ELF(Executable and Linkable Format) 即可執行可連結檔案格式,是目前作業系統上最常見的可執行檔案格式。不同系統的目標檔案不一樣,Windows是PE(Portable Executable),linux是ELF(Executable Linkable Format),它們都是COFF(Common file format)格式的變種。
ELF格式的目標檔案和可執行檔案在結構上沒有本質差異,ELF不僅僅描述目標檔案,也用於描述可執行檔案,Windows下的dll和.lib, Linux下的.so和.a檔案都是按照類ELF格式儲存,下圖描述了ELF連結檢視(.o檔案、.so檔案)和執行檢視,連結檢視描述了各個段(section)的組成,如.text、.data、bss段。執行檢視由segment組成,segment用於表示一個一定長度的區域,按照唯讀/可讀寫劃分,不區分資料的屬性,如程式碼段、資料段。
目標檔案是未經過連結的,裡面的符號和地址沒有調整導致無法執行。例如直接執行目標檔案,系統提示無法執行該二進位制檔案。
$ . hello.o bash: .: hello.o: cannot execute binary file $ file hello.o hello.o: Intel amd64 COFF object file, no line number info, not stripped, 7 sections, symbol offset=0x2a0, 22 symbols, 1st section name ".text"
ELF檔案格式在位元組對齊和元素解析時,與系統架構、字長有密切關係,ELF 檔案由ELF header和各種段組成,其結構圖如下所示。詳細檔案可以查閱https://elinux.org/Executable_and_Linkable_Format_(ELF)。
ELF 檔案的最前面是檔案頭,描述了ELF檔案的基本屬性,比如ELF檔案版本、目標機器型號、程式入口地址。
詳細的描述可以參考:https://refspecs.linuxfoundation.org/elf/gabi4+/ch4.eheader.html
#define EI_NIDENT 16 typedef struct { unsigned char e_ident[EI_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; 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; $ readelf -h /bin/ls ELF Header: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 Class: ELF64 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: DYN (Position-Independent Executable file) Machine: Advanced Micro Devices X86-64 Version: 0x1 Entry point address: 0x6180 Start of program headers: 64 (bytes into file) Start of section headers: 145256 (bytes into file) Flags: 0x0 Size of this header: 64 (bytes) Size of program headers: 56 (bytes) Number of program headers: 11 Size of section headers: 64 (bytes) Number of section headers: 30 Section header string table index: 29
上面結構體裡成員型別長度的定義為:
名稱 |
大小 |
說明 |
Elf32_Addr |
4 |
無符號程式地址 |
Elf32_Half |
2 |
無符號中等整數 |
Elf32_Off |
4 |
無符號檔案偏移 |
Elf32_SWord |
4 |
有符號大整數 |
Elf32_Word |
4 |
無符號大整數 |
unsigned char |
1 |
無符號笑整數 |
Elf32_Ehdr 各個成員簡介:
其中e_ident 對應了對各欄位,有MAGIC、Class、Data、Version、 ABI這幾個引數。
Name |
Value |
Purpose |
EI_MAG0 |
0 |
File identification |
EI_MAG1 |
1 |
File identification |
EI_MAG2 |
2 |
File identification |
EI_MAG3 |
3 |
File identification |
EI_CLASS |
4 |
File class |
EI_DATA |
5 |
Data encoding |
EI_VERSION |
6 |
File version |
EI_OSABI |
7 |
Operating system/ABI identification |
EI_ABIVERSION |
8 |
ABI version |
EI_PAD |
9 |
Start of padding bytes |
EI_NIDENT |
16 |
Size of e_ident[] |
1)MAGIC是ELF標誌碼:魔數,佔4位元組,byte0固定為0x7F,byte1--byte3是'E', 'L', 'F' 的ASCII碼。
2)EI_CLASS 是CPU字長型別。
Name |
Value |
Meaning |
ELFCLASSNONE |
0 |
Invalid class |
ELFCLASS32 |
1 |
32-bit objects |
ELFCLASS64 |
2 |
64-bit objects |
3)EI_DATA
0:非法格式
1:小端位元組序LSB
2:大端位元組序MSB
4)EI_VERSION: ELF版本號,為1
5)EI_OSABI
Name |
Value |
Meaning |
ELFOSABI_NONE |
0 |
No extensions or unspecified |
ELFOSABI_HPUX |
1 |
Hewlett-Packard HP-UX |
ELFOSABI_NETBSD |
2 |
NetBSD |
ELFOSABI_LINUX |
3 |
Linux |
ELFOSABI_SOLARIS |
6 |
Sun Solaris |
ELFOSABI_AIX |
7 |
AIX |
ELFOSABI_IRIX |
8 |
IRIX |
ELFOSABI_FREEBSD |
9 |
FreeBSD |
ELFOSABI_TRU64 |
10 |
Compaq TRU64 UNIX |
ELFOSABI_MODESTO |
11 |
Novell Modesto |
ELFOSABI_OPENBSD |
12 |
Open BSD |
ELFOSABI_OPENVMS |
13 |
Open VMS |
ELFOSABI_NSK |
14 |
Hewlett-Packard Non-Stop Kernel |
64-255 |
Architecture-specific value range |
ELF 檔案中有很多段,段表(Section Header Table)就是儲存這些段的基本屬性的結構。段表描述了ELF各個段的資訊,如段名、段的長度、在檔案中的偏移、讀寫許可權等。段表在ELF檔案中 的偏移是由檔案頭的e_shoff成員決定的。
typedef struct{ 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
Elf32_Shdr成員含義:
sh_type :段的型別。
Name |
Value |
SHT_NULL |
0 |
SHT_PROGBITS |
1 |
SHT_SYMTAB |
2 |
SHT_STRTAB |
3 |
SHT_RELA |
4 |
SHT_HASH |
5 |
SHT_DYNAMIC |
6 |
SHT_NOTE |
7 |
SHT_NOBITS |
8 |
SHT_REL |
9 |
SHT_SHLIB |
10 |
SHT_DYNSYM |
11 |
SHT_LOPROC |
0x70000000 |
SHT_HIPROC |
0x7fffffff |
SHT_LOUSER |
0x80000000 |
SHT_HIUSER |
0xffffffff |
sh_flag:段的標誌位,表示該段在程序的虛擬地址空間中的屬性,如是否可讀、寫、執行。
Name |
Value |
notes |
SHF_WRITE |
0x1 |
可讀 |
SHF_ALLOC |
0x2 |
需要分配空間 |
SHF_EXECINSTR |
0x4 |
可執行 |
SHF_MASKPROC |
0xf0000000 |
sh_link 和 sh_info: 如果段是與連結相關的,比如重定位表符號表等,sh_link和sh_info這兩個成員所包含的意義如下所示。
sh_type |
sh_link |
sh_info |
SHT_DYNAMIC |
該段所使用的字串表在段表中的下標 |
0 |
SHT_HASH |
該段所使用的符號表在段表中的下標 |
0 |
SHT_REL |
該段所使用的相應符號表在段表中的下標 |
該重定位表所作用的段在段表中的下標 |
SHT_RELA |
該段所使用的相應符號表在段表中的下標 |
該重定位表所作用的段在段表中的下標 |
SHT_SYMTAB |
作業系統相關的 |
作業系統相關的 |
SHT_DYNAMIC |
作業系統相關的 |
作業系統相關的 |
other |
SHN_UNDEF |
0 |
rel.txt段就是重定位表,型別sh_type為SHT_REL(9)。連結器在處理目標檔案時,對目標檔案某些部位進行重定位,即程式碼段和資料段中的那部分絕對地址參照。這些重定位資訊記錄在ELF檔案的重定位表中。
ELF中有很多字串,如變數名段名等,但是字串長度是不定長的,如果用固定的長度來表示比較困難,常見的做法是把字串集中起來放到一個表中,然後使用字串在表中的偏移來參照字串。
在ELF檔案中,把函數和變數統稱為符號(Sysbol),每個符號有一個相應的值叫做符號值。對函數和變數來說,符號值就是它們的地址。在ELF檔案中,用.symtab這個段來記錄符號表。
typedef struct{ 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
st_info 高4位元表示符號繫結資訊,低4位元表示符號型別。
Symbol Binding, ELF32_ST_BIND
Name |
Value |
STB_LOCAL |
0 |
STB_GLOBAL |
1 |
STB_WEAK |
2 |
STB_LOPROC |
13 |
STB_HIPROC |
15 |
Symbol Types, ELF32_ST_TYPE
Name |
Value |
STT_NOTYPE |
0 |
STT_OBJECT |
1 |
STT_FUNC |
2 |
STT_SECTION |
3 |
STT_FILE |
4 |
STT_LOPROC |
13 |
STT_HIPROC |
15 |
.plt和.got 動態連結的跳轉表和全域性入口表。
程式碼段(.text): 程式碼資料
資料段(.data): 初始化過了的全域性變數和區域性靜態變數
唯讀資料段(.rodata) 唯讀資料如const值、字串常數。
.bss段:未初始化的全域性變數和區域性變數,是否為全域性變數和區域性變數預留空間和編譯器的實現相關。
自定義段:在變數和函數前加__attribute__((section("name"))) 屬性就可以把相應的函數或變數放到以name作為段名的段中。
雖然ELF把可變資料和不可變資料分的很細,使用者也可以自己新增段或命名一個段,但載入器把ELF檔案載入到記憶體時,並不按照ELF的結構讀取。例如目標檔案.o裡的程式碼段.text是section,連結時多個可重定位檔案整合成一個可執行的檔案,為了提高程式的效率,連結器把目標檔案中相同的section 整合成一個segment,方便執行時載入器載入程式。由於虛擬記憶體的對映和優化的存在,ELF檔案在載入到虛擬記憶體時,也會合並不同的段來達到節約資源的目的。
1、Linux Referenced Specifications https://refspecs.linuxbase.org/
2、Executable and Linkable Format (ELF) https://elinux.org/Executable_and_Linkable_Format_(ELF)
3、ELF檔案格式 https://zhuanlan.zhihu.com/p/286088470
尊重原創技術文章,轉載請註明: https://www.cnblogs.com/pingwen/p/17323862.html