GNU汇编语言:如何理解递归函数中的堆栈指针(阶乘计算)



我试图通过GAS来理解堆栈框架,这里显示了一个递归函数汇编案例,作为Linux的32位x86程序:

.section .data
.section .text
.globl _start
.globl factorial
_start:
pushl $3
call factorial
popl %ebx
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
popl %ebx
incl %ebx
imul %ebx, %eax
end_factorial:
movl %ebp, %esp
popl %ebp
ret

架构:x86-64在Ubuntu 18.04与GCC 7.5。使用构建

as -o test.o powertest.s --32
ld -o test test.o -m elf_i386

我发现了一些与我的问题相关的类似问题,但我仍然停留在堆栈指针移动或弹出/推回上。

参考这种情况,代码会找到3的阶乘。据我所知,伪代码应该是:

PUSH 3 -> PUSH RET -> PUSH EBP -> PUSH 2 -> PUSH RET -> PUSH EBP -> 
PUSH 1 -> POP EBP -> POP RET -> POP EBX ->POP EBP -> (Stuck here)

当EAX迭代为1时,会弹出内部EBP和RET。

然后,在函数(EAX==3(中,应该弹出POP EBX。

然而,根据上面的伪代码,我认为也许应该弹出EBP。

代码真的得到了正确的结果,这让我很困惑。

我读过一些参考资料,他们说推和弹出的糊状物相互匹配。否则,内存可能会崩溃。

我的问题是,这种情况下的堆栈组件是如何弹出的?

伪代码在PUSH 1:之后缺少PUSH RET -> PUSH EBP

PUSH 3 -> PUSH RET ->
PUSH EBP -> PUSH 2 -> PUSH RET ->
PUSH EBP -> PUSH 1 -> PUSH RET ->
PUSH EBP 

此时eax==1,因此返回呼叫链

POP EBP ->
POP RET -> POP EBX -> POP EBP ->
POP RET -> POP EBX -> POP EBP ->
POP RET -> POP EBX

最新更新