为什么 GNU ld 在链接可执行文件和共享对象时解析符号的方式不同?

2023-12-25

我有一段简单的 C++ 代码,看起来像这样:

#include <boost/timer/timer.hpp>

int main(void) {
    boost::timer::auto_cpu_timer t;
    return 0;
}

我尝试编译并链接它(使用 gcc 4.8.1 和 GNU ld 2.23.52.20130828),如下所示:

$ g++ -o test test.cc -lboost_timer
/usr/bin/ld: /tmp/cc2jP1jv.o: undefined reference to symbol '_ZN5boost6system15system_categoryEv'
/usr/lib/libboost_system.so.1.54.0: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status

一种解决方案是明确提及-lboost_system在命令行上,并且有效。不过,我也可以这样做:

$ g++ -Wl,--copy-dt-needed-entries -o test test.cc -lboost_timer

根据ld文档“在命令行上提到的--copy-dt-needed-entries动态库将被递归搜索,跟随它们的DT_NEEDED标签到其他库,以便解析输出二进制文件所需的符号”,所以这一切都有意义:ld 从 boost_timer 中发现,它还需要链接到 boost_system 才能解析所有符号。

然而,我意识到这也有效:

$ g++ -fPIC -shared -o test test.cc -lboost_timer

显然,我现在生成了一个共享对象而不是可执行文件。不过,显然 ld 能够弄清楚它需要将共享对象链接到 boost_system:

$ ldd test | grep boost_system
        libboost_system.so.1.54.0 => /usr/lib/libboost_system.so.1.54.0 (0x00007f385246e000)

所以我的问题是:为什么在构建共享对象和可执行文件时符号解析不同? ld 如何在没有我指定的情况下确定我的共享对象应该链接到 boost_system--copy-dt-needed-entries?


我的问题的直接答案是--[no-]allow-shlib-undefined我认为是 ld 的选项。从手册页:

默认行为是报告任何未定义符号的错误 如果链接器用于创建,则在共享库中引用 可执行文件,但如果链接器用于创建则允许它们 一个共享库。

因此,当我构建时-shared, boost_system 中的符号未定义,但 ld 的默认行为是不关心。可以说要关心:

$ g++ -fPIC -shared -Wl,--no-allow-shlib-undefined -o test test.cc -lboost_timer
/usr/bin/ld: /tmp/cc6j1de3.o: undefined reference to symbol '_ZN5boost6system15system_categoryEv'
/usr/lib/libboost_system.so.1.54.0: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status

同样,我们可以告诉它在构建可执行文件时不要关心:

$ g++ -Wl,--allow-shlib-undefined -o test test.cc -lboost_timer
/tmp/ccUHoCIU.o: In function `__static_initialization_and_destruction_0(int, int)':
test.cc:(.text+0x7a): undefined reference to `boost::system::generic_category()'
test.cc:(.text+0x86): undefined reference to `boost::system::generic_category()'
test.cc:(.text+0x92): undefined reference to `boost::system::system_category()'
collect2: error: ld returned 1 exit status

但是,如果无法定义这些符号,创建二进制文件就会失败。

感谢@CharlesBailey 为我指明了正确的方向!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 GNU ld 在链接可执行文件和共享对象时解析符号的方式不同? 的相关文章

随机推荐