Assembly 从FPU堆栈中删除某些内容的最简单方法

Assembly 从FPU堆栈中删除某些内容的最简单方法,assembly,x86,x87,Assembly,X86,X87,我最近遇到了一些FPU堆栈溢出的问题。我设法将它追溯到一个有缺陷的库函数,该函数在每次调用FPU堆栈时都会将垃圾值推送到FPU堆栈上,并且从不清理它 幸运的是,这很容易复制,我确切地知道是什么条件造成的。我可以将一个内联ASM块放入调用此例程的例程中,以将顶级值从FPU堆栈中弹出。。。除了我不太知道写什么。我的ASM fu是中等的,但没有那么强 那么,在x86汇编中,如果FPU堆栈上的顶部值是垃圾数据,我不关心它的值,那么最简单的方法是什么呢?如果您知道需要调整堆栈多少,可以使用fincstp。

我最近遇到了一些FPU堆栈溢出的问题。我设法将它追溯到一个有缺陷的库函数,该函数在每次调用FPU堆栈时都会将垃圾值推送到FPU堆栈上,并且从不清理它

幸运的是,这很容易复制,我确切地知道是什么条件造成的。我可以将一个内联ASM块放入调用此例程的例程中,以将顶级值从FPU堆栈中弹出。。。除了我不太知道写什么。我的ASM fu是中等的,但没有那么强


那么,在x86汇编中,如果FPU堆栈上的顶部值是垃圾数据,我不关心它的值,那么最简单的方法是什么呢?

如果您知道需要调整堆栈多少,可以使用
fincstp
。您还希望
ffree
递增的寄存器

然而,最简单的解决方案可能是使用弹出式数据传输操作之一,如
fstp
。通常情况下,您会将结果存储到内存区域供以后使用,例如:

mem_area: defs 10         ; ten bytes for 80 bits
          fstp mem_area   ; pop it
但是,如果您知道您只是想丢弃该值,则可以使用
st(0)
本身作为目标,以节省内存需求:

fstp st(0)

请参阅以获取有关指令(特别是)的详细指南。

只需将其与弹出的任何(快速)指令一起从堆栈中弹出即可。


如果这不起作用,FUCOMPP会弹出两次

如果
st0
是唯一正在使用的x87寄存器,则可以使用以下命令将其清空:

ffree st0
但如果使用多个堆栈寄存器,则这与普通pop不同,因为它不调整堆栈顶部指针(x87状态字中的顶部字段)


st1
在释放
st0
而不是弹出后仍将是
st1
,因此这通常不是您想要的,并且与
fstp st0
相比没有显著优势。对于Delphi/BASM,我认为弹出FPU堆栈的最简单方法是:

asm
 fstp st(0)
end;

这其实是正确的答案。大多数x87实现都针对这种情况进行了优化,甚至不会执行传输,只是从堆栈中弹出值。这不起作用。st0被标记为空,但这不会影响除fpu标记字以外的任何内容。不确定您还希望影响什么,因为它会影响寄存器中内容的定义。当然,您也希望更改堆栈指针。我已经通过实验验证了(通过我的第四个,ciforth的小代码)您的解决方案没有按预期工作。请参阅PhiS给出的正确答案。我为什么要更改sp?堆栈是空的,从哪里开始填充并不重要。@JensBjörnhager:您的更新在技术上是正确的,但对于那些对x87了解不够甚至认为只有1个寄存器在用的条件是相关的/重要的人来说,仍然很容易被误解。我基本上是将答案(代码块除外)重写为我认为值得一投的东西。请注意,“fstp st(0)”需要一个时钟。没有比这更好的了。@AlbertvanderHorst:超标量CPU可以轻松地做得更好
fstp/fst
在Haswell/Skylake上,具有寄存器目的地的实际吞吐量为每0.5c一个(即每时钟2个)。寄存器重命名通过堆栈顶部指针处理依赖关系。对于记录,x87已过时。现代代码通常会使用XMM寄存器,甚至对于标量FP数学,使用指令如
addss
(标量单精度)或。查看编译器为任何FP函数生成的代码以获取示例。