ELF File Format Analysis
What is ELF ?
ELF: Executable and Linkable Format, 可执行与可链接格式
ELF格式文件分类
文件类型 | 说明 | 实例 |
---|---|---|
可重定位文件(Relocatable File) | Linux的.o (对应Windows的.obj) | |
共享目标文件(Shared Object File) | Linux的.so (对应Windows的.dll) | |
可执行文件(Executable File) | Linux的/bin目录下的程序 (对应Windows的.exe) | |
核心转储文件(Core Dump File) | 当进程意外终止时,系统将进程的地址空间的内容及终止时的信息转储到该文件中 | Linux的core dump |
Note: The ELF (Executable and Linkable Format) file format corresponds to Linux, the PE (Portable Executable) file format corresponds to Windows and the Mach-O (Mach Object) corresponds to macOS.
ELF Structure:
Before learning about the detail of the multiple kinds of fields in ELF structure, we should know that ELF is not a human friendly state machine data structure description. Because it breaks the human readability princlple or we can say it doesn’t follow the information locality princlple, which means we can’t get the needed information around the content we are reading and having some questions.
There is an easter egg behind the ELF file format. UNIX using a simple file format to express executable file called a.out, which means assembler output. This is why when we compiling file, we will get a file called a.out defaultly.
补充字段:
.text
: 源语⾔编译后形成的成机器代码.data
: ⼰初始化的全局变量和局部静态变量.bss
(block started by symbol): 末初始化的全局变量和局部静态变量(这部分数据默认值为 0,其实可以直接放在 .data 段,但是存放 0 没有必要,只需要预留一个位置即可).note.GNU-stack
: 堆栈提示段
为什么要将指令和数据分开存放?
- 权限管理:指令只读,数据可读写
- 提高 cache 命中率:指令数据分离利于提高局部性
- 资源复用:共享指令等只读数据
关于 ELF 中的这些 section,应用程序是可以使用一些非系统保留的名字作为段名的(可以通过__attribute__((section("name")))
来指定变量或函数所属的section),并且 ELF 也是支持具有相同名称的 section 同时存在的。
section 的名称对于 compiler 和 linker 来说是有意义的(待明确意义是什么),对于操作系统没有实质性意义,操作系统如何处理一个 section 取决于它的属性和权限
data rodata bss section
变量类型 | 初始化状态 | 存储段 |
---|---|---|
全局非静态变量 | 未初始化 | .bss |
初始化为零 (=0) | .bss | |
初始化为非零 (=42) | .data | |
全局静态变量 (static) | 未初始化 | .bss |
初始化为零 (=0) | .bss | |
初始化为非零 (=10) | .data | |
局部静态变量 (static) | 未初始化 | .bss |
初始化为零 (=0) | .bss | |
初始化为非零 (=20) | .data | |
局部非静态变量 | 未初始化 | 栈 |
初始化为任意值 | 栈 |
实际上,我们可以比较确定的只有静态变量(全局/局部)和局部非静态变量的表现。对于全局非静态变量,在未初始化或者初始化为 0 时的表现和编译器的实现相关,相关理论参见
字符串常量理论上属于只读数据,但是有些编译器会将其放置在 .data 段中
重定位表
如果一个 section 需要进行重定位,那么就会存在一个对应的重定位表,例如 .rel.text
是 .text
section 的重定位表,.rel.data
是 .data
section 的重定位表
符号表
需要了解的是,使用 ld
作为链接器生成可执行程序时,其会自动定义一些来自链接器的链接脚本中的特殊符号,我们无需定义但是可以声明后引用。
相关工具同 ELF 字段的对应关系
objdump
就是挑选了 ELF 中的一些关键 section 做了输出readelf
是读取了 section table 的内容nm
读取了 symbol table 的内容
How can we understand ELF ?
- A file which stores the program data in a special structure.
- A data structure which describes the initial state of state machine
这种说法来源于,可执行文件的执行就是操作系统状态机的一种状态切换,在可执行文件被 execve
加载后状态就切换到该程序,而该程序的字节序列中所包含的一些数据规定了程序的初始状态,从状态机的角度来说就相当于给定了状态机的初始状态描述。
What are the more important things in ELF ?
When we use the static library, there are three important things in ELF we care: 1
- code(代码)
- symbol(符号)
- relocate(重定位)
When we use the dynamic library, in addition to the above content, there are two other important things in ELF.
- GOT(Global Offset Table)
- PLT(Procedure Linkage Table)