1 /* -----------------------------------------------------------------------
2 ffi64.c - Copyright (c) 2011, 2018 Anthony Green
3 Copyright (c) 2013 The Written Word, Inc.
4 Copyright (c) 2008, 2010 Red Hat, Inc.
5 Copyright (c) 2002, 2007 Bo Thorsen <bo@suse.de>
7 x86-64 Foreign Function Interface
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:
17 The above copyright notice and this permission notice shall be included
18 in all copies or substantial portions of the Software.
20 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
21 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 DEALINGS IN THE SOFTWARE.
28 ----------------------------------------------------------------------- */
31 #include <ffi_common.h>
37 #include "internal64.h"
41 #define MAX_GPR_REGS 6
42 #define MAX_SSE_REGS 8
44 #if defined(__INTEL_COMPILER)
45 #include "xmmintrin.h"
46 #define UINT128 __m128
48 #if defined(__SUNPRO_C)
49 #include <sunmedia_types.h>
50 #define UINT128 __m128i
52 #define UINT128 __int128_t
65 /* Registers for argument passing. */
66 UINT64 gpr[MAX_GPR_REGS];
67 union big_int_union sse[MAX_SSE_REGS];
68 UINT64 rax; /* ssecount */
69 UINT64 r10; /* static chain */
72 extern void ffi_call_unix64 (void *args, unsigned long bytes, unsigned flags,
73 void *raddr, void (*fnaddr)(void)) FFI_HIDDEN;
75 /* All reference to register classes here is identical to the code in
76 gcc/config/i386/i386.c. Do *not* change one without the other. */
78 /* Register class used for passing given 64bit part of the argument.
79 These represent classes as documented by the PS ABI, with the
80 exception of SSESF, SSEDF classes, that are basically SSE class,
81 just gcc will use SF or DFmode move instead of DImode to avoid
82 reformatting penalties.
84 Similary we play games with INTEGERSI_CLASS to use cheaper SImode moves
85 whenever possible (upper half does contain padding). */
90 X86_64_INTEGERSI_CLASS,
97 X86_64_COMPLEX_X87_CLASS,
101 #define MAX_CLASSES 4
103 #define SSE_CLASS_P(X) ((X) >= X86_64_SSE_CLASS && X <= X86_64_SSEUP_CLASS)
105 /* x86-64 register passing implementation. See x86-64 ABI for details. Goal
106 of this code is to classify each 8bytes of incoming argument by the register
107 class and assign registers accordingly. */
109 /* Return the union class of CLASS1 and CLASS2.
110 See the x86-64 PS ABI for details. */
112 static enum x86_64_reg_class
113 merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2)
115 /* Rule #1: If both classes are equal, this is the resulting class. */
116 if (class1 == class2)
119 /* Rule #2: If one of the classes is NO_CLASS, the resulting class is
121 if (class1 == X86_64_NO_CLASS)
123 if (class2 == X86_64_NO_CLASS)
126 /* Rule #3: If one of the classes is MEMORY, the result is MEMORY. */
127 if (class1 == X86_64_MEMORY_CLASS || class2 == X86_64_MEMORY_CLASS)
128 return X86_64_MEMORY_CLASS;
130 /* Rule #4: If one of the classes is INTEGER, the result is INTEGER. */
131 if ((class1 == X86_64_INTEGERSI_CLASS && class2 == X86_64_SSESF_CLASS)
132 || (class2 == X86_64_INTEGERSI_CLASS && class1 == X86_64_SSESF_CLASS))
133 return X86_64_INTEGERSI_CLASS;
134 if (class1 == X86_64_INTEGER_CLASS || class1 == X86_64_INTEGERSI_CLASS
135 || class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS)
136 return X86_64_INTEGER_CLASS;
138 /* Rule #5: If one of the classes is X87, X87UP, or COMPLEX_X87 class,
140 if (class1 == X86_64_X87_CLASS
141 || class1 == X86_64_X87UP_CLASS
142 || class1 == X86_64_COMPLEX_X87_CLASS
143 || class2 == X86_64_X87_CLASS
144 || class2 == X86_64_X87UP_CLASS
145 || class2 == X86_64_COMPLEX_X87_CLASS)
146 return X86_64_MEMORY_CLASS;
148 /* Rule #6: Otherwise class SSE is used. */
149 return X86_64_SSE_CLASS;
152 /* Classify the argument of type TYPE and mode MODE.
153 CLASSES will be filled by the register class used to pass each word
154 of the operand. The number of words is returned. In case the parameter
155 should be passed in memory, 0 is returned. As a special case for zero
156 sized containers, classes[0] will be NO_CLASS and 1 is returned.
158 See the x86-64 PS ABI for details.
161 classify_argument (ffi_type *type, enum x86_64_reg_class classes[],
168 case FFI_TYPE_UINT16:
169 case FFI_TYPE_SINT16:
170 case FFI_TYPE_UINT32:
171 case FFI_TYPE_SINT32:
172 case FFI_TYPE_UINT64:
173 case FFI_TYPE_SINT64:
174 case FFI_TYPE_POINTER:
177 size_t size = byte_offset + type->size;
181 classes[0] = X86_64_INTEGERSI_CLASS;
186 classes[0] = X86_64_INTEGER_CLASS;
191 classes[0] = X86_64_INTEGER_CLASS;
192 classes[1] = X86_64_INTEGERSI_CLASS;
197 classes[0] = classes[1] = X86_64_INTEGER_CLASS;
204 if (!(byte_offset % 8))
205 classes[0] = X86_64_SSESF_CLASS;
207 classes[0] = X86_64_SSE_CLASS;
209 case FFI_TYPE_DOUBLE:
210 classes[0] = X86_64_SSEDF_CLASS;
212 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
213 case FFI_TYPE_LONGDOUBLE:
214 classes[0] = X86_64_X87_CLASS;
215 classes[1] = X86_64_X87UP_CLASS;
218 case FFI_TYPE_STRUCT:
220 const size_t UNITS_PER_WORD = 8;
221 size_t words = (type->size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
224 enum x86_64_reg_class subclasses[MAX_CLASSES];
226 /* If the struct is larger than 32 bytes, pass it on the stack. */
230 for (i = 0; i < words; i++)
231 classes[i] = X86_64_NO_CLASS;
233 /* Zero sized arrays or structures are NO_CLASS. We return 0 to
234 signalize memory class, so handle it as special case. */
238 classes[0] = X86_64_NO_CLASS;
242 /* Merge the fields of structure. */
243 for (ptr = type->elements; *ptr != NULL; ptr++)
247 byte_offset = FFI_ALIGN (byte_offset, (*ptr)->alignment);
249 num = classify_argument (*ptr, subclasses, byte_offset % 8);
252 for (i = 0; i < num; i++)
254 size_t pos = byte_offset / 8;
256 merge_classes (subclasses[i], classes[i + pos]);
259 byte_offset += (*ptr)->size;
264 /* When size > 16 bytes, if the first one isn't
265 X86_64_SSE_CLASS or any other ones aren't
266 X86_64_SSEUP_CLASS, everything should be passed in
268 if (classes[0] != X86_64_SSE_CLASS)
271 for (i = 1; i < words; i++)
272 if (classes[i] != X86_64_SSEUP_CLASS)
276 /* Final merger cleanup. */
277 for (i = 0; i < words; i++)
279 /* If one class is MEMORY, everything should be passed in
281 if (classes[i] == X86_64_MEMORY_CLASS)
284 /* The X86_64_SSEUP_CLASS should be always preceded by
285 X86_64_SSE_CLASS or X86_64_SSEUP_CLASS. */
286 if (i > 1 && classes[i] == X86_64_SSEUP_CLASS
287 && classes[i - 1] != X86_64_SSE_CLASS
288 && classes[i - 1] != X86_64_SSEUP_CLASS)
290 /* The first one should never be X86_64_SSEUP_CLASS. */
292 classes[i] = X86_64_SSE_CLASS;
295 /* If X86_64_X87UP_CLASS isn't preceded by X86_64_X87_CLASS,
296 everything should be passed in memory. */
297 if (i > 1 && classes[i] == X86_64_X87UP_CLASS
298 && (classes[i - 1] != X86_64_X87_CLASS))
300 /* The first one should never be X86_64_X87UP_CLASS. */
307 case FFI_TYPE_COMPLEX:
309 ffi_type *inner = type->elements[0];
315 case FFI_TYPE_UINT16:
316 case FFI_TYPE_SINT16:
317 case FFI_TYPE_UINT32:
318 case FFI_TYPE_SINT32:
319 case FFI_TYPE_UINT64:
320 case FFI_TYPE_SINT64:
324 classes[0] = X86_64_SSE_CLASS;
327 classes[1] = X86_64_SSESF_CLASS;
331 case FFI_TYPE_DOUBLE:
332 classes[0] = classes[1] = X86_64_SSEDF_CLASS;
334 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
335 case FFI_TYPE_LONGDOUBLE:
336 classes[0] = X86_64_COMPLEX_X87_CLASS;
345 /* Examine the argument and return set number of register required in each
346 class. Return zero iff parameter should be passed in memory, otherwise
347 the number of registers. */
350 examine_argument (ffi_type *type, enum x86_64_reg_class classes[MAX_CLASSES],
351 _Bool in_return, int *pngpr, int *pnsse)
357 n = classify_argument (type, classes, 0);
362 for (i = 0; i < n; ++i)
365 case X86_64_INTEGER_CLASS:
366 case X86_64_INTEGERSI_CLASS:
369 case X86_64_SSE_CLASS:
370 case X86_64_SSESF_CLASS:
371 case X86_64_SSEDF_CLASS:
374 case X86_64_NO_CLASS:
375 case X86_64_SSEUP_CLASS:
377 case X86_64_X87_CLASS:
378 case X86_64_X87UP_CLASS:
379 case X86_64_COMPLEX_X87_CLASS:
380 return in_return != 0;
391 /* Perform machine dependent cif processing. */
395 ffi_prep_cif_machdep_efi64(ffi_cif *cif);
398 ffi_status FFI_HIDDEN
399 ffi_prep_cif_machdep (ffi_cif *cif)
401 int gprcount, ssecount, i, avn, ngpr, nsse;
403 enum x86_64_reg_class classes[MAX_CLASSES];
404 size_t bytes, n, rtype_size;
408 if (cif->abi == FFI_EFI64 || cif->abi == FFI_GNUW64)
409 return ffi_prep_cif_machdep_efi64(cif);
411 if (cif->abi != FFI_UNIX64)
414 gprcount = ssecount = 0;
417 rtype_size = rtype->size;
421 flags = UNIX64_RET_VOID;
424 flags = UNIX64_RET_UINT8;
427 flags = UNIX64_RET_SINT8;
429 case FFI_TYPE_UINT16:
430 flags = UNIX64_RET_UINT16;
432 case FFI_TYPE_SINT16:
433 flags = UNIX64_RET_SINT16;
435 case FFI_TYPE_UINT32:
436 flags = UNIX64_RET_UINT32;
439 case FFI_TYPE_SINT32:
440 flags = UNIX64_RET_SINT32;
442 case FFI_TYPE_UINT64:
443 case FFI_TYPE_SINT64:
444 flags = UNIX64_RET_INT64;
446 case FFI_TYPE_POINTER:
447 flags = (sizeof(void *) == 4 ? UNIX64_RET_UINT32 : UNIX64_RET_INT64);
450 flags = UNIX64_RET_XMM32;
452 case FFI_TYPE_DOUBLE:
453 flags = UNIX64_RET_XMM64;
455 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
456 case FFI_TYPE_LONGDOUBLE:
457 flags = UNIX64_RET_X87;
460 case FFI_TYPE_STRUCT:
461 n = examine_argument (cif->rtype, classes, 1, &ngpr, &nsse);
464 /* The return value is passed in memory. A pointer to that
465 memory is the first argument. Allocate a register for it. */
467 /* We don't have to do anything in asm for the return. */
468 flags = UNIX64_RET_VOID | UNIX64_FLAG_RET_IN_MEM;
472 _Bool sse0 = SSE_CLASS_P (classes[0]);
474 if (rtype_size == 4 && sse0)
475 flags = UNIX64_RET_XMM32;
476 else if (rtype_size == 8)
477 flags = sse0 ? UNIX64_RET_XMM64 : UNIX64_RET_INT64;
480 _Bool sse1 = n == 2 && SSE_CLASS_P (classes[1]);
482 flags = UNIX64_RET_ST_XMM0_XMM1;
484 flags = UNIX64_RET_ST_XMM0_RAX;
486 flags = UNIX64_RET_ST_RAX_XMM0;
488 flags = UNIX64_RET_ST_RAX_RDX;
489 flags |= rtype_size << UNIX64_SIZE_SHIFT;
493 case FFI_TYPE_COMPLEX:
494 switch (rtype->elements[0]->type)
498 case FFI_TYPE_UINT16:
499 case FFI_TYPE_SINT16:
501 case FFI_TYPE_UINT32:
502 case FFI_TYPE_SINT32:
503 case FFI_TYPE_UINT64:
504 case FFI_TYPE_SINT64:
505 flags = UNIX64_RET_ST_RAX_RDX | ((unsigned) rtype_size << UNIX64_SIZE_SHIFT);
508 flags = UNIX64_RET_XMM64;
510 case FFI_TYPE_DOUBLE:
511 flags = UNIX64_RET_ST_XMM0_XMM1 | (16 << UNIX64_SIZE_SHIFT);
513 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
514 case FFI_TYPE_LONGDOUBLE:
515 flags = UNIX64_RET_X87_2;
519 return FFI_BAD_TYPEDEF;
523 return FFI_BAD_TYPEDEF;
526 /* Go over all arguments and determine the way they should be passed.
527 If it's in a register and there is space for it, let that be so. If
528 not, add it's size to the stack byte count. */
529 for (bytes = 0, i = 0, avn = cif->nargs; i < avn; i++)
531 if (examine_argument (cif->arg_types[i], classes, 0, &ngpr, &nsse) == 0
532 || gprcount + ngpr > MAX_GPR_REGS
533 || ssecount + nsse > MAX_SSE_REGS)
535 long align = cif->arg_types[i]->alignment;
540 bytes = FFI_ALIGN (bytes, align);
541 bytes += cif->arg_types[i]->size;
550 flags |= UNIX64_FLAG_XMM_ARGS;
553 cif->bytes = (unsigned) FFI_ALIGN (bytes, 8);
559 ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
560 void **avalue, void *closure)
562 enum x86_64_reg_class classes[MAX_CLASSES];
564 ffi_type **arg_types;
565 int gprcount, ssecount, ngpr, nsse, i, avn, flags;
566 struct register_args *reg_args;
568 /* Can't call 32-bit mode from 64-bit mode. */
569 FFI_ASSERT (cif->abi == FFI_UNIX64);
571 /* If the return value is a struct and we don't have a return value
572 address then we need to make one. Otherwise we can ignore it. */
576 if (flags & UNIX64_FLAG_RET_IN_MEM)
577 rvalue = alloca (cif->rtype->size);
579 flags = UNIX64_RET_VOID;
582 /* Allocate the space for the arguments, plus 4 words of temp space. */
583 stack = alloca (sizeof (struct register_args) + cif->bytes + 4*8);
584 reg_args = (struct register_args *) stack;
585 argp = stack + sizeof (struct register_args);
587 reg_args->r10 = (uintptr_t) closure;
589 gprcount = ssecount = 0;
591 /* If the return value is passed in memory, add the pointer as the
592 first integer argument. */
593 if (flags & UNIX64_FLAG_RET_IN_MEM)
594 reg_args->gpr[gprcount++] = (unsigned long) rvalue;
597 arg_types = cif->arg_types;
599 for (i = 0; i < avn; ++i)
601 size_t n, size = arg_types[i]->size;
603 n = examine_argument (arg_types[i], classes, 0, &ngpr, &nsse);
605 || gprcount + ngpr > MAX_GPR_REGS
606 || ssecount + nsse > MAX_SSE_REGS)
608 long align = arg_types[i]->alignment;
610 /* Stack arguments are *always* at least 8 byte aligned. */
614 /* Pass this argument in memory. */
615 argp = (void *) FFI_ALIGN (argp, align);
616 memcpy (argp, avalue[i], size);
621 /* The argument is passed entirely in registers. */
622 char *a = (char *) avalue[i];
625 for (j = 0; j < n; j++, a += 8, size -= 8)
629 case X86_64_NO_CLASS:
630 case X86_64_SSEUP_CLASS:
632 case X86_64_INTEGER_CLASS:
633 case X86_64_INTEGERSI_CLASS:
634 /* Sign-extend integer arguments passed in general
635 purpose registers, to cope with the fact that
636 LLVM incorrectly assumes that this will be done
637 (the x86-64 PS ABI does not specify this). */
638 switch (arg_types[i]->type)
641 reg_args->gpr[gprcount] = (SINT64) *((SINT8 *) a);
643 case FFI_TYPE_SINT16:
644 reg_args->gpr[gprcount] = (SINT64) *((SINT16 *) a);
646 case FFI_TYPE_SINT32:
647 reg_args->gpr[gprcount] = (SINT64) *((SINT32 *) a);
650 reg_args->gpr[gprcount] = 0;
651 memcpy (®_args->gpr[gprcount], a, size);
655 case X86_64_SSE_CLASS:
656 case X86_64_SSEDF_CLASS:
657 memcpy (®_args->sse[ssecount++].i64, a, sizeof(UINT64));
659 case X86_64_SSESF_CLASS:
660 memcpy (®_args->sse[ssecount++].i32, a, sizeof(UINT32));
668 reg_args->rax = ssecount;
670 ffi_call_unix64 (stack, cif->bytes + sizeof (struct register_args),
676 ffi_call_efi64(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue);
680 ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
683 if (cif->abi == FFI_EFI64 || cif->abi == FFI_GNUW64)
685 ffi_call_efi64(cif, fn, rvalue, avalue);
689 ffi_call_int (cif, fn, rvalue, avalue, NULL);
692 #ifdef FFI_GO_CLOSURES
696 ffi_call_go_efi64(ffi_cif *cif, void (*fn)(void), void *rvalue,
697 void **avalue, void *closure);
701 ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
702 void **avalue, void *closure)
705 if (cif->abi == FFI_EFI64 || cif->abi == FFI_GNUW64)
707 ffi_call_go_efi64(cif, fn, rvalue, avalue, closure);
711 ffi_call_int (cif, fn, rvalue, avalue, closure);
714 #endif /* FFI_GO_CLOSURES */
716 extern void ffi_closure_unix64(void) FFI_HIDDEN;
717 extern void ffi_closure_unix64_sse(void) FFI_HIDDEN;
718 #if defined(FFI_EXEC_STATIC_TRAMP)
719 extern void ffi_closure_unix64_alt(void) FFI_HIDDEN;
720 extern void ffi_closure_unix64_sse_alt(void) FFI_HIDDEN;
725 ffi_prep_closure_loc_efi64(ffi_closure* closure,
727 void (*fun)(ffi_cif*, void*, void**, void*),
733 ffi_prep_closure_loc (ffi_closure* closure,
735 void (*fun)(ffi_cif*, void*, void**, void*),
739 static const unsigned char trampoline[24] = {
741 0xf3, 0x0f, 0x1e, 0xfa,
742 /* leaq -0xb(%rip),%r10 # 0x0 */
743 0x4c, 0x8d, 0x15, 0xf5, 0xff, 0xff, 0xff,
744 /* jmpq *0x7(%rip) # 0x18 */
745 0xff, 0x25, 0x07, 0x00, 0x00, 0x00,
747 0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00
750 char *tramp = closure->tramp;
753 if (cif->abi == FFI_EFI64 || cif->abi == FFI_GNUW64)
754 return ffi_prep_closure_loc_efi64(closure, cif, fun, user_data, codeloc);
756 if (cif->abi != FFI_UNIX64)
759 if (cif->flags & UNIX64_FLAG_XMM_ARGS)
760 dest = ffi_closure_unix64_sse;
762 dest = ffi_closure_unix64;
764 #if defined(FFI_EXEC_STATIC_TRAMP)
765 if (ffi_tramp_is_present(closure))
767 /* Initialize the static trampoline's parameters. */
768 if (dest == ffi_closure_unix64_sse)
769 dest = ffi_closure_unix64_sse_alt;
771 dest = ffi_closure_unix64_alt;
772 ffi_tramp_set_parms (closure->ftramp, dest, closure);
777 /* Initialize the dynamic trampoline. */
778 memcpy (tramp, trampoline, sizeof(trampoline));
779 *(UINT64 *)(tramp + sizeof (trampoline)) = (uintptr_t)dest;
784 closure->user_data = user_data;
790 ffi_closure_unix64_inner(ffi_cif *cif,
791 void (*fun)(ffi_cif*, void*, void**, void*),
794 struct register_args *reg_args,
798 ffi_type **arg_types;
800 int gprcount, ssecount, ngpr, nsse;
805 avalue = alloca(avn * sizeof(void *));
806 gprcount = ssecount = 0;
808 if (flags & UNIX64_FLAG_RET_IN_MEM)
810 /* On return, %rax will contain the address that was passed
811 by the caller in %rdi. */
812 void *r = (void *)(uintptr_t)reg_args->gpr[gprcount++];
813 *(void **)rvalue = r;
815 flags = (sizeof(void *) == 4 ? UNIX64_RET_UINT32 : UNIX64_RET_INT64);
818 arg_types = cif->arg_types;
819 for (i = 0; i < avn; ++i)
821 enum x86_64_reg_class classes[MAX_CLASSES];
824 n = examine_argument (arg_types[i], classes, 0, &ngpr, &nsse);
826 || gprcount + ngpr > MAX_GPR_REGS
827 || ssecount + nsse > MAX_SSE_REGS)
829 long align = arg_types[i]->alignment;
831 /* Stack arguments are *always* at least 8 byte aligned. */
835 /* Pass this argument in memory. */
836 argp = (void *) FFI_ALIGN (argp, align);
838 argp += arg_types[i]->size;
840 /* If the argument is in a single register, or two consecutive
841 integer registers, then we can use that address directly. */
843 || (n == 2 && !(SSE_CLASS_P (classes[0])
844 || SSE_CLASS_P (classes[1]))))
846 /* The argument is in a single register. */
847 if (SSE_CLASS_P (classes[0]))
849 avalue[i] = ®_args->sse[ssecount];
854 avalue[i] = ®_args->gpr[gprcount];
858 /* Otherwise, allocate space to make them consecutive. */
861 char *a = alloca (16);
865 for (j = 0; j < n; j++, a += 8)
867 if (SSE_CLASS_P (classes[j]))
868 memcpy (a, ®_args->sse[ssecount++], 8);
870 memcpy (a, ®_args->gpr[gprcount++], 8);
875 /* Invoke the closure. */
876 fun (cif, rvalue, avalue, user_data);
878 /* Tell assembly how to perform return type promotions. */
882 #ifdef FFI_GO_CLOSURES
884 extern void ffi_go_closure_unix64(void) FFI_HIDDEN;
885 extern void ffi_go_closure_unix64_sse(void) FFI_HIDDEN;
889 ffi_prep_go_closure_efi64(ffi_go_closure* closure, ffi_cif* cif,
890 void (*fun)(ffi_cif*, void*, void**, void*));
894 ffi_prep_go_closure (ffi_go_closure* closure, ffi_cif* cif,
895 void (*fun)(ffi_cif*, void*, void**, void*))
898 if (cif->abi == FFI_EFI64 || cif->abi == FFI_GNUW64)
899 return ffi_prep_go_closure_efi64(closure, cif, fun);
901 if (cif->abi != FFI_UNIX64)
904 closure->tramp = (cif->flags & UNIX64_FLAG_XMM_ARGS
905 ? ffi_go_closure_unix64_sse
906 : ffi_go_closure_unix64);
913 #endif /* FFI_GO_CLOSURES */
915 #if defined(FFI_EXEC_STATIC_TRAMP)
917 ffi_tramp_arch (size_t *tramp_size, size_t *map_size)
919 extern void *trampoline_code_table;
921 *map_size = UNIX64_TRAMP_MAP_SIZE;
922 *tramp_size = UNIX64_TRAMP_SIZE;
923 return &trampoline_code_table;
927 #endif /* __x86_64__ */