172 lines
6.7 KiB
Diff
172 lines
6.7 KiB
Diff
--- a/tools/winebuild/import.c
|
|
+++ a/tools/winebuild/import.c
|
|
@@ -1951,19 +1951,9 @@ void output_syscalls( DLLSPEC *spec )
|
|
switch (target_cpu)
|
|
{
|
|
case CPU_x86:
|
|
- if (UsePIC)
|
|
- {
|
|
- output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
|
|
- output( "1:\tmovl %s-1b(%%eax),%%edx\n", asm_name("__wine_syscall_dispatcher") );
|
|
- output( "\tmovl $%u,%%eax\n", i );
|
|
- needs_get_pc_thunk = 1;
|
|
- }
|
|
- else
|
|
- {
|
|
- output( "\tmovl $%u,%%eax\n", i );
|
|
- output( "\tmovl $%s,%%edx\n", asm_name("__wine_syscall") );
|
|
- }
|
|
- output( "\tcall *%%edx\n" );
|
|
+ output( "\t.byte 0xb8\n" ); /* mov eax, SYSCALL */
|
|
+ output( "\t.long %d\n", i );
|
|
+ output( "\t.byte 0x64,0xff,0x15,0xc0,0x00,0x00,0x00\n" ); /* call dword ptr fs:[0C0h] */
|
|
output( "\tret $%u\n", odp->type == TYPE_STDCALL ? get_args_size( odp ) : 0 );
|
|
break;
|
|
case CPU_x86_64:
|
|
--- a/dlls/ntdll/unix/signal_i386.c
|
|
+++ a/dlls/ntdll/unix/signal_i386.c
|
|
@@ -415,6 +415,8 @@ static inline int set_thread_area( struc
|
|
|
|
static ULONG first_ldt_entry = 32;
|
|
|
|
+static int wine_cs;
|
|
+
|
|
enum i386_trap_code
|
|
{
|
|
#if defined(__FreeBSD__) || defined (__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
|
|
@@ -528,6 +530,11 @@ static inline WORD get_cs(void) { WORD r
|
|
static inline WORD get_ds(void) { WORD res; __asm__( "movw %%ds,%0" : "=r" (res) ); return res; }
|
|
static inline WORD get_fs(void) { WORD res; __asm__( "movw %%fs,%0" : "=r" (res) ); return res; }
|
|
static inline WORD get_gs(void) { WORD res; __asm__( "movw %%gs,%0" : "=r" (res) ); return res; }
|
|
+static CDECL void __attribute((naked)) set_cs( DWORD val ) {
|
|
+ asm ( "movl 4(%esp),%eax\n\t"
|
|
+ "xchg 0(%esp),%eax\n\t"
|
|
+ "push %eax\n\t"
|
|
+ "lret"); }
|
|
static inline void set_fs( WORD val ) { __asm__( "mov %0,%%fs" :: "r" (val)); }
|
|
static inline void set_gs( WORD val ) { __asm__( "mov %0,%%gs" :: "r" (val)); }
|
|
|
|
@@ -694,7 +701,8 @@ static inline void *init_handler( const
|
|
}
|
|
#endif
|
|
|
|
- if (!ldt_is_system(CS_sig(sigcontext)) || !ldt_is_system(SS_sig(sigcontext))) /* 16-bit mode */
|
|
+ if ((CS_sig(sigcontext) != wine_cs && !ldt_is_system(CS_sig(sigcontext))) ||
|
|
+ !ldt_is_system(SS_sig(sigcontext))) /* 16-bit mode */
|
|
{
|
|
/*
|
|
* Win16 or DOS protected mode. Note that during switch
|
|
@@ -1185,7 +1193,7 @@ static inline DWORD is_privileged_instr(
|
|
BYTE instr[16];
|
|
unsigned int i, len, prefix_count = 0;
|
|
|
|
- if (!ldt_is_system( context->SegCs )) return 0;
|
|
+ if (context->SegCs != wine_cs && !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])
|
|
@@ -1252,7 +1260,7 @@ static inline BOOL check_invalid_gs( uco
|
|
WORD system_gs = x86_thread_data()->gs;
|
|
|
|
if (context->SegGs == system_gs) return FALSE;
|
|
- if (!ldt_is_system( context->SegCs )) return FALSE;
|
|
+ if (context->SegCs != wine_cs && !ldt_is_system( context->SegCs )) return FALSE;
|
|
/* only handle faults in system libraries */
|
|
if (virtual_is_valid_code_address( instr, 1 )) return FALSE;
|
|
|
|
@@ -1489,7 +1497,7 @@ C_ASSERT( (offsetof(struct stack_layout,
|
|
EIP_sig(sigcontext) = (DWORD)pKiUserExceptionDispatcher;
|
|
/* clear single-step, direction, and align check flag */
|
|
EFL_sig(sigcontext) &= ~(0x100|0x400|0x40000);
|
|
- CS_sig(sigcontext) = get_cs();
|
|
+ CS_sig(sigcontext) = wine_cs;
|
|
DS_sig(sigcontext) = get_ds();
|
|
ES_sig(sigcontext) = get_ds();
|
|
FS_sig(sigcontext) = get_fs();
|
|
@@ -2108,6 +2116,36 @@ static void ldt_set_entry( WORD sel, LDT
|
|
LDT_FLAGS_ALLOCATED);
|
|
}
|
|
|
|
+static WORD internal_ldt_alloc_entry(void)
|
|
+{
|
|
+ for (int idx = first_ldt_entry; idx < LDT_SIZE; idx++)
|
|
+ {
|
|
+ if (__wine_ldt_copy.flags[idx] & LDT_FLAGS_ALLOCATED) continue;
|
|
+
|
|
+ /* mark selector as allocated */
|
|
+ __wine_ldt_copy.flags[idx] |= LDT_FLAGS_ALLOCATED;
|
|
+ return (idx << 3) | 7;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static inline void cs_init( int first_thread )
|
|
+{
|
|
+ LDT_ENTRY entry;
|
|
+ sigset_t sigset;
|
|
+
|
|
+ /* no locking for first thread */
|
|
+ if (!first_thread) server_enter_uninterrupted_section( &ldt_mutex, &sigset );
|
|
+ if (!wine_cs)
|
|
+ wine_cs = internal_ldt_alloc_entry();
|
|
+
|
|
+ entry = ldt_make_entry( 0, (UINT_PTR)-1, LDT_FLAGS_CODE|LDT_FLAGS_32BIT );
|
|
+ ldt_set_entry( wine_cs, entry );
|
|
+
|
|
+ if (!first_thread) server_leave_uninterrupted_section( &ldt_mutex, &sigset );
|
|
+ set_cs( wine_cs );
|
|
+}
|
|
+
|
|
static void ldt_set_fs( WORD sel, TEB *teb )
|
|
{
|
|
if (sel == gdt_fs_sel)
|
|
@@ -2223,38 +2261,35 @@ void signal_init_threading(void)
|
|
NTSTATUS signal_alloc_thread( TEB *teb )
|
|
{
|
|
struct x86_thread_data *thread_data = (struct x86_thread_data *)&teb->GdiTebBatch;
|
|
+ static int first_thread = 1;
|
|
|
|
if (!gdt_fs_sel)
|
|
{
|
|
- static int first_thread = 1;
|
|
sigset_t sigset;
|
|
- int idx;
|
|
+ WORD sel;
|
|
LDT_ENTRY entry = ldt_make_entry( teb, page_size - 1, LDT_FLAGS_DATA | LDT_FLAGS_32BIT );
|
|
|
|
if (first_thread) /* no locking for first thread */
|
|
{
|
|
/* leave some space if libc is using the LDT for %gs */
|
|
if (!is_gdt_sel( get_gs() )) first_ldt_entry = 512;
|
|
- idx = first_ldt_entry;
|
|
- ldt_set_entry( (idx << 3) | 7, entry );
|
|
- first_thread = 0;
|
|
+ sel = (first_ldt_entry << 3) | 7;
|
|
+ ldt_set_entry( sel, entry );
|
|
}
|
|
else
|
|
{
|
|
server_enter_uninterrupted_section( &ldt_mutex, &sigset );
|
|
- for (idx = first_ldt_entry; idx < LDT_SIZE; idx++)
|
|
- {
|
|
- if (__wine_ldt_copy.flags[idx]) continue;
|
|
- ldt_set_entry( (idx << 3) | 7, entry );
|
|
- break;
|
|
- }
|
|
+ sel = internal_ldt_alloc_entry();
|
|
+ if (sel) ldt_set_entry( sel, entry );
|
|
server_leave_uninterrupted_section( &ldt_mutex, &sigset );
|
|
- if (idx == LDT_SIZE) return STATUS_TOO_MANY_THREADS;
|
|
+ if (!sel) return STATUS_TOO_MANY_THREADS;
|
|
}
|
|
- thread_data->fs = (idx << 3) | 7;
|
|
+ thread_data->fs = sel;
|
|
}
|
|
else thread_data->fs = gdt_fs_sel;
|
|
|
|
+ cs_init( first_thread );
|
|
+ first_thread = 0;
|
|
teb->WOW32Reserved = __wine_syscall_dispatcher;
|
|
return STATUS_SUCCESS;
|
|
}
|