我是汇编语言的初学者,并且注意到编译器发出的x86代码即使在释放/优化模式下也可以将EBP
寄存器用于其他用途时,通常也会保持帧指针。
我理解为什么帧指针可能使代码更易于调试,并且如果alloca()
在函数中调用它可能是必需的。但是,x86的寄存器非常少,当其中一个寄存器足够用时,使用其中两个寄存器来保持堆栈帧的位置对我来说是没有意义的。为什么即使在优化/发布版本中也忽略帧指针还是一个坏主意?
alloca
)3 .运行时易于实现:异常处理,沙箱,GC
我是汇编语言的初学者,并且注意到编译器发出的x86代码即使在释放/优化模式下也可以将EBP
寄存器用于其他用途时,通常也会保持帧指针。
我理解为什么帧指针可能使代码更易于调试,并且如果alloca()
在函数中调用它可能是必需的。但是,x86的寄存器非常少,当其中一个寄存器足够用时,使用其中两个寄存器来保持堆栈帧的位置对我来说是没有意义的。为什么即使在优化/发布版本中也忽略帧指针还是一个坏主意?
alloca
)3 .运行时易于实现:异常处理,沙箱,GC
Answers:
帧指针是一个引用指针,它使调试器可以通过单个常量偏移量知道局部变量或参数在何处。尽管ESP的值在执行过程中会发生变化,但是EBP保持不变,因此可以在相同的偏移量处到达相同的变量(例如,第一个参数将始终为EBP + 8,而ESP的偏移量可能会发生显着变化,因为您将按/弹出东西)
为什么编译器不丢弃帧指针?因为有了帧指针,调试器可以确定局部变量和参数在哪里使用符号表,因为可以保证局部变量和参数与EBP保持恒定的偏移量。否则,没有一种简单的方法可以确定局部变量在代码中任何位置的位置。
如Greg所述,由于EBP提供了堆栈帧的反向链接列表,因此它还有助于调试器展开堆栈,因此使调试器可以计算出函数的堆栈帧的大小(局部变量+自变量)。
大多数编译器都提供了省略帧指针的选项,尽管它使调试工作非常困难。即使在发行代码中,也不应在全局范围内使用该选项。您不知道何时需要调试用户的崩溃。
-fomit-frame-pointer
。该设置是最近gcc中的默认设置。
.eh_frame_hdr
部分也用于运行时异常。您会objdump -h
在Linux系统上的大多数二进制文件中找到它(带有),对于Linux,它约为16k /bin/bash
,而对于GNU /bin/true
,它约为572B,对于Linux,它约为108k ffmpeg
。有一个gcc选项可以禁用它的生成,但这是一个“普通”数据部分,而不是strip
默认情况下会删除的调试部分。否则,您将无法通过没有调试符号的库函数回溯。该部分可能比push/mov/pop
它替换的指令大,但运行时成本(例如uop缓存)几乎为零。
只需在已经不错的答案中加上我的两分钱即可。
拥有一堆堆栈框架是好的语言体系结构的一部分。BP指向当前帧,在该帧中存储子例程局部变量。(局部变量为负偏移量,参数为正偏移量。)
阻止完美的寄存器用于优化的想法提出了一个问题:优化在何时何地真正值得?
仅在以下情况的优化循环中值得优化:1)不调用函数; 2)程序计数器花费其大部分时间,以及3)编译器实际会看到的代码(即非库函数)。这通常只占整体代码的一小部分,尤其是在大型系统中。
可以扭曲和压缩其他代码以摆脱循环,这根本没有关系,因为程序计数器实际上从不存在。
我知道您没有问这个问题,但是根据我的经验,99%的性能问题与编译器优化完全无关。他们与过度设计有关。
当然,这取决于编译器。我已经看到x86编译器发出的优化代码,它们自由地将EBP寄存器用作通用寄存器。(不过,我不记得使用哪个编译器了。)
编译器还可以选择维护EBP寄存器,以帮助在异常处理期间展开堆栈,但这再次取决于精确的编译器实现。
-fomit-frame-pointer
为启用优化时。(在ABI允许的情况下)。即使针对32位Windows,GCC,clang,ICC和MSVC都可以执行IIRC。是的,我的回答是:为什么使用ebp比使用esp寄存器更好地在堆栈上定位参数?表明即使32位Windows也可以省略帧指针。32位x86 Linux绝对可以并且可以做到。当然,64位ABI从一开始就允许省略帧指针。
但是,x86的寄存器很少
这仅在操作码只能寻址8个寄存器的意义上是正确的。处理器本身实际上将拥有更多的寄存器,并使用寄存器重命名,流水线,推测性执行和其他处理器流行语来绕过该限制。Wikipedia很好地介绍了x86处理器可以克服寄存器限制的方法:http : //en.wikipedia.org/wiki/X86#Current_implementations。
在任何硬件中,即使是远程的现代设备,使用堆栈框架都变得非常便宜。如果您有便宜的堆栈帧,那么保存几个寄存器就没有那么重要了。我敢肯定,快速堆栈帧与更多寄存器是一个工程上的权衡,并且可以快速堆栈帧获胜。
您要存多少钱去纯寄存器?这值得么?