在現代的linux
系統中,假設乙個普通的程式會使用到
c語言靜態庫至少
1mb以上,那麼,如果我們的機器執行
100個這樣的程式,就用浪費近
100mb
的記憶體;如果磁碟有
2000
個這樣的程式,就要浪費
2gb的記憶體。
靜態鏈結對程式的更新、發布等也會帶來問題。比如程式program1
使用由第三方廠家提供的庫
lib.o
,當廠家更新
lib.o
時,程式
program1
的廠商必須先得到
lib.o
,那後將
program1
重新鏈結,並將整個新的
program1
發布給客戶。可以想象,如果乙個這個程式很大,這是多麼耗費時間的事。
動態鏈結正是為了解決靜態鏈結而出現的一種技術。它的優點是:共享的目標檔案在磁碟中只有乙個副本,在記憶體中的**段只有乙個副本(通過檔案記憶體對映來實現),這樣不僅節約了記憶體空間,還可以減少物理頁面的換進換出;可以動態更換某個模組而不需要重新編譯整個程式,不過要重新啟動程式才行。這樣使得程式公升級很方便。
動態鏈結的基本思想就是把程式模組拆分成幾個相對獨立的部分,在程式執行時才將它們鏈結在一起形成乙個完整的程式,而不像靜態鏈結把所有程式模組都鏈結成乙個單獨的可執行檔案。linux
系統中,
elf動態鏈結檔案被為動態共享物件(
dso,
dynamic shared objects
),簡稱共享物件,一般以
.so為副檔名。
由於共享物件是可以同時被很多程序共享的,所以我們不應該在編譯共享物件的時候就把共享物件中的位址確定下來。如果確定下來了,由於每個程序的虛擬位址空間都不同,這樣很難避免共享物件的位址空間和程序的其它位址空間衝突。
如果不能在編譯共享物件時確定共享物件的位址,能否在共享物件裝載時確定呢?裝載時重定位看起來好像是可以解決共享物件裝載到任意虛擬位址空間的問題,都是在編譯時目標位址不確定而需要在裝載是將模組重定位。但是裝載時重定位還是不適合用來解決共享物件所存在的問題。想象下,動態鏈結模組被裝載到記憶體且被對映到虛擬位址空間後,指令部分是在多個程序之間共享的,由於裝載時重定位的方法是需要修改指令的,所以沒有辦法做到同乙份指令被多個程序所共享。當然,動態鏈結庫中的可修改資料部分對於不同的程序來說有多個副本,所以它們可以採用裝載時重定位的方法來解決。
我們的目的很簡單,就是希望程式模組中共享的指令在裝載時不需要因為裝載位址的改變而改變,所以實現的基本思想就是把指令中需要修改的部分分離出來,跟資料部分存放在一起,這樣指令部分就可以保持不變了,而資料部分可以每個程序乙個副本。這種技術就是pic
技術(position-independent code
)。elf的具體做法是在資料段中建立乙個指向其它模組變數位址的指標陣列,稱為全域性偏移表(
global offset table
,got
),而**中引用全域性變數的**都改成引用got。當**中需要引用該全域性變數時,就可以通過
got相應項間接引用。
動態鏈結下,程式模組之間包含了大量的函式引用(全域性變數往往比較少,因為大量的全域性變數引用會導致模組之間的耦合很大),所以在程式開始執行時,會消耗大量的時間來解決模組間函式引用的符號查詢和重定位。實際上有很多的函式是不會呼叫的,如錯誤處理函式和使用者很少使用的功能模組,一開始繫結就浪費資源和時間了。所以elf
採用了一種叫做延遲繫結的做法,基本思想就是當函式第一次被用到時才進行繫結,如果沒用到就不繫結。elf使用
plt(
procedure linkage table
)的方法來實現延遲繫結。編譯器將got
分成got
和got.plt
表,got
用來儲存全域性變數的位址,
got.plt
用來儲存函式引用的位址。為了實現延遲繫結,我們就不能直接訪問got
表來獲取目標函式的位址,必須又新增一層中間跳轉表,這個中間跳轉表叫做
plt表,由plt表來真正完成繫結的工作。
ELF靜態鏈結
一直對elf目標檔案是怎樣鏈結成可執行檔案感到比較的疑惑,elf檔案裡面的重定位段是怎樣解決符號引用問題的?前幾天偶然看了 深入理解計算機系統 裡面講了這個問題,看了之後對裡面的實現機制終於有了一定的理解。當有鏈結器鏈結多個可重定位的共享物件時,共享物件時怎樣合併的呢?很簡單,鏈結器將相同型別的節合...
linux下ELF的動態鏈結過程
先列出書中乙個例子的簡單 實現,以展示動態鏈結過程。lib.h ifndef lib h define lib h void foobar int i endif lib.c includevoid foobar int i program1.c include lib.h int main pro...
ELF檔案動態鏈結時 GOT,PLT 的變化過程
intel平台下linux中elf檔案動態鏈結的載入 解析及例項分析 一 載入 intel平台下linux中elf檔案動態鏈結的載入 解析及例項分析 二 函式解析與解除安裝 最後我們討論elf檔案的動態連線機制。每乙個外部定義的符號在全域性偏移表 global offset table got 中有...