From 8a1887f1f1efd32e33b5389715587e85d9592216 Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Wed, 21 Jan 2015 07:35:48 +0000 Subject: [ELF] Minimal implementation for ARM static linking The code is able to statically link the simplest case of: int main() { return 0; } * Only works with ARM code - no Thumb code, no interwork (-marm -mno-thumb-interwork) * musl libc built with no interwork and no Thumb code Differential Revision: http://reviews.llvm.org/D6716 From: Denis Protivensky llvm-svn: 226643 --- lld/docs/open_projects.rst | 1 + lld/lib/Driver/GnuLdDriver.cpp | 4 + lld/lib/ReaderWriter/ELF/ARM/ARMELFFile.h | 41 ++++++ lld/lib/ReaderWriter/ELF/ARM/ARMELFReader.h | 60 +++++++++ lld/lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h | 58 +++++++++ lld/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp | 21 ++++ lld/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h | 40 ++++++ .../ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp | 109 ++++++++++++++++ .../ReaderWriter/ELF/ARM/ARMRelocationHandler.h | 32 +++++ lld/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp | 138 +++++++++++++++++++++ lld/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.h | 31 +++++ lld/lib/ReaderWriter/ELF/ARM/ARMTarget.h | 10 ++ lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp | 43 +++++++ lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h | 68 ++++++++++ lld/lib/ReaderWriter/ELF/ARM/CMakeLists.txt | 10 ++ lld/lib/ReaderWriter/ELF/ARM/Makefile | 15 +++ lld/lib/ReaderWriter/ELF/ARM/TODO.rst | 20 +++ lld/lib/ReaderWriter/ELF/Atoms.h | 5 + lld/lib/ReaderWriter/ELF/CMakeLists.txt | 2 + lld/lib/ReaderWriter/ELF/ELFLinkingContext.cpp | 5 + lld/lib/ReaderWriter/ELF/Targets.h | 1 + lld/test/elf/ARM/defsym.test | 74 +++++++++++ lld/test/elf/ARM/rel-abs32.test | 59 +++++++++ lld/test/elf/ARM/rel-arm-call.test | 60 +++++++++ 24 files changed, 907 insertions(+) create mode 100644 lld/lib/ReaderWriter/ELF/ARM/ARMELFFile.h create mode 100644 lld/lib/ReaderWriter/ELF/ARM/ARMELFReader.h create mode 100644 lld/lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h create mode 100644 lld/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp create mode 100644 lld/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h create mode 100644 lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp create mode 100644 lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h create mode 100644 lld/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp create mode 100644 lld/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.h create mode 100644 lld/lib/ReaderWriter/ELF/ARM/ARMTarget.h create mode 100644 lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp create mode 100644 lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h create mode 100644 lld/lib/ReaderWriter/ELF/ARM/CMakeLists.txt create mode 100644 lld/lib/ReaderWriter/ELF/ARM/Makefile create mode 100644 lld/lib/ReaderWriter/ELF/ARM/TODO.rst create mode 100644 lld/test/elf/ARM/defsym.test create mode 100644 lld/test/elf/ARM/rel-abs32.test create mode 100644 lld/test/elf/ARM/rel-arm-call.test diff --git a/lld/docs/open_projects.rst b/lld/docs/open_projects.rst index 92a26b0b1d4..eb146c8b754 100644 --- a/lld/docs/open_projects.rst +++ b/lld/docs/open_projects.rst @@ -8,6 +8,7 @@ Open Projects .. include:: ../lib/Driver/TODO.rst .. include:: ../lib/ReaderWriter/ELF/X86_64/TODO.rst .. include:: ../lib/ReaderWriter/ELF/AArch64/TODO.rst +.. include:: ../lib/ReaderWriter/ELF/ARM/TODO.rst .. include:: ../tools/lld/TODO.txt Documentation TODOs diff --git a/lld/lib/Driver/GnuLdDriver.cpp b/lld/lib/Driver/GnuLdDriver.cpp index a91aa8646dd..612a5f256a2 100644 --- a/lld/lib/Driver/GnuLdDriver.cpp +++ b/lld/lib/Driver/GnuLdDriver.cpp @@ -192,6 +192,10 @@ getArchType(const llvm::Triple &triple, StringRef value) { if (value == "aarch64linux") return llvm::Triple::aarch64; return llvm::None; + case llvm::Triple::arm: + if (value == "armelf_linux_eabi") + return llvm::Triple::arm; + return llvm::None; default: return llvm::None; } diff --git a/lld/lib/ReaderWriter/ELF/ARM/ARMELFFile.h b/lld/lib/ReaderWriter/ELF/ARM/ARMELFFile.h new file mode 100644 index 00000000000..bba3bbba9a0 --- /dev/null +++ b/lld/lib/ReaderWriter/ELF/ARM/ARMELFFile.h @@ -0,0 +1,41 @@ +//===--------- lib/ReaderWriter/ELF/ARM/ARMELFFile.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_ARM_ARM_ELF_FILE_H +#define LLD_READER_WRITER_ELF_ARM_ARM_ELF_FILE_H + +#include "ELFReader.h" + +namespace lld { +namespace elf { + +class ARMLinkingContext; + +template class ARMELFFile : public ELFFile { +public: + ARMELFFile(std::unique_ptr mb, bool atomizeStrings) + : ELFFile(std::move(mb), atomizeStrings) {} + + static ErrorOr> + create(std::unique_ptr mb, bool atomizeStrings) { + return std::unique_ptr>( + new ARMELFFile(std::move(mb), atomizeStrings)); + } +}; + +template class ARMDynamicFile : public DynamicFile { +public: + ARMDynamicFile(const ARMLinkingContext &context, StringRef name) + : DynamicFile(context, name) {} +}; + +} // elf +} // lld + +#endif // LLD_READER_WRITER_ELF_ARM_ARM_ELF_FILE_H diff --git a/lld/lib/ReaderWriter/ELF/ARM/ARMELFReader.h b/lld/lib/ReaderWriter/ELF/ARM/ARMELFReader.h new file mode 100644 index 00000000000..9adff8fda02 --- /dev/null +++ b/lld/lib/ReaderWriter/ELF/ARM/ARMELFReader.h @@ -0,0 +1,60 @@ +//===--------- lib/ReaderWriter/ELF/ARM/ARMELFReader.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_ARM_ARM_ELF_READER_H +#define LLD_READER_WRITER_ARM_ARM_ELF_READER_H + +#include "ARMELFFile.h" +#include "ELFReader.h" + +namespace lld { +namespace elf { + +typedef llvm::object::ELFType ARMELFType; + +struct ARMDynamicFileCreateELFTraits { + typedef llvm::ErrorOr> result_type; + + template + static result_type create(std::unique_ptr mb, + bool useUndefines) { + return lld::elf::ARMDynamicFile::create(std::move(mb), useUndefines); + } +}; + +struct ARMELFFileCreateELFTraits { + typedef llvm::ErrorOr> result_type; + + template + static result_type create(std::unique_ptr mb, + bool atomizeStrings) { + return lld::elf::ARMELFFile::create(std::move(mb), atomizeStrings); + } +}; + +class ARMELFObjectReader + : public ELFObjectReader { +public: + ARMELFObjectReader(bool atomizeStrings) + : ELFObjectReader( + atomizeStrings, llvm::ELF::EM_ARM) {} +}; + +class ARMELFDSOReader + : public ELFDSOReader { +public: + ARMELFDSOReader(bool useUndefines) + : ELFDSOReader( + useUndefines, llvm::ELF::EM_ARM) {} +}; + +} // namespace elf +} // namespace lld + +#endif // LLD_READER_WRITER_ARM_ARM_ELF_READER_H diff --git a/lld/lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h b/lld/lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h new file mode 100644 index 00000000000..f2733d2fe8c --- /dev/null +++ b/lld/lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h @@ -0,0 +1,58 @@ +//===--------- lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.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_ARM_ARM_EXECUTABLE_WRITER_H +#define LLD_READER_WRITER_ELF_ARM_ARM_EXECUTABLE_WRITER_H + +#include "ExecutableWriter.h" +#include "ARMLinkingContext.h" + +namespace lld { +namespace elf { + +template +class ARMExecutableWriter : public ExecutableWriter { +public: + ARMExecutableWriter(ARMLinkingContext &context, + ARMTargetLayout &layout); + +protected: + // Add any runtime files and their atoms to the output + bool createImplicitFiles(std::vector> &) override; + + void finalizeDefaultAtomValues() override { + // Finalize the atom values that are part of the parent. + ExecutableWriter::finalizeDefaultAtomValues(); + } + + void addDefaultAtoms() override { + ExecutableWriter::addDefaultAtoms(); + } + +private: + ARMLinkingContext &_context; + ARMTargetLayout &_armLayout; +}; + +template +ARMExecutableWriter::ARMExecutableWriter(ARMLinkingContext &context, + ARMTargetLayout &layout) + : ExecutableWriter(context, layout), _context(context), + _armLayout(layout) {} + +template +bool ARMExecutableWriter::createImplicitFiles( + std::vector> &result) { + ExecutableWriter::createImplicitFiles(result); + return true; +} + +} // namespace elf +} // namespace lld + +#endif // LLD_READER_WRITER_ELF_ARM_ARM_EXECUTABLE_WRITER_H diff --git a/lld/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp b/lld/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp new file mode 100644 index 00000000000..269f3f8f8a7 --- /dev/null +++ b/lld/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp @@ -0,0 +1,21 @@ +//===--------- lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp -------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ARMLinkingContext.h" +#include "ARMRelocationPass.h" + +using namespace lld; +using namespace lld::elf; + +void elf::ARMLinkingContext::addPasses(PassManager &pm) { + auto pass = createARMRelocationPass(*this); + if (pass) + pm.add(std::move(pass)); + ELFLinkingContext::addPasses(pm); +} diff --git a/lld/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h b/lld/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h new file mode 100644 index 00000000000..783eca62eae --- /dev/null +++ b/lld/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h @@ -0,0 +1,40 @@ +//===--------- lib/ReaderWriter/ELF/ARM/ARMLinkingContext.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_ARM_ARM_LINKING_CONTEXT_H +#define LLD_READER_WRITER_ELF_ARM_ARM_LINKING_CONTEXT_H + +#include "ARMTargetHandler.h" + +#include "lld/ReaderWriter/ELFLinkingContext.h" + +#include "llvm/Object/ELF.h" +#include "llvm/Support/ELF.h" + +namespace lld { +namespace elf { + +class ARMLinkingContext final : public ELFLinkingContext { +public: + ARMLinkingContext(llvm::Triple triple) + : ELFLinkingContext(triple, std::unique_ptr( + new ARMTargetHandler(*this))) {} + + void addPasses(PassManager &) override; + + uint64_t getBaseAddress() const override { + if (_baseAddress == 0) + return 0x400000; + return _baseAddress; + } +}; +} // end namespace elf +} // end namespace lld + +#endif diff --git a/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp b/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp new file mode 100644 index 00000000000..e3e1d837ca1 --- /dev/null +++ b/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp @@ -0,0 +1,109 @@ +//===--------- lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp ----------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ARMTargetHandler.h" +#include "ARMLinkingContext.h" + +#include "llvm/Support/Debug.h" +#include "llvm/Support/MathExtras.h" + +using namespace lld; +using namespace elf; + +static Reference::Addend readAddend_ARM_CALL(const uint8_t *location) { + const auto value = int32_t( + *reinterpret_cast(location)); + + const bool isBLX = (value & 0xF0000000) == 0xF0000000; + const int32_t bitH = isBLX ? ((value & 0x1000000) >> 24) : 0; + + const int32_t result = ((value & 0xFFFFFF) << 2) | (bitH << 1); + return llvm::SignExtend64<26>(result); +} + +static Reference::Addend readAddend(const uint8_t *location, + Reference::KindValue kindValue) { + switch (kindValue) { + case R_ARM_ABS32: + return int32_t( + *reinterpret_cast(location)); + case R_ARM_CALL: + return readAddend_ARM_CALL(location); + default: + return 0; + } +} + +static inline void applyArmReloc(uint8_t *location, uint32_t result, + uint32_t mask = 0xFFFFFFFF) { + assert(!(result & ~mask)); + *reinterpret_cast(location) = + (uint32_t(*reinterpret_cast(location)) & + ~mask) | (result & mask); +} + +/// \brief R_ARM_ABS32 - (S + A) | T => S + A +static void relocR_ARM_ABS32(uint8_t *location, uint64_t P, uint64_t S, + int64_t A) { + uint32_t result = (uint32_t)(S + A); + DEBUG_WITH_TYPE( + "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; + 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"); + applyArmReloc(location, result); +} + +/// \brief R_ARM_CALL - ((S + A) | T) - P => S + A - P +static void relocR_ARM_CALL(uint8_t *location, uint64_t P, uint64_t S, + int64_t A) { + uint32_t result = (uint32_t)((S + A) - P); + const uint32_t imm24 = (result & 0x03FFFFFC) >> 2; + + DEBUG_WITH_TYPE( + "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; + 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"); + applyArmReloc(location, imm24, 0xFFFFFF); +} + +std::error_code ARMTargetRelocationHandler::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::ARM); + + // Calculate proper initial addend for the relocation + const Reference::Addend addend = + readAddend(location, ref.kindValue()); + + switch (ref.kindValue()) { + case R_ARM_NONE: + break; + case R_ARM_ABS32: + relocR_ARM_ABS32(location, relocVAddress, targetVAddress, addend); + break; + case R_ARM_CALL: + relocR_ARM_CALL(location, relocVAddress, targetVAddress, addend); + break; + default: + make_unhandled_reloc_error(); + } + + return std::error_code(); +} diff --git a/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h b/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h new file mode 100644 index 00000000000..2f43b852280 --- /dev/null +++ b/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h @@ -0,0 +1,32 @@ +//===--------- lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.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_ARM_ARM_RELOCATION_HANDLER_H +#define LLD_READER_WRITER_ELF_ARM_ARM_RELOCATION_HANDLER_H + +#include "ARMTargetHandler.h" + +namespace lld { +namespace elf { +typedef llvm::object::ELFType ARMELFType; + +template class ARMTargetLayout; + +class ARMTargetRelocationHandler final + : public TargetRelocationHandler { +public: + std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &, + const lld::AtomLayout &, + const Reference &) const override; +}; + +} // end namespace elf +} // end namespace lld + +#endif // LLD_READER_WRITER_ELF_ARM_ARM_RELOCATION_HANDLER_H diff --git a/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp b/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp new file mode 100644 index 00000000000..e1c540ae73b --- /dev/null +++ b/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp @@ -0,0 +1,138 @@ +//===--------- lib/ReaderWriter/ELF/ARM/ARMRelocationPass.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 ARM. 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 "ARMRelocationPass.h" + +#include "lld/Core/Simple.h" + +#include "llvm/ADT/DenseMap.h" + +#include "Atoms.h" +#include "ARMLinkingContext.h" +#include "llvm/Support/Debug.h" + +using namespace lld; +using namespace lld::elf; +using namespace llvm::ELF; + +namespace { +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 ARMRelocationPass : public Pass { + /// \brief Handle a specific reference. + void handleReference(const DefinedAtom &atom, const Reference &ref) { + DEBUG_WITH_TYPE( + "ARM", llvm::dbgs() << "\t" << LLVM_FUNCTION_NAME << "()" + << ": 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::ARM); + switch (ref.kindValue()) { + } + } + +protected: +public: + ARMRelocationPass(const ELFLinkingContext &ctx) + : _file(ctx), _ctx(ctx) {} + + /// \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(), "ARM GOT/PLT Pass"); + DEBUG_WITH_TYPE( + "ARM", 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"; + } + + llvm::dbgs() << "Defined Atoms" << "\n"; + for (const auto &atom + : mf->defined()) { + llvm::dbgs() << " Name of Atom: " << atom->name().str() << "\n"; + }); + + // Process all references. + for (const auto &atom : mf->defined()) { + for (const auto &ref : *atom) { + handleReference(*atom, *ref); + } + } + } + +protected: + /// \brief Owner of all the Atoms created by this pass. + ELFPassFile _file; + const ELFLinkingContext &_ctx; +}; + +/// 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 ARMStaticRelocationPass final + : public ARMRelocationPass { +public: + ARMStaticRelocationPass(const elf::ARMLinkingContext &ctx) + : ARMRelocationPass(ctx) {} +}; + +} // end anon namespace + +std::unique_ptr +lld::elf::createARMRelocationPass(const ARMLinkingContext &ctx) { + switch (ctx.getOutputELFType()) { + case llvm::ELF::ET_EXEC: + if (ctx.isDynamic()) + llvm_unreachable("Unhandled output file type"); + else + return std::unique_ptr(new ARMStaticRelocationPass(ctx)); + default: + llvm_unreachable("Unhandled output file type"); + } +} diff --git a/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.h b/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.h new file mode 100644 index 00000000000..651e798f33b --- /dev/null +++ b/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.h @@ -0,0 +1,31 @@ +//===--------- lib/ReaderWriter/ELF/ARM/ARMRelocationPass.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 ARM. This includes +/// GOT and PLT entries, TLS, COPY, and ifunc. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READER_WRITER_ELF_ARM_ARM_RELOCATION_PASS_H +#define LLD_READER_WRITER_ELF_ARM_ARM_RELOCATION_PASS_H + +#include + +namespace lld { +class Pass; +namespace elf { +class ARMLinkingContext; + +/// \brief Create ARM relocation pass for the given linking context. +std::unique_ptr createARMRelocationPass(const ARMLinkingContext &); +} +} + +#endif diff --git a/lld/lib/ReaderWriter/ELF/ARM/ARMTarget.h b/lld/lib/ReaderWriter/ELF/ARM/ARMTarget.h new file mode 100644 index 00000000000..5b9478f8cbc --- /dev/null +++ b/lld/lib/ReaderWriter/ELF/ARM/ARMTarget.h @@ -0,0 +1,10 @@ +//===--------- lib/ReaderWriter/ELF/ARM/ARMTarget.h -----------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ARMLinkingContext.h" diff --git a/lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp b/lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp new file mode 100644 index 00000000000..5a2f32aa00e --- /dev/null +++ b/lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp @@ -0,0 +1,43 @@ +//===--------- lib/ReaderWriter/ELF/ARM/ARMTargetHandler.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 "ARMExecutableWriter.h" +#include "ARMTargetHandler.h" +#include "ARMLinkingContext.h" + +using namespace lld; +using namespace elf; + +ARMTargetHandler::ARMTargetHandler(ARMLinkingContext &context) + : _context(context), _armTargetLayout( + new ARMTargetLayout(context)), + _armRelocationHandler(new ARMTargetRelocationHandler()) {} + +void ARMTargetHandler::registerRelocationNames(Registry ®istry) { + registry.addKindTable(Reference::KindNamespace::ELF, Reference::KindArch::ARM, + kindStrings); +} + +std::unique_ptr ARMTargetHandler::getWriter() { + switch (this->_context.getOutputELFType()) { + case llvm::ELF::ET_EXEC: + return std::unique_ptr( + new ARMExecutableWriter(_context, *_armTargetLayout.get())); + default: + llvm_unreachable("unsupported output type"); + } +} + +#define ELF_RELOC(name, value) LLD_KIND_STRING_ENTRY(name), + +const Registry::KindStrings ARMTargetHandler::kindStrings[] = { +#include "llvm/Support/ELFRelocs/ARM.def" + LLD_KIND_STRING_END +}; diff --git a/lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h b/lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h new file mode 100644 index 00000000000..02b00b06cb2 --- /dev/null +++ b/lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h @@ -0,0 +1,68 @@ +//===--------- lib/ReaderWriter/ELF/ARM/ARMTargetHandler.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_ARM_ARM_TARGET_HANDLER_H +#define LLD_READER_WRITER_ELF_ARM_ARM_TARGET_HANDLER_H + +#include "ARMELFFile.h" +#include "ARMELFReader.h" +#include "ARMRelocationHandler.h" +#include "DefaultTargetHandler.h" +#include "TargetLayout.h" + +#include "lld/Core/Simple.h" +#include "llvm/ADT/Optional.h" +#include + +namespace lld { +namespace elf { +typedef llvm::object::ELFType ARMELFType; +class ARMLinkingContext; + +template class ARMTargetLayout : public TargetLayout { +public: + ARMTargetLayout(ARMLinkingContext &context) + : TargetLayout(context) {} +}; + +class ARMTargetHandler final : public DefaultTargetHandler { +public: + ARMTargetHandler(ARMLinkingContext &context); + + ARMTargetLayout &getTargetLayout() override { + return *(_armTargetLayout.get()); + } + + void registerRelocationNames(Registry ®istry) override; + + const ARMTargetRelocationHandler &getRelocationHandler() const override { + return *(_armRelocationHandler.get()); + } + + std::unique_ptr getObjReader(bool atomizeStrings) override { + return std::unique_ptr(new ARMELFObjectReader(atomizeStrings)); + } + + std::unique_ptr getDSOReader(bool useShlibUndefines) override { + return std::unique_ptr(new ARMELFDSOReader(useShlibUndefines)); + } + + std::unique_ptr getWriter() override; + +private: + static const Registry::KindStrings kindStrings[]; + ARMLinkingContext &_context; + std::unique_ptr> _armTargetLayout; + std::unique_ptr _armRelocationHandler; +}; + +} // end namespace elf +} // end namespace lld + +#endif // LLD_READER_WRITER_ELF_ARM_ARM_TARGET_HANDLER_H diff --git a/lld/lib/ReaderWriter/ELF/ARM/CMakeLists.txt b/lld/lib/ReaderWriter/ELF/ARM/CMakeLists.txt new file mode 100644 index 00000000000..571928f186a --- /dev/null +++ b/lld/lib/ReaderWriter/ELF/ARM/CMakeLists.txt @@ -0,0 +1,10 @@ +add_lld_library(lldARMELFTarget + ARMLinkingContext.cpp + ARMTargetHandler.cpp + ARMRelocationHandler.cpp + ARMRelocationPass.cpp + ) + +target_link_libraries(lldARMELFTarget ${cmake_2_8_12_INTERFACE} + lldCore + ) diff --git a/lld/lib/ReaderWriter/ELF/ARM/Makefile b/lld/lib/ReaderWriter/ELF/ARM/Makefile new file mode 100644 index 00000000000..f67d36a1b61 --- /dev/null +++ b/lld/lib/ReaderWriter/ELF/ARM/Makefile @@ -0,0 +1,15 @@ +##===------ lld/lib/ReaderWriter/ELF/ARM/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 := lldARMELFTarget +USEDLIBS = lldCore.a +CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF/ARM -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF + +include $(LLD_LEVEL)/Makefile diff --git a/lld/lib/ReaderWriter/ELF/ARM/TODO.rst b/lld/lib/ReaderWriter/ELF/ARM/TODO.rst new file mode 100644 index 00000000000..d05419decb7 --- /dev/null +++ b/lld/lib/ReaderWriter/ELF/ARM/TODO.rst @@ -0,0 +1,20 @@ +ELF ARM +~~~~~~~~~~~ + +Unimplemented Features +###################### + +* Static executable linking - in progress +* Dynamic executable linking +* DSO linking +* PLT entries' generation for images larger than 2^28 bytes (see Sec. A.3 of the ELF reference) +* ARM and Thumb interworking (see http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0203j/Bcghfebi.html) +* .ARM.exidx section handling +* -init/-fini options +* Lots of relocations + +Unimplemented Relocations +######################### + +All of these relocations are defined in: +http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044e/IHI0044E_aaelf.pdf diff --git a/lld/lib/ReaderWriter/ELF/Atoms.h b/lld/lib/ReaderWriter/ELF/Atoms.h index 1aed34698f7..1cad03a13b3 100644 --- a/lld/lib/ReaderWriter/ELF/Atoms.h +++ b/lld/lib/ReaderWriter/ELF/Atoms.h @@ -682,6 +682,11 @@ public: Reference::Addend a) { this->addReferenceELF(Reference::KindArch::AArch64, relocType, off, t, a); } + + void addReferenceELF_ARM(uint16_t relocType, uint64_t off, const Atom *t, + Reference::Addend a) { + this->addReferenceELF(Reference::KindArch::ARM, relocType, off, t, a); + } }; /// \brief Atom which represents an object for which a COPY relocation will be diff --git a/lld/lib/ReaderWriter/ELF/CMakeLists.txt b/lld/lib/ReaderWriter/ELF/CMakeLists.txt index cdca07bec5b..f374a8fd1af 100644 --- a/lld/lib/ReaderWriter/ELF/CMakeLists.txt +++ b/lld/lib/ReaderWriter/ELF/CMakeLists.txt @@ -14,6 +14,7 @@ target_link_libraries(lldELF ${cmake_2_8_12_INTERFACE} lldX86ELFTarget lldX86_64ELFTarget lldAArch64ELFTarget + lldARMELFTarget ) include_directories(.) @@ -24,3 +25,4 @@ add_subdirectory(PPC) add_subdirectory(Mips) add_subdirectory(Hexagon) add_subdirectory(AArch64) +add_subdirectory(ARM) diff --git a/lld/lib/ReaderWriter/ELF/ELFLinkingContext.cpp b/lld/lib/ReaderWriter/ELF/ELFLinkingContext.cpp index 0b7b4b0a9be..ff80e30bb5a 100644 --- a/lld/lib/ReaderWriter/ELF/ELFLinkingContext.cpp +++ b/lld/lib/ReaderWriter/ELF/ELFLinkingContext.cpp @@ -85,6 +85,8 @@ uint16_t ELFLinkingContext::getOutputMachine() const { return llvm::ELF::EM_PPC; case llvm::Triple::aarch64: return llvm::ELF::EM_AARCH64; + case llvm::Triple::arm: + return llvm::ELF::EM_ARM; default: llvm_unreachable("Unhandled arch"); } @@ -148,6 +150,9 @@ ELFLinkingContext::create(llvm::Triple triple) { case llvm::Triple::aarch64: return std::unique_ptr( new lld::elf::AArch64LinkingContext(triple)); + case llvm::Triple::arm: + return std::unique_ptr( + new lld::elf::ARMLinkingContext(triple)); default: return nullptr; } diff --git a/lld/lib/ReaderWriter/ELF/Targets.h b/lld/lib/ReaderWriter/ELF/Targets.h index 0c1f3da326f..94d7b6c8f1f 100644 --- a/lld/lib/ReaderWriter/ELF/Targets.h +++ b/lld/lib/ReaderWriter/ELF/Targets.h @@ -11,6 +11,7 @@ #define LLD_READER_WRITER_ELF_TARGETS_H #include "AArch64/AArch64Target.h" +#include "ARM/ARMTarget.h" #include "Hexagon/HexagonTarget.h" #include "Mips/MipsTarget.h" #include "PPC/PPCTarget.h" diff --git a/lld/test/elf/ARM/defsym.test b/lld/test/elf/ARM/defsym.test new file mode 100644 index 00000000000..d7cb8f3249d --- /dev/null +++ b/lld/test/elf/ARM/defsym.test @@ -0,0 +1,74 @@ +# Check that defined symbols are present in the generated executable + +# RUN: yaml2obj -format=elf %s > %t-o.o +# RUN: lld -flavor gnu -target arm-linux-gnu --defsym=main=fn -e=fn \ +# RUN: -static --noinhibit-exec %t-o.o -o %t +# RUN: llvm-readobj -symbols %t | FileCheck %s + +# CHECK: Symbol { +# CHECK: Name: main (1) +# CHECK: Value: 0x400075 +# CHECK: Size: 0 +# CHECK: Binding: Global (0x1) +# CHECK: Type: Function (0x2) +# CHECK: Other: 0 +# CHECK: Section: .text (0x1) +# CHECK: } +# CHECK: Symbol { +# CHECK: Name: fn (6) +# CHECK: Value: 0x400075 +# CHECK: Size: 15 +# CHECK: Binding: Global (0x1) +# CHECK: Type: Function (0x2) +# CHECK: Other: 0 +# CHECK: Section: .text (0x1) +# CHECK: } + +--- +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_ARM + Flags: [ EF_ARM_EABI_VER5 ] +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 0x0000000000000004 + Content: 80B400AF00231846BD465DF8047B7047 + - Name: .data + Type: SHT_PROGBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + AddressAlign: 0x0000000000000001 + Content: '' + - Name: .bss + Type: SHT_NOBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + AddressAlign: 0x0000000000000001 + Content: '' + - Name: .note.GNU-stack + Type: SHT_PROGBITS + AddressAlign: 0x0000000000000001 + Content: '' +Symbols: + Local: + - Name: .text + Type: STT_SECTION + Section: .text + - Name: .data + Type: STT_SECTION + Section: .data + - Name: .bss + Type: STT_SECTION + Section: .bss + - Name: .note.GNU-stack + Type: STT_SECTION + Section: .note.GNU-stack + Global: + - Name: fn + Type: STT_FUNC + Section: .text + Value: 0x0000000000000001 + Size: 0x0000000000000010 +... diff --git a/lld/test/elf/ARM/rel-abs32.test b/lld/test/elf/ARM/rel-abs32.test new file mode 100644 index 00000000000..00be6209020 --- /dev/null +++ b/lld/test/elf/ARM/rel-abs32.test @@ -0,0 +1,59 @@ +# Check handling of R_ARM_ABS32 relocation. +# RUN: yaml2obj -format=elf %s > %t-o.o +# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \ +# RUN: --noinhibit-exec %t-o.o -o %t +# RUN: llvm-objdump -s -t %t | FileCheck %s + +# CHECK: Contents of section .data: +# CHECK-NEXT: 401000 84004000 +# data = 0x400084 ^^ +# data main addr content +# 0x400084 = 0x400074 + 0x10 +# CHECK: SYMBOL TABLE: +# CHECK: 00400074 g F .text 0000001c main +# CHECK: 00401000 g .data 00000004 data + +--- +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_ARM + Flags: [ EF_ARM_EABI_VER5 ] +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 0x0000000000000004 + Content: 04B02DE500B08DE20030A0E30300A0E100D04BE204B09DE41EFF2FE1 + - Name: .data + Type: SHT_PROGBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + AddressAlign: 0x0000000000000004 + Content: '10000000' + - Name: .rel.data + Type: SHT_REL + Link: .symtab + AddressAlign: 0x0000000000000004 + Info: .data + Relocations: + - Offset: 0x0000000000000000 + Symbol: main + Type: R_ARM_ABS32 + Addend: 0 + - Name: .bss + Type: SHT_NOBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + AddressAlign: 0x0000000000000001 + Content: '' +Symbols: + Global: + - Name: main + Type: STT_FUNC + Section: .text + Size: 0x000000000000001C + - Name: data + Type: STT_OBJECT + Section: .data + Size: 0x0000000000000004 +... diff --git a/lld/test/elf/ARM/rel-arm-call.test b/lld/test/elf/ARM/rel-arm-call.test new file mode 100644 index 00000000000..bee2e468880 --- /dev/null +++ b/lld/test/elf/ARM/rel-arm-call.test @@ -0,0 +1,60 @@ +# Check handling of R_ARM_CALL relocation. +# RUN: yaml2obj -format=elf %s > %t-o.o +# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \ +# RUN: --noinhibit-exec %t-o.o -o %t +# RUN: llvm-objdump -s -t %t | FileCheck %s + +# CHECK: Contents of section .text: +# CHECK: 400084 1eff2fe1 00482de9 04b08de2 f7ffffeb +# offset = -0x24 ^^ +# call site offset PC(arm) _Z1fv addr +# 0x400090 + (-0x24) + 0x8 = 0x400074 +# CHECK: SYMBOL TABLE: +# CHECK: 00400074 g F .text 00000014 _Z1fv +# CHECK: 00400088 g F .text 00000018 main + +--- +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_ARM + Flags: [ EF_ARM_EABI_VER5 ] +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 0x0000000000000004 + Content: 04B02DE500B08DE200D04BE204B09DE41EFF2FE100482DE904B08DE2FEFFFFEB0030A0E30300A0E10088BDE8 + - Name: .rel.text + Type: SHT_REL + Link: .symtab + AddressAlign: 0x0000000000000004 + Info: .text + Relocations: + - Offset: 0x000000000000001C + Symbol: _Z1fv + Type: R_ARM_CALL + Addend: 0 + - Name: .data + Type: SHT_PROGBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + AddressAlign: 0x0000000000000001 + Content: '' + - Name: .bss + Type: SHT_NOBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + AddressAlign: 0x0000000000000001 + Content: '' +Symbols: + Global: + - Name: _Z1fv + Type: STT_FUNC + Section: .text + Size: 0x0000000000000014 + - Name: main + Type: STT_FUNC + Section: .text + Value: 0x0000000000000014 + Size: 0x0000000000000018 +... -- cgit v1.2.1