Skip to content

Commit 964f466

Browse files
committed
[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. llvm-svn: 301587
1 parent 716f0ff commit 964f466

File tree

9 files changed

+169
-53
lines changed

9 files changed

+169
-53
lines changed

llvm/include/llvm/Transforms/Utils/ModuleUtils.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,17 @@ void appendToCompilerUsed(Module &M, ArrayRef<GlobalValue *> Values);
8484
void filterDeadComdatFunctions(
8585
Module &M, SmallVectorImpl<Function *> &DeadComdatFunctions);
8686

87+
/// \brief Produce a unique identifier for this module by taking the MD5 sum of
88+
/// the names of the module's strong external symbols.
89+
///
90+
/// This identifier is normally guaranteed to be unique, or the program would
91+
/// fail to link due to multiply defined symbols.
92+
///
93+
/// If the module has no strong external symbols (such a module may still have a
94+
/// semantic effect if it performs global initialization), we cannot produce a
95+
/// unique identifier for this module, so we return the empty string.
96+
std::string getUniqueModuleId(Module *M);
97+
8798
} // End llvm namespace
8899

89100
#endif // LLVM_TRANSFORMS_UTILS_MODULEUTILS_H

llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp

Lines changed: 2 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -30,42 +30,11 @@
3030
#include "llvm/Transforms/IPO.h"
3131
#include "llvm/Transforms/IPO/FunctionAttrs.h"
3232
#include "llvm/Transforms/Utils/Cloning.h"
33+
#include "llvm/Transforms/Utils/ModuleUtils.h"
3334
using namespace llvm;
3435

