You need to enable JavaScript to run this app. x86_64 Intel汇编实现ft_putnbr仅首位数字输出正确的问题
优惠活动
大模型
产品
解决方案
定价
更多

x86_64 Intel汇编实现ft_putnbr仅首位数字输出正确的问题

代码错误定位

核心问题排查

  • 递归调用后寄存器值被覆盖,导致数位输出错误
    按照System V AMD64调用约定,rdx属于跨函数调用可被随意改写的临时寄存器。你在除法操作中得到的数位余数存在rdx中,紧接着就调用递归版本的_ft_putnbr——这个递归流程内部的除法操作、甚至调用_ft_putchar时的系统调用,都会直接覆盖rdx的值。等递归返回后再用mov rdi, rdx取数位时,拿到的根本不是之前计算的余数,全是流程运行留下的残留值,这就是正数输入时仅最高位(最外层直接走到打印分支的数位)正确、其余数位全输出0的原因。
  • 未遵守调用约定保存保留寄存器rbx
    rbx属于被调用者必须保护的寄存器,任何函数修改rbx前必须先入栈保存,返回前恢复原值。你在除法逻辑中直接mov rbx, 10修改寄存器值,没有做任何保存恢复,会直接破坏外层调用方的栈帧和局部变量,导致函数返回时栈指针错位,这就是负数输入时输出无意义大数值的原因。
  • 无效栈操作逻辑错误
    你在递归调用前写的mov rdi, 0 / push rdi没有实际作用:这步原本的设计意图是保存除法得到的余数,但你只把0压入栈,没有真正保存需要的rdx值,等于空做了栈操作。
  • 未兼容整数溢出边界
    当前neg rdi的逻辑,在输入64位有符号整数最小值时,会因为neg操作产生整数溢出,无法得到正确的绝对值,属于边界场景缺失。
修正后可正常运行的代码
BITS 64

extern  _ft_putchar

    section .text
    global  _ft_putnbr

_ft_putnbr:
    push    rbx         ; 按调用约定保存rbx,避免破坏调用方寄存器
    mov     rbx, 10    ; 固定除数,无需重复赋值

_loop:
    cmp     rdi, 0
    jl      _put_dash
    cmp     rdi, rbx
    jae     _div_ten
    jmp     _put_dig

_div_ten:
    mov     rax, rdi
    xor     rdx, rdx    ; 清空rdx,准备做64位除法
    div     rbx         ; 除法完成:rax=商,rdx=余数
    push    rdx         ; 先把余数压栈,避免被递归调用覆盖
    mov     rdi, rax
    call    _ft_putnbr  ; 递归打印高位部分
    pop     rdx         ; 递归返回后取出之前保存的数位
    mov     rdi, rdx
    jmp     _put_dig

_put_dash:
    push    rdi
    mov     rdi, '-'
    call    _ft_putchar
    pop     rdi
    neg     rdi
    js      _min_val_handle  ; 处理neg溢出的整数最小值场景
    jmp     _loop

_min_val_handle:
    ; 处理无法取绝对值的64位最小值:先打印个位8,再递归打印剩余部分
    mov     rdi, 8
    call    _ft_putchar
    mov     rdi, 922337203685477580
    call    _ft_putnbr
    jmp     _exit

_put_dig:
    add     rdi, 48      ; 转换为ASCII字符
    call    _ft_putchar

_exit:
    pop     rbx         ; 恢复rbx原值
    ret

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.04 08:45:04