GDT段寄存器详解

什么是Real Mode

  实地址模式:是指寻址采用和8086相同的16位段和偏移量,最大的寻址空间是1MB,(?)寻址时将段寄存器的值左移四位加上偏移地址,得到1MB空间内的地址。它是CPU启动的时候的模式,这就相当于一个超级快的8086。

  寻址方式:DS(data segment)<<4 + IP(偏移量)(偏移地址/逻辑地址) == 物理地址。

什么是Protected Mode

  保护地址模式:就是要做到和之前的机器兼容,段寄存器还是16位,地址总线增加,为了能寻址更多的空间,就不能把段寄存器的内容当成实模式下的那种用法,它的值会被当成一个索引,用来在描述符表中找相应的断描述符,进而找到段基址,从而能寻址更大的地址范围。

  寻址方式

实模式和保护地址模式的区别

  保护模式相比于实模式根本区别是进程内存受保护与否。可寻址空间的大小 不同只是这一原因的果。

实模式将整个物理内存看成分段的区域,程序代码和数据 位于不同区域,操作系统和用户程序没有区别对待,而且每个指针都是指向“实在”的物理地址,这样一来,用户程序的一个指针如果指向了系统程序区域或其他用户程序的区域,并修改了值,那么对于这个被修改的系统程序或用户程序,其后果就很可能是灾难性的。

  为了克服这种,低劣的内存管理方式,处理器厂商开发保护模式。这样,物理内存地址不可能直接被程序访问,程序内部的地址(虚拟地址)要由操作系统转化为物理地址去防卫,程序对此一无所知。

GDT(全局段描述符表)和LDT(局部段描述符表)

GDT的来源:

在Protected Mode下,一个重要的结构就是GDT(Global Descriptor Table)。

为什么要有GDT?我们先来了解一下Real Mode下的编程模型:

  在Real Mode下,我们对一个内存的地址访问是通过:Segment--Offset的方式进行的,其中Segment是一个段的Base Address,一个Segment的最大长度为64K,这是16-bit系统所能表示的最大长度。而Offset则是相比于此Segment Base Address的偏移量。Base Address + Offset就是一个内存的绝对地址。

因此,一个段需要:基地址(Base Address) 段最大长度(Limit)。

在实际编程中,使用16-bit段寄存器CS (Code Segment),DS(Data Segment),SS(Stack Segment),ES()。来指定Segment。CPU将段寄存器中的数值向左偏移4-bit,放到20-bit的地址总线上就成为20-bit的Base Address。

到了Protected Mode,内存管理分为了:纯段模式,段页式。因为段页式的主体就是段式。既然这样,我们先来了解段模式:

访问一个内存地址仍然使用Segment--Offset的方式,这是很自然。由于ProtectMode是在32-bit系统上,那么Segment的两个因素:Base Address和Limit

也都是32位的。

另外,保护模式顾名思义又为段模式提供了保护机制,也就是一个段的描述符需要规定对自身的访问权限(Access)。所以,在保护模式下,对一个段的描述则包括3方面因素:【Base Address,Limit,Access】,他们加在一起被放在一个64-bit的长的数据结构中,被称为段描述符。这种情况下,如果我们直接通过一个64-bit段描述符来引用一个段的时候,就必须使用一个64-bit长的段寄存器装入这个段描述符。但是Intel为了保持向后兼容,将段寄存器仍然规定为16-bit(尽管每个段寄存器事实上有一个64-bit长的不可见部分,但对于程序员来说,段寄存器就是16-bit的),很明显,我们无法通过16-bit长度的段寄存器来直接引用64-bit的段描述符。

那么,怎么解决呢??方法:把这些长度为64-bit的段描述符放入到一个数组中,而将段寄存器中的值作为下标索引来间接引用(事实上,是将段寄存器中的高13-bit的内容作为索引)。这个全局的数组就是GDT。事实上,GDT中存放的不仅仅是段描述符,还有其他的描述符,他们都是64-bit长。

GDT是Protected Mode所必需的结构,也是唯一的。另外正像他的名字(Global Descriptor Table)所揭示的,它是全局可见的,对任何一个任务而言都是这样的。

GDT的构成

GDT的结构图如下:GDT表相当于一个64bit的数组

结构解析:

1.G:

  (1)G = 0时,段限长的20位为实际段限长,最大限长为2^20 = 1MB

  (2)G = 1时,实际段限长为20位段限长乘以2^12=4KB,最大限长达到4GB

2.D/B:

 当描述符指向的是可执行代码段时,这一位叫做D位,D=1使用32位地址和32/8位操作数,D=0使用16位地址和16/8位操作数。

 如果指向的是向下拓展的数据段,这一位叫做B位,B=1时的段上界为4GB,B=0,时段的上界为64KB。

 如果指向的是堆栈段,这一位叫做B位,B = 1使用32位操作数,堆栈指针用ESP,B=0时使用16位操作数,堆栈指针使用SP。

3.DPL:特权级,0为最高特权级,3为最低,表示访问该段时CPU所需处于的最低特权级

4.type:类型

  (1)type<8时:数据段

(2).type>=8时:代码段

GDTR是什么?

GDT可以被放在内存的任何位置,那么程序员通过段寄存器来引用一个段描述符时,CPU必须知道GDT的入口(地址),也就是基地址放在哪里,所以Intel的设计者们提供了一个寄存器GDTR用来存放GDT的入口地址,程序员设定在内存中某个位置之后,可以通过LGDT指令将GDT的入口地址装入此寄存器,从此之后,CPU就根据此寄存器中的内容作为GDT的访问入口。

LDT是什么?

  除了GDT之外,与之相类似的结构还有LDT(Local Descriptor Table,局部描述符表)

与GDT不同的是,LDT在系统中可以存在多个,并且它不是全局可见的,它们只是对引用它们的任务可见,每个任务最多有LDT。另外,每一个LDT自身作为一个段存在,他们的段描述符被放在GDT中。
这种结构一般很少用。

LDTR是什么?

IA-32为LDT的入口地址也提供了一个寄存器LDTR,因为在任何时刻只能有一个任务在运行,所以LDT寄存器全局也只需要有一个。如果一个任务拥有自身的LDT,那么当它需要引用自身的LDT时,它需要通过lldt指令将其LDT的段描述符装入此寄存器。

猜你喜欢

转载自blog.csdn.net/genzld/article/details/83750730