x64指令编码和ModRM字节



call qword ptr [rax]
call qword ptr [rcx]

FF 10
FF 11

我可以看到最后一个数字(0/1)来自哪里(寄存器号),但我试图找出倒数第二个数字(1)来自哪里。根据AMD64架构程序员手册第3卷:通用和系统指令第56页,

"/digit -表示ModRM字节只指定一个寄存器或内存(r/m)操作数。该数字由ModRM reg字段指定,并用作指令操作码扩展。有效的数字取值范围是0 ~ 7。"

等效的Intel文档也有类似的内容,并且通过寄存器的call被指定为编码为

FF /2

…我不知道这意味着什么,也不知道规范中的2如何连接到最终结果中的高1位数。有没有不同的解释?

ModR/M字节有3个字段:

bit 7 & bit 6 = mod
bit 5 through bit 3 = reg = /digit
bit 2 through bit 0 = r/m

这在Intel® 64 and IA-32 Architectures Software Developer’s Manual的第2A卷的Figure 2-1. Intel 64 and IA-32 Architectures Instruction Format中有描述。

:

,,0x10 = 00.010.000 (mod=0, reg/digit=2, r/m=0)

,,0x11 = 00.010.001 (mod=0, reg/digit=2, r/m=1)。

我想你应该检查表2-2中的Intel®64和IA-32架构开发人员手册:组合卷,卷2:指令参考集,第2章:指令格式,2.1.5 ModR/M和SIB字节的寻址模式编码:

<>之前表2 - 2。使用ModR/M字节的32位寻址形式r8(/r) AL CL DL BL AH h DH BHr16(/r) AX CX DX BX SP BP SI DIr32(/r) EAX ECX EDX EBX ESP EBP ESI EDImm(/r) MM0 MM1 MM2 MM3 MM4 MM5 MM6 MM7xmm(/r) XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7(十进制)/数字(操作码)0 1 2 3 4 5 6 7(二进制)REG = 000 001 010 011 100 101 110 111有效地址ModR/M ModR/M字节的值(十六进制)[ax] 00 000 00 08 10 18 20 28 30 38[译文][译文[au:] [au:] [au:[ebx] 011 03 0b 13 1b 23 2b 33 3b[--][--] *1 100 4 0c 14 c 24 2c 34 cdis32 *2 101 05 0D 15 1D 25 2D 35 3D[qh] [qh] [qh] [qh[au:] [au:[EAX]+ dis8 *3 01 000 40 48 50 58 60 68 70 78[ECX]+ dis8 001 41 49 51 59 61 69 71 79[EDX]+ dis8 010 42 4A 52 5A 62 6A 72 7A[EBX]+ [[EBX]] [qh[--][--] [--][--] [--][--] [--[qh] [qh] [qh] [qh[qh] [qh] [qh] [qh[au:] [qh] [au:[EAX]+ 32 1 000 80 88 90 98 A0 A8 B0 B8[ECX]+ dis32 001 81 89 91 99 A1 A9 B1 B9[EDX]+ dis32 010 82 8A 92 9A A2 AA B2 BA[EBX]+ dis32 011 83 8B 93 9B A3 AB B3 BB[——][——]+ dis32 100 84 8C 94 9C A4 AC B4 BC[EBP]+ dis32 101 85 8D 95 9D A5 AD B5 BD[ESI]+ p32 110 86 8E 96 9E A6 AE B6 BE[au:] [au:] [au:] [au:Eax/ax/al/mm0/xmm0 11 000 c0 c8 d0 d8 e0 e8 f0 f8exx/cx/cl/mm/xmm1 001 c1 c9 d1 d9 e1 e9 f1 f9Edx/dx/dl/mm2/xmm2 010 c2 ca d2 da e2 ea f2 faEbx/bx/bl/mm3/xmm3 011 c3 cb d3 db e3 eb f3 fbEsp/sp/ah/mm4/xmm4 100 c4 cc d4 dc e4 ec f4 fcEbp/bp/ch/mm5/xmm5 101 c5 CD d5 dd e5 Ed f5 fdEsi/si/dh/mm6/xmm6 110 c6 ce d6 de e6 ee f6 feEdi/di/bh/mm7/xmm7 111 c7 cf d7 df e7 ef f7 ff注:1. [——][——]命名法表示SIB遵循ModR/M字节。2. dis32命名法表示在ModR/M字节(或SIB)之后的32位位移字节(如果有的话),并将其添加到索引中。3.dis8命名法表示ModR/M字节(或SIB)后面的8位位移字节(如果有的话),然后进行符号扩展并添加到索引中。

/2表示查找表2-2中的Intel文档的Volume 2A(表和Volume中的2与那里的/2没有关系)。在左上角的表格中是/digit。所以到右边一栏找到/2。我们会回来讨论的。

现在,如果您查看call指令定义,您将看到Op/En,"操作数编码"。

Op/En       Operand 1       Operand 2       Operand 3       Operand 4
D           Offset          NA              NA              NA
M           ModRM:r/m (r)   NA              NA              NA

还要注意第一个表中的call签名,例如,这一个,它是64位的,对应于rax的用法:

Opcode    Instruction   Op/En
FF /2     CALL r/m64    M

M告诉我们在操作数编码中查找M;(Op/En)下表,即

Op/En       Operand 1       Operand 2     Operand 3       Operand 4
M           ModRM:r/m (r)   NA            NA              NA

所以操作数1是ModRM:r/m (r)(r)表示操作数是(不是写)。ModRM:r/m表示操作数有一个带有r/m值的ModRM字节。r/m中的r表示"寄存器",m表示"内存"。

回到表2-2中的/2列,我们有010,就在写REG的那行。这里指的是ModRM中间的"规则"。段。

据此,我们有:

mod     description (relevant to us)
00      register indirect addressing mode
01      one-byte signed displacement follows addressing mode byte(s)
10      four-byte signed displacement follows addressing mode byte(s)
11      register addressing mode

由于我们使用的是[rax],这是寄存器间接寻址模式,所以00 .

我们有了mod和reg,现在我们需要r/m来完成ModRM字节。

从web上的其他地方: r/m字段编码使用的寄存器。如果我们回到表2-2和/2列,并将其与左侧的Mod 00框匹配,并且我们使用EAX行(与call [rax]中使用的RAX相同),我们最终得到10。同样,如果我们遵循ECX行(与call [rcx]中的RCX相同),我们得到11。我们得到:

FF 10       call [rax]
FF 11       call [rcx]

注意这个表也显示了r/m值:000表示rax, 001表示rcx。这就得到了最终的ModRM字节。

ModRM         for        hex
00.010.000    rax        10
00.010.001    rcx        11

还请注意,如果您执行call [eax],则以十六进制的67为前缀:

67 FF 01

对应于"地址大小"覆盖前缀

最新更新