编写VMM引导加载器时遇nasm 64位模式指令不支持错误求助
问题分析与解决方案
核心错误原因
- 编译模式完全错误:MBR引导加载器运行在CPU的16位实模式下,但你用
nasm -f elf64编译成64位ELF目标文件,这和实模式的运行环境完全不兼容。64位模式下确实不支持jmp eax这类32位寄存器直接跳转的指令,所以编译报错。 - 代码逻辑问题:
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
相关产品推荐
相关产品推荐

