为什么NASM在两个寄存器之间组装MOV指令时使用0x89操作码(137)?
以下是使用NASM组装的代码示例:
55 push ebp
89E5 mov ebp, esp
83EC04 sub esp, byte +0x4
31C0 xor eax, eax
C9 leave
C3 ret
我想要这样的东西:
55 push ebp
8BEC mov ebp, esp
83EC04 sub esp, byte +0x4
33C0 xor eax, eax
C9 leave
C3 ret
我想要0x8B的原因是:如果你查看MOV指令的二进制表示,它在NASM中看起来像这样:
Opcode Mod Reg R/M
10001001 11 100 101 (89 E5)
令人困惑的部分是reg操作数是第二个。
NASM语法是:0x89 11 source_reg destination_reg
和
MOV指令为mov destination_reg, source_reg
答案 0 :(得分:6)
两个操作码是相同的。这是x86的冗余。汇编程序可以选择它喜欢的任何东西
x86架构的典型指令有两个操作码。它们中的第一个具有寄存器作为第一个操作数,寄存器或存储器位置作为第二个(在操作码引用中缩写为
"reg, reg/mem32"
或在操作码表中缩写为"Gv, Ev"
)。第二个操作码的操作数是相反的(缩写为"reg/mem32, reg"
或"Ev, Gv"
)。这是有道理的:处理器必须知道它是复制到内存还是从内存复制。但是当两个操作数都是寄存器时,编码变得多余:
; mod reg r/m
03C3 add eax, ebx ; 11 000 011
01D8 add eax, ebx ; 11 011 000
这样的reg / reg风格不仅仅是这样。见here
不同的汇编程序发出不同的操作码,因此该技术可用于identify the assembler
某些汇编程序允许您选择编码。例如,如果您将.s
附加到结尾
10 de adcb %bl,%dh
12 f3 adcb.s %bl,%dh