【发布时间】:2015-07-04 12:02:18
【问题描述】:
在为 gcc 编译器的 -O2 优化运行一些测试时,我在函数的反汇编代码中观察到以下指令:
data32 data32 data32 data32 nopw %cs:0x0(%rax,%rax,1)
这条指令有什么作用?
更详细地说,我试图了解编译器如何通过 O2 优化来优化无用的递归,如下所示:
int foo(void)
{
return foo();
}
int main (void)
{
return foo();
}
上面的代码在没有优化的情况下编译会导致堆栈溢出,但适用于O2优化的代码。
我认为使用 O2 它完全消除了函数 foo 的推送堆栈,但为什么需要 data32 data32 data32 data32 nopw %cs:0x0(%rax,%rax,1)?
0000000000400480 <foo>:
foo():
400480: eb fe jmp 400480 <foo>
400482: 66 66 66 66 66 2e 0f data32 data32 data32 data32 nopw %cs:0x0(%rax,%rax,1)
400489: 1f 84 00 00 00 00 00
0000000000400490 <main>:
main():
400490: eb fe jmp 400490 <main>
【问题讨论】:
-
它似乎不是一条指令,而是(随机?)数据,反汇编程序仍然试图解析这些数据。 (
66是“数据大小”前缀。)顺便说一句,优化用尾部跳转替换了嵌套调用。jmp是函数foo中的唯一代码。 -
@Jongware 我认为管道优化需要它。
-
就是把函数对齐到16个字节。参见例如agner.org/optimize/optimizing_assembly.pdf 中的 代码对齐 部分。作为评论发布,因为有人可能会解释为什么选择这些特定的填充值。至少我猜你会想要一些不会混淆反汇编程序的值,所以也许这就是它的全部。
-
@peterh:等一下……看看
main!似乎最明显的优化是放弃整个函数foo。 (但我仍然觉得数据不是本应执行的代码的一部分。) -
@Jongware 是的,但是尽管
foo需要编译并存在于二进制文件中,因为从C 的角度来看,它没有被声明为static。因此,不能保证有人不想从外部对象调用foo()。我不知道为什么在main()之后没有发生类似的优化 - 也许它发生了,但 OP 没有在这里复制它。
标签: c gcc assembly optimization x86