注:本文档为《从0学x86操作系统》课程配套的学习文档,提供相应的辅助学习资料和答疑勘误。 有关该课程的信息,请点击这里访问:https://study.163.com/provider/1017884735/index.htm 在阅读本文档时,如有疑问和建议,欢迎在下方留言或者直接联系我。

本课时主要介绍GDT表项的细节,以及如何重新加载GDT表。之所以重新加载GDT表,是因为原表项太小,以及该内存可能被用作其它用途,如栈。

GDT表项格式

image.png
以下仅界限表项的属性部分:

  • S:1-代码段或数据段,0 - 系统段
  • DPL:特权级,取值0-3
  • P:段是否存在,1存在,0不存在
  • D/B:指示代码或栈的大小是32位还是16位,1 - 32位,0-16位
  • G:段界限的单位。1 - 界限的单位是4KB,0 - 字节。
  • L和AVL:我们不没有用到,使用0即可。
  • type:见下表,用于描述段的具体类型

image.png

GDTR寄存器

使用LGDT指令,可以将GDT表相关的信息加载到GDTR寄存器中。后续对寄存器的访问,都会通过其指向的GDT表。
image.png
在重新设置后,需要使用jmp $选择子, $offset跳转。有的同学认为,可以不跳转,因为CS的值为8,新表中代码段描述符对应的选择子也为8,二者相等,无需跳转。
image.png

之所以要重新跳转,是为了使CS寄存器重新加载新GDT表中相应的信息。如下图所求,CS寄存器除了保存选择子信息外,还会在内部自动保存从GDT表中加载的基地址、界限、属性等相关信息。当使用jmp $选择子, $offset进行跳转后,CS将从新表中加载新的信息,这样就避免了仍然使用原来的信息。所以,最好是重新加载,以使用新的信息。
image.png
当然,在目前的工程中,由于新表中代码段相关的信息和旧表中的相同,所以不重新加载也不影响程序的运行。

参考资料

  • 课程附带的intel编程文档卷3:Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 3 (3A, 3B, 3C & 3D): System Programming Guide