2
votes
  1. If I write a function that returns void, according to the x86-64 convention call can I spoil rax/eax?
  2. A similar question about a function that returns a double (because the real return will happen in xmm0)
  3. If I do movq xmm0 -> rax. Then I get a number which can be put to

    union { 
        int, 
        double
    };
    

    through int. Then when I read it through double, I get double that was expected. What are the pitfalls of my actions?

2
What are you asking in part 3? Are you returning a union of that type?Peter Cordes
Isn't rax 64 bits, and int 32 bits in x86-64? How are you putting 64 bits in 32 bits?MSalters
Did you read the documentation about the SysV ABI for amd64?fuz

2 Answers

3
votes

rax is a scratch register, and double is in class SSE, so it is returned in xmm0/xmm1. These are documented in the SysV ABI. Nothing prevents you from using xmm0 as scratch before placing the return value(s) to it. There are links to the ABI documents in the x86 tag wiki.

To answer #3, we need to see your code. Perhaps it's UB in C++, or perhaps your assembly is wrong.

1
votes
  1. yes, void functions can leave whatever they want in all arg-returning registers (RAX, RDX, XMM0, etc.). void means the caller shouldn't do anything with any value that you leave anywhere (except of course the call-preserved registers like RBX, RBP, and RSP).

  2. similar to what? A function can't be declared as returning void double, so IDK what you're asking.

  3. MOVQ lets you copy around the binary representation of a double. Yes, of course you can type-pun that 64-bit integer back to a double with a union in C99. But in C++, union type-punning is only legal as a GNU extension. In asm, it's all just bits that you can copy around however you want.

Note that a union with an int member is bogus for this, because that's only 32-bit in the x86-64 SysV ABI. You're presumably truncating the low 32 bits of your mantissa, so you've probably only tested this for small integers where the low bits of the mantissa are all zero anyway.

Actually, that doesn't sound right; it should be truncating the high half of the double, because x86's float byte order stores the byte that includes the sign bit at the highest address. So it shouldn't work unless you stored into the union with a 64-bit store in asm.