Home | History | Annotate | Download | only in libffi_arm_wince
      1 /* -----------------------------------------------------------------------
      2    ffi.c - Copyright (c) 1998  Red Hat, Inc.
      3 
      4    ARM Foreign Function Interface
      5 
      6    Permission is hereby granted, free of charge, to any person obtaining
      7    a copy of this software and associated documentation files (the
      8    ``Software''), to deal in the Software without restriction, including
      9    without limitation the rights to use, copy, modify, merge, publish,
     10    distribute, sublicense, and/or sell copies of the Software, and to
     11    permit persons to whom the Software is furnished to do so, subject to
     12    the following conditions:
     13 
     14    The above copyright notice and this permission notice shall be included
     15    in all copies or substantial portions of the Software.
     16 
     17    THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
     18    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     19    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     20    IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     21    OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     22    ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     23    OTHER DEALINGS IN THE SOFTWARE.
     24    ----------------------------------------------------------------------- */
     25 
     26 #include <ffi.h>
     27 #include <ffi_common.h>
     28 
     29 #include <stdlib.h>
     30 
     31 #ifdef _WIN32_WCE
     32 #pragma warning (disable : 4142)    /* benign redefinition of type */
     33 #include <windows.h>
     34 #endif
     35 
     36 /* ffi_prep_args is called by the assembly routine once stack space
     37    has been allocated for the function's arguments */
     38 
     39 /*@-exportheader@*/
     40 void ffi_prep_args(char *stack, extended_cif *ecif)
     41 /*@=exportheader@*/
     42 {
     43   register unsigned int i;
     44   register void **p_argv;
     45   register char *argp;
     46   register ffi_type **p_arg;
     47 
     48   argp = stack;
     49 
     50   if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) {
     51     *(void **) argp = ecif->rvalue;
     52     argp += 4;
     53   }
     54 
     55   p_argv = ecif->avalue;
     56 
     57   for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
     58        (i != 0);
     59        i--, p_arg++)
     60     {
     61       size_t z;
     62       size_t argalign = (*p_arg)->alignment;
     63 
     64 #ifdef _WIN32_WCE
     65       if (argalign > 4)
     66         argalign = 4;
     67 #endif
     68       /* Align if necessary */
     69       if ((argalign - 1) & (unsigned) argp) {
     70 	argp = (char *) ALIGN(argp, argalign);
     71       }
     72 
     73 	  z = (*p_arg)->size;
     74 	  if (z < sizeof(int))
     75 	    {
     76 	      z = sizeof(int);
     77 	      switch ((*p_arg)->type)
     78 		{
     79 		case FFI_TYPE_SINT8:
     80 		  *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
     81 		  break;
     82 
     83 		case FFI_TYPE_UINT8:
     84 		  *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
     85 		  break;
     86 
     87 		case FFI_TYPE_SINT16:
     88 		  *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
     89 		  break;
     90 
     91 		case FFI_TYPE_UINT16:
     92 		  *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
     93 		  break;
     94 
     95 		case FFI_TYPE_STRUCT:
     96                   /* *p_argv may not be aligned for a UINT32 */
     97                   memcpy(argp, *p_argv, z);
     98 		  break;
     99 
    100 		default:
    101 		  FFI_ASSERT(0);
    102 		}
    103 	    }
    104 	  else if (z == sizeof(int))
    105 	    {
    106 	      *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
    107 	    }
    108 	  else
    109 	    {
    110 	      memcpy(argp, *p_argv, z);
    111 	    }
    112 	  p_argv++;
    113 	  argp += z;
    114     }
    115 
    116   return;
    117 }
    118 
    119 /* Perform machine dependent cif processing */
    120 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
    121 {
    122   /* Set the return type flag */
    123   switch (cif->rtype->type)
    124     {
    125     case FFI_TYPE_VOID:
    126     case FFI_TYPE_STRUCT:
    127     case FFI_TYPE_FLOAT:
    128     case FFI_TYPE_DOUBLE:
    129     case FFI_TYPE_SINT64:
    130       cif->flags = (unsigned) cif->rtype->type;
    131       break;
    132 
    133     case FFI_TYPE_UINT64:
    134       cif->flags = FFI_TYPE_SINT64;
    135       break;
    136 
    137     default:
    138       cif->flags = FFI_TYPE_INT;
    139       break;
    140     }
    141 
    142   return FFI_OK;
    143 }
    144 
    145 /*@-declundef@*/
    146 /*@-exportheader@*/
    147 extern void ffi_call_SYSV(void (*)(char *, extended_cif *),
    148 			  /*@out@*/ extended_cif *,
    149 			  unsigned, unsigned,
    150 			  /*@out@*/ unsigned *,
    151 			  void (*fn)());
    152 /*@=declundef@*/
    153 /*@=exportheader@*/
    154 
    155 /* Return type changed from void for ctypes */
    156 int ffi_call(/*@dependent@*/ ffi_cif *cif,
    157 	      void (*fn)(),
    158 	      /*@out@*/ void *rvalue,
    159 	      /*@dependent@*/ void **avalue)
    160 {
    161   extended_cif ecif;
    162 
    163   ecif.cif = cif;
    164   ecif.avalue = avalue;
    165 
    166   /* If the return value is a struct and we don't have a return	*/
    167   /* value address then we need to make one		        */
    168 
    169   if ((rvalue == NULL) &&
    170       (cif->rtype->type == FFI_TYPE_STRUCT))
    171     {
    172       /*@-sysunrecog@*/
    173       ecif.rvalue = alloca(cif->rtype->size);
    174       /*@=sysunrecog@*/
    175     }
    176   else
    177     ecif.rvalue = rvalue;
    178 
    179 
    180   switch (cif->abi)
    181     {
    182     case FFI_SYSV:
    183       /*@-usedef@*/
    184       ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes,
    185 		    cif->flags, ecif.rvalue, fn);
    186       /*@=usedef@*/
    187       break;
    188     default:
    189       FFI_ASSERT(0);
    190       break;
    191     }
    192   /* I think calculating the real stack pointer delta is not useful
    193      because stdcall is not supported */
    194   return 0;
    195 }
    196 
    197 /** private members **/
    198 
    199 static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
    200 					 void** args, ffi_cif* cif);
    201 
    202 /* This function is called by ffi_closure_SYSV in sysv.asm */
    203 
    204 unsigned int
    205 ffi_closure_SYSV_inner (ffi_closure *closure, char *in_args, void *rvalue)
    206 {
    207   ffi_cif *cif = closure->cif;
    208   void **out_args;
    209 
    210   out_args = (void **) alloca(cif->nargs * sizeof (void *));
    211 
    212   /* this call will initialize out_args, such that each
    213    * element in that array points to the corresponding
    214    * value on the stack; and if the function returns
    215    * a structure, it will re-set rvalue to point to the
    216    * structure return address.  */
    217 
    218   ffi_prep_incoming_args_SYSV(in_args, &rvalue, out_args, cif);
    219 
    220   (closure->fun)(cif, rvalue, out_args, closure->user_data);
    221 
    222   /* Tell ffi_closure_SYSV what the returntype is */
    223   return cif->flags;
    224 }
    225 
    226 /*@-exportheader@*/
    227 static void
    228 ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
    229 			    void **avalue, ffi_cif *cif)
    230 /*@=exportheader@*/
    231 {
    232   unsigned int i;
    233   void **p_argv;
    234   char *argp;
    235   ffi_type **p_arg;
    236 
    237   argp = stack;
    238 
    239   if ( cif->rtype->type == FFI_TYPE_STRUCT ) {
    240     *rvalue = *(void **) argp;
    241     argp += 4;
    242   }
    243 
    244   p_argv = avalue;
    245 
    246   for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
    247     {
    248       size_t z;
    249       size_t argalign = (*p_arg)->alignment;
    250 
    251 #ifdef _WIN32_WCE
    252       if (argalign > 4)
    253         argalign = 4;
    254 #endif
    255       /* Align if necessary */
    256       if ((argalign - 1) & (unsigned) argp) {
    257 	argp = (char *) ALIGN(argp, argalign);
    258       }
    259 
    260       z = (*p_arg)->size;
    261       if (z < sizeof(int))
    262         z = sizeof(int);
    263 
    264       *p_argv = (void*) argp;
    265 
    266       p_argv++;
    267       argp += z;
    268     }
    269 }
    270 
    271 /*
    272     add   ip, pc, #-8     ; ip = address of this trampoline == address of ffi_closure
    273     ldr   pc, [pc, #-4]   ; jump to __fun
    274     DCD __fun
    275 */
    276 #define FFI_INIT_TRAMPOLINE(TRAMP,FUN) \
    277 { \
    278     unsigned int *__tramp = (unsigned int *)(TRAMP); \
    279     __tramp[0] = 0xe24fc008;            /* add   ip, pc, #-8    */ \
    280     __tramp[1] = 0xe51ff004;            /* ldr   pc, [pc, #-4]  */ \
    281     __tramp[2] = (unsigned int)(FUN); \
    282   }
    283 
    284 /* the cif must already be prep'ed */
    285 
    286 /* defined in sysv.asm */
    287 void ffi_closure_SYSV(void);
    288 
    289 ffi_status
    290 ffi_prep_closure (ffi_closure* closure,
    291 		  ffi_cif* cif,
    292 		  void (*fun)(ffi_cif*,void*,void**,void*),
    293 		  void *user_data)
    294 {
    295   FFI_ASSERT (cif->abi == FFI_SYSV);
    296 
    297   FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_SYSV);
    298 
    299   closure->cif  = cif;
    300   closure->user_data = user_data;
    301   closure->fun  = fun;
    302 
    303 #ifdef _WIN32_WCE
    304   /* This is important to allow calling the trampoline safely */
    305   FlushInstructionCache(GetCurrentProcess(), 0, 0);
    306 #endif
    307 
    308   return FFI_OK;
    309 }
    310 
    311