linux 關於動態庫的知識

2022-05-08 17:03:10 字數 3674 閱讀 8702

問題起緣於編譯乙個程式時,使用glib2-2.28.8的動態庫,而系統自帶的是glib2-2.22.5

不想公升級系統的glib2庫,而使用程式自帶庫檔案的方式載入(類似windows系統,優先載入當前目錄的dll檔案)。

1.首先編譯時,使用-l指定lib路徑,-lglib-2.0指定庫檔名

2.執行時通過,ld_library_path=./ 指定搜尋當前目錄為庫目錄

3.測試發現使用的是系統的庫

ldd ./test

linux-vdso.so.1 => (0x00007fff86fff000)

libglib-2.0.so.0 => /lib64/libglib-2.0.so.0 (0x00007f386e16c000)

libgmodule-2.0.so.0 => /lib64/libgmodule-2.0.so.0 (0x00007f386df68000)

libz.so.1 => /lib64/libz.so.1 (0x00007f386dd52000)

libc.so.6 => /lib64/libc.so.6 (0x00007f386d9bf000)

libdl.so.2 => /lib64/libdl.so.2 (0x00007f386d7bb000)

/lib64/ld-linux-x86-64.so.2 (0x00007f386e45f000)

失敗,懷疑是ld_library_path指定的庫路徑,處於搜尋路徑的佇列尾部,造成優先找到系統的庫,那麼可不可以通過修改「鏈結的庫檔名」,達到目的了

1.修改libglib-2.0.so檔案為libmyglib.so,鏈結時使用-lmyglib指定鏈結庫

2.執行時通過,ld_library_path=./ 指定搜尋當前目錄為庫目錄

3.測試發現我定義的庫居然沒有出現,而且還使用來系統的glib2庫

ldd ./test 

linux-vdso.so.1 => (0x00007fff86fff000)

libglib-2.0.so.0 => /lib64/libglib-2.0.so.0 (0x00007f386e16c000)

libgmodule-2.0.so.0 => /lib64/libgmodule-2.0.so.0 (0x00007f386df68000)

libz.so.1 => /lib64/libz.so.1 (0x00007f386dd52000)

libc.so.6 => /lib64/libc.so.6 (0x00007f386d9bf000)

libdl.so.2 => /lib64/libdl.so.2 (0x00007f386d7bb000)

/lib64/ld-linux-x86-64.so.2 (0x00007f386e45f000)

查詢資料後發現,「對於動態庫,實際鏈結發生在執行時而不是編譯和鏈結時」,好吧,我理解。

那麼編譯的時候,

難道沒有把程式要使用到的動態庫檔名稱,記錄到程式內部??

就像windows下,缺少某個dll,程式會提示缺少dll檔案的檔名。

於是又查詢資料發現  「

生成可執行檔案時,如果鏈結的是靜態庫,那麼鏈結器會按照靜態鏈結規則,將對應的符號引用進行重定位。而如果是動態庫,鏈結器會將這個符號標記為動態鏈結的符號,不進行重定位,而是在裝載時再進行。所以,儘管是動態鏈結,如果是已經進入到了鏈結階段,那麼也需要能在相應的.so中找到某符號的定義,否則也會引發undefined reference to的鏈結錯誤。因為鏈結器只有通過.so檔案,才能判斷某符號是個動態鏈結符號,所以也需要讀取這些.so檔案,找到相應符號的定義」

意思就是,聯結器只是做確認函式符號可用,就編譯通過來,更本沒記錄動態庫的檔名,這點和windows不一樣

而實際執行裝載的時候,只通過函式符號,裝載需要的.so就可以來,索引我定義的libmyglib.so又被沒有機會裝載進來,被系統的替代了。

知道問題原因,解決方法有2個

1.解決載入順序的問題,ld_preload可以實現

ld_library_path 將其他目錄加入庫搜尋路徑。它的內容應該是由冒號

