这与英特尔平台上的BP / EBP / RBP注册有关。该寄存器默认为堆栈段(不需要特殊的前缀即可访问堆栈段)。
EBP是用于访问堆栈中的数据结构,变量和动态分配的工作空间的寄存器的最佳选择。EBP通常用于相对于堆栈上的固定点而不是相对于当前TOS访问堆栈上的元素。它通常标识为当前过程建立的当前堆栈帧的基地址。当在偏移量计算中将EBP用作基址寄存器时,将在当前堆栈段(即SS当前选择的段)中自动计算偏移量。由于不必显式指定SS,因此在这种情况下的指令编码更为有效。EBP也可以用于索引可通过其他段寄存器寻址的段。
(来源-http://css.csail.mit.edu/6.858/2017/readings/i386/s02_03.htm)
由于在大多数32位平台上,数据段和堆栈段是相同的,因此EBP / RBP与堆栈的关联不再是问题。在64位平台上也是如此:AMD在2003年推出的x86-64架构已大大放弃了对64位模式下分段的支持:分段寄存器中的四个:CS,SS,DS和ES被强制设置为0 x86 32位和64位平台的这些情况实质上意味着可以在访问内存的处理器指令中使用EBP / RBP寄存器而没有任何前缀。
因此,您撰写的编译器选项允许BP / EBP / RBP用于其他方式,例如,保存局部变量。
“这避免了保存,设置和还原帧指针的说明”的意思是避免在每个函数的输入项上使用以下代码:
push ebp
mov ebp, esp
或enter
说明,这在Intel 80286和80386处理器上非常有用。
另外,在函数返回之前,将使用以下代码:
mov esp, ebp
pop ebp
或leave
说明。
调试工具可以在定位时扫描堆栈数据并使用这些推入的EBP寄存器数据call sites
,即,以分层调用的顺序显示函数名称和参数。
程序员可能对栈框架的问题不是广义上的(它是栈中的一个实体,仅服务于一个函数调用,并保留返回地址,参数和局部变量),而是一个狭义的问题–当stack frames
在编译器选项的上下文。从编译器的角度来看,堆栈帧只是例程的入口和出口代码,它将锚点压入堆栈-也可以用于调试和异常处理。调试工具可能会扫描堆栈数据,并在定位call sites
到堆栈中时使用这些定位符进行回溯,即以分层调用的顺序显示功能名称。
这就是为什么对于程序员而言,了解编译器选项中的堆栈框架非常重要的原因-因为编译器可以控制是否生成此代码。
在某些情况下,编译器可以省略堆栈帧(例程的进入和退出代码),并且将直接通过堆栈指针(SP / ESP / RSP)而不是便捷的基本指针(BP / ESP / RSP)。编译器忽略某些函数的堆栈框架的条件可能有所不同,例如:(1)该函数是叶函数(即,不调用其他函数的端实体);(2)不使用任何例外;(3)不会在堆栈上使用输出参数调用例程;(4)该函数没有参数。
省略堆栈帧(例程的进入和退出代码)可以使代码更小,更快,但是也可能对调试器回溯堆栈中的数据并将其显示给程序员的能力产生负面影响。这些是编译器选项,这些选项确定函数应满足的条件,以便编译器向其授予堆栈帧入口和出口代码。例如,在以下情况下,编译器可以选择将此类进入和退出代码添加到函数中:(a)始终,(b)从不,(c)需要时(指定条件)。
从一般性回到特殊性:如果您将使用-fomit-frame-pointer
GCC编译器选项,则可能会赢得例程的进入和退出代码,并获得额外的寄存器(除非默认情况下它本身已被打开,或者已被其他隐式打开)选项,在这种情况下,您已经从使用EBP / RBP寄存器的收益中受益,并且通过显式指定此选项(如果已经隐式启用)将不会获得额外的收益)。但是请注意,在16位和32位模式下,BP寄存器无法像AX的(AL和AH)那样访问其8位部分。
由于此选项除了允许编译器在优化中将EBP用作通用寄存器外,还防止了生成堆栈帧的退出和进入代码,这使调试变得复杂-这就是GCC文档明确声明的原因(通常以粗体强调样式),则启用此选项将导致无法在某些计算机上进行调试
另请注意,与调试或优化相关的其他编译器选项可能会隐式打开-fomit-frame-pointer
或关闭该选项。
我没有在gcc.gnu.org上找到任何其他信息如何影响-fomit-frame-pointer
x86平台的官方信息,https://gcc.gnu.org/onlinedocs/gcc-3.4.4/gcc/Optimize-Options.html仅声明以下内容:
-O还会在不干扰调试的机器上打开-fomit-frame-pointer。
因此,从文档本身尚不清楚,-fomit-frame-pointer
如果仅-O
在x86平台上使用单个选项进行编译,是否会打开。可以凭经验进行测试,但是在这种情况下,GCC开发人员没有承诺将来不更改此选项的行为,恕不另行通知。
但是,Peter Cordes在评论中指出-fomit-frame-pointer
x86-16平台和x86-32 / 64平台之间的默认设置有所不同。
此选项---fomit-frame-pointer
也与Intel C ++编译器15.0有关,不仅与GCC有关:
对于Intel编译器,此选项具有别名/Oy
。
这是英特尔写的:
这些选项确定在优化中是否将EBP用作通用寄存器。选项-fomit-frame-pointer和/ Oy允许这种用法。选项-fno-omit-frame-pointer和/ Oy-禁止使用它。
一些调试器期望EBP用作堆栈帧指针,除非如此,否则无法产生堆栈回溯。-fno-omit-frame-pointer和/ Oy-选项指示编译器生成代码,该代码维护并使用EBP作为所有功能的堆栈帧指针,以便调试器仍可以在不执行以下操作的情况下生成堆栈回溯:
对于-fno-omit-frame-pointer:使用-O0关闭优化对于/ Oy-:关闭/ O1,/ O2或/ O3优化-fno-omit-frame-pointer选项在指定选项时设置- O0或-g选项。当您指定选项-O1,-O2或-O3时,将设置-fomit-frame-pointer选项。
指定/ O1,/ O2或/ O3选项时,将设置/ Oy选项。当指定/ Od选项时,将设置选项/ Oy-。
使用-fno-omit-frame-pointer或/ Oy-选项会将可用的通用寄存器的数量减少1,并且可能导致代码效率略低。
注意对于Linux *系统:GCC 3.2异常处理当前存在问题。因此,当为C ++安装了GCC 3.2且打开了异常处理功能时(默认),英特尔编译器将忽略此选项。
请注意,以上引用仅与Intel C ++ 15编译器相关,与GCC不相关。