diff --git a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp --- a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -2072,10 +2072,23 @@ SetComdatForGlobalMetadata(G, Metadata, UniqueModuleId); } + // This should never be called when there are no globals, by the logic that + // computes the UniqueModuleId string, which is "" when there are no globals. + // It's important that this path is only used when there are actually some + // globals, because that means that there will certainly be a live + // `asan_globals` input section at link time and thus `__start_asan_globals` + // and `__stop_asan_globals` symbols will definitely be defined at link time. + // This means there's no need for the references to them to be weak, which + // enables better code generation because ExternalWeakLinkage implies + // isInterposable() and thus requires GOT indirection for PIC. Since these + // are known-defined hidden/dso_local symbols, direct PIC accesses without + // dynamic relocation are always sufficient. + assert(!MetadataGlobals.empty()); + assert(!UniqueModuleId.empty()); + // Update llvm.compiler.used, adding the new metadata globals. This is // needed so that during LTO these variables stay alive. - if (!MetadataGlobals.empty()) - appendToCompilerUsed(M, MetadataGlobals); + appendToCompilerUsed(M, MetadataGlobals); // 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 @@ -2088,15 +2101,18 @@ ConstantInt::get(IntptrTy, 0), kAsanGlobalsRegisteredFlagName); RegisteredFlag->setVisibility(GlobalVariable::HiddenVisibility); - // Create start and stop symbols. - GlobalVariable *StartELFMetadata = new GlobalVariable( - M, IntptrTy, false, GlobalVariable::ExternalWeakLinkage, nullptr, - "__start_" + getGlobalMetadataSection()); - StartELFMetadata->setVisibility(GlobalVariable::HiddenVisibility); - GlobalVariable *StopELFMetadata = new GlobalVariable( - M, IntptrTy, false, GlobalVariable::ExternalWeakLinkage, nullptr, - "__stop_" + getGlobalMetadataSection()); - StopELFMetadata->setVisibility(GlobalVariable::HiddenVisibility); + // Create start and stop symbols. These are known to be defined by + // the linker, see comment above. + auto MakeStartStopGV = [&](const char *Prefix) { + GlobalVariable *StartStop = + new GlobalVariable(M, IntptrTy, false, GlobalVariable::ExternalLinkage, + nullptr, Prefix + getGlobalMetadataSection()); + StartStop->setVisibility(GlobalVariable::HiddenVisibility); + assert(StartStop->isImplicitDSOLocal()); + return StartStop; + }; + GlobalVariable *StartELFMetadata = MakeStartStopGV("__start_"); + GlobalVariable *StopELFMetadata = MakeStartStopGV("__stop_"); // Create a call to register the globals with the runtime. IRB.CreateCall(AsanRegisterElfGlobals, diff --git a/llvm/test/Instrumentation/AddressSanitizer/global_metadata.ll b/llvm/test/Instrumentation/AddressSanitizer/global_metadata.ll --- a/llvm/test/Instrumentation/AddressSanitizer/global_metadata.ll +++ b/llvm/test/Instrumentation/AddressSanitizer/global_metadata.ll @@ -28,6 +28,10 @@ ; during LTO. ; CHECK: @llvm.compiler.used {{.*}} @__asan_global_global {{.*}} section "llvm.metadata" +; Check that start and stop symbols will be accessed as dso_local. +; CHECK: @__start_asan_globals = external hidden global i64 +; CHECK: @__stop_asan_globals = external hidden global i64 + ; Check that location descriptors and global names were passed into __asan_register_globals: ; CHECK: call void @__asan_register_elf_globals(i64 ptrtoint (i64* @___asan_globals_registered to i64), i64 ptrtoint (i64* @__start_asan_globals to i64), i64 ptrtoint (i64* @__stop_asan_globals to i64))