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