系列:

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 是“加载器 / 内核”的视角(运行时布局)