Assembly x86程序集:为什么需要堆栈帧?

Assembly x86程序集:为什么需要堆栈帧?,assembly,x86,nasm,Assembly,X86,Nasm,在我看到的大多数x86程序集(尤其是NASM)代码示例(甚至是GCC生成的代码示例)上,我看到了所谓的“堆栈框架设置”。像这样: main: /*setting the stack frame*/ push ebp mov ebp,esp ... code goes here ... /*removing the stack frame*/

在我看到的大多数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个问题:

  • 如果我的代码没有触及堆栈,那么如上所述设置/删除堆栈帧是完全无用的,对吗

  • 即使我的代码使用堆栈,只要弹出我推送的所有内容(保持堆栈的本质不变),那么再次设置堆栈帧是完全无用的,对吗

  • 在我看来,这样做的唯一目的是保存ESP的价值,这样我就可以在我的代码中使用它,而不用担心把事情弄糟,一旦我完成了,我就可以恢复它的原始价值。这是堆栈帧设置的目的还是我遗漏了什么


  • 谢谢

    你基本上是对的


    不过,堆栈帧确实有某些好处,即使您不需要固定的堆栈引用来访问参数和局部变量。特别是在那里使用它们可以精确地遍历堆栈,以便生成用于调试目的的堆栈跟踪。

    这是按照约定完成的。C语言函数使用堆栈帧访问发送给函数的参数,并设置动态局部变量。这就是为什么他们会在您正在查看的示例代码中这样做。当然,如果您想按自己的方式执行,您可以,但您将无法从C等调用代码


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

    事实上,您不需要堆栈帧

    当您在堆栈中保存寄存器和存储局部变量时,堆栈帧非常方便—以简化编写和调试:您只需将
    ebp
    设置为堆栈中的一个固定点,并使用
    ebp
    对所有堆栈数据进行寻址。而且更容易在最后恢复
    esp

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


    因此,1的答案是肯定的,2和3的答案在上面。

    如果要调试程序并查看堆栈跟踪,堆栈帧也是必需的。堆栈帧实际上不需要。如你所见。在X86-64中,我们没有堆栈帧和ebp寄存器。所以您是对的,堆栈帧只是为了方便使用。
    -fomit frame pointer
    在Linux
    gcc-m32
    中启用优化时默认为打开。2013年可能不是这样,或者如果您使用的是更旧的编译器,但多年来(2018年)都是这样<代码>-默认情况下,x86-64模式下,fomit帧指针始终处于打开状态。参数实际上与当前堆栈帧的底部成负偏移。它使用堆栈将参数传递给函数,但如果我没有记错,它不会指定使用堆栈帧。实际上,函数调用约定根本不依赖于堆栈帧。@akonsu在我看来,您的措辞暗示了这一点,但我错了。C中函数内部的代码使用堆栈帧基(我不确定正确的术语是什么)来访问参数和设置局部变量。参数位于帧基准(负偏移)之外,局部区域位于帧内部。这就是我20年前的记忆@谢谢你。我改变了措辞。组装是非常有趣的使用。很长时间过去了。我不再使用它了。。。