1.ELF概念:
ELF(Executable and Linkable Format),即“可執行可鏈接格式”,最初由UNIX系統實驗室作為應用程序二進制接口(Application Binary Interface – ABI)的一部分而制定和發布,是COFF(Common file format)格式的變種。Linux系統上所運行的就是ELF格式的文件,相關定義在“/usr/include/elf.h”文件里。
它和在Windows下pe文件是相對的。
可以看到ELF文件非常的多,我沒有細細的看。
2.ELF文件的幾種類型:
ELF文件分為三種類型,可執行文件(.exec)、可重定位文件(.rel)和共享目標文件(.dyn):
- 可執行文件(executable file):經過鏈接的、可執行的目標文件,通常也被稱為程序。
- 可重定位文件(relocatable file):由源文件編譯而成且尚未鏈接的目標文件,通常以“.o”作為擴展名。用於與其他目標文件進行鏈接以構成可執行文件或動態鏈接庫,通常是一段位置獨立的代碼(Position Independent Code, PIC)。
對於.o結尾的文件,在編譯的時候可以link到我們的程序中去 - 共享目標文件(shared object file):動態鏈接庫文件。用於在鏈接過程中與其他動態鏈接庫或可重定位文件一起構建新的目標文件,或者在可執行文件加載時,鏈接到進程中作為運行代碼的一部分。
3.ELF文件的結構
在ELF文件格式規范中,ELF文件被統稱為object file,這與我們通常理解的.o文件是不太一樣的。
- 在審視一個目標文件時,有兩種視角可供選擇,一種是鏈接視角,通過節(Section)來進行划分;另一種是運行視角,通過段(Segment)來進行划分
下面我們先從鏈接視角去來看看:
(這是簡化版的elf文件頭)
我們可以看見代碼段(.text)和數據段(.data)是分開處理的,這一點就是從安全的角度去出發考慮的。
下面我們自上而下的介紹鏈接視角去看的elf文件.
首先我們寫一個簡單的helloworld程序,然后使用gcc編譯器將編譯過程中的中間文件給生成出來。
我們額可以通過gcc生成幾個不同main可執行文件過程中的幾個中間文件查看elf文件readelf -h main
我們可以看見這個第一條就是一個magic,這個是個什么意思呢??這個美其名曰魔術字符(7f 45 4c 46),當文件被映射到內存中的時候,通過尋找這
個字符可以確定映射的地址。
這里我們給出ELF64_Ehdr結構體的代碼:
看完了elf_hander下面我們就來看看section節:
- 一個目標文件包含了許多的節,這些節的信息保持在節頭表中(section header table)中,表的每一項都是ELF64_Shdr的結構體(注意與之前的ELF64_Ehdr區別)
查看節表頭
讀取節頭表 readelf -S main.o
至於另外的兩個.data和.bss段我不想看了,因為腿這會麻了。
這是一些其他節的東西,我看着書上面寫出來的我復制一些吧,也算自己記憶。
字符串表(shstrtab和strtab)中包含了以null結尾的字符序列,用來表示符號名和節名,引用字符串時只需給出字符序列在表中的偏移即可。字符串表的第一個字符和最后一個字符都是null字符,以確保所有字符串的開始和終止。
- 符號表(.dynsym和.symtab)記錄了目標文件中所用到的所有符號信息,通常分為.dynsym和.symtab,前者是后者的子集。.dynsym保存了引用自外部文件的符號,只能在運行時被解析,而.symtab還保存了本地符號,用於調試和鏈接。目標文件通過一個符號在表中的索引值來使用該符號。索引值從0開始計數,但值為0的表項不具有實際的意義,它表示未定義的符號。每個符號都有一個符號值(symbol value),對於變量和函數,該值就是符號的地址。
num就是索引值。
- 接下來我們看的是重定位
重定位是連接符號定義與符號引用的過程。可重定位文件在構建可執行文件或共享目標文件時,需要把節中的符號引用換成這些符號在進程空間中的虛擬地址。
這里offset是在重定位時候需要被修改的符號偏移,info分為兩個部分:type知識如何修改引用,symbol指示應該修改引用為那個符號,addend表示對於被修改符號的引用做偏移調整。
以上呢就是在link視角下去看elf文件了