From: Billy Laws blaws05@gmail.com
These trap on linux but under Windows userspace will write 0 to the destination register. Fixes recent versions of VC redist that use this unconditionally. --- dlls/ntdll/tests/exception.c | 20 ++++++++++++++++++++ dlls/ntdll/unix/signal_arm64.c | 15 +++++++++++++++ 2 files changed, 35 insertions(+)
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index 4a89cf6a5dc..9b5ca2ca508 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -8296,6 +8296,25 @@ static void test_restore_context(void) ok(0, "unexpected pass %ld\n", pass); }
+static void test_mrs_currentel(void) +{ + DWORD64 (*func_ptr)(void) = code_mem; + DWORD64 result; + + static const DWORD call_func[] = + { + 0xd5384240, /* mrs x0, CurrentEL */ + 0xd538425f, /* mrs xzr, CurrentEL */ + 0xd65f03c0, /* ret */ + }; + + memcpy( func_ptr, call_func, sizeof(call_func) ); + FlushInstructionCache( GetCurrentProcess(), func_ptr, sizeof(call_func) ); + result = func_ptr(); + ok( result == 0, "expected 0, got %llx\n", result ); +} + + #endif /* __aarch64__ */
#if defined(__i386__) || defined(__x86_64__) @@ -12024,6 +12043,7 @@ START_TEST(exception) test_nested_exception(); test_collided_unwind(); test_restore_context(); + test_mrs_currentel();
#elif defined(__arm__)
diff --git a/dlls/ntdll/unix/signal_arm64.c b/dlls/ntdll/unix/signal_arm64.c index 8ec4251feca..57d9c375076 100644 --- a/dlls/ntdll/unix/signal_arm64.c +++ b/dlls/ntdll/unix/signal_arm64.c @@ -1097,6 +1097,21 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) static void ill_handler( int signal, siginfo_t *siginfo, void *sigcontext ) { EXCEPTION_RECORD rec = { EXCEPTION_ILLEGAL_INSTRUCTION }; + ucontext_t *context = sigcontext; + + if (!(PSTATE_sig( context ) & 0x10) && /* AArch64 (not WoW) */ + !(PC_sig( context ) & 3)) + { + ULONG instr = *(ULONG *)PC_sig( context ); + /* emulate mrs xN, CurrentEL */ + if ((instr & ~0x1f) == 0xd5384240) { + ULONG reg = instr & 0x1f; + /* ignore writes to xzr */ + if (reg != 31) REGn_sig(reg, context) = 0; + PC_sig(context) += 4; + return; + } + }
setup_exception( sigcontext, &rec ); }