diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index 1d0a1461fb2..dd27df88990 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -2056,6 +2056,67 @@ static inline BOOL emulate_xgetbv( ucontext_t *sigcontext, CONTEXT *context ) TRACE_(seh)( "emulated an XGETBV instruction\n" ); return TRUE; } + +/*********************************************************************** + * handle_fndisi + * + * Check if the fault location is an x87 FNDISI instruction that should be treated as a NOP. + */ +static inline BOOL handle_fndisi( ucontext_t *sigcontext, CONTEXT *context ) +{ + BYTE instr[16]; + unsigned int i, prefix_count = 0; + unsigned int len = virtual_uninterrupted_read_memory( (BYTE *)context->Rip, instr, sizeof(instr) ); + + for (i = 0; i < len; i++) switch (instr[i]) + { + /* instruction prefixes */ + case 0x2e: /* %cs: */ + case 0x36: /* %ss: */ + case 0x3e: /* %ds: */ + case 0x26: /* %es: */ + case 0x40: /* rex */ + case 0x41: /* rex */ + case 0x42: /* rex */ + case 0x43: /* rex */ + case 0x44: /* rex */ + case 0x45: /* rex */ + case 0x46: /* rex */ + case 0x47: /* rex */ + case 0x48: /* rex */ + case 0x49: /* rex */ + case 0x4a: /* rex */ + case 0x4b: /* rex */ + case 0x4c: /* rex */ + case 0x4d: /* rex */ + case 0x4e: /* rex */ + case 0x4f: /* rex */ + case 0x64: /* %fs: */ + case 0x65: /* %gs: */ + case 0x66: /* opcode size */ + case 0x67: /* addr size */ + case 0xf0: /* lock */ + case 0xf2: /* repne */ + case 0xf3: /* repe */ + if (++prefix_count >= 15) return FALSE; + continue; + + case 0xdb: + if (i == len - 1) return 0; + switch (instr[i + 1]) + { + case 0xe1: + /* RDSSPD/RDSSPQ: (prefixes) DB E1 */ + RIP_sig(sigcontext) += prefix_count + 2; + TRACE_(seh)( "skipped FNDISI instruction\n" ); + return TRUE; + } + break; + default: + return FALSE; + } + return FALSE; +} #endif /*********************************************************************** @@ -2407,6 +2468,8 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) if (handle_cet_nop( ucontext, &context.c )) return; /* CW HACK 23427 */ if (emulate_xgetbv( ucontext, &context.c )) return; + /* Winehq Bug 56441 */ + if (handle_fndisi( ucontext, &context.c )) return; #endif rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; break;