共享库查找过程

14 篇文章 1 订阅
6 篇文章 0 订阅
在开源系统中,包括所有的Linux系统在内的很多都是基于Glibc的。在这些系统里面,动态链接的ELF可执行文件在启动是同时会启动动态链接骑。在Linux系统中,动态链接器是/lib/ld-linux.so.X(X是版本号),程序所依赖的共享对象全部由动态链接器负责装载和初始化。任何一个动态链接的模块所依赖的模块路径保存在“.dynamic”段里,由DT_NEED类型的项表示。动态链接器对于模块的查找有一定的规则:如果DT_NEED里面保存的是绝对路径,那么动态链接器就按照这个路径去找;如果DT_NEED里面保存的是相对路径,那么动态链接器会在/lib、/usr/lib和由/etc/ld.so.conf配置文件指定的目录中查找共享库。为了程序的可移植性和兼容性,共享库的路径往往是相对的。

         ld.so.conf是一个纯文本配置文件,它可能包含其他的配置文件,这些配置文件中存放着用于搜寻共享库文件的路径的信息。比如,在我的机器上,该文件的内容为:
1.include /etc/ld.so.conf.d/*.conf
2./mnt/android_proj/hanpfei/lib

如果动态链接器在每次查找共享库时都去遍历这些目录,那将会非常耗费时间。所以,linux系统中有一个叫做ldconfig的程序,这个程序的作用是为共享库目录下的各个共享库创建、删除更新相应的SO-NAME(即相应的符号链接),这样每个共享库的SO-NAME就能够指向正确的共享库文件;并且 这个程序还会将这些SO-NAME收集起来,集中存放到/etc/ld.so.cache文件里面,以建立一个SO-NAME的缓存。当动态链接器要查找共享库时,它可以直接从/etc/ld.so.cache里面查找。而/etc/ld.so.cache的结构是经过特殊设计的,非常适合查找,所以这个设计大大加快了共享库的查找过程。

如果动态链接器在/etc/ld.so.cache里面没有找到所需要的共享库,那么它还会遍历/lib和/usr/lib这两个目录,如果还是没找到,就宣告失败。

所以,理论上讲,如果我们在系统指定的共享库目录下添加、删除或更新任何一个共享库,或者我们更改了/etc/ld.so.conf的内容,都应该运行ldconfig这个程序,以便调整SO-NAME和/etc/ld.so.cache:
1.hanpfei@hanpfei-F6Ve:/mnt/android_proj$ sudo ldconfig

动态链接相关环境变量对动态链接库查找过程的影响

LD_LIBRARY_PATH
使用LD_LIBRARY_PATH环境变量可以临时改变某个应用程序动态链接库的查找过程。在Linux系统中,LD_LIBRARY_PATH是一个由若干个路径组成的环境变量,每个路径之间由冒号隔开。默认情况下,
为空。如果我们为某个设置了LD_LIBRARY_PATH环境变量,那么进程在启动时,动态链接器在查找共享库时,会首先查找有LD_LIBRARY_PATH指定的目录。比如我们希望使用修改过的libs.so.6,可以将这个新版的libc放到我们的用户目录中,然后定义LD_LIBRARY_PATH环境变量:
1.hanpfei@hanpfei-F6Ve:/mnt/android_proj$ LD_LIBRARY_PATH=/home/user /bin/ls

Linux中还有一种可以实现与LD_LIBRARY_PATH环境变量类似的功能的方法,那就是直接运行动态链接器来启动程序,比如
1.hanpfei@hanpfei-F6Ve:/mnt/android_proj$ /lib/ld-linux.so.2 -library-path /home/user /bin/ls

LD_LIBRARY_PATH环境变量的定义,将使对于共享链接库的搜寻按照如下的顺序:
1、由环境变量LD_LIBRARY_PATH指定的路径。
2、由路径缓存文件/etc/ld.so.cache指定的路径。
3、默认的共享库目录,先/usr/lib,然后/lib。

随意修改LD_LIBRARY_PATH环境变量并将其导出至全局范围,将可能引起其他应用程序运行出现问题;LD_LIBRARY_PATH也会影响GCC编译时查找库的路径,它里面包含的目录相当于链接时GCC的"-L" 参数。

LD_PRELOAD
环境变量LD_PRELOAD,我们可以通过它指定预先装载的一些共享库或是目标文件。在LD_PRELOAD里面指定的文件会在动态链接器按照固定规则搜索共享库之前装载,它比LD_LIBRARY_PATH里面所指定的目录中存在的共享库的优先级还要高。无论程序是否依赖于它们,LD_PRELOAD里面所指定的共享库或目标文件都会被装载。

由于全局符号介入这个机制的存在,LD_PRELOAD里面指定的共享库或目标文件中的全局符号就会覆盖后面的同名全局符号,这使得我们方便的做到改写标准C库中的某个或某几个函数而不影响其他函数,这对于程序的调试或测试非常有用。同样正常情况下,应该尽量避免使用LD_PRELOAD环境变量。

指定LD_PRELOAD时,各个动态链接库之间的分割符是什么?是否和LD_LIBRARY_PATH一样是冒号?

系统配置文件中有一个文件是/etc/ld.so.preload,它的作用与LD_PRELOAD一样,在这个文件里面记录共享库或目标文件的效果跟定义LD_PRELOAD环境变量一样。

方便动态链接过程调试的LD_DEBUG环境变量

LD_DEBUG这个环境变量可以打开动态链接器的调试功能。当我们设置这个环境变量时,动态链接器会在运行时打印各种有用的信息,对于我们开发和调试共享库有很大的帮助。比如我们可以将LD_DEBUG设置成“files”,并且运行任何一个程序:
1.hanpfei@hanpfei-F6Ve:/mnt/android_proj$ export LD_DEBUG=files
2.hanpfei@hanpfei-F6Ve:/mnt/android_proj$ ls
3.5337: 
4.5337: file=libselinux.so.1 [0]; needed by ls [0]
5.5337: file=libselinux.so.1 [0]; generating link map
6.5337: dynamic: 0x00919ea8 base: 0x008fd000 size: 0x0001db7c
7.5337: entry: 0x00900f40 phdr: 0x008fd034 phnum: 8
8.5337: 
9.5337: 
10.5337: file=librt.so.1 [0]; needed by ls [0]
11.5337: file=librt.so.1 [0]; generating link map
12.5337: dynamic: 0x00891ef0 base: 0x0088a000 size: 0x00008254
13.5337: entry: 0x0088b8b0 phdr: 0x0088a034 phnum: 9
14.5337: 
15.5337: 
16.5337: file=libacl.so.1 [0]; needed by ls [0]
17.5337: file=libacl.so.1 [0]; generating link map
18.5337: dynamic: 0x00d3fef4 base: 0x00d38000 size: 0x00008140
19.5337: entry: 0x00d39480 phdr: 0x00d38034 phnum: 7
20.5337: 
21.5337: 
22.5337: file=libc.so.6 [0]; needed by ls [0]
23.5337: file=libc.so.6 [0]; generating link map
24.5337: dynamic: 0x005f3d7c base: 0x0047c000 size: 0x0017ba18
25.5337: entry: 0x00495270 phdr: 0x0047c034 phnum: 10
26.5337: 
27.5337: 
28.5337: file=libdl.so.2 [0]; needed by /lib/i386-linux-gnu/libselinux.so.1 [0]
29.5337: file=libdl.so.2 [0]; generating link map
30.5337: dynamic: 0x0096aec0 base: 0x00967000 size: 0x00004078
31.5337: entry: 0x00967a60 phdr: 0x00967034 phnum: 9
32.5337: 
33.5337: 
34.5337: file=libpthread.so.0 [0]; needed by /lib/i386-linux-gnu/librt.so.1 [0]
35.5337: file=libpthread.so.0 [0]; generating link map
36.5337: dynamic: 0x00e81eb4 base: 0x00e6a000 size: 0x0001a208
37.5337: entry: 0x00e6fb80 phdr: 0x00e6a034 phnum: 9
38.5337: 
39.5337: 
40.5337: file=libattr.so.1 [0]; needed by /lib/i386-linux-gnu/libacl.so.1 [0]
41.5337: file=libattr.so.1 [0]; generating link map
42.5337: dynamic: 0x009bff0c base: 0x009bb000 size: 0x00005068
43.5337: entry: 0x009bbc40 phdr: 0x009bb034 phnum: 7
44.5337: 
45.5337: 
46.5337: calling init: /lib/i386-linux-gnu/libpthread.so.0
47.5337: 
48.5337: 
49.5337: calling init: /lib/i386-linux-gnu/libc.so.6
50.5337: 
51.5337: 
52.5337: calling init: /lib/i386-linux-gnu/libattr.so.1
53.5337: 
54.5337: 
55.5337: calling init: /lib/i386-linux-gnu/libdl.so.2
56.5337: 
57.5337: 
58.5337: calling init: /lib/i386-linux-gnu/libacl.so.1
59.5337: 
60.5337: 
61.5337: calling init: /lib/i386-linux-gnu/librt.so.1
62.5337: 
63.5337: 
64.5337: calling init: /lib/i386-linux-gnu/libselinux.so.1
65.5337: 
66.5337: 
67.5337: initialize program: ls
68.5337: 
69.5337: 
70.5337: transferring control: ls
71.5337: 
72.android_src Document font_language hanpfei lost+found Musics myproject softwares workspace

动态链接器打印出了整个装载过程,显示程序依赖与哪个共享库,并且按照什么步骤来装载和初始化,共享库装载时的地址等。LD_DEBUG环境变量还可以设置成其他值,比如:
“bindings”显示动态链接的符号绑定过程。
"libs"显示共享库的查找过程。
“versions”显示符号的版本依赖关系。
“reloc“显示重定位过程。
”symbols“显示符号表查找过程。
”statistics“显示动态链接过程中的各种统计信息。
”all“显示以上所有信息。
”help“显示上面的各种可选值的帮助信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值