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

x86-64 GNU汇编移动代码行后寄存器值异常 阶乘计算结果错误

异常原因分析

x86-64 Linux遵循的System V AMD64调用约定明确规定:%rbx、%rbp、%r12~%r15属于被调用者保存寄存器。也就是说如果函数内部需要修改这些寄存器,必须先在栈上备份寄存器的原值,函数返回前再恢复原值,否则会破坏上层调用者存在这些寄存器里的数据。

你当前的factorial函数没有对%rbx做任何备份就直接修改,本身就不符合ABI规范,只是原来把mov 16(%rbp), %rbx放在call factorial之后,修改完%rbx马上就用来做乘法,之后函数直接返回,没有上层逻辑依赖%rbx的原值,才刚好没有触发问题。

当你把这行移到call factorial之前时,执行逻辑变成:

  1. 当前递归层把参数n存入%rbx
  2. 调用下一层的factorial
  3. 下一层factorial执行时也会修改%rbx,且没有备份
  4. 下层执行完毕返回到当前层时,%rbx里之前存的n已经被下层覆盖成了其他值
  5. 最终相乘时用了错误的%rbx值,导致阶乘计算错误。

退出码为16正是计算过程中寄存器值被反复覆盖、最终乘法结果错误导致的。

解决方法

提供两种可直接落地的修复方案:

方案1:遵守ABI规范,备份%rbx寄存器

在factorial函数的栈帧创建逻辑中增加%rbx的备份和恢复步骤,修改后的栈帧操作代码如下:

factorial:
# 创建栈帧,同时备份%rbx
push %rbp
push %rbx
mov %rsp, %rbp

# ...... 原有函数逻辑不变 ......

return_factorial:
mov %rbp, %rsp
pop %rbx # 恢复%rbx原值
pop %rbp
ret

修改后无论mov 16(%rbp), %rbx放在函数内的哪个位置,都不会出现值被异常覆盖的问题。

方案2:消除%rbx的使用,直接用内存参数计算

imul指令支持直接和内存地址中的值相乘,完全不需要用%rbx做中转,可以直接把相关两行代码替换为一行:

# 替换原来的mov 16(%rbp), %rbx和imul %rbx, %rax两行
imul 16(%rbp), %rax

该方案彻底规避了寄存器使用冲突,代码更简洁,执行效率也更高。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 19:48:03