8

我正在玩弄gcc -S以了解内存和堆栈的工作原理。在这些戏剧中,我发现了一些我不清楚的事情。你能帮我理解原因吗?

  1. 当调用函数为被调用的函数设置参数时,它movesp改为使用push. 不使用有什么好处push

  2. 使用位于堆栈的参数的函数将它们指向为ebp + (N + offset)(其中 N 是为返回地址保留的大小)。我希望看看esp - offset哪个更容易理解。ebp无处不在的作为基点的理由是什么?我知道这些是平等的,但无论如何?

  3. 这个魔法在开头有什么用main?为什么esp必须以这种方式初始化?

    and    esp,0xfffffff0
    

谢谢,

4

1 回答 1

7

我假设您在 32 位环境下工作,因为在 64 位环境中,参数是在寄存器中传递的。

问题 1

也许您在这里传递了一个浮点参数。您不能直接推送这些,因为push32 位运行时中的指令一次推送 4 个字节,因此您必须分解该值。有时更容易从中减去 8,esp然后将 8 字节四字移动到[esp].

问题2

ebp经常用于索引 32 位代码中堆栈帧中的参数和局部变量。即使堆栈指针移动,这也允许固定帧内的偏移量。例如考虑

void f(int x) {
    int a;
    g(x, 5);
}

现在,如果您只使用esp, then ais at访问堆栈帧内容,则[esp]返回地址将是 at[esp+4]并且x将是 at [esp+8]。现在让我们生成代码来调用g. 我们必须先 push 5 然后 push x。但是推 5 之后,xfrom的偏移量发生了esp变化!这就是ebp使用的原因。通常在进入函数时,我们推送旧值ebp来保存它,然后复制espebp. 现在ebp可用于访问堆栈帧内容。当我们在传递参数时它不会移动。

问题 3

and指令将 的最后 4 位清零esp,使其与 16 字节边界对齐。由于堆栈向下增长,这是好的和安全的。

于 2012-06-24T07:24:51.010 回答