added libffi for win support

This commit is contained in:
Araq 2013-12-19 01:00:51 +01:00
commit e2a4d591e5
22 changed files with 7192 additions and 10 deletions

View file

@ -0,0 +1,457 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 1996, 1998, 1999, 2001 Red Hat, Inc.
Copyright (c) 2002 Ranjit Mathew
Copyright (c) 2002 Bo Thorsen
Copyright (c) 2002 Roger Sayle
x86 Foreign Function Interface
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
``Software''), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
----------------------------------------------------------------------- */
#include <ffi.h>
#include <ffi_common.h>
#include <stdlib.h>
/* ffi_prep_args is called by the assembly routine once stack space
has been allocated for the function's arguments */
extern void Py_FatalError(const char *msg);
/*@-exportheader@*/
void ffi_prep_args(char *stack, extended_cif *ecif)
/*@=exportheader@*/
{
register unsigned int i;
register void **p_argv;
register char *argp;
register ffi_type **p_arg;
argp = stack;
if (ecif->cif->rtype->type == FFI_TYPE_STRUCT)
{
*(void **) argp = ecif->rvalue;
argp += sizeof(void *);
}
p_argv = ecif->avalue;
for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
i != 0;
i--, p_arg++)
{
size_t z;
/* Align if necessary */
if ((sizeof(void *) - 1) & (size_t) argp)
argp = (char *) ALIGN(argp, sizeof(void *));
z = (*p_arg)->size;
if (z < sizeof(int))
{
z = sizeof(int);
switch ((*p_arg)->type)
{
case FFI_TYPE_SINT8:
*(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
break;
case FFI_TYPE_UINT8:
*(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
break;
case FFI_TYPE_SINT16:
*(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
break;
case FFI_TYPE_UINT16:
*(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
break;
case FFI_TYPE_SINT32:
*(signed int *) argp = (signed int)*(SINT32 *)(* p_argv);
break;
case FFI_TYPE_UINT32:
*(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
break;
case FFI_TYPE_STRUCT:
*(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
break;
default:
FFI_ASSERT(0);
}
}
else
{
memcpy(argp, *p_argv, z);
}
p_argv++;
argp += z;
}
if (argp >= stack && (unsigned)(argp - stack) > ecif->cif->bytes)
{
Py_FatalError("FFI BUG: not enough stack space for arguments");
}
return;
}
/* Perform machine dependent cif processing */
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
{
/* Set the return type flag */
switch (cif->rtype->type)
{
case FFI_TYPE_VOID:
case FFI_TYPE_STRUCT:
case FFI_TYPE_SINT64:
case FFI_TYPE_FLOAT:
case FFI_TYPE_DOUBLE:
case FFI_TYPE_LONGDOUBLE:
cif->flags = (unsigned) cif->rtype->type;
break;
case FFI_TYPE_UINT64:
#ifdef _WIN64
case FFI_TYPE_POINTER:
#endif
cif->flags = FFI_TYPE_SINT64;
break;
default:
cif->flags = FFI_TYPE_INT;
break;
}
return FFI_OK;
}
#ifdef _WIN32
extern int
ffi_call_x86(void (*)(char *, extended_cif *),
/*@out@*/ extended_cif *,
unsigned, unsigned,
/*@out@*/ unsigned *,
void (*fn)());
#endif
#ifdef _WIN64
extern int
ffi_call_AMD64(void (*)(char *, extended_cif *),
/*@out@*/ extended_cif *,
unsigned, unsigned,
/*@out@*/ unsigned *,
void (*fn)());
#endif
int
ffi_call(/*@dependent@*/ ffi_cif *cif,
void (*fn)(),
/*@out@*/ void *rvalue,
/*@dependent@*/ void **avalue)
{
extended_cif ecif;
ecif.cif = cif;
ecif.avalue = avalue;
/* If the return value is a struct and we don't have a return */
/* value address then we need to make one */
if ((rvalue == NULL) &&
(cif->rtype->type == FFI_TYPE_STRUCT))
{
/*@-sysunrecog@*/
ecif.rvalue = alloca(cif->rtype->size);
/*@=sysunrecog@*/
}
else
ecif.rvalue = rvalue;
switch (cif->abi)
{
#if !defined(_WIN64)
case FFI_SYSV:
case FFI_STDCALL:
return ffi_call_x86(ffi_prep_args, &ecif, cif->bytes,
cif->flags, ecif.rvalue, fn);
break;
#else
case FFI_SYSV:
/*@-usedef@*/
/* Function call needs at least 40 bytes stack size, on win64 AMD64 */
return ffi_call_AMD64(ffi_prep_args, &ecif, cif->bytes ? cif->bytes : 40,
cif->flags, ecif.rvalue, fn);
/*@=usedef@*/
break;
#endif
default:
FFI_ASSERT(0);
break;
}
return -1; /* theller: Hrm. */
}
/** private members **/
static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
void** args, ffi_cif* cif);
/* This function is jumped to by the trampoline */
#ifdef _WIN64
void *
#else
static void __fastcall
#endif
ffi_closure_SYSV (ffi_closure *closure, int *argp)
{
// this is our return value storage
long double res;
// our various things...
ffi_cif *cif;
void **arg_area;
unsigned short rtype;
void *resp = (void*)&res;
void *args = &argp[1];
cif = closure->cif;
arg_area = (void**) alloca (cif->nargs * sizeof (void*));
/* this call will initialize ARG_AREA, such that each
* element in that array points to the corresponding
* value on the stack; and if the function returns
* a structure, it will re-set RESP to point to the
* structure return address. */
ffi_prep_incoming_args_SYSV(args, (void**)&resp, arg_area, cif);
(closure->fun) (cif, resp, arg_area, closure->user_data);
rtype = cif->flags;
#if defined(_WIN32) && !defined(_WIN64)
#ifdef _MSC_VER
/* now, do a generic return based on the value of rtype */
if (rtype == FFI_TYPE_INT)
{
_asm mov eax, resp ;
_asm mov eax, [eax] ;
}
else if (rtype == FFI_TYPE_FLOAT)
{
_asm mov eax, resp ;
_asm fld DWORD PTR [eax] ;
// asm ("flds (%0)" : : "r" (resp) : "st" );
}
else if (rtype == FFI_TYPE_DOUBLE)
{
_asm mov eax, resp ;
_asm fld QWORD PTR [eax] ;
// asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" );
}
else if (rtype == FFI_TYPE_LONGDOUBLE)
{
// asm ("fldt (%0)" : : "r" (resp) : "st", "st(1)" );
}
else if (rtype == FFI_TYPE_SINT64)
{
_asm mov edx, resp ;
_asm mov eax, [edx] ;
_asm mov edx, [edx + 4] ;
// asm ("movl 0(%0),%%eax;"
// "movl 4(%0),%%edx"
// : : "r"(resp)
// : "eax", "edx");
}
#else
/* now, do a generic return based on the value of rtype */
if (rtype == FFI_TYPE_INT)
{
asm ("movl (%0),%%eax" : : "r" (resp) : "eax");
}
else if (rtype == FFI_TYPE_FLOAT)
{
asm ("flds (%0)" : : "r" (resp) : "st" );
}
else if (rtype == FFI_TYPE_DOUBLE)
{
asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" );
}
else if (rtype == FFI_TYPE_LONGDOUBLE)
{
asm ("fldt (%0)" : : "r" (resp) : "st", "st(1)" );
}
else if (rtype == FFI_TYPE_SINT64)
{
asm ("movl 0(%0),%%eax;"
"movl 4(%0),%%edx"
: : "r"(resp)
: "eax", "edx");
}
#endif
#endif
#ifdef _WIN64
/* The result is returned in rax. This does the right thing for
result types except for floats; we have to 'mov xmm0, rax' in the
caller to correct this.
*/
return *(void **)resp;
#endif
}
/*@-exportheader@*/
static void
ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
void **avalue, ffi_cif *cif)
/*@=exportheader@*/
{
register unsigned int i;
register void **p_argv;
register char *argp;
register ffi_type **p_arg;
argp = stack;
if ( cif->rtype->type == FFI_TYPE_STRUCT ) {
*rvalue = *(void **) argp;
argp += 4;
}
p_argv = avalue;
for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
{
size_t z;
/* Align if necessary */
if ((sizeof(char *) - 1) & (size_t) argp) {
argp = (char *) ALIGN(argp, sizeof(char*));
}
z = (*p_arg)->size;
/* because we're little endian, this is what it turns into. */
*p_argv = (void*) argp;
p_argv++;
argp += z;
}
return;
}
/* the cif must already be prep'ed */
extern void ffi_closure_OUTER();
ffi_status
ffi_prep_closure_loc (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*,void*,void**,void*),
void *user_data,
void *codeloc)
{
short bytes;
char *tramp;
#ifdef _WIN64
int mask = 0;
#endif
FFI_ASSERT (cif->abi == FFI_SYSV);
if (cif->abi == FFI_SYSV)
bytes = 0;
#if !defined(_WIN64)
else if (cif->abi == FFI_STDCALL)
bytes = cif->bytes;
#endif
else
return FFI_BAD_ABI;
tramp = &closure->tramp[0];
#define BYTES(text) memcpy(tramp, text, sizeof(text)), tramp += sizeof(text)-1
#define POINTER(x) *(void**)tramp = (void*)(x), tramp += sizeof(void*)
#define SHORT(x) *(short*)tramp = x, tramp += sizeof(short)
#define INT(x) *(int*)tramp = x, tramp += sizeof(int)
#ifdef _WIN64
if (cif->nargs >= 1 &&
(cif->arg_types[0]->type == FFI_TYPE_FLOAT
|| cif->arg_types[0]->type == FFI_TYPE_DOUBLE))
mask |= 1;
if (cif->nargs >= 2 &&
(cif->arg_types[1]->type == FFI_TYPE_FLOAT
|| cif->arg_types[1]->type == FFI_TYPE_DOUBLE))
mask |= 2;
if (cif->nargs >= 3 &&
(cif->arg_types[2]->type == FFI_TYPE_FLOAT
|| cif->arg_types[2]->type == FFI_TYPE_DOUBLE))
mask |= 4;
if (cif->nargs >= 4 &&
(cif->arg_types[3]->type == FFI_TYPE_FLOAT
|| cif->arg_types[3]->type == FFI_TYPE_DOUBLE))
mask |= 8;
/* 41 BB ---- mov r11d,mask */
BYTES("\x41\xBB"); INT(mask);
/* 48 B8 -------- mov rax, closure */
BYTES("\x48\xB8"); POINTER(closure);
/* 49 BA -------- mov r10, ffi_closure_OUTER */
BYTES("\x49\xBA"); POINTER(ffi_closure_OUTER);
/* 41 FF E2 jmp r10 */
BYTES("\x41\xFF\xE2");
#else
/* mov ecx, closure */
BYTES("\xb9"); POINTER(closure);
/* mov edx, esp */
BYTES("\x8b\xd4");
/* call ffi_closure_SYSV */
BYTES("\xe8"); POINTER((char*)&ffi_closure_SYSV - (tramp + 4));
/* ret bytes */
BYTES("\xc2");
SHORT(bytes);
#endif
if (tramp - &closure->tramp[0] > FFI_TRAMPOLINE_SIZE)
Py_FatalError("FFI_TRAMPOLINE_SIZE too small in " __FILE__);
closure->cif = cif;
closure->user_data = user_data;
closure->fun = fun;
return FFI_OK;
}

View file

@ -0,0 +1,175 @@
/* -----------------------------------------------------------------------
prep_cif.c - Copyright (c) 1996, 1998 Red Hat, Inc.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
``Software''), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
----------------------------------------------------------------------- */
#include <ffi.h>
#include <ffi_common.h>
#include <stdlib.h>
/* Round up to FFI_SIZEOF_ARG. */
#define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG)
/* Perform machine independent initialization of aggregate type
specifications. */
static ffi_status initialize_aggregate(/*@out@*/ ffi_type *arg)
{
ffi_type **ptr;
FFI_ASSERT(arg != NULL);
/*@-usedef@*/
FFI_ASSERT(arg->elements != NULL);
FFI_ASSERT(arg->size == 0);
FFI_ASSERT(arg->alignment == 0);
ptr = &(arg->elements[0]);
while ((*ptr) != NULL)
{
if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK))
return FFI_BAD_TYPEDEF;
/* Perform a sanity check on the argument type */
FFI_ASSERT_VALID_TYPE(*ptr);
arg->size = ALIGN(arg->size, (*ptr)->alignment);
arg->size += (*ptr)->size;
arg->alignment = (arg->alignment > (*ptr)->alignment) ?
arg->alignment : (*ptr)->alignment;
ptr++;
}
/* Structure size includes tail padding. This is important for
structures that fit in one register on ABIs like the PowerPC64
Linux ABI that right justify small structs in a register.
It's also needed for nested structure layout, for example
struct A { long a; char b; }; struct B { struct A x; char y; };
should find y at an offset of 2*sizeof(long) and result in a
total size of 3*sizeof(long). */
arg->size = ALIGN (arg->size, arg->alignment);
if (arg->size == 0)
return FFI_BAD_TYPEDEF;
else
return FFI_OK;
/*@=usedef@*/
}
/* Perform machine independent ffi_cif preparation, then call
machine dependent routine. */
ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif,
ffi_abi abi, unsigned int nargs,
/*@dependent@*/ /*@out@*/ /*@partial@*/ ffi_type *rtype,
/*@dependent@*/ ffi_type **atypes)
{
unsigned bytes = 0;
unsigned int i;
ffi_type **ptr;
FFI_ASSERT(cif != NULL);
FFI_ASSERT((abi > FFI_FIRST_ABI) && (abi <= FFI_DEFAULT_ABI));
cif->abi = abi;
cif->arg_types = atypes;
cif->nargs = nargs;
cif->rtype = rtype;
cif->flags = 0;
/* Initialize the return type if necessary */
/*@-usedef@*/
if ((cif->rtype->size == 0) && (initialize_aggregate(cif->rtype) != FFI_OK))
return FFI_BAD_TYPEDEF;
/*@=usedef@*/
/* Perform a sanity check on the return type */
FFI_ASSERT_VALID_TYPE(cif->rtype);
/* x86-64 and s390 stack space allocation is handled in prep_machdep. */
#if !defined M68K && !defined __x86_64__ && !defined S390
/* Make space for the return structure pointer */
if (cif->rtype->type == FFI_TYPE_STRUCT
/* MSVC returns small structures in registers. But we have a different
workaround: pretend int32 or int64 return type, and converting to
structure afterwards. */
#ifdef SPARC
&& (cif->abi != FFI_V9 || cif->rtype->size > 32)
#endif
)
bytes = STACK_ARG_SIZE(sizeof(void*));
#endif
for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
{
/* Initialize any uninitialized aggregate type definitions */
if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK))
return FFI_BAD_TYPEDEF;
/* Perform a sanity check on the argument type, do this
check after the initialization. */
FFI_ASSERT_VALID_TYPE(*ptr);
#if !defined __x86_64__ && !defined S390
#ifdef SPARC
if (((*ptr)->type == FFI_TYPE_STRUCT
&& ((*ptr)->size > 16 || cif->abi != FFI_V9))
|| ((*ptr)->type == FFI_TYPE_LONGDOUBLE
&& cif->abi != FFI_V9))
bytes += sizeof(void*);
else
#endif
{
#if !defined(_MSC_VER) && !defined(__MINGW32__)
/* Don't know if this is a libffi bug or not. At least on
Windows with MSVC, function call parameters are *not*
aligned in the same way as structure fields are, they are
only aligned in integer boundaries.
This doesn't do any harm for cdecl functions and closures,
since the caller cleans up the stack, but it is wrong for
stdcall functions where the callee cleans.
*/
/* Add any padding if necessary */
if (((*ptr)->alignment - 1) & bytes)
bytes = ALIGN(bytes, (*ptr)->alignment);
#endif
bytes += STACK_ARG_SIZE((*ptr)->size);
}
#endif
}
cif->bytes = bytes;
/* Perform machine dependent cif processing */
return ffi_prep_cif_machdep(cif);
}

