Always allocate main thread stack from pthread stack area on x86_64.
* dcrt0.cc: Semi-revert commit 12743c2d5d
.
(dll_crt0_0): Drop setting wow64_needs_stack_adjustment on 64 bit.
(_dll_crt0): Split out 64 bit code again and always create new main
thread stack, unless forked off from the non main thread in the parent.
Call create_new_main_thread_stack with parent stack commitsize if
started from the parent's main thread.
Only call child_info_fork::alloc_stack for the latter case on 64 bit.
Slightly rearrange moving rsp and rbp to new stack and document how.
Revert 32 bit wow64 handling to its former self.
* miscfunc.cc (create_new_main_thread_stack): Take a commitsize
parameter and use it if it's not 0. Don't set _main_tls here, it's
done in the caller _dll_crt0 anyway. Return stackbase - 16 bytes,
rather than stacklimit (which was very wrong anyway).
* miscfuncs.h (create_new_main_thread_stack): Accommodate declaration
to aforementioned change.
* wincap.h (wincaps::has_3264_stack_broken): Remove element.
* wincap.cc: Ditto, throughout.
* wow64.cc: Semi-revert to pre-12743c2d5d2721f3a80b4d7671a349be03c1f520
but keep architecture-agnostic type changes intact. Fix formatting.
* wow64.h: Revert to pre-12743c2d5d2721f3a80b4d7671a349be03c1f520.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
@@ -782,11 +782,6 @@ dll_crt0_0 ()
|
||||
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
|
||||
@@ -1068,59 +1063,76 @@ extern "C" void __stdcall
|
||||
_dll_crt0 ()
|
||||
{
|
||||
#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))
|
||||
/* 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 always 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 (!dynamically_loaded)
|
||||
{
|
||||
if (!in_forkee || fork_info->from_main)
|
||||
{
|
||||
/* Must be static since it's referenced after the stack and frame
|
||||
pointer registers have been changed. */
|
||||
static PVOID allocationbase;
|
||||
SIZE_T commitsize = in_forkee ? (PBYTE) fork_info->stackbase
|
||||
- (PBYTE) fork_info->stacklimit
|
||||
: 0;
|
||||
PVOID stackaddr = create_new_main_thread_stack (allocationbase,
|
||||
commitsize);
|
||||
if (stackaddr)
|
||||
{
|
||||
/* Set stack pointer to new address. Set frame pointer to
|
||||
stack pointer and subtract 32 bytes for shadow space. */
|
||||
__asm__ ("\n\
|
||||
movq %[ADDR], %%rsp \n\
|
||||
movq %%rsp, %%rbp \n\
|
||||
subq $32,%%rsp \n"
|
||||
: : [ADDR] "r" (stackaddr));
|
||||
/* We're on the new 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
|
||||
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. */
|
||||
#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;
|
||||
|
||||
PVOID stackaddr = CREATE_STACK (allocationbase);
|
||||
PVOID stackaddr = wow64_revert_to_original_stack (allocationbase);
|
||||
if (stackaddr)
|
||||
{
|
||||
/* 2nd half of the stack move. Set stack pointer to new address.
|
||||
Set frame pointer to 0. */
|
||||
FIX_STACK (stackaddr);
|
||||
/* Now we're back on the original stack. Free up space taken by the
|
||||
/* 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 ();
|
||||
wow64_respawn_process();
|
||||
}
|
||||
_feinitialise ();
|
||||
#ifndef __x86_64__
|
||||
main_environ = user_data->envptr;
|
||||
#endif
|
||||
if (in_forkee)
|
||||
{
|
||||
fork_info->alloc_stack ();
|
||||
_main_tls = &_my_tls;
|
||||
}
|
||||
fork_info->alloc_stack ();
|
||||
#endif
|
||||
|
||||
_feinitialise ();
|
||||
_main_tls = &_my_tls;
|
||||
_main_tls->call ((DWORD (*) (void *, void *)) dll_crt0_1, NULL);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user