--- /dev/null
+//===- 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<uint8_t> rawContent() const {
+ return ArrayRef<uint8_t>(_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<uint8_t> rawContent() const {
+ return ArrayRef<uint8_t>(_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<uint8_t> rawContent() const {
+ return ArrayRef<uint8_t>(_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
//
//===----------------------------------------------------------------------===//
+#include "HexagonDynamicAtoms.h"
#include "HexagonTargetHandler.h"
#include "HexagonTargetInfo.h"
: 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 Derived> 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<Derived *>(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<const Atom *, GOTAtom *> _gotMap;
+
+ /// \brief Map Atoms to their PLT entries.
+ llvm::DenseMap<const Atom *, PLTAtom *> _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<DynamicGOTPLTPass> {
+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<void> handlePLT32(const Reference &ref) {
+ // Turn this into a PC32 to the PLT entry.
+ const_cast<Reference &>(ref).setKind(R_HEX_B22_PCREL);
+ const_cast<Reference &>(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<Pass>(new DynamicGOTPLTPass(*this)));
+ ELFTargetInfo::addPasses(pm);
+}