From ea639387658c32c0e7df03795462f140f8921f06 Mon Sep 17 00:00:00 2001
From: Martin Storsjo <martin@martin.st>
Date: Wed, 16 Aug 2017 23:48:40 +0300
Subject: [PATCH] ntdll: Always restore TEB to x18 on aarch 64 on return
 from calls to builtins

This requires always enabling relaying of calls though.

This isn't enough for cases where builtin functions call back into
the user code though, but works well enough for all pratical cases
I've run so far.

This does give a bit of performance overhead, but it makes it
possible to run most real arm64 binaries (all I've tried).

Signed-off-by: Martin Storsjo <martin@martin.st>
---
 dlls/ntdll/loader.c | 8 +++++++-
 dlls/ntdll/relay.c  | 4 ++++
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c
index 994ff6f215..1f40021b7a 100644
--- a/dlls/ntdll/loader.c
+++ b/dlls/ntdll/loader.c
@@ -1827,7 +1827,13 @@ static void load_builtin_callback( void *module, const char *filename )
     SERVER_END_REQ;
 
     /* setup relay debugging entry points */
-    if (TRACE_ON(relay)) RELAY_SetupDLL( module );
+#ifdef __aarch64__
+    /* Always enable relay entry points on aarch64, to allow restoring
+     * the TEB to x18. */
+#else
+    if (TRACE_ON(relay))
+#endif
+        RELAY_SetupDLL( module );
 }
 
 
diff --git a/dlls/ntdll/relay.c b/dlls/ntdll/relay.c
index 7974587c4a..1d88eddb3f 100644
--- a/dlls/ntdll/relay.c
+++ b/dlls/ntdll/relay.c
@@ -709,8 +709,12 @@ static LONGLONG WINAPI relay_call( struct relay_descr *descr, unsigned int idx,
 {
     unsigned int nb_args;
     void *func = relay_trace_entry( descr, idx, stack, &nb_args );
+    void *teb;
     LONGLONG ret = call_entry_point( func, nb_args, stack );
     relay_trace_exit( descr, idx, stack[-1], ret );
+    teb = NtCurrentTeb();
+    /* Restore the TEB pointer, in case the builtin call clobbered it. */
+    __asm__ __volatile__( "mov x18, %0" : : "r" (teb) );
     return ret;
 }
 
-- 
2.17.1

