解码特定 x87 FPU 指令时的歧义

Hri*_*ali 1 fpu opcode x87

在解码 x87 FPU 指令方面,我面临着一个模棱两可的情况。看看下面的指令取自第 2A 卷英特尔指令集手册 [1] 的第 3-380 页。

D9 /0    --> FLD m32fp --> Push m32fp onto the FPU register stack.
D9 C0+i  --> FLD ST(i) --> Push ST(i) onto the FPU register stack.
Run Code Online (Sandbox Code Playgroud)

这两条指令都具有相同的单字节基本操作码0xD9。第一条指令的扩展操作码为0x00. 扩展操作码将在 ModR/M 字节的“reg”字段中指定。但第二条指令是一个 2 字节的操作码,具有“添加到获取寄存器”功能。这意味着:

D9 C0  --> FLD ST0  
D9 C1  --> FLD ST1  
(and so on)
Run Code Online (Sandbox Code Playgroud)

关于区分这两个指令,我有一个小问题。一个小例子是:

现在,假设我得到操作码序列"D9 C1"。如果我需要检查它是否是指令"FLD m32fp",那么我必须检查 ModR/M 字节的“reg”字段是否为 0x00。如果是这样,那么它确实是"FLD m32fp"正在使用的指令。

的二进制表示C1"1100 0001"。假设bit0是LSB,那么bit3-bit5(含)构成ModR/M字节的'reg'字段"C1"。我们看到它确实是0x00(3 个零)。

所以我将操作码序列映射"D9 C1""FLD m32fp"指令。进一步解码,我们看到操作数实际上变成"ecx"了这种情况。但是我们看到它"FLD ST1"也有操作码序列"D9 C1",这是用于该操作码序列的实际指令。

本质上,我怎么能确定操作码序列"D9 C1"对应于指令"FLD ST1"而不是"FLD ecx"

"FMUL"指令也出现了非常相似的问题,因为采用与"FLD"此处相同的方式获取操作数。

[1] http://www.intel.com/design/intarch/manuals/243191.HTM

感谢和问候,
赫瑞诗凯诗穆拉利

use*_*653 5

这在“A.2.6. Escape Opcode Instructions”中有描述,相关部分是:

如果 ModR/M 字节在 00H 到 BFH 的范围内,则 ModR/M 字节的第 5、4 和 3 位用作操作码扩展,类似于用于 1 和 2 字节操作码的技术(请参阅到第 A.2.5 节,“一字节和两字节操作码的操作码扩展”)。如果 ModR/M 字节在 00H 到 BFH 的范围之外,则整个 ModR/M 字节用作操作码扩展。

关于问题:

现在,假设我得到操作码序列“D9 C1”。如果我需要检查它是否是指令“FLD m32fp”,那么我必须检查 ModR/M 字节的“reg”字段是否为 0x00。如果是这样,那么确实是使用了“FLD m32fp”指令。

当您遇到 x87 指令时,您必须检查 mod/rm 字节是否 >= 0xC0(对应于 0b11 或 3 的 mod 字段),然后在表 A-10(对于 D9)中查找。看着那里,你看到了D9 C1 = FLD ST(0),ST(1)

当 mod/rm 字节 < 0xC0 时,要使用的表是 A-9。D9 01(mod = 0b00, opcode extension (reg) = 0b000, rm = 0b001) 是“FLD single-real”,从表 2-2 来看,结果是fld dword [ecx].

顺便说一句,没有像“FLD ecx”这样的指令,因为您不能直接从整数寄存器加载到 FPU 堆栈上。