假设我有一个C程序main.c
,它静态地链接到libmine.a
。静态地链接到库会导致库函数在编译时嵌入到主可执行文件中。
如果libmine.a
要使用main.c
没有使用的函数,编译器(例如GCC)会放弃这些函数吗?
这个问题的灵感来源于使用静态库使可执行文件更大的“公共消息传递”,所以我很好奇编译器是否至少从归档文件中删除了未使用的代码。
发布于 2022-09-02 12:26:33
在您的示例中,可执行文件将最终包含来自main.c
(main.o
)的代码,以及提供main.c
使用的所有函数所需的来自libmine.a
的任何对象文件(这是对象文件的存档)。
因此,链接器不一定包括所有的libmine.a
,但是它可以使用的粒度不是函数(默认情况下),而是对象文件(严格地说,是节)。这样做的原因是,当将给定的.c
文件编译为对象文件时,源代码中的信息就会丢失;特别是,函数的结束不会被存储,只存储它的开始,而且由于可以组合多个函数,因此很难从对象文件中确定如果函数未使用会实际删除什么。
但是,如果编译器和链接器能够访问所需的额外信息,它们就有可能做得更好。例如,80年代Mac上的LightspeedC编程环境可以使用项目作为库,而且由于在这种情况下它有完整的源代码,所以它只包含实际需要的函数。
在更现代的系统中,编译器可以被告知生成允许链接器单独处理函数的对象文件。使用GCC,在启用.o
选项的情况下构建-ffunction-sections -fdata-sections
文件,并将最终程序与--gc-sections
选项链接起来。这确实会产生影响,特别是通过阻止某些类别的优化;有关详细信息,请参阅GCC中的废函数。
与现代编译器和链接器一起使用的另一个选项是链接时间优化;使用-flto
启用此选项。当启用优化时(例如,编译对象文件时的-O2
),链接器将不会在生成的二进制文件中包含未使用的函数。即使没有-ffunction-sections -fdata-sections
,这也是可行的。
发布于 2022-09-02 12:26:08
是。但是它是在模块级别上,而不是在函数上。
例如,您有两个源文件: foo_goo.c和bar.c
// foo_goo.c
int foo() { .. };
int goo() { .. };
// bar.c
int bar() { .. };
将它们编译成foo_goo.o
和bar.o
,并将两个.o
放到归档libmine.a
中。
现在,在您的main()
中,您只调用foo()
函数。
// main.c
int main(int argc, char **argv) {
return foo();
}
将此源文件编译为main.o
并与.a
链接。
链接器将在模块foo()
中看到函数foo_goo.o
并使用它,main()
将引用foo()
函数,goo()
函数将被添加到最终的二进制文件中,但不会被重新修改。bar.o
将被忽略,因为其中没有引用任何名称。
发布于 2022-09-03 09:17:09
这与编译器无关。如果使用静态链接,则是将所需的所有对象放到一个文件中的链接器。
这将是C程序的main()函数,所有可能由main使用的东西,任何可能被main使用的东西,可能被main使用的东西所使用的所有东西,等等。如果有一个函数不可能被调用,或者一个对象不可能被访问,那么链接器可以忽略它。如果一个对象文件包含五个可以调用的函数和十个不能调用的函数,那么链接器可能只包含前五个函数。
https://unix.stackexchange.com/questions/715899
复制相似问题