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 */
+ {