x86 XOR 操作码差异

x86 XOR opcode differences

查看 http://ref.x86asm.net/coder32.html 我发现了两个与语句

匹配的操作码

xor eax,eax

1) 操作码 31 异或 r/m16/32 r16/32

2) 操作码 33 异或 r16/32 r/m16/32

operand1和operand2均指32位寄存器。那么,在对两个 32 位寄存器进行 XORing 的这种特定情况下有什么不同吗?

x86 有 2 种冗余方式来编码任何基本 ALU 指令(可追溯到 8086)的 2 寄存器实例,使用 r/m 源和 r/m 目标形式。

这种 reg,reg 编码的冗余是 x86 机器代码如何允许大多数指令的内存目标或内存源的结果:而不是花费 ModR/M 字节中的位来具有两个操作数的灵活编码,大多数指令只有两个单独的操作码。

(这就是为什么任何指令都不允许使用两个显式内存操作数,如 xor [eax], [ecx] 其中一个或两个内存操作数是隐式的,如 rep movspush [mem] 允许两个内存操作数,绝不允许一条指令具有两个独立的 ModR/M 编码寻址模式。)


编码有模式

请注意 3133 对于 word/dword/qword-sized xor differ only in bit #1. Other instructions like 29 vs. 2B sub 遵循相同的模式。 位#1 有时被称为操作码的“方向”位。 (不要与EFLAGS中的DF混淆,方向flag)。

另请注意,这些指令的字节与 word/dword/qword 操作数大小版本仅在低位不同,如 30 XOR r/m8, r831 XOR r/m16, r16。同样,这种模式出现在可追溯到 8086 的 ALU 指令编码中。这些操作码的第 0 位有时称为“大小”位。

这些对每个方向和大小组合都有编码的“基本 ALU”指令可以追溯到原始 8086;许多后来的指令像 386 bsf r, r/m or 186 imul r, r/m, imm don't have a form that could allow a memory destination. Or for bt* r/m, r 只有 目的地可以是 reg/mem.

这也是为什么后来的指令(或它们的新形式,如 imul)通常没有针对字节操作数大小的单独操作码,只允许通过正常前缀机制 word/dword/qword。 8086 用掉了大部分编码 space,后来的扩展希望为以后的更多扩展留出空间。所以这就是为什么没有 imul r, r/m8.

(dword 和 qword 操作数大小本身就是扩展;8086 没有操作数大小或 REX 前缀。因此原始 8086 在使用其操作码编码 space 以及具有模式来让解码不再一团糟。)


表单之间没有执行差异

对于 reg,reg 指令,它们在我所知道的任何 CPU 上的解码和执行方式都没有区别;唯一需要关心汇编程序使用哪种编码的情况是当您希望机器代码满足某些其他要求时,例如仅使用表示可打印 ASCII 字符的字节。 (例如,对于漏洞利用负载)。


指定希望汇编器使用的形式

一些汇编器具有覆盖其默认编码选择的语法,例如GAS had a .s suffix to get the non-default encoding. That's now deprecated, and you should use {load} or {store} prefixes before the mnemonic (see the docs), 像这样:

{load} xor %eax, %ecx
{store} xor %eax, %ecx
{vex3} vpaddd %xmm0, %xmm1, %xmm1
vpaddd %xmm0, %xmm1, %xmm1        # default is to use 2-byte VEX when possible

gcc -c foo.S && objdump -drwC foo.o

0:   31 c1                   xor    %eax,%ecx
2:   33 c8                   xor    %eax,%ecx
4:   c4 e1 71 fe c8          vpaddd %xmm0,%xmm1,%xmm1
9:   c5 f1 fe c8             vpaddd %xmm0,%xmm1,%xmm1

(相关: 用于 {vex3}{evex}{disp32} 的用例。)

NASM 也有 {vex2}{vex3}{evex} 前缀,其语法与 GAS 相同,例如{vex3} vpaddd xmm1, xmm1, xmm0。但我没有看到一种方法来覆盖 op r/m, rop r, r/m 操作码的选择。


相关问答,有些基本重复

  • Why does the Solaris assembler generate different machine code than the GNU assembler here? - 一些汇编器有不同的默认“方向”选择。
  • 一些汇编程序甚至使用该选择(可能还有其他冗余)作为在其输出机器代码中添加足迹/水印的方法。 which was shareware, using this as a way to detect binaries from people that didn't pay the shareware fee. A86 tag wiki.
  • What is the ".s" suffix in x86 instructions?(GAS 源中 {load}{store} 覆盖的前身)。
  • Encoding ADC EAX, ECX - 2 different ways to encode? (arch x86)