了解if(a> = 3)的gcc输出

Jam*_*mes -2 c x86 assembly gcc

在此输入图像描述

我认为因为条件是> = 3,我们应该使用jl(更少).

但gcc使用jle(少或相等).

这对我没有意义; 为什么编译器会这样做?

Pet*_*des 6

通过编译器在从C源到asm实现的过程中所做的转换,你会感到困惑.gcc的输出以这种方式实现你的功能:

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

ret0:
return 0;
Run Code Online (Sandbox Code Playgroud)

这一切都笨拙和多余的,因为你编译-O0,所以它存储a到内存中,然后重新加载它,所以你可以用一个调试器,如果你设置一个断点,仍然有码"工作"进行修改.

另请参见如何从GCC /铿锵声组件输出中删除"噪音"?


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

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

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

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

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

所以它变成了>=128一个>127比较.这样可以节省3个字节的机器代码,因为cmp $127, %edi可以使用cmp $imm8, r/m32编码(cmp r/m32, imm8英特尔手册中的英特尔语法),但128必须使用cmp $imm32, r/m32.

顺便说一句,比较和条件在英特尔语法中是有意义的,但在AT&T语法中是倒退的.例如, cmp edi, 127/ jg如果edi > 127.

但是在AT&T语法中,它是cmp $127, %edi,所以你必须在心理上扭转操作数或想到一个>而不是<