From ceef08daa722b3a411ef838c03fb2fe6ada2f884 Mon Sep 17 00:00:00 2001 From: Josef 'Jeff' Sipek Date: Tue, 5 Jan 2016 15:30:17 -0500 Subject: [PATCH] 6507 i386 makecontext(3c) needs to 16-byte align the stack Reviewed by: Gordon Ross Reviewed by: Robert Mustacchi Approved by: Dan McDonald --- usr/src/lib/common/i386/crt1.s | 13 +++++++- usr/src/lib/common/i386/crti.s | 16 +++++----- usr/src/lib/libc/i386/gen/makectxt.c | 53 +++++++++++++++++++++++++-------- usr/src/lib/libc/i386/threads/machdep.c | 17 ++++++----- 4 files changed, 71 insertions(+), 28 deletions(-) diff --git a/usr/src/lib/common/i386/crt1.s b/usr/src/lib/common/i386/crt1.s index 970c78d2d0..0fe2cb816e 100644 --- a/usr/src/lib/common/i386/crt1.s +++ b/usr/src/lib/common/i386/crt1.s @@ -161,8 +161,19 @@ __do_exit_code_ptr: leal 16(%ebp,%eax,4),%edx /* envp */ movl %edx,_environ /* copy to _environ */ 1: + /* + * The stack needs to be 16-byte aligned with a 4-byte bias. See + * comment in lib/libc/i386/gen/makectxt.c. + * + * Note: If you change it, you need to change it in the following + * files as well: + * + * - lib/libc/i386/threads/machdep.c + * - lib/libc/i386/gen/makectxt.c + * - lib/common/i386/crti.s + */ andl $-16,%esp /* make main() and exit() be called with */ - subl $4,%esp /* a 16-byte aligned stack pointer */ + subl $4,%esp /* a properly aligned stack pointer */ pushl %edx leal 12(%ebp),%edx /* argv */ movl %edx,___Argv diff --git a/usr/src/lib/common/i386/crti.s b/usr/src/lib/common/i386/crti.s index af177b8332..8f8a7ed477 100644 --- a/usr/src/lib/common/i386/crti.s +++ b/usr/src/lib/common/i386/crti.s @@ -40,13 +40,15 @@ .file "crti.s" /* - * Note that when _init and _fini are called we have 16-byte alignment per the - * ABI. We need to make sure that our asm leaves it such that subsequent calls - * will be aligned. gcc expects stack alignment before the call instruction is - * executed. Specifically if we call function foo(), the stack pointer will be - * 0xc aligned after executing the call instruction and before executing foo's - * prologue. Note that because 16-byte alignment also ensures 4-byte alignment - * we will not be breaking compatibility with older applications. + * Note that when _init and _fini are called the stack needs to be 16-byte + * aligned with a 4-byte bias. See comment in lib/libc/i386/gen/makectxt.c. + * + * Note: If you change it, you need to change it in the following files as + * well: + * + * - lib/libc/i386/threads/machdep.c + * - lib/libc/i386/gen/makectxt.c + * - lib/common/i386/crt1.s */ /* diff --git a/usr/src/lib/libc/i386/gen/makectxt.c b/usr/src/lib/libc/i386/gen/makectxt.c index d72a67a481..27ea2a5fc6 100644 --- a/usr/src/lib/libc/i386/gen/makectxt.c +++ b/usr/src/lib/libc/i386/gen/makectxt.c @@ -27,8 +27,6 @@ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ -#pragma ident "%Z%%M% %I% %E% SMI" - #pragma weak _makecontext = makecontext #include "lint.h" @@ -46,6 +44,32 @@ * uc_stack, and which will return to the ucontext_t specified by uc_link. */ +/* + * The original i386 ABI said that the stack pointer need be only 4-byte + * aligned before a function call (STACK_ALIGN == 4). The ABI supplement + * version 1.0 changed the required alignment to 16-byte for the benefit of + * floating point code compiled using sse2. The compiler assumes this + * alignment and maintains it for calls it generates. If the stack is + * initially properly aligned, it will continue to be so aligned. If it is + * not initially so aligned, it will never become so aligned. + * + * One slightly confusing detail to keep in mind is that the 16-byte + * alignment (%esp & 0xf == 0) is true just *before* the call instruction. + * The call instruction will then push a return value, decrementing %esp by + * 4. Therefore, if one dumps %esp at the at the very first instruction in + * a function, it will end with a 0xc. The compiler expects this and + * compensates for it properly. + * + * Note: If you change this value, you need to change it in the following + * files as well: + * + * - lib/libc/i386/threads/machdep.c + * - lib/common/i386/crti.s + * - lib/common/i386/crt1.s + */ +#undef STACK_ALIGN +#define STACK_ALIGN 16 + static void resumecontext(void); void @@ -60,22 +84,27 @@ makecontext(ucontext_t *ucp, void (*func)(), int argc, ...) size = sizeof (long) * (argc + 1); - sp = (long *)(((uintptr_t)ucp->uc_stack.ss_sp + + tsp = (long *)(((uintptr_t)ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size - size) & ~(STACK_ALIGN - 1)); - tsp = sp + 1; - - va_start(ap, argc); - - while (argc-- > 0) { - *tsp++ = va_arg(ap, long); - } - - va_end(ap); + /* + * Since we're emulating the call instruction, we must push the + * return address (which involves adjusting the stack pointer to + * have the proper 4-byte bias). + */ + sp = tsp - 1; *sp = (long)resumecontext; /* return address */ ucp->uc_mcontext.gregs[UESP] = (greg_t)sp; + + /* + * "push" all the arguments + */ + va_start(ap, argc); + while (argc-- > 0) + *tsp++ = va_arg(ap, long); + va_end(ap); } diff --git a/usr/src/lib/libc/i386/threads/machdep.c b/usr/src/lib/libc/i386/threads/machdep.c index c9c38e369b..a39a4a0908 100644 --- a/usr/src/lib/libc/i386/threads/machdep.c +++ b/usr/src/lib/libc/i386/threads/machdep.c @@ -29,14 +29,15 @@ #include /* - * The i386 ABI says that the stack pointer need be only 4-byte aligned - * before a function call (STACK_ALIGN == 4). We use a 16-byte stack - * alignment for the benefit of floating point code compiled using sse2. - * Even though the i386 ABI doesn't require it, both cc and gcc - * assume this alignment on entry to a function and maintain it - * for calls made from that function. If the stack is initially - * aligned on a 16-byte boundary, it will continue to be so aligned. - * If it is not initially so aligned, it will never become so aligned. + * The stack needs to be 16-byte aligned with a 4-byte bias. See comment in + * lib/libc/i386/gen/makectxt.c. + * + * Note: If you change it, you need to change it in the following files as + * well: + * + * - lib/libc/i386/gen/makectxt.c + * - lib/common/i386/crti.s + * - lib/common/i386/crt1.s */ #undef STACK_ALIGN #define STACK_ALIGN 16 -- 2.11.4.GIT