This is the mail archive of the libffi-discuss@sourceware.org mailing list for the libffi project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 06/13] x86: Rewrite ffi_call


Decouple the assembly from FFI_TYPE_*.  Merge prep_args with ffi_call,
passing the frame and the stack to the assembly.

Note that this patch isn't really standalone, as this breaks closures.
---
 src/x86/ffi.c       | 601 ++++++++++++++++++++++++++--------------------------
 src/x86/ffitarget.h |   4 -
 src/x86/internal.h  |  23 ++
 src/x86/sysv.S      | 243 ++++++++++-----------
 4 files changed, 448 insertions(+), 423 deletions(-)
 create mode 100644 src/x86/internal.h

diff --git a/src/x86/ffi.c b/src/x86/ffi.c
index 339ca89..1c77bb8 100644
--- a/src/x86/ffi.c
+++ b/src/x86/ffi.c
@@ -29,10 +29,10 @@
    ----------------------------------------------------------------------- */
 
 #ifndef __x86_64__
-
 #include <ffi.h>
 #include <ffi_common.h>
 #include <stdlib.h>
+#include "internal.h"
 
 /* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE;
    all further uses in this file will refer to the 80-bit type.  */
@@ -45,276 +45,277 @@
 # define FFI_TYPE_LONGDOUBLE 4
 #endif
 
+#if defined(__GNUC__) && !defined(__declspec)
+# define __declspec(x)  __attribute__((x))
+#endif
 
