x64汇编递归阶乘程序始终返回1问题排查求助
递归阶乘程序返回1的问题分析与修复
核心错误点
比较逻辑完全颠倒:
原代码中cmp %rax, %rbx结合jle if,实际判断的是1 <= n——只要输入的n≥1,就会直接跳转到终止分支返回1,完全跳过递归逻辑。正确逻辑应为当n <= 1时返回1,需将比较指令改为cmp %rbx, %rax,让jle if在n≤1时触发。递归参数传递错误:
原代码仅修改了栈上的局部变量,却未将减1后的值加载到rdi寄存器(x64 System V调用约定中第一个参数存于rdi)。递归调用fact时仍使用初始的n值,导致递归层级无法递减,最终还是返回1。阶乘计算逻辑错误:
原代码在递归前修改了栈上的n值为n-1,导致递归返回后乘的是n-1而非原始n,结果会变成(n-1)!而非n!。应保留栈上的原始n值,单独计算n-1作为递归参数。未正确保存非易失性寄存器:
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
相关产品推荐
相关产品推荐

