ELF文件中的“节“与“段“,如何与虚拟地址空间中的“分页“和“分段“产生联系?

为了理清它们的关系,必须先说明:

ELF文件中的"段(Segment)"x86 CPU硬件上的"分段(Segmentation)" ,虽然中文和英文名字极其相似,但它们没有任何直接关系

静态视角下的 ELF

在硬盘上,ELF 文件同时具备两种视角:

  1. 链接视图(以"节 Section"为主):
    这是给编译器和链接器 看的。比如存放代码的 .text 节,存放初始化全局变量的 .data 节,存放未初始化变量的 .bss 节。它们切分得非常细致,方便链接器拼图。
  2. 执行视图(以"段 Segment"为主):
    这是给操作系统加载器(Loader)看的。操作系统在运行程序时,根本不关心你这里面有几个"节"。它只关心内存权限。因此,ELF 文件内部会有一个"程序头表(Program Header Table)",它把具有相同权限的"节"合并成一个"段(Segment)"。
  • 比如:把 .text.rodata(只读数据)合并成一个属性为 可读、可执行 (R-E)LOAD Segment
  • .data.bss 合并成一个属性为 可读、可写 (R-W)LOAD Segment

结论 1: ELF 中的"段(Segment)"纯粹是一个软件层面的数据结构打包概念,与 CPU 的硬件分段单元(Segmentation)毫无瓜葛。


操作系统加载 ELF (mmap)

当敲下 ./my_program 回车时,操作系统开始工作。它如何把 ELF 的"段"与虚拟地址空间联系起来?

操作系统读取 ELF 的执行视图(LOAD Segments),然后在进程的虚拟地址空间 中划分出一块块对应的区域(在 Linux 源码中叫 VMA,Virtual Memory Area)。

这个过程是通过一个叫做 mmap 的系统调用完成的。

  • 操作系统说:"ELF 文件的 LOAD Segment 1(包含代码),你应该被放在虚拟地址的 0x4000000x401000,权限是只读和执行。"
  • 这个时候,程序还没有真正进入物理内存(RAM)。操作系统只是在虚拟地址空间里"占了个座",画了一张饼。

分页机制,从虚拟地址到物理内存 (Paging)

现在的状态是:进程拥有了虚拟地址,ELF文件依然躺在硬盘上,物理内存里什么都没有。

当 CPU 的指令寄存器(RIP)指向 0x400000 准备执行第一条指令时,真正的联系发生了:

  1. 缺页中断(Page Fault): CPU 通过逻辑地址(等于虚拟地址)去访问内存。它去查分页表(Page Table) ,发现这个虚拟地址 0x400000 并没有对应的物理内存页!于是 CPU 触发一个"缺页中断",暂停当前程序,呼叫操作系统内核。
  2. 按需调页(Demand Paging): 操作系统内核接管后,查看记录,发现 0x400000 这个虚拟地址对应的是硬盘上 ELF 文件的 LOAD Segment 1 的起始位置。
  3. 加载与映射: 操作系统赶紧从物理内存(RAM)中找一个空闲的物理页(Physical Page,通常是 4KB)。然后把硬盘上 ELF 文件对应的那 4KB 数据复制到这个物理页中。
  4. 更新页表: 操作系统更新当前进程的分页表,写下记录:"虚拟地址 0x4000000x400FFF,对应物理内存的 页框 X"。
  5. 恢复执行: 操作系统把控制权交还给程序,CPU 再次尝试访问 0x400000。这一次,分页单元顺利地通过页表找到了物理内存,指令成功执行。

结论 2: ELF 的"段"决定了虚拟地址空间的布局;而"分页(Paging)"则是连接虚拟地址与物理内存、并按需将 ELF 内容搬运到内存中的底层搬运工


总结

  • 硬件分段(Segmentation): 在 Linux 中被彻底架空(基址设为 0),只负责把逻辑地址原封不动地变成虚拟地址。
  • ELF 节(Section): 细粒度的代码/数据分类,给链接器看。
  • ELF 段(Segment / Program Header): 多个 Section 的集合,按权限分类,操作系统依据它来规划虚拟地址空间的布局。
  • 硬件分页(Paging): 负责把虚拟地址空间切成 4KB 的小块(页),并在程序实际运行时,把 ELF 文件的内容一点点搬进物理内存
相关推荐
一只旭宝2 分钟前
预约系统版本2(pyhton+flask可视化版本)
服务器·数据库·c++·笔记·python·flask
byte轻骑兵4 分钟前
【BlueZ 】BLE 与经典蓝牙的差异:BlueZ 中双模式的源码区分设计
linux·bluez·电脑蓝牙·嵌入式蓝牙
小雪崩1 小时前
嵌入式学习 day30:minilog
linux·c语言·学习
嵌入式小能手1 小时前
飞凌嵌入式ElfBoard-Shell脚本编写基础-传参-$0
linux
丰锋ff1 小时前
初识Linux操作系统
linux·运维·服务器
嵌入式小能手2 小时前
飞凌嵌入式ElfBoard-Shell脚本编写基础-特殊变量
linux·运维·服务器
SWAGGY..2 小时前
【C++初阶】:(15)模板进阶--从非类型参数到模板特化与分离编译
java·服务器·前端
呉師傅2 小时前
关于惠普LaserJet1018打印机在Windows11上打印颜色偏淡的问题解决方法
运维·服务器·windows·计算机外设·电脑
Dovis(誓平步青云)3 小时前
番茄钟真正难的不是倒计时:启动、暂停、重置与页面销毁
android·服务器·前端
吹什么轩3 小时前
Linux系统复习:权限的解析
linux·运维·服务器