我在程序中得到了这条指令:
FSTENV (28-BYTE) PTR SS:[ESP-1C]
它做了什么?
它使用和更新了哪些寄存器?
谢谢!
答案 0 :(得分:4)
存储浮点环境。这包括:当前控制字,状态字,标记字,指令指针和操作数指针。它们存储在内存中的结构中。在16位模式下,该结构为14个字节。在32位模式下,它是28个字节。我完全不确定它是否可用于64位模式(64位模式主要使用SSE)[编辑:显然在32位和64位模式下运行相同。]
我不相信它会改变协处理器的任何当前状态[编辑:oops - 确实如此,它掩盖了FP异常,但大多数人从不揭露它们开始,所以...] - 但是当您使用fldenv
时,会将状态恢复为使用fstenv
存储时的状态。
答案 1 :(得分:2)
Jerry Coffins答案是正确的。
如果您想知道(28-BYTE) PTR SS:[ESP-1C]
:这是FP环境存储的有效地址,它指定28字节该命令的版本并指向堆栈段中堆栈指针下方的28(0x1c)字节
我只是添加了英特尔的官方说明,我发现这是使用搜索引擎。
<强>描述强>
将当前FPU操作环境保存在内存位置 使用目标操作数指定,然后屏蔽全部 浮点异常。 FPU操作环境包括 FPU控制字,状态字,标记字,指令指针,数据 指针和最后一个操作码。 IA-32中的图7-13至7-16 英特尔®架构软件开发人员手册第1卷显示了 存储环境的内存布局,取决于操作 处理器的模式(受保护或实际)和当前操作数大小 属性(16位或32位)。在virtual-8086模式下,实模式 使用布局。
FSTENV指令检查并处理任何未处理的未屏蔽的 存储FPU环境之前的浮点异常;该 FNSTENV指令没有。保存的图像反映了状态 在前面的所有浮点指令之后的FPU 指令流中的FSTENV / FNSTENV指令已经完成 执行。
这些指令通常由异常处理程序使用,因为它们 提供对FPU指令和数据指针的访问。该 环境通常保存在堆栈中。掩盖所有异常 保存环境后会阻止浮点异常 中断异常处理程序。英特尔®架构兼容性
在MS-DOS *操作中操作Pentium®或Intel486™处理器时 系统兼容模式,有可能(不寻常 情况)FNSTENV指令在之前被中断 被执行以处理待处理的FPU异常。见部分 标题为“无等待FPU指令可以在窗口中获得FPU中断” IA-32英特尔®架构软件开发人员的附录D. 手册,第1卷,描述这些情况。一个FNSTENV 在Pentium Pro上不能以这种方式中断指令 处理器。
<强>操作强>
DEST [FPUControlWord]&lt; - FPUControlWord;
DEST [FPUStatusWord]&lt; - FPUStatusWord;
DEST [FPUTagWord]&lt; - FPUTagWord;
DEST [FPUDataPointer]&lt; - FPUDataPointer;
DEST [FPUInstructionPointer]&lt; - FPUInstructionPointer;
DEST [FPULastInstructionOpcode]&lt; - FPULastInstructionOpcode;
受影响的FPU标志
C0,C1,C2和C3未定义。
浮点异常
无。
受保护模式例外
GP(0) - 如果目的地位于不可写的段中。如果内存操作数有效地址在CS,DS,ES,FS或GS之外 分段限制。如果使用DS,ES,FS或GS寄存器进行访问 内存,它包含一个空段选择器。
SS(0) - 如果内存操作数有效地址超出SS段限制。
NM - 设置CR0中的EM或TS。
PF(故障代码) - 如果发生页面错误。
AC(0) - 如果启用了对齐检查,并且在当前权限级别为3时进行了未对齐的内存引用。实地址 模式例外
GP - 如果内存操作数有效地址超出CS,DS,ES,FS或GS段限制。
SS - 如果内存操作数有效地址超出SS段限制。
NM - 设置CR0中的EM或TS。 Virtual-8086模式异常
GP(0) - 如果内存操作数有效地址超出CS,DS,ES,FS或GS段限制。
SS(0) - 如果内存操作数有效地址超出SS段限制。
NM - 设置CR0中的EM或TS。
PF(故障代码) - 如果发生页面错误。
AC(0) - 如果启用了对齐检查并且未进行未对齐的内存引用。
答案 2 :(得分:2)
我想用不同的方法回答这个问题。
FSTENV不是真实的&#34;指令。
在搜索&#34; FNSTENV&#34;时,您可能会更幸运。操作码。
仔细研究编码(来自Intel SDM):
FSTENV 9B D9 /6
FNSTENV D9 /6
看到领先&#34; 9B&#34;? 它真的是一个&#34; FWAIT&#34;先于&#34; FNSTENV&#34;。
所以,&#34; FSTENV&#34;就像许多其他指令一样,它只是大多数汇编程序和反汇编程序都能理解的约定。
英特尔手册确实提到了这种特性,但你不应该指望它在100%的情况下都是精确的,有时它可能会省略这些细节:
FSTENV / FNSTENV-Store x87 FPU环境(第2A卷3-393)
汇编程序为FSTENV指令发出两条指令( FWAIT 指令后跟FNSTENV 指令),处理器分别执行这些指令中的每一个。如果生成异常 这些指令中的任何一个,保存EIP指向导致异常的指令。
有很多这样的&#34;特别&#34;说明。
例如,您可能会感到惊讶much NOP's there are in x86,
他们通常会将其他说明作为别名。
Intel XED可能会在您的斗争中得心应手,原因如下:
Go asm有一个名为x86.csv的内容列出了x86指令 采用英特尔SDM方式,但有时还有其他信息 如果你为#34; FSTENV&#34; grep它,你会看到&#34;伪&#34;与之相关的标签 请注意,x86.v0.2.csv可能会遗漏一些指令,尤其是来自较新的扩展(虽然这将在v0.3中修复)。
答案 3 :(得分:1)
为了完整起见,这里是FSTENV
/ FNSTENV
指令产生的内存布局。它在x86-64 "Long 64-bit Mode"
和x86 "32 bit compatibility mode"
中是相同的(除非您在x86-64中使用前缀66h
作为前缀。)
引用this unwieldy英特尔文档,这是布局:
(顺便说一下,上面的图片应该被命名为#34;长模式&#34;以及
因此,如果我们在长64位模式下运行实际测试:
并在具有以下上下文状态的FNSTENV
指令后立即中断:
它返回的内存布局如下:
我不会躲起来,这是非常奇怪的。 (从切断的RIP寄存器到看起来很奇怪的操作码的任何东西。)但是由于遗留原因,我仍然支持它。
好消息是,在编写现代x64代码时,目前没有太多用于这些古老的x87 FPU指令的用法。在这种情况下,您应该坚持使用XMM0
到XMM15
寄存器及其相关指令来满足您的浮点需求。