采取空程序
//demo.c
int main(void)
{
}
在默认优化时编译程序。
gcc -S demo.c -o dasm.asm
我得到汇编输出为
//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
现在在-O2优化时编译程序。
gcc -O2 -S demo.c -o dasm.asm
我得到了优化的程序集
main:
rep
ret
在我最初的搜索中,我发现优化标志 -fomit-frame-pointer 负责删除序言和结尾。
我在gcc compiler manual中找到了有关该旗帜的更多信息。但是在手册中给出的删除序言和结语的情况下,我无法理解以下这个原因。
不要将帧指针保留在寄存器中以查找不能执行的功能 需要一个。
出于上述原因,还有其他方法吗?
"rep"
指令出现在-02优化的原因是什么?
为什么main函数不需要堆栈帧初始化?
如果没有在主函数内设置帧指针,那么谁来做这个工作?
是由操作系统完成的还是硬件的功能?
答案 0 :(得分:5)
编译器越来越聪明,它知道你不需要存储在寄存器中的堆栈帧指针,因为你放入main()函数的任何东西都没有使用堆栈。
至于rep ret:
这是原则。处理器尝试获取接下来的几个 要执行的指令,以便它可以启动进程 解码并执行它们。它甚至可以通过跳跃和返回来实现 说明,猜测程序下一步的位置。
AMD在这里说的是,如果一个ret指令紧随其后 条件跳转指令,他们的预测器无法弄清楚在哪里 ret指令正在进行中。预取必须停止,直到 ret实际执行,只有这样它才能开始寻找 再次前进。
“rep ret”技巧显然可以解决这个问题,并且可以解决问题 预测者做好自己的工作。 “rep”对指令没有影响。
来源:一些论坛,谷歌一句话找到它。
有一点需要注意的是,仅仅因为没有序言它并不意味着没有堆栈,你仍然可以轻松推送和弹出它只是复杂的堆栈操作将是困难的。
没有序言/结语的功能通常被称为裸体。黑客喜欢使用它们,因为当你对它们进行jmp时它们不会污染堆栈,我必须承认我知道在优化之外没有其他用途。在Visual Studio中,它通过以下方式完成:
__declspec(naked)