为什么我用GCC做的最小编译exe是67KB?

时间:2015-11-08 18:34:45

标签: c gcc mingw compiler-optimization

我想制作一个非常小的编译exe,它是用C语言编写的。但我能设法得到的最小的是67KB。我正在使用MinGW。 我已经尝试过不使用任何头文件,并且编译时没有错误:

//no header
void main() {
 write(1, "Hello world!", 12);
}

如果我构建并运行它,GCC没有显示错误,但它也是67KB。

1 个答案:

答案 0 :(得分:2)

我刚在x86_64 Linux中试过这个,虽然你永远不知道,但在这个级别上可能与MinGW没什么不同。

基本上,问题在于,即使没有任何内容从C库中提取,除非它被引用,CRT" startfiles"确实参考了一小部分内容,这些东西反过来引用了其他一些东西,并且" Hello world"最终看起来很糟糕。这不是一个值得修复的问题因为所有真正的程序都会引用这些核心功能。

启动文件的源代码是可用的,并且非常小,如果您选择,编译器允许您覆盖标准文件,因此优化它们并不是一件大事。它们是用汇编代码编写的,但你可以通过简单地删除行来删除大部分无关的垃圾。

但是,有一个黑客可以完全删除启动文件:

#include <unistd.h>

void _start (void) {
  write(1,"Hello world!", 12);
  _exit(0);
}

编译:{{1​​}}

哪个有用(偶然,见下文),并给我一个 1792字节的文件大小。

为了进行比较,你的原始代码给出了738624个字节,使用相同的编译器,当我删除gcc -nostartfiles t.c -s -static时,它会下降到4400个字节,但那就是作弊! (我的代码实际上得到的更大没有-static,因为动态链接器元数据超过了-staticwrite的代码。

偶然部分,该程序现在已初始化无堆栈指针。同样,对于所有其他全局状态,启动文件通常会处理。事实上,在x86_64 Linux上,这不是致命的问题(只是不要在生产中这样做,对吧?)但是,当我用_exit尝试它时,我在-m32内遇到了分段错误{1}}。

可以通过为这些东西添加自己的初始化来解决问题,但是代码将不再是 可移植的(它不是绝对可移植的)。或者,直接调用write系统调用。