The powerpc64 ABIs align structs passed by value, a fact ignored by
authorAlan Modra <amodra@gmail.com>
Sat, 16 Nov 2013 11:41:36 +0000 (06:41 -0500)
committerAnthony Green <green@moxielogic.com>
Sat, 16 Nov 2013 11:41:36 +0000 (06:41 -0500)
gcc for quite some time.  Since gcc now does the correct alignment,
libffi needs to follow suit.  This ought to be made selectable via
a new abi value, and the #ifdefs removed from ffi.c along with many
other #ifdefs present there and in assembly.  I'll do that with a
followup patch sometime.

This is a revised version of
https://sourceware.org/ml/libffi-discuss/2013/msg00162.html

ChangeLog
src/powerpc/ffi.c

index bca121198f2fa8b76828d4d9e522b6c9e7575814..2a4c8dc8ad02d7585a788ebe491f7dd26592de1a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2013-11-16  Alan Modra  <amodra@gmail.com>
+
+       * src/powerpc/ffi.c (ffi_prep_args64): Align struct parameters
+       according to __STRUCT_PARM_ALIGN__.
+       (ffi_prep_cif_machdep_core): Likewise.
+       (ffi_closure_helper_LINUX64): Likewise.
+
 2013-11-16  Alan Modra  <amodra@gmail.com>
 
        * src/powerpc/linux64.S (ffi_call_LINUX64): Tweak restore of r28.
index a22ac27b9ec3b4209cc07679685fc2271c8bc2e9..12501b6de44bdbc99562aa9d225d8b774bb57019 100644 (file)
@@ -439,6 +439,7 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
     unsigned long *ul;
     float *f;
     double *d;
+    size_t p;
   } valp;
 
   /* 'stacktop' points at the previous backchain pointer.  */
@@ -473,6 +474,9 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
     double **d;
   } p_argv;
   unsigned long gprvalue;
+#ifdef __STRUCT_PARM_ALIGN__
+  unsigned long align;
+#endif
 
   stacktop.c = (char *) stack + bytes;
   gpr_base.ul = stacktop.ul - ASM_NEEDS_REGISTERS64 - NUM_GPR_ARG_REGISTERS64;
@@ -549,6 +553,13 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
 #endif
 
        case FFI_TYPE_STRUCT:
+#ifdef __STRUCT_PARM_ALIGN__
+         align = (*ptr)->alignment;
+         if (align > __STRUCT_PARM_ALIGN__)
+           align = __STRUCT_PARM_ALIGN__;
+         if (align > 1)
+           next_arg.p = ALIGN (next_arg.p, align);
+#endif
          words = ((*ptr)->size + 7) / 8;
          if (next_arg.ul >= gpr_base.ul && next_arg.ul + words > gpr_end.ul)
            {
@@ -853,6 +864,10 @@ ffi_prep_cif_machdep_core (ffi_cif *cif)
   else
     for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
       {
+#ifdef __STRUCT_PARM_ALIGN__
+       unsigned int align;
+#endif
+
        switch ((*ptr)->type)
          {
 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
@@ -868,6 +883,14 @@ ffi_prep_cif_machdep_core (ffi_cif *cif)
            break;
 
          case FFI_TYPE_STRUCT:
+#ifdef __STRUCT_PARM_ALIGN__
+           align = (*ptr)->alignment;
+           if (align > __STRUCT_PARM_ALIGN__)
+             align = __STRUCT_PARM_ALIGN__;
+           align = align / 8;
+           if (align > 1)
+             intarg_count = ALIGN (intarg_count, align);
+#endif
            intarg_count += ((*ptr)->size + 7) / 8;
            break;
 
@@ -1399,6 +1422,9 @@ ffi_closure_helper_LINUX64 (ffi_closure *closure, void *rvalue,
   unsigned long i, avn, nfixedargs;
   ffi_cif *cif;
   ffi_dblfl *end_pfr = pfr + NUM_FPR_ARG_REGISTERS64;
+#ifdef __STRUCT_PARM_ALIGN__
+  unsigned long align;
+#endif
 
   cif = closure->cif;
   avalue = alloca (cif->nargs * sizeof (void *));
@@ -1453,6 +1479,13 @@ ffi_closure_helper_LINUX64 (ffi_closure *closure, void *rvalue,
          break;
 
        case FFI_TYPE_STRUCT:
+#ifdef __STRUCT_PARM_ALIGN__
+         align = arg_types[i]->alignment;
+         if (align > __STRUCT_PARM_ALIGN__)
+           align = __STRUCT_PARM_ALIGN__;
+         if (align > 1)
+           pst = (unsigned long *) ALIGN ((size_t) pst, align);
+#endif
 #ifndef __LITTLE_ENDIAN__
          /* Structures with size less than eight bytes are passed
             left-padded.  */