汇编实现递归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个核心问题,直接触发段错误、逻辑错误:
- 栈操作完全失衡:
call指令执行时会自动将返回地址压入栈顶,进入函数后[rsp+8]才是传入的参数。原代码在递归分支执行add rsp, 8直接弹出当前层参数后,没有处理当前栈顶留存的返回地址,后续递归返回执行ret时,会从栈顶取到非法地址跳转,直接触发段错误。 - 递归逻辑完全错误:阶乘递归的核心逻辑是
n! = n * (n-1)!,需要等下一层递归返回(n-1)!的结果后再和当前层的n做乘法。原代码在当前层直接计算n*(n-1)就进入递归,完全没有做结果累积,基线条件(n=0)触发时也没有返回0!对应的结果1,最终根本拿不到正确计算值。 - 寄存器使用违反调用约定:x86-64体系下
rbx是被调用者保存寄存器,函数内修改rbx前必须提前压栈保存,返回前恢复,否则会破坏上层调用的上下文,触发不可预期的错误。 - 参数比较逻辑错误:原代码用
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
相关产品推荐
相关产品推荐

