* [dizzy] [PATCH 1/1] python: Add support for aarch64 for ctypes module
@ 2015-03-04 15:04 Tudor Florea
2015-03-04 20:25 ` Burton, Ross
2015-03-10 0:24 ` Tudor Florea
0 siblings, 2 replies; 5+ messages in thread
From: Tudor Florea @ 2015-03-04 15:04 UTC (permalink / raw)
To: openembedded-core
Python have its own version of libffi used for ctypes module.
libffi 3.0.10 contained in original source of Python-2.7.3 does not have
support for aarch64 architecture.
This is patch is backport support for aarch64 from libffi 3.1
---
.../python/python/ctypes-libffi-aarch64.patch | 22 +
.../python/python/libffi-aarch64.patch | 1608 ++++++++++++++++++++
meta/recipes-devtools/python/python_2.7.3.bb | 2 +
3 files changed, 1632 insertions(+)
create mode 100644 meta/recipes-devtools/python/python/ctypes-libffi-aarch64.patch
create mode 100644 meta/recipes-devtools/python/python/libffi-aarch64.patch
diff --git a/meta/recipes-devtools/python/python/ctypes-libffi-aarch64.patch b/meta/recipes-devtools/python/python/ctypes-libffi-aarch64.patch
new file mode 100644
index 0000000..7349c7b
--- /dev/null
+++ b/meta/recipes-devtools/python/python/ctypes-libffi-aarch64.patch
@@ -0,0 +1,22 @@
+Add missing fficonfig.py bits for aarch64
+
+# HG changeset patch
+# User Andreas Schwab <schwab@suse.de>
+# Date 1367276434 -7200
+# Node ID 05e8999a3901b4853e60d6701510e9b3dd54a7f3
+# Parent 84cef4f1999ad9e362694cdac2f65f0981e3d5d0
+
+Upstream-Status: Backport
+Signed-off-by: Tudor Florea <tudor.florea@enea.com>
+
+diff -r 84cef4f1999a -r 05e8999a3901 Modules/_ctypes/libffi/fficonfig.py.in
+--- a/Modules/_ctypes/libffi/fficonfig.py.in Mon Apr 29 16:09:39 2013 -0400
++++ b/Modules/_ctypes/libffi/fficonfig.py.in Tue Apr 30 01:00:34 2013 +0200
+@@ -28,6 +28,7 @@
+ 'PA': ['src/pa/linux.S', 'src/pa/ffi.c'],
+ 'PA_LINUX': ['src/pa/linux.S', 'src/pa/ffi.c'],
+ 'PA_HPUX': ['src/pa/hpux32.S', 'src/pa/ffi.c'],
++ 'AARCH64' : ['src/aarch64/ffi.c', 'src/aarch64/sysv.S'],
+ }
+
+ ffi_sources += ffi_platforms['@TARGET@']
diff --git a/meta/recipes-devtools/python/python/libffi-aarch64.patch b/meta/recipes-devtools/python/python/libffi-aarch64.patch
new file mode 100644
index 0000000..5581922
--- /dev/null
+++ b/meta/recipes-devtools/python/python/libffi-aarch64.patch
@@ -0,0 +1,1608 @@
+Add support for aarch64 for ctypes module
+
+Python have its own version of libffi used for ctypes module.
+libffi 3.0.10 contained in original source of Python-2.7.3 does not have
+support for aarch64 architecture.
+This is patch is backport support for aarch64 from libffi 3.1
+
+Upstream-Status: Backport
+Signed-off-by: Tudor Florea <tudor.florea@enea.com>
+
+diff -ruN Python-2.7.3.orig/Modules/_ctypes/libffi/configure.ac Python-2.7.3/Modules/_ctypes/libffi/configure.ac
+--- Python-2.7.3.orig/Modules/_ctypes/libffi/configure.ac 2015-02-27 23:15:16.118393178 +0100
++++ Python-2.7.3/Modules/_ctypes/libffi/configure.ac 2015-02-27 23:51:03.351556903 +0100
+@@ -44,6 +44,10 @@
+
+ TARGETDIR="unknown"
+ case "$host" in
++ aarch64*-*-*)
++ TARGET=AARCH64; TARGETDIR=aarch64
++ ;;
++
+ alpha*-*-*)
+ TARGET=ALPHA; TARGETDIR=alpha;
+ # Support 128-bit long double, changeable via command-line switch.
+@@ -195,6 +199,7 @@
+ AM_CONDITIONAL(POWERPC_AIX, test x$TARGET = xPOWERPC_AIX)
+ AM_CONDITIONAL(POWERPC_DARWIN, test x$TARGET = xPOWERPC_DARWIN)
+ AM_CONDITIONAL(POWERPC_FREEBSD, test x$TARGET = xPOWERPC_FREEBSD)
++AM_CONDITIONAL(AARCH64, test x$TARGET = xAARCH64)
+ AM_CONDITIONAL(ARM, test x$TARGET = xARM)
+ AM_CONDITIONAL(AVR32, test x$TARGET = xAVR32)
+ AM_CONDITIONAL(LIBFFI_CRIS, test x$TARGET = xLIBFFI_CRIS)
+diff -ruN Python-2.7.3.orig/Modules/_ctypes/libffi/src/aarch64/ffi.c Python-2.7.3/Modules/_ctypes/libffi/src/aarch64/ffi.c
+--- Python-2.7.3.orig/Modules/_ctypes/libffi/src/aarch64/ffi.c 1970-01-01 01:00:00.000000000 +0100
++++ Python-2.7.3/Modules/_ctypes/libffi/src/aarch64/ffi.c 2014-04-25 19:45:13.000000000 +0200
+@@ -0,0 +1,1168 @@
++/* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd.
++
++Permission is hereby granted, free of charge, to any person obtaining
++a copy of this software and associated documentation files (the
++``Software''), to deal in the Software without restriction, including
++without limitation the rights to use, copy, modify, merge, publish,
++distribute, sublicense, and/or sell copies of the Software, and to
++permit persons to whom the Software is furnished to do so, subject to
++the following conditions:
++
++The above copyright notice and this permission notice shall be
++included in all copies or substantial portions of the Software.
++
++THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
++IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
++CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
++TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
++SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
++
++#include <stdio.h>
++
++#include <ffi.h>
++#include <ffi_common.h>
++
++#include <stdlib.h>
++
++/* Stack alignment requirement in bytes */
++#if defined (__APPLE__)
++#define AARCH64_STACK_ALIGN 1
++#else
++#define AARCH64_STACK_ALIGN 16
++#endif
++
++#define N_X_ARG_REG 8
++#define N_V_ARG_REG 8
++
++#define AARCH64_FFI_WITH_V (1 << AARCH64_FFI_WITH_V_BIT)
++
++union _d
++{
++ UINT64 d;
++ UINT32 s[2];
++};
++
++struct call_context
++{
++ UINT64 x [AARCH64_N_XREG];
++ struct
++ {
++ union _d d[2];
++ } v [AARCH64_N_VREG];
++};
++
++#if defined (__clang__) && defined (__APPLE__)
++extern void
++sys_icache_invalidate (void *start, size_t len);
++#endif
++
++static inline void
++ffi_clear_cache (void *start, void *end)
++{
++#if defined (__clang__) && defined (__APPLE__)
++ sys_icache_invalidate (start, (char *)end - (char *)start);
++#elif defined (__GNUC__)
++ __builtin___clear_cache (start, end);
++#else
++#error "Missing builtin to flush instruction cache"
++#endif
++}
++
++static void *
++get_x_addr (struct call_context *context, unsigned n)
++{
++ return &context->x[n];
++}
++
++static void *
++get_s_addr (struct call_context *context, unsigned n)
++{
++#if defined __AARCH64EB__
++ return &context->v[n].d[1].s[1];
++#else
++ return &context->v[n].d[0].s[0];
++#endif
++}
++
++static void *
++get_d_addr (struct call_context *context, unsigned n)
++{
++#if defined __AARCH64EB__
++ return &context->v[n].d[1];
++#else
++ return &context->v[n].d[0];
++#endif
++}
++
++static void *
++get_v_addr (struct call_context *context, unsigned n)
++{
++ return &context->v[n];
++}
++
++/* Return the memory location at which a basic type would reside
++ were it to have been stored in register n. */
++
++static void *
++get_basic_type_addr (unsigned short type, struct call_context *context,
++ unsigned n)
++{
++ switch (type)
++ {
++ case FFI_TYPE_FLOAT:
++ return get_s_addr (context, n);
++ case FFI_TYPE_DOUBLE:
++ return get_d_addr (context, n);
++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
++ case FFI_TYPE_LONGDOUBLE:
++ return get_v_addr (context, n);
++#endif
++ case FFI_TYPE_UINT8:
++ case FFI_TYPE_SINT8:
++ case FFI_TYPE_UINT16:
++ case FFI_TYPE_SINT16:
++ case FFI_TYPE_UINT32:
++ case FFI_TYPE_SINT32:
++ case FFI_TYPE_INT:
++ case FFI_TYPE_POINTER:
++ case FFI_TYPE_UINT64:
++ case FFI_TYPE_SINT64:
++ return get_x_addr (context, n);
++ case FFI_TYPE_VOID:
++ return NULL;
++ default:
++ FFI_ASSERT (0);
++ return NULL;
++ }
++}
++
++/* Return the alignment width for each of the basic types. */
++
++static size_t
++get_basic_type_alignment (unsigned short type)
++{
++ switch (type)
++ {
++ case FFI_TYPE_FLOAT:
++ case FFI_TYPE_DOUBLE:
++ return sizeof (UINT64);
++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
++ case FFI_TYPE_LONGDOUBLE:
++ return sizeof (long double);
++#endif
++ case FFI_TYPE_UINT8:
++ case FFI_TYPE_SINT8:
++#if defined (__APPLE__)
++ return sizeof (UINT8);
++#endif
++ case FFI_TYPE_UINT16:
++ case FFI_TYPE_SINT16:
++#if defined (__APPLE__)
++ return sizeof (UINT16);
++#endif
++ case FFI_TYPE_UINT32:
++ case FFI_TYPE_INT:
++ case FFI_TYPE_SINT32:
++#if defined (__APPLE__)
++ return sizeof (UINT32);
++#endif
++ case FFI_TYPE_POINTER:
++ case FFI_TYPE_UINT64:
++ case FFI_TYPE_SINT64:
++ return sizeof (UINT64);
++
++ default:
++ FFI_ASSERT (0);
++ return 0;
++ }
++}
++
++/* Return the size in bytes for each of the basic types. */
++
++static size_t
++get_basic_type_size (unsigned short type)
++{
++ switch (type)
++ {
++ case FFI_TYPE_FLOAT:
++ return sizeof (UINT32);
++ case FFI_TYPE_DOUBLE:
++ return sizeof (UINT64);
++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
++ case FFI_TYPE_LONGDOUBLE:
++ return sizeof (long double);
++#endif
++ case FFI_TYPE_UINT8:
++ return sizeof (UINT8);
++ case FFI_TYPE_SINT8:
++ return sizeof (SINT8);
++ case FFI_TYPE_UINT16:
++ return sizeof (UINT16);
++ case FFI_TYPE_SINT16:
++ return sizeof (SINT16);
++ case FFI_TYPE_UINT32:
++ return sizeof (UINT32);
++ case FFI_TYPE_INT:
++ case FFI_TYPE_SINT32:
++ return sizeof (SINT32);
++ case FFI_TYPE_POINTER:
++ case FFI_TYPE_UINT64:
++ return sizeof (UINT64);
++ case FFI_TYPE_SINT64:
++ return sizeof (SINT64);
++
++ default:
++ FFI_ASSERT (0);
++ return 0;
++ }
++}
++
++extern void
++ffi_call_SYSV (unsigned (*)(struct call_context *context, unsigned char *,
++ extended_cif *),
++ struct call_context *context,
++ extended_cif *,
++ size_t,
++ void (*fn)(void));
++
++extern void
++ffi_closure_SYSV (ffi_closure *);
++
++/* Test for an FFI floating point representation. */
++
++static unsigned
++is_floating_type (unsigned short type)
++{
++ return (type == FFI_TYPE_FLOAT || type == FFI_TYPE_DOUBLE
++ || type == FFI_TYPE_LONGDOUBLE);
++}
++
++/* Test for a homogeneous structure. */
++
++static unsigned short
++get_homogeneous_type (ffi_type *ty)
++{
++ if (ty->type == FFI_TYPE_STRUCT && ty->elements)
++ {
++ unsigned i;
++ unsigned short candidate_type
++ = get_homogeneous_type (ty->elements[0]);
++ for (i =1; ty->elements[i]; i++)
++ {
++ unsigned short iteration_type = 0;
++ /* If we have a nested struct, we must find its homogeneous type.
++ If that fits with our candidate type, we are still
++ homogeneous. */
++ if (ty->elements[i]->type == FFI_TYPE_STRUCT
++ && ty->elements[i]->elements)
++ {
++ iteration_type = get_homogeneous_type (ty->elements[i]);
++ }
++ else
++ {
++ iteration_type = ty->elements[i]->type;
++ }
++
++ /* If we are not homogeneous, return FFI_TYPE_STRUCT. */
++ if (candidate_type != iteration_type)
++ return FFI_TYPE_STRUCT;
++ }
++ return candidate_type;
++ }
++
++ /* Base case, we have no more levels of nesting, so we
++ are a basic type, and so, trivially homogeneous in that type. */
++ return ty->type;
++}
++
++/* Determine the number of elements within a STRUCT.
++
++ Note, we must handle nested structs.
++
++ If ty is not a STRUCT this function will return 0. */
++
++static unsigned
++element_count (ffi_type *ty)
++{
++ if (ty->type == FFI_TYPE_STRUCT && ty->elements)
++ {
++ unsigned n;
++ unsigned elems = 0;
++ for (n = 0; ty->elements[n]; n++)
++ {
++ if (ty->elements[n]->type == FFI_TYPE_STRUCT
++ && ty->elements[n]->elements)
++ elems += element_count (ty->elements[n]);
++ else
++ elems++;
++ }
++ return elems;
++ }
++ return 0;
++}
++
++/* Test for a homogeneous floating point aggregate.
++
++ A homogeneous floating point aggregate is a homogeneous aggregate of
++ a half- single- or double- precision floating point type with one
++ to four elements. Note that this includes nested structs of the
++ basic type. */
++
++static int
++is_hfa (ffi_type *ty)
++{
++ if (ty->type == FFI_TYPE_STRUCT
++ && ty->elements[0]
++ && is_floating_type (get_homogeneous_type (ty)))
++ {
++ unsigned n = element_count (ty);
++ return n >= 1 && n <= 4;
++ }
++ return 0;
++}
++
++/* Test if an ffi_type is a candidate for passing in a register.
++
++ This test does not check that sufficient registers of the
++ appropriate class are actually available, merely that IFF
++ sufficient registers are available then the argument will be passed
++ in register(s).
++
++ Note that an ffi_type that is deemed to be a register candidate
++ will always be returned in registers.
++
++ Returns 1 if a register candidate else 0. */
++
++static int
++is_register_candidate (ffi_type *ty)
++{
++ switch (ty->type)
++ {
++ case FFI_TYPE_VOID:
++ case FFI_TYPE_FLOAT:
++ case FFI_TYPE_DOUBLE:
++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
++ case FFI_TYPE_LONGDOUBLE:
++#endif
++ case FFI_TYPE_UINT8:
++ case FFI_TYPE_UINT16:
++ case FFI_TYPE_UINT32:
++ case FFI_TYPE_UINT64:
++ case FFI_TYPE_POINTER:
++ case FFI_TYPE_SINT8:
++ case FFI_TYPE_SINT16:
++ case FFI_TYPE_SINT32:
++ case FFI_TYPE_INT:
++ case FFI_TYPE_SINT64:
++ return 1;
++
++ case FFI_TYPE_STRUCT:
++ if (is_hfa (ty))
++ {
++ return 1;
++ }
++ else if (ty->size > 16)
++ {
++ /* Too large. Will be replaced with a pointer to memory. The
++ pointer MAY be passed in a register, but the value will
++ not. This test specifically fails since the argument will
++ never be passed by value in registers. */
++ return 0;
++ }
++ else
++ {
++ /* Might be passed in registers depending on the number of
++ registers required. */
++ return (ty->size + 7) / 8 < N_X_ARG_REG;
++ }
++ break;
++
++ default:
++ FFI_ASSERT (0);
++ break;
++ }
++
++ return 0;
++}
++
++/* Test if an ffi_type argument or result is a candidate for a vector
++ register. */
++
++static int
++is_v_register_candidate (ffi_type *ty)
++{
++ return is_floating_type (ty->type)
++ || (ty->type == FFI_TYPE_STRUCT && is_hfa (ty));
++}
++
++/* Representation of the procedure call argument marshalling
++ state.
++
++ The terse state variable names match the names used in the AARCH64
++ PCS. */
++
++struct arg_state
++{
++ unsigned ngrn; /* Next general-purpose register number. */
++ unsigned nsrn; /* Next vector register number. */
++ size_t nsaa; /* Next stack offset. */
++
++#if defined (__APPLE__)
++ unsigned allocating_variadic;
++#endif
++};
++
++/* Initialize a procedure call argument marshalling state. */
++static void
++arg_init (struct arg_state *state, size_t call_frame_size)
++{
++ state->ngrn = 0;
++ state->nsrn = 0;
++ state->nsaa = 0;
++
++#if defined (__APPLE__)
++ state->allocating_variadic = 0;
++#endif
++}
++
++/* Return the number of available consecutive core argument
++ registers. */
++
++static unsigned
++available_x (struct arg_state *state)
++{
++ return N_X_ARG_REG - state->ngrn;
++}
++
++/* Return the number of available consecutive vector argument
++ registers. */
++
++static unsigned
++available_v (struct arg_state *state)
++{
++ return N_V_ARG_REG - state->nsrn;
++}
++
++static void *
++allocate_to_x (struct call_context *context, struct arg_state *state)
++{
++ FFI_ASSERT (state->ngrn < N_X_ARG_REG);
++ return get_x_addr (context, (state->ngrn)++);
++}
++
++static void *
++allocate_to_s (struct call_context *context, struct arg_state *state)
++{
++ FFI_ASSERT (state->nsrn < N_V_ARG_REG);
++ return get_s_addr (context, (state->nsrn)++);
++}
++
++static void *
++allocate_to_d (struct call_context *context, struct arg_state *state)
++{
++ FFI_ASSERT (state->nsrn < N_V_ARG_REG);
++ return get_d_addr (context, (state->nsrn)++);
++}
++
++static void *
++allocate_to_v (struct call_context *context, struct arg_state *state)
++{
++ FFI_ASSERT (state->nsrn < N_V_ARG_REG);
++ return get_v_addr (context, (state->nsrn)++);
++}
++
++/* Allocate an aligned slot on the stack and return a pointer to it. */
++static void *
++allocate_to_stack (struct arg_state *state, void *stack, size_t alignment,
++ size_t size)
++{
++ void *allocation;
++
++ /* Round up the NSAA to the larger of 8 or the natural
++ alignment of the argument's type. */
++ state->nsaa = ALIGN (state->nsaa, alignment);
++ state->nsaa = ALIGN (state->nsaa, alignment);
++#if defined (__APPLE__)
++ if (state->allocating_variadic)
++ state->nsaa = ALIGN (state->nsaa, 8);
++#else
++ state->nsaa = ALIGN (state->nsaa, 8);
++#endif
++
++ allocation = stack + state->nsaa;
++
++ state->nsaa += size;
++ return allocation;
++}
++
++static void
++copy_basic_type (void *dest, void *source, unsigned short type)
++{
++ /* This is necessary to ensure that basic types are copied
++ sign extended to 64-bits as libffi expects. */
++ switch (type)
++ {
++ case FFI_TYPE_FLOAT:
++ *(float *) dest = *(float *) source;
++ break;
++ case FFI_TYPE_DOUBLE:
++ *(double *) dest = *(double *) source;
++ break;
++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
++ case FFI_TYPE_LONGDOUBLE:
++ *(long double *) dest = *(long double *) source;
++ break;
++#endif
++ case FFI_TYPE_UINT8:
++ *(ffi_arg *) dest = *(UINT8 *) source;
++ break;
++ case FFI_TYPE_SINT8:
++ *(ffi_sarg *) dest = *(SINT8 *) source;
++ break;
++ case FFI_TYPE_UINT16:
++ *(ffi_arg *) dest = *(UINT16 *) source;
++ break;
++ case FFI_TYPE_SINT16:
++ *(ffi_sarg *) dest = *(SINT16 *) source;
++ break;
++ case FFI_TYPE_UINT32:
++ *(ffi_arg *) dest = *(UINT32 *) source;
++ break;
++ case FFI_TYPE_INT:
++ case FFI_TYPE_SINT32:
++ *(ffi_sarg *) dest = *(SINT32 *) source;
++ break;
++ case FFI_TYPE_POINTER:
++ case FFI_TYPE_UINT64:
++ *(ffi_arg *) dest = *(UINT64 *) source;
++ break;
++ case FFI_TYPE_SINT64:
++ *(ffi_sarg *) dest = *(SINT64 *) source;
++ break;
++ case FFI_TYPE_VOID:
++ break;
++
++ default:
++ FFI_ASSERT (0);
++ }
++}
++
++static void
++copy_hfa_to_reg_or_stack (void *memory,
++ ffi_type *ty,
++ struct call_context *context,
++ unsigned char *stack,
++ struct arg_state *state)
++{
++ unsigned elems = element_count (ty);
++ if (available_v (state) < elems)
++ {
++ /* There are insufficient V registers. Further V register allocations
++ are prevented, the NSAA is adjusted (by allocate_to_stack ())
++ and the argument is copied to memory at the adjusted NSAA. */
++ state->nsrn = N_V_ARG_REG;
++ memcpy (allocate_to_stack (state, stack, ty->alignment, ty->size),
++ memory,
++ ty->size);
++ }
++ else
++ {
++ int i;
++ unsigned short type = get_homogeneous_type (ty);
++ for (i = 0; i < elems; i++)
++ {
++ void *reg = allocate_to_v (context, state);
++ copy_basic_type (reg, memory, type);
++ memory += get_basic_type_size (type);
++ }
++ }
++}
++
++/* Either allocate an appropriate register for the argument type, or if
++ none are available, allocate a stack slot and return a pointer
++ to the allocated space. */
++
++static void *
++allocate_to_register_or_stack (struct call_context *context,
++ unsigned char *stack,
++ struct arg_state *state,
++ unsigned short type)
++{
++ size_t alignment = get_basic_type_alignment (type);
++ size_t size = alignment;
++ switch (type)
++ {
++ case FFI_TYPE_FLOAT:
++ /* This is the only case for which the allocated stack size
++ should not match the alignment of the type. */
++ size = sizeof (UINT32);
++ /* Fall through. */
++ case FFI_TYPE_DOUBLE:
++ if (state->nsrn < N_V_ARG_REG)
++ return allocate_to_d (context, state);
++ state->nsrn = N_V_ARG_REG;
++ break;
++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
++ case FFI_TYPE_LONGDOUBLE:
++ if (state->nsrn < N_V_ARG_REG)
++ return allocate_to_v (context, state);
++ state->nsrn = N_V_ARG_REG;
++ break;
++#endif
++ case FFI_TYPE_UINT8:
++ case FFI_TYPE_SINT8:
++ case FFI_TYPE_UINT16:
++ case FFI_TYPE_SINT16:
++ case FFI_TYPE_UINT32:
++ case FFI_TYPE_SINT32:
++ case FFI_TYPE_INT:
++ case FFI_TYPE_POINTER:
++ case FFI_TYPE_UINT64:
++ case FFI_TYPE_SINT64:
++ if (state->ngrn < N_X_ARG_REG)
++ return allocate_to_x (context, state);
++ state->ngrn = N_X_ARG_REG;
++ break;
++ default:
++ FFI_ASSERT (0);
++ }
++
++ return allocate_to_stack (state, stack, alignment, size);
++}
++
++/* Copy a value to an appropriate register, or if none are
++ available, to the stack. */
++
++static void
++copy_to_register_or_stack (struct call_context *context,
++ unsigned char *stack,
++ struct arg_state *state,
++ void *value,
++ unsigned short type)
++{
++ copy_basic_type (
++ allocate_to_register_or_stack (context, stack, state, type),
++ value,
++ type);
++}
++
++/* Marshall the arguments from FFI representation to procedure call
++ context and stack. */
++
++static unsigned
++aarch64_prep_args (struct call_context *context, unsigned char *stack,
++ extended_cif *ecif)
++{
++ int i;
++ struct arg_state state;
++
++ arg_init (&state, ALIGN(ecif->cif->bytes, 16));
++
++ for (i = 0; i < ecif->cif->nargs; i++)
++ {
++ ffi_type *ty = ecif->cif->arg_types[i];
++ switch (ty->type)
++ {
++ case FFI_TYPE_VOID:
++ FFI_ASSERT (0);
++ break;
++
++ /* If the argument is a basic type the argument is allocated to an
++ appropriate register, or if none are available, to the stack. */
++ case FFI_TYPE_FLOAT:
++ case FFI_TYPE_DOUBLE:
++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
++ case FFI_TYPE_LONGDOUBLE:
++#endif
++ case FFI_TYPE_UINT8:
++ case FFI_TYPE_SINT8:
++ case FFI_TYPE_UINT16:
++ case FFI_TYPE_SINT16:
++ case FFI_TYPE_UINT32:
++ case FFI_TYPE_INT:
++ case FFI_TYPE_SINT32:
++ case FFI_TYPE_POINTER:
++ case FFI_TYPE_UINT64:
++ case FFI_TYPE_SINT64:
++ copy_to_register_or_stack (context, stack, &state,
++ ecif->avalue[i], ty->type);
++ break;
++
++ case FFI_TYPE_STRUCT:
++ if (is_hfa (ty))
++ {
++ copy_hfa_to_reg_or_stack (ecif->avalue[i], ty, context,
++ stack, &state);
++ }
++ else if (ty->size > 16)
++ {
++ /* If the argument is a composite type that is larger than 16
++ bytes, then the argument has been copied to memory, and
++ the argument is replaced by a pointer to the copy. */
++
++ copy_to_register_or_stack (context, stack, &state,
++ &(ecif->avalue[i]), FFI_TYPE_POINTER);
++ }
++ else if (available_x (&state) >= (ty->size + 7) / 8)
++ {
++ /* If the argument is a composite type and the size in
++ double-words is not more than the number of available
++ X registers, then the argument is copied into consecutive
++ X registers. */
++ int j;
++ for (j = 0; j < (ty->size + 7) / 8; j++)
++ {
++ memcpy (allocate_to_x (context, &state),
++ &(((UINT64 *) ecif->avalue[i])[j]),
++ sizeof (UINT64));
++ }
++ }
++ else
++ {
++ /* Otherwise, there are insufficient X registers. Further X
++ register allocations are prevented, the NSAA is adjusted
++ (by allocate_to_stack ()) and the argument is copied to
++ memory at the adjusted NSAA. */
++ state.ngrn = N_X_ARG_REG;
++
++ memcpy (allocate_to_stack (&state, stack, ty->alignment,
++ ty->size), ecif->avalue + i, ty->size);
++ }
++ break;
++
++ default:
++ FFI_ASSERT (0);
++ break;
++ }
++
++#if defined (__APPLE__)
++ if (i + 1 == ecif->cif->aarch64_nfixedargs)
++ {
++ state.ngrn = N_X_ARG_REG;
++ state.nsrn = N_V_ARG_REG;
++
++ state.allocating_variadic = 1;
++ }
++#endif
++ }
++
++ return ecif->cif->aarch64_flags;
++}
++
++ffi_status
++ffi_prep_cif_machdep (ffi_cif *cif)
++{
++ /* Round the stack up to a multiple of the stack alignment requirement. */
++ cif->bytes =
++ (cif->bytes + (AARCH64_STACK_ALIGN - 1)) & ~ (AARCH64_STACK_ALIGN - 1);
++
++ /* Initialize our flags. We are interested if this CIF will touch a
++ vector register, if so we will enable context save and load to
++ those registers, otherwise not. This is intended to be friendly
++ to lazy float context switching in the kernel. */
++ cif->aarch64_flags = 0;
++
++ if (is_v_register_candidate (cif->rtype))
++ {
++ cif->aarch64_flags |= AARCH64_FFI_WITH_V;
++ }
++ else
++ {
++ int i;
++ for (i = 0; i < cif->nargs; i++)
++ if (is_v_register_candidate (cif->arg_types[i]))
++ {
++ cif->aarch64_flags |= AARCH64_FFI_WITH_V;
++ break;
++ }
++ }
++
++ return FFI_OK;
++}
++
++#if defined (__APPLE__)
++
++/* Perform Apple-specific cif processing for variadic calls */
++ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif,
++ unsigned int nfixedargs,
++ unsigned int ntotalargs)
++{
++ cif->aarch64_nfixedargs = nfixedargs;
++
++ return ffi_prep_cif_machdep(cif);
++}
++
++#endif
++
++/* Call a function with the provided arguments and capture the return
++ value. */
++void
++ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
++{
++ extended_cif ecif;
++
++ ecif.cif = cif;
++ ecif.avalue = avalue;
++ ecif.rvalue = rvalue;
++
++ switch (cif->abi)
++ {
++ case FFI_SYSV:
++ {
++ struct call_context context;
++ size_t stack_bytes;
++
++ /* Figure out the total amount of stack space we need, the
++ above call frame space needs to be 16 bytes aligned to
++ ensure correct alignment of the first object inserted in
++ that space hence the ALIGN applied to cif->bytes.*/
++ stack_bytes = ALIGN(cif->bytes, 16);
++
++ memset (&context, 0, sizeof (context));
++ if (is_register_candidate (cif->rtype))
++ {
++ ffi_call_SYSV (aarch64_prep_args, &context, &ecif, stack_bytes, fn);
++ switch (cif->rtype->type)
++ {
++ case FFI_TYPE_VOID:
++ case FFI_TYPE_FLOAT:
++ case FFI_TYPE_DOUBLE:
++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
++ case FFI_TYPE_LONGDOUBLE:
++#endif
++ case FFI_TYPE_UINT8:
++ case FFI_TYPE_SINT8:
++ case FFI_TYPE_UINT16:
++ case FFI_TYPE_SINT16:
++ case FFI_TYPE_UINT32:
++ case FFI_TYPE_SINT32:
++ case FFI_TYPE_POINTER:
++ case FFI_TYPE_UINT64:
++ case FFI_TYPE_INT:
++ case FFI_TYPE_SINT64:
++ {
++ void *addr = get_basic_type_addr (cif->rtype->type,
++ &context, 0);
++ copy_basic_type (rvalue, addr, cif->rtype->type);
++ break;
++ }
++
++ case FFI_TYPE_STRUCT:
++ if (is_hfa (cif->rtype))
++ {
++ int j;
++ unsigned short type = get_homogeneous_type (cif->rtype);
++ unsigned elems = element_count (cif->rtype);
++ for (j = 0; j < elems; j++)
++ {
++ void *reg = get_basic_type_addr (type, &context, j);
++ copy_basic_type (rvalue, reg, type);
++ rvalue += get_basic_type_size (type);
++ }
++ }
++ else if ((cif->rtype->size + 7) / 8 < N_X_ARG_REG)
++ {
++ size_t size = ALIGN (cif->rtype->size, sizeof (UINT64));
++ memcpy (rvalue, get_x_addr (&context, 0), size);
++ }
++ else
++ {
++ FFI_ASSERT (0);
++ }
++ break;
++
++ default:
++ FFI_ASSERT (0);
++ break;
++ }
++ }
++ else
++ {
++ memcpy (get_x_addr (&context, 8), &rvalue, sizeof (UINT64));
++ ffi_call_SYSV (aarch64_prep_args, &context, &ecif,
++ stack_bytes, fn);
++ }
++ break;
++ }
++
++ default:
++ FFI_ASSERT (0);
++ break;
++ }
++}
++
++static unsigned char trampoline [] =
++{ 0x70, 0x00, 0x00, 0x58, /* ldr x16, 1f */
++ 0x91, 0x00, 0x00, 0x10, /* adr x17, 2f */
++ 0x00, 0x02, 0x1f, 0xd6 /* br x16 */
++};
++
++/* Build a trampoline. */
++
++#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX,FLAGS) \
++ ({unsigned char *__tramp = (unsigned char*)(TRAMP); \
++ UINT64 __fun = (UINT64)(FUN); \
++ UINT64 __ctx = (UINT64)(CTX); \
++ UINT64 __flags = (UINT64)(FLAGS); \
++ memcpy (__tramp, trampoline, sizeof (trampoline)); \
++ memcpy (__tramp + 12, &__fun, sizeof (__fun)); \
++ memcpy (__tramp + 20, &__ctx, sizeof (__ctx)); \
++ memcpy (__tramp + 28, &__flags, sizeof (__flags)); \
++ ffi_clear_cache(__tramp, __tramp + FFI_TRAMPOLINE_SIZE); \
++ })
++
++ffi_status
++ffi_prep_closure_loc (ffi_closure* closure,
++ ffi_cif* cif,
++ void (*fun)(ffi_cif*,void*,void**,void*),
++ void *user_data,
++ void *codeloc)
++{
++ if (cif->abi != FFI_SYSV)
++ return FFI_BAD_ABI;
++
++ FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_SYSV, codeloc,
++ cif->aarch64_flags);
++
++ closure->cif = cif;
++ closure->user_data = user_data;
++ closure->fun = fun;
++
++ return FFI_OK;
++}
++
++/* Primary handler to setup and invoke a function within a closure.
++
++ A closure when invoked enters via the assembler wrapper
++ ffi_closure_SYSV(). The wrapper allocates a call context on the
++ stack, saves the interesting registers (from the perspective of
++ the calling convention) into the context then passes control to
++ ffi_closure_SYSV_inner() passing the saved context and a pointer to
++ the stack at the point ffi_closure_SYSV() was invoked.
++
++ On the return path the assembler wrapper will reload call context
++ registers.
++
++ ffi_closure_SYSV_inner() marshalls the call context into ffi value
++ descriptors, invokes the wrapped function, then marshalls the return
++ value back into the call context. */
++
++void FFI_HIDDEN
++ffi_closure_SYSV_inner (ffi_closure *closure, struct call_context *context,
++ void *stack)
++{
++ ffi_cif *cif = closure->cif;
++ void **avalue = (void**) alloca (cif->nargs * sizeof (void*));
++ void *rvalue = NULL;
++ int i;
++ struct arg_state state;
++
++ arg_init (&state, ALIGN(cif->bytes, 16));
++
++ for (i = 0; i < cif->nargs; i++)
++ {
++ ffi_type *ty = cif->arg_types[i];
++
++ switch (ty->type)
++ {
++ case FFI_TYPE_VOID:
++ FFI_ASSERT (0);
++ break;
++
++ case FFI_TYPE_UINT8:
++ case FFI_TYPE_SINT8:
++ case FFI_TYPE_UINT16:
++ case FFI_TYPE_SINT16:
++ case FFI_TYPE_UINT32:
++ case FFI_TYPE_SINT32:
++ case FFI_TYPE_INT:
++ case FFI_TYPE_POINTER:
++ case FFI_TYPE_UINT64:
++ case FFI_TYPE_SINT64:
++ case FFI_TYPE_FLOAT:
++ case FFI_TYPE_DOUBLE:
++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
++ case FFI_TYPE_LONGDOUBLE:
++ avalue[i] = allocate_to_register_or_stack (context, stack,
++ &state, ty->type);
++ break;
++#endif
++
++ case FFI_TYPE_STRUCT:
++ if (is_hfa (ty))
++ {
++ unsigned n = element_count (ty);
++ if (available_v (&state) < n)
++ {
++ state.nsrn = N_V_ARG_REG;
++ avalue[i] = allocate_to_stack (&state, stack, ty->alignment,
++ ty->size);
++ }
++ else
++ {
++ switch (get_homogeneous_type (ty))
++ {
++ case FFI_TYPE_FLOAT:
++ {
++ /* Eeek! We need a pointer to the structure,
++ however the homogeneous float elements are
++ being passed in individual S registers,
++ therefore the structure is not represented as
++ a contiguous sequence of bytes in our saved
++ register context. We need to fake up a copy
++ of the structure laid out in memory
++ correctly. The fake can be tossed once the
++ closure function has returned hence alloca()
++ is sufficient. */
++ int j;
++ UINT32 *p = avalue[i] = alloca (ty->size);
++ for (j = 0; j < element_count (ty); j++)
++ memcpy (&p[j],
++ allocate_to_s (context, &state),
++ sizeof (*p));
++ break;
++ }
++
++ case FFI_TYPE_DOUBLE:
++ {
++ /* Eeek! We need a pointer to the structure,
++ however the homogeneous float elements are
++ being passed in individual S registers,
++ therefore the structure is not represented as
++ a contiguous sequence of bytes in our saved
++ register context. We need to fake up a copy
++ of the structure laid out in memory
++ correctly. The fake can be tossed once the
++ closure function has returned hence alloca()
++ is sufficient. */
++ int j;
++ UINT64 *p = avalue[i] = alloca (ty->size);
++ for (j = 0; j < element_count (ty); j++)
++ memcpy (&p[j],
++ allocate_to_d (context, &state),
++ sizeof (*p));
++ break;
++ }
++
++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
++ case FFI_TYPE_LONGDOUBLE:
++ memcpy (&avalue[i],
++ allocate_to_v (context, &state),
++ sizeof (*avalue));
++ break;
++#endif
++
++ default:
++ FFI_ASSERT (0);
++ break;
++ }
++ }
++ }
++ else if (ty->size > 16)
++ {
++ /* Replace Composite type of size greater than 16 with a
++ pointer. */
++ memcpy (&avalue[i],
++ allocate_to_register_or_stack (context, stack,
++ &state, FFI_TYPE_POINTER),
++ sizeof (avalue[i]));
++ }
++ else if (available_x (&state) >= (ty->size + 7) / 8)
++ {
++ avalue[i] = get_x_addr (context, state.ngrn);
++ state.ngrn += (ty->size + 7) / 8;
++ }
++ else
++ {
++ state.ngrn = N_X_ARG_REG;
++
++ avalue[i] = allocate_to_stack (&state, stack, ty->alignment,
++ ty->size);
++ }
++ break;
++
++ default:
++ FFI_ASSERT (0);
++ break;
++ }
++ }
++
++ /* Figure out where the return value will be passed, either in
++ registers or in a memory block allocated by the caller and passed
++ in x8. */
++
++ if (is_register_candidate (cif->rtype))
++ {
++ /* Register candidates are *always* returned in registers. */
++
++ /* Allocate a scratchpad for the return value, we will let the
++ callee scrible the result into the scratch pad then move the
++ contents into the appropriate return value location for the
++ call convention. */
++ rvalue = alloca (cif->rtype->size);
++ (closure->fun) (cif, rvalue, avalue, closure->user_data);
++
++ /* Copy the return value into the call context so that it is returned
++ as expected to our caller. */
++ switch (cif->rtype->type)
++ {
++ case FFI_TYPE_VOID:
++ break;
++
++ case FFI_TYPE_UINT8:
++ case FFI_TYPE_UINT16:
++ case FFI_TYPE_UINT32:
++ case FFI_TYPE_POINTER:
++ case FFI_TYPE_UINT64:
++ case FFI_TYPE_SINT8:
++ case FFI_TYPE_SINT16:
++ case FFI_TYPE_INT:
++ case FFI_TYPE_SINT32:
++ case FFI_TYPE_SINT64:
++ case FFI_TYPE_FLOAT:
++ case FFI_TYPE_DOUBLE:
++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
++ case FFI_TYPE_LONGDOUBLE:
++#endif
++ {
++ void *addr = get_basic_type_addr (cif->rtype->type, context, 0);
++ copy_basic_type (addr, rvalue, cif->rtype->type);
++ break;
++ }
++ case FFI_TYPE_STRUCT:
++ if (is_hfa (cif->rtype))
++ {
++ int j;
++ unsigned short type = get_homogeneous_type (cif->rtype);
++ unsigned elems = element_count (cif->rtype);
++ for (j = 0; j < elems; j++)
++ {
++ void *reg = get_basic_type_addr (type, context, j);
++ copy_basic_type (reg, rvalue, type);
++ rvalue += get_basic_type_size (type);
++ }
++ }
++ else if ((cif->rtype->size + 7) / 8 < N_X_ARG_REG)
++ {
++ size_t size = ALIGN (cif->rtype->size, sizeof (UINT64)) ;
++ memcpy (get_x_addr (context, 0), rvalue, size);
++ }
++ else
++ {
++ FFI_ASSERT (0);
++ }
++ break;
++ default:
++ FFI_ASSERT (0);
++ break;
++ }
++ }
++ else
++ {
++ memcpy (&rvalue, get_x_addr (context, 8), sizeof (UINT64));
++ (closure->fun) (cif, rvalue, avalue, closure->user_data);
++ }
++}
++
+diff -ruN Python-2.7.3.orig/Modules/_ctypes/libffi/src/aarch64/ffitarget.h Python-2.7.3/Modules/_ctypes/libffi/src/aarch64/ffitarget.h
+--- Python-2.7.3.orig/Modules/_ctypes/libffi/src/aarch64/ffitarget.h 1970-01-01 01:00:00.000000000 +0100
++++ Python-2.7.3/Modules/_ctypes/libffi/src/aarch64/ffitarget.h 2014-04-25 19:45:13.000000000 +0200
+@@ -0,0 +1,63 @@
++/* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd.
++
++Permission is hereby granted, free of charge, to any person obtaining
++a copy of this software and associated documentation files (the
++``Software''), to deal in the Software without restriction, including
++without limitation the rights to use, copy, modify, merge, publish,
++distribute, sublicense, and/or sell copies of the Software, and to
++permit persons to whom the Software is furnished to do so, subject to
++the following conditions:
++
++The above copyright notice and this permission notice shall be
++included in all copies or substantial portions of the Software.
++
++THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
++IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
++CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
++TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
++SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
++
++#ifndef LIBFFI_TARGET_H
++#define LIBFFI_TARGET_H
++
++#ifndef LIBFFI_H
++#error "Please do not include ffitarget.h directly into your source. Use ffi.h instead."
++#endif
++
++#ifndef LIBFFI_ASM
++typedef unsigned long ffi_arg;
++typedef signed long ffi_sarg;
++
++typedef enum ffi_abi
++ {
++ FFI_FIRST_ABI = 0,
++ FFI_SYSV,
++ FFI_LAST_ABI,
++ FFI_DEFAULT_ABI = FFI_SYSV
++ } ffi_abi;
++#endif
++
++/* ---- Definitions for closures ----------------------------------------- */
++
++#define FFI_CLOSURES 1
++#define FFI_TRAMPOLINE_SIZE 36
++#define FFI_NATIVE_RAW_API 0
++
++/* ---- Internal ---- */
++
++#if defined (__APPLE__)
++#define FFI_TARGET_SPECIFIC_VARIADIC
++#define FFI_EXTRA_CIF_FIELDS unsigned aarch64_flags; unsigned aarch64_nfixedargs
++#else
++#define FFI_EXTRA_CIF_FIELDS unsigned aarch64_flags
++#endif
++
++#define AARCH64_FFI_WITH_V_BIT 0
++
++#define AARCH64_N_XREG 32
++#define AARCH64_N_VREG 32
++#define AARCH64_CALL_CONTEXT_SIZE (AARCH64_N_XREG * 8 + AARCH64_N_VREG * 16)
++
++#endif
+diff -ruN Python-2.7.3.orig/Modules/_ctypes/libffi/src/aarch64/sysv.S Python-2.7.3/Modules/_ctypes/libffi/src/aarch64/sysv.S
+--- Python-2.7.3.orig/Modules/_ctypes/libffi/src/aarch64/sysv.S 1970-01-01 01:00:00.000000000 +0100
++++ Python-2.7.3/Modules/_ctypes/libffi/src/aarch64/sysv.S 2014-04-25 19:45:13.000000000 +0200
+@@ -0,0 +1,333 @@
++/* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd.
++
++Permission is hereby granted, free of charge, to any person obtaining
++a copy of this software and associated documentation files (the
++``Software''), to deal in the Software without restriction, including
++without limitation the rights to use, copy, modify, merge, publish,
++distribute, sublicense, and/or sell copies of the Software, and to
++permit persons to whom the Software is furnished to do so, subject to
++the following conditions:
++
++The above copyright notice and this permission notice shall be
++included in all copies or substantial portions of the Software.
++
++THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
++IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
++CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
++TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
++SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
++
++#define LIBFFI_ASM
++#include <fficonfig.h>
++#include <ffi.h>
++
++#ifdef HAVE_MACHINE_ASM_H
++#include <machine/asm.h>
++#else
++#ifdef __USER_LABEL_PREFIX__
++#define CONCAT1(a, b) CONCAT2(a, b)
++#define CONCAT2(a, b) a ## b
++
++/* Use the right prefix for global labels. */
++#define CNAME(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
++#else
++#define CNAME(x) x
++#endif
++#endif
++
++#define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off
++#define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off
++#define cfi_restore(reg) .cfi_restore reg
++#define cfi_def_cfa_register(reg) .cfi_def_cfa_register reg
++
++ .text
++ .globl CNAME(ffi_call_SYSV)
++#ifdef __ELF__
++ .type CNAME(ffi_call_SYSV), #function
++#endif
++#ifdef __APPLE__
++ .align 2
++#endif
++
++/* ffi_call_SYSV()
++
++ Create a stack frame, setup an argument context, call the callee
++ and extract the result.
++
++ The maximum required argument stack size is provided,
++ ffi_call_SYSV() allocates that stack space then calls the
++ prepare_fn to populate register context and stack. The
++ argument passing registers are loaded from the register
++ context and the callee called, on return the register passing
++ register are saved back to the context. Our caller will
++ extract the return value from the final state of the saved
++ register context.
++
++ Prototype:
++
++ extern unsigned
++ ffi_call_SYSV (void (*)(struct call_context *context, unsigned char *,
++ extended_cif *),
++ struct call_context *context,
++ extended_cif *,
++ size_t required_stack_size,
++ void (*fn)(void));
++
++ Therefore on entry we have:
++
++ x0 prepare_fn
++ x1 &context
++ x2 &ecif
++ x3 bytes
++ x4 fn
++
++ This function uses the following stack frame layout:
++
++ ==
++ saved x30(lr)
++ x29(fp)-> saved x29(fp)
++ saved x24
++ saved x23
++ saved x22
++ sp' -> saved x21
++ ...
++ sp -> (constructed callee stack arguments)
++ ==
++
++ Voila! */
++
++#define ffi_call_SYSV_FS (8 * 4)
++
++ .cfi_startproc
++CNAME(ffi_call_SYSV):
++ stp x29, x30, [sp, #-16]!
++ cfi_adjust_cfa_offset (16)
++ cfi_rel_offset (x29, 0)
++ cfi_rel_offset (x30, 8)
++
++ mov x29, sp
++ cfi_def_cfa_register (x29)
++ sub sp, sp, #ffi_call_SYSV_FS
++
++ stp x21, x22, [sp, #0]
++ cfi_rel_offset (x21, 0 - ffi_call_SYSV_FS)
++ cfi_rel_offset (x22, 8 - ffi_call_SYSV_FS)
++
++ stp x23, x24, [sp, #16]
++ cfi_rel_offset (x23, 16 - ffi_call_SYSV_FS)
++ cfi_rel_offset (x24, 24 - ffi_call_SYSV_FS)
++
++ mov x21, x1
++ mov x22, x2
++ mov x24, x4
++
++ /* Allocate the stack space for the actual arguments, many
++ arguments will be passed in registers, but we assume
++ worst case and allocate sufficient stack for ALL of
++ the arguments. */
++ sub sp, sp, x3
++
++ /* unsigned (*prepare_fn) (struct call_context *context,
++ unsigned char *stack, extended_cif *ecif);
++ */
++ mov x23, x0
++ mov x0, x1
++ mov x1, sp
++ /* x2 already in place */
++ blr x23
++
++ /* Preserve the flags returned. */
++ mov x23, x0
++
++ /* Figure out if we should touch the vector registers. */
++ tbz x23, #AARCH64_FFI_WITH_V_BIT, 1f
++
++ /* Load the vector argument passing registers. */
++ ldp q0, q1, [x21, #8*32 + 0]
++ ldp q2, q3, [x21, #8*32 + 32]
++ ldp q4, q5, [x21, #8*32 + 64]
++ ldp q6, q7, [x21, #8*32 + 96]
++1:
++ /* Load the core argument passing registers. */
++ ldp x0, x1, [x21, #0]
++ ldp x2, x3, [x21, #16]
++ ldp x4, x5, [x21, #32]
++ ldp x6, x7, [x21, #48]
++
++ /* Don't forget x8 which may be holding the address of a return buffer.
++ */
++ ldr x8, [x21, #8*8]
++
++ blr x24
++
++ /* Save the core argument passing registers. */
++ stp x0, x1, [x21, #0]
++ stp x2, x3, [x21, #16]
++ stp x4, x5, [x21, #32]
++ stp x6, x7, [x21, #48]
++
++ /* Note nothing useful ever comes back in x8! */
++
++ /* Figure out if we should touch the vector registers. */
++ tbz x23, #AARCH64_FFI_WITH_V_BIT, 1f
++
++ /* Save the vector argument passing registers. */
++ stp q0, q1, [x21, #8*32 + 0]
++ stp q2, q3, [x21, #8*32 + 32]
++ stp q4, q5, [x21, #8*32 + 64]
++ stp q6, q7, [x21, #8*32 + 96]
++1:
++ /* All done, unwind our stack frame. */
++ ldp x21, x22, [x29, # - ffi_call_SYSV_FS]
++ cfi_restore (x21)
++ cfi_restore (x22)
++
++ ldp x23, x24, [x29, # - ffi_call_SYSV_FS + 16]
++ cfi_restore (x23)
++ cfi_restore (x24)
++
++ mov sp, x29
++ cfi_def_cfa_register (sp)
++
++ ldp x29, x30, [sp], #16
++ cfi_adjust_cfa_offset (-16)
++ cfi_restore (x29)
++ cfi_restore (x30)
++
++ ret
++
++ .cfi_endproc
++#ifdef __ELF__
++ .size CNAME(ffi_call_SYSV), .-CNAME(ffi_call_SYSV)
++#endif
++
++#define ffi_closure_SYSV_FS (8 * 2 + AARCH64_CALL_CONTEXT_SIZE)
++
++/* ffi_closure_SYSV
++
++ Closure invocation glue. This is the low level code invoked directly by
++ the closure trampoline to setup and call a closure.
++
++ On entry x17 points to a struct trampoline_data, x16 has been clobbered
++ all other registers are preserved.
++
++ We allocate a call context and save the argument passing registers,
++ then invoked the generic C ffi_closure_SYSV_inner() function to do all
++ the real work, on return we load the result passing registers back from
++ the call context.
++
++ On entry
++
++ extern void
++ ffi_closure_SYSV (struct trampoline_data *);
++
++ struct trampoline_data
++ {
++ UINT64 *ffi_closure;
++ UINT64 flags;
++ };
++
++ This function uses the following stack frame layout:
++
++ ==
++ saved x30(lr)
++ x29(fp)-> saved x29(fp)
++ saved x22
++ saved x21
++ ...
++ sp -> call_context
++ ==
++
++ Voila! */
++
++ .text
++ .globl CNAME(ffi_closure_SYSV)
++#ifdef __APPLE__
++ .align 2
++#endif
++ .cfi_startproc
++CNAME(ffi_closure_SYSV):
++ stp x29, x30, [sp, #-16]!
++ cfi_adjust_cfa_offset (16)
++ cfi_rel_offset (x29, 0)
++ cfi_rel_offset (x30, 8)
++
++ mov x29, sp
++ cfi_def_cfa_register (x29)
++
++ sub sp, sp, #ffi_closure_SYSV_FS
++
++ stp x21, x22, [x29, #-16]
++ cfi_rel_offset (x21, -16)
++ cfi_rel_offset (x22, -8)
++
++ /* Load x21 with &call_context. */
++ mov x21, sp
++ /* Preserve our struct trampoline_data * */
++ mov x22, x17
++
++ /* Save the rest of the argument passing registers. */
++ stp x0, x1, [x21, #0]
++ stp x2, x3, [x21, #16]
++ stp x4, x5, [x21, #32]
++ stp x6, x7, [x21, #48]
++ /* Don't forget we may have been given a result scratch pad address.
++ */
++ str x8, [x21, #64]
++
++ /* Figure out if we should touch the vector registers. */
++ ldr x0, [x22, #8]
++ tbz x0, #AARCH64_FFI_WITH_V_BIT, 1f
++
++ /* Save the argument passing vector registers. */
++ stp q0, q1, [x21, #8*32 + 0]
++ stp q2, q3, [x21, #8*32 + 32]
++ stp q4, q5, [x21, #8*32 + 64]
++ stp q6, q7, [x21, #8*32 + 96]
++1:
++ /* Load &ffi_closure.. */
++ ldr x0, [x22, #0]
++ mov x1, x21
++ /* Compute the location of the stack at the point that the
++ trampoline was called. */
++ add x2, x29, #16
++
++ bl CNAME(ffi_closure_SYSV_inner)
++
++ /* Figure out if we should touch the vector registers. */
++ ldr x0, [x22, #8]
++ tbz x0, #AARCH64_FFI_WITH_V_BIT, 1f
++
++ /* Load the result passing vector registers. */
++ ldp q0, q1, [x21, #8*32 + 0]
++ ldp q2, q3, [x21, #8*32 + 32]
++ ldp q4, q5, [x21, #8*32 + 64]
++ ldp q6, q7, [x21, #8*32 + 96]
++1:
++ /* Load the result passing core registers. */
++ ldp x0, x1, [x21, #0]
++ ldp x2, x3, [x21, #16]
++ ldp x4, x5, [x21, #32]
++ ldp x6, x7, [x21, #48]
++ /* Note nothing useful is returned in x8. */
++
++ /* We are done, unwind our frame. */
++ ldp x21, x22, [x29, #-16]
++ cfi_restore (x21)
++ cfi_restore (x22)
++
++ mov sp, x29
++ cfi_def_cfa_register (sp)
++
++ ldp x29, x30, [sp], #16
++ cfi_adjust_cfa_offset (-16)
++ cfi_restore (x29)
++ cfi_restore (x30)
++
++ ret
++ .cfi_endproc
++#ifdef __ELF__
++ .size CNAME(ffi_closure_SYSV), .-CNAME(ffi_closure_SYSV)
++#endif
diff --git a/meta/recipes-devtools/python/python_2.7.3.bb b/meta/recipes-devtools/python/python_2.7.3.bb
index cbe8d7f..de1f57f 100644
--- a/meta/recipes-devtools/python/python_2.7.3.bb
+++ b/meta/recipes-devtools/python/python_2.7.3.bb
@@ -40,6 +40,8 @@ SRC_URI += "\
file://posix_close.patch \
file://python-2.7.3-CVE-2014-7185.patch \
file://python2.7.3-nossl3.patch \
+ file://ctypes-libffi-aarch64.patch \
+ file://libffi-aarch64.patch \
"
S = "${WORKDIR}/Python-${PV}"
--
1.9.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [dizzy] [PATCH 1/1] python: Add support for aarch64 for ctypes module
2015-03-04 15:04 [dizzy] [PATCH 1/1] python: Add support for aarch64 for ctypes module Tudor Florea
@ 2015-03-04 20:25 ` Burton, Ross
2015-03-04 22:52 ` Tudor Florea
2015-03-10 0:24 ` Tudor Florea
1 sibling, 1 reply; 5+ messages in thread
From: Burton, Ross @ 2015-03-04 20:25 UTC (permalink / raw)
To: Tudor Florea; +Cc: OE-core
[-- Attachment #1: Type: text/plain, Size: 407 bytes --]
On 4 March 2015 at 15:04, Tudor Florea <tudor.florea@enea.com> wrote:
> Python have its own version of libffi used for ctypes module.
> libffi 3.0.10 contained in original source of Python-2.7.3 does not have
> support for aarch64 architecture.
> This is patch is backport support for aarch64 from libffi 3.1
>
Can you confirm that this is already fixed in master by having Python 2.7.9?
Ross
[-- Attachment #2: Type: text/html, Size: 816 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [dizzy] [PATCH 1/1] python: Add support for aarch64 for ctypes module
2015-03-04 20:25 ` Burton, Ross
@ 2015-03-04 22:52 ` Tudor Florea
0 siblings, 0 replies; 5+ messages in thread
From: Tudor Florea @ 2015-03-04 22:52 UTC (permalink / raw)
To: Burton, Ross; +Cc: OE-core
[-- Attachment #1: Type: text/plain, Size: 632 bytes --]
On 3/4/2015 22:25, Burton, Ross wrote:
>
> On 4 March 2015 at 15:04, Tudor Florea <tudor.florea@enea.com
> <mailto:tudor.florea@enea.com>> wrote:
>
> Python have its own version of libffi used for ctypes module.
> libffi 3.0.10 contained in original source of Python-2.7.3 does
> not have
> support for aarch64 architecture.
> This is patch is backport support for aarch64 from libffi 3.1
>
>
> Can you confirm that this is already fixed in master by having Python
> 2.7.9?
I can confirm master (Python 2.7.9) have already the support for aarch64
included.
Regards,
Tudor.
>
> Ross
[-- Attachment #2: Type: text/html, Size: 40071 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [dizzy] [PATCH 1/1] python: Add support for aarch64 for ctypes module
2015-03-04 15:04 [dizzy] [PATCH 1/1] python: Add support for aarch64 for ctypes module Tudor Florea
2015-03-04 20:25 ` Burton, Ross
@ 2015-03-10 0:24 ` Tudor Florea
2015-03-11 13:42 ` akuster808
1 sibling, 1 reply; 5+ messages in thread
From: Tudor Florea @ 2015-03-10 0:24 UTC (permalink / raw)
To: Tudor Florea, openembedded-core@lists.openembedded.org
Ping.
> -----Original Message-----
> From: Tudor Florea [mailto:tudor.florea@enea.com]
> Sent: Wednesday, March 04, 2015 17:04
> To: openembedded-core@lists.openembedded.org
> Cc: Tudor Florea
> Subject: [dizzy] [PATCH 1/1] python: Add support for aarch64 for ctypes
> module
>
> Python have its own version of libffi used for ctypes module.
> libffi 3.0.10 contained in original source of Python-2.7.3 does not have
> support for aarch64 architecture.
> This is patch is backport support for aarch64 from libffi 3.1
> ---
> .../python/python/ctypes-libffi-aarch64.patch | 22 +
> .../python/python/libffi-aarch64.patch | 1608
> ++++++++++++++++++++
> meta/recipes-devtools/python/python_2.7.3.bb | 2 +
> 3 files changed, 1632 insertions(+)
> create mode 100644 meta/recipes-devtools/python/python/ctypes-libffi-
> aarch64.patch
> create mode 100644 meta/recipes-devtools/python/python/libffi-
> aarch64.patch
>
> diff --git a/meta/recipes-devtools/python/python/ctypes-libffi-
> aarch64.patch b/meta/recipes-devtools/python/python/ctypes-libffi-
> aarch64.patch
> new file mode 100644
> index 0000000..7349c7b
> --- /dev/null
> +++ b/meta/recipes-devtools/python/python/ctypes-libffi-aarch64.patch
> @@ -0,0 +1,22 @@
> +Add missing fficonfig.py bits for aarch64
> +
> +# HG changeset patch
> +# User Andreas Schwab <schwab@suse.de>
> +# Date 1367276434 -7200
> +# Node ID 05e8999a3901b4853e60d6701510e9b3dd54a7f3
> +# Parent 84cef4f1999ad9e362694cdac2f65f0981e3d5d0
> +
> +Upstream-Status: Backport
> +Signed-off-by: Tudor Florea <tudor.florea@enea.com>
> +
> +diff -r 84cef4f1999a -r 05e8999a3901 Modules/_ctypes/libffi/fficonfig.py.in
> +--- a/Modules/_ctypes/libffi/fficonfig.py.in Mon Apr 29 16:09:39 2013 -
> 0400
> ++++ b/Modules/_ctypes/libffi/fficonfig.py.in Tue Apr 30 01:00:34 2013
> +0200
> +@@ -28,6 +28,7 @@
> + 'PA': ['src/pa/linux.S', 'src/pa/ffi.c'],
> + 'PA_LINUX': ['src/pa/linux.S', 'src/pa/ffi.c'],
> + 'PA_HPUX': ['src/pa/hpux32.S', 'src/pa/ffi.c'],
> ++ 'AARCH64' : ['src/aarch64/ffi.c', 'src/aarch64/sysv.S'],
> + }
> +
> + ffi_sources += ffi_platforms['@TARGET@']
> diff --git a/meta/recipes-devtools/python/python/libffi-aarch64.patch
> b/meta/recipes-devtools/python/python/libffi-aarch64.patch
> new file mode 100644
> index 0000000..5581922
> --- /dev/null
> +++ b/meta/recipes-devtools/python/python/libffi-aarch64.patch
> @@ -0,0 +1,1608 @@
> +Add support for aarch64 for ctypes module
> +
> +Python have its own version of libffi used for ctypes module.
> +libffi 3.0.10 contained in original source of Python-2.7.3 does not have
> +support for aarch64 architecture.
> +This is patch is backport support for aarch64 from libffi 3.1
> +
> +Upstream-Status: Backport
> +Signed-off-by: Tudor Florea <tudor.florea@enea.com>
> +
> +diff -ruN Python-2.7.3.orig/Modules/_ctypes/libffi/configure.ac Python-
> 2.7.3/Modules/_ctypes/libffi/configure.ac
> +--- Python-2.7.3.orig/Modules/_ctypes/libffi/configure.ac 2015-02-27
> 23:15:16.118393178 +0100
> ++++ Python-2.7.3/Modules/_ctypes/libffi/configure.ac 2015-02-27
> 23:51:03.351556903 +0100
> +@@ -44,6 +44,10 @@
> +
> + TARGETDIR="unknown"
> + case "$host" in
> ++ aarch64*-*-*)
> ++ TARGET=AARCH64; TARGETDIR=aarch64
> ++ ;;
> ++
> + alpha*-*-*)
> + TARGET=ALPHA; TARGETDIR=alpha;
> + # Support 128-bit long double, changeable via command-line switch.
> +@@ -195,6 +199,7 @@
> + AM_CONDITIONAL(POWERPC_AIX, test x$TARGET = xPOWERPC_AIX)
> + AM_CONDITIONAL(POWERPC_DARWIN, test x$TARGET =
> xPOWERPC_DARWIN)
> + AM_CONDITIONAL(POWERPC_FREEBSD, test x$TARGET =
> xPOWERPC_FREEBSD)
> ++AM_CONDITIONAL(AARCH64, test x$TARGET = xAARCH64)
> + AM_CONDITIONAL(ARM, test x$TARGET = xARM)
> + AM_CONDITIONAL(AVR32, test x$TARGET = xAVR32)
> + AM_CONDITIONAL(LIBFFI_CRIS, test x$TARGET = xLIBFFI_CRIS)
> +diff -ruN Python-2.7.3.orig/Modules/_ctypes/libffi/src/aarch64/ffi.c
> Python-2.7.3/Modules/_ctypes/libffi/src/aarch64/ffi.c
> +--- Python-2.7.3.orig/Modules/_ctypes/libffi/src/aarch64/ffi.c 1970-
> 01-01 01:00:00.000000000 +0100
> ++++ Python-2.7.3/Modules/_ctypes/libffi/src/aarch64/ffi.c 2014-04-25
> 19:45:13.000000000 +0200
> +@@ -0,0 +1,1168 @@
> ++/* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd.
> ++
> ++Permission is hereby granted, free of charge, to any person obtaining
> ++a copy of this software and associated documentation files (the
> ++``Software''), to deal in the Software without restriction, including
> ++without limitation the rights to use, copy, modify, merge, publish,
> ++distribute, sublicense, and/or sell copies of the Software, and to
> ++permit persons to whom the Software is furnished to do so, subject to
> ++the following conditions:
> ++
> ++The above copyright notice and this permission notice shall be
> ++included in all copies or substantial portions of the Software.
> ++
> ++THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
> ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
> OF
> ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> NONINFRINGEMENT.
> ++IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
> ANY
> ++CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
> CONTRACT,
> ++TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
> THE
> ++SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
> ++
> ++#include <stdio.h>
> ++
> ++#include <ffi.h>
> ++#include <ffi_common.h>
> ++
> ++#include <stdlib.h>
> ++
> ++/* Stack alignment requirement in bytes */
> ++#if defined (__APPLE__)
> ++#define AARCH64_STACK_ALIGN 1
> ++#else
> ++#define AARCH64_STACK_ALIGN 16
> ++#endif
> ++
> ++#define N_X_ARG_REG 8
> ++#define N_V_ARG_REG 8
> ++
> ++#define AARCH64_FFI_WITH_V (1 << AARCH64_FFI_WITH_V_BIT)
> ++
> ++union _d
> ++{
> ++ UINT64 d;
> ++ UINT32 s[2];
> ++};
> ++
> ++struct call_context
> ++{
> ++ UINT64 x [AARCH64_N_XREG];
> ++ struct
> ++ {
> ++ union _d d[2];
> ++ } v [AARCH64_N_VREG];
> ++};
> ++
> ++#if defined (__clang__) && defined (__APPLE__)
> ++extern void
> ++sys_icache_invalidate (void *start, size_t len);
> ++#endif
> ++
> ++static inline void
> ++ffi_clear_cache (void *start, void *end)
> ++{
> ++#if defined (__clang__) && defined (__APPLE__)
> ++ sys_icache_invalidate (start, (char *)end - (char *)start);
> ++#elif defined (__GNUC__)
> ++ __builtin___clear_cache (start, end);
> ++#else
> ++#error "Missing builtin to flush instruction cache"
> ++#endif
> ++}
> ++
> ++static void *
> ++get_x_addr (struct call_context *context, unsigned n)
> ++{
> ++ return &context->x[n];
> ++}
> ++
> ++static void *
> ++get_s_addr (struct call_context *context, unsigned n)
> ++{
> ++#if defined __AARCH64EB__
> ++ return &context->v[n].d[1].s[1];
> ++#else
> ++ return &context->v[n].d[0].s[0];
> ++#endif
> ++}
> ++
> ++static void *
> ++get_d_addr (struct call_context *context, unsigned n)
> ++{
> ++#if defined __AARCH64EB__
> ++ return &context->v[n].d[1];
> ++#else
> ++ return &context->v[n].d[0];
> ++#endif
> ++}
> ++
> ++static void *
> ++get_v_addr (struct call_context *context, unsigned n)
> ++{
> ++ return &context->v[n];
> ++}
> ++
> ++/* Return the memory location at which a basic type would reside
> ++ were it to have been stored in register n. */
> ++
> ++static void *
> ++get_basic_type_addr (unsigned short type, struct call_context *context,
> ++ unsigned n)
> ++{
> ++ switch (type)
> ++ {
> ++ case FFI_TYPE_FLOAT:
> ++ return get_s_addr (context, n);
> ++ case FFI_TYPE_DOUBLE:
> ++ return get_d_addr (context, n);
> ++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
> ++ case FFI_TYPE_LONGDOUBLE:
> ++ return get_v_addr (context, n);
> ++#endif
> ++ case FFI_TYPE_UINT8:
> ++ case FFI_TYPE_SINT8:
> ++ case FFI_TYPE_UINT16:
> ++ case FFI_TYPE_SINT16:
> ++ case FFI_TYPE_UINT32:
> ++ case FFI_TYPE_SINT32:
> ++ case FFI_TYPE_INT:
> ++ case FFI_TYPE_POINTER:
> ++ case FFI_TYPE_UINT64:
> ++ case FFI_TYPE_SINT64:
> ++ return get_x_addr (context, n);
> ++ case FFI_TYPE_VOID:
> ++ return NULL;
> ++ default:
> ++ FFI_ASSERT (0);
> ++ return NULL;
> ++ }
> ++}
> ++
> ++/* Return the alignment width for each of the basic types. */
> ++
> ++static size_t
> ++get_basic_type_alignment (unsigned short type)
> ++{
> ++ switch (type)
> ++ {
> ++ case FFI_TYPE_FLOAT:
> ++ case FFI_TYPE_DOUBLE:
> ++ return sizeof (UINT64);
> ++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
> ++ case FFI_TYPE_LONGDOUBLE:
> ++ return sizeof (long double);
> ++#endif
> ++ case FFI_TYPE_UINT8:
> ++ case FFI_TYPE_SINT8:
> ++#if defined (__APPLE__)
> ++ return sizeof (UINT8);
> ++#endif
> ++ case FFI_TYPE_UINT16:
> ++ case FFI_TYPE_SINT16:
> ++#if defined (__APPLE__)
> ++ return sizeof (UINT16);
> ++#endif
> ++ case FFI_TYPE_UINT32:
> ++ case FFI_TYPE_INT:
> ++ case FFI_TYPE_SINT32:
> ++#if defined (__APPLE__)
> ++ return sizeof (UINT32);
> ++#endif
> ++ case FFI_TYPE_POINTER:
> ++ case FFI_TYPE_UINT64:
> ++ case FFI_TYPE_SINT64:
> ++ return sizeof (UINT64);
> ++
> ++ default:
> ++ FFI_ASSERT (0);
> ++ return 0;
> ++ }
> ++}
> ++
> ++/* Return the size in bytes for each of the basic types. */
> ++
> ++static size_t
> ++get_basic_type_size (unsigned short type)
> ++{
> ++ switch (type)
> ++ {
> ++ case FFI_TYPE_FLOAT:
> ++ return sizeof (UINT32);
> ++ case FFI_TYPE_DOUBLE:
> ++ return sizeof (UINT64);
> ++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
> ++ case FFI_TYPE_LONGDOUBLE:
> ++ return sizeof (long double);
> ++#endif
> ++ case FFI_TYPE_UINT8:
> ++ return sizeof (UINT8);
> ++ case FFI_TYPE_SINT8:
> ++ return sizeof (SINT8);
> ++ case FFI_TYPE_UINT16:
> ++ return sizeof (UINT16);
> ++ case FFI_TYPE_SINT16:
> ++ return sizeof (SINT16);
> ++ case FFI_TYPE_UINT32:
> ++ return sizeof (UINT32);
> ++ case FFI_TYPE_INT:
> ++ case FFI_TYPE_SINT32:
> ++ return sizeof (SINT32);
> ++ case FFI_TYPE_POINTER:
> ++ case FFI_TYPE_UINT64:
> ++ return sizeof (UINT64);
> ++ case FFI_TYPE_SINT64:
> ++ return sizeof (SINT64);
> ++
> ++ default:
> ++ FFI_ASSERT (0);
> ++ return 0;
> ++ }
> ++}
> ++
> ++extern void
> ++ffi_call_SYSV (unsigned (*)(struct call_context *context, unsigned char *,
> ++ extended_cif *),
> ++ struct call_context *context,
> ++ extended_cif *,
> ++ size_t,
> ++ void (*fn)(void));
> ++
> ++extern void
> ++ffi_closure_SYSV (ffi_closure *);
> ++
> ++/* Test for an FFI floating point representation. */
> ++
> ++static unsigned
> ++is_floating_type (unsigned short type)
> ++{
> ++ return (type == FFI_TYPE_FLOAT || type == FFI_TYPE_DOUBLE
> ++ || type == FFI_TYPE_LONGDOUBLE);
> ++}
> ++
> ++/* Test for a homogeneous structure. */
> ++
> ++static unsigned short
> ++get_homogeneous_type (ffi_type *ty)
> ++{
> ++ if (ty->type == FFI_TYPE_STRUCT && ty->elements)
> ++ {
> ++ unsigned i;
> ++ unsigned short candidate_type
> ++ = get_homogeneous_type (ty->elements[0]);
> ++ for (i =1; ty->elements[i]; i++)
> ++ {
> ++ unsigned short iteration_type = 0;
> ++ /* If we have a nested struct, we must find its homogeneous type.
> ++ If that fits with our candidate type, we are still
> ++ homogeneous. */
> ++ if (ty->elements[i]->type == FFI_TYPE_STRUCT
> ++ && ty->elements[i]->elements)
> ++ {
> ++ iteration_type = get_homogeneous_type (ty->elements[i]);
> ++ }
> ++ else
> ++ {
> ++ iteration_type = ty->elements[i]->type;
> ++ }
> ++
> ++ /* If we are not homogeneous, return FFI_TYPE_STRUCT. */
> ++ if (candidate_type != iteration_type)
> ++ return FFI_TYPE_STRUCT;
> ++ }
> ++ return candidate_type;
> ++ }
> ++
> ++ /* Base case, we have no more levels of nesting, so we
> ++ are a basic type, and so, trivially homogeneous in that type. */
> ++ return ty->type;
> ++}
> ++
> ++/* Determine the number of elements within a STRUCT.
> ++
> ++ Note, we must handle nested structs.
> ++
> ++ If ty is not a STRUCT this function will return 0. */
> ++
> ++static unsigned
> ++element_count (ffi_type *ty)
> ++{
> ++ if (ty->type == FFI_TYPE_STRUCT && ty->elements)
> ++ {
> ++ unsigned n;
> ++ unsigned elems = 0;
> ++ for (n = 0; ty->elements[n]; n++)
> ++ {
> ++ if (ty->elements[n]->type == FFI_TYPE_STRUCT
> ++ && ty->elements[n]->elements)
> ++ elems += element_count (ty->elements[n]);
> ++ else
> ++ elems++;
> ++ }
> ++ return elems;
> ++ }
> ++ return 0;
> ++}
> ++
> ++/* Test for a homogeneous floating point aggregate.
> ++
> ++ A homogeneous floating point aggregate is a homogeneous aggregate of
> ++ a half- single- or double- precision floating point type with one
> ++ to four elements. Note that this includes nested structs of the
> ++ basic type. */
> ++
> ++static int
> ++is_hfa (ffi_type *ty)
> ++{
> ++ if (ty->type == FFI_TYPE_STRUCT
> ++ && ty->elements[0]
> ++ && is_floating_type (get_homogeneous_type (ty)))
> ++ {
> ++ unsigned n = element_count (ty);
> ++ return n >= 1 && n <= 4;
> ++ }
> ++ return 0;
> ++}
> ++
> ++/* Test if an ffi_type is a candidate for passing in a register.
> ++
> ++ This test does not check that sufficient registers of the
> ++ appropriate class are actually available, merely that IFF
> ++ sufficient registers are available then the argument will be passed
> ++ in register(s).
> ++
> ++ Note that an ffi_type that is deemed to be a register candidate
> ++ will always be returned in registers.
> ++
> ++ Returns 1 if a register candidate else 0. */
> ++
> ++static int
> ++is_register_candidate (ffi_type *ty)
> ++{
> ++ switch (ty->type)
> ++ {
> ++ case FFI_TYPE_VOID:
> ++ case FFI_TYPE_FLOAT:
> ++ case FFI_TYPE_DOUBLE:
> ++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
> ++ case FFI_TYPE_LONGDOUBLE:
> ++#endif
> ++ case FFI_TYPE_UINT8:
> ++ case FFI_TYPE_UINT16:
> ++ case FFI_TYPE_UINT32:
> ++ case FFI_TYPE_UINT64:
> ++ case FFI_TYPE_POINTER:
> ++ case FFI_TYPE_SINT8:
> ++ case FFI_TYPE_SINT16:
> ++ case FFI_TYPE_SINT32:
> ++ case FFI_TYPE_INT:
> ++ case FFI_TYPE_SINT64:
> ++ return 1;
> ++
> ++ case FFI_TYPE_STRUCT:
> ++ if (is_hfa (ty))
> ++ {
> ++ return 1;
> ++ }
> ++ else if (ty->size > 16)
> ++ {
> ++ /* Too large. Will be replaced with a pointer to memory. The
> ++ pointer MAY be passed in a register, but the value will
> ++ not. This test specifically fails since the argument will
> ++ never be passed by value in registers. */
> ++ return 0;
> ++ }
> ++ else
> ++ {
> ++ /* Might be passed in registers depending on the number of
> ++ registers required. */
> ++ return (ty->size + 7) / 8 < N_X_ARG_REG;
> ++ }
> ++ break;
> ++
> ++ default:
> ++ FFI_ASSERT (0);
> ++ break;
> ++ }
> ++
> ++ return 0;
> ++}
> ++
> ++/* Test if an ffi_type argument or result is a candidate for a vector
> ++ register. */
> ++
> ++static int
> ++is_v_register_candidate (ffi_type *ty)
> ++{
> ++ return is_floating_type (ty->type)
> ++ || (ty->type == FFI_TYPE_STRUCT && is_hfa (ty));
> ++}
> ++
> ++/* Representation of the procedure call argument marshalling
> ++ state.
> ++
> ++ The terse state variable names match the names used in the AARCH64
> ++ PCS. */
> ++
> ++struct arg_state
> ++{
> ++ unsigned ngrn; /* Next general-purpose register number. */
> ++ unsigned nsrn; /* Next vector register number. */
> ++ size_t nsaa; /* Next stack offset. */
> ++
> ++#if defined (__APPLE__)
> ++ unsigned allocating_variadic;
> ++#endif
> ++};
> ++
> ++/* Initialize a procedure call argument marshalling state. */
> ++static void
> ++arg_init (struct arg_state *state, size_t call_frame_size)
> ++{
> ++ state->ngrn = 0;
> ++ state->nsrn = 0;
> ++ state->nsaa = 0;
> ++
> ++#if defined (__APPLE__)
> ++ state->allocating_variadic = 0;
> ++#endif
> ++}
> ++
> ++/* Return the number of available consecutive core argument
> ++ registers. */
> ++
> ++static unsigned
> ++available_x (struct arg_state *state)
> ++{
> ++ return N_X_ARG_REG - state->ngrn;
> ++}
> ++
> ++/* Return the number of available consecutive vector argument
> ++ registers. */
> ++
> ++static unsigned
> ++available_v (struct arg_state *state)
> ++{
> ++ return N_V_ARG_REG - state->nsrn;
> ++}
> ++
> ++static void *
> ++allocate_to_x (struct call_context *context, struct arg_state *state)
> ++{
> ++ FFI_ASSERT (state->ngrn < N_X_ARG_REG);
> ++ return get_x_addr (context, (state->ngrn)++);
> ++}
> ++
> ++static void *
> ++allocate_to_s (struct call_context *context, struct arg_state *state)
> ++{
> ++ FFI_ASSERT (state->nsrn < N_V_ARG_REG);
> ++ return get_s_addr (context, (state->nsrn)++);
> ++}
> ++
> ++static void *
> ++allocate_to_d (struct call_context *context, struct arg_state *state)
> ++{
> ++ FFI_ASSERT (state->nsrn < N_V_ARG_REG);
> ++ return get_d_addr (context, (state->nsrn)++);
> ++}
> ++
> ++static void *
> ++allocate_to_v (struct call_context *context, struct arg_state *state)
> ++{
> ++ FFI_ASSERT (state->nsrn < N_V_ARG_REG);
> ++ return get_v_addr (context, (state->nsrn)++);
> ++}
> ++
> ++/* Allocate an aligned slot on the stack and return a pointer to it. */
> ++static void *
> ++allocate_to_stack (struct arg_state *state, void *stack, size_t alignment,
> ++ size_t size)
> ++{
> ++ void *allocation;
> ++
> ++ /* Round up the NSAA to the larger of 8 or the natural
> ++ alignment of the argument's type. */
> ++ state->nsaa = ALIGN (state->nsaa, alignment);
> ++ state->nsaa = ALIGN (state->nsaa, alignment);
> ++#if defined (__APPLE__)
> ++ if (state->allocating_variadic)
> ++ state->nsaa = ALIGN (state->nsaa, 8);
> ++#else
> ++ state->nsaa = ALIGN (state->nsaa, 8);
> ++#endif
> ++
> ++ allocation = stack + state->nsaa;
> ++
> ++ state->nsaa += size;
> ++ return allocation;
> ++}
> ++
> ++static void
> ++copy_basic_type (void *dest, void *source, unsigned short type)
> ++{
> ++ /* This is necessary to ensure that basic types are copied
> ++ sign extended to 64-bits as libffi expects. */
> ++ switch (type)
> ++ {
> ++ case FFI_TYPE_FLOAT:
> ++ *(float *) dest = *(float *) source;
> ++ break;
> ++ case FFI_TYPE_DOUBLE:
> ++ *(double *) dest = *(double *) source;
> ++ break;
> ++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
> ++ case FFI_TYPE_LONGDOUBLE:
> ++ *(long double *) dest = *(long double *) source;
> ++ break;
> ++#endif
> ++ case FFI_TYPE_UINT8:
> ++ *(ffi_arg *) dest = *(UINT8 *) source;
> ++ break;
> ++ case FFI_TYPE_SINT8:
> ++ *(ffi_sarg *) dest = *(SINT8 *) source;
> ++ break;
> ++ case FFI_TYPE_UINT16:
> ++ *(ffi_arg *) dest = *(UINT16 *) source;
> ++ break;
> ++ case FFI_TYPE_SINT16:
> ++ *(ffi_sarg *) dest = *(SINT16 *) source;
> ++ break;
> ++ case FFI_TYPE_UINT32:
> ++ *(ffi_arg *) dest = *(UINT32 *) source;
> ++ break;
> ++ case FFI_TYPE_INT:
> ++ case FFI_TYPE_SINT32:
> ++ *(ffi_sarg *) dest = *(SINT32 *) source;
> ++ break;
> ++ case FFI_TYPE_POINTER:
> ++ case FFI_TYPE_UINT64:
> ++ *(ffi_arg *) dest = *(UINT64 *) source;
> ++ break;
> ++ case FFI_TYPE_SINT64:
> ++ *(ffi_sarg *) dest = *(SINT64 *) source;
> ++ break;
> ++ case FFI_TYPE_VOID:
> ++ break;
> ++
> ++ default:
> ++ FFI_ASSERT (0);
> ++ }
> ++}
> ++
> ++static void
> ++copy_hfa_to_reg_or_stack (void *memory,
> ++ ffi_type *ty,
> ++ struct call_context *context,
> ++ unsigned char *stack,
> ++ struct arg_state *state)
> ++{
> ++ unsigned elems = element_count (ty);
> ++ if (available_v (state) < elems)
> ++ {
> ++ /* There are insufficient V registers. Further V register allocations
> ++ are prevented, the NSAA is adjusted (by allocate_to_stack ())
> ++ and the argument is copied to memory at the adjusted NSAA. */
> ++ state->nsrn = N_V_ARG_REG;
> ++ memcpy (allocate_to_stack (state, stack, ty->alignment, ty->size),
> ++ memory,
> ++ ty->size);
> ++ }
> ++ else
> ++ {
> ++ int i;
> ++ unsigned short type = get_homogeneous_type (ty);
> ++ for (i = 0; i < elems; i++)
> ++ {
> ++ void *reg = allocate_to_v (context, state);
> ++ copy_basic_type (reg, memory, type);
> ++ memory += get_basic_type_size (type);
> ++ }
> ++ }
> ++}
> ++
> ++/* Either allocate an appropriate register for the argument type, or if
> ++ none are available, allocate a stack slot and return a pointer
> ++ to the allocated space. */
> ++
> ++static void *
> ++allocate_to_register_or_stack (struct call_context *context,
> ++ unsigned char *stack,
> ++ struct arg_state *state,
> ++ unsigned short type)
> ++{
> ++ size_t alignment = get_basic_type_alignment (type);
> ++ size_t size = alignment;
> ++ switch (type)
> ++ {
> ++ case FFI_TYPE_FLOAT:
> ++ /* This is the only case for which the allocated stack size
> ++ should not match the alignment of the type. */
> ++ size = sizeof (UINT32);
> ++ /* Fall through. */
> ++ case FFI_TYPE_DOUBLE:
> ++ if (state->nsrn < N_V_ARG_REG)
> ++ return allocate_to_d (context, state);
> ++ state->nsrn = N_V_ARG_REG;
> ++ break;
> ++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
> ++ case FFI_TYPE_LONGDOUBLE:
> ++ if (state->nsrn < N_V_ARG_REG)
> ++ return allocate_to_v (context, state);
> ++ state->nsrn = N_V_ARG_REG;
> ++ break;
> ++#endif
> ++ case FFI_TYPE_UINT8:
> ++ case FFI_TYPE_SINT8:
> ++ case FFI_TYPE_UINT16:
> ++ case FFI_TYPE_SINT16:
> ++ case FFI_TYPE_UINT32:
> ++ case FFI_TYPE_SINT32:
> ++ case FFI_TYPE_INT:
> ++ case FFI_TYPE_POINTER:
> ++ case FFI_TYPE_UINT64:
> ++ case FFI_TYPE_SINT64:
> ++ if (state->ngrn < N_X_ARG_REG)
> ++ return allocate_to_x (context, state);
> ++ state->ngrn = N_X_ARG_REG;
> ++ break;
> ++ default:
> ++ FFI_ASSERT (0);
> ++ }
> ++
> ++ return allocate_to_stack (state, stack, alignment, size);
> ++}
> ++
> ++/* Copy a value to an appropriate register, or if none are
> ++ available, to the stack. */
> ++
> ++static void
> ++copy_to_register_or_stack (struct call_context *context,
> ++ unsigned char *stack,
> ++ struct arg_state *state,
> ++ void *value,
> ++ unsigned short type)
> ++{
> ++ copy_basic_type (
> ++ allocate_to_register_or_stack (context, stack, state, type),
> ++ value,
> ++ type);
> ++}
> ++
> ++/* Marshall the arguments from FFI representation to procedure call
> ++ context and stack. */
> ++
> ++static unsigned
> ++aarch64_prep_args (struct call_context *context, unsigned char *stack,
> ++ extended_cif *ecif)
> ++{
> ++ int i;
> ++ struct arg_state state;
> ++
> ++ arg_init (&state, ALIGN(ecif->cif->bytes, 16));
> ++
> ++ for (i = 0; i < ecif->cif->nargs; i++)
> ++ {
> ++ ffi_type *ty = ecif->cif->arg_types[i];
> ++ switch (ty->type)
> ++ {
> ++ case FFI_TYPE_VOID:
> ++ FFI_ASSERT (0);
> ++ break;
> ++
> ++ /* If the argument is a basic type the argument is allocated to an
> ++ appropriate register, or if none are available, to the stack. */
> ++ case FFI_TYPE_FLOAT:
> ++ case FFI_TYPE_DOUBLE:
> ++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
> ++ case FFI_TYPE_LONGDOUBLE:
> ++#endif
> ++ case FFI_TYPE_UINT8:
> ++ case FFI_TYPE_SINT8:
> ++ case FFI_TYPE_UINT16:
> ++ case FFI_TYPE_SINT16:
> ++ case FFI_TYPE_UINT32:
> ++ case FFI_TYPE_INT:
> ++ case FFI_TYPE_SINT32:
> ++ case FFI_TYPE_POINTER:
> ++ case FFI_TYPE_UINT64:
> ++ case FFI_TYPE_SINT64:
> ++ copy_to_register_or_stack (context, stack, &state,
> ++ ecif->avalue[i], ty->type);
> ++ break;
> ++
> ++ case FFI_TYPE_STRUCT:
> ++ if (is_hfa (ty))
> ++ {
> ++ copy_hfa_to_reg_or_stack (ecif->avalue[i], ty, context,
> ++ stack, &state);
> ++ }
> ++ else if (ty->size > 16)
> ++ {
> ++ /* If the argument is a composite type that is larger than 16
> ++ bytes, then the argument has been copied to memory, and
> ++ the argument is replaced by a pointer to the copy. */
> ++
> ++ copy_to_register_or_stack (context, stack, &state,
> ++ &(ecif->avalue[i]),
> FFI_TYPE_POINTER);
> ++ }
> ++ else if (available_x (&state) >= (ty->size + 7) / 8)
> ++ {
> ++ /* If the argument is a composite type and the size in
> ++ double-words is not more than the number of available
> ++ X registers, then the argument is copied into consecutive
> ++ X registers. */
> ++ int j;
> ++ for (j = 0; j < (ty->size + 7) / 8; j++)
> ++ {
> ++ memcpy (allocate_to_x (context, &state),
> ++ &(((UINT64 *) ecif->avalue[i])[j]),
> ++ sizeof (UINT64));
> ++ }
> ++ }
> ++ else
> ++ {
> ++ /* Otherwise, there are insufficient X registers. Further X
> ++ register allocations are prevented, the NSAA is adjusted
> ++ (by allocate_to_stack ()) and the argument is copied to
> ++ memory at the adjusted NSAA. */
> ++ state.ngrn = N_X_ARG_REG;
> ++
> ++ memcpy (allocate_to_stack (&state, stack, ty->alignment,
> ++ ty->size), ecif->avalue + i, ty->size);
> ++ }
> ++ break;
> ++
> ++ default:
> ++ FFI_ASSERT (0);
> ++ break;
> ++ }
> ++
> ++#if defined (__APPLE__)
> ++ if (i + 1 == ecif->cif->aarch64_nfixedargs)
> ++ {
> ++ state.ngrn = N_X_ARG_REG;
> ++ state.nsrn = N_V_ARG_REG;
> ++
> ++ state.allocating_variadic = 1;
> ++ }
> ++#endif
> ++ }
> ++
> ++ return ecif->cif->aarch64_flags;
> ++}
> ++
> ++ffi_status
> ++ffi_prep_cif_machdep (ffi_cif *cif)
> ++{
> ++ /* Round the stack up to a multiple of the stack alignment requirement.
> */
> ++ cif->bytes =
> ++ (cif->bytes + (AARCH64_STACK_ALIGN - 1)) & ~
> (AARCH64_STACK_ALIGN - 1);
> ++
> ++ /* Initialize our flags. We are interested if this CIF will touch a
> ++ vector register, if so we will enable context save and load to
> ++ those registers, otherwise not. This is intended to be friendly
> ++ to lazy float context switching in the kernel. */
> ++ cif->aarch64_flags = 0;
> ++
> ++ if (is_v_register_candidate (cif->rtype))
> ++ {
> ++ cif->aarch64_flags |= AARCH64_FFI_WITH_V;
> ++ }
> ++ else
> ++ {
> ++ int i;
> ++ for (i = 0; i < cif->nargs; i++)
> ++ if (is_v_register_candidate (cif->arg_types[i]))
> ++ {
> ++ cif->aarch64_flags |= AARCH64_FFI_WITH_V;
> ++ break;
> ++ }
> ++ }
> ++
> ++ return FFI_OK;
> ++}
> ++
> ++#if defined (__APPLE__)
> ++
> ++/* Perform Apple-specific cif processing for variadic calls */
> ++ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif,
> ++ unsigned int nfixedargs,
> ++ unsigned int ntotalargs)
> ++{
> ++ cif->aarch64_nfixedargs = nfixedargs;
> ++
> ++ return ffi_prep_cif_machdep(cif);
> ++}
> ++
> ++#endif
> ++
> ++/* Call a function with the provided arguments and capture the return
> ++ value. */
> ++void
> ++ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
> ++{
> ++ extended_cif ecif;
> ++
> ++ ecif.cif = cif;
> ++ ecif.avalue = avalue;
> ++ ecif.rvalue = rvalue;
> ++
> ++ switch (cif->abi)
> ++ {
> ++ case FFI_SYSV:
> ++ {
> ++ struct call_context context;
> ++ size_t stack_bytes;
> ++
> ++ /* Figure out the total amount of stack space we need, the
> ++ above call frame space needs to be 16 bytes aligned to
> ++ ensure correct alignment of the first object inserted in
> ++ that space hence the ALIGN applied to cif->bytes.*/
> ++ stack_bytes = ALIGN(cif->bytes, 16);
> ++
> ++ memset (&context, 0, sizeof (context));
> ++ if (is_register_candidate (cif->rtype))
> ++ {
> ++ ffi_call_SYSV (aarch64_prep_args, &context, &ecif, stack_bytes, fn);
> ++ switch (cif->rtype->type)
> ++ {
> ++ case FFI_TYPE_VOID:
> ++ case FFI_TYPE_FLOAT:
> ++ case FFI_TYPE_DOUBLE:
> ++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
> ++ case FFI_TYPE_LONGDOUBLE:
> ++#endif
> ++ case FFI_TYPE_UINT8:
> ++ case FFI_TYPE_SINT8:
> ++ case FFI_TYPE_UINT16:
> ++ case FFI_TYPE_SINT16:
> ++ case FFI_TYPE_UINT32:
> ++ case FFI_TYPE_SINT32:
> ++ case FFI_TYPE_POINTER:
> ++ case FFI_TYPE_UINT64:
> ++ case FFI_TYPE_INT:
> ++ case FFI_TYPE_SINT64:
> ++ {
> ++ void *addr = get_basic_type_addr (cif->rtype->type,
> ++ &context, 0);
> ++ copy_basic_type (rvalue, addr, cif->rtype->type);
> ++ break;
> ++ }
> ++
> ++ case FFI_TYPE_STRUCT:
> ++ if (is_hfa (cif->rtype))
> ++ {
> ++ int j;
> ++ unsigned short type = get_homogeneous_type (cif-
> >rtype);
> ++ unsigned elems = element_count (cif->rtype);
> ++ for (j = 0; j < elems; j++)
> ++ {
> ++ void *reg = get_basic_type_addr (type, &context, j);
> ++ copy_basic_type (rvalue, reg, type);
> ++ rvalue += get_basic_type_size (type);
> ++ }
> ++ }
> ++ else if ((cif->rtype->size + 7) / 8 < N_X_ARG_REG)
> ++ {
> ++ size_t size = ALIGN (cif->rtype->size, sizeof (UINT64));
> ++ memcpy (rvalue, get_x_addr (&context, 0), size);
> ++ }
> ++ else
> ++ {
> ++ FFI_ASSERT (0);
> ++ }
> ++ break;
> ++
> ++ default:
> ++ FFI_ASSERT (0);
> ++ break;
> ++ }
> ++ }
> ++ else
> ++ {
> ++ memcpy (get_x_addr (&context, 8), &rvalue, sizeof (UINT64));
> ++ ffi_call_SYSV (aarch64_prep_args, &context, &ecif,
> ++ stack_bytes, fn);
> ++ }
> ++ break;
> ++ }
> ++
> ++ default:
> ++ FFI_ASSERT (0);
> ++ break;
> ++ }
> ++}
> ++
> ++static unsigned char trampoline [] =
> ++{ 0x70, 0x00, 0x00, 0x58, /* ldr x16, 1f */
> ++ 0x91, 0x00, 0x00, 0x10, /* adr x17, 2f */
> ++ 0x00, 0x02, 0x1f, 0xd6 /* br x16 */
> ++};
> ++
> ++/* Build a trampoline. */
> ++
> ++#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX,FLAGS)
> \
> ++ ({unsigned char *__tramp = (unsigned char*)(TRAMP);
> \
> ++ UINT64 __fun = (UINT64)(FUN); \
> ++ UINT64 __ctx = (UINT64)(CTX); \
> ++ UINT64 __flags = (UINT64)(FLAGS);
> \
> ++ memcpy (__tramp, trampoline, sizeof (trampoline));
> \
> ++ memcpy (__tramp + 12, &__fun, sizeof (__fun)); \
> ++ memcpy (__tramp + 20, &__ctx, sizeof (__ctx)); \
> ++ memcpy (__tramp + 28, &__flags, sizeof (__flags));
> \
> ++ ffi_clear_cache(__tramp, __tramp + FFI_TRAMPOLINE_SIZE);
> \
> ++ })
> ++
> ++ffi_status
> ++ffi_prep_closure_loc (ffi_closure* closure,
> ++ ffi_cif* cif,
> ++ void (*fun)(ffi_cif*,void*,void**,void*),
> ++ void *user_data,
> ++ void *codeloc)
> ++{
> ++ if (cif->abi != FFI_SYSV)
> ++ return FFI_BAD_ABI;
> ++
> ++ FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_SYSV, codeloc,
> ++ cif->aarch64_flags);
> ++
> ++ closure->cif = cif;
> ++ closure->user_data = user_data;
> ++ closure->fun = fun;
> ++
> ++ return FFI_OK;
> ++}
> ++
> ++/* Primary handler to setup and invoke a function within a closure.
> ++
> ++ A closure when invoked enters via the assembler wrapper
> ++ ffi_closure_SYSV(). The wrapper allocates a call context on the
> ++ stack, saves the interesting registers (from the perspective of
> ++ the calling convention) into the context then passes control to
> ++ ffi_closure_SYSV_inner() passing the saved context and a pointer to
> ++ the stack at the point ffi_closure_SYSV() was invoked.
> ++
> ++ On the return path the assembler wrapper will reload call context
> ++ registers.
> ++
> ++ ffi_closure_SYSV_inner() marshalls the call context into ffi value
> ++ descriptors, invokes the wrapped function, then marshalls the return
> ++ value back into the call context. */
> ++
> ++void FFI_HIDDEN
> ++ffi_closure_SYSV_inner (ffi_closure *closure, struct call_context *context,
> ++ void *stack)
> ++{
> ++ ffi_cif *cif = closure->cif;
> ++ void **avalue = (void**) alloca (cif->nargs * sizeof (void*));
> ++ void *rvalue = NULL;
> ++ int i;
> ++ struct arg_state state;
> ++
> ++ arg_init (&state, ALIGN(cif->bytes, 16));
> ++
> ++ for (i = 0; i < cif->nargs; i++)
> ++ {
> ++ ffi_type *ty = cif->arg_types[i];
> ++
> ++ switch (ty->type)
> ++ {
> ++ case FFI_TYPE_VOID:
> ++ FFI_ASSERT (0);
> ++ break;
> ++
> ++ case FFI_TYPE_UINT8:
> ++ case FFI_TYPE_SINT8:
> ++ case FFI_TYPE_UINT16:
> ++ case FFI_TYPE_SINT16:
> ++ case FFI_TYPE_UINT32:
> ++ case FFI_TYPE_SINT32:
> ++ case FFI_TYPE_INT:
> ++ case FFI_TYPE_POINTER:
> ++ case FFI_TYPE_UINT64:
> ++ case FFI_TYPE_SINT64:
> ++ case FFI_TYPE_FLOAT:
> ++ case FFI_TYPE_DOUBLE:
> ++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
> ++ case FFI_TYPE_LONGDOUBLE:
> ++ avalue[i] = allocate_to_register_or_stack (context, stack,
> ++ &state, ty->type);
> ++ break;
> ++#endif
> ++
> ++ case FFI_TYPE_STRUCT:
> ++ if (is_hfa (ty))
> ++ {
> ++ unsigned n = element_count (ty);
> ++ if (available_v (&state) < n)
> ++ {
> ++ state.nsrn = N_V_ARG_REG;
> ++ avalue[i] = allocate_to_stack (&state, stack, ty->alignment,
> ++ ty->size);
> ++ }
> ++ else
> ++ {
> ++ switch (get_homogeneous_type (ty))
> ++ {
> ++ case FFI_TYPE_FLOAT:
> ++ {
> ++ /* Eeek! We need a pointer to the structure,
> ++ however the homogeneous float elements are
> ++ being passed in individual S registers,
> ++ therefore the structure is not represented as
> ++ a contiguous sequence of bytes in our saved
> ++ register context. We need to fake up a copy
> ++ of the structure laid out in memory
> ++ correctly. The fake can be tossed once the
> ++ closure function has returned hence alloca()
> ++ is sufficient. */
> ++ int j;
> ++ UINT32 *p = avalue[i] = alloca (ty->size);
> ++ for (j = 0; j < element_count (ty); j++)
> ++ memcpy (&p[j],
> ++ allocate_to_s (context, &state),
> ++ sizeof (*p));
> ++ break;
> ++ }
> ++
> ++ case FFI_TYPE_DOUBLE:
> ++ {
> ++ /* Eeek! We need a pointer to the structure,
> ++ however the homogeneous float elements are
> ++ being passed in individual S registers,
> ++ therefore the structure is not represented as
> ++ a contiguous sequence of bytes in our saved
> ++ register context. We need to fake up a copy
> ++ of the structure laid out in memory
> ++ correctly. The fake can be tossed once the
> ++ closure function has returned hence alloca()
> ++ is sufficient. */
> ++ int j;
> ++ UINT64 *p = avalue[i] = alloca (ty->size);
> ++ for (j = 0; j < element_count (ty); j++)
> ++ memcpy (&p[j],
> ++ allocate_to_d (context, &state),
> ++ sizeof (*p));
> ++ break;
> ++ }
> ++
> ++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
> ++ case FFI_TYPE_LONGDOUBLE:
> ++ memcpy (&avalue[i],
> ++ allocate_to_v (context, &state),
> ++ sizeof (*avalue));
> ++ break;
> ++#endif
> ++
> ++ default:
> ++ FFI_ASSERT (0);
> ++ break;
> ++ }
> ++ }
> ++ }
> ++ else if (ty->size > 16)
> ++ {
> ++ /* Replace Composite type of size greater than 16 with a
> ++ pointer. */
> ++ memcpy (&avalue[i],
> ++ allocate_to_register_or_stack (context, stack,
> ++ &state,
> FFI_TYPE_POINTER),
> ++ sizeof (avalue[i]));
> ++ }
> ++ else if (available_x (&state) >= (ty->size + 7) / 8)
> ++ {
> ++ avalue[i] = get_x_addr (context, state.ngrn);
> ++ state.ngrn += (ty->size + 7) / 8;
> ++ }
> ++ else
> ++ {
> ++ state.ngrn = N_X_ARG_REG;
> ++
> ++ avalue[i] = allocate_to_stack (&state, stack, ty->alignment,
> ++ ty->size);
> ++ }
> ++ break;
> ++
> ++ default:
> ++ FFI_ASSERT (0);
> ++ break;
> ++ }
> ++ }
> ++
> ++ /* Figure out where the return value will be passed, either in
> ++ registers or in a memory block allocated by the caller and passed
> ++ in x8. */
> ++
> ++ if (is_register_candidate (cif->rtype))
> ++ {
> ++ /* Register candidates are *always* returned in registers. */
> ++
> ++ /* Allocate a scratchpad for the return value, we will let the
> ++ callee scrible the result into the scratch pad then move the
> ++ contents into the appropriate return value location for the
> ++ call convention. */
> ++ rvalue = alloca (cif->rtype->size);
> ++ (closure->fun) (cif, rvalue, avalue, closure->user_data);
> ++
> ++ /* Copy the return value into the call context so that it is returned
> ++ as expected to our caller. */
> ++ switch (cif->rtype->type)
> ++ {
> ++ case FFI_TYPE_VOID:
> ++ break;
> ++
> ++ case FFI_TYPE_UINT8:
> ++ case FFI_TYPE_UINT16:
> ++ case FFI_TYPE_UINT32:
> ++ case FFI_TYPE_POINTER:
> ++ case FFI_TYPE_UINT64:
> ++ case FFI_TYPE_SINT8:
> ++ case FFI_TYPE_SINT16:
> ++ case FFI_TYPE_INT:
> ++ case FFI_TYPE_SINT32:
> ++ case FFI_TYPE_SINT64:
> ++ case FFI_TYPE_FLOAT:
> ++ case FFI_TYPE_DOUBLE:
> ++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
> ++ case FFI_TYPE_LONGDOUBLE:
> ++#endif
> ++ {
> ++ void *addr = get_basic_type_addr (cif->rtype->type, context, 0);
> ++ copy_basic_type (addr, rvalue, cif->rtype->type);
> ++ break;
> ++ }
> ++ case FFI_TYPE_STRUCT:
> ++ if (is_hfa (cif->rtype))
> ++ {
> ++ int j;
> ++ unsigned short type = get_homogeneous_type (cif->rtype);
> ++ unsigned elems = element_count (cif->rtype);
> ++ for (j = 0; j < elems; j++)
> ++ {
> ++ void *reg = get_basic_type_addr (type, context, j);
> ++ copy_basic_type (reg, rvalue, type);
> ++ rvalue += get_basic_type_size (type);
> ++ }
> ++ }
> ++ else if ((cif->rtype->size + 7) / 8 < N_X_ARG_REG)
> ++ {
> ++ size_t size = ALIGN (cif->rtype->size, sizeof (UINT64)) ;
> ++ memcpy (get_x_addr (context, 0), rvalue, size);
> ++ }
> ++ else
> ++ {
> ++ FFI_ASSERT (0);
> ++ }
> ++ break;
> ++ default:
> ++ FFI_ASSERT (0);
> ++ break;
> ++ }
> ++ }
> ++ else
> ++ {
> ++ memcpy (&rvalue, get_x_addr (context, 8), sizeof (UINT64));
> ++ (closure->fun) (cif, rvalue, avalue, closure->user_data);
> ++ }
> ++}
> ++
> +diff -ruN Python-2.7.3.orig/Modules/_ctypes/libffi/src/aarch64/ffitarget.h
> Python-2.7.3/Modules/_ctypes/libffi/src/aarch64/ffitarget.h
> +--- Python-2.7.3.orig/Modules/_ctypes/libffi/src/aarch64/ffitarget.h 1970-
> 01-01 01:00:00.000000000 +0100
> ++++ Python-2.7.3/Modules/_ctypes/libffi/src/aarch64/ffitarget.h 2014-
> 04-25 19:45:13.000000000 +0200
> +@@ -0,0 +1,63 @@
> ++/* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd.
> ++
> ++Permission is hereby granted, free of charge, to any person obtaining
> ++a copy of this software and associated documentation files (the
> ++``Software''), to deal in the Software without restriction, including
> ++without limitation the rights to use, copy, modify, merge, publish,
> ++distribute, sublicense, and/or sell copies of the Software, and to
> ++permit persons to whom the Software is furnished to do so, subject to
> ++the following conditions:
> ++
> ++The above copyright notice and this permission notice shall be
> ++included in all copies or substantial portions of the Software.
> ++
> ++THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
> ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
> OF
> ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> NONINFRINGEMENT.
> ++IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
> ANY
> ++CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
> CONTRACT,
> ++TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
> THE
> ++SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
> ++
> ++#ifndef LIBFFI_TARGET_H
> ++#define LIBFFI_TARGET_H
> ++
> ++#ifndef LIBFFI_H
> ++#error "Please do not include ffitarget.h directly into your source. Use
> ffi.h instead."
> ++#endif
> ++
> ++#ifndef LIBFFI_ASM
> ++typedef unsigned long ffi_arg;
> ++typedef signed long ffi_sarg;
> ++
> ++typedef enum ffi_abi
> ++ {
> ++ FFI_FIRST_ABI = 0,
> ++ FFI_SYSV,
> ++ FFI_LAST_ABI,
> ++ FFI_DEFAULT_ABI = FFI_SYSV
> ++ } ffi_abi;
> ++#endif
> ++
> ++/* ---- Definitions for closures ----------------------------------------- */
> ++
> ++#define FFI_CLOSURES 1
> ++#define FFI_TRAMPOLINE_SIZE 36
> ++#define FFI_NATIVE_RAW_API 0
> ++
> ++/* ---- Internal ---- */
> ++
> ++#if defined (__APPLE__)
> ++#define FFI_TARGET_SPECIFIC_VARIADIC
> ++#define FFI_EXTRA_CIF_FIELDS unsigned aarch64_flags; unsigned
> aarch64_nfixedargs
> ++#else
> ++#define FFI_EXTRA_CIF_FIELDS unsigned aarch64_flags
> ++#endif
> ++
> ++#define AARCH64_FFI_WITH_V_BIT 0
> ++
> ++#define AARCH64_N_XREG 32
> ++#define AARCH64_N_VREG 32
> ++#define AARCH64_CALL_CONTEXT_SIZE (AARCH64_N_XREG * 8 +
> AARCH64_N_VREG * 16)
> ++
> ++#endif
> +diff -ruN Python-2.7.3.orig/Modules/_ctypes/libffi/src/aarch64/sysv.S
> Python-2.7.3/Modules/_ctypes/libffi/src/aarch64/sysv.S
> +--- Python-2.7.3.orig/Modules/_ctypes/libffi/src/aarch64/sysv.S 1970-
> 01-01 01:00:00.000000000 +0100
> ++++ Python-2.7.3/Modules/_ctypes/libffi/src/aarch64/sysv.S 2014-04-25
> 19:45:13.000000000 +0200
> +@@ -0,0 +1,333 @@
> ++/* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd.
> ++
> ++Permission is hereby granted, free of charge, to any person obtaining
> ++a copy of this software and associated documentation files (the
> ++``Software''), to deal in the Software without restriction, including
> ++without limitation the rights to use, copy, modify, merge, publish,
> ++distribute, sublicense, and/or sell copies of the Software, and to
> ++permit persons to whom the Software is furnished to do so, subject to
> ++the following conditions:
> ++
> ++The above copyright notice and this permission notice shall be
> ++included in all copies or substantial portions of the Software.
> ++
> ++THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
> ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
> OF
> ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> NONINFRINGEMENT.
> ++IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
> ANY
> ++CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
> CONTRACT,
> ++TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
> THE
> ++SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
> ++
> ++#define LIBFFI_ASM
> ++#include <fficonfig.h>
> ++#include <ffi.h>
> ++
> ++#ifdef HAVE_MACHINE_ASM_H
> ++#include <machine/asm.h>
> ++#else
> ++#ifdef __USER_LABEL_PREFIX__
> ++#define CONCAT1(a, b) CONCAT2(a, b)
> ++#define CONCAT2(a, b) a ## b
> ++
> ++/* Use the right prefix for global labels. */
> ++#define CNAME(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
> ++#else
> ++#define CNAME(x) x
> ++#endif
> ++#endif
> ++
> ++#define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off
> ++#define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off
> ++#define cfi_restore(reg) .cfi_restore reg
> ++#define cfi_def_cfa_register(reg) .cfi_def_cfa_register reg
> ++
> ++ .text
> ++ .globl CNAME(ffi_call_SYSV)
> ++#ifdef __ELF__
> ++ .type CNAME(ffi_call_SYSV), #function
> ++#endif
> ++#ifdef __APPLE__
> ++ .align 2
> ++#endif
> ++
> ++/* ffi_call_SYSV()
> ++
> ++ Create a stack frame, setup an argument context, call the callee
> ++ and extract the result.
> ++
> ++ The maximum required argument stack size is provided,
> ++ ffi_call_SYSV() allocates that stack space then calls the
> ++ prepare_fn to populate register context and stack. The
> ++ argument passing registers are loaded from the register
> ++ context and the callee called, on return the register passing
> ++ register are saved back to the context. Our caller will
> ++ extract the return value from the final state of the saved
> ++ register context.
> ++
> ++ Prototype:
> ++
> ++ extern unsigned
> ++ ffi_call_SYSV (void (*)(struct call_context *context, unsigned char *,
> ++ extended_cif *),
> ++ struct call_context *context,
> ++ extended_cif *,
> ++ size_t required_stack_size,
> ++ void (*fn)(void));
> ++
> ++ Therefore on entry we have:
> ++
> ++ x0 prepare_fn
> ++ x1 &context
> ++ x2 &ecif
> ++ x3 bytes
> ++ x4 fn
> ++
> ++ This function uses the following stack frame layout:
> ++
> ++ ==
> ++ saved x30(lr)
> ++ x29(fp)-> saved x29(fp)
> ++ saved x24
> ++ saved x23
> ++ saved x22
> ++ sp' -> saved x21
> ++ ...
> ++ sp -> (constructed callee stack arguments)
> ++ ==
> ++
> ++ Voila! */
> ++
> ++#define ffi_call_SYSV_FS (8 * 4)
> ++
> ++ .cfi_startproc
> ++CNAME(ffi_call_SYSV):
> ++ stp x29, x30, [sp, #-16]!
> ++ cfi_adjust_cfa_offset (16)
> ++ cfi_rel_offset (x29, 0)
> ++ cfi_rel_offset (x30, 8)
> ++
> ++ mov x29, sp
> ++ cfi_def_cfa_register (x29)
> ++ sub sp, sp, #ffi_call_SYSV_FS
> ++
> ++ stp x21, x22, [sp, #0]
> ++ cfi_rel_offset (x21, 0 - ffi_call_SYSV_FS)
> ++ cfi_rel_offset (x22, 8 - ffi_call_SYSV_FS)
> ++
> ++ stp x23, x24, [sp, #16]
> ++ cfi_rel_offset (x23, 16 - ffi_call_SYSV_FS)
> ++ cfi_rel_offset (x24, 24 - ffi_call_SYSV_FS)
> ++
> ++ mov x21, x1
> ++ mov x22, x2
> ++ mov x24, x4
> ++
> ++ /* Allocate the stack space for the actual arguments, many
> ++ arguments will be passed in registers, but we assume
> ++ worst case and allocate sufficient stack for ALL of
> ++ the arguments. */
> ++ sub sp, sp, x3
> ++
> ++ /* unsigned (*prepare_fn) (struct call_context *context,
> ++ unsigned char *stack, extended_cif *ecif);
> ++ */
> ++ mov x23, x0
> ++ mov x0, x1
> ++ mov x1, sp
> ++ /* x2 already in place */
> ++ blr x23
> ++
> ++ /* Preserve the flags returned. */
> ++ mov x23, x0
> ++
> ++ /* Figure out if we should touch the vector registers. */
> ++ tbz x23, #AARCH64_FFI_WITH_V_BIT, 1f
> ++
> ++ /* Load the vector argument passing registers. */
> ++ ldp q0, q1, [x21, #8*32 + 0]
> ++ ldp q2, q3, [x21, #8*32 + 32]
> ++ ldp q4, q5, [x21, #8*32 + 64]
> ++ ldp q6, q7, [x21, #8*32 + 96]
> ++1:
> ++ /* Load the core argument passing registers. */
> ++ ldp x0, x1, [x21, #0]
> ++ ldp x2, x3, [x21, #16]
> ++ ldp x4, x5, [x21, #32]
> ++ ldp x6, x7, [x21, #48]
> ++
> ++ /* Don't forget x8 which may be holding the address of a return
> buffer.
> ++ */
> ++ ldr x8, [x21, #8*8]
> ++
> ++ blr x24
> ++
> ++ /* Save the core argument passing registers. */
> ++ stp x0, x1, [x21, #0]
> ++ stp x2, x3, [x21, #16]
> ++ stp x4, x5, [x21, #32]
> ++ stp x6, x7, [x21, #48]
> ++
> ++ /* Note nothing useful ever comes back in x8! */
> ++
> ++ /* Figure out if we should touch the vector registers. */
> ++ tbz x23, #AARCH64_FFI_WITH_V_BIT, 1f
> ++
> ++ /* Save the vector argument passing registers. */
> ++ stp q0, q1, [x21, #8*32 + 0]
> ++ stp q2, q3, [x21, #8*32 + 32]
> ++ stp q4, q5, [x21, #8*32 + 64]
> ++ stp q6, q7, [x21, #8*32 + 96]
> ++1:
> ++ /* All done, unwind our stack frame. */
> ++ ldp x21, x22, [x29, # - ffi_call_SYSV_FS]
> ++ cfi_restore (x21)
> ++ cfi_restore (x22)
> ++
> ++ ldp x23, x24, [x29, # - ffi_call_SYSV_FS + 16]
> ++ cfi_restore (x23)
> ++ cfi_restore (x24)
> ++
> ++ mov sp, x29
> ++ cfi_def_cfa_register (sp)
> ++
> ++ ldp x29, x30, [sp], #16
> ++ cfi_adjust_cfa_offset (-16)
> ++ cfi_restore (x29)
> ++ cfi_restore (x30)
> ++
> ++ ret
> ++
> ++ .cfi_endproc
> ++#ifdef __ELF__
> ++ .size CNAME(ffi_call_SYSV), .-CNAME(ffi_call_SYSV)
> ++#endif
> ++
> ++#define ffi_closure_SYSV_FS (8 * 2 + AARCH64_CALL_CONTEXT_SIZE)
> ++
> ++/* ffi_closure_SYSV
> ++
> ++ Closure invocation glue. This is the low level code invoked directly by
> ++ the closure trampoline to setup and call a closure.
> ++
> ++ On entry x17 points to a struct trampoline_data, x16 has been clobbered
> ++ all other registers are preserved.
> ++
> ++ We allocate a call context and save the argument passing registers,
> ++ then invoked the generic C ffi_closure_SYSV_inner() function to do all
> ++ the real work, on return we load the result passing registers back from
> ++ the call context.
> ++
> ++ On entry
> ++
> ++ extern void
> ++ ffi_closure_SYSV (struct trampoline_data *);
> ++
> ++ struct trampoline_data
> ++ {
> ++ UINT64 *ffi_closure;
> ++ UINT64 flags;
> ++ };
> ++
> ++ This function uses the following stack frame layout:
> ++
> ++ ==
> ++ saved x30(lr)
> ++ x29(fp)-> saved x29(fp)
> ++ saved x22
> ++ saved x21
> ++ ...
> ++ sp -> call_context
> ++ ==
> ++
> ++ Voila! */
> ++
> ++ .text
> ++ .globl CNAME(ffi_closure_SYSV)
> ++#ifdef __APPLE__
> ++ .align 2
> ++#endif
> ++ .cfi_startproc
> ++CNAME(ffi_closure_SYSV):
> ++ stp x29, x30, [sp, #-16]!
> ++ cfi_adjust_cfa_offset (16)
> ++ cfi_rel_offset (x29, 0)
> ++ cfi_rel_offset (x30, 8)
> ++
> ++ mov x29, sp
> ++ cfi_def_cfa_register (x29)
> ++
> ++ sub sp, sp, #ffi_closure_SYSV_FS
> ++
> ++ stp x21, x22, [x29, #-16]
> ++ cfi_rel_offset (x21, -16)
> ++ cfi_rel_offset (x22, -8)
> ++
> ++ /* Load x21 with &call_context. */
> ++ mov x21, sp
> ++ /* Preserve our struct trampoline_data * */
> ++ mov x22, x17
> ++
> ++ /* Save the rest of the argument passing registers. */
> ++ stp x0, x1, [x21, #0]
> ++ stp x2, x3, [x21, #16]
> ++ stp x4, x5, [x21, #32]
> ++ stp x6, x7, [x21, #48]
> ++ /* Don't forget we may have been given a result scratch pad address.
> ++ */
> ++ str x8, [x21, #64]
> ++
> ++ /* Figure out if we should touch the vector registers. */
> ++ ldr x0, [x22, #8]
> ++ tbz x0, #AARCH64_FFI_WITH_V_BIT, 1f
> ++
> ++ /* Save the argument passing vector registers. */
> ++ stp q0, q1, [x21, #8*32 + 0]
> ++ stp q2, q3, [x21, #8*32 + 32]
> ++ stp q4, q5, [x21, #8*32 + 64]
> ++ stp q6, q7, [x21, #8*32 + 96]
> ++1:
> ++ /* Load &ffi_closure.. */
> ++ ldr x0, [x22, #0]
> ++ mov x1, x21
> ++ /* Compute the location of the stack at the point that the
> ++ trampoline was called. */
> ++ add x2, x29, #16
> ++
> ++ bl CNAME(ffi_closure_SYSV_inner)
> ++
> ++ /* Figure out if we should touch the vector registers. */
> ++ ldr x0, [x22, #8]
> ++ tbz x0, #AARCH64_FFI_WITH_V_BIT, 1f
> ++
> ++ /* Load the result passing vector registers. */
> ++ ldp q0, q1, [x21, #8*32 + 0]
> ++ ldp q2, q3, [x21, #8*32 + 32]
> ++ ldp q4, q5, [x21, #8*32 + 64]
> ++ ldp q6, q7, [x21, #8*32 + 96]
> ++1:
> ++ /* Load the result passing core registers. */
> ++ ldp x0, x1, [x21, #0]
> ++ ldp x2, x3, [x21, #16]
> ++ ldp x4, x5, [x21, #32]
> ++ ldp x6, x7, [x21, #48]
> ++ /* Note nothing useful is returned in x8. */
> ++
> ++ /* We are done, unwind our frame. */
> ++ ldp x21, x22, [x29, #-16]
> ++ cfi_restore (x21)
> ++ cfi_restore (x22)
> ++
> ++ mov sp, x29
> ++ cfi_def_cfa_register (sp)
> ++
> ++ ldp x29, x30, [sp], #16
> ++ cfi_adjust_cfa_offset (-16)
> ++ cfi_restore (x29)
> ++ cfi_restore (x30)
> ++
> ++ ret
> ++ .cfi_endproc
> ++#ifdef __ELF__
> ++ .size CNAME(ffi_closure_SYSV), .-CNAME(ffi_closure_SYSV)
> ++#endif
> diff --git a/meta/recipes-devtools/python/python_2.7.3.bb b/meta/recipes-
> devtools/python/python_2.7.3.bb
> index cbe8d7f..de1f57f 100644
> --- a/meta/recipes-devtools/python/python_2.7.3.bb
> +++ b/meta/recipes-devtools/python/python_2.7.3.bb
> @@ -40,6 +40,8 @@ SRC_URI += "\
> file://posix_close.patch \
> file://python-2.7.3-CVE-2014-7185.patch \
> file://python2.7.3-nossl3.patch \
> + file://ctypes-libffi-aarch64.patch \
> + file://libffi-aarch64.patch \
> "
>
> S = "${WORKDIR}/Python-${PV}"
> --
> 1.9.1
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [dizzy] [PATCH 1/1] python: Add support for aarch64 for ctypes module
2015-03-10 0:24 ` Tudor Florea
@ 2015-03-11 13:42 ` akuster808
0 siblings, 0 replies; 5+ messages in thread
From: akuster808 @ 2015-03-11 13:42 UTC (permalink / raw)
To: openembedded-core
Tudor,
I don't think aarch64 was supported in dizzy. If I find examples where
it's support has been accept then I will consider letting this in.
- Armin
On 03/09/2015 05:24 PM, Tudor Florea wrote:
> Ping.
>
>> -----Original Message-----
>> From: Tudor Florea [mailto:tudor.florea@enea.com]
>> Sent: Wednesday, March 04, 2015 17:04
>> To: openembedded-core@lists.openembedded.org
>> Cc: Tudor Florea
>> Subject: [dizzy] [PATCH 1/1] python: Add support for aarch64 for ctypes
>> module
>>
>> Python have its own version of libffi used for ctypes module.
>> libffi 3.0.10 contained in original source of Python-2.7.3 does not have
>> support for aarch64 architecture.
>> This is patch is backport support for aarch64 from libffi 3.1
>> ---
>> .../python/python/ctypes-libffi-aarch64.patch | 22 +
>> .../python/python/libffi-aarch64.patch | 1608
>> ++++++++++++++++++++
>> meta/recipes-devtools/python/python_2.7.3.bb | 2 +
>> 3 files changed, 1632 insertions(+)
>> create mode 100644 meta/recipes-devtools/python/python/ctypes-libffi-
>> aarch64.patch
>> create mode 100644 meta/recipes-devtools/python/python/libffi-
>> aarch64.patch
>>
>> diff --git a/meta/recipes-devtools/python/python/ctypes-libffi-
>> aarch64.patch b/meta/recipes-devtools/python/python/ctypes-libffi-
>> aarch64.patch
>> new file mode 100644
>> index 0000000..7349c7b
>> --- /dev/null
>> +++ b/meta/recipes-devtools/python/python/ctypes-libffi-aarch64.patch
>> @@ -0,0 +1,22 @@
>> +Add missing fficonfig.py bits for aarch64
>> +
>> +# HG changeset patch
>> +# User Andreas Schwab <schwab@suse.de>
>> +# Date 1367276434 -7200
>> +# Node ID 05e8999a3901b4853e60d6701510e9b3dd54a7f3
>> +# Parent 84cef4f1999ad9e362694cdac2f65f0981e3d5d0
>> +
>> +Upstream-Status: Backport
>> +Signed-off-by: Tudor Florea <tudor.florea@enea.com>
>> +
>> +diff -r 84cef4f1999a -r 05e8999a3901 Modules/_ctypes/libffi/fficonfig.py.in
>> +--- a/Modules/_ctypes/libffi/fficonfig.py.in Mon Apr 29 16:09:39 2013 -
>> 0400
>> ++++ b/Modules/_ctypes/libffi/fficonfig.py.in Tue Apr 30 01:00:34 2013
>> +0200
>> +@@ -28,6 +28,7 @@
>> + 'PA': ['src/pa/linux.S', 'src/pa/ffi.c'],
>> + 'PA_LINUX': ['src/pa/linux.S', 'src/pa/ffi.c'],
>> + 'PA_HPUX': ['src/pa/hpux32.S', 'src/pa/ffi.c'],
>> ++ 'AARCH64' : ['src/aarch64/ffi.c', 'src/aarch64/sysv.S'],
>> + }
>> +
>> + ffi_sources += ffi_platforms['@TARGET@']
>> diff --git a/meta/recipes-devtools/python/python/libffi-aarch64.patch
>> b/meta/recipes-devtools/python/python/libffi-aarch64.patch
>> new file mode 100644
>> index 0000000..5581922
>> --- /dev/null
>> +++ b/meta/recipes-devtools/python/python/libffi-aarch64.patch
>> @@ -0,0 +1,1608 @@
>> +Add support for aarch64 for ctypes module
>> +
>> +Python have its own version of libffi used for ctypes module.
>> +libffi 3.0.10 contained in original source of Python-2.7.3 does not have
>> +support for aarch64 architecture.
>> +This is patch is backport support for aarch64 from libffi 3.1
>> +
>> +Upstream-Status: Backport
>> +Signed-off-by: Tudor Florea <tudor.florea@enea.com>
>> +
>> +diff -ruN Python-2.7.3.orig/Modules/_ctypes/libffi/configure.ac Python-
>> 2.7.3/Modules/_ctypes/libffi/configure.ac
>> +--- Python-2.7.3.orig/Modules/_ctypes/libffi/configure.ac 2015-02-27
>> 23:15:16.118393178 +0100
>> ++++ Python-2.7.3/Modules/_ctypes/libffi/configure.ac 2015-02-27
>> 23:51:03.351556903 +0100
>> +@@ -44,6 +44,10 @@
>> +
>> + TARGETDIR="unknown"
>> + case "$host" in
>> ++ aarch64*-*-*)
>> ++ TARGET=AARCH64; TARGETDIR=aarch64
>> ++ ;;
>> ++
>> + alpha*-*-*)
>> + TARGET=ALPHA; TARGETDIR=alpha;
>> + # Support 128-bit long double, changeable via command-line switch.
>> +@@ -195,6 +199,7 @@
>> + AM_CONDITIONAL(POWERPC_AIX, test x$TARGET = xPOWERPC_AIX)
>> + AM_CONDITIONAL(POWERPC_DARWIN, test x$TARGET =
>> xPOWERPC_DARWIN)
>> + AM_CONDITIONAL(POWERPC_FREEBSD, test x$TARGET =
>> xPOWERPC_FREEBSD)
>> ++AM_CONDITIONAL(AARCH64, test x$TARGET = xAARCH64)
>> + AM_CONDITIONAL(ARM, test x$TARGET = xARM)
>> + AM_CONDITIONAL(AVR32, test x$TARGET = xAVR32)
>> + AM_CONDITIONAL(LIBFFI_CRIS, test x$TARGET = xLIBFFI_CRIS)
>> +diff -ruN Python-2.7.3.orig/Modules/_ctypes/libffi/src/aarch64/ffi.c
>> Python-2.7.3/Modules/_ctypes/libffi/src/aarch64/ffi.c
>> +--- Python-2.7.3.orig/Modules/_ctypes/libffi/src/aarch64/ffi.c 1970-
>> 01-01 01:00:00.000000000 +0100
>> ++++ Python-2.7.3/Modules/_ctypes/libffi/src/aarch64/ffi.c 2014-04-25
>> 19:45:13.000000000 +0200
>> +@@ -0,0 +1,1168 @@
>> ++/* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd.
>> ++
>> ++Permission is hereby granted, free of charge, to any person obtaining
>> ++a copy of this software and associated documentation files (the
>> ++``Software''), to deal in the Software without restriction, including
>> ++without limitation the rights to use, copy, modify, merge, publish,
>> ++distribute, sublicense, and/or sell copies of the Software, and to
>> ++permit persons to whom the Software is furnished to do so, subject to
>> ++the following conditions:
>> ++
>> ++The above copyright notice and this permission notice shall be
>> ++included in all copies or substantial portions of the Software.
>> ++
>> ++THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
>> ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
>> OF
>> ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
>> NONINFRINGEMENT.
>> ++IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
>> ANY
>> ++CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
>> CONTRACT,
>> ++TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
>> THE
>> ++SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
>> ++
>> ++#include <stdio.h>
>> ++
>> ++#include <ffi.h>
>> ++#include <ffi_common.h>
>> ++
>> ++#include <stdlib.h>
>> ++
>> ++/* Stack alignment requirement in bytes */
>> ++#if defined (__APPLE__)
>> ++#define AARCH64_STACK_ALIGN 1
>> ++#else
>> ++#define AARCH64_STACK_ALIGN 16
>> ++#endif
>> ++
>> ++#define N_X_ARG_REG 8
>> ++#define N_V_ARG_REG 8
>> ++
>> ++#define AARCH64_FFI_WITH_V (1 << AARCH64_FFI_WITH_V_BIT)
>> ++
>> ++union _d
>> ++{
>> ++ UINT64 d;
>> ++ UINT32 s[2];
>> ++};
>> ++
>> ++struct call_context
>> ++{
>> ++ UINT64 x [AARCH64_N_XREG];
>> ++ struct
>> ++ {
>> ++ union _d d[2];
>> ++ } v [AARCH64_N_VREG];
>> ++};
>> ++
>> ++#if defined (__clang__) && defined (__APPLE__)
>> ++extern void
>> ++sys_icache_invalidate (void *start, size_t len);
>> ++#endif
>> ++
>> ++static inline void
>> ++ffi_clear_cache (void *start, void *end)
>> ++{
>> ++#if defined (__clang__) && defined (__APPLE__)
>> ++ sys_icache_invalidate (start, (char *)end - (char *)start);
>> ++#elif defined (__GNUC__)
>> ++ __builtin___clear_cache (start, end);
>> ++#else
>> ++#error "Missing builtin to flush instruction cache"
>> ++#endif
>> ++}
>> ++
>> ++static void *
>> ++get_x_addr (struct call_context *context, unsigned n)
>> ++{
>> ++ return &context->x[n];
>> ++}
>> ++
>> ++static void *
>> ++get_s_addr (struct call_context *context, unsigned n)
>> ++{
>> ++#if defined __AARCH64EB__
>> ++ return &context->v[n].d[1].s[1];
>> ++#else
>> ++ return &context->v[n].d[0].s[0];
>> ++#endif
>> ++}
>> ++
>> ++static void *
>> ++get_d_addr (struct call_context *context, unsigned n)
>> ++{
>> ++#if defined __AARCH64EB__
>> ++ return &context->v[n].d[1];
>> ++#else
>> ++ return &context->v[n].d[0];
>> ++#endif
>> ++}
>> ++
>> ++static void *
>> ++get_v_addr (struct call_context *context, unsigned n)
>> ++{
>> ++ return &context->v[n];
>> ++}
>> ++
>> ++/* Return the memory location at which a basic type would reside
>> ++ were it to have been stored in register n. */
>> ++
>> ++static void *
>> ++get_basic_type_addr (unsigned short type, struct call_context *context,
>> ++ unsigned n)
>> ++{
>> ++ switch (type)
>> ++ {
>> ++ case FFI_TYPE_FLOAT:
>> ++ return get_s_addr (context, n);
>> ++ case FFI_TYPE_DOUBLE:
>> ++ return get_d_addr (context, n);
>> ++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
>> ++ case FFI_TYPE_LONGDOUBLE:
>> ++ return get_v_addr (context, n);
>> ++#endif
>> ++ case FFI_TYPE_UINT8:
>> ++ case FFI_TYPE_SINT8:
>> ++ case FFI_TYPE_UINT16:
>> ++ case FFI_TYPE_SINT16:
>> ++ case FFI_TYPE_UINT32:
>> ++ case FFI_TYPE_SINT32:
>> ++ case FFI_TYPE_INT:
>> ++ case FFI_TYPE_POINTER:
>> ++ case FFI_TYPE_UINT64:
>> ++ case FFI_TYPE_SINT64:
>> ++ return get_x_addr (context, n);
>> ++ case FFI_TYPE_VOID:
>> ++ return NULL;
>> ++ default:
>> ++ FFI_ASSERT (0);
>> ++ return NULL;
>> ++ }
>> ++}
>> ++
>> ++/* Return the alignment width for each of the basic types. */
>> ++
>> ++static size_t
>> ++get_basic_type_alignment (unsigned short type)
>> ++{
>> ++ switch (type)
>> ++ {
>> ++ case FFI_TYPE_FLOAT:
>> ++ case FFI_TYPE_DOUBLE:
>> ++ return sizeof (UINT64);
>> ++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
>> ++ case FFI_TYPE_LONGDOUBLE:
>> ++ return sizeof (long double);
>> ++#endif
>> ++ case FFI_TYPE_UINT8:
>> ++ case FFI_TYPE_SINT8:
>> ++#if defined (__APPLE__)
>> ++ return sizeof (UINT8);
>> ++#endif
>> ++ case FFI_TYPE_UINT16:
>> ++ case FFI_TYPE_SINT16:
>> ++#if defined (__APPLE__)
>> ++ return sizeof (UINT16);
>> ++#endif
>> ++ case FFI_TYPE_UINT32:
>> ++ case FFI_TYPE_INT:
>> ++ case FFI_TYPE_SINT32:
>> ++#if defined (__APPLE__)
>> ++ return sizeof (UINT32);
>> ++#endif
>> ++ case FFI_TYPE_POINTER:
>> ++ case FFI_TYPE_UINT64:
>> ++ case FFI_TYPE_SINT64:
>> ++ return sizeof (UINT64);
>> ++
>> ++ default:
>> ++ FFI_ASSERT (0);
>> ++ return 0;
>> ++ }
>> ++}
>> ++
>> ++/* Return the size in bytes for each of the basic types. */
>> ++
>> ++static size_t
>> ++get_basic_type_size (unsigned short type)
>> ++{
>> ++ switch (type)
>> ++ {
>> ++ case FFI_TYPE_FLOAT:
>> ++ return sizeof (UINT32);
>> ++ case FFI_TYPE_DOUBLE:
>> ++ return sizeof (UINT64);
>> ++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
>> ++ case FFI_TYPE_LONGDOUBLE:
>> ++ return sizeof (long double);
>> ++#endif
>> ++ case FFI_TYPE_UINT8:
>> ++ return sizeof (UINT8);
>> ++ case FFI_TYPE_SINT8:
>> ++ return sizeof (SINT8);
>> ++ case FFI_TYPE_UINT16:
>> ++ return sizeof (UINT16);
>> ++ case FFI_TYPE_SINT16:
>> ++ return sizeof (SINT16);
>> ++ case FFI_TYPE_UINT32:
>> ++ return sizeof (UINT32);
>> ++ case FFI_TYPE_INT:
>> ++ case FFI_TYPE_SINT32:
>> ++ return sizeof (SINT32);
>> ++ case FFI_TYPE_POINTER:
>> ++ case FFI_TYPE_UINT64:
>> ++ return sizeof (UINT64);
>> ++ case FFI_TYPE_SINT64:
>> ++ return sizeof (SINT64);
>> ++
>> ++ default:
>> ++ FFI_ASSERT (0);
>> ++ return 0;
>> ++ }
>> ++}
>> ++
>> ++extern void
>> ++ffi_call_SYSV (unsigned (*)(struct call_context *context, unsigned char *,
>> ++ extended_cif *),
>> ++ struct call_context *context,
>> ++ extended_cif *,
>> ++ size_t,
>> ++ void (*fn)(void));
>> ++
>> ++extern void
>> ++ffi_closure_SYSV (ffi_closure *);
>> ++
>> ++/* Test for an FFI floating point representation. */
>> ++
>> ++static unsigned
>> ++is_floating_type (unsigned short type)
>> ++{
>> ++ return (type == FFI_TYPE_FLOAT || type == FFI_TYPE_DOUBLE
>> ++ || type == FFI_TYPE_LONGDOUBLE);
>> ++}
>> ++
>> ++/* Test for a homogeneous structure. */
>> ++
>> ++static unsigned short
>> ++get_homogeneous_type (ffi_type *ty)
>> ++{
>> ++ if (ty->type == FFI_TYPE_STRUCT && ty->elements)
>> ++ {
>> ++ unsigned i;
>> ++ unsigned short candidate_type
>> ++ = get_homogeneous_type (ty->elements[0]);
>> ++ for (i =1; ty->elements[i]; i++)
>> ++ {
>> ++ unsigned short iteration_type = 0;
>> ++ /* If we have a nested struct, we must find its homogeneous type.
>> ++ If that fits with our candidate type, we are still
>> ++ homogeneous. */
>> ++ if (ty->elements[i]->type == FFI_TYPE_STRUCT
>> ++ && ty->elements[i]->elements)
>> ++ {
>> ++ iteration_type = get_homogeneous_type (ty->elements[i]);
>> ++ }
>> ++ else
>> ++ {
>> ++ iteration_type = ty->elements[i]->type;
>> ++ }
>> ++
>> ++ /* If we are not homogeneous, return FFI_TYPE_STRUCT. */
>> ++ if (candidate_type != iteration_type)
>> ++ return FFI_TYPE_STRUCT;
>> ++ }
>> ++ return candidate_type;
>> ++ }
>> ++
>> ++ /* Base case, we have no more levels of nesting, so we
>> ++ are a basic type, and so, trivially homogeneous in that type. */
>> ++ return ty->type;
>> ++}
>> ++
>> ++/* Determine the number of elements within a STRUCT.
>> ++
>> ++ Note, we must handle nested structs.
>> ++
>> ++ If ty is not a STRUCT this function will return 0. */
>> ++
>> ++static unsigned
>> ++element_count (ffi_type *ty)
>> ++{
>> ++ if (ty->type == FFI_TYPE_STRUCT && ty->elements)
>> ++ {
>> ++ unsigned n;
>> ++ unsigned elems = 0;
>> ++ for (n = 0; ty->elements[n]; n++)
>> ++ {
>> ++ if (ty->elements[n]->type == FFI_TYPE_STRUCT
>> ++ && ty->elements[n]->elements)
>> ++ elems += element_count (ty->elements[n]);
>> ++ else
>> ++ elems++;
>> ++ }
>> ++ return elems;
>> ++ }
>> ++ return 0;
>> ++}
>> ++
>> ++/* Test for a homogeneous floating point aggregate.
>> ++
>> ++ A homogeneous floating point aggregate is a homogeneous aggregate of
>> ++ a half- single- or double- precision floating point type with one
>> ++ to four elements. Note that this includes nested structs of the
>> ++ basic type. */
>> ++
>> ++static int
>> ++is_hfa (ffi_type *ty)
>> ++{
>> ++ if (ty->type == FFI_TYPE_STRUCT
>> ++ && ty->elements[0]
>> ++ && is_floating_type (get_homogeneous_type (ty)))
>> ++ {
>> ++ unsigned n = element_count (ty);
>> ++ return n >= 1 && n <= 4;
>> ++ }
>> ++ return 0;
>> ++}
>> ++
>> ++/* Test if an ffi_type is a candidate for passing in a register.
>> ++
>> ++ This test does not check that sufficient registers of the
>> ++ appropriate class are actually available, merely that IFF
>> ++ sufficient registers are available then the argument will be passed
>> ++ in register(s).
>> ++
>> ++ Note that an ffi_type that is deemed to be a register candidate
>> ++ will always be returned in registers.
>> ++
>> ++ Returns 1 if a register candidate else 0. */
>> ++
>> ++static int
>> ++is_register_candidate (ffi_type *ty)
>> ++{
>> ++ switch (ty->type)
>> ++ {
>> ++ case FFI_TYPE_VOID:
>> ++ case FFI_TYPE_FLOAT:
>> ++ case FFI_TYPE_DOUBLE:
>> ++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
>> ++ case FFI_TYPE_LONGDOUBLE:
>> ++#endif
>> ++ case FFI_TYPE_UINT8:
>> ++ case FFI_TYPE_UINT16:
>> ++ case FFI_TYPE_UINT32:
>> ++ case FFI_TYPE_UINT64:
>> ++ case FFI_TYPE_POINTER:
>> ++ case FFI_TYPE_SINT8:
>> ++ case FFI_TYPE_SINT16:
>> ++ case FFI_TYPE_SINT32:
>> ++ case FFI_TYPE_INT:
>> ++ case FFI_TYPE_SINT64:
>> ++ return 1;
>> ++
>> ++ case FFI_TYPE_STRUCT:
>> ++ if (is_hfa (ty))
>> ++ {
>> ++ return 1;
>> ++ }
>> ++ else if (ty->size > 16)
>> ++ {
>> ++ /* Too large. Will be replaced with a pointer to memory. The
>> ++ pointer MAY be passed in a register, but the value will
>> ++ not. This test specifically fails since the argument will
>> ++ never be passed by value in registers. */
>> ++ return 0;
>> ++ }
>> ++ else
>> ++ {
>> ++ /* Might be passed in registers depending on the number of
>> ++ registers required. */
>> ++ return (ty->size + 7) / 8 < N_X_ARG_REG;
>> ++ }
>> ++ break;
>> ++
>> ++ default:
>> ++ FFI_ASSERT (0);
>> ++ break;
>> ++ }
>> ++
>> ++ return 0;
>> ++}
>> ++
>> ++/* Test if an ffi_type argument or result is a candidate for a vector
>> ++ register. */
>> ++
>> ++static int
>> ++is_v_register_candidate (ffi_type *ty)
>> ++{
>> ++ return is_floating_type (ty->type)
>> ++ || (ty->type == FFI_TYPE_STRUCT && is_hfa (ty));
>> ++}
>> ++
>> ++/* Representation of the procedure call argument marshalling
>> ++ state.
>> ++
>> ++ The terse state variable names match the names used in the AARCH64
>> ++ PCS. */
>> ++
>> ++struct arg_state
>> ++{
>> ++ unsigned ngrn; /* Next general-purpose register number. */
>> ++ unsigned nsrn; /* Next vector register number. */
>> ++ size_t nsaa; /* Next stack offset. */
>> ++
>> ++#if defined (__APPLE__)
>> ++ unsigned allocating_variadic;
>> ++#endif
>> ++};
>> ++
>> ++/* Initialize a procedure call argument marshalling state. */
>> ++static void
>> ++arg_init (struct arg_state *state, size_t call_frame_size)
>> ++{
>> ++ state->ngrn = 0;
>> ++ state->nsrn = 0;
>> ++ state->nsaa = 0;
>> ++
>> ++#if defined (__APPLE__)
>> ++ state->allocating_variadic = 0;
>> ++#endif
>> ++}
>> ++
>> ++/* Return the number of available consecutive core argument
>> ++ registers. */
>> ++
>> ++static unsigned
>> ++available_x (struct arg_state *state)
>> ++{
>> ++ return N_X_ARG_REG - state->ngrn;
>> ++}
>> ++
>> ++/* Return the number of available consecutive vector argument
>> ++ registers. */
>> ++
>> ++static unsigned
>> ++available_v (struct arg_state *state)
>> ++{
>> ++ return N_V_ARG_REG - state->nsrn;
>> ++}
>> ++
>> ++static void *
>> ++allocate_to_x (struct call_context *context, struct arg_state *state)
>> ++{
>> ++ FFI_ASSERT (state->ngrn < N_X_ARG_REG);
>> ++ return get_x_addr (context, (state->ngrn)++);
>> ++}
>> ++
>> ++static void *
>> ++allocate_to_s (struct call_context *context, struct arg_state *state)
>> ++{
>> ++ FFI_ASSERT (state->nsrn < N_V_ARG_REG);
>> ++ return get_s_addr (context, (state->nsrn)++);
>> ++}
>> ++
>> ++static void *
>> ++allocate_to_d (struct call_context *context, struct arg_state *state)
>> ++{
>> ++ FFI_ASSERT (state->nsrn < N_V_ARG_REG);
>> ++ return get_d_addr (context, (state->nsrn)++);
>> ++}
>> ++
>> ++static void *
>> ++allocate_to_v (struct call_context *context, struct arg_state *state)
>> ++{
>> ++ FFI_ASSERT (state->nsrn < N_V_ARG_REG);
>> ++ return get_v_addr (context, (state->nsrn)++);
>> ++}
>> ++
>> ++/* Allocate an aligned slot on the stack and return a pointer to it. */
>> ++static void *
>> ++allocate_to_stack (struct arg_state *state, void *stack, size_t alignment,
>> ++ size_t size)
>> ++{
>> ++ void *allocation;
>> ++
>> ++ /* Round up the NSAA to the larger of 8 or the natural
>> ++ alignment of the argument's type. */
>> ++ state->nsaa = ALIGN (state->nsaa, alignment);
>> ++ state->nsaa = ALIGN (state->nsaa, alignment);
>> ++#if defined (__APPLE__)
>> ++ if (state->allocating_variadic)
>> ++ state->nsaa = ALIGN (state->nsaa, 8);
>> ++#else
>> ++ state->nsaa = ALIGN (state->nsaa, 8);
>> ++#endif
>> ++
>> ++ allocation = stack + state->nsaa;
>> ++
>> ++ state->nsaa += size;
>> ++ return allocation;
>> ++}
>> ++
>> ++static void
>> ++copy_basic_type (void *dest, void *source, unsigned short type)
>> ++{
>> ++ /* This is necessary to ensure that basic types are copied
>> ++ sign extended to 64-bits as libffi expects. */
>> ++ switch (type)
>> ++ {
>> ++ case FFI_TYPE_FLOAT:
>> ++ *(float *) dest = *(float *) source;
>> ++ break;
>> ++ case FFI_TYPE_DOUBLE:
>> ++ *(double *) dest = *(double *) source;
>> ++ break;
>> ++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
>> ++ case FFI_TYPE_LONGDOUBLE:
>> ++ *(long double *) dest = *(long double *) source;
>> ++ break;
>> ++#endif
>> ++ case FFI_TYPE_UINT8:
>> ++ *(ffi_arg *) dest = *(UINT8 *) source;
>> ++ break;
>> ++ case FFI_TYPE_SINT8:
>> ++ *(ffi_sarg *) dest = *(SINT8 *) source;
>> ++ break;
>> ++ case FFI_TYPE_UINT16:
>> ++ *(ffi_arg *) dest = *(UINT16 *) source;
>> ++ break;
>> ++ case FFI_TYPE_SINT16:
>> ++ *(ffi_sarg *) dest = *(SINT16 *) source;
>> ++ break;
>> ++ case FFI_TYPE_UINT32:
>> ++ *(ffi_arg *) dest = *(UINT32 *) source;
>> ++ break;
>> ++ case FFI_TYPE_INT:
>> ++ case FFI_TYPE_SINT32:
>> ++ *(ffi_sarg *) dest = *(SINT32 *) source;
>> ++ break;
>> ++ case FFI_TYPE_POINTER:
>> ++ case FFI_TYPE_UINT64:
>> ++ *(ffi_arg *) dest = *(UINT64 *) source;
>> ++ break;
>> ++ case FFI_TYPE_SINT64:
>> ++ *(ffi_sarg *) dest = *(SINT64 *) source;
>> ++ break;
>> ++ case FFI_TYPE_VOID:
>> ++ break;
>> ++
>> ++ default:
>> ++ FFI_ASSERT (0);
>> ++ }
>> ++}
>> ++
>> ++static void
>> ++copy_hfa_to_reg_or_stack (void *memory,
>> ++ ffi_type *ty,
>> ++ struct call_context *context,
>> ++ unsigned char *stack,
>> ++ struct arg_state *state)
>> ++{
>> ++ unsigned elems = element_count (ty);
>> ++ if (available_v (state) < elems)
>> ++ {
>> ++ /* There are insufficient V registers. Further V register allocations
>> ++ are prevented, the NSAA is adjusted (by allocate_to_stack ())
>> ++ and the argument is copied to memory at the adjusted NSAA. */
>> ++ state->nsrn = N_V_ARG_REG;
>> ++ memcpy (allocate_to_stack (state, stack, ty->alignment, ty->size),
>> ++ memory,
>> ++ ty->size);
>> ++ }
>> ++ else
>> ++ {
>> ++ int i;
>> ++ unsigned short type = get_homogeneous_type (ty);
>> ++ for (i = 0; i < elems; i++)
>> ++ {
>> ++ void *reg = allocate_to_v (context, state);
>> ++ copy_basic_type (reg, memory, type);
>> ++ memory += get_basic_type_size (type);
>> ++ }
>> ++ }
>> ++}
>> ++
>> ++/* Either allocate an appropriate register for the argument type, or if
>> ++ none are available, allocate a stack slot and return a pointer
>> ++ to the allocated space. */
>> ++
>> ++static void *
>> ++allocate_to_register_or_stack (struct call_context *context,
>> ++ unsigned char *stack,
>> ++ struct arg_state *state,
>> ++ unsigned short type)
>> ++{
>> ++ size_t alignment = get_basic_type_alignment (type);
>> ++ size_t size = alignment;
>> ++ switch (type)
>> ++ {
>> ++ case FFI_TYPE_FLOAT:
>> ++ /* This is the only case for which the allocated stack size
>> ++ should not match the alignment of the type. */
>> ++ size = sizeof (UINT32);
>> ++ /* Fall through. */
>> ++ case FFI_TYPE_DOUBLE:
>> ++ if (state->nsrn < N_V_ARG_REG)
>> ++ return allocate_to_d (context, state);
>> ++ state->nsrn = N_V_ARG_REG;
>> ++ break;
>> ++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
>> ++ case FFI_TYPE_LONGDOUBLE:
>> ++ if (state->nsrn < N_V_ARG_REG)
>> ++ return allocate_to_v (context, state);
>> ++ state->nsrn = N_V_ARG_REG;
>> ++ break;
>> ++#endif
>> ++ case FFI_TYPE_UINT8:
>> ++ case FFI_TYPE_SINT8:
>> ++ case FFI_TYPE_UINT16:
>> ++ case FFI_TYPE_SINT16:
>> ++ case FFI_TYPE_UINT32:
>> ++ case FFI_TYPE_SINT32:
>> ++ case FFI_TYPE_INT:
>> ++ case FFI_TYPE_POINTER:
>> ++ case FFI_TYPE_UINT64:
>> ++ case FFI_TYPE_SINT64:
>> ++ if (state->ngrn < N_X_ARG_REG)
>> ++ return allocate_to_x (context, state);
>> ++ state->ngrn = N_X_ARG_REG;
>> ++ break;
>> ++ default:
>> ++ FFI_ASSERT (0);
>> ++ }
>> ++
>> ++ return allocate_to_stack (state, stack, alignment, size);
>> ++}
>> ++
>> ++/* Copy a value to an appropriate register, or if none are
>> ++ available, to the stack. */
>> ++
>> ++static void
>> ++copy_to_register_or_stack (struct call_context *context,
>> ++ unsigned char *stack,
>> ++ struct arg_state *state,
>> ++ void *value,
>> ++ unsigned short type)
>> ++{
>> ++ copy_basic_type (
>> ++ allocate_to_register_or_stack (context, stack, state, type),
>> ++ value,
>> ++ type);
>> ++}
>> ++
>> ++/* Marshall the arguments from FFI representation to procedure call
>> ++ context and stack. */
>> ++
>> ++static unsigned
>> ++aarch64_prep_args (struct call_context *context, unsigned char *stack,
>> ++ extended_cif *ecif)
>> ++{
>> ++ int i;
>> ++ struct arg_state state;
>> ++
>> ++ arg_init (&state, ALIGN(ecif->cif->bytes, 16));
>> ++
>> ++ for (i = 0; i < ecif->cif->nargs; i++)
>> ++ {
>> ++ ffi_type *ty = ecif->cif->arg_types[i];
>> ++ switch (ty->type)
>> ++ {
>> ++ case FFI_TYPE_VOID:
>> ++ FFI_ASSERT (0);
>> ++ break;
>> ++
>> ++ /* If the argument is a basic type the argument is allocated to an
>> ++ appropriate register, or if none are available, to the stack. */
>> ++ case FFI_TYPE_FLOAT:
>> ++ case FFI_TYPE_DOUBLE:
>> ++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
>> ++ case FFI_TYPE_LONGDOUBLE:
>> ++#endif
>> ++ case FFI_TYPE_UINT8:
>> ++ case FFI_TYPE_SINT8:
>> ++ case FFI_TYPE_UINT16:
>> ++ case FFI_TYPE_SINT16:
>> ++ case FFI_TYPE_UINT32:
>> ++ case FFI_TYPE_INT:
>> ++ case FFI_TYPE_SINT32:
>> ++ case FFI_TYPE_POINTER:
>> ++ case FFI_TYPE_UINT64:
>> ++ case FFI_TYPE_SINT64:
>> ++ copy_to_register_or_stack (context, stack, &state,
>> ++ ecif->avalue[i], ty->type);
>> ++ break;
>> ++
>> ++ case FFI_TYPE_STRUCT:
>> ++ if (is_hfa (ty))
>> ++ {
>> ++ copy_hfa_to_reg_or_stack (ecif->avalue[i], ty, context,
>> ++ stack, &state);
>> ++ }
>> ++ else if (ty->size > 16)
>> ++ {
>> ++ /* If the argument is a composite type that is larger than 16
>> ++ bytes, then the argument has been copied to memory, and
>> ++ the argument is replaced by a pointer to the copy. */
>> ++
>> ++ copy_to_register_or_stack (context, stack, &state,
>> ++ &(ecif->avalue[i]),
>> FFI_TYPE_POINTER);
>> ++ }
>> ++ else if (available_x (&state) >= (ty->size + 7) / 8)
>> ++ {
>> ++ /* If the argument is a composite type and the size in
>> ++ double-words is not more than the number of available
>> ++ X registers, then the argument is copied into consecutive
>> ++ X registers. */
>> ++ int j;
>> ++ for (j = 0; j < (ty->size + 7) / 8; j++)
>> ++ {
>> ++ memcpy (allocate_to_x (context, &state),
>> ++ &(((UINT64 *) ecif->avalue[i])[j]),
>> ++ sizeof (UINT64));
>> ++ }
>> ++ }
>> ++ else
>> ++ {
>> ++ /* Otherwise, there are insufficient X registers. Further X
>> ++ register allocations are prevented, the NSAA is adjusted
>> ++ (by allocate_to_stack ()) and the argument is copied to
>> ++ memory at the adjusted NSAA. */
>> ++ state.ngrn = N_X_ARG_REG;
>> ++
>> ++ memcpy (allocate_to_stack (&state, stack, ty->alignment,
>> ++ ty->size), ecif->avalue + i, ty->size);
>> ++ }
>> ++ break;
>> ++
>> ++ default:
>> ++ FFI_ASSERT (0);
>> ++ break;
>> ++ }
>> ++
>> ++#if defined (__APPLE__)
>> ++ if (i + 1 == ecif->cif->aarch64_nfixedargs)
>> ++ {
>> ++ state.ngrn = N_X_ARG_REG;
>> ++ state.nsrn = N_V_ARG_REG;
>> ++
>> ++ state.allocating_variadic = 1;
>> ++ }
>> ++#endif
>> ++ }
>> ++
>> ++ return ecif->cif->aarch64_flags;
>> ++}
>> ++
>> ++ffi_status
>> ++ffi_prep_cif_machdep (ffi_cif *cif)
>> ++{
>> ++ /* Round the stack up to a multiple of the stack alignment requirement.
>> */
>> ++ cif->bytes =
>> ++ (cif->bytes + (AARCH64_STACK_ALIGN - 1)) & ~
>> (AARCH64_STACK_ALIGN - 1);
>> ++
>> ++ /* Initialize our flags. We are interested if this CIF will touch a
>> ++ vector register, if so we will enable context save and load to
>> ++ those registers, otherwise not. This is intended to be friendly
>> ++ to lazy float context switching in the kernel. */
>> ++ cif->aarch64_flags = 0;
>> ++
>> ++ if (is_v_register_candidate (cif->rtype))
>> ++ {
>> ++ cif->aarch64_flags |= AARCH64_FFI_WITH_V;
>> ++ }
>> ++ else
>> ++ {
>> ++ int i;
>> ++ for (i = 0; i < cif->nargs; i++)
>> ++ if (is_v_register_candidate (cif->arg_types[i]))
>> ++ {
>> ++ cif->aarch64_flags |= AARCH64_FFI_WITH_V;
>> ++ break;
>> ++ }
>> ++ }
>> ++
>> ++ return FFI_OK;
>> ++}
>> ++
>> ++#if defined (__APPLE__)
>> ++
>> ++/* Perform Apple-specific cif processing for variadic calls */
>> ++ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif,
>> ++ unsigned int nfixedargs,
>> ++ unsigned int ntotalargs)
>> ++{
>> ++ cif->aarch64_nfixedargs = nfixedargs;
>> ++
>> ++ return ffi_prep_cif_machdep(cif);
>> ++}
>> ++
>> ++#endif
>> ++
>> ++/* Call a function with the provided arguments and capture the return
>> ++ value. */
>> ++void
>> ++ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
>> ++{
>> ++ extended_cif ecif;
>> ++
>> ++ ecif.cif = cif;
>> ++ ecif.avalue = avalue;
>> ++ ecif.rvalue = rvalue;
>> ++
>> ++ switch (cif->abi)
>> ++ {
>> ++ case FFI_SYSV:
>> ++ {
>> ++ struct call_context context;
>> ++ size_t stack_bytes;
>> ++
>> ++ /* Figure out the total amount of stack space we need, the
>> ++ above call frame space needs to be 16 bytes aligned to
>> ++ ensure correct alignment of the first object inserted in
>> ++ that space hence the ALIGN applied to cif->bytes.*/
>> ++ stack_bytes = ALIGN(cif->bytes, 16);
>> ++
>> ++ memset (&context, 0, sizeof (context));
>> ++ if (is_register_candidate (cif->rtype))
>> ++ {
>> ++ ffi_call_SYSV (aarch64_prep_args, &context, &ecif, stack_bytes, fn);
>> ++ switch (cif->rtype->type)
>> ++ {
>> ++ case FFI_TYPE_VOID:
>> ++ case FFI_TYPE_FLOAT:
>> ++ case FFI_TYPE_DOUBLE:
>> ++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
>> ++ case FFI_TYPE_LONGDOUBLE:
>> ++#endif
>> ++ case FFI_TYPE_UINT8:
>> ++ case FFI_TYPE_SINT8:
>> ++ case FFI_TYPE_UINT16:
>> ++ case FFI_TYPE_SINT16:
>> ++ case FFI_TYPE_UINT32:
>> ++ case FFI_TYPE_SINT32:
>> ++ case FFI_TYPE_POINTER:
>> ++ case FFI_TYPE_UINT64:
>> ++ case FFI_TYPE_INT:
>> ++ case FFI_TYPE_SINT64:
>> ++ {
>> ++ void *addr = get_basic_type_addr (cif->rtype->type,
>> ++ &context, 0);
>> ++ copy_basic_type (rvalue, addr, cif->rtype->type);
>> ++ break;
>> ++ }
>> ++
>> ++ case FFI_TYPE_STRUCT:
>> ++ if (is_hfa (cif->rtype))
>> ++ {
>> ++ int j;
>> ++ unsigned short type = get_homogeneous_type (cif-
>>> rtype);
>> ++ unsigned elems = element_count (cif->rtype);
>> ++ for (j = 0; j < elems; j++)
>> ++ {
>> ++ void *reg = get_basic_type_addr (type, &context, j);
>> ++ copy_basic_type (rvalue, reg, type);
>> ++ rvalue += get_basic_type_size (type);
>> ++ }
>> ++ }
>> ++ else if ((cif->rtype->size + 7) / 8 < N_X_ARG_REG)
>> ++ {
>> ++ size_t size = ALIGN (cif->rtype->size, sizeof (UINT64));
>> ++ memcpy (rvalue, get_x_addr (&context, 0), size);
>> ++ }
>> ++ else
>> ++ {
>> ++ FFI_ASSERT (0);
>> ++ }
>> ++ break;
>> ++
>> ++ default:
>> ++ FFI_ASSERT (0);
>> ++ break;
>> ++ }
>> ++ }
>> ++ else
>> ++ {
>> ++ memcpy (get_x_addr (&context, 8), &rvalue, sizeof (UINT64));
>> ++ ffi_call_SYSV (aarch64_prep_args, &context, &ecif,
>> ++ stack_bytes, fn);
>> ++ }
>> ++ break;
>> ++ }
>> ++
>> ++ default:
>> ++ FFI_ASSERT (0);
>> ++ break;
>> ++ }
>> ++}
>> ++
>> ++static unsigned char trampoline [] =
>> ++{ 0x70, 0x00, 0x00, 0x58, /* ldr x16, 1f */
>> ++ 0x91, 0x00, 0x00, 0x10, /* adr x17, 2f */
>> ++ 0x00, 0x02, 0x1f, 0xd6 /* br x16 */
>> ++};
>> ++
>> ++/* Build a trampoline. */
>> ++
>> ++#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX,FLAGS)
>> \
>> ++ ({unsigned char *__tramp = (unsigned char*)(TRAMP);
>> \
>> ++ UINT64 __fun = (UINT64)(FUN); \
>> ++ UINT64 __ctx = (UINT64)(CTX); \
>> ++ UINT64 __flags = (UINT64)(FLAGS);
>> \
>> ++ memcpy (__tramp, trampoline, sizeof (trampoline));
>> \
>> ++ memcpy (__tramp + 12, &__fun, sizeof (__fun)); \
>> ++ memcpy (__tramp + 20, &__ctx, sizeof (__ctx)); \
>> ++ memcpy (__tramp + 28, &__flags, sizeof (__flags));
>> \
>> ++ ffi_clear_cache(__tramp, __tramp + FFI_TRAMPOLINE_SIZE);
>> \
>> ++ })
>> ++
>> ++ffi_status
>> ++ffi_prep_closure_loc (ffi_closure* closure,
>> ++ ffi_cif* cif,
>> ++ void (*fun)(ffi_cif*,void*,void**,void*),
>> ++ void *user_data,
>> ++ void *codeloc)
>> ++{
>> ++ if (cif->abi != FFI_SYSV)
>> ++ return FFI_BAD_ABI;
>> ++
>> ++ FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_SYSV, codeloc,
>> ++ cif->aarch64_flags);
>> ++
>> ++ closure->cif = cif;
>> ++ closure->user_data = user_data;
>> ++ closure->fun = fun;
>> ++
>> ++ return FFI_OK;
>> ++}
>> ++
>> ++/* Primary handler to setup and invoke a function within a closure.
>> ++
>> ++ A closure when invoked enters via the assembler wrapper
>> ++ ffi_closure_SYSV(). The wrapper allocates a call context on the
>> ++ stack, saves the interesting registers (from the perspective of
>> ++ the calling convention) into the context then passes control to
>> ++ ffi_closure_SYSV_inner() passing the saved context and a pointer to
>> ++ the stack at the point ffi_closure_SYSV() was invoked.
>> ++
>> ++ On the return path the assembler wrapper will reload call context
>> ++ registers.
>> ++
>> ++ ffi_closure_SYSV_inner() marshalls the call context into ffi value
>> ++ descriptors, invokes the wrapped function, then marshalls the return
>> ++ value back into the call context. */
>> ++
>> ++void FFI_HIDDEN
>> ++ffi_closure_SYSV_inner (ffi_closure *closure, struct call_context *context,
>> ++ void *stack)
>> ++{
>> ++ ffi_cif *cif = closure->cif;
>> ++ void **avalue = (void**) alloca (cif->nargs * sizeof (void*));
>> ++ void *rvalue = NULL;
>> ++ int i;
>> ++ struct arg_state state;
>> ++
>> ++ arg_init (&state, ALIGN(cif->bytes, 16));
>> ++
>> ++ for (i = 0; i < cif->nargs; i++)
>> ++ {
>> ++ ffi_type *ty = cif->arg_types[i];
>> ++
>> ++ switch (ty->type)
>> ++ {
>> ++ case FFI_TYPE_VOID:
>> ++ FFI_ASSERT (0);
>> ++ break;
>> ++
>> ++ case FFI_TYPE_UINT8:
>> ++ case FFI_TYPE_SINT8:
>> ++ case FFI_TYPE_UINT16:
>> ++ case FFI_TYPE_SINT16:
>> ++ case FFI_TYPE_UINT32:
>> ++ case FFI_TYPE_SINT32:
>> ++ case FFI_TYPE_INT:
>> ++ case FFI_TYPE_POINTER:
>> ++ case FFI_TYPE_UINT64:
>> ++ case FFI_TYPE_SINT64:
>> ++ case FFI_TYPE_FLOAT:
>> ++ case FFI_TYPE_DOUBLE:
>> ++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
>> ++ case FFI_TYPE_LONGDOUBLE:
>> ++ avalue[i] = allocate_to_register_or_stack (context, stack,
>> ++ &state, ty->type);
>> ++ break;
>> ++#endif
>> ++
>> ++ case FFI_TYPE_STRUCT:
>> ++ if (is_hfa (ty))
>> ++ {
>> ++ unsigned n = element_count (ty);
>> ++ if (available_v (&state) < n)
>> ++ {
>> ++ state.nsrn = N_V_ARG_REG;
>> ++ avalue[i] = allocate_to_stack (&state, stack, ty->alignment,
>> ++ ty->size);
>> ++ }
>> ++ else
>> ++ {
>> ++ switch (get_homogeneous_type (ty))
>> ++ {
>> ++ case FFI_TYPE_FLOAT:
>> ++ {
>> ++ /* Eeek! We need a pointer to the structure,
>> ++ however the homogeneous float elements are
>> ++ being passed in individual S registers,
>> ++ therefore the structure is not represented as
>> ++ a contiguous sequence of bytes in our saved
>> ++ register context. We need to fake up a copy
>> ++ of the structure laid out in memory
>> ++ correctly. The fake can be tossed once the
>> ++ closure function has returned hence alloca()
>> ++ is sufficient. */
>> ++ int j;
>> ++ UINT32 *p = avalue[i] = alloca (ty->size);
>> ++ for (j = 0; j < element_count (ty); j++)
>> ++ memcpy (&p[j],
>> ++ allocate_to_s (context, &state),
>> ++ sizeof (*p));
>> ++ break;
>> ++ }
>> ++
>> ++ case FFI_TYPE_DOUBLE:
>> ++ {
>> ++ /* Eeek! We need a pointer to the structure,
>> ++ however the homogeneous float elements are
>> ++ being passed in individual S registers,
>> ++ therefore the structure is not represented as
>> ++ a contiguous sequence of bytes in our saved
>> ++ register context. We need to fake up a copy
>> ++ of the structure laid out in memory
>> ++ correctly. The fake can be tossed once the
>> ++ closure function has returned hence alloca()
>> ++ is sufficient. */
>> ++ int j;
>> ++ UINT64 *p = avalue[i] = alloca (ty->size);
>> ++ for (j = 0; j < element_count (ty); j++)
>> ++ memcpy (&p[j],
>> ++ allocate_to_d (context, &state),
>> ++ sizeof (*p));
>> ++ break;
>> ++ }
>> ++
>> ++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
>> ++ case FFI_TYPE_LONGDOUBLE:
>> ++ memcpy (&avalue[i],
>> ++ allocate_to_v (context, &state),
>> ++ sizeof (*avalue));
>> ++ break;
>> ++#endif
>> ++
>> ++ default:
>> ++ FFI_ASSERT (0);
>> ++ break;
>> ++ }
>> ++ }
>> ++ }
>> ++ else if (ty->size > 16)
>> ++ {
>> ++ /* Replace Composite type of size greater than 16 with a
>> ++ pointer. */
>> ++ memcpy (&avalue[i],
>> ++ allocate_to_register_or_stack (context, stack,
>> ++ &state,
>> FFI_TYPE_POINTER),
>> ++ sizeof (avalue[i]));
>> ++ }
>> ++ else if (available_x (&state) >= (ty->size + 7) / 8)
>> ++ {
>> ++ avalue[i] = get_x_addr (context, state.ngrn);
>> ++ state.ngrn += (ty->size + 7) / 8;
>> ++ }
>> ++ else
>> ++ {
>> ++ state.ngrn = N_X_ARG_REG;
>> ++
>> ++ avalue[i] = allocate_to_stack (&state, stack, ty->alignment,
>> ++ ty->size);
>> ++ }
>> ++ break;
>> ++
>> ++ default:
>> ++ FFI_ASSERT (0);
>> ++ break;
>> ++ }
>> ++ }
>> ++
>> ++ /* Figure out where the return value will be passed, either in
>> ++ registers or in a memory block allocated by the caller and passed
>> ++ in x8. */
>> ++
>> ++ if (is_register_candidate (cif->rtype))
>> ++ {
>> ++ /* Register candidates are *always* returned in registers. */
>> ++
>> ++ /* Allocate a scratchpad for the return value, we will let the
>> ++ callee scrible the result into the scratch pad then move the
>> ++ contents into the appropriate return value location for the
>> ++ call convention. */
>> ++ rvalue = alloca (cif->rtype->size);
>> ++ (closure->fun) (cif, rvalue, avalue, closure->user_data);
>> ++
>> ++ /* Copy the return value into the call context so that it is returned
>> ++ as expected to our caller. */
>> ++ switch (cif->rtype->type)
>> ++ {
>> ++ case FFI_TYPE_VOID:
>> ++ break;
>> ++
>> ++ case FFI_TYPE_UINT8:
>> ++ case FFI_TYPE_UINT16:
>> ++ case FFI_TYPE_UINT32:
>> ++ case FFI_TYPE_POINTER:
>> ++ case FFI_TYPE_UINT64:
>> ++ case FFI_TYPE_SINT8:
>> ++ case FFI_TYPE_SINT16:
>> ++ case FFI_TYPE_INT:
>> ++ case FFI_TYPE_SINT32:
>> ++ case FFI_TYPE_SINT64:
>> ++ case FFI_TYPE_FLOAT:
>> ++ case FFI_TYPE_DOUBLE:
>> ++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
>> ++ case FFI_TYPE_LONGDOUBLE:
>> ++#endif
>> ++ {
>> ++ void *addr = get_basic_type_addr (cif->rtype->type, context, 0);
>> ++ copy_basic_type (addr, rvalue, cif->rtype->type);
>> ++ break;
>> ++ }
>> ++ case FFI_TYPE_STRUCT:
>> ++ if (is_hfa (cif->rtype))
>> ++ {
>> ++ int j;
>> ++ unsigned short type = get_homogeneous_type (cif->rtype);
>> ++ unsigned elems = element_count (cif->rtype);
>> ++ for (j = 0; j < elems; j++)
>> ++ {
>> ++ void *reg = get_basic_type_addr (type, context, j);
>> ++ copy_basic_type (reg, rvalue, type);
>> ++ rvalue += get_basic_type_size (type);
>> ++ }
>> ++ }
>> ++ else if ((cif->rtype->size + 7) / 8 < N_X_ARG_REG)
>> ++ {
>> ++ size_t size = ALIGN (cif->rtype->size, sizeof (UINT64)) ;
>> ++ memcpy (get_x_addr (context, 0), rvalue, size);
>> ++ }
>> ++ else
>> ++ {
>> ++ FFI_ASSERT (0);
>> ++ }
>> ++ break;
>> ++ default:
>> ++ FFI_ASSERT (0);
>> ++ break;
>> ++ }
>> ++ }
>> ++ else
>> ++ {
>> ++ memcpy (&rvalue, get_x_addr (context, 8), sizeof (UINT64));
>> ++ (closure->fun) (cif, rvalue, avalue, closure->user_data);
>> ++ }
>> ++}
>> ++
>> +diff -ruN Python-2.7.3.orig/Modules/_ctypes/libffi/src/aarch64/ffitarget.h
>> Python-2.7.3/Modules/_ctypes/libffi/src/aarch64/ffitarget.h
>> +--- Python-2.7.3.orig/Modules/_ctypes/libffi/src/aarch64/ffitarget.h 1970-
>> 01-01 01:00:00.000000000 +0100
>> ++++ Python-2.7.3/Modules/_ctypes/libffi/src/aarch64/ffitarget.h 2014-
>> 04-25 19:45:13.000000000 +0200
>> +@@ -0,0 +1,63 @@
>> ++/* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd.
>> ++
>> ++Permission is hereby granted, free of charge, to any person obtaining
>> ++a copy of this software and associated documentation files (the
>> ++``Software''), to deal in the Software without restriction, including
>> ++without limitation the rights to use, copy, modify, merge, publish,
>> ++distribute, sublicense, and/or sell copies of the Software, and to
>> ++permit persons to whom the Software is furnished to do so, subject to
>> ++the following conditions:
>> ++
>> ++The above copyright notice and this permission notice shall be
>> ++included in all copies or substantial portions of the Software.
>> ++
>> ++THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
>> ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
>> OF
>> ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
>> NONINFRINGEMENT.
>> ++IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
>> ANY
>> ++CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
>> CONTRACT,
>> ++TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
>> THE
>> ++SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
>> ++
>> ++#ifndef LIBFFI_TARGET_H
>> ++#define LIBFFI_TARGET_H
>> ++
>> ++#ifndef LIBFFI_H
>> ++#error "Please do not include ffitarget.h directly into your source. Use
>> ffi.h instead."
>> ++#endif
>> ++
>> ++#ifndef LIBFFI_ASM
>> ++typedef unsigned long ffi_arg;
>> ++typedef signed long ffi_sarg;
>> ++
>> ++typedef enum ffi_abi
>> ++ {
>> ++ FFI_FIRST_ABI = 0,
>> ++ FFI_SYSV,
>> ++ FFI_LAST_ABI,
>> ++ FFI_DEFAULT_ABI = FFI_SYSV
>> ++ } ffi_abi;
>> ++#endif
>> ++
>> ++/* ---- Definitions for closures ----------------------------------------- */
>> ++
>> ++#define FFI_CLOSURES 1
>> ++#define FFI_TRAMPOLINE_SIZE 36
>> ++#define FFI_NATIVE_RAW_API 0
>> ++
>> ++/* ---- Internal ---- */
>> ++
>> ++#if defined (__APPLE__)
>> ++#define FFI_TARGET_SPECIFIC_VARIADIC
>> ++#define FFI_EXTRA_CIF_FIELDS unsigned aarch64_flags; unsigned
>> aarch64_nfixedargs
>> ++#else
>> ++#define FFI_EXTRA_CIF_FIELDS unsigned aarch64_flags
>> ++#endif
>> ++
>> ++#define AARCH64_FFI_WITH_V_BIT 0
>> ++
>> ++#define AARCH64_N_XREG 32
>> ++#define AARCH64_N_VREG 32
>> ++#define AARCH64_CALL_CONTEXT_SIZE (AARCH64_N_XREG * 8 +
>> AARCH64_N_VREG * 16)
>> ++
>> ++#endif
>> +diff -ruN Python-2.7.3.orig/Modules/_ctypes/libffi/src/aarch64/sysv.S
>> Python-2.7.3/Modules/_ctypes/libffi/src/aarch64/sysv.S
>> +--- Python-2.7.3.orig/Modules/_ctypes/libffi/src/aarch64/sysv.S 1970-
>> 01-01 01:00:00.000000000 +0100
>> ++++ Python-2.7.3/Modules/_ctypes/libffi/src/aarch64/sysv.S 2014-04-25
>> 19:45:13.000000000 +0200
>> +@@ -0,0 +1,333 @@
>> ++/* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd.
>> ++
>> ++Permission is hereby granted, free of charge, to any person obtaining
>> ++a copy of this software and associated documentation files (the
>> ++``Software''), to deal in the Software without restriction, including
>> ++without limitation the rights to use, copy, modify, merge, publish,
>> ++distribute, sublicense, and/or sell copies of the Software, and to
>> ++permit persons to whom the Software is furnished to do so, subject to
>> ++the following conditions:
>> ++
>> ++The above copyright notice and this permission notice shall be
>> ++included in all copies or substantial portions of the Software.
>> ++
>> ++THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
>> ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
>> OF
>> ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
>> NONINFRINGEMENT.
>> ++IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
>> ANY
>> ++CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
>> CONTRACT,
>> ++TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
>> THE
>> ++SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
>> ++
>> ++#define LIBFFI_ASM
>> ++#include <fficonfig.h>
>> ++#include <ffi.h>
>> ++
>> ++#ifdef HAVE_MACHINE_ASM_H
>> ++#include <machine/asm.h>
>> ++#else
>> ++#ifdef __USER_LABEL_PREFIX__
>> ++#define CONCAT1(a, b) CONCAT2(a, b)
>> ++#define CONCAT2(a, b) a ## b
>> ++
>> ++/* Use the right prefix for global labels. */
>> ++#define CNAME(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
>> ++#else
>> ++#define CNAME(x) x
>> ++#endif
>> ++#endif
>> ++
>> ++#define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off
>> ++#define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off
>> ++#define cfi_restore(reg) .cfi_restore reg
>> ++#define cfi_def_cfa_register(reg) .cfi_def_cfa_register reg
>> ++
>> ++ .text
>> ++ .globl CNAME(ffi_call_SYSV)
>> ++#ifdef __ELF__
>> ++ .type CNAME(ffi_call_SYSV), #function
>> ++#endif
>> ++#ifdef __APPLE__
>> ++ .align 2
>> ++#endif
>> ++
>> ++/* ffi_call_SYSV()
>> ++
>> ++ Create a stack frame, setup an argument context, call the callee
>> ++ and extract the result.
>> ++
>> ++ The maximum required argument stack size is provided,
>> ++ ffi_call_SYSV() allocates that stack space then calls the
>> ++ prepare_fn to populate register context and stack. The
>> ++ argument passing registers are loaded from the register
>> ++ context and the callee called, on return the register passing
>> ++ register are saved back to the context. Our caller will
>> ++ extract the return value from the final state of the saved
>> ++ register context.
>> ++
>> ++ Prototype:
>> ++
>> ++ extern unsigned
>> ++ ffi_call_SYSV (void (*)(struct call_context *context, unsigned char *,
>> ++ extended_cif *),
>> ++ struct call_context *context,
>> ++ extended_cif *,
>> ++ size_t required_stack_size,
>> ++ void (*fn)(void));
>> ++
>> ++ Therefore on entry we have:
>> ++
>> ++ x0 prepare_fn
>> ++ x1 &context
>> ++ x2 &ecif
>> ++ x3 bytes
>> ++ x4 fn
>> ++
>> ++ This function uses the following stack frame layout:
>> ++
>> ++ ==
>> ++ saved x30(lr)
>> ++ x29(fp)-> saved x29(fp)
>> ++ saved x24
>> ++ saved x23
>> ++ saved x22
>> ++ sp' -> saved x21
>> ++ ...
>> ++ sp -> (constructed callee stack arguments)
>> ++ ==
>> ++
>> ++ Voila! */
>> ++
>> ++#define ffi_call_SYSV_FS (8 * 4)
>> ++
>> ++ .cfi_startproc
>> ++CNAME(ffi_call_SYSV):
>> ++ stp x29, x30, [sp, #-16]!
>> ++ cfi_adjust_cfa_offset (16)
>> ++ cfi_rel_offset (x29, 0)
>> ++ cfi_rel_offset (x30, 8)
>> ++
>> ++ mov x29, sp
>> ++ cfi_def_cfa_register (x29)
>> ++ sub sp, sp, #ffi_call_SYSV_FS
>> ++
>> ++ stp x21, x22, [sp, #0]
>> ++ cfi_rel_offset (x21, 0 - ffi_call_SYSV_FS)
>> ++ cfi_rel_offset (x22, 8 - ffi_call_SYSV_FS)
>> ++
>> ++ stp x23, x24, [sp, #16]
>> ++ cfi_rel_offset (x23, 16 - ffi_call_SYSV_FS)
>> ++ cfi_rel_offset (x24, 24 - ffi_call_SYSV_FS)
>> ++
>> ++ mov x21, x1
>> ++ mov x22, x2
>> ++ mov x24, x4
>> ++
>> ++ /* Allocate the stack space for the actual arguments, many
>> ++ arguments will be passed in registers, but we assume
>> ++ worst case and allocate sufficient stack for ALL of
>> ++ the arguments. */
>> ++ sub sp, sp, x3
>> ++
>> ++ /* unsigned (*prepare_fn) (struct call_context *context,
>> ++ unsigned char *stack, extended_cif *ecif);
>> ++ */
>> ++ mov x23, x0
>> ++ mov x0, x1
>> ++ mov x1, sp
>> ++ /* x2 already in place */
>> ++ blr x23
>> ++
>> ++ /* Preserve the flags returned. */
>> ++ mov x23, x0
>> ++
>> ++ /* Figure out if we should touch the vector registers. */
>> ++ tbz x23, #AARCH64_FFI_WITH_V_BIT, 1f
>> ++
>> ++ /* Load the vector argument passing registers. */
>> ++ ldp q0, q1, [x21, #8*32 + 0]
>> ++ ldp q2, q3, [x21, #8*32 + 32]
>> ++ ldp q4, q5, [x21, #8*32 + 64]
>> ++ ldp q6, q7, [x21, #8*32 + 96]
>> ++1:
>> ++ /* Load the core argument passing registers. */
>> ++ ldp x0, x1, [x21, #0]
>> ++ ldp x2, x3, [x21, #16]
>> ++ ldp x4, x5, [x21, #32]
>> ++ ldp x6, x7, [x21, #48]
>> ++
>> ++ /* Don't forget x8 which may be holding the address of a return
>> buffer.
>> ++ */
>> ++ ldr x8, [x21, #8*8]
>> ++
>> ++ blr x24
>> ++
>> ++ /* Save the core argument passing registers. */
>> ++ stp x0, x1, [x21, #0]
>> ++ stp x2, x3, [x21, #16]
>> ++ stp x4, x5, [x21, #32]
>> ++ stp x6, x7, [x21, #48]
>> ++
>> ++ /* Note nothing useful ever comes back in x8! */
>> ++
>> ++ /* Figure out if we should touch the vector registers. */
>> ++ tbz x23, #AARCH64_FFI_WITH_V_BIT, 1f
>> ++
>> ++ /* Save the vector argument passing registers. */
>> ++ stp q0, q1, [x21, #8*32 + 0]
>> ++ stp q2, q3, [x21, #8*32 + 32]
>> ++ stp q4, q5, [x21, #8*32 + 64]
>> ++ stp q6, q7, [x21, #8*32 + 96]
>> ++1:
>> ++ /* All done, unwind our stack frame. */
>> ++ ldp x21, x22, [x29, # - ffi_call_SYSV_FS]
>> ++ cfi_restore (x21)
>> ++ cfi_restore (x22)
>> ++
>> ++ ldp x23, x24, [x29, # - ffi_call_SYSV_FS + 16]
>> ++ cfi_restore (x23)
>> ++ cfi_restore (x24)
>> ++
>> ++ mov sp, x29
>> ++ cfi_def_cfa_register (sp)
>> ++
>> ++ ldp x29, x30, [sp], #16
>> ++ cfi_adjust_cfa_offset (-16)
>> ++ cfi_restore (x29)
>> ++ cfi_restore (x30)
>> ++
>> ++ ret
>> ++
>> ++ .cfi_endproc
>> ++#ifdef __ELF__
>> ++ .size CNAME(ffi_call_SYSV), .-CNAME(ffi_call_SYSV)
>> ++#endif
>> ++
>> ++#define ffi_closure_SYSV_FS (8 * 2 + AARCH64_CALL_CONTEXT_SIZE)
>> ++
>> ++/* ffi_closure_SYSV
>> ++
>> ++ Closure invocation glue. This is the low level code invoked directly by
>> ++ the closure trampoline to setup and call a closure.
>> ++
>> ++ On entry x17 points to a struct trampoline_data, x16 has been clobbered
>> ++ all other registers are preserved.
>> ++
>> ++ We allocate a call context and save the argument passing registers,
>> ++ then invoked the generic C ffi_closure_SYSV_inner() function to do all
>> ++ the real work, on return we load the result passing registers back from
>> ++ the call context.
>> ++
>> ++ On entry
>> ++
>> ++ extern void
>> ++ ffi_closure_SYSV (struct trampoline_data *);
>> ++
>> ++ struct trampoline_data
>> ++ {
>> ++ UINT64 *ffi_closure;
>> ++ UINT64 flags;
>> ++ };
>> ++
>> ++ This function uses the following stack frame layout:
>> ++
>> ++ ==
>> ++ saved x30(lr)
>> ++ x29(fp)-> saved x29(fp)
>> ++ saved x22
>> ++ saved x21
>> ++ ...
>> ++ sp -> call_context
>> ++ ==
>> ++
>> ++ Voila! */
>> ++
>> ++ .text
>> ++ .globl CNAME(ffi_closure_SYSV)
>> ++#ifdef __APPLE__
>> ++ .align 2
>> ++#endif
>> ++ .cfi_startproc
>> ++CNAME(ffi_closure_SYSV):
>> ++ stp x29, x30, [sp, #-16]!
>> ++ cfi_adjust_cfa_offset (16)
>> ++ cfi_rel_offset (x29, 0)
>> ++ cfi_rel_offset (x30, 8)
>> ++
>> ++ mov x29, sp
>> ++ cfi_def_cfa_register (x29)
>> ++
>> ++ sub sp, sp, #ffi_closure_SYSV_FS
>> ++
>> ++ stp x21, x22, [x29, #-16]
>> ++ cfi_rel_offset (x21, -16)
>> ++ cfi_rel_offset (x22, -8)
>> ++
>> ++ /* Load x21 with &call_context. */
>> ++ mov x21, sp
>> ++ /* Preserve our struct trampoline_data * */
>> ++ mov x22, x17
>> ++
>> ++ /* Save the rest of the argument passing registers. */
>> ++ stp x0, x1, [x21, #0]
>> ++ stp x2, x3, [x21, #16]
>> ++ stp x4, x5, [x21, #32]
>> ++ stp x6, x7, [x21, #48]
>> ++ /* Don't forget we may have been given a result scratch pad address.
>> ++ */
>> ++ str x8, [x21, #64]
>> ++
>> ++ /* Figure out if we should touch the vector registers. */
>> ++ ldr x0, [x22, #8]
>> ++ tbz x0, #AARCH64_FFI_WITH_V_BIT, 1f
>> ++
>> ++ /* Save the argument passing vector registers. */
>> ++ stp q0, q1, [x21, #8*32 + 0]
>> ++ stp q2, q3, [x21, #8*32 + 32]
>> ++ stp q4, q5, [x21, #8*32 + 64]
>> ++ stp q6, q7, [x21, #8*32 + 96]
>> ++1:
>> ++ /* Load &ffi_closure.. */
>> ++ ldr x0, [x22, #0]
>> ++ mov x1, x21
>> ++ /* Compute the location of the stack at the point that the
>> ++ trampoline was called. */
>> ++ add x2, x29, #16
>> ++
>> ++ bl CNAME(ffi_closure_SYSV_inner)
>> ++
>> ++ /* Figure out if we should touch the vector registers. */
>> ++ ldr x0, [x22, #8]
>> ++ tbz x0, #AARCH64_FFI_WITH_V_BIT, 1f
>> ++
>> ++ /* Load the result passing vector registers. */
>> ++ ldp q0, q1, [x21, #8*32 + 0]
>> ++ ldp q2, q3, [x21, #8*32 + 32]
>> ++ ldp q4, q5, [x21, #8*32 + 64]
>> ++ ldp q6, q7, [x21, #8*32 + 96]
>> ++1:
>> ++ /* Load the result passing core registers. */
>> ++ ldp x0, x1, [x21, #0]
>> ++ ldp x2, x3, [x21, #16]
>> ++ ldp x4, x5, [x21, #32]
>> ++ ldp x6, x7, [x21, #48]
>> ++ /* Note nothing useful is returned in x8. */
>> ++
>> ++ /* We are done, unwind our frame. */
>> ++ ldp x21, x22, [x29, #-16]
>> ++ cfi_restore (x21)
>> ++ cfi_restore (x22)
>> ++
>> ++ mov sp, x29
>> ++ cfi_def_cfa_register (sp)
>> ++
>> ++ ldp x29, x30, [sp], #16
>> ++ cfi_adjust_cfa_offset (-16)
>> ++ cfi_restore (x29)
>> ++ cfi_restore (x30)
>> ++
>> ++ ret
>> ++ .cfi_endproc
>> ++#ifdef __ELF__
>> ++ .size CNAME(ffi_closure_SYSV), .-CNAME(ffi_closure_SYSV)
>> ++#endif
>> diff --git a/meta/recipes-devtools/python/python_2.7.3.bb b/meta/recipes-
>> devtools/python/python_2.7.3.bb
>> index cbe8d7f..de1f57f 100644
>> --- a/meta/recipes-devtools/python/python_2.7.3.bb
>> +++ b/meta/recipes-devtools/python/python_2.7.3.bb
>> @@ -40,6 +40,8 @@ SRC_URI += "\
>> file://posix_close.patch \
>> file://python-2.7.3-CVE-2014-7185.patch \
>> file://python2.7.3-nossl3.patch \
>> + file://ctypes-libffi-aarch64.patch \
>> + file://libffi-aarch64.patch \
>> "
>>
>> S = "${WORKDIR}/Python-${PV}"
>> --
>> 1.9.1
>
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2015-03-11 13:42 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-03-04 15:04 [dizzy] [PATCH 1/1] python: Add support for aarch64 for ctypes module Tudor Florea
2015-03-04 20:25 ` Burton, Ross
2015-03-04 22:52 ` Tudor Florea
2015-03-10 0:24 ` Tudor Florea
2015-03-11 13:42 ` akuster808
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox