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

汇编引导扇区在VirtualBox正常运行但真机异常问题求助

汇编引导加载程序真机启动异常问题排查与修复

问题描述

编写的汇编引导加载程序功能为打印若干字符串后等待按键输入,在VirtualBox中运行正常,但写入U盘在真机启动时出现异常:光标移动至屏幕右下角并打印一个形似带东北方向箭头的O的奇怪字符;按下按键后屏幕被清空,光标乱跳后再次打印该奇怪字符。已尝试清零所有寄存器、验证栈的解决方案,但问题仍存在。

原代码

[org 0x7c00]
mov al, 0
mov ah, 0
mov ax, 0
mov bx, 0
mov bp , 0x8000 ; Set the base of the stack a little above where BIOS
mov sp , bp ; loads our boot sector - so it won ’t overwrite us.
jmp main
message:
    db 0x0a,0x0d,'Enderbyte Programs',0x0a,0x0d,0
bmessage:
    db 0x0a,0x0d,'Booting...',0x0a,0x0d,0
cmessage:
    db 0x0a,0x0d,'Just kidding this does nothing ',0
kmessage:
    db 'Or does it?',0
print_string:
    mov al, [bx]
    inc bx
    cmp al, 0 
    jne print_char
    mov bx, 0
    ret
print_char: 
    int 0x10; Print AL register
    jmp print_string
main:
    mov ah, 0x0e ; int 10/ ah = 0 eh -> scrolling teletype BIOS routine
    mov bx, message
    call print_string
    mov bx, bmessage
    call print_string
    mov bx, cmessage,
    call print_string
    mov ah, 00h
    int 16h; Wait for keypress?
    mov ah, 0x0e
    mov bx, kmessage
    call print_string
    ;jmp $

反汇编内容

B0 00 B4 00 B8 00 00 BB 00 00 BD 00 80 89 EC EB
63 0A 0D 45 6E 64 65 72 62 79 74 65 20 50 72 6F
67 72 61 6D 73 0A 0D 00 0A 0D 42 6F 6F 74 69 6E
67 2E 2E 2E 0A 0D 00 0A 0D 4A 75 73 74 20 6B 69
64 64 69 6E 67 20 74 68 69 73 20 64 6F 65 73 20
6E 6F 74 68 69 6E 67 20 00 4F 72 20 64 6F 65 73
20 69 74 3F 00 8A 07 43 3C 00 75 04 BB 00 00 C3
CD 10 EB F1 B4 0E BB 11 7C E8 E9 FF BB 28 7C E8
E3 FF BB 37 7C E8 DD FF B4 00 CD 16 B4 0E BB 59
7C E8 D1 FF 25 00 00 00 00 00 00 00 00 00 00 00
*
00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 AA

问题分析

  1. 语法错误导致非法指令:原代码中mov bx, cmessage,末尾多了一个逗号,汇编器会生成错误的机器码,虚拟机对非法指令的容错性较强,但真机BIOS执行时会出现不可预测的行为。
  2. 段寄存器未初始化:[org 0x7c00]仅指定汇编地址偏移,但DS寄存器默认值不确定,导致字符串的实际寻址地址(DS:偏移)与预期不符,出现乱码。
  3. BIOS中断调用参数不完整:调用int 0x10的0x0e功能时,未指定BH(视频页码)和BL(文本属性),真机BIOS可能使用随机的寄存器值,导致输出位置错乱和字符异常。
  4. 程序无终止逻辑:注释掉了jmp $死循环,程序执行完后会继续运行引导扇区后的垃圾代码,引发异常。

修复方案

修复后的代码

[org 0x7c00]
; 初始化段寄存器与通用寄存器,确保寻址正确
mov ax, 0
mov ds, ax
mov es, ax
mov ss, ax
mov bp, 0x8000  ; 将栈基址设在0x8000,避免覆盖引导扇区
mov sp, bp
mov bx, 0
mov cx, 0
mov dx, 0

jmp main

message:
    db 0x0a,0x0d,'Enderbyte Programs',0x0a,0x0d,0
bmessage:
    db 0x0a,0x0d,'Booting...',0x0a,0x0d,0
cmessage:
    db 0x0a,0x0d,'Just kidding this does nothing ',0
kmessage:
    db 'Or does it?',0

print_string:
    mov al, [bx]
    inc bx
    cmp al, 0 
    jne print_char
    ret  ; 无需清零BX,下次调用会重新赋值

print_char: 
    mov ah, 0x0e
    mov bh, 0x00  ; 指定第0视频页
    mov bl, 0x07  ; 文本属性:白字黑底(默认文本模式属性)
    int 0x10      ; 调用BIOS打印字符
    jmp print_string

main:
    mov bx, message
    call print_string
    mov bx, bmessage
    call print_string
    mov bx, cmessage  ; 修复末尾多余的逗号
    call print_string
    
    ; 等待按键输入
    mov ah, 0x00
    int 0x16
    
    mov bx, kmessage
    call print_string
    
    jmp $  ; 死循环,防止执行后续垃圾代码

; 填充引导扇区至512字节,添加BIOS引导标志
times 510-($-$$) db 0
dw 0xaa55

关键修复点说明

  • 修正语法错误:删除mov bx, cmessage末尾的逗号,消除非法指令。
  • 初始化段寄存器:将DS、ES、SS设为0,确保内存寻址与org 0x7c00的偏移一致,正确访问字符串。
  • 完善BIOS中断参数:在print_char中明确设置BH和BL,保证真机BIOS输出到正确位置并使用标准文本属性。
  • 恢复死循环:添加jmp $,避免程序执行到引导扇区外的垃圾代码。
  • 规范引导扇区结构:用times 510-($-$$) db 0确保扇区刚好512字节,末尾的0xaa55是BIOS识别引导扇区的必要标志。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 11:40:38