【问题标题】:x86 Assembly: Why Do I Need Stack Frames?x86 组装:为什么需要堆栈框架?
【发布时间】:2013-06-18 20:28:11
【问题描述】:

在我看到的大多数 x86 汇编(特别是 NASM)代码示例中(即使是 GCC 生成的代码示例),我看到了所谓的“堆栈框架设置”。像这样:

main: 
        /*setting the stack frame*/
        push    ebp     
        mov     ebp,esp

        ...
        code goes here
        ...

        /*removing the stack frame*/
        mov     esp, ebp
        pop     ebp

我对这种做法有 3 个问题:

  1. 如果我的代码没有触及堆栈,那么如上所述设置/删除堆栈框架是完全没用的,对吧?

  2. 即使我的代码使用堆栈,只要弹出我推送的所有内容(本质上保持堆栈不变)然后再次设置堆栈帧完全没用,对吧?

  3. 在我看来,这样做的唯一目的是保存 ESP 的值,这样我就可以在我的代码中使用它而不必担心搞砸了,一旦我完成了,我只需恢复它原值。这是堆栈框架设置的目的还是我遗漏了什么?

谢谢

【问题讨论】:

  • 如果要调试程序并查看堆栈跟踪,堆栈帧也是必要的。
  • 栈帧并不是真正需要的。如你看到的。在 X86-64 中,我们没有堆栈帧和 ebp 寄存器。所以你是对的,堆栈框架只是为了方便。
  • -fomit-frame-pointer 在 Linux gcc -m32 中默认开启,当启用优化时。 2013 年可能不是这种情况,或者如果您使用的是更旧的编译器,但多年来(2018 年)一直是这种情况。 -fomit-frame-pointer 在 x86-64 模式下一直默认开启。

标签: assembly x86 nasm


【解决方案1】:

你基本上是正确的。

不过,堆栈框架确实有一些好处,即使您不需要固定的堆栈引用来访问参数和局部变量。特别是让它们在那里允许准确的堆栈遍历,以生成用于调试目的的堆栈跟踪。

【讨论】:

    【解决方案2】:

    这是按照惯例完成的。 C 语言函数使用堆栈帧来访问发送给函数的参数,并设置动态局部变量。这就是他们在您正在查看的示例代码中执行此操作的原因。当然,如果你想按照自己的方式做,你可以,但你不能从 C 等调用你的代码。

    编辑:我也很确定有些编译器实现了不同的调用约定来优化它,并且可能根本不创建框架。所以基本上,你是对的。不需要堆栈帧。

    【讨论】:

    • 参数实际上是在当前栈帧底部的负偏移处。
    • 它使用堆栈将参数传递给函数,但如果我没记错的话,它并没有指定使用堆栈帧。事实上,函数调用约定根本不依赖于栈帧。
    • @akonsu 在我看来,您的措辞暗示了这一点,但我的错误。
    • C 中函数内部的代码使用堆栈框架库(我不确定正确的术语是什么)来访问参数并设置局部变量。参数在框架基础之外(负偏移),局部在框架内。这就是我对20年前的记忆。 :)
    • @HunterMcMillen 谢谢。我改变了措辞。组装使用起来很有趣。很长一段时间过去了。我不再使用它了...
    【解决方案3】:

    嗯,事实上,您不需要堆栈帧。

    当您保存寄存器并将局部变量存储在堆栈中时,堆栈帧很方便 - 使编写和调试更容易:您只需将 ebp 设置为堆栈中的固定点并使用 ebp 寻址所有堆栈数据。最后恢复esp更容易。

    此外,调试器通常期望堆栈帧存在,否则您可能会得到不准确的堆栈调用。

    所以,1的答案是肯定的,2和3的答案在上面。

    【讨论】:

      猜你喜欢
      • 2011-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-02
      • 1970-01-01
      • 2015-02-03
      • 2014-07-13
      相关资源
      最近更新 更多