winebuild: Save/restore the %fs register in the syscall dispatcher on Linux.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2021-07-06 12:50:56 +02:00
parent 5e12256ec4
commit 216d241178
2 changed files with 31 additions and 2 deletions

View File

@ -41,6 +41,9 @@
#ifdef HAVE_MACHINE_SYSARCH_H #ifdef HAVE_MACHINE_SYSARCH_H
# include <machine/sysarch.h> # include <machine/sysarch.h>
#endif #endif
#ifdef HAVE_SYS_AUXV_H
# include <sys/auxv.h>
#endif
#ifdef HAVE_SYS_PARAM_H #ifdef HAVE_SYS_PARAM_H
# include <sys/param.h> # include <sys/param.h>
#endif #endif
@ -276,8 +279,10 @@ C_ASSERT( sizeof(XSTATE) == 0x140 );
C_ASSERT( sizeof(struct stack_layout) == 0x590 ); /* Should match the size in call_user_exception_dispatcher(). */ C_ASSERT( sizeof(struct stack_layout) == 0x590 ); /* Should match the size in call_user_exception_dispatcher(). */
/* flags to control the behavior of the syscall dispatcher */ /* flags to control the behavior of the syscall dispatcher */
#define SYSCALL_HAVE_XSAVE 1 #define SYSCALL_HAVE_XSAVE 1
#define SYSCALL_HAVE_XSAVEC 2 #define SYSCALL_HAVE_XSAVEC 2
#define SYSCALL_HAVE_PTHREAD_TEB 4
#define SYSCALL_HAVE_WRFSGSBASE 8
/* stack layout when calling an user apc function. /* stack layout when calling an user apc function.
* FIXME: match Windows ABI. */ * FIXME: match Windows ABI. */
@ -2859,6 +2864,8 @@ void signal_init_process(void)
if ((sel = alloc_fs_sel( -1, teb32 )) != -1) if ((sel = alloc_fs_sel( -1, teb32 )) != -1)
{ {
fs32_sel = (sel << 3) | 3; fs32_sel = (sel << 3) | 3;
__wine_syscall_flags |= SYSCALL_HAVE_PTHREAD_TEB;
if (getauxval( AT_HWCAP2 ) & 2) __wine_syscall_flags |= SYSCALL_HAVE_WRFSGSBASE;
} }
else ERR( "failed to allocate %%fs selector\n" ); else ERR( "failed to allocate %%fs selector\n" );
} }

View File

@ -1597,6 +1597,21 @@ static void output_syscall_dispatcher(void)
output( "\tjmp 3f\n" ); output( "\tjmp 3f\n" );
output( "2:\tfxsave64 0xc0(%%rcx)\n" ); output( "2:\tfxsave64 0xc0(%%rcx)\n" );
output( "3:\tleaq 0x98(%%rcx),%%rbp\n" ); output( "3:\tleaq 0x98(%%rcx),%%rbp\n" );
if (target_platform == PLATFORM_LINUX)
{
output( "\ttestl $12,%%r14d\n" ); /* SYSCALL_HAVE_PTHREAD_TEB | SYSCALL_HAVE_WRFSGSBASE */
output( "\tjz 2f\n" );
output( "\tmovq %%gs:0x330,%%rsi\n" ); /* amd64_thread_data()->pthread_teb */
output( "\ttestl $8,%%r14d\n" ); /* SYSCALL_HAVE_WRFSGSBASE */
output( "\tjz 1f\n" );
output( "\twrfsbase %%rsi\n" );
output( "\tjmp 2f\n" );
output( "1:\tmov $0x1002,%%edi\n" ); /* ARCH_SET_FS */
output( "\tmov $158,%%eax\n" ); /* SYS_arch_prctl */
output( "\tsyscall\n" );
output( "\tleaq -0x98(%%rbp),%%rcx\n" );
output( "2:\n" );
}
output( "\tleaq 0x28(%%rsp),%%rsi\n" ); /* first argument */ output( "\tleaq 0x28(%%rsp),%%rsi\n" ); /* first argument */
output( "\tmovq %%rcx,%%rsp\n" ); output( "\tmovq %%rcx,%%rsp\n" );
output( "\tmovq 0x00(%%rcx),%%rax\n" ); output( "\tmovq 0x00(%%rcx),%%rax\n" );
@ -1625,6 +1640,13 @@ static void output_syscall_dispatcher(void)
output( "\tcallq *(%%r10,%%rax,8)\n" ); output( "\tcallq *(%%r10,%%rax,8)\n" );
output( "\tleaq -0x98(%%rbp),%%rcx\n" ); output( "\tleaq -0x98(%%rbp),%%rcx\n" );
output( "2:\tmovl 0x94(%%rcx),%%edx\n" ); /* frame->restore_flags */ output( "2:\tmovl 0x94(%%rcx),%%edx\n" ); /* frame->restore_flags */
if (target_platform == PLATFORM_LINUX)
{
output( "\ttestl $12,%%r14d\n" ); /* SYSCALL_HAVE_PTHREAD_TEB | SYSCALL_HAVE_WRFSGSBASE */
output( "\tjz 1f\n" );
output( "\tmovw 0x7e(%%rcx),%%fs\n" );
output( "1:\n" );
}
output( "\ttestl $0x48,%%edx\n" ); /* CONTEXT_FLOATING_POINT | CONTEXT_XSTATE */ output( "\ttestl $0x48,%%edx\n" ); /* CONTEXT_FLOATING_POINT | CONTEXT_XSTATE */
output( "\tjz 4f\n" ); output( "\tjz 4f\n" );
output( "\ttestl $3,%%r14d\n" ); /* SYSCALL_HAVE_XSAVE | SYSCALL_HAVE_XSAVEC */ output( "\ttestl $3,%%r14d\n" ); /* SYSCALL_HAVE_XSAVE | SYSCALL_HAVE_XSAVEC */