Commit aa2c4141722ec8b8b014b97e049ffa2d140d0c0d

Anthony Green 2022-05-29T10:28:10

64-bit cygwin: fix struct args. Document change.

diff --git a/README.md b/README.md
index d23c487..8750f32 100644
--- a/README.md
+++ b/README.md
@@ -198,6 +198,7 @@ See the git log for details at http://github.com/libffi/libffi.
 
     3.4.3 TBD
         Fix x32 static trampolines.
+        All struct args are passed by value, regardless of size.
         Add support for Loongson's LoonArch64 architecture.
 
     3.4.2 Jun-28-21
diff --git a/src/x86/ffiw64.c b/src/x86/ffiw64.c
index 6870d07..81d41bf 100644
--- a/src/x86/ffiw64.c
+++ b/src/x86/ffiw64.c
@@ -123,9 +123,26 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
   UINT64 *stack;
   size_t rsize;
   struct win64_call_frame *frame;
+  ffi_type **arg_types = cif->arg_types;
+  int nargs = cif->nargs;
+  const int max_reg_struct_size = cif->abi == FFI_GNUW64 ? 8 : 16;
 
   FFI_ASSERT(cif->abi == FFI_GNUW64 || cif->abi == FFI_WIN64);
 
+  /* 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 > max_reg_struct_size)
+        {
+          char *argcopy = alloca (size);
+          memcpy (argcopy, avalue[i], size);
+          avalue[i] = argcopy;
+        }
+    }
+
   flags = cif->flags;
   rsize = 0;