View file

@ -0,0 +1,104 @@
/* -----------------------------------------------------------------------
types.c - Copyright (c) 1996, 1998 Red Hat, Inc.
Predefined ffi_types needed by libffi.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
``Software''), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
----------------------------------------------------------------------- */
#include <ffi.h>
#include <ffi_common.h>
/* Type definitions */
#define FFI_INTEGRAL_TYPEDEF(n, s, a, t) ffi_type ffi_type_##n = { s, a, t, NULL }
#define FFI_AGGREGATE_TYPEDEF(n, e) ffi_type ffi_type_##n = { 0, 0, FFI_TYPE_STRUCT, e }
/* Size and alignment are fake here. They must not be 0. */
FFI_INTEGRAL_TYPEDEF(void, 1, 1, FFI_TYPE_VOID);
FFI_INTEGRAL_TYPEDEF(uint8, 1, 1, FFI_TYPE_UINT8);
FFI_INTEGRAL_TYPEDEF(sint8, 1, 1, FFI_TYPE_SINT8);
FFI_INTEGRAL_TYPEDEF(uint16, 2, 2, FFI_TYPE_UINT16);
FFI_INTEGRAL_TYPEDEF(sint16, 2, 2, FFI_TYPE_SINT16);
FFI_INTEGRAL_TYPEDEF(uint32, 4, 4, FFI_TYPE_UINT32);
FFI_INTEGRAL_TYPEDEF(sint32, 4, 4, FFI_TYPE_SINT32);
FFI_INTEGRAL_TYPEDEF(float, 4, 4, FFI_TYPE_FLOAT);
#if defined ALPHA || defined SPARC64 || defined X86_64 || defined S390X \
|| defined IA64
FFI_INTEGRAL_TYPEDEF(pointer, 8, 8, FFI_TYPE_POINTER);
#else
FFI_INTEGRAL_TYPEDEF(pointer, 4, 4, FFI_TYPE_POINTER);
#endif
#if defined X86 || defined X86_WIN32 || defined ARM || defined M68K
FFI_INTEGRAL_TYPEDEF(uint64, 8, 4, FFI_TYPE_UINT64);
FFI_INTEGRAL_TYPEDEF(sint64, 8, 4, FFI_TYPE_SINT64);
#elif defined SH
FFI_INTEGRAL_TYPEDEF(uint64, 8, 4, FFI_TYPE_UINT64);
FFI_INTEGRAL_TYPEDEF(sint64, 8, 4, FFI_TYPE_SINT64);
#else
FFI_INTEGRAL_TYPEDEF(uint64, 8, 8, FFI_TYPE_UINT64);
FFI_INTEGRAL_TYPEDEF(sint64, 8, 8, FFI_TYPE_SINT64);
#endif
#if defined X86 || defined X86_WIN32 || defined M68K
FFI_INTEGRAL_TYPEDEF(double, 8, 4, FFI_TYPE_DOUBLE);
FFI_INTEGRAL_TYPEDEF(longdouble, 12, 4, FFI_TYPE_LONGDOUBLE);
#elif defined ARM || defined SH || defined POWERPC_AIX || defined POWERPC_DARWIN
FFI_INTEGRAL_TYPEDEF(double, 8, 4, FFI_TYPE_DOUBLE);
FFI_INTEGRAL_TYPEDEF(longdouble, 8, 4, FFI_TYPE_LONGDOUBLE);
#elif defined SPARC
FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE);
#ifdef SPARC64
FFI_INTEGRAL_TYPEDEF(longdouble, 16, 16, FFI_TYPE_LONGDOUBLE);
#else
FFI_INTEGRAL_TYPEDEF(longdouble, 16, 8, FFI_TYPE_LONGDOUBLE);
#endif
#elif defined X86_64
FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE);
FFI_INTEGRAL_TYPEDEF(longdouble, 16, 16, FFI_TYPE_LONGDOUBLE);
#else
FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE);
FFI_INTEGRAL_TYPEDEF(longdouble, 8, 8, FFI_TYPE_LONGDOUBLE);
#endif

