1#include "sanitizer_common/sanitizer_asm.h"
2
3// The content of this file is RISCV64-only:
4#if defined(__riscv) && (__riscv_xlen == 64)
5
6// The responsibility of the HWASan entry point in compiler-rt is to primarily
7// readjust the stack from the callee and save the current register values to
8// the stack.
9// This entry point function should be called from a __hwasan_check_* symbol.
10// These are generated during a lowering pass in the backend, and are found in
11// RISCVAsmPrinter::EmitHwasanMemaccessSymbols(). Please look there for
12// further information.
13// The __hwasan_check_* caller of this function should have expanded the stack
14// and saved the previous values of x10(arg0), x11(arg1), x1(ra), and x8(fp).
15// This function will "consume" these saved values and treats it as part of its
16// own stack frame. In this sense, the __hwasan_check_* callee and this function
17// "share" a stack frame. This allows us to omit having unwinding information
18// (.cfi_*) present in every __hwasan_check_* function, therefore reducing binary size.
19// This is particularly important as hwasan_check_* instances are duplicated in every
20// translation unit where HWASan is enabled.
21// This function calls HwasanTagMismatch to step back into the C++ code that
22// completes the stack unwinding and error printing. This function is is not
23// permitted to return.
24
25
26// |              ...                |
27// |              ...                |
28// | Previous stack frames...        |
29// +=================================+
30// |              ...                |
31// |                                 |
32// | Stack frame space for x12 - x31.|
33// |                                 |
34// |              ...                |
35// +---------------------------------+ <-- [SP + 96]
36// | Saved x11(arg1), as             |
37// | __hwasan_check_* clobbers it.   |
38// +---------------------------------+ <-- [SP + 88]
39// | Saved x10(arg0), as             |
40// | __hwasan_check_* clobbers it.   |
41// +---------------------------------+ <-- [SP + 80]
42// |                                 |
43// | Stack frame space for x9.       |
44// +---------------------------------+ <-- [SP + 72]
45// |                                 |
46// | Saved x8(fp), as                |
47// | __hwasan_check_* clobbers it.   |
48// +---------------------------------+ <-- [SP + 64]
49// |              ...                |
50// |                                 |
51// | Stack frame space for x2 - x7.  |
52// |                                 |
53// |              ...                |
54// +---------------------------------+ <-- [SP + 16]
55// | Return address (x1) for caller  |
56// | of __hwasan_check_*.            |
57// +---------------------------------+ <-- [SP + 8]
58// | Reserved place for x0, possibly |
59// | junk, since we don't save it.   |
60// +---------------------------------+ <-- [x2 / SP]
61
62// This function takes two arguments:
63//   * x10/a0: The data address.
64//   * x11/a1: The encoded access info for the failing access.
65
66.section .text
67.file "hwasan_tag_mismatch_riscv64.S"
68
69.global __hwasan_tag_mismatch_v2
70ASM_TYPE_FUNCTION(__hwasan_tag_mismatch_v2)
71__hwasan_tag_mismatch_v2:
72  CFI_STARTPROC
73
74  // Set the CFA to be the return address for caller of __hwasan_check_*. Note
75  // that we do not emit CFI predicates to describe the contents of this stack
76  // frame, as this proxy entry point should never be debugged. The contents
77  // are static and are handled by the unwinder after calling
78  // __hwasan_tag_mismatch. The frame pointer is already correctly setup
79  // by __hwasan_check_*.
80  addi fp, sp, 256
81  CFI_DEF_CFA(fp, 0)
82  CFI_OFFSET(ra, -248)
83  CFI_OFFSET(fp, -192)
84
85  // Save the rest of the registers into the preallocated space left by
86  // __hwasan_check.
87  sd x31, 248(sp)
88  sd x30, 240(sp)
89  sd x29, 232(sp)
90  sd x28, 224(sp)
91  sd x27, 216(sp)
92  sd x26, 208(sp)
93  sd x25, 200(sp)
94  sd x24, 192(sp)
95  sd x23, 184(sp)
96  sd x22, 176(sp)
97  sd x21, 168(sp)
98  sd x20, 160(sp)
99  sd x19, 152(sp)
100  sd x18, 144(sp)
101  sd x17, 136(sp)
102  sd x16, 128(sp)
103  sd x15, 120(sp)
104  sd x14, 112(sp)
105  sd x13, 104(sp)
106  sd x12, 96(sp)
107  // sd x11, 88(sp) ; already saved
108  // sd x10, 80(sp) ; already saved
109  sd x9, 72(sp)
110  // sd x8, 64(sp) ; already saved
111  sd x7, 56(sp)
112  sd x6, 48(sp)
113  sd x5, 40(sp)
114  sd x4, 32(sp)
115  sd x3, 24(sp)
116  sd x2, 16(sp)
117  // sd x1, 8(sp) ; already saved
118  // sd x0, 0(sp) ; don't store zero register
119
120  // Pass the address of the frame to __hwasan_tag_mismatch4, so that it can
121  // extract the saved registers from this frame without having to worry about
122  // finding this frame.
123  mv x12, sp
124
125  call __hwasan_tag_mismatch4
126  CFI_ENDPROC
127ASM_SIZE(__hwasan_tag_mismatch_v2)
128
129#endif  // defined(__riscv) && (__riscv_xlen == 64)
130
131// We do not need executable stack.
132NO_EXEC_STACK_DIRECTIVE
133