【问题标题】:After load the GDT加载 GDT 后
【发布时间】:2018-06-22 14:31:06
【问题描述】:
# 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指令是做什么的?

【问题讨论】:

  • 它加载全局描述符表,然后使用数据选择器加载段寄存器(可能是 32 位数据 r/w flat 4gb 段)。 LJMP 用于设置代码段(CS)。 CS不能直接用mov指令加载。 1f 是标签: 的地址。因此 JMP 有效地跳转到下一条指令,但同时设置 CS。

标签: assembly x86 operating-system att gdt


【解决方案1】:

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

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

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

ljmp 是一个far jmp,它设置 CS(在这种情况下使用与数据描述符不同的描述符)。 x86 不允许movpop 设置CS,只能跳远。推测 CPU 不会通过此跳转更改模式,否则 asm 源将需要使用 .code32.code16 指令。

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

mov%ss 与设置%esp 的指令分开有点奇怪,因为x86 会自动将中断延迟到指令之后 movSS .这使您可以在不使用 cli/sti 的情况下自动设置 SS:SP,但可能此代码在已禁用中断的情况下运行。这段代码可能只在启动期间运行一次,因此只要需要设置新的 GDT 和 IDT,就可以禁用中断。

【讨论】:

  • CLI 很可能早在此之前就已出现问题,因为 iDT 可能尚未设置。当然这只是一个猜测,但这里很可能就是这种情况。
  • 次要的挑剔/琐事:8086/8(不是 CMOS 版本)确实支持 mov cs, r/m16pop cs。随着 186+ 的出现,mov 悄无声息地被删除了(参见here)。由于 286 第一个 #UDs 和第二个是转义字节(286 引入 PM)。在当时的手册中,8086/80186并没有禁止CS使用movpop,但后者并没有在转移指令表中包含移动(前者没有这样桌子)。 286+ 人禁止流行音乐。
  • @MargaretBloom:有趣的历史事实,谢谢。这就解释了为什么在 popmov 到 CS 的指令编码中有空间。我仍然对我的回答说“x86 不支持”(一般而言)感到满意,尽管上个世纪的几个人这样做了。绝对没有可以运行此代码的(因为 32 位操作数大小)
猜你喜欢
  • 2021-06-13
  • 2014-07-21
  • 2020-07-02
  • 2012-12-26
  • 2013-03-22
  • 2013-01-17
  • 2020-05-14
  • 2015-08-11
相关资源
最近更新 更多