1 //===- lib/ReaderWriter/MachO/TLVPass.cpp -----------------------*- C++ -*-===//
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
11 /// This linker pass transforms all TLV references to real references.
13 //===----------------------------------------------------------------------===//
15 #include "ArchHandler.h"
17 #include "MachOPasses.h"
18 #include "lld/Core/Simple.h"
19 #include "llvm/ADT/STLExtras.h"
20 #include "llvm/Support/Debug.h"
26 // TLVP Entry Atom created by the TLV pass.
28 class TLVPEntryAtom : public SimpleDefinedAtom {
30 TLVPEntryAtom(const File &file, bool is64, StringRef name)
31 : SimpleDefinedAtom(file), _is64(is64), _name(name) {}
33 ~TLVPEntryAtom() override = default;
35 ContentType contentType() const override {
36 return DefinedAtom::typeTLVInitializerPtr;
39 Alignment alignment() const override {
43 uint64_t size() const override {
47 ContentPermissions permissions() const override {
48 return DefinedAtom::permRW_;
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());
57 StringRef slotName() const {
66 class TLVPass : public Pass {
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());
75 llvm::Error perform(SimpleFile &mergedFile) override {
76 bool allowTLV = _ctx.minOS("10.7", "1.0");
78 for (const DefinedAtom *atom : mergedFile.defined()) {
79 for (const Reference *ref : *atom) {
80 if (!_archHandler.isTLVAccess(*ref))
84 return llvm::make_error<GenericError>(
85 "targeted OS version does not support use of thread local "
86 "variables in " + atom->name() + " for architecture " +
89 const Atom *target = ref->target();
90 assert(target != nullptr);
92 const DefinedAtom *tlvpEntry = makeTLVPEntry(target);
93 const_cast<Reference*>(ref)->setTarget(tlvpEntry);
94 _archHandler.updateReferenceToTLV(ref);
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);
107 for (const TLVPEntryAtom *slot : entries)
108 mergedFile.addAtom(*slot);
110 return llvm::Error::success();
113 const DefinedAtom *makeTLVPEntry(const Atom *target) {
114 auto pos = _targetToTLVP.find(target);
116 if (pos != _targetToTLVP.end())
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);
129 const MachOLinkingContext &_ctx;
130 mach_o::ArchHandler &_archHandler;
132 llvm::DenseMap<const Atom*, const TLVPEntryAtom*> _targetToTLVP;
135 void addTLVPass(PassManager &pm, const MachOLinkingContext &ctx) {
136 assert(ctx.needsTLVPass());
137 pm.add(llvm::make_unique<TLVPass>(ctx));
140 } // end namesapce mach_o
141 } // end namesapce lld