分隔的目錄列表,與可執行檔案的 path 變數具有相同的格式。

如果呼叫設定使用者 id 或者程序 id 的程式,該變數被忽略。

ld_preload 首先裝入使用者定義的庫,使得它們有機會覆蓋或者重新定義標準庫。

export ld_preload=./libglib.so:./libgmodule.so

ldd ./test

linux-vdso.so.1 => (0x00007fffc31ff000)

./libglib.so (0x00007ffa5d757000)

./libgmodule.so (0x00007ffa5d553000)

libz.so.1 => /lib64/libz.so.1 (0x00007ffa5d330000)

libc.so.6 => /lib64/libc.so.6 (0x00007ffa5cf9d000)

librt.so.1 => /lib64/librt.so.1 (0x00007ffa5cd95000)

libdl.so.2 => /lib64/libdl.so.2 (0x00007ffa5cb91000)

/lib64/ld-linux-x86-64.so.2 (0x00007ffa5da6e000)

libpthread.so.0 => /lib64/libpthread.so.0 (0x00007ffa5c974000)

2.替換系統的glib2庫,有三種方式,最好使用第一種,其他方式會遺留垃圾

2.1公升級安裝覆蓋

2.2直接拷貝.so覆蓋,或更改libglib-2.0.so.0鏈結的指向

2.3共享當前版本的庫的系統 sudo ldconfig  /opt/glib-2.28.8/lib

ldd ../bin/test

linux-vdso.so.1 => (0x00007fff897ff000)

libglib-2.0.so.0 => /opt/glib-2.28.8/lib/libglib-2.0.so.0 (0x00007f59f5f02000)

libgmodule-2.0.so.0 => /opt/glib-2.28.8/lib/libgmodule-2.0.so.0 (0x00007f59f5cfe000)

libz.so.1 => /lib64/libz.so.1 (0x00007f59f5ae8000)

libc.so.6 => /lib64/libc.so.6 (0x00007f59f5755000)

librt.so.1 => /lib64/librt.so.1 (0x00007f59f554d000)

libdl.so.2 => /lib64/libdl.so.2 (0x00007f59f5349000)

/lib64/ld-linux-x86-64.so.2 (0x00007f59f6226000)

libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f59f512c000)

ld_preload環境變數指定的共享庫會被預先載入,如果出現重名的函式,預先載入的函式將會被呼叫,如在預先載入的庫中包含自定義的puts函式,則在執行程式時將使用自定義版本的puts函式,而不是libc庫中的puts函式。

列出鏈結符號

nm -du /lib64/libglib-2.0.so.0 

vc 關於動態庫的哪些知識

專案開發都是分模組的,所以常常需要些個動態庫方便別人呼叫。這兩天因為專案整合,因為是組長負責整合我只需要跟進就可以,模組有問題需要及時調整的。所以上班的時候有零碎的時間。就看看公司的一些 然後有感而發,就把動多型庫的知識看了一下。下面是一些心得 都是從乙個文章摘抄的一些東西,pdf我會上傳的 1.靜...

Linux 關於靜態庫和動態庫

為什麼要使用庫?如何使用庫 靜態庫與動態庫 查詢c標準靜態庫 find usr lib name libc.a查詢c標準動態庫 find usr lib name libc.so 如何給別人提供乙個靜態庫 首先要自己提供一套方法,然後打包。就以add函式和sub函式為例,說明如何給別人提供乙個靜態庫...

關於linux動態鏈結庫

找工作之餘,把apue上乙個簡單面向連線的socket程式寫了下。上面用到別的章節的函式直接都用的extern,因為前天面試問我動態鏈結庫了,就想這讓用到的這些外部函式,直接動態鏈結。順便學習下,怎麼編譯動態鏈結庫的。沒學習那麼深,只是知道怎麼製作,應用就好,可中間還是碰到了點小問題。要判斷乙個程式...