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(包含代码),你应该被放在虚拟地址的 0x400000 到 0x401000,权限是只读和执行。"
  • 这个时候,程序还没有真正进入物理内存(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. 更新页表: 操作系统更新当前进程的分页表,写下记录:"虚拟地址 0x400000 到 0x400FFF,对应物理内存的 页框 X"。
  5. 恢复执行: 操作系统把控制权交还给程序,CPU 再次尝试访问 0x400000。这一次,分页单元顺利地通过页表找到了物理内存,指令成功执行。

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


总结

  • 硬件分段(Segmentation): 在 Linux 中被彻底架空(基址设为 0),只负责把逻辑地址原封不动地变成虚拟地址。
  • ELF 节(Section): 细粒度的代码/数据分类,给链接器看。
  • ELF 段(Segment / Program Header): 多个 Section 的集合,按权限分类,操作系统依据它来规划虚拟地址空间的布局。
  • 硬件分页(Paging): 负责把虚拟地址空间切成 4KB 的小块(页),并在程序实际运行时,把 ELF 文件的内容一点点搬进物理内存。
相关推荐
程序员清风11 小时前
数据处理脚本工程化:日志、配置、命令行与测试
服务器·开发语言·数据库
readhere11 小时前
从ZYNQ7000开发板,学会启动嵌入式Linux系统——入门学习:EBAZ4205篇目录
linux·启动·嵌入式linux·zynq7000·ebaz4205
打工仔折腾 AI13 小时前
在 Ubuntu ARM64 部署 Q1 V3.0 MuJoCo 模型:加载、单步推理与执行器响应解析
linux·运维·人工智能·python·深度学习·ubuntu·性能优化
yyuuuzz13 小时前
跨境站点日志时区混乱的排查记录
运维·服务器·网络·云计算·aws·1024程序员节
‎ദ്ദിᵔ.˛.ᵔ₎13 小时前
关于Linux 线程局部存储的认识
linux·运维
数字新视界14 小时前
一体化机柜在数据中心运维中的创新应用与优势分析
大数据·服务器·数据库·动环监控系统·动力与环境监控系统
运维行者_15 小时前
网络监控工具怎么选?从设备监控到智能运维的能力清单
运维·服务器·开发语言·网络·人工智能·支持向量机·php
小小de风呀15 小时前
de风——【从零开始学习Linux】(九):进程基础 —— 从冯诺依曼体系到 fork 创建进程
linux·学习
2401_8685347815 小时前
陈冲2026年上海纽约大学全英文毕业演讲
服务器·网络