Assembly 在没有%rbp寄存器的情况下,堆栈帧的释放是如何进行的?

Assembly 在没有%rbp寄存器的情况下,堆栈帧的释放是如何进行的?,assembly,x86,stack,x86-64,Assembly,X86,Stack,X86 64,我已经读到,使用基址寄存器来跟踪堆栈帧并不是真正必要的。我不明白编译器是如何实现这一点的,它是否将堆栈帧大小存储在某个位置,然后读取并将其添加到%rsp中?这通常也不是必需的,只要您处于以下两种情况之一: rsp仅按已知数量变化 rsp从来没有改变过你可以说这是一个已知的数量,数量是0 通常,在x64代码中,rsp仅在序言、尾声中更改,并在调用/返回时隐式更改。任何临时空间都是预先分配的,并且通常通过索引到堆栈帧中来寻址,除了偏移量是来自rsp而不是基指针-如果rsp没有改变,而不是通过推送和弹

我已经读到,使用基址寄存器来跟踪堆栈帧并不是真正必要的。我不明白编译器是如何实现这一点的,它是否将堆栈帧大小存储在某个位置,然后读取并将其添加到%rsp中?

这通常也不是必需的,只要您处于以下两种情况之一:

rsp仅按已知数量变化 rsp从来没有改变过你可以说这是一个已知的数量,数量是0 通常,在x64代码中,rsp仅在序言、尾声中更改,并在调用/返回时隐式更改。任何临时空间都是预先分配的,并且通常通过索引到堆栈帧中来寻址,除了偏移量是来自rsp而不是基指针-如果rsp没有改变,而不是通过推送和弹出,这不会有任何区别。在这种情况下,很容易恢复旧的rsp,只需添加序言中减去的相同内容

或者,这尤其适用于有红区的linux,对于许多叶函数,您可以不改变rsp而不受影响。在这种情况下,您甚至不需要开场白或尾声,只需要一堆普通代码,后面跟着ret


显然,alloca和其他分配可变堆栈空间的构造打破了这一点,帧指针将再次被使用。

这通常也不是必需的,只要您处于以下两种情况之一:

rsp仅按已知数量变化 rsp从来没有改变过你可以说这是一个已知的数量,数量是0 通常,在x64代码中,rsp仅在序言、尾声中更改,并在调用/返回时隐式更改。任何临时空间都是预先分配的,并且通常通过索引到堆栈帧中来寻址,除了偏移量是来自rsp而不是基指针-如果rsp没有改变,而不是通过推送和弹出,这不会有任何区别。在这种情况下,很容易恢复旧的rsp,只需添加序言中减去的相同内容

或者,这尤其适用于有红区的linux,对于许多叶函数,您可以不改变rsp而不受影响。在这种情况下,您甚至不需要开场白或尾声,只需要一堆普通代码,后面跟着ret


显然,alloca和其他分配可变堆栈空间的结构打破了这一点,帧指针将再次使用。

编译器仍然在包含C99可变长度数组或其他类似内容的函数中使用%rbp生成堆栈帧。当帧大小是编译时常量时,不需要堆栈帧,在这种情况下,它只存储为要添加的立即操作数。查看任何编译器输出,例如on。堆栈帧大小也存储在.eh_frame元数据中,因此异常处理程序和调试器可以展开堆栈。编译器仍然在包含C99可变长度数组或其他类似内容的函数中使用%rbp生成堆栈帧。当帧大小是编译时常量时,不需要堆栈帧,在这种情况下,它只存储为要添加的立即操作数。查看任何编译器输出,例如on。堆栈帧大小也存储在.eh_帧元数据中,因此异常处理程序和调试器可以展开堆栈。