查看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位寄存器执行“异或”运算的具体情况有什么区别吗?
查看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位寄存器执行“异或”运算的具体情况有什么区别吗?
1条答案
按热度按时间5kgi1eie1#
x86有两种冗余方式来编码任何基本ALU指令(可追溯到8086)的双寄存器示例,使用r/m源格式和r/m目标格式。
reg,reg
编码的这种冗余是x86机器代码如何允许大多数指令的存储器目的地或存储器源的结果:不是花费ModR/M字节中的位来具有用于两个操作数的灵活编码,而是对于大多数指令仅存在两个单独的操作码。(This这就是为什么任何指令都不允许有两个显式内存操作数(如
xor [eax], [ecx]
)的原因。只有少数一个或两个内存操作数都是隐式的指令(如rep movs
或push [mem]
)才允许有两个内存操作数,而一条指令绝不允许有两个独立的ModR/M编码寻址模式。)编码存在模式
请注意,对于字/双字/四字大小得xor,
31
与33
仅在第1位不同.其他指令(如29
与2B
sub)也遵循相同得模式.第1位有时称为操作码得“方向”位.(不要与EFLAGS中得DF混淆,即方向 * 标志 *).另请注意,这些指令得字节与字/双字/四字操作数大小版本仅在低位不同,如
30 XOR r/m8, r8
与31 XOR r/m16, r16
.同样,这种模式也出现在8086之前得ALU指令编码中.这些操作码得位#0有时称为“大小”位.这些“基本ALU”指令对每个方向和大小组合都有一个编码,可以追溯到原始的8086;许多后来的指令(如386
bsf r, r/m
或186imul 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}
前缀,如下所示:gcc -c foo.S && objdump -drwC foo.o
(相关: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, r
和op r, r/m
的操作码选择。相关问答,有些基本重复
{load}
和{store}
覆盖的前身)。