加载GDT后

时间:2018-01-13 07:45:34

标签: assembly x86 operating-system att gdt

# Load the GDT.
mov $gdt_descriptor, %ecx
lgdt (%ecx)
mov $0x10, %cx
mov %cx, %ds
mov %cx, %es
mov %cx, %fs
mov %cx, %gs
mov %cx, %ss
ljmp $0x8, $1f
1:  mov $kernel_stack, %esp

我无法理解这段代码的作用。 为什么在加载GDT后将mov $ 0x10转换为cx然后再转到其他寄存器? ljmp指令做了什么?

1 个答案:

答案 0 :(得分:3)

它从lgdt告诉CPU的新GDT加载段描述符缓存(在CPU内部)。

当您更改表条目或更改表格指向的位置时,CPU内部的段描述不会自动更新。

您甚至可以切换回实时模式,DS base = 0 limit = 4GiB(ES和SS相同),并在实模式下使用32位地址,直到下一个mov ds, r16或{{1} }指令覆盖缓存的段描述。 (这被称为big / huge unreal mode,如果你也为CS做了很多,但这不太方便,因为实模式中的中断只能保存IP,而不是EIP。)

pop dsfar jmp,它设置CS(在这种情况下使用与数据描述符不同的描述符)。 x86不允许ljmpmov设置CS,只有远程跳转。据推测,CPU不会通过此跳转来改变模式,否则asm源需要使用pop.code32指令。

目标是.code16方向的1:标签。因此fmov使用GDT索引1中的任何代码段设置进行解码/运行。(段选择器的低3位是权限位,因此%esp是GDT索引1,$8是GDT索引2.)

$0x10mov从设置%ss的指令分开是有点奇怪的,因为x86会自动推迟中断,直到指令 之后> %espmov。这使您可以在不使用SS / cli的情况下自动设置SS:SP,但可能此代码在已禁用中断的情况下运行。此代码可能仅在启动期间运行一次,因此只要在设置新的GDT和IDT所需的时间内禁用中断就有意义。