【问题标题】:x86(x87) floating point operation operands (theory)x86(x87) 浮点运算操作数(理论)
【发布时间】:2020-12-06 09:17:10
【问题描述】:

我正在关注https://en.wikibooks.org/wiki/X86_Assembly/Floating_Point 学习基本的 FPU 操作。

对于乘法(在这种情况下计算平方),它使用:

fmul   st0, st0; //

但我读到 FPU 是作为堆栈实现的,并且在堆栈的顶部或 (top - 1) 上运行。 所以我认为它应该是这样的

fld qword [c]
fmul st(0)
fmulp st(1)

为什么 FPU 允许通过堆栈索引进行间接寄存器访问? 感觉就像它违背了堆栈与寄存器参数。

【问题讨论】:

  • 每条 x87 指令的参数之一是隐式 st0,另一个可以是任何堆栈寄存器或内存操作数。

标签: assembly x86 cpu-architecture fpu x87


【解决方案1】:

这不是“间接”,它仍然是直接的:使用嵌入在机器代码中的寄存器号。使用 1-explicit-operand 机器代码可以让代码更紧凑,这对设计 8087 的古代设计来说是一个好处。源操作数或目标操作数必须是st0,操作码暗示它是 src 还是 dst。

一个寄存器号仍然被硬编码到大多数指令中,您可以使用fmul st, st6,但不能使用fmul st4, st6。看看available encodings of fmul

  • D8 /1 FMUL m32fp内存源,无堆栈调整
  • DC /1 FMUL m64fp 一样。
  • D8 C8+i FMUL ST(0), ST(i) - reg,reg 以 st0 作为目标
  • DC C8+i FMUL ST(i), ST(0) - reg,reg 以 st0 作为源
  • DE C8+i FMULP ST(i), ST(0) - reg,reg 然后将 st0 从堆栈中弹出
  • DE C9 FMULP - 只是前一个的特例,fmulp st1, st0

因此 3 个操作码字节(以及各种 ModRM 编码)允许内存或寄存器源,或 reg,reg 具有更高的目标。

“堆叠”是为了节省机器代码的大小,而不是让它成为“纯”堆叠机器。这会降低性能:需要浪费大量指令才能将所需数据放入 st0、st1。 并且会使大部分寄存器堆栈无法使用;几乎所有代码都只需将大多数结果存储/重新加载到内存中,而不是在寄存器堆栈中保持较高位置。


此外,您的没有操作数的 fmul 示例已损坏。如果你用 NASM 组装它,fmul 会出于某种奇怪的原因组装到DE C9 fmulp st(1),st,这样就会从 x87 堆栈中读取顶部的 两个 寄存器,但其中一个是空的,所以你会得到 NaN。如果你想使用fmulp,你首先需要一个fld st0

英特尔的手册没有列出没有明确操作数的fmul 形式,只有fmulp。要将 st0 平方两次,您需要 fmul st0 / fmul st0。这给了你d8 c8 fmul st,st(0)

【讨论】:

  • 谢谢,将示例编辑为正确。
猜你喜欢
  • 2013-05-15
  • 2015-07-31
  • 2014-05-07
  • 1970-01-01
  • 2015-11-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多