首页
社区
课程
招聘
[转帖]使用WinDBG观察启用PAE后的分页机制
发表于: 2008-7-4 11:19 11727

[转帖]使用WinDBG观察启用PAE后的分页机制

2008-7-4 11:19
11727
使用WinDBG观察启用PAE后的分页机制

我在《软件调试》一书的2.7节介绍了CPU的分页机制,因为这属于这本书的支持性内容,考虑篇幅限制,没有介绍启用PAE的情况。书出版后,很多读者对这一内容很感兴趣,也有读者遇到了启用PAE的情况。因此决定写这篇短文来介绍一下PAE的概况,以及如何在启用PAE后的系统中做2.7.5节的试验。

PAE是 Physical Address Extension的缩写,即物理地址扩展。简单来说,就是把IA-32处理器的寻址能力从原来的4GB扩展到64GB。寻址4GB空间,要求物理地址的宽度为32位。类似的,要寻址64GB空间,那么物理地址的宽度就是36位。因为这个原因,PAE又被称为PAE-36bit。

如果从CPU的引脚来讲,那么支持PAE的CPU原则上应该有36根地址线,但因为IA-32 CPU的前端总线是64位宽,每次可同时传递8个字节数据。因此实际上省略了低三位地址线。以奔腾4 CPU为例,它的地址线是A[35:3]#。也就是说,CPU在访问内存时,它总是向前端总线给出一个低3位为0的地址,这实际上也起到了将地址按8字节对齐的功效。

PAE功能是P6处理器的第一代产品,Pentium Pro所引入的(参见《软件调试》35页),此后的IA-32 CPU都支持这一特征。系统软件可以使用CPUID指令检测当前运行的CPU是否支持PAE。控制寄存器CR4的第5位(CR4[5])用来启用PAE (参见《软件调试》44页)。

因为当IA-32 CPU工作在32位模式时,软件中使用的是32位宽的虚拟地址和线性地址,因此便产生了一个问题,如何将32位宽的线性地址翻译为36位宽的物理地址?答案是将原来的二级映射扩展为三级映射,也就是在原来的页目录和页表基础上再增加一级,称为页目录指针表。根据单个内存页的大小不同(4KB或者2MB)又分为两种情况。

图1 启用PAE时将线性地址翻译为物理地址(4KB内存页)(摘自IA-32手册卷3A)

上图中画出的是4KB内存页的情况。其中的PDPTR是Page Directory Pointer Table Register的缩写,它是启用PAE后CR3寄存器的别名。此时,32位线性地址被分割为如下三个部分:

    * 2位(位30和位31)的页目录指针表索引,用来索引本地址在页目录指针表中的对应表项。
    * 9位(位21-29)的页目录表索引,用来索引本地址在页目录表中的对应表项。
    * 9位(位12-20)的页表索引,用来索引本地址在页表中的对应表项。
    * 12位(位0-11)的页内偏移,这与以前是相同的。

与没有启用PAE的4KB情况(参见《软件调试》2.7.4节)相比,有以下不同:

表的数量由原来的两张变为三张。

因为表中的地址都是物理地址,所以三张表的每个表项都有原来的32位变为64位,具体格式如下图所示。

图2 启用PAE时的地址转换表项格式(4KB内存页)(摘自IA-32手册卷3A)

也就是说,每个64位的表项中有24位是用来代表基地址的,这24位对应的是物理地址的高24位,低12位为0。这意味着,页目录表、页表和每个页的基地址都是按4KB对齐的。

图3 启用PAE时将线性地址翻译为物理地址(2MB内存页)(摘自IA-32手册卷3A)

图3所示的是2MB内存页的情形。与未启用PAE的情况一样,不再需要页表。

有了以上基础后,下面我们来在一个启用了PAE的Windows XP SP2系统上做2.7.5节中的试验。

根据步骤1-4,找到gpszNum变量的地址为000ab048,其内容如下:

0:002> db 000ab048

000ab048  31 00 32 00 33 00 34 00-35 00 36 00 37 00 38 00  1.2.3.4.5.6.7.8.

000ab058  39 00 2e 00 00 00 00 00-00 00 00 00 00 00 00 00  9...............

