linux动态库加载时搜索路径
?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?
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下也未尝不是一种简单易行的优化方案。相关链接
???各家IC厂商财报大PK
- 诺西完成首个LTE切换测试
- Cree:LED供不应求是长期问题
- IBM给我们的启示在哪里
- 中国首台千万亿次计算机诞生?常用MCU产品选型
- 高交会热点抢“鲜”看
- ADC设计全接触
- NI LabVIEW 2009助您超越
- wimax09:侃技术谈发展10.?【ADS2005A视频讲解】[安捷伦公司...