]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lld/lib/ReaderWriter/MachO/TLVPass.cpp
MFV r309587:
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lld / lib / ReaderWriter / MachO / TLVPass.cpp
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