I'm using an AMD 64bit (I don't think it matters what exact architecture) on Linux, also 64bit. Compiling with gcc to elf64.
I've seen from the C ABI that integer arguments are passed to a function via general purpose registers, and I can find the values on the assembly side of my code (the callee). The problem arises when I need to retrieve the results from the callee to the caller.
As far as I can understand, RAX gets the 1st integer returned value, and I can easily find and use that one. The 2nd integer returned value is passed via RDX. And this is the point that baffles me.
I can also see, from the C ABI, that RDX is the register used to pass the third integer function argument from the caller to the callee, but my function doesn't use a third argument.
How do I get the RDX out from my function? Do I have to fake an argument in the function just to be able to refer to it on the caller side?
fixed point multiplication 16.16:
called from C looks like:
typedef long int Fixedpoint;
Fixedpoint _FixedMul(Fixedpoint v1, Fixedpoint v2);
and this is the function itself:
_FixedMul:
push bp
mov bp, sp
; entering the function EDI contains v1, ESI contains v2. So:
mov eax, edi ; eax = v1
imul dword esi ; eax = v1 * v2
; at this point EDX contains the higher part of the
; imul moltiplication, EAX the lower one.
add eax, 8000h ; round by adding 2^(-17)
adc edx, 0 ; whole part of result is in DX
shr eax, 16 ; put the fractional part in AX
pop bp
ret
from System V Application Binary Interface AMD64 Architecture Processor Supplement
Returning of Values algorithm:
The returning of values is done according to the following
- Classify the return type with the classification algorithm.
- If the type has class MEMORY, then the caller provides space for the return value and passes the address of this storage in %rdi as if it were the first argument to the function. In effect, this address becomes a “hidden” first ar- gument. This storage must not overlap any data visible to the callee through other names than this argument. On return %rax will contain the address that has been passed in by the caller in %rdi.
- If the class is INTEGER, the next available register of the sequence %rax, %rdx is used.
I hope is more clear what i mean.
PS: sorry for confusion I've made in comments. Thanks for the tip.
rax
orxmm0
or in memory depending on the type. – Jester(E/R)AX
; however, if the function receives some pointers to "return" more values, those pointers will be passed as normal arguments (usually on the stack, in__stdcall
and__cdecl
, which are most common). – user4520rbp
, not just the low 16 bits! If you're not spilling any local variables to memory on the stack, don't even bother creating a stack frame by savingrsp
. – Peter Cordes