地址

我迷失在田野里,渐渐忘记了回家的路

几种不同的地址

名称 概念
逻辑地址 程序产生的段内偏移,由段选择符和段内偏移组成的地址。由操作系统决定,和物理地址一一对应的地址,C语言中的指针即为逻辑地址
逻辑地址就是段+页偏移
线性地址 段基址+段内偏移量构成的地址,如果未开启分页,那么线性地址就是物理地址,否则还需二次转换。
线性地址就是段偏移,但是还未进行页转换的地址
虚拟地址就是线性地址(linux内核明确表示)
物理地址 真实物理内存中的地址,即内存地址寄存器中的地址物理地址

物理地址

物理地址就是硬件支持的地址空间,起始地址为0,一直到$\textrm{MAX}_{\textrm{sys}}$,如下所示:

图片名称

每个物理内存单元的物理地址编号是唯一的,给写程序造成了不便,因此我们需要使用逻辑地址或虚拟地址,建立虚拟地址与物理地址之间的映射,从而可以使用相同的虚拟地址指向不同的物理地址

逻辑地址

CPU运行进程时看到的地址,起始地址为0,一直到$\textrm{MAX}_{\textrm{proc}}$

逻辑地址的作用

  • 避免直接将物理地址暴露,从而导致访问任意内存程序崩溃
  • 可以用相邻的虚拟地址映射到不相邻的物理地址
  • 可以使用一系列的虚拟地址访问大于可用物理内存的内存缓冲区(虚拟内存)
  • 不同进程间使用虚拟地址相互隔离

例如,如果同一时刻由两个进程P1和P2,那么两者的逻辑地址范围是多少?假设逻辑地址最大为65535。实际上,P1和P2可以有一样范围的地址,都为0-65535,操作系统会确保其逻辑地址指向不同的物理地址。

从这个问题中我们也可以看出,操作系统帮我们屏蔽了底层的物理实现。

逻辑地址的生成过程

图片名称

生成时机和限制

  • 编译时(最不灵活,写死的,但是比较简单)
    • 假设起始地址已知
    • 如果起始地址改变,必须重新编译
  • 加载时(加载程序可以选择加载位置,但是加载好了执行过程中不能变)
    • 如编译时起始位置未知,编译器需要生成可重定位的代码
    • 加载时生成绝对地址,在可执行文件中有一个重定位表,根据表修改绝对地址
  • 执行时(执行过程中可以移动代码,最灵活,需要虚拟地址支持)
    • 执行时代码可移动(前两种情况不能随意改动)
    • 需要地址转换(映射)硬件支持

地址转换

虚拟地址(线性地址)到物理地址转换步骤

这里讨论一个二级页表情况下VA到PA的转换过程,已知一个虚拟地址为0x01EB6338,CR3寄存器的值为0xAC0F1000,求物理地址。

第一步:写出二进制地址并拆分

虚拟地址的二进制为:$0000,0001 ,1110 ,1011 ,0110 ,0011 ,0011 ,1000$

按照线性地址2级分页进行划分,地址可以被拆分为:

  • Dir:0000,0001,11
  • Table:10 ,1011 ,0110
  • Offset:0011 ,0011 ,1000

换算成十六进制可得到如下结果:

  • 页目录索引:7
  • 页表索引:0x2B6
  • 偏移量:0x338

第二步:根据CR3寄存器的物理地址确定页目录表的基地址

CR3中存放的物理地址就是页目录表的基地址

第三步:计算页表项的地址

页表地址存放在Page Directory Entry的第7项中,即

1
 [0xAC0F1000 + 4 * 7] = [0xAC0F101C] = 0xAC0F101C: pte

0xAC0F101C这个地址保存了pte的值,假设这个值为0x2F103841,那么其中PTE为0x2F103000,而页表属性为0x381。

第四步:计算页面的物理地址

页表的地址为0x2F103000,存放在第0x2B6项,所以虚拟地址所在页的物理地址为:

1
[0x2F103000 + 0x2B6 * 4] = [0x2F103AD8] = 0x2F103AD8: pa

这里得到的pa是未经偏移的物理地址,假设为0x7095e847,那么页面物理地址为0x7095E000,属性为0x847

最后一步:计算偏移量

最终物理地址为0x7095E000+0x338 = 7095E338

地址生成过程的硬件解释

图片名称

CPU与内存连接的结构图如上图所示,我们从一条指令执行过程出发,分析虚拟地址到物理地址的转换过程。

  • CPU当前正在执行一条指令
    • ALU:需要逻辑地址指向的内存内容
    • MMU:根据页表进行逻辑到物理的转换
    • CPU控制器:给总线发送物理地址请求
  • 内存
    • 根据控制信号是读还是写,向总线发送或接收内容
  • 操作系统
    • 建立逻辑地址LA到物理地址PA的映射,地址转换是MMU硬件完成的,而操作系统只负责提供映射表

寻址方式

现代CPU采用虚拟寻址的方式,需要将虚拟地址翻译成物理地址,这样才能访问真实的物理内存。完成虚拟地址转换为物理地址的的硬件是CPU中的MMU。转换过程为:

图片名称

其中,C语言中的指针就是虚拟地址中的Offset部分,如果关闭了段选,那么线性地址就是虚拟地址。更具体的带有多级页表的转换方式如下:

图片名称

地址检查

在地址转换过程中,操作系统会对地址进行检查。例如在段选过程中,操作系统会判断逻辑地址是否大于段长度寄存器,如果是,那么会触发内存异常。如果不是,那么地址会和段基址寄存器相加,生成线性地址。操作系统负责设置段长度和段基址。

分级

上面的线性地址被分为了两级,分别是:

  • Dir
  • Table

Page Table Entry

PDE与PTE

PDE与PTE的大小都为32位,具体格式如下:

图片名称

PDE(页目录表)

MMU通过%cr3寄存器获得PD位置,即完成不同进程之间PD的切换

PTE(页表)

PTE由Physical Page Number(20-bit)和flags(12-bit)组成,其中:

  • Physical Page Number = PPN,根据这个值可以找到对应的物理内存页的基地址
  • flag记录了该页的控制信息(是否存在、能否写以及能否被进程使用等)

MMU将会把这20位的虚拟地址替换为PTE中的物理地址。PTE由MMU加载并存储在内存中。

标志位解析

标志位 全称 功能
P Present 对于大多数操作系统,如果present为0,代表PDE或PTE数据无效
W Writable 内存是否可写
U(PTE_U) User 用户是否可访问

参考文献

0%