为什么gcc在创建汇编代码时会这样做?

时间:2012-06-24 06:46:50

标签: gcc assembly

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

  1. 当调用函数集被调用的参数时,它使用movesp而不是push。不使用push的优势是什么?

  2. 与其堆栈相关的函数将参数指向ebp + (N + offset)(其中N是为返回地址保留的大小)。我希望看到esp - offset更容易理解。将ebp作为基本点到处使用的原因是什么?我知道这些是平等但无论如何?

  3. main一开始有什么神奇之处?为什么必须以这种方式初始化esp

    and    esp,0xfffffff0
    
  4. 谢谢,

1 个答案:

答案 0 :(得分:7)

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

问题1

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

问题2

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

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

现在,如果您只使用esp访问了堆栈框架内容,则a位于[esp],返回地址位于[esp+4]x将在[esp+8]。现在让我们生成调用g的代码。我们必须先推5然后推x。但是在推动5之后,xesp的偏移已经改变了!这就是使用ebp的原因。通常在输入函数时,我们会推送ebp的旧值来保存它,然后将esp复制到ebp。现在ebp可用于访问堆栈帧内容。当我们处于传递论证的中间时,它不会移动。

问题3

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