On Fri, 11 Apr 2025, Jacek Caban wrote:
Based on Wine code by Alexandre Julliard.
---
mingw-w64-crt/Makefile.am | 8 ++-
mingw-w64-crt/misc/arm64ec/longjmp.c | 30 ++++++++
mingw-w64-crt/misc/arm64ec/setjmp.c | 104 +++++++++++++++++++++++++++
mingw-w64-crt/misc/longjmp.S | 2 +
mingw-w64-crt/misc/setjmp.S | 2 +
5 files changed, 145 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 ec06e5ed0..b4712cda8 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) \
@@ -2548,7 +2554,7 @@ libarm64_libmsvcrt_extra_a_SOURCES = $(src_msvcrtarm64)
libarm64_libmsvcrt_extra_a_CPPFLAGS=$(CPPFLAGSARM64) -D__LIBMSVCRT__
-D__LIBMSVCRT_OS__ $(extra_include) $(sysincludes)
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..ebf795f63
--- /dev/null
+++ b/mingw-w64-crt/misc/arm64ec/longjmp.c
@@ -0,0 +1,30 @@
+/**
+ * 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>
+
+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) );
+}
+
+const void *__imp_longjmp = longjmp;
Elsewhere, we use __MINGW_IMP_SYMBOL and a more specific type signature
for this declaration - I think that may be nice to do here as well, for
consistency (and possibly for reducing the risk of a compiler warning
about it - even if I guess this cast should be fine in general)?
diff --git a/mingw-w64-crt/misc/arm64ec/setjmp.c
b/mingw-w64-crt/misc/arm64ec/setjmp.c
new file mode 100644
index 000000000..1d13837f0
--- /dev/null
+++ b/mingw-w64-crt/misc/arm64ec/setjmp.c
@@ -0,0 +1,104 @@
+/**
+ * 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 )
I'm a little unsure if "static __attribute__((used))" is enough for
referencing a local function from assembly, in all possible build
scenarios. In particular LTO may be tricky with this. Then again, if it
works for you now perhaps it's good enough, and we can change it if it
doesn't work. (I guess the alternative is to make it global and give it an
__mingw prefix?)
+{
+ CONTEXT context = { .ContextFlags = CONTEXT_FULL };
+
+ buf->MxCsr = fpcsr_to_mxcsr( fpcr, fpsr );
+ buf->FpCsr = 0x27f;
+
+ 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;
Hmm, this feels odd. If we're not called from x86_64 code, we'd keep the
values as they were within __intrinsic_setjmpex, but if we're called from
x86_64, we update the jmp_buf contents with that of one stack frame
further up.
Is that specifically what we need to do? Wouldn't it be more
consistent if we'd e.g. always store the output after this one unwind
step?
But I guess there's something more to it than I realize here?
In any case, this perhaps could use some more comments for clarity.
Other than that, I think this patch seems fine.
// Martin
_______________________________________________
Mingw-w64-public mailing list
Mingw-w64-public@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public