使用NASM汇编在DOSBox中打印字符串遇逻辑错误求助
DOSBox下NASM汇编字符串打印问题修复
问题分析与修复点
栈不平衡导致程序崩溃(需重启DOSBox的根源)
cal_Len和mystr子程序中均存在push ax仅1次、pop ax执行2次的错误,多余的出栈操作会破坏栈帧中的基址指针bp和返回地址,导致程序异常退出,进而影响DOSBox环境稳定性。修复方式:移除两个子程序中多余的pop ax指令。视频内存偏移计算错误
DOS视频内存中每个字符占2字节(ASCII码+属性),原代码直接将80*y + x作为偏移量,未做乘2处理,导致字符写入错误内存位置。修复方式:在计算出字符索引后,添加shl ax, 1指令将索引转换为正确的视频内存偏移。打印参数读取顺序错误
调用mystr时的参数压栈顺序为字符串地址→x坐标→y坐标→属性,但原代码颠倒了x、y坐标的读取位置,导致打印位置偏移。修复方式:调整坐标计算逻辑,正确读取bp+8(y坐标)和bp+6(x坐标)。
修复后的完整代码
org 0x0100 jmp start msg: db "Aurangzaib Awan", 0 msgLen: dw 0 ; 清屏子程序 clrscreen: push es push ax push cx push di mov ax, 0x0b800 mov es, ax mov ax, 0x0720 ; 黑底白字空格 mov cx, 2000 ; 80*25=2000个屏幕位置 rep stosw ; 填充整个屏幕 pop di pop cx pop ax pop es ret ; 计算字符串长度子程序 cal_Len: push bp mov bp, sp push ax push cx push si push di mov di, [bp + 4] ; 获取传入的字符串地址 mov cx, 0xffff ; 设置最大计数 xor al, al ; 以0为终止符搜索 repne scasb ; 逐个字节查找终止符 mov ax, 0xffff sub ax, cx ; 得到含终止符的总长度 dec ax ; 减去终止符,得到实际字符串长度 mov word [msgLen], ax pop di pop si pop cx pop ax pop bp ret 2 ; 清理栈上的1个参数 ; 字符串打印子程序 mystr: push bp mov bp, sp push es push ax push cx push si push di mov ax, 0xb800 mov es, ax mov ax, 80 mul byte [bp + 8] ; 计算80*y坐标 add ax, [bp + 6] ; 加上x坐标得到字符索引 shl ax, 1 ; 索引乘2,转换为视频内存偏移 mov di, ax mov si, [bp + 10] ; 获取字符串地址 mov cx, [msgLen] ; 获取字符串长度 mov ax, [bp + 4] ; 获取显示属性 cld ; 清零方向标志,正向读取 nextChar: lodsb ; 读取一个字符到al stosw ; 写入视频内存(字符+属性) loop nextChar ; 循环打印所有字符 pop di pop si pop cx pop ax pop es pop bp ret 10 ; 清理栈上的4个参数(共10字节) start: call clrscreen mov ax, msg push ax call cal_Len ; 压入参数:字符串地址→x坐标→y坐标→属性 mov ax, msg push ax mov ax, 30 ; x坐标 push ax mov ax, 20 ; y坐标 push ax mov ax, 1 ; 显示属性(蓝底白字) push ax call mystr mov ax, 0x4c00 int 0x21
编译运行步骤
- 用NASM编译:
nasm -f bin yourfile.asm -o yourfile.com - 在DOSBox中运行生成的
.com文件,即可正常显示目标字符串。
内容的提问来源于stack exchange,提问作者Aurangzaib Shehzad
相关产品推荐
相关产品推荐

