午夜视频在线网站,日韩视频精品在线,中文字幕精品一区二区三区在线,在线播放精品,1024你懂我懂的旧版人,欧美日韩一级黄色片,一区二区三区在线观看视频

分享

ELF的GOT和PLT以及PIC | Zhiwei.Li

 瀟湘居士 2010-11-03

ELF的GOT和PLT以及PIC

全局偏移表(GOT)和過(guò)程鏈接表(PLT)

ELF 格式的共享庫(kù)使用 PIC 技術(shù)使代碼和數(shù)據(jù)的引用與地址無(wú)關(guān),程序可以被加載到地址空間的任意位置。PIC 在代碼中的跳轉(zhuǎn)和分支指令不使用絕對(duì)地址。PIC 在 ELF 可執(zhí)行映像的數(shù)據(jù)段中建立一個(gè)存放所有全局變量指針的全局偏移量表 GOT

對(duì)于模塊外部引用的全局變量和全局函數(shù),用 GOT 表的表項(xiàng)內(nèi)容作為地址來(lái)間接尋址;對(duì)于本模塊內(nèi)的靜態(tài)變量和靜態(tài)函數(shù),用 GOT 表的首地址作為一個(gè)基準(zhǔn),用相對(duì)于該基準(zhǔn)的偏移量來(lái)引用,因?yàn)椴徽摮绦虮患虞d到何種地址空間,模塊內(nèi)的靜態(tài)變量和靜態(tài)函數(shù)與 GOT 的距離是固定的,并且在鏈接階段就可知曉其距離的大小。這樣,PIC 使用 GOT 來(lái)引用變量和函數(shù)的絕對(duì)地址,把位置獨(dú)立的引用重定向到絕對(duì)位置。

對(duì)于 PIC 代碼,代碼段內(nèi)不存在重定位項(xiàng),實(shí)際的重定位項(xiàng)只是在數(shù)據(jù)段的 GOT 表內(nèi)。共享目標(biāo)文件中的重定位類型有 R_386_RELATIVE、R_386_GLOB_DAT 和 R_386_JMP_SLOT,用于在動(dòng)態(tài)鏈接器加載映射共享庫(kù)或者模塊運(yùn)行的時(shí)候?qū)χ羔橆愋偷撵o態(tài)數(shù)據(jù)、全局變量符號(hào)地址和全局函數(shù)符號(hào)地址進(jìn)行重定位。

1.2 PLT 表
過(guò)程鏈接表用于把位置獨(dú)立的函數(shù)調(diào)用重定向到絕對(duì)位置。通過(guò) PLT 動(dòng)態(tài)鏈接的程序支持惰性綁定模式。每個(gè)動(dòng)態(tài)鏈接的程序和共享庫(kù)都有一個(gè) PLT,PLT 表的每一項(xiàng)都是一小段代碼,對(duì)應(yīng)于本運(yùn)行模塊要引用的一個(gè)全局函數(shù)。程序?qū)δ硞€(gè)函數(shù)的訪問(wèn)都被調(diào)整為對(duì) PLT 入口的訪問(wèn)。

每個(gè) PLT 入口項(xiàng)對(duì)應(yīng)一個(gè) GOT 項(xiàng),執(zhí)行函數(shù)實(shí)際上就是跳轉(zhuǎn)到相應(yīng) GOT 項(xiàng)存儲(chǔ)的地址,該 GOT 項(xiàng)初始值為 PLTn項(xiàng)中的 push 指令地址(即 jmp 的下一條指令,所以第 1 次跳轉(zhuǎn)沒(méi)有任何作用),待符號(hào)解析完成后存放符號(hào)的真正地址。動(dòng)態(tài)鏈接器在裝載映射共享庫(kù)時(shí)在 GOT 里設(shè)置 2 個(gè)特殊值:在 GOT+4( 即 GOT[1]) 設(shè)置動(dòng)態(tài)庫(kù)映射信息數(shù)據(jù)結(jié)構(gòu)link_map 地址;在 GOT+8(即 GOT[2])設(shè)置動(dòng)態(tài)鏈接器符號(hào)解
析函數(shù)的地址_dl_runtime_resolve。

