【发布时间】:2022-01-21 20:45:17
【问题描述】:
考虑以下源文件:
交流:
extern int baz();
int foo() { return 123; }
int bar() { return baz() + 1; }
b.c:
extern int foo();
int main() { return foo(); }
现在,当我尝试使用这些资源构建程序时,会发生以下情况:
$ gcc -c -o a.o a.c
$ gcc -c -o b.o b.c
$ gcc -o prog a.o b.o
/usr/bin/ld: a.o: in function `bar':
a.c:(.text+0x15): undefined reference to `baz'
collect2: error: ld returned 1 exit status
这是在 Devuan GNU/Linux Chimaera 上,带有 GNU ld 2.35.2,GCC 10.2.1。
为什么会这样?我的意思是,不需要任何复杂的优化就可以知道baz() 在bar() 中并不真正需要 - ld 在某些时候自然会注意到这一点 - 例如在完成对bar() 的遍历时,没有注意到使用baz() 的位置。
现在,你可以说“einpoklum,你没有让编译器为你找麻烦”——我想这很公平,但即使我在这些指令中使用-O3,我也会得到相同的结果错误。
注意:启用 LTO 和优化后,我们可以规避这个问题:
$ gcc -c -flto -O1 -o b.o b.c
$ gcc -c -flto -O1 -o a.o a.c
$ gcc -o prog -O1 -flto a.o b.o
$ /prog ; echo $?;
123
【问题讨论】:
-
启用死代码删除并使用 -fdata-sections -ffunction-sections
-
@0___________: 1. 但不管怎样,链接时死代码都会被删除,不是吗?它不像链接器将库的 all 放在可执行文件中......还是这样? 2. 为什么我需要使用神秘的
-f开关才能让一些微不足道的事情发生? :-( -
@它有用吗?
-
@0___________:我不确定您所说的“启用死代码删除”是什么意思。
-O3会处理它吗?另外,这些开关是用于编译还是用于链接?当我在所有 gcc 调用中使用-O3 -flto -fdata-sections -ffunction-sections时,它不起作用。 -
编译器 不知道
bar不会被使用,并将其放入公共.text部分。链接器知道,但它不能消除具有函数粒度的代码,它可以删除部分。这就是为什么每个函数都需要放在一个单独的部分中。
标签: c linux linker undefined-symbol lto