Static tramp v5 (#624)
[platform/upstream/libffi.git] / src / aarch64 / ffi.c
1 /* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd.
2
3 Permission is hereby granted, free of charge, to any person obtaining
4 a copy of this software and associated documentation files (the
5 ``Software''), to deal in the Software without restriction, including
6 without limitation the rights to use, copy, modify, merge, publish,
7 distribute, sublicense, and/or sell copies of the Software, and to
8 permit persons to whom the Software is furnished to do so, subject to
9 the following conditions:
10
11 The above copyright notice and this permission notice shall be
12 included in all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
15 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
21
22 #if defined(__aarch64__) || defined(__arm64__)|| defined (_M_ARM64)
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <stdint.h>
26 #include <fficonfig.h>
27 #include <ffi.h>
28 #include <ffi_common.h>
29 #include "internal.h"
30 #ifdef _WIN32
31 #include <windows.h> /* FlushInstructionCache */
32 #endif
33 #include <tramp.h>
34
35 /* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE;
36    all further uses in this file will refer to the 128-bit type.  */
37 #if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
38 # if FFI_TYPE_LONGDOUBLE != 4
39 #  error FFI_TYPE_LONGDOUBLE out of date
40 # endif
41 #else
42 # undef FFI_TYPE_LONGDOUBLE
43 # define FFI_TYPE_LONGDOUBLE 4
44 #endif
45
46 union _d
47 {
48   UINT64 d;
49   UINT32 s[2];
50 };
51
52 struct _v
53 {
54   union _d d[2] __attribute__((aligned(16)));
55 };
56
57 struct call_context
58 {
59   struct _v v[N_V_ARG_REG];
60   UINT64 x[N_X_ARG_REG];
61 };
62
63 #if FFI_EXEC_TRAMPOLINE_TABLE
64
65 #ifdef __MACH__
66 #ifdef HAVE_PTRAUTH
67 #include <ptrauth.h>
68 #endif
69 #include <mach/vm_param.h>
70 #endif
71
72 #else
73
74 #if defined (__clang__) && defined (__APPLE__)
75 extern void sys_icache_invalidate (void *start, size_t len);
76 #endif
77
78 static inline void
79 ffi_clear_cache (void *start, void *end)
80 {
81 #if defined (__clang__) && defined (__APPLE__)
82   sys_icache_invalidate (start, (char *)end - (char *)start);
83 #elif defined (__GNUC__)
84   __builtin___clear_cache (start, end);
85 #elif defined (_WIN32)
86   FlushInstructionCache(GetCurrentProcess(), start, (char*)end - (char*)start);
87 #else
88 #error "Missing builtin to flush instruction cache"
89 #endif
90 }
91
92 #endif
93
94 /* A subroutine of is_vfp_type.  Given a structure type, return the type code
95    of the first non-structure element.  Recurse for structure elements.
96    Return -1 if the structure is in fact empty, i.e. no nested elements.  */
97
98 static int
99 is_hfa0 (const ffi_type *ty)
100 {
101   ffi_type **elements = ty->elements;
102   int i, ret = -1;
103
104   if (elements != NULL)
105     for (i = 0; elements[i]; ++i)
106       {
107         ret = elements[i]->type;
108         if (ret == FFI_TYPE_STRUCT || ret == FFI_TYPE_COMPLEX)
109           {
110             ret = is_hfa0 (elements[i]);
111             if (ret < 0)
112               continue;
113           }
114         break;
115       }
116
117   return ret;
118 }
119
120 /* A subroutine of is_vfp_type.  Given a structure type, return true if all
121    of the non-structure elements are the same as CANDIDATE.  */
122
123 static int
124 is_hfa1 (const ffi_type *ty, int candidate)
125 {
126   ffi_type **elements = ty->elements;
127   int i;
128
129   if (elements != NULL)
130     for (i = 0; elements[i]; ++i)
131       {
132         int t = elements[i]->type;
133         if (t == FFI_TYPE_STRUCT || t == FFI_TYPE_COMPLEX)
134           {
135             if (!is_hfa1 (elements[i], candidate))
136               return 0;
137           }
138         else if (t != candidate)
139           return 0;
140       }
141
142   return 1;
143 }
144
145 /* Determine if TY may be allocated to the FP registers.  This is both an
146    fp scalar type as well as an homogenous floating point aggregate (HFA).
147    That is, a structure consisting of 1 to 4 members of all the same type,
148    where that type is an fp scalar.
149
150    Returns non-zero iff TY is an HFA.  The result is the AARCH64_RET_*
151    constant for the type.  */
152
153 static int
154 is_vfp_type (const ffi_type *ty)
155 {
156   ffi_type **elements;
157   int candidate, i;
158   size_t size, ele_count;
159
160   /* Quickest tests first.  */
161   candidate = ty->type;
162   switch (candidate)
163     {
164     default:
165       return 0;
166     case FFI_TYPE_FLOAT:
167     case FFI_TYPE_DOUBLE:
168     case FFI_TYPE_LONGDOUBLE:
169       ele_count = 1;
170       goto done;
171     case FFI_TYPE_COMPLEX:
172       candidate = ty->elements[0]->type;
173       switch (candidate)
174         {
175         case FFI_TYPE_FLOAT:
176         case FFI_TYPE_DOUBLE:
177         case FFI_TYPE_LONGDOUBLE:
178           ele_count = 2;
179           goto done;
180         }
181       return 0;
182     case FFI_TYPE_STRUCT:
183       break;
184     }
185
186   /* No HFA types are smaller than 4 bytes, or larger than 64 bytes.  */
187   size = ty->size;
188   if (size < 4 || size > 64)
189     return 0;
190
191   /* Find the type of the first non-structure member.  */
192   elements = ty->elements;
193   candidate = elements[0]->type;
194   if (candidate == FFI_TYPE_STRUCT || candidate == FFI_TYPE_COMPLEX)
195     {
196       for (i = 0; ; ++i)
197         {
198           candidate = is_hfa0 (elements[i]);
199           if (candidate >= 0)
200             break;
201         }
202     }
203
204   /* If the first member is not a floating point type, it's not an HFA.
205      Also quickly re-check the size of the structure.  */
206   switch (candidate)
207     {
208     case FFI_TYPE_FLOAT:
209       ele_count = size / sizeof(float);
210       if (size != ele_count * sizeof(float))
211         return 0;
212       break;
213     case FFI_TYPE_DOUBLE:
214       ele_count = size / sizeof(double);
215       if (size != ele_count * sizeof(double))
216         return 0;
217       break;
218     case FFI_TYPE_LONGDOUBLE:
219       ele_count = size / sizeof(long double);
220       if (size != ele_count * sizeof(long double))
221         return 0;
222       break;
223     default:
224       return 0;
225     }
226   if (ele_count > 4)
227     return 0;
228
229   /* Finally, make sure that all scalar elements are the same type.  */
230   for (i = 0; elements[i]; ++i)
231     {
232       int t = elements[i]->type;
233       if (t == FFI_TYPE_STRUCT || t == FFI_TYPE_COMPLEX)
234         {
235           if (!is_hfa1 (elements[i], candidate))
236             return 0;
237         }
238       else if (t != candidate)
239         return 0;
240     }
241
242   /* All tests succeeded.  Encode the result.  */
243  done:
244   return candidate * 4 + (4 - (int)ele_count);
245 }
246
247 /* Representation of the procedure call argument marshalling
248    state.
249
250    The terse state variable names match the names used in the AARCH64
251    PCS. */
252
253 struct arg_state
254 {
255   unsigned ngrn;                /* Next general-purpose register number. */
256   unsigned nsrn;                /* Next vector register number. */
257   size_t nsaa;                  /* Next stack offset. */
258
259 #if defined (__APPLE__)
260   unsigned allocating_variadic;
261 #endif
262 };
263
264 /* Initialize a procedure call argument marshalling state.  */
265 static void
266 arg_init (struct arg_state *state)
267 {
268   state->ngrn = 0;
269   state->nsrn = 0;
270   state->nsaa = 0;
271 #if defined (__APPLE__)
272   state->allocating_variadic = 0;
273 #endif
274 }
275
276 /* Allocate an aligned slot on the stack and return a pointer to it.  */
277 static void *
278 allocate_to_stack (struct arg_state *state, void *stack,
279                    size_t alignment, size_t size)
280 {
281   size_t nsaa = state->nsaa;
282
283   /* Round up the NSAA to the larger of 8 or the natural
284      alignment of the argument's type.  */
285 #if defined (__APPLE__)
286   if (state->allocating_variadic && alignment < 8)
287     alignment = 8;
288 #else
289   if (alignment < 8)
290     alignment = 8;
291 #endif
292     
293   nsaa = FFI_ALIGN (nsaa, alignment);
294   state->nsaa = nsaa + size;
295
296   return (char *)stack + nsaa;
297 }
298
299 static ffi_arg
300 extend_integer_type (void *source, int type)
301 {
302   switch (type)
303     {
304     case FFI_TYPE_UINT8:
305       return *(UINT8 *) source;
306     case FFI_TYPE_SINT8:
307       return *(SINT8 *) source;
308     case FFI_TYPE_UINT16:
309       return *(UINT16 *) source;
310     case FFI_TYPE_SINT16:
311       return *(SINT16 *) source;
312     case FFI_TYPE_UINT32:
313       return *(UINT32 *) source;
314     case FFI_TYPE_INT:
315     case FFI_TYPE_SINT32:
316       return *(SINT32 *) source;
317     case FFI_TYPE_UINT64:
318     case FFI_TYPE_SINT64:
319       return *(UINT64 *) source;
320       break;
321     case FFI_TYPE_POINTER:
322       return *(uintptr_t *) source;
323     default:
324       abort();
325     }
326 }
327
328 #if defined(_MSC_VER)
329 void extend_hfa_type (void *dest, void *src, int h);
330 #else
331 static void
332 extend_hfa_type (void *dest, void *src, int h)
333 {
334   ssize_t f = h - AARCH64_RET_S4;
335   void *x0;
336
337   asm volatile (
338         "adr    %0, 0f\n"
339 "       add     %0, %0, %1\n"
340 "       br      %0\n"
341 "0:     ldp     s16, s17, [%3]\n"       /* S4 */
342 "       ldp     s18, s19, [%3, #8]\n"
343 "       b       4f\n"
344 "       ldp     s16, s17, [%3]\n"       /* S3 */
345 "       ldr     s18, [%3, #8]\n"
346 "       b       3f\n"
347 "       ldp     s16, s17, [%3]\n"       /* S2 */
348 "       b       2f\n"
349 "       nop\n"
350 "       ldr     s16, [%3]\n"            /* S1 */
351 "       b       1f\n"
352 "       nop\n"
353 "       ldp     d16, d17, [%3]\n"       /* D4 */
354 "       ldp     d18, d19, [%3, #16]\n"
355 "       b       4f\n"
356 "       ldp     d16, d17, [%3]\n"       /* D3 */
357 "       ldr     d18, [%3, #16]\n"
358 "       b       3f\n"
359 "       ldp     d16, d17, [%3]\n"       /* D2 */
360 "       b       2f\n"
361 "       nop\n"
362 "       ldr     d16, [%3]\n"            /* D1 */
363 "       b       1f\n"
364 "       nop\n"
365 "       ldp     q16, q17, [%3]\n"       /* Q4 */
366 "       ldp     q18, q19, [%3, #32]\n"
367 "       b       4f\n"
368 "       ldp     q16, q17, [%3]\n"       /* Q3 */
369 "       ldr     q18, [%3, #32]\n"
370 "       b       3f\n"
371 "       ldp     q16, q17, [%3]\n"       /* Q2 */
372 "       b       2f\n"
373 "       nop\n"
374 "       ldr     q16, [%3]\n"            /* Q1 */
375 "       b       1f\n"
376 "4:     str     q19, [%2, #48]\n"
377 "3:     str     q18, [%2, #32]\n"
378 "2:     str     q17, [%2, #16]\n"
379 "1:     str     q16, [%2]"
380     : "=&r"(x0)
381     : "r"(f * 12), "r"(dest), "r"(src)
382     : "memory", "v16", "v17", "v18", "v19");
383 }
384 #endif
385
386 #if defined(_MSC_VER)
387 void* compress_hfa_type (void *dest, void *src, int h);
388 #else
389 static void *
390 compress_hfa_type (void *dest, void *reg, int h)
391 {
392   switch (h)
393     {
394     case AARCH64_RET_S1:
395       if (dest == reg)
396         {
397 #ifdef __AARCH64EB__
398           dest += 12;
399 #endif
400         }
401       else
402         *(float *)dest = *(float *)reg;
403       break;
404     case AARCH64_RET_S2:
405       asm ("ldp q16, q17, [%1]\n\t"
406            "st2 { v16.s, v17.s }[0], [%0]"
407            : : "r"(dest), "r"(reg) : "memory", "v16", "v17");
408       break;
409     case AARCH64_RET_S3:
410       asm ("ldp q16, q17, [%1]\n\t"
411            "ldr q18, [%1, #32]\n\t"
412            "st3 { v16.s, v17.s, v18.s }[0], [%0]"
413            : : "r"(dest), "r"(reg) : "memory", "v16", "v17", "v18");
414       break;
415     case AARCH64_RET_S4:
416       asm ("ldp q16, q17, [%1]\n\t"
417            "ldp q18, q19, [%1, #32]\n\t"
418            "st4 { v16.s, v17.s, v18.s, v19.s }[0], [%0]"
419            : : "r"(dest), "r"(reg) : "memory", "v16", "v17", "v18", "v19");
420       break;
421
422     case AARCH64_RET_D1:
423       if (dest == reg)
424         {
425 #ifdef __AARCH64EB__
426           dest += 8;
427 #endif
428         }
429       else
430         *(double *)dest = *(double *)reg;
431       break;
432     case AARCH64_RET_D2:
433       asm ("ldp q16, q17, [%1]\n\t"
434            "st2 { v16.d, v17.d }[0], [%0]"
435            : : "r"(dest), "r"(reg) : "memory", "v16", "v17");
436       break;
437     case AARCH64_RET_D3:
438       asm ("ldp q16, q17, [%1]\n\t"
439            "ldr q18, [%1, #32]\n\t"
440            "st3 { v16.d, v17.d, v18.d }[0], [%0]"
441            : : "r"(dest), "r"(reg) : "memory", "v16", "v17", "v18");
442       break;
443     case AARCH64_RET_D4:
444       asm ("ldp q16, q17, [%1]\n\t"
445            "ldp q18, q19, [%1, #32]\n\t"
446            "st4 { v16.d, v17.d, v18.d, v19.d }[0], [%0]"
447            : : "r"(dest), "r"(reg) : "memory", "v16", "v17", "v18", "v19");
448       break;
449
450     default:
451       if (dest != reg)
452         return memcpy (dest, reg, 16 * (4 - (h & 3)));
453       break;
454     }
455   return dest;
456 }
457 #endif
458
459 /* Either allocate an appropriate register for the argument type, or if
460    none are available, allocate a stack slot and return a pointer
461    to the allocated space.  */
462
463 static void *
464 allocate_int_to_reg_or_stack (struct call_context *context,
465                               struct arg_state *state,
466                               void *stack, size_t size)
467 {
468   if (state->ngrn < N_X_ARG_REG)
469     return &context->x[state->ngrn++];
470
471   state->ngrn = N_X_ARG_REG;
472   return allocate_to_stack (state, stack, size, size);
473 }
474
475 ffi_status FFI_HIDDEN
476 ffi_prep_cif_machdep (ffi_cif *cif)
477 {
478   ffi_type *rtype = cif->rtype;
479   size_t bytes = cif->bytes;
480   int flags, i, n;
481
482   switch (rtype->type)
483     {
484     case FFI_TYPE_VOID:
485       flags = AARCH64_RET_VOID;
486       break;
487     case FFI_TYPE_UINT8:
488       flags = AARCH64_RET_UINT8;
489       break;
490     case FFI_TYPE_UINT16:
491       flags = AARCH64_RET_UINT16;
492       break;
493     case FFI_TYPE_UINT32:
494       flags = AARCH64_RET_UINT32;
495       break;
496     case FFI_TYPE_SINT8:
497       flags = AARCH64_RET_SINT8;
498       break;
499     case FFI_TYPE_SINT16:
500       flags = AARCH64_RET_SINT16;
501       break;
502     case FFI_TYPE_INT:
503     case FFI_TYPE_SINT32:
504       flags = AARCH64_RET_SINT32;
505       break;
506     case FFI_TYPE_SINT64:
507     case FFI_TYPE_UINT64:
508       flags = AARCH64_RET_INT64;
509       break;
510     case FFI_TYPE_POINTER:
511       flags = (sizeof(void *) == 4 ? AARCH64_RET_UINT32 : AARCH64_RET_INT64);
512       break;
513
514     case FFI_TYPE_FLOAT:
515     case FFI_TYPE_DOUBLE:
516     case FFI_TYPE_LONGDOUBLE:
517     case FFI_TYPE_STRUCT:
518     case FFI_TYPE_COMPLEX:
519       flags = is_vfp_type (rtype);
520       if (flags == 0)
521         {
522           size_t s = rtype->size;
523           if (s > 16)
524             {
525               flags = AARCH64_RET_VOID | AARCH64_RET_IN_MEM;
526               bytes += 8;
527             }
528           else if (s == 16)
529             flags = AARCH64_RET_INT128;
530           else if (s == 8)
531             flags = AARCH64_RET_INT64;
532           else
533             flags = AARCH64_RET_INT128 | AARCH64_RET_NEED_COPY;
534         }
535       break;
536
537     default:
538       abort();
539     }
540
541   for (i = 0, n = cif->nargs; i < n; i++)
542     if (is_vfp_type (cif->arg_types[i]))
543       {
544         flags |= AARCH64_FLAG_ARG_V;
545         break;
546       }
547
548   /* Round the stack up to a multiple of the stack alignment requirement. */
549   cif->bytes = (unsigned) FFI_ALIGN(bytes, 16);
550   cif->flags = flags;
551 #if defined (__APPLE__)
552   cif->aarch64_nfixedargs = 0;
553 #endif
554
555   return FFI_OK;
556 }
557
558 #if defined (__APPLE__)
559 /* Perform Apple-specific cif processing for variadic calls */
560 ffi_status FFI_HIDDEN
561 ffi_prep_cif_machdep_var(ffi_cif *cif, unsigned int nfixedargs,
562                          unsigned int ntotalargs)
563 {
564   ffi_status status = ffi_prep_cif_machdep (cif);
565   cif->aarch64_nfixedargs = nfixedargs;
566   return status;
567 }
568 #else
569 ffi_status FFI_HIDDEN
570 ffi_prep_cif_machdep_var(ffi_cif *cif, unsigned int nfixedargs, unsigned int ntotalargs)
571 {
572   ffi_status status = ffi_prep_cif_machdep (cif);
573   cif->flags |= AARCH64_FLAG_VARARG;
574   return status;
575 }
576 #endif /* __APPLE__ */
577
578 extern void ffi_call_SYSV (struct call_context *context, void *frame,
579                            void (*fn)(void), void *rvalue, int flags,
580                            void *closure) FFI_HIDDEN;
581
582 /* Call a function with the provided arguments and capture the return
583    value.  */
584 static void
585 ffi_call_int (ffi_cif *cif, void (*fn)(void), void *orig_rvalue,
586               void **avalue, void *closure)
587 {
588   struct call_context *context;
589   void *stack, *frame, *rvalue;
590   struct arg_state state;
591   size_t stack_bytes, rtype_size, rsize;
592   int i, nargs, flags, isvariadic = 0;
593   ffi_type *rtype;
594
595   flags = cif->flags;
596   rtype = cif->rtype;
597   rtype_size = rtype->size;
598   stack_bytes = cif->bytes;
599
600   if (flags & AARCH64_FLAG_VARARG)
601   {
602     isvariadic = 1;
603     flags &= ~AARCH64_FLAG_VARARG;
604   }
605
606   /* If the target function returns a structure via hidden pointer,
607      then we cannot allow a null rvalue.  Otherwise, mash a null
608      rvalue to void return type.  */
609   rsize = 0;
610   if (flags & AARCH64_RET_IN_MEM)
611     {
612       if (orig_rvalue == NULL)
613         rsize = rtype_size;
614     }
615   else if (orig_rvalue == NULL)
616     flags &= AARCH64_FLAG_ARG_V;
617   else if (flags & AARCH64_RET_NEED_COPY)
618     rsize = 16;
619
620   /* Allocate consectutive stack for everything we'll need.  */
621   context = alloca (sizeof(struct call_context) + stack_bytes + 32 + rsize);
622   stack = context + 1;
623   frame = (void*)((uintptr_t)stack + (uintptr_t)stack_bytes);
624   rvalue = (rsize ? (void*)((uintptr_t)frame + 32) : orig_rvalue);
625
626   arg_init (&state);
627   for (i = 0, nargs = cif->nargs; i < nargs; i++)
628     {
629       ffi_type *ty = cif->arg_types[i];
630       size_t s = ty->size;
631       void *a = avalue[i];
632       int h, t;
633
634       t = ty->type;
635       switch (t)
636         {
637         case FFI_TYPE_VOID:
638           FFI_ASSERT (0);
639           break;
640
641         /* If the argument is a basic type the argument is allocated to an
642            appropriate register, or if none are available, to the stack.  */
643         case FFI_TYPE_INT:
644         case FFI_TYPE_UINT8:
645         case FFI_TYPE_SINT8:
646         case FFI_TYPE_UINT16:
647         case FFI_TYPE_SINT16:
648         case FFI_TYPE_UINT32:
649         case FFI_TYPE_SINT32:
650         case FFI_TYPE_UINT64:
651         case FFI_TYPE_SINT64:
652         case FFI_TYPE_POINTER:
653         do_pointer:
654           {
655             ffi_arg ext = extend_integer_type (a, t);
656             if (state.ngrn < N_X_ARG_REG)
657               context->x[state.ngrn++] = ext;
658             else
659               {
660                 void *d = allocate_to_stack (&state, stack, ty->alignment, s);
661                 state.ngrn = N_X_ARG_REG;
662                 /* Note that the default abi extends each argument
663                    to a full 64-bit slot, while the iOS abi allocates
664                    only enough space. */
665 #ifdef __APPLE__
666                 memcpy(d, a, s);
667 #else
668                 *(ffi_arg *)d = ext;
669 #endif
670               }
671           }
672           break;
673
674         case FFI_TYPE_FLOAT:
675         case FFI_TYPE_DOUBLE:
676         case FFI_TYPE_LONGDOUBLE:
677         case FFI_TYPE_STRUCT:
678         case FFI_TYPE_COMPLEX:
679           {
680             void *dest;
681
682             h = is_vfp_type (ty);
683             if (h)
684               {
685               int elems = 4 - (h & 3);
686               if (cif->abi == FFI_WIN64 && isvariadic)
687               {
688                 if (state.ngrn + elems <= N_X_ARG_REG)
689                 {
690                   dest = &context->x[state.ngrn];
691                   state.ngrn += elems;
692                   extend_hfa_type(dest, a, h);
693                   break;
694                 }
695                 state.nsrn = N_X_ARG_REG;
696                 dest = allocate_to_stack(&state, stack, ty->alignment, s);
697               }
698               else
699               {
700                 if (state.nsrn + elems <= N_V_ARG_REG)
701                 {
702                   dest = &context->v[state.nsrn];
703                   state.nsrn += elems;
704                   extend_hfa_type (dest, a, h);
705                   break;
706                 }
707                 state.nsrn = N_V_ARG_REG;
708                 dest = allocate_to_stack (&state, stack, ty->alignment, s);
709               }
710               }
711             else if (s > 16)
712               {
713                 /* If the argument is a composite type that is larger than 16
714                    bytes, then the argument has been copied to memory, and
715                    the argument is replaced by a pointer to the copy.  */
716                 a = &avalue[i];
717                 t = FFI_TYPE_POINTER;
718                 s = sizeof (void *);
719                 goto do_pointer;
720               }
721             else
722               {
723                 size_t n = (s + 7) / 8;
724                 if (state.ngrn + n <= N_X_ARG_REG)
725                   {
726                     /* If the argument is a composite type and the size in
727                        double-words is not more than the number of available
728                        X registers, then the argument is copied into
729                        consecutive X registers.  */
730                     dest = &context->x[state.ngrn];
731                     state.ngrn += (unsigned int)n;
732                   }
733                 else
734                   {
735                     /* Otherwise, there are insufficient X registers. Further
736                        X register allocations are prevented, the NSAA is
737                        adjusted and the argument is copied to memory at the
738                        adjusted NSAA.  */
739                     state.ngrn = N_X_ARG_REG;
740                     dest = allocate_to_stack (&state, stack, ty->alignment, s);
741                   }
742                 }
743               memcpy (dest, a, s);
744             }
745           break;
746
747         default:
748           abort();
749         }
750
751 #if defined (__APPLE__)
752       if (i + 1 == cif->aarch64_nfixedargs)
753         {
754           state.ngrn = N_X_ARG_REG;
755           state.nsrn = N_V_ARG_REG;
756           state.allocating_variadic = 1;
757         }
758 #endif
759     }
760
761   ffi_call_SYSV (context, frame, fn, rvalue, flags, closure);
762
763   if (flags & AARCH64_RET_NEED_COPY)
764     memcpy (orig_rvalue, rvalue, rtype_size);
765 }
766
767 void
768 ffi_call (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue)
769 {
770   ffi_call_int (cif, fn, rvalue, avalue, NULL);
771 }
772
773 #ifdef FFI_GO_CLOSURES
774 void
775 ffi_call_go (ffi_cif *cif, void (*fn) (void), void *rvalue,
776              void **avalue, void *closure)
777 {
778   ffi_call_int (cif, fn, rvalue, avalue, closure);
779 }
780 #endif /* FFI_GO_CLOSURES */
781
782 /* Build a trampoline.  */
783
784 extern void ffi_closure_SYSV (void) FFI_HIDDEN;
785 extern void ffi_closure_SYSV_V (void) FFI_HIDDEN;
786 #if defined(FFI_EXEC_STATIC_TRAMP)
787 extern void ffi_closure_SYSV_alt (void) FFI_HIDDEN;
788 extern void ffi_closure_SYSV_V_alt (void) FFI_HIDDEN;
789 #endif
790
791 ffi_status
792 ffi_prep_closure_loc (ffi_closure *closure,
793                       ffi_cif* cif,
794                       void (*fun)(ffi_cif*,void*,void**,void*),
795                       void *user_data,
796                       void *codeloc)
797 {
798   if (cif->abi != FFI_SYSV)
799     return FFI_BAD_ABI;
800
801   void (*start)(void);
802   
803   if (cif->flags & AARCH64_FLAG_ARG_V)
804     start = ffi_closure_SYSV_V;
805   else
806     start = ffi_closure_SYSV;
807
808 #if FFI_EXEC_TRAMPOLINE_TABLE
809 #ifdef __MACH__
810 #ifdef HAVE_PTRAUTH
811   codeloc = ptrauth_strip (codeloc, ptrauth_key_asia);
812 #endif
813   void **config = (void **)((uint8_t *)codeloc - PAGE_MAX_SIZE);
814   config[0] = closure;
815   config[1] = start;
816 #endif
817 #else
818   static const unsigned char trampoline[16] = {
819     0x90, 0x00, 0x00, 0x58,     /* ldr  x16, tramp+16   */
820     0xf1, 0xff, 0xff, 0x10,     /* adr  x17, tramp+0    */
821     0x00, 0x02, 0x1f, 0xd6      /* br   x16             */
822   };
823   char *tramp = closure->tramp;
824
825 #if defined(FFI_EXEC_STATIC_TRAMP)
826   if (ffi_tramp_is_present(closure))
827     {
828       /* Initialize the static trampoline's parameters. */
829       if (start == ffi_closure_SYSV_V)
830           start = ffi_closure_SYSV_V_alt;
831       else
832           start = ffi_closure_SYSV_alt;
833       ffi_tramp_set_parms (closure->ftramp, start, closure);
834       goto out;
835     }
836 #endif
837
838   /* Initialize the dynamic trampoline. */
839   memcpy (tramp, trampoline, sizeof(trampoline));
840   
841   *(UINT64 *)(tramp + 16) = (uintptr_t)start;
842
843   ffi_clear_cache(tramp, tramp + FFI_TRAMPOLINE_SIZE);
844
845   /* Also flush the cache for code mapping.  */
846 #ifdef _WIN32
847   // Not using dlmalloc.c for Windows ARM64 builds
848   // so calling ffi_data_to_code_pointer() isn't necessary
849   unsigned char *tramp_code = tramp;
850   #else
851   unsigned char *tramp_code = ffi_data_to_code_pointer (tramp);
852   #endif
853   ffi_clear_cache (tramp_code, tramp_code + FFI_TRAMPOLINE_SIZE);
854 out:
855 #endif
856
857   closure->cif = cif;
858   closure->fun = fun;
859   closure->user_data = user_data;
860
861   return FFI_OK;
862 }
863
864 #ifdef FFI_GO_CLOSURES
865 extern void ffi_go_closure_SYSV (void) FFI_HIDDEN;
866 extern void ffi_go_closure_SYSV_V (void) FFI_HIDDEN;
867
868 ffi_status
869 ffi_prep_go_closure (ffi_go_closure *closure, ffi_cif* cif,
870                      void (*fun)(ffi_cif*,void*,void**,void*))
871 {
872   void (*start)(void);
873
874   if (cif->abi != FFI_SYSV)
875     return FFI_BAD_ABI;
876
877   if (cif->flags & AARCH64_FLAG_ARG_V)
878     start = ffi_go_closure_SYSV_V;
879   else
880     start = ffi_go_closure_SYSV;
881
882   closure->tramp = start;
883   closure->cif = cif;
884   closure->fun = fun;
885
886   return FFI_OK;
887 }
888 #endif /* FFI_GO_CLOSURES */
889
890 /* Primary handler to setup and invoke a function within a closure.
891
892    A closure when invoked enters via the assembler wrapper
893    ffi_closure_SYSV(). The wrapper allocates a call context on the
894    stack, saves the interesting registers (from the perspective of
895    the calling convention) into the context then passes control to
896    ffi_closure_SYSV_inner() passing the saved context and a pointer to
897    the stack at the point ffi_closure_SYSV() was invoked.
898
899    On the return path the assembler wrapper will reload call context
900    registers.
901
902    ffi_closure_SYSV_inner() marshalls the call context into ffi value
903    descriptors, invokes the wrapped function, then marshalls the return
904    value back into the call context.  */
905
906 int FFI_HIDDEN
907 ffi_closure_SYSV_inner (ffi_cif *cif,
908                         void (*fun)(ffi_cif*,void*,void**,void*),
909                         void *user_data,
910                         struct call_context *context,
911                         void *stack, void *rvalue, void *struct_rvalue)
912 {
913   void **avalue = (void**) alloca (cif->nargs * sizeof (void*));
914   int i, h, nargs, flags;
915   struct arg_state state;
916
917   arg_init (&state);
918
919   for (i = 0, nargs = cif->nargs; i < nargs; i++)
920     {
921       ffi_type *ty = cif->arg_types[i];
922       int t = ty->type;
923       size_t n, s = ty->size;
924
925       switch (t)
926         {
927         case FFI_TYPE_VOID:
928           FFI_ASSERT (0);
929           break;
930
931         case FFI_TYPE_INT:
932         case FFI_TYPE_UINT8:
933         case FFI_TYPE_SINT8:
934         case FFI_TYPE_UINT16:
935         case FFI_TYPE_SINT16:
936         case FFI_TYPE_UINT32:
937         case FFI_TYPE_SINT32:
938         case FFI_TYPE_UINT64:
939         case FFI_TYPE_SINT64:
940         case FFI_TYPE_POINTER:
941           avalue[i] = allocate_int_to_reg_or_stack (context, &state, stack, s);
942           break;
943
944         case FFI_TYPE_FLOAT:
945         case FFI_TYPE_DOUBLE:
946         case FFI_TYPE_LONGDOUBLE:
947         case FFI_TYPE_STRUCT:
948         case FFI_TYPE_COMPLEX:
949           h = is_vfp_type (ty);
950           if (h)
951             {
952               n = 4 - (h & 3);
953 #ifdef _WIN32  /* for handling armasm calling convention */
954               if (cif->is_variadic)
955                 {
956                   if (state.ngrn + n <= N_X_ARG_REG)
957                     {
958                       void *reg = &context->x[state.ngrn];
959                       state.ngrn += (unsigned int)n;
960     
961                       /* Eeek! We need a pointer to the structure, however the
962                        homogeneous float elements are being passed in individual
963                        registers, therefore for float and double the structure
964                        is not represented as a contiguous sequence of bytes in
965                        our saved register context.  We don't need the original
966                        contents of the register storage, so we reformat the
967                        structure into the same memory.  */
968                       avalue[i] = compress_hfa_type(reg, reg, h);
969                     }
970                   else
971                     {
972                       state.ngrn = N_X_ARG_REG;
973                       state.nsrn = N_V_ARG_REG;
974                       avalue[i] = allocate_to_stack(&state, stack,
975                              ty->alignment, s);
976                     }
977                 }
978               else
979                 {
980 #endif  /* for handling armasm calling convention */
981                   if (state.nsrn + n <= N_V_ARG_REG)
982                     {
983                       void *reg = &context->v[state.nsrn];
984                       state.nsrn += (unsigned int)n;
985                       avalue[i] = compress_hfa_type(reg, reg, h);
986                     }
987                   else
988                     {
989                       state.nsrn = N_V_ARG_REG;
990                       avalue[i] = allocate_to_stack(&state, stack,
991                                                    ty->alignment, s);
992                     }
993 #ifdef _WIN32  /* for handling armasm calling convention */
994                 }
995 #endif  /* for handling armasm calling convention */
996             }
997           else if (s > 16)
998             {
999               /* Replace Composite type of size greater than 16 with a
1000                   pointer.  */
1001               avalue[i] = *(void **)
1002               allocate_int_to_reg_or_stack (context, &state, stack,
1003                                          sizeof (void *));
1004             }
1005           else
1006             {
1007               n = (s + 7) / 8;
1008               if (state.ngrn + n <= N_X_ARG_REG)
1009                 {
1010                   avalue[i] = &context->x[state.ngrn];
1011                   state.ngrn += (unsigned int)n;
1012                 }
1013               else
1014                 {
1015                   state.ngrn = N_X_ARG_REG;
1016                   avalue[i] = allocate_to_stack(&state, stack,
1017                                            ty->alignment, s);
1018                 }
1019             }
1020           break;
1021
1022         default:
1023           abort();
1024       }
1025
1026 #if defined (__APPLE__)
1027       if (i + 1 == cif->aarch64_nfixedargs)
1028         {
1029           state.ngrn = N_X_ARG_REG;
1030           state.nsrn = N_V_ARG_REG;
1031           state.allocating_variadic = 1;
1032         }
1033 #endif
1034     }
1035
1036   flags = cif->flags;
1037   if (flags & AARCH64_RET_IN_MEM)
1038     rvalue = struct_rvalue;
1039
1040   fun (cif, rvalue, avalue, user_data);
1041
1042   return flags;
1043 }
1044
1045 #if defined(FFI_EXEC_STATIC_TRAMP)
1046 void *
1047 ffi_tramp_arch (size_t *tramp_size, size_t *map_size)
1048 {
1049   extern void *trampoline_code_table;
1050
1051   *tramp_size = AARCH64_TRAMP_SIZE;
1052   *map_size = AARCH64_TRAMP_MAP_SIZE;
1053   return &trampoline_code_table;
1054 }
1055 #endif
1056
1057 #endif /* (__aarch64__) || defined(__arm64__)|| defined (_M_ARM64)*/