![畢業(yè)論文:基于PowerPC Linux的ELF格式分析(終稿)_第1頁](http://file2.renrendoc.com/fileroot_temp3/2021-5/22/900f70ac-ab96-47d7-bc21-8e16d83a225f/900f70ac-ab96-47d7-bc21-8e16d83a225f1.gif)
![畢業(yè)論文:基于PowerPC Linux的ELF格式分析(終稿)_第2頁](http://file2.renrendoc.com/fileroot_temp3/2021-5/22/900f70ac-ab96-47d7-bc21-8e16d83a225f/900f70ac-ab96-47d7-bc21-8e16d83a225f2.gif)
![畢業(yè)論文:基于PowerPC Linux的ELF格式分析(終稿)_第3頁](http://file2.renrendoc.com/fileroot_temp3/2021-5/22/900f70ac-ab96-47d7-bc21-8e16d83a225f/900f70ac-ab96-47d7-bc21-8e16d83a225f3.gif)
![畢業(yè)論文:基于PowerPC Linux的ELF格式分析(終稿)_第4頁](http://file2.renrendoc.com/fileroot_temp3/2021-5/22/900f70ac-ab96-47d7-bc21-8e16d83a225f/900f70ac-ab96-47d7-bc21-8e16d83a225f4.gif)
![畢業(yè)論文:基于PowerPC Linux的ELF格式分析(終稿)_第5頁](http://file2.renrendoc.com/fileroot_temp3/2021-5/22/900f70ac-ab96-47d7-bc21-8e16d83a225f/900f70ac-ab96-47d7-bc21-8e16d83a225f5.gif)
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、基于powerpc linux的elf格式分析第一部分 elf格式概述elf(executable and linkable format)是一種對(duì)可執(zhí)行文件、目標(biāo)文件以及庫文件使用的文件格式,它在linux下成為標(biāo)準(zhǔn)文件已經(jīng)有很長的一段時(shí)間,代替了早期的a.out格式。elf格式的一個(gè)優(yōu)點(diǎn)是同一個(gè)文件格式可以用在linux kernel支持的所有體系結(jié)構(gòu)之上。這不僅簡化了用戶空間工具程序的創(chuàng)建,也簡化了內(nèi)核自身的程序設(shè)計(jì),比如必須為可執(zhí)行程序生成裝載例程時(shí)。但是文件格式相同并不意味著不同系統(tǒng)上的程序之間存在二進(jìn)制兼容性,例如freebsd和linux都使用elf作為二進(jìn)制格式,但是freeb
2、sd上的程序不能運(yùn)行于linux上,因?yàn)閮烧咴谙到y(tǒng)調(diào)用機(jī)制和系統(tǒng)調(diào)用語義方面仍然有所不同,反之亦然;如果想讓二者之間的程序能夠運(yùn)行,必須要有一個(gè)中間仿真層。同樣powerpc平臺(tái)編譯的elf程序,也不能在x86平臺(tái)的機(jī)器上運(yùn)行,反之依然,因?yàn)閮烧叩捏w系結(jié)構(gòu)是完全不同的。但是由于elf格式的存在,相同體系結(jié)構(gòu)上的elf程序本身的相關(guān)信息,以及程序的各個(gè)部分在二進(jìn)制文件中的編碼方式都是相同的。linux不僅將elf用于用戶空間應(yīng)用程序和庫,還用于工具模塊,另外linux內(nèi)核本身也是elf格式。備注:elf文件是一種開放的格式,其規(guī)范可以自由獲得。elf文件有三種類型:可重定位文件:也就是通常稱的目
3、標(biāo)文件,后綴為.o;共享文件:也就是通常稱的庫文件,后綴為.so;可執(zhí)行文件:本文主要討論的文件格式;總的來說,可執(zhí)行文件的格式與上述兩種文件的格式之間的區(qū)別主要在于觀察的角度不同:一種稱為連接視圖(linking view),一種稱為執(zhí)行視圖(execution view)。示意圖如下:第二部分 布局和結(jié)構(gòu)elf header:除了用于標(biāo)識(shí)elf文件的幾個(gè)字節(jié)之外,elf文件頭還包含了有關(guān)文件類型和大小的信息,以及文件加載后程序執(zhí)行的入口信息等等,總之elf頭部是一個(gè)關(guān)于本elf文件的路線圖(road map),從總體上描述文件的結(jié)構(gòu)。程序表頭(program head table):向系統(tǒng)
4、提供了可執(zhí)行文件的數(shù)據(jù)在進(jìn)程虛擬地址空間中組織方式的相關(guān)信息,它還表示了文件可能包含的段的數(shù)目,段的位置以及用途。各個(gè)段segmentx(x=1,2,)和節(jié)sectionx(x=1,2,):保存了與文件相關(guān)的各種形式的數(shù)據(jù),例如符號(hào)表、實(shí)際的二進(jìn)制代碼、固定值或者程序使用的數(shù)值常數(shù)。節(jié)頭表(section header table):包含了與各段相關(guān)的附加信息。下面我們一個(gè)例子,用readelf工具來分析elf文件:例如如下:/test.c#include #include int add(int a, int b) printf(numbers are added togethern); r
5、eturn a + b;int main() int a, b; a = 3; b = 4; int ret = add(a,b); printf(result : %un,ret); exit(0);我們用file命令來顯示編譯器生成的兩個(gè)文件的信息:一個(gè)是可執(zhí)行文件,另一個(gè)是可重定位文件,示意圖如下:2.1 elf header文件結(jié)構(gòu)我們用readelf工具來分析上例中生成elf文件的elf header,視圖如下:在test文件的開始處是四個(gè)標(biāo)志字節(jié),0x 7f、0x45、0x4c、0x46。其中的0x45、0x4c、0x46分別代碼“e”“l(fā)”“f”的ascii碼,這使得所有處理el
6、f文件的工具都可以識(shí)別elf類型的文件。還有一些與機(jī)器體系結(jié)構(gòu)相關(guān)的信息。比如上圖中machine類型為powerpc表明該elf文件運(yùn)行于powerpc平臺(tái);elf32表明這是一個(gè)運(yùn)行在32位平臺(tái)的機(jī)器;文件類型為exec表明這是一個(gè)可執(zhí)行程序;version用于區(qū)分當(dāng)前elf文件的各個(gè)修訂版本,當(dāng)前elf文件是基于版本1;另外還包含elf文件各個(gè)部分的長度和索引的位置,后面會(huì)相信討論。如果elf文件是可重定位文件,不同的字段如下圖所示:如圖所示:test.o的文件類型為rel,即它是一個(gè)可重定位的文件,其代碼可以移動(dòng)到任意位置,該文件沒有程序頭program headers,對(duì)于需要鏈接的
7、對(duì)象而言該表是不需要的,所以其所以長度均為0。2.2 程序頭表(program head table)分析下面我們來分析一下elf可執(zhí)行文件test中program head table,示意圖如下:在program headers中列出了8個(gè)段,這些段組成了最終在內(nèi)存中執(zhí)行的程序,并且還提供了各個(gè)段在虛擬地址空間和物理地址空間中的位置、大小、訪問授權(quán)和其它方面的信息。從上圖中我們可以看出,示例程序中包含的各個(gè)段的語義如下:phdr:保存program headers tableinterp:制定程序已經(jīng)從可執(zhí)行文件映射到內(nèi)存之后,必須調(diào)用的解釋器。在這里,解釋器并不意味著二進(jìn)制文件的內(nèi)容必須
8、由另一個(gè)程序解釋(比如java字節(jié)代碼必須由java虛擬機(jī)來解釋),它指的是這樣的程序:通過鏈接其它庫來滿足未解決的引用。load:表示一個(gè)需要從二進(jìn)制文件映射到虛擬地址空間的段,其中保存常量數(shù)據(jù)(如字符串),程序的目標(biāo)代碼等等。dynamic:保存了由動(dòng)態(tài)鏈接區(qū)(即interp中指定的解釋器)使用的信息。note:保存了專用信息,與當(dāng)前主題無關(guān)。gnu_eh_fram和gnu_stack:用來分析棧幀,與體系結(jié)構(gòu)相關(guān),在powerpc體系結(jié)構(gòu)中需要分析棧幀實(shí)現(xiàn)回溯。備注:我們需要特別指出段是可以重疊的,比如在上圖中l(wèi)oad段從物理地址0x1000 0000到物理地址0x1000 0000+0
9、x007f8的范圍,該范圍包含了phdr、interp、note、gnu_eh_fram和gnu_stack段,在elf標(biāo)準(zhǔn)中是允許這種行為的。2.3 節(jié)頭標(biāo)(section header table)分析在elf文件中描述各段的內(nèi)容時(shí),是指定了哪些節(jié)的數(shù)據(jù)映射到段中。在elf中是有一張節(jié)頭表來管理文件中的各個(gè)節(jié),readelf同樣可以用于顯示可重定位文件test.o中的各個(gè)節(jié),示意圖如下:這里指定的偏移量0x168是相對(duì)于二進(jìn)制文件的。節(jié)信息不需要復(fù)制到在虛擬地址空間中做為可執(zhí)行文件創(chuàng)建的最終進(jìn)程映象,盡管如此在elf二進(jìn)制文件中節(jié)信息總是存在的。每個(gè)節(jié)都指定了一個(gè)類型,定義了節(jié)數(shù)據(jù)的語義。
10、包含progbits、systab、rela和strtab。progbits:程序必須解釋的信息,比如二進(jìn)制代碼,程序的二進(jìn)制代碼被稱之為text,指的是用作機(jī)器代碼的二進(jìn)制信息systab:符號(hào)表rela:重定位信息strtab:用于存儲(chǔ)與elf相關(guān)的字符串,但與程序沒有直接的關(guān)系。各個(gè)節(jié)section都指定了其大小和在二進(jìn)制文件內(nèi)部的偏移量。地址addr:指定加載到虛擬地址空間的位置,因?yàn)槲覀兊睦又刑幚淼氖且粋€(gè)可鏈接的對(duì)象,目標(biāo)地址是沒有定義的,因而表示為0。標(biāo)志flg:指出各個(gè)節(jié)section如何被訪問或者處理。我們對(duì)標(biāo)志a比較感興趣,因?yàn)樗刂浦b載文件時(shí)是否將節(jié)的數(shù)據(jù)復(fù)制到虛擬地址
11、空間中。盡管節(jié)的名稱是可以自由選擇的,但是linux(和其它所有使用elf的類unix系統(tǒng))都提供了一些標(biāo)準(zhǔn)節(jié),其中一些是強(qiáng)制性的,例如總是有一個(gè)名為.text的節(jié)來保存二進(jìn)制代碼(即與該elf文件相關(guān)聯(lián)的程序信息),.rel.text保存了節(jié)的重定位信息。備注:節(jié)名以點(diǎn)開始是由系統(tǒng)自身使用的,如果應(yīng)用程序要想定義自身的節(jié),就不應(yīng)該以點(diǎn)開頭,以避免與系統(tǒng)節(jié)名相沖突??蓤?zhí)行程序包含了一些重定位的信息,示意圖如下:與可重定位文件的11個(gè)節(jié)相比,可執(zhí)行文件有36個(gè)節(jié),并非所有的節(jié)都與我們的討論有關(guān)。上圖中標(biāo)出的節(jié)是有具體意義的:.interp:保存了解釋器的文件名,例如在我們的例子中用的是是ld.s
12、o.1;.data:保存了初始化的數(shù)據(jù),這是普通程序數(shù)據(jù)的一部分,可以在程序運(yùn)行時(shí)修改;.rodata:保存了只讀數(shù)據(jù),可以讀但不可以修改,例如編譯器將所有出現(xiàn)在printf中的靜態(tài)字符串封裝到該節(jié);.init和.fini:保存了進(jìn)程初始化和結(jié)束時(shí)所用的代碼,這兩個(gè)節(jié)通常是編譯器自動(dòng)添加的,無需應(yīng)用程序員關(guān)注;.hash:是一個(gè)散列表,允許在不對(duì)全表元素進(jìn)行線性搜索的情況下,快速訪問所有的符號(hào)表項(xiàng)。備注:可執(zhí)行文件elf各個(gè)section中的addr字段保存了有效地址的值,因?yàn)橄鄳?yīng)的代碼必須映射到虛擬地址空間中某些已經(jīng)定義好的位置,在基于powerpc的linux中應(yīng)用程序通常使用0x1000
13、 0000以上的內(nèi)存區(qū)間。2.4 符號(hào)表(symbol table)符號(hào)表是每個(gè)elf文件的一個(gè)重要的組成部分,因?yàn)樗4媪顺绦驅(qū)崿F(xiàn)或者使用過程中所有的(全局)變量和函數(shù),如果程序使用了一個(gè)自身代碼沒有定義的符號(hào),則稱之為未定義符號(hào)(例如例子中的printf函數(shù)是定義在c標(biāo)準(zhǔn)庫中,自身沒有定義),此類應(yīng)用必須在靜態(tài)鏈接期間用其它的目標(biāo)模塊或者庫來解決,或者在加載期間使用lib/ ld.so.1來解決。我們可以使用nm工具生成程序定義或者使用的所有符號(hào)列表,如果下圖所示:左側(cè)一列給出了符號(hào)的值,即符號(hào)定義在目標(biāo)文件中的位置,例子中包含了兩個(gè)不同的符號(hào)類型:如果函數(shù)定義在text段,縮寫為t;而未
14、定義的引用用u標(biāo)明。邏輯上沒有定義的函數(shù)沒有符號(hào)值??稍诳蓤?zhí)行elf文件test中,還會(huì)有更多的符號(hào)。當(dāng)時(shí)大多數(shù)都是由編譯器自動(dòng)生成的,供運(yùn)行時(shí)系統(tǒng)內(nèi)部使用,以下例子中我們僅標(biāo)出了同時(shí)出現(xiàn)在test.o中的符號(hào): u exitglibc_2.01000058c t add100005dc t main u putsglibc_2.0解釋:exit和puts雖然是沒有定義的,但是同時(shí)增加了一些版本信息,標(biāo)明能夠提供函數(shù)的gnu標(biāo)準(zhǔn)庫的最低版本,在我們的例子中要求庫的最低版本不能低于2.0,這意味著該程序無法使用libc5和lib4工作,因?yàn)閘ibc4和libc5是linux專用的c標(biāo)準(zhǔn)庫,gli
15、bc_2.0是該庫的第一個(gè)跨平臺(tái)版本,它替換了就版本,它替換了舊版本。由函數(shù)本身定義的add和main已經(jīng)移到虛擬地址空間中的固定位置(在文件加載時(shí),對(duì)應(yīng)的代碼將會(huì)映射到這些位置)elf使用以下的三個(gè)節(jié)(section);來實(shí)現(xiàn)字符串的管理:.systalb:確定字符串的名稱與其值的索引,但符號(hào)的名稱不是以字符串的形式出現(xiàn)的,而是表示為某個(gè)字符串?dāng)?shù)組的索引;.strtab:保存了字符串?dāng)?shù)組;.hash:保存了一個(gè)hash表用于快速查找符號(hào)。簡而言之,符號(hào)名在字符串表(string table )中的位置和符號(hào)的值,為了說明字符串表示如何管理elf中的字符串,我們看下面的例子:表的第一個(gè)字節(jié)是n
16、ull(即ascii碼值為0),后續(xù)的各個(gè)字符串通過null字節(jié)分割,為了引用字符串必須指定一個(gè)位置,即字符串的索引。這將選擇下一個(gè)null字節(jié)之前的所有字符(如果用null字節(jié)的位置作為索引,那么將會(huì)對(duì)應(yīng)空串)。如果允許索引不僅僅選擇字符串的起始地址,也可以選擇字符串中間的任何位置,就能夠支持字串的用法(但是非常受限)上述的.strtab節(jié)并不是默認(rèn)情況下的唯一的字符串表,.shstrtab用于存放文件中各個(gè)節(jié)的文本名稱(比如.text)第三部分 linux 內(nèi)核中的數(shù)據(jù)結(jié)構(gòu)內(nèi)核在兩處使用了elf文件格式:elf用于處理可執(zhí)行文件和庫,用于實(shí)現(xiàn)模塊。這些地方使用了不同的代碼來讀取和操作數(shù)據(jù),
17、但這兩種情況下都利用了我們本文所介紹的數(shù)據(jù)結(jié)構(gòu),其基礎(chǔ)是include/elf.h文件,它實(shí)現(xiàn)了elf標(biāo)準(zhǔn),基本沒有做改動(dòng)!3.1 數(shù)據(jù)類型elf是一個(gè)與cpu和體系結(jié)構(gòu)無關(guān)的格式,它不能依賴與特定的字長和字節(jié)序(大端還是小端),至少對(duì)文件中的那些需要在所有系統(tǒng)上讀取和理解的數(shù)據(jù)元素來說是這樣。出現(xiàn)在.text段中的機(jī)器代碼存儲(chǔ)為宿主系統(tǒng)的表示格式,以避免轉(zhuǎn)換工作。為此linux內(nèi)核定義了一些數(shù)據(jù)類型,在所有體系結(jié)構(gòu)上具有相同的位寬,如下所示:/32-bit elf 基本類型typedef _u32 elf32_addr;typedef _u16 elf32_half;typedef _u32
18、 elf32_off;typedef _s32 elf32_sword;typedef _u32 elf32_word;/ 64-bit elf 基本類型typedef _u64 elf64_addr;typedef _u16 elf64_half;typedef _s16 elf64_shalf;typedef _u64 elf64_off;typedef _s32 elf64_sword;typedef _u32 elf64_word;typedef _u64 elf64_xword;typedef _s64 elf64_sxword;因?yàn)轶w系結(jié)構(gòu)相關(guān)的代碼必須總是明確定義整數(shù)類型的符號(hào)和
19、位寬,elf標(biāo)準(zhǔn)的數(shù)據(jù)類型可以毫不費(fèi)力的通過typedef實(shí)現(xiàn)3.2 elf頭部格式實(shí)現(xiàn)對(duì)elf格式的各種頭部文件,32位和64位需要分別定義其數(shù)據(jù)結(jié)構(gòu):32位的elf頭在include/elf.h定義如下:#define ei_nident 16typedef struct elf32_hdr unsigned char e_identei_nident; elf32_half e_type; elf32_half e_machine; elf32_word e_version; elf32_addr e_entry; elf32_off e_phoff; elf32_off e_shoff
20、; elf32_word e_flags; elf32_half e_ehsize; elf32_half e_phentsize; elf32_half e_phnum; elf32_half e_shentsize; elf32_half e_shnum; elf32_half e_shstrndx; elf32_ehdr;解釋:e_ident:可以容納16個(gè)字節(jié),這些字節(jié)在所有的體系結(jié)構(gòu)上都是由char數(shù)據(jù)類型表示的,前4個(gè)字節(jié)分別為0x7f(即ascii碼中的del)和字母e、l、f,我們?cè)?.1節(jié)曾介紹過。其它的字節(jié)位置有其特定的含義:e_ident4:ei_class標(biāo)識(shí)文件的類型
21、,將文件分為32位和64位兩類,即elfclass32和elfclass64e_ident5:ei_data指定了格式所使用的字節(jié)序,即elfdata2lsb(小端)和elfdata2msb()大端ei_ident6:ei_version指定elf頭文件的版本(該版本可能獨(dú)立于數(shù)據(jù)段的版本),當(dāng)前,值允許使用ev_current,這是第一個(gè)版本ei_ident7: ei_osabi指定采用的os的abi版本,當(dāng)前是unix system v abi從ei_ident8ei_pad起的剩余字節(jié):用null來填充,因?yàn)檫@些位置上elf不需要。e_type用去區(qū)分各種elf文件的類型,如下所示:e_
22、machine指定了文件所需的體系結(jié)構(gòu),下表列出了linux支持的各種選項(xiàng):注意:每種體系結(jié)構(gòu)都需要定義elf_check_arch,并由內(nèi)核的通用代碼使用,來確保加載的elf文件可以在相應(yīng)的體系結(jié)構(gòu)上運(yùn)行。e_version:保存了版本信息,用于區(qū)分不同的elf變體,目前該規(guī)范僅支持版本1,由ev_current指出來e_entry:給出了文件在虛擬內(nèi)存中的入口點(diǎn),在程序已經(jīng)加載并映射到內(nèi)存之后,執(zhí)行開始的位置e_phoff:保存了程序頭表(program header table)在二進(jìn)制elf文件中的偏移e_shoff:保存了節(jié)表頭(section header table) 在二進(jìn)制e
23、lf文件中的偏移e_flags:保存了特定于處理器的標(biāo)志,當(dāng)前l(fā)inux內(nèi)核不適用該標(biāo)志e_ehsize:指定了elf header的長度,單位是字節(jié)e_phentsize:指定了program header中一個(gè)表項(xiàng)的長度,單位是字節(jié)(所有表項(xiàng)的長度均相同)e_phnum:指定了program header table中表項(xiàng)的數(shù)目e_shentsize:指定了section header table中一個(gè)表項(xiàng)的長度,單位是字節(jié)(所有表項(xiàng)的長度均相同)e_shnum:指定了節(jié)頭表中項(xiàng)的數(shù)目e_shstrndx:保存了包含各節(jié)(section)名稱的字符串表在section header中的索引
24、位置備注:64位下elf頭的數(shù)據(jù)結(jié)構(gòu)可以同樣定義,唯一的差別在于其中使用了對(duì)應(yīng)的64位數(shù)據(jù)類型,這使得頭文件稍大。但兩者數(shù)據(jù)結(jié)構(gòu)的前16字節(jié)都是相同的,兩種體系結(jié)構(gòu)的類型能夠根據(jù)這些字節(jié)來識(shí)別不同字長機(jī)器的elf文件3.3 program header實(shí)現(xiàn)程序頭表由幾個(gè)項(xiàng)實(shí)現(xiàn),其處理方式類似于數(shù)組項(xiàng)(項(xiàng)的數(shù)據(jù)由elf頭中的e_phnum指定),表項(xiàng)的數(shù)據(jù)類型定義為獨(dú)立的結(jié)構(gòu),在32的機(jī)器上其內(nèi)容如下:typedef struct elf32_phdr elf32_word p_type; elf32_off p_offset; elf32_addr p_vaddr; elf32_addr p_
25、paddr; elf32_word p_filesz; elf32_word p_memsz; elf32_word p_flags; elf32_word p_align; elf32_phdr;解釋:p_type:表示當(dāng)前項(xiàng)描述的段的種類,為其定義了下列常數(shù):pt_null:表示沒有使用的段pt_load:表示可裝載段,在程序執(zhí)行前從二進(jìn)制文件映射到內(nèi)存pt_dynamic:表示段包含了用于動(dòng)態(tài)鏈接器的信息pt_interp:表示當(dāng)前段指定了用于動(dòng)態(tài)鏈接的解釋程序,比如ld.so.1pt_note:指定一個(gè)段,其中可能含有專有的編譯器信息還有兩個(gè)常數(shù)pt_loproc和pt_highpro
26、c用于定義與處理器相關(guān)的用途,內(nèi)核并不使用p_offset:指出所描述段從elf文件起始處的偏移量,以字節(jié)為單位p_vaddr:給出段的數(shù)據(jù)映射到虛擬地址空間中的位置(對(duì)應(yīng)pt_load類型的段),只支持物理尋找,不支持虛擬尋址的系統(tǒng)將使用p_paddr保存的信息p_filesz:指定了段在elf文件中的長度p_memsz:指定了段在虛擬地址空間中的長度,與文件中物理段的差值可以通過階段數(shù)據(jù)或者填充0字節(jié)來填充p_flags:保存了標(biāo)志信息,定義了段的訪問權(quán)限:pf_r讀權(quán)限,pf_w寫權(quán)限,pf_x執(zhí)行權(quán)限p_align:指定了段在內(nèi)存和二進(jìn)制文件中的對(duì)齊方式(即p_vaddr和p_offs
27、et地址必須是模p_align,即為p_align的倍數(shù))比如p_align的值為0x1000=4kb,這意味著段必須4kb對(duì)齊。對(duì)64為體系結(jié)構(gòu)定義的類似的數(shù)據(jù)結(jié)構(gòu),與32位相比,唯一的差別在于所使用的數(shù)據(jù)結(jié)構(gòu),各數(shù)據(jù)項(xiàng)的語義都是相同的。其具體內(nèi)容如下:typedef struct elf64_phdr elf64_word p_type; elf64_word p_flags; elf64_off p_offset; /segment file offset elf64_addr p_vaddr; /segment virtual address elf64_addr p_paddr; /
28、segment physical address elf64_xword p_filesz; /segment size in file elf64_xword p_memsz; /segment size in memory elf64_xword p_align; /segment alignment, file & memory elf64_phdr;3.4 節(jié)頭表section header table代碼實(shí)現(xiàn)節(jié)頭表通過數(shù)組實(shí)現(xiàn),每個(gè)數(shù)組項(xiàng)包含一節(jié)的信息,各個(gè)節(jié)構(gòu)成了程序頭表program header table定義的各個(gè)段的內(nèi)容。下來數(shù)據(jù)結(jié)構(gòu)表示一個(gè)節(jié):typedef struct
29、 elf32_shdr elf32_word sh_name; elf32_word sh_type; elf32_word sh_flags; elf32_addr sh_addr; elf32_off sh_offset; elf32_word sh_size; elf32_word sh_link; elf32_word sh_info; elf32_word sh_addralign; elf32_word sh_entsize; elf32_shdr;解釋:sh_name:指定了節(jié)的名稱,其值不是字符串本身,而是字符串表的一個(gè)索引。sh_type:指定了節(jié)的類型,有下列的類型可用:
30、sh_null表示該節(jié)不使用,其數(shù)據(jù)將會(huì)被忽略 sh_progbits保存程序的相關(guān)信息,其格式是不定義的,與這里的討論無關(guān) sh_symtab保存一個(gè)符合表,其結(jié)構(gòu)我們?cè)?.4節(jié)已經(jīng)討論,sh_dynsym也保存一個(gè)符號(hào)表,二者的差別我們?cè)谏院笥懻?sh_strtab表示一個(gè)包含字符串表的節(jié) sh_rela和sht_rela保存重定位信息,我們也將在后面討論 sh_hash定義了一個(gè)節(jié)保存hash表,用于快速的查找符號(hào)表中的項(xiàng) sh_dynamic保存了動(dòng)態(tài)鏈接表的信息,我們也將在后面討論 還有類型值sht_hiproc、sht_loproc、sht_hiuser、sht_louser,這些
31、專項(xiàng)特定于cpu和應(yīng)用程序的用途,與這里討論的內(nèi)容無關(guān)sh_flags:表示節(jié)是否可重寫(shf_write),是否將其分配虛擬內(nèi)存(shr_alloc),是否包含可執(zhí)行的機(jī)器代碼(shf_execinstr)sh_addr:指定節(jié)映射到虛擬地址空間中的位置sh_offset:指定了節(jié)在內(nèi)存中的位置sh_size:指定了節(jié)的長度sh_link:引用另一個(gè)節(jié)頭表項(xiàng),可以根據(jù)節(jié)類型進(jìn)行不同的解釋,其性能我們?cè)诤竺鎲为?dú)討論sh_info和sh_link聯(lián)用,其確切語義我們也會(huì)在下文中再討論。sh_addralign:指定了節(jié)數(shù)據(jù)在內(nèi)存中的對(duì)齊方式sh_entsize:指定了節(jié)中各個(gè)數(shù)據(jù)項(xiàng)的長度,前提
32、是這些數(shù)據(jù)項(xiàng)的長度均相同。例如字符串表根據(jù)節(jié)類型不同,sh_link和sh_info的用法也不盡相同,具體情況如下:第一:sht_dynamic類型的節(jié)使用sh_link指向節(jié)數(shù)據(jù)指向的字符串表,這種情況下不使用sh_info,sh_info設(shè)置為0;第二:散列表(sht_hash類型的節(jié))使用sh_link指向所散列的符合表,sh_info不使用第三:類型為sht_rela和sht_rel的重定位節(jié),使用sh_link指向相關(guān)的符號(hào)表,sh_info中保存的是節(jié)頭表中的索引,表示對(duì)哪個(gè)節(jié)進(jìn)行重定向;第四:sh_link指定了用作符號(hào)表的字符串表(sht_symtab和sht_dynsym),
33、而sh_info表示符號(hào)表中緊隨最后一個(gè)局部符號(hào)之后的索引位置(stb_local類型)而64位系統(tǒng)有一個(gè)單獨(dú)的數(shù)據(jù)結(jié)構(gòu),其內(nèi)容和32系統(tǒng)相同,除了使用64位的數(shù)據(jù)類型。內(nèi)容如下:typedef struct elf64_shdr elf64_word sh_name; / section name, index in string tbl elf64_word sh_type; / type of section elf64_xword sh_flags; / miscellaneous section attributes elf64_addr sh_addr; / section vir
34、tual addr at execution elf64_off sh_offset; / section file offset elf64_xword sh_size; / size of section in bytes elf64_word sh_link; / index of another section elf64_word sh_info; / additional section information elf64_xword sh_addralign; / section alignment elf64_xword sh_entsize; / entry size if
35、section holds table elf64_shdr;elf標(biāo)準(zhǔn)定義了若干固定名稱的節(jié),這些節(jié)用于執(zhí)行大多數(shù)目標(biāo)文件所需要的標(biāo)準(zhǔn)任務(wù),所有名稱都從點(diǎn)開始,以便與用戶定義的節(jié)或者非標(biāo)準(zhǔn)的節(jié)相區(qū)分。最重要的標(biāo)準(zhǔn)節(jié)如下所示:.bss:保存程序未初始化的數(shù)據(jù),在程序開始時(shí)填充0字節(jié).data:保存已經(jīng)初始化的數(shù)據(jù),例如在編譯期間用靜態(tài)數(shù)據(jù)初始化的結(jié)構(gòu),這些數(shù)據(jù)可以在程序運(yùn)行期間更改.rodata:保存了程序使用的只讀數(shù)據(jù),不能更改.dynamic和.dynstr:保存了動(dòng)態(tài)信息,后面討論.interp:保存了程序解釋器的名稱,形式為字符串.shstrtab:包含了一個(gè)字符串表,定義了節(jié)名稱.s
36、trtab:保存了一個(gè)字符串表,主要包含了符合表所需要的各個(gè)字符串.symtab:保存了二進(jìn)制文件的符合表.init和.fini:保存了程序初始化和結(jié)束時(shí)執(zhí)行的機(jī)器指令,這兩個(gè)節(jié)的內(nèi)容有編譯器或者輔助工具自動(dòng)創(chuàng)建,主要是為程序建立一個(gè)適當(dāng)?shù)倪\(yùn)行環(huán)境.text:保存了主要的機(jī)器指令3.5 字符串表string tables字符串表的格式我們?cè)?.4的結(jié)尾處討論過,因?yàn)槠涓袷椒浅?dòng)態(tài),內(nèi)核不同提供一個(gè)固定的數(shù)據(jù)結(jié)構(gòu),必需手工分析現(xiàn)存數(shù)據(jù)3.6 符號(hào)表symbol tables符號(hào)表保存了查找程序符號(hào)、為符號(hào)賦值、重定位符號(hào)所需要的全部信息,如上所述,有一個(gè)專門類型的節(jié)來保存符號(hào)表,其格式有下列數(shù)據(jù)
37、結(jié)構(gòu)定義:typedef struct elf32_sym elf32_word st_name; elf32_addr st_value; elf32_word st_size; unsigned char st_info; unsigned char st_other; elf32_half st_shndx; elf32_sym;解釋:符號(hào)表的任務(wù)就是將一個(gè)字符串和一個(gè)值關(guān)聯(lián)起來,例如printf符號(hào)表表示printf函數(shù)在虛擬空間中的地址,該函數(shù)的機(jī)器碼就存在于該地址處。符號(hào)也可能有絕對(duì)值,有程序解釋,例如數(shù)據(jù)常數(shù)。一個(gè)符號(hào)的確切用途有st_info定義,它分為兩個(gè)部分(比特位如何劃分
38、與我們的討論不相關(guān)),其中定義了下列信息:第一:符號(hào)的綁定(binding),這確定了符號(hào)的可見性,允許有下列三種不同的設(shè)置:1:局部符號(hào)(stb_local):只有在目標(biāo)文件內(nèi)部可見,在于程序的其它部分連接時(shí)是不可見的。如果一個(gè)程序的幾個(gè)目標(biāo)文件都定義同名的此類符號(hào)是沒有問題的,這些局部符號(hào)間彼此不會(huì)干擾。2:全局符號(hào)(stb_global):在定義的目標(biāo)文件內(nèi)部可見,也可以由構(gòu)成程序的其它目標(biāo)文件引用,每個(gè)全局符號(hào)在一個(gè)程序的內(nèi)部只引用一次,否則鏈接器就會(huì)報(bào)錯(cuò)。執(zhí)行全局符號(hào)的位定義引用,將在重定位期間確定相關(guān)符號(hào)的位置,如果對(duì)全局符號(hào)的未定義引用無法解決,則拒絕程序執(zhí)行或者靜態(tài)綁定。3:弱
39、符號(hào)(stb_weak):在整個(gè)程序中可見,當(dāng)可以由多個(gè)定義。如果程序中一個(gè)全局符號(hào)和一個(gè)局部符號(hào)名稱相同,則全局符號(hào)就優(yōu)先處理;即使一個(gè)弱符號(hào)沒有定義,程序也是可以靜態(tài)鏈接或者動(dòng)態(tài)鏈接,這種情況下若符號(hào)的值為0第二:符號(hào)類型也有若干備選項(xiàng),只有以下三個(gè)與目標(biāo)的主題相關(guān)(對(duì)其它值的描述由elf標(biāo)準(zhǔn)提供)stt_objct:符號(hào)關(guān)聯(lián)到一二數(shù)據(jù)對(duì)象,比如變量,數(shù)組和指針;stt_func:符號(hào)關(guān)聯(lián)到一個(gè)函數(shù)或者過程;stt_nottype:符號(hào)的類型為制定,用于未定義引用;elf32_sym結(jié)構(gòu)體除了包含st_name,st_value,st_info,還包含以下成員,其語義如下:st_size:
40、制定對(duì)象的長度,例如一個(gè)指針的長度或者struct對(duì)象中包含的字節(jié)數(shù),如果長度有位置,其值可以設(shè)置為0;標(biāo)準(zhǔn)的elf標(biāo)準(zhǔn)不支持st_otherst_shndx:保存一個(gè)節(jié)(在節(jié)頭表)中的索引,符號(hào)將綁定到該節(jié),該符號(hào)通常定義在此節(jié)的代碼中,但下列兩個(gè)值具有特殊的語義:shn_abs制定符號(hào)的絕對(duì)值,不因重定位而改變shn_under標(biāo)準(zhǔn)未定義符號(hào),必須通過外部來源(比如鏈接目標(biāo)文件或者庫)來解決。同樣,符號(hào)表也有一個(gè)64位的變體,除了使用的數(shù)據(jù)類型不同,其內(nèi)容與32位的對(duì)應(yīng)結(jié)構(gòu)是相同的,如下所示;typedef struct elf64_sym elf64_word st_name; / sy
41、mbol name, index in string tbl unsigned char st_info; / type and binding attributes unsigned char st_other; / no defined meaning, 0 elf64_half st_shndx; / associated section index elf64_addr st_value; / value of the symbol elf64_xword st_size; / associated symbol size elf64_sym;我們可以使用readelf來查找程序的符號(hào)
42、表中所有的符號(hào),圖中標(biāo)出的六項(xiàng)在test.o目標(biāo)文件中特別重要,其它的數(shù)據(jù)項(xiàng)由編譯器自動(dòng)生成的,與我們的討論無關(guān)o(_)o分析:源文件中名稱”test.c”存儲(chǔ)為一個(gè)絕對(duì)值,它是常數(shù)不隨著重定位而改變。該局部符號(hào)使用set_file類型,將一個(gè)目標(biāo)文件關(guān)聯(lián)到對(duì)應(yīng)的源文件、文件中定義了兩個(gè)函數(shù)main和add,存儲(chǔ)為set_func類型的全家符號(hào),兩個(gè)符號(hào)都執(zhí)行節(jié)1,即elf文件中的.text節(jié),保存了兩個(gè)函數(shù)的機(jī)器代碼。_nldbl_printf、puts、exit符號(hào)屬于未定義引用,節(jié)索引值為und,因而在程序鏈接時(shí)它們必須關(guān)聯(lián)到標(biāo)準(zhǔn)庫中的函數(shù),或者其它庫中以該名稱定義的函數(shù)。因?yàn)榫幾g器不指
43、定所涉及的符號(hào)的類型,因而這兩個(gè)符號(hào)的類型都是stt_notype。第四部分 重定位項(xiàng)relocation entries重定位是將elf文件中為定義符號(hào)關(guān)聯(lián)到有效值的處理過程,在我們的例子test.o中,這意味著對(duì)printf、exit、puts的未定義引用必須替換為該進(jìn)程的虛擬地址空間中相應(yīng)的機(jī)器代碼所在的空間,在目標(biāo)文件中用到的符號(hào)之處都將被替換。對(duì)用戶空間程序的替換,內(nèi)核并不會(huì)牽涉其中。因?yàn)樗械奶鎿Q操作都是由外面工具完成的。當(dāng)對(duì)于linux內(nèi)核模塊來說,情況有所不同,因?yàn)閮?nèi)核所接受到得模塊裸數(shù)據(jù)與存儲(chǔ)在二進(jìn)制文件中的數(shù)據(jù)完全相同,內(nèi)核負(fù)責(zé)重定位操作。在每個(gè)目標(biāo)文件中都有一個(gè)專門的表,
44、包含了重定位表項(xiàng),標(biāo)識(shí)了需要進(jìn)行重定位的地方。每個(gè)表項(xiàng)都包含了下列信息:第一:一個(gè)偏移量,用來指定所要修改的項(xiàng)的位置第二:對(duì)符號(hào)的引用(符號(hào)表的索引),提供了所要插入的重定位位置的數(shù)據(jù)為了說明如何使用重定位信息,我們來看一下此前test.c測(cè)試程序,我們用readelf顯示的所有重定位項(xiàng)如下圖所示:在程序運(yùn)行時(shí)或者test.o產(chǎn)生可執(zhí)行文件時(shí),如果某些機(jī)器代碼使用了虛擬地址空間中位置尚不明確的符號(hào)或者函數(shù),則會(huì)使用offset列的信息。main函數(shù)的匯編語言代碼調(diào)用了若干函數(shù),分別位于偏移量0x 7c,0x98,0xa0如下所示:00000050 : 50: 94 21 ff e0 stwu
45、r1,-32(r1) 54: 7c 08 02 a6 mflr r0 58: 90 01 00 24 stw r0,36(r1) 5c: 93 e1 00 1c stw r31,28(r1) 60: 7c 3f 0b 78 mr r31,r1 64: 38 00 00 03 li r0,3 68: 90 1f 00 08 stw r0,8(r31) 6c: 38 00 00 04 li r0,4 70: 90 1f 00 0c stw r0,12(r31) 74: 80 7f 00 08 lwz r3,8(r31) 78: 80 9f 00 0c lwz r4,12(r31) 7c: 48 0
46、0 00 01 bl 7c 80: 90 7f 00 10 stw r3,16(r31) 84: 3c 00 00 00 lis r0,0 88: 30 00 00 1c addic r0,r0,28 8c: 7c 03 03 78 mr r3,r0 90: 80 9f 00 10 lwz r4,16(r31) 94: 4c c6 31 82 crclr 4*cr1+eq 98: 48 00 00 01 bl 98 9c: 38 60 00 00 li r3,0 a0: 48 00 00 01 bl a0 備注:我們可以用objdump工具查看,示意圖如下:在printf和add函數(shù)的地址已經(jīng)
47、確定后,必須將它們插入指定的偏移量處,以便可以生成正確運(yùn)行的可執(zhí)行代碼。4.1 linux內(nèi)核中相關(guān)的數(shù)據(jù)結(jié)構(gòu)由于技術(shù)原因,有兩種類型的重定位信息,有兩種稍有不同的數(shù)據(jù)結(jié)構(gòu)表示:第一種:普通重定位,sht_rel類型的節(jié)中的重定位表項(xiàng)由以下的數(shù)據(jù)結(jié)構(gòu)表示:typedef struct elf32_rel elf32_addr r_offset; elf32_word r_info; elf32_rel;解釋:r_offset:指定需要重定位的項(xiàng)的位置r_info:不僅提供了符合表中的一個(gè)位置,還包括重定位類型的有關(guān)信息。這是通過把值劃分為兩個(gè)部分來達(dá)到的。第二種:需要添加常數(shù)的重定位項(xiàng)只出現(xiàn)在
48、sht_rela類型的節(jié)中,這類結(jié)構(gòu)由下列數(shù)據(jù)結(jié)構(gòu)定義:typedef struct elf32_rela elf32_addr r_offset; elf32_word r_info; elf32_sword r_addend; elf32_rela;解釋:這里除了有第一種重定位類型提供的r_offset和r_info字段之外,還補(bǔ)充了r_addend字段,其中存放一個(gè)稱之為加數(shù)(addend)的值。在計(jì)算重定位值時(shí),將根據(jù)重定位類型,對(duì)該值進(jìn)行不同的處理。請(qǐng)注意:在使用elf32_rel時(shí)也會(huì)出現(xiàn)加數(shù)這個(gè)值,盡管在數(shù)據(jù)結(jié)構(gòu)中沒有明確的保存,但鏈接器根據(jù)該值應(yīng)該在內(nèi)存中出現(xiàn)的位置,將計(jì)算出的
49、重定位長度作為加數(shù)填入,該值的用途將在下面的例子中說明。對(duì)兩種重定位類型,都有功能等效的64位數(shù)據(jù)結(jié)構(gòu):typedef struct elf64_rel elf64_addr r_offset; /location at which to apply the action elf64_xword r_info; /index and type of relocation elf64_rel;typedef struct elf64_rela elf64_addr r_offset; /location at which to apply the action elf64_xword r_inf
50、o; /index and type of relocation elf64_sxword r_addend; /constant addend used to compute value elf64_rela;解釋:這兩個(gè)數(shù)據(jù)結(jié)構(gòu)和32位的對(duì)應(yīng)類型非常相似,這里就不在討論4.2 重定位類型elf標(biāo)準(zhǔn)定義了很多重定位類型,對(duì)于每種支持的體系結(jié)構(gòu),都有一個(gè)獨(dú)立的集合,這些類型大部分用于生成動(dòng)態(tài)庫或者與裝載位置無關(guān)的代碼。linux內(nèi)核只對(duì)模塊的重定位感興趣,因此使用下面的兩種重定位類型:相對(duì)重定位和絕對(duì)重定位。我們通過一個(gè)例子介紹一下相對(duì)從定位:1000058c :1000058c: 94 21 ff e0 stwu r1,-32(r1)100005d8: 4e 80 00 20 blr100005dc :100005dc: 94 21 ff e0 stwu r1,-32(r1).1000
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 藝術(shù)品交易中介服務(wù)協(xié)議
- 旅游規(guī)劃與設(shè)計(jì)服務(wù)合同
- 隧道機(jī)械租賃合同
- 項(xiàng)目團(tuán)隊(duì)月度工作總結(jié)報(bào)告書
- 7《一匹出色的馬》教學(xué)設(shè)計(jì)-2023-2024學(xué)年二年級(jí)下冊(cè)語文統(tǒng)編版
- Unit 1 Family Lesson3(教學(xué)設(shè)計(jì))-2024-2025學(xué)年北師大版(三起)(2024)英語三年級(jí)上冊(cè)
- 第6單元 20陀螺(教學(xué)設(shè)計(jì))2024-2025學(xué)年四年級(jí)語文上冊(cè)同步教學(xué)(統(tǒng)編版)
- 西寧高鐵u型渠施工方案
- 濟(jì)寧鋼質(zhì)入戶門施工方案
- 北京拼接式蓄水池施工方案
- 出血熱知識(shí)培訓(xùn)課件
- 廣東省汕頭市潮南區(qū)2024-2025學(xué)年高一上學(xué)期期末教學(xué)質(zhì)量監(jiān)測(cè)英語試卷(無答案)
- 大模型落地應(yīng)用實(shí)踐方案
- 2025年八省聯(lián)考內(nèi)蒙古高考生物試卷真題答案詳解(精校打印)
- 2024年度工業(yè)自動(dòng)化設(shè)備維護(hù)保養(yǎng)及上門維修合同3篇
- 地下室頂板后澆帶混凝土構(gòu)造柱支撐方案
- GB/T 19799.2-2024無損檢測(cè)超聲檢測(cè)試塊第2部分:2號(hào)標(biāo)準(zhǔn)試塊
- 2025年公司總經(jīng)理年終總結(jié)工作報(bào)告
- 2024山東一卡通文化旅游一卡通合作協(xié)議3篇
- 安徽省“江淮十?!?024屆高考化學(xué)一模試卷含解析
- 圖書外借服務(wù)計(jì)劃
評(píng)論
0/150
提交評(píng)論