diff options
| author | Simon Atanasyan <simon@atanasyan.com> | 2014-06-07 13:20:53 +0000 |
|---|---|---|
| committer | Simon Atanasyan <simon@atanasyan.com> | 2014-06-07 13:20:53 +0000 |
| commit | c8e86fb0323a9cba7e1745e68c713ff0dee3f85c (patch) | |
| tree | 77fb8c25a4fef5cf4df16c3a4c7abcf9a74619c1 /lld/lib | |
| parent | 4ba22f08133c0a5dbccaa6a442219693c1d677f0 (diff) | |
| download | bcm5719-llvm-c8e86fb0323a9cba7e1745e68c713ff0dee3f85c.tar.gz bcm5719-llvm-c8e86fb0323a9cba7e1745e68c713ff0dee3f85c.zip | |
[Mips] Handle Mips TLS relocations R_MIPS_TLS_GOTTPREL / R_MIPS_TLS_GD / R_MIPS_TLS_LDM etc.
llvm-svn: 210394
Diffstat (limited to 'lld/lib')
7 files changed, 168 insertions, 27 deletions
diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsELFFile.h b/lld/lib/ReaderWriter/ELF/Mips/MipsELFFile.h index afdfc11ebe4..9d1c5888f8f 100644 --- a/lld/lib/ReaderWriter/ELF/Mips/MipsELFFile.h +++ b/lld/lib/ReaderWriter/ELF/Mips/MipsELFFile.h @@ -118,6 +118,7 @@ public: /// \brief .tdata section address plus fixed offset. uint64_t getTPOffset() const { return *_tpOff; } + uint64_t getDTPOffset() const { return *_dtpOff; } private: typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym; @@ -125,10 +126,11 @@ private: typedef llvm::object::Elf_Rel_Impl<ELFT, false> Elf_Rel; typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel_Iter Elf_Rel_Iter; - enum { TP_OFFSET = 0x7000 }; + enum { TP_OFFSET = 0x7000, DTP_OFFSET = 0x8000 }; llvm::Optional<int64_t> _gp0; llvm::Optional<uint64_t> _tpOff; + llvm::Optional<uint64_t> _dtpOff; ErrorOr<ELFDefinedAtom<ELFT> *> handleDefinedSymbol( StringRef symName, StringRef sectionName, const Elf_Sym *sym, @@ -155,8 +157,10 @@ private: assert(raw.size() == sizeof(Elf_RegInfo) && "Invalid size of RegInfo section"); _gp0 = reinterpret_cast<const Elf_RegInfo *>(raw.data())->ri_gp_value; - } else if (!_tpOff.hasValue() && section.sh_flags & llvm::ELF::SHF_TLS) + } else if (!_tpOff.hasValue() && section.sh_flags & llvm::ELF::SHF_TLS) { _tpOff = section.sh_addr + TP_OFFSET; + _dtpOff = section.sh_addr + DTP_OFFSET; + } } return error_code(); } @@ -201,6 +205,11 @@ private: case llvm::ELF::R_MIPS_HI16: case llvm::ELF::R_MIPS_LO16: case llvm::ELF::R_MIPS_GOT16: + case llvm::ELF::R_MIPS_TLS_GD: + case llvm::ELF::R_MIPS_TLS_LDM: + case llvm::ELF::R_MIPS_TLS_GOTTPREL: + case llvm::ELF::R_MIPS_TLS_DTPREL_HI16: + case llvm::ELF::R_MIPS_TLS_DTPREL_LO16: case llvm::ELF::R_MIPS_TLS_TPREL_HI16: case llvm::ELF::R_MIPS_TLS_TPREL_LO16: return *(int16_t *)ap; diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsExecutableWriter.h b/lld/lib/ReaderWriter/ELF/Mips/MipsExecutableWriter.h index 65034d279e5..8f28312a1d9 100644 --- a/lld/lib/ReaderWriter/ELF/Mips/MipsExecutableWriter.h +++ b/lld/lib/ReaderWriter/ELF/Mips/MipsExecutableWriter.h @@ -59,6 +59,14 @@ template <class ELFT> void MipsExecutableWriter<ELFT>::buildDynamicSymbolTable(const File &file) { // MIPS ABI requires to add to dynsym even undefined symbols // if they have a corresponding entries in a global part of GOT. + for (auto sec : this->_layout.sections()) + if (auto section = dyn_cast<AtomSection<ELFT>>(sec)) + for (const auto &atom : section->atoms()) { + if (_writeHelper.hasGlobalGOTEntry(atom->_atom)) + this->_dynamicSymbolTable->addSymbol(atom->_atom, section->ordinal(), + atom->_virtualAddr, atom); + } + for (const UndefinedAtom *a : file.undefined()) // FIXME (simon): Consider to move this check to the // MipsELFUndefinedAtom class method. That allows to diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp b/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp index 9e0e81d3534..946c96c7fa2 100644 --- a/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp +++ b/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp @@ -56,6 +56,9 @@ bool MipsLinkingContext::isDynamicRelocation(const DefinedAtom &, switch (r.kindValue()) { case llvm::ELF::R_MIPS_COPY: case llvm::ELF::R_MIPS_REL32: + case llvm::ELF::R_MIPS_TLS_DTPMOD32: + case llvm::ELF::R_MIPS_TLS_DTPREL32: + case llvm::ELF::R_MIPS_TLS_TPREL32: return true; default: return false; diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp index a1e0ea36237..d3665022fbc 100644 --- a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp +++ b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp @@ -92,14 +92,14 @@ static void relocGOT(uint8_t *location, uint64_t P, uint64_t S, int64_t A, applyReloc(location, G, 0xffff); } -/// \brief R_MIPS_TLS_TPREL_HI16, LLD_R_MIPS_HI16 +/// \brief R_MIPS_TLS_DTPREL_HI16, R_MIPS_TLS_TPREL_HI16, LLD_R_MIPS_HI16 /// (S + A) >> 16 static void relocGeneralHi16(uint8_t *location, uint64_t S, int64_t A) { int32_t result = S + A + 0x8000; applyReloc(location, result >> 16, 0xffff); } -/// \brief R_MIPS_TLS_TPREL_LO16, LLD_R_MIPS_LO16 +/// \brief R_MIPS_TLS_DTPREL_LO16, R_MIPS_TLS_TPREL_LO16, LLD_R_MIPS_LO16 /// S + A static void relocGeneralLo16(uint8_t *location, uint64_t S, int64_t A) { int32_t result = S + A; @@ -158,9 +158,18 @@ error_code MipsTargetRelocationHandler::applyRelocation( case R_MIPS_CALL16: relocGOT(location, relocVAddress, targetVAddress, ref.addend(), gpAddr); break; + case R_MIPS_TLS_GD: + relocGOT(location, relocVAddress, targetVAddress, ref.addend(), gpAddr); + break; + case R_MIPS_TLS_LDM: + case R_MIPS_TLS_GOTTPREL: + relocGOT(location, relocVAddress, targetVAddress, ref.addend(), gpAddr); + break; + case R_MIPS_TLS_DTPREL_HI16: case R_MIPS_TLS_TPREL_HI16: relocGeneralHi16(location, targetVAddress, ref.addend()); break; + case R_MIPS_TLS_DTPREL_LO16: case R_MIPS_TLS_TPREL_LO16: relocGeneralLo16(location, targetVAddress, ref.addend()); break; @@ -173,6 +182,9 @@ error_code MipsTargetRelocationHandler::applyRelocation( case R_MIPS_REL32: case R_MIPS_JUMP_SLOT: case R_MIPS_COPY: + case R_MIPS_TLS_DTPMOD32: + case R_MIPS_TLS_DTPREL32: + case R_MIPS_TLS_TPREL32: // Ignore runtime relocations. break; case R_MIPS_PC32: diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp index 16f8af839f1..5e507255cac 100644 --- a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp +++ b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp @@ -28,6 +28,12 @@ static const uint8_t mipsGotModulePointerAtomContent[] = { 0x00, 0x00, 0x00, 0x80 }; +// TLS GD Entry +static const uint8_t mipsGotTlsGdAtomContent[] = { + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 +}; + // PLT0 entry static const uint8_t mipsPlt0AtomContent[] = { 0x00, 0x00, 0x1c, 0x3c, // lui $28, %hi(&GOTPLT[0]) @@ -86,6 +92,16 @@ public: } }; +/// \brief MIPS GOT TLS GD entry. +class GOTTLSGdAtom : public MipsGOTAtom { +public: + GOTTLSGdAtom(const File &f) : MipsGOTAtom(f) {} + + ArrayRef<uint8_t> rawContent() const override { + return llvm::makeArrayRef(mipsGotTlsGdAtomContent); + } +}; + class PLT0Atom : public PLTAtom { public: PLT0Atom(const File &f) : PLTAtom(f, ".plt") {} @@ -156,12 +172,24 @@ private: /// \brief Map Atoms to global GOT entries. llvm::DenseMap<const Atom *, GOTAtom *> _gotGlobalMap; + /// \brief Map Atoms to TLS GOT entries. + llvm::DenseMap<const Atom *, GOTAtom *> _gotTLSMap; + + /// \brief Map Atoms to TLS GD GOT entries. + llvm::DenseMap<const Atom *, GOTAtom *> _gotTLSGdMap; + + /// \brief GOT entry for the R_MIPS_TLS_LDM relocation. + GOTTLSGdAtom *_gotLDMEntry; + /// \brief the list of local GOT atoms. std::vector<GOTAtom *> _localGotVector; /// \brief the list of global GOT atoms. std::vector<GOTAtom *> _globalGotVector; + /// \brief the list of TLS GOT atoms. + std::vector<GOTAtom *> _tlsGotVector; + /// \brief Map Atoms to their PLT entries. llvm::DenseMap<const Atom *, PLTAtom *> _pltMap; @@ -205,10 +233,12 @@ private: void handle26(Reference &ref); void handleGOT(Reference &ref); void handleGPRel(const MipsELFDefinedAtom<ELFT> &atom, Reference &ref); - void handleTLS(const MipsELFDefinedAtom<ELFT> &atom, Reference &ref); const GOTAtom *getLocalGOTEntry(const Reference &ref); const GOTAtom *getGlobalGOTEntry(const Atom *a); + const GOTAtom *getTLSGOTEntry(const Atom *a); + const GOTAtom *getTLSGdGOTEntry(const Atom *a); + const GOTAtom *getTLSLdmGOTEntry(const Atom *a); PLTAtom *getPLTEntry(const Atom *a); const LA25Atom *getLA25Entry(const Atom *a); const ObjectAtom *getObjectEntry(const SharedLibraryAtom *a); @@ -230,7 +260,7 @@ private: template <typename ELFT> RelocationPass<ELFT>::RelocationPass(MipsLinkingContext &context) - : _context(context), _file(context) { + : _context(context), _file(context), _gotLDMEntry(nullptr) { _localGotVector.push_back(new (_file._alloc) GOT0Atom(_file)); _localGotVector.push_back(new (_file._alloc) GOTModulePointerAtom(_file)); } @@ -275,6 +305,11 @@ void RelocationPass<ELFT>::perform(std::unique_ptr<MutableFile> &mf) { mf->addAtom(*got); } + for (auto &got : _tlsGotVector) { + got->setOrdinal(ordinal++); + mf->addAtom(*got); + } + for (auto &plt : _pltVector) { DEBUG_WITH_TYPE("MipsGOT", llvm::dbgs() << "[ PLT ] Adding " << plt->name() << "\n"); @@ -326,9 +361,22 @@ void RelocationPass<ELFT>::handleReference(const MipsELFDefinedAtom<ELFT> &atom, case R_MIPS_GPREL32: handleGPRel(atom, ref); break; + case R_MIPS_TLS_DTPREL_HI16: + case R_MIPS_TLS_DTPREL_LO16: + ref.setAddend(ref.addend() - atom.file().getDTPOffset()); + break; case R_MIPS_TLS_TPREL_HI16: case R_MIPS_TLS_TPREL_LO16: - handleTLS(atom, ref); + ref.setAddend(ref.addend() - atom.file().getTPOffset()); + break; + case R_MIPS_TLS_GD: + ref.setTarget(getTLSGdGOTEntry(ref.target())); + break; + case R_MIPS_TLS_LDM: + ref.setTarget(getTLSLdmGOTEntry(ref.target())); + break; + case R_MIPS_TLS_GOTTPREL: + ref.setTarget(getTLSGOTEntry(ref.target())); break; } } @@ -513,15 +561,6 @@ void RelocationPass<ELFT>::handleGPRel(const MipsELFDefinedAtom<ELFT> &atom, } template <typename ELFT> -void RelocationPass<ELFT>::handleTLS(const MipsELFDefinedAtom<ELFT> &atom, - Reference &ref) { - assert((ref.kindValue() == R_MIPS_TLS_TPREL_HI16 || - ref.kindValue() == R_MIPS_TLS_TPREL_LO16) && - "Unexpected kind of relocation"); - ref.setAddend(ref.addend() - atom.file().getTPOffset()); -} - -template <typename ELFT> bool RelocationPass<ELFT>::isLocalCall(const Atom *a) const { Atom::Scope scope; if (auto *da = dyn_cast<DefinedAtom>(a)) @@ -601,6 +640,49 @@ const GOTAtom *RelocationPass<ELFT>::getGlobalGOTEntry(const Atom *a) { return ga; } +template <typename ELFT> +const GOTAtom *RelocationPass<ELFT>::getTLSGOTEntry(const Atom *a) { + auto got = _gotTLSMap.find(a); + if (got != _gotTLSMap.end()) + return got->second; + + auto ga = new (_file._alloc) GOT0Atom(_file); + _gotTLSMap[a] = ga; + + _tlsGotVector.push_back(ga); + ga->addReferenceELF_Mips(R_MIPS_TLS_TPREL32, 0, a, 0); + + return ga; +} + +template <typename ELFT> +const GOTAtom *RelocationPass<ELFT>::getTLSGdGOTEntry(const Atom *a) { + auto got = _gotTLSGdMap.find(a); + if (got != _gotTLSGdMap.end()) + return got->second; + + auto ga = new (_file._alloc) GOTTLSGdAtom(_file); + _gotTLSGdMap[a] = ga; + + _tlsGotVector.push_back(ga); + ga->addReferenceELF_Mips(R_MIPS_TLS_DTPMOD32, 0, a, 0); + ga->addReferenceELF_Mips(R_MIPS_TLS_DTPREL32, 4, a, 0); + + return ga; +} + +template <typename ELFT> +const GOTAtom *RelocationPass<ELFT>::getTLSLdmGOTEntry(const Atom *a) { + if (_gotLDMEntry) + return _gotLDMEntry; + + _gotLDMEntry = new (_file._alloc) GOTTLSGdAtom(_file); + _tlsGotVector.push_back(_gotLDMEntry); + _gotLDMEntry->addReferenceELF_Mips(R_MIPS_TLS_DTPMOD32, 0, _gotLDMEntry, 0); + + return _gotLDMEntry; +} + template <typename ELFT> void RelocationPass<ELFT>::createPLTHeader() { assert(_pltVector.empty() && _gotpltVector.empty()); diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h b/lld/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h index a8ae8b3d11d..05c32b781c5 100644 --- a/lld/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h +++ b/lld/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h @@ -21,21 +21,22 @@ public: MipsGOTSection(const MipsLinkingContext &context) : AtomSection<ELFType>(context, ".got", DefinedAtom::typeGOT, DefinedAtom::permRW_, - MipsTargetLayout<ELFType>::ORDER_GOT) { + MipsTargetLayout<ELFType>::ORDER_GOT), + _hasNonLocal(false), _localCount(0) { this->_flags |= SHF_MIPS_GPREL; this->_align2 = 4; } /// \brief Number of local GOT entries. - std::size_t getLocalCount() const { - return this->_atoms.size() - getGlobalCount(); - } + std::size_t getLocalCount() const { return _localCount; } /// \brief Number of global GOT entries. std::size_t getGlobalCount() const { return _posMap.size(); } /// \brief Does the atom have a global GOT entry? - bool hasGlobalGOTEntry(const Atom *a) const { return _posMap.count(a); } + bool hasGlobalGOTEntry(const Atom *a) const { + return _posMap.count(a) || _tlsMap.count(a); + } /// \brief Compare two atoms accordingly theirs positions in the GOT. bool compare(const Atom *a, const Atom *b) const { @@ -51,24 +52,42 @@ public: const lld::AtomLayout &appendAtom(const Atom *atom) override { const DefinedAtom *da = dyn_cast<DefinedAtom>(atom); - const Atom *ta = nullptr; for (const auto &r : *da) { if (r->kindNamespace() != lld::Reference::KindNamespace::ELF) continue; assert(r->kindArch() == Reference::KindArch::Mips); - if (r->kindValue() == LLD_R_MIPS_GLOBAL_GOT) { - ta = r->target(); - break; + switch (r->kindValue()) { + case LLD_R_MIPS_GLOBAL_GOT: + _hasNonLocal = true; + _posMap[r->target()] = _posMap.size(); + return AtomSection<ELFType>::appendAtom(atom); + case R_MIPS_TLS_TPREL32: + case R_MIPS_TLS_DTPREL32: + _hasNonLocal = true; + _tlsMap[r->target()] = _tlsMap.size(); + return AtomSection<ELFType>::appendAtom(atom); + case R_MIPS_TLS_DTPMOD32: + _hasNonLocal = true; + return AtomSection<ELFType>::appendAtom(atom); } } - if (ta) - _posMap[ta] = _posMap.size(); + if (!_hasNonLocal) + ++_localCount; return AtomSection<ELFType>::appendAtom(atom); } private: + /// \brief True if the GOT contains non-local entries. + bool _hasNonLocal; + + /// \brief Number of local GOT entries. + std::size_t _localCount; + + /// \brief Map TLS Atoms to their GOT entry index. + llvm::DenseMap<const Atom *, std::size_t> _tlsMap; + /// \brief Map Atoms to their GOT entry index. llvm::DenseMap<const Atom *, std::size_t> _posMap; }; diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp b/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp index 1c90031a47b..fc32ba3d398 100644 --- a/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp +++ b/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp @@ -57,6 +57,14 @@ const Registry::KindStrings MipsTargetHandler::kindStrings[] = { LLD_KIND_STRING_ENTRY(R_MIPS_CALL16), LLD_KIND_STRING_ENTRY(R_MIPS_GPREL32), LLD_KIND_STRING_ENTRY(R_MIPS_JALR), + LLD_KIND_STRING_ENTRY(R_MIPS_TLS_DTPMOD32), + LLD_KIND_STRING_ENTRY(R_MIPS_TLS_DTPREL32), + LLD_KIND_STRING_ENTRY(R_MIPS_TLS_GD), + LLD_KIND_STRING_ENTRY(R_MIPS_TLS_LDM), + LLD_KIND_STRING_ENTRY(R_MIPS_TLS_GOTTPREL), + LLD_KIND_STRING_ENTRY(R_MIPS_TLS_TPREL32), + LLD_KIND_STRING_ENTRY(R_MIPS_TLS_DTPREL_HI16), + LLD_KIND_STRING_ENTRY(R_MIPS_TLS_DTPREL_LO16), LLD_KIND_STRING_ENTRY(R_MIPS_TLS_TPREL_HI16), LLD_KIND_STRING_ENTRY(R_MIPS_TLS_TPREL_LO16), LLD_KIND_STRING_ENTRY(R_MIPS_COPY), |

