我有这段代码,上面写着
global main
[BITS 64]
section .text
main:
mov r13, 0x1234
mov rax, 60
mov rdi, 0
syscall
当我手动翻译这条指令 mov r13, 0x1234
时,我得到了十六进制代码 0x48_BD_34_12_00_00
。
该指令的操作码是REX.W + B8+ rd io(我猜)。
当我在 Linux 上翻译文件时,十六进制翻译为 0x41_BD_34_12_00_00
。
41 是 0100_0001但 REX.W 说 W = 1,所以它应该是 0100_1001b。
所以我不明白为什么 REX 前缀是 41h 而不是 49h。
最佳答案
造成这种情况的原因有两个。
首先,NASM 编码的指令实际上是 mov r13d, 0x1234
而不是 mov r13, 0x1234
。这是因为前一条指令更短,但执行相同的操作。
为什么我们会看到这种编码?这里有一个解释:
41 bd 34 12 00 00
|| || ||||||||||
|| || ``````````-- immediate value
|| ``-------------- opcode b8 + reg (5)
``----------------- REX.B prefix
我们要编码的寄存器编号为13。该寄存器编号的低3位被编码在操作码字节中。高位被编码在 REX.B 位中。因此,需要一个 REX.B 前缀。
如果我们想将 mov r13, 0x1234
编码为 nasm -O0
,例如 mov r13, strict qword 0x1234
,它会看起来像这样:
49 bd 34 12 00 00 00 00 00 00
这里我们有一个 REX.BW 前缀 49
来编码附加寄存器位和 64 位操作数宽度。这是 mov r64, imm64
编码,与 mov r32, imm32
相同的操作码,但带有 REX.W。
不优化为 32 位寄存器但为您编写的内容选择最短编码(例如 YASM 或 GAS)的汇编器将使用 mov r/m64, sign_extended_imm32
编码,该编码您可以使用 mov r13, strict dword 0x1234
从 NASM 获取。 C7 和 C5 字节是操作码和 Mod/RM,后跟 4 字节立即数。
49 c7 c5 34 12 00 00
关于assembly - mov 立即数到 64 位寄存器的十六进制机器代码没有 REX.W 前缀?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72338052/