-/* ffi_prep_args is called by the assembly routine once stack space
-   has been allocated for the function's arguments */
-
-unsigned int ffi_prep_args(char *stack, extended_cif *ecif);
-unsigned int ffi_prep_args(char *stack, extended_cif *ecif)
+/* Perform machine dependent cif processing.  */
+ffi_status FFI_HIDDEN
+ffi_prep_cif_machdep(ffi_cif *cif)
 {
-  register unsigned int i;
-  register void **p_argv;
-  register char *argp;
-  register ffi_type **p_arg;
-  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;
-
-  argp = stack;
+  size_t bytes = 0;
+  int i, n, flags, cabi = cif->abi;
 
-  if ((ecif->cif->flags == FFI_TYPE_STRUCT
-       || ecif->cif->flags == FFI_TYPE_MS_STRUCT))
+  switch (cabi)
     {
-      /* 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;
-        }
-
-      *(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;
-       i != 0;
-       i--, p_arg += dir, p_argv += dir)
-    {
-      /* Align if necessary */
-      if ((sizeof(void*) - 1) & (size_t) argp)
-        argp = (char *) ALIGN(argp, sizeof(void*));
-
-      size_t z = (*p_arg)->size;
-
-      if (z < FFI_SIZEOF_ARG)
-        {
-          z = FFI_SIZEOF_ARG;
-          switch ((*p_arg)->type)
-            {
-            case FFI_TYPE_SINT8:
-              *(ffi_sarg *) argp = (ffi_sarg)*(SINT8 *)(* p_argv);
-              break;
-
-            case FFI_TYPE_UINT8:
-              *(ffi_arg *) argp = (ffi_arg)*(UINT8 *)(* p_argv);
-              break;
-
-            case FFI_TYPE_SINT16:
-              *(ffi_sarg *) argp = (ffi_sarg)*(SINT16 *)(* p_argv);
-              break;
-
-            case FFI_TYPE_UINT16:
-              *(ffi_arg *) argp = (ffi_arg)*(UINT16 *)(* p_argv);
-              break;
-
-            case FFI_TYPE_SINT32:
-              *(ffi_sarg *) argp = (ffi_sarg)*(SINT32 *)(* p_argv);
-              break;
-
-            case FFI_TYPE_UINT32:
-              *(ffi_arg *) argp = (ffi_arg)*(UINT32 *)(* p_argv);
-              break;
-
-            case FFI_TYPE_STRUCT:
-              *(ffi_arg *) argp = *(ffi_arg *)(* p_argv);
-              break;
-
-            default:
-              FFI_ASSERT(0);
-            }
-        }
-      else
-        {
-          memcpy(argp, *p_argv, z);
-        }
-
-    /* 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;
-      }
-
-      argp += z;
-    }
-
-  /* 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;
-        }
+    case FFI_SYSV:
+    case FFI_STDCALL:
+    case FFI_THISCALL:
+    case FFI_FASTCALL:
+    case FFI_MS_CDECL:
+    case FFI_PASCAL:
+    case FFI_REGISTER:
+      break;
+    default:
+      return FFI_BAD_ABI;
     }
 
-    return stack_args_count;
-    return 0;
-}
-
-/* Perform machine dependent cif processing */
-ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
-{
-  unsigned int i;
-  ffi_type **ptr;
-
-  /* Set the return type flag */
   switch (cif->rtype->type)
     {
     case FFI_TYPE_VOID:
+      flags = X86_RET_VOID;
+      break;
+    case FFI_TYPE_FLOAT:
+      flags = X86_RET_FLOAT;
+      break;
+    case FFI_TYPE_DOUBLE:
+      flags = X86_RET_DOUBLE;
+      break;
+    case FFI_TYPE_LONGDOUBLE:
+      flags = X86_RET_LDOUBLE;
+      break;
     case FFI_TYPE_UINT8:
+      flags = X86_RET_UINT8;
+      break;
     case FFI_TYPE_UINT16:
+      flags = X86_RET_UINT16;
+      break;
     case FFI_TYPE_SINT8:
+      flags = X86_RET_SINT8;
+      break;
     case FFI_TYPE_SINT16:
-    case FFI_TYPE_SINT64:
-    case FFI_TYPE_FLOAT:
-    case FFI_TYPE_DOUBLE:
-    case FFI_TYPE_LONGDOUBLE:
-      cif->flags = (unsigned) cif->rtype->type;
+      flags = X86_RET_SINT16;
       break;
-
+    case FFI_TYPE_INT:
+    case FFI_TYPE_SINT32:
+    case FFI_TYPE_UINT32:
+    case FFI_TYPE_POINTER:
+      flags = X86_RET_INT32;
+      break;
+    case FFI_TYPE_SINT64:
     case FFI_TYPE_UINT64:
-      cif->flags = FFI_TYPE_SINT64;
+      flags = X86_RET_INT64;
       break;
-
     case FFI_TYPE_STRUCT:
 #ifndef X86
       /* ??? This should be a different ABI rather than an ifdef.  */
       if (cif->rtype->size == 1)
-	cif->flags = FFI_TYPE_SMALL_STRUCT_1B;	/* same as char size */
+	flags = X86_RET_STRUCT_1B;
       else if (cif->rtype->size == 2)
-	cif->flags = FFI_TYPE_SMALL_STRUCT_2B;	/* same as short size */
+	flags = X86_RET_STRUCT_2B;
       else if (cif->rtype->size == 4)
-	cif->flags = FFI_TYPE_INT;		/* same as int type */
+	flags = X86_RET_INT32;
       else if (cif->rtype->size == 8)
-	cif->flags = FFI_TYPE_SINT64;		/* same as int64 type */
+	flags = X86_RET_INT64;
       else
 #endif
 	{
-	  if (cif->abi == FFI_MS_CDECL)
-	    cif->flags = FFI_TYPE_MS_STRUCT;
-	  else
-	    cif->flags = FFI_TYPE_STRUCT;
+	  switch (cabi)
+	    {
+	    case FFI_THISCALL:
+	    case FFI_FASTCALL:
+	    case FFI_STDCALL:
+	    case FFI_MS_CDECL:
+	      flags = X86_RET_STRUCTARG;
+	      break;
+	    default:
+	      flags = X86_RET_STRUCTPOP;
+	      break;
+	    }
 	  /* Allocate space for return value pointer.  */
-	  cif->bytes += ALIGN(sizeof(void*), FFI_SIZEOF_ARG);
+	  bytes += ALIGN (sizeof(void*), FFI_SIZEOF_ARG);
 	}
       break;
-
     default:
-      cif->flags = FFI_TYPE_INT;
-      break;
+      return FFI_BAD_TYPEDEF;
     }
+  cif->flags = flags;
 
-  for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
+  for (i = 0, n = cif->nargs; i < n; i++)
     {
-      if (((*ptr)->alignment - 1) & cif->bytes)
-        cif->bytes = ALIGN(cif->bytes, (*ptr)->alignment);
-      cif->bytes += (unsigned)ALIGN((*ptr)->size, FFI_SIZEOF_ARG);
-    }
+      ffi_type *t = cif->arg_types[i];
 
-  if (cif->abi == FFI_SYSV)
-    cif->bytes = ALIGN (cif->bytes, 15);
+      bytes = ALIGN (bytes, t->alignment);
+      bytes += ALIGN (t->size, FFI_SIZEOF_ARG);
+    }
+  cif->bytes = ALIGN (bytes, 16);
 
   return FFI_OK;
 }
 
-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));
-
-void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
+static ffi_arg
+extend_basic_type(void *arg, int type)
 {
-  extended_cif ecif;
+  switch (type)
+    {
+    case FFI_TYPE_SINT8:
+      return *(SINT8 *)arg;
+    case FFI_TYPE_UINT8:
+      return *(UINT8 *)arg;
+    case FFI_TYPE_SINT16:
+      return *(SINT16 *)arg;
+    case FFI_TYPE_UINT16:
+      return *(UINT16 *)arg;
+
+    case FFI_TYPE_SINT32:
+    case FFI_TYPE_UINT32:
+    case FFI_TYPE_POINTER:
+    case FFI_TYPE_FLOAT:
+      return *(UINT32 *)arg;
+
+    default:
+      abort();
+    }
+}
 
