#include "cygxdr.h"
#include "fenv.h"
#include "ntdll.h"
+#include "wow64.h"
#define MAX_AT_FILE_LEVEL 10
child_info NO_COPY *child_proc_info = NULL;
-#define CYGWIN_GUARD (PAGE_EXECUTE_READWRITE | PAGE_GUARD)
+#define CYGWIN_GUARD (PAGE_READWRITE | PAGE_GUARD)
void
child_info_fork::alloc_stack_hard_way (volatile char *b)
api_fatal ("fork: can't reserve memory for stack %p - %p, %E",
stackaddr, stackbottom);
stacksize = (char *) stackbottom - (char *) stacktop;
- stack_ptr = VirtualAlloc (stacktop, stacksize, MEM_COMMIT,
- PAGE_EXECUTE_READWRITE);
+ stack_ptr = VirtualAlloc (stacktop, stacksize, MEM_COMMIT, PAGE_READWRITE);
if (!stack_ptr)
abort ("can't commit memory for stack %p(%d), %E", stacktop, stacksize);
if (guardsize != (size_t) -1)
{
volatile char * volatile esp;
__asm__ volatile ("movl %%esp,%0": "=r" (esp));
- if (_tlsbase != stackbottom)
+ /* 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 _tlsbase of the forked child is not the same
+ as the _tlsbase of the parent (== stackbottom), 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. */
+ if (_tlsbase != stackbottom
+ && (!wincap.is_wow64 ()
+ || stacktop < (char *) NtCurrentTeb ()->DeallocationStack
+ || stackbottom > _tlsbase))
alloc_stack_hard_way (esp);
else
{
while (_tlstop >= st)
esp = getstack (esp);
stackaddr = 0;
+ /* This only affects forked children of a process started from a native
+ 64 bit process, but it doesn't hurt to do it unconditionally. Fix
+ StackBase in the child to be the same as in the parent, so that the
+ computation of _my_tls is correct. */
+ _tlsbase = (char *) stackbottom;
}
}
static void
init_windows_system_directory ()
{
- windows_system_directory_length =
- GetSystemDirectoryW (windows_system_directory, MAX_PATH);
- if (windows_system_directory_length == 0)
- api_fatal ("can't find windows system directory");
- windows_system_directory[windows_system_directory_length++] = L'\\';
- windows_system_directory[windows_system_directory_length] = L'\0';
+ if (!windows_system_directory_length)
+ {
+ windows_system_directory_length =
+ GetSystemDirectoryW (windows_system_directory, MAX_PATH);
+ if (windows_system_directory_length == 0)
+ api_fatal ("can't find windows system directory");
+ windows_system_directory[windows_system_directory_length++] = L'\\';
+ windows_system_directory[windows_system_directory_length] = L'\0';
+
+ system_wow64_directory_length =
+ GetSystemWow64DirectoryW (system_wow64_directory, MAX_PATH);
+ if (system_wow64_directory_length)
+ {
+ system_wow64_directory[system_wow64_directory_length++] = L'\\';
+ system_wow64_directory[system_wow64_directory_length] = L'\0';
+ }
+ }
}
void
cygthread::init ();
if (!child_proc_info)
- memory_init (true);
+ {
+ memory_init (true);
+ /* WOW64 process? Check if we have been started from 64 bit process
+ and if our stack is at an unusual address. Set wow64_has_64bit_parent
+ if so. Problem description in wow64_test_for_64bit_parent. */
+ if (wincap.is_wow64 ())
+ wow64_has_64bit_parent = wow64_test_for_64bit_parent ();
+ }
else
{
cygwin_user_h = child_proc_info->user_h;
extern "C" void __stdcall
_dll_crt0 ()
{
+ /* Handle WOW64 process started from native 64 bit process. See comment
+ in wow64_test_for_64bit_parent for a full problem description. */
+ if (wow64_has_64bit_parent && !dynamically_loaded)
+ {
+ /* Must be static since it's referenced after the stack pointers have
+ been moved. */
+ static PVOID allocationbase = 0;
+
+ /* Check if we just move the stack. See comment in
+ wow64_revert_to_original_stack for the gory details. */
+ PVOID stackaddr = wow64_revert_to_original_stack (allocationbase);
+ if (stackaddr)
+ {
+ /* 2nd half of the stack move. Set stack pointers to new address. */
+ __asm__ ("\n\
+ movl %[ADDR], %%esp \n\
+ movl %%esp, %%ebp \n"
+ : : [ADDR] "r" (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. */
+ wow64_respawn_process ();
+ }
#ifdef __i386__
_feinitialise ();
#endif