Linux内核系列:GDT/LDT

GDT

现代的内存寻址方式一般采用保护模式。

Q:什么是保护模式?

A:保护模式是相对于实模式来说的,以前的内存寻址是直接由cpu段寄存器+偏移量去实存里面找物理地址,例如在8086的时候,也就是16位cpu的时候,CPU配备了4个16位段寄存器(CS代码段寄存器、DS数据段寄存器、SS堆栈段寄存器和ES附加寄存器),这种方式非常粗暴并且很容易出错,一旦用户修改段寄存的值,就可以随意访问所有内存,到了80296芯片,大家意识到直接访问实地址的危害,intel将寻址方式改为保护模式,保护模式下段寄存器不在指向一个真实地址,而是变成指向一个数据结构的指针,这个数据结构就是Segment Descripter Table,又根据这个段描述符表里存的是全局共同的,还是进程私有的,分成了全局段描述符表(GDT)和局部段描述符表(LDT)。

需要了解的:

  1. GDT里面具体存的是什么?
    • 段描述符,8字节,包括系统级段描述符和LDT段描述符
  2. 我们访问内存的具体步骤是什么?
    • 从GDTR中拿到GDT在内存中的基地址,得到段描述符表;
    • 从段选择子中的前13位得到我们要访问的段的描述符在段描述符表中的索引(需要考虑TI和RPL);
    • 从段描述符表中得到要访问的段的描述符,得到其基地址;
    • 基地址加上偏移地址就是我们要访问的内存地址(当然这里是虚拟地址,接下来是分页机制的功能将虚地址转换为物理地址,不做讨论。)

具体参考这篇文章这篇文章

LDT

LDT和GDT差不多,区别有:

  1. LDT是局部段描述符表,GDT是全局段描述符表
  2. LDT可以有多个,GDT只能有一个
  3. LDT本身是个段,需要在GDT中保存其自身描述符
  4. GDT用来描述系统的分段,LDT用来描述某个任务的分段情况,由于每个进程都有自己的一套程序段、数据段、堆栈段,有了局部描述符表则可以将每个进程的程序段、数据段、堆栈段封装在一起,只要改变LDTR就可以实现对不同进程的段进行访问。