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

X86 2次函数调用期间堆栈中EBP和ESP的行为,x86,return,cpu-registers,calling-convention,X86,Return,Cpu Registers,Calling Convention,我正在学习函数调用在x86平台中的工作原理。据我了解,如下 调用函数时会执行以下步骤: 函数的参数和返回地址被推送到堆栈上 然后将当前EBP的值推送到堆栈上 现在ESP已更改(由于步骤2),EBP将替换为ESP,现在它们已更改 指向(堆栈?)的相同地址 然后局部变量被推送,函数完成它的工作 最后,这个函数的局部变量和寄存器都会被弹出。在这个 过程ESP也在移动,对吗 最后,EBP被替换为当前ESP中保持的值 现在ESP和EBP指向堆栈的相同地址 所以我的问题是,如果以上几点都是正确的,否则请纠正

我正在学习函数调用在x86平台中的工作原理。据我了解,如下 调用函数时会执行以下步骤:

  • 函数的参数和返回地址被推送到堆栈上

  • 然后将当前EBP的值推送到堆栈上

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

  • 然后局部变量被推送,函数完成它的工作

  • 最后,这个函数的局部变量和寄存器都会被弹出。在这个 过程ESP也在移动,对吗

  • 最后,EBP被替换为当前ESP中保持的值

  • 现在ESP和EBP指向堆栈的相同地址

  • 所以我的问题是,如果以上几点都是正确的,否则请纠正我,我会怎么做 此系统在两个函数调用的情况下工作。让我解释一下

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

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

  • 现在让我们假设有来自foo()的第二个函数调用,比如goo()

  • 现在同样的程序将再次发生。。。。当前ebp将被推送到堆栈

  • esp和ebp将相同,esp将增加(技术上, 用于goo()函数的局部变量

  • 现在让我们关注函数何时返回

  • 从goo()返回,esp在本地寄存器从堆栈和 最后一个esp将被分配位置ebp持有的值,而不是当前值 ebp,对吗

  • 然后将弹出保存ebp的位置

  • 所以我的问题是,如果现在是这样的话,我们已经失去了一堆 函数foo(),因为ebp和esp指向foo()的ebp,它将在 foo()返回

    由于实际情况并非如此,我肯定错过了一些东西。请帮帮我


    谢谢。

    我想您是在谈论cdecl()调用约定(c中经常使用的约定)

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

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


    和%ebp和%esp有效地引用堆栈的底部和“顶部”。没问题

    谢谢你的回答,那么你能告诉我什么时候ebp和esp是相等的,ebp是流行的吗。我的意思是当执行返回到main()函数时,它肯定会发生,对吗?但是如果没有涉及到其他函数,如何区分这两种情况呢?%ebp和%esp可以在从子例程返回后在函数中相等,如果您在调用例程中做的第一件事是调用该子例程,则不会发生。例如,如果在调用子例程之前声明了另一个局部变量,则即使从该子例程返回,%esp也不会等于%ebp。。。。当我说它不会发生时,我的意思是只要例程还没有完成它必须做的事情,当它完成时,它就会通过弹出堆栈或增加%esp的值来释放一些局部变量,从而将%esp恢复到进入例程时的值。不,我们不会松开它,因为它被调用方保存了,之前的%esp值,在调用子例程之后也是一样的。子例程可以根据需要修改%esp,但必须在返回之前还原它。@paramvir:另请参阅中的ABI/调用约定链接。让我们来看看。