Drop wow64_has_secondary_stack flag
This commit is contained in:
parent
105f79b489
commit
bd4339e2a2
|
@ -395,7 +395,6 @@ DLL_OFILES:= \
|
|||
wincap.o \
|
||||
window.o \
|
||||
winf.o \
|
||||
wow64.o \
|
||||
xsique.o \
|
||||
$(EXTRA_OFILES) \
|
||||
$(MALLOC_OFILES) \
|
||||
|
|
|
@ -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 ();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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__ */
|
|
@ -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__ */
|
Loading…
Reference in New Issue