为什么简单的程序会占用这么多存储空间space?

Why do simple programs take up so much storage space?

我用 C 语言创建了一个简单的 hello world 程序:

#include <stdio.h>

int main() {
    printf("Hello World!\n");
    return 0;
}

之后,我使用 gcc 在 Mac 上编译它并使用 xxd 转储它。每行 16 个字节(8 个字),编译后的程序总共有 3073 行或 49 424 个字节。在所有这些字节中,只有 1 904 个字节组成了程序,而其余 47 520 个字节都是零。 考虑到只有大约 3.9% 的字节不为零,这是浪费 space 的明显例子。有什么办法可以在这里优化可执行文件的大小吗? (顺便说一下,我已经尝试使用 -Os 编译器选项但没有得到任何结果。)

编辑:我通过计算 hexdump 的行数得到这些数字,但在包含实际指令的行中也有零。我没有计算这些字节,因为它们可能对程序的执行至关重要。 (就像字符串 Hello World! 的空终止符一样)我只计算了完整的零块。

生成的文件不仅仅包含程序所需的代码和数据。它还包含正确加载和执行程序所需的元数据。一般来说,这个元数据可能被拆分成多个section,每个section需要在一定的边界对齐。为了做到这一点,可以添加一些零来填充。对更大的程序进行相同的检查将导致更少的 space 被元数据和填充占用。

可执行文件也可能被制作成可以快速加载到内存中。特别是文本和数据段可能与 OS 的页面大小对齐。这通常是 4KB 或 2 的更大次方。在您称某些东西为 space 的浪费之前,请确保您了解 link 编辑和加载、分段和 Executable and Linkable Format (小精灵).

gcc on MacOS 生成 object 和 Mach-O 文件格式的可执行文件。该文件被分成多个段,每个段都有一些对齐要求以使加载更有效(因此你得到所有的零填充)。我拿了你的代码并用 gcc 在我的 Mac 上构建它,给我一个 8432 字节的可执行文件大小。是的,xxd 给了我一堆零。这是 headers:

部分的 objdump 输出
$ objdump -section-headers hello

hello:  file format Mach-O 64-bit x86-64

Sections:
Idx Name          Size      Address          Type
  0 __text        0000002a 0000000100000f50 TEXT 
  1 __stubs       00000006 0000000100000f7a TEXT 
  2 __stub_helper 0000001a 0000000100000f80 TEXT 
  3 __cstring     0000000f 0000000100000f9a DATA 
  4 __unwind_info 00000048 0000000100000fac DATA 
  5 __nl_symbol_ptr 00000010 0000000100001000 DATA 
  6 __la_symbol_ptr 00000008 0000000100001010 DATA 

__text 包含程序的机器代码,__cstring 包含文字 "Hello World!\n",每个部分都有一堆元数据。

这种结构对于像你这样的简单程序来说显然是矫枉过正,但像你这样的简单程序并不常见。 Object 和可执行文件格式必须能够支持动态加载、符号重定位和其他需要复杂结构的东西。任何编译的程序都有最低级别的复杂性(以及因此的大小)。

因此,“小”程序的可执行文件比您认为的基于源代码的要大,但请注意,其中不仅仅是您的源代码。