manual: add dup3
[glibc.git] / sysdeps / x86_64 / __longjmp.S
blob22fedc49970eba0ab86cb8dec8411197bec95d37
1 /* Copyright (C) 2001-2024 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, see
16    <https://www.gnu.org/licenses/>.  */
18 #include <sysdep.h>
19 #include <pointer_guard.h>
20 #include <jmpbuf-offsets.h>
21 #include <jmp_buf-ssp.h>
22 #include <asm-syntax.h>
23 #include <stap-probe.h>
25 /* Don't restore shadow stack register if shadow stack isn't enabled.  */
26 #if !SHSTK_ENABLED || defined DO_NOT_RESTORE_SHADOW_STACK
27 # undef SHADOW_STACK_POINTER_OFFSET
28 #endif
30 #ifndef CHECK_INVALID_LONGJMP
31 # define CHECK_INVALID_LONGJMP
32 #endif
34 /* Jump to the position specified by ENV, causing the
35    setjmp call there to return VAL, or 1 if VAL is 0.
36    void __longjmp (__jmp_buf env, int val).  */
37         .text
38 ENTRY(__longjmp)
39         /* Restore registers.  */
40         mov (JB_RSP*8)(%rdi),%R8_LP
41         mov (JB_RBP*8)(%rdi),%R9_LP
42         mov (JB_PC*8)(%rdi),%RDX_LP
43 #ifdef PTR_DEMANGLE
44         PTR_DEMANGLE (%R8_LP)
45         PTR_DEMANGLE (%R9_LP)
46         PTR_DEMANGLE (%RDX_LP)
47 # ifdef __ILP32__
48         /* We ignored the high bits of the %rbp value because only the low
49            bits are mangled.  But we cannot presume that %rbp is being used
50            as a pointer and truncate it, so recover the high bits.  */
51         movl (JB_RBP*8 + 4)(%rdi), %eax
52         shlq $32, %rax
53         orq %rax, %r9
54 # endif
55 #endif
57         CHECK_INVALID_LONGJMP
59 #ifdef SHADOW_STACK_POINTER_OFFSET
60 # if IS_IN (libc) && defined SHARED && defined FEATURE_1_OFFSET
61         /* Check if Shadow Stack is enabled.  */
62         testl $X86_FEATURE_1_SHSTK, %fs:FEATURE_1_OFFSET
63         jz L(skip_ssp)
64 # else
65         xorl %eax, %eax
66 # endif
67         /* Check and adjust the Shadow-Stack-Pointer.  */
68         /* Get the current ssp.  */
69         rdsspq %rax
70         /* Save the current ssp.  */
71         movq %rax, %r10
72         /* And compare it with the saved ssp value.  */
73         movq SHADOW_STACK_POINTER_OFFSET(%rdi), %rcx
74         subq %rcx, %rax
75         je L(skip_ssp)
77         /* Save the target ssp.  */
78         movq %rcx, %r11
80 L(find_restore_token_loop):
81         /* Look for a restore token.  */
82         movq -8(%rcx), %rbx
83         andq $-8, %rbx
84         cmpq %rcx, %rbx
85         /* Find the restore token.  */
86         je L(restore_shadow_stack)
88         /* Try the next slot.  */
89         subq $8, %rcx
90         /* Stop if the current ssp is found.  */
91         cmpq %rcx, %r10
92         jne L(find_restore_token_loop)
93         jmp L(no_shadow_stack_token)
95 L(restore_shadow_stack):
96         /* Restore the target shadow stack.  */
97         rstorssp -8(%rcx)
98         /* Save the restore token on the old shadow stack.  */
99         saveprevssp
100         rdsspq %rax
101         subq %r11, %rax
103 L(no_shadow_stack_token):
104         /* Count the number of frames to adjust and adjust it
105            with incssp instruction.  The instruction can adjust
106            the ssp by [0..255] value only thus use a loop if
107            the number of frames is bigger than 255.  */
108         negq %rax
109         shrq $3, %rax
110         /* NB: We saved Shadow-Stack-Pointer of setjmp.  Since we are
111                restoring Shadow-Stack-Pointer of setjmp's caller, we
112                need to unwind shadow stack by one more frame.  */
113         addq $1, %rax
115         movl $255, %ebx
116 L(loop):
117         cmpq %rbx, %rax
118         cmovb %rax, %rbx
119         incsspq %rbx
120         subq %rbx, %rax
121         ja L(loop)
123 L(skip_ssp):
124 #endif
125         LIBC_PROBE (longjmp, 3, LP_SIZE@%RDI_LP, -4@%esi, LP_SIZE@%RDX_LP)
126         /* We add unwind information for the target here.  */
127         cfi_def_cfa(%rdi, 0)
128         cfi_register(%rsp,%r8)
129         cfi_register(%rbp,%r9)
130         cfi_register(%rip,%rdx)
131         cfi_offset(%rbx,JB_RBX*8)
132         cfi_offset(%r12,JB_R12*8)
133         cfi_offset(%r13,JB_R13*8)
134         cfi_offset(%r14,JB_R14*8)
135         cfi_offset(%r15,JB_R15*8)
136         movq (JB_RBX*8)(%rdi),%rbx
137         movq (JB_R12*8)(%rdi),%r12
138         movq (JB_R13*8)(%rdi),%r13
139         movq (JB_R14*8)(%rdi),%r14
140         movq (JB_R15*8)(%rdi),%r15
141         /* Set return value for setjmp.  */
142         mov %esi, %eax
143         mov %R8_LP,%RSP_LP
144         movq %r9,%rbp
145         LIBC_PROBE (longjmp_target, 3,
146                     LP_SIZE@%RDI_LP, -4@%eax, LP_SIZE@%RDX_LP)
147         jmpq *%rdx
148 END (__longjmp)