摘自http://gotowqj.iteye.com/blog/1926613

对动态库的实际应用还不太熟悉的读者可能曾经遇到过类似“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> 

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> 

3 extern void print_foo(); 

5
int main() 
6 { 
7 print_foo(); 

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)

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)

0x6ffffff0 (VERSYM) 0x80482f6 
0x00000000 (NULL)
0x0

“readelf -d”可以用来查看ELF文件的动态节(Dynamic
Section)。对比pfoo 和pfoo_r的结果我们可以发现,pfoo_r中多出来了RPATH项,指定”Library rpath:
[./]”。通过这种方式,我们可以用非常小的代价(仅增加几乎可以忽略的空间开销),对每个ELF文件都指定最优化的搜索路径,达到提升性能的目的。这是我们比较推荐的一种方法。当然了,具体如果操作依赖于具体的软件系统的情况,简单的系统中直接将所有的库都放到/lib下也未尝不是一种简单易行的优化方案。

linux动态库加载时搜索路径的更多相关文章

  1. linux动态库加载RPATH, RUNPATH

    摘自http://gotowqj.iteye.com/blog/1926771 linux动态库加载RPATH, RUNPATH 链接动态库 如何程序在连接时使用了共享库,就必须在运行的时候能够找到共 ...

  2. Linux 动态库加载

    动态库运行时搜索顺序 1.LD_PRELOAD LD_PRELOAD是一个环境变量,用于动态库加载,动态库加载的优先级最高: 2.-wl,-rpath 编译目标代码时指定的动态库搜索路径(指的是用-w ...

  3. linux动态库加载的秘密

    摘自http://gotowqj.iteye.com/blog/1926734 摘自http://www.360doc.com/content/14/0313/13/12747488_36024641 ...

  4. linux 动态库加载路径修改

    1.在 /etc/ld.so.conf 文件中添加搜索路径,重启或者 ldconfig 生效: 2.在 /etc/ld.so.conf.d 目录下添加 *.conf 文件,其中可以添加搜索路径,重启获 ...

  5. linux动态库加载路径修改

    1.在 /etc/ld.so.conf 文件中添加搜索路径,重启或者 ldconfig 生效: 2.在 /etc/ld.so.conf.d 目录下添加 *.conf 文件,其中可以添加搜索路径,重启获 ...

  6. 动态库加载时GetLasterror();值总是126的原因

    1.dll路径不正确,导致找不到dll文件. 2.有可能是你要载入的DLL在内部还需要载入其它的dll,而它不存在,同样会返回126错误代码.比如一个你给系统添加了一个PCI设备,像AD采集卡之类的, ...

  7. linux和windows动态库加载路径区别

    # linux和windows动态库加载路径区别 ### 简介------------------------------ linux加载动态库的路径是系统目录/lib和/usr/lib.- wind ...

  8. libdl.so 动态库加载、查找

    使用libdl.so库 动态库加载原理   动态库中函数的查找已经封装成 libdl.so,有4个函数: dlopen  : 打开一个动态库 dlsym   : 在打开的动态库里找一个函数 dlclo ...

  9. 【转载】Linux下动态共享库加载时的搜索路径详解

    转载自:http://www.eefocus.com/article/09-04/71617s.html 对动态库的实际应用还不太熟悉的读者可能曾经遇到过类似“error while loading ...

随机推荐

  1. 在Activity中响应ListView内部按钮的点击事件的两种方法!!!

    在Activity中响应ListView内部按钮的点击事件的两种方法 转载:http://www.cnblogs.com/ivan-xu/p/4124967.html 最近交流群里面有人问到一个问题: ...

  2. tomcat,tomcat7配置https

    <一,>,tomcat7配置https 1,生成keystore文件及导出证书

  3. Qt Creator编译时:cannot open file 'debug\QtGuiEx.exe' File not found

    Qt Creator编译时:cannot open file 'debug\QtGuiEx.exe' File not found 利用Qt Creator编译工程时,出现如题目所示的错误,其中红色部 ...

  4. Python常用模块(time, datetime, random, os, sys, hashlib)

    time模块 在Python中,通常有这几种方式来表示时间: 时间戳(timestamp) :         通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量.我们运 ...

  5. android面试题集1

    Android 面试题(有详细答案) 附带答案,共100分 一.选择题(30题,每题1.5分,共45分) 1.java.io包中定义了多个流类型来实现输入和输出功能,可以从不同的角度对其进行分类,按功 ...

  6. 多媒体封装格式----mkv

    Matroska 开源多媒体容器标准.MKV属于其中的一部分.Matroska常见的有.MKV视频格式.MKA音频格式..MKS字幕格式..MK3D files (stereoscopic/3D vi ...

  7. sublime 快键

    Keyboard Shortcuts - Windows/Linux Warning This topic is a draft and may contain wrong information. ...

  8. iframe 重新加载闪过白块问题

    在使用iframe时,iframe背景为白块,刷新时也会闪过白块.如果刷新时间长,就会一直出现白块,让人很烦恼,通过网上搜资料,测试最终解决方法如下所示,注意主要针对IE浏览器测试. 一.iframe ...

  9. git-svn 的使用

    从 SVN 克隆代码 git svn clone https://192.168.1.3/svn/project-name   git-svn 初始化 git svn init (svn remote ...

  10. ajax数据显示,使用js通用模板

    最近用ajax获取数据,上级要求要自己写一个js模板,以往看到的js模板,大都数都是在js里面拼接的,现在换一种比较简单的写法, 通过ajax获取数据源,js模板循环显示数据 function Get ...