hu3167343 发表于 2011-6-12 19:59

详解Windows内存分页机制 by hu3167343[LSG]

本帖最后由 是昔流芳 于 2011-6-13 09:12 编辑

我的的博客: http://hi.baidu.com/hu3167343 大家支持下,谢谢了.

昨天新买了两本书, 看到了内存分页部分, 特此记录下, 没什么技术含量, 错误之处还请大牛指点.

大多数现代的操作系统都支持虚存, 这使得系统上的每个程序都拥有自己的地址空间. 每当程序读取内存时, 都必须指定一个地址. 对于每个进程, 该地址必须转换为实际的物理内存地址.
例如, 若我们的MzfHips.exe 程序需要的数据在虚拟内存地址的0x0041FF10处, 则实际的物理地址可能被映射为0x01EE2F10.
如下图:

图1: 虚拟地址转物理地址示意图 (图中的数据仅仅是为了演示)

内存地址的转换主要通过一个称为页表目录的特殊表来完成. Intel x86 CPU将页表目录的指针存储在特殊寄存器CR3中. 该寄存器指向一个包含1024个32位值的数组, 称为页目录. 每个数组元素称为页目录项, 它指定了页表在物理内存中的基地址, 还通过状态位指示该页表当前是否存在于内存中. 从页表中可以获得实际的物理地址.


图2: 在内存中寻找页面

下面我们来看下虚拟地址的组成:


由图可知, 虚拟地址的前10位用来定位页目录项, 中间10位用来定位页表项, 最后12位得到具体物理地址的偏移.


到了这里, 我们来总结下具体的步骤:
1.CPU查询CR3寄存器以找到页表目录的基地址
2.操作系统根据所请求的虚拟地址的前10位(如图3), 来定位页目录项, 从而在内存中找到相应的页表.
3.页表根据中间的10位定位该页相应的物理内存首地址
4.根据虚拟地址的后12位得到具体的物理地址相对于首地址的偏移量.
5.最后得到的物理地址即包含我们要请求的数据

知道了前面的知识, 下面我们来看下具体的页目录项和页表项中的内容.
由前面我们知道, CR3寄存器指向页目录的首地址, 而页目录是由最多1024个可能的页目录项组成.
下面我们看下页目录项的地址组成:


当访问页目录项时, 要检查U位(第2位), 若U位为0, 则意味着正在处理的页表只能用于内核.
还要检查W位(第1位), 若W位为0, 则内存是只读的.
页目录项指向整个页表, 即整个页面集合, 因此, 页目录项中的设置应用于整个内存页范围.

下面来看下页表项:


当访问页表项时, 仍然首先要检查U位(第2位), 若U位为0, 则只有内核模式的程序才能够访问该内存页.
还要检查W位(第1位), 以判断读写访问权限.
最后还要判断P位(第0位), 若它设置为0, 则当前内存页被换出在磁盘上. 若它设置为1, 则内存是常驻, 并且当前是可用的.
在将内存页换出后, 内存管理器在成功访问它之前必须将该页换入内存.

还有最后一个问题就是, 系统上的大多数可执行程序的其实地址都是0x00400000. 多个进程如何能使用同一个虚拟地址, 而不会在物理内存中发生冲突?那是因为系统上的每个进程都维护一个独立的页目录, 都拥有自己私有的CR3寄存器的值.
当线程发生切换时, 旧线程的状态会被保存起来. 若当前调度运行的线程不属于刚才的进程, 则当前进程的页目录地址会被加载到CR3寄存器中. 页目录地址可以在进程的KPROCESS结构中找到.



