]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp
Vendor import of lld trunk r233088:
[FreeBSD/FreeBSD.git] / lib / ReaderWriter / ELF / Mips / MipsRelocationPass.cpp
1 //===- lib/ReaderWriter/ELF/Mips/MipsRelocationPass.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 "MipsELFFile.h"
11 #include "MipsLinkingContext.h"
12 #include "MipsRelocationPass.h"
13 #include "MipsTargetHandler.h"
14 #include "llvm/ADT/DenseSet.h"
15
16 using namespace lld;
17 using namespace lld::elf;
18 using namespace llvm::ELF;
19
20 // Lazy resolver
21 static const uint8_t mipsGot0AtomContent[] = {
22   0x00, 0x00, 0x00, 0x00,
23   0x00, 0x00, 0x00, 0x00
24 };
25
26 // Module pointer
27 static const uint8_t mipsGotModulePointerAtomContent[] = {
28   0x00, 0x00, 0x00, 0x00,
29   0x00, 0x00, 0x00, 0x80
30 };
31
32 // TLS GD Entry
33 static const uint8_t mipsGotTlsGdAtomContent[] = {
34   0x00, 0x00, 0x00, 0x00,
35   0x00, 0x00, 0x00, 0x00,
36   0x00, 0x00, 0x00, 0x00,
37   0x00, 0x00, 0x00, 0x00
38 };
39
40 // Regular PLT0 entry
41 static const uint8_t mipsPlt0AtomContent[] = {
42   0x00, 0x00, 0x1c, 0x3c, // lui   $28, %hi(&GOTPLT[0])
43   0x00, 0x00, 0x99, 0x8f, // lw    $25, %lo(&GOTPLT[0])($28)
44   0x00, 0x00, 0x9c, 0x27, // addiu $28, $28, %lo(&GOTPLT[0])
45   0x23, 0xc0, 0x1c, 0x03, // subu  $24, $24, $28
46   0x21, 0x78, 0xe0, 0x03, // move  $15, $31
47   0x82, 0xc0, 0x18, 0x00, // srl   $24, $24, 2
48   0x09, 0xf8, 0x20, 0x03, // jalr  $25
49   0xfe, 0xff, 0x18, 0x27  // subu  $24, $24, 2
50 };
51
52 // microMIPS PLT0 entry
53 static const uint8_t micromipsPlt0AtomContent[] = {
54   0x80, 0x79, 0x00, 0x00, // addiupc $3,  (&GOTPLT[0]) - .
55   0x23, 0xff, 0x00, 0x00, // lw      $25, 0($3)
56   0x35, 0x05,             // subu    $2,  $2, $3
57   0x25, 0x25,             // srl     $2,  $2, 2
58   0x02, 0x33, 0xfe, 0xff, // subu    $24, $2, 2
59   0xff, 0x0d,             // move    $15, $31
60   0xf9, 0x45,             // jalrs   $25
61   0x83, 0x0f,             // move    $28, $3
62   0x00, 0x0c              // nop
63 };
64
65 // Regular PLT entry
66 static const uint8_t mipsPltAAtomContent[] = {
67   0x00, 0x00, 0x0f, 0x3c, // lui   $15, %hi(.got.plt entry)
68   0x00, 0x00, 0xf9, 0x8d, // l[wd] $25, %lo(.got.plt entry)($15)
69   0x08, 0x00, 0x20, 0x03, // jr    $25
70   0x00, 0x00, 0xf8, 0x25  // addiu $24, $15, %lo(.got.plt entry)
71 };
72
73 // microMIPS PLT entry
74 static const uint8_t micromipsPltAtomContent[] = {
75   0x00, 0x79, 0x00, 0x00, // addiupc $2, (.got.plt entry) - .
76   0x22, 0xff, 0x00, 0x00, // lw $25, 0($2)
77   0x99, 0x45,             // jr $25
78   0x02, 0x0f              // move $24, $2
79 };
80
81 // R6 PLT entry
82 static const uint8_t mipsR6PltAAtomContent[] = {
83   0x00, 0x00, 0x0f, 0x3c, // lui   $15, %hi(.got.plt entry)
84   0x00, 0x00, 0xf9, 0x8d, // l[wd] $25, %lo(.got.plt entry)($15)
85   0x09, 0x00, 0x20, 0x03, // jr    $25
86   0x00, 0x00, 0xf8, 0x25  // addiu $24, $15, %lo(.got.plt entry)
87 };
88
89 // LA25 stub entry
90 static const uint8_t mipsLA25AtomContent[] = {
91   0x00, 0x00, 0x19, 0x3c, // lui   $25, %hi(func)
92   0x00, 0x00, 0x00, 0x08, // j     func
93   0x00, 0x00, 0x39, 0x27, // addiu $25, $25, %lo(func)
94   0x00, 0x00, 0x00, 0x00  // nop
95 };
96
97 // microMIPS LA25 stub entry
98 static const uint8_t micromipsLA25AtomContent[] = {
99   0xb9, 0x41, 0x00, 0x00, // lui   $25, %hi(func)
100   0x00, 0xd4, 0x00, 0x00, // j     func
101   0x39, 0x33, 0x00, 0x00, // addiu $25, $25, %lo(func)
102   0x00, 0x00, 0x00, 0x00  // nop
103 };
104
105 namespace {
106
107 /// \brief Abstract base class represent MIPS GOT entries.
108 class MipsGOTAtom : public GOTAtom {
109 public:
110   MipsGOTAtom(const File &f) : GOTAtom(f, ".got") {}
111
112   Alignment alignment() const override { return Alignment(2); }
113 };
114
115 /// \brief MIPS GOT entry initialized by zero.
116 template <typename ELFT> class GOT0Atom : public MipsGOTAtom {
117 public:
118   GOT0Atom(const File &f) : MipsGOTAtom(f) {}
119
120   ArrayRef<uint8_t> rawContent() const override;
121 };
122
123 template <> ArrayRef<uint8_t> GOT0Atom<Mips32ELType>::rawContent() const {
124   return llvm::makeArrayRef(mipsGot0AtomContent).slice(4);
125 }
126 template <> ArrayRef<uint8_t> GOT0Atom<Mips64ELType>::rawContent() const {
127   return llvm::makeArrayRef(mipsGot0AtomContent);
128 }
129
130 /// \brief MIPS GOT entry initialized by zero.
131 template <typename ELFT> class GOTModulePointerAtom : public MipsGOTAtom {
132 public:
133   GOTModulePointerAtom(const File &f) : MipsGOTAtom(f) {}
134
135   ArrayRef<uint8_t> rawContent() const override;
136 };
137
138 template <>
139 ArrayRef<uint8_t> GOTModulePointerAtom<Mips32ELType>::rawContent() const {
140   return llvm::makeArrayRef(mipsGotModulePointerAtomContent).slice(4);
141 }
142 template <>
143 ArrayRef<uint8_t> GOTModulePointerAtom<Mips64ELType>::rawContent() const {
144   return llvm::makeArrayRef(mipsGotModulePointerAtomContent);
145 }
146
147 /// \brief MIPS GOT TLS GD entry.
148 template <typename ELFT> class GOTTLSGdAtom : public MipsGOTAtom {
149 public:
150   GOTTLSGdAtom(const File &f) : MipsGOTAtom(f) {}
151
152   ArrayRef<uint8_t> rawContent() const override;
153 };
154
155 template <> ArrayRef<uint8_t> GOTTLSGdAtom<Mips32ELType>::rawContent() const {
156     return llvm::makeArrayRef(mipsGotTlsGdAtomContent).slice(8);
157 }
158
159 template <> ArrayRef<uint8_t> GOTTLSGdAtom<Mips64ELType>::rawContent() const {
160     return llvm::makeArrayRef(mipsGotTlsGdAtomContent);
161 }
162
163 class GOTPLTAtom : public GOTAtom {
164 public:
165   GOTPLTAtom(const File &f) : GOTAtom(f, ".got.plt") {}
166   GOTPLTAtom(const Atom *a, const File &f) : GOTAtom(f, ".got.plt") {
167     // Create dynamic relocation to adjust the .got.plt entry at runtime.
168     addReferenceELF_Mips(R_MIPS_JUMP_SLOT, 0, a, 0);
169   }
170
171   /// Setup reference to assign initial value to the .got.plt entry.
172   void setPLT0(const PLTAtom *plt0) {
173     addReferenceELF_Mips(R_MIPS_32, 0, plt0, 0);
174   }
175
176   Alignment alignment() const override { return Alignment(2); }
177
178   ArrayRef<uint8_t> rawContent() const override {
179     return llvm::makeArrayRef(mipsGot0AtomContent).slice(4);
180   }
181 };
182
183 class PLT0Atom : public PLTAtom {
184 public:
185   PLT0Atom(const Atom *got, const File &f) : PLTAtom(f, ".plt") {
186     // Setup reference to fixup the PLT0 entry.
187     addReferenceELF_Mips(LLD_R_MIPS_HI16, 0, got, 0);
188     addReferenceELF_Mips(LLD_R_MIPS_LO16, 4, got, 0);
189     addReferenceELF_Mips(LLD_R_MIPS_LO16, 8, got, 0);
190   }
191
192   ArrayRef<uint8_t> rawContent() const override {
193     return llvm::makeArrayRef(mipsPlt0AtomContent);
194   }
195 };
196
197 class PLT0MicroAtom : public PLTAtom {
198 public:
199   PLT0MicroAtom(const Atom *got, const File &f) : PLTAtom(f, ".plt") {
200     // Setup reference to fixup the PLT0 entry.
201     addReferenceELF_Mips(R_MICROMIPS_PC23_S2, 0, got, 0);
202   }
203
204   CodeModel codeModel() const override { return codeMipsMicro; }
205
206   ArrayRef<uint8_t> rawContent() const override {
207     return llvm::makeArrayRef(micromipsPlt0AtomContent);
208   }
209 };
210
211 class PLTAAtom : public PLTAtom {
212 public:
213   PLTAAtom(const GOTPLTAtom *got, const File &f) : PLTAtom(f, ".plt") {
214     // Setup reference to fixup the PLT entry.
215     addReferenceELF_Mips(LLD_R_MIPS_HI16, 0, got, 0);
216     addReferenceELF_Mips(LLD_R_MIPS_LO16, 4, got, 0);
217     addReferenceELF_Mips(LLD_R_MIPS_LO16, 12, got, 0);
218   }
219
220   ArrayRef<uint8_t> rawContent() const override {
221     return llvm::makeArrayRef(mipsPltAAtomContent);
222   }
223 };
224
225 class PLTR6Atom : public PLTAAtom {
226 public:
227   PLTR6Atom(const GOTPLTAtom *got, const File &f) : PLTAAtom(got, f) {}
228
229   ArrayRef<uint8_t> rawContent() const override {
230     return llvm::makeArrayRef(mipsR6PltAAtomContent);
231   }
232 };
233
234 class PLTMicroAtom : public PLTAtom {
235 public:
236   PLTMicroAtom(const GOTPLTAtom *got, const File &f) : PLTAtom(f, ".plt") {
237     // Setup reference to fixup the microMIPS PLT entry.
238     addReferenceELF_Mips(R_MICROMIPS_PC23_S2, 0, got, 0);
239   }
240
241   Alignment alignment() const override { return Alignment(1); }
242   CodeModel codeModel() const override { return codeMipsMicro; }
243
244   ArrayRef<uint8_t> rawContent() const override {
245     return llvm::makeArrayRef(micromipsPltAtomContent);
246   }
247 };
248
249 class LA25Atom : public PLTAtom {
250 public:
251   LA25Atom(const File &f) : PLTAtom(f, ".text") {}
252 };
253
254 class LA25RegAtom : public LA25Atom {
255 public:
256   LA25RegAtom(const Atom *a, const File &f) : LA25Atom(f) {
257     // Setup reference to fixup the LA25 stub entry.
258     addReferenceELF_Mips(R_MIPS_HI16, 0, a, 0);
259     addReferenceELF_Mips(R_MIPS_26, 4, a, 0);
260     addReferenceELF_Mips(R_MIPS_LO16, 8, a, 0);
261   }
262
263   ArrayRef<uint8_t> rawContent() const override {
264     return llvm::makeArrayRef(mipsLA25AtomContent);
265   }
266 };
267
268 class LA25MicroAtom : public LA25Atom {
269 public:
270   LA25MicroAtom(const Atom *a, const File &f) : LA25Atom(f) {
271     // Setup reference to fixup the microMIPS LA25 stub entry.
272     addReferenceELF_Mips(R_MICROMIPS_HI16, 0, a, 0);
273     addReferenceELF_Mips(R_MICROMIPS_26_S1, 4, a, 0);
274     addReferenceELF_Mips(R_MICROMIPS_LO16, 8, a, 0);
275   }
276
277   CodeModel codeModel() const override { return codeMipsMicro; }
278
279   ArrayRef<uint8_t> rawContent() const override {
280     return llvm::makeArrayRef(micromipsLA25AtomContent);
281   }
282 };
283
284 class RelocationPassFile : public SimpleFile {
285 public:
286   RelocationPassFile(const ELFLinkingContext &ctx)
287       : SimpleFile("RelocationPassFile") {
288     setOrdinal(ctx.getNextOrdinalAndIncrement());
289   }
290
291   llvm::BumpPtrAllocator _alloc;
292 };
293
294 template <typename ELFT> class RelocationPass : public Pass {
295 public:
296   RelocationPass(MipsLinkingContext &ctx);
297
298   void perform(std::unique_ptr<MutableFile> &mf) override;
299
300 private:
301   /// \brief Reference to the linking context.
302   const MipsLinkingContext &_ctx;
303
304   /// \brief Owner of all the Atoms created by this pass.
305   RelocationPassFile _file;
306
307   /// \brief Map Atoms and addend to local GOT entries.
308   typedef std::pair<const Atom *, int64_t> LocalGotMapKeyT;
309   llvm::DenseMap<LocalGotMapKeyT, GOTAtom *> _gotLocalMap;
310   llvm::DenseMap<LocalGotMapKeyT, GOTAtom *> _gotLocalPageMap;
311
312   /// \brief Map Atoms to global GOT entries.
313   llvm::DenseMap<const Atom *, GOTAtom *> _gotGlobalMap;
314
315   /// \brief Map Atoms to TLS GOT entries.
316   llvm::DenseMap<const Atom *, GOTAtom *> _gotTLSMap;
317
318   /// \brief Map Atoms to TLS GD GOT entries.
319   llvm::DenseMap<const Atom *, GOTAtom *> _gotTLSGdMap;
320
321   /// \brief GOT entry for the R_xxxMIPS_TLS_LDM relocations.
322   GOTTLSGdAtom<ELFT> *_gotLDMEntry;
323
324   /// \brief the list of local GOT atoms.
325   std::vector<GOTAtom *> _localGotVector;
326
327   /// \brief the list of global GOT atoms.
328   std::vector<GOTAtom *> _globalGotVector;
329
330   /// \brief the list of TLS GOT atoms.
331   std::vector<GOTAtom *> _tlsGotVector;
332
333   /// \brief Map Atoms to their GOTPLT entries.
334   llvm::DenseMap<const Atom *, GOTPLTAtom *> _gotpltMap;
335
336   /// \brief Map Atoms to their PLT entries.
337   llvm::DenseMap<const Atom *, PLTAAtom *> _pltRegMap;
338   llvm::DenseMap<const Atom *, PLTMicroAtom *> _pltMicroMap;
339
340   /// \brief Map Atoms to their Object entries.
341   llvm::DenseMap<const Atom *, ObjectAtom *> _objectMap;
342
343   /// \brief Map Atoms to their LA25 entries.
344   llvm::DenseMap<const Atom *, LA25RegAtom *> _la25RegMap;
345   llvm::DenseMap<const Atom *, LA25MicroAtom *> _la25MicroMap;
346
347   /// \brief Atoms referenced by static relocations.
348   llvm::DenseSet<const Atom *> _hasStaticRelocations;
349
350   /// \brief Atoms require pointers equality.
351   llvm::DenseSet<const Atom *> _requiresPtrEquality;
352
353   /// \brief References which are candidates for converting
354   /// to the R_MIPS_REL32 relocation.
355   std::vector<Reference *> _rel32Candidates;
356
357   /// \brief the list of PLT atoms.
358   std::vector<PLTAtom *> _pltRegVector;
359   std::vector<PLTAtom *> _pltMicroVector;
360
361   /// \brief the list of GOTPLT atoms.
362   std::vector<GOTPLTAtom *> _gotpltVector;
363
364   /// \brief the list of Object entries.
365   std::vector<ObjectAtom *> _objectVector;
366
367   /// \brief the list of LA25 entries.
368   std::vector<LA25Atom *> _la25Vector;
369
370   /// \brief Handle a specific reference.
371   void handleReference(const MipsELFDefinedAtom<ELFT> &atom, Reference &ref);
372
373   /// \brief Collect information about the reference to use it
374   /// later in the handleReference() routine.
375   void collectReferenceInfo(const MipsELFDefinedAtom<ELFT> &atom,
376                             Reference &ref);
377
378   void handlePlain(const MipsELFDefinedAtom<ELFT> &atom, Reference &ref);
379   void handle26(const MipsELFDefinedAtom<ELFT> &atom, Reference &ref);
380   void handleGOT(Reference &ref);
381
382   const GOTAtom *getLocalGOTEntry(const Reference &ref);
383   const GOTAtom *getLocalGOTPageEntry(const Reference &ref);
384   const GOTAtom *getGlobalGOTEntry(const Atom *a);
385   const GOTAtom *getTLSGOTEntry(const Atom *a);
386   const GOTAtom *getTLSGdGOTEntry(const Atom *a);
387   const GOTAtom *getTLSLdmGOTEntry(const Atom *a);
388   const GOTPLTAtom *getGOTPLTEntry(const Atom *a);
389   const PLTAtom *getPLTEntry(const Atom *a);
390   const PLTAtom *getPLTRegEntry(const Atom *a);
391   const PLTAtom *getPLTMicroEntry(const Atom *a);
392   const LA25Atom *getLA25Entry(const Atom *target, bool isMicroMips);
393   const LA25Atom *getLA25RegEntry(const Atom *a);
394   const LA25Atom *getLA25MicroEntry(const Atom *a);
395   const ObjectAtom *getObjectEntry(const SharedLibraryAtom *a);
396
397   PLTAtom *createPLTHeader(bool isMicroMips);
398
399   bool isLocal(const Atom *a) const;
400   bool isLocalCall(const Atom *a) const;
401   bool isDynamic(const Atom *atom) const;
402   bool requireLA25Stub(const Atom *a) const;
403   bool requirePLTEntry(const Atom *a) const;
404   bool requireCopy(const Atom *a) const;
405   bool mightBeDynamic(const MipsELFDefinedAtom<ELFT> &atom,
406                       Reference::KindValue refKind) const;
407   bool hasPLTEntry(const Atom *atom) const;
408
409   bool isR6Target() const;
410 };
411
412 template <typename ELFT>
413 RelocationPass<ELFT>::RelocationPass(MipsLinkingContext &ctx)
414     : _ctx(ctx), _file(ctx), _gotLDMEntry(nullptr) {
415   _localGotVector.push_back(new (_file._alloc) GOT0Atom<ELFT>(_file));
416   _localGotVector.push_back(new (_file._alloc)
417                                 GOTModulePointerAtom<ELFT>(_file));
418 }
419
420 template <typename ELFT>
421 void RelocationPass<ELFT>::perform(std::unique_ptr<MutableFile> &mf) {
422   for (const auto &atom : mf->defined())
423     for (const auto &ref : *atom)
424       collectReferenceInfo(*cast<MipsELFDefinedAtom<ELFT>>(atom),
425                            const_cast<Reference &>(*ref));
426
427   // Process all references.
428   for (const auto &atom : mf->defined())
429     for (const auto &ref : *atom)
430       handleReference(*cast<MipsELFDefinedAtom<ELFT>>(atom),
431                       const_cast<Reference &>(*ref));
432
433   // Create R_MIPS_REL32 relocations.
434   for (auto *ref : _rel32Candidates) {
435     if (!isDynamic(ref->target()) || hasPLTEntry(ref->target()))
436       continue;
437     ref->setKindValue(R_MIPS_REL32);
438     if (ELFT::Is64Bits)
439       static_cast<MipsELFReference<ELFT> *>(ref)->setTag(R_MIPS_64);
440     if (!isLocalCall(ref->target()))
441       getGlobalGOTEntry(ref->target());
442   }
443
444   uint64_t ordinal = 0;
445
446   for (auto &got : _localGotVector) {
447     got->setOrdinal(ordinal++);
448     mf->addAtom(*got);
449   }
450
451   for (auto &got : _globalGotVector) {
452     got->setOrdinal(ordinal++);
453     mf->addAtom(*got);
454   }
455
456   for (auto &got : _tlsGotVector) {
457     got->setOrdinal(ordinal++);
458     mf->addAtom(*got);
459   }
460
461   // Create and emit PLT0 entry.
462   PLTAtom *plt0Atom = nullptr;
463   if (!_pltRegVector.empty())
464     plt0Atom = createPLTHeader(false);
465   else if (!_pltMicroVector.empty())
466     plt0Atom = createPLTHeader(true);
467
468   if (plt0Atom) {
469     plt0Atom->setOrdinal(ordinal++);
470     mf->addAtom(*plt0Atom);
471   }
472
473   // Emit regular PLT entries firts.
474   for (auto &plt : _pltRegVector) {
475     plt->setOrdinal(ordinal++);
476     mf->addAtom(*plt);
477   }
478
479   // microMIPS PLT entries come after regular ones.
480   for (auto &plt : _pltMicroVector) {
481     plt->setOrdinal(ordinal++);
482     mf->addAtom(*plt);
483   }
484
485   // Assign PLT0 to GOTPLT entries.
486   assert(_gotpltMap.empty() || plt0Atom);
487   for (auto &a: _gotpltMap)
488     a.second->setPLT0(plt0Atom);
489
490   for (auto &gotplt : _gotpltVector) {
491     gotplt->setOrdinal(ordinal++);
492     mf->addAtom(*gotplt);
493   }
494
495   for (auto obj : _objectVector) {
496     obj->setOrdinal(ordinal++);
497     mf->addAtom(*obj);
498   }
499
500   for (auto la25 : _la25Vector) {
501     la25->setOrdinal(ordinal++);
502     mf->addAtom(*la25);
503   }
504 }
505
506 template <typename ELFT>
507 void RelocationPass<ELFT>::handleReference(const MipsELFDefinedAtom<ELFT> &atom,
508                                            Reference &ref) {
509   if (!ref.target())
510     return;
511   if (ref.kindNamespace() != lld::Reference::KindNamespace::ELF)
512     return;
513   assert(ref.kindArch() == Reference::KindArch::Mips);
514   switch (ref.kindValue()) {
515   case R_MIPS_32:
516   case R_MIPS_PC32:
517   case R_MIPS_HI16:
518   case R_MIPS_LO16:
519   case R_MIPS_PCHI16:
520   case R_MIPS_PCLO16:
521   case R_MICROMIPS_HI16:
522   case R_MICROMIPS_LO16:
523     // FIXME (simon): Handle dynamic/static linking differently.
524     handlePlain(atom, ref);
525     break;
526   case R_MIPS_26:
527   case R_MICROMIPS_26_S1:
528     handle26(atom, ref);
529     break;
530   case R_MIPS_GOT16:
531   case R_MIPS_CALL16:
532   case R_MICROMIPS_GOT16:
533   case R_MICROMIPS_CALL16:
534   case R_MIPS_GOT_DISP:
535   case R_MIPS_GOT_PAGE:
536     handleGOT(ref);
537     break;
538   case R_MIPS_GOT_OFST:
539     // Nothing to do. We create GOT page entry in the R_MIPS_GOT_PAGE handler.
540     break;
541   case R_MIPS_GPREL16:
542     if (isLocal(ref.target()))
543       ref.setAddend(ref.addend() + atom.file().getGP0());
544     break;
545   case R_MIPS_GPREL32:
546     ref.setAddend(ref.addend() + atom.file().getGP0());
547     break;
548   case R_MIPS_TLS_DTPREL_HI16:
549   case R_MIPS_TLS_DTPREL_LO16:
550   case R_MICROMIPS_TLS_DTPREL_HI16:
551   case R_MICROMIPS_TLS_DTPREL_LO16:
552     ref.setAddend(ref.addend() - atom.file().getDTPOffset());
553     break;
554   case R_MIPS_TLS_TPREL_HI16:
555   case R_MIPS_TLS_TPREL_LO16:
556   case R_MICROMIPS_TLS_TPREL_HI16:
557   case R_MICROMIPS_TLS_TPREL_LO16:
558     ref.setAddend(ref.addend() - atom.file().getTPOffset());
559     break;
560   case R_MIPS_TLS_GD:
561   case R_MICROMIPS_TLS_GD:
562     ref.setTarget(getTLSGdGOTEntry(ref.target()));
563     break;
564   case R_MIPS_TLS_LDM:
565   case R_MICROMIPS_TLS_LDM:
566     ref.setTarget(getTLSLdmGOTEntry(ref.target()));
567     break;
568   case R_MIPS_TLS_GOTTPREL:
569   case R_MICROMIPS_TLS_GOTTPREL:
570     ref.setTarget(getTLSGOTEntry(ref.target()));
571     break;
572   }
573 }
574
575 template <typename ELFT>
576 static bool isConstrainSym(const MipsELFDefinedAtom<ELFT> &atom,
577                            Reference::KindValue refKind) {
578   if ((atom.section()->sh_flags & SHF_ALLOC) == 0)
579     return false;
580   switch (refKind) {
581   case R_MIPS_NONE:
582   case R_MIPS_JALR:
583   case R_MICROMIPS_JALR:
584   case R_MIPS_GPREL16:
585   case R_MIPS_GPREL32:
586     return false;
587   default:
588     return true;
589   }
590 }
591
592 template <typename ELFT>
593 void RelocationPass<ELFT>::collectReferenceInfo(
594     const MipsELFDefinedAtom<ELFT> &atom, Reference &ref) {
595   if (!ref.target())
596     return;
597   if (ref.kindNamespace() != lld::Reference::KindNamespace::ELF)
598     return;
599
600   auto refKind = ref.kindValue();
601   if (!isConstrainSym(atom, refKind))
602     return;
603
604   if (mightBeDynamic(atom, refKind))
605     _rel32Candidates.push_back(&ref);
606   else
607     _hasStaticRelocations.insert(ref.target());
608
609   if (refKind != R_MIPS_CALL16 && refKind != R_MICROMIPS_CALL16 &&
610       refKind != R_MIPS_26 && refKind != R_MICROMIPS_26_S1)
611     _requiresPtrEquality.insert(ref.target());
612 }
613
614 template <typename ELFT>
615 bool RelocationPass<ELFT>::isLocal(const Atom *a) const {
616   if (auto *da = dyn_cast<DefinedAtom>(a))
617     return da->scope() == Atom::scopeTranslationUnit;
618   return false;
619 }
620
621 template <typename ELFT>
622 static bool isMipsReadonly(const MipsELFDefinedAtom<ELFT> &atom) {
623   auto secFlags = atom.section()->sh_flags;
624   auto secType = atom.section()->sh_type;
625
626   if ((secFlags & SHF_ALLOC) == 0)
627     return false;
628   if (secType == SHT_NOBITS)
629     return false;
630   if ((secFlags & SHF_WRITE) != 0)
631     return false;
632   return true;
633 }
634
635 template <typename ELFT>
636 bool RelocationPass<ELFT>::mightBeDynamic(const MipsELFDefinedAtom<ELFT> &atom,
637                                           Reference::KindValue refKind) const {
638   if (refKind == R_MIPS_CALL16 || refKind == R_MIPS_GOT16 ||
639       refKind == R_MICROMIPS_CALL16 || refKind == R_MICROMIPS_GOT16)
640     return true;
641
642   if (refKind != R_MIPS_32 && refKind != R_MIPS_64)
643     return false;
644   if ((atom.section()->sh_flags & SHF_ALLOC) == 0)
645     return false;
646
647   if (_ctx.getOutputELFType() == ET_DYN)
648     return true;
649   if (!isMipsReadonly(atom))
650     return true;
651   if (atom.file().isPIC())
652     return true;
653
654   return false;
655 }
656
657 template <typename ELFT>
658 bool RelocationPass<ELFT>::hasPLTEntry(const Atom *atom) const {
659   return _pltRegMap.count(atom) || _pltMicroMap.count(atom);
660 }
661
662 template <typename ELFT> bool RelocationPass<ELFT>::isR6Target() const {
663   switch (_ctx.getMergedELFFlags() & EF_MIPS_ARCH) {
664   case EF_MIPS_ARCH_32R6:
665   case EF_MIPS_ARCH_64R6:
666     return true;
667   default:
668     return false;
669   }
670 }
671
672 template <typename ELFT>
673 bool RelocationPass<ELFT>::requirePLTEntry(const Atom *a) const {
674   if (!_hasStaticRelocations.count(a))
675     return false;
676   const auto *sa = dyn_cast<ELFDynamicAtom<ELFT>>(a);
677   if (sa && sa->type() != SharedLibraryAtom::Type::Code)
678     return false;
679   const auto *da = dyn_cast<ELFDefinedAtom<ELFT>>(a);
680   if (da && da->contentType() != DefinedAtom::typeCode)
681     return false;
682   if (isLocalCall(a))
683     return false;
684   return true;
685 }
686
687 template <typename ELFT>
688 bool RelocationPass<ELFT>::requireCopy(const Atom *a) const {
689   if (!_hasStaticRelocations.count(a))
690     return false;
691   const auto *sa = dyn_cast<ELFDynamicAtom<ELFT>>(a);
692   return sa && sa->type() == SharedLibraryAtom::Type::Data;
693 }
694
695 template <typename ELFT>
696 bool RelocationPass<ELFT>::isDynamic(const Atom *atom) const {
697   const auto *da = dyn_cast<const DefinedAtom>(atom);
698   if (da && da->dynamicExport() == DefinedAtom::dynamicExportAlways)
699     return true;
700
701   const auto *sa = dyn_cast<SharedLibraryAtom>(atom);
702   if (sa)
703     return true;
704
705   if (_ctx.getOutputELFType() == ET_DYN) {
706     if (da && da->scope() != DefinedAtom::scopeTranslationUnit)
707       return true;
708
709     const auto *ua = dyn_cast<UndefinedAtom>(atom);
710     if (ua)
711       return true;
712   }
713
714   return false;
715 }
716
717 template <typename ELFT>
718 static bool isMicroMips(const MipsELFDefinedAtom<ELFT> &atom) {
719   return atom.codeModel() == DefinedAtom::codeMipsMicro ||
720          atom.codeModel() == DefinedAtom::codeMipsMicroPIC;
721 }
722
723 template <typename ELFT>
724 const LA25Atom *RelocationPass<ELFT>::getLA25Entry(const Atom *target,
725                                                    bool isMicroMips) {
726   return isMicroMips ? getLA25MicroEntry(target) : getLA25RegEntry(target);
727 }
728
729 template <typename ELFT>
730 const PLTAtom *RelocationPass<ELFT>::getPLTEntry(const Atom *a) {
731   bool hasMicroCode = _ctx.getMergedELFFlags() & EF_MIPS_MICROMIPS;
732
733   // If file contains microMIPS code try to reuse compressed PLT entry...
734   if (hasMicroCode) {
735     auto microPLT = _pltMicroMap.find(a);
736     if (microPLT != _pltMicroMap.end())
737       return microPLT->second;
738   }
739
740   // ... then try to reuse a regular PLT entry ...
741   auto regPLT = _pltRegMap.find(a);
742   if (regPLT != _pltRegMap.end())
743     return regPLT->second;
744
745   // ... and finally prefer to create new compressed PLT entry.
746   return hasMicroCode ? getPLTMicroEntry(a) : getPLTRegEntry(a);
747 }
748
749 template <typename ELFT>
750 void RelocationPass<ELFT>::handlePlain(const MipsELFDefinedAtom<ELFT> &atom,
751                                        Reference &ref) {
752   if (!isDynamic(ref.target()))
753       return;
754
755   if (requirePLTEntry(ref.target()))
756     ref.setTarget(getPLTEntry(ref.target()));
757   else if (requireCopy(ref.target()))
758     ref.setTarget(getObjectEntry(cast<SharedLibraryAtom>(ref.target())));
759 }
760
761 template <typename ELFT>
762 void RelocationPass<ELFT>::handle26(const MipsELFDefinedAtom<ELFT> &atom,
763                                     Reference &ref) {
764   bool isMicro = ref.kindValue() == R_MICROMIPS_26_S1;
765   assert((isMicro || ref.kindValue() == R_MIPS_26) && "Unexpected relocation");
766
767   const auto *sla = dyn_cast<SharedLibraryAtom>(ref.target());
768   if (sla && sla->type() == SharedLibraryAtom::Type::Code)
769     ref.setTarget(isMicro ? getPLTMicroEntry(sla) : getPLTRegEntry(sla));
770
771   if (requireLA25Stub(ref.target()))
772     ref.setTarget(getLA25Entry(ref.target(), isMicro));
773
774   if (!isLocal(ref.target())) {
775     if (isMicro)
776       ref.setKindValue(LLD_R_MICROMIPS_GLOBAL_26_S1);
777     else
778       ref.setKindValue(LLD_R_MIPS_GLOBAL_26);
779   }
780 }
781
782 template <typename ELFT> void RelocationPass<ELFT>::handleGOT(Reference &ref) {
783   if (!isLocalCall(ref.target())) {
784     ref.setTarget(getGlobalGOTEntry(ref.target()));
785     return;
786   }
787
788   if (ref.kindValue() == R_MIPS_GOT_PAGE)
789     ref.setTarget(getLocalGOTPageEntry(ref));
790   else if (ref.kindValue() == R_MIPS_GOT_DISP)
791     ref.setTarget(getLocalGOTEntry(ref));
792   else if (isLocal(ref.target()))
793     ref.setTarget(getLocalGOTPageEntry(ref));
794   else
795     ref.setTarget(getLocalGOTEntry(ref));
796 }
797
798 template <typename ELFT>
799 bool RelocationPass<ELFT>::isLocalCall(const Atom *a) const {
800   Atom::Scope scope;
801   if (auto *da = dyn_cast<DefinedAtom>(a))
802     scope = da->scope();
803   else if (auto *aa = dyn_cast<AbsoluteAtom>(a))
804     scope = aa->scope();
805   else
806     return false;
807
808   // Local and hidden symbols must be local.
809   if (scope == Atom::scopeTranslationUnit || scope == Atom::scopeLinkageUnit)
810     return true;
811
812   // Calls to external symbols defined in an executable file resolved locally.
813   if (_ctx.getOutputELFType() == ET_EXEC)
814     return true;
815
816   return false;
817 }
818
819 template <typename ELFT>
820 bool RelocationPass<ELFT>::requireLA25Stub(const Atom *a) const {
821   if (isLocal(a))
822     return false;
823   if (auto *da = dyn_cast<DefinedAtom>(a))
824     return static_cast<const MipsELFDefinedAtom<ELFT> *>(da)->file().isPIC();
825   return false;
826 }
827
828 template <typename ELFT>
829 const GOTAtom *RelocationPass<ELFT>::getLocalGOTEntry(const Reference &ref) {
830   const Atom *a = ref.target();
831   LocalGotMapKeyT key(a, ref.addend());
832
833   auto got = _gotLocalMap.find(key);
834   if (got != _gotLocalMap.end())
835     return got->second;
836
837   auto ga = new (_file._alloc) GOT0Atom<ELFT>(_file);
838   _gotLocalMap[key] = ga;
839
840   _localGotVector.push_back(ga);
841
842   Reference::KindValue relKind = ELFT::Is64Bits ? R_MIPS_64 : R_MIPS_32;
843   ga->addReferenceELF_Mips(relKind, 0, a, 0);
844
845   return ga;
846 }
847
848 template <typename ELFT>
849 const GOTAtom *
850 RelocationPass<ELFT>::getLocalGOTPageEntry(const Reference &ref) {
851   const Atom *a = ref.target();
852   LocalGotMapKeyT key(a, ref.addend());
853
854   auto got = _gotLocalPageMap.find(key);
855   if (got != _gotLocalPageMap.end())
856     return got->second;
857
858   auto ga = new (_file._alloc) GOT0Atom<ELFT>(_file);
859   _gotLocalPageMap[key] = ga;
860
861   _localGotVector.push_back(ga);
862
863   Reference::KindValue relKind =
864       ELFT::Is64Bits ? LLD_R_MIPS_64_HI16 : LLD_R_MIPS_32_HI16;
865   ga->addReferenceELF_Mips(relKind, 0, a, ref.addend());
866
867   return ga;
868 }
869
870 template <typename ELFT>
871 const GOTAtom *RelocationPass<ELFT>::getGlobalGOTEntry(const Atom *a) {
872   auto got = _gotGlobalMap.find(a);
873   if (got != _gotGlobalMap.end())
874     return got->second;
875
876   auto ga = new (_file._alloc) GOT0Atom<ELFT>(_file);
877   _gotGlobalMap[a] = ga;
878
879   _globalGotVector.push_back(ga);
880   ga->addReferenceELF_Mips(LLD_R_MIPS_GLOBAL_GOT, 0, a, 0);
881
882   if (const DefinedAtom *da = dyn_cast<DefinedAtom>(a))
883     ga->addReferenceELF_Mips(R_MIPS_32, 0, da, 0);
884
885   return ga;
886 }
887
888 template <typename ELFT>
889 const GOTAtom *RelocationPass<ELFT>::getTLSGOTEntry(const Atom *a) {
890   auto got = _gotTLSMap.find(a);
891   if (got != _gotTLSMap.end())
892     return got->second;
893
894   auto ga = new (_file._alloc) GOT0Atom<ELFT>(_file);
895   _gotTLSMap[a] = ga;
896
897   _tlsGotVector.push_back(ga);
898   Reference::KindValue relKind =
899       ELFT::Is64Bits ? R_MIPS_TLS_TPREL64 : R_MIPS_TLS_TPREL32;
900   ga->addReferenceELF_Mips(relKind, 0, a, 0);
901
902   return ga;
903 }
904
905 template <typename ELFT>
906 const GOTAtom *RelocationPass<ELFT>::getTLSGdGOTEntry(const Atom *a) {
907   auto got = _gotTLSGdMap.find(a);
908   if (got != _gotTLSGdMap.end())
909     return got->second;
910
911   auto ga = new (_file._alloc) GOTTLSGdAtom<ELFT>(_file);
912   _gotTLSGdMap[a] = ga;
913
914   _tlsGotVector.push_back(ga);
915   if (ELFT::Is64Bits) {
916     ga->addReferenceELF_Mips(R_MIPS_TLS_DTPMOD64, 0, a, 0);
917     ga->addReferenceELF_Mips(R_MIPS_TLS_DTPREL64, 8, a, 0);
918   } else {
919     ga->addReferenceELF_Mips(R_MIPS_TLS_DTPMOD32, 0, a, 0);
920     ga->addReferenceELF_Mips(R_MIPS_TLS_DTPREL32, 4, a, 0);
921   }
922
923   return ga;
924 }
925
926 template <typename ELFT>
927 const GOTAtom *RelocationPass<ELFT>::getTLSLdmGOTEntry(const Atom *a) {
928   if (_gotLDMEntry)
929     return _gotLDMEntry;
930
931   _gotLDMEntry = new (_file._alloc) GOTTLSGdAtom<ELFT>(_file);
932   _tlsGotVector.push_back(_gotLDMEntry);
933   if (ELFT::Is64Bits)
934     _gotLDMEntry->addReferenceELF_Mips(R_MIPS_TLS_DTPMOD64, 0, _gotLDMEntry, 0);
935   else
936     _gotLDMEntry->addReferenceELF_Mips(R_MIPS_TLS_DTPMOD32, 0, _gotLDMEntry, 0);
937
938   return _gotLDMEntry;
939 }
940
941 template <typename ELFT>
942 PLTAtom *RelocationPass<ELFT>::createPLTHeader(bool isMicroMips) {
943   auto ga1 = new (_file._alloc) GOTPLTAtom(_file);
944   _gotpltVector.insert(_gotpltVector.begin(), ga1);
945   auto ga0 = new (_file._alloc) GOTPLTAtom(_file);
946   _gotpltVector.insert(_gotpltVector.begin(), ga0);
947
948   if (isMicroMips)
949     return new (_file._alloc) PLT0MicroAtom(ga0, _file);
950   else
951     return new (_file._alloc) PLT0Atom(ga0, _file);
952 }
953
954 template <typename ELFT>
955 const GOTPLTAtom *RelocationPass<ELFT>::getGOTPLTEntry(const Atom *a) {
956   auto it = _gotpltMap.find(a);
957   if (it != _gotpltMap.end())
958     return it->second;
959
960   auto ga = new (_file._alloc) GOTPLTAtom(a, _file);
961   _gotpltMap[a] = ga;
962   _gotpltVector.push_back(ga);
963   return ga;
964 }
965
966 template <typename ELFT>
967 const PLTAtom *RelocationPass<ELFT>::getPLTRegEntry(const Atom *a) {
968   auto plt = _pltRegMap.find(a);
969   if (plt != _pltRegMap.end())
970     return plt->second;
971
972   PLTAAtom *pa = isR6Target()
973                      ? new (_file._alloc) PLTR6Atom(getGOTPLTEntry(a), _file)
974                      : new (_file._alloc) PLTAAtom(getGOTPLTEntry(a), _file);
975   _pltRegMap[a] = pa;
976   _pltRegVector.push_back(pa);
977
978   // Check that 'a' dynamic symbol table record should point to the PLT.
979   if (_hasStaticRelocations.count(a) && _requiresPtrEquality.count(a))
980     pa->addReferenceELF_Mips(LLD_R_MIPS_STO_PLT, 0, a, 0);
981
982   return pa;
983 }
984
985 template <typename ELFT>
986 const PLTAtom *RelocationPass<ELFT>::getPLTMicroEntry(const Atom *a) {
987   auto plt = _pltMicroMap.find(a);
988   if (plt != _pltMicroMap.end())
989     return plt->second;
990
991   auto pa = new (_file._alloc) PLTMicroAtom(getGOTPLTEntry(a), _file);
992   _pltMicroMap[a] = pa;
993   _pltMicroVector.push_back(pa);
994
995   // Check that 'a' dynamic symbol table record should point to the PLT.
996   if (_hasStaticRelocations.count(a) && _requiresPtrEquality.count(a))
997     pa->addReferenceELF_Mips(LLD_R_MIPS_STO_PLT, 0, a, 0);
998
999   return pa;
1000 }
1001
1002 template <typename ELFT>
1003 const LA25Atom *RelocationPass<ELFT>::getLA25RegEntry(const Atom *a) {
1004   auto la25 = _la25RegMap.find(a);
1005   if (la25 != _la25RegMap.end())
1006     return la25->second;
1007
1008   auto sa = new (_file._alloc) LA25RegAtom(a, _file);
1009   _la25RegMap[a] = sa;
1010   _la25Vector.push_back(sa);
1011
1012   return sa;
1013 }
1014
1015 template <typename ELFT>
1016 const LA25Atom *RelocationPass<ELFT>::getLA25MicroEntry(const Atom *a) {
1017   auto la25 = _la25MicroMap.find(a);
1018   if (la25 != _la25MicroMap.end())
1019     return la25->second;
1020
1021   auto sa = new (_file._alloc) LA25MicroAtom(a, _file);
1022   _la25MicroMap[a] = sa;
1023   _la25Vector.push_back(sa);
1024
1025   return sa;
1026 }
1027
1028 template <typename ELFT>
1029 const ObjectAtom *
1030 RelocationPass<ELFT>::getObjectEntry(const SharedLibraryAtom *a) {
1031   auto obj = _objectMap.find(a);
1032   if (obj != _objectMap.end())
1033     return obj->second;
1034
1035   auto oa = new (_file._alloc) ObjectAtom(_file);
1036   oa->addReferenceELF_Mips(R_MIPS_COPY, 0, oa, 0);
1037   oa->_name = a->name();
1038   oa->_size = a->size();
1039
1040   _objectMap[a] = oa;
1041   _objectVector.push_back(oa);
1042
1043   return oa;
1044 }
1045
1046 } // end anon namespace
1047
1048 static std::unique_ptr<Pass> createPass(MipsLinkingContext &ctx) {
1049   switch (ctx.getTriple().getArch()) {
1050   case llvm::Triple::mipsel:
1051     return llvm::make_unique<RelocationPass<Mips32ELType>>(ctx);
1052   case llvm::Triple::mips64el:
1053     return llvm::make_unique<RelocationPass<Mips64ELType>>(ctx);
1054   default:
1055     llvm_unreachable("Unhandled arch");
1056   }
1057 }
1058
1059 std::unique_ptr<Pass>
1060 lld::elf::createMipsRelocationPass(MipsLinkingContext &ctx) {
1061   switch (ctx.getOutputELFType()) {
1062   case ET_EXEC:
1063   case ET_DYN:
1064     return createPass(ctx);
1065   case ET_REL:
1066     return nullptr;
1067   default:
1068     llvm_unreachable("Unhandled output file type");
1069   }
1070 }