From 0de8f0763ac11d8d13c8aa19ecff99543de32280 Mon Sep 17 00:00:00 2001 From: Christopher Wellons Date: Sun, 18 Oct 2026 10:24:39 -0400 Subject: [PATCH] Keep long long locals 8-byte aligned on i686 GCC 16 lowered the 32-bit cygming preferred stack boundary to 4 bytes, and the i386 back end then places long long locals at 4-byte alignment even though -malign-double, the default on these targets, makes _Alignof(long long) 8. Such locals trap under -fsanitize=alignment. Treat them as the back end already treats doubles. Co-Authored-By: Claude Opus 5.5 --- src/gcc/align-double-locals.patch | 43 +++++++++++++++++++++++++++++++ src/gcc/series | 1 + 2 files changed, 44 insertions(+) create mode 100644 src/gcc/align-double-locals.patch diff --git a/src/gcc/align-double-locals.patch b/src/gcc/align-double-locals.patch new file mode 100644 index 0000000..e8c4e65 --- /dev/null +++ b/src/gcc/align-double-locals.patch @@ -0,0 +1,43 @@ +Keep long long locals 8-byte aligned on i686 Windows. GCC 16 lowered +the default preferred stack boundary for 32-bit cygming targets to 4 +bytes. With a 4-byte boundary, the i386 back end lowers the alignment +of long long locals to 4 bytes to avoid dynamic stack realignment, both +when laying out declarations (ix86_local_alignment) and when deciding +whether a frame needs realignment (ix86_minimum_alignment). That is +valid for the System V i386 ABI, where long long has 4-byte ABI +alignment, but these targets default to -malign-double, so +_Alignof(long long) is 8. Lowering then places objects below their +type's alignment, and -fsanitize=alignment traps on them: + + void store(long long *p) { *p = 1; } + void f(void) { long long x; store(&x); } // &x % 8 == 4 + +Doubles and address-taken long long parameters are already realigned; +this treats long long locals the same way whenever -malign-double is in +effect. Spill slots that are not visible to the program are realigned +too, but the cost is small: on zstd and xxHash at -O2, about 0.6% more +instructions. + +--- a/gcc/config/i386/i386.cc ++++ b/gcc/config/i386/i386.cc +@@ -18763,7 +18763,7 @@ + /* Don't do dynamic stack realignment for long long objects with + -mpreferred-stack-boundary=2. */ + if (may_lower +- && !TARGET_64BIT ++ && !TARGET_64BIT && !TARGET_ALIGN_DOUBLE + && align == 64 + && ix86_preferred_stack_boundary < 64 + && (mode == DImode || (type && TYPE_MODE (type) == DImode)) +@@ -18873,7 +18873,10 @@ + decl = NULL; + } + +- if (TARGET_64BIT || align != 64 || ix86_preferred_stack_boundary >= 64) ++ /* With -malign-double the ABI alignment of long long is 64 bits, so ++ it cannot be lowered (see x86_field_alignment). */ ++ if (TARGET_64BIT || TARGET_ALIGN_DOUBLE ++ || align != 64 || ix86_preferred_stack_boundary >= 64) + return align; + + /* Don't do dynamic stack realignment for long long objects with diff --git a/src/gcc/series b/src/gcc/series index 01435be..d9162c6 100644 --- a/src/gcc/series +++ b/src/gcc/series @@ -3,3 +3,4 @@ dynamic-load-tzdb.patch libgfortran-mapview.patch trap-terminate.patch system-clock-y2038.patch +align-double-locals.patch