[v2 2/3] ntdll: Save rdi and rsi in raise_func_trampoline.

Andrew Wesie awesie at gmail.com
Sat Feb 4 23:54:42 CST 2017


On Windows, RDI and RSI are callee-saved registers, but on Linux
they are caller-saved registers. As such, raise_func_trampoline
needs to explicitly unwind them.

Signed-off-by: Andrew Wesie <awesie at gmail.com>
---
 dlls/ntdll/signal_x86_64.c   | 12 +++++++++---
 dlls/ntdll/tests/exception.c | 42 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 51 insertions(+), 3 deletions(-)

diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c
index af16cfd..8b85be7 100644
--- a/dlls/ntdll/signal_x86_64.c
+++ b/dlls/ntdll/signal_x86_64.c
@@ -2067,9 +2067,11 @@ NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
 extern void raise_func_trampoline( EXCEPTION_RECORD *rec, CONTEXT *context, raise_func func );
 __ASM_GLOBAL_FUNC( raise_func_trampoline,
                    __ASM_CFI(".cfi_signal_frame\n\t")
-                   __ASM_CFI(".cfi_def_cfa %rbp,144\n\t")  /* red zone + rip + rbp */
-                   __ASM_CFI(".cfi_rel_offset %rip,8\n\t")
-                   __ASM_CFI(".cfi_rel_offset %rbp,0\n\t")
+                   __ASM_CFI(".cfi_def_cfa %rbp,160\n\t")  /* red zone + rip + rbp + rdi + rsi */
+                   __ASM_CFI(".cfi_rel_offset %rip,24\n\t")
+                   __ASM_CFI(".cfi_rel_offset %rbp,16\n\t")
+                   __ASM_CFI(".cfi_rel_offset %rdi,8\n\t")
+                   __ASM_CFI(".cfi_rel_offset %rsi,0\n\t")
                    "call *%rdx\n\t"
                    "int $3")
 
@@ -2086,6 +2088,8 @@ static EXCEPTION_RECORD *setup_exception( ucontext_t *sigcontext, raise_func fun
     {
         CONTEXT           context;
         EXCEPTION_RECORD  rec;
+        ULONG64           rsi;
+        ULONG64           rdi;
         ULONG64           rbp;
         ULONG64           rip;
         ULONG64           red_zone[16];
@@ -2155,6 +2159,8 @@ static EXCEPTION_RECORD *setup_exception( ucontext_t *sigcontext, raise_func fun
     rsp_ptr = (ULONG64 *)RSP_sig(sigcontext) - 16;
     *(--rsp_ptr) = RIP_sig(sigcontext);
     *(--rsp_ptr) = RBP_sig(sigcontext);
+    *(--rsp_ptr) = RDI_sig(sigcontext);
+    *(--rsp_ptr) = RSI_sig(sigcontext);
 
     /* now modify the sigcontext to return to the raise function */
     RIP_sig(sigcontext) = (ULONG_PTR)raise_func_trampoline;
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c
index 446f0da..c1a8eaa 100644
--- a/dlls/ntdll/tests/exception.c
+++ b/dlls/ntdll/tests/exception.c
@@ -2030,6 +2030,47 @@ static DWORD run_exception_test(void *handler, const void* context,
     return result;
 }
 
+static DWORD WINAPI unwind_rdi_rsi_handler( EXCEPTION_RECORD *rec, ULONG64 frame,
+                      CONTEXT *context, DISPATCHER_CONTEXT *dispatcher )
+{
+    if (rec->ExceptionCode != STATUS_BREAKPOINT)
+        return ExceptionContinueSearch;
+
+    RtlUnwind( (PVOID)context->Rsp, (PVOID)(context->Rip + 1), rec, NULL );
+    return ExceptionContinueSearch;
+}
+
+static const BYTE unwind_rdi_test_code[] = {
+        0x57,                                           /* push %rdi */
+        0x48, 0xc7, 0xc7, 0x55, 0x55, 0x55, 0x55,       /* mov $0x55555555, %rdi */
+        0xcc,                                           /* int3 */
+        0x48, 0x89, 0xf8,                               /* mov %rdi, %rax */
+        0x5f,                                           /* pop %rdi */
+        0xc3,                                           /* ret */
+};
+
+static const BYTE unwind_rsi_test_code[] = {
+        0x56,                                           /* push %rsi */
+        0x48, 0xc7, 0xc6, 0x33, 0x33, 0x33, 0x33,       /* mov $0x33333333, %rsi */
+        0xcc,                                           /* int3 */
+        0x48, 0x89, 0xf0,                               /* mov %rsi, %rax */
+        0x5e,                                           /* pop %rsi */
+        0xc3,                                           /* ret */
+};
+
+static void test_unwind_rdi_rsi(void)
+{
+    DWORD result;
+
+    result = run_exception_test(unwind_rdi_rsi_handler, NULL, unwind_rdi_test_code,
+            sizeof(unwind_rdi_test_code), 0);
+    ok( result == 0x55555555, "expected %x, got %x\n", 0x55555555, result );
+
+    result = run_exception_test(unwind_rdi_rsi_handler, NULL, unwind_rsi_test_code,
+            sizeof(unwind_rsi_test_code), 0);
+    ok( result == 0x33333333, "expected %x, got %x\n", 0x33333333, result );
+}
+
 static DWORD WINAPI dr7_handler( EXCEPTION_RECORD *rec, ULONG64 frame,
                       CONTEXT *context, DISPATCHER_CONTEXT *dispatcher )
 {
@@ -2608,6 +2649,7 @@ START_TEST(exception)
     test_virtual_unwind();
     test___C_specific_handler();
     test_restore_context();
+    test_unwind_rdi_rsi();
 
     if (pRtlAddFunctionTable && pRtlDeleteFunctionTable && pRtlInstallFunctionTableCallback && pRtlLookupFunctionEntry)
       test_dynamic_unwind();
-- 
2.7.4




More information about the wine-patches mailing list