動態鏈結概述

2022-09-09 05:33:11 字數 2190 閱讀 5114

學習《程式設計師的自我修養》一書,進行記錄總結。本文為第七章的主要內容。

前面說過靜態鏈結,大體上可以認為是將一大堆的.o檔案合併成乙個可執行檔案(.a 是.o的打包而已)。這就造成乙個.o檔案發生變換,整個**都需要重新進行鏈結,增加編譯負擔。而且不同程序使用相同的.o檔案,都會在程序空間內存在相同的副本造成空間浪費。所以接著出現了動態鏈結的概念,相應的檔案為.so檔案,也被稱為共享物件。

大體邏輯是,在編譯時,只將so的部分資訊新增到可執行檔案裡,而不是將整個so合併進來。在執行時,才將檔案對映到程序的虛存空間中。而且,如果某個so已經被對映,那麼另乙個程序還需要這個so,只需要將對映資訊複製乙份到程序空間中即可。即so被對映到一段物理空間上,而這個物理空間可以被對映到多個程序各自虛擬空間的不同位址,從而達到避免相同資訊在物理記憶體出現多次(當然,可讀寫資料還是程序私有,只能進行拷貝)。並且,要求這個對映到程序虛存的位址不能固定,否則這個so就強行占用了所有需要用到自身的程序的位址空間,對程序本身的**以及記憶體管理帶來極大地麻煩。也就是說,這個so,可以根據程序的實際情況裝載到不同的虛存上。

動態鏈結首先遇到的問題是,共享物件被載入,如何確定在程序虛擬空間中的位址?這個一般是有核心決定,在程序虛存空間中選乙個位址進行對映。這也就意味著,相同的實體地址,在不同的程序空間的虛擬位址是不一樣的。那麼如果共享物件的**段有函式呼叫,資料訪問,這些位址是不能直接定死的(試想如果每個動態庫都固定的占去一段位址空間,那麼佔相同位址空間的動態庫是無法互相共存的)。

為了實現這個有兩種方案,一種是基址重置,一種是位址無關碼。

#-----------------plt段,每3*4個位元組為一項(32位作業系統),除了第0項-----------------------

plt0:

push *(got+4)

jump *(got+8)

...pltn: #假設為bar函式的plt項,在**內呼叫方式為jmp *(bar@plt),n為編譯後的下標,這一行等同於bar@plt。

jmp *(bar@got)

push n

jump plt0

#-----------.got.plt段,在plt段中被表示為got,每4位元組為一項-------------------------

addr of .dynamic #(got+0)

module id #(got+4)

_dl_runtime_resolve(); #(got+8)

addr of funca #初始情況下為plt0+1*3*4+4

addr of funcb #初始情況下為plt0+2*3*4+4

...addr of bar #初始情況下為plt0+n*3*4+4,等同於bar@plt+4

#.got.plt內第三項往後,在呼叫後會被_dl_runtime_resolve修正

#-----------對於bar函式的呼叫**,在.text段中

...push ***x #壓引數,壓返回位址, 於棧

push ***x

jmp *(bar@plt)

上面這些**的邏輯是這樣的,首先看最後乙個.text段中的呼叫,a直接跳向了.plt表中的bar項,b然後跳轉到了.got.plt中的bar項所指的位址,c實際上就是跳回來到了push n這條指令。d接著調到plt的第0項,e壓入模組的id,f又跳到了.got.plt的第三項即_dl_runtime_resolve,g在這裡_dl_runtime_resolve修改了.got.plt中的bar項,並且使bar函式被呼叫。而第二次呼叫bar時,在b項就直接調到bar函式裡了。

為了實現**段的程序間共享以及任意對映,人們設計了很多機制。但對於資料段,操作方式是不同的,資料段是指可讀寫資料,(唯讀資料可採用與**段相同的處理策略在程序間共享)。對於資料段中的實際資料比如某個位址存個數字1,某個位址存個數字2,這就直接存就行了。但是怕就怕在資料段中某個位置上存的是某個符號的指標位址,在這種情況下,由於動態庫載入的位置不同,這些指標位址其實是不一定一樣的,所以本節討論的問題主要是對資料段中絕對位址的引用這種情況進行處理的策略。資料段是在各個程序中是私有的,所以可以採取基址重置策略(裝載時重定位),即資料段中存的絕對位址引用被標記為需要重定位,在裝載時鏈結器完成重定位。

DLL 動態鏈結庫 概述

windows api 中所有的函式都包含在 dll中,其中有 3個最重要的 dll。1 kernel32.dll 它包含那些用於管理記憶體 程序和執行緒的函式,例如createthread函式 2 user32.dll 它包含那些用於執行使用者介面任務 如視窗的建立和訊息的傳送 的函式,例如cre...

動態鏈結 靜態鏈結

在linux系統中,ld鏈結器將彙編器編譯出來的目標檔案和靜態庫里的.a檔案鏈結生成可執行檔案。靜態庫中的.a檔案的 會在靜態鏈結過程中新增到可執行檔案中,可執行檔案會變得很大。與靜態鏈結不同,linux系統的ld鏈結器會將動態庫.so檔案進行符號重定位生成可執行檔案,動態庫.so檔案並不新增到可執...

靜態鏈結 動態鏈結

如果函式庫的乙份拷貝是可執行檔案的物理組成部分,那麼我們稱之為靜態鏈結。如果可執行檔案只是包含了檔名,讓載入器在執行時能夠尋找程式所需的函式庫,那麼稱為動態鏈結。即根據函式庫是不是可執行檔案的組成部分區分靜態鏈結和動態鏈結。1 可執行檔案的體積小。2 雖然執行速度稍慢,但是能更加有效的利用磁碟空間,...