Linux动态库相关知识整理
作者:网络转载 发布时间:[ 2015/11/13 11:41:03 ] 推荐标签:操作系统
动态库的加载
动态库创建那一节,我演示如何隐式使用动态库,那么编译运行这段代码试一下。
gcc main.c -L./ -lelfhash
./a.out
//执行可执行程序
//以下是输出结果
./a.out: error while loading shared libraries: libelfhash.so: cannot open shared object file: No such file or directory
结果运行时报错,可执行程序找不到动态库。 网上有一些说法是编译时设置-L选项,但在Linux上面证明是不行的(SunOS上可行),这个选项只能在编译链接时有效, 可以让你使用-l如上面的-lelfhash。使用readelf -d a.out可以看到可执行文件依赖的动态库信息。
0x0000000000000001 (NEEDED) Shared library: [libelfhash.so]
可以看到这里面并没有包含动态库的路径信息。查阅一下动态链接器的文档man ld-linux.so可以发现这样一句话(有的没有,版本问题)
If a slash is found, then the dependency string is interpreted as a (relative or absolute) pathname, and the library is loaded using that pathname
这段话太长,我只截取一部分,大致是说,当依赖中有/符号,那么会被解析成动态库加载的路径,隐式使用的例子换一种编译方法。
gcc main.c ./libelfhash.so
./a.out
23621492 //输出正常
再用readelf -d a.out查看会发现,依赖信息中有了一个路径。
0x0000000000000001 (NEEDED) Shared library: [./libelfhash.so]
这种方法虽然解决了问题,但是依赖中的路径是硬编码,不是很灵活。 动态链接器是如何查找的动态库的需要进一步查阅文档。关于查找的顺序有点长,这里不直接引用了,大致是这样:
(仅ELF文件) 使用可执行文件中DT_RPATH区域设置的属性,如果DT_RUNPATH被设置,那么忽略DT_RPATH(在我的Linux对应的是RPATH和RUNPATH)。
使用环境变量LD_LIBRARY_PATH,如果可执行文件中有set-user-id/set-group-id, 会被忽略。
(仅ELF文件) 使用可执行文件中DT_RUNPATH区域设置的属性
从/etc/ld.so.cache缓存文件中查找
从默认路径/lib, /usr/lib文件目录中查找
我们需要设置RPATH或者RUNPATH,可以这样做
gcc main.c -Wl,-rpath,/home/xxx,--enable-new-dtags -L./ -lelfhash
这里的-Wl选项告诉链接器ld如果如何处理,接下来传递的-rpath(或者使用-R)告诉ld动态库的路径信息(注意-Wl,和后面选项之间不能有空格)。如果没有--enable-new-dtags那么只会设置RPATH,反之,RPATH和RUNPATH会同时被设置。使用readelf -d a.out查看结果:
0x000000000000000f (RPATH) Library rpath: [/home/xxx]
0x000000000000001d (RUNPATH) Library runpath: [/home/xxx]
如果使用环境变量LD_LIBRARY_PATH,那么一般这样用 export
export LD_LIBRARY_PATH=/home/xxx;$LD_LIBRARY_PATH
RPATH和RUNPATH指定动态库的路径,用起来简单,但是也缺乏灵活性,LDLIBRARYPATH在临时测试的也是很有用的,但是在正式环境中,直接使用它也不是好的实践,因为环境变量跟用户的环境关系比较大。动态库不仅要考虑自己使用, 还有分发给别的用户使用的情况。
更通用的方法是使用ldconfig,有几种方法,先在/etc/ld.so.conf.d/目录下创建一个文件,然后把你的动态库路径写进去。或者将你的动态库放到/lib,/lib64(64位),/usr/lib,/usr/lib64(64位)然后运行sudo ldconfig重建/etc/ld.so.cache文件。
动态库版本
通常在使用第三方给的动态库的时候,都是带有版本(文件命名),可以在/usr/lib64下看到很多这样的动态库。现在我重新编译动态库,这次加上版本信息。
gcc -fPIC -shared -Wall -Wl,-soname,libelfhash.so.0 -o libelfhash.so.0.0.0 elfhash.c
每个动态库都有一个名字,如这里的libelfhash.so.0.0.0,叫real name,命名规则跟简单,通常是libxxx.so.MAJOR.MINOR.VERSION(有的时候VERSION会被省略),如果动态库在接口上的兼容性,比如删除了接口或者修改了接口参数,MAJOR增加,如果接口兼容,只是做了更新或者bug修复那么MINOR和VERSION增加。也是说MAJOR相同的库接口都是兼容的,反之不兼容,如果使用不兼容的动态库需要重新编译可执行程序。
编译动态库时,通过给ld传递连接选项-soname可以指定一个soname, 如这里的libelfhash.so.0 只保留MAJOR,可执行程序运行加载动态库时,会加载这个指定名字的库。
动态库还有一个名字是link name,编译可执行程序时,传个链接器ld的动态库名字,通常是没有版本号以.so结尾的文件名。 一般作法是对soname创建软链。
按照这个规则来命名的动态库可以ldconfig识别,我们把libelfhash.so.0.0.0放到/usr/lib64文件夹中,执行以下指令
$sudo ldconfig -v | grep libelfhash.so
libelfhash.so.0 -> libelfhash.so.0.0.0
可以发现ldconfig根据libelfhash.so.0.0.0的信息,创建了一个soname指向real name的软链,当动态库更新(MINOR,VERSION增加),拷贝新库到相应的位置,再执行sudo ldconfig会自动更新软链指向新的动态库,动态库更新完成了。
总结
OK,关于Linux动态库知识整理到这里了,这些知识虽说都是些基础,少有涉及动态库内部的一些原理,但是却很常用。整理过程中我带着疑问去阅读了ld和ld-linux.so的文档,收获颇丰。同样,希望本文能帮你解释遇到的部分问题或疑惑。
本文内容不用于商业目的,如涉及知识产权问题,请权利人联系SPASVO小编(021-61079698-8054),我们将立即处理,马上删除。
相关推荐
Linux下开源的DDR压力测试工具曝Linux恶意软件:让树莓派设备挖掘数字货币linux系统中不同颜色的文件夹及根目录介绍软件测试工程师必知必会Linux命令Linux下DNS服务器配置如何成为不可替代的Linux运维工程师?详解Linux进程(作业)的查看和杀死Linux 日志定时轮询流程详解比特币勒索病毒不只Windows系统有,Linux版的来了Linux日志定时轮询流程详解Linux iommu和vfio概念空间解构Linux系统如何低于TCP洪水攻击Linux无损调整分区大小Linux下防火墙配置实例Linux使用Jexus托管Asp.Net Core应用程序Linux中引号的那些事
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11热门文章
常见的移动App Bug??崩溃的测试用例设计如何用Jmeter做压力测试QC使用说明APP压力测试入门教程移动app测试中的主要问题jenkins+testng+ant+webdriver持续集成测试使用JMeter进行HTTP负载测试Selenium 2.0 WebDriver 使用指南