ntdll: Allocate 64-bit TEB and PEB in WoW64 mode.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
e3b059b5ba
commit
a865a4f61d
|
@ -3906,7 +3906,6 @@ void __wine_process_init(void)
|
|||
UNICODE_STRING nt_name;
|
||||
MEMORY_BASIC_INFORMATION meminfo;
|
||||
INITIAL_TEB stack;
|
||||
ULONG_PTR val;
|
||||
TEB *teb = NtCurrentTeb();
|
||||
PEB *peb = teb->Peb;
|
||||
|
||||
|
@ -3935,8 +3934,9 @@ void __wine_process_init(void)
|
|||
InitializeListHead( &ldr.InMemoryOrderModuleList );
|
||||
InitializeListHead( &ldr.InInitializationOrderModuleList );
|
||||
|
||||
NtQueryInformationProcess( GetCurrentProcess(), ProcessWow64Information, &val, sizeof(val), NULL );
|
||||
is_wow64 = !!val;
|
||||
#ifndef _WIN64
|
||||
is_wow64 = !!NtCurrentTeb64();
|
||||
#endif
|
||||
|
||||
init_unix_codepage();
|
||||
init_directories();
|
||||
|
@ -4008,6 +4008,19 @@ void __wine_process_init(void)
|
|||
NtTerminateProcess( GetCurrentProcess(), status );
|
||||
}
|
||||
|
||||
#ifndef _WIN64
|
||||
if (NtCurrentTeb64())
|
||||
{
|
||||
PEB64 *peb64 = UlongToPtr( NtCurrentTeb64()->Peb );
|
||||
peb64->ImageBaseAddress = PtrToUlong( peb->ImageBaseAddress );
|
||||
peb64->OSMajorVersion = peb->OSMajorVersion;
|
||||
peb64->OSMinorVersion = peb->OSMinorVersion;
|
||||
peb64->OSBuildNumber = peb->OSBuildNumber;
|
||||
peb64->OSPlatformId = peb->OSPlatformId;
|
||||
peb64->SessionId = peb->SessionId;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* the main exe needs to be the first in the load order list */
|
||||
RemoveEntryList( &wm->ldr.InLoadOrderLinks );
|
||||
InsertHeadList( &peb->LdrData->InLoadOrderModuleList, &wm->ldr.InLoadOrderLinks );
|
||||
|
|
|
@ -129,6 +129,10 @@ static inline struct ntdll_thread_data *ntdll_get_thread_data(void)
|
|||
return (struct ntdll_thread_data *)&NtCurrentTeb()->GdiTebBatch;
|
||||
}
|
||||
|
||||
#ifndef _WIN64
|
||||
static inline TEB64 *NtCurrentTeb64(void) { return (TEB64 *)NtCurrentTeb()->GdiBatchCount; }
|
||||
#endif
|
||||
|
||||
#define HASH_STRING_ALGORITHM_DEFAULT 0
|
||||
#define HASH_STRING_ALGORITHM_X65599 1
|
||||
#define HASH_STRING_ALGORITHM_INVALID 0xffffffff
|
||||
|
|
|
@ -2636,6 +2636,47 @@ static void test_thread_info(void)
|
|||
ok( len == 0xdeadbeef, "wrong len %u\n", len );
|
||||
}
|
||||
|
||||
static void test_wow64(void)
|
||||
{
|
||||
#ifndef _WIN64
|
||||
if (is_wow64)
|
||||
{
|
||||
PEB64 *peb64;
|
||||
TEB64 *teb64 = (TEB64 *)NtCurrentTeb()->GdiBatchCount;
|
||||
|
||||
ok( !!teb64, "GdiBatchCount not set\n" );
|
||||
ok( (char *)NtCurrentTeb() + NtCurrentTeb()->WowTebOffset == (char *)teb64 ||
|
||||
broken(!NtCurrentTeb()->WowTebOffset), /* pre-win10 */
|
||||
"wrong WowTebOffset %x (%p/%p)\n", NtCurrentTeb()->WowTebOffset, teb64, NtCurrentTeb() );
|
||||
ok( (char *)teb64 + 0x2000 == (char *)NtCurrentTeb(), "unexpected diff %p / %p\n",
|
||||
teb64, NtCurrentTeb() );
|
||||
ok( teb64->Tib.ExceptionList == PtrToUlong( NtCurrentTeb() ), "wrong Tib.ExceptionList %s / %p\n",
|
||||
wine_dbgstr_longlong(teb64->Tib.ExceptionList), NtCurrentTeb() );
|
||||
ok( teb64->Tib.Self == PtrToUlong( teb64 ), "wrong Tib.Self %s / %p\n",
|
||||
wine_dbgstr_longlong(teb64->Tib.Self), teb64 );
|
||||
ok( teb64->StaticUnicodeString.Buffer == PtrToUlong( teb64->StaticUnicodeBuffer ),
|
||||
"wrong StaticUnicodeString %s / %p\n",
|
||||
wine_dbgstr_longlong(teb64->StaticUnicodeString.Buffer), teb64->StaticUnicodeBuffer );
|
||||
ok( teb64->ClientId.UniqueProcess == GetCurrentProcessId(), "wrong pid %s / %x\n",
|
||||
wine_dbgstr_longlong(teb64->ClientId.UniqueProcess), GetCurrentProcessId() );
|
||||
ok( teb64->ClientId.UniqueThread == GetCurrentThreadId(), "wrong tid %s / %x\n",
|
||||
wine_dbgstr_longlong(teb64->ClientId.UniqueThread), GetCurrentThreadId() );
|
||||
peb64 = ULongToPtr( teb64->Peb );
|
||||
ok( peb64->ImageBaseAddress == PtrToUlong( NtCurrentTeb()->Peb->ImageBaseAddress ),
|
||||
"wrong ImageBaseAddress %s / %p\n",
|
||||
wine_dbgstr_longlong(peb64->ImageBaseAddress), NtCurrentTeb()->Peb->ImageBaseAddress);
|
||||
ok( peb64->OSBuildNumber == NtCurrentTeb()->Peb->OSBuildNumber, "wrong OSBuildNumber %x / %x\n",
|
||||
peb64->OSBuildNumber, NtCurrentTeb()->Peb->OSBuildNumber );
|
||||
ok( peb64->OSPlatformId == NtCurrentTeb()->Peb->OSPlatformId, "wrong OSPlatformId %x / %x\n",
|
||||
peb64->OSPlatformId, NtCurrentTeb()->Peb->OSPlatformId );
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
ok( !NtCurrentTeb()->GdiBatchCount, "GdiBatchCount set to %x\n", NtCurrentTeb()->GdiBatchCount );
|
||||
ok( !NtCurrentTeb()->WowTebOffset, "WowTebOffset set to %x\n", NtCurrentTeb()->WowTebOffset );
|
||||
}
|
||||
|
||||
|
||||
START_TEST(info)
|
||||
{
|
||||
char **argv;
|
||||
|
@ -2693,6 +2734,7 @@ START_TEST(info)
|
|||
test_thread_lookup();
|
||||
|
||||
test_affinity();
|
||||
test_wow64();
|
||||
|
||||
/* belongs to its own file */
|
||||
test_readvirtualmemory();
|
||||
|
|
|
@ -1551,7 +1551,19 @@ size_t server_init_thread( void *entry_point, BOOL *suspend )
|
|||
}
|
||||
SERVER_END_REQ;
|
||||
|
||||
is_wow64 = !is_win64 && (server_cpus & ((1 << CPU_x86_64) | (1 << CPU_ARM64))) != 0;
|
||||
#ifndef _WIN64
|
||||
is_wow64 = (server_cpus & ((1 << CPU_x86_64) | (1 << CPU_ARM64))) != 0;
|
||||
if (is_wow64)
|
||||
{
|
||||
TEB64 *teb64 = (TEB64 *)((char *)NtCurrentTeb() - teb_offset);
|
||||
|
||||
NtCurrentTeb()->GdiBatchCount = PtrToUlong( teb64 );
|
||||
NtCurrentTeb()->WowTebOffset = -teb_offset;
|
||||
teb64->ClientId.UniqueProcess = PtrToUlong( NtCurrentTeb()->ClientId.UniqueProcess );
|
||||
teb64->ClientId.UniqueThread = PtrToUlong( NtCurrentTeb()->ClientId.UniqueThread );
|
||||
}
|
||||
#endif
|
||||
|
||||
ntdll_get_thread_data()->wow64_redir = is_wow64;
|
||||
|
||||
switch (ret)
|
||||
|
|
|
@ -540,7 +540,7 @@ static inline TEB *get_current_teb(void)
|
|||
{
|
||||
unsigned long esp;
|
||||
__asm__("movl %%esp,%0" : "=g" (esp) );
|
||||
return (TEB *)(esp & ~signal_stack_mask);
|
||||
return (TEB *)((esp & ~signal_stack_mask) + teb_offset);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1937,7 +1937,7 @@ static void ldt_set_fs( WORD sel, TEB *teb )
|
|||
struct modify_ldt_s ldt_info = { sel >> 3 };
|
||||
|
||||
ldt_info.base_addr = teb;
|
||||
ldt_info.limit = teb_size - 1;
|
||||
ldt_info.limit = page_size - 1;
|
||||
ldt_info.seg_32bit = 1;
|
||||
if (set_thread_area( &ldt_info ) < 0) perror( "set_thread_area" );
|
||||
#elif defined(__FreeBSD__) || defined (__FreeBSD_kernel__) || defined(__DragonFly__)
|
||||
|
@ -2052,7 +2052,7 @@ NTSTATUS signal_alloc_thread( TEB *teb )
|
|||
static int first_thread = 1;
|
||||
sigset_t sigset;
|
||||
int idx;
|
||||
LDT_ENTRY entry = ldt_make_entry( teb, teb_size - 1, LDT_FLAGS_DATA | LDT_FLAGS_32BIT );
|
||||
LDT_ENTRY entry = ldt_make_entry( teb, page_size - 1, LDT_FLAGS_DATA | LDT_FLAGS_32BIT );
|
||||
|
||||
if (first_thread) /* no locking for first thread */
|
||||
{
|
||||
|
|
|
@ -71,7 +71,17 @@ static inline struct ntdll_thread_data *ntdll_get_thread_data(void)
|
|||
return (struct ntdll_thread_data *)&NtCurrentTeb()->GdiTebBatch;
|
||||
}
|
||||
|
||||
static const UINT_PTR page_size = 0x1000;
|
||||
static const SIZE_T page_size = 0x1000;
|
||||
static const SIZE_T signal_stack_mask = 0xffff;
|
||||
#ifdef _WIN64
|
||||
static const SIZE_T teb_size = 0x2000;
|
||||
static const SIZE_T teb_offset = 0;
|
||||
static const SIZE_T signal_stack_size = 0x10000 - 0x2000;
|
||||
#else
|
||||
static const SIZE_T teb_size = 0x3000; /* TEB64 + TEB */
|
||||
static const SIZE_T teb_offset = 0x2000;
|
||||
static const SIZE_T signal_stack_size = 0x10000 - 0x3000;
|
||||
#endif
|
||||
|
||||
/* callbacks to PE ntdll from the Unix side */
|
||||
extern void (WINAPI *pDbgUiRemoteBreakin)( void *arg ) DECLSPEC_HIDDEN;
|
||||
|
@ -144,9 +154,6 @@ extern BOOL is_wow64 DECLSPEC_HIDDEN;
|
|||
extern HANDLE keyed_event DECLSPEC_HIDDEN;
|
||||
extern timeout_t server_start_time DECLSPEC_HIDDEN;
|
||||
extern sigset_t server_block_set DECLSPEC_HIDDEN;
|
||||
extern SIZE_T signal_stack_size DECLSPEC_HIDDEN;
|
||||
extern SIZE_T signal_stack_mask DECLSPEC_HIDDEN;
|
||||
static const SIZE_T teb_size = 0x1000 * sizeof(void *) / 4;
|
||||
extern struct _KUSER_SHARED_DATA *user_shared_data DECLSPEC_HIDDEN;
|
||||
#ifdef __i386__
|
||||
extern struct ldt_copy __wine_ldt_copy DECLSPEC_HIDDEN;
|
||||
|
@ -278,7 +285,7 @@ static inline IMAGE_NT_HEADERS *get_exe_nt_header(void)
|
|||
|
||||
static inline void *get_signal_stack(void)
|
||||
{
|
||||
return (char *)NtCurrentTeb() + teb_size;
|
||||
return (char *)NtCurrentTeb() + teb_size - teb_offset;
|
||||
}
|
||||
|
||||
static inline size_t ntdll_wcslen( const WCHAR *str )
|
||||
|
|
|
@ -154,12 +154,9 @@ static void *working_set_limit = (void *)0x7fff0000;
|
|||
|
||||
struct _KUSER_SHARED_DATA *user_shared_data = (void *)0x7ffe0000;
|
||||
|
||||
SIZE_T signal_stack_size = 0;
|
||||
SIZE_T signal_stack_mask = 0;
|
||||
|
||||
/* TEB allocation blocks */
|
||||
static TEB *teb_block;
|
||||
static TEB *next_free_teb;
|
||||
static void *teb_block;
|
||||
static void **next_free_teb;
|
||||
static int teb_block_pos;
|
||||
static struct list teb_list = LIST_INIT( teb_list );
|
||||
|
||||
|
@ -2361,7 +2358,7 @@ void virtual_init(void)
|
|||
const struct preload_info **preload_info = dlsym( RTLD_DEFAULT, "wine_main_preload_info" );
|
||||
const char *preload = getenv( "WINEPRELOADRESERVE" );
|
||||
struct alloc_virtual_heap alloc_views;
|
||||
size_t size, align;
|
||||
size_t size;
|
||||
int i;
|
||||
pthread_mutexattr_t attr;
|
||||
|
||||
|
@ -2389,13 +2386,6 @@ void virtual_init(void)
|
|||
}
|
||||
}
|
||||
|
||||
size = teb_size + max( MINSIGSTKSZ, 8192 );
|
||||
/* find the first power of two not smaller than size */
|
||||
align = page_shift;
|
||||
while ((1u << align) < size) align++;
|
||||
signal_stack_mask = (1 << align) - 1;
|
||||
signal_stack_size = (1 << align) - teb_size;
|
||||
|
||||
/* try to find space in a reserved area for the views and pages protection table */
|
||||
#ifdef _WIN64
|
||||
pages_vprot_size = ((size_t)address_space_limit >> page_shift >> pages_vprot_shift) + 1;
|
||||
|
@ -2566,6 +2556,19 @@ static void init_teb( TEB *teb, PEB *peb )
|
|||
{
|
||||
struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch;
|
||||
|
||||
#ifndef _WIN64
|
||||
TEB64 *teb64 = (TEB64 *)((char *)teb - teb_offset);
|
||||
|
||||
teb64->Peb = PtrToUlong( (char *)peb + page_size );
|
||||
teb64->Tib.Self = PtrToUlong( teb64 );
|
||||
teb64->Tib.ExceptionList = PtrToUlong( teb );
|
||||
teb64->ActivationContextStackPointer = PtrToUlong( &teb64->ActivationContextStack );
|
||||
teb64->ActivationContextStack.FrameListCache.Flink =
|
||||
teb64->ActivationContextStack.FrameListCache.Blink =
|
||||
PtrToUlong( &teb64->ActivationContextStack.FrameListCache );
|
||||
teb64->StaticUnicodeString.Buffer = PtrToUlong( teb64->StaticUnicodeBuffer );
|
||||
teb64->StaticUnicodeString.MaximumLength = sizeof( teb64->StaticUnicodeBuffer );
|
||||
#endif
|
||||
teb->Peb = peb;
|
||||
teb->Tib.Self = &teb->Tib;
|
||||
teb->Tib.ExceptionList = (void *)~0ul;
|
||||
|
@ -2589,10 +2592,11 @@ TEB *virtual_alloc_first_teb(void)
|
|||
{
|
||||
TEB *teb;
|
||||
PEB *peb;
|
||||
void *ptr;
|
||||
NTSTATUS status;
|
||||
SIZE_T data_size = page_size;
|
||||
SIZE_T peb_size = page_size;
|
||||
SIZE_T block_size = signal_stack_size + teb_size;
|
||||
SIZE_T peb_size = page_size * (is_win64 ? 1 : 2);
|
||||
SIZE_T block_size = signal_stack_mask + 1;
|
||||
SIZE_T total = 32 * block_size;
|
||||
|
||||
/* reserve space for shared user data */
|
||||
|
@ -2604,12 +2608,13 @@ TEB *virtual_alloc_first_teb(void)
|
|||
exit(1);
|
||||
}
|
||||
|
||||
NtAllocateVirtualMemory( NtCurrentProcess(), (void **)&teb_block, 0, &total,
|
||||
NtAllocateVirtualMemory( NtCurrentProcess(), &teb_block, 0, &total,
|
||||
MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE );
|
||||
teb_block_pos = 30;
|
||||
teb = (TEB *)((char *)teb_block + 30 * block_size);
|
||||
ptr = ((char *)teb_block + 30 * block_size);
|
||||
teb = (TEB *)((char *)ptr + teb_offset);
|
||||
peb = (PEB *)((char *)teb_block + 32 * block_size - peb_size);
|
||||
NtAllocateVirtualMemory( NtCurrentProcess(), (void **)&teb, 0, &block_size, MEM_COMMIT, PAGE_READWRITE );
|
||||
NtAllocateVirtualMemory( NtCurrentProcess(), (void **)&ptr, 0, &block_size, MEM_COMMIT, PAGE_READWRITE );
|
||||
NtAllocateVirtualMemory( NtCurrentProcess(), (void **)&peb, 0, &peb_size, MEM_COMMIT, PAGE_READWRITE );
|
||||
init_teb( teb, peb );
|
||||
*(ULONG_PTR *)peb->Reserved = get_image_address();
|
||||
|
@ -2623,46 +2628,46 @@ TEB *virtual_alloc_first_teb(void)
|
|||
NTSTATUS virtual_alloc_teb( TEB **ret_teb )
|
||||
{
|
||||
sigset_t sigset;
|
||||
TEB *teb = NULL;
|
||||
TEB *teb;
|
||||
void *ptr = NULL;
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
SIZE_T teb_size = signal_stack_mask + 1;
|
||||
SIZE_T block_size = signal_stack_mask + 1;
|
||||
|
||||
server_enter_uninterrupted_section( &virtual_mutex, &sigset );
|
||||
if (next_free_teb)
|
||||
{
|
||||
teb = next_free_teb;
|
||||
next_free_teb = *(TEB **)teb;
|
||||
memset( teb, 0, sizeof(*teb) );
|
||||
ptr = next_free_teb;
|
||||
next_free_teb = *(void **)ptr;
|
||||
memset( ptr, 0, teb_size );
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!teb_block_pos)
|
||||
{
|
||||
void *addr = NULL;
|
||||
SIZE_T total = 32 * teb_size;
|
||||
SIZE_T total = 32 * block_size;
|
||||
|
||||
if ((status = NtAllocateVirtualMemory( NtCurrentProcess(), &addr, 0, &total,
|
||||
if ((status = NtAllocateVirtualMemory( NtCurrentProcess(), &ptr, 0, &total,
|
||||
MEM_RESERVE, PAGE_READWRITE )))
|
||||
{
|
||||
server_leave_uninterrupted_section( &virtual_mutex, &sigset );
|
||||
return status;
|
||||
}
|
||||
teb_block = addr;
|
||||
teb_block = ptr;
|
||||
teb_block_pos = 32;
|
||||
}
|
||||
teb = (TEB *)((char *)teb_block + --teb_block_pos * teb_size);
|
||||
NtAllocateVirtualMemory( NtCurrentProcess(), (void **)&teb, 0, &teb_size,
|
||||
ptr = ((char *)teb_block + --teb_block_pos * block_size);
|
||||
NtAllocateVirtualMemory( NtCurrentProcess(), (void **)&ptr, 0, &block_size,
|
||||
MEM_COMMIT, PAGE_READWRITE );
|
||||
}
|
||||
*ret_teb = teb = (TEB *)((char *)ptr + teb_offset);
|
||||
init_teb( teb, NtCurrentTeb()->Peb );
|
||||
*ret_teb = teb;
|
||||
server_leave_uninterrupted_section( &virtual_mutex, &sigset );
|
||||
|
||||
if ((status = signal_alloc_thread( teb )))
|
||||
{
|
||||
server_enter_uninterrupted_section( &virtual_mutex, &sigset );
|
||||
*(TEB **)teb = next_free_teb;
|
||||
next_free_teb = teb;
|
||||
*(void **)ptr = next_free_teb;
|
||||
next_free_teb = ptr;
|
||||
server_leave_uninterrupted_section( &virtual_mutex, &sigset );
|
||||
}
|
||||
return status;
|
||||
|
@ -2675,6 +2680,7 @@ NTSTATUS virtual_alloc_teb( TEB **ret_teb )
|
|||
void virtual_free_teb( TEB *teb )
|
||||
{
|
||||
struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch;
|
||||
void *ptr;
|
||||
SIZE_T size;
|
||||
sigset_t sigset;
|
||||
|
||||
|
@ -2692,8 +2698,9 @@ void virtual_free_teb( TEB *teb )
|
|||
|
||||
server_enter_uninterrupted_section( &virtual_mutex, &sigset );
|
||||
list_remove( &thread_data->entry );
|
||||
*(TEB **)teb = next_free_teb;
|
||||
next_free_teb = teb;
|
||||
ptr = (char *)teb - teb_offset;
|
||||
*(void **)ptr = next_free_teb;
|
||||
next_free_teb = ptr;
|
||||
server_leave_uninterrupted_section( &virtual_mutex, &sigset );
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue