On 22.04.2025 14:27, Martin Storsjö wrote:
On Fri, 11 Apr 2025, Jacek Caban wrote:

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)?


I guess it’s a matter of taste. The full function type can be useful in some cases, like when we call the function via such pointer, but when we don’t need that capability, it just adds complexity without much benefit. Similarly, __MINGW_IMP_SYMBOL is useful for adding an underscore on i386, but in code that's never built for i386, it only clutters things without a real upside.

That said, consistency is a valid counterargument, so I’ll change it.

As a side note: technically, for ARM64EC we should also expose additional __imp_aux_* symbols, which are referenced when taking the address of an imported function. I haven’t looked into that much yet, it feels like a secondary concern for now. For reference, see [1] for how I handled it in Wine.


+/* 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?)


I checked, and the construct seems to work fine with LTO. That said, LTO isn’t really supported on ARM64EC yet. I’ve added some basic support in LLD, but it still doesn’t handle symbol mangling and aliasing correctly.



+{
+    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.


Note that __intrinsic_setjmpex stores x30 (the link register) as Rip, so the context in the buffer already represents the caller’s stack frame state. If we’re called from x64 code, there’s an additional entry thunk between the x64 code and __intrinsic_setjmpex. My understanding is that this unwinding is intended to skip over the entry thunk’s frame, so that the context points to the x64 caller, matching what we’d see on a real x86 system. I will extend the comment.


Thanks,

Jacek


[1] https://gitlab.winehq.org/wine/wine/-/merge_requests/6487



_______________________________________________
Mingw-w64-public mailing list
Mingw-w64-public@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public

Reply via email to