aboutsummaryrefslogtreecommitdiff
path: root/libffi/src/x86/ffi.c
diff options
context:
space:
mode:
Diffstat (limited to 'libffi/src/x86/ffi.c')
-rw-r--r--libffi/src/x86/ffi.c162
1 files changed, 128 insertions, 34 deletions
diff --git a/libffi/src/x86/ffi.c b/libffi/src/x86/ffi.c
index feb5cbb..24431c1 100644
--- a/libffi/src/x86/ffi.c
+++ b/libffi/src/x86/ffi.c
@@ -1,5 +1,6 @@
/* -----------------------------------------------------------------------
- ffi.c - Copyright (c) 1996, 1998, 1999, 2001, 2007, 2008 Red Hat, Inc.
+ ffi.c - Copyright (c) 2017 Anthony Green
+ Copyright (c) 1996, 1998, 1999, 2001, 2007, 2008 Red Hat, Inc.
Copyright (c) 2002 Ranjit Mathew
Copyright (c) 2002 Bo Thorsen
Copyright (c) 2002 Roger Sayle
@@ -28,10 +29,12 @@
DEALINGS IN THE SOFTWARE.
----------------------------------------------------------------------- */
-#ifndef __x86_64__
+#if defined(__i386__) || defined(_M_IX86)
#include <ffi.h>
#include <ffi_common.h>
+#include <stdint.h>
#include <stdlib.h>
+#include <tramp.h>
#include "internal.h"
/* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE;
@@ -49,6 +52,13 @@
# define __declspec(x) __attribute__((x))
#endif
+#if defined(_MSC_VER) && defined(_M_IX86)
+/* Stack is not 16-byte aligned on Windows. */
+#define STACK_ALIGN(bytes) (bytes)
+#else
+#define STACK_ALIGN(bytes) FFI_ALIGN (bytes, 16)
+#endif
+
/* Perform machine dependent cif processing. */
ffi_status FFI_HIDDEN
ffi_prep_cif_machdep(ffi_cif *cif)
@@ -134,7 +144,7 @@ ffi_prep_cif_machdep(ffi_cif *cif)
break;
}
/* Allocate space for return value pointer. */
- bytes += ALIGN (sizeof(void*), FFI_SIZEOF_ARG);
+ bytes += FFI_ALIGN (sizeof(void*), FFI_SIZEOF_ARG);
}
break;
case FFI_TYPE_COMPLEX:
@@ -172,10 +182,10 @@ ffi_prep_cif_machdep(ffi_cif *cif)
{
ffi_type *t = cif->arg_types[i];
- bytes = ALIGN (bytes, t->alignment);
- bytes += ALIGN (t->size, FFI_SIZEOF_ARG);
+ bytes = FFI_ALIGN (bytes, t->alignment);
+ bytes += FFI_ALIGN (t->size, FFI_SIZEOF_ARG);
}
- cif->bytes = ALIGN (bytes, 16);
+ cif->bytes = bytes;
return FFI_OK;
}
@@ -234,12 +244,25 @@ static const struct abi_params abi_params[FFI_LAST_ABI] = {
[FFI_MS_CDECL] = { 1, R_ECX, 0 }
};
-extern void ffi_call_i386(struct call_frame *, char *)
-#if HAVE_FASTCALL
- __declspec(fastcall)
+#ifdef HAVE_FASTCALL
+ #ifdef _MSC_VER
+ #define FFI_DECLARE_FASTCALL __fastcall
+ #else
+ #define FFI_DECLARE_FASTCALL __declspec(fastcall)
+ #endif
+#else
+ #define FFI_DECLARE_FASTCALL
#endif
- FFI_HIDDEN;
+extern void FFI_DECLARE_FASTCALL ffi_call_i386(struct call_frame *, char *) FFI_HIDDEN;
+
+/* We perform some black magic here to use some of the parent's stack frame in
+ * ffi_call_i386() that breaks with the MSVC compiler with the /RTCs or /GZ
+ * flags. Disable the 'Stack frame run time error checking' for this function
+ * so we don't hit weird exceptions in debug builds. */
+#if defined(_MSC_VER)
+#pragma runtime_checks("s", off)
+#endif
static void
ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
void **avalue, void *closure)
@@ -277,7 +300,7 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
}
}
- bytes = cif->bytes;
+ bytes = STACK_ALIGN (cif->bytes);
stack = alloca(bytes + sizeof(*frame) + rsize);
argp = (dir < 0 ? stack + bytes : stack);
frame = (struct call_frame *)(stack + bytes);
@@ -334,9 +357,18 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
}
else
{
- size_t za = ALIGN (z, FFI_SIZEOF_ARG);
+ size_t za = FFI_ALIGN (z, FFI_SIZEOF_ARG);
size_t align = FFI_SIZEOF_ARG;
+ /* Issue 434: For thiscall and fastcall, if the paramter passed
+ as 64-bit integer or struct, all following integer parameters
+ will be passed on stack. */
+ if ((cabi == FFI_THISCALL || cabi == FFI_FASTCALL)
+ && (t == FFI_TYPE_SINT64
+ || t == FFI_TYPE_UINT64
+ || t == FFI_TYPE_STRUCT))
+ narg_reg = 2;
+
/* Alignment rules for arguments are quite complex. Vectors and
structures with 16 byte alignment get it. Note that long double
on Darwin does have 16 byte alignment, and does not get this
@@ -356,7 +388,7 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
}
else
{
- argp = (char *)ALIGN (argp, align);
+ argp = (char *)FFI_ALIGN (argp, align);
memcpy (argp, valp, z);
argp += za;
}
@@ -366,6 +398,9 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
ffi_call_i386 (frame, stack);
}
+#if defined(_MSC_VER)
+#pragma runtime_checks("s", restore)
+#endif
void
ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
@@ -373,18 +408,25 @@ ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
ffi_call_int (cif, fn, rvalue, avalue, NULL);
}
+#ifdef FFI_GO_CLOSURES
void
ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
void **avalue, void *closure)
{
ffi_call_int (cif, fn, rvalue, avalue, closure);
}
+#endif
/** private members **/
void FFI_HIDDEN ffi_closure_i386(void);
void FFI_HIDDEN ffi_closure_STDCALL(void);
void FFI_HIDDEN ffi_closure_REGISTER(void);
+#if defined(FFI_EXEC_STATIC_TRAMP)
+void FFI_HIDDEN ffi_closure_i386_alt(void);
+void FFI_HIDDEN ffi_closure_STDCALL_alt(void);
+void FFI_HIDDEN ffi_closure_REGISTER_alt(void);
+#endif
struct closure_frame
{
@@ -395,10 +437,7 @@ struct closure_frame
void *user_data; /* 36 */
};
-int FFI_HIDDEN
-#if HAVE_FASTCALL
-__declspec(fastcall)
-#endif
+int FFI_HIDDEN FFI_DECLARE_FASTCALL
ffi_closure_inner (struct closure_frame *frame, char *stack)
{
ffi_cif *cif = frame->cif;
@@ -415,7 +454,7 @@ ffi_closure_inner (struct closure_frame *frame, char *stack)
rvalue = frame->rettemp;
pabi = &abi_params[cabi];
dir = pabi->dir;
- argp = (dir < 0 ? stack + cif->bytes : stack);
+ argp = (dir < 0 ? stack + STACK_ALIGN (cif->bytes) : stack);
switch (flags)
{
@@ -463,13 +502,22 @@ ffi_closure_inner (struct closure_frame *frame, char *stack)
}
else
{
- size_t za = ALIGN (z, FFI_SIZEOF_ARG);
+ size_t za = FFI_ALIGN (z, FFI_SIZEOF_ARG);
size_t align = FFI_SIZEOF_ARG;
/* See the comment in ffi_call_int. */
if (t == FFI_TYPE_STRUCT && ty->alignment >= 16)
align = 16;
+ /* Issue 434: For thiscall and fastcall, if the paramter passed
+ as 64-bit integer or struct, all following integer parameters
+ will be passed on stack. */
+ if ((cabi == FFI_THISCALL || cabi == FFI_FASTCALL)
+ && (t == FFI_TYPE_SINT64
+ || t == FFI_TYPE_UINT64
+ || t == FFI_TYPE_STRUCT))
+ narg_reg = 2;
+
if (dir < 0)
{
/* ??? These reverse argument ABIs are probably too old
@@ -479,7 +527,7 @@ ffi_closure_inner (struct closure_frame *frame, char *stack)
}
else
{
- argp = (char *)ALIGN (argp, align);
+ argp = (char *)FFI_ALIGN (argp, align);
valp = argp;
argp += za;
}
@@ -490,10 +538,17 @@ ffi_closure_inner (struct closure_frame *frame, char *stack)
frame->fun (cif, rvalue, avalue, frame->user_data);
- if (cabi == FFI_STDCALL)
- return flags + (cif->bytes << X86_RET_POP_SHIFT);
- else
- return flags;
+ switch (cabi)
+ {
+ case FFI_STDCALL:
+ return flags | (cif->bytes << X86_RET_POP_SHIFT);
+ case FFI_THISCALL:
+ case FFI_FASTCALL:
+ return flags | ((cif->bytes - (narg_reg * FFI_SIZEOF_ARG))
+ << X86_RET_POP_SHIFT);
+ default:
+ return flags;
+ }
}
ffi_status
@@ -510,30 +565,51 @@ ffi_prep_closure_loc (ffi_closure* closure,
switch (cif->abi)
{
case FFI_SYSV:
- case FFI_THISCALL:
- case FFI_FASTCALL:
case FFI_MS_CDECL:
dest = ffi_closure_i386;
break;
case FFI_STDCALL:
+ case FFI_THISCALL:
+ case FFI_FASTCALL:
case FFI_PASCAL:
dest = ffi_closure_STDCALL;
break;
case FFI_REGISTER:
dest = ffi_closure_REGISTER;
op = 0x68; /* pushl imm */
+ break;
default:
return FFI_BAD_ABI;
}
+#if defined(FFI_EXEC_STATIC_TRAMP)
+ if (ffi_tramp_is_present(closure))
+ {
+ /* Initialize the static trampoline's parameters. */
+ if (dest == ffi_closure_i386)
+ dest = ffi_closure_i386_alt;
+ else if (dest == ffi_closure_STDCALL)
+ dest = ffi_closure_STDCALL_alt;
+ else
+ dest = ffi_closure_REGISTER_alt;
+ ffi_tramp_set_parms (closure->ftramp, dest, closure);
+ goto out;
+ }
+#endif
+
+ /* Initialize the dynamic trampoline. */
+ /* endbr32. */
+ *(UINT32 *) tramp = 0xfb1e0ff3;
+
/* movl or pushl immediate. */
- tramp[0] = op;
- *(void **)(tramp + 1) = codeloc;
+ tramp[4] = op;
+ *(void **)(tramp + 5) = codeloc;
/* jmp dest */
- tramp[5] = 0xe9;
- *(unsigned *)(tramp + 6) = (unsigned)dest - ((unsigned)codeloc + 10);
+ tramp[9] = 0xe9;
+ *(unsigned *)(tramp + 10) = (unsigned)dest - ((unsigned)codeloc + 14);
+out:
closure->cif = cif;
closure->fun = fun;
closure->user_data = user_data;
@@ -541,6 +617,8 @@ ffi_prep_closure_loc (ffi_closure* closure,
return FFI_OK;
}
+#ifdef FFI_GO_CLOSURES
+
void FFI_HIDDEN ffi_go_closure_EAX(void);
void FFI_HIDDEN ffi_go_closure_ECX(void);
void FFI_HIDDEN ffi_go_closure_STDCALL(void);
@@ -577,6 +655,8 @@ ffi_prep_go_closure (ffi_go_closure* closure, ffi_cif* cif,
return FFI_OK;
}
+#endif /* FFI_GO_CLOSURES */
+
/* ------- Native raw API support -------------------------------- */
#if !FFI_NO_RAW_API
@@ -669,8 +749,9 @@ ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *avalue)
}
}
- bytes = cif->bytes;
- argp = stack = alloca(bytes + sizeof(*frame) + rsize);
+ bytes = STACK_ALIGN (cif->bytes);
+ argp = stack =
+ (void *)((uintptr_t)alloca(bytes + sizeof(*frame) + rsize + 15) & ~16);
frame = (struct call_frame *)(stack + bytes);
if (rsize)
rvalue = frame + 1;
@@ -714,7 +795,7 @@ ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *avalue)
else
{
memcpy (argp, avalue, z);
- z = ALIGN (z, FFI_SIZEOF_ARG);
+ z = FFI_ALIGN (z, FFI_SIZEOF_ARG);
argp += z;
}
avalue += z;
@@ -726,4 +807,17 @@ ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *avalue)
ffi_call_i386 (frame, stack);
}
#endif /* !FFI_NO_RAW_API */
-#endif /* !__x86_64__ */
+
+#if defined(FFI_EXEC_STATIC_TRAMP)
+void *
+ffi_tramp_arch (size_t *tramp_size, size_t *map_size)
+{
+ extern void *trampoline_code_table;
+
+ *map_size = X86_TRAMP_MAP_SIZE;
+ *tramp_size = X86_TRAMP_SIZE;
+ return &trampoline_code_table;
+}
+#endif
+
+#endif /* __i386__ */