1351282Sdim#include "sanitizer_common/sanitizer_asm.h" 2351282Sdim 3351282Sdim// The content of this file is AArch64-only: 4351282Sdim#if defined(__aarch64__) 5351282Sdim 6351282Sdim// The responsibility of the HWASan entry point in compiler-rt is to primarily 7351282Sdim// readjust the stack from the callee and save the current register values to 8351282Sdim// the stack. 9351282Sdim// This entry point function should be called from a __hwasan_check_* symbol. 10351282Sdim// These are generated during a lowering pass in the backend, and are found in 11351282Sdim// AArch64AsmPrinter::EmitHwasanMemaccessSymbols(). Please look there for 12351282Sdim// further information. 13351282Sdim// The __hwasan_check_* caller of this function should have expanded the stack 14351282Sdim// and saved the previous values of x0, x1, x29, and x30. This function will 15351282Sdim// "consume" these saved values and treats it as part of its own stack frame. 16351282Sdim// In this sense, the __hwasan_check_* callee and this function "share" a stack 17351282Sdim// frame. This allows us to omit having unwinding information (.cfi_*) present 18351282Sdim// in every __hwasan_check_* function, therefore reducing binary size. This is 19351282Sdim// particularly important as hwasan_check_* instances are duplicated in every 20351282Sdim// translation unit where HWASan is enabled. 21351282Sdim// This function calls HwasanTagMismatch to step back into the C++ code that 22351282Sdim// completes the stack unwinding and error printing. This function is is not 23351282Sdim// permitted to return. 24351282Sdim 25351282Sdim 26351282Sdim// Frame from __hwasan_check_: 27351282Sdim// | ... | 28351282Sdim// | ... | 29351282Sdim// | Previous stack frames... | 30351282Sdim// +=================================+ 31351282Sdim// | Unused 8-bytes for maintaining | 32351282Sdim// | 16-byte SP alignment. | 33351282Sdim// +---------------------------------+ 34351282Sdim// | Return address (x30) for caller | 35351282Sdim// | of __hwasan_check_*. | 36351282Sdim// +---------------------------------+ 37351282Sdim// | Frame address (x29) for caller | 38351282Sdim// | of __hwasan_check_* | 39351282Sdim// +---------------------------------+ <-- [SP + 232] 40351282Sdim// | ... | 41351282Sdim// | | 42351282Sdim// | Stack frame space for x2 - x28. | 43351282Sdim// | | 44351282Sdim// | ... | 45351282Sdim// +---------------------------------+ <-- [SP + 16] 46351282Sdim// | | 47351282Sdim// | Saved x1, as __hwasan_check_* | 48351282Sdim// | clobbers it. | 49351282Sdim// +---------------------------------+ 50351282Sdim// | Saved x0, likewise above. | 51351282Sdim// +---------------------------------+ <-- [x30 / SP] 52351282Sdim 53351282Sdim// This function takes two arguments: 54360784Sdim// * x0: The data address. 55360784Sdim// * x1: The encoded access info for the failing access. 56351282Sdim 57360784Sdim// This function has two entry points. The first, __hwasan_tag_mismatch, is used 58360784Sdim// by clients that were compiled without short tag checks (i.e. binaries built 59360784Sdim// by older compilers and binaries targeting older runtimes). In this case the 60360784Sdim// outlined tag check will be missing the code handling short tags (which won't 61360784Sdim// be used in the binary's own stack variables but may be used on the heap 62360784Sdim// or stack variables in other binaries), so the check needs to be done here. 63360784Sdim// 64360784Sdim// The second, __hwasan_tag_mismatch_v2, is used by binaries targeting newer 65360784Sdim// runtimes. This entry point bypasses the short tag check since it will have 66360784Sdim// already been done as part of the outlined tag check. Since tag mismatches are 67360784Sdim// uncommon, there isn't a significant performance benefit to being able to 68360784Sdim// bypass the check; the main benefits are that we can sometimes avoid 69360784Sdim// clobbering the x17 register in error reports, and that the program will have 70360784Sdim// a runtime dependency on the __hwasan_tag_mismatch_v2 symbol therefore it will 71360784Sdim// fail to start up given an older (i.e. incompatible) runtime. 72351282Sdim.section .text 73351282Sdim.file "hwasan_tag_mismatch_aarch64.S" 74351282Sdim.global __hwasan_tag_mismatch 75351282Sdim.type __hwasan_tag_mismatch, %function 76351282Sdim__hwasan_tag_mismatch: 77360784Sdim // Compute the granule position one past the end of the access. 78360784Sdim mov x16, #1 79360784Sdim and x17, x1, #0xf 80360784Sdim lsl x16, x16, x17 81360784Sdim and x17, x0, #0xf 82360784Sdim add x17, x16, x17 83360784Sdim 84360784Sdim // Load the shadow byte again and check whether it is a short tag within the 85360784Sdim // range of the granule position computed above. 86360784Sdim ubfx x16, x0, #4, #52 87360784Sdim ldrb w16, [x9, x16] 88360784Sdim cmp w16, #0xf 89360784Sdim b.hi __hwasan_tag_mismatch_v2 90360784Sdim cmp w16, w17 91360784Sdim b.lo __hwasan_tag_mismatch_v2 92360784Sdim 93360784Sdim // Load the real tag from the last byte of the granule and compare against 94360784Sdim // the pointer tag. 95360784Sdim orr x16, x0, #0xf 96360784Sdim ldrb w16, [x16] 97360784Sdim cmp x16, x0, lsr #56 98360784Sdim b.ne __hwasan_tag_mismatch_v2 99360784Sdim 100360784Sdim // Restore x0, x1 and sp to their values from before the __hwasan_tag_mismatch 101360784Sdim // call and resume execution. 102360784Sdim ldp x0, x1, [sp], #256 103360784Sdim ret 104360784Sdim 105360784Sdim.global __hwasan_tag_mismatch_v2 106360784Sdim.type __hwasan_tag_mismatch_v2, %function 107360784Sdim__hwasan_tag_mismatch_v2: 108351282Sdim CFI_STARTPROC 109351282Sdim 110351282Sdim // Set the CFA to be the return address for caller of __hwasan_check_*. Note 111351282Sdim // that we do not emit CFI predicates to describe the contents of this stack 112351282Sdim // frame, as this proxy entry point should never be debugged. The contents 113351282Sdim // are static and are handled by the unwinder after calling 114351282Sdim // __hwasan_tag_mismatch. The frame pointer is already correctly setup 115351282Sdim // by __hwasan_check_*. 116351282Sdim add x29, sp, #232 117351282Sdim CFI_DEF_CFA(w29, 24) 118351282Sdim CFI_OFFSET(w30, -16) 119351282Sdim CFI_OFFSET(w29, -24) 120351282Sdim 121351282Sdim // Save the rest of the registers into the preallocated space left by 122351282Sdim // __hwasan_check. 123351282Sdim str x28, [sp, #224] 124351282Sdim stp x26, x27, [sp, #208] 125351282Sdim stp x24, x25, [sp, #192] 126351282Sdim stp x22, x23, [sp, #176] 127351282Sdim stp x20, x21, [sp, #160] 128351282Sdim stp x18, x19, [sp, #144] 129351282Sdim stp x16, x17, [sp, #128] 130351282Sdim stp x14, x15, [sp, #112] 131351282Sdim stp x12, x13, [sp, #96] 132351282Sdim stp x10, x11, [sp, #80] 133351282Sdim stp x8, x9, [sp, #64] 134351282Sdim stp x6, x7, [sp, #48] 135351282Sdim stp x4, x5, [sp, #32] 136351282Sdim stp x2, x3, [sp, #16] 137351282Sdim 138360784Sdim // Pass the address of the frame to __hwasan_tag_mismatch4, so that it can 139351282Sdim // extract the saved registers from this frame without having to worry about 140351282Sdim // finding this frame. 141351282Sdim mov x2, sp 142351282Sdim 143360784Sdim bl __hwasan_tag_mismatch4 144351282Sdim CFI_ENDPROC 145351282Sdim 146351282Sdim.Lfunc_end0: 147351282Sdim .size __hwasan_tag_mismatch, .Lfunc_end0-__hwasan_tag_mismatch 148351282Sdim 149351282Sdim#endif // defined(__aarch64__) 150351282Sdim 151351282Sdim// We do not need executable stack. 152351282SdimNO_EXEC_STACK_DIRECTIVE 153