summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAnthony Green <green@moxielogic.com>2022-05-28 09:42:13 -0400
committerAnthony Green <green@moxielogic.com>2022-05-28 09:42:13 -0400
commite409225b41b60c490a094bb068e639a2364202fd (patch)
treee8bb9ffbcbb49faec83ebaed6dc90dab07042f7e /src
parent01d54435c9f9e22345cb2f7d482fcfb42fd11416 (diff)
downloadlibffi-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')
-rw-r--r--src/aarch64/ffi.c39
-rw-r--r--src/x86/ffi64.c19
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)
{