I have an assembly application for Linux x64 where I pass arguments to the functions via registers, thus I'm using a certain calling convention, in this case fastcall
. Now I want to call a C function from the assembly application which, say, expects 10 arguments.
Do I have to switch to cdecl
for that and pass the arguments via stack regardless of the fact everywhere else in my application I'm passing them via registers? Is it allowed to mix calling conventions in one application?
I assume that by fastcall, you mean the amd64 calling convention used by the SysV ABI (i.e. what Linux uses) where the first few arguments are passed in rdi
, rsi
, and rdx
.
The ABI is slightly complicated, the following is a simplification. You might want to read the specification for details.
Generally speaking, the first few (leftmost) integer or pointer arguments are placed into the registers rdi
, rsi
, rdx
, rcx
, r8
, and r9
. Floating point arguments are passed in xmm0
to xmm7
. If the register space is exhausted, additional arguments are passed through the stack from right to left. For example, to call a function with 10 integer arguments:
foo(a, b, c, d, e, f, g, h, i, k);
you would need code like this:
mov $a,%edi
mov $b,%esi
mov $c,%edx
mov $d,%ecx
mov $e,%r8d
mov $f,%r9d
push $k
push $i
push $h
push $g
call foo
add $32,%rsp
For your concrete example, of getnameinfo
:
int getnameinfo(
const struct sockaddr *sa,
socklen_t salen,
char *host,
size_t hostlen,
char *serv,
size_t servlen,
int flags);
You would pass sa
in rdi
, salen
in rsi
, host
in rdx
, hostlen
in rcx
, serv
in r8
, servlen
in r9
and flags
on the stack.