为什么在链接可执行文件和共享对象时,GNU ld不同地解析符号? [英] Why does GNU ld resolve symbols differently when linking executables vs shared objects?

查看:396
本文介绍了为什么在链接可执行文件和共享对象时,GNU ld不同地解析符号?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个微不足道的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:未定义对符号_ZN5boost6system15system_categoryEv的引用
/usr/lib/libboost_system.so.1.54.0:添加符号时出错:命令行中缺少DSO
collect2:error: ld返回1退出状态

一个解决方案是明确提及 -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,我想。从手册页:


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


因此,当我用 -shared 构建时,boost_system中的符号是未定义的,但ld的默认行为不在乎。它可以告诉照顾:

  $ g ++ -fPIC -shared -Wl, -  no-allow-shlib-undefined  - o test test.cc -lboost_timer 
/ usr / bin / ld:/tmp/cc6j1de3.o:未定义对符号_ZN5boost6system15system_categoryEv'的引用
/usr/lib/libboost_system.so.1.54.0:error添加符号:命令行中缺少DSO
collect2:错误:ld返回1退出状态

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

  $ g ++ -Wl, -  allow-shlib-undefined -o test test.cc -lboost_timer 
/tmp/ccUHoCIU.o:在函数`__static_initialization_and_destruction_0(int,int)'中:
test.cc:(.text+0x7a):未定义引用`boost :: system :: generic :: Category :: generic ::()
test.cc:(.text + 0x86):未定义引用`boost :: system :: generic_category()'
test.cc:(.text+ 0x92):未定义引用`boost :: system :: system_category()'
collect2:error:ld返回1退出状态

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



感谢@CharlesBailey指向正确的方向! p>

I have a trivial piece of C++ code that looks something like this:

#include <boost/timer/timer.hpp>

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

I tried to compile and link it (with gcc 4.8.1 and GNU ld 2.23.52.20130828) as follows:

$ 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

One solution is to explicitly mention -lboost_system on the command line, and that works. However, I can also do:

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

According to the ld documentation "with --copy-dt-needed-entries dynamic libraries mentioned on the command line will be recursively searched, following their DT_NEEDED tags to other libraries, in order to resolve symbols required by the output binary", so this all makes sense: ld is figuring out from boost_timer that it also needs to link against boost_system in order to resolve all the symbols.

However, I realised that this also works:

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

Obviously, I've now generated a shared object rather than an executable. Apparently, though, ld was able to figure out that it needed to link the shared object against boost_system:

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

So my question is this: why is symbol resolution different when building a shared object versus an executable? How is ld able to figure out that my shared object should be linked against boost_system without my specifying --copy-dt-needed-entries?

解决方案

The direct answer to my question is in the --[no-]allow-shlib-undefined option to ld, I think. From the man page:

The default behaviour is to report errors for any undefined symbols referenced in shared libraries if the linker is being used to create an executable, but to allow them if the linker is being used to create a shared library.

Therefore, when I build with -shared, the symbols in boost_system are undefined, but the default behaviour of ld is not to care. It can be told to care:

$ 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

Similarly, we can tell it not to care when building an executable:

$ 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

But creating the binary fails without being able to define those symbols.

Thanks @CharlesBailey for pointing me in the right direction!

这篇关于为什么在链接可执行文件和共享对象时,GNU ld不同地解析符号?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