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 {
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);
size_t n = GlobalsToChange.size();
if (n == 0) return false;
+ bool UseComdatMetadata = TargetTriple.isOSBinFormatCOFF();
+ bool UseMachOGlobalsSection = ShouldUseMachOGlobalsSection();
+ bool UseMetadataArray = !(UseComdatMetadata || UseMachOGlobalsSection);
+
// A global is described by a structure
// size_t beg;
// size_t size;
StructType *GlobalStructTy =
StructType::get(IntptrTy, IntptrTy, IntptrTy, IntptrTy, IntptrTy,
IntptrTy, IntptrTy, IntptrTy, nullptr);
- SmallVector<Constant *, 16> Initializers(n);
+ SmallVector<Constant *, 16> 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<GlobalValue *, 16> LivenessGlobals(
+ UseMachOGlobalsSection ? n : 0);
bool HasDynamicallyInitializedGlobals = false;
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()) {
InstrumentedGlobal = GA;
}
- Initializers[i] = ConstantStruct::get(
+ Constant *Initializer = ConstantStruct::get(
GlobalStructTy,
ConstantExpr::getPointerCast(InstrumentedGlobal, IntptrTy),
ConstantInt::get(IntptrTy, SizeInBytes),
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[i] = 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<GlobalValue *, 16> 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 {
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 {