Eugene Zelenko | 4154794 | 2015-11-10 22:37:38 +0000 | [diff] [blame] | 1 | //===- lib/ReaderWriter/MachO/TLVPass.cpp -----------------------*- C++ -*-===// |
Lang Hames | 4904703 | 2015-06-23 20:35:31 +0000 | [diff] [blame] | 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 | |
Pete Cooper | 8ad55fb | 2016-03-22 17:15:50 +0000 | [diff] [blame^] | 33 | ~TLVPEntryAtom() override = default; |
| 34 | |
Lang Hames | 4904703 | 2015-06-23 20:35:31 +0000 | [diff] [blame] | 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()), |
Pete Cooper | c0c464c | 2016-03-21 23:17:47 +0000 | [diff] [blame] | 70 | _file(*_ctx.make_file<MachOFile>("<mach-o TLV pass>")) { |
Pete Cooper | c7d4035 | 2016-02-02 01:52:40 +0000 | [diff] [blame] | 71 | _file.setOrdinal(_ctx.getNextOrdinalAndIncrement()); |
| 72 | } |
Lang Hames | 4904703 | 2015-06-23 20:35:31 +0000 | [diff] [blame] | 73 | |
| 74 | private: |
Lang Hames | 4904703 | 2015-06-23 20:35:31 +0000 | [diff] [blame] | 75 | std::error_code perform(SimpleFile &mergedFile) override { |
Lang Hames | 4904703 | 2015-06-23 20:35:31 +0000 | [diff] [blame] | 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 make_dynamic_error_code( |
| 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 std::error_code(); |
| 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 | |
Eugene Zelenko | 4154794 | 2015-11-10 22:37:38 +0000 | [diff] [blame] | 119 | auto *tlvpEntry = new (_file.allocator()) |
Lang Hames | 4904703 | 2015-06-23 20:35:31 +0000 | [diff] [blame] | 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; |
Pete Cooper | c0c464c | 2016-03-21 23:17:47 +0000 | [diff] [blame] | 131 | MachOFile &_file; |
Lang Hames | 4904703 | 2015-06-23 20:35:31 +0000 | [diff] [blame] | 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 | |
Lang Hames | 4904703 | 2015-06-23 20:35:31 +0000 | [diff] [blame] | 140 | } // end namesapce mach_o |
| 141 | } // end namesapce lld |