-  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                     */
+struct call_frame
+{
+  void *ebp;		/* 0 */
+  void *retaddr;	/* 4 */
+  void (*fn)(void);	/* 8 */
+  int flags;		/* 12 */
+  void *rvalue;		/* 16 */
+  unsigned regs[3];	/* 20-28 */
+};
+
+struct abi_params
+{
+  int dir;		/* parameter growth direction */
+  int nregs;		/* number of register parameters */
+  int regs[3];
+};
+
+static const struct abi_params abi_params[FFI_LAST_ABI] = {
+  [FFI_SYSV] = { 1, 0 },
+  [FFI_THISCALL] = { 1, 1, { R_ECX } },
+  [FFI_FASTCALL] = { 1, 2, { R_ECX, R_EDX } },
+  [FFI_STDCALL] = { 1, 0 },
+  [FFI_PASCAL] = { -1, 0 },
+  [FFI_REGISTER] = { -1, 3, { R_EAX, R_EDX, R_ECX } },
+  [FFI_MS_CDECL] = { 1, 0 }
+};
+
+extern void ffi_call_i386(struct call_frame *, char *)
+	FFI_HIDDEN __declspec(fastcall);
 
-  if (rvalue == NULL
-      && (cif->flags == FFI_TYPE_STRUCT
-          || cif->flags == FFI_TYPE_MS_STRUCT))
+void
+ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
+{
+  size_t rsize, bytes;
+  struct call_frame *frame;
+  char *stack, *argp;
+  ffi_type **arg_types;
+  int flags, cabi, i, n, dir, narg_reg;
+  const struct abi_params *pabi;
+
+  flags = cif->flags;
+  cabi = cif->abi;
+  pabi = &abi_params[cabi];
+  dir = pabi->dir;
+
+  rsize = 0;
+  if (rvalue == NULL)
     {
-      ecif.rvalue = alloca(cif->rtype->size);
+      switch (flags)
+	{
+	case X86_RET_FLOAT:
+	case X86_RET_DOUBLE:
+	case X86_RET_LDOUBLE:
+	case X86_RET_STRUCTPOP:
+	case X86_RET_STRUCTARG:
+	  /* The float cases need to pop the 387 stack.
+	     The struct cases need to pass a valid pointer to the callee.  */
+	  rsize = cif->rtype->size;
+	  break;
+	default:
+	  /* We can pretend that the callee returns nothing.  */
+	  flags = X86_RET_VOID;
+	  break;
+	}
     }
-  else
-    ecif.rvalue = rvalue;
-    
-  
-  switch (cif->abi) 
+
+  bytes = cif->bytes;
+  stack = alloca(bytes + sizeof(*frame) + rsize);
+  argp = (dir < 0 ? stack + bytes : stack);
+  frame = (struct call_frame *)(stack + bytes);
+  if (rsize)
+    rvalue = frame + 1;
+
+  frame->fn = fn;
+  frame->flags = flags;
+  frame->rvalue = rvalue;
+
+  narg_reg = 0;
+  switch (flags)
     {
-#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;
-    default:
-      FFI_ASSERT(0);
+    case X86_RET_STRUCTARG:
+      /* The pointer is passed as the first argument.  */
+      if (pabi->nregs > 0)
+	{
+	  frame->regs[pabi->regs[0]] = (unsigned)rvalue;
+	  narg_reg = 1;
+	  break;
+	}
+      /* fallthru */
+    case X86_RET_STRUCTPOP:
+      *(void **)argp = rvalue;
+      argp += sizeof(void *);
       break;
     }
+
+  arg_types = cif->arg_types;
+  for (i = 0, n = cif->nargs; i < n; i++)
+    {
+      ffi_type *ty = arg_types[i];
+      void *valp = avalue[i];
+      size_t z = ty->size;
+      int t = ty->type;
+
+      if (z <= FFI_SIZEOF_ARG && t != FFI_TYPE_STRUCT)
+        {
+	  ffi_arg val = extend_basic_type (valp, t);
+
+	  if (t != FFI_TYPE_FLOAT && narg_reg < pabi->nregs)
+	    frame->regs[pabi->regs[narg_reg++]] = val;
+	  else if (dir < 0)
+	    {
+	      argp -= 4;
+	      *(ffi_arg *)argp = val;
+	    }
+	  else
+	    {
+	      *(ffi_arg *)argp = val;
+	      argp += 4;
+	    }
+	}
+      else
+	{
+	  size_t za = ALIGN (z, FFI_SIZEOF_ARG);
+	  if (dir < 0)
+	    {
+	      argp -= za;
+	      memcpy (argp, valp, z);
+	    }
+	  else
+	    {
+	      memcpy (argp, valp, z);
+	      argp += za;
+	    }
+	}
+    }
+  FFI_ASSERT (dir > 0 || argp == stack);
+
+  ffi_call_i386 (frame, stack);
 }
 
 