3536
namespace {
3637

37-
// Produce a unique identifier for this module by taking the MD5 sum of the
38-
// names of the module's strong external symbols. This identifier is
39-
// normally guaranteed to be unique, or the program would fail to link due to
40-
// multiply defined symbols.
41-
//
42-
// If the module has no strong external symbols (such a module may still have a
43-
// semantic effect if it performs global initialization), we cannot produce a
44-
// unique identifier for this module, so we return the empty string, which
45-
// causes the entire module to be written as a regular LTO module.
46-
std::string getModuleId(Module *M) {
47-
MD5 Md5;
48-
bool ExportsSymbols = false;
49-
for (auto &GV : M->global_values()) {
50-
if (GV.isDeclaration() || GV.getName().startswith("llvm.") ||
51-
!GV.hasExternalLinkage())
52-
continue;
53-
ExportsSymbols = true;
54-
Md5.update(GV.getName());
55-
Md5.update(ArrayRef<uint8_t>{0});
56-
}
57-
58-
if (!ExportsSymbols)
59-
return "";
60-
61-
MD5::MD5Result R;
62-
Md5.final(R);
63-
64-
SmallString<32> Str;
65-
MD5::stringifyResult(R, Str);
66-
return ("$" + Str).str();
67-
}
68-
6938
// Promote each local-linkage entity defined by ExportM and used by ImportM by
7039
// changing visibility and appending the given ModuleId.
7140
void promoteInternals(Module &ExportM, Module &ImportM, StringRef ModuleId) {
@@ -251,7 +220,7 @@ void forEachVirtualFunction(Constant *C, function_ref<void(Function *)> Fn) {
251220
void splitAndWriteThinLTOBitcode(
252221
raw_ostream &OS, raw_ostream *ThinLinkOS,
253222
function_ref<AAResults &(Function &)> AARGetter, Module &M) {
254-
std::string ModuleId = getModuleId(&M);
223+
std::string ModuleId = getUniqueModuleId(&M);
255224
if (ModuleId.empty()) {
256225
// We couldn't generate a module ID for this module, just write it out as a
257226
// regular LTO module.

llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp

Lines changed: 104 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@ static const char *const kAsanRegisterImageGlobalsName =
101101
"__asan_register_image_globals";
102102
static const char *const kAsanUnregisterImageGlobalsName =
103103
"__asan_unregister_image_globals";
104+
static const char *const kAsanRegisterElfGlobalsName =
105+
"__asan_register_elf_globals";
106+
static const char *const kAsanUnregisterElfGlobalsName =
107+
"__asan_unregister_elf_globals";
104108
static const char *const kAsanPoisonGlobalsName = "__asan_before_dynamic_init";
105109
static const char *const kAsanUnpoisonGlobalsName = "__asan_after_dynamic_init";
106110
static const char *const kAsanInitName = "__asan_init";
@@ -120,8 +124,11 @@ static const char *const kAsanPoisonStackMemoryName =
120124
"__asan_poison_stack_memory";
121125
static const char *const kAsanUnpoisonStackMemoryName =
122126
"__asan_unpoison_stack_memory";
127+
128+
// ASan version script has __asan_* wildcard. Triple underscore prevents a
129+
// linker (gold) warning about attempting to export a local symbol.
123130
static const char *const kAsanGlobalsRegisteredFlagName =
124-
"__asan_globals_registered";
131+
"___asan_globals_registered";
125132

126133
static const char *const kAsanOptionDetectUseAfterReturn =
127134
"__asan_option_detect_stack_use_after_return";
@@ -618,6 +625,10 @@ class AddressSanitizerModule : public ModulePass {
618625
void InstrumentGlobalsCOFF(IRBuilder<> &IRB, Module &M,
619626
ArrayRef<GlobalVariable *> ExtendedGlobals,
620627
ArrayRef<Constant *> MetadataInitializers);
628+
void InstrumentGlobalsELF(IRBuilder<> &IRB, Module &M,
629+
ArrayRef<GlobalVariable *> ExtendedGlobals,
630+
ArrayRef<Constant *> MetadataInitializers,
631+
const std::string &UniqueModuleId);
621632
void InstrumentGlobalsMachO(IRBuilder<> &IRB, Module &M,
622633
ArrayRef<GlobalVariable *> ExtendedGlobals,
623634
ArrayRef<Constant *> MetadataInitializers);
@@ -628,7 +639,8 @@ class AddressSanitizerModule : public ModulePass {
628639

629640
GlobalVariable *CreateMetadataGlobal(Module &M, Constant *Initializer,
630641
StringRef OriginalName);
631-
void SetComdatForGlobalMetadata(GlobalVariable *G, GlobalVariable *Metadata);
642+
void SetComdatForGlobalMetadata(GlobalVariable *G, GlobalVariable *Metadata,
643+
StringRef InternalSuffix);
632644
IRBuilder<> CreateAsanModuleDtor(Module &M);
633645

634646
bool ShouldInstrumentGlobal(GlobalVariable *G);
@@ -654,6 +666,8 @@ class AddressSanitizerModule : public ModulePass {
654666
Function *AsanUnregisterGlobals;
655667
Function *AsanRegisterImageGlobals;
656668
Function *AsanUnregisterImageGlobals;
669+
Function *AsanRegisterElfGlobals;
670+
Function *AsanUnregisterElfGlobals;
657671

658672
Function *AsanCtorFunction = nullptr;
659673
Function *AsanDtorFunction = nullptr;
@@ -1609,12 +1623,22 @@ void AddressSanitizerModule::initializeCallbacks(Module &M) {
16091623
checkSanitizerInterfaceFunction(M.getOrInsertFunction(
16101624
kAsanUnregisterImageGlobalsName, IRB.getVoidTy(), IntptrTy));
16111625
AsanUnregisterImageGlobals->setLinkage(Function::ExternalLinkage);
1626+
1627+
AsanRegisterElfGlobals = checkSanitizerInterfaceFunction(
1628+
M.getOrInsertFunction(kAsanRegisterElfGlobalsName, IRB.getVoidTy(),
1629+
IntptrTy, IntptrTy, IntptrTy));
1630+
AsanRegisterElfGlobals->setLinkage(Function::ExternalLinkage);
1631+
1632+
AsanUnregisterElfGlobals = checkSanitizerInterfaceFunction(
1633+
M.getOrInsertFunction(kAsanUnregisterElfGlobalsName, IRB.getVoidTy(),
1634+
IntptrTy, IntptrTy, IntptrTy));
1635+
AsanUnregisterElfGlobals->setLinkage(Function::ExternalLinkage);
16121636
}
16131637

16141638
// Put the metadata and the instrumented global in the same group. This ensures
16151639
// that the metadata is discarded if the instrumented global is discarded.
16161640
void AddressSanitizerModule::SetComdatForGlobalMetadata(
1617-
GlobalVariable *G, GlobalVariable *Metadata) {
1641+
GlobalVariable *G, GlobalVariable *Metadata, StringRef InternalSuffix) {
16181642
Module &M = *G->getParent();
16191643
Comdat *C = G->getComdat();
16201644
if (!C) {
@@ -1624,7 +1648,15 @@ void AddressSanitizerModule::SetComdatForGlobalMetadata(
16241648
assert(G->hasLocalLinkage());
16251649
G->setName(Twine(kAsanGenPrefix) + "_anon_global");
16261650
}
1627-
C = M.getOrInsertComdat(G->getName());
1651+
1652+
if (!InternalSuffix.empty() && G->hasLocalLinkage()) {
1653+
std::string Name = G->getName();
1654+
Name += InternalSuffix;
1655+
C = M.getOrInsertComdat(Name);
1656+
} else {
1657+
C = M.getOrInsertComdat(G->getName());
1658+
}
1659+
16281660
// Make this IMAGE_COMDAT_SELECT_NODUPLICATES on COFF.
16291661
if (TargetTriple.isOSBinFormatCOFF())
16301662
C->setSelectionKind(Comdat::NoDuplicates);
@@ -1679,10 +1711,69 @@ void AddressSanitizerModule::InstrumentGlobalsCOFF(
16791711
"global metadata will not be padded appropriately");
16801712
Metadata->setAlignment(SizeOfGlobalStruct);
16811713

1682-
SetComdatForGlobalMetadata(G, Metadata);
1714+
SetComdatForGlobalMetadata(G, Metadata, "");
16831715
}
16841716
}
16851717

1718+
void AddressSanitizerModule::InstrumentGlobalsELF(
1719+
IRBuilder<> &IRB, Module &M, ArrayRef<GlobalVariable *> ExtendedGlobals,
1720+
ArrayRef<Constant *> MetadataInitializers,
1721+
const std::string &UniqueModuleId) {
1722+
assert(ExtendedGlobals.size() == MetadataInitializers.size());
1723+
1724+
SmallVector<GlobalValue *, 16> MetadataGlobals(ExtendedGlobals.size());
1725+
for (size_t i = 0; i < ExtendedGlobals.size(); i++) {
1726+
GlobalVariable *G = ExtendedGlobals[i];
1727+
GlobalVariable *Metadata =
1728+
CreateMetadataGlobal(M, MetadataInitializers[i], G->getName());
1729+
MDNode *MD = MDNode::get(M.getContext(), ValueAsMetadata::get(G));
1730+
Metadata->setMetadata(LLVMContext::MD_associated, MD);
1731+
MetadataGlobals[i] = Metadata;
1732+
1733+
SetComdatForGlobalMetadata(G, Metadata, UniqueModuleId);
1734+
}
1735+
1736+
// Update llvm.compiler.used, adding the new metadata globals. This is
1737+
// needed so that during LTO these variables stay alive.
1738+
if (!MetadataGlobals.empty())
1739+
appendToCompilerUsed(M, MetadataGlobals);
1740+
1741+
// RegisteredFlag serves two purposes. First, we can pass it to dladdr()
1742+
// to look up the loaded image that contains it. Second, we can store in it
1743+
// whether registration has already occurred, to prevent duplicate
1744+
// registration.
1745+
//
1746+
// Common linkage ensures that there is only one global per shared library.
1747+
GlobalVariable *RegisteredFlag = new GlobalVariable(
1748+
M, IntptrTy, false, GlobalVariable::CommonLinkage,
1749+
ConstantInt::get(IntptrTy, 0), kAsanGlobalsRegisteredFlagName);
1750+
RegisteredFlag->setVisibility(GlobalVariable::HiddenVisibility);
1751+
1752+
// Create start and stop symbols.
1753+
GlobalVariable *StartELFMetadata = new GlobalVariable(
1754+
M, IntptrTy, false, GlobalVariable::ExternalWeakLinkage, nullptr,
1755+
"__start_" + getGlobalMetadataSection());
1756+
StartELFMetadata->setVisibility(GlobalVariable::HiddenVisibility);
1757+
GlobalVariable *StopELFMetadata = new GlobalVariable(
1758+
M, IntptrTy, false, GlobalVariable::ExternalWeakLinkage, nullptr,
1759+
"__stop_" + getGlobalMetadataSection());
1760+
StopELFMetadata->setVisibility(GlobalVariable::HiddenVisibility);
1761+
1762+
// Create a call to register the globals with the runtime.
1763+
IRB.CreateCall(AsanRegisterElfGlobals,
1764+
{IRB.CreatePointerCast(RegisteredFlag, IntptrTy),
1765+
IRB.CreatePointerCast(StartELFMetadata, IntptrTy),
1766+
IRB.CreatePointerCast(StopELFMetadata, IntptrTy)});
1767+
1768+
// We also need to unregister globals at the end, e.g., when a shared library
1769+
// gets closed.
1770+
IRBuilder<> IRB_Dtor = CreateAsanModuleDtor(M);
1771+
IRB_Dtor.CreateCall(AsanUnregisterElfGlobals,
1772+
{IRB.CreatePointerCast(RegisteredFlag, IntptrTy),
1773+
IRB.CreatePointerCast(StartELFMetadata, IntptrTy),
1774+
IRB.CreatePointerCast(StopELFMetadata, IntptrTy)});
1775+
}
1776+
16861777
void AddressSanitizerModule::InstrumentGlobalsMachO(
16871778
IRBuilder<> &IRB, Module &M, ArrayRef<GlobalVariable *> ExtendedGlobals,
16881779
ArrayRef<Constant *> MetadataInitializers) {
@@ -1931,7 +2022,14 @@ bool AddressSanitizerModule::InstrumentGlobals(IRBuilder<> &IRB, Module &M, bool
19312022
Initializers[i] = Initializer;
19322023
}
19332024

1934-
if (UseGlobalsGC && TargetTriple.isOSBinFormatCOFF()) {
2025+
std::string ELFUniqueModuleId =
2026+
(UseGlobalsGC && TargetTriple.isOSBinFormatELF()) ? getUniqueModuleId(&M)
2027+
: "";
2028+
2029+
if (!ELFUniqueModuleId.empty()) {
2030+
InstrumentGlobalsELF(IRB, M, NewGlobals, Initializers, ELFUniqueModuleId);
2031+
*CtorComdat = true;
2032+
} else if (UseGlobalsGC && TargetTriple.isOSBinFormatCOFF()) {
19352033
InstrumentGlobalsCOFF(IRB, M, NewGlobals, Initializers);
19362034
} else if (UseGlobalsGC && ShouldUseMachOGlobalsSection()) {
19372035
InstrumentGlobalsMachO(IRB, M, NewGlobals, Initializers);

llvm/lib/Transforms/Utils/ModuleUtils.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,3 +237,35 @@ void llvm::filterDeadComdatFunctions(
237237
ComdatEntriesCovered.end();
238238
});
239239
}
240+
241+
std::string llvm::getUniqueModuleId(Module *M) {
242+
MD5 Md5;
243+
bool ExportsSymbols = false;
244+
auto AddGlobal = [&](GlobalValue &GV) {
245+
if (GV.isDeclaration() || GV.getName().startswith("llvm.") ||
246+
!GV.hasExternalLinkage())
247+
return;
248+
ExportsSymbols = true;
249+
Md5.update(GV.getName());
250+
Md5.update(ArrayRef<uint8_t>{0});
251+
};
252+
253+
for (auto &F : *M)
254+
AddGlobal(F);
255+
for (auto &GV : M->globals())
256+
AddGlobal(GV);
257+
for (auto &GA : M->aliases())
258+
AddGlobal(GA);
259+
for (auto &IF : M->ifuncs())
260+
AddGlobal(IF);
261+
262+
if (!ExportsSymbols)
263+
return "";
264+
265+
MD5::MD5Result R;
266+
Md5.final(R);
267+
268+
SmallString<32> Str;
269+
MD5::stringifyResult(R, Str);
270+
return ("$" + Str).str();
271+
}

llvm/test/Instrumentation/AddressSanitizer/global_metadata.ll

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
; RUN: opt < %s -asan -asan-module -S | FileCheck %s
1+
; RUN: opt < %s -asan -asan-module -asan-globals-live-support=1 -S | FileCheck %s
22

33
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
44
target triple = "x86_64-unknown-linux-gnu"
@@ -12,17 +12,23 @@ target triple = "x86_64-unknown-linux-gnu"
1212
@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_asan_globals.cpp, i8* null }]
1313

1414
; Check that globals were instrumented:
15-
; CHECK: @global = global { i32, [60 x i8] } zeroinitializer, 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 }, align 32
15+
16+
; CHECK: @global = global { i32, [60 x i8] } zeroinitializer, comdat, align 32
17+
; 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
1718

1819
; Check emitted location descriptions:
1920
; CHECK: [[VARNAME:@__asan_gen_.[0-9]+]] = private unnamed_addr constant [7 x i8] c"global\00", align 1
2021
; CHECK: [[FILENAME:@__asan_gen_.[0-9]+]] = private unnamed_addr constant [22 x i8] c"/tmp/asan-globals.cpp\00", align 1
2122
; CHECK: [[LOCDESCR:@__asan_gen_.[0-9]+]] = private unnamed_addr constant { [22 x i8]*, i32, i32 } { [22 x i8]* [[FILENAME]], i32 5, i32 5 }
23+
; CHECK: @__asan_global_global = {{.*}}i64 ptrtoint ({ i32, [60 x i8] }* @global to i64){{.*}} section "asan_globals"{{.*}}, !associated
24+
; CHECK: @__asan_global_.str = {{.*}}i64 ptrtoint ({ [14 x i8], [50 x i8] }* @.str to i64){{.*}} section "asan_globals"{{.*}}, !associated
25+
26+
; The metadata has to be inserted to llvm.compiler.used to avoid being stripped
27+
; during LTO.
28+
; CHECK: @llvm.compiler.used {{.*}} @__asan_global_global {{.*}} section "llvm.metadata"
2229

2330
; Check that location descriptors and global names were passed into __asan_register_globals:
24-
; CHECK: i64 ptrtoint ([7 x i8]* [[VARNAME]] to i64)
25-
; CHECK: i64 ptrtoint ({ [22 x i8]*, i32, i32 }* [[LOCDESCR]] to i64)
31+
; 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))
2632

2733
; Function Attrs: nounwind sanitize_address
2834
define internal void @__cxx_global_var_init() #0 section ".text.startup" {

llvm/test/Instrumentation/AddressSanitizer/global_metadata_darwin.ll

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
; allowing dead stripping to be performed, and that the appropriate runtime
33
; routines are invoked.
44

5-
; RUN: opt < %s -asan -asan-module -S | FileCheck %s
5+
; RUN: opt < %s -asan -asan-module -asan-globals-live-support=1 -S | FileCheck %s
66

77
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
88
target triple = "x86_64-apple-macosx10.11.0"
@@ -26,16 +26,16 @@ target triple = "x86_64-apple-macosx10.11.0"
2626
; CHECK: @llvm.compiler.used {{.*}} @__asan_binder_global {{.*}} section "llvm.metadata"
2727

2828
; Test that there is the flag global variable:
29-
; CHECK: @__asan_globals_registered = common hidden global i64 0
29+
; CHECK: @___asan_globals_registered = common hidden global i64 0
3030

3131
; Test that __asan_register_image_globals is invoked from the constructor:
3232
; CHECK-LABEL: define internal void @asan.module_ctor
3333
; CHECK-NOT: ret
34-
; CHECK: call void @__asan_register_image_globals(i64 ptrtoint (i64* @__asan_globals_registered to i64))
34+
; CHECK: call void @__asan_register_image_globals(i64 ptrtoint (i64* @___asan_globals_registered to i64))
3535
; CHECK: ret
3636

3737
; Test that __asan_unregister_image_globals is invoked from the destructor:
3838
; CHECK-LABEL: define internal void @asan.module_dtor
3939
; CHECK-NOT: ret
40-
; CHECK: call void @__asan_unregister_image_globals(i64 ptrtoint (i64* @__asan_globals_registered to i64))
40+
; CHECK: call void @__asan_unregister_image_globals(i64 ptrtoint (i64* @___asan_globals_registered to i64))
4141
; CHECK: ret

llvm/test/Instrumentation/AddressSanitizer/global_metadata_windows.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
; FIXME: Later we can use this to instrument linkonce odr string literals.
66

7-
; RUN: opt < %s -asan -asan-module -S | FileCheck %s
7+
; RUN: opt < %s -asan -asan-module -asan-globals-live-support=1 -S | FileCheck %s
88

99
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
1010
target triple = "x86_64-pc-windows-msvc19.0.24215"

llvm/test/Instrumentation/AddressSanitizer/instrument_global.ll

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
; RUN: opt < %s -asan -asan-module -S | FileCheck %s
1+
; RUN: opt < %s -asan -asan-module -asan-globals-live-support=1 -S | FileCheck %s
22
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"
33
target triple = "x86_64-unknown-linux-gnu"
44
@xxx = global i32 0, align 4
@@ -73,10 +73,10 @@ entry:
7373

7474
; CHECK-LABEL: define internal void @asan.module_ctor
7575
; CHECK-NOT: ret
76-
; CHECK: call void @__asan_register_globals
76+
; CHECK: call void @__asan_register_elf_globals
7777
; CHECK: ret
7878

7979
; CHECK-LABEL: define internal void @asan.module_dtor
8080
; CHECK-NOT: ret
81-
; CHECK: call void @__asan_unregister_globals
81+
; CHECK: call void @__asan_unregister_elf_globals
8282
; CHECK: ret

llvm/test/Instrumentation/AddressSanitizer/no-globals.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
; A module with no asan-instrumented globals has no asan destructor, and has an asan constructor in a comdat.
2-
; RUN: opt -mtriple=x86_64-unknown-linux-gnu < %s -asan -asan-module -asan-with-comdat=1 -S | FileCheck %s
2+
; RUN: opt -mtriple=x86_64-unknown-linux-gnu < %s -asan -asan-module -asan-with-comdat=1 -asan-globals-live-support=1 -S | FileCheck %s
33

44
define void @f() {
55
ret void

0 commit comments

Comments
 (0)