On Tuesday 30 June 2026 14:57:04 LIU Hao wrote:
> Hi Pali,
> 
> There's a report about this linker error today:
> https://github.com/mingw-w64/mingw-w64/issues/177#issuecomment-4840677432
> 
> The current setup where libmsvcrt references symbols from libmingw32 doesn't
> look quite correct; in GCC default specs, CRT libraries are linked in this
> order `-lmingw32 -lmingwex -lmsvcrt`. Therefore I suggest
> b9ac6b67372d065a5bcd4f515b7f84118a65446b be reverted before the issue is
> solved.

Hello, thank you for noticing me about this problem.

I understand this problem, variables/functions/symbols defined in
mingw-w64-crt/crt/ directory cannot be referenced in files from other
directories because /crt/ is in libmingw32.a library and that is before
other libraries in gcc specs file.

The bad thing about this issue is that it happens only sometimes. I did
not figured out when gcc/ld starts complaining about
"undefined reference" and when not. I observed that higher probability
is when the LTO is enabled.

For example on CI in tests are used those i386__beginthreadex.c
implementations and 32-bit x86 gcc on CI is happy, it always passed.
Also it passed all my local testing. So such issues can happen and we
will get info about them only once somebody hit it.


In the attachment I'm sending a proposal for fixing this issue.
Basically "copy" the implementation into both crtexe.c and
i386__beginthreadex.c files. I do not see any easy way how to "share"
that one symbol between libmingw32.a and libmsvcrt-os.a (or libmsvcrt.a).
And because now the __mingw_SEH_error_handler implementation is very
small (just wrapper around the _XcptFilter), so do not think this
copy would be an issue.

I have tested it only locally, to provide fix as fast as possible, so
maybe there could be some CI issues.

Could you please forward these patches to reporter, so could try to
verify if it works?

Note that patches are on top of my "__mingw_init_ehandler" changes:
https://sourceforge.net/p/mingw-w64/mailman/message/59348860/
but rebasing without them should be relatively easy, there should be
just context conflict in crtexe.c around "asm volatile" line.
>From 2e2f7c4fa08b98fc0d55d8c69a1110ea2e42ec19 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <[email protected]>
Date: Tue, 23 Jun 2026 22:34:44 +0200
Subject: [PATCH 1/3] crt: Move duplicated sse_float_exception_handler function
 into common file i386_sse_float_exception_handler.h

---
 mingw-w64-crt/misc/i386__beginthread.c        | 19 +--------------
 mingw-w64-crt/misc/i386__beginthreadex.c      | 19 +--------------
 .../misc/i386_sse_float_exception_handler.h   | 24 +++++++++++++++++++
 3 files changed, 26 insertions(+), 36 deletions(-)
 create mode 100644 mingw-w64-crt/misc/i386_sse_float_exception_handler.h

diff --git a/mingw-w64-crt/misc/i386__beginthread.c 
b/mingw-w64-crt/misc/i386__beginthread.c
index 6d07df7e7cfa..150b0f3d6ec6 100644
--- a/mingw-w64-crt/misc/i386__beginthread.c
+++ b/mingw-w64-crt/misc/i386__beginthread.c
@@ -6,29 +6,12 @@
 
 #if defined(__i386__)
 
-/* Function _beginthread() in pre-msvcr100 libraries do not handle 
STATUS_FLOAT_MULTIPLE_FAULTS and STATUS_FLOAT_MULTIPLE_TRAPS SEH exceptions.
- * These two SEH exceptions are thrown by Windows system for 32-bit x86 
processes when SSE floating point exception occurs.
- * So fix the pre-msvcr100 behavior by catching those two exceptions manually 
and propagating them to __mingw_SEH_error_handler() which correctly process 
them.
- * x87 floating point exceptions and also 64-bit x86 processes are correctly 
handled by msvcr* libraries. */
-
 #include <stdlib.h>
 #include <errno.h>
 #include <process.h>
 #include <windows.h>
 
