summaryrefslogtreecommitdiffstats
path: root/llvm
diff options
context:
space:
mode:
Diffstat (limited to 'llvm')
-rw-r--r--llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp144
-rw-r--r--llvm/test/Instrumentation/AddressSanitizer/global_metadata_darwin.ll8
-rw-r--r--llvm/test/Instrumentation/AddressSanitizer/global_metadata_windows.ll38
3 files changed, 139 insertions, 51 deletions
diff --git a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
index ac1eebda259..db9dd1f8c61 100644
--- a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
@@ -601,6 +601,7 @@ private:
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 @@ bool AddressSanitizerModule::ShouldUseMachOGlobalsSection() 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);
@@ -1550,6 +1561,10 @@ bool AddressSanitizerModule::InstrumentGlobals(IRBuilder<> &IRB, Module &M) {
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;
@@ -1563,7 +1578,16 @@ bool AddressSanitizerModule::InstrumentGlobals(IRBuilder<> &IRB, Module &M) {
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;
@@ -1636,6 +1660,25 @@ bool AddressSanitizerModule::InstrumentGlobals(IRBuilder<> &IRB, Module &M) {
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 @@ bool AddressSanitizerModule::InstrumentGlobals(IRBuilder<> &IRB, Module &M) {
InstrumentedGlobal = GA;
}
- Initializers[i] = ConstantStruct::get(
+ Constant *Initializer = ConstantStruct::get(
GlobalStructTy,
ConstantExpr::getPointerCast(InstrumentedGlobal, IntptrTy),
ConstantInt::get(IntptrTy, SizeInBytes),
@@ -1685,78 +1728,85 @@ bool AddressSanitizerModule::InstrumentGlobals(IRBuilder<> &IRB, Module &M) {
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 {
@@ -1773,7 +1823,7 @@ bool AddressSanitizerModule::InstrumentGlobals(IRBuilder<> &IRB, Module &M) {
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 {
diff --git a/llvm/test/Instrumentation/AddressSanitizer/global_metadata_darwin.ll b/llvm/test/Instrumentation/AddressSanitizer/global_metadata_darwin.ll
index 82168175361..9b0c1ef9b5e 100644
--- a/llvm/test/Instrumentation/AddressSanitizer/global_metadata_darwin.ll
+++ b/llvm/test/Instrumentation/AddressSanitizer/global_metadata_darwin.ll
@@ -15,15 +15,15 @@ target triple = "x86_64-apple-macosx10.11.0"
!1 = !{!"test-globals.c", i32 1, i32 5}
-; Test that there is the flag global variable:
-; CHECK: @__asan_globals_registered = common global i64 0
-
; Find the metadata for @global:
-; CHECK: [[METADATA:@[0-9]+]] = internal global {{.*}} @global {{.*}} section "__DATA,__asan_globals,regular", align 1
+; CHECK: [[METADATA:@.+]] = internal global {{.*}} @global {{.*}} section "__DATA,__asan_globals,regular", align 1
; Find the liveness binder for @global and its metadata:
; CHECK: @__asan_binder_global = internal global {{.*}} @global {{.*}} [[METADATA]] {{.*}} section "__DATA,__asan_liveness,regular,live_support"
+; Test that there is the flag global variable:
+; CHECK: @__asan_globals_registered = common global i64 0
+
; The binder has to be inserted to llvm.compiler.used to avoid being stripped
; during LTO.
; CHECK: @llvm.compiler.used {{.*}} @__asan_binder_global {{.*}} section "llvm.metadata"
diff --git a/llvm/test/Instrumentation/AddressSanitizer/global_metadata_windows.ll b/llvm/test/Instrumentation/AddressSanitizer/global_metadata_windows.ll
new file mode 100644
index 00000000000..446b355931e
--- /dev/null
+++ b/llvm/test/Instrumentation/AddressSanitizer/global_metadata_windows.ll
@@ -0,0 +1,38 @@
+; Test that global metadata is placed in a separate section on Windows, and that
+; it is in the same comdat group as the instrumented global. This ensures that
+; linker dead stripping (/OPT:REF) works as intended.
+
+; FIXME: Later we can use this to instrument linkonce odr string literals.
+
+; RUN: opt < %s -asan -asan-module -S | FileCheck %s
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc19.0.24215"
+
+$mystr = comdat any
+
+; CHECK: $dead_global = comdat noduplicates
+; CHECK: @dead_global = local_unnamed_addr global { i32, [60 x i8] } { i32 42, [60 x i8] zeroinitializer }, comdat, align 32
+; CHECK: @__asan_global_dead_global = internal global { {{.*}} }, section ".ASAN$GL", comdat($dead_global), align 1
+
+@dead_global = local_unnamed_addr global i32 42, align 4
+@mystr = linkonce_odr unnamed_addr constant [5 x i8] c"main\00", comdat, align 1
+
+; Function Attrs: nounwind uwtable
+define i32 @main() local_unnamed_addr #0 {
+entry:
+ %call = tail call i32 @puts(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @mystr, i64 0, i64 0))
+ ret i32 0
+}
+
+; Function Attrs: nounwind
+declare i32 @puts(i8* nocapture readonly) local_unnamed_addr #1
+
+attributes #0 = { nounwind uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.module.flags = !{!0}
+!llvm.ident = !{!1}
+
+!0 = !{i32 1, !"PIC Level", i32 2}
+!1 = !{!"clang version 4.0.0 "}
OpenPOWER on IntegriCloud