;; x86.cdecl.64.s: x86-64 cdecl impl
; vim: ft=nasm
%macro ccall 1-*
%if %0 > ccall.reg.ct
%assign ct ccall.reg.ct
%else
%assign ct %0-1
%endif
%assign i 0
%rotate 1
%rep ct
; if the function is well-behaved, all its arguments fit
; in registers. if not, things get ugly. see below.
mov ccall.reg. %+ i, %1
%assign i i+1
%rotate 1
%endrep
%if %0 > ccall.reg.ct
; if there are more parameters to a C function than the
; number of permitted registers, they must be pushed in
; reverse order to the stack.
; keep your function signatures under control, people.
%assign ct (%0-ct)-1
%rotate ct
%rep ct
%rotate -1
push %1
%endrep
%rotate ct
push rsp ; it's our responsibility to preserve the stack
%endif
call %1
%if %0 > ccall.reg.ct
; the extra arguments are still on the stack; time to
; dump them back into the Garbage Zone
pop rsp
%endif
%endmacro
; register order for ccall convention
%define ccall.reg.ct 6
%define ccall.reg.ret rdi
%define ccall.reg.0 rdi
%define ccall.reg.1 rsi
%define ccall.reg.2 rdx
%define ccall.reg.3 rcx
%define ccall.reg.4 r8
%define ccall.reg.5 r9