+2015-12-03 Corinna Vinschen <corinna@vinschen.de>
+
+ * dcrt0.cc (dll_crt0_0): On 64 bit, set wow64_needs_stack_adjustment
+ if not started from a 64 bit process.
+ (_dll_crt0): Enable wow64_needs_stack_adjustment branch on 64 bit
+ as well. Remove 64 bit only code. Introduce CREATE_STACK and
+ FIX_STACK macros to conditionalize the code. Rearrange and
+ partially rewrite comments.
+ * wincap.h (wincaps::has_3264_stack_broken): New element.
+ * wincap.cc: Implement above element throughout.
+ (wincapc::init): Set has_3264_stack_broken to false on 32 bit.
+ * wow64.cc: Enable functionality on 64 bit architecture, except for
+ wow64_revert_to_original_stack. Enhance comments to explain.
+ (wow64_eval_expected_main_stack): Make 64 bit clean.
+ (wow64_test_for_64bit_parent): Ditto.
+ * wow64.h: Export wow64_revert_to_original_stack on 32 bit only,
+ everything else on all architectures.
+
2015-12-03 Corinna Vinschen <corinna@vinschen.de>
* fhandler_process.cc (thread_info::thread_info): Accommodate the fact
description in wow64_test_for_64bit_parent. */
if (wincap.wow64_has_secondary_stack ())
wow64_needs_stack_adjustment = wow64_test_for_64bit_parent ();
+#else
+ /* Windows 10 1511 has a stack move when a 64 bit process is started from
+ a 32 bit process, just as it was vice versa in XP/2003. */
+ if (wincap.has_3264_stack_broken ())
+ wow64_needs_stack_adjustment = !wow64_test_for_64bit_parent ();
#endif /* !__x86_64__ */
}
else
extern "C" void __stdcall
_dll_crt0 ()
{
-#ifndef __x86_64__
+#ifdef __x86_64__
+ /* Handle 64 bit process on Windows 10 rel 1511 which has been started from
+ 32 bit WOW64 process. See comment in wow64_test_for_64bit_parent for a
+ problem description. Unfortunately the areas the stacks would have to
+ be moved to are both taken by "something else"(tm) in both, forker and
+ forkee, so we can't use the wow64_revert_to_original_stack method as in
+ the 32 bit case. Rather, we move the main thread stack to the stack area
+ reserved for pthread stacks for this process. */
+#define CREATE_STACK(a) create_new_main_thread_stack(a)
+#define FIX_STACK(s) __asm__ ("\n" \
+ "movq %[ADDR], %%rsp \n" \
+ "movq %%rsp, %%rbp \n" \
+ : : [ADDR] "r" (s))
+#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. */
+#define CREATE_STACK(a) wow64_revert_to_original_stack(a)
+#define FIX_STACK(s) __asm__ ("\n" \
+ "movl %[ADDR], %%esp \n" \
+ "xorl %%ebp, %%ebp \n" \
+ : : [ADDR] "r" (s))
+#endif
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 = 0;
+ static PVOID allocationbase;
- /* Check if we just move the stack. If so, wow64_revert_to_original_stack
- returns a non-NULL, 16 byte aligned address. See comments in
- wow64_revert_to_original_stack for the gory details. */
- PVOID stackaddr = wow64_revert_to_original_stack (allocationbase);
+ PVOID stackaddr = CREATE_STACK (allocationbase);
if (stackaddr)
{
/* 2nd half of the stack move. Set stack pointer to new address.
Set frame pointer to 0. */
- __asm__ ("\n\
- movl %[ADDR], %%esp \n\
- xorl %%ebp, %%ebp \n"
- : : [ADDR] "r" (stackaddr));
+ FIX_STACK (stackaddr);
/* Now we're back on the original stack. 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 respawn if wow64_revert_to_original_stack fails. */
+ /* Fall back to respawning if creating a new stack fails. */
wow64_respawn_process ();
}
-#else
- /* Starting with Windows 10 rel 1511, the main stack of an application is
- not reproducible if a 64 bit process has been started from a 32 bit
- process. Given that we have enough virtual address space on 64 bit
- anyway, we now move the main thread stack to the stack area reserved for
- pthread stacks. This allows a reproducible stack space under our own
- control and avoids collision with the OS. */
- if (!in_forkee && !dynamically_loaded)
- {
- /* Must be static since it's referenced after the stack and frame
- pointer registers have been changed. */
- static PVOID allocationbase;
-
- PVOID stackaddr = create_new_main_thread_stack (allocationbase);
- if (stackaddr)
- {
- /* 2nd half of the stack move. Set stack pointer to new address.
- Don't set frame pointer to 0 since x86_64 uses the stack while
- evaluating NtCurrentTeb (). */
- __asm__ ("\n\
- movq %[ADDR], %%rsp \n\
- movq %%rsp, %%rbp \n"
- : : [ADDR] "r" (stackaddr));
- /* Now we're back on the new stack. Free up space taken by the
- former main thread stack and set DeallocationStack correctly. */
- VirtualFree (NtCurrentTeb ()->DeallocationStack, 0, MEM_RELEASE);
- NtCurrentTeb ()->DeallocationStack = allocationbase;
- }
- }
-#endif /* !__x86_64__ */
_feinitialise ();
#ifndef __x86_64__
main_environ = user_data->envptr;
has_processor_groups:false,
has_broken_prefetchvm:false,
has_new_pebteb_region:false,
+ has_3264_stack_broken:false,
};
wincaps wincap_2003 __attribute__((section (".cygwin_dll_common"), shared)) = {
has_processor_groups:false,
has_broken_prefetchvm:false,
has_new_pebteb_region:false,
+ has_3264_stack_broken:false,
};
wincaps wincap_vista __attribute__((section (".cygwin_dll_common"), shared)) = {
has_processor_groups:false,
has_broken_prefetchvm:false,
has_new_pebteb_region:false,
+ has_3264_stack_broken:false,
};
wincaps wincap_7 __attribute__((section (".cygwin_dll_common"), shared)) = {
has_processor_groups:true,
has_broken_prefetchvm:false,
has_new_pebteb_region:false,
+ has_3264_stack_broken:false,
};
wincaps wincap_8 __attribute__((section (".cygwin_dll_common"), shared)) = {
has_processor_groups:true,
has_broken_prefetchvm:false,
has_new_pebteb_region:false,
+ has_3264_stack_broken:false,
};
wincaps wincap_10 __attribute__((section (".cygwin_dll_common"), shared)) = {
has_processor_groups:true,
has_broken_prefetchvm:true,
has_new_pebteb_region:false,
+ has_3264_stack_broken:false,
};
wincaps wincap_10_1511 __attribute__((section (".cygwin_dll_common"), shared)) = {
has_processor_groups:true,
has_broken_prefetchvm:false,
has_new_pebteb_region:true,
+ has_3264_stack_broken:true,
};
wincapc wincap __attribute__((section (".cygwin_dll_common"), shared));
target process on 64 bit XP/2003 in native 64 bit mode only. Reset the
flag here for 32 bit. */
((wincaps *)caps)->has_broken_rtl_query_process_debug_information = false;
+ /* Windows 10 1511 has a stack move when a 64 bit process is started from
+ a 32 bit process, just as it was vice versa in XP/2003. Reset the flag
+ here for 32 bit. */
+ ((wincaps *)caps)->has_3264_stack_broken = false;
if (NT_SUCCESS (NtQueryInformationProcess (NtCurrentProcess (),
ProcessWow64Information,
&wow64, sizeof wow64, NULL))
unsigned has_processor_groups : 1;
unsigned has_broken_prefetchvm : 1;
unsigned has_new_pebteb_region : 1;
+ unsigned has_3264_stack_broken : 1;
};
class wincapc
bool IMPLEMENT (has_processor_groups)
bool IMPLEMENT (has_broken_prefetchvm)
bool IMPLEMENT (has_new_pebteb_region)
+ bool IMPLEMENT (has_3264_stack_broken)
#undef IMPLEMENT
};
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"
wow64_eval_expected_main_stack (PVOID &allocbase, PVOID &stackbase)
{
PIMAGE_DOS_HEADER dosheader;
- PIMAGE_NT_HEADERS32 ntheader;
- DWORD size;
+ PIMAGE_NT_HEADERS ntheader;
+ SIZE_T size;
dosheader = (PIMAGE_DOS_HEADER) GetModuleHandle (NULL);
- ntheader = (PIMAGE_NT_HEADERS32) ((PBYTE) dosheader + dosheader->e_lfanew);
+ 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
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. */
+ started from a 64 bit parent.
+
+ On 64 bit W10 1511 the stack starts at 0x400000 by default. See comment
+ in wow64_test_for_64bit_parent. */
+#ifdef __x86_64__
+ allocbase = (PVOID) 0x400000;
+#else
allocbase = (PVOID) 0x30000;
+#endif
/* Stack size. The OS always rounds the size up to allocation granularity
and it never allocates less than 256K. */
size = roundup2 (ntheader->OptionalHeader.SizeOfStackReserve,
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 excpected main
+ 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. */
+
+ /* Amazing but true: Starting with Windows 10 1511 this problem has been
+ reintroduced, just in the opposite direction: If a 64 bit process is
+ created from a 32 bit WOW64 process, the main thread stack in the 64
+ bit child gets moved to another location than the default. In the
+ forked child, the stack is back where it usually is when started from
+ another 64 bit process. Therefore we have to be able to recognize
+ this scenarion now on 64 bit as well. We I don't believe it... */
NTSTATUS ret;
PROCESS_BASIC_INFORMATION pbi;
HANDLE parent;
/* 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) allocbase && &wow64 < (PULONG) 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
return !wow64;
}
+#ifndef __x86_64__
+
PVOID
wow64_revert_to_original_stack (PVOID &allocationbase)
{
return PTR_ADD (NtCurrentTeb()->Tib.StackBase, -16);
}
+#endif /* !__x86_64__ */
+
/* 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.
TerminateProcess (GetCurrentProcess (), ret);
ExitProcess (ret);
}
-
-#endif /* !__x86_64__ */
/* wow64.h
- Copyright 2011, 2012 Red Hat, Inc.
+ Copyright 2011, 2012, 2015 Red Hat, Inc.
This file is part of Cygwin.
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));
+#ifndef __x86_64__
+
+extern PVOID wow64_revert_to_original_stack (PVOID &allocationbase);
+
#endif /* !__x86_64__ */