2 Copyright (C) 2002-2021 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
25 # include <libc-pointer-arith.h>
26 # include <sys/prctl.h>
29 #include "ucontext_i.h"
31 /* This implementation can handle any ARGC value but only
32 normal integer parameters.
33 makecontext sets up a stack and the registers for the
34 user context. The stack looks like this:
35 +-----------------------+
37 +-----------------------+
39 +-----------------------+
40 | trampoline address |
41 %rsp -> +-----------------------+
43 The registers are set up like this:
44 %rdi,%rsi,%rdx,%rcx,%r8,%r9: parameter 1 to 6
45 %rbx : address of next context
49 /* XXX: This implementation currently only handles integer arguments.
50 To handle long int and pointer arguments the va_arg arguments needs
51 to be changed to long and also the stdlib/tst-setcontext.c file needs
52 to be changed to pass long arguments to makecontext. */
56 __makecontext (ucontext_t
*ucp
, void (*func
) (void), int argc
, ...)
58 extern void __start_context (void) attribute_hidden
;
59 extern void __push___start_context (ucontext_t
*)
62 unsigned int idx_uc_link
;
66 /* Generate room on stack for parameter if needed and uc_link. */
67 sp
= (greg_t
*) ((uintptr_t) ucp
->uc_stack
.ss_sp
68 + ucp
->uc_stack
.ss_size
);
69 sp
-= (argc
> 6 ? argc
- 6 : 0) + 1;
70 /* Align stack and make space for trampoline address. */
71 sp
= (greg_t
*) ((((uintptr_t) sp
) & -16L) - 8);
73 idx_uc_link
= (argc
> 6 ? argc
- 6 : 0) + 1;
75 /* Setup context ucp. */
76 /* Address to jump to. */
77 ucp
->uc_mcontext
.gregs
[REG_RIP
] = (uintptr_t) func
;
79 ucp
->uc_mcontext
.gregs
[REG_RBX
] = (uintptr_t) &sp
[idx_uc_link
];
80 ucp
->uc_mcontext
.gregs
[REG_RSP
] = (uintptr_t) sp
;
84 struct pthread
*self
= THREAD_SELF
;
85 unsigned int feature_1
= THREAD_GETMEM (self
, header
.feature_1
);
86 /* NB: We must check feature_1 before accessing __ssp since caller
87 may be compiled against ucontext_t without __ssp. */
88 if ((feature_1
& X86_FEATURE_1_SHSTK
) != 0)
90 /* Shadow stack is enabled. We need to allocate a new shadow
92 unsigned long ssp_size
= (((uintptr_t) sp
93 - (uintptr_t) ucp
->uc_stack
.ss_sp
)
94 >> STACK_SIZE_TO_SHADOW_STACK_SIZE_SHIFT
);
95 /* Align shadow stack to 8 bytes. */
96 ssp_size
= ALIGN_UP (ssp_size
, 8);
98 ucp
->__ssp
[1] = ssp_size
;
99 ucp
->__ssp
[2] = ssp_size
;
101 /* Call __push___start_context to allocate a new shadow stack,
102 push __start_context onto the new stack as well as the new
103 shadow stack. NB: After __push___start_context returns,
104 ucp->__ssp[0]: The new shadow stack pointer.
105 ucp->__ssp[1]: The base address of the new shadow stack.
106 ucp->__ssp[2]: The size of the new shadow stack.
108 __push___start_context (ucp
);
112 sp
[0] = (uintptr_t) &__start_context
;
113 sp
[idx_uc_link
] = (uintptr_t) ucp
->uc_link
;
118 The standard says the parameters must all be int values. This is
119 an historic accident and would be done differently today. For
120 x86-64 all integer values are passed as 64-bit values and
121 therefore extending the API to copy 64-bit values instead of
122 32-bit ints makes sense. It does not break existing
123 functionality and it does not violate the standard which says
124 that passing non-int values means undefined behavior. */
125 for (i
= 0; i
< argc
; ++i
)
129 ucp
->uc_mcontext
.gregs
[REG_RDI
] = va_arg (ap
, greg_t
);
132 ucp
->uc_mcontext
.gregs
[REG_RSI
] = va_arg (ap
, greg_t
);
135 ucp
->uc_mcontext
.gregs
[REG_RDX
] = va_arg (ap
, greg_t
);
138 ucp
->uc_mcontext
.gregs
[REG_RCX
] = va_arg (ap
, greg_t
);
141 ucp
->uc_mcontext
.gregs
[REG_R8
] = va_arg (ap
, greg_t
);
144 ucp
->uc_mcontext
.gregs
[REG_R9
] = va_arg (ap
, greg_t
);
147 /* Put value on stack. */
148 sp
[i
- 5] = va_arg (ap
, greg_t
);
156 weak_alias (__makecontext
, makecontext
)