diff options
Diffstat (limited to 'ext/ffi_c/libffi/src/x86/ffi.c')
-rw-r--r-- | ext/ffi_c/libffi/src/x86/ffi.c | 491 |
1 files changed, 389 insertions, 102 deletions
diff --git a/ext/ffi_c/libffi/src/x86/ffi.c b/ext/ffi_c/libffi/src/x86/ffi.c index 34f9c66..006c95d 100644 --- a/ext/ffi_c/libffi/src/x86/ffi.c +++ b/ext/ffi_c/libffi/src/x86/ffi.c @@ -28,7 +28,7 @@ DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- */ -#if !defined(__x86_64__) || defined(_WIN64) +#if !defined(__x86_64__) || defined(_WIN64) || defined(__CYGWIN__) #ifdef _WIN64 #include <windows.h> @@ -39,52 +39,82 @@ #include <stdlib.h> + /* ffi_prep_args is called by the assembly routine once stack space has been allocated for the function's arguments */ -void ffi_prep_args(char *stack, extended_cif *ecif) +unsigned int ffi_prep_args(char *stack, extended_cif *ecif); +unsigned int ffi_prep_args(char *stack, extended_cif *ecif) { register unsigned int i; register void **p_argv; register char *argp; register ffi_type **p_arg; +#ifndef X86_WIN64 + const int cabi = ecif->cif->abi; + const int dir = (cabi == FFI_PASCAL || cabi == FFI_REGISTER) ? -1 : +1; + unsigned int stack_args_count = 0; + void *p_stack_data[3]; + char *argp2 = stack; +#else + #define dir 1 +#endif argp = stack; - if (ecif->cif->flags == FFI_TYPE_STRUCT + if ((ecif->cif->flags == FFI_TYPE_STRUCT + || ecif->cif->flags == FFI_TYPE_MS_STRUCT) #ifdef X86_WIN64 - && (ecif->cif->rtype->size != 1 && ecif->cif->rtype->size != 2 - && ecif->cif->rtype->size != 4 && ecif->cif->rtype->size != 8) + && ((ecif->cif->rtype->size & (1 | 2 | 4 | 8)) == 0) #endif ) { +#ifndef X86_WIN64 + /* For fastcall/thiscall/register this is first register-passed + argument. */ + if (cabi == FFI_THISCALL || cabi == FFI_FASTCALL || cabi == FFI_REGISTER) + { + p_stack_data[stack_args_count] = argp; + ++stack_args_count; + } +#endif + *(void **) argp = ecif->rvalue; argp += sizeof(void*); } + p_arg = ecif->cif->arg_types; p_argv = ecif->avalue; + if (dir < 0) + { + const int nargs = ecif->cif->nargs - 1; + if (nargs > 0) + { + p_arg += nargs; + p_argv += nargs; + } + } - for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; + for (i = ecif->cif->nargs; i != 0; - i--, p_arg++) + i--, p_arg += dir, p_argv += dir) { - size_t z; - /* Align if necessary */ if ((sizeof(void*) - 1) & (size_t) argp) argp = (char *) ALIGN(argp, sizeof(void*)); - z = (*p_arg)->size; + size_t z = (*p_arg)->size; + #ifdef X86_WIN64 - if (z > sizeof(ffi_arg) + if (z > FFI_SIZEOF_ARG || ((*p_arg)->type == FFI_TYPE_STRUCT - && (z != 1 && z != 2 && z != 4 && z != 8)) + && (z & (1 | 2 | 4 | 8)) == 0) #if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE || ((*p_arg)->type == FFI_TYPE_LONGDOUBLE) #endif ) { - z = sizeof(ffi_arg); + z = FFI_SIZEOF_ARG; *(void **)argp = *p_argv; } else if ((*p_arg)->type == FFI_TYPE_FLOAT) @@ -93,9 +123,9 @@ void ffi_prep_args(char *stack, extended_cif *ecif) } else #endif - if (z < sizeof(ffi_arg)) + if (z < FFI_SIZEOF_ARG) { - z = sizeof(ffi_arg); + z = FFI_SIZEOF_ARG; switch ((*p_arg)->type) { case FFI_TYPE_SINT8: @@ -134,15 +164,69 @@ void ffi_prep_args(char *stack, extended_cif *ecif) { memcpy(argp, *p_argv, z); } - p_argv++; + +#ifndef X86_WIN64 + /* For thiscall/fastcall/register convention register-passed arguments + are the first two none-floating-point arguments with a size + smaller or equal to sizeof (void*). */ + if ((z == FFI_SIZEOF_ARG) + && ((cabi == FFI_REGISTER) + || (cabi == FFI_THISCALL && stack_args_count < 1) + || (cabi == FFI_FASTCALL && stack_args_count < 2)) + && ((*p_arg)->type != FFI_TYPE_FLOAT && (*p_arg)->type != FFI_TYPE_STRUCT) + ) + { + if (dir < 0 && stack_args_count > 2) + { + /* Iterating arguments backwards, so first register-passed argument + will be passed last. Shift temporary values to make place. */ + p_stack_data[0] = p_stack_data[1]; + p_stack_data[1] = p_stack_data[2]; + stack_args_count = 2; + } + + p_stack_data[stack_args_count] = argp; + ++stack_args_count; + } +#endif + #ifdef X86_WIN64 argp += (z + sizeof(void*) - 1) & ~(sizeof(void*) - 1); #else argp += z; #endif } - - return; + +#ifndef X86_WIN64 + /* We need to move the register-passed arguments for thiscall/fastcall/register + on top of stack, so that those can be moved to registers by call-handler. */ + if (stack_args_count > 0) + { + if (dir < 0 && stack_args_count > 1) + { + /* Reverse order if iterating arguments backwards */ + ffi_arg tmp = *(ffi_arg*) p_stack_data[0]; + *(ffi_arg*) p_stack_data[0] = *(ffi_arg*) p_stack_data[stack_args_count - 1]; + *(ffi_arg*) p_stack_data[stack_args_count - 1] = tmp; + } + + int i; + for (i = 0; i < stack_args_count; i++) + { + if (p_stack_data[i] != argp2) + { + ffi_arg tmp = *(ffi_arg*) p_stack_data[i]; + memmove (argp2 + FFI_SIZEOF_ARG, argp2, (size_t) ((char*) p_stack_data[i] - (char*)argp2)); + *(ffi_arg *) argp2 = tmp; + } + + argp2 += FFI_SIZEOF_ARG; + } + } + + return stack_args_count; +#endif + return 0; } /* Perform machine dependent cif processing */ @@ -206,7 +290,12 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif) else #endif { - cif->flags = FFI_TYPE_STRUCT; +#ifdef X86_WIN32 + if (cif->abi == FFI_MS_CDECL) + cif->flags = FFI_TYPE_MS_STRUCT; + else +#endif + cif->flags = FFI_TYPE_STRUCT; /* allocate space for return value pointer */ cif->bytes += ALIGN(sizeof(void*), FFI_SIZEOF_ARG); } @@ -228,16 +317,19 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif) { if (((*ptr)->alignment - 1) & cif->bytes) cif->bytes = ALIGN(cif->bytes, (*ptr)->alignment); - cif->bytes += ALIGN((*ptr)->size, FFI_SIZEOF_ARG); + cif->bytes += (unsigned)ALIGN((*ptr)->size, FFI_SIZEOF_ARG); } #ifdef X86_WIN64 /* ensure space for storing four registers */ - cif->bytes += 4 * sizeof(ffi_arg); + cif->bytes += 4 * FFI_SIZEOF_ARG; #endif -#ifdef X86_DARWIN - cif->bytes = (cif->bytes + 15) & ~0xF; +#ifndef X86_WIN32 +#ifndef X86_WIN64 + if (cif->abi == FFI_SYSV || cif->abi == FFI_UNIX64) +#endif + cif->bytes = (cif->bytes + 15) & ~0xF; #endif return FFI_OK; @@ -245,13 +337,12 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif) #ifdef X86_WIN64 extern int -ffi_call_win64(void (*)(char *, extended_cif *), extended_cif *, - unsigned, unsigned, unsigned *, void (*fn)(void)); -#elif defined(X86_WIN32) -extern void -ffi_call_win32(void (*)(char *, extended_cif *), extended_cif *, +ffi_call_win64(unsigned int (*)(char *, extended_cif *), extended_cif *, unsigned, unsigned, unsigned *, void (*fn)(void)); #else +extern void +ffi_call_win32(unsigned int (*)(char *, extended_cif *), extended_cif *, + unsigned, unsigned, unsigned, unsigned *, void (*fn)(void)); extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *, unsigned, unsigned, unsigned *, void (*fn)(void)); #endif @@ -269,14 +360,14 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) #ifdef X86_WIN64 if (rvalue == NULL && cif->flags == FFI_TYPE_STRUCT - && cif->rtype->size != 1 && cif->rtype->size != 2 - && cif->rtype->size != 4 && cif->rtype->size != 8) + && ((cif->rtype->size & (1 | 2 | 4 | 8)) == 0)) { ecif.rvalue = alloca((cif->rtype->size + 0xF) & ~0xF); } #else if (rvalue == NULL - && cif->flags == FFI_TYPE_STRUCT) + && (cif->flags == FFI_TYPE_STRUCT + || cif->flags == FFI_TYPE_MS_STRUCT)) { ecif.rvalue = alloca(cif->rtype->size); } @@ -292,17 +383,24 @@ 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) - case FFI_SYSV: - case FFI_STDCALL: - ffi_call_win32(ffi_prep_args, &ecif, cif->bytes, cif->flags, - ecif.rvalue, fn); - break; #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_MS_CDECL: +#endif + case FFI_STDCALL: + case FFI_THISCALL: + case FFI_FASTCALL: + case FFI_PASCAL: + case FFI_REGISTER: + ffi_call_win32(ffi_prep_args, &ecif, cif->abi, cif->bytes, cif->flags, + ecif.rvalue, fn); + break; #endif default: FFI_ASSERT(0); @@ -314,20 +412,27 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) /** private members **/ /* The following __attribute__((regparm(1))) decorations will have no effect - on MSVC - standard cdecl convention applies. */ -static void ffi_prep_incoming_args_SYSV (char *stack, void **ret, - void** args, ffi_cif* cif); + on MSVC or SUNPRO_C -- standard conventions apply. */ +static unsigned int ffi_prep_incoming_args (char *stack, void **ret, + void** args, ffi_cif* cif); void FFI_HIDDEN ffi_closure_SYSV (ffi_closure *) __attribute__ ((regparm(1))); unsigned int FFI_HIDDEN ffi_closure_SYSV_inner (ffi_closure *, void **, void *) __attribute__ ((regparm(1))); +unsigned int FFI_HIDDEN ffi_closure_WIN32_inner (ffi_closure *, void **, void *) + __attribute__ ((regparm(1))); void FFI_HIDDEN ffi_closure_raw_SYSV (ffi_raw_closure *) __attribute__ ((regparm(1))); #ifdef X86_WIN32 -void FFI_HIDDEN ffi_closure_STDCALL (ffi_closure *) +void FFI_HIDDEN ffi_closure_raw_THISCALL (ffi_raw_closure *) __attribute__ ((regparm(1))); #endif -#ifdef X86_WIN64 +#ifndef X86_WIN64 +void FFI_HIDDEN ffi_closure_STDCALL (ffi_closure *); +void FFI_HIDDEN ffi_closure_THISCALL (ffi_closure *); +void FFI_HIDDEN ffi_closure_FASTCALL (ffi_closure *); +void FFI_HIDDEN ffi_closure_REGISTER (ffi_closure *); +#else void FFI_HIDDEN ffi_closure_win64 (ffi_closure *); #endif @@ -350,7 +455,7 @@ ffi_closure_win64_inner (ffi_closure *closure, void *args) { * a structure, it will change RESP to point to the * structure return address. */ - ffi_prep_incoming_args_SYSV(args, &resp, arg_area, cif); + ffi_prep_incoming_args(args, &resp, arg_area, cif); (closure->fun) (cif, resp, arg_area, closure->user_data); @@ -379,79 +484,165 @@ ffi_closure_SYSV_inner (ffi_closure *closure, void **respp, void *args) * a structure, it will change RESP to point to the * structure return address. */ - ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif); + ffi_prep_incoming_args(args, respp, arg_area, cif); (closure->fun) (cif, *respp, arg_area, closure->user_data); return cif->flags; } + +unsigned int FFI_HIDDEN __attribute__ ((regparm(1))) +ffi_closure_WIN32_inner (ffi_closure *closure, void **respp, void *args) +{ + /* our various things... */ + ffi_cif *cif; + void **arg_area; + unsigned int ret; + + 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 change RESP to point to the + * structure return address. */ + + ret = ffi_prep_incoming_args(args, respp, arg_area, cif); + + (closure->fun) (cif, *respp, arg_area, closure->user_data); + + return ret; +} #endif /* !X86_WIN64 */ -static void -ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, void **avalue, - ffi_cif *cif) +static unsigned int +ffi_prep_incoming_args(char *stack, void **rvalue, void **avalue, + ffi_cif *cif) { register unsigned int i; register void **p_argv; register char *argp; register ffi_type **p_arg; +#ifndef X86_WIN64 + const int cabi = cif->abi; + const int dir = (cabi == FFI_PASCAL || cabi == FFI_REGISTER) ? -1 : +1; + const unsigned int max_stack_count = (cabi == FFI_THISCALL) ? 1 + : (cabi == FFI_FASTCALL) ? 2 + : (cabi == FFI_REGISTER) ? 3 + : 0; + unsigned int passed_regs = 0; + void *p_stack_data[3] = { stack - 1 }; +#else + #define dir 1 +#endif argp = stack; +#ifndef X86_WIN64 + argp += max_stack_count * FFI_SIZEOF_ARG; +#endif + if ((cif->flags == FFI_TYPE_STRUCT + || cif->flags == FFI_TYPE_MS_STRUCT) #ifdef X86_WIN64 - if (cif->rtype->size > sizeof(ffi_arg) - || (cif->flags == FFI_TYPE_STRUCT - && (cif->rtype->size != 1 && cif->rtype->size != 2 - && cif->rtype->size != 4 && cif->rtype->size != 8))) { - *rvalue = *(void **) argp; - argp += sizeof(void *); - } -#else - if ( cif->flags == FFI_TYPE_STRUCT ) { - *rvalue = *(void **) argp; - argp += sizeof(void *); - } + && ((cif->rtype->size & (1 | 2 | 4 | 8)) == 0) +#endif + ) + { +#ifndef X86_WIN64 + if (passed_regs < max_stack_count) + { + *rvalue = *(void**) (stack + (passed_regs*FFI_SIZEOF_ARG)); + ++passed_regs; + } + else #endif + { + *rvalue = *(void **) argp; + argp += sizeof(void *); + } + } - p_argv = avalue; +#ifndef X86_WIN64 + /* Do register arguments first */ + for (i = 0, p_arg = cif->arg_types; + i < cif->nargs && passed_regs < max_stack_count; + i++, p_arg++) + { + if ((*p_arg)->type == FFI_TYPE_FLOAT + || (*p_arg)->type == FFI_TYPE_STRUCT) + continue; - for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++) + size_t sz = (*p_arg)->size; + if(sz == 0 || sz > FFI_SIZEOF_ARG) + continue; + + p_stack_data[passed_regs] = avalue + i; + avalue[i] = stack + (passed_regs*FFI_SIZEOF_ARG); + ++passed_regs; + } +#endif + + p_arg = cif->arg_types; + p_argv = avalue; + if (dir < 0) { - size_t z; + const int nargs = cif->nargs - 1; + if (nargs > 0) + { + p_arg += nargs; + p_argv += nargs; + } + } + for (i = cif->nargs; + i != 0; + i--, p_arg += dir, p_argv += dir) + { /* Align if necessary */ - if ((sizeof(void*) - 1) & (size_t) argp) { + if ((sizeof(void*) - 1) & (size_t) argp) argp = (char *) ALIGN(argp, sizeof(void*)); - } + + size_t z = (*p_arg)->size; #ifdef X86_WIN64 - if ((*p_arg)->size > sizeof(ffi_arg) + if (z > FFI_SIZEOF_ARG || ((*p_arg)->type == FFI_TYPE_STRUCT - && ((*p_arg)->size != 1 && (*p_arg)->size != 2 - && (*p_arg)->size != 4 && (*p_arg)->size != 8))) + && (z & (1 | 2 | 4 | 8)) == 0) +#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE + || ((*p_arg)->type == FFI_TYPE_LONGDOUBLE) +#endif + ) { - z = sizeof(void *); + z = FFI_SIZEOF_ARG; *p_argv = *(void **)argp; } else +#else + if (passed_regs > 0 + && z <= FFI_SIZEOF_ARG + && (p_argv == p_stack_data[0] + || p_argv == p_stack_data[1] + || p_argv == p_stack_data[2])) + { + /* Already assigned a register value */ + continue; + } + else #endif { - z = (*p_arg)->size; - /* because we're little endian, this is what it turns into. */ - *p_argv = (void*) argp; } - - p_argv++; + #ifdef X86_WIN64 argp += (z + sizeof(void*) - 1) & ~(sizeof(void*) - 1); #else argp += z; #endif } - - return; + + return (size_t)argp - (size_t)stack; } #define FFI_INIT_TRAMPOLINE_WIN64(TRAMP,FUN,CTX,MASK) \ @@ -481,22 +672,46 @@ ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, void **avalue, unsigned int __dis = __fun - (__ctx + 10); \ *(unsigned char*) &__tramp[0] = 0xb8; \ *(unsigned int*) &__tramp[1] = __ctx; /* movl __ctx, %eax */ \ - *(unsigned char *) &__tramp[5] = 0xe9; \ + *(unsigned char*) &__tramp[5] = 0xe9; \ *(unsigned int*) &__tramp[6] = __dis; /* jmp __fun */ \ } -#define FFI_INIT_TRAMPOLINE_STDCALL(TRAMP,FUN,CTX,SIZE) \ +#define FFI_INIT_TRAMPOLINE_RAW_THISCALL(TRAMP,FUN,CTX,SIZE) \ { unsigned char *__tramp = (unsigned char*)(TRAMP); \ unsigned int __fun = (unsigned int)(FUN); \ unsigned int __ctx = (unsigned int)(CTX); \ - unsigned int __dis = __fun - (__ctx + 10); \ + unsigned int __dis = __fun - (__ctx + 49); \ unsigned short __size = (unsigned short)(SIZE); \ - *(unsigned char*) &__tramp[0] = 0xb8; \ - *(unsigned int*) &__tramp[1] = __ctx; /* movl __ctx, %eax */ \ - *(unsigned char *) &__tramp[5] = 0xe8; \ - *(unsigned int*) &__tramp[6] = __dis; /* call __fun */ \ - *(unsigned char *) &__tramp[10] = 0xc2; \ - *(unsigned short*) &__tramp[11] = __size; /* ret __size */ \ + *(unsigned int *) &__tramp[0] = 0x8324048b; /* mov (%esp), %eax */ \ + *(unsigned int *) &__tramp[4] = 0x4c890cec; /* sub $12, %esp */ \ + *(unsigned int *) &__tramp[8] = 0x04890424; /* mov %ecx, 4(%esp) */ \ + *(unsigned char*) &__tramp[12] = 0x24; /* mov %eax, (%esp) */ \ + *(unsigned char*) &__tramp[13] = 0xb8; \ + *(unsigned int *) &__tramp[14] = __size; /* mov __size, %eax */ \ + *(unsigned int *) &__tramp[18] = 0x08244c8d; /* lea 8(%esp), %ecx */ \ + *(unsigned int *) &__tramp[22] = 0x4802e8c1; /* shr $2, %eax ; dec %eax */ \ + *(unsigned short*) &__tramp[26] = 0x0b74; /* jz 1f */ \ + *(unsigned int *) &__tramp[28] = 0x8908518b; /* 2b: mov 8(%ecx), %edx */ \ + *(unsigned int *) &__tramp[32] = 0x04c18311; /* mov %edx, (%ecx) ; add $4, %ecx */ \ + *(unsigned char*) &__tramp[36] = 0x48; /* dec %eax */ \ + *(unsigned short*) &__tramp[37] = 0xf575; /* jnz 2b ; 1f: */ \ + *(unsigned char*) &__tramp[39] = 0xb8; \ + *(unsigned int*) &__tramp[40] = __ctx; /* movl __ctx, %eax */ \ + *(unsigned char *) &__tramp[44] = 0xe8; \ + *(unsigned int*) &__tramp[45] = __dis; /* call __fun */ \ + *(unsigned char*) &__tramp[49] = 0xc2; /* ret */ \ + *(unsigned short*) &__tramp[50] = (__size + 8); /* ret (__size + 8) */ \ + } + +#define FFI_INIT_TRAMPOLINE_WIN32(TRAMP,FUN,CTX) \ +{ unsigned char *__tramp = (unsigned char*)(TRAMP); \ + unsigned int __fun = (unsigned int)(FUN); \ + unsigned int __ctx = (unsigned int)(CTX); \ + unsigned int __dis = __fun - (__ctx + 10); \ + *(unsigned char*) &__tramp[0] = 0x68; \ + *(unsigned int*) &__tramp[1] = __ctx; /* push __ctx */ \ + *(unsigned char*) &__tramp[5] = 0xe9; \ + *(unsigned int*) &__tramp[6] = __dis; /* jmp __fun */ \ } /* the cif must already be prep'ed */ @@ -526,12 +741,36 @@ ffi_prep_closure_loc (ffi_closure* closure, &ffi_closure_SYSV, (void*)codeloc); } -#ifdef X86_WIN32 - else if (cif->abi == FFI_STDCALL) + else if (cif->abi == FFI_REGISTER) + { + FFI_INIT_TRAMPOLINE_WIN32 (&closure->tramp[0], + &ffi_closure_REGISTER, + (void*)codeloc); + } + else if (cif->abi == FFI_FASTCALL) + { + FFI_INIT_TRAMPOLINE_WIN32 (&closure->tramp[0], + &ffi_closure_FASTCALL, + (void*)codeloc); + } + else if (cif->abi == FFI_THISCALL) + { + FFI_INIT_TRAMPOLINE_WIN32 (&closure->tramp[0], + &ffi_closure_THISCALL, + (void*)codeloc); + } + else if (cif->abi == FFI_STDCALL || cif->abi == FFI_PASCAL) { - FFI_INIT_TRAMPOLINE_STDCALL (&closure->tramp[0], + FFI_INIT_TRAMPOLINE_WIN32 (&closure->tramp[0], &ffi_closure_STDCALL, - (void*)codeloc, cif->bytes); + (void*)codeloc); + } +#ifdef X86_WIN32 + else if (cif->abi == FFI_MS_CDECL) + { + FFI_INIT_TRAMPOLINE (&closure->tramp[0], + &ffi_closure_SYSV, + (void*)codeloc); } #endif /* X86_WIN32 */ #endif /* !X86_WIN64 */ @@ -560,9 +799,12 @@ ffi_prep_raw_closure_loc (ffi_raw_closure* closure, { int i; - if (cif->abi != FFI_SYSV) { + if (cif->abi != FFI_SYSV +#ifdef X86_WIN32 + && 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 @@ -575,10 +817,19 @@ ffi_prep_raw_closure_loc (ffi_raw_closure* closure, FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_LONGDOUBLE); } - +#ifdef X86_WIN32 + if (cif->abi == FFI_SYSV) + { +#endif FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_raw_SYSV, codeloc); - +#ifdef X86_WIN32 + } + else if (cif->abi == FFI_THISCALL) + { + FFI_INIT_TRAMPOLINE_RAW_THISCALL (&closure->tramp[0], &ffi_closure_raw_THISCALL, codeloc, cif->bytes); + } +#endif closure->cif = cif; closure->user_data = user_data; closure->fun = fun; @@ -586,10 +837,38 @@ ffi_prep_raw_closure_loc (ffi_raw_closure* closure, return FFI_OK; } -static void +static unsigned int ffi_prep_args_raw(char *stack, extended_cif *ecif) { - memcpy (stack, ecif->avalue, ecif->cif->bytes); + const ffi_cif *cif = ecif->cif; + unsigned int i, passed_regs = 0; + +#ifndef X86_WIN64 + const unsigned int abi = cif->abi; + const unsigned int max_regs = (abi == FFI_THISCALL) ? 1 + : (abi == FFI_FASTCALL) ? 2 + : (abi == FFI_REGISTER) ? 3 + : 0; + + if (cif->flags == FFI_TYPE_STRUCT) + ++passed_regs; + + for (i = 0; i < cif->nargs && passed_regs <= max_regs; i++) + { + if (cif->arg_types[i]->type == FFI_TYPE_FLOAT + || cif->arg_types[i]->type == FFI_TYPE_STRUCT) + continue; + + size_t sz = cif->arg_types[i]->size; + if (sz == 0 || sz > FFI_SIZEOF_ARG) + continue; + + ++passed_regs; + } +#endif + + memcpy (stack, ecif->avalue, cif->bytes); + return passed_regs; } /* we borrow this routine from libffi (it must be changed, though, to @@ -609,8 +888,9 @@ ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *fake_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)) + if (rvalue == NULL + && (cif->flags == FFI_TYPE_STRUCT + || cif->flags == FFI_TYPE_MS_STRUCT)) { ecif.rvalue = alloca(cif->rtype->size); } @@ -620,16 +900,23 @@ 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: - case FFI_STDCALL: - ffi_call_win32(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags, - ecif.rvalue, fn); + ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags, + ecif.rvalue, fn); break; #else case FFI_SYSV: - ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags, - ecif.rvalue, fn); + case FFI_MS_CDECL: +#endif +#ifndef X86_WIN64 + case FFI_STDCALL: + case FFI_THISCALL: + case FFI_FASTCALL: + case FFI_PASCAL: + case FFI_REGISTER: + ffi_call_win32(ffi_prep_args_raw, &ecif, cif->abi, cif->bytes, cif->flags, + ecif.rvalue, fn); break; #endif default: |