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

x86汇编逐字节读取程序调试器中正常,直接运行返回错误值

x86汇编程序返回值异常原因分析

这段x86汇编程序的功能是逐字节读取标准输入的十进制ASCII数字,转换为整数后存入EDI寄存器,最终通过_exit系统调用将EDI的值作为进程退出码返回。但出现以下异常:

  • GDB逐步调试时,EDI寄存器的值正确(输入2后直接Ctrl+D,EDI为2)
  • 直接运行程序(输入2→回车→Ctrl+D),通过echo $?查看返回值为238(0xEE)

汇编代码

global _start
%macro kernel 4
    mov eax, %1
    mov ebx, %2
    mov ecx, %3
    mov edx, %4
    int 80h
%endmacro
section .bss
    symbol resb 1
section .text
_start:
    mov esi, 10
    xor edi, edi
.loop:
    kernel 3, 0, symbol, 1 ; load 1 char from STDIN into symbol
    test eax, eax          ; nothing loaded - EOF
    jz .quit
    xor ebx, ebx
    mov bl, [symbol]
    sub bl, '0'
    cmp bl, 9
    jg .quit               ; not a number
    mov eax, edi           ; previously accumulated number
    mul esi                ; eax *= 10
    lea edi, [eax + ebx]
    jmp .loop

.quit:
    mov eax, 1
    mov ebx, edi
    int 80h

编译与运行命令

$ nasm -g -f elf32 st3-18a.asm
$ ld -g -m elf_i386 st3-18a.o -o st3-18a
$ ./st3-18a
2[Enter]
Ctrl-d

异常核心原因:条件跳转指令使用错误

问题出在判断输入是否为数字的跳转逻辑上:

  • 当输入2后按回车,程序会读取到两个字符:'2'(ASCII 50)和'\n'(ASCII 10)
  • 处理'\n'时,sub bl, '0'后bl的值为10 - 48 = -38,对应8位无符号数是0xEE(238)
  • 代码中使用cmp bl, 9后接jg .quit:jg是有符号数的大于跳转指令,对于有符号数来说,-38 < 9,因此不会跳转到.quit,反而继续执行后续的数值计算
  • 后续计算中,eax = 2 * 10 = 20,lea edi, [eax + ebx]得到edi = 20 + (-38) = -18,对应32位值为0xFFFFFFEE
  • Linux的_exit系统调用(eax=1)只返回ebx的低8位作为进程退出码,因此最终返回0xEE(238)

而GDB调试时,若直接输入2后按Ctrl+D,程序仅读取到'2'就遇到EOF,不会触发错误的数值计算,因此EDI值正确。

修复方案

将jg .quit替换为无符号数大于跳转指令ja .quit:

cmp bl, 9
ja .quit               ; not a number

ja会按无符号数比较,0xEE(238)大于9,此时会跳转到.quit,避免错误计算EDI的值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 00:25:31