【问题标题】:Understanding optimized assembly code generated by gcc了解 gcc 生成的优化汇编代码
【发布时间】:2013-09-30 02:37:15
【问题描述】:

我试图了解 gcc 在设置 -O3 标志时执行了哪些优化。我很困惑这两行是什么,

xor %esi, %esi
lea 0x0(%esi), %esi

在我看来这是多余的。在这里使用 lea 指令有什么意义?

【问题讨论】:

  • 您是在查看未链接的 .o 文件的反汇编输出,还是原始 -S 输出?如果是后者,我不知道。如果是前者,那可能是链接器计算偏移量之后的位置。
  • 是编译后的c文件的反汇编输出
  • 啊,在那种情况下,可能是因为链接器在链接时计算了偏移量,结果发现偏移量为 0。我必须查看源代码和/或中间代码 @987654323 @ 输出确定。
  • @torek -S 的程序集输出尚未传递给链接器。 @REALFREE 这后面是一个循环吗?我的猜测是它只是一个用于对齐目的的多字节无操作。
  • 是的,后面跟着循环。所以 %esi 保持不变?

标签: gcc assembly


【解决方案1】:

该指令用于填充空间以进行对齐。当循环从对齐的地址开始时会更快,因为处理器将内存以块的形式加载到解码器中。通过对齐循环和函数的开头,它们更有可能位于这些块之一的开头。这可以防止加载以前不会使用的指令,最大化未来指令的数量,并且可能最重要的是,确保第一条指令完全在第一个块中,因此执行它不需要两次加载.

编译器知道最好对齐循环,并且有两个选项可以这样做。它可以跳转到循环的开头,也可以用无操作来填补空白,让处理器通过它们。跳转指令会破坏指令流,并经常在现代处理器上造成周期浪费,因此不必要地添加它们是不可取的。对于这样的短距离,无操作更好。

x86 架构包含一条专门用于无所事事的指令,nop。但是,这是一个字节长,因此对齐循环需要不止一个字节。解码每个指令并决定它什么都不做需要时间,因此简单地插入另一个没有副作用的更长指令会更快。因此,编译器插入了您看到的lea 指令。它绝对没有任何影响,并且由编译器选择以具有所需的确切长度。事实上,最近的处理器有标准的多字节无操作指令,所以这很可能在解码过程中被识别出来,甚至永远不会被执行。

【讨论】:

    【解决方案2】:

    正如 ughoavgfhw 所解释的 - 这些是用于更好地对齐代码的填充。 您可以在以下链接中找到这个lea -

    http://mail.openjdk.java.net/pipermail/hotspot-compiler-dev/2010-September/003881.html

    引用:

      1-byte: XCHG EAX, EAX
      2-byte: 66 NOP
      3-byte: LEA REG, 0 (REG) (8-bit displacement)
      4-byte: NOP DWORD PTR [EAX + 0] (8-bit displacement)
      5-byte: NOP DWORD PTR [EAX + EAX*1 + 0] (8-bit displacement)
    **6-byte: LEA REG, 0 (REG) (32-bit displacement)**
      7-byte: NOP DWORD PTR [EAX + 0] (32-bit displacement)
      8-byte: NOP DWORD PTR [EAX + EAX*1 + 0] (32-bit displacement)
      9-byte: NOP WORD  PTR [EAX + EAX*1 + 0] (32-bit displacement)
    

    还要注意这个 SO 问题更详细地描述它 - What does NOPL do in x86 system?

    请注意,xor 本身不是 nop(它会更改 reg 的值),但执行起来也很便宜,因为它是一个零习语 - What is the purpose of XORing a register with itself?

    【讨论】:

      猜你喜欢
      • 2014-02-03
      • 1970-01-01
      • 1970-01-01
      • 2017-08-17
      • 2013-06-04
      • 2013-02-20
      • 2013-07-24
      • 2013-10-05
      相关资源
      最近更新 更多