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

汇编实现递归Factorial阶乘程序触发segfault段错误

递归实现阶乘触发段错误问题排查

问题现象

  • 手写汇编实现Factorial阶乘递归逻辑,程序运行直接触发segfault段错误,无法正常输出结果
  • 尝试使用gdb调试未定位到具体故障点

原问题给出的实现代码如下:

push 4
        call Factorial

        exit
        
        Factorial:
            cmp byte [rsp + 8], 0
            jz end
            
            mov eax, [rsp + 8]
            mov ebx, eax
            dec ebx
            imul eax, ebx
            add rsp, 8
            push rbx
            call Factorial

            end:
                ret

故障根因

代码存在4个核心问题,直接触发段错误、逻辑错误:

  1. 栈操作完全失衡:call指令执行时会自动将返回地址压入栈顶,进入函数后[rsp+8]才是传入的参数。原代码在递归分支执行add rsp, 8直接弹出当前层参数后,没有处理当前栈顶留存的返回地址,后续递归返回执行ret时,会从栈顶取到非法地址跳转,直接触发段错误。
  2. 递归逻辑完全错误:阶乘递归的核心逻辑是n! = n * (n-1)!,需要等下一层递归返回(n-1)!的结果后再和当前层的n做乘法。原代码在当前层直接计算n*(n-1)就进入递归,完全没有做结果累积,基线条件(n=0)触发时也没有返回0!对应的结果1,最终根本拿不到正确计算值。
  3. 寄存器使用违反调用约定:x86-64体系下rbx是被调用者保存寄存器,函数内修改rbx前必须提前压栈保存,返回前恢复,否则会破坏上层调用的上下文,触发不可预期的错误。
  4. 参数比较逻辑错误:原代码用cmp byte [rsp + 8], 0只比较参数的最低1字节,传入参数高位非0时会直接判断错误,导致递归无法正常终止。

修正后可正常运行的实现

; 测试入口:计算4!
push 4
call Factorial
; 执行完成后rax寄存器存储结果24
; 注意自行实现exit逻辑时保证栈对齐符合系统调用要求
exit

Factorial:
    ; 提前保存被调用者寄存器rbx,遵守调用约定
    push rbx
    ; 取出传入的参数n:当前栈顶是保存的rbx,rsp+8是返回地址,rsp+16是传入的第一个参数
    mov rax, [rsp + 16]
    ; 基线条件:n=0时返回0! = 1
    cmp rax, 0
    jnz .recurse
    mov rax, 1
    jmp .return
.recurse:
    ; 暂存当前n到rbx,避免递归调用后值被覆盖
    mov rbx, rax
    ; 传入参数n-1,递归计算(n-1)!
    dec rax
    push rax
    call Factorial
    ; 弹出递归传入的参数,平衡栈
    add rsp, 8
    ; 计算n * (n-1)!,结果存在rax作为返回值
    imul rax, rbx
.return:
    ; 恢复保存的rbx寄存器
    pop rbx
    ret

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 10:21:18