Based on Wine code by Alexandre Julliard. --- v2: - extended a comment about unwinding entry thunk in setjmp - __imp_ symbol more consistent with the codebase - added a local RtlUnwind declaration with __MINGW_ATTRIB_NORETURN to avoid -Winvalid-noreturn warning
mingw-w64-crt/Makefile.am | 8 +- mingw-w64-crt/misc/arm64ec/longjmp.c | 32 ++++++++ mingw-w64-crt/misc/arm64ec/setjmp.c | 106 +++++++++++++++++++++++++++ mingw-w64-crt/misc/longjmp.S | 2 + mingw-w64-crt/misc/setjmp.S | 2 + 5 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 mingw-w64-crt/misc/arm64ec/longjmp.c create mode 100644 mingw-w64-crt/misc/arm64ec/setjmp.c diff --git a/mingw-w64-crt/Makefile.am b/mingw-w64-crt/Makefile.am index d16ebdcf2..04b61c429 100644 --- a/mingw-w64-crt/Makefile.am +++ b/mingw-w64-crt/Makefile.am @@ -461,6 +461,12 @@ src_ucrtapp=\ string/wcsrchr.c \ string/wcsstr.c +if ARM64EC +src_ucrtapp_arm64=\ + misc/arm64ec/longjmp.c \ + misc/arm64ec/setjmp.c +endif + # Files included in libucrt*.a on x86_32 src_ucrtbase32=\ $(src_ucrtbase) \ @@ -2563,7 +2569,7 @@ libarm64_libmsvcrt_extra_a_CPPFLAGS=$(CPPFLAGSARM64) -D__LIBMSVCRT__ -D__LIBMSVC libarm64_libmsvcrt_extra_a_LIBADD=$(src_msvcrtarm64_x64) libarm64_libucrt_extra_a_SOURCES = $(src_ucrtbasearm64) libarm64_libucrt_extra_a_CPPFLAGS=$(CPPFLAGSARM64) -D__LIBMSVCRT__ $(extra_include) $(sysincludes) -libarm64_libucrtapp_extra_a_SOURCES = $(src_ucrtapp) +libarm64_libucrtapp_extra_a_SOURCES = $(src_ucrtapp) $(src_ucrtapp_arm64) libarm64_libucrtapp_extra_a_CPPFLAGS=$(CPPFLAGSARM64) -D__LIBMSVCRT__ $(extra_include) $(sysincludes) libarm64_DATA += libarm64/libvcruntime140.a diff --git a/mingw-w64-crt/misc/arm64ec/longjmp.c b/mingw-w64-crt/misc/arm64ec/longjmp.c new file mode 100644 index 000000000..937394c93 --- /dev/null +++ b/mingw-w64-crt/misc/arm64ec/longjmp.c @@ -0,0 +1,32 @@ +/** + * 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. + */ + +#undef __MSVCRT_VERSION__ +#define _UCRT + +#include <setjmp.h> +#include <windef.h> +#include <winbase.h> + +NTSYSAPI __MINGW_ATTRIB_NORETURN void NTAPI RtlUnwind(PVOID, PVOID, PEXCEPTION_RECORD, PVOID); + +void __cdecl longjmp( jmp_buf b, int retval ) +{ + _JUMP_BUFFER *buf = (_JUMP_BUFFER *)b; + EXCEPTION_RECORD rec; + + if (!retval) retval = 1; + + rec.ExceptionCode = STATUS_LONGJUMP; + rec.ExceptionFlags = 0; + rec.ExceptionRecord = NULL; + rec.ExceptionAddress = NULL; + rec.NumberParameters = 1; + rec.ExceptionInformation[0] = (DWORD_PTR)buf; + RtlUnwind( (void *)buf->Frame, (void *)buf->Rip, &rec, IntToPtr(retval) ); +} + +void (__cdecl *__MINGW_IMP_SYMBOL(longjmp))( jmp_buf b, int retval ) = longjmp; diff --git a/mingw-w64-crt/misc/arm64ec/setjmp.c b/mingw-w64-crt/misc/arm64ec/setjmp.c new file mode 100644 index 000000000..00dc33fbf --- /dev/null +++ b/mingw-w64-crt/misc/arm64ec/setjmp.c @@ -0,0 +1,106 @@ +/** + * 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. + */ + +#undef __MSVCRT_VERSION__ +#define _UCRT + +#include <setjmp.h> +#include <windef.h> +#include <winbase.h> + +static inline UINT fpcsr_to_mxcsr( UINT fpcr, UINT fpsr ) +{ + UINT ret = 0; + + if (fpsr & 0x0001) ret |= 0x0001; /* invalid operation */ + if (fpsr & 0x0002) ret |= 0x0004; /* zero-divide */ + if (fpsr & 0x0004) ret |= 0x0008; /* overflow */ + if (fpsr & 0x0008) ret |= 0x0010; /* underflow */ + if (fpsr & 0x0010) ret |= 0x0020; /* precision */ + if (fpsr & 0x0080) ret |= 0x0002; /* denormal */ + + if (fpcr & 0x0080000) ret |= 0x0040; /* denormals are zero */ + if (!(fpcr & 0x0000100)) ret |= 0x0080; /* invalid operation mask */ + if (!(fpcr & 0x0000200)) ret |= 0x0200; /* zero-divide mask */ + if (!(fpcr & 0x0000400)) ret |= 0x0400; /* overflow mask */ + if (!(fpcr & 0x0000800)) ret |= 0x0800; /* underflow mask */ + if (!(fpcr & 0x0001000)) ret |= 0x1000; /* precision mask */ + if (!(fpcr & 0x0008000)) ret |= 0x0100; /* denormal mask */ + if (fpcr & 0x0400000) ret |= 0x4000; /* round up */ + if (fpcr & 0x0800000) ret |= 0x2000; /* round down */ + if (fpcr & 0x1000000) ret |= 0x8000; /* flush to zero */ + return ret; +} + +/* unwind context by one call frame */ +static void unwind_one_frame( CONTEXT *context ) +{ + void *data; + ULONG_PTR base, frame, pc = context->Rip - 4; + RUNTIME_FUNCTION *func = RtlLookupFunctionEntry( pc, &base, NULL ); + + RtlVirtualUnwind( UNW_FLAG_NHANDLER, base, pc, func, context, &data, &frame, NULL ); +} + +/* fixup jump buffer information; helper for _setjmpex */ +static int __attribute__((used)) do_setjmpex( _JUMP_BUFFER *buf, UINT fpcr, UINT fpsr ) +{ + CONTEXT context = { .ContextFlags = CONTEXT_FULL }; + + buf->MxCsr = fpcsr_to_mxcsr( fpcr, fpsr ); + buf->FpCsr = 0x27f; + + /* If the caller is x64, the buffer contains an entry thunk capture. + * Attempt to unwind it to retrieve the actual x64 context, if applicable. */ + context.Rbx = buf->Rbx; + context.Rsp = buf->Rsp; + context.Rbp = buf->Rbp; + context.Rsi = buf->Rsi; + context.Rdi = buf->Rdi; + context.R12 = buf->R12; + context.R13 = buf->R13; + context.R14 = buf->R14; + context.R15 = buf->R15; + context.Rip = buf->Rip; + memcpy( &context.Xmm6, &buf->Xmm6, 10 * sizeof(context.Xmm6) ); + unwind_one_frame( &context ); + if (!RtlIsEcCode( context.Rip )) /* caller is x64, use its context instead of the ARM one */ + { + buf->Rbx = context.Rbx; + buf->Rsp = context.Rsp; + buf->Rbp = context.Rbp; + buf->Rsi = context.Rsi; + buf->Rdi = context.Rdi; + buf->R12 = context.R12; + buf->R13 = context.R13; + buf->R14 = context.R14; + buf->R15 = context.R15; + buf->Rip = context.Rip; + memcpy( &buf->Xmm6, &context.Xmm6, 10 * sizeof(context.Xmm6) ); + } + return 0; +} + +int __attribute__((naked)) __intrinsic_setjmpex( jmp_buf buf, void *frame ) +{ + asm( ".seh_proc \"#__intrinsic_setjmpex\"\n\t" + ".seh_endprologue\n\t" + "stp x1, x27, [x0]\n\t" /* jmp_buf->Frame,Rbx */ + "mov x1, sp\n\t" + "stp x1, x29, [x0, #0x10]\n\t" /* jmp_buf->Rsp,Rbp */ + "stp x25, x26, [x0, #0x20]\n\t" /* jmp_buf->Rsi,Rdi */ + "stp x19, x20, [x0, #0x30]\n\t" /* jmp_buf->R12,R13 */ + "stp x21, x22, [x0, #0x40]\n\t" /* jmp_buf->R14,R15 */ + "str x30, [x0, #0x50]\n\t" /* jmp_buf->Rip */ + "stp d8, d9, [x0, #0x80]\n\t" /* jmp_buf->Xmm8,Xmm9 */ + "stp d10, d11, [x0, #0xa0]\n\t" /* jmp_buf->Xmm10,Xmm11 */ + "stp d12, d13, [x0, #0xc0]\n\t" /* jmp_buf->Xmm12,Xmm13 */ + "stp d14, d15, [x0, #0xe0]\n\t" /* jmp_buf->Xmm14,Xmm15 */ + "mrs x1, fpcr\n\t" + "mrs x2, fpsr\n\t" + "b \"#do_setjmpex\"\n\t" + ".seh_endproc" ); +} diff --git a/mingw-w64-crt/misc/longjmp.S b/mingw-w64-crt/misc/longjmp.S index 7026ed575..b5f81cffc 100644 --- a/mingw-w64-crt/misc/longjmp.S +++ b/mingw-w64-crt/misc/longjmp.S @@ -6,6 +6,7 @@ #include <_mingw_mac.h> +#ifndef __arm64ec__ .globl __MINGW_USYMBOL(longjmp) .def __MINGW_USYMBOL(longjmp); .scl 2; .type 32; .endef @@ -98,3 +99,4 @@ __MINGW_IMP_LSYMBOL(longjmp): #else .long __MINGW_USYMBOL(longjmp) #endif +#endif /* __arm64ec__ */ diff --git a/mingw-w64-crt/misc/setjmp.S b/mingw-w64-crt/misc/setjmp.S index 0c06b8632..2baaae49c 100644 --- a/mingw-w64-crt/misc/setjmp.S +++ b/mingw-w64-crt/misc/setjmp.S @@ -6,6 +6,7 @@ #include <_mingw_mac.h> +#ifndef __arm64ec__ .globl __MINGW_USYMBOL(__intrinsic_setjmp) .def __MINGW_USYMBOL(__intrinsic_setjmp); .scl 2; .type 32; .endef @@ -115,3 +116,4 @@ __MINGW_USYMBOL(__intrinsic_setjmpex): mov x0, #0 ret #endif +#endif /* __arm64ec__ */ -- 2.49.0 _______________________________________________ Mingw-w64-public mailing list Mingw-w64-public@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mingw-w64-public