4

我无法理解以下代码的工作原理。这是一段简单的代码,它使用递归函数来查找数字的阶乘。在这种情况下4*3*2*1 = 24

.section .data
.section .text
.globl _start
._start:

 pushl $4
 call factorial
 addl $4, %esp

 movl %eax, %ebx
 movl $1, %eax
 int $0x80

 .type factorial, @function
 factorial:
 pushl %ebp
 movl %esp, %ebp
 movl 8(%ebp), %eax

 cmpl $1, %eax
 je end_factorial
 decl %eax
 pushl %eax
 call factorial
 movl 8(%ebp), %ebx
 imull %ebx, %eax

 end_factorial:
 movl %ebp, %esp
 popl %ebp
 ret

我了解有关代码的所有内容,但我不明白为什么要执行此部分(第 25/26 行)。

movl 8(%ebp), %ebx
imull %ebx, %eax

我的理解(这显然是错误的)是该函数将继续调用自身,直到值为%eax1。此时它将乘以“4”乘以%eax1。这将给出 4 的值,这对于 4 的阶乘是完全错误的。但是,当我运行它时,它实际上给出了正确的输出 24。我在想每次函数时都应该执行乘法指令执行,而不是在函数完成调用自身之后。

有人可以通过代码向我解释为什么代码实际上给出了 24 的正确答案,而不是我认为它应该给出的答案 (4)。

每次在函数内部调用函数时,ebp 都会推送到堆栈并将更改为 esp。(推 %ebp 移动 %esb,%ebp)。如果是这样,我们如何在函数结束时将 esp,ebp 值恢复为初始值。(据我了解,pop 是在 end_function 中执行的,我们已经多次调用该函数,该函数已将 ebp、return、eax 多次推送到堆栈)。这真的让我的组装逻辑崩溃了。请有人定期解释它,说明堆栈有什么,并在每个点注册。

4

1 回答 1

3

请记住,函数的返回值总是进入%eax

汇编函数通过并调用阶乘,%eax每次减1并将其压入堆栈。什么时候%eax是一,它终于回来了。这将带您回到存储在 2call factorial时的递归调用(回想一下它是被推送的)。所以现在你有 2*1=2= 。现在它完成并再次返回并重复该过程,直到它返回到首先调用的函数。%eax8(%ebp)%eaxfactorial

于 2012-11-06T02:18:27.687 回答