OSDN Git Service

2009-06-05 Andrew Haley <aph@redhat.com>
[pf3gnuchains/gcc-fork.git] / libffi / src / x86 / ffi.c
index 14b0295..767effb 100644 (file)
@@ -1,10 +1,11 @@
 /* -----------------------------------------------------------------------
-   ffi.c - Copyright (c) 1996, 1998, 1999, 2001  Red Hat, Inc.
+   ffi.c - 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
-   
-   x86 Foreign Function Interface 
+          Copyright (C) 2008  Free Software Foundation, Inc.
+
+   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
    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.
+   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.
    ----------------------------------------------------------------------- */
 
 #ifndef __x86_64__
@@ -36,9 +38,7 @@
 /* ffi_prep_args is called by the assembly routine once stack space
    has been allocated for the function's arguments */
 
-/*@-exportheader@*/
 void ffi_prep_args(char *stack, extended_cif *ecif)
-/*@=exportheader@*/
 {
   register unsigned int i;
   register void **p_argv;
@@ -47,7 +47,7 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
 
   argp = stack;
 
-  if (ecif->cif->rtype->type == FFI_TYPE_STRUCT)
+  if (ecif->cif->flags == FFI_TYPE_STRUCT)
     {
       *(void **) argp = ecif->rvalue;
       argp += 4;
@@ -121,7 +121,16 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
   switch (cif->rtype->type)
     {
     case FFI_TYPE_VOID:
+#ifdef X86
     case FFI_TYPE_STRUCT:
+#endif
+#if defined(X86) || defined(X86_DARWIN)
+    case FFI_TYPE_UINT8:
+    case FFI_TYPE_UINT16:
+    case FFI_TYPE_SINT8:
+    case FFI_TYPE_SINT16:
+#endif
+
     case FFI_TYPE_SINT64:
     case FFI_TYPE_FLOAT:
     case FFI_TYPE_DOUBLE:
@@ -133,40 +142,53 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
       cif->flags = FFI_TYPE_SINT64;
       break;
 
+#ifndef X86
+    case FFI_TYPE_STRUCT:
+      if (cif->rtype->size == 1)
+        {
+          cif->flags = FFI_TYPE_SMALL_STRUCT_1B; /* same as char size */
+        }
+      else if (cif->rtype->size == 2)
+        {
+          cif->flags = FFI_TYPE_SMALL_STRUCT_2B; /* same as short size */
+        }
+      else if (cif->rtype->size == 4)
+        {
+          cif->flags = FFI_TYPE_INT; /* same as int type */
+        }
+      else if (cif->rtype->size == 8)
+        {
+          cif->flags = FFI_TYPE_SINT64; /* same as int64 type */
+        }
+      else
+        {
+          cif->flags = FFI_TYPE_STRUCT;
+        }
+      break;
+#endif
+
     default:
       cif->flags = FFI_TYPE_INT;
       break;
     }
 
+#ifdef X86_DARWIN
+  cif->bytes = (cif->bytes + 15) & ~0xF;
+#endif
+
   return FFI_OK;
 }
 
-/*@-declundef@*/
-/*@-exportheader@*/
-extern void ffi_call_SYSV(void (*)(char *, extended_cif *), 
-                         /*@out@*/ extended_cif *, 
-                         unsigned, unsigned, 
-                         /*@out@*/ unsigned *, 
-                         void (*fn)());
-/*@=declundef@*/
-/*@=exportheader@*/
+extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
+                         unsigned, unsigned, unsigned *, void (*fn)(void));
 
 #ifdef X86_WIN32
-/*@-declundef@*/
-/*@-exportheader@*/
-extern void ffi_call_STDCALL(void (*)(char *, extended_cif *),
-                         /*@out@*/ extended_cif *,
-                         unsigned, unsigned,
-                         /*@out@*/ unsigned *,
-                         void (*fn)());
-/*@=declundef@*/
-/*@=exportheader@*/
+extern void ffi_call_STDCALL(void (*)(char *, extended_cif *), extended_cif *,
+                         unsigned, unsigned, unsigned *, void (*fn)(void));
+
 #endif /* X86_WIN32 */
 
