ELF

ELF文件包括
可重定位文件(Relocatable File) :即 xxx.o 文件。包含适合于与其他目标文件链接来创
建可执行文件或者共享目标文件的代码和数据。
可执行文件(Executable File) :即可执行程序。
共享目标文件(Shared Object File) :即 xxx.so文件。
内核转储(core dumps) ,存放当前进程的执行上下文,用于dump信号触发。

ELF文件由以下四部分组成
1. ELF Header
文件总入口,存放全局元信息: 魔数、32/64 位、大小端、文件类型 (ET_REL/ET_EXEC/ET_DYN)、入口地址、各个表头在文件中的偏移、表头数量、结构体大小。
bash
readelf -h a.out


程序的入口地址,程序是从哪里开始的
2. Program Header Table(程序头表)
执行视图,内核加载进程使用 每一项描述一个 Segment(内存段): 文件偏移、虚拟地址、内存大小、文件大小、读写执行权限、页对齐。
bash
readelf -l a.out


为什么要将section合并成为segment
• Section合并的主要原因是为了减少页面碎片,提高内存使用效率。如果不进行合并,
假设页面大小为4096字节(内存块基本大小,加载,管理的基本单位),如果.text部分
为4097字节,.init部分为512字节,那么它们将占用3个页面,而合并后,它们只需2个
页面。
• 此外,操作系统在加载程序时,会将具有相同属性的section合并成一个大的
segment,这样就可以实现不同的访问权限,从而优化内存管理和权限访问控制。
对
Segment N号段:包含哪些Section 用于完成节的合并

链接器 ld 在生成可执行文件 /.so 的链接阶段 ,就提前按照内存权限,把多个 Section 分组,写入 Program Header(程序头表) 。 Segment 本质:程序头表内的描述条目,是一套 "加载规则"
文件二进制中只有节的数据,段只是对节的分组描述。
通俗理解: Section = 文件里真实存放的数据块(代码、常量、变量) Segment = 链接器预先写好的「分组说明书」,告诉内核:把哪几组节映射到同一块虚拟内存、设置什么读写执行权限。
3. Section Header Table(节头表)
链接视图,链接器、调试工具使用 每一项描述一个 Section(节):.text .data .bss .symtab 等。 所有 ELF 类型(.o、exe、.so)都存在节头表(可被 strip 删除)。
bash
readelf -S a.out


代码结

W可写入
X可执行

数据结

符号结->&引用的实现
4. Section Data(段原始数据)
真正存放机器指令、常量、变量、符号表、重定位表等二进制内容。 .bss 特殊:在节头表有记录,但文件里不占用数据空间
bash
objdump -S ./a.out>section.s



这里面信息和ELF Header, Section Header Table都是一样的
加载
可执行程序加载

对于第一个问题,必然是先有相关的数据结构,然后有ELF格式的二进制文件

未加载到内存时(在磁盘上)
程序有自己的地址空间 ,这是一个逻辑地址空间(也叫虚拟地址空间)
每个程序都有自己的独立的 逻辑地址空间,地址从 0 开始.但这只是逻辑地址,不是物理内存地址


虚拟地址不是加载到内存的时候才有的.其实在形成.o文件时就存在了
bash
objdump -d a.out





| 地址类型 | 说明 | 示例 |
|---|---|---|
| 虚拟地址(VMA) | 程序期望加载到内存的地址 | 0x400000 |
| 文件偏移(File Offset) | 在ELF文件中的位置 | 0x1000 |
| 相对地址(RVA) | 相对于基址的偏移 | 0x100 |
动态库加载
