Linux下動態共享庫 連線和載入路徑

2021-06-20 13:39:28 字數 4868 閱讀 4543

1. 連線時找不到某乙個函式,出現「 ***xx undefined」,應該就是連線時找不到相應的動態庫,連線時動態庫的路徑如下:

1> 預設路徑是:/lib,  /usr/lib/,  /usr/local/lib

2> -l: 指定連線時動態庫的路徑

3> ld_library_path:  指定連線路徑

2. 執行應用程式時出現「

error

while loading shared libraries」,則是載入時找不到相應的動態庫

下面的文章詳細介紹了動態庫的載入路徑:

對動態庫的實際應用還不太熟悉的讀者可能曾經遇到過類似「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

23  void print_foo()

4  注意將它編譯成共享庫:

# 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

23  extern void print_foo();

45  int main()

6  編譯之後的執行結果如下:

# 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) 

0x00x00000003 (pltgot) 

0x80495f8

0x00000002 (pltrelsz) 

16 (bytes)

0x00000014 (pltrel) 

rel0x00000017 (jmprel) 

0x8048334

0x00000011 (rel) 

0x804832c

0x00000012 (relsz) 

8 (bytes)

0x00000013 (relent) 

8 (bytes)

0x6ffffffe (verneed) 

0x804830c

0x6fffffff (verneednum) 

10x6ffffff0 (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) 

0x00x00000003 (pltgot) 

0x8049*

0x00000002 (pltrelsz) 

16 (bytes)

0x00000014 (pltrel) 

rel0x00000017 (jmprel) 

0x8048338

0x00000011 (rel) 

0x8048330

0x00000012 (relsz) 

8 (bytes)

0x00000013 (relent) 

8 (bytes)

0x6ffffffe (verneed) 

0x8048310

0x6fffffff (verneednum) 

10x6ffffff0 (versym) 

0x80482f6

0x00000000 (null) 

0x0「readelf -d」可以用來檢視elf檔案的動態節(dynamic section)。對比pfoo 和pfoo_r的結果我們可以發現,pfoo_r中多出來了rpath項,指定」library rpath: [./]」。通過這種方式,我們可以用非常小的代價(僅增加幾乎可以忽略的空間開銷),對每個elf檔案都指定最優化的搜尋路徑,達到提公升效能的目的。這是我們比較推薦的一種方法。當然了,具體如果操作依賴於具體的軟體系統的情況,簡單的系統中直接將所有的庫都放到/lib下也未嘗不是一種簡單易行的優化方案。

Linux下動態共享庫 連線和載入路徑

1.連線時找不到某乙個函式,出現 xx undefined 應該就是連線時找不到相應的動態庫,連線時動態庫的路徑如下 1 預設路徑是 lib,usr lib usr local lib 2 l 指定連線時動態庫的路徑 3 ld library path 指定連線路徑 2.執行應用程式時出現 erro...

linux下的共享庫(動態庫)和靜態庫

linux下的共享庫 動態庫 和靜態庫 1.什麼是庫 在windows平台和linux平台下都大量存在著庫。本質上來說庫是一種可執行 的二進位制形式,可以被作業系統載入記憶體執行。由於windows和linux的本質不同,因此二者庫的二進位制是不相容的。本文僅限於介紹linux下的庫。2.庫的種類 ...

linux下的共享庫(動態庫)和靜態庫

說很基礎,但很重要!原文 1.什麼是庫 在windows平台和linux平台下都大量存在著庫。本質上來說庫是一種可執行 的二進位制形式,可以被作業系統載入記憶體執行。由於windows和linux的本質不同,因此二者庫的二進位制是不相容的。本文僅限於介紹linux下的庫。2.庫的種類 linux下的...