-void ffi_call(/*@dependent@*/ ffi_cif *cif, 
-             void (*fn)(), 
-             /*@out@*/ void *rvalue, 
-             /*@dependent@*/ void **avalue)
+void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
 {
   extended_cif ecif;
 
@@ -177,11 +199,9 @@ void ffi_call(/*@dependent@*/ ffi_cif *cif,
   /* value address then we need to make one                    */
 
   if ((rvalue == NULL) && 
-      (cif->rtype->type == FFI_TYPE_STRUCT))
+      (cif->flags == FFI_TYPE_STRUCT))
     {
-      /*@-sysunrecog@*/
       ecif.rvalue = alloca(cif->rtype->size);
-      /*@=sysunrecog@*/
     }
   else
     ecif.rvalue = rvalue;
@@ -190,17 +210,13 @@ void ffi_call(/*@dependent@*/ ffi_cif *cif,
   switch (cif->abi) 
     {
     case FFI_SYSV:
-      /*@-usedef@*/
-      ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, 
-                   cif->flags, ecif.rvalue, fn);
-      /*@=usedef@*/
+      ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue,
+                   fn);
       break;
 #ifdef X86_WIN32
     case FFI_STDCALL:
-      /*@-usedef@*/
-      ffi_call_STDCALL(ffi_prep_args, &ecif, cif->bytes,
-                   cif->flags, ecif.rvalue, fn);
-      /*@=usedef@*/
+      ffi_call_STDCALL(ffi_prep_args, &ecif, cif->bytes, cif->flags,
+                      ecif.rvalue, fn);
       break;
 #endif /* X86_WIN32 */
     default:
@@ -214,26 +230,28 @@ void ffi_call(/*@dependent@*/ ffi_cif *cif,
 
 static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
                                         void** args, ffi_cif* cif);
-static void ffi_closure_SYSV (ffi_closure *)
+void FFI_HIDDEN ffi_closure_SYSV (ffi_closure *)
      __attribute__ ((regparm(1)));
-static void ffi_closure_raw_SYSV (ffi_raw_closure *)
+unsigned int FFI_HIDDEN ffi_closure_SYSV_inner (ffi_closure *, void **, void *)
      __attribute__ ((regparm(1)));
+void FFI_HIDDEN ffi_closure_raw_SYSV (ffi_raw_closure *)
+     __attribute__ ((regparm(1)));
+#ifdef X86_WIN32
+void FFI_HIDDEN ffi_closure_STDCALL (ffi_closure *)
+     __attribute__ ((regparm(1)));
+#endif
 
 /* This function is jumped to by the trampoline */
 
-static void
-ffi_closure_SYSV (closure)
+unsigned int FFI_HIDDEN
+ffi_closure_SYSV_inner (closure, respp, args)
      ffi_closure *closure;
+     void **respp;
+     void *args;
 {
-  // this is our return value storage
-  long double    res;
-
-  // our various things...
+  /* our various things...  */
   ffi_cif       *cif;
   void         **arg_area;
-  unsigned short rtype;
-  void          *resp = (void*)&res;
-  void *args = __builtin_dwarf_cfa ();
 
   cif         = closure->cif;
   arg_area    = (void**) alloca (cif->nargs * sizeof (void*));  
@@ -244,43 +262,16 @@ ffi_closure_SYSV (closure)
    * 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);
+  ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif);
 
-  rtype = cif->flags;
+  (closure->fun) (cif, *respp, arg_area, closure->user_data);
 
-  /* 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");
-    }
+  return cif->flags;
 }
 
-/*@-exportheader@*/
-static void 
-ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
-                           void **avalue, ffi_cif *cif)
-/*@=exportheader@*/
+static void
+ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, void **avalue,
+                           ffi_cif *cif)
 {
   register unsigned int i;
   register void **p_argv;
@@ -289,7 +280,7 @@ ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
 
   argp = stack;
 
-  if ( cif->rtype->type == FFI_TYPE_STRUCT ) {
+  if ( cif->flags == FFI_TYPE_STRUCT ) {
     *rvalue = *(void **) argp;
     argp += 4;
   }
@@ -324,27 +315,54 @@ ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
 ({ unsigned char *__tramp = (unsigned char*)(TRAMP); \
    unsigned int  __fun = (unsigned int)(FUN); \
    unsigned int  __ctx = (unsigned int)(CTX); \
-   unsigned int  __dis = __fun - ((unsigned int) __tramp + FFI_TRAMPOLINE_SIZE); \
+   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 int*)  &__tramp[6] = __dis; /* jmp __fun  */ \
  })
 
+#define FFI_INIT_TRAMPOLINE_STDCALL(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 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  */ \
+ })
 
 /* the cif must already be prep'ed */
 
 ffi_status
