elf文件[0]-section和segment的区别
系列:
Section 是给链接器和调试器看的,Segment 是给程序加载器(比如内核、bootloader)加载用的。
具体区别
对比项 | Section(段) | Segment(程序段) |
---|---|---|
来自哪儿 | Section Header Table(由 shoff 定位) |
Program Header Table(由 phoff 定位) |
用途 | 给 链接器、调试器 用 | 给 加载器(如 exec) 用 |
是否加载进内存 | 不一定,比如 .symtab 、.strtab 等只调试用 |
是的,PT_LOAD 类型会加载进内存 |
典型内容 | .text , .data , .bss , .rodata 等 |
一个 Segment 可能包含多个 Section |
是否可选 | 可选(strip 可移除) |
必须存在,运行离不开它 |
ELF 文件结构中 | 在 Section Header Table 描述 | 在 Program Header Table 描述 |
类比理解
假设你在打包东西出门旅行:
- Section(段):像你家衣柜里的“衣服”“裤子”“电器”“洗漱包”这些分类,存储和组织方便,归类清晰(链接器喜欢)。
- Segment(程序段):像你把这些打包进行李箱的“格子”,有的格子是专门放衣服的,有的是放易碎品的(加载器关心怎么加载进“内存”)。
举个例子
你的 ELF 文件里有这些 Section:
.text
— 代码段.data
— 初始化数据.bss
— 未初始化数据.rodata
— 常量数据
它们可能会被合并进两个 Segment:
- 一个只读的 segment:包含
.text
+.rodata
- 一个读写的 segment:包含
.data
+.bss
为什么要合并
为了页对齐、简化加载和权限控制。
页对齐
Segment 通常按页对齐(如 0x1000),以便于映射和访问。
Section 之间未必页对齐,把它们分别搞成 Segment 会浪费内存(碎片)。
合并后可以使用连续的物理页映射,简化内存管理,提高性能。
简化加载
如果每个 Section 都创建一个 Segment,程序加载会非常复杂、低效(更多系统调用、更多内存碎片)。Segment 数量少,加载效率高,exec
调用成本低
权限控制
操作系统通常以「页」为单位管理内存(一般是 4KB)。每个 Segment 会映射到一段虚拟地址空间,并设置相应权限。
比如:
Segment 内容 | 权限 | 包含的 Section |
---|---|---|
代码段(只读可执行) | R-X | .text , .rodata |
数据段(读写不可执行) | RW- | .data , .bss |
总结
Section
是“编译器 / 链接器 / 调试器”的视角(逻辑结构)
Segment
是“加载器 / 内核”的视角(运行时布局)
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Troy's blog!
评论