3

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

如何将值从ST(0)(FPU 堆栈的顶部)移动到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                                           
4

2 回答 2

5

没有真正的理由你应该这样做。请记住,这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中,并清理已使用的堆栈空间。


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

如果你想对 FP 位模式进行整数操作/测试,你只需要这个。(即在 C 中实现类型双关语,例如memcpyfrom a floatto uint32_t)。例如,对于Quake 源代码中使用的著名但现在大多已过时的快速近似反sqrtf幻数 hack 。

于 2012-08-10T12:25:43.853 回答
4

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

您必须使用内存作为中间体。

于 2012-08-10T10:53:24.760 回答