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

zwe*_*nov 8 assembly gcc

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

  1. 当调用函数的参数设置为一个名为一个它使用movesp代替push.没有使用的优势是什么push

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

  3. 这个魔术在一开始是main什么?为什么esp必须以这种方式初始化?

    and    esp,0xfffffff0
    
    Run Code Online (Sandbox Code Playgroud)

谢谢,

Ray*_*oal 7

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

问题1

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

问题2

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

void f(int x) {
    int a;
    g(x, 5);
}
Run Code Online (Sandbox Code Playgroud)

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

问题3

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