实模式下编写栈传参字符串打印函数的问题咨询
核心问题分析
你代码运行输出异常的核心原因有两个:
- BIOS中断
int 0x10的0x0E电传打印功能要求显式设置bh寄存器为当前显示页号,你代码中没有给bh赋值,BIOS会使用寄存器内的随机值,导致字符输出到非当前显示页,出现乱码。 - 你定义的字符串里仅添加了换行符
0x0a,缺少回车符0x0d,换行后光标不会回到行首,会导致后续输出位置错位。
修复方案
只需要修改两处代码即可正常运行:
- 在打印字符的逻辑前添加
mov bh, 0,指定输出到0号显示页 - 将buffer定义里的
0x0a修改为0x0d, 0x0a,补充回车符
通用优化建议
- 栈平衡:调用
print前你压入了2字节的字符串地址参数,函数返回后需要执行add sp, 2清理栈空间,养成良好的栈操作习惯,避免后续逻辑出现栈溢出问题 - 指令简化:可以用
lodsb指令替代mov al, [si]+add si, 1的组合,该指令会自动从ds:si地址读取1字节到al,同时自动将si加1,代码更简洁 - 方向标志位校验:可在
print入口添加cld指令,确保方向标志位DF为0,避免lodsb出现逆向遍历的异常 - 注释准确性:
org 0x7c00是BIOS加载引导扇区的固定内存地址,不是随意设置的,可修正注释避免误解 - 鲁棒性优化:可在
print入口增加参数非空判断,避免传入空地址时访问非法内存
修复后完整代码
[bits 16] [global _start] org 0x7c00 ; BIOS固定将引导扇区加载到0x7c00地址 ; 全局数据定义 buffer: db "Hello World!", 0x0d, 0x0a, 0 ; 补充回车符,以0结尾的字符串 eop: db "End of program", 0 _start: xor ax, ax mov ds, ax ; 数据段设为0,匹配org设置 push buffer call print ; 压入字符串地址调用打印函数 add sp, 2 ; 清理栈上的参数,平衡栈 mov al, 'F' ; 调试输出 mov ah, 0x0e mov bh, 0 int 0x10 jmp $ ; 程序结束,死循环 print: .prepare: push bp mov bp, sp pusha ; 保存所有寄存器上下文 cld ; 确保方向标志位为0,lodsb正向遍历 mov si, [bp+4] ; 从栈中获取传入的字符串地址 .char_loop: lodsb ; 读取当前字符到al,si自动+1 cmp al, 0 ; 遇到0结束符就退出 je .return mov ah, 0x0e mov bh, 0 ; 指定输出到0号显示页 int 0x10 jmp .char_loop .return: popa pop bp ret times 510-($-$$) db 0 ; 填充剩余空间到510字节 db 0x55, 0xaa ; 引导扇区魔数标识
内容的提问来源于stack exchange,提问作者Just a Salad Knight
相关产品推荐
相关产品推荐

