3

Hullo, I am learning x86 FPU assembly, and I have got a simple question I cannot find answer for:

How to move value from ST(0) ( top of the FPU stack ) to EAX ?

also:
is this code correct:

; 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                                           
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
grunge fightr
  • 1,360
  • 2
  • 19
  • 38
  • 5
    do you want the bit representation of the fp number in EAX or the integer representation(conversion)? – Necrolis Aug 10 '12 at 10:43
  • I think maybe I ve done some kind of mistake, I need to write c-like function that will return a float - I was mistaken by assumption that ret value is by eax but this is float so maybe i should just leave it on st0 -( now i realize so, ) besides are my FPU dot(float*, float*) calculations ok?? – grunge fightr Aug 10 '12 at 10:51
  • Yes, in the usual calling conventions, FP values are returned in `ST(0)`, or in `XMM0`. Never in `eax`, because then the caller would have to bounce it back into `ST(0)` or `XMM0` to use it. – Peter Cordes Nov 11 '17 at 16:31

2 Answers2

5

There is no real reason why you should. Remember that EAX is only a 32-bit register, while all the FPU registers are 80 bits in width, because the FPU does calculations on 80-bit floats by default. Therefore, moving data from the FPU register to a general purpose register will cause data loss. If you really want to do something like that, try this (assuming that you've got some stack space available) :

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

This instruction sequence will round the float currently on the top of the FPU stack to a 32-bit one, then write it to a temporary stack location, load the float (binary32) bit pattern into EAX, and clean up the used stack space.


This is almost never what you want. The standard calling conventions return float / double / long double values in st(0), so that's where a C compiler will expect a double foo() function to leave the value. (Or xmm0 with SSE/SSE2).

You only need this if you want to do integer manipulation / tests on FP bit-patterns. (i.e. to implement type-punning in C like memcpy from a float to uint32_t). e.g. for the famous but now mostly obsolete fast approximate inverse-sqrtf magic-number hack used in Quake source code.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Daniel Kamil Kozar
  • 18,476
  • 5
  • 50
  • 64
  • Ok, TNX for a way, Didnt know that there is no such instruction (it is a little sad maybe, to have to use ram as intermediate) But in such routine I ve tested i could leave result on top of stack - and it is ok – grunge fightr Aug 10 '12 at 13:02
  • 1
    The last 2 instructions could be replaced with `pop eax`. That would be at least as efficient on modern CPUs. Of course normally you'd just reserve some stack space at the start of the function and store/reload to/from that instead of messing with the stack pointer inside a loop. – Peter Cordes Nov 11 '17 at 16:27
4

There are no x87 instructions to move floating point values between the FPU registers and the CPU registers.

You have to use memory as the intermediate.

Alexey Frunze
  • 61,140
  • 12
  • 83
  • 180