汇编带偏移长跳转的不同语法及内核GDT编写的汇编链接问题
Hey there! Sounds like you're making solid progress on your kernel's GDT setup—awesome stuff. Let's dive into the different assembly syntaxes for that critical far jump we need to update the CS register after loading a new GDT.
First, a quick recap: We can't just mov a new value into CS directly. A far jump is required because it's the only way to atomically set both the segment selector (for CS) and the offset, forcing the CPU to recognize the new GDT's code segment.
1. NASM Syntax (likely what your tutorial uses)
NASM uses a straightforward segment:offset syntax for far jumps. Here's how the full gdt_flush routine might look, matching your tutorial's structure:
global _gdt_flush ; Expose this function to C code _gdt_flush: ; Grab the GDT pointer address passed from C mov eax, [esp+4] ; Load the new GDT lgdt [eax] ; Update all data segment registers with the new data selector (0x10 here) mov ax, 0x10 mov ds, ax mov es, ax mov fs, ax mov gs, ax mov ss, ax ; Far jump to update CS: use code segment selector (0x08) and jump to local label jmp 0x08:.flush .flush: ; Return back to C code ret
The key line here is jmp 0x08:.flush—0x08 is your GDT's code segment selector, and .flush is the offset within that segment.
2. GNU Assembler (GAS) Syntax
GAS uses a reversed syntax compared to NASM, with $ prefixes for immediate values. Far jumps use the ljmp instruction:
.global gdt_flush ; Make function visible to C gdt_flush: ; Get GDT pointer from stack (C function argument) movl 4(%esp), %eax lgdt (%eax) ; Update data segment registers movw $0x10, %ax movw %ax, %ds movw %ax, %es movw %ax, %fs movw %ax, %gs movw %ax, %ss ; Far jump: specify segment selector and offset with $ prefixes ljmp $0x08, $.flush .flush: ret
Here, ljmp $0x08, $.flush does the same job as the NASM version—$0x08 is the code segment selector, $.flush is the target offset.
3. MASM Syntax (common for Windows kernel development)
MASM requires the FAR PTR keyword to explicitly mark a far jump, with a similar segment:offset structure:
PUBLIC _gdt_flush _gdt_flush PROC ; Retrieve GDT pointer from stack mov eax, [esp+4] lgdt [eax] ; Update data segments mov ax, 0x10 mov ds, ax mov es, ax mov fs, ax mov gs, ax mov ss, ax ; Far jump with FAR PTR qualifier jmp FAR PTR 0x08:flush flush: ret _gdt_flush ENDP
The FAR PTR tells MASM this isn't a near jump, ensuring the CPU updates the CS register.
Quick Note
No matter which assembler you use, the core goal is the same: trigger a far jump to load your new code segment selector into CS. The exact syntax varies by toolchain, but the logic stays consistent.
内容的提问来源于stack exchange,提问作者user5930979

