2017-07-27 58 views
2

我正在研究如何在動態鏈接中使用GOT和PLT。我很困惑爲什麼每個動態鏈接的函數調用似乎都跳轉到PLT中的某個位置,該位置將始終跳轉到GOT中的相同位置。爲什麼不首先跳到GOT的那個位置呢?爲什麼需要另一層間接尋址?爲什麼從PLT到GOT蹦牀而不是直​​接跳到GOT?


我可能從根本上誤解了一些關於GOT和PLT,所以這裏是我的如何的PLT和GOT用於概念性理解的簡要說明。

我們有一個名爲FunctionX的函數,PLT中的一個對應位置PLT [X],以及GOT中對應的位置GOT [X]。 PLT和GOT的地址在編譯時已知,但FunctionX的地址不是。

爲了調用FunctionX:

1)調用(在裝配有義)PLT [X]的地址。

2)PLT [X]跳轉到GOT [X]所包含的值。 3a)如果FunctionX已經被解析,GOT [X]包含函數地址,所以第2步是跳轉到FunctionX。 3b)否則,GOT [X]包含將在運行時解析FunctionX地址的代碼地址,將該地址寫入GOT [X],然後跳轉到FunctionX。在這種情況下,步驟2會導致FunctionX被解析然後跳轉到。

步驟1的目的是什麼?

我對這個主題的理解很粗略,所以請指出任何可能有助於解決問題的說明。

+0

這裏只是猜測,但也許PLT是一個標準化的東西,但它恰巧使用GOT的事實只是一個意外的實現細節。 – Jester

+1

請參閱https://stackoverflow.com/questions/43048932/why-does-the-plt-exist-in-addition-to-the-got-instead-of-just-using-the-got?rq=1爲什麼PLT不能輕易在x86目標上被淘汰。 –

+0

@RossRidge這回答了我的問題。謝謝。 – Praxeolitic

回答

0

只是要想想

想象任何地址爲GOT [X]的一些客戶端代碼(例如主)的第一個電話。正如你在3b)所說的那樣,這將調用將解析FunctionX地址的代碼。但是,解析代碼如何知道您想要解析FunctionX?您將它稱爲正常功能,您不會爲解析器提供任何其他信息,因爲它是您要修補的FunctionX地址。在跳轉到GOT [X]之前,存根推動堆棧額外的信息。

最後幾段文章this幫了很大忙。

+0

我把那部分拿出來了。本質上,GOT [X]最初包含的地址是專門用於解析FunctionX的代碼地址。該代碼設置參數,指定我們正在解析FunctionX,並將地址寫入GOT [X],然後分派給通用符號解析代碼。我的理解是,對PLT [X]的初始調用總是一個簡單的跳轉。 – Praxeolitic

+0

是的,並且設置paremetres的代碼是存根(stub),不是嗎?就我所知,這就是它的目的。 – Tom

+0

PLT [X]中的第一條指令跳回自己,它在第一次調用時實際上是NOP指令。 – Tom