blob: 80496532a30882a23b372b183c458c5e280a2a8b [file] [log] [blame]
Anthony Greenc6dddbd2009-10-04 08:11:33 -04001/* -----------------------------------------------------------------------
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#if !defined(__x86_64__) || defined(_WIN64)
32
33#ifdef _WIN64
34#include <windows.h>
35#endif
36
37#include <ffi.h>
38#include <ffi_common.h>
39
40#include <stdlib.h>
41
42/* ffi_prep_args is called by the assembly routine once stack space
43 has been allocated for the function's arguments */
44
45void ffi_prep_args(char *stack, extended_cif *ecif)
46{
47 register unsigned int i;
48 register void **p_argv;
49 register char *argp;
50 register ffi_type **p_arg;
51
52 argp = stack;
53
54 if (ecif->cif->flags == FFI_TYPE_STRUCT
55#ifdef X86_WIN64
56 && (ecif->cif->rtype->size != 1 && ecif->cif->rtype->size != 2
57 && ecif->cif->rtype->size != 4 && ecif->cif->rtype->size != 8)
58#endif
59 )
60 {
61 *(void **) argp = ecif->rvalue;
62 argp += sizeof(void*);
63 }
64
65 p_argv = ecif->avalue;
66
67 for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
68 i != 0;
69 i--, p_arg++)
70 {
71 size_t z;
72
73 /* Align if necessary */
74 if ((sizeof(void*) - 1) & (size_t) argp)
75 argp = (char *) ALIGN(argp, sizeof(void*));
76
77 z = (*p_arg)->size;
78#ifdef X86_WIN64
79 if (z > sizeof(ffi_arg)
80 || ((*p_arg)->type == FFI_TYPE_STRUCT
81 && (z != 1 && z != 2 && z != 4 && z != 8))
82#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
83 || ((*p_arg)->type == FFI_TYPE_LONGDOUBLE)
84#endif
85 )
86 {
87 z = sizeof(ffi_arg);
88 *(void **)argp = *p_argv;
89 }
90 else if ((*p_arg)->type == FFI_TYPE_FLOAT)
91 {
92 memcpy(argp, *p_argv, z);
93 }
94 else
95#endif
96 if (z < sizeof(ffi_arg))
97 {
98 z = sizeof(ffi_arg);
99 switch ((*p_arg)->type)
100 {
101 case FFI_TYPE_SINT8:
102 *(ffi_sarg *) argp = (ffi_sarg)*(SINT8 *)(* p_argv);
103 break;
104
105 case FFI_TYPE_UINT8:
106 *(ffi_arg *) argp = (ffi_arg)*(UINT8 *)(* p_argv);
107 break;
108
109 case FFI_TYPE_SINT16:
110 *(ffi_sarg *) argp = (ffi_sarg)*(SINT16 *)(* p_argv);
111 break;
112
113 case FFI_TYPE_UINT16:
114 *(ffi_arg *) argp = (ffi_arg)*(UINT16 *)(* p_argv);
115 break;
116
117 case FFI_TYPE_SINT32:
118 *(ffi_sarg *) argp = (ffi_sarg)*(SINT32 *)(* p_argv);
119 break;
120
121 case FFI_TYPE_UINT32:
122 *(ffi_arg *) argp = (ffi_arg)*(UINT32 *)(* p_argv);
123 break;
124
125 case FFI_TYPE_STRUCT:
126 *(ffi_arg *) argp = *(ffi_arg *)(* p_argv);
127 break;
128
129 default:
130 FFI_ASSERT(0);
131 }
132 }
133 else
134 {
135 memcpy(argp, *p_argv, z);
136 }
137 p_argv++;
138#ifdef X86_WIN64
139 argp += (z + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
140#else
141 argp += z;
142#endif
143 }
144
145 return;
146}
147
148/* Perform machine dependent cif processing */
149ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
150{
Anthony Greencadeba62010-01-15 10:46:51 -0500151 unsigned int i;
152 ffi_type **ptr;
153
Anthony Greenc6dddbd2009-10-04 08:11:33 -0400154 /* Set the return type flag */
155 switch (cif->rtype->type)
156 {
157 case FFI_TYPE_VOID:
Anthony Greenc6dddbd2009-10-04 08:11:33 -0400158#if defined(X86) || defined (X86_WIN32) || defined(X86_FREEBSD) || defined(X86_DARWIN) || defined(X86_WIN64)
159 case FFI_TYPE_UINT8:
160 case FFI_TYPE_UINT16:
161 case FFI_TYPE_SINT8:
162 case FFI_TYPE_SINT16:
163#endif
164#ifdef X86_WIN64
165 case FFI_TYPE_UINT32:
166 case FFI_TYPE_SINT32:
167#endif
Anthony Greenc6dddbd2009-10-04 08:11:33 -0400168 case FFI_TYPE_SINT64:
169 case FFI_TYPE_FLOAT:
170 case FFI_TYPE_DOUBLE:
171#ifndef X86_WIN64
172#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
173 case FFI_TYPE_LONGDOUBLE:
174#endif
175#endif
176 cif->flags = (unsigned) cif->rtype->type;
177 break;
178
179 case FFI_TYPE_UINT64:
180#ifdef X86_WIN64
181 case FFI_TYPE_POINTER:
182#endif
183 cif->flags = FFI_TYPE_SINT64;
184 break;
185
Anthony Greenc6dddbd2009-10-04 08:11:33 -0400186 case FFI_TYPE_STRUCT:
Anthony Greencadeba62010-01-15 10:46:51 -0500187#ifndef X86
Anthony Greenc6dddbd2009-10-04 08:11:33 -0400188 if (cif->rtype->size == 1)
189 {
190 cif->flags = FFI_TYPE_SMALL_STRUCT_1B; /* same as char size */
191 }
192 else if (cif->rtype->size == 2)
193 {
194 cif->flags = FFI_TYPE_SMALL_STRUCT_2B; /* same as short size */
195 }
196 else if (cif->rtype->size == 4)
197 {
198#ifdef X86_WIN64
199 cif->flags = FFI_TYPE_SMALL_STRUCT_4B;
200#else
201 cif->flags = FFI_TYPE_INT; /* same as int type */
202#endif
203 }
204 else if (cif->rtype->size == 8)
205 {
206 cif->flags = FFI_TYPE_SINT64; /* same as int64 type */
207 }
208 else
Anthony Greencadeba62010-01-15 10:46:51 -0500209#endif
Anthony Greenc6dddbd2009-10-04 08:11:33 -0400210 {
211 cif->flags = FFI_TYPE_STRUCT;
Anthony Greenc6dddbd2009-10-04 08:11:33 -0400212 // allocate space for return value pointer
213 cif->bytes += ALIGN(sizeof(void*), FFI_SIZEOF_ARG);
Anthony Greenc6dddbd2009-10-04 08:11:33 -0400214 }
215 break;
Anthony Greenc6dddbd2009-10-04 08:11:33 -0400216
217 default:
218#ifdef X86_WIN64
219 cif->flags = FFI_TYPE_SINT64;
220 break;
221 case FFI_TYPE_INT:
222 cif->flags = FFI_TYPE_SINT32;
223#else
224 cif->flags = FFI_TYPE_INT;
225#endif
226 break;
227 }
228
Anthony Greencadeba62010-01-15 10:46:51 -0500229 for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
230 {
231 if (((*ptr)->alignment - 1) & cif->bytes)
232 cif->bytes = ALIGN(cif->bytes, (*ptr)->alignment);
233 cif->bytes += ALIGN((*ptr)->size, FFI_SIZEOF_ARG);
234 }
Anthony Greenc6dddbd2009-10-04 08:11:33 -0400235
236#ifdef X86_WIN64
Anthony Greenc6dddbd2009-10-04 08:11:33 -0400237 // ensure space for storing four registers
238 cif->bytes += 4 * sizeof(ffi_arg);
239#endif
240
Anthony Greencadeba62010-01-15 10:46:51 -0500241#ifdef X86_DARWIN
242 cif->bytes = (cif->bytes + 15) & ~0xF;
243#endif
244
Anthony Greenc6dddbd2009-10-04 08:11:33 -0400245 return FFI_OK;
246}
247
Anthony Greenc6dddbd2009-10-04 08:11:33 -0400248#ifdef X86_WIN64
249extern int
250ffi_call_win64(void (*)(char *, extended_cif *), extended_cif *,
251 unsigned, unsigned, unsigned *, void (*fn)(void));
Anthony Greencadeba62010-01-15 10:46:51 -0500252#elif defined(X86_WIN32)
253extern void
254ffi_call_win32(void (*)(char *, extended_cif *), extended_cif *,
255 unsigned, unsigned, unsigned *, void (*fn)(void));
256#else
257extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
258 unsigned, unsigned, unsigned *, void (*fn)(void));
Anthony Greenc6dddbd2009-10-04 08:11:33 -0400259#endif
260
261void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
262{
263 extended_cif ecif;
264
265 ecif.cif = cif;
266 ecif.avalue = avalue;
267
268 /* If the return value is a struct and we don't have a return */
269 /* value address then we need to make one */
270
271#ifdef X86_WIN64
272 if (rvalue == NULL
273 && cif->flags == FFI_TYPE_STRUCT
274 && cif->rtype->size != 1 && cif->rtype->size != 2
275 && cif->rtype->size != 4 && cif->rtype->size != 8)
276 {
277 ecif.rvalue = alloca((cif->rtype->size + 0xF) & ~0xF);
278 }
279#else
280 if (rvalue == NULL
281 && cif->flags == FFI_TYPE_STRUCT)
282 {
283 ecif.rvalue = alloca(cif->rtype->size);
284 }
285#endif
286 else
287 ecif.rvalue = rvalue;
288
289
290 switch (cif->abi)
291 {
292#ifdef X86_WIN64
293 case FFI_WIN64:
294 {
295 // Make copies of all struct arguments
296 // NOTE: not sure if responsibility should be here or in caller
297 unsigned int i;
298 for (i=0; i < cif->nargs;i++) {
299 size_t size = cif->arg_types[i]->size;
300 if ((cif->arg_types[i]->type == FFI_TYPE_STRUCT
301 && (size != 1 && size != 2 && size != 4 && size != 8))
302#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
303 || cif->arg_types[i]->type == FFI_TYPE_LONGDOUBLE
304#endif
305 )
306 {
307 void *local = alloca(size);
308 memcpy(local, avalue[i], size);
309 avalue[i] = local;
310 }
311 }
312 ffi_call_win64(ffi_prep_args, &ecif, cif->bytes,
313 cif->flags, ecif.rvalue, fn);
314 }
315 break;
Anthony Greencadeba62010-01-15 10:46:51 -0500316#elif defined(X86_WIN32)
317 case FFI_SYSV:
318 case FFI_STDCALL:
319 ffi_call_win32(ffi_prep_args, &ecif, cif->bytes, cif->flags,
320 ecif.rvalue, fn);
321 break;
Anthony Greenc6dddbd2009-10-04 08:11:33 -0400322#else
323 case FFI_SYSV:
324 ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue,
325 fn);
326 break;
Anthony Greencadeba62010-01-15 10:46:51 -0500327#endif
Anthony Greenc6dddbd2009-10-04 08:11:33 -0400328 default:
329 FFI_ASSERT(0);
330 break;
331 }
332}
333
334
335/** private members **/
336
Anthony Greencadeba62010-01-15 10:46:51 -0500337/* The following __attribute__((regparm(1))) decorations will have no effect
338 on MSVC - standard cdecl convention applies. */
Anthony Greenc6dddbd2009-10-04 08:11:33 -0400339static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
340 void** args, ffi_cif* cif);
341void FFI_HIDDEN ffi_closure_SYSV (ffi_closure *)
342 __attribute__ ((regparm(1)));
343unsigned int FFI_HIDDEN ffi_closure_SYSV_inner (ffi_closure *, void **, void *)
344 __attribute__ ((regparm(1)));
345void FFI_HIDDEN ffi_closure_raw_SYSV (ffi_raw_closure *)
346 __attribute__ ((regparm(1)));
347#ifdef X86_WIN32
348void FFI_HIDDEN ffi_closure_STDCALL (ffi_closure *)
349 __attribute__ ((regparm(1)));
350#endif
351#ifdef X86_WIN64
352void FFI_HIDDEN ffi_closure_win64 (ffi_closure *);
353#endif
354
355/* This function is jumped to by the trampoline */
356
357#ifdef X86_WIN64
358void * FFI_HIDDEN
359ffi_closure_win64_inner (ffi_closure *closure, void *args) {
360 ffi_cif *cif;
361 void **arg_area;
362 void *result;
363 void *resp = &result;
364
365 cif = closure->cif;
366 arg_area = (void**) alloca (cif->nargs * sizeof (void*));
367
368 /* this call will initialize ARG_AREA, such that each
369 * element in that array points to the corresponding
370 * value on the stack; and if the function returns
371 * a structure, it will change RESP to point to the
372 * structure return address. */
373
374 ffi_prep_incoming_args_SYSV(args, &resp, arg_area, cif);
375
376 (closure->fun) (cif, resp, arg_area, closure->user_data);
377
378 /* The result is returned in rax. This does the right thing for
379 result types except for floats; we have to 'mov xmm0, rax' in the
380 caller to correct this.
381 TODO: structure sizes of 3 5 6 7 are returned by reference, too!!!
382 */
383 return cif->rtype->size > sizeof(void *) ? resp : *(void **)resp;
384}
385
386#else
Anthony Greencadeba62010-01-15 10:46:51 -0500387unsigned int FFI_HIDDEN __attribute__ ((regparm(1)))
388ffi_closure_SYSV_inner (ffi_closure *closure, void **respp, void *args)
Anthony Greenc6dddbd2009-10-04 08:11:33 -0400389{
390 /* our various things... */
391 ffi_cif *cif;
392 void **arg_area;
393
394 cif = closure->cif;
395 arg_area = (void**) alloca (cif->nargs * sizeof (void*));
396
397 /* this call will initialize ARG_AREA, such that each
398 * element in that array points to the corresponding
399 * value on the stack; and if the function returns
400 * a structure, it will change RESP to point to the
401 * structure return address. */
402
403 ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif);
404
405 (closure->fun) (cif, *respp, arg_area, closure->user_data);
406
407 return cif->flags;
408}
409#endif /* !X86_WIN64 */
410
411static void
412ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, void **avalue,
413 ffi_cif *cif)
414{
415 register unsigned int i;
416 register void **p_argv;
417 register char *argp;
418 register ffi_type **p_arg;
419
420 argp = stack;
421
422#ifdef X86_WIN64
423 if (cif->rtype->size > sizeof(ffi_arg)
424 || (cif->flags == FFI_TYPE_STRUCT
425 && (cif->rtype->size != 1 && cif->rtype->size != 2
426 && cif->rtype->size != 4 && cif->rtype->size != 8))) {
427 *rvalue = *(void **) argp;
428 argp += sizeof(void *);
429 }
430#else
431 if ( cif->flags == FFI_TYPE_STRUCT ) {
432 *rvalue = *(void **) argp;
433 argp += sizeof(void *);
434 }
435#endif
436
437 p_argv = avalue;
438
439 for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
440 {
441 size_t z;
442
443 /* Align if necessary */
444 if ((sizeof(void*) - 1) & (size_t) argp) {
445 argp = (char *) ALIGN(argp, sizeof(void*));
446 }
447
448#ifdef X86_WIN64
449 if ((*p_arg)->size > sizeof(ffi_arg)
450 || ((*p_arg)->type == FFI_TYPE_STRUCT
451 && ((*p_arg)->size != 1 && (*p_arg)->size != 2
452 && (*p_arg)->size != 4 && (*p_arg)->size != 8)))
453 {
454 z = sizeof(void *);
455 *p_argv = *(void **)argp;
456 }
457 else
458#endif
459 {
460 z = (*p_arg)->size;
461
462 /* because we're little endian, this is what it turns into. */
463
464 *p_argv = (void*) argp;
465 }
466
467 p_argv++;
468#ifdef X86_WIN64
469 argp += (z + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
470#else
471 argp += z;
472#endif
473 }
474
475 return;
476}
477
478#define FFI_INIT_TRAMPOLINE_WIN64(TRAMP,FUN,CTX,MASK) \
479{ unsigned char *__tramp = (unsigned char*)(TRAMP); \
480 void* __fun = (void*)(FUN); \
481 void* __ctx = (void*)(CTX); \
482 *(unsigned char*) &__tramp[0] = 0x41; \
483 *(unsigned char*) &__tramp[1] = 0xbb; \
484 *(unsigned int*) &__tramp[2] = MASK; /* mov $mask, %r11 */ \
485 *(unsigned char*) &__tramp[6] = 0x48; \
486 *(unsigned char*) &__tramp[7] = 0xb8; \
487 *(void**) &__tramp[8] = __ctx; /* mov __ctx, %rax */ \
488 *(unsigned char *) &__tramp[16] = 0x49; \
489 *(unsigned char *) &__tramp[17] = 0xba; \
490 *(void**) &__tramp[18] = __fun; /* mov __fun, %r10 */ \
491 *(unsigned char *) &__tramp[26] = 0x41; \
492 *(unsigned char *) &__tramp[27] = 0xff; \
493 *(unsigned char *) &__tramp[28] = 0xe2; /* jmp %r10 */ \
494 }
495
496/* How to make a trampoline. Derived from gcc/config/i386/i386.c. */
497
498#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \
Anthony Greencadeba62010-01-15 10:46:51 -0500499{ unsigned char *__tramp = (unsigned char*)(TRAMP); \
Anthony Greenc6dddbd2009-10-04 08:11:33 -0400500 unsigned int __fun = (unsigned int)(FUN); \
501 unsigned int __ctx = (unsigned int)(CTX); \
502 unsigned int __dis = __fun - (__ctx + 10); \
503 *(unsigned char*) &__tramp[0] = 0xb8; \
504 *(unsigned int*) &__tramp[1] = __ctx; /* movl __ctx, %eax */ \
505 *(unsigned char *) &__tramp[5] = 0xe9; \
506 *(unsigned int*) &__tramp[6] = __dis; /* jmp __fun */ \
Anthony Greencadeba62010-01-15 10:46:51 -0500507 }
Anthony Greenc6dddbd2009-10-04 08:11:33 -0400508
509#define FFI_INIT_TRAMPOLINE_STDCALL(TRAMP,FUN,CTX,SIZE) \
Anthony Greencadeba62010-01-15 10:46:51 -0500510{ unsigned char *__tramp = (unsigned char*)(TRAMP); \
Anthony Greenc6dddbd2009-10-04 08:11:33 -0400511 unsigned int __fun = (unsigned int)(FUN); \
512 unsigned int __ctx = (unsigned int)(CTX); \
513 unsigned int __dis = __fun - (__ctx + 10); \
514 unsigned short __size = (unsigned short)(SIZE); \
515 *(unsigned char*) &__tramp[0] = 0xb8; \
516 *(unsigned int*) &__tramp[1] = __ctx; /* movl __ctx, %eax */ \
517 *(unsigned char *) &__tramp[5] = 0xe8; \
518 *(unsigned int*) &__tramp[6] = __dis; /* call __fun */ \
519 *(unsigned char *) &__tramp[10] = 0xc2; \
520 *(unsigned short*) &__tramp[11] = __size; /* ret __size */ \
Anthony Greencadeba62010-01-15 10:46:51 -0500521 }
Anthony Greenc6dddbd2009-10-04 08:11:33 -0400522
523/* the cif must already be prep'ed */
524
525ffi_status
526ffi_prep_closure_loc (ffi_closure* closure,
527 ffi_cif* cif,
528 void (*fun)(ffi_cif*,void*,void**,void*),
529 void *user_data,
530 void *codeloc)
531{
532#ifdef X86_WIN64
533#define ISFLOAT(IDX) (cif->arg_types[IDX]->type == FFI_TYPE_FLOAT || cif->arg_types[IDX]->type == FFI_TYPE_DOUBLE)
534#define FLAG(IDX) (cif->nargs>(IDX)&&ISFLOAT(IDX)?(1<<(IDX)):0)
535 if (cif->abi == FFI_WIN64)
536 {
537 int mask = FLAG(0)|FLAG(1)|FLAG(2)|FLAG(3);
538 FFI_INIT_TRAMPOLINE_WIN64 (&closure->tramp[0],
539 &ffi_closure_win64,
540 codeloc, mask);
541 /* make sure we can execute here */
542 }
543#else
544 if (cif->abi == FFI_SYSV)
545 {
546 FFI_INIT_TRAMPOLINE (&closure->tramp[0],
547 &ffi_closure_SYSV,
548 (void*)codeloc);
549 }
550#ifdef X86_WIN32
551 else if (cif->abi == FFI_STDCALL)
552 {
553 FFI_INIT_TRAMPOLINE_STDCALL (&closure->tramp[0],
554 &ffi_closure_STDCALL,
555 (void*)codeloc, cif->bytes);
556 }
557#endif /* X86_WIN32 */
558#endif /* !X86_WIN64 */
559 else
560 {
561 return FFI_BAD_ABI;
562 }
563
564 closure->cif = cif;
565 closure->user_data = user_data;
566 closure->fun = fun;
567
568 return FFI_OK;
569}
570
571/* ------- Native raw API support -------------------------------- */
572
573#if !FFI_NO_RAW_API
574
575ffi_status
576ffi_prep_raw_closure_loc (ffi_raw_closure* closure,
577 ffi_cif* cif,
578 void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
579 void *user_data,
580 void *codeloc)
581{
582 int i;
583
584 if (cif->abi != FFI_SYSV) {
585 return FFI_BAD_ABI;
586 }
587
Anthony Green3de1eb32010-03-15 05:57:24 -0400588 /* we currently don't support certain kinds of arguments for raw
589 closures. This should be implemented by a separate assembly
590 language routine, since it would require argument processing,
591 something we don't do now for performance. */
Anthony Greenc6dddbd2009-10-04 08:11:33 -0400592
593 for (i = cif->nargs-1; i >= 0; i--)
594 {
595 FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_STRUCT);
596 FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_LONGDOUBLE);
597 }
598
599
600 FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_raw_SYSV,
601 codeloc);
602
603 closure->cif = cif;
604 closure->user_data = user_data;
605 closure->fun = fun;
606
607 return FFI_OK;
608}
609
610static void
611ffi_prep_args_raw(char *stack, extended_cif *ecif)
612{
613 memcpy (stack, ecif->avalue, ecif->cif->bytes);
614}
615
616/* we borrow this routine from libffi (it must be changed, though, to
617 * actually call the function passed in the first argument. as of
618 * libffi-1.20, this is not the case.)
619 */
620
Anthony Greenc6dddbd2009-10-04 08:11:33 -0400621void
622ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *fake_avalue)
623{
624 extended_cif ecif;
625 void **avalue = (void **)fake_avalue;
626
627 ecif.cif = cif;
628 ecif.avalue = avalue;
629
630 /* If the return value is a struct and we don't have a return */
631 /* value address then we need to make one */
632
633 if ((rvalue == NULL) &&
634 (cif->rtype->type == FFI_TYPE_STRUCT))
635 {
636 ecif.rvalue = alloca(cif->rtype->size);
637 }
638 else
639 ecif.rvalue = rvalue;
640
641
642 switch (cif->abi)
643 {
Anthony Greencadeba62010-01-15 10:46:51 -0500644#ifdef X86_WIN32
645 case FFI_SYSV:
646 case FFI_STDCALL:
647 ffi_call_win32(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags,
648 ecif.rvalue, fn);
649 break;
650#else
Anthony Greenc6dddbd2009-10-04 08:11:33 -0400651 case FFI_SYSV:
652 ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags,
653 ecif.rvalue, fn);
654 break;
Anthony Greencadeba62010-01-15 10:46:51 -0500655#endif
Anthony Greenc6dddbd2009-10-04 08:11:33 -0400656 default:
657 FFI_ASSERT(0);
658 break;
659 }
660}
661
662#endif
663
664#endif /* !__x86_64__ || X86_WIN64 */
665