我这台32位 DOS的远跳指令不起作用,为什么?

编程语言 2026-07-11

我在用32位创建一个DOS,并且在远跳上遇到了一些问题。

下面是我将数据加载到内存地址0x0000:0x8000的方式:

load_next_boot:
    mov ah, 0x02
    mov al, 1
    mov ch, 0
    mov cl, 2
    mov dh, 0
    mov dl, 0x00
    mov bx, 0x8000
    int 0x13

    jmp 0x0000:0x8000

其次,我核对了第二个扇区是否处于正确的内存地址,这里是第二扇区的主体代码:

[BITS 16]
[ORG 0x8000]

start:
    mov ah, 0x0E
    mov al, 'A'
    int 0x10
    cli
    mov eax, cr0
    or eax, 1
    mov cr0, eax
    jmp 0x08:protected_mode_start_32

[BITS 32]
protected_mode_start_32:
    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    mov esp, 0x90000

    mov esi, msg2
    mov edi, 0xB8000
    call print_string_32

hang:
    jmp hang

(我已经用gdt_null、gdt_code和 gdt_data设置了一个全局描述符表(GDT)。问题中我就不展示GDT。)

有人知道为什么远跳不起作用吗?

解决方案

BIOS中断13h ax=0x02(用于在内存中读取并加载磁盘扇区的中断。)使用ES:BX将寄存器转换为一个地址。在这段代码中:

load_next_boot:
    mov ah, 0x02
    mov al, 1
    mov ch, 0
    mov cl, 2
    mov dh, 0
    mov dl, 0x00
    mov bx, 0x8000
    int 0x13

    jmp 0x0000:0x8000

ES寄存器未被赋值,因此其值往往是随机的。

代码应该是这样的:

load_next_boot: ; Label
    mov bx, 0x8000 ; Offset
    xor ax, ax ; Set ax at 0
    mov es, ax ; Set es at ax(0)

    mov ah, 0x02 ; 
    mov al, 16 ; Numbers of segment(Should be greater than 1.)
    mov ch, 0 ; Cylinder
    mov cl, 2 ; Read sectors starting with sector 2
    mov dh, 0 ; Head
    mov dl, 0x00 ; Drive
    int 0x13

    jmp 0x0000:0x8000

此外,我们不能直接给ES赋值,需要使用一个中间寄存器。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章