[PATCH 2/2] ntdll: Avoid resetting x87 FPU state when saving context.

Paul Gofman gofmanp at gmail.com
Fri Mar 1 15:20:11 CST 2019


'FNSAVE' x87 instruction resets the FPU state to default values
(like FINIT). This results in FPU state reset to default in any
ntdll call which getting x87 FPU state, e. g. loading context
or raising exception.

Signed-off-by: Paul Gofman <gofmanp at gmail.com>
---
 dlls/ntdll/signal_i386.c     | 18 ++++++++++++++++++
 dlls/ntdll/tests/exception.c |  2 +-
 2 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c
index 0274a7d26d..f1deb1c65c 100644
--- a/dlls/ntdll/signal_i386.c
+++ b/dlls/ntdll/signal_i386.c
@@ -860,8 +860,26 @@ static inline void *init_handler( const ucontext_t *sigcontext, WORD *fs, WORD *
 static inline void save_fpu( CONTEXT *context )
 {
 #ifdef __GNUC__
+    struct
+    {
+        DWORD ControlWord;
+        DWORD StatusWord;
+        DWORD TagWord;
+        DWORD ErrorOffset;
+        DWORD ErrorSelector;
+        DWORD DataOffset;
+        DWORD DataSelector;
+    }
+    float_status;
+
     context->ContextFlags |= CONTEXT_FLOATING_POINT;
     __asm__ __volatile__( "fnsave %0; fwait" : "=m" (context->FloatSave) );
+
+    /* Reset unmasked exceptions status to avoid firing an exception. */
+    memcpy(&float_status, &context->FloatSave, sizeof(float_status));
+    float_status.StatusWord &= float_status.ControlWord | 0xffffff80;
+
+    __asm__ __volatile__( "fldenv %0" : "=m" (float_status) );
 #endif
 }
 
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c
index 5d108bade1..f61b4a6c3a 100644
--- a/dlls/ntdll/tests/exception.c
+++ b/dlls/ntdll/tests/exception.c
@@ -1643,7 +1643,7 @@ static void test_thread_context(void)
 
     ok( LOWORD(context.FloatSave.ControlWord) == LOWORD(expect.x87_control),
             "wrong x87 control word %#x/%#x.\n", context.FloatSave.ControlWord, expect.x87_control );
-    todo_wine ok( LOWORD(expect.x87_control) == LOWORD(expect.new_x87_control),
+    ok( LOWORD(expect.x87_control) == LOWORD(expect.new_x87_control),
             "x87 control word changed in NtGetContextThread() %#x/%#x.\n",
             LOWORD(expect.x87_control), LOWORD(expect.new_x87_control) );
 
-- 
2.20.1




More information about the wine-devel mailing list