前言
下文所示案例为运行在armV7架构、linux平台之下的动态库文件。
ELF文件格式
链接器以ELF文件的固定格式对目标程序进行链接,程序加载器以ELF文件的固定格式对其进行解析。ELF文件的组成框架在链接器和加载器的视角中分别如下:
如上图所示,链接器以section为单位对数据进行组织,以section header table对section进行描述,而忽略program header table中的内容;加载器以segment为单位对数据进行组织,以program header table对segment进行描述,而忽略section header table中的内容。其中,加载器中的segment实际由单个或多个链接器中的section组成。ELF文件包含三种类型:可重定位文件(relocatable)—编译器和汇编器产生的.o文件,被Linker所处理;可执行文件(executable)—Linker对.o文件进行处理输出的文件,进程映像;共享对象文件(shared object)—动态库文件.so。
ELF Header
通过readelf工具,查看ELF Header中的内容如下:
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Shared object file)
Machine: ARM
Version: 0x1
Entry point address: 0x2154
Start of program headers: 52 (bytes into file)
Start of section headers: 660064 (bytes into file)
Flags: 0x5000400, Version5 EABI, hard-float ABI
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 8
Size of section headers: 40 (bytes)
Number of section headers: 38
Section header string table index: 37
ELF Header记录了该文件的基本信息:该文件类型为动态库文件;程序入口地址为0x2154(偏移),Program Header Table位于文件偏移量为52字节处,包含8个program header,每个program header占用32个字节描述一个segment;Section Header Table位于文件偏移量为660064字节处,包含38个section header,每个section header占用40个字节,用于描述对应的section;section header string table 对应的section header 在Section Header Table中的索引为37(即最后一个,索引值从0开始),该section为记录了各个section名称的符号表。
Section Header Table
Section Header Table中每个section header由如下结构体进行描述:
typedef struct {
Elf32_Word sh_name; //section 名称,为section header string table的一个偏移量,在该偏移量处保存的以‘\0’结束的字符串即为该section的名称
Elf32_Word sh_type; //section 类型,不同的section类型保存有不同的数据,
Elf32_Word sh_flags; //section 属性标志
Elf32_Addr sh_addr; //section 地址,该section映射到虚拟地址空间的地址,该地址也是文件加载的虚拟地址的偏移
Elf32_Off sh_offset; //section 偏移,该section在elf文件中的偏移量,为物理偏移,sh_addr可以理解为虚拟地址偏移
Elf32_Word sh_size; //section 大小
Elf32_Word sh_link; //与sh_info一样,对于不同的section有不同的含义,但是一般是指本section引用到的section的索引
Elf32_Word sh_info;
Elf32_Word sh_addralign; //section 地址对齐
Elf32_Word sh_entsize; //当section为一个table表时,记录该table表中每一个entry的大小
} Elf32_Shdr;
通过readelf工具查看该文件的Section Header Table,其内容如下:
There are 38 section headers, starting at offset 0xa1260:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .note.gnu.build-i NOTE 00000134 000134 000024 00 A 0 0 4
[ 2] .gnu.hash GNU_HASH 00000158 000158 000144 04 A 3 0 4
[ 3] .dynsym DYNSYM 0000029c 00029c 0007a0 10 A 4 3 4
[ 4] .dynstr STRTAB 00000a3c 000a3c 000c0b 00 A 0 0 1
[ 5] .gnu.version VERSYM 00001648 001648 0000f4 02 A 3 0 2
[ 6] .gnu.version_r VERNEED 0000173c 00173c 000130 00 A 4 6 4
[ 7] .rel.dyn REL 0000186c 00186c 000140 08 A 3 0 4
[ 8] .rel.plt REL 000019ac 0019ac 0002f8 08 AI 3 22 4
[ 9] .init PROGBITS 00001ca4 001ca4 00000c 00 AX 0 0 4
[10] .plt PROGBITS 00001cb0 001cb0 0004a4 04 AX 0