功能序言和结语由GCC优化删除

Bar*_*mar 5 c optimization x86 assembly gcc

采取一个空的程序

//demo.c

int main(void)
{

}
Run Code Online (Sandbox Code Playgroud)

在默认优化时编译程序.

gcc -S  demo.c -o dasm.asm 
Run Code Online (Sandbox Code Playgroud)

我得到汇编输出为

//Removed labels and directive which are not relevant

main:

pushl   %ebp                  // prologue of main
movl    %esp, %ebp            // prologue of main
popl    %ebp                  // epilogue of main
ret
Run Code Online (Sandbox Code Playgroud)

现在在-O2优化时编译程序.

gcc -O2 -S  demo.c -o dasm.asm 
Run Code Online (Sandbox Code Playgroud)

我得到了优化的装配

main:

rep
ret
Run Code Online (Sandbox Code Playgroud)

在我最初的搜索中,我发现优化标志-fomit-frame-pointer负责删除序言和结尾.

我在gcc编译器手册中找到了有关该标志的更多信息.但是,由于手册的原因,我无法理解下面的原因,用于删除序言和结尾.

不要将帧指针保存在寄存器中以查找不需要的函数.

出于上述原因,还有其他方法吗?

"rep"教学的原因是什么,出现在-02优化?

为什么主函数,不需要堆栈帧初始化?

如果没有在主函数内设置帧指针,那么谁来完成这项工作呢?

它是由操作系统完成还是硬件的功能?

小智 5

编译器变得聪明,它知道你不需要存储在寄存器中的堆栈帧指针,因为你放入main()函数的任何东西都不使用堆栈.

至于rep ret:

这是原则.处理器尝试获取要执行的下几条指令,以便它可以开始解码和执行它们的过程.它甚至可以通过跳转和返回指令来做到这一点,猜测程序将在下一步发挥作用.

AMD在这里说的是,如果ret指令紧跟在条件跳转指令之后,它们的预测器就无法确定ret指令的去向.预取必须停止,直到ret实际执行,然后才能再次开始向前看.

"rep ret"技巧显然可以解决问题,并让预测器完成它的工作."rep"对指令没有影响.

来源:一些论坛,谷歌一句话找到它.

有一点需要注意的是,仅仅因为没有序言它并不意味着没有堆栈,你仍然可以轻松地推送和弹出它只是复杂的堆栈操作将是困难的.

没有序言/结语的函数通常被称为裸体.黑客喜欢使用它们,因为当你对它们进行jmp时它们不会污染堆栈,我必须承认我知道在优化之外没有其他用途.在Visual Studio中,它通过以下方式完成:

__declspec(naked)
Run Code Online (Sandbox Code Playgroud)

  • `pause`是`rep nop`,`rep ret`是不同的东西. (4认同)