为什么这个组件会产生24而不是4?

时间:2012-11-06 02:08:52

标签: function assembly recursion gnu

我无法理解以下代码的工作原理。它是一段简单的代码,它使用递归函数来查找数字的阶乘。在这种情况下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

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

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

每次在函数内部调用函数时,ebp都会推送到堆栈并更改为esp。 (pushl%ebp                                            Movl%esb,%ebp)。如果是这样,我们如何将esp,ebp值恢复到函数末尾的初始值。 (据我所知pop是在end_function中执行的,我们已经多次调用了函数,它已经将ebp,return,eax打上了几次)。这真令人困惑,我的装配逻辑正在崩溃。请一些人解释一下它是什么样的halons堆栈,并在每个点注册。

1 个答案:

答案 0 :(得分:3)

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

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