@@ -270,6 +270,13 @@ static cl::opt<bool>
270
270
" code stripping of globals" ),
271
271
cl::Hidden, cl::init(true ));
272
272
273
+ // This is on by default even though there is a bug in gold:
274
+ // https://sourceware.org/bugzilla/show_bug.cgi?id=19002
275
+ static cl::opt<bool >
276
+ ClWithComdat (" asan-with-comdat" ,
277
+ cl::desc (" Place ASan constructors in comdat sections" ),
278
+ cl::Hidden, cl::init(true ));
279
+
273
280
// Debug flags.
274
281
static cl::opt<int > ClDebug (" asan-debug" , cl::desc(" debug" ), cl::Hidden,
275
282
cl::init(0 ));
@@ -607,7 +614,7 @@ class AddressSanitizerModule : public ModulePass {
607
614
private:
608
615
void initializeCallbacks (Module &M);
609
616
610
- bool InstrumentGlobals (IRBuilder<> &IRB, Module &M);
617
+ bool InstrumentGlobals (IRBuilder<> &IRB, Module &M, bool *CtorComdat );
611
618
void InstrumentGlobalsCOFF (IRBuilder<> &IRB, Module &M,
612
619
ArrayRef<GlobalVariable *> ExtendedGlobals,
613
620
ArrayRef<Constant *> MetadataInitializers);
@@ -647,6 +654,9 @@ class AddressSanitizerModule : public ModulePass {
647
654
Function *AsanUnregisterGlobals;
648
655
Function *AsanRegisterImageGlobals;
649
656
Function *AsanUnregisterImageGlobals;
657
+
658
+ Function *AsanCtorFunction = nullptr ;
659
+ Function *AsanDtorFunction = nullptr ;
650
660
};
651
661
652
662
// Stack poisoning does not play well with exception handling.
@@ -1431,8 +1441,13 @@ void AddressSanitizerModule::poisonOneInitializer(Function &GlobalInit,
1431
1441
void AddressSanitizerModule::createInitializerPoisonCalls (
1432
1442
Module &M, GlobalValue *ModuleName) {
1433
1443
GlobalVariable *GV = M.getGlobalVariable (" llvm.global_ctors" );
1444
+ if (!GV)
1445
+ return ;
1446
+
1447
+ ConstantArray *CA = dyn_cast<ConstantArray>(GV->getInitializer ());
1448
+ if (!CA)
1449
+ return ;
1434
1450
1435
- ConstantArray *CA = cast<ConstantArray>(GV->getInitializer ());
1436
1451
for (Use &OP : CA->operands ()) {
1437
1452
if (isa<ConstantAggregateZero>(OP)) continue ;
1438
1453
ConstantStruct *CS = cast<ConstantStruct>(OP);
@@ -1636,11 +1651,10 @@ AddressSanitizerModule::CreateMetadataGlobal(Module &M, Constant *Initializer,
1636
1651
}
1637
1652
1638
1653
IRBuilder<> AddressSanitizerModule::CreateAsanModuleDtor (Module &M) {
1639
- Function * AsanDtorFunction =
1654
+ AsanDtorFunction =
1640
1655
Function::Create (FunctionType::get (Type::getVoidTy (*C), false ),
1641
1656
GlobalValue::InternalLinkage, kAsanModuleDtorName , &M);
1642
1657
BasicBlock *AsanDtorBB = BasicBlock::Create (*C, " " , AsanDtorFunction);
1643
- appendToGlobalDtors (M, AsanDtorFunction, kAsanCtorAndDtorPriority );
1644
1658
1645
1659
return IRBuilder<>(ReturnInst::Create (*C, AsanDtorBB));
1646
1660
}
@@ -1756,7 +1770,10 @@ void AddressSanitizerModule::InstrumentGlobalsWithMetadataArray(
1756
1770
// This function replaces all global variables with new variables that have
1757
1771
// trailing redzones. It also creates a function that poisons
1758
1772
// redzones and inserts this function into llvm.global_ctors.
1759
- bool AddressSanitizerModule::InstrumentGlobals (IRBuilder<> &IRB, Module &M) {
1773
+ // Sets *CtorComdat to true if the global registration code emitted into the
1774
+ // asan constructor is comdat-compatible.
1775
+ bool AddressSanitizerModule::InstrumentGlobals (IRBuilder<> &IRB, Module &M, bool *CtorComdat) {
1776
+ *CtorComdat = false ;
1760
1777
GlobalsMD.init (M);
1761
1778
1762
1779
SmallVector<GlobalVariable *, 16 > GlobalsToChange;
@@ -1766,7 +1783,10 @@ bool AddressSanitizerModule::InstrumentGlobals(IRBuilder<> &IRB, Module &M) {
1766
1783
}
1767
1784
1768
1785
size_t n = GlobalsToChange.size ();
1769
- if (n == 0 ) return false ;
1786
+ if (n == 0 ) {
1787
+ *CtorComdat = true ;
1788
+ return false ;
1789
+ }
1770
1790
1771
1791
auto &DL = M.getDataLayout ();
1772
1792
@@ -1938,17 +1958,36 @@ bool AddressSanitizerModule::runOnModule(Module &M) {
1938
1958
if (CompileKernel)
1939
1959
return false ;
1940
1960
1941
- Function *AsanCtorFunction;
1961
+ // Create a module constructor. A destructor is created lazily because not all
1962
+ // platforms, and not all modules need it.
1942
1963
std::tie (AsanCtorFunction, std::ignore) = createSanitizerCtorAndInitFunctions (
1943
1964
M, kAsanModuleCtorName , kAsanInitName , /* InitArgTypes=*/ {},
1944
1965
/* InitArgs=*/ {}, kAsanVersionCheckName );
1945
- appendToGlobalCtors (M, AsanCtorFunction, kAsanCtorAndDtorPriority );
1946
1966
1967
+ bool CtorComdat = true ;
1947
1968
bool Changed = false ;
1948
1969
// TODO(glider): temporarily disabled globals instrumentation for KASan.
1949
1970
if (ClGlobals) {
1950
1971
IRBuilder<> IRB (AsanCtorFunction->getEntryBlock ().getTerminator ());
1951
- Changed |= InstrumentGlobals (IRB, M);
1972
+ Changed |= InstrumentGlobals (IRB, M, &CtorComdat);
1973
+ }
1974
+
1975
+ // Put the constructor and destructor in comdat if both
1976
+ // (1) global instrumentation is not TU-specific
1977
+ // (2) target is ELF.
1978
+ if (ClWithComdat && TargetTriple.isOSBinFormatELF () && CtorComdat) {
1979
+ AsanCtorFunction->setComdat (M.getOrInsertComdat (kAsanModuleCtorName ));
1980
+ appendToGlobalCtors (M, AsanCtorFunction, kAsanCtorAndDtorPriority ,
1981
+ AsanCtorFunction);
1982
+ if (AsanDtorFunction) {
1983
+ AsanDtorFunction->setComdat (M.getOrInsertComdat (kAsanModuleDtorName ));
1984
+ appendToGlobalDtors (M, AsanDtorFunction, kAsanCtorAndDtorPriority ,
1985
+ AsanDtorFunction);
1986
+ }
1987
+ } else {
1988
+ appendToGlobalCtors (M, AsanCtorFunction, kAsanCtorAndDtorPriority );
1989
+ if (AsanDtorFunction)
1990
+ appendToGlobalDtors (M, AsanDtorFunction, kAsanCtorAndDtorPriority );
1952
1991
}
1953
1992
1954
1993
return Changed;
0 commit comments