Back to index

plt-scheme  4.2.1
ffi.c
Go to the documentation of this file.
00001 /* -----------------------------------------------------------------------
00002    ffi.c - Copyright (c) 1998 Cygnus Solutions
00003            Copyright (c) 2004 Simon Posnjak
00004           Copyright (c) 2005 Axis Communications AB
00005           Copyright (C) 2007 Free Software Foundation, Inc.
00006 
00007    CRIS Foreign Function Interface
00008 
00009    Permission is hereby granted, free of charge, to any person obtaining
00010    a copy of this software and associated documentation files (the
00011    ``Software''), to deal in the Software without restriction, including
00012    without limitation the rights to use, copy, modify, merge, publish,
00013    distribute, sublicense, and/or sell copies of the Software, and to
00014    permit persons to whom the Software is furnished to do so, subject to
00015    the following conditions:
00016 
00017    The above copyright notice and this permission notice shall be included
00018    in all copies or substantial portions of the Software.
00019 
00020    THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
00021    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00022    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
00023    IN NO EVENT SHALL SIMON POSNJAK BE LIABLE FOR ANY CLAIM, DAMAGES OR
00024    OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
00025    ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
00026    OTHER DEALINGS IN THE SOFTWARE.
00027    ----------------------------------------------------------------------- */
00028 
00029 #include <ffi.h>
00030 #include <ffi_common.h>
00031 
00032 #define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG)
00033 
00034 static ffi_status
00035 initialize_aggregate_packed_struct (ffi_type * arg)
00036 {
00037   ffi_type **ptr;
00038 
00039   FFI_ASSERT (arg != NULL);
00040 
00041   FFI_ASSERT (arg->elements != NULL);
00042   FFI_ASSERT (arg->size == 0);
00043   FFI_ASSERT (arg->alignment == 0);
00044 
00045   ptr = &(arg->elements[0]);
00046 
00047   while ((*ptr) != NULL)
00048     {
00049       if (((*ptr)->size == 0)
00050          && (initialize_aggregate_packed_struct ((*ptr)) != FFI_OK))
00051        return FFI_BAD_TYPEDEF;
00052 
00053       FFI_ASSERT (ffi_type_test ((*ptr)));
00054 
00055       arg->size += (*ptr)->size;
00056 
00057       arg->alignment = (arg->alignment > (*ptr)->alignment) ?
00058        arg->alignment : (*ptr)->alignment;
00059 
00060       ptr++;
00061     }
00062 
00063   if (arg->size == 0)
00064     return FFI_BAD_TYPEDEF;
00065   else
00066     return FFI_OK;
00067 }
00068 
00069 int
00070 ffi_prep_args (char *stack, extended_cif * ecif)
00071 {
00072   unsigned int i;
00073   unsigned int struct_count = 0;
00074   void **p_argv;
00075   char *argp;
00076   ffi_type **p_arg;
00077 
00078   argp = stack;
00079 
00080   p_argv = ecif->avalue;
00081 
00082   for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
00083        (i != 0); i--, p_arg++)
00084     {
00085       size_t z;
00086 
00087       switch ((*p_arg)->type)
00088        {
00089        case FFI_TYPE_STRUCT:
00090          {
00091            z = (*p_arg)->size;
00092            if (z <= 4)
00093              {
00094               memcpy (argp, *p_argv, z);
00095               z = 4;
00096              }
00097            else if (z <= 8)
00098              {
00099               memcpy (argp, *p_argv, z);
00100               z = 8;
00101              }
00102            else
00103              {
00104               unsigned int uiLocOnStack;
00105               z = sizeof (void *);
00106               uiLocOnStack = 4 * ecif->cif->nargs + struct_count;
00107               struct_count = struct_count + (*p_arg)->size;
00108               *(unsigned int *) argp =
00109                 (unsigned int) (UINT32 *) (stack + uiLocOnStack);
00110               memcpy ((stack + uiLocOnStack), *p_argv, (*p_arg)->size);
00111              }
00112            break;
00113          }
00114        default:
00115          z = (*p_arg)->size;
00116          if (z < sizeof (int))
00117            {
00118              switch ((*p_arg)->type)
00119               {
00120               case FFI_TYPE_SINT8:
00121                 *(signed int *) argp = (signed int) *(SINT8 *) (*p_argv);
00122                 break;
00123 
00124               case FFI_TYPE_UINT8:
00125                 *(unsigned int *) argp =
00126                   (unsigned int) *(UINT8 *) (*p_argv);
00127                 break;
00128 
00129               case FFI_TYPE_SINT16:
00130                 *(signed int *) argp = (signed int) *(SINT16 *) (*p_argv);
00131                 break;
00132 
00133               case FFI_TYPE_UINT16:
00134                 *(unsigned int *) argp =
00135                   (unsigned int) *(UINT16 *) (*p_argv);
00136                 break;
00137 
00138               default:
00139                 FFI_ASSERT (0);
00140               }
00141              z = sizeof (int);
00142            }
00143          else if (z == sizeof (int))
00144            *(unsigned int *) argp = (unsigned int) *(UINT32 *) (*p_argv);
00145          else
00146            memcpy (argp, *p_argv, z);
00147          break;
00148        }
00149       p_argv++;
00150       argp += z;
00151     }
00152 
00153   return (struct_count);
00154 }
00155 
00156 ffi_status
00157 ffi_prep_cif (ffi_cif * cif,
00158              ffi_abi abi, unsigned int nargs,
00159              ffi_type * rtype, ffi_type ** atypes)
00160 {
00161   unsigned bytes = 0;
00162   unsigned int i;
00163   ffi_type **ptr;
00164 
00165   FFI_ASSERT (cif != NULL);
00166   FFI_ASSERT ((abi > FFI_FIRST_ABI) && (abi <= FFI_DEFAULT_ABI));
00167 
00168   cif->abi = abi;
00169   cif->arg_types = atypes;
00170   cif->nargs = nargs;
00171   cif->rtype = rtype;
00172 
00173   cif->flags = 0;
00174 
00175   if ((cif->rtype->size == 0)
00176       && (initialize_aggregate_packed_struct (cif->rtype) != FFI_OK))
00177     return FFI_BAD_TYPEDEF;
00178 
00179   FFI_ASSERT_VALID_TYPE (cif->rtype);
00180 
00181   for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
00182     {
00183       if (((*ptr)->size == 0)
00184          && (initialize_aggregate_packed_struct ((*ptr)) != FFI_OK))
00185        return FFI_BAD_TYPEDEF;
00186 
00187       FFI_ASSERT_VALID_TYPE (*ptr);
00188 
00189       if (((*ptr)->alignment - 1) & bytes)
00190        bytes = ALIGN (bytes, (*ptr)->alignment);
00191       if ((*ptr)->type == FFI_TYPE_STRUCT)
00192        {
00193          if ((*ptr)->size > 8)
00194            {
00195              bytes += (*ptr)->size;
00196              bytes += sizeof (void *);
00197            }
00198          else
00199            {
00200              if ((*ptr)->size > 4)
00201               bytes += 8;
00202              else
00203               bytes += 4;
00204            }
00205        }
00206       else
00207        bytes += STACK_ARG_SIZE ((*ptr)->size);
00208     }
00209 
00210   cif->bytes = bytes;
00211 
00212   return ffi_prep_cif_machdep (cif);
00213 }
00214 
00215 ffi_status
00216 ffi_prep_cif_machdep (ffi_cif * cif)
00217 {
00218   switch (cif->rtype->type)
00219     {
00220     case FFI_TYPE_VOID:
00221     case FFI_TYPE_STRUCT:
00222     case FFI_TYPE_FLOAT:
00223     case FFI_TYPE_DOUBLE:
00224     case FFI_TYPE_SINT64:
00225     case FFI_TYPE_UINT64:
00226       cif->flags = (unsigned) cif->rtype->type;
00227       break;
00228 
00229     default:
00230       cif->flags = FFI_TYPE_INT;
00231       break;
00232     }
00233 
00234   return FFI_OK;
00235 }
00236 
00237 extern void ffi_call_SYSV (int (*)(char *, extended_cif *),
00238                         extended_cif *,
00239                         unsigned, unsigned, unsigned *, void (*fn) ())
00240      __attribute__ ((__visibility__ ("hidden")));
00241 
00242 void
00243 ffi_call (ffi_cif * cif, void (*fn) (), void *rvalue, void **avalue)
00244 {
00245   extended_cif ecif;
00246 
00247   ecif.cif = cif;
00248   ecif.avalue = avalue;
00249 
00250   if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT))
00251     {
00252       ecif.rvalue = alloca (cif->rtype->size);
00253     }
00254   else
00255     ecif.rvalue = rvalue;
00256 
00257   switch (cif->abi)
00258     {
00259     case FFI_SYSV:
00260       ffi_call_SYSV (ffi_prep_args, &ecif, cif->bytes,
00261                    cif->flags, ecif.rvalue, fn);
00262       break;
00263     default:
00264       FFI_ASSERT (0);
00265       break;
00266     }
00267 }
00268 
00269 /* Because the following variables are not exported outside libffi, we
00270    mark them hidden.  */
00271 
00272 /* Assembly code for the jump stub.  */
00273 extern const char ffi_cris_trampoline_template[]
00274  __attribute__ ((__visibility__ ("hidden")));
00275 
00276 /* Offset into ffi_cris_trampoline_template of where to put the
00277    ffi_prep_closure_inner function.  */
00278 extern const int ffi_cris_trampoline_fn_offset
00279  __attribute__ ((__visibility__ ("hidden")));
00280 
00281 /* Offset into ffi_cris_trampoline_template of where to put the
00282    closure data.  */
00283 extern const int ffi_cris_trampoline_closure_offset
00284  __attribute__ ((__visibility__ ("hidden")));
00285 
00286 /* This function is sibling-called (jumped to) by the closure
00287    trampoline.  We get R10..R13 at PARAMS[0..3] and a copy of [SP] at
00288    PARAMS[4] to simplify handling of a straddling parameter.  A copy
00289    of R9 is at PARAMS[5] and SP at PARAMS[6].  These parameters are
00290    put at the appropriate place in CLOSURE which is then executed and
00291    the return value is passed back to the caller.  */
00292 
00293 static unsigned long long
00294 ffi_prep_closure_inner (void **params, ffi_closure* closure)
00295 {
00296   char *register_args = (char *) params;
00297   void *struct_ret = params[5];
00298   char *stack_args = params[6];
00299   char *ptr = register_args;
00300   ffi_cif *cif = closure->cif;
00301   ffi_type **arg_types = cif->arg_types;
00302 
00303   /* Max room needed is number of arguments as 64-bit values.  */
00304   void **avalue = alloca (closure->cif->nargs * sizeof(void *));
00305   int i;
00306   int doing_regs;
00307   long long llret = 0;
00308 
00309   /* Find the address of each argument.  */
00310   for (i = 0, doing_regs = 1; i < cif->nargs; i++)
00311     {
00312       /* Types up to and including 8 bytes go by-value.  */
00313       if (arg_types[i]->size <= 4)
00314        {
00315          avalue[i] = ptr;
00316          ptr += 4;
00317        }
00318       else if (arg_types[i]->size <= 8)
00319        {
00320          avalue[i] = ptr;
00321          ptr += 8;
00322        }
00323       else
00324        {
00325          FFI_ASSERT (arg_types[i]->type == FFI_TYPE_STRUCT);
00326 
00327          /* Passed by-reference, so copy the pointer.  */
00328          avalue[i] = *(void **) ptr;
00329          ptr += 4;
00330        }
00331 
00332       /* If we've handled more arguments than fit in registers, start
00333         looking at the those passed on the stack.  Step over the
00334         first one if we had a straddling parameter.  */
00335       if (doing_regs && ptr >= register_args + 4*4)
00336        {
00337          ptr = stack_args + ((ptr > register_args + 4*4) ? 4 : 0);
00338          doing_regs = 0;
00339        }
00340     }
00341 
00342   /* Invoke the closure.  */
00343   (closure->fun) (cif,
00344 
00345                 cif->rtype->type == FFI_TYPE_STRUCT
00346                 /* The caller allocated space for the return
00347                    structure, and passed a pointer to this space in
00348                    R9.  */
00349                 ? struct_ret
00350 
00351                 /* We take advantage of being able to ignore that
00352                    the high part isn't set if the return value is
00353                    not in R10:R11, but in R10 only.  */
00354                 : (void *) &llret,
00355 
00356                 avalue, closure->user_data);
00357 
00358   return llret;
00359 }
00360 
00361 /* API function: Prepare the trampoline.  */
00362 
00363 ffi_status
00364 ffi_prep_closure_loc (ffi_closure* closure,
00365                     ffi_cif* cif,
00366                     void (*fun)(ffi_cif *, void *, void **, void*),
00367                     void *user_data,
00368                     void *codeloc)
00369 {
00370   void *innerfn = ffi_prep_closure_inner;
00371   FFI_ASSERT (cif->abi == FFI_SYSV);
00372   closure->cif  = cif;
00373   closure->user_data = user_data;
00374   closure->fun  = fun;
00375   memcpy (closure->tramp, ffi_cris_trampoline_template,
00376          FFI_CRIS_TRAMPOLINE_CODE_PART_SIZE);
00377   memcpy (closure->tramp + ffi_cris_trampoline_fn_offset,
00378          &innerfn, sizeof (void *));
00379   memcpy (closure->tramp + ffi_cris_trampoline_closure_offset,
00380          &codeloc, sizeof (void *));
00381 
00382   return FFI_OK;
00383 }