我有一个代码
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。
1条答案
按热度按时间wtlkbnrh1#
这有两个原因。
首先,NASM编码的指令实际上是
mov r13d, 0x1234
,而不是mov r13, 0x1234
,这是因为前一条指令较短,但执行的是相同的操作。为什么我们会看到这样的编码呢?这里有一个解释:
我们要编码的寄存器编号为13。此寄存器编号的低3位编码在操作码字节中。高位编码在雷克斯.B位中。因此,需要REX.B前缀。
如果我们想把
mov r13, 0x1234
编码成nasm -O0
,就像mov r13, strict qword 0x1234
一样,它看起来像这样:这里我们有一个雷克斯.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字节立即数。