assembly x86 XOR操作码差异

vxbzzdmp  于 2022-11-13  发布在  其他
关注(0)|答案(1)|浏览(245)

查看http://ref.x86asm.net/coder32.html时,我找到了两个与该语句匹配的操作码

异或eax,eax

1)操作码31异或r/m16/32 r16/32
2)操作码33异或r16/32 r16/32
操作数1和操作数2都是32位寄存器。那么,对两个32位寄存器执行“异或”运算的具体情况有什么区别吗?

5kgi1eie

5kgi1eie1#

x86有两种冗余方式来编码任何基本ALU指令(可追溯到8086)的双寄存器示例,使用r/m源格式和r/m目标格式。
reg,reg编码的这种冗余是x86机器代码如何允许大多数指令的存储器目的地或存储器源的结果:不是花费ModR/M字节中的位来具有用于两个操作数的灵活编码,而是对于大多数指令仅存在两个单独的操作码。
(This这就是为什么任何指令都不允许有两个显式内存操作数(如xor [eax], [ecx])的原因。只有少数一个或两个内存操作数都是隐式的指令(如rep movspush [mem])才允许有两个内存操作数,而一条指令绝不允许有两个独立的ModR/M编码寻址模式。)

编码存在模式

请注意,对于字/双字/四字大小得xor3133仅在第1位不同.其他指令(如292Bsub)也遵循相同得模式.第1位有时称为操作码得“方向”位.(不要与EFLAGS中得DF混淆,即方向 * 标志 *).
另请注意,这些指令得字节与字/双字/四字操作数大小版本仅在低位不同,如30 XOR r/m8, r831 XOR r/m16, r16.同样,这种模式也出现在8086之前得ALU指令编码中.这些操作码得位#0有时称为“大小”位.
这些“基本ALU”指令对每个方向和大小组合都有一个编码,可以追溯到原始的8086;许多后来的指令(如386 bsf r, r/m186 imul r, r/m, imm)没有允许存储器目的地的形式。或者,对于bt* r/m, r * 仅 *,目的地可以是reg/mem。
这也是为什么后来的指令(或者像imul这样的新形式)通常没有针对字节操作数大小的单独操作码,只允许通过正常的前缀机制使用word/dword/qword。8086占用了大量的编码空间,而后来的扩展希望为更多的未来扩展留出空间,这就是为什么没有imul r, r/m8
(双字和四字操作数大小本身是扩展; 8086没有操作数大小或雷克斯前缀,所以原始的8086在使用操作码编码空间方面是相当明智的,而且有模式使解码不至于一团糟。)

表单之间没有执行差异

对于reg,reg指令,它们在我所知道的任何CPU上解码和执行的方式没有区别;只有当你想让机器码满足一些其他的要求时,你才需要关心你的汇编器使用哪种编码,比如只使用代表可打印ASCII字符的字节。

指定汇编程序要使用的格式

有些汇编器有语法可以覆盖默认的编码选择,例如GAS had a .s suffix to get the non-default encoding。现在不推荐使用这种语法,您应该在助记符(see the docs)前使用{load}{store}前缀,如下所示:

{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

(相关:What methods can be used to efficiently extend instruction length on modern x86?适用于{vex3}{evex}{disp32}的用例。)

NASM也有{vex2}{vex3}{evex}前缀,它们的语法与GAS相同,例如{vex3} vpaddd xmm1, xmm1, xmm0。但我看不出有什么方法可以覆盖op r/m, rop r, r/m的操作码选择。

相关问答,有些基本重复

相关问题