ROUNDSS的RMI Instruction Operand Encoding是如何工作的?
How does the RMI Instruction Operand Encoding of ROUNDSS work?
像ROUNDSS这样的一些x86指令需要这种看似晦涩的指令操作数编码,我在英特尔的软件开发人员手册中找不到任何文档或定义。
这个编码的比特是怎么用的?我将 66 0f 3a 0b c0 0c
(roundsd xmm0,xmm0,0xc
) 放入反汇编程序并改变位以获得更好的理解,但只能访问一半的 XMM 寄存器。
我也不清楚
的意思
128-bit Legacy SSE version: The first source operand and the destination operand are the same.
作为电子。 G。 66 0f 3a 0b c1 0c
在没有 warning/error 的情况下反汇编为 roundsd xmm0,xmm1,0xc
.
传统编码
编码如下:
66 0F 3A 0A /r ib
操作码是 0F 3A
操作码平面中的 0A
。必须提供强制性 66
前缀。操作码后跟一个 modr/m 字节 (/r
),编码 R 字段中的第一个操作数和 R/M 字段中的第二个操作数。该指令后跟一个 8 位立即数 (ib
),对第三个操作数进行编码。
让我们编码例如
roundss xmm8, [rdx+r9*8+64], 0xc
我们有 xmm8
和 r9
作为“高”寄存器,因此必须提供 REX.RX 前缀 46
来保存额外的位。
modr/m 字节是 44
,表示 8 位位移(mod = 01),存在 SIB 字节(r/m = 100),并且 xmm8
作为reg操作数(reg = 000,REX.R设置)。
SIB字节为CA
表示rdx
为base(base=010),r9
为index(index=001,REX.Xset)和比例为 8(比例 = 11)。
然后是位移40
(即十进制64)。
最后,我们有 8 位立即数 0c
。
然后按照遗留前缀、REX 前缀、操作码平面前缀、操作码、modr/m 字节、SIB 字节、位移、立即数的顺序组装这些位。所以整个指令是
66 46 0F 3A 0A 44 CA 40 0C
| | | | | | | \... immediate
| | | | | | \...... displacement
| | | | | \......... SIB byte
| | | | \............ modr/m byte
| | | \............... opcode
| | \..................... opcode plane prefix
| \........................ REX prefix
\........................... mandatory prefix
VEX 编码
128-bit Legacy SSE version: The first source operand and the destination operand are the same.
指令的 VEX 编码变体 vroundss
有一个额外的源操作数。而不是这个操作数,旧编码版本从目标操作数读取这个源操作数。
如果我们想将这条指令编码为 VEX 编码的变体
vroundss xmm8, xmm2, [rdx+r9*8+64], 0xc
相反,我们从 VEX 前缀开始。该前缀将强制前缀、REX 前缀和操作码平面前缀合并为一个 3 字节前缀。此前缀的格式为:
11000100 RXBmmmmm WvvvvLpp
R, X, B: complemented REX prefix bits
W: REX.W prefix bit (not complemented)
m: opcode plane (1: `0F`, 2: `0F 38`, 3: `0F 3A`)
L: vector length (0: 128 bit, 1: 256 bit)
p: mandatory prefix (0: none, 1: `66`, 2: `F3`, 3: `F2`)
v: complemented extra source register number
更短的 2 字节 VEX 前缀
11000101 RvvvvLpp
可以在REX.X、REX.B、REX.W明确且m=00000的情况下使用,这里不是这样。编码为
VEX.LIG.66.0F3A.WIG 0A /r ib VROUNDSS xmm1, xmm2, xmm3/m32, imm8
表示L和W字段被忽略,有一个强制性的66
前缀并且操作码在0F 3A
操作码平面中是0A
,后面是modr/m 操作数和一个字节立即数。第一个和第三个操作数在 modr/m 字节中编码,第二个操作数是由 VEX 前缀编码的附加操作数。
所以我们有我们的指令
R = 0, indicating presence of REX.R
X = 0, indicating presence of REX.X
B = 1, indicating absence of REX.B
W = 0, indicating absence of REX.W (ignored)
L = 0, indicating a 128 bit operand size (ignored)
m = 00010, indicating the 0F 3A opcode plane
p = 01, indicating a 66 mandatory prefix
v = 1101, indicating xmm2 as a first operand
给出 VEX 前缀 C4 22 69
。其余与旧编码相同,给出完整指令
C4 23 69 0A 44 CA 40 0C
| | | | | \... immediate
| | | | \...... displacement
| | | \......... SIB byte
| | \............ modr/m byte
| \............... opcode
\........................ VEX prefix
像ROUNDSS这样的一些x86指令需要这种看似晦涩的指令操作数编码,我在英特尔的软件开发人员手册中找不到任何文档或定义。
这个编码的比特是怎么用的?我将 66 0f 3a 0b c0 0c
(roundsd xmm0,xmm0,0xc
) 放入反汇编程序并改变位以获得更好的理解,但只能访问一半的 XMM 寄存器。
我也不清楚
的意思128-bit Legacy SSE version: The first source operand and the destination operand are the same.
作为电子。 G。 66 0f 3a 0b c1 0c
在没有 warning/error 的情况下反汇编为 roundsd xmm0,xmm1,0xc
.
传统编码
编码如下:
66 0F 3A 0A /r ib
操作码是 0F 3A
操作码平面中的 0A
。必须提供强制性 66
前缀。操作码后跟一个 modr/m 字节 (/r
),编码 R 字段中的第一个操作数和 R/M 字段中的第二个操作数。该指令后跟一个 8 位立即数 (ib
),对第三个操作数进行编码。
让我们编码例如
roundss xmm8, [rdx+r9*8+64], 0xc
我们有 xmm8
和 r9
作为“高”寄存器,因此必须提供 REX.RX 前缀 46
来保存额外的位。
modr/m 字节是 44
,表示 8 位位移(mod = 01),存在 SIB 字节(r/m = 100),并且 xmm8
作为reg操作数(reg = 000,REX.R设置)。
SIB字节为CA
表示rdx
为base(base=010),r9
为index(index=001,REX.Xset)和比例为 8(比例 = 11)。
然后是位移40
(即十进制64)。
最后,我们有 8 位立即数 0c
。
然后按照遗留前缀、REX 前缀、操作码平面前缀、操作码、modr/m 字节、SIB 字节、位移、立即数的顺序组装这些位。所以整个指令是
66 46 0F 3A 0A 44 CA 40 0C
| | | | | | | \... immediate
| | | | | | \...... displacement
| | | | | \......... SIB byte
| | | | \............ modr/m byte
| | | \............... opcode
| | \..................... opcode plane prefix
| \........................ REX prefix
\........................... mandatory prefix
VEX 编码
128-bit Legacy SSE version: The first source operand and the destination operand are the same.
指令的 VEX 编码变体 vroundss
有一个额外的源操作数。而不是这个操作数,旧编码版本从目标操作数读取这个源操作数。
如果我们想将这条指令编码为 VEX 编码的变体
vroundss xmm8, xmm2, [rdx+r9*8+64], 0xc
相反,我们从 VEX 前缀开始。该前缀将强制前缀、REX 前缀和操作码平面前缀合并为一个 3 字节前缀。此前缀的格式为:
11000100 RXBmmmmm WvvvvLpp
R, X, B: complemented REX prefix bits
W: REX.W prefix bit (not complemented)
m: opcode plane (1: `0F`, 2: `0F 38`, 3: `0F 3A`)
L: vector length (0: 128 bit, 1: 256 bit)
p: mandatory prefix (0: none, 1: `66`, 2: `F3`, 3: `F2`)
v: complemented extra source register number
更短的 2 字节 VEX 前缀
11000101 RvvvvLpp
可以在REX.X、REX.B、REX.W明确且m=00000的情况下使用,这里不是这样。编码为
VEX.LIG.66.0F3A.WIG 0A /r ib VROUNDSS xmm1, xmm2, xmm3/m32, imm8
表示L和W字段被忽略,有一个强制性的66
前缀并且操作码在0F 3A
操作码平面中是0A
,后面是modr/m 操作数和一个字节立即数。第一个和第三个操作数在 modr/m 字节中编码,第二个操作数是由 VEX 前缀编码的附加操作数。
所以我们有我们的指令
R = 0, indicating presence of REX.R
X = 0, indicating presence of REX.X
B = 1, indicating absence of REX.B
W = 0, indicating absence of REX.W (ignored)
L = 0, indicating a 128 bit operand size (ignored)
m = 00010, indicating the 0F 3A opcode plane
p = 01, indicating a 66 mandatory prefix
v = 1101, indicating xmm2 as a first operand
给出 VEX 前缀 C4 22 69
。其余与旧编码相同,给出完整指令
C4 23 69 0A 44 CA 40 0C
| | | | | \... immediate
| | | | \...... displacement
| | | \......... SIB byte
| | \............ modr/m byte
| \............... opcode
\........................ VEX prefix