从这个站点:http : //eli.thegreenplace.net/2011/02/04/where-the-top-of-the-stack-is-on-x86/ 我看到这个程序堆栈:
int foobar(int a, int b, int c)
{
int xx = a + 2;
int yy = b + 3;
int zz = c + 4;
int sum = xx + yy + zz;
return xx * yy * zz + sum;
}
int main()
{
return foobar(77, 88, 99);
}
Run Code Online (Sandbox Code Playgroud)
在内存中如下图所示:
我不明白为什么基指针从堆栈中获取内存,难道它不能像堆栈指针一样存储在寄存器中,只是指向他需要的地方吗?(我知道当堆栈指针进行推送和弹出时,基指针用于更容易地查找变量,但我不明白为什么它的值存储在堆栈中,而不仅仅是在寄存器中!),非常感谢您的帮助(恐怕我遗漏了一些非常重要的东西)
编辑:这可能更有助于我的困惑:在图像中,它们显示“EBP”(寄存器)和“保存的 ebp”。我不明白为什么有两个...
首先,您应该意识到这种风格的堆栈框架不再是真正必要的。大多数当前的编译器可以(并且确实)消除在堆栈上保存 [E]BP,并在函数入口处将 [E]SP 复制到 [E]BP。有一次(16 位代码)这是需要的,因为 BP 可以充当基址寄存器,但 SP 不能。这意味着你不能做类似的事情-7[SP],但你可以做-7[BP]。然而,从 386 位和 32 位代码开始,情况不再如此——您可以使用 ESP(或任何其他寄存器)作为基址寄存器。
尽管如此,仍然有一些理由在进入过程/函数时保存 EBP:除非堆栈被破坏,否则它真的很容易走。EBP 指向 EBP 的前一个值,该值指向前一个值,依此类推,一直到堆栈。如果您正在调试(例如),这使得进行堆栈跟踪变得非常容易。如果您必须浏览一些没有符号的代码,您可以浏览它们,找到您理解的早期堆栈帧,并详细检查它们。
相比之下,如果您直接使用 ESP,它会在进入函数时进行调整,以便为该函数的局部变量腾出空间。您需要知道它被调整了多少才能返回到前一个堆栈帧。如果您到了一个没有任何信息的点,并且您不知道在进入该函数时调整了多少 ESP,那么您就陷入了困境(没有反汇编代码以找到堆栈调整,因此您可以取消它)。