我正在查看函数调用在x86平台中的工作方式。据我了解以下情况 调用函数时会发生以下步骤:
将函数的参数和返回地址压入堆栈。
然后将当前EBP的值压入堆栈。
现在ESP已经改变了(由于步骤2),EBP被替换为ESP,现在它们已经改变了 指向(Stack?)的相同地址。
然后推送局部变量,功能就可以了。
最后,该函数的局部变量是有效的,寄存器也是如此。在这 过程ESP也在移动,对吗?
最后,EBP被当前ESP保留的价值取代
现在ESP和EBP指向堆栈的相同地址。
所以我的问题如果以上所有要点都是正确的,否则请纠正我,将如何 这个系统在2个函数调用的情况下工作。让我解释一下
对于第一个函数调用,ebp被推送到堆栈,esp和ebp被设为相同。
现在esp增加以创建第一个函数调用的本地堆栈,比如foo()。
现在假设有一个来自foo()的第二个函数调用,比如说goo()。
现在再次执行相同的程序....当前的ebp将被推送到堆栈
esp和ebp将相同,esp将增加(技术上, 对于goo()函数的局部变量,递减)。
现在让我们关注函数何时返回。
从goo()返回,esp递增,因为本地寄存器从堆栈中取出并且在 last esp将被赋予ebp所持有的值而不是current的值 ebp,对吧?
然后将持有ebp的位置。
所以我的问题是,如果是这种情况,我们现在已经失去了筹码的开始 函数foo(),因为ebp和esp指向foo()的ebp,它将尽快加速 foo()返回...
由于这不是实际发生的事情,我必须遗漏一些东西。请帮帮我......
感谢。
答案 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有效地指代基数和顶部'堆栈。没问题