llvm.org GIT mirror llvm / 131962d
[asan] Make ASan compatible with linker dead stripping on Windows Summary: This is similar to what was done for Darwin in rL264645 / http://reviews.llvm.org/D16737, but it uses COFF COMDATs to achive the same result instead of relying on new custom linker features. As on MachO, this creates one metadata global per instrumented global. The metadata global is placed in the custom .ASAN$GL section, which the ASan runtime will iterate over during initialization. There are no other references to the metadata, so normal linker dead stripping would discard it. However, the metadata is put in a COMDAT group with the instrumented global, so that it will be discarded if and only if the instrumented global is discarded. I didn't update the ASan ABI version check since this doesn't affect non-Windows platforms, and the WinASan ABI isn't really stable yet. Implementing this for ELF will require extending LLVM IR and MC a bit so that we can use non-COMDAT section groups. Reviewers: pcc, kcc, mehdi_amini, kubabrecka Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D26770 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@287576 91177308-0d34-0410-b5e6-96231b3b80d8 Reid Kleckner 4 years ago
3 changed file(s) with 141 addition(s) and 53 deletion(s). Raw diff Collapse all Expand all
600600 bool InstrumentGlobals(IRBuilder<> &IRB, Module &M);
601601 bool ShouldInstrumentGlobal(GlobalVariable *G);
602602 bool ShouldUseMachOGlobalsSection() const;
603 StringRef getGlobalMetadataSection() const;
603604 void poisonOneInitializer(Function &GlobalInit, GlobalValue *ModuleName);
604605 void createInitializerPoisonCalls(Module &M, GlobalValue *ModuleName);
605606 size_t MinRedzoneSizeForGlobal() const {
15011502 return false;
15021503 }
15031504
1505 StringRef AddressSanitizerModule::getGlobalMetadataSection() const {
1506 switch (TargetTriple.getObjectFormat()) {
1507 case Triple::COFF: return ".ASAN$GL";
1508 case Triple::ELF: return "asan_globals";
1509 case Triple::MachO: return "__DATA,__asan_globals,regular";
1510 default: break;
1511 }
1512 llvm_unreachable("unsupported object format");
1513 }
1514
15041515 void AddressSanitizerModule::initializeCallbacks(Module &M) {
15051516 IRBuilder<> IRB(*C);
15061517
15481559
15491560 size_t n = GlobalsToChange.size();
15501561 if (n == 0) return false;
1562
1563 bool UseComdatMetadata = TargetTriple.isOSBinFormatCOFF();
1564 bool UseMachOGlobalsSection = ShouldUseMachOGlobalsSection();
1565 bool UseMetadataArray = !(UseComdatMetadata || UseMachOGlobalsSection);
15511566
15521567 // A global is described by a structure
15531568 // size_t beg;
15621577 StructType *GlobalStructTy =
15631578 StructType::get(IntptrTy, IntptrTy, IntptrTy, IntptrTy, IntptrTy,
15641579 IntptrTy, IntptrTy, IntptrTy, nullptr);
1565 SmallVector Initializers(n);
1580 SmallVector Initializers(UseMetadataArray ? n : 0);
1581
1582 // On recent Mach-O platforms, use a structure which binds the liveness of
1583 // the global variable to the metadata struct. Keep the list of "Liveness" GV
1584 // created to be added to llvm.compiler.used
1585 StructType *LivenessTy = nullptr;
1586 if (UseMachOGlobalsSection)
1587 LivenessTy = StructType::get(IntptrTy, IntptrTy, nullptr);
1588 SmallVector LivenessGlobals(
1589 UseMachOGlobalsSection ? n : 0);
15661590
15671591 bool HasDynamicallyInitializedGlobals = false;
15681592
16351659 ConstantExpr::getGetElementPtr(NewTy, NewGlobal, Indices2, true));
16361660 NewGlobal->takeName(G);
16371661 G->eraseFromParent();
1662 G = NewGlobal;
1663
1664 if (UseComdatMetadata) {
1665 // Get or create a COMDAT for G so that we can use it with our metadata.
1666 Comdat *C = G->getComdat();
1667 if (!C) {
1668 if (!G->hasName()) {
1669 // If G is unnamed, it must be internal. Give it an artificial name
1670 // so we can put it in a comdat.
1671 assert(G->hasLocalLinkage());
1672 G->setName(Twine(kAsanGenPrefix) + "_anon_global");
1673 }
1674 C = M.getOrInsertComdat(G->getName());
1675 // Make this IMAGE_COMDAT_SELECT_NODUPLICATES on COFF.
1676 if (TargetTriple.isOSBinFormatCOFF())
1677 C->setSelectionKind(Comdat::NoDuplicates);
1678 G->setComdat(C);
1679 }
1680 }
16381681
16391682 Constant *SourceLoc;
16401683 if (!MD.SourceLoc.empty()) {
16711714 InstrumentedGlobal = GA;
16721715 }
16731716
1674 Initializers[i] = ConstantStruct::get(
1717 Constant *Initializer = ConstantStruct::get(
16751718 GlobalStructTy,
16761719 ConstantExpr::getPointerCast(InstrumentedGlobal, IntptrTy),
16771720 ConstantInt::get(IntptrTy, SizeInBytes),
16841727 if (ClInitializers && MD.IsDynInit) HasDynamicallyInitializedGlobals = true;
16851728
16861729 DEBUG(dbgs() << "NEW GLOBAL: " << *NewGlobal << "\n");
1687 }
1688
1730
1731 // If we aren't using separate metadata globals, add it to the initializer
1732 // list and continue.
1733 if (UseMetadataArray) {
1734 Initializers[i] = Initializer;
1735 continue;
1736 }
1737
1738 // Create a separate metadata global and put it in the appropriate ASan
1739 // global registration section.
1740 GlobalVariable *Metadata = new GlobalVariable(
1741 M, GlobalStructTy, false, GlobalVariable::InternalLinkage,
1742 Initializer, Twine("__asan_global_") +
1743 GlobalValue::getRealLinkageName(G->getName()));
1744 Metadata->setSection(getGlobalMetadataSection());
1745 Metadata->setAlignment(1); // Don't leave padding in between.
1746
1747 // On platforms that support comdats, put the metadata and the
1748 // instrumented global in the same group. This ensures that the metadata
1749 // is discarded if the instrumented global is discarded.
1750 if (UseComdatMetadata) {
1751 assert(G->hasComdat());
1752 Metadata->setComdat(G->getComdat());
1753 continue;
1754 }
1755 assert(UseMachOGlobalsSection);
1756
1757 // On recent Mach-O platforms, we emit the global metadata in a way that
1758 // allows the linker to properly strip dead globals.
1759 auto LivenessBinder = ConstantStruct::get(
1760 LivenessTy, Initializer->getAggregateElement(0u),
1761 ConstantExpr::getPointerCast(Metadata, IntptrTy), nullptr);
1762 GlobalVariable *Liveness = new GlobalVariable(
1763 M, LivenessTy, false, GlobalVariable::InternalLinkage, LivenessBinder,
1764 Twine("__asan_binder_") + G->getName());
1765 Liveness->setSection("__DATA,__asan_liveness,regular,live_support");
1766 LivenessGlobals[i] = Liveness;
1767 }
1768
1769 // Create calls for poisoning before initializers run and unpoisoning after.
1770 if (HasDynamicallyInitializedGlobals)
1771 createInitializerPoisonCalls(M, ModuleName);
1772
1773 // Platforms with a dedicated metadata section don't need to emit any more
1774 // code.
1775 if (UseComdatMetadata)
1776 return true;
16891777
16901778 GlobalVariable *AllGlobals = nullptr;
16911779 GlobalVariable *RegisteredFlag = nullptr;
16921780
1693 // On recent Mach-O platforms, we emit the global metadata in a way that
1694 // allows the linker to properly strip dead globals.
1695 if (ShouldUseMachOGlobalsSection()) {
1781 if (UseMachOGlobalsSection) {
16961782 // RegisteredFlag serves two purposes. First, we can pass it to dladdr()
16971783 // to look up the loaded image that contains it. Second, we can store in it
16981784 // whether registration has already occurred, to prevent duplicate
16991785 // registration.
17001786 //
1701 // Common linkage allows us to coalesce needles defined in each object
1702 // file so that there's only one per shared library.
1787 // common linkage ensures that there is only one global per shared library.
17031788 RegisteredFlag = new GlobalVariable(
17041789 M, IntptrTy, false, GlobalVariable::CommonLinkage,
17051790 ConstantInt::get(IntptrTy, 0), kAsanGlobalsRegisteredFlagName);
1706
1707 // We also emit a structure which binds the liveness of the global
1708 // variable to the metadata struct.
1709 StructType *LivenessTy = StructType::get(IntptrTy, IntptrTy, nullptr);
1710
1711 // Keep the list of "Liveness" GV created to be added to llvm.compiler.used
1712 SmallVector LivenessGlobals;
1713 LivenessGlobals.reserve(n);
1714
1715 for (size_t i = 0; i < n; i++) {
1716 GlobalVariable *Metadata = new GlobalVariable(
1717 M, GlobalStructTy, false, GlobalVariable::InternalLinkage,
1718 Initializers[i], "");
1719 Metadata->setSection("__DATA,__asan_globals,regular");
1720 Metadata->setAlignment(1); // don't leave padding in between
1721
1722 auto LivenessBinder = ConstantStruct::get(LivenessTy,
1723 Initializers[i]->getAggregateElement(0u),
1724 ConstantExpr::getPointerCast(Metadata, IntptrTy),
1725 nullptr);
1726
1727 // Recover the name of the variable this global is pointing to
1728 StringRef GVName =
1729 Initializers[i]->getAggregateElement(0u)->getOperand(0)->getName();
1730
1731 GlobalVariable *Liveness = new GlobalVariable(
1732 M, LivenessTy, false, GlobalVariable::InternalLinkage, LivenessBinder,
1733 Twine("__asan_binder_") + GVName);
1734 Liveness->setSection("__DATA,__asan_liveness,regular,live_support");
1735 LivenessGlobals.push_back(Liveness);
1736 }
17371791
17381792 // Update llvm.compiler.used, adding the new liveness globals. This is
17391793 // needed so that during LTO these variables stay alive. The alternative
17411795 // current API does not expose access to the section for each symbol.
17421796 if (!LivenessGlobals.empty())
17431797 appendToCompilerUsed(M, LivenessGlobals);
1744 } else {
1745 // On all other platfoms, we just emit an array of global metadata
1746 // structures.
1798 } else if (UseMetadataArray) {
1799 // On platforms that don't have a custom metadata section, we emit an array
1800 // of global metadata structures.
17471801 ArrayType *ArrayOfGlobalStructTy = ArrayType::get(GlobalStructTy, n);
17481802 AllGlobals = new GlobalVariable(
17491803 M, ArrayOfGlobalStructTy, false, GlobalVariable::InternalLinkage,
17501804 ConstantArray::get(ArrayOfGlobalStructTy, Initializers), "");
17511805 }
17521806
1753 // Create calls for poisoning before initializers run and unpoisoning after.
1754 if (HasDynamicallyInitializedGlobals)
1755 createInitializerPoisonCalls(M, ModuleName);
1756
17571807 // Create a call to register the globals with the runtime.
1758 if (ShouldUseMachOGlobalsSection()) {
1808 if (UseMachOGlobalsSection) {
17591809 IRB.CreateCall(AsanRegisterImageGlobals,
17601810 {IRB.CreatePointerCast(RegisteredFlag, IntptrTy)});
17611811 } else {
17721822 BasicBlock *AsanDtorBB = BasicBlock::Create(*C, "", AsanDtorFunction);
17731823 IRBuilder<> IRB_Dtor(ReturnInst::Create(*C, AsanDtorBB));
17741824
1775 if (ShouldUseMachOGlobalsSection()) {
1825 if (UseMachOGlobalsSection) {
17761826 IRB_Dtor.CreateCall(AsanUnregisterImageGlobals,
17771827 {IRB.CreatePointerCast(RegisteredFlag, IntptrTy)});
17781828 } else {
1414 !1 = !{!"test-globals.c", i32 1, i32 5}
1515
1616
17 ; Test that there is the flag global variable:
18 ; CHECK: @__asan_globals_registered = common global i64 0
19
2017 ; Find the metadata for @global:
21 ; CHECK: [[METADATA:@[0-9]+]] = internal global {{.*}} @global {{.*}} section "__DATA,__asan_globals,regular", align 1
18 ; CHECK: [[METADATA:@.+]] = internal global {{.*}} @global {{.*}} section "__DATA,__asan_globals,regular", align 1
2219
2320 ; Find the liveness binder for @global and its metadata:
2421 ; CHECK: @__asan_binder_global = internal global {{.*}} @global {{.*}} [[METADATA]] {{.*}} section "__DATA,__asan_liveness,regular,live_support"
22
23 ; Test that there is the flag global variable:
24 ; CHECK: @__asan_globals_registered = common global i64 0
2525
2626 ; The binder has to be inserted to llvm.compiler.used to avoid being stripped
2727 ; during LTO.
0 ; Test that global metadata is placed in a separate section on Windows, and that
1 ; it is in the same comdat group as the instrumented global. This ensures that
2 ; linker dead stripping (/OPT:REF) works as intended.
3
4 ; FIXME: Later we can use this to instrument linkonce odr string literals.
5
6 ; RUN: opt < %s -asan -asan-module -S | FileCheck %s
7
8 target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
9 target triple = "x86_64-pc-windows-msvc19.0.24215"
10
11 $mystr = comdat any
12
13 ; CHECK: $dead_global = comdat noduplicates
14 ; CHECK: @dead_global = local_unnamed_addr global { i32, [60 x i8] } { i32 42, [60 x i8] zeroinitializer }, comdat, align 32
15 ; CHECK: @__asan_global_dead_global = internal global { {{.*}} }, section ".ASAN$GL", comdat($dead_global), align 1
16
17 @dead_global = local_unnamed_addr global i32 42, align 4
18 @mystr = linkonce_odr unnamed_addr constant [5 x i8] c"main\00", comdat, align 1
19
20 ; Function Attrs: nounwind uwtable
21 define i32 @main() local_unnamed_addr #0 {
22 entry:
23 %call = tail call i32 @puts(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @mystr, i64 0, i64 0))
24 ret i32 0
25 }
26
27 ; Function Attrs: nounwind
28 declare i32 @puts(i8* nocapture readonly) local_unnamed_addr #1
29
30 attributes #0 = { nounwind uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
31 attributes #1 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
32
33 !llvm.module.flags = !{!0}
34 !llvm.ident = !{!1}
35
36 !0 = !{i32 1, !"PIC Level", i32 2}
37 !1 = !{!"clang version 4.0.0 "}