1 //===- lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp -------------------===//
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "MipsELFFile.h"
11 #include "MipsLinkingContext.h"
12 #include "MipsRelocationPass.h"
13 #include "MipsTargetHandler.h"
14 #include "llvm/ADT/DenseSet.h"
17 using namespace lld::elf;
18 using namespace llvm::ELF;
21 static const uint8_t mipsGot0AtomContent[] = {
22 0x00, 0x00, 0x00, 0x00,
23 0x00, 0x00, 0x00, 0x00
27 static const uint8_t mipsGotModulePointerAtomContent[] = {
28 0x00, 0x00, 0x00, 0x00,
29 0x00, 0x00, 0x00, 0x80
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
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
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
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)
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)
78 0x02, 0x0f // move $24, $2
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)
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
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
107 /// \brief Abstract base class represent MIPS GOT entries.
108 class MipsGOTAtom : public GOTAtom {
110 MipsGOTAtom(const File &f) : GOTAtom(f, ".got") {}
112 Alignment alignment() const override { return Alignment(2); }
115 /// \brief MIPS GOT entry initialized by zero.
116 template <typename ELFT> class GOT0Atom : public MipsGOTAtom {
118 GOT0Atom(const File &f) : MipsGOTAtom(f) {}
120 ArrayRef<uint8_t> rawContent() const override;
123 template <> ArrayRef<uint8_t> GOT0Atom<Mips32ELType>::rawContent() const {
124 return llvm::makeArrayRef(mipsGot0AtomContent).slice(4);
126 template <> ArrayRef<uint8_t> GOT0Atom<Mips64ELType>::rawContent() const {
127 return llvm::makeArrayRef(mipsGot0AtomContent);
130 /// \brief MIPS GOT entry initialized by zero.
131 template <typename ELFT> class GOTModulePointerAtom : public MipsGOTAtom {
133 GOTModulePointerAtom(const File &f) : MipsGOTAtom(f) {}
135 ArrayRef<uint8_t> rawContent() const override;
139 ArrayRef<uint8_t> GOTModulePointerAtom<Mips32ELType>::rawContent() const {
140 return llvm::makeArrayRef(mipsGotModulePointerAtomContent).slice(4);
143 ArrayRef<uint8_t> GOTModulePointerAtom<Mips64ELType>::rawContent() const {
144 return llvm::makeArrayRef(mipsGotModulePointerAtomContent);
147 /// \brief MIPS GOT TLS GD entry.
148 template <typename ELFT> class GOTTLSGdAtom : public MipsGOTAtom {
150 GOTTLSGdAtom(const File &f) : MipsGOTAtom(f) {}
152 ArrayRef<uint8_t> rawContent() const override;
155 template <> ArrayRef<uint8_t> GOTTLSGdAtom<Mips32ELType>::rawContent() const {
156 return llvm::makeArrayRef(mipsGotTlsGdAtomContent).slice(8);
159 template <> ArrayRef<uint8_t> GOTTLSGdAtom<Mips64ELType>::rawContent() const {
160 return llvm::makeArrayRef(mipsGotTlsGdAtomContent);
163 class GOTPLTAtom : public GOTAtom {
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);
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);
176 Alignment alignment() const override { return Alignment(2); }
178 ArrayRef<uint8_t> rawContent() const override {
179 return llvm::makeArrayRef(mipsGot0AtomContent).slice(4);
183 class PLT0Atom : public PLTAtom {
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);
192 ArrayRef<uint8_t> rawContent() const override {
193 return llvm::makeArrayRef(mipsPlt0AtomContent);
197 class PLT0MicroAtom : public PLTAtom {
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);
204 CodeModel codeModel() const override { return codeMipsMicro; }
206 ArrayRef<uint8_t> rawContent() const override {
207 return llvm::makeArrayRef(micromipsPlt0AtomContent);
211 class PLTAAtom : public PLTAtom {
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);
220 ArrayRef<uint8_t> rawContent() const override {
221 return llvm::makeArrayRef(mipsPltAAtomContent);
225 class PLTR6Atom : public PLTAAtom {
227 PLTR6Atom(const GOTPLTAtom *got, const File &f) : PLTAAtom(got, f) {}
229 ArrayRef<uint8_t> rawContent() const override {
230 return llvm::makeArrayRef(mipsR6PltAAtomContent);
234 class PLTMicroAtom : public PLTAtom {
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);
241 Alignment alignment() const override { return Alignment(1); }
242 CodeModel codeModel() const override { return codeMipsMicro; }
244 ArrayRef<uint8_t> rawContent() const override {
245 return llvm::makeArrayRef(micromipsPltAtomContent);
249 class LA25Atom : public PLTAtom {
251 LA25Atom(const File &f) : PLTAtom(f, ".text") {}
254 class LA25RegAtom : public LA25Atom {
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);
263 ArrayRef<uint8_t> rawContent() const override {
264 return llvm::makeArrayRef(mipsLA25AtomContent);
268 class LA25MicroAtom : public LA25Atom {
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);
277 CodeModel codeModel() const override { return codeMipsMicro; }
279 ArrayRef<uint8_t> rawContent() const override {
280 return llvm::makeArrayRef(micromipsLA25AtomContent);
284 class RelocationPassFile : public SimpleFile {
286 RelocationPassFile(const ELFLinkingContext &ctx)
287 : SimpleFile("RelocationPassFile") {
288 setOrdinal(ctx.getNextOrdinalAndIncrement());
291 llvm::BumpPtrAllocator _alloc;
294 template <typename ELFT> class RelocationPass : public Pass {
296 RelocationPass(MipsLinkingContext &ctx);
298 void perform(std::unique_ptr<MutableFile> &mf) override;
301 /// \brief Reference to the linking context.
302 const MipsLinkingContext &_ctx;
304 /// \brief Owner of all the Atoms created by this pass.
305 RelocationPassFile _file;
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;
312 /// \brief Map Atoms to global GOT entries.
313 llvm::DenseMap<const Atom *, GOTAtom *> _gotGlobalMap;
315 /// \brief Map Atoms to TLS GOT entries.
316 llvm::DenseMap<const Atom *, GOTAtom *> _gotTLSMap;
318 /// \brief Map Atoms to TLS GD GOT entries.
319 llvm::DenseMap<const Atom *, GOTAtom *> _gotTLSGdMap;
321 /// \brief GOT entry for the R_xxxMIPS_TLS_LDM relocations.
322 GOTTLSGdAtom<ELFT> *_gotLDMEntry;
324 /// \brief the list of local GOT atoms.
325 std::vector<GOTAtom *> _localGotVector;
327 /// \brief the list of global GOT atoms.
328 std::vector<GOTAtom *> _globalGotVector;
330 /// \brief the list of TLS GOT atoms.
331 std::vector<GOTAtom *> _tlsGotVector;
333 /// \brief Map Atoms to their GOTPLT entries.
334 llvm::DenseMap<const Atom *, GOTPLTAtom *> _gotpltMap;
336 /// \brief Map Atoms to their PLT entries.
337 llvm::DenseMap<const Atom *, PLTAAtom *> _pltRegMap;
338 llvm::DenseMap<const Atom *, PLTMicroAtom *> _pltMicroMap;
340 /// \brief Map Atoms to their Object entries.
341 llvm::DenseMap<const Atom *, ObjectAtom *> _objectMap;
343 /// \brief Map Atoms to their LA25 entries.
344 llvm::DenseMap<const Atom *, LA25RegAtom *> _la25RegMap;
345 llvm::DenseMap<const Atom *, LA25MicroAtom *> _la25MicroMap;
347 /// \brief Atoms referenced by static relocations.
348 llvm::DenseSet<const Atom *> _hasStaticRelocations;
350 /// \brief Atoms require pointers equality.
351 llvm::DenseSet<const Atom *> _requiresPtrEquality;
353 /// \brief References which are candidates for converting
354 /// to the R_MIPS_REL32 relocation.
355 std::vector<Reference *> _rel32Candidates;
357 /// \brief the list of PLT atoms.
358 std::vector<PLTAtom *> _pltRegVector;
359 std::vector<PLTAtom *> _pltMicroVector;
361 /// \brief the list of GOTPLT atoms.
362 std::vector<GOTPLTAtom *> _gotpltVector;
364 /// \brief the list of Object entries.
365 std::vector<ObjectAtom *> _objectVector;
367 /// \brief the list of LA25 entries.
368 std::vector<LA25Atom *> _la25Vector;
370 /// \brief Handle a specific reference.
371 void handleReference(const MipsELFDefinedAtom<ELFT> &atom, Reference &ref);
373 /// \brief Collect information about the reference to use it
374 /// later in the handleReference() routine.
375 void collectReferenceInfo(const MipsELFDefinedAtom<ELFT> &atom,
378 void handlePlain(const MipsELFDefinedAtom<ELFT> &atom, Reference &ref);
379 void handle26(const MipsELFDefinedAtom<ELFT> &atom, Reference &ref);
380 void handleGOT(Reference &ref);
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);
397 PLTAtom *createPLTHeader(bool isMicroMips);
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;
409 bool isR6Target() const;
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));
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));
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));
433 // Create R_MIPS_REL32 relocations.
434 for (auto *ref : _rel32Candidates) {
435 if (!isDynamic(ref->target()) || hasPLTEntry(ref->target()))
437 ref->setKindValue(R_MIPS_REL32);
439 static_cast<MipsELFReference<ELFT> *>(ref)->setTag(R_MIPS_64);
440 if (!isLocalCall(ref->target()))
441 getGlobalGOTEntry(ref->target());
444 uint64_t ordinal = 0;
446 for (auto &got : _localGotVector) {
447 got->setOrdinal(ordinal++);
451 for (auto &got : _globalGotVector) {
452 got->setOrdinal(ordinal++);
456 for (auto &got : _tlsGotVector) {
457 got->setOrdinal(ordinal++);
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);
469 plt0Atom->setOrdinal(ordinal++);
470 mf->addAtom(*plt0Atom);
473 // Emit regular PLT entries firts.
474 for (auto &plt : _pltRegVector) {
475 plt->setOrdinal(ordinal++);
479 // microMIPS PLT entries come after regular ones.
480 for (auto &plt : _pltMicroVector) {
481 plt->setOrdinal(ordinal++);
485 // Assign PLT0 to GOTPLT entries.
486 assert(_gotpltMap.empty() || plt0Atom);
487 for (auto &a: _gotpltMap)
488 a.second->setPLT0(plt0Atom);
490 for (auto &gotplt : _gotpltVector) {
491 gotplt->setOrdinal(ordinal++);
492 mf->addAtom(*gotplt);
495 for (auto obj : _objectVector) {
496 obj->setOrdinal(ordinal++);
500 for (auto la25 : _la25Vector) {
501 la25->setOrdinal(ordinal++);
506 template <typename ELFT>
507 void RelocationPass<ELFT>::handleReference(const MipsELFDefinedAtom<ELFT> &atom,
511 if (ref.kindNamespace() != lld::Reference::KindNamespace::ELF)
513 assert(ref.kindArch() == Reference::KindArch::Mips);
514 switch (ref.kindValue()) {
521 case R_MICROMIPS_HI16:
522 case R_MICROMIPS_LO16:
523 // FIXME (simon): Handle dynamic/static linking differently.
524 handlePlain(atom, ref);
527 case R_MICROMIPS_26_S1:
532 case R_MICROMIPS_GOT16:
533 case R_MICROMIPS_CALL16:
534 case R_MIPS_GOT_DISP:
535 case R_MIPS_GOT_PAGE:
538 case R_MIPS_GOT_OFST:
539 // Nothing to do. We create GOT page entry in the R_MIPS_GOT_PAGE handler.
542 if (isLocal(ref.target()))
543 ref.setAddend(ref.addend() + atom.file().getGP0());
546 ref.setAddend(ref.addend() + atom.file().getGP0());
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());
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());
561 case R_MICROMIPS_TLS_GD:
562 ref.setTarget(getTLSGdGOTEntry(ref.target()));
565 case R_MICROMIPS_TLS_LDM:
566 ref.setTarget(getTLSLdmGOTEntry(ref.target()));
568 case R_MIPS_TLS_GOTTPREL:
569 case R_MICROMIPS_TLS_GOTTPREL:
570 ref.setTarget(getTLSGOTEntry(ref.target()));
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)
583 case R_MICROMIPS_JALR:
592 template <typename ELFT>
593 void RelocationPass<ELFT>::collectReferenceInfo(
594 const MipsELFDefinedAtom<ELFT> &atom, Reference &ref) {
597 if (ref.kindNamespace() != lld::Reference::KindNamespace::ELF)
600 auto refKind = ref.kindValue();
601 if (!isConstrainSym(atom, refKind))
604 if (mightBeDynamic(atom, refKind))
605 _rel32Candidates.push_back(&ref);
607 _hasStaticRelocations.insert(ref.target());
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());
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;
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;
626 if ((secFlags & SHF_ALLOC) == 0)
628 if (secType == SHT_NOBITS)
630 if ((secFlags & SHF_WRITE) != 0)
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)
642 if (refKind != R_MIPS_32 && refKind != R_MIPS_64)
644 if ((atom.section()->sh_flags & SHF_ALLOC) == 0)
647 if (_ctx.getOutputELFType() == ET_DYN)
649 if (!isMipsReadonly(atom))
651 if (atom.file().isPIC())
657 template <typename ELFT>
658 bool RelocationPass<ELFT>::hasPLTEntry(const Atom *atom) const {
659 return _pltRegMap.count(atom) || _pltMicroMap.count(atom);
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:
672 template <typename ELFT>
673 bool RelocationPass<ELFT>::requirePLTEntry(const Atom *a) const {
674 if (!_hasStaticRelocations.count(a))
676 const auto *sa = dyn_cast<ELFDynamicAtom<ELFT>>(a);
677 if (sa && sa->type() != SharedLibraryAtom::Type::Code)
679 const auto *da = dyn_cast<ELFDefinedAtom<ELFT>>(a);
680 if (da && da->contentType() != DefinedAtom::typeCode)
687 template <typename ELFT>
688 bool RelocationPass<ELFT>::requireCopy(const Atom *a) const {
689 if (!_hasStaticRelocations.count(a))
691 const auto *sa = dyn_cast<ELFDynamicAtom<ELFT>>(a);
692 return sa && sa->type() == SharedLibraryAtom::Type::Data;
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)
701 const auto *sa = dyn_cast<SharedLibraryAtom>(atom);
705 if (_ctx.getOutputELFType() == ET_DYN) {
706 if (da && da->scope() != DefinedAtom::scopeTranslationUnit)
709 const auto *ua = dyn_cast<UndefinedAtom>(atom);
717 template <typename ELFT>
718 static bool isMicroMips(const MipsELFDefinedAtom<ELFT> &atom) {
719 return atom.codeModel() == DefinedAtom::codeMipsMicro ||
720 atom.codeModel() == DefinedAtom::codeMipsMicroPIC;
723 template <typename ELFT>
724 const LA25Atom *RelocationPass<ELFT>::getLA25Entry(const Atom *target,
726 return isMicroMips ? getLA25MicroEntry(target) : getLA25RegEntry(target);
729 template <typename ELFT>
730 const PLTAtom *RelocationPass<ELFT>::getPLTEntry(const Atom *a) {
731 bool hasMicroCode = _ctx.getMergedELFFlags() & EF_MIPS_MICROMIPS;
733 // If file contains microMIPS code try to reuse compressed PLT entry...
735 auto microPLT = _pltMicroMap.find(a);
736 if (microPLT != _pltMicroMap.end())
737 return microPLT->second;
740 // ... then try to reuse a regular PLT entry ...
741 auto regPLT = _pltRegMap.find(a);
742 if (regPLT != _pltRegMap.end())
743 return regPLT->second;
745 // ... and finally prefer to create new compressed PLT entry.
746 return hasMicroCode ? getPLTMicroEntry(a) : getPLTRegEntry(a);
749 template <typename ELFT>
750 void RelocationPass<ELFT>::handlePlain(const MipsELFDefinedAtom<ELFT> &atom,
752 if (!isDynamic(ref.target()))
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())));
761 template <typename ELFT>
762 void RelocationPass<ELFT>::handle26(const MipsELFDefinedAtom<ELFT> &atom,
764 bool isMicro = ref.kindValue() == R_MICROMIPS_26_S1;
765 assert((isMicro || ref.kindValue() == R_MIPS_26) && "Unexpected relocation");
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));
771 if (requireLA25Stub(ref.target()))
772 ref.setTarget(getLA25Entry(ref.target(), isMicro));
774 if (!isLocal(ref.target())) {
776 ref.setKindValue(LLD_R_MICROMIPS_GLOBAL_26_S1);
778 ref.setKindValue(LLD_R_MIPS_GLOBAL_26);
782 template <typename ELFT> void RelocationPass<ELFT>::handleGOT(Reference &ref) {
783 if (!isLocalCall(ref.target())) {
784 ref.setTarget(getGlobalGOTEntry(ref.target()));
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));
795 ref.setTarget(getLocalGOTEntry(ref));
798 template <typename ELFT>
799 bool RelocationPass<ELFT>::isLocalCall(const Atom *a) const {
801 if (auto *da = dyn_cast<DefinedAtom>(a))
803 else if (auto *aa = dyn_cast<AbsoluteAtom>(a))
808 // Local and hidden symbols must be local.
809 if (scope == Atom::scopeTranslationUnit || scope == Atom::scopeLinkageUnit)
812 // Calls to external symbols defined in an executable file resolved locally.
813 if (_ctx.getOutputELFType() == ET_EXEC)
819 template <typename ELFT>
820 bool RelocationPass<ELFT>::requireLA25Stub(const Atom *a) const {
823 if (auto *da = dyn_cast<DefinedAtom>(a))
824 return static_cast<const MipsELFDefinedAtom<ELFT> *>(da)->file().isPIC();
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());
833 auto got = _gotLocalMap.find(key);
834 if (got != _gotLocalMap.end())
837 auto ga = new (_file._alloc) GOT0Atom<ELFT>(_file);
838 _gotLocalMap[key] = ga;
840 _localGotVector.push_back(ga);
842 Reference::KindValue relKind = ELFT::Is64Bits ? R_MIPS_64 : R_MIPS_32;
843 ga->addReferenceELF_Mips(relKind, 0, a, 0);
848 template <typename ELFT>
850 RelocationPass<ELFT>::getLocalGOTPageEntry(const Reference &ref) {
851 const Atom *a = ref.target();
852 LocalGotMapKeyT key(a, ref.addend());
854 auto got = _gotLocalPageMap.find(key);
855 if (got != _gotLocalPageMap.end())
858 auto ga = new (_file._alloc) GOT0Atom<ELFT>(_file);
859 _gotLocalPageMap[key] = ga;
861 _localGotVector.push_back(ga);
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());
870 template <typename ELFT>
871 const GOTAtom *RelocationPass<ELFT>::getGlobalGOTEntry(const Atom *a) {
872 auto got = _gotGlobalMap.find(a);
873 if (got != _gotGlobalMap.end())
876 auto ga = new (_file._alloc) GOT0Atom<ELFT>(_file);
877 _gotGlobalMap[a] = ga;
879 _globalGotVector.push_back(ga);
880 ga->addReferenceELF_Mips(LLD_R_MIPS_GLOBAL_GOT, 0, a, 0);
882 if (const DefinedAtom *da = dyn_cast<DefinedAtom>(a))
883 ga->addReferenceELF_Mips(R_MIPS_32, 0, da, 0);
888 template <typename ELFT>
889 const GOTAtom *RelocationPass<ELFT>::getTLSGOTEntry(const Atom *a) {
890 auto got = _gotTLSMap.find(a);
891 if (got != _gotTLSMap.end())
894 auto ga = new (_file._alloc) GOT0Atom<ELFT>(_file);
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);
905 template <typename ELFT>
906 const GOTAtom *RelocationPass<ELFT>::getTLSGdGOTEntry(const Atom *a) {
907 auto got = _gotTLSGdMap.find(a);
908 if (got != _gotTLSGdMap.end())
911 auto ga = new (_file._alloc) GOTTLSGdAtom<ELFT>(_file);
912 _gotTLSGdMap[a] = ga;
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);
919 ga->addReferenceELF_Mips(R_MIPS_TLS_DTPMOD32, 0, a, 0);
920 ga->addReferenceELF_Mips(R_MIPS_TLS_DTPREL32, 4, a, 0);
926 template <typename ELFT>
927 const GOTAtom *RelocationPass<ELFT>::getTLSLdmGOTEntry(const Atom *a) {
931 _gotLDMEntry = new (_file._alloc) GOTTLSGdAtom<ELFT>(_file);
932 _tlsGotVector.push_back(_gotLDMEntry);
934 _gotLDMEntry->addReferenceELF_Mips(R_MIPS_TLS_DTPMOD64, 0, _gotLDMEntry, 0);
936 _gotLDMEntry->addReferenceELF_Mips(R_MIPS_TLS_DTPMOD32, 0, _gotLDMEntry, 0);
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);
949 return new (_file._alloc) PLT0MicroAtom(ga0, _file);
951 return new (_file._alloc) PLT0Atom(ga0, _file);
954 template <typename ELFT>
955 const GOTPLTAtom *RelocationPass<ELFT>::getGOTPLTEntry(const Atom *a) {
956 auto it = _gotpltMap.find(a);
957 if (it != _gotpltMap.end())
960 auto ga = new (_file._alloc) GOTPLTAtom(a, _file);
962 _gotpltVector.push_back(ga);
966 template <typename ELFT>
967 const PLTAtom *RelocationPass<ELFT>::getPLTRegEntry(const Atom *a) {
968 auto plt = _pltRegMap.find(a);
969 if (plt != _pltRegMap.end())
972 PLTAAtom *pa = isR6Target()
973 ? new (_file._alloc) PLTR6Atom(getGOTPLTEntry(a), _file)
974 : new (_file._alloc) PLTAAtom(getGOTPLTEntry(a), _file);
976 _pltRegVector.push_back(pa);
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);
985 template <typename ELFT>
986 const PLTAtom *RelocationPass<ELFT>::getPLTMicroEntry(const Atom *a) {
987 auto plt = _pltMicroMap.find(a);
988 if (plt != _pltMicroMap.end())
991 auto pa = new (_file._alloc) PLTMicroAtom(getGOTPLTEntry(a), _file);
992 _pltMicroMap[a] = pa;
993 _pltMicroVector.push_back(pa);
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);
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;
1008 auto sa = new (_file._alloc) LA25RegAtom(a, _file);
1009 _la25RegMap[a] = sa;
1010 _la25Vector.push_back(sa);
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;
1021 auto sa = new (_file._alloc) LA25MicroAtom(a, _file);
1022 _la25MicroMap[a] = sa;
1023 _la25Vector.push_back(sa);
1028 template <typename ELFT>
1030 RelocationPass<ELFT>::getObjectEntry(const SharedLibraryAtom *a) {
1031 auto obj = _objectMap.find(a);
1032 if (obj != _objectMap.end())
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();
1041 _objectVector.push_back(oa);
1046 } // end anon namespace
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);
1055 llvm_unreachable("Unhandled arch");
1059 std::unique_ptr<Pass>
1060 lld::elf::createMipsRelocationPass(MipsLinkingContext &ctx) {
1061 switch (ctx.getOutputELFType()) {
1064 return createPass(ctx);
1068 llvm_unreachable("Unhandled output file type");