1. 背景
由于一直对 elf 文件充满好奇心,链接器如何将 elf 文件链接成可执行文件的?可执行文件为什么可执行?操作系统到底是怎么将该文件加载并让 CPU 去执行的?这些真要弄明白,其实并不容易,因此,首先就从 elf 文件的格式开始探索吧!!
2. 什么是 ELF
ELF(Executable and Linking Format)是一种文件格式,该格式的文件可执行,可链接。可执行是站在操作系统的角度的,可链接是站在链接器(Linker)的角度。可执行指的是操作系统能够加载该文件到内存中,并让 CPU 去执行该文件中的指令。可链接指的是链接器能够将分离的这种格式的文件链接(拼图)成为一个可以让操作系统加载的文件。
实际上,让 cpu 执行与 链接器链接 这两个动作是非常复杂的,而 elf 格式的目的就是辅助操作系统或者链接器去完成这些动作,不然随意整一格式的文件,操作系统与链接器肯定是不认识的(除非自己写操作系统,自己写编译器、链接器,然后自己定出自己的格式)。
经常使用的 ELF 文件类型
- 可执行文件(.out): 该文件上述说过了,可被操作系统加载
- 可重定位文件(.o): 上述可链接文件
- 共享库文件(.so): 动态库文件
- 内核转储文件(coredump): 当用户态程序发生段错误时,操作系统将该进程发生错误时刻的上下文保存到该文件中(pid、ppid、信号、寄存器等等信息)
3. 实验环境
-
操作系统使用的是 ubuntu 18.04,其他 linux 发行版皆可
-
编译工具链:gcc
-
实验源码,只编译不链接,本文章探究可重定位文件(可执行文件与之类似)。
gcc -c my_test.c unsigned int data_0 = 0xffff0000; unsigned int data_1 = 0xffff1111; static int data_bss; int func_0(void); int func_1(void);
-
可执行文件是将可重定位文件中相同类型的的 section 聚合到一起形成 Segment,这样有利于操作系统的加载。
4. ELF 文件布局
从上到下,包含了 elf 头、程序头表、各种类型的 section、节头表,从箭头可以看出,头表中指向了中间的各个节
section 本文叫做 节
5. ELF header
头的作用就是为了表明,我是 elf 格式的文件,是一种身份的表示,使用 hexdump 工具将文件中的数据按照 16 进制的方式显示出来,如下
hexdump -n 512 -C my_test.o //打印前 512 字节,并显示出对应 ascii 码,高字节在后,如下
00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 |.ELF............|
00000010 01 00 3e 00 01 00 00 00 00 00 00 00 00 00 00 00 |..>.............|
00000020 00 00 00 00 00 00 00 00 d0 01 00 00 00 00 00 00 |................|
00000030 00 00 00 00 40 00 00 00 00 00 40 00 09 00 08 00 |....@.....@.....|
00000040 00 00 ff ff 11 11 ff ff 00 47 43 43 3a 20 28 55 |.........GCC: (U|
00000050 62 75 6e 74 75 20 37 2e 35 2e 30 2d 33 75 62 75 |buntu 7.5.0-3ubu|
00000060 6e 74 75 31 7e 31 38 2e 30 34 29 20 37 2e 35 2e |ntu1~18.04) 7.5.|
00000070 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |0...............|
00000080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000090 01 00 00 00 04 00 f1 ff 00 00 00 00 00 00 00 00 |................|
000000a0 00 00 00 00 00 00 00 00 00 00 00 00 03 00 01 00 |................|
000000b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000000c0 00 00 00 00 03 00 02 00 00 00 00 00 00 00 00 00 |................|
000000d0 00 00 00 00 00 00 00 00 00 00 00 00 03 00 03 00 |................|
000000e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000000f0 09 00 00 00 01 00 03 00 00 00 00 00 00 00 00 00 |................|
00000100 04 00 00 00 00 00 00 00 00 00 00 00 03 00 05 00 |................|
00000110 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000120 00 00 00 00 03 00 04 00 00 00 00 00 00 00 00 00 |................|
00000130 00 00 00 00 00 00 00 00 12 00 00 00 11 00 02 00 |................|
00000140 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 |................|
00000150 19 00 00 00 11 00 02 00 04 00 00 00 00 00 00 00 |................|
00000160 04 00 00 00 00 00 00 00 00 68 65 6c 6c 6f 2e 63 |.........hello.c|
00000170 00 64 61 74 61 5f 62 73 73 00 64 61 74 61 5f 30 |.data_bss.data_0|
00000180 00 64 61 74 61 5f 31 00 00 2e 73 79 6d 74 61 62 |.data_1...symtab|
00000190 00 2e 73 74 72 74 61 62 00 2e 73 68 73 74 72 74 |..strtab..shstrt|
000001a0 61 62 00 2e 74 65 78 74 00 2e 64 61 74 61 00 2e |ab..text..data..|
000001b0 62 73 73 00 2e 63 6f 6d 6d 65 6e 74 00 2e 6e 6f |bss..comment..no|
000001c0 74 65 2e 47 4e 55 2d 73 74 61 63 6b 00 00 00 00 |te.GNU-stack....|
000001d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000200
这就是 elf 文件中前 512 字节的内容,文件头数据结构定义如下
/* linux 内核 elf.h 中定义 */
typedef __u64 Elf64_Addr;
typedef __u16 Elf64_Half;
typedef __s16 Elf64_SHalf;
typedef __u64 Elf64_Off;
typedef __s32 Elf64_Sword;
typedef __u32 Elf64_Word;
typedef __u64 Elf64_Xword;
typedef __s64 Elf64_Sxword;
#define EI_NIDENT 16
typedef struct elf64_hdr {
unsigned char e_ident[EI_NIDENT];// 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Elf64_Half e_type;// 01 00 ,elf 文件类型 1 为重定位文件
Elf64_Half e_machine; // 3e 00
Elf64_Word e_version; // 01 00 00 00
Elf64_Addr e_entry; // 00 00 00 00 00 00 00 00 程序入口地址,可重定位文件不可执行,此时还没有入口地址
Elf64_Off e_phoff;// 00 00 00 00 00 00 00 00 由于是可重定位文件,暂时不存在程序头表,因此为 0
Elf64_Off e_shoff;// d0 01 00 00 00 00 00 00 节头表在该文件中的偏移 0x1d0
Elf64_Word e_flags; // 00 00 00 00
Elf64_Half e_ehsize; // 40 00 elf header 大小,也就是在该文件中的占用也就是该结构的占用 sizeof(elf64_hdr)
Elf64_Half e_phentsize; // 00 00 程序头表大小,可重定位文件中没有,因此为 0
Elf64_Half e_phnum; // 00 00 程序头表个数,可重定位文件中没有,因此为 0
Elf64_Half e_shentsize; //40 00 节头表大小,0x40 字节
Elf64_Half e_shnum; // 09 00 节头表个数
Elf64_Half e_shstrndx; // 08 00 节字符串表在 节头表中的下标
} Elf64_Ehdr;
据上述分析,ELF 文件头中的内容已经按照数据结构的定义一一对照起来了,可以使用 readelf -h my_test.o 进一步查看,如下
ELF 头:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 // e_ident 16字节
类别: ELF64 // e_ident[4] == 02
数据: 2 补码,小端序 (little endian) // e_ident[5] == 01
版本: 1 (current) // e_ident[6] == 01
OS/ABI: UNIX - System V // e_machine
ABI 版本: 0
类型: REL (可重定位文件) // e_type
系统架构: Advanced Micro Devices X86-64 // e_machine
版本: 0x1 // e_version
入口点地址: 0x0 // e_entry
程序头起点: 0 (bytes into file) // e_entry
Start of section headers: 464 (bytes into file) // e_shoff 0x1d0
标志: 0x0
本头的大小: 64 (字节) // e_ehsize 0x40
程序头大小: 0 (字节) // e_phentsize 0x00
Number of program headers: 0 // e_phnum 0x00
节头大小: 64 (字节) // e_shentsize 0x40
节头数量: 9 // e_shnum 0x9
字符串表索引节头: 8 // 0x8
有了 elf head ,可以知道节头部表偏移,得到了 节头部表的位置,解析节头部表就能够找到 节,我们的代码中的 代码与数据就放在这些节中,比如代码放在 .text 节、可读写变量放在 .data 节、初始化为0或者未初始化的全局或静态变量放在 .bss 节、变量名称放在 .strtab 节、节名称放在 .shstrtab 节等等。
6. ELF section head table
根据分析 elf 头我们知道 section head table 的位置 0x1d0,我们找到 0x1d0 的位置,将该文件用 hexdump -C my_test.o 全部打印出来,如下(hexdump 自动省略了一部分为0数据,用 *代替)
00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 |.ELF............|
00000010 01 00 3e 00 01 00 00 00 00 00 00 00 00 00 00 00 |..>.............|
00000020 00 00 00 00 00 00 00 00 d0 01 00 00 00 00 00 00 |................|
00000030 00 00 00 00 40 00 00 00 00 00 40 00 09 00 08 00 |....@.....@.....|
00000040 00 00 ff ff 11 11 ff ff 00 47 43 43 3a 20 28 55 |.........GCC: (U|
00000050 62 75 6e 74 75 20 37 2e 35 2e 30 2d 33 75 62 75 |buntu 7.5.0-3ubu|
00000060 6e 74 75 31 7e 31 38 2e 30 34 29 20 37 2e 35 2e |ntu1~18.04) 7.5.|
00000070 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |0...............|
00000080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000090 01 00 00 00 04 00 f1 ff 00 00 00 00 00 00 00 00 |................|
000000a0 00 00 00 00 00 00 00 00 00 00 00 00 03 00 01 00 |................|
000000b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000000c0 00 00 00 00 03 00 02 00 00 00 00 00 00 00 00 00 |................|
000000d0 00 00 00 00 00 00 00 00 00 00 00 00 03 00 03 00 |................|
000000e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000000f0 09 00 00 00 01 00 03 00 00 00 00 00 00 00 00 00 |................|
00000100 04 00 00 00 00 00 00 00 00 00 00 00 03 00 05 00 |................|
00000110 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000120 00 00 00 00 03 00 04 00 00 00 00 00 00 00 00 00 |................|
00000130 00 00 00 00 00 00 00 00 12 00 00 00 11 00 02 00 |................|
00000140 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 |................|
00000150 19 00 00 00 11 00 02 00 04 00 00 00 00 00 00 00 |................|
00000160 04 00 00 00 00 00 00 00 00 68 65 6c 6c 6f 2e 63 |.........hello.c|
00000170 00 64 61 74 61 5f 62 73 73 00 64 61 74 61 5f 30 |.data_bss.data_0|
00000180 00 64 61 74 61 5f 31 00 00 2e 73 79 6d 74 61 62 |.data_1...symtab|
00000190 00 2e 73 74 72 74 61 62 00 2e 73 68 73 74 72 74 |..strtab..shstrt|
000001a0 61 62 00 2e 74 65 78 74 00 2e 64 61 74 61 00 2e |ab..text..data..|
000001b0 62 73 73 00 2e 63 6f 6d 6d 65 6e 74 00 2e 6e 6f |bss..comment..no|
000001c0 74 65 2e 47 4e 55 2d 73 74 61 63 6b 00 00 00 00 |te.GNU-stack....|
000001d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| // section head table
*
00000210 1b 00 00 00 01 00 00 00 06 00 00 00 00 00 00 00 |................|
00000220 00 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 |........@.......|
00000230 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000240 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000250 21 00 00 00 01 00 00 00 03 00 00 00 00 00 00 00 |!...............|
00000260 00 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 |........@.......|
00000270 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000280 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000290 27 00 00 00 08 00 00 00 03 00 00 00 00 00 00 00 |'...............|
000002a0 00 00 00 00 00 00 00 00 48 00 00 00 00 00 00 00 |........H.......|
000002b0 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
000002d0 2c 00 00 00 01 00 00 00 30 00 00 00 00 00 00 00 |,.......0.......|
000002e0 00 00 00 00 00 00 00 00 48 00 00 00 00 00 00 00 |........H.......|
000002f0 2a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |*...............|
00000300 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 |................|
00000310 35 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 |5...............|
00000320 00 00 00 00 00 00 00 00 72 00 00 00 00 00 00 00 |........r.......|
00000330 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000340 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000350 01 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00 |................|
00000360 00 00 00 00 00 00 00 00 78 00 00 00 00 00 00 00 |........x.......|
00000370 f0 00 00 00 00 00 00 00 07 00 00 00 08 00 00 00 |................|
00000380 08 00 00 00 00 00 00 00 18 00 00 00 00 00 00 00 |................|
00000390 09 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 |................|
000003a0 00 00 00 00 00 00 00 00 68 01 00 00 00 00 00 00 |........h.......|
000003b0 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ...............|
000003c0 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000003d0 11 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 |................|
000003e0 00 00 00 00 00 00 00 00 88 01 00 00 00 00 00 00 |................|
000003f0 45 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |E...............|
00000400 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000410
从 elf 头中可以知道每一个 section head table 的大小为 0x40 个字节,也就是从 0x1d0 开始,每 4 行数据代表一个 table,section head table 结构如下
typedef struct elf64_shdr {
Elf64_Word sh_name; /* 节名称在 节字符串表中的索引 */
Elf64_Word sh_type; /* 节类型 */
Elf64_Xword sh_flags; /* 标识该节的是否可修改可执行等内容 */
Elf64_Addr sh_addr; /* 该节在内存中的虚拟地址 */
Elf64_Off sh_offset; /* 节在该文件中的偏移 */
Elf64_Xword sh_size; /* 该节的大小 */
Elf64_Word sh_link; /* Index of another section */
Elf64_Word sh_info; /* Additional section information */
Elf64_Xword sh_addralign; /* Section alignment */
Elf64_Xword sh_entsize; /* 如果该节是一个表项,该值为每个表项的大小,如符号表 */
} Elf64_Shdr;
通过 struct elf64_shdr 这个结构,配合 hexdump 出来的数据,可以分析出各 section 的基本信息以及在该文件中的偏移,通过 readelf -h my_test.o 可以查看该 elf 文件中各个 section 的信息
可以发现,.text 节位于 section head table 的 1 号位置,而每个表项占用 sizeof(struct elf64_shdr) = 64 字节,因此 .text 节头部表在该文件的起始节头部表 + 64 字节 = 0x1d0 + 0x40 = 0x210 处,如下
00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 |.ELF............|
00000010 01 00 3e 00 01 00 00 00 00 00 00 00 00 00 00 00 |..>.............|
00000020 00 00 00 00 00 00 00 00 d0 01 00 00 00 00 00 00 |................|
00000030 00 00 00 00 40 00 00 00 00 00 40 00 09 00 08 00 |....@.....@.....|
00000040 00 00 ff ff 11 11 ff ff 00 47 43 43 3a 20 28 55 |.........GCC: (U|
00000050 62 75 6e 74 75 20 37 2e 35 2e 30 2d 33 75 62 75 |buntu 7.5.0-3ubu|
00000060 6e 74 75 31 7e 31 38 2e 30 34 29 20 37 2e 35 2e |ntu1~18.04) 7.5.|
00000070 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |0...............|
00000080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000090 01 00 00 00 04 00 f1 ff 00 00 00 00 00 00 00 00 |................|
000000a0 00 00 00 00 00 00 00 00 00 00 00 00 03 00 01 00 |................|
000000b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000000c0 00 00 00 00 03 00 02 00 00 00 00 00 00 00 00 00 |................|
000000d0 00 00 00 00 00 00 00 00 00 00 00 00 03 00 03 00 |................|
000000e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000000f0 09 00 00 00 01 00 03 00 00 00 00 00 00 00 00 00 |................|
00000100 04 00 00 00 00 00 00 00 00 00 00 00 03 00 05 00 |................|
00000110 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000120 00 00 00 00 03 00 04 00 00 00 00 00 00 00 00 00 |................|
00000130 00 00 00 00 00 00 00 00 12 00 00 00 11 00 02 00 |................|
00000140 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 |................|
00000150 19 00 00 00 11 00 02 00 04 00 00 00 00 00 00 00 |................|
00000160 04 00 00 00 00 00 00 00 00 68 65 6c 6c 6f 2e 63 |.........hello.c|
00000170 00 64 61 74 61 5f 62 73 73 00 64 61 74 61 5f 30 |.data_bss.data_0|
00000180 00 64 61 74 61 5f 31 00 00 2e 73 79 6d 74 61 62 |.data_1...symtab|
00000190 00 2e 73 74 72 74 61 62 00 2e 73 68 73 74 72 74 |..strtab..shstrt|
000001a0 61 62 00 2e 74 65 78 74 00 2e 64 61 74 61 00 2e |ab..text..data..| // .text: 2e 74 65 78 74
000001b0 62 73 73 00 2e 63 6f 6d 6d 65 6e 74 00 2e 6e 6f |bss..comment..no| // .data: 2e 64 61 74 61
000001c0 74 65 2e 47 4e 55 2d 73 74 61 63 6b 00 00 00 00 |te.GNU-stack....|
000001d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| // 0 号无名节的信息
*
00000210 1b 00 00 00 01 00 00 00 06 00 00 00 00 00 00 00 |................| // .text 节的信息
00000220 00 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 |........@.......|
00000230 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000240 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000250 21 00 00 00 01 00 00 00 03 00 00 00 00 00 00 00 |!...............|// .data 节的信息
00000260 00 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 |........@.......|
00000270 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000280 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000290 27 00 00 00 08 00 00 00 03 00 00 00 00 00 00 00 |'...............|// .bss 节的信息
000002a0 00 00 00 00 00 00 00 00 48 00 00 00 00 00 00 00 |........H.......|
000002b0 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
000002d0 2c 00 00 00 01 00 00 00 30 00 00 00 00 00 00 00 |,.......0.......|// .comment 节信息
000002e0 00 00 00 00 00 00 00 00 48 00 00 00 00 00 00 00 |........H.......|
000002f0 2a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |*...............|
00000300 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 |................|
00000310 35 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 |5...............|// .note.GNU-stack 节信息
00000320 00 00 00 00 00 00 00 00 72 00 00 00 00 00 00 00 |........r.......|
00000330 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000340 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000350 01 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00 |................|// .symtab 节信息
00000360 00 00 00 00 00 00 00 00 78 00 00 00 00 00 00 00 |........x.......|
00000370 f0 00 00 00 00 00 00 00 07 00 00 00 08 00 00 00 |................|
00000380 08 00 00 00 00 00 00 00 18 00 00 00 00 00 00 00 |................|
00000390 09 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 |................|// .strtab 节信息
000003a0 00 00 00 00 00 00 00 00 68 01 00 00 00 00 00 00 |........h.......|
000003b0 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ...............|
000003c0 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000003d0 11 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 |................|// .shstrtab 节信息
000003e0 00 00 00 00 00 00 00 00 88 01 00 00 00 00 00 00 |................|
000003f0 45 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |E...............|
00000400 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000410
分析 .text 节,该节的名称在 节字符串表中的偏移为 0x1b,而节字符串表在整个文件中的偏移为 0x188 处,因此,.text 节的节名 “.text” 在该 elf 文件的 0x188 + 0x1b = 0x1a3 处,以 \0 结尾,因此 0x1a3 处开始的 2e 74 65 78 74,这 5 个字节对应的 ascii 字符就是 .text,其余节同理,如 .data 节的名字在节字符串表中的偏移是 0x21,因此 0x21 + 0x188 = 0x1A9,对应的 ascii 码为 2e 64 61 74 61。
sh_entsize 这个成员很有意思,对于普通的节,该成员的值为 0,但有些节这个成员不为 0,表明这个节中的内容同样是表组成的,该表项的大小为 sh_entsize。
.symtab 节中 sh_entsize 为 18 00 00 00 00 00 00 00 也就是 0x18 字节,也就是 24 字节,表明该节中的内容同样是个表,类似于正在分析的 section head table (节头部表),为什么偏偏是 24 字节?通过符号表的结构来分析,如下,首先猜测,sizeof(struct elf64_sym) = 24 字节
typedef struct elf64_sym {
Elf64_Word st_name; /* 该符号的名字在字符串表中的起始下标 */
unsigned char st_info; /* Type and binding attributes */
unsigned char st_other; /* No defined meaning, 0 */
Elf64_Half st_shndx; /* Associated section index */
Elf64_Addr st_value; /* Value of the symbol */
Elf64_Xword st_size; /* Associated symbol size */
} Elf64_Sym;
对于符号表的分析,另起一篇文章,符号表还是蛮重要的。