Assembly 64bit: How to return a double value?

前端 未结 2 1685
我寻月下人不归
我寻月下人不归 2020-12-22 00:12

How do I return in Assembler a 64bit value ? I tried this:

C-program:

#include 

double result=0;
double a = 10;
extern double func(         


        
相关标签:
2条回答
  • 2020-12-22 00:23

    @Michael Petch noted that the whole function could be much more efficient with the following code:

    addsd xmm0, xmm0   ; Add input parameter to itself
    ret                ; Done!  (return values go in xmm0)
    

    x86-64 passes/returns double in XMM registers, not memory or the x87 stack. (Applies to both the x86-64 System V ABI/calling convention, and Windows x64. See links in the x86 tag wiki)


    The code posted didn't have comments. Commenting it would have helped the OP, so...

    ;; Buggy original version with comments
    movq qword[x],xmm0  ; Store current value in memory  [Why?]
    fld qword [x]       ; Load current value from memory [Why??]
    fld qword [x]       ; Load current value from memory again
    fadd                ; Add top two stack items
    
    movq xmm0,qword[x]  ; reload original value from memory, unmodified
    

    @ElderBug noted that the OP forgot to store the result of the fadd into memory before doing the final movq, so this function simply returns its input, like
    double foo(double x) { return x; } but leaving garbage on the x87 stack.


    @Michael Petch went on to note that the original code left a large amount of 'debris' on the floating point stack - there was no attempt to clean it up with various pop versions of the instructions (fstp, or faddp instead of fadd). This leaves less room for the next floating point function - until finally a floating-point stack overflow is caused, resulting in an unexpected NaN!

    0 讨论(0)
  • 2020-12-22 00:27

    You cannot mix up FPU and XMM calculations. When you calculate something on the FPU you must store it (as @Elderbug said) in memory and then you must load it to a XMM Register to return it on 64bit procs on x64 on a Win OS. There still can be an advantage of using FPU on 64bit Systems, cause the internal precision of the FPU can be 80bits (if you use the right FPU Control Word: bits 8,9 float32 (24-bit mantissa) = 00b double float (53-bit mantissa) = 10b extended precision (64bit mantissa) = 11b

    If you want to use the FPU:

    fld QWORD PTR x   ; laod var to FPU: into ST(0)  (MASM Syntax)
    fadd ST(0), ST(0)   ; this adds [x]+[x]
    fstp QWORD PTR x  ; store result back in var
    movsd xmm0, QWORD PTR x
    

    NOTE: for movsd always SSE2 is required. (On SSE1 machines a GP fault wil occur! See Intel® 64 and IA-32 Architectures Software Developer’s Manual: http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html However, if you run Windows8/8.1/10 that is never an issue for you, cause the OS itself requests SSE2 as system requirement.

    EDIT: SSE2 is baseline in x86-x64 (as stated by Peter Cordes in the comments), so you can use it always on 64bit.

    If you want to use SIMD with XMM registers:

    movsd xmm0, QWORD PTR x
    addsd xmm0, xmm0   ; this instruction also requires SSE2   
    ; ok, retun xmm0
    

    Also note, that you also cannot mix up XMM and MMX-Registers! (The instructions MOVQ2DQ and MOVDQ2Q can convert them from one to the other but others can't)

    If your function uses parameters and if it should run on a Windows operating system, you need to ensure a valid function prolog/epilog. see: https://future2048.blogspot.com

    0 讨论(0)
提交回复
热议问题