Commit 86d5ecc5e84fbbc79fcff6a307310630d9d68549

Anthony Green 2021-07-29T16:58:32

Fix struct arg passing

diff --git a/src/moxie/ffi.c b/src/moxie/ffi.c
index 16d2bb3..696581a 100644
--- a/src/moxie/ffi.c
+++ b/src/moxie/ffi.c
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------
-   ffi.c - Copyright (C) 2012, 2013, 2018  Anthony Green
-   
-   Moxie Foreign Function Interface 
+   ffi.c - Copyright (C) 2012, 2013, 2018, 2021  Anthony Green
+
+   Moxie Foreign Function Interface
 
    Permission is hereby granted, free of charge, to any person obtaining
    a copy of this software and associated documentation files (the
@@ -54,14 +54,14 @@ void *ffi_prep_args(char *stack, extended_cif *ecif)
        i--, p_arg++)
     {
       size_t z;
-      
+
       z = (*p_arg)->size;
 
       if ((*p_arg)->type == FFI_TYPE_STRUCT)
 	{
 	  z = sizeof(void*);
 	  *(void **) argp = *p_argv;
-	} 
+	}
       else if (z < sizeof(int))
 	{
 	  z = sizeof(int);
@@ -70,19 +70,19 @@ void *ffi_prep_args(char *stack, extended_cif *ecif)
 	    case FFI_TYPE_SINT8:
 	      *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
 	      break;
-	      
+
 	    case FFI_TYPE_UINT8:
 	      *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
 	      break;
-	      
+
 	    case FFI_TYPE_SINT16:
 	      *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
 	      break;
-		  
+
 	    case FFI_TYPE_UINT16:
 	      *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
 	      break;
-		  
+
 	    default:
 	      FFI_ASSERT(0);
 	    }
@@ -116,26 +116,26 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
   return FFI_OK;
 }
 
-extern void ffi_call_EABI(void *(*)(char *, extended_cif *), 
-			  extended_cif *, 
-			  unsigned, unsigned, 
-			  unsigned *, 
+extern void ffi_call_EABI(void *(*)(char *, extended_cif *),
+			  extended_cif *,
+			  unsigned, unsigned,
+			  unsigned *,
 			  void (*fn)(void));
 
-void ffi_call(ffi_cif *cif, 
-	      void (*fn)(void), 
-	      void *rvalue, 
+void ffi_call(ffi_cif *cif,
+	      void (*fn)(void),
+	      void *rvalue,
 	      void **avalue)
 {
   extended_cif ecif;
 
   ecif.cif = cif;
   ecif.avalue = avalue;
-  
+
   /* If the return value is a struct and we don't have a return	*/
   /* value address then we need to make one		        */
 
-  if ((rvalue == NULL) && 
+  if ((rvalue == NULL) &&
       (cif->rtype->type == FFI_TYPE_STRUCT))
     {
       ecif.rvalue = alloca(cif->rtype->size);
@@ -143,10 +143,10 @@ void ffi_call(ffi_cif *cif,
   else
     ecif.rvalue = rvalue;
 
-  switch (cif->abi) 
+  switch (cif->abi)
     {
     case FFI_EABI:
-      ffi_call_EABI(ffi_prep_args, &ecif, cif->bytes, 
+      ffi_call_EABI(ffi_prep_args, &ecif, cif->bytes,
 		    cif->flags, ecif.rvalue, fn);
       break;
     default:
@@ -172,7 +172,7 @@ void ffi_closure_eabi (unsigned arg1, unsigned arg2, unsigned arg3,
   void *struct_rvalue = (void *) arg1;
 
   /* 6 words reserved for register args + 3 words from jsr */
-  char *stack_args = frame_pointer + 9*4; 
+  char *stack_args = frame_pointer + 9*4;
 
   /* Lay the register arguments down in a continuous chunk of memory.  */
   unsigned register_args[6] =
@@ -211,7 +211,16 @@ void ffi_closure_eabi (unsigned arg1, unsigned arg2, unsigned arg3,
 	  avalue[i] = ptr;
 	  break;
 	case FFI_TYPE_STRUCT:
-	  avalue[i] = *(void**)ptr;
+          {
+            if (arg_types[i]->type->size > 4)
+              {
+                void *copy = alloca(arg_types[i]->type->size);
+                memcpy(copy, *(void**)ptr, arg_types[i]->type->size);
+                avalue[i] = copy;
+              }
+            else
+              avalue[i] = *(void**)ptr;
+          }
 	  break;
 	default:
 	  /* This is an 8-byte value.  */