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

时间:2016-08-11 09:43:57

标签: x86 return cpu-registers calling-convention

我正在查看函数调用在x86平台中的工作方式。据我了解以下情况 调用函数时会发生以下步骤:

  1. 将函数的参数和返回地址压入堆栈。

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

  3. 现在ESP已经改变了(由于步骤2),EBP被替换为ESP,现在它们已经改变了 指向(Stack?)的相同地址。

  4. 然后推送局部变量,功能就可以了。

  5. 最后,该函数的局部变量是有效的,寄存器也是如此。在这 过程ESP也在移动,对吗?

  6. 最后,EBP被当前ESP保留的价值取代

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

  8. 所以我的问题如果以上所有要点都是正确的,否则请纠正我,将如何 这个系统在2个函数调用的情况下工作。让我解释一下

    1. 对于第一个函数调用,ebp被推送到堆栈,esp和ebp被设为相同。

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

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

    4. 现在再次执行相同的程序....当前的ebp将被推送到堆栈

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

    6. 现在让我们关注函数何时返回。

      1. 从goo()返回,esp递增,因为本地寄存器从堆栈中取出并且在 last esp将被赋予ebp所持有的值而不是current的值 ebp,对吧?

      2. 然后将持有ebp的位置。

      3. 所以我的问题是,如果是这种情况,我们现在已经失去了筹码的开始 函数foo(),因为ebp和esp指向foo()的ebp,它将尽快加速 foo()返回...

        由于这不是实际发生的事情,我必须遗漏一些东西。请帮帮我......

        感谢。

1 个答案:

答案 0 :(得分:2)

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

%ebp是Base Pointer寄存器,它被callee保存,这意味着调用者可以假定被调用者不会修改其值,因此调用者可以假设%ebp将始终引用其堆栈的基数。 / p>

%esp是堆栈指针寄存器,它也被callee保存,但是,由于调用者在堆栈上推送了被调用者的参数,因此%esp递减,因此当被调用者返回时需要递增。而且我认为这是你的问题潜伏的地方,%esp的值只会增加到足以释放分配的参数,而不是返回到堆栈的基础。

%ebp和%esp有效地指代基数和顶部'堆栈。没问题