@@ -89,6 +89,10 @@ static const char *const kAsanReportErrorTemplate = "__asan_report_";
8989static const char *const kAsanRegisterGlobalsName = " __asan_register_globals" ;
9090static const char *const kAsanUnregisterGlobalsName =
9191 " __asan_unregister_globals" ;
92+ static const char *const kAsanRegisterImageGlobalsName =
93+ " __asan_register_image_globals" ;
94+ static const char *const kAsanUnregisterImageGlobalsName =
95+ " __asan_unregister_image_globals" ;
9296static const char *const kAsanPoisonGlobalsName = " __asan_before_dynamic_init" ;
9397static const char *const kAsanUnpoisonGlobalsName = " __asan_after_dynamic_init" ;
9498static const char *const kAsanInitName = " __asan_init" ;
@@ -106,6 +110,8 @@ static const char *const kAsanPoisonStackMemoryName =
106110 " __asan_poison_stack_memory" ;
107111static const char *const kAsanUnpoisonStackMemoryName =
108112 " __asan_unpoison_stack_memory" ;
113+ static const char *const kAsanGlobalsRegisteredFlagName =
114+ " __asan_globals_registered" ;
109115
110116static const char *const kAsanOptionDetectUAR =
111117 " __asan_option_detect_stack_use_after_return" ;
@@ -226,6 +232,13 @@ static cl::opt<uint32_t> ClForceExperiment(
226232 cl::desc (" Force optimization experiment (for testing)" ), cl::Hidden,
227233 cl::init(0 ));
228234
235+ static cl::opt<bool >
236+ ClUseMachOGlobalsSection (" asan-globals-live-support" ,
237+ cl::desc (" Use linker features to support dead "
238+ " code stripping of globals "
239+ " (Mach-O only)" ),
240+ cl::Hidden, cl::init(false ));
241+
229242// Debug flags.
230243static cl::opt<int > ClDebug (" asan-debug" , cl::desc(" debug" ), cl::Hidden,
231244 cl::init(0 ));
@@ -520,6 +533,7 @@ class AddressSanitizerModule : public ModulePass {
520533
521534 bool InstrumentGlobals (IRBuilder<> &IRB, Module &M);
522535 bool ShouldInstrumentGlobal (GlobalVariable *G);
536+ bool ShouldUseMachOGlobalsSection () const ;
523537 void poisonOneInitializer (Function &GlobalInit, GlobalValue *ModuleName);
524538 void createInitializerPoisonCalls (Module &M, GlobalValue *ModuleName);
525539 size_t MinRedzoneSizeForGlobal () const {
@@ -537,6 +551,8 @@ class AddressSanitizerModule : public ModulePass {
537551 Function *AsanUnpoisonGlobals;
538552 Function *AsanRegisterGlobals;
539553 Function *AsanUnregisterGlobals;
554+ Function *AsanRegisterImageGlobals;
555+ Function *AsanUnregisterImageGlobals;
540556};
541557
542558// Stack poisoning does not play well with exception handling.
@@ -1272,15 +1288,37 @@ bool AddressSanitizerModule::ShouldInstrumentGlobal(GlobalVariable *G) {
12721288 return true ;
12731289}
12741290
1291+ // On Mach-O platforms, we emit global metadata in a separate section of the
1292+ // binary in order to allow the linker to properly dead strip. This is only
1293+ // supported on recent versions of ld64.
1294+ bool AddressSanitizerModule::ShouldUseMachOGlobalsSection () const {
1295+ if (!ClUseMachOGlobalsSection)
1296+ return false ;
1297+
1298+ if (!TargetTriple.isOSBinFormatMachO ())
1299+ return false ;
1300+
1301+ if (TargetTriple.isMacOSX () && !TargetTriple.isMacOSXVersionLT (10 , 11 ))
1302+ return true ;
1303+ if (TargetTriple.isiOS () /* or tvOS */ && !TargetTriple.isOSVersionLT (9 ))
1304+ return true ;
1305+ if (TargetTriple.isWatchOS () && !TargetTriple.isOSVersionLT (2 ))
1306+ return true ;
1307+
1308+ return false ;
1309+ }
1310+
12751311void AddressSanitizerModule::initializeCallbacks (Module &M) {
12761312 IRBuilder<> IRB (*C);
1313+
12771314 // Declare our poisoning and unpoisoning functions.
12781315 AsanPoisonGlobals = checkSanitizerInterfaceFunction (M.getOrInsertFunction (
12791316 kAsanPoisonGlobalsName , IRB.getVoidTy (), IntptrTy, nullptr ));
12801317 AsanPoisonGlobals->setLinkage (Function::ExternalLinkage);
12811318 AsanUnpoisonGlobals = checkSanitizerInterfaceFunction (M.getOrInsertFunction (
12821319 kAsanUnpoisonGlobalsName , IRB.getVoidTy (), nullptr ));
12831320 AsanUnpoisonGlobals->setLinkage (Function::ExternalLinkage);
1321+
12841322 // Declare functions that register/unregister globals.
12851323 AsanRegisterGlobals = checkSanitizerInterfaceFunction (M.getOrInsertFunction (
12861324 kAsanRegisterGlobalsName , IRB.getVoidTy (), IntptrTy, IntptrTy, nullptr ));
@@ -1289,6 +1327,18 @@ void AddressSanitizerModule::initializeCallbacks(Module &M) {
12891327 M.getOrInsertFunction (kAsanUnregisterGlobalsName , IRB.getVoidTy (),
12901328 IntptrTy, IntptrTy, nullptr ));
12911329 AsanUnregisterGlobals->setLinkage (Function::ExternalLinkage);
1330+
1331+ // Declare the functions that find globals in a shared object and then invoke
1332+ // the (un)register function on them.
1333+ AsanRegisterImageGlobals = checkSanitizerInterfaceFunction (
1334+ M.getOrInsertFunction (kAsanRegisterImageGlobalsName ,
1335+ IRB.getVoidTy (), IntptrTy, nullptr ));
1336+ AsanRegisterImageGlobals->setLinkage (Function::ExternalLinkage);
1337+
1338+ AsanUnregisterImageGlobals = checkSanitizerInterfaceFunction (
1339+ M.getOrInsertFunction (kAsanUnregisterImageGlobalsName ,
1340+ IRB.getVoidTy (), IntptrTy, nullptr ));
1341+ AsanUnregisterImageGlobals->setLinkage (Function::ExternalLinkage);
12921342}
12931343
12941344// This function replaces all global variables with new variables that have
@@ -1397,28 +1447,84 @@ bool AddressSanitizerModule::InstrumentGlobals(IRBuilder<> &IRB, Module &M) {
13971447 DEBUG (dbgs () << " NEW GLOBAL: " << *NewGlobal << " \n " );
13981448 }
13991449
1400- ArrayType *ArrayOfGlobalStructTy = ArrayType::get (GlobalStructTy, n);
1401- GlobalVariable *AllGlobals = new GlobalVariable (
1402- M, ArrayOfGlobalStructTy, false , GlobalVariable::InternalLinkage,
1403- ConstantArray::get (ArrayOfGlobalStructTy, Initializers), " " );
1450+
1451+ GlobalVariable *AllGlobals = nullptr ;
1452+ GlobalVariable *RegisteredFlag = nullptr ;
1453+
1454+ // On recent Mach-O platforms, we emit the global metadata in a way that
1455+ // allows the linker to properly strip dead globals.
1456+ if (ShouldUseMachOGlobalsSection ()) {
1457+ // RegisteredFlag serves two purposes. First, we can pass it to dladdr()
1458+ // to look up the loaded image that contains it. Second, we can store in it
1459+ // whether registration has already occurred, to prevent duplicate
1460+ // registration.
1461+ //
1462+ // Common linkage allows us to coalesce needles defined in each object
1463+ // file so that there's only one per shared library.
1464+ RegisteredFlag = new GlobalVariable (
1465+ M, IntptrTy, false , GlobalVariable::CommonLinkage,
1466+ ConstantInt::get (IntptrTy, 0 ), kAsanGlobalsRegisteredFlagName );
1467+
1468+ // We also emit a structure which binds the liveness of the global
1469+ // variable to the metadata struct.
1470+ StructType *LivenessTy = StructType::get (IntptrTy, IntptrTy, nullptr );
1471+
1472+ for (size_t i = 0 ; i < n; i++) {
1473+ GlobalVariable *Metadata = new GlobalVariable (
1474+ M, GlobalStructTy, false , GlobalVariable::InternalLinkage,
1475+ Initializers[i], " " );
1476+ Metadata->setSection (" __DATA,__asan_globals,regular" );
1477+ Metadata->setAlignment (1 ); // don't leave padding in between
1478+
1479+ auto LivenessBinder = ConstantStruct::get (LivenessTy,
1480+ Initializers[i]->getAggregateElement (0u ),
1481+ ConstantExpr::getPointerCast (Metadata, IntptrTy),
1482+ nullptr );
1483+ GlobalVariable *Liveness = new GlobalVariable (
1484+ M, LivenessTy, false , GlobalVariable::InternalLinkage,
1485+ LivenessBinder, " " );
1486+ Liveness->setSection (" __DATA,__asan_liveness,regular,live_support" );
1487+ }
1488+ } else {
1489+ // On all other platfoms, we just emit an array of global metadata
1490+ // structures.
1491+ ArrayType *ArrayOfGlobalStructTy = ArrayType::get (GlobalStructTy, n);
1492+ AllGlobals = new GlobalVariable (
1493+ M, ArrayOfGlobalStructTy, false , GlobalVariable::InternalLinkage,
1494+ ConstantArray::get (ArrayOfGlobalStructTy, Initializers), " " );
1495+ }
14041496
14051497 // Create calls for poisoning before initializers run and unpoisoning after.
14061498 if (HasDynamicallyInitializedGlobals)
14071499 createInitializerPoisonCalls (M, ModuleName);
1408- IRB.CreateCall (AsanRegisterGlobals,
1409- {IRB.CreatePointerCast (AllGlobals, IntptrTy),
1410- ConstantInt::get (IntptrTy, n)});
14111500
1412- // We also need to unregister globals at the end, e.g. when a shared library
1501+ // Create a call to register the globals with the runtime.
1502+ if (ShouldUseMachOGlobalsSection ()) {
1503+ IRB.CreateCall (AsanRegisterImageGlobals,
1504+ {IRB.CreatePointerCast (RegisteredFlag, IntptrTy)});
1505+ } else {
1506+ IRB.CreateCall (AsanRegisterGlobals,
1507+ {IRB.CreatePointerCast (AllGlobals, IntptrTy),
1508+ ConstantInt::get (IntptrTy, n)});
1509+ }
1510+
1511+ // We also need to unregister globals at the end, e.g., when a shared library
14131512 // gets closed.
14141513 Function *AsanDtorFunction =
14151514 Function::Create (FunctionType::get (Type::getVoidTy (*C), false ),
14161515 GlobalValue::InternalLinkage, kAsanModuleDtorName , &M);
14171516 BasicBlock *AsanDtorBB = BasicBlock::Create (*C, " " , AsanDtorFunction);
14181517 IRBuilder<> IRB_Dtor (ReturnInst::Create (*C, AsanDtorBB));
1419- IRB_Dtor.CreateCall (AsanUnregisterGlobals,
1420- {IRB.CreatePointerCast (AllGlobals, IntptrTy),
1421- ConstantInt::get (IntptrTy, n)});
1518+
1519+ if (ShouldUseMachOGlobalsSection ()) {
1520+ IRB_Dtor.CreateCall (AsanUnregisterImageGlobals,
1521+ {IRB.CreatePointerCast (RegisteredFlag, IntptrTy)});
1522+ } else {
1523+ IRB_Dtor.CreateCall (AsanUnregisterGlobals,
1524+ {IRB.CreatePointerCast (AllGlobals, IntptrTy),
1525+ ConstantInt::get (IntptrTy, n)});
1526+ }
1527+
14221528 appendToGlobalDtors (M, AsanDtorFunction, kAsanCtorAndDtorPriority );
14231529
14241530 DEBUG (dbgs () << M);
0 commit comments