1. 程序未加载前的逻辑地址
程序编译完成后,内部已存在虚拟地址概念。每个地址对应不同的指令,这些虚拟地址划分为不同区块,类似于进程地址空间结构。这是因为编译器设计需考虑操作系统规范,此时的虚拟地址称为逻辑地址。CPU 执行指令从初始地址开始顺序执行,遇到跳转则跳转,最终返回继续执行。
2. 程序加载后的物理地址映射
当程序从磁盘加载至物理内存后,每条指令拥有物理地址。执行前需确定起始地址,程序生成时会创建表头,内含 entry 入口地址。该地址加载至 CPU 的 EIP/PC 寄存器,CPU 通过 task_struct 中的 cwd 和 exe 获取工作路径及可执行文件位置,随后从 entry 地址开始执行指令。
此时虚拟地址与物理地址尚未通过页表映射,访问时会触发缺页中断,建立映射关系。CPU 读取的指令可能包含数据或地址,若访问的虚拟地址内容不存在即发生缺页中断。此过程形成循环,确保访问地址均为虚拟地址。
3. 动态库的地址与位置无关码
关键问题在于共享库过大,无法固定映射到特定位置。当 CPU 访问动态库函数时,根据映射在共享区查找。若动态库方法为绝对编址,则必须加载到固定位置,但这不可行。因此采用偏移量方式进行相对编址,使库在任何位置都能通过偏移找到对应函数。这就是加载动态库时需加入 -fPIC(位置无关代码)选项的原因。
静态库对比: 静态库在编译时直接加载入程序,方法地址固定,故无需讨论加载位置无关性。
4. 信号与进程地址空间
CPU 内部信号(如汇编语句 int 80)用于从用户态陷入内核态,赋予进程访问操作系统数据的权限。
页表数量:
- 用户页表:每个进程一份,体现进程独立性。
- 内核页表:系统只有一份,所有进程看到的 3~4GB 内核空间内容及代码一致。进程切换时,内核空间内容保持不变。
视角差异:
- 进程视角:调用系统方法是在自身地址空间执行。
- 操作系统视角:任意时刻都有进程调度,可随时执行操作系统代码。
操作系统的本质是基于时钟中断的死循环。硬件时钟芯片定期发送时钟中断。
5. 多线程与资源分配
CPU 中 CR3 寄存器存储页表的页目录地址,另有寄存器存储进程控制块地址。
虚拟地址转物理地址(32 位为例): 32 位虚拟地址分为三部分:10 位页目录索引 + 10 位页表索引 + 12 位页内偏移。
- 前 20 位确定页框起始位置。
- 页框起始位置 + 最后 12 位偏移量 = 物理地址中的数据。
创建进程是较重的工作。至此可知,虚拟地址映射物理地址的原理,访问变量即为起始地址加类型偏移。
线程资源分配: 线程分配资源的本质是分配地址空间的范围。


