blob: 9132748f206a1c1bf5fca162d4b15c2ff0ddbd8d [file] [log] [blame]
Rui Ueyama0ca149f2013-08-06 22:31:59 +00001//===- lib/ReaderWriter/CoreLinkingContext.cpp ----------------------------===//
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#include "lld/ReaderWriter/CoreLinkingContext.h"
11
12#include "lld/Core/Pass.h"
13#include "lld/Core/PassManager.h"
14#include "lld/Passes/LayoutPass.h"
Shankar Easwaran2bc24922013-10-29 05:12:14 +000015#include "lld/Passes/RoundTripNativePass.h"
16#include "lld/Passes/RoundTripYAMLPass.h"
17#include "lld/ReaderWriter/Simple.h"
Rui Ueyama0ca149f2013-08-06 22:31:59 +000018
19#include "llvm/ADT/ArrayRef.h"
20
21using namespace lld;
22
23namespace {
24
25/// \brief Simple atom created by the stubs pass.
26class TestingStubAtom : public DefinedAtom {
27public:
28 TestingStubAtom(const File &F, const Atom &) : _file(F) {
29 static uint32_t lastOrdinal = 0;
30 _ordinal = lastOrdinal++;
31 }
32
33 virtual const File &file() const { return _file; }
34
35 virtual StringRef name() const { return StringRef(); }
36
37 virtual uint64_t ordinal() const { return _ordinal; }
38
39 virtual uint64_t size() const { return 0; }
40
41 virtual Scope scope() const { return DefinedAtom::scopeLinkageUnit; }
42
43 virtual Interposable interposable() const { return DefinedAtom::interposeNo; }
44
45 virtual Merge merge() const { return DefinedAtom::mergeNo; }
46
47 virtual ContentType contentType() const { return DefinedAtom::typeStub; }
48
49 virtual Alignment alignment() const { return Alignment(0, 0); }
50
51 virtual SectionChoice sectionChoice() const {
52 return DefinedAtom::sectionBasedOnContent;
53 }
54
55 virtual StringRef customSectionName() const { return StringRef(); }
56
57 virtual SectionPosition sectionPosition() const { return sectionPositionAny; }
58
59 virtual DeadStripKind deadStrip() const {
60 return DefinedAtom::deadStripNormal;
61 }
62
63 virtual ContentPermissions permissions() const {
64 return DefinedAtom::permR_X;
65 }
66
67 virtual bool isAlias() const { return false; }
68
69 virtual ArrayRef<uint8_t> rawContent() const { return ArrayRef<uint8_t>(); }
70
71 virtual reference_iterator begin() const {
72 return reference_iterator(*this, nullptr);
73 }
74
75 virtual reference_iterator end() const {
76 return reference_iterator(*this, nullptr);
77 }
78
79 virtual const Reference *derefIterator(const void *iter) const {
80 return nullptr;
81 }
82
83 virtual void incrementIterator(const void *&iter) const {}
84
85private:
86 const File &_file;
87 uint32_t _ordinal;
88};
89
90/// \brief Simple atom created by the GOT pass.
91class TestingGOTAtom : public DefinedAtom {
92public:
93 TestingGOTAtom(const File &F, const Atom &) : _file(F) {
94 static uint32_t lastOrdinal = 0;
95 _ordinal = lastOrdinal++;
96 }
97
98 virtual const File &file() const { return _file; }
99
100 virtual StringRef name() const { return StringRef(); }
101
102 virtual uint64_t ordinal() const { return _ordinal; }
103
104 virtual uint64_t size() const { return 0; }
105
106 virtual Scope scope() const { return DefinedAtom::scopeLinkageUnit; }
107
108 virtual Interposable interposable() const { return DefinedAtom::interposeNo; }
109
110 virtual Merge merge() const { return DefinedAtom::mergeNo; }
111
112 virtual ContentType contentType() const { return DefinedAtom::typeGOT; }
113
114 virtual Alignment alignment() const { return Alignment(3, 0); }
115
116 virtual SectionChoice sectionChoice() const {
117 return DefinedAtom::sectionBasedOnContent;
118 }
119
120 virtual StringRef customSectionName() const { return StringRef(); }
121
122 virtual SectionPosition sectionPosition() const { return sectionPositionAny; }
123
124 virtual DeadStripKind deadStrip() const {
125 return DefinedAtom::deadStripNormal;
126 }
127
128 virtual ContentPermissions permissions() const {
129 return DefinedAtom::permRW_;
130 }
131
132 virtual bool isAlias() const { return false; }
133
134 virtual ArrayRef<uint8_t> rawContent() const { return ArrayRef<uint8_t>(); }
135
136 virtual reference_iterator begin() const {
137 return reference_iterator(*this, nullptr);
138 }
139
140 virtual reference_iterator end() const {
141 return reference_iterator(*this, nullptr);
142 }
143
144 virtual const Reference *derefIterator(const void *iter) const {
145 return nullptr;
146 }
147
148 virtual void incrementIterator(const void *&iter) const {}
149
150private:
151 const File &_file;
152 uint32_t _ordinal;
153};
154
Shankar Easwaran2bc24922013-10-29 05:12:14 +0000155class TestingPassFile : public SimpleFile {
Rui Ueyama0ca149f2013-08-06 22:31:59 +0000156public:
Rui Ueyama352e7302013-08-27 00:04:42 +0000157 TestingPassFile(const LinkingContext &ctx)
Shankar Easwaran2bc24922013-10-29 05:12:14 +0000158 : SimpleFile(ctx, "Testing pass") {}
Rui Ueyama0ca149f2013-08-06 22:31:59 +0000159
160 virtual void addAtom(const Atom &atom) {
161 if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(&atom))
162 _definedAtoms._atoms.push_back(defAtom);
163 else
164 llvm_unreachable("atom has unknown definition kind");
165 }
166
167 virtual DefinedAtomRange definedAtoms() {
168 return range<std::vector<const DefinedAtom *>::iterator>(
169 _definedAtoms._atoms.begin(), _definedAtoms._atoms.end());
170 }
171
172 virtual const atom_collection<DefinedAtom> &defined() const {
173 return _definedAtoms;
174 }
175 virtual const atom_collection<UndefinedAtom> &undefined() const {
176 return _undefinedAtoms;
177 }
178 virtual const atom_collection<SharedLibraryAtom> &sharedLibrary() const {
179 return _sharedLibraryAtoms;
180 }
181 virtual const atom_collection<AbsoluteAtom> &absolute() const {
182 return _absoluteAtoms;
183 }
184
185private:
186 atom_collection_vector<DefinedAtom> _definedAtoms;
187 atom_collection_vector<UndefinedAtom> _undefinedAtoms;
188 atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
189 atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
190};
191
192struct TestingKindMapping {
193 const char *string;
194 int32_t value;
195 bool isBranch;
196 bool isGotLoad;
197 bool isGotUse;
198};
199
200//
201// Table of fixup kinds in YAML documents used for testing
202//
203const TestingKindMapping sKinds[] = {
204 { "in-group", -3, false, false, false },
205 { "layout-after", -2, false, false, false },
206 { "layout-before", -1, false, false, false },
207 { "call32", 2, true, false, false }, { "pcrel32", 3, false, false, false },
208 { "gotLoad32", 7, false, true, true }, { "gotUse32", 9, false, false, true },
209 { "lea32wasGot", 8, false, false, false }, { nullptr, 0, false, false, false }
210};
211
212class TestingStubsPass : public StubsPass {
213public:
Rui Ueyama352e7302013-08-27 00:04:42 +0000214 TestingStubsPass(const LinkingContext &ctx) : _file(TestingPassFile(ctx)) {}
Rui Ueyama0ca149f2013-08-06 22:31:59 +0000215
216 virtual bool noTextRelocs() { return true; }
217
218 virtual bool isCallSite(int32_t kind) {
219 for (const TestingKindMapping *p = sKinds; p->string != nullptr; ++p) {
220 if (kind == p->value)
221 return p->isBranch;
222 }
223 return false;
224 }
225
226 virtual const DefinedAtom *getStub(const Atom &target) {
227 const DefinedAtom *result = new TestingStubAtom(_file, target);
228 _file.addAtom(*result);
229 return result;
230 }
231
232 virtual void addStubAtoms(MutableFile &mergedFile) {
233 for (const DefinedAtom *stub : _file.defined()) {
234 mergedFile.addAtom(*stub);
235 }
236 }
237
238private:
239 TestingPassFile _file;
240};
241
242class TestingGOTPass : public GOTPass {
243public:
Rui Ueyama352e7302013-08-27 00:04:42 +0000244 TestingGOTPass(const LinkingContext &ctx) : _file(TestingPassFile(ctx)) {}
Rui Ueyama0ca149f2013-08-06 22:31:59 +0000245
246 virtual bool noTextRelocs() { return true; }
247
248 virtual bool isGOTAccess(int32_t kind, bool &canBypassGOT) {
249 for (const TestingKindMapping *p = sKinds; p->string != nullptr; ++p) {
250 if (kind == p->value) {
251 canBypassGOT = p->isGotLoad;
252 return p->isGotUse || p->isGotLoad;
253 }
254 }
255 return false;
256 }
257
258 virtual void updateReferenceToGOT(const Reference *ref, bool targetIsNowGOT) {
259 if (targetIsNowGOT)
260 const_cast<Reference *>(ref)->setKind(3); // pcrel32
261 else
262 const_cast<Reference *>(ref)->setKind(8); // lea32wasGot
263 }
264
265 virtual const DefinedAtom *makeGOTEntry(const Atom &target) {
266 return new TestingGOTAtom(_file, target);
267 }
268
269private:
270 TestingPassFile _file;
271};
272
273} // anonymous namespace
274
275CoreLinkingContext::CoreLinkingContext() {}
276
Shankar Easwaran7f1146c2013-10-08 15:43:48 +0000277bool CoreLinkingContext::validateImpl(raw_ostream &) {
Shankar Easwarana96f3a32013-10-07 02:47:09 +0000278 _reader = createReaderYAML(*this);
Shankar Easwaran7f1146c2013-10-08 15:43:48 +0000279 _writer = createWriterYAML(*this);
Rui Ueyama8db1edd2013-09-24 23:26:34 +0000280 return true;
Rui Ueyama0ca149f2013-08-06 22:31:59 +0000281}
282
Shankar Easwaran2bc24922013-10-29 05:12:14 +0000283void CoreLinkingContext::addPasses(PassManager &pm) {
Rui Ueyama0ca149f2013-08-06 22:31:59 +0000284 for (StringRef name : _passNames) {
285 if (name.equals("layout"))
286 pm.add(std::unique_ptr<Pass>((new LayoutPass())));
287 else if (name.equals("GOT"))
288 pm.add(std::unique_ptr<Pass>(new TestingGOTPass(*this)));
289 else if (name.equals("stubs"))
290 pm.add(std::unique_ptr<Pass>(new TestingStubsPass(*this)));
291 else
292 llvm_unreachable("bad pass name");
293 }
294}
295
Shankar Easwaran7f1146c2013-10-08 15:43:48 +0000296Writer &CoreLinkingContext::writer() const { return *_writer; }
Rui Ueyama0ca149f2013-08-06 22:31:59 +0000297
298ErrorOr<Reference::Kind>
299CoreLinkingContext::relocKindFromString(StringRef str) const {
300 for (const TestingKindMapping *p = sKinds; p->string != nullptr; ++p) {
301 if (str.equals(p->string))
302 return p->value;
303 }
Rui Ueyamac6015f62013-10-09 00:57:22 +0000304 return make_error_code(YamlReaderError::illegal_value);
Rui Ueyama0ca149f2013-08-06 22:31:59 +0000305}
306
307ErrorOr<std::string>
308CoreLinkingContext::stringFromRelocKind(Reference::Kind kind) const {
309 for (const TestingKindMapping *p = sKinds; p->string != nullptr; ++p) {
310 if (kind == p->value)
311 return std::string(p->string);
312 }
Rui Ueyamac6015f62013-10-09 00:57:22 +0000313 return make_error_code(YamlReaderError::illegal_value);
Rui Ueyama0ca149f2013-08-06 22:31:59 +0000314}