1 //===- lib/ReaderWriter/MachO/TLVPass.cpp -----------------------*- C++ -*-===// 2 // 3 // The LLVM Linker 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 /// 10 /// \file 11 /// This linker pass transforms all TLV references to real references. 12 /// 13 //===----------------------------------------------------------------------===// 14 15 #include "ArchHandler.h" 16 #include "File.h" 17 #include "MachOPasses.h" 18 #include "lld/Core/Simple.h" 19 #include "llvm/ADT/STLExtras.h" 20 #include "llvm/Support/Debug.h" 21 22 namespace lld { 23 namespace mach_o { 24 25 // 26 // TLVP Entry Atom created by the TLV pass. 27 // 28 class TLVPEntryAtom : public SimpleDefinedAtom { 29 public: 30 TLVPEntryAtom(const File &file, bool is64, StringRef name) 31 : SimpleDefinedAtom(file), _is64(is64), _name(name) {} 32 33 ~TLVPEntryAtom() override = default; 34 35 ContentType contentType() const override { 36 return DefinedAtom::typeTLVInitializerPtr; 37 } 38 39 Alignment alignment() const override { 40 return _is64 ? 8 : 4; 41 } 42 43 uint64_t size() const override { 44 return _is64 ? 8 : 4; 45 } 46 47 ContentPermissions permissions() const override { 48 return DefinedAtom::permRW_; 49 } 50 51 ArrayRef<uint8_t> rawContent() const override { 52 static const uint8_t zeros[] = 53 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 54 return llvm::makeArrayRef(zeros, size()); 55 } 56 57 StringRef slotName() const { 58 return _name; 59 } 60 61 private: 62 const bool _is64; 63 StringRef _name; 64 }; 65 66 class TLVPass : public Pass { 67 public: 68 TLVPass(const MachOLinkingContext &context) 69 : _ctx(context), _archHandler(_ctx.archHandler()), 70 _file(*_ctx.make_file<MachOFile>("<mach-o TLV pass>")) { 71 _file.setOrdinal(_ctx.getNextOrdinalAndIncrement()); 72 } 73 74 private: 75 llvm::Error perform(SimpleFile &mergedFile) override { 76 bool allowTLV = _ctx.minOS("10.7", "1.0"); 77 78 for (const DefinedAtom *atom : mergedFile.defined()) { 79 for (const Reference *ref : *atom) { 80 if (!_archHandler.isTLVAccess(*ref)) 81 continue; 82 83 if (!allowTLV) 84 return llvm::make_error<GenericError>( 85 "targeted OS version does not support use of thread local " 86 "variables in " + atom->name() + " for architecture " + 87 _ctx.archName()); 88 89 const Atom *target = ref->target(); 90 assert(target != nullptr); 91 92 const DefinedAtom *tlvpEntry = makeTLVPEntry(target); 93 const_cast<Reference*>(ref)->setTarget(tlvpEntry); 94 _archHandler.updateReferenceToTLV(ref); 95 } 96 } 97 98 std::vector<const TLVPEntryAtom*> entries; 99 entries.reserve(_targetToTLVP.size()); 100 for (auto &it : _targetToTLVP) 101 entries.push_back(it.second); 102 std::sort(entries.begin(), entries.end(), 103 [](const TLVPEntryAtom *lhs, const TLVPEntryAtom *rhs) { 104 return (lhs->slotName().compare(rhs->slotName()) < 0); 105 }); 106 107 for (const TLVPEntryAtom *slot : entries) 108 mergedFile.addAtom(*slot); 109 110 return llvm::Error(); 111 } 112 113 const DefinedAtom *makeTLVPEntry(const Atom *target) { 114 auto pos = _targetToTLVP.find(target); 115 116 if (pos != _targetToTLVP.end()) 117 return pos->second; 118 119 auto *tlvpEntry = new (_file.allocator()) 120 TLVPEntryAtom(_file, _ctx.is64Bit(), target->name()); 121 _targetToTLVP[target] = tlvpEntry; 122 const ArchHandler::ReferenceInfo &nlInfo = 123 _archHandler.stubInfo().nonLazyPointerReferenceToBinder; 124 tlvpEntry->addReference(Reference::KindNamespace::mach_o, nlInfo.arch, 125 nlInfo.kind, 0, target, 0); 126 return tlvpEntry; 127 } 128 129 const MachOLinkingContext &_ctx; 130 mach_o::ArchHandler &_archHandler; 131 MachOFile &_file; 132 llvm::DenseMap<const Atom*, const TLVPEntryAtom*> _targetToTLVP; 133 }; 134 135 void addTLVPass(PassManager &pm, const MachOLinkingContext &ctx) { 136 assert(ctx.needsTLVPass()); 137 pm.add(llvm::make_unique<TLVPass>(ctx)); 138 } 139 140 } // end namesapce mach_o 141 } // end namesapce lld 142