【问题标题】:GCC linker changes from 7.x to 8.xGCC 链接器从 7.x 更改为 8.x
【发布时间】: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 链接器变得更智能了吗?如果是这样,它会变得更加智能,并且在未来会保持更智能吗?您能提供的任何帮助将不胜感激。

【问题讨论】:

    标签: gcc linker ld


    【解决方案1】:

    两个编译器都可能使用相同的链接器,因此链接器并没有变得更智能。这一切都在编译器默认传递给链接器的链接器选项中。 -v 是你的朋友。

    这些命令在任一版本的编译器中的工作方式相同。

    g++ -Wl,-as-needed -std=c++11 main.cpp -o main -L. -ltest2 -ltest1 # fails
    g++ -Wl,-no-as-needed -std=c++11 main.cpp -o main -L. -ltest2 -ltest1 #succeeds
    

    【讨论】:

    • 这正是问题所在。即使经过更多的挖掘,我发现编译器默认传递给链接器的内容因发行版而异,(构建到构建)相同的编译器版本。 -v 选项很有用。还使用strace 来查看collect/ld 是如何被调用的。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2013-11-01
    • 2020-01-26
    • 2014-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-07
    • 1970-01-01
    相关资源
    最近更新 更多