动态库依赖关系_查看运行的动态库

动态库依赖关系_查看运行的动态库1前言这两天在编写一个插件系统Demo的时候,发现了个很奇怪的问题:插件加载器中已经链接了ld库,但是应用程序在链接插件加载器的时候,却还需要显式的来链接ld库。否则就会报:DSOmissingfromcommandline。这个报错翻译过来就是没有在命令行中指定该动态库。这个报错就很搞事了,你说你明明知道需要哪个库,为什么不直接帮我链接呢,非得我显示的在命令行中指定呢?2现象描…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

1 前言

这两天在编写一个插件系统Demo的时候,发现了个很奇怪的问题:插件加载器中已经链接了ld库,但是应用程序在链接插件加载器的时候,却还需要显式的来链接ld库。否则就会报:DSO missing from command line。这个报错翻译过来就是没有在命令行中指定该动态库
这个报错就很搞事了,你说你明明知道需要哪个库,为什么不直接帮我链接呢,非得我显示的在命令行中指定呢?

2 现象描述

问题可以简单描述为:当链接可执行文件时,依赖于libA.so,而libA.so又依赖于libB.so,而且可执行文件中还直接调用了libB.so中的函数,那么此时链接就会出现错误。

2.1 问题发生的前置条件

  • libA.so在编译过程中显式的链接了libB.so
  • 可执行文件中使用了libB.so的函数
  • binuntils版本 ≥ 2.22

2.2 Talk is cheap. Show me the code

话不多说,先看看可以复现改问题的代码吧

libB.so的源码:

#include <stdio.h>

int funB1(){ 
   

    printf("in funB1");

    return 0;
}

int funB2(){ 
   

    printf("in funB2");

    return 0;
}

这里面有两个函数:funB1funB2
其中funB1函数会被libA调用,而funB2会被可执行文件调用。

编译libB.so:

$ gcc libB.cpp -fPIC -shared -o libB.so

libA.so的源码:

#include <stdio.h>

int funB1();

int funA1(){ 
   

    printf("in funA1 \n");

    funB1();

    return 0;
}

该库中只有一个函数funA1,该函数在内部调用了libB中的funB1函数。且该函数会被可执行文件调用。

编译libA.so:

$ gcc libA.cpp -fPIC -shared -o libA.so -Wl,-rpath=./ -L./ -lB

main.cpp的源码:

int funA1();
int funB2();

int main(){ 
   

    funA1();
    funB2();

    return 0;
}

编译main.cpp:(复现错误的编译方法)

gcc main.cpp -L./ -lA

当我们按照上面的指令编译main.cpp的时候,便报错了。

/usr/bin/ld: /tmp/ccDQXTKy.o: undefined reference to symbol '_Z5funB2v'
.//libB.so: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status

(问号.jpg)这,这GCC不是搞事吗,你明明知道我需要连接libB.so为啥就不帮我链接上去呢?难道我libA.so没有指明要使用libB.so?我们使用下面的指令来看一下

$ ldd libA.so

得到如下信息:

	linux-vdso.so.1 =>  (0x00007ffd09def000)
	libB.so => ./libB.so (0x00007fc513d7d000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc5139b3000)
	/lib64/ld-linux-x86-64.so.2 (0x00007fc514181000)

明明libA.so已经显式的指明我要依赖libB.so了,那为啥在编译main.cpp的时候链接了libA.so,GCC却还要我们显式的链接libB.so呢?

3 答案

答案很简单,那就是GCC就是想要你显式链接呗。(你是编译器,你牛好吧。)那这是为啥呢?
官方一点的答案就是,自从binutils 2.22版本以后,如果你在程序中使用了你依赖的动态库所依赖的动态库中的函数时,你就必须显式的指定你依赖的动态库所依赖的动态库。

说那么多,我们更想知道的是,通过修改什么参数可以解决这个问题呢?因为你可能不想在编译程序的时候要把动态库所依赖的所有动态库都显示链接一遍。

4 究极答案

实际上,这是binutils在2.22版本以后,默认把--no-copy-dt-needed-entries这个选项打开了。当打开了这个选项的时候,编译器在链接的时候是不会递归的去获取依赖动态库的依赖项的,于是就会出现上述的问题。关于该配置项的详细说明如下:

   --copy-dt-needed-entries
   --no-copy-dt-needed-entries
       This option affects the treatment of dynamic libraries referred to by DT_NEEDED tags inside ELF dynamic libraries mentioned on the command line.  Normally the linker won't add a DT_NEEDED
       tag to the output binary for each library mentioned in a DT_NEEDED tag in an input dynamic library.  With --copy-dt-needed-entries specified on the command line however any dynamic
       libraries that follow it will have their DT_NEEDED entries added.  The default behaviour can be restored with --no-copy-dt-needed-entries.

       This option also has an effect on the resolution of symbols in dynamic libraries.  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.  With the default setting however the searching of dynamic
       libraries that follow it will stop with the dynamic library itself.  No DT_NEEDED links will be traversed to resolve symbols.

