Always move 64 bit main thread stack to defined pthread stack area

x86_64 only:
        * dcrt0.cc (_dll_crt0): Always move stack to pthread stack area.
        Explain why.
        * miscfuncs.cc (create_new_main_thread_stack): New function to create
        OS-like stack for main thread in pthread stack area.
        * miscfuncs.cc (create_new_main_thread_stack): Declare.

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
Corinna Vinschen 2015-12-03 13:02:55 +01:00
parent 81e6c7515d
commit 8a14e51901
4 changed files with 83 additions and 0 deletions

View File

@ -1,3 +1,12 @@
2015-12-03 Corinna Vinschen <corinna@vinschen.de>
x86_64 only:
* dcrt0.cc (_dll_crt0): Always move stack to pthread stack area.
Explain why.
* miscfuncs.cc (create_new_main_thread_stack): New function to create
OS-like stack for main thread in pthread stack area.
* miscfuncs.cc (create_new_main_thread_stack): Declare.
2015-12-03 Corinna Vinschen <corinna@vinschen.de>
* dcrt0.cc (child_info_fork::alloc_stack): Fix formatting.

View File

@ -1093,6 +1093,35 @@ _dll_crt0 ()
/* Fall back to respawn if wow64_revert_to_original_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__

View File

@ -760,6 +760,47 @@ public:
};
thread_allocator thr_alloc NO_COPY;
/* Just set up a system-like main thread stack from the pthread stack area
maintained by the thr_alloc class. See the description in the x86_64-only
code in _dll_crt0 to understand why we have to do this. */
PVOID
create_new_main_thread_stack (PVOID &allocationbase)
{
PIMAGE_DOS_HEADER dosheader;
PIMAGE_NT_HEADERS ntheader;
SIZE_T stacksize;
ULONG guardsize;
ULONG commitsize;
PBYTE stacklimit;
dosheader = (PIMAGE_DOS_HEADER) GetModuleHandle (NULL);
ntheader = (PIMAGE_NT_HEADERS)
((PBYTE) dosheader + dosheader->e_lfanew);
stacksize = ntheader->OptionalHeader.SizeOfStackReserve;
stacksize = roundup2 (stacksize, wincap.allocation_granularity ());
allocationbase
= thr_alloc.alloc (ntheader->OptionalHeader.SizeOfStackReserve);
guardsize = wincap.def_guard_page_size ();
commitsize = ntheader->OptionalHeader.SizeOfStackCommit;
commitsize = roundup2 (commitsize, wincap.page_size ());
if (commitsize > stacksize - guardsize - wincap.page_size ())
commitsize = stacksize - guardsize - wincap.page_size ();
stacklimit = (PBYTE) allocationbase + stacksize - commitsize - guardsize;
/* Setup guardpage. */
if (!VirtualAlloc (stacklimit, guardsize,
MEM_COMMIT, PAGE_READWRITE | PAGE_GUARD))
return NULL;
/* Setup committed region. */
stacklimit += guardsize;
if (!VirtualAlloc (stacklimit, commitsize, MEM_COMMIT, PAGE_READWRITE))
return NULL;
NtCurrentTeb()->Tib.StackBase = ((PBYTE) allocationbase + stacksize);
NtCurrentTeb()->Tib.StackLimit = stacklimit;
_main_tls = &_my_tls;
return stacklimit - 64;
}
#endif
HANDLE WINAPI

View File

@ -70,6 +70,10 @@ ssize_t __reg3 check_iovec (const struct iovec *, int, bool);
#define check_iovec_for_read(a, b) check_iovec ((a), (b), false)
#define check_iovec_for_write(a, b) check_iovec ((a), (b), true)
#ifdef __x86_64__
extern PVOID create_new_main_thread_stack (PVOID &allocationbase);
#endif
extern "C" DWORD WINAPI pthread_wrapper (PVOID arg);
extern "C" HANDLE WINAPI CygwinCreateThread (LPTHREAD_START_ROUTINE thread_func,
PVOID thread_arg, PVOID stackaddr,