PageRenderTime 36ms CodeModel.GetById 10ms app.highlight 20ms RepoModel.GetById 1ms app.codeStats 0ms

/Modules/_ctypes/libffi_arm_wince/ffi.c

http://unladen-swallow.googlecode.com/
C | 310 lines | 191 code | 55 blank | 64 comment | 25 complexity | b1b44ba73a2612b22815f031ca639604 MD5 | raw file
  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@*/
 40void 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 */
120ffi_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@*/
147extern 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 */
156int 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
199static 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
204unsigned int
205ffi_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@*/
227static void 
228ffi_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 */
287void ffi_closure_SYSV(void);
288
289ffi_status
290ffi_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