Index: docs/open_projects.rst =================================================================== --- docs/open_projects.rst +++ docs/open_projects.rst @@ -7,6 +7,7 @@ .. include:: ../lib/Core/TODO.txt .. include:: ../lib/Driver/TODO.rst .. include:: ../lib/ReaderWriter/ELF/X86_64/TODO.rst +.. include:: ../lib/ReaderWriter/ELF/AArch64/TODO.rst .. include:: ../tools/lld/TODO.txt Documentation TODOs Index: include/lld/Core/Reference.h =================================================================== --- include/lld/Core/Reference.h +++ include/lld/Core/Reference.h @@ -64,7 +64,8 @@ ARM = 3, PowerPC = 4, Hexagon = 5, - Mips = 6 + Mips = 6, + AArch64 = 7 }; KindArch kindArch() const { return (KindArch)_kindArch; } Index: lib/Driver/GnuLdDriver.cpp =================================================================== --- lib/Driver/GnuLdDriver.cpp +++ lib/Driver/GnuLdDriver.cpp @@ -204,6 +204,10 @@ if (value == "elf32ltsmip") return llvm::Triple::mipsel; return llvm::None; + case llvm::Triple::aarch64: + if (value == "aarch64linux") + return llvm::Triple::aarch64; + return llvm::None; default: return llvm::None; } Index: lib/ReaderWriter/ELF/AArch64/AArch64DynamicLibraryWriter.h =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/AArch64/AArch64DynamicLibraryWriter.h @@ -0,0 +1,69 @@ +//===- lib/ReaderWriter/ELF/AArch64/AArch64DynamicLibraryWriter.h ---------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef AARCH64_DYNAMIC_LIBRARY_WRITER_H +#define AARCH64_DYNAMIC_LIBRARY_WRITER_H + +#include "DynamicLibraryWriter.h" +#include "AArch64LinkingContext.h" + +namespace lld { +namespace elf { + +template +class AArch64DynamicLibraryWriter : public DynamicLibraryWriter { +public: + AArch64DynamicLibraryWriter(AArch64LinkingContext &context, + AArch64TargetLayout &layout); + +protected: + // Add any runtime files and their atoms to the output + virtual bool createImplicitFiles(std::vector> &); + + virtual void finalizeDefaultAtomValues() { + return DynamicLibraryWriter::finalizeDefaultAtomValues(); + } + + virtual void addDefaultAtoms() { + return DynamicLibraryWriter::addDefaultAtoms(); + } + +private: + class GOTFile : public SimpleFile { + public: + GOTFile(const ELFLinkingContext &eti) : SimpleFile("GOTFile") {} + llvm::BumpPtrAllocator _alloc; + }; + + std::unique_ptr _gotFile; + AArch64LinkingContext &_context; + AArch64TargetLayout &_AArch64Layout; +}; + +template +AArch64DynamicLibraryWriter::AArch64DynamicLibraryWriter( + AArch64LinkingContext &context, AArch64TargetLayout &layout) + : DynamicLibraryWriter(context, layout), + _gotFile(new GOTFile(context)), _context(context), + _AArch64Layout(layout) {} + +template +bool AArch64DynamicLibraryWriter::createImplicitFiles( + std::vector> &result) { + DynamicLibraryWriter::createImplicitFiles(result); + _gotFile->addAtom(*new (_gotFile->_alloc) GLOBAL_OFFSET_TABLEAtom(*_gotFile)); + _gotFile->addAtom(*new (_gotFile->_alloc) TLSGETADDRAtom(*_gotFile)); + _gotFile->addAtom(*new (_gotFile->_alloc) DYNAMICAtom(*_gotFile)); + result.push_back(std::move(_gotFile)); + return true; +} + +} // namespace elf +} // namespace lld + +#endif Index: lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.h =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.h @@ -0,0 +1,69 @@ +//===- lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.h -------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef AARCH64_EXECUTABLE_WRITER_H +#define AARCH64_EXECUTABLE_WRITER_H + +#include "ExecutableWriter.h" +#include "AArch64LinkingContext.h" + +namespace lld { +namespace elf { + +template +class AArch64ExecutableWriter : public ExecutableWriter { +public: + AArch64ExecutableWriter(AArch64LinkingContext &context, + AArch64TargetLayout &layout); + +protected: + // Add any runtime files and their atoms to the output + bool createImplicitFiles(std::vector> &) override; + + void finalizeDefaultAtomValues() override { + return ExecutableWriter::finalizeDefaultAtomValues(); + } + + void addDefaultAtoms() override{ + return ExecutableWriter::addDefaultAtoms(); + } + +private: + class GOTFile : public SimpleFile { + public: + GOTFile(const ELFLinkingContext &eti) : SimpleFile("GOTFile") {} + llvm::BumpPtrAllocator _alloc; + }; + + std::unique_ptr _gotFile; + AArch64LinkingContext &_context; + AArch64TargetLayout &_AArch64Layout; +}; + +template +AArch64ExecutableWriter::AArch64ExecutableWriter( + AArch64LinkingContext &context, AArch64TargetLayout &layout) + : ExecutableWriter(context, layout), _gotFile(new GOTFile(context)), + _context(context), _AArch64Layout(layout) {} + +template +bool AArch64ExecutableWriter::createImplicitFiles( + std::vector> &result) { + ExecutableWriter::createImplicitFiles(result); + _gotFile->addAtom(*new (_gotFile->_alloc) GLOBAL_OFFSET_TABLEAtom(*_gotFile)); + _gotFile->addAtom(*new (_gotFile->_alloc) TLSGETADDRAtom(*_gotFile)); + if (_context.isDynamic()) + _gotFile->addAtom(*new (_gotFile->_alloc) DYNAMICAtom(*_gotFile)); + result.push_back(std::move(_gotFile)); + return true; +} + +} // namespace elf +} // namespace lld + +#endif Index: lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.h =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.h @@ -0,0 +1,96 @@ +//===- lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.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_AARCH64_AARCH64_LINKING_CONTEXT_H +#define LLD_READER_WRITER_ELF_AARCH64_AARCH64_LINKING_CONTEXT_H + +#include "AArch64TargetHandler.h" + +#include "lld/ReaderWriter/ELFLinkingContext.h" + +#include "llvm/Object/ELF.h" +#include "llvm/Support/ELF.h" +#include + +namespace lld { +namespace elf { + +enum { + /// \brief The offset to add operation for a R_AARCH64_ADR_GOT_PAGE + ADD_AARCH64_GOTRELINDEX = 0xE000, +}; + +class AArch64LinkingContext final : public ELFLinkingContext { +public: + AArch64LinkingContext(llvm::Triple triple) + : ELFLinkingContext(triple, std::unique_ptr( + new AArch64TargetHandler(*this))) {} + + void addPasses(PassManager &) override; + + uint64_t getBaseAddress() const override { + if (_baseAddress == 0) + return 0x400000; + return _baseAddress; + } + + bool isDynamicRelocation(const DefinedAtom &, + const Reference &r) const override { + if (r.kindNamespace() != Reference::KindNamespace::ELF) + return false; + assert(r.kindArch() == Reference::KindArch::AArch64); + switch (r.kindValue()) { + case llvm::ELF::R_AARCH64_COPY: + case llvm::ELF::R_AARCH64_GLOB_DAT: + case llvm::ELF::R_AARCH64_RELATIVE: + case llvm::ELF::R_AARCH64_TLS_DTPREL64: + case llvm::ELF::R_AARCH64_TLS_DTPMOD64: + case llvm::ELF::R_AARCH64_TLS_TPREL64: + case llvm::ELF::R_AARCH64_TLSDESC: + case llvm::ELF::R_AARCH64_IRELATIVE: + return true; + default: + return false; + } + } + + bool isPLTRelocation(const DefinedAtom &, + const Reference &r) const override { + if (r.kindNamespace() != Reference::KindNamespace::ELF) + return false; + assert(r.kindArch() == Reference::KindArch::AArch64); + switch (r.kindValue()) { + case llvm::ELF::R_AARCH64_JUMP_SLOT: + case llvm::ELF::R_AARCH64_IRELATIVE: + return true; + default: + return false; + } + } + + bool isRelativeReloc(const Reference &r) const override { + if (r.kindNamespace() != Reference::KindNamespace::ELF) + return false; + assert(r.kindArch() == Reference::KindArch::AArch64); + switch (r.kindValue()) { + case llvm::ELF::R_AARCH64_IRELATIVE: + case llvm::ELF::R_AARCH64_RELATIVE: + return true; + default: + return false; + } + } + + /// \brief Create Internal files for Init/Fini + void createInternalFiles(std::vector> &) const override; +}; +} // end namespace elf +} // end namespace lld + +#endif Index: lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.cpp =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.cpp @@ -0,0 +1,112 @@ +//===- lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.cpp -------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "AArch64LinkingContext.h" + +#include "lld/Core/File.h" +#include "lld/Core/Instrumentation.h" + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringSwitch.h" + +#include "Atoms.h" +#include "AArch64RelocationPass.h" + +using namespace lld; +using namespace lld::elf; + +using llvm::makeArrayRef; + +namespace { +using namespace llvm::ELF; + +const uint8_t AArch64InitFiniAtomContent[8] = {0}; + +// AArch64InitFini Atom +class AArch64InitAtom : public InitFiniAtom { +public: + AArch64InitAtom(const File &f, StringRef function) + : InitFiniAtom(f, ".init_array") { +#ifndef NDEBUG + _name = "__init_fn_"; + _name += function; +#endif + } + ArrayRef rawContent() const override { + return makeArrayRef(AArch64InitFiniAtomContent); + } + Alignment alignment() const override { return Alignment(3); } +}; + +class AArch64FiniAtom : public InitFiniAtom { +public: + AArch64FiniAtom(const File &f, StringRef function) + : InitFiniAtom(f, ".fini_array") { +#ifndef NDEBUG + _name = "__fini_fn_"; + _name += function; +#endif + } + ArrayRef rawContent() const override { + return makeArrayRef(AArch64InitFiniAtomContent); + } + + Alignment alignment() const override { return Alignment(3); } +}; + +class AArch64InitFiniFile : public SimpleFile { +public: + AArch64InitFiniFile(const ELFLinkingContext &context) + : SimpleFile("command line option -init/-fini"), _ordinal(0) {} + + void addInitFunction(StringRef name) { + Atom *initFunctionAtom = new (_allocator) SimpleUndefinedAtom(*this, name); + AArch64InitAtom *initAtom = (new (_allocator) AArch64InitAtom(*this, name)); + initAtom->addReferenceELF_AArch64(llvm::ELF::R_AARCH64_ABS64, 0, + initFunctionAtom, 0); + initAtom->setOrdinal(_ordinal++); + addAtom(*initFunctionAtom); + addAtom(*initAtom); + } + + void addFiniFunction(StringRef name) { + Atom *finiFunctionAtom = new (_allocator) SimpleUndefinedAtom(*this, name); + AArch64FiniAtom *finiAtom = (new (_allocator) AArch64FiniAtom(*this, name)); + finiAtom->addReferenceELF_AArch64(llvm::ELF::R_AARCH64_ABS64, 0, + finiFunctionAtom, 0); + finiAtom->setOrdinal(_ordinal++); + addAtom(*finiFunctionAtom); + addAtom(*finiAtom); + } + +private: + llvm::BumpPtrAllocator _allocator; + uint64_t _ordinal; +}; + +} // end anon namespace + +void elf::AArch64LinkingContext::addPasses(PassManager &pm) { + auto pass = createAArch64RelocationPass(*this); + if (pass) + pm.add(std::move(pass)); + ELFLinkingContext::addPasses(pm); +} + +void elf::AArch64LinkingContext::createInternalFiles( + std::vector> &result) const { + ELFLinkingContext::createInternalFiles(result); + std::unique_ptr initFiniFile( + new AArch64InitFiniFile(*this)); + for (auto ai : initFunctions()) + initFiniFile->addInitFunction(ai); + for (auto ai : finiFunctions()) + initFiniFile->addFiniFunction(ai); + result.push_back(std::move(initFiniFile)); +} Index: lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.h =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.h @@ -0,0 +1,44 @@ +//===- lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.h ------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef AARCH64_RELOCATION_HANDLER_H +#define AARCH64_RELOCATION_HANDLER_H + +#include "AArch64TargetHandler.h" + +namespace lld { +namespace elf { +typedef llvm::object::ELFType AArch64ELFType; + +template class AArch64TargetLayout; + +class AArch64TargetRelocationHandler final + : public TargetRelocationHandler { +public: + AArch64TargetRelocationHandler(AArch64TargetLayout &layout) + : _tlsSize(0), _AArch64Layout(layout) {} + + std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &, + const lld::AtomLayout &, + const Reference &) const override; + + virtual int64_t relocAddend(const Reference &) const; + + static const Registry::KindStrings kindStrings[]; + +private: + // Cached size of the TLS segment. + mutable uint64_t _tlsSize; + AArch64TargetLayout &_AArch64Layout; +}; + +} // end namespace elf +} // end namespace lld + +#endif // AArch64_RELOCATION_HANDLER_H Index: lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.cpp =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.cpp @@ -0,0 +1,490 @@ +//===- lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.cpp ----------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "AArch64TargetHandler.h" +#include "AArch64LinkingContext.h" +#include "llvm/Support/Debug.h" + +using namespace lld; +using namespace elf; + +#define PAGE(X) ((X) & ~0x0FFFL) + +/// \brief R_AARCH64_ABS64 - word64: S + A +static void relocR_AARCH64_ABS64(uint8_t *location, uint64_t P, uint64_t S, + int64_t A) { + int64_t result = (int64_t)S + A; + DEBUG_WITH_TYPE("AArch64", llvm::dbgs() << "\t\tHandle " << __func__ << " -"; + llvm::dbgs() << " S: 0x" << Twine::utohexstr(S); + llvm::dbgs() << " A: 0x" << Twine::utohexstr(A); + llvm::dbgs() << " P: 0x" << Twine::utohexstr(P); + llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) + << "\n"); + *reinterpret_cast(location) = + result | + (int64_t) * reinterpret_cast(location); +} + +/// \brief R_AARCH64_PREL32 - word32: S + A - P +static void relocR_AARCH64_PREL32(uint8_t *location, uint64_t P, uint64_t S, + int64_t A) { + int32_t result = (int32_t)((S + A) - P); + *reinterpret_cast(location) = + result + + (int32_t) * reinterpret_cast(location); +} + +/// \brief R_AARCH64_ABS32 - word32: S + A +static void relocR_AARCH64_ABS32(uint8_t *location, uint64_t P, uint64_t S, + int64_t A) { + int32_t result = (int32_t)(S + A); + DEBUG_WITH_TYPE("AArch64", llvm::dbgs() << "\t\tHandle " << __func__ << " -"; + llvm::dbgs() << " S: 0x" << Twine::utohexstr(S); + llvm::dbgs() << " A: 0x" << Twine::utohexstr(A); + llvm::dbgs() << " P: 0x" << Twine::utohexstr(P); + llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) + << "\n"); + *reinterpret_cast(location) = + result | + (int32_t) * reinterpret_cast(location); +} + +/// \brief R_AARCH64_ADR_PREL_PG_HI21 - Page(S+A) - Page(P) +static void relocR_AARCH64_ADR_PREL_PG_HI21(uint8_t *location, uint64_t P, + uint64_t S, int64_t A) { + uint64_t result = (PAGE(S + A) - PAGE(P)); + result = result >> 12; + uint32_t immlo = result & 0x3; + uint32_t immhi = result & 0x1FFFFC; + immlo = immlo << 29; + immhi = immhi << 3; + DEBUG_WITH_TYPE("AArch64", llvm::dbgs() << "\t\tHandle " << __func__ << " -"; + llvm::dbgs() << " S: " << Twine::utohexstr(S); + llvm::dbgs() << " A: " << Twine::utohexstr(A); + llvm::dbgs() << " P: " << Twine::utohexstr(P); + llvm::dbgs() << " immhi: " << Twine::utohexstr(immhi); + llvm::dbgs() << " immlo: " << Twine::utohexstr(immlo); + llvm::dbgs() << " result: " << Twine::utohexstr(result) + << "\n"); + *reinterpret_cast(location) = + immlo | immhi | + (int32_t) * reinterpret_cast(location); + // TODO: Make sure this is correct! +} + +/// \brief R_AARCH64_ADR_PREL_LO21 - S + A - P +static void relocR_AARCH64_ADR_PREL_LO21(uint8_t *location, uint64_t P, + uint64_t S, int64_t A) { + uint64_t result = (S + A) - P; + uint32_t immlo = result & 0x3; + uint32_t immhi = result & 0x1FFFFC; + immlo = immlo << 29; + immhi = immhi << 3; + DEBUG_WITH_TYPE("AArch64", llvm::dbgs() << "\t\tHandle " << __func__ << " -"; + llvm::dbgs() << " S: " << Twine::utohexstr(S); + llvm::dbgs() << " A: " << Twine::utohexstr(A); + llvm::dbgs() << " P: " << Twine::utohexstr(P); + llvm::dbgs() << " immhi: " << Twine::utohexstr(immhi); + llvm::dbgs() << " immlo: " << Twine::utohexstr(immlo); + llvm::dbgs() << " result: " << Twine::utohexstr(result) + << "\n"); + *reinterpret_cast(location) = + immlo | immhi | + (int32_t) * reinterpret_cast(location); + // TODO: Make sure this is correct! +} + +/// \brief R_AARCH64_ADD_ABS_LO12_NC +static void relocR_AARCH64_ADD_ABS_LO12_NC(uint8_t *location, uint64_t P, + uint64_t S, int64_t A) { + int32_t result = (int32_t)((S + A) & 0xFFF); + result <<= 10; + DEBUG_WITH_TYPE("AArch64", llvm::dbgs() << "\t\tHandle " << __func__ << " -"; + llvm::dbgs() << " S: " << Twine::utohexstr(S); + llvm::dbgs() << " A: " << Twine::utohexstr(A); + llvm::dbgs() << " P: " << Twine::utohexstr(P); + llvm::dbgs() << " result: " << Twine::utohexstr(result) + << "\n"); + *reinterpret_cast(location) = + result | + (int32_t) * reinterpret_cast(location); +} + +static void relocJump26(uint8_t *location, uint64_t P, uint64_t S, int64_t A) { + int32_t result = (int32_t)((S + A) - P); + result &= 0x0FFFFFFC; + result >>= 2; + DEBUG_WITH_TYPE("AArch64", llvm::dbgs() << "\t\tHandle " << __func__ << " -"; + llvm::dbgs() << " S: " << Twine::utohexstr(S); + llvm::dbgs() << " A: " << Twine::utohexstr(A); + llvm::dbgs() << " P: " << Twine::utohexstr(P); + llvm::dbgs() << " result: " << Twine::utohexstr(result) + << "\n"); + *reinterpret_cast(location) = + result | + (int32_t) * reinterpret_cast(location); +} + +/// \brief R_AARCH64_CONDBR19 +static void relocR_AARCH64_CONDBR19(uint8_t *location, uint64_t P, uint64_t S, + int64_t A) { + int32_t result = (int32_t)((S + A) - P); + result &= 0x01FFFFC; + result <<= 3; + DEBUG_WITH_TYPE("AArch64", llvm::dbgs() << "\t\tHandle " << __func__ << " -"; + llvm::dbgs() << " S: " << Twine::utohexstr(S); + llvm::dbgs() << " A: " << Twine::utohexstr(A); + llvm::dbgs() << " P: " << Twine::utohexstr(P); + llvm::dbgs() << " result: " << Twine::utohexstr(result) + << "\n"); + *reinterpret_cast(location) = + result | + (int32_t) * reinterpret_cast(location); +} + +/// \brief R_AARCH64_LDST8_ABS_LO12_NC - S + A +static void relocR_AARCH64_LDST8_ABS_LO12_NC(uint8_t *location, uint64_t P, + uint64_t S, int64_t A) { + int32_t result = (int32_t)((S + A) & 0xFFF); + result <<= 10; + DEBUG_WITH_TYPE("AArch64", llvm::dbgs() << "\t\tHandle " << __func__ << " -"; + llvm::dbgs() << " S: " << Twine::utohexstr(S); + llvm::dbgs() << " A: " << Twine::utohexstr(A); + llvm::dbgs() << " P: " << Twine::utohexstr(P); + llvm::dbgs() << " result: " << Twine::utohexstr(result) + << "\n"); + *reinterpret_cast(location) = + result | + (int32_t) * reinterpret_cast(location); +} + +/// \brief R_AARCH64_LDST16_ABS_LO12_NC +static void relocR_AARCH64_LDST16_ABS_LO12_NC(uint8_t *location, uint64_t P, + uint64_t S, int64_t A) { + int32_t result = (int32_t)(S + A); + result &= 0x0FFC; + result <<= 9; + DEBUG_WITH_TYPE("AArch64", llvm::dbgs() << "\t\tHandle " << __func__ << " -"; + llvm::dbgs() << " S: " << Twine::utohexstr(S); + llvm::dbgs() << " A: " << Twine::utohexstr(A); + llvm::dbgs() << " P: " << Twine::utohexstr(P); + llvm::dbgs() << " result: " << Twine::utohexstr(result) + << "\n"); + *reinterpret_cast(location) = + result | + (int32_t) * reinterpret_cast(location); +} + +/// \brief R_AARCH64_LDST32_ABS_LO12_NC +static void relocR_AARCH64_LDST32_ABS_LO12_NC(uint8_t *location, uint64_t P, + uint64_t S, int64_t A) { + int32_t result = (int32_t)(S + A); + result &= 0x0FFC; + result <<= 8; + DEBUG_WITH_TYPE("AArch64", llvm::dbgs() << "\t\tHandle " << __func__ << " -"; + llvm::dbgs() << " S: " << Twine::utohexstr(S); + llvm::dbgs() << " A: " << Twine::utohexstr(A); + llvm::dbgs() << " P: " << Twine::utohexstr(P); + llvm::dbgs() << " result: " << Twine::utohexstr(result) + << "\n"); + *reinterpret_cast(location) = + result | + (int32_t) * reinterpret_cast(location); +} + +/// \brief R_AARCH64_LDST64_ABS_LO12_NC +static void relocR_AARCH64_LDST64_ABS_LO12_NC(uint8_t *location, uint64_t P, + uint64_t S, int64_t A) { + int32_t result = (int32_t)(S + A); + result &= 0x0FF8; + result <<= 7; + DEBUG_WITH_TYPE("AArch64", llvm::dbgs() << "\t\tHandle " << __func__ << " -"; + llvm::dbgs() << " S: " << Twine::utohexstr(S); + llvm::dbgs() << " A: " << Twine::utohexstr(A); + llvm::dbgs() << " P: " << Twine::utohexstr(P); + llvm::dbgs() << " result: " << Twine::utohexstr(result) + << "\n"); + *reinterpret_cast(location) = + result | + (int32_t) * reinterpret_cast(location); +} + +/// \brief R_AARCH64_LDST128_ABS_LO12_NC +static void relocR_AARCH64_LDST128_ABS_LO12_NC(uint8_t *location, uint64_t P, + uint64_t S, int64_t A) { + int32_t result = (int32_t)(S + A); + result &= 0x0FF8; + result <<= 6; + DEBUG_WITH_TYPE("AArch64", llvm::dbgs() << "\t\tHandle " << __func__ << " -"; + llvm::dbgs() << " S: " << Twine::utohexstr(S); + llvm::dbgs() << " A: " << Twine::utohexstr(A); + llvm::dbgs() << " P: " << Twine::utohexstr(P); + llvm::dbgs() << " result: " << Twine::utohexstr(result) + << "\n"); + *reinterpret_cast(location) = + result | + (int32_t) * reinterpret_cast(location); +} + +static void relocR_AARCH64_ADR_GOT_PAGE(uint8_t *location, uint64_t P, + uint64_t S, int64_t A) { + uint64_t result = PAGE(S + A) - PAGE(P); + result >>= 12; + uint32_t immlo = result & 0x3; + uint32_t immhi = result & 0x1FFFFC; + immlo = immlo << 29; + immhi = immhi << 3; + DEBUG_WITH_TYPE("AArch64", llvm::dbgs() << "\t\tHandle " << __func__ << " -"; + llvm::dbgs() << " S: " << Twine::utohexstr(S); + llvm::dbgs() << " A: " << Twine::utohexstr(A); + llvm::dbgs() << " P: " << Twine::utohexstr(P); + llvm::dbgs() << " immhi: " << Twine::utohexstr(immhi); + llvm::dbgs() << " immlo: " << Twine::utohexstr(immlo); + llvm::dbgs() << " result: " << Twine::utohexstr(result) + << "\n"); + *reinterpret_cast(location) = + immlo | immhi | + (int32_t) * reinterpret_cast(location); +} + +// R_AARCH64_LD64_GOT_LO12_NC +static void relocR_AARCH64_LD64_GOT_LO12_NC(uint8_t *location, uint64_t P, + uint64_t S, int64_t A) { + int32_t result = S + A; + DEBUG_WITH_TYPE("AArch64", llvm::dbgs() << "\t\tHandle " << __func__ << " -"; + llvm::dbgs() << " S: " << Twine::utohexstr(S); + llvm::dbgs() << " A: " << Twine::utohexstr(A); + llvm::dbgs() << " P: " << Twine::utohexstr(P); + llvm::dbgs() << " result: " << Twine::utohexstr(result) + << "\n"); + result &= 0xFF8; + result <<= 7; + *reinterpret_cast(location) = + result | + (int32_t) * reinterpret_cast(location); +} + +// ADD_AARCH64_GOTRELINDEX +static void relocADD_AARCH64_GOTRELINDEX(uint8_t *location, uint64_t P, + uint64_t S, int64_t A) { + int32_t result = S + A; + DEBUG_WITH_TYPE("AArch64", llvm::dbgs() << "\t\tHandle " << __func__ << " -"; + llvm::dbgs() << " S: " << Twine::utohexstr(S); + llvm::dbgs() << " A: " << Twine::utohexstr(A); + llvm::dbgs() << " P: " << Twine::utohexstr(P); + llvm::dbgs() << " result: " << Twine::utohexstr(result) + << "\n"); + result &= 0xFFF; + result <<= 10; + *reinterpret_cast(location) = + result | + (int32_t) * reinterpret_cast(location); +} + +// R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 +static void relocR_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21(uint8_t *location, + uint64_t P, uint64_t S, + int64_t A) { + int64_t result = PAGE(S + A) - PAGE(P); + result >>= 12; + uint32_t immlo = result & 0x3; + uint32_t immhi = result & 0x1FFFFC; + immlo = immlo << 29; + immhi = immhi << 3; + DEBUG_WITH_TYPE("AArch64", llvm::dbgs() << "\t\tHandle " << __func__ << " -"; + llvm::dbgs() << " S: " << Twine::utohexstr(S); + llvm::dbgs() << " A: " << Twine::utohexstr(A); + llvm::dbgs() << " P: " << Twine::utohexstr(P); + llvm::dbgs() << " immhi: " << Twine::utohexstr(immhi); + llvm::dbgs() << " immlo: " << Twine::utohexstr(immlo); + llvm::dbgs() << " result: " << Twine::utohexstr(result) + << "\n"); + *reinterpret_cast(location) = + immlo | immhi | + (int32_t) * reinterpret_cast(location); +} + +// R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC +static void relocR_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC(uint8_t *location, + uint64_t P, uint64_t S, + int64_t A) { + int32_t result = S + A; + result &= 0xFF8; + result <<= 7; + DEBUG_WITH_TYPE("AArch64", llvm::dbgs() << "\t\tHandle " << __func__ << " -"; + llvm::dbgs() << " S: " << Twine::utohexstr(S); + llvm::dbgs() << " A: " << Twine::utohexstr(A); + llvm::dbgs() << " P: " << Twine::utohexstr(P); + llvm::dbgs() << " result: " << Twine::utohexstr(result) + << "\n"); + *reinterpret_cast(location) = + result | + (int32_t) * reinterpret_cast(location); +} + +/// \brief R_AARCH64_TLSLE_ADD_TPREL_HI12 +static void relocR_AARCH64_TLSLE_ADD_TPREL_HI12(uint8_t *location, uint64_t P, + uint64_t S, int64_t A) { + int32_t result = S + A; + result &= 0x0FFF000; + result >>= 2; + DEBUG_WITH_TYPE("AArch64", llvm::dbgs() << "\t\tHandle " << __func__ << " -"; + llvm::dbgs() << " S: " << Twine::utohexstr(S); + llvm::dbgs() << " A: " << Twine::utohexstr(A); + llvm::dbgs() << " P: " << Twine::utohexstr(P); + llvm::dbgs() << " result: " << Twine::utohexstr(result) + << "\n"); + *reinterpret_cast(location) = + result | + (int32_t) * reinterpret_cast(location); +} + +/// \brief R_AARCH64_TLSLE_ADD_TPREL_LO12_NC +static void relocR_AARCH64_TLSLE_ADD_TPREL_LO12_NC(uint8_t *location, + uint64_t P, uint64_t S, + int64_t A) { + int32_t result = S + A; + result &= 0x0FFF; + result <<= 10; + DEBUG_WITH_TYPE("AArch64", llvm::dbgs() << "\t\tHandle " << __func__ << " -"; + llvm::dbgs() << " S: " << Twine::utohexstr(S); + llvm::dbgs() << " A: " << Twine::utohexstr(A); + llvm::dbgs() << " P: " << Twine::utohexstr(P); + llvm::dbgs() << " result: " << Twine::utohexstr(result) + << "\n"); + *reinterpret_cast(location) = + result | + (int32_t) * reinterpret_cast(location); +} + +int64_t +AArch64TargetRelocationHandler::relocAddend(const Reference &ref) const { + if (ref.kindNamespace() != Reference::KindNamespace::ELF) + return false; + assert(ref.kindArch() == Reference::KindArch::AArch64); + switch (ref.kindValue()) { + case R_AARCH64_PREL32: + return 4; + default: + return 0; + } + return 0; +} + +std::error_code AArch64TargetRelocationHandler::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(); + + if (ref.kindNamespace() != Reference::KindNamespace::ELF) + return std::error_code(); + assert(ref.kindArch() == Reference::KindArch::AArch64); + switch (ref.kindValue()) { + case R_AARCH64_NONE: + break; + case R_AARCH64_ABS64: + relocR_AARCH64_ABS64(location, relocVAddress, targetVAddress, ref.addend()); + break; + case R_AARCH64_PREL32: + relocR_AARCH64_PREL32(location, relocVAddress, targetVAddress, + ref.addend()); + break; + case R_AARCH64_ABS32: + relocR_AARCH64_ABS32(location, relocVAddress, targetVAddress, ref.addend()); + break; + // Runtime only relocations. Ignore here. + case R_AARCH64_RELATIVE: + case R_AARCH64_IRELATIVE: + case R_AARCH64_JUMP_SLOT: + case R_AARCH64_GLOB_DAT: + break; + case R_AARCH64_ADR_PREL_PG_HI21: + relocR_AARCH64_ADR_PREL_PG_HI21(location, relocVAddress, targetVAddress, + ref.addend()); + break; + case R_AARCH64_ADR_PREL_LO21: + relocR_AARCH64_ADR_PREL_LO21(location, relocVAddress, targetVAddress, + ref.addend()); + break; + case R_AARCH64_ADD_ABS_LO12_NC: + relocR_AARCH64_ADD_ABS_LO12_NC(location, relocVAddress, targetVAddress, + ref.addend()); + break; + case R_AARCH64_CALL26: + case R_AARCH64_JUMP26: + relocJump26(location, relocVAddress, targetVAddress, ref.addend()); + break; + case R_AARCH64_CONDBR19: + relocR_AARCH64_CONDBR19(location, relocVAddress, targetVAddress, + ref.addend()); + break; + case R_AARCH64_ADR_GOT_PAGE: + relocR_AARCH64_ADR_GOT_PAGE(location, relocVAddress, targetVAddress, + ref.addend()); + break; + case R_AARCH64_LD64_GOT_LO12_NC: + relocR_AARCH64_LD64_GOT_LO12_NC(location, relocVAddress, targetVAddress, + ref.addend()); + break; + case R_AARCH64_LDST8_ABS_LO12_NC: + relocR_AARCH64_LDST8_ABS_LO12_NC(location, relocVAddress, targetVAddress, + ref.addend()); + break; + case R_AARCH64_LDST16_ABS_LO12_NC: + relocR_AARCH64_LDST16_ABS_LO12_NC(location, relocVAddress, targetVAddress, + ref.addend()); + break; + case R_AARCH64_LDST32_ABS_LO12_NC: + relocR_AARCH64_LDST32_ABS_LO12_NC(location, relocVAddress, targetVAddress, + ref.addend()); + break; + case R_AARCH64_LDST64_ABS_LO12_NC: + relocR_AARCH64_LDST64_ABS_LO12_NC(location, relocVAddress, targetVAddress, + ref.addend()); + break; + case R_AARCH64_LDST128_ABS_LO12_NC: + relocR_AARCH64_LDST128_ABS_LO12_NC(location, relocVAddress, targetVAddress, + ref.addend()); + break; + case ADD_AARCH64_GOTRELINDEX: + relocADD_AARCH64_GOTRELINDEX(location, relocVAddress, targetVAddress, + ref.addend()); + break; + case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: + relocR_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21(location, relocVAddress, + targetVAddress, ref.addend()); + break; + case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: + relocR_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC(location, relocVAddress, + targetVAddress, ref.addend()); + break; + case R_AARCH64_TLSLE_ADD_TPREL_HI12: + relocR_AARCH64_TLSLE_ADD_TPREL_HI12(location, relocVAddress, targetVAddress, + ref.addend()); + break; + case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: + relocR_AARCH64_TLSLE_ADD_TPREL_LO12_NC(location, relocVAddress, + targetVAddress, ref.addend()); + break; + default: { + std::string str; + llvm::raw_string_ostream s(str); + s << "Unhandled relocation: " << atom._atom->file().path() << ":" + << atom._atom->name() << "@" << ref.offsetInAtom() << " " + << "#" << ref.kindValue(); + s.flush(); + llvm_unreachable(str.c_str()); + } + } + + return std::error_code(); +} Index: lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.h =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.h @@ -0,0 +1,32 @@ +//===- lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.h ---------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Declares the relocation processing pass for x86-64. This includes +/// GOT and PLT entries, TLS, COPY, and ifunc. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READER_WRITER_ELF_AARCH64_AARCH64_RELOCATION_PASS_H +#define LLD_READER_WRITER_ELF_AARCH64_AARCH64_RELOCATION_PASS_H + +#include + +namespace lld { +class Pass; +namespace elf { +class AArch64LinkingContext; + +/// \brief Create AArch64 relocation pass for the given linking context. +std::unique_ptr +createAArch64RelocationPass(const AArch64LinkingContext &); +} +} + +#endif Index: lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.cpp =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.cpp @@ -0,0 +1,535 @@ +//===- lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.cpp -------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines the relocation processing pass for AArch64. This includes +/// GOT and PLT entries, TLS, COPY, and ifunc. +/// +/// This also includes additional behavior that gnu-ld and gold implement but +/// which is not specified anywhere. +/// +//===----------------------------------------------------------------------===// + +#include "AArch64RelocationPass.h" + +#include "lld/Core/Simple.h" + +#include "llvm/ADT/DenseMap.h" + +#include "Atoms.h" +#include "AArch64LinkingContext.h" +#include "llvm/Support/Debug.h" + +using namespace lld; +using namespace lld::elf; +using namespace llvm::ELF; + +namespace { +// .got values +const uint8_t AArch64GotAtomContent[8] = {0}; + +// .plt value (entry 0) +const uint8_t AArch64Plt0AtomContent[32] = { + 0xf0, 0x7b, 0xbf, + 0xa9, // stp x16, x30, [sp,#-16]! + 0x10, 0x00, 0x00, + 0x90, // adrp x16, Page(eh_frame) + 0x11, 0x02, 0x40, + 0xf9, // ldr x17, [x16,#offset] + 0x10, 0x02, 0x00, + 0x91, // add x16, x16, #offset + 0x20, 0x02, 0x1f, + 0xd6, // br x17 + 0x1f, 0x20, 0x03, + 0xd5, // nop + 0x1f, 0x20, 0x03, + 0xd5, // nop + 0x1f, 0x20, 0x03, + 0xd5 // nop +}; + +// .plt values (other entries) +const uint8_t AArch64PltAtomContent[16] = { + 0x10, 0x00, 0x00, + 0x90, // adrp x16, PAGE() + 0x11, 0x02, 0x40, + 0xf9, // ldr x17, [x16,#offset] + 0x10, 0x02, 0x00, + 0x91, // add x16, x16, #offset + 0x20, 0x02, 0x1f, + 0xd6 // br x17 +}; + +/// \brief Atoms that are used by AArch64 dynamic linking +class AArch64GOTAtom : public GOTAtom { +public: + AArch64GOTAtom(const File &f, StringRef secName) : GOTAtom(f, secName) {} + + ArrayRef rawContent() const override { + return ArrayRef(AArch64GotAtomContent, 8); + } +}; + +class AArch64PLT0Atom : public PLT0Atom { +public: + AArch64PLT0Atom(const File &f) : PLT0Atom(f) { +#ifndef NDEBUG + _name = ".PLT0"; +#endif + } + ArrayRef rawContent() const override { + return ArrayRef(AArch64Plt0AtomContent, 32); + } +}; + +class AArch64PLTAtom : public PLTAtom { +public: + AArch64PLTAtom(const File &f, StringRef secName) : PLTAtom(f, secName) {} + + ArrayRef rawContent() const override { + return ArrayRef(AArch64PltAtomContent, 16); + } +}; + +class ELFPassFile : public SimpleFile { +public: + ELFPassFile(const ELFLinkingContext &eti) : SimpleFile("ELFPassFile") { + setOrdinal(eti.getNextOrdinalAndIncrement()); + } + + llvm::BumpPtrAllocator _alloc; +}; + +/// \brief CRTP base for handling relocations. +template class AArch64RelocationPass : public Pass { + /// \brief Handle a specific reference. + void handleReference(const DefinedAtom &atom, const Reference &ref) { + DEBUG_WITH_TYPE( + "AArch64", llvm::dbgs() + << "\t" << __func__ << "()" + << ": Name of Defined Atom: " << atom.name().str(); + llvm::dbgs() << " kindValue: " << ref.kindValue() << "\n"); + if (ref.kindNamespace() != Reference::KindNamespace::ELF) + return; + assert(ref.kindArch() == Reference::KindArch::AArch64); + switch (ref.kindValue()) { + case R_AARCH64_ABS32: + case R_AARCH64_ABS16: + case R_AARCH64_ABS64: + case R_AARCH64_PREL16: + case R_AARCH64_PREL32: + case R_AARCH64_PREL64: + static_cast(this)->handlePlain(ref); + break; + case R_AARCH64_GOTREL32: + case R_AARCH64_GOTREL64: + static_cast(this)->handleGOT(ref); + break; + case R_AARCH64_ADR_PREL_PG_HI21: + static_cast(this)->handlePlain(ref); + break; + case R_AARCH64_LDST8_ABS_LO12_NC: + case R_AARCH64_LDST16_ABS_LO12_NC: + case R_AARCH64_LDST32_ABS_LO12_NC: + case R_AARCH64_LDST64_ABS_LO12_NC: + case R_AARCH64_LDST128_ABS_LO12_NC: + static_cast(this)->handlePlain(ref); + break; + case R_AARCH64_ADD_ABS_LO12_NC: + static_cast(this)->handlePlain(ref); + break; + case R_AARCH64_CALL26: + case R_AARCH64_JUMP26: + case R_AARCH64_CONDBR19: + static_cast(this)->handlePlain(ref); + break; + case R_AARCH64_TLSLE_ADD_TPREL_HI12: + case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: + static_cast(this)->handlePlain(ref); + break; + case R_AARCH64_ADR_GOT_PAGE: + case R_AARCH64_LD64_GOT_LO12_NC: + case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: + case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: + static_cast(this)->handleGOT(ref); + break; + default: + llvm_unreachable("Unhandled type in handleReference"); + } + } + +protected: + /// \brief get the PLT entry for a given IFUNC Atom. + /// + /// If the entry does not exist. Both the GOT and PLT entry is created. + const PLTAtom *getIFUNCPLTEntry(const DefinedAtom *da) { + auto plt = _pltMap.find(da); + if (plt != _pltMap.end()) + return plt->second; + auto ga = new (_file._alloc) AArch64GOTAtom(_file, ".got.plt"); + ga->addReferenceELF_AArch64(R_AARCH64_IRELATIVE, 0, da, 0); + auto pa = new (_file._alloc) AArch64PLTAtom(_file, ".plt"); + pa->addReferenceELF_AArch64(R_AARCH64_PREL32, 2, ga, -4); +#ifndef NDEBUG + ga->_name = "__got_ifunc_"; + ga->_name += da->name(); + pa->_name = "__plt_ifunc_"; + pa->_name += da->name(); +#endif + _gotMap[da] = ga; + _pltMap[da] = pa; + _gotVector.push_back(ga); + _pltVector.push_back(pa); + return pa; + } + + /// \brief Redirect the call to the PLT stub for the target IFUNC. + /// + /// This create a PLT and GOT entry for the IFUNC if one does not exist. The + /// GOT entry and a IRELATIVE relocation to the original target resolver. + std::error_code handleIFUNC(const Reference &ref) { + auto target = dyn_cast_or_null(ref.target()); + if (target && target->contentType() == DefinedAtom::typeResolver) + const_cast(ref).setTarget(getIFUNCPLTEntry(target)); + return std::error_code(); + } + + /// \brief Create a GOT entry for the TP offset of a TLS atom. + const GOTAtom *getGOTTPOFF(const Atom *atom) { + auto got = _gotMap.find(atom); + if (got == _gotMap.end()) { + auto g = new (_file._alloc) AArch64GOTAtom(_file, ".got"); + g->addReferenceELF_AArch64(R_AARCH64_GOTREL64, 0, atom, 0); +#ifndef NDEBUG + g->_name = "__got_tls_"; + g->_name += atom->name(); +#endif + _gotMap[atom] = g; + _gotVector.push_back(g); + return g; + } + return got->second; + } + + /// \brief Create a TPOFF64 GOT entry and change the relocation to a PC32 to + /// the GOT. + void handleGOTTPOFF(const Reference &ref) { + const_cast(ref).setTarget(getGOTTPOFF(ref.target())); + const_cast(ref).setKindValue(R_AARCH64_PREL32); + } + + /// \brief Create a GOT entry containing 0. + const GOTAtom *getNullGOT() { + if (!_null) { + _null = new (_file._alloc) AArch64GOTAtom(_file, ".got.plt"); +#ifndef NDEBUG + _null->_name = "__got_null"; +#endif + } + return _null; + } + + const GOTAtom *getGOT(const DefinedAtom *da) { + auto got = _gotMap.find(da); + if (got == _gotMap.end()) { + auto g = new (_file._alloc) AArch64GOTAtom(_file, ".got"); + g->addReferenceELF_AArch64(R_AARCH64_ABS64, 0, da, 0); +#ifndef NDEBUG + g->_name = "__got_"; + g->_name += da->name(); +#endif + _gotMap[da] = g; + _gotVector.push_back(g); + return g; + } + return got->second; + } + +public: + AArch64RelocationPass(const ELFLinkingContext &ctx) + : _file(ctx), _ctx(ctx), _null(nullptr), _PLT0(nullptr), _got0(nullptr), + _got1(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. + void perform(std::unique_ptr &mf) override { + ScopedTask task(getDefaultDomain(), "AArch64 GOT/PLT Pass"); + DEBUG_WITH_TYPE( + "AArch64", llvm::dbgs() << "Undefined Atoms" + << "\n"; + for (const auto &atom + : mf->undefined()) { + llvm::dbgs() << " Name of Atom: " << atom->name().str() << "\n"; + } llvm::dbgs() + << "Shared Library Atoms" + << "\n"; + for (const auto &atom + : mf->sharedLibrary()) { + llvm::dbgs() << " Name of Atom: " << atom->name().str() << "\n"; + } llvm::dbgs() + << "Absolute Atoms" + << "\n"; + for (const auto &atom + : mf->absolute()) { + llvm::dbgs() << " Name of Atom: " << atom->name().str() << "\n"; + } + // Process all references. + llvm::dbgs() + << "Defined Atoms" + << "\n"); + 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 (auto &plt : _pltVector) { + plt->setOrdinal(ordinal++); + mf->addAtom(*plt); + } + if (_null) { + _null->setOrdinal(ordinal++); + mf->addAtom(*_null); + } + if (_PLT0) { + _got0->setOrdinal(ordinal++); + _got1->setOrdinal(ordinal++); + mf->addAtom(*_got0); + mf->addAtom(*_got1); + } + for (auto &got : _gotVector) { + got->setOrdinal(ordinal++); + mf->addAtom(*got); + } + for (auto obj : _objectVector) { + obj->setOrdinal(ordinal++); + mf->addAtom(*obj); + } + } + +protected: + /// \brief Owner of all the Atoms created by this pass. + ELFPassFile _file; + const ELFLinkingContext &_ctx; + + /// \brief Map Atoms to their GOT entries. + llvm::DenseMap _gotMap; + + /// \brief Map Atoms to their PLT entries. + llvm::DenseMap _pltMap; + + /// \brief Map Atoms to their Object entries. + llvm::DenseMap _objectMap; + + /// \brief the list of GOT/PLT atoms + std::vector _gotVector; + std::vector _pltVector; + std::vector _objectVector; + + /// \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; + GOTAtom *_got1; + /// @} +}; + +/// This implements the static relocation model. Meaning GOT and PLT entries are +/// not created for references that can be directly resolved. These are +/// converted to a direct relocation. For entries that do require a GOT or PLT +/// entry, that entry is statically bound. +/// +/// TLS always assumes module 1 and attempts to remove indirection. +class AArch64StaticRelocationPass final + : public AArch64RelocationPass { +public: + AArch64StaticRelocationPass(const elf::AArch64LinkingContext &ctx) + : AArch64RelocationPass(ctx) {} + + std::error_code handlePlain(const Reference &ref) { return handleIFUNC(ref); } + + std::error_code handlePLT32(const Reference &ref) { + // __tls_get_addr is handled elsewhere. + if (ref.target() && ref.target()->name() == "__tls_get_addr") { + const_cast(ref).setKindValue(R_AARCH64_NONE); + return std::error_code(); + } + // Static code doesn't need PLTs. + const_cast(ref).setKindValue(R_AARCH64_PREL32); + // Handle IFUNC. + if (const DefinedAtom *da = + dyn_cast_or_null(ref.target())) + if (da->contentType() == DefinedAtom::typeResolver) + return handleIFUNC(ref); + return std::error_code(); + } + + std::error_code handleGOT(const Reference &ref) { + if (isa(ref.target())) + const_cast(ref).setTarget(getNullGOT()); + else if (const DefinedAtom *da = dyn_cast(ref.target())) + const_cast(ref).setTarget(getGOT(da)); + return std::error_code(); + } +}; + +class AArch64DynamicRelocationPass final + : public AArch64RelocationPass { +public: + AArch64DynamicRelocationPass(const elf::AArch64LinkingContext &ctx) + : AArch64RelocationPass(ctx) {} + + const PLT0Atom *getPLT0() { + if (_PLT0) + return _PLT0; + // Fill in the null entry. + getNullGOT(); + _PLT0 = new (_file._alloc) AArch64PLT0Atom(_file); + _got0 = new (_file._alloc) AArch64GOTAtom(_file, ".got.plt"); + _got1 = new (_file._alloc) AArch64GOTAtom(_file, ".got.plt"); + _PLT0->addReferenceELF_AArch64(R_AARCH64_ADR_GOT_PAGE, 4, _got0, 0); + _PLT0->addReferenceELF_AArch64(R_AARCH64_LD64_GOT_LO12_NC, 8, _got1, 0); + _PLT0->addReferenceELF_AArch64(ADD_AARCH64_GOTRELINDEX, 12, _got1, 0); +#ifndef NDEBUG + _got0->_name = "__got0"; + _got1->_name = "__got1"; +#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) AArch64GOTAtom(_file, ".got.plt"); + ga->addReferenceELF_AArch64(R_AARCH64_JUMP_SLOT, 0, a, 0); + auto pa = new (_file._alloc) AArch64PLTAtom(_file, ".plt"); + pa->addReferenceELF_AArch64(R_AARCH64_ADR_GOT_PAGE, 0, ga, 0); + pa->addReferenceELF_AArch64(R_AARCH64_LD64_GOT_LO12_NC, 4, ga, 0); + pa->addReferenceELF_AArch64(ADD_AARCH64_GOTRELINDEX, 8, ga, 0); + pa->addReferenceELF_AArch64(R_AARCH64_NONE, 12, getPLT0(), 0); + // Set the starting address of the got entry to the first instruction in + // the plt0 entry. + ga->addReferenceELF_AArch64(R_AARCH64_ABS32, 0, pa, 0); +#ifndef NDEBUG + ga->_name = "__got_"; + ga->_name += a->name(); + pa->_name = "__plt_"; + pa->_name += a->name(); +#endif + _gotMap[a] = ga; + _pltMap[a] = pa; + _gotVector.push_back(ga); + _pltVector.push_back(pa); + return pa; + } + + const ObjectAtom *getObjectEntry(const SharedLibraryAtom *a) { + auto obj = _objectMap.find(a); + if (obj != _objectMap.end()) + return obj->second; + + auto oa = new (_file._alloc) ObjectAtom(_file); + // This needs to point to the atom that we just created. + oa->addReferenceELF_AArch64(R_AARCH64_COPY, 0, oa, 0); + + oa->_name = a->name(); + oa->_size = a->size(); + + _objectMap[a] = oa; + _objectVector.push_back(oa); + return oa; + } + + std::error_code handlePlain(const Reference &ref) { + if (!ref.target()) + return std::error_code(); + if (auto sla = dyn_cast(ref.target())) { + if (sla->type() == SharedLibraryAtom::Type::Data) + const_cast(ref).setTarget(getObjectEntry(sla)); + else if (sla->type() == SharedLibraryAtom::Type::Code) + const_cast(ref).setTarget(getPLTEntry(sla)); + } else + return handleIFUNC(ref); + return std::error_code(); + } + + std::error_code handlePLT32(const Reference &ref) { + // Turn this into a PC32 to the PLT entry. + const_cast(ref).setKindValue(R_AARCH64_PREL32); + // Handle IFUNC. + if (const DefinedAtom *da = + dyn_cast_or_null(ref.target())) + if (da->contentType() == DefinedAtom::typeResolver) + return handleIFUNC(ref); + if (isa(ref.target())) + const_cast(ref).setTarget(getPLTEntry(ref.target())); + return std::error_code(); + } + + const GOTAtom *getSharedGOT(const SharedLibraryAtom *sla) { + auto got = _gotMap.find(sla); + if (got == _gotMap.end()) { + auto g = new (_file._alloc) AArch64GOTAtom(_file, ".got.dyn"); + g->addReferenceELF_AArch64(R_AARCH64_GLOB_DAT, 0, sla, 0); +#ifndef NDEBUG + g->_name = "__got_"; + g->_name += sla->name(); +#endif + _gotMap[sla] = g; + _gotVector.push_back(g); + return g; + } + return got->second; + } + + std::error_code handleGOT(const Reference &ref) { + if (isa(ref.target())) + const_cast(ref).setTarget(getNullGOT()); + else if (const DefinedAtom *da = dyn_cast(ref.target())) + const_cast(ref).setTarget(getGOT(da)); + else if (const auto sla = dyn_cast(ref.target())) + const_cast(ref).setTarget(getSharedGOT(sla)); + return std::error_code(); + } +}; +} // end anon namespace + +std::unique_ptr +lld::elf::createAArch64RelocationPass(const AArch64LinkingContext &ctx) { + switch (ctx.getOutputELFType()) { + case llvm::ELF::ET_EXEC: + if (ctx.isDynamic()) + return std::unique_ptr(new AArch64DynamicRelocationPass(ctx)); + else + return std::unique_ptr(new AArch64StaticRelocationPass(ctx)); + case llvm::ELF::ET_DYN: + return std::unique_ptr(new AArch64DynamicRelocationPass(ctx)); + case llvm::ELF::ET_REL: + return std::unique_ptr(); + default: + llvm_unreachable("Unhandled output file type"); + } +} Index: lib/ReaderWriter/ELF/AArch64/AArch64Target.h =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/AArch64/AArch64Target.h @@ -0,0 +1,10 @@ +//===- lib/ReaderWriter/ELF/AArch64/AArch64Target.h -----------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "AArch64LinkingContext.h" Index: lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.h =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.h @@ -0,0 +1,57 @@ +//===- lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.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_AARCH64_AARCH64_TARGET_HANDLER_H +#define LLD_READER_WRITER_ELF_AARCH64_AARCH64_TARGET_HANDLER_H + +#include "DefaultTargetHandler.h" +#include "ELFFile.h" +#include "AArch64RelocationHandler.h" +#include "TargetLayout.h" + +#include "lld/Core/Simple.h" + +namespace lld { +namespace elf { +typedef llvm::object::ELFType AArch64ELFType; +class AArch64LinkingContext; + +template class AArch64TargetLayout : public TargetLayout { +public: + AArch64TargetLayout(AArch64LinkingContext &context) + : TargetLayout(context) {} +}; + +class AArch64TargetHandler final : public DefaultTargetHandler { +public: + AArch64TargetHandler(AArch64LinkingContext &context); + + AArch64TargetLayout &getTargetLayout() override { + return *(_AArch64TargetLayout.get()); + } + + void registerRelocationNames(Registry ®istry) override; + + const AArch64TargetRelocationHandler &getRelocationHandler() const override { + return *(_AArch64RelocationHandler.get()); + } + + std::unique_ptr getWriter() override; + +private: + static const Registry::KindStrings kindStrings[]; + AArch64LinkingContext &_context; + std::unique_ptr> _AArch64TargetLayout; + std::unique_ptr _AArch64RelocationHandler; +}; + +} // end namespace elf +} // end namespace lld + +#endif Index: lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.cpp =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.cpp @@ -0,0 +1,129 @@ +//===- lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.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 "AArch64ExecutableWriter.h" +#include "AArch64DynamicLibraryWriter.h" +#include "AArch64TargetHandler.h" +#include "AArch64LinkingContext.h" + +using namespace lld; +using namespace elf; + +AArch64TargetHandler::AArch64TargetHandler(AArch64LinkingContext &context) + : DefaultTargetHandler(context), _context(context), + _AArch64TargetLayout(new AArch64TargetLayout(context)), + _AArch64RelocationHandler( + new AArch64TargetRelocationHandler(*_AArch64TargetLayout.get())) {} + +void AArch64TargetHandler::registerRelocationNames(Registry ®istry) { + registry.addKindTable(Reference::KindNamespace::ELF, + Reference::KindArch::AArch64, kindStrings); +} + +std::unique_ptr AArch64TargetHandler::getWriter() { + switch (this->_context.getOutputELFType()) { + case llvm::ELF::ET_EXEC: + return std::unique_ptr(new AArch64ExecutableWriter( + _context, *_AArch64TargetLayout.get())); + case llvm::ELF::ET_DYN: + return std::unique_ptr( + new AArch64DynamicLibraryWriter( + _context, *_AArch64TargetLayout.get())); + case llvm::ELF::ET_REL: + llvm_unreachable("TODO: support -r mode"); + default: + llvm_unreachable("unsupported output type"); + } +} + +const Registry::KindStrings AArch64TargetHandler::kindStrings[] = { + LLD_KIND_STRING_ENTRY(R_AARCH64_NONE), + LLD_KIND_STRING_ENTRY(R_AARCH64_ABS64), + LLD_KIND_STRING_ENTRY(R_AARCH64_ABS32), + LLD_KIND_STRING_ENTRY(R_AARCH64_ABS16), + LLD_KIND_STRING_ENTRY(R_AARCH64_PREL64), + LLD_KIND_STRING_ENTRY(R_AARCH64_PREL32), + LLD_KIND_STRING_ENTRY(R_AARCH64_PREL16), + LLD_KIND_STRING_ENTRY(R_AARCH64_MOVW_UABS_G0), + LLD_KIND_STRING_ENTRY(R_AARCH64_MOVW_UABS_G0_NC), + LLD_KIND_STRING_ENTRY(R_AARCH64_MOVW_UABS_G1), + LLD_KIND_STRING_ENTRY(R_AARCH64_MOVW_UABS_G1_NC), + LLD_KIND_STRING_ENTRY(R_AARCH64_MOVW_UABS_G2), + LLD_KIND_STRING_ENTRY(R_AARCH64_MOVW_UABS_G2_NC), + LLD_KIND_STRING_ENTRY(R_AARCH64_MOVW_UABS_G3), + LLD_KIND_STRING_ENTRY(R_AARCH64_MOVW_SABS_G0), + LLD_KIND_STRING_ENTRY(R_AARCH64_MOVW_SABS_G1), + LLD_KIND_STRING_ENTRY(R_AARCH64_MOVW_SABS_G2), + LLD_KIND_STRING_ENTRY(R_AARCH64_LD_PREL_LO19), + LLD_KIND_STRING_ENTRY(R_AARCH64_ADR_PREL_LO21), + LLD_KIND_STRING_ENTRY(R_AARCH64_ADR_PREL_PG_HI21), + LLD_KIND_STRING_ENTRY(R_AARCH64_ADD_ABS_LO12_NC), + LLD_KIND_STRING_ENTRY(R_AARCH64_LDST8_ABS_LO12_NC), + LLD_KIND_STRING_ENTRY(R_AARCH64_TSTBR14), + LLD_KIND_STRING_ENTRY(R_AARCH64_CONDBR19), + LLD_KIND_STRING_ENTRY(R_AARCH64_JUMP26), + LLD_KIND_STRING_ENTRY(R_AARCH64_CALL26), + LLD_KIND_STRING_ENTRY(R_AARCH64_LDST16_ABS_LO12_NC), + LLD_KIND_STRING_ENTRY(R_AARCH64_LDST32_ABS_LO12_NC), + LLD_KIND_STRING_ENTRY(R_AARCH64_LDST64_ABS_LO12_NC), + LLD_KIND_STRING_ENTRY(R_AARCH64_LDST128_ABS_LO12_NC), + LLD_KIND_STRING_ENTRY(R_AARCH64_ADR_GOT_PAGE), + LLD_KIND_STRING_ENTRY(R_AARCH64_LD64_GOT_LO12_NC), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSLD_MOVW_DTPREL_G2), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSLD_MOVW_DTPREL_G1), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSLD_MOVW_DTPREL_G0), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSLD_ADD_DTPREL_HI12), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSLD_ADD_DTPREL_LO12), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSLD_LDST8_DTPREL_LO12), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSLD_LDST16_DTPREL_LO12), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSLD_LDST32_DTPREL_LO12), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSLD_LDST64_DTPREL_LO12), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSIE_MOVW_GOTTPREL_G1), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSIE_LD_GOTTPREL_PREL19), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSLE_MOVW_TPREL_G2), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSLE_MOVW_TPREL_G1), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSLE_MOVW_TPREL_G1_NC), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSLE_MOVW_TPREL_G0), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSLE_MOVW_TPREL_G0_NC), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSLE_ADD_TPREL_HI12), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSLE_ADD_TPREL_LO12), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSLE_ADD_TPREL_LO12_NC), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSLE_LDST8_TPREL_LO12), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSLE_LDST16_TPREL_LO12), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSLE_LDST32_TPREL_LO12), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSLE_LDST64_TPREL_LO12), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSDESC_ADR_PAGE), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSDESC_LD64_LO12_NC), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSDESC_ADD_LO12_NC), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSDESC_CALL), + LLD_KIND_STRING_ENTRY(R_AARCH64_COPY), + LLD_KIND_STRING_ENTRY(R_AARCH64_GLOB_DAT), + LLD_KIND_STRING_ENTRY(R_AARCH64_JUMP_SLOT), + LLD_KIND_STRING_ENTRY(R_AARCH64_RELATIVE), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLS_DTPREL64), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLS_DTPMOD64), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLS_TPREL64), + LLD_KIND_STRING_ENTRY(R_AARCH64_TLSDESC), + LLD_KIND_STRING_ENTRY(R_AARCH64_IRELATIVE), + LLD_KIND_STRING_END}; Index: lib/ReaderWriter/ELF/AArch64/CMakeLists.txt =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/AArch64/CMakeLists.txt @@ -0,0 +1,10 @@ +add_lld_library(lldAArch64ELFTarget + AArch64LinkingContext.cpp + AArch64TargetHandler.cpp + AArch64RelocationHandler.cpp + AArch64RelocationPass.cpp + ) + +target_link_libraries(lldAArch64ELFTarget + lldCore + ) Index: lib/ReaderWriter/ELF/AArch64/Makefile =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/AArch64/Makefile @@ -0,0 +1,15 @@ +##===- lld/lib/ReaderWriter/ELF/AArch64/Makefile ----------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LLD_LEVEL := ../../../.. +LIBRARYNAME := lldAArch64ELFTarget +USEDLIBS = lldCore.a +CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF/AArch64 -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF + +include $(LLD_LEVEL)/Makefile Index: lib/ReaderWriter/ELF/AArch64/TODO.rst =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/AArch64/TODO.rst @@ -0,0 +1,15 @@ +ELF AArch64 +~~~~~~~~~~ + +Unimplemented Features +###################### + +* Just about everything! + +Unimplemented Relocations +######################### + +All of these relocations are defined in: +http://infocenter.arm.com/help/topic/com.arm.doc.ihi0056b/IHI0056B_aaelf64.pdf + + Index: lib/ReaderWriter/ELF/Atoms.h =================================================================== --- lib/ReaderWriter/ELF/Atoms.h +++ lib/ReaderWriter/ELF/Atoms.h @@ -679,6 +679,11 @@ Reference::Addend a) { this->addReferenceELF(Reference::KindArch::Mips, relocType, off, t, a); } + + void addReferenceELF_AArch64(uint16_t relocType, uint64_t off, const Atom *t, + Reference::Addend a) { + this->addReferenceELF(Reference::KindArch::AArch64, relocType, off, t, a); + } }; /// \brief Atom which represents an object for which a COPY relocation will be Index: lib/ReaderWriter/ELF/CMakeLists.txt =================================================================== --- lib/ReaderWriter/ELF/CMakeLists.txt +++ lib/ReaderWriter/ELF/CMakeLists.txt @@ -13,6 +13,7 @@ lldReaderWriter lldX86ELFTarget lldX86_64ELFTarget + lldAArch64ELFTarget ) include_directories(.) Index: lib/ReaderWriter/ELF/ELFFile.h =================================================================== --- lib/ReaderWriter/ELF/ELFFile.h +++ lib/ReaderWriter/ELF/ELFFile.h @@ -452,6 +452,8 @@ return Reference::KindArch::Hexagon; case llvm::ELF::EM_MIPS: return Reference::KindArch::Mips; + case llvm::ELF::EM_AARCH64: + return Reference::KindArch::AArch64; } llvm_unreachable("unsupported e_machine value"); } Index: lib/ReaderWriter/ELF/ELFLinkingContext.cpp =================================================================== --- lib/ReaderWriter/ELF/ELFLinkingContext.cpp +++ lib/ReaderWriter/ELF/ELFLinkingContext.cpp @@ -87,6 +87,8 @@ return llvm::ELF::EM_MIPS; case llvm::Triple::ppc: return llvm::ELF::EM_PPC; + case llvm::Triple::aarch64: + return llvm::ELF::EM_AARCH64; default: llvm_unreachable("Unhandled arch"); } @@ -147,6 +149,9 @@ case llvm::Triple::ppc: return std::unique_ptr( new lld::elf::PPCLinkingContext(triple)); + case llvm::Triple::aarch64: + return std::unique_ptr( + new lld::elf::AArch64LinkingContext(triple)); default: return nullptr; } Index: lib/ReaderWriter/ELF/Makefile =================================================================== --- lib/ReaderWriter/ELF/Makefile +++ lib/ReaderWriter/ELF/Makefile @@ -10,12 +10,12 @@ LLD_LEVEL := ../../.. LIBRARYNAME := lldELF USEDLIBS = lldHexagonELFTarget.a lldPPCELFTarget.a lldMipsELFTarget.a \ - lldX86ELFTarget.a lldX86_64ELFTarget.a \ + lldX86ELFTarget.a lldX86_64ELFTarget.a lldAArch64ELFTarget.a \ lldReaderWriter.a lldPasses.a CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF # these link against this lib -PARALLEL_DIRS := Hexagon PPC X86 X86_64 Mips +PARALLEL_DIRS := Hexagon PPC X86 X86_64 Mips AArch64 include $(LLD_LEVEL)/Makefile Index: lib/ReaderWriter/ELF/Targets.h =================================================================== --- lib/ReaderWriter/ELF/Targets.h +++ lib/ReaderWriter/ELF/Targets.h @@ -15,5 +15,6 @@ #include "PPC/PPCTarget.h" #include "X86/X86Target.h" #include "X86_64/X86_64Target.h" +#include "AArch64/AArch64Target.h" #endif Index: test/elf/AArch64/Inputs/fn.c =================================================================== --- /dev/null +++ test/elf/AArch64/Inputs/fn.c @@ -0,0 +1,4 @@ +int fn() +{ + return 0; +} Index: test/elf/AArch64/Inputs/initfini-option.c =================================================================== --- /dev/null +++ test/elf/AArch64/Inputs/initfini-option.c @@ -0,0 +1,12 @@ +#include + +void init() { + printf("%s\n", __FUNCTION__); +} + +void fini() { + printf("%s\n", __FUNCTION__); +} + +int main() { +} Index: test/elf/AArch64/Inputs/initfini.c =================================================================== --- /dev/null +++ test/elf/AArch64/Inputs/initfini.c @@ -0,0 +1,14 @@ +#include + +void __attribute__ ((constructor)) constructor() { + printf("%s\n", __FUNCTION__); +} + +void __attribute__ ((destructor)) destructor() { + printf("%s\n", __FUNCTION__); +} + +int main() { + return 0; +} + Index: test/elf/AArch64/Inputs/main.c =================================================================== --- /dev/null +++ test/elf/AArch64/Inputs/main.c @@ -0,0 +1,4 @@ +int main() { + fn(); + return 0; +} Index: test/elf/AArch64/Inputs/no-interp-section.c =================================================================== --- /dev/null +++ test/elf/AArch64/Inputs/no-interp-section.c @@ -0,0 +1 @@ +int c = 10; Index: test/elf/AArch64/Inputs/zerosizedsection.s =================================================================== --- /dev/null +++ test/elf/AArch64/Inputs/zerosizedsection.s @@ -0,0 +1,3 @@ +.text +.data +.word .text Index: test/elf/AArch64/defsym.test =================================================================== --- /dev/null +++ test/elf/AArch64/defsym.test @@ -0,0 +1,22 @@ +RUN: lld -flavor gnu -target aarch64--linux-gnu --defsym=main=fn \ +RUN: --noinhibit-exec %p/Inputs/fn.o -o %t +RUN: llvm-readobj -symbols %t | FileCheck %s + +CHECK: Symbol { +CHECK: Name: main (1) +CHECK: Value: 0x4001A4 +CHECK: Size: 0 +CHECK: Binding: Global (0x1) +CHECK: Type: Function (0x2) +CHECK: Other: 0 +CHECK: Section: .text (0x5) +CHECK: } +CHECK: Symbol { +CHECK: Name: fn (6) +CHECK: Value: 0x4001A4 +CHECK: Size: 8 +CHECK: Binding: Global (0x1) +CHECK: Type: Function (0x2) +CHECK: Other: 0 +CHECK: Section: .text (0x5) +CHECK: } Index: test/elf/AArch64/dontignorezerosize-sections.test =================================================================== --- /dev/null +++ test/elf/AArch64/dontignorezerosize-sections.test @@ -0,0 +1,9 @@ +# This tests that lld is not ignoring zero sized sections +RUN: lld -flavor gnu -target aarch64--linux-gnu %p/Inputs/zerosizedsection.o \ +RUN: --noinhibit-exec --output-filetype=yaml -o %t +RUN: FileCheck %s < %t + +CHECK: references: +CHECK: - kind: layout-after +CHECK: offset: 0 +CHECK: target: L000 Index: test/elf/AArch64/dynlib-nointerp-section.test =================================================================== --- /dev/null +++ test/elf/AArch64/dynlib-nointerp-section.test @@ -0,0 +1,5 @@ +RUN: lld -flavor gnu -target aarch64--linux-gnu %p/Inputs/no-interp-section.o \ +RUN: -o %t -shared +RUN: llvm-objdump -section-headers %t | FileCheck %s + +CHECK-NOT: .interp Index: test/elf/AArch64/initfini-alignment.test =================================================================== --- /dev/null +++ test/elf/AArch64/initfini-alignment.test @@ -0,0 +1,12 @@ +# This tests the functionality that lld is able to create +# init_array/fini_array sections in the output ELF with the +# right alignment + +RUN: lld -flavor gnu -target aarch64--linux-gnu %p/Inputs/initfini-option.o \ +RUN: -init init -fini fini --noinhibit-exec -o %t +RUN: llvm-readobj -s %t | FileCheck %s + +CHECK: Name: .init_array +CHECK: AddressAlignment: 8 +CHECK: Name: .fini_array +CHECK: AddressAlignment: 8 Index: test/elf/AArch64/initfini-option.test =================================================================== --- /dev/null +++ test/elf/AArch64/initfini-option.test @@ -0,0 +1,22 @@ +# This tests the functionality that lld is able to create +# init_array/fini_array sections in the output ELF. This +# corresponds to the the .init_array/.fini_array sections +# in the output ELF. + +RUN: lld -flavor gnu -target aarch64--linux-gnu %p/Inputs/initfini-option.o \ +RUN: -init init -fini fini --noinhibit-exec --output-filetype=yaml -static -o %t +RUN: FileCheck %s < %t + +CHECK: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ] +CHECK: section-name: .init_array +CHECK: references: +CHECK: - kind: R_AARCH64_ABS64 +CHECK: offset: 0 +CHECK: target: init +CHECK: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ] +CHECK: section-name: .fini_array +CHECK: references: +CHECK: - kind: R_AARCH64_ABS64 +CHECK: offset: 0 +CHECK: target: fini + Index: test/elf/AArch64/initfini.test =================================================================== --- /dev/null +++ test/elf/AArch64/initfini.test @@ -0,0 +1,23 @@ +# This tests the functionality that lld is able to read +# init_array/fini_array sections in the input ELF. This +# corresponds to the the .init_array/.fini_array sections +# in the output ELF. + +RUN: lld -flavor gnu -target aarch64--linu-gnu %p/Inputs/initfini.o \ +RUN: --noinhibit-exec --output-filetype=yaml -o %t +RUN: FileCheck %s < %t + +CHECK: type: data +CHECK: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ] +CHECK: section-name: .init_array +CHECK: references: +CHECK: - kind: R_AARCH64_ABS64 +CHECK: offset: 0 +CHECK: target: constructor +CHECK: type: data +CHECK: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ] +CHECK: section-name: .fini_array +CHECK: references: +CHECK: - kind: R_AARCH64_ABS64 +CHECK: offset: 0 +CHECK: target: destructor Index: tools/lld/Makefile =================================================================== --- tools/lld/Makefile +++ tools/lld/Makefile @@ -23,6 +23,7 @@ lldELF.a lldMachO.a lldPasses.a lldPECOFF.a lldYAML.a \ lldReaderWriter.a lldCore.a lldNative.a \ lldHexagonELFTarget.a lldPPCELFTarget.a lldMipsELFTarget.a \ - lldX86ELFTarget.a lldX86_64ELFTarget.a LLVMOption.a + lldX86ELFTarget.a lldX86_64ELFTarget.a lldAArch64ELFTarget.a \ + LLVMOption.a include $(LLD_LEVEL)/Makefile