diff options
Diffstat (limited to 'llvm/lib')
-rw-r--r-- | llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp | 46 |
1 files changed, 39 insertions, 7 deletions
diff --git a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp index 3d50007..33e0206 100644 --- a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -136,8 +136,8 @@ static const char *const kAsanUnregisterElfGlobalsName = static const char *const kAsanPoisonGlobalsName = "__asan_before_dynamic_init"; static const char *const kAsanUnpoisonGlobalsName = "__asan_after_dynamic_init"; static const char *const kAsanInitName = "__asan_init"; -static const char *const kAsanVersionCheckName = - "__asan_version_mismatch_check_v8"; +static const char *const kAsanVersionCheckNamePrefix = + "__asan_version_mismatch_check_v"; static const char *const kAsanPtrCmp = "__sanitizer_ptr_cmp"; static const char *const kAsanPtrSub = "__sanitizer_ptr_sub"; static const char *const kAsanHandleNoReturnName = "__asan_handle_no_return"; @@ -207,6 +207,12 @@ static cl::opt<bool> ClForceDynamicShadow( cl::desc("Load shadow address into a local variable for each function"), cl::Hidden, cl::init(false)); +static cl::opt<bool> + ClWithIfunc("asan-with-ifunc", + cl::desc("Access dynamic shadow through an ifunc global on " + "platforms that support this"), + cl::Hidden, cl::init(false)); + // This flag limits the number of instructions to be instrumented // in any given BB. Normally, this should be set to unlimited (INT_MAX), // but due to http://llvm.org/bugs/show_bug.cgi?id=12652 we temporary @@ -447,10 +453,14 @@ private: /// This struct defines the shadow mapping using the rule: /// shadow = (mem >> Scale) ADD-or-OR Offset. +/// If InGlobal is true, then +/// extern char __asan_shadow[]; +/// shadow = (mem >> Scale) + &__asan_shadow struct ShadowMapping { int Scale; uint64_t Offset; bool OrShadowOffset; + bool InGlobal; }; } // end anonymous namespace @@ -472,6 +482,7 @@ static ShadowMapping getShadowMapping(Triple &TargetTriple, int LongSize, TargetTriple.getArch() == Triple::mipsel; bool IsMIPS64 = TargetTriple.getArch() == Triple::mips64 || TargetTriple.getArch() == Triple::mips64el; + bool IsArmOrThumb = TargetTriple.isARM() || TargetTriple.isThumb(); bool IsAArch64 = TargetTriple.getArch() == Triple::aarch64; bool IsWindows = TargetTriple.isOSWindows(); bool IsFuchsia = TargetTriple.isOSFuchsia(); @@ -479,10 +490,8 @@ static ShadowMapping getShadowMapping(Triple &TargetTriple, int LongSize, ShadowMapping Mapping; if (LongSize == 32) { - // Android is always PIE, which means that the beginning of the address - // space is always available. if (IsAndroid) - Mapping.Offset = 0; + Mapping.Offset = kDynamicShadowSentinel; else if (IsMIPS32) Mapping.Offset = kMIPS32_ShadowOffset32; else if (IsFreeBSD) @@ -550,6 +559,7 @@ static ShadowMapping getShadowMapping(Triple &TargetTriple, int LongSize, Mapping.OrShadowOffset = !IsAArch64 && !IsPPC64 && !IsSystemZ && !IsPS4CPU && !(Mapping.Offset & (Mapping.Offset - 1)) && Mapping.Offset != kDynamicShadowSentinel; + Mapping.InGlobal = ClWithIfunc && IsAndroid && IsArmOrThumb; return Mapping; } @@ -672,6 +682,7 @@ private: DominatorTree *DT; Function *AsanHandleNoReturnFunc; Function *AsanPtrCmpFunction, *AsanPtrSubFunction; + Constant *AsanShadowGlobal; // These arrays is indexed by AccessIsWrite, Experiment and log2(AccessSize). Function *AsanErrorCallback[2][2][kNumberOfAccessSizes]; @@ -744,6 +755,7 @@ private: size_t MinRedzoneSizeForGlobal() const { return RedzoneSizeForScale(Mapping.Scale); } + int GetAsanVersion(const Module &M) const; GlobalsMetadata GlobalsMD; bool CompileKernel; @@ -1109,6 +1121,11 @@ Value *AddressSanitizer::memToShadow(Value *Shadow, IRBuilder<> &IRB) { if (Mapping.Offset == 0) return Shadow; // (Shadow >> scale) | offset Value *ShadowBase; + if (Mapping.InGlobal) + return IRB.CreatePtrToInt( + IRB.CreateGEP(AsanShadowGlobal, + {ConstantInt::get(IntptrTy, 0), Shadow}), + IntptrTy); if (LocalDynamicShadow) ShadowBase = LocalDynamicShadow; else @@ -2156,6 +2173,16 @@ bool AddressSanitizerModule::InstrumentGlobals(IRBuilder<> &IRB, Module &M, bool return true; } +int AddressSanitizerModule::GetAsanVersion(const Module &M) const { + int LongSize = M.getDataLayout().getPointerSizeInBits(); + bool isAndroid = Triple(M.getTargetTriple()).isAndroid(); + int Version = 8; + // 32-bit Android is one version ahead because of the switch to dynamic + // shadow. + Version += (LongSize == 32 && isAndroid); + return Version; +} + bool AddressSanitizerModule::runOnModule(Module &M) { C = &(M.getContext()); int LongSize = M.getDataLayout().getPointerSizeInBits(); @@ -2169,9 +2196,11 @@ bool AddressSanitizerModule::runOnModule(Module &M) { // Create a module constructor. A destructor is created lazily because not all // platforms, and not all modules need it. + std::string VersionCheckName = + kAsanVersionCheckNamePrefix + std::to_string(GetAsanVersion(M)); std::tie(AsanCtorFunction, std::ignore) = createSanitizerCtorAndInitFunctions( M, kAsanModuleCtorName, kAsanInitName, /*InitArgTypes=*/{}, - /*InitArgs=*/{}, kAsanVersionCheckName); + /*InitArgs=*/{}, VersionCheckName); bool CtorComdat = true; bool Changed = false; @@ -2270,6 +2299,9 @@ void AddressSanitizer::initializeCallbacks(Module &M) { EmptyAsm = InlineAsm::get(FunctionType::get(IRB.getVoidTy(), false), StringRef(""), StringRef(""), /*hasSideEffects=*/true); + if (Mapping.InGlobal) + AsanShadowGlobal = M.getOrInsertGlobal("__asan_shadow", + ArrayType::get(IRB.getInt8Ty(), 0)); } // virtual @@ -2311,7 +2343,7 @@ bool AddressSanitizer::maybeInsertAsanInitAtFunctionEntry(Function &F) { void AddressSanitizer::maybeInsertDynamicShadowAtFunctionEntry(Function &F) { // Generate code only when dynamic addressing is needed. - if (Mapping.Offset != kDynamicShadowSentinel) + if (Mapping.Offset != kDynamicShadowSentinel || Mapping.InGlobal) return; IRBuilder<> IRB(&F.front().front()); |