我无法理解以下代码的工作原理。它是一段简单的代码,它使用递归函数来查找数字的阶乘。在这种情况下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堆栈,并在每个点注册。
答案 0 :(得分:3)
请记住,函数的返回值总是进入%eax
汇编函数通过并调用阶乘,每次递减%eax
并将其推入堆栈。当%eax
为1时,它最终返回。当call factorial
为2时,这将使您返回%eax
递归调用,该调用存储在8(%ebp)
(回想一下它被推送)。所以现在你有2 * 1 = 2 = %eax
。现在它完成并再次返回并重复该过程,直到它返回到首先调用factorial
的函数。