summaryrefslogtreecommitdiff
path: root/lib/ReaderWriter/ELF
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2015-03-24 21:31:36 +0000
committerDimitry Andric <dim@FreeBSD.org>2015-03-24 21:31:36 +0000
commitfb911942f1434f3d1750f83f25f5e42c80e60638 (patch)
tree1678c4a4f0182e4029a86d135aa4a1b7d09e3c41 /lib/ReaderWriter/ELF
Notes
Diffstat (limited to 'lib/ReaderWriter/ELF')
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64DynamicLibraryWriter.h69
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64ELFFile.h41
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64ELFReader.h62
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.h68
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.cpp33
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.h95
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.cpp440
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.h33
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.cpp527
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.h32
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.cpp52
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.h64
-rw-r--r--lib/ReaderWriter/ELF/AArch64/CMakeLists.txt12
-rw-r--r--lib/ReaderWriter/ELF/AArch64/Makefile15
-rw-r--r--lib/ReaderWriter/ELF/AArch64/TODO.rst15
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMELFFile.h97
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMELFReader.h62
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h121
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp34
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h36
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp500
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h38
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp373
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMRelocationPass.h31
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h46
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp44
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h88
-rw-r--r--lib/ReaderWriter/ELF/ARM/CMakeLists.txt12
-rw-r--r--lib/ReaderWriter/ELF/ARM/Makefile15
-rw-r--r--lib/ReaderWriter/ELF/ARM/TODO.rst20
-rw-r--r--lib/ReaderWriter/ELF/Atoms.h849
-rw-r--r--lib/ReaderWriter/ELF/CMakeLists.txt19
-rw-r--r--lib/ReaderWriter/ELF/Chunk.h102
-rw-r--r--lib/ReaderWriter/ELF/CreateELF.h118
-rw-r--r--lib/ReaderWriter/ELF/DefaultLayout.h1050
-rw-r--r--lib/ReaderWriter/ELF/DefaultTargetHandler.h38
-rw-r--r--lib/ReaderWriter/ELF/DynamicFile.h123
-rw-r--r--lib/ReaderWriter/ELF/DynamicLibraryWriter.h96
-rw-r--r--lib/ReaderWriter/ELF/ELFFile.h1179
-rw-r--r--lib/ReaderWriter/ELF/ELFLinkingContext.cpp259
-rw-r--r--lib/ReaderWriter/ELF/ELFReader.h102
-rw-r--r--lib/ReaderWriter/ELF/ExecutableWriter.h182
-rw-r--r--lib/ReaderWriter/ELF/HeaderChunks.h364
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/CMakeLists.txt11
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonDynamicLibraryWriter.h79
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonELFFile.h170
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonELFReader.h62
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonELFWriters.h61
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonEncodings.h601
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonExecutableAtoms.h29
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonExecutableWriter.h86
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.cpp25
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.h69
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonRelocationFunctions.h49
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.cpp350
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.h35
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonSectionChunks.h86
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.cpp334
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.h143
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/Makefile16
-rw-r--r--lib/ReaderWriter/ELF/Layout.h59
-rw-r--r--lib/ReaderWriter/ELF/Makefile18
-rw-r--r--lib/ReaderWriter/ELF/Mips/CMakeLists.txt14
-rw-r--r--lib/ReaderWriter/ELF/Mips/Makefile15
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.cpp73
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.h25
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsDynamicLibraryWriter.h101
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsDynamicTable.h115
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsELFFile.h331
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsELFFlagsMerger.cpp149
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsELFFlagsMerger.h36
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsELFReader.h93
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsELFWriters.h82
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsExecutableWriter.h154
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp115
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h68
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp606
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.h31
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp1070
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsRelocationPass.h25
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h170
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp35
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h257
-rw-r--r--lib/ReaderWriter/ELF/OrderPass.h30
-rw-r--r--lib/ReaderWriter/ELF/OutputELFWriter.h615
-rw-r--r--lib/ReaderWriter/ELF/Reader.cpp43
-rw-r--r--lib/ReaderWriter/ELF/SectionChunks.h1498
-rw-r--r--lib/ReaderWriter/ELF/SegmentChunks.h686
-rw-r--r--lib/ReaderWriter/ELF/TODO.txt18
-rw-r--r--lib/ReaderWriter/ELF/TargetHandler.h86
-rw-r--r--lib/ReaderWriter/ELF/TargetLayout.h28
-rw-r--r--lib/ReaderWriter/ELF/Writer.cpp23
-rw-r--r--lib/ReaderWriter/ELF/Writer.h38
-rw-r--r--lib/ReaderWriter/ELF/X86/CMakeLists.txt11
-rw-r--r--lib/ReaderWriter/ELF/X86/Makefile15
-rw-r--r--lib/ReaderWriter/ELF/X86/X86DynamicLibraryWriter.h67
-rw-r--r--lib/ReaderWriter/ELF/X86/X86ELFFile.h41
-rw-r--r--lib/ReaderWriter/ELF/X86/X86ELFReader.h62
-rw-r--r--lib/ReaderWriter/ELF/X86/X86ExecutableWriter.h57
-rw-r--r--lib/ReaderWriter/ELF/X86/X86LinkingContext.cpp28
-rw-r--r--lib/ReaderWriter/ELF/X86/X86LinkingContext.h42
-rw-r--r--lib/ReaderWriter/ELF/X86/X86RelocationHandler.cpp57
-rw-r--r--lib/ReaderWriter/ELF/X86/X86RelocationHandler.h29
-rw-r--r--lib/ReaderWriter/ELF/X86/X86TargetHandler.cpp53
-rw-r--r--lib/ReaderWriter/ELF/X86/X86TargetHandler.h63
-rw-r--r--lib/ReaderWriter/ELF/X86_64/CMakeLists.txt16
-rw-r--r--lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/CMakeLists.txt11
-rw-r--r--lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleLinkingContext.cpp35
-rw-r--r--lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleLinkingContext.h31
-rw-r--r--lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleTargetHandler.cpp23
-rw-r--r--lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleTargetHandler.h31
-rw-r--r--lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/Makefile15
-rw-r--r--lib/ReaderWriter/ELF/X86_64/Makefile19
-rw-r--r--lib/ReaderWriter/ELF/X86_64/TODO.rst46
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64DynamicLibraryWriter.h63
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64ELFFile.h41
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64ELFReader.h62
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64ElfType.h21
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64ExecutableWriter.h61
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp38
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h100
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp151
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.h39
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp513
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.h32
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.cpp52
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h69
127 files changed, 18463 insertions, 0 deletions
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64DynamicLibraryWriter.h b/lib/ReaderWriter/ELF/AArch64/AArch64DynamicLibraryWriter.h
new file mode 100644
index 0000000000000..12ba52a38f380
--- /dev/null
+++ b/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 "AArch64LinkingContext.h"
+#include "AArch64TargetHandler.h"
+#include "DynamicLibraryWriter.h"
+
+namespace lld {
+namespace elf {
+
+template <class ELFT>
+class AArch64DynamicLibraryWriter : public DynamicLibraryWriter<ELFT> {
+public:
+ AArch64DynamicLibraryWriter(AArch64LinkingContext &context,
+ AArch64TargetLayout<ELFT> &layout);
+
+protected:
+ // Add any runtime files and their atoms to the output
+ virtual bool createImplicitFiles(std::vector<std::unique_ptr<File>> &);
+
+ virtual void finalizeDefaultAtomValues() {
+ return DynamicLibraryWriter<ELFT>::finalizeDefaultAtomValues();
+ }
+
+ virtual void addDefaultAtoms() {
+ return DynamicLibraryWriter<ELFT>::addDefaultAtoms();
+ }
+
+private:
+ class GOTFile : public SimpleFile {
+ public:
+ GOTFile(const ELFLinkingContext &eti) : SimpleFile("GOTFile") {}
+ llvm::BumpPtrAllocator _alloc;
+ };
+
+ std::unique_ptr<GOTFile> _gotFile;
+ AArch64LinkingContext &_context;
+ AArch64TargetLayout<ELFT> &_AArch64Layout;
+};
+
+template <class ELFT>
+AArch64DynamicLibraryWriter<ELFT>::AArch64DynamicLibraryWriter(
+ AArch64LinkingContext &context, AArch64TargetLayout<ELFT> &layout)
+ : DynamicLibraryWriter<ELFT>(context, layout),
+ _gotFile(new GOTFile(context)), _context(context),
+ _AArch64Layout(layout) {}
+
+template <class ELFT>
+bool AArch64DynamicLibraryWriter<ELFT>::createImplicitFiles(
+ std::vector<std::unique_ptr<File>> &result) {
+ DynamicLibraryWriter<ELFT>::createImplicitFiles(result);
+ _gotFile->addAtom(*new (_gotFile->_alloc) GLOBAL_OFFSET_TABLEAtom(*_gotFile));
+ _gotFile->addAtom(*new (_gotFile->_alloc) DYNAMICAtom(*_gotFile));
+ result.push_back(std::move(_gotFile));
+ return true;
+}
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64ELFFile.h b/lib/ReaderWriter/ELF/AArch64/AArch64ELFFile.h
new file mode 100644
index 0000000000000..9d5207c1c4b49
--- /dev/null
+++ b/lib/ReaderWriter/ELF/AArch64/AArch64ELFFile.h
@@ -0,0 +1,41 @@
+//===- lib/ReaderWriter/ELF/AArch64/AArch64ELFFile.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_ELF_FILE_H
+#define LLD_READER_WRITER_ELF_AARCH64_AARCH64_ELF_FILE_H
+
+#include "ELFReader.h"
+
+namespace lld {
+namespace elf {
+
+class AArch64LinkingContext;
+
+template <class ELFT> class AArch64ELFFile : public ELFFile<ELFT> {
+public:
+ AArch64ELFFile(std::unique_ptr<MemoryBuffer> mb, AArch64LinkingContext &ctx)
+ : ELFFile<ELFT>(std::move(mb), ctx) {}
+
+ static ErrorOr<std::unique_ptr<AArch64ELFFile>>
+ create(std::unique_ptr<MemoryBuffer> mb, AArch64LinkingContext &ctx) {
+ return std::unique_ptr<AArch64ELFFile<ELFT>>(
+ new AArch64ELFFile<ELFT>(std::move(mb), ctx));
+ }
+};
+
+template <class ELFT> class AArch64DynamicFile : public DynamicFile<ELFT> {
+public:
+ AArch64DynamicFile(const AArch64LinkingContext &context, StringRef name)
+ : DynamicFile<ELFT>(context, name) {}
+};
+
+} // elf
+} // lld
+
+#endif // LLD_READER_WRITER_ELF_AARCH64_AARCH64_ELF_FILE_H
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64ELFReader.h b/lib/ReaderWriter/ELF/AArch64/AArch64ELFReader.h
new file mode 100644
index 0000000000000..05f312db3e7b7
--- /dev/null
+++ b/lib/ReaderWriter/ELF/AArch64/AArch64ELFReader.h
@@ -0,0 +1,62 @@
+//===- lib/ReaderWriter/ELF/AArch64/AArch64ELFReader.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_AARCH64_AARCH64_ELF_READER_H
+#define LLD_READER_WRITER_AARCH64_AARCH64_ELF_READER_H
+
+#include "AArch64ELFFile.h"
+#include "ELFReader.h"
+
+namespace lld {
+namespace elf {
+
+typedef llvm::object::ELFType<llvm::support::little, 2, true> AArch64ELFType;
+
+struct AArch64DynamicFileCreateELFTraits {
+ typedef llvm::ErrorOr<std::unique_ptr<lld::SharedLibraryFile>> result_type;
+
+ template <class ELFT>
+ static result_type create(std::unique_ptr<llvm::MemoryBuffer> mb,
+ AArch64LinkingContext &ctx) {
+ return lld::elf::AArch64DynamicFile<ELFT>::create(std::move(mb), ctx);
+ }
+};
+
+struct AArch64ELFFileCreateELFTraits {
+ typedef llvm::ErrorOr<std::unique_ptr<lld::File>> result_type;
+
+ template <class ELFT>
+ static result_type create(std::unique_ptr<llvm::MemoryBuffer> mb,
+ AArch64LinkingContext &ctx) {
+ return lld::elf::AArch64ELFFile<ELFT>::create(std::move(mb), ctx);
+ }
+};
+
+class AArch64ELFObjectReader
+ : public ELFObjectReader<AArch64ELFType, AArch64ELFFileCreateELFTraits,
+ AArch64LinkingContext> {
+public:
+ AArch64ELFObjectReader(AArch64LinkingContext &ctx)
+ : ELFObjectReader<AArch64ELFType, AArch64ELFFileCreateELFTraits,
+ AArch64LinkingContext>(ctx, llvm::ELF::EM_AARCH64) {}
+};
+
+class AArch64ELFDSOReader
+ : public ELFDSOReader<AArch64ELFType, AArch64DynamicFileCreateELFTraits,
+ AArch64LinkingContext> {
+public:
+ AArch64ELFDSOReader(AArch64LinkingContext &ctx)
+ : ELFDSOReader<AArch64ELFType, AArch64DynamicFileCreateELFTraits,
+ AArch64LinkingContext>(ctx, llvm::ELF::EM_AARCH64) {}
+};
+
+} // namespace elf
+} // namespace lld
+
+#endif // LLD_READER_WRITER_AARCH64_AARCH64_ELF_READER_H
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.h b/lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.h
new file mode 100644
index 0000000000000..73963f56ef70f
--- /dev/null
+++ b/lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.h
@@ -0,0 +1,68 @@
+//===- 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 "AArch64LinkingContext.h"
+#include "ExecutableWriter.h"
+
+namespace lld {
+namespace elf {
+
+template <class ELFT>
+class AArch64ExecutableWriter : public ExecutableWriter<ELFT> {
+public:
+ AArch64ExecutableWriter(AArch64LinkingContext &context,
+ AArch64TargetLayout<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 {
+ return ExecutableWriter<ELFT>::finalizeDefaultAtomValues();
+ }
+
+ void addDefaultAtoms() override{
+ return ExecutableWriter<ELFT>::addDefaultAtoms();
+ }
+
+private:
+ class GOTFile : public SimpleFile {
+ public:
+ GOTFile(const ELFLinkingContext &eti) : SimpleFile("GOTFile") {}
+ llvm::BumpPtrAllocator _alloc;
+ };
+
+ std::unique_ptr<GOTFile> _gotFile;
+ AArch64LinkingContext &_context;
+ AArch64TargetLayout<ELFT> &_AArch64Layout;
+};
+
+template <class ELFT>
+AArch64ExecutableWriter<ELFT>::AArch64ExecutableWriter(
+ AArch64LinkingContext &context, AArch64TargetLayout<ELFT> &layout)
+ : ExecutableWriter<ELFT>(context, layout), _gotFile(new GOTFile(context)),
+ _context(context), _AArch64Layout(layout) {}
+
+template <class ELFT>
+bool AArch64ExecutableWriter<ELFT>::createImplicitFiles(
+ std::vector<std::unique_ptr<File>> &result) {
+ ExecutableWriter<ELFT>::createImplicitFiles(result);
+ _gotFile->addAtom(*new (_gotFile->_alloc) GLOBAL_OFFSET_TABLEAtom(*_gotFile));
+ if (_context.isDynamic())
+ _gotFile->addAtom(*new (_gotFile->_alloc) DYNAMICAtom(*_gotFile));
+ result.push_back(std::move(_gotFile));
+ return true;
+}
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.cpp b/lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.cpp
new file mode 100644
index 0000000000000..9eb98f4477098
--- /dev/null
+++ b/lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.cpp
@@ -0,0 +1,33 @@
+//===- 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 "AArch64RelocationPass.h"
+#include "AArch64TargetHandler.h"
+
+using namespace lld;
+
+std::unique_ptr<ELFLinkingContext>
+elf::AArch64LinkingContext::create(llvm::Triple triple) {
+ if (triple.getArch() == llvm::Triple::aarch64)
+ return std::unique_ptr<ELFLinkingContext>(
+ new elf::AArch64LinkingContext(triple));
+ return nullptr;
+}
+
+elf::AArch64LinkingContext::AArch64LinkingContext(llvm::Triple triple)
+ : ELFLinkingContext(triple, std::unique_ptr<TargetHandlerBase>(
+ new AArch64TargetHandler(*this))) {}
+
+void elf::AArch64LinkingContext::addPasses(PassManager &pm) {
+ auto pass = createAArch64RelocationPass(*this);
+ if (pass)
+ pm.add(std::move(pass));
+ ELFLinkingContext::addPasses(pm);
+}
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.h b/lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.h
new file mode 100644
index 0000000000000..ebd91fe0a95b8
--- /dev/null
+++ b/lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.h
@@ -0,0 +1,95 @@
+//===- 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 "lld/ReaderWriter/ELFLinkingContext.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/ELF.h"
+
+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:
+ static std::unique_ptr<ELFLinkingContext> create(llvm::Triple);
+ AArch64LinkingContext(llvm::Triple);
+
+ void addPasses(PassManager &) override;
+
+ uint64_t getBaseAddress() const override {
+ if (_baseAddress == 0)
+ return 0x400000;
+ return _baseAddress;
+ }
+
+ bool isDynamicRelocation(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 isCopyRelocation(const Reference &r) const override {
+ if (r.kindNamespace() != Reference::KindNamespace::ELF)
+ return false;
+ assert(r.kindArch() == Reference::KindArch::AArch64);
+ if (r.kindValue() == llvm::ELF::R_AARCH64_COPY)
+ return true;
+ return false;
+ }
+
+ bool isPLTRelocation(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;
+ }
+ }
+};
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.cpp b/lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.cpp
new file mode 100644
index 0000000000000..d1ecc7fa884b0
--- /dev/null
+++ b/lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.cpp
@@ -0,0 +1,440 @@
+//===- 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"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/MathExtras.h"
+
+using namespace lld;
+using namespace lld::elf;
+using namespace llvm::support::endian;
+
+#define PAGE(X) ((X) & ~0x0FFFL)
+
+/// \brief Check X is in the interval (-2^(bits-1), 2^bits]
+static bool withinSignedUnsignedRange(int64_t X, int bits) {
+ return isIntN(bits - 1, X) || isUIntN(bits, X);
+}
+
+/// \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 " << 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");
+ write64le(location, result | read64le(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);
+ write32le(location, result + (int32_t)read32le(location));
+}
+
+/// \brief R_AARCH64_ABS32 - word32: S + A
+static std::error_code relocR_AARCH64_ABS32(uint8_t *location, uint64_t P,
+ uint64_t S, int64_t A) {
+ int64_t result = S + A;
+ if (!withinSignedUnsignedRange(result, 32))
+ return make_out_of_range_reloc_error();
+ DEBUG_WITH_TYPE(
+ "AArch64", 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");
+ write32le(location, result | read32le(location));
+ return std::error_code();
+}
+
+/// \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 " << LLVM_FUNCTION_NAME << " -";
+ 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");
+ write32le(location, immlo | immhi | read32le(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 " << LLVM_FUNCTION_NAME << " -";
+ 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");
+ write32le(location, immlo | immhi | read32le(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 " << LLVM_FUNCTION_NAME << " -";
+ 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");
+ write32le(location, result | read32le(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 " << LLVM_FUNCTION_NAME << " -";
+ 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");
+ write32le(location, result | read32le(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 " << LLVM_FUNCTION_NAME << " -";
+ 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");
+ write32le(location, result | read32le(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 " << LLVM_FUNCTION_NAME << " -";
+ 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");
+ write32le(location, result | read32le(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 " << LLVM_FUNCTION_NAME << " -";
+ 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");
+ write32le(location, result | read32le(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 " << LLVM_FUNCTION_NAME << " -";
+ 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");
+ write32le(location, result | read32le(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 " << LLVM_FUNCTION_NAME << " -";
+ 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");
+ write32le(location, result | read32le(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 " << LLVM_FUNCTION_NAME << " -";
+ 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");
+ write32le(location, result | read32le(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 " << LLVM_FUNCTION_NAME << " -";
+ 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");
+ write32le(location, result | read32le(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 " << LLVM_FUNCTION_NAME << " -";
+ 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;
+ write32le(location, result | read32le(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 " << LLVM_FUNCTION_NAME << " -";
+ 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;
+ write32le(location, result | read32le(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 " << LLVM_FUNCTION_NAME << " -";
+ 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");
+ write32le(location, immlo | immhi | read32le(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 " << LLVM_FUNCTION_NAME << " -";
+ 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");
+ write32le(location, result | read32le(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 " << LLVM_FUNCTION_NAME << " -";
+ 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");
+ write32le(location, result | read32le(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 " << LLVM_FUNCTION_NAME << " -";
+ 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");
+ write32le(location, result | read32le(location));
+}
+
+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:
+ return relocR_AARCH64_ABS32(location, relocVAddress, targetVAddress,
+ ref.addend());
+ // 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:
+ return make_unhandled_reloc_error();
+ }
+
+ return std::error_code();
+}
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.h b/lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.h
new file mode 100644
index 0000000000000..b1d3c09dc936c
--- /dev/null
+++ b/lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.h
@@ -0,0 +1,33 @@
+//===- 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<llvm::support::little, 2, true> AArch64ELFType;
+
+template <class ELFT> class AArch64TargetLayout;
+
+class AArch64TargetRelocationHandler final : public TargetRelocationHandler {
+public:
+ std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &,
+ const lld::AtomLayout &,
+ const Reference &) const override;
+
+ static const Registry::KindStrings kindStrings[];
+};
+
+} // end namespace elf
+} // end namespace lld
+
+#endif // AArch64_RELOCATION_HANDLER_H
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.cpp b/lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.cpp
new file mode 100644
index 0000000000000..0bd12958b27bd
--- /dev/null
+++ b/lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.cpp
@@ -0,0 +1,527 @@
+//===- 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 "AArch64LinkingContext.h"
+#include "Atoms.h"
+#include "lld/Core/Simple.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.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(<GLOBAL_OFFSET_TABLE>)
+ 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<uint8_t> rawContent() const override {
+ return ArrayRef<uint8_t>(AArch64GotAtomContent, 8);
+ }
+};
+
+class AArch64PLT0Atom : public PLT0Atom {
+public:
+ AArch64PLT0Atom(const File &f) : PLT0Atom(f) {}
+ ArrayRef<uint8_t> rawContent() const override {
+ return ArrayRef<uint8_t>(AArch64Plt0AtomContent, 32);
+ }
+};
+
+class AArch64PLTAtom : public PLTAtom {
+public:
+ AArch64PLTAtom(const File &f, StringRef secName) : PLTAtom(f, secName) {}
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return ArrayRef<uint8_t>(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 Derived> class AArch64RelocationPass : public Pass {
+ /// \brief Handle a specific reference.
+ void handleReference(const DefinedAtom &atom, const Reference &ref) {
+ DEBUG_WITH_TYPE(
+ "AArch64", 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::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<Derived *>(this)->handlePlain(ref);
+ break;
+ case R_AARCH64_GOTREL32:
+ case R_AARCH64_GOTREL64:
+ static_cast<Derived *>(this)->handleGOT(ref);
+ break;
+ case R_AARCH64_ADR_PREL_PG_HI21:
+ static_cast<Derived *>(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<Derived *>(this)->handlePlain(ref);
+ break;
+ case R_AARCH64_ADD_ABS_LO12_NC:
+ static_cast<Derived *>(this)->handlePlain(ref);
+ break;
+ case R_AARCH64_CALL26:
+ case R_AARCH64_JUMP26:
+ case R_AARCH64_CONDBR19:
+ static_cast<Derived *>(this)->handlePlain(ref);
+ break;
+ case R_AARCH64_TLSLE_ADD_TPREL_HI12:
+ case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
+ static_cast<Derived *>(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<Derived *>(this)->handleGOT(ref);
+ break;
+ }
+ }
+
+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<const DefinedAtom>(ref.target());
+ if (target && target->contentType() == DefinedAtom::typeResolver)
+ const_cast<Reference &>(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<Reference &>(ref).setTarget(getGOTTPOFF(ref.target()));
+ const_cast<Reference &>(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<MutableFile> &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<const Atom *, GOTAtom *> _gotMap;
+
+ /// \brief Map Atoms to their PLT entries.
+ llvm::DenseMap<const Atom *, PLTAtom *> _pltMap;
+
+ /// \brief Map Atoms to their Object entries.
+ llvm::DenseMap<const Atom *, ObjectAtom *> _objectMap;
+
+ /// \brief the list of GOT/PLT atoms
+ std::vector<GOTAtom *> _gotVector;
+ std::vector<PLTAtom *> _pltVector;
+ std::vector<ObjectAtom *> _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<AArch64StaticRelocationPass> {
+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<Reference &>(ref).setKindValue(R_AARCH64_NONE);
+ return std::error_code();
+ }
+ // Static code doesn't need PLTs.
+ const_cast<Reference &>(ref).setKindValue(R_AARCH64_PREL32);
+ // Handle IFUNC.
+ if (const DefinedAtom *da =
+ dyn_cast_or_null<const DefinedAtom>(ref.target()))
+ if (da->contentType() == DefinedAtom::typeResolver)
+ return handleIFUNC(ref);
+ return std::error_code();
+ }
+
+ std::error_code handleGOT(const Reference &ref) {
+ if (isa<UndefinedAtom>(ref.target()))
+ const_cast<Reference &>(ref).setTarget(getNullGOT());
+ else if (const DefinedAtom *da = dyn_cast<const DefinedAtom>(ref.target()))
+ const_cast<Reference &>(ref).setTarget(getGOT(da));
+ return std::error_code();
+ }
+};
+
+class AArch64DynamicRelocationPass final
+ : public AArch64RelocationPass<AArch64DynamicRelocationPass> {
+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
+ _PLT0->_name = "__PLT0";
+ _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, getPLT0(), 0);
+#ifndef NDEBUG
+ ga->_name = "__got_";
+ ga->_name += a->name();
+ pa->_name = "__plt_";
+ pa->_name += a->name();
+#endif
+ _gotMap[a] = ga;
+ _pltMap[a] = pa;
+ _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<SharedLibraryAtom>(ref.target())) {
+ if (sla->type() == SharedLibraryAtom::Type::Data)
+ const_cast<Reference &>(ref).setTarget(getObjectEntry(sla));
+ else if (sla->type() == SharedLibraryAtom::Type::Code)
+ const_cast<Reference &>(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<Reference &>(ref).setKindValue(R_AARCH64_PREL32);
+ // Handle IFUNC.
+ if (const DefinedAtom *da =
+ dyn_cast_or_null<const DefinedAtom>(ref.target()))
+ if (da->contentType() == DefinedAtom::typeResolver)
+ return handleIFUNC(ref);
+ if (isa<const SharedLibraryAtom>(ref.target()))
+ const_cast<Reference &>(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");
+ 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<UndefinedAtom>(ref.target()))
+ const_cast<Reference &>(ref).setTarget(getNullGOT());
+ else if (const DefinedAtom *da = dyn_cast<const DefinedAtom>(ref.target()))
+ const_cast<Reference &>(ref).setTarget(getGOT(da));
+ else if (const auto sla = dyn_cast<const SharedLibraryAtom>(ref.target()))
+ const_cast<Reference &>(ref).setTarget(getSharedGOT(sla));
+ return std::error_code();
+ }
+};
+} // end anon namespace
+
+std::unique_ptr<Pass>
+lld::elf::createAArch64RelocationPass(const AArch64LinkingContext &ctx) {
+ switch (ctx.getOutputELFType()) {
+ case llvm::ELF::ET_EXEC:
+ if (ctx.isDynamic())
+ return llvm::make_unique<AArch64DynamicRelocationPass>(ctx);
+ return llvm::make_unique<AArch64StaticRelocationPass>(ctx);
+ case llvm::ELF::ET_DYN:
+ return llvm::make_unique<AArch64DynamicRelocationPass>(ctx);
+ case llvm::ELF::ET_REL:
+ return nullptr;
+ default:
+ llvm_unreachable("Unhandled output file type");
+ }
+}
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.h b/lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.h
new file mode 100644
index 0000000000000..73d784e3b52d8
--- /dev/null
+++ b/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 AArch64. 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 <memory>
+
+namespace lld {
+class Pass;
+namespace elf {
+class AArch64LinkingContext;
+
+/// \brief Create AArch64 relocation pass for the given linking context.
+std::unique_ptr<Pass>
+createAArch64RelocationPass(const AArch64LinkingContext &);
+}
+}
+
+#endif
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.cpp b/lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.cpp
new file mode 100644
index 0000000000000..607f767f8b8a4
--- /dev/null
+++ b/lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.cpp
@@ -0,0 +1,52 @@
+//===- 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 "AArch64DynamicLibraryWriter.h"
+#include "AArch64ExecutableWriter.h"
+#include "AArch64LinkingContext.h"
+#include "AArch64TargetHandler.h"
+
+using namespace lld;
+using namespace elf;
+
+AArch64TargetHandler::AArch64TargetHandler(AArch64LinkingContext &context)
+ : _context(context),
+ _AArch64TargetLayout(new AArch64TargetLayout<AArch64ELFType>(context)),
+ _AArch64RelocationHandler(new AArch64TargetRelocationHandler()) {}
+
+void AArch64TargetHandler::registerRelocationNames(Registry &registry) {
+ registry.addKindTable(Reference::KindNamespace::ELF,
+ Reference::KindArch::AArch64, kindStrings);
+}
+
+std::unique_ptr<Writer> AArch64TargetHandler::getWriter() {
+ switch (this->_context.getOutputELFType()) {
+ case llvm::ELF::ET_EXEC:
+ return std::unique_ptr<Writer>(new AArch64ExecutableWriter<AArch64ELFType>(
+ _context, *_AArch64TargetLayout.get()));
+ case llvm::ELF::ET_DYN:
+ return std::unique_ptr<Writer>(
+ new AArch64DynamicLibraryWriter<AArch64ELFType>(
+ _context, *_AArch64TargetLayout.get()));
+ case llvm::ELF::ET_REL:
+ llvm_unreachable("TODO: support -r mode");
+ default:
+ llvm_unreachable("unsupported output type");
+ }
+}
+
+#define ELF_RELOC(name, value) LLD_KIND_STRING_ENTRY(name),
+
+const Registry::KindStrings AArch64TargetHandler::kindStrings[] = {
+#include "llvm/Support/ELFRelocs/AArch64.def"
+ LLD_KIND_STRING_END
+};
+
+#undef ELF_RELOC
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.h b/lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.h
new file mode 100644
index 0000000000000..4eb6786cdf1fb
--- /dev/null
+++ b/lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.h
@@ -0,0 +1,64 @@
+//===- 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 "AArch64ELFFile.h"
+#include "AArch64ELFReader.h"
+#include "AArch64RelocationHandler.h"
+#include "DefaultTargetHandler.h"
+#include "TargetLayout.h"
+#include "lld/Core/Simple.h"
+
+namespace lld {
+namespace elf {
+class AArch64LinkingContext;
+
+template <class ELFT> class AArch64TargetLayout : public TargetLayout<ELFT> {
+public:
+ AArch64TargetLayout(AArch64LinkingContext &context)
+ : TargetLayout<ELFT>(context) {}
+};
+
+class AArch64TargetHandler final : public DefaultTargetHandler<AArch64ELFType> {
+public:
+ AArch64TargetHandler(AArch64LinkingContext &context);
+
+ AArch64TargetLayout<AArch64ELFType> &getTargetLayout() override {
+ return *(_AArch64TargetLayout.get());
+ }
+
+ void registerRelocationNames(Registry &registry) override;
+
+ const AArch64TargetRelocationHandler &getRelocationHandler() const override {
+ return *(_AArch64RelocationHandler.get());
+ }
+
+ std::unique_ptr<Reader> getObjReader() override {
+ return std::unique_ptr<Reader>(new AArch64ELFObjectReader(_context));
+ }
+
+ std::unique_ptr<Reader> getDSOReader() override {
+ return std::unique_ptr<Reader>(new AArch64ELFDSOReader(_context));
+ }
+
+ std::unique_ptr<Writer> getWriter() override;
+
+private:
+ static const Registry::KindStrings kindStrings[];
+ AArch64LinkingContext &_context;
+ std::unique_ptr<AArch64TargetLayout<AArch64ELFType>> _AArch64TargetLayout;
+ std::unique_ptr<AArch64TargetRelocationHandler> _AArch64RelocationHandler;
+};
+
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/AArch64/CMakeLists.txt b/lib/ReaderWriter/ELF/AArch64/CMakeLists.txt
new file mode 100644
index 0000000000000..de94a4df5078a
--- /dev/null
+++ b/lib/ReaderWriter/ELF/AArch64/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_llvm_library(lldAArch64ELFTarget
+ AArch64LinkingContext.cpp
+ AArch64TargetHandler.cpp
+ AArch64RelocationHandler.cpp
+ AArch64RelocationPass.cpp
+ LINK_LIBS
+ lldELF
+ lldReaderWriter
+ lldCore
+ LLVMObject
+ LLVMSupport
+ )
diff --git a/lib/ReaderWriter/ELF/AArch64/Makefile b/lib/ReaderWriter/ELF/AArch64/Makefile
new file mode 100644
index 0000000000000..02cff4747d0d2
--- /dev/null
+++ b/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
diff --git a/lib/ReaderWriter/ELF/AArch64/TODO.rst b/lib/ReaderWriter/ELF/AArch64/TODO.rst
new file mode 100644
index 0000000000000..aa6f616ff33fb
--- /dev/null
+++ b/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
+
+
diff --git a/lib/ReaderWriter/ELF/ARM/ARMELFFile.h b/lib/ReaderWriter/ELF/ARM/ARMELFFile.h
new file mode 100644
index 0000000000000..bc5ee35b8213b
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ARM/ARMELFFile.h
@@ -0,0 +1,97 @@
+//===--------- 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 ARMELFDefinedAtom : public ELFDefinedAtom<ELFT> {
+ typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+ typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr;
+
+public:
+ ARMELFDefinedAtom(const ELFFile<ELFT> &file, StringRef symbolName,
+ StringRef sectionName, const Elf_Sym *symbol,
+ const Elf_Shdr *section, ArrayRef<uint8_t> contentData,
+ unsigned int referenceStart, unsigned int referenceEnd,
+ std::vector<ELFReference<ELFT> *> &referenceList)
+ : ELFDefinedAtom<ELFT>(file, symbolName, sectionName, symbol, section,
+ contentData, referenceStart, referenceEnd,
+ referenceList) {}
+
+ bool isThumbFunc(const Elf_Sym *symbol) const {
+ return symbol->getType() == llvm::ELF::STT_FUNC &&
+ (static_cast<uint64_t>(symbol->st_value) & 0x1);
+ }
+
+ /// Correct st_value for symbols addressing Thumb instructions
+ /// by removing its zero bit.
+ uint64_t getSymbolValue(const Elf_Sym *symbol) const override {
+ const auto value = static_cast<uint64_t>(symbol->st_value);
+ return isThumbFunc(symbol) ? value & ~0x1 : value;
+ }
+
+ DefinedAtom::CodeModel codeModel() const override {
+ if (isThumbFunc(this->_symbol))
+ return DefinedAtom::codeARMThumb;
+ return DefinedAtom::codeNA;
+ }
+};
+
+template <class ELFT> class ARMELFFile : public ELFFile<ELFT> {
+public:
+ ARMELFFile(std::unique_ptr<MemoryBuffer> mb, ARMLinkingContext &ctx)
+ : ELFFile<ELFT>(std::move(mb), ctx) {}
+
+ static ErrorOr<std::unique_ptr<ARMELFFile>>
+ create(std::unique_ptr<MemoryBuffer> mb, ARMLinkingContext &ctx) {
+ return std::unique_ptr<ARMELFFile<ELFT>>(
+ new ARMELFFile<ELFT>(std::move(mb), ctx));
+ }
+
+private:
+ typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+ typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr;
+
+ /// Correct st_value for symbols addressing Thumb instructions
+ /// by removing its zero bit.
+ uint64_t getSymbolValue(const Elf_Sym *symbol) const override {
+ const auto value = static_cast<uint64_t>(symbol->st_value);
+ return symbol->getType() == llvm::ELF::STT_FUNC ? value & ~0x1 : value;
+ }
+
+ /// Process the Defined symbol and create an atom for it.
+ ErrorOr<ELFDefinedAtom<ELFT> *> handleDefinedSymbol(StringRef symName,
+ StringRef sectionName,
+ const Elf_Sym *sym, const Elf_Shdr *sectionHdr,
+ ArrayRef<uint8_t> contentData,
+ unsigned int referenceStart, unsigned int referenceEnd,
+ std::vector<ELFReference<ELFT> *> &referenceList) override {
+ return new (this->_readerStorage) ARMELFDefinedAtom<ELFT>(
+ *this, symName, sectionName, sym, sectionHdr, contentData,
+ referenceStart, referenceEnd, referenceList);
+ }
+};
+
+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/lib/ReaderWriter/ELF/ARM/ARMELFReader.h b/lib/ReaderWriter/ELF/ARM/ARMELFReader.h
new file mode 100644
index 0000000000000..31af531563ea5
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ARM/ARMELFReader.h
@@ -0,0 +1,62 @@
+//===--------- 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,
+ ARMLinkingContext &ctx) {
+ return lld::elf::ARMDynamicFile<ELFT>::create(std::move(mb), ctx);
+ }
+};
+
+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,
+ ARMLinkingContext &ctx) {
+ return lld::elf::ARMELFFile<ELFT>::create(std::move(mb), ctx);
+ }
+};
+
+class ARMELFObjectReader
+ : public ELFObjectReader<ARMELFType, ARMELFFileCreateELFTraits,
+ ARMLinkingContext> {
+public:
+ ARMELFObjectReader(ARMLinkingContext &ctx)
+ : ELFObjectReader<ARMELFType, ARMELFFileCreateELFTraits,
+ ARMLinkingContext>(ctx, llvm::ELF::EM_ARM) {}
+};
+
+class ARMELFDSOReader
+ : public ELFDSOReader<ARMELFType, ARMDynamicFileCreateELFTraits,
+ ARMLinkingContext> {
+public:
+ ARMELFDSOReader(ARMLinkingContext &ctx)
+ : ELFDSOReader<ARMELFType, ARMDynamicFileCreateELFTraits,
+ ARMLinkingContext>(ctx, llvm::ELF::EM_ARM) {}
+};
+
+} // namespace elf
+} // namespace lld
+
+#endif // LLD_READER_WRITER_ARM_ARM_ELF_READER_H
diff --git a/lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h b/lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h
new file mode 100644
index 0000000000000..19311d516e4de
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h
@@ -0,0 +1,121 @@
+//===--------- 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"
+#include "ARMTargetHandler.h"
+#include "ARMSymbolTable.h"
+
+namespace {
+const char *gotSymbol = "_GLOBAL_OFFSET_TABLE_";
+}
+
+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;
+
+ void addDefaultAtoms() override {
+ ExecutableWriter<ELFT>::addDefaultAtoms();
+ }
+
+ /// \brief Create symbol table.
+ unique_bump_ptr<SymbolTable<ELFT>> createSymbolTable() override;
+
+ void processUndefinedSymbol(StringRef symName,
+ RuntimeFile<ELFT> &file) const override;
+
+ // Setup the ELF header.
+ std::error_code setELFHeader() override;
+
+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;
+}
+
+template <class ELFT>
+void ARMExecutableWriter<ELFT>::finalizeDefaultAtomValues() {
+ // Finalize the atom values that are part of the parent.
+ ExecutableWriter<ELFT>::finalizeDefaultAtomValues();
+ auto gotAtomIter = _armLayout.findAbsoluteAtom(gotSymbol);
+ if (gotAtomIter != _armLayout.absoluteAtoms().end()) {
+ auto *gotAtom = *gotAtomIter;
+ if (auto gotpltSection = _armLayout.findOutputSection(".got.plt"))
+ gotAtom->_virtualAddr = gotpltSection->virtualAddr();
+ else if (auto gotSection = _armLayout.findOutputSection(".got"))
+ gotAtom->_virtualAddr = gotSection->virtualAddr();
+ else
+ gotAtom->_virtualAddr = 0;
+ }
+ // TODO: resolve addresses of __exidx_start/_end atoms
+}
+
+template <class ELFT>
+unique_bump_ptr<SymbolTable<ELFT>>
+ ARMExecutableWriter<ELFT>::createSymbolTable() {
+ return unique_bump_ptr<SymbolTable<ELFT>>(
+ new (this->_alloc) ARMSymbolTable<ELFT>(this->_context));
+}
+
+template <class ELFT>
+void ARMExecutableWriter<ELFT>::processUndefinedSymbol(
+ StringRef symName, RuntimeFile<ELFT> &file) const {
+ if (symName == gotSymbol) {
+ file.addAbsoluteAtom(gotSymbol);
+ } else if (symName.startswith("__exidx")) {
+ file.addAbsoluteAtom("__exidx_start");
+ file.addAbsoluteAtom("__exidx_end");
+ }
+}
+
+template <class ELFT>
+std::error_code ARMExecutableWriter<ELFT>::setELFHeader() {
+ if (std::error_code ec = ExecutableWriter<ELFT>::setELFHeader())
+ return ec;
+
+ // Fixup entry point for Thumb code.
+ StringRef entryName = _context.entrySymbolName();
+ if (const AtomLayout *al = _armLayout.findAtomLayoutByName(entryName)) {
+ const auto *ea = dyn_cast<DefinedAtom>(al->_atom);
+ if (ea && ea->codeModel() == DefinedAtom::codeARMThumb)
+ this->_elfHeader->e_entry(al->_virtualAddr | 0x1);
+ }
+
+ return std::error_code();
+}
+
+} // namespace elf
+} // namespace lld
+
+#endif // LLD_READER_WRITER_ELF_ARM_ARM_EXECUTABLE_WRITER_H
diff --git a/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp b/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp
new file mode 100644
index 0000000000000..5f24366742684
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp
@@ -0,0 +1,34 @@
+//===--------- 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"
+#include "ARMTargetHandler.h"
+
+using namespace lld;
+using namespace lld::elf;
+
+std::unique_ptr<ELFLinkingContext>
+elf::ARMLinkingContext::create(llvm::Triple triple) {
+ if (triple.getArch() == llvm::Triple::arm)
+ return std::unique_ptr<ELFLinkingContext>(
+ new elf::ARMLinkingContext(triple));
+ return nullptr;
+}
+
+elf::ARMLinkingContext::ARMLinkingContext(llvm::Triple triple)
+ : ELFLinkingContext(triple, std::unique_ptr<TargetHandlerBase>(
+ new ARMTargetHandler(*this))) {}
+
+void elf::ARMLinkingContext::addPasses(PassManager &pm) {
+ auto pass = createARMRelocationPass(*this);
+ if (pass)
+ pm.add(std::move(pass));
+ ELFLinkingContext::addPasses(pm);
+}
diff --git a/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h b/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h
new file mode 100644
index 0000000000000..249b79c4f07d0
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h
@@ -0,0 +1,36 @@
+//===--------- 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 "lld/ReaderWriter/ELFLinkingContext.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/ELF.h"
+
+namespace lld {
+namespace elf {
+
+class ARMLinkingContext final : public ELFLinkingContext {
+public:
+ static std::unique_ptr<ELFLinkingContext> create(llvm::Triple);
+ ARMLinkingContext(llvm::Triple);
+
+ 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/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp b/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp
new file mode 100644
index 0000000000000..d24fdf0fa410a
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp
@@ -0,0 +1,500 @@
+//===--------- 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/Endian.h"
+#include "llvm/Support/MathExtras.h"
+
+using namespace lld;
+using namespace lld::elf;
+using namespace llvm::support::endian;
+
+static Reference::Addend readAddend_THM_MOV(const uint8_t *location) {
+ const uint16_t halfHi = read16le(location);
+ const uint16_t halfLo = read16le(location + 2);
+
+ const uint16_t imm8 = halfLo & 0xFF;
+ const uint16_t imm3 = (halfLo >> 12) & 0x7;
+
+ const uint16_t imm4 = halfHi & 0xF;
+ const uint16_t bitI = (halfHi >> 10) & 0x1;
+
+ const auto result = int16_t((imm4 << 12) | (bitI << 11) | (imm3 << 8) | imm8);
+ return result;
+}
+
+static Reference::Addend readAddend_ARM_MOV(const uint8_t *location) {
+ const uint32_t value = read32le(location);
+
+ const uint32_t imm12 = value & 0xFFF;
+ const uint32_t imm4 = (value >> 16) & 0xF;
+
+ const auto result = int32_t((imm4 << 12) | imm12);
+ return result;
+}
+
+static Reference::Addend readAddend_THM_CALL(const uint8_t *location) {
+ const uint16_t halfHi = read16le(location);
+ const uint16_t halfLo = read16le(location + 2);
+
+ const uint16_t imm10 = halfHi & 0x3FF;
+ const uint16_t bitS = (halfHi >> 10) & 0x1;
+
+ const uint16_t imm11 = halfLo & 0x7FF;
+ const uint16_t bitJ2 = (halfLo >> 11) & 0x1;
+ const uint16_t bitI2 = (~(bitJ2 ^ bitS)) & 0x1;
+ const uint16_t bitJ1 = (halfLo >> 13) & 0x1;
+ const uint16_t bitI1 = (~(bitJ1 ^ bitS)) & 0x1;
+
+ const auto result = int32_t((bitS << 24) | (bitI1 << 23) | (bitI2 << 22) |
+ (imm10 << 12) | (imm11 << 1));
+ return llvm::SignExtend64<25>(result);
+}
+
+static Reference::Addend readAddend_ARM_CALL(const uint8_t *location) {
+ const uint32_t value = read32le(location);
+
+ const bool isBLX = (value & 0xF0000000) == 0xF0000000;
+ const uint32_t bitH = isBLX ? ((value & 0x1000000) >> 24) : 0;
+
+ const auto result = int32_t(((value & 0xFFFFFF) << 2) | (bitH << 1));
+ return llvm::SignExtend64<26>(result);
+}
+
+static Reference::Addend readAddend_THM_JUMP11(const uint8_t *location) {
+ const auto value = read16le(location);
+ const uint16_t imm11 = value & 0x7FF;
+
+ return llvm::SignExtend32<12>(imm11 << 1);
+}
+
+static Reference::Addend readAddend(const uint8_t *location,
+ Reference::KindValue kindValue) {
+ switch (kindValue) {
+ case R_ARM_ABS32:
+ case R_ARM_REL32:
+ case R_ARM_TLS_IE32:
+ case R_ARM_TLS_LE32:
+ return (int32_t)read32le(location);
+ case R_ARM_PREL31:
+ return (int32_t)(read32le(location) & 0x7FFFFFFF);
+ case R_ARM_THM_CALL:
+ case R_ARM_THM_JUMP24:
+ return readAddend_THM_CALL(location);
+ case R_ARM_THM_JUMP11:
+ return readAddend_THM_JUMP11(location);
+ case R_ARM_CALL:
+ case R_ARM_JUMP24:
+ return readAddend_ARM_CALL(location);
+ case R_ARM_MOVW_ABS_NC:
+ case R_ARM_MOVT_ABS:
+ return readAddend_ARM_MOV(location);
+ case R_ARM_THM_MOVW_ABS_NC:
+ case R_ARM_THM_MOVT_ABS:
+ return readAddend_THM_MOV(location);
+ default:
+ return 0;
+ }
+}
+
+static inline void applyArmReloc(uint8_t *location, uint32_t result,
+ uint32_t mask = 0xFFFFFFFF) {
+ assert(!(result & ~mask));
+ write32le(location, (read32le(location) & ~mask) | (result & mask));
+}
+
+static inline void applyThmReloc(uint8_t *location, uint16_t resHi,
+ uint16_t resLo, uint16_t maskHi,
+ uint16_t maskLo = 0xFFFF) {
+ assert(!(resHi & ~maskHi) && !(resLo & ~maskLo));
+ write16le(location, (read16le(location) & ~maskHi) | (resHi & maskHi));
+ location += 2;
+ write16le(location, (read16le(location) & ~maskLo) | (resLo & maskLo));
+}
+
+static inline void applyThumb16Reloc(uint8_t *location, uint16_t result,
+ uint16_t mask = 0xFFFF) {
+ assert(!(result & ~mask));
+ write16le(location, (read16le(location) & ~mask) | (result & mask));
+}
+
+/// \brief R_ARM_ABS32 - (S + A) | T
+static void relocR_ARM_ABS32(uint8_t *location, uint64_t P, uint64_t S,
+ int64_t A, bool addressesThumb) {
+ uint64_t T = addressesThumb;
+ uint32_t result = (uint32_t)((S + A) | T);
+
+ 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() << " T: 0x" << Twine::utohexstr(T);
+ llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
+ applyArmReloc(location, result);
+}
+
+/// \brief R_ARM_REL32 - ((S + A) | T) - P
+static void relocR_ARM_REL32(uint8_t *location, uint64_t P, uint64_t S,
+ int64_t A, bool addressesThumb) {
+ uint64_t T = addressesThumb;
+ uint32_t result = (uint32_t)(((S + A) | T) - P);
+
+ 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() << " T: 0x" << Twine::utohexstr(T);
+ llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
+ applyArmReloc(location, result);
+}
+
+/// \brief R_ARM_PREL31 - ((S + A) | T) - P
+static void relocR_ARM_PREL31(uint8_t *location, uint64_t P, uint64_t S,
+ int64_t A, bool addressesThumb) {
+ uint64_t T = addressesThumb;
+ uint32_t result = (uint32_t)(((S + A) | T) - P);
+ const uint32_t mask = 0x7FFFFFFF;
+ uint32_t rel31 = result & mask;
+
+ 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() << " T: 0x" << Twine::utohexstr(T);
+ llvm::dbgs() << " result: 0x" << Twine::utohexstr(result);
+ llvm::dbgs() << " rel31: 0x" << Twine::utohexstr(rel31) << "\n");
+
+ applyArmReloc(location, rel31, mask);
+}
+
+/// \brief Relocate B/BL instructions. useJs defines whether J1 & J2 are used
+static void relocR_ARM_THM_B_L(uint8_t *location, uint32_t result, bool useJs) {
+ result = (result & 0x01FFFFFE) >> 1;
+
+ const uint16_t imm10 = (result >> 11) & 0x3FF;
+ const uint16_t bitS = (result >> 23) & 0x1;
+ const uint16_t resHi = (bitS << 10) | imm10;
+
+ const uint16_t imm11 = result & 0x7FF;
+ const uint16_t bitJ2 = useJs ? ((result >> 21) & 0x1) : bitS;
+ const uint16_t bitI2 = (~(bitJ2 ^ bitS)) & 0x1;
+ const uint16_t bitJ1 = useJs ? ((result >> 22) & 0x1) : bitS;
+ const uint16_t bitI1 = (~(bitJ1 ^ bitS)) & 0x1;
+ const uint16_t resLo = (bitI1 << 13) | (bitI2 << 11) | imm11;
+
+ applyThmReloc(location, resHi, resLo, 0x7FF, 0x2FFF);
+}
+
+/// \brief R_ARM_THM_CALL - ((S + A) | T) - P
+static void relocR_ARM_THM_CALL(uint8_t *location, uint64_t P, uint64_t S,
+ int64_t A, bool useJs, bool addressesThumb) {
+ uint64_t T = addressesThumb;
+ const bool switchMode = !addressesThumb;
+
+ if (switchMode) {
+ P &= ~0x3; // Align(P, 4) by rounding down
+ }
+
+ uint32_t result = (uint32_t)(((S + A) | T) - P);
+
+ 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() << " T: 0x" << Twine::utohexstr(T);
+ llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
+ relocR_ARM_THM_B_L(location, result, useJs);
+
+ if (switchMode) {
+ applyThmReloc(location, 0, 0, 0, 0x1001);
+ }
+}
+
+/// \brief R_ARM_THM_JUMP24 - ((S + A) | T) - P
+static void relocR_ARM_THM_JUMP24(uint8_t *location, uint64_t P, uint64_t S,
+ int64_t A, bool addressesThumb) {
+ uint64_t T = addressesThumb;
+ uint32_t result = (uint32_t)(((S + A) | T) - P);
+
+ 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() << " T: 0x" << Twine::utohexstr(T);
+ llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
+ relocR_ARM_THM_B_L(location, result, true);
+}
+
+/// \brief R_ARM_THM_JUMP11 - S + A - P
+static void relocR_ARM_THM_JUMP11(uint8_t *location, uint64_t P, uint64_t S,
+ int64_t A) {
+ uint32_t result = (uint32_t)(S + A - P);
+
+ 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");
+
+ //we cut off first bit because it is always 1 according to p. 4.5.3
+ result = (result & 0x0FFE) >> 1;
+
+ applyThumb16Reloc(location, result, 0x7FF);
+}
+
+/// \brief R_ARM_CALL - ((S + A) | T) - P
+static void relocR_ARM_CALL(uint8_t *location, uint64_t P, uint64_t S,
+ int64_t A, bool addressesThumb) {
+ uint64_t T = addressesThumb;
+ const bool switchMode = addressesThumb;
+
+ uint32_t result = (uint32_t)(((S + A) | T) - 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() << " T: 0x" << Twine::utohexstr(T);
+ llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
+ applyArmReloc(location, imm24, 0xFFFFFF);
+
+ if (switchMode) {
+ const uint32_t bitH = (result & 0x2) >> 1;
+ applyArmReloc(location, (0xFA | bitH) << 24, 0xFF000000);
+ }
+}
+
+/// \brief R_ARM_JUMP24 - ((S + A) | T) - P
+static void relocR_ARM_JUMP24(uint8_t *location, uint64_t P, uint64_t S,
+ int64_t A, bool addressesThumb) {
+ uint64_t T = addressesThumb;
+ uint32_t result = (uint32_t)(((S + A) | T) - 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() << " T: 0x" << Twine::utohexstr(T);
+ llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
+ applyArmReloc(location, imm24, 0xFFFFFF);
+}
+
+/// \brief Relocate ARM MOVW/MOVT instructions
+static void relocR_ARM_MOV(uint8_t *location, uint32_t result) {
+ const uint32_t imm12 = result & 0xFFF;
+ const uint32_t imm4 = (result >> 12) & 0xF;
+
+ applyArmReloc(location, (imm4 << 16) | imm12, 0xF0FFF);
+}
+
+/// \brief R_ARM_MOVW_ABS_NC - (S + A) | T
+static void relocR_ARM_MOVW_ABS_NC(uint8_t *location, uint64_t P, uint64_t S,
+ int64_t A, bool addressesThumb) {
+ uint64_t T = addressesThumb;
+ uint32_t result = (uint32_t)((S + A) | T);
+ const uint32_t arg = result & 0x0000FFFF;
+
+ 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() << " T: 0x" << Twine::utohexstr(T);
+ llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
+ return relocR_ARM_MOV(location, arg);
+}
+
+/// \brief R_ARM_MOVT_ABS - S + A
+static void relocR_ARM_MOVT_ABS(uint8_t *location, uint64_t P, uint64_t S,
+ int64_t A) {
+ uint32_t result = (uint32_t)(S + A);
+ const uint32_t arg = (result & 0xFFFF0000) >> 16;
+
+ 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");
+ return relocR_ARM_MOV(location, arg);
+}
+
+/// \brief Relocate Thumb MOVW/MOVT instructions
+static void relocR_ARM_THM_MOV(uint8_t *location, uint32_t result) {
+ const uint16_t imm8 = result & 0xFF;
+ const uint16_t imm3 = (result >> 8) & 0x7;
+ const uint16_t resLo = (imm3 << 12) | imm8;
+
+ const uint16_t imm4 = (result >> 12) & 0xF;
+ const uint16_t bitI = (result >> 11) & 0x1;
+ const uint16_t resHi = (bitI << 10) | imm4;
+
+ applyThmReloc(location, resHi, resLo, 0x40F, 0x70FF);
+}
+
+/// \brief R_ARM_THM_MOVW_ABS_NC - (S + A) | T
+static void relocR_ARM_THM_MOVW_ABS_NC(uint8_t *location, uint64_t P,
+ uint64_t S, int64_t A,
+ bool addressesThumb) {
+ uint64_t T = addressesThumb;
+ uint32_t result = (uint32_t)((S + A) | T);
+ const uint32_t arg = result & 0x0000FFFF;
+
+ 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() << " T: 0x" << Twine::utohexstr(T);
+ llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
+ return relocR_ARM_THM_MOV(location, arg);
+}
+
+/// \brief R_ARM_THM_MOVT_ABS - S + A
+static void relocR_ARM_THM_MOVT_ABS(uint8_t *location, uint64_t P, uint64_t S,
+ int64_t A) {
+ uint32_t result = (uint32_t)(S + A);
+ const uint32_t arg = (result & 0xFFFF0000) >> 16;
+
+ 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");
+ return relocR_ARM_THM_MOV(location, arg);
+}
+
+/// \brief R_ARM_TLS_IE32 - GOT(S) + A - P => S + A - P
+static void relocR_ARM_TLS_IE32(uint8_t *location, uint64_t P, uint64_t S,
+ int64_t A) {
+ uint32_t result = (uint32_t)(S + A - P);
+
+ 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_TLS_LE32 - S + A - tp => S + A + tpoff
+static void relocR_ARM_TLS_LE32(uint8_t *location, uint64_t P, uint64_t S,
+ int64_t A, uint64_t tpoff) {
+ uint32_t result = (uint32_t)(S + A + tpoff);
+
+ 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);
+}
+
+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());
+
+ // Flags that the relocation addresses Thumb instruction
+ bool addressesThumb = false;
+
+ if (const auto *definedAtom = dyn_cast<DefinedAtom>(ref.target())) {
+ addressesThumb = (DefinedAtom::codeARMThumb == definedAtom->codeModel());
+ }
+
+ switch (ref.kindValue()) {
+ case R_ARM_NONE:
+ break;
+ case R_ARM_ABS32:
+ relocR_ARM_ABS32(location, relocVAddress, targetVAddress, addend,
+ addressesThumb);
+ break;
+ case R_ARM_REL32:
+ relocR_ARM_REL32(location, relocVAddress, targetVAddress, addend,
+ addressesThumb);
+ break;
+ case R_ARM_THM_CALL:
+ // TODO: consider adding bool variable to disable J1 & J2 for archs
+ // before ARMv6
+ relocR_ARM_THM_CALL(location, relocVAddress, targetVAddress, addend, true,
+ addressesThumb);
+ break;
+ case R_ARM_CALL:
+ relocR_ARM_CALL(location, relocVAddress, targetVAddress, addend,
+ addressesThumb);
+ break;
+ case R_ARM_JUMP24:
+ relocR_ARM_JUMP24(location, relocVAddress, targetVAddress, addend,
+ addressesThumb);
+ break;
+ case R_ARM_THM_JUMP24:
+ relocR_ARM_THM_JUMP24(location, relocVAddress, targetVAddress, addend,
+ addressesThumb);
+ break;
+ case R_ARM_THM_JUMP11:
+ relocR_ARM_THM_JUMP11(location, relocVAddress, targetVAddress, addend);
+ break;
+ case R_ARM_MOVW_ABS_NC:
+ relocR_ARM_MOVW_ABS_NC(location, relocVAddress, targetVAddress, addend,
+ addressesThumb);
+ break;
+ case R_ARM_MOVT_ABS:
+ relocR_ARM_MOVT_ABS(location, relocVAddress, targetVAddress, addend);
+ break;
+ case R_ARM_THM_MOVW_ABS_NC:
+ relocR_ARM_THM_MOVW_ABS_NC(location, relocVAddress, targetVAddress, addend,
+ addressesThumb);
+ break;
+ case R_ARM_THM_MOVT_ABS:
+ relocR_ARM_THM_MOVT_ABS(location, relocVAddress, targetVAddress, addend);
+ break;
+ case R_ARM_PREL31:
+ relocR_ARM_PREL31(location, relocVAddress, targetVAddress, addend,
+ addressesThumb);
+ break;
+ case R_ARM_TLS_IE32:
+ relocR_ARM_TLS_IE32(location, relocVAddress, targetVAddress, addend);
+ break;
+ case R_ARM_TLS_LE32:
+ relocR_ARM_TLS_LE32(location, relocVAddress, targetVAddress, addend,
+ _armLayout.getTPOffset());
+ break;
+ default:
+ return make_unhandled_reloc_error();
+ }
+
+ return std::error_code();
+}
diff --git a/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h b/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h
new file mode 100644
index 0000000000000..227d68617bf98
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h
@@ -0,0 +1,38 @@
+//===--------- 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:
+ ARMTargetRelocationHandler(ARMTargetLayout<ARMELFType> &layout)
+ : _armLayout(layout) {}
+
+ std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &,
+ const lld::AtomLayout &,
+ const Reference &) const override;
+
+private:
+ ARMTargetLayout<ARMELFType> &_armLayout;
+};
+
+} // end namespace elf
+} // end namespace lld
+
+#endif // LLD_READER_WRITER_ELF_ARM_ARM_RELOCATION_HANDLER_H
diff --git a/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp b/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp
new file mode 100644
index 0000000000000..27ec66ac55572
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp
@@ -0,0 +1,373 @@
+//===--------- 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 "ARMLinkingContext.h"
+#include "Atoms.h"
+#include "lld/Core/Simple.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Debug.h"
+
+using namespace lld;
+using namespace lld::elf;
+using namespace llvm::ELF;
+
+// ARM B/BL instructions of static relocation veneer.
+// TODO: consider different instruction set for archs below ARMv5
+// (one as for Thumb may be used though it's less optimal).
+static const uint8_t Veneer_ARM_B_BL_StaticAtomContent[8] = {
+ 0x04, 0xf0, 0x1f, 0xe5, // ldr pc, [pc, #-4]
+ 0x00, 0x00, 0x00, 0x00 // <target_symbol_address>
+};
+
+// Thumb B/BL instructions of static relocation veneer.
+// TODO: consider different instruction set for archs above ARMv5
+// (one as for ARM may be used since it's more optimal).
+static const uint8_t Veneer_THM_B_BL_StaticAtomContent[8] = {
+ 0x78, 0x47, // bx pc
+ 0x00, 0x00, // nop
+ 0xfe, 0xff, 0xff, 0xea // b <target_symbol_address>
+};
+
+// .got values
+static const uint8_t ARMGotAtomContent[4] = {0};
+
+namespace {
+/// \brief Atoms that hold veneer code.
+class VeneerAtom : public SimpleELFDefinedAtom {
+ StringRef _section;
+
+public:
+ VeneerAtom(const File &f, StringRef secName)
+ : SimpleELFDefinedAtom(f), _section(secName) {}
+
+ Scope scope() const override { return DefinedAtom::scopeTranslationUnit; }
+
+ SectionChoice sectionChoice() const override {
+ return DefinedAtom::sectionBasedOnContent;
+ }
+
+ StringRef customSectionName() const override { return _section; }
+
+ ContentType contentType() const override {
+ return DefinedAtom::typeCode;
+ }
+
+ uint64_t size() const override { return rawContent().size(); }
+
+ ContentPermissions permissions() const override { return permR_X; }
+
+ Alignment alignment() const override { return Alignment(2); }
+
+ StringRef name() const override { return _name; }
+ std::string _name;
+};
+
+/// \brief Atoms that hold veneer for statically relocated
+/// ARM B/BL instructions.
+class Veneer_ARM_B_BL_StaticAtom : public VeneerAtom {
+public:
+ Veneer_ARM_B_BL_StaticAtom(const File &f, StringRef secName)
+ : VeneerAtom(f, secName) {}
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return llvm::makeArrayRef(Veneer_ARM_B_BL_StaticAtomContent);
+ }
+};
+
+/// \brief Atoms that hold veneer for statically relocated
+/// Thumb B/BL instructions.
+class Veneer_THM_B_BL_StaticAtom : public VeneerAtom {
+public:
+ Veneer_THM_B_BL_StaticAtom(const File &f, StringRef secName)
+ : VeneerAtom(f, secName) {}
+
+ DefinedAtom::CodeModel codeModel() const override {
+ return DefinedAtom::codeARMThumb;
+ }
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return llvm::makeArrayRef(Veneer_THM_B_BL_StaticAtomContent);
+ }
+};
+
+/// \brief Atoms that are used by ARM dynamic linking
+class ARMGOTAtom : public GOTAtom {
+public:
+ ARMGOTAtom(const File &f, StringRef secName) : GOTAtom(f, secName) {}
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return llvm::makeArrayRef(ARMGotAtomContent);
+ }
+
+ Alignment alignment() const override { return Alignment(2); }
+};
+
+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()) {
+ case R_ARM_JUMP24:
+ case R_ARM_THM_JUMP24:
+ static_cast<Derived *>(this)->handleVeneer(atom, ref);
+ break;
+ case R_ARM_TLS_IE32:
+ static_cast<Derived *>(this)->handleTLSIE32(ref);
+ break;
+ }
+ }
+
+protected:
+ std::error_code handleVeneer(const DefinedAtom &atom, const Reference &ref) {
+ // Target symbol and relocated place should have different
+ // instruction sets in order a veneer to be generated in between.
+ const auto *target = dyn_cast<DefinedAtom>(ref.target());
+ if (!target || target->codeModel() == atom.codeModel())
+ return std::error_code();
+
+ // TODO: For unconditional jump instructions (R_ARM_CALL and R_ARM_THM_CALL)
+ // fixup isn't possible without veneer generation for archs below ARMv5.
+
+ // Veneers may only be generated for STT_FUNC target symbols
+ // or for symbols located in sections different to the place of relocation.
+ const auto kindValue = ref.kindValue();
+ StringRef secName = atom.customSectionName();
+ if (DefinedAtom::typeCode != target->contentType() &&
+ !target->customSectionName().equals(secName)) {
+ StringRef kindValStr;
+ if (!this->_ctx.registry().referenceKindToString(
+ ref.kindNamespace(), ref.kindArch(), kindValue, kindValStr)) {
+ kindValStr = "unknown";
+ }
+
+ std::string errStr =
+ (Twine("Reference of type ") + Twine(kindValue) + " (" + kindValStr +
+ ") from " + atom.name() + "+" + Twine(ref.offsetInAtom()) + " to " +
+ ref.target()->name() + "+" + Twine(ref.addend()) +
+ " cannot be effected without a veneer").str();
+
+ llvm_unreachable(errStr.c_str());
+ }
+
+ const Atom *veneer = nullptr;
+ switch (kindValue) {
+ case R_ARM_JUMP24:
+ veneer = static_cast<Derived *>(this)
+ ->getVeneer_ARM_B_BL(target, secName);
+ break;
+ case R_ARM_THM_JUMP24:
+ veneer = static_cast<Derived *>(this)
+ ->getVeneer_THM_B_BL(target, secName);
+ break;
+ default:
+ llvm_unreachable("Unhandled reference type for veneer generation");
+ }
+
+ assert(veneer && "The veneer is not set");
+ const_cast<Reference &>(ref).setTarget(veneer);
+ return std::error_code();
+ }
+
+ std::error_code handleTLSIE32(const Reference &ref) {
+ if (const auto *target = dyn_cast<DefinedAtom>(ref.target())) {
+ const_cast<Reference &>(ref).setTarget(
+ static_cast<Derived *>(this)->getTLSTPOFF32(target));
+ return std::error_code();
+ }
+ llvm_unreachable("R_ARM_TLS_IE32 reloc targets wrong atom type");
+ }
+
+ /// \brief Create a GOT entry for TLS with reloc type and addend specified.
+ template <Reference::KindValue R_ARM_TLS, Reference::Addend A = 0>
+ const GOTAtom *getGOTTLSEntry(const DefinedAtom *da) {
+ auto got = _gotMap.find(da);
+ if (got != _gotMap.end())
+ return got->second;
+ auto g = new (_file._alloc) ARMGOTAtom(_file, ".got");
+ g->addReferenceELF_ARM(R_ARM_TLS, 0, da, A);
+#ifndef NDEBUG
+ g->_name = "__got_tls_";
+ g->_name += da->name();
+#endif
+ _gotMap[da] = g;
+ _gotVector.push_back(g);
+ return g;
+ }
+
+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);
+ }
+ }
+
+ // Add all created atoms to the link.
+ uint64_t ordinal = 0;
+ for (auto &got : _gotVector) {
+ got->setOrdinal(ordinal++);
+ mf->addAtom(*got);
+ }
+ for (auto &veneer : _veneerVector) {
+ veneer->setOrdinal(ordinal++);
+ mf->addAtom(*veneer);
+ }
+ }
+
+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<const Atom *, GOTAtom *> _gotMap;
+
+ /// \brief Map Atoms to their veneers.
+ llvm::DenseMap<const Atom *, VeneerAtom *> _veneerMap;
+
+ /// \brief the list of GOT/PLT atoms
+ std::vector<GOTAtom *> _gotVector;
+
+ /// \brief the list of veneer atoms.
+ std::vector<VeneerAtom *> _veneerVector;
+};
+
+/// 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) {}
+
+ /// \brief Get the veneer for ARM B/BL instructions.
+ const VeneerAtom *getVeneer_ARM_B_BL(const DefinedAtom *da,
+ StringRef secName) {
+ auto veneer = _veneerMap.find(da);
+ if (_veneerMap.end() != veneer)
+ return veneer->second;
+
+ auto v = new (_file._alloc) Veneer_ARM_B_BL_StaticAtom(_file, secName);
+ v->addReferenceELF_ARM(R_ARM_ABS32, 4, da, 0);
+
+ v->_name = "__";
+ v->_name += da->name();
+ v->_name += "_from_arm";
+
+ _veneerMap[da] = v;
+ _veneerVector.push_back(v);
+ return v;
+ }
+
+ /// \brief Get the veneer for Thumb B/BL instructions.
+ const VeneerAtom *getVeneer_THM_B_BL(const DefinedAtom *da,
+ StringRef secName) {
+ auto veneer = _veneerMap.find(da);
+ if (_veneerMap.end() != veneer)
+ return veneer->second;
+
+ auto v = new (_file._alloc) Veneer_THM_B_BL_StaticAtom(_file, secName);
+ v->addReferenceELF_ARM(R_ARM_JUMP24, 4, da, 0);
+
+ v->_name = "__";
+ v->_name += da->name();
+ v->_name += "_from_thumb";
+
+ _veneerMap[da] = v;
+ _veneerVector.push_back(v);
+ return v;
+ }
+
+ /// \brief Create a GOT entry for R_ARM_TLS_TPOFF32 reloc.
+ const GOTAtom *getTLSTPOFF32(const DefinedAtom *da) {
+ return getGOTTLSEntry<R_ARM_TLS_LE32>(da);
+ }
+};
+
+} // end of 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");
+ return llvm::make_unique<ARMStaticRelocationPass>(ctx);
+ default:
+ llvm_unreachable("Unhandled output file type");
+ }
+}
diff --git a/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.h b/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.h
new file mode 100644
index 0000000000000..651e798f33b1b
--- /dev/null
+++ b/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/lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h b/lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h
new file mode 100644
index 0000000000000..540a480421a8a
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h
@@ -0,0 +1,46 @@
+//===--------- lib/ReaderWriter/ELF/ARM/ARMSymbolTable.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_SYMBOL_TABLE_H
+#define LLD_READER_WRITER_ELF_ARM_ARM_SYMBOL_TABLE_H
+
+namespace lld {
+namespace elf {
+
+/// \brief The SymbolTable class represents the symbol table in a ELF file
+template<class ELFT>
+class ARMSymbolTable : public SymbolTable<ELFT> {
+public:
+ typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+
+ ARMSymbolTable(const ELFLinkingContext &context);
+
+ void addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da,
+ int64_t addr) override;
+};
+
+template <class ELFT>
+ARMSymbolTable<ELFT>::ARMSymbolTable(const ELFLinkingContext &context)
+ : SymbolTable<ELFT>(context, ".symtab",
+ DefaultLayout<ELFT>::ORDER_SYMBOL_TABLE) {}
+
+template <class ELFT>
+void ARMSymbolTable<ELFT>::addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da,
+ int64_t addr) {
+ SymbolTable<ELFT>::addDefinedAtom(sym, da, addr);
+
+ // Set zero bit to distinguish symbols addressing Thumb instructions
+ if (DefinedAtom::codeARMThumb == da->codeModel())
+ sym.st_value = static_cast<int64_t>(sym.st_value) | 0x1;
+}
+
+} // elf
+} // lld
+
+#endif // LLD_READER_WRITER_ELF_ARM_ARM_SYMBOL_TABLE_H
diff --git a/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp b/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp
new file mode 100644
index 0000000000000..de90f490f621b
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp
@@ -0,0 +1,44 @@
+//===--------- 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(
+ *_armTargetLayout.get())) {}
+
+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/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h b/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h
new file mode 100644
index 0000000000000..10641954da25d
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h
@@ -0,0 +1,88 @@
+//===--------- 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) {}
+
+ uint64_t getTPOffset() {
+ if (_tpOff.hasValue())
+ return *_tpOff;
+
+ for (const auto &phdr : *this->_programHeader) {
+ if (phdr->p_type == llvm::ELF::PT_TLS) {
+ _tpOff = llvm::RoundUpToAlignment(TCB_SIZE, phdr->p_align);
+ return *_tpOff;
+ }
+ }
+ llvm_unreachable("TLS segment not found");
+ }
+
+private:
+ // TCB block size of the TLS.
+ enum { TCB_SIZE = 0x8 };
+
+ // Cached value of the TLS offset from the $tp pointer.
+ llvm::Optional<uint64_t> _tpOff;
+};
+
+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() override {
+ return std::unique_ptr<Reader>(new ARMELFObjectReader(_context));
+ }
+
+ std::unique_ptr<Reader> getDSOReader() override {
+ return std::unique_ptr<Reader>(new ARMELFDSOReader(_context));
+ }
+
+ 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/lib/ReaderWriter/ELF/ARM/CMakeLists.txt b/lib/ReaderWriter/ELF/ARM/CMakeLists.txt
new file mode 100644
index 0000000000000..2ccf9eb6266db
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ARM/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_llvm_library(lldARMELFTarget
+ ARMLinkingContext.cpp
+ ARMTargetHandler.cpp
+ ARMRelocationHandler.cpp
+ ARMRelocationPass.cpp
+ LINK_LIBS
+ lldELF
+ lldReaderWriter
+ lldCore
+ LLVMObject
+ LLVMSupport
+ )
diff --git a/lib/ReaderWriter/ELF/ARM/Makefile b/lib/ReaderWriter/ELF/ARM/Makefile
new file mode 100644
index 0000000000000..f67d36a1b612d
--- /dev/null
+++ b/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/lib/ReaderWriter/ELF/ARM/TODO.rst b/lib/ReaderWriter/ELF/ARM/TODO.rst
new file mode 100644
index 0000000000000..d05419decb786
--- /dev/null
+++ b/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/lib/ReaderWriter/ELF/Atoms.h b/lib/ReaderWriter/ELF/Atoms.h
new file mode 100644
index 0000000000000..6a506d21d9385
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Atoms.h
@@ -0,0 +1,849 @@
+//===- lib/ReaderWriter/ELF/Atoms.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_ATOMS_H
+#define LLD_READER_WRITER_ELF_ATOMS_H
+
+#include "TargetHandler.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Simple.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include <memory>
+#include <vector>
+
+namespace lld {
+namespace elf {
+template <class ELFT> class DynamicFile;
+template <typename ELFT> class ELFFile;
+
+/// \brief Relocation References: Defined Atoms may contain references that will
+/// need to be patched before the executable is written.
+///
+/// Construction of ELFReferences is two pass process. ELFReferences are
+/// instantiated while we are iterating over symbol tables to atomize
+/// symbols. At that time we only know the index of relocation target symbol
+/// (not target atom) about a relocation, so we store the index to
+/// ELFREference. In the second pass, ELFReferences are revisited to update
+/// target atoms by target symbol indexes.
+template <class ELFT> class ELFReference : public Reference {
+ typedef llvm::object::Elf_Rel_Impl<ELFT, false> Elf_Rel;
+ typedef llvm::object::Elf_Rel_Impl<ELFT, true> Elf_Rela;
+ typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+
+public:
+ ELFReference(const Elf_Rela *rela, uint64_t off, Reference::KindArch arch,
+ Reference::KindValue relocType, uint32_t idx)
+ : Reference(Reference::KindNamespace::ELF, arch, relocType),
+ _target(nullptr), _targetSymbolIndex(idx), _offsetInAtom(off),
+ _addend(rela->r_addend) {}
+
+ ELFReference(uint64_t off, Reference::KindArch arch,
+ Reference::KindValue relocType, uint32_t idx)
+ : Reference(Reference::KindNamespace::ELF, arch, relocType),
+ _target(nullptr), _targetSymbolIndex(idx), _offsetInAtom(off),
+ _addend(0) {}
+
+ ELFReference(uint32_t edgeKind)
+ : Reference(Reference::KindNamespace::all, Reference::KindArch::all,
+ edgeKind),
+ _target(nullptr), _targetSymbolIndex(0), _offsetInAtom(0), _addend(0) {}
+
+ uint64_t offsetInAtom() const override { return _offsetInAtom; }
+
+ const Atom *target() const override { return _target; }
+
+ /// \brief The symbol table index that contains the target reference.
+ uint64_t targetSymbolIndex() const {
+ return _targetSymbolIndex;
+ }
+
+ Addend addend() const override { return _addend; }
+
+ virtual void setOffset(uint64_t off) { _offsetInAtom = off; }
+
+ void setAddend(Addend A) override { _addend = A; }
+
+ void setTarget(const Atom *newAtom) override { _target = newAtom; }
+
+private:
+ const Atom *_target;
+ uint64_t _targetSymbolIndex;
+ uint64_t _offsetInAtom;
+ Addend _addend;
+};
+
+/// \brief These atoms store symbols that are fixed to a particular address.
+/// This atom has no content its address will be used by the writer to fixup
+/// references that point to it.
+template <class ELFT> class ELFAbsoluteAtom : public AbsoluteAtom {
+ typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+
+public:
+ ELFAbsoluteAtom(const ELFFile<ELFT> &file, StringRef name,
+ const Elf_Sym *symbol, uint64_t value)
+ : _owningFile(file), _name(name), _symbol(symbol), _value(value) {
+ }
+
+ const ELFFile<ELFT> &file() const override { return _owningFile; }
+
+ Scope scope() const override {
+ if (_symbol->getVisibility() == llvm::ELF::STV_HIDDEN)
+ return scopeLinkageUnit;
+ if (_symbol->getBinding() == llvm::ELF::STB_LOCAL)
+ return scopeTranslationUnit;
+ return scopeGlobal;
+ }
+
+ StringRef name() const override { return _name; }
+
+ uint64_t value() const override { return _value; }
+
+private:
+ const ELFFile<ELFT> &_owningFile;
+ StringRef _name;
+ const Elf_Sym *_symbol;
+ uint64_t _value;
+};
+
+/// \brief ELFUndefinedAtom: These atoms store undefined symbols and are place
+/// holders that will be replaced by defined atoms later in the linking process.
+template <class ELFT> class ELFUndefinedAtom : public lld::UndefinedAtom {
+ typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+
+public:
+ ELFUndefinedAtom(const File &file, StringRef name, const Elf_Sym *symbol)
+ : _owningFile(file), _name(name), _symbol(symbol) {}
+
+ const File &file() const override { return _owningFile; }
+
+ StringRef name() const override { return _name; }
+
+ // A symbol in ELF can be undefined at build time if the symbol is a undefined
+ // weak symbol.
+ CanBeNull canBeNull() const override {
+ if (_symbol->getBinding() == llvm::ELF::STB_WEAK)
+ return CanBeNull::canBeNullAtBuildtime;
+ return CanBeNull::canBeNullNever;
+ }
+
+private:
+ const File &_owningFile;
+ StringRef _name;
+ const Elf_Sym *_symbol;
+};
+
+/// \brief This atom stores defined symbols and will contain either data or
+/// code.
+template <class ELFT> class ELFDefinedAtom : public DefinedAtom {
+ typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+ typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr;
+
+public:
+ ELFDefinedAtom(const ELFFile<ELFT> &file, StringRef symbolName,
+ StringRef sectionName, const Elf_Sym *symbol,
+ const Elf_Shdr *section, ArrayRef<uint8_t> contentData,
+ unsigned int referenceStart, unsigned int referenceEnd,
+ std::vector<ELFReference<ELFT> *> &referenceList)
+ : _owningFile(file), _symbolName(symbolName), _sectionName(sectionName),
+ _symbol(symbol), _section(section), _contentData(contentData),
+ _referenceStartIndex(referenceStart), _referenceEndIndex(referenceEnd),
+ _referenceList(referenceList), _contentType(typeUnknown),
+ _permissions(permUnknown) {}
+
+ ~ELFDefinedAtom() {}
+
+ const ELFFile<ELFT> &file() const override { return _owningFile; }
+
+ StringRef name() const override { return _symbolName; }
+
+ uint64_t ordinal() const override { return _ordinal; }
+
+ const Elf_Sym *symbol() const { return _symbol; }
+
+ const Elf_Shdr *section() const { return _section; }
+
+ uint64_t size() const override {
+ // Common symbols are not allocated in object files,
+ // so use st_size to tell how many bytes are required.
+ if (_symbol && (_symbol->getType() == llvm::ELF::STT_COMMON ||
+ _symbol->st_shndx == llvm::ELF::SHN_COMMON))
+ return (uint64_t) _symbol->st_size;
+
+ return _contentData.size();
+ }
+
+ Scope scope() const override {
+ if (!_symbol)
+ return scopeGlobal;
+ if (_symbol->getVisibility() == llvm::ELF::STV_HIDDEN)
+ return scopeLinkageUnit;
+ if (_symbol->getBinding() != llvm::ELF::STB_LOCAL)
+ return scopeGlobal;
+ return scopeTranslationUnit;
+ }
+
+ // FIXME: Need to revisit this in future.
+ Interposable interposable() const override { return interposeNo; }
+
+ Merge merge() const override {
+ if (!_symbol)
+ return mergeNo;
+
+ if (_symbol->getBinding() == llvm::ELF::STB_WEAK)
+ return mergeAsWeak;
+
+ if ((_symbol->getType() == llvm::ELF::STT_COMMON) ||
+ _symbol->st_shndx == llvm::ELF::SHN_COMMON)
+ return mergeAsTentative;
+
+ return mergeNo;
+ }
+
+ ContentType contentType() const override {
+ if (_contentType != typeUnknown)
+ return _contentType;
+
+ ContentType ret = typeUnknown;
+ uint64_t flags = _section->sh_flags;
+
+ if (_section->sh_type == llvm::ELF::SHT_GROUP)
+ return typeGroupComdat;
+
+ if (!_symbol && _sectionName.startswith(".gnu.linkonce"))
+ return typeGnuLinkOnce;
+
+ if (!(flags & llvm::ELF::SHF_ALLOC))
+ return _contentType = typeNoAlloc;
+
+ if (_section->sh_flags ==
+ (llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE | llvm::ELF::SHF_TLS)) {
+ return _contentType = _section->sh_type == llvm::ELF::SHT_NOBITS ? typeThreadZeroFill
+ : typeThreadData;
+ }
+
+ if ((_section->sh_flags == llvm::ELF::SHF_ALLOC) &&
+ (_section->sh_type == llvm::ELF::SHT_PROGBITS))
+ return _contentType = typeConstant;
+
+ if (_symbol->getType() == llvm::ELF::STT_GNU_IFUNC)
+ return _contentType = typeResolver;
+
+ if (_symbol->st_shndx == llvm::ELF::SHN_COMMON)
+ return _contentType = typeZeroFill;
+
+ switch (_section->sh_type) {
+ case llvm::ELF::SHT_PROGBITS:
+ flags &= ~llvm::ELF::SHF_ALLOC;
+ flags &= ~llvm::ELF::SHF_GROUP;
+ switch (flags) {
+ case llvm::ELF::SHF_EXECINSTR:
+ case (llvm::ELF::SHF_WRITE|llvm::ELF::SHF_EXECINSTR):
+ ret = typeCode;
+ break;
+ case llvm::ELF::SHF_WRITE:
+ ret = typeData;
+ break;
+ case (llvm::ELF::SHF_MERGE|llvm::ELF::SHF_STRINGS):
+ case llvm::ELF::SHF_STRINGS:
+ case llvm::ELF::SHF_MERGE:
+ ret = typeConstant;
+ break;
+ default:
+ ret = typeCode;
+ break;
+ }
+ break;
+ case llvm::ELF::SHT_NOTE:
+ flags &= ~llvm::ELF::SHF_ALLOC;
+ switch (flags) {
+ case llvm::ELF::SHF_WRITE:
+ ret = typeRWNote;
+ break;
+ default:
+ ret = typeRONote;
+ break;
+ }
+ break;
+ case llvm::ELF::SHT_NOBITS:
+ ret = typeZeroFill;
+ break;
+ case llvm::ELF::SHT_NULL:
+ if ((_symbol->getType() == llvm::ELF::STT_COMMON)
+ || _symbol->st_shndx == llvm::ELF::SHN_COMMON)
+ ret = typeZeroFill;
+ break;
+ case llvm::ELF::SHT_INIT_ARRAY:
+ case llvm::ELF::SHT_FINI_ARRAY:
+ ret = typeData;
+ break;
+ }
+
+ return _contentType = ret;
+ }
+
+ Alignment alignment() const override {
+ if (!_symbol)
+ return Alignment(0);
+
+ // Obtain proper value of st_value field.
+ const auto symValue = getSymbolValue(_symbol);
+
+ // Unallocated common symbols specify their alignment constraints in
+ // st_value.
+ if ((_symbol->getType() == llvm::ELF::STT_COMMON) ||
+ _symbol->st_shndx == llvm::ELF::SHN_COMMON) {
+ return Alignment(llvm::Log2_64(symValue));
+ }
+ if (_section->sh_addralign == 0) {
+ // sh_addralign of 0 means no alignment
+ return Alignment(0, symValue);
+ }
+ return Alignment(llvm::Log2_64(_section->sh_addralign),
+ symValue % _section->sh_addralign);
+ }
+
+ // Do we have a choice for ELF? All symbols live in explicit sections.
+ SectionChoice sectionChoice() const override {
+ switch (contentType()) {
+ case typeCode:
+ case typeData:
+ case typeZeroFill:
+ case typeThreadZeroFill:
+ case typeThreadData:
+ case typeConstant:
+ if ((_sectionName == ".text") || (_sectionName == ".data") ||
+ (_sectionName == ".bss") || (_sectionName == ".rodata") ||
+ (_sectionName == ".tdata") || (_sectionName == ".tbss"))
+ return sectionBasedOnContent;
+ default:
+ break;
+ }
+ return sectionCustomRequired;
+ }
+
+ StringRef customSectionName() const override {
+ if ((contentType() == typeZeroFill) ||
+ (_symbol && _symbol->st_shndx == llvm::ELF::SHN_COMMON))
+ return ".bss";
+ return _sectionName;
+ }
+
+ // It isn't clear that __attribute__((used)) is transmitted to the ELF object
+ // file.
+ DeadStripKind deadStrip() const override { return deadStripNormal; }
+
+ ContentPermissions permissions() const override {
+ if (_permissions != permUnknown)
+ return _permissions;
+
+ uint64_t flags = _section->sh_flags;
+
+ if (!(flags & llvm::ELF::SHF_ALLOC))
+ return _permissions = perm___;
+
+ switch (_section->sh_type) {
+ // permRW_L is for sections modified by the runtime
+ // loader.
+ case llvm::ELF::SHT_REL:
+ case llvm::ELF::SHT_RELA:
+ return _permissions = permRW_L;
+
+ case llvm::ELF::SHT_DYNAMIC:
+ case llvm::ELF::SHT_PROGBITS:
+ case llvm::ELF::SHT_NOTE:
+ flags &= ~llvm::ELF::SHF_ALLOC;
+ flags &= ~llvm::ELF::SHF_GROUP;
+ switch (flags) {
+ // Code
+ case llvm::ELF::SHF_EXECINSTR:
+ return _permissions = permR_X;
+ case (llvm::ELF::SHF_WRITE|llvm::ELF::SHF_EXECINSTR):
+ return _permissions = permRWX;
+ // Data
+ case llvm::ELF::SHF_WRITE:
+ return _permissions = permRW_;
+ // Strings
+ case llvm::ELF::SHF_MERGE:
+ case llvm::ELF::SHF_STRINGS:
+ return _permissions = permR__;
+
+ default:
+ if (flags & llvm::ELF::SHF_WRITE)
+ return _permissions = permRW_;
+ return _permissions = permR__;
+ }
+
+ case llvm::ELF::SHT_NOBITS:
+ return _permissions = permRW_;
+
+ case llvm::ELF::SHT_INIT_ARRAY:
+ case llvm::ELF::SHT_FINI_ARRAY:
+ return _permissions = permRW_;
+
+ default:
+ return _permissions = perm___;
+ }
+ }
+
+ ArrayRef<uint8_t> rawContent() const override { return _contentData; }
+
+ DefinedAtom::reference_iterator begin() const override {
+ uintptr_t index = _referenceStartIndex;
+ const void *it = reinterpret_cast<const void*>(index);
+ return reference_iterator(*this, it);
+ }
+
+ DefinedAtom::reference_iterator end() const override {
+ uintptr_t index = _referenceEndIndex;
+ const void *it = reinterpret_cast<const void*>(index);
+ return reference_iterator(*this, it);
+ }
+
+ const Reference *derefIterator(const void *It) const override {
+ uintptr_t index = reinterpret_cast<uintptr_t>(It);
+ assert(index >= _referenceStartIndex);
+ assert(index < _referenceEndIndex);
+ return ((_referenceList)[index]);
+ }
+
+ void incrementIterator(const void *&It) const override {
+ uintptr_t index = reinterpret_cast<uintptr_t>(It);
+ ++index;
+ It = reinterpret_cast<const void *>(index);
+ }
+
+ void addReference(ELFReference<ELFT> *reference) {
+ _referenceList.push_back(reference);
+ _referenceEndIndex = _referenceList.size();
+ }
+
+ virtual void setOrdinal(uint64_t ord) { _ordinal = ord; }
+
+protected:
+ /// Returns correct st_value for the symbol depending on the architecture.
+ /// For most architectures it's just a regular st_value with no changes.
+ virtual uint64_t getSymbolValue(const Elf_Sym *symbol) const {
+ return symbol->st_value;
+ }
+
+protected:
+ const ELFFile<ELFT> &_owningFile;
+ StringRef _symbolName;
+ StringRef _sectionName;
+ const Elf_Sym *_symbol;
+ const Elf_Shdr *_section;
+ /// \brief Holds the bits that make up the atom.
+ ArrayRef<uint8_t> _contentData;
+
+ uint64_t _ordinal;
+ unsigned int _referenceStartIndex;
+ unsigned int _referenceEndIndex;
+ std::vector<ELFReference<ELFT> *> &_referenceList;
+ mutable ContentType _contentType;
+ mutable ContentPermissions _permissions;
+};
+
+/// \brief This atom stores mergeable Strings
+template <class ELFT> class ELFMergeAtom : public DefinedAtom {
+ typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr;
+
+public:
+ ELFMergeAtom(const ELFFile<ELFT> &file, StringRef sectionName,
+ const Elf_Shdr *section, ArrayRef<uint8_t> contentData,
+ uint64_t offset)
+ : _owningFile(file), _sectionName(sectionName), _section(section),
+ _contentData(contentData), _offset(offset) {
+ }
+
+ const ELFFile<ELFT> &file() const override { return _owningFile; }
+
+ StringRef name() const override { return ""; }
+
+ virtual uint64_t section() const { return _section->sh_name; }
+
+ virtual uint64_t offset() const { return _offset; }
+
+ virtual void setOrdinal(uint64_t ord) { _ordinal = ord; }
+
+ uint64_t ordinal() const override { return _ordinal; }
+
+ uint64_t size() const override { return _contentData.size(); }
+
+ Scope scope() const override { return scopeTranslationUnit; }
+
+ Interposable interposable() const override { return interposeNo; }
+
+ Merge merge() const override { return mergeByContent; }
+
+ ContentType contentType() const override { return typeConstant; }
+
+ Alignment alignment() const override {
+ return Alignment(llvm::Log2_64(_section->sh_addralign));
+ }
+
+ SectionChoice sectionChoice() const override { return sectionCustomRequired; }
+
+ StringRef customSectionName() const override { return _sectionName; }
+
+ DeadStripKind deadStrip() const override { return deadStripNormal; }
+
+ ContentPermissions permissions() const override { return permR__; }
+
+ ArrayRef<uint8_t> rawContent() const override { return _contentData; }
+
+ DefinedAtom::reference_iterator begin() const override {
+ uintptr_t index = 0;
+ const void *it = reinterpret_cast<const void *>(index);
+ return reference_iterator(*this, it);
+ }
+
+ DefinedAtom::reference_iterator end() const override {
+ uintptr_t index = 0;
+ const void *it = reinterpret_cast<const void *>(index);
+ return reference_iterator(*this, it);
+ }
+
+ const Reference *derefIterator(const void *It) const override {
+ return nullptr;
+ }
+
+ void incrementIterator(const void *&It) const override {}
+
+private:
+
+ const ELFFile<ELFT> &_owningFile;
+ StringRef _sectionName;
+ const Elf_Shdr *_section;
+ /// \brief Holds the bits that make up the atom.
+ ArrayRef<uint8_t> _contentData;
+ uint64_t _ordinal;
+ uint64_t _offset;
+};
+
+template <class ELFT> class ELFCommonAtom : public DefinedAtom {
+ typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+public:
+ ELFCommonAtom(const ELFFile<ELFT> &file,
+ StringRef symbolName,
+ const Elf_Sym *symbol)
+ : _owningFile(file),
+ _symbolName(symbolName),
+ _symbol(symbol) {}
+
+ const ELFFile<ELFT> &file() const override { return _owningFile; }
+
+ StringRef name() const override { return _symbolName; }
+
+ uint64_t ordinal() const override { return _ordinal; }
+
+ virtual void setOrdinal(uint64_t ord) { _ordinal = ord; }
+
+ uint64_t size() const override { return _symbol->st_size; }
+
+ Scope scope() const override {
+ if (_symbol->getVisibility() == llvm::ELF::STV_HIDDEN)
+ return scopeLinkageUnit;
+ if (_symbol->getBinding() != llvm::ELF::STB_LOCAL)
+ return scopeGlobal;
+ return scopeTranslationUnit;
+ }
+
+ Interposable interposable() const override { return interposeNo; }
+
+ Merge merge() const override { return mergeAsTentative; }
+
+ ContentType contentType() const override { return typeZeroFill; }
+
+ Alignment alignment() const override {
+ return Alignment(llvm::Log2_64(_symbol->st_value));
+ }
+
+ SectionChoice sectionChoice() const override { return sectionBasedOnContent; }
+
+ StringRef customSectionName() const override { return ".bss"; }
+
+ DeadStripKind deadStrip() const override { return deadStripNormal; }
+
+ ContentPermissions permissions() const override { return permRW_; }
+
+ ArrayRef<uint8_t> rawContent() const override { return ArrayRef<uint8_t>(); }
+
+ DefinedAtom::reference_iterator begin() const override {
+ uintptr_t index = 0;
+ const void *it = reinterpret_cast<const void *>(index);
+ return reference_iterator(*this, it);
+ }
+
+ DefinedAtom::reference_iterator end() const override {
+ uintptr_t index = 0;
+ const void *it = reinterpret_cast<const void *>(index);
+ return reference_iterator(*this, it);
+ }
+
+protected:
+ const Reference *derefIterator(const void *iter) const override {
+ return nullptr;
+ }
+
+ void incrementIterator(const void *&iter) const override {}
+
+ const ELFFile<ELFT> &_owningFile;
+ StringRef _symbolName;
+ const Elf_Sym *_symbol;
+ uint64_t _ordinal;
+};
+
+/// \brief An atom from a shared library.
+template <class ELFT> class ELFDynamicAtom : public SharedLibraryAtom {
+ typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+
+public:
+ ELFDynamicAtom(const DynamicFile<ELFT> &file, StringRef symbolName,
+ StringRef loadName, const Elf_Sym *symbol)
+ : _owningFile(file), _symbolName(symbolName), _loadName(loadName),
+ _symbol(symbol) {
+ }
+
+ const DynamicFile<ELFT> &file() const override { return _owningFile; }
+
+ StringRef name() const override { return _symbolName; }
+
+ virtual Scope scope() const {
+ if (_symbol->getVisibility() == llvm::ELF::STV_HIDDEN)
+ return scopeLinkageUnit;
+ if (_symbol->getBinding() != llvm::ELF::STB_LOCAL)
+ return scopeGlobal;
+ return scopeTranslationUnit;
+ }
+
+ StringRef loadName() const override { return _loadName; }
+
+ bool canBeNullAtRuntime() const override {
+ return _symbol->getBinding() == llvm::ELF::STB_WEAK;
+ }
+
+ Type type() const override {
+ switch (_symbol->getType()) {
+ case llvm::ELF::STT_FUNC:
+ case llvm::ELF::STT_GNU_IFUNC:
+ return Type::Code;
+ case llvm::ELF::STT_OBJECT:
+ return Type::Data;
+ default:
+ return Type::Unknown;
+ }
+ }
+
+ uint64_t size() const override {
+ return _symbol->st_size;
+ }
+
+private:
+
+ const DynamicFile<ELFT> &_owningFile;
+ StringRef _symbolName;
+ StringRef _loadName;
+ const Elf_Sym *_symbol;
+};
+
+class SimpleELFDefinedAtom : public SimpleDefinedAtom {
+public:
+ SimpleELFDefinedAtom(const File &f) : SimpleDefinedAtom(f) {}
+
+ void addReferenceELF(Reference::KindArch arch, Reference::KindValue kindValue,
+ uint64_t off, const Atom *target,
+ Reference::Addend addend) {
+ this->addReference(Reference::KindNamespace::ELF, arch, kindValue, off,
+ target, addend);
+ }
+
+ void addReferenceELF_Hexagon(Reference::KindValue relocType, uint64_t off,
+ const Atom *t, Reference::Addend a) {
+ this->addReferenceELF(Reference::KindArch::Hexagon, relocType, off, t, a);
+ }
+
+ void addReferenceELF_x86_64(Reference::KindValue relocType, uint64_t off,
+ const Atom *t, Reference::Addend a) {
+ this->addReferenceELF(Reference::KindArch::x86_64, relocType, off, t, a);
+ }
+
+ void addReferenceELF_Mips(Reference::KindValue relocType, uint64_t off,
+ const Atom *t, Reference::Addend a) {
+ this->addReferenceELF(Reference::KindArch::Mips, relocType, off, t, a);
+ }
+
+ void addReferenceELF_AArch64(Reference::KindValue relocType, uint64_t off,
+ const Atom *t, Reference::Addend a) {
+ this->addReferenceELF(Reference::KindArch::AArch64, relocType, off, t, a);
+ }
+
+ void addReferenceELF_ARM(Reference::KindValue 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
+/// generated.
+class ObjectAtom : public SimpleELFDefinedAtom {
+public:
+ ObjectAtom(const File &f) : SimpleELFDefinedAtom(f) {}
+
+ Scope scope() const override { return scopeGlobal; }
+
+ SectionChoice sectionChoice() const override { return sectionBasedOnContent; }
+
+ ContentType contentType() const override { return typeZeroFill; }
+
+ uint64_t size() const override { return _size; }
+
+ DynamicExport dynamicExport() const override { return dynamicExportAlways; }
+
+ ContentPermissions permissions() const override { return permRW_; }
+
+ ArrayRef<uint8_t> rawContent() const override { return ArrayRef<uint8_t>(); }
+
+ Alignment alignment() const override {
+ // The alignment should be 8 byte aligned
+ return Alignment(3);
+ }
+
+ StringRef name() const override { return _name; }
+
+ std::string _name;
+ uint64_t _size;
+};
+
+class GOTAtom : public SimpleELFDefinedAtom {
+ StringRef _section;
+
+public:
+ GOTAtom(const File &f, StringRef secName)
+ : SimpleELFDefinedAtom(f), _section(secName) {}
+
+ Scope scope() const override { return scopeTranslationUnit; }
+
+ SectionChoice sectionChoice() const override { return sectionCustomRequired; }
+
+ StringRef customSectionName() const override { return _section; }
+
+ ContentType contentType() const override { return typeGOT; }
+
+ uint64_t size() const override { return rawContent().size(); }
+
+ ContentPermissions permissions() const override { return permRW_; }
+
+ Alignment alignment() const override {
+ // The alignment should be 8 byte aligned
+ return Alignment(3);
+ }
+
+#ifndef NDEBUG
+ StringRef name() const override { return _name; }
+ std::string _name;
+#else
+ StringRef name() const override { return ""; }
+#endif
+};
+
+class PLTAtom : public SimpleELFDefinedAtom {
+ StringRef _section;
+
+public:
+ PLTAtom(const File &f, StringRef secName)
+ : SimpleELFDefinedAtom(f), _section(secName) {}
+
+ Scope scope() const override { return scopeTranslationUnit; }
+
+ SectionChoice sectionChoice() const override { return sectionCustomRequired; }
+
+ StringRef customSectionName() const override { return _section; }
+
+ ContentType contentType() const override { return typeStub; }
+
+ uint64_t size() const override { return rawContent().size(); }
+
+ ContentPermissions permissions() const override { return permR_X; }
+
+ Alignment alignment() const override {
+ return Alignment(4); // 16
+ }
+
+#ifndef NDEBUG
+ StringRef name() const override { return _name; }
+ std::string _name;
+#else
+ StringRef name() const override { return ""; }
+#endif
+};
+
+class PLT0Atom : public PLTAtom {
+public:
+ PLT0Atom(const File &f) : PLTAtom(f, ".plt") {
+#ifndef NDEBUG
+ _name = ".PLT0";
+#endif
+ }
+};
+
+class GLOBAL_OFFSET_TABLEAtom : public SimpleELFDefinedAtom {
+public:
+ GLOBAL_OFFSET_TABLEAtom(const File &f) : SimpleELFDefinedAtom(f) {}
+
+ StringRef name() const override { return "_GLOBAL_OFFSET_TABLE_"; }
+
+ Scope scope() const override { return scopeLinkageUnit; }
+
+ SectionChoice sectionChoice() const override { return sectionCustomRequired; }
+
+ StringRef customSectionName() const override { return ".got.plt"; }
+
+ ContentType contentType() const override { return typeGOT; }
+
+ uint64_t size() const override { return 0; }
+
+ ContentPermissions permissions() const override { return permRW_; }
+
+ Alignment alignment() const override {
+ // Needs 8 byte alignment
+ return Alignment(3);
+ }
+
+ ArrayRef<uint8_t> rawContent() const override { return ArrayRef<uint8_t>(); }
+};
+
+class DYNAMICAtom : public SimpleELFDefinedAtom {
+public:
+ DYNAMICAtom(const File &f) : SimpleELFDefinedAtom(f) {}
+
+ StringRef name() const override { return "_DYNAMIC"; }
+
+ Scope scope() const override { return scopeLinkageUnit; }
+
+ Merge merge() const override { return mergeNo; }
+
+ SectionChoice sectionChoice() const override { return sectionCustomRequired; }
+
+ StringRef customSectionName() const override { return ".dynamic"; }
+
+ ContentType contentType() const override { return typeData; }
+
+ uint64_t size() const override { return 0; }
+
+ ContentPermissions permissions() const override { return permRW_; }
+
+ Alignment alignment() const override { return Alignment(0); }
+
+ ArrayRef<uint8_t> rawContent() const override { return ArrayRef<uint8_t>(); }
+};
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/CMakeLists.txt b/lib/ReaderWriter/ELF/CMakeLists.txt
new file mode 100644
index 0000000000000..fd4cb669904d9
--- /dev/null
+++ b/lib/ReaderWriter/ELF/CMakeLists.txt
@@ -0,0 +1,19 @@
+add_llvm_library(lldELF
+ ELFLinkingContext.cpp
+ Reader.cpp
+ Writer.cpp
+ LINK_LIBS
+ lldReaderWriter
+ lldCore
+ lldYAML
+ LLVMSupport
+ )
+
+include_directories(.)
+
+add_subdirectory(X86)
+add_subdirectory(X86_64)
+add_subdirectory(Mips)
+add_subdirectory(Hexagon)
+add_subdirectory(AArch64)
+add_subdirectory(ARM)
diff --git a/lib/ReaderWriter/ELF/Chunk.h b/lib/ReaderWriter/ELF/Chunk.h
new file mode 100644
index 0000000000000..2658d023b3a9b
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Chunk.h
@@ -0,0 +1,102 @@
+//===- lib/ReaderWriter/ELF/Chunks.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_CHUNKS_H
+#define LLD_READER_WRITER_ELF_CHUNKS_H
+
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ELF.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include <memory>
+
+namespace lld {
+class ELFLinkingContext;
+
+namespace elf {
+class ELFWriter;
+
+template <class ELFT> class TargetLayout;
+
+/// \brief A chunk is a contiguous region of space
+template<class ELFT>
+class Chunk {
+public:
+
+ /// \brief Describes the type of Chunk
+ enum Kind : uint8_t{ ELFHeader, ///< ELF Header
+ ProgramHeader, ///< Program Header
+ SectionHeader, ///< Section header
+ ELFSegment, ///< Segment
+ ELFSection, ///< Section
+ AtomSection, ///< A section containing atoms.
+ Expression ///< A linker script expression
+ };
+ /// \brief the ContentType of the chunk
+ enum ContentType : uint8_t{ Unknown, Header, Code, Data, Note, TLS };
+
+ Chunk(StringRef name, Kind kind, const ELFLinkingContext &context)
+ : _name(name), _kind(kind), _fsize(0), _msize(0), _alignment(0), _order(0),
+ _ordinal(1), _start(0), _fileoffset(0), _context(context) {}
+ virtual ~Chunk() {}
+ // The name of the chunk
+ StringRef name() const { return _name; }
+ // Kind of chunk
+ Kind kind() const { return _kind; }
+ virtual uint64_t fileSize() const { return _fsize; }
+ virtual void setFileSize(uint64_t sz) { _fsize = sz; }
+ virtual void setAlign(uint64_t align) { _alignment = align; }
+ virtual uint64_t alignment() const { return _alignment; }
+
+ // The ordinal value of the chunk
+ uint64_t ordinal() const { return _ordinal;}
+ void setOrdinal(uint64_t newVal) { _ordinal = newVal;}
+ // The order in which the chunk would appear in the output file
+ uint64_t order() const { return _order; }
+ void setOrder(uint32_t order) { _order = order; }
+ // Output file offset of the chunk
+ uint64_t fileOffset() const { return _fileoffset; }
+ void setFileOffset(uint64_t offset) { _fileoffset = offset; }
+ // Output start address of the chunk
+ virtual void setVirtualAddr(uint64_t start) { _start = start; }
+ virtual uint64_t virtualAddr() const { return _start; }
+ // Memory size of the chunk
+ uint64_t memSize() const { return _msize; }
+ void setMemSize(uint64_t msize) { _msize = msize; }
+ // Whats the contentType of the chunk?
+ virtual int getContentType() const = 0;
+ // Writer the chunk
+ virtual void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
+ llvm::FileOutputBuffer &buffer) = 0;
+ // Finalize the chunk before assigning offsets/virtual addresses
+ virtual void doPreFlight() = 0;
+ // Finalize the chunk before writing
+ virtual void finalize() = 0;
+
+protected:
+ StringRef _name;
+ Kind _kind;
+ uint64_t _fsize;
+ uint64_t _msize;
+ uint64_t _alignment;
+ uint32_t _order;
+ uint64_t _ordinal;
+ uint64_t _start;
+ uint64_t _fileoffset;
+ const ELFLinkingContext &_context;
+};
+
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/CreateELF.h b/lib/ReaderWriter/ELF/CreateELF.h
new file mode 100644
index 0000000000000..ad34dddb24d3d
--- /dev/null
+++ b/lib/ReaderWriter/ELF/CreateELF.h
@@ -0,0 +1,118 @@
+//===- lib/ReaderWriter/ELF/CreateELF.h -----------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file provides a simple way to create an object templated on
+/// ELFType depending on the runtime type needed.
+///
+//===----------------------------------------------------------------------===//
+#ifndef LLD_READER_WRITER_ELF_CREATE_ELF_H
+#define LLD_READER_WRITER_ELF_CREATE_ELF_H
+
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Compiler.h"
+
+namespace {
+using llvm::object::ELFType;
+
+/// \func createELF
+/// \brief Create an object depending on the runtime attributes and alignment
+/// of an ELF file.
+///
+/// \param Traits
+/// Traits::result_type must be a type convertable from what create returns.
+/// Traits::create must be a template function which takes an ELFType and
+/// returns something convertable to Traits::result_type.
+///
+/// \param ident pair of EI_CLASS and EI_DATA.
+/// \param maxAlignment the maximum alignment of the file.
+/// \param args arguments forwarded to CreateELFTraits<T>::create.
+
+#define LLVM_CREATE_ELF_CreateELFTraits(endian, align, is64, ...) \
+ Traits::template create<ELFType<llvm::support::endian, align, is64>>( \
+ __VA_ARGS__);
+
+#if !LLVM_IS_UNALIGNED_ACCESS_FAST
+# define LLVM_CREATE_ELF_MaxAlignCheck(normal, low, endian, is64, ...) \
+ if (maxAlignment >= normal) \
+ return LLVM_CREATE_ELF_CreateELFTraits(endian, normal, is64, __VA_ARGS__) \
+ else if (maxAlignment >= low) \
+ return LLVM_CREATE_ELF_CreateELFTraits(endian, low, is64, __VA_ARGS__) \
+ else \
+ llvm_unreachable("Invalid alignment for ELF file!");
+#else
+# define LLVM_CREATE_ELF_MaxAlignCheck(normal, low, endian, is64, ...) \
+ if (maxAlignment >= low) \
+ return LLVM_CREATE_ELF_CreateELFTraits(endian, low, is64, __VA_ARGS__) \
+ else \
+ llvm_unreachable("Invalid alignment for ELF file!");
+#endif
+
+#define LLVM_CREATE_ELF_IMPL(...) \
+ if (ident.first == llvm::ELF::ELFCLASS32 && \
+ ident.second == llvm::ELF::ELFDATA2LSB) { \
+ LLVM_CREATE_ELF_MaxAlignCheck(4, 2, little, false, __VA_ARGS__) \
+ } else if (ident.first == llvm::ELF::ELFCLASS32 && \
+ ident.second == llvm::ELF::ELFDATA2MSB) { \
+ LLVM_CREATE_ELF_MaxAlignCheck(4, 2, big, false, __VA_ARGS__) \
+ } else if (ident.first == llvm::ELF::ELFCLASS64 && \
+ ident.second == llvm::ELF::ELFDATA2MSB) { \
+ LLVM_CREATE_ELF_MaxAlignCheck(8, 2, big, true, __VA_ARGS__) \
+ } else if (ident.first == llvm::ELF::ELFCLASS64 && \
+ ident.second == llvm::ELF::ELFDATA2LSB) { \
+ LLVM_CREATE_ELF_MaxAlignCheck(8, 2, little, true, __VA_ARGS__) \
+ } \
+ llvm_unreachable("Invalid ELF type!");
+
+#if LLVM_HAS_VARIADIC_TEMPLATES
+template <class Traits, class ...Args>
+typename Traits::result_type createELF(
+ std::pair<unsigned char, unsigned char> ident, std::size_t maxAlignment,
+ Args &&...args) {
+ LLVM_CREATE_ELF_IMPL(std::forward<Args>(args)...)
+}
+#else
+template <class Traits, class T1>
+typename Traits::result_type createELF(
+ std::pair<unsigned char, unsigned char> ident, std::size_t maxAlignment,
+ T1 &&t1) {
+ LLVM_CREATE_ELF_IMPL(std::forward<T1>(t1))
+}
+
+template <class Traits, class T1, class T2>
+typename Traits::result_type createELF(
+ std::pair<unsigned char, unsigned char> ident, std::size_t maxAlignment,
+ T1 &&t1, T2 &&t2) {
+ LLVM_CREATE_ELF_IMPL(std::forward<T1>(t1), std::forward<T2>(t2))
+}
+
+template <class Traits, class T1, class T2, class T3>
+typename Traits::result_type createELF(
+ std::pair<unsigned char, unsigned char> ident, std::size_t maxAlignment,
+ T1 &&t1, T2 &&t2, T3 &&t3) {
+ LLVM_CREATE_ELF_IMPL(std::forward<T1>(t1), std::forward<T2>(t2),
+ std::forward<T3>(t3))
+}
+
+template <class Traits, class T1, class T2, class T3, class T4>
+typename Traits::result_type createELF(
+ std::pair<unsigned char, unsigned char> ident, std::size_t maxAlignment,
+ T1 &&t1, T2 &&t2, T3 &&t3, T4 &&t4) {
+ LLVM_CREATE_ELF_IMPL(std::forward<T1>(t1), std::forward<T2>(t2),
+ std::forward<T3>(t3), std::forward<T4>(t4))
+}
+
+#endif // LLVM_HAS_VARIADIC_TEMPLATES
+} // end anon namespace
+
+#undef LLVM_CREATE_ELF_CreateELFTraits
+#undef LLVM_CREATE_ELF_MaxAlignCheck
+#undef LLVM_CREATE_ELF_IMPL
+
+#endif
diff --git a/lib/ReaderWriter/ELF/DefaultLayout.h b/lib/ReaderWriter/ELF/DefaultLayout.h
new file mode 100644
index 0000000000000..9af3b8eb8dc63
--- /dev/null
+++ b/lib/ReaderWriter/ELF/DefaultLayout.h
@@ -0,0 +1,1050 @@
+//===- lib/ReaderWriter/ELF/DefaultLayout.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_DEFAULT_LAYOUT_H
+#define LLD_READER_WRITER_ELF_DEFAULT_LAYOUT_H
+
+#include "Atoms.h"
+#include "Chunk.h"
+#include "HeaderChunks.h"
+#include "Layout.h"
+#include "SectionChunks.h"
+#include "SegmentChunks.h"
+#include "lld/Core/Instrumentation.h"
+#include "lld/Core/STDExtras.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Format.h"
+#include <map>
+#include <unordered_map>
+
+namespace lld {
+namespace elf {
+/// \brief The DefaultLayout class is used by the Writer to arrange
+/// sections and segments in the order determined by the target ELF
+/// format. The writer creates a single instance of the DefaultLayout
+/// class
+template<class ELFT>
+class DefaultLayout : public Layout {
+public:
+
+ // The order in which the sections appear in the output file
+ // If its determined, that the layout needs to change
+ // just changing the order of enumerations would essentially
+ // change the layout in the output file
+ // Change the enumerations so that Target can override and stick
+ // a section anywhere it wants to
+ enum DefaultSectionOrder {
+ ORDER_NOT_DEFINED = 0,
+ ORDER_INTERP = 10,
+ ORDER_RO_NOTE = 15,
+ ORDER_HASH = 30,
+ ORDER_DYNAMIC_SYMBOLS = 40,
+ ORDER_DYNAMIC_STRINGS = 50,
+ ORDER_DYNAMIC_RELOCS = 52,
+ ORDER_DYNAMIC_PLT_RELOCS = 54,
+ ORDER_INIT = 60,
+ ORDER_PLT = 70,
+ ORDER_TEXT = 80,
+ ORDER_FINI = 90,
+ ORDER_REL = 95,
+ ORDER_RODATA = 100,
+ ORDER_EH_FRAME = 110,
+ ORDER_EH_FRAMEHDR = 120,
+ ORDER_TDATA = 124,
+ ORDER_TBSS = 128,
+ ORDER_CTORS = 130,
+ ORDER_DTORS = 140,
+ ORDER_INIT_ARRAY = 150,
+ ORDER_FINI_ARRAY = 160,
+ ORDER_DYNAMIC = 170,
+ ORDER_GOT = 180,
+ ORDER_GOT_PLT = 190,
+ ORDER_DATA = 200,
+ ORDER_RW_NOTE = 205,
+ ORDER_BSS = 210,
+ ORDER_NOALLOC = 215,
+ ORDER_OTHER = 220,
+ ORDER_SECTION_STRINGS = 230,
+ ORDER_SYMBOL_TABLE = 240,
+ ORDER_STRING_TABLE = 250,
+ ORDER_SECTION_HEADERS = 260
+ };
+
+public:
+
+ // The Key used for creating Sections
+ // The sections are created using
+ // SectionName, contentPermissions
+ struct SectionKey {
+ SectionKey(StringRef name, DefinedAtom::ContentPermissions perm,
+ StringRef path)
+ : _name(name), _perm(perm), _path(path) {}
+
+ // Data members
+ StringRef _name;
+ DefinedAtom::ContentPermissions _perm;
+ StringRef _path;
+ };
+
+ struct SectionKeyHash {
+ int64_t operator()(const SectionKey &k) const {
+ return llvm::hash_combine(k._name, k._perm, k._path);
+ }
+ };
+
+ struct SectionKeyEq {
+ bool operator()(const SectionKey &lhs, const SectionKey &rhs) const {
+ return ((lhs._name == rhs._name) && (lhs._perm == rhs._perm) &&
+ (lhs._path == rhs._path));
+ }
+ };
+
+ typedef typename std::vector<Chunk<ELFT> *>::iterator ChunkIter;
+ typedef typename std::vector<Segment<ELFT> *>::iterator SegmentIter;
+
+ // The additional segments are used to figure out
+ // if there is a segment by that type already created
+ // For example : PT_TLS, we have two sections .tdata/.tbss
+ // that are part of PT_TLS, we need to create this additional
+ // segment only once
+ typedef std::pair<int64_t, int64_t> AdditionalSegmentKey;
+ // The segments are created using
+ // SegmentName, Segment flags
+ typedef std::pair<StringRef, int64_t> SegmentKey;
+
+ // HashKey for the Segment
+ class SegmentHashKey {
+ public:
+ int64_t operator() (const SegmentKey &k) const {
+ // k.first = SegmentName
+ // k.second = SegmentFlags
+ return llvm::hash_combine(k.first, k.second);
+ }
+ };
+
+ class AdditionalSegmentHashKey {
+ public:
+ int64_t operator()(const AdditionalSegmentKey &k) const {
+ // k.first = SegmentName
+ // k.second = SegmentFlags
+ return llvm::hash_combine(k.first, k.second);
+ }
+ };
+
+ // Output Sections contain the map of Sectionnames to a vector of sections,
+ // that have been merged to form a single section
+ typedef llvm::StringMap<OutputSection<ELFT> *> OutputSectionMapT;
+ typedef
+ typename std::vector<OutputSection<ELFT> *>::iterator OutputSectionIter;
+
+ typedef std::unordered_map<SectionKey, AtomSection<ELFT> *, SectionKeyHash,
+ SectionKeyEq> SectionMapT;
+ typedef std::unordered_map<AdditionalSegmentKey, Segment<ELFT> *,
+ AdditionalSegmentHashKey> AdditionalSegmentMapT;
+ typedef std::unordered_map<SegmentKey, Segment<ELFT> *, SegmentHashKey>
+ SegmentMapT;
+
+ /// \brief find a absolute atom pair given a absolute atom name
+ struct FindByName {
+ const std::string _name;
+ FindByName(StringRef name) : _name(name) {}
+ bool operator()(const lld::AtomLayout *j) { return j->_atom->name() == _name; }
+ };
+
+ typedef typename std::vector<lld::AtomLayout *>::iterator AbsoluteAtomIterT;
+
+ typedef llvm::DenseSet<const Atom *> AtomSetT;
+
+ DefaultLayout(ELFLinkingContext &context)
+ : _context(context), _linkerScriptSema(context.linkerScriptSema()) {}
+
+ /// \brief Return the section order for a input section
+ SectionOrder getSectionOrder(StringRef name, int32_t contentType,
+ int32_t contentPermissions) override;
+
+ /// \brief Return the name of the input section by decoding the input
+ /// sectionChoice.
+ virtual StringRef getInputSectionName(const DefinedAtom *da) const;
+
+ /// \brief Return the name of the output section from the input section.
+ virtual StringRef getOutputSectionName(StringRef archivePath,
+ StringRef memberPath,
+ StringRef inputSectionName) const;
+
+ /// \brief Gets or creates a section.
+ AtomSection<ELFT> *
+ getSection(StringRef name, int32_t contentType,
+ DefinedAtom::ContentPermissions contentPermissions,
+ const DefinedAtom *da);
+
+ /// \brief Gets the segment for a output section
+ virtual Layout::SegmentType getSegmentType(Section<ELFT> *section) const;
+
+ /// \brief Returns true/false depending on whether the section has a Output
+ // segment or not
+ static bool hasOutputSegment(Section<ELFT> *section);
+
+ // Adds an atom to the section
+ ErrorOr<const lld::AtomLayout *> addAtom(const Atom *atom) override;
+
+ /// \brief Find an output Section given a section name.
+ OutputSection<ELFT> *findOutputSection(StringRef name) {
+ auto iter = _outputSectionMap.find(name);
+ if (iter == _outputSectionMap.end())
+ return nullptr;
+ return iter->second;
+ }
+
+ /// \brief find a absolute atom given a name
+ AbsoluteAtomIterT findAbsoluteAtom(StringRef name) {
+ return std::find_if(_absoluteAtoms.begin(), _absoluteAtoms.end(),
+ FindByName(name));
+ }
+
+ // Output sections with the same name into a OutputSection
+ void createOutputSections();
+
+ /// \brief Sort the sections by their order as defined by the layout,
+ /// preparing all sections to be assigned to a segment.
+ virtual void sortInputSections();
+
+ /// \brief Add extra chunks to a segment just before including the input
+ /// section given by <archivePath, memberPath, sectionName>. This
+ /// is used to add linker script expressions before each section.
+ virtual void addExtraChunksToSegment(Segment<ELFT> *segment,
+ StringRef archivePath,
+ StringRef memberPath,
+ StringRef sectionName);
+
+ void assignSectionsToSegments() override;
+
+ void assignVirtualAddress() override;
+
+ void assignFileOffsetsForMiscSections();
+
+ range<AbsoluteAtomIterT> absoluteAtoms() { return _absoluteAtoms; }
+
+ void addSection(Chunk<ELFT> *c) { _sections.push_back(c); }
+
+ void finalize() {
+ ScopedTask task(getDefaultDomain(), "Finalize layout");
+ for (auto &si : _sections)
+ si->finalize();
+ }
+
+ void doPreFlight() {
+ for (auto &si : _sections)
+ si->doPreFlight();
+ }
+
+ const AtomLayout *findAtomLayoutByName(StringRef name) const override {
+ for (auto sec : _sections)
+ if (auto section = dyn_cast<Section<ELFT>>(sec))
+ if (auto *al = section->findAtomLayoutByName(name))
+ return al;
+ return nullptr;
+ }
+
+ void setHeader(ELFHeader<ELFT> *elfHeader) { _elfHeader = elfHeader; }
+
+ void setProgramHeader(ProgramHeader<ELFT> *p) {
+ _programHeader = p;
+ }
+
+ range<OutputSectionIter> outputSections() { return _outputSections; }
+
+ range<ChunkIter> sections() { return _sections; }
+
+ range<SegmentIter> segments() { return _segments; }
+
+ ELFHeader<ELFT> *getHeader() { return _elfHeader; }
+
+ bool hasDynamicRelocationTable() const { return !!_dynamicRelocationTable; }
+
+ bool hasPLTRelocationTable() const { return !!_pltRelocationTable; }
+
+ /// \brief Get or create the dynamic relocation table. All relocations in this
+ /// table are processed at startup.
+ RelocationTable<ELFT> *getDynamicRelocationTable() {
+ if (!_dynamicRelocationTable) {
+ _dynamicRelocationTable = std::move(createRelocationTable(
+ _context.isRelaOutputFormat() ? ".rela.dyn" : ".rel.dyn",
+ ORDER_DYNAMIC_RELOCS));
+ addSection(_dynamicRelocationTable.get());
+ }
+ return _dynamicRelocationTable.get();
+ }
+
+ /// \brief Get or create the PLT relocation table. Referenced by DT_JMPREL.
+ RelocationTable<ELFT> *getPLTRelocationTable() {
+ if (!_pltRelocationTable) {
+ _pltRelocationTable = std::move(createRelocationTable(
+ _context.isRelaOutputFormat() ? ".rela.plt" : ".rel.plt",
+ ORDER_DYNAMIC_PLT_RELOCS));
+ addSection(_pltRelocationTable.get());
+ }
+ return _pltRelocationTable.get();
+ }
+
+ uint64_t getTLSSize() const {
+ for (const auto &phdr : *_programHeader)
+ if (phdr->p_type == llvm::ELF::PT_TLS)
+ return phdr->p_memsz;
+ return 0;
+ }
+
+ bool isReferencedByDefinedAtom(const Atom *a) const {
+ return _referencedDynAtoms.count(a);
+ }
+
+ bool isCopied(const SharedLibraryAtom *sla) const {
+ return _copiedDynSymNames.count(sla->name());
+ }
+
+ /// \brief Handle SORT_BY_PRIORITY.
+ void sortOutputSectionByPriority(StringRef outputSectionName,
+ StringRef prefix);
+
+protected:
+ /// \brief TargetLayouts may use these functions to reorder the input sections
+ /// in a order defined by their ABI.
+ virtual void finalizeOutputSectionLayout() {}
+
+ /// \brief Allocate a new section.
+ virtual AtomSection<ELFT> *createSection(
+ StringRef name, int32_t contentType,
+ DefinedAtom::ContentPermissions contentPermissions,
+ SectionOrder sectionOrder);
+
+ /// \brief Create a new relocation table.
+ virtual unique_bump_ptr<RelocationTable<ELFT>>
+ createRelocationTable(StringRef name, int32_t order) {
+ return unique_bump_ptr<RelocationTable<ELFT>>(
+ new (_allocator) RelocationTable<ELFT>(_context, name, order));
+ }
+
+private:
+ /// Helper function that returns the priority value from an input section.
+ uint32_t getPriorityFromSectionName(StringRef sectionName) const;
+
+protected:
+ llvm::BumpPtrAllocator _allocator;
+ SectionMapT _sectionMap;
+ OutputSectionMapT _outputSectionMap;
+ AdditionalSegmentMapT _additionalSegmentMap;
+ SegmentMapT _segmentMap;
+ std::vector<Chunk<ELFT> *> _sections;
+ std::vector<Segment<ELFT> *> _segments;
+ std::vector<OutputSection<ELFT> *> _outputSections;
+ ELFHeader<ELFT> *_elfHeader;
+ ProgramHeader<ELFT> *_programHeader;
+ unique_bump_ptr<RelocationTable<ELFT>> _dynamicRelocationTable;
+ unique_bump_ptr<RelocationTable<ELFT>> _pltRelocationTable;
+ std::vector<lld::AtomLayout *> _absoluteAtoms;
+ AtomSetT _referencedDynAtoms;
+ llvm::StringSet<> _copiedDynSymNames;
+ ELFLinkingContext &_context;
+ script::Sema &_linkerScriptSema;
+};
+
+template <class ELFT>
+Layout::SectionOrder DefaultLayout<ELFT>::getSectionOrder(
+ StringRef name, int32_t contentType, int32_t contentPermissions) {
+ switch (contentType) {
+ case DefinedAtom::typeResolver:
+ case DefinedAtom::typeCode:
+ return llvm::StringSwitch<Layout::SectionOrder>(name)
+ .StartsWith(".eh_frame_hdr", ORDER_EH_FRAMEHDR)
+ .StartsWith(".eh_frame", ORDER_EH_FRAME)
+ .StartsWith(".init", ORDER_INIT)
+ .StartsWith(".fini", ORDER_FINI)
+ .StartsWith(".hash", ORDER_HASH)
+ .Default(ORDER_TEXT);
+
+ case DefinedAtom::typeConstant:
+ return ORDER_RODATA;
+
+ case DefinedAtom::typeData:
+ case DefinedAtom::typeDataFast:
+ return llvm::StringSwitch<Layout::SectionOrder>(name)
+ .StartsWith(".init_array", ORDER_INIT_ARRAY)
+ .StartsWith(".fini_array", ORDER_FINI_ARRAY)
+ .StartsWith(".dynamic", ORDER_DYNAMIC)
+ .StartsWith(".ctors", ORDER_CTORS)
+ .StartsWith(".dtors", ORDER_DTORS)
+ .Default(ORDER_DATA);
+
+ case DefinedAtom::typeZeroFill:
+ case DefinedAtom::typeZeroFillFast:
+ return ORDER_BSS;
+
+ case DefinedAtom::typeGOT:
+ return llvm::StringSwitch<Layout::SectionOrder>(name)
+ .StartsWith(".got.plt", ORDER_GOT_PLT)
+ .Default(ORDER_GOT);
+
+ case DefinedAtom::typeStub:
+ return ORDER_PLT;
+
+ case DefinedAtom::typeRONote:
+ return ORDER_RO_NOTE;
+
+ case DefinedAtom::typeRWNote:
+ return ORDER_RW_NOTE;
+
+ case DefinedAtom::typeNoAlloc:
+ return ORDER_NOALLOC;
+
+ case DefinedAtom::typeThreadData:
+ return ORDER_TDATA;
+ case DefinedAtom::typeThreadZeroFill:
+ return ORDER_TBSS;
+ default:
+ // If we get passed in a section push it to OTHER
+ if (contentPermissions == DefinedAtom::perm___)
+ return ORDER_OTHER;
+
+ return ORDER_NOT_DEFINED;
+ }
+}
+
+/// \brief This maps the input sections to the output section names
+template <class ELFT>
+StringRef
+DefaultLayout<ELFT>::getInputSectionName(const DefinedAtom *da) const {
+ if (da->sectionChoice() == DefinedAtom::sectionBasedOnContent) {
+ switch (da->contentType()) {
+ case DefinedAtom::typeCode:
+ return ".text";
+ case DefinedAtom::typeData:
+ return ".data";
+ case DefinedAtom::typeConstant:
+ return ".rodata";
+ case DefinedAtom::typeZeroFill:
+ return ".bss";
+ case DefinedAtom::typeThreadData:
+ return ".tdata";
+ case DefinedAtom::typeThreadZeroFill:
+ return ".tbss";
+ default:
+ break;
+ }
+ }
+ return da->customSectionName();
+}
+
+/// \brief This maps the input sections to the output section names.
+template <class ELFT>
+StringRef
+DefaultLayout<ELFT>::getOutputSectionName(StringRef archivePath,
+ StringRef memberPath,
+ StringRef inputSectionName) const {
+ StringRef outputSectionName;
+ if (_linkerScriptSema.hasLayoutCommands()) {
+ script::Sema::SectionKey key = {archivePath, memberPath, inputSectionName};
+ outputSectionName = _linkerScriptSema.getOutputSection(key);
+ if (!outputSectionName.empty())
+ return outputSectionName;
+ }
+ return llvm::StringSwitch<StringRef>(inputSectionName)
+ .StartsWith(".text", ".text")
+ .StartsWith(".ctors", ".ctors")
+ .StartsWith(".dtors", ".dtors")
+ .StartsWith(".rodata", ".rodata")
+ .StartsWith(".gcc_except_table", ".gcc_except_table")
+ .StartsWith(".data.rel.ro", ".data.rel.ro")
+ .StartsWith(".data.rel.local", ".data.rel.local")
+ .StartsWith(".data", ".data")
+ .StartsWith(".tdata", ".tdata")
+ .StartsWith(".tbss", ".tbss")
+ .StartsWith(".init_array", ".init_array")
+ .StartsWith(".fini_array", ".fini_array")
+ .Default(inputSectionName);
+}
+
+/// \brief Gets the segment for a output section
+template <class ELFT>
+Layout::SegmentType DefaultLayout<ELFT>::getSegmentType(
+ Section<ELFT> *section) const {
+
+ switch (section->order()) {
+ case ORDER_INTERP:
+ return llvm::ELF::PT_INTERP;
+
+ case ORDER_TEXT:
+ case ORDER_HASH:
+ case ORDER_DYNAMIC_SYMBOLS:
+ case ORDER_DYNAMIC_STRINGS:
+ case ORDER_DYNAMIC_RELOCS:
+ case ORDER_DYNAMIC_PLT_RELOCS:
+ case ORDER_REL:
+ case ORDER_INIT:
+ case ORDER_PLT:
+ case ORDER_FINI:
+ case ORDER_RODATA:
+ case ORDER_EH_FRAME:
+ case ORDER_CTORS:
+ case ORDER_DTORS:
+ return llvm::ELF::PT_LOAD;
+
+ case ORDER_RO_NOTE:
+ case ORDER_RW_NOTE:
+ return llvm::ELF::PT_NOTE;
+
+ case ORDER_DYNAMIC:
+ return llvm::ELF::PT_DYNAMIC;
+
+ case ORDER_EH_FRAMEHDR:
+ return llvm::ELF::PT_GNU_EH_FRAME;
+
+ case ORDER_GOT:
+ case ORDER_GOT_PLT:
+ case ORDER_DATA:
+ case ORDER_BSS:
+ case ORDER_INIT_ARRAY:
+ case ORDER_FINI_ARRAY:
+ return llvm::ELF::PT_LOAD;
+
+ case ORDER_TDATA:
+ case ORDER_TBSS:
+ return llvm::ELF::PT_TLS;
+
+ default:
+ return llvm::ELF::PT_NULL;
+ }
+}
+
+template <class ELFT>
+bool DefaultLayout<ELFT>::hasOutputSegment(Section<ELFT> *section) {
+ switch (section->order()) {
+ case ORDER_INTERP:
+ case ORDER_HASH:
+ case ORDER_DYNAMIC_SYMBOLS:
+ case ORDER_DYNAMIC_STRINGS:
+ case ORDER_DYNAMIC_RELOCS:
+ case ORDER_DYNAMIC_PLT_RELOCS:
+ case ORDER_REL:
+ case ORDER_INIT:
+ case ORDER_PLT:
+ case ORDER_TEXT:
+ case ORDER_FINI:
+ case ORDER_RODATA:
+ case ORDER_EH_FRAME:
+ case ORDER_EH_FRAMEHDR:
+ case ORDER_TDATA:
+ case ORDER_TBSS:
+ case ORDER_RO_NOTE:
+ case ORDER_RW_NOTE:
+ case ORDER_DYNAMIC:
+ case ORDER_CTORS:
+ case ORDER_DTORS:
+ case ORDER_GOT:
+ case ORDER_GOT_PLT:
+ case ORDER_DATA:
+ case ORDER_INIT_ARRAY:
+ case ORDER_FINI_ARRAY:
+ case ORDER_BSS:
+ case ORDER_NOALLOC:
+ return true;
+ default:
+ return section->hasOutputSegment();
+ }
+}
+
+template <class ELFT>
+AtomSection<ELFT> *DefaultLayout<ELFT>::createSection(
+ StringRef sectionName, int32_t contentType,
+ DefinedAtom::ContentPermissions permissions, SectionOrder sectionOrder) {
+ return new (_allocator) AtomSection<ELFT>(_context, sectionName, contentType,
+ permissions, sectionOrder);
+}
+
+template <class ELFT>
+AtomSection<ELFT> *
+DefaultLayout<ELFT>::getSection(StringRef sectionName, int32_t contentType,
+ DefinedAtom::ContentPermissions permissions,
+ const DefinedAtom *da) {
+ const SectionKey sectionKey(sectionName, permissions, da->file().path());
+ SectionOrder sectionOrder = getSectionOrder(sectionName, contentType, permissions);
+ auto sec = _sectionMap.find(sectionKey);
+ if (sec != _sectionMap.end())
+ return sec->second;
+ AtomSection<ELFT> *newSec =
+ createSection(sectionName, contentType, permissions, sectionOrder);
+
+ newSec->setOutputSectionName(getOutputSectionName(
+ da->file().archivePath(), da->file().memberPath(), sectionName));
+ newSec->setOrder(sectionOrder);
+ newSec->setArchiveNameOrPath(da->file().archivePath());
+ newSec->setMemberNameOrPath(da->file().memberPath());
+ _sections.push_back(newSec);
+ _sectionMap.insert(std::make_pair(sectionKey, newSec));
+ return newSec;
+}
+
+template <class ELFT>
+ErrorOr<const lld::AtomLayout *>
+DefaultLayout<ELFT>::addAtom(const Atom *atom) {
+ if (const DefinedAtom *definedAtom = dyn_cast<DefinedAtom>(atom)) {
+ // HACK: Ignore undefined atoms. We need to adjust the interface so that
+ // undefined atoms can still be included in the output symbol table for
+ // -noinhibit-exec.
+ if (definedAtom->contentType() == DefinedAtom::typeUnknown)
+ return make_error_code(llvm::errc::invalid_argument);
+ const DefinedAtom::ContentPermissions permissions =
+ definedAtom->permissions();
+ const DefinedAtom::ContentType contentType = definedAtom->contentType();
+
+ StringRef sectionName = getInputSectionName(definedAtom);
+ AtomSection<ELFT> *section =
+ getSection(sectionName, contentType, permissions, definedAtom);
+
+ // Add runtime relocations to the .rela section.
+ for (const auto &reloc : *definedAtom) {
+ bool isLocalReloc = true;
+ if (_context.isDynamicRelocation(*reloc)) {
+ getDynamicRelocationTable()->addRelocation(*definedAtom, *reloc);
+ isLocalReloc = false;
+ } else if (_context.isPLTRelocation(*reloc)) {
+ getPLTRelocationTable()->addRelocation(*definedAtom, *reloc);
+ isLocalReloc = false;
+ }
+
+ if (!reloc->target())
+ continue;
+
+ //Ignore undefined atoms that are not target of dynamic relocations
+ if (isa<UndefinedAtom>(reloc->target()) && isLocalReloc)
+ continue;
+
+ if (_context.isCopyRelocation(*reloc)) {
+ _copiedDynSymNames.insert(definedAtom->name());
+ continue;
+ }
+
+ _referencedDynAtoms.insert(reloc->target());
+ }
+
+ return section->appendAtom(atom);
+ } else if (const AbsoluteAtom *absoluteAtom = dyn_cast<AbsoluteAtom>(atom)) {
+ // Absolute atoms are not part of any section, they are global for the whole
+ // link
+ _absoluteAtoms.push_back(new (_allocator)
+ lld::AtomLayout(absoluteAtom, 0, absoluteAtom->value()));
+ return _absoluteAtoms.back();
+ } else {
+ llvm_unreachable("Only absolute / defined atoms can be added here");
+ }
+}
+
+/// Output sections with the same name into a OutputSection
+template <class ELFT> void DefaultLayout<ELFT>::createOutputSections() {
+ OutputSection<ELFT> *outputSection;
+
+ for (auto &si : _sections) {
+ Section<ELFT> *section = dyn_cast<Section<ELFT>>(si);
+ if (!section)
+ continue;
+ const std::pair<StringRef, OutputSection<ELFT> *> currentOutputSection(
+ section->outputSectionName(), nullptr);
+ std::pair<typename OutputSectionMapT::iterator, bool> outputSectionInsert(
+ _outputSectionMap.insert(currentOutputSection));
+ if (!outputSectionInsert.second) {
+ outputSection = outputSectionInsert.first->second;
+ } else {
+ outputSection = new (_allocator.Allocate<OutputSection<ELFT>>())
+ OutputSection<ELFT>(section->outputSectionName());
+ _outputSections.push_back(outputSection);
+ outputSectionInsert.first->second = outputSection;
+ }
+ outputSection->appendSection(si);
+ }
+}
+
+template <class ELFT>
+uint32_t
+DefaultLayout<ELFT>::getPriorityFromSectionName(StringRef sectionName) const {
+ StringRef priority = sectionName.drop_front().rsplit('.').second;
+ uint32_t prio;
+ if (priority.getAsInteger(10, prio))
+ return std::numeric_limits<uint32_t>::max();
+ return prio;
+}
+
+template <class ELFT>
+void DefaultLayout<ELFT>::sortOutputSectionByPriority(
+ StringRef outputSectionName, StringRef prefix) {
+ OutputSection<ELFT> *outputSection = findOutputSection(outputSectionName);
+ if (!outputSection)
+ return;
+
+ auto sections = outputSection->sections();
+
+ std::sort(sections.begin(), sections.end(),
+ [&](Chunk<ELFT> *lhs, Chunk<ELFT> *rhs) {
+ Section<ELFT> *lhsSection = dyn_cast<Section<ELFT>>(lhs);
+ Section<ELFT> *rhsSection = dyn_cast<Section<ELFT>>(rhs);
+ if (!lhsSection || !rhsSection)
+ return false;
+ StringRef lhsSectionName = lhsSection->inputSectionName();
+ StringRef rhsSectionName = rhsSection->inputSectionName();
+
+ if (!prefix.empty()) {
+ if (!lhsSectionName.startswith(prefix) ||
+ !rhsSectionName.startswith(prefix))
+ return false;
+ }
+ return getPriorityFromSectionName(lhsSectionName) <
+ getPriorityFromSectionName(rhsSectionName);
+ });
+}
+
+template <class ELFT> void DefaultLayout<ELFT>::assignSectionsToSegments() {
+ ScopedTask task(getDefaultDomain(), "assignSectionsToSegments");
+ ELFLinkingContext::OutputMagic outputMagic = _context.getOutputMagic();
+ // sort the sections by their order as defined by the layout
+ sortInputSections();
+
+ // Create output sections.
+ createOutputSections();
+
+ // Finalize output section layout.
+ finalizeOutputSectionLayout();
+
+ // Set the ordinal after sorting the sections
+ int ordinal = 1;
+ for (auto osi : _outputSections) {
+ osi->setOrdinal(ordinal);
+ for (auto ai : osi->sections()) {
+ ai->setOrdinal(ordinal);
+ }
+ ++ordinal;
+ }
+ for (auto osi : _outputSections) {
+ for (auto ai : osi->sections()) {
+ if (auto section = dyn_cast<Section<ELFT> >(ai)) {
+ if (!hasOutputSegment(section))
+ continue;
+
+ osi->setLoadableSection(section->isLoadableSection());
+
+ // Get the segment type for the section
+ int64_t segmentType = getSegmentType(section);
+
+ osi->setHasSegment();
+ section->setSegmentType(segmentType);
+ StringRef segmentName = section->segmentKindToStr();
+
+ int64_t lookupSectionFlag = osi->flags();
+ if ((!(lookupSectionFlag & llvm::ELF::SHF_WRITE)) &&
+ (_context.mergeRODataToTextSegment()))
+ lookupSectionFlag &= ~llvm::ELF::SHF_EXECINSTR;
+
+ // Merge string sections into Data segment itself
+ lookupSectionFlag &= ~(llvm::ELF::SHF_STRINGS | llvm::ELF::SHF_MERGE);
+
+ // Merge the TLS section into the DATA segment itself
+ lookupSectionFlag &= ~(llvm::ELF::SHF_TLS);
+
+ Segment<ELFT> *segment;
+ // We need a separate segment for sections that don't have
+ // the segment type to be PT_LOAD
+ if (segmentType != llvm::ELF::PT_LOAD) {
+ const AdditionalSegmentKey key(segmentType, lookupSectionFlag);
+ const std::pair<AdditionalSegmentKey, Segment<ELFT> *>
+ additionalSegment(key, nullptr);
+ std::pair<typename AdditionalSegmentMapT::iterator, bool>
+ additionalSegmentInsert(
+ _additionalSegmentMap.insert(additionalSegment));
+ if (!additionalSegmentInsert.second) {
+ segment = additionalSegmentInsert.first->second;
+ } else {
+ segment = new (_allocator)
+ Segment<ELFT>(_context, segmentName, segmentType);
+ additionalSegmentInsert.first->second = segment;
+ _segments.push_back(segment);
+ }
+ segment->append(section);
+ }
+ if (segmentType == llvm::ELF::PT_NULL)
+ continue;
+
+ // If the output magic is set to OutputMagic::NMAGIC or
+ // OutputMagic::OMAGIC, Place the data alongside text in one single
+ // segment
+ if (outputMagic == ELFLinkingContext::OutputMagic::NMAGIC ||
+ outputMagic == ELFLinkingContext::OutputMagic::OMAGIC)
+ lookupSectionFlag = llvm::ELF::SHF_EXECINSTR | llvm::ELF::SHF_ALLOC |
+ llvm::ELF::SHF_WRITE;
+
+ // Use the flags of the merged Section for the segment
+ const SegmentKey key("PT_LOAD", lookupSectionFlag);
+ const std::pair<SegmentKey, Segment<ELFT> *> currentSegment(key,
+ nullptr);
+ std::pair<typename SegmentMapT::iterator, bool> segmentInsert(
+ _segmentMap.insert(currentSegment));
+ if (!segmentInsert.second) {
+ segment = segmentInsert.first->second;
+ } else {
+ segment = new (_allocator)
+ Segment<ELFT>(_context, "PT_LOAD", llvm::ELF::PT_LOAD);
+ segmentInsert.first->second = segment;
+ _segments.push_back(segment);
+ }
+ // Insert chunks with linker script expressions that occur at this
+ // point, just before appending a new input section
+ addExtraChunksToSegment(segment, section->archivePath(),
+ section->memberPath(),
+ section->inputSectionName());
+ segment->append(section);
+ }
+ }
+ }
+ if (_context.isDynamic() && !_context.isDynamicLibrary()) {
+ Segment<ELFT> *segment =
+ new (_allocator) ProgramHeaderSegment<ELFT>(_context);
+ _segments.push_back(segment);
+ segment->append(_elfHeader);
+ segment->append(_programHeader);
+ }
+}
+
+template<class ELFT>
+void
+DefaultLayout<ELFT>::assignVirtualAddress() {
+ if (_segments.empty())
+ return;
+
+ std::sort(_segments.begin(), _segments.end(), Segment<ELFT>::compareSegments);
+
+ uint64_t baseAddress = _context.getBaseAddress();
+
+ // HACK: This is a super dirty hack. The elf header and program header are
+ // not part of a section, but we need them to be loaded at the base address
+ // so that AT_PHDR is set correctly by the loader and so they are accessible
+ // at runtime. To do this we simply prepend them to the first loadable Segment
+ // and let the layout logic take care of it.
+ Segment<ELFT> *firstLoadSegment = nullptr;
+ for (auto si : _segments) {
+ if (si->segmentType() == llvm::ELF::PT_LOAD) {
+ firstLoadSegment = si;
+ si->firstSection()->setAlign(si->alignment());
+ break;
+ }
+ }
+ assert(firstLoadSegment != nullptr && "No loadable segment!");
+ firstLoadSegment->prepend(_programHeader);
+ firstLoadSegment->prepend(_elfHeader);
+ bool newSegmentHeaderAdded = true;
+ bool virtualAddressAssigned = false;
+ bool fileOffsetAssigned = false;
+ while (true) {
+ for (auto si : _segments) {
+ si->finalize();
+ // Don't add PT_NULL segments into the program header
+ if (si->segmentType() != llvm::ELF::PT_NULL)
+ newSegmentHeaderAdded = _programHeader->addSegment(si);
+ }
+ if (!newSegmentHeaderAdded && virtualAddressAssigned)
+ break;
+ uint64_t address = baseAddress;
+ // start assigning virtual addresses
+ for (auto &si : _segments) {
+ if ((si->segmentType() != llvm::ELF::PT_LOAD) &&
+ (si->segmentType() != llvm::ELF::PT_NULL))
+ continue;
+
+ if (si->segmentType() == llvm::ELF::PT_NULL) {
+ si->assignVirtualAddress(0 /*non loadable*/);
+ } else {
+ if (virtualAddressAssigned && (address != baseAddress) &&
+ (address == si->virtualAddr()))
+ break;
+ si->assignVirtualAddress(address);
+ }
+ address = si->virtualAddr() + si->memSize();
+ }
+ uint64_t baseFileOffset = 0;
+ uint64_t fileoffset = baseFileOffset;
+ for (auto &si : _segments) {
+ if ((si->segmentType() != llvm::ELF::PT_LOAD) &&
+ (si->segmentType() != llvm::ELF::PT_NULL))
+ continue;
+ if (fileOffsetAssigned && (fileoffset != baseFileOffset) &&
+ (fileoffset == si->fileOffset()))
+ break;
+ si->assignFileOffsets(fileoffset);
+ fileoffset = si->fileOffset() + si->fileSize();
+ }
+ virtualAddressAssigned = true;
+ fileOffsetAssigned = true;
+ _programHeader->resetProgramHeaders();
+ }
+ Section<ELFT> *section;
+ // Fix the offsets of all the atoms within a section
+ for (auto &si : _sections) {
+ section = dyn_cast<Section<ELFT>>(si);
+ if (section && DefaultLayout<ELFT>::hasOutputSegment(section))
+ section->assignFileOffsets(section->fileOffset());
+ }
+ // Set the size of the merged Sections
+ for (auto osi : _outputSections) {
+ uint64_t sectionfileoffset = 0;
+ uint64_t startFileOffset = 0;
+ uint64_t sectionsize = 0;
+ bool isFirstSection = true;
+ for (auto si : osi->sections()) {
+ if (isFirstSection) {
+ startFileOffset = si->fileOffset();
+ isFirstSection = false;
+ }
+ sectionfileoffset = si->fileOffset();
+ sectionsize = si->fileSize();
+ }
+ sectionsize = (sectionfileoffset - startFileOffset) + sectionsize;
+ osi->setFileOffset(startFileOffset);
+ osi->setSize(sectionsize);
+ }
+ // Set the virtual addr of the merged Sections
+ for (auto osi : _outputSections) {
+ uint64_t sectionstartaddr = 0;
+ uint64_t startaddr = 0;
+ uint64_t sectionsize = 0;
+ bool isFirstSection = true;
+ for (auto si : osi->sections()) {
+ if (isFirstSection) {
+ startaddr = si->virtualAddr();
+ isFirstSection = false;
+ }
+ sectionstartaddr = si->virtualAddr();
+ sectionsize = si->memSize();
+ }
+ sectionsize = (sectionstartaddr - startaddr) + sectionsize;
+ osi->setMemSize(sectionsize);
+ osi->setAddr(startaddr);
+ }
+}
+
+template <class ELFT>
+void DefaultLayout<ELFT>::assignFileOffsetsForMiscSections() {
+ uint64_t fileoffset = 0;
+ uint64_t size = 0;
+ for (auto si : _segments) {
+ // Don't calculate offsets from non loadable segments
+ if ((si->segmentType() != llvm::ELF::PT_LOAD) &&
+ (si->segmentType() != llvm::ELF::PT_NULL))
+ continue;
+ fileoffset = si->fileOffset();
+ size = si->fileSize();
+ }
+ fileoffset = fileoffset + size;
+ Section<ELFT> *section;
+ for (auto si : _sections) {
+ section = dyn_cast<Section<ELFT>>(si);
+ if (section && DefaultLayout<ELFT>::hasOutputSegment(section))
+ continue;
+ fileoffset = llvm::RoundUpToAlignment(fileoffset, si->alignment());
+ si->setFileOffset(fileoffset);
+ si->setVirtualAddr(0);
+ fileoffset += si->fileSize();
+ }
+}
+
+template <class ELFT> void DefaultLayout<ELFT>::sortInputSections() {
+ // First, sort according to default layout's order
+ std::stable_sort(
+ _sections.begin(), _sections.end(),
+ [](Chunk<ELFT> *A, Chunk<ELFT> *B) { return A->order() < B->order(); });
+
+ if (!_linkerScriptSema.hasLayoutCommands())
+ return;
+
+ // Sort the sections by their order as defined by the linker script
+ std::stable_sort(this->_sections.begin(), this->_sections.end(),
+ [this](Chunk<ELFT> *A, Chunk<ELFT> *B) {
+ auto *a = dyn_cast<Section<ELFT>>(A);
+ auto *b = dyn_cast<Section<ELFT>>(B);
+
+ if (a == nullptr)
+ return false;
+ if (b == nullptr)
+ return true;
+
+ return _linkerScriptSema.less(
+ {a->archivePath(), a->memberPath(),
+ a->inputSectionName()},
+ {b->archivePath(), b->memberPath(),
+ b->inputSectionName()});
+ });
+ // Now try to arrange sections with no mapping rules to sections with
+ // similar content
+ auto p = this->_sections.begin();
+ // Find first section that has no assigned rule id
+ while (p != this->_sections.end()) {
+ auto *sect = dyn_cast<AtomSection<ELFT>>(*p);
+ if (!sect)
+ break;
+
+ if (!_linkerScriptSema.hasMapping({sect->archivePath(),
+ sect->memberPath(),
+ sect->inputSectionName()}))
+ break;
+
+ ++p;
+ }
+ // For all sections that have no assigned rule id, try to move them near a
+ // section with similar contents
+ if (p != this->_sections.begin()) {
+ for (; p != this->_sections.end(); ++p) {
+ auto q = p;
+ --q;
+ while (q != this->_sections.begin() &&
+ (*q)->getContentType() != (*p)->getContentType())
+ --q;
+ if ((*q)->getContentType() != (*p)->getContentType())
+ continue;
+ ++q;
+ for (auto i = p; i != q;) {
+ auto next = i--;
+ std::iter_swap(i, next);
+ }
+ }
+ }
+}
+
+template <class ELFT>
+void DefaultLayout<ELFT>::addExtraChunksToSegment(Segment<ELFT> *segment,
+ StringRef archivePath,
+ StringRef memberPath,
+ StringRef sectionName) {
+ if (!_linkerScriptSema.hasLayoutCommands())
+ return;
+
+ std::vector<const script::SymbolAssignment *> exprs =
+ _linkerScriptSema.getExprs({archivePath, memberPath, sectionName});
+ for (auto expr : exprs) {
+ auto expChunk =
+ new (this->_allocator) ExpressionChunk<ELFT>(this->_context, expr);
+ segment->append(expChunk);
+ }
+}
+
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/DefaultTargetHandler.h b/lib/ReaderWriter/ELF/DefaultTargetHandler.h
new file mode 100644
index 0000000000000..16668f2df6182
--- /dev/null
+++ b/lib/ReaderWriter/ELF/DefaultTargetHandler.h
@@ -0,0 +1,38 @@
+//===- lib/ReaderWriter/ELF/DefaultTargetHandler.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_DEFAULT_TARGET_HANDLER_H
+#define LLD_READER_WRITER_ELF_DEFAULT_TARGET_HANDLER_H
+
+#include "DefaultLayout.h"
+#include "DynamicLibraryWriter.h"
+#include "ELFReader.h"
+#include "ExecutableWriter.h"
+#include "TargetHandler.h"
+#include "lld/ReaderWriter/ELFLinkingContext.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/ELF.h"
+
+namespace lld {
+namespace elf {
+template <class ELFT>
+class DefaultTargetHandler : public TargetHandler<ELFT> {
+public:
+ const TargetRelocationHandler &getRelocationHandler() const = 0;
+
+ virtual std::unique_ptr<Reader> getObjReader() = 0;
+
+ virtual std::unique_ptr<Reader> getDSOReader() = 0;
+
+ virtual std::unique_ptr<Writer> getWriter() = 0;
+};
+
+} // end namespace elf
+} // end namespace lld
+#endif
diff --git a/lib/ReaderWriter/ELF/DynamicFile.h b/lib/ReaderWriter/ELF/DynamicFile.h
new file mode 100644
index 0000000000000..c4e3e7165efd2
--- /dev/null
+++ b/lib/ReaderWriter/ELF/DynamicFile.h
@@ -0,0 +1,123 @@
+//===- lib/ReaderWriter/ELF/DynamicFile.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_DYNAMIC_FILE_H
+#define LLD_READER_WRITER_ELF_DYNAMIC_FILE_H
+
+#include "Atoms.h"
+#include "lld/Core/SharedLibraryFile.h"
+#include "lld/ReaderWriter/ELFLinkingContext.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Path.h"
+#include <unordered_map>
+
+namespace lld {
+namespace elf {
+template <class ELFT> class DynamicFile : public SharedLibraryFile {
+public:
+ static ErrorOr<std::unique_ptr<DynamicFile>>
+ create(std::unique_ptr<llvm::MemoryBuffer> mb, ELFLinkingContext &ctx);
+
+ const SharedLibraryAtom *exports(StringRef name,
+ bool dataSymbolOnly) const override {
+ assert(!dataSymbolOnly && "Invalid option for ELF exports!");
+ // See if we have the symbol.
+ auto sym = _nameToSym.find(name);
+ if (sym == _nameToSym.end())
+ return nullptr;
+ // Have we already created a SharedLibraryAtom for it?
+ if (sym->second._atom)
+ return sym->second._atom;
+ // Create a SharedLibraryAtom for this symbol.
+ return sym->second._atom = new (_alloc) ELFDynamicAtom<ELFT>(
+ *this, name, _soname, sym->second._symbol);
+ }
+
+ StringRef getDSOName() const override { return _soname; }
+
+protected:
+ std::error_code doParse() override {
+ std::error_code ec;
+ _objFile.reset(
+ new llvm::object::ELFFile<ELFT>(_mb->getBuffer(), ec));
+ if (ec)
+ return ec;
+
+ llvm::object::ELFFile<ELFT> &obj = *_objFile;
+
+ _soname = obj.getLoadName();
+ if (_soname.empty())
+ _soname = llvm::sys::path::filename(path());
+
+ // Create a map from names to dynamic symbol table entries.
+ // TODO: This should use the object file's build in hash table instead if
+ // it exists.
+ for (auto i = obj.begin_dynamic_symbols(), e = obj.end_dynamic_symbols();
+ i != e; ++i) {
+ auto name = obj.getSymbolName(i);
+ if ((ec = name.getError()))
+ return ec;
+
+ // Dont add local symbols to dynamic entries. The first symbol in the
+ // dynamic symbol table is a local symbol.
+ if (i->getBinding() == llvm::ELF::STB_LOCAL)
+ continue;
+
+ // TODO: Add absolute symbols
+ if (i->st_shndx == llvm::ELF::SHN_ABS)
+ continue;
+
+ if (i->st_shndx == llvm::ELF::SHN_UNDEF) {
+ if (!_useShlibUndefines)
+ continue;
+ // Create an undefined atom.
+ if (!name->empty()) {
+ auto *newAtom = new (_alloc) ELFUndefinedAtom<ELFT>(*this, *name, &*i);
+ _undefinedAtoms._atoms.push_back(newAtom);
+ }
+ continue;
+ }
+ _nameToSym[*name]._symbol = &*i;
+ }
+ return std::error_code();
+ }
+
+private:
+ DynamicFile(std::unique_ptr<MemoryBuffer> mb, ELFLinkingContext &ctx)
+ : SharedLibraryFile(mb->getBufferIdentifier()), _mb(std::move(mb)),
+ _ctx(ctx), _useShlibUndefines(ctx.useShlibUndefines()) {}
+
+ mutable llvm::BumpPtrAllocator _alloc;
+ std::unique_ptr<llvm::object::ELFFile<ELFT>> _objFile;
+ /// \brief DT_SONAME
+ StringRef _soname;
+
+ struct SymAtomPair {
+ SymAtomPair() : _symbol(nullptr), _atom(nullptr) {}
+ const typename llvm::object::ELFFile<ELFT>::Elf_Sym *_symbol;
+ const SharedLibraryAtom *_atom;
+ };
+
+ std::unique_ptr<MemoryBuffer> _mb;
+ ELFLinkingContext &_ctx;
+ bool _useShlibUndefines;
+ mutable std::unordered_map<StringRef, SymAtomPair> _nameToSym;
+};
+
+template <class ELFT>
+ErrorOr<std::unique_ptr<DynamicFile<ELFT>>>
+DynamicFile<ELFT>::create(std::unique_ptr<llvm::MemoryBuffer> mb,
+ ELFLinkingContext &ctx) {
+ return std::unique_ptr<DynamicFile>(new DynamicFile(std::move(mb), ctx));
+}
+
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/DynamicLibraryWriter.h b/lib/ReaderWriter/ELF/DynamicLibraryWriter.h
new file mode 100644
index 0000000000000..f97514b525c0b
--- /dev/null
+++ b/lib/ReaderWriter/ELF/DynamicLibraryWriter.h
@@ -0,0 +1,96 @@
+//===- lib/ReaderWriter/ELF/DynamicLibraryWriter.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_DYNAMIC_LIBRARY_WRITER_H
+#define LLD_READER_WRITER_ELF_DYNAMIC_LIBRARY_WRITER_H
+
+#include "OutputELFWriter.h"
+
+namespace lld {
+namespace elf {
+using namespace llvm;
+using namespace llvm::object;
+
+template<class ELFT>
+class DynamicLibraryWriter;
+
+//===----------------------------------------------------------------------===//
+// DynamicLibraryWriter Class
+//===----------------------------------------------------------------------===//
+template<class ELFT>
+class DynamicLibraryWriter : public OutputELFWriter<ELFT> {
+public:
+ DynamicLibraryWriter(ELFLinkingContext &context, TargetLayout<ELFT> &layout)
+ : OutputELFWriter<ELFT>(context, layout),
+ _runtimeFile(new RuntimeFile<ELFT>(context, "C runtime")) {}
+
+protected:
+ virtual void buildDynamicSymbolTable(const File &file);
+ virtual void addDefaultAtoms();
+ virtual bool createImplicitFiles(std::vector<std::unique_ptr<File> > &);
+ virtual void finalizeDefaultAtomValues();
+
+protected:
+ std::unique_ptr<RuntimeFile<ELFT> > _runtimeFile;
+};
+
+//===----------------------------------------------------------------------===//
+// DynamicLibraryWriter
+//===----------------------------------------------------------------------===//
+template <class ELFT>
+void DynamicLibraryWriter<ELFT>::buildDynamicSymbolTable(const File &file) {
+ // Add all the defined symbols to the dynamic symbol table
+ // we need hooks into the Atom to find out which atoms need
+ // to be exported
+ for (auto sec : this->_layout.sections())
+ if (auto section = dyn_cast<AtomSection<ELFT>>(sec))
+ for (const auto &atom : section->atoms()) {
+ const DefinedAtom *da = dyn_cast<const DefinedAtom>(atom->_atom);
+ if (da && (da->scope() == DefinedAtom::scopeGlobal))
+ this->_dynamicSymbolTable->addSymbol(atom->_atom, section->ordinal(),
+ atom->_virtualAddr, atom);
+ }
+
+ for (const UndefinedAtom *a : file.undefined())
+ this->_dynamicSymbolTable->addSymbol(a, ELF::SHN_UNDEF);
+
+ OutputELFWriter<ELFT>::buildDynamicSymbolTable(file);
+}
+
+template <class ELFT> void DynamicLibraryWriter<ELFT>::addDefaultAtoms() {
+ _runtimeFile->addAbsoluteAtom("_end");
+}
+
+/// \brief Hook in lld to add CRuntime file
+template <class ELFT>
+bool DynamicLibraryWriter<ELFT>::createImplicitFiles(
+ std::vector<std::unique_ptr<File> > &result) {
+ // Add the default atoms as defined by executables
+ DynamicLibraryWriter<ELFT>::addDefaultAtoms();
+ OutputELFWriter<ELFT>::createImplicitFiles(result);
+ result.push_back(std::move(_runtimeFile));
+ return true;
+}
+
+template <class ELFT>
+void DynamicLibraryWriter<ELFT>::finalizeDefaultAtomValues() {
+ auto underScoreEndAtomIter = this->_layout.findAbsoluteAtom("_end");
+
+ if (auto bssSection = this->_layout.findOutputSection(".bss")) {
+ (*underScoreEndAtomIter)->_virtualAddr =
+ bssSection->virtualAddr() + bssSection->memSize();
+ } else if (auto dataSection = this->_layout.findOutputSection(".data")) {
+ (*underScoreEndAtomIter)->_virtualAddr =
+ dataSection->virtualAddr() + dataSection->memSize();
+ }
+}
+
+} // namespace elf
+} // namespace lld
+
+#endif // LLD_READER_WRITER_ELF_DYNAMIC_LIBRARY_WRITER_H
diff --git a/lib/ReaderWriter/ELF/ELFFile.h b/lib/ReaderWriter/ELF/ELFFile.h
new file mode 100644
index 0000000000000..11f4ee4fc633f
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ELFFile.h
@@ -0,0 +1,1179 @@
+//===- lib/ReaderWriter/ELF/ELFFile.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_FILE_H
+#define LLD_READER_WRITER_ELF_FILE_H
+
+#include "Atoms.h"
+#include <llvm/ADT/MapVector.h>
+#include <map>
+#include <unordered_map>
+
+namespace lld {
+
+namespace elf {
+/// \brief Read a binary, find out based on the symbol table contents what kind
+/// of symbol it is and create corresponding atoms for it
+template <class ELFT> class ELFFile : public File {
+
+ typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+ typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr;
+ typedef llvm::object::Elf_Rel_Impl<ELFT, false> Elf_Rel;
+ typedef llvm::object::Elf_Rel_Impl<ELFT, true> Elf_Rela;
+ typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym_Iter Elf_Sym_Iter;
+ typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela_Iter Elf_Rela_Iter;
+ typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel_Iter Elf_Rel_Iter;
+ typedef typename llvm::object::ELFFile<ELFT>::Elf_Word Elf_Word;
+
+ // A Map is used to hold the atoms that have been divided up
+ // after reading the section that contains Merge String attributes
+ struct MergeSectionKey {
+ MergeSectionKey(const Elf_Shdr *shdr, int64_t offset)
+ : _shdr(shdr), _offset(offset) {}
+ // Data members
+ const Elf_Shdr *_shdr;
+ int64_t _offset;
+ };
+ struct MergeSectionEq {
+ int64_t operator()(const MergeSectionKey &k) const {
+ return llvm::hash_combine((int64_t)(k._shdr->sh_name),
+ (int64_t)k._offset);
+ }
+ bool operator()(const MergeSectionKey &lhs,
+ const MergeSectionKey &rhs) const {
+ return ((lhs._shdr->sh_name == rhs._shdr->sh_name) &&
+ (lhs._offset == rhs._offset));
+ }
+ };
+
+ struct MergeString {
+ MergeString(int64_t offset, StringRef str, const Elf_Shdr *shdr,
+ StringRef sectionName)
+ : _offset(offset), _string(str), _shdr(shdr),
+ _sectionName(sectionName) {}
+ // the offset of this atom
+ int64_t _offset;
+ // The content
+ StringRef _string;
+ // Section header
+ const Elf_Shdr *_shdr;
+ // Section name
+ StringRef _sectionName;
+ };
+
+ // This is used to find the MergeAtom given a relocation
+ // offset
+ typedef std::vector<ELFMergeAtom<ELFT> *> MergeAtomsT;
+
+ /// \brief find a mergeAtom given a start offset
+ struct FindByOffset {
+ const Elf_Shdr *_shdr;
+ int64_t _offset;
+ FindByOffset(const Elf_Shdr *shdr, int64_t offset)
+ : _shdr(shdr), _offset(offset) {}
+ bool operator()(const ELFMergeAtom<ELFT> *a) {
+ int64_t off = a->offset();
+ return (_shdr->sh_name == a->section()) &&
+ ((_offset >= off) && (_offset <= off + (int64_t)a->size()));
+ }
+ };
+
+ /// \brief find a merge atom given a offset
+ ELFMergeAtom<ELFT> *findMergeAtom(const Elf_Shdr *shdr, uint64_t offset) {
+ auto it = std::find_if(_mergeAtoms.begin(), _mergeAtoms.end(),
+ FindByOffset(shdr, offset));
+ assert(it != _mergeAtoms.end());
+ return *it;
+ }
+
+ typedef std::unordered_map<MergeSectionKey, DefinedAtom *, MergeSectionEq,
+ MergeSectionEq> MergedSectionMapT;
+ typedef typename MergedSectionMapT::iterator MergedSectionMapIterT;
+
+public:
+ ELFFile(StringRef name, ELFLinkingContext &ctx)
+ : File(name, kindObject), _ordinal(0),
+ _doStringsMerge(ctx.mergeCommonStrings()), _useWrap(false), _ctx(ctx) {
+ setLastError(std::error_code());
+ }
+
+ ELFFile(std::unique_ptr<MemoryBuffer> mb, ELFLinkingContext &ctx)
+ : File(mb->getBufferIdentifier(), kindObject), _mb(std::move(mb)),
+ _ordinal(0), _doStringsMerge(ctx.mergeCommonStrings()),
+ _useWrap(ctx.wrapCalls().size()), _ctx(ctx) {}
+
+ static ErrorOr<std::unique_ptr<ELFFile>>
+ create(std::unique_ptr<MemoryBuffer> mb, ELFLinkingContext &ctx);
+
+ virtual Reference::KindArch kindArch();
+
+ /// \brief Create symbols from LinkingContext.
+ std::error_code createAtomsFromContext();
+
+ /// \brief Read input sections and populate necessary data structures
+ /// to read them later and create atoms
+ std::error_code createAtomizableSections();
+
+ /// \brief Create mergeable atoms from sections that have the merge attribute
+ /// set
+ std::error_code createMergeableAtoms();
+
+ /// \brief Add the symbols that the sections contain. The symbols will be
+ /// converted to atoms for
+ /// Undefined symbols, absolute symbols
+ std::error_code createSymbolsFromAtomizableSections();
+
+ /// \brief Create individual atoms
+ std::error_code createAtoms();
+
+ const atom_collection<DefinedAtom> &defined() const override {
+ return _definedAtoms;
+ }
+
+ const atom_collection<UndefinedAtom> &undefined() const override {
+ return _undefinedAtoms;
+ }
+
+ const atom_collection<SharedLibraryAtom> &sharedLibrary() const override {
+ return _sharedLibraryAtoms;
+ }
+
+ const atom_collection<AbsoluteAtom> &absolute() const override {
+ return _absoluteAtoms;
+ }
+
+ Atom *findAtom(const Elf_Sym *sourceSymbol, const Elf_Sym *targetSymbol) {
+ // All references to atoms inside a group are through undefined atoms.
+ Atom *targetAtom = _symbolToAtomMapping.lookup(targetSymbol);
+ StringRef targetSymbolName = targetAtom->name();
+ if (targetAtom->definition() != Atom::definitionRegular)
+ return targetAtom;
+ if ((llvm::dyn_cast<DefinedAtom>(targetAtom))->scope() ==
+ DefinedAtom::scopeTranslationUnit)
+ return targetAtom;
+ if (!redirectReferenceUsingUndefAtom(sourceSymbol, targetSymbol))
+ return targetAtom;
+ auto undefForGroupchild = _undefAtomsForGroupChild.find(targetSymbolName);
+ if (undefForGroupchild != _undefAtomsForGroupChild.end())
+ return undefForGroupchild->getValue();
+ auto undefGroupChildAtom =
+ new (_readerStorage) SimpleUndefinedAtom(*this, targetSymbolName);
+ _undefinedAtoms._atoms.push_back(undefGroupChildAtom);
+ return (_undefAtomsForGroupChild[targetSymbolName] = undefGroupChildAtom);
+ }
+
+protected:
+ ELFDefinedAtom<ELFT> *createDefinedAtomAndAssignRelocations(
+ StringRef symbolName, StringRef sectionName, const Elf_Sym *symbol,
+ const Elf_Shdr *section, ArrayRef<uint8_t> symContent,
+ ArrayRef<uint8_t> secContent);
+
+ std::error_code doParse() override;
+
+ /// \brief Iterate over Elf_Rela relocations list and create references.
+ virtual void createRelocationReferences(const Elf_Sym *symbol,
+ ArrayRef<uint8_t> content,
+ range<Elf_Rela_Iter> rels);
+
+ /// \brief Iterate over Elf_Rel relocations list and create references.
+ virtual void createRelocationReferences(const Elf_Sym *symbol,
+ ArrayRef<uint8_t> symContent,
+ ArrayRef<uint8_t> secContent,
+ range<Elf_Rel_Iter> rels);
+
+ /// \brief After all the Atoms and References are created, update each
+ /// Reference's target with the Atom pointer it refers to.
+ void updateReferences();
+
+ /// \brief Update the reference if the access corresponds to a merge string
+ /// section.
+ void updateReferenceForMergeStringAccess(ELFReference<ELFT> *ref,
+ const Elf_Sym *symbol,
+ const Elf_Shdr *shdr);
+
+ /// \brief Do we want to ignore the section. Ignored sections are
+ /// not processed to create atoms
+ bool isIgnoredSection(const Elf_Shdr *section);
+
+ /// \brief Is the current section be treated as a mergeable string section.
+ /// The contents of a mergeable string section are null-terminated strings.
+ /// If the section have mergeable strings, the linker would need to split
+ /// the section into multiple atoms and mark them mergeByContent.
+ bool isMergeableStringSection(const Elf_Shdr *section);
+
+ /// \brief Returns a new anonymous atom whose size is equal to the
+ /// section size. That atom will be used to represent the entire
+ /// section that have no symbols.
+ ELFDefinedAtom<ELFT> *createSectionAtom(const Elf_Shdr *section,
+ StringRef sectionName,
+ ArrayRef<uint8_t> contents);
+
+ /// Returns the symbol's content size. The nextSymbol should be null if the
+ /// symbol is the last one in the section.
+ uint64_t symbolContentSize(const Elf_Shdr *section,
+ const Elf_Sym *symbol,
+ const Elf_Sym *nextSymbol);
+
+ void createEdge(ELFDefinedAtom<ELFT> *from, ELFDefinedAtom<ELFT> *to,
+ uint32_t edgeKind);
+
+ /// Get the section name for a section.
+ ErrorOr<StringRef> getSectionName(const Elf_Shdr *shdr) const {
+ if (!shdr)
+ return StringRef();
+ return _objFile->getSectionName(shdr);
+ }
+
+ /// Determines if the section occupy memory space.
+ bool sectionOccupiesMemorySpace(const Elf_Shdr *shdr) const {
+ return (shdr->sh_type != llvm::ELF::SHT_NOBITS);
+ }
+
+ /// Return the section contents.
+ ErrorOr<ArrayRef<uint8_t>> getSectionContents(const Elf_Shdr *shdr) const {
+ if (!shdr || !sectionOccupiesMemorySpace(shdr))
+ return ArrayRef<uint8_t>();
+ return _objFile->getSectionContents(shdr);
+ }
+
+ /// Returns true if the symbol is a undefined symbol.
+ bool isUndefinedSymbol(const Elf_Sym *sym) const {
+ return (sym->st_shndx == llvm::ELF::SHN_UNDEF);
+ }
+
+ /// Determines if the target wants to create an atom for a section that has no
+ /// symbol references.
+ bool handleSectionWithNoSymbols(const Elf_Shdr *shdr,
+ std::vector<Elf_Sym_Iter> &syms) const {
+ return shdr && (shdr->sh_type == llvm::ELF::SHT_PROGBITS) && syms.empty();
+ }
+
+ /// Handle creation of atoms for .gnu.linkonce sections.
+ std::error_code handleGnuLinkOnceSection(
+ StringRef sectionName,
+ llvm::StringMap<std::vector<ELFDefinedAtom<ELFT> *>> &atomsForSection,
+ const Elf_Shdr *shdr);
+
+ // Handle Section groups/COMDAT scetions.
+ std::error_code handleSectionGroup(
+ StringRef signature, StringRef groupSectionName,
+ llvm::StringMap<std::vector<ELFDefinedAtom<ELFT> *>> &atomsForSection,
+ llvm::DenseMap<const Elf_Shdr *, std::vector<StringRef>> &comdatSections,
+ const Elf_Shdr *shdr);
+
+ /// Process the Undefined symbol and create an atom for it.
+ ErrorOr<ELFUndefinedAtom<ELFT> *>
+ handleUndefinedSymbol(StringRef symName, const Elf_Sym *sym) {
+ return new (_readerStorage) ELFUndefinedAtom<ELFT>(*this, symName, sym);
+ }
+
+ /// Returns true if the symbol is a absolute symbol.
+ bool isAbsoluteSymbol(const Elf_Sym *sym) const {
+ return (sym->st_shndx == llvm::ELF::SHN_ABS);
+ }
+
+ /// Process the Absolute symbol and create an atom for it.
+ ErrorOr<ELFAbsoluteAtom<ELFT> *>
+ handleAbsoluteSymbol(StringRef symName, const Elf_Sym *sym, int64_t value) {
+ return new (_readerStorage)
+ ELFAbsoluteAtom<ELFT>(*this, symName, sym, value);
+ }
+
+ /// Returns true if the symbol is common symbol. A common symbol represents a
+ /// tentive definition in C. It has name, size and alignment constraint, but
+ /// actual storage has not yet been allocated. (The linker will allocate
+ /// storage for them in the later pass after coalescing tentative symbols by
+ /// name.)
+ virtual bool isCommonSymbol(const Elf_Sym *symbol) const {
+ return symbol->getType() == llvm::ELF::STT_COMMON ||
+ symbol->st_shndx == llvm::ELF::SHN_COMMON;
+ }
+
+ /// Returns true if the section is a gnulinkonce section.
+ bool isGnuLinkOnceSection(StringRef sectionName) const {
+ return sectionName.startswith(".gnu.linkonce.");
+ }
+
+ /// Returns true if the section is a COMDAT group section.
+ bool isGroupSection(const Elf_Shdr *shdr) const {
+ return (shdr->sh_type == llvm::ELF::SHT_GROUP);
+ }
+
+ /// Returns true if the section is a member of some group.
+ bool isSectionMemberOfGroup(const Elf_Shdr *shdr) const {
+ return (shdr->sh_flags & llvm::ELF::SHF_GROUP);
+ }
+
+ /// Returns correct st_value for the symbol depending on the architecture.
+ /// For most architectures it's just a regular st_value with no changes.
+ virtual uint64_t getSymbolValue(const Elf_Sym *symbol) const {
+ return symbol->st_value;
+ }
+
+ /// Process the common symbol and create an atom for it.
+ virtual ErrorOr<ELFCommonAtom<ELFT> *>
+ handleCommonSymbol(StringRef symName, const Elf_Sym *sym) {
+ return new (_readerStorage) ELFCommonAtom<ELFT>(*this, symName, sym);
+ }
+
+ /// Returns true if the symbol is a defined symbol.
+ virtual bool isDefinedSymbol(const Elf_Sym *sym) const {
+ return (sym->getType() == llvm::ELF::STT_NOTYPE ||
+ sym->getType() == llvm::ELF::STT_OBJECT ||
+ sym->getType() == llvm::ELF::STT_FUNC ||
+ sym->getType() == llvm::ELF::STT_GNU_IFUNC ||
+ sym->getType() == llvm::ELF::STT_SECTION ||
+ sym->getType() == llvm::ELF::STT_FILE ||
+ sym->getType() == llvm::ELF::STT_TLS);
+ }
+
+ /// Process the Defined symbol and create an atom for it.
+ virtual ErrorOr<ELFDefinedAtom<ELFT> *>
+ handleDefinedSymbol(StringRef symName, StringRef sectionName,
+ const Elf_Sym *sym, const Elf_Shdr *sectionHdr,
+ ArrayRef<uint8_t> contentData,
+ unsigned int referenceStart, unsigned int referenceEnd,
+ std::vector<ELFReference<ELFT> *> &referenceList) {
+ return new (_readerStorage) ELFDefinedAtom<ELFT>(
+ *this, symName, sectionName, sym, sectionHdr, contentData,
+ referenceStart, referenceEnd, referenceList);
+ }
+
+ /// Process the Merge string and create an atom for it.
+ ErrorOr<ELFMergeAtom<ELFT> *>
+ handleMergeString(StringRef sectionName, const Elf_Shdr *sectionHdr,
+ ArrayRef<uint8_t> contentData, unsigned int offset) {
+ ELFMergeAtom<ELFT> *mergeAtom = new (_readerStorage)
+ ELFMergeAtom<ELFT>(*this, sectionName, sectionHdr, contentData, offset);
+ const MergeSectionKey mergedSectionKey(sectionHdr, offset);
+ if (_mergedSectionMap.find(mergedSectionKey) == _mergedSectionMap.end())
+ _mergedSectionMap.insert(std::make_pair(mergedSectionKey, mergeAtom));
+ return mergeAtom;
+ }
+
+ /// References to the sections comprising a group, from sections
+ /// outside the group, must be made via global UNDEF symbols,
+ /// referencing global symbols defined as addresses in the group
+ /// sections. They may not reference local symbols for addresses in
+ /// the group's sections, including section symbols.
+ /// ABI Doc : https://mentorembedded.github.io/cxx-abi/abi/prop-72-comdat.html
+ /// Does the atom need to be redirected using a separate undefined atom?
+ bool redirectReferenceUsingUndefAtom(const Elf_Sym *sourceSymbol,
+ const Elf_Sym *targetSymbol) const;
+
+ void addReferenceToSymbol(const ELFReference<ELFT> *r, const Elf_Sym *sym) {
+ _referenceToSymbol[r] = sym;
+ }
+
+ const Elf_Sym *findSymbolForReference(const ELFReference<ELFT> *r) const {
+ auto elfReferenceToSymbol = _referenceToSymbol.find(r);
+ if (elfReferenceToSymbol != _referenceToSymbol.end())
+ return elfReferenceToSymbol->second;
+ return nullptr;
+ }
+
+ llvm::BumpPtrAllocator _readerStorage;
+ std::unique_ptr<llvm::object::ELFFile<ELFT> > _objFile;
+ atom_collection_vector<DefinedAtom> _definedAtoms;
+ atom_collection_vector<UndefinedAtom> _undefinedAtoms;
+ atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
+ atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
+
+ /// \brief _relocationAddendReferences and _relocationReferences contain the
+ /// list of relocations references. In ELF, if a section named, ".text" has
+ /// relocations will also have a section named ".rel.text" or ".rela.text"
+ /// which will hold the entries.
+ std::unordered_map<StringRef, range<Elf_Rela_Iter>>
+ _relocationAddendReferences;
+ MergedSectionMapT _mergedSectionMap;
+ std::unordered_map<StringRef, range<Elf_Rel_Iter>> _relocationReferences;
+ std::vector<ELFReference<ELFT> *> _references;
+ llvm::DenseMap<const Elf_Sym *, Atom *> _symbolToAtomMapping;
+ llvm::DenseMap<const ELFReference<ELFT> *, const Elf_Sym *>
+ _referenceToSymbol;
+ // Group child atoms have a pair corresponding to the signature and the
+ // section header of the section that was used for generating the signature.
+ llvm::DenseMap<const Elf_Sym *, std::pair<StringRef, const Elf_Shdr *>>
+ _groupChild;
+ llvm::StringMap<Atom *> _undefAtomsForGroupChild;
+
+ /// \brief Atoms that are created for a section that has the merge property
+ /// set
+ MergeAtomsT _mergeAtoms;
+
+ /// \brief the section and the symbols that are contained within it to create
+ /// used to create atoms
+ llvm::MapVector<const Elf_Shdr *, std::vector<Elf_Sym_Iter>> _sectionSymbols;
+
+ /// \brief Sections that have merge string property
+ std::vector<const Elf_Shdr *> _mergeStringSections;
+
+ std::unique_ptr<MemoryBuffer> _mb;
+ int64_t _ordinal;
+
+ /// \brief the cached options relevant while reading the ELF File
+ bool _doStringsMerge;
+
+ /// \brief Is --wrap on?
+ bool _useWrap;
+
+ /// \brief The LinkingContext.
+ ELFLinkingContext &_ctx;
+
+ // Wrap map
+ llvm::StringMap<UndefinedAtom *> _wrapSymbolMap;
+};
+
+/// \brief All atoms are owned by a File. To add linker specific atoms
+/// the atoms need to be inserted to a file called (RuntimeFile) which
+/// are basically additional symbols required by libc and other runtime
+/// libraries part of executing a program. This class provides support
+/// for adding absolute symbols and undefined symbols
+template <class ELFT> class RuntimeFile : public ELFFile<ELFT> {
+public:
+ typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+ RuntimeFile(ELFLinkingContext &context, StringRef name)
+ : ELFFile<ELFT>(name, context) {}
+
+ /// \brief add a global absolute atom
+ virtual Atom *addAbsoluteAtom(StringRef symbolName) {
+ assert(!symbolName.empty() && "AbsoluteAtoms must have a name");
+ Elf_Sym *symbol = new (this->_readerStorage) Elf_Sym;
+ symbol->st_name = 0;
+ symbol->st_value = 0;
+ symbol->st_shndx = llvm::ELF::SHN_ABS;
+ symbol->setBindingAndType(llvm::ELF::STB_GLOBAL, llvm::ELF::STT_OBJECT);
+ symbol->setVisibility(llvm::ELF::STV_DEFAULT);
+ symbol->st_size = 0;
+ auto newAtom = this->handleAbsoluteSymbol(symbolName, symbol, -1);
+ this->_absoluteAtoms._atoms.push_back(*newAtom);
+ return *newAtom;
+ }
+
+ /// \brief add an undefined atom
+ virtual Atom *addUndefinedAtom(StringRef symbolName) {
+ assert(!symbolName.empty() && "UndefinedAtoms must have a name");
+ Elf_Sym *symbol = new (this->_readerStorage) Elf_Sym;
+ symbol->st_name = 0;
+ symbol->st_value = 0;
+ symbol->st_shndx = llvm::ELF::SHN_UNDEF;
+ symbol->setBindingAndType(llvm::ELF::STB_GLOBAL, llvm::ELF::STT_NOTYPE);
+ symbol->setVisibility(llvm::ELF::STV_DEFAULT);
+ symbol->st_size = 0;
+ auto newAtom = this->handleUndefinedSymbol(symbolName, symbol);
+ this->_undefinedAtoms._atoms.push_back(*newAtom);
+ return *newAtom;
+ }
+
+ // cannot add atoms to Runtime file
+ virtual void addAtom(const Atom &) {
+ llvm_unreachable("cannot add atoms to Runtime files");
+ }
+};
+
+template <class ELFT>
+ErrorOr<std::unique_ptr<ELFFile<ELFT>>>
+ELFFile<ELFT>::create(std::unique_ptr<MemoryBuffer> mb,
+ ELFLinkingContext &ctx) {
+ std::unique_ptr<ELFFile<ELFT>> file(new ELFFile<ELFT>(std::move(mb), ctx));
+ return std::move(file);
+}
+
+template <class ELFT>
+std::error_code ELFFile<ELFT>::doParse() {
+ std::error_code ec;
+ _objFile.reset(new llvm::object::ELFFile<ELFT>(_mb->getBuffer(), ec));
+ if (ec)
+ return ec;
+
+ if ((ec = createAtomsFromContext()))
+ return ec;
+
+ // Read input sections from the input file that need to be converted to
+ // atoms
+ if ((ec = createAtomizableSections()))
+ return ec;
+
+ // For mergeable strings, we would need to split the section into various
+ // atoms
+ if ((ec = createMergeableAtoms()))
+ return ec;
+
+ // Create the necessary symbols that are part of the section that we
+ // created in createAtomizableSections function
+ if ((ec = createSymbolsFromAtomizableSections()))
+ return ec;
+
+ // Create the appropriate atoms from the file
+ if ((ec = createAtoms()))
+ return ec;
+ return std::error_code();
+}
+
+template <class ELFT> Reference::KindArch ELFFile<ELFT>::kindArch() {
+ switch (_objFile->getHeader()->e_machine) {
+ case llvm::ELF::EM_X86_64:
+ return Reference::KindArch::x86_64;
+ case llvm::ELF::EM_386:
+ return Reference::KindArch::x86;
+ case llvm::ELF::EM_ARM:
+ return Reference::KindArch::ARM;
+ case llvm::ELF::EM_HEXAGON:
+ 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");
+}
+
+template <class ELFT>
+std::error_code ELFFile<ELFT>::createAtomizableSections() {
+ // Handle: SHT_REL and SHT_RELA sections:
+ // Increment over the sections, when REL/RELA section types are found add
+ // the contents to the RelocationReferences map.
+ // Record the number of relocs to guess at preallocating the buffer.
+ uint64_t totalRelocs = 0;
+ for (const Elf_Shdr &section : _objFile->sections()) {
+ if (isIgnoredSection(&section))
+ continue;
+
+ if (isMergeableStringSection(&section)) {
+ _mergeStringSections.push_back(&section);
+ continue;
+ }
+
+ if (section.sh_type == llvm::ELF::SHT_RELA) {
+ auto sHdr = _objFile->getSection(section.sh_info);
+
+ auto sectionName = _objFile->getSectionName(sHdr);
+ if (std::error_code ec = sectionName.getError())
+ return ec;
+
+ auto rai(_objFile->begin_rela(&section));
+ auto rae(_objFile->end_rela(&section));
+
+ _relocationAddendReferences[*sectionName] = make_range(rai, rae);
+ totalRelocs += std::distance(rai, rae);
+ } else if (section.sh_type == llvm::ELF::SHT_REL) {
+ auto sHdr = _objFile->getSection(section.sh_info);
+
+ auto sectionName = _objFile->getSectionName(sHdr);
+ if (std::error_code ec = sectionName.getError())
+ return ec;
+
+ auto ri(_objFile->begin_rel(&section));
+ auto re(_objFile->end_rel(&section));
+
+ _relocationReferences[*sectionName] = make_range(ri, re);
+ totalRelocs += std::distance(ri, re);
+ } else {
+ _sectionSymbols[&section];
+ }
+ }
+ _references.reserve(totalRelocs);
+ return std::error_code();
+}
+
+template <class ELFT> std::error_code ELFFile<ELFT>::createMergeableAtoms() {
+ // Divide the section that contains mergeable strings into tokens
+ // TODO
+ // a) add resolver support to recognize multibyte chars
+ // b) Create a separate section chunk to write mergeable atoms
+ std::vector<MergeString *> tokens;
+ for (const Elf_Shdr *msi : _mergeStringSections) {
+ auto sectionName = getSectionName(msi);
+ if (std::error_code ec = sectionName.getError())
+ return ec;
+
+ auto sectionContents = getSectionContents(msi);
+ if (std::error_code ec = sectionContents.getError())
+ return ec;
+
+ StringRef secCont(reinterpret_cast<const char *>(sectionContents->begin()),
+ sectionContents->size());
+
+ unsigned int prev = 0;
+ for (std::size_t i = 0, e = sectionContents->size(); i != e; ++i) {
+ if ((*sectionContents)[i] == '\0') {
+ tokens.push_back(new (_readerStorage) MergeString(
+ prev, secCont.slice(prev, i + 1), msi, *sectionName));
+ prev = i + 1;
+ }
+ }
+ }
+
+ // Create Mergeable atoms
+ for (const MergeString *tai : tokens) {
+ ArrayRef<uint8_t> content((const uint8_t *)tai->_string.data(),
+ tai->_string.size());
+ ErrorOr<ELFMergeAtom<ELFT> *> mergeAtom =
+ handleMergeString(tai->_sectionName, tai->_shdr, content, tai->_offset);
+ (*mergeAtom)->setOrdinal(++_ordinal);
+ _definedAtoms._atoms.push_back(*mergeAtom);
+ _mergeAtoms.push_back(*mergeAtom);
+ }
+ return std::error_code();
+}
+
+template <class ELFT>
+std::error_code ELFFile<ELFT>::createSymbolsFromAtomizableSections() {
+ // Increment over all the symbols collecting atoms and symbol names for
+ // later use.
+ auto SymI = _objFile->begin_symbols(), SymE = _objFile->end_symbols();
+
+ // Skip over dummy sym.
+ if (SymI != SymE)
+ ++SymI;
+
+ for (; SymI != SymE; ++SymI) {
+ const Elf_Shdr *section = _objFile->getSection(&*SymI);
+
+ auto symbolName = _objFile->getSymbolName(SymI);
+ if (std::error_code ec = symbolName.getError())
+ return ec;
+
+ if (isAbsoluteSymbol(&*SymI)) {
+ ErrorOr<ELFAbsoluteAtom<ELFT> *> absAtom =
+ handleAbsoluteSymbol(*symbolName, &*SymI, (int64_t)getSymbolValue(&*SymI));
+ _absoluteAtoms._atoms.push_back(*absAtom);
+ _symbolToAtomMapping.insert(std::make_pair(&*SymI, *absAtom));
+ } else if (isUndefinedSymbol(&*SymI)) {
+ if (_useWrap &&
+ (_wrapSymbolMap.find(*symbolName) != _wrapSymbolMap.end())) {
+ auto wrapAtom = _wrapSymbolMap.find(*symbolName);
+ _symbolToAtomMapping.insert(
+ std::make_pair(&*SymI, wrapAtom->getValue()));
+ continue;
+ }
+ ErrorOr<ELFUndefinedAtom<ELFT> *> undefAtom =
+ handleUndefinedSymbol(*symbolName, &*SymI);
+ _undefinedAtoms._atoms.push_back(*undefAtom);
+ _symbolToAtomMapping.insert(std::make_pair(&*SymI, *undefAtom));
+ } else if (isCommonSymbol(&*SymI)) {
+ ErrorOr<ELFCommonAtom<ELFT> *> commonAtom =
+ handleCommonSymbol(*symbolName, &*SymI);
+ (*commonAtom)->setOrdinal(++_ordinal);
+ _definedAtoms._atoms.push_back(*commonAtom);
+ _symbolToAtomMapping.insert(std::make_pair(&*SymI, *commonAtom));
+ } else if (isDefinedSymbol(&*SymI)) {
+ _sectionSymbols[section].push_back(SymI);
+ } else {
+ llvm::errs() << "Unable to create atom for: " << *symbolName << "\n";
+ return llvm::object::object_error::parse_failed;
+ }
+ }
+
+ return std::error_code();
+}
+
+template <class ELFT> std::error_code ELFFile<ELFT>::createAtoms() {
+ // Holds all the atoms that are part of the section. They are the targets of
+ // the kindGroupChild reference.
+ llvm::StringMap<std::vector<ELFDefinedAtom<ELFT> *>> atomsForSection;
+ // group sections have a mapping of the section header to the
+ // signature/section.
+ llvm::DenseMap<const Elf_Shdr *, std::pair<StringRef, StringRef>>
+ groupSections;
+ // Contains a list of comdat sections for a group.
+ llvm::DenseMap<const Elf_Shdr *, std::vector<StringRef>> comdatSections;
+ for (auto &i : _sectionSymbols) {
+ const Elf_Shdr *section = i.first;
+ std::vector<Elf_Sym_Iter> &symbols = i.second;
+
+ // Sort symbols by position.
+ std::stable_sort(symbols.begin(), symbols.end(),
+ [this](Elf_Sym_Iter a, Elf_Sym_Iter b) {
+ return getSymbolValue(&*a) < getSymbolValue(&*b);
+ });
+
+ ErrorOr<StringRef> sectionName = this->getSectionName(section);
+ if (std::error_code ec = sectionName.getError())
+ return ec;
+
+ auto sectionContents = getSectionContents(section);
+ if (std::error_code ec = sectionContents.getError())
+ return ec;
+
+ bool addAtoms = true;
+
+ // A section of type SHT_GROUP defines a grouping of sections. The name of a
+ // symbol from one of the containing object's symbol tables provides a
+ // signature
+ // for the section group. The section header of the SHT_GROUP section
+ // specifies
+ // the identifying symbol entry, as described : the sh_link member contains
+ // the section header index of the symbol table section that contains the
+ // entry.
+ // The sh_info member contains the symbol table index of the identifying
+ // entry.
+ // The sh_flags member of the section header contains 0. The name of the
+ // section
+ // (sh_name) is not specified.
+ if (isGroupSection(section)) {
+ const Elf_Word *groupMembers =
+ reinterpret_cast<const Elf_Word *>(sectionContents->data());
+ const long count = (section->sh_size) / sizeof(Elf_Word);
+ for (int i = 1; i < count; i++) {
+ const Elf_Shdr *sHdr = _objFile->getSection(groupMembers[i]);
+ ErrorOr<StringRef> sectionName = _objFile->getSectionName(sHdr);
+ if (std::error_code ec = sectionName.getError())
+ return ec;
+ comdatSections[section].push_back(*sectionName);
+ }
+ const Elf_Sym *symbol = _objFile->getSymbol(section->sh_info);
+ const Elf_Shdr *symtab = _objFile->getSection(section->sh_link);
+ ErrorOr<StringRef> symbolName = _objFile->getSymbolName(symtab, symbol);
+ if (std::error_code ec = symbolName.getError())
+ return ec;
+ groupSections.insert(
+ std::make_pair(section, std::make_pair(*symbolName, *sectionName)));
+ continue;
+ }
+
+ if (isGnuLinkOnceSection(*sectionName)) {
+ groupSections.insert(
+ std::make_pair(section, std::make_pair(*sectionName, *sectionName)));
+ addAtoms = false;
+ }
+
+ if (isSectionMemberOfGroup(section))
+ addAtoms = false;
+
+ if (handleSectionWithNoSymbols(section, symbols)) {
+ ELFDefinedAtom<ELFT> *newAtom =
+ createSectionAtom(section, *sectionName, *sectionContents);
+ newAtom->setOrdinal(++_ordinal);
+ if (addAtoms)
+ _definedAtoms._atoms.push_back(newAtom);
+ else
+ atomsForSection[*sectionName].push_back(newAtom);
+ continue;
+ }
+
+ ELFDefinedAtom<ELFT> *previousAtom = nullptr;
+ ELFReference<ELFT> *anonFollowedBy = nullptr;
+
+ for (auto si = symbols.begin(), se = symbols.end(); si != se; ++si) {
+ auto symbol = *si;
+ StringRef symbolName = "";
+ if (symbol->getType() != llvm::ELF::STT_SECTION) {
+ auto symName = _objFile->getSymbolName(symbol);
+ if (std::error_code ec = symName.getError())
+ return ec;
+ symbolName = *symName;
+ }
+
+ uint64_t contentSize = symbolContentSize(
+ section, &*symbol, (si + 1 == se) ? nullptr : &**(si + 1));
+
+ // Check to see if we need to add the FollowOn Reference
+ ELFReference<ELFT> *followOn = nullptr;
+ if (previousAtom) {
+ // Replace the followon atom with the anonymous atom that we created,
+ // so that the next symbol that we create is a followon from the
+ // anonymous atom.
+ if (anonFollowedBy) {
+ followOn = anonFollowedBy;
+ } else {
+ followOn = new (_readerStorage)
+ ELFReference<ELFT>(lld::Reference::kindLayoutAfter);
+ previousAtom->addReference(followOn);
+ }
+ }
+
+ ArrayRef<uint8_t> symbolData((const uint8_t *)sectionContents->data() +
+ getSymbolValue(&*symbol),
+ contentSize);
+
+ // If the linker finds that a section has global atoms that are in a
+ // mergeable section, treat them as defined atoms as they shouldn't be
+ // merged away as well as these symbols have to be part of symbol
+ // resolution
+ if (isMergeableStringSection(section)) {
+ if (symbol->getBinding() == llvm::ELF::STB_GLOBAL) {
+ auto definedMergeAtom = handleDefinedSymbol(
+ symbolName, *sectionName, &**si, section, symbolData,
+ _references.size(), _references.size(), _references);
+ (*definedMergeAtom)->setOrdinal(++_ordinal);
+ if (addAtoms)
+ _definedAtoms._atoms.push_back(*definedMergeAtom);
+ else
+ atomsForSection[*sectionName].push_back(*definedMergeAtom);
+ }
+ continue;
+ }
+
+ // Don't allocate content to a weak symbol, as they may be merged away.
+ // Create an anonymous atom to hold the data.
+ ELFDefinedAtom<ELFT> *anonAtom = nullptr;
+ anonFollowedBy = nullptr;
+ if (symbol->getBinding() == llvm::ELF::STB_WEAK) {
+ // Create anonymous new non-weak ELF symbol that holds the symbol
+ // data.
+ auto sym = new (_readerStorage) Elf_Sym(*symbol);
+ sym->setBinding(llvm::ELF::STB_GLOBAL);
+ anonAtom = createDefinedAtomAndAssignRelocations(
+ "", *sectionName, sym, section, symbolData, *sectionContents);
+ symbolData = ArrayRef<uint8_t>();
+
+ // If this is the last atom, let's not create a followon reference.
+ if (anonAtom && (si + 1) != se) {
+ anonFollowedBy = new (_readerStorage)
+ ELFReference<ELFT>(lld::Reference::kindLayoutAfter);
+ anonAtom->addReference(anonFollowedBy);
+ }
+ }
+
+ ELFDefinedAtom<ELFT> *newAtom = createDefinedAtomAndAssignRelocations(
+ symbolName, *sectionName, &*symbol, section, symbolData,
+ *sectionContents);
+ newAtom->setOrdinal(++_ordinal);
+
+ // If the atom was a weak symbol, let's create a followon reference to
+ // the anonymous atom that we created.
+ if (anonAtom)
+ createEdge(newAtom, anonAtom, Reference::kindLayoutAfter);
+
+ if (previousAtom) {
+ // Set the followon atom to the weak atom that we have created, so
+ // that they would alias when the file gets written.
+ followOn->setTarget(anonAtom ? anonAtom : newAtom);
+ }
+
+ // The previous atom is always the atom created before unless the atom
+ // is a weak atom.
+ previousAtom = anonAtom ? anonAtom : newAtom;
+
+ if (addAtoms)
+ _definedAtoms._atoms.push_back(newAtom);
+ else
+ atomsForSection[*sectionName].push_back(newAtom);
+
+ _symbolToAtomMapping.insert(std::make_pair(&*symbol, newAtom));
+ if (anonAtom) {
+ anonAtom->setOrdinal(++_ordinal);
+ if (addAtoms)
+ _definedAtoms._atoms.push_back(anonAtom);
+ else
+ atomsForSection[*sectionName].push_back(anonAtom);
+ }
+ }
+ }
+
+ // Iterate over all the group sections to create parent atoms pointing to
+ // group-child atoms.
+ for (auto &sect : groupSections) {
+ StringRef signature = sect.second.first;
+ StringRef groupSectionName = sect.second.second;
+ if (isGnuLinkOnceSection(signature))
+ handleGnuLinkOnceSection(signature, atomsForSection, sect.first);
+ else if (isGroupSection(sect.first))
+ handleSectionGroup(signature, groupSectionName, atomsForSection,
+ comdatSections, sect.first);
+ }
+
+ updateReferences();
+ return std::error_code();
+}
+
+template <class ELFT>
+std::error_code ELFFile<ELFT>::handleGnuLinkOnceSection(
+ StringRef signature,
+ llvm::StringMap<std::vector<ELFDefinedAtom<ELFT> *>> &atomsForSection,
+ const Elf_Shdr *shdr) {
+ // TODO: Check for errors.
+ unsigned int referenceStart = _references.size();
+ std::vector<ELFReference<ELFT> *> refs;
+ for (auto ha : atomsForSection[signature]) {
+ _groupChild[ha->symbol()] = std::make_pair(signature, shdr);
+ ELFReference<ELFT> *ref =
+ new (_readerStorage) ELFReference<ELFT>(lld::Reference::kindGroupChild);
+ ref->setTarget(ha);
+ refs.push_back(ref);
+ }
+ atomsForSection[signature].clear();
+ // Create a gnu linkonce atom.
+ auto gnuLinkOnceAtom = handleDefinedSymbol(
+ signature, signature, nullptr, shdr, ArrayRef<uint8_t>(), referenceStart,
+ _references.size(), _references);
+ (*gnuLinkOnceAtom)->setOrdinal(++_ordinal);
+ _definedAtoms._atoms.push_back(*gnuLinkOnceAtom);
+ for (auto reference : refs)
+ (*gnuLinkOnceAtom)->addReference(reference);
+ return std::error_code();
+}
+
+template <class ELFT>
+std::error_code ELFFile<ELFT>::handleSectionGroup(
+ StringRef signature, StringRef groupSectionName,
+ llvm::StringMap<std::vector<ELFDefinedAtom<ELFT> *>> &atomsForSection,
+ llvm::DenseMap<const Elf_Shdr *, std::vector<StringRef>> &comdatSections,
+ const Elf_Shdr *shdr) {
+ // TODO: Check for errors.
+ unsigned int referenceStart = _references.size();
+ std::vector<ELFReference<ELFT> *> refs;
+ auto sectionNamesInGroup = comdatSections[shdr];
+ for (auto sectionName : sectionNamesInGroup) {
+ for (auto ha : atomsForSection[sectionName]) {
+ _groupChild[ha->symbol()] = std::make_pair(signature, shdr);
+ ELFReference<ELFT> *ref = new (_readerStorage)
+ ELFReference<ELFT>(lld::Reference::kindGroupChild);
+ ref->setTarget(ha);
+ refs.push_back(ref);
+ }
+ atomsForSection[sectionName].clear();
+ }
+ // Create a gnu linkonce atom.
+ auto sectionGroupAtom = handleDefinedSymbol(
+ signature, groupSectionName, nullptr, shdr, ArrayRef<uint8_t>(),
+ referenceStart, _references.size(), _references);
+ (*sectionGroupAtom)->setOrdinal(++_ordinal);
+ _definedAtoms._atoms.push_back(*sectionGroupAtom);
+ for (auto reference : refs)
+ (*sectionGroupAtom)->addReference(reference);
+ return std::error_code();
+}
+
+template <class ELFT> std::error_code ELFFile<ELFT>::createAtomsFromContext() {
+ if (!_useWrap)
+ return std::error_code();
+ // Steps :-
+ // a) Create an undefined atom for the symbol specified by the --wrap option,
+ // as that
+ // may be needed to be pulled from an archive.
+ // b) Create an undefined atom for __wrap_<symbolname>.
+ // c) All references to the symbol specified by wrap should point to
+ // __wrap_<symbolname>
+ // d) All references to __real_symbol should point to the <symbol>
+ for (auto &wrapsym : _ctx.wrapCalls()) {
+ StringRef wrapStr = wrapsym.getKey();
+ // Create a undefined symbol fror the wrap symbol.
+ UndefinedAtom *wrapSymAtom =
+ new (_readerStorage) SimpleUndefinedAtom(*this, wrapStr);
+ StringRef wrapCallSym =
+ _ctx.allocateString((llvm::Twine("__wrap_") + wrapStr).str());
+ StringRef realCallSym =
+ _ctx.allocateString((llvm::Twine("__real_") + wrapStr).str());
+ UndefinedAtom *wrapCallAtom =
+ new (_readerStorage) SimpleUndefinedAtom(*this, wrapCallSym);
+ // Create maps, when there is call to sym, it should point to wrapCallSym.
+ _wrapSymbolMap.insert(std::make_pair(wrapStr, wrapCallAtom));
+ // Whenever there is a reference to realCall it should point to the symbol
+ // created for each wrap usage.
+ _wrapSymbolMap.insert(std::make_pair(realCallSym, wrapSymAtom));
+ _undefinedAtoms._atoms.push_back(wrapSymAtom);
+ _undefinedAtoms._atoms.push_back(wrapCallAtom);
+ }
+ return std::error_code();
+}
+
+template <class ELFT>
+ELFDefinedAtom<ELFT> *ELFFile<ELFT>::createDefinedAtomAndAssignRelocations(
+ StringRef symbolName, StringRef sectionName, const Elf_Sym *symbol,
+ const Elf_Shdr *section, ArrayRef<uint8_t> symContent,
+ ArrayRef<uint8_t> secContent) {
+ unsigned int referenceStart = _references.size();
+
+ // Add Rela (those with r_addend) references:
+ auto rari = _relocationAddendReferences.find(sectionName);
+ if (rari != _relocationAddendReferences.end())
+ createRelocationReferences(symbol, symContent, rari->second);
+
+ // Add Rel references.
+ auto rri = _relocationReferences.find(sectionName);
+ if (rri != _relocationReferences.end())
+ createRelocationReferences(symbol, symContent, secContent, rri->second);
+
+ // Create the DefinedAtom and add it to the list of DefinedAtoms.
+ return *handleDefinedSymbol(symbolName, sectionName, symbol, section,
+ symContent, referenceStart, _references.size(),
+ _references);
+}
+
+template <class ELFT>
+void ELFFile<ELFT>::createRelocationReferences(const Elf_Sym *symbol,
+ ArrayRef<uint8_t> content,
+ range<Elf_Rela_Iter> rels) {
+ bool isMips64EL = _objFile->isMips64EL();
+ const auto symValue = getSymbolValue(symbol);
+ for (const auto &rel : rels) {
+ if (rel.r_offset < symValue ||
+ symValue + content.size() <= rel.r_offset)
+ continue;
+ auto elfRelocation = new (_readerStorage)
+ ELFReference<ELFT>(&rel, rel.r_offset - symValue, kindArch(),
+ rel.getType(isMips64EL), rel.getSymbol(isMips64EL));
+ addReferenceToSymbol(elfRelocation, symbol);
+ _references.push_back(elfRelocation);
+ }
+}
+
+template <class ELFT>
+void ELFFile<ELFT>::createRelocationReferences(const Elf_Sym *symbol,
+ ArrayRef<uint8_t> symContent,
+ ArrayRef<uint8_t> secContent,
+ range<Elf_Rel_Iter> rels) {
+ bool isMips64EL = _objFile->isMips64EL();
+ const auto symValue = getSymbolValue(symbol);
+ for (const auto &rel : rels) {
+ if (rel.r_offset < symValue ||
+ symValue + symContent.size() <= rel.r_offset)
+ continue;
+ auto elfRelocation = new (_readerStorage)
+ ELFReference<ELFT>(rel.r_offset - symValue, kindArch(),
+ rel.getType(isMips64EL), rel.getSymbol(isMips64EL));
+ int32_t addend = *(symContent.data() + rel.r_offset - symValue);
+ elfRelocation->setAddend(addend);
+ addReferenceToSymbol(elfRelocation, symbol);
+ _references.push_back(elfRelocation);
+ }
+}
+
+template <class ELFT>
+void ELFFile<ELFT>::updateReferenceForMergeStringAccess(ELFReference<ELFT> *ref,
+ const Elf_Sym *symbol,
+ const Elf_Shdr *shdr) {
+ // If the target atom is mergeable strefng atom, the atom might have been
+ // merged with other atom having the same contents. Try to find the
+ // merged one if that's the case.
+ int64_t addend = ref->addend();
+ if (addend < 0)
+ addend = 0;
+
+ const MergeSectionKey ms(shdr, addend);
+ auto msec = _mergedSectionMap.find(ms);
+ if (msec != _mergedSectionMap.end()) {
+ ref->setTarget(msec->second);
+ return;
+ }
+
+ // The target atom was not merged. Mergeable atoms are not in
+ // _symbolToAtomMapping, so we cannot find it by calling findAtom(). We
+ // instead call findMergeAtom().
+ if (symbol->getType() != llvm::ELF::STT_SECTION)
+ addend = getSymbolValue(symbol) + addend;
+ ELFMergeAtom<ELFT> *mergedAtom = findMergeAtom(shdr, addend);
+ ref->setOffset(addend - mergedAtom->offset());
+ ref->setAddend(0);
+ ref->setTarget(mergedAtom);
+}
+
+template <class ELFT> void ELFFile<ELFT>::updateReferences() {
+ for (auto &ri : _references) {
+ if (ri->kindNamespace() != lld::Reference::KindNamespace::ELF)
+ continue;
+ const Elf_Sym *symbol = _objFile->getSymbol(ri->targetSymbolIndex());
+ const Elf_Shdr *shdr = _objFile->getSection(symbol);
+
+ // If the atom is not in mergeable string section, the target atom is
+ // simply that atom.
+ if (isMergeableStringSection(shdr))
+ updateReferenceForMergeStringAccess(ri, symbol, shdr);
+ else
+ ri->setTarget(findAtom(findSymbolForReference(ri), symbol));
+ }
+}
+
+template <class ELFT>
+bool ELFFile<ELFT>::isIgnoredSection(const Elf_Shdr *section) {
+ switch (section->sh_type) {
+ case llvm::ELF::SHT_NULL:
+ case llvm::ELF::SHT_STRTAB:
+ case llvm::ELF::SHT_SYMTAB:
+ case llvm::ELF::SHT_SYMTAB_SHNDX:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+template <class ELFT>
+bool ELFFile<ELFT>::isMergeableStringSection(const Elf_Shdr *section) {
+ if (_doStringsMerge && section) {
+ int64_t sectionFlags = section->sh_flags;
+ sectionFlags &= ~llvm::ELF::SHF_ALLOC;
+ // Mergeable string sections have both SHF_MERGE and SHF_STRINGS flags
+ // set. sh_entsize is the size of each character which is normally 1.
+ if ((section->sh_entsize < 2) &&
+ (sectionFlags == (llvm::ELF::SHF_MERGE | llvm::ELF::SHF_STRINGS))) {
+ return true;
+ }
+ }
+ return false;
+}
+
+template <class ELFT>
+ELFDefinedAtom<ELFT> *
+ELFFile<ELFT>::createSectionAtom(const Elf_Shdr *section, StringRef sectionName,
+ ArrayRef<uint8_t> content) {
+ Elf_Sym *sym = new (_readerStorage) Elf_Sym;
+ sym->st_name = 0;
+ sym->setBindingAndType(llvm::ELF::STB_LOCAL, llvm::ELF::STT_SECTION);
+ sym->st_other = 0;
+ sym->st_shndx = 0;
+ sym->st_value = 0;
+ sym->st_size = 0;
+ auto *newAtom = createDefinedAtomAndAssignRelocations(
+ "", sectionName, sym, section, content, content);
+ newAtom->setOrdinal(++_ordinal);
+ return newAtom;
+}
+
+template <class ELFT>
+uint64_t ELFFile<ELFT>::symbolContentSize(const Elf_Shdr *section,
+ const Elf_Sym *symbol,
+ const Elf_Sym *nextSymbol) {
+ const auto symValue = getSymbolValue(symbol);
+ // if this is the last symbol, take up the remaining data.
+ return nextSymbol ? getSymbolValue(nextSymbol) - symValue
+ : section->sh_size - symValue;
+}
+
+template <class ELFT>
+void ELFFile<ELFT>::createEdge(ELFDefinedAtom<ELFT> *from,
+ ELFDefinedAtom<ELFT> *to, uint32_t edgeKind) {
+ auto reference = new (_readerStorage) ELFReference<ELFT>(edgeKind);
+ reference->setTarget(to);
+ from->addReference(reference);
+}
+
+/// Does the atom need to be redirected using a separate undefined atom?
+template <class ELFT>
+bool ELFFile<ELFT>::redirectReferenceUsingUndefAtom(
+ const Elf_Sym *sourceSymbol, const Elf_Sym *targetSymbol) const {
+ auto groupChildTarget = _groupChild.find(targetSymbol);
+
+ // If the reference is not to a group child atom, there is no need to redirect
+ // using a undefined atom. Its also not needed if the source and target are
+ // from the same section.
+ if ((groupChildTarget == _groupChild.end()) ||
+ (sourceSymbol->st_shndx == targetSymbol->st_shndx))
+ return false;
+
+ auto groupChildSource = _groupChild.find(sourceSymbol);
+
+ // If the source symbol is not in a group, use a undefined symbol too.
+ if (groupChildSource == _groupChild.end())
+ return true;
+
+ // If the source and child are from the same group, we dont need the
+ // relocation to go through a undefined symbol.
+ if (groupChildSource->second.second == groupChildTarget->second.second)
+ return false;
+
+ return true;
+}
+
+} // end namespace elf
+} // end namespace lld
+
+#endif // LLD_READER_WRITER_ELF_FILE_H
diff --git a/lib/ReaderWriter/ELF/ELFLinkingContext.cpp b/lib/ReaderWriter/ELF/ELFLinkingContext.cpp
new file mode 100644
index 0000000000000..c7dffda8a463e
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ELFLinkingContext.cpp
@@ -0,0 +1,259 @@
+//===- lib/ReaderWriter/ELF/ELFLinkingContext.cpp -------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/ReaderWriter/ELFLinkingContext.h"
+#include "ELFFile.h"
+#include "OrderPass.h"
+#include "TargetHandler.h"
+#include "lld/Core/Instrumentation.h"
+#include "lld/Core/SharedLibraryFile.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Config/config.h"
+#include "llvm/Support/ELF.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+
+#if defined(HAVE_CXXABI_H)
+#include <cxxabi.h>
+#endif
+
+namespace lld {
+
+class CommandLineUndefinedAtom : public SimpleUndefinedAtom {
+public:
+ CommandLineUndefinedAtom(const File &f, StringRef name)
+ : SimpleUndefinedAtom(f, name) {}
+
+ CanBeNull canBeNull() const override {
+ return CanBeNull::canBeNullAtBuildtime;
+ }
+};
+
+ELFLinkingContext::ELFLinkingContext(
+ llvm::Triple triple, std::unique_ptr<TargetHandlerBase> targetHandler)
+ : _outputELFType(llvm::ELF::ET_EXEC), _triple(triple),
+ _targetHandler(std::move(targetHandler)), _baseAddress(0),
+ _isStaticExecutable(false), _noInhibitExec(false), _exportDynamic(false),
+ _mergeCommonStrings(false), _useShlibUndefines(true),
+ _dynamicLinkerArg(false), _noAllowDynamicLibraries(false),
+ _mergeRODataToTextSegment(true), _demangle(true),
+ _stripSymbols(false), _alignSegments(true), _collectStats(false),
+ _outputMagic(OutputMagic::DEFAULT), _initFunction("_init"),
+ _finiFunction("_fini"), _sysrootPath(""), _linkerScriptSema() {}
+
+void ELFLinkingContext::addPasses(PassManager &pm) {
+ pm.add(llvm::make_unique<elf::OrderPass>());
+}
+
+uint16_t ELFLinkingContext::getOutputMachine() const {
+ switch (getTriple().getArch()) {
+ case llvm::Triple::x86:
+ return llvm::ELF::EM_386;
+ case llvm::Triple::x86_64:
+ return llvm::ELF::EM_X86_64;
+ case llvm::Triple::hexagon:
+ return llvm::ELF::EM_HEXAGON;
+ case llvm::Triple::mipsel:
+ case llvm::Triple::mips64el:
+ return llvm::ELF::EM_MIPS;
+ case llvm::Triple::aarch64:
+ return llvm::ELF::EM_AARCH64;
+ case llvm::Triple::arm:
+ return llvm::ELF::EM_ARM;
+ default:
+ llvm_unreachable("Unhandled arch");
+ }
+}
+
+StringRef ELFLinkingContext::entrySymbolName() const {
+ if (_outputELFType == llvm::ELF::ET_EXEC && _entrySymbolName.empty())
+ return "_start";
+ return _entrySymbolName;
+}
+
+bool ELFLinkingContext::validateImpl(raw_ostream &diagnostics) {
+ switch (outputFileType()) {
+ case LinkingContext::OutputFileType::YAML:
+ _writer = createWriterYAML(*this);
+ break;
+ case LinkingContext::OutputFileType::Native:
+ llvm_unreachable("Unimplemented");
+ break;
+ default:
+ _writer = createWriterELF(this->targetHandler());
+ break;
+ }
+
+ // If -dead_strip, set up initial live symbols.
+ if (deadStrip())
+ addDeadStripRoot(entrySymbolName());
+ return true;
+}
+
+bool ELFLinkingContext::isDynamic() const {
+ switch (_outputELFType) {
+ case llvm::ELF::ET_EXEC:
+ return !_isStaticExecutable;
+ case llvm::ELF::ET_DYN:
+ return true;
+ }
+ return false;
+}
+
+bool ELFLinkingContext::isRelativeReloc(const Reference &) const {
+ return false;
+}
+
+Writer &ELFLinkingContext::writer() const { return *_writer; }
+
+static void buildSearchPath(SmallString<128> &path, StringRef dir,
+ StringRef sysRoot) {
+ if (!dir.startswith("=/"))
+ path.assign(dir);
+ else {
+ path.assign(sysRoot);
+ path.append(dir.substr(1));
+ }
+}
+
+ErrorOr<StringRef> ELFLinkingContext::searchLibrary(StringRef libName) const {
+ bool hasColonPrefix = libName[0] == ':';
+ SmallString<128> path;
+ for (StringRef dir : _inputSearchPaths) {
+ // Search for dynamic library
+ if (!_isStaticExecutable) {
+ buildSearchPath(path, dir, _sysrootPath);
+ llvm::sys::path::append(path, hasColonPrefix
+ ? libName.drop_front()
+ : Twine("lib", libName) + ".so");
+ if (llvm::sys::fs::exists(path.str()))
+ return StringRef(*new (_allocator) std::string(path.str()));
+ }
+ // Search for static libraries too
+ buildSearchPath(path, dir, _sysrootPath);
+ llvm::sys::path::append(path, hasColonPrefix
+ ? libName.drop_front()
+ : Twine("lib", libName) + ".a");
+ if (llvm::sys::fs::exists(path.str()))
+ return StringRef(*new (_allocator) std::string(path.str()));
+ }
+ if (hasColonPrefix && llvm::sys::fs::exists(libName.drop_front()))
+ return libName.drop_front();
+
+ return make_error_code(llvm::errc::no_such_file_or_directory);
+}
+
+ErrorOr<StringRef> ELFLinkingContext::searchFile(StringRef fileName,
+ bool isSysRooted) const {
+ SmallString<128> path;
+ if (llvm::sys::path::is_absolute(fileName) && isSysRooted) {
+ path.assign(_sysrootPath);
+ path.append(fileName);
+ if (llvm::sys::fs::exists(path.str()))
+ return StringRef(*new (_allocator) std::string(path.str()));
+ } else if (llvm::sys::fs::exists(fileName))
+ return fileName;
+
+ if (llvm::sys::path::is_absolute(fileName))
+ return make_error_code(llvm::errc::no_such_file_or_directory);
+
+ for (StringRef dir : _inputSearchPaths) {
+ buildSearchPath(path, dir, _sysrootPath);
+ llvm::sys::path::append(path, fileName);
+ if (llvm::sys::fs::exists(path.str()))
+ return StringRef(*new (_allocator) std::string(path.str()));
+ }
+ return make_error_code(llvm::errc::no_such_file_or_directory);
+}
+
+void ELFLinkingContext::createInternalFiles(
+ std::vector<std::unique_ptr<File>> &files) const {
+ std::unique_ptr<SimpleFile> file(
+ new SimpleFile("<internal file for --defsym>"));
+ for (auto &i : getAbsoluteSymbols()) {
+ StringRef sym = i.first;
+ uint64_t val = i.second;
+ file->addAtom(*(new (_allocator) SimpleAbsoluteAtom(
+ *file, sym, Atom::scopeGlobal, val)));
+ }
+ files.push_back(std::move(file));
+ LinkingContext::createInternalFiles(files);
+}
+
+void ELFLinkingContext::finalizeInputFiles() {
+ // Add virtual archive that resolves undefined symbols.
+ if (_resolver)
+ getNodes().push_back(llvm::make_unique<FileNode>(std::move(_resolver)));
+}
+
+std::unique_ptr<File> ELFLinkingContext::createUndefinedSymbolFile() const {
+ if (_initialUndefinedSymbols.empty())
+ return nullptr;
+ std::unique_ptr<SimpleFile> undefinedSymFile(
+ new SimpleFile("command line option -u"));
+ for (auto undefSymStr : _initialUndefinedSymbols)
+ undefinedSymFile->addAtom(*(new (_allocator) CommandLineUndefinedAtom(
+ *undefinedSymFile, undefSymStr)));
+ return std::move(undefinedSymFile);
+}
+
+void ELFLinkingContext::notifySymbolTableCoalesce(const Atom *existingAtom,
+ const Atom *newAtom,
+ bool &useNew) {
+ // First suppose that the `existingAtom` is defined
+ // and the `newAtom` is undefined.
+ auto *da = dyn_cast<DefinedAtom>(existingAtom);
+ auto *ua = dyn_cast<UndefinedAtom>(newAtom);
+ if (!da && !ua) {
+ // Then try to reverse the assumption.
+ da = dyn_cast<DefinedAtom>(newAtom);
+ ua = dyn_cast<UndefinedAtom>(existingAtom);
+ }
+
+ if (da && ua && da->scope() == Atom::scopeGlobal &&
+ isa<SharedLibraryFile>(ua->file()))
+ // If strong defined atom coalesces away an atom declared
+ // in the shared object the strong atom needs to be dynamically exported.
+ // Save its name.
+ _dynamicallyExportedSymbols.insert(ua->name());
+}
+
+std::string ELFLinkingContext::demangle(StringRef symbolName) const {
+ if (!demangleSymbols())
+ return symbolName;
+
+ // Only try to demangle symbols that look like C++ symbols
+ if (!symbolName.startswith("_Z"))
+ return symbolName;
+
+#if defined(HAVE_CXXABI_H)
+ SmallString<256> symBuff;
+ StringRef nullTermSym = Twine(symbolName).toNullTerminatedStringRef(symBuff);
+ const char *cstr = nullTermSym.data();
+ int status;
+ char *demangled = abi::__cxa_demangle(cstr, nullptr, nullptr, &status);
+ if (demangled != NULL) {
+ std::string result(demangled);
+ // __cxa_demangle() always uses a malloc'ed buffer to return the result.
+ free(demangled);
+ return result;
+ }
+#endif
+
+ return symbolName;
+}
+
+void ELFLinkingContext::setUndefinesResolver(std::unique_ptr<File> resolver) {
+ assert(isa<ArchiveLibraryFile>(resolver.get()) && "Wrong resolver type");
+ _resolver = std::move(resolver);
+}
+
+} // end namespace lld
diff --git a/lib/ReaderWriter/ELF/ELFReader.h b/lib/ReaderWriter/ELF/ELFReader.h
new file mode 100644
index 0000000000000..43f218115c666
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ELFReader.h
@@ -0,0 +1,102 @@
+//===- lib/ReaderWriter/ELF/ELFReader.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_READER_H
+#define LLD_READER_WRITER_ELF_READER_H
+
+#include "CreateELF.h"
+#include "DynamicFile.h"
+#include "ELFFile.h"
+#include "lld/Core/Reader.h"
+
+namespace lld {
+namespace elf {
+
+template <typename ELFT, typename ELFTraitsT, typename ContextT>
+class ELFObjectReader : public Reader {
+public:
+ typedef llvm::object::Elf_Ehdr_Impl<ELFT> Elf_Ehdr;
+
+ ELFObjectReader(ContextT &ctx, uint64_t machine)
+ : _ctx(ctx), _machine(machine) {}
+
+ bool canParse(file_magic magic, StringRef,
+ const MemoryBuffer &buf) const override {
+ return (magic == llvm::sys::fs::file_magic::elf_relocatable &&
+ elfHeader(buf)->e_machine == _machine);
+ }
+
+ std::error_code
+ loadFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &,
+ std::vector<std::unique_ptr<File>> &result) const override {
+ std::size_t maxAlignment =
+ 1ULL << llvm::countTrailingZeros(uintptr_t(mb->getBufferStart()));
+ auto f =
+ createELF<ELFTraitsT>(llvm::object::getElfArchType(mb->getBuffer()),
+ maxAlignment, std::move(mb), _ctx);
+ if (std::error_code ec = f.getError())
+ return ec;
+ result.push_back(std::move(*f));
+ return std::error_code();
+ }
+
+ const Elf_Ehdr *elfHeader(const MemoryBuffer &buf) const {
+ const uint8_t *data =
+ reinterpret_cast<const uint8_t *>(buf.getBuffer().data());
+ return (reinterpret_cast<const Elf_Ehdr *>(data));
+ }
+
+protected:
+ ContextT &_ctx;
+ uint64_t _machine;
+};
+
+template <typename ELFT, typename ELFTraitsT, typename ContextT>
+class ELFDSOReader : public Reader {
+public:
+ typedef llvm::object::Elf_Ehdr_Impl<ELFT> Elf_Ehdr;
+
+ ELFDSOReader(ContextT &ctx, uint64_t machine)
+ : _ctx(ctx), _machine(machine) {}
+
+ bool canParse(file_magic magic, StringRef,
+ const MemoryBuffer &buf) const override {
+ return (magic == llvm::sys::fs::file_magic::elf_shared_object &&
+ elfHeader(buf)->e_machine == _machine);
+ }
+
+ std::error_code
+ loadFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &,
+ std::vector<std::unique_ptr<File>> &result) const override {
+ std::size_t maxAlignment =
+ 1ULL << llvm::countTrailingZeros(uintptr_t(mb->getBufferStart()));
+ auto f =
+ createELF<ELFTraitsT>(llvm::object::getElfArchType(mb->getBuffer()),
+ maxAlignment, std::move(mb), _ctx);
+ if (std::error_code ec = f.getError())
+ return ec;
+ result.push_back(std::move(*f));
+ return std::error_code();
+ }
+
+ const Elf_Ehdr *elfHeader(const MemoryBuffer &buf) const {
+ const uint8_t *data =
+ reinterpret_cast<const uint8_t *>(buf.getBuffer().data());
+ return (reinterpret_cast<const Elf_Ehdr *>(data));
+ }
+
+protected:
+ ContextT &_ctx;
+ uint64_t _machine;
+};
+
+} // namespace elf
+} // namespace lld
+
+#endif // LLD_READER_WRITER_ELF_READER_H
diff --git a/lib/ReaderWriter/ELF/ExecutableWriter.h b/lib/ReaderWriter/ELF/ExecutableWriter.h
new file mode 100644
index 0000000000000..477e3920abaee
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ExecutableWriter.h
@@ -0,0 +1,182 @@
+//===- lib/ReaderWriter/ELF/ExecutableWriter.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_EXECUTABLE_WRITER_H
+#define LLD_READER_WRITER_ELF_EXECUTABLE_WRITER_H
+
+#include "OutputELFWriter.h"
+
+namespace lld {
+namespace elf {
+using namespace llvm;
+using namespace llvm::object;
+
+template<class ELFT>
+class ExecutableWriter;
+
+//===----------------------------------------------------------------------===//
+// ExecutableWriter Class
+//===----------------------------------------------------------------------===//
+template<class ELFT>
+class ExecutableWriter : public OutputELFWriter<ELFT> {
+public:
+ ExecutableWriter(ELFLinkingContext &context, TargetLayout<ELFT> &layout)
+ : OutputELFWriter<ELFT>(context, layout),
+ _runtimeFile(new RuntimeFile<ELFT>(context, "C runtime")) {}
+
+protected:
+ virtual void buildDynamicSymbolTable(const File &file);
+ virtual void addDefaultAtoms();
+ virtual bool createImplicitFiles(std::vector<std::unique_ptr<File> > &);
+ virtual void finalizeDefaultAtomValues();
+ virtual void createDefaultSections();
+
+ virtual bool isNeededTagRequired(const SharedLibraryAtom *sla) const {
+ return this->_layout.isCopied(sla);
+ }
+
+ unique_bump_ptr<InterpSection<ELFT>> _interpSection;
+ std::unique_ptr<RuntimeFile<ELFT> > _runtimeFile;
+};
+
+//===----------------------------------------------------------------------===//
+// ExecutableWriter
+//===----------------------------------------------------------------------===//
+template<class ELFT>
+void ExecutableWriter<ELFT>::buildDynamicSymbolTable(const File &file) {
+ for (auto sec : this->_layout.sections())
+ if (auto section = dyn_cast<AtomSection<ELFT>>(sec))
+ for (const auto &atom : section->atoms()) {
+ const DefinedAtom *da = dyn_cast<const DefinedAtom>(atom->_atom);
+ if (!da)
+ continue;
+ if (da->dynamicExport() != DefinedAtom::dynamicExportAlways &&
+ !this->_context.isDynamicallyExportedSymbol(da->name()) &&
+ !(this->_context.shouldExportDynamic() &&
+ da->scope() == Atom::Scope::scopeGlobal))
+ continue;
+ this->_dynamicSymbolTable->addSymbol(atom->_atom, section->ordinal(),
+ atom->_virtualAddr, atom);
+ }
+
+ // Put weak symbols in the dynamic symbol table.
+ if (this->_context.isDynamic()) {
+ for (const UndefinedAtom *a : file.undefined()) {
+ if (this->_layout.isReferencedByDefinedAtom(a) &&
+ a->canBeNull() != UndefinedAtom::canBeNullNever)
+ this->_dynamicSymbolTable->addSymbol(a, ELF::SHN_UNDEF);
+ }
+ }
+
+ OutputELFWriter<ELFT>::buildDynamicSymbolTable(file);
+}
+
+/// \brief Add absolute symbols by default. These are linker added
+/// absolute symbols
+template<class ELFT>
+void ExecutableWriter<ELFT>::addDefaultAtoms() {
+ OutputELFWriter<ELFT>::addDefaultAtoms();
+ _runtimeFile->addUndefinedAtom(this->_context.entrySymbolName());
+ _runtimeFile->addAbsoluteAtom("__bss_start");
+ _runtimeFile->addAbsoluteAtom("__bss_end");
+ _runtimeFile->addAbsoluteAtom("_end");
+ _runtimeFile->addAbsoluteAtom("end");
+ _runtimeFile->addAbsoluteAtom("__preinit_array_start");
+ _runtimeFile->addAbsoluteAtom("__preinit_array_end");
+ _runtimeFile->addAbsoluteAtom("__init_array_start");
+ _runtimeFile->addAbsoluteAtom("__init_array_end");
+ if (this->_context.isRelaOutputFormat()) {
+ _runtimeFile->addAbsoluteAtom("__rela_iplt_start");
+ _runtimeFile->addAbsoluteAtom("__rela_iplt_end");
+ } else {
+ _runtimeFile->addAbsoluteAtom("__rel_iplt_start");
+ _runtimeFile->addAbsoluteAtom("__rel_iplt_end");
+ }
+ _runtimeFile->addAbsoluteAtom("__fini_array_start");
+ _runtimeFile->addAbsoluteAtom("__fini_array_end");
+}
+
+/// \brief Hook in lld to add CRuntime file
+template <class ELFT>
+bool ExecutableWriter<ELFT>::createImplicitFiles(
+ std::vector<std::unique_ptr<File> > &result) {
+ // Add the default atoms as defined by executables
+ ExecutableWriter<ELFT>::addDefaultAtoms();
+ OutputELFWriter<ELFT>::createImplicitFiles(result);
+ result.push_back(std::move(_runtimeFile));
+ return true;
+}
+
+template <class ELFT> void ExecutableWriter<ELFT>::createDefaultSections() {
+ OutputELFWriter<ELFT>::createDefaultSections();
+ if (this->_context.isDynamic()) {
+ _interpSection.reset(new (this->_alloc) InterpSection<ELFT>(
+ this->_context, ".interp", DefaultLayout<ELFT>::ORDER_INTERP,
+ this->_context.getInterpreter()));
+ this->_layout.addSection(_interpSection.get());
+ }
+}
+
+/// Finalize the value of all the absolute symbols that we
+/// created
+template <class ELFT> void ExecutableWriter<ELFT>::finalizeDefaultAtomValues() {
+ OutputELFWriter<ELFT>::finalizeDefaultAtomValues();
+ auto bssStartAtomIter = this->_layout.findAbsoluteAtom("__bss_start");
+ auto bssEndAtomIter = this->_layout.findAbsoluteAtom("__bss_end");
+ auto underScoreEndAtomIter = this->_layout.findAbsoluteAtom("_end");
+ auto endAtomIter = this->_layout.findAbsoluteAtom("end");
+
+ auto startEnd = [&](StringRef sym, StringRef sec) -> void {
+ std::string start = ("__" + sym + "_start").str();
+ std::string end = ("__" + sym + "_end").str();
+ auto s = this->_layout.findAbsoluteAtom(start);
+ auto e = this->_layout.findAbsoluteAtom(end);
+ auto section = this->_layout.findOutputSection(sec);
+ if (section) {
+ (*s)->_virtualAddr = section->virtualAddr();
+ (*e)->_virtualAddr = section->virtualAddr() + section->memSize();
+ } else {
+ (*s)->_virtualAddr = 0;
+ (*e)->_virtualAddr = 0;
+ }
+ };
+
+ startEnd("preinit_array", ".preinit_array");
+ startEnd("init_array", ".init_array");
+ if (this->_context.isRelaOutputFormat())
+ startEnd("rela_iplt", ".rela.plt");
+ else
+ startEnd("rel_iplt", ".rel.plt");
+ startEnd("fini_array", ".fini_array");
+
+ assert(!(bssStartAtomIter == this->_layout.absoluteAtoms().end() ||
+ bssEndAtomIter == this->_layout.absoluteAtoms().end() ||
+ underScoreEndAtomIter == this->_layout.absoluteAtoms().end() ||
+ endAtomIter == this->_layout.absoluteAtoms().end()) &&
+ "Unable to find the absolute atoms that have been added by lld");
+
+ auto bssSection = this->_layout.findOutputSection(".bss");
+
+ // If we don't find a bss section, then don't set these values
+ if (bssSection) {
+ (*bssStartAtomIter)->_virtualAddr = bssSection->virtualAddr();
+ (*bssEndAtomIter)->_virtualAddr =
+ bssSection->virtualAddr() + bssSection->memSize();
+ (*underScoreEndAtomIter)->_virtualAddr = (*bssEndAtomIter)->_virtualAddr;
+ (*endAtomIter)->_virtualAddr = (*bssEndAtomIter)->_virtualAddr;
+ } else if (auto dataSection = this->_layout.findOutputSection(".data")) {
+ (*underScoreEndAtomIter)->_virtualAddr =
+ dataSection->virtualAddr() + dataSection->memSize();
+ (*endAtomIter)->_virtualAddr = (*underScoreEndAtomIter)->_virtualAddr;
+ }
+}
+
+} // namespace elf
+} // namespace lld
+
+#endif // LLD_READER_WRITER_ELF_EXECUTABLE_WRITER_H
diff --git a/lib/ReaderWriter/ELF/HeaderChunks.h b/lib/ReaderWriter/ELF/HeaderChunks.h
new file mode 100644
index 0000000000000..eab132b9b2f69
--- /dev/null
+++ b/lib/ReaderWriter/ELF/HeaderChunks.h
@@ -0,0 +1,364 @@
+//===- lib/ReaderWriter/ELF/HeaderChunks.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_HEADER_CHUNKS_H
+#define LLD_READER_WRITER_ELF_HEADER_CHUNKS_H
+
+#include "SegmentChunks.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ELF.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/Format.h"
+
+/// \brief An Header represents the Elf[32/64]_Ehdr structure at the
+/// start of an ELF executable file.
+namespace lld {
+namespace elf {
+template <class ELFT> class ELFHeader : public Chunk<ELFT> {
+public:
+ typedef llvm::object::Elf_Ehdr_Impl<ELFT> Elf_Ehdr;
+
+ ELFHeader(const ELFLinkingContext &);
+
+ void e_ident(int I, unsigned char C) { _eh.e_ident[I] = C; }
+ void e_type(uint16_t type) { _eh.e_type = type; }
+ void e_machine(uint16_t machine) { _eh.e_machine = machine; }
+ void e_version(uint32_t version) { _eh.e_version = version; }
+ void e_entry(int64_t entry) { _eh.e_entry = entry; }
+ void e_phoff(int64_t phoff) { _eh.e_phoff = phoff; }
+ void e_shoff(int64_t shoff) { _eh.e_shoff = shoff; }
+ void e_flags(uint32_t flags) { _eh.e_flags = flags; }
+ void e_ehsize(uint16_t ehsize) { _eh.e_ehsize = ehsize; }
+ void e_phentsize(uint16_t phentsize) { _eh.e_phentsize = phentsize; }
+ void e_phnum(uint16_t phnum) { _eh.e_phnum = phnum; }
+ void e_shentsize(uint16_t shentsize) { _eh.e_shentsize = shentsize; }
+ void e_shnum(uint16_t shnum) { _eh.e_shnum = shnum; }
+ void e_shstrndx(uint16_t shstrndx) { _eh.e_shstrndx = shstrndx; }
+ uint64_t fileSize() const { return sizeof(Elf_Ehdr); }
+
+ static bool classof(const Chunk<ELFT> *c) {
+ return c->Kind() == Chunk<ELFT>::Kind::ELFHeader;
+ }
+
+ int getContentType() const { return Chunk<ELFT>::ContentType::Header; }
+
+ void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
+ llvm::FileOutputBuffer &buffer);
+
+ virtual void doPreFlight() {}
+
+ void finalize() {
+ _eh.e_ident[llvm::ELF::EI_CLASS] =
+ (ELFT::Is64Bits) ? llvm::ELF::ELFCLASS64 : llvm::ELF::ELFCLASS32;
+ _eh.e_ident[llvm::ELF::EI_DATA] =
+ (ELFT::TargetEndianness == llvm::support::little)
+ ? llvm::ELF::ELFDATA2LSB
+ : llvm::ELF::ELFDATA2MSB;
+ _eh.e_type = this->_context.getOutputELFType();
+ _eh.e_machine = this->_context.getOutputMachine();
+ }
+
+private:
+ Elf_Ehdr _eh;
+};
+
+template <class ELFT>
+ELFHeader<ELFT>::ELFHeader(const ELFLinkingContext &context)
+ : Chunk<ELFT>("elfhdr", Chunk<ELFT>::Kind::ELFHeader, context) {
+ this->_alignment = ELFT::Is64Bits ? 8 : 4;
+ this->_fsize = sizeof(Elf_Ehdr);
+ this->_msize = sizeof(Elf_Ehdr);
+ memset(_eh.e_ident, 0, llvm::ELF::EI_NIDENT);
+ e_ident(llvm::ELF::EI_MAG0, 0x7f);
+ e_ident(llvm::ELF::EI_MAG1, 'E');
+ e_ident(llvm::ELF::EI_MAG2, 'L');
+ e_ident(llvm::ELF::EI_MAG3, 'F');
+ e_ehsize(sizeof(Elf_Ehdr));
+ e_flags(0);
+}
+
+template <class ELFT>
+void ELFHeader<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout,
+ llvm::FileOutputBuffer &buffer) {
+ uint8_t *chunkBuffer = buffer.getBufferStart();
+ uint8_t *atomContent = chunkBuffer + this->fileOffset();
+ memcpy(atomContent, &_eh, fileSize());
+}
+
+/// \brief An ProgramHeader represents the Elf[32/64]_Phdr structure at the
+/// start of an ELF executable file.
+template<class ELFT>
+class ProgramHeader : public Chunk<ELFT> {
+public:
+ typedef llvm::object::Elf_Phdr_Impl<ELFT> Elf_Phdr;
+ typedef typename std::vector<Elf_Phdr *>::iterator PhIterT;
+ typedef typename std::reverse_iterator<PhIterT> ReversePhIterT;
+
+ /// \brief Find a program header entry, given the type of entry that
+ /// we are looking for
+ class FindPhdr {
+ public:
+ FindPhdr(uint64_t type, uint64_t flags, uint64_t flagsClear)
+ : _type(type)
+ , _flags(flags)
+ , _flagsClear(flagsClear) {
+ }
+
+ bool operator()(const llvm::object::Elf_Phdr_Impl<ELFT> *j) const {
+ return ((j->p_type == _type) &&
+ ((j->p_flags & _flags) == _flags) &&
+ (!(j->p_flags & _flagsClear)));
+ }
+ private:
+ uint64_t _type;
+ uint64_t _flags;
+ uint64_t _flagsClear;
+ };
+
+ ProgramHeader(const ELFLinkingContext &context)
+ : Chunk<ELFT>("elfphdr", Chunk<ELFT>::Kind::ProgramHeader, context) {
+ this->_alignment = ELFT::Is64Bits ? 8 : 4;
+ resetProgramHeaders();
+ }
+
+ bool addSegment(Segment<ELFT> *segment);
+
+ void resetProgramHeaders() { _phi = _ph.begin(); }
+
+ uint64_t fileSize() const { return sizeof(Elf_Phdr) * _ph.size(); }
+
+ static bool classof(const Chunk<ELFT> *c) {
+ return c->Kind() == Chunk<ELFT>::Kind::ProgramHeader;
+ }
+
+ void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
+ llvm::FileOutputBuffer &buffer);
+
+ /// \brief find a program header entry in the list of program headers
+ ReversePhIterT
+ findProgramHeader(uint64_t type, uint64_t flags, uint64_t flagClear) {
+ return std::find_if(_ph.rbegin(), _ph.rend(),
+ FindPhdr(type, flags, flagClear));
+ }
+
+ PhIterT begin() {
+ return _ph.begin();
+ }
+
+ PhIterT end() {
+ return _ph.end();
+ }
+
+ ReversePhIterT rbegin() { return _ph.rbegin(); }
+
+ ReversePhIterT rend() { return _ph.rend(); }
+
+ virtual void doPreFlight() {}
+
+ void finalize() {}
+
+ int64_t entsize() { return sizeof(Elf_Phdr); }
+
+ int64_t numHeaders() {
+ return _ph.size();
+ }
+
+ int getContentType() const { return Chunk<ELFT>::ContentType::Header; }
+
+private:
+ Elf_Phdr *allocateProgramHeader(bool &allocatedNew) {
+ Elf_Phdr *phdr;
+ if (_phi == _ph.end()) {
+ phdr = new (_allocator) Elf_Phdr;
+ _ph.push_back(phdr);
+ _phi = _ph.end();
+ allocatedNew = true;
+ } else {
+ phdr = (*_phi);
+ ++_phi;
+ }
+ return phdr;
+ }
+
+ std::vector<Elf_Phdr *> _ph;
+ PhIterT _phi;
+ llvm::BumpPtrAllocator _allocator;
+};
+
+template <class ELFT>
+bool ProgramHeader<ELFT>::addSegment(Segment<ELFT> *segment) {
+ bool allocatedNew = false;
+ ELFLinkingContext::OutputMagic outputMagic = this->_context.getOutputMagic();
+ // For segments that are not a loadable segment, we
+ // just pick the values directly from the segment as there
+ // wouldnt be any slices within that
+ if (segment->segmentType() != llvm::ELF::PT_LOAD) {
+ Elf_Phdr *phdr = allocateProgramHeader(allocatedNew);
+ phdr->p_type = segment->segmentType();
+ phdr->p_offset = segment->fileOffset();
+ phdr->p_vaddr = segment->virtualAddr();
+ phdr->p_paddr = segment->virtualAddr();
+ phdr->p_filesz = segment->fileSize();
+ phdr->p_memsz = segment->memSize();
+ phdr->p_flags = segment->flags();
+ phdr->p_align = segment->alignment();
+ this->_fsize = fileSize();
+ this->_msize = this->_fsize;
+ return allocatedNew;
+ }
+ // For all other segments, use the slice
+ // to derive program headers
+ for (auto slice : segment->slices()) {
+ Elf_Phdr *phdr = allocateProgramHeader(allocatedNew);
+ phdr->p_type = segment->segmentType();
+ phdr->p_offset = slice->fileOffset();
+ phdr->p_vaddr = slice->virtualAddr();
+ phdr->p_paddr = slice->virtualAddr();
+ phdr->p_filesz = slice->fileSize();
+ phdr->p_memsz = slice->memSize();
+ phdr->p_flags = segment->flags();
+ phdr->p_align = slice->alignment();
+ uint64_t segPageSize = segment->pageSize();
+ uint64_t sliceAlign = slice->alignment();
+ // Alignment of PT_LOAD segments are set to the page size, but if the
+ // alignment of the slice is greater than the page size, set the alignment
+ // of the segment appropriately.
+ if (outputMagic != ELFLinkingContext::OutputMagic::NMAGIC &&
+ outputMagic != ELFLinkingContext::OutputMagic::OMAGIC) {
+ phdr->p_align = (phdr->p_type == llvm::ELF::PT_LOAD)
+ ? (segPageSize < sliceAlign) ? sliceAlign : segPageSize
+ : sliceAlign;
+ } else
+ phdr->p_align = slice->alignment();
+ }
+ this->_fsize = fileSize();
+ this->_msize = this->_fsize;
+
+ return allocatedNew;
+}
+
+template <class ELFT>
+void ProgramHeader<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout,
+ llvm::FileOutputBuffer &buffer) {
+ uint8_t *chunkBuffer = buffer.getBufferStart();
+ uint8_t *dest = chunkBuffer + this->fileOffset();
+ for (auto phi : _ph) {
+ memcpy(dest, phi, sizeof(Elf_Phdr));
+ dest += sizeof(Elf_Phdr);
+ }
+}
+
+/// \brief An SectionHeader represents the Elf[32/64]_Shdr structure
+/// at the end of the file
+template<class ELFT>
+class SectionHeader : public Chunk<ELFT> {
+public:
+ typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr;
+
+ SectionHeader(const ELFLinkingContext &, int32_t order);
+
+ void appendSection(OutputSection<ELFT> *section);
+
+ void updateSection(Section<ELFT> *section);
+
+ static bool classof(const Chunk<ELFT> *c) {
+ return c->getChunkKind() == Chunk<ELFT>::Kind::SectionHeader;
+ }
+
+ void setStringSection(StringTable<ELFT> *s) {
+ _stringSection = s;
+ }
+
+ void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
+ llvm::FileOutputBuffer &buffer);
+
+ virtual void doPreFlight() {}
+
+ void finalize() {}
+
+ uint64_t fileSize() const { return sizeof(Elf_Shdr) * _sectionInfo.size(); }
+
+ uint64_t entsize() { return sizeof(Elf_Shdr); }
+
+ int getContentType() const { return Chunk<ELFT>::ContentType::Header; }
+
+ uint64_t numHeaders() { return _sectionInfo.size(); }
+
+private:
+ StringTable<ELFT> *_stringSection;
+ std::vector<Elf_Shdr*> _sectionInfo;
+ llvm::BumpPtrAllocator _sectionAllocate;
+};
+
+template <class ELFT>
+SectionHeader<ELFT>::SectionHeader(const ELFLinkingContext &context,
+ int32_t order)
+ : Chunk<ELFT>("shdr", Chunk<ELFT>::Kind::SectionHeader, context) {
+ this->_fsize = 0;
+ this->_alignment = 8;
+ this->setOrder(order);
+ // The first element in the list is always NULL
+ Elf_Shdr *nullshdr = new (_sectionAllocate.Allocate<Elf_Shdr>()) Elf_Shdr;
+ ::memset(nullshdr, 0, sizeof (Elf_Shdr));
+ _sectionInfo.push_back(nullshdr);
+ this->_fsize += sizeof (Elf_Shdr);
+}
+
+template <class ELFT>
+void SectionHeader<ELFT>::appendSection(OutputSection<ELFT> *section) {
+ Elf_Shdr *shdr = new (_sectionAllocate.Allocate<Elf_Shdr>()) Elf_Shdr;
+ shdr->sh_name = _stringSection->addString(section->name());
+ shdr->sh_type = section->type();
+ shdr->sh_flags = section->flags();
+ shdr->sh_offset = section->fileOffset();
+ shdr->sh_addr = section->virtualAddr();
+ if (section->isLoadableSection())
+ shdr->sh_size = section->memSize();
+ else
+ shdr->sh_size = section->fileSize();
+ shdr->sh_link = section->link();
+ shdr->sh_info = section->shinfo();
+ shdr->sh_addralign = section->alignment();
+ shdr->sh_entsize = section->entsize();
+ _sectionInfo.push_back(shdr);
+}
+
+template<class ELFT>
+void
+SectionHeader<ELFT>::updateSection(Section<ELFT> *section) {
+ Elf_Shdr *shdr = _sectionInfo[section->ordinal()];
+ shdr->sh_type = section->getType();
+ shdr->sh_flags = section->getFlags();
+ shdr->sh_offset = section->fileOffset();
+ shdr->sh_addr = section->virtualAddr();
+ shdr->sh_size = section->fileSize();
+ shdr->sh_link = section->getLink();
+ shdr->sh_info = section->getInfo();
+ shdr->sh_addralign = section->alignment();
+ shdr->sh_entsize = section->getEntSize();
+}
+
+template <class ELFT>
+void SectionHeader<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout,
+ llvm::FileOutputBuffer &buffer) {
+ uint8_t *chunkBuffer = buffer.getBufferStart();
+ uint8_t *dest = chunkBuffer + this->fileOffset();
+ for (auto shi : _sectionInfo) {
+ memcpy(dest, shi, sizeof(Elf_Shdr));
+ dest += sizeof(Elf_Shdr);
+ }
+ _stringSection->write(writer, layout, buffer);
+}
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/Hexagon/CMakeLists.txt b/lib/ReaderWriter/ELF/Hexagon/CMakeLists.txt
new file mode 100644
index 0000000000000..6928f43c54592
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Hexagon/CMakeLists.txt
@@ -0,0 +1,11 @@
+add_llvm_library(lldHexagonELFTarget
+ HexagonLinkingContext.cpp
+ HexagonRelocationHandler.cpp
+ HexagonTargetHandler.cpp
+ LINK_LIBS
+ lldELF
+ lldReaderWriter
+ lldCore
+ LLVMObject
+ LLVMSupport
+ )
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonDynamicLibraryWriter.h b/lib/ReaderWriter/ELF/Hexagon/HexagonDynamicLibraryWriter.h
new file mode 100644
index 0000000000000..e2d3193045b75
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Hexagon/HexagonDynamicLibraryWriter.h
@@ -0,0 +1,79 @@
+//===- lib/ReaderWriter/ELF/Hexagon/HexagonDynamicLibraryWriter.h ---------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef HEXAGON_DYNAMIC_LIBRARY_WRITER_H
+#define HEXAGON_DYNAMIC_LIBRARY_WRITER_H
+
+#include "DynamicLibraryWriter.h"
+#include "HexagonExecutableAtoms.h"
+#include "HexagonLinkingContext.h"
+
+namespace lld {
+namespace elf {
+
+template <typename ELFT> class HexagonTargetLayout;
+
+template <class ELFT>
+class HexagonDynamicLibraryWriter : public DynamicLibraryWriter<ELFT>,
+ public HexagonELFWriter<ELFT> {
+public:
+ HexagonDynamicLibraryWriter(HexagonLinkingContext &context,
+ HexagonTargetLayout<ELFT> &layout);
+
+protected:
+ // Add any runtime files and their atoms to the output
+ virtual bool createImplicitFiles(std::vector<std::unique_ptr<File>> &);
+
+ virtual void finalizeDefaultAtomValues();
+
+ virtual std::error_code setELFHeader() {
+ DynamicLibraryWriter<ELFT>::setELFHeader();
+ HexagonELFWriter<ELFT>::setELFHeader(*this->_elfHeader);
+ return std::error_code();
+ }
+
+private:
+ void addDefaultAtoms() {
+ _hexagonRuntimeFile->addAbsoluteAtom("_GLOBAL_OFFSET_TABLE_");
+ _hexagonRuntimeFile->addAbsoluteAtom("_DYNAMIC");
+ }
+
+ HexagonLinkingContext &_hexagonLinkingContext;
+ HexagonTargetLayout<ELFT> &_hexagonTargetLayout;
+ std::unique_ptr<HexagonRuntimeFile<ELFT>> _hexagonRuntimeFile;
+};
+
+template <class ELFT>
+HexagonDynamicLibraryWriter<ELFT>::HexagonDynamicLibraryWriter(
+ HexagonLinkingContext &context, HexagonTargetLayout<ELFT> &layout)
+ : DynamicLibraryWriter<ELFT>(context, layout),
+ HexagonELFWriter<ELFT>(context, layout), _hexagonLinkingContext(context),
+ _hexagonTargetLayout(layout),
+ _hexagonRuntimeFile(new HexagonRuntimeFile<ELFT>(context)) {}
+
+template <class ELFT>
+bool HexagonDynamicLibraryWriter<ELFT>::createImplicitFiles(
+ std::vector<std::unique_ptr<File>> &result) {
+ DynamicLibraryWriter<ELFT>::createImplicitFiles(result);
+ // Add the default atoms as defined for hexagon
+ addDefaultAtoms();
+ result.push_back(std::move(_hexagonRuntimeFile));
+ return true;
+}
+
+template <class ELFT>
+void HexagonDynamicLibraryWriter<ELFT>::finalizeDefaultAtomValues() {
+ // Finalize the atom values that are part of the parent.
+ DynamicLibraryWriter<ELFT>::finalizeDefaultAtomValues();
+ HexagonELFWriter<ELFT>::finalizeHexagonRuntimeAtomValues();
+}
+
+} // namespace elf
+} // namespace lld
+
+#endif // HEXAGON_DYNAMIC_LIBRARY_WRITER_H
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonELFFile.h b/lib/ReaderWriter/ELF/Hexagon/HexagonELFFile.h
new file mode 100644
index 0000000000000..ab0b9b432b430
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Hexagon/HexagonELFFile.h
@@ -0,0 +1,170 @@
+//===- lib/ReaderWriter/ELF/HexagonELFFile.h ------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_HEXAGON_ELF_FILE_H
+#define LLD_READER_WRITER_ELF_HEXAGON_ELF_FILE_H
+
+#include "ELFReader.h"
+#include "HexagonLinkingContext.h"
+
+namespace lld {
+namespace elf {
+
+template <class ELFT> class HexagonELFFile;
+
+template <class ELFT>
+class HexagonELFDefinedAtom : public ELFDefinedAtom<ELFT> {
+ typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+ typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr;
+
+public:
+ HexagonELFDefinedAtom(const HexagonELFFile<ELFT> &file, StringRef symbolName,
+ StringRef sectionName, const Elf_Sym *symbol,
+ const Elf_Shdr *section, ArrayRef<uint8_t> contentData,
+ unsigned int referenceStart, unsigned int referenceEnd,
+ std::vector<ELFReference<ELFT> *> &referenceList)
+ : ELFDefinedAtom<ELFT>(file, symbolName, sectionName, symbol, section,
+ contentData, referenceStart, referenceEnd,
+ referenceList) {}
+
+ virtual DefinedAtom::ContentType contentType() const {
+ if (this->_contentType != DefinedAtom::typeUnknown)
+ return this->_contentType;
+ else if (this->_section->sh_flags & llvm::ELF::SHF_HEX_GPREL) {
+ if (this->_section->sh_type == llvm::ELF::SHT_NOBITS)
+ return (this->_contentType = DefinedAtom::typeZeroFillFast);
+ else
+ return (this->_contentType = DefinedAtom::typeDataFast);
+ }
+ return ELFDefinedAtom<ELFT>::contentType();
+ }
+
+ virtual DefinedAtom::ContentPermissions permissions() const {
+ if (this->_section->sh_flags & llvm::ELF::SHF_HEX_GPREL)
+ return DefinedAtom::permRW_;
+ return ELFDefinedAtom<ELFT>::permissions();
+ }
+};
+
+template <class ELFT> class HexagonELFCommonAtom : public ELFCommonAtom<ELFT> {
+ typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+ typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr;
+
+public:
+ HexagonELFCommonAtom(const HexagonELFFile<ELFT> &file, StringRef symbolName,
+ const Elf_Sym *symbol)
+ : ELFCommonAtom<ELFT>(file, symbolName, symbol) {}
+
+ virtual bool isSmallCommonSymbol() const {
+ switch (this->_symbol->st_shndx) {
+ // Common symbols
+ case llvm::ELF::SHN_HEXAGON_SCOMMON:
+ case llvm::ELF::SHN_HEXAGON_SCOMMON_1:
+ case llvm::ELF::SHN_HEXAGON_SCOMMON_2:
+ case llvm::ELF::SHN_HEXAGON_SCOMMON_4:
+ case llvm::ELF::SHN_HEXAGON_SCOMMON_8:
+ return true;
+ default:
+ break;
+ }
+ return false;
+ }
+
+ virtual uint64_t size() const {
+ if (isSmallCommonSymbol())
+ return this->_symbol->st_size;
+ return ELFCommonAtom<ELFT>::size();
+ }
+
+ virtual DefinedAtom::Merge merge() const {
+ if (this->_symbol->getBinding() == llvm::ELF::STB_WEAK)
+ return DefinedAtom::mergeAsWeak;
+ if (isSmallCommonSymbol())
+ return DefinedAtom::mergeAsTentative;
+ return ELFCommonAtom<ELFT>::merge();
+ }
+
+ virtual DefinedAtom::ContentType contentType() const {
+ if (isSmallCommonSymbol())
+ return DefinedAtom::typeZeroFillFast;
+ return ELFCommonAtom<ELFT>::contentType();
+ }
+
+ virtual DefinedAtom::Alignment alignment() const {
+ if (isSmallCommonSymbol())
+ return DefinedAtom::Alignment(llvm::Log2_64(this->_symbol->st_value));
+ return ELFCommonAtom<ELFT>::alignment();
+ }
+
+ virtual DefinedAtom::ContentPermissions permissions() const {
+ if (isSmallCommonSymbol())
+ return DefinedAtom::permRW_;
+ return ELFCommonAtom<ELFT>::permissions();
+ }
+};
+
+template <class ELFT> class HexagonELFFile : public ELFFile<ELFT> {
+ typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+ typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr;
+
+public:
+ HexagonELFFile(std::unique_ptr<MemoryBuffer> mb, HexagonLinkingContext &ctx)
+ : ELFFile<ELFT>(std::move(mb), ctx) {}
+
+ static ErrorOr<std::unique_ptr<HexagonELFFile>>
+ create(std::unique_ptr<MemoryBuffer> mb, HexagonLinkingContext &ctx) {
+ return std::unique_ptr<HexagonELFFile<ELFT>>(
+ new HexagonELFFile<ELFT>(std::move(mb), ctx));
+ }
+
+ bool isCommonSymbol(const Elf_Sym *symbol) const override {
+ switch (symbol->st_shndx) {
+ // Common symbols
+ case llvm::ELF::SHN_HEXAGON_SCOMMON:
+ case llvm::ELF::SHN_HEXAGON_SCOMMON_1:
+ case llvm::ELF::SHN_HEXAGON_SCOMMON_2:
+ case llvm::ELF::SHN_HEXAGON_SCOMMON_4:
+ case llvm::ELF::SHN_HEXAGON_SCOMMON_8:
+ return true;
+ default:
+ break;
+ }
+ return ELFFile<ELFT>::isCommonSymbol(symbol);
+ }
+
+ /// Process the Defined symbol and create an atom for it.
+ ErrorOr<ELFDefinedAtom<ELFT> *>
+ handleDefinedSymbol(StringRef symName, StringRef sectionName,
+ const Elf_Sym *sym, const Elf_Shdr *sectionHdr,
+ ArrayRef<uint8_t> contentData,
+ unsigned int referenceStart, unsigned int referenceEnd,
+ std::vector<ELFReference<ELFT> *> &referenceList) override {
+ return new (this->_readerStorage) HexagonELFDefinedAtom<ELFT>(
+ *this, symName, sectionName, sym, sectionHdr, contentData,
+ referenceStart, referenceEnd, referenceList);
+ }
+
+ /// Process the Common symbol and create an atom for it.
+ ErrorOr<ELFCommonAtom<ELFT> *>
+ handleCommonSymbol(StringRef symName, const Elf_Sym *sym) override {
+ return new (this->_readerStorage)
+ HexagonELFCommonAtom<ELFT>(*this, symName, sym);
+ }
+};
+
+template <class ELFT> class HexagonDynamicFile : public DynamicFile<ELFT> {
+public:
+ HexagonDynamicFile(const HexagonLinkingContext &context, StringRef name)
+ : DynamicFile<ELFT>(context, name) {}
+};
+
+} // elf
+} // lld
+
+#endif // LLD_READER_WRITER_ELF_HEXAGON_ELF_FILE_H
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonELFReader.h b/lib/ReaderWriter/ELF/Hexagon/HexagonELFReader.h
new file mode 100644
index 0000000000000..1a4f891df7997
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Hexagon/HexagonELFReader.h
@@ -0,0 +1,62 @@
+//===- lib/ReaderWriter/ELF/HexagonELFReader.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_HEXAGON_ELF_READER_H
+#define LLD_READER_WRITER_HEXAGON_ELF_READER_H
+
+#include "ELFReader.h"
+#include "HexagonELFFile.h"
+
+namespace lld {
+namespace elf {
+
+typedef llvm::object::ELFType<llvm::support::little, 2, false> HexagonELFType;
+
+struct HexagonDynamicFileCreateELFTraits {
+ typedef llvm::ErrorOr<std::unique_ptr<lld::SharedLibraryFile>> result_type;
+
+ template <class ELFT>
+ static result_type create(std::unique_ptr<llvm::MemoryBuffer> mb,
+ HexagonLinkingContext &ctx) {
+ return lld::elf::HexagonDynamicFile<ELFT>::create(std::move(mb), ctx);
+ }
+};
+
+struct HexagonELFFileCreateELFTraits {
+ typedef llvm::ErrorOr<std::unique_ptr<lld::File>> result_type;
+
+ template <class ELFT>
+ static result_type create(std::unique_ptr<llvm::MemoryBuffer> mb,
+ HexagonLinkingContext &ctx) {
+ return lld::elf::HexagonELFFile<ELFT>::create(std::move(mb), ctx);
+ }
+};
+
+class HexagonELFObjectReader
+ : public ELFObjectReader<HexagonELFType, HexagonELFFileCreateELFTraits,
+ HexagonLinkingContext> {
+public:
+ HexagonELFObjectReader(HexagonLinkingContext &ctx)
+ : ELFObjectReader<HexagonELFType, HexagonELFFileCreateELFTraits,
+ HexagonLinkingContext>(ctx, llvm::ELF::EM_HEXAGON) {}
+};
+
+class HexagonELFDSOReader
+ : public ELFDSOReader<HexagonELFType, HexagonDynamicFileCreateELFTraits,
+ HexagonLinkingContext> {
+public:
+ HexagonELFDSOReader(HexagonLinkingContext &ctx)
+ : ELFDSOReader<HexagonELFType, HexagonDynamicFileCreateELFTraits,
+ HexagonLinkingContext>(ctx, llvm::ELF::EM_HEXAGON) {}
+};
+
+} // namespace elf
+} // namespace lld
+
+#endif // LLD_READER_WRITER_ELF_READER_H
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonELFWriters.h b/lib/ReaderWriter/ELF/Hexagon/HexagonELFWriters.h
new file mode 100644
index 0000000000000..96c74f72222dc
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Hexagon/HexagonELFWriters.h
@@ -0,0 +1,61 @@
+//===- lib/ReaderWriter/ELF/Hexagon/HexagonELFWriters.h -------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef HEXAGON_ELF_WRITERS_H
+#define HEXAGON_ELF_WRITERS_H
+
+#include "HexagonLinkingContext.h"
+#include "OutputELFWriter.h"
+
+namespace lld {
+namespace elf {
+
+template <class ELFT> class HexagonTargetLayout;
+
+template <typename ELFT> class HexagonELFWriter {
+public:
+ HexagonELFWriter(HexagonLinkingContext &context,
+ HexagonTargetLayout<ELFT> &targetLayout)
+ : _hexagonLinkingContext(context), _hexagonTargetLayout(targetLayout) {}
+
+protected:
+ bool setELFHeader(ELFHeader<ELFT> &elfHeader) {
+ elfHeader.e_ident(llvm::ELF::EI_VERSION, 1);
+ elfHeader.e_ident(llvm::ELF::EI_OSABI, 0);
+ elfHeader.e_version(1);
+ elfHeader.e_flags(0x3);
+ return true;
+ }
+
+ void finalizeHexagonRuntimeAtomValues() {
+ if (_hexagonLinkingContext.isDynamic()) {
+ auto gotAtomIter =
+ _hexagonTargetLayout.findAbsoluteAtom("_GLOBAL_OFFSET_TABLE_");
+ auto gotpltSection = _hexagonTargetLayout.findOutputSection(".got.plt");
+ if (gotpltSection)
+ (*gotAtomIter)->_virtualAddr = gotpltSection->virtualAddr();
+ else
+ (*gotAtomIter)->_virtualAddr = 0;
+ auto dynamicAtomIter = _hexagonTargetLayout.findAbsoluteAtom("_DYNAMIC");
+ auto dynamicSection = _hexagonTargetLayout.findOutputSection(".dynamic");
+ if (dynamicSection)
+ (*dynamicAtomIter)->_virtualAddr = dynamicSection->virtualAddr();
+ else
+ (*dynamicAtomIter)->_virtualAddr = 0;
+ }
+ }
+
+private:
+ HexagonLinkingContext &_hexagonLinkingContext;
+ HexagonTargetLayout<ELFT> &_hexagonTargetLayout;
+};
+
+} // elf
+} // lld
+#endif // HEXAGON_ELF_WRITERS_H
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonEncodings.h b/lib/ReaderWriter/ELF/Hexagon/HexagonEncodings.h
new file mode 100644
index 0000000000000..3e12786704a25
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Hexagon/HexagonEncodings.h
@@ -0,0 +1,601 @@
+//===- lib/ReaderWriter/ELF/Hexagon/HexagonEncodings.h -------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+Instruction insn_encodings[] = {
+ { 0xffe00004, 0x40000000, 0x20f8, 0x0 },
+ { 0xffe03080, 0x9ca03080, 0xf60, 0x0 },
+ { 0xf9e00000, 0x48c00000, 0x61f20ff, 0x0 },
+ { 0xf7c02300, 0x13802100, 0x3000fe, 0x0 },
+ { 0xffe00000, 0x60c00000, 0x1f18, 0x0 },
+ { 0xffe00000, 0x69c00000, 0x1f18, 0x0 },
+ { 0xffe02000, 0x43000000, 0x7e0, 0x0 },
+ { 0xff602060, 0x3e000060, 0x1f80, 0x0 },
+ { 0xffe03000, 0x9ae01000, 0xf60, 0x0 },
+ { 0xf9e00000, 0x91600000, 0x6003fe0, 0x0 },
+ { 0xffe02084, 0xaf000084, 0x30078, 0x0 },
+ { 0xff602060, 0x3e000020, 0x1f80, 0x0 },
+ { 0xff602060, 0x3e200040, 0x1f80, 0x0 },
+ { 0xf7c02000, 0x10c02000, 0x3000fe, 0x0 },
+ { 0xffe00000, 0x60200000, 0x1f18, 0x0 },
+ { 0xffe00000, 0x69200000, 0x1f18, 0x0 },
+ { 0xffe038c0, 0xada00880, 0x3f, 0x0 },
+ { 0xff602000, 0x73002000, 0x1fe0, 0x0 },
+ { 0xf7c02000, 0x26c02000, 0x3000fe, 0x0 },
+ { 0xffe03880, 0x9f403880, 0x1f0100, 0x0 },
+ { 0xf9e00000, 0x48400000, 0x61f20ff, 0x0 },
+ { 0xffe02000, 0x41600000, 0x7e0, 0x0 },
+ { 0xffe02084, 0xaf000080, 0x30078, 0x0 },
+ { 0xf7c02300, 0x13800100, 0x3000fe, 0x0 },
+ { 0xffe01804, 0x46a00000, 0x20f8, 0x0 },
+ { 0xffe00004, 0x42400000, 0x20f8, 0x0 },
+ { 0xf7c02000, 0x22400000, 0x3000fe, 0x0 },
+ { 0xf7c02000, 0x12402000, 0x3000fe, 0x0 },
+ { 0xfc003d18, 0x28003c18, 0x3f00000, 0x1 },
+ { 0xffe00000, 0x39000000, 0x201f, 0x0 },
+ { 0xff601018, 0xdd400008, 0xfe0, 0x0 },
+ { 0xffc0001c, 0x75400000, 0x203fe0, 0x0 },
+ { 0xfc003fc7, 0x48003f47, 0x3f00000, 0x1 },
+ { 0xffe03080, 0x9ca03000, 0xf60, 0x0 },
+ { 0xf9e00000, 0x90800000, 0x6003fe0, 0x0 },
+ { 0xf8003fc7, 0x40003fc4, 0x7f00000, 0x1 },
+ { 0xfc003e00, 0x68003c00, 0x3f00000, 0x1 },
+ { 0xf8003fc7, 0x40003fc5, 0x7f00000, 0x1 },
+ { 0xf9e00000, 0x91800000, 0x6003fe0, 0x0 },
+ { 0xff602060, 0x3e400060, 0x1f80, 0x0 },
+ { 0xff602060, 0x3e000000, 0x1f80, 0x0 },
+ { 0xf8003d18, 0x20003c18, 0x7f00000, 0x1 },
+ { 0xf8003f00, 0x20003800, 0x7f00000, 0x1 },
+ { 0xf8003d18, 0x20003c10, 0x7f00000, 0x1 },
+ { 0xff602000, 0x73602000, 0x1fe0, 0x0 },
+ { 0xffe03880, 0x9f002080, 0x1f0100, 0x0 },
+ { 0xffe02000, 0x47000000, 0x7e0, 0x0 },
+ { 0xf9e00000, 0x91400000, 0x6003fe0, 0x0 },
+ { 0xffe02080, 0xabc00080, 0x3f, 0x0 },
+ { 0xf7c02000, 0x20802000, 0x3000fe, 0x0 },
+ { 0xf8003fc7, 0x40003f44, 0x7f00000, 0x1 },
+ { 0xffe03884, 0xafa03084, 0x30078, 0x0 },
+ { 0xffe03000, 0x9b001000, 0xf60, 0x0 },
+ { 0xffe01804, 0x42a00800, 0x20f8, 0x0 },
+ { 0xfc003f00, 0x28003100, 0x3f00000, 0x1 },
+ { 0xffe02080, 0xab800080, 0x3f, 0x0 },
+ { 0xf7c02000, 0x24c00000, 0x3000fe, 0x0 },
+ { 0xffe00000, 0x39a00000, 0x201f, 0x0 },
+ { 0xf7c02300, 0x13802300, 0x3000fe, 0x0 },
+ { 0xffe01804, 0x46a00800, 0x20f8, 0x0 },
+ { 0xffe020c0, 0xad602080, 0x3f, 0x0 },
+ { 0xfc003f00, 0x28003500, 0x3f00000, 0x1 },
+ { 0xfc003f00, 0x28003400, 0x3f00000, 0x1 },
+ { 0xffe020c0, 0xad6000c0, 0x3f, 0x0 },
+ { 0xffe00000, 0x60000000, 0x1f18, 0x0 },
+ { 0xf8003000, 0x40000000, 0x7f00000, 0x1 },
+ { 0xffe00000, 0x69000000, 0x1f18, 0x0 },
+ { 0xffe03080, 0x9c601080, 0xf60, 0x0 },
+ { 0xffe03080, 0x9ce01000, 0xf60, 0x0 },
+ { 0xffe03080, 0x9c601000, 0xf60, 0x0 },
+ { 0xf7c02000, 0x13402000, 0x3000fe, 0x0 },
+ { 0xffe03080, 0x9c603000, 0xf60, 0x0 },
+ { 0xf7c02000, 0x21c00000, 0x3000fe, 0x0 },
+ { 0xfc003000, 0x68000000, 0x3f00000, 0x1 },
+ { 0xf8003800, 0x60002000, 0x7f00000, 0x1 },
+ { 0xffe02084, 0xaf802084, 0x30078, 0x0 },
+ { 0xfc003000, 0x48000000, 0x3f00000, 0x1 },
+ { 0xf7c02300, 0x11c02100, 0x3000fe, 0x0 },
+ { 0xf7c02000, 0x12800000, 0x3000fe, 0x0 },
+ { 0xfc003e70, 0x28003a40, 0x3f00000, 0x1 },
+ { 0xfc003f00, 0x28003300, 0x3f00000, 0x1 },
+ { 0xff800000, 0xe0000000, 0x1fe0, 0x0 },
+ { 0xff602060, 0x3f400000, 0x1f80, 0x0 },
+ { 0xffe00004, 0x42000000, 0x20f8, 0x0 },
+ { 0xf8003f00, 0x60003300, 0x7f00000, 0x1 },
+ { 0xffe01804, 0x42a00000, 0x20f8, 0x0 },
+ { 0xf7c02000, 0x12c00000, 0x3000fe, 0x0 },
+ { 0xf0000000, 0x0, 0xfff3fff, 0x0 },
+ { 0xff000016, 0xde000016, 0xe020e8, 0x0 },
+ { 0xffe03000, 0x9b201000, 0xf60, 0x0 },
+ { 0xffe03880, 0xaba00880, 0x3f, 0x0 },
+ { 0xf8003e00, 0x40003c00, 0x7f00000, 0x1 },
+ { 0xff602060, 0x3f200040, 0x1f80, 0x0 },
+ { 0xffe03880, 0x9f203880, 0x1f0100, 0x0 },
+ { 0xf7c02000, 0x20c00000, 0x3000fe, 0x0 },
+ { 0xf9e01800, 0x48a00800, 0x61f20ff, 0x0 },
+ { 0xf9e00000, 0x90a00000, 0x6003fe0, 0x0 },
+ { 0xff802000, 0x74802000, 0x1fe0, 0x0 },
+ { 0xffe03000, 0x9a401000, 0xf60, 0x0 },
+ { 0xf7c02000, 0x10002000, 0x3000fe, 0x0 },
+ { 0xf7c03000, 0x14803000, 0x3000fe, 0x0 },
+ { 0xffe020c0, 0xad0020c0, 0x3f, 0x0 },
+ { 0xffe0001c, 0x75800000, 0x3fe0, 0x0 },
+ { 0xf9e01800, 0x48a01000, 0x61f20ff, 0x0 },
+ { 0xffe03080, 0x9dc03000, 0xf60, 0x0 },
+ { 0xffe03080, 0x9dc03080, 0xf60, 0x0 },
+ { 0xffe03080, 0x9dc01000, 0xf60, 0x0 },
+ { 0xffe03080, 0x9dc01080, 0xf60, 0x0 },
+ { 0xffe03080, 0x9d601000, 0xf60, 0x0 },
+ { 0xffe03080, 0x9d601080, 0xf60, 0x0 },
+ { 0xffe03080, 0x9d603000, 0xf60, 0x0 },
+ { 0xffe03080, 0x9d603080, 0xf60, 0x0 },
+ { 0xfc003e00, 0x48003c00, 0x3f00000, 0x1 },
+ { 0xffe02084, 0xaf402084, 0x30078, 0x0 },
+ { 0xffe00004, 0x46600000, 0x20f8, 0x0 },
+ { 0xffe03880, 0x9f203080, 0x1f0100, 0x0 },
+ { 0xf8003f00, 0x20003100, 0x7f00000, 0x1 },
+ { 0xf7c02000, 0x11402000, 0x3000fe, 0x0 },
+ { 0xf8003d08, 0x20003d00, 0x7f00000, 0x1 },
+ { 0xffe03080, 0x9ca01080, 0xf60, 0x0 },
+ { 0xffe03080, 0x9ca01000, 0xf60, 0x0 },
+ { 0xffe00000, 0x38a00000, 0x201f, 0x0 },
+ { 0xf7c02300, 0x11800000, 0x3000fe, 0x0 },
+ { 0xf7c02300, 0x13c02300, 0x3000fe, 0x0 },
+ { 0xffe03080, 0x9ce03000, 0xf60, 0x0 },
+ { 0xf9e00000, 0x90e00000, 0x6003fe0, 0x0 },
+ { 0xffe02084, 0xaf400080, 0x30078, 0x0 },
+ { 0xffe03080, 0x9ce03080, 0xf60, 0x0 },
+ { 0xff000000, 0x78000000, 0xdf3fe0, 0x0 },
+ { 0xffe03080, 0x9ce01080, 0xf60, 0x0 },
+ { 0xffe03880, 0xaba01080, 0x3f, 0x0 },
+ { 0xffe020c0, 0xad002080, 0x3f, 0x0 },
+ { 0xffe020c0, 0xad0000c0, 0x3f, 0x0 },
+ { 0xffe020c0, 0xad000080, 0x3f, 0x0 },
+ { 0xf7c02000, 0x25000000, 0x3000fe, 0x0 },
+ { 0xff602060, 0x3f200020, 0x1f80, 0x0 },
+ { 0xffe02084, 0xafc00084, 0x30078, 0x0 },
+ { 0xf7c02000, 0x24400000, 0x3000fe, 0x0 },
+ { 0xfc003000, 0x48001000, 0x3f00000, 0x1 },
+ { 0xf9e01800, 0xa1a01000, 0x60020ff, 0x0 },
+ { 0xff602060, 0x3f000040, 0x1f80, 0x0 },
+ { 0xffe02084, 0xaf602084, 0x30078, 0x0 },
+ { 0xf8003f00, 0x20003400, 0x7f00000, 0x1 },
+ { 0xffe02084, 0xaf400084, 0x30078, 0x0 },
+ { 0xffe01804, 0x44a01000, 0x20f8, 0x0 },
+ { 0xff602060, 0x3e200000, 0x1f80, 0x0 },
+ { 0xf8003e70, 0x20003a70, 0x7f00000, 0x1 },
+ { 0xf8003f00, 0x40003e00, 0x7f00000, 0x1 },
+ { 0xf8003f00, 0x20003300, 0x7f00000, 0x1 },
+ { 0xf7c02300, 0x13800300, 0x3000fe, 0x0 },
+ { 0xffe038c0, 0xada00080, 0x3f, 0x0 },
+ { 0xf9e00000, 0x49400000, 0x61f3fe0, 0x0 },
+ { 0xf8003800, 0x40002800, 0x7f00000, 0x1 },
+ { 0xffe038c0, 0xada020c0, 0x3f, 0x0 },
+ { 0xffe03884, 0xafa00880, 0x30078, 0x0 },
+ { 0xf9e00000, 0x49000000, 0x61f3fe0, 0x0 },
+ { 0xff800000, 0xd7000000, 0x6020e0, 0x0 },
+ { 0xffc00000, 0xda000000, 0x203fe0, 0x0 },
+ { 0xf7c02000, 0x12802000, 0x3000fe, 0x0 },
+ { 0xf9e00000, 0x49600000, 0x61f3fe0, 0x0 },
+ { 0xffe02000, 0x47400000, 0x7e0, 0x0 },
+ { 0xf9e00000, 0x49c00000, 0x61f3fe0, 0x0 },
+ { 0xffe03000, 0x9bc01000, 0xf60, 0x0 },
+ { 0xf7c02300, 0x13c00100, 0x3000fe, 0x0 },
+ { 0xffe03880, 0x9f002880, 0x1f0100, 0x0 },
+ { 0xffe03000, 0x9b601000, 0xf60, 0x0 },
+ { 0xffe01804, 0x40a00800, 0x20f8, 0x0 },
+ { 0xffe00004, 0x42800000, 0x20f8, 0x0 },
+ { 0xf7c03000, 0x14800000, 0x3000fe, 0x0 },
+ { 0xfc003000, 0x68001000, 0x3f00000, 0x1 },
+ { 0xfc003fc7, 0x48003f44, 0x3f00000, 0x1 },
+ { 0xfc003fc7, 0x48003f45, 0x3f00000, 0x1 },
+ { 0xf7c02000, 0x10800000, 0x3000fe, 0x0 },
+ { 0xf8003e70, 0x20003a50, 0x7f00000, 0x1 },
+ { 0xf7c02000, 0x21002000, 0x3000fe, 0x0 },
+ { 0xf8003fc4, 0x40003fc0, 0x7f00000, 0x1 },
+ { 0xf9e00000, 0x48000000, 0x61f20ff, 0x0 },
+ { 0xffc0001c, 0x75000010, 0x203fe0, 0x0 },
+ { 0xf8003f00, 0x20003800, 0x7f00000, 0x1 },
+ { 0xf9e00000, 0xa1800000, 0x60020ff, 0x0 },
+ { 0xffc01000, 0x61c00000, 0x202ffe, 0x0 },
+ { 0xffe02084, 0xaf402080, 0x30078, 0x0 },
+ { 0xffe03880, 0x9f602880, 0x1f0100, 0x0 },
+ { 0xfc003f00, 0x68003000, 0x3f00000, 0x1 },
+ { 0xfc003f00, 0x68003100, 0x3f00000, 0x1 },
+ { 0xff602060, 0x3f200000, 0x1f80, 0x0 },
+ { 0xffe03000, 0x9a801000, 0xf60, 0x0 },
+ { 0xf7c02000, 0x24802000, 0x3000fe, 0x0 },
+ { 0xffe00004, 0x42c00000, 0x20f8, 0x0 },
+ { 0xf7c02300, 0x11802000, 0x3000fe, 0x0 },
+ { 0xffc01000, 0x61401000, 0x202ffe, 0x0 },
+ { 0xffe02000, 0x43c00000, 0x7e0, 0x0 },
+ { 0xf7c02000, 0x11400000, 0x3000fe, 0x0 },
+ { 0xf7c02000, 0x21800000, 0x3000fe, 0x0 },
+ { 0xfc003c00, 0x28002c00, 0x3f00000, 0x1 },
+ { 0xfc003f00, 0x28003200, 0x3f00000, 0x1 },
+ { 0xffe03080, 0x9c803080, 0xf60, 0x0 },
+ { 0xf7c03000, 0x14c03000, 0x3000fe, 0x0 },
+ { 0xff800000, 0xdb800000, 0x6020e0, 0x0 },
+ { 0xf7c02000, 0x22402000, 0x3000fe, 0x0 },
+ { 0xffe00004, 0x46800000, 0x20f8, 0x0 },
+ { 0xffe00000, 0x69a00000, 0x1f18, 0x0 },
+ { 0xfc003e00, 0x68002a00, 0x3f00000, 0x1 },
+ { 0xffe00000, 0x60a00000, 0x1f18, 0x0 },
+ { 0xf7c02000, 0x25400000, 0x3000fe, 0x0 },
+ { 0xfc003e70, 0x28003a70, 0x3f00000, 0x1 },
+ { 0xffe03080, 0x9c803000, 0xf60, 0x0 },
+ { 0xffc01000, 0x61400000, 0x202ffe, 0x0 },
+ { 0xffe01804, 0x42a01000, 0x20f8, 0x0 },
+ { 0xffc0001c, 0x75000000, 0x203fe0, 0x0 },
+ { 0xffe02084, 0xafc02080, 0x30078, 0x0 },
+ { 0xffe03884, 0xafa00884, 0x30078, 0x0 },
+ { 0xffe03884, 0xafa02080, 0x30078, 0x0 },
+ { 0xffe00000, 0x38c00000, 0x201f, 0x0 },
+ { 0xffc01000, 0x61001000, 0x202ffe, 0x0 },
+ { 0xf9e00000, 0x48800000, 0x61f20ff, 0x0 },
+ { 0xf8003800, 0x40003000, 0x7f00000, 0x1 },
+ { 0xf7c03000, 0x15403000, 0x3000fe, 0x0 },
+ { 0xf7c03000, 0x15400000, 0x3000fe, 0x0 },
+ { 0xf7c02000, 0x21000000, 0x3000fe, 0x0 },
+ { 0xffe00004, 0x40c00000, 0x20f8, 0x0 },
+ { 0xffe01804, 0x46a01000, 0x20f8, 0x0 },
+ { 0xf8003d08, 0x20003d08, 0x7f00000, 0x1 },
+ { 0xffe038c0, 0xada02080, 0x3f, 0x0 },
+ { 0xffe03080, 0x9c203000, 0xf60, 0x0 },
+ { 0xfc003800, 0x68002000, 0x3f00000, 0x1 },
+ { 0xf9e00000, 0x90600000, 0x6003fe0, 0x0 },
+ { 0xf7c03000, 0x14000000, 0x3000fe, 0x0 },
+ { 0xf8003e70, 0x20003a40, 0x7f00000, 0x1 },
+ { 0xff201800, 0x5c000800, 0xdf20fe, 0x0 },
+ { 0xffe02000, 0x41800000, 0x7e0, 0x0 },
+ { 0xff800000, 0xdb000000, 0x6020e0, 0x0 },
+ { 0xfc003f00, 0x48003e00, 0x3f00000, 0x1 },
+ { 0xf7c03000, 0x14002000, 0x3000fe, 0x0 },
+ { 0xf7c02300, 0x11800100, 0x3000fe, 0x0 },
+ { 0xfc003e00, 0x68002800, 0x3f00000, 0x1 },
+ { 0xffe00004, 0x44c00000, 0x20f8, 0x0 },
+ { 0xffe03880, 0x9f003880, 0x1f0100, 0x0 },
+ { 0xff602000, 0x73402000, 0x1fe0, 0x0 },
+ { 0xffe00000, 0x38200000, 0x201f, 0x0 },
+ { 0xf7c02000, 0x24800000, 0x3000fe, 0x0 },
+ { 0xf7c03000, 0x15001000, 0x3000fe, 0x0 },
+ { 0xff800000, 0x7c800000, 0x1f2000, 0x0 },
+ { 0xf8003fc7, 0x40003fc6, 0x7f00000, 0x1 },
+ { 0xf7c02000, 0x12000000, 0x3000fe, 0x0 },
+ { 0xff602000, 0x73202000, 0x1fe0, 0x0 },
+ { 0xf7c02300, 0x13c00000, 0x3000fe, 0x0 },
+ { 0xff602060, 0x3f400040, 0x1f80, 0x0 },
+ { 0xf7c02000, 0x24002000, 0x3000fe, 0x0 },
+ { 0xffe02084, 0xaf800080, 0x30078, 0x0 },
+ { 0xffe00000, 0x38800000, 0x201f, 0x0 },
+ { 0xfc003f00, 0x28003800, 0x3f00000, 0x1 },
+ { 0xffe03080, 0x9c801080, 0xf60, 0x0 },
+ { 0xffe020c0, 0xad4000c0, 0x3f, 0x0 },
+ { 0xffe00000, 0x39400000, 0x201f, 0x0 },
+ { 0xf7c02300, 0x13c02100, 0x3000fe, 0x0 },
+ { 0xffe020c0, 0xad400080, 0x3f, 0x0 },
+ { 0xffe03880, 0x9f603880, 0x1f0100, 0x0 },
+ { 0xff000016, 0xde000002, 0xe020e8, 0x0 },
+ { 0xfc003d08, 0x28003d00, 0x3f00000, 0x1 },
+ { 0xfc003f00, 0x28003000, 0x3f00000, 0x1 },
+ { 0xffe03080, 0x9c401000, 0xf60, 0x0 },
+ { 0xf7c02000, 0x21402000, 0x3000fe, 0x0 },
+ { 0xff201800, 0x5c200800, 0xdf20fe, 0x0 },
+ { 0xffe01804, 0x40a01000, 0x20f8, 0x0 },
+ { 0xfc003f00, 0x68003300, 0x3f00000, 0x1 },
+ { 0xfc003f00, 0x68003200, 0x3f00000, 0x1 },
+ { 0xf7c03000, 0x15401000, 0x3000fe, 0x0 },
+ { 0xffe01804, 0x44a00800, 0x20f8, 0x0 },
+ { 0xf7c02000, 0x26000000, 0x3000fe, 0x0 },
+ { 0xffc00000, 0xda400000, 0x203fe0, 0x0 },
+ { 0xffe00004, 0x40600000, 0x20f8, 0x0 },
+ { 0xffe02080, 0xab600080, 0x3f, 0x0 },
+ { 0xf8003f00, 0x20003600, 0x7f00000, 0x1 },
+ { 0xf7c02300, 0x11c00300, 0x3000fe, 0x0 },
+ { 0xf8003f00, 0x20003700, 0x7f00000, 0x1 },
+ { 0xf7c02000, 0x25c00000, 0x3000fe, 0x0 },
+ { 0xf7c02300, 0x11800300, 0x3000fe, 0x0 },
+ { 0xffe03880, 0x9f802880, 0x1f0100, 0x0 },
+ { 0xfc003800, 0x48003000, 0x3f00000, 0x1 },
+ { 0xf8003c00, 0x20002c00, 0x7f00000, 0x1 },
+ { 0xf7c02000, 0x10400000, 0x3000fe, 0x0 },
+ { 0xff602060, 0x3f400060, 0x1f80, 0x0 },
+ { 0xffe03080, 0x9c801000, 0xf60, 0x0 },
+ { 0xff602060, 0x3e400040, 0x1f80, 0x0 },
+ { 0xf7c03000, 0x14402000, 0x3000fe, 0x0 },
+ { 0xffe0001c, 0x75800010, 0x3fe0, 0x0 },
+ { 0xff000016, 0xde000014, 0xe020e8, 0x0 },
+ { 0xf7c02300, 0x11c02000, 0x3000fe, 0x0 },
+ { 0xff600018, 0xdd200008, 0x1fe0, 0x0 },
+ { 0xff602060, 0x3e200060, 0x1f80, 0x0 },
+ { 0xff000016, 0xde000006, 0xe020e8, 0x0 },
+ { 0xffe00004, 0x44600000, 0x20f8, 0x0 },
+ { 0xf8003e00, 0x60002800, 0x7f00000, 0x1 },
+ { 0xfe600000, 0x3c000000, 0x207f, 0x0 },
+ { 0xffe03884, 0xafa02884, 0x30078, 0x0 },
+ { 0xf7c02300, 0x11802300, 0x3000fe, 0x0 },
+ { 0xffe00000, 0x38000000, 0x201f, 0x0 },
+ { 0xff200800, 0x5c000000, 0xdf20fe, 0x0 },
+ { 0xf7c02000, 0x13400000, 0x3000fe, 0x0 },
+ { 0xff200800, 0x5c200000, 0xdf20fe, 0x0 },
+ { 0xffe02000, 0x41000000, 0x7e0, 0x0 },
+ { 0xffe03880, 0x9fc02880, 0x1f0100, 0x0 },
+ { 0xffe00004, 0x46000000, 0x20f8, 0x0 },
+ { 0xff602060, 0x3f000020, 0x1f80, 0x0 },
+ { 0xfc003d08, 0x28003d08, 0x3f00000, 0x1 },
+ { 0xff602060, 0x3f200060, 0x1f80, 0x0 },
+ { 0xffe038c0, 0xada028c0, 0x3f, 0x0 },
+ { 0xffe038c0, 0xada008c0, 0x3f, 0x0 },
+ { 0xf8003f00, 0x20003500, 0x7f00000, 0x1 },
+ { 0xfc003fc4, 0x48003f40, 0x3f00000, 0x1 },
+ { 0xf9e01800, 0x48a00000, 0x61f20ff, 0x0 },
+ { 0xf7c03000, 0x14802000, 0x3000fe, 0x0 },
+ { 0xfc003f00, 0x28003900, 0x3f00000, 0x1 },
+ { 0xf8003fc7, 0x40003fc7, 0x7f00000, 0x1 },
+ { 0xffe02000, 0x45400000, 0x7e0, 0x0 },
+ { 0xffe038c0, 0xada02880, 0x3f, 0x0 },
+ { 0xffe02084, 0xaf002080, 0x30078, 0x0 },
+ { 0xffe03880, 0x9f803880, 0x1f0100, 0x0 },
+ { 0xf7c03000, 0x15000000, 0x3000fe, 0x0 },
+ { 0xfc003f00, 0x28003700, 0x3f00000, 0x1 },
+ { 0xfc003f00, 0x28003600, 0x3f00000, 0x1 },
+ { 0xffe02000, 0x47200000, 0x7e0, 0x0 },
+ { 0xffe03880, 0xaba00080, 0x3f, 0x0 },
+ { 0xffe02084, 0xafc00080, 0x30078, 0x0 },
+ { 0xff802000, 0x73800000, 0x1fe0, 0x0 },
+ { 0xffe03880, 0x9f202880, 0x1f0100, 0x0 },
+ { 0xf8003d18, 0x20003c00, 0x7f00000, 0x1 },
+ { 0xf9e00000, 0xa1600000, 0x60020ff, 0x0 },
+ { 0xffe00004, 0x44800000, 0x20f8, 0x0 },
+ { 0xf7c02000, 0x21802000, 0x3000fe, 0x0 },
+ { 0xff000000, 0xd8000000, 0x6020e0, 0x0 },
+ { 0xf9e00000, 0xa1000000, 0x60020ff, 0x0 },
+ { 0xffe03884, 0xafa00084, 0x30078, 0x0 },
+ { 0xff201800, 0x5c201800, 0xdf20fe, 0x0 },
+ { 0xff000016, 0xde000010, 0xe020e8, 0x0 },
+ { 0xffe03880, 0x9f603080, 0x1f0100, 0x0 },
+ { 0xffe02000, 0x41c00000, 0x7e0, 0x0 },
+ { 0xf7c02000, 0x20402000, 0x3000fe, 0x0 },
+ { 0xff800000, 0xe1000000, 0x1fe0, 0x0 },
+ { 0xf9e00000, 0xa1400000, 0x60020ff, 0x0 },
+ { 0xf7c03000, 0x14c00000, 0x3000fe, 0x0 },
+ { 0xf8003fc7, 0x40003f47, 0x7f00000, 0x1 },
+ { 0xffe00004, 0x40800000, 0x20f8, 0x0 },
+ { 0xff800000, 0xe1800000, 0x1fe0, 0x0 },
+ { 0xf7c02300, 0x11802100, 0x3000fe, 0x0 },
+ { 0xf9e00000, 0x49800000, 0x61f3fe0, 0x0 },
+ { 0xf7c02000, 0x26400000, 0x3000fe, 0x0 },
+ { 0xf8003c00, 0x20002800, 0x7f00000, 0x1 },
+ { 0xff902000, 0x7e002000, 0xf1fe0, 0x0 },
+ { 0xff902000, 0x7e802000, 0xf1fe0, 0x0 },
+ { 0xf9e00000, 0x91c00000, 0x6003fe0, 0x0 },
+ { 0xffe03884, 0xafa02880, 0x30078, 0x0 },
+ { 0xf7c02000, 0x22000000, 0x3000fe, 0x0 },
+ { 0xffe03080, 0x9d203000, 0xf60, 0x0 },
+ { 0xf7c02000, 0x26002000, 0x3000fe, 0x0 },
+ { 0xff800000, 0xe2000000, 0x1fe0, 0x0 },
+ { 0xf7c02000, 0x26c00000, 0x3000fe, 0x0 },
+ { 0xff602060, 0x3e400000, 0x1f80, 0x0 },
+ { 0xffe00000, 0x38400000, 0x201f, 0x0 },
+ { 0xfc003800, 0x48002000, 0x3f00000, 0x1 },
+ { 0xff000016, 0xde000000, 0xe020e8, 0x0 },
+ { 0xf8003f00, 0x20003000, 0x7f00000, 0x1 },
+ { 0xf8003e70, 0x20003a60, 0x7f00000, 0x1 },
+ { 0xff902000, 0x7e800000, 0xf1fe0, 0x0 },
+ { 0xffe020c0, 0xad6020c0, 0x3f, 0x0 },
+ { 0xf7c02300, 0x13802000, 0x3000fe, 0x0 },
+ { 0xffe020c0, 0xad600080, 0x3f, 0x0 },
+ { 0xff902000, 0x7e000000, 0xf1fe0, 0x0 },
+ { 0xf7000000, 0x17000000, 0x3000fe, 0x0 },
+ { 0xf7000000, 0x16000000, 0x3000fe, 0x0 },
+ { 0xf7c02000, 0x25002000, 0x3000fe, 0x0 },
+ { 0xfc003fc7, 0x48003fc7, 0x3f00000, 0x1 },
+ { 0xffc01000, 0x61801000, 0x202ffe, 0x0 },
+ { 0xffe03884, 0xafa03080, 0x30078, 0x0 },
+ { 0xf8003fc4, 0x40003f40, 0x7f00000, 0x1 },
+ { 0xfc003e70, 0x28003a60, 0x3f00000, 0x1 },
+ { 0xf7c02300, 0x13800000, 0x3000fe, 0x0 },
+ { 0xffe03880, 0x9f802080, 0x1f0100, 0x0 },
+ { 0xf0000000, 0xb0000000, 0xfe03fe0, 0x0 },
+ { 0xffe03880, 0x9f402080, 0x1f0100, 0x0 },
+ { 0xffe02000, 0x43200000, 0x7e0, 0x0 },
+ { 0xffe00000, 0x39800000, 0x201f, 0x0 },
+ { 0xffe03880, 0x9fc03880, 0x1f0100, 0x0 },
+ { 0xffe02000, 0x45600000, 0x7e0, 0x0 },
+ { 0xf9e00000, 0x91200000, 0x6003fe0, 0x0 },
+ { 0xffe02000, 0x43600000, 0x7e0, 0x0 },
+ { 0xfc003f00, 0x28003800, 0x3f00000, 0x1 },
+ { 0xff802000, 0x74000000, 0x1fe0, 0x0 },
+ { 0xffe02084, 0xaf002084, 0x30078, 0x0 },
+ { 0xff802000, 0x74800000, 0x1fe0, 0x0 },
+ { 0xf7c03000, 0x14c02000, 0x3000fe, 0x0 },
+ { 0xfe000001, 0x5a000000, 0x1ff3ffe, 0x0 },
+ { 0xff602060, 0x3f400020, 0x1f80, 0x0 },
+ { 0xf7c02000, 0x10802000, 0x3000fe, 0x0 },
+ { 0xffe02084, 0xaf802080, 0x30078, 0x0 },
+ { 0xffe00004, 0x46400000, 0x20f8, 0x0 },
+ { 0xffe020c0, 0xad800080, 0x3f, 0x0 },
+ { 0xffe020c0, 0xad8000c0, 0x3f, 0x0 },
+ { 0xf8003fc7, 0x40003f45, 0x7f00000, 0x1 },
+ { 0xf8003e00, 0x60002a00, 0x7f00000, 0x1 },
+ { 0xffe02084, 0xaf600084, 0x30078, 0x0 },
+ { 0xffe03080, 0x9c201000, 0xf60, 0x0 },
+ { 0xffe02000, 0x43400000, 0x7e0, 0x0 },
+ { 0xffe03080, 0x9c203080, 0xf60, 0x0 },
+ { 0xffe02000, 0x41200000, 0x7e0, 0x0 },
+ { 0xffe03080, 0x9c201080, 0xf60, 0x0 },
+ { 0xf7c02300, 0x11c02300, 0x3000fe, 0x0 },
+ { 0xffe03880, 0x9fc03080, 0x1f0100, 0x0 },
+ { 0xffe03880, 0x9f402880, 0x1f0100, 0x0 },
+ { 0xf8003800, 0x40002000, 0x7f00000, 0x1 },
+ { 0xf7c02000, 0x24402000, 0x3000fe, 0x0 },
+ { 0xf7c02000, 0x20c02000, 0x3000fe, 0x0 },
+ { 0xf7c02300, 0x11c00000, 0x3000fe, 0x0 },
+ { 0xffe02000, 0x45200000, 0x7e0, 0x0 },
+ { 0xf8003f00, 0x20003900, 0x7f00000, 0x1 },
+ { 0xf7c02300, 0x11c00100, 0x3000fe, 0x0 },
+ { 0xffe02084, 0xaf800084, 0x30078, 0x0 },
+ { 0xfe600000, 0x3c200000, 0x207f, 0x0 },
+ { 0xf7c02000, 0x26800000, 0x3000fe, 0x0 },
+ { 0xffe03880, 0x9f003080, 0x1f0100, 0x0 },
+ { 0xffe03884, 0xafa01084, 0x30078, 0x0 },
+ { 0xffc00000, 0x76000000, 0x203fe0, 0x0 },
+ { 0xff602060, 0x3e000040, 0x1f80, 0x0 },
+ { 0xffe020c0, 0xadc020c0, 0x3f, 0x0 },
+ { 0xffe00004, 0x44400000, 0x20f8, 0x0 },
+ { 0xffe020c0, 0xadc02080, 0x3f, 0x0 },
+ { 0xfe600000, 0x3c400000, 0x207f, 0x0 },
+ { 0xf7c02000, 0x20400000, 0x3000fe, 0x0 },
+ { 0xff800000, 0x7c000000, 0x1fe0, 0x0 },
+ { 0xffe03884, 0xafa00080, 0x30078, 0x0 },
+ { 0xff201800, 0x5c001800, 0xdf20fe, 0x0 },
+ { 0xffe02000, 0x47800000, 0x7e0, 0x0 },
+ { 0xff601018, 0xdd400000, 0xfe0, 0x0 },
+ { 0xffe020c0, 0xad4020c0, 0x3f, 0x0 },
+ { 0xffe020c0, 0xad402080, 0x3f, 0x0 },
+ { 0xf8003000, 0x40001000, 0x7f00000, 0x1 },
+ { 0xffe02084, 0xafc02084, 0x30078, 0x0 },
+ { 0xffe03080, 0x9c403080, 0xf60, 0x0 },
+ { 0xfc003e40, 0x28003a00, 0x3f00000, 0x1 },
+ { 0xffe038c0, 0xada010c0, 0x3f, 0x0 },
+ { 0xffe038c0, 0xada01080, 0x3f, 0x0 },
+ { 0xffe038c0, 0xada030c0, 0x3f, 0x0 },
+ { 0xffe038c0, 0xada03080, 0x3f, 0x0 },
+ { 0xf7c02000, 0x20800000, 0x3000fe, 0x0 },
+ { 0xfc003fc7, 0x48003f46, 0x3f00000, 0x1 },
+ { 0xffe01804, 0x44a00000, 0x20f8, 0x0 },
+ { 0xf7c02000, 0x20002000, 0x3000fe, 0x0 },
+ { 0xf7c02000, 0x12c02000, 0x3000fe, 0x0 },
+ { 0xffe03000, 0x9a601000, 0xf60, 0x0 },
+ { 0xffc00000, 0xda800000, 0x203fe0, 0x0 },
+ { 0xf9e00000, 0x90400000, 0x6003fe0, 0x0 },
+ { 0xffe02000, 0x47600000, 0x7e0, 0x0 },
+ { 0xffe03080, 0x9d403000, 0xf60, 0x0 },
+ { 0xffe03080, 0x9d403080, 0xf60, 0x0 },
+ { 0xffe03080, 0x9d401000, 0xf60, 0x0 },
+ { 0xffe03080, 0x9d401080, 0xf60, 0x0 },
+ { 0xffe02000, 0x41400000, 0x7e0, 0x0 },
+ { 0xff800000, 0xdf800000, 0x6020e0, 0x0 },
+ { 0xffc01000, 0x61000000, 0x202ffe, 0x0 },
+ { 0xffe03880, 0x9f202080, 0x1f0100, 0x0 },
+ { 0xfc003fc7, 0x48003fc6, 0x3f00000, 0x1 },
+ { 0xfe000000, 0x7a000000, 0x1fe0, 0x0 },
+ { 0xffff0000, 0x6a490000, 0x1f80, 0x0 },
+ { 0xff802000, 0x73000000, 0x1fe0, 0x0 },
+ { 0xff602060, 0x3e200020, 0x1f80, 0x0 },
+ { 0xf7c02000, 0x24000000, 0x3000fe, 0x0 },
+ { 0xf8003e40, 0x20003a00, 0x7f00000, 0x1 },
+ { 0xf7c03000, 0x14401000, 0x3000fe, 0x0 },
+ { 0xf8003f00, 0x20003200, 0x7f00000, 0x1 },
+ { 0xffc00000, 0x76400000, 0x203fe0, 0x0 },
+ { 0xf7c02000, 0x22002000, 0x3000fe, 0x0 },
+ { 0xffc01000, 0x61c01000, 0x202ffe, 0x0 },
+ { 0xf7c03000, 0x14801000, 0x3000fe, 0x0 },
+ { 0xf7c02000, 0x12002000, 0x3000fe, 0x0 },
+ { 0xf7c02000, 0x10402000, 0x3000fe, 0x0 },
+ { 0xff201800, 0x5d200000, 0xdf20fe, 0x0 },
+ { 0xf7c02000, 0x21400000, 0x3000fe, 0x0 },
+ { 0xff201800, 0x5d000000, 0xdf20fe, 0x0 },
+ { 0xffe02000, 0x45c00000, 0x7e0, 0x0 },
+ { 0xf7c02000, 0x25802000, 0x3000fe, 0x0 },
+ { 0xfc003e70, 0x28003a50, 0x3f00000, 0x1 },
+ { 0xf7c02300, 0x13c00300, 0x3000fe, 0x0 },
+ { 0xf9e01800, 0xa1a00800, 0x60020ff, 0x0 },
+ { 0xffe02000, 0x43800000, 0x7e0, 0x0 },
+ { 0xfc003fc4, 0x48003fc0, 0x3f00000, 0x1 },
+ { 0xff800000, 0xe2800000, 0x1fe0, 0x0 },
+ { 0xf7c02300, 0x13c02000, 0x3000fe, 0x0 },
+ { 0xffe03080, 0x9d803080, 0xf60, 0x0 },
+ { 0xffe03080, 0x9d803000, 0xf60, 0x0 },
+ { 0xffe03080, 0x9d801080, 0xf60, 0x0 },
+ { 0xf8003fc4, 0x40003f00, 0x7f00000, 0x1 },
+ { 0xffe00000, 0x39c00000, 0x201f, 0x0 },
+ { 0xffe03080, 0x9d203080, 0xf60, 0x0 },
+ { 0xffe02080, 0xab000080, 0x3f, 0x0 },
+ { 0xf8003e00, 0x60003c00, 0x7f00000, 0x1 },
+ { 0xffe03880, 0x9f602080, 0x1f0100, 0x0 },
+ { 0xffc00000, 0x76800000, 0x203fe0, 0x0 },
+ { 0xffe03884, 0xafa02084, 0x30078, 0x0 },
+ { 0xf7c02000, 0x13002000, 0x3000fe, 0x0 },
+ { 0xf9e00000, 0x91000000, 0x6003fe0, 0x0 },
+ { 0xffe03080, 0x9d201080, 0xf60, 0x0 },
+ { 0xf7c03000, 0x15002000, 0x3000fe, 0x0 },
+ { 0xf8003000, 0x60000000, 0x7f00000, 0x1 },
+ { 0xffc01000, 0x61800000, 0x202ffe, 0x0 },
+ { 0xf7c03000, 0x14400000, 0x3000fe, 0x0 },
+ { 0xffe03000, 0x9b401000, 0xf60, 0x0 },
+ { 0xf7c03000, 0x14003000, 0x3000fe, 0x0 },
+ { 0xffe03880, 0x9fc02080, 0x1f0100, 0x0 },
+ { 0xfc003fc4, 0x48003f00, 0x3f00000, 0x1 },
+ { 0xffe02000, 0x45000000, 0x7e0, 0x0 },
+ { 0xfc003800, 0x48002800, 0x3f00000, 0x1 },
+ { 0xfc003fc7, 0x48003fc5, 0x3f00000, 0x1 },
+ { 0xfc003d18, 0x28003c00, 0x3f00000, 0x1 },
+ { 0xfc003fc7, 0x48003fc4, 0x3f00000, 0x1 },
+ { 0xf8003f00, 0x60003200, 0x7f00000, 0x1 },
+ { 0xffe02084, 0xaf600080, 0x30078, 0x0 },
+ { 0xf9e01800, 0xa1a00000, 0x60020ff, 0x0 },
+ { 0xf7c03000, 0x14001000, 0x3000fe, 0x0 },
+ { 0xf7c03000, 0x14c01000, 0x3000fe, 0x0 },
+ { 0xffe00004, 0x46c00000, 0x20f8, 0x0 },
+ { 0xf7c03000, 0x15003000, 0x3000fe, 0x0 },
+ { 0xf7c02000, 0x10000000, 0x3000fe, 0x0 },
+ { 0xf8003d18, 0x20003c08, 0x7f00000, 0x1 },
+ { 0xffc0001c, 0x75400010, 0x203fe0, 0x0 },
+ { 0xf9e00000, 0x48600000, 0x61f20ff, 0x0 },
+ { 0xffe03080, 0x9c603080, 0xf60, 0x0 },
+ { 0xfe000000, 0x58000000, 0x1ff3ffe, 0x0 },
+ { 0xffe03000, 0x9a201000, 0xf60, 0x0 },
+ { 0xffe00000, 0x69e00000, 0x1f18, 0x0 },
+ { 0xffe020c0, 0xad802080, 0x3f, 0x0 },
+ { 0xffe02000, 0x47c00000, 0x7e0, 0x0 },
+ { 0xffe00000, 0x60e00000, 0x1f18, 0x0 },
+ { 0xf7c03000, 0x15402000, 0x3000fe, 0x0 },
+ { 0xffe020c0, 0xad8020c0, 0x3f, 0x0 },
+ { 0xff000016, 0xde000012, 0xe020e8, 0x0 },
+ { 0xf7c02000, 0x25c02000, 0x3000fe, 0x0 },
+ { 0xf8003f00, 0x60003100, 0x7f00000, 0x1 },
+ { 0xf8003f00, 0x60003000, 0x7f00000, 0x1 },
+ { 0xf7c02000, 0x25800000, 0x3000fe, 0x0 },
+ { 0xf7c03000, 0x14403000, 0x3000fe, 0x0 },
+ { 0xfc003d18, 0x28003c08, 0x3f00000, 0x1 },
+ { 0xffe03880, 0x9f403080, 0x1f0100, 0x0 },
+ { 0xf7c02000, 0x25402000, 0x3000fe, 0x0 },
+ { 0xf7c02000, 0x10c00000, 0x3000fe, 0x0 },
+ { 0xffe02000, 0x45800000, 0x7e0, 0x0 },
+ { 0xffe03880, 0x9f803080, 0x1f0100, 0x0 },
+ { 0xffe03080, 0x9d001000, 0xf60, 0x0 },
+ { 0xffe03080, 0x9d001080, 0xf60, 0x0 },
+ { 0xffe03080, 0x9d003000, 0xf60, 0x0 },
+ { 0xffe03080, 0x9d003080, 0xf60, 0x0 },
+ { 0xffe03080, 0x9d801000, 0xf60, 0x0 },
+ { 0xf9e00000, 0x49200000, 0x61f3fe0, 0x0 },
+ { 0xf9e00000, 0xa1c00000, 0x60020ff, 0x0 },
+ { 0xf9e00000, 0x90200000, 0x6003fe0, 0x0 },
+ { 0xffe03080, 0x9d201000, 0xf60, 0x0 },
+ { 0xffe03884, 0xafa01080, 0x30078, 0x0 },
+ { 0xffe02084, 0xaf602080, 0x30078, 0x0 },
+ { 0xffe038c0, 0xada000c0, 0x3f, 0x0 },
+ { 0xffe02080, 0xab400080, 0x3f, 0x0 },
+ { 0xff000016, 0xde000004, 0xe020e8, 0x0 },
+ { 0xffe00004, 0x44000000, 0x20f8, 0x0 },
+ { 0xf7c02000, 0x20000000, 0x3000fe, 0x0 },
+ { 0xfc003d18, 0x28003c10, 0x3f00000, 0x1 },
+ { 0xff600018, 0xdd000008, 0x1fe0, 0x0 },
+ { 0xffe020c0, 0xadc000c0, 0x3f, 0x0 },
+ { 0xffe020c0, 0xadc00080, 0x3f, 0x0 },
+ { 0xffe03000, 0x9b801000, 0xf60, 0x0 },
+ { 0xf8003fc7, 0x40003f46, 0x7f00000, 0x1 },
+ { 0xf7c02000, 0x21c02000, 0x3000fe, 0x0 },
+ { 0xffe01804, 0x40a00000, 0x20f8, 0x0 },
+ { 0xf7c02000, 0x26402000, 0x3000fe, 0x0 },
+ { 0xffe03080, 0x9c401080, 0xf60, 0x0 },
+ { 0xffe00000, 0x39200000, 0x201f, 0x0 },
+ { 0xffe03080, 0x9c403000, 0xf60, 0x0 },
+ { 0xf7c02000, 0x11002000, 0x3000fe, 0x0 },
+ { 0xfc003c00, 0x28002800, 0x3f00000, 0x1 },
+ { 0xffe00004, 0x40400000, 0x20f8, 0x0 },
+ { 0xf7c02000, 0x26802000, 0x3000fe, 0x0 },
+ { 0xf7c02000, 0x13000000, 0x3000fe, 0x0 },
+ { 0xffe00004, 0x42600000, 0x20f8, 0x0 },
+ { 0xf8003000, 0x60001000, 0x7f00000, 0x1 },
+ { 0xff602060, 0x3e400020, 0x1f80, 0x0 },
+ { 0xff602060, 0x3f000000, 0x1f80, 0x0 },
+ { 0xf7c02000, 0x24c02000, 0x3000fe, 0x0 },
+ { 0xff802000, 0x74002000, 0x1fe0, 0x0 },
+ { 0xf8003800, 0x20002000, 0x7f00000, 0x1 },
+ { 0xffe03000, 0x9aa01000, 0xf60, 0x0 },
+ { 0xf7c02000, 0x12400000, 0x3000fe, 0x0 },
+ { 0xff602060, 0x3f000060, 0x1f80, 0x0 },
+ { 0xf7c02000, 0x11000000, 0x3000fe, 0x0 },
+};
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonExecutableAtoms.h b/lib/ReaderWriter/ELF/Hexagon/HexagonExecutableAtoms.h
new file mode 100644
index 0000000000000..a2505aa460c5b
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Hexagon/HexagonExecutableAtoms.h
@@ -0,0 +1,29 @@
+//===- lib/ReaderWriter/ELF/Hexagon/HexagonExecutableAtoms.h --------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_EXECUTABLE_ATOM_H
+#define LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_EXECUTABLE_ATOM_H
+
+#include "ELFFile.h"
+
+namespace lld {
+namespace elf {
+typedef llvm::object::ELFType<llvm::support::little, 2, false> HexagonELFType;
+class HexagonLinkingContext;
+
+template <class HexagonELFType> class HexagonRuntimeFile
+ : public RuntimeFile<HexagonELFType> {
+public:
+ HexagonRuntimeFile(HexagonLinkingContext &context)
+ : RuntimeFile<HexagonELFType>(context, "Hexagon runtime file") {}
+};
+} // elf
+} // lld
+
+#endif // LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_EXECUTABLE_ATOM_H
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonExecutableWriter.h b/lib/ReaderWriter/ELF/Hexagon/HexagonExecutableWriter.h
new file mode 100644
index 0000000000000..0848e64166faa
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Hexagon/HexagonExecutableWriter.h
@@ -0,0 +1,86 @@
+//===- lib/ReaderWriter/ELF/Hexagon/HexagonExecutableWriter.h -------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef HEXAGON_EXECUTABLE_WRITER_H
+#define HEXAGON_EXECUTABLE_WRITER_H
+
+#include "ExecutableWriter.h"
+#include "HexagonELFWriters.h"
+#include "HexagonExecutableAtoms.h"
+#include "HexagonLinkingContext.h"
+
+namespace lld {
+namespace elf {
+
+template <typename ELFT> class HexagonTargetLayout;
+
+template <class ELFT>
+class HexagonExecutableWriter : public ExecutableWriter<ELFT>,
+ public HexagonELFWriter<ELFT> {
+public:
+ HexagonExecutableWriter(HexagonLinkingContext &context,
+ HexagonTargetLayout<ELFT> &layout);
+
+protected:
+ // Add any runtime files and their atoms to the output
+ virtual bool createImplicitFiles(std::vector<std::unique_ptr<File>> &);
+
+ virtual void finalizeDefaultAtomValues();
+
+ virtual std::error_code setELFHeader() {
+ ExecutableWriter<ELFT>::setELFHeader();
+ HexagonELFWriter<ELFT>::setELFHeader(*this->_elfHeader);
+ return std::error_code();
+ }
+
+private:
+ void addDefaultAtoms() {
+ _hexagonRuntimeFile->addAbsoluteAtom("_SDA_BASE_");
+ if (this->_context.isDynamic()) {
+ _hexagonRuntimeFile->addAbsoluteAtom("_GLOBAL_OFFSET_TABLE_");
+ _hexagonRuntimeFile->addAbsoluteAtom("_DYNAMIC");
+ }
+ }
+
+ HexagonLinkingContext &_hexagonLinkingContext;
+ HexagonTargetLayout<ELFT> &_hexagonTargetLayout;
+ std::unique_ptr<HexagonRuntimeFile<ELFT>> _hexagonRuntimeFile;
+};
+
+template <class ELFT>
+HexagonExecutableWriter<ELFT>::HexagonExecutableWriter(
+ HexagonLinkingContext &context, HexagonTargetLayout<ELFT> &layout)
+ : ExecutableWriter<ELFT>(context, layout),
+ HexagonELFWriter<ELFT>(context, layout), _hexagonLinkingContext(context),
+ _hexagonTargetLayout(layout),
+ _hexagonRuntimeFile(new HexagonRuntimeFile<ELFT>(context)) {}
+
+template <class ELFT>
+bool HexagonExecutableWriter<ELFT>::createImplicitFiles(
+ std::vector<std::unique_ptr<File>> &result) {
+ ExecutableWriter<ELFT>::createImplicitFiles(result);
+ // Add the default atoms as defined for hexagon
+ addDefaultAtoms();
+ result.push_back(std::move(_hexagonRuntimeFile));
+ return true;
+}
+
+template <class ELFT>
+void HexagonExecutableWriter<ELFT>::finalizeDefaultAtomValues() {
+ // Finalize the atom values that are part of the parent.
+ ExecutableWriter<ELFT>::finalizeDefaultAtomValues();
+ auto sdabaseAtomIter = _hexagonTargetLayout.findAbsoluteAtom("_SDA_BASE_");
+ (*sdabaseAtomIter)->_virtualAddr =
+ _hexagonTargetLayout.getSDataSection()->virtualAddr();
+ HexagonELFWriter<ELFT>::finalizeHexagonRuntimeAtomValues();
+}
+
+} // namespace elf
+} // namespace lld
+
+#endif // HEXAGON_EXECUTABLE_WRITER_H
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.cpp b/lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.cpp
new file mode 100644
index 0000000000000..7eacb2b44c3b2
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.cpp
@@ -0,0 +1,25 @@
+//===- lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.cpp -------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "HexagonLinkingContext.h"
+#include "HexagonTargetHandler.h"
+
+using namespace lld::elf;
+
+std::unique_ptr<lld::ELFLinkingContext>
+HexagonLinkingContext::create(llvm::Triple triple) {
+ if (triple.getArch() == llvm::Triple::hexagon)
+ return std::unique_ptr<lld::ELFLinkingContext>(
+ new HexagonLinkingContext(triple));
+ return nullptr;
+}
+
+HexagonLinkingContext::HexagonLinkingContext(llvm::Triple triple)
+ : ELFLinkingContext(triple, std::unique_ptr<TargetHandlerBase>(
+ new HexagonTargetHandler(*this))) {}
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.h b/lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.h
new file mode 100644
index 0000000000000..c920cdf153aaf
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.h
@@ -0,0 +1,69 @@
+//===- lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.h ---------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_LINKING_CONTEXT_H
+#define LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_LINKING_CONTEXT_H
+
+#include "lld/ReaderWriter/ELFLinkingContext.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/ELF.h"
+
+namespace lld {
+namespace elf {
+
+typedef llvm::object::ELFType<llvm::support::little, 2, false> HexagonELFType;
+
+class HexagonLinkingContext final : public ELFLinkingContext {
+public:
+ static std::unique_ptr<ELFLinkingContext> create(llvm::Triple);
+ HexagonLinkingContext(llvm::Triple triple);
+
+ void addPasses(PassManager &) override;
+
+ bool isDynamicRelocation(const Reference &r) const override {
+ if (r.kindNamespace() != Reference::KindNamespace::ELF)
+ return false;
+ switch (r.kindValue()) {
+ case llvm::ELF::R_HEX_RELATIVE:
+ case llvm::ELF::R_HEX_GLOB_DAT:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ bool isPLTRelocation(const Reference &r) const override {
+ if (r.kindNamespace() != Reference::KindNamespace::ELF)
+ return false;
+ switch (r.kindValue()) {
+ case llvm::ELF::R_HEX_JMP_SLOT:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /// \brief Hexagon has only one relative relocation
+ /// a) for supporting relative relocs - R_HEX_RELATIVE
+ bool isRelativeReloc(const Reference &r) const override {
+ if (r.kindNamespace() != Reference::KindNamespace::ELF)
+ return false;
+ switch (r.kindValue()) {
+ case llvm::ELF::R_HEX_RELATIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+};
+
+} // elf
+} // lld
+
+#endif // LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_LINKING_CONTEXT_H
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationFunctions.h b/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationFunctions.h
new file mode 100644
index 0000000000000..2b9e25ce363b5
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationFunctions.h
@@ -0,0 +1,49 @@
+//===- HexagonRelocationFunction.h ----------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_RELOCATION_FUNCTIONS_H
+#define LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_RELOCATION_FUNCTIONS_H
+
+namespace lld {
+namespace elf {
+
+/// \brief HexagonInstruction which is used to store various values
+typedef struct {
+ uint32_t insnMask;
+ uint32_t insnCmpMask;
+ uint32_t insnBitMask;
+ bool isDuplex;
+} Instruction;
+
+#include "HexagonEncodings.h"
+
+#define FINDV4BITMASK(INSN) \
+ findBitMask((uint32_t) * ((llvm::support::ulittle32_t *) INSN), \
+ insn_encodings, \
+ sizeof(insn_encodings) / sizeof(Instruction))
+
+/// \brief finds the scatter Bits that need to be used to apply relocations
+inline uint32_t
+findBitMask(uint32_t insn, Instruction *encodings, int32_t numInsns) {
+ for (int32_t i = 0; i < numInsns; i++) {
+ if (((insn & 0xc000) == 0) && !(encodings[i].isDuplex))
+ continue;
+
+ if (((insn & 0xc000) != 0) && (encodings[i].isDuplex))
+ continue;
+
+ if (((encodings[i].insnMask) & insn) == encodings[i].insnCmpMask)
+ return encodings[i].insnBitMask;
+ }
+ llvm_unreachable("found unknown instruction");
+}
+
+} // elf
+} // lld
+
+#endif // LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_RELOCATION_FUNCTIONS_H
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.cpp b/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.cpp
new file mode 100644
index 0000000000000..21967d356a311
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.cpp
@@ -0,0 +1,350 @@
+//===- lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.cpp ---------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "HexagonLinkingContext.h"
+#include "HexagonRelocationFunctions.h"
+#include "HexagonTargetHandler.h"
+#include "HexagonRelocationHandler.h"
+#include "llvm/Support/Endian.h"
+
+using namespace lld;
+using namespace lld::elf;
+using namespace llvm::ELF;
+using namespace llvm::support::endian;
+
+#define APPLY_RELOC(result) \
+ write32le(location, result | read32le(location));
+
+static int relocBNPCREL(uint8_t *location, uint64_t P, uint64_t S, uint64_t A,
+ int32_t nBits) {
+ int32_t result = (uint32_t)(((S + A) - P) >> 2);
+ int32_t range = 1 << nBits;
+ if (result < range && result > -range) {
+ result = lld::scatterBits<int32_t>(result, FINDV4BITMASK(location));
+ APPLY_RELOC(result);
+ return 0;
+ }
+ return 1;
+}
+
+/// \brief Word32_LO: 0x00c03fff : (S + A) : Truncate
+static int relocLO16(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) {
+ uint32_t result = (uint32_t)(S + A);
+ result = lld::scatterBits<int32_t>(result, 0x00c03fff);
+ APPLY_RELOC(result);
+ return 0;
+}
+
+/// \brief Word32_LO: 0x00c03fff : (S + A) >> 16 : Truncate
+static int relocHI16(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) {
+ uint32_t result = (uint32_t)((S + A) >> 16);
+ result = lld::scatterBits<int32_t>(result, 0x00c03fff);
+ APPLY_RELOC(result);
+ return 0;
+}
+
+/// \brief Word32: 0xffffffff : (S + A) : Truncate
+static int reloc32(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) {
+ uint32_t result = (uint32_t)(S + A);
+ APPLY_RELOC(result);
+ return 0;
+}
+
+static int reloc32_6_X(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) {
+ int64_t result = ((S + A) >> 6);
+ int64_t range = ((int64_t)1) << 32;
+ if (result > range)
+ return 1;
+ result = lld::scatterBits<int32_t>(result, 0xfff3fff);
+ APPLY_RELOC(result);
+ return 0;
+}
+
+// R_HEX_B32_PCREL_X
+static int relocHexB32PCRELX(uint8_t *location, uint64_t P, uint64_t S,
+ uint64_t A) {
+ int64_t result = ((S + A - P) >> 6);
+ result = lld::scatterBits<int32_t>(result, 0xfff3fff);
+ APPLY_RELOC(result);
+ return 0;
+}
+
+// R_HEX_BN_PCREL_X
+static int relocHexBNPCRELX(uint8_t *location, uint64_t P, uint64_t S,
+ uint64_t A, int nbits) {
+ int32_t result = ((S + A - P) & 0x3f);
+ int32_t range = 1 << nbits;
+ if (result < range && result > -range) {
+ result = lld::scatterBits<int32_t>(result, FINDV4BITMASK(location));
+ APPLY_RELOC(result);
+ return 0;
+ }
+ return 1;
+}
+
+// R_HEX_6_PCREL_X
+static int relocHex6PCRELX(uint8_t *location, uint64_t P, uint64_t S,
+ uint64_t A) {
+ int32_t result = (S + A - P);
+ result = lld::scatterBits<int32_t>(result, FINDV4BITMASK(location));
+ APPLY_RELOC(result);
+ return 0;
+}
+
+// R_HEX_N_X : Word32_U6 : (S + A) : Unsigned Truncate
+static int relocHex_N_X(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) {
+ uint32_t result = (S + A);
+ result = lld::scatterBits<uint32_t>(result, FINDV4BITMASK(location));
+ APPLY_RELOC(result);
+ return 0;
+}
+
+// GP REL relocations
+static int relocHexGPRELN(uint8_t *location, uint64_t P, uint64_t S, uint64_t A,
+ uint64_t GP, int nShiftBits) {
+ int32_t result = (int64_t)((S + A - GP) >> nShiftBits);
+ int32_t range = 1L << 16;
+ if (result <= range) {
+ result = lld::scatterBits<uint32_t>(result, FINDV4BITMASK(location));
+ APPLY_RELOC(result);
+ return 0;
+ }
+ return 1;
+}
+
+/// \brief Word32_LO: 0x00c03fff : (G) : Truncate
+static int relocHexGOTLO16(uint8_t *location, uint64_t A, uint64_t GOT) {
+ int32_t result = (int32_t)(A-GOT);
+ result = lld::scatterBits<int32_t>(result, 0x00c03fff);
+ APPLY_RELOC(result);
+ return 0;
+}
+
+/// \brief Word32_LO: 0x00c03fff : (G) >> 16 : Truncate
+static int relocHexGOTHI16(uint8_t *location, uint64_t A, uint64_t GOT) {
+ int32_t result = (int32_t)((A-GOT) >> 16);
+ result = lld::scatterBits<int32_t>(result, 0x00c03fff);
+ APPLY_RELOC(result);
+ return 0;
+}
+
+/// \brief Word32: 0xffffffff : (G) : Truncate
+static int relocHexGOT32(uint8_t *location, uint64_t A, uint64_t GOT) {
+ int32_t result = (int32_t)(GOT - A);
+ APPLY_RELOC(result);
+ return 0;
+}
+
+/// \brief Word32_U16 : (G) : Truncate
+static int relocHexGOT16(uint8_t *location, uint64_t A, uint64_t GOT) {
+ int32_t result = (int32_t)(GOT-A);
+ int32_t range = 1L << 16;
+ if (result <= range) {
+ result = lld::scatterBits<int32_t>(result, FINDV4BITMASK(location));
+ APPLY_RELOC(result);
+ return 0;
+ }
+ return 1;
+}
+
+static int relocHexGOT32_6_X(uint8_t *location, uint64_t A, uint64_t GOT) {
+ int32_t result = (int32_t)((A-GOT) >> 6);
+ result = lld::scatterBits<int32_t>(result, FINDV4BITMASK(location));
+ APPLY_RELOC(result);
+ return 0;
+}
+
+static int relocHexGOT16_X(uint8_t *location, uint64_t A, uint64_t GOT) {
+ int32_t result = (int32_t)(A-GOT);
+ int32_t range = 1L << 6;
+ if (result <= range) {
+ result = lld::scatterBits<int32_t>(result, FINDV4BITMASK(location));
+ APPLY_RELOC(result);
+ return 0;
+ }
+ return 1;
+}
+
+static int relocHexGOT11_X(uint8_t *location, uint64_t A, uint64_t GOT) {
+ uint32_t result = (uint32_t)(A-GOT);
+ result = lld::scatterBits<uint32_t>(result, FINDV4BITMASK(location));
+ APPLY_RELOC(result);
+ return 0;
+}
+
+static int relocHexGOTRELSigned(uint8_t *location, uint64_t P, uint64_t S,
+ uint64_t A, uint64_t GOT, int shiftBits = 0) {
+ int32_t result = (int32_t)((S + A - GOT) >> shiftBits);
+ result = lld::scatterBits<int32_t>(result, FINDV4BITMASK(location));
+ APPLY_RELOC(result);
+ return 0;
+}
+
+static int relocHexGOTRELUnsigned(uint8_t *location, uint64_t P, uint64_t S,
+ uint64_t A, uint64_t GOT, int shiftBits = 0) {
+ uint32_t result = (uint32_t)((S + A - GOT) >> shiftBits);
+ result = lld::scatterBits<uint32_t>(result, FINDV4BITMASK(location));
+ APPLY_RELOC(result);
+ return 0;
+}
+
+static int relocHexGOTREL_HILO16(uint8_t *location, uint64_t P, uint64_t S,
+ uint64_t A, uint64_t GOT, int shiftBits = 0) {
+ int32_t result = (int32_t)((S + A - GOT) >> shiftBits);
+ result = lld::scatterBits<int32_t>(result, 0x00c03fff);
+ APPLY_RELOC(result);
+ return 0;
+}
+
+static int relocHexGOTREL_32(uint8_t *location, uint64_t P, uint64_t S,
+ uint64_t A, uint64_t GOT) {
+ int32_t result = (int32_t)(S + A - GOT);
+ APPLY_RELOC(result);
+ return 0;
+}
+
+std::error_code HexagonTargetRelocationHandler::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::Hexagon);
+ switch (ref.kindValue()) {
+ case R_HEX_B22_PCREL:
+ relocBNPCREL(location, relocVAddress, targetVAddress, ref.addend(), 21);
+ break;
+ case R_HEX_B15_PCREL:
+ relocBNPCREL(location, relocVAddress, targetVAddress, ref.addend(), 14);
+ break;
+ case R_HEX_B9_PCREL:
+ relocBNPCREL(location, relocVAddress, targetVAddress, ref.addend(), 8);
+ break;
+ case R_HEX_LO16:
+ relocLO16(location, relocVAddress, targetVAddress, ref.addend());
+ break;
+ case R_HEX_HI16:
+ relocHI16(location, relocVAddress, targetVAddress, ref.addend());
+ break;
+ case R_HEX_32:
+ reloc32(location, relocVAddress, targetVAddress, ref.addend());
+ break;
+ case R_HEX_32_6_X:
+ reloc32_6_X(location, relocVAddress, targetVAddress, ref.addend());
+ break;
+ case R_HEX_B32_PCREL_X:
+ relocHexB32PCRELX(location, relocVAddress, targetVAddress, ref.addend());
+ break;
+ case R_HEX_B22_PCREL_X:
+ relocHexBNPCRELX(location, relocVAddress, targetVAddress, ref.addend(), 21);
+ break;
+ case R_HEX_B15_PCREL_X:
+ relocHexBNPCRELX(location, relocVAddress, targetVAddress, ref.addend(), 14);
+ break;
+ case R_HEX_B13_PCREL_X:
+ relocHexBNPCRELX(location, relocVAddress, targetVAddress, ref.addend(), 12);
+ break;
+ case R_HEX_B9_PCREL_X:
+ relocHexBNPCRELX(location, relocVAddress, targetVAddress, ref.addend(), 8);
+ break;
+ case R_HEX_B7_PCREL_X:
+ relocHexBNPCRELX(location, relocVAddress, targetVAddress, ref.addend(), 6);
+ break;
+ case R_HEX_GPREL16_0:
+ relocHexGPRELN(location, relocVAddress, targetVAddress, ref.addend(),
+ _hexagonTargetLayout.getSDataSection()->virtualAddr(), 0);
+ break;
+ case R_HEX_GPREL16_1:
+ relocHexGPRELN(location, relocVAddress, targetVAddress, ref.addend(),
+ _hexagonTargetLayout.getSDataSection()->virtualAddr(), 1);
+ break;
+ case R_HEX_GPREL16_2:
+ relocHexGPRELN(location, relocVAddress, targetVAddress, ref.addend(),
+ _hexagonTargetLayout.getSDataSection()->virtualAddr(), 2);
+ break;
+ case R_HEX_GPREL16_3:
+ relocHexGPRELN(location, relocVAddress, targetVAddress, ref.addend(),
+ _hexagonTargetLayout.getSDataSection()->virtualAddr(), 3);
+ break;
+ case R_HEX_16_X:
+ case R_HEX_12_X:
+ case R_HEX_11_X:
+ case R_HEX_10_X:
+ case R_HEX_9_X:
+ case R_HEX_8_X:
+ case R_HEX_7_X:
+ case R_HEX_6_X:
+ relocHex_N_X(location, relocVAddress, targetVAddress, ref.addend());
+ break;
+ case R_HEX_6_PCREL_X:
+ relocHex6PCRELX(location, relocVAddress, targetVAddress, ref.addend());
+ break;
+ case R_HEX_JMP_SLOT:
+ case R_HEX_GLOB_DAT:
+ break;
+ case R_HEX_GOTREL_32:
+ relocHexGOTREL_32(location, relocVAddress, targetVAddress, ref.addend(),
+ _hexagonTargetLayout.getGOTSymAddr());
+ break;
+ case R_HEX_GOTREL_LO16:
+ relocHexGOTREL_HILO16(location, relocVAddress, targetVAddress, ref.addend(),
+ _hexagonTargetLayout.getGOTSymAddr());
+ break;
+ case R_HEX_GOTREL_HI16:
+ relocHexGOTREL_HILO16(location, relocVAddress, targetVAddress, ref.addend(),
+ _hexagonTargetLayout.getGOTSymAddr(), 16);
+ break;
+ case R_HEX_GOT_LO16:
+ relocHexGOTLO16(location, targetVAddress,
+ _hexagonTargetLayout.getGOTSymAddr());
+ break;
+ case R_HEX_GOT_HI16:
+ relocHexGOTHI16(location, targetVAddress,
+ _hexagonTargetLayout.getGOTSymAddr());
+ break;
+ case R_HEX_GOT_32:
+ relocHexGOT32(location, targetVAddress,
+ _hexagonTargetLayout.getGOTSymAddr());
+ break;
+ case R_HEX_GOT_16:
+ relocHexGOT16(location, targetVAddress,
+ _hexagonTargetLayout.getGOTSymAddr());
+ break;
+ case R_HEX_GOT_32_6_X:
+ relocHexGOT32_6_X(location, targetVAddress,
+ _hexagonTargetLayout.getGOTSymAddr());
+ break;
+ case R_HEX_GOT_16_X:
+ relocHexGOT16_X(location, targetVAddress,
+ _hexagonTargetLayout.getGOTSymAddr());
+ break;
+ case R_HEX_GOT_11_X:
+ relocHexGOT11_X(location, targetVAddress,
+ _hexagonTargetLayout.getGOTSymAddr());
+ break;
+ case R_HEX_GOTREL_32_6_X:
+ relocHexGOTRELSigned(location, relocVAddress, targetVAddress, ref.addend(),
+ _hexagonTargetLayout.getGOTSymAddr(), 6);
+ break;
+ case R_HEX_GOTREL_16_X:
+ case R_HEX_GOTREL_11_X:
+ relocHexGOTRELUnsigned(location, relocVAddress, targetVAddress,
+ ref.addend(), _hexagonTargetLayout.getGOTSymAddr());
+ break;
+
+ default:
+ return make_unhandled_reloc_error();
+ }
+
+ return std::error_code();
+}
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.h b/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.h
new file mode 100644
index 0000000000000..4795d0264b9cd
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.h
@@ -0,0 +1,35 @@
+//===- lld/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.h -----------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_RELOCATION_HANDLER_H
+#define LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_RELOCATION_HANDLER_H
+
+#include "HexagonSectionChunks.h"
+#include "HexagonTargetHandler.h"
+#include "lld/ReaderWriter/RelocationHelperFunctions.h"
+
+namespace lld {
+namespace elf {
+
+class HexagonTargetHandler;
+
+class HexagonTargetRelocationHandler final : public TargetRelocationHandler {
+public:
+ HexagonTargetRelocationHandler(HexagonTargetLayout<HexagonELFType> &layout)
+ : _hexagonTargetLayout(layout) {}
+
+ std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &,
+ const lld::AtomLayout &,
+ const Reference &) const override;
+
+private:
+ HexagonTargetLayout<HexagonELFType> &_hexagonTargetLayout;
+};
+} // elf
+} // lld
+#endif
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonSectionChunks.h b/lib/ReaderWriter/ELF/Hexagon/HexagonSectionChunks.h
new file mode 100644
index 0000000000000..5b3fbbbd899be
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Hexagon/HexagonSectionChunks.h
@@ -0,0 +1,86 @@
+//===- lib/ReaderWriter/ELF/Hexagon/HexagonSectionChunks.h-----------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef HEXAGON_SECTION_CHUNKS_H
+#define HEXAGON_SECTION_CHUNKS_H
+
+#include "HexagonTargetHandler.h"
+
+namespace lld {
+namespace elf {
+template <typename ELFT> class HexagonTargetLayout;
+class HexagonLinkingContext;
+
+/// \brief Handle Hexagon SData section
+template <class HexagonELFType>
+class SDataSection : public AtomSection<HexagonELFType> {
+public:
+ SDataSection(const HexagonLinkingContext &context)
+ : AtomSection<HexagonELFType>(
+ context, ".sdata", DefinedAtom::typeDataFast, 0,
+ HexagonTargetLayout<HexagonELFType>::ORDER_SDATA) {
+ this->_type = SHT_PROGBITS;
+ this->_flags = SHF_ALLOC | SHF_WRITE;
+ this->_alignment = 4096;
+ }
+
+ /// \brief Finalize the section contents before writing
+ virtual void doPreFlight();
+
+ /// \brief Does this section have an output segment.
+ virtual bool hasOutputSegment() { return true; }
+
+ const lld::AtomLayout *appendAtom(const Atom *atom) {
+ const DefinedAtom *definedAtom = cast<DefinedAtom>(atom);
+ DefinedAtom::Alignment atomAlign = definedAtom->alignment();
+ uint64_t alignment = 1u << atomAlign.powerOf2;
+ this->_atoms.push_back(new (this->_alloc) lld::AtomLayout(atom, 0, 0));
+ // Set the section alignment to the largest alignment
+ // std::max doesn't support uint64_t
+ if (this->_alignment < alignment)
+ this->_alignment = alignment;
+ return (this->_atoms.back());
+ }
+
+}; // SDataSection
+
+template <class HexagonELFType>
+void SDataSection<HexagonELFType>::doPreFlight() {
+ // sort the atoms on the alignments they have been set
+ std::stable_sort(this->_atoms.begin(), this->_atoms.end(),
+ [](const lld::AtomLayout * A,
+ const lld::AtomLayout * B) {
+ const DefinedAtom *definedAtomA = cast<DefinedAtom>(A->_atom);
+ const DefinedAtom *definedAtomB = cast<DefinedAtom>(B->_atom);
+ int64_t alignmentA = 1 << definedAtomA->alignment().powerOf2;
+ int64_t alignmentB = 1 << definedAtomB->alignment().powerOf2;
+ if (alignmentA == alignmentB) {
+ if (definedAtomA->merge() == DefinedAtom::mergeAsTentative)
+ return false;
+ if (definedAtomB->merge() == DefinedAtom::mergeAsTentative)
+ return true;
+ }
+ return alignmentA < alignmentB;
+ });
+
+ // Set the fileOffset, and the appropriate size of the section
+ for (auto &ai : this->_atoms) {
+ const DefinedAtom *definedAtom = cast<DefinedAtom>(ai->_atom);
+ DefinedAtom::Alignment atomAlign = definedAtom->alignment();
+ uint64_t fOffset = this->alignOffset(this->fileSize(), atomAlign);
+ uint64_t mOffset = this->alignOffset(this->memSize(), atomAlign);
+ ai->_fileOffset = fOffset;
+ this->_fsize = fOffset + definedAtom->size();
+ this->_msize = mOffset + definedAtom->size();
+ }
+} // finalize
+
+} // elf
+} // lld
+
+#endif // LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_SECTION_CHUNKS_H
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.cpp b/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.cpp
new file mode 100644
index 0000000000000..9b10c2f160f41
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.cpp
@@ -0,0 +1,334 @@
+//===- lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.cpp --------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "HexagonExecutableWriter.h"
+#include "HexagonDynamicLibraryWriter.h"
+#include "HexagonLinkingContext.h"
+#include "HexagonTargetHandler.h"
+
+using namespace lld;
+using namespace elf;
+using namespace llvm::ELF;
+
+using llvm::makeArrayRef;
+
+HexagonTargetHandler::HexagonTargetHandler(HexagonLinkingContext &context)
+ : _hexagonLinkingContext(context),
+ _hexagonRuntimeFile(new HexagonRuntimeFile<HexagonELFType>(context)),
+ _hexagonTargetLayout(new HexagonTargetLayout<HexagonELFType>(context)),
+ _hexagonRelocationHandler(new HexagonTargetRelocationHandler(
+ *_hexagonTargetLayout.get())) {}
+
+std::unique_ptr<Writer> HexagonTargetHandler::getWriter() {
+ switch (_hexagonLinkingContext.getOutputELFType()) {
+ case llvm::ELF::ET_EXEC:
+ return std::unique_ptr<Writer>(
+ new elf::HexagonExecutableWriter<HexagonELFType>(
+ _hexagonLinkingContext, *_hexagonTargetLayout.get()));
+ case llvm::ELF::ET_DYN:
+ return std::unique_ptr<Writer>(
+ new elf::HexagonDynamicLibraryWriter<HexagonELFType>(
+ _hexagonLinkingContext, *_hexagonTargetLayout.get()));
+ case llvm::ELF::ET_REL:
+ llvm_unreachable("TODO: support -r mode");
+ default:
+ llvm_unreachable("unsupported output type");
+ }
+}
+
+using namespace llvm::ELF;
+
+// .got atom
+const uint8_t hexagonGotAtomContent[4] = { 0 };
+// .got.plt atom (entry 0)
+const uint8_t hexagonGotPlt0AtomContent[16] = { 0 };
+// .got.plt atom (all other entries)
+const uint8_t hexagonGotPltAtomContent[4] = { 0 };
+// .plt (entry 0)
+const uint8_t hexagonPlt0AtomContent[28] = {
+ 0x00, 0x40, 0x00, 0x00, // { immext (#0)
+ 0x1c, 0xc0, 0x49, 0x6a, // r28 = add (pc, ##GOT0@PCREL) } # address of GOT0
+ 0x0e, 0x42, 0x9c, 0xe2, // { r14 -= add (r28, #16) # offset of GOTn from GOTa
+ 0x4f, 0x40, 0x9c, 0x91, // r15 = memw (r28 + #8) # object ID at GOT2
+ 0x3c, 0xc0, 0x9c, 0x91, // r28 = memw (r28 + #4) }# dynamic link at GOT1
+ 0x0e, 0x42, 0x0e, 0x8c, // { r14 = asr (r14, #2) # index of PLTn
+ 0x00, 0xc0, 0x9c, 0x52, // jumpr r28 } # call dynamic linker
+};
+
+// .plt (other entries)
+const uint8_t hexagonPltAtomContent[16] = {
+ 0x00, 0x40, 0x00, 0x00, // { immext (#0)
+ 0x0e, 0xc0, 0x49, 0x6a, // r14 = add (pc, ##GOTn@PCREL) } # address of GOTn
+ 0x1c, 0xc0, 0x8e, 0x91, // r28 = memw (r14) # contents of GOTn
+ 0x00, 0xc0, 0x9c, 0x52, // jumpr r28 # call it
+};
+
+class HexagonGOTAtom : public GOTAtom {
+public:
+ HexagonGOTAtom(const File &f) : GOTAtom(f, ".got") {}
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return makeArrayRef(hexagonGotAtomContent);
+ }
+
+ Alignment alignment() const override { return Alignment(2); }
+};
+
+class HexagonGOTPLTAtom : public GOTAtom {
+public:
+ HexagonGOTPLTAtom(const File &f) : GOTAtom(f, ".got.plt") {}
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return makeArrayRef(hexagonGotPltAtomContent);
+ }
+
+ Alignment alignment() const override { return Alignment(2); }
+};
+
+class HexagonGOTPLT0Atom : public GOTAtom {
+public:
+ HexagonGOTPLT0Atom(const File &f) : GOTAtom(f, ".got.plt") {}
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return makeArrayRef(hexagonGotPlt0AtomContent);
+ }
+
+ Alignment alignment() const override { return Alignment(3); }
+};
+
+class HexagonPLT0Atom : public PLT0Atom {
+public:
+ HexagonPLT0Atom(const File &f) : PLT0Atom(f) {}
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return makeArrayRef(hexagonPlt0AtomContent);
+ }
+};
+
+class HexagonPLTAtom : public PLTAtom {
+
+public:
+ HexagonPLTAtom(const File &f, StringRef secName) : PLTAtom(f, secName) {}
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return makeArrayRef(hexagonPltAtomContent);
+ }
+};
+
+class ELFPassFile : public SimpleFile {
+public:
+ ELFPassFile(const ELFLinkingContext &eti) : SimpleFile("ELFPassFile") {
+ setOrdinal(eti.getNextOrdinalAndIncrement());
+ }
+
+ llvm::BumpPtrAllocator _alloc;
+};
+
+/// \brief Create GOT and PLT entries for relocations. Handles standard GOT/PLT
+template <class Derived> class GOTPLTPass : public Pass {
+ /// \brief Handle a specific reference.
+ void handleReference(const DefinedAtom &atom, const Reference &ref) {
+ if (ref.kindNamespace() != Reference::KindNamespace::ELF)
+ return;
+ assert(ref.kindArch() == Reference::KindArch::Hexagon);
+ switch (ref.kindValue()) {
+ case R_HEX_PLT_B22_PCREL:
+ case R_HEX_B22_PCREL:
+ static_cast<Derived *>(this)->handlePLT32(ref);
+ break;
+ case R_HEX_GOT_LO16:
+ case R_HEX_GOT_HI16:
+ case R_HEX_GOT_32_6_X:
+ case R_HEX_GOT_16_X:
+ case R_HEX_GOT_11_X:
+ static_cast<Derived *>(this)->handleGOTREL(ref);
+ break;
+ }
+ }
+
+protected:
+ /// \brief Create a GOT entry containing 0.
+ const GOTAtom *getNullGOT() {
+ if (!_null) {
+ _null = new (_file._alloc) HexagonGOTPLTAtom(_file);
+#ifndef NDEBUG
+ _null->_name = "__got_null";
+#endif
+ }
+ return _null;
+ }
+
+public:
+ GOTPLTPass(const ELFLinkingContext &ctx)
+ : _file(ctx), _null(nullptr), _PLT0(nullptr), _got0(nullptr) {}
+
+ /// \brief Do the pass.
+ ///
+ /// The goal here is to first process each reference individually. Each call
+ /// to handleReference may modify the reference itself and/or create new
+ /// atoms which must be stored in one of the maps below.
+ ///
+ /// After all references are handled, the atoms created during that are all
+ /// added to mf.
+ void perform(std::unique_ptr<MutableFile> &mf) override {
+ // Process all references.
+ for (const auto &atom : mf->defined())
+ for (const auto &ref : *atom)
+ handleReference(*atom, *ref);
+
+ // Add all created atoms to the link.
+ uint64_t ordinal = 0;
+ if (_PLT0) {
+ _PLT0->setOrdinal(ordinal++);
+ mf->addAtom(*_PLT0);
+ }
+ for (auto &plt : _pltVector) {
+ plt->setOrdinal(ordinal++);
+ mf->addAtom(*plt);
+ }
+ if (_null) {
+ _null->setOrdinal(ordinal++);
+ mf->addAtom(*_null);
+ }
+ if (_got0) {
+ _got0->setOrdinal(ordinal++);
+ mf->addAtom(*_got0);
+ }
+ for (auto &got : _gotVector) {
+ got->setOrdinal(ordinal++);
+ mf->addAtom(*got);
+ }
+ }
+
+protected:
+ /// \brief Owner of all the Atoms created by this pass.
+ ELFPassFile _file;
+
+ /// \brief Map Atoms to their GOT entries.
+ llvm::DenseMap<const Atom *, GOTAtom *> _gotMap;
+
+ /// \brief Map Atoms to their PLT entries.
+ llvm::DenseMap<const Atom *, PLTAtom *> _pltMap;
+
+ /// \brief the list of GOT/PLT atoms
+ std::vector<GOTAtom *> _gotVector;
+ std::vector<PLTAtom *> _pltVector;
+
+ /// \brief GOT entry that is always 0. Used for undefined weaks.
+ GOTAtom *_null;
+
+ /// \brief The got and plt entries for .PLT0. This is used to call into the
+ /// dynamic linker for symbol resolution.
+ /// @{
+ PLT0Atom *_PLT0;
+ GOTAtom *_got0;
+ /// @}
+};
+
+class DynamicGOTPLTPass final : public GOTPLTPass<DynamicGOTPLTPass> {
+public:
+ DynamicGOTPLTPass(const elf::HexagonLinkingContext &ctx) : GOTPLTPass(ctx) {
+ _got0 = new (_file._alloc) HexagonGOTPLT0Atom(_file);
+#ifndef NDEBUG
+ _got0->_name = "__got0";
+#endif
+ }
+
+ const PLT0Atom *getPLT0() {
+ if (_PLT0)
+ return _PLT0;
+ _PLT0 = new (_file._alloc) HexagonPLT0Atom(_file);
+ _PLT0->addReferenceELF_Hexagon(R_HEX_B32_PCREL_X, 0, _got0, 0);
+ _PLT0->addReferenceELF_Hexagon(R_HEX_6_PCREL_X, 4, _got0, 4);
+ DEBUG_WITH_TYPE("PLT", llvm::dbgs() << "[ PLT0/GOT0 ] "
+ << "Adding plt0/got0 \n");
+ 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) HexagonGOTPLTAtom(_file);
+ ga->addReferenceELF_Hexagon(R_HEX_JMP_SLOT, 0, a, 0);
+ auto pa = new (_file._alloc) HexagonPLTAtom(_file, ".plt");
+ pa->addReferenceELF_Hexagon(R_HEX_B32_PCREL_X, 0, ga, 0);
+ pa->addReferenceELF_Hexagon(R_HEX_6_PCREL_X, 4, ga, 4);
+
+ // Point the got entry to the PLT0 atom initially
+ ga->addReferenceELF_Hexagon(R_HEX_32, 0, getPLT0(), 0);
+#ifndef NDEBUG
+ ga->_name = "__got_";
+ ga->_name += a->name();
+ pa->_name = "__plt_";
+ pa->_name += a->name();
+ DEBUG_WITH_TYPE("PLT", llvm::dbgs() << "[" << a->name() << "] "
+ << "Adding plt/got: " << pa->_name
+ << "/" << ga->_name << "\n");
+#endif
+ _gotMap[a] = ga;
+ _pltMap[a] = pa;
+ _gotVector.push_back(ga);
+ _pltVector.push_back(pa);
+ return pa;
+ }
+
+ const GOTAtom *getGOTEntry(const Atom *a) {
+ auto got = _gotMap.find(a);
+ if (got != _gotMap.end())
+ return got->second;
+ auto ga = new (_file._alloc) HexagonGOTAtom(_file);
+ ga->addReferenceELF_Hexagon(R_HEX_GLOB_DAT, 0, a, 0);
+
+#ifndef NDEBUG
+ ga->_name = "__got_";
+ ga->_name += a->name();
+ DEBUG_WITH_TYPE("GOT", llvm::dbgs() << "[" << a->name() << "] "
+ << "Adding got: " << ga->_name << "\n");
+#endif
+ _gotMap[a] = ga;
+ _gotVector.push_back(ga);
+ return ga;
+ }
+
+ std::error_code handleGOTREL(const Reference &ref) {
+ // Turn this so that the target is set to the GOT entry
+ const_cast<Reference &>(ref).setTarget(getGOTEntry(ref.target()));
+ return std::error_code();
+ }
+
+ std::error_code handlePLT32(const Reference &ref) {
+ // Turn this into a PC32 to the PLT entry.
+ assert(ref.kindNamespace() == Reference::KindNamespace::ELF);
+ assert(ref.kindArch() == Reference::KindArch::Hexagon);
+ const_cast<Reference &>(ref).setKindValue(R_HEX_B22_PCREL);
+ const_cast<Reference &>(ref).setTarget(getPLTEntry(ref.target()));
+ return std::error_code();
+ }
+};
+
+void elf::HexagonLinkingContext::addPasses(PassManager &pm) {
+ if (isDynamic())
+ pm.add(llvm::make_unique<DynamicGOTPLTPass>(*this));
+ ELFLinkingContext::addPasses(pm);
+}
+
+void HexagonTargetHandler::registerRelocationNames(Registry &registry) {
+ registry.addKindTable(Reference::KindNamespace::ELF,
+ Reference::KindArch::Hexagon, kindStrings);
+}
+
+#define ELF_RELOC(name, value) LLD_KIND_STRING_ENTRY(name),
+
+const Registry::KindStrings HexagonTargetHandler::kindStrings[] = {
+#include "llvm/Support/ELFRelocs/Hexagon.def"
+ LLD_KIND_STRING_END
+};
+
+#undef ELF_RELOC
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.h b/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.h
new file mode 100644
index 0000000000000..f4315f710ec7c
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.h
@@ -0,0 +1,143 @@
+//===- lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.h ----------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef HEXAGON_TARGET_HANDLER_H
+#define HEXAGON_TARGET_HANDLER_H
+
+#include "DefaultTargetHandler.h"
+#include "HexagonELFReader.h"
+#include "HexagonExecutableAtoms.h"
+#include "HexagonRelocationHandler.h"
+#include "HexagonSectionChunks.h"
+#include "TargetLayout.h"
+
+namespace lld {
+namespace elf {
+class HexagonLinkingContext;
+
+/// \brief TargetLayout for Hexagon
+template <class HexagonELFType>
+class HexagonTargetLayout final : public TargetLayout<HexagonELFType> {
+public:
+ enum HexagonSectionOrder {
+ ORDER_SDATA = 205
+ };
+
+ HexagonTargetLayout(HexagonLinkingContext &hti)
+ : TargetLayout<HexagonELFType>(hti), _sdataSection(nullptr),
+ _gotSymAtom(nullptr), _cachedGotSymAtom(false) {
+ _sdataSection = new (_alloc) SDataSection<HexagonELFType>(hti);
+ }
+
+ /// \brief Return the section order for a input section
+ virtual Layout::SectionOrder getSectionOrder(
+ StringRef name, int32_t contentType, int32_t contentPermissions) {
+ if ((contentType == DefinedAtom::typeDataFast) ||
+ (contentType == DefinedAtom::typeZeroFillFast))
+ return ORDER_SDATA;
+
+ return DefaultLayout<HexagonELFType>::getSectionOrder(name, contentType,
+ contentPermissions);
+ }
+
+ /// \brief Return the appropriate input section name.
+ virtual StringRef getInputSectionName(const DefinedAtom *da) const {
+ switch (da->contentType()) {
+ case DefinedAtom::typeDataFast:
+ case DefinedAtom::typeZeroFillFast:
+ return ".sdata";
+ default:
+ break;
+ }
+ return DefaultLayout<HexagonELFType>::getInputSectionName(da);
+ }
+
+ /// \brief Gets or creates a section.
+ virtual AtomSection<HexagonELFType> *
+ createSection(StringRef name, int32_t contentType,
+ DefinedAtom::ContentPermissions contentPermissions,
+ Layout::SectionOrder sectionOrder) {
+ if ((contentType == DefinedAtom::typeDataFast) ||
+ (contentType == DefinedAtom::typeZeroFillFast))
+ return _sdataSection;
+ return DefaultLayout<HexagonELFType>::createSection(
+ name, contentType, contentPermissions, sectionOrder);
+ }
+
+ /// \brief get the segment type for the section thats defined by the target
+ virtual Layout::SegmentType
+ getSegmentType(Section<HexagonELFType> *section) const {
+ if (section->order() == ORDER_SDATA)
+ return PT_LOAD;
+
+ return DefaultLayout<HexagonELFType>::getSegmentType(section);
+ }
+
+ Section<HexagonELFType> *getSDataSection() const {
+ return _sdataSection;
+ }
+
+ uint64_t getGOTSymAddr() {
+ if (!_cachedGotSymAtom) {
+ auto gotAtomIter = this->findAbsoluteAtom("_GLOBAL_OFFSET_TABLE_");
+ _gotSymAtom = (*gotAtomIter);
+ _cachedGotSymAtom = true;
+ }
+ if (_gotSymAtom)
+ return _gotSymAtom->_virtualAddr;
+ return 0;
+ }
+
+private:
+ llvm::BumpPtrAllocator _alloc;
+ SDataSection<HexagonELFType> *_sdataSection;
+ AtomLayout *_gotSymAtom;
+ bool _cachedGotSymAtom;
+};
+
+/// \brief TargetHandler for Hexagon
+class HexagonTargetHandler final :
+ public DefaultTargetHandler<HexagonELFType> {
+public:
+ HexagonTargetHandler(HexagonLinkingContext &targetInfo);
+
+ void registerRelocationNames(Registry &registry) override;
+
+ const HexagonTargetRelocationHandler &getRelocationHandler() const override {
+ return *(_hexagonRelocationHandler.get());
+ }
+
+ HexagonTargetLayout<HexagonELFType> &getTargetLayout() override {
+ return *(_hexagonTargetLayout.get());
+ }
+
+ std::unique_ptr<Reader> getObjReader() override {
+ return std::unique_ptr<Reader>(
+ new HexagonELFObjectReader(_hexagonLinkingContext));
+ }
+
+ std::unique_ptr<Reader> getDSOReader() override {
+ return std::unique_ptr<Reader>(
+ new HexagonELFDSOReader(_hexagonLinkingContext));
+ }
+
+ std::unique_ptr<Writer> getWriter() override;
+
+private:
+ llvm::BumpPtrAllocator _alloc;
+ static const Registry::KindStrings kindStrings[];
+ HexagonLinkingContext &_hexagonLinkingContext;
+ std::unique_ptr<HexagonRuntimeFile<HexagonELFType> > _hexagonRuntimeFile;
+ std::unique_ptr<HexagonTargetLayout<HexagonELFType>> _hexagonTargetLayout;
+ std::unique_ptr<HexagonTargetRelocationHandler> _hexagonRelocationHandler;
+};
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/Hexagon/Makefile b/lib/ReaderWriter/ELF/Hexagon/Makefile
new file mode 100644
index 0000000000000..8d6f1a0a3b1ed
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Hexagon/Makefile
@@ -0,0 +1,16 @@
+##===- lld/lib/ReaderWriter/ELF/Hexagon/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 := lldHexagonELFTarget
+USEDLIBS = lldCore.a
+
+CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF/Hexagon -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF
+
+include $(LLD_LEVEL)/Makefile
diff --git a/lib/ReaderWriter/ELF/Layout.h b/lib/ReaderWriter/ELF/Layout.h
new file mode 100644
index 0000000000000..826cf5035d59a
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Layout.h
@@ -0,0 +1,59 @@
+//===- lib/ReaderWriter/ELF/Layout.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_LAYOUT_H
+#define LLD_READER_WRITER_ELF_LAYOUT_H
+
+#include "lld/Core/DefinedAtom.h"
+#include "lld/ReaderWriter/AtomLayout.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ELF.h"
+#include "llvm/Support/ErrorOr.h"
+
+namespace lld {
+namespace elf {
+
+/// \brief The ELFLayout is an abstract class for managing the final layout for
+/// the kind of binaries(Shared Libraries / Relocatables / Executables 0
+/// Each architecture (Hexagon, MIPS) would have a concrete
+/// subclass derived from Layout for generating each binary thats
+// needed by the lld linker
+class Layout {
+public:
+ typedef uint32_t SectionOrder;
+ typedef uint32_t SegmentType;
+ typedef uint32_t Flags;
+
+public:
+ /// Return the order the section would appear in the output file
+ virtual SectionOrder getSectionOrder(StringRef name, int32_t contentType,
+ int32_t contentPerm) = 0;
+ /// \brief Append the Atom to the layout and create appropriate sections.
+ /// \returns A reference to the atom layout or an error. The atom layout will
+ /// be updated as linking progresses.
+ virtual ErrorOr<const lld::AtomLayout *> addAtom(const Atom *atom) = 0;
+ /// find the Atom in the current layout
+ virtual const AtomLayout *findAtomLayoutByName(StringRef name) const = 0;
+ /// associates a section to a segment
+ virtual void assignSectionsToSegments() = 0;
+ /// associates a virtual address to the segment, section, and the atom
+ virtual void assignVirtualAddress() = 0;
+
+public:
+ Layout() {}
+
+ virtual ~Layout() { }
+};
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/Makefile b/lib/ReaderWriter/ELF/Makefile
new file mode 100644
index 0000000000000..5791ecb9733d1
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Makefile
@@ -0,0 +1,18 @@
+##===- lld/lib/ReaderWriter/ELF/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 := lldELF
+
+CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF
+
+# these link against this lib
+PARALLEL_DIRS := Hexagon X86 X86_64 Mips AArch64 ARM
+
+include $(LLD_LEVEL)/Makefile
diff --git a/lib/ReaderWriter/ELF/Mips/CMakeLists.txt b/lib/ReaderWriter/ELF/Mips/CMakeLists.txt
new file mode 100644
index 0000000000000..d982508b7ddcc
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/CMakeLists.txt
@@ -0,0 +1,14 @@
+add_llvm_library(lldMipsELFTarget
+ MipsCtorsOrderPass.cpp
+ MipsELFFlagsMerger.cpp
+ MipsLinkingContext.cpp
+ MipsRelocationHandler.cpp
+ MipsRelocationPass.cpp
+ MipsTargetHandler.cpp
+ LINK_LIBS
+ lldELF
+ lldReaderWriter
+ lldCore
+ LLVMObject
+ LLVMSupport
+ )
diff --git a/lib/ReaderWriter/ELF/Mips/Makefile b/lib/ReaderWriter/ELF/Mips/Makefile
new file mode 100644
index 0000000000000..0b2f4ff82279a
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/Makefile
@@ -0,0 +1,15 @@
+##===- lld/lib/ReaderWriter/ELF/Mips/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 := lldMipsELFTarget
+USEDLIBS = lldCore.a
+CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF
+
+include $(LLD_LEVEL)/Makefile
diff --git a/lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.cpp b/lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.cpp
new file mode 100644
index 0000000000000..8bf80257fc89f
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.cpp
@@ -0,0 +1,73 @@
+//===- lib/ReaderWriter/ELF/Mips/Mips/CtorsOrderPass.cpp ------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MipsCtorsOrderPass.h"
+#include <algorithm>
+#include <climits>
+
+using namespace lld;
+using namespace lld::elf;
+
+static bool matchCrtObjName(StringRef objName, StringRef objPath) {
+ if (!objPath.endswith(".o"))
+ return false;
+
+ // check *<objName> case
+ objPath = objPath.drop_back(2);
+ if (objPath.endswith(objName))
+ return true;
+
+ // check *<objName>? case
+ return !objPath.empty() && objPath.drop_back(1).endswith(objName);
+}
+
+static int32_t getSectionPriority(StringRef path, StringRef sectionName) {
+ // Arrange .ctors/.dtors sections in the following order:
+ // .ctors from crtbegin.o or crtbegin?.o
+ // .ctors from regular object files
+ // .ctors.* (sorted) from regular object files
+ // .ctors from crtend.o or crtend?.o
+
+ if (matchCrtObjName("crtbegin", path))
+ return std::numeric_limits<int32_t>::min();
+ if (matchCrtObjName("crtend", path))
+ return std::numeric_limits<int32_t>::max();
+
+ StringRef num = sectionName.drop_front().rsplit('.').second;
+
+ int32_t priority = std::numeric_limits<int32_t>::min() + 1;
+ if (!num.empty())
+ num.getAsInteger(10, priority);
+
+ return priority;
+}
+
+void MipsCtorsOrderPass::perform(std::unique_ptr<MutableFile> &f) {
+ auto definedAtoms = f->definedAtoms();
+
+ auto last = std::stable_partition(definedAtoms.begin(), definedAtoms.end(),
+ [](const DefinedAtom *atom) {
+ if (atom->sectionChoice() != DefinedAtom::sectionCustomRequired)
+ return false;
+
+ StringRef name = atom->customSectionName();
+ return name.startswith(".ctors") || name.startswith(".dtors");
+ });
+
+ std::stable_sort(definedAtoms.begin(), last,
+ [](const DefinedAtom *left, const DefinedAtom *right) {
+ StringRef leftSec = left->customSectionName();
+ StringRef rightSec = right->customSectionName();
+
+ int32_t leftPriority = getSectionPriority(left->file().path(), leftSec);
+ int32_t rightPriority = getSectionPriority(right->file().path(), rightSec);
+
+ return leftPriority < rightPriority;
+ });
+}
diff --git a/lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.h b/lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.h
new file mode 100644
index 0000000000000..eeb1a194f9c77
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.h
@@ -0,0 +1,25 @@
+//===- lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.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_MIPS_MIPS_CTORS_ORDER_PASS_H
+#define LLD_READER_WRITER_ELF_MIPS_MIPS_CTORS_ORDER_PASS_H
+
+#include "lld/Core/Pass.h"
+
+namespace lld {
+namespace elf {
+/// \brief This pass sorts atoms in .{ctors,dtors}.<priority> sections.
+class MipsCtorsOrderPass : public Pass {
+public:
+ void perform(std::unique_ptr<MutableFile> &mergedFile) override;
+};
+}
+}
+
+#endif
diff --git a/lib/ReaderWriter/ELF/Mips/MipsDynamicLibraryWriter.h b/lib/ReaderWriter/ELF/Mips/MipsDynamicLibraryWriter.h
new file mode 100644
index 0000000000000..30b5b0ba6dae9
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsDynamicLibraryWriter.h
@@ -0,0 +1,101 @@
+//===- lib/ReaderWriter/ELF/Mips/MipsDynamicLibraryWriter.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_MIPS_MIPS_DYNAMIC_LIBRARY_WRITER_H
+#define LLD_READER_WRITER_ELF_MIPS_MIPS_DYNAMIC_LIBRARY_WRITER_H
+
+#include "DynamicLibraryWriter.h"
+#include "MipsDynamicTable.h"
+#include "MipsELFWriters.h"
+#include "MipsLinkingContext.h"
+
+namespace lld {
+namespace elf {
+
+template <typename ELFT> class MipsSymbolTable;
+template <typename ELFT> class MipsDynamicSymbolTable;
+template <typename ELFT> class MipsTargetLayout;
+
+template <class ELFT>
+class MipsDynamicLibraryWriter : public DynamicLibraryWriter<ELFT> {
+public:
+ MipsDynamicLibraryWriter(MipsLinkingContext &ctx,
+ MipsTargetLayout<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;
+
+ std::error_code setELFHeader() override {
+ DynamicLibraryWriter<ELFT>::setELFHeader();
+ _writeHelper.setELFHeader(*this->_elfHeader);
+ return std::error_code();
+ }
+
+ unique_bump_ptr<SymbolTable<ELFT>> createSymbolTable() override;
+ unique_bump_ptr<DynamicTable<ELFT>> createDynamicTable() override;
+
+ unique_bump_ptr<DynamicSymbolTable<ELFT>>
+ createDynamicSymbolTable() override;
+
+private:
+ MipsELFWriter<ELFT> _writeHelper;
+ MipsTargetLayout<ELFT> &_mipsTargetLayout;
+};
+
+template <class ELFT>
+MipsDynamicLibraryWriter<ELFT>::MipsDynamicLibraryWriter(
+ MipsLinkingContext &ctx, MipsTargetLayout<ELFT> &layout)
+ : DynamicLibraryWriter<ELFT>(ctx, layout), _writeHelper(ctx, layout),
+ _mipsTargetLayout(layout) {}
+
+template <class ELFT>
+bool MipsDynamicLibraryWriter<ELFT>::createImplicitFiles(
+ std::vector<std::unique_ptr<File>> &result) {
+ DynamicLibraryWriter<ELFT>::createImplicitFiles(result);
+ result.push_back(std::move(_writeHelper.createRuntimeFile()));
+ return true;
+}
+
+template <class ELFT>
+void MipsDynamicLibraryWriter<ELFT>::finalizeDefaultAtomValues() {
+ // Finalize the atom values that are part of the parent.
+ DynamicLibraryWriter<ELFT>::finalizeDefaultAtomValues();
+ _writeHelper.finalizeMipsRuntimeAtomValues();
+}
+
+template <class ELFT>
+unique_bump_ptr<SymbolTable<ELFT>>
+ MipsDynamicLibraryWriter<ELFT>::createSymbolTable() {
+ return unique_bump_ptr<SymbolTable<ELFT>>(new (
+ this->_alloc) MipsSymbolTable<ELFT>(this->_context));
+}
+
+/// \brief create dynamic table
+template <class ELFT>
+unique_bump_ptr<DynamicTable<ELFT>>
+ MipsDynamicLibraryWriter<ELFT>::createDynamicTable() {
+ return unique_bump_ptr<DynamicTable<ELFT>>(new (
+ this->_alloc) MipsDynamicTable<ELFT>(this->_context, _mipsTargetLayout));
+}
+
+/// \brief create dynamic symbol table
+template <class ELFT>
+unique_bump_ptr<DynamicSymbolTable<ELFT>>
+ MipsDynamicLibraryWriter<ELFT>::createDynamicSymbolTable() {
+ return unique_bump_ptr<DynamicSymbolTable<ELFT>>(
+ new (this->_alloc) MipsDynamicSymbolTable<ELFT>(
+ this->_context, _mipsTargetLayout));
+}
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/Mips/MipsDynamicTable.h b/lib/ReaderWriter/ELF/Mips/MipsDynamicTable.h
new file mode 100644
index 0000000000000..2b9562f42b57d
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsDynamicTable.h
@@ -0,0 +1,115 @@
+//===- lib/ReaderWriter/ELF/Mips/MipsDynamicTable.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_MIPS_MIPS_DYNAMIC_TABLE_H
+#define LLD_READER_WRITER_ELF_MIPS_MIPS_DYNAMIC_TABLE_H
+
+#include "DefaultLayout.h"
+#include "SectionChunks.h"
+
+namespace lld {
+namespace elf {
+
+template <class ELFType> class MipsTargetLayout;
+
+template <class MipsELFType>
+class MipsDynamicTable : public DynamicTable<MipsELFType> {
+public:
+ MipsDynamicTable(const ELFLinkingContext &ctx,
+ MipsTargetLayout<MipsELFType> &layout)
+ : DynamicTable<MipsELFType>(ctx, layout, ".dynamic",
+ DefaultLayout<MipsELFType>::ORDER_DYNAMIC),
+ _mipsTargetLayout(layout) {}
+
+ void createDefaultEntries() override {
+ DynamicTable<MipsELFType>::createDefaultEntries();
+
+ typename DynamicTable<MipsELFType>::Elf_Dyn dyn;
+
+ // Version id for the Runtime Linker Interface.
+ dyn.d_un.d_val = 1;
+ dyn.d_tag = DT_MIPS_RLD_VERSION;
+ this->addEntry(dyn);
+
+ // MIPS flags.
+ dyn.d_un.d_val = RHF_NOTPOT;
+ dyn.d_tag = DT_MIPS_FLAGS;
+ this->addEntry(dyn);
+
+ // The base address of the segment.
+ dyn.d_un.d_ptr = 0;
+ dyn.d_tag = DT_MIPS_BASE_ADDRESS;
+ _dt_baseaddr = this->addEntry(dyn);
+
+ // Number of local global offset table entries.
+ dyn.d_un.d_val = 0;
+ dyn.d_tag = DT_MIPS_LOCAL_GOTNO;
+ _dt_localgot = this->addEntry(dyn);
+
+ // Number of entries in the .dynsym section.
+ dyn.d_un.d_val = 0;
+ dyn.d_tag = DT_MIPS_SYMTABNO;
+ _dt_symtabno = this->addEntry(dyn);
+
+ // The index of the first dynamic symbol table entry that corresponds
+ // to an entry in the global offset table.
+ dyn.d_un.d_val = 0;
+ dyn.d_tag = DT_MIPS_GOTSYM;
+ _dt_gotsym = this->addEntry(dyn);
+
+ // Address of the .got section.
+ dyn.d_un.d_val = 0;
+ dyn.d_tag = DT_PLTGOT;
+ _dt_pltgot = this->addEntry(dyn);
+ }
+
+ void updateDynamicTable() override {
+ DynamicTable<MipsELFType>::updateDynamicTable();
+
+ // Assign the minimum segment address to the DT_MIPS_BASE_ADDRESS tag.
+ auto baseAddr = std::numeric_limits<uint64_t>::max();
+ for (auto si : _mipsTargetLayout.segments())
+ if (si->segmentType() != llvm::ELF::PT_NULL)
+ baseAddr = std::min(baseAddr, si->virtualAddr());
+ this->_entries[_dt_baseaddr].d_un.d_val = baseAddr;
+
+ auto &got = _mipsTargetLayout.getGOTSection();
+
+ this->_entries[_dt_symtabno].d_un.d_val = this->getSymbolTable()->size();
+ this->_entries[_dt_gotsym].d_un.d_val =
+ this-> getSymbolTable()->size() - got.getGlobalCount();
+ this->_entries[_dt_localgot].d_un.d_val = got.getLocalCount();
+ this->_entries[_dt_pltgot].d_un.d_ptr =
+ _mipsTargetLayout.findOutputSection(".got")->virtualAddr();
+ }
+
+ int64_t getGotPltTag() override { return DT_MIPS_PLTGOT; }
+
+protected:
+ /// \brief Adjust the symbol's value for microMIPS code.
+ uint64_t getAtomVirtualAddress(const AtomLayout *al) const override {
+ if (const auto *da = dyn_cast<DefinedAtom>(al->_atom))
+ if (da->codeModel() == DefinedAtom::codeMipsMicro ||
+ da->codeModel() == DefinedAtom::codeMipsMicroPIC)
+ return al->_virtualAddr | 1;
+ return al->_virtualAddr;
+ }
+
+private:
+ std::size_t _dt_symtabno;
+ std::size_t _dt_localgot;
+ std::size_t _dt_gotsym;
+ std::size_t _dt_pltgot;
+ std::size_t _dt_baseaddr;
+ MipsTargetLayout<MipsELFType> &_mipsTargetLayout;
+};
+
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/Mips/MipsELFFile.h b/lib/ReaderWriter/ELF/Mips/MipsELFFile.h
new file mode 100644
index 0000000000000..7381c7e977bf2
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsELFFile.h
@@ -0,0 +1,331 @@
+//===- lib/ReaderWriter/ELF/MipsELFFile.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_MIPS_MIPS_ELF_FILE_H
+#define LLD_READER_WRITER_ELF_MIPS_MIPS_ELF_FILE_H
+
+#include "ELFReader.h"
+#include "MipsLinkingContext.h"
+#include "MipsRelocationHandler.h"
+
+namespace llvm {
+namespace object {
+
+template <class ELFT>
+struct Elf_RegInfo;
+
+template <llvm::support::endianness TargetEndianness, std::size_t MaxAlign>
+struct Elf_RegInfo<ELFType<TargetEndianness, MaxAlign, false>> {
+ LLVM_ELF_IMPORT_TYPES(TargetEndianness, MaxAlign, false)
+ Elf_Word ri_gprmask; // bit-mask of used general registers
+ Elf_Word ri_cprmask[4]; // bit-mask of used co-processor registers
+ Elf_Addr ri_gp_value; // gp register value
+};
+
+template <llvm::support::endianness TargetEndianness, std::size_t MaxAlign>
+struct Elf_RegInfo<ELFType<TargetEndianness, MaxAlign, true>> {
+ LLVM_ELF_IMPORT_TYPES(TargetEndianness, MaxAlign, true)
+ Elf_Word ri_gprmask; // bit-mask of used general registers
+ Elf_Word ri_pad; // unused padding field
+ Elf_Word ri_cprmask[4]; // bit-mask of used co-processor registers
+ Elf_Addr ri_gp_value; // gp register value
+};
+
+template <class ELFT> struct Elf_Mips_Options {
+ LLVM_ELF_IMPORT_TYPES(ELFT::TargetEndianness, ELFT::MaxAlignment,
+ ELFT::Is64Bits)
+ uint8_t kind; // Determines interpretation of variable part of descriptor
+ uint8_t size; // Byte size of descriptor, including this header
+ Elf_Half section; // Section header index of section affected,
+ // or 0 for global options
+ Elf_Word info; // Kind-specific information
+};
+
+} // end namespace object.
+} // end namespace llvm.
+
+namespace lld {
+namespace elf {
+
+template <class ELFT> class MipsELFFile;
+
+template <class ELFT>
+class MipsELFDefinedAtom : public ELFDefinedAtom<ELFT> {
+ typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+ typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr;
+
+public:
+ MipsELFDefinedAtom(const MipsELFFile<ELFT> &file, StringRef symbolName,
+ StringRef sectionName, const Elf_Sym *symbol,
+ const Elf_Shdr *section, ArrayRef<uint8_t> contentData,
+ unsigned int referenceStart, unsigned int referenceEnd,
+ std::vector<ELFReference<ELFT> *> &referenceList)
+ : ELFDefinedAtom<ELFT>(file, symbolName, sectionName, symbol, section,
+ contentData, referenceStart, referenceEnd,
+ referenceList) {}
+
+ const MipsELFFile<ELFT>& file() const override {
+ return static_cast<const MipsELFFile<ELFT> &>(this->_owningFile);
+ }
+
+ DefinedAtom::CodeModel codeModel() const override {
+ switch (this->_symbol->st_other & llvm::ELF::STO_MIPS_MIPS16) {
+ case llvm::ELF::STO_MIPS_MIPS16:
+ return DefinedAtom::codeMips16;
+ case llvm::ELF::STO_MIPS_PIC:
+ return DefinedAtom::codeMipsPIC;
+ case llvm::ELF::STO_MIPS_MICROMIPS:
+ return DefinedAtom::codeMipsMicro;
+ case llvm::ELF::STO_MIPS_MICROMIPS | llvm::ELF::STO_MIPS_PIC:
+ return DefinedAtom::codeMipsMicroPIC;
+ default:
+ return DefinedAtom::codeNA;
+ }
+ }
+};
+
+template <class ELFT> class MipsELFReference : public ELFReference<ELFT> {
+ typedef llvm::object::Elf_Rel_Impl<ELFT, false> Elf_Rel;
+ typedef llvm::object::Elf_Rel_Impl<ELFT, true> Elf_Rela;
+
+ static const bool _isMips64EL =
+ ELFT::Is64Bits && ELFT::TargetEndianness == llvm::support::little;
+
+public:
+ MipsELFReference(uint64_t symValue, const Elf_Rela &rel)
+ : ELFReference<ELFT>(
+ &rel, rel.r_offset - symValue, Reference::KindArch::Mips,
+ rel.getType(_isMips64EL) & 0xff, rel.getSymbol(_isMips64EL)),
+ _tag(uint32_t(rel.getType(_isMips64EL)) >> 8) {}
+
+ MipsELFReference(uint64_t symValue, const Elf_Rel &rel)
+ : ELFReference<ELFT>(rel.r_offset - symValue, Reference::KindArch::Mips,
+ rel.getType(_isMips64EL) & 0xff,
+ rel.getSymbol(_isMips64EL)),
+ _tag(uint32_t(rel.getType(_isMips64EL)) >> 8) {}
+
+ uint32_t tag() const override { return _tag; }
+ void setTag(uint32_t tag) { _tag = tag; }
+
+private:
+ uint32_t _tag;
+};
+
+template <class ELFT> class MipsELFFile : public ELFFile<ELFT> {
+public:
+ MipsELFFile(std::unique_ptr<MemoryBuffer> mb, MipsLinkingContext &ctx)
+ : ELFFile<ELFT>(std::move(mb), ctx) {}
+
+ static ErrorOr<std::unique_ptr<MipsELFFile>>
+ create(std::unique_ptr<MemoryBuffer> mb, MipsLinkingContext &ctx) {
+ return std::unique_ptr<MipsELFFile<ELFT>>(
+ new MipsELFFile<ELFT>(std::move(mb), ctx));
+ }
+
+ bool isPIC() const {
+ return this->_objFile->getHeader()->e_flags & llvm::ELF::EF_MIPS_PIC;
+ }
+
+ /// \brief gp register value stored in the .reginfo section.
+ int64_t getGP0() const { return _gp0 ? *_gp0 : 0; }
+
+ /// \brief .tdata section address plus fixed offset.
+ uint64_t getTPOffset() const { return *_tpOff; }
+ uint64_t getDTPOffset() const { return *_dtpOff; }
+
+protected:
+ std::error_code doParse() override {
+ if (std::error_code ec = ELFFile<ELFT>::doParse())
+ return ec;
+ // Retrieve some auxiliary data like GP value, TLS section address etc
+ // from the object file.
+ return readAuxData();
+ }
+
+private:
+ typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+ typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr;
+ typedef llvm::object::Elf_Rel_Impl<ELFT, false> Elf_Rel;
+ typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel_Iter Elf_Rel_Iter;
+ typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela_Iter Elf_Rela_Iter;
+
+ enum { TP_OFFSET = 0x7000, DTP_OFFSET = 0x8000 };
+
+ static const bool _isMips64EL =
+ ELFT::Is64Bits && ELFT::TargetEndianness == llvm::support::little;
+
+ llvm::Optional<int64_t> _gp0;
+ llvm::Optional<uint64_t> _tpOff;
+ llvm::Optional<uint64_t> _dtpOff;
+
+ ErrorOr<ELFDefinedAtom<ELFT> *> handleDefinedSymbol(
+ StringRef symName, StringRef sectionName, const Elf_Sym *sym,
+ const Elf_Shdr *sectionHdr, ArrayRef<uint8_t> contentData,
+ unsigned int referenceStart, unsigned int referenceEnd,
+ std::vector<ELFReference<ELFT> *> &referenceList) override {
+ return new (this->_readerStorage) MipsELFDefinedAtom<ELFT>(
+ *this, symName, sectionName, sym, sectionHdr, contentData,
+ referenceStart, referenceEnd, referenceList);
+ }
+
+ const Elf_Shdr *findSectionByType(uint64_t type) {
+ for (const Elf_Shdr &section : this->_objFile->sections())
+ if (section.sh_type == type)
+ return &section;
+ return nullptr;
+ }
+
+ const Elf_Shdr *findSectionByFlags(uint64_t flags) {
+ for (const Elf_Shdr &section : this->_objFile->sections())
+ if (section.sh_flags & flags)
+ return &section;
+ return nullptr;
+ }
+
+ std::error_code readAuxData() {
+ using namespace llvm::ELF;
+ if (const Elf_Shdr *sec = findSectionByFlags(SHF_TLS)) {
+ _tpOff = sec->sh_addr + TP_OFFSET;
+ _dtpOff = sec->sh_addr + DTP_OFFSET;
+ }
+
+ typedef llvm::object::Elf_RegInfo<ELFT> Elf_RegInfo;
+ typedef llvm::object::Elf_Mips_Options<ELFT> Elf_Mips_Options;
+
+ if (const Elf_Shdr *sec = findSectionByType(SHT_MIPS_OPTIONS)) {
+ auto contents = this->getSectionContents(sec);
+ if (std::error_code ec = contents.getError())
+ return ec;
+
+ ArrayRef<uint8_t> raw = contents.get();
+ while (!raw.empty()) {
+ if (raw.size() < sizeof(Elf_Mips_Options))
+ return make_dynamic_error_code(
+ StringRef("Invalid size of MIPS_OPTIONS section"));
+
+ const auto *opt = reinterpret_cast<const Elf_Mips_Options *>(raw.data());
+ if (opt->kind == ODK_REGINFO) {
+ _gp0 = reinterpret_cast<const Elf_RegInfo *>(opt + 1)->ri_gp_value;
+ break;
+ }
+ raw = raw.slice(opt->size);
+ }
+ } else if (const Elf_Shdr *sec = findSectionByType(SHT_MIPS_REGINFO)) {
+ auto contents = this->getSectionContents(sec);
+ if (std::error_code ec = contents.getError())
+ return ec;
+
+ ArrayRef<uint8_t> raw = contents.get();
+ if (raw.size() != sizeof(Elf_RegInfo))
+ return make_dynamic_error_code(
+ StringRef("Invalid size of MIPS_REGINFO section"));
+
+ _gp0 = reinterpret_cast<const Elf_RegInfo *>(raw.data())->ri_gp_value;
+ }
+ return std::error_code();
+ }
+
+ void createRelocationReferences(const Elf_Sym *symbol,
+ ArrayRef<uint8_t> content,
+ range<Elf_Rela_Iter> rels) override {
+ const auto value = this->getSymbolValue(symbol);
+ for (const auto &rel : rels) {
+ if (rel.r_offset < value || value + content.size() <= rel.r_offset)
+ continue;
+ auto r = new (this->_readerStorage) MipsELFReference<ELFT>(value, rel);
+ this->addReferenceToSymbol(r, symbol);
+ this->_references.push_back(r);
+ }
+ }
+
+ void createRelocationReferences(const Elf_Sym *symbol,
+ ArrayRef<uint8_t> symContent,
+ ArrayRef<uint8_t> secContent,
+ range<Elf_Rel_Iter> rels) override {
+ const auto value = this->getSymbolValue(symbol);
+ for (Elf_Rel_Iter rit = rels.begin(), eit = rels.end(); rit != eit; ++rit) {
+ if (rit->r_offset < value || value + symContent.size() <= rit->r_offset)
+ continue;
+
+ auto r = new (this->_readerStorage) MipsELFReference<ELFT>(value, *rit);
+ this->addReferenceToSymbol(r, symbol);
+ this->_references.push_back(r);
+
+ auto addend = readAddend(*rit, secContent);
+ auto pairRelType = getPairRelocation(*rit);
+ if (pairRelType != llvm::ELF::R_MIPS_NONE) {
+ addend <<= 16;
+ auto mit = findMatchingRelocation(pairRelType, rit, eit);
+ if (mit != eit)
+ addend += int16_t(readAddend(*mit, secContent));
+ else
+ // FIXME (simon): Show detailed warning.
+ llvm::errs() << "lld warning: cannot matching LO16 relocation\n";
+ }
+ this->_references.back()->setAddend(addend);
+ }
+ }
+
+ Reference::Addend readAddend(const Elf_Rel &ri,
+ const ArrayRef<uint8_t> content) const {
+ const auto &rh =
+ this->_ctx.template getTargetHandler<ELFT>().getRelocationHandler();
+ return static_cast<const MipsRelocationHandler &>(rh)
+ .readAddend(getPrimaryType(ri), content.data() + ri.r_offset);
+ }
+
+ uint32_t getPairRelocation(const Elf_Rel &rel) const {
+ switch (getPrimaryType(rel)) {
+ case llvm::ELF::R_MIPS_HI16:
+ return llvm::ELF::R_MIPS_LO16;
+ case llvm::ELF::R_MIPS_PCHI16:
+ return llvm::ELF::R_MIPS_PCLO16;
+ case llvm::ELF::R_MIPS_GOT16:
+ if (isLocalBinding(rel))
+ return llvm::ELF::R_MIPS_LO16;
+ break;
+ case llvm::ELF::R_MICROMIPS_HI16:
+ return llvm::ELF::R_MICROMIPS_LO16;
+ case llvm::ELF::R_MICROMIPS_GOT16:
+ if (isLocalBinding(rel))
+ return llvm::ELF::R_MICROMIPS_LO16;
+ break;
+ default:
+ // Nothing to do.
+ break;
+ }
+ return llvm::ELF::R_MIPS_NONE;
+ }
+
+ Elf_Rel_Iter findMatchingRelocation(uint32_t pairRelType, Elf_Rel_Iter rit,
+ Elf_Rel_Iter eit) const {
+ return std::find_if(rit, eit, [&](const Elf_Rel &rel) {
+ return getPrimaryType(rel) == pairRelType &&
+ rel.getSymbol(_isMips64EL) == rit->getSymbol(_isMips64EL);
+ });
+ }
+
+ static uint8_t getPrimaryType(const Elf_Rel &rel) {
+ return rel.getType(_isMips64EL) & 0xff;
+ }
+ bool isLocalBinding(const Elf_Rel &rel) const {
+ return this->_objFile->getSymbol(rel.getSymbol(_isMips64EL))
+ ->getBinding() == llvm::ELF::STB_LOCAL;
+ }
+};
+
+template <class ELFT> class MipsDynamicFile : public DynamicFile<ELFT> {
+public:
+ MipsDynamicFile(const MipsLinkingContext &context, StringRef name)
+ : DynamicFile<ELFT>(context, name) {}
+};
+
+} // elf
+} // lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/Mips/MipsELFFlagsMerger.cpp b/lib/ReaderWriter/ELF/Mips/MipsELFFlagsMerger.cpp
new file mode 100644
index 0000000000000..0ef2c70b81564
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsELFFlagsMerger.cpp
@@ -0,0 +1,149 @@
+//===- lib/ReaderWriter/ELF/MipsELFFlagsMerger.cpp ------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MipsELFFlagsMerger.h"
+#include "lld/Core/Error.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/ELF.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace lld;
+using namespace lld::elf;
+using namespace llvm::ELF;
+
+struct MipsISATreeEdge {
+ unsigned child;
+ unsigned parent;
+};
+
+static MipsISATreeEdge isaTree[] = {
+ // MIPS32R6 and MIPS64R6 are not compatible with other extensions
+
+ // MIPS64 extensions.
+ {EF_MIPS_ARCH_64R2, EF_MIPS_ARCH_64},
+ // MIPS V extensions.
+ {EF_MIPS_ARCH_64, EF_MIPS_ARCH_5},
+ // MIPS IV extensions.
+ {EF_MIPS_ARCH_5, EF_MIPS_ARCH_4},
+ // MIPS III extensions.
+ {EF_MIPS_ARCH_4, EF_MIPS_ARCH_3},
+ // MIPS32 extensions.
+ {EF_MIPS_ARCH_32R2, EF_MIPS_ARCH_32},
+ // MIPS II extensions.
+ {EF_MIPS_ARCH_3, EF_MIPS_ARCH_2},
+ {EF_MIPS_ARCH_32, EF_MIPS_ARCH_2},
+ // MIPS I extensions.
+ {EF_MIPS_ARCH_2, EF_MIPS_ARCH_1},
+};
+
+static bool matchMipsISA(unsigned base, unsigned ext) {
+ if (base == ext)
+ return true;
+ if (base == EF_MIPS_ARCH_32 && matchMipsISA(EF_MIPS_ARCH_64, ext))
+ return true;
+ if (base == EF_MIPS_ARCH_32R2 && matchMipsISA(EF_MIPS_ARCH_64R2, ext))
+ return true;
+ for (const auto &edge : isaTree) {
+ if (ext == edge.child) {
+ ext = edge.parent;
+ if (ext == base)
+ return true;
+ }
+ }
+ return false;
+}
+
+MipsELFFlagsMerger::MipsELFFlagsMerger(bool is64Bits)
+ : _is64Bit(is64Bits), _flags(0) {}
+
+uint32_t MipsELFFlagsMerger::getMergedELFFlags() const { return _flags; }
+
+std::error_code MipsELFFlagsMerger::merge(uint8_t newClass, uint32_t newFlags) {
+ // Check bitness.
+ if (_is64Bit != (newClass == ELFCLASS64))
+ return make_dynamic_error_code(
+ Twine("Bitness is incompatible with that of the selected target"));
+
+ // We support two ABI: O32 and N64. The last one does not have
+ // the corresponding ELF flag.
+ uint32_t inAbi = newFlags & EF_MIPS_ABI;
+ uint32_t supportedAbi = _is64Bit ? 0 : uint32_t(EF_MIPS_ABI_O32);
+ if (inAbi != supportedAbi)
+ return make_dynamic_error_code(Twine("Unsupported ABI"));
+
+ // ... and reduced set of architectures ...
+ uint32_t newArch = newFlags & EF_MIPS_ARCH;
+ switch (newArch) {
+ case EF_MIPS_ARCH_1:
+ case EF_MIPS_ARCH_2:
+ case EF_MIPS_ARCH_3:
+ case EF_MIPS_ARCH_4:
+ case EF_MIPS_ARCH_5:
+ case EF_MIPS_ARCH_32:
+ case EF_MIPS_ARCH_64:
+ case EF_MIPS_ARCH_32R2:
+ case EF_MIPS_ARCH_64R2:
+ case EF_MIPS_ARCH_32R6:
+ case EF_MIPS_ARCH_64R6:
+ break;
+ default:
+ return make_dynamic_error_code(Twine("Unsupported instruction set"));
+ }
+
+ // ... and still do not support MIPS-16 extension.
+ if (newFlags & EF_MIPS_ARCH_ASE_M16)
+ return make_dynamic_error_code(Twine("Unsupported extension: MIPS16"));
+
+ // PIC code is inherently CPIC and may not set CPIC flag explicitly.
+ // Ensure that this flag will exist in the linked file.
+ if (newFlags & EF_MIPS_PIC)
+ newFlags |= EF_MIPS_CPIC;
+
+ std::lock_guard<std::mutex> lock(_mutex);
+
+ // If the old set of flags is empty, use the new one as a result.
+ if (!_flags) {
+ _flags = newFlags;
+ return std::error_code();
+ }
+
+ // Check PIC / CPIC flags compatibility.
+ uint32_t newPic = newFlags & (EF_MIPS_PIC | EF_MIPS_CPIC);
+ uint32_t oldPic = _flags & (EF_MIPS_PIC | EF_MIPS_CPIC);
+
+ if ((newPic != 0) != (oldPic != 0))
+ llvm::errs() << "lld warning: linking abicalls and non-abicalls files\n";
+
+ if (!(newPic & EF_MIPS_PIC))
+ _flags &= ~EF_MIPS_PIC;
+ if (newPic)
+ _flags |= EF_MIPS_CPIC;
+
+ // Check mixing -mnan=2008 / -mnan=legacy modules.
+ if ((newFlags & EF_MIPS_NAN2008) != (_flags & EF_MIPS_NAN2008))
+ return make_dynamic_error_code(
+ Twine("Linking -mnan=2008 and -mnan=legacy modules"));
+
+ // Check ISA compatibility and update the extension flag.
+ uint32_t oldArch = _flags & EF_MIPS_ARCH;
+ if (!matchMipsISA(newArch, oldArch)) {
+ if (!matchMipsISA(oldArch, newArch))
+ return make_dynamic_error_code(
+ Twine("Linking modules with incompatible ISA"));
+ _flags &= ~EF_MIPS_ARCH;
+ _flags |= newArch;
+ }
+
+ _flags |= newFlags & EF_MIPS_NOREORDER;
+ _flags |= newFlags & EF_MIPS_MICROMIPS;
+ _flags |= newFlags & EF_MIPS_NAN2008;
+ _flags |= newFlags & EF_MIPS_32BITMODE;
+
+ return std::error_code();
+}
diff --git a/lib/ReaderWriter/ELF/Mips/MipsELFFlagsMerger.h b/lib/ReaderWriter/ELF/Mips/MipsELFFlagsMerger.h
new file mode 100644
index 0000000000000..6ade86f0163cc
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsELFFlagsMerger.h
@@ -0,0 +1,36 @@
+//===- lib/ReaderWriter/ELF/MipsELFFlagsMerger.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_MIPS_MIPS_ELF_FLAGS_MERGER_H
+#define LLD_READER_WRITER_ELF_MIPS_MIPS_ELF_FLAGS_MERGER_H
+
+#include <mutex>
+#include <system_error>
+
+namespace lld {
+namespace elf {
+
+class MipsELFFlagsMerger {
+public:
+ MipsELFFlagsMerger(bool is64Bits);
+
+ uint32_t getMergedELFFlags() const;
+
+ /// \brief Merge saved ELF header flags and the new set of flags.
+ std::error_code merge(uint8_t newClass, uint32_t newFlags);
+
+private:
+ const bool _is64Bit;
+ std::mutex _mutex;
+ uint32_t _flags;
+};
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/Mips/MipsELFReader.h b/lib/ReaderWriter/ELF/Mips/MipsELFReader.h
new file mode 100644
index 0000000000000..8b325b38bb522
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsELFReader.h
@@ -0,0 +1,93 @@
+//===- lib/ReaderWriter/ELF/MipsELFReader.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_MIPS_MIPS_ELF_READER_H
+#define LLD_READER_WRITER_ELF_MIPS_MIPS_ELF_READER_H
+
+#include "ELFReader.h"
+#include "MipsELFFile.h"
+#include "MipsELFFlagsMerger.h"
+#include "MipsLinkingContext.h"
+
+namespace lld {
+namespace elf {
+
+struct MipsELFFileCreateTraits {
+ typedef llvm::ErrorOr<std::unique_ptr<lld::File>> result_type;
+
+ template <class ELFT>
+ static result_type create(std::unique_ptr<llvm::MemoryBuffer> mb,
+ MipsLinkingContext &ctx) {
+ return lld::elf::MipsELFFile<ELFT>::create(std::move(mb), ctx);
+ }
+};
+
+struct MipsDynamicFileCreateELFTraits {
+ typedef llvm::ErrorOr<std::unique_ptr<lld::SharedLibraryFile>> result_type;
+
+ template <class ELFT>
+ static result_type create(std::unique_ptr<llvm::MemoryBuffer> mb,
+ MipsLinkingContext &ctx) {
+ return lld::elf::MipsDynamicFile<ELFT>::create(std::move(mb), ctx);
+ }
+};
+
+template <class ELFT>
+class MipsELFObjectReader
+ : public ELFObjectReader<ELFT, MipsELFFileCreateTraits,
+ MipsLinkingContext> {
+ typedef ELFObjectReader<ELFT, MipsELFFileCreateTraits, MipsLinkingContext>
+ BaseReaderType;
+
+public:
+ MipsELFObjectReader(MipsLinkingContext &ctx)
+ : BaseReaderType(ctx, llvm::ELF::EM_MIPS),
+ _flagMerger(ctx.getELFFlagsMerger()) {}
+
+ std::error_code
+ loadFile(std::unique_ptr<MemoryBuffer> mb, const Registry &registry,
+ std::vector<std::unique_ptr<File>> &result) const override {
+ auto &hdr = *this->elfHeader(*mb);
+ if (std::error_code ec = _flagMerger.merge(hdr.getFileClass(), hdr.e_flags))
+ return ec;
+ return BaseReaderType::loadFile(std::move(mb), registry, result);
+ }
+
+private:
+ MipsELFFlagsMerger &_flagMerger;
+};
+
+template <class ELFT>
+class MipsELFDSOReader
+ : public ELFDSOReader<ELFT, MipsDynamicFileCreateELFTraits,
+ MipsLinkingContext> {
+ typedef ELFDSOReader<ELFT, MipsDynamicFileCreateELFTraits, MipsLinkingContext>
+ BaseReaderType;
+
+public:
+ MipsELFDSOReader(MipsLinkingContext &ctx)
+ : BaseReaderType(ctx, llvm::ELF::EM_MIPS),
+ _flagMerger(ctx.getELFFlagsMerger()) {}
+
+ std::error_code
+ loadFile(std::unique_ptr<MemoryBuffer> mb, const Registry &registry,
+ std::vector<std::unique_ptr<File>> &result) const override {
+ auto &hdr = *this->elfHeader(*mb);
+ if (std::error_code ec = _flagMerger.merge(hdr.getFileClass(), hdr.e_flags))
+ return ec;
+ return BaseReaderType::loadFile(std::move(mb), registry, result);
+ }
+
+private:
+ MipsELFFlagsMerger &_flagMerger;
+};
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/Mips/MipsELFWriters.h b/lib/ReaderWriter/ELF/Mips/MipsELFWriters.h
new file mode 100644
index 0000000000000..d94dd757a0f30
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsELFWriters.h
@@ -0,0 +1,82 @@
+//===- lib/ReaderWriter/ELF/Mips/MipsELFWriters.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_MIPS_MIPS_ELF_WRITERS_H
+#define LLD_READER_WRITER_ELF_MIPS_MIPS_ELF_WRITERS_H
+
+#include "MipsLinkingContext.h"
+#include "OutputELFWriter.h"
+
+namespace lld {
+namespace elf {
+
+template <class ELFT> class MipsRuntimeFile;
+
+template <class ELFT> class MipsTargetLayout;
+
+template <typename ELFT> class MipsELFWriter {
+public:
+ MipsELFWriter(MipsLinkingContext &ctx, MipsTargetLayout<ELFT> &targetLayout)
+ : _ctx(ctx), _targetLayout(targetLayout) {}
+
+ void setELFHeader(ELFHeader<ELFT> &elfHeader) {
+ elfHeader.e_version(1);
+ elfHeader.e_ident(llvm::ELF::EI_VERSION, llvm::ELF::EV_CURRENT);
+ elfHeader.e_ident(llvm::ELF::EI_OSABI, llvm::ELF::ELFOSABI_NONE);
+ if (_targetLayout.findOutputSection(".got.plt"))
+ elfHeader.e_ident(llvm::ELF::EI_ABIVERSION, 1);
+ else
+ elfHeader.e_ident(llvm::ELF::EI_ABIVERSION, 0);
+
+ elfHeader.e_flags(_ctx.getMergedELFFlags());
+ }
+
+ void finalizeMipsRuntimeAtomValues() {
+ if (!_ctx.isDynamic())
+ return;
+
+ auto gotSection = _targetLayout.findOutputSection(".got");
+ auto got = gotSection ? gotSection->virtualAddr() : 0;
+ auto gp = gotSection ? got + _targetLayout.getGPOffset() : 0;
+
+ setAtomValue("_GLOBAL_OFFSET_TABLE_", got);
+ setAtomValue("_gp", gp);
+ setAtomValue("_gp_disp", gp);
+ setAtomValue("__gnu_local_gp", gp);
+ }
+
+ bool hasGlobalGOTEntry(const Atom *a) const {
+ return _targetLayout.getGOTSection().hasGlobalGOTEntry(a);
+ }
+
+ std::unique_ptr<MipsRuntimeFile<ELFT>> createRuntimeFile() {
+ auto file = llvm::make_unique<MipsRuntimeFile<ELFT>>(_ctx);
+ if (_ctx.isDynamic()) {
+ file->addAbsoluteAtom("_GLOBAL_OFFSET_TABLE_");
+ file->addAbsoluteAtom("_gp");
+ file->addAbsoluteAtom("_gp_disp");
+ file->addAbsoluteAtom("__gnu_local_gp");
+ }
+ return file;
+ }
+
+private:
+ MipsLinkingContext &_ctx;
+ MipsTargetLayout<ELFT> &_targetLayout;
+
+ void setAtomValue(StringRef name, uint64_t value) {
+ auto atom = _targetLayout.findAbsoluteAtom(name);
+ assert(atom != _targetLayout.absoluteAtoms().end());
+ (*atom)->_virtualAddr = value;
+ }
+};
+
+} // elf
+} // lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/Mips/MipsExecutableWriter.h b/lib/ReaderWriter/ELF/Mips/MipsExecutableWriter.h
new file mode 100644
index 0000000000000..1a85bba3bd0f6
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsExecutableWriter.h
@@ -0,0 +1,154 @@
+//===- lib/ReaderWriter/ELF/Mips/MipsExecutableWriter.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_MIPS_MIPS_EXECUTABLE_WRITER_H
+#define LLD_READER_WRITER_ELF_MIPS_MIPS_EXECUTABLE_WRITER_H
+
+#include "ExecutableWriter.h"
+#include "MipsDynamicTable.h"
+#include "MipsELFWriters.h"
+#include "MipsLinkingContext.h"
+
+namespace lld {
+namespace elf {
+
+template <typename ELFT> class MipsTargetLayout;
+
+template <class ELFT>
+class MipsExecutableWriter : public ExecutableWriter<ELFT> {
+public:
+ MipsExecutableWriter(MipsLinkingContext &ctx, MipsTargetLayout<ELFT> &layout);
+
+protected:
+ void buildDynamicSymbolTable(const File &file) override;
+
+ // Add any runtime files and their atoms to the output
+ bool createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
+
+ void finalizeDefaultAtomValues() override;
+ std::error_code setELFHeader() override;
+
+ unique_bump_ptr<SymbolTable<ELFT>> createSymbolTable() override;
+ unique_bump_ptr<DynamicTable<ELFT>> createDynamicTable() override;
+
+ unique_bump_ptr<DynamicSymbolTable<ELFT>>
+ createDynamicSymbolTable() override;
+
+private:
+ MipsELFWriter<ELFT> _writeHelper;
+ MipsTargetLayout<ELFT> &_mipsTargetLayout;
+};
+
+template <class ELFT>
+MipsExecutableWriter<ELFT>::MipsExecutableWriter(MipsLinkingContext &ctx,
+ MipsTargetLayout<ELFT> &layout)
+ : ExecutableWriter<ELFT>(ctx, layout), _writeHelper(ctx, layout),
+ _mipsTargetLayout(layout) {}
+
+template <class ELFT>
+std::error_code MipsExecutableWriter<ELFT>::setELFHeader() {
+ std::error_code ec = ExecutableWriter<ELFT>::setELFHeader();
+ if (ec)
+ return ec;
+
+ StringRef entryName = this->_context.entrySymbolName();
+ if (const AtomLayout *al = this->_layout.findAtomLayoutByName(entryName)) {
+ const auto *ea = cast<DefinedAtom>(al->_atom);
+ if (ea->codeModel() == DefinedAtom::codeMipsMicro ||
+ ea->codeModel() == DefinedAtom::codeMipsMicroPIC)
+ // Adjust entry symbol value if this symbol is microMIPS encoded.
+ this->_elfHeader->e_entry(al->_virtualAddr | 1);
+ }
+
+ _writeHelper.setELFHeader(*this->_elfHeader);
+ return std::error_code();
+}
+
+template <class ELFT>
+void MipsExecutableWriter<ELFT>::buildDynamicSymbolTable(const File &file) {
+ // MIPS ABI requires to add to dynsym even undefined symbols
+ // if they have a corresponding entries in a global part of GOT.
+ for (auto sec : this->_layout.sections())
+ if (auto section = dyn_cast<AtomSection<ELFT>>(sec))
+ for (const auto &atom : section->atoms()) {
+ if (_writeHelper.hasGlobalGOTEntry(atom->_atom)) {
+ this->_dynamicSymbolTable->addSymbol(atom->_atom, section->ordinal(),
+ atom->_virtualAddr, atom);
+ continue;
+ }
+
+ const DefinedAtom *da = dyn_cast<const DefinedAtom>(atom->_atom);
+ if (!da)
+ continue;
+
+ if (da->dynamicExport() != DefinedAtom::dynamicExportAlways &&
+ !this->_context.isDynamicallyExportedSymbol(da->name()) &&
+ !(this->_context.shouldExportDynamic() &&
+ da->scope() == Atom::Scope::scopeGlobal))
+ continue;
+
+ this->_dynamicSymbolTable->addSymbol(atom->_atom, section->ordinal(),
+ atom->_virtualAddr, atom);
+ }
+
+ for (const UndefinedAtom *a : file.undefined())
+ // FIXME (simon): Consider to move this check to the
+ // MipsELFUndefinedAtom class method. That allows to
+ // handle more complex coditions in the future.
+ if (_writeHelper.hasGlobalGOTEntry(a))
+ this->_dynamicSymbolTable->addSymbol(a, ELF::SHN_UNDEF);
+
+ // Skip our immediate parent class method
+ // ExecutableWriter<ELFT>::buildDynamicSymbolTable because we replaced it
+ // with our own version. Call OutputELFWriter directly.
+ OutputELFWriter<ELFT>::buildDynamicSymbolTable(file);
+}
+
+template <class ELFT>
+bool MipsExecutableWriter<ELFT>::createImplicitFiles(
+ std::vector<std::unique_ptr<File>> &result) {
+ ExecutableWriter<ELFT>::createImplicitFiles(result);
+ result.push_back(std::move(_writeHelper.createRuntimeFile()));
+ return true;
+}
+
+template <class ELFT>
+void MipsExecutableWriter<ELFT>::finalizeDefaultAtomValues() {
+ // Finalize the atom values that are part of the parent.
+ ExecutableWriter<ELFT>::finalizeDefaultAtomValues();
+ _writeHelper.finalizeMipsRuntimeAtomValues();
+}
+
+template <class ELFT>
+unique_bump_ptr<SymbolTable<ELFT>>
+ MipsExecutableWriter<ELFT>::createSymbolTable() {
+ return unique_bump_ptr<SymbolTable<ELFT>>(new (
+ this->_alloc) MipsSymbolTable<ELFT>(this->_context));
+}
+
+/// \brief create dynamic table
+template <class ELFT>
+unique_bump_ptr<DynamicTable<ELFT>>
+ MipsExecutableWriter<ELFT>::createDynamicTable() {
+ return unique_bump_ptr<DynamicTable<ELFT>>(new (
+ this->_alloc) MipsDynamicTable<ELFT>(this->_context, _mipsTargetLayout));
+}
+
+/// \brief create dynamic symbol table
+template <class ELFT>
+unique_bump_ptr<DynamicSymbolTable<ELFT>>
+ MipsExecutableWriter<ELFT>::createDynamicSymbolTable() {
+ return unique_bump_ptr<DynamicSymbolTable<ELFT>>(
+ new (this->_alloc) MipsDynamicSymbolTable<ELFT>(
+ this->_context, _mipsTargetLayout));
+}
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp b/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp
new file mode 100644
index 0000000000000..7bffcbeb5c085
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp
@@ -0,0 +1,115 @@
+//===- lib/ReaderWriter/ELF/Mips/MipsLinkingContext.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 "MipsCtorsOrderPass.h"
+#include "MipsLinkingContext.h"
+#include "MipsRelocationPass.h"
+#include "MipsTargetHandler.h"
+
+using namespace lld;
+using namespace lld::elf;
+
+std::unique_ptr<ELFLinkingContext>
+MipsLinkingContext::create(llvm::Triple triple) {
+ if (triple.getArch() == llvm::Triple::mipsel ||
+ triple.getArch() == llvm::Triple::mips64el)
+ return std::unique_ptr<ELFLinkingContext>(new MipsLinkingContext(triple));
+ return nullptr;
+}
+
+typedef std::unique_ptr<TargetHandlerBase> TargetHandlerBasePtr;
+
+static TargetHandlerBasePtr createTarget(llvm::Triple triple,
+ MipsLinkingContext &ctx) {
+ switch (triple.getArch()) {
+ case llvm::Triple::mipsel:
+ return TargetHandlerBasePtr(new MipsTargetHandler<Mips32ELType>(ctx));
+ case llvm::Triple::mips64el:
+ return TargetHandlerBasePtr(new MipsTargetHandler<Mips64ELType>(ctx));
+ default:
+ llvm_unreachable("Unhandled arch");
+ }
+}
+
+MipsLinkingContext::MipsLinkingContext(llvm::Triple triple)
+ : ELFLinkingContext(triple, createTarget(triple, *this)),
+ _flagsMerger(triple.isArch64Bit()) {}
+
+uint32_t MipsLinkingContext::getMergedELFFlags() const {
+ return _flagsMerger.getMergedELFFlags();
+}
+
+MipsELFFlagsMerger &MipsLinkingContext::getELFFlagsMerger() {
+ return _flagsMerger;
+}
+
+uint64_t MipsLinkingContext::getBaseAddress() const {
+ if (_baseAddress == 0 && getOutputELFType() == llvm::ELF::ET_EXEC)
+ return getTriple().isArch64Bit() ? 0x120000000 : 0x400000;
+ return _baseAddress;
+}
+
+StringRef MipsLinkingContext::entrySymbolName() const {
+ if (_outputELFType == elf::ET_EXEC && _entrySymbolName.empty())
+ return "__start";
+ return _entrySymbolName;
+}
+
+StringRef MipsLinkingContext::getDefaultInterpreter() const {
+ return getTriple().isArch64Bit() ? "/lib64/ld.so.1" : "/lib/ld.so.1";
+}
+
+void MipsLinkingContext::addPasses(PassManager &pm) {
+ auto pass = createMipsRelocationPass(*this);
+ if (pass)
+ pm.add(std::move(pass));
+ ELFLinkingContext::addPasses(pm);
+ pm.add(llvm::make_unique<elf::MipsCtorsOrderPass>());
+}
+
+bool MipsLinkingContext::isDynamicRelocation(const Reference &r) const {
+ if (r.kindNamespace() != Reference::KindNamespace::ELF)
+ return false;
+ assert(r.kindArch() == Reference::KindArch::Mips);
+ switch (r.kindValue()) {
+ case llvm::ELF::R_MIPS_COPY:
+ case llvm::ELF::R_MIPS_REL32:
+ case llvm::ELF::R_MIPS_TLS_DTPMOD32:
+ case llvm::ELF::R_MIPS_TLS_DTPREL32:
+ case llvm::ELF::R_MIPS_TLS_TPREL32:
+ case llvm::ELF::R_MIPS_TLS_DTPMOD64:
+ case llvm::ELF::R_MIPS_TLS_DTPREL64:
+ case llvm::ELF::R_MIPS_TLS_TPREL64:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool MipsLinkingContext::isCopyRelocation(const Reference &r) const {
+ if (r.kindNamespace() != Reference::KindNamespace::ELF)
+ return false;
+ assert(r.kindArch() == Reference::KindArch::Mips);
+ if (r.kindValue() == llvm::ELF::R_MIPS_COPY)
+ return true;
+ return false;
+}
+
+bool MipsLinkingContext::isPLTRelocation(const Reference &r) const {
+ if (r.kindNamespace() != Reference::KindNamespace::ELF)
+ return false;
+ assert(r.kindArch() == Reference::KindArch::Mips);
+ switch (r.kindValue()) {
+ case llvm::ELF::R_MIPS_JUMP_SLOT:
+ return true;
+ default:
+ return false;
+ }
+}
diff --git a/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h b/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h
new file mode 100644
index 0000000000000..824605f5fa7f2
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h
@@ -0,0 +1,68 @@
+//===- lib/ReaderWriter/ELF/Mips/MipsLinkingContext.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_MIPS_MIPS_LINKING_CONTEXT_H
+#define LLD_READER_WRITER_ELF_MIPS_MIPS_LINKING_CONTEXT_H
+
+#include "MipsELFFlagsMerger.h"
+#include "lld/ReaderWriter/ELFLinkingContext.h"
+
+namespace lld {
+namespace elf {
+
+/// \brief Mips internal references.
+enum {
+ /// \brief Do nothing but mark GOT entry as a global one.
+ LLD_R_MIPS_GLOBAL_GOT = 1024,
+ /// \brief Apply high 16 bits of symbol + addend.
+ LLD_R_MIPS_32_HI16 = 1025,
+ /// \brief The same as R_MIPS_26 but for global symbols.
+ LLD_R_MIPS_GLOBAL_26 = 1026,
+ /// \brief Setup hi 16 bits using the symbol this reference refers to.
+ LLD_R_MIPS_HI16 = 1027,
+ /// \brief Setup low 16 bits using the symbol this reference refers to.
+ LLD_R_MIPS_LO16 = 1028,
+ /// \brief Represents a reference between PLT and dynamic symbol.
+ LLD_R_MIPS_STO_PLT = 1029,
+ /// \brief The same as R_MICROMIPS_26_S1 but for global symbols.
+ LLD_R_MICROMIPS_GLOBAL_26_S1 = 1030,
+ /// \brief Apply high 32+16 bits of symbol + addend.
+ LLD_R_MIPS_64_HI16 = 1031,
+};
+
+typedef llvm::object::ELFType<llvm::support::little, 2, false> Mips32ELType;
+typedef llvm::object::ELFType<llvm::support::little, 2, true> Mips64ELType;
+typedef llvm::object::ELFType<llvm::support::big, 2, false> Mips32BEType;
+typedef llvm::object::ELFType<llvm::support::big, 2, true> Mips64BEType;
+
+class MipsLinkingContext final : public ELFLinkingContext {
+public:
+ static std::unique_ptr<ELFLinkingContext> create(llvm::Triple);
+ MipsLinkingContext(llvm::Triple triple);
+
+ uint32_t getMergedELFFlags() const;
+ MipsELFFlagsMerger &getELFFlagsMerger();
+
+ // ELFLinkingContext
+ uint64_t getBaseAddress() const override;
+ StringRef entrySymbolName() const override;
+ StringRef getDefaultInterpreter() const override;
+ void addPasses(PassManager &pm) override;
+ bool isRelaOutputFormat() const override { return false; }
+ bool isDynamicRelocation(const Reference &r) const override;
+ bool isCopyRelocation(const Reference &r) const override;
+ bool isPLTRelocation(const Reference &r) const override;
+
+private:
+ MipsELFFlagsMerger _flagsMerger;
+};
+
+} // elf
+} // lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp b/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp
new file mode 100644
index 0000000000000..173ce0e6b1a87
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp
@@ -0,0 +1,606 @@
+//===- lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp ----------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MipsTargetHandler.h"
+#include "MipsLinkingContext.h"
+#include "MipsRelocationHandler.h"
+
+using namespace lld;
+using namespace elf;
+using namespace llvm::ELF;
+using namespace llvm::support;
+
+namespace {
+enum class CrossJumpMode {
+ None, // Not a jump or non-isa-cross jump
+ ToRegular, // cross isa jump to regular symbol
+ ToMicro // cross isa jump to microMips symbol
+};
+
+struct MipsRelocationParams {
+ uint8_t _size; // Relocations's size in bytes
+ uint64_t _mask; // Read/write mask of relocation
+ uint8_t _shift; // Relocation's addendum left shift size
+ bool _shuffle; // Relocation's addendum/result needs to be shuffled
+};
+
+template <class ELFT> class RelocationHandler : public MipsRelocationHandler {
+public:
+ RelocationHandler(MipsLinkingContext &ctx) : _ctx(ctx) {}
+
+ std::error_code applyRelocation(ELFWriter &writer,
+ llvm::FileOutputBuffer &buf,
+ const lld::AtomLayout &atom,
+ const Reference &ref) const override;
+
+ Reference::Addend readAddend(Reference::KindValue kind,
+ const uint8_t *content) const override;
+
+private:
+ MipsLinkingContext &_ctx;
+};
+}
+
+static MipsRelocationParams getRelocationParams(uint32_t rType) {
+ switch (rType) {
+ case R_MIPS_NONE:
+ return {4, 0x0, 0, false};
+ case R_MIPS_64:
+ case R_MIPS_SUB:
+ return {8, 0xffffffffffffffffull, 0, false};
+ case R_MIPS_32:
+ case R_MIPS_GPREL32:
+ case R_MIPS_PC32:
+ return {4, 0xffffffff, 0, false};
+ case LLD_R_MIPS_32_HI16:
+ return {4, 0xffff0000, 0, false};
+ case LLD_R_MIPS_64_HI16:
+ return {8, 0xffffffffffff0000ull, 0, false};
+ case R_MIPS_26:
+ case LLD_R_MIPS_GLOBAL_26:
+ return {4, 0x3ffffff, 2, false};
+ case R_MIPS_PC18_S3:
+ return {4, 0x3ffff, 3, false};
+ case R_MIPS_PC19_S2:
+ return {4, 0x7ffff, 2, false};
+ case R_MIPS_PC21_S2:
+ return {4, 0x1fffff, 2, false};
+ case R_MIPS_PC26_S2:
+ return {4, 0x3ffffff, 2, false};
+ case R_MIPS_HI16:
+ case R_MIPS_LO16:
+ case R_MIPS_PCHI16:
+ case R_MIPS_PCLO16:
+ case R_MIPS_GPREL16:
+ case R_MIPS_GOT16:
+ case R_MIPS_GOT_DISP:
+ case R_MIPS_GOT_PAGE:
+ case R_MIPS_GOT_OFST:
+ case R_MIPS_TLS_DTPREL_HI16:
+ case R_MIPS_TLS_DTPREL_LO16:
+ case R_MIPS_TLS_TPREL_HI16:
+ case R_MIPS_TLS_TPREL_LO16:
+ case LLD_R_MIPS_HI16:
+ case LLD_R_MIPS_LO16:
+ return {4, 0xffff, 0, false};
+ case R_MICROMIPS_TLS_DTPREL_HI16:
+ case R_MICROMIPS_TLS_DTPREL_LO16:
+ case R_MICROMIPS_TLS_TPREL_HI16:
+ case R_MICROMIPS_TLS_TPREL_LO16:
+ return {4, 0xffff, 0, true};
+ case R_MICROMIPS_26_S1:
+ case LLD_R_MICROMIPS_GLOBAL_26_S1:
+ return {4, 0x3ffffff, 1, true};
+ case R_MICROMIPS_HI16:
+ case R_MICROMIPS_LO16:
+ case R_MICROMIPS_GOT16:
+ return {4, 0xffff, 0, true};
+ case R_MICROMIPS_PC16_S1:
+ return {4, 0xffff, 1, true};
+ case R_MICROMIPS_PC7_S1:
+ return {4, 0x7f, 1, false};
+ case R_MICROMIPS_PC10_S1:
+ return {4, 0x3ff, 1, false};
+ case R_MICROMIPS_PC23_S2:
+ return {4, 0x7fffff, 2, true};
+ case R_MIPS_CALL16:
+ case R_MIPS_TLS_GD:
+ case R_MIPS_TLS_LDM:
+ case R_MIPS_TLS_GOTTPREL:
+ return {4, 0xffff, 0, false};
+ case R_MICROMIPS_CALL16:
+ case R_MICROMIPS_TLS_GD:
+ case R_MICROMIPS_TLS_LDM:
+ case R_MICROMIPS_TLS_GOTTPREL:
+ return {4, 0xffff, 0, true};
+ case R_MIPS_JALR:
+ return {4, 0x0, 0, false};
+ case R_MICROMIPS_JALR:
+ return {4, 0x0, 0, true};
+ case R_MIPS_REL32:
+ case R_MIPS_JUMP_SLOT:
+ case R_MIPS_COPY:
+ case R_MIPS_TLS_DTPMOD32:
+ case R_MIPS_TLS_DTPREL32:
+ case R_MIPS_TLS_TPREL32:
+ // Ignore runtime relocations.
+ return {4, 0x0, 0, false};
+ case R_MIPS_TLS_DTPMOD64:
+ case R_MIPS_TLS_DTPREL64:
+ case R_MIPS_TLS_TPREL64:
+ return {8, 0x0, 0, false};
+ case LLD_R_MIPS_GLOBAL_GOT:
+ case LLD_R_MIPS_STO_PLT:
+ // Do nothing.
+ return {4, 0x0, 0, false};
+ default:
+ llvm_unreachable("Unknown relocation");
+ }
+}
+
+/// \brief R_MIPS_32
+/// local/external: word32 S + A (truncate)
+static uint32_t reloc32(uint64_t S, int64_t A) { return S + A; }
+
+/// \brief R_MIPS_64
+/// local/external: word64 S + A (truncate)
+static uint64_t reloc64(uint64_t S, int64_t A) { return S + A; }
+
+/// \brief R_MIPS_SUB
+/// local/external: word64 S - A (truncate)
+static uint64_t relocSub(uint64_t S, int64_t A) { return S - A; }
+
+/// \brief R_MIPS_PC32
+/// local/external: word32 S + A i- P (truncate)
+static uint32_t relocpc32(uint64_t P, uint64_t S, int64_t A) {
+ return S + A - P;
+}
+
+/// \brief R_MIPS_26, R_MICROMIPS_26_S1
+/// local : ((A | ((P + 4) & 0x3F000000)) + S) >> 2
+static uint32_t reloc26loc(uint64_t P, uint64_t S, int32_t A, uint32_t shift) {
+ uint32_t result = (A | ((P + 4) & (0xfc000000 << shift))) + S;
+ return result >> shift;
+}
+
+/// \brief LLD_R_MIPS_GLOBAL_26, LLD_R_MICROMIPS_GLOBAL_26_S1
+/// external: (sign-extend(A) + S) >> 2
+static uint32_t reloc26ext(uint64_t S, int32_t A, uint32_t shift) {
+ int32_t result =
+ shift == 1 ? llvm::SignExtend32<27>(A) : llvm::SignExtend32<28>(A);
+ return (result + S) >> shift;
+}
+
+/// \brief R_MIPS_HI16, R_MIPS_TLS_DTPREL_HI16, R_MIPS_TLS_TPREL_HI16,
+/// R_MICROMIPS_HI16, R_MICROMIPS_TLS_DTPREL_HI16, R_MICROMIPS_TLS_TPREL_HI16,
+/// LLD_R_MIPS_HI16
+/// local/external: hi16 (AHL + S) - (short)(AHL + S) (truncate)
+/// _gp_disp : hi16 (AHL + GP - P) - (short)(AHL + GP - P) (verify)
+static uint32_t relocHi16(uint64_t P, uint64_t S, int64_t AHL, bool isGPDisp) {
+ int32_t result = isGPDisp ? AHL + S - P : AHL + S;
+ return (result + 0x8000) >> 16;
+}
+
+/// \brief R_MIPS_PCHI16
+/// local/external: hi16 (S + AHL - P)
+static uint32_t relocPcHi16(uint64_t P, uint64_t S, int64_t AHL) {
+ int32_t result = S + AHL - P;
+ return (result + 0x8000) >> 16;
+}
+
+/// \brief R_MIPS_LO16, R_MIPS_TLS_DTPREL_LO16, R_MIPS_TLS_TPREL_LO16,
+/// R_MICROMIPS_LO16, R_MICROMIPS_TLS_DTPREL_LO16, R_MICROMIPS_TLS_TPREL_LO16,
+/// LLD_R_MIPS_LO16
+/// local/external: lo16 AHL + S (truncate)
+/// _gp_disp : lo16 AHL + GP - P + 4 (verify)
+static uint32_t relocLo16(uint64_t P, uint64_t S, int64_t AHL, bool isGPDisp,
+ bool micro) {
+ int32_t result = isGPDisp ? AHL + S - P + (micro ? 3 : 4) : AHL + S;
+ return result;
+}
+
+/// \brief R_MIPS_PCLO16
+/// local/external: lo16 (S + AHL - P)
+static uint32_t relocPcLo16(uint64_t P, uint64_t S, int64_t AHL) {
+ AHL = llvm::SignExtend32<16>(AHL);
+ int32_t result = S + AHL - P;
+ return result;
+}
+
+/// \brief R_MIPS_GOT16, R_MIPS_CALL16, R_MICROMIPS_GOT16, R_MICROMIPS_CALL16
+/// rel16 G (verify)
+static uint64_t relocGOT(uint64_t S, uint64_t GP) {
+ int64_t G = (int64_t)(S - GP);
+ return G;
+}
+
+/// R_MIPS_GOT_OFST
+/// rel16 offset of (S+A) from the page pointer (verify)
+static uint32_t relocGOTOfst(uint64_t S, int64_t A) {
+ uint64_t page = (S + A + 0x8000) & ~0xffff;
+ return S + A - page;
+}
+
+/// \brief R_MIPS_GPREL16
+/// local: sign-extend(A) + S + GP0 - GP
+/// external: sign-extend(A) + S - GP
+static uint64_t relocGPRel16(uint64_t S, int64_t A, uint64_t GP) {
+ // We added GP0 to addendum for a local symbol during a Relocation pass.
+ return llvm::SignExtend32<16>(A) + S - GP;
+}
+
+/// \brief R_MIPS_GPREL32
+/// local: rel32 A + S + GP0 - GP (truncate)
+static uint64_t relocGPRel32(uint64_t S, int64_t A, uint64_t GP) {
+ // We added GP0 to addendum for a local symbol during a Relocation pass.
+ return A + S - GP;
+}
+
+/// \brief R_MIPS_PC18_S3
+/// local/external: (S + A - P) >> 3 (P with cleared 3 less significant bits)
+static uint32_t relocPc18(uint64_t P, uint64_t S, int64_t A) {
+ A = llvm::SignExtend32<21>(A);
+ // FIXME (simon): Check that S + A has 8-byte alignment
+ int32_t result = S + A - ((P | 7) ^ 7);
+ return result >> 3;
+}
+
+/// \brief R_MIPS_PC19_S2
+/// local/external: (S + A - P) >> 2
+static uint32_t relocPc19(uint64_t P, uint64_t S, int64_t A) {
+ A = llvm::SignExtend32<21>(A);
+ // FIXME (simon): Check that S + A has 4-byte alignment
+ int32_t result = S + A - P;
+ return result >> 2;
+}
+
+/// \brief R_MIPS_PC21_S2
+/// local/external: (S + A - P) >> 2
+static uint32_t relocPc21(uint64_t P, uint64_t S, int64_t A) {
+ A = llvm::SignExtend32<23>(A);
+ // FIXME (simon): Check that S + A has 4-byte alignment
+ int32_t result = S + A - P;
+ return result >> 2;
+}
+
+/// \brief R_MIPS_PC26_S2
+/// local/external: (S + A - P) >> 2
+static uint32_t relocPc26(uint64_t P, uint64_t S, int64_t A) {
+ A = llvm::SignExtend32<28>(A);
+ // FIXME (simon): Check that S + A has 4-byte alignment
+ int32_t result = S + A - P;
+ return result >> 2;
+}
+
+/// \brief R_MICROMIPS_PC7_S1
+static uint32_t relocPc7(uint64_t P, uint64_t S, int64_t A) {
+ A = llvm::SignExtend32<8>(A);
+ int32_t result = S + A - P;
+ return result >> 1;
+}
+
+/// \brief R_MICROMIPS_PC10_S1
+static uint32_t relocPc10(uint64_t P, uint64_t S, int64_t A) {
+ A = llvm::SignExtend32<11>(A);
+ int32_t result = S + A - P;
+ return result >> 1;
+}
+
+/// \brief R_MICROMIPS_PC16_S1
+static uint32_t relocPc16(uint64_t P, uint64_t S, int64_t A) {
+ A = llvm::SignExtend32<17>(A);
+ int32_t result = S + A - P;
+ return result >> 1;
+}
+
+/// \brief R_MICROMIPS_PC23_S2
+static uint32_t relocPc23(uint64_t P, uint64_t S, int64_t A) {
+ A = llvm::SignExtend32<25>(A);
+ int32_t result = S + A - P;
+
+ // Check addiupc 16MB range.
+ if (result + 0x1000000 >= 0x2000000)
+ llvm::errs() << "The addiupc instruction immediate "
+ << llvm::format_hex(result, 10) << " is out of range.\n";
+
+ return result >> 2;
+}
+
+/// \brief LLD_R_MIPS_32_HI16, LLD_R_MIPS_64_HI16
+static uint64_t relocMaskLow16(uint64_t S, int64_t A) {
+ return S + A + 0x8000;
+}
+
+static std::error_code adjustJumpOpCode(uint64_t &ins, uint64_t tgt,
+ CrossJumpMode mode) {
+ if (mode == CrossJumpMode::None)
+ return std::error_code();
+
+ bool toMicro = mode == CrossJumpMode::ToMicro;
+ uint32_t opNative = toMicro ? 0x03 : 0x3d;
+ uint32_t opCross = toMicro ? 0x1d : 0x3c;
+
+ if ((tgt & 1) != toMicro)
+ return make_dynamic_error_code(
+ Twine("Incorrect bit 0 for the jalx target"));
+
+ if (tgt & 2)
+ return make_dynamic_error_code(Twine("The jalx target 0x") +
+ Twine::utohexstr(tgt) +
+ " is not word-aligned");
+ uint8_t op = ins >> 26;
+ if (op != opNative && op != opCross)
+ return make_dynamic_error_code(Twine("Unsupported jump opcode (0x") +
+ Twine::utohexstr(op) +
+ ") for ISA modes cross call");
+
+ ins = (ins & ~(0x3f << 26)) | (opCross << 26);
+ return std::error_code();
+}
+
+static bool isMicroMipsAtom(const Atom *a) {
+ if (const auto *da = dyn_cast<DefinedAtom>(a))
+ return da->codeModel() == DefinedAtom::codeMipsMicro ||
+ da->codeModel() == DefinedAtom::codeMipsMicroPIC;
+ return false;
+}
+
+static CrossJumpMode getCrossJumpMode(const Reference &ref) {
+ if (!isa<DefinedAtom>(ref.target()))
+ return CrossJumpMode::None;
+ bool isTgtMicro = isMicroMipsAtom(ref.target());
+ switch (ref.kindValue()) {
+ case R_MIPS_26:
+ case LLD_R_MIPS_GLOBAL_26:
+ return isTgtMicro ? CrossJumpMode::ToMicro : CrossJumpMode::None;
+ case R_MICROMIPS_26_S1:
+ case LLD_R_MICROMIPS_GLOBAL_26_S1:
+ return isTgtMicro ? CrossJumpMode::None : CrossJumpMode::ToRegular;
+ default:
+ return CrossJumpMode::None;
+ }
+}
+
+static uint32_t microShuffle(uint32_t ins) {
+ return ((ins & 0xffff) << 16) | ((ins & 0xffff0000) >> 16);
+}
+
+static ErrorOr<uint64_t> calculateRelocation(Reference::KindValue kind,
+ Reference::Addend addend,
+ uint64_t tgtAddr, uint64_t relAddr,
+ uint64_t gpAddr, bool isGP,
+ CrossJumpMode jumpMode) {
+ bool isCrossJump = jumpMode != CrossJumpMode::None;
+ switch (kind) {
+ case R_MIPS_NONE:
+ return 0;
+ case R_MIPS_32:
+ return reloc32(tgtAddr, addend);
+ case R_MIPS_64:
+ return reloc64(tgtAddr, addend);
+ case R_MIPS_SUB:
+ return relocSub(tgtAddr, addend);
+ case R_MIPS_26:
+ return reloc26loc(relAddr, tgtAddr, addend, 2);
+ case R_MICROMIPS_26_S1:
+ return reloc26loc(relAddr, tgtAddr, addend, isCrossJump ? 2 : 1);
+ case R_MIPS_HI16:
+ case R_MICROMIPS_HI16:
+ return relocHi16(relAddr, tgtAddr, addend, isGP);
+ case R_MIPS_PCHI16:
+ return relocPcHi16(relAddr, tgtAddr, addend);
+ case R_MIPS_LO16:
+ return relocLo16(relAddr, tgtAddr, addend, isGP, false);
+ case R_MIPS_PCLO16:
+ return relocPcLo16(relAddr, tgtAddr, addend);
+ case R_MICROMIPS_LO16:
+ return relocLo16(relAddr, tgtAddr, addend, isGP, true);
+ case R_MIPS_GOT16:
+ case R_MIPS_CALL16:
+ case R_MIPS_GOT_DISP:
+ case R_MIPS_GOT_PAGE:
+ case R_MICROMIPS_GOT16:
+ case R_MICROMIPS_CALL16:
+ case R_MIPS_TLS_GD:
+ case R_MIPS_TLS_LDM:
+ case R_MIPS_TLS_GOTTPREL:
+ case R_MICROMIPS_TLS_GD:
+ case R_MICROMIPS_TLS_LDM:
+ case R_MICROMIPS_TLS_GOTTPREL:
+ return relocGOT(tgtAddr, gpAddr);
+ case R_MIPS_GOT_OFST:
+ return relocGOTOfst(tgtAddr, addend);
+ case R_MIPS_PC18_S3:
+ return relocPc18(relAddr, tgtAddr, addend);
+ case R_MIPS_PC19_S2:
+ return relocPc19(relAddr, tgtAddr, addend);
+ case R_MIPS_PC21_S2:
+ return relocPc21(relAddr, tgtAddr, addend);
+ case R_MIPS_PC26_S2:
+ return relocPc26(relAddr, tgtAddr, addend);
+ case R_MICROMIPS_PC7_S1:
+ return relocPc7(relAddr, tgtAddr, addend);
+ case R_MICROMIPS_PC10_S1:
+ return relocPc10(relAddr, tgtAddr, addend);
+ case R_MICROMIPS_PC16_S1:
+ return relocPc16(relAddr, tgtAddr, addend);
+ case R_MICROMIPS_PC23_S2:
+ return relocPc23(relAddr, tgtAddr, addend);
+ case R_MIPS_TLS_DTPREL_HI16:
+ case R_MIPS_TLS_TPREL_HI16:
+ case R_MICROMIPS_TLS_DTPREL_HI16:
+ case R_MICROMIPS_TLS_TPREL_HI16:
+ return relocHi16(0, tgtAddr, addend, false);
+ case R_MIPS_TLS_DTPREL_LO16:
+ case R_MIPS_TLS_TPREL_LO16:
+ return relocLo16(0, tgtAddr, addend, false, false);
+ case R_MICROMIPS_TLS_DTPREL_LO16:
+ case R_MICROMIPS_TLS_TPREL_LO16:
+ return relocLo16(0, tgtAddr, addend, false, true);
+ case R_MIPS_GPREL16:
+ return relocGPRel16(tgtAddr, addend, gpAddr);
+ case R_MIPS_GPREL32:
+ return relocGPRel32(tgtAddr, addend, gpAddr);
+ case R_MIPS_JALR:
+ case R_MICROMIPS_JALR:
+ // We do not do JALR optimization now.
+ return 0;
+ case R_MIPS_REL32:
+ case R_MIPS_JUMP_SLOT:
+ case R_MIPS_COPY:
+ case R_MIPS_TLS_DTPMOD32:
+ case R_MIPS_TLS_DTPREL32:
+ case R_MIPS_TLS_TPREL32:
+ case R_MIPS_TLS_DTPMOD64:
+ case R_MIPS_TLS_DTPREL64:
+ case R_MIPS_TLS_TPREL64:
+ // Ignore runtime relocations.
+ return 0;
+ case R_MIPS_PC32:
+ return relocpc32(relAddr, tgtAddr, addend);
+ case LLD_R_MIPS_GLOBAL_GOT:
+ // Do nothing.
+ case LLD_R_MIPS_32_HI16:
+ case LLD_R_MIPS_64_HI16:
+ return relocMaskLow16(tgtAddr, addend);
+ case LLD_R_MIPS_GLOBAL_26:
+ return reloc26ext(tgtAddr, addend, 2);
+ case LLD_R_MICROMIPS_GLOBAL_26_S1:
+ return reloc26ext(tgtAddr, addend, isCrossJump ? 2 : 1);
+ case LLD_R_MIPS_HI16:
+ return relocHi16(0, tgtAddr, 0, false);
+ case LLD_R_MIPS_LO16:
+ return relocLo16(0, tgtAddr, 0, false, false);
+ case LLD_R_MIPS_STO_PLT:
+ // Do nothing.
+ return 0;
+ default:
+ return make_unhandled_reloc_error();
+ }
+}
+
+template <class ELFT>
+static uint64_t relocRead(const MipsRelocationParams &params,
+ const uint8_t *loc) {
+ uint64_t data;
+ switch (params._size) {
+ case 4:
+ data = endian::read<uint32_t, ELFT::TargetEndianness, unaligned>(loc);
+ break;
+ case 8:
+ data = endian::read<uint64_t, ELFT::TargetEndianness, unaligned>(loc);
+ break;
+ default:
+ llvm_unreachable("Unexpected size");
+ }
+ if (params._shuffle)
+ data = microShuffle(data);
+ return data;
+}
+
+template <class ELFT>
+static void relocWrite(uint64_t data, const MipsRelocationParams &params,
+ uint8_t *loc) {
+ if (params._shuffle)
+ data = microShuffle(data);
+ switch (params._size) {
+ case 4:
+ endian::write<uint32_t, ELFT::TargetEndianness, unaligned>(loc, data);
+ break;
+ case 8:
+ endian::write<uint64_t, ELFT::TargetEndianness, unaligned>(loc, data);
+ break;
+ default:
+ llvm_unreachable("Unexpected size");
+ }
+}
+
+template <class ELFT>
+std::error_code RelocationHandler<ELFT>::applyRelocation(
+ ELFWriter &writer, llvm::FileOutputBuffer &buf, const lld::AtomLayout &atom,
+ const Reference &ref) const {
+ if (ref.kindNamespace() != lld::Reference::KindNamespace::ELF)
+ return std::error_code();
+ assert(ref.kindArch() == Reference::KindArch::Mips);
+
+ auto &targetLayout = static_cast<MipsTargetLayout<ELFT> &>(
+ _ctx.getTargetHandler<ELFT>().getTargetLayout());
+
+ AtomLayout *gpAtom = targetLayout.getGP();
+ uint64_t gpAddr = gpAtom ? gpAtom->_virtualAddr : 0;
+
+ AtomLayout *gpDispAtom = targetLayout.getGPDisp();
+ bool isGpDisp = gpDispAtom && ref.target() == gpDispAtom->_atom;
+
+ uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset;
+ uint8_t *location = atomContent + ref.offsetInAtom();
+ uint64_t tgtAddr = writer.addressOfAtom(ref.target());
+ uint64_t relAddr = atom._virtualAddr + ref.offsetInAtom();
+
+ if (isMicroMipsAtom(ref.target()))
+ tgtAddr |= 1;
+
+ CrossJumpMode jumpMode = getCrossJumpMode(ref);
+
+ ErrorOr<uint64_t> res =
+ calculateRelocation(ref.kindValue(), ref.addend(), tgtAddr, relAddr,
+ gpAddr, isGpDisp, jumpMode);
+ if (auto ec = res.getError())
+ return ec;
+
+ Reference::KindValue op = ref.kindValue();
+
+ // FIXME (simon): Handle r_ssym value.
+ for (auto tag = (ref.tag() & 0xffff); tag & 0xff; tag >>= 8) {
+ op = tag & 0xff;
+ res = calculateRelocation(op, *res, 0, relAddr, gpAddr, isGpDisp, jumpMode);
+ if (auto ec = res.getError())
+ return ec;
+ }
+
+ auto params = getRelocationParams(op);
+ uint64_t ins = relocRead<ELFT>(params, location);
+
+ if (auto ec = adjustJumpOpCode(ins, tgtAddr, jumpMode))
+ return ec;
+
+ ins = (ins & ~params._mask) | (*res & params._mask);
+ relocWrite<ELFT>(ins, params, location);
+
+ return std::error_code();
+}
+
+template <class ELFT>
+Reference::Addend
+RelocationHandler<ELFT>::readAddend(Reference::KindValue kind,
+ const uint8_t *content) const {
+ auto params = getRelocationParams(kind);
+ uint64_t ins = relocRead<ELFT>(params, content);
+ return (ins & params._mask) << params._shift;
+}
+
+namespace lld {
+namespace elf {
+
+template <>
+std::unique_ptr<TargetRelocationHandler>
+createMipsRelocationHandler<Mips32ELType>(MipsLinkingContext &ctx) {
+ return std::unique_ptr<TargetRelocationHandler>(
+ new RelocationHandler<Mips32ELType>(ctx));
+}
+
+template <>
+std::unique_ptr<TargetRelocationHandler>
+createMipsRelocationHandler<Mips64ELType>(MipsLinkingContext &ctx) {
+ return std::unique_ptr<TargetRelocationHandler>(
+ new RelocationHandler<Mips64ELType>(ctx));
+}
+
+} // elf
+} // lld
diff --git a/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.h b/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.h
new file mode 100644
index 0000000000000..87066b2b5c101
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.h
@@ -0,0 +1,31 @@
+//===- lld/ReaderWriter/ELF/Mips/MipsRelocationHandler.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_MIPS_MIPS_RELOCATION_HANDLER_H
+#define LLD_READER_WRITER_ELF_MIPS_MIPS_RELOCATION_HANDLER_H
+
+#include "TargetHandler.h"
+#include "lld/Core/Reference.h"
+
+namespace lld {
+namespace elf {
+
+class MipsRelocationHandler : public TargetRelocationHandler {
+public:
+ virtual Reference::Addend readAddend(Reference::KindValue kind,
+ const uint8_t *content) const = 0;
+};
+
+template <class ELFT>
+std::unique_ptr<TargetRelocationHandler>
+createMipsRelocationHandler(MipsLinkingContext &ctx);
+
+} // elf
+} // lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp b/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp
new file mode 100644
index 0000000000000..a1b3530dfcdf6
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp
@@ -0,0 +1,1070 @@
+//===- lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp -------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MipsELFFile.h"
+#include "MipsLinkingContext.h"
+#include "MipsRelocationPass.h"
+#include "MipsTargetHandler.h"
+#include "llvm/ADT/DenseSet.h"
+
+using namespace lld;
+using namespace lld::elf;
+using namespace llvm::ELF;
+
+// Lazy resolver
+static const uint8_t mipsGot0AtomContent[] = {
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+// Module pointer
+static const uint8_t mipsGotModulePointerAtomContent[] = {
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x80
+};
+
+// TLS GD Entry
+static const uint8_t mipsGotTlsGdAtomContent[] = {
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+// Regular PLT0 entry
+static const uint8_t mipsPlt0AtomContent[] = {
+ 0x00, 0x00, 0x1c, 0x3c, // lui $28, %hi(&GOTPLT[0])
+ 0x00, 0x00, 0x99, 0x8f, // lw $25, %lo(&GOTPLT[0])($28)
+ 0x00, 0x00, 0x9c, 0x27, // addiu $28, $28, %lo(&GOTPLT[0])
+ 0x23, 0xc0, 0x1c, 0x03, // subu $24, $24, $28
+ 0x21, 0x78, 0xe0, 0x03, // move $15, $31
+ 0x82, 0xc0, 0x18, 0x00, // srl $24, $24, 2
+ 0x09, 0xf8, 0x20, 0x03, // jalr $25
+ 0xfe, 0xff, 0x18, 0x27 // subu $24, $24, 2
+};
+
+// microMIPS PLT0 entry
+static const uint8_t micromipsPlt0AtomContent[] = {
+ 0x80, 0x79, 0x00, 0x00, // addiupc $3, (&GOTPLT[0]) - .
+ 0x23, 0xff, 0x00, 0x00, // lw $25, 0($3)
+ 0x35, 0x05, // subu $2, $2, $3
+ 0x25, 0x25, // srl $2, $2, 2
+ 0x02, 0x33, 0xfe, 0xff, // subu $24, $2, 2
+ 0xff, 0x0d, // move $15, $31
+ 0xf9, 0x45, // jalrs $25
+ 0x83, 0x0f, // move $28, $3
+ 0x00, 0x0c // nop
+};
+
+// Regular PLT entry
+static const uint8_t mipsPltAAtomContent[] = {
+ 0x00, 0x00, 0x0f, 0x3c, // lui $15, %hi(.got.plt entry)
+ 0x00, 0x00, 0xf9, 0x8d, // l[wd] $25, %lo(.got.plt entry)($15)
+ 0x08, 0x00, 0x20, 0x03, // jr $25
+ 0x00, 0x00, 0xf8, 0x25 // addiu $24, $15, %lo(.got.plt entry)
+};
+
+// microMIPS PLT entry
+static const uint8_t micromipsPltAtomContent[] = {
+ 0x00, 0x79, 0x00, 0x00, // addiupc $2, (.got.plt entry) - .
+ 0x22, 0xff, 0x00, 0x00, // lw $25, 0($2)
+ 0x99, 0x45, // jr $25
+ 0x02, 0x0f // move $24, $2
+};
+
+// R6 PLT entry
+static const uint8_t mipsR6PltAAtomContent[] = {
+ 0x00, 0x00, 0x0f, 0x3c, // lui $15, %hi(.got.plt entry)
+ 0x00, 0x00, 0xf9, 0x8d, // l[wd] $25, %lo(.got.plt entry)($15)
+ 0x09, 0x00, 0x20, 0x03, // jr $25
+ 0x00, 0x00, 0xf8, 0x25 // addiu $24, $15, %lo(.got.plt entry)
+};
+
+// LA25 stub entry
+static const uint8_t mipsLA25AtomContent[] = {
+ 0x00, 0x00, 0x19, 0x3c, // lui $25, %hi(func)
+ 0x00, 0x00, 0x00, 0x08, // j func
+ 0x00, 0x00, 0x39, 0x27, // addiu $25, $25, %lo(func)
+ 0x00, 0x00, 0x00, 0x00 // nop
+};
+
+// microMIPS LA25 stub entry
+static const uint8_t micromipsLA25AtomContent[] = {
+ 0xb9, 0x41, 0x00, 0x00, // lui $25, %hi(func)
+ 0x00, 0xd4, 0x00, 0x00, // j func
+ 0x39, 0x33, 0x00, 0x00, // addiu $25, $25, %lo(func)
+ 0x00, 0x00, 0x00, 0x00 // nop
+};
+
+namespace {
+
+/// \brief Abstract base class represent MIPS GOT entries.
+class MipsGOTAtom : public GOTAtom {
+public:
+ MipsGOTAtom(const File &f) : GOTAtom(f, ".got") {}
+
+ Alignment alignment() const override { return Alignment(2); }
+};
+
+/// \brief MIPS GOT entry initialized by zero.
+template <typename ELFT> class GOT0Atom : public MipsGOTAtom {
+public:
+ GOT0Atom(const File &f) : MipsGOTAtom(f) {}
+
+ ArrayRef<uint8_t> rawContent() const override;
+};
+
+template <> ArrayRef<uint8_t> GOT0Atom<Mips32ELType>::rawContent() const {
+ return llvm::makeArrayRef(mipsGot0AtomContent).slice(4);
+}
+template <> ArrayRef<uint8_t> GOT0Atom<Mips64ELType>::rawContent() const {
+ return llvm::makeArrayRef(mipsGot0AtomContent);
+}
+
+/// \brief MIPS GOT entry initialized by zero.
+template <typename ELFT> class GOTModulePointerAtom : public MipsGOTAtom {
+public:
+ GOTModulePointerAtom(const File &f) : MipsGOTAtom(f) {}
+
+ ArrayRef<uint8_t> rawContent() const override;
+};
+
+template <>
+ArrayRef<uint8_t> GOTModulePointerAtom<Mips32ELType>::rawContent() const {
+ return llvm::makeArrayRef(mipsGotModulePointerAtomContent).slice(4);
+}
+template <>
+ArrayRef<uint8_t> GOTModulePointerAtom<Mips64ELType>::rawContent() const {
+ return llvm::makeArrayRef(mipsGotModulePointerAtomContent);
+}
+
+/// \brief MIPS GOT TLS GD entry.
+template <typename ELFT> class GOTTLSGdAtom : public MipsGOTAtom {
+public:
+ GOTTLSGdAtom(const File &f) : MipsGOTAtom(f) {}
+
+ ArrayRef<uint8_t> rawContent() const override;
+};
+
+template <> ArrayRef<uint8_t> GOTTLSGdAtom<Mips32ELType>::rawContent() const {
+ return llvm::makeArrayRef(mipsGotTlsGdAtomContent).slice(8);
+}
+
+template <> ArrayRef<uint8_t> GOTTLSGdAtom<Mips64ELType>::rawContent() const {
+ return llvm::makeArrayRef(mipsGotTlsGdAtomContent);
+}
+
+class GOTPLTAtom : public GOTAtom {
+public:
+ GOTPLTAtom(const File &f) : GOTAtom(f, ".got.plt") {}
+ GOTPLTAtom(const Atom *a, const File &f) : GOTAtom(f, ".got.plt") {
+ // Create dynamic relocation to adjust the .got.plt entry at runtime.
+ addReferenceELF_Mips(R_MIPS_JUMP_SLOT, 0, a, 0);
+ }
+
+ /// Setup reference to assign initial value to the .got.plt entry.
+ void setPLT0(const PLTAtom *plt0) {
+ addReferenceELF_Mips(R_MIPS_32, 0, plt0, 0);
+ }
+
+ Alignment alignment() const override { return Alignment(2); }
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return llvm::makeArrayRef(mipsGot0AtomContent).slice(4);
+ }
+};
+
+class PLT0Atom : public PLTAtom {
+public:
+ PLT0Atom(const Atom *got, const File &f) : PLTAtom(f, ".plt") {
+ // Setup reference to fixup the PLT0 entry.
+ addReferenceELF_Mips(LLD_R_MIPS_HI16, 0, got, 0);
+ addReferenceELF_Mips(LLD_R_MIPS_LO16, 4, got, 0);
+ addReferenceELF_Mips(LLD_R_MIPS_LO16, 8, got, 0);
+ }
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return llvm::makeArrayRef(mipsPlt0AtomContent);
+ }
+};
+
+class PLT0MicroAtom : public PLTAtom {
+public:
+ PLT0MicroAtom(const Atom *got, const File &f) : PLTAtom(f, ".plt") {
+ // Setup reference to fixup the PLT0 entry.
+ addReferenceELF_Mips(R_MICROMIPS_PC23_S2, 0, got, 0);
+ }
+
+ CodeModel codeModel() const override { return codeMipsMicro; }
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return llvm::makeArrayRef(micromipsPlt0AtomContent);
+ }
+};
+
+class PLTAAtom : public PLTAtom {
+public:
+ PLTAAtom(const GOTPLTAtom *got, const File &f) : PLTAtom(f, ".plt") {
+ // Setup reference to fixup the PLT entry.
+ addReferenceELF_Mips(LLD_R_MIPS_HI16, 0, got, 0);
+ addReferenceELF_Mips(LLD_R_MIPS_LO16, 4, got, 0);
+ addReferenceELF_Mips(LLD_R_MIPS_LO16, 12, got, 0);
+ }
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return llvm::makeArrayRef(mipsPltAAtomContent);
+ }
+};
+
+class PLTR6Atom : public PLTAAtom {
+public:
+ PLTR6Atom(const GOTPLTAtom *got, const File &f) : PLTAAtom(got, f) {}
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return llvm::makeArrayRef(mipsR6PltAAtomContent);
+ }
+};
+
+class PLTMicroAtom : public PLTAtom {
+public:
+ PLTMicroAtom(const GOTPLTAtom *got, const File &f) : PLTAtom(f, ".plt") {
+ // Setup reference to fixup the microMIPS PLT entry.
+ addReferenceELF_Mips(R_MICROMIPS_PC23_S2, 0, got, 0);
+ }
+
+ Alignment alignment() const override { return Alignment(1); }
+ CodeModel codeModel() const override { return codeMipsMicro; }
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return llvm::makeArrayRef(micromipsPltAtomContent);
+ }
+};
+
+class LA25Atom : public PLTAtom {
+public:
+ LA25Atom(const File &f) : PLTAtom(f, ".text") {}
+};
+
+class LA25RegAtom : public LA25Atom {
+public:
+ LA25RegAtom(const Atom *a, const File &f) : LA25Atom(f) {
+ // Setup reference to fixup the LA25 stub entry.
+ addReferenceELF_Mips(R_MIPS_HI16, 0, a, 0);
+ addReferenceELF_Mips(R_MIPS_26, 4, a, 0);
+ addReferenceELF_Mips(R_MIPS_LO16, 8, a, 0);
+ }
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return llvm::makeArrayRef(mipsLA25AtomContent);
+ }
+};
+
+class LA25MicroAtom : public LA25Atom {
+public:
+ LA25MicroAtom(const Atom *a, const File &f) : LA25Atom(f) {
+ // Setup reference to fixup the microMIPS LA25 stub entry.
+ addReferenceELF_Mips(R_MICROMIPS_HI16, 0, a, 0);
+ addReferenceELF_Mips(R_MICROMIPS_26_S1, 4, a, 0);
+ addReferenceELF_Mips(R_MICROMIPS_LO16, 8, a, 0);
+ }
+
+ CodeModel codeModel() const override { return codeMipsMicro; }
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return llvm::makeArrayRef(micromipsLA25AtomContent);
+ }
+};
+
+class RelocationPassFile : public SimpleFile {
+public:
+ RelocationPassFile(const ELFLinkingContext &ctx)
+ : SimpleFile("RelocationPassFile") {
+ setOrdinal(ctx.getNextOrdinalAndIncrement());
+ }
+
+ llvm::BumpPtrAllocator _alloc;
+};
+
+template <typename ELFT> class RelocationPass : public Pass {
+public:
+ RelocationPass(MipsLinkingContext &ctx);
+
+ void perform(std::unique_ptr<MutableFile> &mf) override;
+
+private:
+ /// \brief Reference to the linking context.
+ const MipsLinkingContext &_ctx;
+
+ /// \brief Owner of all the Atoms created by this pass.
+ RelocationPassFile _file;
+
+ /// \brief Map Atoms and addend to local GOT entries.
+ typedef std::pair<const Atom *, int64_t> LocalGotMapKeyT;
+ llvm::DenseMap<LocalGotMapKeyT, GOTAtom *> _gotLocalMap;
+ llvm::DenseMap<LocalGotMapKeyT, GOTAtom *> _gotLocalPageMap;
+
+ /// \brief Map Atoms to global GOT entries.
+ llvm::DenseMap<const Atom *, GOTAtom *> _gotGlobalMap;
+
+ /// \brief Map Atoms to TLS GOT entries.
+ llvm::DenseMap<const Atom *, GOTAtom *> _gotTLSMap;
+
+ /// \brief Map Atoms to TLS GD GOT entries.
+ llvm::DenseMap<const Atom *, GOTAtom *> _gotTLSGdMap;
+
+ /// \brief GOT entry for the R_xxxMIPS_TLS_LDM relocations.
+ GOTTLSGdAtom<ELFT> *_gotLDMEntry;
+
+ /// \brief the list of local GOT atoms.
+ std::vector<GOTAtom *> _localGotVector;
+
+ /// \brief the list of global GOT atoms.
+ std::vector<GOTAtom *> _globalGotVector;
+
+ /// \brief the list of TLS GOT atoms.
+ std::vector<GOTAtom *> _tlsGotVector;
+
+ /// \brief Map Atoms to their GOTPLT entries.
+ llvm::DenseMap<const Atom *, GOTPLTAtom *> _gotpltMap;
+
+ /// \brief Map Atoms to their PLT entries.
+ llvm::DenseMap<const Atom *, PLTAAtom *> _pltRegMap;
+ llvm::DenseMap<const Atom *, PLTMicroAtom *> _pltMicroMap;
+
+ /// \brief Map Atoms to their Object entries.
+ llvm::DenseMap<const Atom *, ObjectAtom *> _objectMap;
+
+ /// \brief Map Atoms to their LA25 entries.
+ llvm::DenseMap<const Atom *, LA25RegAtom *> _la25RegMap;
+ llvm::DenseMap<const Atom *, LA25MicroAtom *> _la25MicroMap;
+
+ /// \brief Atoms referenced by static relocations.
+ llvm::DenseSet<const Atom *> _hasStaticRelocations;
+
+ /// \brief Atoms require pointers equality.
+ llvm::DenseSet<const Atom *> _requiresPtrEquality;
+
+ /// \brief References which are candidates for converting
+ /// to the R_MIPS_REL32 relocation.
+ std::vector<Reference *> _rel32Candidates;
+
+ /// \brief the list of PLT atoms.
+ std::vector<PLTAtom *> _pltRegVector;
+ std::vector<PLTAtom *> _pltMicroVector;
+
+ /// \brief the list of GOTPLT atoms.
+ std::vector<GOTPLTAtom *> _gotpltVector;
+
+ /// \brief the list of Object entries.
+ std::vector<ObjectAtom *> _objectVector;
+
+ /// \brief the list of LA25 entries.
+ std::vector<LA25Atom *> _la25Vector;
+
+ /// \brief Handle a specific reference.
+ void handleReference(const MipsELFDefinedAtom<ELFT> &atom, Reference &ref);
+
+ /// \brief Collect information about the reference to use it
+ /// later in the handleReference() routine.
+ void collectReferenceInfo(const MipsELFDefinedAtom<ELFT> &atom,
+ Reference &ref);
+
+ void handlePlain(const MipsELFDefinedAtom<ELFT> &atom, Reference &ref);
+ void handle26(const MipsELFDefinedAtom<ELFT> &atom, Reference &ref);
+ void handleGOT(Reference &ref);
+
+ const GOTAtom *getLocalGOTEntry(const Reference &ref);
+ const GOTAtom *getLocalGOTPageEntry(const Reference &ref);
+ const GOTAtom *getGlobalGOTEntry(const Atom *a);
+ const GOTAtom *getTLSGOTEntry(const Atom *a);
+ const GOTAtom *getTLSGdGOTEntry(const Atom *a);
+ const GOTAtom *getTLSLdmGOTEntry(const Atom *a);
+ const GOTPLTAtom *getGOTPLTEntry(const Atom *a);
+ const PLTAtom *getPLTEntry(const Atom *a);
+ const PLTAtom *getPLTRegEntry(const Atom *a);
+ const PLTAtom *getPLTMicroEntry(const Atom *a);
+ const LA25Atom *getLA25Entry(const Atom *target, bool isMicroMips);
+ const LA25Atom *getLA25RegEntry(const Atom *a);
+ const LA25Atom *getLA25MicroEntry(const Atom *a);
+ const ObjectAtom *getObjectEntry(const SharedLibraryAtom *a);
+
+ PLTAtom *createPLTHeader(bool isMicroMips);
+
+ bool isLocal(const Atom *a) const;
+ bool isLocalCall(const Atom *a) const;
+ bool isDynamic(const Atom *atom) const;
+ bool requireLA25Stub(const Atom *a) const;
+ bool requirePLTEntry(const Atom *a) const;
+ bool requireCopy(const Atom *a) const;
+ bool mightBeDynamic(const MipsELFDefinedAtom<ELFT> &atom,
+ Reference::KindValue refKind) const;
+ bool hasPLTEntry(const Atom *atom) const;
+
+ bool isR6Target() const;
+};
+
+template <typename ELFT>
+RelocationPass<ELFT>::RelocationPass(MipsLinkingContext &ctx)
+ : _ctx(ctx), _file(ctx), _gotLDMEntry(nullptr) {
+ _localGotVector.push_back(new (_file._alloc) GOT0Atom<ELFT>(_file));
+ _localGotVector.push_back(new (_file._alloc)
+ GOTModulePointerAtom<ELFT>(_file));
+}
+
+template <typename ELFT>
+void RelocationPass<ELFT>::perform(std::unique_ptr<MutableFile> &mf) {
+ for (const auto &atom : mf->defined())
+ for (const auto &ref : *atom)
+ collectReferenceInfo(*cast<MipsELFDefinedAtom<ELFT>>(atom),
+ const_cast<Reference &>(*ref));
+
+ // Process all references.
+ for (const auto &atom : mf->defined())
+ for (const auto &ref : *atom)
+ handleReference(*cast<MipsELFDefinedAtom<ELFT>>(atom),
+ const_cast<Reference &>(*ref));
+
+ // Create R_MIPS_REL32 relocations.
+ for (auto *ref : _rel32Candidates) {
+ if (!isDynamic(ref->target()) || hasPLTEntry(ref->target()))
+ continue;
+ ref->setKindValue(R_MIPS_REL32);
+ if (ELFT::Is64Bits)
+ static_cast<MipsELFReference<ELFT> *>(ref)->setTag(R_MIPS_64);
+ if (!isLocalCall(ref->target()))
+ getGlobalGOTEntry(ref->target());
+ }
+
+ uint64_t ordinal = 0;
+
+ for (auto &got : _localGotVector) {
+ got->setOrdinal(ordinal++);
+ mf->addAtom(*got);
+ }
+
+ for (auto &got : _globalGotVector) {
+ got->setOrdinal(ordinal++);
+ mf->addAtom(*got);
+ }
+
+ for (auto &got : _tlsGotVector) {
+ got->setOrdinal(ordinal++);
+ mf->addAtom(*got);
+ }
+
+ // Create and emit PLT0 entry.
+ PLTAtom *plt0Atom = nullptr;
+ if (!_pltRegVector.empty())
+ plt0Atom = createPLTHeader(false);
+ else if (!_pltMicroVector.empty())
+ plt0Atom = createPLTHeader(true);
+
+ if (plt0Atom) {
+ plt0Atom->setOrdinal(ordinal++);
+ mf->addAtom(*plt0Atom);
+ }
+
+ // Emit regular PLT entries firts.
+ for (auto &plt : _pltRegVector) {
+ plt->setOrdinal(ordinal++);
+ mf->addAtom(*plt);
+ }
+
+ // microMIPS PLT entries come after regular ones.
+ for (auto &plt : _pltMicroVector) {
+ plt->setOrdinal(ordinal++);
+ mf->addAtom(*plt);
+ }
+
+ // Assign PLT0 to GOTPLT entries.
+ assert(_gotpltMap.empty() || plt0Atom);
+ for (auto &a: _gotpltMap)
+ a.second->setPLT0(plt0Atom);
+
+ for (auto &gotplt : _gotpltVector) {
+ gotplt->setOrdinal(ordinal++);
+ mf->addAtom(*gotplt);
+ }
+
+ for (auto obj : _objectVector) {
+ obj->setOrdinal(ordinal++);
+ mf->addAtom(*obj);
+ }
+
+ for (auto la25 : _la25Vector) {
+ la25->setOrdinal(ordinal++);
+ mf->addAtom(*la25);
+ }
+}
+
+template <typename ELFT>
+void RelocationPass<ELFT>::handleReference(const MipsELFDefinedAtom<ELFT> &atom,
+ Reference &ref) {
+ if (!ref.target())
+ return;
+ if (ref.kindNamespace() != lld::Reference::KindNamespace::ELF)
+ return;
+ assert(ref.kindArch() == Reference::KindArch::Mips);
+ switch (ref.kindValue()) {
+ case R_MIPS_32:
+ case R_MIPS_PC32:
+ case R_MIPS_HI16:
+ case R_MIPS_LO16:
+ case R_MIPS_PCHI16:
+ case R_MIPS_PCLO16:
+ case R_MICROMIPS_HI16:
+ case R_MICROMIPS_LO16:
+ // FIXME (simon): Handle dynamic/static linking differently.
+ handlePlain(atom, ref);
+ break;
+ case R_MIPS_26:
+ case R_MICROMIPS_26_S1:
+ handle26(atom, ref);
+ break;
+ case R_MIPS_GOT16:
+ case R_MIPS_CALL16:
+ case R_MICROMIPS_GOT16:
+ case R_MICROMIPS_CALL16:
+ case R_MIPS_GOT_DISP:
+ case R_MIPS_GOT_PAGE:
+ handleGOT(ref);
+ break;
+ case R_MIPS_GOT_OFST:
+ // Nothing to do. We create GOT page entry in the R_MIPS_GOT_PAGE handler.
+ break;
+ case R_MIPS_GPREL16:
+ if (isLocal(ref.target()))
+ ref.setAddend(ref.addend() + atom.file().getGP0());
+ break;
+ case R_MIPS_GPREL32:
+ ref.setAddend(ref.addend() + atom.file().getGP0());
+ break;
+ case R_MIPS_TLS_DTPREL_HI16:
+ case R_MIPS_TLS_DTPREL_LO16:
+ case R_MICROMIPS_TLS_DTPREL_HI16:
+ case R_MICROMIPS_TLS_DTPREL_LO16:
+ ref.setAddend(ref.addend() - atom.file().getDTPOffset());
+ break;
+ case R_MIPS_TLS_TPREL_HI16:
+ case R_MIPS_TLS_TPREL_LO16:
+ case R_MICROMIPS_TLS_TPREL_HI16:
+ case R_MICROMIPS_TLS_TPREL_LO16:
+ ref.setAddend(ref.addend() - atom.file().getTPOffset());
+ break;
+ case R_MIPS_TLS_GD:
+ case R_MICROMIPS_TLS_GD:
+ ref.setTarget(getTLSGdGOTEntry(ref.target()));
+ break;
+ case R_MIPS_TLS_LDM:
+ case R_MICROMIPS_TLS_LDM:
+ ref.setTarget(getTLSLdmGOTEntry(ref.target()));
+ break;
+ case R_MIPS_TLS_GOTTPREL:
+ case R_MICROMIPS_TLS_GOTTPREL:
+ ref.setTarget(getTLSGOTEntry(ref.target()));
+ break;
+ }
+}
+
+template <typename ELFT>
+static bool isConstrainSym(const MipsELFDefinedAtom<ELFT> &atom,
+ Reference::KindValue refKind) {
+ if ((atom.section()->sh_flags & SHF_ALLOC) == 0)
+ return false;
+ switch (refKind) {
+ case R_MIPS_NONE:
+ case R_MIPS_JALR:
+ case R_MICROMIPS_JALR:
+ case R_MIPS_GPREL16:
+ case R_MIPS_GPREL32:
+ return false;
+ default:
+ return true;
+ }
+}
+
+template <typename ELFT>
+void RelocationPass<ELFT>::collectReferenceInfo(
+ const MipsELFDefinedAtom<ELFT> &atom, Reference &ref) {
+ if (!ref.target())
+ return;
+ if (ref.kindNamespace() != lld::Reference::KindNamespace::ELF)
+ return;
+
+ auto refKind = ref.kindValue();
+ if (!isConstrainSym(atom, refKind))
+ return;
+
+ if (mightBeDynamic(atom, refKind))
+ _rel32Candidates.push_back(&ref);
+ else
+ _hasStaticRelocations.insert(ref.target());
+
+ if (refKind != R_MIPS_CALL16 && refKind != R_MICROMIPS_CALL16 &&
+ refKind != R_MIPS_26 && refKind != R_MICROMIPS_26_S1)
+ _requiresPtrEquality.insert(ref.target());
+}
+
+template <typename ELFT>
+bool RelocationPass<ELFT>::isLocal(const Atom *a) const {
+ if (auto *da = dyn_cast<DefinedAtom>(a))
+ return da->scope() == Atom::scopeTranslationUnit;
+ return false;
+}
+
+template <typename ELFT>
+static bool isMipsReadonly(const MipsELFDefinedAtom<ELFT> &atom) {
+ auto secFlags = atom.section()->sh_flags;
+ auto secType = atom.section()->sh_type;
+
+ if ((secFlags & SHF_ALLOC) == 0)
+ return false;
+ if (secType == SHT_NOBITS)
+ return false;
+ if ((secFlags & SHF_WRITE) != 0)
+ return false;
+ return true;
+}
+
+template <typename ELFT>
+bool RelocationPass<ELFT>::mightBeDynamic(const MipsELFDefinedAtom<ELFT> &atom,
+ Reference::KindValue refKind) const {
+ if (refKind == R_MIPS_CALL16 || refKind == R_MIPS_GOT16 ||
+ refKind == R_MICROMIPS_CALL16 || refKind == R_MICROMIPS_GOT16)
+ return true;
+
+ if (refKind != R_MIPS_32 && refKind != R_MIPS_64)
+ return false;
+ if ((atom.section()->sh_flags & SHF_ALLOC) == 0)
+ return false;
+
+ if (_ctx.getOutputELFType() == ET_DYN)
+ return true;
+ if (!isMipsReadonly(atom))
+ return true;
+ if (atom.file().isPIC())
+ return true;
+
+ return false;
+}
+
+template <typename ELFT>
+bool RelocationPass<ELFT>::hasPLTEntry(const Atom *atom) const {
+ return _pltRegMap.count(atom) || _pltMicroMap.count(atom);
+}
+
+template <typename ELFT> bool RelocationPass<ELFT>::isR6Target() const {
+ switch (_ctx.getMergedELFFlags() & EF_MIPS_ARCH) {
+ case EF_MIPS_ARCH_32R6:
+ case EF_MIPS_ARCH_64R6:
+ return true;
+ default:
+ return false;
+ }
+}
+
+template <typename ELFT>
+bool RelocationPass<ELFT>::requirePLTEntry(const Atom *a) const {
+ if (!_hasStaticRelocations.count(a))
+ return false;
+ const auto *sa = dyn_cast<ELFDynamicAtom<ELFT>>(a);
+ if (sa && sa->type() != SharedLibraryAtom::Type::Code)
+ return false;
+ const auto *da = dyn_cast<ELFDefinedAtom<ELFT>>(a);
+ if (da && da->contentType() != DefinedAtom::typeCode)
+ return false;
+ if (isLocalCall(a))
+ return false;
+ return true;
+}
+
+template <typename ELFT>
+bool RelocationPass<ELFT>::requireCopy(const Atom *a) const {
+ if (!_hasStaticRelocations.count(a))
+ return false;
+ const auto *sa = dyn_cast<ELFDynamicAtom<ELFT>>(a);
+ return sa && sa->type() == SharedLibraryAtom::Type::Data;
+}
+
+template <typename ELFT>
+bool RelocationPass<ELFT>::isDynamic(const Atom *atom) const {
+ const auto *da = dyn_cast<const DefinedAtom>(atom);
+ if (da && da->dynamicExport() == DefinedAtom::dynamicExportAlways)
+ return true;
+
+ const auto *sa = dyn_cast<SharedLibraryAtom>(atom);
+ if (sa)
+ return true;
+
+ if (_ctx.getOutputELFType() == ET_DYN) {
+ if (da && da->scope() != DefinedAtom::scopeTranslationUnit)
+ return true;
+
+ const auto *ua = dyn_cast<UndefinedAtom>(atom);
+ if (ua)
+ return true;
+ }
+
+ return false;
+}
+
+template <typename ELFT>
+static bool isMicroMips(const MipsELFDefinedAtom<ELFT> &atom) {
+ return atom.codeModel() == DefinedAtom::codeMipsMicro ||
+ atom.codeModel() == DefinedAtom::codeMipsMicroPIC;
+}
+
+template <typename ELFT>
+const LA25Atom *RelocationPass<ELFT>::getLA25Entry(const Atom *target,
+ bool isMicroMips) {
+ return isMicroMips ? getLA25MicroEntry(target) : getLA25RegEntry(target);
+}
+
+template <typename ELFT>
+const PLTAtom *RelocationPass<ELFT>::getPLTEntry(const Atom *a) {
+ bool hasMicroCode = _ctx.getMergedELFFlags() & EF_MIPS_MICROMIPS;
+
+ // If file contains microMIPS code try to reuse compressed PLT entry...
+ if (hasMicroCode) {
+ auto microPLT = _pltMicroMap.find(a);
+ if (microPLT != _pltMicroMap.end())
+ return microPLT->second;
+ }
+
+ // ... then try to reuse a regular PLT entry ...
+ auto regPLT = _pltRegMap.find(a);
+ if (regPLT != _pltRegMap.end())
+ return regPLT->second;
+
+ // ... and finally prefer to create new compressed PLT entry.
+ return hasMicroCode ? getPLTMicroEntry(a) : getPLTRegEntry(a);
+}
+
+template <typename ELFT>
+void RelocationPass<ELFT>::handlePlain(const MipsELFDefinedAtom<ELFT> &atom,
+ Reference &ref) {
+ if (!isDynamic(ref.target()))
+ return;
+
+ if (requirePLTEntry(ref.target()))
+ ref.setTarget(getPLTEntry(ref.target()));
+ else if (requireCopy(ref.target()))
+ ref.setTarget(getObjectEntry(cast<SharedLibraryAtom>(ref.target())));
+}
+
+template <typename ELFT>
+void RelocationPass<ELFT>::handle26(const MipsELFDefinedAtom<ELFT> &atom,
+ Reference &ref) {
+ bool isMicro = ref.kindValue() == R_MICROMIPS_26_S1;
+ assert((isMicro || ref.kindValue() == R_MIPS_26) && "Unexpected relocation");
+
+ const auto *sla = dyn_cast<SharedLibraryAtom>(ref.target());
+ if (sla && sla->type() == SharedLibraryAtom::Type::Code)
+ ref.setTarget(isMicro ? getPLTMicroEntry(sla) : getPLTRegEntry(sla));
+
+ if (requireLA25Stub(ref.target()))
+ ref.setTarget(getLA25Entry(ref.target(), isMicro));
+
+ if (!isLocal(ref.target())) {
+ if (isMicro)
+ ref.setKindValue(LLD_R_MICROMIPS_GLOBAL_26_S1);
+ else
+ ref.setKindValue(LLD_R_MIPS_GLOBAL_26);
+ }
+}
+
+template <typename ELFT> void RelocationPass<ELFT>::handleGOT(Reference &ref) {
+ if (!isLocalCall(ref.target())) {
+ ref.setTarget(getGlobalGOTEntry(ref.target()));
+ return;
+ }
+
+ if (ref.kindValue() == R_MIPS_GOT_PAGE)
+ ref.setTarget(getLocalGOTPageEntry(ref));
+ else if (ref.kindValue() == R_MIPS_GOT_DISP)
+ ref.setTarget(getLocalGOTEntry(ref));
+ else if (isLocal(ref.target()))
+ ref.setTarget(getLocalGOTPageEntry(ref));
+ else
+ ref.setTarget(getLocalGOTEntry(ref));
+}
+
+template <typename ELFT>
+bool RelocationPass<ELFT>::isLocalCall(const Atom *a) const {
+ Atom::Scope scope;
+ if (auto *da = dyn_cast<DefinedAtom>(a))
+ scope = da->scope();
+ else if (auto *aa = dyn_cast<AbsoluteAtom>(a))
+ scope = aa->scope();
+ else
+ return false;
+
+ // Local and hidden symbols must be local.
+ if (scope == Atom::scopeTranslationUnit || scope == Atom::scopeLinkageUnit)
+ return true;
+
+ // Calls to external symbols defined in an executable file resolved locally.
+ if (_ctx.getOutputELFType() == ET_EXEC)
+ return true;
+
+ return false;
+}
+
+template <typename ELFT>
+bool RelocationPass<ELFT>::requireLA25Stub(const Atom *a) const {
+ if (isLocal(a))
+ return false;
+ if (auto *da = dyn_cast<DefinedAtom>(a))
+ return static_cast<const MipsELFDefinedAtom<ELFT> *>(da)->file().isPIC();
+ return false;
+}
+
+template <typename ELFT>
+const GOTAtom *RelocationPass<ELFT>::getLocalGOTEntry(const Reference &ref) {
+ const Atom *a = ref.target();
+ LocalGotMapKeyT key(a, ref.addend());
+
+ auto got = _gotLocalMap.find(key);
+ if (got != _gotLocalMap.end())
+ return got->second;
+
+ auto ga = new (_file._alloc) GOT0Atom<ELFT>(_file);
+ _gotLocalMap[key] = ga;
+
+ _localGotVector.push_back(ga);
+
+ Reference::KindValue relKind = ELFT::Is64Bits ? R_MIPS_64 : R_MIPS_32;
+ ga->addReferenceELF_Mips(relKind, 0, a, 0);
+
+ return ga;
+}
+
+template <typename ELFT>
+const GOTAtom *
+RelocationPass<ELFT>::getLocalGOTPageEntry(const Reference &ref) {
+ const Atom *a = ref.target();
+ LocalGotMapKeyT key(a, ref.addend());
+
+ auto got = _gotLocalPageMap.find(key);
+ if (got != _gotLocalPageMap.end())
+ return got->second;
+
+ auto ga = new (_file._alloc) GOT0Atom<ELFT>(_file);
+ _gotLocalPageMap[key] = ga;
+
+ _localGotVector.push_back(ga);
+
+ Reference::KindValue relKind =
+ ELFT::Is64Bits ? LLD_R_MIPS_64_HI16 : LLD_R_MIPS_32_HI16;
+ ga->addReferenceELF_Mips(relKind, 0, a, ref.addend());
+
+ return ga;
+}
+
+template <typename ELFT>
+const GOTAtom *RelocationPass<ELFT>::getGlobalGOTEntry(const Atom *a) {
+ auto got = _gotGlobalMap.find(a);
+ if (got != _gotGlobalMap.end())
+ return got->second;
+
+ auto ga = new (_file._alloc) GOT0Atom<ELFT>(_file);
+ _gotGlobalMap[a] = ga;
+
+ _globalGotVector.push_back(ga);
+ ga->addReferenceELF_Mips(LLD_R_MIPS_GLOBAL_GOT, 0, a, 0);
+
+ if (const DefinedAtom *da = dyn_cast<DefinedAtom>(a))
+ ga->addReferenceELF_Mips(R_MIPS_32, 0, da, 0);
+
+ return ga;
+}
+
+template <typename ELFT>
+const GOTAtom *RelocationPass<ELFT>::getTLSGOTEntry(const Atom *a) {
+ auto got = _gotTLSMap.find(a);
+ if (got != _gotTLSMap.end())
+ return got->second;
+
+ auto ga = new (_file._alloc) GOT0Atom<ELFT>(_file);
+ _gotTLSMap[a] = ga;
+
+ _tlsGotVector.push_back(ga);
+ Reference::KindValue relKind =
+ ELFT::Is64Bits ? R_MIPS_TLS_TPREL64 : R_MIPS_TLS_TPREL32;
+ ga->addReferenceELF_Mips(relKind, 0, a, 0);
+
+ return ga;
+}
+
+template <typename ELFT>
+const GOTAtom *RelocationPass<ELFT>::getTLSGdGOTEntry(const Atom *a) {
+ auto got = _gotTLSGdMap.find(a);
+ if (got != _gotTLSGdMap.end())
+ return got->second;
+
+ auto ga = new (_file._alloc) GOTTLSGdAtom<ELFT>(_file);
+ _gotTLSGdMap[a] = ga;
+
+ _tlsGotVector.push_back(ga);
+ if (ELFT::Is64Bits) {
+ ga->addReferenceELF_Mips(R_MIPS_TLS_DTPMOD64, 0, a, 0);
+ ga->addReferenceELF_Mips(R_MIPS_TLS_DTPREL64, 8, a, 0);
+ } else {
+ ga->addReferenceELF_Mips(R_MIPS_TLS_DTPMOD32, 0, a, 0);
+ ga->addReferenceELF_Mips(R_MIPS_TLS_DTPREL32, 4, a, 0);
+ }
+
+ return ga;
+}
+
+template <typename ELFT>
+const GOTAtom *RelocationPass<ELFT>::getTLSLdmGOTEntry(const Atom *a) {
+ if (_gotLDMEntry)
+ return _gotLDMEntry;
+
+ _gotLDMEntry = new (_file._alloc) GOTTLSGdAtom<ELFT>(_file);
+ _tlsGotVector.push_back(_gotLDMEntry);
+ if (ELFT::Is64Bits)
+ _gotLDMEntry->addReferenceELF_Mips(R_MIPS_TLS_DTPMOD64, 0, _gotLDMEntry, 0);
+ else
+ _gotLDMEntry->addReferenceELF_Mips(R_MIPS_TLS_DTPMOD32, 0, _gotLDMEntry, 0);
+
+ return _gotLDMEntry;
+}
+
+template <typename ELFT>
+PLTAtom *RelocationPass<ELFT>::createPLTHeader(bool isMicroMips) {
+ auto ga1 = new (_file._alloc) GOTPLTAtom(_file);
+ _gotpltVector.insert(_gotpltVector.begin(), ga1);
+ auto ga0 = new (_file._alloc) GOTPLTAtom(_file);
+ _gotpltVector.insert(_gotpltVector.begin(), ga0);
+
+ if (isMicroMips)
+ return new (_file._alloc) PLT0MicroAtom(ga0, _file);
+ else
+ return new (_file._alloc) PLT0Atom(ga0, _file);
+}
+
+template <typename ELFT>
+const GOTPLTAtom *RelocationPass<ELFT>::getGOTPLTEntry(const Atom *a) {
+ auto it = _gotpltMap.find(a);
+ if (it != _gotpltMap.end())
+ return it->second;
+
+ auto ga = new (_file._alloc) GOTPLTAtom(a, _file);
+ _gotpltMap[a] = ga;
+ _gotpltVector.push_back(ga);
+ return ga;
+}
+
+template <typename ELFT>
+const PLTAtom *RelocationPass<ELFT>::getPLTRegEntry(const Atom *a) {
+ auto plt = _pltRegMap.find(a);
+ if (plt != _pltRegMap.end())
+ return plt->second;
+
+ PLTAAtom *pa = isR6Target()
+ ? new (_file._alloc) PLTR6Atom(getGOTPLTEntry(a), _file)
+ : new (_file._alloc) PLTAAtom(getGOTPLTEntry(a), _file);
+ _pltRegMap[a] = pa;
+ _pltRegVector.push_back(pa);
+
+ // Check that 'a' dynamic symbol table record should point to the PLT.
+ if (_hasStaticRelocations.count(a) && _requiresPtrEquality.count(a))
+ pa->addReferenceELF_Mips(LLD_R_MIPS_STO_PLT, 0, a, 0);
+
+ return pa;
+}
+
+template <typename ELFT>
+const PLTAtom *RelocationPass<ELFT>::getPLTMicroEntry(const Atom *a) {
+ auto plt = _pltMicroMap.find(a);
+ if (plt != _pltMicroMap.end())
+ return plt->second;
+
+ auto pa = new (_file._alloc) PLTMicroAtom(getGOTPLTEntry(a), _file);
+ _pltMicroMap[a] = pa;
+ _pltMicroVector.push_back(pa);
+
+ // Check that 'a' dynamic symbol table record should point to the PLT.
+ if (_hasStaticRelocations.count(a) && _requiresPtrEquality.count(a))
+ pa->addReferenceELF_Mips(LLD_R_MIPS_STO_PLT, 0, a, 0);
+
+ return pa;
+}
+
+template <typename ELFT>
+const LA25Atom *RelocationPass<ELFT>::getLA25RegEntry(const Atom *a) {
+ auto la25 = _la25RegMap.find(a);
+ if (la25 != _la25RegMap.end())
+ return la25->second;
+
+ auto sa = new (_file._alloc) LA25RegAtom(a, _file);
+ _la25RegMap[a] = sa;
+ _la25Vector.push_back(sa);
+
+ return sa;
+}
+
+template <typename ELFT>
+const LA25Atom *RelocationPass<ELFT>::getLA25MicroEntry(const Atom *a) {
+ auto la25 = _la25MicroMap.find(a);
+ if (la25 != _la25MicroMap.end())
+ return la25->second;
+
+ auto sa = new (_file._alloc) LA25MicroAtom(a, _file);
+ _la25MicroMap[a] = sa;
+ _la25Vector.push_back(sa);
+
+ return sa;
+}
+
+template <typename ELFT>
+const ObjectAtom *
+RelocationPass<ELFT>::getObjectEntry(const SharedLibraryAtom *a) {
+ auto obj = _objectMap.find(a);
+ if (obj != _objectMap.end())
+ return obj->second;
+
+ auto oa = new (_file._alloc) ObjectAtom(_file);
+ oa->addReferenceELF_Mips(R_MIPS_COPY, 0, oa, 0);
+ oa->_name = a->name();
+ oa->_size = a->size();
+
+ _objectMap[a] = oa;
+ _objectVector.push_back(oa);
+
+ return oa;
+}
+
+} // end anon namespace
+
+static std::unique_ptr<Pass> createPass(MipsLinkingContext &ctx) {
+ switch (ctx.getTriple().getArch()) {
+ case llvm::Triple::mipsel:
+ return llvm::make_unique<RelocationPass<Mips32ELType>>(ctx);
+ case llvm::Triple::mips64el:
+ return llvm::make_unique<RelocationPass<Mips64ELType>>(ctx);
+ default:
+ llvm_unreachable("Unhandled arch");
+ }
+}
+
+std::unique_ptr<Pass>
+lld::elf::createMipsRelocationPass(MipsLinkingContext &ctx) {
+ switch (ctx.getOutputELFType()) {
+ case ET_EXEC:
+ case ET_DYN:
+ return createPass(ctx);
+ case ET_REL:
+ return nullptr;
+ default:
+ llvm_unreachable("Unhandled output file type");
+ }
+}
diff --git a/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.h b/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.h
new file mode 100644
index 0000000000000..af343de5f0276
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.h
@@ -0,0 +1,25 @@
+//===- lib/ReaderWriter/ELF/Mips/MipsRelocationPass.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_MIPS_MIPS_RELOCATION_PASS_H
+#define LLD_READER_WRITER_ELF_MIPS_MIPS_RELOCATION_PASS_H
+
+#include <memory>
+
+namespace lld {
+class Pass;
+
+namespace elf {
+class MipsLinkingContext;
+
+std::unique_ptr<Pass> createMipsRelocationPass(MipsLinkingContext &ctx);
+
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h b/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h
new file mode 100644
index 0000000000000..de9390f2b3074
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h
@@ -0,0 +1,170 @@
+//===- lib/ReaderWriter/ELF/Mips/MipsSectionChunks.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_MIPS_MIPS_SECTION_CHUNKS_H
+#define LLD_READER_WRITER_ELF_MIPS_MIPS_SECTION_CHUNKS_H
+
+namespace lld {
+namespace elf {
+
+template <typename ELFT> class MipsTargetLayout;
+class MipsLinkingContext;
+
+/// \brief Handle Mips GOT section
+template <class ELFType> class MipsGOTSection : public AtomSection<ELFType> {
+public:
+ MipsGOTSection(const MipsLinkingContext &ctx)
+ : AtomSection<ELFType>(ctx, ".got", DefinedAtom::typeGOT,
+ DefinedAtom::permRW_,
+ MipsTargetLayout<ELFType>::ORDER_GOT),
+ _hasNonLocal(false), _localCount(0) {
+ this->_flags |= SHF_MIPS_GPREL;
+ this->_alignment = 4;
+ }
+
+ /// \brief Number of local GOT entries.
+ std::size_t getLocalCount() const { return _localCount; }
+
+ /// \brief Number of global GOT entries.
+ std::size_t getGlobalCount() const { return _posMap.size(); }
+
+ /// \brief Does the atom have a global GOT entry?
+ bool hasGlobalGOTEntry(const Atom *a) const {
+ return _posMap.count(a) || _tlsMap.count(a);
+ }
+
+ /// \brief Compare two atoms accordingly theirs positions in the GOT.
+ bool compare(const Atom *a, const Atom *b) const {
+ auto ia = _posMap.find(a);
+ auto ib = _posMap.find(b);
+
+ if (ia != _posMap.end() && ib != _posMap.end())
+ return ia->second < ib->second;
+
+ return ia == _posMap.end() && ib != _posMap.end();
+ }
+
+ const lld::AtomLayout *appendAtom(const Atom *atom) override {
+ const DefinedAtom *da = dyn_cast<DefinedAtom>(atom);
+
+ for (const auto &r : *da) {
+ if (r->kindNamespace() != lld::Reference::KindNamespace::ELF)
+ continue;
+ assert(r->kindArch() == Reference::KindArch::Mips);
+ switch (r->kindValue()) {
+ case LLD_R_MIPS_GLOBAL_GOT:
+ _hasNonLocal = true;
+ _posMap[r->target()] = _posMap.size();
+ return AtomSection<ELFType>::appendAtom(atom);
+ case R_MIPS_TLS_TPREL32:
+ case R_MIPS_TLS_DTPREL32:
+ case R_MIPS_TLS_TPREL64:
+ case R_MIPS_TLS_DTPREL64:
+ _hasNonLocal = true;
+ _tlsMap[r->target()] = _tlsMap.size();
+ return AtomSection<ELFType>::appendAtom(atom);
+ case R_MIPS_TLS_DTPMOD32:
+ case R_MIPS_TLS_DTPMOD64:
+ _hasNonLocal = true;
+ break;
+ }
+ }
+
+ if (!_hasNonLocal)
+ ++_localCount;
+
+ return AtomSection<ELFType>::appendAtom(atom);
+ }
+
+private:
+ /// \brief True if the GOT contains non-local entries.
+ bool _hasNonLocal;
+
+ /// \brief Number of local GOT entries.
+ std::size_t _localCount;
+
+ /// \brief Map TLS Atoms to their GOT entry index.
+ llvm::DenseMap<const Atom *, std::size_t> _tlsMap;
+
+ /// \brief Map Atoms to their GOT entry index.
+ llvm::DenseMap<const Atom *, std::size_t> _posMap;
+};
+
+/// \brief Handle Mips PLT section
+template <class ELFType> class MipsPLTSection : public AtomSection<ELFType> {
+public:
+ MipsPLTSection(const MipsLinkingContext &ctx)
+ : AtomSection<ELFType>(ctx, ".plt", DefinedAtom::typeGOT,
+ DefinedAtom::permR_X,
+ MipsTargetLayout<ELFType>::ORDER_PLT) {}
+
+ const AtomLayout *findPLTLayout(const Atom *plt) const {
+ auto it = _pltLayoutMap.find(plt);
+ return it != _pltLayoutMap.end() ? it->second : nullptr;
+ }
+
+ const lld::AtomLayout *appendAtom(const Atom *atom) override {
+ const auto *layout = AtomSection<ELFType>::appendAtom(atom);
+
+ const DefinedAtom *da = cast<DefinedAtom>(atom);
+
+ for (const auto &r : *da) {
+ if (r->kindNamespace() != lld::Reference::KindNamespace::ELF)
+ continue;
+ assert(r->kindArch() == Reference::KindArch::Mips);
+ if (r->kindValue() == LLD_R_MIPS_STO_PLT) {
+ _pltLayoutMap[r->target()] = layout;
+ break;
+ }
+ }
+
+ return layout;
+ }
+
+private:
+ /// \brief Map PLT Atoms to their layouts.
+ std::unordered_map<const Atom *, const AtomLayout *> _pltLayoutMap;
+};
+
+template <class ELFT> class MipsRelocationTable : public RelocationTable<ELFT> {
+ typedef llvm::object::Elf_Rel_Impl<ELFT, false> Elf_Rel;
+ typedef llvm::object::Elf_Rel_Impl<ELFT, true> Elf_Rela;
+
+ static const bool _isMips64EL =
+ ELFT::Is64Bits && ELFT::TargetEndianness == llvm::support::little;
+
+public:
+ MipsRelocationTable(const ELFLinkingContext &context, StringRef str,
+ int32_t order)
+ : RelocationTable<ELFT>(context, str, order) {}
+
+protected:
+ void writeRela(ELFWriter *writer, Elf_Rela &r, const DefinedAtom &atom,
+ const Reference &ref) override {
+ uint32_t rType = ref.kindValue() | (ref.tag() << 8);
+ r.setSymbolAndType(this->getSymbolIndex(ref.target()), rType, _isMips64EL);
+ r.r_offset = writer->addressOfAtom(&atom) + ref.offsetInAtom();
+ // The addend is used only by relative relocations
+ if (this->_context.isRelativeReloc(ref))
+ r.r_addend = writer->addressOfAtom(ref.target()) + ref.addend();
+ else
+ r.r_addend = 0;
+ }
+
+ void writeRel(ELFWriter *writer, Elf_Rel &r, const DefinedAtom &atom,
+ const Reference &ref) override {
+ uint32_t rType = ref.kindValue() | (ref.tag() << 8);
+ r.setSymbolAndType(this->getSymbolIndex(ref.target()), rType, _isMips64EL);
+ r.r_offset = writer->addressOfAtom(&atom) + ref.offsetInAtom();
+ }
+};
+
+} // elf
+} // lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp b/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp
new file mode 100644
index 0000000000000..f60ab63c6af7f
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp
@@ -0,0 +1,35 @@
+//===- lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp --------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MipsTargetHandler.h"
+
+using namespace lld;
+using namespace elf;
+
+void MipsRelocationStringTable::registerTable(Registry &registry) {
+ registry.addKindTable(Reference::KindNamespace::ELF,
+ Reference::KindArch::Mips, kindStrings);
+}
+
+#define ELF_RELOC(name, value) LLD_KIND_STRING_ENTRY(name),
+
+const Registry::KindStrings MipsRelocationStringTable::kindStrings[] = {
+#include "llvm/Support/ELFRelocs/Mips.def"
+ LLD_KIND_STRING_ENTRY(LLD_R_MIPS_GLOBAL_GOT),
+ LLD_KIND_STRING_ENTRY(LLD_R_MIPS_32_HI16),
+ LLD_KIND_STRING_ENTRY(LLD_R_MIPS_64_HI16),
+ LLD_KIND_STRING_ENTRY(LLD_R_MIPS_GLOBAL_26),
+ LLD_KIND_STRING_ENTRY(LLD_R_MIPS_HI16),
+ LLD_KIND_STRING_ENTRY(LLD_R_MIPS_LO16),
+ LLD_KIND_STRING_ENTRY(LLD_R_MIPS_STO_PLT),
+ LLD_KIND_STRING_ENTRY(LLD_R_MICROMIPS_GLOBAL_26_S1),
+ LLD_KIND_STRING_END
+};
+
+#undef ELF_RELOC
diff --git a/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h b/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h
new file mode 100644
index 0000000000000..79509addf40b4
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h
@@ -0,0 +1,257 @@
+//===- lib/ReaderWriter/ELF/Mips/MipsTargetHandler.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_MIPS_MIPS_TARGET_HANDLER_H
+#define LLD_READER_WRITER_ELF_MIPS_MIPS_TARGET_HANDLER_H
+
+#include "DefaultTargetHandler.h"
+#include "MipsDynamicLibraryWriter.h"
+#include "MipsELFReader.h"
+#include "MipsExecutableWriter.h"
+#include "MipsLinkingContext.h"
+#include "MipsRelocationHandler.h"
+#include "MipsSectionChunks.h"
+#include "TargetLayout.h"
+#include "llvm/ADT/DenseSet.h"
+
+namespace lld {
+namespace elf {
+
+/// \brief TargetLayout for Mips
+template <class ELFT> class MipsTargetLayout final : public TargetLayout<ELFT> {
+public:
+ MipsTargetLayout(MipsLinkingContext &ctx)
+ : TargetLayout<ELFT>(ctx),
+ _gotSection(new (this->_allocator) MipsGOTSection<ELFT>(ctx)),
+ _pltSection(new (this->_allocator) MipsPLTSection<ELFT>(ctx)) {}
+
+ const MipsGOTSection<ELFT> &getGOTSection() const { return *_gotSection; }
+ const MipsPLTSection<ELFT> &getPLTSection() const { return *_pltSection; }
+
+ AtomSection<ELFT> *createSection(StringRef name, int32_t type,
+ DefinedAtom::ContentPermissions permissions,
+ Layout::SectionOrder order) override {
+ if (type == DefinedAtom::typeGOT && name == ".got")
+ return _gotSection;
+ if (type == DefinedAtom::typeStub && name == ".plt")
+ return _pltSection;
+ return DefaultLayout<ELFT>::createSection(name, type, permissions, order);
+ }
+
+ /// \brief GP offset relative to .got section.
+ uint64_t getGPOffset() const { return 0x7FF0; }
+
+ /// \brief Get '_gp' symbol atom layout.
+ AtomLayout *getGP() {
+ if (!_gpAtom.hasValue()) {
+ auto atom = this->findAbsoluteAtom("_gp");
+ _gpAtom = atom != this->absoluteAtoms().end() ? *atom : nullptr;
+ }
+ return *_gpAtom;
+ }
+
+ /// \brief Get '_gp_disp' symbol atom layout.
+ AtomLayout *getGPDisp() {
+ if (!_gpDispAtom.hasValue()) {
+ auto atom = this->findAbsoluteAtom("_gp_disp");
+ _gpDispAtom = atom != this->absoluteAtoms().end() ? *atom : nullptr;
+ }
+ return *_gpDispAtom;
+ }
+
+ /// \brief Return the section order for a input section
+ Layout::SectionOrder getSectionOrder(StringRef name, int32_t contentType,
+ int32_t contentPermissions) override {
+ if ((contentType == DefinedAtom::typeStub) && (name.startswith(".text")))
+ return DefaultLayout<ELFT>::ORDER_TEXT;
+
+ return DefaultLayout<ELFT>::getSectionOrder(name, contentType,
+ contentPermissions);
+ }
+
+protected:
+ unique_bump_ptr<RelocationTable<ELFT>>
+ createRelocationTable(StringRef name, int32_t order) override {
+ return unique_bump_ptr<RelocationTable<ELFT>>(
+ new (this->_allocator)
+ MipsRelocationTable<ELFT>(this->_context, name, order));
+ }
+
+private:
+ MipsGOTSection<ELFT> *_gotSection;
+ MipsPLTSection<ELFT> *_pltSection;
+ llvm::Optional<AtomLayout *> _gpAtom;
+ llvm::Optional<AtomLayout *> _gpDispAtom;
+};
+
+/// \brief Mips Runtime file.
+template <class ELFT> class MipsRuntimeFile final : public RuntimeFile<ELFT> {
+public:
+ MipsRuntimeFile(MipsLinkingContext &ctx)
+ : RuntimeFile<ELFT>(ctx, "Mips runtime file") {}
+};
+
+/// \brief Auxiliary class holds relocation's names table.
+class MipsRelocationStringTable {
+ static const Registry::KindStrings kindStrings[];
+
+public:
+ static void registerTable(Registry &registry);
+};
+
+/// \brief TargetHandler for Mips
+template <class ELFT>
+class MipsTargetHandler final : public DefaultTargetHandler<ELFT> {
+public:
+ MipsTargetHandler(MipsLinkingContext &ctx)
+ : _ctx(ctx), _runtimeFile(new MipsRuntimeFile<ELFT>(ctx)),
+ _targetLayout(new MipsTargetLayout<ELFT>(ctx)),
+ _relocationHandler(createMipsRelocationHandler<ELFT>(ctx)) {}
+
+ MipsTargetLayout<ELFT> &getTargetLayout() override { return *_targetLayout; }
+
+ std::unique_ptr<Reader> getObjReader() override {
+ return std::unique_ptr<Reader>(new MipsELFObjectReader<ELFT>(_ctx));
+ }
+
+ std::unique_ptr<Reader> getDSOReader() override {
+ return std::unique_ptr<Reader>(new MipsELFDSOReader<ELFT>(_ctx));
+ }
+
+ const TargetRelocationHandler &getRelocationHandler() const override {
+ return *_relocationHandler;
+ }
+
+ std::unique_ptr<Writer> getWriter() override {
+ switch (_ctx.getOutputELFType()) {
+ case llvm::ELF::ET_EXEC:
+ return std::unique_ptr<Writer>(
+ new MipsExecutableWriter<ELFT>(_ctx, *_targetLayout));
+ case llvm::ELF::ET_DYN:
+ return std::unique_ptr<Writer>(
+ new MipsDynamicLibraryWriter<ELFT>(_ctx, *_targetLayout));
+ case llvm::ELF::ET_REL:
+ llvm_unreachable("TODO: support -r mode");
+ default:
+ llvm_unreachable("unsupported output type");
+ }
+ }
+
+ void registerRelocationNames(Registry &registry) override {
+ MipsRelocationStringTable::registerTable(registry);
+ }
+
+private:
+ MipsLinkingContext &_ctx;
+ std::unique_ptr<MipsRuntimeFile<ELFT>> _runtimeFile;
+ std::unique_ptr<MipsTargetLayout<ELFT>> _targetLayout;
+ std::unique_ptr<TargetRelocationHandler> _relocationHandler;
+};
+
+template <class ELFT> class MipsSymbolTable : public SymbolTable<ELFT> {
+public:
+ typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+
+ MipsSymbolTable(const ELFLinkingContext &ctx)
+ : SymbolTable<ELFT>(ctx, ".symtab",
+ DefaultLayout<ELFT>::ORDER_SYMBOL_TABLE) {}
+
+ void addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da,
+ int64_t addr) override {
+ SymbolTable<ELFT>::addDefinedAtom(sym, da, addr);
+
+ switch (da->codeModel()) {
+ case DefinedAtom::codeMipsMicro:
+ sym.st_other |= llvm::ELF::STO_MIPS_MICROMIPS;
+ break;
+ case DefinedAtom::codeMipsMicroPIC:
+ sym.st_other |= llvm::ELF::STO_MIPS_MICROMIPS | llvm::ELF::STO_MIPS_PIC;
+ break;
+ default:
+ break;
+ }
+ }
+
+ void finalize(bool sort) override {
+ SymbolTable<ELFT>::finalize(sort);
+
+ for (auto &ste : this->_symbolTable) {
+ if (!ste._atom)
+ continue;
+ if (const auto *da = dyn_cast<DefinedAtom>(ste._atom)) {
+ if (da->codeModel() == DefinedAtom::codeMipsMicro ||
+ da->codeModel() == DefinedAtom::codeMipsMicroPIC) {
+ // Adjust dynamic microMIPS symbol value. That allows a dynamic
+ // linker to recognize and handle this symbol correctly.
+ ste._symbol.st_value = ste._symbol.st_value | 1;
+ }
+ }
+ }
+ }
+};
+
+template <class ELFT>
+class MipsDynamicSymbolTable : public DynamicSymbolTable<ELFT> {
+public:
+ MipsDynamicSymbolTable(const ELFLinkingContext &ctx,
+ MipsTargetLayout<ELFT> &layout)
+ : DynamicSymbolTable<ELFT>(ctx, layout, ".dynsym",
+ DefaultLayout<ELFT>::ORDER_DYNAMIC_SYMBOLS),
+ _targetLayout(layout) {}
+
+ void sortSymbols() override {
+ typedef typename DynamicSymbolTable<ELFT>::SymbolEntry SymbolEntry;
+ std::stable_sort(this->_symbolTable.begin(), this->_symbolTable.end(),
+ [this](const SymbolEntry &A, const SymbolEntry &B) {
+ if (A._symbol.getBinding() != STB_GLOBAL &&
+ B._symbol.getBinding() != STB_GLOBAL)
+ return A._symbol.getBinding() < B._symbol.getBinding();
+
+ return _targetLayout.getGOTSection().compare(A._atom, B._atom);
+ });
+ }
+
+ void finalize() override {
+ DynamicSymbolTable<ELFT>::finalize();
+
+ const auto &pltSection = _targetLayout.getPLTSection();
+
+ for (auto &ste : this->_symbolTable) {
+ const Atom *a = ste._atom;
+ if (!a)
+ continue;
+ if (auto *layout = pltSection.findPLTLayout(a)) {
+ a = layout->_atom;
+ // Under some conditions a dynamic symbol table record should hold
+ // a symbol value of the corresponding PLT entry. For details look
+ // at the PLT entry creation code in the class MipsRelocationPass.
+ // Let's update atomLayout fields for such symbols.
+ assert(!ste._atomLayout);
+ ste._symbol.st_value = layout->_virtualAddr;
+ ste._symbol.st_other |= ELF::STO_MIPS_PLT;
+ }
+
+ if (const auto *da = dyn_cast<DefinedAtom>(a)) {
+ if (da->codeModel() == DefinedAtom::codeMipsMicro ||
+ da->codeModel() == DefinedAtom::codeMipsMicroPIC) {
+ // Adjust dynamic microMIPS symbol value. That allows a dynamic
+ // linker to recognize and handle this symbol correctly.
+ ste._symbol.st_value = ste._symbol.st_value | 1;
+ }
+ }
+ }
+ }
+
+private:
+ MipsTargetLayout<ELFT> &_targetLayout;
+};
+
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/OrderPass.h b/lib/ReaderWriter/ELF/OrderPass.h
new file mode 100644
index 0000000000000..d126b830db963
--- /dev/null
+++ b/lib/ReaderWriter/ELF/OrderPass.h
@@ -0,0 +1,30 @@
+//===- lib/ReaderWriter/ELF/OrderPass.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_ORDER_PASS_H
+#define LLD_READER_WRITER_ELF_ORDER_PASS_H
+
+#include "lld/Core/Parallel.h"
+#include <limits>
+
+namespace lld {
+namespace elf {
+
+/// \brief This pass sorts atoms by file and atom ordinals.
+class OrderPass : public Pass {
+public:
+ void perform(std::unique_ptr<MutableFile> &file) override {
+ parallel_sort(file->definedAtoms().begin(), file->definedAtoms().end(),
+ DefinedAtom::compareByPosition);
+ }
+};
+}
+}
+
+#endif
diff --git a/lib/ReaderWriter/ELF/OutputELFWriter.h b/lib/ReaderWriter/ELF/OutputELFWriter.h
new file mode 100644
index 0000000000000..c137905b936b6
--- /dev/null
+++ b/lib/ReaderWriter/ELF/OutputELFWriter.h
@@ -0,0 +1,615 @@
+//===- lib/ReaderWriter/ELF/OutputELFWriter.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_OUTPUT_WRITER_H
+#define LLD_READER_WRITER_ELF_OUTPUT_WRITER_H
+
+#include "DefaultLayout.h"
+#include "ELFFile.h"
+#include "TargetLayout.h"
+#include "lld/Core/Instrumentation.h"
+#include "lld/Core/Parallel.h"
+#include "lld/Core/SharedLibraryFile.h"
+#include "lld/ReaderWriter/ELFLinkingContext.h"
+#include "lld/Core/Simple.h"
+#include "lld/Core/Writer.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/Support/Path.h"
+
+namespace lld {
+namespace elf {
+using namespace llvm;
+using namespace llvm::object;
+
+template <class ELFT> class OutputELFWriter;
+template <class ELFT> class TargetLayout;
+
+namespace {
+
+template<class ELFT>
+class SymbolFile : public RuntimeFile<ELFT> {
+public:
+ SymbolFile(ELFLinkingContext &context)
+ : RuntimeFile<ELFT>(context, "Dynamic absolute symbols"),
+ _atomsAdded(false) {}
+
+ Atom *addAbsoluteAtom(StringRef symbolName) override {
+ auto *a = RuntimeFile<ELFT>::addAbsoluteAtom(symbolName);
+ if (a) _atomsAdded = true;
+ return a;
+ }
+
+ Atom *addUndefinedAtom(StringRef) override {
+ llvm_unreachable("Cannot add undefined atoms to resolve undefined symbols");
+ }
+
+ bool hasAtoms() const { return _atomsAdded; }
+
+private:
+ bool _atomsAdded;
+};
+
+template<class ELFT>
+class DynamicSymbolFile : public SimpleArchiveLibraryFile {
+ typedef std::function<void(StringRef, RuntimeFile<ELFT> &)> Resolver;
+public:
+ DynamicSymbolFile(ELFLinkingContext &context, Resolver resolver)
+ : SimpleArchiveLibraryFile("Dynamically added runtime symbols"),
+ _context(context), _resolver(resolver) {}
+
+ File *find(StringRef sym, bool dataSymbolOnly) override {
+ if (!_file)
+ _file.reset(new (_alloc) SymbolFile<ELFT>(_context));
+
+ assert(!_file->hasAtoms() && "The file shouldn't have atoms yet");
+ _resolver(sym, *_file);
+ // If atoms were added - release the file to the caller.
+ return _file->hasAtoms() ? _file.release() : nullptr;
+ }
+
+private:
+ ELFLinkingContext &_context;
+ Resolver _resolver;
+
+ // The allocator should go before bump pointers because of
+ // reversed destruction order.
+ llvm::BumpPtrAllocator _alloc;
+ unique_bump_ptr<SymbolFile<ELFT>> _file;
+};
+
+} // end anon namespace
+
+//===----------------------------------------------------------------------===//
+// OutputELFWriter Class
+//===----------------------------------------------------------------------===//
+/// \brief This acts as the base class for all the ELF writers that are output
+/// for emitting an ELF output file. This class also acts as a common class for
+/// creating static and dynamic executables. All the function in this class
+/// can be overridden and an appropriate writer be created
+template<class ELFT>
+class OutputELFWriter : public ELFWriter {
+public:
+ typedef Elf_Shdr_Impl<ELFT> Elf_Shdr;
+ typedef Elf_Sym_Impl<ELFT> Elf_Sym;
+ typedef Elf_Dyn_Impl<ELFT> Elf_Dyn;
+
+ OutputELFWriter(ELFLinkingContext &context, TargetLayout<ELFT> &layout);
+
+protected:
+ // build the sections that need to be created
+ virtual void createDefaultSections();
+
+ // Build all the output sections
+ void buildChunks(const File &file) override;
+
+ // Build the output file
+ virtual std::error_code buildOutput(const File &file);
+
+ // Setup the ELF header.
+ virtual std::error_code setELFHeader();
+
+ // Write the file to the path specified
+ std::error_code writeFile(const File &File, StringRef path) override;
+
+ // Write to the output file.
+ virtual std::error_code writeOutput(const File &file, StringRef path);
+
+ // Get the size of the output file that the linker would emit.
+ virtual uint64_t outputFileSize() const;
+
+ // Build the atom to address map, this has to be called
+ // before applying relocations
+ virtual void buildAtomToAddressMap(const File &file);
+
+ // Build the symbol table for static linking
+ virtual void buildStaticSymbolTable(const File &file);
+
+ // Build the dynamic symbol table for dynamic linking
+ virtual void buildDynamicSymbolTable(const File &file);
+
+ // Build the section header table
+ virtual void buildSectionHeaderTable();
+
+ // Assign sections that have no segments such as the symbol table,
+ // section header table, string table etc
+ virtual void assignSectionsWithNoSegments();
+
+ // Add default atoms that need to be present in the output file
+ virtual void addDefaultAtoms();
+
+ // Add any runtime files and their atoms to the output
+ bool createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
+
+ // Finalize the default atom values
+ virtual void finalizeDefaultAtomValues();
+
+ // This is called by the write section to apply relocations
+ uint64_t addressOfAtom(const Atom *atom) override {
+ auto addr = _atomToAddressMap.find(atom);
+ return addr == _atomToAddressMap.end() ? 0 : addr->second;
+ }
+
+ // This is a hook for creating default dynamic entries
+ virtual void createDefaultDynamicEntries() {}
+
+ /// \brief Create symbol table.
+ virtual unique_bump_ptr<SymbolTable<ELFT>> createSymbolTable();
+
+ /// \brief create dynamic table.
+ virtual unique_bump_ptr<DynamicTable<ELFT>> createDynamicTable();
+
+ /// \brief create dynamic symbol table.
+ virtual unique_bump_ptr<DynamicSymbolTable<ELFT>>
+ createDynamicSymbolTable();
+
+ /// \brief Create entry in the dynamic symbols table for this atom.
+ virtual bool isDynSymEntryRequired(const SharedLibraryAtom *sla) const {
+ return _layout.isReferencedByDefinedAtom(sla);
+ }
+
+ /// \brief Create DT_NEEDED dynamic tage for the shared library.
+ virtual bool isNeededTagRequired(const SharedLibraryAtom *sla) const {
+ return false;
+ }
+
+ /// \brief Process undefined symbols that left after resolution step.
+ virtual void processUndefinedSymbol(StringRef symName,
+ RuntimeFile<ELFT> &file) const {}
+
+ llvm::BumpPtrAllocator _alloc;
+
+ ELFLinkingContext &_context;
+ TargetHandler<ELFT> &_targetHandler;
+
+ typedef llvm::DenseMap<const Atom *, uint64_t> AtomToAddress;
+ AtomToAddress _atomToAddressMap;
+ TargetLayout<ELFT> &_layout;
+ unique_bump_ptr<ELFHeader<ELFT>> _elfHeader;
+ unique_bump_ptr<ProgramHeader<ELFT>> _programHeader;
+ unique_bump_ptr<SymbolTable<ELFT>> _symtab;
+ unique_bump_ptr<StringTable<ELFT>> _strtab;
+ unique_bump_ptr<StringTable<ELFT>> _shstrtab;
+ unique_bump_ptr<SectionHeader<ELFT>> _shdrtab;
+ unique_bump_ptr<EHFrameHeader<ELFT>> _ehFrameHeader;
+ /// \name Dynamic sections.
+ /// @{
+ unique_bump_ptr<DynamicTable<ELFT>> _dynamicTable;
+ unique_bump_ptr<DynamicSymbolTable<ELFT>> _dynamicSymbolTable;
+ unique_bump_ptr<StringTable<ELFT>> _dynamicStringTable;
+ unique_bump_ptr<HashSection<ELFT>> _hashTable;
+ llvm::StringSet<> _soNeeded;
+ /// @}
+ std::unique_ptr<RuntimeFile<ELFT>> _scriptFile;
+
+private:
+ static StringRef maybeGetSOName(Node *node);
+};
+
+//===----------------------------------------------------------------------===//
+// OutputELFWriter
+//===----------------------------------------------------------------------===//
+template <class ELFT>
+OutputELFWriter<ELFT>::OutputELFWriter(ELFLinkingContext &context,
+ TargetLayout<ELFT> &layout)
+ : _context(context), _targetHandler(context.getTargetHandler<ELFT>()),
+ _layout(layout),
+ _scriptFile(new RuntimeFile<ELFT>(context, "Linker script runtime")) {}
+
+template <class ELFT>
+void OutputELFWriter<ELFT>::buildChunks(const File &file) {
+ ScopedTask task(getDefaultDomain(), "buildChunks");
+ for (const DefinedAtom *definedAtom : file.defined()) {
+ DefinedAtom::ContentType contentType = definedAtom->contentType();
+ // Dont add COMDAT group atoms and GNU linkonce atoms, as they are used for
+ // symbol resolution.
+ // TODO: handle partial linking.
+ if (contentType == DefinedAtom::typeGroupComdat ||
+ contentType == DefinedAtom::typeGnuLinkOnce)
+ continue;
+ _layout.addAtom(definedAtom);
+ }
+ for (const AbsoluteAtom *absoluteAtom : file.absolute())
+ _layout.addAtom(absoluteAtom);
+}
+
+template <class ELFT>
+void OutputELFWriter<ELFT>::buildStaticSymbolTable(const File &file) {
+ ScopedTask task(getDefaultDomain(), "buildStaticSymbolTable");
+ for (auto sec : _layout.sections())
+ if (auto section = dyn_cast<AtomSection<ELFT>>(sec))
+ for (const auto &atom : section->atoms())
+ _symtab->addSymbol(atom->_atom, section->ordinal(), atom->_virtualAddr);
+ for (auto &atom : _layout.absoluteAtoms())
+ _symtab->addSymbol(atom->_atom, ELF::SHN_ABS, atom->_virtualAddr);
+ for (const UndefinedAtom *a : file.undefined())
+ _symtab->addSymbol(a, ELF::SHN_UNDEF);
+}
+
+// Returns the DSO name for a given input file if it's a shared library
+// file and not marked as --as-needed.
+template <class ELFT>
+StringRef OutputELFWriter<ELFT>::maybeGetSOName(Node *node) {
+ if (auto *fnode = dyn_cast<FileNode>(node))
+ if (!fnode->asNeeded())
+ if (auto *file = dyn_cast<SharedLibraryFile>(fnode->getFile()))
+ return file->getDSOName();
+ return "";
+}
+
+template <class ELFT>
+void OutputELFWriter<ELFT>::buildDynamicSymbolTable(const File &file) {
+ ScopedTask task(getDefaultDomain(), "buildDynamicSymbolTable");
+ for (const auto &sla : file.sharedLibrary()) {
+ if (isDynSymEntryRequired(sla)) {
+ _dynamicSymbolTable->addSymbol(sla, ELF::SHN_UNDEF);
+ _soNeeded.insert(sla->loadName());
+ continue;
+ }
+ if (isNeededTagRequired(sla))
+ _soNeeded.insert(sla->loadName());
+ }
+ for (const std::unique_ptr<Node> &node : _context.getNodes()) {
+ StringRef soname = maybeGetSOName(node.get());
+ if (!soname.empty())
+ _soNeeded.insert(soname);
+ }
+ // Never mark the dynamic linker as DT_NEEDED
+ _soNeeded.erase(sys::path::filename(_context.getInterpreter()));
+ for (const auto &loadName : _soNeeded) {
+ Elf_Dyn dyn;
+ dyn.d_tag = DT_NEEDED;
+ dyn.d_un.d_val = _dynamicStringTable->addString(loadName.getKey());
+ _dynamicTable->addEntry(dyn);
+ }
+ const auto &rpathList = _context.getRpathList();
+ if (!rpathList.empty()) {
+ auto rpath = new (_alloc) std::string(join(rpathList.begin(),
+ rpathList.end(), ":"));
+ Elf_Dyn dyn;
+ dyn.d_tag = DT_RPATH;
+ dyn.d_un.d_val = _dynamicStringTable->addString(*rpath);
+ _dynamicTable->addEntry(dyn);
+ }
+ StringRef soname = _context.sharedObjectName();
+ if (!soname.empty() && _context.getOutputELFType() == llvm::ELF::ET_DYN) {
+ Elf_Dyn dyn;
+ dyn.d_tag = DT_SONAME;
+ dyn.d_un.d_val = _dynamicStringTable->addString(soname);
+ _dynamicTable->addEntry(dyn);
+ }
+ // The dynamic symbol table need to be sorted earlier because the hash
+ // table needs to be built using the dynamic symbol table. It would be
+ // late to sort the symbols due to that in finalize. In the dynamic symbol
+ // table finalize, we call the symbol table finalize and we don't want to
+ // sort again
+ _dynamicSymbolTable->sortSymbols();
+
+ // Add the dynamic symbols into the hash table
+ _dynamicSymbolTable->addSymbolsToHashTable();
+}
+
+template <class ELFT>
+void OutputELFWriter<ELFT>::buildAtomToAddressMap(const File &file) {
+ ScopedTask task(getDefaultDomain(), "buildAtomToAddressMap");
+ int64_t totalAbsAtoms = _layout.absoluteAtoms().size();
+ int64_t totalUndefinedAtoms = file.undefined().size();
+ int64_t totalDefinedAtoms = 0;
+ for (auto sec : _layout.sections())
+ if (auto section = dyn_cast<AtomSection<ELFT> >(sec)) {
+ totalDefinedAtoms += section->atoms().size();
+ for (const auto &atom : section->atoms())
+ _atomToAddressMap[atom->_atom] = atom->_virtualAddr;
+ }
+ // build the atomToAddressMap that contains absolute symbols too
+ for (auto &atom : _layout.absoluteAtoms())
+ _atomToAddressMap[atom->_atom] = atom->_virtualAddr;
+
+ // Set the total number of atoms in the symbol table, so that appropriate
+ // resizing of the string table can be done
+ _symtab->setNumEntries(totalDefinedAtoms + totalAbsAtoms +
+ totalUndefinedAtoms);
+}
+
+template<class ELFT>
+void OutputELFWriter<ELFT>::buildSectionHeaderTable() {
+ ScopedTask task(getDefaultDomain(), "buildSectionHeaderTable");
+ for (auto outputSection : _layout.outputSections()) {
+ if (outputSection->kind() != Chunk<ELFT>::Kind::ELFSection &&
+ outputSection->kind() != Chunk<ELFT>::Kind::AtomSection)
+ continue;
+ if (outputSection->hasSegment())
+ _shdrtab->appendSection(outputSection);
+ }
+}
+
+template<class ELFT>
+void OutputELFWriter<ELFT>::assignSectionsWithNoSegments() {
+ ScopedTask task(getDefaultDomain(), "assignSectionsWithNoSegments");
+ for (auto outputSection : _layout.outputSections()) {
+ if (outputSection->kind() != Chunk<ELFT>::Kind::ELFSection &&
+ outputSection->kind() != Chunk<ELFT>::Kind::AtomSection)
+ continue;
+ if (!outputSection->hasSegment())
+ _shdrtab->appendSection(outputSection);
+ }
+ _layout.assignFileOffsetsForMiscSections();
+ for (auto sec : _layout.sections())
+ if (auto section = dyn_cast<Section<ELFT>>(sec))
+ if (!DefaultLayout<ELFT>::hasOutputSegment(section))
+ _shdrtab->updateSection(section);
+}
+
+template <class ELFT> void OutputELFWriter<ELFT>::addDefaultAtoms() {
+ const llvm::StringSet<> &symbols =
+ _context.linkerScriptSema().getScriptDefinedSymbols();
+ for (auto &sym : symbols)
+ _scriptFile->addAbsoluteAtom(sym.getKey());
+}
+
+template <class ELFT>
+bool OutputELFWriter<ELFT>::createImplicitFiles(
+ std::vector<std::unique_ptr<File>> &result) {
+ // Add the virtual archive to resolve undefined symbols.
+ // The file will be added later in the linking context.
+ auto callback = [this](StringRef sym, RuntimeFile<ELFT> &file) {
+ processUndefinedSymbol(sym, file);
+ };
+ auto &ctx = const_cast<ELFLinkingContext &>(_context);
+ ctx.setUndefinesResolver(
+ llvm::make_unique<DynamicSymbolFile<ELFT>>(ctx, std::move(callback)));
+ // Add script defined symbols
+ result.push_back(std::move(_scriptFile));
+ return true;
+}
+
+template <class ELFT>
+void OutputELFWriter<ELFT>::finalizeDefaultAtomValues() {
+ const llvm::StringSet<> &symbols =
+ _context.linkerScriptSema().getScriptDefinedSymbols();
+ for (auto &sym : symbols) {
+ uint64_t res =
+ _context.linkerScriptSema().getLinkerScriptExprValue(sym.getKey());
+ auto a = _layout.findAbsoluteAtom(sym.getKey());
+ (*a)->_virtualAddr = res;
+ }
+}
+
+template <class ELFT> void OutputELFWriter<ELFT>::createDefaultSections() {
+ _elfHeader.reset(new (_alloc) ELFHeader<ELFT>(_context));
+ _programHeader.reset(new (_alloc) ProgramHeader<ELFT>(_context));
+ _layout.setHeader(_elfHeader.get());
+ _layout.setProgramHeader(_programHeader.get());
+
+ _symtab = std::move(this->createSymbolTable());
+ _strtab.reset(new (_alloc) StringTable<ELFT>(
+ _context, ".strtab", DefaultLayout<ELFT>::ORDER_STRING_TABLE));
+ _shstrtab.reset(new (_alloc) StringTable<ELFT>(
+ _context, ".shstrtab", DefaultLayout<ELFT>::ORDER_SECTION_STRINGS));
+ _shdrtab.reset(new (_alloc) SectionHeader<ELFT>(
+ _context, DefaultLayout<ELFT>::ORDER_SECTION_HEADERS));
+ _layout.addSection(_symtab.get());
+ _layout.addSection(_strtab.get());
+ _layout.addSection(_shstrtab.get());
+ _shdrtab->setStringSection(_shstrtab.get());
+ _symtab->setStringSection(_strtab.get());
+ _layout.addSection(_shdrtab.get());
+
+ for (auto sec : _layout.sections()) {
+ // TODO: use findOutputSection
+ auto section = dyn_cast<Section<ELFT>>(sec);
+ if (!section || section->outputSectionName() != ".eh_frame")
+ continue;
+ _ehFrameHeader.reset(new (_alloc) EHFrameHeader<ELFT>(
+ _context, ".eh_frame_hdr", _layout,
+ DefaultLayout<ELFT>::ORDER_EH_FRAMEHDR));
+ _layout.addSection(_ehFrameHeader.get());
+ break;
+ }
+
+ if (_context.isDynamic()) {
+ _dynamicTable = std::move(createDynamicTable());
+ _dynamicStringTable.reset(new (_alloc) StringTable<ELFT>(
+ _context, ".dynstr", DefaultLayout<ELFT>::ORDER_DYNAMIC_STRINGS, true));
+ _dynamicSymbolTable = std::move(createDynamicSymbolTable());
+ _hashTable.reset(new (_alloc) HashSection<ELFT>(
+ _context, ".hash", DefaultLayout<ELFT>::ORDER_HASH));
+ // Set the hash table in the dynamic symbol table so that the entries in the
+ // hash table can be created
+ _dynamicSymbolTable->setHashTable(_hashTable.get());
+ _hashTable->setSymbolTable(_dynamicSymbolTable.get());
+ _layout.addSection(_dynamicTable.get());
+ _layout.addSection(_dynamicStringTable.get());
+ _layout.addSection(_dynamicSymbolTable.get());
+ _layout.addSection(_hashTable.get());
+ _dynamicSymbolTable->setStringSection(_dynamicStringTable.get());
+ _dynamicTable->setSymbolTable(_dynamicSymbolTable.get());
+ _dynamicTable->setHashTable(_hashTable.get());
+ if (_layout.hasDynamicRelocationTable())
+ _layout.getDynamicRelocationTable()->setSymbolTable(
+ _dynamicSymbolTable.get());
+ if (_layout.hasPLTRelocationTable())
+ _layout.getPLTRelocationTable()->setSymbolTable(
+ _dynamicSymbolTable.get());
+ }
+}
+
+template <class ELFT>
+unique_bump_ptr<SymbolTable<ELFT>>
+ OutputELFWriter<ELFT>::createSymbolTable() {
+ return unique_bump_ptr<SymbolTable<ELFT>>(new (_alloc) SymbolTable<ELFT>(
+ this->_context, ".symtab", DefaultLayout<ELFT>::ORDER_SYMBOL_TABLE));
+}
+
+/// \brief create dynamic table
+template <class ELFT>
+unique_bump_ptr<DynamicTable<ELFT>>
+ OutputELFWriter<ELFT>::createDynamicTable() {
+ return unique_bump_ptr<DynamicTable<ELFT>>(
+ new (_alloc) DynamicTable<ELFT>(
+ this->_context, _layout, ".dynamic", DefaultLayout<ELFT>::ORDER_DYNAMIC));
+}
+
+/// \brief create dynamic symbol table
+template <class ELFT>
+unique_bump_ptr<DynamicSymbolTable<ELFT>>
+ OutputELFWriter<ELFT>::createDynamicSymbolTable() {
+ return unique_bump_ptr<DynamicSymbolTable<ELFT>>(
+ new (_alloc) DynamicSymbolTable<ELFT>(
+ this->_context, _layout, ".dynsym",
+ DefaultLayout<ELFT>::ORDER_DYNAMIC_SYMBOLS));
+}
+
+template <class ELFT>
+std::error_code OutputELFWriter<ELFT>::buildOutput(const File &file) {
+ ScopedTask buildTask(getDefaultDomain(), "ELF Writer buildOutput");
+ buildChunks(file);
+
+ // Create the default sections like the symbol table, string table, and the
+ // section string table
+ createDefaultSections();
+
+ // Set the Layout
+ _layout.assignSectionsToSegments();
+
+ // Create the dynamic table entries
+ if (_context.isDynamic()) {
+ _dynamicTable->createDefaultEntries();
+ buildDynamicSymbolTable(file);
+ }
+
+ // Call the preFlight callbacks to modify the sections and the atoms
+ // contained in them, in anyway the targets may want
+ _layout.doPreFlight();
+
+ _layout.assignVirtualAddress();
+
+ // Finalize the default value of symbols that the linker adds
+ finalizeDefaultAtomValues();
+
+ // Build the Atom To Address map for applying relocations
+ buildAtomToAddressMap(file);
+
+ // Create symbol table and section string table
+ // Do it only if -s is not specified.
+ if (!_context.stripSymbols())
+ buildStaticSymbolTable(file);
+
+ // Finalize the layout by calling the finalize() functions
+ _layout.finalize();
+
+ // build Section Header table
+ buildSectionHeaderTable();
+
+ // assign Offsets and virtual addresses
+ // for sections with no segments
+ assignSectionsWithNoSegments();
+
+ if (_context.isDynamic())
+ _dynamicTable->updateDynamicTable();
+
+ return std::error_code();
+}
+
+template <class ELFT> std::error_code OutputELFWriter<ELFT>::setELFHeader() {
+ _elfHeader->e_type(_context.getOutputELFType());
+ _elfHeader->e_machine(_context.getOutputMachine());
+ _elfHeader->e_ident(ELF::EI_VERSION, 1);
+ _elfHeader->e_ident(ELF::EI_OSABI, 0);
+ _elfHeader->e_version(1);
+ _elfHeader->e_phoff(_programHeader->fileOffset());
+ _elfHeader->e_shoff(_shdrtab->fileOffset());
+ _elfHeader->e_phentsize(_programHeader->entsize());
+ _elfHeader->e_phnum(_programHeader->numHeaders());
+ _elfHeader->e_shentsize(_shdrtab->entsize());
+ _elfHeader->e_shnum(_shdrtab->numHeaders());
+ _elfHeader->e_shstrndx(_shstrtab->ordinal());
+ if (const auto *al = _layout.findAtomLayoutByName(_context.entrySymbolName()))
+ _elfHeader->e_entry(al->_virtualAddr);
+ else
+ _elfHeader->e_entry(0);
+
+ return std::error_code();
+}
+
+template <class ELFT> uint64_t OutputELFWriter<ELFT>::outputFileSize() const {
+ return _shdrtab->fileOffset() + _shdrtab->fileSize();
+}
+
+template <class ELFT>
+std::error_code OutputELFWriter<ELFT>::writeOutput(const File &file,
+ StringRef path) {
+ std::unique_ptr<FileOutputBuffer> buffer;
+ ScopedTask createOutputTask(getDefaultDomain(), "ELF Writer Create Output");
+ std::error_code ec = FileOutputBuffer::create(path, outputFileSize(), buffer,
+ FileOutputBuffer::F_executable);
+ createOutputTask.end();
+
+ if (ec)
+ return ec;
+
+ ScopedTask writeTask(getDefaultDomain(), "ELF Writer write to memory");
+
+ // HACK: We have to write out the header and program header here even though
+ // they are a member of a segment because only sections are written in the
+ // following loop.
+
+ // Finalize ELF Header / Program Headers.
+ _elfHeader->finalize();
+ _programHeader->finalize();
+
+ _elfHeader->write(this, _layout, *buffer);
+ _programHeader->write(this, _layout, *buffer);
+
+ auto sections = _layout.sections();
+ parallel_for_each(
+ sections.begin(), sections.end(),
+ [&](Chunk<ELFT> *section) { section->write(this, _layout, *buffer); });
+ writeTask.end();
+
+ ScopedTask commitTask(getDefaultDomain(), "ELF Writer commit to disk");
+ return buffer->commit();
+}
+
+template <class ELFT>
+std::error_code OutputELFWriter<ELFT>::writeFile(const File &file,
+ StringRef path) {
+ std::error_code ec = buildOutput(file);
+ if (ec)
+ return ec;
+
+ ec = setELFHeader();
+ if (ec)
+ return ec;
+
+ return writeOutput(file, path);
+}
+} // namespace elf
+} // namespace lld
+
+#endif // LLD_READER_WRITER_ELF_OUTPUT_WRITER_H
diff --git a/lib/ReaderWriter/ELF/Reader.cpp b/lib/ReaderWriter/ELF/Reader.cpp
new file mode 100644
index 0000000000000..fc113d4789132
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Reader.cpp
@@ -0,0 +1,43 @@
+//===- lib/ReaderWriter/ELF/Reader.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 ELF Reader and all helper sub classes to consume an ELF
+/// file and produces atoms out of it.
+///
+//===----------------------------------------------------------------------===//
+
+#include "ELFReader.h"
+#include <map>
+#include <vector>
+
+using llvm::support::endianness;
+using namespace llvm::object;
+
+namespace lld {
+
+// This dynamic registration of a handler causes support for all ELF
+// architectures to be pulled into the linker. If we want to support making a
+// linker that only supports one ELF architecture, we'd need to change this
+// to have a different registration method for each architecture.
+void Registry::addSupportELFObjects(ELFLinkingContext &ctx) {
+
+ // Tell registry about the ELF object file parser.
+ add(std::move(ctx.targetHandler()->getObjReader()));
+
+ // Tell registry about the relocation name to number mapping for this arch.
+ ctx.targetHandler()->registerRelocationNames(*this);
+}
+
+void Registry::addSupportELFDynamicSharedObjects(ELFLinkingContext &ctx) {
+ // Tell registry about the ELF dynamic shared library file parser.
+ add(ctx.targetHandler()->getDSOReader());
+}
+
+} // end namespace lld
diff --git a/lib/ReaderWriter/ELF/SectionChunks.h b/lib/ReaderWriter/ELF/SectionChunks.h
new file mode 100644
index 0000000000000..03bdb59e65681
--- /dev/null
+++ b/lib/ReaderWriter/ELF/SectionChunks.h
@@ -0,0 +1,1498 @@
+//===- lib/ReaderWriter/ELF/SectionChunks.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_SECTION_CHUNKS_H
+#define LLD_READER_WRITER_ELF_SECTION_CHUNKS_H
+
+#include "Chunk.h"
+#include "Layout.h"
+#include "TargetHandler.h"
+#include "Writer.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/Parallel.h"
+#include "lld/Core/range.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Dwarf.h"
+#include "llvm/Support/ELF.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include <memory>
+#include <mutex>
+
+namespace lld {
+namespace elf {
+template <class> class OutputSection;
+using namespace llvm::ELF;
+template <class ELFT> class Segment;
+
+/// \brief An ELF section.
+template <class ELFT> class Section : public Chunk<ELFT> {
+public:
+ Section(const ELFLinkingContext &context, StringRef sectionName,
+ StringRef chunkName,
+ typename Chunk<ELFT>::Kind k = Chunk<ELFT>::Kind::ELFSection)
+ : Chunk<ELFT>(chunkName, k, context), _outputSection(nullptr), _flags(0),
+ _entSize(0), _type(0), _link(0), _info(0),
+ _isFirstSectionInOutputSection(false), _segmentType(SHT_NULL),
+ _inputSectionName(sectionName), _outputSectionName(sectionName) {}
+
+ /// \brief Modify the section contents before assigning virtual addresses
+ // or assigning file offsets
+ void doPreFlight() override {}
+
+ /// \brief Finalize the section contents before writing
+ void finalize() override {}
+
+ /// \brief Does this section have an output segment.
+ virtual bool hasOutputSegment() {
+ return false;
+ }
+
+ /// Return if the section is a loadable section that occupies memory
+ virtual bool isLoadableSection() const { return false; }
+
+ /// \brief Assign file offsets starting at offset.
+ virtual void assignFileOffsets(uint64_t offset) {}
+
+ /// \brief Assign virtual addresses starting at addr.
+ virtual void assignVirtualAddress(uint64_t addr) {}
+
+ uint64_t getFlags() const { return _flags; }
+ uint64_t getEntSize() const { return _entSize; }
+ uint32_t getType() const { return _type; }
+ uint32_t getLink() const { return _link; }
+ uint32_t getInfo() const { return _info; }
+ Layout::SegmentType getSegmentType() const { return _segmentType; }
+
+ /// \brief Return the type of content that the section contains
+ virtual int getContentType() const override {
+ if (_flags & llvm::ELF::SHF_EXECINSTR)
+ return Chunk<ELFT>::ContentType::Code;
+ else if (_flags & llvm::ELF::SHF_WRITE)
+ return Chunk<ELFT>::ContentType::Data;
+ else if (_flags & llvm::ELF::SHF_ALLOC)
+ return Chunk<ELFT>::ContentType::Code;
+ else
+ return Chunk<ELFT>::ContentType::Unknown;
+ }
+
+ /// \brief convert the segment type to a String for diagnostics and printing
+ /// purposes
+ StringRef segmentKindToStr() const;
+
+ /// \brief Records the segmentType, that this section belongs to
+ void setSegmentType(const Layout::SegmentType segmentType) {
+ this->_segmentType = segmentType;
+ }
+
+ virtual const AtomLayout *findAtomLayoutByName(StringRef) const {
+ return nullptr;
+ }
+
+ void setOutputSection(OutputSection<ELFT> *os, bool isFirst = false) {
+ _outputSection = os;
+ _isFirstSectionInOutputSection = isFirst;
+ }
+
+ static bool classof(const Chunk<ELFT> *c) {
+ return c->kind() == Chunk<ELFT>::Kind::ELFSection ||
+ c->kind() == Chunk<ELFT>::Kind::AtomSection;
+ }
+
+ uint64_t alignment() const override {
+ return _isFirstSectionInOutputSection ? _outputSection->alignment()
+ : this->_alignment;
+ }
+
+ virtual StringRef inputSectionName() const { return _inputSectionName; }
+
+ virtual StringRef outputSectionName() const { return _outputSectionName; }
+
+ virtual void setOutputSectionName(StringRef outputSectionName) {
+ _outputSectionName = outputSectionName;
+ }
+
+ void setArchiveNameOrPath(StringRef name) { _archivePath = name; }
+
+ void setMemberNameOrPath(StringRef name) { _memberPath = name; }
+
+ StringRef archivePath() { return _archivePath; }
+
+ StringRef memberPath() { return _memberPath; }
+
+protected:
+ /// \brief OutputSection this Section is a member of, or nullptr.
+ OutputSection<ELFT> *_outputSection;
+ /// \brief ELF SHF_* flags.
+ uint64_t _flags;
+ /// \brief The size of each entity.
+ uint64_t _entSize;
+ /// \brief ELF SHT_* type.
+ uint32_t _type;
+ /// \brief sh_link field.
+ uint32_t _link;
+ /// \brief the sh_info field.
+ uint32_t _info;
+ /// \brief Is this the first section in the output section.
+ bool _isFirstSectionInOutputSection;
+ /// \brief the output ELF segment type of this section.
+ Layout::SegmentType _segmentType;
+ /// \brief Input section name.
+ StringRef _inputSectionName;
+ /// \brief Output section name.
+ StringRef _outputSectionName;
+ StringRef _archivePath;
+ StringRef _memberPath;
+};
+
+/// \brief A section containing atoms.
+template <class ELFT> class AtomSection : public Section<ELFT> {
+public:
+ AtomSection(const ELFLinkingContext &context, StringRef sectionName,
+ int32_t contentType, int32_t permissions, int32_t order)
+ : Section<ELFT>(context, sectionName, "AtomSection",
+ Chunk<ELFT>::Kind::AtomSection),
+ _contentType(contentType), _contentPermissions(permissions),
+ _isLoadedInMemory(true) {
+ this->setOrder(order);
+
+ switch (contentType) {
+ case DefinedAtom::typeCode:
+ case DefinedAtom::typeDataFast:
+ case DefinedAtom::typeData:
+ case DefinedAtom::typeConstant:
+ case DefinedAtom::typeGOT:
+ case DefinedAtom::typeStub:
+ case DefinedAtom::typeResolver:
+ case DefinedAtom::typeThreadData:
+ this->_type = SHT_PROGBITS;
+ break;
+
+ case DefinedAtom::typeThreadZeroFill:
+ case DefinedAtom::typeZeroFillFast:
+ case DefinedAtom::typeZeroFill:
+ this->_type = SHT_NOBITS;
+ break;
+
+ case DefinedAtom::typeRONote:
+ case DefinedAtom::typeRWNote:
+ this->_type = SHT_NOTE;
+ break;
+
+ case DefinedAtom::typeNoAlloc:
+ this->_type = SHT_PROGBITS;
+ this->_isLoadedInMemory = false;
+ break;
+ }
+
+ switch (permissions) {
+ case DefinedAtom::permR__:
+ this->_flags = SHF_ALLOC;
+ break;
+ case DefinedAtom::permR_X:
+ this->_flags = SHF_ALLOC | SHF_EXECINSTR;
+ break;
+ case DefinedAtom::permRW_:
+ case DefinedAtom::permRW_L:
+ this->_flags = SHF_ALLOC | SHF_WRITE;
+ if (_contentType == DefinedAtom::typeThreadData ||
+ _contentType == DefinedAtom::typeThreadZeroFill)
+ this->_flags |= SHF_TLS;
+ break;
+ case DefinedAtom::permRWX:
+ this->_flags = SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR;
+ break;
+ case DefinedAtom::perm___:
+ this->_flags = 0;
+ break;
+ }
+ }
+
+ /// Align the offset to the required modulus defined by the atom alignment
+ uint64_t alignOffset(uint64_t offset, DefinedAtom::Alignment &atomAlign);
+
+ /// Return if the section is a loadable section that occupies memory
+ bool isLoadableSection() const override { return _isLoadedInMemory; }
+
+ // \brief Append an atom to a Section. The atom gets pushed into a vector
+ // contains the atom, the atom file offset, the atom virtual address
+ // the atom file offset is aligned appropriately as set by the Reader
+ virtual const lld::AtomLayout *appendAtom(const Atom *atom);
+
+ /// \brief Set the virtual address of each Atom in the Section. This
+ /// routine gets called after the linker fixes up the virtual address
+ /// of the section
+ virtual void assignVirtualAddress(uint64_t addr) override {
+ parallel_for_each(_atoms.begin(), _atoms.end(), [&](AtomLayout *ai) {
+ ai->_virtualAddr = addr + ai->_fileOffset;
+ });
+ }
+
+ /// \brief Set the file offset of each Atom in the section. This routine
+ /// gets called after the linker fixes up the section offset
+ void assignFileOffsets(uint64_t offset) override {
+ parallel_for_each(_atoms.begin(), _atoms.end(), [&](AtomLayout *ai) {
+ ai->_fileOffset = offset + ai->_fileOffset;
+ });
+ }
+
+ /// \brief Find the Atom address given a name, this is needed to properly
+ /// apply relocation. The section class calls this to find the atom address
+ /// to fix the relocation
+ const AtomLayout *findAtomLayoutByName(StringRef name) const override {
+ for (auto ai : _atoms)
+ if (ai->_atom->name() == name)
+ return ai;
+ return nullptr;
+ }
+
+ /// \brief Return the raw flags, we need this to sort segments
+ int64_t atomflags() const { return _contentPermissions; }
+
+ /// Atom Iterators
+ typedef typename std::vector<lld::AtomLayout *>::iterator atom_iter;
+
+ range<atom_iter> atoms() { return _atoms; }
+
+ void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
+ llvm::FileOutputBuffer &buffer) override;
+
+ static bool classof(const Chunk<ELFT> *c) {
+ return c->kind() == Chunk<ELFT>::Kind::AtomSection;
+ }
+
+protected:
+ llvm::BumpPtrAllocator _alloc;
+ int32_t _contentType;
+ int32_t _contentPermissions;
+ bool _isLoadedInMemory;
+ std::vector<lld::AtomLayout *> _atoms;
+ mutable std::mutex _outputMutex;
+
+ void printError(const std::string &errorStr, const AtomLayout &atom,
+ const Reference &ref) const {
+ StringRef kindValStr;
+ if (!this->_context.registry().referenceKindToString(ref.kindNamespace(),
+ ref.kindArch(),
+ ref.kindValue(),
+ kindValStr)) {
+ kindValStr = "unknown";
+ }
+
+ std::string errStr = (Twine(errorStr) + " in file " +
+ atom._atom->file().path() +
+ ": reference from " + atom._atom->name() +
+ "+" + Twine(ref.offsetInAtom()) +
+ " to " + ref.target()->name() +
+ "+" + Twine(ref.addend()) +
+ " of type " + Twine(ref.kindValue()) +
+ " (" + kindValStr + ")\n").str();
+
+ // Take the lock to prevent output getting interleaved between threads
+ std::lock_guard<std::mutex> lock(_outputMutex);
+ llvm::errs() << errStr;
+ }
+};
+
+/// Align the offset to the required modulus defined by the atom alignment
+template <class ELFT>
+uint64_t AtomSection<ELFT>::alignOffset(uint64_t offset,
+ DefinedAtom::Alignment &atomAlign) {
+ uint64_t requiredModulus = atomAlign.modulus;
+ uint64_t alignment = 1u << atomAlign.powerOf2;
+ uint64_t currentModulus = (offset % alignment);
+ uint64_t retOffset = offset;
+ if (currentModulus != requiredModulus) {
+ if (requiredModulus > currentModulus)
+ retOffset += requiredModulus - currentModulus;
+ else
+ retOffset += alignment + requiredModulus - currentModulus;
+ }
+ return retOffset;
+}
+
+// \brief Append an atom to a Section. The atom gets pushed into a vector
+// contains the atom, the atom file offset, the atom virtual address
+// the atom file offset is aligned appropriately as set by the Reader
+template <class ELFT>
+const lld::AtomLayout *AtomSection<ELFT>::appendAtom(const Atom *atom) {
+ const DefinedAtom *definedAtom = cast<DefinedAtom>(atom);
+
+ DefinedAtom::Alignment atomAlign = definedAtom->alignment();
+ uint64_t alignment = 1u << atomAlign.powerOf2;
+ // Align the atom to the required modulus/ align the file offset and the
+ // memory offset separately this is required so that BSS symbols are handled
+ // properly as the BSS symbols only occupy memory size and not file size
+ uint64_t fOffset = alignOffset(this->fileSize(), atomAlign);
+ uint64_t mOffset = alignOffset(this->memSize(), atomAlign);
+ switch(definedAtom->contentType()) {
+ case DefinedAtom::typeCode:
+ case DefinedAtom::typeConstant:
+ case DefinedAtom::typeData:
+ case DefinedAtom::typeDataFast:
+ case DefinedAtom::typeZeroFillFast:
+ case DefinedAtom::typeGOT:
+ case DefinedAtom::typeStub:
+ case DefinedAtom::typeResolver:
+ case DefinedAtom::typeThreadData:
+ case DefinedAtom::typeRONote:
+ case DefinedAtom::typeRWNote:
+ _atoms.push_back(new (_alloc) lld::AtomLayout(atom, fOffset, 0));
+ this->_fsize = fOffset + definedAtom->size();
+ this->_msize = mOffset + definedAtom->size();
+ DEBUG_WITH_TYPE("Section",
+ llvm::dbgs() << "[" << this->name() << " " << this << "] "
+ << "Adding atom: " << atom->name() << "@"
+ << fOffset << "\n");
+ break;
+ case DefinedAtom::typeNoAlloc:
+ _atoms.push_back(new (_alloc) lld::AtomLayout(atom, fOffset, 0));
+ this->_fsize = fOffset + definedAtom->size();
+ DEBUG_WITH_TYPE("Section", llvm::dbgs() << "[" << this->name() << " "
+ << this << "] "
+ << "Adding atom: " << atom->name()
+ << "@" << fOffset << "\n");
+ break;
+ case DefinedAtom::typeThreadZeroFill:
+ case DefinedAtom::typeZeroFill:
+ _atoms.push_back(new (_alloc) lld::AtomLayout(atom, mOffset, 0));
+ this->_msize = mOffset + definedAtom->size();
+ break;
+ default:
+ llvm::dbgs() << definedAtom->contentType() << "\n";
+ llvm_unreachable("Uexpected content type.");
+ }
+ // Set the section alignment to the largest alignment
+ // std::max doesn't support uint64_t
+ if (this->_alignment < alignment)
+ this->_alignment = alignment;
+
+ if (_atoms.size())
+ return _atoms.back();
+ return nullptr;
+}
+
+/// \brief convert the segment type to a String for diagnostics
+/// and printing purposes
+template <class ELFT> StringRef Section<ELFT>::segmentKindToStr() const {
+ switch(_segmentType) {
+ case llvm::ELF::PT_DYNAMIC:
+ return "DYNAMIC";
+ case llvm::ELF::PT_INTERP:
+ return "INTERP";
+ case llvm::ELF::PT_LOAD:
+ return "LOAD";
+ case llvm::ELF::PT_GNU_EH_FRAME:
+ return "EH_FRAME";
+ case llvm::ELF::PT_GNU_RELRO:
+ return "GNU_RELRO";
+ case llvm::ELF::PT_NOTE:
+ return "NOTE";
+ case llvm::ELF::PT_NULL:
+ return "NULL";
+ case llvm::ELF::PT_TLS:
+ return "TLS";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+/// \brief Write the section and the atom contents to the buffer
+template <class ELFT>
+void AtomSection<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout,
+ llvm::FileOutputBuffer &buffer) {
+ uint8_t *chunkBuffer = buffer.getBufferStart();
+ bool success = true;
+ parallel_for_each(_atoms.begin(), _atoms.end(), [&](lld::AtomLayout * ai) {
+ DEBUG_WITH_TYPE("Section",
+ llvm::dbgs() << "Writing atom: " << ai->_atom->name()
+ << " | " << ai->_fileOffset << "\n");
+ const DefinedAtom *definedAtom = cast<DefinedAtom>(ai->_atom);
+ if (!definedAtom->occupiesDiskSpace())
+ return;
+ // Copy raw content of atom to file buffer.
+ ArrayRef<uint8_t> content = definedAtom->rawContent();
+ uint64_t contentSize = content.size();
+ if (contentSize == 0)
+ return;
+ uint8_t *atomContent = chunkBuffer + ai->_fileOffset;
+ std::memcpy(atomContent, content.data(), contentSize);
+ const TargetRelocationHandler &relHandler =
+ this->_context.template getTargetHandler<ELFT>().getRelocationHandler();
+ for (const auto ref : *definedAtom) {
+ if (std::error_code ec = relHandler.applyRelocation(*writer, buffer,
+ *ai, *ref)) {
+ printError(ec.message(), *ai, *ref);
+ success = false;
+ }
+ }
+ });
+ if (!success)
+ llvm::report_fatal_error("relocating output");
+}
+
+/// \brief A OutputSection represents a set of sections grouped by the same
+/// name. The output file that gets written by the linker has sections grouped
+/// by similar names
+template <class ELFT> class OutputSection {
+public:
+ // Iterators
+ typedef typename std::vector<Chunk<ELFT> *>::iterator ChunkIter;
+
+ OutputSection(StringRef name);
+
+ // Appends a section into the list of sections that are part of this Output
+ // Section
+ void appendSection(Chunk<ELFT> *c);
+
+ // Set the OutputSection is associated with a segment
+ void setHasSegment() { _hasSegment = true; }
+
+ /// Sets the ordinal
+ void setOrdinal(uint64_t ordinal) { _ordinal = ordinal; }
+
+ /// Sets the Memory size
+ void setMemSize(uint64_t memsz) { _memSize = memsz; }
+
+ /// Sets the size fo the output Section.
+ void setSize(uint64_t fsiz) { _size = fsiz; }
+
+ // The offset of the first section contained in the output section is
+ // contained here.
+ void setFileOffset(uint64_t foffset) { _fileOffset = foffset; }
+
+ // Sets the starting address of the section
+ void setAddr(uint64_t addr) { _virtualAddr = addr; }
+
+ // Is the section loadable?
+ bool isLoadableSection() const { return _isLoadableSection; }
+
+ // Set section Loadable
+ void setLoadableSection(bool isLoadable) {
+ _isLoadableSection = isLoadable;
+ }
+
+ void setLink(uint64_t link) { _link = link; }
+
+ void setInfo(uint64_t info) { _shInfo = info; }
+
+ void setFlag(uint64_t flags) { _flags = flags; }
+
+ void setType(int16_t type) { _type = type; }
+
+ range<ChunkIter> sections() { return _sections; }
+
+ // The below functions returns the properties of the OutputSection.
+ bool hasSegment() const { return _hasSegment; }
+
+ StringRef name() const { return _name; }
+
+ int64_t shinfo() const { return _shInfo; }
+
+ uint64_t alignment() const { return _alignment; }
+
+ int64_t link() const { return _link; }
+
+ int64_t type() const { return _type; }
+
+ uint64_t virtualAddr() const { return _virtualAddr; }
+
+ int64_t ordinal() const { return _ordinal; }
+
+ int64_t kind() const { return _kind; }
+
+ uint64_t fileSize() const { return _size; }
+
+ int64_t entsize() const { return _entSize; }
+
+ uint64_t fileOffset() const { return _fileOffset; }
+
+ int64_t flags() const { return _flags; }
+
+ uint64_t memSize() { return _memSize; }
+
+private:
+ StringRef _name;
+ bool _hasSegment;
+ uint64_t _ordinal;
+ uint64_t _flags;
+ uint64_t _size;
+ uint64_t _memSize;
+ uint64_t _fileOffset;
+ uint64_t _virtualAddr;
+ int64_t _shInfo;
+ int64_t _entSize;
+ int64_t _link;
+ uint64_t _alignment;
+ int64_t _kind;
+ int64_t _type;
+ bool _isLoadableSection;
+ std::vector<Chunk<ELFT> *> _sections;
+};
+
+/// OutputSection
+template <class ELFT>
+OutputSection<ELFT>::OutputSection(StringRef name)
+ : _name(name), _hasSegment(false), _ordinal(0), _flags(0), _size(0),
+ _memSize(0), _fileOffset(0), _virtualAddr(0), _shInfo(0), _entSize(0),
+ _link(0), _alignment(0), _kind(0), _type(0), _isLoadableSection(false) {}
+
+template <class ELFT> void OutputSection<ELFT>::appendSection(Chunk<ELFT> *c) {
+ if (c->alignment() > _alignment)
+ _alignment = c->alignment();
+ if (const auto section = dyn_cast<Section<ELFT>>(c)) {
+ assert(!_link && "Section already has a link!");
+ _link = section->getLink();
+ _shInfo = section->getInfo();
+ _entSize = section->getEntSize();
+ _type = section->getType();
+ if (_flags < section->getFlags())
+ _flags = section->getFlags();
+ section->setOutputSection(this, (_sections.size() == 0));
+ }
+ _kind = c->kind();
+ _sections.push_back(c);
+}
+
+/// \brief The class represents the ELF String Table
+template<class ELFT>
+class StringTable : public Section<ELFT> {
+public:
+ StringTable(const ELFLinkingContext &, const char *str, int32_t order,
+ bool dynamic = false);
+
+ uint64_t addString(StringRef symname);
+
+ void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
+ llvm::FileOutputBuffer &buffer) override;
+
+ void setNumEntries(int64_t numEntries) { _stringMap.resize(numEntries); }
+
+private:
+ std::vector<StringRef> _strings;
+
+ struct StringRefMappingInfo {
+ static StringRef getEmptyKey() { return StringRef(); }
+ static StringRef getTombstoneKey() { return StringRef(" ", 1); }
+ static unsigned getHashValue(StringRef const val) {
+ return llvm::HashString(val);
+ }
+ static bool isEqual(StringRef const lhs, StringRef const rhs) {
+ return lhs.equals(rhs);
+ }
+ };
+ typedef typename llvm::DenseMap<StringRef, uint64_t,
+ StringRefMappingInfo> StringMapT;
+ typedef typename StringMapT::iterator StringMapTIter;
+ StringMapT _stringMap;
+};
+
+template <class ELFT>
+StringTable<ELFT>::StringTable(const ELFLinkingContext &context,
+ const char *str, int32_t order, bool dynamic)
+ : Section<ELFT>(context, str, "StringTable") {
+ // the string table has a NULL entry for which
+ // add an empty string
+ _strings.push_back("");
+ this->_fsize = 1;
+ this->_alignment = 1;
+ this->setOrder(order);
+ this->_type = SHT_STRTAB;
+ if (dynamic) {
+ this->_flags = SHF_ALLOC;
+ this->_msize = this->_fsize;
+ }
+}
+
+template <class ELFT> uint64_t StringTable<ELFT>::addString(StringRef symname) {
+ if (symname.empty())
+ return 0;
+ StringMapTIter stringIter = _stringMap.find(symname);
+ if (stringIter == _stringMap.end()) {
+ _strings.push_back(symname);
+ uint64_t offset = this->_fsize;
+ this->_fsize += symname.size() + 1;
+ if (this->_flags & SHF_ALLOC)
+ this->_msize = this->_fsize;
+ _stringMap[symname] = offset;
+ return offset;
+ }
+ return stringIter->second;
+}
+
+template <class ELFT>
+void StringTable<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &,
+ llvm::FileOutputBuffer &buffer) {
+ uint8_t *chunkBuffer = buffer.getBufferStart();
+ uint8_t *dest = chunkBuffer + this->fileOffset();
+ for (auto si : _strings) {
+ memcpy(dest, si.data(), si.size());
+ dest += si.size();
+ memcpy(dest, "", 1);
+ dest += 1;
+ }
+}
+
+/// \brief The SymbolTable class represents the symbol table in a ELF file
+template<class ELFT>
+class SymbolTable : public Section<ELFT> {
+ typedef typename llvm::object::ELFDataTypeTypedefHelper<ELFT>::Elf_Addr
+ Elf_Addr;
+
+public:
+ typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+
+ SymbolTable(const ELFLinkingContext &context, const char *str, int32_t order);
+
+ /// \brief set the number of entries that would exist in the symbol
+ /// table for the current link
+ void setNumEntries(int64_t numEntries) const {
+ if (_stringSection)
+ _stringSection->setNumEntries(numEntries);
+ }
+
+ /// \brief return number of entries
+ std::size_t size() const { return _symbolTable.size(); }
+
+ void addSymbol(const Atom *atom, int32_t sectionIndex, uint64_t addr = 0,
+ const lld::AtomLayout *layout = nullptr);
+
+ /// \brief Get the symbol table index for an Atom. If it's not in the symbol
+ /// table, return STN_UNDEF.
+ uint32_t getSymbolTableIndex(const Atom *a) const {
+ for (size_t i = 0, e = _symbolTable.size(); i < e; ++i)
+ if (_symbolTable[i]._atom == a)
+ return i;
+ return STN_UNDEF;
+ }
+
+ void finalize() override { finalize(true); }
+
+ virtual void sortSymbols() {
+ std::stable_sort(_symbolTable.begin(), _symbolTable.end(),
+ [](const SymbolEntry & A, const SymbolEntry & B) {
+ return A._symbol.getBinding() < B._symbol.getBinding();
+ });
+ }
+
+ virtual void addAbsoluteAtom(Elf_Sym &sym, const AbsoluteAtom *aa,
+ int64_t addr);
+
+ virtual void addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da,
+ int64_t addr);
+
+ virtual void addUndefinedAtom(Elf_Sym &sym, const UndefinedAtom *ua);
+
+ virtual void addSharedLibAtom(Elf_Sym &sym, const SharedLibraryAtom *sla);
+
+ virtual void finalize(bool sort);
+
+ void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
+ llvm::FileOutputBuffer &buffer) override;
+
+ void setStringSection(StringTable<ELFT> *s) { _stringSection = s; }
+
+ StringTable<ELFT> *getStringTable() const { return _stringSection; }
+
+protected:
+ struct SymbolEntry {
+ SymbolEntry(const Atom *a, const Elf_Sym &sym,
+ const lld::AtomLayout *layout)
+ : _atom(a), _atomLayout(layout), _symbol(sym) {}
+
+ const Atom *_atom;
+ const lld::AtomLayout *_atomLayout;
+ Elf_Sym _symbol;
+ };
+
+ llvm::BumpPtrAllocator _symbolAllocate;
+ StringTable<ELFT> *_stringSection;
+ std::vector<SymbolEntry> _symbolTable;
+};
+
+/// ELF Symbol Table
+template <class ELFT>
+SymbolTable<ELFT>::SymbolTable(const ELFLinkingContext &context,
+ const char *str, int32_t order)
+ : Section<ELFT>(context, str, "SymbolTable") {
+ this->setOrder(order);
+ Elf_Sym symbol;
+ std::memset(&symbol, 0, sizeof(Elf_Sym));
+ _symbolTable.push_back(SymbolEntry(nullptr, symbol, nullptr));
+ this->_entSize = sizeof(Elf_Sym);
+ this->_fsize = sizeof(Elf_Sym);
+ this->_alignment = sizeof(Elf_Addr);
+ this->_type = SHT_SYMTAB;
+}
+
+template <class ELFT>
+void SymbolTable<ELFT>::addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da,
+ int64_t addr) {
+ unsigned char binding = 0, type = 0;
+ sym.st_size = da->size();
+ DefinedAtom::ContentType ct;
+ switch (ct = da->contentType()) {
+ case DefinedAtom::typeCode:
+ case DefinedAtom::typeStub:
+ sym.st_value = addr;
+ type = llvm::ELF::STT_FUNC;
+ break;
+ case DefinedAtom::typeResolver:
+ sym.st_value = addr;
+ type = llvm::ELF::STT_GNU_IFUNC;
+ break;
+ case DefinedAtom::typeDataFast:
+ case DefinedAtom::typeData:
+ case DefinedAtom::typeConstant:
+ sym.st_value = addr;
+ type = llvm::ELF::STT_OBJECT;
+ break;
+ case DefinedAtom::typeGOT:
+ sym.st_value = addr;
+ type = llvm::ELF::STT_NOTYPE;
+ break;
+ case DefinedAtom::typeZeroFill:
+ case DefinedAtom::typeZeroFillFast:
+ type = llvm::ELF::STT_OBJECT;
+ sym.st_value = addr;
+ break;
+ case DefinedAtom::typeThreadData:
+ case DefinedAtom::typeThreadZeroFill:
+ type = llvm::ELF::STT_TLS;
+ sym.st_value = addr;
+ break;
+ default:
+ type = llvm::ELF::STT_NOTYPE;
+ }
+ if (da->customSectionName() == da->name())
+ type = llvm::ELF::STT_SECTION;
+
+ if (da->scope() == DefinedAtom::scopeTranslationUnit)
+ binding = llvm::ELF::STB_LOCAL;
+ else
+ binding = llvm::ELF::STB_GLOBAL;
+
+ sym.setBindingAndType(binding, type);
+}
+
+template <class ELFT>
+void SymbolTable<ELFT>::addAbsoluteAtom(Elf_Sym &sym, const AbsoluteAtom *aa,
+ int64_t addr) {
+ unsigned char binding = 0, type = 0;
+ type = llvm::ELF::STT_OBJECT;
+ sym.st_shndx = llvm::ELF::SHN_ABS;
+ switch (aa->scope()) {
+ case AbsoluteAtom::scopeLinkageUnit:
+ sym.setVisibility(llvm::ELF::STV_HIDDEN);
+ binding = llvm::ELF::STB_LOCAL;
+ break;
+ case AbsoluteAtom::scopeTranslationUnit:
+ binding = llvm::ELF::STB_LOCAL;
+ break;
+ case AbsoluteAtom::scopeGlobal:
+ binding = llvm::ELF::STB_GLOBAL;
+ break;
+ }
+ sym.st_value = addr;
+ sym.setBindingAndType(binding, type);
+}
+
+template <class ELFT>
+void SymbolTable<ELFT>::addSharedLibAtom(Elf_Sym &sym,
+ const SharedLibraryAtom *aa) {
+ unsigned char binding = 0, type = 0;
+ if (aa->type() == SharedLibraryAtom::Type::Data) {
+ type = llvm::ELF::STT_OBJECT;
+ sym.st_size = aa->size();
+ } else
+ type = llvm::ELF::STT_FUNC;
+ sym.st_shndx = llvm::ELF::SHN_UNDEF;
+ binding = llvm::ELF::STB_GLOBAL;
+ sym.setBindingAndType(binding, type);
+}
+
+template <class ELFT>
+void SymbolTable<ELFT>::addUndefinedAtom(Elf_Sym &sym,
+ const UndefinedAtom *ua) {
+ unsigned char binding = 0, type = 0;
+ sym.st_value = 0;
+ type = llvm::ELF::STT_NOTYPE;
+ if (ua->canBeNull())
+ binding = llvm::ELF::STB_WEAK;
+ else
+ binding = llvm::ELF::STB_GLOBAL;
+ sym.setBindingAndType(binding, type);
+}
+
+/// Add a symbol to the symbol Table, definedAtoms which get added to the symbol
+/// section don't have their virtual addresses set at the time of adding the
+/// symbol to the symbol table(Example: dynamic symbols), the addresses needs
+/// to be updated in the table before writing the dynamic symbol table
+/// information
+template <class ELFT>
+void SymbolTable<ELFT>::addSymbol(const Atom *atom, int32_t sectionIndex,
+ uint64_t addr,
+ const lld::AtomLayout *atomLayout) {
+ Elf_Sym symbol;
+
+ if (atom->name().empty())
+ return;
+
+ symbol.st_name = _stringSection->addString(atom->name());
+ symbol.st_size = 0;
+ symbol.st_shndx = sectionIndex;
+ symbol.st_value = 0;
+ symbol.st_other = 0;
+ symbol.setVisibility(llvm::ELF::STV_DEFAULT);
+
+ // Add all the atoms
+ if (const DefinedAtom *da = dyn_cast<const DefinedAtom>(atom))
+ addDefinedAtom(symbol, da, addr);
+ else if (const AbsoluteAtom *aa = dyn_cast<const AbsoluteAtom>(atom))
+ addAbsoluteAtom(symbol, aa, addr);
+ else if (isa<const SharedLibraryAtom>(atom))
+ addSharedLibAtom(symbol, dyn_cast<SharedLibraryAtom>(atom));
+ else
+ addUndefinedAtom(symbol, dyn_cast<UndefinedAtom>(atom));
+
+ _symbolTable.push_back(SymbolEntry(atom, symbol, atomLayout));
+ this->_fsize += sizeof(Elf_Sym);
+ if (this->_flags & SHF_ALLOC)
+ this->_msize = this->_fsize;
+}
+
+template <class ELFT> void SymbolTable<ELFT>::finalize(bool sort) {
+ // sh_info should be one greater than last symbol with STB_LOCAL binding
+ // we sort the symbol table to keep all local symbols at the beginning
+ if (sort)
+ sortSymbols();
+
+ uint16_t shInfo = 0;
+ for (const auto &i : _symbolTable) {
+ if (i._symbol.getBinding() != llvm::ELF::STB_LOCAL)
+ break;
+ shInfo++;
+ }
+ this->_info = shInfo;
+ this->_link = _stringSection->ordinal();
+ if (this->_outputSection) {
+ this->_outputSection->setInfo(this->_info);
+ this->_outputSection->setLink(this->_link);
+ }
+}
+
+template <class ELFT>
+void SymbolTable<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &,
+ llvm::FileOutputBuffer &buffer) {
+ uint8_t *chunkBuffer = buffer.getBufferStart();
+ uint8_t *dest = chunkBuffer + this->fileOffset();
+ for (const auto &sti : _symbolTable) {
+ memcpy(dest, &sti._symbol, sizeof(Elf_Sym));
+ dest += sizeof(Elf_Sym);
+ }
+}
+
+template <class ELFT> class HashSection;
+
+template <class ELFT> class DynamicSymbolTable : public SymbolTable<ELFT> {
+public:
+ DynamicSymbolTable(const ELFLinkingContext &context,
+ TargetLayout<ELFT> &layout, const char *str, int32_t order)
+ : SymbolTable<ELFT>(context, str, order), _hashTable(nullptr),
+ _layout(layout) {
+ this->_type = SHT_DYNSYM;
+ this->_flags = SHF_ALLOC;
+ this->_msize = this->_fsize;
+ }
+
+ // Set the dynamic hash table for symbols to be added into
+ void setHashTable(HashSection<ELFT> *hashTable) { _hashTable = hashTable; }
+
+ // Add all the dynamic symbos to the hash table
+ void addSymbolsToHashTable() {
+ int index = 0;
+ for (auto &ste : this->_symbolTable) {
+ if (!ste._atom)
+ _hashTable->addSymbol("", index);
+ else
+ _hashTable->addSymbol(ste._atom->name(), index);
+ ++index;
+ }
+ }
+
+ void finalize() override {
+ // Defined symbols which have been added into the dynamic symbol table
+ // don't have their addresses known until addresses have been assigned
+ // so let's update the symbol values after they have got assigned
+ for (auto &ste: this->_symbolTable) {
+ const lld::AtomLayout *atomLayout = ste._atomLayout;
+ if (!atomLayout)
+ continue;
+ ste._symbol.st_value = atomLayout->_virtualAddr;
+ }
+
+ // Don't sort the symbols
+ SymbolTable<ELFT>::finalize(false);
+ }
+
+protected:
+ HashSection<ELFT> *_hashTable;
+ TargetLayout<ELFT> &_layout;
+};
+
+template <class ELFT> class RelocationTable : public Section<ELFT> {
+public:
+ typedef llvm::object::Elf_Rel_Impl<ELFT, false> Elf_Rel;
+ typedef llvm::object::Elf_Rel_Impl<ELFT, true> Elf_Rela;
+
+ RelocationTable(const ELFLinkingContext &context, StringRef str,
+ int32_t order)
+ : Section<ELFT>(context, str, "RelocationTable"), _symbolTable(nullptr) {
+ this->setOrder(order);
+ this->_flags = SHF_ALLOC;
+ // Set the alignment properly depending on the target architecture
+ this->_alignment = ELFT::Is64Bits ? 8 : 4;
+ if (context.isRelaOutputFormat()) {
+ this->_entSize = sizeof(Elf_Rela);
+ this->_type = SHT_RELA;
+ } else {
+ this->_entSize = sizeof(Elf_Rel);
+ this->_type = SHT_REL;
+ }
+ }
+
+ /// \returns the index of the relocation added.
+ uint32_t addRelocation(const DefinedAtom &da, const Reference &r) {
+ _relocs.emplace_back(&da, &r);
+ this->_fsize = _relocs.size() * this->_entSize;
+ this->_msize = this->_fsize;
+ return _relocs.size() - 1;
+ }
+
+ bool getRelocationIndex(const Reference &r, uint32_t &res) {
+ auto rel = std::find_if(
+ _relocs.begin(), _relocs.end(),
+ [&](const std::pair<const DefinedAtom *, const Reference *> &p) {
+ if (p.second == &r)
+ return true;
+ return false;
+ });
+ if (rel == _relocs.end())
+ return false;
+ res = std::distance(_relocs.begin(), rel);
+ return true;
+ }
+
+ void setSymbolTable(const DynamicSymbolTable<ELFT> *symbolTable) {
+ _symbolTable = symbolTable;
+ }
+
+ /// \brief Check if any relocation modifies a read-only section.
+ bool canModifyReadonlySection() const {
+ for (const auto &rel : _relocs) {
+ const DefinedAtom *atom = rel.first;
+ if ((atom->permissions() & DefinedAtom::permRW_) != DefinedAtom::permRW_)
+ return true;
+ }
+ return false;
+ }
+
+ void finalize() override {
+ this->_link = _symbolTable ? _symbolTable->ordinal() : 0;
+ if (this->_outputSection)
+ this->_outputSection->setLink(this->_link);
+ }
+
+ void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
+ llvm::FileOutputBuffer &buffer) override {
+ uint8_t *chunkBuffer = buffer.getBufferStart();
+ uint8_t *dest = chunkBuffer + this->fileOffset();
+ for (const auto &rel : _relocs) {
+ if (this->_context.isRelaOutputFormat()) {
+ auto &r = *reinterpret_cast<Elf_Rela *>(dest);
+ writeRela(writer, r, *rel.first, *rel.second);
+ DEBUG_WITH_TYPE("ELFRelocationTable",
+ llvm::dbgs()
+ << rel.second->kindValue() << " relocation at "
+ << rel.first->name() << "@" << r.r_offset << " to "
+ << rel.second->target()->name() << "@" << r.r_addend
+ << "\n";);
+ } else {
+ auto &r = *reinterpret_cast<Elf_Rel *>(dest);
+ writeRel(writer, r, *rel.first, *rel.second);
+ DEBUG_WITH_TYPE("ELFRelocationTable",
+ llvm::dbgs() << rel.second->kindValue()
+ << " relocation at " << rel.first->name()
+ << "@" << r.r_offset << " to "
+ << rel.second->target()->name() << "\n";);
+ }
+ dest += this->_entSize;
+ }
+ }
+
+protected:
+ const DynamicSymbolTable<ELFT> *_symbolTable;
+
+ virtual void writeRela(ELFWriter *writer, Elf_Rela &r,
+ const DefinedAtom &atom, const Reference &ref) {
+ r.setSymbolAndType(getSymbolIndex(ref.target()), ref.kindValue(), false);
+ r.r_offset = writer->addressOfAtom(&atom) + ref.offsetInAtom();
+ // The addend is used only by relative relocations
+ if (this->_context.isRelativeReloc(ref))
+ r.r_addend = writer->addressOfAtom(ref.target()) + ref.addend();
+ else
+ r.r_addend = 0;
+ }
+
+ virtual void writeRel(ELFWriter *writer, Elf_Rel &r, const DefinedAtom &atom,
+ const Reference &ref) {
+ r.setSymbolAndType(getSymbolIndex(ref.target()), ref.kindValue(), false);
+ r.r_offset = writer->addressOfAtom(&atom) + ref.offsetInAtom();
+ }
+
+ uint32_t getSymbolIndex(const Atom *a) {
+ return _symbolTable ? _symbolTable->getSymbolTableIndex(a)
+ : (uint32_t)STN_UNDEF;
+ }
+
+private:
+ std::vector<std::pair<const DefinedAtom *, const Reference *> > _relocs;
+};
+
+template <class ELFT> class HashSection;
+
+template <class ELFT> class DynamicTable : public Section<ELFT> {
+public:
+ typedef llvm::object::Elf_Dyn_Impl<ELFT> Elf_Dyn;
+ typedef std::vector<Elf_Dyn> EntriesT;
+
+ DynamicTable(const ELFLinkingContext &context, TargetLayout<ELFT> &layout,
+ StringRef str, int32_t order)
+ : Section<ELFT>(context, str, "DynamicSection"), _layout(layout) {
+ this->setOrder(order);
+ this->_entSize = sizeof(Elf_Dyn);
+ this->_alignment = ELFT::Is64Bits ? 8 : 4;
+ // Reserve space for the DT_NULL entry.
+ this->_fsize = sizeof(Elf_Dyn);
+ this->_msize = sizeof(Elf_Dyn);
+ this->_type = SHT_DYNAMIC;
+ this->_flags = SHF_ALLOC;
+ }
+
+ range<typename EntriesT::iterator> entries() { return _entries; }
+
+ /// \returns the index of the entry.
+ std::size_t addEntry(Elf_Dyn e) {
+ _entries.push_back(e);
+ this->_fsize = (_entries.size() * sizeof(Elf_Dyn)) + sizeof(Elf_Dyn);
+ this->_msize = this->_fsize;
+ return _entries.size() - 1;
+ }
+
+ void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
+ llvm::FileOutputBuffer &buffer) override {
+ uint8_t *chunkBuffer = buffer.getBufferStart();
+ uint8_t *dest = chunkBuffer + this->fileOffset();
+ // Add the null entry.
+ Elf_Dyn d;
+ d.d_tag = 0;
+ d.d_un.d_val = 0;
+ _entries.push_back(d);
+ std::memcpy(dest, _entries.data(), this->_fsize);
+ }
+
+ virtual void createDefaultEntries() {
+ bool isRela = this->_context.isRelaOutputFormat();
+
+ Elf_Dyn dyn;
+ dyn.d_un.d_val = 0;
+
+ dyn.d_tag = DT_HASH;
+ _dt_hash = addEntry(dyn);
+ dyn.d_tag = DT_STRTAB;
+ _dt_strtab = addEntry(dyn);
+ dyn.d_tag = DT_SYMTAB;
+ _dt_symtab = addEntry(dyn);
+ dyn.d_tag = DT_STRSZ;
+ _dt_strsz = addEntry(dyn);
+ dyn.d_tag = DT_SYMENT;
+ _dt_syment = addEntry(dyn);
+ if (_layout.hasDynamicRelocationTable()) {
+ dyn.d_tag = isRela ? DT_RELA : DT_REL;
+ _dt_rela = addEntry(dyn);
+ dyn.d_tag = isRela ? DT_RELASZ : DT_RELSZ;
+ _dt_relasz = addEntry(dyn);
+ dyn.d_tag = isRela ? DT_RELAENT : DT_RELENT;
+ _dt_relaent = addEntry(dyn);
+
+ if (_layout.getDynamicRelocationTable()->canModifyReadonlySection()) {
+ dyn.d_tag = DT_TEXTREL;
+ _dt_textrel = addEntry(dyn);
+ }
+ }
+ if (_layout.hasPLTRelocationTable()) {
+ dyn.d_tag = DT_PLTRELSZ;
+ _dt_pltrelsz = addEntry(dyn);
+ dyn.d_tag = getGotPltTag();
+ _dt_pltgot = addEntry(dyn);
+ dyn.d_tag = DT_PLTREL;
+ dyn.d_un.d_val = isRela ? DT_RELA : DT_REL;
+ _dt_pltrel = addEntry(dyn);
+ dyn.d_un.d_val = 0;
+ dyn.d_tag = DT_JMPREL;
+ _dt_jmprel = addEntry(dyn);
+ }
+ }
+
+ void doPreFlight() override {
+ Elf_Dyn dyn;
+ dyn.d_un.d_val = 0;
+ auto initArray = _layout.findOutputSection(".init_array");
+ auto finiArray = _layout.findOutputSection(".fini_array");
+ if (initArray) {
+ dyn.d_tag = DT_INIT_ARRAY;
+ _dt_init_array = addEntry(dyn);
+ dyn.d_tag = DT_INIT_ARRAYSZ;
+ _dt_init_arraysz = addEntry(dyn);
+ }
+ if (finiArray) {
+ dyn.d_tag = DT_FINI_ARRAY;
+ _dt_fini_array = addEntry(dyn);
+ dyn.d_tag = DT_FINI_ARRAYSZ;
+ _dt_fini_arraysz = addEntry(dyn);
+ }
+ if (getInitAtomLayout()) {
+ dyn.d_tag = DT_INIT;
+ _dt_init = addEntry(dyn);
+ }
+ if (getFiniAtomLayout()) {
+ dyn.d_tag = DT_FINI;
+ _dt_fini = addEntry(dyn);
+ }
+ }
+
+ /// \brief Dynamic table tag for .got.plt section referencing.
+ /// Usually but not always targets use DT_PLTGOT for that.
+ virtual int64_t getGotPltTag() { return DT_PLTGOT; }
+
+ void finalize() override {
+ StringTable<ELFT> *dynamicStringTable =
+ _dynamicSymbolTable->getStringTable();
+ this->_link = dynamicStringTable->ordinal();
+ if (this->_outputSection) {
+ this->_outputSection->setType(this->_type);
+ this->_outputSection->setInfo(this->_info);
+ this->_outputSection->setLink(this->_link);
+ }
+ }
+
+ void setSymbolTable(DynamicSymbolTable<ELFT> *dynsym) {
+ _dynamicSymbolTable = dynsym;
+ }
+
+ const DynamicSymbolTable<ELFT> *getSymbolTable() const {
+ return _dynamicSymbolTable;
+ }
+
+ void setHashTable(HashSection<ELFT> *hsh) { _hashTable = hsh; }
+
+ virtual void updateDynamicTable() {
+ StringTable<ELFT> *dynamicStringTable =
+ _dynamicSymbolTable->getStringTable();
+ _entries[_dt_hash].d_un.d_val = _hashTable->virtualAddr();
+ _entries[_dt_strtab].d_un.d_val = dynamicStringTable->virtualAddr();
+ _entries[_dt_symtab].d_un.d_val = _dynamicSymbolTable->virtualAddr();
+ _entries[_dt_strsz].d_un.d_val = dynamicStringTable->memSize();
+ _entries[_dt_syment].d_un.d_val = _dynamicSymbolTable->getEntSize();
+ auto initArray = _layout.findOutputSection(".init_array");
+ if (initArray) {
+ _entries[_dt_init_array].d_un.d_val = initArray->virtualAddr();
+ _entries[_dt_init_arraysz].d_un.d_val = initArray->memSize();
+ }
+ auto finiArray = _layout.findOutputSection(".fini_array");
+ if (finiArray) {
+ _entries[_dt_fini_array].d_un.d_val = finiArray->virtualAddr();
+ _entries[_dt_fini_arraysz].d_un.d_val = finiArray->memSize();
+ }
+ if (const auto *al = getInitAtomLayout())
+ _entries[_dt_init].d_un.d_val = getAtomVirtualAddress(al);
+ if (const auto *al = getFiniAtomLayout())
+ _entries[_dt_fini].d_un.d_val = getAtomVirtualAddress(al);
+ if (_layout.hasDynamicRelocationTable()) {
+ auto relaTbl = _layout.getDynamicRelocationTable();
+ _entries[_dt_rela].d_un.d_val = relaTbl->virtualAddr();
+ _entries[_dt_relasz].d_un.d_val = relaTbl->memSize();
+ _entries[_dt_relaent].d_un.d_val = relaTbl->getEntSize();
+ }
+ if (_layout.hasPLTRelocationTable()) {
+ auto relaTbl = _layout.getPLTRelocationTable();
+ _entries[_dt_jmprel].d_un.d_val = relaTbl->virtualAddr();
+ _entries[_dt_pltrelsz].d_un.d_val = relaTbl->memSize();
+ auto gotplt = _layout.findOutputSection(".got.plt");
+ _entries[_dt_pltgot].d_un.d_val = gotplt->virtualAddr();
+ }
+ }
+
+protected:
+ EntriesT _entries;
+
+ /// \brief Return a virtual address (maybe adjusted) for the atom layout
+ /// Some targets like microMIPS and ARM Thumb use the last bit
+ /// of a symbol's value to mark 'compressed' code. This function allows
+ /// to adjust a virtal address before using it in the dynamic table tag.
+ virtual uint64_t getAtomVirtualAddress(const AtomLayout *al) const {
+ return al->_virtualAddr;
+ }
+
+private:
+ std::size_t _dt_hash;
+ std::size_t _dt_strtab;
+ std::size_t _dt_symtab;
+ std::size_t _dt_rela;
+ std::size_t _dt_relasz;
+ std::size_t _dt_relaent;
+ std::size_t _dt_strsz;
+ std::size_t _dt_syment;
+ std::size_t _dt_pltrelsz;
+ std::size_t _dt_pltgot;
+ std::size_t _dt_pltrel;
+ std::size_t _dt_jmprel;
+ std::size_t _dt_init_array;
+ std::size_t _dt_init_arraysz;
+ std::size_t _dt_fini_array;
+ std::size_t _dt_fini_arraysz;
+ std::size_t _dt_textrel;
+ std::size_t _dt_init;
+ std::size_t _dt_fini;
+ TargetLayout<ELFT> &_layout;
+ DynamicSymbolTable<ELFT> *_dynamicSymbolTable;
+ HashSection<ELFT> *_hashTable;
+
+ const AtomLayout *getInitAtomLayout() {
+ auto al = _layout.findAtomLayoutByName(this->_context.initFunction());
+ if (al && isa<DefinedAtom>(al->_atom))
+ return al;
+ return nullptr;
+ }
+
+ const AtomLayout *getFiniAtomLayout() {
+ auto al = _layout.findAtomLayoutByName(this->_context.finiFunction());
+ if (al && isa<DefinedAtom>(al->_atom))
+ return al;
+ return nullptr;
+ }
+};
+
+template <class ELFT> class InterpSection : public Section<ELFT> {
+public:
+ InterpSection(const ELFLinkingContext &context, StringRef str, int32_t order,
+ StringRef interp)
+ : Section<ELFT>(context, str, "Dynamic:Interp"), _interp(interp) {
+ this->setOrder(order);
+ this->_alignment = 1;
+ // + 1 for null term.
+ this->_fsize = interp.size() + 1;
+ this->_msize = this->_fsize;
+ this->_type = SHT_PROGBITS;
+ this->_flags = SHF_ALLOC;
+ }
+
+ void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
+ llvm::FileOutputBuffer &buffer) {
+ uint8_t *chunkBuffer = buffer.getBufferStart();
+ uint8_t *dest = chunkBuffer + this->fileOffset();
+ std::memcpy(dest, _interp.data(), _interp.size());
+ }
+
+private:
+ StringRef _interp;
+};
+
+/// The hash table in the dynamic linker is organized into
+///
+/// [ nbuckets ]
+/// [ nchains ]
+/// [ buckets[0] ]
+/// .........................
+/// [ buckets[nbuckets-1] ]
+/// [ chains[0] ]
+/// .........................
+/// [ chains[nchains - 1] ]
+///
+/// nbuckets - total number of hash buckets
+/// nchains is equal to the number of dynamic symbols.
+///
+/// The symbol is searched by the dynamic linker using the below approach.
+/// * Calculate the hash of the symbol that needs to be searched
+/// * Take the value from the buckets[hash % nbuckets] as the index of symbol
+/// * Compare the symbol's name, if true return, if false, look through the
+/// * array since there was a collision
+
+template <class ELFT> class HashSection : public Section<ELFT> {
+ struct SymbolTableEntry {
+ StringRef _name;
+ uint32_t _index;
+ };
+
+public:
+ HashSection(const ELFLinkingContext &context, StringRef name, int32_t order)
+ : Section<ELFT>(context, name, "Dynamic:Hash"), _symbolTable(nullptr) {
+ this->setOrder(order);
+ this->_entSize = 4;
+ this->_type = SHT_HASH;
+ this->_flags = SHF_ALLOC;
+ this->_alignment = ELFT::Is64Bits ? 8 : 4;
+ this->_fsize = 0;
+ this->_msize = 0;
+ }
+
+ /// \brief add the dynamic symbol into the table so that the
+ /// hash could be calculated
+ void addSymbol(StringRef name, uint32_t index) {
+ SymbolTableEntry ste;
+ ste._name = name;
+ ste._index = index;
+ _entries.push_back(ste);
+ }
+
+ /// \brief Set the dynamic symbol table
+ void setSymbolTable(const DynamicSymbolTable<ELFT> *symbolTable) {
+ _symbolTable = symbolTable;
+ }
+
+ // The size of the section has to be determined so that fileoffsets
+ // may be properly assigned. Let's calculate the buckets and the chains
+ // and fill the chains and the buckets hash table used by the dynamic
+ // linker and update the filesize and memory size accordingly
+ void doPreFlight() override {
+ // The number of buckets to use for a certain number of symbols.
+ // If there are less than 3 symbols, 1 bucket will be used. If
+ // there are less than 17 symbols, 3 buckets will be used, and so
+ // forth. The bucket numbers are defined by GNU ld. We use the
+ // same rules here so we generate hash sections with the same
+ // size as those generated by GNU ld.
+ uint32_t hashBuckets[] = { 1, 3, 17, 37, 67, 97, 131, 197, 263, 521, 1031,
+ 2053, 4099, 8209, 16411, 32771, 65537, 131101,
+ 262147 };
+ int hashBucketsCount = sizeof(hashBuckets) / sizeof(uint32_t);
+
+ unsigned int bucketsCount = 0;
+ unsigned int dynSymCount = _entries.size();
+
+ // Get the number of buckes that we want to use
+ for (int i = 0; i < hashBucketsCount; ++i) {
+ if (dynSymCount < hashBuckets[i])
+ break;
+ bucketsCount = hashBuckets[i];
+ }
+ _buckets.resize(bucketsCount);
+ _chains.resize(_entries.size());
+
+ // Create the hash table for the dynamic linker
+ for (auto ai : _entries) {
+ unsigned int dynsymIndex = ai._index;
+ unsigned int bucketpos = llvm::object::elf_hash(ai._name) % bucketsCount;
+ _chains[dynsymIndex] = _buckets[bucketpos];
+ _buckets[bucketpos] = dynsymIndex;
+ }
+
+ this->_fsize = (2 + _chains.size() + _buckets.size()) * sizeof(uint32_t);
+ this->_msize = this->_fsize;
+ }
+
+ void finalize() override {
+ this->_link = _symbolTable ? _symbolTable->ordinal() : 0;
+ if (this->_outputSection)
+ this->_outputSection->setLink(this->_link);
+ }
+
+ void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
+ llvm::FileOutputBuffer &buffer) override {
+ uint8_t *chunkBuffer = buffer.getBufferStart();
+ uint8_t *dest = chunkBuffer + this->fileOffset();
+ uint32_t bucketChainCounts[2];
+ bucketChainCounts[0] = _buckets.size();
+ bucketChainCounts[1] = _chains.size();
+ std::memcpy(dest, (char *)bucketChainCounts, sizeof(bucketChainCounts));
+ dest += sizeof(bucketChainCounts);
+ // write bucket values
+ for (auto bi : _buckets) {
+ uint32_t val = (bi);
+ std::memcpy(dest, &val, sizeof(uint32_t));
+ dest += sizeof(uint32_t);
+ }
+ // write chain values
+ for (auto ci : _chains) {
+ uint32_t val = (ci);
+ std::memcpy(dest, &val, sizeof(uint32_t));
+ dest += sizeof(uint32_t);
+ }
+ }
+
+private:
+ std::vector<SymbolTableEntry> _entries;
+ std::vector<uint32_t> _buckets;
+ std::vector<uint32_t> _chains;
+ const DynamicSymbolTable<ELFT> *_symbolTable;
+};
+
+template <class ELFT> class EHFrameHeader : public Section<ELFT> {
+public:
+ EHFrameHeader(const ELFLinkingContext &context, StringRef name,
+ TargetLayout<ELFT> &layout, int32_t order)
+ : Section<ELFT>(context, name, "EHFrameHeader"), _ehFrameOffset(0),
+ _layout(layout) {
+ this->setOrder(order);
+ this->_entSize = 0;
+ this->_type = SHT_PROGBITS;
+ this->_flags = SHF_ALLOC;
+ this->_alignment = ELFT::Is64Bits ? 8 : 4;
+ // Minimum size for empty .eh_frame_hdr.
+ this->_fsize = 1 + 1 + 1 + 1 + 4;
+ this->_msize = this->_fsize;
+ }
+
+ void doPreFlight() override {
+ // TODO: Generate a proper binary search table.
+ }
+
+ void finalize() override {
+ OutputSection<ELFT> *s = _layout.findOutputSection(".eh_frame");
+ OutputSection<ELFT> *h = _layout.findOutputSection(".eh_frame_hdr");
+ if (s && h)
+ _ehFrameOffset = s->virtualAddr() - (h->virtualAddr() + 4);
+ }
+
+ void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
+ llvm::FileOutputBuffer &buffer) override {
+ uint8_t *chunkBuffer = buffer.getBufferStart();
+ uint8_t *dest = chunkBuffer + this->fileOffset();
+ int pos = 0;
+ dest[pos++] = 1; // version
+ dest[pos++] = llvm::dwarf::DW_EH_PE_pcrel |
+ llvm::dwarf::DW_EH_PE_sdata4; // eh_frame_ptr_enc
+ dest[pos++] = llvm::dwarf::DW_EH_PE_omit; // fde_count_enc
+ dest[pos++] = llvm::dwarf::DW_EH_PE_omit; // table_enc
+ *reinterpret_cast<typename llvm::object::ELFFile<ELFT>::Elf_Sword *>(
+ dest + pos) = _ehFrameOffset;
+ }
+
+private:
+ int32_t _ehFrameOffset;
+ TargetLayout<ELFT> &_layout;
+};
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/SegmentChunks.h b/lib/ReaderWriter/ELF/SegmentChunks.h
new file mode 100644
index 0000000000000..f2a975aaeed0b
--- /dev/null
+++ b/lib/ReaderWriter/ELF/SegmentChunks.h
@@ -0,0 +1,686 @@
+//===- lib/ReaderWriter/ELF/SegmentChunks.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_SEGMENT_CHUNKS_H
+#define LLD_READER_WRITER_ELF_SEGMENT_CHUNKS_H
+
+#include "Chunk.h"
+#include "Layout.h"
+#include "SectionChunks.h"
+#include "Writer.h"
+#include "lld/Core/range.h"
+#include "lld/Core/Writer.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ELF.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include <memory>
+
+namespace lld {
+namespace elf {
+
+template <typename ELFT> class DefaultLayout;
+
+/// \brief A segment can be divided into segment slices
+/// depending on how the segments can be split
+template<class ELFT>
+class SegmentSlice {
+public:
+ typedef typename std::vector<Chunk<ELFT> *>::iterator SectionIter;
+
+ SegmentSlice() { }
+
+ /// Set the start of the slice.
+ void setStart(int32_t s) { _startSection = s; }
+
+ // Set the segment slice start and end iterators. This is used to walk through
+ // the sections that are part of the Segment slice
+ void setSections(range<SectionIter> sections) { _sections = sections; }
+
+ // Return the fileOffset of the slice
+ uint64_t fileOffset() const { return _offset; }
+
+ void setFileOffset(uint64_t offset) { _offset = offset; }
+
+ // Return the size of the slice
+ uint64_t fileSize() const { return _fsize; }
+
+ void setFileSize(uint64_t filesz) { _fsize = filesz; }
+
+ // Return the start of the slice
+ int32_t startSection() const { return _startSection; }
+
+ // Return the start address of the slice
+ uint64_t virtualAddr() const { return _addr; }
+
+ // Return the memory size of the slice
+ uint64_t memSize() const { return _memSize; }
+
+ // Return the alignment of the slice
+ uint64_t alignment() const { return _alignment; }
+
+ void setMemSize(uint64_t memsz) { _memSize = memsz; }
+
+ void setVirtualAddr(uint64_t addr) { _addr = addr; }
+
+ void setAlign(uint64_t align) { _alignment = align; }
+
+ static bool compare_slices(SegmentSlice<ELFT> *a, SegmentSlice<ELFT> *b) {
+ return a->startSection() < b->startSection();
+ }
+
+ range<SectionIter> sections() { return _sections; }
+
+private:
+ range<SectionIter> _sections;
+ int32_t _startSection;
+ uint64_t _addr;
+ uint64_t _offset;
+ uint64_t _alignment;
+ uint64_t _fsize;
+ uint64_t _memSize;
+};
+
+/// \brief A segment contains a set of sections, that have similar properties
+// the sections are already separated based on different flags and properties
+// the segment is just a way to concatenate sections to segments
+template<class ELFT>
+class Segment : public Chunk<ELFT> {
+public:
+ typedef typename std::vector<SegmentSlice<ELFT> *>::iterator SliceIter;
+ typedef typename std::vector<Chunk<ELFT> *>::iterator SectionIter;
+
+ Segment(const ELFLinkingContext &context, StringRef name,
+ const Layout::SegmentType type);
+
+ /// \brief the Order of segments that appear in the output file
+ enum SegmentOrder {
+ permUnknown,
+ permRWX,
+ permRX,
+ permR,
+ permRWL,
+ permRW,
+ permNonAccess
+ };
+
+ /// append a section to a segment
+ virtual void append(Chunk<ELFT> *chunk);
+
+ /// Sort segments depending on the property
+ /// If we have a Program Header segment, it should appear first
+ /// If we have a INTERP segment, that should appear after the Program Header
+ /// All Loadable segments appear next in this order
+ /// All Read Write Execute segments follow
+ /// All Read Execute segments appear next
+ /// All Read only segments appear first
+ /// All Write execute segments follow
+ static bool compareSegments(Segment<ELFT> *sega, Segment<ELFT> *segb);
+
+ /// \brief Start assigning file offset to the segment chunks The fileoffset
+ /// needs to be page at the start of the segment and in addition the
+ /// fileoffset needs to be aligned to the max section alignment within the
+ /// segment. This is required so that the ELF property p_poffset % p_align =
+ /// p_vaddr mod p_align holds true.
+ /// The algorithm starts off by assigning the startOffset thats passed in as
+ /// parameter to the first section in the segment, if the difference between
+ /// the newly computed offset is greater than a page, then we create a segment
+ /// slice, as it would be a waste of virtual memory just to be filled with
+ /// zeroes
+ void assignFileOffsets(uint64_t startOffset);
+
+ /// \brief Assign virtual addresses to the slices
+ void assignVirtualAddress(uint64_t addr);
+
+ // Write the Segment
+ void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
+ llvm::FileOutputBuffer &buffer);
+
+ int64_t flags() const;
+
+ /// Prepend a generic chunk to the segment.
+ void prepend(Chunk<ELFT> *c) {
+ _sections.insert(_sections.begin(), c);
+ }
+
+ /// Finalize the segment before assigning File Offsets / Virtual addresses
+ void doPreFlight() {}
+
+ /// Finalize the segment, before we want to write the segment header
+ /// information
+ void finalize() {
+ // We want to finalize the segment values for now only for non loadable
+ // segments, since those values are not set in the Layout
+ if (_segmentType == llvm::ELF::PT_LOAD)
+ return;
+ // The size is the difference of the
+ // last section to the first section, especially for TLS because
+ // the TLS segment contains both .tdata/.tbss
+ this->setFileOffset(_sections.front()->fileOffset());
+ this->setVirtualAddr(_sections.front()->virtualAddr());
+ size_t startFileOffset = _sections.front()->fileOffset();
+ size_t startAddr = _sections.front()->virtualAddr();
+ for (auto ai : _sections) {
+ this->_fsize = ai->fileOffset() + ai->fileSize() - startFileOffset;
+ this->_msize = ai->virtualAddr() + ai->memSize() - startAddr;
+ }
+ }
+
+ // For LLVM RTTI
+ static bool classof(const Chunk<ELFT> *c) {
+ return c->kind() == Chunk<ELFT>::Kind::ELFSegment;
+ }
+
+ // Getters
+ int32_t sectionCount() const { return _sections.size(); }
+
+ /// \brief, this function returns the type of segment (PT_*)
+ Layout::SegmentType segmentType() { return _segmentType; }
+
+ /// \brief return the segment type depending on the content,
+ /// If the content corresponds to Code, this will return Segment::Code
+ /// If the content corresponds to Data, this will return Segment::Data
+ /// If the content corresponds to TLS, this will return Segment::TLS
+ virtual int getContentType() const {
+ int64_t fl = flags();
+ switch (_segmentType) {
+ case llvm::ELF::PT_LOAD: {
+ if (fl && llvm::ELF::PF_X)
+ return Chunk<ELFT>::ContentType::Code;
+ if (fl && llvm::ELF::PF_W)
+ return Chunk<ELFT>::ContentType::Data;
+ }
+ case llvm::ELF::PT_TLS:
+ return Chunk<ELFT>::ContentType::TLS;
+ case llvm::ELF::PT_NOTE:
+ return Chunk<ELFT>::ContentType::Note;
+ default:
+ return Chunk<ELFT>::ContentType::Unknown;
+ }
+ }
+
+ int pageSize() const { return this->_context.getPageSize(); }
+
+ int rawflags() const { return _atomflags; }
+
+ int64_t atomflags() const {
+ switch (_atomflags) {
+
+ case DefinedAtom::permUnknown:
+ return permUnknown;
+
+ case DefinedAtom::permRWX:
+ return permRWX;
+
+ case DefinedAtom::permR_X:
+ return permRX;
+
+ case DefinedAtom::permR__:
+ return permR;
+
+ case DefinedAtom::permRW_L:
+ return permRWL;
+
+ case DefinedAtom::permRW_:
+ return permRW;
+
+ case DefinedAtom::perm___:
+ default:
+ return permNonAccess;
+ }
+ }
+
+ int64_t numSlices() const { return _segmentSlices.size(); }
+
+ range<SliceIter> slices() { return _segmentSlices; }
+
+ Chunk<ELFT> *firstSection() { return _sections[0]; }
+
+private:
+
+ /// \brief Check if the chunk needs to be aligned
+ bool needAlign(Chunk<ELFT> *chunk) const {
+ if (chunk->getContentType() == Chunk<ELFT>::ContentType::Data &&
+ _outputMagic == ELFLinkingContext::OutputMagic::NMAGIC)
+ return true;
+ return false;
+ }
+
+ // Cached value of outputMagic
+ ELFLinkingContext::OutputMagic _outputMagic;
+
+protected:
+ /// \brief Section or some other chunk type.
+ std::vector<Chunk<ELFT> *> _sections;
+ std::vector<SegmentSlice<ELFT> *> _segmentSlices;
+ Layout::SegmentType _segmentType;
+ uint64_t _flags;
+ int64_t _atomflags;
+ llvm::BumpPtrAllocator _segmentAllocate;
+};
+
+/// This chunk represents a linker script expression that needs to be calculated
+/// at the time the virtual addresses for the parent segment are being assigned.
+template <class ELFT> class ExpressionChunk : public Chunk<ELFT> {
+public:
+ ExpressionChunk(ELFLinkingContext &ctx, const script::SymbolAssignment *expr)
+ : Chunk<ELFT>(StringRef(), Chunk<ELFT>::Kind::Expression, ctx),
+ _expr(expr), _linkerScriptSema(ctx.linkerScriptSema()) {
+ this->_alignment = 1;
+ }
+
+ static bool classof(const Chunk<ELFT> *c) {
+ return c->kind() == Chunk<ELFT>::Kind::Expression;
+ }
+
+ int getContentType() const override {
+ return Chunk<ELFT>::ContentType::Unknown;
+ }
+ void write(ELFWriter *, TargetLayout<ELFT> &,
+ llvm::FileOutputBuffer &) override {}
+ void doPreFlight() override {}
+ void finalize() override {}
+
+ std::error_code evalExpr(uint64_t &curPos) {
+ return _linkerScriptSema.evalExpr(_expr, curPos);
+ }
+
+private:
+ const script::SymbolAssignment *_expr;
+ script::Sema &_linkerScriptSema;
+};
+
+/// \brief A Program Header segment contains a set of chunks instead of sections
+/// The segment doesn't contain any slice
+template <class ELFT> class ProgramHeaderSegment : public Segment<ELFT> {
+public:
+ ProgramHeaderSegment(const ELFLinkingContext &context)
+ : Segment<ELFT>(context, "PHDR", llvm::ELF::PT_PHDR) {
+ this->_alignment = 8;
+ this->_flags = (llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR);
+ }
+
+ /// Finalize the segment, before we want to write the segment header
+ /// information
+ void finalize() {
+ // If the segment is of type Program Header, then the values fileOffset
+ // and the fileSize need to be picked up from the last section, the first
+ // section points to the ELF header and the second chunk points to the
+ // actual program headers
+ this->setFileOffset(this->_sections.back()->fileOffset());
+ this->setVirtualAddr(this->_sections.back()->virtualAddr());
+ this->_fsize = this->_sections.back()->fileSize();
+ this->_msize = this->_sections.back()->memSize();
+ }
+
+};
+
+template <class ELFT>
+Segment<ELFT>::Segment(const ELFLinkingContext &context, StringRef name,
+ const Layout::SegmentType type)
+ : Chunk<ELFT>(name, Chunk<ELFT>::Kind::ELFSegment, context),
+ _segmentType(type), _flags(0), _atomflags(0) {
+ this->_alignment = 0;
+ this->_fsize = 0;
+ _outputMagic = context.getOutputMagic();
+}
+
+// This function actually is used, but not in all instantiations of Segment.
+LLVM_ATTRIBUTE_UNUSED
+static DefinedAtom::ContentPermissions toAtomPerms(uint64_t flags) {
+ switch (flags & (SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR)) {
+ case SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR:
+ return DefinedAtom::permRWX;
+ case SHF_ALLOC | SHF_EXECINSTR:
+ return DefinedAtom::permR_X;
+ case SHF_ALLOC:
+ return DefinedAtom::permR__;
+ case SHF_ALLOC | SHF_WRITE:
+ return DefinedAtom::permRW_;
+ default:
+ return DefinedAtom::permUnknown;
+ }
+}
+
+template <class ELFT> void Segment<ELFT>::append(Chunk<ELFT> *chunk) {
+ _sections.push_back(chunk);
+ Section<ELFT> *section = dyn_cast<Section<ELFT>>(chunk);
+ if (!section)
+ return;
+ if (_flags < section->getFlags())
+ _flags |= section->getFlags();
+ if (_atomflags < toAtomPerms(_flags))
+ _atomflags = toAtomPerms(_flags);
+ if (this->_alignment < section->alignment())
+ this->_alignment = section->alignment();
+}
+
+template <class ELFT>
+bool Segment<ELFT>::compareSegments(Segment<ELFT> *sega, Segment<ELFT> *segb) {
+ int64_t type1 = sega->segmentType();
+ int64_t type2 = segb->segmentType();
+
+ if (type1 == type2)
+ return sega->atomflags() < segb->atomflags();
+
+ // The single PT_PHDR segment is required to precede any loadable
+ // segment. We simply make it always first.
+ if (type1 == llvm::ELF::PT_PHDR)
+ return true;
+ if (type2 == llvm::ELF::PT_PHDR)
+ return false;
+
+ // The single PT_INTERP segment is required to precede any loadable
+ // segment. We simply make it always second.
+ if (type1 == llvm::ELF::PT_INTERP)
+ return true;
+ if (type2 == llvm::ELF::PT_INTERP)
+ return false;
+
+ // We then put PT_LOAD segments before any other segments.
+ if (type1 == llvm::ELF::PT_LOAD)
+ return true;
+ if (type2 == llvm::ELF::PT_LOAD)
+ return false;
+
+ // We put the PT_GNU_RELRO segment last, because that is where the
+ // dynamic linker expects to find it
+ if (type1 == llvm::ELF::PT_GNU_RELRO)
+ return false;
+ if (type2 == llvm::ELF::PT_GNU_RELRO)
+ return true;
+
+ // We put the PT_TLS segment last except for the PT_GNU_RELRO
+ // segment, because that is where the dynamic linker expects to find
+ if (type1 == llvm::ELF::PT_TLS)
+ return false;
+ if (type2 == llvm::ELF::PT_TLS)
+ return true;
+
+ // Otherwise compare the types to establish an arbitrary ordering.
+ // FIXME: Should figure out if we should just make all other types compare
+ // equal, but if so, we should probably do the same for atom flags and change
+ // users of this to use stable_sort.
+ return type1 < type2;
+}
+
+template <class ELFT>
+void Segment<ELFT>::assignFileOffsets(uint64_t startOffset) {
+ uint64_t fileOffset = startOffset;
+ uint64_t curSliceFileOffset = fileOffset;
+ bool isDataPageAlignedForNMagic = false;
+ bool alignSegments = this->_context.alignSegments();
+ uint64_t p_align = this->_context.getPageSize();
+ uint64_t lastVirtualAddress = 0;
+
+ this->setFileOffset(startOffset);
+ for (auto &slice : slices()) {
+ bool isFirstSection = true;
+ for (auto section : slice->sections()) {
+ // Handle linker script expressions, which may change the offset
+ if (!isFirstSection)
+ if (auto expr = dyn_cast<ExpressionChunk<ELFT>>(section))
+ fileOffset += expr->virtualAddr() - lastVirtualAddress;
+ // Align fileoffset to the alignment of the section.
+ fileOffset = llvm::RoundUpToAlignment(fileOffset, section->alignment());
+ // If the linker outputmagic is set to OutputMagic::NMAGIC, align the Data
+ // to a page boundary
+ if (isFirstSection &&
+ _outputMagic != ELFLinkingContext::OutputMagic::NMAGIC &&
+ _outputMagic != ELFLinkingContext::OutputMagic::OMAGIC) {
+ // Align to a page only if the output is not
+ // OutputMagic::NMAGIC/OutputMagic::OMAGIC
+ if (alignSegments)
+ fileOffset = llvm::RoundUpToAlignment(fileOffset, p_align);
+ else {
+ // Align according to ELF spec.
+ // in p75, http://www.sco.com/developers/devspecs/gabi41.pdf
+ uint64_t virtualAddress = slice->virtualAddr();
+ Section<ELFT> *sect = dyn_cast<Section<ELFT>>(section);
+ if (sect && sect->isLoadableSection() &&
+ ((virtualAddress & (p_align - 1)) !=
+ (fileOffset & (p_align - 1))))
+ fileOffset = llvm::RoundUpToAlignment(fileOffset, p_align) +
+ (virtualAddress % p_align);
+ }
+ } else if (!isDataPageAlignedForNMagic && needAlign(section)) {
+ fileOffset =
+ llvm::RoundUpToAlignment(fileOffset, this->_context.getPageSize());
+ isDataPageAlignedForNMagic = true;
+ }
+ if (isFirstSection) {
+ slice->setFileOffset(fileOffset);
+ isFirstSection = false;
+ curSliceFileOffset = fileOffset;
+ }
+ section->setFileOffset(fileOffset);
+ fileOffset += section->fileSize();
+ lastVirtualAddress = section->virtualAddr() + section->memSize();
+ }
+ slice->setFileSize(fileOffset - curSliceFileOffset);
+ }
+ this->setFileSize(fileOffset - startOffset);
+}
+
+/// \brief Assign virtual addresses to the slices
+template <class ELFT> void Segment<ELFT>::assignVirtualAddress(uint64_t addr) {
+ int startSection = 0;
+ int currSection = 0;
+ SectionIter startSectionIter;
+
+ // slice align is set to the max alignment of the chunks that are
+ // contained in the slice
+ uint64_t sliceAlign = 0;
+ // Current slice size
+ uint64_t curSliceSize = 0;
+ // Current Slice File Offset
+ uint64_t curSliceAddress = 0;
+
+ startSectionIter = _sections.begin();
+ startSection = 0;
+ bool isFirstSection = true;
+ bool isDataPageAlignedForNMagic = false;
+ uint64_t startAddr = addr;
+ SegmentSlice<ELFT> *slice = nullptr;
+ uint64_t tlsStartAddr = 0;
+ bool alignSegments = this->_context.alignSegments();
+ StringRef prevOutputSectionName = StringRef();
+
+ for (auto si = _sections.begin(); si != _sections.end(); ++si) {
+ // If this is first section in the segment, page align the section start
+ // address. The linker needs to align the data section to a page boundary
+ // only if NMAGIC is set.
+ if (isFirstSection) {
+ isFirstSection = false;
+ if (alignSegments &&
+ _outputMagic != ELFLinkingContext::OutputMagic::NMAGIC &&
+ _outputMagic != ELFLinkingContext::OutputMagic::OMAGIC)
+ // Align to a page only if the output is not
+ // OutputMagic::NMAGIC/OutputMagic::OMAGIC
+ startAddr =
+ llvm::RoundUpToAlignment(startAddr, this->_context.getPageSize());
+ else if (!isDataPageAlignedForNMagic && needAlign(*si)) {
+ // If the linker outputmagic is set to OutputMagic::NMAGIC, align the
+ // Data to a page boundary.
+ startAddr =
+ llvm::RoundUpToAlignment(startAddr, this->_context.getPageSize());
+ isDataPageAlignedForNMagic = true;
+ }
+ // align the startOffset to the section alignment
+ uint64_t newAddr = llvm::RoundUpToAlignment(startAddr, (*si)->alignment());
+ // Handle linker script expressions, which *may update newAddr* if the
+ // expression assigns to "."
+ if (auto expr = dyn_cast<ExpressionChunk<ELFT>>(*si))
+ expr->evalExpr(newAddr);
+ curSliceAddress = newAddr;
+ sliceAlign = (*si)->alignment();
+ (*si)->setVirtualAddr(curSliceAddress);
+
+ // Handle TLS.
+ if (auto section = dyn_cast<Section<ELFT>>(*si)) {
+ if (section->getSegmentType() == llvm::ELF::PT_TLS) {
+ tlsStartAddr =
+ llvm::RoundUpToAlignment(tlsStartAddr, (*si)->alignment());
+ section->assignVirtualAddress(tlsStartAddr);
+ tlsStartAddr += (*si)->memSize();
+ } else {
+ section->assignVirtualAddress(newAddr);
+ }
+ }
+ // TBSS section is special in that it doesn't contribute to memory of any
+ // segment. If we see a tbss section, don't add memory size to addr The
+ // fileOffset is automatically taken care of since TBSS section does not
+ // end up using file size
+ if ((*si)->order() != DefaultLayout<ELFT>::ORDER_TBSS)
+ curSliceSize = (*si)->memSize();
+ } else {
+ uint64_t curAddr = curSliceAddress + curSliceSize;
+ if (!isDataPageAlignedForNMagic && needAlign(*si)) {
+ // If the linker outputmagic is set to OutputMagic::NMAGIC, align the
+ // Data
+ // to a page boundary
+ curAddr =
+ llvm::RoundUpToAlignment(curAddr, this->_context.getPageSize());
+ isDataPageAlignedForNMagic = true;
+ }
+ uint64_t newAddr = llvm::RoundUpToAlignment(curAddr, (*si)->alignment());
+ // Handle linker script expressions, which *may update newAddr* if the
+ // expression assigns to "."
+ if (auto expr = dyn_cast<ExpressionChunk<ELFT>>(*si))
+ expr->evalExpr(newAddr);
+ Section<ELFT> *sec = dyn_cast<Section<ELFT>>(*si);
+ StringRef curOutputSectionName;
+ if (sec)
+ curOutputSectionName = sec->outputSectionName();
+ else {
+ // If this is a linker script expression, propagate the name of the
+ // previous section instead
+ if (isa<ExpressionChunk<ELFT>>(*si))
+ curOutputSectionName = prevOutputSectionName;
+ else
+ curOutputSectionName = (*si)->name();
+ }
+ bool autoCreateSlice = true;
+ if (curOutputSectionName == prevOutputSectionName)
+ autoCreateSlice = false;
+ // If the newAddress computed is more than a page away, let's create
+ // a separate segment, so that memory is not used up while running.
+ // Dont create a slice, if the new section falls in the same output
+ // section as the previous section.
+ if (autoCreateSlice &&
+ ((newAddr - curAddr) > this->_context.getPageSize()) &&
+ (_outputMagic != ELFLinkingContext::OutputMagic::NMAGIC &&
+ _outputMagic != ELFLinkingContext::OutputMagic::OMAGIC)) {
+ auto sliceIter =
+ std::find_if(_segmentSlices.begin(), _segmentSlices.end(),
+ [startSection](SegmentSlice<ELFT> *s) -> bool {
+ return s->startSection() == startSection;
+ });
+ if (sliceIter == _segmentSlices.end()) {
+ slice = new (_segmentAllocate.Allocate<SegmentSlice<ELFT>>())
+ SegmentSlice<ELFT>();
+ _segmentSlices.push_back(slice);
+ } else {
+ slice = (*sliceIter);
+ }
+ slice->setStart(startSection);
+ slice->setSections(make_range(startSectionIter, si));
+ slice->setMemSize(curSliceSize);
+ slice->setAlign(sliceAlign);
+ slice->setVirtualAddr(curSliceAddress);
+ // Start new slice
+ curSliceAddress = newAddr;
+ (*si)->setVirtualAddr(curSliceAddress);
+ startSectionIter = si;
+ startSection = currSection;
+ if (auto section = dyn_cast<Section<ELFT>>(*si))
+ section->assignVirtualAddress(newAddr);
+ curSliceSize = newAddr - curSliceAddress + (*si)->memSize();
+ sliceAlign = (*si)->alignment();
+ } else {
+ if (sliceAlign < (*si)->alignment())
+ sliceAlign = (*si)->alignment();
+ (*si)->setVirtualAddr(newAddr);
+ // Handle TLS.
+ if (auto section = dyn_cast<Section<ELFT>>(*si)) {
+ if (section->getSegmentType() == llvm::ELF::PT_TLS) {
+ tlsStartAddr =
+ llvm::RoundUpToAlignment(tlsStartAddr, (*si)->alignment());
+ section->assignVirtualAddress(tlsStartAddr);
+ tlsStartAddr += (*si)->memSize();
+ } else {
+ section->assignVirtualAddress(newAddr);
+ }
+ }
+ // TBSS section is special in that it doesn't contribute to memory of
+ // any segment. If we see a tbss section, don't add memory size to addr
+ // The fileOffset is automatically taken care of since TBSS section does
+ // not end up using file size.
+ if ((*si)->order() != DefaultLayout<ELFT>::ORDER_TBSS)
+ curSliceSize = newAddr - curSliceAddress + (*si)->memSize();
+ else
+ curSliceSize = newAddr - curSliceAddress;
+ }
+ prevOutputSectionName = curOutputSectionName;
+ }
+ currSection++;
+ }
+ auto sliceIter = std::find_if(_segmentSlices.begin(), _segmentSlices.end(),
+ [startSection](SegmentSlice<ELFT> *s) -> bool {
+ return s->startSection() == startSection;
+ });
+ if (sliceIter == _segmentSlices.end()) {
+ slice = new (_segmentAllocate.Allocate<SegmentSlice<ELFT>>())
+ SegmentSlice<ELFT>();
+ _segmentSlices.push_back(slice);
+ } else {
+ slice = (*sliceIter);
+ }
+ slice->setStart(startSection);
+ slice->setVirtualAddr(curSliceAddress);
+ slice->setMemSize(curSliceSize);
+ slice->setSections(make_range(startSectionIter, _sections.end()));
+ slice->setAlign(sliceAlign);
+
+ // Set the segment memory size and the virtual address.
+ this->setMemSize(curSliceAddress - startAddr + curSliceSize);
+ this->setVirtualAddr(curSliceAddress);
+ std::stable_sort(_segmentSlices.begin(), _segmentSlices.end(),
+ SegmentSlice<ELFT>::compare_slices);
+}
+
+// Write the Segment
+template <class ELFT>
+void Segment<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout,
+ llvm::FileOutputBuffer &buffer) {
+ for (auto slice : slices())
+ for (auto section : slice->sections())
+ section->write(writer, layout, buffer);
+}
+
+template<class ELFT>
+int64_t
+Segment<ELFT>::flags() const {
+ int64_t fl = 0;
+ if (_flags & llvm::ELF::SHF_ALLOC)
+ fl |= llvm::ELF::PF_R;
+ if (_flags & llvm::ELF::SHF_WRITE)
+ fl |= llvm::ELF::PF_W;
+ if (_flags & llvm::ELF::SHF_EXECINSTR)
+ fl |= llvm::ELF::PF_X;
+ return fl;
+}
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/TODO.txt b/lib/ReaderWriter/ELF/TODO.txt
new file mode 100644
index 0000000000000..90c334b781ba1
--- /dev/null
+++ b/lib/ReaderWriter/ELF/TODO.txt
@@ -0,0 +1,18 @@
+lib/ReaderWriter/ELF
+~~~~~~~~~~~~~~~~~~~~
+
+- Implement processing of DT_NEEDED elements including -rpath-link /
+ -rpath processing.
+
+- _GLOBAL_OFFSET_TABLE should be hidden and normally dropped from the output.
+
+- Merge SHT_NOTE sections only if applicable.
+
+- Do not create __got_* / __plt_* symbol table entries by default.
+
+- Weak references to symbols defined in a DSO should remain weak.
+
+- Fix section flags as they appear in input (update content permissions)
+
+- Check for errors in the ELFReader when creating atoms for LinkOnce
+ sections/Group sections. Add tests to account for the change when it happens.
diff --git a/lib/ReaderWriter/ELF/TargetHandler.h b/lib/ReaderWriter/ELF/TargetHandler.h
new file mode 100644
index 0000000000000..ca7a442276d18
--- /dev/null
+++ b/lib/ReaderWriter/ELF/TargetHandler.h
@@ -0,0 +1,86 @@
+//===- lib/ReaderWriter/ELF/TargetHandler.h -------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief These interfaces provide target specific hooks to change the linker's
+/// behaivor.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_TARGET_HANDLER_H
+#define LLD_READER_WRITER_ELF_TARGET_HANDLER_H
+
+#include "Layout.h"
+#include "lld/Core/Atom.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/LinkingContext.h"
+#include "lld/Core/STDExtras.h"
+#include "lld/ReaderWriter/ELFLinkingContext.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include <memory>
+#include <vector>
+
+namespace lld {
+namespace elf {
+template <class ELFT> class DynamicTable;
+template <class ELFT> class DynamicSymbolTable;
+template <class ELFT> class ELFDefinedAtom;
+template <class ELFT> class ELFReference;
+class ELFWriter;
+template <class ELFT> class ELFHeader;
+template <class ELFT> class Section;
+template <class ELFT> class TargetLayout;
+
+class TargetRelocationHandler {
+public:
+ /// Constructor
+ TargetRelocationHandler() {}
+ virtual ~TargetRelocationHandler() {}
+
+ virtual std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &,
+ const lld::AtomLayout &,
+ const Reference &) const = 0;
+};
+
+/// \brief TargetHandler contains all the information responsible to handle a
+/// a particular target on ELF. A target might wish to override implementation
+/// of creating atoms and how the atoms are written to the output file.
+template <class ELFT> class TargetHandler : public TargetHandlerBase {
+public:
+ /// The layout determined completely by the Target.
+ virtual TargetLayout<ELFT> &getTargetLayout() = 0;
+
+ /// Determine how relocations need to be applied.
+ virtual const TargetRelocationHandler &getRelocationHandler() const = 0;
+
+ /// How does the target deal with reading input files.
+ virtual std::unique_ptr<Reader> getObjReader() = 0;
+
+ /// How does the target deal with reading dynamic libraries.
+ virtual std::unique_ptr<Reader> getDSOReader() = 0;
+
+ /// How does the target deal with writing ELF output.
+ virtual std::unique_ptr<Writer> getWriter() = 0;
+};
+
+inline std::error_code make_unhandled_reloc_error() {
+ return make_dynamic_error_code(Twine("Unhandled reference type"));
+}
+
+inline std::error_code make_out_of_range_reloc_error() {
+ return make_dynamic_error_code(Twine("Relocation out of range"));
+}
+
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/TargetLayout.h b/lib/ReaderWriter/ELF/TargetLayout.h
new file mode 100644
index 0000000000000..ab7a7890a2747
--- /dev/null
+++ b/lib/ReaderWriter/ELF/TargetLayout.h
@@ -0,0 +1,28 @@
+//===- lib/ReaderWriter/ELF/TargetLayout.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_TARGET_LAYOUT_H
+#define LLD_READER_WRITER_ELF_TARGET_LAYOUT_H
+
+#include "DefaultLayout.h"
+#include "lld/Core/LLVM.h"
+
+namespace lld {
+namespace elf {
+/// \brief The target can override certain functions in the DefaultLayout
+/// class so that the order, the name of the section and the segment type could
+/// be changed in the final layout
+template <class ELFT> class TargetLayout : public DefaultLayout<ELFT> {
+public:
+ TargetLayout(ELFLinkingContext &context) : DefaultLayout<ELFT>(context) {}
+};
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/Writer.cpp b/lib/ReaderWriter/ELF/Writer.cpp
new file mode 100644
index 0000000000000..3071827e07d07
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Writer.cpp
@@ -0,0 +1,23 @@
+//===- lib/ReaderWriter/ELF/WriterELF.cpp ---------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/Writer.h"
+#include "DynamicLibraryWriter.h"
+#include "ExecutableWriter.h"
+
+using namespace llvm;
+using namespace llvm::object;
+
+namespace lld {
+
+std::unique_ptr<Writer> createWriterELF(TargetHandlerBase *handler) {
+ return std::move(handler->getWriter());
+}
+
+} // namespace lld
diff --git a/lib/ReaderWriter/ELF/Writer.h b/lib/ReaderWriter/ELF/Writer.h
new file mode 100644
index 0000000000000..1e819467c558f
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Writer.h
@@ -0,0 +1,38 @@
+//===- lib/ReaderWriter/ELF/Writer.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_WRITER_H
+#define LLD_READER_WRITER_ELF_WRITER_H
+
+#include "lld/Core/File.h"
+#include "lld/Core/Writer.h"
+
+namespace lld {
+namespace elf {
+/// \brief The Writer class is a base class for the linker to write
+/// various kinds of ELF files.
+class ELFWriter : public Writer {
+public:
+ ELFWriter() { }
+
+public:
+ /// \brief builds the chunks that needs to be written to the output
+ /// ELF file
+ virtual void buildChunks(const File &file) = 0;
+
+ /// \brief Writes the chunks into the output file specified by path
+ virtual std::error_code writeFile(const File &file, StringRef path) = 0;
+
+ /// \brief Get the virtual address of \p atom after layout.
+ virtual uint64_t addressOfAtom(const Atom *atom) = 0;
+};
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/X86/CMakeLists.txt b/lib/ReaderWriter/ELF/X86/CMakeLists.txt
new file mode 100644
index 0000000000000..191f7ab3d61dc
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86/CMakeLists.txt
@@ -0,0 +1,11 @@
+add_llvm_library(lldX86ELFTarget
+ X86LinkingContext.cpp
+ X86TargetHandler.cpp
+ X86RelocationHandler.cpp
+ LINK_LIBS
+ lldELF
+ lldReaderWriter
+ lldCore
+ LLVMObject
+ LLVMSupport
+ )
diff --git a/lib/ReaderWriter/ELF/X86/Makefile b/lib/ReaderWriter/ELF/X86/Makefile
new file mode 100644
index 0000000000000..058d5133eaba2
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86/Makefile
@@ -0,0 +1,15 @@
+##===- lld/lib/ReaderWriter/ELF/X86/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 := lldX86ELFTarget
+USEDLIBS = lldCore.a
+CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF
+
+include $(LLD_LEVEL)/Makefile
diff --git a/lib/ReaderWriter/ELF/X86/X86DynamicLibraryWriter.h b/lib/ReaderWriter/ELF/X86/X86DynamicLibraryWriter.h
new file mode 100644
index 0000000000000..86376295bec43
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86/X86DynamicLibraryWriter.h
@@ -0,0 +1,67 @@
+//===- lib/ReaderWriter/ELF/X86/X86DynamicLibraryWriter.h -----------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef X86_X86_DYNAMIC_LIBRARY_WRITER_H
+#define X86_X86_DYNAMIC_LIBRARY_WRITER_H
+
+#include "DynamicLibraryWriter.h"
+#include "X86LinkingContext.h"
+
+namespace lld {
+namespace elf {
+
+template <class ELFT>
+class X86DynamicLibraryWriter : public DynamicLibraryWriter<ELFT> {
+public:
+ X86DynamicLibraryWriter(X86LinkingContext &context,
+ X86TargetLayout<ELFT> &layout);
+
+protected:
+ // Add any runtime files and their atoms to the output
+ virtual bool createImplicitFiles(std::vector<std::unique_ptr<File>> &);
+
+ virtual void finalizeDefaultAtomValues() {
+ return DynamicLibraryWriter<ELFT>::finalizeDefaultAtomValues();
+ }
+
+ virtual void addDefaultAtoms() {
+ return DynamicLibraryWriter<ELFT>::addDefaultAtoms();
+ }
+
+private:
+ class GOTFile : public SimpleFile {
+ public:
+ GOTFile(const ELFLinkingContext &eti) : SimpleFile("GOTFile") {}
+ llvm::BumpPtrAllocator _alloc;
+ };
+
+ std::unique_ptr<GOTFile> _gotFile;
+ X86LinkingContext &_context;
+ X86TargetLayout<ELFT> &_x86Layout;
+};
+
+template <class ELFT>
+X86DynamicLibraryWriter<ELFT>::X86DynamicLibraryWriter(
+ X86LinkingContext &context, X86TargetLayout<ELFT> &layout)
+ : DynamicLibraryWriter<ELFT>(context, layout),
+ _gotFile(new GOTFile(context)), _context(context), _x86Layout(layout) {}
+
+template <class ELFT>
+bool X86DynamicLibraryWriter<ELFT>::createImplicitFiles(
+ std::vector<std::unique_ptr<File>> &result) {
+ DynamicLibraryWriter<ELFT>::createImplicitFiles(result);
+ _gotFile->addAtom(*new (_gotFile->_alloc) GLOBAL_OFFSET_TABLEAtom(*_gotFile));
+ _gotFile->addAtom(*new (_gotFile->_alloc) DYNAMICAtom(*_gotFile));
+ result.push_back(std::move(_gotFile));
+ return true;
+}
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/X86/X86ELFFile.h b/lib/ReaderWriter/ELF/X86/X86ELFFile.h
new file mode 100644
index 0000000000000..621c38c435054
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86/X86ELFFile.h
@@ -0,0 +1,41 @@
+//===- lib/ReaderWriter/ELF/X86/X86ELFFile.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_X86_X86_ELF_FILE_H
+#define LLD_READER_WRITER_ELF_X86_X86_ELF_FILE_H
+
+#include "ELFReader.h"
+
+namespace lld {
+namespace elf {
+
+class X86LinkingContext;
+
+template <class ELFT> class X86ELFFile : public ELFFile<ELFT> {
+public:
+ X86ELFFile(std::unique_ptr<MemoryBuffer> mb, X86LinkingContext &ctx)
+ : ELFFile<ELFT>(std::move(mb), ctx) {}
+
+ static ErrorOr<std::unique_ptr<X86ELFFile>>
+ create(std::unique_ptr<MemoryBuffer> mb, X86LinkingContext &ctx) {
+ return std::unique_ptr<X86ELFFile<ELFT>>(
+ new X86ELFFile<ELFT>(std::move(mb), ctx));
+ }
+};
+
+template <class ELFT> class X86DynamicFile : public DynamicFile<ELFT> {
+public:
+ X86DynamicFile(const X86LinkingContext &context, StringRef name)
+ : DynamicFile<ELFT>(context, name) {}
+};
+
+} // elf
+} // lld
+
+#endif // LLD_READER_WRITER_ELF_X86_X86_ELF_FILE_H
diff --git a/lib/ReaderWriter/ELF/X86/X86ELFReader.h b/lib/ReaderWriter/ELF/X86/X86ELFReader.h
new file mode 100644
index 0000000000000..96186c5eb0248
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86/X86ELFReader.h
@@ -0,0 +1,62 @@
+//===- lib/ReaderWriter/ELF/X86/X86ELFReader.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_X86_X86_ELF_READER_H
+#define LLD_READER_WRITER_X86_X86_ELF_READER_H
+
+#include "ELFReader.h"
+#include "X86ELFFile.h"
+
+namespace lld {
+namespace elf {
+
+typedef llvm::object::ELFType<llvm::support::little, 2, false> X86ELFType;
+
+struct X86DynamicFileCreateELFTraits {
+ typedef llvm::ErrorOr<std::unique_ptr<lld::SharedLibraryFile>> result_type;
+
+ template <class ELFT>
+ static result_type create(std::unique_ptr<llvm::MemoryBuffer> mb,
+ X86LinkingContext &ctx) {
+ return lld::elf::X86DynamicFile<ELFT>::create(std::move(mb), ctx);
+ }
+};
+
+struct X86ELFFileCreateELFTraits {
+ typedef llvm::ErrorOr<std::unique_ptr<lld::File>> result_type;
+
+ template <class ELFT>
+ static result_type create(std::unique_ptr<llvm::MemoryBuffer> mb,
+ X86LinkingContext &ctx) {
+ return lld::elf::X86ELFFile<ELFT>::create(std::move(mb), ctx);
+ }
+};
+
+class X86ELFObjectReader
+ : public ELFObjectReader<X86ELFType, X86ELFFileCreateELFTraits,
+ X86LinkingContext> {
+public:
+ X86ELFObjectReader(X86LinkingContext &ctx)
+ : ELFObjectReader<X86ELFType, X86ELFFileCreateELFTraits,
+ X86LinkingContext>(ctx, llvm::ELF::EM_386) {}
+};
+
+class X86ELFDSOReader
+ : public ELFDSOReader<X86ELFType, X86DynamicFileCreateELFTraits,
+ X86LinkingContext> {
+public:
+ X86ELFDSOReader(X86LinkingContext &ctx)
+ : ELFDSOReader<X86ELFType, X86DynamicFileCreateELFTraits,
+ X86LinkingContext>(ctx, llvm::ELF::EM_386) {}
+};
+
+} // namespace elf
+} // namespace lld
+
+#endif // LLD_READER_WRITER_X86_X86_ELF_READER_H
diff --git a/lib/ReaderWriter/ELF/X86/X86ExecutableWriter.h b/lib/ReaderWriter/ELF/X86/X86ExecutableWriter.h
new file mode 100644
index 0000000000000..68acc06c2261e
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86/X86ExecutableWriter.h
@@ -0,0 +1,57 @@
+//===- lib/ReaderWriter/ELF/X86/X86ExecutableWriter.h ---------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef X86_X86_EXECUTABLE_WRITER_H
+#define X86_X86_EXECUTABLE_WRITER_H
+
+#include "ExecutableWriter.h"
+#include "X86LinkingContext.h"
+
+namespace lld {
+namespace elf {
+
+template <class ELFT>
+class X86ExecutableWriter : public ExecutableWriter<ELFT> {
+public:
+ X86ExecutableWriter(X86LinkingContext &context,
+ X86TargetLayout<ELFT> &layout);
+
+protected:
+ // Add any runtime files and their atoms to the output
+ virtual bool createImplicitFiles(std::vector<std::unique_ptr<File>> &);
+
+ virtual void finalizeDefaultAtomValues() {
+ return ExecutableWriter<ELFT>::finalizeDefaultAtomValues();
+ }
+
+ virtual void addDefaultAtoms() {
+ return ExecutableWriter<ELFT>::addDefaultAtoms();
+ }
+
+private:
+ X86LinkingContext &_context;
+ X86TargetLayout<ELFT> &_x86Layout;
+};
+
+template <class ELFT>
+X86ExecutableWriter<ELFT>::X86ExecutableWriter(X86LinkingContext &context,
+ X86TargetLayout<ELFT> &layout)
+ : ExecutableWriter<ELFT>(context, layout), _context(context),
+ _x86Layout(layout) {}
+
+template <class ELFT>
+bool X86ExecutableWriter<ELFT>::createImplicitFiles(
+ std::vector<std::unique_ptr<File>> &result) {
+ ExecutableWriter<ELFT>::createImplicitFiles(result);
+ return true;
+}
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/X86/X86LinkingContext.cpp b/lib/ReaderWriter/ELF/X86/X86LinkingContext.cpp
new file mode 100644
index 0000000000000..26d715cf29534
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86/X86LinkingContext.cpp
@@ -0,0 +1,28 @@
+//===- lib/ReaderWriter/ELF/X86/X86LinkingContext.cpp ---------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "X86LinkingContext.h"
+#include "X86TargetHandler.h"
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/ErrorOr.h"
+
+using namespace lld;
+
+std::unique_ptr<ELFLinkingContext>
+elf::X86LinkingContext::create(llvm::Triple triple) {
+ if (triple.getArch() == llvm::Triple::x86)
+ return std::unique_ptr<ELFLinkingContext>(
+ new elf::X86LinkingContext(triple));
+ return nullptr;
+}
+
+elf::X86LinkingContext::X86LinkingContext(llvm::Triple triple)
+ : ELFLinkingContext(triple, std::unique_ptr<TargetHandlerBase>(
+ new X86TargetHandler(*this))) {}
diff --git a/lib/ReaderWriter/ELF/X86/X86LinkingContext.h b/lib/ReaderWriter/ELF/X86/X86LinkingContext.h
new file mode 100644
index 0000000000000..ff424f411aae5
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86/X86LinkingContext.h
@@ -0,0 +1,42 @@
+//===- lib/ReaderWriter/ELF/X86/X86LinkingContext.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_X86_TARGETINFO_H
+#define LLD_READER_WRITER_ELF_X86_TARGETINFO_H
+
+#include "lld/ReaderWriter/ELFLinkingContext.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/ELF.h"
+
+namespace lld {
+namespace elf {
+class X86LinkingContext final : public ELFLinkingContext {
+public:
+ static std::unique_ptr<ELFLinkingContext> create(llvm::Triple);
+ X86LinkingContext(llvm::Triple);
+
+ /// \brief X86 has only two relative relocation
+ /// a) for supporting IFUNC relocs - R_386_IRELATIVE
+ /// b) for supporting relative relocs - R_386_RELATIVE
+ bool isRelativeReloc(const Reference &r) const override {
+ if (r.kindNamespace() != Reference::KindNamespace::ELF)
+ return false;
+ assert(r.kindArch() == Reference::KindArch::x86);
+ switch (r.kindValue()) {
+ case llvm::ELF::R_386_IRELATIVE:
+ case llvm::ELF::R_386_RELATIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+};
+} // end namespace elf
+} // end namespace lld
+#endif
diff --git a/lib/ReaderWriter/ELF/X86/X86RelocationHandler.cpp b/lib/ReaderWriter/ELF/X86/X86RelocationHandler.cpp
new file mode 100644
index 0000000000000..da5a24c6ec37d
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86/X86RelocationHandler.cpp
@@ -0,0 +1,57 @@
+//===- lib/ReaderWriter/ELF/X86/X86RelocationHandler.cpp ------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "X86LinkingContext.h"
+#include "X86TargetHandler.h"
+#include "llvm/Support/Endian.h"
+
+using namespace lld;
+using namespace lld::elf;
+using namespace llvm::support::endian;
+
+namespace {
+/// \brief R_386_32 - word32: S + A
+static int reloc32(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) {
+ int32_t result = (uint32_t)(S + A);
+ write32le(location, result | read32le(location));
+ return 0;
+}
+
+/// \brief R_386_PC32 - word32: S + A - P
+static int relocPC32(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) {
+ uint32_t result = (uint32_t)((S + A) - P);
+ write32le(location, result + read32le(location));
+ return 0;
+}
+}
+
+std::error_code X86TargetRelocationHandler::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::x86);
+ switch (ref.kindValue()) {
+ case R_386_32:
+ reloc32(location, relocVAddress, targetVAddress, ref.addend());
+ break;
+ case R_386_PC32:
+ relocPC32(location, relocVAddress, targetVAddress, ref.addend());
+ break;
+ default:
+ return make_unhandled_reloc_error();
+ }
+
+ return std::error_code();
+}
diff --git a/lib/ReaderWriter/ELF/X86/X86RelocationHandler.h b/lib/ReaderWriter/ELF/X86/X86RelocationHandler.h
new file mode 100644
index 0000000000000..f161cdd55983d
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86/X86RelocationHandler.h
@@ -0,0 +1,29 @@
+//===- lib/ReaderWriter/ELF/X86/X86RelocationHandler.h --------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef X86_X86_RELOCATION_HANDLER_H
+#define X86_X86_RELOCATION_HANDLER_H
+
+#include "X86TargetHandler.h"
+
+namespace lld {
+namespace elf {
+typedef llvm::object::ELFType<llvm::support::little, 2, false> X86ELFType;
+
+class X86TargetRelocationHandler 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 // X86_X86_RELOCATION_HANDLER_H
diff --git a/lib/ReaderWriter/ELF/X86/X86TargetHandler.cpp b/lib/ReaderWriter/ELF/X86/X86TargetHandler.cpp
new file mode 100644
index 0000000000000..22d9182314248
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86/X86TargetHandler.cpp
@@ -0,0 +1,53 @@
+//===- lib/ReaderWriter/ELF/X86/X86TargetHandler.cpp ----------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "X86TargetHandler.h"
+#include "X86DynamicLibraryWriter.h"
+#include "X86ExecutableWriter.h"
+#include "X86LinkingContext.h"
+#include "X86RelocationHandler.h"
+
+using namespace lld;
+using namespace elf;
+
+using namespace llvm::ELF;
+
+std::unique_ptr<Writer> X86TargetHandler::getWriter() {
+ switch (_x86LinkingContext.getOutputELFType()) {
+ case llvm::ELF::ET_EXEC:
+ return std::unique_ptr<Writer>(new X86ExecutableWriter<X86ELFType>(
+ _x86LinkingContext, *_x86TargetLayout.get()));
+ case llvm::ELF::ET_DYN:
+ return std::unique_ptr<Writer>(new X86DynamicLibraryWriter<X86ELFType>(
+ _x86LinkingContext, *_x86TargetLayout.get()));
+ case llvm::ELF::ET_REL:
+ llvm_unreachable("TODO: support -r mode");
+ default:
+ llvm_unreachable("unsupported output type");
+ }
+}
+
+#define ELF_RELOC(name, value) LLD_KIND_STRING_ENTRY(name),
+
+const Registry::KindStrings X86TargetHandler::kindStrings[] = {
+#include "llvm/Support/ELFRelocs/i386.def"
+ LLD_KIND_STRING_END
+};
+
+#undef ELF_RELOC
+
+void X86TargetHandler::registerRelocationNames(Registry &registry) {
+ registry.addKindTable(Reference::KindNamespace::ELF, Reference::KindArch::x86,
+ kindStrings);
+}
+
+X86TargetHandler::X86TargetHandler(X86LinkingContext &context)
+ : _x86LinkingContext(context),
+ _x86TargetLayout(new X86TargetLayout<X86ELFType>(context)),
+ _x86RelocationHandler(new X86TargetRelocationHandler()) {}
diff --git a/lib/ReaderWriter/ELF/X86/X86TargetHandler.h b/lib/ReaderWriter/ELF/X86/X86TargetHandler.h
new file mode 100644
index 0000000000000..6c40267354192
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86/X86TargetHandler.h
@@ -0,0 +1,63 @@
+//===- lib/ReaderWriter/ELF/X86/X86TargetHandler.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_X86_TARGET_HANDLER_H
+#define LLD_READER_WRITER_ELF_X86_TARGET_HANDLER_H
+
+#include "DefaultTargetHandler.h"
+#include "TargetLayout.h"
+#include "X86ELFFile.h"
+#include "X86ELFReader.h"
+#include "X86RelocationHandler.h"
+
+namespace lld {
+namespace elf {
+
+class X86LinkingContext;
+
+template <class ELFT> class X86TargetLayout : public TargetLayout<ELFT> {
+public:
+ X86TargetLayout(X86LinkingContext &context) : TargetLayout<ELFT>(context) {}
+};
+
+class X86TargetHandler final
+ : public DefaultTargetHandler<X86ELFType> {
+public:
+ X86TargetHandler(X86LinkingContext &context);
+
+ X86TargetLayout<X86ELFType> &getTargetLayout() override {
+ return *(_x86TargetLayout.get());
+ }
+
+ void registerRelocationNames(Registry &registry) override;
+
+ const X86TargetRelocationHandler &getRelocationHandler() const override {
+ return *(_x86RelocationHandler.get());
+ }
+
+ std::unique_ptr<Reader> getObjReader() override {
+ return std::unique_ptr<Reader>(new X86ELFObjectReader(_x86LinkingContext));
+ }
+
+ std::unique_ptr<Reader> getDSOReader() override {
+ return std::unique_ptr<Reader>(new X86ELFDSOReader(_x86LinkingContext));
+ }
+
+ std::unique_ptr<Writer> getWriter() override;
+
+protected:
+ static const Registry::KindStrings kindStrings[];
+ X86LinkingContext &_x86LinkingContext;
+ std::unique_ptr<X86TargetLayout<X86ELFType>> _x86TargetLayout;
+ std::unique_ptr<X86TargetRelocationHandler> _x86RelocationHandler;
+};
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/X86_64/CMakeLists.txt b/lib/ReaderWriter/ELF/X86_64/CMakeLists.txt
new file mode 100644
index 0000000000000..a85d2b5046306
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/CMakeLists.txt
@@ -0,0 +1,16 @@
+add_llvm_library(lldX86_64ELFTarget
+ X86_64LinkingContext.cpp
+ X86_64TargetHandler.cpp
+ X86_64RelocationHandler.cpp
+ X86_64RelocationPass.cpp
+ LINK_LIBS
+ lldELF
+ lldReaderWriter
+ lldCore
+ LLVMObject
+ LLVMSupport
+ )
+
+include_directories(.)
+
+add_subdirectory(ExampleSubTarget)
diff --git a/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/CMakeLists.txt b/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/CMakeLists.txt
new file mode 100644
index 0000000000000..d13c98008e55f
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/CMakeLists.txt
@@ -0,0 +1,11 @@
+add_llvm_library(lldExampleSubTarget
+ ExampleLinkingContext.cpp
+ ExampleTargetHandler.cpp
+ LINK_LIBS
+ lldX86_64ELFTarget
+ lldELF
+ lldReaderWriter
+ lldCore
+ LLVMObject
+ LLVMSupport
+ )
diff --git a/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleLinkingContext.cpp b/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleLinkingContext.cpp
new file mode 100644
index 0000000000000..dbbb3ad3bc90d
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleLinkingContext.cpp
@@ -0,0 +1,35 @@
+//===- lib/ReaderWriter/ELF/X86_64/ExampleTarget/ExampleLinkingContext.cpp ----===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExampleLinkingContext.h"
+#include "ExampleTargetHandler.h"
+
+using namespace lld;
+using namespace elf;
+
+std::unique_ptr<ELFLinkingContext>
+ExampleLinkingContext::create(llvm::Triple triple) {
+ if (triple.getVendorName() == "example")
+ return llvm::make_unique<ExampleLinkingContext>(triple);
+ return nullptr;
+}
+
+ExampleLinkingContext::ExampleLinkingContext(llvm::Triple triple)
+ : X86_64LinkingContext(triple, std::unique_ptr<TargetHandlerBase>(
+ new ExampleTargetHandler(*this))) {
+ _outputELFType = llvm::ELF::ET_LOPROC;
+}
+
+StringRef ExampleLinkingContext::entrySymbolName() const {
+ return "_start";
+}
+
+void ExampleLinkingContext::addPasses(PassManager &p) {
+ ELFLinkingContext::addPasses(p);
+}
diff --git a/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleLinkingContext.h b/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleLinkingContext.h
new file mode 100644
index 0000000000000..5bb11cd35b41e
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleLinkingContext.h
@@ -0,0 +1,31 @@
+//===- lib/ReaderWriter/ELF/X86_64/ExampleTarget/ExampleLinkingContext.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_X86_64_EXAMPLE_TARGET_EXAMPLE_LINKING_CONTEXT
+#define LLD_READER_WRITER_ELF_X86_64_EXAMPLE_TARGET_EXAMPLE_LINKING_CONTEXT
+
+#include "X86_64LinkingContext.h"
+#include "X86_64TargetHandler.h"
+
+namespace lld {
+namespace elf {
+
+class ExampleLinkingContext final : public X86_64LinkingContext {
+public:
+ static std::unique_ptr<ELFLinkingContext> create(llvm::Triple);
+ ExampleLinkingContext(llvm::Triple triple);
+
+ StringRef entrySymbolName() const override;
+ void addPasses(PassManager &) override;
+};
+
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleTargetHandler.cpp b/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleTargetHandler.cpp
new file mode 100644
index 0000000000000..b66b0d903f6a4
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleTargetHandler.cpp
@@ -0,0 +1,23 @@
+//===- lib/ReaderWriter/ELF/X86_64/ExampleTarget/ExampleTargetHandler.cpp -===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExampleTargetHandler.h"
+#include "X86_64ExecutableWriter.h"
+#include "ExampleLinkingContext.h"
+
+using namespace lld;
+using namespace elf;
+
+ExampleTargetHandler::ExampleTargetHandler(ExampleLinkingContext &c)
+ : X86_64TargetHandler(c), _exampleContext(c) {}
+
+std::unique_ptr<Writer> ExampleTargetHandler::getWriter() {
+ return std::unique_ptr<Writer>(
+ new X86_64ExecutableWriter(_exampleContext, *_x86_64TargetLayout));
+}
diff --git a/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleTargetHandler.h b/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleTargetHandler.h
new file mode 100644
index 0000000000000..19a642113359f
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleTargetHandler.h
@@ -0,0 +1,31 @@
+//===- lib/ReaderWriter/ELF/X86_64/ExampleTarget/ExampleTargetHandler.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_X86_64_EXAMPLE_TARGET_EXAMPLE_TARGET_HANDLER_H
+#define LLD_READER_WRITER_ELF_X86_64_EXAMPLE_TARGET_EXAMPLE_TARGET_HANDLER_H
+
+#include "X86_64TargetHandler.h"
+
+namespace lld {
+namespace elf {
+class ExampleLinkingContext;
+
+class ExampleTargetHandler final : public X86_64TargetHandler {
+public:
+ ExampleTargetHandler(ExampleLinkingContext &c);
+
+ std::unique_ptr<Writer> getWriter() override;
+
+private:
+ ExampleLinkingContext &_exampleContext;
+};
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/Makefile b/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/Makefile
new file mode 100644
index 0000000000000..8f0b0fead1f69
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/Makefile
@@ -0,0 +1,15 @@
+##===- lld/lib/ReaderWriter/ELF/X86_64/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 := lldExampleSubTarget
+USEDLIBS = lldX86_64ELFTarget.a
+CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF
+
+include $(LLD_LEVEL)/Makefile
diff --git a/lib/ReaderWriter/ELF/X86_64/Makefile b/lib/ReaderWriter/ELF/X86_64/Makefile
new file mode 100644
index 0000000000000..dbeb4d2270507
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/Makefile
@@ -0,0 +1,19 @@
+##===- lld/lib/ReaderWriter/ELF/X86_64/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 := lldX86_64ELFTarget
+USEDLIBS = lldCore.a
+
+CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF
+CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF/X86_64/
+
+PARALLEL_DIRS := ExampleSubTarget
+
+include $(LLD_LEVEL)/Makefile
diff --git a/lib/ReaderWriter/ELF/X86_64/TODO.rst b/lib/ReaderWriter/ELF/X86_64/TODO.rst
new file mode 100644
index 0000000000000..a2411a00d1ea1
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/TODO.rst
@@ -0,0 +1,46 @@
+ELF x86-64
+~~~~~~~~~~
+
+Unimplemented Features
+######################
+
+* Code models other than the small code model
+* TLS strength reduction
+
+Unimplemented Relocations
+#########################
+
+All of these relocations are defined in:
+http://www.x86-64.org/documentation/abi.pdf
+
+Trivial Relocs
+<<<<<<<<<<<<<<
+
+These are very simple relocation calculations to implement.
+See lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp
+
+* R_X86_64_8
+* R_X86_64_PC8
+* R_X86_64_SIZE32
+* R_X86_64_SIZE64
+* R_X86_64_GOTPC32 (this relocation requires there to be a __GLOBAL_OFFSET_TABLE__)
+
+Global Offset Table Relocs
+<<<<<<<<<<<<<<<<<<<<<<<<<<
+
+* R_X86_64_GOTOFF32
+* R_X86_64_GOTOFF64
+
+Global Dynamic Thread Local Storage Relocs
+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+
+These relocations take more effort to implement, but some of them are done.
+Their implementation lives in lib/ReaderWriter/ELF/X86_64/{X86_64RelocationPass.cpp,X86_64RelocationHandler.cpp}.
+
+Documentation on these relocations can be found in:
+http://www.akkadia.org/drepper/tls.pdf
+http://www.fsfla.org/~lxoliva/writeups/TLS/RFC-TLSDESC-x86.txt
+
+* R_X86_64_GOTPC32_TLSDESC
+* R_X86_64_TLSDESC_CALL
+* R_X86_64_TLSDESC
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64DynamicLibraryWriter.h b/lib/ReaderWriter/ELF/X86_64/X86_64DynamicLibraryWriter.h
new file mode 100644
index 0000000000000..b996186115b66
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/X86_64DynamicLibraryWriter.h
@@ -0,0 +1,63 @@
+//===- lib/ReaderWriter/ELF/X86/X86_64DynamicLibraryWriter.h ---------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef X86_64_DYNAMIC_LIBRARY_WRITER_H
+#define X86_64_DYNAMIC_LIBRARY_WRITER_H
+
+#include "DynamicLibraryWriter.h"
+#include "X86_64ElfType.h"
+#include "X86_64LinkingContext.h"
+#include "X86_64TargetHandler.h"
+
+namespace lld {
+namespace elf {
+
+class X86_64DynamicLibraryWriter : public DynamicLibraryWriter<X86_64ELFType> {
+public:
+ X86_64DynamicLibraryWriter(X86_64LinkingContext &context,
+ X86_64TargetLayout &layout);
+
+protected:
+ // Add any runtime files and their atoms to the output
+ virtual bool createImplicitFiles(std::vector<std::unique_ptr<File>> &);
+
+ 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> _gotFile;
+};
+
+X86_64DynamicLibraryWriter::X86_64DynamicLibraryWriter(
+ X86_64LinkingContext &context, X86_64TargetLayout &layout)
+ : DynamicLibraryWriter(context, layout), _gotFile(new GOTFile(context)) {}
+
+bool X86_64DynamicLibraryWriter::createImplicitFiles(
+ std::vector<std::unique_ptr<File>> &result) {
+ DynamicLibraryWriter::createImplicitFiles(result);
+ _gotFile->addAtom(*new (_gotFile->_alloc) GLOBAL_OFFSET_TABLEAtom(*_gotFile));
+ _gotFile->addAtom(*new (_gotFile->_alloc) DYNAMICAtom(*_gotFile));
+ result.push_back(std::move(_gotFile));
+ return true;
+}
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64ELFFile.h b/lib/ReaderWriter/ELF/X86_64/X86_64ELFFile.h
new file mode 100644
index 0000000000000..d43840a63e7e0
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/X86_64ELFFile.h
@@ -0,0 +1,41 @@
+//===- lib/ReaderWriter/ELF/X86_64/X86_64ELFFile.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_X86_64_ELF_FILE_H
+#define LLD_READER_WRITER_ELF_X86_64_ELF_FILE_H
+
+#include "ELFReader.h"
+
+namespace lld {
+namespace elf {
+
+class X86_64LinkingContext;
+
+template <class ELFT> class X86_64ELFFile : public ELFFile<ELFT> {
+public:
+ X86_64ELFFile(std::unique_ptr<MemoryBuffer> mb, X86_64LinkingContext &ctx)
+ : ELFFile<ELFT>(std::move(mb), ctx) {}
+
+ static ErrorOr<std::unique_ptr<X86_64ELFFile>>
+ create(std::unique_ptr<MemoryBuffer> mb, X86_64LinkingContext &ctx) {
+ return std::unique_ptr<X86_64ELFFile<ELFT>>(
+ new X86_64ELFFile<ELFT>(std::move(mb), ctx));
+ }
+};
+
+template <class ELFT> class X86_64DynamicFile : public DynamicFile<ELFT> {
+public:
+ X86_64DynamicFile(const X86_64LinkingContext &context, StringRef name)
+ : DynamicFile<ELFT>(context, name) {}
+};
+
+} // elf
+} // lld
+
+#endif // LLD_READER_WRITER_ELF_X86_64_ELF_FILE_H
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64ELFReader.h b/lib/ReaderWriter/ELF/X86_64/X86_64ELFReader.h
new file mode 100644
index 0000000000000..9b1284c6dfa8c
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/X86_64ELFReader.h
@@ -0,0 +1,62 @@
+//===- lib/ReaderWriter/ELF/X86_64/X86_64ELFReader.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_X86_64_X86_64_ELF_READER_H
+#define LLD_READER_WRITER_X86_64_X86_64_ELF_READER_H
+
+#include "ELFReader.h"
+#include "X86_64ELFFile.h"
+
+namespace lld {
+namespace elf {
+
+typedef llvm::object::ELFType<llvm::support::little, 2, true> X86_64ELFType;
+
+struct X86_64DynamicFileCreateELFTraits {
+ typedef llvm::ErrorOr<std::unique_ptr<lld::SharedLibraryFile>> result_type;
+
+ template <class ELFT>
+ static result_type create(std::unique_ptr<llvm::MemoryBuffer> mb,
+ X86_64LinkingContext &ctx) {
+ return lld::elf::X86_64DynamicFile<ELFT>::create(std::move(mb), ctx);
+ }
+};
+
+struct X86_64ELFFileCreateELFTraits {
+ typedef llvm::ErrorOr<std::unique_ptr<lld::File>> result_type;
+
+ template <class ELFT>
+ static result_type create(std::unique_ptr<llvm::MemoryBuffer> mb,
+ X86_64LinkingContext &ctx) {
+ return lld::elf::X86_64ELFFile<ELFT>::create(std::move(mb), ctx);
+ }
+};
+
+class X86_64ELFObjectReader
+ : public ELFObjectReader<X86_64ELFType, X86_64ELFFileCreateELFTraits,
+ X86_64LinkingContext> {
+public:
+ X86_64ELFObjectReader(X86_64LinkingContext &ctx)
+ : ELFObjectReader<X86_64ELFType, X86_64ELFFileCreateELFTraits,
+ X86_64LinkingContext>(ctx, llvm::ELF::EM_X86_64) {}
+};
+
+class X86_64ELFDSOReader
+ : public ELFDSOReader<X86_64ELFType, X86_64DynamicFileCreateELFTraits,
+ X86_64LinkingContext> {
+public:
+ X86_64ELFDSOReader(X86_64LinkingContext &ctx)
+ : ELFDSOReader<X86_64ELFType, X86_64DynamicFileCreateELFTraits,
+ X86_64LinkingContext>(ctx, llvm::ELF::EM_X86_64) {}
+};
+
+} // namespace elf
+} // namespace lld
+
+#endif // LLD_READER_WRITER_ELF_X86_64_X86_64_READER_H
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64ElfType.h b/lib/ReaderWriter/ELF/X86_64/X86_64ElfType.h
new file mode 100644
index 0000000000000..0b982e7754e21
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/X86_64ElfType.h
@@ -0,0 +1,21 @@
+//===- lib/ReaderWriter/ELF/X86_64/X86_64ElfType.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_X86_64_X86_64_ELF_TYPE_H
+#define LLD_READER_WRITER_ELF_X86_64_X86_64_ELF_TYPE_H
+
+#include "llvm/Object/ELF.h"
+
+namespace lld {
+namespace elf {
+typedef llvm::object::ELFType<llvm::support::little, 2, true> X86_64ELFType;
+}
+}
+
+#endif
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64ExecutableWriter.h b/lib/ReaderWriter/ELF/X86_64/X86_64ExecutableWriter.h
new file mode 100644
index 0000000000000..f549ed6dcfcbb
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/X86_64ExecutableWriter.h
@@ -0,0 +1,61 @@
+//===- lib/ReaderWriter/ELF/X86/X86_64ExecutableWriter.h ------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef X86_64_EXECUTABLE_WRITER_H
+#define X86_64_EXECUTABLE_WRITER_H
+
+#include "ExecutableWriter.h"
+#include "X86_64ElfType.h"
+#include "X86_64LinkingContext.h"
+
+namespace lld {
+namespace elf {
+
+class X86_64ExecutableWriter : public ExecutableWriter<X86_64ELFType> {
+public:
+ X86_64ExecutableWriter(X86_64LinkingContext &context,
+ X86_64TargetLayout &layout)
+ : ExecutableWriter(context, layout), _gotFile(new GOTFile(context)),
+ _context(context) {}
+
+protected:
+ // Add any runtime files and their atoms to the output
+ virtual bool
+ createImplicitFiles(std::vector<std::unique_ptr<File>> &result) {
+ ExecutableWriter::createImplicitFiles(result);
+ _gotFile->addAtom(*new (_gotFile->_alloc)
+ GLOBAL_OFFSET_TABLEAtom(*_gotFile));
+ if (_context.isDynamic())
+ _gotFile->addAtom(*new (_gotFile->_alloc) DYNAMICAtom(*_gotFile));
+ result.push_back(std::move(_gotFile));
+ return true;
+ }
+
+ virtual void finalizeDefaultAtomValues() {
+ return ExecutableWriter::finalizeDefaultAtomValues();
+ }
+
+ virtual void addDefaultAtoms() {
+ return ExecutableWriter::addDefaultAtoms();
+ }
+
+private:
+ class GOTFile : public SimpleFile {
+ public:
+ GOTFile(const ELFLinkingContext &eti) : SimpleFile("GOTFile") {}
+ llvm::BumpPtrAllocator _alloc;
+ };
+
+ std::unique_ptr<GOTFile> _gotFile;
+ X86_64LinkingContext &_context;
+};
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp b/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp
new file mode 100644
index 0000000000000..6a8ce8bd64967
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp
@@ -0,0 +1,38 @@
+//===- lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp ---------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "X86_64LinkingContext.h"
+#include "X86_64RelocationPass.h"
+#include "X86_64TargetHandler.h"
+
+using namespace lld;
+using namespace elf;
+
+X86_64LinkingContext::X86_64LinkingContext(
+ llvm::Triple triple, std::unique_ptr<TargetHandlerBase> handler)
+ : ELFLinkingContext(triple, std::move(handler)) {}
+
+X86_64LinkingContext::X86_64LinkingContext(llvm::Triple triple)
+ : X86_64LinkingContext(triple,
+ llvm::make_unique<X86_64TargetHandler>(*this)) {}
+
+void X86_64LinkingContext::addPasses(PassManager &pm) {
+ auto pass = createX86_64RelocationPass(*this);
+ if (pass)
+ pm.add(std::move(pass));
+ ELFLinkingContext::addPasses(pm);
+}
+
+std::unique_ptr<ELFLinkingContext>
+X86_64LinkingContext::create(llvm::Triple triple) {
+ if (triple.getArch() == llvm::Triple::x86_64)
+ return std::unique_ptr<ELFLinkingContext>(
+ new elf::X86_64LinkingContext(triple));
+ return nullptr;
+}
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h b/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h
new file mode 100644
index 0000000000000..2cc799a9c8102
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h
@@ -0,0 +1,100 @@
+//===- lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.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_X86_64_X86_64_LINKING_CONTEXT_H
+#define LLD_READER_WRITER_ELF_X86_64_X86_64_LINKING_CONTEXT_H
+
+#include "lld/ReaderWriter/ELFLinkingContext.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/ELF.h"
+
+namespace lld {
+namespace elf {
+
+/// \brief x86-64 internal references.
+enum {
+ /// \brief The 32 bit index of the relocation in the got this reference refers
+ /// to.
+ LLD_R_X86_64_GOTRELINDEX = 1024,
+};
+
+class X86_64LinkingContext : public ELFLinkingContext {
+protected:
+ X86_64LinkingContext(llvm::Triple, std::unique_ptr<TargetHandlerBase>);
+public:
+ static std::unique_ptr<ELFLinkingContext> create(llvm::Triple);
+ X86_64LinkingContext(llvm::Triple);
+
+ void addPasses(PassManager &) override;
+
+ uint64_t getBaseAddress() const override {
+ if (_baseAddress == 0)
+ return 0x400000;
+ return _baseAddress;
+ }
+
+ bool isDynamicRelocation(const Reference &r) const override {
+ if (r.kindNamespace() != Reference::KindNamespace::ELF)
+ return false;
+ assert(r.kindArch() == Reference::KindArch::x86_64);
+ switch (r.kindValue()) {
+ case llvm::ELF::R_X86_64_RELATIVE:
+ case llvm::ELF::R_X86_64_GLOB_DAT:
+ case llvm::ELF::R_X86_64_COPY:
+ case llvm::ELF::R_X86_64_DTPMOD64:
+ case llvm::ELF::R_X86_64_DTPOFF64:
+ case llvm::ELF::R_X86_64_TPOFF64:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ bool isCopyRelocation(const Reference &r) const override {
+ if (r.kindNamespace() != Reference::KindNamespace::ELF)
+ return false;
+ assert(r.kindArch() == Reference::KindArch::x86_64);
+ if (r.kindValue() == llvm::ELF::R_X86_64_COPY)
+ return true;
+ return false;
+ }
+
+ virtual bool isPLTRelocation(const Reference &r) const override {
+ if (r.kindNamespace() != Reference::KindNamespace::ELF)
+ return false;
+ assert(r.kindArch() == Reference::KindArch::x86_64);
+ switch (r.kindValue()) {
+ case llvm::ELF::R_X86_64_JUMP_SLOT:
+ case llvm::ELF::R_X86_64_IRELATIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /// \brief X86_64 has two relative relocations
+ /// a) for supporting IFUNC - R_X86_64_IRELATIVE
+ /// b) for supporting relative relocs - R_X86_64_RELATIVE
+ bool isRelativeReloc(const Reference &r) const override {
+ if (r.kindNamespace() != Reference::KindNamespace::ELF)
+ return false;
+ assert(r.kindArch() == Reference::KindArch::x86_64);
+ switch (r.kindValue()) {
+ case llvm::ELF::R_X86_64_IRELATIVE:
+ case llvm::ELF::R_X86_64_RELATIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+};
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp b/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp
new file mode 100644
index 0000000000000..8fd74f43bbd28
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp
@@ -0,0 +1,151 @@
+//===- lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp ------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "X86_64LinkingContext.h"
+#include "X86_64TargetHandler.h"
+#include "llvm/Support/Endian.h"
+
+using namespace lld;
+using namespace lld::elf;
+using namespace llvm::support::endian;
+
+/// \brief R_X86_64_64 - word64: S + A
+static void reloc64(uint8_t *location, uint64_t P, uint64_t S, int64_t A) {
+ uint64_t result = S + A;
+ write64le(location, result | read64le(location));
+}
+
+/// \brief R_X86_64_PC32 - word32: S + A - P
+static void relocPC32(uint8_t *location, uint64_t P, uint64_t S, int64_t A) {
+ uint32_t result = (uint32_t)((S + A) - P);
+ write32le(location, result + read32le(location));
+}
+
+/// \brief R_X86_64_32 - word32: S + A
+static void reloc32(uint8_t *location, uint64_t P, uint64_t S, int64_t A) {
+ int32_t result = (uint32_t)(S + A);
+ write32le(location, result | read32le(location));
+ // TODO: Make sure that the result zero extends to the 64bit value.
+}
+
+/// \brief R_X86_64_32S - word32: S + A
+static void reloc32S(uint8_t *location, uint64_t P, uint64_t S, int64_t A) {
+ int32_t result = (int32_t)(S + A);
+ write32le(location, result | read32le(location));
+ // TODO: Make sure that the result sign extends to the 64bit value.
+}
+
+/// \brief R_X86_64_16 - word16: S + A
+static void reloc16(uint8_t *location, uint64_t P, uint64_t S, int64_t A) {
+ uint16_t result = (uint16_t)(S + A);
+ write16le(location, result | read16le(location));
+ // TODO: Check for overflow.
+}
+
+/// \brief R_X86_64_PC16 - word16: S + A - P
+static void relocPC16(uint8_t *location, uint64_t P, uint64_t S, int64_t A) {
+ uint16_t result = (uint16_t)((S + A) - P);
+ write16le(location, result | read16le(location));
+ // TODO: Check for overflow.
+}
+
+/// \brief R_X86_64_PC64 - word64: S + A - P
+static void relocPC64(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) {
+ int64_t result = (uint64_t)((S + A) - P);
+ write64le(location, result | read64le(location));
+}
+
+std::error_code X86_64TargetRelocationHandler::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::x86_64);
+ switch (ref.kindValue()) {
+ case R_X86_64_NONE:
+ break;
+ case R_X86_64_64:
+ reloc64(location, relocVAddress, targetVAddress, ref.addend());
+ break;
+ case R_X86_64_PC32:
+ case R_X86_64_GOTPCREL:
+ relocPC32(location, relocVAddress, targetVAddress, ref.addend());
+ break;
+ case R_X86_64_32:
+ reloc32(location, relocVAddress, targetVAddress, ref.addend());
+ break;
+ case R_X86_64_32S:
+ reloc32S(location, relocVAddress, targetVAddress, ref.addend());
+ break;
+ case R_X86_64_16:
+ reloc16(location, relocVAddress, targetVAddress, ref.addend());
+ break;
+ case R_X86_64_PC16:
+ relocPC16(location, relocVAddress, targetVAddress, ref.addend());
+ break;
+ case R_X86_64_TPOFF64:
+ case R_X86_64_DTPOFF32:
+ case R_X86_64_TPOFF32: {
+ _tlsSize = _x86_64Layout.getTLSSize();
+ if (ref.kindValue() == R_X86_64_TPOFF32 ||
+ ref.kindValue() == R_X86_64_DTPOFF32) {
+ write32le(location, targetVAddress - _tlsSize);
+ } else {
+ write64le(location, targetVAddress - _tlsSize);
+ }
+ break;
+ }
+ case R_X86_64_TLSGD: {
+ relocPC32(location, relocVAddress, targetVAddress, ref.addend());
+ break;
+ }
+ case R_X86_64_TLSLD: {
+ // Rewrite to move %fs:0 into %rax. Technically we should verify that the
+ // next relocation is a PC32 to __tls_get_addr...
+ static uint8_t instr[] = { 0x66, 0x66, 0x66, 0x64, 0x48, 0x8b, 0x04, 0x25,
+ 0x00, 0x00, 0x00, 0x00 };
+ std::memcpy(location - 3, instr, sizeof(instr));
+ break;
+ }
+ case R_X86_64_PC64:
+ relocPC64(location, relocVAddress, targetVAddress, ref.addend());
+ break;
+ case LLD_R_X86_64_GOTRELINDEX: {
+ const DefinedAtom *target = cast<const DefinedAtom>(ref.target());
+ for (const Reference *r : *target) {
+ if (r->kindValue() == R_X86_64_JUMP_SLOT) {
+ uint32_t index;
+ if (!_x86_64Layout.getPLTRelocationTable()->getRelocationIndex(*r,
+ index))
+ llvm_unreachable("Relocation doesn't exist");
+ reloc32(location, 0, index, 0);
+ break;
+ }
+ }
+ break;
+ }
+ // Runtime only relocations. Ignore here.
+ case R_X86_64_RELATIVE:
+ case R_X86_64_IRELATIVE:
+ case R_X86_64_JUMP_SLOT:
+ case R_X86_64_GLOB_DAT:
+ case R_X86_64_DTPMOD64:
+ case R_X86_64_DTPOFF64:
+ break;
+ default:
+ return make_unhandled_reloc_error();
+ }
+
+ return std::error_code();
+}
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.h b/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.h
new file mode 100644
index 0000000000000..9e2c2171015d1
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.h
@@ -0,0 +1,39 @@
+//===- lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.h --------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef X86_64_RELOCATION_HANDLER_H
+#define X86_64_RELOCATION_HANDLER_H
+
+#include "X86_64TargetHandler.h"
+
+namespace lld {
+namespace elf {
+typedef llvm::object::ELFType<llvm::support::little, 2, true> X86_64ELFType;
+
+class X86_64TargetLayout;
+
+class X86_64TargetRelocationHandler final : public TargetRelocationHandler {
+public:
+ X86_64TargetRelocationHandler(X86_64TargetLayout &layout)
+ : _tlsSize(0), _x86_64Layout(layout) {}
+
+ std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &,
+ const lld::AtomLayout &,
+ const Reference &) const override;
+
+private:
+ // Cached size of the TLS segment.
+ mutable uint64_t _tlsSize;
+ X86_64TargetLayout &_x86_64Layout;
+};
+
+} // end namespace elf
+} // end namespace lld
+
+#endif // X86_64_RELOCATION_HANDLER_H
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp b/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp
new file mode 100644
index 0000000000000..0703927fd56c3
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp
@@ -0,0 +1,513 @@
+//===- lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.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 x86-64. This includes
+/// GOT and PLT entries, TLS, COPY, and ifunc.
+///
+/// This is based on section 4.4.1 of the AMD64 ABI (no stable URL as of Oct,
+/// 2013).
+///
+/// This also includes aditional behaivor that gnu-ld and gold implement but
+/// which is not specified anywhere.
+///
+//===----------------------------------------------------------------------===//
+
+#include "X86_64RelocationPass.h"
+#include "Atoms.h"
+#include "X86_64LinkingContext.h"
+#include "lld/Core/Simple.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
+
+using namespace lld;
+using namespace lld::elf;
+using namespace llvm::ELF;
+
+// .got values
+static const uint8_t x86_64GotAtomContent[8] = {0};
+
+// .plt value (entry 0)
+static const uint8_t x86_64Plt0AtomContent[16] = {
+ 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushq GOT+8(%rip)
+ 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *GOT+16(%rip)
+ 0x90, 0x90, 0x90, 0x90 // nopnopnop
+};
+
+// .plt values (other entries)
+static const uint8_t x86_64PltAtomContent[16] = {
+ 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmpq *gotatom(%rip)
+ 0x68, 0x00, 0x00, 0x00, 0x00, // pushq reloc-index
+ 0xe9, 0x00, 0x00, 0x00, 0x00 // jmpq plt[-1]
+};
+
+// TLS GD Entry
+static const uint8_t x86_64GotTlsGdAtomContent[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+namespace {
+/// \brief Atoms that are used by X86_64 dynamic linking
+class X86_64GOTAtom : public GOTAtom {
+public:
+ X86_64GOTAtom(const File &f, StringRef secName) : GOTAtom(f, secName) {}
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return ArrayRef<uint8_t>(x86_64GotAtomContent, 8);
+ }
+};
+
+/// \brief X86_64 GOT TLS GD entry.
+class GOTTLSGdAtom : public X86_64GOTAtom {
+public:
+ GOTTLSGdAtom(const File &f, StringRef secName) : X86_64GOTAtom(f, secName) {}
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return llvm::makeArrayRef(x86_64GotTlsGdAtomContent);
+ }
+};
+
+class X86_64PLT0Atom : public PLT0Atom {
+public:
+ X86_64PLT0Atom(const File &f) : PLT0Atom(f) {}
+ ArrayRef<uint8_t> rawContent() const override {
+ return ArrayRef<uint8_t>(x86_64Plt0AtomContent, 16);
+ }
+};
+
+class X86_64PLTAtom : public PLTAtom {
+public:
+ X86_64PLTAtom(const File &f, StringRef secName) : PLTAtom(f, secName) {}
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return ArrayRef<uint8_t>(x86_64PltAtomContent, 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 Derived> class RelocationPass : public Pass {
+ /// \brief Handle a specific reference.
+ void handleReference(const DefinedAtom &atom, const Reference &ref) {
+ if (ref.kindNamespace() != Reference::KindNamespace::ELF)
+ return;
+ assert(ref.kindArch() == Reference::KindArch::x86_64);
+ switch (ref.kindValue()) {
+ case R_X86_64_16:
+ case R_X86_64_32:
+ case R_X86_64_32S:
+ case R_X86_64_64:
+ case R_X86_64_PC16:
+ case R_X86_64_PC32:
+ case R_X86_64_PC64:
+ static_cast<Derived *>(this)->handlePlain(ref);
+ break;
+ case R_X86_64_PLT32:
+ static_cast<Derived *>(this)->handlePLT32(ref);
+ break;
+ case R_X86_64_GOT32:
+ case R_X86_64_GOTPC32:
+ case R_X86_64_GOTPCREL:
+ case R_X86_64_GOTOFF64:
+ static_cast<Derived *>(this)->handleGOT(ref);
+ break;
+ case R_X86_64_GOTTPOFF: // GOT Thread Pointer Offset
+ static_cast<Derived *>(this)->handleGOTTPOFF(ref);
+ break;
+ case R_X86_64_TLSGD:
+ static_cast<Derived *>(this)->handleTLSGd(ref);
+ break;
+ }
+ }
+
+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) X86_64GOTAtom(_file, ".got.plt");
+ ga->addReferenceELF_x86_64(R_X86_64_IRELATIVE, 0, da, 0);
+ auto pa = new (_file._alloc) X86_64PLTAtom(_file, ".plt");
+ pa->addReferenceELF_x86_64(R_X86_64_PC32, 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<const DefinedAtom>(ref.target());
+ if (target && target->contentType() == DefinedAtom::typeResolver)
+ const_cast<Reference &>(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) X86_64GOTAtom(_file, ".got");
+ g->addReferenceELF_x86_64(R_X86_64_TPOFF64, 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<Reference &>(ref).setTarget(getGOTTPOFF(ref.target()));
+ const_cast<Reference &>(ref).setKindValue(R_X86_64_PC32);
+ }
+
+ /// \brief Create a TLS GOT entry with DTPMOD64/DTPOFF64 dynamic relocations.
+ void handleTLSGd(const Reference &ref) {
+ const_cast<Reference &>(ref).setTarget(getTLSGdGOTEntry(ref.target()));
+ }
+
+ /// \brief Create a GOT entry containing 0.
+ const GOTAtom *getNullGOT() {
+ if (!_null) {
+ _null = new (_file._alloc) X86_64GOTAtom(_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) X86_64GOTAtom(_file, ".got");
+ g->addReferenceELF_x86_64(R_X86_64_64, 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;
+ }
+
+ const GOTAtom *getTLSGdGOTEntry(const Atom *a) {
+ auto got = _gotTLSGdMap.find(a);
+ if (got != _gotTLSGdMap.end())
+ return got->second;
+
+ auto ga = new (_file._alloc) GOTTLSGdAtom(_file, ".got");
+ _gotTLSGdMap[a] = ga;
+
+ _tlsGotVector.push_back(ga);
+ ga->addReferenceELF_x86_64(R_X86_64_DTPMOD64, 0, a, 0);
+ ga->addReferenceELF_x86_64(R_X86_64_DTPOFF64, 8, a, 0);
+
+ return ga;
+ }
+
+public:
+ RelocationPass(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<MutableFile> &mf) override {
+ ScopedTask task(getDefaultDomain(), "X86-64 GOT/PLT Pass");
+ // Process all references.
+ for (const auto &atom : mf->defined())
+ for (const auto &ref : *atom)
+ handleReference(*atom, *ref);
+
+ // Add all created atoms to the link.
+ uint64_t ordinal = 0;
+ if (_PLT0) {
+ _PLT0->setOrdinal(ordinal++);
+ mf->addAtom(*_PLT0);
+ }
+ for (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 &got : _tlsGotVector) {
+ 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<const Atom *, GOTAtom *> _gotMap;
+
+ /// \brief Map Atoms to their PLT entries.
+ llvm::DenseMap<const Atom *, PLTAtom *> _pltMap;
+
+ /// \brief Map Atoms to TLS GD GOT entries.
+ llvm::DenseMap<const Atom *, GOTAtom *> _gotTLSGdMap;
+
+ /// \brief Map Atoms to their Object entries.
+ llvm::DenseMap<const Atom *, ObjectAtom *> _objectMap;
+
+ /// \brief the list of GOT/PLT atoms
+ std::vector<GOTAtom *> _gotVector;
+ std::vector<PLTAtom *> _pltVector;
+ std::vector<ObjectAtom *> _objectVector;
+
+ /// \brief the list of TLS GOT atoms.
+ std::vector<GOTAtom *> _tlsGotVector;
+
+ /// \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 StaticRelocationPass final
+ : public RelocationPass<StaticRelocationPass> {
+public:
+ StaticRelocationPass(const elf::X86_64LinkingContext &ctx)
+ : RelocationPass(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<Reference &>(ref).setKindValue(R_X86_64_NONE);
+ return std::error_code();
+ }
+ // Static code doesn't need PLTs.
+ const_cast<Reference &>(ref).setKindValue(R_X86_64_PC32);
+ // Handle IFUNC.
+ if (const DefinedAtom *da =
+ dyn_cast_or_null<const DefinedAtom>(ref.target()))
+ if (da->contentType() == DefinedAtom::typeResolver)
+ return handleIFUNC(ref);
+ return std::error_code();
+ }
+
+ std::error_code handleGOT(const Reference &ref) {
+ if (isa<UndefinedAtom>(ref.target()))
+ const_cast<Reference &>(ref).setTarget(getNullGOT());
+ else if (const DefinedAtom *da = dyn_cast<const DefinedAtom>(ref.target()))
+ const_cast<Reference &>(ref).setTarget(getGOT(da));
+ return std::error_code();
+ }
+};
+
+class DynamicRelocationPass final
+ : public RelocationPass<DynamicRelocationPass> {
+public:
+ DynamicRelocationPass(const elf::X86_64LinkingContext &ctx)
+ : RelocationPass(ctx) {}
+
+ const PLT0Atom *getPLT0() {
+ if (_PLT0)
+ return _PLT0;
+ // Fill in the null entry.
+ getNullGOT();
+ _PLT0 = new (_file._alloc) X86_64PLT0Atom(_file);
+ _got0 = new (_file._alloc) X86_64GOTAtom(_file, ".got.plt");
+ _got1 = new (_file._alloc) X86_64GOTAtom(_file, ".got.plt");
+ _PLT0->addReferenceELF_x86_64(R_X86_64_PC32, 2, _got0, -4);
+ _PLT0->addReferenceELF_x86_64(R_X86_64_PC32, 8, _got1, -4);
+#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) X86_64GOTAtom(_file, ".got.plt");
+ ga->addReferenceELF_x86_64(R_X86_64_JUMP_SLOT, 0, a, 0);
+ auto pa = new (_file._alloc) X86_64PLTAtom(_file, ".plt");
+ pa->addReferenceELF_x86_64(R_X86_64_PC32, 2, ga, -4);
+ pa->addReferenceELF_x86_64(LLD_R_X86_64_GOTRELINDEX, 7, ga, 0);
+ pa->addReferenceELF_x86_64(R_X86_64_PC32, 12, getPLT0(), -4);
+ // Set the starting address of the got entry to the second instruction in
+ // the plt entry.
+ ga->addReferenceELF_x86_64(R_X86_64_64, 0, pa, 6);
+#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_x86_64(R_X86_64_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<SharedLibraryAtom>(ref.target())) {
+ if (sla->type() == SharedLibraryAtom::Type::Data)
+ const_cast<Reference &>(ref).setTarget(getObjectEntry(sla));
+ else if (sla->type() == SharedLibraryAtom::Type::Code)
+ const_cast<Reference &>(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<Reference &>(ref).setKindValue(R_X86_64_PC32);
+ // Handle IFUNC.
+ if (const DefinedAtom *da =
+ dyn_cast_or_null<const DefinedAtom>(ref.target()))
+ if (da->contentType() == DefinedAtom::typeResolver)
+ return handleIFUNC(ref);
+ // If it is undefined at link time, push the work to the dynamic linker by
+ // creating a PLT entry
+ if (isa<SharedLibraryAtom>(ref.target()) ||
+ isa<UndefinedAtom>(ref.target()))
+ const_cast<Reference &>(ref).setTarget(getPLTEntry(ref.target()));
+ return std::error_code();
+ }
+
+ const GOTAtom *getSharedGOT(const Atom *a) {
+ auto got = _gotMap.find(a);
+ if (got == _gotMap.end()) {
+ auto g = new (_file._alloc) X86_64GOTAtom(_file, ".got");
+ g->addReferenceELF_x86_64(R_X86_64_GLOB_DAT, 0, a, 0);
+#ifndef NDEBUG
+ g->_name = "__got_";
+ g->_name += a->name();
+#endif
+ _gotMap[a] = g;
+ _gotVector.push_back(g);
+ return g;
+ }
+ return got->second;
+ }
+
+ std::error_code handleGOT(const Reference &ref) {
+ if (const DefinedAtom *da = dyn_cast<const DefinedAtom>(ref.target()))
+ const_cast<Reference &>(ref).setTarget(getGOT(da));
+ // Handle undefined atoms in the same way as shared lib atoms: to be
+ // resolved at run time.
+ else if (isa<SharedLibraryAtom>(ref.target()) ||
+ isa<UndefinedAtom>(ref.target()))
+ const_cast<Reference &>(ref).setTarget(getSharedGOT(ref.target()));
+ return std::error_code();
+ }
+};
+} // end anon namespace
+
+std::unique_ptr<Pass>
+lld::elf::createX86_64RelocationPass(const X86_64LinkingContext &ctx) {
+ switch (ctx.getOutputELFType()) {
+ case llvm::ELF::ET_EXEC:
+ if (ctx.isDynamic())
+ return llvm::make_unique<DynamicRelocationPass>(ctx);
+ return llvm::make_unique<StaticRelocationPass>(ctx);
+ case llvm::ELF::ET_DYN:
+ return llvm::make_unique<DynamicRelocationPass>(ctx);
+ case llvm::ELF::ET_REL:
+ return nullptr;
+ default:
+ llvm_unreachable("Unhandled output file type");
+ }
+}
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.h b/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.h
new file mode 100644
index 0000000000000..1635b5e5f57b1
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.h
@@ -0,0 +1,32 @@
+//===- lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.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_X86_64_X86_64_RELOCATION_PASS_H
+#define LLD_READER_WRITER_ELF_X86_64_X86_64_RELOCATION_PASS_H
+
+#include <memory>
+
+namespace lld {
+class Pass;
+namespace elf {
+class X86_64LinkingContext;
+
+/// \brief Create x86-64 relocation pass for the given linking context.
+std::unique_ptr<Pass>
+createX86_64RelocationPass(const X86_64LinkingContext &);
+}
+}
+
+#endif
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.cpp b/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.cpp
new file mode 100644
index 0000000000000..f35330eb25c05
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.cpp
@@ -0,0 +1,52 @@
+//===- lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.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 "X86_64DynamicLibraryWriter.h"
+#include "X86_64ExecutableWriter.h"
+#include "X86_64LinkingContext.h"
+#include "X86_64TargetHandler.h"
+
+using namespace lld;
+using namespace elf;
+
+X86_64TargetHandler::X86_64TargetHandler(X86_64LinkingContext &context)
+ : _context(context), _x86_64TargetLayout(new X86_64TargetLayout(context)),
+ _x86_64RelocationHandler(
+ new X86_64TargetRelocationHandler(*_x86_64TargetLayout.get())) {}
+
+void X86_64TargetHandler::registerRelocationNames(Registry &registry) {
+ registry.addKindTable(Reference::KindNamespace::ELF,
+ Reference::KindArch::x86_64, kindStrings);
+}
+
+std::unique_ptr<Writer> X86_64TargetHandler::getWriter() {
+ switch (this->_context.getOutputELFType()) {
+ case llvm::ELF::ET_EXEC:
+ return std::unique_ptr<Writer>(
+ new X86_64ExecutableWriter(_context, *_x86_64TargetLayout.get()));
+ case llvm::ELF::ET_DYN:
+ return std::unique_ptr<Writer>(
+ new X86_64DynamicLibraryWriter(_context, *_x86_64TargetLayout.get()));
+ case llvm::ELF::ET_REL:
+ llvm_unreachable("TODO: support -r mode");
+ default:
+ llvm_unreachable("unsupported output type");
+ }
+}
+
+#define ELF_RELOC(name, value) LLD_KIND_STRING_ENTRY(name),
+
+const Registry::KindStrings X86_64TargetHandler::kindStrings[] = {
+#include "llvm/Support/ELFRelocs/x86_64.def"
+ LLD_KIND_STRING_ENTRY(LLD_R_X86_64_GOTRELINDEX),
+ LLD_KIND_STRING_END
+};
+
+#undef ELF_RELOC
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h b/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h
new file mode 100644
index 0000000000000..57da7bca01e67
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h
@@ -0,0 +1,69 @@
+//===- lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.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_X86_64_X86_64_TARGET_HANDLER_H
+#define LLD_READER_WRITER_ELF_X86_64_X86_64_TARGET_HANDLER_H
+
+#include "DefaultTargetHandler.h"
+#include "TargetLayout.h"
+#include "X86_64ELFFile.h"
+#include "X86_64ELFReader.h"
+#include "X86_64LinkingContext.h"
+#include "X86_64RelocationHandler.h"
+#include "lld/Core/Simple.h"
+
+namespace lld {
+namespace elf {
+class X86_64TargetLayout : public TargetLayout<X86_64ELFType> {
+public:
+ X86_64TargetLayout(X86_64LinkingContext &context)
+ : TargetLayout(context) {}
+
+ void finalizeOutputSectionLayout() override {
+ sortOutputSectionByPriority(".init_array", ".init_array");
+ sortOutputSectionByPriority(".fini_array", ".fini_array");
+ }
+};
+
+class X86_64TargetHandler
+ : public DefaultTargetHandler<X86_64ELFType> {
+public:
+ X86_64TargetHandler(X86_64LinkingContext &context);
+
+ X86_64TargetLayout &getTargetLayout() override {
+ return *(_x86_64TargetLayout.get());
+ }
+
+ void registerRelocationNames(Registry &registry) override;
+
+ const X86_64TargetRelocationHandler &getRelocationHandler() const override {
+ return *(_x86_64RelocationHandler.get());
+ }
+
+ std::unique_ptr<Reader> getObjReader() override {
+ return std::unique_ptr<Reader>(new X86_64ELFObjectReader(_context));
+ }
+
+ std::unique_ptr<Reader> getDSOReader() override {
+ return std::unique_ptr<Reader>(new X86_64ELFDSOReader(_context));
+ }
+
+ std::unique_ptr<Writer> getWriter() override;
+
+protected:
+ static const Registry::KindStrings kindStrings[];
+ X86_64LinkingContext &_context;
+ std::unique_ptr<X86_64TargetLayout> _x86_64TargetLayout;
+ std::unique_ptr<X86_64TargetRelocationHandler> _x86_64RelocationHandler;
+};
+
+} // end namespace elf
+} // end namespace lld
+
+#endif