summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Fitzgerald <garious@gmail.com>2015-01-21 07:35:48 +0000
committerGreg Fitzgerald <garious@gmail.com>2015-01-21 07:35:48 +0000
commit8a1887f1f1efd32e33b5389715587e85d9592216 (patch)
tree5664bfdccd4d6882f8e03eb3c6c13c05e5e9cee5
parentf38dea1cfa2dba7848aaba79ad9866896e00f0ad (diff)
downloadbcm5719-llvm-8a1887f1f1efd32e33b5389715587e85d9592216.tar.gz
bcm5719-llvm-8a1887f1f1efd32e33b5389715587e85d9592216.zip
[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 <dprotivensky@accesssoftek.com> llvm-svn: 226643
-rw-r--r--lld/docs/open_projects.rst1
-rw-r--r--lld/lib/Driver/GnuLdDriver.cpp4
-rw-r--r--lld/lib/ReaderWriter/ELF/ARM/ARMELFFile.h41
-rw-r--r--lld/lib/ReaderWriter/ELF/ARM/ARMELFReader.h60
-rw-r--r--lld/lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h58
-rw-r--r--lld/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp21
-rw-r--r--lld/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h40
-rw-r--r--lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp109
-rw-r--r--lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h32
-rw-r--r--lld/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp138
-rw-r--r--lld/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.h31
-rw-r--r--lld/lib/ReaderWriter/ELF/ARM/ARMTarget.h10
-rw-r--r--lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp43
-rw-r--r--lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h68
-rw-r--r--lld/lib/ReaderWriter/ELF/ARM/CMakeLists.txt10
-rw-r--r--lld/lib/ReaderWriter/ELF/ARM/Makefile15
-rw-r--r--lld/lib/ReaderWriter/ELF/ARM/TODO.rst20
-rw-r--r--lld/lib/ReaderWriter/ELF/Atoms.h5
-rw-r--r--lld/lib/ReaderWriter/ELF/CMakeLists.txt2
-rw-r--r--lld/lib/ReaderWriter/ELF/ELFLinkingContext.cpp5
-rw-r--r--lld/lib/ReaderWriter/ELF/Targets.h1
-rw-r--r--lld/test/elf/ARM/defsym.test74
-rw-r--r--lld/test/elf/ARM/rel-abs32.test59
-rw-r--r--lld/test/elf/ARM/rel-arm-call.test60
24 files changed, 907 insertions, 0 deletions
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 ELFT> class ARMELFFile : public ELFFile<ELFT> {
+public:
+ ARMELFFile(std::unique_ptr<MemoryBuffer> mb, bool atomizeStrings)
+ : ELFFile<ELFT>(std::move(mb), atomizeStrings) {}
+
+ static ErrorOr<std::unique_ptr<ARMELFFile>>
+ create(std::unique_ptr<MemoryBuffer> mb, bool atomizeStrings) {
+ return std::unique_ptr<ARMELFFile<ELFT>>(
+ new ARMELFFile<ELFT>(std::move(mb), atomizeStrings));
+ }
+};
+
+template <class ELFT> class ARMDynamicFile : public DynamicFile<ELFT> {
+public:
+ ARMDynamicFile(const ARMLinkingContext &context, StringRef name)
+ : DynamicFile<ELFT>(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<llvm::support::little, 2, false> ARMELFType;
+
+struct ARMDynamicFileCreateELFTraits {
+ typedef llvm::ErrorOr<std::unique_ptr<lld::SharedLibraryFile>> result_type;
+
+ template <class ELFT>
+ static result_type create(std::unique_ptr<llvm::MemoryBuffer> mb,
+ bool useUndefines) {
+ return lld::elf::ARMDynamicFile<ELFT>::create(std::move(mb), useUndefines);
+ }
+};
+
+struct ARMELFFileCreateELFTraits {
+ typedef llvm::ErrorOr<std::unique_ptr<lld::File>> result_type;
+
+ template <class ELFT>
+ static result_type create(std::unique_ptr<llvm::MemoryBuffer> mb,
+ bool atomizeStrings) {
+ return lld::elf::ARMELFFile<ELFT>::create(std::move(mb), atomizeStrings);
+ }
+};
+
+class ARMELFObjectReader
+ : public ELFObjectReader<ARMELFType, ARMELFFileCreateELFTraits> {
+public:
+ ARMELFObjectReader(bool atomizeStrings)
+ : ELFObjectReader<ARMELFType, ARMELFFileCreateELFTraits>(
+ atomizeStrings, llvm::ELF::EM_ARM) {}
+};
+
+class ARMELFDSOReader
+ : public ELFDSOReader<ARMELFType, ARMDynamicFileCreateELFTraits> {
+public:
+ ARMELFDSOReader(bool useUndefines)
+ : ELFDSOReader<ARMELFType, ARMDynamicFileCreateELFTraits>(
+ 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 ELFT>
+class ARMExecutableWriter : public ExecutableWriter<ELFT> {
+public:
+ ARMExecutableWriter(ARMLinkingContext &context,
+ ARMTargetLayout<ELFT> &layout);
+
+protected:
+ // Add any runtime files and their atoms to the output
+ bool createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
+
+ void finalizeDefaultAtomValues() override {
+ // Finalize the atom values that are part of the parent.
+ ExecutableWriter<ELFT>::finalizeDefaultAtomValues();
+ }
+
+ void addDefaultAtoms() override {
+ ExecutableWriter<ELFT>::addDefaultAtoms();
+ }
+
+private:
+ ARMLinkingContext &_context;
+ ARMTargetLayout<ELFT> &_armLayout;
+};
+
+template <class ELFT>
+ARMExecutableWriter<ELFT>::ARMExecutableWriter(ARMLinkingContext &context,
+ ARMTargetLayout<ELFT> &layout)
+ : ExecutableWriter<ELFT>(context, layout), _context(context),
+ _armLayout(layout) {}
+
+template <class ELFT>
+bool ARMExecutableWriter<ELFT>::createImplicitFiles(
+ std::vector<std::unique_ptr<File>> &result) {
+ ExecutableWriter<ELFT>::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<TargetHandlerBase>(
+ 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<const llvm::support::little32_t *>(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<const llvm::support::little32_t *>(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<llvm::support::ulittle32_t *>(location) =
+ (uint32_t(*reinterpret_cast<llvm::support::ulittle32_t *>(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<llvm::support::little, 2, false> ARMELFType;
+
+template <class ELFT> 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 Derived> 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<MutableFile> &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<ARMStaticRelocationPass> {
+public:
+ ARMStaticRelocationPass(const elf::ARMLinkingContext &ctx)
+ : ARMRelocationPass(ctx) {}
+};
+
+} // end anon namespace
+
+std::unique_ptr<Pass>
+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<Pass>(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 <memory>
+
+namespace lld {
+class Pass;
+namespace elf {
+class ARMLinkingContext;
+
+/// \brief Create ARM relocation pass for the given linking context.
+std::unique_ptr<Pass> 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<ARMELFType>(context)),
+ _armRelocationHandler(new ARMTargetRelocationHandler()) {}
+
+void ARMTargetHandler::registerRelocationNames(Registry &registry) {
+ registry.addKindTable(Reference::KindNamespace::ELF, Reference::KindArch::ARM,
+ kindStrings);
+}
+
+std::unique_ptr<Writer> ARMTargetHandler::getWriter() {
+ switch (this->_context.getOutputELFType()) {
+ case llvm::ELF::ET_EXEC:
+ return std::unique_ptr<Writer>(
+ new ARMExecutableWriter<ARMELFType>(_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 <map>
+
+namespace lld {
+namespace elf {
+typedef llvm::object::ELFType<llvm::support::little, 2, false> ARMELFType;
+class ARMLinkingContext;
+
+template <class ELFT> class ARMTargetLayout : public TargetLayout<ELFT> {
+public:
+ ARMTargetLayout(ARMLinkingContext &context)
+ : TargetLayout<ELFT>(context) {}
+};
+
+class ARMTargetHandler final : public DefaultTargetHandler<ARMELFType> {
+public:
+ ARMTargetHandler(ARMLinkingContext &context);
+
+ ARMTargetLayout<ARMELFType> &getTargetLayout() override {
+ return *(_armTargetLayout.get());
+ }
+
+ void registerRelocationNames(Registry &registry) override;
+
+ const ARMTargetRelocationHandler &getRelocationHandler() const override {
+ return *(_armRelocationHandler.get());
+ }
+
+ std::unique_ptr<Reader> getObjReader(bool atomizeStrings) override {
+ return std::unique_ptr<Reader>(new ARMELFObjectReader(atomizeStrings));
+ }
+
+ std::unique_ptr<Reader> getDSOReader(bool useShlibUndefines) override {
+ return std::unique_ptr<Reader>(new ARMELFDSOReader(useShlibUndefines));
+ }
+
+ std::unique_ptr<Writer> getWriter() override;
+
+private:
+ static const Registry::KindStrings kindStrings[];
+ ARMLinkingContext &_context;
+ std::unique_ptr<ARMTargetLayout<ARMELFType>> _armTargetLayout;
+ std::unique_ptr<ARMTargetRelocationHandler> _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<ELFLinkingContext>(
new lld::elf::AArch64LinkingContext(triple));
+ case llvm::Triple::arm:
+ return std::unique_ptr<ELFLinkingContext>(
+ 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
+...
OpenPOWER on IntegriCloud