@@ -641,88 +642,92 @@ ffi_prep_raw_closure_loc (ffi_raw_closure* closure,
   return FFI_OK;
 }
 
-static unsigned int 
-ffi_prep_args_raw(char *stack, extended_cif *ecif)
+void
+ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *avalue)
 {
-  const ffi_cif *cif = ecif->cif;
-  unsigned int i, passed_regs = 0;
-  
-  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++)
+  size_t rsize, bytes;
+  struct call_frame *frame;
+  char *stack, *argp;
+  ffi_type **arg_types;
+  int flags, cabi, i, n, narg_reg;
+  const struct abi_params *pabi;
+
+  flags = cif->flags;
+  cabi = cif->abi;
+  pabi = &abi_params[cabi];
+
+  rsize = 0;
+  if (rvalue == NULL)
     {
-      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;
+      switch (flags)
+	{
+	case X86_RET_FLOAT:
+	case X86_RET_DOUBLE:
+	case X86_RET_LDOUBLE:
+	case X86_RET_STRUCTPOP:
+	case X86_RET_STRUCTARG:
+	  /* The float cases need to pop the 387 stack.
+	     The struct cases need to pass a valid pointer to the callee.  */
+	  rsize = cif->rtype->size;
+	  break;
+	default:
+	  /* We can pretend that the callee returns nothing.  */
+	  flags = X86_RET_VOID;
+	  break;
+	}
     }
 
-  memcpy (stack, ecif->avalue, cif->bytes);
-  return passed_regs;
-}
-
-/* we borrow this routine from libffi (it must be changed, though, to
- * actually call the function passed in the first argument.  as of
- * libffi-1.20, this is not the case.)
- */
+  bytes = cif->bytes;
+  argp = stack = alloca(bytes + sizeof(*frame) + rsize);
+  frame = (struct call_frame *)(stack + bytes);
+  if (rsize)
+    rvalue = frame + 1;
 
-void
-ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *fake_avalue)
-{
-  extended_cif ecif;
-  void **avalue = (void **)fake_avalue;
-
-  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->flags == FFI_TYPE_STRUCT
-          || cif->flags == FFI_TYPE_MS_STRUCT))
+  narg_reg = 0;
+  switch (flags)
     {
-      ecif.rvalue = alloca(cif->rtype->size);
+    case X86_RET_STRUCTARG:
+      /* The pointer is passed as the first argument.  */
+      if (pabi->nregs > 0)
+	{
+	  frame->regs[pabi->regs[0]] = (unsigned)rvalue;
+	  narg_reg = 1;
+	  break;
+	}
+      /* fallthru */
+    case X86_RET_STRUCTPOP:
+      *(void **)argp = rvalue;
+      argp += sizeof(void *);
+      bytes -= sizeof(void *);
+      break;
     }