-EXCEPTION_DISPOSITION __cdecl __mingw_SEH_error_handler(EXCEPTION_RECORD *, 
PVOID, CONTEXT *, PVOID);
-
-#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 EXCEPTION_DISPOSITION __cdecl 
sse_float_exception_handler(EXCEPTION_RECORD *ExceptionRecord, PVOID 
EstablisherFrame, CONTEXT *ContextRecord, PVOID DispatcherContext)
-{
-  if (ExceptionRecord->ExceptionCode == STATUS_FLOAT_MULTIPLE_FAULTS || 
ExceptionRecord->ExceptionCode == STATUS_FLOAT_MULTIPLE_TRAPS)
-    return __mingw_SEH_error_handler(ExceptionRecord, EstablisherFrame, 
ContextRecord, DispatcherContext);
-  else
-    return ExceptionContinueSearch;
-}
+#include "i386_sse_float_exception_handler.h"
 
 #if defined(__i386__)
 /* We need to make sure that we align the stack to 16 bytes for the sake of 
SSE */
diff --git a/mingw-w64-crt/misc/i386__beginthreadex.c 
b/mingw-w64-crt/misc/i386__beginthreadex.c
index aede03f34d31..b23f654844fa 100644
--- a/mingw-w64-crt/misc/i386__beginthreadex.c
+++ b/mingw-w64-crt/misc/i386__beginthreadex.c
@@ -6,29 +6,12 @@
 
 #if defined(__i386__)
 
-/* Function _beginthreadex() in pre-msvcr100 libraries do not handle 
STATUS_FLOAT_MULTIPLE_FAULTS and STATUS_FLOAT_MULTIPLE_TRAPS SEH exceptions.
- * These two SEH exceptions are thrown by Windows system for 32-bit x86 
processes when SSE floating point exception occurs.
- * So fix the pre-msvcr100 behavior by catching those two exceptions manually 
and propagating them to __mingw_SEH_error_handler() which correctly process 
them.
- * x87 floating point exceptions and also 64-bit x86 processes are correctly 
handled by msvcr* libraries. */
-
 #include <stdlib.h>
 #include <errno.h>
 #include <process.h>
 #include <windows.h>
 
-EXCEPTION_DISPOSITION __cdecl __mingw_SEH_error_handler(EXCEPTION_RECORD *, 
PVOID, CONTEXT *, PVOID);
-
-#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 EXCEPTION_DISPOSITION __cdecl 
sse_float_exception_handler(EXCEPTION_RECORD *ExceptionRecord, PVOID 
EstablisherFrame, CONTEXT *ContextRecord, PVOID DispatcherContext)
-{
-  if (ExceptionRecord->ExceptionCode == STATUS_FLOAT_MULTIPLE_FAULTS || 
ExceptionRecord->ExceptionCode == STATUS_FLOAT_MULTIPLE_TRAPS)
-    return __mingw_SEH_error_handler(ExceptionRecord, EstablisherFrame, 
ContextRecord, DispatcherContext);
-  else
-    return ExceptionContinueSearch;
-}
+#include "i386_sse_float_exception_handler.h"
 
 #if defined(__i386__)
 /* We need to make sure that we align the stack to 16 bytes for the sake of 
SSE */
diff --git a/mingw-w64-crt/misc/i386_sse_float_exception_handler.h 
b/mingw-w64-crt/misc/i386_sse_float_exception_handler.h
new file mode 100644
index 000000000000..940c88c6aa12
--- /dev/null
+++ b/mingw-w64-crt/misc/i386_sse_float_exception_handler.h
@@ -0,0 +1,24 @@
+/**
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is part of the mingw-w64 runtime package.
+ * No warranty is given; refer to the file DISCLAIMER.PD within this package.
+ */
+
+/* Functions _beginthread() and _beginthreadex() in 32-bit x86 pre-msvcr100 
libraries do not handle STATUS_FLOAT_MULTIPLE_FAULTS and 
STATUS_FLOAT_MULTIPLE_TRAPS SEH exceptions.
+ * These two SEH exceptions are thrown by Windows system for 32-bit x86 
processes when SSE floating point exception occurs.
+ * So fix the pre-msvcr100 behavior by catching those two exceptions manually 
and propagating them to __mingw_SEH_error_handler() which correctly process 
them.
+ * x87 floating point exceptions and also 64-bit x86 processes are correctly 
handled by msvcr* libraries. */
+
+EXCEPTION_DISPOSITION __cdecl __mingw_SEH_error_handler(EXCEPTION_RECORD *, 
PVOID, CONTEXT *, PVOID);
+
+#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 EXCEPTION_DISPOSITION __cdecl 
sse_float_exception_handler(EXCEPTION_RECORD *ExceptionRecord, PVOID 
EstablisherFrame, CONTEXT *ContextRecord, PVOID DispatcherContext)
+{
+  if (ExceptionRecord->ExceptionCode == STATUS_FLOAT_MULTIPLE_FAULTS || 
ExceptionRecord->ExceptionCode == STATUS_FLOAT_MULTIPLE_TRAPS)
+    return __mingw_SEH_error_handler(ExceptionRecord, EstablisherFrame, 
ContextRecord, DispatcherContext);
+  else
+    return ExceptionContinueSearch;
+}
-- 
2.20.1


>From 2f305bf87586f7f915409f95bfeecda7dac1532c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <[email protected]>
Date: Tue, 30 Jun 2026 20:34:06 +0200
Subject: [PATCH 2/3] crt: Fix linking issues for __mingw_SEH_error_handler
 symbol

When LTO is enabled, gcc in some configurations cannot reference the
__mingw_SEH_error_handler symbol from i386__beginthreadex.c file.

This is because -lmingw32 is before -lmsvcrt in gcc specs file, which means
that libmsvcrt.a (library which contains i386__beginthreadex.o) cannot
reference symbols from libmingw32.a (library which provides the
__mingw_SEH_error_handler symbol). Only opposite direction is valid.

Fix this problem by including the implementation of
__mingw_SEH_error_handler symbol into the i386__beginthreadex.c itself.

To prevent this issue to happen again, move the implementation of
__mingw_SEH_error_handler from .c file to internal header file and mark it
as static. That header file is then included into the i386__beginthreadex.c.

And also remove arm64ec symbol mangling in crtexe.c file which is needed
only for non-static symbols. Static symbols do not use that mangling.
---
 mingw-w64-crt/Makefile.am                            |  4 ++--
 mingw-w64-crt/crt/crtexe.c                           | 12 +++---------
 .../crt/{crt_handler.c => seh_signal_dispatcher.h}   |  4 +---
 .../misc/i386_sse_float_exception_handler.h          |  2 +-
 4 files changed, 7 insertions(+), 15 deletions(-)
 rename mingw-w64-crt/crt/{crt_handler.c => seh_signal_dispatcher.h} (92%)

diff --git a/mingw-w64-crt/Makefile.am b/mingw-w64-crt/Makefile.am
index b651dce59d51..31ce267e9183 100644
--- a/mingw-w64-crt/Makefile.am
+++ b/mingw-w64-crt/Makefile.am
@@ -115,14 +115,14 @@ src_libtaskschd=libsrc/taskschd.c
 src_libntoskrnl=libsrc/memcmp.c
 src_libdloadhelper=libsrc/dloadhelper.c misc/delay-f.c
 
-src_libmingw32=include/internal.h include/sect_attribs.h \
+src_libmingw32=include/internal.h include/sect_attribs.h 
crt/seh_signal_dispatcher.h \
   crt/crtexewin.c     crt/dll_argv.c  crt/gccmain.c     crt/natstart.c  
crt/pseudo-reloc-list.c  crt/wildcard.c \
   crt/charmax.c       crt/ucrtexewin.c crt/dllargv.c    crt/_newmode.c  
crt/tlssup.c             crt/xncommod.c \
   crt/cinitexe.c      crt/merr.c      crt/pesect.c      crt/udllargc.c  
crt/xthdloc.c \
   crt/mingw_custom.c  crt/mingw_helpers.c  \
   crt/pseudo-reloc.c  crt/udll_argv.c      \
   crt/usermatherr.c   \
