Index: lib/ReaderWriter/ELF/CMakeLists.txt =================================================================== --- lib/ReaderWriter/ELF/CMakeLists.txt +++ lib/ReaderWriter/ELF/CMakeLists.txt @@ -7,6 +7,7 @@ target_link_libraries(lldELF lldHexagonELFTarget + lldMipsELFTarget lldPPCELFTarget lldPasses lldReaderWriter Index: lib/ReaderWriter/ELF/DefaultLayout.h =================================================================== --- lib/ReaderWriter/ELF/DefaultLayout.h +++ lib/ReaderWriter/ELF/DefaultLayout.h @@ -198,6 +198,14 @@ return iter->second; } + /// \brief Find an output Section given a section name. + const MergedSections *findOutputSection(StringRef name) const { + auto iter = _mergedSectionMap.find(name); + if (iter == _mergedSectionMap.end()) + return nullptr; + return iter->second; + } + /// \brief find a absolute atom given a name AbsoluteAtomIterT findAbsoluteAtom(StringRef name) { return std::find_if(_absoluteAtoms.begin(), _absoluteAtoms.end(), Index: lib/ReaderWriter/ELF/DefaultTargetHandler.h =================================================================== --- lib/ReaderWriter/ELF/DefaultTargetHandler.h +++ lib/ReaderWriter/ELF/DefaultTargetHandler.h @@ -58,6 +58,24 @@ /// \brief allocate Commons, some architectures may move small common /// symbols over to small data, this would also be used void allocateCommons() {} + + /// \brief create dynamic table + LLD_UNIQUE_BUMP_PTR(DynamicTable) createDynamicTable() { + return LLD_UNIQUE_BUMP_PTR(DynamicTable)( + new (_alloc) DynamicTable( + this->_context, ".dynamic", DefaultLayout::ORDER_DYNAMIC)); + } + + /// \brief create dynamic symbol table + LLD_UNIQUE_BUMP_PTR(DynamicSymbolTable) createDynamicSymbolTable() { + return LLD_UNIQUE_BUMP_PTR(DynamicSymbolTable)( + new (_alloc) DynamicSymbolTable( + this->_context, ".dynsym", + DefaultLayout::ORDER_DYNAMIC_SYMBOLS)); + } + +private: + llvm::BumpPtrAllocator _alloc; }; } // end namespace elf } // end namespace lld Index: lib/ReaderWriter/ELF/ELFLinkingContext.cpp =================================================================== --- lib/ReaderWriter/ELF/ELFLinkingContext.cpp +++ lib/ReaderWriter/ELF/ELFLinkingContext.cpp @@ -67,6 +67,8 @@ return llvm::ELF::EM_X86_64; case llvm::Triple::hexagon: return llvm::ELF::EM_HEXAGON; + case llvm::Triple::mipsel: + return llvm::ELF::EM_MIPS; case llvm::Triple::ppc: return llvm::ELF::EM_PPC; default: @@ -124,6 +126,9 @@ case llvm::Triple::hexagon: return std::unique_ptr( new lld::elf::HexagonLinkingContext(triple)); + case llvm::Triple::mipsel: + return std::unique_ptr( + new lld::elf::MipsLinkingContext(triple)); case llvm::Triple::ppc: return std::unique_ptr( new lld::elf::PPCLinkingContext(triple)); Index: lib/ReaderWriter/ELF/Mips/CMakeLists.txt =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/Mips/CMakeLists.txt @@ -0,0 +1,9 @@ +add_lld_library(lldMipsELFTarget + MipsLinkingContext.cpp + MipsRelocationHandler.cpp + MipsTargetHandler.cpp + ) + +target_link_libraries(lldMipsELFTarget + lldCore + ) Index: lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h @@ -0,0 +1,39 @@ +//===- lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h ---------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef LLD_READER_WRITER_ELF_MIPS_LINKING_CONTEXT_H +#define LLD_READER_WRITER_ELF_MIPS_LINKING_CONTEXT_H + +#include "lld/ReaderWriter/ELFLinkingContext.h" + +namespace lld { +namespace elf { + +typedef llvm::object::ELFType Mips32ElELFType; + +template +class MipsTargetLayout; + +class MipsLinkingContext LLVM_FINAL : public ELFLinkingContext { +public: + MipsLinkingContext(llvm::Triple triple); + + MipsTargetLayout &getTargetLayout(); + const MipsTargetLayout &getTargetLayout() const; + + // ELFLinkingContext + virtual bool isLittleEndian() const; + virtual ErrorOr relocKindFromString(StringRef str) const; + virtual ErrorOr stringFromRelocKind(Reference::Kind kind) const; + virtual void addPasses(PassManager &pm); +}; + +} // elf +} // lld + +#endif Index: lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp @@ -0,0 +1,233 @@ +//===- lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp -------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Atoms.h" +#include "MipsLinkingContext.h" +#include "MipsTargetHandler.h" + +#include "llvm/ADT/StringSwitch.h" + +using namespace lld; +using namespace lld::elf; + +namespace { + +const uint8_t mipsGot0AtomContent[] = { + 0x00, 0x00, 0x00, 0x00 // Lazy resolver +}; + +const uint8_t mipsGotModulePointerAtomContent[] = { + 0x00, 0x00, 0x00, 0x80 // Module pointer +}; + +/// \brief Abstract base class represent MIPS GOT entries. +class MipsGOTAtom : public GOTAtom { +public: + MipsGOTAtom(const File &f) : GOTAtom(f, ".got") {} + + virtual Alignment alignment() const { return Alignment(2); } +}; + +/// \brief MIPS GOT entry initialized by zero. +class MipsGOT0Atom : public MipsGOTAtom { +public: + MipsGOT0Atom(const File &f) : MipsGOTAtom(f) {} + + virtual ArrayRef rawContent() const { + return llvm::makeArrayRef(mipsGot0AtomContent); + } +}; + +/// \brief MIPS GOT entry initialized by zero. +class MipsGOTModulePointerAtom : public MipsGOTAtom { +public: + MipsGOTModulePointerAtom(const File &f) : MipsGOTAtom(f) {} + + virtual ArrayRef rawContent() const { + return llvm::makeArrayRef(mipsGotModulePointerAtomContent); + } +}; + +class MipsGOTPassFile : public SimpleFile { +public: + MipsGOTPassFile(const ELFLinkingContext &eti) + : SimpleFile(eti, "MipsGOTPassFile") { + setOrdinal(eti.getNextOrdinalAndIncrement()); + } + + llvm::BumpPtrAllocator _alloc; +}; + +class MipsGOTPass : public Pass { +public: + MipsGOTPass(MipsLinkingContext &context) + : _file(context), + _got0(new (_file._alloc) MipsGOT0Atom(_file)), + _got1(new (_file._alloc) MipsGOTModulePointerAtom(_file)) { + _localGotVector.push_back(_got0); + _localGotVector.push_back(_got1); + } + + virtual void 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); + } + } + +private: + /// \brief Owner of all the Atoms created by this pass. + MipsGOTPassFile _file; + + /// \brief GOT header entries. + GOTAtom *_got0; + GOTAtom *_got1; + + /// \brief Map Atoms to their GOT entries. + llvm::DenseMap _gotMap; + + /// \brief the list of local GOT atoms. + std::vector _localGotVector; + + /// \brief the list of global GOT atoms. + std::vector _globalGotVector; + + /// \brief Handle a specific reference. + void handleReference(const DefinedAtom &atom, const Reference &ref) { + switch (ref.kind()) { + case R_MIPS_GOT16: + case R_MIPS_CALL16: + handleGOT(ref); + break; + } + } + + void handleGOT(const Reference &ref) { + const_cast(ref).setTarget(getEntry(ref.target())); + } + + const GOTAtom *getEntry(const Atom *a) { + auto got = _gotMap.find(a); + if (got != _gotMap.end()) + return got->second; + + const DefinedAtom *da = dyn_cast(a); + bool isLocal = da && da->scope() == Atom::scopeTranslationUnit; + + auto ga = new (_file._alloc) MipsGOT0Atom(_file); + _gotMap[a] = ga; + if (isLocal) + _localGotVector.push_back(ga); + else { + if (da) + ga->addReference(R_MIPS_32, 0, a, 0); + else + ga->addReference(R_MIPS_NONE, 0, a, 0); + _globalGotVector.push_back(ga); + } + + DEBUG_WITH_TYPE("MipsGOT", { + ga->_name = "__got_"; + ga->_name += a->name(); + llvm::dbgs() << "[ GOT ] Create " << (isLocal ? "L " : "G ") << a->name() + << "\n"; + }); + + return ga; + } +}; + +} // end anon namespace + +MipsLinkingContext::MipsLinkingContext(llvm::Triple triple) + : ELFLinkingContext(triple, std::unique_ptr( + new MipsTargetHandler(*this))) {} + +MipsTargetLayout &MipsLinkingContext::getTargetLayout() { + auto &layout = getTargetHandler().targetLayout(); + return static_cast &>(layout); +} + +const MipsTargetLayout & +MipsLinkingContext::getTargetLayout() const { + auto &layout = getTargetHandler().targetLayout(); + return static_cast &>(layout); +} + +bool MipsLinkingContext::isLittleEndian() const { + return Mips32ElELFType::TargetEndianness == llvm::support::little; +} + +#undef LLD_CASE +#define LLD_CASE(name) .Case(#name, llvm::ELF::name) + +ErrorOr +MipsLinkingContext::relocKindFromString(StringRef str) const { + int32_t ret = llvm::StringSwitch(str) + LLD_CASE(R_MIPS_NONE) + LLD_CASE(R_MIPS_32) + LLD_CASE(R_MIPS_HI16) + LLD_CASE(R_MIPS_LO16) + LLD_CASE(R_MIPS_GOT16) + LLD_CASE(R_MIPS_CALL16) + LLD_CASE(R_MIPS_JALR) + .Default(-1); + + if (ret == -1) + return make_error_code(YamlReaderError::illegal_value); + return ret; +} + +#undef LLD_CASE +#define LLD_CASE(name) \ + case llvm::ELF::name: \ + return std::string(#name); + +ErrorOr +MipsLinkingContext::stringFromRelocKind(Reference::Kind kind) const { + switch (kind) { + LLD_CASE(R_MIPS_NONE) + LLD_CASE(R_MIPS_32) + LLD_CASE(R_MIPS_HI16) + LLD_CASE(R_MIPS_LO16) + LLD_CASE(R_MIPS_GOT16) + LLD_CASE(R_MIPS_CALL16) + LLD_CASE(R_MIPS_JALR) + } + + return make_error_code(YamlReaderError::illegal_value); +} + +void MipsLinkingContext::addPasses(PassManager &pm) { + switch (getOutputELFType()) { + case llvm::ELF::ET_DYN: + pm.add(std::unique_ptr(new MipsGOTPass(*this))); + break; + default: + llvm_unreachable("Unhandled output file type"); + } + + ELFLinkingContext::addPasses(pm); +} Index: lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.h =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.h @@ -0,0 +1,50 @@ +//===- lld/ReaderWriter/ELF/Mips/MipsRelocationHandler.h ------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef LLD_READER_WRITER_ELF_MIPS_RELOCATION_HANDLER_H +#define LLD_READER_WRITER_ELF_MIPS_RELOCATION_HANDLER_H + +#include "MipsLinkingContext.h" + +namespace lld { +namespace elf { + +class MipsTargetHandler; + +class MipsTargetRelocationHandler LLVM_FINAL : + public TargetRelocationHandler { +public: + MipsTargetRelocationHandler(const MipsLinkingContext &context, + const MipsTargetHandler &tH); + + virtual error_code applyRelocation(ELFWriter &, + llvm::FileOutputBuffer &, + const lld::AtomLayout &, + const Reference &) const; + +private: + const MipsLinkingContext &_context; + const MipsTargetHandler &_targetHandler; + + typedef std::vector PairedRelocationsT; + typedef std::unordered_map + PairedRelocationMapT; + + mutable PairedRelocationMapT _pairedRelocations; + + void savePairedRelocation(const lld::AtomLayout &atom, + const Reference &ref) const; + void applyPairedRelocations(ELFWriter &writer, llvm::FileOutputBuffer &buf, + const lld::AtomLayout &atom, + int64_t loAddend) const; +}; + +} // elf +} // lld + +#endif Index: lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp @@ -0,0 +1,192 @@ +//===- lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp ----------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MipsTargetHandler.h" +#include "MipsLinkingContext.h" +#include "MipsRelocationHandler.h" + +#include "lld/ReaderWriter/RelocationHelperFunctions.h" + +using namespace lld; +using namespace elf; +using namespace llvm::ELF; + +namespace { + +inline void applyReloc(uint8_t *location, uint32_t result) { + auto target = reinterpret_cast(location); + *target = result | *target; +} + +/// \brief Calculate AHL value combines addends from 'hi' and 'lo' relocations. +inline int64_t calcAHL(int64_t AHI, int64_t ALO) { + AHI &= 0xffff; + ALO &= 0xffff; + return (AHI << 16) + (int16_t)ALO; +} + +/// \brief R_MIPS_32 +/// local/external: word32 S + A (truncate) +void reloc32(uint8_t *location, uint64_t P, uint64_t S, int64_t A) { + uint32_t result = (uint32_t)(S + A); + applyReloc(location, result); +} + +/// \brief R_MIPS_HI16 +/// local/external: hi16 (AHL + S) - (short)(AHL + S) (truncate) +/// _gp_disp : hi16 (AHL + GP - P) - (short)(AHL + GP - P) (verify) +void relocHi16(uint8_t *location, uint64_t P, uint64_t S, int64_t AHL, + uint64_t GP, bool isGPDisp) { + int32_t result = 0; + + if (isGPDisp) + result = (AHL + GP - P) - (int16_t)(AHL + GP - P); + else + result = (AHL + S) - (int16_t)(AHL + S); + + result = lld::scatterBits(result >> 16, 0xffff); + applyReloc(location, result); +} + +/// \brief R_MIPS_LO16 +/// local/external: lo16 AHL + S (truncate) +/// _gp_disp : lo16 AHL + GP - P + 4 (verify) +void relocLo16(uint8_t *location, uint64_t P, uint64_t S, int64_t AHL, + uint64_t GP, bool isGPDisp) { + int32_t result = 0; + + if (isGPDisp) + result = AHL + GP - P + 4; + else + result = AHL + S; + + result = lld::scatterBits(result, 0xffff); + applyReloc(location, result); +} + +/// \brief R_MIPS_GOT16 +/// local/external: rel16 G (verify) +void relocGOT16(uint8_t *location, uint64_t P, uint64_t S, int64_t AHL, + uint64_t GP) { + // FIXME (simon): for local sym put high 16 bit of AHL to the GOT + int32_t G = (int32_t)(S - GP); + int32_t result = lld::scatterBits(G, 0xffff); + applyReloc(location, result); +} + +/// \brief R_MIPS_CALL16 +/// external: rel16 G (verify) +void relocCall16(uint8_t *location, uint64_t P, uint64_t S, int64_t A, + uint64_t GP) { + int32_t G = (int32_t)(S - GP); + int32_t result = lld::scatterBits(G, 0xffff); + applyReloc(location, result); +} + +} // end anon namespace + +MipsTargetRelocationHandler::MipsTargetRelocationHandler( + const MipsLinkingContext &context, + const MipsTargetHandler &tH) + : _context(context), + _targetHandler(tH) +{} + +void +MipsTargetRelocationHandler::savePairedRelocation(const lld::AtomLayout &atom, + const Reference &ref) const { + auto pi = _pairedRelocations.find(&atom); + if (pi == _pairedRelocations.end()) + pi = _pairedRelocations.emplace(&atom, PairedRelocationsT()).first; + + pi->second.push_back(&ref); +} + +void MipsTargetRelocationHandler::applyPairedRelocations( + ELFWriter &writer, llvm::FileOutputBuffer &buf, + const lld::AtomLayout &atom, int64_t loAddend) const { + auto pi = _pairedRelocations.find(&atom); + if (pi == _pairedRelocations.end()) + return; + + for (auto ri : pi->second) { + uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset; + uint8_t *location = atomContent + ri->offsetInAtom(); + uint64_t targetVAddress = writer.addressOfAtom(ri->target()); + uint64_t relocVAddress = atom._virtualAddr + ri->offsetInAtom(); + + int64_t ahl = calcAHL(ri->addend(), loAddend); + + switch (ri->kind()) { + case R_MIPS_HI16: + relocHi16(location, relocVAddress, targetVAddress, ahl, + _targetHandler.getGPDispSymAddr(), + ri->target()->name() == "_gp_disp"); + break; + case R_MIPS_GOT16: + relocGOT16(location, relocVAddress, targetVAddress, ahl, + _targetHandler.getGPDispSymAddr()); + break; + default: + llvm_unreachable("Unknown type of paired relocation."); + } + } + + _pairedRelocations.erase(pi); +} + +error_code MipsTargetRelocationHandler::applyRelocation( + ELFWriter &writer, llvm::FileOutputBuffer &buf, + const lld::AtomLayout &atom, const Reference &ref) const { + uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset; + uint8_t *location = atomContent + ref.offsetInAtom(); + uint64_t targetVAddress = writer.addressOfAtom(ref.target()); + uint64_t relocVAddress = atom._virtualAddr + ref.offsetInAtom(); + + switch (ref.kind()) { + case R_MIPS_NONE: + break; + case R_MIPS_32: + reloc32(location, relocVAddress, targetVAddress, ref.addend()); + break; + case R_MIPS_HI16: + savePairedRelocation(atom, ref); + break; + case R_MIPS_LO16: + relocLo16(location, relocVAddress, targetVAddress, calcAHL(0, ref.addend()), + _targetHandler.getGPDispSymAddr(), + ref.target()->name() == "_gp_disp"); + applyPairedRelocations(writer, buf, atom, ref.addend()); + break; + case R_MIPS_GOT16: + savePairedRelocation(atom, ref); + break; + case R_MIPS_CALL16: + relocCall16(location, relocVAddress, targetVAddress, ref.addend(), + _targetHandler.getGPDispSymAddr()); + break; + case R_MIPS_JALR: + // We do not do JALR optimization now. + break; + case lld::Reference::kindLayoutAfter: + case lld::Reference::kindLayoutBefore: + case lld::Reference::kindInGroup: + break; + default : { + std::string str; + llvm::raw_string_ostream s(str); + auto name = _context.stringFromRelocKind(ref.kind()); + s << "Unhandled relocation: " + << (name ? *name : "") << " (" << ref.kind() << ")"; + llvm_unreachable(s.str().c_str()); + } + } + + return error_code::success(); +} Index: lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h @@ -0,0 +1,83 @@ +//===- lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h ----------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef LLD_READER_WRITER_ELF_MIPS_SECTION_CHUNKS_H +#define LLD_READER_WRITER_ELF_MIPS_SECTION_CHUNKS_H + +namespace lld { +namespace elf { + +template class MipsTargetLayout; +class MipsLinkingContext; + +/// \brief Handle Mips GOT section +template +class MipsGOTSection : public AtomSection { +public: + MipsGOTSection(const MipsLinkingContext &context) + : AtomSection(context, ".got", DefinedAtom::typeGOT, + DefinedAtom::permRW_, + MipsTargetLayout::ORDER_GOT), + _globalCount(0) { + this->_flags |= SHF_MIPS_GPREL; + this->_align2 = 4; + } + + /// \brief Number of local GOT entries. + std::size_t getLocalCount() const { + return this->_atoms.size() - _globalCount; + } + + /// \brief Number of global GOT entries. + std::size_t getGlobalCount() const { + return _globalCount; + } + + /// \brief Compare two atoms accordingly theirs positions in the GOT. + bool compare(const Atom *a, const Atom *b) const { + auto ia = _posMap.find(a); + auto ib = _posMap.find(b); + + if (ia != _posMap.end() && ib != _posMap.end()) + return ia->second < ib->second; + + return ia == _posMap.end() && ib != _posMap.end(); + } + + virtual const lld::AtomLayout &appendAtom(const Atom *atom) { + const DefinedAtom *da = dyn_cast(atom); + + const Atom *ta = nullptr; + for (const auto &r : *da) { + if (r->kind() == llvm::ELF::R_MIPS_32 || + r->kind() == llvm::ELF::R_MIPS_NONE) { + ta = r->target(); + break; + } + } + + if (ta) { + _posMap[ta] = _posMap.size(); + ++_globalCount; + } + + return AtomSection::appendAtom(atom); + } + +private: + /// \brief Number of global GOT entries. + std::size_t _globalCount; + + /// \brief Map Atoms to their GOT entry index. + llvm::DenseMap _posMap; +}; + +} // elf +} // lld + +#endif Index: lib/ReaderWriter/ELF/Mips/MipsTarget.h =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/Mips/MipsTarget.h @@ -0,0 +1,10 @@ +//===- lib/ReaderWriter/ELF/Mips/MipsTarget.h -----------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MipsLinkingContext.h" Index: lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h @@ -0,0 +1,76 @@ +//===- lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h ----------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef LLD_READER_WRITER_ELF_MIPS_TARGET_HANDLER_H +#define LLD_READER_WRITER_ELF_MIPS_TARGET_HANDLER_H + +#include "DefaultTargetHandler.h" +#include "MipsLinkingContext.h" +#include "MipsRelocationHandler.h" +#include "MipsSectionChunks.h" +#include "TargetLayout.h" + +namespace lld { +namespace elf { + +/// \brief TargetLayout for Mips +template +class MipsTargetLayout LLVM_FINAL : public TargetLayout { +public: + MipsTargetLayout(const MipsLinkingContext &ctx) + : TargetLayout(ctx), + _gotSection(new (_alloc) MipsGOTSection(ctx)) {} + + const MipsGOTSection &getGOTSection() const { + return *_gotSection; + } + + virtual AtomSection * + createSection(StringRef name, int32_t type, + DefinedAtom::ContentPermissions permissions, + Layout::SectionOrder order) { + if (type == DefinedAtom::typeGOT) + return _gotSection; + return DefaultLayout::createSection(name, type, permissions, + order); + } + +private: + llvm::BumpPtrAllocator _alloc; + MipsGOTSection *_gotSection; +}; + +/// \brief TargetHandler for Mips +class MipsTargetHandler LLVM_FINAL + : public DefaultTargetHandler { +public: + MipsTargetHandler(MipsLinkingContext &targetInfo); + + uint64_t getGPDispSymAddr() const; + + virtual MipsTargetLayout &targetLayout(); + virtual const MipsTargetRelocationHandler &getRelocationHandler() const; + virtual LLD_UNIQUE_BUMP_PTR(DynamicTable) + createDynamicTable(); + virtual LLD_UNIQUE_BUMP_PTR(DynamicSymbolTable) + createDynamicSymbolTable(); + virtual bool createImplicitFiles(std::vector> &result); + virtual void finalizeSymbolValues(); + +private: + llvm::BumpPtrAllocator _alloc; + MipsTargetLayout _targetLayout; + MipsTargetRelocationHandler _relocationHandler; + AtomLayout *_gotSymAtom; + AtomLayout *_gpDispSymAtom; +}; + +} // end namespace elf +} // end namespace lld + +#endif Index: lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp @@ -0,0 +1,179 @@ +//===- lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp --------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "File.h" +#include "MipsLinkingContext.h" +#include "MipsTargetHandler.h" + +using namespace lld; +using namespace elf; + +namespace { + +class MipsDynamicSymbolTable : public DynamicSymbolTable { +public: + MipsDynamicSymbolTable(const MipsLinkingContext &context) + : DynamicSymbolTable( + context, ".dynsym", + DefaultLayout::ORDER_DYNAMIC_SYMBOLS), + _layout(context.getTargetLayout()) {} + + virtual void sortSymbols() { + std::stable_sort(_symbolTable.begin(), _symbolTable.end(), + [this](const SymbolEntry & A, const SymbolEntry & B) { + if (A._symbol.getBinding() != STB_GLOBAL && + B._symbol.getBinding() != STB_GLOBAL) + return A._symbol.getBinding() < B._symbol.getBinding(); + + return _layout.getGOTSection().compare(A._atom, B._atom); + }); + } + +private: + const MipsTargetLayout &_layout; +}; + +class MipsDynamicTable : public DynamicTable { +public: + MipsDynamicTable(const MipsLinkingContext &context) + : DynamicTable( + context, ".dynamic", + DefaultLayout::ORDER_DYNAMIC), + _layout(context.getTargetLayout()) {} + + virtual void createDefaultEntries() { + DynamicTable::createDefaultEntries(); + + Elf_Dyn dyn; + + // Version id for the Runtime Linker Interface. + dyn.d_un.d_val = 1; + dyn.d_tag = DT_MIPS_RLD_VERSION; + addEntry(dyn); + + // MIPS flags. + dyn.d_un.d_val = RHF_NOTPOT; + dyn.d_tag = DT_MIPS_FLAGS; + addEntry(dyn); + + // The base address of the segment. + dyn.d_un.d_ptr = 0; + dyn.d_tag = DT_MIPS_BASE_ADDRESS; + addEntry(dyn); + + // Number of local global offset table entries. + dyn.d_un.d_val = 0; + dyn.d_tag = DT_MIPS_LOCAL_GOTNO; + _dt_localgot = addEntry(dyn); + + // Number of entries in the .dynsym section. + dyn.d_un.d_val = 0; + dyn.d_tag = DT_MIPS_SYMTABNO; + _dt_symtabno = addEntry(dyn); + + // The index of the first dynamic symbol table entry that corresponds + // to an entry in the global offset table. + dyn.d_un.d_val = 0; + dyn.d_tag = DT_MIPS_GOTSYM; + _dt_gotsym = addEntry(dyn); + + // Address of the .got section. + dyn.d_un.d_val = 0; + dyn.d_tag = DT_PLTGOT; + _dt_pltgot = addEntry(dyn); + } + + virtual void updateDynamicTable() { + DynamicTable::updateDynamicTable(); + + auto &got = _layout.getGOTSection(); + + _entries[_dt_symtabno].d_un.d_val = getSymbolTable()->size(); + _entries[_dt_gotsym].d_un.d_val = + getSymbolTable()->size() - got.getGlobalCount(); + _entries[_dt_localgot].d_un.d_val = got.getLocalCount(); + _entries[_dt_pltgot].d_un.d_ptr = + _layout.findOutputSection(".got")->virtualAddr(); + } + +private: + const MipsTargetLayout &_layout; + + std::size_t _dt_symtabno; + std::size_t _dt_localgot; + std::size_t _dt_gotsym; + std::size_t _dt_pltgot; +}; + +} + +MipsTargetHandler::MipsTargetHandler(MipsLinkingContext &context) + : DefaultTargetHandler(context), + _targetLayout(context), + _relocationHandler(context, *this) +{} + +uint64_t MipsTargetHandler::getGPDispSymAddr() const { + return _gpDispSymAtom ? _gpDispSymAtom->_virtualAddr : 0; +} + +MipsTargetLayout &MipsTargetHandler::targetLayout() { + return _targetLayout; +} + +const MipsTargetRelocationHandler & +MipsTargetHandler::getRelocationHandler() const { + return _relocationHandler; +} + +LLD_UNIQUE_BUMP_PTR(DynamicTable) +MipsTargetHandler::createDynamicTable() { + return LLD_UNIQUE_BUMP_PTR(DynamicTable)( + new (_alloc) MipsDynamicTable( + static_cast(_context))); +} + +LLD_UNIQUE_BUMP_PTR(DynamicSymbolTable) +MipsTargetHandler::createDynamicSymbolTable() { + return LLD_UNIQUE_BUMP_PTR(DynamicSymbolTable)( + new (_alloc) MipsDynamicSymbolTable( + static_cast(_context))); +} + +bool MipsTargetHandler::createImplicitFiles( + std::vector> &result) { + typedef CRuntimeFile RFile; + auto file = std::unique_ptr(new RFile(_context, "MIPS runtime file")); + + if (_context.isDynamic()) { + file->addAbsoluteAtom("_GLOBAL_OFFSET_TABLE_"); + file->addAbsoluteAtom("_gp_disp"); + } + result.push_back(std::move(file)); + return true; +} + +void MipsTargetHandler::finalizeSymbolValues() { + DefaultTargetHandler::finalizeSymbolValues(); + + if (_context.isDynamic()) { + auto gotSection = _targetLayout.findOutputSection(".got"); + + auto gotAtomIter = _targetLayout.findAbsoluteAtom("_GLOBAL_OFFSET_TABLE_"); + assert(gotAtomIter != _targetLayout.absoluteAtoms().end()); + _gotSymAtom = (*gotAtomIter); + _gotSymAtom->_virtualAddr = gotSection ? gotSection->virtualAddr() : 0; + + auto gpDispAtomIter = _targetLayout.findAbsoluteAtom("_gp_disp"); + assert(gpDispAtomIter != _targetLayout.absoluteAtoms().end()); + _gpDispSymAtom = (*gpDispAtomIter); + _gpDispSymAtom->_virtualAddr = + gotSection ? gotSection->virtualAddr() + 0x7FF0 : 0; + } +} Index: lib/ReaderWriter/ELF/OutputELFWriter.h =================================================================== --- lib/ReaderWriter/ELF/OutputELFWriter.h +++ lib/ReaderWriter/ELF/OutputELFWriter.h @@ -286,12 +286,10 @@ } if (_context.isDynamic()) { - _dynamicTable.reset(new (_alloc) DynamicTable( - _context, ".dynamic", DefaultLayout::ORDER_DYNAMIC)); + _dynamicTable = std::move(_targetHandler.createDynamicTable()); _dynamicStringTable.reset(new (_alloc) StringTable( _context, ".dynstr", DefaultLayout::ORDER_DYNAMIC_STRINGS, true)); - _dynamicSymbolTable.reset(new (_alloc) DynamicSymbolTable( - _context, ".dynsym", DefaultLayout::ORDER_DYNAMIC_SYMBOLS)); + _dynamicSymbolTable = std::move(_targetHandler.createDynamicSymbolTable()); _hashTable.reset(new (_alloc) HashSection( _context, ".hash", DefaultLayout::ORDER_HASH)); // Set the hash table in the dynamic symbol table so that the entries in the Index: lib/ReaderWriter/ELF/SectionChunks.h =================================================================== --- lib/ReaderWriter/ELF/SectionChunks.h +++ lib/ReaderWriter/ELF/SectionChunks.h @@ -607,19 +607,9 @@ class SymbolTable : public Section { typedef typename llvm::object::ELFDataTypeTypedefHelper::Elf_Addr Elf_Addr; +public: typedef llvm::object::Elf_Sym_Impl Elf_Sym; - struct SymbolEntry { - SymbolEntry(const Atom *a, const Elf_Sym &sym, - const lld::AtomLayout *layout) - : _atom(a), _atomLayout(layout), _symbol(sym) {} - - const Atom *_atom; - const lld::AtomLayout *_atomLayout; - Elf_Sym _symbol; - }; - -public: SymbolTable(const ELFLinkingContext &context, const char *str, int32_t order); /// \brief set the number of entries that would exist in the symbol @@ -629,6 +619,11 @@ _stringSection->setNumEntries(numEntries); } + /// \brief return number of entries + std::size_t size() const { + return _symbolTable.size(); + } + void addSymbol(const Atom *atom, int32_t sectionIndex, uint64_t addr = 0, const lld::AtomLayout *layout = nullptr); @@ -669,6 +664,16 @@ StringTable *getStringTable() const { return _stringSection; } protected: + struct SymbolEntry { + SymbolEntry(const Atom *a, const Elf_Sym &sym, + const lld::AtomLayout *layout) + : _atom(a), _atomLayout(layout), _symbol(sym) {} + + const Atom *_atom; + const lld::AtomLayout *_atomLayout; + Elf_Sym _symbol; + }; + llvm::BumpPtrAllocator _symbolAllocate; StringTable *_stringSection; std::vector _symbolTable; @@ -982,10 +987,10 @@ template class HashSection; template class DynamicTable : public Section { +public: typedef llvm::object::Elf_Dyn_Impl Elf_Dyn; typedef std::vector EntriesT; -public: DynamicTable(const ELFLinkingContext &context, StringRef str, int32_t order) : Section(context, str) { this->setOrder(order); @@ -1020,7 +1025,7 @@ std::memcpy(dest, _entries.data(), this->_fsize); } - void createDefaultEntries() { + virtual void createDefaultEntries() { Elf_Dyn dyn; dyn.d_un.d_val = 0; @@ -1074,9 +1079,13 @@ _dynamicSymbolTable = dynsym; } + const DynamicSymbolTable *getSymbolTable() const { + return _dynamicSymbolTable; + } + void setHashTable(HashSection *hsh) { _hashTable = hsh; } - void updateDynamicTable() { + virtual void updateDynamicTable() { StringTable *dynamicStringTable = _dynamicSymbolTable->getStringTable(); _entries[_dt_hash].d_un.d_val = _hashTable->virtualAddr(); @@ -1104,8 +1113,10 @@ } } -private: +protected: EntriesT _entries; + +private: std::size_t _dt_hash; std::size_t _dt_strtab; std::size_t _dt_symtab; Index: lib/ReaderWriter/ELF/TargetHandler.h =================================================================== --- lib/ReaderWriter/ELF/TargetHandler.h +++ lib/ReaderWriter/ELF/TargetHandler.h @@ -20,6 +20,7 @@ #include "lld/Core/LLVM.h" #include "lld/Core/LinkingContext.h" +#include "lld/Core/STDExtras.h" #include "lld/ReaderWriter/ELFLinkingContext.h" #include "llvm/ADT/Hashing.h" @@ -30,6 +31,8 @@ namespace lld { namespace elf { +template class DynamicTable; +template class DynamicSymbolTable; template class ELFDefinedAtom; template class ELFReference; class ELFWriter; @@ -117,6 +120,13 @@ /// symbols over to small data, this would also be used virtual void allocateCommons() = 0; + /// \brief create dynamic table + virtual LLD_UNIQUE_BUMP_PTR(DynamicTable) createDynamicTable() = 0; + + /// \brief create dynamic symbol table + virtual LLD_UNIQUE_BUMP_PTR(DynamicSymbolTable) + createDynamicSymbolTable() = 0; + protected: const ELFLinkingContext &_context; }; Index: lib/ReaderWriter/ELF/Targets.h =================================================================== --- lib/ReaderWriter/ELF/Targets.h +++ lib/ReaderWriter/ELF/Targets.h @@ -11,6 +11,7 @@ #define LLD_READER_WRITER_ELF_TARGETS_H #include "Hexagon/HexagonTarget.h" +#include "Mips/MipsTarget.h" #include "PPC/PPCTarget.h" #include "X86/X86Target.h" #include "X86_64/X86_64Target.h" Index: test/elf/Mips/Inputs/dynobj.c =================================================================== --- /dev/null +++ test/elf/Mips/Inputs/dynobj.c @@ -0,0 +1,14 @@ +// clang -O0 -EL -fPIC -target mipsel-linux-gnu -c dynobj.c -o dynobj.o +int xyz(const char *); +int abc(const char *); + +int bar(void) +{ + return 1; +} + +int foo(void) +{ + bar(); + return xyz("str1") + abc("str2"); +} Index: test/elf/Mips/dynlib-dynamic.test =================================================================== --- /dev/null +++ test/elf/Mips/dynlib-dynamic.test @@ -0,0 +1,27 @@ +# Check MIPS specific tags in the dynamic table. +RUN: lld -flavor gnu -target mipsel -shared --noinhibit-exec \ +RUN: -o %t %p/Inputs/dynobj.o +RUN: llvm-readobj -dynamic-table %t | FileCheck %s + +CHECK: Format: ELF32-mips +CHECK: Arch: mipsel +CHECK: AddressSize: 32bit +CHECK: LoadName: +CHECK: DynamicSection [ (15 entries) +CHECK: Tag Type Name/Value +CHECK: 0x00000004 HASH 0xE0 +CHECK: 0x00000005 STRTAB 0x158 +CHECK: 0x00000006 SYMTAB 0x108 +CHECK: 0x0000000A STRSZ 17 (bytes) +CHECK: 0x0000000B SYMENT 16 (bytes) +CHECK: 0x0000001A FINI_ARRAY 0x0 +CHECK: 0x0000001C FINI_ARRAYSZ 0 (bytes) +CHECK: 0x70000001 MIPS_RLD_VERSION 1 +CHECK: 0x70000005 MIPS_FLAGS 0x2 +CHECK: 0x70000006 MIPS_BASE_ADDRESS 0x0 +CHECK: 0x7000000A MIPS_LOCAL_GOTNO 4 +CHECK: 0x70000011 MIPS_SYMTABNO 5 +CHECK: 0x70000013 MIPS_GOTSYM 0x2 +CHECK: 0x00000003 PLTGOT 0x1000 +CHECK: 0x00000000 NULL 0x0 +CHECK: ] Index: test/elf/Mips/dynlib-dynsym.test =================================================================== --- /dev/null +++ test/elf/Mips/dynlib-dynsym.test @@ -0,0 +1,118 @@ +# Check sorting of .dynsym content accordingly to .got section. +RUN: lld -flavor gnu -target mipsel -shared --noinhibit-exec \ +RUN: -o %t %p/Inputs/dynobj.o +RUN: llvm-readobj -dyn-symbols %t | FileCheck -check-prefix=CHECK-DYN %s + +RUN: lld -flavor gnu -target mipsel -shared --noinhibit-exec \ +RUN: --output-filetype=yaml -o %t %p/Inputs/dynobj.o +RUN: FileCheck -check-prefix=CHECK-GOT %s < %t + +CHECK-DYN: Format: ELF32-mips +CHECK-DYN: Arch: mipsel +CHECK-DYN: AddressSize: 32bit +CHECK-DYN: LoadName: +CHECK-DYN: DynamicSymbols [ +CHECK-DYN: Symbol { +CHECK-DYN: Name: @ (0) +CHECK-DYN: Value: 0x0 +CHECK-DYN: Size: 0 +CHECK-DYN: Binding: Local (0x0) +CHECK-DYN: Type: None (0x0) +CHECK-DYN: Other: 0 +CHECK-DYN: Section: (0x0) +CHECK-DYN: } +CHECK-DYN: Symbol { +CHECK-DYN: Name: foo@ (5) +CHECK-DYN: Value: 0x194 +CHECK-DYN: Size: 156 +CHECK-DYN: Binding: Global (0x1) +CHECK-DYN: Type: Function (0x2) +CHECK-DYN: Other: 0 +CHECK-DYN: Section: .text (0x4) +CHECK-DYN: } +CHECK-DYN: Symbol { +CHECK-DYN: Name: bar@ (1) +CHECK-DYN: Value: 0x170 +CHECK-DYN: Size: 36 +CHECK-DYN: Binding: Global (0x1) +CHECK-DYN: Type: Function (0x2) +CHECK-DYN: Other: 0 +CHECK-DYN: Section: .text (0x4) +CHECK-DYN: } +CHECK-DYN: Symbol { +CHECK-DYN: Name: xyz@ (9) +CHECK-DYN: Value: 0x0 +CHECK-DYN: Size: 0 +CHECK-DYN: Binding: Global (0x1) +CHECK-DYN: Type: None (0x0) +CHECK-DYN: Other: 0 +CHECK-DYN: Section: (0x0) +CHECK-DYN: } +CHECK-DYN: Symbol { +CHECK-DYN: Name: abc@ (13) +CHECK-DYN: Value: 0x0 +CHECK-DYN: Size: 0 +CHECK-DYN: Binding: Global (0x1) +CHECK-DYN: Type: None (0x0) +CHECK-DYN: Other: 0 +CHECK-DYN: Section: (0x0) +CHECK-DYN: } +CHECK-DYN: ] + +CHECK-GOT: - type: got +CHECK-GOT: content: [ 00, 00, 00, 00 ] +CHECK-GOT: alignment: 2^2 +CHECK-GOT: section-choice: custom-required +CHECK-GOT: section-name: .got +CHECK-GOT: permissions: rw- +CHECK-GOT: - type: got +CHECK-GOT: content: [ 00, 00, 00, 80 ] +CHECK-GOT: alignment: 2^2 +CHECK-GOT: section-choice: custom-required +CHECK-GOT: section-name: .got +CHECK-GOT: permissions: rw- +CHECK-GOT: - ref-name: L004 +CHECK-GOT: type: got +CHECK-GOT: content: [ 00, 00, 00, 00 ] +CHECK-GOT: alignment: 2^2 +CHECK-GOT: section-choice: custom-required +CHECK-GOT: section-name: .got +CHECK-GOT: permissions: rw- +CHECK-GOT: - ref-name: L006 +CHECK-GOT: type: got +CHECK-GOT: content: [ 00, 00, 00, 00 ] +CHECK-GOT: alignment: 2^2 +CHECK-GOT: section-choice: custom-required +CHECK-GOT: section-name: .got +CHECK-GOT: permissions: rw- +CHECK-GOT: - ref-name: L003 +CHECK-GOT: type: got +CHECK-GOT: content: [ 00, 00, 00, 00 ] +CHECK-GOT: alignment: 2^2 +CHECK-GOT: section-choice: custom-required +CHECK-GOT: section-name: .got +CHECK-GOT: permissions: rw- +CHECK-GOT: references: +CHECK-GOT: - kind: R_MIPS_32 +CHECK-GOT: offset: 0 +CHECK-GOT: target: bar +CHECK-GOT: - ref-name: L005 +CHECK-GOT: type: got +CHECK-GOT: content: [ 00, 00, 00, 00 ] +CHECK-GOT: alignment: 2^2 +CHECK-GOT: section-choice: custom-required +CHECK-GOT: section-name: .got +CHECK-GOT: permissions: rw- +CHECK-GOT: - ref-name: L007 +CHECK-GOT: type: got +CHECK-GOT: content: [ 00, 00, 00, 00 ] +CHECK-GOT: alignment: 2^2 +CHECK-GOT: section-choice: custom-required +CHECK-GOT: section-name: .got +CHECK-GOT: permissions: rw- +CHECK-GOT: - ref-name: L002 +CHECK-GOT: alignment: 2^4 +CHECK-GOT: references: +CHECK-GOT: - kind: layout-after +CHECK-GOT: offset: 0 +CHECK-GOT: target: bar Index: test/elf/Mips/dynlib-fileheader.test =================================================================== --- /dev/null +++ test/elf/Mips/dynlib-fileheader.test @@ -0,0 +1,33 @@ +RUN: lld -flavor gnu -target mipsel -shared --noinhibit-exec \ +RUN: -o %t %p/Inputs/dynobj.o +RUN: llvm-readobj -file-headers %t | FileCheck %s + +CHECK: Format: ELF32-mips +CHECK: Arch: mipsel +CHECK: AddressSize: 32bit +CHECK: LoadName: +CHECK: ElfHeader { +CHECK: Ident { +CHECK: Magic: (7F 45 4C 46) +CHECK: Class: 32-bit (0x1) +CHECK: DataEncoding: LittleEndian (0x1) +CHECK: FileVersion: 1 +CHECK: OS/ABI: SystemV (0x0) +CHECK: ABIVersion: 0 +CHECK: Unused: (00 00 00 00 00 00 00) +CHECK: } +CHECK: Type: SharedObject (0x3) +CHECK: Machine: EM_MIPS (0x8) +CHECK: Version: 1 +CHECK: Entry: 0x170 +CHECK: ProgramHeaderOffset: 0x34 +CHECK: SectionHeaderOffset: 0x21C8 +CHECK: Flags [ (0x0) +CHECK: ] +CHECK: HeaderSize: 52 +CHECK: ProgramHeaderEntrySize: 32 +CHECK: ProgramHeaderCount: 5 +CHECK: SectionHeaderEntrySize: 40 +CHECK: SectionHeaderCount: 16 +CHECK: StringTableSectionIndex: 13 +CHECK:} Index: test/elf/Mips/dynlib-gotsym.test =================================================================== --- /dev/null +++ test/elf/Mips/dynlib-gotsym.test @@ -0,0 +1,11 @@ +# Check _gp_disp and GOT_OFFSET_TABLE value +RUN: lld -flavor gnu -target mipsel -shared --noinhibit-exec \ +RUN: -o %t %p/Inputs/dynobj.o +RUN: llvm-objdump -section-headers -t %t | FileCheck %s + +CHECK: Idx Name Size Address Type +CHECK: 7 .got 0000001c 0000000000001000 DATA + +CHECK: SYMBOL TABLE: +CHECK: 00001000 g *ABS* 00000000 _GLOBAL_OFFSET_TABLE_ +CHECK: 00008ff0 g *ABS* 00000000 _gp_disp Index: test/elf/phdr.test =================================================================== --- test/elf/phdr.test +++ test/elf/phdr.test @@ -92,7 +92,7 @@ I386-NEXT: Flags [ (0x4) I386-NEXT: PF_R (0x4) I386-NEXT: ] -I386-NEXT: Alignment: 4 +I386-NEXT: Alignment: 2 I386-NEXT: } X86_64: LOAD off 0x0000000000000000