当静态链接到 .a 文件时,C 编译器是否会丢弃未使用的函数?

Izz*_*zzo 35 compiling c compiler libraries static-linking

假设我有一个静态main.c链接到libmine.a. 静态链接到库会导致库函数在编译时嵌入到主可执行文件中。

如果libmine.a要提供 未使用的函数main.c,编译器(例如 GCC)会丢弃这些函数吗?

这个问题的灵感来自于“常见消息传递”,即使用静态库会使可执行文件更大,所以我很好奇编译器是否至少从存档文件中删除未使用的代码。

Ste*_*itt 37

默认情况下,链接器将目标文件作为一个整体来处理。main.c在您的示例中,可执行文件最终将包含( )中的代码main.o,以及libmine.a提供main.c(传递)使用的所有函数所需的任何目标文件(目标文件的存档)。

\n

因此链接器不一定会包含所有libmine.a,但它可以使用的粒度是 xe2x80x99t 函数(默认情况下),它是目标文件(严格来说是节)。这样做的原因是,当给定.c文件编译为目标文件时,源代码中的信息会丢失;特别是,函数的结尾不被存储,只存储其开始,并且由于可以组合多个函数,因此很难从目标文件中确定实际上可以删除的内容,如果某个函数未使用。

\n

然而,如果编译器和链接器能够访问所需的额外信息,则可以做得更好。例如,\xe2\x80\x9980s Mac 上的 LightspeedC 编程环境可以使用项目作为库,并且由于在这种情况下它具有完整的源代码,因此它只会包含实际需要的功能。

\n

在更现代的系统上,可以告诉编译器生成允许链接器单独处理函数的目标文件。使用 GCC,在启用选项的情况.o下构建文件-ffunction-sections -fdata-sections,并将最终程序与该--gc-sections选项链接。这确实会产生影响,特别是阻止某些类别的优化;有关详细信息,请参阅丢弃 GCC 中未使用的函数

\n

现代编译器和链接器可以使用的另一个选项是链接时优化;启用此功能-flto。当启用优化时(例如 -O2编译目标文件时),链接器将不会在生成的二进制文件中包含未使用的函数。即使没有-ffunction-sections -fdata-sections.

\n

  • @CodyGray 使用 LTO(和优化,因此实际上是“-O2 -flto”),链接器将从生成的二进制文件中消除未使用的函数,即使目标文件是*没有*“-ffunction-sections”构建的。 (2认同)

Whi*_*Owl 14

是的。但它是在模块级别上,而不是在功能上。

例如,您有两个源文件:foo_goo.c 和 bar.c

// foo_goo.c
int foo() { .. };
int goo() { .. };
Run Code Online (Sandbox Code Playgroud)
// bar.c
int bar() { .. };
Run Code Online (Sandbox Code Playgroud)

将它们编译成foo_goo.obar.o,并将它们.o放入存档中libmine.a

现在,main()您只调用该foo()函数。

// main.c
int main(int argc, char **argv) {
   return foo();
}
Run Code Online (Sandbox Code Playgroud)

将此源文件编译为main.o并链接到.a.

链接器将foo()在模块中看到该函数foo_goo.o并使用它,main()将引用该foo()函数,并且该goo()函数将被添加到最终的二进制文件中,但不会被引用。将bar.o被忽略,因为其中没有引用任何名称。