diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp index c636d4bbff2d..10f470fcccbf 100644 --- a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp +++ b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp @@ -114,53 +114,9 @@ public: class RelocationPass : public Pass { public: - RelocationPass(MipsLinkingContext &context) - : _context(context), _file(context) { - _localGotVector.push_back(new (_file._alloc) GOT0Atom(_file)); - _localGotVector.push_back(new (_file._alloc) GOTModulePointerAtom(_file)); - } + RelocationPass(MipsLinkingContext &context); - void perform(std::unique_ptr &mf) override { - // Process all references. - for (const auto &atom : mf->defined()) - for (const auto &ref : *atom) - handleReference(*atom, *ref); - - uint64_t ordinal = 0; - - for (auto &got : _localGotVector) { - DEBUG_WITH_TYPE("MipsGOT", llvm::dbgs() << "[ GOT ] Adding L " - << got->name() << "\n"); - got->setOrdinal(ordinal++); - mf->addAtom(*got); - } - - for (auto &got : _globalGotVector) { - DEBUG_WITH_TYPE("MipsGOT", llvm::dbgs() << "[ GOT ] Adding G " - << got->name() << "\n"); - got->setOrdinal(ordinal++); - mf->addAtom(*got); - } - - for (auto &plt : _pltVector) { - DEBUG_WITH_TYPE("MipsGOT", llvm::dbgs() << "[ PLT ] Adding " - << plt->name() << "\n"); - plt->setOrdinal(ordinal++); - mf->addAtom(*plt); - } - - for (auto &gotplt : _gotpltVector) { - DEBUG_WITH_TYPE("MipsGOT", llvm::dbgs() << "[ GOTPLT ] Adding " - << gotplt->name() << "\n"); - gotplt->setOrdinal(ordinal++); - mf->addAtom(*gotplt); - } - - for (auto obj : _objectVector) { - obj->setOrdinal(ordinal++); - mf->addAtom(*obj); - } - } + void perform(std::unique_ptr &mf) override; private: /// \brief Reference to the linking context. @@ -194,187 +150,249 @@ private: std::vector _objectVector; /// \brief Handle a specific reference. - void handleReference(const DefinedAtom &atom, const Reference &ref) { - if (ref.kindNamespace() != lld::Reference::KindNamespace::ELF) - return; - assert(ref.kindArch() == Reference::KindArch::Mips); - switch (ref.kindValue()) { - case R_MIPS_32: - case R_MIPS_HI16: - case R_MIPS_LO16: - // FIXME (simon): Handle dynamic/static linking differently. - handlePlain(ref); - break; - case R_MIPS_26: - handlePLT(ref); - break; - case R_MIPS_GOT16: - case R_MIPS_CALL16: - handleGOT(ref); - break; - } - } + void handleReference(const DefinedAtom &atom, const Reference &ref); - bool isLocal(const Atom *a) { - if (auto *da = dyn_cast(a)) - return da->scope() == Atom::scopeTranslationUnit; - return false; - } + void handlePlain(const Reference &ref); + void handlePLT(const Reference &ref); + void handleGOT(const Reference &ref); - void handlePlain(const Reference &ref) { - if (!ref.target()) - return; - auto sla = dyn_cast(ref.target()); - if (sla && sla->type() == SharedLibraryAtom::Type::Data) - const_cast(ref).setTarget(getObjectEntry(sla)); - } + const GOTAtom *getGOTEntry(const Atom *a); + const PLTAtom *getPLTEntry(const Atom *a); + const ObjectAtom *getObjectEntry(const SharedLibraryAtom *a); - void handlePLT(const Reference &ref) { - if (ref.kindValue() == R_MIPS_26 && !isLocal(ref.target())) - const_cast(ref).setKindValue(LLD_R_MIPS_GLOBAL_26); - - if (isa(ref.target())) - const_cast(ref).setTarget(getPLTEntry(ref.target())); - } - - void handleGOT(const Reference &ref) { - if (ref.kindValue() == R_MIPS_GOT16 && !isLocal(ref.target())) - const_cast(ref).setKindValue(LLD_R_MIPS_GLOBAL_GOT16); - - const_cast(ref).setTarget(getGOTEntry(ref.target())); - } - - bool requireLocalGOT(const Atom *a) { - Atom::Scope scope; - if (auto *da = dyn_cast(a)) - scope = da->scope(); - else if (auto *aa = dyn_cast(a)) - scope = aa->scope(); - else - return false; - - // Local and hidden symbols must be local. - if (scope == Atom::scopeTranslationUnit || - scope == Atom::scopeLinkageUnit) - return true; - - // External symbol defined in an executable file requires a local GOT entry. - if (_context.getOutputELFType() == llvm::ELF::ET_EXEC) - return true; - - return false; - } - - const GOTAtom *getGOTEntry(const Atom *a) { - auto got = _gotMap.find(a); - if (got != _gotMap.end()) - return got->second; - - auto ga = new (_file._alloc) GOT0Atom(_file); - _gotMap[a] = ga; - - bool localGOT = requireLocalGOT(a); - - if (localGOT) - _localGotVector.push_back(ga); - else { - _globalGotVector.push_back(ga); - ga->addReferenceELF_Mips(LLD_R_MIPS_GLOBAL_GOT, 0, a, 0); - } - - if (const DefinedAtom *da = dyn_cast(a)) - ga->addReferenceELF_Mips(R_MIPS_32, 0, da, 0); - - DEBUG_WITH_TYPE("MipsGOT", { - ga->_name = "__got_"; - ga->_name += a->name(); - llvm::dbgs() << "[ GOT ] Create " << (localGOT ? "L " : "G ") << a->name() - << "\n"; - }); - - return ga; - } - - void createPLTHeader() { - assert(_pltVector.empty() && _gotpltVector.empty()); - - auto pa = new (_file._alloc) PLT0Atom(_file); - _pltVector.push_back(pa); - - auto ga0 = new (_file._alloc) GOTPLTAtom(_file); - _gotpltVector.push_back(ga0); - auto ga1 = new (_file._alloc) GOTPLTAtom(_file); - _gotpltVector.push_back(ga1); - - // Setup reference to fixup the PLT0 entry. - pa->addReferenceELF_Mips(LLD_R_MIPS_HI16, 0, ga0, 0); - pa->addReferenceELF_Mips(LLD_R_MIPS_LO16, 4, ga0, 0); - pa->addReferenceELF_Mips(LLD_R_MIPS_LO16, 8, ga0, 0); - - DEBUG_WITH_TYPE("MipsGOT", { - pa->_name = "__plt0"; - llvm::dbgs() << "[ PLT ] Create PLT0\n"; - ga0->_name = "__gotplt0"; - llvm::dbgs() << "[ GOTPLT ] Create GOTPLT0\n"; - ga1->_name = "__gotplt1"; - llvm::dbgs() << "[ GOTPLT ] Create GOTPLT1\n"; - }); - } - - const PLTAtom *getPLTEntry(const Atom *a) { - auto plt = _pltMap.find(a); - if (plt != _pltMap.end()) - return plt->second; - - if (_pltVector.empty()) - createPLTHeader(); - - auto pa = new (_file._alloc) PLTAAtom(_file); - _pltMap[a] = pa; - _pltVector.push_back(pa); - - auto ga = new (_file._alloc) GOTPLTAtom(_file); - _gotpltVector.push_back(ga); - - // Setup reference to fixup the PLT entry. - pa->addReferenceELF_Mips(LLD_R_MIPS_HI16, 0, ga, 0); - pa->addReferenceELF_Mips(LLD_R_MIPS_LO16, 4, ga, 0); - pa->addReferenceELF_Mips(LLD_R_MIPS_LO16, 12, ga, 0); - - // Setup reference to assign initial value to the .got.plt entry. - ga->addReferenceELF_Mips(R_MIPS_32, 0, _pltVector.front(), 0); - // Create dynamic relocation to adjust the .got.plt entry at runtime. - ga->addReferenceELF_Mips(R_MIPS_JUMP_SLOT, 0, a, 0); - - DEBUG_WITH_TYPE("MipsGOT", { - pa->_name = "__plt_"; - pa->_name += a->name(); - llvm::dbgs() << "[ PLT ] Create " << a->name() << "\n"; - ga->_name = "__got_plt_"; - ga->_name += a->name(); - llvm::dbgs() << "[ GOTPLT ] Create " << a->name() << "\n"; - }); - - return pa; - } - - const ObjectAtom *getObjectEntry(const SharedLibraryAtom *a) { - auto obj = _objectMap.find(a); - if (obj != _objectMap.end()) - return obj->second; - - auto oa = new (_file._alloc) ObjectAtom(_file); - oa->addReferenceELF_Mips(R_MIPS_COPY, 0, oa, 0); - oa->_name = a->name(); - oa->_size = a->size(); - - _objectMap[a] = oa; - _objectVector.push_back(oa); - - return oa; - } + bool isLocal(const Atom *a); + bool requireLocalGOT(const Atom *a); + void createPLTHeader(); }; +RelocationPass::RelocationPass(MipsLinkingContext &context) + : _context(context), _file(context) { + _localGotVector.push_back(new (_file._alloc) GOT0Atom(_file)); + _localGotVector.push_back(new (_file._alloc) GOTModulePointerAtom(_file)); +} + +void RelocationPass::perform(std::unique_ptr &mf) { + // Process all references. + for (const auto &atom : mf->defined()) + for (const auto &ref : *atom) + handleReference(*atom, *ref); + + uint64_t ordinal = 0; + + for (auto &got : _localGotVector) { + DEBUG_WITH_TYPE("MipsGOT", llvm::dbgs() << "[ GOT ] Adding L " + << got->name() << "\n"); + got->setOrdinal(ordinal++); + mf->addAtom(*got); + } + + for (auto &got : _globalGotVector) { + DEBUG_WITH_TYPE("MipsGOT", llvm::dbgs() << "[ GOT ] Adding G " + << got->name() << "\n"); + got->setOrdinal(ordinal++); + mf->addAtom(*got); + } + + for (auto &plt : _pltVector) { + DEBUG_WITH_TYPE("MipsGOT", llvm::dbgs() << "[ PLT ] Adding " << plt->name() + << "\n"); + plt->setOrdinal(ordinal++); + mf->addAtom(*plt); + } + + for (auto &gotplt : _gotpltVector) { + DEBUG_WITH_TYPE("MipsGOT", llvm::dbgs() << "[ GOTPLT ] Adding " + << gotplt->name() << "\n"); + gotplt->setOrdinal(ordinal++); + mf->addAtom(*gotplt); + } + + for (auto obj : _objectVector) { + obj->setOrdinal(ordinal++); + mf->addAtom(*obj); + } +} + +void RelocationPass::handleReference(const DefinedAtom &atom, + const Reference &ref) { + if (ref.kindNamespace() != lld::Reference::KindNamespace::ELF) + return; + assert(ref.kindArch() == Reference::KindArch::Mips); + switch (ref.kindValue()) { + case R_MIPS_32: + case R_MIPS_HI16: + case R_MIPS_LO16: + // FIXME (simon): Handle dynamic/static linking differently. + handlePlain(ref); + break; + case R_MIPS_26: + handlePLT(ref); + break; + case R_MIPS_GOT16: + case R_MIPS_CALL16: + handleGOT(ref); + break; + } +} + +bool RelocationPass::isLocal(const Atom *a) { + if (auto *da = dyn_cast(a)) + return da->scope() == Atom::scopeTranslationUnit; + return false; +} + +void RelocationPass::handlePlain(const Reference &ref) { + if (!ref.target()) + return; + auto sla = dyn_cast(ref.target()); + if (sla && sla->type() == SharedLibraryAtom::Type::Data) + const_cast(ref).setTarget(getObjectEntry(sla)); +} + +void RelocationPass::handlePLT(const Reference &ref) { + if (ref.kindValue() == R_MIPS_26 && !isLocal(ref.target())) + const_cast(ref).setKindValue(LLD_R_MIPS_GLOBAL_26); + + if (isa(ref.target())) + const_cast(ref).setTarget(getPLTEntry(ref.target())); +} + +void RelocationPass::handleGOT(const Reference &ref) { + if (ref.kindValue() == R_MIPS_GOT16 && !isLocal(ref.target())) + const_cast(ref).setKindValue(LLD_R_MIPS_GLOBAL_GOT16); + + const_cast(ref).setTarget(getGOTEntry(ref.target())); +} + +bool RelocationPass::requireLocalGOT(const Atom *a) { + Atom::Scope scope; + if (auto *da = dyn_cast(a)) + scope = da->scope(); + else if (auto *aa = dyn_cast(a)) + scope = aa->scope(); + else + return false; + + // Local and hidden symbols must be local. + if (scope == Atom::scopeTranslationUnit || scope == Atom::scopeLinkageUnit) + return true; + + // External symbol defined in an executable file requires a local GOT entry. + if (_context.getOutputELFType() == llvm::ELF::ET_EXEC) + return true; + + return false; +} + +const GOTAtom *RelocationPass::getGOTEntry(const Atom *a) { + auto got = _gotMap.find(a); + if (got != _gotMap.end()) + return got->second; + + auto ga = new (_file._alloc) GOT0Atom(_file); + _gotMap[a] = ga; + + bool localGOT = requireLocalGOT(a); + + if (localGOT) + _localGotVector.push_back(ga); + else { + _globalGotVector.push_back(ga); + ga->addReferenceELF_Mips(LLD_R_MIPS_GLOBAL_GOT, 0, a, 0); + } + + if (const DefinedAtom *da = dyn_cast(a)) + ga->addReferenceELF_Mips(R_MIPS_32, 0, da, 0); + + DEBUG_WITH_TYPE("MipsGOT", { + ga->_name = "__got_"; + ga->_name += a->name(); + llvm::dbgs() << "[ GOT ] Create " << (localGOT ? "L " : "G ") << a->name() + << "\n"; + }); + + return ga; +} + +void RelocationPass::createPLTHeader() { + assert(_pltVector.empty() && _gotpltVector.empty()); + + auto pa = new (_file._alloc) PLT0Atom(_file); + _pltVector.push_back(pa); + + auto ga0 = new (_file._alloc) GOTPLTAtom(_file); + _gotpltVector.push_back(ga0); + auto ga1 = new (_file._alloc) GOTPLTAtom(_file); + _gotpltVector.push_back(ga1); + + // Setup reference to fixup the PLT0 entry. + pa->addReferenceELF_Mips(LLD_R_MIPS_HI16, 0, ga0, 0); + pa->addReferenceELF_Mips(LLD_R_MIPS_LO16, 4, ga0, 0); + pa->addReferenceELF_Mips(LLD_R_MIPS_LO16, 8, ga0, 0); + + DEBUG_WITH_TYPE("MipsGOT", { + pa->_name = "__plt0"; + llvm::dbgs() << "[ PLT ] Create PLT0\n"; + ga0->_name = "__gotplt0"; + llvm::dbgs() << "[ GOTPLT ] Create GOTPLT0\n"; + ga1->_name = "__gotplt1"; + llvm::dbgs() << "[ GOTPLT ] Create GOTPLT1\n"; + }); +} + +const PLTAtom *RelocationPass::getPLTEntry(const Atom *a) { + auto plt = _pltMap.find(a); + if (plt != _pltMap.end()) + return plt->second; + + if (_pltVector.empty()) + createPLTHeader(); + + auto pa = new (_file._alloc) PLTAAtom(_file); + _pltMap[a] = pa; + _pltVector.push_back(pa); + + auto ga = new (_file._alloc) GOTPLTAtom(_file); + _gotpltVector.push_back(ga); + + // Setup reference to fixup the PLT entry. + pa->addReferenceELF_Mips(LLD_R_MIPS_HI16, 0, ga, 0); + pa->addReferenceELF_Mips(LLD_R_MIPS_LO16, 4, ga, 0); + pa->addReferenceELF_Mips(LLD_R_MIPS_LO16, 12, ga, 0); + + // Setup reference to assign initial value to the .got.plt entry. + ga->addReferenceELF_Mips(R_MIPS_32, 0, _pltVector.front(), 0); + // Create dynamic relocation to adjust the .got.plt entry at runtime. + ga->addReferenceELF_Mips(R_MIPS_JUMP_SLOT, 0, a, 0); + + DEBUG_WITH_TYPE("MipsGOT", { + pa->_name = "__plt_"; + pa->_name += a->name(); + llvm::dbgs() << "[ PLT ] Create " << a->name() << "\n"; + ga->_name = "__got_plt_"; + ga->_name += a->name(); + llvm::dbgs() << "[ GOTPLT ] Create " << a->name() << "\n"; + }); + + return pa; +} + +const ObjectAtom *RelocationPass::getObjectEntry(const SharedLibraryAtom *a) { + auto obj = _objectMap.find(a); + if (obj != _objectMap.end()) + return obj->second; + + auto oa = new (_file._alloc) ObjectAtom(_file); + oa->addReferenceELF_Mips(R_MIPS_COPY, 0, oa, 0); + oa->_name = a->name(); + oa->_size = a->size(); + + _objectMap[a] = oa; + _objectVector.push_back(oa); + + return oa; +} + } // end anon namespace std::unique_ptr