View file

@ -0,0 +1,162 @@
/* -----------------------------------------------------------------------
win32.S - Copyright (c) 1996, 1998, 2001, 2002 Red Hat, Inc.
Copyright (c) 2001 John Beniton
Copyright (c) 2002 Ranjit Mathew
X86 Foreign Function Interface
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
``Software''), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
----------------------------------------------------------------------- */
/* theller: almost verbatim translation from gas syntax to MSVC inline
assembler code. */
/* theller: ffi_call_x86 now returns an integer - the difference of the stack
pointer before and after the function call. If everything is ok, zero is
returned. If stdcall functions are passed the wrong number of arguments,
the difference will be nonzero. */
#include <ffi.h>
#include <ffi_common.h>
__declspec(naked) int
ffi_call_x86(void (* prepfunc)(char *, extended_cif *), /* 8 */
extended_cif *ecif, /* 12 */
unsigned bytes, /* 16 */
unsigned flags, /* 20 */
unsigned *rvalue, /* 24 */
void (*fn)()) /* 28 */
{
_asm {
push ebp
mov ebp, esp
push esi // NEW: this register must be preserved across function calls
// XXX SAVE ESP NOW!
mov esi, esp // save stack pointer before the call
// Make room for all of the new args.
mov ecx, [ebp+16]
sub esp, ecx // sub esp, bytes
mov eax, esp
// Place all of the ffi_prep_args in position
push [ebp + 12] // ecif
push eax
call [ebp + 8] // prepfunc
// Return stack to previous state and call the function
add esp, 8
// FIXME: Align the stack to a 128-bit boundary to avoid
// potential performance hits.
call [ebp + 28]
// Load ecif->cif->abi
mov ecx, [ebp + 12]
mov ecx, [ecx]ecif.cif
mov ecx, [ecx]ecif.cif.abi
cmp ecx, FFI_STDCALL
je noclean
// STDCALL: Remove the space we pushed for the args
mov ecx, [ebp + 16]
add esp, ecx
// CDECL: Caller has already cleaned the stack
noclean:
// Check that esp has the same value as before!
sub esi, esp
// Load %ecx with the return type code
mov ecx, [ebp + 20]
// If the return value pointer is NULL, assume no return value.
/*
Intel asm is weird. We have to explicitely specify 'DWORD PTR' in the nexr instruction,
otherwise only one BYTE will be compared (instead of a DWORD)!
*/
cmp DWORD PTR [ebp + 24], 0
jne sc_retint
// Even if there is no space for the return value, we are
// obliged to handle floating-point values.
cmp ecx, FFI_TYPE_FLOAT
jne sc_noretval
// fstp %st(0)
fstp st(0)
jmp sc_epilogue
sc_retint:
cmp ecx, FFI_TYPE_INT
jne sc_retfloat
// # Load %ecx with the pointer to storage for the return value
mov ecx, [ebp + 24]
mov [ecx + 0], eax
jmp sc_epilogue
sc_retfloat:
cmp ecx, FFI_TYPE_FLOAT
jne sc_retdouble
// Load %ecx with the pointer to storage for the return value
mov ecx, [ebp+24]
// fstps (%ecx)
fstp DWORD PTR [ecx]
jmp sc_epilogue
sc_retdouble:
cmp ecx, FFI_TYPE_DOUBLE
jne sc_retlongdouble
// movl 24(%ebp),%ecx
mov ecx, [ebp+24]
fstp QWORD PTR [ecx]
jmp sc_epilogue
jmp sc_retlongdouble // avoid warning about unused label
sc_retlongdouble:
cmp ecx, FFI_TYPE_LONGDOUBLE
jne sc_retint64
// Load %ecx with the pointer to storage for the return value
mov ecx, [ebp+24]
// fstpt (%ecx)
fstp QWORD PTR [ecx] /* XXX ??? */
jmp sc_epilogue
sc_retint64:
cmp ecx, FFI_TYPE_SINT64
jne sc_retstruct
// Load %ecx with the pointer to storage for the return value
mov ecx, [ebp+24]
mov [ecx+0], eax
mov [ecx+4], edx
sc_retstruct:
// Nothing to do!
sc_noretval:
sc_epilogue:
mov eax, esi
pop esi // NEW restore: must be preserved across function calls
mov esp, ebp
pop ebp
ret
}
}

