1#include "sanitizer_common/sanitizer_asm.h"
2#include "builtins/assembly.h"
3
4// The content of this file is AArch64-only:
5#if defined(__aarch64__)
6
7// The responsibility of the HWASan entry point in compiler-rt is to primarily
8// readjust the stack from the callee and save the current register values to
9// the stack.
10// This entry point function should be called from a __hwasan_check_* symbol.
11// These are generated during a lowering pass in the backend, and are found in
12// AArch64AsmPrinter::EmitHwasanMemaccessSymbols(). Please look there for
13// further information.
14// The __hwasan_check_* caller of this function should have expanded the stack
15// and saved the previous values of x0, x1, x29, and x30. This function will
16// "consume" these saved values and treats it as part of its own stack frame.
17// In this sense, the __hwasan_check_* callee and this function "share" a stack
18// frame. This allows us to omit having unwinding information (.cfi_*) present
19// in every __hwasan_check_* function, therefore reducing binary size. This is
20// particularly important as hwasan_check_* instances are duplicated in every
21// translation unit where HWASan is enabled.
22// This function calls HwasanTagMismatch to step back into the C++ code that
23// completes the stack unwinding and error printing. This function is is not
24// permitted to return.
25
26
27// Frame from __hwasan_check_:
28// |              ...                |
29// |              ...                |
30// | Previous stack frames...        |
31// +=================================+
32// | Unused 8-bytes for maintaining  |
33// | 16-byte SP alignment.           |
34// +---------------------------------+
35// | Return address (x30) for caller |
36// | of __hwasan_check_*.            |
37// +---------------------------------+
38// | Frame address (x29) for caller  |
39// | of __hwasan_check_*             |
40// +---------------------------------+ <-- [SP + 232]
41// |              ...                |
42// |                                 |
43// | Stack frame space for x2 - x28. |
44// |                                 |
45// |              ...                |
46// +---------------------------------+ <-- [SP + 16]
47// |                                 |
48// | Saved x1, as __hwasan_check_*   |
49// | clobbers it.                    |
50// +---------------------------------+
51// | Saved x0, likewise above.       |
52// +---------------------------------+ <-- [x30 / SP]
53
54// This function takes two arguments:
55//   * x0: The data address.
56//   * x1: The encoded access info for the failing access.
57
58// This function has two entry points. The first, __hwasan_tag_mismatch, is used
59// by clients that were compiled without short tag checks (i.e. binaries built
60// by older compilers and binaries targeting older runtimes). In this case the
61// outlined tag check will be missing the code handling short tags (which won't
62// be used in the binary's own stack variables but may be used on the heap
63// or stack variables in other binaries), so the check needs to be done here.
64//
65// The second, __hwasan_tag_mismatch_v2, is used by binaries targeting newer
66// runtimes. This entry point bypasses the short tag check since it will have
67// already been done as part of the outlined tag check. Since tag mismatches are
68// uncommon, there isn't a significant performance benefit to being able to
69// bypass the check; the main benefits are that we can sometimes avoid
70// clobbering the x17 register in error reports, and that the program will have
71// a runtime dependency on the __hwasan_tag_mismatch_v2 symbol therefore it will
72// fail to start up given an older (i.e. incompatible) runtime.
73.section .text
74.file "hwasan_tag_mismatch_aarch64.S"
75.global __hwasan_tag_mismatch
76.type __hwasan_tag_mismatch, %function
77__hwasan_tag_mismatch:
78  BTI_J
79
80  // Compute the granule position one past the end of the access.
81  mov x16, #1
82  and x17, x1, #0xf
83  lsl x16, x16, x17
84  and x17, x0, #0xf
85  add x17, x16, x17
86
87  // Load the shadow byte again and check whether it is a short tag within the
88  // range of the granule position computed above.
89  ubfx x16, x0, #4, #52
90  ldrb w16, [x9, x16]
91  cmp w16, #0xf
92  b.hi __hwasan_tag_mismatch_v2
93  cmp w16, w17
94  b.lo __hwasan_tag_mismatch_v2
95
96  // Load the real tag from the last byte of the granule and compare against
97  // the pointer tag.
98  orr x16, x0, #0xf
99  ldrb w16, [x16]
100  cmp x16, x0, lsr #56
101  b.ne __hwasan_tag_mismatch_v2
102
103  // Restore x0, x1 and sp to their values from before the __hwasan_tag_mismatch
104  // call and resume execution.
105  ldp x0, x1, [sp], #256
106  ret
107
108.global __hwasan_tag_mismatch_v2
109.type __hwasan_tag_mismatch_v2, %function
110__hwasan_tag_mismatch_v2:
111  CFI_STARTPROC
112  BTI_J
113
114  // Set the CFA to be the return address for caller of __hwasan_check_*. Note
115  // that we do not emit CFI predicates to describe the contents of this stack
116  // frame, as this proxy entry point should never be debugged. The contents
117  // are static and are handled by the unwinder after calling
118  // __hwasan_tag_mismatch. The frame pointer is already correctly setup
119  // by __hwasan_check_*.
120  add x29, sp, #232
121  CFI_DEF_CFA(w29, 24)
122  CFI_OFFSET(w30, -16)
123  CFI_OFFSET(w29, -24)
124
125  // Save the rest of the registers into the preallocated space left by
126  // __hwasan_check.
127  str     x28,      [sp, #224]
128  stp     x26, x27, [sp, #208]
129  stp     x24, x25, [sp, #192]
130  stp     x22, x23, [sp, #176]
131  stp     x20, x21, [sp, #160]
132  stp     x18, x19, [sp, #144]
133  stp     x16, x17, [sp, #128]
134  stp     x14, x15, [sp, #112]
135  stp     x12, x13, [sp, #96]
136  stp     x10, x11, [sp, #80]
137  stp     x8,  x9,  [sp, #64]
138  stp     x6,  x7,  [sp, #48]
139  stp     x4,  x5,  [sp, #32]
140  stp     x2,  x3,  [sp, #16]
141
142  // Pass the address of the frame to __hwasan_tag_mismatch4, so that it can
143  // extract the saved registers from this frame without having to worry about
144  // finding this frame.
145  mov x2, sp
146
147  bl __hwasan_tag_mismatch4
148  CFI_ENDPROC
149
150.Lfunc_end0:
151  .size __hwasan_tag_mismatch, .Lfunc_end0-__hwasan_tag_mismatch
152
153#endif  // defined(__aarch64__)
154
155// We do not need executable stack.
156NO_EXEC_STACK_DIRECTIVE
157
158GNU_PROPERTY_BTI_PAC
159