是的是的,我已经非常非常清楚,您所说的: 首先会根据段寄存器中的段选择子在GDT或LDT中找到一个描述符,取其中的基地值,加上这个偏移,等到所谓的线性地址
其实Intel 指令手册第三卷中关于保护模式已经详细地说明了这个问题,我觉得我自己是比较清楚了。 关于PTE,页属性我也都看了,我觉得我非常清楚了,
让我很混乱的是: 所谓Windows Flat内存模式,Undocument Winnt上指示说那代表其实windows是不分段的,只使用段偏移, 段选择子只加载一次,如下 0008 Code32 Base=00000000 Lim=FFFFFFFF DPL=0 P R 0010 Data32 Base=00000000 Lim=FFFFFFFF DPL=0 P R 001B Code32 Base=00000000 Lim=FFFFFFFF DPL=3 P R 0023 Data32 Base=00000000 Lim=FFFFFFFF DPL=3 P R 这前面四个段,就是不分段的证明。
原文是这么写的: 首先我们来看 Windows NT 是如何为进程提供平面地址空间的。 通过前面一节我们知道,Intel 的 80386 既提供了分段又提供了分页。那么 Windows NT 又是如何只提供平面内存而不提供分段的呢?关闭了分段吗?80386 上的分段可是关不掉的。 但是操作系统可以只加载一次段寄存器然后再后面的指令里只指定偏移,这在 80386 处理器上是可以做到的。Windows NT 就是这么干的。Windows NT 初始化所有的寄存器使之指向 0 到 4GB 的内存单元。页就是说基址设为 0,界限值设为 4GB。 CS、SS、DS 和 ES 都用指向 0 至 4GB 内存单元的独立的描述符初始化。现在,应用程序就可以只用32位偏移了。 最后,我们看到的就是32位平面地址空间。Windows NT 下的32位应用程序不用改变任何的段寄存器。
让我疑惑的是同一个4g地址为什么要有两个同样的段Code32和Data32,是不是当CPL = 0 指代的就是DPL=0的那个Code32? 更奇怪的是,windows是不是基本上都不用LDT? 否则,不应该只有一个LDT显示才对的。
其实我就是想对照386 protection mode和windows的工作方式应该能够看到一一对应才对。 真是可惜首先LDT就对不上号,TSS32也对不上, 386当中说每个任务都有tss,104个字节,这确实不错,可惜Softice里面的第一个tss,不是104个字节的。 而且似乎只有5个TSS段在GDT内,这也不符合386保护模式,也只有一个描述LDT的段描述符在GDT内,
如下摘录win32汇编:
GDTR指向的描述符表为全局描述符表GDT(Global Descriptor Table)。它包含系统中所有任务都可用的段描述符,通常包含描述操作系统所使用的代码段、数据段和堆栈段的描述符及各任务的LDT段等;全局描述符表只有一个。
LDTR则指向局部描述符表LDT(Local Descriptor Table)。80386处理器设计成每个任务都有一个独立的LDT。它包含有每个任务私有的代码段、数据段和堆栈段的描述符,也包含该任务所使用的一些门描述符,如任务门和调用门描述符等。
不同任务的局部描述符表分别组成不同的内存段,描述这些内存段的描述符当做系统描述符放在全局描述符表中。和GDTR直接指向内存地址不同,LDTR和CS,DS等段选择器一样只存放索引值,指向局部描述符表内存段对应的描述符在全局描述符表中的位置。随着任务的切换,只要改变LDTR的值,系统当前的局部描述符表LDT也随之切换,这样便于各任务之间数据的隔离。但GDT并不随着任务的切换而切换。
看到这里,读者可能会提出一个问题,既然有全局描述符表和局部描述符表两个表,那么段选择器中的索引值对应哪个表中的描述符呢。实际上,16位的段选择器中只有高13位表示索引值。剩下的3个数据位中,第0,1位表示程序的当前优先级RPL;第2位TI位用来表示在段描述符的位置;TI=0表示在GDT中,TI=1表示在LDT中。
我猜测如果windows基本不用LDT,那么TI永远等于0也就不存在到LDT去找线性地址的可能了。
WINDOWS下平坦模式难道就是直接直接从偏移取线性地址的,因为段选择子limit= 0 ~ 4G.
0023 Data32 Base=00000000 Lim=FFFFFFFF DPL=3 P R 0028 TSS32 Base=8000B000 Lim=000020AB DPL=0 P B
而这个更是违反规则的,段描述符是64位的,
0023-0028只有5个字节,怎么可能?
|