linux 延遲重定位

2021-09-19 13:15:56 字數 1819 閱讀 4631

以前看書的時候,模模糊糊知道linux延遲重定位的意思,沒對知識點進行總結和記錄,面試的時候,問到了elf檔案的時候,才知道自己並沒有搞懂。

在面試中,elf檔案中的plt和got是必問的問題,plt和got是用來實現linux中的延遲重定位,意思是等到呼叫到這個外部函式的時候再進行重定位,優點很明顯,加快了程式的啟動速度,在傳統的執行時重定位中,在程式啟動的時候,直接將對每個動態函式解析,將動態函式的位址填入到got表中,在程式比較大的時候,無疑會影響程式的啟動速度,延遲重定位技術將重定位放到了動態函式第一次被呼叫的時候,這種技術的實現就是利用了elf格式檔案中的plt和got,首先plt表和got表類似於陣列,兩者的不同點是plt表中放的是可執行**,所以plt表中的資料是不能改變的,接著是got表,got表中存放的是資料,所以got表中的資料是可以改動的,這些資料其實就是一些跳轉位址,提供給plt中的**使用。下面寫個**除錯下。

#includevoid helloworld()

int main()

這段**中,printf為外部模組函式,需要進行動態重定位,gcc -g test.c -o test,生成可執行檔案test,gdb test 動態除錯test。

可以看到helloworld函式在 0x40052d中,接著檢視helloworld函式。

在helloworld中 callq 400410 代表了呼叫了puts函式,其中的@plt是關鍵,代表了0x400410這個位址並不是puts函式的真實位址,而是plt表的位址,說明函式會先跳到plt表中,接著看下0x400410中有什麼內容。

可以看到0x40010 中是plt表中的內容,這裡存放著三行**。

jmpq *0x200c02(%rip)

pushq $0x0

jmpq 0x400400

這裡看到plt中又直接跳轉到了 *0x200c02(%rip)中,跳轉到(0x200c02 + rip)中存放的資料,接著看一下(0x200c02 + rip)中存放了什麼,在x86彙編中rip是指向下一條指令的位址,所以是0x601018,上面這條指令右邊的注釋已經幫我們標明了。

可以看到值為0x400416,正是當前指令的下一條指令pushq $0x0。pushq $0x0這條指令將要鏈結的函式的索引入棧,在rel.plt中使用該索引,可以用readelf -r test檢視。可以看到puts再索引為0的地方,跟上面的push一致。

接著是jmpq 0x400400指令,不知道為啥disas指令不起作用,用了x /5i 0x400400指令。

到這裡的時候,第乙個pushq 0x200c02(%rip) 將link_map的位址入棧,jmpq *0x200c04(%rip)跳轉到dl_runtime_reslove中解析函式,解析完畢,再將解析到的函式位址,填到對應的got表項中。關於dl_runtime_reslove怎麼知道填到哪個got表項中,可以看rle.plt表專案中的offset,offset欄位中的值為0x601018,跟前面got表項的位址對上了。每個外部函式第一次呼叫都要進行這樣一次函式的查詢,並將位址填到got表項中,這樣下次呼叫的時候,就無需查詢了,直接跳轉到外部函式。

共享可寫節包含重定位 理解重定位

一 段的概念 段是程式的組成元素。將整個程式分成乙個乙個段,並且給每個段起乙個名字,然後在鏈結時就可以用這個名字來指示這些段,使得這些段排布在合適的位置。乙個程式通常包含以下五個段 段 text 存放 指令 唯讀資料段 rodata 存放有初始值並且const修飾的全域性類變數 全域性變數或stat...

什麼是重定位

6 1 儲存器的基本概念 主儲存器管理仍然是今天作業系統十分重要的內容 能否合理而有效的使用主存,在很大成度上反映了作業系統的效能,並直接影響到整個計算機系統作用的發揮。6.1.1 儲存器的層次 目前在許多計算機系統中,採用 儲存器結構,即高速緩衝儲存器 主儲存器和外部儲存器。儲存器的比較 從快取記...

u boot中重定位

在學習 u boot的時候,對程式重定位不理解,不知道為什麼要進行重定位,在網上查詢資料學習了一下。首先,要了解一下乙個程式的生成的四個步驟 預處理 編譯 彙編 鏈結。經過這四步,最終才生成可執行檔案bin檔案。預處理主要是巨集定義的展開,編譯主要是進行語法此分析,如我們常見的語法錯誤,某些函式未定...