llvm.org GIT mirror llvm / 226bbc3
[asan] Fix dead stripping of globals on Linux. Use a combination of !associated, comdat, @llvm.compiler.used and custom sections to allow dead stripping of globals and their asan metadata. Sometimes. Currently this works on LLD, which supports SHF_LINK_ORDER with sh_link pointing to the associated section. This also works on BFD, which seems to treat comdats as all-or-nothing with respect to linker GC. There is a weird quirk where the "first" global in each link is never GC-ed because of the section symbols. At this moment it does not work on Gold (as in the globals are never stripped). This is a second re-land of r298158. This time, this feature is limited to -fdata-sections builds. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@301587 91177308-0d34-0410-b5e6-96231b3b80d8 Evgeniy Stepanov 2 years ago
9 changed file(s) with 170 addition(s) and 54 deletion(s). Raw diff Collapse all Expand all
8383 void filterDeadComdatFunctions(
8484 Module &M, SmallVectorImpl &DeadComdatFunctions);
8585
86 /// \brief Produce a unique identifier for this module by taking the MD5 sum of
87 /// the names of the module's strong external symbols.
88 ///
89 /// This identifier is normally guaranteed to be unique, or the program would
90 /// fail to link due to multiply defined symbols.
91 ///
92 /// If the module has no strong external symbols (such a module may still have a
93 /// semantic effect if it performs global initialization), we cannot produce a
94 /// unique identifier for this module, so we return the empty string.
95 std::string getUniqueModuleId(Module *M);
96
8697 } // End llvm namespace
8798
8899 #endif // LLVM_TRANSFORMS_UTILS_MODULEUTILS_H
2929 #include "llvm/Transforms/IPO.h"
3030 #include "llvm/Transforms/IPO/FunctionAttrs.h"
3131 #include "llvm/Transforms/Utils/Cloning.h"
32 #include "llvm/Transforms/Utils/ModuleUtils.h"
3233 using namespace llvm;
3334
3435 namespace {
35
36 // Produce a unique identifier for this module by taking the MD5 sum of the
37 // names of the module's strong external symbols. This identifier is
38 // normally guaranteed to be unique, or the program would fail to link due to
39 // multiply defined symbols.
40 //
41 // If the module has no strong external symbols (such a module may still have a
42 // semantic effect if it performs global initialization), we cannot produce a
43 // unique identifier for this module, so we return the empty string, which
44 // causes the entire module to be written as a regular LTO module.
45 std::string getModuleId(Module *M) {
46 MD5 Md5;
47 bool ExportsSymbols = false;
48 for (auto &GV : M->global_values()) {
49 if (GV.isDeclaration() || GV.getName().startswith("llvm.") ||
50 !GV.hasExternalLinkage())
51 continue;
52 ExportsSymbols = true;
53 Md5.update(GV.getName());
54 Md5.update(ArrayRef{0});
55 }
56
57 if (!ExportsSymbols)
58 return "";
59
60 MD5::MD5Result R;
61 Md5.final(R);
62
63 SmallString<32> Str;
64 MD5::stringifyResult(R, Str);
65 return ("$" + Str).str();
66 }
6736
6837 // Promote each local-linkage entity defined by ExportM and used by ImportM by
6938 // changing visibility and appending the given ModuleId.
250219 void splitAndWriteThinLTOBitcode(
251220 raw_ostream &OS, raw_ostream *ThinLinkOS,
252221 function_ref AARGetter, Module &M) {
253 std::string ModuleId = getModuleId(&M);
222 std::string ModuleId = getUniqueModuleId(&M);
254223 if (ModuleId.empty()) {
255224 // We couldn't generate a module ID for this module, just write it out as a
256225 // regular LTO module.
100100 "__asan_register_image_globals";
101101 static const char *const kAsanUnregisterImageGlobalsName =
102102 "__asan_unregister_image_globals";
103 static const char *const kAsanRegisterElfGlobalsName =
104 "__asan_register_elf_globals";
105 static const char *const kAsanUnregisterElfGlobalsName =
106 "__asan_unregister_elf_globals";
103107 static const char *const kAsanPoisonGlobalsName = "__asan_before_dynamic_init";
104108 static const char *const kAsanUnpoisonGlobalsName = "__asan_after_dynamic_init";
105109 static const char *const kAsanInitName = "__asan_init";
119123 "__asan_poison_stack_memory";
120124 static const char *const kAsanUnpoisonStackMemoryName =
121125 "__asan_unpoison_stack_memory";
126
127 // ASan version script has __asan_* wildcard. Triple underscore prevents a
128 // linker (gold) warning about attempting to export a local symbol.
122129 static const char *const kAsanGlobalsRegisteredFlagName =
123 "__asan_globals_registered";
130 "___asan_globals_registered";
124131
125132 static const char *const kAsanOptionDetectUseAfterReturn =
126133 "__asan_option_detect_stack_use_after_return";
617624 void InstrumentGlobalsCOFF(IRBuilder<> &IRB, Module &M,
618625 ArrayRef ExtendedGlobals,
619626 ArrayRef MetadataInitializers);
627 void InstrumentGlobalsELF(IRBuilder<> &IRB, Module &M,
628 ArrayRef ExtendedGlobals,
629 ArrayRef MetadataInitializers,
630 const std::string &UniqueModuleId);
620631 void InstrumentGlobalsMachO(IRBuilder<> &IRB, Module &M,
621632 ArrayRef ExtendedGlobals,
622633 ArrayRef MetadataInitializers);
627638
628639 GlobalVariable *CreateMetadataGlobal(Module &M, Constant *Initializer,
629640 StringRef OriginalName);
630 void SetComdatForGlobalMetadata(GlobalVariable *G, GlobalVariable *Metadata);
641 void SetComdatForGlobalMetadata(GlobalVariable *G, GlobalVariable *Metadata,
642 StringRef InternalSuffix);
631643 IRBuilder<> CreateAsanModuleDtor(Module &M);
632644
633645 bool ShouldInstrumentGlobal(GlobalVariable *G);
653665 Function *AsanUnregisterGlobals;
654666 Function *AsanRegisterImageGlobals;
655667 Function *AsanUnregisterImageGlobals;
668 Function *AsanRegisterElfGlobals;
669 Function *AsanUnregisterElfGlobals;
656670
657671 Function *AsanCtorFunction = nullptr;
658672 Function *AsanDtorFunction = nullptr;
16081622 checkSanitizerInterfaceFunction(M.getOrInsertFunction(
16091623 kAsanUnregisterImageGlobalsName, IRB.getVoidTy(), IntptrTy));
16101624 AsanUnregisterImageGlobals->setLinkage(Function::ExternalLinkage);
1625
1626 AsanRegisterElfGlobals = checkSanitizerInterfaceFunction(
1627 M.getOrInsertFunction(kAsanRegisterElfGlobalsName, IRB.getVoidTy(),
1628 IntptrTy, IntptrTy, IntptrTy));
1629 AsanRegisterElfGlobals->setLinkage(Function::ExternalLinkage);
1630
1631 AsanUnregisterElfGlobals = checkSanitizerInterfaceFunction(
1632 M.getOrInsertFunction(kAsanUnregisterElfGlobalsName, IRB.getVoidTy(),
1633 IntptrTy, IntptrTy, IntptrTy));
1634 AsanUnregisterElfGlobals->setLinkage(Function::ExternalLinkage);
16111635 }
16121636
16131637 // Put the metadata and the instrumented global in the same group. This ensures
16141638 // that the metadata is discarded if the instrumented global is discarded.
16151639 void AddressSanitizerModule::SetComdatForGlobalMetadata(
1616 GlobalVariable *G, GlobalVariable *Metadata) {
1640 GlobalVariable *G, GlobalVariable *Metadata, StringRef InternalSuffix) {
16171641 Module &M = *G->getParent();
16181642 Comdat *C = G->getComdat();
16191643 if (!C) {
16231647 assert(G->hasLocalLinkage());
16241648 G->setName(Twine(kAsanGenPrefix) + "_anon_global");
16251649 }
1626 C = M.getOrInsertComdat(G->getName());
1650
1651 if (!InternalSuffix.empty() && G->hasLocalLinkage()) {
1652 std::string Name = G->getName();
1653 Name += InternalSuffix;
1654 C = M.getOrInsertComdat(Name);
1655 } else {
1656 C = M.getOrInsertComdat(G->getName());
1657 }
1658
16271659 // Make this IMAGE_COMDAT_SELECT_NODUPLICATES on COFF.
16281660 if (TargetTriple.isOSBinFormatCOFF())
16291661 C->setSelectionKind(Comdat::NoDuplicates);
16781710 "global metadata will not be padded appropriately");
16791711 Metadata->setAlignment(SizeOfGlobalStruct);
16801712
1681 SetComdatForGlobalMetadata(G, Metadata);
1682 }
1713 SetComdatForGlobalMetadata(G, Metadata, "");
1714 }
1715 }
1716
1717 void AddressSanitizerModule::InstrumentGlobalsELF(
1718 IRBuilder<> &IRB, Module &M, ArrayRef ExtendedGlobals,
1719 ArrayRef MetadataInitializers,
1720 const std::string &UniqueModuleId) {
1721 assert(ExtendedGlobals.size() == MetadataInitializers.size());
1722
1723 SmallVector MetadataGlobals(ExtendedGlobals.size());
1724 for (size_t i = 0; i < ExtendedGlobals.size(); i++) {
1725 GlobalVariable *G = ExtendedGlobals[i];
1726 GlobalVariable *Metadata =
1727 CreateMetadataGlobal(M, MetadataInitializers[i], G->getName());
1728 MDNode *MD = MDNode::get(M.getContext(), ValueAsMetadata::get(G));
1729 Metadata->setMetadata(LLVMContext::MD_associated, MD);
1730 MetadataGlobals[i] = Metadata;
1731
1732 SetComdatForGlobalMetadata(G, Metadata, UniqueModuleId);
1733 }
1734
1735 // Update llvm.compiler.used, adding the new metadata globals. This is
1736 // needed so that during LTO these variables stay alive.
1737 if (!MetadataGlobals.empty())
1738 appendToCompilerUsed(M, MetadataGlobals);
1739
1740 // RegisteredFlag serves two purposes. First, we can pass it to dladdr()
1741 // to look up the loaded image that contains it. Second, we can store in it
1742 // whether registration has already occurred, to prevent duplicate
1743 // registration.
1744 //
1745 // Common linkage ensures that there is only one global per shared library.
1746 GlobalVariable *RegisteredFlag = new GlobalVariable(
1747 M, IntptrTy, false, GlobalVariable::CommonLinkage,
1748 ConstantInt::get(IntptrTy, 0), kAsanGlobalsRegisteredFlagName);
1749 RegisteredFlag->setVisibility(GlobalVariable::HiddenVisibility);
1750
1751 // Create start and stop symbols.
1752 GlobalVariable *StartELFMetadata = new GlobalVariable(
1753 M, IntptrTy, false, GlobalVariable::ExternalWeakLinkage, nullptr,
1754 "__start_" + getGlobalMetadataSection());
1755 StartELFMetadata->setVisibility(GlobalVariable::HiddenVisibility);
1756 GlobalVariable *StopELFMetadata = new GlobalVariable(
1757 M, IntptrTy, false, GlobalVariable::ExternalWeakLinkage, nullptr,
1758 "__stop_" + getGlobalMetadataSection());
1759 StopELFMetadata->setVisibility(GlobalVariable::HiddenVisibility);
1760
1761 // Create a call to register the globals with the runtime.
1762 IRB.CreateCall(AsanRegisterElfGlobals,
1763 {IRB.CreatePointerCast(RegisteredFlag, IntptrTy),
1764 IRB.CreatePointerCast(StartELFMetadata, IntptrTy),
1765 IRB.CreatePointerCast(StopELFMetadata, IntptrTy)});
1766
1767 // We also need to unregister globals at the end, e.g., when a shared library
1768 // gets closed.
1769 IRBuilder<> IRB_Dtor = CreateAsanModuleDtor(M);
1770 IRB_Dtor.CreateCall(AsanUnregisterElfGlobals,
1771 {IRB.CreatePointerCast(RegisteredFlag, IntptrTy),
1772 IRB.CreatePointerCast(StartELFMetadata, IntptrTy),
1773 IRB.CreatePointerCast(StopELFMetadata, IntptrTy)});
16831774 }
16841775
16851776 void AddressSanitizerModule::InstrumentGlobalsMachO(
19302021 Initializers[i] = Initializer;
19312022 }
19322023
1933 if (UseGlobalsGC && TargetTriple.isOSBinFormatCOFF()) {
2024 std::string ELFUniqueModuleId =
2025 (UseGlobalsGC && TargetTriple.isOSBinFormatELF()) ? getUniqueModuleId(&M)
2026 : "";
2027
2028 if (!ELFUniqueModuleId.empty()) {
2029 InstrumentGlobalsELF(IRB, M, NewGlobals, Initializers, ELFUniqueModuleId);
2030 *CtorComdat = true;
2031 } else if (UseGlobalsGC && TargetTriple.isOSBinFormatCOFF()) {
19342032 InstrumentGlobalsCOFF(IRB, M, NewGlobals, Initializers);
19352033 } else if (UseGlobalsGC && ShouldUseMachOGlobalsSection()) {
19362034 InstrumentGlobalsMachO(IRB, M, NewGlobals, Initializers);
236236 ComdatEntriesCovered.end();
237237 });
238238 }
239
240 std::string llvm::getUniqueModuleId(Module *M) {
241 MD5 Md5;
242 bool ExportsSymbols = false;
243 auto AddGlobal = [&](GlobalValue &GV) {
244 if (GV.isDeclaration() || GV.getName().startswith("llvm.") ||
245 !GV.hasExternalLinkage())
246 return;
247 ExportsSymbols = true;
248 Md5.update(GV.getName());
249 Md5.update(ArrayRef{0});
250 };
251
252 for (auto &F : *M)
253 AddGlobal(F);
254 for (auto &GV : M->globals())
255 AddGlobal(GV);
256 for (auto &GA : M->aliases())
257 AddGlobal(GA);
258 for (auto &IF : M->ifuncs())
259 AddGlobal(IF);
260
261 if (!ExportsSymbols)
262 return "";
263
264 MD5::MD5Result R;
265 Md5.final(R);
266
267 SmallString<32> Str;
268 MD5::stringifyResult(R, Str);
269 return ("$" + Str).str();
270 }
None ; RUN: opt < %s -asan -asan-module -S | FileCheck %s
0 ; RUN: opt < %s -asan -asan-module -asan-globals-live-support=1 -S | FileCheck %s
11
22 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
33 target triple = "x86_64-unknown-linux-gnu"
1111 @llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_asan_globals.cpp, i8* null }]
1212
1313 ; Check that globals were instrumented:
14 ; CHECK: @global = global { i32, [60 x i8] } zeroinitializer, align 32
15 ; CHECK: @.str = internal unnamed_addr constant { [14 x i8], [50 x i8] } { [14 x i8] c"Hello, world!\00", [50 x i8] zeroinitializer }, align 32
14
15 ; CHECK: @global = global { i32, [60 x i8] } zeroinitializer, comdat, align 32
16 ; CHECK: @.str = internal unnamed_addr constant { [14 x i8], [50 x i8] } { [14 x i8] c"Hello, world!\00", [50 x i8] zeroinitializer }, comdat($".str${{[01-9a-f]+}}"), align 32
1617
1718 ; Check emitted location descriptions:
1819 ; CHECK: [[VARNAME:@__asan_gen_.[0-9]+]] = private unnamed_addr constant [7 x i8] c"global\00", align 1
1920 ; CHECK: [[FILENAME:@__asan_gen_.[0-9]+]] = private unnamed_addr constant [22 x i8] c"/tmp/asan-globals.cpp\00", align 1
2021 ; CHECK: [[LOCDESCR:@__asan_gen_.[0-9]+]] = private unnamed_addr constant { [22 x i8]*, i32, i32 } { [22 x i8]* [[FILENAME]], i32 5, i32 5 }
22 ; CHECK: @__asan_global_global = {{.*}}i64 ptrtoint ({ i32, [60 x i8] }* @global to i64){{.*}} section "asan_globals"{{.*}}, !associated
23 ; CHECK: @__asan_global_.str = {{.*}}i64 ptrtoint ({ [14 x i8], [50 x i8] }* @.str to i64){{.*}} section "asan_globals"{{.*}}, !associated
24
25 ; The metadata has to be inserted to llvm.compiler.used to avoid being stripped
26 ; during LTO.
27 ; CHECK: @llvm.compiler.used {{.*}} @__asan_global_global {{.*}} section "llvm.metadata"
2128
2229 ; Check that location descriptors and global names were passed into __asan_register_globals:
23 ; CHECK: i64 ptrtoint ([7 x i8]* [[VARNAME]] to i64)
24 ; CHECK: i64 ptrtoint ({ [22 x i8]*, i32, i32 }* [[LOCDESCR]] to i64)
30 ; 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))
2531
2632 ; Function Attrs: nounwind sanitize_address
2733 define internal void @__cxx_global_var_init() #0 section ".text.startup" {
11 ; allowing dead stripping to be performed, and that the appropriate runtime
22 ; routines are invoked.
33
4 ; RUN: opt < %s -asan -asan-module -S | FileCheck %s
4 ; RUN: opt < %s -asan -asan-module -asan-globals-live-support=1 -S | FileCheck %s
55
66 target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
77 target triple = "x86_64-apple-macosx10.11.0"
2525 ; CHECK: @llvm.compiler.used {{.*}} @__asan_binder_global {{.*}} section "llvm.metadata"
2626
2727 ; Test that there is the flag global variable:
28 ; CHECK: @__asan_globals_registered = common hidden global i64 0
28 ; CHECK: @___asan_globals_registered = common hidden global i64 0
2929
3030 ; Test that __asan_register_image_globals is invoked from the constructor:
3131 ; CHECK-LABEL: define internal void @asan.module_ctor
3232 ; CHECK-NOT: ret
33 ; CHECK: call void @__asan_register_image_globals(i64 ptrtoint (i64* @__asan_globals_registered to i64))
33 ; CHECK: call void @__asan_register_image_globals(i64 ptrtoint (i64* @___asan_globals_registered to i64))
3434 ; CHECK: ret
3535
3636 ; Test that __asan_unregister_image_globals is invoked from the destructor:
3737 ; CHECK-LABEL: define internal void @asan.module_dtor
3838 ; CHECK-NOT: ret
39 ; CHECK: call void @__asan_unregister_image_globals(i64 ptrtoint (i64* @__asan_globals_registered to i64))
39 ; CHECK: call void @__asan_unregister_image_globals(i64 ptrtoint (i64* @___asan_globals_registered to i64))
4040 ; CHECK: ret
33
44 ; FIXME: Later we can use this to instrument linkonce odr string literals.
55
6 ; RUN: opt < %s -asan -asan-module -S | FileCheck %s
6 ; RUN: opt < %s -asan -asan-module -asan-globals-live-support=1 -S | FileCheck %s
77
88 target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
99 target triple = "x86_64-pc-windows-msvc19.0.24215"
None ; RUN: opt < %s -asan -asan-module -S | FileCheck %s
0 ; RUN: opt < %s -asan -asan-module -asan-globals-live-support=1 -S | FileCheck %s
11 target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
22 target triple = "x86_64-unknown-linux-gnu"
33 @xxx = global i32 0, align 4
7272
7373 ; CHECK-LABEL: define internal void @asan.module_ctor
7474 ; CHECK-NOT: ret
75 ; CHECK: call void @__asan_register_globals
75 ; CHECK: call void @__asan_register_elf_globals
7676 ; CHECK: ret
7777
7878 ; CHECK-LABEL: define internal void @asan.module_dtor
7979 ; CHECK-NOT: ret
80 ; CHECK: call void @__asan_unregister_globals
80 ; CHECK: call void @__asan_unregister_elf_globals
8181 ; CHECK: ret
0 ; A module with no asan-instrumented globals has no asan destructor, and has an asan constructor in a comdat.
1 ; RUN: opt -mtriple=x86_64-unknown-linux-gnu < %s -asan -asan-module -asan-with-comdat=1 -S | FileCheck %s
1 ; RUN: opt -mtriple=x86_64-unknown-linux-gnu < %s -asan -asan-module -asan-with-comdat=1 -asan-globals-live-support=1 -S | FileCheck %s
22
33 define void @f() {
44 ret void