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

x86汇编Linux系统调用计算器无法显示计算结果问题排查

解决x86汇编计算器无法显示结果的问题

嘿,我帮你揪出了几个导致结果无法正常显示的核心问题,咱们一步步来修复:

问题1:输入读取的文件描述符错误

Linux系统调用中,sys_read(eax=3)的文件描述符参数(ebx),标准输入是0,而你写成了2(这是标准错误stderr)。虽然某些环境下可能凑巧能读到输入,但这是不规范的,还可能引发异常。把所有读取输入的mov ebx, 2改成mov ebx, 0。

问题2:缺少字符串转整数的处理

你直接把first和second的内容加到eax里,但用户输入的是ASCII字符串(比如输入"10",内存里是字符'1'(ASCII 49)和'0'(ASCII 48)),不是直接可用的整数。必须先把这些字符串转换成十进制整数才能计算。

我给你加个字符串转整数的函数str_to_int,它会把输入的数字字符串转成整数存在eax里:

; 字符串转整数:输入ecx=字符串地址,输出eax=转换后的整数
str_to_int:
    xor eax, eax        ; 初始化结果为0
    mov esi, ecx        ; esi指向字符串起始
.next_digit:
    movzx edx, byte [esi] ; 取当前字符
    cmp dl, 0xA         ; 判断是否是换行符(输入结束)
    je .done
    cmp dl, 0xD         ; 处理回车符
    je .done
    sub dl, '0'         ; ASCII转数字
    imul eax, 10        ; 结果*10
    add eax, edx        ; 加上当前数字
    inc esi             ; 指针后移
    jmp .next_digit
.done:
    ret

然后在读取完first和second后调用这个函数,把结果存到对应的内存里:

; 读取第一个数字后转成整数
mov ecx, first
call str_to_int
mov [first_num], eax

; 读取第二个数字后转成整数
mov ecx, second
call str_to_int
mov [second_num], eax

记得在.bss段加上存储整数的变量:

first_num resd 1
second_num resd 1

问题3:缺少整数转字符串的处理

计算后的结果是整数(比如15),但sys_write需要输出ASCII字符串。你直接把[result]作为输出地址,其实是把整数的二进制值当成内存地址,指向的内容不是可显示的字符,所以看不到正确结果。

再加个整数转字符串的函数int_to_str,把整数转成ASCII字符串:

; 整数转字符串:输入eax=整数,ecx=输出字符串地址,输出edx=字符串长度,ecx=字符串起始地址
int_to_str:
    mov esi, ecx
    add esi, 9          ; 从字符串末尾开始(最多10位数字)
    mov byte [esi], 0   ; 字符串结束符
    mov ebx, 10         ; 除数10
.next_digit:
    xor edx, edx
    div ebx             ; eax=商,edx=余数
    add dl, '0'         ; 余数转ASCII
    dec esi
    mov [esi], dl
    test eax, eax
    jnz .next_digit
    mov edx, ecx
    add edx, 10
    sub edx, esi        ; 计算字符串长度
    mov ecx, esi        ; 字符串起始地址
    ret

然后在计算完结果后调用这个函数,再输出:

equalsSignSum: ;sum system
xor eax, eax
add eax, [first_num] ; 用转换后的整数计算
add eax, [second_num]
mov ecx, result
call int_to_str
;display result section
mov eax, 4
mov ebx, 1
mov ecx, resultMsg
mov edx, lenResultMsg
int 80h
;display the result number
mov eax, 4
mov ebx, 1
; int_to_str已经把ecx设为字符串起始,edx设为长度
int 80h
jmp exit

修改后的完整代码

section .data ;Data segment
firstNumberMsg db 'Please give the first number: ' ;Ask the user for first number to calculate
lenFirstNumberMsg equ $-firstNumberMsg ;The length of the message
secondNumberMsg db 'Please give the second number: ' ;Ask the user for second number to calculate
lenSecondNumberMsg equ $-secondNumberMsg ;The length of the message
signMsg db 'Please give the calculation sign: ' ;Ask the user for calculation type
lenSignMsg equ $-signMsg ;The length of the message
resultMsg db 'Result: '
lenResultMsg equ $-resultMsg

section .bss
first resb 5
second resb 5
result resb 10
sign resb 1
first_num resd 1
second_num resd 1

section .text
global _start

; 字符串转整数:输入ecx=字符串地址,输出eax=转换后的整数
str_to_int:
    xor eax, eax
    mov esi, ecx
.next_digit:
    movzx edx, byte [esi]
    cmp dl, 0xA
    je .done
    cmp dl, 0xD
    je .done
    sub dl, '0'
    imul eax, 10
    add eax, edx
    inc esi
    jmp .next_digit
.done:
    ret

; 整数转字符串:输入eax=整数,ecx=输出字符串地址,输出edx=字符串长度,ecx=字符串起始地址
int_to_str:
    mov esi, ecx
    add esi, 9
    mov byte [esi], 0
    mov ebx, 10
.next_digit:
    xor edx, edx
    div ebx
    add dl, '0'
    dec esi
    mov [esi], dl
    test eax, eax
    jnz .next_digit
    mov edx, ecx
    add edx, 10
    sub edx, esi
    mov ecx, esi
    ret

exit: ;Exit from program
mov eax, 1
mov ebx, 0
int 80h

equalsSignSum: ;sum system
xor eax, eax
add eax, [first_num]
add eax, [second_num]
mov ecx, result
call int_to_str
;display result section
mov eax, 4
mov ebx, 1
mov ecx, resultMsg
mov edx, lenResultMsg
int 80h
;display the result number
mov eax, 4
mov ebx, 1
int 80h
jmp exit

_start: ;Display the first prompt for entering a number
mov eax, 4
mov ebx, 1
mov ecx, firstNumberMsg
mov edx, lenFirstNumberMsg
int 80h
;Read stdin from user (as a first number)
mov eax, 3
mov ebx, 0
mov ecx, first
mov edx, 5 ;5 bytes (numeric, 1 for sign) of that information
int 80h
; 转成整数
mov ecx, first
call str_to_int
mov [first_num], eax

;Display the second prompt for entering a number
mov eax, 4
mov ebx, 1
mov ecx, secondNumberMsg
mov edx, lenSecondNumberMsg
int 80h
;Read stdin from user (as a second number)
mov eax, 3
mov ebx, 0
mov ecx, second
mov edx, 5 ;5 bytes (numeric, 1 for sign) of that information
int 80h
; 转成整数
mov ecx, second
call str_to_int
mov [second_num], eax

;Display the sign prompt
mov eax, 4
mov ebx, 1
mov ecx, signMsg
mov edx, lenSignMsg
int 80h
;Read stdin from user (as a sign)
mov eax, 3
mov ebx, 0
mov ecx, sign
mov edx, 2 ; 多读1字节,因为输入+后会按回车,避免后续判断出错
int 80h
;Calculation sign section
mov ebx, 43 ;43 is '+' in ascii
cmp [sign], ebx
je equalsSignSum ;jump to this label if user entered '+' as sign
;else
; Exit code
mov eax, 1
mov ebx, 0
int 80h

编译运行

还是用你原来的编译命令:

nasm -f elf calculator.asm && ld -m elf_i386 -s -o calculator calculator.o && ./calculator

现在输入10、5、+,就能正常显示Result: 15啦~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 00:17:31