]>
Commit | Line | Data |
---|---|---|
dff8da6b | 1 | /* Copyright (C) 2001-2024 Free Software Foundation, Inc. |
c9cf6dde AJ |
2 | This file is part of the GNU C Library. |
3 | ||
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. | |
8 | ||
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. | |
13 | ||
14 | You should have received a copy of the GNU Lesser General Public | |
59ba27a6 | 15 | License along with the GNU C Library; if not, see |
5a82c748 | 16 | <https://www.gnu.org/licenses/>. */ |
c9cf6dde AJ |
17 | |
18 | #include <sysdep.h> | |
88f4b692 | 19 | #include <pointer_guard.h> |
a7140723 | 20 | #include <jmpbuf-offsets.h> |
faaee1f0 | 21 | #include <jmp_buf-ssp.h> |
c9cf6dde | 22 | #include <asm-syntax.h> |
8422c9a5 | 23 | #include <stap-probe.h> |
c9cf6dde | 24 | |
faaee1f0 L |
25 | /* Don't restore shadow stack register if |
26 | 1. Shadow stack isn't enabled. Or | |
27 | 2. __longjmp is defined for __longjmp_cancel. | |
28 | */ | |
29 | #if !SHSTK_ENABLED || defined __longjmp | |
30 | # undef SHADOW_STACK_POINTER_OFFSET | |
31 | #endif | |
32 | ||
c9cf6dde AJ |
33 | /* Jump to the position specified by ENV, causing the |
34 | setjmp call there to return VAL, or 1 if VAL is 0. | |
35 | void __longjmp (__jmp_buf env, int val). */ | |
e7535de7 | 36 | .text |
c9cf6dde AJ |
37 | ENTRY(__longjmp) |
38 | /* Restore registers. */ | |
eda41706 | 39 | mov (JB_RSP*8)(%rdi),%R8_LP |
6c7fb145 | 40 | mov (JB_RBP*8)(%rdi),%R9_LP |
eda41706 | 41 | mov (JB_PC*8)(%rdi),%RDX_LP |
ff8fecbe | 42 | #ifdef PTR_DEMANGLE |
eda41706 | 43 | PTR_DEMANGLE (%R8_LP) |
6c7fb145 | 44 | PTR_DEMANGLE (%R9_LP) |
eda41706 | 45 | PTR_DEMANGLE (%RDX_LP) |
6c7fb145 RM |
46 | # ifdef __ILP32__ |
47 | /* We ignored the high bits of the %rbp value because only the low | |
48 | bits are mangled. But we cannot presume that %rbp is being used | |
49 | as a pointer and truncate it, so recover the high bits. */ | |
50 | movl (JB_RBP*8 + 4)(%rdi), %eax | |
51 | shlq $32, %rax | |
52 | orq %rax, %r9 | |
53 | # endif | |
faaee1f0 L |
54 | #endif |
55 | #ifdef SHADOW_STACK_POINTER_OFFSET | |
56 | # if IS_IN (libc) && defined SHARED && defined FEATURE_1_OFFSET | |
57 | /* Check if Shadow Stack is enabled. */ | |
58 | testl $X86_FEATURE_1_SHSTK, %fs:FEATURE_1_OFFSET | |
59 | jz L(skip_ssp) | |
60 | # else | |
61 | xorl %eax, %eax | |
62 | # endif | |
63 | /* Check and adjust the Shadow-Stack-Pointer. */ | |
64 | /* Get the current ssp. */ | |
65 | rdsspq %rax | |
66 | /* And compare it with the saved ssp value. */ | |
67 | subq SHADOW_STACK_POINTER_OFFSET(%rdi), %rax | |
68 | je L(skip_ssp) | |
69 | /* Count the number of frames to adjust and adjust it | |
70 | with incssp instruction. The instruction can adjust | |
71 | the ssp by [0..255] value only thus use a loop if | |
72 | the number of frames is bigger than 255. */ | |
73 | negq %rax | |
74 | shrq $3, %rax | |
75 | /* NB: We saved Shadow-Stack-Pointer of setjmp. Since we are | |
76 | restoring Shadow-Stack-Pointer of setjmp's caller, we | |
77 | need to unwind shadow stack by one more frame. */ | |
78 | addq $1, %rax | |
79 | ||
80 | movl $255, %ebx | |
81 | L(loop): | |
82 | cmpq %rbx, %rax | |
83 | cmovb %rax, %rbx | |
84 | incsspq %rbx | |
85 | subq %rbx, %rax | |
86 | ja L(loop) | |
87 | ||
88 | L(skip_ssp): | |
ff8fecbe | 89 | #endif |
8422c9a5 | 90 | LIBC_PROBE (longjmp, 3, LP_SIZE@%RDI_LP, -4@%esi, LP_SIZE@%RDX_LP) |
7e7458e3 AJ |
91 | /* We add unwind information for the target here. */ |
92 | cfi_def_cfa(%rdi, 0) | |
ff8fecbe UD |
93 | cfi_register(%rsp,%r8) |
94 | cfi_register(%rbp,%r9) | |
95 | cfi_register(%rip,%rdx) | |
7e7458e3 | 96 | cfi_offset(%rbx,JB_RBX*8) |
7e7458e3 AJ |
97 | cfi_offset(%r12,JB_R12*8) |
98 | cfi_offset(%r13,JB_R13*8) | |
99 | cfi_offset(%r14,JB_R14*8) | |
100 | cfi_offset(%r15,JB_R15*8) | |
c9cf6dde | 101 | movq (JB_RBX*8)(%rdi),%rbx |
c9cf6dde AJ |
102 | movq (JB_R12*8)(%rdi),%r12 |
103 | movq (JB_R13*8)(%rdi),%r13 | |
104 | movq (JB_R14*8)(%rdi),%r14 | |
105 | movq (JB_R15*8)(%rdi),%r15 | |
106 | /* Set return value for setjmp. */ | |
c9cf6dde | 107 | mov %esi, %eax |
eda41706 | 108 | mov %R8_LP,%RSP_LP |
ff8fecbe | 109 | movq %r9,%rbp |
8422c9a5 RM |
110 | LIBC_PROBE (longjmp_target, 3, |
111 | LP_SIZE@%RDI_LP, -4@%eax, LP_SIZE@%RDX_LP) | |
c9cf6dde | 112 | jmpq *%rdx |
5ead9ce5 | 113 | END (__longjmp) |