如何避免 C 运行时 (crt*.o) 垃圾
How to avoid C runtime (crt*.o) garbage
我有两个C源文件
foo1.c
:
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
puts("hello world");
return 0;
}
和foo2.c
:
#include <stdlib.h>
#include <stdio.h>
void _start(void)
{
puts("hello world");
exit(0);
}
我在我的 i386 GNU/Linux 平台上像这样编译它们:
$ #compile foo1
$ cc -o foo1 foo1.c
$ #compile foo2
$ cc -S foo2.c
$ as -o foo2.o foo2.s
$ ld -o foo2 -dynamic-linker /lib/i386-linux-gnu/ld-linux.so.2 -lc foo2.o
$ #notice that crt1.o and others are missing
从用户的角度来看,输出的可执行文件做同样的事情。
$ ./foo1
hello world
$ ./foo2
hello world
但它们是不同的:
$ wc -c foo1
5000
$ wc -c foo2
2208
$ objdump -d foo1 | wc -l
238
$ objdump -d foo2 | wc -l
35
即使我启用 gcc 的 -Os
选项来优化大小,
$ #compile foo1
$ gcc -o foo1 foo1.c -Os
并没有小很多:
$ wc -c foo1
4908
$ objdump -d foo1 | wc -l
229
有没有什么方法可以让 GCC 优化掉 crt1.o
和我怀疑导致文件过大的朋友的部分,而无需求助于非标准代码和奇怪的(在某些情况下可能有害)编译?我的 GCC 版本字符串是“gcc (Debian 4.9.2-10) 4.9.2
”。
有了gcc/clang你可以使用-nostartfiles
,但是你使用的c库可能依赖于它自己的_start()
动态链接实现。由于您使用 Linux,我建议使用 musl-libc.
的静态构建
或者,您可以只实现 write()
和 exit()
系统调用,并将 '\n' 添加到您的字符串中,通过使用 _start()
而不是 [= 来完全避免 c 库15=]。如果您需要访问 argc、argv 和 envp,您将需要一些内联汇编来访问堆栈(Linux 在堆栈上为所有 ELF 二进制文件传递这些,无论架构如何)。
我有两个C源文件
foo1.c
:
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
puts("hello world");
return 0;
}
和foo2.c
:
#include <stdlib.h>
#include <stdio.h>
void _start(void)
{
puts("hello world");
exit(0);
}
我在我的 i386 GNU/Linux 平台上像这样编译它们:
$ #compile foo1
$ cc -o foo1 foo1.c
$ #compile foo2
$ cc -S foo2.c
$ as -o foo2.o foo2.s
$ ld -o foo2 -dynamic-linker /lib/i386-linux-gnu/ld-linux.so.2 -lc foo2.o
$ #notice that crt1.o and others are missing
从用户的角度来看,输出的可执行文件做同样的事情。
$ ./foo1
hello world
$ ./foo2
hello world
但它们是不同的:
$ wc -c foo1
5000
$ wc -c foo2
2208
$ objdump -d foo1 | wc -l
238
$ objdump -d foo2 | wc -l
35
即使我启用 gcc 的 -Os
选项来优化大小,
$ #compile foo1
$ gcc -o foo1 foo1.c -Os
并没有小很多:
$ wc -c foo1
4908
$ objdump -d foo1 | wc -l
229
有没有什么方法可以让 GCC 优化掉 crt1.o
和我怀疑导致文件过大的朋友的部分,而无需求助于非标准代码和奇怪的(在某些情况下可能有害)编译?我的 GCC 版本字符串是“gcc (Debian 4.9.2-10) 4.9.2
”。
有了gcc/clang你可以使用-nostartfiles
,但是你使用的c库可能依赖于它自己的_start()
动态链接实现。由于您使用 Linux,我建议使用 musl-libc.
或者,您可以只实现 write()
和 exit()
系统调用,并将 '\n' 添加到您的字符串中,通过使用 _start()
而不是 [= 来完全避免 c 库15=]。如果您需要访问 argc、argv 和 envp,您将需要一些内联汇编来访问堆栈(Linux 在堆栈上为所有 ELF 二进制文件传递这些,无论架构如何)。