-  crt/xtxtmode.c      crt/crt_handler.c    \
+  crt/xtxtmode.c      \
   crt/tlsthrd.c       crt/tlsmthread.c     crt/tlsmcrt.c   \
   crt/cxa_atexit.c    crt/cxa_thread_atexit.c crt/tls_atexit.c
 
diff --git a/mingw-w64-crt/crt/crtexe.c b/mingw-w64-crt/crt/crtexe.c
index c52ac02ac214..82324497b828 100644
--- a/mingw-w64-crt/crt/crtexe.c
+++ b/mingw-w64-crt/crt/crtexe.c
@@ -24,19 +24,14 @@
 #else
 #define ASM_SEH_EXCEPT "@except"
 #endif
-#ifdef __arm64ec__
-#define ASM_SEH_PREFIX "\"#"
-#define ASM_SEH_SUFFIX "\""
-#else
-#define ASM_SEH_PREFIX ""
-#define ASM_SEH_SUFFIX ""
-#endif
 #endif
 
 #if !defined(__i386__) && !defined(SEH_INLINE_ASM)
 #include "runtime_seh.h"
 #endif
 
+#include "seh_signal_dispatcher.h"
+
 extern IMAGE_DOS_HEADER __ImageBase;
 
 int *__cdecl __p__commode(void);
@@ -70,7 +65,6 @@ static int managedapp;
 static int has_cctor = 0;
 
 extern void _pei386_runtime_relocator (void);
-EXCEPTION_DISPOSITION __cdecl __mingw_SEH_error_handler (struct 
_EXCEPTION_RECORD *, void *, struct _CONTEXT *, void *);
 static int duplicate_ppstrings (int ac, _TCHAR ***av);
 
 extern int _MINGW_INSTALL_DEBUG_MATHERR;
@@ -172,7 +166,7 @@ __tmainCRTStartup (void)
     };
     __writefsdword (0, (DWORD)&exception_record); /* dynamically register SEH 
error handler, it is active until manually unregistered */
 #elif defined(SEH_INLINE_ASM)
-    asm volatile (".seh_handler " ASM_SEH_PREFIX "%c0" ASM_SEH_SUFFIX ", " 
ASM_SEH_EXCEPT :: "i" (__mingw_SEH_error_handler)); /* statically register SEH 
error handler, it is active only in the current function */
+    asm volatile (".seh_handler %c0, " ASM_SEH_EXCEPT :: "i" 
(__mingw_SEH_error_handler)); /* statically register SEH error handler, it is 
active only in the current function */
 #else
     asm volatile ("" :: "r" (__builtin_frame_address (0))); /* force usage of 
the standard prolog with frame pointer */
     if (!register_runtime_function_exception_handler 
((uintptr_t)&__tmainCRTStartup, (uintptr_t)&__tmainCRTStartup_end, 
__mingw_SEH_error_handler)) /* dynamically register SEH error handler, it is 
active only in the specified function */
diff --git a/mingw-w64-crt/crt/crt_handler.c 
b/mingw-w64-crt/crt/seh_signal_dispatcher.h
similarity index 92%
rename from mingw-w64-crt/crt/crt_handler.c
rename to mingw-w64-crt/crt/seh_signal_dispatcher.h
index c484e8e57a8c..e9fab6b67991 100644
--- a/mingw-w64-crt/crt/crt_handler.c
+++ b/mingw-w64-crt/crt/seh_signal_dispatcher.h
@@ -8,13 +8,11 @@
 #include <excpt.h>
 #include <stdlib.h>
 
-EXCEPTION_DISPOSITION __cdecl __mingw_SEH_error_handler(struct 
_EXCEPTION_RECORD *, void *, struct _CONTEXT *, void *);
-
 #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
