16

问题

以下两个 x86 指令之间的(非平凡)区别是什么?

39 /r    CMP r/m32,r32   Compare r32 with r/m32
3B /r    CMP r32,r/m32   Compare r/m32 with r32

背景

我正在构建一个 Java 汇编器,我的编译器的中间语言将使用它来生成 Windows-32 可执行文件。

目前我有以下代码:

final ModelBase mb = new ModelBase(); // create new memory model
mb.addCode(new Compare(Register.ECX, Register.EAX)); // add code
mb.addCode(new Compare(Register.EAX, Register.ECX)); // add code

final FileOutputStream fos = new FileOutputStream(new File("test.exe"));
mb.writeToFile(fos);
fos.close();

输出一个有效的可执行文件,在一个 TEXT-section 中包含两条 CMP 指令。输出到“text.exe”的可执行文件不会做任何有趣的事情,但这不是重点。该类CompareCMP指令的包装器。

上面的代码产生(用 OllyDbg 检查):

Address   Hex dump                 Command
0040101F  |.  3BC8                 CMP ECX,EAX
00401021  |.  3BC1                 CMP EAX,ECX

区别很微妙:如果我使用39字节操作码:

Address   Hex dump                 Command
0040101F  |.  39C1                 CMP ECX,EAX
00401021  |.  39C8                 CMP EAX,ECX

这让我想知道它们的同义性以及为什么会存在。

4

2 回答 2

21

如果比较两个寄存器,则使用哪个操作码并不重要。唯一的区别是在将寄存器与内存操作数进行比较时,因为使用的操作码决定了从哪个中减去哪个。

至于为什么存在:x86指令格式使用ModR/M字节来表示内存地址或者寄存器。每条指令只能有一个 ModR/M 值,即只能访问一个内存地址(不包括 MOVSB 等特殊指令)。所以这意味着不能有一个通用cmp r/m32, r/m32指令,我们需要两个不同的操作码:cmp r/m32, r32cmp r32, r/m32。作为副作用,这在比较两个寄存器时会产生一些冗余。

于 2010-05-03T20:15:44.553 回答
6

是 x86 的冗余。像这样的案例还有很多。编译器/汇编器可以自由使用任何有效的操作码

一些汇编器允许您选择要发出的操作码。例如在 GAS 上,您可以附加“.s”以使用其他指令编码

10 de   adcb   %bl,%dh
12 f3   adcb.s %bl,%dh
于 2013-11-15T05:32:10.027 回答