PageRenderTime 602ms CodeModel.GetById 191ms app.highlight 96ms RepoModel.GetById 124ms app.codeStats 0ms

/Modules/_ctypes/libffi/src/x86/ffi.c

http://unladen-swallow.googlecode.com/
C | 475 lines | 331 code | 85 blank | 59 comment | 45 complexity | 7cf89b614cc2be1b8ac7863c1c3d1ce9 MD5 | raw file
  1/* -----------------------------------------------------------------------
  2   ffi.c - Copyright (c) 1996, 1998, 1999, 2001, 2007, 2008  Red Hat, Inc.
  3           Copyright (c) 2002  Ranjit Mathew
  4           Copyright (c) 2002  Bo Thorsen
  5           Copyright (c) 2002  Roger Sayle
  6	   Copyright (C) 2008  Free Software Foundation, Inc.
  7
  8   x86 Foreign Function Interface
  9
 10   Permission is hereby granted, free of charge, to any person obtaining
 11   a copy of this software and associated documentation files (the
 12   ``Software''), to deal in the Software without restriction, including
 13   without limitation the rights to use, copy, modify, merge, publish,
 14   distribute, sublicense, and/or sell copies of the Software, and to
 15   permit persons to whom the Software is furnished to do so, subject to
 16   the following conditions:
 17
 18   The above copyright notice and this permission notice shall be included
 19   in all copies or substantial portions of the Software.
 20
 21   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
 22   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 23   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 24   NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 25   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 26   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 27   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 28   DEALINGS IN THE SOFTWARE.
 29   ----------------------------------------------------------------------- */
 30
 31#ifndef __x86_64__
 32
 33#include <ffi.h>
 34#include <ffi_common.h>
 35
 36#include <stdlib.h>
 37
 38/* ffi_prep_args is called by the assembly routine once stack space
 39   has been allocated for the function's arguments */
 40
 41void ffi_prep_args(char *stack, extended_cif *ecif)
 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->flags == FFI_TYPE_STRUCT)
 51    {
 52      *(void **) argp = ecif->rvalue;
 53      argp += 4;
 54    }
 55
 56  p_argv = ecif->avalue;
 57
 58  for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
 59       i != 0;
 60       i--, p_arg++)
 61    {
 62      size_t z;
 63
 64      /* Align if necessary */
 65      if ((sizeof(int) - 1) & (unsigned) argp)
 66	argp = (char *) ALIGN(argp, sizeof(int));
 67
 68      z = (*p_arg)->size;
 69      if (z < sizeof(int))
 70	{
 71	  z = sizeof(int);
 72	  switch ((*p_arg)->type)
 73	    {
 74	    case FFI_TYPE_SINT8:
 75	      *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
 76	      break;
 77
 78	    case FFI_TYPE_UINT8:
 79	      *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
 80	      break;
 81
 82	    case FFI_TYPE_SINT16:
 83	      *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
 84	      break;
 85
 86	    case FFI_TYPE_UINT16:
 87	      *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
 88	      break;
 89
 90	    case FFI_TYPE_SINT32:
 91	      *(signed int *) argp = (signed int)*(SINT32 *)(* p_argv);
 92	      break;
 93
 94	    case FFI_TYPE_UINT32:
 95	      *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
 96	      break;
 97
 98	    case FFI_TYPE_STRUCT:
 99	      *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
100	      break;
101
102	    default:
103	      FFI_ASSERT(0);
104	    }
105	}
106      else
107	{
108	  memcpy(argp, *p_argv, z);
109	}
110      p_argv++;
111      argp += z;
112    }
113  
114  return;
115}
116
117/* Perform machine dependent cif processing */
118ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
119{
120  /* Set the return type flag */
121  switch (cif->rtype->type)
122    {
123    case FFI_TYPE_VOID:
124#ifdef X86
125    case FFI_TYPE_STRUCT:
126#endif
127#if defined(X86) || defined(X86_DARWIN)
128    case FFI_TYPE_UINT8:
129    case FFI_TYPE_UINT16:
130    case FFI_TYPE_SINT8:
131    case FFI_TYPE_SINT16:
132#endif
133
134    case FFI_TYPE_SINT64:
135    case FFI_TYPE_FLOAT:
136    case FFI_TYPE_DOUBLE:
137    case FFI_TYPE_LONGDOUBLE:
138      cif->flags = (unsigned) cif->rtype->type;
139      break;
140
141    case FFI_TYPE_UINT64:
142      cif->flags = FFI_TYPE_SINT64;
143      break;
144
145#ifndef X86
146    case FFI_TYPE_STRUCT:
147      if (cif->rtype->size == 1)
148        {
149          cif->flags = FFI_TYPE_SMALL_STRUCT_1B; /* same as char size */
150        }
151      else if (cif->rtype->size == 2)
152        {
153          cif->flags = FFI_TYPE_SMALL_STRUCT_2B; /* same as short size */
154        }
155      else if (cif->rtype->size == 4)
156        {
157          cif->flags = FFI_TYPE_INT; /* same as int type */
158        }
159      else if (cif->rtype->size == 8)
160        {
161          cif->flags = FFI_TYPE_SINT64; /* same as int64 type */
162        }
163      else
164        {
165          cif->flags = FFI_TYPE_STRUCT;
166        }
167      break;
168#endif
169
170    default:
171      cif->flags = FFI_TYPE_INT;
172      break;
173    }
174
175#ifdef X86_DARWIN
176  cif->bytes = (cif->bytes + 15) & ~0xF;
177#endif
178
179  return FFI_OK;
180}
181
182extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
183			  unsigned, unsigned, unsigned *, void (*fn)(void));
184
185#ifdef X86_WIN32
186extern void ffi_call_STDCALL(void (*)(char *, extended_cif *), extended_cif *,
187			  unsigned, unsigned, unsigned *, void (*fn)(void));
188
189#endif /* X86_WIN32 */
190
191void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
192{
193  extended_cif ecif;
194
195  ecif.cif = cif;
196  ecif.avalue = avalue;
197  
198  /* If the return value is a struct and we don't have a return	*/
199  /* value address then we need to make one		        */
200
201  if ((rvalue == NULL) && 
202      (cif->flags == FFI_TYPE_STRUCT))
203    {
204      ecif.rvalue = alloca(cif->rtype->size);
205    }
206  else
207    ecif.rvalue = rvalue;
208    
209  
210  switch (cif->abi) 
211    {
212    case FFI_SYSV:
213      ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue,
214		    fn);
215      break;
216#ifdef X86_WIN32
217    case FFI_STDCALL:
218      ffi_call_STDCALL(ffi_prep_args, &ecif, cif->bytes, cif->flags,
219		       ecif.rvalue, fn);
220      break;
221#endif /* X86_WIN32 */
222    default:
223      FFI_ASSERT(0);
224      break;
225    }
226}
227
228
229/** private members **/
230
231static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
232					 void** args, ffi_cif* cif);
233void FFI_HIDDEN ffi_closure_SYSV (ffi_closure *)
234     __attribute__ ((regparm(1)));
235unsigned int FFI_HIDDEN ffi_closure_SYSV_inner (ffi_closure *, void **, void *)
236     __attribute__ ((regparm(1)));
237void FFI_HIDDEN ffi_closure_raw_SYSV (ffi_raw_closure *)
238     __attribute__ ((regparm(1)));
239#ifdef X86_WIN32
240void FFI_HIDDEN ffi_closure_STDCALL (ffi_closure *)
241     __attribute__ ((regparm(1)));
242#endif
243
244/* This function is jumped to by the trampoline */
245
246unsigned int FFI_HIDDEN
247ffi_closure_SYSV_inner (closure, respp, args)
248     ffi_closure *closure;
249     void **respp;
250     void *args;
251{
252  /* our various things...  */
253  ffi_cif       *cif;
254  void         **arg_area;
255
256  cif         = closure->cif;
257  arg_area    = (void**) alloca (cif->nargs * sizeof (void*));  
258
259  /* this call will initialize ARG_AREA, such that each
260   * element in that array points to the corresponding 
261   * value on the stack; and if the function returns
262   * a structure, it will re-set RESP to point to the
263   * structure return address.  */
264
265  ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif);
266
267  (closure->fun) (cif, *respp, arg_area, closure->user_data);
268
269  return cif->flags;
270}
271
272static void
273ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, void **avalue,
274			    ffi_cif *cif)
275{
276  register unsigned int i;
277  register void **p_argv;
278  register char *argp;
279  register ffi_type **p_arg;
280
281  argp = stack;
282
283  if ( cif->flags == FFI_TYPE_STRUCT ) {
284    *rvalue = *(void **) argp;
285    argp += 4;
286  }
287
288  p_argv = avalue;
289
290  for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
291    {
292      size_t z;
293
294      /* Align if necessary */
295      if ((sizeof(int) - 1) & (unsigned) argp) {
296	argp = (char *) ALIGN(argp, sizeof(int));
297      }
298
299      z = (*p_arg)->size;
300
301      /* because we're little endian, this is what it turns into.   */
302
303      *p_argv = (void*) argp;
304
305      p_argv++;
306      argp += z;
307    }
308  
309  return;
310}
311
312/* How to make a trampoline.  Derived from gcc/config/i386/i386.c. */
313
314#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \
315({ unsigned char *__tramp = (unsigned char*)(TRAMP); \
316   unsigned int  __fun = (unsigned int)(FUN); \
317   unsigned int  __ctx = (unsigned int)(CTX); \
318   unsigned int  __dis = __fun - (__ctx + 10);	\
319   *(unsigned char*) &__tramp[0] = 0xb8; \
320   *(unsigned int*)  &__tramp[1] = __ctx; /* movl __ctx, %eax */ \
321   *(unsigned char *)  &__tramp[5] = 0xe9; \
322   *(unsigned int*)  &__tramp[6] = __dis; /* jmp __fun  */ \
323 })
324
325#define FFI_INIT_TRAMPOLINE_STDCALL(TRAMP,FUN,CTX,SIZE)  \
326({ unsigned char *__tramp = (unsigned char*)(TRAMP); \
327   unsigned int  __fun = (unsigned int)(FUN); \
328   unsigned int  __ctx = (unsigned int)(CTX); \
329   unsigned int  __dis = __fun - (__ctx + 10); \
330   unsigned short __size = (unsigned short)(SIZE); \
331   *(unsigned char*) &__tramp[0] = 0xb8; \
332   *(unsigned int*)  &__tramp[1] = __ctx; /* movl __ctx, %eax */ \
333   *(unsigned char *)  &__tramp[5] = 0xe8; \
334   *(unsigned int*)  &__tramp[6] = __dis; /* call __fun  */ \
335   *(unsigned char *)  &__tramp[10] = 0xc2; \
336   *(unsigned short*)  &__tramp[11] = __size; /* ret __size  */ \
337 })
338
339/* the cif must already be prep'ed */
340
341ffi_status
342ffi_prep_closure_loc (ffi_closure* closure,
343		      ffi_cif* cif,
344		      void (*fun)(ffi_cif*,void*,void**,void*),
345		      void *user_data,
346		      void *codeloc)
347{
348  if (cif->abi == FFI_SYSV)
349    {
350      FFI_INIT_TRAMPOLINE (&closure->tramp[0],
351                           &ffi_closure_SYSV,
352                           (void*)codeloc);
353    }
354#ifdef X86_WIN32
355  else if (cif->abi == FFI_STDCALL)
356    {
357      FFI_INIT_TRAMPOLINE_STDCALL (&closure->tramp[0],
358                                   &ffi_closure_STDCALL,
359                                   (void*)codeloc, cif->bytes);
360    }
361#endif
362  else
363    {
364      return FFI_BAD_ABI;
365    }
366    
367  closure->cif  = cif;
368  closure->user_data = user_data;
369  closure->fun  = fun;
370
371  return FFI_OK;
372}
373
374/* ------- Native raw API support -------------------------------- */
375
376#if !FFI_NO_RAW_API
377
378ffi_status
379ffi_prep_raw_closure_loc (ffi_raw_closure* closure,
380			  ffi_cif* cif,
381			  void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
382			  void *user_data,
383			  void *codeloc)
384{
385  int i;
386
387  if (cif->abi != FFI_SYSV) {
388    return FFI_BAD_ABI;
389  }
390
391  /* we currently don't support certain kinds of arguments for raw
392  // closures.  This should be implemented by a separate assembly language
393  // routine, since it would require argument processing, something we
394  // don't do now for performance. */
395
396  for (i = cif->nargs-1; i >= 0; i--)
397    {
398      FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_STRUCT);
399      FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_LONGDOUBLE);
400    }
401  
402
403  FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_raw_SYSV,
404		       codeloc);
405    
406  closure->cif  = cif;
407  closure->user_data = user_data;
408  closure->fun  = fun;
409
410  return FFI_OK;
411}
412
413static void 
414ffi_prep_args_raw(char *stack, extended_cif *ecif)
415{
416  memcpy (stack, ecif->avalue, ecif->cif->bytes);
417}
418
419/* we borrow this routine from libffi (it must be changed, though, to
420 * actually call the function passed in the first argument.  as of
421 * libffi-1.20, this is not the case.)
422 */
423
424extern void
425ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *, unsigned, 
426	      unsigned, unsigned *, void (*fn)(void));
427
428#ifdef X86_WIN32
429extern void
430ffi_call_STDCALL(void (*)(char *, extended_cif *), extended_cif *, unsigned,
431		 unsigned, unsigned *, void (*fn)(void));
432#endif /* X86_WIN32 */
433
434void
435ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *fake_avalue)
436{
437  extended_cif ecif;
438  void **avalue = (void **)fake_avalue;
439
440  ecif.cif = cif;
441  ecif.avalue = avalue;
442  
443  /* If the return value is a struct and we don't have a return	*/
444  /* value address then we need to make one		        */
445
446  if ((rvalue == NULL) && 
447      (cif->rtype->type == FFI_TYPE_STRUCT))
448    {
449      ecif.rvalue = alloca(cif->rtype->size);
450    }
451  else
452    ecif.rvalue = rvalue;
453    
454  
455  switch (cif->abi) 
456    {
457    case FFI_SYSV:
458      ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags,
459		    ecif.rvalue, fn);
460      break;
461#ifdef X86_WIN32
462    case FFI_STDCALL:
463      ffi_call_STDCALL(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags,
464		       ecif.rvalue, fn);
465      break;
466#endif /* X86_WIN32 */
467    default:
468      FFI_ASSERT(0);
469      break;
470    }
471}
472
473#endif
474
475#endif /* __x86_64__  */