-EXCEPTION_DISPOSITION __cdecl
+static EXCEPTION_DISPOSITION __cdecl
 __mingw_SEH_error_handler (struct _EXCEPTION_RECORD* ExceptionRecord,
                           void *EstablisherFrame  __attribute__ ((unused)),
                           struct _CONTEXT* ContextRecord,
diff --git a/mingw-w64-crt/misc/i386_sse_float_exception_handler.h 
b/mingw-w64-crt/misc/i386_sse_float_exception_handler.h
index 940c88c6aa12..44aca73f3a64 100644
--- a/mingw-w64-crt/misc/i386_sse_float_exception_handler.h
+++ b/mingw-w64-crt/misc/i386_sse_float_exception_handler.h
@@ -9,7 +9,7 @@
  * So fix the pre-msvcr100 behavior by catching those two exceptions manually 
and propagating them to __mingw_SEH_error_handler() which correctly process 
them.
  * x87 floating point exceptions and also 64-bit x86 processes are correctly 
handled by msvcr* libraries. */
 
-EXCEPTION_DISPOSITION __cdecl __mingw_SEH_error_handler(EXCEPTION_RECORD *, 
PVOID, CONTEXT *, PVOID);
+#include "../crt/seh_signal_dispatcher.h"
 
 #if defined(__i386__)
 /* We need to make sure that we align the stack to 16 bytes for the sake of 
SSE */
-- 
2.20.1


>From 96113be0d4cc7725fb75a04e65ec9b13e0e78e29 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <[email protected]>
Date: Sat, 13 Jun 2026 11:48:35 +0200
Subject: [PATCH 3/3] crt: Rename __mingw_SEH_error_handler to
 __mingw_SEH_signal_dispatcher

This better describe the purpose and logic of that function.
Add also description of the function into the comment.
---
 mingw-w64-crt/crt/crtexe.c                            | 8 ++++----
 mingw-w64-crt/crt/seh_signal_dispatcher.h             | 7 ++++++-
 mingw-w64-crt/misc/i386_sse_float_exception_handler.h | 4 ++--
 3 files changed, 12 insertions(+), 7 deletions(-)

diff --git a/mingw-w64-crt/crt/crtexe.c b/mingw-w64-crt/crt/crtexe.c
index 82324497b828..17899f39794f 100644
--- a/mingw-w64-crt/crt/crtexe.c
+++ b/mingw-w64-crt/crt/crtexe.c
@@ -157,19 +157,19 @@ __attribute__((section(".text.__tmainCRTStartup$A")))
 __declspec(noinline) int
 __tmainCRTStartup (void)
 {
-    /* Registration of SEH error handler __mingw_SEH_error_handler used for
+    /* Registration of SEH error handler __mingw_SEH_signal_dispatcher used for
      * delivering SEH exceptions to registered CRT signal handlers. */
 #if defined(__i386__)
     EXCEPTION_REGISTRATION_RECORD exception_record = {
       .Next = (EXCEPTION_REGISTRATION_RECORD *)__readfsdword (0),
-      .Handler = (PEXCEPTION_ROUTINE)(INT_PTR)__mingw_SEH_error_handler,
+      .Handler = (PEXCEPTION_ROUTINE)(INT_PTR)__mingw_SEH_signal_dispatcher,
     };
     __writefsdword (0, (DWORD)&exception_record); /* dynamically register SEH 
error handler, it is active until manually unregistered */
 #elif defined(SEH_INLINE_ASM)
-    asm volatile (".seh_handler %c0, " ASM_SEH_EXCEPT :: "i" 
(__mingw_SEH_error_handler)); /* statically register SEH error handler, it is 
active only in the current function */
+    asm volatile (".seh_handler %c0, " ASM_SEH_EXCEPT :: "i" 
(__mingw_SEH_signal_dispatcher)); /* statically register SEH error handler, it 
is active only in the current function */
 #else
     asm volatile ("" :: "r" (__builtin_frame_address (0))); /* force usage of 
the standard prolog with frame pointer */
-    if (!register_runtime_function_exception_handler 
((uintptr_t)&__tmainCRTStartup, (uintptr_t)&__tmainCRTStartup_end, 
__mingw_SEH_error_handler)) /* dynamically register SEH error handler, it is 
active only in the specified function */
+    if (!register_runtime_function_exception_handler 
((uintptr_t)&__tmainCRTStartup, (uintptr_t)&__tmainCRTStartup_end, 
__mingw_SEH_signal_dispatcher)) /* dynamically register SEH error handler, it 
is active only in the specified function */
       _amsg_exit (22); /* _RT_NONCONT_TXT */
     if (!register_runtime_image_unwind_info ()) /* dynamically register 
propagation of SEH exceptions for the whole image */
       _amsg_exit (22); /* _RT_NONCONT_TXT */
diff --git a/mingw-w64-crt/crt/seh_signal_dispatcher.h 
b/mingw-w64-crt/crt/seh_signal_dispatcher.h
index e9fab6b67991..7d087ffc1e7c 100644
--- a/mingw-w64-crt/crt/seh_signal_dispatcher.h
+++ b/mingw-w64-crt/crt/seh_signal_dispatcher.h
@@ -8,12 +8,17 @@
 #include <excpt.h>
 #include <stdlib.h>
 
+/* This is SEH exception handler which handles only SEH exceptions for
+ * C signals and dispatches them to the registered C signal handler.
+ * Calling the appropriate C signal handler which was registered by the
+ * CRT signal() function is done by the CRT _XcptFilter() function.
+ */
 #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 EXCEPTION_DISPOSITION __cdecl
-__mingw_SEH_error_handler (struct _EXCEPTION_RECORD* ExceptionRecord,
+__mingw_SEH_signal_dispatcher (struct _EXCEPTION_RECORD* ExceptionRecord,
                           void *EstablisherFrame  __attribute__ ((unused)),
                           struct _CONTEXT* ContextRecord,
                           void *DispatcherContext __attribute__ ((unused)))
diff --git a/mingw-w64-crt/misc/i386_sse_float_exception_handler.h 
b/mingw-w64-crt/misc/i386_sse_float_exception_handler.h
index 44aca73f3a64..98ebecb2bc0e 100644
--- a/mingw-w64-crt/misc/i386_sse_float_exception_handler.h
+++ b/mingw-w64-crt/misc/i386_sse_float_exception_handler.h
@@ -6,7 +6,7 @@
 
 /* Functions _beginthread() and _beginthreadex() in 32-bit x86 pre-msvcr100 
libraries do not handle STATUS_FLOAT_MULTIPLE_FAULTS and 
STATUS_FLOAT_MULTIPLE_TRAPS SEH exceptions.
  * These two SEH exceptions are thrown by Windows system for 32-bit x86 
processes when SSE floating point exception occurs.
- * So fix the pre-msvcr100 behavior by catching those two exceptions manually 
and propagating them to __mingw_SEH_error_handler() which correctly process 
them.
+ * So fix the pre-msvcr100 behavior by catching those two exceptions manually 
and propagating them to __mingw_SEH_signal_dispatcher() which correctly process 
them.
  * x87 floating point exceptions and also 64-bit x86 processes are correctly 
handled by msvcr* libraries. */
 
 #include "../crt/seh_signal_dispatcher.h"
@@ -18,7 +18,7 @@ __attribute__((force_align_arg_pointer))
 static EXCEPTION_DISPOSITION __cdecl 
sse_float_exception_handler(EXCEPTION_RECORD *ExceptionRecord, PVOID 
EstablisherFrame, CONTEXT *ContextRecord, PVOID DispatcherContext)
 {
   if (ExceptionRecord->ExceptionCode == STATUS_FLOAT_MULTIPLE_FAULTS || 
ExceptionRecord->ExceptionCode == STATUS_FLOAT_MULTIPLE_TRAPS)
-    return __mingw_SEH_error_handler(ExceptionRecord, EstablisherFrame, 
ContextRecord, DispatcherContext);
+    return __mingw_SEH_signal_dispatcher(ExceptionRecord, EstablisherFrame, 
ContextRecord, DispatcherContext);
   else
     return ExceptionContinueSearch;
 }
-- 
2.20.1

_______________________________________________
Mingw-w64-public mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public

Reply via email to