分页机制的主要目的是高效地利用内存。按页来组织和管理内存空间,把暂时不用的数据放到外部存储器(通常是硬盘)上。在启用分页机制后,操作系统将线性地址划分为固定大小的页面(4KB、2MB或4MB)。每个页可以被映射到物理内存或外部存储器上的虚拟内存文件中。
分页由处理器的控制寄存器的三个标志来控制:
1、PG(分页)标志,CR0寄存器的位31,用于启动分页机制。(从intel386处理器开始的所有intel处理器都有这个标志)
2、PSE(页尺寸拓展)标志,CR4寄存器的位4,启动物理地址拓展,可以最多寻址64GB物理内存,否则最多寻址4GB物理内存。(在Pentium和Pentium Pro处理器中引入)
3、PAE(物理地址拓展)标志,CR4寄存器的位5,用于启用大页面支持,当PAE=1时,大页面为2MB,当PAE=0时,大页面为4MB。(Pentium Pro处理器中引入)
1、页表和页目录
1、页目录
页目录是一个由32位页目录项(page-directory entries,PDEs)组成是数组。每个页目录占一个4KB的内存页,每个PDE的长度为4字节,因此每个页目录中最多包含1024个PDE。
2、页表
页表是用来存放页表表项(page-table entries:PTEs)的线性表。每个页表占一个4KB的内存页,每个PTE的长度为4字节,每个页表中最多包含1024个PTE。PTE的iao高20位代表的是4KB内存页的起始物理地址的高20位,该起始物理地址的低12位假定为0。
3、页目录指针表
页目录指针表(page-directory pointer table)包含4个64位的表项,每个表项指向一个页目录,仅用于启用PAE时。启用PAE后,每个PDE和PTE的长度都增大为64位。
2、地址翻译
将32位的虚拟地址翻译为32位的物理地址,其过程可以概括如下:
1、通过CR3寄存器定位到页目录的起始地址。
2、取线性地址的高10位作为索引选取页目录的一个表项(PDE)。
3、根据PDE中的页表基地址(取PDE的高20位,低12位为0)定位到页表。
4、取线性地址的12位到21位作为索引选取页表的一个表项(PTE)。
5、取出PTE中的内存页基地址(PTE的高20位,低12位为0)。
6、取线性地址的低12位作为页中偏移与上一步的内存页基地址相加相加得到物理地址。
3、WinDbg观察分页机制
1、启动计计算器(calc.exe),输入一串数字(如123654)以便后面观察。
2、启动Windbg,附加到计算器程序上开始调试。
3、在Windbg的命令区输入x calc!g*命令列出计算器程序中以g开头的所有符号。
1 | 01014d90 calc!ghnoNum = <no type information> |
4、在Windbg的命令区输入dd calc! gpszNum L1命令,查看该符号地址的内容。
1 | 01014db0 000c4d60 |
5、继续查看地址000c4d60处的内容。
可以看到,地址000c4d60处的内容就是我们在计算器中输入的内容(123654)。
6、将字符串地址000c4d60翻译为物理地址。
虚拟地址000c8868的页目录索引(高10位)为0;页表索引(中间10位)为0011 0001 00,即0xC4;
页内偏移为(低12位)1101 0110 0000,即0xD60。
7、查看calc.exe的页目录基地址。
8、使用!dd命令显示页目录表的内容。
第一个表项内容为2587d001 ,其高20位为页表的起始地址的高20位,低12(067)位为页表属性。
8、使用!dd命令显示页表的内容。
高20位为所在内存页的起始地址的高20位,即0x2b37d000,低12位(067)为内存页属性。
9、查看物理地址中的内容。
可以看到,虚拟地址000c4d60和物理地址2b37dd60中的内容是一致的。