-ffi_prep_closure (ffi_closure* closure,
-                 ffi_cif* cif,
-                 void (*fun)(ffi_cif*,void*,void**,void*),
-                 void *user_data)
+ffi_prep_closure_loc (ffi_closure* closure,
+                     ffi_cif* cif,
+                     void (*fun)(ffi_cif*,void*,void**,void*),
+                     void *user_data,
+                     void *codeloc)
 {
-  FFI_ASSERT (cif->abi == FFI_SYSV);
-
-  FFI_INIT_TRAMPOLINE (&closure->tramp[0], \
-                      &ffi_closure_SYSV,  \
-                      (void*)closure);
+  if (cif->abi == FFI_SYSV)
+    {
+      FFI_INIT_TRAMPOLINE (&closure->tramp[0],
+                           &ffi_closure_SYSV,
+                           (void*)codeloc);
+    }
+#ifdef X86_WIN32
+  else if (cif->abi == FFI_STDCALL)
+    {
+      FFI_INIT_TRAMPOLINE_STDCALL (&closure->tramp[0],
+                                   &ffi_closure_STDCALL,
+                                   (void*)codeloc, cif->bytes);
+    }
+#endif
+  else
+    {
+      return FFI_BAD_ABI;
+    }
     
   closure->cif  = cif;
   closure->user_data = user_data;
@@ -357,66 +375,18 @@ ffi_prep_closure (ffi_closure* closure,
 
 #if !FFI_NO_RAW_API
 
-static void
-ffi_closure_raw_SYSV (closure)
-     ffi_raw_closure *closure;
-{
-  // this is our return value storage
-  long double    res;
-
-  // our various things...
-  ffi_raw         *raw_args;
-  ffi_cif         *cif;
-  unsigned short   rtype;
-  void            *resp = (void*)&res;
-
-  /* get the cif */
-  cif = closure->cif;
-
-  /* the SYSV/X86 abi matches the RAW API exactly, well.. almost */
-  raw_args = (ffi_raw*) __builtin_dwarf_cfa ();
-
-  (closure->fun) (cif, resp, raw_args, closure->user_data);
-
-  rtype = cif->flags;
-
-  /* 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");
-    }
-}
-
-
-
 ffi_status
-ffi_prep_raw_closure (ffi_raw_closure* closure,
-                     ffi_cif* cif,
-                     void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
-                     void *user_data)
+ffi_prep_raw_closure_loc (ffi_raw_closure* closure,
+                         ffi_cif* cif,
+                         void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
+                         void *user_data,
+                         void *codeloc)
 {
   int i;
 
-  FFI_ASSERT (cif->abi == FFI_SYSV);
+  if (cif->abi != FFI_SYSV) {
+    return FFI_BAD_ABI;
+  }
 
   // we currently don't support certain kinds of arguments for raw
   // closures.  This should be implemented by a separate assembly language
@@ -431,7 +401,7 @@ ffi_prep_raw_closure (ffi_raw_closure* closure,
   
 
   FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_raw_SYSV,
-                      (void*)closure);
+                      codeloc);
     
   closure->cif  = cif;
   closure->user_data = user_data;
@@ -451,27 +421,18 @@ ffi_prep_args_raw(char *stack, extended_cif *ecif)
  * libffi-1.20, this is not the case.)
  */
 
-extern void 
-ffi_call_SYSV(void (*)(char *, extended_cif *), 
-             /*@out@*/ extended_cif *, 
-             unsigned, unsigned, 
-             /*@out@*/ unsigned *, 
-             void (*fn)());
+extern void
+ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *, unsigned, 
+             unsigned, unsigned *, void (*fn)(void));
 
 #ifdef X86_WIN32
 extern void
-ffi_call_STDCALL(void (*)(char *, extended_cif *),
-             /*@out@*/ extended_cif *,
-             unsigned, unsigned,
-             /*@out@*/ unsigned *,
-             void (*fn)());
+ffi_call_STDCALL(void (*)(char *, extended_cif *), extended_cif *, unsigned,
+                unsigned, unsigned *, void (*fn)(void));
 #endif /* X86_WIN32 */
 
 void
-ffi_raw_call(/*@dependent@*/ ffi_cif *cif, 
-            void (*fn)(), 
-            /*@out@*/ void *rvalue, 
-            /*@dependent@*/ ffi_raw *fake_avalue)
+ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *fake_avalue)
 {
   extended_cif ecif;
   void **avalue = (void **)fake_avalue;
@@ -485,9 +446,7 @@ ffi_raw_call(/*@dependent@*/ ffi_cif *cif,
   if ((rvalue == NULL) && 
       (cif->rtype->type == FFI_TYPE_STRUCT))
     {
-      /*@-sysunrecog@*/
       ecif.rvalue = alloca(cif->rtype->size);
-      /*@=sysunrecog@*/
     }
   else
     ecif.rvalue = rvalue;
@@ -496,17 +455,13 @@ ffi_raw_call(/*@dependent@*/ ffi_cif *cif,
   switch (cif->abi) 
     {
     case FFI_SYSV:
-      /*@-usedef@*/
-      ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes, 
-                   cif->flags, ecif.rvalue, fn);
-      /*@=usedef@*/
+      ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags,
+                   ecif.rvalue, fn);
       break;
 #ifdef X86_WIN32
     case FFI_STDCALL:
-      /*@-usedef@*/
-      ffi_call_STDCALL(ffi_prep_args_raw, &ecif, cif->bytes,
-                   cif->flags, ecif.rvalue, fn);
-      /*@=usedef@*/
+      ffi_call_STDCALL(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags,
+                      ecif.rvalue, fn);
       break;
 #endif /* X86_WIN32 */
     default: