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 almost all the other #ifdefs present there and in assembly.
* 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. diff -urp gcc5/libffi/src/powerpc/ffi.c gcc6/libffi/src/powerpc/ffi.c --- gcc5/libffi/src/powerpc/ffi.c 2013-11-15 23:47:31.890003986 +1030 +++ gcc6/libffi/src/powerpc/ffi.c 2013-11-15 23:47:40.153680507 +1030 @@ -428,6 +428,7 @@ ffi_prep_args64 (extended_cif *ecif, uns unsigned long *ul; float *f; double *d; + size_t p; } valp; /* 'stacktop' points at the previous backchain pointer. */ @@ -462,6 +463,9 @@ ffi_prep_args64 (extended_cif *ecif, uns 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; @@ -538,6 +542,13 @@ ffi_prep_args64 (extended_cif *ecif, uns #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) { @@ -828,6 +839,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 @@ -843,6 +858,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; @@ -1383,6 +1406,9 @@ ffi_closure_helper_LINUX64 (ffi_closure 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 *)); @@ -1437,6 +1463,13 @@ ffi_closure_helper_LINUX64 (ffi_closure 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. */ -- Alan Modra Australia Development Lab, IBM