diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c index fd761246c5..29a5ad7db8 100644 --- a/dlls/ntdll/signal_i386.c +++ b/dlls/ntdll/signal_i386.c @@ -442,6 +442,8 @@ static size_t signal_stack_size; static wine_signal_handler handlers[256]; +static int wine_cs; + enum i386_trap_code { TRAP_x86_UNKNOWN = -1, /* Unknown fault (TRAP_sig not defined) */ @@ -846,7 +848,7 @@ static inline void *init_handler( const ucontext_t *sigcontext, WORD *fs, WORD * } #endif - if (!wine_ldt_is_system(CS_sig(sigcontext)) || + if ((CS_sig(sigcontext) != wine_cs && !wine_ldt_is_system(CS_sig(sigcontext))) || !wine_ldt_is_system(SS_sig(sigcontext))) /* 16-bit mode */ { /* @@ -1533,7 +1535,7 @@ static inline DWORD is_privileged_instr( CONTEXT *context ) BYTE instr[16]; unsigned int i, len, prefix_count = 0; - if (!wine_ldt_is_system( context->SegCs )) return 0; + if (context->SegCs != wine_cs && !wine_ldt_is_system( context->SegCs )) return 0; len = virtual_uninterrupted_read_memory( (BYTE *)context->Eip, instr, sizeof(instr) ); for (i = 0; i < len; i++) switch (instr[i]) @@ -1600,7 +1602,7 @@ static inline BOOL check_invalid_gs( ucontext_t *sigcontext, CONTEXT *context ) WORD system_gs = x86_thread_data()->gs; if (context->SegGs == system_gs) return FALSE; - if (!wine_ldt_is_system( context->SegCs )) return FALSE; + if (context->SegCs != wine_cs && !wine_ldt_is_system( context->SegCs )) return 0; /* only handle faults in system libraries */ if (virtual_is_valid_code_address( instr, 1 )) return FALSE; @@ -1883,7 +1885,7 @@ static void setup_raise_exception( ucontext_t *sigcontext, struct stack_layout * EIP_sig(sigcontext) = (DWORD)raise_generic_exception; /* clear single-step, direction, and align check flag */ EFL_sig(sigcontext) &= ~(0x100|0x400|0x40000); - CS_sig(sigcontext) = wine_get_cs(); + CS_sig(sigcontext) = wine_cs; DS_sig(sigcontext) = wine_get_ds(); ES_sig(sigcontext) = wine_get_es(); FS_sig(sigcontext) = wine_get_fs(); @@ -2275,6 +2277,21 @@ static void ldt_unlock(void) } +void signal_init_cs(void) +{ + LDT_ENTRY entry; + + if (!wine_cs) + wine_cs = wine_ldt_alloc_entries( 1 ); + + wine_ldt_set_base( &entry, 0 ); + wine_ldt_set_limit( &entry, (UINT_PTR)-1 ); + wine_ldt_set_flags( &entry, WINE_LDT_FLAGS_CODE|WINE_LDT_FLAGS_32BIT ); + wine_ldt_set_entry( wine_cs, &entry ); + + wine_set_cs( wine_cs ); +} + /********************************************************************** * signal_alloc_thread */ @@ -2311,6 +2328,9 @@ NTSTATUS signal_alloc_thread( TEB **teb ) status = STATUS_TOO_MANY_THREADS; } } + + signal_init_cs(); + return status; } diff --git a/include/wine/library.h b/include/wine/library.h index af9deaf93f..cac3e3bc64 100644 --- a/include/wine/library.h +++ b/include/wine/library.h @@ -193,6 +193,7 @@ __DEFINE_SET_SEG(fs) __DEFINE_SET_SEG(gs) #undef __DEFINE_GET_SEG #undef __DEFINE_SET_SEG +extern void wine_set_cs(unsigned int); #endif /* __i386__ */ diff --git a/libs/wine/ldt.c b/libs/wine/ldt.c index baf12a2e3a..edf7247dc0 100644 --- a/libs/wine/ldt.c +++ b/libs/wine/ldt.c @@ -463,6 +463,10 @@ __ASM_GLOBAL_FUNC( wine_get_es, "movw %es,%ax\n\tret" ) __ASM_GLOBAL_FUNC( wine_get_fs, "movw %fs,%ax\n\tret" ) __ASM_GLOBAL_FUNC( wine_get_gs, "movw %gs,%ax\n\tret" ) __ASM_GLOBAL_FUNC( wine_get_ss, "movw %ss,%ax\n\tret" ) +__ASM_GLOBAL_FUNC( wine_set_cs, "movl 4(%esp),%eax\n\t" + "xchg 0(%esp),%eax\n\t" + "push %eax\n\t" + "retf" ) __ASM_GLOBAL_FUNC( wine_set_fs, "movl 4(%esp),%eax\n\tmovw %ax,%fs\n\tret" ) __ASM_GLOBAL_FUNC( wine_set_gs, "movl 4(%esp),%eax\n\tmovw %ax,%gs\n\tret" ) diff --git a/libs/wine/wine.map b/libs/wine/wine.map index 2159fac852..43c735cc59 100644 --- a/libs/wine/wine.map +++ b/libs/wine/wine.map @@ -63,6 +63,7 @@ WINE_1.0 wine_mmap_enum_free_areas; wine_mmap_is_in_free_area; wine_mmap_remove_free_area; + wine_set_cs; wine_set_fs; wine_set_gs; wine_utf8_mbstowcs;