Linux動態庫的查找路徑


前兩天寫了一個動態庫,然后試圖編譯到程序里面去運行,結果發現編譯的時候通過gcc的-L參數來指定路徑僅僅能讓編譯通過,運行時還是會出問題的。

比如下面這個例子:

main.c是主程序,sum.c中間含有一個函數add,用來執行加法,代碼如下:

 1 /*
 2  *  main.c
 3  */
 4 #include <stdio.h>
 5 
 6 int add(int a, int b);
 7 
 8 int main(int argc,char *argv[])
 9 {
10     printf("sum = %d\n", add(3,5));
11     return 0;
12 }

 

1 /*
2  * sum.c
3  */
4 int add(int a, int b)
5 {
6     return a + b;
7 }

 

出錯結果如下圖所示:

我在編譯的時候通過-L指定了查找動態庫的位置,結果運行的時候還是找不到我自己寫的那個libsum.so這個動態庫,后來去查了一下,才明白其中原委。

程序在鏈接動態庫的時候分為2步,編譯時鏈接和運行時鏈接。

1. 編譯時鏈接

  這個過程是由ld程序來執行的,所以編譯時找不到動態庫的位置的話,經常就會看到這種錯誤:

  

  這個過程嚴格意義上來說並不能說是鏈接,因為在這里ld程序並沒有真正的把庫里面的函數的執行代碼寫到可執行文件里面,只是把一些符號還有其他的必要信息寫道了可執行文件里面,供可執行文件運行時查找。

  總的來說,ld在這一步里面就是做了兩個事情:

  1. 查找動態庫中是否含有我們需要的符號(函數和全局變量),如果都能找到,則鏈接允許通過,生成了可執行文件。

  2. 在可執行文件中寫入了符號和其他必要的信息(例如符號的地址),供可執行文件運行時查找。

2. 運行時鏈接

  這個過程是由ld-linux.so程序來執行,這個才是真正的鏈接。它所做的工作就是將動態庫的代碼映射到進程(可執行文件運行起來就是進程啦...)的虛擬地址空間中,供進程來調用。

 

關於鏈接,加載,運行的更多信息可以參看<參考文章1>(詳細地址見本文最后)。

 

OK,明白了上面兩個鏈接之后,我們再來看這兩個鏈接查找動態庫的目錄位置,如下:

運行時,ld-linux.so查找共享庫的順序

(1)ld-linux.so.6在可執行的目標文件中被指定,可用readelf命令查看 
(2)ld-linux.so.6缺省在/usr/lib和lib中搜索;當glibc安裝到/usr/local下時,它查找/usr/local/lib
(3)LD_LIBRARY_PATH環境變量中所設定的路徑 
(4)/etc/ld.so.conf(或/usr/local/etc/ld.so.conf)中所指定的路徑,由ldconfig生成二進制的ld.so.cache中

編譯時,ld-linux.so查找共享庫的順序

(1)ld-linux.so.6由gcc的spec文件中所設定 
(2)gcc --print-search-dirs所打印出的路徑,主要是libgcc_s.so等庫。可以通過GCC_EXEC_PREFIX來設定 
(3)LIBRARY_PATH環境變量中所設定的路徑,或編譯的命令行中指定的-L/usr/local/lib 
(4)binutils中的ld所設定的缺省搜索路徑順序,編譯binutils時指定。(可以通過“ld --verbose | grep SEARCH”來查看) 
(5)二進制程序的搜索路徑順序為PATH環境變量中所設定。一般/usr/local/bin高於/usr/bin
(6)編譯時的頭文件的搜索路徑順序,與library的查找順序類似。一般/usr/local/include高於/usr/include

 

大家注意編譯時查找的路徑可以通過gcc -L參數或者LIBRARY_PATH來指定,但是運行時的查找路徑卻不包含gcc -L和LIBRARY_PATH環境變量指定的路徑,所以這樣就會出現我們剛開始所說的那個問題,編譯時通過-L指定了動態庫的搜索路徑,編譯也通過了,但是運行時卻會報錯,這是因為運行時查找動態庫的路徑還沒指定,所以我們自己寫的動態庫就找不到了,而要解決這個問題,通過設置環境變量LD_LIBRARY_PATH或者修改/etc/ld.so.conf(記得修改完了運行ldconfi來生成ld.so.cache)就可以了。如下圖所示:

 

參考文章:

1.  C編譯器、鏈接器、加載器詳解

2.  ld-linux.so查找共享庫的順序

3.  readelf命令

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM