x86 支持两种虚拟内存方案(在此处阅读):
- 分段,必须,使用分段表 GDT 管理。
- 分页,可选,使用页表 PDT 管理。
大多数操作系统都希望使用分页并且不希望分段,但它必须而且不能只是禁用。
所以诀窍是禁用它的效果,因为它不存在。这通常可以通过创建 4 个大的重叠段描述符(在空段旁边)来完成:
- 段索引 0:空段描述符
- 段索引 1:特权(内核)模式的代码段描述符
- 段索引 2:特权(内核)模式的数据段描述符
- 段索引 3:非特权(用户)模式的代码段描述符
- 段索引 4:非特权(用户)模式的数据段描述符
所有这些段都从0x00000000
到开始0xffffffff
,因此您最终会得到重叠的大段,即特权代码和数据,以及同时存在的非特权代码和数据。这应该打开虚拟内存并禁用分段效果。
处理器使用段选择器(段寄存器cs
, ds
, ss
...)来找出正确的段(再一次,分段是必须的)。
每个段选择器都是 16 位大小,并具有以下布局(源代码):

如果您解释0x08
加载的cs
,它将是二进制的:
0000000000001 0 00
index 1 (code) GDT privileged
并且0x10
加载在ds
, ss
, ... 中:
0000000000010 0 00
index 2 (data) GDT privileged
如果您阅读任何用户模式程序的段选择器,您应该会看到该cs
值为27
( 0x1b
),这意味着:
0000000000011 0 11
index 3 (code) GDT non-privileged
并且数据选择器ds
, ss
, ... 应该存储 35 ( 0x23
):
0000000000100 0 11
index 4 (data) GDT non-privileged
数据段选择器(寄存器)可以使用简单mov
的指令轻松修改,但cs
不能与 一起使用mov
,因此您可以使用jmp 0x08:OFFSET
将段配置加载到代码段选择器中。