《程式設計師自我修養》閱讀筆記 動態鏈結

2021-09-07 23:13:00 字數 2055 閱讀 4519

1、動態鏈結的含義。動態鏈結就是將鏈結時的重定位推遲到載入時。相比於靜態鏈結,動態鏈結的乙個優點是可以節省記憶體。因為共享檔案的**可以共享。使用動態鏈結的時候,可執行檔案和共享檔案都會載入到記憶體。但是,如果很多可執行檔案都使用了同乙個共享檔案的時候,共享檔案的**部分只需要裝載一次,這樣就達到了節省記憶體的目的。在這裡,共享檔案的資料部分在每個可執行檔案中都要儲存乙份。所以,共享檔案中跟自己的資料有關的**就可能會變化,因為資料的位址不確定。一旦變化,就不能達到**共享的目的了。所以,在這裡,一般共享檔案是位址無關**。

2、位址無關**。目的是指令部分在裝載時不需要因為裝載位址的改變而改變,所以應該把指令中那些需要修改的部分分離出來跟資料放在一起,這樣指令部分就可以保持不變。這種技術就叫位址無關**技術。下面分幾種情況介紹如何實現位址無關:

(1)模組內部的資料訪問。模組內部的指令和該指令要訪問的資料之間的距離是固定的,但是又不能使用絕對位址,因為共享檔案最後載入的位址不能確定,所以這時候該指令的位址加上乙個差值就能訪問到資料了。

(2)模組間的資料訪問。其他模組的資料的位址到了裝載時才能確定,所以此時的做法是在資料段裡建立乙個指向這些變數的陣列(全域性偏移表got),等到裝載的時候由動態鏈結器來負責填寫got中的資料。因為got是在自己這個模組的資料段裡,所以這個got的位址在編譯的時候就可以確定,所以got相應於指令的偏移是確定的。

(3)模組間的函式訪問。模組間的函式訪問跟模組間的資料訪問差不多,也是將其他模組的函式位址放到got裡。

(4)模組內部的函式訪問。這個跟模組內部的資料訪問可能看起來差不多。但是實際上不太一樣。因為linux有乙個問題叫做全域性符號介入,比如說可執行檔案需要共享檔案a和b,但是a和b都都定義了函式f(),這時候不會報錯,動態鏈結器會簡單地用其中的乙個函式覆蓋另乙個,也就是說這時候本模組中的函式不一定就是最後鏈結後使用的函式,這時候,編譯器會把這種情況當做(3)來處理,即將這個函式加入got裡。

3、延遲繫結。在裝載的時候將所有的函式引用進行重定位是一種浪費,因為可能有些函式在整個執行過程中不會用到。elf使用一種叫做plt的方法來實現延遲繫結。有乙個專門的段叫做.got.plt,所有引用的外部函式都放在這個裡,而不是.got裡。.got.plt的前三項是固定的,第一項是.dynamic段的位址,第二項是本模組的id,第三項是_dl_runtime_resolve的位址,這個函式進進行符號解析和重定位工作的。.got.plt後面的項是外部函式的引用,每一項中存放了三條指令(假設外部函式是bar):

jmp *(bar@got)

push n

jump plt0

其中plt0的內容是:

push *(got+4)

jump *(got+8)

n指的是bar函式在重定位表中的下標,got+4的位置是本模組的位址,got+8的是_dl_runtime_resolve。初始時,bar@got存放的不是bar函式的真實位址,而是「push n」這條指令的位址,第一次呼叫bar函式時會進行繫結,_dl_runtime_resolve會把bar函式真實的位址寫入bar@got,寫入之後應該呼叫該函式。

4 、在動態鏈結中,作業系統在裝載完可執行檔案後,不會把控制權交給可執行檔案,而是先將動態鏈結器載入到程序的位址空間,然後把控制權交給動態鏈結器,動態鏈結器進行動態鏈結工作,最後交給可執行檔案。可執行檔案中專門有個段".interp",指定使用的動態鏈結器。

6、動態符號表:描述符號的匯入匯出關係,即定義了哪些符號,引用了哪些符號。同時有動態符號字串表。對於每個符號項的結構跟目標檔案中對靜態符號表的描述是一樣的。

7、動態鏈結重定位表:包括兩個段,.rel.dyn,這個用於對外部資料引用的修正,.rel.plt,這個用於對外部函式引用的修正,它修正的函式在.got.plt中。在這裡,函式的重定位型別一般是r_386_jump_slot,這個只需要找到相應函式的位址,直接填進去就行。r_386_glob_dat跟r_386_jump_slot類似,只需要找到位址填進去就行。還有一種是r_386_relative,這個修正的是資料中對絕對位址的引用,比如下面這個p:

static int a;

static int* p=&a;

編譯時,只知道a相對起始位置的偏移,在裝載時,共享物件裝載的位址確定後,a的最終位址才能確定,這時候才能確定p指向的位址。

程式設計師的自我修養(十)動態鏈結

動態鏈結其實就是把鏈結的過程推遲到了執行時再進行。特點 重定位位址無關 fpic與 fpie 模組內部的函式呼叫 跳轉等 這種不需要重定位 模組內部的資料訪問,比如模組中定義的全域性變數 靜態變數 相對定址 模組外部的函式呼叫 跳轉等 got,但是儲存的是目標函式的位址 模組外部的資料訪問,比如其他...

程式設計師的自我修養 動態鏈結(1)

7.1為什麼要動態鏈結 用動態鏈結的原因是因為靜態鏈結有這樣那樣的問題。對比二者我們可以總結出靜態鏈結的倆大缺點,和動態鏈結的兩大優點 1 靜態鏈結浪費記憶體和磁碟空間 靜態鏈結會把所有鏈結到的庫裝載入記憶體,而卻這些庫裝載入記憶體後只能給程序自己使用,不能共享給別的程式程序使用。用書中的例子說,1...

程式設計師的自我修養閱讀筆記03

今天來談一下程式設計師的煩惱,哦哦哦哦哦。大多數如我一般的初學者,最大的煩惱就是 不會程式設計,程式設計好難。嗯。至少我的是如此。1.也是我們比較關心的問題 是否還應該留在一線城市 大人們的思想搞不懂,2.這個我比較感興趣 小公司做的事太繁雜了 3.好像與我無關的樣子 創業公司中的危機感 4.還好 ...