2 次函数调用期间 EBP 和 ESP 在堆栈中的行为

Behaviour of EBP and ESP in stack during 2 function calls

我正在研究函数调用在 x86 平台上的工作方式。据我了解如下 调用函数时发生的步骤:

  1. 函数的参数和return地址被压入堆栈。

  2. 然后将当前EBP的值压入堆栈。

  3. 现在 ESP 已更改(由于步骤 2),EBP 已替换为 ESP,现在它们是 指向(堆栈?)的相同地址。

  4. 然后局部变量被推送,函数执行它的工作。

  5. 最后弹出这个函数的局部变量和寄存器。在这个 进程ESP也在动吧?

  6. 最后,EBP 被替换为当前 ESP

  7. 的值
  8. 现在 ESP 和 EBP 指向相同的堆栈地址。

所以我的问题如果以上几点都正确,否则请指正,如何 该系统在 2 个函数调用的情况下工作。让我解释一下

  1. 对于第一个函数调用,ebp 被压入堆栈并且 esp 和 ebp 相同。

  2. 现在 esp 递增以创建第一个函数调用的本地堆栈,例如 foo()。

  3. 现在假设有来自 foo() 的第二个函数调用,比如 goo()。

  4. 现在将再次发生相同的过程....当前 ebp 将被推入堆栈

  5. esp 和 ebp 将相同并且 esp 将递增(从技术上讲, 递减 ) 对于 goo() 函数的局部变量。

现在让我们关注函数何时 return。

  1. return 从 goo() 中调用,esp 递增,因为本地寄存器从堆栈中弹出并在 last esp 将被分配位置 ebp 持有的值而不是 current 的值 ebp,对吧?

  2. 然后弹出保存ebp的位置

所以我的问题是,如果是这种情况,现在我们已经丢失了 function foo() 因为ebp和esp指向foo()的ebp,一旦出现就会弹出 foo() returns...

由于实际情况并非如此,我一定遗漏了一些东西。请帮助我...

谢谢。

我假设你在谈论 cdecl (https://en.wikipedia.org/wiki/X86_calling_conventions#cdecl) 调用约定(c 中经常使用的那个)。

%ebp 是基址指针寄存器,它是被调用者保存的,这意味着调用者可以假设被调用者不会修改它的值,因此调用者可以假设 %ebp 将始终引用其堆栈的基址.

%esp是Stack Pointer寄存器,也是callee保存的,但是,由于caller将callee的参数压入stack,%esp是递减的,所以当callee return.我认为这就是您的问题所在,%esp 的值仅增加到足以释放分配的参数,而不是 return 到堆栈的底部。

而 %ebp 和 %esp 实际上指的是堆栈的基址和 'top'。没问题