]>
Commit | Line | Data |
---|---|---|
e3726b05 | 1 | /* longjmp for i386. |
6d7e8eda | 2 | Copyright (C) 1995-2023 Free Software Foundation, Inc. |
c57abfa7 | 3 | This file is part of the GNU C Library. |
e3726b05 | 4 | |
c57abfa7 | 5 | The GNU C Library is free software; you can redistribute it and/or |
41bdb6e2 AJ |
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. | |
e3726b05 | 9 | |
c57abfa7 UD |
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 | |
41bdb6e2 | 13 | Lesser General Public License for more details. |
e3726b05 | 14 | |
41bdb6e2 | 15 | You should have received a copy of the GNU Lesser General Public |
59ba27a6 | 16 | License along with the GNU C Library; if not, see |
5a82c748 | 17 | <https://www.gnu.org/licenses/>. */ |
e3726b05 RM |
18 | |
19 | #include <sysdep.h> | |
88f4b692 | 20 | #include <pointer_guard.h> |
a7140723 | 21 | #include <jmpbuf-offsets.h> |
faaee1f0 | 22 | #include <jmp_buf-ssp.h> |
e5f88e0c | 23 | #include <asm-syntax.h> |
8422c9a5 | 24 | #include <stap-probe.h> |
e3726b05 | 25 | |
faaee1f0 L |
26 | /* Don't restore shadow stack register if |
27 | 1. Shadow stack isn't enabled. Or | |
28 | 2. __longjmp is defined for __longjmp_cancel. | |
29 | */ | |
30 | #if !SHSTK_ENABLED || defined __longjmp | |
31 | # undef SHADOW_STACK_POINTER_OFFSET | |
32 | #endif | |
33 | ||
e7535de7 | 34 | .text |
da97dfdc | 35 | ENTRY (__longjmp) |
272b2898 | 36 | #ifdef PTR_DEMANGLE |
da97dfdc | 37 | movl 4(%esp), %eax /* User's jmp_buf in %eax. */ |
272b2898 | 38 | |
faaee1f0 L |
39 | # ifdef SHADOW_STACK_POINTER_OFFSET |
40 | # if IS_IN (libc) && defined SHARED && defined FEATURE_1_OFFSET | |
41 | /* Check if Shadow Stack is enabled. */ | |
42 | testl $X86_FEATURE_1_SHSTK, %gs:FEATURE_1_OFFSET | |
43 | jz L(skip_ssp) | |
44 | # else | |
45 | xorl %edx, %edx | |
46 | # endif | |
47 | /* Check and adjust the Shadow-Stack-Pointer. */ | |
48 | rdsspd %edx | |
49 | /* And compare it with the saved ssp value. */ | |
50 | subl SHADOW_STACK_POINTER_OFFSET(%eax), %edx | |
51 | je L(skip_ssp) | |
52 | /* Count the number of frames to adjust and adjust it | |
53 | with incssp instruction. The instruction can adjust | |
54 | the ssp by [0..255] value only thus use a loop if | |
55 | the number of frames is bigger than 255. */ | |
56 | negl %edx | |
57 | shrl $2, %edx | |
58 | /* NB: We saved Shadow-Stack-Pointer of setjmp. Since we are | |
59 | restoring Shadow-Stack-Pointer of setjmp's caller, we | |
60 | need to unwind shadow stack by one more frame. */ | |
61 | addl $1, %edx | |
62 | movl $255, %ebx | |
63 | L(loop): | |
64 | cmpl %ebx, %edx | |
65 | cmovb %edx, %ebx | |
66 | incsspd %ebx | |
67 | subl %ebx, %edx | |
68 | ja L(loop) | |
69 | L(skip_ssp): | |
70 | # endif | |
272b2898 UD |
71 | /* Save the return address now. */ |
72 | movl (JB_PC*4)(%eax), %edx | |
73 | /* Get the stack pointer. */ | |
74 | movl (JB_SP*4)(%eax), %ecx | |
75 | PTR_DEMANGLE (%edx) | |
76 | PTR_DEMANGLE (%ecx) | |
8422c9a5 | 77 | LIBC_PROBE (longjmp, 3, 4@%eax, -4@8(%esp), 4@%edx) |
272b2898 UD |
78 | cfi_def_cfa(%eax, 0) |
79 | cfi_register(%eip, %edx) | |
80 | cfi_register(%esp, %ecx) | |
81 | cfi_offset(%ebx, JB_BX*4) | |
82 | cfi_offset(%esi, JB_SI*4) | |
83 | cfi_offset(%edi, JB_DI*4) | |
84 | cfi_offset(%ebp, JB_BP*4) | |
350635a5 | 85 | /* Restore registers. */ |
272b2898 UD |
86 | movl (JB_BX*4)(%eax), %ebx |
87 | movl (JB_SI*4)(%eax), %esi | |
88 | movl (JB_DI*4)(%eax), %edi | |
89 | movl (JB_BP*4)(%eax), %ebp | |
90 | cfi_restore(%ebx) | |
91 | cfi_restore(%esi) | |
92 | cfi_restore(%edi) | |
93 | cfi_restore(%ebp) | |
94 | ||
8422c9a5 | 95 | LIBC_PROBE (longjmp_target, 3, 4@%eax, -4@8(%esp), 4@%edx) |
da97dfdc | 96 | movl 8(%esp), %eax /* Second argument is return value. */ |
272b2898 UD |
97 | movl %ecx, %esp |
98 | #else | |
da97dfdc | 99 | movl 4(%esp), %ecx /* User's jmp_buf in %ecx. */ |
da97dfdc | 100 | movl 8(%esp), %eax /* Second argument is return value. */ |
faaee1f0 L |
101 | # ifdef SHADOW_STACK_POINTER_OFFSET |
102 | # if IS_IN (libc) && defined SHARED | |
103 | /* Check if Shadow Stack is enabled. */ | |
104 | testl $X86_FEATURE_1_SHSTK, %gs:FEATURE_1_OFFSET | |
105 | jz L(skip_ssp) | |
106 | # endif | |
107 | /* Check and adjust the Shadow-Stack-Pointer. */ | |
108 | xorl %edx, %edx | |
109 | /* Get the current ssp. */ | |
110 | rdsspd %edx | |
111 | /* And compare it with the saved ssp value. */ | |
112 | subl SHADOW_STACK_POINTER_OFFSET(%ecx), %edx | |
113 | je L(skip_ssp) | |
114 | /* Count the number of frames to adjust and adjust it | |
115 | with incssp instruction. The instruction can adjust | |
116 | the ssp by [0..255] value only thus use a loop if | |
117 | the number of frames is bigger than 255. */ | |
118 | negl %edx | |
119 | shrl $2, %edx | |
120 | /* NB: We saved Shadow-Stack-Pointer of setjmp. Since we are | |
121 | restoring Shadow-Stack-Pointer of setjmp's caller, we | |
122 | need to unwind shadow stack by one more frame. */ | |
123 | addl $1, %edx | |
124 | movl $255, %ebx | |
125 | L(loop): | |
126 | cmpl %ebx, %edx | |
127 | cmovb %edx, %ebx | |
128 | incsspd %ebx | |
129 | subl %ebx, %edx | |
130 | ja L(loop) | |
131 | L(skip_ssp): | |
132 | # endif | |
14e9dd67 UD |
133 | /* Save the return address now. */ |
134 | movl (JB_PC*4)(%ecx), %edx | |
8422c9a5 | 135 | LIBC_PROBE (longjmp, 3, 4@%ecx, -4@%eax, 4@%edx) |
350635a5 | 136 | /* Restore registers. */ |
44c8d1a2 RM |
137 | movl (JB_BX*4)(%ecx), %ebx |
138 | movl (JB_SI*4)(%ecx), %esi | |
139 | movl (JB_DI*4)(%ecx), %edi | |
140 | movl (JB_BP*4)(%ecx), %ebp | |
141 | movl (JB_SP*4)(%ecx), %esp | |
8422c9a5 | 142 | LIBC_PROBE (longjmp_target, 3, 4@%ecx, -4@%ecx, 4@%edx) |
827b7087 | 143 | #endif |
e3726b05 | 144 | /* Jump to saved PC. */ |
350635a5 | 145 | jmp *%edx |
da97dfdc | 146 | END (__longjmp) |