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

x86 Intel汇编中递归的工作原理及示例代码疑问解析

Intel汇编递归求和代码详解

先看这段实现数字各位之和递归计算的Intel汇编代码:

.intel_syntax noprefix
.data
.text
.global sum

sum:
    enter 0, 0

    mov esi, 0        # result = 0
    cmp edi, 0        # if n == 0, return 0
    je end

    mov eax, edi      # preparing for division
    mov edx, 0
    mov ecx, 10
    div ecx           # eax = n / 10, edx = n % 10


    push rdx          # save the current digit (n % 10)

    mov edi, eax      # I don't understand this line at all, why are we moving eax back to edi?
    call sum          # recursive call - result in eax

    pop rdx           # get n % 10 back from stack
    add eax, edx      # result = sum(n / 10) + (n % 10)

end:
    leave
    ret

下面逐个解答你的疑问:

1. 为什么要把eax的值移回edi?

x86-64 System V调用约定里,第一个整数参数通过edi传递。当前函数的输入参数n存在edi中,执行div ecx后,eax存储的是n/10——这正是递归调用sum时需要传入的参数。把eax的值放到edi,就是为下一次递归调用准备好输入参数。

2. call sum具体执行了什么?会自动push/pop rax吗?

call指令做两件事:

  • 把当前指令的下一条指令地址(也就是pop rdx的地址)压入栈,作为递归返回后要执行的位置
  • 跳转到sum函数的入口开始执行

它不会自动push或pop rax,寄存器的内容需要你手动管理。当递归调用完成后,ret指令会把栈里保存的返回地址弹出,跳回原来的位置继续执行。

3. 为什么pop rdx后要和eax相加?

递归调用sum(n/10)的返回结果存在eax里,而之前push rdx保存的是当前数字的个位(n%10)。弹出rdx后加到eax上,正好对应递归公式:
sum(n) = sum(n/10) + (n%10)
这就是计算各位数字之和的核心逻辑。

4. mov esi, 0没被使用却每次都设置,意义何在?

这行代码是冗余的——整个函数里从来没用到过esi的值,大概率是写代码时的残留(比如原本打算用esi存结果,后来改成用eax返回),完全可以删掉,不会影响函数功能。

额外补充:递归的栈工作逻辑

每次递归调用前,我们把当前的个位数字压栈保存;当递归到n=0时触发je end,开始逐层返回:

  • 每次返回时弹出之前保存的个位数字,加到当前eax的结果上
  • 直到最外层调用完成,eax里就是最终的各位数字之和

内容的提问来源于stack exchange,提问作者Danilo Jonić

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 03:42:39