为什么 cmp 指令中的参数顺序很重要?

Jim*_*Suh 1 x86 assembly att

我想知道为什么cmp指令需要一定的参数顺序条件。

例如,我已经尝试了这两种方法。

  1. cmpl %eax, $'A'
  2. cmpl $'A', %eax

第一行返回错误,表示操作数类型不匹配。第二行工作得很好。

我浏览了 Intel IA-32 手册,但它无法回答我的问题。它只是说参数 1 和参数 2 之间的减法,而不是每个参数应该具有的类型。

我想知道为什么第一行代码返回的操作数类型不匹配,而第二行却没有。

Pet*_*des 5

机器代码指令仅支持立即数的方向。如果你没有找到这个,那么你找错了地方。Intel 的 vol.2 手册详细介绍了每条指令的每个可用编码。 这是 .html 条目的 HTML 摘录cmp


请记住,程序集限制不是任意的源代码级别选择;它不是像 C++ 这样的语言,它是一种描述机器代码的方式。

大多数 ALU 指令都会写入它们的目的地(尤其是可以追溯到原始 8086 的指令),因此它不能是立即的。例如sub %eax, $123显然没有意义。 因此,机器代码格式的一致性/易于解码是没有具有cmp直接“目标”的特殊操作码的原因之一。 如果汇编程序将该操作码映射到相同的cmp助记符而不是不同的 reverse-cmp 助记符,则汇编语法也是不规则的。

相比之下,cmp r/m32, r32cmp r32, r/m32同时存在,这样你可以比较内存在任一方向的寄存器。同样,这与其他 ALU 指令(如add和 )的模式一致sub,因此这对于机器代码中更“常规”的解码/模式也很有意义。

如果您对结果进行分支,jcc您可以随时交换操作数并使用相反的条件。有时您希望 CF 设置某种方式来馈送adcsbb,所以是的,有时这会带来不便。

但这并不足以让 8086 指令集的架构师 Stephen Morse 使用少数未使用的操作码之一与cmp.


可能有意义的是像 ARM 那样的反向减法或反向比较指令(即dst = src - dst而不是dst -= src),但 x86 的可变长度机器代码格式意味着只有这么多的 1 字节操作码。那可能只是一个“正常”的立即 ALU 指令。

或者实际上还有 5 个操作码,如果我们遵循正常 ALU 指令的模式,则包括 2 个专用字节: normal op r/m8, imm8, op r/m16, sign_extended_imm8,op r/m16, imm16和 AL,imm8 和 AX,imm16 短格式(没有 ModRM 字节)。我猜对于非立即操作数,助记符可能是cmp操作数反转的别名,所以我们也不需要这 4 个操作码(双向 8 位和 16 位)。

ARM 后来出现并使用了固定宽度的 32 位指令字,因此有相当多的操作码编码空间可用于诸如反向比较和反向减法之类的有用指令。