【发布时间】:2017-09-25 18:59:15
【问题描述】:
【问题讨论】:
-
汇编代码与
2比较,而不是C 代码中的3。所以它是jle而不是jl。 -
请编辑您的问题以将代码和 asm 包含为文本,而不是文本图像。
-
跳转是为了到达 else 部分,所以它不是你为 if 部分写的条件。
【问题讨论】:
2 比较,而不是C 代码中的3。所以它是jle 而不是jl。
编译器在从 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
因此它将>=128 转换为>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 > 127,则采用cmp edi, 127 / jg。
但在 AT&T 语法中,它是 cmp $127, %edi,因此您必须在心理上反转操作数或想到 > 而不是 <
【讨论】:
汇编代码将a 与两个而不是三个进行比较。这就是它使用jle 的原因。如果 a 小于或等于 2,则逻辑上遵循 IS NOT 大于或等于 3,因此应返回 0。
【讨论】: