UPi*_*nar 1 assembly x86-64 machine-code opcode instruction-encoding
这些是MOV来自Intel\xc2\xae 64 和 IA-32 架构软件开发人员手册的指令操作码:
B8+ rd id MOV r32, imm32 OI Valid Valid Move imm32 to r32。
C7 /0 id MOV r/m32, imm32 MI Valid Valid Move imm32 to r/m32。
我拆解如下:
\n0: b8 44 33 22 11 mov eax, 0x11223344\nRun Code Online (Sandbox Code Playgroud)\n0: 67 c7 00 44 33 22 11 mov DWORD PTR[eax], 0x11223344\nRun Code Online (Sandbox Code Playgroud)\n我想问的问题是:
\n为什么C7操作码是寄存器/内存(r/m32, imm32)而不是仅内存(m32, imm32)?
是否有任何时候我们使用C7register-only ( r32, imm32) 而不是 using B8?
为什么是操作码
C7r/m32, imm32而不是仅内存m32,imm32?
因为它可能需要额外的晶体管来对其进行特殊处理,并#UD在 ModRM.mode = 11(寄存器目标)上出错,而不是像其他具有只写目标(如 )的指令一样运行它mov r/m32, r32。
我们是否会在任何时候使用 C7 而
mov r32, imm32不是使用B8?
在 32 位模式下,当做出此设计选择时,不会。除了对齐后面的代码而不是单独的代码nop-
可以使用哪些方法来有效地扩展现代 x86 上的指令长度?
在 64 位模式下,您可以使用带有寄存器目标的 C7,但只能带有 REX.W 前缀。最短的编码mov rax, -123是 REX.W mov r/m64, sign_extended_imm32。REX.WB8+rd是 10 字节mov r64, imm64。
当然,对于适合 32 位零扩展的 64 位值,例如mov rax, 0x0000000012345678,您实际上应该使用 5 字节mov eax, 0x12345678。默认情况下,NASM 会为您执行此操作,带有as -Os或 的GAS 也会执行此操作gcc -Wa,-Os。其他汇编器不会,因此程序员可以将 32 位操作数大小用于非巨大非负 64 位常量。
请参阅示例和更多详细信息
[eax]顺便说一句,在 64 位模式下用作目标有点奇怪;64 位地址大小[rax]具有更紧凑的机器代码,通常您的地址会正确扩展到 64 位寄存器,即使您将它们打包到更窄的存储中也是如此。这就是为什么你的反汇编有一个额外的67字节。