Back to index

plt-scheme  4.2.1
ffi.c
Go to the documentation of this file.
00001 /* -----------------------------------------------------------------------
00002    ffi.c - Copyright (c) 1996, 1998, 1999, 2001, 2007  Red Hat, Inc.
00003            Copyright (c) 2002  Ranjit Mathew
00004            Copyright (c) 2002  Bo Thorsen
00005            Copyright (c) 2002  Roger Sayle
00006           Copyright (C) 2008  Free Software Foundation, Inc.
00007 
00008    x86 Foreign Function Interface
00009 
00010    Permission is hereby granted, free of charge, to any person obtaining
00011    a copy of this software and associated documentation files (the
00012    ``Software''), to deal in the Software without restriction, including
00013    without limitation the rights to use, copy, modify, merge, publish,
00014    distribute, sublicense, and/or sell copies of the Software, and to
00015    permit persons to whom the Software is furnished to do so, subject to
00016    the following conditions:
00017 
00018    The above copyright notice and this permission notice shall be included
00019    in all copies or substantial portions of the Software.
00020 
00021    THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
00022    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00023    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
00024    IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
00025    OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
00026    ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
00027    OTHER DEALINGS IN THE SOFTWARE.
00028    ----------------------------------------------------------------------- */
00029 
00030 #ifndef __x86_64__
00031 
00032 #include <ffi.h>
00033 #include <ffi_common.h>
00034 
00035 #include <stdlib.h>
00036 
00037 /* ffi_prep_args is called by the assembly routine once stack space
00038    has been allocated for the function's arguments */
00039 
00040 void ffi_prep_args(char *stack, extended_cif *ecif)
00041 {
00042   register unsigned int i;
00043   register void **p_argv;
00044   register char *argp;
00045   register ffi_type **p_arg;
00046 
00047   argp = stack;
00048 
00049   if (ecif->cif->flags == FFI_TYPE_STRUCT)
00050     {
00051       *(void **) argp = ecif->rvalue;
00052       argp += 4;
00053     }
00054 
00055   p_argv = ecif->avalue;
00056 
00057   for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
00058        i != 0;
00059        i--, p_arg++)
00060     {
00061       size_t z;
00062 
00063       /* Align if necessary */
00064       if ((sizeof(int) - 1) & (unsigned) argp)
00065        argp = (char *) ALIGN(argp, sizeof(int));
00066 
00067       z = (*p_arg)->size;
00068       if (z < sizeof(int))
00069        {
00070          z = sizeof(int);
00071          switch ((*p_arg)->type)
00072            {
00073            case FFI_TYPE_SINT8:
00074              *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
00075              break;
00076 
00077            case FFI_TYPE_UINT8:
00078              *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
00079              break;
00080 
00081            case FFI_TYPE_SINT16:
00082              *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
00083              break;
00084 
00085            case FFI_TYPE_UINT16:
00086              *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
00087              break;
00088 
00089            case FFI_TYPE_SINT32:
00090              *(signed int *) argp = (signed int)*(SINT32 *)(* p_argv);
00091              break;
00092 
00093            case FFI_TYPE_UINT32:
00094              *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
00095              break;
00096 
00097            case FFI_TYPE_STRUCT:
00098              *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
00099              break;
00100 
00101            default:
00102              FFI_ASSERT(0);
00103            }
00104        }
00105       else
00106        {
00107          memcpy(argp, *p_argv, z);
00108        }
00109       p_argv++;
00110       argp += z;
00111     }
00112   
00113   return;
00114 }
00115 
00116 /* Perform machine dependent cif processing */
00117 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
00118 {
00119   /* Set the return type flag */
00120   switch (cif->rtype->type)
00121     {
00122     case FFI_TYPE_VOID:
00123 #ifdef X86
00124     case FFI_TYPE_STRUCT:
00125 #endif
00126 #if defined(X86) || defined(X86_DARWIN)
00127     case FFI_TYPE_UINT8:
00128     case FFI_TYPE_UINT16:
00129     case FFI_TYPE_SINT8:
00130     case FFI_TYPE_SINT16:
00131 #endif
00132 
00133     case FFI_TYPE_SINT64:
00134     case FFI_TYPE_FLOAT:
00135     case FFI_TYPE_DOUBLE:
00136     case FFI_TYPE_LONGDOUBLE:
00137       cif->flags = (unsigned) cif->rtype->type;
00138       break;
00139 
00140     case FFI_TYPE_UINT64:
00141       cif->flags = FFI_TYPE_SINT64;
00142       break;
00143 
00144 #ifndef X86
00145     case FFI_TYPE_STRUCT:
00146       if (cif->rtype->size == 1)
00147         {
00148           cif->flags = FFI_TYPE_SMALL_STRUCT_1B; /* same as char size */
00149         }
00150       else if (cif->rtype->size == 2)
00151         {
00152           cif->flags = FFI_TYPE_SMALL_STRUCT_2B; /* same as short size */
00153         }
00154       else if (cif->rtype->size == 4)
00155         {
00156           cif->flags = FFI_TYPE_INT; /* same as int type */
00157         }
00158       else if (cif->rtype->size == 8)
00159         {
00160           cif->flags = FFI_TYPE_SINT64; /* same as int64 type */
00161         }
00162       else
00163         {
00164           cif->flags = FFI_TYPE_STRUCT;
00165         }
00166       break;
00167 #endif
00168 
00169     default:
00170       cif->flags = FFI_TYPE_INT;
00171       break;
00172     }
00173 
00174 #ifdef X86_DARWIN
00175   cif->bytes = (cif->bytes + 15) & ~0xF;
00176 #endif
00177 
00178   return FFI_OK;
00179 }
00180 
00181 extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
00182                        unsigned, unsigned, unsigned *, void (*fn)());
00183 
00184 #ifdef X86_WIN32
00185 extern void ffi_call_STDCALL(void (*)(char *, extended_cif *), extended_cif *,
00186                        unsigned, unsigned, unsigned *, void (*fn)());
00187 
00188 #endif /* X86_WIN32 */
00189 
00190 void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
00191 {
00192   extended_cif ecif;
00193 
00194   ecif.cif = cif;
00195   ecif.avalue = avalue;
00196   
00197   /* If the return value is a struct and we don't have a return       */
00198   /* value address then we need to make one                     */
00199 
00200   if ((rvalue == NULL) && 
00201       (cif->flags == FFI_TYPE_STRUCT))
00202     {
00203       ecif.rvalue = alloca(cif->rtype->size);
00204     }
00205   else
00206     ecif.rvalue = rvalue;
00207     
00208   
00209   switch (cif->abi) 
00210     {
00211     case FFI_SYSV:
00212       ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue,
00213                   fn);
00214       break;
00215 #ifdef X86_WIN32
00216     case FFI_STDCALL:
00217       ffi_call_STDCALL(ffi_prep_args, &ecif, cif->bytes, cif->flags,
00218                      ecif.rvalue, fn);
00219       break;
00220 #endif /* X86_WIN32 */
00221     default:
00222       FFI_ASSERT(0);
00223       break;
00224     }
00225 }
00226 
00227 
00230 static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
00231                                     void** args, ffi_cif* cif);
00232 void FFI_HIDDEN ffi_closure_SYSV (ffi_closure *)
00233      __attribute__ ((regparm(1)));
00234 unsigned int FFI_HIDDEN ffi_closure_SYSV_inner (ffi_closure *, void **, void *)
00235      __attribute__ ((regparm(1)));
00236 void FFI_HIDDEN ffi_closure_raw_SYSV (ffi_raw_closure *)
00237      __attribute__ ((regparm(1)));
00238 
00239 /* This function is jumped to by the trampoline */
00240 
00241 unsigned int FFI_HIDDEN
00242 ffi_closure_SYSV_inner (closure, respp, args)
00243      ffi_closure *closure;
00244      void **respp;
00245      void *args;
00246 {
00247   // our various things...
00248   ffi_cif       *cif;
00249   void         **arg_area;
00250 
00251   cif         = closure->cif;
00252   arg_area    = (void**) alloca (cif->nargs * sizeof (void*));  
00253 
00254   /* this call will initialize ARG_AREA, such that each
00255    * element in that array points to the corresponding 
00256    * value on the stack; and if the function returns
00257    * a structure, it will re-set RESP to point to the
00258    * structure return address.  */
00259 
00260   ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif);
00261 
00262   (closure->fun) (cif, *respp, arg_area, closure->user_data);
00263 
00264   return cif->flags;
00265 }
00266 
00267 static void
00268 ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, void **avalue,
00269                          ffi_cif *cif)
00270 {
00271   register unsigned int i;
00272   register void **p_argv;
00273   register char *argp;
00274   register ffi_type **p_arg;
00275 
00276   argp = stack;
00277 
00278   if ( cif->flags == FFI_TYPE_STRUCT ) {
00279     *rvalue = *(void **) argp;
00280     argp += 4;
00281   }
00282 
00283   p_argv = avalue;
00284 
00285   for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
00286     {
00287       size_t z;
00288 
00289       /* Align if necessary */
00290       if ((sizeof(int) - 1) & (unsigned) argp) {
00291        argp = (char *) ALIGN(argp, sizeof(int));
00292       }
00293 
00294       z = (*p_arg)->size;
00295 
00296       /* because we're little endian, this is what it turns into.   */
00297 
00298       *p_argv = (void*) argp;
00299 
00300       p_argv++;
00301       argp += z;
00302     }
00303   
00304   return;
00305 }
00306 
00307 /* How to make a trampoline.  Derived from gcc/config/i386/i386.c. */
00308 
00309 #define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \
00310 ({ unsigned char *__tramp = (unsigned char*)(TRAMP); \
00311    unsigned int  __fun = (unsigned int)(FUN); \
00312    unsigned int  __ctx = (unsigned int)(CTX); \
00313    unsigned int  __dis = __fun - (__ctx + FFI_TRAMPOLINE_SIZE); \
00314    *(unsigned char*) &__tramp[0] = 0xb8; \
00315    *(unsigned int*)  &__tramp[1] = __ctx; /* movl __ctx, %eax */ \
00316    *(unsigned char *)  &__tramp[5] = 0xe9; \
00317    *(unsigned int*)  &__tramp[6] = __dis; /* jmp __fun  */ \
00318  })
00319 
00320 
00321 /* the cif must already be prep'ed */
00322 
00323 ffi_status
00324 ffi_prep_closure_loc (ffi_closure* closure,
00325                     ffi_cif* cif,
00326                     void (*fun)(ffi_cif*,void*,void**,void*),
00327                     void *user_data,
00328                     void *codeloc)
00329 {
00330   FFI_ASSERT (cif->abi == FFI_SYSV);
00331 
00332   FFI_INIT_TRAMPOLINE (&closure->tramp[0], \
00333                      &ffi_closure_SYSV,  \
00334                      codeloc);
00335     
00336   closure->cif  = cif;
00337   closure->user_data = user_data;
00338   closure->fun  = fun;
00339 
00340   return FFI_OK;
00341 }
00342 
00343 /* ------- Native raw API support -------------------------------- */
00344 
00345 #if !FFI_NO_RAW_API
00346 
00347 ffi_status
00348 ffi_prep_raw_closure_loc (ffi_raw_closure* closure,
00349                        ffi_cif* cif,
00350                        void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
00351                        void *user_data,
00352                        void *codeloc)
00353 {
00354   int i;
00355 
00356   FFI_ASSERT (cif->abi == FFI_SYSV);
00357 
00358   // we currently don't support certain kinds of arguments for raw
00359   // closures.  This should be implemented by a separate assembly language
00360   // routine, since it would require argument processing, something we
00361   // don't do now for performance.
00362 
00363   for (i = cif->nargs-1; i >= 0; i--)
00364     {
00365       FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_STRUCT);
00366       FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_LONGDOUBLE);
00367     }
00368   
00369 
00370   FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_raw_SYSV,
00371                      codeloc);
00372     
00373   closure->cif  = cif;
00374   closure->user_data = user_data;
00375   closure->fun  = fun;
00376 
00377   return FFI_OK;
00378 }
00379 
00380 static void 
00381 ffi_prep_args_raw(char *stack, extended_cif *ecif)
00382 {
00383   memcpy (stack, ecif->avalue, ecif->cif->bytes);
00384 }
00385 
00386 /* we borrow this routine from libffi (it must be changed, though, to
00387  * actually call the function passed in the first argument.  as of
00388  * libffi-1.20, this is not the case.)
00389  */
00390 
00391 extern void
00392 ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *, unsigned, 
00393              unsigned, unsigned *, void (*fn)());
00394 
00395 #ifdef X86_WIN32
00396 extern void
00397 ffi_call_STDCALL(void (*)(char *, extended_cif *), extended_cif *, unsigned,
00398                unsigned, unsigned *, void (*fn)());
00399 #endif /* X86_WIN32 */
00400 
00401 void
00402 ffi_raw_call(ffi_cif *cif, void (*fn)(), void *rvalue, ffi_raw *fake_avalue)
00403 {
00404   extended_cif ecif;
00405   void **avalue = (void **)fake_avalue;
00406 
00407   ecif.cif = cif;
00408   ecif.avalue = avalue;
00409   
00410   /* If the return value is a struct and we don't have a return       */
00411   /* value address then we need to make one                     */
00412 
00413   if ((rvalue == NULL) && 
00414       (cif->rtype->type == FFI_TYPE_STRUCT))
00415     {
00416       ecif.rvalue = alloca(cif->rtype->size);
00417     }
00418   else
00419     ecif.rvalue = rvalue;
00420     
00421   
00422   switch (cif->abi) 
00423     {
00424     case FFI_SYSV:
00425       ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags,
00426                   ecif.rvalue, fn);
00427       break;
00428 #ifdef X86_WIN32
00429     case FFI_STDCALL:
00430       ffi_call_STDCALL(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags,
00431                      ecif.rvalue, fn);
00432       break;
00433 #endif /* X86_WIN32 */
00434     default:
00435       FFI_ASSERT(0);
00436       break;
00437     }
00438 }
00439 
00440 #endif
00441 
00442 #endif /* __x86_64__  */