为什么 cmp 指令中的参数顺序很重要?
Why is order of arguments in cmp instruction important?
我想知道为什么 cmp
指令需要特定的参数顺序条件。
比如这两个我都试过了
cmpl %eax, $'A'
cmpl $'A', %eax
第一行返回错误,说操作数类型不匹配。
二线运作良好。
我查看了 Intel IA-32 手册,但它无法回答我的问题。它只是说参数1和2之间的减法,而不是每个参数应该有什么类型。
我想知道为什么第一行代码返回操作数类型不匹配,而第二行没有。
machine-code指令只支持带立即数的方向。如果你没有找到这个,那你找错地方了。 Intel 的第 2 卷手册详细说明了每条指令的每种可用编码。 Here's an HTML extract of the entry for cmp
.
请记住,装配限制不是任意 source-level 选择;它不是像 C++ 这样的语言,它是一种描述机器代码的方式。
大多数 ALU 指令写入它们的目的地(尤其是可追溯到原始 8086 的指令),因此它不能是立即数。例如sub %eax, 3
显然没有意义。 因此 machine-code 格式的一致性/易于解码是没有具有立即 "destination" 的特殊 cmp
操作码的原因之一。 这也是汇编语法不规则,如果汇编程序将该操作码映射到相同的 cmp
助记符而不是不同的 reverse-cmp 助记符。
相比之下,cmp r/m32, r32
和 cmp r32, r/m32
都存在,因此您可以将内存与任一方向的寄存器进行比较。同样,这与 add
和 sub
等其他 ALU 指令的模式一致,因此这对于机器代码中的更多 "regular" 解码/模式也有意义。
如果您使用 jcc
对结果进行分支,您始终可以交换操作数并使用相反的条件。不过,有时您希望 CF 设置某种方式来提供 adc
或 sbb
,所以是的,这偶尔会带来不便。
但这并不足以让 8086 指令集的架构师 Stephen Morse 将少数未使用的操作码之一用于 reverse-compare 并立即编码 cmp
。
有意义的是 reverse-subtract 或 reverse-compare 指令,例如 ARM 具有 (即 dst = src - dst
而不是 dst -= src
), 但 x86 的 variable-length machine-code 格式意味着只有这么多的 1 字节操作码。那可能只是一条 "normal" 立即 ALU 指令。
或者实际上还有 5 个操作码,如果我们遵循普通 ALU 指令的模式,包括 2 个专用字节:普通 op r/m8, imm8
、op r/m16, sign_extended_imm8
、op r/m16, imm16
和 AL、imm8 和 AX ,imm16 短格式(没有 ModRM 字节)。我想对于 non-immediate 操作数,助记符可能是 cmp
的别名,操作数颠倒了,所以我们也不需要这 4 个操作码(双向 8 位和 16 位)。
ARM 后来出现并使用 fixed-width 32 位指令字,因此有相当多的操作码编码 space 可用于有用的指令,例如 reverse-compare 和 reverse-subtract.
我想知道为什么 cmp
指令需要特定的参数顺序条件。
比如这两个我都试过了
cmpl %eax, $'A'
cmpl $'A', %eax
第一行返回错误,说操作数类型不匹配。 二线运作良好。
我查看了 Intel IA-32 手册,但它无法回答我的问题。它只是说参数1和2之间的减法,而不是每个参数应该有什么类型。
我想知道为什么第一行代码返回操作数类型不匹配,而第二行没有。
machine-code指令只支持带立即数的方向。如果你没有找到这个,那你找错地方了。 Intel 的第 2 卷手册详细说明了每条指令的每种可用编码。 Here's an HTML extract of the entry for cmp
.
请记住,装配限制不是任意 source-level 选择;它不是像 C++ 这样的语言,它是一种描述机器代码的方式。
大多数 ALU 指令写入它们的目的地(尤其是可追溯到原始 8086 的指令),因此它不能是立即数。例如sub %eax, 3
显然没有意义。 因此 machine-code 格式的一致性/易于解码是没有具有立即 "destination" 的特殊 cmp
操作码的原因之一。 这也是汇编语法不规则,如果汇编程序将该操作码映射到相同的 cmp
助记符而不是不同的 reverse-cmp 助记符。
相比之下,cmp r/m32, r32
和 cmp r32, r/m32
都存在,因此您可以将内存与任一方向的寄存器进行比较。同样,这与 add
和 sub
等其他 ALU 指令的模式一致,因此这对于机器代码中的更多 "regular" 解码/模式也有意义。
如果您使用 jcc
对结果进行分支,您始终可以交换操作数并使用相反的条件。不过,有时您希望 CF 设置某种方式来提供 adc
或 sbb
,所以是的,这偶尔会带来不便。
但这并不足以让 8086 指令集的架构师 Stephen Morse 将少数未使用的操作码之一用于 reverse-compare 并立即编码 cmp
。
有意义的是 reverse-subtract 或 reverse-compare 指令,例如 ARM 具有 (即 dst = src - dst
而不是 dst -= src
), 但 x86 的 variable-length machine-code 格式意味着只有这么多的 1 字节操作码。那可能只是一条 "normal" 立即 ALU 指令。
或者实际上还有 5 个操作码,如果我们遵循普通 ALU 指令的模式,包括 2 个专用字节:普通 op r/m8, imm8
、op r/m16, sign_extended_imm8
、op r/m16, imm16
和 AL、imm8 和 AX ,imm16 短格式(没有 ModRM 字节)。我想对于 non-immediate 操作数,助记符可能是 cmp
的别名,操作数颠倒了,所以我们也不需要这 4 个操作码(双向 8 位和 16 位)。
ARM 后来出现并使用 fixed-width 32 位指令字,因此有相当多的操作码编码 space 可用于有用的指令,例如 reverse-compare 和 reverse-subtract.