2012-11-06 47 views
4

我无法理解下面的代码如何工作。这是一段简单的代码,它使用递归函数来查找数字的阶乘。在这种情况下,4*3*2*1 = 24为什么此组件产量为24而不是4?

.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。在这一点上它将乘以%eax这是一个“4”。这将给出4的值,这对于4的阶乘是完全错误的。然而,当我运行这个时,它确实提供了24的正确输出。我认为每次函数都应该执行乘法指令执行,而不是在函数完成调用之后。

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

而且每次在函数内部调用该函数时,ebp都会被压入堆栈,并且会被更改为esp。 (pushl%ebp Movl%esb,%ebp)。如果是的话,我们如何才能将esp,ebp值恢复到函数末尾的初始值。 (据我所知,pop在end_function中是做的,我们已经多次调用了这个函数,这已经推动了ebp,return,eax等几次堆栈)。这真是令人困惑,我的组装逻辑崩溃了。请有人解释一下它是什么意思,并说明什么是堆栈,并在每个点上注册。

+0

你应该学会使用调试器。这些将允许您逐步浏览代码并观察发生的情况,并通过指令进行指导。从大多数代码中剔除它。 –

回答

3

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

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

相关问题