diff options
author | Anthony Green <green@moxielogic.com> | 2022-05-28 09:42:13 -0400 |
---|---|---|
committer | Anthony Green <green@moxielogic.com> | 2022-05-28 09:42:13 -0400 |
commit | e409225b41b60c490a094bb068e639a2364202fd (patch) | |
tree | e8bb9ffbcbb49faec83ebaed6dc90dab07042f7e /src/aarch64 | |
parent | 01d54435c9f9e22345cb2f7d482fcfb42fd11416 (diff) | |
download | libffi-e409225b41b60c490a094bb068e639a2364202fd.tar.gz |
Pass large structs by value for Linux x86_64 and Aarch64.
Aarch patch by Andreas Schwab. https://github.com/libffi/libffi/commit/482b37f00467325e3389bab322525099860dd9aa
Diffstat (limited to 'src/aarch64')
-rw-r--r-- | src/aarch64/ffi.c | 39 |
1 files changed, 31 insertions, 8 deletions
diff --git a/src/aarch64/ffi.c b/src/aarch64/ffi.c index 5c85fcd..8f8c140 100644 --- a/src/aarch64/ffi.c +++ b/src/aarch64/ffi.c @@ -248,13 +248,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; @@ -263,11 +268,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 @@ -296,6 +302,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) { @@ -624,13 +645,14 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *orig_rvalue, frame = (void*)((uintptr_t)stack + (uintptr_t)stack_bytes); rvalue = (rsize ? (void*)((uintptr_t)frame + 40) : 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) @@ -678,8 +700,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) { @@ -712,9 +732,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; @@ -917,7 +940,7 @@ ffi_closure_SYSV_inner (ffi_cif *cif, int i, h, nargs, flags, isvariadic = 0; struct arg_state state; - arg_init (&state); + arg_init (&state, cif->bytes); flags = cif->flags; if (flags & AARCH64_FLAG_VARARG) |