物理地址查询(计算机物理地址怎么查)

第一,逻辑地址到线性地址机器指令中出现的内存地址都是逻辑地址,需要先转换成线性地址,再由MMU(CPU中的内存管理单元)转换成物理地址才能访问。我们先写一个最简

第一,逻辑地址到线性地址

机器指令中出现的内存地址都是逻辑地址,需要先转换成线性地址,再由MMU(CPU中的内存管理单元)转换成物理地址才能访问。

我们先写一个最简单的hello world程序,用gccs编译,然后反编译看看下面的指令:

mov 0x80495b0,%eax

这里的内存地址0x80495b0是一个逻辑地址,必须加上DS数据段的隐含基址才能形成线性地址。即0x80495b0是当前任务的DS数据段中的偏移量。

在x86保护模式下,段信息(段基线地址、长度、权限等。),即段描述符,占用8个字节,段信息不能直接存储在段寄存器中(段寄存器只有2个字节)。Intel的设计是段描述符集中存储在GDT或LDT,而段寄存器存储段描述符的索引值在GDT或LDT。

Linux中的逻辑地址等于线性地址。为什么这么说?因为所有Linux段(用户代码段、用户数据段、内核代码段、内核数据段)的线性地址都是从0x0000000开始,长度为4G,所以线性地址=逻辑地址+0x00000000,也就是说逻辑地址等于线性地址。

在这种情况下,Linux只使用GDT,用户任务和内核任务都不使用LDT。GDT的第12和第13段描述符是__KERNEL_CS和__KERNEL_DS,第14和第15段描述符是__USER_CS和__USER_DS。内核使用__KERNEL_CS和__KERNEL_DS,所有用户任务共享__USER_CS和__USER_DS,这意味着不需要单独给每个任务分配段描述符。尽管内核段描述符和用户段描述符具有相同的初始线性地址和长度,但DPL(描述符特权级别)是不同的。__KERNEL_CS和__KERNEL_DS的DPL值为0(最高权限),而__USER_CS和__USER_DS的DPL值为3。

使用gdb调试程序时,使用info reg显示当前寄存器的值:

cs 0x73 115

ss 0x7b 123

ds 0x7b 123

es 0x7b 123

可以看到ds值为0x7b,转换成二进制00000000111011,TI字段值为0,表示使用了GDT。GDT索引值为01111,即十进制15,对应GDT的__USER_DATA用户数据段描述符。

从上面可以看出,Linux运行在x86的分段机制上,但是它以一种巧妙的方式绕过了分段。

Linux主要通过分页来实现内存管理。

物理地址查询(计算机物理地址怎么查)

C/C++ Linux服务器架构师需要学习私有信息“信息”(信息包括C/C++、Linux、golang技术、Nginx、ZeroMQ、MySQL、Redis、fastdfs、MongoDB、ZK、流媒体、CDN、P2P、K8S、Docker、TCP/IP、协同学、DPDK、ffmpeg等

物理地址查询(计算机物理地址怎么查)

第二,线性地址到物理地址

前面说过Linux中的逻辑地址等于线性地址,那么线性地址如何对应物理地址呢?众所周知,分页机制,具体来说就是页表查找,对应的是物理地址。

准确的说,分页是CPU提供的一种机制,Linux只是根据这种机制的规则用它来实现内存管理。

在保护模式下,控制寄存器CR0的最高有效PG位控制分页管理机制是否生效。如果PG=1,分页机制生效,仅通过页表查找就可以将线性地址转换为物理地址。如果PG=0,则分页机制无效,直接使用线性地址作为物理地址。

分页的基本原理是将内存分成若干个固定大小的单元,每个单元称为一个页面,每个页面包含4k字节的地址空(为了简化分析,我们不考虑扩展分页的情况)。这样,每页的起始地址是4k字节对齐的。为了转换成物理地址,我们需要给CPU提供一个当前任务的线性地址到物理地址的查找表,也就是页表。注意,为了实现每个任务的扁平虚拟内存,每个任务都有自己的页目录表和页表。

为了节省页表占用的内存空,x86通过页目录表和页表的两级查找,将线性地址转换为物理地址。

32位线性地址分为3部分:

最高的10位目录页目录表偏移量,中间的10位表是页表偏移量,最低的12位偏移量是物理页内的字节偏移量。

页表的大小为4k(正好是一页的大小),包含1024个条目,每个条目4个字节(32位)。存储在条目中的内容是页表的物理地址。如果页目录表中的页表没有被分配,则物理地址用0填充。

页面大小为4k,同样包含1024个条目,每个条目有4个字节,内容为最终物理页面的物理内存起始地址。

每个活动任务必须首先分配一个页目录表,页目录表的物理地址存储在cr3寄存器中。页面可以提前分配,也可以在使用时重新分配。

以mov 0x80495b0,%eax中的地址为例,分析线性地址到物理地址的过程。

前面说过,Linux中的逻辑地址等于线性地址,所以我们要转换的线性地址是0x80495b0。转换过程由CPU自动完成。Linux要做的就是准备好转换所需的页目录表和页表(假设已经准备好了,物理内存分配给页目录表和页表的过程非常复杂,后面会分析)。

内核首先将当前任务的页目录表的物理地址填入cr3寄存器。

线性地址0x80495b0转换成二进制后为0000 1000 0000 0100 1001 0101 1011 0000,最高10位小数0000 1000 00为32。CPU检查存储页表的物理地址的页目录表的第32项。线性地址的中间10位00 0100 1001的小数为73,页表的第73项存储最终物理页的物理起始地址。将物理基址加到线性地址中最低12位的偏移量上,CPU找到线性地址最终对应的物理内存单元。

我们知道Linux中用户进程的线性地址可以在0-3G范围内寻址,那么是否有必要提前建立3G虚拟内存的所有页表?一般物理内存远小于3G,同时运行的进程很多,无法提前为每个进程建立3G线性地址页表。Linux CPU的一种机制被用来解决这个问题。创建流程后,我们可以用零填充页面目录表的所有条目。当CPU搜索页表时,如果条目的内容为零,就会引起缺页异常,进程将被挂起。这时候Linux内核就可以通过一系列复杂的算法分配一个物理页面,将物理页面的地址填入条目中,然后进程就会恢复执行。当然在这个过程中进程是被蒙蔽的,它自己的感觉是正常访问了物理内存。

物理地址查询(计算机物理地址怎么查)

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。

作者:美站资讯,如若转载,请注明出处:https://www.meizw.com/n/40602.html

发表回复

登录后才能评论