PLT 的第 1 個(gè)入口 PLT0 是一段訪問(wèn)動(dòng)態(tài)鏈接器的特殊代碼。程序?qū)?PLT 入口的第 1 次訪問(wèn)都轉(zhuǎn)到了 PLT0,最后跳入 GOT[2]存儲(chǔ)的地址執(zhí)行符號(hào)解析函數(shù)。待完成符號(hào)解析后,將符號(hào)的實(shí)際地址存入相應(yīng)的 GOT 項(xiàng),這樣以后調(diào)用函數(shù)時(shí)可直接跳到實(shí)際的函數(shù)地址,不必再執(zhí)行符號(hào)解析函數(shù)

操作系統(tǒng)運(yùn)行程序時(shí),首先將解釋器程序即動(dòng)態(tài)鏈接器ld.so 映射到一個(gè)合適的地址,然后啟動(dòng) ld.so。ld.so 先完成自己的初始化工作,再?gòu)目蓤?zhí)行文件的動(dòng)態(tài)庫(kù)依賴表中指定的路徑名查找所需要的庫(kù),將其加載映射到內(nèi)存。

Linux用一個(gè)全局的庫(kù)映射信息結(jié)構(gòu) struct link_map鏈表來(lái)管理和控制所有動(dòng)態(tài)庫(kù)的加載,動(dòng)態(tài)庫(kù)的加載過(guò)程實(shí)際上是映射庫(kù)文件到內(nèi)存中,并填充庫(kù)映射信息結(jié)構(gòu)添加到鏈表中的過(guò)程。結(jié)構(gòu) struct link_map 描述共享目標(biāo)文件的加載映射信息,是動(dòng)態(tài)鏈接器在運(yùn)行時(shí)內(nèi)部使用的一個(gè)結(jié)構(gòu),通過(guò)它保持對(duì)已裝載的庫(kù)和庫(kù)中符號(hào)的跟蹤。
link_map 使用雙向鏈接中間件“l_next”和“l_prev”鏈接進(jìn)程中所有加載的共享庫(kù)。當(dāng)動(dòng)態(tài)鏈接器需要去查找符號(hào)的時(shí)候,可以向前或向后遍歷這個(gè)鏈表,通過(guò)訪問(wèn)鏈表上的每一個(gè)庫(kù)去搜索需要查找的符號(hào)。Link_map 鏈表的入口由每個(gè)可執(zhí)行映像的全局偏移表的第 2 個(gè)入口(GOT[1])指向,查找符號(hào)時(shí)先從 GOT[1]讀取 link_map 結(jié)點(diǎn)地址,然后沿著link-map 結(jié)點(diǎn)進(jìn)行搜索。

動(dòng)態(tài)庫(kù)的加載映射過(guò)程主要分 3 步:
(1) 動(dòng)態(tài)鏈接器調(diào)用 __mmap 函數(shù)對(duì)動(dòng)態(tài)庫(kù)的所有PT_LOAD 可加載段進(jìn)行整體映射:

l_map_start=(ElfW(Addr))__mmap ((void *)0, maplength, prot,
MAP_COPY | MAP_FILE, fd, mapoff);

返回值 l_map_start 是實(shí)際映射的虛擬地址,和段結(jié)構(gòu)成員 p_vaddr 指定的虛擬地址不一定相同,這對(duì)于位置無(wú)關(guān)代碼不會(huì)產(chǎn)生影響。但是對(duì)于數(shù)據(jù)段和 link_map 結(jié)構(gòu)中其它相關(guān)的位置描述信息還要進(jìn)行修正。共享庫(kù)映射的內(nèi)存位置關(guān)系如圖 1,l_addr 是實(shí)際映射地址和原來(lái)指定的映射地址的差值,用于其它位置信息的修正,即簡(jiǎn)單地將原來(lái)指定的虛擬地址加上 l_addr 就可以得到實(shí)際加載的虛擬地址

(2)共享文件映射完畢,動(dòng)態(tài)鏈接器處理共享庫(kù)的PT_DYNAMIC 動(dòng)態(tài)段,將各項(xiàng)動(dòng)態(tài)鏈接信息主要是哈希表、符號(hào)表、字符串表、重定位表、PLT 重定位項(xiàng)表等地址填寫(xiě)到 link_map 的 l_info 數(shù)組結(jié)構(gòu)中。l_info 是 link_map 最重要的字段之一,幾乎所有與動(dòng)態(tài)鏈接管理相關(guān)的內(nèi)容都與 l_info數(shù)組有關(guān)。動(dòng)態(tài)鏈接器還要加載處理當(dāng)前共享庫(kù)的所有依賴庫(kù)。

