assembly - mov 立即数到 64 位寄存器的十六进制机器代码没有 REX.W 前缀?

标签 assembly x86-64 nasm machine-code instruction-encoding

我有这段代码,上面写着

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/

相关文章:

assembly - RISC-V 汇编语法中的混合目标/源操作数顺序

c - 如何在汇编代码中使用c变量

assembly - 0和双字0有什么区别?

C11 Atomic Acquire/Release 和 x86_64 缺乏加载/存储一致性?

assembly - 在 NASM 汇编中计算哈希

linux - 使用程序集执行系统命令(bash)?

assembly - 如何编写汇编语言使 DMA 工作

c++ - 编译器在 eax 上来回生成 mov

linux - nasm 和 ld 的 assembly/链接问题

linux - NASM 参数长度