mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-18 23:28:29 +00:00
Fix stack pointer alignment for x86_64 platforms
The x86_64 ABI requires the stack pointer to be 16-byte aligned before the call of a function and decreased by 8 at the function entrypoint (after the return address has been pushed to the stack). Currently, when a new Genode thread gets created, the initial stack pointer is aligned to 16 byte. On Genode/Linux, the thread entry function is entered by a 'call' instruction, so the stack pointer alignment at the function entrypoint is correct. On Fiasco.OC and NOVA, however, the thread entry function gets executed without a return address being pushed to the stack, so at the function entrypoint the stack pointer is still aligned to 16 byte, which can cause problems with compiler-generated SSE instructions. With this patch, the stack pointer given to a new thread gets aligned to 16 bytes and decreased by 8 by default, since most of the currently supported base platforms execute the thread entry function without pushing a return address to the stack. For base-linux, the stack pointer gets realigned to 16 bytes before the thread entry function gets called. Fixes #1043.
This commit is contained in:
committed by
Christian Helmuth
parent
a19d491fbd
commit
4b420f6e71
@ -153,6 +153,12 @@ Thread_base::Context *Thread_base::_alloc_context(size_t stack_size)
|
|||||||
context->stack_base = ds_addr;
|
context->stack_base = ds_addr;
|
||||||
context->ds_cap = ds_cap;
|
context->ds_cap = ds_cap;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The value at the top of the stack might get interpreted as return
|
||||||
|
* address of the thread start function by GDB, so we set it to 0.
|
||||||
|
*/
|
||||||
|
*(addr_t*)context->stack_top() = 0;
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,9 +122,7 @@ void Thread_base::start()
|
|||||||
threadlib_initialized = true;
|
threadlib_initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* align initial stack to 16 byte boundary */
|
_tid.tid = lx_create_thread(Thread_base::_thread_start, stack_top(), this);
|
||||||
void *thread_sp = (void *)((addr_t)(stack_top()) & ~0xf);
|
|
||||||
_tid.tid = lx_create_thread(Thread_base::_thread_start, thread_sp, this);
|
|
||||||
_tid.pid = lx_getpid();
|
_tid.pid = lx_getpid();
|
||||||
|
|
||||||
/* wait until the 'thread_start' function got entered */
|
/* wait until the 'thread_start' function got entered */
|
||||||
|
@ -83,8 +83,7 @@ L(thread_start):
|
|||||||
.cfi_startproc;
|
.cfi_startproc;
|
||||||
/* Clearing frame pointer is insufficient, use CFI. */
|
/* Clearing frame pointer is insufficient, use CFI. */
|
||||||
.cfi_undefined %eip;
|
.cfi_undefined %eip;
|
||||||
/* Note: %esi is zero. */
|
xorl %ebp,%ebp /* terminate the stack frame */
|
||||||
movl %esi,%ebp /* terminate the stack frame */
|
|
||||||
call *%ebx
|
call *%ebx
|
||||||
#ifdef PIC
|
#ifdef PIC
|
||||||
call L(here)
|
call L(here)
|
||||||
|
@ -17,6 +17,9 @@
|
|||||||
lx_clone:
|
lx_clone:
|
||||||
.cfi_startproc
|
.cfi_startproc
|
||||||
|
|
||||||
|
/* Align the new stack pointer to 16 bytes. */
|
||||||
|
andq $0xfffffffffffffff0, %rsi
|
||||||
|
|
||||||
/* Insert the argument onto the new stack. */
|
/* Insert the argument onto the new stack. */
|
||||||
subq $16,%rsi
|
subq $16,%rsi
|
||||||
movq %rcx,8(%rsi)
|
movq %rcx,8(%rsi)
|
||||||
@ -51,7 +54,7 @@ L(thread_start):
|
|||||||
|
|
||||||
/* Clear the frame pointer. The ABI suggests this be done, to mark
|
/* Clear the frame pointer. The ABI suggests this be done, to mark
|
||||||
the outermost frame obviously. */
|
the outermost frame obviously. */
|
||||||
xorl %ebp, %ebp
|
xorq %rbp, %rbp
|
||||||
|
|
||||||
/* Set up arguments for the function call. */
|
/* Set up arguments for the function call. */
|
||||||
popq %rax /* Function to call. */
|
popq %rax /* Function to call. */
|
||||||
|
@ -100,11 +100,16 @@ namespace Genode {
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Top of stack aligned to 16 byte
|
* Top of stack
|
||||||
*
|
*
|
||||||
* The alignment is also sufficient for the AMD64 ABI.
|
* The alignment matches an initial stack frame, which is
|
||||||
|
* sufficient for the AMD64 ABI (stack top + 8 is 16-byte
|
||||||
|
* aligned).
|
||||||
*/
|
*/
|
||||||
addr_t stack_top() const { return (addr_t)_stack & ~0xf; }
|
addr_t stack_top() const
|
||||||
|
{
|
||||||
|
return ((addr_t)_stack & ~0xf) - sizeof(addr_t);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Virtual address of the start of the stack
|
* Virtual address of the start of the stack
|
||||||
|
@ -153,6 +153,12 @@ Thread_base::Context *Thread_base::_alloc_context(size_t stack_size)
|
|||||||
context->stack_base = ds_addr;
|
context->stack_base = ds_addr;
|
||||||
context->ds_cap = ds_cap;
|
context->ds_cap = ds_cap;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The value at the top of the stack might get interpreted as return
|
||||||
|
* address of the thread start function by GDB, so we set it to 0.
|
||||||
|
*/
|
||||||
|
*(addr_t*)context->stack_top() = 0;
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user