llvm.org GIT mirror llvm / 642853b
[asan] Support dead code stripping on Mach-O platforms On OS X El Capitan and iOS 9, the linker supports a new section attribute, live_support, which allows dead stripping to remove dead globals along with the ASAN metadata about them. With this change __asan_global structures are emitted in a new __DATA,__asan_globals section on Darwin. Additionally, there is a __DATA,__asan_liveness section with the live_support attribute. Each entry in this section is simply a tuple that binds together the liveness of a global variable and its ASAN metadata structure. Thus the metadata structure will be alive if and only if the global it references is also alive. Review: http://reviews.llvm.org/D16737 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@264645 91177308-0d34-0410-b5e6-96231b3b80d8 Ryan Govostes 4 years ago
3 changed file(s) with 147 addition(s) and 14 deletion(s). Raw diff Collapse all Expand all
9191 static const char *const kAsanRegisterGlobalsName = "__asan_register_globals";
9292 static const char *const kAsanUnregisterGlobalsName =
9393 "__asan_unregister_globals";
94 static const char *const kAsanRegisterImageGlobalsName =
95 "__asan_register_image_globals";
96 static const char *const kAsanUnregisterImageGlobalsName =
97 "__asan_unregister_image_globals";
9498 static const char *const kAsanPoisonGlobalsName = "__asan_before_dynamic_init";
9599 static const char *const kAsanUnpoisonGlobalsName = "__asan_after_dynamic_init";
96100 static const char *const kAsanInitName = "__asan_init";
97101 static const char *const kAsanVersionCheckName =
98 "__asan_version_mismatch_check_v7";
102 "__asan_version_mismatch_check_v8";
99103 static const char *const kAsanPtrCmp = "__sanitizer_ptr_cmp";
100104 static const char *const kAsanPtrSub = "__sanitizer_ptr_sub";
101105 static const char *const kAsanHandleNoReturnName = "__asan_handle_no_return";
109113 "__asan_poison_stack_memory";
110114 static const char *const kAsanUnpoisonStackMemoryName =
111115 "__asan_unpoison_stack_memory";
116 static const char *const kAsanGlobalsRegisteredFlagName =
117 "__asan_globals_registered";
112118
113119 static const char *const kAsanOptionDetectUAR =
114120 "__asan_option_detect_stack_use_after_return";
533539
534540 bool InstrumentGlobals(IRBuilder<> &IRB, Module &M);
535541 bool ShouldInstrumentGlobal(GlobalVariable *G);
542 bool ShouldUseMachOGlobalsSection() const;
536543 void poisonOneInitializer(Function &GlobalInit, GlobalValue *ModuleName);
537544 void createInitializerPoisonCalls(Module &M, GlobalValue *ModuleName);
538545 size_t MinRedzoneSizeForGlobal() const {
550557 Function *AsanUnpoisonGlobals;
551558 Function *AsanRegisterGlobals;
552559 Function *AsanUnregisterGlobals;
560 Function *AsanRegisterImageGlobals;
561 Function *AsanUnregisterImageGlobals;
553562 };
554563
555564 // Stack poisoning does not play well with exception handling.
12861295 return true;
12871296 }
12881297
1298 // On Mach-O platforms, we emit global metadata in a separate section of the
1299 // binary in order to allow the linker to properly dead strip. This is only
1300 // supported on recent versions of ld64.
1301 bool AddressSanitizerModule::ShouldUseMachOGlobalsSection() const {
1302 if (!TargetTriple.isOSBinFormatMachO())
1303 return false;
1304
1305 if (TargetTriple.isMacOSX() && !TargetTriple.isMacOSXVersionLT(10, 11))
1306 return true;
1307 if (TargetTriple.isiOS() /* or tvOS */ && !TargetTriple.isOSVersionLT(9))
1308 return true;
1309 if (TargetTriple.isWatchOS() && !TargetTriple.isOSVersionLT(2))
1310 return true;
1311
1312 return false;
1313 }
1314
12891315 void AddressSanitizerModule::initializeCallbacks(Module &M) {
12901316 IRBuilder<> IRB(*C);
1317
12911318 // Declare our poisoning and unpoisoning functions.
12921319 AsanPoisonGlobals = checkSanitizerInterfaceFunction(M.getOrInsertFunction(
12931320 kAsanPoisonGlobalsName, IRB.getVoidTy(), IntptrTy, nullptr));
12951322 AsanUnpoisonGlobals = checkSanitizerInterfaceFunction(M.getOrInsertFunction(
12961323 kAsanUnpoisonGlobalsName, IRB.getVoidTy(), nullptr));
12971324 AsanUnpoisonGlobals->setLinkage(Function::ExternalLinkage);
1325
12981326 // Declare functions that register/unregister globals.
12991327 AsanRegisterGlobals = checkSanitizerInterfaceFunction(M.getOrInsertFunction(
13001328 kAsanRegisterGlobalsName, IRB.getVoidTy(), IntptrTy, IntptrTy, nullptr));
13031331 M.getOrInsertFunction(kAsanUnregisterGlobalsName, IRB.getVoidTy(),
13041332 IntptrTy, IntptrTy, nullptr));
13051333 AsanUnregisterGlobals->setLinkage(Function::ExternalLinkage);
1334
1335 // Declare the functions that find globals in a shared object and then invoke
1336 // the (un)register function on them.
1337 AsanRegisterImageGlobals = checkSanitizerInterfaceFunction(
1338 M.getOrInsertFunction(kAsanRegisterImageGlobalsName,
1339 IRB.getVoidTy(), IntptrTy, nullptr));
1340 AsanRegisterImageGlobals->setLinkage(Function::ExternalLinkage);
1341
1342 AsanUnregisterImageGlobals = checkSanitizerInterfaceFunction(
1343 M.getOrInsertFunction(kAsanUnregisterImageGlobalsName,
1344 IRB.getVoidTy(), IntptrTy, nullptr));
1345 AsanUnregisterImageGlobals->setLinkage(Function::ExternalLinkage);
13061346 }
13071347
13081348 // This function replaces all global variables with new variables that have
14411481 DEBUG(dbgs() << "NEW GLOBAL: " << *NewGlobal << "\n");
14421482 }
14431483
1444 ArrayType *ArrayOfGlobalStructTy = ArrayType::get(GlobalStructTy, n);
1445 GlobalVariable *AllGlobals = new GlobalVariable(
1446 M, ArrayOfGlobalStructTy, false, GlobalVariable::InternalLinkage,
1447 ConstantArray::get(ArrayOfGlobalStructTy, Initializers), "");
1484
1485 GlobalVariable *AllGlobals = nullptr;
1486 GlobalVariable *RegisteredFlag = nullptr;
1487
1488 // On recent Mach-O platforms, we emit the global metadata in a way that
1489 // allows the linker to properly strip dead globals.
1490 if (ShouldUseMachOGlobalsSection()) {
1491 // RegisteredFlag serves two purposes. First, we can pass it to dladdr()
1492 // to look up the loaded image that contains it. Second, we can store in it
1493 // whether registration has already occurred, to prevent duplicate
1494 // registration.
1495 //
1496 // Common linkage allows us to coalesce needles defined in each object
1497 // file so that there's only one per shared library.
1498 RegisteredFlag = new GlobalVariable(
1499 M, IntptrTy, false, GlobalVariable::CommonLinkage,
1500 ConstantInt::get(IntptrTy, 0), kAsanGlobalsRegisteredFlagName);
1501
1502 // We also emit a structure which binds the liveness of the global
1503 // variable to the metadata struct.
1504 StructType *LivenessTy = StructType::get(IntptrTy, IntptrTy, nullptr);
1505
1506 for (size_t i = 0; i < n; i++) {
1507 GlobalVariable *Metadata = new GlobalVariable(
1508 M, GlobalStructTy, false, GlobalVariable::InternalLinkage,
1509 Initializers[i], "");
1510 Metadata->setSection("__DATA,__asan_globals,regular");
1511 Metadata->setAlignment(1); // don't leave padding in between
1512
1513 auto LivenessBinder = ConstantStruct::get(LivenessTy,
1514 Initializers[i]->getAggregateElement(0u),
1515 ConstantExpr::getPointerCast(Metadata, IntptrTy),
1516 nullptr);
1517 GlobalVariable *Liveness = new GlobalVariable(
1518 M, LivenessTy, false, GlobalVariable::InternalLinkage,
1519 LivenessBinder, "");
1520 Liveness->setSection("__DATA,__asan_liveness,regular,live_support");
1521 }
1522 } else {
1523 // On all other platfoms, we just emit an array of global metadata
1524 // structures.
1525 ArrayType *ArrayOfGlobalStructTy = ArrayType::get(GlobalStructTy, n);
1526 AllGlobals = new GlobalVariable(
1527 M, ArrayOfGlobalStructTy, false, GlobalVariable::InternalLinkage,
1528 ConstantArray::get(ArrayOfGlobalStructTy, Initializers), "");
1529 }
14481530
14491531 // Create calls for poisoning before initializers run and unpoisoning after.
14501532 if (HasDynamicallyInitializedGlobals)
14511533 createInitializerPoisonCalls(M, ModuleName);
1452 IRB.CreateCall(AsanRegisterGlobals,
1453 {IRB.CreatePointerCast(AllGlobals, IntptrTy),
1454 ConstantInt::get(IntptrTy, n)});
1455
1456 // We also need to unregister globals at the end, e.g. when a shared library
1534
1535 // Create a call to register the globals with the runtime.
1536 if (ShouldUseMachOGlobalsSection()) {
1537 IRB.CreateCall(AsanRegisterImageGlobals,
1538 {IRB.CreatePointerCast(RegisteredFlag, IntptrTy)});
1539 } else {
1540 IRB.CreateCall(AsanRegisterGlobals,
1541 {IRB.CreatePointerCast(AllGlobals, IntptrTy),
1542 ConstantInt::get(IntptrTy, n)});
1543 }
1544
1545 // We also need to unregister globals at the end, e.g., when a shared library
14571546 // gets closed.
14581547 Function *AsanDtorFunction =
14591548 Function::Create(FunctionType::get(Type::getVoidTy(*C), false),
14601549 GlobalValue::InternalLinkage, kAsanModuleDtorName, &M);
14611550 BasicBlock *AsanDtorBB = BasicBlock::Create(*C, "", AsanDtorFunction);
14621551 IRBuilder<> IRB_Dtor(ReturnInst::Create(*C, AsanDtorBB));
1463 IRB_Dtor.CreateCall(AsanUnregisterGlobals,
1464 {IRB.CreatePointerCast(AllGlobals, IntptrTy),
1465 ConstantInt::get(IntptrTy, n)});
1552
1553 if (ShouldUseMachOGlobalsSection()) {
1554 IRB_Dtor.CreateCall(AsanUnregisterImageGlobals,
1555 {IRB.CreatePointerCast(RegisteredFlag, IntptrTy)});
1556 } else {
1557 IRB_Dtor.CreateCall(AsanUnregisterGlobals,
1558 {IRB.CreatePointerCast(AllGlobals, IntptrTy),
1559 ConstantInt::get(IntptrTy, n)});
1560 }
1561
14661562 appendToGlobalDtors(M, AsanDtorFunction, kAsanCtorAndDtorPriority);
14671563
14681564 DEBUG(dbgs() << M);
1919 ; CHECK: [[FILENAME:@__asan_gen_.[0-9]+]] = private unnamed_addr constant [22 x i8] c"/tmp/asan-globals.cpp\00", align 1
2020 ; CHECK: [[LOCDESCR:@__asan_gen_.[0-9]+]] = private unnamed_addr constant { [22 x i8]*, i32, i32 } { [22 x i8]* [[FILENAME]], i32 5, i32 5 }
2121
22 ; Check that location decriptors and global names were passed into __asan_register_globals:
22 ; Check that location descriptors and global names were passed into __asan_register_globals:
2323 ; CHECK: i64 ptrtoint ([7 x i8]* [[VARNAME]] to i64)
2424 ; CHECK: i64 ptrtoint ({ [22 x i8]*, i32, i32 }* [[LOCDESCR]] to i64)
2525
0 ; Test that global metadata is placed in a separate section on Mach-O platforms,
1 ; allowing dead stripping to be performed, and that the appropriate runtime
2 ; routines are invoked.
3
4 ; RUN: opt < %s -asan -asan-module -S | FileCheck %s
5
6 target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
7 target triple = "x86_64-apple-macosx10.11.0"
8
9 @global = global [1 x i32] zeroinitializer, align 4
10
11 !llvm.asan.globals = !{!0}
12
13 !0 = !{[1 x i32]* @global, !1, !"global", i1 false, i1 false}
14 !1 = !{!"test-globals.c", i32 1, i32 5}
15
16
17 ; Test that there is a Needle global variable:
18 ; CHECK: @__asan_needle = internal global i64 0
19
20 ; Find the metadata for @global:
21 ; CHECK: [[METADATA:@[0-9]+]] = internal global {{.*}} @global {{.*}} section "__DATA,__asan_globals,regular", align 1
22
23 ; Find the liveness binder for @global and its metadata:
24 ; CHECK: @{{[0-9]+}} = internal global {{.*}} @global {{.*}} [[METADATA]] {{.*}} section "__DATA,__asan_liveness,regular,live_support"
25
26 ; Test that __asan_apply_to_globals is invoked from the constructor:
27 ; CHECK-LABEL: define internal void @asan.module_ctor
28 ; CHECK-NOT: ret
29 ; CHECK: call void @__asan_apply_to_globals(i64 ptrtoint (void (i64, i64)* @__asan_register_globals to i64), i64 ptrtoint (i64* @__asan_needle to i64))
30 ; CHECK: ret
31
32 ; Test that __asan_apply_to_globals is invoked from the destructor:
33 ; CHECK-LABEL: define internal void @asan.module_dtor
34 ; CHECK-NOT: ret
35 ; CHECK: call void @__asan_apply_to_globals(i64 ptrtoint (void (i64, i64)* @__asan_unregister_globals to i64), i64 ptrtoint (i64* @__asan_needle to i64))
36 ; CHECK: ret