Skip to content

Commit b3e219b

Browse files
committed
[hwasan] Add intrinsics for fixed shadow on Aarch64
This separates out the first half of "Optimize outlined memaccess for fixed shadow on Aarch64" (llvm#88544). This patch does not meaningfully affect the behavior of HWASan, since the second half of that patch has the changes that will make HWASan use these intrinsics. This patch introduces HWASan memaccess intrinsics that assume a fixed shadow (with the offset provided by --hwasan-mapping-offset=...), with and without short granule support. We currently only support lowering the LLVM IR intrinsic to AArch64. The test case is adapted from hwasan-check-memaccess.ll.
1 parent b8adf16 commit b3e219b

File tree

6 files changed

+226
-9
lines changed

6 files changed

+226
-9
lines changed

llvm/include/llvm/IR/Intrinsics.td

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2362,13 +2362,32 @@ def int_load_relative: DefaultAttrsIntrinsic<[llvm_ptr_ty], [llvm_ptr_ty, llvm_a
23622362
def int_asan_check_memaccess :
23632363
Intrinsic<[],[llvm_ptr_ty, llvm_i32_ty], [ImmArg<ArgIndex<1>>]>;
23642364

2365+
// HWASan intrinsics to test whether a pointer is addressable.
2366+
// Parameters: Shadow base, pointer to be checked for validity, AccessInfo
2367+
// (AccessInfo is defined in HWAddressSanitizer.h)
23652368
def int_hwasan_check_memaccess :
23662369
Intrinsic<[], [llvm_ptr_ty, llvm_ptr_ty, llvm_i32_ty],
23672370
[ImmArg<ArgIndex<2>>]>;
2371+
2372+
// Same as memaccess but supports short granule checks.
2373+
// Parameters: Shadow base, pointer to be checked for validity, AccessInfo
23682374
def int_hwasan_check_memaccess_shortgranules :
23692375
Intrinsic<[], [llvm_ptr_ty, llvm_ptr_ty, llvm_i32_ty],
23702376
[ImmArg<ArgIndex<2>>]>;
23712377

2378+
// Same as memaccess but assumes a fixed shadow offset,
2379+
// which no longer needs to be passed as a parameter.
2380+
// Parameters: Pointer to be checked for validity, AccessInfo
2381+
def int_hwasan_check_memaccess_fixedshadow :
2382+
Intrinsic<[], [llvm_ptr_ty, llvm_i32_ty],
2383+
[ImmArg<ArgIndex<1>>]>;
2384+
2385+
// Same as memaccess but supports short granule checks and assumes a fixed
2386+
// shadow offset, which no longer needs to be passed as a parameter.
2387+
def int_hwasan_check_memaccess_shortgranules_fixedshadow :
2388+
Intrinsic<[], [llvm_ptr_ty, llvm_i32_ty],
2389+
[ImmArg<ArgIndex<1>>]>;
2390+
23722391
// Xray intrinsics
23732392
//===----------------------------------------------------------------------===//
23742393
// Custom event logging for x-ray.

llvm/include/llvm/Transforms/Instrumentation/HWAddressSanitizer.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ enum { RuntimeMask = 0xffff };
6767

6868
} // namespace HWASanAccessInfo
6969

70+
std::optional<unsigned long long> getFixedShadowBase(void);
71+
7072
} // namespace llvm
7173

7274
#endif

llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
#include <cstdint>
6565
#include <map>
6666
#include <memory>
67+
#include <optional>
6768

6869
using namespace llvm;
6970

