The powerpc64 ABIs align structs passed by value, a fact ignored by 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
diff --git a/ChangeLog b/ChangeLog
index bca1211..2a4c8dc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,12 @@
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.
(.note.GNU-stack): Move inside outer #ifdef.
* src/powerpc/linux64_closure.S (STACKFRAME, PARMSAVE,
diff --git a/src/powerpc/ffi.c b/src/powerpc/ffi.c
index a22ac27..12501b6 100644
--- a/src/powerpc/ffi.c
+++ b/src/powerpc/ffi.c
@@ -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. */