日期:2014-05-16  浏览次数:20602 次

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:?
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?<