diff --git a/dlls/ntdll/signal_arm64ec.c b/dlls/ntdll/signal_arm64ec.c
index c307714e56e..6f73919c886 100644
--- a/dlls/ntdll/signal_arm64ec.c
+++ b/dlls/ntdll/signal_arm64ec.c
@@ -1755,12 +1755,19 @@ BOOLEAN WINAPI RtlIsEcCode( ULONG_PTR ptr )
 }
 
 
+/* 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 );
+}
+
 /* capture context information; helper for RtlCaptureContext */
 static void __attribute__((used)) capture_context( CONTEXT *context, UINT cpsr, UINT fpcr, UINT fpsr )
 {
-    RUNTIME_FUNCTION *func;
-    void *handler_data;
-    ULONG_PTR pc, base, frame;
     CONTEXT unwind_context;
 
     context->ContextFlags = CONTEXT_AMD64_FULL;
@@ -1772,9 +1779,7 @@ static void __attribute__((used)) capture_context( CONTEXT *context, UINT cpsr,
 
     /* unwind one level to get register values from caller function */
     unwind_context = *context;
-    pc = context->Rip - 4;
-    func = RtlLookupFunctionEntry( pc, &base, NULL );
-    RtlVirtualUnwind( UNW_FLAG_NHANDLER, base, pc, func, &unwind_context, &handler_data, &frame, NULL );
+    unwind_one_frame( &unwind_context );
     memcpy( &context->Rax, &unwind_context.Rax, offsetof(CONTEXT,FltSave) - offsetof(CONTEXT,Rax) );
 }
 
@@ -1826,6 +1831,67 @@ void __attribute__((naked)) RtlCaptureContext( CONTEXT *context )
          ".seh_endproc" );
 }
 
+/* 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;
+
+    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;
+}
+
+/***********************************************************************
+ *		_setjmpex (NTDLL.@)
+ */
+int __attribute__((naked)) NTDLL__setjmpex( _JUMP_BUFFER *buf, void *frame )
+{
+    asm( ".seh_proc NTDLL__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" );
+}
+
 
 /*******************************************************************
  *              RtlRestoreContext (NTDLL.@)