• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *  * Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 *  * Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in
12 *    the documentation and/or other materials provided with the
13 *    distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <private/bionic_asm.h>
30#include <private/bionic_constants.h>
31
32// According to AARCH64 PCS document we need to save the following
33// registers:
34//
35// Core     x19 - x30, sp (see section 5.1.1)
36// VFP      d8 - d15 (see section 5.1.2)
37//
38// NOTE: All the registers saved here will have 64 bit vales.
39//       AAPCS mandates that the higher part of q registers do not need to
40//       be saved by the callee.
41//
42// The internal structure of a jmp_buf is totally private.
43// Current layout (changes from release to release):
44//
45// word   name            description
46// 0      sigflag/cookie  setjmp cookie in top 31 bits, signal mask flag in low bit
47// 1      sigmask         signal mask (not used with _setjmp / _longjmp)
48// 2      core_base       base of core registers (x18-x30, sp)
49// 16     float_base      base of float registers (d8-d15)
50// 24     checksum        checksum of core registers
51// 25     reserved        reserved entries (room to grow)
52// 32
53
54#define _JB_SIGFLAG     0
55#define _JB_SIGMASK     (_JB_SIGFLAG + 1)
56#define _JB_X30_SP      (_JB_SIGMASK + 1)
57#define _JB_X28_X29     (_JB_X30_SP  + 2)
58#define _JB_X26_X27     (_JB_X28_X29 + 2)
59#define _JB_X24_X25     (_JB_X26_X27 + 2)
60#define _JB_X22_X23     (_JB_X24_X25 + 2)
61#define _JB_X20_X21     (_JB_X22_X23 + 2)
62#define _JB_SCS_X19     (_JB_X20_X21 + 2)
63#define _JB_D14_D15     (_JB_SCS_X19 + 2)
64#define _JB_D12_D13     (_JB_D14_D15 + 2)
65#define _JB_D10_D11     (_JB_D12_D13 + 2)
66#define _JB_D8_D9       (_JB_D10_D11 + 2)
67#define _JB_CHECKSUM    (_JB_D8_D9 + 2)
68
69.macro m_mangle_registers reg, sp_reg
70  eor x3, x3, \reg
71  eor x19, x19, \reg
72  eor x20, x20, \reg
73  eor x21, x21, \reg
74  eor x22, x22, \reg
75  eor x23, x23, \reg
76  eor x24, x24, \reg
77  eor x25, x25, \reg
78  eor x26, x26, \reg
79  eor x27, x27, \reg
80  eor x28, x28, \reg
81  eor x29, x29, \reg
82  eor x30, x30, \reg
83  eor \sp_reg, \sp_reg, \reg
84.endm
85
86.macro m_calculate_checksum dst, src, scratch
87  mov \dst, #0
88  .irp i,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23
89    ldr \scratch, [\src, #(\i * 8)]
90    eor \dst, \dst, \scratch
91  .endr
92.endm
93
94.macro m_unmangle_registers reg, sp_reg
95  m_mangle_registers \reg, sp_reg=\sp_reg
96.endm
97
98ENTRY(setjmp)
99__BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(setjmp)
100  mov w1, #1
101  b sigsetjmp
102END(setjmp)
103
104ENTRY(_setjmp)
105__BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(_setjmp)
106  mov w1, #0
107  b sigsetjmp
108END(_setjmp)
109
110// int sigsetjmp(sigjmp_buf env, int save_signal_mask);
111ENTRY(sigsetjmp)
112__BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(sigsetjmp)
113  paciasp
114  .cfi_negate_ra_state
115  stp x0, x30, [sp, #-16]!
116  .cfi_def_cfa_offset 16
117  .cfi_rel_offset x0, 0
118  .cfi_rel_offset x30, 8
119
120  // Get the cookie and store it along with the signal flag.
121  mov x0, x1
122  bl __bionic_setjmp_cookie_get
123  mov x1, x0
124  ldr x0, [sp, #0]
125  str x1, [x0, #(_JB_SIGFLAG * 8)]
126
127  // Do we need to save the signal mask?
128  tbz w1, #0, 1f
129
130  // Save the cookie for later.
131  stp x1, xzr, [sp, #-16]!
132  .cfi_adjust_cfa_offset 16
133
134  // Save current signal mask.
135  // The 'how' argument is ignored if new_mask is NULL.
136  mov x1, #0 // NULL.
137  add x2, x0, #(_JB_SIGMASK * 8) // old_mask.
138  bl sigprocmask
139
140  ldp x1, xzr, [sp], #16
141  .cfi_adjust_cfa_offset -16
142
1431:
144  // Restore original x0 and lr.
145  ldp x0, x30, [sp], #16
146  .cfi_adjust_cfa_offset -16
147  .cfi_restore x0
148  .cfi_restore x30
149
150  // Mask off the signal flag bit.
151  bic x1, x1, #1
152
153  // Mask off the high bits of the shadow call stack pointer.
154  // We only store the low bits of x18 to avoid leaking the
155  // shadow call stack address into memory.
156  // See the SCS commentary in pthread_internal.h for more detail.
157  and x3, x18, #SCS_MASK
158
159  // Save core registers.
160  mov x10, sp
161  m_mangle_registers x1, sp_reg=x10
162  stp x30, x10, [x0, #(_JB_X30_SP  * 8)]
163  stp x28, x29, [x0, #(_JB_X28_X29 * 8)]
164  stp x26, x27, [x0, #(_JB_X26_X27 * 8)]
165  stp x24, x25, [x0, #(_JB_X24_X25 * 8)]
166  stp x22, x23, [x0, #(_JB_X22_X23 * 8)]
167  stp x20, x21, [x0, #(_JB_X20_X21 * 8)]
168  stp x3,  x19, [x0, #(_JB_SCS_X19 * 8)]
169  m_unmangle_registers x1, sp_reg=x10
170
171  // Save floating point registers.
172  stp d14, d15, [x0, #(_JB_D14_D15 * 8)]
173  stp d12, d13, [x0, #(_JB_D12_D13 * 8)]
174  stp d10, d11, [x0, #(_JB_D10_D11 * 8)]
175  stp d8,  d9,  [x0, #(_JB_D8_D9   * 8)]
176
177  // Calculate the checksum.
178  m_calculate_checksum x12, x0, x2
179  str x12, [x0, #(_JB_CHECKSUM * 8)]
180
181  mov w0, #0
182  autiasp
183  .cfi_negate_ra_state
184  ret
185END(sigsetjmp)
186
187// void siglongjmp(sigjmp_buf env, int value);
188ENTRY(siglongjmp)
189__BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(siglongjmp)
190  // Check the checksum before doing anything.
191  m_calculate_checksum x12, x0, x2
192  ldr x2, [x0, #(_JB_CHECKSUM * 8)]
193  cmp x2, x12
194  bne __bionic_setjmp_checksum_mismatch
195
196  // Update stack memory tags (MTE + hwasan).
197  stp x0, x30, [sp, #-16]!
198  .cfi_adjust_cfa_offset 16
199  .cfi_rel_offset x0, 0
200  .cfi_rel_offset x30, 8
201  mov x19, x1 // Save 'value'.
202
203  // load and unmangle destination SP
204  ldr x2, [x0, #(_JB_SIGFLAG * 8)]
205  bic x2, x2, #1
206  ldr x0, [x0, #(_JB_X30_SP  * 8 + 8)]
207  eor x0, x0, x2
208  bl memtag_handle_longjmp
209
210  mov x1, x19 // Restore 'value'.
211  // Restore original x0 and lr.
212  ldp x0, x30, [sp], #16
213  .cfi_adjust_cfa_offset -16
214  .cfi_restore x0
215  .cfi_restore x30
216
217  // Do we need to restore the signal mask?
218  ldr x2, [x0, #(_JB_SIGFLAG * 8)]
219  tbz w2, #0, 1f
220
221  stp x0, x30, [sp, #-16]!
222  .cfi_adjust_cfa_offset 16
223  .cfi_rel_offset x0, 0
224  .cfi_rel_offset x30, 8
225
226  // Restore signal mask.
227  mov x19, x1 // Save 'value'.
228
229  mov x2, x0
230  mov x0, #2 // SIG_SETMASK
231  add x1, x2, #(_JB_SIGMASK * 8) // new_mask.
232  mov x2, #0 // NULL.
233  bl sigprocmask
234  mov x1, x19 // Restore 'value'.
235
236  // Restore original x0 and lr.
237  ldp x0, x30, [sp], #16
238  .cfi_adjust_cfa_offset -16
239  .cfi_restore x0
240  .cfi_restore x30
241
242  ldr x2, [x0, #(_JB_SIGFLAG * 8)]
2431:
244  // Restore core registers.
245  bic x2, x2, #1
246  // x30 was saved with PAC to jmp_buf in sigsetjmp().
247  ldp x30, x10, [x0, #(_JB_X30_SP  * 8)]
248  .cfi_negate_ra_state
249  ldp x28, x29, [x0, #(_JB_X28_X29 * 8)]
250  ldp x26, x27, [x0, #(_JB_X26_X27 * 8)]
251  ldp x24, x25, [x0, #(_JB_X24_X25 * 8)]
252  ldp x22, x23, [x0, #(_JB_X22_X23 * 8)]
253  ldp x20, x21, [x0, #(_JB_X20_X21 * 8)]
254  ldp x3,  x19, [x0, #(_JB_SCS_X19 * 8)]
255  m_unmangle_registers x2, sp_reg=x10
256  mov sp, x10
257
258  // Restore the low bits of the shadow call stack pointer.
259  and x18, x18, #~SCS_MASK
260  orr x18, x3, x18
261
262  stp x0, x1, [sp, #-16]!
263  .cfi_adjust_cfa_offset 16
264  .cfi_rel_offset x0, 0
265  .cfi_rel_offset x1, 8
266  stp x30, xzr, [sp, #-16]!
267  .cfi_adjust_cfa_offset 16
268  .cfi_rel_offset x30, 0
269  ldr x0, [x0, #(_JB_SIGFLAG * 8)]
270  bl __bionic_setjmp_cookie_check
271  ldp x30, xzr, [sp], #16
272  .cfi_adjust_cfa_offset -16
273  .cfi_restore x30
274  ldp x0, x1, [sp], #16
275  .cfi_adjust_cfa_offset -16
276  .cfi_restore x0
277  .cfi_restore x1
278
279  // Restore floating point registers.
280  ldp d14, d15, [x0, #(_JB_D14_D15 * 8)]
281  ldp d12, d13, [x0, #(_JB_D12_D13 * 8)]
282  ldp d10, d11, [x0, #(_JB_D10_D11 * 8)]
283  ldp d8,  d9,  [x0, #(_JB_D8_D9   * 8)]
284
285  // Set return value.
286  cmp w1, wzr
287  csinc w0, w1, wzr, ne
288  autiasp
289  .cfi_negate_ra_state
290  ret
291END(siglongjmp)
292
293ALIAS_SYMBOL(longjmp, siglongjmp)
294__BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(longjmp)
295ALIAS_SYMBOL(_longjmp, siglongjmp)
296__BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(_longjmp)
297
298NOTE_GNU_PROPERTY()
299