@@ -117,6 +118,7 @@ class AArch64AsmPrinter : public AsmPrinter {
117118
void LowerPATCHABLE_EVENT_CALL(const MachineInstr &MI, bool Typed);
118119

119120
typedef std::tuple<unsigned, bool, uint32_t> HwasanMemaccessTuple;
121+
std::optional<unsigned long long> HwasanFixedShadowBase = std::nullopt;
120122
std::map<HwasanMemaccessTuple, MCSymbol *> HwasanMemaccessSymbols;
121123
void LowerKCFI_CHECK(const MachineInstr &MI);
122124
void LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI);
@@ -551,8 +553,16 @@ void AArch64AsmPrinter::LowerKCFI_CHECK(const MachineInstr &MI) {
551553
void AArch64AsmPrinter::LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI) {
552554
Register Reg = MI.getOperand(0).getReg();
553555
bool IsShort =
554-
MI.getOpcode() == AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES;
556+
((MI.getOpcode() == AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES) ||
557+
(MI.getOpcode() ==
558+
AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES_FIXEDSHADOW));
555559
uint32_t AccessInfo = MI.getOperand(1).getImm();
560+
561+
if ((MI.getOpcode() == AArch64::HWASAN_CHECK_MEMACCESS_FIXEDSHADOW) ||
562+
(MI.getOpcode() ==
563+
AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES_FIXEDSHADOW))
564+
HwasanFixedShadowBase = getFixedShadowBase();
565+
556566
MCSymbol *&Sym =
557567
HwasanMemaccessSymbols[HwasanMemaccessTuple(Reg, IsShort, AccessInfo)];
558568
if (!Sym) {
@@ -625,14 +635,32 @@ void AArch64AsmPrinter::emitHwasanMemaccessSymbols(Module &M) {
625635
.addImm(4)
626636
.addImm(55),
627637
*STI);
628-
OutStreamer->emitInstruction(
629-
MCInstBuilder(AArch64::LDRBBroX)
630-
.addReg(AArch64::W16)
631-
.addReg(IsShort ? AArch64::X20 : AArch64::X9)
632-
.addReg(AArch64::X16)
633-
.addImm(0)
634-
.addImm(0),
635-
*STI);
638+
639+
if (HwasanFixedShadowBase.has_value()) {
640+
OutStreamer->emitInstruction(
641+
MCInstBuilder(AArch64::MOVZXi)
642+
.addReg(AArch64::X17)
643+
.addImm(HwasanFixedShadowBase.value() >> 32)
644+
.addImm(32),
645+
*STI);
646+
OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDRBBroX)
647+
.addReg(AArch64::W16)
648+
.addReg(AArch64::X17)
649+
.addReg(AArch64::X16)
650+
.addImm(0)
651+
.addImm(0),
652+
*STI);
653+
} else {
654+
OutStreamer->emitInstruction(
655+
MCInstBuilder(AArch64::LDRBBroX)
656+
.addReg(AArch64::W16)
657+
.addReg(IsShort ? AArch64::X20 : AArch64::X9)
658+
.addReg(AArch64::X16)
659+
.addImm(0)
660+
.addImm(0),
661+
*STI);
662+
}
663+
636664
OutStreamer->emitInstruction(
637665
MCInstBuilder(AArch64::SUBSXrs)
638666
.addReg(AArch64::XZR)
@@ -1765,6 +1793,8 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) {
17651793

17661794
case AArch64::HWASAN_CHECK_MEMACCESS:
17671795
case AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES:
1796+
case AArch64::HWASAN_CHECK_MEMACCESS_FIXEDSHADOW:
1797+
case AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES_FIXEDSHADOW:
17681798
LowerHWASAN_CHECK_MEMACCESS(*MI);
17691799
return;
17701800

llvm/lib/Target/AArch64/AArch64InstrInfo.td

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1818,6 +1818,20 @@ def HWASAN_CHECK_MEMACCESS_SHORTGRANULES : Pseudo<
18181818
Sched<[]>;
18191819
}
18201820

1821+
let Defs = [ X16, X17, LR, NZCV ] in {
1822+
def HWASAN_CHECK_MEMACCESS_FIXEDSHADOW : Pseudo<
1823+
(outs), (ins GPR64noip:$ptr, i32imm:$accessinfo),
1824+
[(int_hwasan_check_memaccess_fixedshadow GPR64noip:$ptr, (i32 timm:$accessinfo))]>,
1825+
Sched<[]>;
1826+
}
1827+
1828+
let Defs = [ X16, X17, LR, NZCV ] in {
1829+
def HWASAN_CHECK_MEMACCESS_SHORTGRANULES_FIXEDSHADOW : Pseudo<
1830+
(outs), (ins GPR64noip:$ptr, i32imm:$accessinfo),
1831+
[(int_hwasan_check_memaccess_shortgranules_fixedshadow GPR64noip:$ptr, (i32 timm:$accessinfo))]>,
1832+
Sched<[]>;
1833+
}
1834+
18211835
// The virtual cycle counter register is CNTVCT_EL0.
18221836
def : Pat<(readcyclecounter), (MRS 0xdf02)>;
18231837

llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,14 @@ class HWAddressSanitizer {
448448

449449
} // end anonymous namespace
450450

451+
namespace llvm {
452+
std::optional<unsigned long long> getFixedShadowBase(void) {
453+
if (ClMappingOffset.getNumOccurrences() > 0)
454+
return ClMappingOffset;
455+
return std::nullopt;
456+
}
457+
} // namespace llvm
458+
451459
PreservedAnalyses HWAddressSanitizerPass::run(Module &M,
452460
ModuleAnalysisManager &MAM) {
453461
const StackSafetyGlobalInfo *SSI = nullptr;
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
; RUN: llc --hwasan-mapping-offset=4398046511104 < %s | FileCheck %s
2+
3+
target triple = "aarch64--linux-android"
4+
5+
define ptr @f1(ptr %x0, ptr %x1) {
6+
; CHECK: f1:
7+
; CHECK: str x30, [sp, #-16]!
8+
; CHECK-NEXT: .cfi_def_cfa_offset 16
9+
; CHECK-NEXT: .cfi_offset w30, -16
10+
; CHECK-NEXT: bl __hwasan_check_x1_1
11+
; CHECK-NEXT: mov x0, x1
12+
; CHECK-NEXT: ldr x30, [sp], #16
13+
; CHECK-NEXT: ret
14+
call void @llvm.hwasan.check.memaccess.fixedshadow(ptr %x1, i32 1)
15+
ret ptr %x1
16+
}
17+
18+
define ptr @f2(ptr %x0, ptr %x1) {
19+
; CHECK: f2:
20+
; CHECK: str x30, [sp, #-16]!
21+
; CHECK-NEXT: .cfi_def_cfa_offset 16
22+
; CHECK-NEXT: .cfi_offset w30, -16
23+
; CHECK-NEXT: bl __hwasan_check_x0_2_short_v2
24+
; CHECK-NEXT: ldr x30, [sp], #16
25+
; CHECK-NEXT: ret
26+
call void @llvm.hwasan.check.memaccess.shortgranules.fixedshadow(ptr %x0, i32 2)
27+
ret ptr %x0
28+
}
29+
30+
define void @f3(ptr %x0, ptr %x1) {
31+
; 0x3ff0000 (kernel, match-all = 0xff)
32+
call void @llvm.hwasan.check.memaccess.fixedshadow(ptr %x1, i32 67043328)
33+
ret void
34+
}
35+
36+
define void @f4(ptr %x0, ptr %x1) {
37+
; 0x1000010 (access-size-index = 0, is-write = 1, match-all = 0x0)
38+
call void @llvm.hwasan.check.memaccess.shortgranules.fixedshadow(ptr %x1, i32 16777232)
39+
ret void
40+
}
41+
42+
declare void @llvm.hwasan.check.memaccess.fixedshadow(ptr, i32)
43+
declare void @llvm.hwasan.check.memaccess.shortgranules.fixedshadow(ptr, i32)
44+
45+
; CHECK: .section .text.hot,"axG",@progbits,__hwasan_check_x0_2_short_v2,comdat
46+
; CHECK-NEXT: .type __hwasan_check_x0_2_short_v2,@function
47+
; CHECK-NEXT: .weak __hwasan_check_x0_2_short_v2
48+
; CHECK-NEXT: .hidden __hwasan_check_x0_2_short_v2
49+
; CHECK-NEXT: __hwasan_check_x0_2_short_v2:
50+
; CHECK-NEXT: sbfx x16, x0, #4, #52
51+
; CHECK-NEXT: mov x17, #4398046511104
52+
; CHECK-NEXT: ldrb w16, [x17, x16]
53+
; CHECK-NEXT: cmp x16, x0, lsr #56
54+
; CHECK-NEXT: b.ne .Ltmp0
55+
; CHECK-NEXT: .Ltmp1:
56+
; CHECK-NEXT: ret
57+
; CHECK-NEXT: .Ltmp0:
58+
; CHECK-NEXT: cmp w16, #15
59+
; CHECK-NEXT: b.hi .Ltmp2
60+
; CHECK-NEXT: and x17, x0, #0xf
61+
; CHECK-NEXT: add x17, x17, #3
62+
; CHECK-NEXT: cmp w16, w17
63+
; CHECK-NEXT: b.ls .Ltmp2
64+
; CHECK-NEXT: orr x16, x0, #0xf
65+
; CHECK-NEXT: ldrb w16, [x16]
66+
; CHECK-NEXT: cmp x16, x0, lsr #56
67+
; CHECK-NEXT: b.eq .Ltmp1
68+
; CHECK-NEXT: .Ltmp2:
69+
; CHECK-NEXT: stp x0, x1, [sp, #-256]!
70+
; CHECK-NEXT: stp x29, x30, [sp, #232]
71+
; CHECK-NEXT: mov x1, #2
72+
; CHECK-NEXT: adrp x16, :got:__hwasan_tag_mismatch_v2
73+
; CHECK-NEXT: ldr x16, [x16, :got_lo12:__hwasan_tag_mismatch_v2]
74+
; CHECK-NEXT: br x16
75+
76+
77+
; CHECK: .section .text.hot,"axG",@progbits,__hwasan_check_x1_1,comdat
78+
; CHECK-NEXT: .type __hwasan_check_x1_1,@function
79+
; CHECK-NEXT: .weak __hwasan_check_x1_1
80+
; CHECK-NEXT: .hidden __hwasan_check_x1_1
81+
; CHECK-NEXT: __hwasan_check_x1_1:
82+
; CHECK-NEXT: sbfx x16, x1, #4, #52
83+
; CHECK-NEXT: mov x17, #4398046511104
84+
; CHECK-NEXT: ldrb w16, [x17, x16]
85+
; CHECK-NEXT: cmp x16, x1, lsr #56
86+
; CHECK-NEXT: b.ne .Ltmp3
87+
; CHECK-NEXT: .Ltmp4:
88+
; CHECK-NEXT: ret
89+
; CHECK-NEXT: .Ltmp3:
90+
; CHECK-NEXT: stp x0, x1, [sp, #-256]!
91+
; CHECK-NEXT: stp x29, x30, [sp, #232]
92+
; CHECK-NEXT: mov x0, x1
93+
; CHECK-NEXT: mov x1, #1
94+
; CHECK-NEXT: adrp x16, :got:__hwasan_tag_mismatch
95+
; CHECK-NEXT: ldr x16, [x16, :got_lo12:__hwasan_tag_mismatch]
96+
; CHECK-NEXT: br x16
97+
98+
; CHECK: __hwasan_check_x1_67043328:
99+
; CHECK-NEXT: sbfx x16, x1, #4, #52
100+
; CHECK-NEXT: mov x17, #4398046511104
101+
; CHECK-NEXT: ldrb w16, [x17, x16]
102+
; CHECK-NEXT: cmp x16, x1, lsr #56
103+
; CHECK-NEXT: b.ne .Ltmp5
104+
; CHECK-NEXT: .Ltmp6:
105+
; CHECK-NEXT: ret
106+
; CHECK-NEXT: .Ltmp5:
107+
; CHECK-NEXT: lsr x17, x1, #56
108+
; CHECK-NEXT: cmp x17, #255
109+
; CHECK-NEXT: b.eq .Ltmp6
110+
; CHECK-NEXT: stp x0, x1, [sp, #-256]!
111+
; CHECK-NEXT: stp x29, x30, [sp, #232]
112+
; CHECK-NEXT: mov x0, x1
113+
; CHECK-NEXT: mov x1, #0
114+
; CHECK-NEXT: b __hwasan_tag_mismatch
115+
116+
; CHECK: __hwasan_check_x1_16777232_short_v2:
117+
; CHECK-NEXT: sbfx x16, x1, #4, #52
118+
; CHECK-NEXT: mov x17, #4398046511104
119+
; CHECK-NEXT: ldrb w16, [x17, x16]
120+
; CHECK-NEXT: cmp x16, x1, lsr #56
121+
; CHECK-NEXT: b.ne .Ltmp7
122+
; CHECK-NEXT: .Ltmp8:
123+
; CHECK-NEXT: ret
124+
; CHECK-NEXT: .Ltmp7:
125+
; CHECK-NEXT: lsr x17, x1, #56
126+
; CHECK-NEXT: cmp x17, #0
127+
; CHECK-NEXT: b.eq .Ltmp8
128+
; CHECK-NEXT: cmp w16, #15
129+
; CHECK-NEXT: b.hi .Ltmp9
130+
; CHECK-NEXT: and x17, x1, #0xf
131+
; CHECK-NEXT: cmp w16, w17
132+
; CHECK-NEXT: b.ls .Ltmp9
133+
; CHECK-NEXT: orr x16, x1, #0xf
134+
; CHECK-NEXT: ldrb w16, [x16]
135+
; CHECK-NEXT: cmp x16, x1, lsr #56
136+
; CHECK-NEXT: b.eq .Ltmp8
137+
; CHECK-NEXT: .Ltmp9:
138+
; CHECK-NEXT: stp x0, x1, [sp, #-256]!
139+
; CHECK-NEXT: stp x29, x30, [sp, #232]
140+
; CHECK-NEXT: mov x0, x1
141+
; CHECK-NEXT: mov x1, #16
142+
; CHECK-NEXT: adrp x16, :got:__hwasan_tag_mismatch_v2
143+
; CHECK-NEXT: ldr x16, [x16, :got_lo12:__hwasan_tag_mismatch_v2]
144+
; CHECK-NEXT: br x16

0 commit comments

Comments
 (0)