You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

编写VMM引导加载器时遇nasm 64位模式指令不支持错误求助

问题分析与解决方案

核心错误原因

  1. 编译模式完全错误:MBR引导加载器运行在CPU的16位实模式下,但你用nasm -f elf64编译成64位ELF目标文件,这和实模式的运行环境完全不兼容。64位模式下确实不支持jmp eax这类32位寄存器直接跳转的指令,所以编译报错。
  2. 代码逻辑问题:jmp eax指令会直接跳转到计算出的内核地址,后面的"Loading complete."显示代码永远不会被执行;同时64位编译的代码在实模式下无法正确运行,这也是移除该指令后运行无输出的核心原因。

步骤1:修正汇编引导加载器代码

调整代码逻辑与指令

  • 将显示代码移到jmp eax之前,确保跳转前能输出提示;
  • 实模式下跳转到32位线性地址,需使用jmp dword eax(实模式支持32位地址操作,前提是编译为16位模式);
  • 补充错误处理的显示逻辑,方便调试;
  • 修正MBR签名的定义(必须是2字节的0xAA55,而非4字节)。

修正后的汇编代码:

section .text align=1
bits 16 ; 明确指定16位实模式代码
start:
    ; 初始化段寄存器(实模式下必须的基础操作)
    mov ax, 0x07C0
    mov ds, ax
    mov es, ax
    mov ss, ax
    mov sp, 0x7C00

    ; Load the kernel code into memory
    mov edx, 0x8000
    mov dh, 0x02
    mov dl, 0x80
    mov ah, 0x02
    int 0x13
    jnc kernel_loaded
    jmp error

kernel_loaded:
    ; 先显示加载完成提示
    mov si, loading_msg
    call print_string

    ; Set the entry point for the kernel
    mov eax, [0x8000 + 0x218]
    mov ecx, [0x8000 + 0x21A]
    mov edx, 0
    add edx, ecx
    add ecx, ecx
    add edx, ecx
    add ecx, ecx
    add edx, ecx
    add ecx, ecx
    add edx, ecx
    add ecx, ecx
    add edx, ecx
    add eax, edx
    add eax, 0x8000
    jmp dword eax ; 实模式下用dword前缀支持32位地址跳转

error:
    ; 显示错误提示
    mov si, error_msg
    call print_string
    cli
    hlt

; 实模式字符串打印函数
print_string:
    mov ah, 0x0E
    mov bh, 0x00
    mov bl, 0x07
.next_char:
    lodsb
    or al, al
    jz .done
    int 0x10
    jmp .next_char
.done:
    ret

; 字符串数据
loading_msg db 'Loading complete.', 0x0D, 0x0A, 0
error_msg db 'Error loading kernel!', 0x0D, 0x0A, 0

; Pad the boot loader to 512 bytes
times 510 - ($-$$) db 0
dw 0xAA55 ; MBR签名必须是2字节,用dw而非dd

步骤2:修正编译与构建流程

1. 编译引导加载器

直接生成16位二进制MBR文件,不要用ELF格式:

nasm -f bin -o boot.bin boot.asm

验证:执行ls -l boot.bin,文件大小必须是512字节。

2. 编译D语言VMM代码

VMM需要运行在保护模式或长模式下,编译时需指定对应架构:

# 64位长模式代码
dmd -c -m64 vmmonitor.d
# 32位保护模式代码
# dmd -c -m32 vmmonitor.d

3. 合并引导加载器与VMM代码

需要将VMM代码放到内存指定位置(比如你汇编中加载内核的0x8000地址),推荐用链接脚本精确控制地址:
创建链接脚本link.ld:

SECTIONS {
  . = 0x7C00;
  bootloader : { boot.o(.text) }
  . = 0x8000;
  vmm : { vmmonitor.o(.text .data .bss) }
}

先将引导加载器编译为32位ELF目标文件:

nasm -f elf32 -o boot.o boot.asm

再链接生成合并后的二进制文件:

ld -T link.ld -o combined.bin boot.o vmmonitor.o

4. 生成可引导ISO

用genisoimage生成ISO时,指定正确的引导参数:

genisoimage -o boot.iso -b combined.bin -no-emul-boot -boot-load-size 4 combined.bin

-boot-load-size 4表示加载4个扇区(2048字节),如果你的combined.bin更大,需按实际大小调整该值。

关键注意事项

  • MBR必须严格为512字节,最后两个字节必须是0xAA55,之前的dd 0xAA55会写入4字节,导致MBR格式错误;
  • 实模式下必须初始化段寄存器,否则内存访问会出现异常;
  • 若VMM是64位代码,引导加载器需要完成从实模式→保护模式→长模式的切换流程,才能正确运行64位VMM。

内容的提问来源于stack exchange,提问作者clickerticker48

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 16:30:46