引文
我们在工作中经常会遇到动态库链接的问题,因为正常的方式并不能满足我们的场景。常见的问题可以总结如下:
程序的加载流程
根据专栏《程序员的自我修养》中的【程序员的自我修养02】初识ELF文件格式-CSDN博客可知,可执行文件的运行流程简述如下:
- 操作系统加载ELF的文件头。以检查文件格式、操作权限等属性。
- 根据文件头中的段表地址,定位到各个段内容。将各个段映射到虚拟地址中。
- 查找依赖的动态库并加载。
- 进入文件头中的Entry point address。执行业务代码。
其中链接器查找依赖的动态库并加载,这个流程实质很复杂,后续我会在《程序员的自我修养》专栏中详细介绍。本文我们只关心链接器如何去找动态库。
答:ELF文件中有一个段.dynamic。这个段里面保存了动态链接器所需要的基本信息,比如依赖哪些动态库、动态链接符号表的位置、动态链接重定位表的位置、共享对象初始化代码的地址等。我们可以通过readelf –d main命令查看该段内容,如下:
Dynamic section at offset 0xda8 contains 29 entries: |
如上可知:main 可执行程序依赖 两个动态库 liba.so、libc.so.6。其中黄色字体0x000000000000000f (RPATH) Library rpath: [/home/yihua/]表示链接器查找动态库的路径,其优先级最高。需要我们关注。其它的参数暂不考虑。
查看依赖的动态库还可以通过ldd main命令或objdump -x main | grep NEEDED命令。
知道可执行程序依赖哪些动态库口,动态链接器就需要去找这些动态库,查找的方式主要有以下四种。
- 环境变量:LD_LIBRARY_PATH
其动态链接器加载的顺序分别是rpath –> LD_LIBRARY_PATH –> /etc/ld.so.conf –> /lib 、 /usr/lib。
//a.c |
编译:
C |
集成:分别将 main 和 liba.so 放入到bin 和lib目录下。
Shell |
运行:
Shell |
如上错误,是因为动态链接器没有找到liba.so导致的。可通过以下四种方式修复。
-Wl,-rpath
该方式是通过在编译阶段,修改main 可执行程序中的dynamic段达到目的。可查看当前main的dynamic段内容:
yihua@ubuntu:~/test/dynamic$ gcc -FPIC –shared -o liba.so a.c |
再查看dynamic段内容:
运行:
拓展:
-Wl,-rpath是编译阶段修改可执行程序的rpath参数,但是往往我们在工程中是不太确认最终的集成路径的。可以在集成时,采用chrpath命令,修改可执行程序的rpath参数。如下:
yihua@ubuntu:~/test/dynamic$ chrpath –r ./lib/ bin/main //修改rpath |
完结撒花~~~
LD_LIBRARY_PATH
环境变量LD_LIBRARY_PATH是我们最最常用的方式,大部分情况下,我们使用该方式即可。使用方式如下:
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/yihua//test/dynamic/lib。编译如下:
yihua@ubuntu:~/test/dynamic$ gcc -FPIC –shared -o liba.so a.c |
集成:分别将 main 和 liba.so 放入到bin 和lib目录下。
运行:
完结撒花~~~
/etc/ld.so.conf
该配置文件是系统动态链接器加载的配置文件。我们可以重新创建一个窗口(目的是关闭上述的LD_LIBRARY_PATH环境变量)。修改/etc/ld.so.conf文件,如下:
运行:
发现依然没有找到动态库,这是为什么呢?我们可以通过strace ./bin/main命令查看程序的加载流程。输出如下:
yihua@ubuntu:~/test/dynamic$ strace ./bin/main |
我们从输出结果,可以知道,动态链接器只加载/etc/ld.so.cache配置文件,并没有加载/etc/ld.so.conf配置文件。因此,我们需要通过ldconfig命令更新ld.so.cache文件内容。
如下:
完结撒花~~~
系统默认路径
系统默认路径即系统存放动态库的地方,一般为/lib、/usr/lib。我们只需要将动态库放到对应的路径下即可。
完结撒花~~~
总结
综上所述,我们知道了动态链接库寻找动态库的四种方式,其中:
系统默认路径和/etc/ld.so.conf需要系统权限,大部分情况是不能进行修改的。若有相应权限,可以优先使用该方式。
环境变量LD_LIBRARY_PATH可以解决我们大部分场景,比如引文中的第一个场景。但是它并不解决动态库重名的问题。比如引文中的第二个场景。这时,我们就可以采用-Wl,-rpath 编译选项或chrpath修改可执行程序的rpath参数。
原文地址:https://blog.csdn.net/xieyihua1994/article/details/134782826
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_38538.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!