所以,我開始開發 x86_64 愛好內核,我發現這段代碼可以加載 GDT(全域描述符表),但我不明白它的作用。
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 以及剩下的黑魔法是什么?
uj5u.com熱心網友回復:
一旦(新的)GDT 存在,下一步就是將段 regs 設定為索引 GDT 的選擇器;這就是您首先想要 GDT 的原因。或者,如果您要更換舊的 GDT,例如來自 UEFI,則需要自己的 GDT。(由于您已經處于 64 位模式,因此必須已經有 GDT;mov rax, .trampoline與 RIP 相關的 LEA 相比是一個奇怪的選擇,但涉及 REX 前綴,因此在 32 位模式下會解碼錯誤。)
最后幾個是通過遠跳設定 CS,通過推送新的 CS:RIP 并執行遠距將其彈出到 CS:RIP 來完成。它需要是 64 位運算元大小以確保您從堆疊中彈出 64 位 RIP,而不是 32 位 EIP。
(你當然不能mov到 CS;那將是一個跳轉,因為它會改變代碼提取的來源。x86 只允許通過像 call/jmp 或 retf 這樣的跳轉指令來撰寫 E/RIP 或 CS:E/RIP。 )
另見https://wiki.osdev.org/Global_Descriptor_Table
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/384826.html
