blob: e0a031cfb07b296bc485afe145c12ca47e227317 [file] [log] [blame]
Eugene Zelenko41547942015-11-10 22:37:38 +00001//===- lib/ReaderWriter/MachO/TLVPass.cpp -----------------------*- C++ -*-===//
Lang Hames49047032015-06-23 20:35:31 +00002//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Lang Hames49047032015-06-23 20:35:31 +00006//
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
21namespace lld {
22namespace mach_o {
23
24//
25// TLVP Entry Atom created by the TLV pass.
26//
27class TLVPEntryAtom : public SimpleDefinedAtom {
28public:
29 TLVPEntryAtom(const File &file, bool is64, StringRef name)
30 : SimpleDefinedAtom(file), _is64(is64), _name(name) {}
31
Pete Cooper8ad55fb2016-03-22 17:15:50 +000032 ~TLVPEntryAtom() override = default;
33
Lang Hames49047032015-06-23 20:35:31 +000034 ContentType contentType() const override {
35 return DefinedAtom::typeTLVInitializerPtr;
36 }
37
38 Alignment alignment() const override {
39 return _is64 ? 8 : 4;
40 }
41
42 uint64_t size() const override {
43 return _is64 ? 8 : 4;
44 }
45
46 ContentPermissions permissions() const override {
47 return DefinedAtom::permRW_;
48 }
49
50 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
56 StringRef slotName() const {
57 return _name;
58 }
59
60private:
61 const bool _is64;
62 StringRef _name;
63};
64
65class TLVPass : public Pass {
66public:
67 TLVPass(const MachOLinkingContext &context)
68 : _ctx(context), _archHandler(_ctx.archHandler()),
Pete Cooperc0c464c2016-03-21 23:17:47 +000069 _file(*_ctx.make_file<MachOFile>("<mach-o TLV pass>")) {
Pete Cooperc7d40352016-02-02 01:52:40 +000070 _file.setOrdinal(_ctx.getNextOrdinalAndIncrement());
71 }
Lang Hames49047032015-06-23 20:35:31 +000072
73private:
Pete Cooperc73c9d22016-03-30 20:36:31 +000074 llvm::Error perform(SimpleFile &mergedFile) override {
Lang Hames49047032015-06-23 20:35:31 +000075 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)
Pete Cooperc73c9d22016-03-30 20:36:31 +000083 return llvm::make_error<GenericError>(
Lang Hames49047032015-06-23 20:35:31 +000084 "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
Mehdi Aminic1edf562016-11-11 04:29:25 +0000109 return llvm::Error::success();
Lang Hames49047032015-06-23 20:35:31 +0000110 }
111
112 const DefinedAtom *makeTLVPEntry(const Atom *target) {
113 auto pos = _targetToTLVP.find(target);
114
115 if (pos != _targetToTLVP.end())
116 return pos->second;
117
Eugene Zelenko41547942015-11-10 22:37:38 +0000118 auto *tlvpEntry = new (_file.allocator())
Lang Hames49047032015-06-23 20:35:31 +0000119 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;
Pete Cooperc0c464c2016-03-21 23:17:47 +0000130 MachOFile &_file;
Lang Hames49047032015-06-23 20:35:31 +0000131 llvm::DenseMap<const Atom*, const TLVPEntryAtom*> _targetToTLVP;
132};
133
134void addTLVPass(PassManager &pm, const MachOLinkingContext &ctx) {
135 assert(ctx.needsTLVPass());
Jonas Devlieghere6ba79922019-08-14 22:28:17 +0000136 pm.add(std::make_unique<TLVPass>(ctx));
Lang Hames49047032015-06-23 20:35:31 +0000137}
138
Kazuaki Ishizaki7c5fcb32020-04-02 01:21:08 +0900139} // end namespace mach_o
140} // end namespace lld