Back to index

glibc  2.9
makecontext.c
Go to the documentation of this file.
00001 /* Create new context.
00002    Copyright (C) 2002, 2004, 2005, 2008 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Contributed by Andreas Jaeger <aj@suse.de>, 2002.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #include <sysdep.h>
00022 #include <stdarg.h>
00023 #include <stdint.h>
00024 #include <ucontext.h>
00025 
00026 #include "ucontext_i.h"
00027 
00028 /* This implementation can handle any ARGC value but only
00029    normal integer parameters.
00030    makecontext sets up a stack and the registers for the
00031    user context. The stack looks like this:
00032                +-----------------------+
00033                | next context          |
00034                +-----------------------+
00035                | parameter 7-n         |
00036               +-----------------------+
00037               | trampoline address    |
00038     %rsp ->    +-----------------------+
00039 
00040    The registers are set up like this:
00041      %rdi,%rsi,%rdx,%rcx,%r8,%r9: parameter 1 to 6
00042      %rbx   : address of next context
00043      %rsp   : stack pointer.
00044 */
00045 
00046 /* XXX: This implementation currently only handles integer arguments.
00047    To handle long int and pointer arguments the va_arg arguments needs
00048    to be changed to long and also the stdlib/tst-setcontext.c file needs
00049    to be changed to pass long arguments to makecontext.  */
00050 
00051 
00052 void
00053 __makecontext (ucontext_t *ucp, void (*func) (void), int argc, ...)
00054 {
00055   extern void __start_context (void);
00056   unsigned long int *sp, idx_uc_link;
00057   va_list ap;
00058   int i;
00059 
00060   /* Generate room on stack for parameter if needed and uc_link.  */
00061   sp = (unsigned long int *) ((uintptr_t) ucp->uc_stack.ss_sp
00062                            + ucp->uc_stack.ss_size);
00063   sp -= (argc > 6 ? argc - 6 : 0) + 1;
00064   /* Align stack and make space for trampoline address.  */
00065   sp = (unsigned long int *) ((((uintptr_t) sp) & -16L) - 8);
00066 
00067   idx_uc_link = (argc > 6 ? argc - 6 : 0) + 1;
00068 
00069   /* Setup context ucp.  */
00070   /* Address to jump to.  */
00071   ucp->uc_mcontext.gregs[REG_RIP] = (long int) func;
00072   /* Setup rbx.*/
00073   ucp->uc_mcontext.gregs[REG_RBX] = (long int) &sp[idx_uc_link];
00074   ucp->uc_mcontext.gregs[REG_RSP] = (long int) sp;
00075 
00076   /* Setup stack.  */
00077   sp[0] = (unsigned long int) &__start_context;
00078   sp[idx_uc_link] = (unsigned long int) ucp->uc_link;
00079 
00080   va_start (ap, argc);
00081   /* Handle arguments.
00082 
00083      The standard says the parameters must all be int values.  This is
00084      an historic accident and would be done differently today.  For
00085      x86-64 all integer values are passed as 64-bit values and
00086      therefore extending the API to copy 64-bit values instead of
00087      32-bit ints makes sense.  It does not break existing
00088      functionality and it does not violate the standard which says
00089      that passing non-int values means undefined behavior.  */
00090   for (i = 0; i < argc; ++i)
00091     switch (i)
00092       {
00093       case 0:
00094        ucp->uc_mcontext.gregs[REG_RDI] = va_arg (ap, long int);
00095        break;
00096       case 1:
00097        ucp->uc_mcontext.gregs[REG_RSI] = va_arg (ap, long int);
00098        break;
00099       case 2:
00100        ucp->uc_mcontext.gregs[REG_RDX] = va_arg (ap, long int);
00101        break;
00102       case 3:
00103        ucp->uc_mcontext.gregs[REG_RCX] = va_arg (ap, long int);
00104        break;
00105       case 4:
00106        ucp->uc_mcontext.gregs[REG_R8] = va_arg (ap, long int);
00107        break;
00108       case 5:
00109        ucp->uc_mcontext.gregs[REG_R9] = va_arg (ap, long int);
00110        break;
00111       default:
00112        /* Put value on stack.  */
00113        sp[i - 5] = va_arg (ap, unsigned long int);
00114        break;
00115       }
00116   va_end (ap);
00117 
00118 }
00119 
00120 
00121 weak_alias (__makecontext, makecontext)