000ab068  00 00 00 00 00 00 00 00-00 00 00 00 1e 68 72 28  .............hr(

000ab078  02 00 07 00 3e 01 08 00-90 b0 0a 00 00 b0 0a 00  ....>...........

000ab088  04 00 02 00 20 01 0c 00-01 00 00 00 01 00 00 00  .... ...........

000ab098  00 00 00 00 00 00 00 00-00 00 00 00 57 00 53 00  ............W.S.

000ab0a8  02 00 04 00 24 01 0c 00-30 00 00 00 78 01 0a 00  ....$...0...x...

000ab0b8  02 00 02 00 26 01 08 00-d0 b0 0a 00 f0 b0 0a 00  ....&...........

启动一个本地内核调试会话,观察calc进程的概况:

lkd> !process 0 0 calc.exe

PROCESS 896acb08  SessionId: 0  Cid: 1020    Peb: 7ffd5000  ParentCid: 0fc8

    DirBase: 1b1c0aa0  ObjectTable: e3265fb8  HandleCount:  48.

    Image: calc.exe

上面的DirBase便是CR3寄存器的值,即PDPTR的内容,其格式如下:


将要转换的线性地址000ab048 显示为二进制:

lkd> .formats 000ab048

Evaluate expression:

  Hex:     000ab048

  Binary:  00000000 00001010 10110000 01001000

根据图1,分解为如下4个部分:

    * 最高两位为0,是页目录指针表的索引。
    * 接下来的9位(000000 000)为页目录索引,即0。
    * 再接下来的9位(01010 1011)为页目录索引,即0xab。lkd> ? 0y010101011 Evaluate expression: 171 = 000000ab
    * 最后的12位(0000 01001000)是页内偏移,即0x48。

因为CR3值(1b1c0aa0) 的低5位都是0,所以可以知道计算器进程的页目录指针表的基地址就是0x1b1c0aa0。观察这一地址附近的内容:

lkd> !dd 0x1b1c0aa0

#1b1c0aa0 6408b001 00000000 34bcc001 00000000

#1b1c0ab0 3d00d001 00000000 4430a001 00000000

#1b1c0ac0 5ae85001 00000000 12a46001 00000000

#1b1c0ad0 41807001 00000000 5e284001 00000000

#1b1c0ae0 35377001 00000000 3bcb8001 00000000

每个页目录指针表共有4个表项,每个表项是8字节(64位),因此,可以知道上面的前两行内容是计算器进程的页目录指针表。

根据上面的分解,1b1c0aa0对应的是0号表项,即00000000`6408b001。根据图2,位12到位35是页目录表基地址的高24位,因此,可以知道对应的页目录表基地址是0x6408b000,观察它的0号表项:

lkd> !dq 0x6408b000

#6408b000 00000000`42d20067 00000000`3c5b6067

#6408b010 00000000`3f11b067 00000000`1e551067

#6408b020 00000000`0e824067 00000000`2cecc067

#6408b030 00000000`39d4e067 00000000`00000000

#6408b040 00000000`0b6db067 00000000`00000000

#6408b050 00000000`00000000 00000000`00000000

#6408b060 00000000`00000000 00000000`00000000

#6408b070 00000000`00000000 00000000`00000000

可见,我们要翻译的线性地址对应的页目录表项是00000000`42d20067,其中位12到位35是页表基地址的高24位,因此可以知道我们要寻找的页表基地址是42d20000,观察它的0xab号表项:

lkd> !dq 42d20000+0xab*8

#42d20558 80000000`46852067 80000000`2a3db067

#42d20568 80000000`4009c067 80000000`43263067

#42d20578 80000000`444e4067 80000000`7b165067

#42d20588 80000000`0b92e067 80000000`3d12f067

#42d20598 80000000`283b0067 80000000`79871067

#42d205a8 80000000`348ba067 80000000`72cbb067

#42d205b8 80000000`421fd067 80000000`7223e067

#42d205c8 00000000`00000080 00000000`00000000

这样便得到页表表项:80000000`421fd067, 它的位12到位35是内存页基地址的高24位,即线性地址000ab048所对应的内存页基地址是421fd000,加上页内偏移0x48便得到最终的物理地址,即0x421fd048,显示其内容:

lkd> !db 46852048

#46852048 31 00 32 00 33 00 34 00-35 00 36 00 37 00 38 00 1.2.3.4.5.6.7.8.

#46852058 39 00 2e 00 00 00 00 00-00 00 00 00 00 00 00 00 9...............

#46852068 00 00 00 00 00 00 00 00-00 00 00 00 1e 68 72 28 .............hr(

#46852078 02 00 07 00 3e 01 08 00-90 b0 0a 00 00 b0 0a 00 ....>...........

#46852088 04 00 02 00 20 01 0c 00-01 00 00 00 01 00 00 00 .... ...........

#46852098 00 00 00 00 00 00 00 00-00 00 00 00 57 00 53 00 ............W.S.

#468520a8 02 00 04 00 24 01 0c 00-30 00 00 00 78 01 0a 00 ....$...0...x...

#468520b8 02 00 02 00 26 01 08 00-d0 b0 0a 00 f0 b0 0a 00 ....&...........

可见,其内容与前面使用用户态调试器观察的内容是一致的。

张银奎

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 0
支持
分享
最新回复 (16)
雪    币: 207
活跃值: (26)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
2
《软件调试》下载地址:http://bv.csdn.net/resource/rjts.pdf
2008-7-4 11:24
0
雪    币: 347
活跃值: (25)
能力值: ( LV9,RANK:420 )
在线值:
发帖
回帖
粉丝
3
感谢楼主提供的电子书
2008-7-4 13:49
0
雪    币: 563
活跃值: (95)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
好书 顶!!!
2008-7-4 15:45
0
雪    币: 1319
活跃值: (2306)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
5
非常感谢,好书我有一大堆,就是没时间看啊,舍不得花时间,觉得不值得,
2008-7-4 16:29
0
雪    币: 207
活跃值: (26)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
6
忙是忙了点,一年看个1-2本好书物品想您也应该还能抽出这个时间的。
2008-7-4 17:22
0
雪    币: 32
活跃值: (18)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
谢谢,不过这只是部份章节的,不知何时会出来完整版的
2008-7-6 12:35
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
谢了,我先看看哈
2008-7-6 14:31
0
雪    币: 207
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
恩, 在从05年开始间断的接触各个调试器的使用到现在,
忽然看到这样的一本书,觉得挺兴奋的,现在的人也幸福了的
有这样系统的可以学学,不像开始的我,完全就是在网上到处片言片语的看
2008-7-6 21:48
0
雪    币: 207
活跃值: (26)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
10
我们处在一个浮躁的年代,有精力去写1000多页书的作者又能有多少呢?
2008-7-7 12:45
0
雪    币: 347
活跃值: (25)
能力值: ( LV9,RANK:420 )
在线值:
发帖
回帖
粉丝
11
貌似那本书不全?
2008-7-8 11:06
0
雪    币: 207
活跃值: (26)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
12
《软件调试》原书有1040页,这里只是1/10罢了。
2008-7-8 20:18
0
雪    币: 347
活跃值: (25)
能力值: ( LV9,RANK:420 )
在线值:
发帖
回帖
粉丝
13
原来如此,我在网上找了找,貌似没电子版的下载
2008-7-9 16:19
0
雪    币: 207
活跃值: (26)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
14
呵呵,作者花了3年时间写。写出了1040页,不容易啊,呵呵。
2008-7-9 16:38
0
雪    币: 302
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
呵呵,居然在这里遇到楼主,正好有个问题要请教。

页目录是按4KB 边界对齐,所以页目录基地址的低12位总是为0。
书中175页的例子楼主显示记事本进程的DirBase值是0x1f350000

但我的机器显示的DirBase值是:072782c0,低12位并不是为全0,不知道这是为什么。
难道说与系统的版本有关么,我的系统是XP SP2,CPU:AMD Athlon64 双核.
还望指教。另外楼主能留个常用联系方式么,以后可能有很多问题要请教。。
2008-7-9 22:41
0
雪    币: 302
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
再一个,书中的前几章主要是以Intel IA-32处理器为讲解平台,而我的是AMD的CPU,不知道在实验方面会不会有很大的差别,有好几个例子调试按照书中的方法调试都失败了。。。
2008-7-9 22:45
0
雪    币: 207
活跃值: (26)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
17
抱歉,我不是《软件调试》作者,关于这些问题可以到高端调试网站上去留言提问,貌似有这个问题的答案:http://advdbg.com/default.aspx
2008-7-10 10:27
0
游客
登录 | 注册 方可回帖
返回
//