From 1c06515d927d9de1582438d4eb5953890e79c5c7 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Sat, 16 Nov 2013 06:41:36 -0500 Subject: [PATCH] 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 --- ChangeLog | 7 +++++++ src/powerpc/ffi.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/ChangeLog b/ChangeLog index bca12119..2a4c8dc8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2013-11-16 Alan Modra + + * 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 * src/powerpc/linux64.S (ffi_call_LINUX64): Tweak restore of r28. diff --git a/src/powerpc/ffi.c b/src/powerpc/ffi.c index a22ac27b..12501b6d 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. */