2 《Undocumented Windows 2000 Secrets》翻译 --- 第四章

第四章 探索 Windows 2000 的内存管理机制
翻译: Kendiv( fcczj@263.net)
更新: Sunday, February 14, 2005


声明:转载请注明出处,并保证文章的完整性,本人保留译文的所有权利 。



数据结构
本章随后的示例代码的某些部分将涉及底层的内存管理机制,在前面我们已快速浏览了该机制内部的大致轮廓 。为了方便,我用 C 语言定义了几个数据结构 。这是因为 i386 CPU 内部的很多数据项需要使用一个二进制位或一组二进制位,而 C 的位域( bit-fIElds )唾手可得 。位域可以很有效的访问一个大的数据中的一个位或从中提取一组连续的位 。微软的 Visual C/C可以产生非常棒的代码来完成位域的操作 。列表 4-2 是一系列 CPU 数据类型定义的一部分,该列表包含如下的内容:
l X86_REGISTER 这是一个基本的无符号 32 位整数类型,该类型可描述多个 CPU 寄存器 。这包括:通用的、索引、指针、控制、调试和测试寄存器 。
l X86_SELECTOR 代表一个 16 位的段选择器,如 CS 、 DS 、 ES 、 FS 、 GS 和 SS。在 图 4-1 和 图 4-2 中,选择器可描述 48 位逻辑地址的高 8 位,或作为描述符表的索引 。为了计算的方便,16 位选择器的值被扩展到 32 位,不过高 16 位被标识为“保留” 。注意,X86_SELECTOR 结构实际是两个结构的联合( union ) 。第一个指定了选择器的值,该值占用一个 16 位的 Word,其名字为 wValue,第二个采用了位域 。RPL 域指定了请求的特权级,在 Windows 2000 上其值或者为 0 (内核模式)或者为 3 (用户模式) 。TI 位用来选择 GDT 或 LDT。
l X86_DESCRIPTOR 定义了由选择器指向的页表项的格式 。这是一个 64 位的数值,由于历史演化,该结构比较让人费解 。线性基地址定义了与其相关的段的起始位置,它们分散在三个位域中: Base1 、 Base2 和 Base3,Base1 是作用最小的部分 。段的界限指定了段的大小,The segment limit specifying the segment size minus one is divided into the pair Limitl and Limit2, with the former representing the least significant half. 剩余的位域存放不同的段属性( cf. Intel 1999c, pp.3-11 ) 。例如,G 位域定义了段的粒度 。如果为零,段的限制按字节指定;否则,限制值为 4KB 的倍数 。像 X86_SELECTOR 一样,X86_DESCRIPTOR 结构由一个 union 组成,以允许按不同的方式解释它的值 。如果你必须复制描述符(在忽略其内部情况下)那么 dValueLow 和 dValueHigh 成员将会很有帮助 。
l X86_GATE 该结构看起来有些像 X86_DESCRIPTOR。事实上,这两个结构是相关的: X86_DESCRIPTRO 是一个 GDT 项,并描述了一个段的内存属性,X86_GATE 代表中断描述符表( IDT )中的一项,并描述了中断例程的内存属性 。IDT 可以包含任务、中断和陷阱门(不! Bill Gates 并没有存储在 IDT 中! 哈哈) 。X86_GATE 结构可匹配上述三种类型,并通过 Type 位域来进行区分 。Type 5 表示这是一个任务门; Type 6 和 14 为中断门; Type 7 和 15 为陷阱门 。Type 中最重要的位是用来描述门的位数的位:该位若为 0 则表示是 16 位门;其余情况表示 32 位门 。
l X86_TABLE 是一个巧妙的结构,该结构用来读取 GDTR 或 IDTR 的当前值,分别通过汇编指令 SGDT (存储 GDT 寄存器)和 SIDT (存储 IDT 寄存器)来实现( cf. Intel 1999b, pp.3-636 ) 。这两个指令需要一个 48 位的内存操作数,在该操作数中存放限制值和基地址值 。通过在结构体中增加一个 DWORD 来对齐 32 位的基地址,X86_TABLE 以一个 16 位的哑元成员 wReserved 开始 。根据是否使用了 SGDT 或 SIDT 指令,其基地址将被解释为一个描述符指针或一个门指针,就像 PX86_DESCRIPTOR 和 PX86_GATE 中的 union 所暗示的那样 。最后的 wLimit 成员在这两种类型的表中的意义均相同 。

推荐阅读