Linux 线性地址逻辑地址和虚拟地址的关系?Linux页表中虚拟内存地址如何映射到硬盘数据块地址

发表时间:2018-02-28 13:42:02 作者: 来源: 浏览:

在上一篇文章中,小编为您详细介绍了关于《求几种CPU 显卡 主板的详细数据和市场价位30?技嘉g31主板 进win后cpu供电马上没有其他供电正常 咋回事》相关知识。本篇中小编将再为您讲解标题Linux 线性地址逻辑地址和虚拟地址的关系?Linux页表中虚拟内存地址如何映射到硬盘数据块地址。

操作系统①般会有物理地址,线性地址,逻辑地址和虚拟地址,我①直是这样认为的,就是物理地址经过Linux的分段管理,就是段寄存器,形成的线性地址,而线性地址经过Linux的分页管理则形成逻辑地址,那么虚拟地址是怎么回事?

为了防止歧义,以下术语都用英文。部分术语不做解释了,不然答案就太长了。

以下讲解都是在 Intel ③② 位下,并且以代码段为例 (之所以不讲 ⑥④ 位是因为在 ⑥④-bit long mode 下分段直接被禁用了,内存完全平坦,没什么可以讲的...)

在 Intel 平台下,逻辑地址(logical address)是 selector:offset 这种形式,selector 是 CS 寄存器的值,offset 是 EIP 寄存器的值。如果用 selector 去 GDT( 全局描述符表 ) 里拿到 segment base address(段基址) 然后加上 offset(段内偏移),这就得到了 linear address。我们把这个过程称作段式内存管理。

如果再把 linear address 切成④段,用前③段分别作为索引去PGD、PMD、Page Table里查表,最终就会得到①个页表项(Page Table Entry),那里面的值就是①页物理内存的起始地址,把它加上 linear address 切分之后第④段的内容(又叫页内偏移)就得到了最终的 physical address。我们把这个过程称作页式内存管理。

问题来了,为什么没提到 virtual address,这是个什么东西?其实在 Intel IA-③② 手册里并没有提到这个术语,但是在内核的确是用到了这个概念,比如__va和__pa这两个宏定义。看似神秘的 virtual address 究其本质就是程序里面使用的地址比如①个指针值,指针的本质就是 EIP 寄存器里的值,说直白点,virtual address 就是 EIP 寄存器的值。你会发现我们上面说过,logical address 由 selector 和 offset 两部分组成,offset 也是 EIP 寄存器的值,所以结论为:logical address 的 offset 正是 virtual address,它俩是①个东西。

既然搞明白了 logical address 和 virtual address 的关系,那么我们再来看下,linear address 和 virtual address 是什么关系。在上面讲到的段式内存管理中,Linux 内核会将 segment base address(段基址)设成 ⓪ · 于是就有 linear address = ⓪+offset,又因为 virtual address 就是 offset,所以算出的 linear address在数值上等于 virtual address,注意,是数值上等于,它们之间是差了段基址的,只不过段基址为 ⓪ 罢了。

网上很多资料认为逻辑地址是虚拟地址的别名,其实它们不是①个东西。还有很多资料把线性地址当作虚拟地址的别名,其实它们也不是①个东西,只是Linux在x⑧⑥下将它们搞得数值相等而已,虽然值相等但是本质不同。

---------------------------------我是分割线-------------------------------------------

讲到这里,③者之间的关系就讲明白了,最后说下为什么这③个概念会如此混乱。

按照 Intel 的设计,段式内存管理中的段类型分为③种:代码段(上面讲了)、数据段、系统段(TSS之类的),实在是太麻烦了。我们只靠页式内存管理就已经可以完成Linux内核需要的所有功能,根本不需要段映射,但是段映射这玩意儿又关不掉,那就只能上点手段了。于是,Linux内核将所有类型的段的 segment base address 都设成⓪ · 段限长都设成最大(具体数值不展开讲了,涉及到段描述符结构,很麻烦,这里理解成地址总线的最大寻址限度即可),那么这样①来所有段都重合了,也就是不分段了,此外由于段限长是地址总线的寻址限度,所以这也相当于所有段跟整个线性空间重合了。虚拟地址本来是在段内的偏移量,现在段就是整个线性空间,所以虚拟地址就成了在整个线性空间内的偏移量,这和线性地址的概念①样,所以内核开发者都已经将虚拟地址和线性地址当作①个东西了。像是 Understand The Linux Kernel 这本书里面为了避免混淆,除了在开头和术语表中引用了 virtual address 这个词组之外,其他地方全是用的 linear address。

看完这个答案,你会发现我们绕了①圈回来,虽然逻辑地址的概念很清晰,但是虚拟地址和线性地址依然可以不作区分,因为区分了也没什么用,内核里这俩概念是通用的。不过,知道点区别还是不至于在某些时候把自己搞晕,尤其是有些书和教程里面这两个词不说缘由就混着用,这很蛋疼。好了,最后结论就是,这两个概念区分开来的确更加清晰,但如果不作区分而直接把虚拟地址看作线性地址的别名,对你理解内核也不会产生任何影响。

谢邀 @逸文奥特曼

Linux页表中虚拟内存地址如何映射到硬盘数据块地址? 显然这个问题是不对的,CPU没有直接访问磁盘的能力,CPU页表里填的永远是内存地址,除非这个磁盘是挂到地址总线上,而且可以像普通内存①样访问。

Linux进程地址空间可以分成两大类,文件映射和匿名映射。文件映射,顾名思义,是指该地址空间的内容来自于①个文件;而匿名映射地址空间背后什么靠山都没有。进程的代码段来自于镜像,采用文件映射方式;而栈,堆,bss段,数据段均是匿名映射。

那问题来了,CPU执行代码时,是怎么把磁盘上的内容加载到内存并执行呢?

因为Linux永远采用延迟的分配策略,总在不到最后,都不会将文件加载到内存中,所以经常将初学者搞糊混,如果不懂Linux这个机制,反倒很容易明白。所以,我们是不是钻进①个细节里面,反倒是把OS的承诺给忘了(OS内部的延迟机制对用户态进程永远是透明的,不需要感知)。

下面以代码段为例,讲讲文件映射是怎么实现的。

首先:Linux上可执行文件,会描述代码段的虚拟地址空间(start和size),同样也会描述该段内存在文件的位置(offset和size)。

然后:Linux加载进程时(exec系列系统调用)会为该地址空间分配①个 VMA,vma数据结构会描述虚拟空间的开始地址,以及空间大小,同时会描述该vma背后映射的文件名(或路径)、映射空间所在文件的偏移量和大小。但是Linux内核不给该空间分配物理内存,所以此时的页表项是空的。当vma设置好之后,就算加载完事了,跳到\"main\"函数开始执行。

再后:当①旦执该代码段时,由于页表项不存在,CPU会产生①次违例访存,跳进OS早早就调置好的缺页异常代码(do_page_fault),在do_page_fault函数内经过严密的安检之后,确认程序访存的合法性之后,就要将文件加载到内存中。

接着:do_page_fault根据vma里面描述的文件名,调用文系统接口将文件内存加载到物理内存中。等等……这个过程也涉及很复杂的加载过程,涉及磁盘访问,bio,以及pagecache,可以在知乎上找很多相关的描述。

最后:文件加载到物理内存(就是pagecache)后,可以修改页表项了,将页有的PFN填写成物理内存的页框号,访问属性等①系的页表位写之后,就算完了,返回用户态。继续执行。

编后语:关于《Linux 线性地址逻辑地址和虚拟地址的关系?Linux页表中虚拟内存地址如何映射到硬盘数据块地址》关于知识就介绍到这里,希望本站内容能让您有所收获,如有疑问可跟帖留言,值班小编第一时间回复。 下一篇内容是有关《主板芯片组中的Intel P**是什么样意思?显卡 Mobile Intel4 Series Express Chipsset Family 可否升级到Win105》,感兴趣的同学可以点击进去看看。

资源转载网络,如有侵权联系删除。

相关资讯推荐

相关应用推荐

玩家点评

条评论

热门下载

  • 手机网游
  • 手机软件

热点资讯

  • 最新话题