Loading

程序中的地址如何转换

程序中的地址如何转换

操作系统学习笔记,如有错误,还请斧正

我们有什么问题

  • 程序的地址为啥需要转换?
  • 物理地址是什么?
  • 虚拟地址是什么?
  • 虚拟地址和物理地址的关系和转换机制是什么?

什么是物理地址

我们的内存只认识物理地址。其实物理地址也是一种数据,它对应于我们的硬件电路(地址译码器等)产生的电子信号,在地址总线上,一组电子信号的组合会选择到内存的某个存储单元。打个比方,内存就是个酒店,它的存储单元就是一个个房间,每个房间有独一无二的房间号,而你想要找到某个房间,必须提供房间号给前台,前台好比地址总线,然后你就可以根据前台来找到对应的房间了。这里的房间号就是物理地址。

程序的地址为什么要转换

我们写的程序对应到计算机内部一般就分为两个部分:CPU计算执行和内存存储。CPU执行好理解,即一步一步的执行某些指令(也就是我们的程序),此时,这些指令是存放在内存里的。

 

CPU执行程序、处理数据都要先跟内存芯片打交道,通过他们之间的地址总线和数据总线获得特定的数据。

 

首先,我们不考虑地址转换,即不考虑虚拟地址,这就对应CPU的实模式。现在我们编写了程序A,想让他运行。这是一件容易的事,因为程序A的地址就是物理地址,且内存中只有程序A。这时,我们再加入程序B,此时问题便出现了,A,B同时运行时,内存中既有A的程序也有B的程序,我们应该如何分配内存空间呢,我们起码要保证A和B的程序不会互相越界,这其实是一个复杂的问题,而且当更多的程序一起运行时,问题会更加复杂。这时,计算机科学家提出了一种解决方案——引入虚拟地址。虚拟地址是我们自己规定的从0开始的数,它并不实际存在于硬件中,只是我们规定的逻辑上的地址。每个程序都是一块虚拟地址,在数值上他们可能是一样的,但他们所对应的物理地址是不同的。这样就实现了内存分配问题的解耦合,即各个程序不必关心我的地址设定会不会与其他程序有所冲突。下图给出一个简单的示意。

虚拟地址和物理地址的关系和转换机制是什么

上面我们了解到,我们的程序一般设定的地址都是虚拟地址,然而,计算机并不认识我们自己设定的数据,因此,虚拟地址需要被转换为物理地址才能被计算机识别。那么这之间到底是如何转换的呢?答案是MMU(内存管理单元)。

MMU

MMU是通过软硬结合的方式来实现的,即硬件MMU+软件页表。x86和ARM系列的CPU是将MMU集成在CPU核心中的。 MMU 可以接受软件给出的地址对应关系数据,进行地址转换。可以这么说:MMU是一个函数f,输入为虚拟地址v,输出为物理地址p,即p=f(v).

上图从逻辑上展示了MMU工作原理,注意地址关系转换表是存放在物理内存中的。假设虚拟地址和物理地址的转换像上图那样一个虚拟地址对应一个物理地址,这样的转换表是很大的,在32地址空间下,4GB的虚拟地址转换表会将32物理地址空间用完,这样我们就没法存程序了

分页模式

因此,我们需要换一种转换方式。即现代内存管理模式——分页模型

 

分页模式的灵活性、通用性、安全性,是现代操作系统内存管理的基石,更是事实上的标准内存管理模型,现代商用操作系统都必须以此为基础实现虚拟内存功能模块。

 

该方案把虚拟地址空间和物理地址空间都分成同等大小的块(页),按照虚拟页和物理页进行转换,页的大小可以设置为4KB、2MB、4MB、1GB。下面是分页模型框架

一个虚拟页对应一个物理页

分页机制本质:将大小不同的大内存段拆分成大小相等的小内存块,可以提供虚拟的连续内存空间,映射到可以不连续到物理内存,让进程能够运行在不连续到物理空间

 

分页机制可以有效解决转换表太大的问题,那具体情况是什么样的呢?不急,我们需要一些前置知识。

MMU页表

我们上面所说的地址关系转换表就叫做页表

 

为了增加灵活性和节约物理内存空间(因为页表是放在物理内存中的),所以页表中并不存放虚拟地址和物理地址的对应关系,只存放物理页面的地址,MMU 以虚拟地址为索引去查表返回物理页面地址,而且页表是分级的,总体分为三个部分:一个顶级页目录,多个中级页目录,最后才是页表,逻辑结构图如下

从上面可以看出,一个虚拟地址被分成从左至右四个位段。

 

第一个位段索引顶级页目录中一个项,该项指向一个中级页目录,然后用第二个位段去索引中级页目录中的一个项,该项指向一个页目录,再用第三个位段去索引页目录中的项,该项指向一个物理页地址,最后用第四个位段作该物理页内的偏移去访问物理内存。这就是 MMU的工作流程

保护模式下的分页

保护模式下只有 32 位地址空间,最多 4GB-1 大小的空间(0x00为空地址,不能存放数据)。

保护模式下的分页大小通常有两种,一种是 4KB 大小的页,一种是 4MB 大小的页。分页大小的不同,会导致虚拟地址位段的分隔和页目录的层级不同,但虚拟页和物理页的大小始终是等同的。

保护模式下的分页-4KB页

该分页方式下,32 位虚拟地址被分为三个位段:页目录索引、页表索引、页内偏移,只有一级页目录,其中包含 1024 个条目 ,每个条目指向一个页表,每个页表中有 1024 个条目。其中一个条目就指向一个物理页,每个物理页 4KB。这正好是 4GB 地址空间。如下图所示

  • CR3提供页目录物理页表基地址
  • 虚拟地址页目录索引提供物理页表中,要查找的页目录项索引
  • 页目录项提供物理页表项基地址
  • 页面索引提供页表项物理页中, 要查找的页表项索引
  • 页表项提供4KB物理页基地址
  • 页内偏移提供4KB物理页中的偏移量

上图中 CR3 就是 CPU 的一个 32 位的寄存器,MMU 就是根据这个寄存器找到页目录的。下面,我们看看当前分页模式下的 CR3、页目录项、页表项的格式。

这里我理解的是它把页表(含有页表项)又套了一层页表,称之为页目录,即页目录表项=页表,页目录表项和页表项都是4KB大小,即1024X4B大小。
 

而由页表的分配方式我们可以知道,4GB内存,4KB大小分页,因此,物理页表寻址至少4GB/4KB = 1MB个数,即需要20位来进行寻址。结合这个思想我们再看上面那个图,CR3拿出高20位来寻址页目录表物理地址(页目录表由页目录表项组成,所以此处寻找的实际上是页目录表项),页目录表项拿出高20位来寻址页表物理地址(页表由页表项组成,此处寻找的是页表项),然后页表项拿出高20位来寻找4KB物理页的地址,找到物理页后就可以根据偏移地址,来找到特定的物理单元。

 

让我们看看页表占了多大的物理内存吧,一层页表大小1024X4B=4KB,页表的页表大小1024X4B=4KB,算下来,一共占了8KB,还是可以接受的。

 

可以看到,页目录项、页表项都是 4 字节 32 位,1024 个项正好是 4KB(一个页),因此它们的地址始终是 4KB 对齐的,所以低 12 位才可以另作它用,形成了页面的相关属性,如是否存在、是否可读可写、是用户页还是内核页、是否已写入、是否已访问等。

 

引用大佬的评论:

首先,内存的页需要20位进行寻址(2^32 / 2^12) 页目录项1024个4B放满一页,即顶级页表只放一页,顶级页表映射出1024个页表,一个页表有2^10即1024个页表项,所以这1024个页表也刚好占了1024个页,那么页目录表项中的地址也为20位,同理,页表项需要找到具体的页,则页表项中的地址也为20位。 剩下的12位就可以作为别的用途了。

感觉理解了一些东西呢😄

(扩充)在分页模式下,操作系统是如何对应用程序的地址空间进行隔离的?

实模式下多个任务共享所有地址空间太危险,因此才有了保护模式,保护模式下的分页模式是一个巨大的创新。
对于每个进程而言,它会误认为(被操作系统欺骗)自己独有所有地址空间,因此它访问地址是不会考虑任何问题的,可是这个地址是虚拟地址,待被MMU翻译后会得到对应的页表,而这个页表由操作系统管理,不同的进程拥有不同的页表,也因此产生了进程地址空间隔离,但是多个进程也是可以共享某个页表,这也是进程通信(IPC)的根本手段。

posted @ 2022-04-24 23:10  Baiyug  阅读(243)  评论(0编辑  收藏  举报