Back to index

plt-scheme  4.2.1
ffi.c
Go to the documentation of this file.
00001 /* -----------------------------------------------------------------------
00002    ffi.c - Copyright (c) 1998  Red Hat, Inc.
00003    
00004    ARM Foreign Function Interface 
00005 
00006    Permission is hereby granted, free of charge, to any person obtaining
00007    a copy of this software and associated documentation files (the
00008    ``Software''), to deal in the Software without restriction, including
00009    without limitation the rights to use, copy, modify, merge, publish,
00010    distribute, sublicense, and/or sell copies of the Software, and to
00011    permit persons to whom the Software is furnished to do so, subject to
00012    the following conditions:
00013 
00014    The above copyright notice and this permission notice shall be included
00015    in all copies or substantial portions of the Software.
00016 
00017    THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
00018    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00019    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
00020    IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
00021    OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
00022    ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
00023    OTHER DEALINGS IN THE SOFTWARE.
00024    ----------------------------------------------------------------------- */
00025 
00026 #include <ffi.h>
00027 #include <ffi_common.h>
00028 
00029 #include <stdlib.h>
00030 
00031 /* ffi_prep_args is called by the assembly routine once stack space
00032    has been allocated for the function's arguments */
00033 
00034 void ffi_prep_args(char *stack, extended_cif *ecif)
00035 {
00036   register unsigned int i;
00037   register void **p_argv;
00038   register char *argp;
00039   register ffi_type **p_arg;
00040 
00041   argp = stack;
00042 
00043   if ( ecif->cif->flags == FFI_TYPE_STRUCT ) {
00044     *(void **) argp = ecif->rvalue;
00045     argp += 4;
00046   }
00047 
00048   p_argv = ecif->avalue;
00049 
00050   for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
00051        (i != 0);
00052        i--, p_arg++)
00053     {
00054       size_t z;
00055 
00056       /* Align if necessary */
00057       if (((*p_arg)->alignment - 1) & (unsigned) argp) {
00058        argp = (char *) ALIGN(argp, (*p_arg)->alignment);
00059       }
00060 
00061       if ((*p_arg)->type == FFI_TYPE_STRUCT)
00062        argp = (char *) ALIGN(argp, 4);
00063 
00064          z = (*p_arg)->size;
00065          if (z < sizeof(int))
00066            {
00067              z = sizeof(int);
00068              switch ((*p_arg)->type)
00069               {
00070               case FFI_TYPE_SINT8:
00071                 *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
00072                 break;
00073                 
00074               case FFI_TYPE_UINT8:
00075                 *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
00076                 break;
00077                 
00078               case FFI_TYPE_SINT16:
00079                 *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
00080                 break;
00081                 
00082               case FFI_TYPE_UINT16:
00083                 *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
00084                 break;
00085                 
00086               case FFI_TYPE_STRUCT:
00087                 memcpy(argp, *p_argv, (*p_arg)->size);
00088                 break;
00089 
00090               default:
00091                 FFI_ASSERT(0);
00092               }
00093            }
00094          else if (z == sizeof(int))
00095            {
00096              *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
00097            }
00098          else
00099            {
00100              memcpy(argp, *p_argv, z);
00101            }
00102          p_argv++;
00103          argp += z;
00104     }
00105   
00106   return;
00107 }
00108 
00109 /* Perform machine dependent cif processing */
00110 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
00111 {
00112   /* Round the stack up to a multiple of 8 bytes.  This isn't needed 
00113      everywhere, but it is on some platforms, and it doesn't harm anything
00114      when it isn't needed.  */
00115   cif->bytes = (cif->bytes + 7) & ~7;
00116 
00117   /* Set the return type flag */
00118   switch (cif->rtype->type)
00119     {
00120     case FFI_TYPE_VOID:
00121     case FFI_TYPE_FLOAT:
00122     case FFI_TYPE_DOUBLE:
00123       cif->flags = (unsigned) cif->rtype->type;
00124       break;
00125 
00126     case FFI_TYPE_SINT64:
00127     case FFI_TYPE_UINT64:
00128       cif->flags = (unsigned) FFI_TYPE_SINT64;
00129       break;
00130 
00131     case FFI_TYPE_STRUCT:
00132       if (cif->rtype->size <= 4)
00133        /* A Composite Type not larger than 4 bytes is returned in r0.  */
00134        cif->flags = (unsigned)FFI_TYPE_INT;
00135       else
00136        /* A Composite Type larger than 4 bytes, or whose size cannot
00137           be determined statically ... is stored in memory at an
00138           address passed [in r0].  */
00139        cif->flags = (unsigned)FFI_TYPE_STRUCT;
00140       break;
00141 
00142     default:
00143       cif->flags = FFI_TYPE_INT;
00144       break;
00145     }
00146 
00147   return FFI_OK;
00148 }
00149 
00150 extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
00151                        unsigned, unsigned, unsigned *, void (*fn)());
00152 
00153 void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
00154 {
00155   extended_cif ecif;
00156 
00157   int small_struct = (cif->flags == FFI_TYPE_INT 
00158                     && cif->rtype->type == FFI_TYPE_STRUCT);
00159 
00160   ecif.cif = cif;
00161   ecif.avalue = avalue;
00162 
00163   unsigned int temp;
00164   
00165   /* If the return value is a struct and we don't have a return       */
00166   /* value address then we need to make one                     */
00167 
00168   if ((rvalue == NULL) && 
00169       (cif->flags == FFI_TYPE_STRUCT))
00170     {
00171       ecif.rvalue = alloca(cif->rtype->size);
00172     }
00173   else if (small_struct)
00174     ecif.rvalue = &temp;
00175   else
00176     ecif.rvalue = rvalue;
00177 
00178   switch (cif->abi) 
00179     {
00180     case FFI_SYSV:
00181       ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue,
00182                   fn);
00183 
00184       break;
00185     default:
00186       FFI_ASSERT(0);
00187       break;
00188     }
00189   if (small_struct)
00190     memcpy (rvalue, &temp, cif->rtype->size);
00191 }
00192 
00195 static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
00196                                     void** args, ffi_cif* cif);
00197 
00198 void ffi_closure_SYSV (ffi_closure *);
00199 
00200 /* This function is jumped to by the trampoline */
00201 
00202 unsigned int
00203 ffi_closure_SYSV_inner (closure, respp, args)
00204      ffi_closure *closure;
00205      void **respp;
00206      void *args;
00207 {
00208   // our various things...
00209   ffi_cif       *cif;
00210   void         **arg_area;
00211 
00212   cif         = closure->cif;
00213   arg_area    = (void**) alloca (cif->nargs * sizeof (void*));  
00214 
00215   /* this call will initialize ARG_AREA, such that each
00216    * element in that array points to the corresponding 
00217    * value on the stack; and if the function returns
00218    * a structure, it will re-set RESP to point to the
00219    * structure return address.  */
00220 
00221   ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif);
00222 
00223   (closure->fun) (cif, *respp, arg_area, closure->user_data);
00224 
00225   return cif->flags;
00226 }
00227 
00228 /*@-exportheader@*/
00229 static void 
00230 ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
00231                          void **avalue, ffi_cif *cif)
00232 /*@=exportheader@*/
00233 {
00234   register unsigned int i;
00235   register void **p_argv;
00236   register char *argp;
00237   register ffi_type **p_arg;
00238 
00239   argp = stack;
00240 
00241   if ( cif->flags == FFI_TYPE_STRUCT ) {
00242     *rvalue = *(void **) argp;
00243     argp += 4;
00244   }
00245 
00246   p_argv = avalue;
00247 
00248   for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
00249     {
00250       size_t z;
00251 
00252       size_t alignment = (*p_arg)->alignment;
00253       if (alignment < 4)
00254        alignment = 4;
00255       /* Align if necessary */
00256       if ((alignment - 1) & (unsigned) argp) {
00257        argp = (char *) ALIGN(argp, alignment);
00258       }
00259 
00260       z = (*p_arg)->size;
00261 
00262       /* because we're little endian, this is what it turns into.   */
00263 
00264       *p_argv = (void*) argp;
00265 
00266       p_argv++;
00267       argp += z;
00268     }
00269   
00270   return;
00271 }
00272 
00273 /* How to make a trampoline.  */
00274 
00275 #define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX)                            \
00276 ({ unsigned char *__tramp = (unsigned char*)(TRAMP);                  \
00277    unsigned int  __fun = (unsigned int)(FUN);                         \
00278    unsigned int  __ctx = (unsigned int)(CTX);                         \
00279    *(unsigned int*) &__tramp[0] = 0xe92d000f; /* stmfd sp!, {r0-r3} */       \
00280    *(unsigned int*) &__tramp[4] = 0xe59f0000; /* ldr r0, [pc] */      \
00281    *(unsigned int*) &__tramp[8] = 0xe59ff000; /* ldr pc, [pc] */      \
00282    *(unsigned int*) &__tramp[12] = __ctx;                      \
00283    *(unsigned int*) &__tramp[16] = __fun;                      \
00284    __clear_cache((&__tramp[0]), (&__tramp[19]));               \
00285  })
00286 
00287 
00288 /* the cif must already be prep'ed */
00289 
00290 ffi_status
00291 ffi_prep_closure_loc (ffi_closure* closure,
00292                     ffi_cif* cif,
00293                     void (*fun)(ffi_cif*,void*,void**,void*),
00294                     void *user_data,
00295                     void *codeloc)
00296 {
00297   FFI_ASSERT (cif->abi == FFI_SYSV);
00298 
00299   FFI_INIT_TRAMPOLINE (&closure->tramp[0], \
00300                      &ffi_closure_SYSV,  \
00301                      codeloc);
00302     
00303   closure->cif  = cif;
00304   closure->user_data = user_data;
00305   closure->fun  = fun;
00306 
00307   return FFI_OK;
00308 }