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

x86汇编BIOS引导程序:两次调用print函数输出异常求因

问题根源分析与修复方案

我帮你排查出两个关键问题,导致了不符合预期的输出:

1. 变量vaddr的存储长度不匹配,破坏了vline的值

你定义vaddr: db 0x0,只分配了1字节的存储空间,但在print函数末尾用mov [vaddr], bx存储16位的bx寄存器值(bx是16位寄存器)。在x86实模式下,这个操作会写入2字节:低8位到vaddr,高8位到vaddr+1,而vaddr+1正好是vline变量的起始地址(vline紧跟在vaddr后面)。这直接破坏了vline的低8位数据,导致你的换行逻辑(new_line标签下的代码)完全失效,所以单次调用时所有字符串都挤在同一行,而不是按0xa换行。

2. 连续调用print前手动重置了si寄存器

你的代码在两次调用print前都执行了mov si, msg,这会让si每次都重新指向字符串的起始位置。而print函数本身是通过lodsb指令自动推进si的,第一次调用结束后si已经指向字符串的末尾(0x0的下一个位置),如果你希望第二次调用从上次结束的位置继续输出,完全不需要手动重置si。


修复后的代码

下面是修正后的代码,我做了两处关键修改:

  • 将vaddr改为dw 0x0(分配2字节空间,匹配bx的16位长度)
  • 移除第二次调用前的mov si, msg,让si保持在上次结束的位置
[ORG 0x7c00]
xor ax, ax
mov ds, ax
mov ss, ax
mov sp, 0x9c00
mov ax, 0xb800
mov gs, ax

call clear

mov si, msg
mov ah, 4
call print

; 移除手动重置si的指令,直接调用print
mov ah, 4
call print

cli
jmp $

print:
mov bx, [vaddr]
write:
lodsb
cmp al, 0
je end_write
cmp al, 0xa
je new_line
mov [gs:bx], ax
add bx, 2
jmp write
new_line:
mov cx, [vline]
add cx, 160
mov [vline], cx
sub cx, bx
add bx, cx
jmp write
end_write:
mov [vaddr], bx
ret

clear:
mov ah, 0
mov al, ' '
xor bx, bx
mov cx, 2000
clear_char:
mov [gs:bx], ax
add bx, 2
loop clear_char
mov word [vaddr], 0  ; 改为word操作,匹配dw定义
mov dword [vline], 0
ret

msg: db "Hello World1", 0xa, "Hello World2", 0xa, "Hello World3", 0xa, 0xa, 0x0
vaddr: dw 0x0  ; 改为dw,分配2字节空间
vline: dd 0

times 510-($-$$) db 0
db 0x55
db 0xAA

修复后的效果

  • 单次调用print时,会正确按0xa换行,输出三行Hello World,最后留一个空行
  • 连续调用两次print时,第二次会从第一次结束的空行位置继续(但因为第一次已经到了字符串末尾,第二次调用print时lodsb会直接读到0x0,不会输出任何内容,符合预期)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:04:31