Commit 769b7366d2312c7efdfa605cf1fc1156b94ba2e0

Anthony Green 2022-05-28T19:59:35

Fix for MS x64 ABI

diff --git a/src/x86/ffi64.c b/src/x86/ffi64.c
index 74a3003..22d43f5 100644
--- a/src/x86/ffi64.c
+++ b/src/x86/ffi64.c
@@ -581,6 +581,9 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
 	flags = UNIX64_RET_VOID;
     }
 
+  arg_types = cif->arg_types;
+  avn = cif->nargs;
+
   /* Allocate the space for the arguments, plus 4 words of temp space.  */
   stack = alloca (sizeof (struct register_args) + cif->bytes + 4*8);
   reg_args = (struct register_args *) stack;
@@ -595,9 +598,6 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
   if (flags & UNIX64_FLAG_RET_IN_MEM)
     reg_args->gpr[gprcount++] = (unsigned long) rvalue;
 
-  avn = cif->nargs;
-  arg_types = cif->arg_types;
-
   for (i = 0; i < avn; ++i)
     {
       size_t n, size = arg_types[i]->size;
@@ -613,11 +613,12 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
 	  if (align < 8)
 	    align = 8;
 
-	  /* Pass this argument in memory.  */
-	  argp = (void *) FFI_ALIGN (argp, align);
-	  memcpy (argp, avalue[i], size);
-	  argp += size;
-	}
+          /* Pass this argument in memory.  */
+          argp = (void *) FFI_ALIGN (argp, align);
+          memcpy (argp, avalue[i], size);
+
+          argp += size;
+        }
       else
 	{
 	  /* The argument is passed entirely in registers.  */
@@ -683,6 +684,7 @@ ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
 {
   ffi_type **arg_types = cif->arg_types;
   int i, nargs = cif->nargs;
+  const int max_reg_struct_size = cif->abi == FFI_GNUW64 ? 8 : 16;
 
   /* If we have any large structure arguments, make a copy so we are passing
      by value.  */
@@ -690,7 +692,7 @@ ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
     {
       ffi_type *at = arg_types[i];
       int size = at->size;
-      if (at->type == FFI_TYPE_STRUCT && size > 16)
+      if (at->type == FFI_TYPE_STRUCT && size > max_reg_struct_size)
         {
           char *argcopy = alloca (size);
           memcpy (argcopy, avalue[i], size);