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

x64汇编递归阶乘程序始终返回1问题排查求助

递归阶乘程序返回1的问题分析与修复

核心错误点

  1. 比较逻辑完全颠倒:
    原代码中cmp %rax, %rbx结合jle if,实际判断的是1 <= n——只要输入的n≥1,就会直接跳转到终止分支返回1,完全跳过递归逻辑。正确逻辑应为当n <= 1时返回1,需将比较指令改为cmp %rbx, %rax,让jle if在n≤1时触发。

  2. 递归参数传递错误:
    原代码仅修改了栈上的局部变量,却未将减1后的值加载到rdi寄存器(x64 System V调用约定中第一个参数存于rdi)。递归调用fact时仍使用初始的n值,导致递归层级无法递减,最终还是返回1。

  3. 阶乘计算逻辑错误:
    原代码在递归前修改了栈上的n值为n-1,导致递归返回后乘的是n-1而非原始n,结果会变成(n-1)!而非n!。应保留栈上的原始n值,单独计算n-1作为递归参数。

  4. 未正确保存非易失性寄存器:
    rbx属于x64 System V调用约定的非易失性寄存器,函数修改它前需保存到栈,返回前恢复,避免破坏调用者的寄存器状态。

修正后的完整代码

.section .data
    outfmt: .asciz "%d\n"
.section .text
    .extern printf
    .global main

fact:
    pushq %rbx                # 保存非易失性寄存器rbx
    addq $16, %rsp
    movq %rdi, 0(%rsp)        # 将参数n存入局部变量
    movq 0(%rsp), %rax
    movq $1, %rbx
    cmp %rbx, %rax            # 判断n是否小于等于1
    jle if

    # 递归分支:计算n * fact(n-1)
    movq 0(%rsp), %rdi        # 取出原始n
    subq $1, %rdi             # 计算n-1
    call fact                 # 调用fact(n-1),结果存在rax中
    imulq 0(%rsp), %rax       # rax = fact(n-1) * n
    jmp factend

if:
    movq $1, %rax             # 终止条件:n<=1时返回1

factend:
    subq $16, %rsp
    popq %rbx                 # 恢复rbx寄存器
    ret

main:
    movq $5, %rdi
    call fact
    movq %rax, %rsi
    leaq outfmt, %rdi
    movq $0, %rax
    call printf
    ret

验证说明

修正后的代码调用fact(5)时,会依次递归调用fact(4)到fact(1),fact(1)返回1后逐层计算:1*2=2、2*3=6、6*4=24、24*5=120,最终printf输出120,符合5的阶乘结果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 02:20:48