我在解码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.
这两条指令都具有相同的单字节基本操作码0xD9
。第一条指令的扩展操作码为0x00
。扩展操作码将在ModR / M字节的'reg'字段中指定。但第二条指令是一个2字节的操作码,带有“添加到寄存器”功能。这意味着:
D9 C0 --> FLD ST0
D9 C1 --> FLD ST1
(and so on)
关于区分这两条指令,我遇到了一个小问题。一个小例子是:
现在,假设我得到操作码序列"D9 C1"
。如果我需要检查它是否是指令"FLD m32fp"
,那么我必须检查ModR / M字节的'reg'字段是否为0x00。如果是这样,那么确实使用的是"FLD m32fp"
指令。
C1
的二进制表示形式为"1100 0001"
。假设bit0是LSB,则bit3-bit5(包括)构成ModR / M字节"C1"
的'reg'字段。我们看到它确实是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
谢谢和问候,
Hrishikesh Murali
答案 0 :(得分:4)
这在“A.2.6。逃避操作码指令”中有描述,相关部分为:
如果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,操作码扩展名(reg)= 0b000,rm = 0b001)是“FLD single-real”,查看表2-2的结果为fld dword [ecx]
。
另外,没有“FLD ecx”这样的指令,因为你不能直接从整数寄存器加载到FPU堆栈上。