(3)由于實(shí)際的映射地址和指定的虛擬地址有可能不同,因此還要對(duì)動(dòng)態(tài)庫(kù)及其依賴庫(kù)進(jìn)行重定位。設(shè)置動(dòng)態(tài)庫(kù)的第1 個(gè)和第 2 個(gè) GOT 表項(xiàng):

Elf32_Addr *got =
(Elf32_Addr *) lmap->l_info[DT_PLTGOT].d_un.d_ptr;
got[1]=lmap;
got[2]=&_dl_runtime_resolve;

對(duì)動(dòng)態(tài)庫(kù)的所有重定位項(xiàng)進(jìn)行重定位,在重定位項(xiàng)指定的偏移地址處加上修正值 l_addr。動(dòng)態(tài)項(xiàng) DT_REL 給出了重定位表的地址,DT_RELSZ 給出重定位表項(xiàng)的數(shù)目。
映射完畢后,動(dòng)態(tài)鏈接器調(diào)用共享庫(kù)(包括所有相關(guān)的依賴庫(kù))自備的初始化函數(shù)進(jìn)行初始化。

程序連接表(Procedure Linkage Table)可以使被感染的文件調(diào)用外部的函數(shù)。這要比修改LD_PRELOAD環(huán)境變量實(shí)現(xiàn)調(diào)用的重定向優(yōu)越的多,首先不牽扯到環(huán)境變量的修改

程序連接表(PLT)

  在ELF文件中,全局偏移表(Global Offset Table,GOT)能夠把位置無(wú)關(guān)的地址定位到絕對(duì)地址,程序連接表也有類似的作用,它能夠把位置無(wú)關(guān)的函數(shù)調(diào)用定向到絕對(duì)地址。連接編輯器(link editor)不能解決程序從一個(gè)可執(zhí)行文件或者共享庫(kù)目標(biāo)到另外一個(gè)的執(zhí)行轉(zhuǎn)移。結(jié)果,連接編輯器只能把包含程序轉(zhuǎn)移控制的一些入口安排到程序連接表 (PLT)中。在system V體系中,程序連接表位于共享正文中,但是它們使用私有全局偏移表(private global offset table)中的地址。動(dòng)態(tài)連接器(例如:ld-2.2.2.so)會(huì)決定目標(biāo)的絕對(duì)地址并且修改全局偏移表在內(nèi)存中的影象。因而,動(dòng)態(tài)連接器能夠重定向這些入口,而勿需破壞程序正文的位置無(wú)關(guān)性和共享特性??蓤?zhí)行文件和共享目標(biāo)文件有各自的程序連接表。

elf的動(dòng)態(tài)連接庫(kù)是內(nèi)存位置無(wú)關(guān)的,就是說(shuō)你可以把這個(gè)庫(kù)加載到內(nèi)存的任何位置都沒(méi)有影響。這就叫做position independent。在編譯內(nèi)存位置無(wú)關(guān)的動(dòng)態(tài)連接庫(kù)時(shí),要給編譯器加上 -fpic選項(xiàng),讓編譯器產(chǎn)生的目標(biāo)文件是內(nèi)存位置無(wú)關(guān)的還會(huì)盡量減少對(duì)變量引用時(shí)使用絕對(duì)地址。把庫(kù)編譯成內(nèi)存位置無(wú)關(guān)會(huì)帶來(lái)一些花費(fèi),編譯器會(huì)保留一個(gè)寄存器來(lái)指向全局偏移量表(global offset table (or GOT for short)),這就會(huì)導(dǎo)致編譯器在優(yōu)化代碼時(shí)少了一個(gè)寄存器可以使用,但是在最壞的情況下這種性能的減少只有3%,在其他情況下是大大小于3%的。

此條目發(fā)表在 C/C++, Linux, 逆向工程 分類目錄,貼了 , 標(biāo)簽。將固定鏈接加入收藏夾。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多