簡單描述ELF動態鏈接重定位的延遲綁定以及GOT表、PLT表的意義

GOT表

        GOT表(Global Offset Table) ,又稱全局偏移表,位於.data節首,記錄着外部符號動態加載後的首地址信息。在靜態鏈接時,每一個外部符號都會在GOT表對應一個表項,靜態鏈接器並每一個表項生成一個對應的重定位項(數據位於.rel.data節,函數位於.rel.text節)。在動態加載時,動態鏈接器將根據重定位項,修改對應的GOT表中信息,完成重定位。

         在訪問動態庫數據或調用動態庫函數時,直接通過相對位移,找到對應的GOT表項,然後根據GOT表項中記錄的目標地址信息訪問數據或調用函數,從而實現動態加載。

舉例說明:

	extern int b;
	extern void ext();
	int main() {
	    ext();
	}

在這裏插入圖片描述
彙編僞代碼如下:

	0000050c <main>:
	  0000050c:    55                   pushl %ebp
	  ....
	  00000557:    e8 00 00 00 00       call  0000055c
	  0000055c:    5b                   popl  %ebx
	  0000055d:                         addl $0x1204, %ebx
	  0000055e:                         call *(%ebx) 

          通過這種方式,可以發現在調用函數時多使用了三條指令,並多使用了一個%ebx寄存器,加法過程可能會出現寄存器溢出問題。爲解決以上問題,ELF採用延遲綁定技術來解決。

延遲綁定與PLT表

          所謂延遲綁定,就是不在加載動態鏈接庫時進行綁定(重定位填寫GOT表),而是延遲到每一個外部符號第一次被調用時進行,這種方式所導致的效果顯而易見:第一次調用時重定位會較慢,再次調用時則明顯加快,這也可以避免加載動態庫中沒有使用的符號信息。延遲綁定也將涉及到PLT表(Procedure Linkage Table),又稱過程鏈接表,位於.text節(可以看出PLT表中每一項都對應一個代碼塊)。

         此時,GOT表作爲.data節的一部分,開始的三項是固定的,含義如下:
         GOT[0]: 記錄.dynamic節首地址,該節中記錄了動態鏈接器所需的基本信息,如符號表位置,重定位表位置等。
         GOT[1]: 記錄動態鏈接器的標示信息。
         GOT[2]:記錄動態鏈接器延遲綁定代碼的入口地址。

         這裏假設ext函數對應的是GOT[3]。

         PLT作爲.text節的一部分,開始的一項是固定的,其目的是設置動態鏈接器的標示信息與符號ID作爲參數,然後調用動態連機器延遲綁定代碼的入口。

在這裏插入圖片描述
彙編僞代碼如下:

PLT[0]
	0804833c: ff 35 88 95 04 08       pushl 0x8049588
	08048342: ff 25 8c 95 04 08       jmp *0x804958c
	08048348: 00 00 00 00
PLT[1] 
	0804834c: ff 25 90 95 04 08       pushl 0x8049590
	08048352: 68 00 00 00 00          pushl 0x0
	08048357: e9 e0 ff ff ff          jmp 0x0804833c

         第一次調用ext函數時,會相對尋址到對應的PLT表項,然後跳轉到對應的GOT表項中記錄的地址,第一次調用時GOT表項記錄的是PLT表中下一條指令的地址,然後向堆棧中push符號ID後跳轉至PLT[0]表項,然後PLT[0]表項向堆棧push動態鏈接器的標示信息後跳轉至動態連機器延遲綁定代碼的入口。在完成綁定後,由動態鏈接器修改對應GOT表項中記錄的函數地址,從而實現延遲綁定的重定向。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章