【问题标题】:How to move ST(0) to EAX?如何将 ST(0) 移动到 EAX?
【发布时间】:2012-08-10 10:39:44
【问题描述】:

你好,我正在学习 x86 FPU 组装,我有 有一个简单的问题,我找不到答案:

如何从 ST(0) 转移价值(FPU 的顶部 stack ) 到 EAX ?

还有:
这段代码是否正确:

; multiply (dot) two vectors of 3 floats passed by pointers as arg 1 arg 2
; passings are ok I think, but not sure if multiplies-adds are ok

    push    ebp                                     
    mov     ebp, esp                                
    mov     eax, dword [ebp+8H]                     
    mov     edx, dword [ebp+0CH]                    

    fld     qword [eax]                             
    fmul    qword [edx]                             
    fld     qword [eax+4H]                          
    fmul    qword [edx+4H]                          
    fld     qword [eax+8H]                          
    fmul    qword [edx+8H]                          
    faddp   st1, st(0)                              
    faddp   st1, st(0)                            
    fstp    qword [ebp+10H]     ; here I vould prefer 'mov eax, st0'

    pop     ebp                                   
    ret                                           

【问题讨论】:

  • 你想要EAX中fp数的位表示还是整数表示(转换)?
  • 我想也许我犯了某种错误,我需要编写类似 c 的函数来返回一个浮点数 - 我误认为 ret 值是 eax 的,但这是浮点数所以也许我应该把它留在st0上-(现在我意识到了,)除了我的FPU点(float*,float*)计算还可以吗??
  • 是的,在通常的调用约定中,FP 值在ST(0)XMM0 中返回。永远不要在eax 中使用,因为调用者必须将其退回到ST(0)XMM0 才能使用它。

标签: assembly x86 fpu x87


【解决方案1】:

您没有真正的理由应该这样做。请记住,EAX 只是一个 32 位的寄存器,而所有 FPU 寄存器的宽度都是 80 位,因为 FPU 默认在 80 位浮点数上进行计算。因此,将数据从 FPU 寄存器移动到通用寄存器会导致数据丢失。如果你真的想做这样的事情,试试这个(假设你有一些可用的堆栈空间):

sub esp, 4           ; or use space you already reserved
fstp dword [esp]
mov eax, [esp]       ; or better,  pop eax
add esp, 4

此指令序列会将当前位于 FPU 堆栈顶部的浮点数舍入为 32 位,然后将其写入临时堆栈位置,将float(binary32)位模式加载到EAX,然后清理使用的堆栈空间。


这几乎不是你想要的。 标准调用约定在st(0) 中返回float / double / long double 值,因此C 编译器期望double foo() 函数保留该值。 (或 xmm0 与 SSE/SSE2)。

仅当您想对 FP 位模式进行整数操作/测试时才需要它。 (即在 C 中实现类型双关语,例如从 floatuint32_tmemcpy)。例如用于 Quake 源代码中的famous but now mostly obsolete fast approximate inverse-sqrtf magic-number hack

【讨论】:

  • 好吧,TNX 的一种方式,不知道没有这样的指令(也许有点难过,不得不使用 ram 作为中间体)但是在我测试过的这样的例程中,我可以留下结果在堆栈顶部 - 没关系
  • 最后两条指令可以替换为pop eax。这至少在现代 CPU 上同样有效。当然,通常您只需在函数开始时保留一些堆栈空间,然后将其存储/重新加载到/从其中存储/重新加载,而不是在循环中弄乱堆栈指针。
【解决方案2】:

没有用于在 FPU 寄存器和 CPU 寄存器之间移动浮点值的 x87 指令。

你必须使用内存作为中介。

【讨论】:

  • 好的,您能否说明我的 dot(float*, float*) 程序是否正常?
  • 好吧,如果你使用双精度(qword = 四字 = 4 * 2 字节 = 8 字节),你的偏移量不能是 4。你应该能够轻松地测试/调试你的代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-04-05
  • 1970-01-01
  • 1970-01-01
  • 2017-01-26
  • 1970-01-01
  • 1970-01-01
  • 2017-12-12
相关资源
最近更新 更多