From 1729e123589b7ad22ba173ba03160b077f4eb410 Mon Sep 17 00:00:00 2001 From: Shankar Easwaran Date: Sun, 3 Mar 2013 07:34:56 +0000 Subject: [PATCH] [ELF][Hexagon] add initial changes to add GOT/PLT llvm-svn: 176415 --- .../ReaderWriter/ELF/Hexagon/HexagonDynamicAtoms.h | 82 +++++++++++ .../ELF/Hexagon/HexagonRelocationHandler.cpp | 15 ++ .../ELF/Hexagon/HexagonTargetHandler.cpp | 156 +++++++++++++++++++++ .../ReaderWriter/ELF/Hexagon/HexagonTargetInfo.cpp | 1 + .../ReaderWriter/ELF/Hexagon/HexagonTargetInfo.h | 23 +++ lld/test/elf/Hexagon/Inputs/use-shared.hexagon | Bin 0 -> 872 bytes lld/test/elf/Hexagon/hexagon-plt-setup.test | 15 ++ 7 files changed, 292 insertions(+) create mode 100644 lld/lib/ReaderWriter/ELF/Hexagon/HexagonDynamicAtoms.h create mode 100644 lld/test/elf/Hexagon/Inputs/use-shared.hexagon create mode 100644 lld/test/elf/Hexagon/hexagon-plt-setup.test diff --git a/lld/lib/ReaderWriter/ELF/Hexagon/HexagonDynamicAtoms.h b/lld/lib/ReaderWriter/ELF/Hexagon/HexagonDynamicAtoms.h new file mode 100644 index 0000000..00f0f82 --- /dev/null +++ b/lld/lib/ReaderWriter/ELF/Hexagon/HexagonDynamicAtoms.h @@ -0,0 +1,82 @@ +//===- lib/ReaderWriter/ELF/Hexagon/HexagonDynamicAtoms.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_HEXAGON_DYNAMIC_ATOMS_H +#define LLD_READER_WRITER_ELF_HEXAGON_DYNAMIC_ATOMS_H + +#include "Atoms.h" +#include "HexagonTargetInfo.h" + +namespace lld { +namespace elf { + +class HexagonGOTAtom : public GOTAtom { + static const uint8_t _defaultContent[8]; + +public: + HexagonGOTAtom(const File &f, StringRef secName) + : GOTAtom(f, secName) { + } + + virtual ArrayRef rawContent() const { + return ArrayRef(_defaultContent, 8); + } +}; + +const uint8_t HexagonGOTAtom::_defaultContent[8] = { 0 }; + +class HexagonPLTAtom : public PLTAtom { + static const uint8_t _defaultContent[16]; + +public: + HexagonPLTAtom(const File &f, StringRef secName) + : PLTAtom(f, secName) { + } + + virtual ArrayRef rawContent() const { + return ArrayRef(_defaultContent, 16); + } +}; + +const uint8_t HexagonPLTAtom::_defaultContent[16] = { + 0x00, 0x40, 0x00, 0x00, // { immext (#0) + 0x0e, 0xc0, 0x49, 0x6a, // r14 = add (pc, ##GOTn@PCREL) } # address of GOTn + 0x1c, 0xc0, 0x8e, 0x91, // r28 = memw (r14) # contents of GOTn + 0x00, 0xc0, 0x9c, 0x52, // jumpr r28 # call it +}; + +class HexagonPLT0Atom : public PLT0Atom { + static const uint8_t _plt0Content[28]; + +public: + HexagonPLT0Atom(const File &f) : PLT0Atom(f) { +#ifndef NDEBUG + _name = ".PLT0"; +#endif + } + + virtual ArrayRef rawContent() const { + return ArrayRef(_plt0Content, 28); + } +}; + +const uint8_t HexagonPLT0Atom::_plt0Content[28] = { + 0x00, 0x40, 0x00, 0x00, // { immext (#0) + 0x1c, 0xc0, 0x49, 0x6a, // r28 = add (pc, ##GOT0@PCREL) } # address of GOT0 + 0x0e, 0x42, 0x9c, 0xe2, // { r14 -= add (r28, #16) # offset of GOTn from GOTa + 0x4f, 0x40, 0x9c, 0x91, // r15 = memw (r28 + #8) # object ID at GOT2 + 0x3c, 0xc0, 0x9c, 0x91, // r28 = memw (r28 + #4) }# dynamic link at GOT1 + 0x0e, 0x42, 0x0e, 0x8c, // { r14 = asr (r14, #2) # index of PLTn + 0x00, 0xc0, 0x9c, 0x52, // jumpr r28 } # call dynamic linker +}; + +} // elf +} // lld + +#endif // LLD_READER_WRITER_ELF_HEXAGON_DYNAMIC_ATOMS_H diff --git a/lld/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.cpp b/lld/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.cpp index 3792475..d0cd240 100644 --- a/lld/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.cpp +++ b/lld/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.cpp @@ -97,6 +97,16 @@ int relocHexBNPCRELX(uint8_t *location, uint64_t P, uint64_t S, uint64_t A, return 1; } +// R_HEX_6_PCREL_X +int relocHex6PCRELX(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) { + int32_t result = (S + A - P); + result = lld::scatterBits(result, FINDV4BITMASK(location)); + *reinterpret_cast(location) = + result | + (uint32_t) * reinterpret_cast(location); + return 0; +} + // R_HEX_N_X : Word32_U6 : (S + A) : Unsigned Truncate int relocHex_N_X(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) { uint32_t result = (S + A); @@ -197,6 +207,11 @@ ErrorOr HexagonTargetRelocationHandler::applyRelocation( case R_HEX_6_X: relocHex_N_X(location, relocVAddress, targetVAddress, ref.addend()); break; + case R_HEX_6_PCREL_X: + relocHex6PCRELX(location, relocVAddress, targetVAddress, ref.addend()); + break; + case R_HEX_JMP_SLOT: + break; case lld::Reference::kindLayoutAfter: case lld::Reference::kindLayoutBefore: case lld::Reference::kindInGroup: diff --git a/lld/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.cpp b/lld/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.cpp index d7ea9cb..8d9e2e7 100644 --- a/lld/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.cpp +++ b/lld/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.cpp @@ -7,6 +7,7 @@ // //===----------------------------------------------------------------------===// +#include "HexagonDynamicAtoms.h" #include "HexagonTargetHandler.h" #include "HexagonTargetInfo.h" @@ -19,3 +20,158 @@ HexagonTargetHandler::HexagonTargetHandler(HexagonTargetInfo &targetInfo) : DefaultTargetHandler(targetInfo), _targetLayout(targetInfo), _relocationHandler(targetInfo, _targetLayout), _hexagonRuntimeFile(targetInfo) {} + +namespace { + +using namespace llvm::ELF; + +class ELFPassFile : public SimpleFile { +public: + ELFPassFile(const ELFTargetInfo &eti) : SimpleFile(eti, "ELFPassFile") {} + + llvm::BumpPtrAllocator _alloc; +}; + +/// \brief Create GOT and PLT entries for relocations. Handles standard GOT/PLT +template class GOTPLTPass : public Pass { + /// \brief Handle a specific reference. + void handleReference(const DefinedAtom &atom, const Reference &ref) { + switch (ref.kind()) { + case R_HEX_PLT_B22_PCREL: + static_cast(this)->handlePLT32(ref); + break; + } + } + +protected: + /// \brief Create a GOT entry containing 0. + const GOTAtom *getNullGOT() { + if (!_null) { + _null = new (_file._alloc) HexagonGOTAtom(_file, ".got.plt"); +#ifndef NDEBUG + _null->_name = "__got_null"; +#endif + } + return _null; + } + +public: + GOTPLTPass(const ELFTargetInfo &ti) + : _file(ti), _null(nullptr), _PLT0(nullptr), _got0(nullptr) {} + + /// \brief Do the pass. + /// + /// The goal here is to first process each reference individually. Each call + /// to handleReference may modify the reference itself and/or create new + /// atoms which must be stored in one of the maps below. + /// + /// After all references are handled, the atoms created during that are all + /// added to mf. + virtual void perform(MutableFile &mf) { + // Process all references. + for (const auto &atom : mf.defined()) + for (const auto &ref : *atom) + handleReference(*atom, *ref); + + // Add all created atoms to the link. + uint64_t ordinal = 0; + if (_PLT0) { + _PLT0->setOrdinal(ordinal++); + mf.addAtom(*_PLT0); + } + for (const auto &plt : _pltMap) { + plt.second->setOrdinal(ordinal++); + mf.addAtom(*plt.second); + } + if (_null) { + _null->setOrdinal(ordinal++); + mf.addAtom(*_null); + } + if (_PLT0) { + _got0->setOrdinal(ordinal++); + mf.addAtom(*_got0); + } + for (const auto &got : _gotMap) { + got.second->setOrdinal(ordinal++); + mf.addAtom(*got.second); + } + } + +protected: + /// \brief Owner of all the Atoms created by this pass. + ELFPassFile _file; + + /// \brief Map Atoms to their GOT entries. + llvm::DenseMap _gotMap; + + /// \brief Map Atoms to their PLT entries. + llvm::DenseMap _pltMap; + + /// \brief GOT entry that is always 0. Used for undefined weaks. + GOTAtom *_null; + + /// \brief The got and plt entries for .PLT0. This is used to call into the + /// dynamic linker for symbol resolution. + /// @{ + PLT0Atom *_PLT0; + GOTAtom *_got0; + /// @} +}; + +class DynamicGOTPLTPass LLVM_FINAL : public GOTPLTPass { +public: + DynamicGOTPLTPass(const elf::HexagonTargetInfo &ti) : GOTPLTPass(ti) {} + + const PLT0Atom *getPLT0() { + if (_PLT0) + return _PLT0; + // Fill in the null entry. + getNullGOT(); + _PLT0 = new (_file._alloc) HexagonPLT0Atom(_file); + _got0 = new (_file._alloc) HexagonGOTAtom(_file, ".got.plt"); + _PLT0->addReference(R_HEX_B32_PCREL_X, 0, _got0, 0); + _PLT0->addReference(R_HEX_6_PCREL_X, 4, _got0, 0); +#ifndef NDEBUG + _got0->_name = "__got0"; +#endif + return _PLT0; + } + + const PLTAtom *getPLTEntry(const Atom *a) { + auto plt = _pltMap.find(a); + if (plt != _pltMap.end()) + return plt->second; + auto ga = new (_file._alloc) HexagonGOTAtom(_file, ".got.plt"); + ga->addReference(R_HEX_JMP_SLOT, 0, a, 0); + auto pa = new (_file._alloc) HexagonPLTAtom(_file, ".plt"); + pa->addReference(R_HEX_B32_PCREL_X, 0, ga, 0); + pa->addReference(R_HEX_6_PCREL_X, 4, ga, 4); + + // Point the got entry to the PLT0 atom initially + ga->addReference(R_HEX_32, 0, getPLT0(), 0); +#ifndef NDEBUG + ga->_name = "__got_"; + ga->_name += a->name(); + pa->_name = "__plt_"; + pa->_name += a->name(); +#endif + _gotMap[a] = ga; + _pltMap[a] = pa; + return pa; + } + + ErrorOr handlePLT32(const Reference &ref) { + // Turn this into a PC32 to the PLT entry. + const_cast(ref).setKind(R_HEX_B22_PCREL); + const_cast(ref).setTarget(getPLTEntry(ref.target())); + return error_code::success(); + } +}; +} // end anonymous namespace + +void elf::HexagonTargetInfo::addPasses(PassManager &pm) const { + if (_options._outputKind == OutputKind::DynamicExecutable || + _options._outputKind == OutputKind::Shared) + pm.add(std::unique_ptr(new DynamicGOTPLTPass(*this))); + ELFTargetInfo::addPasses(pm); +} diff --git a/lld/lib/ReaderWriter/ELF/Hexagon/HexagonTargetInfo.cpp b/lld/lib/ReaderWriter/ELF/Hexagon/HexagonTargetInfo.cpp index 014943d..ddba886 100644 --- a/lld/lib/ReaderWriter/ELF/Hexagon/HexagonTargetInfo.cpp +++ b/lld/lib/ReaderWriter/ELF/Hexagon/HexagonTargetInfo.cpp @@ -215,3 +215,4 @@ ErrorOr elf::HexagonTargetInfo::stringFromRelocKind( return make_error_code(yaml_reader_error::illegal_value); } + diff --git a/lld/lib/ReaderWriter/ELF/Hexagon/HexagonTargetInfo.h b/lld/lib/ReaderWriter/ELF/Hexagon/HexagonTargetInfo.h index bf25b50..ca8fb94 100644 --- a/lld/lib/ReaderWriter/ELF/Hexagon/HexagonTargetInfo.h +++ b/lld/lib/ReaderWriter/ELF/Hexagon/HexagonTargetInfo.h @@ -32,6 +32,29 @@ public: virtual ErrorOr relocKindFromString(StringRef str) const; virtual ErrorOr stringFromRelocKind(int32_t kind) const; + + virtual void addPasses(PassManager &) const; + + virtual bool isDynamicRelocation(const DefinedAtom &, + const Reference &r) const { + switch (r.kind()){ + case llvm::ELF::R_HEX_RELATIVE: + case llvm::ELF::R_HEX_GLOB_DAT: + return true; + default: + return false; + } + } + + virtual bool isPLTRelocation(const DefinedAtom &, + const Reference &r) const { + switch (r.kind()){ + case llvm::ELF::R_HEX_JMP_SLOT: + return true; + default: + return false; + } + } }; } // elf diff --git a/lld/test/elf/Hexagon/Inputs/use-shared.hexagon b/lld/test/elf/Hexagon/Inputs/use-shared.hexagon new file mode 100644 index 0000000000000000000000000000000000000000..9e5ffb42d36adfc561d118f41da3cb6e151fbdef GIT binary patch literal 872 zcmah`%Syvg5S^O(R!~t8l#)e}7BsXPvAA$kvP;}tToilSXnLGFKynd0%WJFs=-etl>K2fj$R|yKTEDIu|*Ebo- zAUDdrOo?w%Ba(WpT0ON3H@$w?48oy(-M_5b^>!TC$4=?MEuR!^*KwVah!YLFvERTM zhsoK}Q5bZ5Ck_U&ICp;Ri_?fA=#n^6q}l6sgNImO7DW)*r3`es~(+UT31GnG5W2s?9my<9<&OO_WM(J z1|9oh(aJpdViGFP8nF)GpJRJQR2#EILrU$8k$(dD0AB()5BI`>xF@q;1!N03ZR|76 z%zRe9zD +CHECK: offset: 0 +CHECK: target: fn1 -- 2.7.4