elf: Fix _dl_debug_vdprintf to work before self-relocation
[glibc.git] / sysdeps / unix / sysv / linux / i386 / makecontext.S
blob346cdd0e0a79c8bd61cc21a1ff6435aa111bde41
1 /* Create new context.
2    Copyright (C) 2001-2023 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/>.  */
19 #include <sysdep.h>
20 #include <asm/prctl.h>
22 #include "ucontext_i.h"
25 ENTRY(__makecontext)
26         movl    4(%esp), %eax
28         /* Load the address of the function we are supposed to run.  */
29         movl    8(%esp), %ecx
31         /* Compute the address of the stack.  The information comes from
32            to us_stack element.  */
33         movl    oSS_SP(%eax), %edx
34         movl    %ecx, oEIP(%eax)
35         addl    oSS_SIZE(%eax), %edx
37         /* Remember the number of parameters for the exit handler since
38            it has to remove them.  We store the number in the EBX register
39            which the function we will call must preserve.  */
40         movl    12(%esp), %ecx
41         movl    %ecx, oEBX(%eax)
43         /* Make room on the new stack for the parameters.
44            Room for the arguments, return address (== L(exitcode)) and
45            oLINK pointer is needed.  One of the pointer sizes is subtracted
46            after aligning the stack.  */
47         negl    %ecx
48         leal    -4(%edx,%ecx,4), %edx
49         negl    %ecx
51         /* Align the stack.  */
52         andl    $0xfffffff0, %edx
53         subl    $4, %edx
55         /* Store the future stack pointer.  */
56         movl    %edx, oESP(%eax)
58         /* Put the next context on the new stack (from the uc_link
59            element).  */
60         movl    oLINK(%eax), %eax
61         movl    %eax, 4(%edx,%ecx,4)
63         /* Copy all the parameters.  */
64         jecxz   2f
65 1:      movl    12(%esp,%ecx,4), %eax
66         movl    %eax, (%edx,%ecx,4)
67         decl    %ecx
68         jnz     1b
71 #if SHSTK_ENABLED
72         /* Check if Shadow Stack is enabled.  */
73         testl   $X86_FEATURE_1_SHSTK, %gs:FEATURE_1_OFFSET
74         jz      L(skip_ssp)
76         /* Reload the pointer to ucontext.  */
77         movl    4(%esp), %eax
79         /* Shadow stack is enabled.  We need to allocate a new shadow
80            stack.  */
81         subl    oSS_SP(%eax), %edx
82         shrl    $STACK_SIZE_TO_SHADOW_STACK_SIZE_SHIFT, %edx
84         /* Align shadow stack size to 8 bytes.  */
85         addl    $7, %edx
86         andl    $-8, %edx
88         /* Store shadow stack size in __ssp[2].  */
89         movl    %edx, (oSSP + 8)(%eax)
91         /* Save ESI in the second scratch register slot.  */
92         movl    %esi, oSCRATCH2(%eax)
93         /* Save EDI in the third scratch register slot.  */
94         movl    %edi, oSCRATCH3(%eax)
96         /* Save the pointer to ucontext.  */
97         movl    %eax, %edi
99         /* Get the original shadow stack pointer.  */
100         rdsspd  %esi
102         /* Align the saved original shadow stack pointer to the next
103            8 byte aligned boundary.  */
104         andl    $-8, %esi
106         /* Load the top of the new stack into EDX.  */
107         movl    oESP(%eax), %edx
109         /* We need to terminate the FDE here because the unwinder looks
110            at ra-1 for unwind information.  */
111         cfi_endproc
113         /* Swap the original stack pointer with the top of the new
114            stack.  */
115         xchgl   %esp, %edx
117         /* Add 4 bytes since CALL will push the 4-byte return address
118            onto stack.  */
119         addl    $4, %esp
121         /* Allocate the new shadow stack.  Save EBX in the first scratch
122            register slot.  */
123         movl    %ebx, oSCRATCH1(%eax)
125         /* CET syscall takes 64-bit sizes.  */
126         subl    $16, %esp
127         movl    (oSSP + 8)(%eax), %ecx
128         movl    %ecx, (%esp)
129         movl    $0, 4(%esp)
130         movl    %ecx, 8(%esp)
131         movl    $0, 12(%esp)
132         movl    %esp, %ecx
134         movl    $ARCH_CET_ALLOC_SHSTK, %ebx
135         movl    $__NR_arch_prctl, %eax
136         ENTER_KERNEL
137         testl   %eax, %eax
138         jne     L(hlt)          /* This should never happen.  */
140         /* Copy the base address of the new shadow stack to __ssp[1].  */
141         movl    (%esp), %eax
142         movl    %eax, (oSSP + 4)(%edi)
144         addl    $16, %esp
146         /* Restore EBX from the first scratch register slot.  */
147         movl    oSCRATCH1(%edi), %ebx
149         /* Get the size of the new shadow stack.  */
150         movl    (oSSP + 8)(%edi), %ecx
152         /* Use the restore stoken to restore the new shadow stack.  */
153         rstorssp -8(%eax, %ecx)
155         /* Save the restore token at the next 8 byte aligned boundary
156            on the original shadow stack.  */
157         saveprevssp
159         /* Push the address of "jmp exitcode" onto the new stack as
160            well as the new shadow stack.  */
161         call    1f
162         jmp     L(exitcode)
165         /* Get the new shadow stack pointer.  */
166         rdsspd  %eax
168         /* Use the restore stoken to restore the original shadow stack.  */
169         rstorssp -8(%esi)
171         /* Save the restore token on the new shadow stack.  */
172         saveprevssp
174         /* Store the new shadow stack pointer in __ssp[0].  */
175         movl    %eax, oSSP(%edi)
177         /* Restore the original stack.  */
178         mov     %edx, %esp
180         cfi_startproc
182         /* Restore ESI from the second scratch register slot.  */
183         movl    oSCRATCH2(%edi), %esi
184         /* Restore EDI from the third scratch register slot.  */
185         movl    oSCRATCH3(%edi), %edi
187         ret
189 L(skip_ssp):
190 #endif
192         /* If the function we call returns we must continue with the
193            context which is given in the uc_link element.  To do this
194            set the return address for the function the user provides
195            to a little bit of helper code which does the magic (see
196            below).  */
197 #ifdef PIC
198         call    1f
199         cfi_adjust_cfa_offset (4)
200 1:      popl    %ecx
201         cfi_adjust_cfa_offset (-4)
202         addl    $L(exitcode)-1b, %ecx
203         movl    %ecx, (%edx)
204 #else
205         movl    $L(exitcode), (%edx)
206 #endif
207         /* We need to terminate the FDE here instead of after ret because
208            the unwinder looks at ra-1 for unwind information.  */
209         cfi_endproc
211         /* 'makecontext' returns no value.  */
212         ret
214         /* This is the helper code which gets called if a function which
215            is registered with 'makecontext' returns.  In this case we
216            have to install the context listed in the uc_link element of
217            the context 'makecontext' manipulated at the time of the
218            'makecontext' call.  If the pointer is NULL the process must
219            terminate.  */
220 L(exitcode):
221         /* This removes the parameters passed to the function given to
222            'makecontext' from the stack.  EBX contains the number of
223            parameters (see above).  */
224         leal    (%esp,%ebx,4), %esp
226         cmpl    $0, (%esp)              /* Check the next context.  */
227         je      2f                      /* If it is zero exit.  */
229         call    HIDDEN_JUMPTARGET(__setcontext)
230         /* If this returns (which can happen if the syscall fails) we'll
231            exit the program with the return error value (-1).  */
232         jmp L(call_exit)
235         /* Exit with status 0.  */
236         xorl    %eax, %eax
238 L(call_exit):
239         /* Align the stack and pass the exit code (from %eax).  */
240         andl    $0xfffffff0, %esp
241         subl    $12, %esp
242         pushl   %eax
244         call    HIDDEN_JUMPTARGET(exit)
245         /* The 'exit' call should never return.  In case it does cause
246            the process to terminate.  */
247 L(hlt):
248         hlt
249         cfi_startproc
250 END(__makecontext)
252 weak_alias (__makecontext, makecontext)