Fix initial stack alignment on 64-bit systems.

gcc does re-align the stack in the main() function prologue, however,
we still need to set the right alignment for other cases: thread entry,
.init and .fini code that is executed before main() is called or after
it has returned, and signal handlers which may use a separate stack.

Part of #10509
This commit is contained in:
Jérôme Duval 2018-01-14 09:54:25 +01:00 committed by Adrien Destugues
parent 34cdda1dd5
commit 13daa9299e

View File

@ -101,12 +101,16 @@ arch_randomize_stack_pointer(addr_t value)
static_assert(MAX_RANDOM_VALUE >= B_PAGE_SIZE - 1,
"randomization range is too big");
value -= random_value() & (B_PAGE_SIZE - 1);
return value & ~addr_t(0xf);
return (value & ~addr_t(0xf)) - 8;
// This means, result % 16 == 8, which is what rsp should adhere to
// when a function is entered for the stack to be considered aligned to
// 16 byte.
}
static uint8*
get_signal_stack(Thread* thread, iframe* frame, struct sigaction* action)
get_signal_stack(Thread* thread, iframe* frame, struct sigaction* action,
size_t spaceNeeded)
{
// Use the alternate signal stack if we should and can.
if (thread->signal_stack_enabled
@ -115,14 +119,15 @@ get_signal_stack(Thread* thread, iframe* frame, struct sigaction* action)
|| frame->user_sp >= thread->signal_stack_base
+ thread->signal_stack_size)) {
addr_t stackTop = thread->signal_stack_base + thread->signal_stack_size;
return (uint8*)arch_randomize_stack_pointer(stackTop);
return (uint8*)arch_randomize_stack_pointer(stackTop - spaceNeeded);
}
// We are going to use the stack that we are already on. We must not touch
// the red zone (128 byte area below the stack pointer, reserved for use
// by functions to store temporary data and guaranteed not to be modified
// by signal handlers).
return (uint8*)(frame->user_sp - 128);
return (uint8*)((frame->user_sp - 128 - spaceNeeded) & ~addr_t(0xf)) - 8;
// align stack pointer (cf. arch_randomize_stack_pointer())
}
@ -207,19 +212,19 @@ arch_thread_enter_userspace(Thread* thread, addr_t entry, void* args1,
void* args2)
{
addr_t stackTop = thread->user_stack_base + thread->user_stack_size;
addr_t codeAddr;
TRACE("arch_thread_enter_userspace: entry %#lx, args %p %p, "
"stackTop %#lx\n", entry, args1, args2, stackTop);
stackTop = arch_randomize_stack_pointer(stackTop);
stackTop = arch_randomize_stack_pointer(stackTop - sizeof(codeAddr));
// Copy the address of the stub that calls exit_thread() when the thread
// entry function returns to the top of the stack to act as the return
// address. The stub is inside commpage.
addr_t commPageAddress = (addr_t)thread->team->commpage_address;
addr_t codeAddr = ((addr_t*)commPageAddress)[COMMPAGE_ENTRY_X86_THREAD_EXIT]
codeAddr = ((addr_t*)commPageAddress)[COMMPAGE_ENTRY_X86_THREAD_EXIT]
+ commPageAddress;
stackTop -= sizeof(codeAddr);
if (user_memcpy((void*)stackTop, (const void*)&codeAddr, sizeof(codeAddr))
!= B_OK)
return B_BAD_ADDRESS;
@ -315,10 +320,11 @@ arch_setup_signal_frame(Thread* thread, struct sigaction* action,
signalFrameData->syscall_restart_return_value = frame->orig_rax;
// Get the stack to use and copy the frame data to it.
uint8* userStack = get_signal_stack(thread, frame, action);
uint8* userStack = get_signal_stack(thread, frame, action,
sizeof(*signalFrameData) + sizeof(frame->ip));
userStack -= sizeof(*signalFrameData);
signal_frame_data* userSignalFrameData = (signal_frame_data*)userStack;
signal_frame_data* userSignalFrameData
= (signal_frame_data*)(userStack + sizeof(frame->ip));
if (user_memcpy(userSignalFrameData, signalFrameData,
sizeof(*signalFrameData)) != B_OK) {
@ -326,7 +332,6 @@ arch_setup_signal_frame(Thread* thread, struct sigaction* action,
}
// Copy a return address to the stack so that backtraces will be correct.
userStack -= sizeof(frame->ip);
if (user_memcpy(userStack, &frame->ip, sizeof(frame->ip)) != B_OK)
return B_BAD_ADDRESS;