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下也未嘗不是一種簡單易行的優化方案。
?
轉載http://www.cnblogs.com/skyofbitbit/p/3688299.html
轉載于:https://www.cnblogs.com/bigbear1385/p/6638249.html
總結
以上是生活随笔為你收集整理的Linux下动态共享库加载时的搜索路径详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 企业必须由真正在乎它的人掌控
- 下一篇: js的apply方法使用详解,绝对NB