GCC:空程序== 23202字节?

时间:2009-08-22 12:57:33

标签: c++ c gcc linker tdm-mingw

test.c:

int main()
{
    return 0;
}

我没有使用任何标志(我是gcc的新手),只是命令:

gcc test.c

我在win32上使用了最新的TDM build of GCC。 生成的可执行文件几乎是23KB,对于空程序来说太大了。

如何减少可执行文件的大小?

10 个答案:

答案 0 :(得分:37)

不要遵循其建议,但为了娱乐,请阅读this 'story'关于制作尽可能小的ELF二进制文件。

答案 1 :(得分:21)

  

如何减小尺寸?

  • 不要这样做。你只是在浪费时间。
  • 使用-s标志去除符号(gcc -s)

答案 2 :(得分:11)

默认情况下,某些标准库(例如C运行时)与您的可执行文件链接。查看密钥--nostdlib --nostartfiles --nodefaultlib了解详情。链接选项描述为here

对于真正的计划,第二个选项是尝试optimization options,例如-Os(优化尺寸)。

答案 3 :(得分:11)

放弃。在x86 Linux上,gcc 4.3.2生成一个5K二进制文件。可是等等!这是动态链接! 静态链接二进制文件超过半个meg:516K。放松并学会与臃肿一起生活。

并且他们说Modula-3永远不会去任何地方因为200K hello world binary!


如果您想知道发生了什么,Gnu C库的结构可以包含某些功能,无论您的程序是否依赖于它们。这些功能包括malloc和free,dlopen,一些字符串处理以及与语言环境和国际化有关的整个 bucketload 这样的琐事,尽管我找不到任何相关的手册页

为需要最少服务的程序创建小型可执行文件对于glibc来说设计目标。公平地说,对于我曾经使用的每个运行时系统(大约六个),它也是 not 的设计目标。

答案 4 :(得分:7)

实际上,如果您的代码什么都不做,编译器是否仍会创建可执行文件是否公平? ; - )

嗯,在Windows上,任何可执行文件仍然有一个大小,虽然它可以合理地小。使用旧的MS-DOS系统,完整的无操作应用程序只需几个字节。 (我认为四个字节使用21h中断来关闭程序。)然后,这些应用程序被直接加载到内存中。 当EXE格式变得更受欢迎时,情况发生了一些变化。现在,可执行文件包含有关进程本身的其他信息,例如代码和数据段的重定位以及一些校验和和版本信息。 Windows的引入为格式添加了另一个标题,告诉MS-DOS它无法执行可执行文件,因为它需要在Windows下运行。 Windows会毫无问题地识别它。 当然,可执行格式也扩展了资源信息,如位图,图标和对话框形式等等。

现在,无操作可执行文件的大小将介于4到8 KB之间,具体取决于您的编译器以及用于减小其大小的每种方法。这将是UPX实际上会产生更大可执行文件的大小!可能会添加可执行文件中的其他字节,因为您在代码中添加了某些库。特别是具有初始化数据或资源的库将添加相当多的字节。添加调试信息也会增加可执行文件的大小。

虽然这一切都在减小尺寸方面做了很好的练习,但你可能会怀疑是否继续担心应用程序的膨胀是否可行。现代硬盘将分段文件分割,对于真正大的磁盘,差异将非常小。但是,将大小保持尽可能小的麻烦将减慢开发速度,除非您是熟悉这些优化的专家开发人员。这些类型的优化不会提高性能,并且考虑到大多数系统的平均磁盘空间,我不明白为什么它是实用的。 (尽管如此,我确实以类似的方式优化了我自己的代码,但是再次,我对这些优化很有经验。)


EXE header感兴趣?它以字母MZ开头,代表“Mark Zbikowski”。第一部分是可执行文件的旧式MS-DOS头,用作MS-DOS的存根,说该程序是MS-DOS可执行文件。 (在二进制文件中,你可以找到文本'这个程序不能在DOS模式下运行。'这基本上就是它所做的全部:显示该消息。接下来是PE头,Windows将识别并使用而不是MS-DOS它以字母PE for Portable Executable开头。在第二个标题之后,将有可执行文件本身,分为几个代码和数据块。标题包含特殊的重新分配表,告诉操作系统在哪里加载特定的块。如果你可以保持这个限制,最终的可执行文件可以小于4 KB,但90%将是标题信息而没有功能。

答案 5 :(得分:3)

我喜欢许多年前DJGPP FAQ addressed this的方式:

  

通常,通过查看“Hello”程序的大小来判断代码大小是没有意义的,因为这些程序主要由启动代码组成。 ...所有这些功能的大部分功能都浪费在“Hello”程序中。运行所有代码只是打印一个15字节的字符串并退出是没有意义的。

答案 6 :(得分:2)

这项练习的目的是什么?

即使使用与C语言一样低级的语言,仍然需要在调用main之前进行大量设置。其中一些设置由加载器处理(需要某些信息),一些由调用main的代码处理。然后可能会有一些普通程序必须具有的库代码。至少,如果它们在dll中,可能会引用标准库。

检查空程序的二进制大小本身就是一项毫无价值的练习。它什么也没告诉你。如果您想了解有关代码大小的内容,请尝试编写非空(并且最好是非平凡)程序。将使用标准库的程序与自己完成所有工作的程序进行比较。

如果你真的想知道该二进制文件中发生了什么(以及为什么它如此之大),那么找出可执行格式获取二进制转储工具并将其分开。

答案 7 :(得分:2)

size a.out”告诉您代码,数据和bss细分的大小是什么?大多数代码可能是启动代码(在Unix机器上经典crt0.o),它由o / s调用并确实设置工作(比如将命令行参数整理到argc,argv中)调用main()

答案 8 :(得分:1)

在二进制文件上运行strip以除去符号。随着gcc版本3.4.4(cygming special)我从10k下降到4K。

您可以尝试链接自定义运行时(调用main的部分)来设置运行时环境。所有程序都使用相同的程序来设置gcc附带的运行时环境,但对于可执行文件,您不需要数据或零内存。这意味着您可以摆脱未使用的库函数,如memset / memcpy和减少CRT0大小。在寻找有关嵌入式环境中GCC的信息时。嵌入式开发人员通常是唯一使用自定义运行时环境的人。

其余的是加载可执行文件的操作系统的开销。除非你手动调整,否则你不会那么多吗?

答案 9 :(得分:0)

使用GCC,使用-Os而不是其他优化标志(-O2-O3)编译您的程序。这告诉它优化尺寸而不是速度。顺便提一下,如果一些关键部分碰巧更合适,它有时会使程序运行速度比速度优化更快。另一方面,-O3实际上可以导致代码大小的增加。

可能还有一些链接器标志告诉它从最终的二进制文件中遗漏未使用的代码。