Print this page
patch feedback
6507 i386 makecontext(3c) needs to 16-byte align the stack

Split Close
Expand all
Collapse all
          --- old/usr/src/lib/libc/i386/gen/makectxt.c
          +++ new/usr/src/lib/libc/i386/gen/makectxt.c
↓ open down ↓ 19 lines elided ↑ open up ↑
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  24   24   * Use is subject to license terms.
  25   25   */
  26   26  
  27   27  /*      Copyright (c) 1988 AT&T */
  28   28  /*        All Rights Reserved   */
  29   29  
  30      -#pragma ident   "%Z%%M% %I%     %E% SMI"
  31      -
  32   30  #pragma weak _makecontext = makecontext
  33   31  
  34   32  #include "lint.h"
  35   33  #include <stdarg.h>
  36   34  #include <ucontext.h>
  37   35  #include <sys/stack.h>
  38   36  
  39   37  /*
  40   38   * The ucontext_t that the user passes in must have been primed with a
  41   39   * call to getcontext(2), have the uc_stack member set to reflect the
  42   40   * stack which this context will use, and have the uc_link member set
  43   41   * to the context which should be resumed when this context returns.
  44   42   * When makecontext() returns, the ucontext_t will be set to run the
  45   43   * given function with the given parameters on the stack specified by
  46   44   * uc_stack, and which will return to the ucontext_t specified by uc_link.
  47   45   */
  48   46  
       47 +/*
       48 + * The original i386 ABI said that the stack pointer need be only 4-byte
       49 + * aligned before a function call (STACK_ALIGN == 4).  The ABI supplement
       50 + * version 1.0 changed the required alignment to 16-byte for the benefit of
       51 + * floating point code compiled using sse2.  The compiler assumes this
       52 + * alignment and maintains it for calls it generates.  If the stack is
       53 + * initially properly aligned, it will continue to be so aligned.  If it is
       54 + * not initially so aligned, it will never become so aligned.
       55 + *
       56 + * One slightly confusing detail to keep in mind is that the 16-byte
       57 + * alignment (%esp & 0xf == 0) is true just *before* the call instruction.
       58 + * The call instruction will then push a return value, decrementing %esp by
       59 + * 4.  Therefore, if one dumps %esp at the at the very first instruction in
       60 + * a function, it will end with a 0xc.  The compiler expects this and
       61 + * compensates for it properly.
       62 + *
       63 + * Note: If you change this value, you need to change it in the following
       64 + * files as well:
       65 + *
       66 + *  - lib/libc/i386/threads/machdep.c
       67 + *  - lib/common/i386/crti.s
       68 + *  - lib/common/i386/crt1.s
       69 + */
       70 +#undef  STACK_ALIGN
       71 +#define STACK_ALIGN     16
       72 +
  49   73  static void resumecontext(void);
  50   74  
  51   75  void
  52   76  makecontext(ucontext_t *ucp, void (*func)(), int argc, ...)
  53   77  {
  54   78          long *sp;
  55   79          long *tsp;
  56   80          va_list ap;
  57   81          size_t size;
  58   82  
  59   83          ucp->uc_mcontext.gregs[EIP] = (greg_t)func;
  60   84  
  61   85          size = sizeof (long) * (argc + 1);
  62   86  
  63      -        sp = (long *)(((uintptr_t)ucp->uc_stack.ss_sp +
       87 +        tsp = (long *)(((uintptr_t)ucp->uc_stack.ss_sp +
  64   88              ucp->uc_stack.ss_size - size) & ~(STACK_ALIGN - 1));
  65   89  
  66      -        tsp = sp + 1;
  67      -
  68      -        va_start(ap, argc);
  69      -
  70      -        while (argc-- > 0) {
  71      -                *tsp++ = va_arg(ap, long);
  72      -        }
  73      -
  74      -        va_end(ap);
       90 +        /*
       91 +         * Since we're emulating the call instruction, we must push the
       92 +         * return address (which involves adjusting the stack pointer to
       93 +         * have the proper 4-byte bias).
       94 +         */
       95 +        sp = tsp - 1;
  75   96  
  76   97          *sp = (long)resumecontext;              /* return address */
  77   98  
  78   99          ucp->uc_mcontext.gregs[UESP] = (greg_t)sp;
      100 +
      101 +        /*
      102 +         * "push" all the arguments
      103 +         */
      104 +        va_start(ap, argc);
      105 +        while (argc-- > 0)
      106 +                *tsp++ = va_arg(ap, long);
      107 +        va_end(ap);
  79  108  }
  80  109  
  81  110  
  82  111  static void
  83  112  resumecontext(void)
  84  113  {
  85  114          ucontext_t uc;
  86  115  
  87  116          (void) getcontext(&uc);
  88  117          (void) setcontext(uc.uc_link);
  89  118  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX