Elf文件格式 ELF32or64
前言
本文參考鏈接: https://segmentfault.com/a/1190000007103522?utm_source=tuicool&utm_medium=referral
非原創。 在學習ELF的過程中記錄自己學習的歷程。
參考數據: LINUX二進制分析
一丶ELF 程序頭
一個ELF文件可以被標記為以下幾種類型
名詞 | 屬性 | 注解 |
---|---|---|
ET_NONE | 未知類型 | 這個標記表明了文件類型不確定或者還未定義 |
ET_REL | 重定位文件 | 如果elf文件標記為了relocatable那么意味着該文件被標記為了一段可沖定位的代碼,也稱為目標文件。可重定位目標文件通常是還未被鏈接到可執行程序的一段位置獨立代碼的代碼(position independent code)。在編譯完代碼之后通常可以看到一個.o的格式的文件,這種文件包含了創建可執行文件所需要的代碼和數據。 |
ET_EXEC | 可執行文件 | elf文件如果為executable,那么表明了這個文件被標記為了可執行文件。這種類型的文件也成為程序,是一個進程開始執行的入口。 |
ET_DYN | 共享目標文件 | ELF類型如果為dynamic意味着該文件被標記為了一個動態的可鏈接的目標文件,也稱為共享庫。這類共享庫會在程序運行的時候被裝載並且鏈接到程序的進程鏡像中。 |
ET_CORE | 核心文件 | 在進程崩潰或者進程傳遞了一個SIGSEGV信號(分段違規)時,會在核心文件中記錄整個進程的鏡像信息。可以使用GDB讀取這類文件來輔助調試並且查找程序崩潰的原因。 |
在linux有一個readelf的小程序。 可以來查看elf文件。 可以看到原始的elf文件頭。
其實所謂的格式就是 C語言中的結構體來做表,並且賦予每個字段含義以及信息。
例子:
>>> readelf -h main.out
ELF 頭:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
類別: ELF32
數據: 2 補碼,小端序 (little endian)
Version: 1 (current)
OS/ABI: UNIX - System V
ABI 版本: 0
類型: DYN (共享目標文件)
系統架構: Intel 80386
版本: 0x1
入口點地址: 0x1070
程序頭起點: 52 (bytes into file)
Start of section headers: 13980 (bytes into file)
標志: 0x0
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 12
Size of section headers: 40 (bytes)
Number of section headers: 30
Section header string table index: 29
elf文件的結構如下
#define EI_NIDENT 16
typedef struct
{
unsigned char e_ident[EI_NIDENT];
uint16_t e_type; ;表示文件的類型,這里為3 就是ET_DYN類型
uint16_t e_machine; ;表示平台的版本,我使用gcc編譯所以標識 intel 8086
uint32_t e_version; ; 表示版本號
ElfN_Addr e_entry; ; 重要字段標識了入口點位置程序的第一行代碼位置
ElfN_Off e_phoff; ; 重要,標識了program table的在文件的偏移開始位置
ElfN_Off e_shoff; ;section header table的偏移位置
uint32_t e_flags; ;保存與文件相關 特定於處理器的標識。
uint16_t e_ehsize;
uint16_t e_phentsize; ;重要字段,表明了program table 每個結構體的大小
uint16_t e_phnum; ;重要字段,表明programtable有多少項
uint16_t e_shentsize; ;表明了sectiontable每一項結構有多大
uint16_t e_shnum; ;表明了sectiontable有多少項
uint16_t e_shstrndx; ;節區頭部表格中與節區名稱字符串相關的表項的索引。
} ElfN_Ehdr;
其實重要的就幾個字段
1.ELF文件標識頭(4個字節即可)
- e_entry 記錄的程序開始位置
- e_phoff 記錄了program table在文件的起始位置
- e_ phentsize 記錄了program table的每個結構大小
.5 e_phnum 表明了有多少個 program table
其余的非必須的都可以設置為錯誤的值。對於程序來說是可以正常運行的。可以進行手動嘗試
1.2 詳解elf頭(32or64)
上面所說是實際應用過程中我們需要重點了解的內容
那么下面就給出詳細的elf頭。讓我們更加的了解elf其他屬性以及作用。
1.2.1 簡介
可制定鏈接格式 最初是由UNIX系統實驗室開發並且發布的。是作為應用程序二進制接口的一部分。 工具接口委員會還在將發展的ELF標准選作為一種可移植的目標文件格式。 可以在32位的intel體系結構上的很多操作系統中使用。
其中目錄文件有三種類型,分別如下表所示:
名詞 | 文件后綴 | 注解 |
---|---|---|
可重定位文件(RelocatableFIle) | .o 結尾 | 包含適合於其他目標文件鏈接來創建可執行文件或者共享目標文件的代碼和數據。 |
可執行文件(ExecutableFIle) | .exe | 包含適合於可執行的一個程序,此文件規定了exec()如何創建一個程序的進程映像 |
共享目標文件(Shared object FIle) | .so | 包含可在兩種上下文中鏈接的代碼和數據。首先鏈接編輯器可以將它和其它可重定位文件和共享目標文件一起處理, 生成另外一個目標文件。其次動態鏈接器(Dynamic Linker)可能將它與某 個可執行文件以及其它共享目標一起組合,創建進程映像。 |
特點:
目標文件全部是程序的二進制表示。 目的就是直接在某種處理器上直接執行。
1.2.2 數據表示表格
目標文件格式支持8位字節/32位的體系架構。不過他們是可以擴展了。也就是可以運行在現在64位的機器上。
下圖則標識各個結構信息的名稱 大小 對其方式等等。
名稱 | 大小 | 對齊 | 目的 |
---|---|---|---|
Elf32_Addr | 4 | 4 | 無符號程序地址 |
Elf32_Half | 2 | 2 | 無符號中等整數 也就是 unsigned short表示 |
Elf32_Off | 4 | 4 | 無符號文件偏移 |
Elf32_SWord | 4 | 4 | 有符號整數 |
Elf32_Word | 4 | 4 | 無符號整數 |
unsigned char | 1 | 1 | 無符號1字節 |
目標文件中所有的數據結構都要遵守自然大小和對齊的規則。
如果有必要則會進行對齊操作。
1.2.3 Elf Hearder表示
32位結構如下:
/* ELF Header */
#define EI_NIDENT 16
typedef struct elfhdr {
unsigned char e_ident[EI_NIDENT]; /* ELF Identification */
Elf32_Half e_type; /* object file type */
Elf32_Half e_machine; /* machine */
Elf32_Word e_version; /* object file version */
Elf32_Addr e_entry; /* virtual entry point */
Elf32_Off e_phoff; /* program header table offset */
Elf32_Off e_shoff; /* section header table offset */
Elf32_Word e_flags; /* processor-specific flags */
Elf32_Half e_ehsize; /* ELF header size */
Elf32_Half e_phentsize; /* program header entry size */
Elf32_Half e_phnum; /* number of program header entries */
Elf32_Half e_shentsize; /* section header entry size */
Elf32_Half e_shnum; /* number of section header entries */
Elf32_Half e_shstrndx; /* section header table's "section
header string table" entry offset */
} Elf32_Ehdr;
64位結構如下
typedef struct {
unsigned char e_ident[EI_NIDENT]; /* Id bytes */
Elf64_Quarter e_type; /* file type */
Elf64_Quarter e_machine; /* machine type */
Elf64_Half e_version; /* version number */
Elf64_Addr e_entry; /* entry point */
Elf64_Off e_phoff; /* Program hdr offset */
Elf64_Off e_shoff; /* Section hdr offset */
Elf64_Half e_flags; /* Processor flags */
Elf64_Quarter e_ehsize; /* sizeof ehdr */
Elf64_Quarter e_phentsize; /* Program header entry size */
Elf64_Quarter e_phnum; /* Number of program headers */
Elf64_Quarter e_shentsize; /* Section header entry size */
Elf64_Quarter e_shnum; /* Number of section headers */
Elf64_Quarter e_shstrndx; /* String table index */
} Elf64_Ehdr;
成員1: e_ident 是一些標識信息。總共大小是16個字節(32位的結構)
其中他是一個數組。 有一些ELF的標識信息,用來標識數組中不同下表的含義。
名稱 | 值 | 目的 |
---|---|---|
EI_MAG0 | 0 | 文件標識 |
EI_MAG1 | 1 | 文件標識 |
EI_MAG2 | 2 | 文件標識 |
EI_MAG3 | 3 | 文件標識 |
EI_CLASS | 4 | 文件類 |
EI_DATA | 5 | 數據編碼 |
EI_VERSION | 6 | 文件的版本 |
EI_PAD | 7 | 補齊字節開始處 |
EI_NIDENT | 16 | e_ident[]的大小 |
這就是每個下標的意義。 那么下面分別說下索引中每個值
其余字段意義如下
在LINUX下可以使用 readelf -h youelf 則可以看小elf文件頭的信息