-  else
-    ecif.rvalue = rvalue;
-    
-  
-  switch (cif->abi) 
+
+  arg_types = cif->arg_types;
+  for (i = 0, n = cif->nargs; narg_reg < pabi->nregs && i < n; i++)
     {
-#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_MS_CDECL:
-#endif
-    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;
-    default:
-      FFI_ASSERT(0);
-      break;
+      ffi_type *ty = arg_types[i];
+      size_t z = ty->size;
+      int t = ty->type;
+
+      if (z <= FFI_SIZEOF_ARG && t != FFI_TYPE_STRUCT && t != FFI_TYPE_FLOAT)
+	{
+	  ffi_arg val = extend_basic_type (avalue, t);
+	  frame->regs[pabi->regs[narg_reg++]] = val;
+	  z = FFI_SIZEOF_ARG;
+	}
+      else
+	{
+	  memcpy (argp, avalue, z);
+	  z = ALIGN (z, FFI_SIZEOF_ARG);
+	  argp += z;
+	}
+      avalue += z;
+      bytes -= z;
     }
+  if (i < n)
+    memcpy (argp, avalue, bytes);
+
+  ffi_call_i386 (frame, stack);
 }
 #endif /* !FFI_NO_RAW_API */
 #endif /* !__x86_64__ */
