-O2编译下fib_tr_const函数调用方式及未被移除原因问询
为什么内联后的函数仍保留在编译后的二进制文件中?
你的推测没错,fib_tr_const确实被GCC内联到了main函数里,但原函数代码没被移除,主要有这几个原因:
- 函数是全局可见的,编译器无法确认是否被外部引用:如果
fib_tr_const没有加static修饰,它的作用域是整个程序而非当前编译单元。即使当前文件里的调用都被内联了,编译器没法知道其他编译单元(比如其他.c文件)会不会调用这个函数,所以必须保留一份非内联的副本,防止链接时出现未定义符号错误。 - GCC的内联优化不强制删除原函数定义:
-O2开启的内联是启发式优化——编译器觉得内联能提升性能就会做,但不会主动清理未被引用的全局函数。除非你用static inline把函数限定在当前编译单元,再配合-fdata-sections -ffunction-sections -Wl,--gc-sections这类选项,让链接器自动移除未被引用的函数段。 - 符号表或调试信息没被剥离:如果编译时没加
-s选项,二进制里会保留符号表信息,你可能会误以为函数代码还在,但实际只是符号条目。可以用nm tail_call_const_O2查看:如果是弱符号(标记为w),那大概率只有符号没有实际代码;如果是强符号(标记为T),才是真的保留了函数代码。 - 动态链接的默认行为:如果编译的是动态链接可执行文件(GCC默认行为),全局函数会被保留用于动态链接器的符号解析,哪怕当前编译单元里没有直接调用。
验证&解决方法:
- 给
fib_tr_const加上static修饰,重新编译后再反汇编,原函数大概率会被移除。 - 用
objdump -d tail_call_const_O2 | grep -A20 fib_tr_const查看是否有实际的汇编代码,而不只是符号。 - 加上编译选项
-fwhole-program -fdata-sections -ffunction-sections -Wl,--gc-sections,让编译器和链接器彻底清理未被引用的函数。
内容的提问来源于stack exchange,提问作者smwikipedia
相关产品推荐
相关产品推荐

