TASM(DosBOX环境)数字打印程序异常:乱码且冻结求助
汇编程序输出乱码并冻结的修复方案
问题描述
在DOSBox模拟器中使用TASM开发的汇编程序,预期输出两行计算结果:
25 + 10 = 35 25 - 10 = 15
但实际运行时会打印乱码,且程序冻结。原始代码如下:
SSEG segment stack db 256 dup(0) SSEG ends DSEG segment num1 dw 25 num2 dw 10 new_line db 0dh,0ah,'$' msg_add db '25 + 10 = ','$' msg_sub db '25 - 10 = ','$' DSEG ends CSEG segment assume cs:CSEG,ds:DSEG,ss:SSEG begin: mov ax, DSEG mov ds, ax ; ADD mov ah, 09h mov dx, offset msg_add int 21h mov ax, num1 mov bx, num2 add ax, bx mov ax, ax call print_number ; SUB mov ah, 09h mov dx, offset msg_sub int 21h mov ax, num1 mov bx, num2 sub ax, bx mov ax, ax call print_number print_number proc mov si,10 mov cx,0 a: mov dx,0 div si add dx,'0' push dx inc cx cmp ax,0 jnz a aa: pop dx mov ah,02h int 21h loop aa mov ah, 09h mov dx, offset new_line int 21h ret print_number endp mov ah,4ch int 21h CSEG ends end begin
尝试过的无效方案
- 栈传参方式
调用代码:
mov ah, 09h mov dx, offset msg_add int 21h mov ax, num1 mov bx, num2 add ax, bx push ax call print_number
- 错误弹出写法(直接弹出返回地址):
print_number proc pop ax mov si,10 mov cx,0 a: mov dx,0 div si add dx,'0' push dx inc cx cmp ax,0 jnz a aa: pop dx mov ah,02h int 21h loop aa mov ah, 09h mov dx, offset new_line int 21h ret print_number endp
- 冗余压入写法(未保存寄存器):
print_number proc push ax mov si,10 mov cx,0 a: mov dx,0 div si add dx,'0' push dx inc cx cmp ax,0 jnz a aa: pop dx mov ah,02h int 21h loop aa mov ah, 09h mov dx, offset new_line int 21h ret print_number endp
- 寄存器传参方式
调用代码与原始代码一致,过程实现也未做调整,未解决问题。
核心问题分析
- 过程定义位置错误:原始代码中
print_number proc放在主程序执行流程中间,主程序调用完两次print_number后,会直接进入过程代码执行,而非执行退出指令mov ah,4ch,导致程序进入错误流程。 - 寄存器未保存恢复:过程中使用的
ax、cx、dx、si寄存器会破坏主程序的寄存器状态,引发后续逻辑错误。 - 栈传参写法错误:
pop ax直接弹出栈中的返回地址,导致ret指令无法正确返回主程序,引发崩溃。
修复后的完整代码
采用AX寄存器传递待打印数字的方式,修正后的代码如下:
SSEG segment stack db 256 dup(0) SSEG ends DSEG segment num1 dw 25 num2 dw 10 new_line db 0dh,0ah,'$' msg_add db '25 + 10 = ','$' msg_sub db '25 - 10 = ','$' DSEG ends CSEG segment assume cs:CSEG,ds:DSEG,ss:SSEG ; 过程定义移到主程序执行路径之外 print_number proc push ax ; 保存用到的寄存器 push cx push dx push si mov si,10 mov cx,0 a: mov dx,0 div si add dx,'0' push dx inc cx cmp ax,0 jnz a aa: pop dx mov ah,02h int 21h loop aa mov ah, 09h mov dx, offset new_line int 21h pop si ; 恢复寄存器 pop dx pop cx pop ax ret print_number endp begin: mov ax, DSEG mov ds, ax ; ADD mov ah, 09h mov dx, offset msg_add int 21h mov ax, num1 add ax, num2 ; 直接相加,无需BX中转 call print_number ; SUB mov ah, 09h mov dx, offset msg_sub int 21h mov ax, num1 sub ax, num2 ; 直接相减,无需BX中转 call print_number mov ah,4ch int 21h CSEG ends end begin
关键修复点说明
- 调整过程位置:将
print_number proc移到主程序begin:之前,避免主程序意外进入过程代码。 - 寄存器保护:过程开头用
push保存用到的寄存器,结尾用pop恢复,防止破坏主程序的寄存器状态。 - 简化传参逻辑:直接用AX传递待打印数字,去掉冗余的
mov ax, ax代码,计算时直接操作AX,简化逻辑。 - 正确处理栈:避免直接弹出返回地址的错误写法,寄存器传参更简单高效。
内容的提问来源于stack exchange,提问作者Coder4Fun250
相关产品推荐
相关产品推荐

