从GDTR中获取GDT 的基址
从LDTR中获取LDT所在段的位置索引,然后以这个索引在GDT中得到LDT段的位置
以段选择器xx的高13位为索引,在LDT中得到描述符 ,得到了段的起始地址。
小白第一次发帖,我会尽我的最大努力表述清楚。
以前我一直很纳闷,既然现在的cpu已经是32根线寻址了,那为什么还是有fs:[*****]这样的结构呢?fs存在的意义是什么?后来看了罗云彬的《Windows环境下32位汇编语言程序设计》,才彻底明白了fs的作用,希望我可以帮到一些对此还有疑问的朋友。
首先我们先来看一下传统的实模式下,内存的寻址方式:
段地址:偏移地址
段地址放在段寄存器中,寻址时,由处理器将段地址乘以10h,再加上偏移地址(因为是20根地址总线,这样的计算方式也是为了增加寻址的范围)。
社会在发展,技术在进步。转眼间,我们的cpu已经发展到了32位了。可以使用全部的32根地址总线了,即可以寻址4GB的大的内存。不用分段了,那在保护模式下,段寄存器是不是就没用了呢?其实,此时,它的作用更重要了。
在保护模式下,一个地址空间是否可以被写入,可以被多少优先级的代码写入,是不是允许执行等设计保护的问题就出来了。要解决这些问题,必须对一个地址空间定义一下安全的属性,此时,我们的英雄——段寄存器就开始发挥作用了。
涉及属性和保护模式下段的其他参数,要表示的信息太多了,需要64位长的数据才能表示,我们把这64位的属性数据叫做段描述符。但是,80386的段寄存器是16位的,无法放下保护模式下64位的段描述符,怎么办呢?既然寄存器放不下,那我有4GB的内存啊,这么大的地方,放几个64位的数据总可以吧。所以,cpu的设计师把所有的段描述符顺序的放在了内存中的指定位置,组成了一个段描述符表(Descriptor Table);而段寄存器中的16位用来做索引信息,指定这个段的属性用段描述符表中的第几个描述符来表示。这时,段寄存器中的信息不再是段地址了,而是段选择器(有的也叫做段选择子)。
那么,问题来了。段描述符表在哪?为此,在80386中,引入了两个新的寄存器来管理段描述符表:
1、GDTR(Global Descriptor Table Register),48位的全局描述符表寄存器
2、LDTR(Local Descriptor Table Register),16位的局部描述符表寄存器
问题又来了,为什么会有两个描述符表寄存器?好了,看看书上是怎么说的:
GDTR指向的描述符表位全局描述符表GDT。它包含了系统中所有任务都可用的段描述符,通常包含描述操作系统所使用的代码段,数据段和堆栈段的描述符以及各任务的LDT段等;(全局描述符只有一个)。
LDER指向局部描述符表LDT。80386处理器设计成每个任务都有一个独立的LDT。它包含有每个任务私有的代码段,数据段和堆栈段的描述符,也包含该任务所使用的一些门描述符,如任务门和调用门描述符等。
不同任务的局部描述符表分别组成不同的内存段,描述这些内存段的描述符当做系统描述符放在全局描述符表中。和GDRT直接指向内存地址不同,LDTR和CS,DS等段选择器一样只存放索引值,指向局部描述符表内存段对应的描述符在全局描述符表LDT中的位置。随着任务的切换,只要改变LDTR的值,系统当前的局部描述符表LDT 也随之切换。这样便于各任务之间数据的隔离。(GDT并不随着任务的切换而切换)。
其实,16位的段选择器中只有高13位表示索引值,剩下的3个数据位中,第0,1位表示程序的当前优先级RPL,第2位TI位用来表示段描述符的位置:TI=0,表示在GDT中,TI=1,表示在LDT中。
最后,看个例子:
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)