Skip to content
This repository was archived by the owner on Mar 28, 2020. It is now read-only.

Commit 54374f6

Browse files
committed
hwasan: Read shadow address from ifunc if we don't need a frame record.
This saves a cbz+cold call in the interceptor ABI, as well as a realign in both ABIs, trading off a dcache entry against some branch predictor entries and some code size. Unfortunately the functionality is hidden behind a flag because ifunc is known to be broken on static binaries on Android. Differential Revision: https://reviews.llvm.org/D57084 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@351989 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 0046ceb commit 54374f6

File tree

3 files changed

+48
-33
lines changed

3 files changed

+48
-33
lines changed

lib/Transforms/Instrumentation/HWAddressSanitizer.cpp

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,10 @@ static cl::opt<bool> ClInlineAllChecks("hwasan-inline-all-checks",
160160
cl::desc("inline all checks"),
161161
cl::Hidden, cl::init(false));
162162

163+
static cl::opt<bool> ClAllowIfunc("hwasan-allow-ifunc",
164+
cl::desc("allow the use of ifunc"),
165+
cl::Hidden, cl::init(false));
166+
163167
namespace {
164168

165169
/// An instrumentation pass implementing detection of addressability bugs
@@ -183,6 +187,7 @@ class HWAddressSanitizer : public FunctionPass {
183187

184188
void initializeCallbacks(Module &M);
185189

190+
Value *getDynamicShadowIfunc(IRBuilder<> &IRB);
186191
Value *getDynamicShadowNonTls(IRBuilder<> &IRB);
187192

188193
void untagPointerOperand(Instruction *I, Value *Addr);
@@ -384,9 +389,8 @@ void HWAddressSanitizer::initializeCallbacks(Module &M) {
384389
HwasanGenerateTagFunc = checkSanitizerInterfaceFunction(
385390
M.getOrInsertFunction("__hwasan_generate_tag", Int8Ty));
386391

387-
if (Mapping.InGlobal)
388-
ShadowGlobal = M.getOrInsertGlobal("__hwasan_shadow",
389-
ArrayType::get(IRB.getInt8Ty(), 0));
392+
ShadowGlobal = M.getOrInsertGlobal("__hwasan_shadow",
393+
ArrayType::get(IRB.getInt8Ty(), 0));
390394

391395
const std::string MemIntrinCallbackPrefix =
392396
CompileKernel ? std::string("") : ClMemoryAccessCallbackPrefix;
@@ -404,19 +408,23 @@ void HWAddressSanitizer::initializeCallbacks(Module &M) {
404408
M.getOrInsertFunction("__hwasan_thread_enter", IRB.getVoidTy()));
405409
}
406410

411+
Value *HWAddressSanitizer::getDynamicShadowIfunc(IRBuilder<> &IRB) {
412+
// An empty inline asm with input reg == output reg.
413+
// An opaque no-op cast, basically.
414+
InlineAsm *Asm = InlineAsm::get(
415+
FunctionType::get(Int8PtrTy, {ShadowGlobal->getType()}, false),
416+
StringRef(""), StringRef("=r,0"),
417+
/*hasSideEffects=*/false);
418+
return IRB.CreateCall(Asm, {ShadowGlobal}, ".hwasan.shadow");
419+
}
420+
407421
Value *HWAddressSanitizer::getDynamicShadowNonTls(IRBuilder<> &IRB) {
408422
// Generate code only when dynamic addressing is needed.
409423
if (Mapping.Offset != kDynamicShadowSentinel)
410424
return nullptr;
411425

412426
if (Mapping.InGlobal) {
413-
// An empty inline asm with input reg == output reg.
414-
// An opaque no-op cast, basically.
415-
InlineAsm *Asm = InlineAsm::get(
416-
FunctionType::get(Int8PtrTy, {ShadowGlobal->getType()}, false),
417-
StringRef(""), StringRef("=r,0"),
418-
/*hasSideEffects=*/false);
419-
return IRB.CreateCall(Asm, {ShadowGlobal}, ".hwasan.shadow");
427+
return getDynamicShadowIfunc(IRB);
420428
} else {
421429
Value *GlobalDynamicAddress =
422430
IRB.GetInsertBlock()->getParent()->getParent()->getOrInsertGlobal(
@@ -828,6 +836,9 @@ Value *HWAddressSanitizer::emitPrologue(IRBuilder<> &IRB,
828836
if (!Mapping.InTls)
829837
return getDynamicShadowNonTls(IRB);
830838

839+
if (ClAllowIfunc && !WithFrameRecord && TargetTriple.isAndroid())
840+
return getDynamicShadowIfunc(IRB);
841+
831842
Value *SlotPtr = getHwasanThreadSlotPtr(IRB, IntptrTy);
832843
assert(SlotPtr);
833844

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
1-
; RUN: opt -S -hwasan < %s | FileCheck %s
1+
; RUN: opt -S -hwasan -hwasan-allow-ifunc < %s | FileCheck %s
22

3-
target triple = "x86_64-unknown-linux-gnu"
3+
target triple = "aarch64--linux-android"
44

55
declare void @bar([16 x i32]* %p)
66

7-
define void @foo() sanitize_hwaddress "hwasan-abi"="interceptor" {
8-
; CHECK: [[LOAD:%[^ ]*]] = load i64, i64* @__hwasan_tls
7+
define void @alloca() sanitize_hwaddress "hwasan-abi"="interceptor" {
8+
; CHECK: [[A:%[^ ]*]] = call i8* @llvm.thread.pointer()
9+
; CHECK: [[B:%[^ ]*]] = getelementptr i8, i8* [[A]], i32 48
10+
; CHECK: [[C:%[^ ]*]] = bitcast i8* [[B]] to i64*
11+
; CHECK: [[LOAD:%[^ ]*]] = load i64, i64* [[C]]
912
; CHECK: [[ICMP:%[^ ]*]] = icmp eq i64 [[LOAD]], 0
1013
; CHECK: br i1 [[ICMP]], label %[[INIT:[^,]*]], label %[[CONT:[^,]*]], !prof [[PROF:![0-9]+]]
1114

1215
; CHECK: [[INIT]]:
1316
; CHECK: call void @__hwasan_thread_enter()
14-
; CHECK: [[RELOAD:%[^ ]*]] = load i64, i64* @__hwasan_tls
17+
; CHECK: [[RELOAD:%[^ ]*]] = load i64, i64* [[C]]
1518
; CHECK: br label %[[CONT]]
1619

1720
; CHECK: [[CONT]]:
@@ -22,4 +25,12 @@ define void @foo() sanitize_hwaddress "hwasan-abi"="interceptor" {
2225
ret void
2326
}
2427

28+
define i32 @load(i32* %p) sanitize_hwaddress "hwasan-abi"="interceptor" {
29+
; CHECK: [[SHADOW:%[^ ]*]] = call i8* asm "", "=r,0"([0 x i8]* @__hwasan_shadow)
30+
; CHECK-NOT: icmp
31+
; CHECK: call void @llvm.hwasan.check.memaccess(i8* [[SHADOW]],
32+
%v = load i32, i32* %p
33+
ret i32 %v
34+
}
35+
2536
; CHECK: [[PROF]] = !{!"branch_weights", i32 1, i32 100000}

test/Instrumentation/HWAddressSanitizer/prologue.ll

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
; Test -hwasan-with-ifunc flag.
22
;
3-
; RUN: opt -hwasan -S < %s | \
4-
; RUN: FileCheck %s --check-prefixes=CHECK,CHECK-TLS,CHECK-HISTORY
5-
; RUN: opt -hwasan -S -hwasan-with-ifunc=0 -hwasan-with-tls=1 -hwasan-record-stack-history=1 < %s | \
6-
; RUN: FileCheck %s --check-prefixes=CHECK,CHECK-TLS,CHECK-HISTORY
7-
; RUN: opt -hwasan -S -hwasan-with-ifunc=0 -hwasan-with-tls=1 -hwasan-record-stack-history=0 < %s | \
8-
; RUN: FileCheck %s --check-prefixes=CHECK,CHECK-TLS,CHECK-NOHISTORY
9-
; RUN: opt -hwasan -S -hwasan-with-ifunc=0 -hwasan-with-tls=0 < %s | \
3+
; RUN: opt -hwasan -hwasan-allow-ifunc -S < %s | \
4+
; RUN: FileCheck %s --check-prefixes=CHECK,CHECK-NOGLOBAL,CHECK-TLS,CHECK-HISTORY
5+
; RUN: opt -hwasan -hwasan-allow-ifunc -S -hwasan-with-ifunc=0 -hwasan-with-tls=1 -hwasan-record-stack-history=1 < %s | \
6+
; RUN: FileCheck %s --check-prefixes=CHECK,CHECK-NOGLOBAL,CHECK-TLS,CHECK-HISTORY
7+
; RUN: opt -hwasan -hwasan-allow-ifunc -S -hwasan-with-ifunc=0 -hwasan-with-tls=1 -hwasan-record-stack-history=0 < %s | \
8+
; RUN: FileCheck %s --check-prefixes=CHECK,CHECK-NOGLOBAL,CHECK-IFUNC,CHECK-NOHISTORY
9+
; RUN: opt -hwasan -hwasan-allow-ifunc -S -hwasan-with-ifunc=0 -hwasan-with-tls=0 < %s | \
1010
; RUN: FileCheck %s --check-prefixes=CHECK,CHECK-GLOBAL,CHECK-NOHISTORY
11-
; RUN: opt -hwasan -S -hwasan-with-ifunc=1 -hwasan-with-tls=0 < %s | \
12-
; RUN: FileCheck %s --check-prefixes=CHECK,CHECK-IFUNC,CHECK-NOHISTORY
11+
; RUN: opt -hwasan -hwasan-allow-ifunc -S -hwasan-with-ifunc=1 -hwasan-with-tls=0 < %s | \
12+
; RUN: FileCheck %s --check-prefixes=CHECK,CHECk-NOGLOBAL,CHECK-IFUNC,CHECK-NOHISTORY
1313

1414
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
1515
target triple = "aarch64--linux-android22"
@@ -23,18 +23,11 @@ define i32 @test_load(i32* %a) sanitize_hwaddress {
2323
; CHECK-LABEL: @test_load
2424
; CHECK: entry:
2525

26-
; CHECK-IFUNC: %[[A:[^ ]*]] = call i8* asm "", "=r,0"([0 x i8]* @__hwasan_shadow)
27-
; CHECK-IFUNC: @llvm.hwasan.check.memaccess(i8* %[[A]]
26+
; CHECK-NOGLOBAL: %[[A:[^ ]*]] = call i8* asm "", "=r,0"([0 x i8]* @__hwasan_shadow)
27+
; CHECK-NOGLOBAL: @llvm.hwasan.check.memaccess(i8* %[[A]]
2828

2929
; CHECK-GLOBAL: load i8*, i8** @__hwasan_shadow_memory_dynamic_address
3030

31-
; CHECK-TLS: %[[A:[^ ]*]] = call i8* @llvm.thread.pointer()
32-
; CHECK-TLS: %[[B:[^ ]*]] = getelementptr i8, i8* %[[A]], i32 48
33-
; CHECK-TLS: %[[C:[^ ]*]] = bitcast i8* %[[B]] to i64*
34-
; CHECK-TLS: %[[D:[^ ]*]] = load i64, i64* %[[C]]
35-
; CHECK-TLS: %[[E:[^ ]*]] = or i64 %[[D]], 4294967295
36-
; CHECK-TLS: = add i64 %[[E]], 1
37-
3831
; "store i64" is only used to update stack history (this input IR intentionally does not use any i64)
3932
; W/o any allocas, the history is not updated, even if it is enabled explicitly with -hwasan-record-stack-history=1
4033
; CHECK-NOT: store i64

0 commit comments

Comments
 (0)