理论性知识到此结束, 下面我们来分析下MmIsAddressValid函数, 加深下对分页机制的了解.(参考combojiang大叔)
下面是ida 看到的ntoskrnl.exe中导出的MmIsAddressValid。
.text:0040C661 ; BOOLEAN __stdcall MmIsAddressValid(PVOID VirtualAddress)
.text:0040C661               public MmIsAddressValid
.text:0040C661 MmIsAddressValid proc near            ; CODE XREF: sub_40D65E+Cp
.text:0040C661                                       ; sub_415459:loc_415470p ...
.text:0040C661
.text:0040C661 VirtualAddress= dword ptr8
.text:0040C661
.text:0040C661 ; FUNCTION CHUNK AT .text:0041B84E SIZE 00000007 BYTES
.text:0040C661 ; FUNCTION CHUNK AT .text:0044A4F2 SIZE 00000019 BYTES
.text:0040C661
.text:0040C661               mov   edi, edi
.text:0040C663               push    ebp
.text:0040C664               mov   ebp, esp
.text:0040C666               mov   ecx, ;取出虚拟地址
.text:0040C669               mov   eax, ecx
.text:0040C66B               shr   eax, 14h      ; 右移20位
.text:0040C66E               mov   edx, 0FFCh      ; 取高10位
.text:0040C673               and   eax, edx
.text:0040C675               sub   eax, 3FD00000h; 加上0xc0300000
.text:0040C675                                       ; PDE = ((VA >> 22) << 2 )& 0xffc + 0xc0300000
.text:0040C67A               mov   eax,
.text:0040C67C               test    al, 1         ; 页目录项的第0位, 即P位
.text:0040C67E               jz      loc_41B84E
.text:0040C684               test    al, al
.text:0040C686               js      short loc_40C6AC ; 判断page size位
.text:0040C688               shr   ecx, 0Ah      ; 右移10位
.text:0040C68B               and   ecx, 3FFFFCh
.text:0040C691               sub   ecx, 40000000h
.text:0040C697               mov   eax, ecx      ; PTE = ((VA >> 12) << 2 ) & 0x3FFFC + 0xc0000000
.text:0040C699               mov   ecx,       ; ecx = PTE Context
.text:0040C69B               test    cl, 1         ; 判断present位
.text:0040C69E               jz      loc_41B84E
.text:0040C6A4               test    cl, cl
.text:0040C6A6               js      loc_44A4F2      ; 判断page size位
.text:0040C6AC
.text:0040C6AC loc_40C6AC:                           ; CODE XREF: MmIsAddressValid+25j
.text:0040C6AC                                       ; MmIsAddressValid+3DE9Fj
.text:0040C6AC               mov   al, 1
.text:0040C6AE
.text:0040C6AE loc_40C6AE:                           ; CODE XREF: MmIsAddressValid+F1EFj
.text:0040C6AE               pop   ebp
.text:0040C6AF               retn    4
.text:0040C6AF MmIsAddressValid endp
.text:0040C6AF

Ps:上面说的理论是在未开启PAE模式下的一般情况, 在开启了PAE的情况下, 可能会有所不同。

hu3167343 发表于 2011-6-12 20:20

这里有水印, 如果看不清楚的话, 大家可以去我博客, 或者看雪. http://bbs.pediy.com/showthread.php?t=135274

chejava 发表于 2014-11-21 08:57

仅有的温柔 发表于 2011-6-18 11:55
**** 作者被禁止或删除 内容自动屏蔽 ****

不同的系统应该有不同的分页机制吧?

wyjackie 发表于 2011-6-13 18:53

不错。学习了

huitian200 发表于 2011-6-14 11:35

很詳細,謝謝樓主分享,學習了!

仅有的温柔 发表于 2011-6-18 11:55

感谢楼主分享

jacalhu 发表于 2011-7-21 13:36

好文章,学习了。。。

ydh423 发表于 2011-7-22 08:46

感谢楼主分享

lieshu 发表于 2011-11-24 10:21

学习了

bambooqj 发表于 2012-4-10 17:01

话说。分页机制是为了保护程序的独立运行么???

781732825 发表于 2012-11-15 10:57

高手啊   ·· 拜膜··
页: [1] 2
查看完整版本: 详解Windows内存分页机制 by hu3167343[LSG]