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/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(llvm::BumpPtrAllocator &alloc, + StringRef name, int32_t order) { + return LLD_UNIQUE_BUMP_PTR(DynamicTable)( + new (alloc) DynamicTable(TargetHandler::_context, + name, order)); + } + + /// \brief create dynamic symbol table + LLD_UNIQUE_BUMP_PTR(DynamicSymbolTable) + createDynamicSymbolTable(llvm::BumpPtrAllocator &alloc, + StringRef name, int32_t order) { + return LLD_UNIQUE_BUMP_PTR(DynamicSymbolTable)( + new (alloc) DynamicSymbolTable(TargetHandler::_context, + name, order)); + } }; } // end namespace elf } // end namespace lld Index: lib/ReaderWriter/ELF/ELFLinkingContext.cpp =================================================================== --- lib/ReaderWriter/ELF/ELFLinkingContext.cpp +++ lib/ReaderWriter/ELF/ELFLinkingContext.cpp @@ -68,6 +68,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: @@ -126,6 +128,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,10 @@ +add_lld_library(lldMipsELFTarget + MipsGOT.cpp + MipsLinkingContext.cpp + MipsRelocationHandler.cpp + MipsTargetHandler.cpp + ) + +target_link_libraries(lldMipsELFTarget + lldCore + ) Index: lib/ReaderWriter/ELF/Mips/MipsELFTypes.h =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/Mips/MipsELFTypes.h @@ -0,0 +1,22 @@ +//===- lld/ReaderWriter/ELF/Mips/MipsELFTypes.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_ELF_TYPES_H +#define LLD_READER_WRITER_ELF_MIPS_ELF_TYPES_H + +#include "llvm/Object/ELFTypes.h" + +namespace lld { +namespace elf { + +typedef llvm::object::ELFType MipsELFType; + +} // elf +} // lld + +#endif Index: lib/ReaderWriter/ELF/Mips/MipsGOT.h =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/Mips/MipsGOT.h @@ -0,0 +1,68 @@ +//===- lib/ReaderWriter/ELF/Mips/MipsGOT.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_GOT_H +#define LLD_READER_WRITER_ELF_MIPS_GOT_H + +#include "lld/ReaderWriter/Simple.h" + +#include "llvm/ADT/DenseMap.h" + +namespace lld { +namespace elf { + +class GOTAtom; +class MipsLinkingContext; + +class MipsGOT { +public: + MipsGOT(const MipsLinkingContext &context); + + /// \brief Find or create a new GOT entry for the specified atom. + const GOTAtom *getEntry(const Atom *a); + + /// \brief Number of local GOT entries. + std::size_t getLocalCount() const; + + /// \brief Number of global GOT entries. + std::size_t getGlobalCount() const; + + /// \brief Add allocated GOT entries to the file. + void addAtoms(MutableFile &mf); + + /// \brief Compare two atoms accordingly theirs positions in the GOT. + bool compare(const Atom *a, const Atom *b) const; + +private: + /// \brief Allocator used for GOT entries creation. + llvm::BumpPtrAllocator _alloc; + + /// \brief file to hold GOT entries. + SimpleFile _file; + + /// \brief GOT header entries. + GOTAtom *_got0; + GOTAtom *_got1; + + /// \brief Map Atoms to their GOT entries. + llvm::DenseMap _gotMap; + + /// \brief Map Atoms to their GOT entry index. + llvm::DenseMap _posMap; + + /// \brief the list of local GOT atoms. + std::vector _localGotVector; + + /// \brief the list of global GOT atoms. + std::vector _globalGotVector; +}; + +} // elf +} // lld + +#endif Index: lib/ReaderWriter/ELF/Mips/MipsGOT.cpp =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/Mips/MipsGOT.cpp @@ -0,0 +1,135 @@ +//===- lib/ReaderWriter/ELF/Mips/MipsGOT.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 "MipsGOT.h" +#include "MipsLinkingContext.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); + } +}; + +} + +MipsGOT::MipsGOT(const MipsLinkingContext &context) + : _file(context, "MipsGOTPassFile"), + _got0(new (_alloc) MipsGOT0Atom(_file)), + _got1(new (_alloc) MipsGOTModulePointerAtom(_file)) +{} + +const GOTAtom *MipsGOT::getEntry(const Atom *a) { + auto got = _gotMap.find(a); + if (got != _gotMap.end()) + return got->second; + + const DefinedAtom *da = dyn_cast(a); + auto isLocal = da && da->scope() == Atom::scopeTranslationUnit; + + auto ga = new (_alloc) MipsGOT0Atom(_file); + _gotMap[a] = ga; + if (isLocal) + _localGotVector.push_back(ga); + else { + _globalGotVector.push_back(ga); + _posMap[a] = _globalGotVector.size() - 1; + } +#ifndef NDEBUG + ga->_name = "__got_"; + ga->_name += a->name(); + DEBUG_WITH_TYPE("GOT", llvm::dbgs() << "[ GOT ] Create " + << (isLocal ? "L " : "G ") + << a->name() << "\n"); +#endif + return ga; +} + +std::size_t MipsGOT::getLocalCount() const { + return 2 + _localGotVector.size(); +} + +std::size_t MipsGOT::getGlobalCount() const { + return _globalGotVector.size(); +} + +void MipsGOT::addAtoms(MutableFile &mf) { + uint64_t ordinal = 0; + +#ifndef NDEBUG + DEBUG_WITH_TYPE("GOT", llvm::dbgs() << "[ GOT ] Adding GOT header\n"); +#endif + _got0->setOrdinal(ordinal++); + _got1->setOrdinal(ordinal++); + mf.addAtom(*_got0); + mf.addAtom(*_got1); + + for (auto &got : _localGotVector) { +#ifndef NDEBUG + DEBUG_WITH_TYPE("GOT", llvm::dbgs() << "[ GOT ] Adding L " + << got->name() << "\n"); +#endif + got->setOrdinal(ordinal++); + mf.addAtom(*got); + } + + for (auto &got : _globalGotVector) { +#ifndef NDEBUG + DEBUG_WITH_TYPE("GOT", llvm::dbgs() << "[ GOT ] Adding G " + << got->name() << "\n"); +#endif + got->setOrdinal(ordinal++); + mf.addAtom(*got); + } +} + +bool MipsGOT::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(); +} Index: lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h @@ -0,0 +1,45 @@ +//===- 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 "MipsGOT.h" + +#include "lld/ReaderWriter/ELFLinkingContext.h" + +namespace lld { +namespace elf { + +class MipsLinkingContext LLVM_FINAL : public ELFLinkingContext { +public: + MipsLinkingContext(llvm::Triple triple); + + /// \brief Number of local GOT entries. + std::size_t getLocalGOTCount() const; + + /// \brief Number of global GOT entries. + std::size_t getGlobalGOTCount() const; + + /// \brief Compare two atoms accordingly theirs positions in the GOT. + bool compareGOT(const Atom *a, const Atom *b) const; + + // ELFLinkingContext + virtual bool isLittleEndian() const; + virtual ErrorOr relocKindFromString(StringRef str) const; + virtual ErrorOr stringFromRelocKind(Reference::Kind kind) const; + virtual void addPasses(PassManager &pm); + +private: + MipsGOT _got; +}; + +} // elf +} // lld + +#endif Index: lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp @@ -0,0 +1,124 @@ +//===- 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 "MipsGOT.h" +#include "MipsLinkingContext.h" +#include "MipsTargetHandler.h" + +#include "llvm/ADT/StringSwitch.h" + +using namespace lld; +using namespace lld::elf; + +namespace { + +class MipsGOTPass : public Pass { +public: + MipsGOTPass(MipsGOT &got) : _got(got) {} + +private: + /// \brief GOT handler. + MipsGOT &_got; + + virtual void perform(std::unique_ptr &mf) { + // Process all references. + for (const auto &atom : mf->defined()) + for (const auto &ref : *atom) + handleReference(*atom, *ref); + + _got.addAtoms(*mf); + } + + /// \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; + } + } + + error_code handleGOT(const Reference &ref) { + const_cast(ref).setTarget(_got.getEntry(ref.target())); + return error_code::success(); + } +}; + +} // end anon namespace + +MipsLinkingContext::MipsLinkingContext(llvm::Triple triple) + : ELFLinkingContext(triple, std::unique_ptr( + new MipsTargetHandler(*this))), + _got(*this) +{} + +std::size_t MipsLinkingContext::getLocalGOTCount() const { + return _got.getLocalCount(); +} + +std::size_t MipsLinkingContext::getGlobalGOTCount() const { + return _got.getGlobalCount(); +} + +bool MipsLinkingContext::compareGOT(const Atom *a, const Atom *b) const { + return _got.compare(a, b); +} + +bool MipsLinkingContext::isLittleEndian() const { + return MipsELFType::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) { + if (isDynamic()) + pm.add(std::unique_ptr(new MipsGOTPass(_got))); + + ELFLinkingContext::addPasses(pm); +} Index: lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.h =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.h @@ -0,0 +1,52 @@ +//===- 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 "MipsELFTypes.h" + +namespace lld { +namespace elf { + +class MipsLinkingContext; +class MipsTargetHandler; + +class MipsTargetRelocationHandler LLVM_FINAL : + public TargetRelocationHandler { +public: + MipsTargetRelocationHandler(const MipsLinkingContext &context, + const MipsTargetHandler &tH); + +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; + +private: + virtual error_code applyRelocation(ELFWriter &, + llvm::FileOutputBuffer &, + const lld::AtomLayout &, + const Reference &) const; +}; + +} // elf +} // lld + +#endif Index: lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp @@ -0,0 +1,193 @@ +//===- 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 { + +#define APPLY_RELOC(result) \ + *reinterpret_cast(location) = \ + result | \ + (uint32_t) * reinterpret_cast(location); + +// V - verify +// T - truncate +// AHL is (AHI << 16) + (short)ALO + +/// \brief R_MIPS_32 +/// local/external: T-word32 S + A +void reloc32(uint8_t *location, uint64_t P, uint64_t S, int64_t A) { + uint32_t result = (uint32_t)(S + A); + APPLY_RELOC(result); +} + +/// \brief R_MIPS_HI16 +/// local/external: T-hi16 ((AHL + S) - (short)(AHL + S)) >> 16 +/// _gp_disp : V-hi16 ((AHL + GP - P) - (short)(AHL + GP - P)) >> 16 +void relocHi16(uint8_t *location, uint64_t P, uint64_t S, int64_t A, + uint64_t GOT, bool isGPDisp) { + int32_t AHL = A; + + int32_t result = 0; + if (isGPDisp) + result = ((AHL + GOT - P) - (int16_t)(AHL + GOT - P)) >> 16; + else + result = ((AHL + S) - (int16_t)(AHL + S)) >> 16; + + result = lld::scatterBits(result, 0xffff); + APPLY_RELOC(result); +} + +/// \brief R_MIPS_LO16 +/// local/external: T-lo16 AHL + S +/// _gp_disp : V-lo16 AHL + GP - P + 4 +void relocLo16(uint8_t *location, uint64_t P, uint64_t S, int64_t A, + uint64_t GOT, bool isGPDisp) { + int32_t AHL = A & 0xffff; + + int32_t result = 0; + if (isGPDisp) + result = AHL + GOT - P + 4; + else + result = AHL + S; + + result = lld::scatterBits(result, 0xffff); + APPLY_RELOC(result); +} + +/// \brief R_MIPS_GOT16 +/// local : V-rel16 G (calculate AHL and put high 16 bit to GOT) +/// external: V-rel16 G +void relocGOT16(uint8_t *location, uint64_t P, uint64_t S, int64_t A, + uint64_t GOT) { + int32_t result = (int32_t)(S - GOT); + + result = lld::scatterBits(result, 0xffff); + APPLY_RELOC(result); +} + +/// \brief R_MIPS_CALL16 +/// external: V-rel16 G +void relocCall16(uint8_t *location, uint64_t P, uint64_t S, int64_t A, + uint64_t GOT) { + int32_t result = (int32_t)(S - GOT); + result = lld::scatterBits(result, 0xffff); + APPLY_RELOC(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 addend = ((ri->addend() & 0xffff) << 16) + (int16_t)loAddend; + + switch (ri->kind()) { + case R_MIPS_HI16: + relocHi16(location, relocVAddress, targetVAddress, addend, + _targetHandler.getGPDispSymAddr(), + ri->target()->name() == "_gp_disp"); + break; + case R_MIPS_GOT16: + relocGOT16(location, relocVAddress, targetVAddress, addend, + _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, 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() << ")"; + s.flush(); + llvm_unreachable(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,34 @@ +//===- 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) { + this->_flags |= SHF_MIPS_GPREL; + this->_align2 = 16; + } +}; + +} // 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 "MipsRelocationHandler.h" +#include "MipsSectionChunks.h" +#include "MipsELFTypes.h" +#include "TargetLayout.h" + +namespace lld { +namespace elf { + +class MipsLinkingContext; + +/// \brief TargetLayout for Mips +template +class MipsTargetLayout LLVM_FINAL : public TargetLayout { +public: + MipsTargetLayout(const MipsLinkingContext &hti) + : TargetLayout(hti), + _gotSection(new (_alloc) MipsGOTSection(hti)) + {} + +private: + llvm::BumpPtrAllocator _alloc; + MipsGOTSection *_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); + } +}; + +/// \brief TargetHandler for Mips +class MipsTargetHandler LLVM_FINAL : public DefaultTargetHandler { +public: + MipsTargetHandler(MipsLinkingContext &targetInfo); + + uint64_t getGPDispSymAddr() const; + +private: + virtual MipsTargetLayout &targetLayout(); + virtual const MipsTargetRelocationHandler &getRelocationHandler() const; + virtual LLD_UNIQUE_BUMP_PTR(DynamicTable) + createDynamicTable(llvm::BumpPtrAllocator &alloc, + StringRef name, int32_t order); + virtual LLD_UNIQUE_BUMP_PTR(DynamicSymbolTable) + createDynamicSymbolTable(llvm::BumpPtrAllocator &alloc, + StringRef name, int32_t order); + virtual bool createImplicitFiles(std::vector> &result); + virtual void finalizeSymbolValues(); + +private: + 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,175 @@ +//===- 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 ELFLinkingContext &context, StringRef str, + int32_t order) + : DynamicSymbolTable(context, str, order) + {} + +private: + 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(); + + const MipsLinkingContext &ctx = + static_cast(_context); + return ctx.compareGOT(A._atom, B._atom); + }); + } +}; + +class MipsDynamicTable : public DynamicTable { +public: + MipsDynamicTable(const ELFLinkingContext &context, StringRef str, + int32_t order) + : DynamicTable(context, str, order) {} + +private: + std::size_t _dt_symtabno; + std::size_t _dt_localgot; + std::size_t _dt_gotsym; + std::size_t _dt_pltgot; + + 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(); + + const MipsLinkingContext &ctx = + static_cast(_context); + + auto &layout = _context.getTargetHandler().targetLayout(); + + getEntry(_dt_symtabno).d_un.d_val = getSymbolTable()->size(); + getEntry(_dt_gotsym).d_un.d_val = + getSymbolTable()->size() - ctx.getGlobalGOTCount(); + getEntry(_dt_localgot).d_un.d_val = ctx.getLocalGOTCount(); + getEntry(_dt_pltgot).d_un.d_ptr = + layout.findOutputSection(".got")->virtualAddr(); + } +}; + +} + +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(llvm::BumpPtrAllocator &alloc, + StringRef name, int32_t order) { + return LLD_UNIQUE_BUMP_PTR(DynamicTable)( + new (alloc) MipsDynamicTable(_context, name, order)); +} + +LLD_UNIQUE_BUMP_PTR(DynamicSymbolTable) +MipsTargetHandler::createDynamicSymbolTable(llvm::BumpPtrAllocator &alloc, + StringRef name, int32_t order) { + return LLD_UNIQUE_BUMP_PTR(DynamicSymbolTable)( + new (alloc) MipsDynamicSymbolTable(_context, name, order)); +} + +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_"); + _gotSymAtom = (*gotAtomIter); + _gotSymAtom->_virtualAddr = gotSection ? gotSection->virtualAddr() : 0; + + auto gpDispAtomIter = _targetLayout.findAbsoluteAtom("_gp_disp"); + _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,13 @@ } if (_context.isDynamic()) { - _dynamicTable.reset(new (_alloc) DynamicTable( - _context, ".dynamic", DefaultLayout::ORDER_DYNAMIC)); + _dynamicTable = std::move( + _targetHandler.createDynamicTable(_alloc, ".dynamic", + DefaultLayout::ORDER_DYNAMIC)); _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( + _alloc, ".dynsym", DefaultLayout::ORDER_DYNAMIC_SYMBOLS)); _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,6 +607,7 @@ /// \brief The SymbolTable class represents the symbol table in a ELF file template class SymbolTable : public Section { +protected: typedef typename llvm::object::ELFDataTypeTypedefHelper::Elf_Addr Elf_Addr; typedef llvm::object::Elf_Sym_Impl Elf_Sym; @@ -622,7 +623,7 @@ }; public: - SymbolTable(const ELFLinkingContext &context, const char *str, int32_t order); + SymbolTable(const ELFLinkingContext &context, StringRef str, int32_t order); /// \brief set the number of entries that would exist in the symbol /// table for the current link @@ -631,6 +632,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); @@ -679,7 +685,7 @@ /// ELF Symbol Table template SymbolTable::SymbolTable(const ELFLinkingContext &context, - const char *str, int32_t order) + StringRef str, int32_t order) : Section(context, str) { this->setOrder(order); Elf_Sym symbol; @@ -861,7 +867,7 @@ template class DynamicSymbolTable : public SymbolTable { public: - DynamicSymbolTable(const ELFLinkingContext &context, const char *str, + DynamicSymbolTable(const ELFLinkingContext &context, StringRef str, int32_t order) : SymbolTable(context, str, order), _hashTable(nullptr) { this->_type = SHT_DYNSYM; @@ -984,6 +990,7 @@ template class HashSection; template class DynamicTable : public Section { +protected: typedef llvm::object::Elf_Dyn_Impl Elf_Dyn; typedef std::vector EntriesT; @@ -1011,6 +1018,11 @@ return _entries.size() - 1; } + /// \returns an entry by the index + Elf_Dyn &getEntry(std::size_t entry) { + return _entries[entry]; + } + void write(ELFWriter *writer, llvm::FileOutputBuffer &buffer) { uint8_t *chunkBuffer = buffer.getBufferStart(); uint8_t *dest = chunkBuffer + this->fileOffset(); @@ -1022,7 +1034,7 @@ std::memcpy(dest, _entries.data(), this->_fsize); } - void createDefaultEntries() { + virtual void createDefaultEntries() { Elf_Dyn dyn; dyn.d_un.d_val = 0; @@ -1076,9 +1088,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(); 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,16 @@ /// 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(llvm::BumpPtrAllocator &alloc, + StringRef name, int32_t order) = 0; + + /// \brief create dynamic symbol table + virtual LLD_UNIQUE_BUMP_PTR(DynamicSymbolTable) + createDynamicSymbolTable(llvm::BumpPtrAllocator &alloc, + StringRef name, int32_t order) = 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: lib/ReaderWriter/ELF/X86/X86TargetHandler.h =================================================================== --- lib/ReaderWriter/ELF/X86/X86TargetHandler.h +++ lib/ReaderWriter/ELF/X86/X86TargetHandler.h @@ -15,7 +15,7 @@ namespace lld { namespace elf { -typedef llvm::object::ELFType X86ELFType; +typedef llvm::object::ELFType X86ELFType; class X86LinkingContext; class X86TargetRelocationHandler LLVM_FINAL Index: test/elf/Mips/Inputs/dynobj.c =================================================================== --- /dev/null +++ test/elf/Mips/Inputs/dynobj.c @@ -0,0 +1,8 @@ +// clang -O0 -EL -fPIC -target mipsel-linux-gnu -c dynobj.c -o dynobj.o +int xyz(const char *); +int abc(const char *); + +int foo(void) +{ + 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 0x144 +CHECK: 0x00000006 SYMTAB 0x104 +CHECK: 0x0000000A STRSZ 13 (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 4 +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,92 @@ +# 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@ (1) +CHECK-DYN: Value: 0x160 +CHECK-DYN: Size: 128 +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@ (5) +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@ (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: ] + +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: - name: '__got_$.str' +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: - name: '__got_$.str1' +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: - name: __got_xyz +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: - name: __got_abc +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- 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: 0x160 +CHECK: ProgramHeaderOffset: 0x34 +CHECK: SectionHeaderOffset: 0x2200 +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 00000018 0000000000001000 DATA + +CHECK: SYMBOL TABLE: +CHECK: 00001000 g *ABS* 00000000 _GLOBAL_OFFSET_TABLE_ +CHECK: 00008ff0 g *ABS* 00000000 _gp_disp Index: test/elf/Mips/dynlib-text-sec.test =================================================================== --- /dev/null +++ test/elf/Mips/dynlib-text-sec.test @@ -0,0 +1,14 @@ +# Check .text section content +RUN: lld -flavor gnu -target mipsel -shared --noinhibit-exec \ +RUN: -o %t %p/Inputs/dynobj.o +RUN: llvm-objdump -s %t | FileCheck %s + +CHECK: Contents of section .text: +CHECK-NEXT: 0160 0100023c 908e4224 e0ffbd27 1c00bfaf ...<..B$...'.... +CHECK-NEXT: 0170 1800beaf 21f0a003 21105900 1880598c ....!...!.Y...Y. +CHECK-NEXT: 0180 e0012427 2080598c 21e04000 1400c2af ..$' .Y.!.@..... +CHECK-NEXT: 0190 09f82003 00000000 1400c48f 1c80998c .. ............. +CHECK-NEXT: 01a0 e5012427 1400d98f 2480398f 1400dc8f ..$'....$.9..... +CHECK-NEXT: 01b0 1000c2af 09f82003 00000000 1000c48f ...... ......... +CHECK-NEXT: 01c0 21108200 21e8c003 1800be8f 1c00bf8f !...!........... +CHECK-NEXT: 01d0 2000bd27 0800e003 00000000 00000000 ..'............