Index: lib/Transforms/Instrumentation/AddressSanitizer.cpp =================================================================== --- lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -601,6 +601,7 @@ bool InstrumentGlobals(IRBuilder<> &IRB, Module &M); bool ShouldInstrumentGlobal(GlobalVariable *G); bool ShouldUseMachOGlobalsSection() const; + StringRef getGlobalMetadataSection() const; void poisonOneInitializer(Function &GlobalInit, GlobalValue *ModuleName); void createInitializerPoisonCalls(Module &M, GlobalValue *ModuleName); size_t MinRedzoneSizeForGlobal() const { @@ -1502,6 +1503,16 @@ return false; } +StringRef AddressSanitizerModule::getGlobalMetadataSection() const { + switch (TargetTriple.getObjectFormat()) { + case Triple::COFF: return ".ASAN$GL"; + case Triple::ELF: return "asan_globals"; + case Triple::MachO: return "__DATA,__asan_globals,regular"; + default: break; + } + llvm_unreachable("unsupported object format"); +} + void AddressSanitizerModule::initializeCallbacks(Module &M) { IRBuilder<> IRB(*C); @@ -1550,6 +1561,10 @@ size_t n = GlobalsToChange.size(); if (n == 0) return false; + bool UseComdatMetadata = TargetTriple.supportsCOMDAT(); + bool UseMachOGlobalsSection = ShouldUseMachOGlobalsSection(); + bool UseMetadataArray = !(UseComdatMetadata || UseMachOGlobalsSection); + // A global is described by a structure // size_t beg; // size_t size; @@ -1563,7 +1578,16 @@ StructType *GlobalStructTy = StructType::get(IntptrTy, IntptrTy, IntptrTy, IntptrTy, IntptrTy, IntptrTy, IntptrTy, IntptrTy, nullptr); - SmallVector Initializers(n); + SmallVector Initializers(UseMetadataArray ? n : 0); + + // On recent Mach-O platforms, use a structure which binds the liveness of + // the global variable to the metadata struct. Keep the list of "Liveness" GV + // created to be added to llvm.compiler.used + StructType *LivenessTy = nullptr; + if (UseMachOGlobalsSection) + LivenessTy = StructType::get(IntptrTy, IntptrTy, nullptr); + SmallVector LivenessGlobals( + UseMachOGlobalsSection ? n : 0); bool HasDynamicallyInitializedGlobals = false; @@ -1636,6 +1660,25 @@ ConstantExpr::getGetElementPtr(NewTy, NewGlobal, Indices2, true)); NewGlobal->takeName(G); G->eraseFromParent(); + G = NewGlobal; + + if (UseComdatMetadata) { + // Get or create a COMDAT for G so that we can use it with our metadata. + Comdat *C = G->getComdat(); + if (!C) { + if (!G->hasName()) { + // If G is unnamed, it must be internal. Give it an artificial name + // so we can put it in a comdat. + assert(G->hasLocalLinkage()); + G->setName(Twine(kAsanGenPrefix) + "_anon_global"); + } + C = M.getOrInsertComdat(G->getName()); + // Make this IMAGE_COMDAT_SELECT_NODUPLICATES on COFF. + if (TargetTriple.isOSBinFormatCOFF()) + C->setSelectionKind(Comdat::NoDuplicates); + G->setComdat(C); + } + } Constant *SourceLoc; if (!MD.SourceLoc.empty()) { @@ -1672,7 +1715,7 @@ InstrumentedGlobal = GA; } - Initializers[i] = ConstantStruct::get( + Constant *Initializer = ConstantStruct::get( GlobalStructTy, ConstantExpr::getPointerCast(InstrumentedGlobal, IntptrTy), ConstantInt::get(IntptrTy, SizeInBytes), @@ -1685,78 +1728,85 @@ if (ClInitializers && MD.IsDynInit) HasDynamicallyInitializedGlobals = true; DEBUG(dbgs() << "NEW GLOBAL: " << *NewGlobal << "\n"); + + // If we aren't using separate metadata globals, add it to the initializer + // list and continue. + if (UseMetadataArray) { + Initializers[i] = Initializer; + continue; + } + + // Create a separate metadata global and put it in the appropriate ASan + // global registration section. + GlobalVariable *Metadata = new GlobalVariable( + M, GlobalStructTy, false, GlobalVariable::InternalLinkage, + Initializer, Twine("__asan_global_") + + GlobalValue::getRealLinkageName(G->getName())); + Metadata->setSection(getGlobalMetadataSection()); + Metadata->setAlignment(1); // Don't leave padding in between. + + // On platforms that support comdats, put the metadata and the + // instrumented global in the same group. This ensures that the metadata + // is discarded if the instrumented global is discarded. + if (UseComdatMetadata) { + assert(G->hasComdat()); + Metadata->setComdat(G->getComdat()); + continue; + } + assert(UseMachOGlobalsSection); + + // On recent Mach-O platforms, we emit the global metadata in a way that + // allows the linker to properly strip dead globals. + auto LivenessBinder = ConstantStruct::get( + LivenessTy, Initializer->getAggregateElement(0u), + ConstantExpr::getPointerCast(Metadata, IntptrTy), nullptr); + GlobalVariable *Liveness = new GlobalVariable( + M, LivenessTy, false, GlobalVariable::InternalLinkage, LivenessBinder, + Twine("__asan_binder_") + G->getName()); + Liveness->setSection("__DATA,__asan_liveness,regular,live_support"); + LivenessGlobals.push_back(Liveness); } + // Create calls for poisoning before initializers run and unpoisoning after. + if (HasDynamicallyInitializedGlobals) + createInitializerPoisonCalls(M, ModuleName); + + // Platforms with a dedicated metadata section don't need to emit any more + // code. + if (UseComdatMetadata) + return true; GlobalVariable *AllGlobals = nullptr; GlobalVariable *RegisteredFlag = nullptr; - // On recent Mach-O platforms, we emit the global metadata in a way that - // allows the linker to properly strip dead globals. - if (ShouldUseMachOGlobalsSection()) { + if (UseMachOGlobalsSection) { // RegisteredFlag serves two purposes. First, we can pass it to dladdr() // to look up the loaded image that contains it. Second, we can store in it // whether registration has already occurred, to prevent duplicate // registration. // - // Common linkage allows us to coalesce needles defined in each object - // file so that there's only one per shared library. + // common linkage ensures that there is only one global per shared library. RegisteredFlag = new GlobalVariable( M, IntptrTy, false, GlobalVariable::CommonLinkage, ConstantInt::get(IntptrTy, 0), kAsanGlobalsRegisteredFlagName); - // We also emit a structure which binds the liveness of the global - // variable to the metadata struct. - StructType *LivenessTy = StructType::get(IntptrTy, IntptrTy, nullptr); - - // Keep the list of "Liveness" GV created to be added to llvm.compiler.used - SmallVector LivenessGlobals; - LivenessGlobals.reserve(n); - - for (size_t i = 0; i < n; i++) { - GlobalVariable *Metadata = new GlobalVariable( - M, GlobalStructTy, false, GlobalVariable::InternalLinkage, - Initializers[i], ""); - Metadata->setSection("__DATA,__asan_globals,regular"); - Metadata->setAlignment(1); // don't leave padding in between - - auto LivenessBinder = ConstantStruct::get(LivenessTy, - Initializers[i]->getAggregateElement(0u), - ConstantExpr::getPointerCast(Metadata, IntptrTy), - nullptr); - - // Recover the name of the variable this global is pointing to - StringRef GVName = - Initializers[i]->getAggregateElement(0u)->getOperand(0)->getName(); - - GlobalVariable *Liveness = new GlobalVariable( - M, LivenessTy, false, GlobalVariable::InternalLinkage, LivenessBinder, - Twine("__asan_binder_") + GVName); - Liveness->setSection("__DATA,__asan_liveness,regular,live_support"); - LivenessGlobals.push_back(Liveness); - } - // Update llvm.compiler.used, adding the new liveness globals. This is // needed so that during LTO these variables stay alive. The alternative // would be to have the linker handling the LTO symbols, but libLTO // current API does not expose access to the section for each symbol. if (!LivenessGlobals.empty()) appendToCompilerUsed(M, LivenessGlobals); - } else { - // On all other platfoms, we just emit an array of global metadata - // structures. + } else if (UseMetadataArray) { + // On platforms that don't have a custom metadata section, we emit an array + // of global metadata structures. ArrayType *ArrayOfGlobalStructTy = ArrayType::get(GlobalStructTy, n); AllGlobals = new GlobalVariable( M, ArrayOfGlobalStructTy, false, GlobalVariable::InternalLinkage, ConstantArray::get(ArrayOfGlobalStructTy, Initializers), ""); } - // Create calls for poisoning before initializers run and unpoisoning after. - if (HasDynamicallyInitializedGlobals) - createInitializerPoisonCalls(M, ModuleName); - // Create a call to register the globals with the runtime. - if (ShouldUseMachOGlobalsSection()) { + if (UseMachOGlobalsSection) { IRB.CreateCall(AsanRegisterImageGlobals, {IRB.CreatePointerCast(RegisteredFlag, IntptrTy)}); } else { @@ -1773,7 +1823,7 @@ BasicBlock *AsanDtorBB = BasicBlock::Create(*C, "", AsanDtorFunction); IRBuilder<> IRB_Dtor(ReturnInst::Create(*C, AsanDtorBB)); - if (ShouldUseMachOGlobalsSection()) { + if (UseMachOGlobalsSection) { IRB_Dtor.CreateCall(AsanUnregisterImageGlobals, {IRB.CreatePointerCast(RegisteredFlag, IntptrTy)}); } else {