【发布时间】:2020-12-23 05:04:58
【问题描述】:
我一直在寻找一个相当复杂的产品中的一些链接器错误,而我将其归结为非常疯狂。下面是一个非常简单的示例,展示了与我有关的行为。我试图理解这种行为。如果行为更改是有意的,是否可以将其追溯到 gcc 更改日志,以便我将来可以依赖它?
这确实是一个链接排序问题,而且似乎不同版本的链接器以意想不到的方式表现不同。
第一个共享库(libtest1.so):
void test2();
void test1()
{
test2();
}
第二个共享库(libtest2.so):
#include <iostream>
void test2()
{
std::cout << “calling test 2” << std::endl;
}
主程序:
#include “test1.hpp”
int main()
{
test1();
}
当我构建共享库时,我不会让一个库依赖于另一个库。我只是将未解析的符号留在 test1 中,然后将 test1 和 test2 都放在 main 编译的链接设置中。不用担心 rpath 和 LD_LIBRARY_PATH 之类的东西;这些在讨论中并不重要。
使用 gcc 7.5.0
g++ -std=c++11 main.cpp -o main -L. -ltest1 -ltest2 //compiles OK
g++ -std=c++11 main.cpp -o main -L. -ltest2 -ltest1 //link fails; symbol test2 is unresolved
// This makes 100% good sense to me. The linker is a single pass linker and order matters.
// We know and understand this.
使用 gcc 8.3.0 或 gcc 9.2.0
g++ -std=c++11 main.cpp -o main -L. -ltest1 -ltest2 //compiles OK
g++ -std=c++11 main.cpp -o main -L. -ltest2 -ltest1 //compiles OK
// This totally breaks my brain!!! This makes it seem like the linker in the newer gcc toolchains
// is a multi pass linker which is doing a lot more work to find the symbols that are needed to
// correctly link. This seems like a HUGE change in the way the linker works. However, I have
// scoured the change logs for the compilers and I haven’t been able to find any mention that the
// way the linker operates has changed in any significant way. This scares me and makes me worry
// that we can’t depend on this behavior consistently.
那么这里的故事是什么?我看不到更新的链接器版本如何成功地多次传递目标文件。 gcc 链接器变得更智能了吗?如果是这样,它会变得更加智能,并且在未来会保持更智能吗?您能提供的任何帮助将不胜感激。
【问题讨论】: