快乐Linux —— 5. ElF 文件浅析
参考:
《程序员自我修养》《深入理解计算机系统》
https://blog.csdn.net/Vince_/article/details/89076338
http://www.skyfree.org/linux/references/ELF_Format.pdf 这篇英文pdf描述的很详细
0. 简述
ElF (Executable Linkable Format 可执行可连接格式),属于 COFF (Common file format) 通用文件格式 的变种。 因为目标文件( .o) 与可执行文件内容结构相似,所以一般与可执行文件格式采取同一种存储格式,我们将其统称为ELF文件。
我们重点关注 可重定位文件 和 可执行文件 。
有两种不同理解ELF文件的视角。
-
链接视角:在汇编器和链接器看来,ELF文件是由 Section Header Table 描述的一系列 Section。
Program Header Table在汇编和链接过程中没有用到,所以是可有可无的,Section Header Table中保存了所有Section的描述信息。
-
执行视角:在加载器(Loader)看来它是由 Program Header Table 描述的一系列 Segment的集合。
Program Header Table中保存了所有Segment的描述信息,Section Header Table在加载过程中没有用到,所以是可有可无的。
其他需要补充的:
- 可重定位文件需要链接器做进一步处理,所以一定有Section Header Table; 可执行文件需要加载运行,所以一定有Program Header Table; 而共享库既要加载运行,又要在加载时做动态链接, 所以既有Section Header Table又有Program Header Table。
- section:可重定位目标文件中的 .text,.data,.bss 等。
- Segment:是指在程序运行时加载到内存的具有相同属性的区域,由一个或多个Section组成。在静态链接中由一个或多个可重定位目标文件的 section 在链接过程中合并而成。
- 比如有两个Section都要求加载到内存后可读可写,就属于同一个Segment。有些Section只对汇编器和链接器有意义,在运行时用不到,也不需要加载到内存,那么就不属于任何Segment 。
Section Header Table 和 Program Header Table 并不是一定要位于文件开头和结尾的,其位置由ELF Header指出,上图这么画只是为了清晰。
如果仍然对section 和 segment 有疑惑的话,在后面编译链接原理里面有更详细的讲解。
1. ELF可重定位目标文件解析
readelf -S xxx.o
查看文件中的各个段
objdump -s -d xxx.o
查看各个段的内容
-
ELF Header ELF文件头
readelf -h xxx.o
-
.text 代码段
存放已编译的程序的机器指令。
-
.rodata 和 .data
.rodata 存放只读数据和字符串常量。(像printf中的格式串)
.data 存放 已初始化非0 的(全局变量和局部静态变量)。
-
.bss Block Storage Start
存放 初始化为0 的 (全局变量 和 局部静态变量)和 (未初始化 的 局部静态变量)。只在 Section Header 中占一个记录,而不占ELF空间。设置这个区是为了提高空间效率。
而未初始化的全局变量分配给 COMMON 块 在深入理解计算机系统中有这样一段话
在编译链接原理的链接过程中的符号解析详细说明了这个原因。
-
.symtab 符号表
记录ELF文件中用到的所有符号,每个符号有符号值对变量和函数来说,符号值就是它们的地址。
(这块的符号表不包含函数里面的局部自动变量的符号。不要和编译过程中的符号表搞混,前者是由后者在汇编阶段生成)
关于符号的更多信息: https://blog.csdn.net/baidu_41667019/article/details/84789564
-
.rel.text 和 .rel.data 重定位表
-
.debug 调试符号表 .line 源程序中行号和指令映射
当编译器以调试形式生成目标文件时才有这些 section。
-
.strtab 和 .shstrtab
.strtab 保存普通的字符串,比如符号名称,包括.symtab 和 .debug 中符号信息。存放的是ELF文件中的字符串,而不是代码中的字符串。
.shstrtab 常用于保存section名。
-
Section Header Table 段表 / 节头部表
保存各个段的信息包括 段名,段长,文件中的偏移,读写权限等等。
2. ELF可执行目标文件
ELF可执行文件有以下几个特点:
- 与可重定位文件大致类似。
- .init 中定义了一个小函数 叫做 init,程序的初始化代码会调用它。
- 没有 .rel 的区域,因为可执行文件已经被重定位。
可执行文件被设计得很容易加载到内存。在后面的编译链接原理中的装载会详细解释这个。
附加一个网上搜到的图! (右键打开看原图)