<摘录>Linux下动态共享库加载时的搜索路径详解
对动态库的实际应用还不太熟悉的读者可能曾经遇到过类似“error while loading shared libraries”这样的错误,这是典型的因为需要的动态库不在动态链接器ld.so的搜索路径设置当中导致的。
具体说来,动态链接器ld.so按照下面的顺序来搜索需要的动态共享库:
1.ELF可执行文件中动态段中DT_RPATH所指定的路径。这实际上是通过一种不算很常用,却比较实用的方法所设置的:编译目标代码时,可以对gcc加入链接参数“-Wl,-rpath”指定动态库搜索路径;
2.环境变量LD_LIBRARY_PATH指定的动态库搜索路径;
3./etc/ld.so.cache中所缓存的动态库路径(如果支持ld.so.cache的话)。这可以通过修改配置文件/etc/ld.so.conf中指定的动态库搜索路径来改变;
4.默认的动态库搜索路径/lib;
5.默认的动态库搜索路径/usr/lib。
在嵌入式Linux系统的实际应用中,1和2被经常使用,也有一些相对简单的的嵌入式系统会采用4或5的路径来规范动态库。3在嵌入式系统中使用的比较少,因为有很多系统根本就不支持ld.so.cache。
4和5的方式非常简单,只要将所需要的库放到/lib或/usr/lib就可以解决找不到库的问题,不过对于大一些的系统来说,不太方便管理。1和2的方式要稍微复杂一些,下面我们用一个非常简单的例子来说明如何应用。
首先编写一个最简单的动态共享库,源代码pirnt.c如下:
1 #include <stdio.h> 2 3 void print_foo() 4 { 5 printf("fooooooooo\n"); 6 } |
注意将它编译成共享库:
# gcc print.c -shared -o libprint.so # file libprint.so libprint.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), not stripped |
调用该共享库main.c代码如下:
1 #include <stdio.h> 2 3 extern void print_foo(); 4 5 int main() 6 { 7 print_foo(); 8 9 return 0; 10 } |
编译之后的运行结果如下:
# gcc main.c -L./ -lprint -o pfoo # ./pfoo ./pfoo: error while loading shared libraries: libprint.so: cannot open shared object file: No such file or directory |
这便是典型的找不到动态库的错误。通常我们可以通过设置环境变量LD_LIBRARY_PATH来指定动态库的搜索路径(即上面的方法2),比如这样就可以正确运行了:
# export LD_LIBRARY_PATH=./ # ./pfoo fooooooooo |
但这种方法有一个明显的缺点:一旦LD_LIBRARY_PATH被设定,则在这个环境变量生效的范围之内,所有其他的ELF可执行程序也会按照这个顺序去搜索动态库,这样势必会造成搜索时的一些浪费。
我们也可以使用另外一种方案来解决这种问题,即利用参数“-Wl,-rpath”在编译时指定运行时的搜索路径(即上面的方法1),如下所示:
# unset LD_LIBRARY_PATH # echo $LD_LIBRARY_PATH # gcc main.c -L./ -lprint -o pfoo_r -Wl,-rpath=./ # ./pfoo ./pfoo: error while loading shared libraries: libprint.so: cannot open shared object file: No such file or directory # ./pfoo_r fooooooooo |
我们首先unset了LD_LIBRARY_PATH,可以看到它已经不再有效了(当然这不是使用参数“-Wl,-rpath”的必要步骤,在这里只是为
了说明它已经不再起作用了),而且”pfoo”程序运行时也会发生找不到库的错误,而我们加入编译参数“-Wl,-rpath,./”之后得到的
pfoo_r程序则能正常运行。
事实上我们可以通过readelf工具来查看两个文件的差异:
# readelf -d pfoo
Dynamic segment at offset 0x514 contains 21 entries: |
“readelf -d”可以用来查看ELF文件的动态节(Dynamic Section)。对比pfoo
和pfoo_r的结果我们可以发现,pfoo_r中多出来了RPATH项,指定”Library rpath:
[./]”。通过这种方式,我们可以用非常小的代价(仅增加几乎可以忽略的空间开销),对每个ELF文件都指定最优化的搜索路径,达到提升性能的目的。这
是我们比较推荐的一种方法。当然了,具体如果操作依赖于具体的软件系统的情况,简单的系统中直接将所有的库都放到/lib下也未尝不是一种简单易行的优化方案。
最新文章
- wpf模仿QQ表情
- MVC使用x.PagedList分页
- 我收录整理的优秀OC技术类文章
- dg
- EF架构~XMLRepository仓储的实现
- linux 添加用户、权限
- xcode更新,想想也是醉了
- linux Ubuntu安装后没有引导 解决方案
- PHPCMS v9修改栏目或者单页没有权限
- 基于MAC OS 操作系统安装、配置mysql
- Nginx反向代理实现Tomcat负载均衡
- 享元模式-Flyweight(Java实现)
- sed memo 2
- C# 虹软离线SDK引擎 人脸识别
- python学习疑问
- git checkout 命令详解【转】
- HDU 5402(Travelling Salesman Problem-构造矩阵对角最长不相交路径)
- 常用的一些sql
- MVC 中创建简单过滤器
- 题解 P5015 【标题统计】