You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于用户输入的汇编多位数加法代码结果异常求排查

求助:x86汇编多位数加法结果不正确,求排查问题

我最近写了一段x86汇编代码实现多位数加法,但运行后总是得不到正确的计算结果,麻烦帮忙看看哪里出问题了?我的代码如下:

SYS_EXIT equ 1
SYS_READ equ 3
SYS_WRITE equ 4
STDIN equ 0
STDOUT equ 1
segment .data
msg db "The sum is: "
len equ $-msg
msg2 db "Input num1: "
len2 equ $-msg2
msg3 db "Input num2:"
len3 equ $-msg3
lf db 0x0A
segment .bss
sum resb 40 ; 为ASCII字符串分配40字节
sum_len resd 1
number1 resb 40
number2 resb 40
num1_len resd 1
num2_len resd 1
section .text
global _start
_start:
; 输出“输入num1”
mov ecx, msg2
mov edx, len2
mov ebx, 1
mov eax, 4
int 0x80
; 读取并存储输入1
mov eax, SYS_READ
mov ebx, STDIN
mov ecx, number1
mov edx, 3
int 0x80
lea esi,[number1]
mov ecx,4
call string_to_int
; 输出“输入num2”
mov ecx, msg3
mov edx, len3
mov ebx, 1
mov eax, 4
int 0x80
; 读取并存储输入2
mov eax, SYS_READ
mov ebx, STDIN
mov ecx, number2
mov edx, 3
int 0x80
lea esi,[number2]
mov ecx,4
call string_to_int
; 加法运算
mov eax, [number1]
mov ebx, [number2]
add eax, ebx
; 将数字转换为字符串
mov edi, sum ; 参数:目标字符串地址
call int2str
; 获取EAX的数字并存储为ASCII
sub edi, sum
mov [sum_len], edi
; 输出“结果为:”
mov ecx, msg
mov edx, len
mov ebx, 1
mov eax, 4
int 0x80
; 输出求和结果
mov eax, 4
mov ebx, 1
mov ecx, sum
mov edx, [sum_len]
int 0x80
; 输出换行
mov eax, 4
mov ebx, 1
mov ecx, lf
mov edx, 1
int 0x80
; 退出程序
mov eax, 1
mov ebx, 0
int 0x80
; 输入:
; ESI = 待转换字符串的指针
; ECX = 字符串的位数(必须>0)
; 输出:
; EAX = 整数值
string_to_int:
xor ebx,ebx ; 清空ebx
.next_digit:
movzx eax,byte[esi]
inc esi
sub al,'0' ; 从ASCII转换为数字
imul ebx,10
add ebx,eax ; ebx = ebx*10 + eax
loop .next_digit ; 循环(--ecx)
mov eax,ebx
ret
int2str:
; 将EAX中的正整数转换为EDI指向的字符串
xor ecx, ecx
mov ebx, 10
.LL1: ; 第一循环:保存余数
xor edx, edx ; 清空EDX用于除法
div ebx ; EDX:EAX/EBX -> EAX为商,EDX为余数
push dx ; 保存余数
inc ecx ; 增加入栈计数器
test eax, eax ; 还有可除的数吗?
jnz .LL1 ; 是:继续循环
.LL2: ; 第二循环:取出余数
pop dx ; DL中是余数
or dl, '0' ; 转换为ASCII
mov [edi], dl ; 保存到字符串
inc edi ; 移动字符串指针
loop .LL2 ; 循环ECX次
mov byte [edi], 0 ; 终止字符
ret

我排查出几个关键问题:

  • 输入处理逻辑错误:调用SYS_READ时edx设为3,只能读取3个字符,但用户输入数字后按回车,实际输入包含数字和换行符;而且调用string_to_int时硬设ecx=4,会越界读取不确定的内存,导致转换出错误的整数。
  • 数值存储对象错误:string_to_int返回的转换后整数存在eax里,但代码里没有把这个值存到专门的变量,反而直接取[number1](这是ASCII字符串的内存)来做加法,完全搞错了操作对象。
  • 输入长度未正确处理:没有保存SYS_READ返回的实际读取字节数,也没去掉换行符,导致转换时把换行符当成数字处理(换行符ASCII是0x0A,减去'0'后是10,会被当成数字计算)。

