assembly 将立即数移动到64位寄存器的十六进制机器码没有雷克斯.W前缀?

bxfogqkk  于 2022-11-13  发布在  其他
关注(0)|答案(1)|浏览(167)

我有一个代码

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
指令的操作码是雷克斯.W + B8+ rd io(我猜)。
当我在Linux上翻译我的文件时,十六进制的翻译是0x41_BD_34_12_00_00
41为0100_0001 B。但雷克斯.W表示W = 1,因此应为0100_1001b。
所以我不明白为什么雷克斯的前缀是41h而不是49h。

wtlkbnrh

wtlkbnrh1#

这有两个原因。
首先,NASM编码的指令实际上是mov r13d, 0x1234,而不是mov r13, 0x1234,这是因为前一条指令较短,但执行的是相同的操作。
为什么我们会看到这样的编码呢?这里有一个解释:

41 bd 34 12 00 00
|| ||  ||||||||||
|| ||  ``````````-- immediate value
|| ``-------------- opcode b8 + reg (5)
``----------------- REX.B prefix

我们要编码的寄存器编号为13。此寄存器编号的低3位编码在操作码字节中。高位编码在雷克斯.B位中。因此,需要REX.B前缀。
如果我们想把mov r13, 0x1234编码成nasm -O0,就像mov r13, strict qword 0x1234一样,它看起来像这样:

49 bd 34 12 00 00 00 00 00 00

这里我们有一个雷克斯.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

相关问题