ntdll: Allocate a 32-bit %fs selector on Linux in Wow64 mode.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2021-07-06 12:38:07 +02:00
parent cec3db10f4
commit a7b6b4f0d0
1 changed files with 36 additions and 1 deletions

View File

@ -88,6 +88,30 @@ WINE_DEFAULT_DEBUG_CHANNEL(seh);
#include <asm/prctl.h>
static inline int arch_prctl( int func, void *ptr ) { return syscall( __NR_arch_prctl, func, ptr ); }
extern int CDECL alloc_fs_sel( int sel, void *base );
__ASM_GLOBAL_FUNC( alloc_fs_sel,
/* switch to 32-bit stack */
"pushq %rbx\n\t"
"pushq %rdi\n\t"
"movq %rsp,%rdi\n\t"
"movq %gs:0x8,%rsp\n\t" /* NtCurrentTeb()->Tib.StackBase */
"subl $0x10,%esp\n\t"
/* setup modify_ldt struct on 32-bit stack */
"movl %ecx,(%rsp)\n\t" /* entry_number */
"movl %edx,4(%rsp)\n\t" /* base */
"movl $~0,8(%rsp)\n\t" /* limit */
"movl $0x41,12(%rsp)\n\t" /* seg_32bit | usable */
/* invoke 32-bit syscall */
"movl %esp,%ebx\n\t"
"movl $0xf3,%eax\n\t" /* SYS_set_thread_area */
"int $0x80\n\t"
/* restore stack */
"movl (%rsp),%eax\n\t" /* entry_number */
"movq %rdi,%rsp\n\t"
"popq %rdi\n\t"
"popq %rbx\n\t"
"ret" );
#ifndef FP_XSTATE_MAGIC1
#define FP_XSTATE_MAGIC1 0x46505853
#endif
@ -367,6 +391,7 @@ static inline void context_init_xstate( CONTEXT *context, void *xstate_buffer )
static USHORT cs32_sel; /* selector for %cs in 32-bit mode */
static USHORT cs64_sel; /* selector for %cs in 64-bit mode */
static USHORT ds64_sel; /* selector for %ds/%es/%ss in 64-bit mode */
static USHORT fs32_sel; /* selector for %fs in 32-bit mode */
/***********************************************************************
* Definitions for Dwarf unwind tables
@ -1911,7 +1936,7 @@ NTSTATUS set_thread_wow64_context( HANDLE handle, const void *ctx, ULONG size )
{
wow_frame->SegDs = ds64_sel;
wow_frame->SegEs = ds64_sel;
wow_frame->SegFs = 0; /* FIXME */
wow_frame->SegFs = fs32_sel;
wow_frame->SegGs = ds64_sel;
}
if (flags & CONTEXT_I386_DEBUG_REGISTERS)
@ -2743,6 +2768,7 @@ void signal_init_thread( TEB *teb )
#if defined __linux__
arch_prctl( ARCH_SET_GS, teb );
arch_prctl( ARCH_GET_FS, &amd64_thread_data()->pthread_teb );
if (fs32_sel) alloc_fs_sel( fs32_sel >> 3, (char *)teb + teb->WowTebOffset );
#elif defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
amd64_set_gsbase( teb );
#elif defined(__NetBSD__)
@ -2793,7 +2819,15 @@ void signal_init_process(void)
#ifdef __linux__
if (NtCurrentTeb()->WowTebOffset)
{
void *teb32 = (char *)NtCurrentTeb() + NtCurrentTeb()->WowTebOffset;
int sel;
cs32_sel = 0x23;
if ((sel = alloc_fs_sel( -1, teb32 )) != -1)
{
fs32_sel = (sel << 3) | 3;
}
else ERR( "failed to allocate %%fs selector\n" );
}
#endif
@ -2842,6 +2876,7 @@ void DECLSPEC_HIDDEN call_init_thunk( LPTHREAD_START_ROUTINE entry, void *arg, B
context.SegCs = cs64_sel;
context.SegDs = ds64_sel;
context.SegEs = ds64_sel;
context.SegFs = fs32_sel;
context.SegGs = ds64_sel;
context.SegSs = ds64_sel;
context.EFlags = 0x200;