diff --git a/src/x86/ffitarget.h b/src/x86/ffitarget.h
index a4c9573..91e429c 100644
--- a/src/x86/ffitarget.h
+++ b/src/x86/ffitarget.h
@@ -98,11 +98,7 @@ typedef enum ffi_abi {
   FFI_PASCAL    = 6,
   FFI_REGISTER  = 7,
   FFI_LAST_ABI,
-# ifdef _MSC_VER
   FFI_DEFAULT_ABI = FFI_MS_CDECL
-# else
-  FFI_DEFAULT_ABI = FFI_SYSV
-# endif
 #else
   FFI_FIRST_ABI = 0,
   FFI_SYSV      = 1,
diff --git a/src/x86/internal.h b/src/x86/internal.h
new file mode 100644
index 0000000..480c1d0
--- /dev/null
+++ b/src/x86/internal.h
@@ -0,0 +1,23 @@
+#define X86_RET_FLOAT		0
+#define X86_RET_DOUBLE		1
+#define X86_RET_LDOUBLE		2
+#define X86_RET_SINT8		3
+#define X86_RET_SINT16		4
+#define X86_RET_UINT8		5
+#define X86_RET_UINT16		6
+#define X86_RET_INT64		7
+#define X86_RET_INT32		8
+#define X86_RET_VOID		9
+#define X86_RET_STRUCTPOP	10
+#define X86_RET_STRUCTARG       11
+#define X86_RET_STRUCT_1B	12
+#define X86_RET_STRUCT_2B	13
+#define X86_RET_UNUSED14	14
+#define X86_RET_UNUSED15	15
+
+#define X86_RET_TYPE_MASK	15
+#define X86_RET_POP_SHIFT	4
+
+#define R_EAX	0
+#define R_EDX	1
+#define R_ECX	2
diff --git a/src/x86/sysv.S b/src/x86/sysv.S
index fd13bc0..d0b8417 100644
--- a/src/x86/sysv.S
+++ b/src/x86/sysv.S
@@ -31,143 +31,144 @@
 #include <fficonfig.h>
 #include <ffi.h>
 #include <ffi_cfi.h>
+#include "internal.h"
 
-.text
-
-.globl ffi_prep_args
+#define C2(X, Y)  X ## Y
+#define C1(X, Y)  C2(X, Y)
+#ifdef __USER_LABEL_PREFIX__
+# define C(X)     C1(__USER_LABEL_PREFIX__, X)
+#else
+# define C(X)     X
+#endif
 
-	.align 4
-.globl ffi_call_SYSV
-        .type    ffi_call_SYSV,@function
+#ifdef __ELF__
+# define ENDF(X)  .type	X,@function; .size X, . - X
+#else
+# define ENDF(X)
+#endif
 
-ffi_call_SYSV:
-	cfi_startproc
-        pushl %ebp
-	cfi_adjust_cfa_offset(4)
-	cfi_rel_offset(%ebp, 0)
-        movl  %esp,%ebp
-	cfi_def_cfa_register(%ebp)
-	/* Make room for all of the new args.  */
-	movl  16(%ebp),%ecx
-	subl  %ecx,%esp
+/* This macro allows the safe creation of jump tables without an
+   actual table.  The entry points into the table are all 8 bytes.
+   The use of ORG asserts that we're at the correct location.  */
+#define E(X)      .align 8; .org 0b + X * 8
 
-        /* Align the stack pointer to 16-bytes */
-        andl  $0xfffffff0, %esp
+	.text
+	.align	16
+	.globl	C(ffi_call_i386)
+	FFI_HIDDEN(C(ffi_call_i386))
 
-	movl  %esp,%eax
+/* This is declared as
 
-	/* Place all of the ffi_prep_args in position  */
-	pushl 12(%ebp)
-	pushl %eax
-	call  *8(%ebp)
+   void ffi_call_i386(struct ffi_call_frame *frame, char *argp)
+        __attribute__((fastcall));
 
-	/* Return stack to previous state and call the function  */
-	addl  $8,%esp	
+   This the arguments are present in
 
-	call  *28(%ebp)
+        ecx: frame
+        edx: argp
+*/
 
-	/* Load %ecx with the return type code  */
-	movl  20(%ebp),%ecx	
+C(ffi_call_i386):
+	cfi_startproc
+	movl	(%esp), %eax		/* move the return address */
+	movl	%ebp, (%ecx)		/* store %ebp into local frame */
+	movl	%eax, 4(%ecx)		/* store retaddr into local frame */
+
+	/* New stack frame based off ebp.  This is a itty bit of unwind
+	   trickery in that the CFA *has* changed.  There is no easy way
+	   to describe it correctly on entry to the function.  Fortunately,
+	   it doesn't matter too much since at all points we can correctly
+	   unwind back to ffi_call.  Note that the location to which we
+	   moved the return address is (the new) CFA-4, so from the
+	   perspective of the unwind info, it hasn't moved.  */
+	movl	%ecx, %ebp
+	cfi_def_cfa(%ebp, 8)
+	cfi_rel_offset(%ebp, 0)
 
-	/* Protect %esi.  We're going to pop it in the epilogue.  */
-	pushl %esi
+	movl	%edx, %esp		/* set outgoing argument stack */
+	movl	20+R_EAX*4(%ebp), %eax	/* set register arguments */
+	movl	20+R_EDX*4(%ebp), %edx
+	movl	20+R_ECX*4(%ebp), %ecx
 
-	/* If the return value pointer is NULL, assume no return value.  */
-	cmpl  $0,24(%ebp)
-	jne  0f
+	call	*8(%ebp)
 
-	/* Even if there is no space for the return value, we are 
-	   obliged to handle floating-point values.  */
-	cmpl  $FFI_TYPE_FLOAT,%ecx
-	jne   noretval
-	fstp  %st(0)
+	movl	12(%ebp), %ecx		/* load return type code */
+	movl	%ebx, 8(%ebp)		/* preserve %ebx */
+	cfi_rel_offset(%ebp, 8)
 
-        jmp   epilogue
+	andl	$X86_RET_TYPE_MASK, %ecx
+#ifdef __PIC__
+	call	__x86.get_pc_thunk.bx
+1:	leal	0f-1b(%ebx, %ecx, 8), %ebx
+#else
+	leal	0f(,%ecx, 8), %ebx
+#endif
+	movl	16(%ebp), %ecx		/* load result address */
+	jmp	*%ebx
 
+	.align	8
 0:
-	call  1f
-
-.Lstore_table:
-	.long	noretval-.Lstore_table	/* FFI_TYPE_VOID */
-	.long	retint-.Lstore_table	/* FFI_TYPE_INT */
-	.long	retfloat-.Lstore_table	/* FFI_TYPE_FLOAT */
-	.long	retdouble-.Lstore_table	/* FFI_TYPE_DOUBLE */
-	.long	retlongdouble-.Lstore_table	/* FFI_TYPE_LONGDOUBLE */
-	.long	retuint8-.Lstore_table	/* FFI_TYPE_UINT8 */
-	.long	retsint8-.Lstore_table	/* FFI_TYPE_SINT8 */
-	.long	retuint16-.Lstore_table	/* FFI_TYPE_UINT16 */
-	.long	retsint16-.Lstore_table	/* FFI_TYPE_SINT16 */
-	.long	retint-.Lstore_table	/* FFI_TYPE_UINT32 */
-	.long	retint-.Lstore_table	/* FFI_TYPE_SINT32 */
-	.long	retint64-.Lstore_table	/* FFI_TYPE_UINT64 */
-	.long	retint64-.Lstore_table	/* FFI_TYPE_SINT64 */
-	.long	retstruct-.Lstore_table	/* FFI_TYPE_STRUCT */
-	.long	retint-.Lstore_table	/* FFI_TYPE_POINTER */
-
-1:
-	pop  %esi
-	add  (%esi, %ecx, 4), %esi
-	jmp  *%esi
-
-	/* Sign/zero extend as appropriate.  */
-retsint8:
-	movsbl  %al, %eax
-	jmp  retint
-
-retsint16:
-	movswl  %ax, %eax
-	jmp  retint
-
-retuint8:
-	movzbl  %al, %eax
-	jmp  retint
-
-retuint16:
-	movzwl  %ax, %eax
-	jmp  retint
-
-retfloat:
-	/* Load %ecx with the pointer to storage for the return value  */
-	movl  24(%ebp),%ecx	
-	fstps (%ecx)
-	jmp   epilogue
-
-retdouble:
-	/* Load %ecx with the pointer to storage for the return value  */
-	movl  24(%ebp),%ecx	
-	fstpl (%ecx)
-	jmp   epilogue
-
-retlongdouble:
-	/* Load %ecx with the pointer to storage for the return value  */
-	movl  24(%ebp),%ecx	
-	fstpt (%ecx)
-	jmp   epilogue
-	
-retint64:	
-	/* Load %ecx with the pointer to storage for the return value  */
-	movl  24(%ebp),%ecx	
-	movl  %eax,0(%ecx)
-	movl  %edx,4(%ecx)
-	jmp   epilogue
-	
-retint:
-	/* Load %ecx with the pointer to storage for the return value  */
-	movl  24(%ebp),%ecx	
-	movl  %eax,0(%ecx)
-
-retstruct:
-	/* Nothing to do!  */
-
-noretval:
-epilogue:
-        popl %esi
-        movl %ebp,%esp
-        popl %ebp
-        ret
+E(X86_RET_FLOAT)
+	fstps	(%ecx)
+	jmp	9f
+E(X86_RET_DOUBLE)
+	fstpl	(%ecx)
+	jmp	9f
+E(X86_RET_LDOUBLE)
+	fstpt	(%ecx)
+	jmp	9f
+E(X86_RET_SINT8)
+	movsbl	%al, %eax
+	mov	%eax, (%ecx)
+	jmp	9f
+E(X86_RET_SINT16)
+	movswl	%ax, %eax
+	mov	%eax, (%ecx)
+	jmp	9f
+E(X86_RET_UINT8)
+	movzbl	%al, %eax
+	mov	%eax, (%ecx)
+	jmp	9f
+E(X86_RET_UINT16)
+	movzwl	%ax, %eax
+	mov	%eax, (%ecx)
+	jmp	9f
+E(X86_RET_INT64)
+	movl	%edx, 4(%ecx)
+	/* fallthru */
+E(X86_RET_INT32)
+	movl	%eax, (%ecx)
+	/* fallthru */
+E(X86_RET_VOID)
+9:	movl	8(%ebp), %ebx
+	movl	%ebp, %esp
+	popl	%ebp
+	cfi_remember_state
+	cfi_def_cfa(%esp, 4)
+	cfi_restore(%ebx)
+	cfi_restore(%ebp)
+	ret
+	cfi_restore_state
+
+E(X86_RET_STRUCTPOP)
+	jmp	9b
+E(X86_RET_STRUCTARG)
+	jmp	9b
+E(X86_RET_STRUCT_1B)
+	movb	%al, (%ecx)
+	jmp	9b
+E(X86_RET_STRUCT_2B)
+	movw	%ax, (%ecx)
+	jmp	9b
+
+	/* Fill out the table so that bad values are predictable.  */
+E(X86_RET_UNUSED14)
+	ud2
+E(X86_RET_UNUSED15)
+	ud2
+
 	cfi_endproc
-.ffi_call_SYSV_end:
-        .size    ffi_call_SYSV,.ffi_call_SYSV_end-ffi_call_SYSV
+ENDF(C(ffi_call_i386))
 
 	.align	4
 FFI_HIDDEN (ffi_closure_SYSV)
-- 
1.9.3


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]