From 1b12593d7e595c03e5c06377feaeb8ad1b813681 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 24 Nov 2014 12:55:43 +0100 Subject: [PATCH] x86: Honor alignment of arguments Darwin aligns long-double to 16, and thus all of the long double tests were failing due to not honoring that. We ought to be able to devise a test case for GCC using __attribute__((aligned)) that would have failed too. --- src/x86/ffi.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/x86/ffi.c b/src/x86/ffi.c index 4c96c6d..c4d740a 100644 --- a/src/x86/ffi.c +++ b/src/x86/ffi.c @@ -332,13 +332,28 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue, else { size_t za = ALIGN (z, FFI_SIZEOF_ARG); + size_t align = FFI_SIZEOF_ARG; + + /* Alignment rules for arguments are quite complex. Vectors and + structures with 16 byte alignment get it. Note that long double + on Darwin does have 16 byte alignment, and does not get this + alignment if passed directly; a structure with a long double + inside, however, would get 16 byte alignment. Since libffi does + not support vectors, we need non concern ourselves with other + cases. */ + if (t == FFI_TYPE_STRUCT && ty->alignment >= 16) + align = 16; + if (dir < 0) { + /* ??? These reverse argument ABIs are probably too old + to have cared about alignment. Someone should check. */ argp -= za; memcpy (argp, valp, z); } else { + argp = (char *)ALIGN (argp, align); memcpy (argp, valp, z); argp += za; } @@ -419,8 +434,9 @@ ffi_closure_inner (struct closure_frame *frame, char *stack) arg_types = cif->arg_types; for (i = 0; i < n; ++i) { - size_t z = arg_types[i]->size; - int t = arg_types[i]->type; + ffi_type *ty = arg_types[i]; + size_t z = ty->size; + int t = ty->type; void *valp; if (z <= FFI_SIZEOF_ARG && t != FFI_TYPE_STRUCT) @@ -441,13 +457,22 @@ ffi_closure_inner (struct closure_frame *frame, char *stack) else { size_t za = ALIGN (z, FFI_SIZEOF_ARG); + size_t align = FFI_SIZEOF_ARG; + + /* See the comment in ffi_call_int. */ + if (t == FFI_TYPE_STRUCT && ty->alignment >= 16) + align = 16; + if (dir < 0) { + /* ??? These reverse argument ABIs are probably too old + to have cared about alignment. Someone should check. */ argp -= za; valp = argp; } else { + argp = (char *)ALIGN (argp, align); valp = argp; argp += za; } -- 2.7.4