summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--meta/recipes-gnome/libffi/libffi/aarch64-adding-build-support.patch63
-rw-r--r--meta/recipes-gnome/libffi/libffi/add-aarch64-support.patch2672
-rw-r--r--meta/recipes-gnome/libffi/libffi_3.0.11.bb7
3 files changed, 2740 insertions, 2 deletions
diff --git a/meta/recipes-gnome/libffi/libffi/aarch64-adding-build-support.patch b/meta/recipes-gnome/libffi/libffi/aarch64-adding-build-support.patch
new file mode 100644
index 0000000000..b0c0f063dd
--- /dev/null
+++ b/meta/recipes-gnome/libffi/libffi/aarch64-adding-build-support.patch
@@ -0,0 +1,63 @@
1Upstream-Status: merged
2
3From 92f009a706c643d49e8d6e5ae6c9fb94ae5b2e9b Mon Sep 17 00:00:00 2001
4From: Ricardo Salveti de Araujo <ricardo.salveti@linaro.org>
5Date: Sat, 29 Sep 2012 01:07:56 -0300
6Subject: [PATCH] aarch64: adding build support
7
8Signed-off-by: Ricardo Salveti de Araujo <ricardo.salveti@linaro.org>
9---
10 Makefile.am | 6 +++++-
11 configure.ac | 5 +++++
12 2 files changed, 10 insertions(+), 1 deletion(-)
13
14diff --git a/Makefile.am b/Makefile.am
15index 16f32a6..e11050d 100644
16--- a/Makefile.am
17+++ b/Makefile.am
18@@ -36,7 +36,8 @@ EXTRA_DIST = LICENSE ChangeLog.v1 ChangeLog.libgcj configure.host \
19 msvcc.sh generate-ios-source-and-headers.py \
20 generate-osx-source-and-headers.py \
21 libffi.xcodeproj/project.pbxproj \
22- src/arm/trampoline.S
23+ src/arm/trampoline.S src/aarch64/ffi.c \
24+ src/aarch64/ffitarget.h src/aarch64/sysv.S
25
26 info_TEXINFOS = doc/libffi.texi
27
28@@ -157,6 +158,9 @@ if FFI_EXEC_TRAMPOLINE_TABLE
29 nodist_libffi_la_SOURCES += src/arm/trampoline.S
30 endif
31 endif
32+if AARCH64
33+nodist_libffi_la_SOURCES += src/aarch64/sysv.S src/aarch64/ffi.c
34+endif
35 if AVR32
36 nodist_libffi_la_SOURCES += src/avr32/sysv.S src/avr32/ffi.c
37 endif
38diff --git a/configure.ac b/configure.ac
39index 9b946a2..9205391 100644
40--- a/configure.ac
41+++ b/configure.ac
42@@ -63,6 +63,10 @@ case "$host" in
43 TARGET=ARM; TARGETDIR=arm
44 ;;
45
46+ aarch64*-*-*)
47+ TARGET=AARCH64; TARGETDIR=aarch64
48+ ;;
49+
50 amd64-*-freebsd* | amd64-*-openbsd*)
51 TARGET=X86_64; TARGETDIR=x86
52 ;;
53@@ -234,6 +238,7 @@ AM_CONDITIONAL(POWERPC_AIX, test x$TARGET = xPOWERPC_AIX)
54 AM_CONDITIONAL(POWERPC_DARWIN, test x$TARGET = xPOWERPC_DARWIN)
55 AM_CONDITIONAL(POWERPC_FREEBSD, test x$TARGET = xPOWERPC_FREEBSD)
56 AM_CONDITIONAL(ARM, test x$TARGET = xARM)
57+AM_CONDITIONAL(AARCH64, test x$TARGET = xAARCH64)
58 AM_CONDITIONAL(AVR32, test x$TARGET = xAVR32)
59 AM_CONDITIONAL(LIBFFI_CRIS, test x$TARGET = xLIBFFI_CRIS)
60 AM_CONDITIONAL(FRV, test x$TARGET = xFRV)
61--
621.7.10.4
63
diff --git a/meta/recipes-gnome/libffi/libffi/add-aarch64-support.patch b/meta/recipes-gnome/libffi/libffi/add-aarch64-support.patch
new file mode 100644
index 0000000000..d08a5b49b2
--- /dev/null
+++ b/meta/recipes-gnome/libffi/libffi/add-aarch64-support.patch
@@ -0,0 +1,2672 @@
1Upstream-Status: merged
2
3From 6fb142b06652d3a4f295778b14adadbc9d93fbe7 Mon Sep 17 00:00:00 2001
4From: Marcus Shawcroft <marcus. shawcroft@arm.dot.com>
5Date: Fri, 28 Sep 2012 17:28:48 +0100
6Subject: [PATCH] New port for ARM AArch64
7
8ARM would like to contribute a libffi port for the ARM AArch64
9architecture. The port passes the test suite cleanly. The proposed
10ChangeLog and patches are included below.
11
12/Marcus
13
142012-09-18 James Greenhalgh <james.greenhalgh at arm.com>
15 Marcus Shawcroft <marcus.shawcroft at arm.com>
16
17 * README: Add details of aarch64 port.
18 * src/aarch64/ffi.c: New.
19 * src/aarch64/ffitarget.h: Likewise.
20 * src/aarch64/sysv.S: Likewise.
21
222012-09-18 James Greenhalgh <james.greenhalgh at arm.com>
23 Marcus Shawcroft <marcus.shawcroft at arm.com>
24
25 * testsuite/lib/libffi.exp: Add support for aarch64.
26 * testsuite/libffi.call/cls_struct_va1.c: New.
27 * testsuite/libffi.call/cls_uchar_va.c: Likewise.
28 * testsuite/libffi.call/cls_uint_va.c: Likewise.
29 * testsuite/libffi.call/cls_ulong_va.c: Liekwise.
30 * testsuite/libffi.call/cls_ushort_va.c: Likewise.
31 * testsuite/libffi.call/nested_struct11.c: Likewise.
32 * testsuite/libffi.call/uninitialized.c: Likewise.
33 * testsuite/libffi.call/va_1.c: Likewise.
34 * testsuite/libffi.call/va_struct1.c: Likewise.
35 * testsuite/libffi.call/va_struct2.c: Likewise.
36 * testsuite/libffi.call/va_struct3.c: Likewise.
37---
38 README | 2 +
39 src/aarch64/ffi.c | 1076 +++++++++++++++++++++++++++++++
40 src/aarch64/ffitarget.h | 59 ++
41 src/aarch64/sysv.S | 307 +++++++++
42 testsuite/lib/libffi.exp | 4 +
43 testsuite/libffi.call/cls_struct_va1.c | 114 ++++
44 testsuite/libffi.call/cls_uchar_va.c | 44 ++
45 testsuite/libffi.call/cls_uint_va.c | 45 ++
46 testsuite/libffi.call/cls_ulong_va.c | 45 ++
47 testsuite/libffi.call/cls_ushort_va.c | 44 ++
48 testsuite/libffi.call/nested_struct11.c | 121 ++++
49 testsuite/libffi.call/uninitialized.c | 61 ++
50 testsuite/libffi.call/va_1.c | 196 ++++++
51 testsuite/libffi.call/va_struct1.c | 121 ++++
52 testsuite/libffi.call/va_struct2.c | 123 ++++
53 testsuite/libffi.call/va_struct3.c | 125 ++++
54 16 files changed, 2487 insertions(+)
55 create mode 100644 src/aarch64/ffi.c
56 create mode 100644 src/aarch64/ffitarget.h
57 create mode 100644 src/aarch64/sysv.S
58 create mode 100644 testsuite/libffi.call/cls_struct_va1.c
59 create mode 100644 testsuite/libffi.call/cls_uchar_va.c
60 create mode 100644 testsuite/libffi.call/cls_uint_va.c
61 create mode 100644 testsuite/libffi.call/cls_ulong_va.c
62 create mode 100644 testsuite/libffi.call/cls_ushort_va.c
63 create mode 100644 testsuite/libffi.call/nested_struct11.c
64 create mode 100644 testsuite/libffi.call/uninitialized.c
65 create mode 100644 testsuite/libffi.call/va_1.c
66 create mode 100644 testsuite/libffi.call/va_struct1.c
67 create mode 100644 testsuite/libffi.call/va_struct2.c
68 create mode 100644 testsuite/libffi.call/va_struct3.c
69
70diff --git a/README b/README
71index 0cf0720..8fc473f 100644
72--- a/README
73+++ b/README
74@@ -51,6 +51,7 @@ tested:
75 |--------------+------------------|
76 | Architecture | Operating System |
77 |--------------+------------------|
78+| AArch64 | Linux |
79 | Alpha | Linux |
80 | Alpha | Tru64 |
81 | ARM | Linux |
82@@ -319,6 +320,7 @@ Thorup.
83 Major processor architecture ports were contributed by the following
84 developers:
85
86+aarch64 Marcus Shawcroft, James Greenhalgh
87 alpha Richard Henderson
88 arm Raffaele Sena
89 cris Simon Posnjak, Hans-Peter Nilsson
90diff --git a/src/aarch64/ffi.c b/src/aarch64/ffi.c
91new file mode 100644
92index 0000000..1405665
93--- /dev/null
94+++ b/src/aarch64/ffi.c
95@@ -0,0 +1,1076 @@
96+/* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd.
97+
98+Permission is hereby granted, free of charge, to any person obtaining
99+a copy of this software and associated documentation files (the
100+``Software''), to deal in the Software without restriction, including
101+without limitation the rights to use, copy, modify, merge, publish,
102+distribute, sublicense, and/or sell copies of the Software, and to
103+permit persons to whom the Software is furnished to do so, subject to
104+the following conditions:
105+
106+The above copyright notice and this permission notice shall be
107+included in all copies or substantial portions of the Software.
108+
109+THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
110+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
111+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
112+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
113+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
114+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
115+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
116+
117+#include <stdio.h>
118+
119+#include <ffi.h>
120+#include <ffi_common.h>
121+
122+#include <stdlib.h>
123+
124+/* Stack alignment requirement in bytes */
125+#define AARCH64_STACK_ALIGN 16
126+
127+#define N_X_ARG_REG 8
128+#define N_V_ARG_REG 8
129+
130+#define AARCH64_FFI_WITH_V (1 << AARCH64_FFI_WITH_V_BIT)
131+
132+union _d
133+{
134+ UINT64 d;
135+ UINT32 s[2];
136+};
137+
138+struct call_context
139+{
140+ UINT64 x [AARCH64_N_XREG];
141+ struct
142+ {
143+ union _d d[2];
144+ } v [AARCH64_N_VREG];
145+};
146+
147+static void *
148+get_x_addr (struct call_context *context, unsigned n)
149+{
150+ return &context->x[n];
151+}
152+
153+static void *
154+get_s_addr (struct call_context *context, unsigned n)
155+{
156+#if defined __AARCH64EB__
157+ return &context->v[n].d[1].s[1];
158+#else
159+ return &context->v[n].d[0].s[0];
160+#endif
161+}
162+
163+static void *
164+get_d_addr (struct call_context *context, unsigned n)
165+{
166+#if defined __AARCH64EB__
167+ return &context->v[n].d[1];
168+#else
169+ return &context->v[n].d[0];
170+#endif
171+}
172+
173+static void *
174+get_v_addr (struct call_context *context, unsigned n)
175+{
176+ return &context->v[n];
177+}
178+
179+/* Return the memory location at which a basic type would reside
180+ were it to have been stored in register n. */
181+
182+static void *
183+get_basic_type_addr (unsigned short type, struct call_context *context,
184+ unsigned n)
185+{
186+ switch (type)
187+ {
188+ case FFI_TYPE_FLOAT:
189+ return get_s_addr (context, n);
190+ case FFI_TYPE_DOUBLE:
191+ return get_d_addr (context, n);
192+ case FFI_TYPE_LONGDOUBLE:
193+ return get_v_addr (context, n);
194+ case FFI_TYPE_UINT8:
195+ case FFI_TYPE_SINT8:
196+ case FFI_TYPE_UINT16:
197+ case FFI_TYPE_SINT16:
198+ case FFI_TYPE_UINT32:
199+ case FFI_TYPE_SINT32:
200+ case FFI_TYPE_INT:
201+ case FFI_TYPE_POINTER:
202+ case FFI_TYPE_UINT64:
203+ case FFI_TYPE_SINT64:
204+ return get_x_addr (context, n);
205+ default:
206+ FFI_ASSERT (0);
207+ return NULL;
208+ }
209+}
210+
211+/* Return the alignment width for each of the basic types. */
212+
213+static size_t
214+get_basic_type_alignment (unsigned short type)
215+{
216+ switch (type)
217+ {
218+ case FFI_TYPE_FLOAT:
219+ case FFI_TYPE_DOUBLE:
220+ return sizeof (UINT64);
221+ case FFI_TYPE_LONGDOUBLE:
222+ return sizeof (long double);
223+ case FFI_TYPE_UINT8:
224+ case FFI_TYPE_SINT8:
225+ case FFI_TYPE_UINT16:
226+ case FFI_TYPE_SINT16:
227+ case FFI_TYPE_UINT32:
228+ case FFI_TYPE_INT:
229+ case FFI_TYPE_SINT32:
230+ case FFI_TYPE_POINTER:
231+ case FFI_TYPE_UINT64:
232+ case FFI_TYPE_SINT64:
233+ return sizeof (UINT64);
234+
235+ default:
236+ FFI_ASSERT (0);
237+ return 0;
238+ }
239+}
240+
241+/* Return the size in bytes for each of the basic types. */
242+
243+static size_t
244+get_basic_type_size (unsigned short type)
245+{
246+ switch (type)
247+ {
248+ case FFI_TYPE_FLOAT:
249+ return sizeof (UINT32);
250+ case FFI_TYPE_DOUBLE:
251+ return sizeof (UINT64);
252+ case FFI_TYPE_LONGDOUBLE:
253+ return sizeof (long double);
254+ case FFI_TYPE_UINT8:
255+ return sizeof (UINT8);
256+ case FFI_TYPE_SINT8:
257+ return sizeof (SINT8);
258+ case FFI_TYPE_UINT16:
259+ return sizeof (UINT16);
260+ case FFI_TYPE_SINT16:
261+ return sizeof (SINT16);
262+ case FFI_TYPE_UINT32:
263+ return sizeof (UINT32);
264+ case FFI_TYPE_INT:
265+ case FFI_TYPE_SINT32:
266+ return sizeof (SINT32);
267+ case FFI_TYPE_POINTER:
268+ case FFI_TYPE_UINT64:
269+ return sizeof (UINT64);
270+ case FFI_TYPE_SINT64:
271+ return sizeof (SINT64);
272+
273+ default:
274+ FFI_ASSERT (0);
275+ return 0;
276+ }
277+}
278+
279+extern void
280+ffi_call_SYSV (unsigned (*)(struct call_context *context, unsigned char *,
281+ extended_cif *),
282+ struct call_context *context,
283+ extended_cif *,
284+ unsigned,
285+ void (*fn)(void));
286+
287+extern void
288+ffi_closure_SYSV (ffi_closure *);
289+
290+/* Test for an FFI floating point representation. */
291+
292+static unsigned
293+is_floating_type (unsigned short type)
294+{
295+ return (type == FFI_TYPE_FLOAT || type == FFI_TYPE_DOUBLE
296+ || type == FFI_TYPE_LONGDOUBLE);
297+}
298+
299+/* Test for a homogeneous structure. */
300+
301+static unsigned short
302+get_homogeneous_type (ffi_type *ty)
303+{
304+ if (ty->type == FFI_TYPE_STRUCT && ty->elements)
305+ {
306+ unsigned i;
307+ unsigned short candidate_type
308+ = get_homogeneous_type (ty->elements[0]);
309+ for (i =1; ty->elements[i]; i++)
310+ {
311+ unsigned short iteration_type = 0;
312+ /* If we have a nested struct, we must find its homogeneous type.
313+ If that fits with our candidate type, we are still
314+ homogeneous. */
315+ if (ty->elements[i]->type == FFI_TYPE_STRUCT
316+ && ty->elements[i]->elements)
317+ {
318+ iteration_type = get_homogeneous_type (ty->elements[i]);
319+ }
320+ else
321+ {
322+ iteration_type = ty->elements[i]->type;
323+ }
324+
325+ /* If we are not homogeneous, return FFI_TYPE_STRUCT. */
326+ if (candidate_type != iteration_type)
327+ return FFI_TYPE_STRUCT;
328+ }
329+ return candidate_type;
330+ }
331+
332+ /* Base case, we have no more levels of nesting, so we
333+ are a basic type, and so, trivially homogeneous in that type. */
334+ return ty->type;
335+}
336+
337+/* Determine the number of elements within a STRUCT.
338+
339+ Note, we must handle nested structs.
340+
341+ If ty is not a STRUCT this function will return 0. */
342+
343+static unsigned
344+element_count (ffi_type *ty)
345+{
346+ if (ty->type == FFI_TYPE_STRUCT && ty->elements)
347+ {
348+ unsigned n;
349+ unsigned elems = 0;
350+ for (n = 0; ty->elements[n]; n++)
351+ {
352+ if (ty->elements[n]->type == FFI_TYPE_STRUCT
353+ && ty->elements[n]->elements)
354+ elems += element_count (ty->elements[n]);
355+ else
356+ elems++;
357+ }
358+ return elems;
359+ }
360+ return 0;
361+}
362+
363+/* Test for a homogeneous floating point aggregate.
364+
365+ A homogeneous floating point aggregate is a homogeneous aggregate of
366+ a half- single- or double- precision floating point type with one
367+ to four elements. Note that this includes nested structs of the
368+ basic type. */
369+
370+static int
371+is_hfa (ffi_type *ty)
372+{
373+ if (ty->type == FFI_TYPE_STRUCT
374+ && ty->elements[0]
375+ && is_floating_type (get_homogeneous_type (ty)))
376+ {
377+ unsigned n = element_count (ty);
378+ return n >= 1 && n <= 4;
379+ }
380+ return 0;
381+}
382+
383+/* Test if an ffi_type is a candidate for passing in a register.
384+
385+ This test does not check that sufficient registers of the
386+ appropriate class are actually available, merely that IFF
387+ sufficient registers are available then the argument will be passed
388+ in register(s).
389+
390+ Note that an ffi_type that is deemed to be a register candidate
391+ will always be returned in registers.
392+
393+ Returns 1 if a register candidate else 0. */
394+
395+static int
396+is_register_candidate (ffi_type *ty)
397+{
398+ switch (ty->type)
399+ {
400+ case FFI_TYPE_VOID:
401+ case FFI_TYPE_FLOAT:
402+ case FFI_TYPE_DOUBLE:
403+ case FFI_TYPE_LONGDOUBLE:
404+ case FFI_TYPE_UINT8:
405+ case FFI_TYPE_UINT16:
406+ case FFI_TYPE_UINT32:
407+ case FFI_TYPE_UINT64:
408+ case FFI_TYPE_POINTER:
409+ case FFI_TYPE_SINT8:
410+ case FFI_TYPE_SINT16:
411+ case FFI_TYPE_SINT32:
412+ case FFI_TYPE_INT:
413+ case FFI_TYPE_SINT64:
414+ return 1;
415+
416+ case FFI_TYPE_STRUCT:
417+ if (is_hfa (ty))
418+ {
419+ return 1;
420+ }
421+ else if (ty->size > 16)
422+ {
423+ /* Too large. Will be replaced with a pointer to memory. The
424+ pointer MAY be passed in a register, but the value will
425+ not. This test specifically fails since the argument will
426+ never be passed by value in registers. */
427+ return 0;
428+ }
429+ else
430+ {
431+ /* Might be passed in registers depending on the number of
432+ registers required. */
433+ return (ty->size + 7) / 8 < N_X_ARG_REG;
434+ }
435+ break;
436+
437+ default:
438+ FFI_ASSERT (0);
439+ break;
440+ }
441+
442+ return 0;
443+}
444+
445+/* Test if an ffi_type argument or result is a candidate for a vector
446+ register. */
447+
448+static int
449+is_v_register_candidate (ffi_type *ty)
450+{
451+ return is_floating_type (ty->type)
452+ || (ty->type == FFI_TYPE_STRUCT && is_hfa (ty));
453+}
454+
455+/* Representation of the procedure call argument marshalling
456+ state.
457+
458+ The terse state variable names match the names used in the AARCH64
459+ PCS. */
460+
461+struct arg_state
462+{
463+ unsigned ngrn; /* Next general-purpose register number. */
464+ unsigned nsrn; /* Next vector register number. */
465+ unsigned nsaa; /* Next stack offset. */
466+};
467+
468+/* Initialize a procedure call argument marshalling state. */
469+static void
470+arg_init (struct arg_state *state, unsigned call_frame_size)
471+{
472+ state->ngrn = 0;
473+ state->nsrn = 0;
474+ state->nsaa = 0;
475+}
476+
477+/* Return the number of available consecutive core argument
478+ registers. */
479+
480+static unsigned
481+available_x (struct arg_state *state)
482+{
483+ return N_X_ARG_REG - state->ngrn;
484+}
485+
486+/* Return the number of available consecutive vector argument
487+ registers. */
488+
489+static unsigned
490+available_v (struct arg_state *state)
491+{
492+ return N_V_ARG_REG - state->nsrn;
493+}
494+
495+static void *
496+allocate_to_x (struct call_context *context, struct arg_state *state)
497+{
498+ FFI_ASSERT (state->ngrn < N_X_ARG_REG)
499+ return get_x_addr (context, (state->ngrn)++);
500+}
501+
502+static void *
503+allocate_to_s (struct call_context *context, struct arg_state *state)
504+{
505+ FFI_ASSERT (state->nsrn < N_V_ARG_REG)
506+ return get_s_addr (context, (state->nsrn)++);
507+}
508+
509+static void *
510+allocate_to_d (struct call_context *context, struct arg_state *state)
511+{
512+ FFI_ASSERT (state->nsrn < N_V_ARG_REG)
513+ return get_d_addr (context, (state->nsrn)++);
514+}
515+
516+static void *
517+allocate_to_v (struct call_context *context, struct arg_state *state)
518+{
519+ FFI_ASSERT (state->nsrn < N_V_ARG_REG)
520+ return get_v_addr (context, (state->nsrn)++);
521+}
522+
523+/* Allocate an aligned slot on the stack and return a pointer to it. */
524+static void *
525+allocate_to_stack (struct arg_state *state, void *stack, unsigned alignment,
526+ unsigned size)
527+{
528+ void *allocation;
529+
530+ /* Round up the NSAA to the larger of 8 or the natural
531+ alignment of the argument's type. */
532+ state->nsaa = ALIGN (state->nsaa, alignment);
533+ state->nsaa = ALIGN (state->nsaa, alignment);
534+ state->nsaa = ALIGN (state->nsaa, 8);
535+
536+ allocation = stack + state->nsaa;
537+
538+ state->nsaa += size;
539+ return allocation;
540+}
541+
542+static void
543+copy_basic_type (void *dest, void *source, unsigned short type)
544+{
545+ /* This is neccessary to ensure that basic types are copied
546+ sign extended to 64-bits as libffi expects. */
547+ switch (type)
548+ {
549+ case FFI_TYPE_FLOAT:
550+ *(float *) dest = *(float *) source;
551+ break;
552+ case FFI_TYPE_DOUBLE:
553+ *(double *) dest = *(double *) source;
554+ break;
555+ case FFI_TYPE_LONGDOUBLE:
556+ *(long double *) dest = *(long double *) source;
557+ break;
558+ case FFI_TYPE_UINT8:
559+ *(ffi_arg *) dest = *(UINT8 *) source;
560+ break;
561+ case FFI_TYPE_SINT8:
562+ *(ffi_sarg *) dest = *(SINT8 *) source;
563+ break;
564+ case FFI_TYPE_UINT16:
565+ *(ffi_arg *) dest = *(UINT16 *) source;
566+ break;
567+ case FFI_TYPE_SINT16:
568+ *(ffi_sarg *) dest = *(SINT16 *) source;
569+ break;
570+ case FFI_TYPE_UINT32:
571+ *(ffi_arg *) dest = *(UINT32 *) source;
572+ break;
573+ case FFI_TYPE_INT:
574+ case FFI_TYPE_SINT32:
575+ *(ffi_sarg *) dest = *(SINT32 *) source;
576+ break;
577+ case FFI_TYPE_POINTER:
578+ case FFI_TYPE_UINT64:
579+ *(ffi_arg *) dest = *(UINT64 *) source;
580+ break;
581+ case FFI_TYPE_SINT64:
582+ *(ffi_sarg *) dest = *(SINT64 *) source;
583+ break;
584+
585+ default:
586+ FFI_ASSERT (0);
587+ }
588+}
589+
590+static void
591+copy_hfa_to_reg_or_stack (void *memory,
592+ ffi_type *ty,
593+ struct call_context *context,
594+ unsigned char *stack,
595+ struct arg_state *state)
596+{
597+ unsigned elems = element_count (ty);
598+ if (available_v (state) < elems)
599+ {
600+ /* There are insufficient V registers. Further V register allocations
601+ are prevented, the NSAA is adjusted (by allocate_to_stack ())
602+ and the argument is copied to memory at the adjusted NSAA. */
603+ state->nsrn = N_V_ARG_REG;
604+ memcpy (allocate_to_stack (state, stack, ty->alignment, ty->size),
605+ memory,
606+ ty->size);
607+ }
608+ else
609+ {
610+ int i;
611+ unsigned short type = get_homogeneous_type (ty);
612+ unsigned elems = element_count (ty);
613+ for (i = 0; i < elems; i++)
614+ {
615+ void *reg = allocate_to_v (context, state);
616+ copy_basic_type (reg, memory, type);
617+ memory += get_basic_type_size (type);
618+ }
619+ }
620+}
621+
622+/* Either allocate an appropriate register for the argument type, or if
623+ none are available, allocate a stack slot and return a pointer
624+ to the allocated space. */
625+
626+static void *
627+allocate_to_register_or_stack (struct call_context *context,
628+ unsigned char *stack,
629+ struct arg_state *state,
630+ unsigned short type)
631+{
632+ size_t alignment = get_basic_type_alignment (type);
633+ size_t size = alignment;
634+ switch (type)
635+ {
636+ case FFI_TYPE_FLOAT:
637+ /* This is the only case for which the allocated stack size
638+ should not match the alignment of the type. */
639+ size = sizeof (UINT32);
640+ /* Fall through. */
641+ case FFI_TYPE_DOUBLE:
642+ if (state->nsrn < N_V_ARG_REG)
643+ return allocate_to_d (context, state);
644+ state->nsrn = N_V_ARG_REG;
645+ break;
646+ case FFI_TYPE_LONGDOUBLE:
647+ if (state->nsrn < N_V_ARG_REG)
648+ return allocate_to_v (context, state);
649+ state->nsrn = N_V_ARG_REG;
650+ break;
651+ case FFI_TYPE_UINT8:
652+ case FFI_TYPE_SINT8:
653+ case FFI_TYPE_UINT16:
654+ case FFI_TYPE_SINT16:
655+ case FFI_TYPE_UINT32:
656+ case FFI_TYPE_SINT32:
657+ case FFI_TYPE_INT:
658+ case FFI_TYPE_POINTER:
659+ case FFI_TYPE_UINT64:
660+ case FFI_TYPE_SINT64:
661+ if (state->ngrn < N_X_ARG_REG)
662+ return allocate_to_x (context, state);
663+ state->ngrn = N_X_ARG_REG;
664+ break;
665+ default:
666+ FFI_ASSERT (0);
667+ }
668+
669+ return allocate_to_stack (state, stack, alignment, size);
670+}
671+
672+/* Copy a value to an appropriate register, or if none are
673+ available, to the stack. */
674+
675+static void
676+copy_to_register_or_stack (struct call_context *context,
677+ unsigned char *stack,
678+ struct arg_state *state,
679+ void *value,
680+ unsigned short type)
681+{
682+ copy_basic_type (
683+ allocate_to_register_or_stack (context, stack, state, type),
684+ value,
685+ type);
686+}
687+
688+/* Marshall the arguments from FFI representation to procedure call
689+ context and stack. */
690+
691+static unsigned
692+aarch64_prep_args (struct call_context *context, unsigned char *stack,
693+ extended_cif *ecif)
694+{
695+ int i;
696+ struct arg_state state;
697+
698+ arg_init (&state, ALIGN(ecif->cif->bytes, 16));
699+
700+ for (i = 0; i < ecif->cif->nargs; i++)
701+ {
702+ ffi_type *ty = ecif->cif->arg_types[i];
703+ switch (ty->type)
704+ {
705+ case FFI_TYPE_VOID:
706+ FFI_ASSERT (0);
707+ break;
708+
709+ /* If the argument is a basic type the argument is allocated to an
710+ appropriate register, or if none are available, to the stack. */
711+ case FFI_TYPE_FLOAT:
712+ case FFI_TYPE_DOUBLE:
713+ case FFI_TYPE_LONGDOUBLE:
714+ case FFI_TYPE_UINT8:
715+ case FFI_TYPE_SINT8:
716+ case FFI_TYPE_UINT16:
717+ case FFI_TYPE_SINT16:
718+ case FFI_TYPE_UINT32:
719+ case FFI_TYPE_INT:
720+ case FFI_TYPE_SINT32:
721+ case FFI_TYPE_POINTER:
722+ case FFI_TYPE_UINT64:
723+ case FFI_TYPE_SINT64:
724+ copy_to_register_or_stack (context, stack, &state,
725+ ecif->avalue[i], ty->type);
726+ break;
727+
728+ case FFI_TYPE_STRUCT:
729+ if (is_hfa (ty))
730+ {
731+ copy_hfa_to_reg_or_stack (ecif->avalue[i], ty, context,
732+ stack, &state);
733+ }
734+ else if (ty->size > 16)
735+ {
736+ /* If the argument is a composite type that is larger than 16
737+ bytes, then the argument has been copied to memory, and
738+ the argument is replaced by a pointer to the copy. */
739+
740+ copy_to_register_or_stack (context, stack, &state,
741+ &(ecif->avalue[i]), FFI_TYPE_POINTER);
742+ }
743+ else if (available_x (&state) >= (ty->size + 7) / 8)
744+ {
745+ /* If the argument is a composite type and the size in
746+ double-words is not more than the number of available
747+ X registers, then the argument is copied into consecutive
748+ X registers. */
749+ int j;
750+ for (j = 0; j < (ty->size + 7) / 8; j++)
751+ {
752+ memcpy (allocate_to_x (context, &state),
753+ &(((UINT64 *) ecif->avalue[i])[j]),
754+ sizeof (UINT64));
755+ }
756+ }
757+ else
758+ {
759+ /* Otherwise, there are insufficient X registers. Further X
760+ register allocations are prevented, the NSAA is adjusted
761+ (by allocate_to_stack ()) and the argument is copied to
762+ memory at the adjusted NSAA. */
763+ state.ngrn = N_X_ARG_REG;
764+
765+ memcpy (allocate_to_stack (&state, stack, ty->alignment,
766+ ty->size), ecif->avalue + i, ty->size);
767+ }
768+ break;
769+
770+ default:
771+ FFI_ASSERT (0);
772+ break;
773+ }
774+ }
775+
776+ return ecif->cif->aarch64_flags;
777+}
778+
779+ffi_status
780+ffi_prep_cif_machdep (ffi_cif *cif)
781+{
782+ /* Round the stack up to a multiple of the stack alignment requirement. */
783+ cif->bytes =
784+ (cif->bytes + (AARCH64_STACK_ALIGN - 1)) & ~ (AARCH64_STACK_ALIGN - 1);
785+
786+ /* Initialize our flags. We are interested if this CIF will touch a
787+ vector register, if so we will enable context save and load to
788+ those registers, otherwise not. This is intended to be friendly
789+ to lazy float context switching in the kernel. */
790+ cif->aarch64_flags = 0;
791+
792+ if (is_v_register_candidate (cif->rtype))
793+ {
794+ cif->aarch64_flags |= AARCH64_FFI_WITH_V;
795+ }
796+ else
797+ {
798+ int i;
799+ for (i = 0; i < cif->nargs; i++)
800+ if (is_v_register_candidate (cif->arg_types[i]))
801+ {
802+ cif->aarch64_flags |= AARCH64_FFI_WITH_V;
803+ break;
804+ }
805+ }
806+
807+ return FFI_OK;
808+}
809+
810+/* Call a function with the provided arguments and capture the return
811+ value. */
812+void
813+ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
814+{
815+ extended_cif ecif;
816+
817+ ecif.cif = cif;
818+ ecif.avalue = avalue;
819+ ecif.rvalue = rvalue;
820+
821+ switch (cif->abi)
822+ {
823+ case FFI_SYSV:
824+ {
825+ struct call_context context;
826+ unsigned stack_bytes;
827+
828+ /* Figure out the total amount of stack space we need, the
829+ above call frame space needs to be 16 bytes aligned to
830+ ensure correct alignment of the first object inserted in
831+ that space hence the ALIGN applied to cif->bytes.*/
832+ stack_bytes = ALIGN(cif->bytes, 16);
833+
834+ memset (&context, 0, sizeof (context));
835+ if (is_register_candidate (cif->rtype))
836+ {
837+ ffi_call_SYSV (aarch64_prep_args, &context, &ecif, stack_bytes, fn);
838+ switch (cif->rtype->type)
839+ {
840+ case FFI_TYPE_VOID:
841+ case FFI_TYPE_FLOAT:
842+ case FFI_TYPE_DOUBLE:
843+ case FFI_TYPE_LONGDOUBLE:
844+ case FFI_TYPE_UINT8:
845+ case FFI_TYPE_SINT8:
846+ case FFI_TYPE_UINT16:
847+ case FFI_TYPE_SINT16:
848+ case FFI_TYPE_UINT32:
849+ case FFI_TYPE_SINT32:
850+ case FFI_TYPE_POINTER:
851+ case FFI_TYPE_UINT64:
852+ case FFI_TYPE_INT:
853+ case FFI_TYPE_SINT64:
854+ {
855+ void *addr = get_basic_type_addr (cif->rtype->type,
856+ &context, 0);
857+ copy_basic_type (rvalue, addr, cif->rtype->type);
858+ break;
859+ }
860+
861+ case FFI_TYPE_STRUCT:
862+ if (is_hfa (cif->rtype))
863+ {
864+ int j;
865+ unsigned short type = get_homogeneous_type (cif->rtype);
866+ unsigned elems = element_count (cif->rtype);
867+ for (j = 0; j < elems; j++)
868+ {
869+ void *reg = get_basic_type_addr (type, &context, j);
870+ copy_basic_type (rvalue, reg, type);
871+ rvalue += get_basic_type_size (type);
872+ }
873+ }
874+ else if ((cif->rtype->size + 7) / 8 < N_X_ARG_REG)
875+ {
876+ unsigned size = ALIGN (cif->rtype->size, sizeof (UINT64));
877+ memcpy (rvalue, get_x_addr (&context, 0), size);
878+ }
879+ else
880+ {
881+ FFI_ASSERT (0);
882+ }
883+ break;
884+
885+ default:
886+ FFI_ASSERT (0);
887+ break;
888+ }
889+ }
890+ else
891+ {
892+ memcpy (get_x_addr (&context, 8), &rvalue, sizeof (UINT64));
893+ ffi_call_SYSV (aarch64_prep_args, &context, &ecif,
894+ stack_bytes, fn);
895+ }
896+ break;
897+ }
898+
899+ default:
900+ FFI_ASSERT (0);
901+ break;
902+ }
903+}
904+
905+static unsigned char trampoline [] =
906+{ 0x70, 0x00, 0x00, 0x58, /* ldr x16, 1f */
907+ 0x91, 0x00, 0x00, 0x10, /* adr x17, 2f */
908+ 0x00, 0x02, 0x1f, 0xd6 /* br x16 */
909+};
910+
911+/* Build a trampoline. */
912+
913+#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX,FLAGS) \
914+ ({unsigned char *__tramp = (unsigned char*)(TRAMP); \
915+ UINT64 __fun = (UINT64)(FUN); \
916+ UINT64 __ctx = (UINT64)(CTX); \
917+ UINT64 __flags = (UINT64)(FLAGS); \
918+ memcpy (__tramp, trampoline, sizeof (trampoline)); \
919+ memcpy (__tramp + 12, &__fun, sizeof (__fun)); \
920+ memcpy (__tramp + 20, &__ctx, sizeof (__ctx)); \
921+ memcpy (__tramp + 28, &__flags, sizeof (__flags)); \
922+ __clear_cache(__tramp, __tramp + FFI_TRAMPOLINE_SIZE); \
923+ })
924+
925+ffi_status
926+ffi_prep_closure_loc (ffi_closure* closure,
927+ ffi_cif* cif,
928+ void (*fun)(ffi_cif*,void*,void**,void*),
929+ void *user_data,
930+ void *codeloc)
931+{
932+ if (cif->abi != FFI_SYSV)
933+ return FFI_BAD_ABI;
934+
935+ FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_SYSV, codeloc,
936+ cif->aarch64_flags);
937+
938+ closure->cif = cif;
939+ closure->user_data = user_data;
940+ closure->fun = fun;
941+
942+ return FFI_OK;
943+}
944+
945+/* Primary handler to setup and invoke a function within a closure.
946+
947+ A closure when invoked enters via the assembler wrapper
948+ ffi_closure_SYSV(). The wrapper allocates a call context on the
949+ stack, saves the interesting registers (from the perspective of
950+ the calling convention) into the context then passes control to
951+ ffi_closure_SYSV_inner() passing the saved context and a pointer to
952+ the stack at the point ffi_closure_SYSV() was invoked.
953+
954+ On the return path the assembler wrapper will reload call context
955+ regsiters.
956+
957+ ffi_closure_SYSV_inner() marshalls the call context into ffi value
958+ desriptors, invokes the wrapped function, then marshalls the return
959+ value back into the call context. */
960+
961+void
962+ffi_closure_SYSV_inner (ffi_closure *closure, struct call_context *context,
963+ void *stack)
964+{
965+ ffi_cif *cif = closure->cif;
966+ void **avalue = (void**) alloca (cif->nargs * sizeof (void*));
967+ void *rvalue = NULL;
968+ int i;
969+ struct arg_state state;
970+
971+ arg_init (&state, ALIGN(cif->bytes, 16));
972+
973+ for (i = 0; i < cif->nargs; i++)
974+ {
975+ ffi_type *ty = cif->arg_types[i];
976+
977+ switch (ty->type)
978+ {
979+ case FFI_TYPE_VOID:
980+ FFI_ASSERT (0);
981+ break;
982+
983+ case FFI_TYPE_UINT8:
984+ case FFI_TYPE_SINT8:
985+ case FFI_TYPE_UINT16:
986+ case FFI_TYPE_SINT16:
987+ case FFI_TYPE_UINT32:
988+ case FFI_TYPE_SINT32:
989+ case FFI_TYPE_INT:
990+ case FFI_TYPE_POINTER:
991+ case FFI_TYPE_UINT64:
992+ case FFI_TYPE_SINT64:
993+ case FFI_TYPE_FLOAT:
994+ case FFI_TYPE_DOUBLE:
995+ case FFI_TYPE_LONGDOUBLE:
996+ avalue[i] = allocate_to_register_or_stack (context, stack,
997+ &state, ty->type);
998+ break;
999+
1000+ case FFI_TYPE_STRUCT:
1001+ if (is_hfa (ty))
1002+ {
1003+ unsigned n = element_count (ty);
1004+ if (available_v (&state) < n)
1005+ {
1006+ state.nsrn = N_V_ARG_REG;
1007+ avalue[i] = allocate_to_stack (&state, stack, ty->alignment,
1008+ ty->size);
1009+ }
1010+ else
1011+ {
1012+ switch (get_homogeneous_type (ty))
1013+ {
1014+ case FFI_TYPE_FLOAT:
1015+ {
1016+ /* Eeek! We need a pointer to the structure,
1017+ however the homogeneous float elements are
1018+ being passed in individual S registers,
1019+ therefore the structure is not represented as
1020+ a contiguous sequence of bytes in our saved
1021+ register context. We need to fake up a copy
1022+ of the structure layed out in memory
1023+ correctly. The fake can be tossed once the
1024+ closure function has returned hence alloca()
1025+ is sufficient. */
1026+ int j;
1027+ UINT32 *p = avalue[i] = alloca (ty->size);
1028+ for (j = 0; j < element_count (ty); j++)
1029+ memcpy (&p[j],
1030+ allocate_to_s (context, &state),
1031+ sizeof (*p));
1032+ break;
1033+ }
1034+
1035+ case FFI_TYPE_DOUBLE:
1036+ {
1037+ /* Eeek! We need a pointer to the structure,
1038+ however the homogeneous float elements are
1039+ being passed in individual S registers,
1040+ therefore the structure is not represented as
1041+ a contiguous sequence of bytes in our saved
1042+ register context. We need to fake up a copy
1043+ of the structure layed out in memory
1044+ correctly. The fake can be tossed once the
1045+ closure function has returned hence alloca()
1046+ is sufficient. */
1047+ int j;
1048+ UINT64 *p = avalue[i] = alloca (ty->size);
1049+ for (j = 0; j < element_count (ty); j++)
1050+ memcpy (&p[j],
1051+ allocate_to_d (context, &state),
1052+ sizeof (*p));
1053+ break;
1054+ }
1055+
1056+ case FFI_TYPE_LONGDOUBLE:
1057+ memcpy (&avalue[i],
1058+ allocate_to_v (context, &state),
1059+ sizeof (*avalue));
1060+ break;
1061+
1062+ default:
1063+ FFI_ASSERT (0);
1064+ break;
1065+ }
1066+ }
1067+ }
1068+ else if (ty->size > 16)
1069+ {
1070+ /* Replace Composite type of size greater than 16 with a
1071+ pointer. */
1072+ memcpy (&avalue[i],
1073+ allocate_to_register_or_stack (context, stack,
1074+ &state, FFI_TYPE_POINTER),
1075+ sizeof (avalue[i]));
1076+ }
1077+ else if (available_x (&state) >= (ty->size + 7) / 8)
1078+ {
1079+ avalue[i] = get_x_addr (context, state.ngrn);
1080+ state.ngrn += (ty->size + 7) / 8;
1081+ }
1082+ else
1083+ {
1084+ state.ngrn = N_X_ARG_REG;
1085+
1086+ avalue[i] = allocate_to_stack (&state, stack, ty->alignment,
1087+ ty->size);
1088+ }
1089+ break;
1090+
1091+ default:
1092+ FFI_ASSERT (0);
1093+ break;
1094+ }
1095+ }
1096+
1097+ /* Figure out where the return value will be passed, either in
1098+ registers or in a memory block allocated by the caller and passed
1099+ in x8. */
1100+
1101+ if (is_register_candidate (cif->rtype))
1102+ {
1103+ /* Register candidates are *always* returned in registers. */
1104+
1105+ /* Allocate a scratchpad for the return value, we will let the
1106+ callee scrible the result into the scratch pad then move the
1107+ contents into the appropriate return value location for the
1108+ call convention. */
1109+ rvalue = alloca (cif->rtype->size);
1110+ (closure->fun) (cif, rvalue, avalue, closure->user_data);
1111+
1112+ /* Copy the return value into the call context so that it is returned
1113+ as expected to our caller. */
1114+ switch (cif->rtype->type)
1115+ {
1116+ case FFI_TYPE_VOID:
1117+ break;
1118+
1119+ case FFI_TYPE_UINT8:
1120+ case FFI_TYPE_UINT16:
1121+ case FFI_TYPE_UINT32:
1122+ case FFI_TYPE_POINTER:
1123+ case FFI_TYPE_UINT64:
1124+ case FFI_TYPE_SINT8:
1125+ case FFI_TYPE_SINT16:
1126+ case FFI_TYPE_INT:
1127+ case FFI_TYPE_SINT32:
1128+ case FFI_TYPE_SINT64:
1129+ case FFI_TYPE_FLOAT:
1130+ case FFI_TYPE_DOUBLE:
1131+ case FFI_TYPE_LONGDOUBLE:
1132+ {
1133+ void *addr = get_basic_type_addr (cif->rtype->type, context, 0);
1134+ copy_basic_type (addr, rvalue, cif->rtype->type);
1135+ break;
1136+ }
1137+ case FFI_TYPE_STRUCT:
1138+ if (is_hfa (cif->rtype))
1139+ {
1140+ int i;
1141+ unsigned short type = get_homogeneous_type (cif->rtype);
1142+ unsigned elems = element_count (cif->rtype);
1143+ for (i = 0; i < elems; i++)
1144+ {
1145+ void *reg = get_basic_type_addr (type, context, i);
1146+ copy_basic_type (reg, rvalue, type);
1147+ rvalue += get_basic_type_size (type);
1148+ }
1149+ }
1150+ else if ((cif->rtype->size + 7) / 8 < N_X_ARG_REG)
1151+ {
1152+ unsigned size = ALIGN (cif->rtype->size, sizeof (UINT64)) ;
1153+ memcpy (get_x_addr (context, 0), rvalue, size);
1154+ }
1155+ else
1156+ {
1157+ FFI_ASSERT (0);
1158+ }
1159+ break;
1160+ default:
1161+ FFI_ASSERT (0);
1162+ break;
1163+ }
1164+ }
1165+ else
1166+ {
1167+ memcpy (&rvalue, get_x_addr (context, 8), sizeof (UINT64));
1168+ (closure->fun) (cif, rvalue, avalue, closure->user_data);
1169+ }
1170+}
1171+
1172diff --git a/src/aarch64/ffitarget.h b/src/aarch64/ffitarget.h
1173new file mode 100644
1174index 0000000..6f1a348
1175--- /dev/null
1176+++ b/src/aarch64/ffitarget.h
1177@@ -0,0 +1,59 @@
1178+/* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd.
1179+
1180+Permission is hereby granted, free of charge, to any person obtaining
1181+a copy of this software and associated documentation files (the
1182+``Software''), to deal in the Software without restriction, including
1183+without limitation the rights to use, copy, modify, merge, publish,
1184+distribute, sublicense, and/or sell copies of the Software, and to
1185+permit persons to whom the Software is furnished to do so, subject to
1186+the following conditions:
1187+
1188+The above copyright notice and this permission notice shall be
1189+included in all copies or substantial portions of the Software.
1190+
1191+THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
1192+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1193+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
1194+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
1195+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
1196+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
1197+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
1198+
1199+#ifndef LIBFFI_TARGET_H
1200+#define LIBFFI_TARGET_H
1201+
1202+#ifndef LIBFFI_H
1203+#error "Please do not include ffitarget.h directly into your source. Use ffi.h instead."
1204+#endif
1205+
1206+#ifndef LIBFFI_ASM
1207+typedef unsigned long ffi_arg;
1208+typedef signed long ffi_sarg;
1209+
1210+typedef enum ffi_abi
1211+ {
1212+ FFI_FIRST_ABI = 0,
1213+ FFI_SYSV,
1214+ FFI_LAST_ABI,
1215+ FFI_DEFAULT_ABI = FFI_SYSV
1216+ } ffi_abi;
1217+#endif
1218+
1219+/* ---- Definitions for closures ----------------------------------------- */
1220+
1221+#define FFI_CLOSURES 1
1222+#define FFI_TRAMPOLINE_SIZE 36
1223+#define FFI_NATIVE_RAW_API 0
1224+
1225+/* ---- Internal ---- */
1226+
1227+
1228+#define FFI_EXTRA_CIF_FIELDS unsigned aarch64_flags
1229+
1230+#define AARCH64_FFI_WITH_V_BIT 0
1231+
1232+#define AARCH64_N_XREG 32
1233+#define AARCH64_N_VREG 32
1234+#define AARCH64_CALL_CONTEXT_SIZE (AARCH64_N_XREG * 8 + AARCH64_N_VREG * 16)
1235+
1236+#endif
1237diff --git a/src/aarch64/sysv.S b/src/aarch64/sysv.S
1238new file mode 100644
1239index 0000000..b8cd421
1240--- /dev/null
1241+++ b/src/aarch64/sysv.S
1242@@ -0,0 +1,307 @@
1243+/* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd.
1244+
1245+Permission is hereby granted, free of charge, to any person obtaining
1246+a copy of this software and associated documentation files (the
1247+``Software''), to deal in the Software without restriction, including
1248+without limitation the rights to use, copy, modify, merge, publish,
1249+distribute, sublicense, and/or sell copies of the Software, and to
1250+permit persons to whom the Software is furnished to do so, subject to
1251+the following conditions:
1252+
1253+The above copyright notice and this permission notice shall be
1254+included in all copies or substantial portions of the Software.
1255+
1256+THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
1257+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1258+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
1259+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
1260+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
1261+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
1262+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
1263+
1264+#define LIBFFI_ASM
1265+#include <fficonfig.h>
1266+#include <ffi.h>
1267+
1268+#define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off
1269+#define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off
1270+#define cfi_restore(reg) .cfi_restore reg
1271+#define cfi_def_cfa_register(reg) .cfi_def_cfa_register reg
1272+
1273+ .text
1274+ .globl ffi_call_SYSV
1275+ .type ffi_call_SYSV, #function
1276+
1277+/* ffi_call_SYSV()
1278+
1279+ Create a stack frame, setup an argument context, call the callee
1280+ and extract the result.
1281+
1282+ The maximum required argument stack size is provided,
1283+ ffi_call_SYSV() allocates that stack space then calls the
1284+ prepare_fn to populate register context and stack. The
1285+ argument passing registers are loaded from the register
1286+ context and the callee called, on return the register passing
1287+ register are saved back to the context. Our caller will
1288+ extract the return value from the final state of the saved
1289+ register context.
1290+
1291+ Prototype:
1292+
1293+ extern unsigned
1294+ ffi_call_SYSV (void (*)(struct call_context *context, unsigned char *,
1295+ extended_cif *),
1296+ struct call_context *context,
1297+ extended_cif *,
1298+ unsigned required_stack_size,
1299+ void (*fn)(void));
1300+
1301+ Therefore on entry we have:
1302+
1303+ x0 prepare_fn
1304+ x1 &context
1305+ x2 &ecif
1306+ x3 bytes
1307+ x4 fn
1308+
1309+ This function uses the following stack frame layout:
1310+
1311+ ==
1312+ saved x30(lr)
1313+ x29(fp)-> saved x29(fp)
1314+ saved x24
1315+ saved x23
1316+ saved x22
1317+ sp' -> saved x21
1318+ ...
1319+ sp -> (constructed callee stack arguments)
1320+ ==
1321+
1322+ Voila! */
1323+
1324+#define ffi_call_SYSV_FS (8 * 4)
1325+
1326+ .cfi_startproc
1327+ffi_call_SYSV:
1328+ stp x29, x30, [sp, #-16]!
1329+ cfi_adjust_cfa_offset (16)
1330+ cfi_rel_offset (x29, 0)
1331+ cfi_rel_offset (x30, 8)
1332+
1333+ mov x29, sp
1334+ cfi_def_cfa_register (x29)
1335+ sub sp, sp, #ffi_call_SYSV_FS
1336+
1337+ stp x21, x22, [sp, 0]
1338+ cfi_rel_offset (x21, 0 - ffi_call_SYSV_FS)
1339+ cfi_rel_offset (x22, 8 - ffi_call_SYSV_FS)
1340+
1341+ stp x23, x24, [sp, 16]
1342+ cfi_rel_offset (x23, 16 - ffi_call_SYSV_FS)
1343+ cfi_rel_offset (x24, 24 - ffi_call_SYSV_FS)
1344+
1345+ mov x21, x1
1346+ mov x22, x2
1347+ mov x24, x4
1348+
1349+ /* Allocate the stack space for the actual arguments, many
1350+ arguments will be passed in registers, but we assume
1351+ worst case and allocate sufficient stack for ALL of
1352+ the arguments. */
1353+ sub sp, sp, x3
1354+
1355+ /* unsigned (*prepare_fn) (struct call_context *context,
1356+ unsigned char *stack, extended_cif *ecif);
1357+ */
1358+ mov x23, x0
1359+ mov x0, x1
1360+ mov x1, sp
1361+ /* x2 already in place */
1362+ blr x23
1363+
1364+ /* Preserve the flags returned. */
1365+ mov x23, x0
1366+
1367+ /* Figure out if we should touch the vector registers. */
1368+ tbz x23, #AARCH64_FFI_WITH_V_BIT, 1f
1369+
1370+ /* Load the vector argument passing registers. */
1371+ ldp q0, q1, [x21, #8*32 + 0]
1372+ ldp q2, q3, [x21, #8*32 + 32]
1373+ ldp q4, q5, [x21, #8*32 + 64]
1374+ ldp q6, q7, [x21, #8*32 + 96]
1375+1:
1376+ /* Load the core argument passing registers. */
1377+ ldp x0, x1, [x21, #0]
1378+ ldp x2, x3, [x21, #16]
1379+ ldp x4, x5, [x21, #32]
1380+ ldp x6, x7, [x21, #48]
1381+
1382+ /* Don't forget x8 which may be holding the address of a return buffer.
1383+ */
1384+ ldr x8, [x21, #8*8]
1385+
1386+ blr x24
1387+
1388+ /* Save the core argument passing registers. */
1389+ stp x0, x1, [x21, #0]
1390+ stp x2, x3, [x21, #16]
1391+ stp x4, x5, [x21, #32]
1392+ stp x6, x7, [x21, #48]
1393+
1394+ /* Note nothing useful ever comes back in x8! */
1395+
1396+ /* Figure out if we should touch the vector registers. */
1397+ tbz x23, #AARCH64_FFI_WITH_V_BIT, 1f
1398+
1399+ /* Save the vector argument passing registers. */
1400+ stp q0, q1, [x21, #8*32 + 0]
1401+ stp q2, q3, [x21, #8*32 + 32]
1402+ stp q4, q5, [x21, #8*32 + 64]
1403+ stp q6, q7, [x21, #8*32 + 96]
1404+1:
1405+ /* All done, unwind our stack frame. */
1406+ ldp x21, x22, [x29, # - ffi_call_SYSV_FS]
1407+ cfi_restore (x21)
1408+ cfi_restore (x22)
1409+
1410+ ldp x23, x24, [x29, # - ffi_call_SYSV_FS + 16]
1411+ cfi_restore (x23)
1412+ cfi_restore (x24)
1413+
1414+ mov sp, x29
1415+ cfi_def_cfa_register (sp)
1416+
1417+ ldp x29, x30, [sp], #16
1418+ cfi_adjust_cfa_offset (-16)
1419+ cfi_restore (x29)
1420+ cfi_restore (x30)
1421+
1422+ ret
1423+
1424+ .cfi_endproc
1425+ .size ffi_call_SYSV, .-ffi_call_SYSV
1426+
1427+#define ffi_closure_SYSV_FS (8 * 2 + AARCH64_CALL_CONTEXT_SIZE)
1428+
1429+/* ffi_closure_SYSV
1430+
1431+ Closure invocation glue. This is the low level code invoked directly by
1432+ the closure trampoline to setup and call a closure.
1433+
1434+ On entry x17 points to a struct trampoline_data, x16 has been clobbered
1435+ all other registers are preserved.
1436+
1437+ We allocate a call context and save the argument passing registers,
1438+ then invoked the generic C ffi_closure_SYSV_inner() function to do all
1439+ the real work, on return we load the result passing registers back from
1440+ the call context.
1441+
1442+ On entry
1443+
1444+ extern void
1445+ ffi_closure_SYSV (struct trampoline_data *);
1446+
1447+ struct trampoline_data
1448+ {
1449+ UINT64 *ffi_closure;
1450+ UINT64 flags;
1451+ };
1452+
1453+ This function uses the following stack frame layout:
1454+
1455+ ==
1456+ saved x30(lr)
1457+ x29(fp)-> saved x29(fp)
1458+ saved x22
1459+ saved x21
1460+ ...
1461+ sp -> call_context
1462+ ==
1463+
1464+ Voila! */
1465+
1466+ .text
1467+ .globl ffi_closure_SYSV
1468+ .cfi_startproc
1469+ffi_closure_SYSV:
1470+ stp x29, x30, [sp, #-16]!
1471+ cfi_adjust_cfa_offset (16)
1472+ cfi_rel_offset (x29, 0)
1473+ cfi_rel_offset (x30, 8)
1474+
1475+ mov x29, sp
1476+
1477+ sub sp, sp, #ffi_closure_SYSV_FS
1478+ cfi_adjust_cfa_offset (ffi_closure_SYSV_FS)
1479+
1480+ stp x21, x22, [x29, #-16]
1481+ cfi_rel_offset (x21, 0)
1482+ cfi_rel_offset (x22, 8)
1483+
1484+ /* Load x21 with &call_context. */
1485+ mov x21, sp
1486+ /* Preserve our struct trampoline_data * */
1487+ mov x22, x17
1488+
1489+ /* Save the rest of the argument passing registers. */
1490+ stp x0, x1, [x21, #0]
1491+ stp x2, x3, [x21, #16]
1492+ stp x4, x5, [x21, #32]
1493+ stp x6, x7, [x21, #48]
1494+ /* Don't forget we may have been given a result scratch pad address.
1495+ */
1496+ str x8, [x21, #64]
1497+
1498+ /* Figure out if we should touch the vector registers. */
1499+ ldr x0, [x22, #8]
1500+ tbz x0, #AARCH64_FFI_WITH_V_BIT, 1f
1501+
1502+ /* Save the argument passing vector registers. */
1503+ stp q0, q1, [x21, #8*32 + 0]
1504+ stp q2, q3, [x21, #8*32 + 32]
1505+ stp q4, q5, [x21, #8*32 + 64]
1506+ stp q6, q7, [x21, #8*32 + 96]
1507+1:
1508+ /* Load &ffi_closure.. */
1509+ ldr x0, [x22, #0]
1510+ mov x1, x21
1511+ /* Compute the location of the stack at the point that the
1512+ trampoline was called. */
1513+ add x2, x29, #16
1514+
1515+ bl ffi_closure_SYSV_inner
1516+
1517+ /* Figure out if we should touch the vector registers. */
1518+ ldr x0, [x22, #8]
1519+ tbz x0, #AARCH64_FFI_WITH_V_BIT, 1f
1520+
1521+ /* Load the result passing vector registers. */
1522+ ldp q0, q1, [x21, #8*32 + 0]
1523+ ldp q2, q3, [x21, #8*32 + 32]
1524+ ldp q4, q5, [x21, #8*32 + 64]
1525+ ldp q6, q7, [x21, #8*32 + 96]
1526+1:
1527+ /* Load the result passing core registers. */
1528+ ldp x0, x1, [x21, #0]
1529+ ldp x2, x3, [x21, #16]
1530+ ldp x4, x5, [x21, #32]
1531+ ldp x6, x7, [x21, #48]
1532+ /* Note nothing usefull is returned in x8. */
1533+
1534+ /* We are done, unwind our frame. */
1535+ ldp x21, x22, [x29, #-16]
1536+ cfi_restore (x21)
1537+ cfi_restore (x22)
1538+
1539+ mov sp, x29
1540+ cfi_adjust_cfa_offset (-ffi_closure_SYSV_FS)
1541+
1542+ ldp x29, x30, [sp], #16
1543+ cfi_adjust_cfa_offset (-16)
1544+ cfi_restore (x29)
1545+ cfi_restore (x30)
1546+
1547+ ret
1548+ .cfi_endproc
1549+ .size ffi_closure_SYSV, .-ffi_closure_SYSV
1550diff --git a/testsuite/lib/libffi.exp b/testsuite/lib/libffi.exp
1551index 4a65ed1..8ee3f15 100644
1552--- a/testsuite/lib/libffi.exp
1553+++ b/testsuite/lib/libffi.exp
1554@@ -203,6 +203,10 @@ proc libffi_target_compile { source dest type options } {
1555
1556 lappend options "libs= -lffi"
1557
1558+ if { [string match "aarch64*-*-linux*" $target_triplet] } {
1559+ lappend options "libs= -lpthread"
1560+ }
1561+
1562 verbose "options: $options"
1563 return [target_compile $source $dest $type $options]
1564 }
1565diff --git a/testsuite/libffi.call/cls_struct_va1.c b/testsuite/libffi.call/cls_struct_va1.c
1566new file mode 100644
1567index 0000000..91772bd
1568--- /dev/null
1569+++ b/testsuite/libffi.call/cls_struct_va1.c
1570@@ -0,0 +1,114 @@
1571+/* Area: ffi_call, closure_call
1572+ Purpose: Test doubles passed in variable argument lists.
1573+ Limitations: none.
1574+ PR: none.
1575+ Originator: Blake Chaffin 6/6/2007 */
1576+
1577+/* { dg-do run } */
1578+/* { dg-output "" { xfail avr32*-*-* } } */
1579+#include "ffitest.h"
1580+
1581+struct small_tag
1582+{
1583+ unsigned char a;
1584+ unsigned char b;
1585+};
1586+
1587+struct large_tag
1588+{
1589+ unsigned a;
1590+ unsigned b;
1591+ unsigned c;
1592+ unsigned d;
1593+ unsigned e;
1594+};
1595+
1596+static void
1597+test_fn (ffi_cif* cif __UNUSED__, void* resp,
1598+ void** args, void* userdata __UNUSED__)
1599+{
1600+ int n = *(int*)args[0];
1601+ struct small_tag s1 = * (struct small_tag *) args[1];
1602+ struct large_tag l1 = * (struct large_tag *) args[2];
1603+ struct small_tag s2 = * (struct small_tag *) args[3];
1604+
1605+ printf ("%d %d %d %d %d %d %d %d %d %d\n", n, s1.a, s1.b,
1606+ l1.a, l1.b, l1.c, l1.d, l1.e,
1607+ s2.a, s2.b);
1608+ * (int*) resp = 42;
1609+}
1610+
1611+int
1612+main (void)
1613+{
1614+ ffi_cif cif;
1615+ void *code;
1616+ ffi_closure *pcl = ffi_closure_alloc (sizeof (ffi_closure), &code);
1617+ ffi_type* arg_types[5];
1618+
1619+ ffi_arg res = 0;
1620+
1621+ ffi_type s_type;
1622+ ffi_type *s_type_elements[3];
1623+
1624+ ffi_type l_type;
1625+ ffi_type *l_type_elements[6];
1626+
1627+ struct small_tag s1;
1628+ struct small_tag s2;
1629+ struct large_tag l1;
1630+
1631+ int si;
1632+
1633+ s_type.size = 0;
1634+ s_type.alignment = 0;
1635+ s_type.type = FFI_TYPE_STRUCT;
1636+ s_type.elements = s_type_elements;
1637+
1638+ s_type_elements[0] = &ffi_type_uchar;
1639+ s_type_elements[1] = &ffi_type_uchar;
1640+ s_type_elements[2] = NULL;
1641+
1642+ l_type.size = 0;
1643+ l_type.alignment = 0;
1644+ l_type.type = FFI_TYPE_STRUCT;
1645+ l_type.elements = l_type_elements;
1646+
1647+ l_type_elements[0] = &ffi_type_uint;
1648+ l_type_elements[1] = &ffi_type_uint;
1649+ l_type_elements[2] = &ffi_type_uint;
1650+ l_type_elements[3] = &ffi_type_uint;
1651+ l_type_elements[4] = &ffi_type_uint;
1652+ l_type_elements[5] = NULL;
1653+
1654+ arg_types[0] = &ffi_type_sint;
1655+ arg_types[1] = &s_type;
1656+ arg_types[2] = &l_type;
1657+ arg_types[3] = &s_type;
1658+ arg_types[4] = NULL;
1659+
1660+ CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 1, 4, &ffi_type_sint,
1661+ arg_types) == FFI_OK);
1662+
1663+ si = 4;
1664+ s1.a = 5;
1665+ s1.b = 6;
1666+
1667+ s2.a = 20;
1668+ s2.b = 21;
1669+
1670+ l1.a = 10;
1671+ l1.b = 11;
1672+ l1.c = 12;
1673+ l1.d = 13;
1674+ l1.e = 14;
1675+
1676+ CHECK(ffi_prep_closure_loc(pcl, &cif, test_fn, NULL, code) == FFI_OK);
1677+
1678+ res = ((int (*)(int, ...))(code))(si, s1, l1, s2);
1679+ // { dg-output "4 5 6 10 11 12 13 14 20 21" }
1680+ printf("res: %d\n", (int) res);
1681+ // { dg-output "\nres: 42" }
1682+
1683+ exit(0);
1684+}
1685diff --git a/testsuite/libffi.call/cls_uchar_va.c b/testsuite/libffi.call/cls_uchar_va.c
1686new file mode 100644
1687index 0000000..19cd4f3
1688--- /dev/null
1689+++ b/testsuite/libffi.call/cls_uchar_va.c
1690@@ -0,0 +1,44 @@
1691+/* Area: closure_call
1692+ Purpose: Test anonymous unsigned char argument.
1693+ Limitations: none.
1694+ PR: none.
1695+ Originator: ARM Ltd. */
1696+
1697+/* { dg-do run } */
1698+#include "ffitest.h"
1699+
1700+typedef unsigned char T;
1701+
1702+static void cls_ret_T_fn(ffi_cif* cif __UNUSED__, void* resp, void** args,
1703+ void* userdata __UNUSED__)
1704+ {
1705+ *(T *)resp = *(T *)args[0];
1706+
1707+ printf("%d: %d %d\n", *(T *)resp, *(T *)args[0], *(T *)args[1]);
1708+ }
1709+
1710+typedef T (*cls_ret_T)(T, ...);
1711+
1712+int main (void)
1713+{
1714+ ffi_cif cif;
1715+ void *code;
1716+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
1717+ ffi_type * cl_arg_types[3];
1718+ T res;
1719+
1720+ cl_arg_types[0] = &ffi_type_uchar;
1721+ cl_arg_types[1] = &ffi_type_uchar;
1722+ cl_arg_types[2] = NULL;
1723+
1724+ /* Initialize the cif */
1725+ CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 1, 2,
1726+ &ffi_type_uchar, cl_arg_types) == FFI_OK);
1727+
1728+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_ret_T_fn, NULL, code) == FFI_OK);
1729+ res = ((((cls_ret_T)code)(67, 4)));
1730+ /* { dg-output "67: 67 4" } */
1731+ printf("res: %d\n", res);
1732+ /* { dg-output "\nres: 67" } */
1733+ exit(0);
1734+}
1735diff --git a/testsuite/libffi.call/cls_uint_va.c b/testsuite/libffi.call/cls_uint_va.c
1736new file mode 100644
1737index 0000000..150fddd
1738--- /dev/null
1739+++ b/testsuite/libffi.call/cls_uint_va.c
1740@@ -0,0 +1,45 @@
1741+/* Area: closure_call
1742+ Purpose: Test anonymous unsigned int argument.
1743+ Limitations: none.
1744+ PR: none.
1745+ Originator: ARM Ltd. */
1746+
1747+/* { dg-do run } */
1748+
1749+#include "ffitest.h"
1750+
1751+typedef unsigned int T;
1752+
1753+static void cls_ret_T_fn(ffi_cif* cif __UNUSED__, void* resp, void** args,
1754+ void* userdata __UNUSED__)
1755+ {
1756+ *(T *)resp = *(T *)args[0];
1757+
1758+ printf("%d: %d %d\n", *(T *)resp, *(T *)args[0], *(T *)args[1]);
1759+ }
1760+
1761+typedef T (*cls_ret_T)(T, ...);
1762+
1763+int main (void)
1764+{
1765+ ffi_cif cif;
1766+ void *code;
1767+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
1768+ ffi_type * cl_arg_types[3];
1769+ T res;
1770+
1771+ cl_arg_types[0] = &ffi_type_uint;
1772+ cl_arg_types[1] = &ffi_type_uint;
1773+ cl_arg_types[2] = NULL;
1774+
1775+ /* Initialize the cif */
1776+ CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 1, 2,
1777+ &ffi_type_uint, cl_arg_types) == FFI_OK);
1778+
1779+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_ret_T_fn, NULL, code) == FFI_OK);
1780+ res = ((((cls_ret_T)code)(67, 4)));
1781+ /* { dg-output "67: 67 4" } */
1782+ printf("res: %d\n", res);
1783+ /* { dg-output "\nres: 67" } */
1784+ exit(0);
1785+}
1786diff --git a/testsuite/libffi.call/cls_ulong_va.c b/testsuite/libffi.call/cls_ulong_va.c
1787new file mode 100644
1788index 0000000..0315082
1789--- /dev/null
1790+++ b/testsuite/libffi.call/cls_ulong_va.c
1791@@ -0,0 +1,45 @@
1792+/* Area: closure_call
1793+ Purpose: Test anonymous unsigned long argument.
1794+ Limitations: none.
1795+ PR: none.
1796+ Originator: ARM Ltd. */
1797+
1798+/* { dg-do run } */
1799+
1800+#include "ffitest.h"
1801+
1802+typedef unsigned long T;
1803+
1804+static void cls_ret_T_fn(ffi_cif* cif __UNUSED__, void* resp, void** args,
1805+ void* userdata __UNUSED__)
1806+ {
1807+ *(T *)resp = *(T *)args[0];
1808+
1809+ printf("%ld: %ld %ld\n", *(T *)resp, *(T *)args[0], *(T *)args[1]);
1810+ }
1811+
1812+typedef T (*cls_ret_T)(T, ...);
1813+
1814+int main (void)
1815+{
1816+ ffi_cif cif;
1817+ void *code;
1818+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
1819+ ffi_type * cl_arg_types[3];
1820+ T res;
1821+
1822+ cl_arg_types[0] = &ffi_type_ulong;
1823+ cl_arg_types[1] = &ffi_type_ulong;
1824+ cl_arg_types[2] = NULL;
1825+
1826+ /* Initialize the cif */
1827+ CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 1, 2,
1828+ &ffi_type_ulong, cl_arg_types) == FFI_OK);
1829+
1830+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_ret_T_fn, NULL, code) == FFI_OK);
1831+ res = ((((cls_ret_T)code)(67, 4)));
1832+ /* { dg-output "67: 67 4" } */
1833+ printf("res: %ld\n", res);
1834+ /* { dg-output "\nres: 67" } */
1835+ exit(0);
1836+}
1837diff --git a/testsuite/libffi.call/cls_ushort_va.c b/testsuite/libffi.call/cls_ushort_va.c
1838new file mode 100644
1839index 0000000..b2b5a3b
1840--- /dev/null
1841+++ b/testsuite/libffi.call/cls_ushort_va.c
1842@@ -0,0 +1,44 @@
1843+/* Area: closure_call
1844+ Purpose: Test anonymous unsigned short argument.
1845+ Limitations: none.
1846+ PR: none.
1847+ Originator: ARM Ltd. */
1848+
1849+/* { dg-do run } */
1850+#include "ffitest.h"
1851+
1852+typedef unsigned short T;
1853+
1854+static void cls_ret_T_fn(ffi_cif* cif __UNUSED__, void* resp, void** args,
1855+ void* userdata __UNUSED__)
1856+ {
1857+ *(T *)resp = *(T *)args[0];
1858+
1859+ printf("%d: %d %d\n", *(T *)resp, *(T *)args[0], *(T *)args[1]);
1860+ }
1861+
1862+typedef T (*cls_ret_T)(T, ...);
1863+
1864+int main (void)
1865+{
1866+ ffi_cif cif;
1867+ void *code;
1868+ ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
1869+ ffi_type * cl_arg_types[3];
1870+ T res;
1871+
1872+ cl_arg_types[0] = &ffi_type_ushort;
1873+ cl_arg_types[1] = &ffi_type_ushort;
1874+ cl_arg_types[2] = NULL;
1875+
1876+ /* Initialize the cif */
1877+ CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 1, 2,
1878+ &ffi_type_ushort, cl_arg_types) == FFI_OK);
1879+
1880+ CHECK(ffi_prep_closure_loc(pcl, &cif, cls_ret_T_fn, NULL, code) == FFI_OK);
1881+ res = ((((cls_ret_T)code)(67, 4)));
1882+ /* { dg-output "67: 67 4" } */
1883+ printf("res: %d\n", res);
1884+ /* { dg-output "\nres: 67" } */
1885+ exit(0);
1886+}
1887diff --git a/testsuite/libffi.call/nested_struct11.c b/testsuite/libffi.call/nested_struct11.c
1888new file mode 100644
1889index 0000000..fce6948
1890--- /dev/null
1891+++ b/testsuite/libffi.call/nested_struct11.c
1892@@ -0,0 +1,121 @@
1893+/* Area: ffi_call, closure_call
1894+ Purpose: Check parameter passing with nested structs
1895+ of a single type. This tests the special cases
1896+ for homogenous floating-point aggregates in the
1897+ AArch64 PCS.
1898+ Limitations: none.
1899+ PR: none.
1900+ Originator: ARM Ltd. */
1901+
1902+/* { dg-do run } */
1903+#include "ffitest.h"
1904+
1905+typedef struct A {
1906+ float a_x;
1907+ float a_y;
1908+} A;
1909+
1910+typedef struct B {
1911+ float b_x;
1912+ float b_y;
1913+} B;
1914+
1915+typedef struct C {
1916+ A a;
1917+ B b;
1918+} C;
1919+
1920+static C C_fn (int x, int y, int z, C source, int i, int j, int k)
1921+{
1922+ C result;
1923+ result.a.a_x = source.a.a_x;
1924+ result.a.a_y = source.a.a_y;
1925+ result.b.b_x = source.b.b_x;
1926+ result.b.b_y = source.b.b_y;
1927+
1928+ printf ("%d, %d, %d, %d, %d, %d\n", x, y, z, i, j, k);
1929+
1930+ printf ("%.1f, %.1f, %.1f, %.1f, "
1931+ "%.1f, %.1f, %.1f, %.1f\n",
1932+ source.a.a_x, source.a.a_y,
1933+ source.b.b_x, source.b.b_y,
1934+ result.a.a_x, result.a.a_y,
1935+ result.b.b_x, result.b.b_y);
1936+
1937+ return result;
1938+}
1939+
1940+int main (void)
1941+{
1942+ ffi_cif cif;
1943+
1944+ ffi_type* struct_fields_source_a[3];
1945+ ffi_type* struct_fields_source_b[3];
1946+ ffi_type* struct_fields_source_c[3];
1947+ ffi_type* arg_types[8];
1948+
1949+ ffi_type struct_type_a, struct_type_b, struct_type_c;
1950+
1951+ struct A source_fld_a = {1.0, 2.0};
1952+ struct B source_fld_b = {4.0, 8.0};
1953+ int k = 1;
1954+
1955+ struct C result;
1956+ struct C source = {source_fld_a, source_fld_b};
1957+
1958+ struct_type_a.size = 0;
1959+ struct_type_a.alignment = 0;
1960+ struct_type_a.type = FFI_TYPE_STRUCT;
1961+ struct_type_a.elements = struct_fields_source_a;
1962+
1963+ struct_type_b.size = 0;
1964+ struct_type_b.alignment = 0;
1965+ struct_type_b.type = FFI_TYPE_STRUCT;
1966+ struct_type_b.elements = struct_fields_source_b;
1967+
1968+ struct_type_c.size = 0;
1969+ struct_type_c.alignment = 0;
1970+ struct_type_c.type = FFI_TYPE_STRUCT;
1971+ struct_type_c.elements = struct_fields_source_c;
1972+
1973+ struct_fields_source_a[0] = &ffi_type_float;
1974+ struct_fields_source_a[1] = &ffi_type_float;
1975+ struct_fields_source_a[2] = NULL;
1976+
1977+ struct_fields_source_b[0] = &ffi_type_float;
1978+ struct_fields_source_b[1] = &ffi_type_float;
1979+ struct_fields_source_b[2] = NULL;
1980+
1981+ struct_fields_source_c[0] = &struct_type_a;
1982+ struct_fields_source_c[1] = &struct_type_b;
1983+ struct_fields_source_c[2] = NULL;
1984+
1985+ arg_types[0] = &ffi_type_sint32;
1986+ arg_types[1] = &ffi_type_sint32;
1987+ arg_types[2] = &ffi_type_sint32;
1988+ arg_types[3] = &struct_type_c;
1989+ arg_types[4] = &ffi_type_sint32;
1990+ arg_types[5] = &ffi_type_sint32;
1991+ arg_types[6] = &ffi_type_sint32;
1992+ arg_types[7] = NULL;
1993+
1994+ void *args[7];
1995+ args[0] = &k;
1996+ args[1] = &k;
1997+ args[2] = &k;
1998+ args[3] = &source;
1999+ args[4] = &k;
2000+ args[5] = &k;
2001+ args[6] = &k;
2002+ CHECK (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, 7, &struct_type_c,
2003+ arg_types) == FFI_OK);
2004+
2005+ ffi_call (&cif, FFI_FN (C_fn), &result, args);
2006+ /* { dg-output "1, 1, 1, 1, 1, 1\n" } */
2007+ /* { dg-output "1.0, 2.0, 4.0, 8.0, 1.0, 2.0, 4.0, 8.0" } */
2008+ CHECK (result.a.a_x == source.a.a_x);
2009+ CHECK (result.a.a_y == source.a.a_y);
2010+ CHECK (result.b.b_x == source.b.b_x);
2011+ CHECK (result.b.b_y == source.b.b_y);
2012+ exit (0);
2013+}
2014diff --git a/testsuite/libffi.call/uninitialized.c b/testsuite/libffi.call/uninitialized.c
2015new file mode 100644
2016index 0000000..f00d830
2017--- /dev/null
2018+++ b/testsuite/libffi.call/uninitialized.c
2019@@ -0,0 +1,61 @@
2020+/* { dg-do run } */
2021+#include "ffitest.h"
2022+
2023+typedef struct
2024+{
2025+ unsigned char uc;
2026+ double d;
2027+ unsigned int ui;
2028+} test_structure_1;
2029+
2030+static test_structure_1 struct1(test_structure_1 ts)
2031+{
2032+ ts.uc++;
2033+ ts.d--;
2034+ ts.ui++;
2035+
2036+ return ts;
2037+}
2038+
2039+int main (void)
2040+{
2041+ ffi_cif cif;
2042+ ffi_type *args[MAX_ARGS];
2043+ void *values[MAX_ARGS];
2044+ ffi_type ts1_type;
2045+ ffi_type *ts1_type_elements[4];
2046+
2047+ memset(&cif, 1, sizeof(cif));
2048+ ts1_type.size = 0;
2049+ ts1_type.alignment = 0;
2050+ ts1_type.type = FFI_TYPE_STRUCT;
2051+ ts1_type.elements = ts1_type_elements;
2052+ ts1_type_elements[0] = &ffi_type_uchar;
2053+ ts1_type_elements[1] = &ffi_type_double;
2054+ ts1_type_elements[2] = &ffi_type_uint;
2055+ ts1_type_elements[3] = NULL;
2056+
2057+ test_structure_1 ts1_arg;
2058+ /* This is a hack to get a properly aligned result buffer */
2059+ test_structure_1 *ts1_result =
2060+ (test_structure_1 *) malloc (sizeof(test_structure_1));
2061+
2062+ args[0] = &ts1_type;
2063+ values[0] = &ts1_arg;
2064+
2065+ /* Initialize the cif */
2066+ CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
2067+ &ts1_type, args) == FFI_OK);
2068+
2069+ ts1_arg.uc = '\x01';
2070+ ts1_arg.d = 3.14159;
2071+ ts1_arg.ui = 555;
2072+
2073+ ffi_call(&cif, FFI_FN(struct1), ts1_result, values);
2074+
2075+ CHECK(ts1_result->ui == 556);
2076+ CHECK(ts1_result->d == 3.14159 - 1);
2077+
2078+ free (ts1_result);
2079+ exit(0);
2080+}
2081diff --git a/testsuite/libffi.call/va_1.c b/testsuite/libffi.call/va_1.c
2082new file mode 100644
2083index 0000000..5c7cce9
2084--- /dev/null
2085+++ b/testsuite/libffi.call/va_1.c
2086@@ -0,0 +1,196 @@
2087+/* Area: ffi_call
2088+ Purpose: Test passing struct in variable argument lists.
2089+ Limitations: none.
2090+ PR: none.
2091+ Originator: ARM Ltd. */
2092+
2093+/* { dg-do run } */
2094+/* { dg-output "" { xfail avr32*-*-* x86_64-*-*-* } } */
2095+
2096+#include "ffitest.h"
2097+#include <stdarg.h>
2098+
2099+struct small_tag
2100+{
2101+ unsigned char a;
2102+ unsigned char b;
2103+};
2104+
2105+struct large_tag
2106+{
2107+ unsigned a;
2108+ unsigned b;
2109+ unsigned c;
2110+ unsigned d;
2111+ unsigned e;
2112+};
2113+
2114+static int
2115+test_fn (int n, ...)
2116+{
2117+ va_list ap;
2118+ struct small_tag s1;
2119+ struct small_tag s2;
2120+ struct large_tag l;
2121+ unsigned char uc;
2122+ signed char sc;
2123+ unsigned short us;
2124+ signed short ss;
2125+ unsigned int ui;
2126+ signed int si;
2127+ unsigned long ul;
2128+ signed long sl;
2129+ float f;
2130+ double d;
2131+
2132+ va_start (ap, n);
2133+ s1 = va_arg (ap, struct small_tag);
2134+ l = va_arg (ap, struct large_tag);
2135+ s2 = va_arg (ap, struct small_tag);
2136+
2137+ uc = va_arg (ap, unsigned);
2138+ sc = va_arg (ap, signed);
2139+
2140+ us = va_arg (ap, unsigned);
2141+ ss = va_arg (ap, signed);
2142+
2143+ ui = va_arg (ap, unsigned int);
2144+ si = va_arg (ap, signed int);
2145+
2146+ ul = va_arg (ap, unsigned long);
2147+ sl = va_arg (ap, signed long);
2148+
2149+ f = va_arg (ap, double); /* C standard promotes float->double
2150+ when anonymous */
2151+ d = va_arg (ap, double);
2152+
2153+ printf ("%u %u %u %u %u %u %u %u %u uc=%u sc=%d %u %d %u %d %lu %ld %f %f\n",
2154+ s1.a, s1.b, l.a, l.b, l.c, l.d, l.e,
2155+ s2.a, s2.b,
2156+ uc, sc,
2157+ us, ss,
2158+ ui, si,
2159+ ul, sl,
2160+ f, d);
2161+ va_end (ap);
2162+ return n + 1;
2163+}
2164+
2165+int
2166+main (void)
2167+{
2168+ ffi_cif cif;
2169+ void* args[15];
2170+ ffi_type* arg_types[15];
2171+
2172+ ffi_type s_type;
2173+ ffi_type *s_type_elements[3];
2174+
2175+ ffi_type l_type;
2176+ ffi_type *l_type_elements[6];
2177+
2178+ struct small_tag s1;
2179+ struct small_tag s2;
2180+ struct large_tag l1;
2181+
2182+ int n;
2183+ int res;
2184+
2185+ unsigned char uc;
2186+ signed char sc;
2187+ unsigned short us;
2188+ signed short ss;
2189+ unsigned int ui;
2190+ signed int si;
2191+ unsigned long ul;
2192+ signed long sl;
2193+ double d1;
2194+ double f1;
2195+
2196+ s_type.size = 0;
2197+ s_type.alignment = 0;
2198+ s_type.type = FFI_TYPE_STRUCT;
2199+ s_type.elements = s_type_elements;
2200+
2201+ s_type_elements[0] = &ffi_type_uchar;
2202+ s_type_elements[1] = &ffi_type_uchar;
2203+ s_type_elements[2] = NULL;
2204+
2205+ l_type.size = 0;
2206+ l_type.alignment = 0;
2207+ l_type.type = FFI_TYPE_STRUCT;
2208+ l_type.elements = l_type_elements;
2209+
2210+ l_type_elements[0] = &ffi_type_uint;
2211+ l_type_elements[1] = &ffi_type_uint;
2212+ l_type_elements[2] = &ffi_type_uint;
2213+ l_type_elements[3] = &ffi_type_uint;
2214+ l_type_elements[4] = &ffi_type_uint;
2215+ l_type_elements[5] = NULL;
2216+
2217+ arg_types[0] = &ffi_type_sint;
2218+ arg_types[1] = &s_type;
2219+ arg_types[2] = &l_type;
2220+ arg_types[3] = &s_type;
2221+ arg_types[4] = &ffi_type_uint;
2222+ arg_types[5] = &ffi_type_sint;
2223+ arg_types[6] = &ffi_type_uint;
2224+ arg_types[7] = &ffi_type_sint;
2225+ arg_types[8] = &ffi_type_uint;
2226+ arg_types[9] = &ffi_type_sint;
2227+ arg_types[10] = &ffi_type_ulong;
2228+ arg_types[11] = &ffi_type_slong;
2229+ arg_types[12] = &ffi_type_double;
2230+ arg_types[13] = &ffi_type_double;
2231+ arg_types[14] = NULL;
2232+
2233+ CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 1, 14, &ffi_type_sint, arg_types) == FFI_OK);
2234+
2235+ s1.a = 5;
2236+ s1.b = 6;
2237+
2238+ l1.a = 10;
2239+ l1.b = 11;
2240+ l1.c = 12;
2241+ l1.d = 13;
2242+ l1.e = 14;
2243+
2244+ s2.a = 7;
2245+ s2.b = 8;
2246+
2247+ n = 41;
2248+
2249+ uc = 9;
2250+ sc = 10;
2251+ us = 11;
2252+ ss = 12;
2253+ ui = 13;
2254+ si = 14;
2255+ ul = 15;
2256+ sl = 16;
2257+ f1 = 2.12;
2258+ d1 = 3.13;
2259+
2260+ args[0] = &n;
2261+ args[1] = &s1;
2262+ args[2] = &l1;
2263+ args[3] = &s2;
2264+ args[4] = &uc;
2265+ args[5] = &sc;
2266+ args[6] = &us;
2267+ args[7] = &ss;
2268+ args[8] = &ui;
2269+ args[9] = &si;
2270+ args[10] = &ul;
2271+ args[11] = &sl;
2272+ args[12] = &f1;
2273+ args[13] = &d1;
2274+ args[14] = NULL;
2275+
2276+ ffi_call(&cif, FFI_FN(test_fn), &res, args);
2277+ /* { dg-output "5 6 10 11 12 13 14 7 8 uc=9 sc=10 11 12 13 14 15 16 2.120000 3.130000" } */
2278+ printf("res: %d\n", (int) res);
2279+ /* { dg-output "\nres: 42" } */
2280+
2281+ return 0;
2282+}
2283diff --git a/testsuite/libffi.call/va_struct1.c b/testsuite/libffi.call/va_struct1.c
2284new file mode 100644
2285index 0000000..11d1f10
2286--- /dev/null
2287+++ b/testsuite/libffi.call/va_struct1.c
2288@@ -0,0 +1,121 @@
2289+/* Area: ffi_call
2290+ Purpose: Test passing struct in variable argument lists.
2291+ Limitations: none.
2292+ PR: none.
2293+ Originator: ARM Ltd. */
2294+
2295+/* { dg-do run } */
2296+/* { dg-output "" { xfail avr32*-*-* } } */
2297+
2298+#include "ffitest.h"
2299+#include <stdarg.h>
2300+
2301+struct small_tag
2302+{
2303+ unsigned char a;
2304+ unsigned char b;
2305+};
2306+
2307+struct large_tag
2308+{
2309+ unsigned a;
2310+ unsigned b;
2311+ unsigned c;
2312+ unsigned d;
2313+ unsigned e;
2314+};
2315+
2316+static int
2317+test_fn (int n, ...)
2318+{
2319+ va_list ap;
2320+ struct small_tag s1;
2321+ struct small_tag s2;
2322+ struct large_tag l;
2323+
2324+ va_start (ap, n);
2325+ s1 = va_arg (ap, struct small_tag);
2326+ l = va_arg (ap, struct large_tag);
2327+ s2 = va_arg (ap, struct small_tag);
2328+ printf ("%u %u %u %u %u %u %u %u %u\n", s1.a, s1.b, l.a, l.b, l.c, l.d, l.e,
2329+ s2.a, s2.b);
2330+ va_end (ap);
2331+ return n + 1;
2332+}
2333+
2334+int
2335+main (void)
2336+{
2337+ ffi_cif cif;
2338+ void* args[5];
2339+ ffi_type* arg_types[5];
2340+
2341+ ffi_type s_type;
2342+ ffi_type *s_type_elements[3];
2343+
2344+ ffi_type l_type;
2345+ ffi_type *l_type_elements[6];
2346+
2347+ struct small_tag s1;
2348+ struct small_tag s2;
2349+ struct large_tag l1;
2350+
2351+ int n;
2352+ int res;
2353+
2354+ s_type.size = 0;
2355+ s_type.alignment = 0;
2356+ s_type.type = FFI_TYPE_STRUCT;
2357+ s_type.elements = s_type_elements;
2358+
2359+ s_type_elements[0] = &ffi_type_uchar;
2360+ s_type_elements[1] = &ffi_type_uchar;
2361+ s_type_elements[2] = NULL;
2362+
2363+ l_type.size = 0;
2364+ l_type.alignment = 0;
2365+ l_type.type = FFI_TYPE_STRUCT;
2366+ l_type.elements = l_type_elements;
2367+
2368+ l_type_elements[0] = &ffi_type_uint;
2369+ l_type_elements[1] = &ffi_type_uint;
2370+ l_type_elements[2] = &ffi_type_uint;
2371+ l_type_elements[3] = &ffi_type_uint;
2372+ l_type_elements[4] = &ffi_type_uint;
2373+ l_type_elements[5] = NULL;
2374+
2375+ arg_types[0] = &ffi_type_sint;
2376+ arg_types[1] = &s_type;
2377+ arg_types[2] = &l_type;
2378+ arg_types[3] = &s_type;
2379+ arg_types[4] = NULL;
2380+
2381+ CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 1, 4, &ffi_type_sint, arg_types) == FFI_OK);
2382+
2383+ s1.a = 5;
2384+ s1.b = 6;
2385+
2386+ l1.a = 10;
2387+ l1.b = 11;
2388+ l1.c = 12;
2389+ l1.d = 13;
2390+ l1.e = 14;
2391+
2392+ s2.a = 7;
2393+ s2.b = 8;
2394+
2395+ n = 41;
2396+
2397+ args[0] = &n;
2398+ args[1] = &s1;
2399+ args[2] = &l1;
2400+ args[3] = &s2;
2401+ args[4] = NULL;
2402+
2403+ ffi_call(&cif, FFI_FN(test_fn), &res, args);
2404+ /* { dg-output "5 6 10 11 12 13 14 7 8" } */
2405+ printf("res: %d\n", (int) res);
2406+ /* { dg-output "\nres: 42" } */
2407+
2408+ return 0;
2409+}
2410diff --git a/testsuite/libffi.call/va_struct2.c b/testsuite/libffi.call/va_struct2.c
2411new file mode 100644
2412index 0000000..56f5b9c
2413--- /dev/null
2414+++ b/testsuite/libffi.call/va_struct2.c
2415@@ -0,0 +1,123 @@
2416+/* Area: ffi_call
2417+ Purpose: Test passing struct in variable argument lists.
2418+ Limitations: none.
2419+ PR: none.
2420+ Originator: ARM Ltd. */
2421+
2422+/* { dg-do run } */
2423+/* { dg-output "" { xfail avr32*-*-* } } */
2424+
2425+#include "ffitest.h"
2426+#include <stdarg.h>
2427+
2428+struct small_tag
2429+{
2430+ unsigned char a;
2431+ unsigned char b;
2432+};
2433+
2434+struct large_tag
2435+{
2436+ unsigned a;
2437+ unsigned b;
2438+ unsigned c;
2439+ unsigned d;
2440+ unsigned e;
2441+};
2442+
2443+static struct small_tag
2444+test_fn (int n, ...)
2445+{
2446+ va_list ap;
2447+ struct small_tag s1;
2448+ struct small_tag s2;
2449+ struct large_tag l;
2450+
2451+ va_start (ap, n);
2452+ s1 = va_arg (ap, struct small_tag);
2453+ l = va_arg (ap, struct large_tag);
2454+ s2 = va_arg (ap, struct small_tag);
2455+ printf ("%u %u %u %u %u %u %u %u %u\n", s1.a, s1.b, l.a, l.b, l.c, l.d, l.e,
2456+ s2.a, s2.b);
2457+ va_end (ap);
2458+ s1.a += s2.a;
2459+ s1.b += s2.b;
2460+ return s1;
2461+}
2462+
2463+int
2464+main (void)
2465+{
2466+ ffi_cif cif;
2467+ void* args[5];
2468+ ffi_type* arg_types[5];
2469+
2470+ ffi_type s_type;
2471+ ffi_type *s_type_elements[3];
2472+
2473+ ffi_type l_type;
2474+ ffi_type *l_type_elements[6];
2475+
2476+ struct small_tag s1;
2477+ struct small_tag s2;
2478+ struct large_tag l1;
2479+
2480+ int n;
2481+ struct small_tag res;
2482+
2483+ s_type.size = 0;
2484+ s_type.alignment = 0;
2485+ s_type.type = FFI_TYPE_STRUCT;
2486+ s_type.elements = s_type_elements;
2487+
2488+ s_type_elements[0] = &ffi_type_uchar;
2489+ s_type_elements[1] = &ffi_type_uchar;
2490+ s_type_elements[2] = NULL;
2491+
2492+ l_type.size = 0;
2493+ l_type.alignment = 0;
2494+ l_type.type = FFI_TYPE_STRUCT;
2495+ l_type.elements = l_type_elements;
2496+
2497+ l_type_elements[0] = &ffi_type_uint;
2498+ l_type_elements[1] = &ffi_type_uint;
2499+ l_type_elements[2] = &ffi_type_uint;
2500+ l_type_elements[3] = &ffi_type_uint;
2501+ l_type_elements[4] = &ffi_type_uint;
2502+ l_type_elements[5] = NULL;
2503+
2504+ arg_types[0] = &ffi_type_sint;
2505+ arg_types[1] = &s_type;
2506+ arg_types[2] = &l_type;
2507+ arg_types[3] = &s_type;
2508+ arg_types[4] = NULL;
2509+
2510+ CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 1, 4, &s_type, arg_types) == FFI_OK);
2511+
2512+ s1.a = 5;
2513+ s1.b = 6;
2514+
2515+ l1.a = 10;
2516+ l1.b = 11;
2517+ l1.c = 12;
2518+ l1.d = 13;
2519+ l1.e = 14;
2520+
2521+ s2.a = 7;
2522+ s2.b = 8;
2523+
2524+ n = 41;
2525+
2526+ args[0] = &n;
2527+ args[1] = &s1;
2528+ args[2] = &l1;
2529+ args[3] = &s2;
2530+ args[4] = NULL;
2531+
2532+ ffi_call(&cif, FFI_FN(test_fn), &res, args);
2533+ /* { dg-output "5 6 10 11 12 13 14 7 8" } */
2534+ printf("res: %d %d\n", res.a, res.b);
2535+ /* { dg-output "\nres: 12 14" } */
2536+
2537+ return 0;
2538+}
2539diff --git a/testsuite/libffi.call/va_struct3.c b/testsuite/libffi.call/va_struct3.c
2540new file mode 100644
2541index 0000000..9a27e7f
2542--- /dev/null
2543+++ b/testsuite/libffi.call/va_struct3.c
2544@@ -0,0 +1,125 @@
2545+/* Area: ffi_call
2546+ Purpose: Test passing struct in variable argument lists.
2547+ Limitations: none.
2548+ PR: none.
2549+ Originator: ARM Ltd. */
2550+
2551+/* { dg-do run } */
2552+/* { dg-output "" { xfail avr32*-*-* } } */
2553+
2554+#include "ffitest.h"
2555+#include <stdarg.h>
2556+
2557+struct small_tag
2558+{
2559+ unsigned char a;
2560+ unsigned char b;
2561+};
2562+
2563+struct large_tag
2564+{
2565+ unsigned a;
2566+ unsigned b;
2567+ unsigned c;
2568+ unsigned d;
2569+ unsigned e;
2570+};
2571+
2572+static struct large_tag
2573+test_fn (int n, ...)
2574+{
2575+ va_list ap;
2576+ struct small_tag s1;
2577+ struct small_tag s2;
2578+ struct large_tag l;
2579+
2580+ va_start (ap, n);
2581+ s1 = va_arg (ap, struct small_tag);
2582+ l = va_arg (ap, struct large_tag);
2583+ s2 = va_arg (ap, struct small_tag);
2584+ printf ("%u %u %u %u %u %u %u %u %u\n", s1.a, s1.b, l.a, l.b, l.c, l.d, l.e,
2585+ s2.a, s2.b);
2586+ va_end (ap);
2587+ l.a += s1.a;
2588+ l.b += s1.b;
2589+ l.c += s2.a;
2590+ l.d += s2.b;
2591+ return l;
2592+}
2593+
2594+int
2595+main (void)
2596+{
2597+ ffi_cif cif;
2598+ void* args[5];
2599+ ffi_type* arg_types[5];
2600+
2601+ ffi_type s_type;
2602+ ffi_type *s_type_elements[3];
2603+
2604+ ffi_type l_type;
2605+ ffi_type *l_type_elements[6];
2606+
2607+ struct small_tag s1;
2608+ struct small_tag s2;
2609+ struct large_tag l1;
2610+
2611+ int n;
2612+ struct large_tag res;
2613+
2614+ s_type.size = 0;
2615+ s_type.alignment = 0;
2616+ s_type.type = FFI_TYPE_STRUCT;
2617+ s_type.elements = s_type_elements;
2618+
2619+ s_type_elements[0] = &ffi_type_uchar;
2620+ s_type_elements[1] = &ffi_type_uchar;
2621+ s_type_elements[2] = NULL;
2622+
2623+ l_type.size = 0;
2624+ l_type.alignment = 0;
2625+ l_type.type = FFI_TYPE_STRUCT;
2626+ l_type.elements = l_type_elements;
2627+
2628+ l_type_elements[0] = &ffi_type_uint;
2629+ l_type_elements[1] = &ffi_type_uint;
2630+ l_type_elements[2] = &ffi_type_uint;
2631+ l_type_elements[3] = &ffi_type_uint;
2632+ l_type_elements[4] = &ffi_type_uint;
2633+ l_type_elements[5] = NULL;
2634+
2635+ arg_types[0] = &ffi_type_sint;
2636+ arg_types[1] = &s_type;
2637+ arg_types[2] = &l_type;
2638+ arg_types[3] = &s_type;
2639+ arg_types[4] = NULL;
2640+
2641+ CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 1, 4, &l_type, arg_types) == FFI_OK);
2642+
2643+ s1.a = 5;
2644+ s1.b = 6;
2645+
2646+ l1.a = 10;
2647+ l1.b = 11;
2648+ l1.c = 12;
2649+ l1.d = 13;
2650+ l1.e = 14;
2651+
2652+ s2.a = 7;
2653+ s2.b = 8;
2654+
2655+ n = 41;
2656+
2657+ args[0] = &n;
2658+ args[1] = &s1;
2659+ args[2] = &l1;
2660+ args[3] = &s2;
2661+ args[4] = NULL;
2662+
2663+ ffi_call(&cif, FFI_FN(test_fn), &res, args);
2664+ /* { dg-output "5 6 10 11 12 13 14 7 8" } */
2665+ printf("res: %d %d %d %d %d\n", res.a, res.b, res.c, res.d, res.e);
2666+ /* { dg-output "\nres: 15 17 19 21 14" } */
2667+
2668+ return 0;
2669+}
2670--
26711.7.10.4
2672
diff --git a/meta/recipes-gnome/libffi/libffi_3.0.11.bb b/meta/recipes-gnome/libffi/libffi_3.0.11.bb
index e674fd3c25..f2a8cc8234 100644
--- a/meta/recipes-gnome/libffi/libffi_3.0.11.bb
+++ b/meta/recipes-gnome/libffi/libffi_3.0.11.bb
@@ -9,10 +9,13 @@ A layer must exist above `libffi' that handles type conversions for values passe
9LICENSE = "MIT" 9LICENSE = "MIT"
10LIC_FILES_CHKSUM = "file://LICENSE;md5=e54c573c49435ccbbd3f6dc9e49a065e" 10LIC_FILES_CHKSUM = "file://LICENSE;md5=e54c573c49435ccbbd3f6dc9e49a065e"
11 11
12PR = "r0" 12PR = "r1"
13 13
14SRC_URI = "ftp://sourceware.org/pub/libffi/${BPN}-${PV}.tar.gz \ 14SRC_URI = "ftp://sourceware.org/pub/libffi/${BPN}-${PV}.tar.gz \
15 file://0001-libffi-update-for-3.0.11.patch" 15 file://0001-libffi-update-for-3.0.11.patch \
16 file://add-aarch64-support.patch \
17 file://aarch64-adding-build-support.patch \
18"
16 19
17SRC_URI[md5sum] = "f69b9693227d976835b4857b1ba7d0e3" 20SRC_URI[md5sum] = "f69b9693227d976835b4857b1ba7d0e3"
18SRC_URI[sha256sum] = "70bfb01356360089aa97d3e71e3edf05d195599fd822e922e50d46a0055a6283" 21SRC_URI[sha256sum] = "70bfb01356360089aa97d3e71e3edf05d195599fd822e922e50d46a0055a6283"