乙個程式要想執行,首先要載入到記憶體中,程式的pc指標指向記憶體中的**,**在執行的時候會使用記憶體中的資料。所以elf檔案主要包含**和資料。
資料可以分為兩類:
靜態資料。
動態資料。
什麼是動態資料?,動態資料程式執行過程中產生,在堆或者棧上分配記憶體。而靜態資料則不然,靜態資料在**編譯完成後,就應該確定使用的位址和空間。
靜態資料又分為兩種,唯讀資料和可讀寫資料。
乙個庫要想被其他程式呼叫,還要約定一種方式,使呼叫者可以找到被呼叫者的函式位址,所以執行程式還要儲存動態鏈結相關的資訊。另外程式還要告知聯結器,如何將**和資料載入到記憶體中,這就是程式的載入資訊。elf檔案格式是類unix系統中常見的程式和庫的檔案格式,所以elf要包含上述資訊(**,資料,載入資訊和鏈結資訊)。elf怎麼來組這這些資訊呢,下面是elf的資料格式圖。
程式的資訊都儲存在section(節)中,檔案通過section header table(節頭表)來描述每個節的資訊,這些資訊包括如下幾項:
不同型別的節有不同的作用。
程式的載入資訊則儲存在program header table(程式段表)中,elf被載入到記憶體中後用segment(段)表示,段的描述資訊:
程式的鏈結資訊也儲存在section(節)中,關於鏈結資訊我們可以分為兩部分,一部分為庫匯出的函式/變數,另一部分則是庫依賴的其他庫的函式/變數。對於描述匯出的函式/變數是比較容易的,因為庫自身知道函式/變數的名稱和要載入到的記憶體位置,這部分資訊(名字和位址)儲存在型別為dynsym的節中。 對於要匯入的函式/變數,在型別為rela/rel的節中儲存了引用其他庫的函式/變數在符號表中的索引,符號表中則儲存該函式/變數的名稱,在型別為dynamic的節中儲存了程式依賴的庫名稱,鏈結器在鏈結的時候會去依賴的庫中根據函式/變數的名稱去尋找該函式/變數被載入到記憶體的位置,將找到的函式/變數位址寫入到型別為progbits(一般名稱為.got的節) 節對應的位置,之後再使用函式/變數就直接從got表中獲取位址即可。
elf的載入主要的依據為程式頭表,程式頭表中每一項描述的段(segment)的資訊,乙個段可能包含多個section(節)。
我們以上圖中的程式頭表的段資訊來舉例:
程式的匯出符號和匯出符號的位址在符號表節,符號名稱在字串表中。
程式依賴的庫資訊儲存在dynmic型別的節中。
程式的函式/變數資訊儲存在型別為rel/rela的節中,該節儲存了該函式/變數在符號表中的位置,以及重定位的方法以及重定位後的函式位址儲存在型別為progbit節中的位置(一般在可讀寫記憶體區域的節如.got,.got.plt節,因為要後填寫析函式/變數位址,所以該區域為讀寫區域)。
型別為hash的節用於加快根據函式名稱尋找函式位址的過程,也就是函式解析的過程。
efl_load圖中描述的是gcc聯結器預設的鏈結指令碼生成的elf檔案,節的名稱都是gcc定義的。所以我們只要能滿足elf聯結器的要求,elf的節名稱組織方式完全可以自己定義,也就是鏈結指令碼的作用,我們甚至可以自己寫載入器。
ELF檔案格式分析
elf檔案 目標檔案 格式主要三種 1 可重定向檔案 檔案儲存著 和適當的資料,用來和其他的目標檔案一起來建立乙個可執行檔案或者是乙個共享目標檔案。目標檔案或者靜態庫檔案,即linux通常字尾為.a和.o的檔案 2 可執行檔案 檔案儲存著乙個用來執行的程式。例如bash,gcc等 3 共享目標檔案 ...
ELF分析 實踐
分析elf檔案 首先編寫乙個.c檔案,並使用gcc c xx.c o xx.o 對其進行編譯。我在這個實踐中是elf 1.o檔案。接下來輸入ls l elf 1.o 檢視重定位檔案的資訊。接下來以十六進製制來檢視該檔案資訊。輸入 hexdump x elf 1.o 顯示資訊的最左一列表示的是偏移位址...
ELF檔案結構分析以及常用readElf指令
1 elf檔案型別 三種型別 1 可重定位檔案 relocatable file 2 可執行檔案 executable file 3 共享目標檔案 shared object file dynamic linker可以將中這個檔案與其他rf檔案或者sharedobject組合 2 elf目標檔案格式...