为啥 nasm 在寄存器之间组装 MOV 指令时使用 0x89?
Posted
技术标签:
【中文标题】为啥 nasm 在寄存器之间组装 MOV 指令时使用 0x89?【英文标题】:Why does nasm use 0x89 when it assembles a MOV instruction between registers?为什么 nasm 在寄存器之间组装 MOV 指令时使用 0x89? 【发布时间】:2013-10-19 15:20:07 【问题描述】:为什么 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
【问题讨论】:
为什么不呢? 8B 也好不到哪里去。0x89
有什么问题吗?
0x89
是 mov r/m32,r32
。 mov ebp, esp
适合这种格式,那为什么 NASM 会使用其他一些操作码?
【参考方案1】:
两个操作码相同。这就是 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
附加到末尾,GAS 可以发出其他编码
10 de adcb %bl,%dh
12 f3 adcb.s %bl,%dh
What is the ".s" suffix in x86 instructions?
【讨论】:
以上是关于为啥 nasm 在寄存器之间组装 MOV 指令时使用 0x89?的主要内容,如果未能解决你的问题,请参考以下文章