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

x64汇编实现阶乘触发Stack overflow错误,求问题排查

栈溢出问题分析与修复方案

兄弟,你的栈溢出根源是无限递归,而导致无限递归的核心是没遵守Windows x64的调用约定,参数传递全错了,让递归终止条件根本触发不了,最终把栈空间耗尽了。下面一步步给你拆解问题和修复方案:

核心问题拆解

1. x64调用约定完全搞错了

你用的是MSVC的x64汇编,Windows x64的调用约定(fastcall)明确规定:

  • 前4个整数参数通过寄存器传递,第一个参数用RCX,不是像x86那样压栈传递
  • 调用函数前必须保证栈是16字节对齐(call指令会压入8字节返回地址,所以调用前RSP % 16 == 0)

你在main里用push num传参数给factorial,然后在factorial里试图从[rbp+16]取参数——这位置根本不是你传的num值,而是栈上的垃圾数据,导致每次递归拿到的参数都不对,cmp rax,1永远跳不到quit标签,无限递归下去,栈直接爆了。

另外你原来的mov rdx,num也是错误的:你要取的是num存储的数值,不是它的内存地址,这会导致你打印的是地址而非用户输入的数字。

2. 递归栈管理有漏洞

就算参数传递对了,你在factorial里push rax后调用递归,返回后没把这个8字节弹出栈,栈指针会持续向下偏移,递归次数多了也会溢出(不过这次是无限递归先触发了溢出)。

修正后的代码

INCLUDELIB libcmt.lib
INCLUDELIB legacy_stdio_definitions.lib

EXTERN printf:PROC
EXTERN scanf:PROC

.DATA
prompt     BYTE "Enter a number: ", 0
inFmt      BYTE "%d", 0
prompt3    BYTE "The factorial is: %d",10,0
disp       BYTE "You Entered %d", 10,0
num        QWORD ?

.CODE
main PROC C
    ; x64调用需要32字节shadow space,sub rsp,40保证栈对齐+预留空间
    sub rsp, 40

    ; 提示用户输入
    lea rcx, prompt
    call printf

    ; 读取输入到num变量
    lea rdx, num
    lea rcx, inFmt
    call scanf

    ; 打印用户输入的数字(取num的内容而非地址)
    mov rdx, [num]
    lea rcx, disp
    call printf

    ; 调用阶乘函数,用RCX传递参数(x64第一个整数参数约定)
    mov rcx, [num]
    call factorial

    ; 打印阶乘结果
    mov rdx, rax
    lea rcx, prompt3
    call printf

    add rsp, 40
    mov rax, 0
    ret
main ENDP

factorial PROC
    push rbp
    mov rbp, rsp

    ; 从RCX取参数(符合x64调用约定)
    mov rax, rcx
    cmp rax, 1
    jle quit  ; 终止条件:n<=1时直接返回1

    ; 递归调用factorial(n-1)
    dec rax
    push rcx  ; 保存原n值,避免递归修改RCX导致丢失
    mov rcx, rax
    call factorial
    pop rcx   ; 恢复原n值

    ; 计算n * factorial(n-1)
    imul rcx  ; rax = rax * rcx(rax是递归返回的阶乘结果,rcx是原n)

quit:
    mov rsp, rbp
    pop rbp
    ret
factorial ENDP
END

关键修改点说明

  1. 参数传递修正:用RCX传递阶乘函数的参数,完全符合x64调用约定
  2. 栈对齐修正:main开头sub rsp,40,满足32字节shadow space要求同时保证栈16字节对齐
  3. 变量取值修正:把mov rdx,num改成mov rdx,[num],正确读取用户输入的数值
  4. 递归栈管理:递归前保存原参数到栈,调用后恢复,避免寄存器值丢失

注意:如果输入的数字超过20,会触发整数溢出(64位无符号整数的阶乘最大值是20!),但这和本次的栈溢出是不同类型的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 06:50:00