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

时间:2019-05-19 07:34:57

标签: assembly x86 att

我想知道为什么cmp指令要求参数顺序必须满足某些条件。

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

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

第一行返回错误,指出操作数类型不匹配。 二线效果很好。

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

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

1 个答案:

答案 0 :(得分:3)

机器码指令仅支持立即指令。如果找不到,则说明您在错误的位置。英特尔第2卷手册详细介绍了每条指令的每种可用编码。 Here's an HTML extract of the entry for cmp


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

大多数ALU指令都会写出其目的地(尤其是可追溯至原始8086的指令),因此它不能是立即执行的。例如sub %eax, $123显然没有任何意义。 因此,机器代码格式的一致性/易于解码是没有特殊的cmp操作码带有立即“目的地”的原因之一。如果汇编器使用汇编语法,这也是不规则的将该操作码映射到相同的cmp助记符,而不是其他的反向cmp助记符。

通过对比,cmp r/m32, r32cmp r32, r/m32都存在,因此您可以在任一方向上将内存与寄存器进行比较。同样,这与其他addsub这样的ALU指令的模式是一致的,因此对于机器代码中更多的“常规”解码/模式也很有意义。

如果要使用jcc分支结果,则可以始终交换操作数并使用相反的条件。有时候,您可能希望CF设置某种方式来填充adcsbb,所以是的,这有时会带来不便。

但这并不是8086指令集的设计者Stephen Morse充分理由使用少数几个未使用的操作码之一进行反向比较并立即编码cmp的充分理由。


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

或者实际上还有5个操作码,如果遵循普通ALU指令的模式,则包括2个专用字节:普通op r/m8, imm8op r/m16, sign_extended_imm8op r/m16, imm16以及AL,imm8和AX,imm16简短形式(无ModRM字节)。我猜对于非立即操作数,助记符可以是cmp的别名,而操作数则相反,因此我们也不需要这4个操作码(双向8位和16位)。

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