2ab98d1a0d44d18fbdcc3b86bc9635ac87f60615
[libffi.git] / .pc / stdcall-x86-closure-fix / src / x86 / ffi.c
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, 2010 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
45 void 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 #ifdef X86_WIN32
52 size_t p_stack_args[2];
53 void *p_stack_data[2];
54 char *argp2 = stack;
55 int stack_args_count = 0;
56 int cabi = ecif->cif->abi;
57 #endif
58
59 argp = stack;
60
61 if (ecif->cif->flags == FFI_TYPE_STRUCT
62 #ifdef X86_WIN64
63 && (ecif->cif->rtype->size != 1 && ecif->cif->rtype->size != 2
64 && ecif->cif->rtype->size != 4 && ecif->cif->rtype->size != 8)
65 #endif
66 )
67 {
68 *(void **) argp = ecif->rvalue;
69 #ifdef X86_WIN32
70 /* For fastcall/thiscall this is first register-passed
71 argument. */
72 if (cabi == FFI_THISCALL || cabi == FFI_FASTCALL)
73 {
74 p_stack_args[stack_args_count] = sizeof (void*);
75 p_stack_data[stack_args_count] = argp;
76 ++stack_args_count;
77 }
78 #endif
79 argp += sizeof(void*);
80 }
81
82 p_argv = ecif->avalue;
83
84 for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
85 i != 0;
86 i--, p_arg++)
87 {
88 size_t z;
89
90 /* Align if necessary */
91 if ((sizeof(void*) - 1) & (size_t) argp)
92 argp = (char *) ALIGN(argp, sizeof(void*));
93
94 z = (*p_arg)->size;
95 #ifdef X86_WIN64
96 if (z > sizeof(ffi_arg)
97 || ((*p_arg)->type == FFI_TYPE_STRUCT
98 && (z != 1 && z != 2 && z != 4 && z != 8))
99 #if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
100 || ((*p_arg)->type == FFI_TYPE_LONGDOUBLE)
101 #endif
102 )
103 {
104 z = sizeof(ffi_arg);
105 *(void **)argp = *p_argv;
106 }
107 else if ((*p_arg)->type == FFI_TYPE_FLOAT)
108 {
109 memcpy(argp, *p_argv, z);
110 }
111 else
112 #endif
113 if (z < sizeof(ffi_arg))
114 {
115 z = sizeof(ffi_arg);
116 switch ((*p_arg)->type)
117 {
118 case FFI_TYPE_SINT8:
119 *(ffi_sarg *) argp = (ffi_sarg)*(SINT8 *)(* p_argv);
120 break;
121
122 case FFI_TYPE_UINT8:
123 *(ffi_arg *) argp = (ffi_arg)*(UINT8 *)(* p_argv);
124 break;
125
126 case FFI_TYPE_SINT16:
127 *(ffi_sarg *) argp = (ffi_sarg)*(SINT16 *)(* p_argv);
128 break;
129
130 case FFI_TYPE_UINT16:
131 *(ffi_arg *) argp = (ffi_arg)*(UINT16 *)(* p_argv);
132 break;
133
134 case FFI_TYPE_SINT32:
135 *(ffi_sarg *) argp = (ffi_sarg)*(SINT32 *)(* p_argv);
136 break;
137
138 case FFI_TYPE_UINT32:
139 *(ffi_arg *) argp = (ffi_arg)*(UINT32 *)(* p_argv);
140 break;
141
142 case FFI_TYPE_STRUCT:
143 *(ffi_arg *) argp = *(ffi_arg *)(* p_argv);
144 break;
145
146 default:
147 FFI_ASSERT(0);
148 }
149 }
150 else
151 {
152 memcpy(argp, *p_argv, z);
153 }
154
155 #ifdef X86_WIN32
156 /* For thiscall/fastcall convention register-passed arguments
157 are the first two none-floating-point arguments with a size
158 smaller or equal to sizeof (void*). */
159 if ((cabi == FFI_THISCALL && stack_args_count < 1)
160 || (cabi == FFI_FASTCALL && stack_args_count < 2))
161 {
162 if (z <= 4
163 && ((*p_arg)->type != FFI_TYPE_FLOAT
164 && (*p_arg)->type != FFI_TYPE_STRUCT))
165 {
166 p_stack_args[stack_args_count] = z;
167 p_stack_data[stack_args_count] = argp;
168 ++stack_args_count;
169 }
170 }
171 #endif
172 p_argv++;
173 #ifdef X86_WIN64
174 argp += (z + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
175 #else
176 argp += z;
177 #endif
178 }
179
180 #ifdef X86_WIN32
181 /* We need to move the register-passed arguments for thiscall/fastcall
182 on top of stack, so that those can be moved to registers ecx/edx by
183 call-handler. */
184 if (stack_args_count > 0)
185 {
186 size_t zz = (p_stack_args[0] + 3) & ~3;
187 char *h;
188
189 /* Move first argument to top-stack position. */
190 if (p_stack_data[0] != argp2)
191 {
192 h = alloca (zz + 1);
193 memcpy (h, p_stack_data[0], zz);
194 memmove (argp2 + zz, argp2,
195 (size_t) ((char *) p_stack_data[0] - (char*)argp2));
196 memcpy (argp2, h, zz);
197 }
198
199 argp2 += zz;
200 --stack_args_count;
201 if (zz > 4)
202 stack_args_count = 0;
203
204 /* If we have a second argument, then move it on top
205 after the first one. */
206 if (stack_args_count > 0 && p_stack_data[1] != argp2)
207 {
208 zz = p_stack_args[1];
209 zz = (zz + 3) & ~3;
210 h = alloca (zz + 1);
211 h = alloca (zz + 1);
212 memcpy (h, p_stack_data[1], zz);
213 memmove (argp2 + zz, argp2, (size_t) ((char*) p_stack_data[1] - (char*)argp2));
214 memcpy (argp2, h, zz);
215 }
216 }
217 #endif
218 return;
219 }
220
221 /* Perform machine dependent cif processing */
222 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
223 {
224 unsigned int i;
225 ffi_type **ptr;
226
227 /* Set the return type flag */
228 switch (cif->rtype->type)
229 {
230 case FFI_TYPE_VOID:
231 #if defined(X86) || defined (X86_WIN32) || defined(X86_FREEBSD) || defined(X86_DARWIN) || defined(X86_WIN64)
232 case FFI_TYPE_UINT8:
233 case FFI_TYPE_UINT16:
234 case FFI_TYPE_SINT8:
235 case FFI_TYPE_SINT16:
236 #endif
237 #ifdef X86_WIN64
238 case FFI_TYPE_UINT32:
239 case FFI_TYPE_SINT32:
240 #endif
241 case FFI_TYPE_SINT64:
242 case FFI_TYPE_FLOAT:
243 case FFI_TYPE_DOUBLE:
244 #ifndef X86_WIN64
245 #if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
246 case FFI_TYPE_LONGDOUBLE:
247 #endif
248 #endif
249 cif->flags = (unsigned) cif->rtype->type;
250 break;
251
252 case FFI_TYPE_UINT64:
253 #ifdef X86_WIN64
254 case FFI_TYPE_POINTER:
255 #endif
256 cif->flags = FFI_TYPE_SINT64;
257 break;
258
259 case FFI_TYPE_STRUCT:
260 #ifndef X86
261 if (cif->rtype->size == 1)
262 {
263 cif->flags = FFI_TYPE_SMALL_STRUCT_1B; /* same as char size */
264 }
265 else if (cif->rtype->size == 2)
266 {
267 cif->flags = FFI_TYPE_SMALL_STRUCT_2B; /* same as short size */
268 }
269 else if (cif->rtype->size == 4)
270 {
271 #ifdef X86_WIN64
272 cif->flags = FFI_TYPE_SMALL_STRUCT_4B;
273 #else
274 cif->flags = FFI_TYPE_INT; /* same as int type */
275 #endif
276 }
277 else if (cif->rtype->size == 8)
278 {
279 cif->flags = FFI_TYPE_SINT64; /* same as int64 type */
280 }
281 else
282 #endif
283 {
284 cif->flags = FFI_TYPE_STRUCT;
285 /* allocate space for return value pointer */
286 cif->bytes += ALIGN(sizeof(void*), FFI_SIZEOF_ARG);
287 }
288 break;
289
290 default:
291 #ifdef X86_WIN64
292 cif->flags = FFI_TYPE_SINT64;
293 break;
294 case FFI_TYPE_INT:
295 cif->flags = FFI_TYPE_SINT32;
296 #else
297 cif->flags = FFI_TYPE_INT;
298 #endif
299 break;
300 }
301
302 for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
303 {
304 if (((*ptr)->alignment - 1) & cif->bytes)
305 cif->bytes = ALIGN(cif->bytes, (*ptr)->alignment);
306 cif->bytes += ALIGN((*ptr)->size, FFI_SIZEOF_ARG);
307 }
308
309 #ifdef X86_WIN64
310 /* ensure space for storing four registers */
311 cif->bytes += 4 * sizeof(ffi_arg);
312 #endif
313
314 #ifdef X86_DARWIN
315 cif->bytes = (cif->bytes + 15) & ~0xF;
316 #endif
317
318 return FFI_OK;
319 }
320
321 #ifdef X86_WIN64
322 extern int
323 ffi_call_win64(void (*)(char *, extended_cif *), extended_cif *,
324 unsigned, unsigned, unsigned *, void (*fn)(void));
325 #elif defined(X86_WIN32)
326 extern void
327 ffi_call_win32(void (*)(char *, extended_cif *), extended_cif *,
328 unsigned, unsigned, unsigned, unsigned *, void (*fn)(void));
329 #else
330 extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
331 unsigned, unsigned, unsigned *, void (*fn)(void));
332 #endif
333
334 void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
335 {
336 extended_cif ecif;
337
338 ecif.cif = cif;
339 ecif.avalue = avalue;
340
341 /* If the return value is a struct and we don't have a return */
342 /* value address then we need to make one */
343
344 #ifdef X86_WIN64
345 if (rvalue == NULL
346 && cif->flags == FFI_TYPE_STRUCT
347 && cif->rtype->size != 1 && cif->rtype->size != 2
348 && cif->rtype->size != 4 && cif->rtype->size != 8)
349 {
350 ecif.rvalue = alloca((cif->rtype->size + 0xF) & ~0xF);
351 }
352 #else
353 if (rvalue == NULL
354 && cif->flags == FFI_TYPE_STRUCT)
355 {
356 ecif.rvalue = alloca(cif->rtype->size);
357 }
358 #endif
359 else
360 ecif.rvalue = rvalue;
361
362
363 switch (cif->abi)
364 {
365 #ifdef X86_WIN64
366 case FFI_WIN64:
367 ffi_call_win64(ffi_prep_args, &ecif, cif->bytes,
368 cif->flags, ecif.rvalue, fn);
369 break;
370 #elif defined(X86_WIN32)
371 case FFI_SYSV:
372 case FFI_STDCALL:
373 ffi_call_win32(ffi_prep_args, &ecif, cif->abi, cif->bytes, cif->flags,
374 ecif.rvalue, fn);
375 break;
376 case FFI_THISCALL:
377 case FFI_FASTCALL:
378 {
379 unsigned int abi = cif->abi;
380 unsigned int i, passed_regs = 0;
381
382 if (cif->flags == FFI_TYPE_STRUCT)
383 ++passed_regs;
384
385 for (i=0; i < cif->nargs && passed_regs < 2;i++)
386 {
387 size_t sz;
388
389 if (cif->arg_types[i]->type == FFI_TYPE_FLOAT
390 || cif->arg_types[i]->type == FFI_TYPE_STRUCT)
391 continue;
392 sz = (cif->arg_types[i]->size + 3) & ~3;
393 if (sz == 0 || sz > 4)
394 continue;
395 ++passed_regs;
396 }
397 if (passed_regs < 2 && abi == FFI_FASTCALL)
398 abi = FFI_THISCALL;
399 if (passed_regs < 1 && abi == FFI_THISCALL)
400 abi = FFI_STDCALL;
401 ffi_call_win32(ffi_prep_args, &ecif, abi, cif->bytes, cif->flags,
402 ecif.rvalue, fn);
403 }
404 break;
405 #else
406 case FFI_SYSV:
407 ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue,
408 fn);
409 break;
410 #endif
411 default:
412 FFI_ASSERT(0);
413 break;
414 }
415 }
416
417
418 /** private members **/
419
420 /* The following __attribute__((regparm(1))) decorations will have no effect
421 on MSVC - standard cdecl convention applies. */
422 static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
423 void** args, ffi_cif* cif);
424 void FFI_HIDDEN ffi_closure_SYSV (ffi_closure *)
425 __attribute__ ((regparm(1)));
426 unsigned int FFI_HIDDEN ffi_closure_SYSV_inner (ffi_closure *, void **, void *)
427 __attribute__ ((regparm(1)));
428 void FFI_HIDDEN ffi_closure_raw_SYSV (ffi_raw_closure *)
429 __attribute__ ((regparm(1)));
430 #ifdef X86_WIN32
431 void FFI_HIDDEN ffi_closure_STDCALL (ffi_closure *)
432 __attribute__ ((regparm(1)));
433 #endif
434 #ifdef X86_WIN64
435 void FFI_HIDDEN ffi_closure_win64 (ffi_closure *);
436 #endif
437
438 /* This function is jumped to by the trampoline */
439
440 #ifdef X86_WIN64
441 void * FFI_HIDDEN
442 ffi_closure_win64_inner (ffi_closure *closure, void *args) {
443 ffi_cif *cif;
444 void **arg_area;
445 void *result;
446 void *resp = &result;
447
448 cif = closure->cif;
449 arg_area = (void**) alloca (cif->nargs * sizeof (void*));
450
451 /* this call will initialize ARG_AREA, such that each
452 * element in that array points to the corresponding
453 * value on the stack; and if the function returns
454 * a structure, it will change RESP to point to the
455 * structure return address. */
456
457 ffi_prep_incoming_args_SYSV(args, &resp, arg_area, cif);
458
459 (closure->fun) (cif, resp, arg_area, closure->user_data);
460
461 /* The result is returned in rax. This does the right thing for
462 result types except for floats; we have to 'mov xmm0, rax' in the
463 caller to correct this.
464 TODO: structure sizes of 3 5 6 7 are returned by reference, too!!!
465 */
466 return cif->rtype->size > sizeof(void *) ? resp : *(void **)resp;
467 }
468
469 #else
470 unsigned int FFI_HIDDEN __attribute__ ((regparm(1)))
471 ffi_closure_SYSV_inner (ffi_closure *closure, void **respp, void *args)
472 {
473 /* our various things... */
474 ffi_cif *cif;
475 void **arg_area;
476
477 cif = closure->cif;
478 arg_area = (void**) alloca (cif->nargs * sizeof (void*));
479
480 /* this call will initialize ARG_AREA, such that each
481 * element in that array points to the corresponding
482 * value on the stack; and if the function returns
483 * a structure, it will change RESP to point to the
484 * structure return address. */
485
486 ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif);
487
488 (closure->fun) (cif, *respp, arg_area, closure->user_data);
489
490 return cif->flags;
491 }
492 #endif /* !X86_WIN64 */
493
494 static void
495 ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, void **avalue,
496 ffi_cif *cif)
497 {
498 register unsigned int i;
499 register void **p_argv;
500 register char *argp;
501 register ffi_type **p_arg;
502
503 argp = stack;
504
505 #ifdef X86_WIN64
506 if (cif->rtype->size > sizeof(ffi_arg)
507 || (cif->flags == FFI_TYPE_STRUCT
508 && (cif->rtype->size != 1 && cif->rtype->size != 2
509 && cif->rtype->size != 4 && cif->rtype->size != 8))) {
510 *rvalue = *(void **) argp;
511 argp += sizeof(void *);
512 }
513 #else
514 if ( cif->flags == FFI_TYPE_STRUCT ) {
515 *rvalue = *(void **) argp;
516 argp += sizeof(void *);
517 }
518 #endif
519
520 p_argv = avalue;
521
522 for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
523 {
524 size_t z;
525
526 /* Align if necessary */
527 if ((sizeof(void*) - 1) & (size_t) argp) {
528 argp = (char *) ALIGN(argp, sizeof(void*));
529 }
530
531 #ifdef X86_WIN64
532 if ((*p_arg)->size > sizeof(ffi_arg)
533 || ((*p_arg)->type == FFI_TYPE_STRUCT
534 && ((*p_arg)->size != 1 && (*p_arg)->size != 2
535 && (*p_arg)->size != 4 && (*p_arg)->size != 8)))
536 {
537 z = sizeof(void *);
538 *p_argv = *(void **)argp;
539 }
540 else
541 #endif
542 {
543 z = (*p_arg)->size;
544
545 /* because we're little endian, this is what it turns into. */
546
547 *p_argv = (void*) argp;
548 }
549
550 p_argv++;
551 #ifdef X86_WIN64
552 argp += (z + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
553 #else
554 argp += z;
555 #endif
556 }
557
558 return;
559 }
560
561 #define FFI_INIT_TRAMPOLINE_WIN64(TRAMP,FUN,CTX,MASK) \
562 { unsigned char *__tramp = (unsigned char*)(TRAMP); \
563 void* __fun = (void*)(FUN); \
564 void* __ctx = (void*)(CTX); \
565 *(unsigned char*) &__tramp[0] = 0x41; \
566 *(unsigned char*) &__tramp[1] = 0xbb; \
567 *(unsigned int*) &__tramp[2] = MASK; /* mov $mask, %r11 */ \
568 *(unsigned char*) &__tramp[6] = 0x48; \
569 *(unsigned char*) &__tramp[7] = 0xb8; \
570 *(void**) &__tramp[8] = __ctx; /* mov __ctx, %rax */ \
571 *(unsigned char *) &__tramp[16] = 0x49; \
572 *(unsigned char *) &__tramp[17] = 0xba; \
573 *(void**) &__tramp[18] = __fun; /* mov __fun, %r10 */ \
574 *(unsigned char *) &__tramp[26] = 0x41; \
575 *(unsigned char *) &__tramp[27] = 0xff; \
576 *(unsigned char *) &__tramp[28] = 0xe2; /* jmp %r10 */ \
577 }
578
579 /* How to make a trampoline. Derived from gcc/config/i386/i386.c. */
580
581 #define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \
582 { unsigned char *__tramp = (unsigned char*)(TRAMP); \
583 unsigned int __fun = (unsigned int)(FUN); \
584 unsigned int __ctx = (unsigned int)(CTX); \
585 unsigned int __dis = __fun - (__ctx + 10); \
586 *(unsigned char*) &__tramp[0] = 0xb8; \
587 *(unsigned int*) &__tramp[1] = __ctx; /* movl __ctx, %eax */ \
588 *(unsigned char *) &__tramp[5] = 0xe9; \
589 *(unsigned int*) &__tramp[6] = __dis; /* jmp __fun */ \
590 }
591
592 #define FFI_INIT_TRAMPOLINE_STDCALL(TRAMP,FUN,CTX,SIZE) \
593 { unsigned char *__tramp = (unsigned char*)(TRAMP); \
594 unsigned int __fun = (unsigned int)(FUN); \
595 unsigned int __ctx = (unsigned int)(CTX); \
596 unsigned int __dis = __fun - (__ctx + 10); \
597 unsigned short __size = (unsigned short)(SIZE); \
598 *(unsigned char*) &__tramp[0] = 0xb8; \
599 *(unsigned int*) &__tramp[1] = __ctx; /* movl __ctx, %eax */ \
600 *(unsigned char *) &__tramp[5] = 0xe8; \
601 *(unsigned int*) &__tramp[6] = __dis; /* call __fun */ \
602 *(unsigned char *) &__tramp[10] = 0xc2; \
603 *(unsigned short*) &__tramp[11] = __size; /* ret __size */ \
604 }
605
606 /* the cif must already be prep'ed */
607
608 ffi_status
609 ffi_prep_closure_loc (ffi_closure* closure,
610 ffi_cif* cif,
611 void (*fun)(ffi_cif*,void*,void**,void*),
612 void *user_data,
613 void *codeloc)
614 {
615 #ifdef X86_WIN64
616 #define ISFLOAT(IDX) (cif->arg_types[IDX]->type == FFI_TYPE_FLOAT || cif->arg_types[IDX]->type == FFI_TYPE_DOUBLE)
617 #define FLAG(IDX) (cif->nargs>(IDX)&&ISFLOAT(IDX)?(1<<(IDX)):0)
618 if (cif->abi == FFI_WIN64)
619 {
620 int mask = FLAG(0)|FLAG(1)|FLAG(2)|FLAG(3);
621 FFI_INIT_TRAMPOLINE_WIN64 (&closure->tramp[0],
622 &ffi_closure_win64,
623 codeloc, mask);
624 /* make sure we can execute here */
625 }
626 #else
627 if (cif->abi == FFI_SYSV)
628 {
629 FFI_INIT_TRAMPOLINE (&closure->tramp[0],
630 &ffi_closure_SYSV,
631 (void*)codeloc);
632 }
633 #ifdef X86_WIN32
634 else if (cif->abi == FFI_STDCALL)
635 {
636 FFI_INIT_TRAMPOLINE_STDCALL (&closure->tramp[0],
637 &ffi_closure_STDCALL,
638 (void*)codeloc, cif->bytes);
639 }
640 #endif /* X86_WIN32 */
641 #endif /* !X86_WIN64 */
642 else
643 {
644 return FFI_BAD_ABI;
645 }
646
647 closure->cif = cif;
648 closure->user_data = user_data;
649 closure->fun = fun;
650
651 return FFI_OK;
652 }
653
654 /* ------- Native raw API support -------------------------------- */
655
656 #if !FFI_NO_RAW_API
657
658 ffi_status
659 ffi_prep_raw_closure_loc (ffi_raw_closure* closure,
660 ffi_cif* cif,
661 void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
662 void *user_data,
663 void *codeloc)
664 {
665 int i;
666
667 if (cif->abi != FFI_SYSV) {
668 return FFI_BAD_ABI;
669 }
670
671 /* we currently don't support certain kinds of arguments for raw
672 closures. This should be implemented by a separate assembly
673 language routine, since it would require argument processing,
674 something we don't do now for performance. */
675
676 for (i = cif->nargs-1; i >= 0; i--)
677 {
678 FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_STRUCT);
679 FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_LONGDOUBLE);
680 }
681
682
683 FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_raw_SYSV,
684 codeloc);
685
686 closure->cif = cif;
687 closure->user_data = user_data;
688 closure->fun = fun;
689
690 return FFI_OK;
691 }
692
693 static void
694 ffi_prep_args_raw(char *stack, extended_cif *ecif)
695 {
696 memcpy (stack, ecif->avalue, ecif->cif->bytes);
697 }
698
699 /* we borrow this routine from libffi (it must be changed, though, to
700 * actually call the function passed in the first argument. as of
701 * libffi-1.20, this is not the case.)
702 */
703
704 void
705 ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *fake_avalue)
706 {
707 extended_cif ecif;
708 void **avalue = (void **)fake_avalue;
709
710 ecif.cif = cif;
711 ecif.avalue = avalue;
712
713 /* If the return value is a struct and we don't have a return */
714 /* value address then we need to make one */
715
716 if ((rvalue == NULL) &&
717 (cif->rtype->type == FFI_TYPE_STRUCT))
718 {
719 ecif.rvalue = alloca(cif->rtype->size);
720 }
721 else
722 ecif.rvalue = rvalue;
723
724
725 switch (cif->abi)
726 {
727 #ifdef X86_WIN32
728 case FFI_SYSV:
729 case FFI_STDCALL:
730 ffi_call_win32(ffi_prep_args, &ecif, cif->abi, cif->bytes, cif->flags,
731 ecif.rvalue, fn);
732 break;
733 case FFI_THISCALL:
734 case FFI_FASTCALL:
735 {
736 unsigned int abi = cif->abi;
737 unsigned int i, passed_regs = 0;
738
739 if (cif->flags == FFI_TYPE_STRUCT)
740 ++passed_regs;
741
742 for (i=0; i < cif->nargs && passed_regs < 2;i++)
743 {
744 size_t sz;
745
746 if (cif->arg_types[i]->type == FFI_TYPE_FLOAT
747 || cif->arg_types[i]->type == FFI_TYPE_STRUCT)
748 continue;
749 sz = (cif->arg_types[i]->size + 3) & ~3;
750 if (sz == 0 || sz > 4)
751 continue;
752 ++passed_regs;
753 }
754 if (passed_regs < 2 && abi == FFI_FASTCALL)
755 cif->abi = abi = FFI_THISCALL;
756 if (passed_regs < 1 && abi == FFI_THISCALL)
757 cif->abi = abi = FFI_STDCALL;
758 ffi_call_win32(ffi_prep_args, &ecif, abi, cif->bytes, cif->flags,
759 ecif.rvalue, fn);
760 }
761 break;
762 #else
763 case FFI_SYSV:
764 ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags,
765 ecif.rvalue, fn);
766 break;
767 #endif
768 default:
769 FFI_ASSERT(0);
770 break;
771 }
772 }
773
774 #endif
775
776 #endif /* !__x86_64__ || X86_WIN64 */
777