Hello, I was debugging one of my own beginthreadex & floating point test why it is crashing on 32-bit x86 when executing floating point operation and I have figured out that it is because of unaligned SSE2 instructions. It was quite hard to figure it out when I was modifying test for floating point exceptions and I got some other exception that I was expected.
Basically WinAPI or CRT functions on 32-bit x86 can call callback passed from gcc/mingw-w64 without prepared stack for SSE2 execution. To avoid any crashing issues, it is really needed to align stack for SSE2 execution inside any callback function passed to the WinAPI or CRT via the __attribute__((force_align_arg_pointer)). mingw-w64 already have this attribute declared on more callback places but there are still few missing. In attachment I'm sending changes which adds it. Kirill Makurin run CI testing for me and all of them passed: https://github.com/maiddaisuki/mingw-w64/actions/runs/25266565815 Pali
>From 9627843b900ccc444050d243a1d325328abc92f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <[email protected]> Date: Sun, 22 Feb 2026 20:13:01 +0100 Subject: [PATCH 1/3] winpthreads: Use force_align_arg_pointer attribute for entry point passed to _beginthreadex() for i386 gcc builds --- mingw-w64-libraries/winpthreads/tests/clock/t_nanosleep.c | 6 ++++++ .../winpthreads/tests/pthread_cancel/cancel7.c | 6 ++++++ .../winpthreads/tests/pthread_cancel/cancel8.c | 6 ++++++ mingw-w64-libraries/winpthreads/tests/pthread_exit/exit4.c | 6 ++++++ mingw-w64-libraries/winpthreads/tests/pthread_exit/exit5.c | 6 ++++++ 5 files changed, 30 insertions(+) diff --git a/mingw-w64-libraries/winpthreads/tests/clock/t_nanosleep.c b/mingw-w64-libraries/winpthreads/tests/clock/t_nanosleep.c index c876dc7b0a7c..001bb2c5b1b2 100644 --- a/mingw-w64-libraries/winpthreads/tests/clock/t_nanosleep.c +++ b/mingw-w64-libraries/winpthreads/tests/clock/t_nanosleep.c @@ -15,6 +15,12 @@ __int64 timespec_diff_as_ms(struct timespec *__old, struct timespec *__new) + (__new->tv_nsec - __old->tv_nsec) / POW10_6; } +#if defined(__i386__) +/* Align ESP on 16-byte boundaries. */ +# if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2)) +__attribute__((force_align_arg_pointer)) +# endif +#endif unsigned __stdcall start_address(void *dummy) { int counter = 0; diff --git a/mingw-w64-libraries/winpthreads/tests/pthread_cancel/cancel7.c b/mingw-w64-libraries/winpthreads/tests/pthread_cancel/cancel7.c index 27c12afb74fe..494432057caa 100644 --- a/mingw-w64-libraries/winpthreads/tests/pthread_cancel/cancel7.c +++ b/mingw-w64-libraries/winpthreads/tests/pthread_cancel/cancel7.c @@ -95,6 +95,12 @@ struct bag_t_ { static bag_t threadbag[NUMTHREADS + 1]; +#if defined(__i386__) +/* Align ESP on 16-byte boundaries. */ +# if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2)) +__attribute__((force_align_arg_pointer)) +# endif +#endif unsigned int __stdcall Win32thread(void * arg) { diff --git a/mingw-w64-libraries/winpthreads/tests/pthread_cancel/cancel8.c b/mingw-w64-libraries/winpthreads/tests/pthread_cancel/cancel8.c index faf28f1e73ed..9972f33c624d 100644 --- a/mingw-w64-libraries/winpthreads/tests/pthread_cancel/cancel8.c +++ b/mingw-w64-libraries/winpthreads/tests/pthread_cancel/cancel8.c @@ -32,6 +32,12 @@ static void wrap_pthread_mutex_unlock (void *ptr) pthread_mutex_unlock ((pthread_mutex_t *) ptr); } +#if defined(__i386__) +/* Align ESP on 16-byte boundaries. */ +# if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2)) +__attribute__((force_align_arg_pointer)) +# endif +#endif unsigned int __stdcall Win32thread(void * arg) { diff --git a/mingw-w64-libraries/winpthreads/tests/pthread_exit/exit4.c b/mingw-w64-libraries/winpthreads/tests/pthread_exit/exit4.c index aa377dc94135..4c92660dbe4a 100644 --- a/mingw-w64-libraries/winpthreads/tests/pthread_exit/exit4.c +++ b/mingw-w64-libraries/winpthreads/tests/pthread_exit/exit4.c @@ -94,6 +94,12 @@ struct bag_t_ { static bag_t threadbag[NUMTHREADS + 1]; +#if defined(__i386__) +/* Align ESP on 16-byte boundaries. */ +# if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2)) +__attribute__((force_align_arg_pointer)) +# endif +#endif unsigned int __stdcall Win32thread(void * arg) { diff --git a/mingw-w64-libraries/winpthreads/tests/pthread_exit/exit5.c b/mingw-w64-libraries/winpthreads/tests/pthread_exit/exit5.c index bb07ef4fa663..2153f49fa75b 100644 --- a/mingw-w64-libraries/winpthreads/tests/pthread_exit/exit5.c +++ b/mingw-w64-libraries/winpthreads/tests/pthread_exit/exit5.c @@ -95,6 +95,12 @@ struct bag_t_ { static bag_t threadbag[NUMTHREADS + 1]; +#if defined(__i386__) +/* Align ESP on 16-byte boundaries. */ +# if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2)) +__attribute__((force_align_arg_pointer)) +# endif +#endif unsigned int __stdcall Win32thread(void * arg) { -- 2.20.1 >From 38754bd17fd88f92313cf38886edf610c20b49e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <[email protected]> Date: Sun, 22 Feb 2026 21:14:11 +0100 Subject: [PATCH 2/3] crt: Mark profil profthr_func as force_align_arg_pointer --- mingw-w64-crt/profile/profil.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mingw-w64-crt/profile/profil.c b/mingw-w64-crt/profile/profil.c index c566bb6dd98d..d03018a36ec9 100644 --- a/mingw-w64-crt/profile/profil.c +++ b/mingw-w64-crt/profile/profil.c @@ -72,6 +72,10 @@ print_prof (struct profinfo *p) static DWORD CALLBACK profthr_func (LPVOID); +#if defined(__i386__) +/* We need to make sure that we align the stack to 16 bytes for the sake of SSE */ +__attribute__((force_align_arg_pointer)) +#endif static DWORD CALLBACK profthr_func (LPVOID arg) { -- 2.20.1 >From 746b8e247118d2ce74cd6df64c2b0a08937c242d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <[email protected]> Date: Sun, 22 Feb 2026 21:14:42 +0100 Subject: [PATCH 3/3] crt: test: Mark thread_main entry point as force_align_arg_pointer --- mingw-w64-crt/testcases/t_safe_flush.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mingw-w64-crt/testcases/t_safe_flush.c b/mingw-w64-crt/testcases/t_safe_flush.c index 7f63dd900870..8c323e8b924a 100644 --- a/mingw-w64-crt/testcases/t_safe_flush.c +++ b/mingw-w64-crt/testcases/t_safe_flush.c @@ -15,6 +15,10 @@ CRITICAL_SECTION cs; +#if defined(__i386__) +/* We need to make sure that we align the stack to 16 bytes for the sake of SSE */ +__attribute__((force_align_arg_pointer)) +#endif static DWORD WINAPI thread_main(LPVOID user_data) { HANDLE handle_event = (HANDLE) user_data; -- 2.20.1
_______________________________________________ Mingw-w64-public mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/mingw-w64-public
