When the msvc setjmpex.h file is included in source file then msvc changes the behavior of C setjmp() and longjmp() calls to be SEH safe. Without including the setjmpex.h file, these C calls are not SEH safe by default.
In following table is behavior of the msvc compiler, which symbols are called in the emitted binary object code (not linked): without setjmpex.h with setjmpex.h i386 _setjmp3 + longjmp _setjmp3 + _longjmpex amd64 _setjmp + longjmp _setjmpex + longjmp arm32 _setjmp + longjmp _setjmpex + longjmp arm64 _setjmpex + longjmp _setjmpex + longjmp This table was produced from results on https://godbolt.org/z/Gabv1qT9c When the compiled code is linked into final binary with UCRT library, the _setjmp symbol is resolved to UCRT _intrinsic_setjmp symbol and the _setjmpex symbol is resolved to UCRT _intrinsic_setjmpex. i386 _setjmp3 stays as without the _intrinsic prefix and the i386 _setjmp is not emitted at all. Fix the mingw-w64 setjmpex.h and setjmp.h include files to define setjmp() and longjmp() macros which expands to functions emitted by msvc compiler to match the msvc behavior. Note that msvc setjmpex.h and setjmp.h header files are different than mingw-w64 and is because it looks like that msvc compiler parses the source code with setjmp and longjmp keywords differently and is doing some transformations not specified in header files. Something which gcc is not doing. mingw-w64 setjmpex.h and setjmp.h files are defined based on the observation of output from msvc compiler, not from the msvc header files. --- mingw-w64-headers/crt/setjmp.h | 104 ++++++++++++++++++------------- mingw-w64-headers/crt/setjmpex.h | 16 +---- 2 files changed, 63 insertions(+), 57 deletions(-) diff --git a/mingw-w64-headers/crt/setjmp.h b/mingw-w64-headers/crt/setjmp.h index 54e3ad03b67f..0d85d0e9f9f8 100644 --- a/mingw-w64-headers/crt/setjmp.h +++ b/mingw-w64-headers/crt/setjmp.h @@ -26,7 +26,7 @@ extern "C" { #endif -#if (defined(_X86_) && !defined(__x86_64)) +#if defined(__i386__) #define _JBLEN 16 #define _JBTYPE int @@ -40,6 +40,7 @@ extern "C" { unsigned long Eip; unsigned long Registration; unsigned long TryLevel; + /* Following fields are only for new _setjmp3(), the are not for old _setjmp(). */ unsigned long Cookie; unsigned long UnwindFunc; unsigned long UnwindData[6]; @@ -107,7 +108,7 @@ extern "C" { } _JUMP_BUFFER; -#elif defined(__x86_64) +#elif defined(__x86_64__) typedef _CRT_ALIGN(16) struct _SETJMP_FLOAT128 { __MINGW_EXTENSION unsigned __int64 Part[2]; @@ -202,64 +203,83 @@ extern "C" { #define _JMP_BUF_DEFINED #endif -_CRTIMP __MINGW_ATTRIB_NORETURN __attribute__ ((__nothrow__)) void __cdecl longjmp(jmp_buf _Buf,int _Value); +_CRTIMP __MINGW_ATTRIB_NORETURN __attribute__ ((__nothrow__)) void __cdecl longjmp(jmp_buf _Buf, int _Value); /* for setjmp.h and non-i386 setjmpex.h */ +#ifdef __i386__ +_CRTIMP __MINGW_ATTRIB_NORETURN __attribute__ ((__nothrow__)) void __cdecl _longjmpex(jmp_buf _Buf, int _Value); /* for i386 setjmpex.h */ +#endif + +#ifdef __i386__ +_CRTIMP int __cdecl __attribute__ ((__nothrow__,__returns_twice__)) _setjmp(jmp_buf _Buf); /* old i386 crtdll setjmp.h */ +_CRTIMP int __cdecl __attribute__ ((__nothrow__,__returns_twice__)) _setjmp3(jmp_buf _Buf, int _Count, ...); /* new i386 msvcrt20+ setjmp.h and setjmpex.h */ +#else +#ifndef __aarch64__ +_CRTIMP int __cdecl __attribute__ ((__nothrow__,__returns_twice__)) _setjmp(jmp_buf _Buf, void *_Frame); /* for non-i386 and non-aarch64 setjmp.h */ +#endif +_CRTIMP int __cdecl __attribute__ ((__nothrow__,__returns_twice__)) _setjmpex(jmp_buf _Buf, void *_Frame); /* for non-i386 setjmpex.h and aarch64 setjmp.h */ +#endif + +#if defined(__arm__) || defined(__aarch64__) +int __cdecl __attribute__ ((__nothrow__,__returns_twice__)) __mingw_setjmp(jmp_buf _Buf); +__MINGW_ATTRIB_NORETURN __attribute__ ((__nothrow__)) void __mingw_longjmp(jmp_buf _Buf, int _Value); +#endif void * __cdecl __attribute__ ((__nothrow__)) mingw_getsp (void); +#ifdef __cplusplus +} +#endif + +#pragma pack(pop) +#endif /* _INC_SETJMP */ + +/* + * Now outside of the _INC_SETJMP block, defines setjmp() and longjmp(). + * It allows '#include <setjmpex.h>' to override the existing setjmp() and longjmp() definitions. + */ + #pragma push_macro("__has_builtin") #ifndef __has_builtin #define __has_builtin(x) 0 #endif -#ifdef __aarch64__ - /* ARM64 lacks _setjmp, only has _setjmpex. */ -# define _setjmp _setjmpex +#ifdef setjmp +# undef setjmp #endif -#ifndef _INC_SETJMPEX -# if defined(_X86_) || defined(__i386__) -# define setjmp(BUF) _setjmp3((BUF), 0) -# elif !defined(__SEH__) || defined(__USE_MINGW_SETJMP_NON_SEH) -# if defined(__arm__) || defined(__aarch64__) -# define setjmp(BUF) __mingw_setjmp((BUF)) -# define longjmp __mingw_longjmp - int __cdecl __attribute__ ((__nothrow__,__returns_twice__)) __mingw_setjmp(jmp_buf _Buf); - __MINGW_ATTRIB_NORETURN __attribute__ ((__nothrow__)) void __mingw_longjmp(jmp_buf _Buf,int _Value); -# else -# define setjmp(BUF) _setjmp((BUF), NULL) -# endif -# elif __has_builtin(__builtin_sponentry) +#if defined(__i386__) +# define setjmp(BUF) _setjmp3((BUF), 0) +#elif !defined(_INC_SETJMPEX) && (!defined(__SEH__) || defined(__USE_MINGW_SETJMP_NON_SEH)) +# if defined(__arm__) || defined(__aarch64__) +# define setjmp(BUF) __mingw_setjmp((BUF)) +# else +# define setjmp(BUF) _setjmp((BUF), NULL) +# endif +#elif !defined(_INC_SETJMPEX) && !defined(__aarch64__) +# if __has_builtin(__builtin_sponentry) # define setjmp(BUF) _setjmp((BUF), __builtin_sponentry()) # elif (__MINGW_GCC_VERSION < 40702) && !defined(__clang__) # define setjmp(BUF) _setjmp((BUF), mingw_getsp()) # else -# define setjmp(BUF) _setjmp((BUF), __builtin_frame_address (0)) -# endif - int __cdecl __attribute__ ((__nothrow__,__returns_twice__)) _setjmp(jmp_buf _Buf, void *_Ctx); -# if defined(_X86_) || defined(__i386__) - int __cdecl __attribute__ ((__nothrow__,__returns_twice__)) _setjmp3(jmp_buf _Buf, int _Count, ...); +# define setjmp(BUF) _setjmp((BUF), __builtin_frame_address(0)) # endif #else -# undef setjmp -# ifdef __SEH__ -# if (__MINGW_GCC_VERSION < 40702) && !defined(__clang__) -# define setjmp(BUF) _setjmpex((BUF), mingw_getsp()) -# define setjmpex(BUF) _setjmpex((BUF), mingw_getsp()) -# else -# define setjmp(BUF) _setjmpex((BUF), __builtin_frame_address (0)) -# define setjmpex(BUF) _setjmpex((BUF), __builtin_frame_address (0)) -# endif +# if __has_builtin(__builtin_sponentry) +# define setjmp(BUF) _setjmpex((BUF), __builtin_sponentry()) +# elif (__MINGW_GCC_VERSION < 40702) && !defined(__clang__) +# define setjmp(BUF) _setjmpex((BUF), mingw_getsp()) # else -# define setjmp(BUF) _setjmpex((BUF), NULL) -# define setjmpex(BUF) _setjmpex((BUF), NULL) +# define setjmp(BUF) _setjmpex((BUF), __builtin_frame_address(0)) # endif - int __cdecl __attribute__ ((__nothrow__,__returns_twice__)) _setjmpex(jmp_buf _Buf,void *_Ctx); #endif -#pragma pop_macro("__has_builtin") - -#ifdef __cplusplus -} +#ifdef longjmp +# undef longjmp #endif - -#pragma pack(pop) +#if defined(_INC_SETJMPEX) && defined(__i386__) +# define longjmp _longjmpex +#elif !defined(_INC_SETJMPEX) && (!defined(__SEH__) || defined(__USE_MINGW_SETJMP_NON_SEH)) && (defined(__arm__) || defined(__aarch64__)) +# define longjmp __mingw_longjmp +#else +# define longjmp longjmp #endif + +#pragma pop_macro("__has_builtin") diff --git a/mingw-w64-headers/crt/setjmpex.h b/mingw-w64-headers/crt/setjmpex.h index c5540b970f05..a1017c3e9e4c 100644 --- a/mingw-w64-headers/crt/setjmpex.h +++ b/mingw-w64-headers/crt/setjmpex.h @@ -4,21 +4,7 @@ * No warranty is given; refer to the file DISCLAIMER.PD within this package. */ #ifndef _INC_SETJMPEX +/* setjmp.h defines setjmp() and longjmp() based on _INC_SETJMPEX */ #define _INC_SETJMPEX - -#ifndef _WIN32 -#error Only Win32 target is supported! -#endif - -#if (defined(_X86_) && !defined(__x86_64)) -#define setjmp _setjmp -#define longjmp _longjmpex -#else -#ifdef setjmp -#undef setjmp -#endif -#define setjmp _setjmpex -#endif - #include <setjmp.h> #endif -- 2.20.1 _______________________________________________ Mingw-w64-public mailing list Mingw-w64-public@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mingw-w64-public