修复后的代码:

我调整了变量定义,正确处理输入长度和数值存储,修复后的代码如下:

SYS_EXIT equ 1
SYS_READ equ 3
SYS_WRITE equ 4
STDIN equ 0
STDOUT equ 1
segment .data
msg db "The sum is: "
len equ $-msg
msg2 db "Input num1: "
len2 equ $-msg2
msg3 db "Input num2: "
len3 equ $-msg3
lf db 0x0A
segment .bss
sum resb 40 ; 为ASCII字符串分配40字节
sum_len resd 1
number1 resb 40
number2 resb 40
num1_val resd 1  ; 存储转换后的第一个整数
num2_val resd 1  ; 存储转换后的第二个整数
num1_len resd 1
num2_len resd 1
section .text
global _start
_start:
; 输出“输入num1”
mov ecx, msg2
mov edx, len2
mov ebx, STDOUT
mov eax, SYS_WRITE
int 0x80
; 读取并存储输入1
mov eax, SYS_READ
mov ebx, STDIN
mov ecx, number1
mov edx, 40  ; 最多读取40字节
int 0x80
mov [num1_len], eax  ; 保存实际读取的字节数
lea esi, [number1]
mov ecx, eax
dec ecx  ; 减去换行符的长度(最后一个字符是0x0A)
call string_to_int
mov [num1_val], eax  ; 把转换后的整数存起来

; 输出“输入num2”
mov ecx, msg3
mov edx, len3
mov ebx, STDOUT
mov eax, SYS_WRITE
int 0x80
; 读取并存储输入2
mov eax, SYS_READ
mov ebx, STDIN
mov ecx, number2
mov edx, 40
int 0x80
mov [num2_len], eax
lea esi, [number2]
mov ecx, eax
dec ecx  ; 去掉换行符
call string_to_int
mov [num2_val], eax

; 加法运算
mov eax, [num1_val]
mov ebx, [num2_val]
add eax, ebx

; 将数字转换为字符串
mov edi, sum ; 参数:目标字符串地址
call int2str
; 获取字符串长度
sub edi, sum
mov [sum_len], edi

; 输出“结果为:”
mov ecx, msg
mov edx, len
mov ebx, STDOUT
mov eax, SYS_WRITE
int 0x80
; 输出求和结果
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, sum
mov edx, [sum_len]
int 0x80
; 输出换行
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, lf
mov edx, 1
int 0x80
; 退出程序
mov eax, SYS_EXIT
mov ebx, 0
int 0x80

; 输入:
; ESI = 待转换字符串的指针
; ECX = 字符串的位数(必须>0)
; 输出:
; EAX = 整数值
string_to_int:
xor ebx, ebx ; 清空ebx用来累加数值
.next_digit:
movzx eax, byte[esi]
inc esi
sub al, '0' ; 从ASCII转换为数字
imul ebx, 10
add ebx, eax ; ebx = ebx*10 + 当前数字
loop .next_digit ; 循环处理每一位
mov eax, ebx ; 把结果放到eax返回
ret

int2str:
; 将EAX中的正整数转换为EDI指向的字符串
xor ecx, ecx
mov ebx, 10
.LL1: ; 第一循环:分解数字,余数入栈
xor edx, edx ; 清空EDX,因为div是EDX:EAX除以EBX
div ebx ; EAX=商,EDX=余数
push dx ; 保存余数(DL是余数的ASCII对应值)
inc ecx ; 记录入栈次数
test eax, eax ; 判断商是否为0
jnz .LL1 ; 不为0继续循环
.LL2: ; 第二循环:出栈转换为ASCII
pop dx
or dl, '0' ; 余数转成ASCII字符
mov [edi], dl
inc edi
loop .LL2
mov byte [edi], 0 ; 字符串结束符
ret

修复说明:

  1. 新增了num1_val和num2_val变量,专门存储转换后的整数,避免直接操作字符串内存。
  2. 读取输入时设置足够大的edx(40字节),保存实际读取的长度,调用string_to_int时减去换行符的长度,避免把换行符当成数字处理。
  3. 统一使用宏定义的常量(比如SYS_WRITE代替直接写4),让代码更清晰易读。

内容的提问来源于stack exchange,提问作者er 21

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 20:42:56