ffi.c revision 001d3a1d8ac9b5a057a585950182880f5733c608
1/* -----------------------------------------------------------------------
2   ffi.c - Copyright (c) 1996, 1998, 1999, 2001  Red Hat, Inc.
3           Copyright (c) 2002  Ranjit Mathew
4           Copyright (c) 2002  Bo Thorsen
5           Copyright (c) 2002  Roger Sayle
6
7   x86 Foreign Function Interface
8
9   Permission is hereby granted, free of charge, to any person obtaining
10   a copy of this software and associated documentation files (the
11   ``Software''), to deal in the Software without restriction, including
12   without limitation the rights to use, copy, modify, merge, publish,
13   distribute, sublicense, and/or sell copies of the Software, and to
14   permit persons to whom the Software is furnished to do so, subject to
15   the following conditions:
16
17   The above copyright notice and this permission notice shall be included
18   in all copies or substantial portions of the Software.
19
20   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
21   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23   IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
24   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
25   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26   OTHER DEALINGS IN THE SOFTWARE.
27   ----------------------------------------------------------------------- */
28
29#include <ffi.h>
30#include <ffi_common.h>
31
32#include <stdlib.h>
33
34/* ffi_prep_args is called by the assembly routine once stack space
35   has been allocated for the function's arguments */
36
37extern void Py_FatalError(const char *msg);
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  if (ecif->cif->rtype->type == FFI_TYPE_STRUCT)
50    {
51      *(void **) argp = ecif->rvalue;
52      argp += sizeof(void *);
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
63      /* Align if necessary */
64      if ((sizeof(void *) - 1) & (size_t) argp)
65	argp = (char *) ALIGN(argp, sizeof(void *));
66
67      z = (*p_arg)->size;
68      if (z < sizeof(int))
69	{
70	  z = sizeof(int);
71	  switch ((*p_arg)->type)
72	    {
73	    case FFI_TYPE_SINT8:
74	      *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
75	      break;
76
77	    case FFI_TYPE_UINT8:
78	      *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
79	      break;
80
81	    case FFI_TYPE_SINT16:
82	      *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
83	      break;
84
85	    case FFI_TYPE_UINT16:
86	      *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
87	      break;
88
89	    case FFI_TYPE_SINT32:
90	      *(signed int *) argp = (signed int)*(SINT32 *)(* p_argv);
91	      break;
92
93	    case FFI_TYPE_UINT32:
94	      *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
95	      break;
96
97	    case FFI_TYPE_STRUCT:
98	      *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
99	      break;
100
101	    default:
102	      FFI_ASSERT(0);
103	    }
104	}
105      else
106	{
107	  memcpy(argp, *p_argv, z);
108	}
109      p_argv++;
110      argp += z;
111    }
112
113  if (argp - stack > ecif->cif->bytes)
114    {
115      Py_FatalError("FFI BUG: not enough stack space for arguments");
116    }
117  return;
118}
119
120/* Perform machine dependent cif processing */
121ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
122{
123  /* Set the return type flag */
124  switch (cif->rtype->type)
125    {
126    case FFI_TYPE_VOID:
127    case FFI_TYPE_STRUCT:
128    case FFI_TYPE_SINT64:
129    case FFI_TYPE_FLOAT:
130    case FFI_TYPE_DOUBLE:
131    case FFI_TYPE_LONGDOUBLE:
132      cif->flags = (unsigned) cif->rtype->type;
133      break;
134
135    case FFI_TYPE_UINT64:
136#ifdef _WIN64
137    case FFI_TYPE_POINTER:
138#endif
139      cif->flags = FFI_TYPE_SINT64;
140      break;
141
142    default:
143      cif->flags = FFI_TYPE_INT;
144      break;
145    }
146
147  return FFI_OK;
148}
149
150#ifdef _WIN32
151extern int
152ffi_call_x86(void (*)(char *, extended_cif *),
153	     /*@out@*/ extended_cif *,
154	     unsigned, unsigned,
155	     /*@out@*/ unsigned *,
156	     void (*fn)());
157#endif
158
159#ifdef _WIN64
160extern int
161ffi_call_AMD64(void (*)(char *, extended_cif *),
162		 /*@out@*/ extended_cif *,
163		 unsigned, unsigned,
164		 /*@out@*/ unsigned *,
165		 void (*fn)());
166#endif
167
168int
169ffi_call(/*@dependent@*/ ffi_cif *cif,
170	 void (*fn)(),
171	 /*@out@*/ void *rvalue,
172	 /*@dependent@*/ void **avalue)
173{
174  extended_cif ecif;
175
176  ecif.cif = cif;
177  ecif.avalue = avalue;
178
179  /* If the return value is a struct and we don't have a return	*/
180  /* value address then we need to make one		        */
181
182  if ((rvalue == NULL) &&
183      (cif->rtype->type == FFI_TYPE_STRUCT))
184    {
185      /*@-sysunrecog@*/
186      ecif.rvalue = alloca(cif->rtype->size);
187      /*@=sysunrecog@*/
188    }
189  else
190    ecif.rvalue = rvalue;
191
192
193  switch (cif->abi)
194    {
195#if !defined(_WIN64)
196    case FFI_SYSV:
197    case FFI_STDCALL:
198      return ffi_call_x86(ffi_prep_args, &ecif, cif->bytes,
199			  cif->flags, ecif.rvalue, fn);
200      break;
201#else
202    case FFI_SYSV:
203      /*@-usedef@*/
204      /* Function call needs at least 40 bytes stack size, on win64 AMD64 */
205      return ffi_call_AMD64(ffi_prep_args, &ecif, cif->bytes ? cif->bytes : 40,
206			   cif->flags, ecif.rvalue, fn);
207      /*@=usedef@*/
208      break;
209#endif
210
211    default:
212      FFI_ASSERT(0);
213      break;
214    }
215  return -1; /* theller: Hrm. */
216}
217
218
219/** private members **/
220
221static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
222					  void** args, ffi_cif* cif);
223/* This function is jumped to by the trampoline */
224
225#ifdef _WIN64
226void *
227#else
228static void __fastcall
229#endif
230ffi_closure_SYSV (ffi_closure *closure, int *argp)
231{
232  // this is our return value storage
233  long double    res;
234
235  // our various things...
236  ffi_cif       *cif;
237  void         **arg_area;
238  unsigned short rtype;
239  void          *resp = (void*)&res;
240  void *args = &argp[1];
241
242  cif         = closure->cif;
243  arg_area    = (void**) alloca (cif->nargs * sizeof (void*));
244
245  /* this call will initialize ARG_AREA, such that each
246   * element in that array points to the corresponding
247   * value on the stack; and if the function returns
248   * a structure, it will re-set RESP to point to the
249   * structure return address.  */
250
251  ffi_prep_incoming_args_SYSV(args, (void**)&resp, arg_area, cif);
252
253  (closure->fun) (cif, resp, arg_area, closure->user_data);
254
255  rtype = cif->flags;
256
257#if defined(_WIN32) && !defined(_WIN64)
258#ifdef _MSC_VER
259  /* now, do a generic return based on the value of rtype */
260  if (rtype == FFI_TYPE_INT)
261    {
262	    _asm mov eax, resp ;
263	    _asm mov eax, [eax] ;
264    }
265  else if (rtype == FFI_TYPE_FLOAT)
266    {
267	    _asm mov eax, resp ;
268	    _asm fld DWORD PTR [eax] ;
269//      asm ("flds (%0)" : : "r" (resp) : "st" );
270    }
271  else if (rtype == FFI_TYPE_DOUBLE)
272    {
273	    _asm mov eax, resp ;
274	    _asm fld QWORD PTR [eax] ;
275//      asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" );
276    }
277  else if (rtype == FFI_TYPE_LONGDOUBLE)
278    {
279//      asm ("fldt (%0)" : : "r" (resp) : "st", "st(1)" );
280    }
281  else if (rtype == FFI_TYPE_SINT64)
282    {
283	    _asm mov edx, resp ;
284	    _asm mov eax, [edx] ;
285	    _asm mov edx, [edx + 4] ;
286//      asm ("movl 0(%0),%%eax;"
287//	   "movl 4(%0),%%edx"
288//	   : : "r"(resp)
289//	   : "eax", "edx");
290    }
291#else
292  /* now, do a generic return based on the value of rtype */
293  if (rtype == FFI_TYPE_INT)
294    {
295      asm ("movl (%0),%%eax" : : "r" (resp) : "eax");
296    }
297  else if (rtype == FFI_TYPE_FLOAT)
298    {
299      asm ("flds (%0)" : : "r" (resp) : "st" );
300    }
301  else if (rtype == FFI_TYPE_DOUBLE)
302    {
303      asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" );
304    }
305  else if (rtype == FFI_TYPE_LONGDOUBLE)
306    {
307      asm ("fldt (%0)" : : "r" (resp) : "st", "st(1)" );
308    }
309  else if (rtype == FFI_TYPE_SINT64)
310    {
311      asm ("movl 0(%0),%%eax;"
312	   "movl 4(%0),%%edx"
313	   : : "r"(resp)
314	   : "eax", "edx");
315    }
316#endif
317#endif
318
319#ifdef _WIN64
320  /* The result is returned in rax.  This does the right thing for
321     result types except for floats; we have to 'mov xmm0, rax' in the
322     caller to correct this.
323  */
324  return *(void **)resp;
325#endif
326}
327
328/*@-exportheader@*/
329static void
330ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
331			    void **avalue, ffi_cif *cif)
332/*@=exportheader@*/
333{
334  register unsigned int i;
335  register void **p_argv;
336  register char *argp;
337  register ffi_type **p_arg;
338
339  argp = stack;
340
341  if ( cif->rtype->type == FFI_TYPE_STRUCT ) {
342    *rvalue = *(void **) argp;
343    argp += 4;
344  }
345
346  p_argv = avalue;
347
348  for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
349    {
350      size_t z;
351
352      /* Align if necessary */
353      if ((sizeof(char *) - 1) & (size_t) argp) {
354	argp = (char *) ALIGN(argp, sizeof(char*));
355      }
356
357      z = (*p_arg)->size;
358
359      /* because we're little endian, this is what it turns into.   */
360
361      *p_argv = (void*) argp;
362
363      p_argv++;
364      argp += z;
365    }
366
367  return;
368}
369
370/* the cif must already be prep'ed */
371extern void ffi_closure_OUTER();
372
373ffi_status
374ffi_prep_closure_loc (ffi_closure* closure,
375					  ffi_cif* cif,
376					  void (*fun)(ffi_cif*,void*,void**,void*),
377					  void *user_data,
378					  void *codeloc)
379{
380  short bytes;
381  char *tramp;
382#ifdef _WIN64
383  int mask;
384#endif
385  FFI_ASSERT (cif->abi == FFI_SYSV);
386
387  if (cif->abi == FFI_SYSV)
388    bytes = 0;
389#if !defined(_WIN64)
390  else if (cif->abi == FFI_STDCALL)
391    bytes = cif->bytes;
392#endif
393  else
394    return FFI_BAD_ABI;
395
396  tramp = &closure->tramp[0];
397
398#define BYTES(text) memcpy(tramp, text, sizeof(text)), tramp += sizeof(text)-1
399#define POINTER(x) *(void**)tramp = (void*)(x), tramp += sizeof(void*)
400#define SHORT(x) *(short*)tramp = x, tramp += sizeof(short)
401#define INT(x) *(int*)tramp = x, tramp += sizeof(int)
402
403#ifdef _WIN64
404  if (cif->nargs >= 1 &&
405      (cif->arg_types[0]->type == FFI_TYPE_FLOAT
406       || cif->arg_types[0]->type == FFI_TYPE_DOUBLE))
407    mask |= 1;
408  if (cif->nargs >= 2 &&
409      (cif->arg_types[1]->type == FFI_TYPE_FLOAT
410       || cif->arg_types[1]->type == FFI_TYPE_DOUBLE))
411    mask |= 2;
412  if (cif->nargs >= 3 &&
413      (cif->arg_types[2]->type == FFI_TYPE_FLOAT
414       || cif->arg_types[2]->type == FFI_TYPE_DOUBLE))
415    mask |= 4;
416  if (cif->nargs >= 4 &&
417      (cif->arg_types[3]->type == FFI_TYPE_FLOAT
418       || cif->arg_types[3]->type == FFI_TYPE_DOUBLE))
419    mask |= 8;
420
421  /* 41 BB ----         mov         r11d,mask */
422  BYTES("\x41\xBB"); INT(mask);
423
424  /* 48 B8 --------     mov         rax, closure			*/
425  BYTES("\x48\xB8"); POINTER(closure);
426
427  /* 49 BA --------     mov         r10, ffi_closure_OUTER */
428  BYTES("\x49\xBA"); POINTER(ffi_closure_OUTER);
429
430  /* 41 FF E2           jmp         r10 */
431  BYTES("\x41\xFF\xE2");
432
433#else
434
435  /* mov ecx, closure */
436  BYTES("\xb9"); POINTER(closure);
437
438  /* mov edx, esp */
439  BYTES("\x8b\xd4");
440
441  /* call ffi_closure_SYSV */
442  BYTES("\xe8"); POINTER((char*)&ffi_closure_SYSV - (tramp + 4));
443
444  /* ret bytes */
445  BYTES("\xc2");
446  SHORT(bytes);
447
448#endif
449
450  if (tramp - &closure->tramp[0] > FFI_TRAMPOLINE_SIZE)
451    Py_FatalError("FFI_TRAMPOLINE_SIZE too small in " __FILE__);
452
453  closure->cif  = cif;
454  closure->user_data = user_data;
455  closure->fun  = fun;
456  return FFI_OK;
457}
458