From 482b37f00467325e3389bab322525099860dd9aa Mon Sep 17 00:00:00 2001 From: Andreas Schwab Date: Mon, 18 Sep 2017 12:44:08 +0200 Subject: [PATCH] Fix passing struct by value on aarch64 This fixes the ctypes test in the python testsuite. --- src/aarch64/ffi.c | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/src/aarch64/ffi.c b/src/aarch64/ffi.c index 4400b61a..b64a6b92 100644 --- a/src/aarch64/ffi.c +++ b/src/aarch64/ffi.c @@ -238,13 +238,18 @@ is_vfp_type (const ffi_type *ty) state. The terse state variable names match the names used in the AARCH64 - PCS. */ + PCS. + + The struct area is allocated downwards from the top of the argument + area. It is used to hold copies of structures passed by value that are + bigger than 16 bytes. */ struct arg_state { unsigned ngrn; /* Next general-purpose register number. */ unsigned nsrn; /* Next vector register number. */ size_t nsaa; /* Next stack offset. */ + size_t next_struct_area; /* Place to allocate big structs. */ #if defined (__APPLE__) unsigned allocating_variadic; @@ -253,11 +258,12 @@ struct arg_state /* Initialize a procedure call argument marshalling state. */ static void -arg_init (struct arg_state *state) +arg_init (struct arg_state *state, size_t size) { state->ngrn = 0; state->nsrn = 0; state->nsaa = 0; + state->next_struct_area = size; #if defined (__APPLE__) state->allocating_variadic = 0; #endif @@ -286,6 +292,21 @@ allocate_to_stack (struct arg_state *state, void *stack, return (char *)stack + nsaa; } +/* Allocate and copy a structure that is passed by value on the stack and + return a pointer to it. */ +static void * +allocate_and_copy_struct_to_stack (struct arg_state *state, void *stack, + size_t alignment, size_t size, void *value) +{ + size_t dest = state->next_struct_area - size; + + /* Round down to the natural alignment of the value. */ + dest = ALIGN_DOWN (dest, alignment); + state->next_struct_area = dest; + + return memcpy ((char *) stack + dest, value, size); +} + static ffi_arg extend_integer_type (void *source, int type) { @@ -591,13 +612,14 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *orig_rvalue, frame = stack + stack_bytes; rvalue = (rsize ? frame + 32 : orig_rvalue); - arg_init (&state); + arg_init (&state, stack_bytes); for (i = 0, nargs = cif->nargs; i < nargs; i++) { ffi_type *ty = cif->arg_types[i]; size_t s = ty->size; void *a = avalue[i]; int h, t; + void *dest; t = ty->type; switch (t) @@ -645,8 +667,6 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *orig_rvalue, case FFI_TYPE_STRUCT: case FFI_TYPE_COMPLEX: { - void *dest; - h = is_vfp_type (ty); if (h) { @@ -664,9 +684,12 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *orig_rvalue, else if (s > 16) { /* If the argument is a composite type that is larger than 16 - bytes, then the argument has been copied to memory, and + bytes, then the argument is copied to memory, and the argument is replaced by a pointer to the copy. */ - a = &avalue[i]; + dest = allocate_and_copy_struct_to_stack (&state, stack, + ty->alignment, s, + avalue[i]); + a = &dest; t = FFI_TYPE_POINTER; s = sizeof (void *); goto do_pointer; @@ -835,7 +858,7 @@ ffi_closure_SYSV_inner (ffi_cif *cif, int i, h, nargs, flags; struct arg_state state; - arg_init (&state); + arg_init (&state, cif->bytes); for (i = 0, nargs = cif->nargs; i < nargs; i++) {