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
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
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:
Tag Type Name/Value
0x00000001 (NEEDED) Shared library: [libprint.so]
0x00000001 (NEEDED) Shared library: [libc.so.6]
0x0000000c (INIT) 0x8048344
0x0000000d (FINI) 0x80484e0
0x00000004 (HASH) 0x8048128
0x00000005 (STRTAB) 0x8048240
0x00000006 (SYMTAB) 0x8048170
0x0000000a (STRSZ) 178 (bytes)
0x0000000b (SYMENT) 16 (bytes)
0x00000015 (DEBUG) 0x0
0x00000003 (PLTGOT) 0x80495f8
0x00000002 (PLTRELSZ) 16 (bytes)
0x00000014 (PLTREL) REL
0x00000017 (JMPREL) 0x8048334
0x00000011 (REL) 0x804832c
0x00000012 (RELSZ) 8 (bytes)
0x00000013 (RELENT) 8 (bytes)
0x6ffffffe (VERNEED) 0x804830c
0x6fffffff (VERNEEDNUM) 1
0x6ffffff0 (VERSYM) 0x80482f2
0x00000000 (NULL) 0x0
[root@localhost ldpath]# readelf -d pfoo_r
Dynamic segment at offset 0x518 contains 22 entries:
Tag Type Name/Value
0x00000001 (NEEDED) Shared library: [libprint.so]
0x00000001 (NEEDED) Shared library: [libc.so.6]
0x0000000f (RPATH) Library rpath: [./]
0x0000000c (INIT) 0x8048348
0x0000000d (FINI) 0x80484e4
0x00000004 (HASH) 0x8048128
0x00000005 (STRTAB) 0x8048240
0x00000006 (SYMTAB) 0x8048170
0x0000000a (STRSZ) 181 (bytes)
0x0000000b (SYMENT) 16 (bytes)
0x00000015 (DEBUG) 0x0
0x00000003 (PLTGOT) 0x8049604
0x00000002 (PLTRELSZ) 16 (bytes)
0x00000014 (PLTREL) REL
0x00000017 (JMPREL) 0x8048338
0x00000011 (REL) 0x8048330
0x00000012 (RELSZ) 8 (bytes)
0x00000013 (RELENT) 8 (bytes)
0x6ffffffe (VERNEED) 0x8048310
0x6fffffff (VERNEEDNUM) 1
0x6ffffff0 (VERSYM) 0x80482f6
0x00000000 (NULL) 0x0
“readelf -d”可以用来查看ELF文件的动态节(Dynamic Section)。对比pfoo 和pfoo_r的结果我们可以发现,pfoo_r中多出来了RPATH项,指定”Library rpath: [./]”。通过这种方式,我们可以用非常小的代价(仅增加几乎可以忽略的空间开销),对每个ELF文件都指定最优化的搜索路径,达到提升性能的目的。这是我们比较推荐的一种方法。当然了,具体如果操作依赖于具体的软件系统的情况,简单的系统中直接将所有的库都放到/lib下也未尝不是一种简单易行的优化方案。
Linux下动态共享库加载时的搜索路径详解的更多相关文章
- 【转载】Linux下动态共享库加载时的搜索路径详解
转载自:http://www.eefocus.com/article/09-04/71617s.html 对动态库的实际应用还不太熟悉的读者可能曾经遇到过类似“error while loading ...
- <摘录>Linux下动态共享库加载时的搜索路径详解
对动态库的实际应用还不太熟悉的读者可能曾经遇到过类似“error while loading shared libraries”这样的错误,这是典型的因为需要的动态库不在动态链接器ld.so的搜索路径 ...
- Linux下动态共享库加载及使用详解【转】
原文地址:http://blog.chinaunix.net/uid-29025972-id-3855500.html 对动态库的实际应用还不太熟悉的读者可能曾经遇到过类似“error while l ...
- Linux下动态共享库加载及使用详解
转载;http://blog.chinaunix.net/uid-29025972-id-3855500.html 对动态库的实际应用还不太熟悉的读者可能曾经遇到过类似“error while loa ...
- linux共享库加载
参考自: <<程序员的自我修养--链接.装载与库>> 第八章 Linux共享库的组织 以下截取部分内容 (这本书比较好的讲解了从程序的链接,装载,到运行) 共享库的兼容性 li ...
- phpcms加载系统类与加载应用类之区别详解
<?php 1. 加载系统类方法load_sys_class($classname, $path = ''", $initialize = 1)系统类文件所在的文件路径:/phpcms ...
- Linux下高并发socket最大连接数所受的各种限制(详解)
1.修改用户进程可打开文件数限制 在Linux平台上,无论编写客户端程序还是服务端程序,在进行高并发TCP连接处理时,最高的并发数量都要受到系统对用户单一进程同时可打开文件数量的限制(这是因为系统为每 ...
- Linux下 ps -ef 和 ps aux 的区别及格式详解
原文:https://www.cnblogs.com/5201351/p/4206461.html Linux下ps -ef和ps aux的区别及格式详解 Linux下显示系统进程的命令ps,最常用的 ...
- linux动态库加载时搜索路径
摘自http://gotowqj.iteye.com/blog/1926613 对动态库的实际应用还不太熟悉的读者可能曾经遇到过类似“error while loading shared librar ...
随机推荐
- 转: IOS程序内发短信 MFMessageComposeViewController
文章转载地址:http://www.headsky.org/?p=63 iOS4.0新加入了MFMessageComposeViewController和MFMessageComposeViewCon ...
- Java 内存释放
问题一什么叫垃圾回收机制 垃圾回收是一种动态存储管理技术它自动地释放不再被程序引用的对象按照特定的垃圾收集算法来实现资源自动回收的功能.当一个对象不再被引用的时候内存回收它占领的空间 ...
- AndroidMainifest标签使用说明1——<action>
1.<action> 格式: <action android:name="string" /> 父标签: <intent-filter> 描写叙 ...
- python笔记30-docstring注释添加变量
前言 python里面添加字符串注释非常简单,如何将变量放入 python 的函数注释里面呢? docstring也就是给代码加注释的内容了,python可以给函数,类.方法,模块添加注释内容,注释标 ...
- Spring加载Hibernate 映射的几种方式及区别
LocalSessionFactoryBean有好几个属性用来查找hibernate映射文件: mappingResources.mappingLocations.mappingDirectoryLo ...
- 将 MRC 项目转换为 ARC 项目
其实很简单,直接使用系统工具转换即可,以下是步骤: 1. 你之前的项目是MRC的 2. 里面有 release, dealloc 等. 3. 开始转化 4. 点击save转化完后,记得把工程重新设置成 ...
- 使用 kubeadm 搭建 kubernetes1.10 集群
PS:所有节点安装之前记得先把镜像准备好,否者将无法启动,也不报错. $ cat /etc/hosts192.168.11.1 master192.168.11.2 node 禁用防火墙: $ sys ...
- 【BestCoder】【Round#42】
模拟+链表+DP Orz AK爷faebdc A Growin要跟全部的n个人握手共2n杯香槟,再加上每对关系的两杯香槟,直接统计邻接矩阵中1的个数,再加2n就是answer //BestCoder ...
- 用java查询HBase中某表的一批数据
java代码如下: package db.query; import java.io.IOException; import org.apache.hadoop.conf.Configuration; ...
- hbase数据模型以及编码压缩(转)
原文链接:hbase源码系列(四)数据模型-表定义和列族定义的具体含义 hbase是一个KeyValue型的数据库,在<hbase实战>描述它的逻辑模型[行键,列族,列限定符,时间版本], ...