aboutsummaryrefslogtreecommitdiffstats
path: root/lib
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
downloadsrc-fb911942f1434f3d1750f83f25f5e42c80e60638.tar.gz
src-fb911942f1434f3d1750f83f25f5e42c80e60638.zip
Vendor import of lld trunk r233088:vendor/lld/lld-trunk-r233088
Notes
Notes: svn path=/vendor/lld/dist/; revision=280461 svn path=/vendor/lld/lld-trunk-r233088/; revision=280462; tag=vendor/lld/lld-trunk-r233088
Diffstat (limited to 'lib')
-rw-r--r--lib/CMakeLists.txt4
-rw-r--r--lib/Config/CMakeLists.txt5
-rw-r--r--lib/Config/Makefile13
-rw-r--r--lib/Config/Version.cpp66
-rw-r--r--lib/Core/CMakeLists.txt12
-rw-r--r--lib/Core/DefinedAtom.cpp96
-rw-r--r--lib/Core/Error.cpp151
-rw-r--r--lib/Core/File.cpp30
-rw-r--r--lib/Core/LinkingContext.cpp104
-rw-r--r--lib/Core/Makefile13
-rw-r--r--lib/Core/Reader.cpp117
-rw-r--r--lib/Core/Resolver.cpp516
-rw-r--r--lib/Core/SymbolTable.cpp390
-rw-r--r--lib/Core/TODO.txt18
-rw-r--r--lib/Core/Writer.cpp23
-rw-r--r--lib/Driver/CMakeLists.txt43
-rw-r--r--lib/Driver/CoreDriver.cpp172
-rw-r--r--lib/Driver/CoreOptions.td15
-rw-r--r--lib/Driver/DarwinLdDriver.cpp832
-rw-r--r--lib/Driver/DarwinLdOptions.td187
-rw-r--r--lib/Driver/Driver.cpp130
-rw-r--r--lib/Driver/GnuLdDriver.cpp760
-rw-r--r--lib/Driver/GnuLdOptions.td323
-rw-r--r--lib/Driver/Makefile38
-rw-r--r--lib/Driver/TODO.rst101
-rw-r--r--lib/Driver/UniversalDriver.cpp218
-rw-r--r--lib/Driver/UniversalDriverOptions.td19
-rw-r--r--lib/Driver/WinLinkDriver.cpp1371
-rw-r--r--lib/Driver/WinLinkModuleDef.cpp295
-rw-r--r--lib/Driver/WinLinkOptions.td120
-rw-r--r--lib/Makefile16
-rw-r--r--lib/ReaderWriter/CMakeLists.txt20
-rw-r--r--lib/ReaderWriter/CoreLinkingContext.cpp171
-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
-rw-r--r--lib/ReaderWriter/FileArchive.cpp293
-rw-r--r--lib/ReaderWriter/LinkerScript.cpp2564
-rw-r--r--lib/ReaderWriter/MachO/ArchHandler.cpp172
-rw-r--r--lib/ReaderWriter/MachO/ArchHandler.h300
-rw-r--r--lib/ReaderWriter/MachO/ArchHandler_arm.cpp1524
-rw-r--r--lib/ReaderWriter/MachO/ArchHandler_arm64.cpp822
-rw-r--r--lib/ReaderWriter/MachO/ArchHandler_x86.cpp642
-rw-r--r--lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp723
-rw-r--r--lib/ReaderWriter/MachO/Atoms.h181
-rw-r--r--lib/ReaderWriter/MachO/CMakeLists.txt26
-rw-r--r--lib/ReaderWriter/MachO/CompactUnwindPass.cpp530
-rw-r--r--lib/ReaderWriter/MachO/ExecutableAtoms.hpp136
-rw-r--r--lib/ReaderWriter/MachO/File.h327
-rw-r--r--lib/ReaderWriter/MachO/GOTPass.cpp185
-rw-r--r--lib/ReaderWriter/MachO/LayoutPass.cpp482
-rw-r--r--lib/ReaderWriter/MachO/LayoutPass.h97
-rw-r--r--lib/ReaderWriter/MachO/MachOLinkingContext.cpp969
-rw-r--r--lib/ReaderWriter/MachO/MachONormalizedFile.h323
-rw-r--r--lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp582
-rw-r--r--lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h177
-rw-r--r--lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp1346
-rw-r--r--lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp1238
-rw-r--r--lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp911
-rw-r--r--lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp802
-rw-r--r--lib/ReaderWriter/MachO/MachOPasses.h28
-rw-r--r--lib/ReaderWriter/MachO/Makefile14
-rw-r--r--lib/ReaderWriter/MachO/ShimPass.cpp129
-rw-r--r--lib/ReaderWriter/MachO/StubsPass.cpp373
-rw-r--r--lib/ReaderWriter/MachO/WriterMachO.cpp72
-rw-r--r--lib/ReaderWriter/Makefile16
-rw-r--r--lib/ReaderWriter/Native/CMakeLists.txt7
-rw-r--r--lib/ReaderWriter/Native/Makefile14
-rw-r--r--lib/ReaderWriter/Native/NativeFileFormat.h258
-rw-r--r--lib/ReaderWriter/Native/ReaderNative.cpp1013
-rw-r--r--lib/ReaderWriter/Native/WriterNative.cpp566
-rw-r--r--lib/ReaderWriter/PECOFF/Atoms.h312
-rw-r--r--lib/ReaderWriter/PECOFF/CMakeLists.txt16
-rw-r--r--lib/ReaderWriter/PECOFF/EdataPass.cpp227
-rw-r--r--lib/ReaderWriter/PECOFF/EdataPass.h99
-rw-r--r--lib/ReaderWriter/PECOFF/IdataPass.cpp345
-rw-r--r--lib/ReaderWriter/PECOFF/IdataPass.h218
-rw-r--r--lib/ReaderWriter/PECOFF/InferSubsystemPass.h66
-rw-r--r--lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.cpp48
-rw-r--r--lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h309
-rw-r--r--lib/ReaderWriter/PECOFF/LoadConfigPass.cpp75
-rw-r--r--lib/ReaderWriter/PECOFF/LoadConfigPass.h63
-rw-r--r--lib/ReaderWriter/PECOFF/Makefile14
-rw-r--r--lib/ReaderWriter/PECOFF/OrderPass.h67
-rw-r--r--lib/ReaderWriter/PECOFF/PDBPass.h43
-rw-r--r--lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp352
-rw-r--r--lib/ReaderWriter/PECOFF/Pass.cpp95
-rw-r--r--lib/ReaderWriter/PECOFF/Pass.h34
-rw-r--r--lib/ReaderWriter/PECOFF/ReaderCOFF.cpp1140
-rw-r--r--lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp389
-rw-r--r--lib/ReaderWriter/PECOFF/WriterImportLibrary.cpp118
-rw-r--r--lib/ReaderWriter/PECOFF/WriterImportLibrary.h23
-rw-r--r--lib/ReaderWriter/PECOFF/WriterPECOFF.cpp1417
-rw-r--r--lib/ReaderWriter/YAML/CMakeLists.txt6
-rw-r--r--lib/ReaderWriter/YAML/Makefile14
-rw-r--r--lib/ReaderWriter/YAML/ReaderWriterYAML.cpp1358
220 files changed, 49542 insertions, 0 deletions
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
new file mode 100644
index 000000000000..699f5e93f8af
--- /dev/null
+++ b/lib/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_subdirectory(Config)
+add_subdirectory(Core)
+add_subdirectory(Driver)
+add_subdirectory(ReaderWriter)
diff --git a/lib/Config/CMakeLists.txt b/lib/Config/CMakeLists.txt
new file mode 100644
index 000000000000..f7ea0423b2c9
--- /dev/null
+++ b/lib/Config/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_llvm_library(lldConfig
+ Version.cpp
+ LINK_LIBS
+ LLVMSupport
+ )
diff --git a/lib/Config/Makefile b/lib/Config/Makefile
new file mode 100644
index 000000000000..b3c57f81418f
--- /dev/null
+++ b/lib/Config/Makefile
@@ -0,0 +1,13 @@
+##===- lib/Config/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 := lldConfig
+
+include $(LLD_LEVEL)/Makefile
diff --git a/lib/Config/Version.cpp b/lib/Config/Version.cpp
new file mode 100644
index 000000000000..b64ccef12c7b
--- /dev/null
+++ b/lib/Config/Version.cpp
@@ -0,0 +1,66 @@
+//===- lib/Config/Version.cpp - LLD Version Number ---------------*- C++-=====//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines several version-related utility functions for LLD.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Config/Version.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstdlib>
+#include <cstring>
+
+using namespace llvm;
+
+namespace lld {
+
+StringRef getLLDRepositoryPath() {
+#ifdef LLD_REPOSITORY_STRING
+ return LLD_REPOSITORY_STRING;
+#else
+ return "";
+#endif
+}
+
+StringRef getLLDRevision() {
+#ifdef LLD_REVISION_STRING
+ return LLD_REVISION_STRING;
+#else
+ return "";
+#endif
+}
+
+std::string getLLDRepositoryVersion() {
+ std::string buf;
+ llvm::raw_string_ostream OS(buf);
+ std::string Path = getLLDRepositoryPath();
+ std::string Revision = getLLDRevision();
+ if (!Path.empty() || !Revision.empty()) {
+ OS << '(';
+ if (!Path.empty())
+ OS << Path;
+ if (!Revision.empty()) {
+ if (!Path.empty())
+ OS << ' ';
+ OS << Revision;
+ }
+ OS << ')';
+ }
+ return OS.str();
+}
+
+StringRef getLLDVersion() {
+#ifdef LLD_VERSION_STRING
+ return LLD_VERSION_STRING;
+#else
+ return "";
+#endif
+}
+
+} // end namespace lld
diff --git a/lib/Core/CMakeLists.txt b/lib/Core/CMakeLists.txt
new file mode 100644
index 000000000000..009b50a38335
--- /dev/null
+++ b/lib/Core/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_llvm_library(lldCore
+ DefinedAtom.cpp
+ Error.cpp
+ File.cpp
+ LinkingContext.cpp
+ Reader.cpp
+ Resolver.cpp
+ SymbolTable.cpp
+ Writer.cpp
+ LINK_LIBS
+ LLVMSupport
+ )
diff --git a/lib/Core/DefinedAtom.cpp b/lib/Core/DefinedAtom.cpp
new file mode 100644
index 000000000000..b3f81ca65a91
--- /dev/null
+++ b/lib/Core/DefinedAtom.cpp
@@ -0,0 +1,96 @@
+//===- DefinedAtom.cpp ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/ErrorHandling.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+
+namespace lld {
+
+DefinedAtom::ContentPermissions DefinedAtom::permissions() const {
+ // By default base permissions on content type.
+ return permissions(this->contentType());
+}
+
+// Utility function for deriving permissions from content type
+DefinedAtom::ContentPermissions DefinedAtom::permissions(ContentType type) {
+ switch (type) {
+ case typeCode:
+ case typeResolver:
+ case typeBranchIsland:
+ case typeBranchShim:
+ case typeStub:
+ case typeStubHelper:
+ case typeMachHeader:
+ return permR_X;
+
+ case typeConstant:
+ case typeCString:
+ case typeUTF16String:
+ case typeCFI:
+ case typeLSDA:
+ case typeLiteral4:
+ case typeLiteral8:
+ case typeLiteral16:
+ case typeDTraceDOF:
+ case typeCompactUnwindInfo:
+ case typeProcessedUnwindInfo:
+ case typeRONote:
+ case typeNoAlloc:
+ return permR__;
+
+ case typeData:
+ case typeDataFast:
+ case typeZeroFill:
+ case typeZeroFillFast:
+ case typeObjC1Class:
+ case typeLazyPointer:
+ case typeLazyDylibPointer:
+ case typeThunkTLV:
+ case typeRWNote:
+ return permRW_;
+
+ case typeGOT:
+ case typeConstData:
+ case typeCFString:
+ case typeInitializerPtr:
+ case typeTerminatorPtr:
+ case typeCStringPtr:
+ case typeObjCClassPtr:
+ case typeObjC2CategoryList:
+ case typeInterposingTuples:
+ case typeTLVInitialData:
+ case typeTLVInitialZeroFill:
+ case typeTLVInitializerPtr:
+ case typeThreadData:
+ case typeThreadZeroFill:
+ return permRW_L;
+
+ case typeGroupComdat:
+ case typeGnuLinkOnce:
+ case typeUnknown:
+ case typeTempLTO:
+ return permUnknown;
+ }
+ llvm_unreachable("unknown content type");
+}
+
+bool DefinedAtom::compareByPosition(const DefinedAtom *lhs,
+ const DefinedAtom *rhs) {
+ if (lhs == rhs)
+ return false;
+ const File *lhsFile = &lhs->file();
+ const File *rhsFile = &rhs->file();
+ if (lhsFile->ordinal() != rhsFile->ordinal())
+ return lhsFile->ordinal() < rhsFile->ordinal();
+ assert(lhs->ordinal() != rhs->ordinal());
+ return lhs->ordinal() < rhs->ordinal();
+}
+
+} // namespace
diff --git a/lib/Core/Error.cpp b/lib/Core/Error.cpp
new file mode 100644
index 000000000000..24809c3869e5
--- /dev/null
+++ b/lib/Core/Error.cpp
@@ -0,0 +1,151 @@
+//===- Error.cpp - system_error extensions for lld --------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/Error.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <mutex>
+#include <string>
+#include <vector>
+
+using namespace lld;
+
+class _NativeReaderErrorCategory : public std::error_category {
+public:
+ const char* name() const LLVM_NOEXCEPT override {
+ return "lld.native.reader";
+ }
+
+ std::string message(int ev) const override {
+ switch (static_cast<NativeReaderError>(ev)) {
+ case NativeReaderError::success:
+ return "Success";
+ case NativeReaderError::unknown_file_format:
+ return "Unknown file format";
+ case NativeReaderError::file_too_short:
+ return "file truncated";
+ case NativeReaderError::file_malformed:
+ return "file malformed";
+ case NativeReaderError::memory_error:
+ return "out of memory";
+ case NativeReaderError::unknown_chunk_type:
+ return "unknown chunk type";
+ case NativeReaderError::conflicting_target_machine:
+ return "conflicting target machine";
+ }
+ llvm_unreachable("An enumerator of NativeReaderError does not have a "
+ "message defined.");
+ }
+};
+
+const std::error_category &lld::native_reader_category() {
+ static _NativeReaderErrorCategory o;
+ return o;
+}
+
+class _YamlReaderErrorCategory : public std::error_category {
+public:
+ const char* name() const LLVM_NOEXCEPT override {
+ return "lld.yaml.reader";
+ }
+
+ std::string message(int ev) const override {
+ switch (static_cast<YamlReaderError>(ev)) {
+ case YamlReaderError::success:
+ return "Success";
+ case YamlReaderError::unknown_keyword:
+ return "Unknown keyword found in yaml file";
+ case YamlReaderError::illegal_value:
+ return "Bad value found in yaml file";
+ }
+ llvm_unreachable("An enumerator of YamlReaderError does not have a "
+ "message defined.");
+ }
+};
+
+const std::error_category &lld::YamlReaderCategory() {
+ static _YamlReaderErrorCategory o;
+ return o;
+}
+
+class _LinkerScriptReaderErrorCategory : public std::error_category {
+public:
+ const char *name() const LLVM_NOEXCEPT override {
+ return "lld.linker-script.reader";
+ }
+
+ std::string message(int ev) const override {
+ switch (static_cast<LinkerScriptReaderError>(ev)) {
+ case LinkerScriptReaderError::success:
+ return "Success";
+ case LinkerScriptReaderError::parse_error:
+ return "Error parsing linker script";
+ case LinkerScriptReaderError::unknown_symbol_in_expr:
+ return "Unknown symbol found when evaluating linker script expression";
+ case LinkerScriptReaderError::unrecognized_function_in_expr:
+ return "Unrecognized function call when evaluating linker script "
+ "expression";
+ }
+ llvm_unreachable("An enumerator of LinkerScriptReaderError does not have a "
+ "message defined.");
+ }
+};
+
+const std::error_category &lld::LinkerScriptReaderCategory() {
+ static _LinkerScriptReaderErrorCategory o;
+ return o;
+}
+
+
+namespace lld {
+
+/// Temporary class to enable make_dynamic_error_code() until
+/// llvm::ErrorOr<> is updated to work with error encapsulations
+/// other than error_code.
+class dynamic_error_category : public std::error_category {
+public:
+ ~dynamic_error_category() LLVM_NOEXCEPT {}
+
+ const char *name() const LLVM_NOEXCEPT override {
+ return "lld.dynamic_error";
+ }
+
+ std::string message(int ev) const override {
+ assert(ev >= 0);
+ assert(ev < (int)_messages.size());
+ // The value is an index into the string vector.
+ return _messages[ev];
+ }
+
+ int add(std::string msg) {
+ std::lock_guard<std::recursive_mutex> lock(_mutex);
+ // Value zero is always the successs value.
+ if (_messages.empty())
+ _messages.push_back("Success");
+ _messages.push_back(msg);
+ // Return the index of the string just appended.
+ return _messages.size() - 1;
+ }
+
+private:
+ std::vector<std::string> _messages;
+ std::recursive_mutex _mutex;
+};
+
+static dynamic_error_category categorySingleton;
+
+std::error_code make_dynamic_error_code(StringRef msg) {
+ return std::error_code(categorySingleton.add(msg), categorySingleton);
+}
+
+std::error_code make_dynamic_error_code(const Twine &msg) {
+ return std::error_code(categorySingleton.add(msg.str()), categorySingleton);
+}
+
+}
diff --git a/lib/Core/File.cpp b/lib/Core/File.cpp
new file mode 100644
index 000000000000..dbac86b368aa
--- /dev/null
+++ b/lib/Core/File.cpp
@@ -0,0 +1,30 @@
+//===- Core/File.cpp - A Container of Atoms -------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/File.h"
+#include "lld/Core/LLVM.h"
+#include <mutex>
+
+namespace lld {
+
+File::~File() {}
+
+File::atom_collection_empty<DefinedAtom> File::_noDefinedAtoms;
+File::atom_collection_empty<UndefinedAtom> File::_noUndefinedAtoms;
+File::atom_collection_empty<SharedLibraryAtom> File::_noSharedLibraryAtoms;
+File::atom_collection_empty<AbsoluteAtom> File::_noAbsoluteAtoms;
+
+std::error_code File::parse() {
+ std::lock_guard<std::mutex> lock(_parseMutex);
+ if (!_lastError.hasValue())
+ _lastError = doParse();
+ return _lastError.getValue();
+}
+
+} // namespace lld
diff --git a/lib/Core/LinkingContext.cpp b/lib/Core/LinkingContext.cpp
new file mode 100644
index 000000000000..c6656b935916
--- /dev/null
+++ b/lib/Core/LinkingContext.cpp
@@ -0,0 +1,104 @@
+//===- lib/Core/LinkingContext.cpp - Linker Context Object Interface ------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/Alias.h"
+#include "lld/Core/LinkingContext.h"
+#include "lld/Core/Resolver.h"
+#include "lld/Core/Simple.h"
+#include "lld/Core/Writer.h"
+#include "llvm/ADT/Triple.h"
+
+namespace lld {
+
+LinkingContext::LinkingContext()
+ : _deadStrip(false), _allowDuplicates(false),
+ _globalsAreDeadStripRoots(false),
+ _searchArchivesToOverrideTentativeDefinitions(false),
+ _searchSharedLibrariesToOverrideTentativeDefinitions(false),
+ _warnIfCoalesableAtomsHaveDifferentCanBeNull(false),
+ _warnIfCoalesableAtomsHaveDifferentLoadName(false),
+ _printRemainingUndefines(true), _allowRemainingUndefines(false),
+ _logInputFiles(false), _allowShlibUndefines(false),
+ _outputFileType(OutputFileType::Default), _nextOrdinal(0) {}
+
+LinkingContext::~LinkingContext() {}
+
+bool LinkingContext::validate(raw_ostream &diagnostics) {
+ return validateImpl(diagnostics);
+}
+
+std::error_code LinkingContext::writeFile(const File &linkedFile) const {
+ return this->writer().writeFile(linkedFile, _outputPath);
+}
+
+bool LinkingContext::createImplicitFiles(
+ std::vector<std::unique_ptr<File> > &result) {
+ return this->writer().createImplicitFiles(result);
+}
+
+std::unique_ptr<File> LinkingContext::createEntrySymbolFile() const {
+ return createEntrySymbolFile("<command line option -e>");
+}
+
+std::unique_ptr<File>
+LinkingContext::createEntrySymbolFile(StringRef filename) const {
+ if (entrySymbolName().empty())
+ return nullptr;
+ std::unique_ptr<SimpleFile> entryFile(new SimpleFile(filename));
+ entryFile->addAtom(
+ *(new (_allocator) SimpleUndefinedAtom(*entryFile, entrySymbolName())));
+ return std::move(entryFile);
+}
+
+std::unique_ptr<File> LinkingContext::createUndefinedSymbolFile() const {
+ return createUndefinedSymbolFile("<command line option -u or --defsym>");
+}
+
+std::unique_ptr<File>
+LinkingContext::createUndefinedSymbolFile(StringRef filename) const {
+ if (_initialUndefinedSymbols.empty())
+ return nullptr;
+ std::unique_ptr<SimpleFile> undefinedSymFile(new SimpleFile(filename));
+ for (StringRef undefSym : _initialUndefinedSymbols)
+ undefinedSymFile->addAtom(*(new (_allocator) SimpleUndefinedAtom(
+ *undefinedSymFile, undefSym)));
+ return std::move(undefinedSymFile);
+}
+
+std::unique_ptr<File> LinkingContext::createAliasSymbolFile() const {
+ if (getAliases().empty())
+ return nullptr;
+ std::unique_ptr<SimpleFile> file(new SimpleFile("<alias>"));
+ for (const auto &i : getAliases()) {
+ StringRef from = i.first;
+ StringRef to = i.second;
+ SimpleDefinedAtom *fromAtom = new (_allocator) AliasAtom(*file, from);
+ UndefinedAtom *toAtom = new (_allocator) SimpleUndefinedAtom(*file, to);
+ fromAtom->addReference(Reference::KindNamespace::all,
+ Reference::KindArch::all, Reference::kindLayoutAfter,
+ 0, toAtom, 0);
+ file->addAtom(*fromAtom);
+ file->addAtom(*toAtom);
+ }
+ return std::move(file);
+}
+
+void LinkingContext::createInternalFiles(
+ std::vector<std::unique_ptr<File> > &result) const {
+ if (std::unique_ptr<File> file = createEntrySymbolFile())
+ result.push_back(std::move(file));
+ if (std::unique_ptr<File> file = createUndefinedSymbolFile())
+ result.push_back(std::move(file));
+ if (std::unique_ptr<File> file = createAliasSymbolFile())
+ result.push_back(std::move(file));
+}
+
+void LinkingContext::addPasses(PassManager &pm) {}
+
+} // end namespace lld
diff --git a/lib/Core/Makefile b/lib/Core/Makefile
new file mode 100644
index 000000000000..042d01a1e1b3
--- /dev/null
+++ b/lib/Core/Makefile
@@ -0,0 +1,13 @@
+##===- lld/lib/Core/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 := lldCore
+
+include $(LLD_LEVEL)/Makefile
diff --git a/lib/Core/Reader.cpp b/lib/Core/Reader.cpp
new file mode 100644
index 000000000000..6f8b8cbd1bf8
--- /dev/null
+++ b/lib/Core/Reader.cpp
@@ -0,0 +1,117 @@
+//===- lib/Core/Reader.cpp ------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/File.h"
+#include "lld/Core/Reader.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/FileUtilities.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include <memory>
+#include <system_error>
+
+namespace lld {
+
+YamlIOTaggedDocumentHandler::~YamlIOTaggedDocumentHandler() {}
+
+void Registry::add(std::unique_ptr<Reader> reader) {
+ _readers.push_back(std::move(reader));
+}
+
+void Registry::add(std::unique_ptr<YamlIOTaggedDocumentHandler> handler) {
+ _yamlHandlers.push_back(std::move(handler));
+}
+
+std::error_code
+Registry::loadFile(std::unique_ptr<MemoryBuffer> mb,
+ std::vector<std::unique_ptr<File>> &result) const {
+ // Get file type.
+ StringRef content(mb->getBufferStart(), mb->getBufferSize());
+ llvm::sys::fs::file_magic fileType = llvm::sys::fs::identify_magic(content);
+ // Get file extension.
+ StringRef extension = llvm::sys::path::extension(mb->getBufferIdentifier());
+
+ // Ask each registered reader if it can handle this file type or extension.
+ for (const std::unique_ptr<Reader> &reader : _readers) {
+ if (!reader->canParse(fileType, extension, *mb))
+ continue;
+ if (std::error_code ec = reader->loadFile(std::move(mb), *this, result))
+ return ec;
+ return std::error_code();
+ }
+
+ // No Reader could parse this file.
+ return make_error_code(llvm::errc::executable_format_error);
+}
+
+static const Registry::KindStrings kindStrings[] = {
+ {Reference::kindLayoutAfter, "layout-after"},
+ {Reference::kindGroupChild, "group-child"},
+ {Reference::kindAssociate, "associate"},
+ LLD_KIND_STRING_END};
+
+Registry::Registry() {
+ addKindTable(Reference::KindNamespace::all, Reference::KindArch::all,
+ kindStrings);
+}
+
+bool Registry::handleTaggedDoc(llvm::yaml::IO &io,
+ const lld::File *&file) const {
+ for (const std::unique_ptr<YamlIOTaggedDocumentHandler> &h : _yamlHandlers)
+ if (h->handledDocTag(io, file))
+ return true;
+ return false;
+}
+
+
+void Registry::addKindTable(Reference::KindNamespace ns,
+ Reference::KindArch arch,
+ const KindStrings array[]) {
+ KindEntry entry = { ns, arch, array };
+ _kindEntries.push_back(entry);
+}
+
+bool Registry::referenceKindFromString(StringRef inputStr,
+ Reference::KindNamespace &ns,
+ Reference::KindArch &arch,
+ Reference::KindValue &value) const {
+ for (const KindEntry &entry : _kindEntries) {
+ for (const KindStrings *pair = entry.array; !pair->name.empty(); ++pair) {
+ if (!inputStr.equals(pair->name))
+ continue;
+ ns = entry.ns;
+ arch = entry.arch;
+ value = pair->value;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Registry::referenceKindToString(Reference::KindNamespace ns,
+ Reference::KindArch arch,
+ Reference::KindValue value,
+ StringRef &str) const {
+ for (const KindEntry &entry : _kindEntries) {
+ if (entry.ns != ns)
+ continue;
+ if (entry.arch != arch)
+ continue;
+ for (const KindStrings *pair = entry.array; !pair->name.empty(); ++pair) {
+ if (pair->value != value)
+ continue;
+ str = pair->name;
+ return true;
+ }
+ }
+ return false;
+}
+
+} // end namespace lld
diff --git a/lib/Core/Resolver.cpp b/lib/Core/Resolver.cpp
new file mode 100644
index 000000000000..393a7ef2bfc8
--- /dev/null
+++ b/lib/Core/Resolver.cpp
@@ -0,0 +1,516 @@
+//===- Core/Resolver.cpp - Resolves Atom References -----------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/Atom.h"
+#include "lld/Core/ArchiveLibraryFile.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Instrumentation.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/LinkingContext.h"
+#include "lld/Core/Resolver.h"
+#include "lld/Core/SharedLibraryFile.h"
+#include "lld/Core/SymbolTable.h"
+#include "lld/Core/UndefinedAtom.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <utility>
+#include <vector>
+
+namespace lld {
+
+bool Resolver::handleFile(File &file) {
+ bool undefAdded = false;
+ for (const DefinedAtom *atom : file.defined())
+ doDefinedAtom(*atom);
+ for (const UndefinedAtom *atom : file.undefined()) {
+ if (doUndefinedAtom(*atom)) {
+ undefAdded = true;
+ maybePreloadArchiveMember(atom->name());
+ }
+ }
+ for (const SharedLibraryAtom *atom : file.sharedLibrary())
+ doSharedLibraryAtom(*atom);
+ for (const AbsoluteAtom *atom : file.absolute())
+ doAbsoluteAtom(*atom);
+ return undefAdded;
+}
+
+void Resolver::forEachUndefines(File &file, bool searchForOverrides,
+ UndefCallback callback) {
+ size_t i = _undefineIndex[&file];
+ do {
+ for (; i < _undefines.size(); ++i) {
+ StringRef undefName = _undefines[i];
+ if (undefName.empty())
+ continue;
+ const Atom *atom = _symbolTable.findByName(undefName);
+ if (!isa<UndefinedAtom>(atom) || _symbolTable.isCoalescedAway(atom)) {
+ // The symbol was resolved by some other file. Cache the result.
+ _undefines[i] = "";
+ continue;
+ }
+ callback(undefName, false);
+ }
+ if (!searchForOverrides)
+ continue;
+ for (StringRef tentDefName : _symbolTable.tentativeDefinitions()) {
+ // Load for previous tentative may also have loaded
+ // something that overrode this tentative, so always check.
+ const Atom *curAtom = _symbolTable.findByName(tentDefName);
+ assert(curAtom != nullptr);
+ if (const DefinedAtom *curDefAtom = dyn_cast<DefinedAtom>(curAtom))
+ if (curDefAtom->merge() == DefinedAtom::mergeAsTentative)
+ callback(tentDefName, true);
+ }
+ } while (i < _undefines.size());
+ _undefineIndex[&file] = i;
+}
+
+bool Resolver::handleArchiveFile(File &file) {
+ ArchiveLibraryFile *archiveFile = cast<ArchiveLibraryFile>(&file);
+ bool searchForOverrides =
+ _ctx.searchArchivesToOverrideTentativeDefinitions();
+ bool undefAdded = false;
+ forEachUndefines(file, searchForOverrides,
+ [&](StringRef undefName, bool dataSymbolOnly) {
+ if (File *member = archiveFile->find(undefName, dataSymbolOnly)) {
+ member->setOrdinal(_ctx.getNextOrdinalAndIncrement());
+ member->beforeLink();
+ updatePreloadArchiveMap();
+ undefAdded = handleFile(*member) || undefAdded;
+ }
+ });
+ return undefAdded;
+}
+
+void Resolver::handleSharedLibrary(File &file) {
+ // Add all the atoms from the shared library
+ SharedLibraryFile *sharedLibrary = cast<SharedLibraryFile>(&file);
+ handleFile(*sharedLibrary);
+ bool searchForOverrides =
+ _ctx.searchSharedLibrariesToOverrideTentativeDefinitions();
+ forEachUndefines(file, searchForOverrides,
+ [&](StringRef undefName, bool dataSymbolOnly) {
+ if (const SharedLibraryAtom *atom =
+ sharedLibrary->exports(undefName, dataSymbolOnly))
+ doSharedLibraryAtom(*atom);
+ });
+}
+
+bool Resolver::doUndefinedAtom(const UndefinedAtom &atom) {
+ DEBUG_WITH_TYPE("resolver", llvm::dbgs()
+ << " UndefinedAtom: "
+ << llvm::format("0x%09lX", &atom)
+ << ", name=" << atom.name() << "\n");
+
+ // add to list of known atoms
+ _atoms.push_back(&atom);
+
+ // tell symbol table
+ bool newUndefAdded = _symbolTable.add(atom);
+ if (newUndefAdded)
+ _undefines.push_back(atom.name());
+
+ // If the undefined symbol has an alternative name, try to resolve the
+ // symbol with the name to give it a second chance. This feature is used
+ // for COFF "weak external" symbol.
+ if (newUndefAdded || !_symbolTable.isDefined(atom.name())) {
+ if (const UndefinedAtom *fallbackAtom = atom.fallback()) {
+ doUndefinedAtom(*fallbackAtom);
+ _symbolTable.addReplacement(&atom, fallbackAtom);
+ }
+ }
+ return newUndefAdded;
+}
+
+/// \brief Add the section group and the group-child reference members.
+void Resolver::maybeAddSectionGroupOrGnuLinkOnce(const DefinedAtom &atom) {
+ // First time adding a group?
+ bool isFirstTime = _symbolTable.addGroup(atom);
+
+ if (!isFirstTime) {
+ // If duplicate symbols are allowed, select the first group.
+ if (_ctx.getAllowDuplicates())
+ return;
+ auto *prevGroup = dyn_cast<DefinedAtom>(_symbolTable.findGroup(atom.name()));
+ assert(prevGroup &&
+ "Internal Error: The group atom could only be a defined atom");
+ // The atoms should be of the same content type, reject invalid group
+ // resolution behaviors.
+ if (atom.contentType() == prevGroup->contentType())
+ return;
+ llvm::errs() << "SymbolTable: error while merging " << atom.name()
+ << "\n";
+ llvm::report_fatal_error("duplicate symbol error");
+ return;
+ }
+
+ for (const Reference *r : atom) {
+ if (r->kindNamespace() == lld::Reference::KindNamespace::all &&
+ r->kindValue() == lld::Reference::kindGroupChild) {
+ const DefinedAtom *target = dyn_cast<DefinedAtom>(r->target());
+ assert(target && "Internal Error: kindGroupChild references need to "
+ "be associated with Defined Atoms only");
+ _atoms.push_back(target);
+ _symbolTable.add(*target);
+ }
+ }
+}
+
+// Called on each atom when a file is added. Returns true if a given
+// atom is added to the symbol table.
+void Resolver::doDefinedAtom(const DefinedAtom &atom) {
+ DEBUG_WITH_TYPE("resolver", llvm::dbgs()
+ << " DefinedAtom: "
+ << llvm::format("0x%09lX", &atom)
+ << ", file=#"
+ << atom.file().ordinal()
+ << ", atom=#"
+ << atom.ordinal()
+ << ", name="
+ << atom.name()
+ << "\n");
+
+ // add to list of known atoms
+ _atoms.push_back(&atom);
+
+ if (atom.isGroupParent()) {
+ maybeAddSectionGroupOrGnuLinkOnce(atom);
+ } else {
+ _symbolTable.add(atom);
+ }
+
+ // An atom that should never be dead-stripped is a dead-strip root.
+ if (_ctx.deadStrip() && atom.deadStrip() == DefinedAtom::deadStripNever) {
+ _deadStripRoots.insert(&atom);
+ }
+}
+
+void Resolver::doSharedLibraryAtom(const SharedLibraryAtom &atom) {
+ DEBUG_WITH_TYPE("resolver", llvm::dbgs()
+ << " SharedLibraryAtom: "
+ << llvm::format("0x%09lX", &atom)
+ << ", name="
+ << atom.name()
+ << "\n");
+
+ // add to list of known atoms
+ _atoms.push_back(&atom);
+
+ // tell symbol table
+ _symbolTable.add(atom);
+}
+
+void Resolver::doAbsoluteAtom(const AbsoluteAtom &atom) {
+ DEBUG_WITH_TYPE("resolver", llvm::dbgs()
+ << " AbsoluteAtom: "
+ << llvm::format("0x%09lX", &atom)
+ << ", name="
+ << atom.name()
+ << "\n");
+
+ // add to list of known atoms
+ _atoms.push_back(&atom);
+
+ // tell symbol table
+ if (atom.scope() != Atom::scopeTranslationUnit)
+ _symbolTable.add(atom);
+}
+
+// utility to add a vector of atoms
+void Resolver::addAtoms(const std::vector<const DefinedAtom *> &newAtoms) {
+ for (const DefinedAtom *newAtom : newAtoms)
+ doDefinedAtom(*newAtom);
+}
+
+// Instantiate an archive file member if there's a file containing a
+// defined symbol for a given symbol name. Instantiation is done in a
+// different worker thread and has no visible side effect.
+void Resolver::maybePreloadArchiveMember(StringRef sym) {
+ auto it = _archiveMap.find(sym);
+ if (it == _archiveMap.end())
+ return;
+ ArchiveLibraryFile *archive = it->second;
+ archive->preload(_ctx.getTaskGroup(), sym);
+}
+
+// Returns true if at least one of N previous files has created an
+// undefined symbol.
+bool Resolver::undefinesAdded(int begin, int end) {
+ std::vector<std::unique_ptr<Node>> &inputs = _ctx.getNodes();
+ for (int i = begin; i < end; ++i)
+ if (FileNode *node = dyn_cast<FileNode>(inputs[i].get()))
+ if (_newUndefinesAdded[node->getFile()])
+ return true;
+ return false;
+}
+
+File *Resolver::getFile(int &index) {
+ std::vector<std::unique_ptr<Node>> &inputs = _ctx.getNodes();
+ if ((size_t)index >= inputs.size())
+ return nullptr;
+ if (GroupEnd *group = dyn_cast<GroupEnd>(inputs[index].get())) {
+ // We are at the end of the current group. If one or more new
+ // undefined atom has been added in the last groupSize files, we
+ // reiterate over the files.
+ int size = group->getSize();
+ if (undefinesAdded(index - size, index)) {
+ index -= size;
+ return getFile(index);
+ }
+ ++index;
+ return getFile(index);
+ }
+ return cast<FileNode>(inputs[index++].get())->getFile();
+}
+
+// Update a map of Symbol -> ArchiveFile. The map is used for speculative
+// file loading.
+void Resolver::updatePreloadArchiveMap() {
+ std::vector<std::unique_ptr<Node>> &nodes = _ctx.getNodes();
+ for (int i = nodes.size() - 1; i >= 0; --i) {
+ auto *fnode = dyn_cast<FileNode>(nodes[i].get());
+ if (!fnode)
+ continue;
+ auto *archive = dyn_cast<ArchiveLibraryFile>(fnode->getFile());
+ if (!archive || _archiveSeen.count(archive))
+ continue;
+ _archiveSeen.insert(archive);
+ for (StringRef sym : archive->getDefinedSymbols())
+ _archiveMap[sym] = archive;
+ }
+}
+
+// Keep adding atoms until _ctx.getNextFile() returns an error. This
+// function is where undefined atoms are resolved.
+bool Resolver::resolveUndefines() {
+ ScopedTask task(getDefaultDomain(), "resolveUndefines");
+ int index = 0;
+ std::set<File *> seen;
+ for (;;) {
+ bool undefAdded = false;
+ File *file = getFile(index);
+ if (!file)
+ return true;
+ if (std::error_code ec = file->parse()) {
+ llvm::errs() << "Cannot open " + file->path()
+ << ": " << ec.message() << "\n";
+ return false;
+ }
+ file->beforeLink();
+ updatePreloadArchiveMap();
+ switch (file->kind()) {
+ case File::kindObject:
+ // The same file may be visited more than once if the file is
+ // in --start-group and --end-group. Only library files should
+ // be processed more than once.
+ if (seen.count(file))
+ break;
+ seen.insert(file);
+ assert(!file->hasOrdinal());
+ file->setOrdinal(_ctx.getNextOrdinalAndIncrement());
+ undefAdded = handleFile(*file);
+ break;
+ case File::kindArchiveLibrary:
+ if (!file->hasOrdinal())
+ file->setOrdinal(_ctx.getNextOrdinalAndIncrement());
+ undefAdded = handleArchiveFile(*file);
+ break;
+ case File::kindSharedLibrary:
+ if (!file->hasOrdinal())
+ file->setOrdinal(_ctx.getNextOrdinalAndIncrement());
+ handleSharedLibrary(*file);
+ break;
+ }
+ _newUndefinesAdded[file] = undefAdded;
+ }
+}
+
+// switch all references to undefined or coalesced away atoms
+// to the new defined atom
+void Resolver::updateReferences() {
+ ScopedTask task(getDefaultDomain(), "updateReferences");
+ for (const Atom *atom : _atoms) {
+ if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom)) {
+ for (const Reference *ref : *defAtom) {
+ // A reference of type kindAssociate should't be updated.
+ // Instead, an atom having such reference will be removed
+ // if the target atom is coalesced away, so that they will
+ // go away as a group.
+ if (ref->kindNamespace() == lld::Reference::KindNamespace::all &&
+ ref->kindValue() == lld::Reference::kindAssociate) {
+ if (_symbolTable.isCoalescedAway(atom))
+ _deadAtoms.insert(ref->target());
+ continue;
+ }
+ const Atom *newTarget = _symbolTable.replacement(ref->target());
+ const_cast<Reference *>(ref)->setTarget(newTarget);
+ }
+ }
+ }
+}
+
+// For dead code stripping, recursively mark atoms "live"
+void Resolver::markLive(const Atom *atom) {
+ // Mark the atom is live. If it's already marked live, then stop recursion.
+ auto exists = _liveAtoms.insert(atom);
+ if (!exists.second)
+ return;
+
+ // Mark all atoms it references as live
+ if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom)) {
+ for (const Reference *ref : *defAtom)
+ markLive(ref->target());
+ for (auto &p : llvm::make_range(_reverseRef.equal_range(defAtom))) {
+ const Atom *target = p.second;
+ markLive(target);
+ }
+ }
+}
+
+static bool isBackref(const Reference *ref) {
+ if (ref->kindNamespace() != lld::Reference::KindNamespace::all)
+ return false;
+ return (ref->kindValue() == lld::Reference::kindLayoutAfter ||
+ ref->kindValue() == lld::Reference::kindGroupChild);
+}
+
+// remove all atoms not actually used
+void Resolver::deadStripOptimize() {
+ ScopedTask task(getDefaultDomain(), "deadStripOptimize");
+ // only do this optimization with -dead_strip
+ if (!_ctx.deadStrip())
+ return;
+
+ // Some type of references prevent referring atoms to be dead-striped.
+ // Make a reverse map of such references before traversing the graph.
+ // While traversing the list of atoms, mark AbsoluteAtoms as live
+ // in order to avoid reclaim.
+ for (const Atom *atom : _atoms) {
+ if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom))
+ for (const Reference *ref : *defAtom)
+ if (isBackref(ref))
+ _reverseRef.insert(std::make_pair(ref->target(), atom));
+ if (const AbsoluteAtom *absAtom = dyn_cast<AbsoluteAtom>(atom))
+ markLive(absAtom);
+ }
+
+ // By default, shared libraries are built with all globals as dead strip roots
+ if (_ctx.globalsAreDeadStripRoots())
+ for (const Atom *atom : _atoms)
+ if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom))
+ if (defAtom->scope() == DefinedAtom::scopeGlobal)
+ _deadStripRoots.insert(defAtom);
+
+ // Or, use list of names that are dead strip roots.
+ for (const StringRef &name : _ctx.deadStripRoots()) {
+ const Atom *symAtom = _symbolTable.findByName(name);
+ assert(symAtom);
+ _deadStripRoots.insert(symAtom);
+ }
+
+ // mark all roots as live, and recursively all atoms they reference
+ for (const Atom *dsrAtom : _deadStripRoots)
+ markLive(dsrAtom);
+
+ // now remove all non-live atoms from _atoms
+ _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), [&](const Atom *a) {
+ return _liveAtoms.count(a) == 0;
+ }),
+ _atoms.end());
+}
+
+// error out if some undefines remain
+bool Resolver::checkUndefines() {
+ // build vector of remaining undefined symbols
+ std::vector<const UndefinedAtom *> undefinedAtoms = _symbolTable.undefines();
+ if (_ctx.deadStrip()) {
+ // When dead code stripping, we don't care if dead atoms are undefined.
+ undefinedAtoms.erase(
+ std::remove_if(undefinedAtoms.begin(), undefinedAtoms.end(),
+ [&](const Atom *a) { return _liveAtoms.count(a) == 0; }),
+ undefinedAtoms.end());
+ }
+
+ if (undefinedAtoms.empty())
+ return false;
+
+ // Warn about unresolved symbols.
+ bool foundUndefines = false;
+ for (const UndefinedAtom *undef : undefinedAtoms) {
+ // Skip over a weak symbol.
+ if (undef->canBeNull() != UndefinedAtom::canBeNullNever)
+ continue;
+
+ // If this is a library and undefined symbols are allowed on the
+ // target platform, skip over it.
+ if (isa<SharedLibraryFile>(undef->file()) && _ctx.allowShlibUndefines())
+ continue;
+
+ // If the undefine is coalesced away, skip over it.
+ if (_symbolTable.isCoalescedAway(undef))
+ continue;
+
+ // Seems like this symbol is undefined. Warn that.
+ foundUndefines = true;
+ if (_ctx.printRemainingUndefines()) {
+ llvm::errs() << "Undefined symbol: " << undef->file().path()
+ << ": " << _ctx.demangle(undef->name())
+ << "\n";
+ }
+ }
+ if (!foundUndefines)
+ return false;
+ if (_ctx.printRemainingUndefines())
+ llvm::errs() << "symbol(s) not found\n";
+ return true;
+}
+
+// remove from _atoms all coaleseced away atoms
+void Resolver::removeCoalescedAwayAtoms() {
+ ScopedTask task(getDefaultDomain(), "removeCoalescedAwayAtoms");
+ _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), [&](const Atom *a) {
+ return _symbolTable.isCoalescedAway(a) || _deadAtoms.count(a);
+ }),
+ _atoms.end());
+}
+
+bool Resolver::resolve() {
+ updatePreloadArchiveMap();
+ if (!resolveUndefines())
+ return false;
+ updateReferences();
+ deadStripOptimize();
+ if (checkUndefines())
+ if (!_ctx.allowRemainingUndefines())
+ return false;
+ removeCoalescedAwayAtoms();
+ _result->addAtoms(_atoms);
+ return true;
+}
+
+void Resolver::MergedFile::addAtoms(std::vector<const Atom *> &all) {
+ ScopedTask task(getDefaultDomain(), "addAtoms");
+ DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "Resolver final atom list:\n");
+ for (const Atom *atom : all) {
+ DEBUG_WITH_TYPE("resolver", llvm::dbgs()
+ << llvm::format(" 0x%09lX", atom)
+ << ", name="
+ << atom->name()
+ << "\n");
+ addAtom(*atom);
+ }
+}
+
+} // namespace lld
diff --git a/lib/Core/SymbolTable.cpp b/lib/Core/SymbolTable.cpp
new file mode 100644
index 000000000000..f3f2da9262e0
--- /dev/null
+++ b/lib/Core/SymbolTable.cpp
@@ -0,0 +1,390 @@
+//===- Core/SymbolTable.cpp - Main Symbol Table ---------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/SymbolTable.h"
+#include "lld/Core/AbsoluteAtom.h"
+#include "lld/Core/Atom.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/LinkingContext.h"
+#include "lld/Core/Resolver.h"
+#include "lld/Core/SharedLibraryAtom.h"
+#include "lld/Core/UndefinedAtom.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdlib>
+#include <vector>
+
+namespace lld {
+SymbolTable::SymbolTable(LinkingContext &context) : _context(context) {}
+
+bool SymbolTable::add(const UndefinedAtom &atom) { return addByName(atom); }
+
+bool SymbolTable::add(const SharedLibraryAtom &atom) { return addByName(atom); }
+
+bool SymbolTable::add(const AbsoluteAtom &atom) { return addByName(atom); }
+
+bool SymbolTable::add(const DefinedAtom &atom) {
+ if (!atom.name().empty() &&
+ atom.scope() != DefinedAtom::scopeTranslationUnit) {
+ // Named atoms cannot be merged by content.
+ assert(atom.merge() != DefinedAtom::mergeByContent);
+ // Track named atoms that are not scoped to file (static).
+ return addByName(atom);
+ }
+ if (atom.merge() == DefinedAtom::mergeByContent) {
+ // Named atoms cannot be merged by content.
+ assert(atom.name().empty());
+ // Currently only read-only constants can be merged.
+ if (atom.permissions() == DefinedAtom::permR__)
+ return addByContent(atom);
+ // TODO: support mergeByContent of data atoms by comparing content & fixups.
+ }
+ return false;
+}
+
+const Atom *SymbolTable::findGroup(StringRef sym) {
+ NameToAtom::iterator pos = _groupTable.find(sym);
+ if (pos == _groupTable.end())
+ return nullptr;
+ return pos->second;
+}
+
+bool SymbolTable::addGroup(const DefinedAtom &da) {
+ StringRef name = da.name();
+ assert(!name.empty());
+ const Atom *existing = findGroup(name);
+ if (existing == nullptr) {
+ _groupTable[name] = &da;
+ return true;
+ }
+ _replacedAtoms[&da] = existing;
+ return false;
+}
+
+enum NameCollisionResolution {
+ NCR_First,
+ NCR_Second,
+ NCR_DupDef,
+ NCR_DupUndef,
+ NCR_DupShLib,
+ NCR_Error
+};
+
+static NameCollisionResolution cases[4][4] = {
+ //regular absolute undef sharedLib
+ {
+ // first is regular
+ NCR_DupDef, NCR_Error, NCR_First, NCR_First
+ },
+ {
+ // first is absolute
+ NCR_Error, NCR_Error, NCR_First, NCR_First
+ },
+ {
+ // first is undef
+ NCR_Second, NCR_Second, NCR_DupUndef, NCR_Second
+ },
+ {
+ // first is sharedLib
+ NCR_Second, NCR_Second, NCR_First, NCR_DupShLib
+ }
+};
+
+static NameCollisionResolution collide(Atom::Definition first,
+ Atom::Definition second) {
+ return cases[first][second];
+}
+
+enum MergeResolution {
+ MCR_First,
+ MCR_Second,
+ MCR_Largest,
+ MCR_SameSize,
+ MCR_Error
+};
+
+static MergeResolution mergeCases[][6] = {
+ // no tentative weak weakAddress sameNameAndSize largest
+ {MCR_Error, MCR_First, MCR_First, MCR_First, MCR_SameSize, MCR_Largest}, // no
+ {MCR_Second, MCR_Largest, MCR_Second, MCR_Second, MCR_SameSize, MCR_Largest}, // tentative
+ {MCR_Second, MCR_First, MCR_First, MCR_Second, MCR_SameSize, MCR_Largest}, // weak
+ {MCR_Second, MCR_First, MCR_First, MCR_First, MCR_SameSize, MCR_Largest}, // weakAddress
+ {MCR_SameSize, MCR_SameSize, MCR_SameSize, MCR_SameSize, MCR_SameSize, MCR_SameSize}, // sameSize
+ {MCR_Largest, MCR_Largest, MCR_Largest, MCR_Largest, MCR_SameSize, MCR_Largest}, // largest
+};
+
+static MergeResolution mergeSelect(DefinedAtom::Merge first,
+ DefinedAtom::Merge second) {
+ assert(first != DefinedAtom::mergeByContent);
+ assert(second != DefinedAtom::mergeByContent);
+ return mergeCases[first][second];
+}
+
+bool SymbolTable::addByName(const Atom &newAtom) {
+ StringRef name = newAtom.name();
+ assert(!name.empty());
+ const Atom *existing = findByName(name);
+ if (existing == nullptr) {
+ // Name is not in symbol table yet, add it associate with this atom.
+ _nameTable[name] = &newAtom;
+ return true;
+ }
+
+ // Do nothing if the same object is added more than once.
+ if (existing == &newAtom)
+ return false;
+
+ // Name is already in symbol table and associated with another atom.
+ bool useNew = true;
+ switch (collide(existing->definition(), newAtom.definition())) {
+ case NCR_First:
+ useNew = false;
+ break;
+ case NCR_Second:
+ useNew = true;
+ break;
+ case NCR_DupDef: {
+ const auto *existingDef = cast<DefinedAtom>(existing);
+ const auto *newDef = cast<DefinedAtom>(&newAtom);
+ switch (mergeSelect(existingDef->merge(), newDef->merge())) {
+ case MCR_First:
+ useNew = false;
+ break;
+ case MCR_Second:
+ useNew = true;
+ break;
+ case MCR_Largest: {
+ uint64_t existingSize = existingDef->sectionSize();
+ uint64_t newSize = newDef->sectionSize();
+ useNew = (newSize >= existingSize);
+ break;
+ }
+ case MCR_SameSize: {
+ uint64_t existingSize = existingDef->sectionSize();
+ uint64_t newSize = newDef->sectionSize();
+ if (existingSize == newSize) {
+ useNew = true;
+ break;
+ }
+ llvm::errs() << "Size mismatch: "
+ << existing->name() << " (" << existingSize << ") "
+ << newAtom.name() << " (" << newSize << ")\n";
+ // fallthrough
+ }
+ case MCR_Error:
+ if (!_context.getAllowDuplicates()) {
+ llvm::errs() << "Duplicate symbols: "
+ << existing->name()
+ << ":"
+ << existing->file().path()
+ << " and "
+ << newAtom.name()
+ << ":"
+ << newAtom.file().path()
+ << "\n";
+ llvm::report_fatal_error("duplicate symbol error");
+ }
+ useNew = false;
+ break;
+ }
+ break;
+ }
+ case NCR_DupUndef: {
+ const UndefinedAtom* existingUndef = cast<UndefinedAtom>(existing);
+ const UndefinedAtom* newUndef = cast<UndefinedAtom>(&newAtom);
+
+ bool sameCanBeNull = (existingUndef->canBeNull() == newUndef->canBeNull());
+ if (!sameCanBeNull &&
+ _context.warnIfCoalesableAtomsHaveDifferentCanBeNull()) {
+ llvm::errs() << "lld warning: undefined symbol "
+ << existingUndef->name()
+ << " has different weakness in "
+ << existingUndef->file().path()
+ << " and in " << newUndef->file().path() << "\n";
+ }
+
+ const UndefinedAtom *existingFallback = existingUndef->fallback();
+ const UndefinedAtom *newFallback = newUndef->fallback();
+ bool hasDifferentFallback =
+ (existingFallback && newFallback &&
+ existingFallback->name() != newFallback->name());
+ if (hasDifferentFallback) {
+ llvm::errs() << "lld warning: undefined symbol "
+ << existingUndef->name() << " has different fallback: "
+ << existingFallback->name() << " in "
+ << existingUndef->file().path() << " and "
+ << newFallback->name() << " in "
+ << newUndef->file().path() << "\n";
+ }
+
+ bool hasNewFallback = newUndef->fallback();
+ if (sameCanBeNull)
+ useNew = hasNewFallback;
+ else
+ useNew = (newUndef->canBeNull() < existingUndef->canBeNull());
+ break;
+ }
+ case NCR_DupShLib: {
+ const SharedLibraryAtom *curShLib = cast<SharedLibraryAtom>(existing);
+ const SharedLibraryAtom *newShLib = cast<SharedLibraryAtom>(&newAtom);
+ bool sameNullness =
+ (curShLib->canBeNullAtRuntime() == newShLib->canBeNullAtRuntime());
+ bool sameName = curShLib->loadName().equals(newShLib->loadName());
+ if (sameName && !sameNullness &&
+ _context.warnIfCoalesableAtomsHaveDifferentCanBeNull()) {
+ // FIXME: need diagonstics interface for writing warning messages
+ llvm::errs() << "lld warning: shared library symbol "
+ << curShLib->name() << " has different weakness in "
+ << curShLib->file().path() << " and in "
+ << newShLib->file().path();
+ }
+ if (!sameName && _context.warnIfCoalesableAtomsHaveDifferentLoadName()) {
+ // FIXME: need diagonstics interface for writing warning messages
+ llvm::errs() << "lld warning: shared library symbol "
+ << curShLib->name() << " has different load path in "
+ << curShLib->file().path() << " and in "
+ << newShLib->file().path();
+ }
+ useNew = false;
+ break;
+ }
+ case NCR_Error:
+ llvm::errs() << "SymbolTable: error while merging " << name << "\n";
+ llvm::report_fatal_error("duplicate symbol error");
+ break;
+ }
+
+ // Give context a chance to change which is kept.
+ _context.notifySymbolTableCoalesce(existing, &newAtom, useNew);
+
+ if (useNew) {
+ // Update name table to use new atom.
+ _nameTable[name] = &newAtom;
+ // Add existing atom to replacement table.
+ _replacedAtoms[existing] = &newAtom;
+ } else {
+ // New atom is not being used. Add it to replacement table.
+ _replacedAtoms[&newAtom] = existing;
+ }
+ return false;
+}
+
+unsigned SymbolTable::AtomMappingInfo::getHashValue(const DefinedAtom *atom) {
+ auto content = atom->rawContent();
+ return llvm::hash_combine(atom->size(),
+ atom->contentType(),
+ llvm::hash_combine_range(content.begin(),
+ content.end()));
+}
+
+bool SymbolTable::AtomMappingInfo::isEqual(const DefinedAtom * const l,
+ const DefinedAtom * const r) {
+ if (l == r)
+ return true;
+ if (l == getEmptyKey())
+ return false;
+ if (r == getEmptyKey())
+ return false;
+ if (l == getTombstoneKey())
+ return false;
+ if (r == getTombstoneKey())
+ return false;
+ if (l->contentType() != r->contentType())
+ return false;
+ if (l->size() != r->size())
+ return false;
+ if (l->sectionChoice() != r->sectionChoice())
+ return false;
+ if (l->sectionChoice() == DefinedAtom::sectionCustomRequired) {
+ if (!l->customSectionName().equals(r->customSectionName()))
+ return false;
+ }
+ ArrayRef<uint8_t> lc = l->rawContent();
+ ArrayRef<uint8_t> rc = r->rawContent();
+ return memcmp(lc.data(), rc.data(), lc.size()) == 0;
+}
+
+bool SymbolTable::addByContent(const DefinedAtom &newAtom) {
+ AtomContentSet::iterator pos = _contentTable.find(&newAtom);
+ if (pos == _contentTable.end()) {
+ _contentTable.insert(&newAtom);
+ return true;
+ }
+ const Atom* existing = *pos;
+ // New atom is not being used. Add it to replacement table.
+ _replacedAtoms[&newAtom] = existing;
+ return false;
+}
+
+const Atom *SymbolTable::findByName(StringRef sym) {
+ NameToAtom::iterator pos = _nameTable.find(sym);
+ if (pos == _nameTable.end())
+ return nullptr;
+ return pos->second;
+}
+
+bool SymbolTable::isDefined(StringRef sym) {
+ if (const Atom *atom = findByName(sym))
+ return !isa<UndefinedAtom>(atom);
+ return false;
+}
+
+void SymbolTable::addReplacement(const Atom *replaced,
+ const Atom *replacement) {
+ _replacedAtoms[replaced] = replacement;
+}
+
+const Atom *SymbolTable::replacement(const Atom *atom) {
+ // Find the replacement for a given atom. Atoms in _replacedAtoms
+ // may be chained, so find the last one.
+ for (;;) {
+ AtomToAtom::iterator pos = _replacedAtoms.find(atom);
+ if (pos == _replacedAtoms.end())
+ return atom;
+ atom = pos->second;
+ }
+}
+
+bool SymbolTable::isCoalescedAway(const Atom *atom) {
+ return _replacedAtoms.count(atom) > 0;
+}
+
+std::vector<const UndefinedAtom *> SymbolTable::undefines() {
+ std::vector<const UndefinedAtom *> ret;
+ for (auto it : _nameTable) {
+ const Atom *atom = it.second;
+ assert(atom != nullptr);
+ if (const auto *undef = dyn_cast<const UndefinedAtom>(atom))
+ if (_replacedAtoms.count(undef) == 0)
+ ret.push_back(undef);
+ }
+ return ret;
+}
+
+std::vector<StringRef> SymbolTable::tentativeDefinitions() {
+ std::vector<StringRef> ret;
+ for (auto entry : _nameTable) {
+ const Atom *atom = entry.second;
+ StringRef name = entry.first;
+ assert(atom != nullptr);
+ if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom))
+ if (defAtom->merge() == DefinedAtom::mergeAsTentative)
+ ret.push_back(name);
+ }
+ return ret;
+}
+
+} // namespace lld
diff --git a/lib/Core/TODO.txt b/lib/Core/TODO.txt
new file mode 100644
index 000000000000..196a3e02c2fc
--- /dev/null
+++ b/lib/Core/TODO.txt
@@ -0,0 +1,18 @@
+lib/Core
+~~~~~~~~
+
+* Add endianness support to the native reader and writer.
+
+* The NativeReader has lots of similar code for converting arrays of ivar
+ data in mapped memory into arrays of objects. The commonality can be
+ factored out, maybe templatized.
+
+* The NativeFileFormat.h is old school C structs and constants. We scope
+ things better by defining constants used with a struct inside the struct
+ declaration.
+
+* The native reader and writer currently just blast in memory enumeration
+ values (e.g. DefinedAtom::Scope) into a byte in the disk format. To support
+ future changes to the enumerations, there should be a translation layer
+ to map disk values to in-memory values.
+
diff --git a/lib/Core/Writer.cpp b/lib/Core/Writer.cpp
new file mode 100644
index 000000000000..39bcc9e68523
--- /dev/null
+++ b/lib/Core/Writer.cpp
@@ -0,0 +1,23 @@
+//===- lib/Core/Writer.cpp ------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/File.h"
+#include "lld/Core/Writer.h"
+
+namespace lld {
+Writer::Writer() {
+}
+
+Writer::~Writer() {
+}
+
+bool Writer::createImplicitFiles(std::vector<std::unique_ptr<File> > &) {
+ return true;
+}
+} // end namespace lld
diff --git a/lib/Driver/CMakeLists.txt b/lib/Driver/CMakeLists.txt
new file mode 100644
index 000000000000..5a410e7eed7e
--- /dev/null
+++ b/lib/Driver/CMakeLists.txt
@@ -0,0 +1,43 @@
+set(LLVM_TARGET_DEFINITIONS UniversalDriverOptions.td)
+tablegen(LLVM UniversalDriverOptions.inc -gen-opt-parser-defs)
+set(LLVM_TARGET_DEFINITIONS GnuLdOptions.td)
+tablegen(LLVM GnuLdOptions.inc -gen-opt-parser-defs)
+set(LLVM_TARGET_DEFINITIONS CoreOptions.td)
+tablegen(LLVM CoreOptions.inc -gen-opt-parser-defs)
+set(LLVM_TARGET_DEFINITIONS DarwinLdOptions.td)
+tablegen(LLVM DarwinLdOptions.inc -gen-opt-parser-defs)
+set(LLVM_TARGET_DEFINITIONS WinLinkOptions.td)
+tablegen(LLVM WinLinkOptions.inc -gen-opt-parser-defs)
+add_public_tablegen_target(DriverOptionsTableGen)
+
+add_llvm_library(lldDriver
+ CoreDriver.cpp
+ DarwinLdDriver.cpp
+ Driver.cpp
+ GnuLdDriver.cpp
+ UniversalDriver.cpp
+ WinLinkDriver.cpp
+ WinLinkModuleDef.cpp
+ LINK_LIBS
+ lldConfig
+ lldMachO
+ lldPECOFF
+ lldELF
+ lldAArch64ELFTarget
+ lldARMELFTarget
+ lldHexagonELFTarget
+ lldMipsELFTarget
+ lldX86ELFTarget
+ lldExampleSubTarget
+ lldX86_64ELFTarget
+ lldCore
+ lldNative
+ lldReaderWriter
+ lldYAML
+ LLVMObject
+ LLVMOption
+ LLVMSupport
+ )
+
+add_dependencies(lldDriver DriverOptionsTableGen)
+
diff --git a/lib/Driver/CoreDriver.cpp b/lib/Driver/CoreDriver.cpp
new file mode 100644
index 000000000000..b8adee55746f
--- /dev/null
+++ b/lib/Driver/CoreDriver.cpp
@@ -0,0 +1,172 @@
+//===- lib/Driver/CoreDriver.cpp ------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/Reader.h"
+#include "lld/Driver/Driver.h"
+#include "lld/ReaderWriter/CoreLinkingContext.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace lld;
+
+namespace {
+
+// Create enum with OPT_xxx values for each option in CoreOptions.td
+enum {
+ OPT_INVALID = 0,
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELP, META) \
+ OPT_##ID,
+#include "CoreOptions.inc"
+#undef OPTION
+};
+
+// Create prefix string literals used in CoreOptions.td
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#include "CoreOptions.inc"
+#undef PREFIX
+
+// Create table mapping all options defined in CoreOptions.td
+static const llvm::opt::OptTable::Info infoTable[] = {
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR) \
+ { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \
+ PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS },
+#include "CoreOptions.inc"
+#undef OPTION
+};
+
+// Create OptTable class for parsing actual command line arguments
+class CoreOptTable : public llvm::opt::OptTable {
+public:
+ CoreOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable)){}
+};
+
+} // namespace anonymous
+
+
+namespace lld {
+
+static const Registry::KindStrings coreKindStrings[] = {
+ { CoreLinkingContext::TEST_RELOC_CALL32, "call32" },
+ { CoreLinkingContext::TEST_RELOC_PCREL32, "pcrel32" },
+ { CoreLinkingContext::TEST_RELOC_GOT_LOAD32, "gotLoad32" },
+ { CoreLinkingContext::TEST_RELOC_GOT_USE32, "gotUse32" },
+ { CoreLinkingContext::TEST_RELOC_LEA32_WAS_GOT, "lea32wasGot" },
+ LLD_KIND_STRING_END
+};
+
+bool CoreDriver::link(int argc, const char *argv[], raw_ostream &diagnostics) {
+ CoreLinkingContext ctx;
+
+ // Register possible input file parsers.
+ ctx.registry().addSupportNativeObjects();
+ ctx.registry().addSupportYamlFiles();
+ ctx.registry().addKindTable(Reference::KindNamespace::testing,
+ Reference::KindArch::all, coreKindStrings);
+
+ if (!parse(argc, argv, ctx))
+ return false;
+ return Driver::link(ctx);
+}
+
+bool CoreDriver::parse(int argc, const char *argv[], CoreLinkingContext &ctx,
+ raw_ostream &diagnostics) {
+ // Parse command line options using CoreOptions.td
+ std::unique_ptr<llvm::opt::InputArgList> parsedArgs;
+ CoreOptTable table;
+ unsigned missingIndex;
+ unsigned missingCount;
+ parsedArgs.reset(
+ table.ParseArgs(&argv[1], &argv[argc], missingIndex, missingCount));
+ if (missingCount) {
+ diagnostics << "error: missing arg value for '"
+ << parsedArgs->getArgString(missingIndex) << "' expected "
+ << missingCount << " argument(s).\n";
+ return false;
+ }
+
+ // Set default options
+ ctx.setOutputPath("-");
+ ctx.setDeadStripping(false);
+ ctx.setGlobalsAreDeadStripRoots(false);
+ ctx.setPrintRemainingUndefines(false);
+ ctx.setAllowRemainingUndefines(true);
+ ctx.setSearchArchivesToOverrideTentativeDefinitions(false);
+
+ // Process all the arguments and create input files.
+ for (auto inputArg : *parsedArgs) {
+ switch (inputArg->getOption().getID()) {
+ case OPT_mllvm:
+ ctx.appendLLVMOption(inputArg->getValue());
+ break;
+
+ case OPT_entry:
+ ctx.setEntrySymbolName(inputArg->getValue());
+ break;
+
+ case OPT_output:
+ ctx.setOutputPath(inputArg->getValue());
+ break;
+
+ case OPT_dead_strip:
+ ctx.setDeadStripping(true);
+ break;
+
+ case OPT_keep_globals:
+ ctx.setGlobalsAreDeadStripRoots(true);
+ break;
+
+ case OPT_undefines_are_errors:
+ ctx.setPrintRemainingUndefines(true);
+ ctx.setAllowRemainingUndefines(false);
+ break;
+
+ case OPT_commons_search_archives:
+ ctx.setSearchArchivesToOverrideTentativeDefinitions(true);
+ break;
+
+ case OPT_add_pass:
+ ctx.addPassNamed(inputArg->getValue());
+ break;
+
+ case OPT_INPUT: {
+ std::vector<std::unique_ptr<File>> files
+ = loadFile(ctx, inputArg->getValue(), false);
+ for (std::unique_ptr<File> &file : files)
+ ctx.getNodes().push_back(llvm::make_unique<FileNode>(std::move(file)));
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+
+ if (ctx.getNodes().empty()) {
+ diagnostics << "No input files\n";
+ return false;
+ }
+
+ // Validate the combination of options used.
+ return ctx.validate(diagnostics);
+}
+
+} // namespace lld
diff --git a/lib/Driver/CoreOptions.td b/lib/Driver/CoreOptions.td
new file mode 100644
index 000000000000..df7cb41737d2
--- /dev/null
+++ b/lib/Driver/CoreOptions.td
@@ -0,0 +1,15 @@
+include "llvm/Option/OptParser.td"
+
+def output : Separate<["-"], "o">;
+def entry : Separate<["-"], "e">;
+
+def dead_strip : Flag<["--"], "dead-strip">;
+def undefines_are_errors : Flag<["--"], "undefines-are-errors">;
+def keep_globals : Flag<["--"], "keep-globals">;
+def commons_search_archives : Flag<["--"], "commons-search-archives">;
+
+def add_pass : Separate<["--"], "add-pass">;
+
+def target : Separate<["-"], "target">, HelpText<"Target triple to link for">;
+def mllvm : Separate<["-"], "mllvm">, HelpText<"Options to pass to LLVM">;
+
diff --git a/lib/Driver/DarwinLdDriver.cpp b/lib/Driver/DarwinLdDriver.cpp
new file mode 100644
index 000000000000..2c64aeee38a5
--- /dev/null
+++ b/lib/Driver/DarwinLdDriver.cpp
@@ -0,0 +1,832 @@
+//===- lib/Driver/DarwinLdDriver.cpp --------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+///
+/// Concrete instance of the Driver for darwin's ld.
+///
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/File.h"
+#include "lld/Core/ArchiveLibraryFile.h"
+#include "lld/Core/SharedLibraryFile.h"
+#include "lld/Driver/Driver.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/MachO.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+
+using namespace lld;
+
+namespace {
+
+// Create enum with OPT_xxx values for each option in DarwinLdOptions.td
+enum {
+ OPT_INVALID = 0,
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELP, META) \
+ OPT_##ID,
+#include "DarwinLdOptions.inc"
+#undef OPTION
+};
+
+// Create prefix string literals used in DarwinLdOptions.td
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#include "DarwinLdOptions.inc"
+#undef PREFIX
+
+// Create table mapping all options defined in DarwinLdOptions.td
+static const llvm::opt::OptTable::Info infoTable[] = {
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR) \
+ { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \
+ PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS },
+#include "DarwinLdOptions.inc"
+#undef OPTION
+};
+
+// Create OptTable class for parsing actual command line arguments
+class DarwinLdOptTable : public llvm::opt::OptTable {
+public:
+ DarwinLdOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable)){}
+};
+
+std::vector<std::unique_ptr<File>>
+loadFile(MachOLinkingContext &ctx, StringRef path,
+ raw_ostream &diag, bool wholeArchive, bool upwardDylib) {
+ if (ctx.logInputFiles())
+ diag << path << "\n";
+
+ ErrorOr<std::unique_ptr<MemoryBuffer>> mbOrErr = ctx.getMemoryBuffer(path);
+ if (std::error_code ec = mbOrErr.getError())
+ return makeErrorFile(path, ec);
+ std::vector<std::unique_ptr<File>> files;
+ if (std::error_code ec = ctx.registry().loadFile(std::move(mbOrErr.get()), files))
+ return makeErrorFile(path, ec);
+ for (std::unique_ptr<File> &pf : files) {
+ // If file is a dylib, inform LinkingContext about it.
+ if (SharedLibraryFile *shl = dyn_cast<SharedLibraryFile>(pf.get())) {
+ if (std::error_code ec = shl->parse())
+ return makeErrorFile(path, ec);
+ ctx.registerDylib(reinterpret_cast<mach_o::MachODylibFile*>(shl),
+ upwardDylib);
+ }
+ }
+ if (wholeArchive)
+ return parseMemberFiles(files);
+ return files;
+}
+
+} // anonymous namespace
+
+// Test may be running on Windows. Canonicalize the path
+// separator to '/' to get consistent outputs for tests.
+static std::string canonicalizePath(StringRef path) {
+ char sep = llvm::sys::path::get_separator().front();
+ if (sep != '/') {
+ std::string fixedPath = path;
+ std::replace(fixedPath.begin(), fixedPath.end(), sep, '/');
+ return fixedPath;
+ } else {
+ return path;
+ }
+}
+
+static void addFile(StringRef path, MachOLinkingContext &ctx,
+ bool loadWholeArchive,
+ bool upwardDylib, raw_ostream &diag) {
+ std::vector<std::unique_ptr<File>> files =
+ loadFile(ctx, path, diag, loadWholeArchive, upwardDylib);
+ for (std::unique_ptr<File> &file : files)
+ ctx.getNodes().push_back(llvm::make_unique<FileNode>(std::move(file)));
+}
+
+// Export lists are one symbol per line. Blank lines are ignored.
+// Trailing comments start with #.
+static std::error_code parseExportsList(StringRef exportFilePath,
+ MachOLinkingContext &ctx,
+ raw_ostream &diagnostics) {
+ // Map in export list file.
+ ErrorOr<std::unique_ptr<MemoryBuffer>> mb =
+ MemoryBuffer::getFileOrSTDIN(exportFilePath);
+ if (std::error_code ec = mb.getError())
+ return ec;
+ ctx.addInputFileDependency(exportFilePath);
+ StringRef buffer = mb->get()->getBuffer();
+ while (!buffer.empty()) {
+ // Split off each line in the file.
+ std::pair<StringRef, StringRef> lineAndRest = buffer.split('\n');
+ StringRef line = lineAndRest.first;
+ // Ignore trailing # comments.
+ std::pair<StringRef, StringRef> symAndComment = line.split('#');
+ StringRef sym = symAndComment.first.trim();
+ if (!sym.empty())
+ ctx.addExportSymbol(sym);
+ buffer = lineAndRest.second;
+ }
+ return std::error_code();
+}
+
+
+
+/// Order files are one symbol per line. Blank lines are ignored.
+/// Trailing comments start with #. Symbol names can be prefixed with an
+/// architecture name and/or .o leaf name. Examples:
+/// _foo
+/// bar.o:_bar
+/// libfrob.a(bar.o):_bar
+/// x86_64:_foo64
+static std::error_code parseOrderFile(StringRef orderFilePath,
+ MachOLinkingContext &ctx,
+ raw_ostream &diagnostics) {
+ // Map in order file.
+ ErrorOr<std::unique_ptr<MemoryBuffer>> mb =
+ MemoryBuffer::getFileOrSTDIN(orderFilePath);
+ if (std::error_code ec = mb.getError())
+ return ec;
+ ctx.addInputFileDependency(orderFilePath);
+ StringRef buffer = mb->get()->getBuffer();
+ while (!buffer.empty()) {
+ // Split off each line in the file.
+ std::pair<StringRef, StringRef> lineAndRest = buffer.split('\n');
+ StringRef line = lineAndRest.first;
+ buffer = lineAndRest.second;
+ // Ignore trailing # comments.
+ std::pair<StringRef, StringRef> symAndComment = line.split('#');
+ if (symAndComment.first.empty())
+ continue;
+ StringRef sym = symAndComment.first.trim();
+ if (sym.empty())
+ continue;
+ // Check for prefix.
+ StringRef prefix;
+ std::pair<StringRef, StringRef> prefixAndSym = sym.split(':');
+ if (!prefixAndSym.second.empty()) {
+ sym = prefixAndSym.second;
+ prefix = prefixAndSym.first;
+ if (!prefix.endswith(".o") && !prefix.endswith(".o)")) {
+ // If arch name prefix does not match arch being linked, ignore symbol.
+ if (!ctx.archName().equals(prefix))
+ continue;
+ prefix = "";
+ }
+ } else
+ sym = prefixAndSym.first;
+ if (!sym.empty()) {
+ ctx.appendOrderedSymbol(sym, prefix);
+ //llvm::errs() << sym << ", prefix=" << prefix << "\n";
+ }
+ }
+ return std::error_code();
+}
+
+//
+// There are two variants of the -filelist option:
+//
+// -filelist <path>
+// In this variant, the path is to a text file which contains one file path
+// per line. There are no comments or trimming of whitespace.
+//
+// -fileList <path>,<dir>
+// In this variant, the path is to a text file which contains a partial path
+// per line. The <dir> prefix is prepended to each partial path.
+//
+static std::error_code loadFileList(StringRef fileListPath,
+ MachOLinkingContext &ctx, bool forceLoad,
+ raw_ostream &diagnostics) {
+ // If there is a comma, split off <dir>.
+ std::pair<StringRef, StringRef> opt = fileListPath.split(',');
+ StringRef filePath = opt.first;
+ StringRef dirName = opt.second;
+ ctx.addInputFileDependency(filePath);
+ // Map in file list file.
+ ErrorOr<std::unique_ptr<MemoryBuffer>> mb =
+ MemoryBuffer::getFileOrSTDIN(filePath);
+ if (std::error_code ec = mb.getError())
+ return ec;
+ StringRef buffer = mb->get()->getBuffer();
+ while (!buffer.empty()) {
+ // Split off each line in the file.
+ std::pair<StringRef, StringRef> lineAndRest = buffer.split('\n');
+ StringRef line = lineAndRest.first;
+ StringRef path;
+ if (!dirName.empty()) {
+ // If there is a <dir> then prepend dir to each line.
+ SmallString<256> fullPath;
+ fullPath.assign(dirName);
+ llvm::sys::path::append(fullPath, Twine(line));
+ path = ctx.copy(fullPath.str());
+ } else {
+ // No <dir> use whole line as input file path.
+ path = ctx.copy(line);
+ }
+ if (!ctx.pathExists(path)) {
+ return make_dynamic_error_code(Twine("File not found '")
+ + path
+ + "'");
+ }
+ if (ctx.testingFileUsage()) {
+ diagnostics << "Found filelist entry " << canonicalizePath(path) << '\n';
+ }
+ addFile(path, ctx, forceLoad, false, diagnostics);
+ buffer = lineAndRest.second;
+ }
+ return std::error_code();
+}
+
+/// Parse number assuming it is base 16, but allow 0x prefix.
+static bool parseNumberBase16(StringRef numStr, uint64_t &baseAddress) {
+ if (numStr.startswith_lower("0x"))
+ numStr = numStr.drop_front(2);
+ return numStr.getAsInteger(16, baseAddress);
+}
+
+namespace lld {
+
+bool DarwinLdDriver::linkMachO(int argc, const char *argv[],
+ raw_ostream &diagnostics) {
+ MachOLinkingContext ctx;
+ if (!parse(argc, argv, ctx, diagnostics))
+ return false;
+ if (ctx.doNothing())
+ return true;
+ return link(ctx, diagnostics);
+}
+
+bool DarwinLdDriver::parse(int argc, const char *argv[],
+ MachOLinkingContext &ctx, raw_ostream &diagnostics) {
+ // Parse command line options using DarwinLdOptions.td
+ std::unique_ptr<llvm::opt::InputArgList> parsedArgs;
+ DarwinLdOptTable table;
+ unsigned missingIndex;
+ unsigned missingCount;
+ bool globalWholeArchive = false;
+ parsedArgs.reset(
+ table.ParseArgs(&argv[1], &argv[argc], missingIndex, missingCount));
+ if (missingCount) {
+ diagnostics << "error: missing arg value for '"
+ << parsedArgs->getArgString(missingIndex) << "' expected "
+ << missingCount << " argument(s).\n";
+ return false;
+ }
+
+ for (auto unknownArg : parsedArgs->filtered(OPT_UNKNOWN)) {
+ diagnostics << "warning: ignoring unknown argument: "
+ << unknownArg->getAsString(*parsedArgs) << "\n";
+ }
+
+ // Figure out output kind ( -dylib, -r, -bundle, -preload, or -static )
+ llvm::MachO::HeaderFileType fileType = llvm::MachO::MH_EXECUTE;
+ if ( llvm::opt::Arg *kind = parsedArgs->getLastArg(OPT_dylib, OPT_relocatable,
+ OPT_bundle, OPT_static, OPT_preload)) {
+ switch (kind->getOption().getID()) {
+ case OPT_dylib:
+ fileType = llvm::MachO::MH_DYLIB;
+ break;
+ case OPT_relocatable:
+ fileType = llvm::MachO::MH_OBJECT;
+ break;
+ case OPT_bundle:
+ fileType = llvm::MachO::MH_BUNDLE;
+ break;
+ case OPT_static:
+ fileType = llvm::MachO::MH_EXECUTE;
+ break;
+ case OPT_preload:
+ fileType = llvm::MachO::MH_PRELOAD;
+ break;
+ }
+ }
+
+ // Handle -arch xxx
+ MachOLinkingContext::Arch arch = MachOLinkingContext::arch_unknown;
+ if (llvm::opt::Arg *archStr = parsedArgs->getLastArg(OPT_arch)) {
+ arch = MachOLinkingContext::archFromName(archStr->getValue());
+ if (arch == MachOLinkingContext::arch_unknown) {
+ diagnostics << "error: unknown arch named '" << archStr->getValue()
+ << "'\n";
+ return false;
+ }
+ }
+ // If no -arch specified, scan input files to find first non-fat .o file.
+ if (arch == MachOLinkingContext::arch_unknown) {
+ for (auto &inFile: parsedArgs->filtered(OPT_INPUT)) {
+ // This is expensive because it opens and maps the file. But that is
+ // ok because no -arch is rare.
+ if (MachOLinkingContext::isThinObjectFile(inFile->getValue(), arch))
+ break;
+ }
+ if (arch == MachOLinkingContext::arch_unknown
+ && !parsedArgs->getLastArg(OPT_test_file_usage)) {
+ // If no -arch and no options at all, print usage message.
+ if (parsedArgs->size() == 0)
+ table.PrintHelp(llvm::outs(), argv[0], "LLVM Linker", false);
+ else
+ diagnostics << "error: -arch not specified and could not be inferred\n";
+ return false;
+ }
+ }
+
+ // Handle -macosx_version_min or -ios_version_min
+ MachOLinkingContext::OS os = MachOLinkingContext::OS::macOSX;
+ uint32_t minOSVersion = 0;
+ if (llvm::opt::Arg *minOS =
+ parsedArgs->getLastArg(OPT_macosx_version_min, OPT_ios_version_min,
+ OPT_ios_simulator_version_min)) {
+ switch (minOS->getOption().getID()) {
+ case OPT_macosx_version_min:
+ os = MachOLinkingContext::OS::macOSX;
+ if (MachOLinkingContext::parsePackedVersion(minOS->getValue(),
+ minOSVersion)) {
+ diagnostics << "error: malformed macosx_version_min value\n";
+ return false;
+ }
+ break;
+ case OPT_ios_version_min:
+ os = MachOLinkingContext::OS::iOS;
+ if (MachOLinkingContext::parsePackedVersion(minOS->getValue(),
+ minOSVersion)) {
+ diagnostics << "error: malformed ios_version_min value\n";
+ return false;
+ }
+ break;
+ case OPT_ios_simulator_version_min:
+ os = MachOLinkingContext::OS::iOS_simulator;
+ if (MachOLinkingContext::parsePackedVersion(minOS->getValue(),
+ minOSVersion)) {
+ diagnostics << "error: malformed ios_simulator_version_min value\n";
+ return false;
+ }
+ break;
+ }
+ } else {
+ // No min-os version on command line, check environment variables
+ }
+
+ // Now that there's enough information parsed in, let the linking context
+ // set up default values.
+ ctx.configure(fileType, arch, os, minOSVersion);
+
+ // Handle -e xxx
+ if (llvm::opt::Arg *entry = parsedArgs->getLastArg(OPT_entry))
+ ctx.setEntrySymbolName(entry->getValue());
+
+ // Handle -o xxx
+ if (llvm::opt::Arg *outpath = parsedArgs->getLastArg(OPT_output))
+ ctx.setOutputPath(outpath->getValue());
+ else
+ ctx.setOutputPath("a.out");
+
+ // Handle -image_base XXX and -seg1addr XXXX
+ if (llvm::opt::Arg *imageBase = parsedArgs->getLastArg(OPT_image_base)) {
+ uint64_t baseAddress;
+ if (parseNumberBase16(imageBase->getValue(), baseAddress)) {
+ diagnostics << "error: image_base expects a hex number\n";
+ return false;
+ } else if (baseAddress < ctx.pageZeroSize()) {
+ diagnostics << "error: image_base overlaps with __PAGEZERO\n";
+ return false;
+ } else if (baseAddress % ctx.pageSize()) {
+ diagnostics << "error: image_base must be a multiple of page size ("
+ << llvm::format("0x%" PRIx64, ctx.pageSize()) << ")\n";
+ return false;
+ }
+
+ ctx.setBaseAddress(baseAddress);
+ }
+
+ // Handle -dead_strip
+ if (parsedArgs->getLastArg(OPT_dead_strip))
+ ctx.setDeadStripping(true);
+
+ // Handle -all_load
+ if (parsedArgs->getLastArg(OPT_all_load))
+ globalWholeArchive = true;
+
+ // Handle -install_name
+ if (llvm::opt::Arg *installName = parsedArgs->getLastArg(OPT_install_name))
+ ctx.setInstallName(installName->getValue());
+ else
+ ctx.setInstallName(ctx.outputPath());
+
+ // Handle -mark_dead_strippable_dylib
+ if (parsedArgs->getLastArg(OPT_mark_dead_strippable_dylib))
+ ctx.setDeadStrippableDylib(true);
+
+ // Handle -compatibility_version and -current_version
+ if (llvm::opt::Arg *vers =
+ parsedArgs->getLastArg(OPT_compatibility_version)) {
+ if (ctx.outputMachOType() != llvm::MachO::MH_DYLIB) {
+ diagnostics
+ << "error: -compatibility_version can only be used with -dylib\n";
+ return false;
+ }
+ uint32_t parsedVers;
+ if (MachOLinkingContext::parsePackedVersion(vers->getValue(), parsedVers)) {
+ diagnostics << "error: -compatibility_version value is malformed\n";
+ return false;
+ }
+ ctx.setCompatibilityVersion(parsedVers);
+ }
+
+ if (llvm::opt::Arg *vers = parsedArgs->getLastArg(OPT_current_version)) {
+ if (ctx.outputMachOType() != llvm::MachO::MH_DYLIB) {
+ diagnostics << "-current_version can only be used with -dylib\n";
+ return false;
+ }
+ uint32_t parsedVers;
+ if (MachOLinkingContext::parsePackedVersion(vers->getValue(), parsedVers)) {
+ diagnostics << "error: -current_version value is malformed\n";
+ return false;
+ }
+ ctx.setCurrentVersion(parsedVers);
+ }
+
+ // Handle -bundle_loader
+ if (llvm::opt::Arg *loader = parsedArgs->getLastArg(OPT_bundle_loader))
+ ctx.setBundleLoader(loader->getValue());
+
+ // Handle -sectalign segname sectname align
+ for (auto &alignArg : parsedArgs->filtered(OPT_sectalign)) {
+ const char* segName = alignArg->getValue(0);
+ const char* sectName = alignArg->getValue(1);
+ const char* alignStr = alignArg->getValue(2);
+ if ((alignStr[0] == '0') && (alignStr[1] == 'x'))
+ alignStr += 2;
+ unsigned long long alignValue;
+ if (llvm::getAsUnsignedInteger(alignStr, 16, alignValue)) {
+ diagnostics << "error: -sectalign alignment value '"
+ << alignStr << "' not a valid number\n";
+ return false;
+ }
+ uint8_t align2 = llvm::countTrailingZeros(alignValue);
+ if ( (unsigned long)(1 << align2) != alignValue ) {
+ diagnostics << "warning: alignment for '-sectalign "
+ << segName << " " << sectName
+ << llvm::format(" 0x%llX", alignValue)
+ << "' is not a power of two, using "
+ << llvm::format("0x%08X", (1 << align2)) << "\n";
+ }
+ ctx.addSectionAlignment(segName, sectName, align2);
+ }
+
+ // Handle -mllvm
+ for (auto &llvmArg : parsedArgs->filtered(OPT_mllvm)) {
+ ctx.appendLLVMOption(llvmArg->getValue());
+ }
+
+ // Handle -print_atoms
+ if (parsedArgs->getLastArg(OPT_print_atoms))
+ ctx.setPrintAtoms();
+
+ // Handle -t (trace) option.
+ if (parsedArgs->getLastArg(OPT_t))
+ ctx.setLogInputFiles(true);
+
+ // Handle -demangle option.
+ if (parsedArgs->getLastArg(OPT_demangle))
+ ctx.setDemangleSymbols(true);
+
+ // Handle -keep_private_externs
+ if (parsedArgs->getLastArg(OPT_keep_private_externs)) {
+ ctx.setKeepPrivateExterns(true);
+ if (ctx.outputMachOType() != llvm::MachO::MH_OBJECT)
+ diagnostics << "warning: -keep_private_externs only used in -r mode\n";
+ }
+
+ // Handle -dependency_info <path> used by Xcode.
+ if (llvm::opt::Arg *depInfo = parsedArgs->getLastArg(OPT_dependency_info)) {
+ if (std::error_code ec = ctx.createDependencyFile(depInfo->getValue())) {
+ diagnostics << "warning: " << ec.message()
+ << ", processing '-dependency_info "
+ << depInfo->getValue()
+ << "'\n";
+ }
+ }
+
+ // In -test_file_usage mode, we'll be given an explicit list of paths that
+ // exist. We'll also be expected to print out information about how we located
+ // libraries and so on that the user specified, but not to actually do any
+ // linking.
+ if (parsedArgs->getLastArg(OPT_test_file_usage)) {
+ ctx.setTestingFileUsage();
+
+ // With paths existing by fiat, linking is not going to end well.
+ ctx.setDoNothing(true);
+
+ // Only bother looking for an existence override if we're going to use it.
+ for (auto existingPath : parsedArgs->filtered(OPT_path_exists)) {
+ ctx.addExistingPathForDebug(existingPath->getValue());
+ }
+ }
+
+ // Register possible input file parsers.
+ if (!ctx.doNothing()) {
+ ctx.registry().addSupportMachOObjects(ctx);
+ ctx.registry().addSupportArchives(ctx.logInputFiles());
+ ctx.registry().addSupportNativeObjects();
+ ctx.registry().addSupportYamlFiles();
+ }
+
+ // Now construct the set of library search directories, following ld64's
+ // baroque set of accumulated hacks. Mostly, the algorithm constructs
+ // { syslibroots } x { libpaths }
+ //
+ // Unfortunately, there are numerous exceptions:
+ // 1. Only absolute paths get modified by syslibroot options.
+ // 2. If there is just 1 -syslibroot, system paths not found in it are
+ // skipped.
+ // 3. If the last -syslibroot is "/", all of them are ignored entirely.
+ // 4. If { syslibroots } x path == {}, the original path is kept.
+ std::vector<StringRef> sysLibRoots;
+ for (auto syslibRoot : parsedArgs->filtered(OPT_syslibroot)) {
+ sysLibRoots.push_back(syslibRoot->getValue());
+ }
+ if (!sysLibRoots.empty()) {
+ // Ignore all if last -syslibroot is "/".
+ if (sysLibRoots.back() != "/")
+ ctx.setSysLibRoots(sysLibRoots);
+ }
+
+ // Paths specified with -L come first, and are not considered system paths for
+ // the case where there is precisely 1 -syslibroot.
+ for (auto libPath : parsedArgs->filtered(OPT_L)) {
+ ctx.addModifiedSearchDir(libPath->getValue());
+ }
+
+ // Process -F directories (where to look for frameworks).
+ for (auto fwPath : parsedArgs->filtered(OPT_F)) {
+ ctx.addFrameworkSearchDir(fwPath->getValue());
+ }
+
+ // -Z suppresses the standard search paths.
+ if (!parsedArgs->hasArg(OPT_Z)) {
+ ctx.addModifiedSearchDir("/usr/lib", true);
+ ctx.addModifiedSearchDir("/usr/local/lib", true);
+ ctx.addFrameworkSearchDir("/Library/Frameworks", true);
+ ctx.addFrameworkSearchDir("/System/Library/Frameworks", true);
+ }
+
+ // Now that we've constructed the final set of search paths, print out those
+ // search paths in verbose mode.
+ if (parsedArgs->getLastArg(OPT_v)) {
+ diagnostics << "Library search paths:\n";
+ for (auto path : ctx.searchDirs()) {
+ diagnostics << " " << path << '\n';
+ }
+ diagnostics << "Framework search paths:\n";
+ for (auto path : ctx.frameworkDirs()) {
+ diagnostics << " " << path << '\n';
+ }
+ }
+
+ // Handle -exported_symbols_list <file>
+ for (auto expFile : parsedArgs->filtered(OPT_exported_symbols_list)) {
+ if (ctx.exportMode() == MachOLinkingContext::ExportMode::blackList) {
+ diagnostics << "error: -exported_symbols_list cannot be combined "
+ << "with -unexported_symbol[s_list]\n";
+ return false;
+ }
+ ctx.setExportMode(MachOLinkingContext::ExportMode::whiteList);
+ if (std::error_code ec = parseExportsList(expFile->getValue(), ctx,
+ diagnostics)) {
+ diagnostics << "error: " << ec.message()
+ << ", processing '-exported_symbols_list "
+ << expFile->getValue()
+ << "'\n";
+ return false;
+ }
+ }
+
+ // Handle -exported_symbol <symbol>
+ for (auto symbol : parsedArgs->filtered(OPT_exported_symbol)) {
+ if (ctx.exportMode() == MachOLinkingContext::ExportMode::blackList) {
+ diagnostics << "error: -exported_symbol cannot be combined "
+ << "with -unexported_symbol[s_list]\n";
+ return false;
+ }
+ ctx.setExportMode(MachOLinkingContext::ExportMode::whiteList);
+ ctx.addExportSymbol(symbol->getValue());
+ }
+
+ // Handle -unexported_symbols_list <file>
+ for (auto expFile : parsedArgs->filtered(OPT_unexported_symbols_list)) {
+ if (ctx.exportMode() == MachOLinkingContext::ExportMode::whiteList) {
+ diagnostics << "error: -unexported_symbols_list cannot be combined "
+ << "with -exported_symbol[s_list]\n";
+ return false;
+ }
+ ctx.setExportMode(MachOLinkingContext::ExportMode::blackList);
+ if (std::error_code ec = parseExportsList(expFile->getValue(), ctx,
+ diagnostics)) {
+ diagnostics << "error: " << ec.message()
+ << ", processing '-unexported_symbols_list "
+ << expFile->getValue()
+ << "'\n";
+ return false;
+ }
+ }
+
+ // Handle -unexported_symbol <symbol>
+ for (auto symbol : parsedArgs->filtered(OPT_unexported_symbol)) {
+ if (ctx.exportMode() == MachOLinkingContext::ExportMode::whiteList) {
+ diagnostics << "error: -unexported_symbol cannot be combined "
+ << "with -exported_symbol[s_list]\n";
+ return false;
+ }
+ ctx.setExportMode(MachOLinkingContext::ExportMode::blackList);
+ ctx.addExportSymbol(symbol->getValue());
+ }
+
+ // Handle obosolete -multi_module and -single_module
+ if (llvm::opt::Arg *mod = parsedArgs->getLastArg(OPT_multi_module,
+ OPT_single_module)) {
+ if (mod->getOption().getID() == OPT_multi_module) {
+ diagnostics << "warning: -multi_module is obsolete and being ignored\n";
+ }
+ else {
+ if (ctx.outputMachOType() != llvm::MachO::MH_DYLIB) {
+ diagnostics << "warning: -single_module being ignored. "
+ "It is only for use when producing a dylib\n";
+ }
+ }
+ }
+
+ // Handle -pie or -no_pie
+ if (llvm::opt::Arg *pie = parsedArgs->getLastArg(OPT_pie, OPT_no_pie)) {
+ switch (ctx.outputMachOType()) {
+ case llvm::MachO::MH_EXECUTE:
+ switch (ctx.os()) {
+ case MachOLinkingContext::OS::macOSX:
+ if ((minOSVersion < 0x000A0500) &&
+ (pie->getOption().getID() == OPT_pie)) {
+ diagnostics << "-pie can only be used when targeting "
+ "Mac OS X 10.5 or later\n";
+ return false;
+ }
+ break;
+ case MachOLinkingContext::OS::iOS:
+ if ((minOSVersion < 0x00040200) &&
+ (pie->getOption().getID() == OPT_pie)) {
+ diagnostics << "-pie can only be used when targeting "
+ "iOS 4.2 or later\n";
+ return false;
+ }
+ break;
+ case MachOLinkingContext::OS::iOS_simulator:
+ if (pie->getOption().getID() == OPT_no_pie)
+ diagnostics << "iOS simulator programs must be built PIE\n";
+ return false;
+ break;
+ case MachOLinkingContext::OS::unknown:
+ break;
+ }
+ ctx.setPIE(pie->getOption().getID() == OPT_pie);
+ break;
+ case llvm::MachO::MH_PRELOAD:
+ break;
+ case llvm::MachO::MH_DYLIB:
+ case llvm::MachO::MH_BUNDLE:
+ diagnostics << "warning: " << pie->getSpelling() << " being ignored. "
+ << "It is only used when linking main executables\n";
+ break;
+ default:
+ diagnostics << pie->getSpelling()
+ << " can only used when linking main executables\n";
+ return false;
+ break;
+ }
+ }
+
+ // Handle debug info handling options: -S
+ if (parsedArgs->hasArg(OPT_S))
+ ctx.setDebugInfoMode(MachOLinkingContext::DebugInfoMode::noDebugMap);
+
+ // Handle -order_file <file>
+ for (auto orderFile : parsedArgs->filtered(OPT_order_file)) {
+ if (std::error_code ec = parseOrderFile(orderFile->getValue(), ctx,
+ diagnostics)) {
+ diagnostics << "error: " << ec.message()
+ << ", processing '-order_file "
+ << orderFile->getValue()
+ << "'\n";
+ return false;
+ }
+ }
+
+ // Handle -rpath <path>
+ if (parsedArgs->hasArg(OPT_rpath)) {
+ switch (ctx.outputMachOType()) {
+ case llvm::MachO::MH_EXECUTE:
+ case llvm::MachO::MH_DYLIB:
+ case llvm::MachO::MH_BUNDLE:
+ if (!ctx.minOS("10.5", "2.0")) {
+ if (ctx.os() == MachOLinkingContext::OS::macOSX) {
+ diagnostics << "error: -rpath can only be used when targeting "
+ "OS X 10.5 or later\n";
+ } else {
+ diagnostics << "error: -rpath can only be used when targeting "
+ "iOS 2.0 or later\n";
+ }
+ return false;
+ }
+ break;
+ default:
+ diagnostics << "error: -rpath can only be used when creating "
+ "a dynamic final linked image\n";
+ return false;
+ }
+
+ for (auto rPath : parsedArgs->filtered(OPT_rpath)) {
+ ctx.addRpath(rPath->getValue());
+ }
+ }
+
+ // Handle input files
+ for (auto &arg : *parsedArgs) {
+ bool upward;
+ ErrorOr<StringRef> resolvedPath = StringRef();
+ switch (arg->getOption().getID()) {
+ default:
+ continue;
+ case OPT_INPUT:
+ addFile(arg->getValue(), ctx, globalWholeArchive, false, diagnostics);
+ break;
+ case OPT_upward_library:
+ addFile(arg->getValue(), ctx, false, true, diagnostics);
+ break;
+ case OPT_force_load:
+ addFile(arg->getValue(), ctx, true, false, diagnostics);
+ break;
+ case OPT_l:
+ case OPT_upward_l:
+ upward = (arg->getOption().getID() == OPT_upward_l);
+ resolvedPath = ctx.searchLibrary(arg->getValue());
+ if (!resolvedPath) {
+ diagnostics << "Unable to find library for " << arg->getSpelling()
+ << arg->getValue() << "\n";
+ return false;
+ } else if (ctx.testingFileUsage()) {
+ diagnostics << "Found " << (upward ? "upward " : " ") << "library "
+ << canonicalizePath(resolvedPath.get()) << '\n';
+ }
+ addFile(resolvedPath.get(), ctx, globalWholeArchive, upward, diagnostics);
+ break;
+ case OPT_framework:
+ case OPT_upward_framework:
+ upward = (arg->getOption().getID() == OPT_upward_framework);
+ resolvedPath = ctx.findPathForFramework(arg->getValue());
+ if (!resolvedPath) {
+ diagnostics << "Unable to find framework for "
+ << arg->getSpelling() << " " << arg->getValue() << "\n";
+ return false;
+ } else if (ctx.testingFileUsage()) {
+ diagnostics << "Found " << (upward ? "upward " : " ") << "framework "
+ << canonicalizePath(resolvedPath.get()) << '\n';
+ }
+ addFile(resolvedPath.get(), ctx, globalWholeArchive, upward, diagnostics);
+ break;
+ case OPT_filelist:
+ if (std::error_code ec = loadFileList(arg->getValue(),
+ ctx, globalWholeArchive,
+ diagnostics)) {
+ diagnostics << "error: " << ec.message()
+ << ", processing '-filelist " << arg->getValue()
+ << "'\n";
+ return false;
+ }
+ break;
+ }
+ }
+
+ if (ctx.getNodes().empty()) {
+ diagnostics << "No input files\n";
+ return false;
+ }
+
+ // Validate the combination of options used.
+ return ctx.validate(diagnostics);
+}
+
+
+} // namespace lld
diff --git a/lib/Driver/DarwinLdOptions.td b/lib/Driver/DarwinLdOptions.td
new file mode 100644
index 000000000000..81dcc0a1d925
--- /dev/null
+++ b/lib/Driver/DarwinLdOptions.td
@@ -0,0 +1,187 @@
+include "llvm/Option/OptParser.td"
+
+
+// output kinds
+def grp_kind : OptionGroup<"outs">, HelpText<"OUTPUT KIND">;
+def relocatable : Flag<["-"], "r">,
+ HelpText<"Create relocatable object file">, Group<grp_kind>;
+def static : Flag<["-"], "static">,
+ HelpText<"Create static executable">, Group<grp_kind>;
+def dynamic : Flag<["-"], "dynamic">,
+ HelpText<"Create dynamic executable (default)">,Group<grp_kind>;
+def dylib : Flag<["-"], "dylib">,
+ HelpText<"Create dynamic library">, Group<grp_kind>;
+def bundle : Flag<["-"], "bundle">,
+ HelpText<"Create dynamic bundle">, Group<grp_kind>;
+def execute : Flag<["-"], "execute">,
+ HelpText<"Create main executable (default)">, Group<grp_kind>;
+def preload : Flag<["-"], "preload">,
+ HelpText<"Create binary for use with embedded systems">, Group<grp_kind>;
+
+// optimizations
+def grp_opts : OptionGroup<"opts">, HelpText<"OPTIMIZATIONS">;
+def dead_strip : Flag<["-"], "dead_strip">,
+ HelpText<"Remove unreference code and data">, Group<grp_opts>;
+def macosx_version_min : Separate<["-"], "macosx_version_min">,
+ MetaVarName<"<version>">,
+ HelpText<"Minimum Mac OS X version">, Group<grp_opts>;
+def ios_version_min : Separate<["-"], "ios_version_min">,
+ MetaVarName<"<version>">,
+ HelpText<"Minimum iOS version">, Group<grp_opts>;
+def iphoneos_version_min : Separate<["-"], "iphoneos_version_min">,
+ Alias<ios_version_min>;
+def ios_simulator_version_min : Separate<["-"], "ios_simulator_version_min">,
+ MetaVarName<"<version>">,
+ HelpText<"Minimum iOS simulator version">, Group<grp_opts>;
+def mllvm : Separate<["-"], "mllvm">,
+ MetaVarName<"<option>">,
+ HelpText<"Options to pass to LLVM during LTO">, Group<grp_opts>;
+def exported_symbols_list : Separate<["-"], "exported_symbols_list">,
+ MetaVarName<"<file-path>">,
+ HelpText<"Restricts which symbols will be exported">, Group<grp_opts>;
+def exported_symbol : Separate<["-"], "exported_symbol">,
+ MetaVarName<"<symbol>">,
+ HelpText<"Restricts which symbols will be exported">, Group<grp_opts>;
+def unexported_symbols_list : Separate<["-"], "unexported_symbols_list">,
+ MetaVarName<"<file-path>">,
+ HelpText<"Lists symbols that should not be exported">, Group<grp_opts>;
+def unexported_symbol : Separate<["-"], "unexported_symbol">,
+ MetaVarName<"<symbol>">,
+ HelpText<"A symbol which should not be exported">, Group<grp_opts>;
+def keep_private_externs : Flag<["-"], "keep_private_externs">,
+ HelpText<"Private extern (hidden) symbols should not be transformed "
+ "into local symbols">, Group<grp_opts>;
+def order_file : Separate<["-"], "order_file">,
+ MetaVarName<"<file-path>">,
+ HelpText<"re-order and move specified symbols to start of their section">,
+ Group<grp_opts>;
+
+// main executable options
+def grp_main : OptionGroup<"opts">, HelpText<"MAIN EXECUTABLE OPTIONS">;
+def entry : Separate<["-"], "e">,
+ MetaVarName<"<entry-name>">,
+ HelpText<"entry symbol name">,Group<grp_main>;
+def pie : Flag<["-"], "pie">,
+ HelpText<"Create Position Independent Executable (for ASLR)">,
+ Group<grp_main>;
+def no_pie : Flag<["-"], "no_pie">,
+ HelpText<"Do not create Position Independent Executable">,
+ Group<grp_main>;
+
+// dylib executable options
+def grp_dylib : OptionGroup<"opts">, HelpText<"DYLIB EXECUTABLE OPTIONS">;
+def install_name : Separate<["-"], "install_name">,
+ MetaVarName<"<path>">,
+ HelpText<"The dylib's install name">, Group<grp_dylib>;
+def mark_dead_strippable_dylib : Flag<["-"], "mark_dead_strippable_dylib">,
+ HelpText<"Marks the dylib as having no side effects during initialization">,
+ Group<grp_dylib>;
+def compatibility_version : Separate<["-"], "compatibility_version">,
+ MetaVarName<"<version>">,
+ HelpText<"The dylib's compatibility version">, Group<grp_dylib>;
+def current_version : Separate<["-"], "current_version">,
+ MetaVarName<"<version>">,
+ HelpText<"The dylib's current version">, Group<grp_dylib>;
+
+// dylib executable options - compatibility aliases
+def dylib_install_name : Separate<["-"], "dylib_install_name">,
+ Alias<install_name>;
+def dylib_compatibility_version : Separate<["-"], "dylib_compatibility_version">,
+ MetaVarName<"<version>">, Alias<compatibility_version>;
+def dylib_current_version : Separate<["-"], "dylib_current_version">,
+ MetaVarName<"<version>">, Alias<current_version>;
+
+// bundle executable options
+def grp_bundle : OptionGroup<"opts">, HelpText<"BUNDLE EXECUTABLE OPTIONS">;
+def bundle_loader : Separate<["-"], "bundle_loader">,
+ MetaVarName<"<path>">,
+ HelpText<"The executable that will be loading this Mach-O bundle">,
+ Group<grp_bundle>;
+
+// library options
+def grp_libs : OptionGroup<"libs">, HelpText<"LIBRARY OPTIONS">;
+def L : JoinedOrSeparate<["-"], "L">,
+ MetaVarName<"<dir>">,
+ HelpText<"Add directory to library search path">, Group<grp_libs>;
+def F : JoinedOrSeparate<["-"], "F">,
+ MetaVarName<"<dir>">,
+ HelpText<"Add directory to framework search path">, Group<grp_libs>;
+def Z : Flag<["-"], "Z">,
+ HelpText<"Do not search standard directories for libraries or frameworks">;
+def all_load : Flag<["-"], "all_load">,
+ HelpText<"Forces all members of all static libraries to be loaded">,
+ Group<grp_libs>;
+def force_load : Separate<["-"], "force_load">,
+ MetaVarName<"<library-path>">,
+ HelpText<"Forces all members of specified static libraries to be loaded">,
+ Group<grp_libs>;
+def syslibroot : Separate<["-"], "syslibroot">, MetaVarName<"<dir>">,
+ HelpText<"Add path to SDK to all absolute library search paths">,
+ Group<grp_libs>;
+
+// Input options
+def l : Joined<["-"], "l">,
+ MetaVarName<"<libname>">,
+ HelpText<"Base name of library searched for in -L directories">;
+def upward_l : Joined<["-"], "upward-l">,
+ MetaVarName<"<libname>">,
+ HelpText<"Base name of upward library searched for in -L directories">;
+def framework : Separate<["-"], "framework">,
+ MetaVarName<"<name>">,
+ HelpText<"Base name of framework searched for in -F directories">;
+def upward_framework : Separate<["-"], "upward_framework">,
+ MetaVarName<"<name>">,
+ HelpText<"Base name of upward framework searched for in -F directories">;
+def upward_library : Separate<["-"], "upward_library">,
+ MetaVarName<"<path>">,
+ HelpText<"path to upward dylib to link with">;
+def filelist : Separate<["-"], "filelist">,
+ MetaVarName<"<path>">,
+ HelpText<"file containing paths to input files">;
+
+
+// test case options
+def print_atoms : Flag<["-"], "print_atoms">,
+ HelpText<"Emit output as yaml atoms">;
+def test_file_usage : Flag<["-"], "test_file_usage">,
+ HelpText<"Only files specified by -file_exists are considered to exist. "
+ "Print which files would be used">;
+def path_exists : Separate<["-"], "path_exists">,
+ MetaVarName<"<path>">,
+ HelpText<"Used with -test_file_usage to declare a path">;
+
+
+// general options
+def output : Separate<["-"], "o">,
+ MetaVarName<"<path>">,
+ HelpText<"Output file path">;
+def arch : Separate<["-"], "arch">,
+ MetaVarName<"<arch-name>">,
+ HelpText<"Architecture to link">;
+def sectalign : MultiArg<["-"], "sectalign", 3>,
+ MetaVarName<"<segname> <sectname> <alignment>">,
+ HelpText<"alignment for segment/section">;
+def image_base : Separate<["-"], "image_base">;
+def seg1addr : Separate<["-"], "seg1addr">, Alias<image_base>;
+def demangle : Flag<["-"], "demangle">,
+ HelpText<"Demangles symbol names in errors and warnings">;
+def dependency_info : Separate<["-"], "dependency_info">,
+ MetaVarName<"<file>">,
+ HelpText<"Write binary list of files used during link">;
+def S : Flag<["-"], "S">,
+ HelpText<"Remove debug information (STABS or DWARF) from the output file">;
+def rpath : Separate<["-"], "rpath">,
+ MetaVarName<"<path>">,
+ HelpText<"Add path to the runpath search path list for image being created">;
+
+def t : Flag<["-"], "t">,
+ HelpText<"Print the names of the input files as ld processes them">;
+def v : Flag<["-"], "v">,
+ HelpText<"Print linker information">;
+
+// Obsolete options
+def grp_obsolete : OptionGroup<"obsolete">, HelpText<"OBSOLETE OPTIONS">;
+def single_module : Flag<["-"], "single_module">,
+ HelpText<"Default for dylibs">, Group<grp_obsolete>;
+def multi_module : Flag<["-"], "multi_module">,
+ HelpText<"Unsupported way to build dylibs">, Group<grp_obsolete>;
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
new file mode 100644
index 000000000000..d32bfa6e47be
--- /dev/null
+++ b/lib/Driver/Driver.cpp
@@ -0,0 +1,130 @@
+//===- lib/Driver/Driver.cpp - Linker Driver Emulator ---------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/ArchiveLibraryFile.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Instrumentation.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Parallel.h"
+#include "lld/Core/PassManager.h"
+#include "lld/Core/Reader.h"
+#include "lld/Core/Resolver.h"
+#include "lld/Core/Writer.h"
+#include "lld/Driver/Driver.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/raw_ostream.h"
+#include <mutex>
+
+namespace lld {
+
+FileVector makeErrorFile(StringRef path, std::error_code ec) {
+ std::vector<std::unique_ptr<File>> result;
+ result.push_back(llvm::make_unique<ErrorFile>(path, ec));
+ return result;
+}
+
+FileVector parseMemberFiles(FileVector &files) {
+ std::vector<std::unique_ptr<File>> members;
+ for (std::unique_ptr<File> &file : files) {
+ if (auto *archive = dyn_cast<ArchiveLibraryFile>(file.get())) {
+ if (std::error_code ec = archive->parseAllMembers(members))
+ return makeErrorFile(file->path(), ec);
+ } else {
+ members.push_back(std::move(file));
+ }
+ }
+ return members;
+}
+
+FileVector loadFile(LinkingContext &ctx, StringRef path, bool wholeArchive) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> mb
+ = MemoryBuffer::getFileOrSTDIN(path);
+ if (std::error_code ec = mb.getError())
+ return makeErrorFile(path, ec);
+ std::vector<std::unique_ptr<File>> files;
+ if (std::error_code ec = ctx.registry().loadFile(std::move(mb.get()), files))
+ return makeErrorFile(path, ec);
+ if (wholeArchive)
+ return parseMemberFiles(files);
+ return files;
+}
+
+/// This is where the link is actually performed.
+bool Driver::link(LinkingContext &context, raw_ostream &diagnostics) {
+ // Honor -mllvm
+ if (!context.llvmOptions().empty()) {
+ unsigned numArgs = context.llvmOptions().size();
+ const char **args = new const char *[numArgs + 2];
+ args[0] = "lld (LLVM option parsing)";
+ for (unsigned i = 0; i != numArgs; ++i)
+ args[i + 1] = context.llvmOptions()[i];
+ args[numArgs + 1] = 0;
+ llvm::cl::ParseCommandLineOptions(numArgs + 1, args);
+ }
+ if (context.getNodes().empty())
+ return false;
+
+ for (std::unique_ptr<Node> &ie : context.getNodes())
+ if (FileNode *node = dyn_cast<FileNode>(ie.get()))
+ context.getTaskGroup().spawn([node] { node->getFile()->parse(); });
+
+ std::vector<std::unique_ptr<File>> internalFiles;
+ context.createInternalFiles(internalFiles);
+ for (auto i = internalFiles.rbegin(), e = internalFiles.rend(); i != e; ++i) {
+ auto &members = context.getNodes();
+ members.insert(members.begin(), llvm::make_unique<FileNode>(std::move(*i)));
+ }
+
+ // Give target a chance to add files.
+ std::vector<std::unique_ptr<File>> implicitFiles;
+ context.createImplicitFiles(implicitFiles);
+ for (auto i = implicitFiles.rbegin(), e = implicitFiles.rend(); i != e; ++i) {
+ auto &members = context.getNodes();
+ members.insert(members.begin(), llvm::make_unique<FileNode>(std::move(*i)));
+ }
+
+ // Give target a chance to postprocess input files.
+ // Mach-O uses this chance to move all object files before library files.
+ // ELF adds specific undefined symbols resolver.
+ context.finalizeInputFiles();
+
+ // Do core linking.
+ ScopedTask resolveTask(getDefaultDomain(), "Resolve");
+ Resolver resolver(context);
+ if (!resolver.resolve())
+ return false;
+ std::unique_ptr<MutableFile> merged = resolver.resultFile();
+ resolveTask.end();
+
+ // Run passes on linked atoms.
+ ScopedTask passTask(getDefaultDomain(), "Passes");
+ PassManager pm;
+ context.addPasses(pm);
+ pm.runOnFile(merged);
+ passTask.end();
+
+ // Give linked atoms to Writer to generate output file.
+ ScopedTask writeTask(getDefaultDomain(), "Write");
+ if (std::error_code ec = context.writeFile(*merged)) {
+ diagnostics << "Failed to write file '" << context.outputPath()
+ << "': " << ec.message() << "\n";
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace
diff --git a/lib/Driver/GnuLdDriver.cpp b/lib/Driver/GnuLdDriver.cpp
new file mode 100644
index 000000000000..b9af04d4b615
--- /dev/null
+++ b/lib/Driver/GnuLdDriver.cpp
@@ -0,0 +1,760 @@
+//===- lib/Driver/GnuLdDriver.cpp -----------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+///
+/// Concrete instance of the Driver for GNU's ld.
+///
+//===----------------------------------------------------------------------===//
+
+#include "lld/Driver/Driver.h"
+#include "lld/ReaderWriter/ELFLinkingContext.h"
+#include "lld/ReaderWriter/ELFTargets.h"
+#include "lld/ReaderWriter/LinkerScript.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/Timer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstring>
+#include <tuple>
+
+using namespace lld;
+
+using llvm::BumpPtrAllocator;
+
+namespace {
+
+// Create enum with OPT_xxx values for each option in GnuLdOptions.td
+enum {
+ OPT_INVALID = 0,
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELP, META) \
+ OPT_##ID,
+#include "GnuLdOptions.inc"
+#undef OPTION
+};
+
+// Create prefix string literals used in GnuLdOptions.td
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#include "GnuLdOptions.inc"
+#undef PREFIX
+
+// Create table mapping all options defined in GnuLdOptions.td
+static const llvm::opt::OptTable::Info infoTable[] = {
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR) \
+ { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \
+ PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS },
+#include "GnuLdOptions.inc"
+#undef OPTION
+};
+
+
+// Create OptTable class for parsing actual command line arguments
+class GnuLdOptTable : public llvm::opt::OptTable {
+public:
+ GnuLdOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable)){}
+};
+
+class DriverStringSaver : public llvm::cl::StringSaver {
+public:
+ DriverStringSaver(BumpPtrAllocator &alloc) : _alloc(alloc) {}
+
+ const char *SaveString(const char *s) override {
+ char *p = _alloc.Allocate<char>(strlen(s) + 1);
+ strcpy(p, s);
+ return p;
+ }
+
+private:
+ BumpPtrAllocator &_alloc;
+};
+
+} // anonymous namespace
+
+// If a command line option starts with "@", the driver reads its suffix as a
+// file, parse its contents as a list of command line options, and insert them
+// at the original @file position. If file cannot be read, @file is not expanded
+// and left unmodified. @file can appear in a response file, so it's a recursive
+// process.
+static std::tuple<int, const char **>
+maybeExpandResponseFiles(int argc, const char **argv, BumpPtrAllocator &alloc) {
+ // Expand response files.
+ SmallVector<const char *, 256> smallvec;
+ for (int i = 0; i < argc; ++i)
+ smallvec.push_back(argv[i]);
+ DriverStringSaver saver(alloc);
+ llvm::cl::ExpandResponseFiles(saver, llvm::cl::TokenizeGNUCommandLine, smallvec);
+
+ // Pack the results to a C-array and return it.
+ argc = smallvec.size();
+ const char **copy = alloc.Allocate<const char *>(argc + 1);
+ std::copy(smallvec.begin(), smallvec.end(), copy);
+ copy[argc] = nullptr;
+ return std::make_tuple(argc, copy);
+}
+
+static std::error_code
+getFileMagic(StringRef path, llvm::sys::fs::file_magic &magic) {
+ std::error_code ec = llvm::sys::fs::identify_magic(path, magic);
+ if (ec)
+ return ec;
+ switch (magic) {
+ case llvm::sys::fs::file_magic::archive:
+ case llvm::sys::fs::file_magic::elf_relocatable:
+ case llvm::sys::fs::file_magic::elf_shared_object:
+ case llvm::sys::fs::file_magic::unknown:
+ return std::error_code();
+ default:
+ return make_dynamic_error_code(StringRef("unknown type of object file"));
+ }
+}
+
+// Parses an argument of --defsym=<sym>=<number>
+static bool parseDefsymAsAbsolute(StringRef opt, StringRef &sym,
+ uint64_t &addr) {
+ size_t equalPos = opt.find('=');
+ if (equalPos == 0 || equalPos == StringRef::npos)
+ return false;
+ sym = opt.substr(0, equalPos);
+ if (opt.substr(equalPos + 1).getAsInteger(0, addr))
+ return false;
+ return true;
+}
+
+// Parses an argument of --defsym=<sym>=<sym>
+static bool parseDefsymAsAlias(StringRef opt, StringRef &sym,
+ StringRef &target) {
+ size_t equalPos = opt.find('=');
+ if (equalPos == 0 || equalPos == StringRef::npos)
+ return false;
+ sym = opt.substr(0, equalPos);
+ target = opt.substr(equalPos + 1);
+ return !target.empty();
+}
+
+// Parses -z max-page-size=<value>
+static bool parseMaxPageSize(StringRef opt, uint64_t &val) {
+ size_t equalPos = opt.find('=');
+ if (equalPos == 0 || equalPos == StringRef::npos)
+ return false;
+ StringRef value = opt.substr(equalPos + 1);
+ val = 0;
+ if (value.getAsInteger(0, val) || !val)
+ return false;
+ return true;
+}
+
+bool GnuLdDriver::linkELF(int argc, const char *argv[], raw_ostream &diag) {
+ BumpPtrAllocator alloc;
+ std::tie(argc, argv) = maybeExpandResponseFiles(argc, argv, alloc);
+ std::unique_ptr<ELFLinkingContext> options;
+ if (!parse(argc, argv, options, diag))
+ return false;
+ if (!options)
+ return true;
+ bool linked = link(*options, diag);
+
+ // Handle --stats.
+ if (options->collectStats()) {
+ llvm::TimeRecord t = llvm::TimeRecord::getCurrentTime(true);
+ diag << "total time in link " << t.getProcessTime() << "\n";
+ diag << "data size " << t.getMemUsed() << "\n";
+ }
+ return linked;
+}
+
+static llvm::Optional<llvm::Triple::ArchType>
+getArchType(const llvm::Triple &triple, StringRef value) {
+ switch (triple.getArch()) {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ if (value == "elf_i386")
+ return llvm::Triple::x86;
+ if (value == "elf_x86_64")
+ return llvm::Triple::x86_64;
+ return llvm::None;
+ case llvm::Triple::mipsel:
+ case llvm::Triple::mips64el:
+ if (value == "elf32ltsmip")
+ return llvm::Triple::mipsel;
+ if (value == "elf64ltsmip")
+ return llvm::Triple::mips64el;
+ return llvm::None;
+ case llvm::Triple::aarch64:
+ if (value == "aarch64linux")
+ return llvm::Triple::aarch64;
+ return llvm::None;
+ case llvm::Triple::arm:
+ if (value == "armelf_linux_eabi")
+ return llvm::Triple::arm;
+ return llvm::None;
+ default:
+ return llvm::None;
+ }
+}
+
+static bool isLinkerScript(StringRef path, raw_ostream &diag) {
+ llvm::sys::fs::file_magic magic = llvm::sys::fs::file_magic::unknown;
+ std::error_code ec = getFileMagic(path, magic);
+ if (ec) {
+ diag << "unknown input file format for file " << path << "\n";
+ return false;
+ }
+ return magic == llvm::sys::fs::file_magic::unknown;
+}
+
+static ErrorOr<StringRef>
+findFile(ELFLinkingContext &ctx, StringRef path, bool dashL) {
+ // If the path was referred to by using a -l argument, let's search
+ // for the file in the search path.
+ if (dashL) {
+ ErrorOr<StringRef> pathOrErr = ctx.searchLibrary(path);
+ if (std::error_code ec = pathOrErr.getError())
+ return make_dynamic_error_code(
+ Twine("Unable to find library -l") + path + ": " + ec.message());
+ path = pathOrErr.get();
+ }
+ if (!llvm::sys::fs::exists(path))
+ return make_dynamic_error_code(
+ Twine("lld: cannot find file ") + path);
+ return path;
+}
+
+static bool isPathUnderSysroot(StringRef sysroot, StringRef path) {
+ if (sysroot.empty())
+ return false;
+ while (!path.empty() && !llvm::sys::fs::equivalent(sysroot, path))
+ path = llvm::sys::path::parent_path(path);
+ return !path.empty();
+}
+
+static std::error_code
+addFilesFromLinkerScript(ELFLinkingContext &ctx, StringRef scriptPath,
+ const std::vector<script::Path> &inputPaths,
+ raw_ostream &diag) {
+ bool sysroot = (!ctx.getSysroot().empty()
+ && isPathUnderSysroot(ctx.getSysroot(), scriptPath));
+ for (const script::Path &path : inputPaths) {
+ ErrorOr<StringRef> pathOrErr = path._isDashlPrefix
+ ? ctx.searchLibrary(path._path) : ctx.searchFile(path._path, sysroot);
+ if (std::error_code ec = pathOrErr.getError()) {
+ auto file = llvm::make_unique<ErrorFile>(path._path, ec);
+ ctx.getNodes().push_back(llvm::make_unique<FileNode>(std::move(file)));
+ continue;
+ }
+
+ std::vector<std::unique_ptr<File>> files
+ = loadFile(ctx, pathOrErr.get(), false);
+ for (std::unique_ptr<File> &file : files) {
+ if (ctx.logInputFiles())
+ diag << file->path() << "\n";
+ ctx.getNodes().push_back(llvm::make_unique<FileNode>(std::move(file)));
+ }
+ }
+ return std::error_code();
+}
+
+std::error_code GnuLdDriver::evalLinkerScript(ELFLinkingContext &ctx,
+ std::unique_ptr<MemoryBuffer> mb,
+ raw_ostream &diag,
+ bool nostdlib) {
+ // Read the script file from disk and parse.
+ StringRef path = mb->getBufferIdentifier();
+ auto parser = llvm::make_unique<script::Parser>(std::move(mb));
+ if (std::error_code ec = parser->parse())
+ return ec;
+ script::LinkerScript *script = parser->get();
+ if (!script)
+ return LinkerScriptReaderError::parse_error;
+ // Evaluate script commands.
+ // Currently we only recognize this subset of linker script commands.
+ for (const script::Command *c : script->_commands) {
+ if (auto *input = dyn_cast<script::Input>(c))
+ if (std::error_code ec = addFilesFromLinkerScript(
+ ctx, path, input->getPaths(), diag))
+ return ec;
+ if (auto *group = dyn_cast<script::Group>(c)) {
+ int origSize = ctx.getNodes().size();
+ if (std::error_code ec = addFilesFromLinkerScript(
+ ctx, path, group->getPaths(), diag))
+ return ec;
+ size_t groupSize = ctx.getNodes().size() - origSize;
+ ctx.getNodes().push_back(llvm::make_unique<GroupEnd>(groupSize));
+ }
+ if (auto *searchDir = dyn_cast<script::SearchDir>(c))
+ if (!nostdlib)
+ ctx.addSearchPath(searchDir->getSearchPath());
+ if (auto *entry = dyn_cast<script::Entry>(c))
+ ctx.setEntrySymbolName(entry->getEntryName());
+ if (auto *output = dyn_cast<script::Output>(c))
+ ctx.setOutputPath(output->getOutputFileName());
+ if (auto *externs = dyn_cast<script::Extern>(c)) {
+ for (auto symbol : *externs) {
+ ctx.addInitialUndefinedSymbol(symbol);
+ }
+ }
+ }
+ // Transfer ownership of the script to the linking context
+ ctx.linkerScriptSema().addLinkerScript(std::move(parser));
+ return std::error_code();
+}
+
+bool GnuLdDriver::applyEmulation(llvm::Triple &triple,
+ llvm::opt::InputArgList &args,
+ raw_ostream &diag) {
+ llvm::opt::Arg *arg = args.getLastArg(OPT_m);
+ if (!arg)
+ return true;
+ llvm::Optional<llvm::Triple::ArchType> arch =
+ getArchType(triple, arg->getValue());
+ if (!arch) {
+ diag << "error: unsupported emulation '" << arg->getValue() << "'.\n";
+ return false;
+ }
+ triple.setArch(*arch);
+ return true;
+}
+
+void GnuLdDriver::addPlatformSearchDirs(ELFLinkingContext &ctx,
+ llvm::Triple &triple,
+ llvm::Triple &baseTriple) {
+ if (triple.getOS() == llvm::Triple::NetBSD &&
+ triple.getArch() == llvm::Triple::x86 &&
+ baseTriple.getArch() == llvm::Triple::x86_64) {
+ ctx.addSearchPath("=/usr/lib/i386");
+ return;
+ }
+ ctx.addSearchPath("=/usr/lib");
+}
+
+std::unique_ptr<ELFLinkingContext>
+GnuLdDriver::createELFLinkingContext(llvm::Triple triple) {
+ std::unique_ptr<ELFLinkingContext> p;
+ // FIXME: #include "llvm/Config/Targets.def"
+#define LLVM_TARGET(targetName) \
+ if ((p = elf::targetName##LinkingContext::create(triple))) return p;
+ LLVM_TARGET(AArch64)
+ LLVM_TARGET(ARM)
+ LLVM_TARGET(Hexagon)
+ LLVM_TARGET(Mips)
+ LLVM_TARGET(X86)
+ LLVM_TARGET(Example)
+ LLVM_TARGET(X86_64)
+#undef LLVM_TARGET
+ return nullptr;
+}
+
+static llvm::Optional<bool>
+getBool(const llvm::opt::InputArgList &parsedArgs,
+ unsigned yesFlag, unsigned noFlag) {
+ if (auto *arg = parsedArgs.getLastArg(yesFlag, noFlag))
+ return arg->getOption().getID() == yesFlag;
+ return llvm::None;
+}
+
+bool GnuLdDriver::parse(int argc, const char *argv[],
+ std::unique_ptr<ELFLinkingContext> &context,
+ raw_ostream &diag) {
+ // Parse command line options using GnuLdOptions.td
+ std::unique_ptr<llvm::opt::InputArgList> parsedArgs;
+ GnuLdOptTable table;
+ unsigned missingIndex;
+ unsigned missingCount;
+
+ parsedArgs.reset(
+ table.ParseArgs(&argv[1], &argv[argc], missingIndex, missingCount));
+ if (missingCount) {
+ diag << "error: missing arg value for '"
+ << parsedArgs->getArgString(missingIndex) << "' expected "
+ << missingCount << " argument(s).\n";
+ return false;
+ }
+
+ // Handle --help
+ if (parsedArgs->hasArg(OPT_help)) {
+ table.PrintHelp(llvm::outs(), argv[0], "LLVM Linker", false);
+ return true;
+ }
+
+ // Use -target or use default target triple to instantiate LinkingContext
+ llvm::Triple baseTriple;
+ if (auto *arg = parsedArgs->getLastArg(OPT_target)) {
+ baseTriple = llvm::Triple(arg->getValue());
+ } else {
+ baseTriple = getDefaultTarget(argv[0]);
+ }
+ llvm::Triple triple(baseTriple);
+
+ if (!applyEmulation(triple, *parsedArgs, diag))
+ return false;
+
+ std::unique_ptr<ELFLinkingContext> ctx(createELFLinkingContext(triple));
+
+ if (!ctx) {
+ diag << "unknown target triple\n";
+ return false;
+ }
+
+ // Copy mllvm
+ for (auto *arg : parsedArgs->filtered(OPT_mllvm))
+ ctx->appendLLVMOption(arg->getValue());
+
+ // Ignore unknown arguments.
+ for (auto unknownArg : parsedArgs->filtered(OPT_UNKNOWN))
+ diag << "warning: ignoring unknown argument: "
+ << unknownArg->getValue() << "\n";
+
+ // Set sys root path.
+ if (auto *arg = parsedArgs->getLastArg(OPT_sysroot))
+ ctx->setSysroot(arg->getValue());
+
+ // Handle --demangle option(For compatibility)
+ if (parsedArgs->hasArg(OPT_demangle))
+ ctx->setDemangleSymbols(true);
+
+ // Handle --no-demangle option.
+ if (parsedArgs->hasArg(OPT_no_demangle))
+ ctx->setDemangleSymbols(false);
+
+ // Figure out output kind (-r, -static, -shared)
+ if (parsedArgs->hasArg(OPT_relocatable)) {
+ ctx->setOutputELFType(llvm::ELF::ET_REL);
+ ctx->setPrintRemainingUndefines(false);
+ ctx->setAllowRemainingUndefines(true);
+ }
+
+ if (parsedArgs->hasArg(OPT_static)) {
+ ctx->setOutputELFType(llvm::ELF::ET_EXEC);
+ ctx->setIsStaticExecutable(true);
+ }
+
+ if (parsedArgs->hasArg(OPT_shared)) {
+ ctx->setOutputELFType(llvm::ELF::ET_DYN);
+ ctx->setAllowShlibUndefines(true);
+ ctx->setUseShlibUndefines(false);
+ ctx->setPrintRemainingUndefines(false);
+ ctx->setAllowRemainingUndefines(true);
+ }
+
+ // Handle --stats.
+ if (parsedArgs->hasArg(OPT_stats)) {
+ ctx->setCollectStats(true);
+ }
+
+ // Figure out if the output type is nmagic/omagic
+ if (auto *arg = parsedArgs->getLastArg(
+ OPT_nmagic, OPT_omagic, OPT_no_omagic)) {
+ switch (arg->getOption().getID()) {
+ case OPT_nmagic:
+ ctx->setOutputMagic(ELFLinkingContext::OutputMagic::NMAGIC);
+ ctx->setIsStaticExecutable(true);
+ break;
+ case OPT_omagic:
+ ctx->setOutputMagic(ELFLinkingContext::OutputMagic::OMAGIC);
+ ctx->setIsStaticExecutable(true);
+ break;
+ case OPT_no_omagic:
+ ctx->setOutputMagic(ELFLinkingContext::OutputMagic::DEFAULT);
+ ctx->setNoAllowDynamicLibraries();
+ break;
+ }
+ }
+
+ if (parsedArgs->hasArg(OPT_strip_all))
+ ctx->setStripSymbols(true);
+
+ if (auto *arg = parsedArgs->getLastArg(OPT_soname))
+ ctx->setSharedObjectName(arg->getValue());
+
+ if (parsedArgs->hasArg(OPT_rosegment))
+ ctx->setCreateSeparateROSegment();
+
+ if (parsedArgs->hasArg(OPT_no_align_segments))
+ ctx->setAlignSegments(false);
+
+ if (auto *arg = parsedArgs->getLastArg(OPT_image_base)) {
+ uint64_t baseAddress = 0;
+ StringRef inputValue = arg->getValue();
+ if (inputValue.getAsInteger(0, baseAddress) || !baseAddress) {
+ diag << "invalid value for image base " << inputValue << "\n";
+ return false;
+ }
+ ctx->setBaseAddress(baseAddress);
+ }
+
+ if (parsedArgs->hasArg(OPT_merge_strings))
+ ctx->setMergeCommonStrings(true);
+
+ if (parsedArgs->hasArg(OPT_t))
+ ctx->setLogInputFiles(true);
+
+ if (parsedArgs->hasArg(OPT_use_shlib_undefs))
+ ctx->setUseShlibUndefines(true);
+
+ if (auto val = getBool(*parsedArgs, OPT_allow_shlib_undefs,
+ OPT_no_allow_shlib_undefs))
+ ctx->setAllowShlibUndefines(*val);
+
+ if (auto *arg = parsedArgs->getLastArg(OPT_e))
+ ctx->setEntrySymbolName(arg->getValue());
+
+ if (auto *arg = parsedArgs->getLastArg(OPT_output))
+ ctx->setOutputPath(arg->getValue());
+
+ if (parsedArgs->hasArg(OPT_noinhibit_exec))
+ ctx->setAllowRemainingUndefines(true);
+
+ if (auto val = getBool(*parsedArgs, OPT_export_dynamic,
+ OPT_no_export_dynamic))
+ ctx->setExportDynamic(*val);
+
+ if (parsedArgs->hasArg(OPT_allow_multiple_definition))
+ ctx->setAllowDuplicates(true);
+
+ if (auto *arg = parsedArgs->getLastArg(OPT_dynamic_linker))
+ ctx->setInterpreter(arg->getValue());
+
+ if (auto *arg = parsedArgs->getLastArg(OPT_init))
+ ctx->setInitFunction(arg->getValue());
+
+ if (auto *arg = parsedArgs->getLastArg(OPT_fini))
+ ctx->setFiniFunction(arg->getValue());
+
+ if (auto *arg = parsedArgs->getLastArg(OPT_output_filetype))
+ ctx->setOutputFileType(arg->getValue());
+
+ for (auto *arg : parsedArgs->filtered(OPT_L))
+ ctx->addSearchPath(arg->getValue());
+
+ // Add the default search directory specific to the target.
+ if (!parsedArgs->hasArg(OPT_nostdlib))
+ addPlatformSearchDirs(*ctx, triple, baseTriple);
+
+ for (auto *arg : parsedArgs->filtered(OPT_u))
+ ctx->addInitialUndefinedSymbol(arg->getValue());
+
+ for (auto *arg : parsedArgs->filtered(OPT_defsym)) {
+ StringRef sym, target;
+ uint64_t addr;
+ if (parseDefsymAsAbsolute(arg->getValue(), sym, addr)) {
+ ctx->addInitialAbsoluteSymbol(sym, addr);
+ } else if (parseDefsymAsAlias(arg->getValue(), sym, target)) {
+ ctx->addAlias(sym, target);
+ } else {
+ diag << "invalid --defsym: " << arg->getValue() << "\n";
+ return false;
+ }
+ }
+
+ for (auto *arg : parsedArgs->filtered(OPT_z)) {
+ StringRef opt = arg->getValue();
+ if (opt == "muldefs") {
+ ctx->setAllowDuplicates(true);
+ } else if (opt.startswith("max-page-size")) {
+ // Parse -z max-page-size option.
+ // The default page size is considered the minimum page size the user
+ // can set, check the user input if its atleast the minimum page size
+ // and does not exceed the maximum page size allowed for the target.
+ uint64_t maxPageSize = 0;
+
+ // Error if the page size user set is less than the maximum page size
+ // and greather than the default page size and the user page size is a
+ // modulo of the default page size.
+ if ((!parseMaxPageSize(opt, maxPageSize)) ||
+ (maxPageSize < ctx->getPageSize()) ||
+ (maxPageSize % ctx->getPageSize())) {
+ diag << "invalid option: " << opt << "\n";
+ return false;
+ }
+ ctx->setMaxPageSize(maxPageSize);
+ } else {
+ diag << "warning: ignoring unknown argument for -z: " << opt << "\n";
+ }
+ }
+
+ for (auto *arg : parsedArgs->filtered(OPT_rpath)) {
+ SmallVector<StringRef, 2> rpaths;
+ StringRef(arg->getValue()).split(rpaths, ":");
+ for (auto path : rpaths)
+ ctx->addRpath(path);
+ }
+
+ for (auto *arg : parsedArgs->filtered(OPT_rpath_link)) {
+ SmallVector<StringRef, 2> rpaths;
+ StringRef(arg->getValue()).split(rpaths, ":");
+ for (auto path : rpaths)
+ ctx->addRpathLink(path);
+ }
+
+ // Support --wrap option.
+ for (auto *arg : parsedArgs->filtered(OPT_wrap))
+ ctx->addWrapForSymbol(arg->getValue());
+
+ // Register possible input file parsers.
+ ctx->registry().addSupportELFObjects(*ctx);
+ ctx->registry().addSupportArchives(ctx->logInputFiles());
+ ctx->registry().addSupportYamlFiles();
+ ctx->registry().addSupportNativeObjects();
+ if (ctx->allowLinkWithDynamicLibraries())
+ ctx->registry().addSupportELFDynamicSharedObjects(*ctx);
+
+ std::stack<int> groupStack;
+ int numfiles = 0;
+ bool asNeeded = false;
+ bool wholeArchive = false;
+
+ // Process files
+ for (auto arg : *parsedArgs) {
+ switch (arg->getOption().getID()) {
+ case OPT_no_whole_archive:
+ wholeArchive = false;
+ break;
+
+ case OPT_whole_archive:
+ wholeArchive = true;
+ break;
+
+ case OPT_as_needed:
+ asNeeded = true;
+ break;
+
+ case OPT_no_as_needed:
+ asNeeded = false;
+ break;
+
+ case OPT_start_group:
+ groupStack.push(numfiles);
+ break;
+
+ case OPT_end_group: {
+ if (groupStack.empty()) {
+ diag << "stray --end-group\n";
+ return false;
+ }
+ int startGroupPos = groupStack.top();
+ ctx->getNodes().push_back(
+ llvm::make_unique<GroupEnd>(numfiles - startGroupPos));
+ groupStack.pop();
+ break;
+ }
+
+ case OPT_INPUT:
+ case OPT_l:
+ case OPT_T: {
+ bool dashL = (arg->getOption().getID() == OPT_l);
+ StringRef path = arg->getValue();
+
+ ErrorOr<StringRef> pathOrErr = findFile(*ctx, path, dashL);
+ if (std::error_code ec = pathOrErr.getError()) {
+ auto file = llvm::make_unique<ErrorFile>(path, ec);
+ auto node = llvm::make_unique<FileNode>(std::move(file));
+ node->setAsNeeded(asNeeded);
+ ctx->getNodes().push_back(std::move(node));
+ break;
+ }
+ StringRef realpath = pathOrErr.get();
+
+ bool isScript =
+ (!path.endswith(".objtxt") && isLinkerScript(realpath, diag));
+ if (isScript) {
+ if (ctx->logInputFiles())
+ diag << path << "\n";
+ ErrorOr<std::unique_ptr<MemoryBuffer>> mb =
+ MemoryBuffer::getFileOrSTDIN(realpath);
+ if (std::error_code ec = mb.getError()) {
+ diag << "Cannot open " << path << ": " << ec.message() << "\n";
+ return false;
+ }
+ bool nostdlib = parsedArgs->hasArg(OPT_nostdlib);
+ std::error_code ec =
+ evalLinkerScript(*ctx, std::move(mb.get()), diag, nostdlib);
+ if (ec) {
+ diag << path << ": Error parsing linker script: "
+ << ec.message() << "\n";
+ return false;
+ }
+ break;
+ }
+ std::vector<std::unique_ptr<File>> files
+ = loadFile(*ctx, realpath, wholeArchive);
+ for (std::unique_ptr<File> &file : files) {
+ if (ctx->logInputFiles())
+ diag << file->path() << "\n";
+ auto node = llvm::make_unique<FileNode>(std::move(file));
+ node->setAsNeeded(asNeeded);
+ ctx->getNodes().push_back(std::move(node));
+ }
+ numfiles += files.size();
+ break;
+ }
+ }
+ }
+
+ if (ctx->getNodes().empty()) {
+ diag << "No input files\n";
+ return false;
+ }
+
+ // Set default output file name if the output file was not specified.
+ if (ctx->outputPath().empty()) {
+ switch (ctx->outputFileType()) {
+ case LinkingContext::OutputFileType::YAML:
+ ctx->setOutputPath("-");
+ break;
+ case LinkingContext::OutputFileType::Native:
+ ctx->setOutputPath("a.native");
+ break;
+ default:
+ ctx->setOutputPath("a.out");
+ break;
+ }
+ }
+
+ // Validate the combination of options used.
+ if (!ctx->validate(diag))
+ return false;
+
+ // Perform linker script semantic actions
+ ctx->linkerScriptSema().perform();
+
+ context.swap(ctx);
+ return true;
+}
+
+/// Get the default target triple based on either the program name
+/// (e.g. "x86-ibm-linux-lld") or the primary target llvm was configured for.
+llvm::Triple GnuLdDriver::getDefaultTarget(const char *progName) {
+ SmallVector<StringRef, 4> components;
+ llvm::SplitString(llvm::sys::path::stem(progName), components, "-");
+ // If has enough parts to be start with a triple.
+ if (components.size() >= 4) {
+ llvm::Triple triple(components[0], components[1], components[2],
+ components[3]);
+ // If first component looks like an arch.
+ if (triple.getArch() != llvm::Triple::UnknownArch)
+ return triple;
+ }
+
+ // Fallback to use whatever default triple llvm was configured for.
+ return llvm::Triple(llvm::sys::getDefaultTargetTriple());
+}
diff --git a/lib/Driver/GnuLdOptions.td b/lib/Driver/GnuLdOptions.td
new file mode 100644
index 000000000000..9d06f2935439
--- /dev/null
+++ b/lib/Driver/GnuLdOptions.td
@@ -0,0 +1,323 @@
+include "llvm/Option/OptParser.td"
+
+//===----------------------------------------------------------------------===//
+/// Utility Functions
+//===----------------------------------------------------------------------===//
+// Single and multiple dash options combined
+multiclass smDash<string opt1, string opt2, string help> {
+ // Option
+ def "" : Separate<["-"], opt1>, HelpText<help>;
+ def opt1_eq : Joined<["-"], opt1#"=">,
+ Alias<!cast<Option>(opt1)>;
+ // Compatibility aliases
+ def opt2_dashdash : Separate<["--"], opt2>,
+ Alias<!cast<Option>(opt1)>;
+ def opt2_dashdash_eq : Joined<["--"], opt2#"=">,
+ Alias<!cast<Option>(opt1)>;
+}
+
+// Support -<option>,-<option>=
+multiclass dashEq<string opt1, string opt2, string help> {
+ // Option
+ def "" : Separate<["-"], opt1>, HelpText<help>;
+ // Compatibility aliases
+ def opt2_eq : Joined<["-"], opt2#"=">,
+ Alias<!cast<Option>(opt1)>;
+}
+
+//===----------------------------------------------------------------------===//
+/// LLVM and Target options
+//===----------------------------------------------------------------------===//
+def grp_llvmtarget : OptionGroup<"opts">,
+ HelpText<"LLVM and Target Options">;
+def mllvm : Separate<["-"], "mllvm">,
+ HelpText<"Options to pass to LLVM">, Group<grp_llvmtarget>;
+def target : Separate<["-"], "target">, MetaVarName<"<triple>">,
+ HelpText<"Target triple to link for">,
+ Group<grp_llvmtarget>;
+
+//===----------------------------------------------------------------------===//
+/// Output Kinds
+//===----------------------------------------------------------------------===//
+def grp_kind : OptionGroup<"outs">,
+ HelpText<"OUTPUT KIND">;
+def relocatable : Flag<["-"], "r">,
+ HelpText<"Create relocatable object file">, Group<grp_kind>;
+def static : Flag<["-"], "static">,
+ HelpText<"Create static executable">, Group<grp_kind>;
+def dynamic : Flag<["-"], "dynamic">,
+ HelpText<"Create dynamic executable (default)">,Group<grp_kind>;
+def shared : Flag<["-"], "shared">,
+ HelpText<"Create dynamic library">, Group<grp_kind>;
+
+// output kinds - compatibility aliases
+def Bstatic : Flag<["-"], "Bstatic">, Alias<static>;
+def Bshareable : Flag<["-"], "Bshareable">, Alias<shared>;
+
+//===----------------------------------------------------------------------===//
+/// General Options
+//===----------------------------------------------------------------------===//
+def grp_general : OptionGroup<"opts">,
+ HelpText<"GENERAL OPTIONS">;
+def output : Separate<["-"], "o">, MetaVarName<"<path>">,
+ HelpText<"Path to file to write output">,
+ Group<grp_general>;
+def m : Separate<["-"], "m">, MetaVarName<"<emulation>">,
+ HelpText<"Select target emulation">,
+ Group<grp_general>;
+def build_id : Flag<["--"], "build-id">,
+ HelpText<"Request creation of \".note.gnu.build-id\" ELF note section">,
+ Group<grp_general>;
+def sysroot : Joined<["--"], "sysroot=">,
+ HelpText<"Set the system root">,
+ Group<grp_general>;
+
+
+//===----------------------------------------------------------------------===//
+/// Executable Options
+//===----------------------------------------------------------------------===//
+def grp_main : OptionGroup<"opts">,
+ HelpText<"EXECUTABLE OPTIONS">;
+def L : Joined<["-"], "L">, MetaVarName<"<dir>">,
+ HelpText<"Directory to search for libraries">,
+ Group<grp_main>;
+def l : Joined<["-"], "l">, MetaVarName<"<libName>">,
+ HelpText<"Root name of library to use">,
+ Group<grp_main>;
+def noinhibit_exec : Flag<["--"], "noinhibit-exec">,
+ HelpText<"Retain the executable output file whenever"
+ " it is still usable">,
+ Group<grp_main>;
+defm e : smDash<"e", "entry",
+ "Name of entry point symbol">,
+ Group<grp_main>;
+defm init: dashEq<"init", "init",
+ "Specify an initializer function">,
+ Group<grp_main>;
+defm fini: dashEq<"fini", "fini",
+ "Specify a finalizer function">,
+ Group<grp_main>;
+def whole_archive: Flag<["--"], "whole-archive">,
+ HelpText<"Force load of all members in a static library">,
+ Group<grp_main>;
+def no_whole_archive: Flag<["--"], "no-whole-archive">,
+ HelpText<"Restores the default behavior of loading archive members">,
+ Group<grp_main>;
+def nostdlib : Flag<["-"], "nostdlib">,
+ HelpText<"Disable default search path for libraries">,
+ Group<grp_main>;
+def image_base : Separate<["--"], "image-base">,
+ HelpText<"Set the base address">,
+ Group<grp_main>;
+
+//===----------------------------------------------------------------------===//
+/// Static Executable Options
+//===----------------------------------------------------------------------===//
+def grp_staticexec : OptionGroup<"opts">,
+ HelpText<"STATIC EXECUTABLE OPTIONS">;
+def nmagic : Flag<["--"], "nmagic">,
+ HelpText<"Turn off page alignment of sections,"
+ " and disable linking against shared libraries">,
+ Group<grp_staticexec>;
+def omagic : Flag<["--"], "omagic">,
+ HelpText<"Set the text and data sections to be readable and writable."
+ " Also, do not page-align the data segment, and"
+ " disable linking against shared libraries.">,
+ Group<grp_staticexec>;
+def no_omagic : Flag<["--"], "no-omagic">,
+ HelpText<"This option negates most of the effects of the -N option."
+ "Disable linking with shared libraries">,
+ Group<grp_staticexec>;
+// Compatible Aliases
+def nmagic_alias : Flag<["-"], "n">,
+ Alias<nmagic>;
+def omagic_alias : Flag<["-"], "N">,
+ Alias<omagic>;
+
+//===----------------------------------------------------------------------===//
+/// Dynamic Library/Executable Options
+//===----------------------------------------------------------------------===//
+def grp_dynlibexec : OptionGroup<"opts">,
+ HelpText<"DYNAMIC LIBRARY/EXECUTABLE OPTIONS">;
+def dynamic_linker : Joined<["--"], "dynamic-linker=">,
+ HelpText<"Set the path to the dynamic linker">, Group<grp_dynlibexec>;
+// Executable options - compatibility aliases
+def dynamic_linker_alias : Separate<["-"], "dynamic-linker">,
+ Alias<dynamic_linker>;
+defm rpath : dashEq<"rpath", "rpath",
+ "Add a directory to the runtime library search path">,
+ Group<grp_dynlibexec>;
+def rpath_link : Separate<["-"], "rpath-link">,
+ HelpText<"Specifies the first set of directories to search">,
+ Group<grp_dynlibexec>;
+def export_dynamic : Flag<["-", "--"], "export-dynamic">,
+ HelpText<"Add all symbols to the dynamic symbol table"
+ " when creating executables">,
+ Group<grp_main>;
+def alias_export_dynamic: Flag<["-"], "E">,
+ Alias<export_dynamic>;
+def no_export_dynamic : Flag<["--"], "no-export-dynamic">,
+ Group<grp_main>;
+
+//===----------------------------------------------------------------------===//
+/// Dynamic Library Options
+//===----------------------------------------------------------------------===//
+def grp_dynlib : OptionGroup<"opts">,
+ HelpText<"DYNAMIC LIBRARY OPTIONS">;
+def soname : Joined<["-", "--"], "soname=">,
+ HelpText<"Set the internal DT_SONAME field to the specified name">,
+ Group<grp_dynlib>;
+def soname_separate : Separate<["-", "--"], "soname">, Alias<soname>;
+def soname_h : Separate<["-"], "h">, Alias<soname>;
+
+//===----------------------------------------------------------------------===//
+/// Resolver Options
+//===----------------------------------------------------------------------===//
+def grp_resolveropt : OptionGroup<"opts">,
+ HelpText<"SYMBOL RESOLUTION OPTIONS">;
+defm u : smDash<"u", "undefined",
+ "Force symbol to be entered in the output file"
+ " as an undefined symbol">,
+ Group<grp_resolveropt>;
+def start_group : Flag<["--"], "start-group">,
+ HelpText<"Start a group">,
+ Group<grp_resolveropt>;
+def alias_start_group: Flag<["-"], "(">,
+ Alias<start_group>;
+def end_group : Flag<["--"], "end-group">,
+ HelpText<"End a group">,
+ Group<grp_resolveropt>;
+def alias_end_group: Flag<["-"], ")">,
+ Alias<end_group>;
+def as_needed : Flag<["--"], "as-needed">,
+ HelpText<"This option affects ELF DT_NEEDED tags for "
+ "dynamic libraries mentioned on the command line">,
+ Group<grp_resolveropt>;
+def no_as_needed : Flag<["--"], "no-as-needed">,
+ HelpText<"This option restores the default behavior"
+ " of adding DT_NEEDED entries">,
+ Group<grp_resolveropt>;
+def no_allow_shlib_undefs : Flag<["--"], "no-allow-shlib-undefined">,
+ HelpText<"Do not allow undefined symbols from dynamic"
+ " library when creating executables">,
+ Group<grp_resolveropt>;
+def allow_shlib_undefs : Flag<["-", "--"], "allow-shlib-undefined">,
+ HelpText<"Allow undefined symbols from dynamic"
+ " library when creating executables">,
+ Group<grp_resolveropt>;
+def use_shlib_undefs: Flag<["--"], "use-shlib-undefines">,
+ HelpText<"Resolve undefined symbols from dynamic libraries">,
+ Group<grp_resolveropt>;
+def allow_multiple_definition: Flag<["--"], "allow-multiple-definition">,
+ HelpText<"Allow multiple definitions">,
+ Group<grp_resolveropt>;
+def defsym : Joined<["--"], "defsym=">,
+ HelpText<"Create a defined symbol">,
+ Group<grp_resolveropt>;
+
+//===----------------------------------------------------------------------===//
+/// Custom Options
+//===----------------------------------------------------------------------===//
+def grp_customopts : OptionGroup<"opts">,
+ HelpText<"CUSTOM OPTIONS">;
+def rosegment: Flag<["--"], "rosegment">,
+ HelpText<"Put read-only non-executable sections in their own segment">,
+ Group<grp_customopts>;
+def z : Separate<["-"], "z">,
+ HelpText<"Linker Option extensions">,
+ Group<grp_customopts>;
+def no_align_segments: Flag<["--"], "no-align-segments">,
+ HelpText<"Don't align ELF segments(virtualaddress/fileoffset) to page boundaries">,
+ Group<grp_customopts>;
+
+//===----------------------------------------------------------------------===//
+/// Symbol options
+//===----------------------------------------------------------------------===//
+def grp_symbolopts : OptionGroup<"opts">,
+ HelpText<"SYMBOL OPTIONS">;
+def demangle : Flag<["--"], "demangle">,
+ HelpText<"Demangle C++ symbols">,
+ Group<grp_symbolopts>;
+def no_demangle : Flag<["--"], "no-demangle">,
+ HelpText<"Dont demangle C++ symbols">,
+ Group<grp_symbolopts>;
+def strip_all : Flag<["--"], "strip-all">,
+ HelpText<"Omit all symbol informations from output">,
+ Group<grp_symbolopts>;
+def alias_strip_all : Flag<["-"], "s">,
+ Alias<strip_all>;
+defm wrap : smDash<"wrap", "wrap",
+ "Use a wrapper function for symbol. Any "
+ " undefined reference to symbol will be resolved to "
+ "\"__wrap_symbol\". Any undefined reference to \"__real_symbol\""
+ " will be resolved to symbol.">,
+ MetaVarName<"<symbol>">,
+ Group<grp_symbolopts>;
+
+//===----------------------------------------------------------------------===//
+/// Script Options
+//===----------------------------------------------------------------------===//
+def grp_scriptopts : OptionGroup<"opts">,
+ HelpText<"SCRIPT OPTIONS">;
+defm T : smDash<"T", "script",
+ "Use the given linker script in place of the default script.">,
+ Group<grp_scriptopts>;
+
+//===----------------------------------------------------------------------===//
+/// Optimization Options
+//===----------------------------------------------------------------------===//
+def grp_opts : OptionGroup<"opts">,
+ HelpText<"OPTIMIZATIONS">;
+def hash_style : Joined <["--"], "hash-style=">,
+ HelpText<"Set the type of linker's hash table(s)">,
+ Group<grp_opts>;
+def merge_strings : Flag<["--"], "merge-strings">,
+ HelpText<"Merge common strings across mergeable sections">,
+ Group<grp_opts>;
+def eh_frame_hdr : Flag<["--"], "eh-frame-hdr">,
+ HelpText<"Request creation of .eh_frame_hdr section and ELF "
+ " PT_GNU_EH_FRAME segment header">,
+ Group<grp_opts>;
+
+//===----------------------------------------------------------------------===//
+/// Tracing Options
+//===----------------------------------------------------------------------===//
+def grp_tracingopts : OptionGroup<"opts">,
+ HelpText<"TRACING OPTIONS">;
+def t : Flag<["-"], "t">,
+ HelpText<"Print the names of the input files as ld processes them">,
+ Group<grp_tracingopts>;
+def stats : Flag<["--"], "stats">,
+ HelpText<"Print time and memory usage stats">, Group<grp_tracingopts>;
+
+//===----------------------------------------------------------------------===//
+/// Extensions
+//===----------------------------------------------------------------------===//
+def grp_extns : OptionGroup<"opts">,
+ HelpText<"Extensions">;
+def output_filetype: Separate<["--"], "output-filetype">,
+ HelpText<"Specify what type of output file that lld creates, YAML/Native">,
+ Group<grp_extns>;
+def alias_output_filetype: Joined<["--"], "output-filetype=">,
+ Alias<output_filetype>;
+
+//===----------------------------------------------------------------------===//
+/// Ignored options
+//===----------------------------------------------------------------------===//
+def grp_ignored: OptionGroup<"ignored">,
+ HelpText<"GNU Options ignored for Compatibility ">;
+def dashg : Flag<["-"], "g">,
+ HelpText<"Ignored.">,
+ Group<grp_ignored>;
+def Qy : Flag<["-"], "Qy">,
+ HelpText<"Ignored for SVR4 Compatibility">,
+ Group<grp_ignored>;
+def qmagic : Flag<["-"], "qmagic">,
+ HelpText<"Ignored for Linux Compatibility">,
+ Group<grp_ignored>;
+
+//===----------------------------------------------------------------------===//
+/// Help
+//===----------------------------------------------------------------------===//
+def help : Flag<["--"], "help">,
+ HelpText<"Display this help message">;
diff --git a/lib/Driver/Makefile b/lib/Driver/Makefile
new file mode 100644
index 000000000000..19024cfab0f1
--- /dev/null
+++ b/lib/Driver/Makefile
@@ -0,0 +1,38 @@
+##===- lld/lib/Driver/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 := lldDriver
+
+BUILT_SOURCES = CoreOptions.inc UniversalDriverOptions.inc DarwinLdOptions.inc \
+ GnuLdOptions.inc WinLinkOptions.inc
+
+TABLEGEN_INC_FILES_COMMON = 1
+
+include $(LLD_LEVEL)/Makefile
+
+$(ObjDir)/CoreOptions.inc.tmp : CoreOptions.td $(LLVM_TBLGEN) $(ObjDir)/.dir
+ $(Echo) "Building LLD CoreOptions Option tables with tblgen"
+ $(Verb) $(LLVMTableGen) -gen-opt-parser-defs -o $(call SYSPATH, $@) $<
+
+$(ObjDir)/UniversalDriverOptions.inc.tmp : UniversalDriverOptions.td $(LLVM_TBLGEN) $(ObjDir)/.dir
+ $(Echo) "Building LLD Universal Driver Options tables with tblgen"
+ $(Verb) $(LLVMTableGen) -gen-opt-parser-defs -o $(call SYSPATH, $@) $<
+
+$(ObjDir)/DarwinLdOptions.inc.tmp : DarwinLdOptions.td $(LLVM_TBLGEN) $(ObjDir)/.dir
+ $(Echo) "Building LLD Darwin ld Option tables with tblgen"
+ $(Verb) $(LLVMTableGen) -gen-opt-parser-defs -o $(call SYSPATH, $@) $<
+
+$(ObjDir)/GnuLdOptions.inc.tmp : GnuLdOptions.td $(LLVM_TBLGEN) $(ObjDir)/.dir
+ $(Echo) "Building LLD Gnu ld Option tables with tblgen"
+ $(Verb) $(LLVMTableGen) -gen-opt-parser-defs -o $(call SYSPATH, $@) $<
+
+$(ObjDir)/WinLinkOptions.inc.tmp : WinLinkOptions.td $(LLVM_TBLGEN) $(ObjDir)/.dir
+ $(Echo) "Building LLD WinLinkOptions Option tables with tblgen"
+ $(Verb) $(LLVMTableGen) -gen-opt-parser-defs -o $(call SYSPATH, $@) $<
diff --git a/lib/Driver/TODO.rst b/lib/Driver/TODO.rst
new file mode 100644
index 000000000000..e03d829c232d
--- /dev/null
+++ b/lib/Driver/TODO.rst
@@ -0,0 +1,101 @@
+GNU ld Driver
+~~~~~~~~~~~~~
+
+Missing Options
+###############
+
+* --audit
+* -A,--architecture
+* -b,--format
+* -d,-dc,-dp
+* -P,--depaudit
+* --exclude-libs
+* --exclude-modules-for-implib
+* -E,--export-dynamic,--no-export-dynamic
+* -EB (We probably shouldn't support this)
+* -EL (We probably shouldn't support this)
+* -f,--auxiliary
+* -F,--filter
+* -G,--gpsize
+* -h
+* -i
+* --library
+* -M
+* --print-map
+* -output
+* -O
+* -q,--emit-relocs
+* --force-dynamic
+* --relocatable
+* -R,--just-symbols
+* -s,--strip-all
+* -S,--strip-debug
+* --trace
+* -dT,--default-script
+* -Ur
+* --unique
+* -v,--version,-V
+* -x,--discard-all
+* -X,--discard-locals
+* -y,--trace-symbol
+* -z (keywords need to be implemented)
+* --accept-unknown-input-arch,--no-accept-unknown-input-arch
+* -Bdynamic,-dy,-call_shared
+* -Bgroup
+* -dn,-non_shared
+* -Bsymbolic
+* -Bsymbolic-functions
+* --dynamic-list
+* --dynamic-list-data
+* --dynamic-list-cpp-new
+* --dynamic-list-cpp-typeinfo
+* --check-sections,--no-check-sections
+* --copy-dt-needed-entries,--no-copy-dt-needed-entires
+* --cref
+* --no-define-common
+* --defsym (only absolute value supported now)
+* --demangle,--no-demangle
+* -I
+* --fatal-warnings,--no-fatal-warnings
+* --force-exe-suffix
+* --gc-sections,--no-gc-sections
+* --print-gc-sections,--no-print-gc-sections
+* --print-output-format
+* --target-help
+* -Map
+* --no-keep-memory
+* --no-undefined,-z defs
+* --allow-shlib-undefined,--no-alow-shlib-undefined
+* --no-undefined-version
+* --default-symver
+* --default-imported-symver
+* --no-warn-mismatch
+* --no-warn-search-mismatch
+* --oformat
+* -pie,--pic-executable
+* --relax,--no-relax
+* --retain-symbols-file
+* --sort-common
+* --sort-section={name,alignment}
+* --split-by-file
+* --split-by-reloc
+* --stats
+* --section-start
+* -T{bss,data,text,{text,rodata,data}-segment}
+* --unresolved-symbols
+* -dll-verbose,--verbose
+* --version-script
+* --warn-common
+* --warn-constructors
+* --warn-multiple-gp
+* --warn-once
+* --warn-section-align
+* --warn-shared-textrel
+* --warn-alternate-em
+* --warn-unresolved-symbols
+* --error-unresolved-symbols
+* --wrap
+* --no-ld-generated-unwind-info
+* --hash-size
+* --reduce-memory-overheads
+* --build-id
diff --git a/lib/Driver/UniversalDriver.cpp b/lib/Driver/UniversalDriver.cpp
new file mode 100644
index 000000000000..7d42ad7b4bfc
--- /dev/null
+++ b/lib/Driver/UniversalDriver.cpp
@@ -0,0 +1,218 @@
+//===- lib/Driver/UniversalDriver.cpp -------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+///
+/// Driver for "universal" lld tool which can mimic any linker command line
+/// parsing once it figures out which command line flavor to use.
+///
+//===----------------------------------------------------------------------===//
+
+#include "lld/Driver/Driver.h"
+#include "lld/Config/Version.h"
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace lld;
+
+namespace {
+
+// Create enum with OPT_xxx values for each option in GnuLdOptions.td
+enum {
+ OPT_INVALID = 0,
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELP, META) \
+ OPT_##ID,
+#include "UniversalDriverOptions.inc"
+#undef OPTION
+};
+
+// Create prefix string literals used in GnuLdOptions.td
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#include "UniversalDriverOptions.inc"
+#undef PREFIX
+
+// Create table mapping all options defined in GnuLdOptions.td
+static const llvm::opt::OptTable::Info infoTable[] = {
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR) \
+ { \
+ PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \
+ PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS \
+ } \
+ ,
+#include "UniversalDriverOptions.inc"
+#undef OPTION
+};
+
+// Create OptTable class for parsing actual command line arguments
+class UniversalDriverOptTable : public llvm::opt::OptTable {
+public:
+ UniversalDriverOptTable()
+ : OptTable(infoTable, llvm::array_lengthof(infoTable)) {}
+};
+
+enum class Flavor {
+ invalid,
+ gnu_ld, // -flavor gnu
+ win_link, // -flavor link
+ darwin_ld, // -flavor darwin
+ core // -flavor core OR -core
+};
+
+struct ProgramNameParts {
+ StringRef _target;
+ StringRef _flavor;
+};
+
+} // anonymous namespace
+
+static Flavor strToFlavor(StringRef str) {
+ return llvm::StringSwitch<Flavor>(str)
+ .Case("gnu", Flavor::gnu_ld)
+ .Case("link", Flavor::win_link)
+ .Case("lld-link", Flavor::win_link)
+ .Case("darwin", Flavor::darwin_ld)
+ .Case("core", Flavor::core)
+ .Case("ld", Flavor::gnu_ld)
+ .Default(Flavor::invalid);
+}
+
+static ProgramNameParts parseProgramName(StringRef programName) {
+ SmallVector<StringRef, 3> components;
+ llvm::SplitString(programName, components, "-");
+ ProgramNameParts ret;
+
+ using std::begin;
+ using std::end;
+
+ // Erase any lld components.
+ components.erase(std::remove(components.begin(), components.end(), "lld"),
+ components.end());
+
+ // Find the flavor component.
+ auto flIter = std::find_if(components.begin(), components.end(),
+ [](StringRef str) -> bool {
+ return strToFlavor(str) != Flavor::invalid;
+ });
+
+ if (flIter != components.end()) {
+ ret._flavor = *flIter;
+ components.erase(flIter);
+ }
+
+ // Any remaining component must be the target.
+ if (components.size() == 1)
+ ret._target = components[0];
+
+ return ret;
+}
+
+// Removes the argument from argv along with its value, if exists, and updates
+// argc.
+static void removeArg(llvm::opt::Arg *arg, int &argc, const char **&argv) {
+ unsigned int numToRemove = arg->getNumValues() + 1;
+ unsigned int argIndex = arg->getIndex() + 1;
+
+ std::rotate(&argv[argIndex], &argv[argIndex + numToRemove], argv + argc);
+ argc -= numToRemove;
+}
+
+static Flavor getFlavor(int &argc, const char **&argv,
+ std::unique_ptr<llvm::opt::InputArgList> &parsedArgs) {
+ if (llvm::opt::Arg *argCore = parsedArgs->getLastArg(OPT_core)) {
+ removeArg(argCore, argc, argv);
+ return Flavor::core;
+ }
+ if (llvm::opt::Arg *argFlavor = parsedArgs->getLastArg(OPT_flavor)) {
+ removeArg(argFlavor, argc, argv);
+ return strToFlavor(argFlavor->getValue());
+ }
+
+#if LLVM_ON_UNIX
+ if (llvm::sys::path::filename(argv[0]).equals("ld")) {
+#if __APPLE__
+ // On a Darwin systems, if linker binary is named "ld", use Darwin driver.
+ return Flavor::darwin_ld;
+#endif
+ // On a ELF based systems, if linker binary is named "ld", use gnu driver.
+ return Flavor::gnu_ld;
+ }
+#endif
+
+ StringRef name = llvm::sys::path::stem(argv[0]);
+ return strToFlavor(parseProgramName(name)._flavor);
+}
+
+namespace lld {
+
+bool UniversalDriver::link(int argc, const char *argv[],
+ raw_ostream &diagnostics) {
+ // Parse command line options using GnuLdOptions.td
+ std::unique_ptr<llvm::opt::InputArgList> parsedArgs;
+ UniversalDriverOptTable table;
+ unsigned missingIndex;
+ unsigned missingCount;
+
+ // Program name
+ StringRef programName = llvm::sys::path::stem(argv[0]);
+
+ parsedArgs.reset(
+ table.ParseArgs(&argv[1], &argv[argc], missingIndex, missingCount));
+
+ if (missingCount) {
+ diagnostics << "error: missing arg value for '"
+ << parsedArgs->getArgString(missingIndex) << "' expected "
+ << missingCount << " argument(s).\n";
+ return false;
+ }
+
+ // Handle -help
+ if (parsedArgs->getLastArg(OPT_help)) {
+ table.PrintHelp(llvm::outs(), programName.data(), "LLVM Linker", false);
+ return true;
+ }
+
+ // Handle -version
+ if (parsedArgs->getLastArg(OPT_version)) {
+ diagnostics << "LLVM Linker Version: " << getLLDVersion()
+ << getLLDRepositoryVersion() << "\n";
+ return true;
+ }
+
+ Flavor flavor = getFlavor(argc, argv, parsedArgs);
+ std::vector<const char *> args(argv, argv + argc);
+
+ // Switch to appropriate driver.
+ switch (flavor) {
+ case Flavor::gnu_ld:
+ return GnuLdDriver::linkELF(args.size(), args.data(), diagnostics);
+ case Flavor::darwin_ld:
+ return DarwinLdDriver::linkMachO(args.size(), args.data(), diagnostics);
+ case Flavor::win_link:
+ return WinLinkDriver::linkPECOFF(args.size(), args.data(), diagnostics);
+ case Flavor::core:
+ return CoreDriver::link(args.size(), args.data(), diagnostics);
+ case Flavor::invalid:
+ diagnostics << "Select the appropriate flavor\n";
+ table.PrintHelp(llvm::outs(), programName.data(), "LLVM Linker", false);
+ return false;
+ }
+ llvm_unreachable("Unrecognised flavor");
+}
+
+} // end namespace lld
diff --git a/lib/Driver/UniversalDriverOptions.td b/lib/Driver/UniversalDriverOptions.td
new file mode 100644
index 000000000000..14abc9ce9911
--- /dev/null
+++ b/lib/Driver/UniversalDriverOptions.td
@@ -0,0 +1,19 @@
+include "llvm/Option/OptParser.td"
+
+// Select an optional flavor
+def flavor: Separate<["-"], "flavor">,
+ HelpText<"Flavor for linking, options are gnu/darwin/link">;
+
+// Select the core flavor
+def core : Flag<["-"], "core">,
+ HelpText<"CORE linking">;
+
+def target: Separate<["-"], "target">,
+ HelpText<"Select the target">;
+
+def version: Flag<["-"], "version">,
+ HelpText<"Display the version">;
+
+// Help message
+def help : Flag<["-"], "help">,
+ HelpText<"Display this help message">;
diff --git a/lib/Driver/WinLinkDriver.cpp b/lib/Driver/WinLinkDriver.cpp
new file mode 100644
index 000000000000..6ee7a5a004b5
--- /dev/null
+++ b/lib/Driver/WinLinkDriver.cpp
@@ -0,0 +1,1371 @@
+//===- lib/Driver/WinLinkDriver.cpp ---------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+///
+/// Concrete instance of the Driver for Windows link.exe.
+///
+//===----------------------------------------------------------------------===//
+
+#include "lld/Driver/Driver.h"
+#include "lld/Driver/WinLinkModuleDef.h"
+#include "lld/ReaderWriter/PECOFFLinkingContext.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cctype>
+#include <map>
+#include <memory>
+#include <sstream>
+#include <tuple>
+
+namespace lld {
+
+//
+// Option definitions
+//
+
+// Create enum with OPT_xxx values for each option in WinLinkOptions.td
+enum {
+ OPT_INVALID = 0,
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELP, META) \
+ OPT_##ID,
+#include "WinLinkOptions.inc"
+#undef OPTION
+};
+
+// Create prefix string literals used in WinLinkOptions.td
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#include "WinLinkOptions.inc"
+#undef PREFIX
+
+// Create table mapping all options defined in WinLinkOptions.td
+static const llvm::opt::OptTable::Info infoTable[] = {
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR) \
+ { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \
+ PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS },
+#include "WinLinkOptions.inc"
+#undef OPTION
+};
+
+namespace {
+
+// Create OptTable class for parsing actual command line arguments
+class WinLinkOptTable : public llvm::opt::OptTable {
+public:
+ // link.exe's command line options are case insensitive, unlike
+ // other driver's options for Unix.
+ WinLinkOptTable()
+ : OptTable(infoTable, llvm::array_lengthof(infoTable),
+ /* ignoreCase */ true) {}
+};
+
+} // anonymous namespace
+
+//
+// Functions to parse each command line option
+//
+
+// Split the given string with spaces.
+static std::vector<std::string> splitArgList(const std::string &str) {
+ std::stringstream stream(str);
+ std::istream_iterator<std::string> begin(stream);
+ std::istream_iterator<std::string> end;
+ return std::vector<std::string>(begin, end);
+}
+
+// Split the given string with the path separator.
+static std::vector<StringRef> splitPathList(StringRef str) {
+ std::vector<StringRef> ret;
+ while (!str.empty()) {
+ StringRef path;
+ std::tie(path, str) = str.split(';');
+ ret.push_back(path);
+ }
+ return ret;
+}
+
+// Parse an argument for /alternatename. The expected string is
+// "<string>=<string>".
+static bool parseAlternateName(StringRef arg, StringRef &weak, StringRef &def,
+ raw_ostream &diag) {
+ std::tie(weak, def) = arg.split('=');
+ if (weak.empty() || def.empty()) {
+ diag << "Error: malformed /alternatename option: " << arg << "\n";
+ return false;
+ }
+ return true;
+}
+
+// Parse an argument for /base, /stack or /heap. The expected string
+// is "<integer>[,<integer>]".
+static bool parseMemoryOption(StringRef arg, uint64_t &reserve,
+ uint64_t &commit) {
+ StringRef reserveStr, commitStr;
+ std::tie(reserveStr, commitStr) = arg.split(',');
+ if (reserveStr.getAsInteger(0, reserve))
+ return false;
+ if (!commitStr.empty() && commitStr.getAsInteger(0, commit))
+ return false;
+ return true;
+}
+
+// Parse an argument for /version or /subsystem. The expected string is
+// "<integer>[.<integer>]".
+static bool parseVersion(StringRef arg, uint32_t &major, uint32_t &minor) {
+ StringRef majorVersion, minorVersion;
+ std::tie(majorVersion, minorVersion) = arg.split('.');
+ if (minorVersion.empty())
+ minorVersion = "0";
+ if (majorVersion.getAsInteger(0, major))
+ return false;
+ if (minorVersion.getAsInteger(0, minor))
+ return false;
+ return true;
+}
+
+// Returns subsystem type for the given string.
+static llvm::COFF::WindowsSubsystem stringToWinSubsystem(StringRef str) {
+ return llvm::StringSwitch<llvm::COFF::WindowsSubsystem>(str.lower())
+ .Case("windows", llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_GUI)
+ .Case("console", llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_CUI)
+ .Case("boot_application",
+ llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION)
+ .Case("efi_application", llvm::COFF::IMAGE_SUBSYSTEM_EFI_APPLICATION)
+ .Case("efi_boot_service_driver",
+ llvm::COFF::IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER)
+ .Case("efi_rom", llvm::COFF::IMAGE_SUBSYSTEM_EFI_ROM)
+ .Case("efi_runtime_driver",
+ llvm::COFF::IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER)
+ .Case("native", llvm::COFF::IMAGE_SUBSYSTEM_NATIVE)
+ .Case("posix", llvm::COFF::IMAGE_SUBSYSTEM_POSIX_CUI)
+ .Default(llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN);
+}
+
+// Parse /subsystem command line option. The form of /subsystem is
+// "subsystem_name[,majorOSVersion[.minorOSVersion]]".
+static bool parseSubsystem(StringRef arg,
+ llvm::COFF::WindowsSubsystem &subsystem,
+ llvm::Optional<uint32_t> &major,
+ llvm::Optional<uint32_t> &minor, raw_ostream &diag) {
+ StringRef subsystemStr, osVersion;
+ std::tie(subsystemStr, osVersion) = arg.split(',');
+ if (!osVersion.empty()) {
+ uint32_t v1, v2;
+ if (!parseVersion(osVersion, v1, v2))
+ return false;
+ major = v1;
+ minor = v2;
+ }
+ subsystem = stringToWinSubsystem(subsystemStr);
+ if (subsystem == llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN) {
+ diag << "error: unknown subsystem name: " << subsystemStr << "\n";
+ return false;
+ }
+ return true;
+}
+
+static llvm::COFF::MachineTypes stringToMachineType(StringRef str) {
+ // FIXME: we have no way to differentiate between ARM and ARMNT currently.
+ // However, given that LLVM only supports ARM NT, default to that for now.
+ return llvm::StringSwitch<llvm::COFF::MachineTypes>(str.lower())
+ .Case("arm", llvm::COFF::IMAGE_FILE_MACHINE_ARMNT)
+ .Case("x64", llvm::COFF::IMAGE_FILE_MACHINE_AMD64)
+ .Case("x86", llvm::COFF::IMAGE_FILE_MACHINE_I386)
+ .Default(llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN);
+}
+
+// Parse /section:name,[[!]{DEKPRSW}]
+//
+// /section option is to set non-default bits in the Characteristics fields of
+// the section header. D, E, K, P, R, S, and W represent discardable,
+// execute, not_cachable, not_pageable, read, shared, and write bits,
+// respectively. You can specify multiple flags in one /section option.
+//
+// If the flag starts with "!", the flags represent a mask that should be turned
+// off regardless of the default value. You can even create a section which is
+// not readable, writable nor executable with this -- although it's probably
+// useless.
+static bool parseSection(StringRef option, std::string &section,
+ llvm::Optional<uint32_t> &flags,
+ llvm::Optional<uint32_t> &mask) {
+ StringRef flagString;
+ std::tie(section, flagString) = option.split(",");
+
+ bool negative = false;
+ if (flagString.startswith("!")) {
+ negative = true;
+ flagString = flagString.substr(1);
+ }
+ if (flagString.empty())
+ return false;
+
+ uint32_t attribs = 0;
+ for (size_t i = 0, e = flagString.size(); i < e; ++i) {
+ switch (tolower(flagString[i])) {
+#define CASE(c, flag) \
+ case c: \
+ attribs |= flag; \
+ break
+ CASE('d', llvm::COFF::IMAGE_SCN_MEM_DISCARDABLE);
+ CASE('e', llvm::COFF::IMAGE_SCN_MEM_EXECUTE);
+ CASE('k', llvm::COFF::IMAGE_SCN_MEM_NOT_CACHED);
+ CASE('p', llvm::COFF::IMAGE_SCN_MEM_NOT_PAGED);
+ CASE('r', llvm::COFF::IMAGE_SCN_MEM_READ);
+ CASE('s', llvm::COFF::IMAGE_SCN_MEM_SHARED);
+ CASE('w', llvm::COFF::IMAGE_SCN_MEM_WRITE);
+#undef CASE
+ default:
+ return false;
+ }
+ }
+
+ if (negative) {
+ mask = attribs;
+ } else {
+ flags = attribs;
+ }
+ return true;
+}
+
+static bool readFile(PECOFFLinkingContext &ctx, StringRef path,
+ ArrayRef<uint8_t> &result) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> buf = MemoryBuffer::getFile(path);
+ if (!buf)
+ return false;
+ StringRef Data = buf.get()->getBuffer();
+ result = ctx.allocate(ArrayRef<uint8_t>(
+ reinterpret_cast<const uint8_t *>(Data.begin()), Data.size()));
+ return true;
+}
+
+// Parse /manifest:EMBED[,ID=#]|NO.
+static bool parseManifest(StringRef option, bool &enable, bool &embed,
+ int &id) {
+ if (option.equals_lower("no")) {
+ enable = false;
+ return true;
+ }
+ if (!option.startswith_lower("embed"))
+ return false;
+
+ embed = true;
+ option = option.substr(strlen("embed"));
+ if (option.empty())
+ return true;
+ if (!option.startswith_lower(",id="))
+ return false;
+ option = option.substr(strlen(",id="));
+ if (option.getAsInteger(0, id))
+ return false;
+ return true;
+}
+
+static bool isLibraryFile(StringRef path) {
+ return path.endswith_lower(".lib") || path.endswith_lower(".imp");
+}
+
+static StringRef getObjectPath(PECOFFLinkingContext &ctx, StringRef path) {
+ std::string result;
+ if (isLibraryFile(path)) {
+ result = ctx.searchLibraryFile(path);
+ } else if (llvm::sys::path::extension(path).empty()) {
+ result = path.str() + ".obj";
+ } else {
+ result = path;
+ }
+ return ctx.allocate(result);
+}
+
+static StringRef getLibraryPath(PECOFFLinkingContext &ctx, StringRef path) {
+ std::string result = isLibraryFile(path)
+ ? ctx.searchLibraryFile(path)
+ : ctx.searchLibraryFile(path.str() + ".lib");
+ return ctx.allocate(result);
+}
+
+// Returns true if the given file is a Windows resource file.
+static bool isResoruceFile(StringRef path) {
+ llvm::sys::fs::file_magic fileType;
+ if (llvm::sys::fs::identify_magic(path, fileType)) {
+ // If we cannot read the file, assume it's not a resource file.
+ // The further stage will raise an error on this unreadable file.
+ return false;
+ }
+ return fileType == llvm::sys::fs::file_magic::windows_resource;
+}
+
+// Merge Windows resource files and convert them to a single COFF file.
+// The temporary file path is set to result.
+static bool convertResourceFiles(PECOFFLinkingContext &ctx,
+ std::vector<std::string> inFiles,
+ std::string &result) {
+ // Create an output file path.
+ SmallString<128> outFile;
+ if (llvm::sys::fs::createTemporaryFile("resource", "obj", outFile))
+ return false;
+ std::string outFileArg = ("/out:" + outFile).str();
+
+ // Construct CVTRES.EXE command line and execute it.
+ std::string program = "cvtres.exe";
+ ErrorOr<std::string> programPathOrErr = llvm::sys::findProgramByName(program);
+ if (!programPathOrErr) {
+ llvm::errs() << "Unable to find " << program << " in PATH\n";
+ return false;
+ }
+ const std::string &programPath = *programPathOrErr;
+
+ std::vector<const char *> args;
+ args.push_back(programPath.c_str());
+ args.push_back(ctx.is64Bit() ? "/machine:x64" : "/machine:x86");
+ args.push_back("/readonly");
+ args.push_back("/nologo");
+ args.push_back(outFileArg.c_str());
+ for (const std::string &path : inFiles)
+ args.push_back(path.c_str());
+ args.push_back(nullptr);
+
+ if (llvm::sys::ExecuteAndWait(programPath.c_str(), &args[0]) != 0) {
+ llvm::errs() << program << " failed\n";
+ return false;
+ }
+ result = outFile.str();
+ return true;
+}
+
+// Parse /manifestuac:(level=<string>|uiAccess=<string>).
+//
+// The arguments will be embedded to the manifest XML file with no error check,
+// so the values given via the command line must be valid as XML attributes.
+// This may sound a bit odd, but that's how link.exe works, so we will follow.
+static bool parseManifestUAC(StringRef option,
+ llvm::Optional<std::string> &level,
+ llvm::Optional<std::string> &uiAccess) {
+ for (;;) {
+ option = option.ltrim();
+ if (option.empty())
+ return true;
+ if (option.startswith_lower("level=")) {
+ option = option.substr(strlen("level="));
+ StringRef value;
+ std::tie(value, option) = option.split(" ");
+ level = value.str();
+ continue;
+ }
+ if (option.startswith_lower("uiaccess=")) {
+ option = option.substr(strlen("uiaccess="));
+ StringRef value;
+ std::tie(value, option) = option.split(" ");
+ uiAccess = value.str();
+ continue;
+ }
+ return false;
+ }
+}
+
+// Returns the machine type (e.g. x86) of the given input file.
+// If the file is not COFF, returns false.
+static bool getMachineType(StringRef path, llvm::COFF::MachineTypes &result) {
+ llvm::sys::fs::file_magic fileType;
+ if (llvm::sys::fs::identify_magic(path, fileType))
+ return false;
+ if (fileType != llvm::sys::fs::file_magic::coff_object)
+ return false;
+ ErrorOr<std::unique_ptr<MemoryBuffer>> buf = MemoryBuffer::getFile(path);
+ if (!buf)
+ return false;
+ std::error_code ec;
+ llvm::object::COFFObjectFile obj(buf.get()->getMemBufferRef(), ec);
+ if (ec)
+ return false;
+ result = static_cast<llvm::COFF::MachineTypes>(obj.getMachine());
+ return true;
+}
+
+// Parse /export:entryname[=internalname][,@ordinal[,NONAME]][,DATA][,PRIVATE].
+//
+// MSDN doesn't say anything about /export:foo=bar style option or PRIVATE
+// attribtute, but link.exe actually accepts them.
+static bool parseExport(StringRef option,
+ PECOFFLinkingContext::ExportDesc &ret) {
+ StringRef name;
+ StringRef rest;
+ std::tie(name, rest) = option.split(",");
+ if (name.empty())
+ return false;
+ if (name.find('=') == StringRef::npos) {
+ ret.name = name;
+ } else {
+ std::tie(ret.externalName, ret.name) = name.split("=");
+ if (ret.name.empty())
+ return false;
+ }
+
+ for (;;) {
+ if (rest.empty())
+ return true;
+ StringRef arg;
+ std::tie(arg, rest) = rest.split(",");
+ if (arg.equals_lower("noname")) {
+ if (ret.ordinal < 0)
+ return false;
+ ret.noname = true;
+ continue;
+ }
+ if (arg.equals_lower("data")) {
+ ret.isData = true;
+ continue;
+ }
+ if (arg.equals_lower("private")) {
+ ret.isPrivate = true;
+ continue;
+ }
+ if (arg.startswith("@")) {
+ int ordinal;
+ if (arg.substr(1).getAsInteger(0, ordinal))
+ return false;
+ if (ordinal <= 0 || 65535 < ordinal)
+ return false;
+ ret.ordinal = ordinal;
+ continue;
+ }
+ return false;
+ }
+}
+
+// Read module-definition file.
+static bool parseDef(StringRef option, llvm::BumpPtrAllocator &alloc,
+ std::vector<moduledef::Directive *> &result) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> buf = MemoryBuffer::getFile(option);
+ if (!buf)
+ return false;
+ moduledef::Lexer lexer(std::move(buf.get()));
+ moduledef::Parser parser(lexer, alloc);
+ return parser.parse(result);
+}
+
+static StringRef replaceExtension(PECOFFLinkingContext &ctx, StringRef path,
+ StringRef extension) {
+ SmallString<128> val = path;
+ llvm::sys::path::replace_extension(val, extension);
+ return ctx.allocate(val.str());
+}
+
+// Create a manifest file contents.
+static std::string createManifestXml(PECOFFLinkingContext &ctx) {
+ std::string ret;
+ llvm::raw_string_ostream out(ret);
+ // Emit the XML. Note that we do *not* verify that the XML attributes are
+ // syntactically correct. This is intentional for link.exe compatibility.
+ out << "<?xml version=\"1.0\" standalone=\"yes\"?>\n"
+ "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\"\n"
+ " manifestVersion=\"1.0\">\n";
+ if (ctx.getManifestUAC()) {
+ out << " <trustInfo>\n"
+ " <security>\n"
+ " <requestedPrivileges>\n"
+ " <requestedExecutionLevel level=" << ctx.getManifestLevel()
+ << " uiAccess=" << ctx.getManifestUiAccess()
+ << "/>\n"
+ " </requestedPrivileges>\n"
+ " </security>\n"
+ " </trustInfo>\n";
+ const std::string &dependency = ctx.getManifestDependency();
+ if (!dependency.empty()) {
+ out << " <dependency>\n"
+ " <dependentAssembly>\n"
+ " <assemblyIdentity " << dependency
+ << " />\n"
+ " </dependentAssembly>\n"
+ " </dependency>\n";
+ }
+ }
+ out << "</assembly>\n";
+ out.flush();
+ return ret;
+}
+
+// Convert one doublequote to two doublequotes, so that we can embed the string
+// into a resource script file.
+static void quoteAndPrintXml(raw_ostream &out, StringRef str) {
+ for (;;) {
+ if (str.empty())
+ return;
+ StringRef line;
+ std::tie(line, str) = str.split("\n");
+ if (line.empty())
+ continue;
+ out << '\"';
+ const char *p = line.data();
+ for (int i = 0, size = line.size(); i < size; ++i) {
+ switch (p[i]) {
+ case '\"':
+ out << '\"';
+ // fallthrough
+ default:
+ out << p[i];
+ }
+ }
+ out << "\"\n";
+ }
+}
+
+// Create a resource file (.res file) containing the manifest XML. This is done
+// in two steps:
+//
+// 1. Create a resource script file containing the XML as a literal string.
+// 2. Run RC.EXE command to compile the script file to a resource file.
+//
+// The temporary file created in step 1 will be deleted on exit from this
+// function. The file created in step 2 will have the same lifetime as the
+// PECOFFLinkingContext.
+static bool createManifestResourceFile(PECOFFLinkingContext &ctx,
+ raw_ostream &diag,
+ std::string &resFile) {
+ // Create a temporary file for the resource script file.
+ SmallString<128> rcFileSmallString;
+ if (llvm::sys::fs::createTemporaryFile("tmp", "rc", rcFileSmallString)) {
+ diag << "Cannot create a temporary file\n";
+ return false;
+ }
+ StringRef rcFile(rcFileSmallString.str());
+ llvm::FileRemover rcFileRemover((Twine(rcFile)));
+
+ // Open the temporary file for writing.
+ std::error_code ec;
+ llvm::raw_fd_ostream out(rcFileSmallString, ec, llvm::sys::fs::F_Text);
+ if (ec) {
+ diag << "Failed to open " << ctx.getManifestOutputPath() << ": "
+ << ec.message() << "\n";
+ return false;
+ }
+
+ // Write resource script to the RC file.
+ out << "#define LANG_ENGLISH 9\n"
+ << "#define SUBLANG_DEFAULT 1\n"
+ << "#define APP_MANIFEST " << ctx.getManifestId() << "\n"
+ << "#define RT_MANIFEST 24\n"
+ << "LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT\n"
+ << "APP_MANIFEST RT_MANIFEST {\n";
+ quoteAndPrintXml(out, createManifestXml(ctx));
+ out << "}\n";
+ out.close();
+
+ // Create output resource file.
+ SmallString<128> resFileSmallString;
+ if (llvm::sys::fs::createTemporaryFile("tmp", "res", resFileSmallString)) {
+ diag << "Cannot create a temporary file";
+ return false;
+ }
+ resFile = resFileSmallString.str();
+
+ // Register the resource file path so that the file will be deleted when the
+ // context's destructor is called.
+ ctx.registerTemporaryFile(resFile);
+
+ // Run RC.EXE /fo tmp.res tmp.rc
+ std::string program = "rc.exe";
+ ErrorOr<std::string> programPathOrErr = llvm::sys::findProgramByName(program);
+ if (!programPathOrErr) {
+ diag << "Unable to find " << program << " in PATH\n";
+ return false;
+ }
+ const std::string &programPath = *programPathOrErr;
+ std::vector<const char *> args;
+ args.push_back(programPath.c_str());
+ args.push_back("/fo");
+ args.push_back(resFile.c_str());
+ args.push_back("/nologo");
+ args.push_back(rcFileSmallString.c_str());
+ args.push_back(nullptr);
+
+ if (llvm::sys::ExecuteAndWait(programPath.c_str(), &args[0]) != 0) {
+ diag << program << " failed\n";
+ return false;
+ }
+ return true;
+}
+
+
+// Create the a side-by-side manifest file.
+//
+// The manifest file will convey some information to the linker, such as whether
+// the binary needs to run as Administrator or not. Instead of being placed in
+// the PE/COFF header, it's in XML format for some reason -- I guess it's
+// probably because it's invented in the early dot-com era.
+//
+// The side-by-side manifest file is a separate XML file having ".manifest"
+// extension. It will be created in the same directory as the resulting
+// executable.
+static bool createSideBySideManifestFile(PECOFFLinkingContext &ctx,
+ raw_ostream &diag) {
+ std::string path = ctx.getManifestOutputPath();
+ if (path.empty()) {
+ // Default name of the manifest file is "foo.exe.manifest" where "foo.exe" is
+ // the output path.
+ path = ctx.outputPath();
+ path.append(".manifest");
+ }
+
+ std::error_code ec;
+ llvm::raw_fd_ostream out(path, ec, llvm::sys::fs::F_Text);
+ if (ec) {
+ diag << ec.message() << "\n";
+ return false;
+ }
+ out << createManifestXml(ctx);
+ return true;
+}
+
+// Handle /failifmismatch option.
+static bool
+handleFailIfMismatchOption(StringRef option,
+ std::map<StringRef, StringRef> &mustMatch,
+ raw_ostream &diag) {
+ StringRef key, value;
+ std::tie(key, value) = option.split('=');
+ if (key.empty() || value.empty()) {
+ diag << "error: malformed /failifmismatch option: " << option << "\n";
+ return true;
+ }
+ auto it = mustMatch.find(key);
+ if (it != mustMatch.end() && it->second != value) {
+ diag << "error: mismatch detected: '" << it->second << "' and '" << value
+ << "' for key '" << key << "'\n";
+ return true;
+ }
+ mustMatch[key] = value;
+ return false;
+}
+
+//
+// Environment variable
+//
+
+// Process "LINK" environment variable. If defined, the value of the variable
+// should be processed as command line arguments.
+static std::vector<const char *> processLinkEnv(PECOFFLinkingContext &ctx,
+ int argc, const char **argv) {
+ std::vector<const char *> ret;
+ // The first argument is the name of the command. This should stay at the head
+ // of the argument list.
+ assert(argc > 0);
+ ret.push_back(argv[0]);
+
+ // Add arguments specified by the LINK environment variable.
+ llvm::Optional<std::string> env = llvm::sys::Process::GetEnv("LINK");
+ if (env.hasValue())
+ for (std::string &arg : splitArgList(*env))
+ ret.push_back(ctx.allocate(arg).data());
+
+ // Add the rest of arguments passed via the command line.
+ for (int i = 1; i < argc; ++i)
+ ret.push_back(argv[i]);
+ ret.push_back(nullptr);
+ return ret;
+}
+
+// Process "LIB" environment variable. The variable contains a list of search
+// paths separated by semicolons.
+static void processLibEnv(PECOFFLinkingContext &ctx) {
+ llvm::Optional<std::string> env = llvm::sys::Process::GetEnv("LIB");
+ if (env.hasValue())
+ for (StringRef path : splitPathList(*env))
+ ctx.appendInputSearchPath(ctx.allocate(path));
+}
+
+namespace {
+class DriverStringSaver : public llvm::cl::StringSaver {
+public:
+ DriverStringSaver(PECOFFLinkingContext &ctx) : _ctx(ctx) {}
+
+ const char *SaveString(const char *s) override {
+ return _ctx.allocate(StringRef(s)).data();
+ }
+
+private:
+ PECOFFLinkingContext &_ctx;
+};
+}
+
+// Tokenize command line options in a given file and add them to result.
+static bool readResponseFile(StringRef path, PECOFFLinkingContext &ctx,
+ std::vector<const char *> &result) {
+ ArrayRef<uint8_t> contents;
+ if (!readFile(ctx, path, contents))
+ return false;
+ StringRef contentsStr(reinterpret_cast<const char *>(contents.data()),
+ contents.size());
+ DriverStringSaver saver(ctx);
+ SmallVector<const char *, 0> args;
+ llvm::cl::TokenizeWindowsCommandLine(contentsStr, saver, args);
+ for (const char *s : args)
+ result.push_back(s);
+ return true;
+}
+
+// Expand arguments starting with "@". It's an error if a specified file does
+// not exist. Returns true on success.
+static bool expandResponseFiles(int &argc, const char **&argv,
+ PECOFFLinkingContext &ctx, raw_ostream &diag,
+ bool &expanded) {
+ std::vector<const char *> newArgv;
+ for (int i = 0; i < argc; ++i) {
+ if (argv[i][0] != '@') {
+ newArgv.push_back(argv[i]);
+ continue;
+ }
+ StringRef filename = StringRef(argv[i] + 1);
+ if (!readResponseFile(filename, ctx, newArgv)) {
+ diag << "error: cannot read response file: " << filename << "\n";
+ return false;
+ }
+ expanded = true;
+ }
+ if (!expanded)
+ return true;
+ argc = newArgv.size();
+ newArgv.push_back(nullptr);
+ argv = &ctx.allocateCopy(newArgv)[0];
+ return true;
+}
+
+// Parses the given command line options and returns the result. Returns NULL if
+// there's an error in the options.
+static std::unique_ptr<llvm::opt::InputArgList>
+parseArgs(int argc, const char **argv, PECOFFLinkingContext &ctx,
+ raw_ostream &diag, bool isReadingDirectiveSection) {
+ // Expand arguments starting with "@".
+ bool expanded = false;
+ if (!expandResponseFiles(argc, argv, ctx, diag, expanded))
+ return nullptr;
+
+ // Parse command line options using WinLinkOptions.td
+ std::unique_ptr<llvm::opt::InputArgList> parsedArgs;
+ WinLinkOptTable table;
+ unsigned missingIndex;
+ unsigned missingCount;
+ parsedArgs.reset(table.ParseArgs(&argv[1], &argv[argc],
+ missingIndex, missingCount));
+ if (missingCount) {
+ diag << "error: missing arg value for '"
+ << parsedArgs->getArgString(missingIndex) << "' expected "
+ << missingCount << " argument(s).\n";
+ return nullptr;
+ }
+
+ // Show warning for unknown arguments. In .drectve section, unknown options
+ // starting with "-?" are silently ignored. This is a COFF's feature to embed a
+ // new linker option to an object file while keeping backward compatibility.
+ for (auto unknownArg : parsedArgs->filtered(OPT_UNKNOWN)) {
+ StringRef arg = unknownArg->getSpelling();
+ if (isReadingDirectiveSection && arg.startswith("-?"))
+ continue;
+ diag << "warning: ignoring unknown argument: " << arg << "\n";
+ }
+
+ // Copy mllvm
+ for (auto arg : parsedArgs->filtered(OPT_mllvm))
+ ctx.appendLLVMOption(arg->getValue());
+
+ // If we have expaneded response files and /verbose is given, print out the
+ // final command line.
+ if (!isReadingDirectiveSection && expanded &&
+ parsedArgs->getLastArg(OPT_verbose)) {
+ diag << "Command line:";
+ for (int i = 0; i < argc; ++i)
+ diag << " " << argv[i];
+ diag << "\n\n";
+ }
+
+ return parsedArgs;
+}
+
+// Returns true if the given file node has already been added to the input
+// graph.
+static bool hasLibrary(PECOFFLinkingContext &ctx, File *file) {
+ StringRef path = file->path();
+ for (std::unique_ptr<Node> &p : ctx.getNodes())
+ if (auto *f = dyn_cast<FileNode>(p.get()))
+ if (f->getFile()->path() == path)
+ return true;
+ return false;
+}
+
+// If the first command line argument is "/lib", link.exe acts as if it's
+// "lib.exe" command. This is for backward compatibility.
+// http://msdn.microsoft.com/en-us/library/h34w59b3.aspx
+static bool maybeRunLibCommand(int argc, const char **argv, raw_ostream &diag) {
+ if (argc <= 1)
+ return false;
+ if (!StringRef(argv[1]).equals_lower("/lib"))
+ return false;
+ ErrorOr<std::string> pathOrErr = llvm::sys::findProgramByName("lib.exe");
+ if (!pathOrErr) {
+ diag << "Unable to find lib.exe in PATH\n";
+ return true;
+ }
+ const std::string &path = *pathOrErr;
+
+ // Run lib.exe
+ std::vector<const char *> vec;
+ vec.push_back(path.c_str());
+ for (int i = 2; i < argc; ++i)
+ vec.push_back(argv[i]);
+ vec.push_back(nullptr);
+
+ if (llvm::sys::ExecuteAndWait(path.c_str(), &vec[0]) != 0)
+ diag << "lib.exe failed\n";
+ return true;
+}
+
+/// \brief Parse the input file to lld::File.
+void addFiles(PECOFFLinkingContext &ctx, StringRef path, raw_ostream &diag,
+ std::vector<std::unique_ptr<File>> &files) {
+ for (std::unique_ptr<File> &file : loadFile(ctx, path, false)) {
+ if (ctx.logInputFiles())
+ diag << file->path() << "\n";
+ files.push_back(std::move(file));
+ }
+}
+
+//
+// Main driver
+//
+
+bool WinLinkDriver::linkPECOFF(int argc, const char **argv, raw_ostream &diag) {
+ if (maybeRunLibCommand(argc, argv, diag))
+ return true;
+
+ PECOFFLinkingContext ctx;
+ ctx.setParseDirectives(parseDirectives);
+ ctx.registry().addSupportCOFFObjects(ctx);
+ ctx.registry().addSupportCOFFImportLibraries(ctx);
+ ctx.registry().addSupportArchives(ctx.logInputFiles());
+ ctx.registry().addSupportNativeObjects();
+ ctx.registry().addSupportYamlFiles();
+
+ std::vector<const char *> newargv = processLinkEnv(ctx, argc, argv);
+ processLibEnv(ctx);
+ if (!parse(newargv.size() - 1, &newargv[0], ctx, diag))
+ return false;
+
+ // Create the file if needed.
+ if (ctx.getCreateManifest() && !ctx.getEmbedManifest())
+ if (!createSideBySideManifestFile(ctx, diag))
+ return false;
+
+ return link(ctx, diag);
+}
+
+bool WinLinkDriver::parse(int argc, const char *argv[],
+ PECOFFLinkingContext &ctx, raw_ostream &diag,
+ bool isReadingDirectiveSection) {
+ // Parse may be called from multiple threads simultaneously to parse .drectve
+ // sections. This function is not thread-safe because it mutates the context
+ // object. So acquire the lock.
+ std::lock_guard<std::recursive_mutex> lock(ctx.getMutex());
+
+ std::map<StringRef, StringRef> failIfMismatchMap;
+ // Parse the options.
+ std::unique_ptr<llvm::opt::InputArgList> parsedArgs =
+ parseArgs(argc, argv, ctx, diag, isReadingDirectiveSection);
+ if (!parsedArgs)
+ return false;
+
+ // The list of input files.
+ std::vector<std::unique_ptr<File>> files;
+ std::vector<std::unique_ptr<File>> libraries;
+
+ // Handle /help
+ if (parsedArgs->hasArg(OPT_help)) {
+ WinLinkOptTable table;
+ table.PrintHelp(llvm::outs(), argv[0], "LLVM Linker", false);
+ return false;
+ }
+
+ // Handle /machine before parsing all the other options, as the target machine
+ // type affects how to handle other options. For example, x86 needs the
+ // leading underscore to mangle symbols, while x64 doesn't need it.
+ if (llvm::opt::Arg *inputArg = parsedArgs->getLastArg(OPT_machine)) {
+ StringRef arg = inputArg->getValue();
+ llvm::COFF::MachineTypes type = stringToMachineType(arg);
+ if (type == llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN) {
+ diag << "error: unknown machine type: " << arg << "\n";
+ return false;
+ }
+ ctx.setMachineType(type);
+ } else {
+ // If /machine option is missing, we need to take a look at
+ // the magic byte of the first object file to infer machine type.
+ std::vector<StringRef> filePaths;
+ for (auto arg : *parsedArgs)
+ if (arg->getOption().getID() == OPT_INPUT)
+ filePaths.push_back(arg->getValue());
+ if (llvm::opt::Arg *arg = parsedArgs->getLastArg(OPT_DASH_DASH))
+ filePaths.insert(filePaths.end(), arg->getValues().begin(),
+ arg->getValues().end());
+ for (StringRef path : filePaths) {
+ llvm::COFF::MachineTypes type;
+ if (!getMachineType(path, type))
+ continue;
+ if (type == llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN)
+ continue;
+ ctx.setMachineType(type);
+ break;
+ }
+ }
+
+ // Handle /nodefaultlib:<lib>. The same option without argument is handled in
+ // the following for loop.
+ for (auto *arg : parsedArgs->filtered(OPT_nodefaultlib))
+ ctx.addNoDefaultLib(arg->getValue());
+
+ // Handle /defaultlib. Argument of the option is added to the input file list
+ // unless it's blacklisted by /nodefaultlib.
+ std::vector<StringRef> defaultLibs;
+ for (auto *arg : parsedArgs->filtered(OPT_defaultlib))
+ defaultLibs.push_back(arg->getValue());
+
+ // -alternatename:<alias>=<symbol>
+ for (auto *arg : parsedArgs->filtered(OPT_alternatename)) {
+ StringRef weak, def;
+ if (!parseAlternateName(arg->getValue(), weak, def, diag))
+ return false;
+ ctx.addAlternateName(weak, def);
+ }
+
+ // Parse /base command line option. The argument for the parameter is in
+ // the form of "<address>[:<size>]".
+ if (auto *arg = parsedArgs->getLastArg(OPT_base)) {
+ uint64_t addr, size;
+ // Size should be set to SizeOfImage field in the COFF header, and if
+ // it's smaller than the actual size, the linker should warn about that.
+ // Currently we just ignore the value of size parameter.
+ if (!parseMemoryOption(arg->getValue(), addr, size))
+ return false;
+ ctx.setBaseAddress(addr);
+ }
+
+ // Parse /dll command line option
+ if (parsedArgs->hasArg(OPT_dll)) {
+ ctx.setIsDll(true);
+ // Default base address of a DLL is 0x10000000.
+ if (!parsedArgs->hasArg(OPT_base))
+ ctx.setBaseAddress(0x10000000);
+ }
+
+ // Parse /stack command line option
+ if (auto *arg = parsedArgs->getLastArg(OPT_stack)) {
+ uint64_t reserve;
+ uint64_t commit = ctx.getStackCommit();
+ if (!parseMemoryOption(arg->getValue(), reserve, commit))
+ return false;
+ ctx.setStackReserve(reserve);
+ ctx.setStackCommit(commit);
+ }
+
+ // Parse /heap command line option
+ if (auto *arg = parsedArgs->getLastArg(OPT_heap)) {
+ uint64_t reserve;
+ uint64_t commit = ctx.getHeapCommit();
+ if (!parseMemoryOption(arg->getValue(), reserve, commit))
+ return false;
+ ctx.setHeapReserve(reserve);
+ ctx.setHeapCommit(commit);
+ }
+
+ if (auto *arg = parsedArgs->getLastArg(OPT_align)) {
+ uint32_t align;
+ StringRef val = arg->getValue();
+ if (val.getAsInteger(10, align)) {
+ diag << "error: invalid value for /align: " << val << "\n";
+ return false;
+ }
+ ctx.setSectionDefaultAlignment(align);
+ }
+
+ if (auto *arg = parsedArgs->getLastArg(OPT_version)) {
+ uint32_t major, minor;
+ if (!parseVersion(arg->getValue(), major, minor))
+ return false;
+ ctx.setImageVersion(PECOFFLinkingContext::Version(major, minor));
+ }
+
+ // Parse /merge:<from>=<to>.
+ for (auto *arg : parsedArgs->filtered(OPT_merge)) {
+ StringRef from, to;
+ std::tie(from, to) = StringRef(arg->getValue()).split('=');
+ if (from.empty() || to.empty()) {
+ diag << "error: malformed /merge option: " << arg->getValue() << "\n";
+ return false;
+ }
+ if (!ctx.addSectionRenaming(diag, from, to))
+ return false;
+ }
+
+ // Parse /subsystem:<subsystem>[,<majorOSVersion>[.<minorOSVersion>]].
+ if (auto *arg = parsedArgs->getLastArg(OPT_subsystem)) {
+ llvm::COFF::WindowsSubsystem subsystem;
+ llvm::Optional<uint32_t> major, minor;
+ if (!parseSubsystem(arg->getValue(), subsystem, major, minor, diag))
+ return false;
+ ctx.setSubsystem(subsystem);
+ if (major.hasValue())
+ ctx.setMinOSVersion(PECOFFLinkingContext::Version(*major, *minor));
+ }
+
+ // Parse /section:name,[[!]{DEKPRSW}]
+ for (auto *arg : parsedArgs->filtered(OPT_section)) {
+ std::string section;
+ llvm::Optional<uint32_t> flags, mask;
+ if (!parseSection(arg->getValue(), section, flags, mask)) {
+ diag << "Unknown argument for /section: " << arg->getValue() << "\n";
+ return false;
+ }
+ if (flags.hasValue())
+ ctx.setSectionSetMask(section, *flags);
+ if (mask.hasValue())
+ ctx.setSectionClearMask(section, *mask);
+ }
+
+ // Parse /manifest:EMBED[,ID=#]|NO.
+ if (auto *arg = parsedArgs->getLastArg(OPT_manifest_colon)) {
+ bool enable = true;
+ bool embed = false;
+ int id = 1;
+ if (!parseManifest(arg->getValue(), enable, embed, id)) {
+ diag << "Unknown argument for /manifest: " << arg->getValue() << "\n";
+ return false;
+ }
+ ctx.setCreateManifest(enable);
+ ctx.setEmbedManifest(embed);
+ ctx.setManifestId(id);
+ }
+
+ // Parse /manifestuac.
+ if (auto *arg = parsedArgs->getLastArg(OPT_manifestuac)) {
+ if (StringRef(arg->getValue()).equals_lower("no")) {
+ ctx.setManifestUAC(false);
+ } else {
+ llvm::Optional<std::string> privilegeLevel;
+ llvm::Optional<std::string> uiAccess;
+ if (!parseManifestUAC(arg->getValue(), privilegeLevel, uiAccess)) {
+ diag << "Unknown argument for /manifestuac: " << arg->getValue()
+ << "\n";
+ return false;
+ }
+ if (privilegeLevel.hasValue())
+ ctx.setManifestLevel(privilegeLevel.getValue());
+ if (uiAccess.hasValue())
+ ctx.setManifestUiAccess(uiAccess.getValue());
+ }
+ }
+
+ if (auto *arg = parsedArgs->getLastArg(OPT_manifestfile))
+ ctx.setManifestOutputPath(ctx.allocate(arg->getValue()));
+
+ // /manifestdependency:<string> option. Note that the argument will be
+ // embedded to the manifest XML file with no error check, for link.exe
+ // compatibility. We do not gurantete that the resulting XML file is
+ // valid.
+ if (auto *arg = parsedArgs->getLastArg(OPT_manifestdependency))
+ ctx.setManifestDependency(ctx.allocate(arg->getValue()));
+
+ for (auto *arg : parsedArgs->filtered(OPT_failifmismatch))
+ if (handleFailIfMismatchOption(arg->getValue(), failIfMismatchMap, diag))
+ return false;
+
+ if (auto *arg = parsedArgs->getLastArg(OPT_entry))
+ ctx.setEntrySymbolName(ctx.allocate(arg->getValue()));
+
+ for (auto *arg : parsedArgs->filtered(OPT_export)) {
+ PECOFFLinkingContext::ExportDesc desc;
+ if (!parseExport(arg->getValue(), desc)) {
+ diag << "Error: malformed /export option: " << arg->getValue() << "\n";
+ return false;
+ }
+
+ // Mangle the symbol name only if it is reading user-supplied command line
+ // arguments. Because the symbol name in the .drectve section is already
+ // mangled by the compiler, we shouldn't add a leading underscore in that
+ // case. It's odd that the command line option has different semantics in
+ // the .drectve section, but this behavior is needed for compatibility
+ // with MSVC's link.exe.
+ if (!isReadingDirectiveSection)
+ desc.name = ctx.decorateSymbol(desc.name);
+ ctx.addDllExport(desc);
+ }
+
+ for (auto *arg : parsedArgs->filtered(OPT_deffile)) {
+ llvm::BumpPtrAllocator alloc;
+ std::vector<moduledef::Directive *> dirs;
+ if (!parseDef(arg->getValue(), alloc, dirs)) {
+ diag << "Error: invalid module-definition file\n";
+ return false;
+ }
+ for (moduledef::Directive *dir : dirs) {
+ if (auto *exp = dyn_cast<moduledef::Exports>(dir)) {
+ for (PECOFFLinkingContext::ExportDesc desc : exp->getExports()) {
+ desc.name = ctx.decorateSymbol(desc.name);
+ ctx.addDllExport(desc);
+ }
+ } else if (auto *hs = dyn_cast<moduledef::Heapsize>(dir)) {
+ ctx.setHeapReserve(hs->getReserve());
+ ctx.setHeapCommit(hs->getCommit());
+ } else if (auto *lib = dyn_cast<moduledef::Library>(dir)) {
+ ctx.setIsDll(true);
+ ctx.setOutputPath(ctx.allocate(lib->getName()));
+ if (lib->getBaseAddress() && !ctx.getBaseAddress())
+ ctx.setBaseAddress(lib->getBaseAddress());
+ } else if (auto *name = dyn_cast<moduledef::Name>(dir)) {
+ if (!name->getOutputPath().empty() && ctx.outputPath().empty())
+ ctx.setOutputPath(ctx.allocate(name->getOutputPath()));
+ if (name->getBaseAddress() && ctx.getBaseAddress())
+ ctx.setBaseAddress(name->getBaseAddress());
+ } else if (auto *ver = dyn_cast<moduledef::Version>(dir)) {
+ ctx.setImageVersion(PECOFFLinkingContext::Version(
+ ver->getMajorVersion(), ver->getMinorVersion()));
+ } else {
+ llvm::dbgs() << static_cast<int>(dir->getKind()) << "\n";
+ llvm_unreachable("Unknown module-definition directive.\n");
+ }
+ }
+ }
+
+ for (auto *arg : parsedArgs->filtered(OPT_libpath))
+ ctx.appendInputSearchPath(ctx.allocate(arg->getValue()));
+
+ for (auto *arg : parsedArgs->filtered(OPT_opt)) {
+ std::string val = StringRef(arg->getValue()).lower();
+ if (val == "noref") {
+ ctx.setDeadStripping(false);
+ } else if (val != "ref" && val != "icf" && val != "noicf" &&
+ val != "lbr" && val != "nolbr" &&
+ !StringRef(val).startswith("icf=")) {
+ diag << "unknown option for /opt: " << val << "\n";
+ return false;
+ }
+ }
+
+ // LLD is not yet capable of creating a PDB file, so /debug does not have
+ // any effect.
+ // TODO: This should disable dead stripping. Currently we can't do that
+ // because removal of associative sections depends on dead stripping.
+ if (parsedArgs->hasArg(OPT_debug))
+ ctx.setDebug(true);
+
+ if (parsedArgs->hasArg(OPT_verbose))
+ ctx.setLogInputFiles(true);
+
+ // /force and /force:unresolved mean the same thing. We do not currently
+ // support /force:multiple.
+ if (parsedArgs->hasArg(OPT_force) ||
+ parsedArgs->hasArg(OPT_force_unresolved)) {
+ ctx.setAllowRemainingUndefines(true);
+ }
+
+ if (parsedArgs->hasArg(OPT_fixed)) {
+ // /fixed is not compatible with /dynamicbase. Check for it.
+ if (parsedArgs->hasArg(OPT_dynamicbase)) {
+ diag << "/dynamicbase must not be specified with /fixed\n";
+ return false;
+ }
+ ctx.setBaseRelocationEnabled(false);
+ ctx.setDynamicBaseEnabled(false);
+ }
+
+ // /swaprun:{cd,net} options set IMAGE_FILE_{REMOVABLE,NET}_RUN_FROM_SWAP
+ // bits in the COFF header, respectively. If one of the bits is on, the
+ // Windows loader will copy the entire file to swap area then execute it,
+ // so that the user can eject a CD or disconnect from the network.
+ if (parsedArgs->hasArg(OPT_swaprun_cd))
+ ctx.setSwapRunFromCD(true);
+
+ if (parsedArgs->hasArg(OPT_swaprun_net))
+ ctx.setSwapRunFromNet(true);
+
+ if (parsedArgs->hasArg(OPT_profile)) {
+ // /profile implies /opt:ref, /opt:noicf, /incremental:no and /fixed:no.
+ ctx.setDeadStripping(true);
+ ctx.setBaseRelocationEnabled(true);
+ ctx.setDynamicBaseEnabled(true);
+ }
+
+ for (auto *arg : parsedArgs->filtered(OPT_implib))
+ ctx.setOutputImportLibraryPath(arg->getValue());
+
+ for (auto *arg : parsedArgs->filtered(OPT_delayload)) {
+ ctx.addInitialUndefinedSymbol(ctx.getDelayLoadHelperName());
+ ctx.addDelayLoadDLL(arg->getValue());
+ }
+
+ if (auto *arg = parsedArgs->getLastArg(OPT_stub)) {
+ ArrayRef<uint8_t> contents;
+ if (!readFile(ctx, arg->getValue(), contents)) {
+ diag << "Failed to read DOS stub file " << arg->getValue() << "\n";
+ return false;
+ }
+ ctx.setDosStub(contents);
+ }
+
+ for (auto *arg : parsedArgs->filtered(OPT_incl))
+ ctx.addInitialUndefinedSymbol(ctx.allocate(arg->getValue()));
+
+ if (parsedArgs->hasArg(OPT_noentry))
+ ctx.setHasEntry(false);
+
+ if (parsedArgs->hasArg(OPT_nodefaultlib_all))
+ ctx.setNoDefaultLibAll(true);
+
+ if (auto *arg = parsedArgs->getLastArg(OPT_out))
+ ctx.setOutputPath(ctx.allocate(arg->getValue()));
+
+ if (auto *arg = parsedArgs->getLastArg(OPT_pdb))
+ ctx.setPDBFilePath(arg->getValue());
+
+ if (auto *arg = parsedArgs->getLastArg(OPT_lldmoduledeffile))
+ ctx.setModuleDefinitionFile(arg->getValue());
+
+ std::vector<StringRef> inputFiles;
+ for (auto *arg : parsedArgs->filtered(OPT_INPUT))
+ inputFiles.push_back(ctx.allocate(arg->getValue()));
+
+#define BOOLEAN_FLAG(name, setter) \
+ if (auto *arg = parsedArgs->getLastArg(OPT_##name, OPT_##name##_no)) \
+ ctx.setter(arg->getOption().matches(OPT_##name));
+
+ BOOLEAN_FLAG(nxcompat, setNxCompat);
+ BOOLEAN_FLAG(largeaddressaware, setLargeAddressAware);
+ BOOLEAN_FLAG(allowbind, setAllowBind);
+ BOOLEAN_FLAG(allowisolation, setAllowIsolation);
+ BOOLEAN_FLAG(dynamicbase, setDynamicBaseEnabled);
+ BOOLEAN_FLAG(tsaware, setTerminalServerAware);
+ BOOLEAN_FLAG(highentropyva, setHighEntropyVA);
+ BOOLEAN_FLAG(safeseh, setSafeSEH);
+#undef BOOLEAN_FLAG
+
+ // Arguments after "--" are interpreted as filenames even if they
+ // start with a hypen or a slash. This is not compatible with link.exe
+ // but useful for us to test lld on Unix.
+ if (llvm::opt::Arg *dashdash = parsedArgs->getLastArg(OPT_DASH_DASH))
+ for (const StringRef value : dashdash->getValues())
+ inputFiles.push_back(value);
+
+ // Compile Windows resource files to compiled resource file.
+ if (ctx.getCreateManifest() && ctx.getEmbedManifest() &&
+ !isReadingDirectiveSection) {
+ std::string resFile;
+ if (!createManifestResourceFile(ctx, diag, resFile))
+ return false;
+ inputFiles.push_back(ctx.allocate(resFile));
+ }
+
+ // A Windows Resource file is not an object file. It contains data,
+ // such as an icon image, and is not in COFF file format. If resource
+ // files are given, the linker merge them into one COFF file using
+ // CVTRES.EXE and then link the resulting file.
+ {
+ auto it = std::partition(inputFiles.begin(), inputFiles.end(),
+ isResoruceFile);
+ if (it != inputFiles.begin()) {
+ std::vector<std::string> resFiles(inputFiles.begin(), it);
+ std::string resObj;
+ if (!convertResourceFiles(ctx, resFiles, resObj)) {
+ diag << "Failed to convert resource files\n";
+ return false;
+ }
+ inputFiles = std::vector<StringRef>(it, inputFiles.end());
+ inputFiles.push_back(ctx.allocate(resObj));
+ ctx.registerTemporaryFile(resObj);
+ }
+ }
+
+ // Prepare objects to add them to the list of input files.
+ for (StringRef path : inputFiles) {
+ path = ctx.allocate(path);
+ if (isLibraryFile(path)) {
+ addFiles(ctx, getLibraryPath(ctx, path), diag, libraries);
+ } else {
+ addFiles(ctx, getObjectPath(ctx, path), diag, files);
+ }
+ }
+
+ // If dead-stripping is enabled, we need to add the entry symbol and
+ // symbols given by /include to the dead strip root set, so that it
+ // won't be removed from the output.
+ if (ctx.deadStrip())
+ for (const StringRef symbolName : ctx.initialUndefinedSymbols())
+ ctx.addDeadStripRoot(symbolName);
+
+ // Add the libraries specified by /defaultlib unless they are already added
+ // nor blacklisted by /nodefaultlib.
+ if (!ctx.getNoDefaultLibAll())
+ for (const StringRef path : defaultLibs)
+ if (!ctx.hasNoDefaultLib(path))
+ addFiles(ctx, getLibraryPath(ctx, path.lower()), diag, libraries);
+
+ if (files.empty() && !isReadingDirectiveSection) {
+ diag << "No input files\n";
+ return false;
+ }
+
+ // If /out option was not specified, the default output file name is
+ // constructed by replacing an extension of the first input file
+ // with ".exe".
+ if (ctx.outputPath().empty()) {
+ StringRef path = files[0]->path();
+ ctx.setOutputPath(replaceExtension(ctx, path, ".exe"));
+ }
+
+ // Add the input files to the linking context.
+ for (std::unique_ptr<File> &file : files) {
+ if (isReadingDirectiveSection) {
+ File *f = file.get();
+ ctx.getTaskGroup().spawn([f] { f->parse(); });
+ }
+ ctx.getNodes().push_back(llvm::make_unique<FileNode>(std::move(file)));
+ }
+
+ // Add the library group to the linking context.
+ if (!isReadingDirectiveSection) {
+ // Add a group-end marker.
+ ctx.getNodes().push_back(llvm::make_unique<GroupEnd>(0));
+ }
+
+ // Add the library files to the library group.
+ for (std::unique_ptr<File> &file : libraries) {
+ if (!hasLibrary(ctx, file.get())) {
+ if (isReadingDirectiveSection) {
+ File *f = file.get();
+ ctx.getTaskGroup().spawn([f] { f->parse(); });
+ }
+ ctx.addLibraryFile(llvm::make_unique<FileNode>(std::move(file)));
+ }
+ }
+
+ // Validate the combination of options used.
+ return ctx.validate(diag);
+}
+
+} // namespace lld
diff --git a/lib/Driver/WinLinkModuleDef.cpp b/lib/Driver/WinLinkModuleDef.cpp
new file mode 100644
index 000000000000..e55a0bc5fe64
--- /dev/null
+++ b/lib/Driver/WinLinkModuleDef.cpp
@@ -0,0 +1,295 @@
+//===- lib/Driver/WinLinkModuleDef.cpp ------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Windows module definition file parser.
+///
+//===----------------------------------------------------------------------===//
+
+#include "lld/Driver/WinLinkModuleDef.h"
+#include "llvm/ADT/StringSwitch.h"
+
+namespace lld {
+namespace moduledef {
+
+Token Lexer::lex() {
+ for (;;) {
+ _buffer = _buffer.trim();
+ if (_buffer.empty() || _buffer[0] == '\0')
+ return Token(Kind::eof, _buffer);
+
+ switch (_buffer[0]) {
+ case ';': {
+ size_t end = _buffer.find('\n');
+ _buffer = (end == _buffer.npos) ? "" : _buffer.drop_front(end);
+ continue;
+ }
+ case '=':
+ _buffer = _buffer.drop_front();
+ return Token(Kind::equal, "=");
+ case ',':
+ _buffer = _buffer.drop_front();
+ return Token(Kind::comma, ",");
+ case '"': {
+ size_t end = _buffer.find('"', 1);
+ Token ret;
+ if (end == _buffer.npos) {
+ ret = Token(Kind::identifier, _buffer.substr(1, end));
+ _buffer = "";
+ } else {
+ ret = Token(Kind::identifier, _buffer.substr(1, end - 1));
+ _buffer = _buffer.drop_front(end + 1);
+ }
+ return ret;
+ }
+ default: {
+ size_t end = _buffer.find_first_not_of(
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "0123456789_.*~+!@#$%^&*()/");
+ StringRef word = _buffer.substr(0, end);
+ Kind kind = llvm::StringSwitch<Kind>(word)
+ .Case("BASE", Kind::kw_base)
+ .Case("DATA", Kind::kw_data)
+ .Case("EXPORTS", Kind::kw_exports)
+ .Case("HEAPSIZE", Kind::kw_heapsize)
+ .Case("LIBRARY", Kind::kw_library)
+ .Case("NAME", Kind::kw_name)
+ .Case("NONAME", Kind::kw_noname)
+ .Case("PRIVATE", Kind::kw_private)
+ .Case("STACKSIZE", Kind::kw_stacksize)
+ .Case("VERSION", Kind::kw_version)
+ .Default(Kind::identifier);
+ _buffer = (end == _buffer.npos) ? "" : _buffer.drop_front(end);
+ return Token(kind, word);
+ }
+ }
+ }
+}
+
+void Parser::consumeToken() {
+ if (_tokBuf.empty()) {
+ _tok = _lex.lex();
+ return;
+ }
+ _tok = _tokBuf.back();
+ _tokBuf.pop_back();
+}
+
+bool Parser::consumeTokenAsInt(uint64_t &result) {
+ consumeToken();
+ if (_tok._kind != Kind::identifier) {
+ ungetToken();
+ error(_tok, "Integer expected");
+ return false;
+ }
+ if (_tok._range.getAsInteger(10, result)) {
+ error(_tok, "Integer expected");
+ return false;
+ }
+ return true;
+}
+
+bool Parser::expectAndConsume(Kind kind, Twine msg) {
+ consumeToken();
+ if (_tok._kind != kind) {
+ error(_tok, msg);
+ return false;
+ }
+ return true;
+}
+
+void Parser::ungetToken() { _tokBuf.push_back(_tok); }
+
+void Parser::error(const Token &tok, Twine msg) {
+ _lex.getSourceMgr().PrintMessage(
+ llvm::SMLoc::getFromPointer(tok._range.data()), llvm::SourceMgr::DK_Error,
+ msg);
+}
+
+bool Parser::parse(std::vector<Directive *> &ret) {
+ for (;;) {
+ Directive *dir = nullptr;
+ if (!parseOne(dir))
+ return false;
+ if (!dir)
+ return true;
+ ret.push_back(dir);
+ }
+}
+
+bool Parser::parseOne(Directive *&ret) {
+ consumeToken();
+ switch (_tok._kind) {
+ case Kind::eof:
+ return true;
+ case Kind::kw_exports: {
+ // EXPORTS
+ std::vector<PECOFFLinkingContext::ExportDesc> exports;
+ for (;;) {
+ PECOFFLinkingContext::ExportDesc desc;
+ if (!parseExport(desc))
+ break;
+ exports.push_back(desc);
+ }
+ ret = new (_alloc) Exports(exports);
+ return true;
+ }
+ case Kind::kw_heapsize: {
+ // HEAPSIZE
+ uint64_t reserve, commit;
+ if (!parseMemorySize(reserve, commit))
+ return false;
+ ret = new (_alloc) Heapsize(reserve, commit);
+ return true;
+ }
+ case Kind::kw_library: {
+ // LIBRARY
+ std::string name;
+ uint64_t baseaddr;
+ if (!parseName(name, baseaddr))
+ return false;
+ if (!StringRef(name).endswith_lower(".dll"))
+ name.append(".dll");
+ ret = new (_alloc) Library(name, baseaddr);
+ return true;
+ }
+ case Kind::kw_stacksize: {
+ // STACKSIZE
+ uint64_t reserve, commit;
+ if (!parseMemorySize(reserve, commit))
+ return false;
+ ret = new (_alloc) Stacksize(reserve, commit);
+ return true;
+ }
+ case Kind::kw_name: {
+ // NAME
+ std::string outputPath;
+ uint64_t baseaddr;
+ if (!parseName(outputPath, baseaddr))
+ return false;
+ ret = new (_alloc) Name(outputPath, baseaddr);
+ return true;
+ }
+ case Kind::kw_version: {
+ // VERSION
+ int major, minor;
+ if (!parseVersion(major, minor))
+ return false;
+ ret = new (_alloc) Version(major, minor);
+ return true;
+ }
+ default:
+ error(_tok, Twine("Unknown directive: ") + _tok._range);
+ return false;
+ }
+}
+
+bool Parser::parseExport(PECOFFLinkingContext::ExportDesc &result) {
+ consumeToken();
+ if (_tok._kind != Kind::identifier) {
+ ungetToken();
+ return false;
+ }
+ result.name = _tok._range;
+
+ consumeToken();
+ if (_tok._kind == Kind::equal) {
+ consumeToken();
+ if (_tok._kind != Kind::identifier)
+ return false;
+ result.externalName = result.name;
+ result.name = _tok._range;
+ } else {
+ ungetToken();
+ }
+
+ for (;;) {
+ consumeToken();
+ if (_tok._kind == Kind::identifier && _tok._range[0] == '@') {
+ _tok._range.drop_front().getAsInteger(10, result.ordinal);
+ consumeToken();
+ if (_tok._kind == Kind::kw_noname) {
+ result.noname = true;
+ } else {
+ ungetToken();
+ }
+ continue;
+ }
+ if (_tok._kind == Kind::kw_data) {
+ result.isData = true;
+ continue;
+ }
+ if (_tok._kind == Kind::kw_private) {
+ result.isPrivate = true;
+ continue;
+ }
+ ungetToken();
+ return true;
+ }
+}
+
+// HEAPSIZE/STACKSIZE reserve[,commit]
+bool Parser::parseMemorySize(uint64_t &reserve, uint64_t &commit) {
+ if (!consumeTokenAsInt(reserve))
+ return false;
+
+ consumeToken();
+ if (_tok._kind != Kind::comma) {
+ ungetToken();
+ commit = 0;
+ return true;
+ }
+
+ if (!consumeTokenAsInt(commit))
+ return false;
+ return true;
+}
+
+// NAME [outputPath] [BASE=address]
+bool Parser::parseName(std::string &outputPath, uint64_t &baseaddr) {
+ consumeToken();
+ if (_tok._kind == Kind::identifier) {
+ outputPath = _tok._range;
+ } else {
+ outputPath = "";
+ ungetToken();
+ return true;
+ }
+ consumeToken();
+ if (_tok._kind == Kind::kw_base) {
+ if (!expectAndConsume(Kind::equal, "'=' expected"))
+ return false;
+ if (!consumeTokenAsInt(baseaddr))
+ return false;
+ } else {
+ ungetToken();
+ baseaddr = 0;
+ }
+ return true;
+}
+
+// VERSION major[.minor]
+bool Parser::parseVersion(int &major, int &minor) {
+ consumeToken();
+ if (_tok._kind != Kind::identifier)
+ return false;
+ StringRef v1, v2;
+ std::tie(v1, v2) = _tok._range.split('.');
+ if (v1.getAsInteger(10, major))
+ return false;
+ if (v2.empty()) {
+ minor = 0;
+ } else if (v2.getAsInteger(10, minor)) {
+ return false;
+ }
+ return true;
+}
+
+} // moddef
+} // namespace lld
diff --git a/lib/Driver/WinLinkOptions.td b/lib/Driver/WinLinkOptions.td
new file mode 100644
index 000000000000..a545639b5bb2
--- /dev/null
+++ b/lib/Driver/WinLinkOptions.td
@@ -0,0 +1,120 @@
+include "llvm/Option/OptParser.td"
+
+// link.exe accepts options starting with either a dash or a slash.
+
+// Flag that takes no arguments.
+class F<string name> : Flag<["/", "-", "-?"], name>;
+
+// Flag that takes one argument after ":".
+class P<string name, string help> :
+ Joined<["/", "-", "-?"], name#":">, HelpText<help>;
+
+// Boolean flag suffixed by ":no".
+multiclass B<string name, string help> {
+ def "" : F<name>;
+ def _no : F<name#":no">, HelpText<help>;
+}
+
+def alternatename : P<"alternatename", "Define weak alias">;
+def base : P<"base", "Base address of the program">;
+def defaultlib : P<"defaultlib", "Add the library to the list of input files">;
+def nodefaultlib : P<"nodefaultlib", "Remove a default library">;
+def disallowlib : Joined<["/", "-", "-?"], "disallowlib:">, Alias<nodefaultlib>;
+def entry : P<"entry", "Name of entry point symbol">;
+// No help text because /failifmismatch is not intended to be used by the user.
+def export : P<"export", "Export a function">;
+def failifmismatch : P<"failifmismatch", "">;
+def heap : P<"heap", "Size of the heap">;
+def align : P<"align", "Section alignment">;
+def libpath : P<"libpath", "Additional library search path">;
+def mllvm : P<"mllvm", "Options to pass to LLVM">;
+def out : P<"out", "Path to file to write output">;
+def stack : P<"stack", "Size of the stack">;
+def machine : P<"machine", "Specify target platform">;
+def version : P<"version", "Specify a version number in the PE header">;
+def merge : P<"merge", "Combine sections">;
+def section : P<"section", "Specify section attributes">;
+def subsystem : P<"subsystem", "Specify subsystem">;
+def stub : P<"stub", "Specify DOS stub file">;
+def opt : P<"opt", "Control optimizations">;
+def implib : P<"implib", "Import library name">;
+def delayload : P<"delayload", "Delay loaded DLL name">;
+def pdb : P<"pdb", "PDB file path">;
+
+def manifest : F<"manifest">;
+def manifest_colon : P<"manifest", "Create manifest file">;
+def manifestuac : P<"manifestuac", "User access control">;
+def manifestfile : P<"manifestfile", "Manifest file path">;
+def manifestdependency : P<"manifestdependency",
+ "Attributes for <dependency> in manifest file">;
+
+// We cannot use multiclass P because class name "incl" is different
+// from its command line option name. We do this because "include" is
+// a reserved keyword in tablegen.
+def incl : Joined<["/", "-"], "include:">,
+ HelpText<"Force symbol to be added to symbol table as undefined one">;
+
+// "def" is also a keyword.
+def deffile : Joined<["/", "-"], "def:">,
+ HelpText<"Use module-definition file">;
+
+def nodefaultlib_all : F<"nodefaultlib">;
+def noentry : F<"noentry">;
+def dll : F<"dll">;
+def verbose : F<"verbose">;
+def debug : F<"debug">;
+def swaprun_cd : F<"swaprun:cd">;
+def swaprun_net : F<"swaprun:net">;
+def profile : F<"profile">;
+
+def force : F<"force">,
+ HelpText<"Allow undefined symbols when creating executables">;
+def force_unresolved : F<"force:unresolved">;
+
+defm nxcompat : B<"nxcompat", "Disable data execution provention">;
+defm largeaddressaware : B<"largeaddressaware", "Disable large addresses">;
+defm allowbind: B<"allowbind", "Disable DLL binding">;
+defm fixed : B<"fixed", "Enable base relocations">;
+defm tsaware : B<"tsaware", "Create non-Terminal Server aware executable">;
+defm allowisolation : B<"allowisolation", "Set NO_ISOLATION bit">;
+defm dynamicbase : B<"dynamicbase",
+ "Disable address space layout randomization">;
+defm safeseh : B<"safeseh", "Produce an image with Safe Exception Handler">;
+defm highentropyva : B<"highentropyva", "Set HIGH_ENTROPY_VA bit">;
+
+def help : F<"help">;
+def help_q : Flag<["/?", "-?"], "">, Alias<help>;
+
+def DASH_DASH : Option<["--"], "", KIND_REMAINING_ARGS>;
+
+// Flag for debug
+def lldmoduledeffile : Joined<["/", "-"], "lldmoduledeffile:">;
+
+//==============================================================================
+// The flags below do nothing. They are defined only for link.exe compatibility.
+//==============================================================================
+
+class QF<string name> : Joined<["/", "-", "-?"], name#":">;
+
+multiclass QB<string name> {
+ def "" : F<name>;
+ def _no : F<name#":no">;
+}
+
+def functionpadmin : F<"functionpadmin">;
+def ignoreidl : F<"ignoreidl">;
+def incremental : F<"incremental">;
+def no_incremental : F<"incremental:no">;
+def nologo : F<"nologo">;
+
+def delay : QF<"delay">;
+def errorreport : QF<"errorreport">;
+def idlout : QF<"idlout">;
+def ignore : QF<"ignore">;
+def maxilksize : QF<"maxilksize">;
+def pdbaltpath : QF<"pdbaltpath">;
+def tlbid : QF<"tlbid">;
+def tlbout : QF<"tlbout">;
+def verbose_all : QF<"verbose">;
+
+defm wx : QB<"wx">;
diff --git a/lib/Makefile b/lib/Makefile
new file mode 100644
index 000000000000..83112eaf972a
--- /dev/null
+++ b/lib/Makefile
@@ -0,0 +1,16 @@
+##===- lib/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 := ..
+
+# ARCMigrate and Rewrite are always needed because of libclang.
+PARALLEL_DIRS = Config Core Driver ReaderWriter
+
+include $(LLD_LEVEL)/../../Makefile.config
+
+include $(LLD_LEVEL)/Makefile
diff --git a/lib/ReaderWriter/CMakeLists.txt b/lib/ReaderWriter/CMakeLists.txt
new file mode 100644
index 000000000000..1fd19eb73a75
--- /dev/null
+++ b/lib/ReaderWriter/CMakeLists.txt
@@ -0,0 +1,20 @@
+add_subdirectory(ELF)
+add_subdirectory(MachO)
+add_subdirectory(Native)
+add_subdirectory(PECOFF)
+add_subdirectory(YAML)
+
+if (MSVC)
+ add_definitions(-wd4062) # Suppress 'warning C4062: Enumerator has no associated handler in a switch statement.'
+endif()
+
+add_llvm_library(lldReaderWriter
+ CoreLinkingContext.cpp
+ FileArchive.cpp
+ LinkerScript.cpp
+ LINK_LIBS
+ lldCore
+ lldYAML
+ LLVMObject
+ LLVMSupport
+ )
diff --git a/lib/ReaderWriter/CoreLinkingContext.cpp b/lib/ReaderWriter/CoreLinkingContext.cpp
new file mode 100644
index 000000000000..86fad4f6e77d
--- /dev/null
+++ b/lib/ReaderWriter/CoreLinkingContext.cpp
@@ -0,0 +1,171 @@
+//===- lib/ReaderWriter/CoreLinkingContext.cpp ----------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Pass.h"
+#include "lld/Core/PassManager.h"
+#include "lld/Core/Simple.h"
+#include "lld/ReaderWriter/CoreLinkingContext.h"
+#include "llvm/ADT/ArrayRef.h"
+
+using namespace lld;
+
+namespace {
+
+/// \brief Simple atom created by the stubs pass.
+class TestingStubAtom : public DefinedAtom {
+public:
+ TestingStubAtom(const File &F, const Atom &) : _file(F) {
+ static uint32_t lastOrdinal = 0;
+ _ordinal = lastOrdinal++;
+ }
+
+ const File &file() const override { return _file; }
+
+ StringRef name() const override { return StringRef(); }
+
+ uint64_t ordinal() const override { return _ordinal; }
+
+ uint64_t size() const override { return 0; }
+
+ Scope scope() const override { return DefinedAtom::scopeLinkageUnit; }
+
+ Interposable interposable() const override { return DefinedAtom::interposeNo; }
+
+ Merge merge() const override { return DefinedAtom::mergeNo; }
+
+ ContentType contentType() const override { return DefinedAtom::typeStub; }
+
+ Alignment alignment() const override { return Alignment(0, 0); }
+
+ SectionChoice sectionChoice() const override {
+ return DefinedAtom::sectionBasedOnContent;
+ }
+
+ StringRef customSectionName() const override { return StringRef(); }
+
+ DeadStripKind deadStrip() const override {
+ return DefinedAtom::deadStripNormal;
+ }
+
+ ContentPermissions permissions() const override {
+ return DefinedAtom::permR_X;
+ }
+
+ ArrayRef<uint8_t> rawContent() const override { return ArrayRef<uint8_t>(); }
+
+ reference_iterator begin() const override {
+ return reference_iterator(*this, nullptr);
+ }
+
+ reference_iterator end() const override {
+ return reference_iterator(*this, nullptr);
+ }
+
+ const Reference *derefIterator(const void *iter) const override {
+ return nullptr;
+ }
+
+ void incrementIterator(const void *&iter) const override {}
+
+private:
+ const File &_file;
+ uint32_t _ordinal;
+};
+
+/// \brief Simple atom created by the GOT pass.
+class TestingGOTAtom : public DefinedAtom {
+public:
+ TestingGOTAtom(const File &F, const Atom &) : _file(F) {
+ static uint32_t lastOrdinal = 0;
+ _ordinal = lastOrdinal++;
+ }
+
+ const File &file() const override { return _file; }
+
+ StringRef name() const override { return StringRef(); }
+
+ uint64_t ordinal() const override { return _ordinal; }
+
+ uint64_t size() const override { return 0; }
+
+ Scope scope() const override { return DefinedAtom::scopeLinkageUnit; }
+
+ Interposable interposable() const override { return DefinedAtom::interposeNo; }
+
+ Merge merge() const override { return DefinedAtom::mergeNo; }
+
+ ContentType contentType() const override { return DefinedAtom::typeGOT; }
+
+ Alignment alignment() const override { return Alignment(3, 0); }
+
+ SectionChoice sectionChoice() const override {
+ return DefinedAtom::sectionBasedOnContent;
+ }
+
+ StringRef customSectionName() const override { return StringRef(); }
+
+ DeadStripKind deadStrip() const override {
+ return DefinedAtom::deadStripNormal;
+ }
+
+ ContentPermissions permissions() const override {
+ return DefinedAtom::permRW_;
+ }
+
+ ArrayRef<uint8_t> rawContent() const override { return ArrayRef<uint8_t>(); }
+
+ reference_iterator begin() const override {
+ return reference_iterator(*this, nullptr);
+ }
+
+ reference_iterator end() const override {
+ return reference_iterator(*this, nullptr);
+ }
+
+ const Reference *derefIterator(const void *iter) const override {
+ return nullptr;
+ }
+
+ void incrementIterator(const void *&iter) const override {}
+
+private:
+ const File &_file;
+ uint32_t _ordinal;
+};
+
+class OrderPass : public Pass {
+public:
+ /// Sorts atoms by position
+ void perform(std::unique_ptr<MutableFile> &file) override {
+ MutableFile::DefinedAtomRange defined = file->definedAtoms();
+ std::sort(defined.begin(), defined.end(), DefinedAtom::compareByPosition);
+ }
+};
+
+} // anonymous namespace
+
+CoreLinkingContext::CoreLinkingContext() {}
+
+bool CoreLinkingContext::validateImpl(raw_ostream &) {
+ _writer = createWriterYAML(*this);
+ return true;
+}
+
+void CoreLinkingContext::addPasses(PassManager &pm) {
+ for (StringRef name : _passNames) {
+ if (name.equals("order"))
+ pm.add(std::unique_ptr<Pass>(new OrderPass()));
+ else
+ llvm_unreachable("bad pass name");
+ }
+}
+
+Writer &CoreLinkingContext::writer() const { return *_writer; }
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64DynamicLibraryWriter.h b/lib/ReaderWriter/ELF/AArch64/AArch64DynamicLibraryWriter.h
new file mode 100644
index 000000000000..12ba52a38f38
--- /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 000000000000..9d5207c1c4b4
--- /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 000000000000..05f312db3e7b
--- /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 000000000000..73963f56ef70
--- /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 000000000000..9eb98f447709
--- /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 000000000000..ebd91fe0a95b
--- /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 000000000000..d1ecc7fa884b
--- /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 000000000000..b1d3c09dc936
--- /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 000000000000..0bd12958b27b
--- /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 000000000000..73d784e3b52d
--- /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 000000000000..607f767f8b8a
--- /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 000000000000..4eb6786cdf1f
--- /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 000000000000..de94a4df5078
--- /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 000000000000..02cff4747d0d
--- /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 000000000000..aa6f616ff33f
--- /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 000000000000..bc5ee35b8213
--- /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 000000000000..31af531563ea
--- /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 000000000000..19311d516e4d
--- /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 000000000000..5f2436674268
--- /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 000000000000..249b79c4f07d
--- /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 000000000000..d24fdf0fa410
--- /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 000000000000..227d68617bf9
--- /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 000000000000..27ec66ac5557
--- /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 000000000000..651e798f33b1
--- /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 000000000000..540a480421a8
--- /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 000000000000..de90f490f621
--- /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 000000000000..10641954da25
--- /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 000000000000..2ccf9eb6266d
--- /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 000000000000..f67d36a1b612
--- /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 000000000000..d05419decb78
--- /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 000000000000..6a506d21d938
--- /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 000000000000..fd4cb669904d
--- /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 000000000000..2658d023b3a9
--- /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 000000000000..ad34dddb24d3
--- /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 000000000000..9af3b8eb8dc6
--- /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 000000000000..16668f2df618
--- /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 000000000000..c4e3e7165efd
--- /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 000000000000..f97514b525c0
--- /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 000000000000..11f4ee4fc633
--- /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 000000000000..c7dffda8a463
--- /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 000000000000..43f218115c66
--- /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 000000000000..477e3920abae
--- /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 000000000000..eab132b9b2f6
--- /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 000000000000..6928f43c5459
--- /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 000000000000..e2d3193045b7
--- /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 000000000000..ab0b9b432b43
--- /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 000000000000..1a4f891df799
--- /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 000000000000..96c74f72222d
--- /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 000000000000..3e12786704a2
--- /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 000000000000..a2505aa460c5
--- /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 000000000000..0848e64166fa
--- /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),