大概意思就是,跟在--no-copy-dt-needed-entries它后面的库都不会遍历其依赖项,使用--copy-dt-needed-entries则相反。也就是使用下面的指令来编译mian.cpp就可以避免该问题了。

$ gcc main.cpp -L./ -Wl,--copy-dt-needed-entries -lA

题外话

在Linux的ELF文件中,如果依赖于其他的动态库,那么改ELF文件会存在一个.dynamic的段,这个段里面会记录其依赖的动态库信息,其标志位为DT_NEEDED。

5 参考文档

1,DSO missing from command line原因及解决办法:https://segmentfault.com/a/1190000002462705
2,折腾gcc/g++链接时.o文件及库的顺序问题: https://www.cnblogs.com/OCaml/archive/2012/06/18/2554086.html#sec-1-4-1

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/188583.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • QQ密码防盗十大建议

    QQ密码防盗十大建议1.去腾讯申请密码保护,这样如果密码被激活成功教程或自己忘记了还可以利用密码保护功能取回来。    2.QQ密码的位数一定要超过8位,而且最好包含数字、字母和特殊符号,否则以现代计算机的超强计算能力,要想暴力激活成功教程你的QQ密码简直是易如反掌。    3.不要在QQ中填入真实的年龄、E-mail等敏感消息,更不能告诉任何人,小心行得万年船。    4.不要随意运行别人发给你的文件,即便那些看起来很诱人的文件也

    2022年7月20日
    39
  • Java解析XML文件

    Java解析XML文件1.DOM方式解析XMLDom解析是将xml文件全部载入到内存,组装成一颗dom树,然后通过节点以及节点之间的关系来解析xml文件,与平台无关,java提供的一种基础的解析XML文件的API,理解较简单,但是由于整个文档都需要载入内存,不适用于文档较大时。2.SAX方式解析XML基于事件驱动,逐条解析,适用于只处理xml数据,不易编码,而且很难同时访问同一个文档中的多处不同数据3.JDOM方式解

    2022年5月4日
    37
  • Busybox的安装步骤[通俗易懂]

    Busybox的安装步骤[通俗易懂]一、下载busyboxwww.busybox.net/downloads/(busybox-1.17-0.tar/bz2)二、安装:1、修改Makefile文件:第175行交叉编译器CORSS_COMPILE2、makemenuconfig当出现如下错误时的解决办法:make[2]:***[scripts/kconfig/lxdialog/check…

    2022年7月16日
    13
  • 奈氏曲线的绘制步骤_qpcr扩增曲线是直线

    奈氏曲线的绘制步骤_qpcr扩增曲线是直线本文由@浅墨_毛星云出品,首发于知乎专栏,转载请注明出处文章链接:https://zhuanlan.zhihu.com/p/69380665作为基于物理的渲染(PBR)技术中材质高光质感的决定因素,更先进的法线分布函数(NormalDistributionFunction,NDF)的问世和发展,是PBR能够在游戏和电影工业日益普及的重要…

    2022年8月11日
    6
  • 以太坊矿机组装教程_eth矿机组装

    以太坊矿机组装教程_eth矿机组装以太坊挖矿矿机组装指南伴随着比特币的热潮,“矿机”一词出现在了大众的视野中。那么何为“矿机”呢?一个矿机的本质就是一个电脑机箱,它的硬件组成与普通的台式机箱几乎相同。有区别的是它的主板上PCIE插槽比较多,电源的功率比较大。在这里简单解释下为什么会有这两点不同:1.PCIE插槽越多可连接的显卡就越多,单个矿机的算力就越大。2.电源功率越大能带动的显卡越多。所以大家在选择配置时一定要根据你的显卡…

    2022年9月30日
    3
  • 你还在认为 Java 是免费的吗[通俗易懂]

    你还在认为 Java 是免费的吗[通俗易懂]在收购了Sun公司的六年后,Oracle正在大规模的加大对违反其许可证的Java客户的审查力度。越来越多的Oracle客户和合作伙伴被拉里·埃里森的团队约谈,声称他们没有遵守Java的规矩。Oracle在2010年 收购了SunMicrosystems公司 ,知情人士透露现在它的许可证管理服务(LMS)正在到处追缴付款。该数据库巨头公司目前已经在全球

    2022年7月9日
    24

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号