View file

@ -0,0 +1,470 @@
/* -----------------------------------------------------------------------
win32.S - Copyright (c) 1996, 1998, 2001, 2002, 2009 Red Hat, Inc.
Copyright (c) 2001 John Beniton
Copyright (c) 2002 Ranjit Mathew
Copyright (c) 2009 Daniel Witte
X86 Foreign Function Interface
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
``Software''), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
-----------------------------------------------------------------------
*/
#define LIBFFI_ASM
#include <fficonfig.h>
#include <ffi.h>
.386
.MODEL FLAT, C
EXTRN ffi_closure_SYSV_inner:NEAR
_TEXT SEGMENT
ffi_call_win32 PROC NEAR,
ffi_prep_args : NEAR PTR DWORD,
ecif : NEAR PTR DWORD,
cif_abi : DWORD,
cif_bytes : DWORD,
cif_flags : DWORD,
rvalue : NEAR PTR DWORD,
fn : NEAR PTR DWORD
;; Make room for all of the new args.
mov ecx, cif_bytes
sub esp, ecx
mov eax, esp
;; Place all of the ffi_prep_args in position
push ecif
push eax
call ffi_prep_args
;; Return stack to previous state and call the function
add esp, 8
;; Handle thiscall and fastcall
cmp cif_abi, 3 ;; FFI_THISCALL
jz do_thiscall
cmp cif_abi, 4 ;; FFI_FASTCALL
jnz do_stdcall
mov ecx, DWORD PTR [esp]
mov edx, DWORD PTR [esp+4]
add esp, 8
jmp do_stdcall
do_thiscall:
mov ecx, DWORD PTR [esp]
add esp, 4
do_stdcall:
call fn
;; cdecl: we restore esp in the epilogue, so there's no need to
;; remove the space we pushed for the args.
;; stdcall: the callee has already cleaned the stack.
;; Load ecx with the return type code
mov ecx, cif_flags
;; If the return value pointer is NULL, assume no return value.
cmp rvalue, 0
jne ca_jumptable
;; Even if there is no space for the return value, we are
;; obliged to handle floating-point values.
cmp ecx, FFI_TYPE_FLOAT
jne ca_epilogue
fstp st(0)
jmp ca_epilogue
ca_jumptable:
jmp [ca_jumpdata + 4 * ecx]
ca_jumpdata:
;; Do not insert anything here between label and jump table.
dd offset ca_epilogue ;; FFI_TYPE_VOID
dd offset ca_retint ;; FFI_TYPE_INT
dd offset ca_retfloat ;; FFI_TYPE_FLOAT
dd offset ca_retdouble ;; FFI_TYPE_DOUBLE
dd offset ca_retlongdouble ;; FFI_TYPE_LONGDOUBLE
dd offset ca_retuint8 ;; FFI_TYPE_UINT8
dd offset ca_retsint8 ;; FFI_TYPE_SINT8
dd offset ca_retuint16 ;; FFI_TYPE_UINT16
dd offset ca_retsint16 ;; FFI_TYPE_SINT16
dd offset ca_retint ;; FFI_TYPE_UINT32
dd offset ca_retint ;; FFI_TYPE_SINT32
dd offset ca_retint64 ;; FFI_TYPE_UINT64
dd offset ca_retint64 ;; FFI_TYPE_SINT64
dd offset ca_epilogue ;; FFI_TYPE_STRUCT
dd offset ca_retint ;; FFI_TYPE_POINTER
dd offset ca_retstruct1b ;; FFI_TYPE_SMALL_STRUCT_1B
dd offset ca_retstruct2b ;; FFI_TYPE_SMALL_STRUCT_2B
dd offset ca_retint ;; FFI_TYPE_SMALL_STRUCT_4B
dd offset ca_epilogue ;; FFI_TYPE_MS_STRUCT
/* Sign/zero extend as appropriate. */
ca_retuint8:
movzx eax, al
jmp ca_retint
ca_retsint8:
movsx eax, al
jmp ca_retint
ca_retuint16:
movzx eax, ax
jmp ca_retint
ca_retsint16:
movsx eax, ax
jmp ca_retint
ca_retint:
;; Load %ecx with the pointer to storage for the return value
mov ecx, rvalue
mov [ecx + 0], eax
jmp ca_epilogue
ca_retint64:
;; Load %ecx with the pointer to storage for the return value
mov ecx, rvalue
mov [ecx + 0], eax
mov [ecx + 4], edx
jmp ca_epilogue
ca_retfloat:
;; Load %ecx with the pointer to storage for the return value
mov ecx, rvalue
fstp DWORD PTR [ecx]
jmp ca_epilogue
ca_retdouble:
;; Load %ecx with the pointer to storage for the return value
mov ecx, rvalue
fstp QWORD PTR [ecx]
jmp ca_epilogue
ca_retlongdouble:
;; Load %ecx with the pointer to storage for the return value
mov ecx, rvalue
fstp TBYTE PTR [ecx]
jmp ca_epilogue
ca_retstruct1b:
;; Load %ecx with the pointer to storage for the return value
mov ecx, rvalue
mov [ecx + 0], al
jmp ca_epilogue
ca_retstruct2b:
;; Load %ecx with the pointer to storage for the return value
mov ecx, rvalue
mov [ecx + 0], ax
jmp ca_epilogue
ca_epilogue:
;; Epilogue code is autogenerated.
ret
ffi_call_win32 ENDP
ffi_closure_THISCALL PROC NEAR FORCEFRAME
sub esp, 40
lea edx, [ebp -24]
mov [ebp - 12], edx /* resp */
lea edx, [ebp + 12] /* account for stub return address on stack */
jmp stub
ffi_closure_THISCALL ENDP
ffi_closure_SYSV PROC NEAR FORCEFRAME
;; the ffi_closure ctx is passed in eax by the trampoline.
sub esp, 40
lea edx, [ebp - 24]
mov [ebp - 12], edx ;; resp
lea edx, [ebp + 8]
stub::
mov [esp + 8], edx ;; args
lea edx, [ebp - 12]
mov [esp + 4], edx ;; &resp
mov [esp], eax ;; closure
call ffi_closure_SYSV_inner
mov ecx, [ebp - 12]
cs_jumptable:
jmp [cs_jumpdata + 4 * eax]
cs_jumpdata:
;; Do not insert anything here between the label and jump table.
dd offset cs_epilogue ;; FFI_TYPE_VOID
dd offset cs_retint ;; FFI_TYPE_INT
dd offset cs_retfloat ;; FFI_TYPE_FLOAT
dd offset cs_retdouble ;; FFI_TYPE_DOUBLE
dd offset cs_retlongdouble ;; FFI_TYPE_LONGDOUBLE
dd offset cs_retuint8 ;; FFI_TYPE_UINT8
dd offset cs_retsint8 ;; FFI_TYPE_SINT8
dd offset cs_retuint16 ;; FFI_TYPE_UINT16
dd offset cs_retsint16 ;; FFI_TYPE_SINT16
dd offset cs_retint ;; FFI_TYPE_UINT32
dd offset cs_retint ;; FFI_TYPE_SINT32
dd offset cs_retint64 ;; FFI_TYPE_UINT64
dd offset cs_retint64 ;; FFI_TYPE_SINT64
dd offset cs_retstruct ;; FFI_TYPE_STRUCT
dd offset cs_retint ;; FFI_TYPE_POINTER
dd offset cs_retsint8 ;; FFI_TYPE_SMALL_STRUCT_1B
dd offset cs_retsint16 ;; FFI_TYPE_SMALL_STRUCT_2B
dd offset cs_retint ;; FFI_TYPE_SMALL_STRUCT_4B
dd offset cs_retmsstruct ;; FFI_TYPE_MS_STRUCT
cs_retuint8:
movzx eax, BYTE PTR [ecx]
jmp cs_epilogue
cs_retsint8:
movsx eax, BYTE PTR [ecx]
jmp cs_epilogue
cs_retuint16:
movzx eax, WORD PTR [ecx]
jmp cs_epilogue
cs_retsint16:
movsx eax, WORD PTR [ecx]
jmp cs_epilogue
cs_retint:
mov eax, [ecx]
jmp cs_epilogue
cs_retint64:
mov eax, [ecx + 0]
mov edx, [ecx + 4]
jmp cs_epilogue
cs_retfloat:
fld DWORD PTR [ecx]
jmp cs_epilogue
cs_retdouble:
fld QWORD PTR [ecx]
jmp cs_epilogue
cs_retlongdouble:
fld TBYTE PTR [ecx]
jmp cs_epilogue
cs_retstruct:
;; Caller expects us to pop struct return value pointer hidden arg.
;; Epilogue code is autogenerated.
ret 4
cs_retmsstruct:
;; Caller expects us to return a pointer to the real return value.
mov eax, ecx
;; Caller doesn't expects us to pop struct return value pointer hidden arg.
jmp cs_epilogue
cs_epilogue:
;; Epilogue code is autogenerated.
ret
ffi_closure_SYSV ENDP
#if !FFI_NO_RAW_API
#define RAW_CLOSURE_CIF_OFFSET ((FFI_TRAMPOLINE_SIZE + 3) AND NOT 3)
#define RAW_CLOSURE_FUN_OFFSET (RAW_CLOSURE_CIF_OFFSET + 4)
#define RAW_CLOSURE_USER_DATA_OFFSET (RAW_CLOSURE_FUN_OFFSET + 4)
#define CIF_FLAGS_OFFSET 20
ffi_closure_raw_THISCALL PROC NEAR USES esi FORCEFRAME
sub esp, 36
mov esi, [eax + RAW_CLOSURE_CIF_OFFSET] ;; closure->cif
mov edx, [eax + RAW_CLOSURE_USER_DATA_OFFSET] ;; closure->user_data
mov [esp + 12], edx
lea edx, [ebp + 12]
jmp stubraw
ffi_closure_raw_THISCALL ENDP
ffi_closure_raw_SYSV PROC NEAR USES esi FORCEFRAME
;; the ffi_closure ctx is passed in eax by the trampoline.
sub esp, 40
mov esi, [eax + RAW_CLOSURE_CIF_OFFSET] ;; closure->cif
mov edx, [eax + RAW_CLOSURE_USER_DATA_OFFSET] ;; closure->user_data
mov [esp + 12], edx ;; user_data
lea edx, [ebp + 8]
stubraw::
mov [esp + 8], edx ;; raw_args
lea edx, [ebp - 24]
mov [esp + 4], edx ;; &res
mov [esp], esi ;; cif
call DWORD PTR [eax + RAW_CLOSURE_FUN_OFFSET] ;; closure->fun
mov eax, [esi + CIF_FLAGS_OFFSET] ;; cif->flags
lea ecx, [ebp - 24]
cr_jumptable:
jmp [cr_jumpdata + 4 * eax]
cr_jumpdata:
;; Do not insert anything here between the label and jump table.
dd offset cr_epilogue ;; FFI_TYPE_VOID
dd offset cr_retint ;; FFI_TYPE_INT
dd offset cr_retfloat ;; FFI_TYPE_FLOAT
dd offset cr_retdouble ;; FFI_TYPE_DOUBLE
dd offset cr_retlongdouble ;; FFI_TYPE_LONGDOUBLE
dd offset cr_retuint8 ;; FFI_TYPE_UINT8
dd offset cr_retsint8 ;; FFI_TYPE_SINT8
dd offset cr_retuint16 ;; FFI_TYPE_UINT16
dd offset cr_retsint16 ;; FFI_TYPE_SINT16
dd offset cr_retint ;; FFI_TYPE_UINT32
dd offset cr_retint ;; FFI_TYPE_SINT32
dd offset cr_retint64 ;; FFI_TYPE_UINT64
dd offset cr_retint64 ;; FFI_TYPE_SINT64
dd offset cr_epilogue ;; FFI_TYPE_STRUCT
dd offset cr_retint ;; FFI_TYPE_POINTER
dd offset cr_retsint8 ;; FFI_TYPE_SMALL_STRUCT_1B
dd offset cr_retsint16 ;; FFI_TYPE_SMALL_STRUCT_2B
dd offset cr_retint ;; FFI_TYPE_SMALL_STRUCT_4B
dd offset cr_epilogue ;; FFI_TYPE_MS_STRUCT
cr_retuint8:
movzx eax, BYTE PTR [ecx]
jmp cr_epilogue
cr_retsint8:
movsx eax, BYTE PTR [ecx]
jmp cr_epilogue
cr_retuint16:
movzx eax, WORD PTR [ecx]
jmp cr_epilogue
cr_retsint16:
movsx eax, WORD PTR [ecx]
jmp cr_epilogue
cr_retint:
mov eax, [ecx]
jmp cr_epilogue
cr_retint64:
mov eax, [ecx + 0]
mov edx, [ecx + 4]
jmp cr_epilogue
cr_retfloat:
fld DWORD PTR [ecx]
jmp cr_epilogue
cr_retdouble:
fld QWORD PTR [ecx]
jmp cr_epilogue
cr_retlongdouble:
fld TBYTE PTR [ecx]
jmp cr_epilogue
cr_epilogue:
;; Epilogue code is autogenerated.
ret
ffi_closure_raw_SYSV ENDP
#endif /* !FFI_NO_RAW_API */
ffi_closure_STDCALL PROC NEAR FORCEFRAME
;; the ffi_closure ctx is passed in eax by the trampoline.
sub esp, 40
lea edx, [ebp - 24]
mov [ebp - 12], edx ;; resp
lea edx, [ebp + 12] ;; account for stub return address on stack
mov [esp + 8], edx ;; args
lea edx, [ebp - 12]
mov [esp + 4], edx ;; &resp
mov [esp], eax ;; closure
call ffi_closure_SYSV_inner
mov ecx, [ebp - 12]
cd_jumptable:
jmp [cd_jumpdata + 4 * eax]
cd_jumpdata:
;; Do not insert anything here between the label and jump table.
dd offset cd_epilogue ;; FFI_TYPE_VOID
dd offset cd_retint ;; FFI_TYPE_INT
dd offset cd_retfloat ;; FFI_TYPE_FLOAT
dd offset cd_retdouble ;; FFI_TYPE_DOUBLE
dd offset cd_retlongdouble ;; FFI_TYPE_LONGDOUBLE
dd offset cd_retuint8 ;; FFI_TYPE_UINT8
dd offset cd_retsint8 ;; FFI_TYPE_SINT8
dd offset cd_retuint16 ;; FFI_TYPE_UINT16
dd offset cd_retsint16 ;; FFI_TYPE_SINT16
dd offset cd_retint ;; FFI_TYPE_UINT32
dd offset cd_retint ;; FFI_TYPE_SINT32
dd offset cd_retint64 ;; FFI_TYPE_UINT64
dd offset cd_retint64 ;; FFI_TYPE_SINT64
dd offset cd_epilogue ;; FFI_TYPE_STRUCT
dd offset cd_retint ;; FFI_TYPE_POINTER
dd offset cd_retsint8 ;; FFI_TYPE_SMALL_STRUCT_1B
dd offset cd_retsint16 ;; FFI_TYPE_SMALL_STRUCT_2B
dd offset cd_retint ;; FFI_TYPE_SMALL_STRUCT_4B
cd_retuint8:
movzx eax, BYTE PTR [ecx]
jmp cd_epilogue
cd_retsint8:
movsx eax, BYTE PTR [ecx]
jmp cd_epilogue
cd_retuint16:
movzx eax, WORD PTR [ecx]
jmp cd_epilogue
cd_retsint16:
movsx eax, WORD PTR [ecx]
jmp cd_epilogue
cd_retint:
mov eax, [ecx]
jmp cd_epilogue
cd_retint64:
mov eax, [ecx + 0]
mov edx, [ecx + 4]
jmp cd_epilogue
cd_retfloat:
fld DWORD PTR [ecx]
jmp cd_epilogue
cd_retdouble:
fld QWORD PTR [ecx]
jmp cd_epilogue
cd_retlongdouble:
fld TBYTE PTR [ecx]
jmp cd_epilogue
cd_epilogue:
;; Epilogue code is autogenerated.
ret
ffi_closure_STDCALL ENDP
_TEXT ENDS
END

