Add support for stdcall, thiscall, and fastcall on non-Windows x86-32

Linux supports the stdcall calling convention, either via functions
explicitly declared with the stdcall attribute, or via code compiled
with -mrtd which effectively makes stdcall the default.

This introduces FFI_STDCALL, FFI_THISCALL, and FFI_FASTCALL on
non-Windows x86-32 platforms, as non-default calling conventions.
This commit is contained in:
Josh Triplett
2014-03-16 03:25:53 -07:00
parent 9531d05f64
commit e1911f78df
16 changed files with 126 additions and 75 deletions

View File

@@ -50,7 +50,7 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
register void **p_argv;
register char *argp;
register ffi_type **p_arg;
#ifdef X86_WIN32
#ifndef X86_WIN64
size_t p_stack_args[2];
void *p_stack_data[2];
char *argp2 = stack;
@@ -69,7 +69,7 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
)
{
*(void **) argp = ecif->rvalue;
#ifdef X86_WIN32
#ifndef X86_WIN64
/* For fastcall/thiscall this is first register-passed
argument. */
if (cabi == FFI_THISCALL || cabi == FFI_FASTCALL)
@@ -155,7 +155,7 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
memcpy(argp, *p_argv, z);
}
#ifdef X86_WIN32
#ifndef X86_WIN64
/* For thiscall/fastcall convention register-passed arguments
are the first two none-floating-point arguments with a size
smaller or equal to sizeof (void*). */
@@ -180,7 +180,7 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
#endif
}
#ifdef X86_WIN32
#ifndef X86_WIN64
/* We need to move the register-passed arguments for thiscall/fastcall
on top of stack, so that those can be moved to registers ecx/edx by
call-handler. */
@@ -318,7 +318,8 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
#endif
#ifndef X86_WIN32
cif->bytes = (cif->bytes + 15) & ~0xF;
if (cif->abi != FFI_STDCALL && cif->abi != FFI_THISCALL && cif->abi != FFI_FASTCALL)
cif->bytes = (cif->bytes + 15) & ~0xF;
#endif
return FFI_OK;
@@ -328,11 +329,10 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
extern int
ffi_call_win64(void (*)(char *, extended_cif *), extended_cif *,
unsigned, unsigned, unsigned *, void (*fn)(void));
#elif defined(X86_WIN32)
#else
extern void
ffi_call_win32(void (*)(char *, extended_cif *), extended_cif *,
unsigned, unsigned, unsigned, unsigned *, void (*fn)(void));
#else
extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
unsigned, unsigned, unsigned *, void (*fn)(void));
#endif
@@ -374,10 +374,17 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
ffi_call_win64(ffi_prep_args, &ecif, cif->bytes,
cif->flags, ecif.rvalue, fn);
break;
#elif defined(X86_WIN32)
#else
#ifndef X86_WIN32
case FFI_SYSV:
ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue,
fn);
break;
#else
case FFI_SYSV:
case FFI_STDCALL:
case FFI_MS_CDECL:
#endif
case FFI_STDCALL:
ffi_call_win32(ffi_prep_args, &ecif, cif->abi, cif->bytes, cif->flags,
ecif.rvalue, fn);
break;
@@ -410,11 +417,6 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
ecif.rvalue, fn);
}
break;
#else
case FFI_SYSV:
ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue,
fn);
break;
#endif
default:
FFI_ASSERT(0);
@@ -435,15 +437,14 @@ unsigned int FFI_HIDDEN ffi_closure_SYSV_inner (ffi_closure *, void **, void *)
__attribute__ ((regparm(1)));
void FFI_HIDDEN ffi_closure_raw_SYSV (ffi_raw_closure *)
__attribute__ ((regparm(1)));
#ifdef X86_WIN32
#ifndef X86_WIN64
void FFI_HIDDEN ffi_closure_raw_THISCALL (ffi_raw_closure *)
__attribute__ ((regparm(1)));
void FFI_HIDDEN ffi_closure_STDCALL (ffi_closure *)
__attribute__ ((regparm(1)));
void FFI_HIDDEN ffi_closure_THISCALL (ffi_closure *)
__attribute__ ((regparm(1)));
#endif
#ifdef X86_WIN64
#else
void FFI_HIDDEN ffi_closure_win64 (ffi_closure *);
#endif
@@ -670,7 +671,6 @@ ffi_prep_closure_loc (ffi_closure* closure,
&ffi_closure_SYSV,
(void*)codeloc);
}
#ifdef X86_WIN32
else if (cif->abi == FFI_THISCALL)
{
FFI_INIT_TRAMPOLINE_THISCALL (&closure->tramp[0],
@@ -684,6 +684,7 @@ ffi_prep_closure_loc (ffi_closure* closure,
&ffi_closure_STDCALL,
(void*)codeloc, cif->bytes);
}
#ifdef X86_WIN32
else if (cif->abi == FFI_MS_CDECL)
{
FFI_INIT_TRAMPOLINE (&closure->tramp[0],
@@ -717,12 +718,12 @@ ffi_prep_raw_closure_loc (ffi_raw_closure* closure,
{
int i;
if (cif->abi != FFI_SYSV) {
#ifdef X86_WIN32
if (cif->abi != FFI_THISCALL)
if (cif->abi != FFI_SYSV
#ifndef X86_WIN64
&& cif->abi != FFI_THISCALL
#endif
)
return FFI_BAD_ABI;
}
/* we currently don't support certain kinds of arguments for raw
closures. This should be implemented by a separate assembly
@@ -735,13 +736,13 @@ ffi_prep_raw_closure_loc (ffi_raw_closure* closure,
FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_LONGDOUBLE);
}
#ifdef X86_WIN32
#ifndef X86_WIN64
if (cif->abi == FFI_SYSV)
{
#endif
FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_raw_SYSV,
codeloc);
#ifdef X86_WIN32
#ifndef X86_WIN64
}
else if (cif->abi == FFI_THISCALL)
{
@@ -791,10 +792,17 @@ ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *fake_avalue)
switch (cif->abi)
{
#ifdef X86_WIN32
#ifndef X86_WIN32
case FFI_SYSV:
ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags,
ecif.rvalue, fn);
break;
#else
case FFI_SYSV:
case FFI_STDCALL:
case FFI_MS_CDECL:
#endif
#ifndef X86_WIN64
case FFI_STDCALL:
ffi_call_win32(ffi_prep_args_raw, &ecif, cif->abi, cif->bytes, cif->flags,
ecif.rvalue, fn);
break;
@@ -827,11 +835,6 @@ ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *fake_avalue)
ecif.rvalue, fn);
}
break;
#else
case FFI_SYSV:
ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags,
ecif.rvalue, fn);
break;
#endif
default:
FFI_ASSERT(0);