Drop wow64_has_secondary_stack flag

This commit is contained in:
Corinna Vinschen 2015-12-15 15:48:44 +01:00
parent 105f79b489
commit bd4339e2a2
7 changed files with 4 additions and 297 deletions

View File

@ -395,7 +395,6 @@ DLL_OFILES:= \
wincap.o \
window.o \
winf.o \
wow64.o \
xsique.o \
$(EXTRA_OFILES) \
$(MALLOC_OFILES) \

View File

@ -35,7 +35,6 @@ details. */
#include "cygxdr.h"
#include "fenv.h"
#include "ntdll.h"
#include "wow64.h"
#define MAX_AT_FILE_LEVEL 10
@ -406,18 +405,8 @@ child_info NO_COPY *child_proc_info;
void
child_info_fork::alloc_stack ()
{
/* Make sure not to try a hard allocation if we have been forked off from
the main thread of a Cygwin process which has been started from a 64 bit
parent. In that case the StackBase of the forked child is not the same
as the StackBase of the parent (== this.stackbase), but only because the
stack of the parent has been slightly rearranged. See comment in
wow64_revert_to_original_stack for details. We check here if the
parent stack fits into the child stack. */
PTEB teb = NtCurrentTeb ();
if (teb->Tib.StackBase != stackbase
&& (!wincap.is_wow64 ()
|| stacklimit < teb->DeallocationStack
|| stackbase > teb->Tib.StackBase))
if (teb->Tib.StackBase != stackbase)
{
void *stack_ptr;
size_t stacksize;
@ -772,14 +761,6 @@ dll_crt0_0 ()
{
setup_cygheap ();
memory_init ();
#ifndef __x86_64__
/* WOW64 process on XP/64 or Server 2003/64? Check if we have been
started from 64 bit process and if our stack is at an unusual
address. Set wow64_needs_stack_adjustment if so. Problem
description in wow64_test_for_64bit_parent. */
if (wincap.wow64_has_secondary_stack ())
wow64_needs_stack_adjustment = wow64_test_for_64bit_parent ();
#endif /* !__x86_64__ */
}
else
{
@ -1091,32 +1072,6 @@ _dll_crt0 ()
fork_info->alloc_stack ();
}
#else
/* Handle WOW64 process on XP/2K3 which has been started from native 64 bit
process. See comment in wow64_test_for_64bit_parent for a full problem
description. */
if (wow64_needs_stack_adjustment && !dynamically_loaded)
{
/* Must be static since it's referenced after the stack and frame
pointer registers have been changed. */
static PVOID allocationbase;
PVOID stackaddr = wow64_revert_to_original_stack (allocationbase);
if (stackaddr)
{
/* Set stack pointer to new address. Set frame pointer to 0. */
__asm__ ("\n\
movl %[ADDR], %%esp \n\
xorl %%ebp, %%ebp \n"
: : [ADDR] "r" (stackaddr));
/* We're back on the original stack now. Free up space taken by the
former main thread stack and set DeallocationStack correctly. */
VirtualFree (NtCurrentTeb ()->DeallocationStack, 0, MEM_RELEASE);
NtCurrentTeb ()->DeallocationStack = allocationbase;
}
else
/* Fall back to respawning if creating a new stack fails. */
wow64_respawn_process ();
}
main_environ = user_data->envptr;
if (in_forkee)
fork_info->alloc_stack ();

View File

@ -54,11 +54,6 @@ munge_threadfunc ()
{
char *threadfunc = NULL;
/* This call to NtQueryInformationThread crashes under WOW64 on
64 bit XP and Server 2003. */
if (wincap.wow64_has_secondary_stack ())
threadfunc = ebp[threadfunc_ix[0]];
else
NtQueryInformationThread (NtCurrentThread (),
ThreadQuerySetWin32StartAddress,
&threadfunc, sizeof threadfunc, NULL);

View File

@ -25,7 +25,6 @@ wincaps wincap_xpsp2 __attribute__((section (".cygwin_dll_common"), shared)) = {
has_gaa_largeaddress_bug:false,
has_broken_alloc_console:false,
has_console_logon_sid:false,
wow64_has_secondary_stack:false,
has_program_compatibility_assistant:false,
has_pipe_reject_remote_clients:false,
terminate_thread_frees_stack:false,
@ -47,7 +46,6 @@ wincaps wincap_2003 __attribute__((section (".cygwin_dll_common"), shared)) = {
has_gaa_largeaddress_bug:false,
has_broken_alloc_console:false,
has_console_logon_sid:false,
wow64_has_secondary_stack:true,
has_program_compatibility_assistant:false,
has_pipe_reject_remote_clients:false,
terminate_thread_frees_stack:false,
@ -69,7 +67,6 @@ wincaps wincap_vista __attribute__((section (".cygwin_dll_common"), shared)) = {
has_gaa_largeaddress_bug:true,
has_broken_alloc_console:false,
has_console_logon_sid:false,
wow64_has_secondary_stack:false,
has_program_compatibility_assistant:true,
has_pipe_reject_remote_clients:true,
terminate_thread_frees_stack:true,
@ -91,7 +88,6 @@ wincaps wincap_7 __attribute__((section (".cygwin_dll_common"), shared)) = {
has_gaa_largeaddress_bug:true,
has_broken_alloc_console:true,
has_console_logon_sid:true,
wow64_has_secondary_stack:false,
has_program_compatibility_assistant:true,
has_pipe_reject_remote_clients:true,
terminate_thread_frees_stack:true,
@ -113,7 +109,6 @@ wincaps wincap_8 __attribute__((section (".cygwin_dll_common"), shared)) = {
has_gaa_largeaddress_bug:false,
has_broken_alloc_console:true,
has_console_logon_sid:true,
wow64_has_secondary_stack:false,
has_program_compatibility_assistant:true,
has_pipe_reject_remote_clients:true,
terminate_thread_frees_stack:true,
@ -135,7 +130,6 @@ wincaps wincap_10 __attribute__((section (".cygwin_dll_common"), shared)) = {
has_gaa_largeaddress_bug:false,
has_broken_alloc_console:true,
has_console_logon_sid:true,
wow64_has_secondary_stack:false,
has_program_compatibility_assistant:true,
has_pipe_reject_remote_clients:true,
terminate_thread_frees_stack:true,
@ -157,7 +151,6 @@ wincaps wincap_10_1511 __attribute__((section (".cygwin_dll_common"), shared)) =
has_gaa_largeaddress_bug:false,
has_broken_alloc_console:true,
has_console_logon_sid:true,
wow64_has_secondary_stack:false,
has_program_compatibility_assistant:true,
has_pipe_reject_remote_clients:true,
terminate_thread_frees_stack:true,
@ -248,7 +241,6 @@ wincapc::init ()
#endif
{
((wincaps *)caps)->needs_count_in_si_lpres2 = false;
((wincaps *)caps)->wow64_has_secondary_stack = false;
((wincaps *)caps)->has_gaa_largeaddress_bug = false;
((wincaps *)caps)->has_broken_prefetchvm = false;
}

View File

@ -18,7 +18,6 @@ struct wincaps
unsigned has_gaa_largeaddress_bug : 1;
unsigned has_broken_alloc_console : 1;
unsigned has_console_logon_sid : 1;
unsigned wow64_has_secondary_stack : 1;
unsigned has_program_compatibility_assistant : 1;
unsigned has_pipe_reject_remote_clients : 1;
unsigned terminate_thread_frees_stack : 1;
@ -65,7 +64,6 @@ public:
bool IMPLEMENT (has_gaa_largeaddress_bug)
bool IMPLEMENT (has_broken_alloc_console)
bool IMPLEMENT (has_console_logon_sid)
bool IMPLEMENT (wow64_has_secondary_stack)
bool IMPLEMENT (has_program_compatibility_assistant)
bool IMPLEMENT (has_pipe_reject_remote_clients)
bool IMPLEMENT (terminate_thread_frees_stack)

View File

@ -1,213 +0,0 @@
/* wow64.cc
This file is part of Cygwin.
This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#ifndef __x86_64__
/* WOW64 only plays a role in the 32 bit version. Don't use any of this
in the 64 bit version. */
#include "winsup.h"
#include "cygtls.h"
#include "ntdll.h"
#include <sys/param.h>
#define PTR_ADD(p,o) ((PVOID)((PBYTE)(p)+(o)))
bool NO_COPY wow64_needs_stack_adjustment = false;
static void
wow64_eval_expected_main_stack (PVOID &allocbase, PVOID &stackbase)
{
PIMAGE_DOS_HEADER dosheader;
PIMAGE_NT_HEADERS ntheader;
SIZE_T size;
dosheader = (PIMAGE_DOS_HEADER) GetModuleHandle (NULL);
ntheader = (PIMAGE_NT_HEADERS) ((PBYTE) dosheader + dosheader->e_lfanew);
/* The main thread stack is expected to be located at 0x30000, which is the
case for all observed NT systems up to Server 2003 R2, unless the
stacksize requested by the StackReserve field in the PE/COFF header is
so big that the stack doesn't fit in the area between 0x30000 and the
start of the image. In case of a conflict, the OS allocates the stack
right after the image.
Sidenote: While post-2K3 32 bit systems continue to have the default
main thread stack address located at 0x30000, the default main thread
stack address on Vista/2008 64 bit is 0x80000 and on W7/2K8R2 64 bit
it is 0x90000. However, this is no problem because the system sticks
to that address for all WOW64 processes, not only for the first one
started from a 64 bit parent. */
allocbase = (PVOID) 0x30000;
/* Stack size. The OS always rounds the size up to allocation granularity
and it never allocates less than 256K. */
size = roundup2 (ntheader->OptionalHeader.SizeOfStackReserve,
wincap.allocation_granularity ());
if (size < 256 * 1024)
size = 256 * 1024;
/* If the stack doesn't fit in the area before the image, it's allocated
right after the image, rounded up to allocation granularity boundary. */
if (PTR_ADD (allocbase, size) > (PVOID) ntheader->OptionalHeader.ImageBase)
allocbase = PTR_ADD (ntheader->OptionalHeader.ImageBase,
ntheader->OptionalHeader.SizeOfImage);
allocbase = (PVOID) roundup2 ((uintptr_t) allocbase,
wincap.allocation_granularity ());
stackbase = PTR_ADD (allocbase, size);
debug_printf ("expected allocbase: %p, stackbase: %p", allocbase, stackbase);
}
bool
wow64_test_for_64bit_parent ()
{
/* On Windows XP 64 and 2003 64 there's a problem with processes running
under WOW64. The first process started from a 64 bit process has its
main thread stack not where it should be. Rather, it uses another
stack while the original stack is used for other purposes.
The problem is, the child has its stack in the usual spot again, thus
we have to "alloc_stack_hard_way". However, this fails in almost all
cases because the stack slot of the parent process is taken by something
else in the child process.
What we do here is to check if the current stack is the expected main
thread stack and if not, if we really have been started from a 64 bit
process here. If so, we note this fact in wow64_needs_stack_adjustment
so we can workaround the stack problem in _dll_crt0. See there for how
we go along. */
NTSTATUS ret;
PROCESS_BASIC_INFORMATION pbi;
HANDLE parent;
PVOID allocbase, stackbase;
ULONG_PTR wow64 = TRUE; /* Opt on the safe side. */
/* First check if the current stack is where it belongs. If so, we don't
have to do anything special. This is the case on Vista and later. */
wow64_eval_expected_main_stack (allocbase, stackbase);
if (&wow64 >= (PULONG_PTR) allocbase && &wow64 < (PULONG_PTR) stackbase)
return false;
/* Check if the parent is a native 64 bit process. Unfortunately there's
no simpler way to retrieve the parent process in NT, as far as I know.
Hints welcome. */
ret = NtQueryInformationProcess (NtCurrentProcess (),
ProcessBasicInformation,
&pbi, sizeof pbi, NULL);
if (NT_SUCCESS (ret)
&& (parent = OpenProcess (PROCESS_QUERY_INFORMATION,
FALSE,
(DWORD) pbi.InheritedFromUniqueProcessId)))
{
NtQueryInformationProcess (parent, ProcessWow64Information,
&wow64, sizeof wow64, NULL);
CloseHandle (parent);
}
return !wow64;
}
PVOID
wow64_revert_to_original_stack (PVOID &allocationbase)
{
/* Test if the original stack exists and has been set up as usual. Even
though the stack of the WOW64 process is at an unusual address, it appears
that the "normal" stack has been created as usual. It's partially in use
by the 32->64 bit transition layer of the OS to help along the WOW64
process, but it's otherwise mostly unused. */
MEMORY_BASIC_INFORMATION mbi;
PVOID stackbase;
wow64_eval_expected_main_stack (allocationbase, stackbase);
/* The stack is allocated in a single call, so the entire stack has the
same AllocationBase. At the start we expect a reserved region big
enough still to host as the main stack. The OS apparently reserves
always at least 256K for the main thread stack. We err on the side
of caution so we test here for a reserved region of at least 256K.
That should be enough (knock on wood). */
VirtualQuery (allocationbase, &mbi, sizeof mbi);
if (mbi.State != MEM_RESERVE || mbi.RegionSize < 256 * 1024)
return NULL;
/* Next we expect a guard page. We fetch the size of the guard area to
see how big it is. Apparently the guard area on 64 bit systems spans
2 pages, only for the main thread for some reason. We better keep it
that way. */
PVOID addr = PTR_ADD (mbi.BaseAddress, mbi.RegionSize);
VirtualQuery (addr, &mbi, sizeof mbi);
if (mbi.AllocationBase != allocationbase
|| mbi.State != MEM_COMMIT
|| !(mbi.Protect & PAGE_GUARD))
return NULL;
PVOID guardaddr = mbi.BaseAddress;
SIZE_T guardsize = mbi.RegionSize;
/* Next we expect a committed R/W region, the in-use area of that stack.
This is just a sanity check. */
addr = PTR_ADD (mbi.BaseAddress, mbi.RegionSize);
VirtualQuery (addr, &mbi, sizeof mbi);
if (mbi.AllocationBase != allocationbase
|| PTR_ADD (mbi.BaseAddress, mbi.RegionSize) != stackbase
|| mbi.State != MEM_COMMIT
|| mbi.Protect != PAGE_READWRITE)
return NULL;
/* The original stack is used by the OS. Leave enough space for the OS
to be happy (another 64K) and constitute a second stack within the so
far reserved stack area. */
PVOID newbase = PTR_ADD (guardaddr, -wincap.allocation_granularity ());
PVOID newtop = PTR_ADD (newbase, -wincap.allocation_granularity ());
guardaddr = PTR_ADD (newtop, -guardsize);
if (!VirtualAlloc (newtop, wincap.allocation_granularity (),
MEM_COMMIT, PAGE_READWRITE))
return NULL;
if (!VirtualAlloc (guardaddr, guardsize, MEM_COMMIT,
PAGE_READWRITE | PAGE_GUARD))
return NULL;
/* We're going to reuse the original stack. Yay, no more respawn!
Set the StackBase and StackLimit values in the TEB, set _main_tls
accordingly, and return the new, 16 byte aligned address for the
stack pointer. The second half of the stack move is done by the
caller _dll_crt0. */
NtCurrentTeb ()->Tib.StackBase = (char *) newbase;
NtCurrentTeb ()->Tib.StackLimit = (char *) newtop;
_main_tls = &_my_tls;
return PTR_ADD (NtCurrentTeb ()->Tib.StackBase, -16);
}
/* Respawn WOW64 process. This is only called if we can't reuse the original
stack. See comment in wow64_revert_to_original_stack for details. See
_dll_crt0 for the call of this function.
Historical note:
Originally we just always respawned, right from dll_entry. This stopped
working with Cygwin 1.7.10 on Windows 2003 R2 64. Starting with Cygwin
1.7.10 we don't link against advapi32.dll anymore. However, any process
linked against advapi32, directly or indirectly, failed to respawn when
trying respawning during DLL_PROCESS_ATTACH initialization. In that
case CreateProcessW returns with ERROR_ACCESS_DENIED for some reason. */
void
wow64_respawn_process ()
{
PROCESS_INFORMATION pi;
STARTUPINFOW si;
DWORD ret = 0;
GetStartupInfoW (&si);
if (!CreateProcessW (global_progname, GetCommandLineW (), NULL, NULL, TRUE,
CREATE_DEFAULT_ERROR_MODE
| GetPriorityClass (GetCurrentProcess ()),
NULL, NULL, &si, &pi))
api_fatal ("Failed to create process <%W> <%W>, %E",
global_progname, GetCommandLineW ());
CloseHandle (pi.hThread);
if (WaitForSingleObject (pi.hProcess, INFINITE) == WAIT_FAILED)
api_fatal ("Waiting for process %u failed, %E", pi.dwProcessId);
GetExitCodeProcess (pi.hProcess, &ret);
CloseHandle (pi.hProcess);
TerminateProcess (GetCurrentProcess (), ret);
ExitProcess (ret);
}
#endif /* !__x86_64__ */

View File

@ -1,19 +0,0 @@
/* wow64.h
This file is part of Cygwin.
This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#ifndef __x86_64__
/* WOW64 only plays a role in the 32 bit version. Don't use any of this
in the 64 bit version. */
extern bool NO_COPY wow64_needs_stack_adjustment;
extern bool wow64_test_for_64bit_parent ();
extern PVOID wow64_revert_to_original_stack (PVOID &allocationbase);
extern void wow64_respawn_process () __attribute__ ((noreturn));
#endif /* !__x86_64__ */