Index: compiler-rt/test/hwasan/lit.cfg =================================================================== --- compiler-rt/test/hwasan/lit.cfg +++ compiler-rt/test/hwasan/lit.cfg @@ -11,7 +11,8 @@ # Setup default compiler flags used with -fsanitize=memory option. clang_cflags = [config.target_cflags] + config.debug_info_flags clang_cxxflags = config.cxx_mode_flags + clang_cflags -clang_hwasan_cflags = ["-fsanitize=hwaddress", "-mllvm", "-hwasan-generate-tags-with-calls"] + clang_cflags +clang_hwasan_cflags = ["-fsanitize=hwaddress", "-mllvm", "-hwasan-generate-tags-with-calls", + "-mllvm", "-hwasan-allow-ifunc"] + clang_cflags clang_hwasan_cxxflags = config.cxx_mode_flags + clang_hwasan_cflags def build_invocation(compile_flags): Index: llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp =================================================================== --- llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp +++ llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp @@ -160,6 +160,10 @@ cl::desc("inline all checks"), cl::Hidden, cl::init(false)); +static cl::opt ClAllowIfunc("hwasan-allow-ifunc", + cl::desc("allow the use of ifunc"), + cl::Hidden, cl::init(false)); + namespace { /// An instrumentation pass implementing detection of addressability bugs @@ -183,6 +187,7 @@ void initializeCallbacks(Module &M); + Value *getDynamicShadowIfunc(IRBuilder<> &IRB); Value *getDynamicShadowNonTls(IRBuilder<> &IRB); void untagPointerOperand(Instruction *I, Value *Addr); @@ -384,9 +389,8 @@ HwasanGenerateTagFunc = checkSanitizerInterfaceFunction( M.getOrInsertFunction("__hwasan_generate_tag", Int8Ty)); - if (Mapping.InGlobal) - ShadowGlobal = M.getOrInsertGlobal("__hwasan_shadow", - ArrayType::get(IRB.getInt8Ty(), 0)); + ShadowGlobal = M.getOrInsertGlobal("__hwasan_shadow", + ArrayType::get(IRB.getInt8Ty(), 0)); const std::string MemIntrinCallbackPrefix = CompileKernel ? std::string("") : ClMemoryAccessCallbackPrefix; @@ -404,19 +408,23 @@ M.getOrInsertFunction("__hwasan_thread_enter", IRB.getVoidTy())); } +Value *HWAddressSanitizer::getDynamicShadowIfunc(IRBuilder<> &IRB) { + // An empty inline asm with input reg == output reg. + // An opaque no-op cast, basically. + InlineAsm *Asm = InlineAsm::get( + FunctionType::get(Int8PtrTy, {ShadowGlobal->getType()}, false), + StringRef(""), StringRef("=r,0"), + /*hasSideEffects=*/false); + return IRB.CreateCall(Asm, {ShadowGlobal}, ".hwasan.shadow"); +} + Value *HWAddressSanitizer::getDynamicShadowNonTls(IRBuilder<> &IRB) { // Generate code only when dynamic addressing is needed. if (Mapping.Offset != kDynamicShadowSentinel) return nullptr; if (Mapping.InGlobal) { - // An empty inline asm with input reg == output reg. - // An opaque no-op cast, basically. - InlineAsm *Asm = InlineAsm::get( - FunctionType::get(Int8PtrTy, {ShadowGlobal->getType()}, false), - StringRef(""), StringRef("=r,0"), - /*hasSideEffects=*/false); - return IRB.CreateCall(Asm, {ShadowGlobal}, ".hwasan.shadow"); + return getDynamicShadowIfunc(IRB); } else { Value *GlobalDynamicAddress = IRB.GetInsertBlock()->getParent()->getParent()->getOrInsertGlobal( @@ -828,6 +836,9 @@ if (!Mapping.InTls) return getDynamicShadowNonTls(IRB); + if (ClAllowIfunc && !WithFrameRecord && TargetTriple.isAndroid()) + return getDynamicShadowIfunc(IRB); + Value *SlotPtr = getHwasanThreadSlotPtr(IRB, IntptrTy); assert(SlotPtr); Index: llvm/test/Instrumentation/HWAddressSanitizer/lazy-thread-init.ll =================================================================== --- llvm/test/Instrumentation/HWAddressSanitizer/lazy-thread-init.ll +++ llvm/test/Instrumentation/HWAddressSanitizer/lazy-thread-init.ll @@ -1,17 +1,20 @@ -; RUN: opt -S -hwasan < %s | FileCheck %s +; RUN: opt -S -hwasan -hwasan-allow-ifunc < %s | FileCheck %s -target triple = "x86_64-unknown-linux-gnu" +target triple = "aarch64--linux-android" declare void @bar([16 x i32]* %p) -define void @foo() sanitize_hwaddress "hwasan-abi"="interceptor" { - ; CHECK: [[LOAD:%[^ ]*]] = load i64, i64* @__hwasan_tls +define void @alloca() sanitize_hwaddress "hwasan-abi"="interceptor" { + ; CHECK: [[A:%[^ ]*]] = call i8* @llvm.thread.pointer() + ; CHECK: [[B:%[^ ]*]] = getelementptr i8, i8* [[A]], i32 48 + ; CHECK: [[C:%[^ ]*]] = bitcast i8* [[B]] to i64* + ; CHECK: [[LOAD:%[^ ]*]] = load i64, i64* [[C]] ; CHECK: [[ICMP:%[^ ]*]] = icmp eq i64 [[LOAD]], 0 ; CHECK: br i1 [[ICMP]], label %[[INIT:[^,]*]], label %[[CONT:[^,]*]], !prof [[PROF:![0-9]+]] ; CHECK: [[INIT]]: ; CHECK: call void @__hwasan_thread_enter() - ; CHECK: [[RELOAD:%[^ ]*]] = load i64, i64* @__hwasan_tls + ; CHECK: [[RELOAD:%[^ ]*]] = load i64, i64* [[C]] ; CHECK: br label %[[CONT]] ; CHECK: [[CONT]]: @@ -22,4 +25,12 @@ ret void } +define i32 @load(i32* %p) sanitize_hwaddress "hwasan-abi"="interceptor" { + ; CHECK: [[SHADOW:%[^ ]*]] = call i8* asm "", "=r,0"([0 x i8]* @__hwasan_shadow) + ; CHECK-NOT: icmp + ; CHECK: call void @llvm.hwasan.check.memaccess(i8* [[SHADOW]], + %v = load i32, i32* %p + ret i32 %v +} + ; CHECK: [[PROF]] = !{!"branch_weights", i32 1, i32 100000} Index: llvm/test/Instrumentation/HWAddressSanitizer/prologue.ll =================================================================== --- llvm/test/Instrumentation/HWAddressSanitizer/prologue.ll +++ llvm/test/Instrumentation/HWAddressSanitizer/prologue.ll @@ -1,15 +1,15 @@ ; Test -hwasan-with-ifunc flag. ; -; RUN: opt -hwasan -S < %s | \ -; RUN: FileCheck %s --check-prefixes=CHECK,CHECK-TLS,CHECK-HISTORY -; RUN: opt -hwasan -S -hwasan-with-ifunc=0 -hwasan-with-tls=1 -hwasan-record-stack-history=1 < %s | \ -; RUN: FileCheck %s --check-prefixes=CHECK,CHECK-TLS,CHECK-HISTORY -; RUN: opt -hwasan -S -hwasan-with-ifunc=0 -hwasan-with-tls=1 -hwasan-record-stack-history=0 < %s | \ -; RUN: FileCheck %s --check-prefixes=CHECK,CHECK-TLS,CHECK-NOHISTORY -; RUN: opt -hwasan -S -hwasan-with-ifunc=0 -hwasan-with-tls=0 < %s | \ +; RUN: opt -hwasan -hwasan-allow-ifunc -S < %s | \ +; RUN: FileCheck %s --check-prefixes=CHECK,CHECK-NOGLOBAL,CHECK-TLS,CHECK-HISTORY +; RUN: opt -hwasan -hwasan-allow-ifunc -S -hwasan-with-ifunc=0 -hwasan-with-tls=1 -hwasan-record-stack-history=1 < %s | \ +; RUN: FileCheck %s --check-prefixes=CHECK,CHECK-NOGLOBAL,CHECK-TLS,CHECK-HISTORY +; RUN: opt -hwasan -hwasan-allow-ifunc -S -hwasan-with-ifunc=0 -hwasan-with-tls=1 -hwasan-record-stack-history=0 < %s | \ +; RUN: FileCheck %s --check-prefixes=CHECK,CHECK-NOGLOBAL,CHECK-IFUNC,CHECK-NOHISTORY +; RUN: opt -hwasan -hwasan-allow-ifunc -S -hwasan-with-ifunc=0 -hwasan-with-tls=0 < %s | \ ; RUN: FileCheck %s --check-prefixes=CHECK,CHECK-GLOBAL,CHECK-NOHISTORY -; RUN: opt -hwasan -S -hwasan-with-ifunc=1 -hwasan-with-tls=0 < %s | \ -; RUN: FileCheck %s --check-prefixes=CHECK,CHECK-IFUNC,CHECK-NOHISTORY +; RUN: opt -hwasan -hwasan-allow-ifunc -S -hwasan-with-ifunc=1 -hwasan-with-tls=0 < %s | \ +; RUN: FileCheck %s --check-prefixes=CHECK,CHECk-NOGLOBAL,CHECK-IFUNC,CHECK-NOHISTORY target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" target triple = "aarch64--linux-android22" @@ -23,18 +23,11 @@ ; CHECK-LABEL: @test_load ; CHECK: entry: -; CHECK-IFUNC: %[[A:[^ ]*]] = call i8* asm "", "=r,0"([0 x i8]* @__hwasan_shadow) -; CHECK-IFUNC: @llvm.hwasan.check.memaccess(i8* %[[A]] +; CHECK-NOGLOBAL: %[[A:[^ ]*]] = call i8* asm "", "=r,0"([0 x i8]* @__hwasan_shadow) +; CHECK-NOGLOBAL: @llvm.hwasan.check.memaccess(i8* %[[A]] ; CHECK-GLOBAL: load i8*, i8** @__hwasan_shadow_memory_dynamic_address -; CHECK-TLS: %[[A:[^ ]*]] = call i8* @llvm.thread.pointer() -; CHECK-TLS: %[[B:[^ ]*]] = getelementptr i8, i8* %[[A]], i32 48 -; CHECK-TLS: %[[C:[^ ]*]] = bitcast i8* %[[B]] to i64* -; CHECK-TLS: %[[D:[^ ]*]] = load i64, i64* %[[C]] -; CHECK-TLS: %[[E:[^ ]*]] = or i64 %[[D]], 4294967295 -; CHECK-TLS: = add i64 %[[E]], 1 - ; "store i64" is only used to update stack history (this input IR intentionally does not use any i64) ; W/o any allocas, the history is not updated, even if it is enabled explicitly with -hwasan-record-stack-history=1 ; CHECK-NOT: store i64