Alexandre Julliard : ntdll: Allocate a 32-bit %fs selector on Linux in Wow64 mode.
Alexandre Julliard
julliard at winehq.org
Tue Jul 6 18:09:35 CDT 2021
Module: wine
Branch: master
Commit: a7b6b4f0d06127526addc4dba7c0b6b09821542b
URL: https://source.winehq.org/git/wine.git/?a=commit;h=a7b6b4f0d06127526addc4dba7c0b6b09821542b
Author: Alexandre Julliard <julliard at winehq.org>
Date: Tue Jul 6 12:38:07 2021 +0200
ntdll: Allocate a 32-bit %fs selector on Linux in Wow64 mode.
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/ntdll/unix/signal_x86_64.c | 37 ++++++++++++++++++++++++++++++++++++-
1 file changed, 36 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c
index 6175bb9b230..b94ad9c4d91 100644
--- a/dlls/ntdll/unix/signal_x86_64.c
+++ b/dlls/ntdll/unix/signal_x86_64.c
@@ -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;
More information about the wine-cvs
mailing list