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

GNU Assembly Language: How to understand the stack pointer in recursive function (factorial calculation)

我尝试通过GAS理解堆栈框架,这里展示了一个递归函数汇编案例,作为[​​=34=]的32位x86程序:

.section .data

.section .text

.globl _start
.globl factorial

_start:
    pushl 
    call factorial
    popl %ebx
    movl %eax, %ebx
    movl , %eax
    int [=10=]x80


.type factorial, @function
factorial:

    pushl %ebp
    movl %esp, %ebp
    movl 8(%ebp), %eax

    cmpl , %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

架构:Ubuntu 18.04 上的 x86-64 和 GCC 7.5。 使用

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

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

参照本例,代码求出 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 和 pop mush 相互匹配。否则内存可能会崩溃。

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

伪代码在 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 所以它 returns 备份调用链

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