程序集使用不同语法的偏移量执行长跳转

问题描述 投票:2回答:2

我正在为内核编写GDT,一切顺利,我正在学习本教程。

http://www.osdever.net/bkerndev/Docs/gdt.htm

将C代码链接到汇编代码时,他使用这段代码。

; This will set up our new segment registers. We need to do
; something special in order to set CS. We do what is called a
; far jump. A jump that includes a segment as well as an offset.
; This is declared in C as 'extern void gdt_flush();'
global _gdt_flush     ; Allows the C code to link to this
extern _gp            ; Says that '_gp' is in another file
_gdt_flush:
lgdt [_gp]        ; Load the GDT with our '_gp' which is a special pointer
    mov ax, 0x10      ; 0x10 is the offset in the GDT to our data segment
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    jmp 0x08:flush2   ; 0x08 is the offset to our code segment: Far jump!
flush2:
ret               ; Returns back to the C code!

但是,我的汇编语法不同,这是我的boot.s文件的一部分。

.global gdt_flush     /*Allows the C code to link to this*/
.extern gp            /*Says that '_gp' is in another file*/
_gdt_flush:
    lgdt gp        /*; Load the GDT with our '_gp' which is a special pointer*/
    mov %ax, 0x10     /* ; 0x10 is the offset in the GDT to our data segment*/
    mov %ds, %ax
    mov %es, %ax
    mov %fs, %ax
    mov %gs, %ax
    mov %ss, %ax
    jmp flush2   /*; 0x08 is the offset to our code segment: Far jump!*/
flush2:
ret               /*; Returns back to the C code!*/

我的问题是如何将此指令的语法翻译成我正在使用的格式?

他的:jmp 0x08:flush2 ; 0x08 is the offset to our code segment: Far jump!

来源:Gazzkssob

assembly x86 gas att osdev
2个回答
4
投票

一些东西。跳远的AT&T语法是:

(long l?)jmp ????flush2   /*; 0x08 is the offset to our code segment: Far jump!*/

在这种情况下,标签需要以jmp $0x08,$flush2 开头。像$这样的直接值也需要一个0x08。这行不符合你的想法:

$

AT&T语法的重要之处在于,与英特尔语法不同,操作数是相反的。源操作数是第一个,目标操作是在之后。其次,x86 / x86-64上的AT&T语法中的立即值需要在它们之前加上mov %ax, 0x10 符号,否则它们实际上被视为内存操作数。您的指令实际上将AX的16位内容移动到内存地址0x00000010,这不是您想要的。你想要的是:

$

这会将立即值0x10移动到AX。操作数被反转的问题也适用于你的所有行:

mov $0x10, %ax

应该:

mov %ds, %ax

我通常更喜欢叫你的功能mov %ax, %ds 。我通常喜欢传递段值(CS和DS)和GDTR的地址,代码如下:

load_gdt

C原型将是这样的:

load_gdt:
    mov 4(%esp), %edx    # EDX is 1st argument - GDT record pointer
    mov 8(%esp), %eax    # EAX is 2nd argument - Data Selector
    lgdt (%edx)          # Load GDT with GDT record pointer passed as 1st argument
    mov %eax, %ds        # Reload all the data descriptors with Data selector (2nd arg)
    mov %eax, %es
    mov %eax, %gs
    mov %eax, %fs
    mov %eax, %ss

    pushl 12(%esp)      # Create FAR pointer on stack using Code selector (3rd argument)
    push $.setcs         # Offset of FAR JMP will be setcs label below
    ljmp *(%esp)        # Do the FAR JMP to next instruction to set CS with Code selector,
                        #    and set the EIP (instruction pointer) to offset of setcs
.setcs:
    add $8, %esp        # Restore stack (remove 2 DWORD values we put on stack to
                        #     create FAR Pointer)
    ret

如果您想将GNU汇编程序与英特尔语法的变体一起使用,您可以尝试将此指令添加到所有程序集文件的顶部:

void load_gdt(struct gdt_ptr *gdt_ptr, unsigned int data_sel, unsigned int code_sel);

0
投票

除了迈克尔的回答,这肯定超出我的意思,这将是我的翻译:

.intel_syntax noprefix
© www.soinside.com 2019 - 2024. All rights reserved.