- 论坛徽章:
- 0
|
恩,关于表限我说错了。实际上我所说的LDT索引存放在LDTR寄存器中,不是GDTR的低16位,GDTR存放是表长度,这部分程序不可见,所以存放在哪用户也看不到这个过程:
LDTR寄存器 LDTR高速缓存
15 0 47 16 15 0
选择符(16位) LDT表基址(32位)表限(16位表长度)
LDTR寄存器中的16位
Bit15~Bit3:选择子
Bit12:0表示GDT 1表示 LDT
Bit0~Bit1:处理器当前运行的级别--CPL,四个等级0、1、2、3
LDTR寄存器本质上是一个16位段寄存器,386段寄存器的最大可用选择是2^14而不是2^16
所以LDTR寄存器最大可选虚拟内存是2^14*4G=64T,这个跟GDT和LDT根本没关系。至于段
寄存器的剩余两位则表示CPL(CPU运行权限或级别)。终于把这个问题搞清楚了。欢迎不同观点。
---------------------------------------------
给出一个定位内存和虚拟内存的源码
call 1a:804304c (call cs:eip即cs = 1a, eip = 804304c)
target_cs = 1a;
target_eip = 0x0804304c;
CPL = CS.RPL; /* 当前执行的代码段的权限级别就是CPL */
RPL = target_cs.RPL; /* 目标段 selector 的低3位是RPL */
target_si = target_cs.SI; /* 目标段 selector 的索引是Bit15~Bit3 */
target_ti = target_cs.TI; /* 目标段selector的描述符表索引是Bit2 */
CODESEG_DESCRIPTOR target_descriptor;
if (target_ti == 0) { /* target_cs.TI为0 就是参考到 GDT(全局描述符表) */
/* 以GDTR寄存器的base 为基地址加上selector的索引乘以8即得出目标
段描述符,目标描述符的DPL就是目标段所需的访问权限 */
target_descriptor = GDTR.base + target_si * 8
} else { /* 否则就是参考 LDT (局部描述符表)*/
/* 以 LDTR寄存器的base 为基地址得出目标段描述符 */
target_descriptor = LDTR.base + target_si * 8;
}
DPL = target_descriptor.DPL; /* 获取DPL */
if (target_descriptor.type & 0x06) { /* conforming */
if (CPL >= DPL) { /* 允许执行高权限代码 */
/* go ahead */
} else {
/* 引发 #GP 异常 */
goto DO_GP_EXCEPTION;
}
} else { /* nonconforming */
if (CPL == DPL && RPL <= CPL) {
/* go ahead */
} else {
/* 引发 #GP 异常 */
goto DO_GP_EXCEPTION;
}
}
/****** go ahead … …******/
CS = target_cs; /* 加载目标段CS 进入 CS 寄存器 */
EIP = target_eip; /* 加载目标指令EIP 进入 EIP 寄存器 */
/* 当前执行权限 CPL 不改变 */
goto target_descriptor.base + target_eip; /* 跳转到目标地址执行 */
DO_GP_EXCEPTION: /* 执行 #GP异常点 */
… … |
|