本文接續之前的日記「ELF(Executable and Linking Format)格式教學文件, #1: ELF 簡介」,在了解 ELF 的用途後,再來我們先由「ELF Header」的部份開始看起,我們的目標是寫一個可以將 ELF 執行檔裡所有 section 讀取出來的程式。未來將繼續朝 user-space 的 ELF 處理前進。
如果您是 Jollen 的讀者,或許曾經在書上讀到這個章節,本系統的內容與書上內容大致相仿,但仍有一些小差異,建議您可再讀一次。我希望能以其它的出版形式,將這些內容都與大家分享。
ELF header:檔頭格式
ELF 於 SysV ABI 標準中定義,其中 ELF header 的結構如下表:
Field | Description |
e_ident | 用來辨別檔案是否為ELF,並包含一些machine independent 的資料。 |
e_type | 檔案的類型 |
e_machine | 檔案的平臺 |
e_version | 版本資訊 |
e_entry | 程式的起始位址(process virtual address) |
e_phoff | program header table的檔案偏移值(offset),單位是bytes。如果沒有program header table則此值為0。 |
e_shoff | section header table的檔案偏移值(offset),單位是bytes。如果沒有section header table則此值為0。 |
e_flags | 與processor有關的旗標值 |
e_ehsize | ELF header的長度,單位是bytes。 |
e_phentsize | program header table每個entry的長度(bytes),每個entry的長度都相等。 |
e_phnum | program header table的entry個數,若無program header table 則此欄的值為0。 |
e_shentsize | section header table每個entry的長度(bytes),每個entry的長度都相等。 |
e_shnum | section header table的entry個數,若無program header table則此欄的值為0。 |
e_shstrndx | section header table的index值,索引至section name string table entry。如果檔案沒有section name string table,則此欄的值為SHN_UNDEF。 |
ELF 檔案格式最基本的就是它的檔頭(header)部份,ELF header 儲存 object file 的各種資訊。ELF header 的讀取方式非常簡單,我們將會實作讀取 ELF header 的程式,以強化我們所讀到的觀念。
ELF header 的資料結構定義在 elf.h 裡,如下:
/* The ELF file header. This appears at the start of every ELF file. */ #define EI_NIDENT (16) typedef struct { unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ Elf32_Half e_type; /* Object file type */ Elf32_Half e_machine; /* Architecture */ Elf32_Word e_version; /* Object file version */ Elf32_Addr e_entry; /* Entry point virtual address */ Elf32_Off e_phoff; /* Program header table file offset */ Elf32_Off e_shoff; /* Section header table file offset */ Elf32_Word e_flags; /* Processor-specific flags */ Elf32_Half e_ehsize; /* ELF header size in bytes */ Elf32_Half e_phentsize; /* Program header table entry size */ Elf32_Half e_phnum; /* Program header table entry count */ Elf32_Half e_shentsize; /* Section header table entry size */ Elf32_Half e_shnum; /* Section header table entry count */ Elf32_Half e_shstrndx; /* Section header string table index */ } Elf32_Ehdr;
Section 與 section header table 的讀取與處理方式,會在介紹完 ELF header 後再做說明。
ELF 的範例程式
本系列日記共有 5 個範例程式,其功能差異整理如下表。
讀取檔頭 | 分析檔頭 | 判斷ELF | 處理Section | 讀取Strtab | 列印節區名稱 | |
loader-0.1.c | ● | ● | ||||
loader-0.2.c | ● | ● | ● | |||
loader-0.3.c | ● | ● | ● | ● | ||
loader-0.4.c | ● | ● | ● | ● | ● | ● |
loader-0.5.c | ● | ● | ● | ● | ● | ● |
為了能了解ELF格式,我們將會實作 6 大項功能如下:
1. 讀取檔頭:讀取 ELF 檔案的檔頭資訊。
2. 分析檔頭:分析讀取的檔頭資訊,例如分析 ELF 執行檔的編碼平臺。
3. 判斷 ELF:判斷所讀取的檔案是否為標準 ELF 格式的檔案。
4. 處理 Section:可以讀取所有 section 的資訊,並做簡單處理,例如找出是 string table 的 section。
5. 讀取 StrTab:讀取 section name string table 裡的資訊。
6. 列印節區名稱:處理 section name string table,可以根據 section name string table 來列印所有 section的名稱(ASCII string)。
我們將會以漸進式的方式來慢慢完成所有的功能,不同版本範例程式間的主要差異將會特別做說明,並詳細解釋新功能的程式實作。
另外,loader-0.4.c 與 loader-0.5.c 看似功能相同,但 loader-0.5.c 主要是為了討論 loader-0.4.c 裡幾個奇怪的地方。我們會在講解loader-0.5.c 程式時再做更詳細的說明。
Loader 在載入 object file 前,必須先由 ELF header 取得 object file 的資訊並且判斷 object file 是否為 ELF 格式的執行檔,然後才能將 object file 載至記憶體。
Also See |
--jollen