View file

@ -0,0 +1,156 @@
PUBLIC ffi_call_AMD64
EXTRN __chkstk:NEAR
EXTRN ffi_closure_SYSV:NEAR
_TEXT SEGMENT
;;; ffi_closure_OUTER will be called with these registers set:
;;; rax points to 'closure'
;;; r11 contains a bit mask that specifies which of the
;;; first four parameters are float or double
;;;
;;; It must move the parameters passed in registers to their stack location,
;;; call ffi_closure_SYSV for the actual work, then return the result.
;;;
ffi_closure_OUTER PROC FRAME
;; save actual arguments to their stack space.
test r11, 1
jne first_is_float
mov QWORD PTR [rsp+8], rcx
jmp second
first_is_float:
movlpd QWORD PTR [rsp+8], xmm0
second:
test r11, 2
jne second_is_float
mov QWORD PTR [rsp+16], rdx
jmp third
second_is_float:
movlpd QWORD PTR [rsp+16], xmm1
third:
test r11, 4
jne third_is_float
mov QWORD PTR [rsp+24], r8
jmp forth
third_is_float:
movlpd QWORD PTR [rsp+24], xmm2
forth:
test r11, 8
jne forth_is_float
mov QWORD PTR [rsp+32], r9
jmp done
forth_is_float:
movlpd QWORD PTR [rsp+32], xmm3
done:
.ALLOCSTACK 40
sub rsp, 40
.ENDPROLOG
mov rcx, rax ; context is first parameter
mov rdx, rsp ; stack is second parameter
add rdx, 40 ; correct our own area
mov rax, ffi_closure_SYSV
call rax ; call the real closure function
;; Here, code is missing that handles float return values
add rsp, 40
movd xmm0, rax ; In case the closure returned a float.
ret 0
ffi_closure_OUTER ENDP
;;; ffi_call_AMD64
stack$ = 0
prepfunc$ = 32
ecif$ = 40
bytes$ = 48
flags$ = 56
rvalue$ = 64
fn$ = 72
ffi_call_AMD64 PROC FRAME
mov QWORD PTR [rsp+32], r9
mov QWORD PTR [rsp+24], r8
mov QWORD PTR [rsp+16], rdx
mov QWORD PTR [rsp+8], rcx
.PUSHREG rbp
push rbp
.ALLOCSTACK 48
sub rsp, 48 ; 00000030H
.SETFRAME rbp, 32
lea rbp, QWORD PTR [rsp+32]
.ENDPROLOG
mov eax, DWORD PTR bytes$[rbp]
add rax, 15
and rax, -16
call __chkstk
sub rsp, rax
lea rax, QWORD PTR [rsp+32]
mov QWORD PTR stack$[rbp], rax
mov rdx, QWORD PTR ecif$[rbp]
mov rcx, QWORD PTR stack$[rbp]
call QWORD PTR prepfunc$[rbp]
mov rsp, QWORD PTR stack$[rbp]
movlpd xmm3, QWORD PTR [rsp+24]
movd r9, xmm3
movlpd xmm2, QWORD PTR [rsp+16]
movd r8, xmm2
movlpd xmm1, QWORD PTR [rsp+8]
movd rdx, xmm1
movlpd xmm0, QWORD PTR [rsp]
movd rcx, xmm0
call QWORD PTR fn$[rbp]
ret_int$:
cmp DWORD PTR flags$[rbp], 1 ; FFI_TYPE_INT
jne ret_float$
mov rcx, QWORD PTR rvalue$[rbp]
mov DWORD PTR [rcx], eax
jmp SHORT ret_nothing$
ret_float$:
cmp DWORD PTR flags$[rbp], 2 ; FFI_TYPE_FLOAT
jne SHORT ret_double$
mov rax, QWORD PTR rvalue$[rbp]
movlpd QWORD PTR [rax], xmm0
jmp SHORT ret_nothing$
ret_double$:
cmp DWORD PTR flags$[rbp], 3 ; FFI_TYPE_DOUBLE
jne SHORT ret_int64$
mov rax, QWORD PTR rvalue$[rbp]
movlpd QWORD PTR [rax], xmm0
jmp SHORT ret_nothing$
ret_int64$:
cmp DWORD PTR flags$[rbp], 12 ; FFI_TYPE_SINT64
jne ret_nothing$
mov rcx, QWORD PTR rvalue$[rbp]
mov QWORD PTR [rcx], rax
jmp SHORT ret_nothing$
ret_nothing$:
xor eax, eax
lea rsp, QWORD PTR [rbp+16]
pop rbp
ret 0
ffi_call_AMD64 ENDP
_TEXT ENDS
END