8086汇编二进制转十进制程序打印BX时循环异常问题排查
问题排查与修复方案
核心问题分析
1. 内存越界破坏数据
在反转二进制字符串的代码段中,循环结束后错误地修改了si指向的内存(此时si已超出bnum缓冲区的起始地址,指向未知内存区域),导致后续变量(如存储转换结果的bx)被意外篡改,进而引发循环异常终止。
原错误代码片段:
reverse: mov al ,[si] mov [di] ,al inc di dec si loop reverse ; add the string terminator inc di MOV BYTE PTR [SI], '$' ; 错误:si此时指向bnum缓冲区外,破坏其他内存
2. 循环终止条件的指令选择
使用JG ST(有符号数大于判断)虽然对正数商有效,但逻辑上更适合用JNZ ST(非零判断),直接判断商是否为0,避免有符号数判断的潜在歧义。
3. 打印循环的冗余操作
printt循环结束后额外打印[di]的操作冗余,且逻辑不够严谨,容易导致重复打印或遗漏。
修复后的完整代码
.model small .STACK 300h .data welcome DB 'Welcome, please enter binary number max(10 digits)',0Ah,0Dh,'Press e to end',0Ah,0Dh,'$' msg1 DB 0Ah,0Dh,'You entered: ',0Ah,0Dh,'$' error DB ' Not an option, sorry. Enter again: ',0Ah,0Dh,'$' obtions DB 0Ah,0Dh,0Ah,0Dh,'convert it to ',0Ah,0Dh,'1-decimal',0Ah,0Dh,'2-octal',0Ah,0Dh,'3-hexa',0Ah,0Dh, '9-End',0Ah,0Dh,'$' bnum DB 11 DUP(?) ; buffer to store the binary number rbnum DB 11 DUP(?) ; buffer to store the reversed binary number fdnum DB 11 DUP(?) ; buffer to store the final decimal answer number length_msg db 0Ah,0Dh,'Length is: ','$' lenght_bnum db 0 ; length of the binary number fans db 0 ; final answer hex_num db 5 DUP ('$') ; buffer to store the hexadecimal number endl DB 0Ah,0Dh dec_result db 6 dup (?) ; decimal result will be stored here oct_result db 5 dup (?) ; octal result will be stored here dec_result_len db 0 .code MAIN PROC .startup ; print welcome MOV ah ,09h LEA dx , welcome int 21h xor ax, ax ; clear ax register ; Read string LEA SI, bnum ; load the address of the buffer into SI MOV CX, 10 ; set the counter to 10 mov bx, 0 ; counter for the length of the binary number READ: MOV AH, 01h INT 21H ; read a character MOV [SI], AL ; store the character in the buffer CMP AL, 0Dh ; if equal to carriage return "Enter", jump string_end JE string_end ; if equal, jump string_end INC SI ; increment the pointer XOR AX, AX inc bx LOOP READ ; repeat until CX = 0 string_end: MOV BYTE PTR [SI], '$' ; add the string terminator ;;;reverse bnum dec si LEA di, rbnum ; load the address of the reversed buffer into DI MOV CX, bx ; set the counter to the length of binary number reverse: mov al ,[si] mov [di] ,al inc di dec si loop reverse ; add the string terminator to rbnum (修复:在rbnum末尾添加$) MOV BYTE PTR [DI], '$' ; 正确:DI此时指向rbnum最后一个字符的下一个位置 ;;; LEA DX, msg1 MOV AH, 09h INT 21h ; print msg1 "You entered:" LEA DX, bnum MOV AH, 09h INT 21h ; print the binary number xor si, si lea dx, length_msg mov ah, 09h int 21h ; print "Length is:" mov lenght_bnum, bl ; store the length of the binary number in lenght_bnum mov dl, lenght_bnum add dl, 30h MOV AH, 02h INT 21h ; print the length of the binary number ; print options obtion: mov ah, 09h LEA dx, obtions int 21h ; read option and store it in al mov ah, 01h ; int 21h ; ;switch cmp al,'1' je decimal cmp al,'2' je octal cmp al,'3' je hexadecimal cmp al,'9' je endd ; print error if not 1 or 2 or 3 or 9, and jump to option mov ah ,09h LEA dx , error int 21h jmp obtion decimal: mov cx ,bx xor bx ,bx ;reset to zero to store answer mov dx ,1 ; initialize weight to 2^0 LEA di, rbnum cbd: ; convert binary to decimal loop cmp [di],'0' je novalue ;if current digit is 0, skip adding weight add bx ,dx novalue: inc di shl dx, 1 ; multiply weight by 2 (next bit's weight) loop cbd ;;;;;;;;;;;;;;;;store decimal in string LEA di, fdnum mov cx,0ah ; divisor is 10 xor ax,ax mov ax,bx ; load decimal result into AX xor dx,dx ; clear DX for division ST : div cx ; AX = quotient, DX = remainder mov bx ,ax ; save quotient to BX add dl ,30h ; convert remainder to ASCII ; MOV AH, 02h ; 测试打印,可注释掉 ; INT 21h ; 测试打印余数,可注释掉 mov [di],dl ; store ASCII digit in buffer inc di ; move to next buffer position mov ax,bx ; load quotient back into AX xor dx,dx ; clear DX for next division CMP AX, 0 JNZ ST ; 修复:用非零判断替代有符号大于,逻辑更直接 dec di ; move to last valid digit in buffer ;;;;;;;;;;;;;;;;;;;; mov ah ,2 ; set DOS print character function LEA si, fdnum ; load start address of result buffer printt : mov dl , [di] ; load digit to print int 21h ; print digit dec di ; move to previous digit cmp di,si ; check if we've reached the start of the buffer JGE printt ; 修复:大于等于时继续循环,避免冗余操作 jmp endd octal: jmp endd hexadecimal: jmp endd endd: .EXIT MAIN ENDP END MAIN
关键修复点说明
- 修复内存越界:将
MOV BYTE PTR [SI], '$'改为MOV BYTE PTR [DI], '$',在反转后的二进制字符串缓冲区rbnum的末尾添加终止符,避免破坏其他内存数据。 - 优化循环终止条件:将
JG ST改为JNZ ST,直接判断商是否为0,逻辑更清晰,适配无符号数的商值判断。 - 简化打印循环:将
jne printt改为JGE printt,并移除末尾冗余的打印操作,确保从最后一个数字到第一个数字完整打印,逻辑更严谨。
内容的提问来源于stack exchange,提问作者Sohil Abuzeid
相关产品推荐
相关产品推荐

