【问题标题】:Understanding gcc output for if (a>=3)了解 if (a>=3) 的 gcc 输出
【发布时间】:2017-09-25 18:59:15
【问题描述】:

我想既然条件是 >= 3,我们应该使用jl(更少)。

但是 gcc 使用了jle(小于或等于)。

这对我来说毫无意义;为什么编译器会这样做?

【问题讨论】:

标签: c gcc assembly x86


【解决方案1】:

编译器在从 C 源代码到 asm 实现的过程中进行的转换使您感到困惑。 gcc 的输出以这种方式实现您的功能:

a = 5;
if (a<=2) goto ret0;
return 1;

ret0:
return 0;

由于您使用-O0 编译,这一切都很笨拙和多余,因此它将a 存储到内存中然后重新加载它,因此如果您设置了断点并且仍然有代码“工作”,则可以使用调试器对其进行修改.

另见How to remove "noise" from GCC/clang assembly output?


编译器通常更喜欢减小比较常数的大小,因此它更有可能适合符号扩展的 8 位立即数,而不是机器代码中需要 32 位立即数。

我们可以通过编写一个接受 arg 的函数来获得一些不错的紧凑代码,因此当我们启用优化时它不会被优化掉。

int cmp(int a) { 
    return a>=128;   // In C, a boolean converts to int as 0 or 1
}

gcc -O3 on Godbolt,针对 x86-64 ABI(与您的代码相同):

    xorl    %eax, %eax           # whole RAX = 0
    cmpl    $127, %edi
    setg    %al                  # al = (edi>127) : 1 : 0
    ret

因此它将&gt;=128 转换为&gt;127 比较。这样可以节省 3 个字节的机器码,因为 cmp $127, %edi 可以使用 cmp $imm8, r/m32 编码(cmp r/m32, imm8 in Intel syntax in Intel's manual),但 128 必须使用 cmp $imm32, r/m32

顺便说一句,比较和条件在 Intel 语法中是有意义的,但在 AT&T 语法中是倒退的。例如,如果edi &gt; 127,则采用cmp edi, 127 / jg

但在 AT&T 语法中,它是 cmp $127, %edi,因此您必须在心理上反转操作数或想到 &gt; 而不是 &lt;

【讨论】:

    【解决方案2】:

    汇编代码将a 与两个而不是三个进行比较。这就是它使用jle 的原因。如果 a 小于或等于 2,则逻辑上遵循 IS NOT 大于或等于 3,因此应返回 0

    【讨论】:

      猜你喜欢
      • 2013-02-23
      • 2020-09-03
      • 1970-01-01
      • 2015-07-30
      • 1970-01-01
      • 1970-01-01
      • 2013-12-16
      • 2019-02-13
      相关资源
      最近更新 更多