【问题标题】:FSTENV? Can barely find any info about this instructionFSTENV?几乎找不到有关此指令的任何信息
【发布时间】:2012-04-26 16:43:01
【问题描述】:

我在一个程序中有这条指令:

FSTENV (28-BYTE) PTR SS:[ESP-1C]

它有什么作用?

它使用和更新了哪些寄存器?

谢谢!

【问题讨论】:

  • 假设您已经 google 过,在大量的文档结果中您有什么不明白的?
  • 还是你不懂的操作数语法?

标签: assembly x86 x87


【解决方案1】:

Jerry Coffins 答案是正确的。
如果您想知道 (28-BYTE) PTR SS:[ESP-1C]:
这是存储 FP 环境的有效地址,它指定 28 字节版本的命令并指向堆栈段中堆栈指针下方的 28 (0x1c) 字节。
我只是添加了英特尔的官方描述,这是我使用搜索引擎找到的。

说明

在内存位置保存当前的 FPU 运行环境 用目标操作数指定,然后屏蔽所有 浮点异常。 FPU操作环境包括 FPU 控制字、状态字、标签字、指令指针、数据 指针和最后一个操作码。 IA-32 中的图 7-13 至 7-16 英特尔® 架构软件开发人员手册,第 1 卷,展示了 存储环境的内存布局,取决于操作 处理器的模式(受保护的或真实的)和当前操作数大小 属性(16 位或 32 位)。在虚拟 8086 模式下,实模式 使用布局。

FSTENV 指令检查并处理任何待处理的未屏蔽 存储 FPU 环境之前的浮点异常;这 FNSTENV 指令没有。保存的图像反映了状态 在 FPU 之前的所有浮点指令之后 指令流中的FSTENV/FNSTENV指令已被 执行。

这些指令经常被异常处理程序使用,因为它们 提供对 FPU 指令和数据指针的访问。这 环境通常保存在堆栈中。屏蔽所有异常 保存环境后防止浮点异常 中断异常处理程序。英特尔® 架构兼容性

在 MS-DOS* 中运行 Pentium® 或 Intel486™ 处理器时 系统兼容模式下,有可能(异常情况下 情况)为一个 FNSTENV 指令被中断之前 正在执行以处理挂起的 FPU 异常。见章节 标题为“No-Wait FPU Instructions Can Get FPU Interrupt in Window” IA-32 英特尔® 架构软件开发人员的附录 D 手册,第 1 卷,用于描述这些情况。一个 FNSTENV 在 Pentium Pro 上不能以这种方式中断指令 处理器。

操作

DEST[FPUControlWord)

DEST[FPUStatusWord)

DEST[FPUTagWord)

DEST[FPUDataPointer)

DEST[FPUInstructionPointer)

DEST[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(fault-code) - 如果发生页面错误。

AC(0) - 如果启用对齐检查并在当前特权级别为 3 时进行未对齐的内存引用。实地址 模式异常

GP - 如果内存操作数有效地址超出 CS、DS、ES、FS 或 GS​​ 段限制。

SS - 如果内存操作数有效地址超出 SS 段限制。

NM - CR0 中的 EM 或 TS 已设置。虚拟 8086 模式异常

GP(0) - 如果内存操作数有效地址超出 CS、DS、ES、FS 或 GS​​ 段限制。

SS(0) - 如果内存操作数有效地址超出 SS 段限制。

NM - CR0 中的 EM 或 TS 已设置。

PF(fault-code) - 如果发生页面错误。

AC(0) - 如果启用了对齐检查并且进行了未对齐的内存引用。

【讨论】:

    【解决方案2】:

    它存储浮点环境。其中包括:当前控制字、状态字、标签字、指令指针和操作数指针。这些存储在内存中的结构中。在 16 位模式下,该结构为 14 个字节。在 32 位模式下,它是 28 个字节。我完全不确定它在 64 位模式下是否可用(64 位模式主要使用 SSE 代替)[编辑:显然在 32 位和 64 位模式下操作相同。]

    我不相信它会改变协处理器的任何当前状态[编辑:哎呀——确实如此,它掩盖了 FP 异常,但大多数人从不从一开始就取消屏蔽它们,所以...]——但是当你使用fldenv 时,它会将状态恢复到你使用fstenv 存储它时的状态。

    【讨论】:

    • 它在 64 位模式和 32 位模式下的行为相同,并且它确实改变处理器的状态:它存储 FPU 环境,然后屏蔽所有浮点异常.
    • @StephenCanon:啊,我忘记了——考虑到我一开始就发现 FP 异常的次数(很少),这并不奇怪。
    • 我很确定每个人都忘记了 =)
    【解决方案3】:

    为了完整起见,这里是FSTENV/FNSTENV 指令产生的内存布局。在 x86-64 "Long 64-bit Mode" 和 x86 "32 bit compatibility mode" 中是相同的(除非您在 x86-64 中添加前缀 66h。)

    引用this unwieldy英特尔文档,这是布局:

    (顺便说一句,上面的图像也应该被命名为“长模式”。)

    因此,如果我们在长 64 位模式下运行实际测试:

    并在 FNSTENV 指令之后立即中断,并具有以下上下文状态:

    它返回的内存布局如下:

    我不会隐瞒,这很奇怪。 (从截断的 RIP 寄存器到看起来很奇怪的操作码的任何内容。)但我猜出于遗留原因,它仍然受支持。

    好消息是,在对现代 x64 代码进行编码时,这些古老的 x87 FPU 指令现在已经没有多少用途了。在这种情况下,您绝对应该坚持使用 XMM0XMM15 寄存器及其相关指令以满足您的浮点需求。

    【讨论】:

      【解决方案4】:

      我想用不同的方法来回答这个问题。

      FSTENV 不是“真正的”指令。
      搜索“FNSTENV”操作码可能会更幸运。

      仔细查看编码(来自Intel SDM):

      FSTENV   9B D9 /6  
      FNSTENV  D9 /6
      

      看到前面的“9B”了吗?
      它实际上是“FNSTENV”前面的“FWAIT”。

      因此,“FSTENV”与许多其他指令一样,只是大多数汇编程序和反汇编程序都理解的约定。

      英特尔手册确实提到了这个特性,但你不应该期望它在 100% 的情况下是准确的,有时它可能会忽略这些细节:

      FSTENV/FNSTENV - 存储 x87 FPU 环境(第 2A 卷 3-393)

      汇编器为 FSTENV 指令发出 两条指令(一条 FWAIT 指令后跟一条 FNSTENV 指令),并且处理器分别执行这些指令中的每一个。如果为 这些指令中的任何一条,保存 EIP 都会指向导致异常的指令。

      有很多这样的“特殊”说明。
      例如,您可能会惊讶于much NOP's there are in x86, 他们通常给其他指令起别名。

      奖金 - 有用的资源

      Intel XED 可以在您的斗争中派上用场,原因如下:

      1. 它可以用作编码器/解码器来验证其他工具。
      2. datafiles 是人类(和机器)可读 ISA 信息的良好来源。您可以找到解释数据文件结构的 engineering notes

      Go asm 有一个名为 x86.csv 的东西,它列出了 x86 指令 采用英特尔 SDM 方式,但有时带有附加信息。
      如果您将其 grep 为“FSTENV”,您将看到与之关联的“伪”标签。
      请注意,x86.v0.2.csv 可能会遗漏一些说明,尤其是来自较新扩展的说明(不过,这将在 v0.3 中修复)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-10-27
        • 1970-01-01
        • 1970-01-01
        • 2017-11-28
        • 2016-07-30
        相关资源
        最近更新 更多