【问题标题】:Why gcc does so when creating assembler code?为什么 gcc 在创建汇编代码时会这样做?
【发布时间】:2012-06-24 06:46:50
【问题描述】:

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

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

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

  3. main开头的这个魔法有什么用?为什么esp只能这样初始化?

    and    esp,0xfffffff0
    

谢谢,

【问题讨论】:

  • 这可能是 3 个独立的问题。无论如何,第三点的答案是堆栈对齐。

标签: gcc assembly


【解决方案1】:

我假设您在 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 字节边界对齐。由于堆栈向下增长,这很好且安全。

【讨论】:

  • Q3:将最后 4 位归零
  • 天哪,谢谢@drhirsch。打字不假思索。糟糕的。非常感谢!已编辑。
猜你喜欢
  • 2012-05-26
  • 2019-02-27
  • 2015-01-14
  • 1970-01-01
  • 1970-01-01
  • 2022-01-20
  • 2015-07-07
  • 2012-09-02
  • 2020-07-12
相关资源
最近更新 更多