DOS Debug汇编程序仅输出12个字符的问题排查求助
DOS Debug汇编程序输出截断问题排查
问题描述
我正在用DOS Debug开发汇编程序,需求如下:
- 接收输入字符串
- 统计每个字符的第0、2、3、6位二进制位之和,若和为偶数则将该字符替换为
4(ASCII码0x34) - 最后倒序输出字符串
目前程序大部分功能正常,但存在输出截断问题:输入字符串abcdefghijklmn(共14个字符)时,实际输出为n4lk4i4g4e44(仅12个字符),预期输出应为n4lk4i4g4e44b4。怀疑是loop循环执行12次后停止,请求排查原因。
汇编代码
a800 db 50 00 a100 mov ah, 09 mov dx, 700 int 21 mov ah, 3f mov dx, 800 int 21 a150 mov bx, 800 mov si, 0 jmp 250 a250 mov al, [bx+si] mov cl, [bx+si] mov byte [750], cl cmp al, 20 jl 490 mov ah, 0 clc rcr al, 1 adc ah, 0 clc rcr al, 2 adc ah, 0 clc rcr al, 1 adc ah, 0 clc rcr al, 4 adc ah, 0 mov al, ah mov ah, 0 clc rcr al, 1 adc ah, 0 cmp ah, 0 jg 300 jmp 320 a300 mov byte [bx+si], 34 inc si jmp 250 a320 mov byte [bx+si], [750] inc si jmp 250 a490 mov byte [bx+si+1], 24 xor dx, dx jmp 500 a500 mov ah, 02 mov dl, [bx+si] int 21 dec si loop 500 mov ah, 4c int 21 a700 db "Iveskite teksta " 0A 0D "$" n bb.com r cx 1000 w q
代码段说明:
a250:统计字符指定二进制位的和a490:在字符串末尾添加$符号
问题原因分析
1. loop循环计数器未正确初始化
loop指令依赖CX寄存器作为循环计数器,每次执行会自动将CX减1,直到CX=0时停止。但你的程序存在两个关键问题:
- 调用
int 21h的0x3F号输入读取功能后,CX寄存器的值会被系统调用修改(0x3F功能执行过程中会改变CX的原始值) - 进入倒序输出的
a500代码段前,从未将CX赋值为输入字符串的有效长度,导致CX为随机垃圾值(此处恰好为12),循环仅执行12次就终止,造成输出截断。
2. 输入长度处理异常
原代码调用0x3F读取输入时,未设置BX(标准输入句柄,需设为0)和CX(最大读取字节数,对应a800处定义的50),且未保存系统调用返回的实际读取字节数(存在AX中),导致无法准确获取输入字符串的有效长度。
3. 位统计逻辑错误
原代码用rcr移位指令统计位之和,多次移位会破坏原始字符值,且判断终止的条件cmp al,20会误将回车符以外的控制字符判定为结束,导致部分字符未被处理。
修复方案
1. 正确读取输入并保存长度
修改a100代码段,补全输入读取的参数,并保存实际读取长度:
a100 mov ah, 09 mov dx, 700 int 21 mov ah, 3f mov bx, 0 ; 指定标准输入句柄 mov cx, 50 ; 对应缓冲区最大长度 mov dx, 800 int 21 mov [802], ax ; 保存实际读取的字节数到内存
2. 初始化循环计数器
修改a490代码段,设置CX为有效字符长度,并修正$符号的位置:
a490 mov byte [bx+si], 24 ; 覆盖回车符位置,无需+1 mov cx, [802] dec cx ; 去掉回车符,得到有效字符数 mov si, cx ; 让SI指向最后一个有效字符的索引 jmp 500
3. 修正位统计逻辑
用test指令安全提取指定二进制位,避免破坏原始字符:
a250 mov al, [bx+si] mov cl, al ; 保存原始字符 cmp al, 0D ; 仅在遇到回车符时结束处理 je 490 mov ah, 0 test al, 00000001b ; 检查第0位 jnz inc_ah jmp skip0 inc_ah: inc ah skip0: test al, 00000100b ; 检查第2位 jnz inc_ah2 jmp skip2 inc_ah2: inc ah skip2: test al, 00001000b ; 检查第3位 jnz inc_ah3 jmp skip3 inc_ah3: inc ah skip3: test al, 01000000b ; 检查第6位 jnz inc_ah6 jmp skip6 inc_ah6: inc ah skip6: test ah, 1 ; 判断和是否为偶数 jnz 320 ; 和为奇数,保留原字符 jmp 300 ; 和为偶数,替换为4
内容的提问来源于stack exchange,提问作者Kurbamit
相关产品推荐
相关产品推荐

