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
相关产品推荐
相关产品推荐

