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 | |
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
-rw-r--r-- | src/aarch64/ffi.c | 39 | ||||
-rw-r--r-- | src/x86/ffi64.c | 19 |
2 files changed, 49 insertions, 9 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) diff --git a/src/x86/ffi64.c b/src/x86/ffi64.c index 438b374..74a3003 100644 --- a/src/x86/ffi64.c +++ b/src/x86/ffi64.c @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------- - ffi64.c - Copyright (c) 2011, 2018 Anthony Green + ffi64.c - Copyright (c) 2011, 2018, 2022 Anthony Green Copyright (c) 2013 The Written Word, Inc. Copyright (c) 2008, 2010 Red Hat, Inc. Copyright (c) 2002, 2007 Bo Thorsen <bo@suse.de> @@ -681,6 +681,23 @@ ffi_call_efi64(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue); void ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) { + ffi_type **arg_types = cif->arg_types; + int i, nargs = cif->nargs; + + /* If we have any large structure arguments, make a copy so we are passing + by value. */ + for (i = 0; i < nargs; i++) + { + ffi_type *at = arg_types[i]; + int size = at->size; + if (at->type == FFI_TYPE_STRUCT && size > 16) + { + char *argcopy = alloca (size); + memcpy (argcopy, avalue[i], size); + avalue[i] = argcopy; + } + } + #ifndef __ILP32__ if (cif->abi == FFI_EFI64 || cif->abi == FFI_GNUW64) { |