• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
37 extern void Py_FatalError(const char *msg);
38 
39 /*@-exportheader@*/
ffi_prep_args(char * stack,extended_cif * ecif)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   if (ecif->cif->flags == 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 #ifdef _WIN64
106       else if (z > 8)
107         {
108           /* On Win64, if a single argument takes more than 8 bytes,
109              then it is always passed by reference. */
110           *(void **)argp = *p_argv;
111           z = 8;
112         }
113 #endif
114       else
115 	{
116 	  memcpy(argp, *p_argv, z);
117 	}
118       p_argv++;
119       argp += z;
120     }
121 
122   if (argp - stack > (long)ecif->cif->bytes)
123     {
124       Py_FatalError("FFI BUG: not enough stack space for arguments");
125     }
126   return;
127 }
128 
129 /* Perform machine dependent cif processing */
ffi_prep_cif_machdep(ffi_cif * cif)130 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
131 {
132   /* Set the return type flag */
133   switch (cif->rtype->type)
134     {
135     case FFI_TYPE_VOID:
136     case FFI_TYPE_SINT64:
137     case FFI_TYPE_FLOAT:
138     case FFI_TYPE_DOUBLE:
139     case FFI_TYPE_LONGDOUBLE:
140       cif->flags = (unsigned) cif->rtype->type;
141       break;
142 
143     case FFI_TYPE_STRUCT:
144       /* MSVC returns small structures in registers.  Put in cif->flags
145          the value FFI_TYPE_STRUCT only if the structure is big enough;
146          otherwise, put the 4- or 8-bytes integer type. */
147       if (cif->rtype->size <= 4)
148         cif->flags = FFI_TYPE_INT;
149       else if (cif->rtype->size <= 8)
150         cif->flags = FFI_TYPE_SINT64;
151       else
152         cif->flags = FFI_TYPE_STRUCT;
153       break;
154 
155     case FFI_TYPE_UINT64:
156 #ifdef _WIN64
157     case FFI_TYPE_POINTER:
158 #endif
159       cif->flags = FFI_TYPE_SINT64;
160       break;
161 
162     default:
163       cif->flags = FFI_TYPE_INT;
164       break;
165     }
166 
167   return FFI_OK;
168 }
169 
170 #ifdef _WIN32
171 extern int
172 ffi_call_x86(void (*)(char *, extended_cif *),
173 	     /*@out@*/ extended_cif *,
174 	     unsigned, unsigned,
175 	     /*@out@*/ unsigned *,
176 	     void (*fn)());
177 #endif
178 
179 #ifdef _WIN64
180 extern int
181 ffi_call_AMD64(void (*)(char *, extended_cif *),
182 		 /*@out@*/ extended_cif *,
183 		 unsigned, unsigned,
184 		 /*@out@*/ unsigned *,
185 		 void (*fn)());
186 #endif
187 
188 int
ffi_call(ffi_cif * cif,void (* fn)(),void * rvalue,void ** avalue)189 ffi_call(/*@dependent@*/ ffi_cif *cif,
190 	 void (*fn)(),
191 	 /*@out@*/ void *rvalue,
192 	 /*@dependent@*/ void **avalue)
193 {
194   extended_cif ecif;
195 
196   ecif.cif = cif;
197   ecif.avalue = avalue;
198 
199   /* If the return value is a struct and we don't have a return	*/
200   /* value address then we need to make one		        */
201 
202   if ((rvalue == NULL) &&
203       (cif->flags == FFI_TYPE_STRUCT))
204     {
205       /*@-sysunrecog@*/
206       ecif.rvalue = alloca(cif->rtype->size);
207       /*@=sysunrecog@*/
208     }
209   else
210     ecif.rvalue = rvalue;
211 
212 
213   switch (cif->abi)
214     {
215 #if !defined(_WIN64)
216     case FFI_SYSV:
217     case FFI_STDCALL:
218       return ffi_call_x86(ffi_prep_args, &ecif, cif->bytes,
219 			  cif->flags, ecif.rvalue, fn);
220       break;
221 #else
222     case FFI_SYSV:
223       /*@-usedef@*/
224       return ffi_call_AMD64(ffi_prep_args, &ecif, cif->bytes,
225 			   cif->flags, ecif.rvalue, fn);
226       /*@=usedef@*/
227       break;
228 #endif
229 
230     default:
231       FFI_ASSERT(0);
232       break;
233     }
234   return -1; /* theller: Hrm. */
235 }
236 
237 
238 /** private members **/
239 
240 static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
241 					  void** args, ffi_cif* cif);
242 /* This function is jumped to by the trampoline */
243 
244 #ifdef _WIN64
245 void *
246 #else
247 static void __fastcall
248 #endif
ffi_closure_SYSV(ffi_closure * closure,char * argp)249 ffi_closure_SYSV (ffi_closure *closure, char *argp)
250 {
251   // this is our return value storage
252   long double    res;
253 
254   // our various things...
255   ffi_cif       *cif;
256   void         **arg_area;
257   unsigned short rtype;
258   void          *resp = (void*)&res;
259   void *args = argp + sizeof(void *);
260 
261   cif         = closure->cif;
262   arg_area    = (void**) alloca (cif->nargs * sizeof (void*));
263 
264   /* this call will initialize ARG_AREA, such that each
265    * element in that array points to the corresponding
266    * value on the stack; and if the function returns
267    * a structure, it will re-set RESP to point to the
268    * structure return address.  */
269 
270   ffi_prep_incoming_args_SYSV(args, (void**)&resp, arg_area, cif);
271 
272   (closure->fun) (cif, resp, arg_area, closure->user_data);
273 
274   rtype = cif->flags;
275 
276 #if defined(_WIN32) && !defined(_WIN64)
277 #ifdef _MSC_VER
278   /* now, do a generic return based on the value of rtype */
279   if (rtype == FFI_TYPE_INT)
280     {
281 	    _asm mov eax, resp ;
282 	    _asm mov eax, [eax] ;
283     }
284   else if (rtype == FFI_TYPE_FLOAT)
285     {
286 	    _asm mov eax, resp ;
287 	    _asm fld DWORD PTR [eax] ;
288 //      asm ("flds (%0)" : : "r" (resp) : "st" );
289     }
290   else if (rtype == FFI_TYPE_DOUBLE)
291     {
292 	    _asm mov eax, resp ;
293 	    _asm fld QWORD PTR [eax] ;
294 //      asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" );
295     }
296   else if (rtype == FFI_TYPE_LONGDOUBLE)
297     {
298 //      asm ("fldt (%0)" : : "r" (resp) : "st", "st(1)" );
299     }
300   else if (rtype == FFI_TYPE_SINT64)
301     {
302 	    _asm mov edx, resp ;
303 	    _asm mov eax, [edx] ;
304 	    _asm mov edx, [edx + 4] ;
305 //      asm ("movl 0(%0),%%eax;"
306 //	   "movl 4(%0),%%edx"
307 //	   : : "r"(resp)
308 //	   : "eax", "edx");
309     }
310 #else
311   /* now, do a generic return based on the value of rtype */
312   if (rtype == FFI_TYPE_INT)
313     {
314       asm ("movl (%0),%%eax" : : "r" (resp) : "eax");
315     }
316   else if (rtype == FFI_TYPE_FLOAT)
317     {
318       asm ("flds (%0)" : : "r" (resp) : "st" );
319     }
320   else if (rtype == FFI_TYPE_DOUBLE)
321     {
322       asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" );
323     }
324   else if (rtype == FFI_TYPE_LONGDOUBLE)
325     {
326       asm ("fldt (%0)" : : "r" (resp) : "st", "st(1)" );
327     }
328   else if (rtype == FFI_TYPE_SINT64)
329     {
330       asm ("movl 0(%0),%%eax;"
331 	   "movl 4(%0),%%edx"
332 	   : : "r"(resp)
333 	   : "eax", "edx");
334     }
335 #endif
336 #endif
337 
338 #ifdef _WIN64
339   /* The result is returned in rax.  This does the right thing for
340      result types except for floats; we have to 'mov xmm0, rax' in the
341      caller to correct this.
342   */
343   return *(void **)resp;
344 #endif
345 }
346 
347 /*@-exportheader@*/
348 static void
ffi_prep_incoming_args_SYSV(char * stack,void ** rvalue,void ** avalue,ffi_cif * cif)349 ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
350 			    void **avalue, ffi_cif *cif)
351 /*@=exportheader@*/
352 {
353   register unsigned int i;
354   register void **p_argv;
355   register char *argp;
356   register ffi_type **p_arg;
357 
358   argp = stack;
359 
360   if ( cif->flags == FFI_TYPE_STRUCT ) {
361     *rvalue = *(void **) argp;
362     argp += 4;
363   }
364 
365   p_argv = avalue;
366 
367   for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
368     {
369       size_t z;
370 
371       /* Align if necessary */
372       if ((sizeof(char *) - 1) & (size_t) argp) {
373 	argp = (char *) ALIGN(argp, sizeof(char*));
374       }
375 
376       z = (*p_arg)->size;
377 
378       /* because we're little endian, this is what it turns into.   */
379 
380 #ifdef _WIN64
381       if (z > 8)
382         {
383           /* On Win64, if a single argument takes more than 8 bytes,
384              then it is always passed by reference. */
385           *p_argv = *((void**) argp);
386           z = 8;
387         }
388       else
389 #endif
390       *p_argv = (void*) argp;
391 
392       p_argv++;
393       argp += z;
394     }
395 
396   return;
397 }
398 
399 /* the cif must already be prep'ed */
400 extern void ffi_closure_OUTER();
401 
402 ffi_status
ffi_prep_closure_loc(ffi_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *),void * user_data,void * codeloc)403 ffi_prep_closure_loc (ffi_closure* closure,
404 					  ffi_cif* cif,
405 					  void (*fun)(ffi_cif*,void*,void**,void*),
406 					  void *user_data,
407 					  void *codeloc)
408 {
409   short bytes;
410   char *tramp;
411 #ifdef _WIN64
412   int mask = 0;
413 #endif
414   FFI_ASSERT (cif->abi == FFI_SYSV);
415 
416   if (cif->abi == FFI_SYSV)
417     bytes = 0;
418 #if !defined(_WIN64)
419   else if (cif->abi == FFI_STDCALL)
420     bytes = cif->bytes;
421 #endif
422   else
423     return FFI_BAD_ABI;
424 
425   tramp = &closure->tramp[0];
426 
427 #define BYTES(text) memcpy(tramp, text, sizeof(text)), tramp += sizeof(text)-1
428 #define POINTER(x) *(void**)tramp = (void*)(x), tramp += sizeof(void*)
429 #define SHORT(x) *(short*)tramp = x, tramp += sizeof(short)
430 #define INT(x) *(int*)tramp = x, tramp += sizeof(int)
431 
432 #ifdef _WIN64
433   if (cif->nargs >= 1 &&
434       (cif->arg_types[0]->type == FFI_TYPE_FLOAT
435        || cif->arg_types[0]->type == FFI_TYPE_DOUBLE))
436     mask |= 1;
437   if (cif->nargs >= 2 &&
438       (cif->arg_types[1]->type == FFI_TYPE_FLOAT
439        || cif->arg_types[1]->type == FFI_TYPE_DOUBLE))
440     mask |= 2;
441   if (cif->nargs >= 3 &&
442       (cif->arg_types[2]->type == FFI_TYPE_FLOAT
443        || cif->arg_types[2]->type == FFI_TYPE_DOUBLE))
444     mask |= 4;
445   if (cif->nargs >= 4 &&
446       (cif->arg_types[3]->type == FFI_TYPE_FLOAT
447        || cif->arg_types[3]->type == FFI_TYPE_DOUBLE))
448     mask |= 8;
449 
450   /* 41 BB ----         mov         r11d,mask */
451   BYTES("\x41\xBB"); INT(mask);
452 
453   /* 48 B8 --------     mov         rax, closure			*/
454   BYTES("\x48\xB8"); POINTER(closure);
455 
456   /* 49 BA --------     mov         r10, ffi_closure_OUTER */
457   BYTES("\x49\xBA"); POINTER(ffi_closure_OUTER);
458 
459   /* 41 FF E2           jmp         r10 */
460   BYTES("\x41\xFF\xE2");
461 
462 #else
463 
464   /* mov ecx, closure */
465   BYTES("\xb9"); POINTER(closure);
466 
467   /* mov edx, esp */
468   BYTES("\x8b\xd4");
469 
470   /* call ffi_closure_SYSV */
471   BYTES("\xe8"); POINTER((char*)&ffi_closure_SYSV - (tramp + 4));
472 
473   /* ret bytes */
474   BYTES("\xc2");
475   SHORT(bytes);
476 
477 #endif
478 
479   if (tramp - &closure->tramp[0] > FFI_TRAMPOLINE_SIZE)
480     Py_FatalError("FFI_TRAMPOLINE_SIZE too small in " __FILE__);
481 
482   closure->cif  = cif;
483   closure->user_data = user_data;
484   closure->fun  = fun;
485   return FFI_OK;
486 }
487