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

时间:2013-10-09 11:28:30

标签: c++ gcc linker ld binutils

我有一段简单的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文档“with --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)

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

2 个答案:

答案 0 :(得分:5)

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

  

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

因此,当我使用-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指出我正确的方向!

答案 1 :(得分:0)

collect2命令中可能存在差异。在http://imgur.com/eMr2tY2处比较不同的命令。右侧创建共享库(-fPic -shared),左侧是正常编译。