为什么可执行文件的文件大小大于.cpp源文件而没有包含?

时间:2015-09-13 18:54:12

标签: c++ windows g++ cygwin

为什么可执行文件的文件大小大于源文件?我做了下面的例子(我能想到的最简单的例子),而且与源相比,可执行文件仍然是如此巨大,尽管(我认为)它没有使用任何库。

Simplest.cpp:33个字节

Simplest.s:386字节

Simplest.exe:60076字节

Simplest.cpp:

int main(void)
{
    return 0;
}

Simplest.s:

        .file   "Simplest.cpp"
        .def    ___main;        .scl    2;      .type   32;     .endef
        .text
        .globl  _main
        .def    _main;  .scl    2;      .type   32;     .endef
_main:
LFB0:
        .cfi_startproc
        pushl   %ebp
        .cfi_def_cfa_offset 8
        .cfi_offset 5, -8
        movl    %esp, %ebp
        .cfi_def_cfa_register 5
        andl    $-16, %esp
        call    ___main
        movl    $0, %eax
        leave
        .cfi_restore 5
        .cfi_def_cfa 4, 4
        ret
        .cfi_endproc
LFE0:
        .ident  "GCC: (GNU) 4.8.3"

不确定它是否相关,但我在Windows 8上使用英特尔处理器在cygwin上使用g ++编译器。

2 个答案:

答案 0 :(得分:3)

可执行文件与许多库链接。因此,当您的编译器完成链接时,文件大小会增加。当您构建C或C ++程序时,始终会链接libclibc++

您可以阅读此article关于 gcc 的关联过程。

ld's manpage

  

ld 组合了许多对象和档案文件,重新定位了他们的数据并绑定了符号引用。通常,编译程序的最后一步是运行 ld

总而言之,链接器可能会将大量内容放入可执行文件中。难怪为什么它的大小可能大于源文件的大小。

注意:上面的链接是关于Unix上的链接,而不是Windows,但Cygwin尝试以某种方式模拟Linux / Unix系统的行为,因此它们仍然相关。

答案 1 :(得分:2)

ForceBru已经解释了高级别的内容,但似乎您已经明白链接库可能会增加可执行文件的大小,但(错误地)认为您的程序不使用库。

实际上,因为您通过运行gcc链接了您的程序,所以在调用ld时,gcc传递了一些额外的选项。要控制此操作,请阅读gcc Link Options

特别感兴趣的是-nostdlib-nodefaultlibs选项,描述如下:

  

-nodefaultlibs

     

链接时不要使用标准系统库。只有您指定的库才会传递给链接器,并且会忽略指定系统库链接的选项,例如-static-libgcc-shared-libgcc。除非使用-nostartfiles,否则标准启动文件将正常使用。

     

编译器可能会生成对memcmpmemsetmemcpymemmove的调用。这些条目通常由libc中的条目解决。当指定此选项时,应通过其他机制提供这些入口点。

     

-nostdlib

     

链接时请勿使用标准系统启动文件或库。没有启动文件,只有您指定的库被传递给链接器,并且忽略指定系统库链接的选项,例如-static-libgcc-shared-libgcc

     

编译器可能会生成对memcmpmemsetmemcpymemmove的调用。这些条目通常由libc中的条目解决。当指定此选项时,应通过其他机制提供这些入口点。

     

-nostdlib-nodefaultlibs绕过的标准库之一是libgcc.a,这是一个内部子程序库,GCC使用它来克服特定机器的缺点或某些语言的特殊需求。 (有关libgcc.a的更多讨论,请参阅与GCC输出的接口。)在大多数情况下,即使您想要避免使用其他标准库,也需要libgcc.a。换句话说,当您指定-nostdlib-nodefaultlibs时,通常也应指定-lgcc。这可确保您没有对内部GCC库子例程的未解析引用。 (此类内部子例程的示例是__main,用于确保调用C ++构造函数;请参阅collect2。)

由于您还没有使用这些选项,因此您的代码 实际上与多个库相关联。

要了解这些库提供的某些行为,即使您的小程序失败,您也可以阅读博客系列Hello from a libc-free world!Part 2