Hello, In the attachment I'm sending changes which address __mingw_init_ehandler code issues and try to implement that functionality also for arm32/arm64. The amd64 is same what I sent in previous email, what I checked on example tests that is working.
The arm32 and arm64 changes are completely untested, I just extended that amd64 code according to the published MS documentation. So I would like to ask Evgeny for testing these changes and running mingw-w64 test suite if it working or if there are any issues.
>From 01635c58e4b3fe1caf5f4b6c58cae1009bc1a651 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <[email protected]> Date: Sat, 13 Jun 2026 11:31:36 +0200 Subject: [PATCH 1/3] crt: crt_handler: Rewrite __mingw_init_ehandler code used for amd64 non-SEH builds The purpose of registering __mingw_SEH_error_handler is to dispatch C signal exceptions and deliver them to C signal handlers. This done at the application entry point. So it should not registered in any DLL module. And also it should not be registered for any other function than the entry point of EXE application. The propagation of SEH exception from one function to another on the backtrace is done via SEH unwind codes. Function __mingw_init_ehandler() is used only for amd64 non-SEH builds and is currently registering the SEH handler __mingw_SEH_error_handler for all functions in EXE application and also for all functions in DLL module, both via the RtlAddFunctionTable() call. This means that the exception is never propagated to parent functions and is immediately processed, even when it should not be. Change this logic for amd64 non-SEH builds by registering SEH handler __mingw_SEH_error_handler via RtlAddFunctionTable() only for __tmainCRTStartup() entry point in EXE application at the exact same place where __mingw_SEH_error_handler is registered for SEH builds. Second change is to not register __mingw_SEH_error_handler for DLL modules at all (like it is already for SEH builds). And for SEH exception propagation register simple SEH unwind code which traverse backtrace via the stack frame pointers %rbp. It is not perfect, but probably the best what can be done for amd64 non-SEH builds. It should be reliable when compiling mingw-w64 and also application code with -fno-omit-frame-pointer flag. And when frame pointers are absent then %rbp should be untouched and not used for temporary variables. This could be achieved by -ffixed-rbp. To make code more modular, put this new code which calls RtlAddFunctionTable() function into the new runtime_seh.h file. --- mingw-w64-crt/crt/crt_handler.c | 67 ----------- mingw-w64-crt/crt/crtdll.c | 28 ++++- mingw-w64-crt/crt/crtexe.c | 28 ++++- mingw-w64-crt/crt/runtime_seh.h | 207 ++++++++++++++++++++++++++++++++ 4 files changed, 254 insertions(+), 76 deletions(-) create mode 100644 mingw-w64-crt/crt/runtime_seh.h diff --git a/mingw-w64-crt/crt/crt_handler.c b/mingw-w64-crt/crt/crt_handler.c index 191c2da65751..c484e8e57a8c 100644 --- a/mingw-w64-crt/crt/crt_handler.c +++ b/mingw-w64-crt/crt/crt_handler.c @@ -6,77 +6,10 @@ #include <windows.h> #include <excpt.h> -#include <string.h> #include <stdlib.h> -#include <malloc.h> -#include <memory.h> -#include <signal.h> -#include <stdio.h> EXCEPTION_DISPOSITION __cdecl __mingw_SEH_error_handler(struct _EXCEPTION_RECORD *, void *, struct _CONTEXT *, void *); -#if defined(__x86_64__) && !defined(_MSC_VER) && !defined(__SEH__) - -#pragma pack(push,1) -typedef struct _UNWIND_INFO { - BYTE Version:3; - BYTE Flags:5; - BYTE PrologSize; - BYTE CountOfUnwindCodes; - BYTE FrameRegisterAndOffset; - ULONG AddressOfExceptionHandler; -} UNWIND_INFO,*PUNWIND_INFO; -#pragma pack(pop) - -PIMAGE_SECTION_HEADER _FindPESectionByName (const char *); -PIMAGE_SECTION_HEADER _FindPESectionExec (size_t); -PBYTE _GetPEImageBase (void); - -#define MAX_PDATA_ENTRIES 32 -static RUNTIME_FUNCTION emu_pdata[MAX_PDATA_ENTRIES]; -static UNWIND_INFO emu_xdata[MAX_PDATA_ENTRIES]; - -int __mingw_init_ehandler (void); -int -__mingw_init_ehandler (void) -{ - static int was_here = 0; - size_t e = 0; - PIMAGE_SECTION_HEADER pSec; - PBYTE _ImageBase = _GetPEImageBase (); - - if (was_here || !_ImageBase) - return was_here; - was_here = 1; - if (_FindPESectionByName (".pdata") != NULL) - return 1; - - e = 0; - /* Fill tables and entries. */ - while (e < MAX_PDATA_ENTRIES && (pSec = _FindPESectionExec (e)) != NULL) - { - emu_xdata[e].Version = 1; - emu_xdata[e].Flags = UNW_FLAG_EHANDLER; - emu_xdata[e].AddressOfExceptionHandler = - (DWORD)(size_t) ((LPBYTE)__mingw_SEH_error_handler - _ImageBase); - emu_pdata[e].BeginAddress = pSec->VirtualAddress; - emu_pdata[e].EndAddress = pSec->VirtualAddress + pSec->Misc.VirtualSize; - emu_pdata[e].UnwindData = - (DWORD)(size_t)((LPBYTE)&emu_xdata[e] - _ImageBase); - ++e; - } -#ifdef _DEBUG_CRT - if (!e || e > MAX_PDATA_ENTRIES) - abort (); -#endif - /* RtlAddFunctionTable. */ - if (e != 0) - RtlAddFunctionTable (emu_pdata, e, (DWORD64)_ImageBase); - return 1; -} - -#endif - #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)) diff --git a/mingw-w64-crt/crt/crtdll.c b/mingw-w64-crt/crt/crtdll.c index 18e831ef9525..2ae36d75fcd5 100644 --- a/mingw-w64-crt/crt/crtdll.c +++ b/mingw-w64-crt/crt/crtdll.c @@ -17,9 +17,14 @@ #include <sect_attribs.h> #include <locale.h> -#if defined(__x86_64__) && !defined(__SEH__) -extern int __mingw_init_ehandler (void); +#if defined(__SEH__) && (!defined(__clang__) || __clang_major__ >= 7) +#define SEH_INLINE_ASM #endif + +#if defined(__x86_64__) && !defined(SEH_INLINE_ASM) +#include "runtime_seh.h" +#endif + extern void __main (); extern void _pei386_runtime_relocator (void); extern _PIFV __xi_a[]; @@ -72,9 +77,6 @@ WINBOOL WINAPI _CRT_INIT (HANDLE hDllHandle, DWORD dwReason, LPVOID lpreserved) __native_startup_state = __initializing; _pei386_runtime_relocator (); -#if defined(__x86_64__) && !defined(__SEH__) - __mingw_init_ehandler (); -#endif ret = _initialize_onexit_table (&atexit_table); if (ret != 0) goto i__leave; @@ -146,6 +148,14 @@ DllMainCRTStartup (HANDLE hDllHandle, DWORD dwReason, LPVOID lpreserved) { WINBOOL retcode = TRUE; +#if defined(__x86_64__) && !defined(SEH_INLINE_ASM) + if (dwReason == DLL_PROCESS_ATTACH) + { + if (!register_runtime_image_unwind_info ()) /* dynamically register propagation of SEH exceptions for the whole image */ + return FALSE; + } +#endif + if (dwReason == DLL_PROCESS_ATTACH) __mingw_app_type = 0; @@ -174,6 +184,14 @@ DllMainCRTStartup (HANDLE hDllHandle, DWORD dwReason, LPVOID lpreserved) } i__leave: __native_dllmain_reason = UINT_MAX; + +#if defined(__x86_64__) && !defined(SEH_INLINE_ASM) + if (dwReason == DLL_PROCESS_DETACH || (dwReason == DLL_PROCESS_ATTACH && !retcode)) + { + unregister_runtime_image_unwind_info (); /* dynamically unregister unwind info when unloading the DLL library */ + } +#endif + return retcode ; } diff --git a/mingw-w64-crt/crt/crtexe.c b/mingw-w64-crt/crt/crtexe.c index 86c3842f6162..c17c5b66cfad 100644 --- a/mingw-w64-crt/crt/crtexe.c +++ b/mingw-w64-crt/crt/crtexe.c @@ -33,6 +33,10 @@ #endif #endif +#if defined(__x86_64__) && !defined(SEH_INLINE_ASM) +#include "runtime_seh.h" +#endif + extern IMAGE_DOS_HEADER __ImageBase; int *__cdecl __p__commode(void); @@ -67,9 +71,6 @@ 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 *); -#if defined(__x86_64__) && !defined(SEH_INLINE_ASM) -int __mingw_init_ehandler (void); -#endif static int duplicate_ppstrings (int ac, _TCHAR ***av); extern int _MINGW_INSTALL_DEBUG_MATHERR; @@ -146,12 +147,19 @@ int mainCRTStartup (void) return __tmainCRTStartup (); } +#if defined(__x86_64__) && !defined(SEH_INLINE_ASM) +static int __tmainCRTStartup_real(void); +static const char __tmainCRTStartup_end; +#endif static #if defined(__i386__) || defined(_X86_) /* We need to make sure that we align the stack to 16 bytes for the sake of SSE opts in main or in functions called from main. */ __attribute__((force_align_arg_pointer)) #endif +#if defined(__x86_64__) && !defined(SEH_INLINE_ASM) +__attribute__((section(".text.__tmainCRTStartup$A"))) +#endif __declspec(noinline) int __tmainCRTStartup (void) { @@ -166,7 +174,19 @@ __tmainCRTStartup (void) #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 */ #elif defined(__x86_64__) - __mingw_init_ehandler (); /* dynamically register SEH error handler for all functions, it is active until program terminates */ + 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 */ + _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 */ + int ret = __tmainCRTStartup_real (); /* call the real __tmainCRTStartup with a new frame */ + asm volatile ("nop"); /* required by SEH unwind for __tmainCRTStartup_real */ + return ret; +} +__attribute__((section(".text.__tmainCRTStartup$Z"))) static const char __tmainCRTStartup_end = 0; +static __declspec(noinline) int __tmainCRTStartup_real (void) +{ + asm volatile ("" :: "r" (__builtin_frame_address (0))); /* force usage of the standard prolog with frame pointer */ #else #error unsupported platform #endif diff --git a/mingw-w64-crt/crt/runtime_seh.h b/mingw-w64-crt/crt/runtime_seh.h new file mode 100644 index 000000000000..29703978cbdd --- /dev/null +++ b/mingw-w64-crt/crt/runtime_seh.h @@ -0,0 +1,207 @@ +/** + * 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. + */ + +#include <windows.h> + +#if defined(__x86_64__) + +/* https://learn.microsoft.com/en-us/cpp/build/exception-handling-x64#unwind-data-definitions-in-c */ + +typedef enum { + UWOP_PUSH_NONVOL = 0, /* info == register number */ + UWOP_ALLOC_LARGE, /* no info, alloc size in next 2 slots */ + UWOP_ALLOC_SMALL, /* info == size of allocation / 8 - 1 */ + UWOP_SET_FPREG, /* no info, FP = RSP + UNWIND_INFO.FPRegOffset*16 */ + UWOP_SAVE_NONVOL, /* info == register number, offset in next slot */ + UWOP_SAVE_NONVOL_FAR, /* info == register number, offset in next 2 slots */ + UWOP_SAVE_XMM = 6, /* info == XMM reg number, offset in next slot, only for Version=1 */ + UWOP_EPILOG = 6, /* info&1 == 1: CodeOffset is both size and offset, 0: CodeOffset is size and offset in next slot, only for Version=2 */ + UWOP_SAVE_XMM_FAR = 7, /* info == XMM reg number, offset in next 2 slots, only for Version=1 */ + UWOP_SPARE = 7, /* no info, spare next 2 slots, only for Version=2 */ + UWOP_SAVE_XMM128, /* info == XMM reg number, offset in next slot */ + UWOP_SAVE_XMM128_FAR, /* info == XMM reg number, offset in next 2 slots */ + UWOP_PUSH_MACHFRAME, /* info == 0: no error-code, 1: error-code */ +} UNWIND_CODE_OPS; + +typedef enum { + UWREG_RAX = 0, + UWREG_RCX, + UWREG_RDX, + UWREG_RBX, + UWREG_RSP, + UWREG_RBP, + UWREG_RSI, + UWREG_RDI, + UWREG_R8, + UWREG_R9, + UWREG_R10, + UWREG_R11, + UWREG_R12, + UWREG_R13, + UWREG_R14, + UWREG_R15, + UWREG_XMM0, + UWREG_XMM1, + UWREG_XMM2, + UWREG_XMM3, + UWREG_XMM4, + UWREG_XMM5, + UWREG_XXM6, + UWREG_XMM7, + UWREG_XMM8, + UWREG_XMM9, + UWREG_XMM10, + UWREG_XMM11, + UWREG_XMM12, + UWREG_XMM13, + UWREG_XXM14, + UWREG_XMM15, +} UNWIND_REGS; + +typedef struct { + BYTE CodeOffset; + BYTE UnwindOp:4; + BYTE OpInfo:4; +} UNWIND_CODE; + +#define UNWIND_INFO(unwind_codes_count, exception_data_count) struct __attribute__((aligned(4))) { \ + BYTE Version:3; \ + BYTE Flags:5; \ + BYTE SizeOfProlog; \ + BYTE CountOfCodes; /* must match unwind_codes_count */ \ + BYTE FrameRegister:4; \ + BYTE FrameOffset:4; \ + UNWIND_CODE UnwindCode[unwind_codes_count]; \ + /* if unwind_codes_count is odd number then there is an automatic padding */ \ + union __attribute__((aligned(4))) { \ + ULONG ExceptionHandler; /* when Flags do not contain UNW_FLAG_CHAININFO */ \ + ULONG FunctionEntry; /* when Flags contains UNW_FLAG_CHAININFO */ \ + }; \ + ULONG ExceptionData[exception_data_count]; \ +} + +/* Define unwind code for standard prolog which uses frame pointers via rbp. + * This makes the RtlUnwind() function to work and allows to traverse stack. + * + * As the one unwind code is defined for the whole image, it means that it + * does not represent one function and so there is no real function prolog. + * Therefore SizeOfProlog is 0 and all CodeOffset are also zeros. + * + * Functions which do not create its own frame pointer on stack (for example + * when compiling with -fomit-frame-pointer) are hidden during unwinding. + * Startup code for mingw-w64 manually ensures that frame pointers via rbp + * are properly maintained. Rest is up to the application. If application + * is compiled with -fomit-frame-pointer then it is expected that rbp value + * is not damaged or used for some intermediate operations. This can be + * achieved by additional application compile flag -ffixed-rbp. + */ +#define UNWIND_CODE_TABLE { \ + { .UnwindOp = UWOP_SET_FPREG, }, /* movq %rbp, %rsp */ \ + { .UnwindOp = UWOP_PUSH_NONVOL, .OpInfo = UWREG_RBP }, /* popq %rbp */ \ +} +#define UNWIND_CODE_TABLE_COUNT (sizeof((UNWIND_CODE[])UNWIND_CODE_TABLE)/sizeof(UNWIND_CODE)) + +#else + +#error unsupported platform + +#endif + + + +#if defined(__x86_64__) +static const UNWIND_INFO(UNWIND_CODE_TABLE_COUNT, 0) all_functions_unwind_xdata = { + .Version = 1, + .CountOfCodes = UNWIND_CODE_TABLE_COUNT, + .FrameRegister = UWREG_RBP, + .UnwindCode = UNWIND_CODE_TABLE, +}; +#else +#error unsupported platform +#endif + +static RUNTIME_FUNCTION all_functions_pdata = { + .BeginAddress = 0, +#if defined(__x86_64__) + .EndAddress = -1, /* filled at runtime */ +#endif + .UnwindData = -1, /* filled at runtime */ +}; + +/* Registration of unwind info for the whole image must be done _after_ + * registering unwind info for separate functions or registering SEH handlers. + * It is because this registration covers whole image and covers also ranges of + * other functions. RtlUnwind() searches for unwind info first in executable + * image and then in runtime tables in order in which they were registered. + */ +static inline __attribute__((always_inline)) int register_runtime_image_unwind_info(void) +{ + /* All addresses in UNWIND_INFO and RUNTIME_FUNCTION are relative the image base. */ + extern IMAGE_DOS_HEADER __ImageBase; + const DWORD image_size = ((IMAGE_NT_HEADERS*)((BYTE*)&__ImageBase + __ImageBase.e_lfanew))->OptionalHeader.SizeOfImage; +#if defined(__x86_64__) + all_functions_pdata.EndAddress = image_size; +#endif + all_functions_pdata.UnwindData = (uintptr_t)&all_functions_unwind_xdata - (uintptr_t)&__ImageBase; + return RtlAddFunctionTable(&all_functions_pdata, 1, (uintptr_t)&__ImageBase); +} + +/* It is required to unregister unwind info when unloading the image. + * This is mostly for cases when DLL library is being unloaded. + */ +static inline __attribute__((always_inline)) void unregister_runtime_image_unwind_info(void) +{ + RtlDeleteFunctionTable(&all_functions_pdata); +} + + + +#if defined(__x86_64__) +static UNWIND_INFO(UNWIND_CODE_TABLE_COUNT, 0) function_unwind_xdata = { + .Version = 1, + .Flags = UNW_FLAG_EHANDLER, + .CountOfCodes = UNWIND_CODE_TABLE_COUNT, + .FrameRegister = UWREG_RBP, + .UnwindCode = UNWIND_CODE_TABLE, + .ExceptionHandler = -1, /* filled at runtime */ +}; +#else +#error unsupported platform +#endif + +static RUNTIME_FUNCTION function_pdata = { + .BeginAddress = -1, /* filled at runtime */ +#if defined(__x86_64__) + .EndAddress = -1, /* filled at runtime */ +#endif + .UnwindData = -1, /* filled at runtime */ +}; + +/* Function for which is being registered SEH exception handler needs to use + * standard prolog and also direct child functions need to use standard prolog. + * Registration of SEH handler for particular function needs to be done before + * calling register_runtime_unwind_info(). Otherwise it would have no effect. + * Also please note that without the followup register_runtime_unwind_info() + * call, the SEH exception would not be propagated to SEH handler because + * RtlUnwind() would not be able to unwind stack and find this SEH handler. + */ +static inline __attribute__((always_inline)) int register_runtime_function_exception_handler(uintptr_t function_begin, uintptr_t function_end, PEXCEPTION_ROUTINE exception_handler) +{ + /* All addresses in UNWIND_INFO and RUNTIME_FUNCTION are relative the image base. */ + extern IMAGE_DOS_HEADER __ImageBase; + function_unwind_xdata.ExceptionHandler = (uintptr_t)exception_handler - (uintptr_t)&__ImageBase; + function_pdata.BeginAddress = function_begin - (uintptr_t)&__ImageBase; +#if defined(__x86_64__) + function_pdata.EndAddress = function_end - (uintptr_t)&__ImageBase; +#endif + function_pdata.UnwindData = (uintptr_t)&function_unwind_xdata - (uintptr_t)&__ImageBase; + return RtlAddFunctionTable(&function_pdata, 1, (uintptr_t)&__ImageBase); +} + +static inline __attribute__((always_inline)) void unregister_runtime_function_exception_handler(void) +{ + RtlDeleteFunctionTable(&function_pdata); +} -- 2.20.1 >From 85093568e03116c290ede6e56eab45e07e301404 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <[email protected]> Date: Wed, 17 Jun 2026 23:39:05 +0200 Subject: [PATCH 2/3] crt: test: Adjust t_sigfpe.c to work for non-SEH builds Every (callback) function compiled by non-SEH build which is called from CRT library needs to have a standard prolog with its own frame pointer and also standard epilog. This is needed to ensure that CRT library would see our function as not continuation of its function. Therefore prevent tail optimization and use __builtin_frame_address(0) which forces compiler to register prolog with frame pointer even when -fomit-frame-pointer is used. With previous and this change, the t_sigfpe.c test compiled by amd64 non-SEH gcc version is passing. --- mingw-w64-crt/testcases/t_sigfpe.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/mingw-w64-crt/testcases/t_sigfpe.c b/mingw-w64-crt/testcases/t_sigfpe.c index 0c30621052c1..bc9ab024568c 100644 --- a/mingw-w64-crt/testcases/t_sigfpe.c +++ b/mingw-w64-crt/testcases/t_sigfpe.c @@ -1162,8 +1162,15 @@ __attribute__((force_align_arg_pointer)) #endif static unsigned __stdcall test_from_beginthreadex(void *arg) { +#if !defined(__i386__) && !defined(__SEH__) + asm volatile ("" :: "r" (__builtin_frame_address(0))); /* force usage of the standard prolog with frame pointer */ +#endif (void)arg; - return test(); + int ret = test(); +#if !defined(__i386__) && !defined(__SEH__) + asm volatile (""); /* prevent tail optimization */ +#endif + return ret; } #if defined(__i386__) @@ -1180,6 +1187,9 @@ static void __cdecl test_from_beginthread(void *arg) * The thread handle is used by _beginthread()'s caller which will close it. * So the only safe option is to exit this tread via WinAPI ExitThread() function. */ +#if !defined(__i386__) && !defined(__SEH__) + asm volatile ("" :: "r" (__builtin_frame_address(0))); /* force usage of the standard prolog with frame pointer */ +#endif (void)arg; ExitThread(test()); } -- 2.20.1 >From 1802c7344e53c7ca790386abee79ddd48e6c6e70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <[email protected]> Date: Sat, 20 Jun 2026 16:41:23 +0200 Subject: [PATCH 3/3] WIP: UNTESTED: crt: crt_handler: Extend SEH handler registration via RtlAddFunctionTable() for arm32 and arm64 gcc toolchain for arm64 platform currently does not support generating SEH code and registering SEH exception handlers. Therefore for these toolchains is needed fallback code via RtlAddFunctionTable() like it is there for amd64. arm32 and arm64 platforms have slightly different UNWIND_DATA (.xdata) structure than the existing amd64. --- mingw-w64-crt/crt/crtexe.c | 10 ++-- mingw-w64-crt/crt/runtime_seh.h | 84 +++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 6 deletions(-) diff --git a/mingw-w64-crt/crt/crtexe.c b/mingw-w64-crt/crt/crtexe.c index c17c5b66cfad..c52ac02ac214 100644 --- a/mingw-w64-crt/crt/crtexe.c +++ b/mingw-w64-crt/crt/crtexe.c @@ -33,7 +33,7 @@ #endif #endif -#if defined(__x86_64__) && !defined(SEH_INLINE_ASM) +#if !defined(__i386__) && !defined(SEH_INLINE_ASM) #include "runtime_seh.h" #endif @@ -147,7 +147,7 @@ int mainCRTStartup (void) return __tmainCRTStartup (); } -#if defined(__x86_64__) && !defined(SEH_INLINE_ASM) +#if !defined(__i386__) && !defined(SEH_INLINE_ASM) static int __tmainCRTStartup_real(void); static const char __tmainCRTStartup_end; #endif @@ -157,7 +157,7 @@ static opts in main or in functions called from main. */ __attribute__((force_align_arg_pointer)) #endif -#if defined(__x86_64__) && !defined(SEH_INLINE_ASM) +#if !defined(__i386__) && !defined(SEH_INLINE_ASM) __attribute__((section(".text.__tmainCRTStartup$A"))) #endif __declspec(noinline) int @@ -173,7 +173,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 */ -#elif defined(__x86_64__) +#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 */ _amsg_exit (22); /* _RT_NONCONT_TXT */ @@ -187,8 +187,6 @@ __attribute__((section(".text.__tmainCRTStartup$Z"))) static const char __tmainC static __declspec(noinline) int __tmainCRTStartup_real (void) { asm volatile ("" :: "r" (__builtin_frame_address (0))); /* force usage of the standard prolog with frame pointer */ -#else -#error unsupported platform #endif void *lock_free = NULL; diff --git a/mingw-w64-crt/crt/runtime_seh.h b/mingw-w64-crt/crt/runtime_seh.h index 29703978cbdd..f5c34f3b39ea 100644 --- a/mingw-w64-crt/crt/runtime_seh.h +++ b/mingw-w64-crt/crt/runtime_seh.h @@ -104,6 +104,68 @@ typedef struct { } #define UNWIND_CODE_TABLE_COUNT (sizeof((UNWIND_CODE[])UNWIND_CODE_TABLE)/sizeof(UNWIND_CODE)) +#elif defined(__arm__) || defined(__aarch64__) + +/* https://learn.microsoft.com/en-us/cpp/build/arm-exception-handling#xdata-records */ +/* https://learn.microsoft.com/en-us/cpp/build/arm64-exception-handling#xdata-records */ +/* IMAGE_ARM64_RUNTIME_FUNCTION_ENTRY_XDATA */ + +#ifdef __arm__ +/* TODO arm32 UNWIND_CODE_OPS enum */ +#else /* __aarch64__ */ +/* This enum is not complete, it contains only opcodes used in the code below. */ +typedef enum { + UWOP_SAVE_FPLR_X = 0x80, + UWOP_SET_FP = 0xE1, + UWOP_END = 0xE4, +} UNWIND_CODE_OPS; +#define UWOP_SAVE_FPLR_X(size) (UWOP_SAVE_FPLR_X + (size)/8-1) +#endif + +#ifdef __arm__ +#define DECLARE_FunctionFragment DWORD FunctionFragment:1 +#define CODE_WORDS_BITS 4 +#else /* __aarch64__ */ +#define DECLARE_FunctionFragment /* FunctionFragment is not present */ +#define CODE_WORDS_BITS 5 +#endif + +#define UNWIND_INFO(epilog_count, unwind_codes_size, exception_data_count) struct __attribute__((aligned(4))) { \ + DWORD FunctionLength:18; \ + DWORD Version:2; \ + DWORD ExceptionDataPresent:1; \ + DWORD EpilogInHeader:1; \ + DECLARE_FunctionFragment; \ + DWORD EpilogCount:5; \ + DWORD CodeWords:CODE_WORDS_BITS; \ + struct { \ + USHORT EpilogCount; \ + BYTE CodeWords; \ + BYTE Reserved; \ + } Extended[!!(((epilog_count) == 0 || (epilog_count) >= 32) && ((unwind_codes_size) == 0 || ((unwind_codes_size)+3)/4 >= 12*CODE_WORDS_BITS))]; \ + DWORD Epilog[epilog_count]; \ + BYTE UnwindCode[unwind_codes_size]; \ + /* if unwind_codes_size is not divisible by 4 then there is an automatic padding */ \ + ULONG ExceptionHandler __attribute__((aligned(4))); \ + ULONG ExceptionData[exception_data_count]; \ +} + +#ifdef __arm__ +#define UNWIND_CODE_TABLE { \ + 0xCB, /* mov sp, r11 */ \ + 0xA8, 0x00, /* pop.w {r11, lr} */ \ + 0xFF, /* bx lr */ \ +} +#else /* __aarch64__ */ +#define UNWIND_CODE_TABLE { \ + UWOP_SET_FP, /* mov sp, x29 */ \ + UWOP_SAVE_FPLR_X(16), /* ldp x29, lr, [sp], #16 */ \ + UWOP_END, /* ret */ \ +} +#endif + +#define UNWIND_CODE_TABLE_SIZE sizeof((BYTE[])UNWIND_CODE_TABLE) + #else #error unsupported platform @@ -119,6 +181,13 @@ static const UNWIND_INFO(UNWIND_CODE_TABLE_COUNT, 0) all_functions_unwind_xdata .FrameRegister = UWREG_RBP, .UnwindCode = UNWIND_CODE_TABLE, }; +#elif defined(__arm__) || defined(__aarch64__) +static UNWIND_INFO(0, UNWIND_CODE_TABLE_SIZE, 0) all_functions_unwind_xdata = { + .FunctionLength = -1, /* filled at runtime */ + .Version = 0, + .CodeWords = (UNWIND_CODE_TABLE_SIZE+3)/4, + .UnwindCode = UNWIND_CODE_TABLE, +}; #else #error unsupported platform #endif @@ -142,6 +211,9 @@ static inline __attribute__((always_inline)) int register_runtime_image_unwind_i /* All addresses in UNWIND_INFO and RUNTIME_FUNCTION are relative the image base. */ extern IMAGE_DOS_HEADER __ImageBase; const DWORD image_size = ((IMAGE_NT_HEADERS*)((BYTE*)&__ImageBase + __ImageBase.e_lfanew))->OptionalHeader.SizeOfImage; +#if defined(__arm__) || defined(__aarch64__) + all_functions_unwind_xdata.FunctionLength = image_size / (sizeof(uintptr_t)/2); +#endif #if defined(__x86_64__) all_functions_pdata.EndAddress = image_size; #endif @@ -168,6 +240,15 @@ static UNWIND_INFO(UNWIND_CODE_TABLE_COUNT, 0) function_unwind_xdata = { .UnwindCode = UNWIND_CODE_TABLE, .ExceptionHandler = -1, /* filled at runtime */ }; +#elif defined(__arm__) || defined(__aarch64__) +static UNWIND_INFO(0, UNWIND_CODE_TABLE_SIZE, 0) function_unwind_xdata = { + .FunctionLength = -1, /* filled at runtime */ + .Version = 0, + .ExceptionDataPresent = 1, + .CodeWords = (UNWIND_CODE_TABLE_SIZE+3)/4, + .UnwindCode = UNWIND_CODE_TABLE, + .ExceptionHandler = -1, /* filled at runtime */ +}; #else #error unsupported platform #endif @@ -192,6 +273,9 @@ static inline __attribute__((always_inline)) int register_runtime_function_excep { /* All addresses in UNWIND_INFO and RUNTIME_FUNCTION are relative the image base. */ extern IMAGE_DOS_HEADER __ImageBase; +#if defined(__arm__) || defined(__aarch64__) + function_unwind_xdata.FunctionLength = (function_end - function_begin) / (sizeof(uintptr_t)/2); +#endif function_unwind_xdata.ExceptionHandler = (uintptr_t)exception_handler - (uintptr_t)&__ImageBase; function_pdata.BeginAddress = function_begin - (uintptr_t)&__ImageBase; #if defined(__x86_64__) -- 2.20.1
_______________________________________________ Mingw-w64-public mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/mingw-w64-public
