为什么这个汇编代码不仅仅做 lgdt?

Why does this assembly code does more than just lgdt?

所以,我开始开发一个 x86_64 爱好内核,我发现这段代码可以加载 GDT(全局描述符 Table),但我不明白它的作用。

load_gdt:
  lgdt [rdi]
  mov ax, 0x10
  mov ss, ax
  mov ds, ax
  mov es, ax
  mov rax, qword .trampoline
  push qword 0x8
  push rax
  o64 retf

.trampoline:
    ret

我知道它从 rdi 寄存器(sysv abi 中函数调用的第一个参数的寄存器)加载我的 gdt 描述符,但我不知道为什么我需要将所有段寄存器设置为 0x10 以及什么黑魔法剩下的还在做吗?

一旦(新的)GDT 存在,下一步就是将段寄存器设置为索引 GDT 的选择器;这就是您首先想要 GDT 的原因。或者如果你要更换旧的 GDT,例如,想要你自己的 GDT来自 UEFI。 (由于您已经处于 64 位模式,因此必须已经有 GDT;mov rax, .trampoline 与相对于 RIP 的 LEA 相比是一个奇怪的选择,但涉及 REX 前缀,因此在 32 位模式下会解码错误.)

最后几个正在设置 CS 远跳,通过推一个新的 CS:RIP 并做一个 far-ret 将其弹出到 CS:RIP。它需要是 64 位操作数大小,以确保从堆栈中弹出 64 位 RIP,而不是 32 位 EIP。

(你当然不能 mov 到 CS;那将是一个跳跃,因为它会改变代码获取的来源。x86 只允许写 E/RIP 或 CS:E/RIP 通过跳转指令,如 call / jmp 或 retf。)

另见 https://wiki.osdev.org/Global_Descriptor_Table