@@ -89,6 +89,10 @@ static const char *const kAsanReportErrorTemplate = "__asan_report_";
89
89
static const char *const kAsanRegisterGlobalsName = " __asan_register_globals" ;
90
90
static const char *const kAsanUnregisterGlobalsName =
91
91
" __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" ;
92
96
static const char *const kAsanPoisonGlobalsName = " __asan_before_dynamic_init" ;
93
97
static const char *const kAsanUnpoisonGlobalsName = " __asan_after_dynamic_init" ;
94
98
static const char *const kAsanInitName = " __asan_init" ;
@@ -106,6 +110,8 @@ static const char *const kAsanPoisonStackMemoryName =
106
110
" __asan_poison_stack_memory" ;
107
111
static const char *const kAsanUnpoisonStackMemoryName =
108
112
" __asan_unpoison_stack_memory" ;
113
+ static const char *const kAsanGlobalsRegisteredFlagName =
114
+ " __asan_globals_registered" ;
109
115
110
116
static const char *const kAsanOptionDetectUAR =
111
117
" __asan_option_detect_stack_use_after_return" ;
@@ -226,6 +232,13 @@ static cl::opt<uint32_t> ClForceExperiment(
226
232
cl::desc (" Force optimization experiment (for testing)" ), cl::Hidden,
227
233
cl::init(0 ));
228
234
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
+
229
242
// Debug flags.
230
243
static cl::opt<int > ClDebug (" asan-debug" , cl::desc(" debug" ), cl::Hidden,
231
244
cl::init(0 ));
@@ -520,6 +533,7 @@ class AddressSanitizerModule : public ModulePass {
520
533
521
534
bool InstrumentGlobals (IRBuilder<> &IRB, Module &M);
522
535
bool ShouldInstrumentGlobal (GlobalVariable *G);
536
+ bool ShouldUseMachOGlobalsSection () const ;
523
537
void poisonOneInitializer (Function &GlobalInit, GlobalValue *ModuleName);
524
538
void createInitializerPoisonCalls (Module &M, GlobalValue *ModuleName);
525
539
size_t MinRedzoneSizeForGlobal () const {
@@ -537,6 +551,8 @@ class AddressSanitizerModule : public ModulePass {
537
551
Function *AsanUnpoisonGlobals;
538
552
Function *AsanRegisterGlobals;
539
553
Function *AsanUnregisterGlobals;
554
+ Function *AsanRegisterImageGlobals;
555
+ Function *AsanUnregisterImageGlobals;
540
556
};
541
557
542
558
// Stack poisoning does not play well with exception handling.
@@ -1272,15 +1288,37 @@ bool AddressSanitizerModule::ShouldInstrumentGlobal(GlobalVariable *G) {
1272
1288
return true ;
1273
1289
}
1274
1290
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
+
1275
1311
void AddressSanitizerModule::initializeCallbacks (Module &M) {
1276
1312
IRBuilder<> IRB (*C);
1313
+
1277
1314
// Declare our poisoning and unpoisoning functions.
1278
1315
AsanPoisonGlobals = checkSanitizerInterfaceFunction (M.getOrInsertFunction (
1279
1316
kAsanPoisonGlobalsName , IRB.getVoidTy (), IntptrTy, nullptr ));
1280
1317
AsanPoisonGlobals->setLinkage (Function::ExternalLinkage);
1281
1318
AsanUnpoisonGlobals = checkSanitizerInterfaceFunction (M.getOrInsertFunction (
1282
1319
kAsanUnpoisonGlobalsName , IRB.getVoidTy (), nullptr ));
1283
1320
AsanUnpoisonGlobals->setLinkage (Function::ExternalLinkage);
1321
+
1284
1322
// Declare functions that register/unregister globals.
1285
1323
AsanRegisterGlobals = checkSanitizerInterfaceFunction (M.getOrInsertFunction (
1286
1324
kAsanRegisterGlobalsName , IRB.getVoidTy (), IntptrTy, IntptrTy, nullptr ));
@@ -1289,6 +1327,18 @@ void AddressSanitizerModule::initializeCallbacks(Module &M) {
1289
1327
M.getOrInsertFunction (kAsanUnregisterGlobalsName , IRB.getVoidTy (),
1290
1328
IntptrTy, IntptrTy, nullptr ));
1291
1329
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);
1292
1342
}
1293
1343
1294
1344
// This function replaces all global variables with new variables that have
@@ -1397,28 +1447,84 @@ bool AddressSanitizerModule::InstrumentGlobals(IRBuilder<> &IRB, Module &M) {
1397
1447
DEBUG (dbgs () << " NEW GLOBAL: " << *NewGlobal << " \n " );
1398
1448
}
1399
1449
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
+ }
1404
1496
1405
1497
// Create calls for poisoning before initializers run and unpoisoning after.
1406
1498
if (HasDynamicallyInitializedGlobals)
1407
1499
createInitializerPoisonCalls (M, ModuleName);
1408
- IRB.CreateCall (AsanRegisterGlobals,
1409
- {IRB.CreatePointerCast (AllGlobals, IntptrTy),
1410
- ConstantInt::get (IntptrTy, n)});
1411
1500
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
1413
1512
// gets closed.
1414
1513
Function *AsanDtorFunction =
1415
1514
Function::Create (FunctionType::get (Type::getVoidTy (*C), false ),
1416
1515
GlobalValue::InternalLinkage, kAsanModuleDtorName , &M);
1417
1516
BasicBlock *AsanDtorBB = BasicBlock::Create (*C, " " , AsanDtorFunction);
1418
1517
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
+
1422
1528
appendToGlobalDtors (M, AsanDtorFunction, kAsanCtorAndDtorPriority );
1423
1529
1424
1530
DEBUG (dbgs () << M);
0 commit comments