目前主流的可执行文件格式主要分为两种:
两种格式都是COFF格式的变种
下面接下来主要介绍ELF文件的文件结构
将使用下面两个工具查看文件结构:
ELF文件类型:可重定位、可执行、共享目标文件、核心转储文件
linux下可使用命令查看文件格式:file 文件
file demo.o
demo.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
file a.out
a.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked,interpreter /lib64/l, for GNU/Linux2.6.32,
BuildID[sha1]=3a49c2dfa1a516767e95146b666d6d444d6403b9, not stripped
file libopencv_hdf.so.3.3.1
libopencv_hdf.so.3.3.1: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked,
BuildID[sha1]=8a273151900f0f70dca804faae8be408848fefd8, not stripped
linux下可以命令查看段表头对比
readelf -S -W 源文件.o
readelf -S -W 源文件.out
目标文件以代码段的形式存储信息
常用的结构,常用的几个段大致为:
目标文件存储结构 |
---|
ELF Header |
.text |
.data |
.bss |
.rodata |
.comment |
…other section |
string tables symbol tables |
以.开头的段是系统保留段,自定义不以.作为前缀否则容易冲突
自定义段保存可以使用__attribute__((section(“name”))) int a;
,将变量a保存到name段中
readelf -h 目标文件
查看ELF文件头
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 -->7f为ascii码的del控制符,2-4位是ELF的ascii码,02表示64位,第6位表示小段存储,第7位是ELF版本,后面作为扩展
Class: ELF64
Data: 2's complement, little endian-->存储方式,小段存储
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file) -->文件类型
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x4003e0 -->与可执行文件的_start函数地址相同,重定位文件为0
Start of program headers: 64 (bytes into file)
Start of section headers: 6600 (bytes into file) -->文件偏移大小后,段开始的位置
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 9
Size of section headers: 64 (bytes)-->段的大小
Number of section headers: 31-->段的数量
Section header string table index: 28
在/include/elf.h中有文件头的结构体,其对应变量与文件头的一一对应,描述如下:
typedef struct
{
unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ 魔数
Elf64_Half e_type; /* Object file type */ELF 文件类型
Elf64_Half e_machine; /* Architecture */ 机器类型
Elf64_Word e_version; /* Object file version */ ELF版本
Elf64_Addr e_entry; /* Entry point virtual address */ 入口地址
Elf64_Off e_phoff; /* Program header table file offset */
Elf64_Off e_shoff; /* Section header table file offset */ 段表偏移
Elf64_Word e_flags; /* Processor-specific flags */
Elf64_Half e_ehsize; /* ELF header size in bytes */ 文件头大小
Elf64_Half e_phentsize; /* Program header table entry size */
Elf64_Half e_phnum; /* Program header table entry count */
Elf64_Half e_shentsize; /* Section header table entry size */ 段的长度
Elf64_Half e_shnum; /* Section header table entry count */ 段的数量
Elf64_Half e_shstrndx; /* Section header string table index */
} Elf64_Ehdr;
objdump -x 目标文件可以看到段表详细的信息
同时readelf也能查看,我们使用readelf查看段表
raedelf -S -W 目标文件
查看段表
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 0] NULL 0000000000000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 0000000000400238 000238 00001c 00 A 0 0 1
[ 2] .note.ABI-tag NOTE 0000000000400254 000254 000020 00 A 0 0 4
[ 3] .note.gnu.build-id NOTE 0000000000400274 000274 000024 00 A 0 0 4
[ 4] .gnu.hash GNU_HASH 0000000000400298 000298 00001c 00 A 5 0 8
[ 5] .dynsym DYNSYM 00000000004002b8 0002b8 000048 18 A 6 1 8
[ 6] .dynstr STRTAB 0000000000400300 000300 000038 00 A 0 0 1
[ 7] .gnu.version VERSYM 0000000000400338 000338 000006 02 A 5 0 2
[ 8] .gnu.version_r VERNEED 0000000000400340 000340 000020 00 A 6 1 8
[ 9] .rela.dyn RELA 0000000000400360 000360 000018 18 A 5 0 8
[10] .rela.plt RELA 0000000000400378 000378 000018 18 AI 5 24 8
[11] .init PROGBITS 0000000000400390 000390 00001a 00 AX 0 0 4
[12] .plt PROGBITS 00000000004003b0 0003b0 000020 10 AX 0 0 16
[13] .plt.got PROGBITS 00000000004003d0 0003d0 000008 00 AX 0 0 8
[14] .text PROGBITS 00000000004003e0 0003e0 000192 00 AX 0 0 16
[15] .fini PROGBITS 0000000000400574 000574 000009 00 AX 0 0 4
[16] .rodata PROGBITS 0000000000400580 000580 000004 04 AM 0 0 4
[17] .eh_frame_hdr PROGBITS 0000000000400584 000584 000034 00 A 0 0 4
[18] .eh_frame PROGBITS 00000000004005b8 0005b8 0000f4 00 A 0 0 8
[19] .init_array INIT_ARRAY 0000000000600e10 000e10 000008 00 WA 0 0 8
[20] .fini_array FINI_ARRAY 0000000000600e18 000e18 000008 00 WA 0 0 8
[21] .jcr PROGBITS 0000000000600e20 000e20 000008 00 WA 0 0 8
[22] .dynamic DYNAMIC 0000000000600e28 000e28 0001d0 10 WA 6 0 8
[23] .got PROGBITS 0000000000600ff8 000ff8 000008 08 WA 0 0 8
[24] .got.plt PROGBITS 0000000000601000 001000 000020 08 WA 0 0 8
[25] .data PROGBITS 0000000000601020 001020 000014 00 WA 0 0 8
[26] .bss NOBITS 0000000000601034 001034 000004 00 WA 0 0 1
[27] .comment PROGBITS 0000000000000000 001034 000035 01 MS 0 0 1
[28] .shstrtab STRTAB 0000000000000000 0018d6 00010c 00 0 0 1
[29] .symtab SYMTAB 0000000000000000 001070 000660 18 30 47 8
[30] .strtab STRTAB 0000000000000000 0016d0 000206 00 0 0 1
在/include/elf.h中段的结构体,其对应变量与段表结构的一一对应,描述如下:
typedef struct
{
Elf64_Word sh_name; /* Section name (string tbl index) */ 段表名
Elf64_Word sh_type; /* Section type */ 段表类型
Elf64_Xword sh_flags; /* Section flags */
Elf64_Addr sh_addr; /* Section virtual addr at execution */ 段表虚拟地址
Elf64_Off sh_offset; /* Section file offset */ 段表偏移
Elf64_Xword sh_size; /* Section size in bytes */ 段表长度
Elf64_Word sh_link; /* Link to another section */
Elf64_Word sh_info; /* Additional section information */
Elf64_Xword sh_addralign; /* Section alignment */ 段地址对齐
Elf64_Xword sh_entsize; /* Entry size if section holds table */ 项的大小
} Elf64_Shdr;