diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index db93d3f6ed0..dd977a6b343 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -520,7 +520,10 @@ C_ASSERT( offsetof( TEB, GdiTebBatch ) + offsetof( struct x86_thread_data, gs ) C_ASSERT( offsetof( TEB, GdiTebBatch ) + offsetof( struct x86_thread_data, exit_frame ) == 0x1f4 ); C_ASSERT( offsetof( TEB, GdiTebBatch ) + offsetof( struct x86_thread_data, syscall_frame ) == 0x1f8 ); -static void *syscall_dispatcher; +/* flags to control the behavior of the syscall dispatcher */ +#define SYSCALL_HAVE_XSAVE 1 +#define SYSCALL_HAVE_XSAVEC 2 +#define SYSCALL_HAVE_FXSAVE 4 static inline struct x86_thread_data *x86_thread_data(void) { @@ -2331,7 +2334,7 @@ NTSTATUS signal_alloc_thread( TEB *teb ) } else thread_data->fs = gdt_fs_sel; - teb->WOW32Reserved = syscall_dispatcher; + teb->WOW32Reserved = __wine_syscall_dispatcher; return STATUS_SUCCESS; } @@ -2374,6 +2377,10 @@ void signal_init_process(void) { struct sigaction sig_act; + if (cpu_info.ProcessorFeatureBits & CPU_FEATURE_FXSR) __wine_syscall_flags |= SYSCALL_HAVE_FXSAVE; + if (cpu_info.ProcessorFeatureBits & CPU_FEATURE_XSAVE) __wine_syscall_flags |= SYSCALL_HAVE_XSAVE; + if (xstate_compaction_enabled) __wine_syscall_flags |= SYSCALL_HAVE_XSAVEC; + sig_act.sa_mask = server_block_set; sig_act.sa_flags = SA_SIGINFO | SA_RESTART | SA_ONSTACK; #ifdef __ANDROID__ @@ -2409,20 +2416,7 @@ void signal_init_process(void) */ void *signal_init_syscalls(void) { - extern void __wine_syscall_dispatcher_fxsave(void) DECLSPEC_HIDDEN; - extern void __wine_syscall_dispatcher_xsave(void) DECLSPEC_HIDDEN; - extern void __wine_syscall_dispatcher_xsavec(void) DECLSPEC_HIDDEN; - - if (xstate_compaction_enabled) - syscall_dispatcher = __wine_syscall_dispatcher_xsavec; - else if (cpu_info.ProcessorFeatureBits & CPU_FEATURE_XSAVE) - syscall_dispatcher = __wine_syscall_dispatcher_xsave; - else if (cpu_info.ProcessorFeatureBits & CPU_FEATURE_FXSR) - syscall_dispatcher = __wine_syscall_dispatcher_fxsave; - else - syscall_dispatcher = __wine_syscall_dispatcher; - - return NtCurrentTeb()->WOW32Reserved = syscall_dispatcher; + return NtCurrentTeb()->WOW32Reserved = __wine_syscall_dispatcher; } diff --git a/tools/winebuild/import.c b/tools/winebuild/import.c index c89d00f65f3..3acf720e1c6 100644 --- a/tools/winebuild/import.c +++ b/tools/winebuild/import.c @@ -1421,15 +1421,14 @@ static int cmp_link_name( const void *e1, const void *e2 ) /* output dispatcher for system calls */ -static void output_syscall_dispatcher( const char *variant ) +static void output_syscall_dispatcher(void) { const unsigned int invalid_param = 0xc000000d; /* STATUS_INVALID_PARAMETER */ - const char *symbol = strmake( "__wine_syscall_dispatcher%s", variant ); unsigned int i; output( "\t.align %d\n", get_alignment(4) ); - output( "\t%s\n", func_declaration(symbol) ); - output( "%s\n", asm_globl(symbol) ); + output( "\t%s\n", func_declaration("__wine_syscall_dispatcher") ); + output( "%s\n", asm_globl("__wine_syscall_dispatcher") ); output_cfi( ".cfi_startproc" ); switch (target_cpu) { @@ -1459,37 +1458,6 @@ static void output_syscall_dispatcher( const char *variant ) output( "\tmovl %%ecx,-0x2c(%%ebp)\n" ); /* frame->eip */ output( "\tsubl $0x2c0,%%esp\n") ; output( "\tandl $~63,%%esp\n" ); - if (!*variant) - { - output( "\tfnsave (%%esp)\n" ); - output( "\tfwait\n" ); - } - else if(!strcmp( variant, "_fxsave" )) - { - output( "\tfxsave (%%esp)\n" ); - } - else if(!strcmp( variant, "_xsave" )) - { - output( "\tmovl %%eax,%%ecx\n "); - output( "\tmovl $7,%%eax\n" ); - output( "\txorl %%edx,%%edx\n" ); - for (i = 0; i < 6; i++) - output( "\tmovl %%edx,0x%x(%%esp)\n", 0x200 + i * 4 ); - output( "\txsave (%%esp)\n" ); - output( "\tmovl %%ecx,%%eax\n "); - } - else /* _xsavec */ - { - output( "\tmovl %%eax,%%ecx\n "); - output( "\tmovl $7,%%eax\n" ); - output( "\txorl %%edx,%%edx\n" ); - for (i = 0; i < 16; i++) - output( "\tmovl %%edx,0x%x(%%esp)\n", 0x200 + i * 4 ); - output( "\txsavec (%%esp)\n" ); - output( "\tmovl %%ecx,%%eax\n "); - } - output( "\tleal -0x30(%%ebp),%%ecx\n" ); - output( "\tmovl %%ecx,%%fs:0x1f8\n" ); /* x86_thread_data()->syscall_frame */ output( "\tmovl %%eax,%%ecx\n" ); output( "\tshrl $8,%%ecx\n" ); output( "\tandl $0x30,%%ecx\n" ); /* syscall table number */ @@ -1499,14 +1467,43 @@ static void output_syscall_dispatcher( const char *variant ) { output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") ); output( "1:\tleal %s-1b(%%eax,%%ecx),%%ebx\n", asm_name("KeServiceDescriptorTable") ); + output( "\tmovl %s-1b(%%eax),%%esi\n", asm_name("__wine_syscall_flags") ); needs_get_pc_thunk = 1; } - else output( "\tleal %s(%%ecx),%%ebx\n", asm_name("KeServiceDescriptorTable") ); - + else + { + output( "\tleal %s(%%ecx),%%ebx\n", asm_name("KeServiceDescriptorTable") ); + output( "\tmovl %s,%%esi\n", asm_name("__wine_syscall_flags") ); + } + output( "\ttestl $3,%%esi\n" ); /* SYSCALL_HAVE_XSAVE | SYSCALL_HAVE_XSAVEC */ + output( "\tjz 2f\n" ); + output( "\tmovl %%edx,%%ecx\n "); + output( "\tmovl $7,%%eax\n" ); + output( "\txorl %%edx,%%edx\n" ); + for (i = 0; i < 6; i++) output( "\tmovl %%edx,0x%x(%%esp)\n", 0x200 + i * 4 ); + output( "\ttestl $2,%%esi\n" ); /* SYSCALL_HAVE_XSAVEC */ + output( "\tjz 1f\n" ); + for (i = 6; i < 16; i++) output( "\tmovl %%edx,0x%x(%%esp)\n", 0x200 + i * 4 ); + output( "\txsavec (%%esp)\n" ); + output( "\tmovl %%ecx,%%edx\n "); + output( "\tjmp 4f\n" ); + output( "1:\txsave (%%esp)\n" ); + output( "\tmovl %%ecx,%%edx\n "); + output( "\tjmp 4f\n" ); + output( "2:\ttestl $4,%%esi\n" ); /* SYSCALL_HAVE_FXSAVE */ + output( "\tjz 3f\n" ); + output( "\tfxsave (%%esp)\n" ); + output( "\tjmp 4f\n" ); + output( "3:\tfnsave (%%esp)\n" ); + output( "\tfwait\n" ); + output( "4:\tleal -0x30(%%ebp),%%ecx\n" ); + output( "\tmovl %%ecx,%%fs:0x1f8\n" ); /* x86_thread_data()->syscall_frame */ output( "\tcmpl 8(%%ebx),%%edx\n" ); /* table->ServiceLimit */ - output( "\tjae 4f\n" ); + output( "\tjae 6f\n" ); output( "\tmovl 12(%%ebx),%%eax\n" ); /* table->ArgumentTable */ output( "\tmovzbl (%%eax,%%edx,1),%%ecx\n" ); + output( "\tmovl (%%ebx),%%eax\n" ); /* table->ServiceTable */ + output( "\tmovl %%esi,%%ebx\n" ); output( "\tsubl %%ecx,%%esp\n" ); output( "\tshrl $2,%%ecx\n" ); output( "\tleal 12(%%ebp),%%esi\n" ); @@ -1514,29 +1511,26 @@ static void output_syscall_dispatcher( const char *variant ) output( "\tmovl %%esp,%%edi\n" ); output( "\tcld\n" ); output( "\trep; movsl\n" ); - output( "\tmovl (%%ebx),%%eax\n" ); /* table->ServiceTable */ + output( "\tmovl %%ebx,%%esi\n" ); output( "\tcall *(%%eax,%%edx,4)\n" ); - output( "2:\tmovl $0,%%fs:0x1f8\n" ); + output( "5:\tmovl $0,%%fs:0x1f8\n" ); output( "\tleal -0x2f0(%%ebp),%%ebx\n") ; output( "\tandl $~63,%%ebx\n" ); - if (!*variant) - { - output( "\tfrstor (%%ebx)\n" ); - output( "\tfwait\n" ); - } - else if(!strcmp( variant, "_fxsave" )) - { - output( "\tfxrstor (%%ebx)\n" ); - } - else - { - output( "\tmovl %%eax,%%ecx\n" ); - output( "\tmovl $7,%%eax\n" ); - output( "\txorl %%edx,%%edx\n" ); - output( "\txrstor (%%ebx)\n" ); - output( "\tmovl %%ecx,%%eax\n" ); - } - output( "\tleal -0x30(%%ebp),%%ebx\n" ); + output( "\ttestl $3,%%esi\n" ); /* SYSCALL_HAVE_XSAVE | SYSCALL_HAVE_XSAVEC */ + output( "\tjz 1f\n" ); + output( "\tmovl %%eax,%%ecx\n" ); + output( "\tmovl $7,%%eax\n" ); + output( "\txorl %%edx,%%edx\n" ); + output( "\txrstor (%%ebx)\n" ); + output( "\tmovl %%ecx,%%eax\n" ); + output( "\tjmp 3f\n" ); + output( "1:\ttestl $4,%%esi\n" ); /* SYSCALL_HAVE_FXSAVE */ + output( "\tjz 2f\n" ); + output( "\tfxrstor (%%ebx)\n" ); + output( "\tjmp 3f\n" ); + output( "2:\tfrstor (%%ebx)\n" ); + output( "\tfwait\n" ); + output( "3:\tleal -0x30(%%ebp),%%ebx\n" ); output_cfi( ".cfi_def_cfa_register %%ebx" ); output_cfi( ".cfi_adjust_cfa_offset 0x30\n" ); output( "\tmovl %%eax,0x18(%%ebx)\n" ); @@ -1583,8 +1577,8 @@ static void output_syscall_dispatcher( const char *variant ) output( "\tmovl 0x1c(%%ebx),%%ebx\n" ); output( "\tpopl %%ds\n" ); output( "\tiret\n" ); - output( "4:\tmovl $0x%x,%%eax\n", invalid_param ); - output( "\tjmp 2b\n" ); + output( "6:\tmovl $0x%x,%%eax\n", invalid_param ); + output( "\tjmp 5b\n" ); break; case CPU_x86_64: output( "\tpushq %%rbp\n" ); @@ -1822,7 +1816,7 @@ static void output_syscall_dispatcher( const char *variant ) assert(0); } output_cfi( ".cfi_endproc" ); - output_function_size( symbol ); + output_function_size( "__wine_syscall_dispatcher" ); } @@ -1847,18 +1841,8 @@ void output_syscalls( DLLSPEC *spec ) if (unix_lib) { - output_syscall_dispatcher( "" ); + output_syscall_dispatcher(); - switch( target_cpu ) - { - case CPU_x86: - output_syscall_dispatcher( "_fxsave" ); - output_syscall_dispatcher( "_xsave" ); - output_syscall_dispatcher( "_xsavec" ); - break; - default: - break; - } output( "\t.data\n" ); output( "\t.align %d\n", get_alignment( get_ptr_size() ) ); output( "%s\n", asm_globl("KeServiceDescriptorTable") );