aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2016-07-23 20:48:50 +0000
committerDimitry Andric <dim@FreeBSD.org>2016-07-23 20:48:50 +0000
commit1c98619801a5705c688e683be3ef9d70169a0686 (patch)
tree8422105cd1a94c368315f2db16b9ac746cf7c000 /lib
parentf4f3ce4613680903220815690ad79fc7ba0a2e26 (diff)
downloadsrc-1c98619801a5705c688e683be3ef9d70169a0686.tar.gz
src-1c98619801a5705c688e683be3ef9d70169a0686.zip
Vendor import of lld release_39 branch r276489:vendor/lld/lld-release_39-r276489
Notes
Notes: svn path=/vendor/lld/dist/; revision=303239 svn path=/vendor/lld/lld-release_39-r276489/; revision=303240; tag=vendor/lld/lld-release_39-r276489
Diffstat (limited to 'lib')
-rw-r--r--lib/Config/Version.cpp27
-rw-r--r--lib/Core/DefinedAtom.cpp11
-rw-r--r--lib/Core/Error.cpp48
-rw-r--r--lib/Core/File.cpp2
-rw-r--r--lib/Core/LinkingContext.cpp47
-rw-r--r--lib/Core/Reader.cpp1
-rw-r--r--lib/Core/Resolver.cpp330
-rw-r--r--lib/Core/SymbolTable.cpp92
-rw-r--r--lib/Driver/CMakeLists.txt21
-rw-r--r--lib/Driver/CoreDriver.cpp173
-rw-r--r--lib/Driver/CoreOptions.td15
-rw-r--r--lib/Driver/DarwinLdDriver.cpp387
-rw-r--r--lib/Driver/DarwinLdOptions.td35
-rw-r--r--lib/Driver/Driver.cpp142
-rw-r--r--lib/Driver/GnuLdDriver.cpp782
-rw-r--r--lib/Driver/GnuLdOptions.td378
-rw-r--r--lib/Driver/TODO.rst99
-rw-r--r--lib/Driver/UniversalDriver.cpp225
-rw-r--r--lib/Driver/UniversalDriverOptions.td19
-rw-r--r--lib/ReaderWriter/CMakeLists.txt3
-rw-r--r--lib/ReaderWriter/CoreLinkingContext.cpp50
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64DynamicLibraryWriter.h45
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.cpp52
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.h38
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.cpp45
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.h101
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.cpp556
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.h36
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.cpp612
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.h32
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64SectionChunks.cpp39
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64SectionChunks.h37
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.cpp51
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.h90
-rw-r--r--lib/ReaderWriter/ELF/AArch64/CMakeLists.txt14
-rw-r--r--lib/ReaderWriter/ELF/AArch64/TODO.rst15
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMDynamicLibraryWriter.h49
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMELFFile.h154
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMELFWriters.h120
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h68
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp64
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h80
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp680
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h35
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp985
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMRelocationPass.h31
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h59
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp32
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h174
-rw-r--r--lib/ReaderWriter/ELF/ARM/CMakeLists.txt12
-rw-r--r--lib/ReaderWriter/ELF/ARM/TODO.rst21
-rw-r--r--lib/ReaderWriter/ELF/Atoms.cpp297
-rw-r--r--lib/ReaderWriter/ELF/Atoms.h493
-rw-r--r--lib/ReaderWriter/ELF/CMakeLists.txt29
-rw-r--r--lib/ReaderWriter/ELF/Chunk.h111
-rw-r--r--lib/ReaderWriter/ELF/DynamicFile.cpp146
-rw-r--r--lib/ReaderWriter/ELF/DynamicFile.h59
-rw-r--r--lib/ReaderWriter/ELF/DynamicLibraryWriter.h86
-rw-r--r--lib/ReaderWriter/ELF/ELFFile.cpp829
-rw-r--r--lib/ReaderWriter/ELF/ELFFile.h395
-rw-r--r--lib/ReaderWriter/ELF/ELFLinkingContext.cpp263
-rw-r--r--lib/ReaderWriter/ELF/ELFReader.h47
-rw-r--r--lib/ReaderWriter/ELF/ExecutableWriter.h157
-rw-r--r--lib/ReaderWriter/ELF/FileCommon.cpp66
-rw-r--r--lib/ReaderWriter/ELF/FileCommon.h45
-rw-r--r--lib/ReaderWriter/ELF/HeaderChunks.cpp205
-rw-r--r--lib/ReaderWriter/ELF/HeaderChunks.h154
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/CMakeLists.txt11
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonDynamicLibraryWriter.h67
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonELFFile.h149
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonEncodings.h638
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonExecutableWriter.h73
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.cpp47
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.h61
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.cpp330
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.h33
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.cpp382
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.h134
-rw-r--r--lib/ReaderWriter/ELF/Mips/CMakeLists.txt18
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsAbiInfoHandler.cpp675
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsAbiInfoHandler.h83
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.cpp76
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.h25
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsDynamicTable.h124
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsELFFile.cpp348
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsELFFile.h126
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsELFWriters.cpp292
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsELFWriters.h102
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp164
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h56
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp687
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.h31
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp1415
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsRelocationPass.h25
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsSectionChunks.cpp264
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h150
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp166
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h73
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsTargetLayout.cpp111
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsTargetLayout.h71
-rw-r--r--lib/ReaderWriter/ELF/OrderPass.h31
-rw-r--r--lib/ReaderWriter/ELF/OutputELFWriter.cpp514
-rw-r--r--lib/ReaderWriter/ELF/OutputELFWriter.h153
-rw-r--r--lib/ReaderWriter/ELF/Reader.cpp43
-rw-r--r--lib/ReaderWriter/ELF/SectionChunks.cpp996
-rw-r--r--lib/ReaderWriter/ELF/SectionChunks.h616
-rw-r--r--lib/ReaderWriter/ELF/SegmentChunks.cpp519
-rw-r--r--lib/ReaderWriter/ELF/SegmentChunks.h246
-rw-r--r--lib/ReaderWriter/ELF/TODO.txt18
-rw-r--r--lib/ReaderWriter/ELF/TargetHandler.h35
-rw-r--r--lib/ReaderWriter/ELF/TargetLayout.cpp747
-rw-r--r--lib/ReaderWriter/ELF/TargetLayout.h327
-rw-r--r--lib/ReaderWriter/ELF/Writer.cpp23
-rw-r--r--lib/ReaderWriter/ELF/Writer.h35
-rw-r--r--lib/ReaderWriter/ELF/X86/CMakeLists.txt11
-rw-r--r--lib/ReaderWriter/ELF/X86/X86DynamicLibraryWriter.h44
-rw-r--r--lib/ReaderWriter/ELF/X86/X86ExecutableWriter.h39
-rw-r--r--lib/ReaderWriter/ELF/X86/X86LinkingContext.cpp39
-rw-r--r--lib/ReaderWriter/ELF/X86/X86LinkingContext.h44
-rw-r--r--lib/ReaderWriter/ELF/X86/X86RelocationHandler.cpp54
-rw-r--r--lib/ReaderWriter/ELF/X86/X86RelocationHandler.h28
-rw-r--r--lib/ReaderWriter/ELF/X86/X86TargetHandler.cpp36
-rw-r--r--lib/ReaderWriter/ELF/X86/X86TargetHandler.h48
-rw-r--r--lib/ReaderWriter/ELF/X86_64/CMakeLists.txt17
-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.cpp22
-rw-r--r--lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleTargetHandler.h31
-rw-r--r--lib/ReaderWriter/ELF/X86_64/TODO.rst46
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64DynamicLibraryWriter.h45
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64ExecutableWriter.h57
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp50
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h103
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp147
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.h37
-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_64SectionChunks.cpp37
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64SectionChunks.h36
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.cpp34
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h104
-rw-r--r--lib/ReaderWriter/FileArchive.cpp173
-rw-r--r--lib/ReaderWriter/LinkerScript.cpp2895
-rw-r--r--lib/ReaderWriter/MachO/ArchHandler.h29
-rw-r--r--lib/ReaderWriter/MachO/ArchHandler_arm.cpp131
-rw-r--r--lib/ReaderWriter/MachO/ArchHandler_arm64.cpp122
-rw-r--r--lib/ReaderWriter/MachO/ArchHandler_x86.cpp74
-rw-r--r--lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp178
-rw-r--r--lib/ReaderWriter/MachO/Atoms.h32
-rw-r--r--lib/ReaderWriter/MachO/CMakeLists.txt2
-rw-r--r--lib/ReaderWriter/MachO/CompactUnwindPass.cpp33
-rw-r--r--lib/ReaderWriter/MachO/ExecutableAtoms.h108
-rw-r--r--lib/ReaderWriter/MachO/File.h93
-rw-r--r--lib/ReaderWriter/MachO/FlatNamespaceFile.h28
-rw-r--r--lib/ReaderWriter/MachO/GOTPass.cpp12
-rw-r--r--lib/ReaderWriter/MachO/LayoutPass.cpp47
-rw-r--r--lib/ReaderWriter/MachO/LayoutPass.h39
-rw-r--r--lib/ReaderWriter/MachO/MachOLinkingContext.cpp216
-rw-r--r--lib/ReaderWriter/MachO/MachONormalizedFile.h32
-rw-r--r--lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp44
-rw-r--r--lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h46
-rw-r--r--lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp461
-rw-r--r--lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp268
-rw-r--r--lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp608
-rw-r--r--lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp81
-rw-r--r--lib/ReaderWriter/MachO/MachOPasses.h1
-rw-r--r--lib/ReaderWriter/MachO/ObjCPass.cpp128
-rw-r--r--lib/ReaderWriter/MachO/SectCreateFile.h19
-rw-r--r--lib/ReaderWriter/MachO/ShimPass.cpp13
-rw-r--r--lib/ReaderWriter/MachO/StubsPass.cpp40
-rw-r--r--lib/ReaderWriter/MachO/TLVPass.cpp14
-rw-r--r--lib/ReaderWriter/MachO/WriterMachO.cpp9
-rw-r--r--lib/ReaderWriter/YAML/ReaderWriterYAML.cpp302
174 files changed, 2828 insertions, 27087 deletions
diff --git a/lib/Config/Version.cpp b/lib/Config/Version.cpp
index b64ccef12c7b..60687b9d8940 100644
--- a/lib/Config/Version.cpp
+++ b/lib/Config/Version.cpp
@@ -13,8 +13,6 @@
#include "lld/Config/Version.h"
#include "llvm/Support/raw_ostream.h"
-#include <cstdlib>
-#include <cstring>
using namespace llvm;
@@ -37,22 +35,15 @@ StringRef getLLDRevision() {
}
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();
+ std::string S = getLLDRepositoryPath();
+ std::string T = getLLDRevision();
+ if (S.empty() && T.empty())
+ return "";
+ if (!S.empty() && !T.empty())
+ return "(" + S + " " + T + ")";
+ if (!S.empty())
+ return "(" + S + ")";
+ return "(" + T + ")";
}
StringRef getLLDVersion() {
diff --git a/lib/Core/DefinedAtom.cpp b/lib/Core/DefinedAtom.cpp
index f1d308088ed4..8dc4d4a16f96 100644
--- a/lib/Core/DefinedAtom.cpp
+++ b/lib/Core/DefinedAtom.cpp
@@ -41,8 +41,8 @@ DefinedAtom::ContentPermissions DefinedAtom::permissions(ContentType type) {
case typeDTraceDOF:
case typeCompactUnwindInfo:
case typeProcessedUnwindInfo:
- case typeRONote:
- case typeNoAlloc:
+ case typeObjCImageInfo:
+ case typeObjCMethodList:
return permR__;
case typeData:
@@ -52,8 +52,8 @@ DefinedAtom::ContentPermissions DefinedAtom::permissions(ContentType type) {
case typeObjC1Class:
case typeLazyPointer:
case typeLazyDylibPointer:
+ case typeNonLazyPointer:
case typeThunkTLV:
- case typeRWNote:
return permRW_;
case typeGOT:
@@ -68,15 +68,12 @@ DefinedAtom::ContentPermissions DefinedAtom::permissions(ContentType type) {
case typeTLVInitialData:
case typeTLVInitialZeroFill:
case typeTLVInitializerPtr:
- case typeThreadData:
- case typeThreadZeroFill:
return permRW_L;
- case typeGroupComdat:
- case typeGnuLinkOnce:
case typeUnknown:
case typeTempLTO:
case typeSectCreate:
+ case typeDSOHandle:
return permUnknown;
}
llvm_unreachable("unknown content type");
diff --git a/lib/Core/Error.cpp b/lib/Core/Error.cpp
index 3b7733746dcd..4df1ce120bd9 100644
--- a/lib/Core/Error.cpp
+++ b/lib/Core/Error.cpp
@@ -39,42 +39,6 @@ const std::error_category &lld::YamlReaderCategory() {
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";
- case LinkerScriptReaderError::unknown_phdr_ids:
- return "Unknown header identifiers (missing in PHDRS command) are used";
- case LinkerScriptReaderError::extra_program_phdr:
- return "Extra program header is found";
- case LinkerScriptReaderError::misplaced_program_phdr:
- return "Program header must precede load segments";
- case LinkerScriptReaderError::program_phdr_wrong_phdrs:
- return "Program header has invalid PHDRS attribute";
- }
- 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
@@ -112,16 +76,16 @@ private:
static dynamic_error_category categorySingleton;
-std::error_code make_dynamic_error_code(const char *msg) {
- return make_dynamic_error_code(StringRef(msg));
-}
-
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);
+char GenericError::ID = 0;
+
+GenericError::GenericError(Twine Msg) : Msg(Msg.str()) { }
+
+void GenericError::log(raw_ostream &OS) const {
+ OS << Msg;
}
} // namespace lld
diff --git a/lib/Core/File.cpp b/lib/Core/File.cpp
index ac95f1016797..b84132bfecd5 100644
--- a/lib/Core/File.cpp
+++ b/lib/Core/File.cpp
@@ -13,7 +13,7 @@
namespace lld {
-File::~File() {}
+File::~File() { }
File::AtomVector<DefinedAtom> File::_noDefinedAtoms;
File::AtomVector<UndefinedAtom> File::_noUndefinedAtoms;
diff --git a/lib/Core/LinkingContext.cpp b/lib/Core/LinkingContext.cpp
index cbcf25c17df2..2732543d306e 100644
--- a/lib/Core/LinkingContext.cpp
+++ b/lib/Core/LinkingContext.cpp
@@ -7,7 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lld/Core/Alias.h"
#include "lld/Core/LinkingContext.h"
#include "lld/Core/Resolver.h"
#include "lld/Core/Simple.h"
@@ -16,16 +15,7 @@
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(true),
- _outputFileType(OutputFileType::Default), _nextOrdinal(0) {}
+LinkingContext::LinkingContext() {}
LinkingContext::~LinkingContext() {}
@@ -33,15 +23,10 @@ bool LinkingContext::validate(raw_ostream &diagnostics) {
return validateImpl(diagnostics);
}
-std::error_code LinkingContext::writeFile(const File &linkedFile) const {
+llvm::Error LinkingContext::writeFile(const File &linkedFile) const {
return this->writer().writeFile(linkedFile, _outputPath);
}
-void LinkingContext::createImplicitFiles(
- std::vector<std::unique_ptr<File>> &result) {
- this->writer().createImplicitFiles(result);
-}
-
std::unique_ptr<File> LinkingContext::createEntrySymbolFile() const {
return createEntrySymbolFile("<command line option -e>");
}
@@ -50,7 +35,8 @@ std::unique_ptr<File>
LinkingContext::createEntrySymbolFile(StringRef filename) const {
if (entrySymbolName().empty())
return nullptr;
- std::unique_ptr<SimpleFile> entryFile(new SimpleFile(filename));
+ std::unique_ptr<SimpleFile> entryFile(new SimpleFile(filename,
+ File::kindEntryObject));
entryFile->addAtom(
*(new (_allocator) SimpleUndefinedAtom(*entryFile, entrySymbolName())));
return std::move(entryFile);
@@ -64,41 +50,20 @@ std::unique_ptr<File>
LinkingContext::createUndefinedSymbolFile(StringRef filename) const {
if (_initialUndefinedSymbols.empty())
return nullptr;
- std::unique_ptr<SimpleFile> undefinedSymFile(new SimpleFile(filename));
+ std::unique_ptr<SimpleFile> undefinedSymFile(
+ new SimpleFile(filename, File::kindUndefinedSymsObject));
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/Reader.cpp b/lib/Core/Reader.cpp
index 6069093d211e..107db07891da 100644
--- a/lib/Core/Reader.cpp
+++ b/lib/Core/Reader.cpp
@@ -47,7 +47,6 @@ Registry::loadFile(std::unique_ptr<MemoryBuffer> mb) const {
static const Registry::KindStrings kindStrings[] = {
{Reference::kindLayoutAfter, "layout-after"},
- {Reference::kindGroupChild, "group-child"},
{Reference::kindAssociate, "associate"},
LLD_KIND_STRING_END};
diff --git a/lib/Core/Resolver.cpp b/lib/Core/Resolver.cpp
index 8f89856c4a47..ef694fd972fc 100644
--- a/lib/Core/Resolver.cpp
+++ b/lib/Core/Resolver.cpp
@@ -19,6 +19,7 @@
#include "lld/Core/UndefinedAtom.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
@@ -29,26 +30,27 @@
namespace lld {
-bool Resolver::handleFile(File &file) {
+llvm::Expected<bool> Resolver::handleFile(File &file) {
+ if (auto ec = _ctx.handleLoadedFile(file))
+ return std::move(ec);
bool undefAdded = false;
- for (const DefinedAtom *atom : file.defined())
- doDefinedAtom(*atom);
- for (const UndefinedAtom *atom : file.undefined()) {
- if (doUndefinedAtom(*atom)) {
+ for (auto &atom : file.defined().owning_ptrs())
+ doDefinedAtom(std::move(atom));
+ for (auto &atom : file.undefined().owning_ptrs()) {
+ if (doUndefinedAtom(std::move(atom)))
undefAdded = true;
- maybePreloadArchiveMember(atom->name());
- }
}
- for (const SharedLibraryAtom *atom : file.sharedLibrary())
- doSharedLibraryAtom(*atom);
- for (const AbsoluteAtom *atom : file.absolute())
- doAbsoluteAtom(*atom);
+ for (auto &atom : file.sharedLibrary().owning_ptrs())
+ doSharedLibraryAtom(std::move(atom));
+ for (auto &atom : file.absolute().owning_ptrs())
+ doAbsoluteAtom(std::move(atom));
return undefAdded;
}
-void Resolver::forEachUndefines(File &file, bool searchForOverrides,
- UndefCallback callback) {
+llvm::Expected<bool> Resolver::forEachUndefines(File &file,
+ UndefCallback callback) {
size_t i = _undefineIndex[&file];
+ bool undefAdded = false;
do {
for (; i < _undefines.size(); ++i) {
StringRef undefName = _undefines[i];
@@ -60,190 +62,120 @@ void Resolver::forEachUndefines(File &file, bool searchForOverrides,
_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);
+ auto undefAddedOrError = callback(undefName);
+ if (auto ec = undefAddedOrError.takeError())
+ return std::move(ec);
+ undefAdded |= undefAddedOrError.get();
}
} while (i < _undefines.size());
_undefineIndex[&file] = i;
+ return undefAdded;
}
-bool Resolver::handleArchiveFile(File &file) {
+llvm::Expected<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)) {
+ return forEachUndefines(file,
+ [&](StringRef undefName) -> llvm::Expected<bool> {
+ if (File *member = archiveFile->find(undefName)) {
member->setOrdinal(_ctx.getNextOrdinalAndIncrement());
- member->beforeLink();
- updatePreloadArchiveMap();
- undefAdded = handleFile(*member) || undefAdded;
+ return handleFile(*member);
}
+ return false;
});
- return undefAdded;
}
-void Resolver::handleSharedLibrary(File &file) {
+llvm::Error 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);
- });
+ auto undefAddedOrError = handleFile(*sharedLibrary);
+ if (auto ec = undefAddedOrError.takeError())
+ return ec;
+ undefAddedOrError =
+ forEachUndefines(file, [&](StringRef undefName) -> llvm::Expected<bool> {
+ auto atom = sharedLibrary->exports(undefName);
+ if (atom.get())
+ doSharedLibraryAtom(std::move(atom));
+ return false;
+ });
+
+ if (auto ec = undefAddedOrError.takeError())
+ return ec;
+ return llvm::Error();
}
-bool Resolver::doUndefinedAtom(const UndefinedAtom &atom) {
+bool Resolver::doUndefinedAtom(OwningAtomPtr<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);
+ << llvm::format("0x%09lX", atom.get())
+ << ", name=" << atom.get()->name() << "\n");
// tell symbol table
- bool newUndefAdded = _symbolTable.add(atom);
+ bool newUndefAdded = _symbolTable.add(*atom.get());
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;
-}
+ _undefines.push_back(atom.get()->name());
-/// \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");
- }
+ // add to list of known atoms
+ _atoms.push_back(OwningAtomPtr<Atom>(atom.release()));
- 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);
- }
- }
+ return newUndefAdded;
}
// 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) {
+void Resolver::doDefinedAtom(OwningAtomPtr<DefinedAtom> atom) {
DEBUG_WITH_TYPE("resolver", llvm::dbgs()
<< " DefinedAtom: "
- << llvm::format("0x%09lX", &atom)
+ << llvm::format("0x%09lX", atom.get())
<< ", file=#"
- << atom.file().ordinal()
+ << atom.get()->file().ordinal()
<< ", atom=#"
- << atom.ordinal()
+ << atom.get()->ordinal()
<< ", name="
- << atom.name()
+ << atom.get()->name()
<< ", type="
- << atom.contentType()
+ << atom.get()->contentType()
<< "\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);
+ if (_ctx.deadStrip() &&
+ atom.get()->deadStrip() == DefinedAtom::deadStripNever) {
+ _deadStripRoots.insert(atom.get());
}
+
+ // add to list of known atoms
+ _symbolTable.add(*atom.get());
+ _atoms.push_back(OwningAtomPtr<Atom>(atom.release()));
}
-void Resolver::doSharedLibraryAtom(const SharedLibraryAtom &atom) {
+void Resolver::doSharedLibraryAtom(OwningAtomPtr<SharedLibraryAtom> atom) {
DEBUG_WITH_TYPE("resolver", llvm::dbgs()
<< " SharedLibraryAtom: "
- << llvm::format("0x%09lX", &atom)
+ << llvm::format("0x%09lX", atom.get())
<< ", name="
- << atom.name()
+ << atom.get()->name()
<< "\n");
- // add to list of known atoms
- _atoms.push_back(&atom);
-
// tell symbol table
- _symbolTable.add(atom);
+ _symbolTable.add(*atom.get());
+
+ // add to list of known atoms
+ _atoms.push_back(OwningAtomPtr<Atom>(atom.release()));
}
-void Resolver::doAbsoluteAtom(const AbsoluteAtom &atom) {
+void Resolver::doAbsoluteAtom(OwningAtomPtr<AbsoluteAtom> atom) {
DEBUG_WITH_TYPE("resolver", llvm::dbgs()
<< " AbsoluteAtom: "
- << llvm::format("0x%09lX", &atom)
+ << llvm::format("0x%09lX", atom.get())
<< ", name="
- << atom.name()
+ << atom.get()->name()
<< "\n");
- // add to list of known atoms
- _atoms.push_back(&atom);
-
// tell symbol table
- if (atom.scope() != Atom::scopeTranslationUnit)
- _symbolTable.add(atom);
-}
+ if (atom.get()->scope() != Atom::scopeTranslationUnit)
+ _symbolTable.add(*atom.get());
-// 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);
+ // add to list of known atoms
+ _atoms.push_back(OwningAtomPtr<Atom>(atom.release()));
}
// Returns true if at least one of N previous files has created an
@@ -276,23 +208,6 @@ File *Resolver::getFile(int &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() {
@@ -315,10 +230,17 @@ bool Resolver::resolveUndefines() {
}
DEBUG_WITH_TYPE("resolver",
llvm::dbgs() << "Loaded file: " << file->path() << "\n");
- file->beforeLink();
- updatePreloadArchiveMap();
switch (file->kind()) {
- case File::kindObject:
+ case File::kindErrorObject:
+ case File::kindNormalizedObject:
+ case File::kindMachObject:
+ case File::kindCEntryObject:
+ case File::kindHeaderObject:
+ case File::kindEntryObject:
+ case File::kindUndefinedSymsObject:
+ case File::kindStubHelperObject:
+ case File::kindResolverMergedObject:
+ case File::kindSectCreateObject: {
// 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.
@@ -327,17 +249,41 @@ bool Resolver::resolveUndefines() {
seen.insert(file);
assert(!file->hasOrdinal());
file->setOrdinal(_ctx.getNextOrdinalAndIncrement());
- undefAdded = handleFile(*file);
+ auto undefAddedOrError = handleFile(*file);
+ if (auto EC = undefAddedOrError.takeError()) {
+ // FIXME: This should be passed to logAllUnhandledErrors but it needs
+ // to be passed a Twine instead of a string.
+ llvm::errs() << "Error in " + file->path() << ": ";
+ logAllUnhandledErrors(std::move(EC), llvm::errs(), std::string());
+ return false;
+ }
+ undefAdded = undefAddedOrError.get();
break;
- case File::kindArchiveLibrary:
+ }
+ case File::kindArchiveLibrary: {
if (!file->hasOrdinal())
file->setOrdinal(_ctx.getNextOrdinalAndIncrement());
- undefAdded = handleArchiveFile(*file);
+ auto undefAddedOrError = handleArchiveFile(*file);
+ if (auto EC = undefAddedOrError.takeError()) {
+ // FIXME: This should be passed to logAllUnhandledErrors but it needs
+ // to be passed a Twine instead of a string.
+ llvm::errs() << "Error in " + file->path() << ": ";
+ logAllUnhandledErrors(std::move(EC), llvm::errs(), std::string());
+ return false;
+ }
+ undefAdded = undefAddedOrError.get();
break;
+ }
case File::kindSharedLibrary:
if (!file->hasOrdinal())
file->setOrdinal(_ctx.getNextOrdinalAndIncrement());
- handleSharedLibrary(*file);
+ if (auto EC = handleSharedLibrary(*file)) {
+ // FIXME: This should be passed to logAllUnhandledErrors but it needs
+ // to be passed a Twine instead of a string.
+ llvm::errs() << "Error in " + file->path() << ": ";
+ logAllUnhandledErrors(std::move(EC), llvm::errs(), std::string());
+ return false;
+ }
break;
}
_newUndefinesAdded[file] = undefAdded;
@@ -350,8 +296,8 @@ void Resolver::updateReferences() {
DEBUG_WITH_TYPE("resolver",
llvm::dbgs() << "******** Updating references:\n");
ScopedTask task(getDefaultDomain(), "updateReferences");
- for (const Atom *atom : _atoms) {
- if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom)) {
+ for (const OwningAtomPtr<Atom> &atom : _atoms) {
+ if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom.get())) {
for (const Reference *ref : *defAtom) {
// A reference of type kindAssociate should't be updated.
// Instead, an atom having such reference will be removed
@@ -359,7 +305,7 @@ void Resolver::updateReferences() {
// go away as a group.
if (ref->kindNamespace() == lld::Reference::KindNamespace::all &&
ref->kindValue() == lld::Reference::kindAssociate) {
- if (_symbolTable.isCoalescedAway(atom))
+ if (_symbolTable.isCoalescedAway(atom.get()))
_deadAtoms.insert(ref->target());
continue;
}
@@ -391,8 +337,7 @@ void Resolver::markLive(const Atom *atom) {
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);
+ return (ref->kindValue() == lld::Reference::kindLayoutAfter);
}
// remove all atoms not actually used
@@ -408,19 +353,19 @@ void Resolver::deadStripOptimize() {
// 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 OwningAtomPtr<Atom> &atom : _atoms) {
+ if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom.get()))
for (const Reference *ref : *defAtom)
if (isBackref(ref))
- _reverseRef.insert(std::make_pair(ref->target(), atom));
- if (const AbsoluteAtom *absAtom = dyn_cast<AbsoluteAtom>(atom))
+ _reverseRef.insert(std::make_pair(ref->target(), atom.get()));
+ if (const AbsoluteAtom *absAtom = dyn_cast<AbsoluteAtom>(atom.get()))
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))
+ for (const OwningAtomPtr<Atom> &atom : _atoms)
+ if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom.get()))
if (defAtom->scope() == DefinedAtom::scopeGlobal)
_deadStripRoots.insert(defAtom);
@@ -436,8 +381,9 @@ void Resolver::deadStripOptimize() {
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.erase(std::remove_if(_atoms.begin(), _atoms.end(),
+ [&](OwningAtomPtr<Atom> &a) {
+ return _liveAtoms.count(a.get()) == 0;
}),
_atoms.end());
}
@@ -496,8 +442,10 @@ void Resolver::removeCoalescedAwayAtoms() {
DEBUG_WITH_TYPE("resolver",
llvm::dbgs() << "******** Removing coalesced away atoms:\n");
ScopedTask task(getDefaultDomain(), "removeCoalescedAwayAtoms");
- _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), [&](const Atom *a) {
- return _symbolTable.isCoalescedAway(a) || _deadAtoms.count(a);
+ _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(),
+ [&](OwningAtomPtr<Atom> &a) {
+ return _symbolTable.isCoalescedAway(a.get()) ||
+ _deadAtoms.count(a.get());
}),
_atoms.end());
}
@@ -505,7 +453,6 @@ void Resolver::removeCoalescedAwayAtoms() {
bool Resolver::resolve() {
DEBUG_WITH_TYPE("resolver",
llvm::dbgs() << "******** Resolving atom references:\n");
- updatePreloadArchiveMap();
if (!resolveUndefines())
return false;
updateReferences();
@@ -524,15 +471,16 @@ bool Resolver::resolve() {
return true;
}
-void Resolver::MergedFile::addAtoms(std::vector<const Atom *> &all) {
+void Resolver::MergedFile::addAtoms(
+ llvm::MutableArrayRef<OwningAtomPtr<Atom>> all) {
ScopedTask task(getDefaultDomain(), "addAtoms");
DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "Resolver final atom list:\n");
- for (const Atom *atom : all) {
+ for (OwningAtomPtr<Atom> &atom : all) {
#ifndef NDEBUG
- if (auto *definedAtom = dyn_cast<DefinedAtom>(atom)) {
+ if (auto *definedAtom = dyn_cast<DefinedAtom>(atom.get())) {
DEBUG_WITH_TYPE("resolver", llvm::dbgs()
- << llvm::format(" 0x%09lX", atom)
+ << llvm::format(" 0x%09lX", definedAtom)
<< ", file=#"
<< definedAtom->file().ordinal()
<< ", atom=#"
@@ -544,13 +492,13 @@ void Resolver::MergedFile::addAtoms(std::vector<const Atom *> &all) {
<< "\n");
} else {
DEBUG_WITH_TYPE("resolver", llvm::dbgs()
- << llvm::format(" 0x%09lX", atom)
+ << llvm::format(" 0x%09lX", atom.get())
<< ", name="
- << atom->name()
+ << atom.get()->name()
<< "\n");
}
#endif
- addAtom(*atom);
+ addAtom(*atom.release());
}
}
diff --git a/lib/Core/SymbolTable.cpp b/lib/Core/SymbolTable.cpp
index b85a83ffbfe6..44631a5d40dc 100644
--- a/lib/Core/SymbolTable.cpp
+++ b/lib/Core/SymbolTable.cpp
@@ -28,8 +28,6 @@
#include <vector>
namespace lld {
-SymbolTable::SymbolTable(LinkingContext &context) : _ctx(context) {}
-
bool SymbolTable::add(const UndefinedAtom &atom) { return addByName(atom); }
bool SymbolTable::add(const SharedLibraryAtom &atom) { return addByName(atom); }
@@ -55,25 +53,6 @@ bool SymbolTable::add(const DefinedAtom &atom) {
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,
@@ -185,19 +164,16 @@ bool SymbolTable::addByName(const Atom &newAtom) {
// fallthrough
}
case MCR_Error:
- if (!_ctx.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;
+ llvm::errs() << "Duplicate symbols: "
+ << existing->name()
+ << ":"
+ << existing->file().path()
+ << " and "
+ << newAtom.name()
+ << ":"
+ << newAtom.file().path()
+ << "\n";
+ llvm::report_fatal_error("duplicate symbol error");
break;
}
break;
@@ -207,56 +183,13 @@ bool SymbolTable::addByName(const Atom &newAtom) {
const UndefinedAtom* newUndef = cast<UndefinedAtom>(&newAtom);
bool sameCanBeNull = (existingUndef->canBeNull() == newUndef->canBeNull());
- if (!sameCanBeNull && _ctx.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;
+ useNew = false;
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 &&
- _ctx.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 && _ctx.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;
}
@@ -266,9 +199,6 @@ bool SymbolTable::addByName(const Atom &newAtom) {
break;
}
- // Give context a chance to change which is kept.
- _ctx.notifySymbolTableCoalesce(existing, &newAtom, useNew);
-
if (useNew) {
// Update name table to use new atom.
_nameTable[name] = &newAtom;
diff --git a/lib/Driver/CMakeLists.txt b/lib/Driver/CMakeLists.txt
index 840ccce50ab3..1bd1f2125816 100644
--- a/lib/Driver/CMakeLists.txt
+++ b/lib/Driver/CMakeLists.txt
@@ -1,19 +1,9 @@
-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)
add_public_tablegen_target(DriverOptionsTableGen)
add_lld_library(lldDriver
- CoreDriver.cpp
DarwinLdDriver.cpp
- Driver.cpp
- GnuLdDriver.cpp
- UniversalDriver.cpp
ADDITIONAL_HEADER_DIRS
${LLD_INCLUDE_DIR}/lld/Driver
@@ -21,16 +11,6 @@ add_lld_library(lldDriver
LINK_LIBS
lldConfig
lldMachO
- lldCOFF
- lldELF
- lldELF2
- lldAArch64ELFTarget
- lldARMELFTarget
- lldHexagonELFTarget
- lldMipsELFTarget
- lldX86ELFTarget
- lldExampleSubTarget
- lldX86_64ELFTarget
lldCore
lldReaderWriter
lldYAML
@@ -40,4 +20,3 @@ add_lld_library(lldDriver
)
add_dependencies(lldDriver DriverOptionsTableGen)
-
diff --git a/lib/Driver/CoreDriver.cpp b/lib/Driver/CoreDriver.cpp
deleted file mode 100644
index ce8648595109..000000000000
--- a/lib/Driver/CoreDriver.cpp
+++ /dev/null
@@ -1,173 +0,0 @@
-//===- 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) {}
-};
-
-} // 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(llvm::ArrayRef<const char *> args,
- raw_ostream &diagnostics) {
- CoreLinkingContext ctx;
-
- // Register possible input file parsers.
- ctx.registry().addSupportYamlFiles();
- ctx.registry().addKindTable(Reference::KindNamespace::testing,
- Reference::KindArch::all, coreKindStrings);
-
- if (!parse(args, ctx))
- return false;
- return Driver::link(ctx);
-}
-
-bool CoreDriver::parse(llvm::ArrayRef<const char *> args,
- CoreLinkingContext &ctx, raw_ostream &diagnostics) {
- // Parse command line options using CoreOptions.td
- CoreOptTable table;
- unsigned missingIndex;
- unsigned missingCount;
- llvm::opt::InputArgList parsedArgs =
- table.ParseArgs(args.slice(1), 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;
- }
- }
-
- parseLLVMOptions(ctx);
-
- 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
deleted file mode 100644
index df7cb41737d2..000000000000
--- a/lib/Driver/CoreOptions.td
+++ /dev/null
@@ -1,15 +0,0 @@
-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
index 40fad74c9529..496b651bab4f 100644
--- a/lib/Driver/DarwinLdDriver.cpp
+++ b/lib/Driver/DarwinLdDriver.cpp
@@ -13,8 +13,11 @@
///
//===----------------------------------------------------------------------===//
-#include "lld/Core/File.h"
#include "lld/Core/ArchiveLibraryFile.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Instrumentation.h"
+#include "lld/Core/PassManager.h"
+#include "lld/Core/Resolver.h"
#include "lld/Core/SharedLibraryFile.h"
#include "lld/Driver/Driver.h"
#include "lld/ReaderWriter/MachOLinkingContext.h"
@@ -25,17 +28,10 @@
#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/Error.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;
@@ -72,6 +68,25 @@ public:
DarwinLdOptTable() : OptTable(infoTable) {}
};
+static std::vector<std::unique_ptr<File>>
+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;
+}
+
+static std::vector<std::unique_ptr<File>>
+parseMemberFiles(std::unique_ptr<File> file) {
+ std::vector<std::unique_ptr<File>> members;
+ 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;
+}
+
std::vector<std::unique_ptr<File>>
loadFile(MachOLinkingContext &ctx, StringRef path,
raw_ostream &diag, bool wholeArchive, bool upwardDylib) {
@@ -215,9 +230,9 @@ static std::error_code parseOrderFile(StringRef orderFilePath,
// 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) {
+static llvm::Error 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;
@@ -227,7 +242,7 @@ static std::error_code loadFileList(StringRef fileListPath,
ErrorOr<std::unique_ptr<MemoryBuffer>> mb =
MemoryBuffer::getFileOrSTDIN(filePath);
if (std::error_code ec = mb.getError())
- return ec;
+ return llvm::errorCodeToError(ec);
StringRef buffer = mb->get()->getBuffer();
while (!buffer.empty()) {
// Split off each line in the file.
@@ -245,9 +260,9 @@ static std::error_code loadFileList(StringRef fileListPath,
path = ctx.copy(line);
}
if (!ctx.pathExists(path)) {
- return make_dynamic_error_code(Twine("File not found '")
- + path
- + "'");
+ return llvm::make_error<GenericError>(Twine("File not found '")
+ + path
+ + "'");
}
if (ctx.testingFileUsage()) {
diagnostics << "Found filelist entry " << canonicalizePath(path) << '\n';
@@ -255,7 +270,7 @@ static std::error_code loadFileList(StringRef fileListPath,
addFile(path, ctx, forceLoad, false, diagnostics);
buffer = lineAndRest.second;
}
- return std::error_code();
+ return llvm::Error();
}
/// Parse number assuming it is base 16, but allow 0x prefix.
@@ -265,20 +280,24 @@ static bool parseNumberBase16(StringRef numStr, uint64_t &baseAddress) {
return numStr.getAsInteger(16, baseAddress);
}
-namespace lld {
-
-bool DarwinLdDriver::linkMachO(llvm::ArrayRef<const char *> args,
- raw_ostream &diagnostics) {
- MachOLinkingContext ctx;
- if (!parse(args, ctx, diagnostics))
- return false;
- if (ctx.doNothing())
- return true;
- return link(ctx, diagnostics);
+static void parseLLVMOptions(const LinkingContext &ctx) {
+ // Honor -mllvm
+ if (!ctx.llvmOptions().empty()) {
+ unsigned numArgs = ctx.llvmOptions().size();
+ auto **args = new const char *[numArgs + 2];
+ args[0] = "lld (LLVM option parsing)";
+ for (unsigned i = 0; i != numArgs; ++i)
+ args[i + 1] = ctx.llvmOptions()[i];
+ args[numArgs + 1] = nullptr;
+ llvm::cl::ParseCommandLineOptions(numArgs + 1, args);
+ }
}
-bool DarwinLdDriver::parse(llvm::ArrayRef<const char *> args,
- MachOLinkingContext &ctx, raw_ostream &diagnostics) {
+namespace lld {
+namespace mach_o {
+
+bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx,
+ raw_ostream &diagnostics) {
// Parse command line options using DarwinLdOptions.td
DarwinLdOptTable table;
unsigned missingIndex;
@@ -299,6 +318,7 @@ bool DarwinLdDriver::parse(llvm::ArrayRef<const char *> args,
// Figure out output kind ( -dylib, -r, -bundle, -preload, or -static )
llvm::MachO::HeaderFileType fileType = llvm::MachO::MH_EXECUTE;
+ bool isStaticExecutable = false;
if (llvm::opt::Arg *kind = parsedArgs.getLastArg(
OPT_dylib, OPT_relocatable, OPT_bundle, OPT_static, OPT_preload)) {
switch (kind->getOption().getID()) {
@@ -313,6 +333,7 @@ bool DarwinLdDriver::parse(llvm::ArrayRef<const char *> args,
break;
case OPT_static:
fileType = llvm::MachO::MH_EXECUTE;
+ isStaticExecutable = true;
break;
case OPT_preload:
fileType = llvm::MachO::MH_PRELOAD;
@@ -350,7 +371,7 @@ bool DarwinLdDriver::parse(llvm::ArrayRef<const char *> args,
}
// Handle -macosx_version_min or -ios_version_min
- MachOLinkingContext::OS os = MachOLinkingContext::OS::macOSX;
+ MachOLinkingContext::OS os = MachOLinkingContext::OS::unknown;
uint32_t minOSVersion = 0;
if (llvm::opt::Arg *minOS =
parsedArgs.getLastArg(OPT_macosx_version_min, OPT_ios_version_min,
@@ -385,9 +406,16 @@ bool DarwinLdDriver::parse(llvm::ArrayRef<const char *> args,
// No min-os version on command line, check environment variables
}
+ // Handle export_dynamic
+ // FIXME: Should we warn when this applies to something other than a static
+ // executable or dylib? Those are the only cases where this has an effect.
+ // Note, this has to come before ctx.configure() so that we get the correct
+ // value for _globalsAreDeadStripRoots.
+ bool exportDynamicSymbols = parsedArgs.hasArg(OPT_export_dynamic);
+
// Now that there's enough information parsed in, let the linking context
// set up default values.
- ctx.configure(fileType, arch, os, minOSVersion);
+ ctx.configure(fileType, arch, os, minOSVersion, exportDynamicSymbols);
// Handle -e xxx
if (llvm::opt::Arg *entry = parsedArgs.getLastArg(OPT_entry))
@@ -673,6 +701,22 @@ bool DarwinLdDriver::parse(llvm::ArrayRef<const char *> args,
}
}
+ // Handle obsolete ObjC options: -objc_gc_compaction, -objc_gc, -objc_gc_only
+ if (parsedArgs.getLastArg(OPT_objc_gc_compaction)) {
+ diagnostics << "error: -objc_gc_compaction is not supported\n";
+ return false;
+ }
+
+ if (parsedArgs.getLastArg(OPT_objc_gc)) {
+ diagnostics << "error: -objc_gc is not supported\n";
+ return false;
+ }
+
+ if (parsedArgs.getLastArg(OPT_objc_gc_only)) {
+ diagnostics << "error: -objc_gc_only is not supported\n";
+ return false;
+ }
+
// Handle -pie or -no_pie
if (llvm::opt::Arg *pie = parsedArgs.getLastArg(OPT_pie, OPT_no_pie)) {
switch (ctx.outputMachOType()) {
@@ -719,6 +763,182 @@ bool DarwinLdDriver::parse(llvm::ArrayRef<const char *> args,
}
}
+ // Handle -version_load_command or -no_version_load_command
+ {
+ bool flagOn = false;
+ bool flagOff = false;
+ if (auto *arg = parsedArgs.getLastArg(OPT_version_load_command,
+ OPT_no_version_load_command)) {
+ flagOn = arg->getOption().getID() == OPT_version_load_command;
+ flagOff = arg->getOption().getID() == OPT_no_version_load_command;
+ }
+
+ // default to adding version load command for dynamic code,
+ // static code must opt-in
+ switch (ctx.outputMachOType()) {
+ case llvm::MachO::MH_OBJECT:
+ ctx.setGenerateVersionLoadCommand(false);
+ break;
+ case llvm::MachO::MH_EXECUTE:
+ // dynamic executables default to generating a version load command,
+ // while static exectuables only generate it if required.
+ if (isStaticExecutable) {
+ if (flagOn)
+ ctx.setGenerateVersionLoadCommand(true);
+ } else {
+ if (!flagOff)
+ ctx.setGenerateVersionLoadCommand(true);
+ }
+ break;
+ case llvm::MachO::MH_PRELOAD:
+ case llvm::MachO::MH_KEXT_BUNDLE:
+ if (flagOn)
+ ctx.setGenerateVersionLoadCommand(true);
+ break;
+ case llvm::MachO::MH_DYLINKER:
+ case llvm::MachO::MH_DYLIB:
+ case llvm::MachO::MH_BUNDLE:
+ if (!flagOff)
+ ctx.setGenerateVersionLoadCommand(true);
+ break;
+ case llvm::MachO::MH_FVMLIB:
+ case llvm::MachO::MH_DYLDLINK:
+ case llvm::MachO::MH_DYLIB_STUB:
+ case llvm::MachO::MH_DSYM:
+ // We don't generate load commands for these file types, even if
+ // forced on.
+ break;
+ }
+ }
+
+ // Handle -function_starts or -no_function_starts
+ {
+ bool flagOn = false;
+ bool flagOff = false;
+ if (auto *arg = parsedArgs.getLastArg(OPT_function_starts,
+ OPT_no_function_starts)) {
+ flagOn = arg->getOption().getID() == OPT_function_starts;
+ flagOff = arg->getOption().getID() == OPT_no_function_starts;
+ }
+
+ // default to adding functions start for dynamic code, static code must
+ // opt-in
+ switch (ctx.outputMachOType()) {
+ case llvm::MachO::MH_OBJECT:
+ ctx.setGenerateFunctionStartsLoadCommand(false);
+ break;
+ case llvm::MachO::MH_EXECUTE:
+ // dynamic executables default to generating a version load command,
+ // while static exectuables only generate it if required.
+ if (isStaticExecutable) {
+ if (flagOn)
+ ctx.setGenerateFunctionStartsLoadCommand(true);
+ } else {
+ if (!flagOff)
+ ctx.setGenerateFunctionStartsLoadCommand(true);
+ }
+ break;
+ case llvm::MachO::MH_PRELOAD:
+ case llvm::MachO::MH_KEXT_BUNDLE:
+ if (flagOn)
+ ctx.setGenerateFunctionStartsLoadCommand(true);
+ break;
+ case llvm::MachO::MH_DYLINKER:
+ case llvm::MachO::MH_DYLIB:
+ case llvm::MachO::MH_BUNDLE:
+ if (!flagOff)
+ ctx.setGenerateFunctionStartsLoadCommand(true);
+ break;
+ case llvm::MachO::MH_FVMLIB:
+ case llvm::MachO::MH_DYLDLINK:
+ case llvm::MachO::MH_DYLIB_STUB:
+ case llvm::MachO::MH_DSYM:
+ // We don't generate load commands for these file types, even if
+ // forced on.
+ break;
+ }
+ }
+
+ // Handle -data_in_code_info or -no_data_in_code_info
+ {
+ bool flagOn = false;
+ bool flagOff = false;
+ if (auto *arg = parsedArgs.getLastArg(OPT_data_in_code_info,
+ OPT_no_data_in_code_info)) {
+ flagOn = arg->getOption().getID() == OPT_data_in_code_info;
+ flagOff = arg->getOption().getID() == OPT_no_data_in_code_info;
+ }
+
+ // default to adding data in code for dynamic code, static code must
+ // opt-in
+ switch (ctx.outputMachOType()) {
+ case llvm::MachO::MH_OBJECT:
+ if (!flagOff)
+ ctx.setGenerateDataInCodeLoadCommand(true);
+ break;
+ case llvm::MachO::MH_EXECUTE:
+ // dynamic executables default to generating a version load command,
+ // while static exectuables only generate it if required.
+ if (isStaticExecutable) {
+ if (flagOn)
+ ctx.setGenerateDataInCodeLoadCommand(true);
+ } else {
+ if (!flagOff)
+ ctx.setGenerateDataInCodeLoadCommand(true);
+ }
+ break;
+ case llvm::MachO::MH_PRELOAD:
+ case llvm::MachO::MH_KEXT_BUNDLE:
+ if (flagOn)
+ ctx.setGenerateDataInCodeLoadCommand(true);
+ break;
+ case llvm::MachO::MH_DYLINKER:
+ case llvm::MachO::MH_DYLIB:
+ case llvm::MachO::MH_BUNDLE:
+ if (!flagOff)
+ ctx.setGenerateDataInCodeLoadCommand(true);
+ break;
+ case llvm::MachO::MH_FVMLIB:
+ case llvm::MachO::MH_DYLDLINK:
+ case llvm::MachO::MH_DYLIB_STUB:
+ case llvm::MachO::MH_DSYM:
+ // We don't generate load commands for these file types, even if
+ // forced on.
+ break;
+ }
+ }
+
+ // Handle sdk_version
+ if (llvm::opt::Arg *arg = parsedArgs.getLastArg(OPT_sdk_version)) {
+ uint32_t sdkVersion = 0;
+ if (MachOLinkingContext::parsePackedVersion(arg->getValue(),
+ sdkVersion)) {
+ diagnostics << "error: malformed sdkVersion value\n";
+ return false;
+ }
+ ctx.setSdkVersion(sdkVersion);
+ } else if (ctx.generateVersionLoadCommand()) {
+ // If we don't have an sdk version, but were going to emit a load command
+ // with min_version, then we need to give an warning as we have no sdk
+ // version to put in that command.
+ // FIXME: We need to decide whether to make this an error.
+ diagnostics << "warning: -sdk_version is required when emitting "
+ "min version load command. "
+ "Setting sdk version to match provided min version\n";
+ ctx.setSdkVersion(ctx.osMinVersion());
+ }
+
+ // Handle source_version
+ if (llvm::opt::Arg *arg = parsedArgs.getLastArg(OPT_source_version)) {
+ uint64_t version = 0;
+ if (MachOLinkingContext::parsePackedVersion(arg->getValue(),
+ version)) {
+ diagnostics << "error: malformed source_version value\n";
+ return false;
+ }
+ ctx.setSourceVersion(version);
+ }
+
// Handle stack_size
if (llvm::opt::Arg *stackSize = parsedArgs.getLastArg(OPT_stack_size)) {
uint64_t stackSizeVal;
@@ -794,6 +1014,10 @@ bool DarwinLdDriver::parse(llvm::ArrayRef<const char *> args,
ctx.setUndefinedMode(UndefMode);
}
+ // Handle -no_objc_category_merging.
+ if (parsedArgs.getLastArg(OPT_no_objc_category_merging))
+ ctx.setMergeObjCCategories(false);
+
// Handle -rpath <path>
if (parsedArgs.hasArg(OPT_rpath)) {
switch (ctx.outputMachOType()) {
@@ -829,7 +1053,7 @@ bool DarwinLdDriver::parse(llvm::ArrayRef<const char *> args,
// Handle input files and sectcreate.
for (auto &arg : parsedArgs) {
bool upward;
- ErrorOr<StringRef> resolvedPath = StringRef();
+ llvm::Optional<StringRef> resolvedPath;
switch (arg->getOption().getID()) {
default:
continue;
@@ -852,9 +1076,10 @@ bool DarwinLdDriver::parse(llvm::ArrayRef<const char *> args,
return false;
} else if (ctx.testingFileUsage()) {
diagnostics << "Found " << (upward ? "upward " : " ") << "library "
- << canonicalizePath(resolvedPath.get()) << '\n';
+ << canonicalizePath(resolvedPath.getValue()) << '\n';
}
- addFile(resolvedPath.get(), ctx, globalWholeArchive, upward, diagnostics);
+ addFile(resolvedPath.getValue(), ctx, globalWholeArchive,
+ upward, diagnostics);
break;
case OPT_framework:
case OPT_upward_framework:
@@ -866,17 +1091,20 @@ bool DarwinLdDriver::parse(llvm::ArrayRef<const char *> args,
return false;
} else if (ctx.testingFileUsage()) {
diagnostics << "Found " << (upward ? "upward " : " ") << "framework "
- << canonicalizePath(resolvedPath.get()) << '\n';
+ << canonicalizePath(resolvedPath.getValue()) << '\n';
}
- addFile(resolvedPath.get(), ctx, globalWholeArchive, upward, diagnostics);
+ addFile(resolvedPath.getValue(), 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";
+ if (auto ec = loadFileList(arg->getValue(),
+ ctx, globalWholeArchive,
+ diagnostics)) {
+ handleAllErrors(std::move(ec), [&](const llvm::ErrorInfoBase &EI) {
+ diagnostics << "error: ";
+ EI.log(diagnostics);
+ diagnostics << ", processing '-filelist " << arg->getValue() << "'\n";
+ });
return false;
}
break;
@@ -908,5 +1136,80 @@ bool DarwinLdDriver::parse(llvm::ArrayRef<const char *> args,
return ctx.validate(diagnostics);
}
+/// This is where the link is actually performed.
+bool link(llvm::ArrayRef<const char *> args, raw_ostream &diagnostics) {
+ MachOLinkingContext ctx;
+ if (!parse(args, ctx, diagnostics))
+ return false;
+ if (ctx.doNothing())
+ return true;
+ if (ctx.getNodes().empty())
+ return false;
+
+ for (std::unique_ptr<Node> &ie : ctx.getNodes())
+ if (FileNode *node = dyn_cast<FileNode>(ie.get()))
+ node->getFile()->parse();
+
+ std::vector<std::unique_ptr<File>> internalFiles;
+ ctx.createInternalFiles(internalFiles);
+ for (auto i = internalFiles.rbegin(), e = internalFiles.rend(); i != e; ++i) {
+ auto &members = ctx.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;
+ ctx.createImplicitFiles(implicitFiles);
+ for (auto i = implicitFiles.rbegin(), e = implicitFiles.rend(); i != e; ++i) {
+ auto &members = ctx.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.
+ ctx.finalizeInputFiles();
+ // Do core linking.
+ ScopedTask resolveTask(getDefaultDomain(), "Resolve");
+ Resolver resolver(ctx);
+ if (!resolver.resolve())
+ return false;
+ SimpleFile *merged = nullptr;
+ {
+ std::unique_ptr<SimpleFile> mergedFile = resolver.resultFile();
+ merged = mergedFile.get();
+ auto &members = ctx.getNodes();
+ members.insert(members.begin(),
+ llvm::make_unique<FileNode>(std::move(mergedFile)));
+ }
+ resolveTask.end();
+
+ // Run passes on linked atoms.
+ ScopedTask passTask(getDefaultDomain(), "Passes");
+ PassManager pm;
+ ctx.addPasses(pm);
+ if (auto ec = pm.runOnFile(*merged)) {
+ // FIXME: This should be passed to logAllUnhandledErrors but it needs
+ // to be passed a Twine instead of a string.
+ diagnostics << "Failed to run passes on file '" << ctx.outputPath()
+ << "': ";
+ logAllUnhandledErrors(std::move(ec), diagnostics, std::string());
+ return false;
+ }
+
+ passTask.end();
+
+ // Give linked atoms to Writer to generate output file.
+ ScopedTask writeTask(getDefaultDomain(), "Write");
+ if (auto ec = ctx.writeFile(*merged)) {
+ // FIXME: This should be passed to logAllUnhandledErrors but it needs
+ // to be passed a Twine instead of a string.
+ diagnostics << "Failed to write file '" << ctx.outputPath() << "': ";
+ logAllUnhandledErrors(std::move(ec), diagnostics, std::string());
+ return false;
+ }
+
+ return true;
+}
+} // namespace mach_o
} // namespace lld
diff --git a/lib/Driver/DarwinLdOptions.td b/lib/Driver/DarwinLdOptions.td
index cbf6ac1d4a4b..fa07f33646e7 100644
--- a/lib/Driver/DarwinLdOptions.td
+++ b/lib/Driver/DarwinLdOptions.td
@@ -33,6 +33,28 @@ def iphoneos_version_min : Separate<["-"], "iphoneos_version_min">,
def ios_simulator_version_min : Separate<["-"], "ios_simulator_version_min">,
MetaVarName<"<version>">,
HelpText<"Minimum iOS simulator version">, Group<grp_opts>;
+def sdk_version : Separate<["-"], "sdk_version">,
+ MetaVarName<"<version>">,
+ HelpText<"SDK version">, Group<grp_opts>;
+def source_version : Separate<["-"], "source_version">,
+ MetaVarName<"<version>">,
+ HelpText<"Source version">, Group<grp_opts>;
+def version_load_command : Flag<["-"], "version_load_command">,
+ HelpText<"Force generation of a version load command">, Group<grp_opts>;
+def no_version_load_command : Flag<["-"], "no_version_load_command">,
+ HelpText<"Disable generation of a version load command">, Group<grp_opts>;
+def function_starts : Flag<["-"], "function_starts">,
+ HelpText<"Force generation of a function starts load command">,
+ Group<grp_opts>;
+def no_function_starts : Flag<["-"], "no_function_starts">,
+ HelpText<"Disable generation of a function starts load command">,
+ Group<grp_opts>;
+def data_in_code_info : Flag<["-"], "data_in_code_info">,
+ HelpText<"Force generation of a data in code load command">,
+ Group<grp_opts>;
+def no_data_in_code_info : Flag<["-"], "no_data_in_code_info">,
+ HelpText<"Disable generation of a data in code load command">,
+ Group<grp_opts>;
def mllvm : Separate<["-"], "mllvm">,
MetaVarName<"<option>">,
HelpText<"Options to pass to LLVM during LTO">, Group<grp_opts>;
@@ -68,6 +90,10 @@ def undefined : Separate<["-"], "undefined">,
MetaVarName<"<undefined>">,
HelpText<"Determines how undefined symbols are handled.">,
Group<grp_opts>;
+def no_objc_category_merging : Flag<["-"], "no_objc_category_merging">,
+ HelpText<"Disables the optimisation which merges Objective-C categories "
+ "on a class in to the class itself.">,
+ Group<grp_opts>;
// main executable options
def grp_main : OptionGroup<"opts">, HelpText<"MAIN EXECUTABLE OPTIONS">;
@@ -84,6 +110,9 @@ def stack_size : Separate<["-"], "stack_size">,
HelpText<"Specifies the maximum stack size for the main thread in a program. "
"Must be a page-size multiple. (default=8Mb)">,
Group<grp_main>;
+def export_dynamic : Flag<["-"], "export_dynamic">,
+ HelpText<"Preserves all global symbols in main executables during LTO">,
+ Group<grp_main>;
// dylib executable options
def grp_dylib : OptionGroup<"opts">, HelpText<"DYLIB EXECUTABLE OPTIONS">;
@@ -205,3 +234,9 @@ 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>;
+def objc_gc_compaction : Flag<["-"], "objc_gc_compaction">,
+ HelpText<"Unsupported ObjC GC option">, Group<grp_obsolete>;
+def objc_gc : Flag<["-"], "objc_gc">,
+ HelpText<"Unsupported ObjC GC option">, Group<grp_obsolete>;
+def objc_gc_only : Flag<["-"], "objc_gc_only">,
+ HelpText<"Unsupported ObjC GC option">, Group<grp_obsolete>;
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
deleted file mode 100644
index 6a7a26b3b0f6..000000000000
--- a/lib/Driver/Driver.cpp
+++ /dev/null
@@ -1,142 +0,0 @@
-//===- lib/Driver/Driver.cpp - Linker Driver Emulator -----------*- C++ -*-===//
-//
-// 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(std::unique_ptr<File> file) {
- std::vector<std::unique_ptr<File>> members;
- 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);
- ErrorOr<std::unique_ptr<File>> fileOrErr =
- ctx.registry().loadFile(std::move(mb.get()));
- if (std::error_code ec = fileOrErr.getError())
- return makeErrorFile(path, ec);
- std::unique_ptr<File> &file = fileOrErr.get();
- if (wholeArchive)
- return parseMemberFiles(std::move(file));
- std::vector<std::unique_ptr<File>> files;
- files.push_back(std::move(file));
- return files;
-}
-
-void Driver::parseLLVMOptions(const LinkingContext &ctx) {
- // Honor -mllvm
- if (!ctx.llvmOptions().empty()) {
- unsigned numArgs = ctx.llvmOptions().size();
- auto **args = new const char *[numArgs + 2];
- args[0] = "lld (LLVM option parsing)";
- for (unsigned i = 0; i != numArgs; ++i)
- args[i + 1] = ctx.llvmOptions()[i];
- args[numArgs + 1] = nullptr;
- llvm::cl::ParseCommandLineOptions(numArgs + 1, args);
- }
-}
-
-/// This is where the link is actually performed.
-bool Driver::link(LinkingContext &ctx, raw_ostream &diagnostics) {
- if (ctx.getNodes().empty())
- return false;
-
- for (std::unique_ptr<Node> &ie : ctx.getNodes())
- if (FileNode *node = dyn_cast<FileNode>(ie.get()))
- ctx.getTaskGroup().spawn([node] { node->getFile()->parse(); });
-
- std::vector<std::unique_ptr<File>> internalFiles;
- ctx.createInternalFiles(internalFiles);
- for (auto i = internalFiles.rbegin(), e = internalFiles.rend(); i != e; ++i) {
- auto &members = ctx.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;
- ctx.createImplicitFiles(implicitFiles);
- for (auto i = implicitFiles.rbegin(), e = implicitFiles.rend(); i != e; ++i) {
- auto &members = ctx.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.
- ctx.finalizeInputFiles();
-
- // Do core linking.
- ScopedTask resolveTask(getDefaultDomain(), "Resolve");
- Resolver resolver(ctx);
- if (!resolver.resolve()) {
- ctx.getTaskGroup().sync();
- return false;
- }
- std::unique_ptr<SimpleFile> merged = resolver.resultFile();
- resolveTask.end();
-
- // Run passes on linked atoms.
- ScopedTask passTask(getDefaultDomain(), "Passes");
- PassManager pm;
- ctx.addPasses(pm);
- if (std::error_code ec = pm.runOnFile(*merged)) {
- diagnostics << "Failed to write file '" << ctx.outputPath()
- << "': " << ec.message() << "\n";
- return false;
- }
-
- passTask.end();
-
- // Give linked atoms to Writer to generate output file.
- ScopedTask writeTask(getDefaultDomain(), "Write");
- if (std::error_code ec = ctx.writeFile(*merged)) {
- diagnostics << "Failed to write file '" << ctx.outputPath()
- << "': " << ec.message() << "\n";
- return false;
- }
-
- return true;
-}
-
-} // namespace lld
diff --git a/lib/Driver/GnuLdDriver.cpp b/lib/Driver/GnuLdDriver.cpp
deleted file mode 100644
index 1cff481dd8d7..000000000000
--- a/lib/Driver/GnuLdDriver.cpp
+++ /dev/null
@@ -1,782 +0,0 @@
-//===- 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/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/StringSaver.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){}
-};
-
-} // 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 llvm::ArrayRef<const char *>
-maybeExpandResponseFiles(llvm::ArrayRef<const char *> args,
- BumpPtrAllocator &alloc) {
- // Expand response files.
- SmallVector<const char *, 256> smallvec;
- for (const char *arg : args)
- smallvec.push_back(arg);
- llvm::StringSaver saver(alloc);
- llvm::cl::ExpandResponseFiles(saver, llvm::cl::TokenizeGNUCommandLine, smallvec);
-
- // Pack the results to a C-array and return it.
- const char **copy = alloc.Allocate<const char *>(smallvec.size() + 1);
- std::copy(smallvec.begin(), smallvec.end(), copy);
- copy[smallvec.size()] = nullptr;
- return llvm::makeArrayRef(copy, smallvec.size() + 1);
-}
-
-// 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(llvm::ArrayRef<const char *> args,
- raw_ostream &diag) {
- BumpPtrAllocator alloc;
- args = maybeExpandResponseFiles(args, alloc);
- std::unique_ptr<ELFLinkingContext> options;
- if (!parse(args, 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::mips:
- case llvm::Triple::mipsel:
- case llvm::Triple::mips64:
- case llvm::Triple::mips64el:
- return llvm::StringSwitch<llvm::Optional<llvm::Triple::ArchType>>(value)
- .Cases("elf32btsmip", "elf32btsmipn32", llvm::Triple::mips)
- .Cases("elf32ltsmip", "elf32ltsmipn32", llvm::Triple::mipsel)
- .Case("elf64btsmip", llvm::Triple::mips64)
- .Case("elf64ltsmip", llvm::Triple::mips64el)
- .Default(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;
- if (std::error_code ec = llvm::sys::fs::identify_magic(path, magic)) {
- diag << "unknown input file format: " << path << ": "
- << ec.message() << "\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;
- if ((p = elf::createAArch64LinkingContext(triple))) return p;
- if ((p = elf::createARMLinkingContext(triple))) return p;
- if ((p = elf::createExampleLinkingContext(triple))) return p;
- if ((p = elf::createHexagonLinkingContext(triple))) return p;
- if ((p = elf::createMipsLinkingContext(triple))) return p;
- if ((p = elf::createX86LinkingContext(triple))) return p;
- if ((p = elf::createX86_64LinkingContext(triple))) return p;
- 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(llvm::ArrayRef<const char *> args,
- std::unique_ptr<ELFLinkingContext> &context,
- raw_ostream &diag) {
- // Parse command line options using GnuLdOptions.td
- GnuLdOptTable table;
- unsigned missingIndex;
- unsigned missingCount;
-
- llvm::opt::InputArgList parsedArgs =
- table.ParseArgs(args.slice(1), 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(), args[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(args[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_discard_loc))
- ctx->setDiscardLocals(true);
-
- if (parsedArgs.hasArg(OPT_discard_temp_loc))
- ctx->setDiscardTempLocals(true);
-
- 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());
-
- // Process ELF/ARM specific options
- bool hasArmTarget1Rel = parsedArgs.hasArg(OPT_target1_rel);
- bool hasArmTarget1Abs = parsedArgs.hasArg(OPT_target1_abs);
- if (triple.getArch() == llvm::Triple::arm) {
- if (hasArmTarget1Rel && hasArmTarget1Abs) {
- diag << "error: options --target1-rel and --target1-abs"
- " can't be used together.\n";
- return false;
- } else if (hasArmTarget1Rel || hasArmTarget1Abs) {
- ctx->setArmTarget1Rel(hasArmTarget1Rel && !hasArmTarget1Abs);
- }
- } else {
- for (const auto *arg : parsedArgs.filtered(OPT_grp_arm_targetopts)) {
- diag << "warning: ignoring unsupported ARM/ELF specific argument: "
- << arg->getSpelling() << "\n";
- }
- }
-
- // Process MIPS specific options.
- if (triple.getArch() == llvm::Triple::mips ||
- triple.getArch() == llvm::Triple::mipsel ||
- triple.getArch() == llvm::Triple::mips64 ||
- triple.getArch() == llvm::Triple::mips64el) {
- ctx->setMipsPcRelEhRel(parsedArgs.hasArg(OPT_pcrel_eh_reloc));
- auto *hashArg = parsedArgs.getLastArg(OPT_hash_style);
- if (hashArg && hashArg->getValue() != StringRef("sysv")) {
- diag << "error: .gnu.hash is incompatible with the MIPS ABI\n";
- return false;
- }
- }
- else {
- for (const auto *arg : parsedArgs.filtered(OPT_grp_mips_targetopts)) {
- diag << "warning: ignoring unsupported MIPS specific argument: "
- << arg->getSpelling() << "\n";
- }
- }
-
- 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 == "now")
- ctx->setDTFlag(ELFLinkingContext::DTFlag::DT_NOW);
- else if (opt == "origin")
- ctx->setDTFlag(ELFLinkingContext::DTFlag::DT_ORIGIN);
- 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);
- }
-
- // Enable new dynamic tags.
- if (parsedArgs.hasArg(OPT_enable_newdtags))
- ctx->setEnableNewDtags(true);
-
- // 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();
- if (ctx->allowLinkWithDynamicLibraries())
- ctx->registry().addSupportELFDynamicSharedObjects(*ctx);
-
- // Parse the LLVM options before we process files in case the file handling
- // makes use of things like DEBUG().
- parseLLVMOptions(*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;
- default:
- ctx->setOutputPath("a.out");
- break;
- }
- }
-
- // Validate the combination of options used.
- if (!ctx->validate(diag))
- return false;
-
- // Perform linker script semantic actions
- if (auto ec = ctx->linkerScriptSema().perform()) {
- diag << "Error in the linker script's semantics: " << ec.message() << "\n";
- return false;
- }
-
- 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
deleted file mode 100644
index 7d850d4d002e..000000000000
--- a/lib/Driver/GnuLdOptions.td
+++ /dev/null
@@ -1,378 +0,0 @@
-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)>;
-}
-
-// Support --<option>,--<option>=
-multiclass mDashEq<string opt1, string help> {
- // Option
- def "" : Separate<["--"], opt1>, HelpText<help>;
- // Compatibility aliases
- def opt2_eq : Joined<["--"], opt1#"=">,
- 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 : JoinedOrSeparate<["-"], "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>;
-defm defsym : mDashEq<"defsym",
- "Create a global symbol in the output file "
- "containing the absolute address given by expression">,
- MetaVarName<"symbol=<expression>">,
- Group<grp_resolveropt>;
-
-//===----------------------------------------------------------------------===//
-/// Custom Options
-//===----------------------------------------------------------------------===//
-def grp_customopts : OptionGroup<"opts">,
- HelpText<"CUSTOM OPTIONS">;
-def disable_newdtags: Flag<["--"], "disable-new-dtags">,
- HelpText<"Disable new dynamic tags">,
- Group<grp_customopts>;
-def enable_newdtags: Flag<["--"], "enable-new-dtags">,
- HelpText<"Enable new dynamic tags">,
- Group<grp_customopts>;
-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 discard_loc : Flag<["--"], "discard-all">,
- HelpText<"Discard all local symbols">,
- Group<grp_symbolopts>;
-def alias_discard_loc: Flag<["-"], "x">,
- Alias<discard_loc>;
-def discard_temp_loc : Flag<["--"], "discard-locals">,
- HelpText<"Discard temporary local symbols">,
- Group<grp_symbolopts>;
-def alias_discard_temp_loc : Flag<["-"], "X">,
- Alias<discard_temp_loc>;
-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 yaml to create an output in YAML format">,
- Group<grp_extns>;
-def alias_output_filetype: Joined<["--"], "output-filetype=">,
- Alias<output_filetype>;
-
-//===----------------------------------------------------------------------===//
-/// Target Specific Options
-//===----------------------------------------------------------------------===//
-def grp_targetopts : OptionGroup<"opts">,
- HelpText<"ARCH SPECIFIC OPTIONS">;
-
-//===----------------------------------------------------------------------===//
-/// ARM Target Specific Options
-//===----------------------------------------------------------------------===//
-def grp_arm_targetopts : OptionGroup<"ARM SPECIFIC OPTIONS">,
- Group<grp_targetopts>;
-def target1_rel : Flag<["--"], "target1-rel">,
- Group<grp_arm_targetopts>, HelpText<"Interpret R_ARM_TARGET1 as R_ARM_REL32">;
-def target1_abs : Flag<["--"], "target1-abs">,
- Group<grp_arm_targetopts>, HelpText<"Interpret R_ARM_TARGET1 as R_ARM_ABS32">;
-
-//===----------------------------------------------------------------------===//
-/// MIPS Target Specific Options
-//===----------------------------------------------------------------------===//
-def grp_mips_targetopts : OptionGroup<"MIPS SPECIFIC OPTIONS">,
- Group<grp_targetopts>;
-def pcrel_eh_reloc : Flag<["-", "--"], "pcrel-eh-reloc">,
- Group<grp_mips_targetopts>,
- HelpText<"Interpret R_MIPS_EH as R_MIPS_PC32">;
-
-//===----------------------------------------------------------------------===//
-/// 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>;
-def G : Separate<["-"], "G">,
- HelpText<"Ignored for MIPS GNU Linker Compatibility">,
- Group<grp_ignored>;
-
-//===----------------------------------------------------------------------===//
-/// Help
-//===----------------------------------------------------------------------===//
-def help : Flag<["--"], "help">,
- HelpText<"Display this help message">;
diff --git a/lib/Driver/TODO.rst b/lib/Driver/TODO.rst
deleted file mode 100644
index 868eaf02290c..000000000000
--- a/lib/Driver/TODO.rst
+++ /dev/null
@@ -1,99 +0,0 @@
-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
-* -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
deleted file mode 100644
index 3dea7ebfae89..000000000000
--- a/lib/Driver/UniversalDriver.cpp
+++ /dev/null
@@ -1,225 +0,0 @@
-//===- 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) {}
-};
-
-enum class Flavor {
- invalid,
- old_gnu_ld, // -flavor old-gnu
- 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("old-gnu", Flavor::old_gnu_ld)
- .Case("gnu", Flavor::gnu_ld)
- .Case("ld.lld", 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,
- llvm::MutableArrayRef<const char *> &args) {
- unsigned int numToRemove = arg->getNumValues() + 1;
- auto sub = args.slice(arg->getIndex() + 1);
- std::rotate(sub.begin(), sub.begin() + numToRemove, sub.end());
- args = args.drop_back(numToRemove);
-}
-
-static Flavor getFlavor(llvm::MutableArrayRef<const char *> &args,
- const llvm::opt::InputArgList &parsedArgs) {
- if (llvm::opt::Arg *argCore = parsedArgs.getLastArg(OPT_core)) {
- removeArg(argCore, args);
- return Flavor::core;
- }
- if (llvm::opt::Arg *argFlavor = parsedArgs.getLastArg(OPT_flavor)) {
- removeArg(argFlavor, args);
- return strToFlavor(argFlavor->getValue());
- }
-
-#if LLVM_ON_UNIX
- if (llvm::sys::path::filename(args[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::filename(args[0]);
- if (name.endswith_lower(".exe"))
- name = llvm::sys::path::stem(name);
- return strToFlavor(parseProgramName(name)._flavor);
-}
-
-namespace lld {
-
-bool UniversalDriver::link(llvm::MutableArrayRef<const char *> args,
- raw_ostream &diagnostics) {
- // Parse command line options using GnuLdOptions.td
- UniversalDriverOptTable table;
- unsigned missingIndex;
- unsigned missingCount;
-
- // Program name
- StringRef programName = llvm::sys::path::stem(args[0]);
-
- llvm::opt::InputArgList parsedArgs =
- table.ParseArgs(args.slice(1), 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(args, parsedArgs);
-
- // Switch to appropriate driver.
- switch (flavor) {
- case Flavor::old_gnu_ld:
- return GnuLdDriver::linkELF(args, diagnostics);
- case Flavor::gnu_ld:
- elf2::link(args);
- return true;
- case Flavor::darwin_ld:
- return DarwinLdDriver::linkMachO(args, diagnostics);
- case Flavor::win_link:
- coff::link(args);
- return true;
- case Flavor::core:
- return CoreDriver::link(args, 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
deleted file mode 100644
index 14abc9ce9911..000000000000
--- a/lib/Driver/UniversalDriverOptions.td
+++ /dev/null
@@ -1,19 +0,0 @@
-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/ReaderWriter/CMakeLists.txt b/lib/ReaderWriter/CMakeLists.txt
index 2bb5655b9e35..4408d9c18b8b 100644
--- a/lib/ReaderWriter/CMakeLists.txt
+++ b/lib/ReaderWriter/CMakeLists.txt
@@ -1,4 +1,3 @@
-add_subdirectory(ELF)
add_subdirectory(MachO)
add_subdirectory(YAML)
@@ -7,9 +6,7 @@ if (MSVC)
endif()
add_lld_library(lldReaderWriter
- CoreLinkingContext.cpp
FileArchive.cpp
- LinkerScript.cpp
ADDITIONAL_HEADER_DIRS
${LLD_INCLUDE_DIR}/lld/ReaderWriter
diff --git a/lib/ReaderWriter/CoreLinkingContext.cpp b/lib/ReaderWriter/CoreLinkingContext.cpp
deleted file mode 100644
index 02f6263c0c3f..000000000000
--- a/lib/ReaderWriter/CoreLinkingContext.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-//===- 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"
-#include "llvm/ADT/STLExtras.h"
-
-using namespace lld;
-
-namespace {
-
-class OrderPass : public Pass {
-public:
- /// Sorts atoms by position
- std::error_code perform(SimpleFile &file) override {
- SimpleFile::DefinedAtomRange defined = file.definedAtoms();
- std::sort(defined.begin(), defined.end(), DefinedAtom::compareByPosition);
- return std::error_code();
- }
-};
-
-} // anonymous namespace
-
-CoreLinkingContext::CoreLinkingContext() {}
-
-bool CoreLinkingContext::validateImpl(raw_ostream &) {
- _writer = createWriterYAML(*this);
- return true;
-}
-
-void CoreLinkingContext::addPasses(PassManager &pm) {
- for (StringRef name : _passNames) {
- (void)name;
- assert(name == "order" && "bad pass name");
- pm.add(llvm::make_unique<OrderPass>());
- }
-}
-
-Writer &CoreLinkingContext::writer() const { return *_writer; }
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64DynamicLibraryWriter.h b/lib/ReaderWriter/ELF/AArch64/AArch64DynamicLibraryWriter.h
deleted file mode 100644
index 73864d2b4c38..000000000000
--- a/lib/ReaderWriter/ELF/AArch64/AArch64DynamicLibraryWriter.h
+++ /dev/null
@@ -1,45 +0,0 @@
-//===- 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 {
-
-class AArch64DynamicLibraryWriter : public DynamicLibraryWriter<ELF64LE> {
-public:
- AArch64DynamicLibraryWriter(AArch64LinkingContext &ctx,
- TargetLayout<ELF64LE> &layout);
-
-protected:
- // Add any runtime files and their atoms to the output
- void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
-};
-
-AArch64DynamicLibraryWriter::AArch64DynamicLibraryWriter(
- AArch64LinkingContext &ctx, TargetLayout<ELF64LE> &layout)
- : DynamicLibraryWriter(ctx, layout) {}
-
-void AArch64DynamicLibraryWriter::createImplicitFiles(
- std::vector<std::unique_ptr<File>> &result) {
- DynamicLibraryWriter::createImplicitFiles(result);
- auto gotFile = llvm::make_unique<SimpleFile>("GOTFile");
- gotFile->addAtom(*new (gotFile->allocator()) GlobalOffsetTableAtom(*gotFile));
- gotFile->addAtom(*new (gotFile->allocator()) DynamicAtom(*gotFile));
- result.push_back(std::move(gotFile));
-}
-
-} // namespace elf
-} // namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.cpp b/lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.cpp
deleted file mode 100644
index 9a9ec6cba12b..000000000000
--- a/lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-//===- lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.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 "AArch64ExecutableWriter.h"
-#include "AArch64TargetHandler.h"
-#include "AArch64SectionChunks.h"
-
-namespace lld {
-namespace elf {
-
-AArch64ExecutableWriter::AArch64ExecutableWriter(AArch64LinkingContext &ctx,
- AArch64TargetLayout &layout)
- : ExecutableWriter(ctx, layout), _targetLayout(layout) {}
-
-void AArch64ExecutableWriter::createImplicitFiles(
- std::vector<std::unique_ptr<File>> &result) {
- ExecutableWriter::createImplicitFiles(result);
- auto gotFile = llvm::make_unique<SimpleFile>("GOTFile");
- gotFile->addAtom(*new (gotFile->allocator()) GlobalOffsetTableAtom(*gotFile));
- if (this->_ctx.isDynamic())
- gotFile->addAtom(*new (gotFile->allocator()) DynamicAtom(*gotFile));
- result.push_back(std::move(gotFile));
-}
-
-void AArch64ExecutableWriter::buildDynamicSymbolTable(const File &file) {
- for (auto sec : this->_layout.sections()) {
- if (auto section = dyn_cast<AtomSection<ELF64LE>>(sec)) {
- for (const auto &atom : section->atoms()) {
- // Add all globals GOT symbols (in both .got and .got.plt sections)
- // on dynamic symbol table.
- for (const auto &section : _targetLayout.getGOTSections()) {
- if (section->hasGlobalGOTEntry(atom->_atom))
- _dynamicSymbolTable->addSymbol(atom->_atom, section->ordinal(),
- atom->_virtualAddr, atom);
- }
- }
- }
- }
-
- ExecutableWriter<ELF64LE>::buildDynamicSymbolTable(file);
-}
-
-} // namespace elf
-} // namespace lld
-
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.h b/lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.h
deleted file mode 100644
index eef825040ffa..000000000000
--- a/lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.h
+++ /dev/null
@@ -1,38 +0,0 @@
-//===- lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.h -------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef AARCH64_EXECUTABLE_WRITER_H
-#define AARCH64_EXECUTABLE_WRITER_H
-
-#include "ExecutableWriter.h"
-
-namespace lld {
-namespace elf {
-
-class AArch64TargetLayout;
-class AArch64LinkingContext;
-
-class AArch64ExecutableWriter : public ExecutableWriter<ELF64LE> {
-public:
- AArch64ExecutableWriter(AArch64LinkingContext &ctx,
- AArch64TargetLayout &layout);
-
-protected:
- // Add any runtime files and their atoms to the output
- void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
-
- void buildDynamicSymbolTable(const File &file) override;
-
-private:
- AArch64TargetLayout &_targetLayout;
-};
-
-} // namespace elf
-} // namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.cpp b/lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.cpp
deleted file mode 100644
index ba883f7f59db..000000000000
--- a/lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-//===- 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;
-using namespace lld::elf;
-
-std::unique_ptr<ELFLinkingContext>
-elf::createAArch64LinkingContext(llvm::Triple triple) {
- if (triple.getArch() == llvm::Triple::aarch64)
- return llvm::make_unique<AArch64LinkingContext>(triple);
- return nullptr;
-}
-
-AArch64LinkingContext::AArch64LinkingContext(llvm::Triple triple)
- : ELFLinkingContext(triple, std::unique_ptr<TargetHandler>(
- new AArch64TargetHandler(*this))) {}
-
-void AArch64LinkingContext::addPasses(PassManager &pm) {
- auto pass = createAArch64RelocationPass(*this);
- if (pass)
- pm.add(std::move(pass));
- ELFLinkingContext::addPasses(pm);
-}
-
-static const Registry::KindStrings kindStrings[] = {
-#define ELF_RELOC(name, value) LLD_KIND_STRING_ENTRY(name),
-#include "llvm/Support/ELFRelocs/AArch64.def"
-#undef ELF_RELOC
- LLD_KIND_STRING_END
-};
-
-void AArch64LinkingContext::registerRelocationNames(Registry &registry) {
- registry.addKindTable(Reference::KindNamespace::ELF,
- Reference::KindArch::AArch64, kindStrings);
-}
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.h b/lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.h
deleted file mode 100644
index 25a173158318..000000000000
--- a/lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.h
+++ /dev/null
@@ -1,101 +0,0 @@
-//===- 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:
- int getMachineType() const override { return llvm::ELF::EM_AARCH64; }
- AArch64LinkingContext(llvm::Triple);
-
- void addPasses(PassManager &) override;
- void registerRelocationNames(Registry &r) 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;
- }
- }
-
- /// \brief The path to the dynamic interpreter
- StringRef getDefaultInterpreter() const override {
- return "/lib/ld-linux-aarch64.so.1";
- }
-};
-} // end namespace elf
-} // end namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.cpp b/lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.cpp
deleted file mode 100644
index ac7c769ec26d..000000000000
--- a/lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.cpp
+++ /dev/null
@@ -1,556 +0,0 @@
-//===- 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"
-
-#define DEBUG_TYPE "AArch64"
-
-using namespace lld;
-using namespace lld::elf;
-using namespace llvm;
-using namespace llvm::support::endian;
-
-static int64_t page(int64_t v) { return v & ~int64_t(0xFFF); }
-
-/// \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(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_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(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_ABS16 - word16: S + A
-static std::error_code relocR_AARCH64_ABS16(uint8_t *location, uint64_t P,
- uint64_t S, int64_t A) {
- int64_t result = S + A;
- if (!withinSignedUnsignedRange(result, 16))
- return make_out_of_range_reloc_error();
- DEBUG(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");
- write16le(location, result | read16le(location));
- return std::error_code();
-}
-
-/// \brief R_AARCH64_PREL64 - word64: S + A - P
-static void relocR_AARCH64_PREL64(uint8_t *location, uint64_t P,
- uint64_t S, int64_t A) {
- int64_t result = S + A - P;
- DEBUG(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 std::error_code relocR_AARCH64_PREL32(uint8_t *location, uint64_t P,
- uint64_t S, int64_t A) {
- int64_t result = S + A - P;
- // ELF for the ARM 64-bit architecture manual states the overflow
- // for R_AARCH64_PREL32 to be -2^(-31) <= X < 2^32
- if (!withinSignedUnsignedRange(result, 32))
- return make_out_of_range_reloc_error();
- DEBUG(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_PREL16 - word16: S + A - P
-static std::error_code relocR_AARCH64_PREL16(uint8_t *location, uint64_t P,
- uint64_t S, int64_t A) {
- int64_t result = S + A - P;
- if (!withinSignedUnsignedRange(result, 16))
- return make_out_of_range_reloc_error();
- DEBUG(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");
- write16le(location, result + read16le(location));
- return std::error_code();
-}
-
-/// \brief R_AARCH64_ADR_PREL_PG_HI21 - Page(S+A) - Page(P)
-static std::error_code relocR_AARCH64_ADR_PREL_PG_HI21(uint8_t *location,
- uint64_t P, uint64_t S,
- int64_t A) {
- int64_t result = page(S + A) - page(P);
- if (!isInt<32>(result))
- return make_out_of_range_reloc_error();
- result = result >> 12;
- uint32_t immlo = result & 0x3;
- uint32_t immhi = result & 0x1FFFFC;
- immlo = immlo << 29;
- immhi = immhi << 3;
- DEBUG(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));
- return std::error_code();
-}
-
-/// \brief R_AARCH64_ADR_PREL_LO21 - S + A - P
-static std::error_code relocR_AARCH64_ADR_PREL_LO21(uint8_t *location, uint64_t P,
- uint64_t S, int64_t A) {
- uint64_t result = S + A - P;
- if (!isInt<20>(result))
- return make_out_of_range_reloc_error();
- uint32_t immlo = result & 0x3;
- uint32_t immhi = result & 0x1FFFFC;
- immlo = immlo << 29;
- immhi = immhi << 3;
- DEBUG(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));
- return std::error_code();
-}
-
-/// \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(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_CALL26 and R_AARCH64_JUMP26
-static std::error_code relocJump26(uint8_t *location, uint64_t P, uint64_t S,
- int64_t A) {
- int64_t result = S + A - P;
- if (!isInt<27>(result))
- return make_out_of_range_reloc_error();
- result &= 0x0FFFFFFC;
- result >>= 2;
- DEBUG(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));
- return std::error_code();
-}
-
-/// \brief R_AARCH64_CONDBR19
-static std::error_code relocR_AARCH64_CONDBR19(uint8_t *location, uint64_t P,
- uint64_t S, int64_t A) {
- int64_t result = S + A - P;
- if (!isInt<20>(result))
- return make_out_of_range_reloc_error();
- result &= 0x01FFFFC;
- result <<= 3;
- DEBUG(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));
- return std::error_code();
-}
-
-/// \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(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(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(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(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(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 std::error_code 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);
- if (!isInt<32>(result))
- return make_out_of_range_reloc_error();
- result = (result >> 12) & 0x3FFFF;
- uint32_t immlo = result & 0x3;
- uint32_t immhi = result & 0x1FFFFC;
- immlo = immlo << 29;
- immhi = immhi << 3;
- DEBUG(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));
- return std::error_code();
-}
-
-// R_AARCH64_LD64_GOT_LO12_NC
-static std::error_code relocR_AARCH64_LD64_GOT_LO12_NC(uint8_t *location,
- uint64_t P, uint64_t S,
- int64_t A) {
- int32_t result = S + A;
- DEBUG(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");
- if ((result & 0x7) != 0)
- return make_unaligned_range_reloc_error();
- result &= 0xFF8;
- result <<= 7;
- write32le(location, result | read32le(location));
- return std::error_code();
-}
-
-// 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(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 std::error_code 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);
- if (!isInt<32>(result))
- return make_out_of_range_reloc_error();
- result >>= 12;
- uint32_t immlo = result & 0x3;
- uint32_t immhi = result & 0x1FFFFC;
- immlo = immlo << 29;
- immhi = immhi << 3;
- DEBUG(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));
- return std::error_code();
-}
-
-// 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(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 std::error_code relocR_AARCH64_TLSLE_ADD_TPREL_HI12(uint8_t *location,
- uint64_t P,
- uint64_t S,
- int64_t A) {
- int64_t result = S + A;
- if (!isUInt<24>(result))
- return make_out_of_range_reloc_error();
- result &= 0x0FFF000;
- result >>= 2;
- DEBUG(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));
- return std::error_code();
-}
-
-/// \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(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_TLSDESC_ADR_PAGE21 - Page(G(GTLSDESC(S+A))) - Page(P)
-static std::error_code relocR_AARCH64_TLSDESC_ADR_PAGE21(uint8_t *location,
- uint64_t P, uint64_t S,
- int64_t A) {
- int64_t result = page(S + A) - page(P);
- if (!isInt<32>(result))
- return make_out_of_range_reloc_error();
- result = result >> 12;
- uint32_t immlo = result & 0x3;
- uint32_t immhi = result & 0x1FFFFC;
- immlo = immlo << 29;
- immhi = immhi << 3;
- DEBUG(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));
- return std::error_code();
-}
-
-/// \brief R_AARCH64_TLSDESC_LD64_LO12_NC - G(GTLSDESC(S+A)) -> S + A
-static std::error_code relocR_AARCH64_TLSDESC_LD64_LO12_NC(uint8_t *location,
- uint64_t P,
- uint64_t S,
- int64_t A) {
- int32_t result = S + A;
- DEBUG(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");
- if ((result & 0x7) != 0)
- return make_unaligned_range_reloc_error();
- result &= 0xFF8;
- result <<= 7;
- write32le(location, result | read32le(location));
- return std::error_code();
-}
-
-/// \brief R_AARCH64_TLSDESC_ADD_LO12_NC - G(GTLSDESC(S+A)) -> S + A
-static void relocR_AARCH64_TLSDESC_ADD_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(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 AtomLayout &atom,
- const Reference &ref) const {
- uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset;
- uint8_t *loc = atomContent + ref.offsetInAtom();
- uint64_t target = writer.addressOfAtom(ref.target());
- uint64_t reloc = atom._virtualAddr + ref.offsetInAtom();
- int64_t addend = ref.addend();
-
- 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(loc, reloc, target, addend);
- break;
- case R_AARCH64_ABS32:
- return relocR_AARCH64_ABS32(loc, reloc, target, addend);
- case R_AARCH64_ABS16:
- return relocR_AARCH64_ABS16(loc, reloc, target, addend);
- case R_AARCH64_PREL64:
- relocR_AARCH64_PREL64(loc, reloc, target, addend);
- break;
- case R_AARCH64_PREL32:
- return relocR_AARCH64_PREL32(loc, reloc, target, addend);
- case R_AARCH64_PREL16:
- return relocR_AARCH64_PREL16(loc, reloc, target, addend);
- case R_AARCH64_ADR_PREL_PG_HI21:
- return relocR_AARCH64_ADR_PREL_PG_HI21(loc, reloc, target, addend);
- case R_AARCH64_ADR_PREL_LO21:
- return relocR_AARCH64_ADR_PREL_LO21(loc, reloc, target, addend);
- case R_AARCH64_ADD_ABS_LO12_NC:
- relocR_AARCH64_ADD_ABS_LO12_NC(loc, reloc, target, addend);
- break;
- case R_AARCH64_CALL26:
- case R_AARCH64_JUMP26:
- return relocJump26(loc, reloc, target, addend);
- case R_AARCH64_CONDBR19:
- return relocR_AARCH64_CONDBR19(loc, reloc, target, addend);
- case R_AARCH64_ADR_GOT_PAGE:
- return relocR_AARCH64_ADR_GOT_PAGE(loc, reloc, target, addend);
- case R_AARCH64_LD64_GOT_LO12_NC:
- return relocR_AARCH64_LD64_GOT_LO12_NC(loc, reloc, target, addend);
- case R_AARCH64_LDST8_ABS_LO12_NC:
- relocR_AARCH64_LDST8_ABS_LO12_NC(loc, reloc, target, addend);
- break;
- case R_AARCH64_LDST16_ABS_LO12_NC:
- relocR_AARCH64_LDST16_ABS_LO12_NC(loc, reloc, target, addend);
- break;
- case R_AARCH64_LDST32_ABS_LO12_NC:
- relocR_AARCH64_LDST32_ABS_LO12_NC(loc, reloc, target, addend);
- break;
- case R_AARCH64_LDST64_ABS_LO12_NC:
- relocR_AARCH64_LDST64_ABS_LO12_NC(loc, reloc, target, addend);
- break;
- case R_AARCH64_LDST128_ABS_LO12_NC:
- relocR_AARCH64_LDST128_ABS_LO12_NC(loc, reloc, target, addend);
- break;
- case ADD_AARCH64_GOTRELINDEX:
- relocADD_AARCH64_GOTRELINDEX(loc, reloc, target, addend);
- break;
- case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
- return relocR_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21(loc, reloc, target, addend);
- case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
- relocR_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC(loc, reloc, target, addend);
- break;
- case R_AARCH64_TLSLE_ADD_TPREL_HI12:
- case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: {
- auto tpoffset = _layout.getTPOffset();
- if (ref.kindValue() == R_AARCH64_TLSLE_ADD_TPREL_HI12)
- return relocR_AARCH64_TLSLE_ADD_TPREL_HI12(loc, reloc, target + tpoffset,
- addend);
- else
- relocR_AARCH64_TLSLE_ADD_TPREL_LO12_NC(loc, reloc, target + tpoffset,
- addend);
- } break;
- case R_AARCH64_TLSDESC_ADR_PAGE21:
- return relocR_AARCH64_TLSDESC_ADR_PAGE21(loc, reloc, target, addend);
- case R_AARCH64_TLSDESC_LD64_LO12_NC:
- return relocR_AARCH64_TLSDESC_LD64_LO12_NC(loc, reloc, target, addend);
- case R_AARCH64_TLSDESC_ADD_LO12_NC:
- relocR_AARCH64_TLSDESC_ADD_LO12_NC(loc, reloc, target, addend);
- break;
- case R_AARCH64_TLSDESC_CALL:
- // Relaxation only to optimize TLS access. Ignore for now.
- break;
- // Runtime only relocations. Ignore here.
- case R_AARCH64_RELATIVE:
- case R_AARCH64_IRELATIVE:
- case R_AARCH64_JUMP_SLOT:
- case R_AARCH64_GLOB_DAT:
- case R_AARCH64_TLS_TPREL64:
- case R_AARCH64_TLSDESC:
- 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
deleted file mode 100644
index 8cde7a03e51a..000000000000
--- a/lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.h
+++ /dev/null
@@ -1,36 +0,0 @@
-//===- 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 "lld/ReaderWriter/ELFLinkingContext.h"
-
-namespace lld {
-namespace elf {
-
-class AArch64TargetLayout;
-
-class AArch64TargetRelocationHandler final : public TargetRelocationHandler {
-public:
- AArch64TargetRelocationHandler(AArch64TargetLayout &layout)
- : _layout(layout) {}
-
- std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &,
- const AtomLayout &,
- const Reference &) const override;
-
-private:
- AArch64TargetLayout &_layout;
-};
-
-} // 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
deleted file mode 100644
index 4d94a793665c..000000000000
--- a/lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.cpp
+++ /dev/null
@@ -1,612 +0,0 @@
-//===- 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;
-
-// .got values
-static const uint8_t AArch64GotAtomContent[8] = {0};
-
-// tls descriptor .got values, the layout is:
-// struct tlsdesc {
-// ptrdiff_t (*entry) (struct tlsdesc *);
-// void *arg;
-// };
-static const uint8_t AArch64TlsdescGotAtomContent[16] = {0};
-
-// .plt value (entry 0)
-static 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)
-static 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
-};
-
-// .plt tlsdesc values
-static const uint8_t AArch64PltTlsdescAtomContent[32] = {
- 0xe2, 0x0f, 0xbf, 0xa9, // stp x2, x3, [sp, #-16]
- 0x02, 0x00, 0x00, 0x90, // adpr x2, 0
- 0x03, 0x00, 0x00, 0x90, // adpr x3, 0
- 0x42, 0x00, 0x40, 0xf9, // ldr x2, [x2, #0]
- 0x63, 0x00, 0x00, 0x91, // add x3, x3, 0
- 0x40, 0x00, 0x1f, 0xd6, // br x2
- 0x1f, 0x20, 0x03, 0xd5, // nop
- 0x1f, 0x20, 0x03, 0xd5 // nop
-};
-
-namespace {
-
-/// \brief Atoms that are used by AArch64 dynamic linking
-class AArch64GOTAtom : public GOTAtom {
-public:
- AArch64GOTAtom(const File &f) : GOTAtom(f, ".got") {}
-
- ArrayRef<uint8_t> rawContent() const override {
- return ArrayRef<uint8_t>(AArch64GotAtomContent, 8);
- }
-
-protected:
- // Constructor for AArch64GOTAtom
- AArch64GOTAtom(const File &f, StringRef secName) : GOTAtom(f, secName) {}
-};
-
-class AArch64GOTPLTAtom : public AArch64GOTAtom {
-public:
- AArch64GOTPLTAtom(const File &f) : AArch64GOTAtom(f, ".got.plt") {}
-};
-
-class AArch64TLSDESCGOTAtom : public AArch64GOTPLTAtom {
-public:
- AArch64TLSDESCGOTAtom(const File &f) : AArch64GOTPLTAtom(f) {}
-
- ArrayRef<uint8_t> rawContent() const override {
- return ArrayRef<uint8_t>(AArch64TlsdescGotAtomContent, 16);
- }
-};
-
-
-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) : PLTAtom(f, ".plt") {}
-
- ArrayRef<uint8_t> rawContent() const override {
- return ArrayRef<uint8_t>(AArch64PltAtomContent, 16);
- }
-};
-
-class AArch64PLTTLSDESCAtom : public PLTAtom {
-public:
- AArch64PLTTLSDESCAtom(const File &f) : PLTAtom(f, ".plt") {}
-
- ArrayRef<uint8_t> rawContent() const override {
- return ArrayRef<uint8_t>(AArch64PltTlsdescAtomContent, 32);
- }
-};
-
-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:
- static_cast<Derived *>(this)->handleGOT(ref);
- break;
- case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
- case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
- static_cast<Derived *>(this)->handleGOTTPREL(ref);
- break;
- case R_AARCH64_TLSDESC_ADR_PAGE21:
- case R_AARCH64_TLSDESC_LD64_LO12_NC:
- case R_AARCH64_TLSDESC_ADD_LO12_NC:
- static_cast<Derived *>(this)->handleTLSDESC(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) AArch64GOTPLTAtom(_file);
- ga->addReferenceELF_AArch64(R_AARCH64_IRELATIVE, 0, da, 0);
- auto pa = new (_file._alloc) AArch64PLTAtom(_file);
- 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 *getGOTTPREL(const Atom *atom) {
- auto got = _gotMap.find(atom);
- if (got == _gotMap.end()) {
- auto g = new (_file._alloc) AArch64GOTAtom(_file);
- g->addReferenceELF_AArch64(R_AARCH64_TLS_TPREL64, 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 GOT TPREL entry to local or external TLS variable.
- std::error_code handleGOTTPREL(const Reference &ref) {
- if (isa<DefinedAtom>(ref.target()) ||
- isa<SharedLibraryAtom>(ref.target()))
- const_cast<Reference &>(ref).setTarget(getGOTTPREL(ref.target()));
- return std::error_code();
- }
-
- /// \brief Generates a double GOT entry with R_AARCH64_TLSDESC dynamic
- /// relocation reference. Since the dynamic relocation is resolved
- /// lazily so the GOT associated should be in .got.plt.
- const GOTAtom *getTLSDESCPLTEntry(const Atom *da) {
- auto got = _gotMap.find(da);
- if (got != _gotMap.end())
- return got->second;
- auto ga = new (_file._alloc) AArch64TLSDESCGOTAtom(_file);
- ga->addReferenceELF_AArch64(R_AARCH64_TLSDESC, 0, da, 0);
- auto pa = new (_file._alloc) AArch64PLTTLSDESCAtom(_file);
- pa->addReferenceELF_AArch64(R_AARCH64_ADR_PREL_PG_HI21, 4, ga, 0);
- pa->addReferenceELF_AArch64(R_AARCH64_ADR_PREL_PG_HI21, 8, ga, 0);
- pa->addReferenceELF_AArch64(R_AARCH64_LDST64_ABS_LO12_NC, 12, ga, 0);
- pa->addReferenceELF_AArch64(R_AARCH64_ADD_ABS_LO12_NC, 16, ga, 0);
-#ifndef NDEBUG
- ga->_name = "__got_tlsdesc_";
- ga->_name += da->name();
- pa->_name = "__plt_tlsdesc_";
- pa->_name += da->name();
-#endif
- _gotMap[da] = ga;
- _pltMap[da] = pa;
- _tlsdescVector.push_back(ga);
- _pltVector.push_back(pa);
- return ga;
- }
-
- std::error_code handleTLSDESC(const Reference &ref) {
- if (isa<DefinedAtom>(ref.target()) ||
- isa<SharedLibraryAtom>(ref.target())) {
- const_cast<Reference &>(ref).setTarget(getTLSDESCPLTEntry(ref.target()));
- }
- return std::error_code();
- }
-
- /// \brief Create a GOT entry containing 0.
- const GOTAtom *getNullGOT() {
- if (!_null) {
- _null = new (_file._alloc) AArch64GOTPLTAtom(_file);
-#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);
- 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) {}
-
- /// \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.
- std::error_code perform(SimpleFile &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);
- }
- // Add any tlsdesc GOT relocation after default PLT and iFUNC entries.
- for (auto &tlsdesc : _tlsdescVector) {
- tlsdesc->setOrdinal(ordinal++);
- mf.addAtom(*tlsdesc);
- }
- for (auto obj : _objectVector) {
- obj->setOrdinal(ordinal++);
- mf.addAtom(*obj);
- }
-
- return std::error_code();
- }
-
-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<GOTAtom *> _tlsdescVector;
- std::vector<PLTAtom *> _pltVector;
- std::vector<ObjectAtom *> _objectVector;
-
- /// \brief GOT entry that is always 0. Used for undefined weaks.
- GOTAtom *_null = nullptr;
-
- /// \brief The got and plt entries for .PLT0. This is used to call into the
- /// dynamic linker for symbol resolution.
- /// @{
- PLT0Atom *_plt0 = nullptr;
- GOTAtom *_got0 = nullptr;
- GOTAtom *_got1 = nullptr;
- /// @}
-};
-
-/// 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) AArch64GOTPLTAtom(_file);
- _got1 = new (_file._alloc) AArch64GOTPLTAtom(_file);
- _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) AArch64GOTPLTAtom(_file);
- ga->addReferenceELF_AArch64(R_AARCH64_JUMP_SLOT, 0, a, 0);
- auto pa = new (_file._alloc) AArch64PLTAtom(_file);
- 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);
- 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
deleted file mode 100644
index 73d784e3b52d..000000000000
--- a/lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.h
+++ /dev/null
@@ -1,32 +0,0 @@
-//===- 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/AArch64SectionChunks.cpp b/lib/ReaderWriter/ELF/AArch64/AArch64SectionChunks.cpp
deleted file mode 100644
index 2734bcdbda5f..000000000000
--- a/lib/ReaderWriter/ELF/AArch64/AArch64SectionChunks.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-//===- lib/ReaderWriter/ELF/AArch64/AArch64SectionChunks.cpp --------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "AArch64SectionChunks.h"
-#include "TargetLayout.h"
-
-namespace lld {
-namespace elf {
-
-AArch64GOTSection::AArch64GOTSection(const ELFLinkingContext &ctx,
- StringRef name, int32_t order)
- : AtomSection<ELF64LE>(ctx, name, DefinedAtom::typeGOT, DefinedAtom::permRW_,
- order) {
- _alignment = 8;
-}
-
-const AtomLayout *AArch64GOTSection::appendAtom(const Atom *atom) {
- const DefinedAtom *da = dyn_cast<DefinedAtom>(atom);
-
- for (const auto &r : *da) {
- if (r->kindNamespace() != Reference::KindNamespace::ELF)
- continue;
- assert(r->kindArch() == Reference::KindArch::AArch64);
- if ((r->kindValue() == R_AARCH64_TLS_TPREL64) ||
- (r->kindValue() == R_AARCH64_TLSDESC))
- _tlsMap[r->target()] = _tlsMap.size();
- }
-
- return AtomSection<ELF64LE>::appendAtom(atom);
-}
-
-} // elf
-} // lld
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64SectionChunks.h b/lib/ReaderWriter/ELF/AArch64/AArch64SectionChunks.h
deleted file mode 100644
index 2b7594c2db84..000000000000
--- a/lib/ReaderWriter/ELF/AArch64/AArch64SectionChunks.h
+++ /dev/null
@@ -1,37 +0,0 @@
-//===- lib/ReaderWriter/ELF/AArch64/AArch64SectionChunks.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_SECTION_CHUNKS_H
-#define LLD_READER_WRITER_ELF_AARCH64_AARCH64_SECTION_CHUNKS_H
-
-#include "TargetLayout.h"
-
-namespace lld {
-namespace elf {
-
-class AArch64GOTSection : public AtomSection<ELF64LE> {
-public:
- AArch64GOTSection(const ELFLinkingContext &ctx, StringRef name,
- int32_t order);
-
- bool hasGlobalGOTEntry(const Atom *a) const {
- return _tlsMap.count(a);
- }
-
- const AtomLayout *appendAtom(const Atom *atom) override;
-
-private:
- /// \brief Map TLS Atoms to their GOT entry index.
- llvm::DenseMap<const Atom *, std::size_t> _tlsMap;
-};
-
-} // elf
-} // lld
-
-#endif
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.cpp b/lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.cpp
deleted file mode 100644
index 083b492c1607..000000000000
--- a/lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-//===- 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"
-#include "AArch64SectionChunks.h"
-
-using namespace lld;
-using namespace elf;
-
-AArch64TargetLayout::AArch64TargetLayout(ELFLinkingContext &ctx) :
- TargetLayout(ctx) {}
-
-AtomSection<ELF64LE> *AArch64TargetLayout::createSection(
- StringRef name, int32_t type, DefinedAtom::ContentPermissions permissions,
- TargetLayout<ELF64LE>::SectionOrder order) {
- if (type == DefinedAtom::typeGOT && (name == ".got" || name == ".got.plt")) {
- auto section = new (this->_allocator) AArch64GOTSection(this->_ctx, name,
- order);
- _gotSections.push_back(section);
- return section;
- }
- return TargetLayout<ELF64LE>::createSection(name, type, permissions, order);
-}
-
-
-AArch64TargetHandler::AArch64TargetHandler(AArch64LinkingContext &ctx)
- : _ctx(ctx), _targetLayout(new AArch64TargetLayout(ctx)),
- _relocationHandler(new AArch64TargetRelocationHandler(*_targetLayout)) {}
-
-std::unique_ptr<Writer> AArch64TargetHandler::getWriter() {
- switch (this->_ctx.getOutputELFType()) {
- case llvm::ELF::ET_EXEC:
- return llvm::make_unique<AArch64ExecutableWriter>(_ctx, *_targetLayout);
- case llvm::ELF::ET_DYN:
- return llvm::make_unique<AArch64DynamicLibraryWriter>(_ctx, *_targetLayout);
- case llvm::ELF::ET_REL:
- llvm_unreachable("TODO: support -r mode");
- default:
- llvm_unreachable("unsupported output type");
- }
-}
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.h b/lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.h
deleted file mode 100644
index c0ecbfa9e44b..000000000000
--- a/lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.h
+++ /dev/null
@@ -1,90 +0,0 @@
-//===- 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 "AArch64RelocationHandler.h"
-#include "ELFReader.h"
-#include "TargetLayout.h"
-#include "lld/Core/Simple.h"
-
-namespace lld {
-namespace elf {
-
-class AArch64LinkingContext;
-class AArch64GOTSection;
-
-class AArch64TargetLayout final : public TargetLayout<ELF64LE> {
- typedef llvm::object::Elf_Shdr_Impl<ELF64LE> Elf_Shdr;
-
-public:
- AArch64TargetLayout(ELFLinkingContext &ctx);
-
- AtomSection<ELF64LE> *
- createSection(StringRef name, int32_t type,
- DefinedAtom::ContentPermissions permissions,
- TargetLayout<ELF64LE>::SectionOrder order) override;
-
- const std::vector<AArch64GOTSection *> &getGOTSections() const {
- return _gotSections;
- }
-
- uint64_t getTPOffset() {
- std::call_once(_tpOffOnce, [this]() {
- for (const auto &phdr : *_programHeader) {
- if (phdr->p_type == llvm::ELF::PT_TLS) {
- _tpOff = llvm::RoundUpToAlignment(TCB_SIZE, phdr->p_align);
- break;
- }
- }
- assert(_tpOff != 0 && "TLS segment not found");
- });
- return _tpOff;
- }
-
-private:
- enum {
- TCB_SIZE = 16,
- };
-
-private:
- std::vector<AArch64GOTSection *> _gotSections;
- uint64_t _tpOff = 0;
- std::once_flag _tpOffOnce;
-};
-
-class AArch64TargetHandler final : public TargetHandler {
-public:
- AArch64TargetHandler(AArch64LinkingContext &ctx);
-
- const TargetRelocationHandler &getRelocationHandler() const override {
- return *_relocationHandler;
- }
-
- std::unique_ptr<Reader> getObjReader() override {
- return llvm::make_unique<ELFReader<ELFFile<ELF64LE>>>(_ctx);
- }
-
- std::unique_ptr<Reader> getDSOReader() override {
- return llvm::make_unique<ELFReader<DynamicFile<ELF64LE>>>(_ctx);
- }
-
- std::unique_ptr<Writer> getWriter() override;
-
-private:
- AArch64LinkingContext &_ctx;
- std::unique_ptr<AArch64TargetLayout> _targetLayout;
- std::unique_ptr<AArch64TargetRelocationHandler> _relocationHandler;
-};
-
-} // end namespace elf
-} // end namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/ELF/AArch64/CMakeLists.txt b/lib/ReaderWriter/ELF/AArch64/CMakeLists.txt
deleted file mode 100644
index aae6420008a4..000000000000
--- a/lib/ReaderWriter/ELF/AArch64/CMakeLists.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-add_lld_library(lldAArch64ELFTarget
- AArch64LinkingContext.cpp
- AArch64TargetHandler.cpp
- AArch64RelocationHandler.cpp
- AArch64RelocationPass.cpp
- AArch64ExecutableWriter.cpp
- AArch64SectionChunks.cpp
- LINK_LIBS
- lldELF
- lldReaderWriter
- lldCore
- LLVMObject
- LLVMSupport
- )
diff --git a/lib/ReaderWriter/ELF/AArch64/TODO.rst b/lib/ReaderWriter/ELF/AArch64/TODO.rst
deleted file mode 100644
index aa6f616ff33f..000000000000
--- a/lib/ReaderWriter/ELF/AArch64/TODO.rst
+++ /dev/null
@@ -1,15 +0,0 @@
-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/ARMDynamicLibraryWriter.h b/lib/ReaderWriter/ELF/ARM/ARMDynamicLibraryWriter.h
deleted file mode 100644
index da843b97abc0..000000000000
--- a/lib/ReaderWriter/ELF/ARM/ARMDynamicLibraryWriter.h
+++ /dev/null
@@ -1,49 +0,0 @@
-//===- lib/ReaderWriter/ELF/ARM/ARMDynamicLibraryWriter.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_DYNAMIC_LIBRARY_WRITER_H
-#define LLD_READER_WRITER_ELF_ARM_ARM_DYNAMIC_LIBRARY_WRITER_H
-
-#include "DynamicLibraryWriter.h"
-#include "ARMELFWriters.h"
-#include "ARMLinkingContext.h"
-#include "ARMTargetHandler.h"
-
-namespace lld {
-namespace elf {
-
-class ARMDynamicLibraryWriter
- : public ARMELFWriter<DynamicLibraryWriter<ELF32LE>> {
-public:
- ARMDynamicLibraryWriter(ARMLinkingContext &ctx, ARMTargetLayout &layout);
-
-protected:
- // Add any runtime files and their atoms to the output
- void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
-
-private:
- ARMLinkingContext &_ctx;
-};
-
-ARMDynamicLibraryWriter::ARMDynamicLibraryWriter(ARMLinkingContext &ctx,
- ARMTargetLayout &layout)
- : ARMELFWriter(ctx, layout), _ctx(ctx) {}
-
-void ARMDynamicLibraryWriter::createImplicitFiles(
- std::vector<std::unique_ptr<File>> &result) {
- DynamicLibraryWriter::createImplicitFiles(result);
- auto file = llvm::make_unique<RuntimeFile<ELF32LE>>(_ctx, "ARM dynamic file");
- file->addAbsoluteAtom(gotSymbol);
- file->addAbsoluteAtom(dynamicSymbol);
- result.push_back(std::move(file));
-}
-
-} // namespace elf
-} // namespace lld
-
-#endif // LLD_READER_WRITER_ELF_ARM_ARM_DYNAMIC_LIBRARY_WRITER_H
diff --git a/lib/ReaderWriter/ELF/ARM/ARMELFFile.h b/lib/ReaderWriter/ELF/ARM/ARMELFFile.h
deleted file mode 100644
index 8f5477017e55..000000000000
--- a/lib/ReaderWriter/ELF/ARM/ARMELFFile.h
+++ /dev/null
@@ -1,154 +0,0 @@
-//===--------- 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;
-
-class ARMELFBaseDefinedAtom : public ELFDefinedAtom<ELF32LE> {
-public:
- /// The values of custom content type enum must not interfere
- /// with ones in base defined atom class' enum.
- enum ARMContentType {
- typeARMExidx = 0x1000, // Identifies ARM_EXIDX section
- };
-
- template <typename... T>
- ARMELFBaseDefinedAtom(T &&... args)
- : ELFDefinedAtom<ELF32LE>(std::forward<T>(args)...) {}
-
- DefinedAtom::ContentPermissions permissions() const override {
- if (_permissions != DefinedAtom::permUnknown)
- return _permissions;
-
- switch (_section->sh_type) {
- case llvm::ELF::SHT_ARM_EXIDX:
- return _permissions = permR__;
- }
- return ELFDefinedAtom::permissions();
- }
-
- DefinedAtom::ContentType contentType() const override {
- if (_contentType != DefinedAtom::typeUnknown)
- return _contentType;
-
- switch (_section->sh_type) {
- case llvm::ELF::SHT_ARM_EXIDX:
- return _contentType = (DefinedAtom::ContentType)typeARMExidx;
- }
- return ELFDefinedAtom::contentType();
- }
-};
-
-class ARMELFMappingAtom : public ARMELFBaseDefinedAtom {
-public:
- template <typename... T>
- ARMELFMappingAtom(DefinedAtom::CodeModel model, T &&... args)
- : ARMELFBaseDefinedAtom(std::forward<T>(args)...), _model(model) {}
-
- DefinedAtom::CodeModel codeModel() const override { return _model; }
-
-private:
- DefinedAtom::CodeModel _model;
-};
-
-class ARMELFDefinedAtom : public ARMELFBaseDefinedAtom {
-public:
- template <typename... T>
- ARMELFDefinedAtom(T &&... args)
- : ARMELFBaseDefinedAtom(std::forward<T>(args)...) {}
-
- bool isThumbFunc() const {
- const auto *symbol = _symbol;
- 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 override {
- const auto value = static_cast<uint64_t>(_symbol->st_value);
- return isThumbFunc() ? value & ~0x1 : value;
- }
-
- DefinedAtom::CodeModel codeModel() const override {
- return isThumbFunc() ? DefinedAtom::codeARMThumb : DefinedAtom::codeNA;
- }
-};
-
-class ARMELFFile : public ELFFile<ELF32LE> {
- typedef llvm::object::Elf_Rel_Impl<ELF32LE, false> Elf_Rel;
-
-public:
- ARMELFFile(std::unique_ptr<MemoryBuffer> mb, ELFLinkingContext &ctx)
- : ELFFile(std::move(mb), ctx) {}
-
-protected:
- /// Returns initial addend; for ARM it is 0, because it is read
- /// during the relocations applying
- Reference::Addend getInitialAddend(ArrayRef<uint8_t>, uint64_t,
- const Elf_Rel &) const override {
- return 0;
- }
-
-private:
- typedef llvm::object::Elf_Sym_Impl<ELF32LE> Elf_Sym;
- typedef llvm::object::Elf_Shdr_Impl<ELF32LE> 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.
- ELFDefinedAtom<ELF32LE> *createDefinedAtom(
- 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<ELF32LE> *> &referenceList) override {
- if (symName.size() >= 2 && symName[0] == '$') {
- switch (symName[1]) {
- case 'a':
- return new (_readerStorage)
- ARMELFMappingAtom(DefinedAtom::codeARM_a, *this, symName,
- sectionName, sym, sectionHdr, contentData,
- referenceStart, referenceEnd, referenceList);
- case 'd':
- return new (_readerStorage)
- ARMELFMappingAtom(DefinedAtom::codeARM_d, *this, symName,
- sectionName, sym, sectionHdr, contentData,
- referenceStart, referenceEnd, referenceList);
- case 't':
- return new (_readerStorage)
- ARMELFMappingAtom(DefinedAtom::codeARM_t, *this, symName,
- sectionName, sym, sectionHdr, contentData,
- referenceStart, referenceEnd, referenceList);
- default:
- // Fall through and create regular defined atom.
- break;
- }
- }
- return new (_readerStorage) ARMELFDefinedAtom(
- *this, symName, sectionName, sym, sectionHdr, contentData,
- referenceStart, referenceEnd, referenceList);
- }
-};
-
-} // elf
-} // lld
-
-#endif // LLD_READER_WRITER_ELF_ARM_ARM_ELF_FILE_H
diff --git a/lib/ReaderWriter/ELF/ARM/ARMELFWriters.h b/lib/ReaderWriter/ELF/ARM/ARMELFWriters.h
deleted file mode 100644
index a842ebe53038..000000000000
--- a/lib/ReaderWriter/ELF/ARM/ARMELFWriters.h
+++ /dev/null
@@ -1,120 +0,0 @@
-//===- lib/ReaderWriter/ELF/ARM/ARMELFWriters.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_WRITERS_H
-#define LLD_READER_WRITER_ELF_ARM_ARM_ELF_WRITERS_H
-
-#include "ARMLinkingContext.h"
-#include "ARMSymbolTable.h"
-#include "llvm/Support/ELF.h"
-
-namespace lld {
-namespace elf {
-
-template <class WriterT> class ARMELFWriter : public WriterT {
-public:
- ARMELFWriter(ARMLinkingContext &ctx, TargetLayout<ELF32LE> &layout);
-
- void finalizeDefaultAtomValues() override;
-
- /// \brief Create symbol table.
- unique_bump_ptr<SymbolTable<ELF32LE>> createSymbolTable() override;
-
- // Setup the ELF header.
- std::error_code setELFHeader() override;
-
-protected:
- static const char *gotSymbol;
- static const char *dynamicSymbol;
-
-private:
- ARMLinkingContext &_ctx;
- TargetLayout<ELF32LE> &_armLayout;
-};
-
-template <class WriterT>
-const char *ARMELFWriter<WriterT>::gotSymbol = "_GLOBAL_OFFSET_TABLE_";
-template <class WriterT>
-const char *ARMELFWriter<WriterT>::dynamicSymbol = "_DYNAMIC";
-
-template <class WriterT>
-ARMELFWriter<WriterT>::ARMELFWriter(ARMLinkingContext &ctx,
- TargetLayout<ELF32LE> &layout)
- : WriterT(ctx, layout), _ctx(ctx), _armLayout(layout) {}
-
-template <class WriterT>
-void ARMELFWriter<WriterT>::finalizeDefaultAtomValues() {
- // Finalize the atom values that are part of the parent.
- WriterT::finalizeDefaultAtomValues();
-
- if (auto *gotAtom = _armLayout.findAbsoluteAtom(gotSymbol)) {
- 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;
- }
-
- if (auto *dynamicAtom = _armLayout.findAbsoluteAtom(dynamicSymbol)) {
- if (auto dynamicSection = _armLayout.findOutputSection(".dynamic"))
- dynamicAtom->_virtualAddr = dynamicSection->virtualAddr();
- else
- dynamicAtom->_virtualAddr = 0;
- }
-
- // Set required by gcc libc __ehdr_start symbol with pointer to ELF header
- if (auto ehdr = _armLayout.findAbsoluteAtom("__ehdr_start"))
- ehdr->_virtualAddr = this->_elfHeader->virtualAddr();
-
- // Set required by gcc libc symbols __exidx_start/__exidx_end
- this->updateScopeAtomValues("exidx", ".ARM.exidx");
-}
-
-template <class WriterT>
-unique_bump_ptr<SymbolTable<ELF32LE>>
-ARMELFWriter<WriterT>::createSymbolTable() {
- return unique_bump_ptr<SymbolTable<ELF32LE>>(new (this->_alloc)
- ARMSymbolTable(_ctx));
-}
-
-template <class WriterT> std::error_code ARMELFWriter<WriterT>::setELFHeader() {
- if (std::error_code ec = WriterT::setELFHeader())
- return ec;
-
- // Set ARM-specific flags.
- this->_elfHeader->e_flags(llvm::ELF::EF_ARM_EABI_VER5 |
- llvm::ELF::EF_ARM_VFP_FLOAT);
-
- StringRef entryName = _ctx.entrySymbolName();
- if (const AtomLayout *al = _armLayout.findAtomLayoutByName(entryName)) {
- if (const auto *ea = dyn_cast<DefinedAtom>(al->_atom)) {
- switch (ea->codeModel()) {
- case DefinedAtom::codeNA:
- if (al->_virtualAddr & 0x3) {
- llvm::report_fatal_error(
- "Two least bits must be zero for ARM entry point");
- }
- break;
- case DefinedAtom::codeARMThumb:
- // Fixup entry point for Thumb code.
- this->_elfHeader->e_entry(al->_virtualAddr | 0x1);
- break;
- default:
- llvm_unreachable("Wrong code model of entry point atom");
- }
- }
- }
-
- return std::error_code();
-}
-
-} // namespace elf
-} // namespace lld
-
-#endif // LLD_READER_WRITER_ELF_ARM_ARM_ELF_WRITERS_H
diff --git a/lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h b/lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h
deleted file mode 100644
index 974dab63a126..000000000000
--- a/lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h
+++ /dev/null
@@ -1,68 +0,0 @@
-//===--------- 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 "ARMELFWriters.h"
-#include "ARMLinkingContext.h"
-#include "ARMTargetHandler.h"
-
-namespace lld {
-namespace elf {
-
-class ARMExecutableWriter : public ARMELFWriter<ExecutableWriter<ELF32LE>> {
-public:
- ARMExecutableWriter(ARMLinkingContext &ctx, ARMTargetLayout &layout);
-
-protected:
- // Add any runtime files and their atoms to the output
- void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
-
- void processUndefinedSymbol(StringRef symName,
- RuntimeFile<ELF32LE> &file) const override;
-
-private:
- ARMLinkingContext &_ctx;
-};
-
-ARMExecutableWriter::ARMExecutableWriter(ARMLinkingContext &ctx,
- ARMTargetLayout &layout)
- : ARMELFWriter(ctx, layout), _ctx(ctx) {}
-
-void ARMExecutableWriter::createImplicitFiles(
- std::vector<std::unique_ptr<File>> &result) {
- ExecutableWriter::createImplicitFiles(result);
- // Add default atoms for ARM.
- if (_ctx.isDynamic()) {
- auto file = llvm::make_unique<RuntimeFile<ELF32LE>>(_ctx, "ARM exec file");
- file->addAbsoluteAtom(gotSymbol);
- file->addAbsoluteAtom(dynamicSymbol);
- result.push_back(std::move(file));
- }
-}
-
-void ARMExecutableWriter::processUndefinedSymbol(
- StringRef symName, RuntimeFile<ELF32LE> &file) const {
- ARMELFWriter<ExecutableWriter<ELF32LE>>::processUndefinedSymbol(symName,
- file);
- if (symName == gotSymbol) {
- file.addAbsoluteAtom(gotSymbol);
- } else if (symName.startswith("__exidx")) {
- file.addAbsoluteAtom("__exidx_start");
- file.addAbsoluteAtom("__exidx_end");
- } else if (symName == "__ehdr_start") {
- file.addAbsoluteAtom("__ehdr_start");
- }
-}
-
-} // 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
deleted file mode 100644
index 74905b47820f..000000000000
--- a/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-//===--------- 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"
-
-namespace lld {
-namespace elf {
-
-std::unique_ptr<ELFLinkingContext>
-createARMLinkingContext(llvm::Triple triple) {
- if (triple.getArch() == llvm::Triple::arm)
- return llvm::make_unique<ARMLinkingContext>(triple);
- return nullptr;
-}
-
-ARMLinkingContext::ARMLinkingContext(llvm::Triple triple)
- : ELFLinkingContext(triple, llvm::make_unique<ARMTargetHandler>(*this)) {}
-
-void ARMLinkingContext::addPasses(PassManager &pm) {
- auto pass = createARMRelocationPass(*this);
- if (pass)
- pm.add(std::move(pass));
- ELFLinkingContext::addPasses(pm);
-}
-
-bool isARMCode(const DefinedAtom *atom) {
- return isARMCode(atom->codeModel());
-}
-
-bool isARMCode(DefinedAtom::CodeModel codeModel) {
- return !isThumbCode(codeModel);
-}
-
-bool isThumbCode(const DefinedAtom *atom) {
- return isThumbCode(atom->codeModel());
-}
-
-bool isThumbCode(DefinedAtom::CodeModel codeModel) {
- return codeModel == DefinedAtom::codeARMThumb ||
- codeModel == DefinedAtom::codeARM_t;
-}
-
-static const Registry::KindStrings kindStrings[] = {
-#define ELF_RELOC(name, value) LLD_KIND_STRING_ENTRY(name),
-#include "llvm/Support/ELFRelocs/ARM.def"
-#undef ELF_RELOC
- LLD_KIND_STRING_END
-};
-
-void ARMLinkingContext::registerRelocationNames(Registry &registry) {
- registry.addKindTable(Reference::KindNamespace::ELF, Reference::KindArch::ARM,
- kindStrings);
-}
-
-} // namespace elf
-} // namespace lld
diff --git a/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h b/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h
deleted file mode 100644
index f687713b25b8..000000000000
--- a/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h
+++ /dev/null
@@ -1,80 +0,0 @@
-//===--------- 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:
- int getMachineType() const override { return llvm::ELF::EM_ARM; }
- ARMLinkingContext(llvm::Triple);
-
- void addPasses(PassManager &) override;
- void registerRelocationNames(Registry &r) override;
-
- bool isRelaOutputFormat() const override { return false; }
-
- 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::ARM);
- switch (r.kindValue()) {
- case llvm::ELF::R_ARM_GLOB_DAT:
- case llvm::ELF::R_ARM_TLS_TPOFF32:
- case llvm::ELF::R_ARM_COPY:
- 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::ARM);
- return r.kindValue() == llvm::ELF::R_ARM_COPY;
- }
-
- bool isPLTRelocation(const Reference &r) const override {
- if (r.kindNamespace() != Reference::KindNamespace::ELF)
- return false;
- assert(r.kindArch() == Reference::KindArch::ARM);
- switch (r.kindValue()) {
- case llvm::ELF::R_ARM_JUMP_SLOT:
- case llvm::ELF::R_ARM_IRELATIVE:
- return true;
- default:
- return false;
- }
- }
-};
-
-// Special methods to check code model of atoms.
-bool isARMCode(const DefinedAtom *atom);
-bool isARMCode(DefinedAtom::CodeModel codeModel);
-bool isThumbCode(const DefinedAtom *atom);
-bool isThumbCode(DefinedAtom::CodeModel codeModel);
-
-} // end namespace elf
-} // end namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp b/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp
deleted file mode 100644
index 97b149133ff2..000000000000
--- a/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp
+++ /dev/null
@@ -1,680 +0,0 @@
-//===--------- 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"
-
-#define DEBUG_TYPE "ARM"
-
-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::SignExtend64<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_TARGET1:
- case R_ARM_GOT_BREL:
- case R_ARM_BASE_PREL:
- case R_ARM_TLS_IE32:
- case R_ARM_TLS_LE32:
- case R_ARM_TLS_TPOFF32:
- return (int32_t)read32le(location);
- case R_ARM_PREL31:
- return llvm::SignExtend64<31>(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 report_unsupported_range_group_reloc_error() {
- llvm::report_fatal_error(
- "Negative offsets for group relocations are not implemented");
-}
-
-static inline std::error_code applyArmReloc(uint8_t *location, uint32_t result,
- uint32_t mask = 0xFFFFFFFF) {
- assert(!(result & ~mask));
- write32le(location, (read32le(location) & ~mask) | (result & mask));
- return std::error_code();
-}
-
-static inline std::error_code applyThumb32Reloc(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));
- return std::error_code();
-}
-
-static inline std::error_code
-applyThumb16Reloc(uint8_t *location, uint16_t result, uint16_t mask = 0xFFFF) {
- assert(!(result & ~mask));
- write16le(location, (read16le(location) & ~mask) | (result & mask));
- return std::error_code();
-}
-
-/// \brief R_ARM_ABS32 - (S + A) | T
-static std::error_code 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(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 applyArmReloc(location, result);
-}
-
-/// \brief R_ARM_REL32 - ((S + A) | T) - P
-static std::error_code 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(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 applyArmReloc(location, result);
-}
-
-/// \brief R_ARM_PREL31 - ((S + A) | T) - P
-static std::error_code 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);
- if (!llvm::isInt<31>((int32_t)result))
- return make_out_of_range_reloc_error();
-
- const uint32_t mask = 0x7FFFFFFF;
- uint32_t rel31 = result & mask;
-
- DEBUG(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");
-
- return applyArmReloc(location, rel31, mask);
-}
-
-/// \brief Relocate B/BL instructions. useJs defines whether J1 & J2 are used
-static std::error_code relocR_ARM_THM_B_L(uint8_t *location, uint32_t result,
- bool useJs) {
- if ((useJs && !llvm::isInt<25>((int32_t)result)) ||
- (!useJs && !llvm::isInt<23>((int32_t)result)))
- return make_out_of_range_reloc_error();
-
- 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;
-
- return applyThumb32Reloc(location, resHi, resLo, 0x7FF, 0x2FFF);
-}
-
-/// \brief R_ARM_THM_CALL - ((S + A) | T) - P
-static std::error_code 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(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");
- if (auto ec = relocR_ARM_THM_B_L(location, result, useJs))
- return ec;
-
- if (switchMode) {
- return applyThumb32Reloc(location, 0, 0, 0, 0x1001);
- }
- return std::error_code();
-}
-
-/// \brief R_ARM_THM_JUMP24 - ((S + A) | T) - P
-static std::error_code 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(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_B_L(location, result, true);
-}
-
-/// \brief R_ARM_THM_JUMP11 - S + A - P
-static std::error_code 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(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");
-
- if (!llvm::isInt<12>((int32_t)result))
- return make_out_of_range_reloc_error();
-
- // we cut off first bit because it is always 1 according to p. 4.5.3
- result = (result & 0x0FFE) >> 1;
- return applyThumb16Reloc(location, result, 0x7FF);
-}
-
-/// \brief R_ARM_BASE_PREL - B(S) + A - P => S + A - P
-static std::error_code relocR_ARM_BASE_PREL(uint8_t *location, uint64_t P,
- uint64_t S, int64_t A) {
- uint32_t result = (uint32_t)(S + A - P);
- DEBUG(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 applyArmReloc(location, result);
-}
-
-/// \brief R_ARM_GOT_BREL - GOT(S) + A - GOT_ORG => S + A - GOT_ORG
-static std::error_code relocR_ARM_GOT_BREL(uint8_t *location, uint64_t P,
- uint64_t S, int64_t A,
- uint64_t GOT_ORG) {
- uint32_t result = (uint32_t)(S + A - GOT_ORG);
- DEBUG(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 applyArmReloc(location, result);
-}
-
-/// \brief R_ARM_CALL - ((S + A) | T) - P
-static std::error_code 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);
- if (!llvm::isInt<26>((int32_t)result))
- return make_out_of_range_reloc_error();
-
- const uint32_t imm24 = (result & 0x03FFFFFC) >> 2;
-
- DEBUG(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");
- if (auto ec = applyArmReloc(location, imm24, 0xFFFFFF))
- return ec;
-
- if (switchMode) {
- const uint32_t bitH = (result & 0x2) >> 1;
- return applyArmReloc(location, (0xFA | bitH) << 24, 0xFF000000);
- }
- return std::error_code();
-}
-
-/// \brief R_ARM_JUMP24 - ((S + A) | T) - P
-static std::error_code 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);
- if (!llvm::isInt<26>((int32_t)result))
- return make_out_of_range_reloc_error();
-
- const uint32_t imm24 = (result & 0x03FFFFFC) >> 2;
-
- DEBUG(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 applyArmReloc(location, imm24, 0xFFFFFF);
-}
-
-/// \brief Relocate ARM MOVW/MOVT instructions
-static std::error_code relocR_ARM_MOV(uint8_t *location, uint32_t result) {
- const uint32_t imm12 = result & 0xFFF;
- const uint32_t imm4 = (result >> 12) & 0xF;
-
- return applyArmReloc(location, (imm4 << 16) | imm12, 0xF0FFF);
-}
-
-/// \brief R_ARM_MOVW_ABS_NC - (S + A) | T
-static std::error_code 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(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 std::error_code 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(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 std::error_code 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;
-
- return applyThumb32Reloc(location, resHi, resLo, 0x40F, 0x70FF);
-}
-
-/// \brief R_ARM_THM_MOVW_ABS_NC - (S + A) | T
-static std::error_code 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(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 std::error_code 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(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 std::error_code 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(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 applyArmReloc(location, result);
-}
-
-/// \brief R_ARM_TLS_LE32 - S + A - tp => S + A + tpoff
-static std::error_code 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(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 applyArmReloc(location, result);
-}
-
-/// \brief R_ARM_TLS_TPOFF32 - S + A - tp => S + A (offset within TLS block)
-static std::error_code relocR_ARM_TLS_TPOFF32(uint8_t *location, uint64_t P,
- uint64_t S, int64_t A) {
- uint32_t result = (uint32_t)(S + A);
-
- DEBUG(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 applyArmReloc(location, result);
-}
-
-template <uint32_t lshift>
-static std::error_code relocR_ARM_ALU_PC_GN_NC(uint8_t *location,
- uint32_t result) {
- static_assert(lshift < 32 && lshift % 2 == 0,
- "lshift must be even and less than word size");
-
- const uint32_t rshift = 32 - lshift;
- result = ((result >> lshift) & 0xFF) | ((rshift / 2) << 8);
-
- return applyArmReloc(location, result, 0xFFF);
-}
-
-/// \brief R_ARM_ALU_PC_G0_NC - ((S + A) | T) - P => S + A - P
-static std::error_code relocR_ARM_ALU_PC_G0_NC(uint8_t *location, uint64_t P,
- uint64_t S, int64_t A) {
- int32_t result = (int32_t)(S + A - P);
- if (result < 0)
- report_unsupported_range_group_reloc_error();
-
- DEBUG(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((uint32_t)result)
- << "\n");
-
- return relocR_ARM_ALU_PC_GN_NC<20>(location, (uint32_t)result);
-}
-
-/// \brief R_ARM_ALU_PC_G1_NC - ((S + A) | T) - P => S + A - P
-static std::error_code relocR_ARM_ALU_PC_G1_NC(uint8_t *location, uint64_t P,
- uint64_t S, int64_t A) {
- int32_t result = (int32_t)(S + A - P);
- if (result < 0)
- report_unsupported_range_group_reloc_error();
-
- DEBUG(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((uint32_t)result)
- << "\n");
-
- return relocR_ARM_ALU_PC_GN_NC<12>(location, (uint32_t)result);
-}
-
-/// \brief R_ARM_LDR_PC_G2 - S + A - P
-static std::error_code relocR_ARM_LDR_PC_G2(uint8_t *location, uint64_t P,
- uint64_t S, int64_t A) {
- int32_t result = (int32_t)(S + A - P);
- if (result < 0)
- report_unsupported_range_group_reloc_error();
-
- DEBUG(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((uint32_t)result)
- << "\n");
-
- const uint32_t mask = 0xFFF;
- return applyArmReloc(location, (uint32_t)result & mask, mask);
-}
-
-/// \brief Fixup unresolved weak reference with NOP instruction
-static bool fixupUnresolvedWeakCall(uint8_t *location,
- Reference::KindValue kindValue) {
- // TODO: workaround for archs without NOP instruction
- switch (kindValue) {
- case R_ARM_THM_CALL:
- case R_ARM_THM_JUMP24:
- // Thumb32 NOP.W
- write32le(location, 0x8000F3AF);
- break;
- case R_ARM_THM_JUMP11:
- // Thumb16 NOP
- write16le(location, 0xBF00);
- break;
- case R_ARM_CALL:
- case R_ARM_JUMP24:
- // A1 NOP<c>, save condition bits
- applyArmReloc(location, 0x320F000, 0xFFFFFFF);
- break;
- default:
- return false;
- }
-
- return true;
-}
-
-std::error_code ARMTargetRelocationHandler::applyRelocation(
- ELFWriter &writer, llvm::FileOutputBuffer &buf, const AtomLayout &atom,
- const Reference &ref) const {
- uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset;
- uint8_t *loc = atomContent + ref.offsetInAtom();
- uint64_t target = writer.addressOfAtom(ref.target());
- uint64_t reloc = atom._virtualAddr + ref.offsetInAtom();
-
- if (ref.kindNamespace() != Reference::KindNamespace::ELF)
- return std::error_code();
- assert(ref.kindArch() == Reference::KindArch::ARM);
-
- // Fixup unresolved weak references
- if (!target) {
- bool isCallFixed = fixupUnresolvedWeakCall(loc, ref.kindValue());
-
- if (isCallFixed) {
- DEBUG(llvm::dbgs() << "\t\tFixup unresolved weak reference '";
- llvm::dbgs() << ref.target()->name() << "'";
- llvm::dbgs() << " at address: 0x" << Twine::utohexstr(reloc);
- llvm::dbgs() << (isCallFixed ? "\n" : " isn't possible\n"));
- return std::error_code();
- }
- }
-
- // Calculate proper initial addend for the relocation
- const Reference::Addend addend =
- readAddend(loc, ref.kindValue()) + ref.addend();
-
- // Flags that the relocation addresses Thumb instruction
- bool thumb = false;
- if (const auto *definedAtom = dyn_cast<DefinedAtom>(ref.target())) {
- thumb = isThumbCode(definedAtom);
- }
-
- switch (ref.kindValue()) {
- case R_ARM_NONE:
- return std::error_code();
- case R_ARM_ABS32:
- return relocR_ARM_ABS32(loc, reloc, target, addend, thumb);
- case R_ARM_REL32:
- return relocR_ARM_REL32(loc, reloc, target, addend, thumb);
- case R_ARM_TARGET1:
- if (_armLayout.target1Rel())
- return relocR_ARM_REL32(loc, reloc, target, addend, thumb);
- else
- return relocR_ARM_ABS32(loc, reloc, target, addend, thumb);
- case R_ARM_THM_CALL:
- // TODO: consider adding bool variable to disable J1 & J2 for archs
- // before ARMv6
- return relocR_ARM_THM_CALL(loc, reloc, target, addend, true, thumb);
- case R_ARM_CALL:
- return relocR_ARM_CALL(loc, reloc, target, addend, thumb);
- case R_ARM_JUMP24:
- return relocR_ARM_JUMP24(loc, reloc, target, addend, thumb);
- case R_ARM_THM_JUMP24:
- return relocR_ARM_THM_JUMP24(loc, reloc, target, addend, thumb);
- case R_ARM_THM_JUMP11:
- return relocR_ARM_THM_JUMP11(loc, reloc, target, addend);
- case R_ARM_MOVW_ABS_NC:
- return relocR_ARM_MOVW_ABS_NC(loc, reloc, target, addend, thumb);
- case R_ARM_MOVT_ABS:
- return relocR_ARM_MOVT_ABS(loc, reloc, target, addend);
- case R_ARM_THM_MOVW_ABS_NC:
- return relocR_ARM_THM_MOVW_ABS_NC(loc, reloc, target, addend, thumb);
- case R_ARM_THM_MOVT_ABS:
- return relocR_ARM_THM_MOVT_ABS(loc, reloc, target, addend);
- case R_ARM_PREL31:
- return relocR_ARM_PREL31(loc, reloc, target, addend, thumb);
- case R_ARM_TLS_IE32:
- return relocR_ARM_TLS_IE32(loc, reloc, target, addend);
- case R_ARM_TLS_LE32:
- return relocR_ARM_TLS_LE32(loc, reloc, target, addend,
- _armLayout.getTPOffset());
- case R_ARM_TLS_TPOFF32:
- return relocR_ARM_TLS_TPOFF32(loc, reloc, target, addend);
- case R_ARM_GOT_BREL:
- return relocR_ARM_GOT_BREL(loc, reloc, target, addend,
- _armLayout.getGOTSymAddr());
- case R_ARM_BASE_PREL:
- // GOT origin is used for NULL symbol and when explicitly specified
- if (!target || ref.target()->name().equals("_GLOBAL_OFFSET_TABLE_")) {
- target = _armLayout.getGOTSymAddr();
- } else {
- return make_dynamic_error_code(
- "Segment-base relative addressing is not supported");
- }
- return relocR_ARM_BASE_PREL(loc, reloc, target, addend);
- case R_ARM_ALU_PC_G0_NC:
- return relocR_ARM_ALU_PC_G0_NC(loc, reloc, target, addend);
- case R_ARM_ALU_PC_G1_NC:
- return relocR_ARM_ALU_PC_G1_NC(loc, reloc, target, addend);
- case R_ARM_LDR_PC_G2:
- return relocR_ARM_LDR_PC_G2(loc, reloc, target, addend);
- case R_ARM_JUMP_SLOT:
- case R_ARM_GLOB_DAT:
- case R_ARM_IRELATIVE:
- // Runtime only relocations. Ignore here.
- return std::error_code();
- case R_ARM_V4BX:
- // TODO implement
- return std::error_code();
- default:
- return make_unhandled_reloc_error();
- }
-
- llvm_unreachable("All switch cases must return directly");
-}
diff --git a/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h b/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h
deleted file mode 100644
index a1f3d091f204..000000000000
--- a/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h
+++ /dev/null
@@ -1,35 +0,0 @@
-//===--------- 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 "lld/ReaderWriter/ELFLinkingContext.h"
-
-namespace lld {
-namespace elf {
-
-class ARMTargetLayout;
-
-class ARMTargetRelocationHandler final : public TargetRelocationHandler {
-public:
- ARMTargetRelocationHandler(ARMTargetLayout &layout) : _armLayout(layout) {}
-
- std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &,
- const AtomLayout &,
- const Reference &) const override;
-
-private:
- ARMTargetLayout &_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
deleted file mode 100644
index fc2ae75cd7a7..000000000000
--- a/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp
+++ /dev/null
@@ -1,985 +0,0 @@
-//===--------- 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/MapVector.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/Support/Debug.h"
-
-using namespace lld;
-using namespace lld::elf;
-using namespace llvm::ELF;
-
-namespace {
-// ARM B/BL instructions of absolute 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_Abs_a_AtomContent[4] = {
- 0x04, 0xf0, 0x1f, 0xe5 // ldr pc, [pc, #-4]
-};
-static const uint8_t Veneer_ARM_B_BL_Abs_d_AtomContent[4] = {
- 0x00, 0x00, 0x00, 0x00 // <target_symbol_address>
-};
-
-// Thumb B/BL instructions of absolute 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_Abs_t_AtomContent[4] = {
- 0x78, 0x47, // bx pc
- 0x00, 0x00 // nop
-};
-static const uint8_t Veneer_THM_B_BL_Abs_a_AtomContent[4] = {
- 0xfe, 0xff, 0xff, 0xea // b <target_symbol_address>
-};
-
-// .got values
-static const uint8_t ARMGotAtomContent[4] = {0};
-
-// .plt value (entry 0)
-static const uint8_t ARMPlt0_a_AtomContent[16] = {
- 0x04, 0xe0, 0x2d, 0xe5, // push {lr}
- 0x04, 0xe0, 0x9f, 0xe5, // ldr lr, [pc, #4]
- 0x0e, 0xe0, 0x8f, 0xe0, // add lr, pc, lr
- 0x00, 0xf0, 0xbe, 0xe5 // ldr pc, [lr, #0]!
-};
-static const uint8_t ARMPlt0_d_AtomContent[4] = {
- 0x00, 0x00, 0x00, 0x00 // <got1_symbol_address>
-};
-
-// .plt values (other entries)
-static const uint8_t ARMPltAtomContent[12] = {
- 0x00, 0xc0, 0x8f, 0xe2, // add ip, pc, #offset[G0]
- 0x00, 0xc0, 0x8c, 0xe2, // add ip, ip, #offset[G1]
- 0x00, 0xf0, 0xbc, 0xe5 // ldr pc, [ip, #offset[G2]]!
-};
-
-// Veneer for switching from Thumb to ARM code for PLT entries.
-static const uint8_t ARMPltVeneerAtomContent[4] = {
- 0x78, 0x47, // bx pc
- 0x00, 0x00 // nop
-};
-
-// Determine proper names for mapping symbols.
-static std::string getMappingAtomName(DefinedAtom::CodeModel model,
- const std::string &part) {
- switch (model) {
- case DefinedAtom::codeARM_a:
- return part.empty() ? "$a" : "$a." + part;
- case DefinedAtom::codeARM_d:
- return part.empty() ? "$d" : "$d." + part;
- case DefinedAtom::codeARM_t:
- return part.empty() ? "$t" : "$t." + part;
- default:
- llvm_unreachable("Wrong code model of mapping atom");
- }
-}
-
-/// \brief Atoms that hold veneer code.
-class VeneerAtom : public SimpleELFDefinedAtom {
- StringRef _section;
-
-public:
- VeneerAtom(const File &f, StringRef secName, const std::string &name = "")
- : SimpleELFDefinedAtom(f), _section(secName), _name(name) {}
-
- 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 4; }
-
- StringRef name() const override { return _name; }
-
-private:
- std::string _name;
-};
-
-/// \brief Atoms that hold veneer for relocated ARM B/BL instructions
-/// in absolute code.
-class Veneer_ARM_B_BL_Abs_a_Atom : public VeneerAtom {
-public:
- Veneer_ARM_B_BL_Abs_a_Atom(const File &f, StringRef secName,
- const std::string &name)
- : VeneerAtom(f, secName, name) {}
-
- ArrayRef<uint8_t> rawContent() const override {
- return llvm::makeArrayRef(Veneer_ARM_B_BL_Abs_a_AtomContent);
- }
-};
-
-class Veneer_ARM_B_BL_Abs_d_Atom : public VeneerAtom {
-public:
- Veneer_ARM_B_BL_Abs_d_Atom(const File &f, StringRef secName)
- : VeneerAtom(f, secName) {}
-
- ArrayRef<uint8_t> rawContent() const override {
- return llvm::makeArrayRef(Veneer_ARM_B_BL_Abs_d_AtomContent);
- }
-};
-
-/// \brief Atoms that hold veneer for relocated Thumb B/BL instructions
-/// in absolute code.
-class Veneer_THM_B_BL_Abs_t_Atom : public VeneerAtom {
-public:
- Veneer_THM_B_BL_Abs_t_Atom(const File &f, StringRef secName,
- const std::string &name)
- : VeneerAtom(f, secName, name) {}
-
- DefinedAtom::CodeModel codeModel() const override {
- return DefinedAtom::codeARMThumb;
- }
-
- ArrayRef<uint8_t> rawContent() const override {
- return llvm::makeArrayRef(Veneer_THM_B_BL_Abs_t_AtomContent);
- }
-};
-
-class Veneer_THM_B_BL_Abs_a_Atom : public VeneerAtom {
-public:
- Veneer_THM_B_BL_Abs_a_Atom(const File &f, StringRef secName)
- : VeneerAtom(f, secName) {}
-
- ArrayRef<uint8_t> rawContent() const override {
- return llvm::makeArrayRef(Veneer_THM_B_BL_Abs_a_AtomContent);
- }
-};
-
-template <DefinedAtom::CodeModel Model>
-class ARMVeneerMappingAtom : public VeneerAtom {
-public:
- ARMVeneerMappingAtom(const File &f, StringRef secName, StringRef name)
- : VeneerAtom(f, secName, getMappingAtomName(Model, name)) {
- static_assert((Model == DefinedAtom::codeARM_a ||
- Model == DefinedAtom::codeARM_d ||
- Model == DefinedAtom::codeARM_t),
- "Only mapping atom types are allowed");
- }
-
- uint64_t size() const override { return 0; }
-
- ArrayRef<uint8_t> rawContent() const override { return ArrayRef<uint8_t>(); }
-
- DefinedAtom::CodeModel codeModel() const override { return Model; }
-};
-
-template <class BaseAtom, DefinedAtom::CodeModel Model>
-class BaseMappingAtom : public BaseAtom {
-public:
- BaseMappingAtom(const File &f, StringRef secName, StringRef name)
- : BaseAtom(f, secName) {
- static_assert((Model == DefinedAtom::codeARM_a ||
- Model == DefinedAtom::codeARM_d ||
- Model == DefinedAtom::codeARM_t),
- "Only mapping atom types are allowed");
-#ifndef NDEBUG
- _name = name;
-#else
- _name = getMappingAtomName(Model, name);
-#endif
- }
-
- DefinedAtom::CodeModel codeModel() const override {
-#ifndef NDEBUG
- return isThumbCode(Model) ? DefinedAtom::codeARMThumb : DefinedAtom::codeNA;
-#else
- return Model;
-#endif
- }
-
- StringRef name() const override { return _name; }
-
-private:
- std::string _name;
-};
-
-/// \brief Atoms that are used by ARM dynamic linking
-class ARMGOTAtom : public GOTAtom {
-public:
- ARMGOTAtom(const File &f) : GOTAtom(f, ".got") {}
-
- ArrayRef<uint8_t> rawContent() const override {
- return llvm::makeArrayRef(ARMGotAtomContent);
- }
-
- Alignment alignment() const override { return 4; }
-
-protected:
- // Constructor for PLTGOT atom.
- ARMGOTAtom(const File &f, StringRef secName) : GOTAtom(f, secName) {}
-};
-
-class ARMGOTPLTAtom : public ARMGOTAtom {
-public:
- ARMGOTPLTAtom(const File &f) : ARMGOTAtom(f, ".got.plt") {}
-};
-
-/// \brief Proxy class to keep type compatibility with PLT0Atom.
-class ARMPLT0Atom : public PLT0Atom {
-public:
- ARMPLT0Atom(const File &f, StringRef) : PLT0Atom(f) {}
-};
-
-/// \brief PLT0 entry atom.
-/// Serves as a mapping symbol in the release mode.
-class ARMPLT0_a_Atom
- : public BaseMappingAtom<ARMPLT0Atom, DefinedAtom::codeARM_a> {
-public:
- ARMPLT0_a_Atom(const File &f, const std::string &name)
- : BaseMappingAtom(f, ".plt", name) {}
-
- ArrayRef<uint8_t> rawContent() const override {
- return llvm::makeArrayRef(ARMPlt0_a_AtomContent);
- }
-
- Alignment alignment() const override { return 4; }
-};
-
-class ARMPLT0_d_Atom
- : public BaseMappingAtom<ARMPLT0Atom, DefinedAtom::codeARM_d> {
-public:
- ARMPLT0_d_Atom(const File &f, const std::string &name)
- : BaseMappingAtom(f, ".plt", name) {}
-
- ArrayRef<uint8_t> rawContent() const override {
- return llvm::makeArrayRef(ARMPlt0_d_AtomContent);
- }
-
- Alignment alignment() const override { return 4; }
-};
-
-/// \brief PLT entry atom.
-/// Serves as a mapping symbol in the release mode.
-class ARMPLTAtom : public BaseMappingAtom<PLTAtom, DefinedAtom::codeARM_a> {
-public:
- ARMPLTAtom(const File &f, const std::string &name)
- : BaseMappingAtom(f, ".plt", name) {}
-
- ArrayRef<uint8_t> rawContent() const override {
- return llvm::makeArrayRef(ARMPltAtomContent);
- }
-
- Alignment alignment() const override { return 4; }
-};
-
-/// \brief Veneer atom for PLT entry.
-/// Serves as a mapping symbol in the release mode.
-class ARMPLTVeneerAtom
- : public BaseMappingAtom<PLTAtom, DefinedAtom::codeARM_t> {
-public:
- ARMPLTVeneerAtom(const File &f, const std::string &name)
- : BaseMappingAtom(f, ".plt", name) {}
-
- ArrayRef<uint8_t> rawContent() const override {
- return llvm::makeArrayRef(ARMPltVeneerAtomContent);
- }
-
- Alignment alignment() const override { return 4; }
-};
-
-/// \brief Atom which represents an object for which a COPY relocation will
-/// be generated.
-class ARMObjectAtom : public ObjectAtom {
-public:
- ARMObjectAtom(const File &f) : ObjectAtom(f) {}
- Alignment alignment() const override { return 4; }
-};
-
-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_ABS32:
- case R_ARM_REL32:
- case R_ARM_TARGET1:
- case R_ARM_MOVW_ABS_NC:
- case R_ARM_MOVT_ABS:
- case R_ARM_THM_MOVW_ABS_NC:
- case R_ARM_THM_MOVT_ABS:
- static_cast<Derived *>(this)->handlePlain(isThumbCode(&atom), ref);
- break;
- case R_ARM_THM_CALL:
- case R_ARM_CALL:
- case R_ARM_JUMP24:
- case R_ARM_THM_JUMP24:
- case R_ARM_THM_JUMP11: {
- const auto actualModel = actualSourceCodeModel(atom, ref);
- const bool fromThumb = isThumbCode(actualModel);
- static_cast<Derived *>(this)->handlePlain(fromThumb, ref);
- static_cast<Derived *>(this)->handleVeneer(atom, fromThumb, ref);
- } break;
- case R_ARM_TLS_IE32:
- static_cast<Derived *>(this)->handleTLSIE32(ref);
- break;
- case R_ARM_GOT_BREL:
- static_cast<Derived *>(this)->handleGOT(ref);
- break;
- default:
- break;
- }
- }
-
-protected:
- /// \brief Determine source atom's actual code model.
- ///
- /// Actual code model may differ from the existing one if fixup
- /// is possible on the later stages for given relocation type.
- DefinedAtom::CodeModel actualSourceCodeModel(const DefinedAtom &atom,
- const Reference &ref) {
- const auto kindValue = ref.kindValue();
- if (kindValue != R_ARM_CALL && kindValue != R_ARM_THM_CALL)
- return atom.codeModel();
-
- // TODO: For unconditional jump instructions (R_ARM_CALL and R_ARM_THM_CALL)
- // fixup isn't possible without veneer generation for archs below ARMv5.
-
- auto actualModel = atom.codeModel();
- if (const auto *da = dyn_cast<DefinedAtom>(ref.target())) {
- actualModel = da->codeModel();
- } else if (const auto *sla = dyn_cast<SharedLibraryAtom>(ref.target())) {
- if (sla->type() == SharedLibraryAtom::Type::Code) {
- // PLT entry will be generated here - assume we don't want a veneer
- // on top of it and prefer instruction fixup if needed.
- actualModel = DefinedAtom::codeNA;
- }
- }
- return actualModel;
- }
-
- std::error_code handleVeneer(const DefinedAtom &atom, bool fromThumb,
- const Reference &ref) {
- // Actual instruction mode differs meaning that further fixup will be
- // applied.
- if (isThumbCode(&atom) != fromThumb)
- return std::error_code();
-
- const VeneerAtom *(Derived::*getVeneer)(const DefinedAtom *, StringRef) =
- nullptr;
- const auto kindValue = ref.kindValue();
- switch (kindValue) {
- case R_ARM_JUMP24:
- getVeneer = &Derived::getVeneer_ARM_B_BL;
- break;
- case R_ARM_THM_JUMP24:
- getVeneer = &Derived::getVeneer_THM_B_BL;
- break;
- default:
- return std::error_code();
- }
-
- // 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 || isThumbCode(target) == isThumbCode(&atom))
- return std::error_code();
-
- // Veneers may only be generated for STT_FUNC target symbols
- // or for symbols located in sections different to the place of relocation.
- 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());
- }
-
- assert(getVeneer && "The veneer handler is missing");
- const Atom *veneer =
- (static_cast<Derived *>(this)->*getVeneer)(target, secName);
-
- assert(veneer && "The veneer is not set");
- const_cast<Reference &>(ref).setTarget(veneer);
- return std::error_code();
- }
-
- /// \brief Get the veneer for ARM B/BL instructions
- /// in absolute code.
- const VeneerAtom *getVeneer_ARM_B_BL_Abs(const DefinedAtom *da,
- StringRef secName) {
- auto veneer = _veneerAtoms.lookup(da);
- if (!veneer.empty())
- return veneer._veneer;
-
- std::string name = "__";
- name += da->name();
- name += "_from_arm";
- // Create parts of veneer with mapping symbols.
- auto v_a =
- new (_file._alloc) Veneer_ARM_B_BL_Abs_a_Atom(_file, secName, name);
- addVeneerWithMapping<DefinedAtom::codeARM_a>(da, v_a, name);
- auto v_d = new (_file._alloc) Veneer_ARM_B_BL_Abs_d_Atom(_file, secName);
- addVeneerWithMapping<DefinedAtom::codeARM_d>(v_a, v_d, name);
-
- // Fake reference to show connection between parts of veneer.
- v_a->addReferenceELF_ARM(R_ARM_NONE, 0, v_d, 0);
- // Real reference to fixup.
- v_d->addReferenceELF_ARM(R_ARM_ABS32, 0, da, 0);
- return v_a;
- }
-
- /// \brief Get the veneer for Thumb B/BL instructions
- /// in absolute code.
- const VeneerAtom *getVeneer_THM_B_BL_Abs(const DefinedAtom *da,
- StringRef secName) {
- auto veneer = _veneerAtoms.lookup(da);
- if (!veneer.empty())
- return veneer._veneer;
-
- std::string name = "__";
- name += da->name();
- name += "_from_thumb";
- // Create parts of veneer with mapping symbols.
- auto v_t =
- new (_file._alloc) Veneer_THM_B_BL_Abs_t_Atom(_file, secName, name);
- addVeneerWithMapping<DefinedAtom::codeARM_t>(da, v_t, name);
- auto v_a = new (_file._alloc) Veneer_THM_B_BL_Abs_a_Atom(_file, secName);
- addVeneerWithMapping<DefinedAtom::codeARM_a>(v_t, v_a, name);
-
- // Fake reference to show connection between parts of veneer.
- v_t->addReferenceELF_ARM(R_ARM_NONE, 0, v_a, 0);
- // Real reference to fixup.
- v_a->addReferenceELF_ARM(R_ARM_JUMP24, 0, da, 0);
- return v_t;
- }
-
- 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) {
- StringRef source;
-#ifndef NDEBUG
- source = "_tls_";
-#endif
- return getGOT<R_ARM_TLS, A>(da, source);
- }
-
- /// \brief Add veneer with mapping symbol.
- template <DefinedAtom::CodeModel Model>
- void addVeneerWithMapping(const DefinedAtom *da, VeneerAtom *va,
- const std::string &name) {
- assert(_veneerAtoms.lookup(da).empty() &&
- "Veneer or mapping already exists");
- auto *ma = new (_file._alloc)
- ARMVeneerMappingAtom<Model>(_file, va->customSectionName(), name);
-
- // Fake reference to show connection between the mapping symbol and veneer.
- va->addReferenceELF_ARM(R_ARM_NONE, 0, ma, 0);
- _veneerAtoms[da] = VeneerWithMapping(va, ma);
- }
-
- /// \brief get a veneer for a PLT entry.
- const PLTAtom *getPLTVeneer(const Atom *da, PLTAtom *pa, StringRef source) {
- std::string name = "__plt_from_thumb";
- name += source.empty() ? "_" : source;
- name += da->name();
- // Create veneer for PLT entry.
- auto va = new (_file._alloc) ARMPLTVeneerAtom(_file, name);
- // Fake reference to show connection between veneer and PLT entry.
- va->addReferenceELF_ARM(R_ARM_NONE, 0, pa, 0);
-
- _pltAtoms[da] = PLTWithVeneer(pa, va);
- return va;
- }
-
- typedef const GOTAtom *(Derived::*GOTFactory)(const Atom *);
-
- /// \brief get a PLT entry referencing PLTGOT entry.
- ///
- /// If the entry does not exist, both GOT and PLT entry are created.
- const PLTAtom *getPLT(const Atom *da, bool fromThumb, GOTFactory gotFactory,
- StringRef source = "") {
- auto pltVeneer = _pltAtoms.lookup(da);
- if (!pltVeneer.empty()) {
- // Return clean PLT entry provided it is ARM code.
- if (!fromThumb)
- return pltVeneer._plt;
-
- // Check if veneer is present for Thumb to ARM transition.
- if (pltVeneer._veneer)
- return pltVeneer._veneer;
-
- // Create veneer for existing PLT entry.
- return getPLTVeneer(da, pltVeneer._plt, source);
- }
-
- // Create specific GOT entry.
- const auto *ga = (static_cast<Derived *>(this)->*gotFactory)(da);
- assert(_gotpltAtoms.lookup(da) == ga &&
- "GOT entry should be added to the PLTGOT map");
- assert(ga->customSectionName() == ".got.plt" &&
- "GOT entry should be in a special section");
-
- std::string name = "__plt";
- name += source.empty() ? "_" : source;
- name += da->name();
- // Create PLT entry for the GOT entry.
- auto pa = new (_file._alloc) ARMPLTAtom(_file, name);
- pa->addReferenceELF_ARM(R_ARM_ALU_PC_G0_NC, 0, ga, -8);
- pa->addReferenceELF_ARM(R_ARM_ALU_PC_G1_NC, 4, ga, -4);
- pa->addReferenceELF_ARM(R_ARM_LDR_PC_G2, 8, ga, 0);
-
- // Since all PLT entries are in ARM code, Thumb to ARM
- // switching should be added if the relocated place contais Thumb code.
- if (fromThumb)
- return getPLTVeneer(da, pa, source);
-
- // Otherwise just add PLT entry and return it to the caller.
- _pltAtoms[da] = PLTWithVeneer(pa);
- return pa;
- }
-
- /// \brief Create the GOT entry for a given IFUNC Atom.
- const GOTAtom *createIFUNCGOT(const Atom *da) {
- assert(!_gotpltAtoms.lookup(da) && "IFUNC GOT entry already exists");
- auto g = new (_file._alloc) ARMGOTPLTAtom(_file);
- g->addReferenceELF_ARM(R_ARM_ABS32, 0, da, 0);
- g->addReferenceELF_ARM(R_ARM_IRELATIVE, 0, da, 0);
-#ifndef NDEBUG
- g->_name = "__got_ifunc_";
- g->_name += da->name();
-#endif
- _gotpltAtoms[da] = g;
- return g;
- }
-
- /// \brief get the PLT entry for a given IFUNC Atom.
- const PLTAtom *getIFUNCPLTEntry(const DefinedAtom *da, bool fromThumb) {
- return getPLT(da, fromThumb, &Derived::createIFUNCGOT, "_ifunc_");
- }
-
- /// \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(bool fromThumb, const Reference &ref) {
- auto target = dyn_cast<const DefinedAtom>(ref.target());
- if (target && target->contentType() == DefinedAtom::typeResolver) {
- const_cast<Reference &>(ref)
- .setTarget(getIFUNCPLTEntry(target, fromThumb));
- }
- return std::error_code();
- }
-
- /// \brief Create a GOT entry containing 0.
- const GOTAtom *getNullGOT() {
- if (!_null) {
- _null = new (_file._alloc) ARMGOTPLTAtom(_file);
-#ifndef NDEBUG
- _null->_name = "__got_null";
-#endif
- }
- return _null;
- }
-
- /// \brief Create regular GOT entry which cannot be used in PLTGOT operation.
- template <Reference::KindValue R_ARM_REL, Reference::Addend A = 0>
- const GOTAtom *getGOT(const Atom *da, StringRef source = "") {
- if (auto got = _gotAtoms.lookup(da))
- return got;
- auto g = new (_file._alloc) ARMGOTAtom(_file);
- g->addReferenceELF_ARM(R_ARM_REL, 0, da, A);
-#ifndef NDEBUG
- g->_name = "__got";
- g->_name += source.empty() ? "_" : source;
- g->_name += da->name();
-#endif
- _gotAtoms[da] = g;
- return g;
- }
-
- /// \brief get GOT entry for a regular defined atom.
- const GOTAtom *getGOTEntry(const DefinedAtom *da) {
- return getGOT<R_ARM_ABS32>(da);
- }
-
- std::error_code handleGOT(const Reference &ref) {
- if (isa<UndefinedAtom>(ref.target()))
- const_cast<Reference &>(ref).setTarget(getNullGOT());
- else if (const auto *da = dyn_cast<DefinedAtom>(ref.target()))
- const_cast<Reference &>(ref).setTarget(getGOTEntry(da));
- return std::error_code();
- }
-
-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.
- std::error_code perform(SimpleFile &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;
- if (_plt0) {
- _plt0->setOrdinal(ordinal++);
- mf.addAtom(*_plt0);
- _plt0_d->setOrdinal(ordinal++);
- mf.addAtom(*_plt0_d);
- }
- for (auto &pltKV : _pltAtoms) {
- auto &plt = pltKV.second;
- if (auto *v = plt._veneer) {
- v->setOrdinal(ordinal++);
- mf.addAtom(*v);
- }
- auto *p = plt._plt;
- p->setOrdinal(ordinal++);
- mf.addAtom(*p);
- }
- if (_null) {
- _null->setOrdinal(ordinal++);
- mf.addAtom(*_null);
- }
- if (_plt0) {
- _got0->setOrdinal(ordinal++);
- mf.addAtom(*_got0);
- _got1->setOrdinal(ordinal++);
- mf.addAtom(*_got1);
- }
- for (auto &gotKV : _gotAtoms) {
- auto &got = gotKV.second;
- got->setOrdinal(ordinal++);
- mf.addAtom(*got);
- }
- for (auto &gotKV : _gotpltAtoms) {
- auto &got = gotKV.second;
- got->setOrdinal(ordinal++);
- mf.addAtom(*got);
- }
- for (auto &objectKV : _objectAtoms) {
- auto &obj = objectKV.second;
- obj->setOrdinal(ordinal++);
- mf.addAtom(*obj);
- }
- for (auto &veneerKV : _veneerAtoms) {
- auto &veneer = veneerKV.second;
- auto *m = veneer._mapping;
- m->setOrdinal(ordinal++);
- mf.addAtom(*m);
- auto *v = veneer._veneer;
- v->setOrdinal(ordinal++);
- mf.addAtom(*v);
- }
-
- return std::error_code();
- }
-
-protected:
- /// \brief Owner of all the Atoms created by this pass.
- ELFPassFile _file;
- const ELFLinkingContext &_ctx;
-
- /// \brief Map Atoms to their GOT entries.
- llvm::MapVector<const Atom *, GOTAtom *> _gotAtoms;
-
- /// \brief Map Atoms to their PLTGOT entries.
- llvm::MapVector<const Atom *, GOTAtom *> _gotpltAtoms;
-
- /// \brief Map Atoms to their Object entries.
- llvm::MapVector<const Atom *, ObjectAtom *> _objectAtoms;
-
- /// \brief Map Atoms to their PLT entries depending on the code model.
- struct PLTWithVeneer {
- PLTWithVeneer(PLTAtom *p = nullptr, PLTAtom *v = nullptr)
- : _plt(p), _veneer(v) {}
-
- bool empty() const {
- assert((_plt || !_veneer) && "Veneer appears without PLT entry");
- return !_plt && !_veneer;
- }
-
- PLTAtom *_plt;
- PLTAtom *_veneer;
- };
- llvm::MapVector<const Atom *, PLTWithVeneer> _pltAtoms;
-
- /// \brief Map Atoms to their veneers.
- struct VeneerWithMapping {
- VeneerWithMapping(VeneerAtom *v = nullptr, VeneerAtom *m = nullptr)
- : _veneer(v), _mapping(m) {}
-
- bool empty() const {
- assert(((bool)_veneer == (bool)_mapping) &&
- "Mapping symbol should always be paired with veneer");
- return !_veneer && !_mapping;
- }
-
- VeneerAtom *_veneer;
- VeneerAtom *_mapping;
- };
- llvm::MapVector<const Atom *, VeneerWithMapping> _veneerAtoms;
-
- /// \brief GOT entry that is always 0. Used for undefined weaks.
- GOTAtom *_null = nullptr;
-
- /// \brief The got and plt entries for .PLT0. This is used to call into the
- /// dynamic linker for symbol resolution.
- /// @{
- PLT0Atom *_plt0 = nullptr;
- PLT0Atom *_plt0_d = nullptr;
- GOTAtom *_got0 = nullptr;
- GOTAtom *_got1 = nullptr;
- /// @}
-};
-
-/// 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 Handle ordinary relocation references.
- std::error_code handlePlain(bool fromThumb, const Reference &ref) {
- return handleIFUNC(fromThumb, ref);
- }
-
- /// \brief Get the veneer for ARM B/BL instructions.
- const VeneerAtom *getVeneer_ARM_B_BL(const DefinedAtom *da,
- StringRef secName) {
- return getVeneer_ARM_B_BL_Abs(da, secName);
- }
-
- /// \brief Get the veneer for Thumb B/BL instructions.
- const VeneerAtom *getVeneer_THM_B_BL(const DefinedAtom *da,
- StringRef secName) {
- return getVeneer_THM_B_BL_Abs(da, secName);
- }
-
- /// \brief Create a GOT entry for R_ARM_TLS_TPOFF32 reloc.
- const GOTAtom *getTLSTPOFF32(const DefinedAtom *da) {
- return getGOTTLSEntry<R_ARM_TLS_LE32>(da);
- }
-};
-
-/// This implements the dynamic relocation model. GOT and PLT entries are
-/// created for references that cannot be directly resolved.
-class ARMDynamicRelocationPass final
- : public ARMRelocationPass<ARMDynamicRelocationPass> {
-public:
- ARMDynamicRelocationPass(const elf::ARMLinkingContext &ctx)
- : ARMRelocationPass(ctx) {}
-
- /// \brief get the PLT entry for a given atom.
- const PLTAtom *getPLTEntry(const SharedLibraryAtom *sla, bool fromThumb) {
- return getPLT(sla, fromThumb, &ARMDynamicRelocationPass::createPLTGOT);
- }
-
- /// \brief Create the GOT entry for a given atom.
- const GOTAtom *createPLTGOT(const Atom *da) {
- assert(!_gotpltAtoms.lookup(da) && "PLTGOT entry already exists");
- auto g = new (_file._alloc) ARMGOTPLTAtom(_file);
- g->addReferenceELF_ARM(R_ARM_ABS32, 0, getPLT0(), 0);
- g->addReferenceELF_ARM(R_ARM_JUMP_SLOT, 0, da, 0);
-#ifndef NDEBUG
- g->_name = "__got_plt0_";
- g->_name += da->name();
-#endif
- _gotpltAtoms[da] = g;
- return g;
- }
-
- const ObjectAtom *getObjectEntry(const SharedLibraryAtom *a) {
- if (auto obj = _objectAtoms.lookup(a))
- return obj;
-
- auto oa = new (_file._alloc) ARMObjectAtom(_file);
- oa->addReferenceELF_ARM(R_ARM_COPY, 0, oa, 0);
-
- oa->_name = a->name();
- oa->_size = a->size();
-
- _objectAtoms[a] = oa;
- return oa;
- }
-
- /// \brief Handle ordinary relocation references.
- std::error_code handlePlain(bool fromThumb, const Reference &ref) {
- if (auto sla = dyn_cast<SharedLibraryAtom>(ref.target())) {
- if (sla->type() == SharedLibraryAtom::Type::Data &&
- _ctx.getOutputELFType() == llvm::ELF::ET_EXEC) {
- const_cast<Reference &>(ref).setTarget(getObjectEntry(sla));
- } else if (sla->type() == SharedLibraryAtom::Type::Code) {
- const_cast<Reference &>(ref).setTarget(getPLTEntry(sla, fromThumb));
- }
- return std::error_code();
- }
- return handleIFUNC(fromThumb, ref);
- }
-
- /// \brief Get the veneer for ARM B/BL instructions.
- const VeneerAtom *getVeneer_ARM_B_BL(const DefinedAtom *da,
- StringRef secName) {
- if (_ctx.getOutputELFType() == llvm::ELF::ET_EXEC) {
- return getVeneer_ARM_B_BL_Abs(da, secName);
- }
- llvm_unreachable("Handle ARM veneer for DSOs");
- }
-
- /// \brief Get the veneer for Thumb B/BL instructions.
- const VeneerAtom *getVeneer_THM_B_BL(const DefinedAtom *da,
- StringRef secName) {
- if (_ctx.getOutputELFType() == llvm::ELF::ET_EXEC) {
- return getVeneer_THM_B_BL_Abs(da, secName);
- }
- llvm_unreachable("Handle Thumb veneer for DSOs");
- }
-
- /// \brief Create a GOT entry for R_ARM_TLS_TPOFF32 reloc.
- const GOTAtom *getTLSTPOFF32(const DefinedAtom *da) {
- return getGOTTLSEntry<R_ARM_TLS_TPOFF32>(da);
- }
-
- const PLT0Atom *getPLT0() {
- if (_plt0)
- return _plt0;
- // Fill in the null entry.
- getNullGOT();
- _plt0 = new (_file._alloc) ARMPLT0_a_Atom(_file, "__PLT0");
- _plt0_d = new (_file._alloc) ARMPLT0_d_Atom(_file, "__PLT0_d");
- _got0 = new (_file._alloc) ARMGOTPLTAtom(_file);
- _got1 = new (_file._alloc) ARMGOTPLTAtom(_file);
- _plt0_d->addReferenceELF_ARM(R_ARM_REL32, 0, _got1, 0);
- // Fake reference to show connection between the GOT and PLT entries.
- _plt0->addReferenceELF_ARM(R_ARM_NONE, 0, _got0, 0);
- // Fake reference to show connection between parts of PLT entry.
- _plt0->addReferenceELF_ARM(R_ARM_NONE, 0, _plt0_d, 0);
-#ifndef NDEBUG
- _got0->_name = "__got0";
- _got1->_name = "__got1";
-#endif
- return _plt0;
- }
-
- const GOTAtom *getSharedGOTEntry(const SharedLibraryAtom *sla) {
- return getGOT<R_ARM_GLOB_DAT>(sla);
- }
-
- std::error_code handleGOT(const Reference &ref) {
- if (const auto sla = dyn_cast<const SharedLibraryAtom>(ref.target())) {
- const_cast<Reference &>(ref).setTarget(getSharedGOTEntry(sla));
- return std::error_code();
- }
- return ARMRelocationPass::handleGOT(ref);
- }
-};
-
-} // 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())
- return llvm::make_unique<ARMDynamicRelocationPass>(ctx);
- return llvm::make_unique<ARMStaticRelocationPass>(ctx);
- case llvm::ELF::ET_DYN:
- return llvm::make_unique<ARMDynamicRelocationPass>(ctx);
- default:
- llvm_unreachable("Unhandled output file type");
- }
-}
diff --git a/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.h b/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.h
deleted file mode 100644
index 651e798f33b1..000000000000
--- a/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.h
+++ /dev/null
@@ -1,31 +0,0 @@
-//===--------- 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
deleted file mode 100644
index 85b9c9162589..000000000000
--- a/lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h
+++ /dev/null
@@ -1,59 +0,0 @@
-//===--------- 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
-
-#include "SectionChunks.h"
-#include "TargetLayout.h"
-#include "ARMELFFile.h"
-
-namespace lld {
-namespace elf {
-
-/// \brief The SymbolTable class represents the symbol table in a ELF file
-class ARMSymbolTable : public SymbolTable<ELF32LE> {
-public:
- typedef llvm::object::Elf_Sym_Impl<ELF32LE> Elf_Sym;
-
- ARMSymbolTable(const ELFLinkingContext &ctx);
-
- void addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da,
- int64_t addr) override;
-};
-
-ARMSymbolTable::ARMSymbolTable(const ELFLinkingContext &ctx)
- : SymbolTable(ctx, ".symtab", TargetLayout<ELF32LE>::ORDER_SYMBOL_TABLE) {}
-
-void ARMSymbolTable::addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da,
- int64_t addr) {
- SymbolTable::addDefinedAtom(sym, da, addr);
-
- if ((ARMELFDefinedAtom::ARMContentType)da->contentType() ==
- ARMELFDefinedAtom::typeARMExidx)
- sym.st_value = addr;
-
- // Set zero bit to distinguish real symbols addressing Thumb instructions.
- // Don't care about mapping symbols like $t and others.
- if (DefinedAtom::codeARMThumb == da->codeModel())
- sym.st_value = static_cast<int64_t>(sym.st_value) | 0x1;
-
- // Mapping symbols should have special values of binding, type and size set.
- if ((DefinedAtom::codeARM_a == da->codeModel()) ||
- (DefinedAtom::codeARM_d == da->codeModel()) ||
- (DefinedAtom::codeARM_t == da->codeModel())) {
- sym.setBindingAndType(llvm::ELF::STB_LOCAL, llvm::ELF::STT_NOTYPE);
- sym.st_size = 0;
- }
-}
-
-} // 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
deleted file mode 100644
index e1f5eadbe789..000000000000
--- a/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-//===--------- 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 "ARMDynamicLibraryWriter.h"
-#include "ARMTargetHandler.h"
-#include "ARMLinkingContext.h"
-
-using namespace lld;
-using namespace elf;
-
-ARMTargetHandler::ARMTargetHandler(ARMLinkingContext &ctx)
- : _ctx(ctx), _targetLayout(new ARMTargetLayout(ctx)),
- _relocationHandler(new ARMTargetRelocationHandler(*_targetLayout)) {}
-
-std::unique_ptr<Writer> ARMTargetHandler::getWriter() {
- switch (this->_ctx.getOutputELFType()) {
- case llvm::ELF::ET_EXEC:
- return llvm::make_unique<ARMExecutableWriter>(_ctx, *_targetLayout);
- case llvm::ELF::ET_DYN:
- return llvm::make_unique<ARMDynamicLibraryWriter>(_ctx, *_targetLayout);
- default:
- llvm_unreachable("unsupported output type");
- }
-}
diff --git a/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h b/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h
deleted file mode 100644
index 0352e81a1f61..000000000000
--- a/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h
+++ /dev/null
@@ -1,174 +0,0 @@
-//===--------- 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 "ARMRelocationHandler.h"
-#include "ELFReader.h"
-#include "TargetLayout.h"
-
-namespace lld {
-class ELFLinkingContext;
-
-namespace elf {
-
-/// \brief ARM specific section (.ARM.exidx) with indexes to exception handlers
-class ARMExidxSection : public AtomSection<ELF32LE> {
- typedef AtomSection<ELF32LE> Base;
-
-public:
- ARMExidxSection(const ELFLinkingContext &ctx, StringRef sectionName,
- int32_t permissions, int32_t order)
- : Base(ctx, sectionName, ARMELFDefinedAtom::typeARMExidx, permissions,
- order) {
- this->_type = SHT_ARM_EXIDX;
- this->_isLoadedInMemory = true;
- }
-
- bool hasOutputSegment() const override { return true; }
-
- const AtomLayout *appendAtom(const Atom *atom) override {
- const DefinedAtom *definedAtom = cast<DefinedAtom>(atom);
- assert((ARMELFDefinedAtom::ARMContentType)definedAtom->contentType() ==
- ARMELFDefinedAtom::typeARMExidx &&
- "atom content type for .ARM.exidx section has to be typeARMExidx");
-
- DefinedAtom::Alignment atomAlign = definedAtom->alignment();
- uint64_t fOffset = alignOffset(this->fileSize(), atomAlign);
- uint64_t mOffset = alignOffset(this->memSize(), atomAlign);
-
- _atoms.push_back(new (_alloc) AtomLayout(atom, fOffset, 0));
- this->_fsize = fOffset + definedAtom->size();
- this->_msize = mOffset + definedAtom->size();
- DEBUG_WITH_TYPE("Section", llvm::dbgs()
- << "[" << this->name() << " " << this << "] "
- << "Adding atom: " << atom->name() << "@"
- << fOffset << "\n");
-
- uint64_t alignment = atomAlign.value;
- if (this->_alignment < alignment)
- this->_alignment = alignment;
-
- return _atoms.back();
- }
-};
-
-class ARMTargetLayout : public TargetLayout<ELF32LE> {
-public:
- enum ARMSectionOrder {
- ORDER_ARM_EXIDX = TargetLayout::ORDER_EH_FRAME + 1,
- };
-
- ARMTargetLayout(ELFLinkingContext &ctx) : TargetLayout(ctx) {}
-
- SectionOrder getSectionOrder(StringRef name, int32_t contentType,
- int32_t contentPermissions) override {
- switch (contentType) {
- case ARMELFDefinedAtom::typeARMExidx:
- return ORDER_ARM_EXIDX;
- default:
- return TargetLayout::getSectionOrder(name, contentType,
- contentPermissions);
- }
- }
-
- StringRef getOutputSectionName(StringRef archivePath, StringRef memberPath,
- StringRef inputSectionName) const override {
- return llvm::StringSwitch<StringRef>(inputSectionName)
- .StartsWith(".ARM.exidx", ".ARM.exidx")
- .StartsWith(".ARM.extab", ".ARM.extab")
- .Default(TargetLayout::getOutputSectionName(archivePath, memberPath,
- inputSectionName));
- }
-
- SegmentType getSegmentType(const Section<ELF32LE> *section) const override {
- switch (section->order()) {
- case ORDER_ARM_EXIDX:
- return llvm::ELF::PT_ARM_EXIDX;
- default:
- return TargetLayout::getSegmentType(section);
- }
- }
-
- AtomSection<ELF32LE> *
- createSection(StringRef name, int32_t contentType,
- DefinedAtom::ContentPermissions contentPermissions,
- SectionOrder sectionOrder) override {
- if ((ARMELFDefinedAtom::ARMContentType)contentType ==
- ARMELFDefinedAtom::typeARMExidx)
- return new ARMExidxSection(_ctx, name, contentPermissions, sectionOrder);
-
- return TargetLayout::createSection(name, contentType, contentPermissions,
- sectionOrder);
- }
-
- uint64_t getGOTSymAddr() {
- std::call_once(_gotSymOnce, [this]() {
- if (AtomLayout *gotAtom = findAbsoluteAtom("_GLOBAL_OFFSET_TABLE_"))
- _gotSymAddr = gotAtom->_virtualAddr;
- });
- return _gotSymAddr;
- }
-
- uint64_t getTPOffset() {
- std::call_once(_tpOffOnce, [this]() {
- for (const auto &phdr : *_programHeader) {
- if (phdr->p_type == llvm::ELF::PT_TLS) {
- _tpOff = llvm::RoundUpToAlignment(TCB_SIZE, phdr->p_align);
- break;
- }
- }
- assert(_tpOff != 0 && "TLS segment not found");
- });
- return _tpOff;
- }
-
- bool target1Rel() const { return _ctx.armTarget1Rel(); }
-
-private:
- // TCB block size of the TLS.
- enum { TCB_SIZE = 0x8 };
-
-private:
- uint64_t _gotSymAddr = 0;
- uint64_t _tpOff = 0;
- std::once_flag _gotSymOnce;
- std::once_flag _tpOffOnce;
-};
-
-class ARMTargetHandler final : public TargetHandler {
-public:
- ARMTargetHandler(ARMLinkingContext &ctx);
-
- const TargetRelocationHandler &getRelocationHandler() const override {
- return *_relocationHandler;
- }
-
- std::unique_ptr<Reader> getObjReader() override {
- return llvm::make_unique<ELFReader<ARMELFFile>>(_ctx);
- }
-
- std::unique_ptr<Reader> getDSOReader() override {
- return llvm::make_unique<ELFReader<DynamicFile<ELF32LE>>>(_ctx);
- }
-
- std::unique_ptr<Writer> getWriter() override;
-
-private:
- ARMLinkingContext &_ctx;
- std::unique_ptr<ARMTargetLayout> _targetLayout;
- std::unique_ptr<ARMTargetRelocationHandler> _relocationHandler;
-};
-
-} // 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
deleted file mode 100644
index c8cd6533d902..000000000000
--- a/lib/ReaderWriter/ELF/ARM/CMakeLists.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-add_lld_library(lldARMELFTarget
- ARMLinkingContext.cpp
- ARMTargetHandler.cpp
- ARMRelocationHandler.cpp
- ARMRelocationPass.cpp
- LINK_LIBS
- lldELF
- lldReaderWriter
- lldCore
- LLVMObject
- LLVMSupport
- )
diff --git a/lib/ReaderWriter/ELF/ARM/TODO.rst b/lib/ReaderWriter/ELF/ARM/TODO.rst
deleted file mode 100644
index 61b585ae698c..000000000000
--- a/lib/ReaderWriter/ELF/ARM/TODO.rst
+++ /dev/null
@@ -1,21 +0,0 @@
-ELF ARM
-~~~~~~~~~~~
-
-Unimplemented Features
-######################
-
-* DSO linking
-* C++ code linking
-* PLT entries' generation for images larger than 2^28 bytes (see Sec. A.3 of the ARM ELF reference)
-* ARM/Thumb interwork veneers in position-independent code
-* .ARM.exidx section (exception handling)
-* -init/-fini options
-* Proper debug information (DWARF data)
-* TLS relocations for dynamic models
-* Lots of other 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.cpp b/lib/ReaderWriter/ELF/Atoms.cpp
deleted file mode 100644
index 639633393161..000000000000
--- a/lib/ReaderWriter/ELF/Atoms.cpp
+++ /dev/null
@@ -1,297 +0,0 @@
-//===- lib/ReaderWriter/ELF/Atoms.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 "DynamicFile.h"
-#include "ELFFile.h"
-#include "TargetHandler.h"
-
-namespace lld {
-namespace elf {
-
-template <class ELFT> AbsoluteAtom::Scope ELFAbsoluteAtom<ELFT>::scope() const {
- if (_symbol->getVisibility() == llvm::ELF::STV_HIDDEN)
- return scopeLinkageUnit;
- if (_symbol->getBinding() == llvm::ELF::STB_LOCAL)
- return scopeTranslationUnit;
- return scopeGlobal;
-}
-
-template <class ELFT>
-UndefinedAtom::CanBeNull ELFUndefinedAtom<ELFT>::canBeNull() const {
- if (_symbol->getBinding() == llvm::ELF::STB_WEAK)
- return CanBeNull::canBeNullAtBuildtime;
- return CanBeNull::canBeNullNever;
-}
-
-template <class ELFT> uint64_t ELFDefinedAtom<ELFT>::size() const {
- // 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();
-}
-
-template <class ELFT> AbsoluteAtom::Scope ELFDefinedAtom<ELFT>::scope() const {
- if (!_symbol)
- return scopeGlobal;
- if (_symbol->getVisibility() == llvm::ELF::STV_HIDDEN)
- return scopeLinkageUnit;
- if (_symbol->getBinding() != llvm::ELF::STB_LOCAL)
- return scopeGlobal;
- return scopeTranslationUnit;
-}
-
-template <class ELFT> DefinedAtom::Merge ELFDefinedAtom<ELFT>::merge() const {
- 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;
-}
-
-template <class ELFT>
-DefinedAtom::ContentType ELFDefinedAtom<ELFT>::doContentType() const {
- using namespace llvm::ELF;
-
- if (_section->sh_type == SHT_GROUP)
- return typeGroupComdat;
- if (!_symbol && _sectionName.startswith(".gnu.linkonce"))
- return typeGnuLinkOnce;
-
- uint64_t flags = _section->sh_flags;
-
- if (!(flags & SHF_ALLOC)) {
- if (_section->sh_type == SHT_NOTE)
- return (flags == SHF_WRITE) ? typeRWNote : typeRONote;
- return _contentType = typeNoAlloc;
- }
-
- if (_section->sh_flags == (SHF_ALLOC | SHF_WRITE | SHF_TLS))
- return _section->sh_type == SHT_NOBITS ? typeThreadZeroFill
- : typeThreadData;
-
- if (_section->sh_flags == SHF_ALLOC && _section->sh_type == SHT_PROGBITS)
- return _contentType = typeConstant;
- if (_symbol->getType() == STT_GNU_IFUNC)
- return _contentType = typeResolver;
- if (_symbol->st_shndx == SHN_COMMON)
- return _contentType = typeZeroFill;
-
- if (_section->sh_type == SHT_PROGBITS) {
- flags &= ~SHF_ALLOC;
- flags &= ~SHF_GROUP;
- if ((flags & SHF_STRINGS) || (flags & SHF_MERGE))
- return typeConstant;
- if (flags == SHF_WRITE)
- return typeData;
- return typeCode;
- }
- if (_section->sh_type == SHT_NOTE) {
- flags &= ~SHF_ALLOC;
- return (flags == SHF_WRITE) ? typeRWNote : typeRONote;
- }
- if (_section->sh_type == SHT_NOBITS)
- return typeZeroFill;
-
- if (_section->sh_type == SHT_NULL)
- if (_symbol->getType() == STT_COMMON || _symbol->st_shndx == SHN_COMMON)
- return typeZeroFill;
-
- if (_section->sh_type == SHT_INIT_ARRAY ||
- _section->sh_type == SHT_FINI_ARRAY)
- return typeData;
- return typeUnknown;
-}
-
-template <class ELFT>
-DefinedAtom::ContentType ELFDefinedAtom<ELFT>::contentType() const {
- if (_contentType != typeUnknown)
- return _contentType;
- _contentType = doContentType();
- return _contentType;
-}
-
-template <class ELFT>
-DefinedAtom::Alignment ELFDefinedAtom<ELFT>::alignment() const {
- if (!_symbol)
- return 1;
-
- // Obtain proper value of st_value field.
- const auto symValue = getSymbolValue();
-
- // 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 symValue;
- }
- if (_section->sh_addralign == 0) {
- // sh_addralign of 0 means no alignment
- return Alignment(1, symValue);
- }
- return Alignment(_section->sh_addralign, symValue % _section->sh_addralign);
-}
-
-// Do we have a choice for ELF? All symbols live in explicit sections.
-template <class ELFT>
-DefinedAtom::SectionChoice ELFDefinedAtom<ELFT>::sectionChoice() const {
- 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;
-}
-
-template <class ELFT>
-StringRef ELFDefinedAtom<ELFT>::customSectionName() const {
- if ((contentType() == typeZeroFill) ||
- (_symbol && _symbol->st_shndx == llvm::ELF::SHN_COMMON))
- return ".bss";
- return _sectionName;
-}
-
-template <class ELFT>
-DefinedAtom::ContentPermissions ELFDefinedAtom<ELFT>::permissions() const {
- 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___;
- }
-}
-
-template <class ELFT>
-DefinedAtom::reference_iterator ELFDefinedAtom<ELFT>::begin() const {
- uintptr_t index = _referenceStartIndex;
- const void *it = reinterpret_cast<const void *>(index);
- return reference_iterator(*this, it);
-}
-
-template <class ELFT>
-DefinedAtom::reference_iterator ELFDefinedAtom<ELFT>::end() const {
- uintptr_t index = _referenceEndIndex;
- const void *it = reinterpret_cast<const void *>(index);
- return reference_iterator(*this, it);
-}
-
-template <class ELFT>
-const Reference *ELFDefinedAtom<ELFT>::derefIterator(const void *It) const {
- uintptr_t index = reinterpret_cast<uintptr_t>(It);
- assert(index >= _referenceStartIndex);
- assert(index < _referenceEndIndex);
- return ((_referenceList)[index]);
-}
-
-template <class ELFT>
-void ELFDefinedAtom<ELFT>::incrementIterator(const void *&It) const {
- uintptr_t index = reinterpret_cast<uintptr_t>(It);
- ++index;
- It = reinterpret_cast<const void *>(index);
-}
-
-template <class ELFT>
-void ELFDefinedAtom<ELFT>::addReference(ELFReference<ELFT> *reference) {
- _referenceList.push_back(reference);
- _referenceEndIndex = _referenceList.size();
-}
-
-template <class ELFT> AbsoluteAtom::Scope ELFDynamicAtom<ELFT>::scope() const {
- if (_symbol->getVisibility() == llvm::ELF::STV_HIDDEN)
- return scopeLinkageUnit;
- if (_symbol->getBinding() != llvm::ELF::STB_LOCAL)
- return scopeGlobal;
- return scopeTranslationUnit;
-}
-
-template <class ELFT>
-SharedLibraryAtom::Type ELFDynamicAtom<ELFT>::type() const {
- 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;
- }
-}
-
-#define INSTANTIATE(klass) \
- template class klass<ELF32LE>; \
- template class klass<ELF32BE>; \
- template class klass<ELF64LE>; \
- template class klass<ELF64BE>
-
-INSTANTIATE(ELFAbsoluteAtom);
-INSTANTIATE(ELFDefinedAtom);
-INSTANTIATE(ELFDynamicAtom);
-INSTANTIATE(ELFUndefinedAtom);
-
-} // end namespace elf
-} // end namespace lld
diff --git a/lib/ReaderWriter/ELF/Atoms.h b/lib/ReaderWriter/ELF/Atoms.h
deleted file mode 100644
index 390c0e16baf8..000000000000
--- a/lib/ReaderWriter/ELF/Atoms.h
+++ /dev/null
@@ -1,493 +0,0 @@
-//===- 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 "lld/ReaderWriter/ELFLinkingContext.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),
- _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),
- _targetSymbolIndex(idx), _offsetInAtom(off) {}
-
- ELFReference(uint32_t edgeKind)
- : Reference(Reference::KindNamespace::all, Reference::KindArch::all,
- edgeKind) {}
-
- 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 = nullptr;
- uint64_t _targetSymbolIndex = 0;
- uint64_t _offsetInAtom = 0;
- Addend _addend = 0;
-};
-
-/// \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;
- 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 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;
-
-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() override = default;
-
- 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;
- Scope scope() const override;
-
- // FIXME: Need to revisit this in future.
- Interposable interposable() const override { return interposeNo; }
-
- Merge merge() const override;
- ContentType contentType() const override;
- Alignment alignment() const override;
- SectionChoice sectionChoice() const override;
- StringRef customSectionName() const override;
-
- // It isn't clear that __attribute__((used)) is transmitted to the ELF object
- // file.
- DeadStripKind deadStrip() const override { return deadStripNormal; }
-
- ContentPermissions permissions() const override;
- ArrayRef<uint8_t> rawContent() const override { return _contentData; }
-
- DefinedAtom::reference_iterator begin() const override;
- DefinedAtom::reference_iterator end() const override;
- const Reference *derefIterator(const void *It) const override;
- void incrementIterator(const void *&It) const override;
- void addReference(ELFReference<ELFT> *reference);
-
- 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 {
- return _symbol->st_value;
- }
-
- ContentType doContentType() const;
-
- 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(_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(_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;
- StringRef loadName() const override { return _loadName; }
-
- bool canBeNullAtRuntime() const override {
- return _symbol->getBinding() == llvm::ELF::STB_WEAK;
- }
-
- Type type() const override;
- 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 *t, Reference::Addend a) {
- addReference(Reference::KindNamespace::ELF, arch, kindValue, off, t, a);
- }
-
- void addReferenceELF_Hexagon(Reference::KindValue relocType, uint64_t off,
- const Atom *t, Reference::Addend a) {
- addReferenceELF(Reference::KindArch::Hexagon, relocType, off, t, a);
- }
-
- void addReferenceELF_x86_64(Reference::KindValue relocType, uint64_t off,
- const Atom *t, Reference::Addend a) {
- addReferenceELF(Reference::KindArch::x86_64, relocType, off, t, a);
- }
-
- void addReferenceELF_Mips(Reference::KindValue relocType, uint64_t off,
- const Atom *t, Reference::Addend a) {
- addReferenceELF(Reference::KindArch::Mips, relocType, off, t, a);
- }
-
- void addReferenceELF_AArch64(Reference::KindValue relocType, uint64_t off,
- const Atom *t, Reference::Addend a) {
- addReferenceELF(Reference::KindArch::AArch64, relocType, off, t, a);
- }
-
- void addReferenceELF_ARM(Reference::KindValue relocType, uint64_t off,
- const Atom *t, Reference::Addend a) {
- 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 { return 8; }
- 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 { return 8; }
-
-#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 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 GlobalOffsetTableAtom : public SimpleELFDefinedAtom {
-public:
- GlobalOffsetTableAtom(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 { return 8; }
- 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 1; }
- ArrayRef<uint8_t> rawContent() const override { return ArrayRef<uint8_t>(); }
-};
-
-} // end namespace elf
-} // end namespace lld
-
-#endif // LLD_READER_WRITER_ELF_ATOMS_H
diff --git a/lib/ReaderWriter/ELF/CMakeLists.txt b/lib/ReaderWriter/ELF/CMakeLists.txt
deleted file mode 100644
index 3bc338507db6..000000000000
--- a/lib/ReaderWriter/ELF/CMakeLists.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-add_lld_library(lldELF
- Atoms.cpp
- DynamicFile.cpp
- ELFFile.cpp
- ELFLinkingContext.cpp
- FileCommon.cpp
- HeaderChunks.cpp
- OutputELFWriter.cpp
- Reader.cpp
- SectionChunks.cpp
- SegmentChunks.cpp
- TargetLayout.cpp
- Writer.cpp
- LINK_LIBS
- lldReaderWriter
- lldCore
- lldYAML
- LLVMObject
- 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
deleted file mode 100644
index f223b6c54163..000000000000
--- a/lib/ReaderWriter/ELF/Chunk.h
+++ /dev/null
@@ -1,111 +0,0 @@
-//===- 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 &ctx)
- : _name(name), _kind(kind), _ctx(ctx) {}
-
- 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; }
-
- // Returns 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() {}
-
- // Finalize the chunk before writing
- virtual void finalize() {}
-
-protected:
- StringRef _name;
- Kind _kind;
- const ELFLinkingContext &_ctx;
- uint64_t _fsize = 0;
- uint64_t _msize = 0;
- uint64_t _alignment = 1;
- uint32_t _order = 0;
- uint64_t _ordinal = 1;
- uint64_t _start = 0;
- uint64_t _fileoffset = 0;
-};
-
-} // end namespace elf
-} // end namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/ELF/DynamicFile.cpp b/lib/ReaderWriter/ELF/DynamicFile.cpp
deleted file mode 100644
index 5339c7d66577..000000000000
--- a/lib/ReaderWriter/ELF/DynamicFile.cpp
+++ /dev/null
@@ -1,146 +0,0 @@
-//===- lib/ReaderWriter/ELF/DynamicFile.cpp -------------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "DynamicFile.h"
-#include "FileCommon.h"
-#include "lld/ReaderWriter/ELFLinkingContext.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/Object/ELF.h"
-#include "llvm/Support/Path.h"
-
-namespace lld {
-namespace elf {
-
-template <class ELFT>
-DynamicFile<ELFT>::DynamicFile(std::unique_ptr<MemoryBuffer> mb,
- ELFLinkingContext &ctx)
- : SharedLibraryFile(mb->getBufferIdentifier()), _mb(std::move(mb)),
- _ctx(ctx), _useShlibUndefines(ctx.useShlibUndefines()) {}
-
-template <typename ELFT>
-std::error_code DynamicFile<ELFT>::isCompatible(MemoryBufferRef mb,
- ELFLinkingContext &ctx) {
- return elf::isCompatible<ELFT>(mb, ctx);
-}
-
-template <class ELFT>
-const SharedLibraryAtom *DynamicFile<ELFT>::exports(StringRef name,
- bool dataSymbolOnly) const {
- 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);
-}
-
-template <class ELFT> StringRef DynamicFile<ELFT>::getDSOName() const {
- return _soname;
-}
-
-template <class ELFT> bool DynamicFile<ELFT>::canParse(file_magic magic) {
- return magic == file_magic::elf_shared_object;
-}
-
-template <class ELFT> std::error_code DynamicFile<ELFT>::doParse() {
- typedef llvm::object::ELFFile<ELFT> ELFO;
- typedef typename ELFO::Elf_Shdr Elf_Shdr;
- typedef typename ELFO::Elf_Dyn Elf_Dyn;
-
- std::error_code ec;
- _objFile.reset(new ELFO(_mb->getBuffer(), ec));
- if (ec)
- return ec;
-
- ELFO &obj = *_objFile;
-
- const char *base = _mb->getBuffer().data();
- const Elf_Dyn *dynStart = nullptr;
- const Elf_Dyn *dynEnd = nullptr;
-
- const Elf_Shdr *dynSymSec = nullptr;
- for (const Elf_Shdr &sec : obj.sections()) {
- switch (sec.sh_type) {
- case llvm::ELF::SHT_DYNAMIC: {
- dynStart = reinterpret_cast<const Elf_Dyn *>(base + sec.sh_offset);
- uint64_t size = sec.sh_size;
- if (size % sizeof(Elf_Dyn))
- return llvm::object::object_error::parse_failed;
- dynEnd = dynStart + size / sizeof(Elf_Dyn);
- break;
- }
- case llvm::ELF::SHT_DYNSYM:
- dynSymSec = &sec;
- break;
- }
- }
-
- ErrorOr<StringRef> strTableOrErr = obj.getStringTableForSymtab(*dynSymSec);
- if (std::error_code ec = strTableOrErr.getError())
- return ec;
- StringRef stringTable = *strTableOrErr;
-
- for (const Elf_Dyn &dyn : llvm::make_range(dynStart, dynEnd)) {
- if (dyn.d_tag == llvm::ELF::DT_SONAME) {
- uint64_t offset = dyn.getVal();
- if (offset >= stringTable.size())
- return llvm::object::object_error::parse_failed;
- _soname = StringRef(stringTable.data() + offset);
- break;
- }
- }
-
- 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.symbol_begin(dynSymSec), e = obj.symbol_end(dynSymSec);
- i != e; ++i) {
- auto name = i->getName(stringTable);
- 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.push_back(newAtom);
- }
- continue;
- }
- _nameToSym[*name]._symbol = &*i;
- }
- return std::error_code();
-}
-
-template class DynamicFile<ELF32LE>;
-template class DynamicFile<ELF32BE>;
-template class DynamicFile<ELF64LE>;
-template class DynamicFile<ELF64BE>;
-
-} // end namespace elf
-} // end namespace lld
diff --git a/lib/ReaderWriter/ELF/DynamicFile.h b/lib/ReaderWriter/ELF/DynamicFile.h
deleted file mode 100644
index a155900de781..000000000000
--- a/lib/ReaderWriter/ELF/DynamicFile.h
+++ /dev/null
@@ -1,59 +0,0 @@
-//===- 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 <unordered_map>
-
-namespace lld {
-class ELFLinkingContext;
-
-namespace elf {
-
-template <class ELFT> class DynamicFile : public SharedLibraryFile {
-public:
- DynamicFile(std::unique_ptr<MemoryBuffer> mb, ELFLinkingContext &ctx);
-
- static std::error_code isCompatible(MemoryBufferRef mb,
- ELFLinkingContext &ctx);
-
- const SharedLibraryAtom *exports(StringRef name,
- bool dataSymbolOnly) const override;
-
- StringRef getDSOName() const override;
-
- static bool canParse(file_magic magic);
-
-protected:
- std::error_code doParse() override;
-
-private:
- mutable llvm::BumpPtrAllocator _alloc;
- std::unique_ptr<llvm::object::ELFFile<ELFT>> _objFile;
- /// \brief DT_SONAME
- StringRef _soname;
-
- struct SymAtomPair {
- const typename llvm::object::ELFFile<ELFT>::Elf_Sym *_symbol = nullptr;
- const SharedLibraryAtom *_atom = nullptr;
- };
-
- std::unique_ptr<MemoryBuffer> _mb;
- ELFLinkingContext &_ctx;
- bool _useShlibUndefines;
- mutable std::unordered_map<StringRef, SymAtomPair> _nameToSym;
-};
-
-} // end namespace elf
-} // end namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/ELF/DynamicLibraryWriter.h b/lib/ReaderWriter/ELF/DynamicLibraryWriter.h
deleted file mode 100644
index 5f2c1d1a8288..000000000000
--- a/lib/ReaderWriter/ELF/DynamicLibraryWriter.h
+++ /dev/null
@@ -1,86 +0,0 @@
-//===- 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;
-
-//===----------------------------------------------------------------------===//
-// DynamicLibraryWriter Class
-//===----------------------------------------------------------------------===//
-template<class ELFT>
-class DynamicLibraryWriter : public OutputELFWriter<ELFT> {
-public:
- DynamicLibraryWriter(ELFLinkingContext &ctx, TargetLayout<ELFT> &layout)
- : OutputELFWriter<ELFT>(ctx, layout) {}
-
-protected:
- void buildDynamicSymbolTable(const File &file) override;
- void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
- void finalizeDefaultAtomValues() override;
-};
-
-//===----------------------------------------------------------------------===//
-// 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);
-}
-
-/// \brief Hook in lld to add CRuntime file
-template <class ELFT>
-void DynamicLibraryWriter<ELFT>::createImplicitFiles(
- std::vector<std::unique_ptr<File> > &result) {
- OutputELFWriter<ELFT>::createImplicitFiles(result);
- // Add the default atoms as defined by executables
- auto file = llvm::make_unique<RuntimeFile<ELFT>>(this->_ctx, "C runtime");
- file->addAbsoluteAtom("_end");
- result.push_back(std::move(file));
-}
-
-template <class ELFT>
-void DynamicLibraryWriter<ELFT>::finalizeDefaultAtomValues() {
- OutputELFWriter<ELFT>::finalizeDefaultAtomValues();
- AtomLayout *underScoreEndAtom = this->_layout.findAbsoluteAtom("_end");
- assert(underScoreEndAtom);
-
- if (auto bssSection = this->_layout.findOutputSection(".bss")) {
- underScoreEndAtom->_virtualAddr =
- bssSection->virtualAddr() + bssSection->memSize();
- } else if (auto dataSection = this->_layout.findOutputSection(".data")) {
- underScoreEndAtom->_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.cpp b/lib/ReaderWriter/ELF/ELFFile.cpp
deleted file mode 100644
index 1488f1862b8d..000000000000
--- a/lib/ReaderWriter/ELF/ELFFile.cpp
+++ /dev/null
@@ -1,829 +0,0 @@
-//===- lib/ReaderWriter/ELF/ELFFile.cpp -------------------------*- C++ -*-===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ELFFile.h"
-#include "FileCommon.h"
-#include "llvm/ADT/STLExtras.h"
-
-namespace lld {
-namespace elf {
-
-template <typename ELFT>
-ELFFile<ELFT>::ELFFile(StringRef name, ELFLinkingContext &ctx)
- : SimpleFile(name), _ordinal(0), _doStringsMerge(ctx.mergeCommonStrings()),
- _useWrap(false), _ctx(ctx) {
- setLastError(std::error_code());
-}
-
-template <typename ELFT>
-ELFFile<ELFT>::ELFFile(std::unique_ptr<MemoryBuffer> mb, ELFLinkingContext &ctx)
- : SimpleFile(mb->getBufferIdentifier()), _mb(std::move(mb)), _ordinal(0),
- _doStringsMerge(ctx.mergeCommonStrings()),
- _useWrap(ctx.wrapCalls().size()), _ctx(ctx) {}
-
-template <typename ELFT>
-std::error_code ELFFile<ELFT>::isCompatible(MemoryBufferRef mb,
- ELFLinkingContext &ctx) {
- return elf::isCompatible<ELFT>(mb, ctx);
-}
-
-template <typename ELFT>
-Atom *ELFFile<ELFT>::findAtom(const Elf_Sym *sourceSym,
- const Elf_Sym *targetSym) {
- // Return the atom for targetSym if we can do so.
- Atom *target = _symbolToAtomMapping.lookup(targetSym);
- if (!target)
- // Some realocations (R_ARM_V4BX) do not have a defined
- // target. For this cases make it points to itself.
- target = _symbolToAtomMapping.lookup(sourceSym);
-
- if (target->definition() != Atom::definitionRegular)
- return target;
- Atom::Scope scope = llvm::cast<DefinedAtom>(target)->scope();
- if (scope == DefinedAtom::scopeTranslationUnit)
- return target;
- if (!redirectReferenceUsingUndefAtom(sourceSym, targetSym))
- return target;
-
- // Otherwise, create a new undefined symbol and returns it.
- StringRef targetName = target->name();
- auto it = _undefAtomsForGroupChild.find(targetName);
- if (it != _undefAtomsForGroupChild.end())
- return it->getValue();
- auto atom = new (_readerStorage) SimpleUndefinedAtom(*this, targetName);
- _undefAtomsForGroupChild[targetName] = atom;
- addAtom(*atom);
- return atom;
-}
-
-template <typename ELFT>
-ErrorOr<StringRef> ELFFile<ELFT>::getSectionName(const Elf_Shdr *shdr) const {
- if (!shdr)
- return StringRef();
- return _objFile->getSectionName(shdr);
-}
-
-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()) {
- switch (section.sh_type) {
- case llvm::ELF::SHT_SYMTAB:
- _symtab = &section;
- continue;
- case llvm::ELF::SHT_SYMTAB_SHNDX: {
- ErrorOr<ArrayRef<Elf_Word>> tableOrErr = _objFile->getSHNDXTable(section);
- if (std::error_code ec = tableOrErr.getError())
- return ec;
- _shndxTable = *tableOrErr;
- continue;
- }
- }
-
- if (isIgnoredSection(&section))
- continue;
-
- if (isMergeableStringSection(&section)) {
- _mergeStringSections.push_back(&section);
- continue;
- }
-
- if (section.sh_type == llvm::ELF::SHT_RELA) {
- auto sHdrOrErr = _objFile->getSection(section.sh_info);
- if (std::error_code ec = sHdrOrErr.getError())
- return ec;
- auto sHdr = *sHdrOrErr;
- auto rai = _objFile->rela_begin(&section);
- auto rae = _objFile->rela_end(&section);
- _relocationAddendReferences[sHdr] = make_range(rai, rae);
- totalRelocs += std::distance(rai, rae);
- } else if (section.sh_type == llvm::ELF::SHT_REL) {
- auto sHdrOrErr = _objFile->getSection(section.sh_info);
- if (std::error_code ec = sHdrOrErr.getError())
- return ec;
- auto sHdr = *sHdrOrErr;
- auto ri = _objFile->rel_begin(&section);
- auto re = _objFile->rel_end(&section);
- _relocationReferences[sHdr] = &section;
- totalRelocs += std::distance(ri, re);
- } else {
- auto sectionName = _objFile->getSectionName(&section);
- if (std::error_code ec = sectionName.getError())
- return ec;
- _ctx.notifyInputSectionName(*sectionName);
- _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());
- ELFMergeAtom<ELFT> *atom = createMergedString(tai->_sectionName, tai->_shdr,
- content, tai->_offset);
- atom->setOrdinal(++_ordinal);
- addAtom(*atom);
- _mergeAtoms.push_back(atom);
- }
- 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.
- if (!_symtab)
- return std::error_code();
-
- ErrorOr<StringRef> strTableOrErr =
- _objFile->getStringTableForSymtab(*_symtab);
- if (std::error_code ec = strTableOrErr.getError())
- return ec;
- StringRef strTable = *strTableOrErr;
-
- auto SymI = _objFile->symbol_begin(_symtab),
- SymE = _objFile->symbol_end(_symtab);
- // Skip over dummy sym.
- ++SymI;
-
- for (; SymI != SymE; ++SymI) {
- ErrorOr<const Elf_Shdr *> section =
- _objFile->getSection(SymI, _symtab, _shndxTable);
- if (std::error_code ec = section.getError())
- return ec;
-
- auto symbolName = SymI->getName(strTable);
- if (std::error_code ec = symbolName.getError())
- return ec;
-
- if (SymI->isAbsolute()) {
- ELFAbsoluteAtom<ELFT> *absAtom = createAbsoluteAtom(
- *symbolName, &*SymI, (int64_t)getSymbolValue(&*SymI));
- addAtom(*absAtom);
- _symbolToAtomMapping.insert(std::make_pair(&*SymI, absAtom));
- } else if (SymI->isUndefined()) {
- if (_useWrap &&
- (_wrapSymbolMap.find(*symbolName) != _wrapSymbolMap.end())) {
- auto wrapAtom = _wrapSymbolMap.find(*symbolName);
- _symbolToAtomMapping.insert(
- std::make_pair(&*SymI, wrapAtom->getValue()));
- continue;
- }
- ELFUndefinedAtom<ELFT> *undefAtom =
- createUndefinedAtom(*symbolName, &*SymI);
- addAtom(*undefAtom);
- _symbolToAtomMapping.insert(std::make_pair(&*SymI, undefAtom));
- } else if (isCommonSymbol(&*SymI)) {
- ELFCommonAtom<ELFT> *commonAtom = createCommonAtom(*symbolName, &*SymI);
- commonAtom->setOrdinal(++_ordinal);
- addAtom(*commonAtom);
- _symbolToAtomMapping.insert(std::make_pair(&*SymI, commonAtom));
- } else if (SymI->isDefined()) {
- _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;
-
- // Contains a list of comdat sections for a group.
- for (auto &i : _sectionSymbols) {
- const Elf_Shdr *section = i.first;
- std::vector<const Elf_Sym *> &symbols = i.second;
-
- // Sort symbols by position.
- std::stable_sort(symbols.begin(), symbols.end(),
- [this](const Elf_Sym *a, const Elf_Sym *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;
-
- // SHT_GROUP sections are handled in the following loop.
- if (isGroupSection(section))
- continue;
-
- bool addAtoms = (!isGnuLinkOnceSection(*sectionName) &&
- !isSectionMemberOfGroup(section));
-
- if (handleSectionWithNoSymbols(section, symbols)) {
- ELFDefinedAtom<ELFT> *newAtom =
- createSectionAtom(section, *sectionName, *sectionContents);
- newAtom->setOrdinal(++_ordinal);
- if (addAtoms)
- addAtom(*newAtom);
- else
- atomsForSection[*sectionName].push_back(newAtom);
- continue;
- }
-
- ELFDefinedAtom<ELFT> *previousAtom = nullptr;
- ELFReference<ELFT> *anonFollowedBy = nullptr;
-
- if (!_symtab)
- continue;
- ErrorOr<StringRef> strTableOrErr =
- _objFile->getStringTableForSymtab(*_symtab);
- if (std::error_code ec = strTableOrErr.getError())
- return ec;
- StringRef strTable = *strTableOrErr;
- 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 = symbol->getName(strTable);
- 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>(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)
- continue;
- ELFDefinedAtom<ELFT> *atom = createDefinedAtom(
- symbolName, *sectionName, &**si, section, symbolData,
- _references.size(), _references.size(), _references);
- atom->setOrdinal(++_ordinal);
- if (addAtoms)
- addAtom(*atom);
- else
- atomsForSection[*sectionName].push_back(atom);
- 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>(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)
- addAtom(*newAtom);
- else
- atomsForSection[*sectionName].push_back(newAtom);
-
- _symbolToAtomMapping.insert(std::make_pair(&*symbol, newAtom));
- if (anonAtom) {
- anonAtom->setOrdinal(++_ordinal);
- if (addAtoms)
- addAtom(*anonAtom);
- else
- atomsForSection[*sectionName].push_back(anonAtom);
- }
- }
- }
-
- for (auto &i : _sectionSymbols)
- if (std::error_code ec = handleSectionGroup(i.first, atomsForSection))
- return ec;
- for (auto &i : _sectionSymbols)
- if (std::error_code ec = handleGnuLinkOnceSection(i.first, atomsForSection))
- return ec;
-
- updateReferences();
- return std::error_code();
-}
-
-template <class ELFT>
-std::error_code ELFFile<ELFT>::handleGnuLinkOnceSection(
- const Elf_Shdr *section,
- llvm::StringMap<std::vector<ELFDefinedAtom<ELFT> *>> &atomsForSection) {
- ErrorOr<StringRef> sectionName = this->getSectionName(section);
- if (std::error_code ec = sectionName.getError())
- return ec;
- if (!isGnuLinkOnceSection(*sectionName))
- return std::error_code();
-
- unsigned int referenceStart = _references.size();
- std::vector<ELFReference<ELFT> *> refs;
- for (auto ha : atomsForSection[*sectionName]) {
- _groupChild[ha->symbol()] = std::make_pair(*sectionName, section);
- auto *ref =
- new (_readerStorage) ELFReference<ELFT>(Reference::kindGroupChild);
- ref->setTarget(ha);
- refs.push_back(ref);
- }
- atomsForSection[*sectionName].clear();
- // Create a gnu linkonce atom.
- ELFDefinedAtom<ELFT> *atom = createDefinedAtom(
- *sectionName, *sectionName, nullptr, section, ArrayRef<uint8_t>(),
- referenceStart, _references.size(), _references);
- atom->setOrdinal(++_ordinal);
- addAtom(*atom);
- for (auto reference : refs)
- atom->addReference(reference);
- return std::error_code();
-}
-
-template <class ELFT>
-std::error_code ELFFile<ELFT>::handleSectionGroup(
- const Elf_Shdr *section,
- llvm::StringMap<std::vector<ELFDefinedAtom<ELFT> *>> &atomsForSection) {
- ErrorOr<StringRef> sectionName = this->getSectionName(section);
- if (std::error_code ec = sectionName.getError())
- return ec;
- if (!isGroupSection(section))
- return std::error_code();
-
- auto sectionContents = getSectionContents(section);
- if (std::error_code ec = sectionContents.getError())
- return ec;
-
- // 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.
- std::vector<StringRef> sectionNames;
- const Elf_Word *groupMembers =
- reinterpret_cast<const Elf_Word *>(sectionContents->data());
- const size_t count = section->sh_size / sizeof(Elf_Word);
- for (size_t i = 1; i < count; i++) {
- ErrorOr<const Elf_Shdr *> shdr = _objFile->getSection(groupMembers[i]);
- if (std::error_code ec = shdr.getError())
- return ec;
- ErrorOr<StringRef> sectionName = _objFile->getSectionName(*shdr);
- if (std::error_code ec = sectionName.getError())
- return ec;
- sectionNames.push_back(*sectionName);
- }
- ErrorOr<const Elf_Shdr *> symtab = _objFile->getSection(section->sh_link);
- if (std::error_code ec = symtab.getError())
- return ec;
- const Elf_Sym *symbol = _objFile->getSymbol(*symtab, section->sh_info);
- ErrorOr<const Elf_Shdr *> strtab_sec =
- _objFile->getSection((*symtab)->sh_link);
- if (std::error_code ec = strtab_sec.getError())
- return ec;
- ErrorOr<StringRef> strtab_or_err = _objFile->getStringTable(*strtab_sec);
- if (std::error_code ec = strtab_or_err.getError())
- return ec;
- StringRef strtab = *strtab_or_err;
- ErrorOr<StringRef> symbolName = symbol->getName(strtab);
- if (std::error_code ec = symbolName.getError())
- return ec;
-
- unsigned int referenceStart = _references.size();
- std::vector<ELFReference<ELFT> *> refs;
- for (auto name : sectionNames) {
- for (auto ha : atomsForSection[name]) {
- _groupChild[ha->symbol()] = std::make_pair(*symbolName, section);
- auto *ref =
- new (_readerStorage) ELFReference<ELFT>(Reference::kindGroupChild);
- ref->setTarget(ha);
- refs.push_back(ref);
- }
- atomsForSection[name].clear();
- }
-
- // Create an atom for comdat signature.
- ELFDefinedAtom<ELFT> *atom = createDefinedAtom(
- *symbolName, *sectionName, nullptr, section, ArrayRef<uint8_t>(),
- referenceStart, _references.size(), _references);
- atom->setOrdinal(++_ordinal);
- addAtom(*atom);
- for (auto reference : refs)
- atom->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));
- addAtom(*wrapSymAtom);
- addAtom(*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(section);
- if (rari != _relocationAddendReferences.end())
- createRelocationReferences(symbol, symContent, rari->second);
-
- // Add Rel references.
- auto rri = _relocationReferences.find(section);
- if (rri != _relocationReferences.end())
- createRelocationReferences(symbol, symContent, secContent, rri->second);
-
- // Create the DefinedAtom and add it to the list of DefinedAtoms.
- return createDefinedAtom(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<const Elf_Rela *> 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,
- const Elf_Shdr *relSec) {
- auto rels = _objFile->rels(relSec);
- 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));
- Reference::Addend addend = getInitialAddend(symContent, symValue, rel);
- 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() != Reference::KindNamespace::ELF)
- continue;
- const Elf_Sym *symbol =
- _objFile->getSymbol(_symtab, ri->targetSymbolIndex());
- ErrorOr<const Elf_Shdr *> shdr =
- _objFile->getSection(symbol, _symtab, _shndxTable);
-
- // 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) {
- auto *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;
-}
-
-template <class ELFT>
-void RuntimeFile<ELFT>::addAbsoluteAtom(StringRef symbolName, bool isHidden) {
- assert(!symbolName.empty() && "AbsoluteAtoms must have a name");
- auto *sym = new (this->_readerStorage) Elf_Sym;
- sym->st_name = 0;
- sym->st_value = 0;
- sym->st_shndx = llvm::ELF::SHN_ABS;
- sym->setBindingAndType(llvm::ELF::STB_GLOBAL, llvm::ELF::STT_OBJECT);
- if (isHidden)
- sym->setVisibility(llvm::ELF::STV_HIDDEN);
- else
- sym->setVisibility(llvm::ELF::STV_DEFAULT);
- sym->st_size = 0;
- ELFAbsoluteAtom<ELFT> *atom = this->createAbsoluteAtom(symbolName, sym, -1);
- this->addAtom(*atom);
-}
-
-template <class ELFT>
-void RuntimeFile<ELFT>::addUndefinedAtom(StringRef symbolName) {
- assert(!symbolName.empty() && "UndefinedAtoms must have a name");
- auto *sym = new (this->_readerStorage) Elf_Sym;
- sym->st_name = 0;
- sym->st_value = 0;
- sym->st_shndx = llvm::ELF::SHN_UNDEF;
- sym->setBindingAndType(llvm::ELF::STB_GLOBAL, llvm::ELF::STT_NOTYPE);
- sym->setVisibility(llvm::ELF::STV_DEFAULT);
- sym->st_size = 0;
- ELFUndefinedAtom<ELFT> *atom = this->createUndefinedAtom(symbolName, sym);
- this->addAtom(*atom);
-}
-
-template class ELFFile<ELF32LE>;
-template class ELFFile<ELF32BE>;
-template class ELFFile<ELF64LE>;
-template class ELFFile<ELF64BE>;
-
-template class RuntimeFile<ELF32LE>;
-template class RuntimeFile<ELF32BE>;
-template class RuntimeFile<ELF64LE>;
-template class RuntimeFile<ELF64BE>;
-
-} // end namespace elf
-} // end namespace lld
diff --git a/lib/ReaderWriter/ELF/ELFFile.h b/lib/ReaderWriter/ELF/ELFFile.h
deleted file mode 100644
index 5e0c2fc75a87..000000000000
--- a/lib/ReaderWriter/ELF/ELFFile.h
+++ /dev/null
@@ -1,395 +0,0 @@
-//===- lib/ReaderWriter/ELF/ELFFile.h ---------------------------*- C++ -*-===//
-//
-// 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 "FileCommon.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 SimpleFile {
- 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_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 {
- 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 merge atom given a offset
- ELFMergeAtom<ELFT> *findMergeAtom(const Elf_Shdr *shdr, int64_t offset) {
- auto it = std::find_if(_mergeAtoms.begin(), _mergeAtoms.end(),
- [=](const ELFMergeAtom<ELFT> *a) {
- int64_t off = a->offset();
- return shdr->sh_name == a->section() &&
- offset >= off &&
- offset <= off + (int64_t)a->size();
- });
- 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);
- ELFFile(std::unique_ptr<MemoryBuffer> mb, ELFLinkingContext &ctx);
-
- static std::error_code isCompatible(MemoryBufferRef mb,
- ELFLinkingContext &ctx);
-
- static bool canParse(file_magic magic) {
- return magic == file_magic::elf_relocatable;
- }
-
- 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();
-
- // Assuming sourceSymbol has a reference to targetSym, find an atom
- // for targetSym. Usually it's just the atom for targetSym.
- // However, if an atom is in a section group, we may want to return an
- // undefined atom for targetSym to let the resolver to resolve the
- // symbol. (It's because if targetSym is in a section group A, and the
- // group A is not linked in because other file already provides a
- // section group B, we want to resolve references to B, not to A.)
- Atom *findAtom(const Elf_Sym *sourceSym, const Elf_Sym *targetSym);
-
-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<const Elf_Rela *> 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,
- const Elf_Shdr *relSec);
-
- /// \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;
-
- /// 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);
- }
-
- /// 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<const Elf_Sym *> &syms) const {
- return shdr &&
- (shdr->sh_type == llvm::ELF::SHT_PROGBITS ||
- shdr->sh_type == llvm::ELF::SHT_INIT_ARRAY ||
- shdr->sh_type == llvm::ELF::SHT_FINI_ARRAY ||
- shdr->sh_type == llvm::ELF::SHT_NOTE) &&
- syms.empty();
- }
-
- /// Handle creation of atoms for .gnu.linkonce sections.
- std::error_code handleGnuLinkOnceSection(
- const Elf_Shdr *section,
- llvm::StringMap<std::vector<ELFDefinedAtom<ELFT> *>> &atomsForSection);
-
- // Handle COMDAT scetions.
- std::error_code handleSectionGroup(
- const Elf_Shdr *section,
- llvm::StringMap<std::vector<ELFDefinedAtom<ELFT> *>> &atomsForSection);
-
- /// Process the Undefined symbol and create an atom for it.
- ELFUndefinedAtom<ELFT> *createUndefinedAtom(StringRef symName,
- const Elf_Sym *sym) {
- return new (_readerStorage) ELFUndefinedAtom<ELFT>(*this, symName, sym);
- }
-
- /// Process the Absolute symbol and create an atom for it.
- ELFAbsoluteAtom<ELFT> *createAbsoluteAtom(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;
- }
-
- /// Returns initial addend
- virtual Reference::Addend getInitialAddend(ArrayRef<uint8_t> symContent,
- uint64_t symbolValue,
- const Elf_Rel& reference) const {
- return *(symContent.data() + reference.r_offset - symbolValue);
- }
-
- /// Process the common symbol and create an atom for it.
- virtual ELFCommonAtom<ELFT> *createCommonAtom(StringRef symName,
- const Elf_Sym *sym) {
- return new (_readerStorage) ELFCommonAtom<ELFT>(*this, symName, sym);
- }
-
- /// Creates an atom for a given defined symbol.
- virtual ELFDefinedAtom<ELFT> *
- createDefinedAtom(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.
- ELFMergeAtom<ELFT> *createMergedString(StringRef sectionName,
- const Elf_Shdr *sectionHdr,
- ArrayRef<uint8_t> contentData,
- unsigned int offset) {
- auto *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;
- const Elf_Shdr *_symtab = nullptr;
- ArrayRef<Elf_Word> _shndxTable;
-
- /// \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<const Elf_Shdr *, range<const Elf_Rela *>>
- _relocationAddendReferences;
- MergedSectionMapT _mergedSectionMap;
- std::unordered_map<const Elf_Shdr *, const Elf_Shdr *> _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<const Elf_Sym *>>
- _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 &ctx, StringRef name)
- : ELFFile<ELFT>(name, ctx) {}
-
- /// \brief add a global absolute atom
- virtual void addAbsoluteAtom(StringRef symbolName, bool isHidden = false);
-
- /// \brief add an undefined atom
- virtual void addUndefinedAtom(StringRef symbolName);
-};
-
-} // 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
deleted file mode 100644
index 70d6d618207d..000000000000
--- a/lib/ReaderWriter/ELF/ELFLinkingContext.cpp
+++ /dev/null
@@ -1,263 +0,0 @@
-//===- 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
-
-using llvm::sys::fs::exists;
-using llvm::sys::path::is_absolute;
-
-namespace lld {
-
-class CommandLineUndefinedAtom : public SimpleUndefinedAtom {
-public:
- CommandLineUndefinedAtom(const File &f, StringRef name)
- : SimpleUndefinedAtom(f, name) {}
-
- CanBeNull canBeNull() const override {
- return CanBeNull::canBeNullAtBuildtime;
- }
-};
-
-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::mips:
- case llvm::Triple::mipsel:
- case llvm::Triple::mips64:
- 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;
- default:
- _writer = createWriterELF(*this);
- 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("=/")) {
- // If a search directory begins with "=", "=" is replaced
- // with the sysroot path.
- path.assign(sysRoot);
- path.append(dir.substr(1));
- } else {
- path.assign(dir);
- }
-}
-
-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 (exists(path.str()))
- return path.str().copy(_allocator);
- }
- // Search for static libraries too
- buildSearchPath(path, dir, _sysrootPath);
- llvm::sys::path::append(path, hasColonPrefix
- ? libName.drop_front()
- : Twine("lib", libName) + ".a");
- if (exists(path.str()))
- return path.str().copy(_allocator);
- }
- if (hasColonPrefix && 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 (is_absolute(fileName) && isSysRooted) {
- path.assign(_sysrootPath);
- path.append(fileName);
- if (exists(path.str()))
- return path.str().copy(_allocator);
- } else if (exists(fileName)) {
- return fileName;
- }
-
- if (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 (exists(path.str()))
- return path.str().copy(_allocator);
- }
- 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 defined(HAVE_CXXABI_H)
- if (!demangleSymbols())
- return symbolName;
-
- // Only try to demangle symbols that look like C++ symbols
- if (!symbolName.startswith("_Z"))
- return symbolName;
-
- 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)
- return symbolName;
- std::string result(demangled);
- // __cxa_demangle() always uses a malloc'ed buffer to return the result.
- free(demangled);
- return result;
-#else
- return symbolName;
-#endif
-}
-
-void ELFLinkingContext::setUndefinesResolver(std::unique_ptr<File> resolver) {
- assert(isa<ArchiveLibraryFile>(resolver.get()) && "Wrong resolver type");
- _resolver = std::move(resolver);
-}
-
-void ELFLinkingContext::notifyInputSectionName(StringRef name) {
- // Save sections names which can be represented as a C identifier.
- if (name.find_first_not_of("0123456789"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "abcdefghijklmnopqrstuvwxyz"
- "_") == StringRef::npos) {
- std::lock_guard<std::mutex> lock(_cidentMutex);
- _cidentSections.insert(name);
- }
-}
-
-} // end namespace lld
diff --git a/lib/ReaderWriter/ELF/ELFReader.h b/lib/ReaderWriter/ELF/ELFReader.h
deleted file mode 100644
index 60af6dff9980..000000000000
--- a/lib/ReaderWriter/ELF/ELFReader.h
+++ /dev/null
@@ -1,47 +0,0 @@
-//===- 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 "DynamicFile.h"
-#include "ELFFile.h"
-#include "lld/Core/File.h"
-#include "lld/Core/Reader.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/Object/ELF.h"
-
-namespace lld {
-namespace elf {
-
-template <typename FileT> class ELFReader : public Reader {
-public:
- ELFReader(ELFLinkingContext &ctx) : _ctx(ctx) {}
-
- bool canParse(file_magic magic, MemoryBufferRef mb) const override {
- return FileT::canParse(magic);
- }
-
- ErrorOr<std::unique_ptr<File>>
- loadFile(std::unique_ptr<MemoryBuffer> mb,
- const class Registry &) const override {
- if (std::error_code ec = FileT::isCompatible(mb->getMemBufferRef(), _ctx))
- return ec;
- std::unique_ptr<File> ret = llvm::make_unique<FileT>(std::move(mb), _ctx);
- return std::move(ret);
- }
-
-private:
- ELFLinkingContext &_ctx;
-};
-
-} // 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
deleted file mode 100644
index 9d9f4d9ce0a5..000000000000
--- a/lib/ReaderWriter/ELF/ExecutableWriter.h
+++ /dev/null
@@ -1,157 +0,0 @@
-//===- 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;
-
-//===----------------------------------------------------------------------===//
-// ExecutableWriter Class
-//===----------------------------------------------------------------------===//
-template<class ELFT>
-class ExecutableWriter : public OutputELFWriter<ELFT> {
-public:
- ExecutableWriter(ELFLinkingContext &ctx, TargetLayout<ELFT> &layout)
- : OutputELFWriter<ELFT>(ctx, layout) {}
-
-protected:
- void buildDynamicSymbolTable(const File &file) override;
- void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
- void finalizeDefaultAtomValues() override;
- void createDefaultSections() override;
-
- bool isNeededTagRequired(const SharedLibraryAtom *sla) const override {
- return this->_layout.isCopied(sla);
- }
-
- unique_bump_ptr<InterpSection<ELFT>> _interpSection;
-
-private:
- std::unique_ptr<RuntimeFile<ELFT>> createRuntimeFile();
-};
-
-//===----------------------------------------------------------------------===//
-// 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->_ctx.isDynamicallyExportedSymbol(da->name()) &&
- !(this->_ctx.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->_ctx.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);
-}
-
-template<class ELFT>
-std::unique_ptr<RuntimeFile<ELFT>> ExecutableWriter<ELFT>::createRuntimeFile() {
- auto file = llvm::make_unique<RuntimeFile<ELFT>>(this->_ctx, "C runtime");
- file->addUndefinedAtom(this->_ctx.entrySymbolName());
- file->addAbsoluteAtom("__bss_start");
- file->addAbsoluteAtom("__bss_end");
- file->addAbsoluteAtom("_end");
- file->addAbsoluteAtom("end");
- file->addAbsoluteAtom("__preinit_array_start", true);
- file->addAbsoluteAtom("__preinit_array_end", true);
- file->addAbsoluteAtom("__init_array_start", true);
- file->addAbsoluteAtom("__init_array_end", true);
- if (this->_ctx.isRelaOutputFormat()) {
- file->addAbsoluteAtom("__rela_iplt_start");
- file->addAbsoluteAtom("__rela_iplt_end");
- } else {
- file->addAbsoluteAtom("__rel_iplt_start");
- file->addAbsoluteAtom("__rel_iplt_end");
- }
- file->addAbsoluteAtom("__fini_array_start", true);
- file->addAbsoluteAtom("__fini_array_end", true);
- return file;
-}
-
-/// \brief Hook in lld to add CRuntime file
-template <class ELFT>
-void ExecutableWriter<ELFT>::createImplicitFiles(
- std::vector<std::unique_ptr<File> > &result) {
- OutputELFWriter<ELFT>::createImplicitFiles(result);
- result.push_back(createRuntimeFile());
-}
-
-template <class ELFT> void ExecutableWriter<ELFT>::createDefaultSections() {
- OutputELFWriter<ELFT>::createDefaultSections();
- if (this->_ctx.isDynamic()) {
- _interpSection.reset(new (this->_alloc) InterpSection<ELFT>(
- this->_ctx, ".interp", TargetLayout<ELFT>::ORDER_INTERP,
- this->_ctx.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();
- AtomLayout *bssStartAtom = this->_layout.findAbsoluteAtom("__bss_start");
- AtomLayout *bssEndAtom = this->_layout.findAbsoluteAtom("__bss_end");
- AtomLayout *underScoreEndAtom = this->_layout.findAbsoluteAtom("_end");
- AtomLayout *endAtom = this->_layout.findAbsoluteAtom("end");
-
- assert((bssStartAtom || bssEndAtom || underScoreEndAtom || endAtom) &&
- "Unable to find the absolute atoms that have been added by lld");
-
- this->updateScopeAtomValues("preinit_array", ".preinit_array");
- this->updateScopeAtomValues("init_array", ".init_array");
- if (this->_ctx.isRelaOutputFormat())
- this->updateScopeAtomValues("rela_iplt", ".rela.plt");
- else
- this->updateScopeAtomValues("rel_iplt", ".rel.plt");
- this->updateScopeAtomValues("fini_array", ".fini_array");
-
- auto bssSection = this->_layout.findOutputSection(".bss");
-
- // If we don't find a bss section, then don't set these values
- if (bssSection) {
- bssStartAtom->_virtualAddr = bssSection->virtualAddr();
- bssEndAtom->_virtualAddr =
- bssSection->virtualAddr() + bssSection->memSize();
- underScoreEndAtom->_virtualAddr = bssEndAtom->_virtualAddr;
- endAtom->_virtualAddr = bssEndAtom->_virtualAddr;
- } else if (auto dataSection = this->_layout.findOutputSection(".data")) {
- underScoreEndAtom->_virtualAddr =
- dataSection->virtualAddr() + dataSection->memSize();
- endAtom->_virtualAddr = underScoreEndAtom->_virtualAddr;
- }
-}
-
-} // namespace elf
-} // namespace lld
-
-#endif // LLD_READER_WRITER_ELF_EXECUTABLE_WRITER_H
diff --git a/lib/ReaderWriter/ELF/FileCommon.cpp b/lib/ReaderWriter/ELF/FileCommon.cpp
deleted file mode 100644
index c23e3f6656cd..000000000000
--- a/lib/ReaderWriter/ELF/FileCommon.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-//===- lib/ReaderWriter/ELF/FileCommon.cpp --------------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ELFFile.h"
-#include "FileCommon.h"
-
-using namespace llvm::ELF;
-
-namespace lld {
-namespace elf {
-
-static const char *elf32_expected = "ELF32 expected, but got ELF64";
-static const char *elf64_expected = "ELF64 expected, but got ELF32";
-static const char *le_expected =
- "Little endian files are expected, but got a big endian file.";
-static const char *be_expected =
- "Big endian files are expected, but got a little endian file.";
-
-template <>
-std::error_code checkCompatibility<ELF32LE>(unsigned char size,
- unsigned char endian) {
- if (size == ELFCLASS64)
- return make_dynamic_error_code(elf32_expected);
- if (endian == ELFDATA2MSB)
- return make_dynamic_error_code(le_expected);
- return std::error_code();
-}
-
-template <>
-std::error_code checkCompatibility<ELF32BE>(unsigned char size,
- unsigned char endian) {
- if (size == ELFCLASS64)
- return make_dynamic_error_code(elf32_expected);
- if (endian == ELFDATA2LSB)
- return make_dynamic_error_code(be_expected);
- return std::error_code();
-}
-
-template <>
-std::error_code checkCompatibility<ELF64LE>(unsigned char size,
- unsigned char endian) {
- if (size == ELFCLASS32)
- return make_dynamic_error_code(elf64_expected);
- if (endian == ELFDATA2MSB)
- return make_dynamic_error_code(le_expected);
- return std::error_code();
-}
-
-template <>
-std::error_code checkCompatibility<ELF64BE>(unsigned char size,
- unsigned char endian) {
- if (size == ELFCLASS32)
- return make_dynamic_error_code(elf64_expected);
- if (endian == ELFDATA2LSB)
- return make_dynamic_error_code(be_expected);
- return std::error_code();
-}
-
-} // end namespace elf
-} // end namespace lld
diff --git a/lib/ReaderWriter/ELF/FileCommon.h b/lib/ReaderWriter/ELF/FileCommon.h
deleted file mode 100644
index eaff12afe72f..000000000000
--- a/lib/ReaderWriter/ELF/FileCommon.h
+++ /dev/null
@@ -1,45 +0,0 @@
-//===- lib/ReaderWriter/ELF/FileCommon.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_COMMON_H
-#define LLD_READER_WRITER_ELF_FILE_COMMON_H
-
-#include "lld/ReaderWriter/ELFLinkingContext.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/ELF.h"
-
-namespace lld {
-namespace elf {
-
-template <class ELFT>
-std::error_code checkCompatibility(unsigned char size, unsigned char endian);
-
-template <typename ELFT>
-std::error_code isCompatible(MemoryBufferRef mb, ELFLinkingContext &ctx) {
- typedef llvm::object::Elf_Ehdr_Impl<ELFT> Elf_Ehdr;
-
- if (uintptr_t(mb.getBufferStart()) & 1)
- return make_dynamic_error_code("invalid alignment");
-
- auto *hdr = reinterpret_cast<const Elf_Ehdr *>(mb.getBuffer().data());
- if (hdr->e_machine != ctx.getMachineType())
- return make_dynamic_error_code("incompatible machine type");
-
- unsigned char size;
- unsigned char endian;
- std::tie(size, endian) = llvm::object::getElfArchType(mb.getBuffer());
- if (std::error_code ec = checkCompatibility<ELFT>(size, endian))
- return ec;
- return std::error_code();
-}
-
-} // end namespace elf
-} // end namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/ELF/HeaderChunks.cpp b/lib/ReaderWriter/ELF/HeaderChunks.cpp
deleted file mode 100644
index 193937c18061..000000000000
--- a/lib/ReaderWriter/ELF/HeaderChunks.cpp
+++ /dev/null
@@ -1,205 +0,0 @@
-//===- lib/ReaderWriter/ELF/HeaderChunks.cpp --------------------*- C++ -*-===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "HeaderChunks.h"
-#include "TargetLayout.h"
-#include "llvm/ADT/STLExtras.h"
-
-namespace lld {
-namespace elf {
-
-template <class ELFT> void ELFHeader<ELFT>::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->_ctx.getOutputELFType();
- _eh.e_machine = this->_ctx.getOutputMachine();
-}
-
-template <class ELFT>
-ELFHeader<ELFT>::ELFHeader(const ELFLinkingContext &ctx)
- : Chunk<ELFT>("elfhdr", Chunk<ELFT>::Kind::ELFHeader, ctx) {
- 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());
-}
-
-template <class ELFT>
-bool ProgramHeader<ELFT>::addSegment(Segment<ELFT> *segment) {
- bool allocatedNew = false;
- ELFLinkingContext::OutputMagic outputMagic = this->_ctx.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);
- }
-}
-
-template <class ELFT>
-typename ProgramHeader<ELFT>::Elf_Phdr *
-ProgramHeader<ELFT>::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;
-}
-
-template <class ELFT>
-SectionHeader<ELFT>::SectionHeader(const ELFLinkingContext &ctx, int32_t order)
- : Chunk<ELFT>("shdr", Chunk<ELFT>::Kind::SectionHeader, ctx) {
- this->_fsize = 0;
- this->_alignment = 8;
- this->setOrder(order);
- // The first element in the list is always NULL
- auto *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) {
- auto *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);
-}
-
-template class ELFHeader<ELF32LE>;
-template class ELFHeader<ELF32BE>;
-template class ELFHeader<ELF64LE>;
-template class ELFHeader<ELF64BE>;
-
-template class ProgramHeader<ELF32LE>;
-template class ProgramHeader<ELF32BE>;
-template class ProgramHeader<ELF64LE>;
-template class ProgramHeader<ELF64BE>;
-
-template class SectionHeader<ELF32LE>;
-template class SectionHeader<ELF32BE>;
-template class SectionHeader<ELF64LE>;
-template class SectionHeader<ELF64BE>;
-
-} // end namespace elf
-} // end namespace lld
diff --git a/lib/ReaderWriter/ELF/HeaderChunks.h b/lib/ReaderWriter/ELF/HeaderChunks.h
deleted file mode 100644
index 51fbe38f1a00..000000000000
--- a/lib/ReaderWriter/ELF/HeaderChunks.h
+++ /dev/null
@@ -1,154 +0,0 @@
-//===- 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/ADT/STLExtras.h"
-#include "llvm/Object/ELF.h"
-#include "llvm/Support/Allocator.h"
-#include "llvm/Support/ELF.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/FileOutputBuffer.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 override { return sizeof(Elf_Ehdr); }
-
- static bool classof(const Chunk<ELFT> *c) {
- return c->kind() == Chunk<ELFT>::Kind::ELFHeader;
- }
-
- int getContentType() const override {
- return Chunk<ELFT>::ContentType::Header;
- }
-
- void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
- llvm::FileOutputBuffer &buffer) override;
-
- void finalize() override;
-
-private:
- Elf_Ehdr _eh;
-};
-
-/// \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;
-
- ProgramHeader(const ELFLinkingContext &ctx)
- : Chunk<ELFT>("elfphdr", Chunk<ELFT>::Kind::ProgramHeader, ctx) {
- this->_alignment = ELFT::Is64Bits ? 8 : 4;
- resetProgramHeaders();
- }
-
- bool addSegment(Segment<ELFT> *segment);
- void resetProgramHeaders() { _phi = _ph.begin(); }
- uint64_t fileSize() const override { 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) override;
-
- PhIterT begin() { return _ph.begin(); }
- PhIterT end() { return _ph.end(); }
- ReversePhIterT rbegin() { return _ph.rbegin(); }
- ReversePhIterT rend() { return _ph.rend(); }
-
- int64_t entsize() { return sizeof(Elf_Phdr); }
- int64_t numHeaders() { return _ph.size(); }
-
- int getContentType() const override {
- return Chunk<ELFT>::ContentType::Header;
- }
-
-private:
- Elf_Phdr *allocateProgramHeader(bool &allocatedNew);
-
- std::vector<Elf_Phdr *> _ph;
- PhIterT _phi;
- llvm::BumpPtrAllocator _allocator;
-};
-
-/// \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->kind() == Chunk<ELFT>::Kind::SectionHeader;
- }
-
- void setStringSection(StringTable<ELFT> *s) {
- _stringSection = s;
- }
-
- void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
- llvm::FileOutputBuffer &buffer) override;
-
- uint64_t fileSize() const override {
- return sizeof(Elf_Shdr) * _sectionInfo.size();
- }
-
- uint64_t entsize() { return sizeof(Elf_Shdr); }
-
- int getContentType() const override {
- return Chunk<ELFT>::ContentType::Header;
- }
-
- uint64_t numHeaders() { return _sectionInfo.size(); }
-
-private:
- StringTable<ELFT> *_stringSection;
- std::vector<Elf_Shdr *> _sectionInfo;
- llvm::BumpPtrAllocator _sectionAllocate;
-};
-
-} // end namespace elf
-} // end namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/ELF/Hexagon/CMakeLists.txt b/lib/ReaderWriter/ELF/Hexagon/CMakeLists.txt
deleted file mode 100644
index e5c5cb77f38c..000000000000
--- a/lib/ReaderWriter/ELF/Hexagon/CMakeLists.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-add_lld_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
deleted file mode 100644
index 84415b273f44..000000000000
--- a/lib/ReaderWriter/ELF/Hexagon/HexagonDynamicLibraryWriter.h
+++ /dev/null
@@ -1,67 +0,0 @@
-//===- 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 "HexagonLinkingContext.h"
-
-namespace lld {
-namespace elf {
-
-class HexagonTargetLayout;
-
-class HexagonDynamicLibraryWriter : public DynamicLibraryWriter<ELF32LE> {
-public:
- HexagonDynamicLibraryWriter(HexagonLinkingContext &ctx,
- HexagonTargetLayout &layout);
-
-protected:
- // Add any runtime files and their atoms to the output
- void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
-
- void finalizeDefaultAtomValues() override;
-
- std::error_code setELFHeader() override {
- DynamicLibraryWriter::setELFHeader();
- setHexagonELFHeader(*_elfHeader);
- return std::error_code();
- }
-
-private:
- HexagonLinkingContext &_ctx;
- HexagonTargetLayout &_targetLayout;
-};
-
-HexagonDynamicLibraryWriter::HexagonDynamicLibraryWriter(
- HexagonLinkingContext &ctx, HexagonTargetLayout &layout)
- : DynamicLibraryWriter(ctx, layout), _ctx(ctx), _targetLayout(layout) {}
-
-void HexagonDynamicLibraryWriter::createImplicitFiles(
- std::vector<std::unique_ptr<File>> &result) {
- DynamicLibraryWriter::createImplicitFiles(result);
- // Add the default atoms as defined for hexagon
- auto file =
- llvm::make_unique<RuntimeFile<ELF32LE>>(_ctx, "Hexagon runtime file");
- file->addAbsoluteAtom("_GLOBAL_OFFSET_TABLE_");
- file->addAbsoluteAtom("_DYNAMIC");
- result.push_back(std::move(file));
-}
-
-void HexagonDynamicLibraryWriter::finalizeDefaultAtomValues() {
- // Finalize the atom values that are part of the parent.
- DynamicLibraryWriter::finalizeDefaultAtomValues();
- if (_ctx.isDynamic())
- finalizeHexagonRuntimeAtomValues(_targetLayout);
-}
-
-} // 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
deleted file mode 100644
index 3d0d38f387dd..000000000000
--- a/lib/ReaderWriter/ELF/Hexagon/HexagonELFFile.h
+++ /dev/null
@@ -1,149 +0,0 @@
-//===- 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 {
-
-class HexagonELFFile;
-
-class HexagonELFDefinedAtom : public ELFDefinedAtom<ELF32LE> {
- typedef llvm::object::Elf_Sym_Impl<ELF32LE> Elf_Sym;
- typedef llvm::object::Elf_Shdr_Impl<ELF32LE> Elf_Shdr;
-
-public:
- template <typename... T>
- HexagonELFDefinedAtom(T &&... args)
- : ELFDefinedAtom(std::forward<T>(args)...) {}
-
- DefinedAtom::ContentType contentType() const override {
- if (_contentType != DefinedAtom::typeUnknown)
- return _contentType;
- if (_section->sh_flags & llvm::ELF::SHF_HEX_GPREL) {
- if (_section->sh_type == llvm::ELF::SHT_NOBITS)
- return (_contentType = DefinedAtom::typeZeroFillFast);
- return (_contentType = DefinedAtom::typeDataFast);
- }
- return ELFDefinedAtom::contentType();
- }
-
- DefinedAtom::ContentPermissions permissions() const override {
- if (_section->sh_flags & llvm::ELF::SHF_HEX_GPREL)
- return DefinedAtom::permRW_;
- return ELFDefinedAtom::permissions();
- }
-};
-
-class HexagonELFCommonAtom : public ELFCommonAtom<ELF32LE> {
- typedef llvm::object::Elf_Sym_Impl<ELF32LE> Elf_Sym;
- typedef llvm::object::Elf_Shdr_Impl<ELF32LE> Elf_Shdr;
-
-public:
- HexagonELFCommonAtom(const ELFFile<ELF32LE> &file, StringRef symbolName,
- const Elf_Sym *symbol)
- : ELFCommonAtom(file, symbolName, symbol) {}
-
- virtual bool isSmallCommonSymbol() const {
- 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 false;
- }
-
- uint64_t size() const override {
- if (isSmallCommonSymbol())
- return _symbol->st_size;
- return ELFCommonAtom::size();
- }
-
- DefinedAtom::Merge merge() const override {
- if (_symbol->getBinding() == llvm::ELF::STB_WEAK)
- return DefinedAtom::mergeAsWeak;
- if (isSmallCommonSymbol())
- return DefinedAtom::mergeAsTentative;
- return ELFCommonAtom::merge();
- }
-
- DefinedAtom::ContentType contentType() const override {
- if (isSmallCommonSymbol())
- return DefinedAtom::typeZeroFillFast;
- return ELFCommonAtom::contentType();
- }
-
- DefinedAtom::Alignment alignment() const override {
- if (isSmallCommonSymbol())
- return DefinedAtom::Alignment(_symbol->st_value);
- return 1;
- }
-
- DefinedAtom::ContentPermissions permissions() const override {
- if (isSmallCommonSymbol())
- return DefinedAtom::permRW_;
- return ELFCommonAtom::permissions();
- }
-};
-
-class HexagonELFFile : public ELFFile<ELF32LE> {
- typedef llvm::object::Elf_Sym_Impl<ELF32LE> Elf_Sym;
- typedef llvm::object::Elf_Shdr_Impl<ELF32LE> Elf_Shdr;
-
-public:
- HexagonELFFile(std::unique_ptr<MemoryBuffer> mb, ELFLinkingContext &ctx)
- : ELFFile(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::isCommonSymbol(symbol);
- }
-
- /// Process the Defined symbol and create an atom for it.
- ELFDefinedAtom<ELF32LE> *createDefinedAtom(
- 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<ELF32LE> *> &referenceList) override {
- return new (_readerStorage) HexagonELFDefinedAtom(
- *this, symName, sectionName, sym, sectionHdr, contentData,
- referenceStart, referenceEnd, referenceList);
- }
-
- /// Process the Common symbol and create an atom for it.
- ELFCommonAtom<ELF32LE> *createCommonAtom(StringRef symName,
- const Elf_Sym *sym) override {
- return new (_readerStorage) HexagonELFCommonAtom(*this, symName, sym);
- }
-};
-
-} // elf
-} // lld
-
-#endif // LLD_READER_WRITER_ELF_HEXAGON_ELF_FILE_H
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonEncodings.h b/lib/ReaderWriter/ELF/Hexagon/HexagonEncodings.h
deleted file mode 100644
index 6af43d88afbb..000000000000
--- a/lib/ReaderWriter/ELF/Hexagon/HexagonEncodings.h
+++ /dev/null
@@ -1,638 +0,0 @@
-//===- 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.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/Support/Endian.h"
-#include "llvm/Support/ErrorHandling.h"
-
-namespace lld {
-namespace elf {
-
-/// \brief Applying fixup on Hexagon requires the relocator to fetch the fixup
-/// mask from the instruction. To fetch the fixup encoding, the linker uses a
-/// static array that contains the instruction mask, the compare mask and the
-/// relocation mask.
-typedef struct {
- uint32_t insnMask; // Instruction mask.
- uint32_t insnCmpMask; // Compare mask.
- uint32_t insnBitMask; // Relocation mask.
- bool isDuplex; // Indicates if the instruction is a duplex instruction.
-} Instruction;
-
-Instruction insn_encodings[] = {
- // InsnMask CompareMask BitMask IsDuplexInstruction
- { 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 },
-};
-
-/// \brief finds the scatter Bits that need to be used to apply relocations
-inline uint32_t findv4bitmask(uint8_t *location) {
- uint32_t insn = llvm::support::endian::read32le(location);
- for (int32_t i = 0, e = llvm::array_lengthof(insn_encodings); i < e; i++) {
- if ((insn & 0xc000) == 0 && !insn_encodings[i].isDuplex)
- continue;
- if ((insn & 0xc000) != 0 && insn_encodings[i].isDuplex)
- continue;
- if ((insn_encodings[i].insnMask & insn) == insn_encodings[i].insnCmpMask)
- return insn_encodings[i].insnBitMask;
- }
- llvm_unreachable("found unknown Hexagon instruction");
-}
-
-} // namespace elf
-} // namespace lld
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonExecutableWriter.h b/lib/ReaderWriter/ELF/Hexagon/HexagonExecutableWriter.h
deleted file mode 100644
index 390694954a75..000000000000
--- a/lib/ReaderWriter/ELF/Hexagon/HexagonExecutableWriter.h
+++ /dev/null
@@ -1,73 +0,0 @@
-//===- 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 "HexagonLinkingContext.h"
-#include "HexagonTargetHandler.h"
-
-namespace lld {
-namespace elf {
-
-class HexagonTargetLayout;
-
-class HexagonExecutableWriter : public ExecutableWriter<ELF32LE> {
-public:
- HexagonExecutableWriter(HexagonLinkingContext &ctx,
- HexagonTargetLayout &layout);
-
-protected:
- // Add any runtime files and their atoms to the output
- void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
-
- void finalizeDefaultAtomValues() override;
-
- std::error_code setELFHeader() override {
- ExecutableWriter::setELFHeader();
- setHexagonELFHeader(*_elfHeader);
- return std::error_code();
- }
-
-private:
- HexagonLinkingContext &_ctx;
- HexagonTargetLayout &_targetLayout;
-};
-
-HexagonExecutableWriter::HexagonExecutableWriter(HexagonLinkingContext &ctx,
- HexagonTargetLayout &layout)
- : ExecutableWriter(ctx, layout), _ctx(ctx), _targetLayout(layout) {}
-
-void HexagonExecutableWriter::createImplicitFiles(
- std::vector<std::unique_ptr<File>> &result) {
- ExecutableWriter::createImplicitFiles(result);
- // Add the default atoms as defined for hexagon
- auto file =
- llvm::make_unique<RuntimeFile<ELF32LE>>(_ctx, "Hexagon runtime file");
- file->addAbsoluteAtom("_SDA_BASE_");
- if (_ctx.isDynamic()) {
- file->addAbsoluteAtom("_GLOBAL_OFFSET_TABLE_");
- file->addAbsoluteAtom("_DYNAMIC");
- }
- result.push_back(std::move(file));
-}
-
-void HexagonExecutableWriter::finalizeDefaultAtomValues() {
- // Finalize the atom values that are part of the parent.
- ExecutableWriter::finalizeDefaultAtomValues();
- AtomLayout *sdabaseAtom = _targetLayout.findAbsoluteAtom("_SDA_BASE_");
- sdabaseAtom->_virtualAddr = _targetLayout.getSDataSection()->virtualAddr();
- if (_ctx.isDynamic())
- finalizeHexagonRuntimeAtomValues(_targetLayout);
-}
-
-} // namespace elf
-} // namespace lld
-
-#endif // HEXAGON_EXECUTABLE_WRITER_H
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.cpp b/lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.cpp
deleted file mode 100644
index 11eabf7e26fc..000000000000
--- a/lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.cpp
+++ /dev/null
@@ -1,47 +0,0 @@
-//===- lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.cpp -------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "HexagonLinkingContext.h"
-#include "HexagonTargetHandler.h"
-
-namespace lld {
-namespace elf {
-
-std::unique_ptr<ELFLinkingContext>
-createHexagonLinkingContext(llvm::Triple triple) {
- if (triple.getArch() == llvm::Triple::hexagon)
- return llvm::make_unique<HexagonLinkingContext>(triple);
- return nullptr;
-}
-
-HexagonLinkingContext::HexagonLinkingContext(llvm::Triple triple)
- : ELFLinkingContext(triple, std::unique_ptr<TargetHandler>(
- new HexagonTargetHandler(*this))) {}
-
-static const Registry::KindStrings kindStrings[] = {
-#define ELF_RELOC(name, value) LLD_KIND_STRING_ENTRY(name),
-#include "llvm/Support/ELFRelocs/Hexagon.def"
-#undef ELF_RELOC
- LLD_KIND_STRING_END
-};
-
-void HexagonLinkingContext::registerRelocationNames(Registry &registry) {
- registry.addKindTable(Reference::KindNamespace::ELF,
- Reference::KindArch::Hexagon, kindStrings);
-}
-
-void setHexagonELFHeader(ELFHeader<ELF32LE> &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);
-}
-
-} // namespace elf
-} // namespace lld
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.h b/lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.h
deleted file mode 100644
index ab91e405fd56..000000000000
--- a/lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.h
+++ /dev/null
@@ -1,61 +0,0 @@
-//===- lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.h ---------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_LINKING_CONTEXT_H
-#define LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_LINKING_CONTEXT_H
-
-#include "OutputELFWriter.h"
-#include "lld/ReaderWriter/ELFLinkingContext.h"
-#include "llvm/Object/ELF.h"
-#include "llvm/Support/ELF.h"
-
-namespace lld {
-namespace elf {
-
-class HexagonLinkingContext final : public ELFLinkingContext {
-public:
- int getMachineType() const override { return llvm::ELF::EM_HEXAGON; }
- HexagonLinkingContext(llvm::Triple triple);
-
- void addPasses(PassManager &) override;
- void registerRelocationNames(Registry &r) override;
-
- bool isDynamicRelocation(const Reference &r) const override {
- if (r.kindNamespace() != Reference::KindNamespace::ELF)
- return false;
- switch (r.kindValue()) {
- case llvm::ELF::R_HEX_RELATIVE:
- case llvm::ELF::R_HEX_GLOB_DAT:
- return true;
- default:
- return false;
- }
- }
-
- bool isPLTRelocation(const Reference &r) const override {
- if (r.kindNamespace() != Reference::KindNamespace::ELF)
- return false;
- return r.kindValue() == llvm::ELF::R_HEX_JMP_SLOT;
- }
-
- /// \brief Hexagon has only one relative relocation
- /// a) for supporting relative relocs - R_HEX_RELATIVE
- bool isRelativeReloc(const Reference &r) const override {
- if (r.kindNamespace() != Reference::KindNamespace::ELF)
- return false;
- return r.kindValue() == llvm::ELF::R_HEX_RELATIVE;
- }
-};
-
-void setHexagonELFHeader(ELFHeader<ELF32LE> &elfHeader);
-
-} // elf
-} // lld
-
-#endif // LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_LINKING_CONTEXT_H
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.cpp b/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.cpp
deleted file mode 100644
index 0a201b32b5f1..000000000000
--- a/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.cpp
+++ /dev/null
@@ -1,330 +0,0 @@
-//===- lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.cpp ---------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "HexagonEncodings.h"
-#include "HexagonLinkingContext.h"
-#include "HexagonRelocationHandler.h"
-#include "HexagonTargetHandler.h"
-#include "llvm/Support/Endian.h"
-
-using namespace lld;
-using namespace lld::elf;
-using namespace llvm::ELF;
-using namespace llvm::support::endian;
-
-// Scatter val's bits as specified by the mask. Example:
-//
-// Val: 0bABCDEFG
-// Mask: 0b10111100001011
-// Output: 0b00ABCD0000E0FG
-static uint32_t scatterBits(uint32_t val, uint32_t mask) {
- uint32_t result = 0;
- size_t off = 0;
- for (size_t bit = 0; bit < 32; ++bit) {
- if ((mask >> bit) & 1) {
- uint32_t valBit = (val >> off) & 1;
- result |= valBit << bit;
- ++off;
- }
- }
- return result;
-}
-
-static void relocBNPCREL(uint8_t *loc, uint64_t P, uint64_t S, uint64_t A,
- int32_t nBits) {
- int32_t result = (S + A - P) >> 2;
- int32_t range = 1 << nBits;
- if (result < range && result > -range) {
- result = scatterBits(result, findv4bitmask(loc));
- write32le(loc, result | read32le(loc));
- }
-}
-
-/// \brief Word32_LO: 0x00c03fff : (S + A) : Truncate
-static void relocLO16(uint8_t *loc, uint64_t P, uint64_t S, uint64_t A) {
- uint32_t result = S + A;
- result = scatterBits(result, 0x00c03fff);
- write32le(loc, result | read32le(loc));
-}
-
-/// \brief Word32_LO: 0x00c03fff : (S + A) >> 16 : Truncate
-static void relocHI16(uint8_t *loc, uint64_t P, uint64_t S, uint64_t A) {
- uint32_t result = (S + A) >> 16;
- result = scatterBits(result, 0x00c03fff);
- write32le(loc, result | read32le(loc));
-}
-
-/// \brief Word32: 0xffffffff : (S + A) : Truncate
-static void reloc32(uint8_t *loc, uint64_t P, uint64_t S, uint64_t A) {
- uint32_t result = S + A;
- write32le(loc, result | read32le(loc));
-}
-
-static void reloc32_6_X(uint8_t *loc, uint64_t P, uint64_t S, uint64_t A) {
- int64_t result = (S + A) >> 6;
- int64_t range = int64_t(1) << 32;
- if (result > range)
- result = scatterBits(result, 0xfff3fff);
- write32le(loc, result | read32le(loc));
-}
-
-// R_HEX_B32_PCREL_X
-static void relocHexB32PCRELX(uint8_t *loc, uint64_t P, uint64_t S,
- uint64_t A) {
- int64_t result = (S + A - P) >> 6;
- result = scatterBits(result, 0xfff3fff);
- write32le(loc, result | read32le(loc));
-}
-
-// R_HEX_BN_PCREL_X
-static void relocHexBNPCRELX(uint8_t *loc, uint64_t P, uint64_t S, uint64_t A,
- int nbits) {
- int32_t result = (S + A - P) & 0x3f;
- int32_t range = 1 << nbits;
- if (result < range && result > -range) {
- result = scatterBits(result, findv4bitmask(loc));
- write32le(loc, result | read32le(loc));
- }
-}
-
-// R_HEX_6_PCREL_X
-static void relocHex6PCRELX(uint8_t *loc, uint64_t P, uint64_t S, uint64_t A) {
- int32_t result = S + A - P;
- result = scatterBits(result, findv4bitmask(loc));
- write32le(loc, result | read32le(loc));
-}
-
-// R_HEX_N_X : Word32_U6 : (S + A) : Unsigned Truncate
-static void relocHex_N_X(uint8_t *loc, uint64_t P, uint64_t S, uint64_t A) {
- uint32_t result = S + A;
- result = scatterBits(result, findv4bitmask(loc));
- write32le(loc, result | read32le(loc));
-}
-
-// GP REL relocs
-static void relocHexGPRELN(uint8_t *loc, uint64_t P, uint64_t S, uint64_t A,
- uint64_t GP, int nShiftBits) {
- int32_t result = (S + A - GP) >> nShiftBits;
- int32_t range = 1L << 16;
- if (result <= range) {
- result = scatterBits(result, findv4bitmask(loc));
- write32le(loc, result | read32le(loc));
- }
-}
-
-/// \brief Word32_LO: 0x00c03fff : (G) : Truncate
-static void relocHexGOTLO16(uint8_t *loc, uint64_t A, uint64_t GOT) {
- int32_t result = A - GOT;
- result = scatterBits(result, 0x00c03fff);
- write32le(loc, result | read32le(loc));
-}
-
-/// \brief Word32_LO: 0x00c03fff : (G) >> 16 : Truncate
-static void relocHexGOTHI16(uint8_t *loc, uint64_t A, uint64_t GOT) {
- int32_t result = (A - GOT) >> 16;
- result = scatterBits(result, 0x00c03fff);
- write32le(loc, result | read32le(loc));
-}
-
-/// \brief Word32: 0xffffffff : (G) : Truncate
-static void relocHexGOT32(uint8_t *loc, uint64_t A, uint64_t GOT) {
- int32_t result = GOT - A;
- write32le(loc, result | read32le(loc));
-}
-
-/// \brief Word32_U16 : (G) : Truncate
-static void relocHexGOT16(uint8_t *loc, uint64_t A, uint64_t GOT) {
- int32_t result = GOT - A;
- int32_t range = 1L << 16;
- if (result <= range) {
- result = scatterBits(result, findv4bitmask(loc));
- write32le(loc, result | read32le(loc));
- }
-}
-
-static void relocHexGOT32_6_X(uint8_t *loc, uint64_t A, uint64_t GOT) {
- int32_t result = (A - GOT) >> 6;
- result = scatterBits(result, findv4bitmask(loc));
- write32le(loc, result | read32le(loc));
-}
-
-static void relocHexGOT16_X(uint8_t *loc, uint64_t A, uint64_t GOT) {
- int32_t result = A - GOT;
- int32_t range = 1L << 6;
- if (result <= range) {
- result = scatterBits(result, findv4bitmask(loc));
- write32le(loc, result | read32le(loc));
- }
-}
-
-static void relocHexGOT11_X(uint8_t *loc, uint64_t A, uint64_t GOT) {
- uint32_t result = A - GOT;
- result = scatterBits(result, findv4bitmask(loc));
- write32le(loc, result | read32le(loc));
-}
-
-static void relocHexGOTRELSigned(uint8_t *loc, uint64_t P, uint64_t S,
- uint64_t A, uint64_t GOT, int shiftBits) {
- int32_t result = (S + A - GOT) >> shiftBits;
- result = scatterBits(result, findv4bitmask(loc));
- write32le(loc, result | read32le(loc));
-}
-
-static void relocHexGOTRELUnsigned(uint8_t *loc, uint64_t P, uint64_t S,
- uint64_t A, uint64_t GOT) {
- uint32_t result = S + A - GOT;
- result = scatterBits(result, findv4bitmask(loc));
- write32le(loc, result | read32le(loc));
-}
-
-static void relocHexGOTREL_HILO16(uint8_t *loc, uint64_t P, uint64_t S,
- uint64_t A, uint64_t GOT, int shiftBits) {
- int32_t result = (S + A - GOT) >> shiftBits;
- result = scatterBits(result, 0x00c03fff);
- write32le(loc, result | read32le(loc));
-}
-
-static void relocHexGOTREL_32(uint8_t *loc, uint64_t P, uint64_t S, uint64_t A,
- uint64_t GOT) {
- int32_t result = S + A - GOT;
- write32le(loc, result | read32le(loc));
-}
-
-std::error_code HexagonTargetRelocationHandler::applyRelocation(
- ELFWriter &writer, llvm::FileOutputBuffer &buf, const AtomLayout &atom,
- const Reference &ref) const {
- uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset;
- uint8_t *loc = atomContent + ref.offsetInAtom();
- uint64_t target = writer.addressOfAtom(ref.target());
- uint64_t reloc = atom._virtualAddr + ref.offsetInAtom();
-
- if (ref.kindNamespace() != Reference::KindNamespace::ELF)
- return std::error_code();
- assert(ref.kindArch() == Reference::KindArch::Hexagon);
- switch (ref.kindValue()) {
- case R_HEX_B22_PCREL:
- relocBNPCREL(loc, reloc, target, ref.addend(), 21);
- break;
- case R_HEX_B15_PCREL:
- relocBNPCREL(loc, reloc, target, ref.addend(), 14);
- break;
- case R_HEX_B9_PCREL:
- relocBNPCREL(loc, reloc, target, ref.addend(), 8);
- break;
- case R_HEX_LO16:
- relocLO16(loc, reloc, target, ref.addend());
- break;
- case R_HEX_HI16:
- relocHI16(loc, reloc, target, ref.addend());
- break;
- case R_HEX_32:
- reloc32(loc, reloc, target, ref.addend());
- break;
- case R_HEX_32_6_X:
- reloc32_6_X(loc, reloc, target, ref.addend());
- break;
- case R_HEX_B32_PCREL_X:
- relocHexB32PCRELX(loc, reloc, target, ref.addend());
- break;
- case R_HEX_B22_PCREL_X:
- relocHexBNPCRELX(loc, reloc, target, ref.addend(), 21);
- break;
- case R_HEX_B15_PCREL_X:
- relocHexBNPCRELX(loc, reloc, target, ref.addend(), 14);
- break;
- case R_HEX_B13_PCREL_X:
- relocHexBNPCRELX(loc, reloc, target, ref.addend(), 12);
- break;
- case R_HEX_B9_PCREL_X:
- relocHexBNPCRELX(loc, reloc, target, ref.addend(), 8);
- break;
- case R_HEX_B7_PCREL_X:
- relocHexBNPCRELX(loc, reloc, target, ref.addend(), 6);
- break;
- case R_HEX_GPREL16_0:
- relocHexGPRELN(loc, reloc, target, ref.addend(),
- _targetLayout.getSDataSection()->virtualAddr(), 0);
- break;
- case R_HEX_GPREL16_1:
- relocHexGPRELN(loc, reloc, target, ref.addend(),
- _targetLayout.getSDataSection()->virtualAddr(), 1);
- break;
- case R_HEX_GPREL16_2:
- relocHexGPRELN(loc, reloc, target, ref.addend(),
- _targetLayout.getSDataSection()->virtualAddr(), 2);
- break;
- case R_HEX_GPREL16_3:
- relocHexGPRELN(loc, reloc, target, ref.addend(),
- _targetLayout.getSDataSection()->virtualAddr(), 3);
- break;
- case R_HEX_16_X:
- case R_HEX_12_X:
- case R_HEX_11_X:
- case R_HEX_10_X:
- case R_HEX_9_X:
- case R_HEX_8_X:
- case R_HEX_7_X:
- case R_HEX_6_X:
- relocHex_N_X(loc, reloc, target, ref.addend());
- break;
- case R_HEX_6_PCREL_X:
- relocHex6PCRELX(loc, reloc, target, ref.addend());
- break;
- case R_HEX_JMP_SLOT:
- case R_HEX_GLOB_DAT:
- break;
- case R_HEX_GOTREL_32:
- relocHexGOTREL_32(loc, reloc, target, ref.addend(),
- _targetLayout.getGOTSymAddr());
- break;
- case R_HEX_GOTREL_LO16:
- relocHexGOTREL_HILO16(loc, reloc, target, ref.addend(),
- _targetLayout.getGOTSymAddr(), 0);
- break;
- case R_HEX_GOTREL_HI16:
- relocHexGOTREL_HILO16(loc, reloc, target, ref.addend(),
- _targetLayout.getGOTSymAddr(), 16);
- break;
- case R_HEX_GOT_LO16:
- relocHexGOTLO16(loc, target, _targetLayout.getGOTSymAddr());
- break;
- case R_HEX_GOT_HI16:
- relocHexGOTHI16(loc, target, _targetLayout.getGOTSymAddr());
- break;
- case R_HEX_GOT_32:
- relocHexGOT32(loc, target, _targetLayout.getGOTSymAddr());
- break;
- case R_HEX_GOT_16:
- relocHexGOT16(loc, target, _targetLayout.getGOTSymAddr());
- break;
- case R_HEX_GOT_32_6_X:
- relocHexGOT32_6_X(loc, target, _targetLayout.getGOTSymAddr());
- break;
- case R_HEX_GOT_16_X:
- relocHexGOT16_X(loc, target, _targetLayout.getGOTSymAddr());
- break;
- case R_HEX_GOT_11_X:
- relocHexGOT11_X(loc, target, _targetLayout.getGOTSymAddr());
- break;
- case R_HEX_GOTREL_32_6_X:
- relocHexGOTRELSigned(loc, reloc, target, ref.addend(),
- _targetLayout.getGOTSymAddr(), 6);
- break;
- case R_HEX_GOTREL_16_X:
- case R_HEX_GOTREL_11_X:
- relocHexGOTRELUnsigned(loc, reloc, target, ref.addend(),
- _targetLayout.getGOTSymAddr());
- break;
-
- default:
- return make_unhandled_reloc_error();
- }
-
- return std::error_code();
-}
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.h b/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.h
deleted file mode 100644
index 6afba0ddb8f3..000000000000
--- a/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.h
+++ /dev/null
@@ -1,33 +0,0 @@
-//===- lld/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.h -----------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_RELOCATION_HANDLER_H
-#define LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_RELOCATION_HANDLER_H
-
-#include "lld/ReaderWriter/ELFLinkingContext.h"
-
-namespace lld {
-namespace elf {
-class HexagonTargetHandler;
-class HexagonTargetLayout;
-
-class HexagonTargetRelocationHandler final : public TargetRelocationHandler {
-public:
- HexagonTargetRelocationHandler(HexagonTargetLayout &layout)
- : _targetLayout(layout) {}
-
- std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &,
- const AtomLayout &,
- const Reference &) const override;
-
-private:
- HexagonTargetLayout &_targetLayout;
-};
-} // elf
-} // lld
-#endif
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.cpp b/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.cpp
deleted file mode 100644
index 6c0360c310f4..000000000000
--- a/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.cpp
+++ /dev/null
@@ -1,382 +0,0 @@
-//===- lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.cpp --------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "HexagonExecutableWriter.h"
-#include "HexagonDynamicLibraryWriter.h"
-#include "HexagonLinkingContext.h"
-#include "HexagonTargetHandler.h"
-
-using namespace llvm::ELF;
-
-using llvm::makeArrayRef;
-
-namespace lld {
-namespace elf {
-
-HexagonTargetHandler::HexagonTargetHandler(HexagonLinkingContext &ctx)
- : _ctx(ctx), _targetLayout(new HexagonTargetLayout(ctx)),
- _relocationHandler(new HexagonTargetRelocationHandler(*_targetLayout)) {}
-
-std::unique_ptr<Writer> HexagonTargetHandler::getWriter() {
- switch (_ctx.getOutputELFType()) {
- case llvm::ELF::ET_EXEC:
- return llvm::make_unique<HexagonExecutableWriter>(_ctx, *_targetLayout);
- case llvm::ELF::ET_DYN:
- return llvm::make_unique<HexagonDynamicLibraryWriter>(_ctx, *_targetLayout);
- case llvm::ELF::ET_REL:
- llvm_unreachable("TODO: support -r mode");
- default:
- llvm_unreachable("unsupported output type");
- }
-}
-
-using namespace llvm::ELF;
-
-// .got atom
-const uint8_t hexagonGotAtomContent[4] = { 0 };
-// .got.plt atom (entry 0)
-const uint8_t hexagonGotPlt0AtomContent[16] = { 0 };
-// .got.plt atom (all other entries)
-const uint8_t hexagonGotPltAtomContent[4] = { 0 };
-// .plt (entry 0)
-const uint8_t hexagonPlt0AtomContent[28] = {
- 0x00, 0x40, 0x00, 0x00, // { immext (#0)
- 0x1c, 0xc0, 0x49, 0x6a, // r28 = add (pc, ##GOT0@PCREL) } # address of GOT0
- 0x0e, 0x42, 0x9c, 0xe2, // { r14 -= add (r28, #16) # offset of GOTn from GOTa
- 0x4f, 0x40, 0x9c, 0x91, // r15 = memw (r28 + #8) # object ID at GOT2
- 0x3c, 0xc0, 0x9c, 0x91, // r28 = memw (r28 + #4) }# dynamic link at GOT1
- 0x0e, 0x42, 0x0e, 0x8c, // { r14 = asr (r14, #2) # index of PLTn
- 0x00, 0xc0, 0x9c, 0x52, // jumpr r28 } # call dynamic linker
-};
-
-// .plt (other entries)
-const uint8_t hexagonPltAtomContent[16] = {
- 0x00, 0x40, 0x00, 0x00, // { immext (#0)
- 0x0e, 0xc0, 0x49, 0x6a, // r14 = add (pc, ##GOTn@PCREL) } # address of GOTn
- 0x1c, 0xc0, 0x8e, 0x91, // r28 = memw (r14) # contents of GOTn
- 0x00, 0xc0, 0x9c, 0x52, // jumpr r28 # call it
-};
-
-class HexagonGOTAtom : public GOTAtom {
-public:
- HexagonGOTAtom(const File &f) : GOTAtom(f, ".got") {}
-
- ArrayRef<uint8_t> rawContent() const override {
- return makeArrayRef(hexagonGotAtomContent);
- }
-
- Alignment alignment() const override { return 4; }
-};
-
-class HexagonGOTPLTAtom : public GOTAtom {
-public:
- HexagonGOTPLTAtom(const File &f) : GOTAtom(f, ".got.plt") {}
-
- ArrayRef<uint8_t> rawContent() const override {
- return makeArrayRef(hexagonGotPltAtomContent);
- }
-
- Alignment alignment() const override { return 4; }
-};
-
-class HexagonGOTPLT0Atom : public GOTAtom {
-public:
- HexagonGOTPLT0Atom(const File &f) : GOTAtom(f, ".got.plt") {}
-
- ArrayRef<uint8_t> rawContent() const override {
- return makeArrayRef(hexagonGotPlt0AtomContent);
- }
-
- Alignment alignment() const override { return 8; }
-};
-
-class HexagonPLT0Atom : public PLT0Atom {
-public:
- HexagonPLT0Atom(const File &f) : PLT0Atom(f) {}
-
- ArrayRef<uint8_t> rawContent() const override {
- return makeArrayRef(hexagonPlt0AtomContent);
- }
-};
-
-class HexagonPLTAtom : public PLTAtom {
-
-public:
- HexagonPLTAtom(const File &f, StringRef secName) : PLTAtom(f, secName) {}
-
- ArrayRef<uint8_t> rawContent() const override {
- return makeArrayRef(hexagonPltAtomContent);
- }
-};
-
-class ELFPassFile : public SimpleFile {
-public:
- ELFPassFile(const ELFLinkingContext &eti) : SimpleFile("ELFPassFile") {
- setOrdinal(eti.getNextOrdinalAndIncrement());
- }
-
- llvm::BumpPtrAllocator _alloc;
-};
-
-/// \brief Create GOT and PLT entries for relocations. Handles standard GOT/PLT
-template <class Derived> class GOTPLTPass : public Pass {
- /// \brief Handle a specific reference.
- void handleReference(const DefinedAtom &atom, const Reference &ref) {
- if (ref.kindNamespace() != Reference::KindNamespace::ELF)
- return;
- assert(ref.kindArch() == Reference::KindArch::Hexagon);
- switch (ref.kindValue()) {
- case R_HEX_PLT_B22_PCREL:
- case R_HEX_B22_PCREL:
- static_cast<Derived *>(this)->handlePLT32(ref);
- break;
- case R_HEX_GOT_LO16:
- case R_HEX_GOT_HI16:
- case R_HEX_GOT_32_6_X:
- case R_HEX_GOT_16_X:
- case R_HEX_GOT_11_X:
- static_cast<Derived *>(this)->handleGOTREL(ref);
- break;
- }
- }
-
-protected:
- /// \brief Create a GOT entry containing 0.
- const GOTAtom *getNullGOT() {
- if (!_null) {
- _null = new (_file._alloc) HexagonGOTPLTAtom(_file);
-#ifndef NDEBUG
- _null->_name = "__got_null";
-#endif
- }
- return _null;
- }
-
-public:
- GOTPLTPass(const ELFLinkingContext &ctx) : _file(ctx) {}
-
- /// \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.
- std::error_code perform(SimpleFile &mf) override {
- // Process all references.
- for (const auto &atom : mf.defined())
- for (const auto &ref : *atom)
- handleReference(*atom, *ref);
-
- // Add all created atoms to the link.
- uint64_t ordinal = 0;
- if (_plt0) {
- _plt0->setOrdinal(ordinal++);
- mf.addAtom(*_plt0);
- }
- for (auto &plt : _pltVector) {
- plt->setOrdinal(ordinal++);
- mf.addAtom(*plt);
- }
- if (_null) {
- _null->setOrdinal(ordinal++);
- mf.addAtom(*_null);
- }
- if (_got0) {
- _got0->setOrdinal(ordinal++);
- mf.addAtom(*_got0);
- }
- for (auto &got : _gotVector) {
- got->setOrdinal(ordinal++);
- mf.addAtom(*got);
- }
-
- return std::error_code();
- }
-
-protected:
- /// \brief Owner of all the Atoms created by this pass.
- ELFPassFile _file;
-
- /// \brief Map Atoms to their GOT entries.
- llvm::DenseMap<const Atom *, GOTAtom *> _gotMap;
-
- /// \brief Map Atoms to their PLT entries.
- llvm::DenseMap<const Atom *, PLTAtom *> _pltMap;
-
- /// \brief the list of GOT/PLT atoms
- std::vector<GOTAtom *> _gotVector;
- std::vector<PLTAtom *> _pltVector;
-
- /// \brief GOT entry that is always 0. Used for undefined weaks.
- GOTAtom *_null = nullptr;
-
- /// \brief The got and plt entries for .PLT0. This is used to call into the
- /// dynamic linker for symbol resolution.
- /// @{
- PLT0Atom *_plt0 = nullptr;
- GOTAtom *_got0 = nullptr;
- /// @}
-};
-
-class DynamicGOTPLTPass final : public GOTPLTPass<DynamicGOTPLTPass> {
-public:
- DynamicGOTPLTPass(const HexagonLinkingContext &ctx) : GOTPLTPass(ctx) {
- _got0 = new (_file._alloc) HexagonGOTPLT0Atom(_file);
-#ifndef NDEBUG
- _got0->_name = "__got0";
-#endif
- }
-
- const PLT0Atom *getPLT0() {
- if (_plt0)
- return _plt0;
- _plt0 = new (_file._alloc) HexagonPLT0Atom(_file);
- _plt0->addReferenceELF_Hexagon(R_HEX_B32_PCREL_X, 0, _got0, 0);
- _plt0->addReferenceELF_Hexagon(R_HEX_6_PCREL_X, 4, _got0, 4);
- DEBUG_WITH_TYPE("PLT", llvm::dbgs() << "[ PLT0/GOT0 ] "
- << "Adding plt0/got0 \n");
- return _plt0;
- }
-
- const PLTAtom *getPLTEntry(const Atom *a) {
- auto plt = _pltMap.find(a);
- if (plt != _pltMap.end())
- return plt->second;
- auto ga = new (_file._alloc) HexagonGOTPLTAtom(_file);
- ga->addReferenceELF_Hexagon(R_HEX_JMP_SLOT, 0, a, 0);
- auto pa = new (_file._alloc) HexagonPLTAtom(_file, ".plt");
- pa->addReferenceELF_Hexagon(R_HEX_B32_PCREL_X, 0, ga, 0);
- pa->addReferenceELF_Hexagon(R_HEX_6_PCREL_X, 4, ga, 4);
-
- // Point the got entry to the PLT0 atom initially
- ga->addReferenceELF_Hexagon(R_HEX_32, 0, getPLT0(), 0);
-#ifndef NDEBUG
- ga->_name = "__got_";
- ga->_name += a->name();
- pa->_name = "__plt_";
- pa->_name += a->name();
- DEBUG_WITH_TYPE("PLT", llvm::dbgs() << "[" << a->name() << "] "
- << "Adding plt/got: " << pa->_name
- << "/" << ga->_name << "\n");
-#endif
- _gotMap[a] = ga;
- _pltMap[a] = pa;
- _gotVector.push_back(ga);
- _pltVector.push_back(pa);
- return pa;
- }
-
- const GOTAtom *getGOTEntry(const Atom *a) {
- auto got = _gotMap.find(a);
- if (got != _gotMap.end())
- return got->second;
- auto ga = new (_file._alloc) HexagonGOTAtom(_file);
- ga->addReferenceELF_Hexagon(R_HEX_GLOB_DAT, 0, a, 0);
-
-#ifndef NDEBUG
- ga->_name = "__got_";
- ga->_name += a->name();
- DEBUG_WITH_TYPE("GOT", llvm::dbgs() << "[" << a->name() << "] "
- << "Adding got: " << ga->_name << "\n");
-#endif
- _gotMap[a] = ga;
- _gotVector.push_back(ga);
- return ga;
- }
-
- std::error_code handleGOTREL(const Reference &ref) {
- // Turn this so that the target is set to the GOT entry
- const_cast<Reference &>(ref).setTarget(getGOTEntry(ref.target()));
- return std::error_code();
- }
-
- std::error_code handlePLT32(const Reference &ref) {
- // Turn this into a PC32 to the PLT entry.
- assert(ref.kindNamespace() == Reference::KindNamespace::ELF);
- assert(ref.kindArch() == Reference::KindArch::Hexagon);
- const_cast<Reference &>(ref).setKindValue(R_HEX_B22_PCREL);
- const_cast<Reference &>(ref).setTarget(getPLTEntry(ref.target()));
- return std::error_code();
- }
-};
-
-void HexagonLinkingContext::addPasses(PassManager &pm) {
- if (isDynamic())
- pm.add(llvm::make_unique<DynamicGOTPLTPass>(*this));
- ELFLinkingContext::addPasses(pm);
-}
-
-void SDataSection::doPreFlight() {
- // sort the atoms on the alignments they have been set
- std::stable_sort(_atoms.begin(), _atoms.end(), [](const AtomLayout *A,
- const AtomLayout *B) {
- const DefinedAtom *definedAtomA = cast<DefinedAtom>(A->_atom);
- const DefinedAtom *definedAtomB = cast<DefinedAtom>(B->_atom);
- int64_t alignmentA = definedAtomA->alignment().value;
- int64_t alignmentB = definedAtomB->alignment().value;
- if (alignmentA == alignmentB) {
- if (definedAtomA->merge() == DefinedAtom::mergeAsTentative)
- return false;
- if (definedAtomB->merge() == DefinedAtom::mergeAsTentative)
- return true;
- }
- return alignmentA < alignmentB;
- });
-
- // Set the fileOffset, and the appropriate size of the section
- for (auto &ai : _atoms) {
- const DefinedAtom *definedAtom = cast<DefinedAtom>(ai->_atom);
- DefinedAtom::Alignment atomAlign = definedAtom->alignment();
- uint64_t fOffset = alignOffset(fileSize(), atomAlign);
- uint64_t mOffset = alignOffset(memSize(), atomAlign);
- ai->_fileOffset = fOffset;
- _fsize = fOffset + definedAtom->size();
- _msize = mOffset + definedAtom->size();
- }
-} // finalize
-
-SDataSection::SDataSection(const HexagonLinkingContext &ctx)
- : AtomSection(ctx, ".sdata", DefinedAtom::typeDataFast, 0,
- HexagonTargetLayout::ORDER_SDATA) {
- _type = SHT_PROGBITS;
- _flags = SHF_ALLOC | SHF_WRITE;
- _alignment = 4096;
-}
-
-const AtomLayout *SDataSection::appendAtom(const Atom *atom) {
- const DefinedAtom *definedAtom = cast<DefinedAtom>(atom);
- DefinedAtom::Alignment atomAlign = definedAtom->alignment();
- uint64_t alignment = atomAlign.value;
- _atoms.push_back(new (_alloc) AtomLayout(atom, 0, 0));
- // Set the section alignment to the largest alignment
- // std::max doesn't support uint64_t
- if (_alignment < alignment)
- _alignment = alignment;
- return _atoms.back();
-}
-
-void finalizeHexagonRuntimeAtomValues(HexagonTargetLayout &layout) {
- AtomLayout *gotAtom = layout.findAbsoluteAtom("_GLOBAL_OFFSET_TABLE_");
- OutputSection<ELF32LE> *gotpltSection = layout.findOutputSection(".got.plt");
- if (gotpltSection)
- gotAtom->_virtualAddr = gotpltSection->virtualAddr();
- else
- gotAtom->_virtualAddr = 0;
- AtomLayout *dynamicAtom = layout.findAbsoluteAtom("_DYNAMIC");
- OutputSection<ELF32LE> *dynamicSection = layout.findOutputSection(".dynamic");
- if (dynamicSection)
- dynamicAtom->_virtualAddr = dynamicSection->virtualAddr();
- else
- dynamicAtom->_virtualAddr = 0;
-}
-
-} // namespace elf
-} // namespace lld
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.h b/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.h
deleted file mode 100644
index b1366bed09ea..000000000000
--- a/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.h
+++ /dev/null
@@ -1,134 +0,0 @@
-//===- lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.h ----------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef HEXAGON_TARGET_HANDLER_H
-#define HEXAGON_TARGET_HANDLER_H
-
-#include "ELFReader.h"
-#include "HexagonELFFile.h"
-#include "HexagonRelocationHandler.h"
-#include "TargetLayout.h"
-
-namespace lld {
-namespace elf {
-class HexagonLinkingContext;
-
-/// \brief Handle Hexagon SData section
-class SDataSection : public AtomSection<ELF32LE> {
-public:
- SDataSection(const HexagonLinkingContext &ctx);
-
- /// \brief Finalize the section contents before writing
- void doPreFlight() override;
-
- /// \brief Does this section have an output segment.
- bool hasOutputSegment() const override { return true; }
-
- const AtomLayout *appendAtom(const Atom *atom) override;
-};
-
-/// \brief TargetLayout for Hexagon
-class HexagonTargetLayout final : public TargetLayout<ELF32LE> {
-public:
- enum HexagonSectionOrder {
- ORDER_SDATA = 205
- };
-
- HexagonTargetLayout(HexagonLinkingContext &ctx)
- : TargetLayout(ctx), _sdataSection(ctx) {}
-
- /// \brief Return the section order for a input section
- TargetLayout::SectionOrder
- getSectionOrder(StringRef name, int32_t contentType,
- int32_t contentPermissions) override {
- if (contentType == DefinedAtom::typeDataFast ||
- contentType == DefinedAtom::typeZeroFillFast)
- return ORDER_SDATA;
- return TargetLayout::getSectionOrder(name, contentType, contentPermissions);
- }
-
- /// \brief Return the appropriate input section name.
- StringRef getInputSectionName(const DefinedAtom *da) const override {
- switch (da->contentType()) {
- case DefinedAtom::typeDataFast:
- case DefinedAtom::typeZeroFillFast:
- return ".sdata";
- default:
- break;
- }
- return TargetLayout::getInputSectionName(da);
- }
-
- /// \brief Gets or creates a section.
- AtomSection<ELF32LE> *
- createSection(StringRef name, int32_t contentType,
- DefinedAtom::ContentPermissions contentPermissions,
- TargetLayout::SectionOrder sectionOrder) override {
- if (contentType == DefinedAtom::typeDataFast ||
- contentType == DefinedAtom::typeZeroFillFast)
- return &_sdataSection;
- return TargetLayout::createSection(name, contentType, contentPermissions,
- sectionOrder);
- }
-
- /// \brief get the segment type for the section thats defined by the target
- TargetLayout::SegmentType
- getSegmentType(const Section<ELF32LE> *section) const override {
- if (section->order() == ORDER_SDATA)
- return PT_LOAD;
- return TargetLayout::getSegmentType(section);
- }
-
- Section<ELF32LE> *getSDataSection() { return &_sdataSection; }
-
- uint64_t getGOTSymAddr() {
- std::call_once(_gotOnce, [this]() {
- if (AtomLayout *got = findAbsoluteAtom("_GLOBAL_OFFSET_TABLE_"))
- _gotAddr = got->_virtualAddr;
- });
- return _gotAddr;
- }
-
-private:
- SDataSection _sdataSection;
- uint64_t _gotAddr = 0;
- std::once_flag _gotOnce;
-};
-
-/// \brief TargetHandler for Hexagon
-class HexagonTargetHandler final : public TargetHandler {
-public:
- HexagonTargetHandler(HexagonLinkingContext &targetInfo);
-
- const TargetRelocationHandler &getRelocationHandler() const override {
- return *_relocationHandler;
- }
-
- std::unique_ptr<Reader> getObjReader() override {
- return llvm::make_unique<ELFReader<HexagonELFFile>>(_ctx);
- }
-
- std::unique_ptr<Reader> getDSOReader() override {
- return llvm::make_unique<ELFReader<DynamicFile<ELF32LE>>>(_ctx);
- }
-
- std::unique_ptr<Writer> getWriter() override;
-
-private:
- HexagonLinkingContext &_ctx;
- std::unique_ptr<HexagonTargetLayout> _targetLayout;
- std::unique_ptr<HexagonTargetRelocationHandler> _relocationHandler;
-};
-
-void finalizeHexagonRuntimeAtomValues(HexagonTargetLayout &layout);
-
-} // end namespace elf
-} // end namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/ELF/Mips/CMakeLists.txt b/lib/ReaderWriter/ELF/Mips/CMakeLists.txt
deleted file mode 100644
index fd52a08ad2d8..000000000000
--- a/lib/ReaderWriter/ELF/Mips/CMakeLists.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-add_lld_library(lldMipsELFTarget
- MipsAbiInfoHandler.cpp
- MipsCtorsOrderPass.cpp
- MipsELFFile.cpp
- MipsELFWriters.cpp
- MipsLinkingContext.cpp
- MipsRelocationHandler.cpp
- MipsRelocationPass.cpp
- MipsSectionChunks.cpp
- MipsTargetHandler.cpp
- MipsTargetLayout.cpp
- LINK_LIBS
- lldELF
- lldReaderWriter
- lldCore
- LLVMObject
- LLVMSupport
- )
diff --git a/lib/ReaderWriter/ELF/Mips/MipsAbiInfoHandler.cpp b/lib/ReaderWriter/ELF/Mips/MipsAbiInfoHandler.cpp
deleted file mode 100644
index ad4e62e64680..000000000000
--- a/lib/ReaderWriter/ELF/Mips/MipsAbiInfoHandler.cpp
+++ /dev/null
@@ -1,675 +0,0 @@
-//===- lib/ReaderWriter/ELF/MipsAbiInfoHandler.cpp ------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "MipsAbiInfoHandler.h"
-#include "lld/Core/Error.h"
-#include "lld/ReaderWriter/ELFLinkingContext.h"
-#include "llvm/ADT/Twine.h"
-#include "llvm/Support/ELF.h"
-#include "llvm/Support/MipsABIFlags.h"
-#include "llvm/Support/raw_ostream.h"
-
-using namespace lld;
-using namespace lld::elf;
-using namespace llvm;
-using namespace llvm::ELF;
-using namespace llvm::Mips;
-
-namespace {
-
-// The joined set of MIPS ISAs and MIPS ISA extensions.
-enum MipsISAs {
- ArchNone,
-
- // General ISAs
- Arch1,
- Arch2,
- Arch3,
- Arch4,
- Arch5,
- Arch32,
- Arch32r2,
- Arch32r3,
- Arch32r5,
- Arch32r6,
- Arch64,
- Arch64r2,
- Arch64r3,
- Arch64r5,
- Arch64r6,
-
- // CPU specific ISAs
- Arch3900,
- Arch4010,
- Arch4100,
- Arch4111,
- Arch4120,
- Arch4650,
- Arch5400,
- Arch5500,
- Arch5900,
- Arch9000,
- Arch10000,
- ArchLs2e,
- ArchLs2f,
- ArchLs3a,
- ArchOcteon,
- ArchOcteonP,
- ArchOcteon2,
- ArchOcteon3,
- ArchSB1,
- ArchXLR
-};
-
-struct MipsISATreeEdge {
- MipsISAs child;
- MipsISAs parent;
-};
-
-struct ElfArchPair {
- uint32_t _elfFlag;
- MipsISAs _arch;
-};
-
-struct AbiIsaArchPair {
- uint8_t _isaLevel;
- uint8_t _isaRev;
- uint8_t _isaExt;
- MipsISAs _arch;
-};
-}
-
-static const MipsISATreeEdge isaTree[] = {
- // MIPS32R6 and MIPS64R6 are not compatible with other extensions
-
- // MIPS64R2 extensions.
- {ArchOcteon3, ArchOcteon2},
- {ArchOcteon2, ArchOcteonP},
- {ArchOcteonP, ArchOcteon},
- {ArchOcteon, Arch64r2},
- {ArchLs3a, Arch64r2},
-
- // MIPS64 extensions.
- {Arch64r2, Arch64},
- {ArchSB1, Arch64},
- {ArchXLR, Arch64},
-
- // MIPS V extensions.
- {Arch64, Arch5},
-
- // R5000 extensions.
- {Arch5500, Arch5400},
-
- // MIPS IV extensions.
- {Arch5, Arch4},
- {Arch5400, Arch4},
- {Arch9000, Arch4},
-
- // VR4100 extensions.
- {Arch4120, Arch4100},
- {Arch4111, Arch4100},
-
- // MIPS III extensions.
- {ArchLs2e, Arch3},
- {ArchLs2f, Arch3},
- {Arch4650, Arch3},
- {Arch4100, Arch3},
- {Arch4010, Arch3},
- {Arch5900, Arch3},
- {Arch4, Arch3},
-
- // MIPS32 extensions.
- {Arch32r2, Arch32},
-
- // MIPS II extensions.
- {Arch3, Arch2},
- {Arch32, Arch2},
-
- // MIPS I extensions.
- {Arch3900, Arch1},
- {Arch2, Arch1},
-};
-
-// Conversion ELF arch flags => MipsISAs
-static const ElfArchPair elfArchPairs[] = {
- {EF_MIPS_ARCH_1 | EF_MIPS_MACH_3900, Arch3900},
- {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4010, Arch4010},
- {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100, Arch4100},
- {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4111, Arch4111},
- {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4120, Arch4120},
- {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4650, Arch4650},
- {EF_MIPS_ARCH_4 | EF_MIPS_MACH_5400, Arch5400},
- {EF_MIPS_ARCH_4 | EF_MIPS_MACH_5500, Arch5500},
- {EF_MIPS_ARCH_3 | EF_MIPS_MACH_5900, Arch5900},
- {EF_MIPS_ARCH_4 | EF_MIPS_MACH_9000, Arch9000},
- {EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2E, ArchLs2e},
- {EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2F, ArchLs2f},
- {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_LS3A, ArchLs3a},
- {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON, ArchOcteon},
- {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON2, ArchOcteon2},
- {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON3, ArchOcteon3},
- {EF_MIPS_ARCH_64 | EF_MIPS_MACH_SB1, ArchSB1},
- {EF_MIPS_ARCH_64 | EF_MIPS_MACH_XLR, ArchXLR},
- {EF_MIPS_ARCH_1, Arch1},
- {EF_MIPS_ARCH_2, Arch2},
- {EF_MIPS_ARCH_3, Arch3},
- {EF_MIPS_ARCH_4, Arch4},
- {EF_MIPS_ARCH_5, Arch5},
- {EF_MIPS_ARCH_32, Arch32},
- {EF_MIPS_ARCH_32R2, Arch32r2},
- {EF_MIPS_ARCH_32R6, Arch32r6},
- {EF_MIPS_ARCH_64, Arch64},
- {EF_MIPS_ARCH_64R2, Arch64r2},
- {EF_MIPS_ARCH_64R6, Arch64r6}
-};
-
-// Conversion MipsISAs => ELF arch flags
-static const ElfArchPair archElfPairs[] = {
- {EF_MIPS_ARCH_1, Arch1},
- {EF_MIPS_ARCH_2, Arch2},
- {EF_MIPS_ARCH_3, Arch3},
- {EF_MIPS_ARCH_4, Arch4},
- {EF_MIPS_ARCH_5, Arch5},
- {EF_MIPS_ARCH_32, Arch32},
- {EF_MIPS_ARCH_32R2, Arch32r2},
- {EF_MIPS_ARCH_32R2, Arch32r3},
- {EF_MIPS_ARCH_32R2, Arch32r5},
- {EF_MIPS_ARCH_32R6, Arch32r6},
- {EF_MIPS_ARCH_64, Arch64},
- {EF_MIPS_ARCH_64R2, Arch64r2},
- {EF_MIPS_ARCH_64R2, Arch64r3},
- {EF_MIPS_ARCH_64R2, Arch64r5},
- {EF_MIPS_ARCH_64R6, Arch64r6},
- {EF_MIPS_ARCH_1 | EF_MIPS_MACH_3900, Arch3900},
- {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4010, Arch4010},
- {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100, Arch4100},
- {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4111, Arch4111},
- {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4120, Arch4120},
- {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4650, Arch4650},
- {EF_MIPS_ARCH_4 | EF_MIPS_MACH_5400, Arch5400},
- {EF_MIPS_ARCH_4 | EF_MIPS_MACH_5500, Arch5500},
- {EF_MIPS_ARCH_3 | EF_MIPS_MACH_5900, Arch5900},
- {EF_MIPS_ARCH_4 | EF_MIPS_MACH_9000, Arch9000},
- {EF_MIPS_ARCH_4, Arch10000},
- {EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2E, ArchLs2e},
- {EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2F, ArchLs2f},
- {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_LS3A, ArchLs3a},
- {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON, ArchOcteon},
- {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON, ArchOcteonP},
- {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON2, ArchOcteon2},
- {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON3, ArchOcteon3},
- {EF_MIPS_ARCH_64 | EF_MIPS_MACH_SB1, ArchSB1},
- {EF_MIPS_ARCH_64 | EF_MIPS_MACH_SB1, ArchXLR}
-};
-
-// Conversion .MIPS.abiflags isa/level/extension <=> MipsISAs
-static const AbiIsaArchPair abiIsaArchPair[] = {
- { 0, 0, 0, ArchNone},
- { 1, 0, 0, Arch1},
- { 2, 0, 0, Arch2},
- { 3, 0, 0, Arch3},
- { 4, 0, 0, Arch4},
- { 5, 0, 0, Arch5},
- {32, 1, 0, Arch32},
- {32, 2, 0, Arch32r2},
- {32, 3, 0, Arch32r3},
- {32, 5, 0, Arch32r5},
- {32, 6, 0, Arch32r6},
- {64, 1, 0, Arch64},
- {64, 2, 0, Arch64r2},
- {64, 3, 0, Arch64r3},
- {64, 5, 0, Arch64r5},
- {64, 6, 0, Arch64r6},
- { 1, 0, AFL_EXT_3900, Arch3900},
- { 3, 0, AFL_EXT_4010, Arch4010},
- { 3, 0, AFL_EXT_4100, Arch4100},
- { 3, 0, AFL_EXT_4111, Arch4111},
- { 3, 0, AFL_EXT_4120, Arch4120},
- { 3, 0, AFL_EXT_4650, Arch4650},
- { 4, 0, AFL_EXT_5400, Arch5400},
- { 4, 0, AFL_EXT_5500, Arch5500},
- { 3, 0, AFL_EXT_5900, Arch5900},
- { 4, 0, AFL_EXT_10000, Arch10000},
- { 3, 0, AFL_EXT_LOONGSON_2E, ArchLs2e},
- { 3, 0, AFL_EXT_LOONGSON_2F, ArchLs2f},
- {64, 2, AFL_EXT_LOONGSON_3A, ArchLs3a},
- {64, 2, AFL_EXT_OCTEON, ArchOcteon},
- {64, 2, AFL_EXT_OCTEON2, ArchOcteon2},
- {64, 2, AFL_EXT_OCTEON3, ArchOcteon3},
- {64, 1, AFL_EXT_SB1, ArchSB1},
- {64, 1, AFL_EXT_XLR, ArchXLR}
-};
-
-static bool matchMipsISA(MipsISAs base, MipsISAs ext) {
- if (base == ext)
- return true;
- if (base == Arch32 && matchMipsISA(Arch64, ext))
- return true;
- if (base == Arch32r2 && matchMipsISA(Arch64r2, ext))
- return true;
- for (const auto &edge : isaTree) {
- if (ext == edge.child) {
- ext = edge.parent;
- if (ext == base)
- return true;
- }
- }
- return false;
-}
-
-static bool is32BitElfFlags(unsigned flags) {
- if (flags & EF_MIPS_32BITMODE)
- return true;
-
- unsigned arch = flags & EF_MIPS_ARCH;
- if (arch == EF_MIPS_ARCH_1 || arch == EF_MIPS_ARCH_2 ||
- arch == EF_MIPS_ARCH_32 || arch == EF_MIPS_ARCH_32R2 ||
- arch == EF_MIPS_ARCH_32R6)
- return true;
-
- unsigned abi = flags & EF_MIPS_ABI;
- if (abi == EF_MIPS_ABI_O32 || abi == EF_MIPS_ABI_EABI32)
- return true;
-
- return false;
-}
-
-static ErrorOr<MipsISAs> headerFlagsToIsa(uint32_t flags) {
- uint32_t arch = flags & (EF_MIPS_ARCH | EF_MIPS_MACH);
- for (const auto &p : elfArchPairs)
- if (p._elfFlag == arch)
- return p._arch;
- return make_dynamic_error_code(
- StringRef("Unknown EF_MIPS_ARCH | EF_MIPS_MACH flags (0x") +
- Twine::utohexstr(arch) + ")");
-}
-
-static uint32_t isaToHeaderFlags(unsigned isa) {
- for (const auto &p : archElfPairs)
- if (p._arch == isa)
- return p._elfFlag;
- llvm_unreachable("Unknown MIPS ISA");
-}
-
-static ErrorOr<uint32_t> flagsToAses(uint32_t flags) {
- uint32_t ases = flags & EF_MIPS_ARCH_ASE;
- switch (ases) {
- case 0:
- return 0;
- case EF_MIPS_MICROMIPS:
- return AFL_ASE_MICROMIPS;
- case EF_MIPS_ARCH_ASE_M16:
- return AFL_ASE_MIPS16;
- case EF_MIPS_ARCH_ASE_MDMX:
- return AFL_ASE_MDMX;
- default:
- return make_dynamic_error_code(
- StringRef("Unknown EF_MIPS_ARCH_ASE flag (0x") +
- Twine::utohexstr(ases) + ")");
- }
-}
-
-static uint32_t asesToFlags(uint32_t ases) {
- switch (ases) {
- case AFL_ASE_MICROMIPS:
- return EF_MIPS_MICROMIPS;
- case AFL_ASE_MIPS16:
- return EF_MIPS_ARCH_ASE_M16;
- case AFL_ASE_MDMX:
- return EF_MIPS_ARCH_ASE_MDMX;
- default:
- return 0;
- }
-}
-
-static ErrorOr<MipsISAs> sectionFlagsToIsa(uint8_t isaLevel, uint8_t isaRev,
- uint8_t isaExt) {
- for (const auto &p : abiIsaArchPair)
- if (p._isaLevel == isaLevel && p._isaRev == isaRev && p._isaExt == isaExt)
- return p._arch;
- return make_dynamic_error_code(
- StringRef("Unknown ISA level/revision/extension ") + Twine(isaLevel) +
- "/" + Twine(isaRev) + "/" + Twine(isaExt));
-}
-
-static std::tuple<uint8_t, uint8_t, uint32_t> isaToSectionFlags(unsigned isa) {
- for (const auto &p : abiIsaArchPair)
- if (p._arch == isa)
- return std::make_tuple(p._isaLevel, p._isaRev, p._isaExt);
- llvm_unreachable("Unknown MIPS ISA");
-}
-
-static bool checkCompatibility(const MipsAbiFlags &hdr,
- const MipsAbiFlags &sec) {
- uint32_t secIsa = ArchNone;
- switch (sec._isa) {
- case Arch32r3:
- case Arch32r5:
- secIsa = Arch32r2;
- break;
- case Arch64r3:
- case Arch64r5:
- secIsa = Arch64r2;
- break;
- default:
- secIsa = sec._isa;
- break;
- }
- if (secIsa != hdr._isa) {
- llvm::errs() << "inconsistent ISA between .MIPS.abiflags "
- "and ELF header e_flags field\n";
- return false;
- }
- if ((sec._ases & hdr._ases) != hdr._ases) {
- llvm::errs() << "inconsistent ASEs between .MIPS.abiflags "
- "and ELF header e_flags field\n";
- return false;
- }
- return true;
-}
-
-static int compareFpAbi(uint32_t fpA, uint32_t fpB) {
- if (fpA == fpB)
- return 0;
- if (fpB == Val_GNU_MIPS_ABI_FP_ANY)
- return 1;
- if (fpB == Val_GNU_MIPS_ABI_FP_64A && fpA == Val_GNU_MIPS_ABI_FP_64)
- return 1;
- if (fpB != Val_GNU_MIPS_ABI_FP_XX)
- return -1;
- if (fpA == Val_GNU_MIPS_ABI_FP_DOUBLE || fpA == Val_GNU_MIPS_ABI_FP_64 ||
- fpA == Val_GNU_MIPS_ABI_FP_64A)
- return 1;
- return -1;
-}
-
-static StringRef getFpAbiName(uint32_t fpAbi) {
- switch (fpAbi) {
- case Val_GNU_MIPS_ABI_FP_ANY:
- return "<any>";
- case Val_GNU_MIPS_ABI_FP_DOUBLE:
- return "-mdouble-float";
- case Val_GNU_MIPS_ABI_FP_SINGLE:
- return "-msingle-float";
- case Val_GNU_MIPS_ABI_FP_SOFT:
- return "-msoft-float";
- case Val_GNU_MIPS_ABI_FP_OLD_64:
- return "-mips32r2 -mfp64 (old)";
- case Val_GNU_MIPS_ABI_FP_XX:
- return "-mfpxx";
- case Val_GNU_MIPS_ABI_FP_64:
- return "-mgp32 -mfp64";
- case Val_GNU_MIPS_ABI_FP_64A:
- return "-mgp32 -mfp64 -mno-odd-spreg";
- default:
- return "<unknown>";
- }
-}
-
-static uint32_t selectFpAbiFlag(uint32_t oldFp, uint32_t newFp) {
- if (compareFpAbi(newFp, oldFp) >= 0)
- return newFp;
- if (compareFpAbi(oldFp, newFp) < 0)
- llvm::errs() << "FP ABI " << getFpAbiName(oldFp) << " is incompatible with "
- << getFpAbiName(newFp) << "\n";
- return oldFp;
-}
-
-namespace lld {
-namespace elf {
-
-template <class ELFT> bool MipsAbiInfoHandler<ELFT>::isMicroMips() const {
- assert(_abiFlags.hasValue());
- return _abiFlags->_ases & AFL_ASE_MICROMIPS;
-}
-
-template <class ELFT> bool MipsAbiInfoHandler<ELFT>::isMipsR6() const {
- assert(_abiFlags.hasValue());
- return _abiFlags->_isa == Arch32r6 || _abiFlags->_isa == Arch64r6;
-}
-
-template <class ELFT> bool MipsAbiInfoHandler<ELFT>::isFp64() const {
- assert(_abiFlags.hasValue());
- return _abiFlags->_fpAbi == Val_GNU_MIPS_ABI_FP_64 ||
- _abiFlags->_fpAbi == Val_GNU_MIPS_ABI_FP_64A;
-}
-
-template <class ELFT> bool MipsAbiInfoHandler<ELFT>::isCPicOnly() const {
- assert(_abiFlags.hasValue());
- return _abiFlags->_isCPic && !_abiFlags->_isPic;
-}
-
-template <class ELFT> uint32_t MipsAbiInfoHandler<ELFT>::getFlags() const {
- std::lock_guard<std::mutex> lock(_mutex);
- uint32_t flags = 0;
- if (_abiFlags.hasValue()) {
- flags |= isaToHeaderFlags(_abiFlags->_isa);
- flags |= asesToFlags(_abiFlags->_ases);
- flags |= _abiFlags->_abi;
- flags |= _abiFlags->_isPic ? EF_MIPS_PIC : 0u;
- flags |= _abiFlags->_isCPic ? EF_MIPS_CPIC : 0u;
- flags |= _abiFlags->_isNoReorder ? EF_MIPS_NOREORDER : 0u;
- flags |= _abiFlags->_is32BitMode ? EF_MIPS_32BITMODE : 0u;
- flags |= _abiFlags->_isNan2008 ? EF_MIPS_NAN2008 : 0u;
- }
- return flags;
-}
-
-template <class ELFT>
-llvm::Optional<typename MipsAbiInfoHandler<ELFT>::Elf_Mips_RegInfo>
-MipsAbiInfoHandler<ELFT>::getRegistersMask() const {
- std::lock_guard<std::mutex> lock(_mutex);
- return _regMask;
-}
-
-template <class ELFT>
-llvm::Optional<typename MipsAbiInfoHandler<ELFT>::Elf_Mips_ABIFlags>
-MipsAbiInfoHandler<ELFT>::getAbiFlags() const {
- std::lock_guard<std::mutex> lock(_mutex);
- if (!_hasAbiSection)
- return llvm::Optional<Elf_Mips_ABIFlags>();
-
- Elf_Mips_ABIFlags sec;
- sec.version = 0;
- std::tie(sec.isa_level, sec.isa_rev, sec.isa_ext) =
- isaToSectionFlags(_abiFlags->_isa);
- sec.gpr_size = _abiFlags->_gprSize;
- sec.cpr1_size = _abiFlags->_cpr1Size;
- sec.cpr2_size = _abiFlags->_cpr2Size;
- sec.fp_abi = _abiFlags->_fpAbi;
- sec.ases = _abiFlags->_ases;
- sec.flags1 = _abiFlags->_flags1;
- sec.flags2 = 0;
- return sec;
-}
-
-template <class ELFT> MipsAbi MipsAbiInfoHandler<ELFT>::getAbi() const {
- if (!_abiFlags.hasValue())
- return ELFT::Is64Bits ? MipsAbi::N64 : MipsAbi::O32;
- switch (_abiFlags->_abi & (EF_MIPS_ABI_O32 | EF_MIPS_ABI2)) {
- case EF_MIPS_ABI_O32:
- return MipsAbi::O32;
- case EF_MIPS_ABI2:
- return MipsAbi::N32;
- case 0:
- return MipsAbi::N64;
- default:
- llvm_unreachable("Unknown ABI flag");
- }
-}
-
-template <class ELFT>
-std::error_code
-MipsAbiInfoHandler<ELFT>::mergeFlags(uint32_t newFlags,
- const Elf_Mips_ABIFlags *newSec) {
- std::lock_guard<std::mutex> lock(_mutex);
-
- ErrorOr<MipsAbiFlags> abiFlags = createAbiFlags(newFlags, newSec);
- if (auto ec = abiFlags.getError())
- return ec;
-
- // We support three ABI: O32, N32, and N64. The last one does not have
- // the corresponding ELF flag.
- if (ELFT::Is64Bits) {
- if (abiFlags->_abi)
- return make_dynamic_error_code("Unsupported ABI");
- } else {
- if (!(abiFlags->_abi & (EF_MIPS_ABI_O32 | EF_MIPS_ABI2)))
- return make_dynamic_error_code("Unsupported ABI");
- }
-
- // ... and still do not support MIPS-16 extension.
- if (abiFlags->_ases & AFL_ASE_MIPS16)
- return make_dynamic_error_code("Unsupported extension: MIPS16");
-
- // PIC code is inherently CPIC and may not set CPIC flag explicitly.
- // Ensure that this flag will exist in the linked file.
- if (abiFlags->_isPic)
- abiFlags->_isCPic = true;
-
- // If the old set of flags is empty, use the new one as a result.
- if (!_abiFlags.hasValue()) {
- _abiFlags = *abiFlags;
- return std::error_code();
- }
-
- // Check ABI compatibility.
- if (abiFlags->_abi != _abiFlags->_abi)
- return make_dynamic_error_code("Linking modules with incompatible ABI");
-
- // Check PIC / CPIC flags compatibility.
- if (abiFlags->_isCPic != _abiFlags->_isCPic)
- llvm::errs() << "lld warning: linking abicalls and non-abicalls files\n";
-
- if (!abiFlags->_isPic)
- _abiFlags->_isPic = false;
- if (abiFlags->_isCPic)
- _abiFlags->_isCPic = true;
-
- // Check mixing -mnan=2008 / -mnan=legacy modules.
- if (abiFlags->_isNan2008 != _abiFlags->_isNan2008)
- return make_dynamic_error_code(
- "Linking -mnan=2008 and -mnan=legacy modules");
-
- // Check ISA compatibility and update the extension flag.
- if (!matchMipsISA(MipsISAs(abiFlags->_isa), MipsISAs(_abiFlags->_isa))) {
- if (!matchMipsISA(MipsISAs(_abiFlags->_isa), MipsISAs(abiFlags->_isa)))
- return make_dynamic_error_code("Linking modules with incompatible ISA");
- _abiFlags->_isa = abiFlags->_isa;
- }
-
- _abiFlags->_ases |= abiFlags->_ases;
- _abiFlags->_isNoReorder = _abiFlags->_isNoReorder || abiFlags->_isNoReorder;
- _abiFlags->_is32BitMode = _abiFlags->_is32BitMode || abiFlags->_is32BitMode;
-
- _abiFlags->_fpAbi = selectFpAbiFlag(_abiFlags->_fpAbi, abiFlags->_fpAbi);
- _abiFlags->_gprSize = std::max(_abiFlags->_gprSize, abiFlags->_gprSize);
- _abiFlags->_cpr1Size = std::max(_abiFlags->_cpr1Size, abiFlags->_cpr1Size);
- _abiFlags->_cpr2Size = std::max(_abiFlags->_cpr2Size, abiFlags->_cpr2Size);
- _abiFlags->_flags1 |= abiFlags->_flags1;
-
- return std::error_code();
-}
-
-template <class ELFT>
-void MipsAbiInfoHandler<ELFT>::mergeRegistersMask(
- const Elf_Mips_RegInfo &info) {
- std::lock_guard<std::mutex> lock(_mutex);
- if (!_regMask.hasValue()) {
- _regMask = info;
- return;
- }
- _regMask->ri_gprmask = _regMask->ri_gprmask | info.ri_gprmask;
- _regMask->ri_cprmask[0] = _regMask->ri_cprmask[0] | info.ri_cprmask[0];
- _regMask->ri_cprmask[1] = _regMask->ri_cprmask[1] | info.ri_cprmask[1];
- _regMask->ri_cprmask[2] = _regMask->ri_cprmask[2] | info.ri_cprmask[2];
- _regMask->ri_cprmask[3] = _regMask->ri_cprmask[3] | info.ri_cprmask[3];
-}
-
-template <class ELFT>
-ErrorOr<MipsAbiFlags>
-MipsAbiInfoHandler<ELFT>::createAbiFlags(uint32_t flags,
- const Elf_Mips_ABIFlags *sec) {
- ErrorOr<MipsAbiFlags> hdrFlags = createAbiFromHeaderFlags(flags);
- if (auto ec = hdrFlags.getError())
- return ec;
- if (!sec)
- return *hdrFlags;
- ErrorOr<MipsAbiFlags> secFlags = createAbiFromSection(*sec);
- if (auto ec = secFlags.getError())
- return ec;
- if (!checkCompatibility(*hdrFlags, *secFlags))
- return *hdrFlags;
-
- _hasAbiSection = true;
-
- secFlags->_abi = hdrFlags->_abi;
- secFlags->_isPic = hdrFlags->_isPic;
- secFlags->_isCPic = hdrFlags->_isCPic;
- secFlags->_isNoReorder = hdrFlags->_isNoReorder;
- secFlags->_is32BitMode = hdrFlags->_is32BitMode;
- secFlags->_isNan2008 = hdrFlags->_isNan2008;
- return *secFlags;
-}
-
-template <class ELFT>
-ErrorOr<MipsAbiFlags>
-MipsAbiInfoHandler<ELFT>::createAbiFromHeaderFlags(uint32_t flags) {
- MipsAbiFlags abi;
- ErrorOr<MipsISAs> isa = headerFlagsToIsa(flags);
- if (auto ec = isa.getError())
- return ec;
- abi._isa = *isa;
-
- abi._fpAbi = Val_GNU_MIPS_ABI_FP_ANY;
- abi._cpr1Size = AFL_REG_NONE;
- abi._cpr2Size = AFL_REG_NONE;
- abi._gprSize = is32BitElfFlags(flags) ? AFL_REG_32 : AFL_REG_64;
-
- ErrorOr<uint32_t> ases = flagsToAses(flags);
- if (auto ec = ases.getError())
- return ec;
- abi._ases = *ases;
- abi._flags1 = 0;
- abi._abi = flags & (EF_MIPS_ABI | EF_MIPS_ABI2);
- abi._isPic = flags & EF_MIPS_PIC;
- abi._isCPic = flags & EF_MIPS_CPIC;
- abi._isNoReorder = flags & EF_MIPS_NOREORDER;
- abi._is32BitMode = flags & EF_MIPS_32BITMODE;
- abi._isNan2008 = flags & EF_MIPS_NAN2008;
- return abi;
-}
-
-template <class ELFT>
-ErrorOr<MipsAbiFlags>
-MipsAbiInfoHandler<ELFT>::createAbiFromSection(const Elf_Mips_ABIFlags &sec) {
- MipsAbiFlags abi;
- ErrorOr<MipsISAs> isa =
- sectionFlagsToIsa(sec.isa_level, sec.isa_rev, sec.isa_ext);
- if (auto ec = isa.getError())
- return ec;
- abi._isa = *isa;
- abi._fpAbi = sec.fp_abi;
- abi._cpr1Size = sec.cpr1_size;
- abi._cpr2Size = sec.cpr2_size;
- abi._gprSize = sec.gpr_size;
- abi._ases = sec.ases;
- abi._flags1 = sec.flags1;
- if (sec.flags2 != 0)
- return make_dynamic_error_code("unexpected non-zero 'flags2' value");
- return abi;
-}
-
-template class MipsAbiInfoHandler<ELF32BE>;
-template class MipsAbiInfoHandler<ELF32LE>;
-template class MipsAbiInfoHandler<ELF64BE>;
-template class MipsAbiInfoHandler<ELF64LE>;
-
-}
-}
diff --git a/lib/ReaderWriter/ELF/Mips/MipsAbiInfoHandler.h b/lib/ReaderWriter/ELF/Mips/MipsAbiInfoHandler.h
deleted file mode 100644
index 44da29f09214..000000000000
--- a/lib/ReaderWriter/ELF/Mips/MipsAbiInfoHandler.h
+++ /dev/null
@@ -1,83 +0,0 @@
-//===- lib/ReaderWriter/ELF/MipsAbiInfoHandler.h --------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_ABI_INFO_HANDLER_H
-#define LLD_READER_WRITER_ELF_MIPS_MIPS_ABI_INFO_HANDLER_H
-
-#include "llvm/ADT/Optional.h"
-#include "llvm/Object/ELFTypes.h"
-#include "llvm/Support/ErrorOr.h"
-#include <mutex>
-#include <system_error>
-
-namespace lld {
-namespace elf {
-
-enum class MipsAbi { O32, N32, N64 };
-
-struct MipsAbiFlags {
- unsigned _isa = 0;
- unsigned _fpAbi = 0;
- unsigned _ases = 0;
- unsigned _flags1 = 0;
- unsigned _gprSize = 0;
- unsigned _cpr1Size = 0;
- unsigned _cpr2Size = 0;
-
- unsigned _abi = 0;
-
- bool _isPic = false;
- bool _isCPic = false;
- bool _isNoReorder = false;
- bool _is32BitMode = false;
- bool _isNan2008 = false;
-};
-
-template <class ELFT> class MipsAbiInfoHandler {
-public:
- typedef llvm::object::Elf_Mips_RegInfo<ELFT> Elf_Mips_RegInfo;
- typedef llvm::object::Elf_Mips_ABIFlags<ELFT> Elf_Mips_ABIFlags;
-
- MipsAbiInfoHandler() = default;
-
- bool hasMipsAbiSection() const { return _hasAbiSection; }
- bool isMicroMips() const;
- bool isMipsR6() const;
- bool isFp64() const;
- bool isCPicOnly() const;
-
- uint32_t getFlags() const;
- llvm::Optional<Elf_Mips_RegInfo> getRegistersMask() const;
- llvm::Optional<Elf_Mips_ABIFlags> getAbiFlags() const;
-
- MipsAbi getAbi() const;
-
- /// \brief Merge saved ELF header flags and the new set of flags.
- std::error_code mergeFlags(uint32_t newFlags,
- const Elf_Mips_ABIFlags *newAbi);
-
- /// \brief Merge saved and new sets of registers usage masks.
- void mergeRegistersMask(const Elf_Mips_RegInfo &info);
-
-private:
- mutable std::mutex _mutex;
- bool _hasAbiSection = false;
- llvm::Optional<MipsAbiFlags> _abiFlags;
- llvm::Optional<Elf_Mips_RegInfo> _regMask;
-
- llvm::ErrorOr<MipsAbiFlags> createAbiFlags(uint32_t flags,
- const Elf_Mips_ABIFlags *sec);
- static llvm::ErrorOr<MipsAbiFlags> createAbiFromHeaderFlags(uint32_t flags);
- static llvm::ErrorOr<MipsAbiFlags>
- createAbiFromSection(const Elf_Mips_ABIFlags &sec);
-};
-
-} // namespace elf
-} // namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.cpp b/lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.cpp
deleted file mode 100644
index a7062813df42..000000000000
--- a/lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-//===- lib/ReaderWriter/ELF/Mips/Mips/CtorsOrderPass.cpp ------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "MipsCtorsOrderPass.h"
-#include "lld/Core/Simple.h"
-#include <algorithm>
-#include <climits>
-
-using namespace lld;
-using namespace lld::elf;
-
-static bool matchCrtObjName(StringRef objName, StringRef objPath) {
- if (!objPath.endswith(".o"))
- return false;
-
- // check *<objName> case
- objPath = objPath.drop_back(2);
- if (objPath.endswith(objName))
- return true;
-
- // check *<objName>? case
- return !objPath.empty() && objPath.drop_back(1).endswith(objName);
-}
-
-static int32_t getSectionPriority(StringRef path, StringRef sectionName) {
- // Arrange .ctors/.dtors sections in the following order:
- // .ctors from crtbegin.o or crtbegin?.o
- // .ctors from regular object files
- // .ctors.* (sorted) from regular object files
- // .ctors from crtend.o or crtend?.o
-
- if (matchCrtObjName("crtbegin", path))
- return std::numeric_limits<int32_t>::min();
- if (matchCrtObjName("crtend", path))
- return std::numeric_limits<int32_t>::max();
-
- StringRef num = sectionName.drop_front().rsplit('.').second;
-
- int32_t priority = std::numeric_limits<int32_t>::min() + 1;
- if (!num.empty())
- num.getAsInteger(10, priority);
-
- return priority;
-}
-
-std::error_code MipsCtorsOrderPass::perform(SimpleFile &f) {
- auto definedAtoms = f.definedAtoms();
-
- auto last = std::stable_partition(definedAtoms.begin(), definedAtoms.end(),
- [](const DefinedAtom *atom) {
- if (atom->sectionChoice() != DefinedAtom::sectionCustomRequired)
- return false;
-
- StringRef name = atom->customSectionName();
- return name.startswith(".ctors") || name.startswith(".dtors");
- });
-
- std::stable_sort(definedAtoms.begin(), last,
- [](const DefinedAtom *left, const DefinedAtom *right) {
- StringRef leftSec = left->customSectionName();
- StringRef rightSec = right->customSectionName();
-
- int32_t leftPriority = getSectionPriority(left->file().path(), leftSec);
- int32_t rightPriority = getSectionPriority(right->file().path(), rightSec);
-
- return leftPriority < rightPriority;
- });
-
- return std::error_code();
-}
diff --git a/lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.h b/lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.h
deleted file mode 100644
index 5b12b7de0fa2..000000000000
--- a/lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.h
+++ /dev/null
@@ -1,25 +0,0 @@
-//===- lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.h ---------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_CTORS_ORDER_PASS_H
-#define LLD_READER_WRITER_ELF_MIPS_MIPS_CTORS_ORDER_PASS_H
-
-#include "lld/Core/Pass.h"
-
-namespace lld {
-namespace elf {
-/// \brief This pass sorts atoms in .{ctors,dtors}.<priority> sections.
-class MipsCtorsOrderPass : public Pass {
-public:
- std::error_code perform(SimpleFile &mergedFile) override;
-};
-}
-}
-
-#endif
diff --git a/lib/ReaderWriter/ELF/Mips/MipsDynamicTable.h b/lib/ReaderWriter/ELF/Mips/MipsDynamicTable.h
deleted file mode 100644
index 480c69cf4600..000000000000
--- a/lib/ReaderWriter/ELF/Mips/MipsDynamicTable.h
+++ /dev/null
@@ -1,124 +0,0 @@
-//===- lib/ReaderWriter/ELF/Mips/MipsDynamicTable.h -----------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_DYNAMIC_TABLE_H
-#define LLD_READER_WRITER_ELF_MIPS_MIPS_DYNAMIC_TABLE_H
-
-#include "TargetLayout.h"
-#include "SectionChunks.h"
-
-namespace lld {
-namespace elf {
-
-template <class ELFT> class MipsTargetLayout;
-
-template <class ELFT> class MipsDynamicTable : public DynamicTable<ELFT> {
-public:
- MipsDynamicTable(const ELFLinkingContext &ctx, MipsTargetLayout<ELFT> &layout)
- : DynamicTable<ELFT>(ctx, layout, ".dynamic",
- TargetLayout<ELFT>::ORDER_DYNAMIC),
- _targetLayout(layout) {}
-
- void createDefaultEntries() override {
- DynamicTable<ELFT>::createDefaultEntries();
-
- // Version id for the Runtime Linker Interface.
- this->addEntry(DT_MIPS_RLD_VERSION, 1);
-
- // The .rld_map section address.
- if (this->_ctx.getOutputELFType() == ET_EXEC) {
- _dt_rldmap = this->addEntry(DT_MIPS_RLD_MAP, 0);
- _dt_rldmaprel = this->addEntry(DT_MIPS_RLD_MAP_REL, 0);
- }
-
- // MIPS flags.
- this->addEntry(DT_MIPS_FLAGS, RHF_NOTPOT);
-
- // The base address of the segment.
- _dt_baseaddr = this->addEntry(DT_MIPS_BASE_ADDRESS, 0);
-
- // Number of local global offset table entries.
- _dt_localgot = this->addEntry(DT_MIPS_LOCAL_GOTNO, 0);
-
- // Number of entries in the .dynsym section.
- _dt_symtabno = this->addEntry(DT_MIPS_SYMTABNO, 0);
-
- // The index of the first dynamic symbol table entry that corresponds
- // to an entry in the global offset table.
- _dt_gotsym = this->addEntry(DT_MIPS_GOTSYM, 0);
-
- // Address of the .got section.
- _dt_pltgot = this->addEntry(DT_PLTGOT, 0);
- }
-
- void doPreFlight() override {
- DynamicTable<ELFT>::doPreFlight();
-
- if (_targetLayout.findOutputSection(".MIPS.options")) {
- _dt_options = this->addEntry(DT_MIPS_OPTIONS, 0);
- }
- }
-
- void updateDynamicTable() override {
- DynamicTable<ELFT>::updateDynamicTable();
-
- // Assign the minimum segment address to the DT_MIPS_BASE_ADDRESS tag.
- auto baseAddr = std::numeric_limits<uint64_t>::max();
- for (auto si : _targetLayout.segments())
- if (si->segmentType() != llvm::ELF::PT_NULL)
- baseAddr = std::min(baseAddr, si->virtualAddr());
- this->_entries[_dt_baseaddr].d_un.d_val = baseAddr;
-
- auto &got = _targetLayout.getGOTSection();
-
- this->_entries[_dt_symtabno].d_un.d_val = this->getSymbolTable()->size();
- this->_entries[_dt_gotsym].d_un.d_val =
- this->getSymbolTable()->size() - got.getGlobalCount();
- this->_entries[_dt_localgot].d_un.d_val = got.getLocalCount();
- this->_entries[_dt_pltgot].d_un.d_ptr = got.virtualAddr();
-
- if (const auto *sec = _targetLayout.findOutputSection(".MIPS.options"))
- this->_entries[_dt_options].d_un.d_ptr = sec->virtualAddr();
-
- if (const auto *sec = _targetLayout.findOutputSection(".rld_map")) {
- this->_entries[_dt_rldmap].d_un.d_ptr = sec->virtualAddr();
- this->_entries[_dt_rldmaprel].d_un.d_ptr =
- sec->virtualAddr() -
- (this->virtualAddr() +
- _dt_rldmaprel * sizeof(typename DynamicTable<ELFT>::Elf_Dyn));
- }
- }
-
- int64_t getGotPltTag() override { return DT_MIPS_PLTGOT; }
-
-protected:
- /// \brief Adjust the symbol's value for microMIPS code.
- uint64_t getAtomVirtualAddress(const AtomLayout *al) const override {
- if (const auto *da = dyn_cast<DefinedAtom>(al->_atom))
- if (da->codeModel() == DefinedAtom::codeMipsMicro ||
- da->codeModel() == DefinedAtom::codeMipsMicroPIC)
- return al->_virtualAddr | 1;
- return al->_virtualAddr;
- }
-
-private:
- std::size_t _dt_symtabno;
- std::size_t _dt_localgot;
- std::size_t _dt_gotsym;
- std::size_t _dt_pltgot;
- std::size_t _dt_baseaddr;
- std::size_t _dt_options;
- std::size_t _dt_rldmap;
- std::size_t _dt_rldmaprel;
- MipsTargetLayout<ELFT> &_targetLayout;
-};
-
-} // end namespace elf
-} // end namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/ELF/Mips/MipsELFFile.cpp b/lib/ReaderWriter/ELF/Mips/MipsELFFile.cpp
deleted file mode 100644
index b081b63d77f7..000000000000
--- a/lib/ReaderWriter/ELF/Mips/MipsELFFile.cpp
+++ /dev/null
@@ -1,348 +0,0 @@
-//===- lib/ReaderWriter/ELF/MipsELFFile.cpp -------------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "MipsELFFile.h"
-#include "MipsTargetHandler.h"
-#include "llvm/ADT/StringExtras.h"
-
-namespace lld {
-namespace elf {
-
-template <class ELFT>
-MipsELFDefinedAtom<ELFT>::MipsELFDefinedAtom(
- const MipsELFFile<ELFT> &file, StringRef symbolName, StringRef sectionName,
- const Elf_Sym *symbol, const Elf_Shdr *section,
- ArrayRef<uint8_t> contentData, unsigned int referenceStart,
- unsigned int referenceEnd, std::vector<ELFReference<ELFT> *> &referenceList)
- : ELFDefinedAtom<ELFT>(file, symbolName, sectionName, symbol, section,
- contentData, referenceStart, referenceEnd,
- referenceList) {}
-
-template <class ELFT>
-const MipsELFFile<ELFT> &MipsELFDefinedAtom<ELFT>::file() const {
- return static_cast<const MipsELFFile<ELFT> &>(this->_owningFile);
-}
-
-template <class ELFT>
-DefinedAtom::CodeModel MipsELFDefinedAtom<ELFT>::codeModel() const {
- switch (this->_symbol->st_other & llvm::ELF::STO_MIPS_MIPS16) {
- case llvm::ELF::STO_MIPS_MIPS16:
- return DefinedAtom::codeMips16;
- case llvm::ELF::STO_MIPS_PIC:
- return DefinedAtom::codeMipsPIC;
- case llvm::ELF::STO_MIPS_MICROMIPS:
- return DefinedAtom::codeMipsMicro;
- case llvm::ELF::STO_MIPS_MICROMIPS | llvm::ELF::STO_MIPS_PIC:
- return DefinedAtom::codeMipsMicroPIC;
- default:
- return DefinedAtom::codeNA;
- }
-}
-
-template <class ELFT> bool MipsELFDefinedAtom<ELFT>::isPIC() const {
- return file().isPIC() || codeModel() == DefinedAtom::codeMipsMicroPIC ||
- codeModel() == DefinedAtom::codeMipsPIC;
-}
-
-template class MipsELFDefinedAtom<ELF32BE>;
-template class MipsELFDefinedAtom<ELF32LE>;
-template class MipsELFDefinedAtom<ELF64BE>;
-template class MipsELFDefinedAtom<ELF64LE>;
-
-template <class ELFT> static bool isMips64EL() {
- return ELFT::Is64Bits && ELFT::TargetEndianness == llvm::support::little;
-}
-
-template <class ELFT, bool isRela>
-static uint32_t
-extractTag(const llvm::object::Elf_Rel_Impl<ELFT, isRela> &rel) {
- return (rel.getType(isMips64EL<ELFT>()) & 0xffffff00) >> 8;
-}
-
-template <class ELFT>
-MipsELFReference<ELFT>::MipsELFReference(uint64_t symValue, const Elf_Rela &rel)
- : ELFReference<ELFT>(&rel, rel.r_offset - symValue,
- Reference::KindArch::Mips,
- rel.getType(isMips64EL<ELFT>()) & 0xff,
- rel.getSymbol(isMips64EL<ELFT>())),
- _tag(extractTag(rel)) {}
-
-template <class ELFT>
-MipsELFReference<ELFT>::MipsELFReference(uint64_t symValue, const Elf_Rel &rel)
- : ELFReference<ELFT>(rel.r_offset - symValue, Reference::KindArch::Mips,
- rel.getType(isMips64EL<ELFT>()) & 0xff,
- rel.getSymbol(isMips64EL<ELFT>())),
- _tag(extractTag(rel)) {}
-
-template class MipsELFReference<ELF32BE>;
-template class MipsELFReference<ELF32LE>;
-template class MipsELFReference<ELF64BE>;
-template class MipsELFReference<ELF64LE>;
-
-template <class ELFT>
-MipsELFFile<ELFT>::MipsELFFile(std::unique_ptr<MemoryBuffer> mb,
- ELFLinkingContext &ctx)
- : ELFFile<ELFT>(std::move(mb), ctx) {}
-
-template <class ELFT> bool MipsELFFile<ELFT>::isPIC() const {
- return this->_objFile->getHeader()->e_flags & llvm::ELF::EF_MIPS_PIC;
-}
-
-template <class ELFT> std::error_code MipsELFFile<ELFT>::doParse() {
- if (std::error_code ec = ELFFile<ELFT>::doParse())
- return ec;
- // Retrieve some auxiliary data like GP value, TLS section address etc
- // from the object file.
- return readAuxData();
-}
-
-template <class ELFT>
-ELFDefinedAtom<ELFT> *MipsELFFile<ELFT>::createDefinedAtom(
- 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 (this->_readerStorage) MipsELFDefinedAtom<ELFT>(
- *this, symName, sectionName, sym, sectionHdr, contentData, referenceStart,
- referenceEnd, referenceList);
-}
-
-template <class ELFT>
-const typename MipsELFFile<ELFT>::Elf_Shdr *
-MipsELFFile<ELFT>::findSectionByType(uint64_t type) const {
- for (const Elf_Shdr &section : this->_objFile->sections())
- if (section.sh_type == type)
- return &section;
- return nullptr;
-}
-
-template <class ELFT>
-const typename MipsELFFile<ELFT>::Elf_Shdr *
-MipsELFFile<ELFT>::findSectionByFlags(uint64_t flags) const {
- for (const Elf_Shdr &section : this->_objFile->sections())
- if (section.sh_flags & flags)
- return &section;
- return nullptr;
-}
-
-template <class ELFT>
-ErrorOr<const typename MipsELFFile<ELFT>::Elf_Mips_RegInfo *>
-MipsELFFile<ELFT>::findRegInfoSec() const {
- using namespace llvm::ELF;
- if (const Elf_Shdr *sec = findSectionByType(SHT_MIPS_OPTIONS)) {
- auto contents = this->getSectionContents(sec);
- if (std::error_code ec = contents.getError())
- return ec;
-
- ArrayRef<uint8_t> raw = contents.get();
- while (!raw.empty()) {
- if (raw.size() < sizeof(Elf_Mips_Options))
- return make_dynamic_error_code(
- StringRef("Invalid size of MIPS_OPTIONS section"));
-
- const auto *opt = reinterpret_cast<const Elf_Mips_Options *>(raw.data());
- if (opt->kind == ODK_REGINFO)
- return &opt->getRegInfo();
- raw = raw.slice(opt->size);
- }
- } else if (const Elf_Shdr *sec = findSectionByType(SHT_MIPS_REGINFO)) {
- auto contents = this->getSectionContents(sec);
- if (std::error_code ec = contents.getError())
- return ec;
-
- ArrayRef<uint8_t> raw = contents.get();
- if (raw.size() != sizeof(Elf_Mips_RegInfo))
- return make_dynamic_error_code(
- StringRef("Invalid size of MIPS_REGINFO section"));
-
- return reinterpret_cast<const Elf_Mips_RegInfo *>(raw.data());
- }
- return nullptr;
-}
-
-template <class ELFT>
-ErrorOr<const typename MipsELFFile<ELFT>::Elf_Mips_ABIFlags *>
-MipsELFFile<ELFT>::findAbiFlagsSec() const {
- const Elf_Shdr *sec = findSectionByType(SHT_MIPS_ABIFLAGS);
- if (!sec)
- return nullptr;
-
- auto contents = this->getSectionContents(sec);
- if (std::error_code ec = contents.getError())
- return ec;
-
- ArrayRef<uint8_t> raw = contents.get();
- if (raw.size() != sizeof(Elf_Mips_ABIFlags))
- return make_dynamic_error_code(
- StringRef("Invalid size of MIPS_ABIFLAGS section"));
-
- const auto *abi = reinterpret_cast<const Elf_Mips_ABIFlags *>(raw.data());
- if (abi->version != 0)
- return make_dynamic_error_code(
- StringRef(".MIPS.abiflags section has unsupported version '") +
- llvm::utostr(abi->version) + "'");
-
- return abi;
-}
-
-template <class ELFT> std::error_code MipsELFFile<ELFT>::readAuxData() {
- using namespace llvm::ELF;
- if (const Elf_Shdr *sec = findSectionByFlags(SHF_TLS)) {
- _tpOff = sec->sh_addr + TP_OFFSET;
- _dtpOff = sec->sh_addr + DTP_OFFSET;
- }
-
- auto &handler =
- static_cast<MipsTargetHandler<ELFT> &>(this->_ctx.getTargetHandler());
- auto &abi = handler.getAbiInfoHandler();
-
- ErrorOr<const Elf_Mips_RegInfo *> regInfoSec = findRegInfoSec();
- if (auto ec = regInfoSec.getError())
- return ec;
- if (const Elf_Mips_RegInfo *regInfo = regInfoSec.get()) {
- abi.mergeRegistersMask(*regInfo);
- _gp0 = regInfo->ri_gp_value;
- }
-
- ErrorOr<const Elf_Mips_ABIFlags *> abiFlagsSec = findAbiFlagsSec();
- if (auto ec = abiFlagsSec.getError())
- return ec;
-
- const Elf_Ehdr *hdr = this->_objFile->getHeader();
- if (std::error_code ec = abi.mergeFlags(hdr->e_flags, abiFlagsSec.get()))
- return ec;
-
- return std::error_code();
-}
-
-template <class ELFT>
-void MipsELFFile<ELFT>::createRelocationReferences(
- const Elf_Sym *symbol, ArrayRef<uint8_t> content,
- range<const Elf_Rela *> rels) {
- const auto value = this->getSymbolValue(symbol);
- unsigned numInGroup = 0;
- for (const auto &rel : rels) {
- if (rel.r_offset < value || value + content.size() <= rel.r_offset) {
- numInGroup = 0;
- continue;
- }
- if (numInGroup > 0) {
- auto &last =
- *static_cast<MipsELFReference<ELFT> *>(this->_references.back());
- if (last.offsetInAtom() + value == rel.r_offset) {
- last.setTag(last.tag() |
- (rel.getType(isMips64EL<ELFT>()) << 8 * (numInGroup - 1)));
- ++numInGroup;
- continue;
- }
- }
- auto r = new (this->_readerStorage) MipsELFReference<ELFT>(value, rel);
- this->addReferenceToSymbol(r, symbol);
- this->_references.push_back(r);
- numInGroup = 1;
- }
-}
-
-template <class ELFT>
-void MipsELFFile<ELFT>::createRelocationReferences(const Elf_Sym *symbol,
- ArrayRef<uint8_t> symContent,
- ArrayRef<uint8_t> secContent,
- const Elf_Shdr *relSec) {
- const Elf_Shdr *symtab = *this->_objFile->getSection(relSec->sh_link);
- auto rels = this->_objFile->rels(relSec);
- const auto value = this->getSymbolValue(symbol);
- for (const Elf_Rel *rit = rels.begin(), *eit = rels.end(); rit != eit;
- ++rit) {
- if (rit->r_offset < value || value + symContent.size() <= rit->r_offset)
- continue;
-
- auto r = new (this->_readerStorage) MipsELFReference<ELFT>(value, *rit);
- this->addReferenceToSymbol(r, symbol);
- this->_references.push_back(r);
-
- auto addend = readAddend(*rit, secContent);
- auto pairRelType = getPairRelocation(symtab, *rit);
- if (pairRelType != llvm::ELF::R_MIPS_NONE) {
- addend <<= 16;
- auto mit = findMatchingRelocation(pairRelType, rit, eit);
- if (mit != eit)
- addend += int16_t(readAddend(*mit, secContent));
- else
- // FIXME (simon): Show detailed warning.
- llvm::errs() << "lld warning: cannot matching LO16 relocation\n";
- }
- this->_references.back()->setAddend(addend);
- }
-}
-
-template <class ELFT>
-static uint8_t
-getPrimaryType(const llvm::object::Elf_Rel_Impl<ELFT, false> &rel) {
- return rel.getType(isMips64EL<ELFT>()) & 0xff;
-}
-
-template <class ELFT>
-Reference::Addend
-MipsELFFile<ELFT>::readAddend(const Elf_Rel &ri,
- const ArrayRef<uint8_t> content) const {
- return readMipsRelocAddend<ELFT>(getPrimaryType(ri),
- content.data() + ri.r_offset);
-}
-
-template <class ELFT>
-uint32_t MipsELFFile<ELFT>::getPairRelocation(const Elf_Shdr *symtab,
- const Elf_Rel &rel) const {
- switch (getPrimaryType(rel)) {
- case llvm::ELF::R_MIPS_HI16:
- return llvm::ELF::R_MIPS_LO16;
- case llvm::ELF::R_MIPS_PCHI16:
- return llvm::ELF::R_MIPS_PCLO16;
- case llvm::ELF::R_MIPS_GOT16:
- if (isLocalBinding(symtab, rel))
- return llvm::ELF::R_MIPS_LO16;
- break;
- case llvm::ELF::R_MICROMIPS_HI16:
- return llvm::ELF::R_MICROMIPS_LO16;
- case llvm::ELF::R_MICROMIPS_GOT16:
- if (isLocalBinding(symtab, rel))
- return llvm::ELF::R_MICROMIPS_LO16;
- break;
- default:
- // Nothing to do.
- break;
- }
- return llvm::ELF::R_MIPS_NONE;
-}
-
-template <class ELFT>
-const typename MipsELFFile<ELFT>::Elf_Rel *
-MipsELFFile<ELFT>::findMatchingRelocation(uint32_t pairRelType,
- const Elf_Rel *rit,
- const Elf_Rel *eit) const {
- return std::find_if(rit, eit, [&](const Elf_Rel &rel) {
- return getPrimaryType(rel) == pairRelType &&
- rel.getSymbol(isMips64EL<ELFT>()) ==
- rit->getSymbol(isMips64EL<ELFT>());
- });
-}
-
-template <class ELFT>
-bool MipsELFFile<ELFT>::isLocalBinding(const Elf_Shdr *symtab,
- const Elf_Rel &rel) const {
- return this->_objFile->getSymbol(symtab, rel.getSymbol(isMips64EL<ELFT>()))
- ->getBinding() == llvm::ELF::STB_LOCAL;
-}
-
-template class MipsELFFile<ELF32BE>;
-template class MipsELFFile<ELF32LE>;
-template class MipsELFFile<ELF64BE>;
-template class MipsELFFile<ELF64LE>;
-
-} // elf
-} // lld
diff --git a/lib/ReaderWriter/ELF/Mips/MipsELFFile.h b/lib/ReaderWriter/ELF/Mips/MipsELFFile.h
deleted file mode 100644
index 934934b539cc..000000000000
--- a/lib/ReaderWriter/ELF/Mips/MipsELFFile.h
+++ /dev/null
@@ -1,126 +0,0 @@
-//===- lib/ReaderWriter/ELF/MipsELFFile.h ---------------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_ELF_FILE_H
-#define LLD_READER_WRITER_ELF_MIPS_MIPS_ELF_FILE_H
-
-#include "ELFReader.h"
-#include "MipsLinkingContext.h"
-#include "MipsRelocationHandler.h"
-#include "llvm/ADT/STLExtras.h"
-
-namespace lld {
-namespace elf {
-
-template <class ELFT> class MipsELFFile;
-
-template <class ELFT>
-class MipsELFDefinedAtom : public ELFDefinedAtom<ELFT> {
- typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
- typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr;
-
-public:
- MipsELFDefinedAtom(const MipsELFFile<ELFT> &file, StringRef symbolName,
- StringRef sectionName, const Elf_Sym *symbol,
- const Elf_Shdr *section, ArrayRef<uint8_t> contentData,
- unsigned int referenceStart, unsigned int referenceEnd,
- std::vector<ELFReference<ELFT> *> &referenceList);
-
- const MipsELFFile<ELFT>& file() const override;
- DefinedAtom::CodeModel codeModel() const override;
-
- bool isPIC() const;
-};
-
-template <class ELFT> class MipsELFReference : public ELFReference<ELFT> {
- typedef llvm::object::Elf_Rel_Impl<ELFT, false> Elf_Rel;
- typedef llvm::object::Elf_Rel_Impl<ELFT, true> Elf_Rela;
-
-public:
- MipsELFReference(uint64_t symValue, const Elf_Rela &rel);
- MipsELFReference(uint64_t symValue, const Elf_Rel &rel);
-
- uint32_t tag() const override { return _tag; }
- void setTag(uint32_t tag) { _tag = tag; }
-
-private:
- uint32_t _tag;
-};
-
-template <class ELFT> class MipsELFFile : public ELFFile<ELFT> {
-public:
- MipsELFFile(std::unique_ptr<MemoryBuffer> mb, ELFLinkingContext &ctx);
-
- bool isPIC() const;
-
- /// \brief gp register value stored in the .reginfo section.
- int64_t getGP0() const { return _gp0; }
-
- /// \brief .tdata section address plus fixed offset.
- uint64_t getTPOffset() const { return _tpOff; }
- uint64_t getDTPOffset() const { return _dtpOff; }
-
-protected:
- std::error_code doParse() override;
-
-private:
- typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
- typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela Elf_Rela;
-
- enum { TP_OFFSET = 0x7000, DTP_OFFSET = 0x8000 };
-
- int64_t _gp0 = 0;
- uint64_t _tpOff = 0;
- uint64_t _dtpOff = 0;
-
- ELFDefinedAtom<ELFT> *
- createDefinedAtom(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;
-
- void createRelocationReferences(const Elf_Sym *symbol,
- ArrayRef<uint8_t> content,
- range<const Elf_Rela *> rels) override;
- void createRelocationReferences(const Elf_Sym *symbol,
- ArrayRef<uint8_t> symContent,
- ArrayRef<uint8_t> secContent,
- const Elf_Shdr *RelSec) override;
-
- const Elf_Shdr *findSectionByType(uint64_t type) const;
- const Elf_Shdr *findSectionByFlags(uint64_t flags) const;
-
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Ehdr Elf_Ehdr;
- typedef llvm::object::Elf_Mips_RegInfo<ELFT> Elf_Mips_RegInfo;
- typedef llvm::object::Elf_Mips_Options<ELFT> Elf_Mips_Options;
- typedef llvm::object::Elf_Mips_ABIFlags<ELFT> Elf_Mips_ABIFlags;
-
- ErrorOr<const Elf_Mips_RegInfo *> findRegInfoSec() const;
- ErrorOr<const Elf_Mips_ABIFlags*> findAbiFlagsSec() const;
-
- std::error_code readAuxData();
-
- Reference::Addend readAddend(const Elf_Rel &ri,
- const ArrayRef<uint8_t> content) const;
-
- uint32_t getPairRelocation(const Elf_Shdr *Symtab, const Elf_Rel &rel) const;
-
- const Elf_Rel *findMatchingRelocation(uint32_t pairRelType,
- const Elf_Rel *rit,
- const Elf_Rel *eit) const;
-
- bool isLocalBinding(const Elf_Shdr *Symtab, const Elf_Rel &rel) const;
-};
-
-} // elf
-} // lld
-
-#endif
diff --git a/lib/ReaderWriter/ELF/Mips/MipsELFWriters.cpp b/lib/ReaderWriter/ELF/Mips/MipsELFWriters.cpp
deleted file mode 100644
index b97a4f5a9070..000000000000
--- a/lib/ReaderWriter/ELF/Mips/MipsELFWriters.cpp
+++ /dev/null
@@ -1,292 +0,0 @@
-//===- lib/ReaderWriter/ELF/Mips/MipsELFWriters.cpp -----------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "MipsDynamicTable.h"
-#include "MipsELFWriters.h"
-#include "MipsLinkingContext.h"
-#include "MipsTargetHandler.h"
-#include "MipsTargetLayout.h"
-
-namespace {
-class MipsDynamicAtom : public lld::elf::DynamicAtom {
-public:
- MipsDynamicAtom(const lld::File &f) : DynamicAtom(f) {}
-
- ContentPermissions permissions() const override { return permR__; }
-};
-}
-
-namespace lld {
-namespace elf {
-
-template <class ELFT>
-MipsELFWriter<ELFT>::MipsELFWriter(MipsLinkingContext &ctx,
- MipsTargetLayout<ELFT> &targetLayout,
- const MipsAbiInfoHandler<ELFT> &abiInfo)
- : _ctx(ctx), _targetLayout(targetLayout), _abiInfo(abiInfo) {}
-
-template <class ELFT>
-void MipsELFWriter<ELFT>::setELFHeader(ELFHeader<ELFT> &elfHeader) {
- elfHeader.e_version(1);
- elfHeader.e_ident(llvm::ELF::EI_VERSION, llvm::ELF::EV_CURRENT);
- elfHeader.e_ident(llvm::ELF::EI_OSABI, llvm::ELF::ELFOSABI_NONE);
-
- unsigned char abiVer = 0;
- if (_ctx.getOutputELFType() == ET_EXEC && _abiInfo.isCPicOnly())
- abiVer = 1;
- if (_abiInfo.isFp64())
- abiVer = 3;
-
- elfHeader.e_ident(llvm::ELF::EI_ABIVERSION, abiVer);
- elfHeader.e_flags(_abiInfo.getFlags());
-}
-
-template <class ELFT>
-void MipsELFWriter<ELFT>::finalizeMipsRuntimeAtomValues() {
- auto gotSection = _targetLayout.findOutputSection(".got");
- auto got = gotSection ? gotSection->virtualAddr() : 0;
- auto gp = gotSection ? got + _targetLayout.getGPOffset() : 0;
-
- setAtomValue("_gp", gp);
- setAtomValue("_gp_disp", gp);
- setAtomValue("__gnu_local_gp", gp);
-
- if (_ctx.isDynamic() && _ctx.getOutputELFType() == ET_EXEC)
- setAtomValue("_DYNAMIC_LINKING", 1);
-}
-
-template <class ELFT>
-std::unique_ptr<RuntimeFile<ELFT>> MipsELFWriter<ELFT>::createRuntimeFile() {
- auto file = llvm::make_unique<RuntimeFile<ELFT>>(_ctx, "Mips runtime file");
- file->addAbsoluteAtom("_gp");
- file->addAbsoluteAtom("_gp_disp");
- file->addAbsoluteAtom("__gnu_local_gp");
- if (_ctx.isDynamic()) {
- file->addAtom(*new (file->allocator()) MipsDynamicAtom(*file));
- if (_ctx.getOutputELFType() == ET_EXEC)
- file->addAbsoluteAtom("_DYNAMIC_LINKING");
- }
- return file;
-}
-
-template <class ELFT>
-unique_bump_ptr<Section<ELFT>>
-MipsELFWriter<ELFT>::createOptionsSection(llvm::BumpPtrAllocator &alloc) {
- typedef unique_bump_ptr<Section<ELFT>> Ptr;
- const auto &regMask = _abiInfo.getRegistersMask();
- if (!regMask.hasValue())
- return Ptr();
- return ELFT::Is64Bits
- ? Ptr(new (alloc)
- MipsOptionsSection<ELFT>(_ctx, _targetLayout, *regMask))
- : Ptr(new (alloc)
- MipsReginfoSection<ELFT>(_ctx, _targetLayout, *regMask));
-}
-
-template <class ELFT>
-unique_bump_ptr<Section<ELFT>>
-MipsELFWriter<ELFT>::createAbiFlagsSection(llvm::BumpPtrAllocator &alloc) {
- typedef unique_bump_ptr<Section<ELFT>> Ptr;
- const auto &abi = _abiInfo.getAbiFlags();
- if (!abi.hasValue())
- return Ptr();
- return Ptr(new (alloc) MipsAbiFlagsSection<ELFT>(_ctx, _targetLayout, *abi));
-}
-
-template <class ELFT>
-void MipsELFWriter<ELFT>::setAtomValue(StringRef name, uint64_t value) {
- AtomLayout *atom = _targetLayout.findAbsoluteAtom(name);
- assert(atom);
- atom->_virtualAddr = value;
-}
-
-template <class ELFT>
-MipsDynamicLibraryWriter<ELFT>::MipsDynamicLibraryWriter(
- MipsLinkingContext &ctx, MipsTargetLayout<ELFT> &layout,
- const MipsAbiInfoHandler<ELFT> &abiInfo)
- : DynamicLibraryWriter<ELFT>(ctx, layout),
- _writeHelper(ctx, layout, abiInfo), _targetLayout(layout) {}
-
-template <class ELFT>
-void MipsDynamicLibraryWriter<ELFT>::createImplicitFiles(
- std::vector<std::unique_ptr<File>> &result) {
- DynamicLibraryWriter<ELFT>::createImplicitFiles(result);
- result.push_back(_writeHelper.createRuntimeFile());
-}
-
-template <class ELFT>
-void MipsDynamicLibraryWriter<ELFT>::finalizeDefaultAtomValues() {
- DynamicLibraryWriter<ELFT>::finalizeDefaultAtomValues();
- _writeHelper.finalizeMipsRuntimeAtomValues();
-}
-
-template <class ELFT>
-void MipsDynamicLibraryWriter<ELFT>::createDefaultSections() {
- DynamicLibraryWriter<ELFT>::createDefaultSections();
- _reginfo = _writeHelper.createOptionsSection(this->_alloc);
- if (_reginfo)
- this->_layout.addSection(_reginfo.get());
- _abiFlags = _writeHelper.createAbiFlagsSection(this->_alloc);
- if (_abiFlags)
- this->_layout.addSection(_abiFlags.get());
-}
-
-template <class ELFT>
-std::error_code MipsDynamicLibraryWriter<ELFT>::setELFHeader() {
- DynamicLibraryWriter<ELFT>::setELFHeader();
- _writeHelper.setELFHeader(*this->_elfHeader);
- return std::error_code();
-}
-
-template <class ELFT>
-unique_bump_ptr<SymbolTable<ELFT>>
-MipsDynamicLibraryWriter<ELFT>::createSymbolTable() {
- return unique_bump_ptr<SymbolTable<ELFT>>(
- new (this->_alloc) MipsSymbolTable<ELFT>(this->_ctx));
-}
-
-template <class ELFT>
-unique_bump_ptr<DynamicTable<ELFT>>
-MipsDynamicLibraryWriter<ELFT>::createDynamicTable() {
- return unique_bump_ptr<DynamicTable<ELFT>>(
- new (this->_alloc) MipsDynamicTable<ELFT>(this->_ctx, _targetLayout));
-}
-
-template <class ELFT>
-unique_bump_ptr<DynamicSymbolTable<ELFT>>
-MipsDynamicLibraryWriter<ELFT>::createDynamicSymbolTable() {
- return unique_bump_ptr<DynamicSymbolTable<ELFT>>(new (
- this->_alloc) MipsDynamicSymbolTable<ELFT>(this->_ctx, _targetLayout));
-}
-
-template class MipsDynamicLibraryWriter<ELF32BE>;
-template class MipsDynamicLibraryWriter<ELF32LE>;
-template class MipsDynamicLibraryWriter<ELF64BE>;
-template class MipsDynamicLibraryWriter<ELF64LE>;
-
-template <class ELFT>
-MipsExecutableWriter<ELFT>::MipsExecutableWriter(
- MipsLinkingContext &ctx, MipsTargetLayout<ELFT> &layout,
- const MipsAbiInfoHandler<ELFT> &abiInfo)
- : ExecutableWriter<ELFT>(ctx, layout), _writeHelper(ctx, layout, abiInfo),
- _targetLayout(layout) {}
-
-template <class ELFT>
-std::error_code MipsExecutableWriter<ELFT>::setELFHeader() {
- std::error_code ec = ExecutableWriter<ELFT>::setELFHeader();
- if (ec)
- return ec;
-
- StringRef entryName = this->_ctx.entrySymbolName();
- if (const AtomLayout *al = this->_layout.findAtomLayoutByName(entryName)) {
- const auto *ea = cast<DefinedAtom>(al->_atom);
- if (ea->codeModel() == DefinedAtom::codeMipsMicro ||
- ea->codeModel() == DefinedAtom::codeMipsMicroPIC)
- // Adjust entry symbol value if this symbol is microMIPS encoded.
- this->_elfHeader->e_entry(al->_virtualAddr | 1);
- }
-
- _writeHelper.setELFHeader(*this->_elfHeader);
- return std::error_code();
-}
-
-template <class ELFT>
-void MipsExecutableWriter<ELFT>::buildDynamicSymbolTable(const File &file) {
- // MIPS ABI requires to add to dynsym even undefined symbols
- // if they have a corresponding entries in a global part of GOT.
- for (auto sec : this->_layout.sections())
- if (auto section = dyn_cast<AtomSection<ELFT>>(sec))
- for (const auto &atom : section->atoms()) {
- if (_targetLayout.getGOTSection().hasGlobalGOTEntry(atom->_atom)) {
- this->_dynamicSymbolTable->addSymbol(atom->_atom, section->ordinal(),
- atom->_virtualAddr, atom);
- continue;
- }
-
- const DefinedAtom *da = dyn_cast<const DefinedAtom>(atom->_atom);
- if (!da)
- continue;
-
- if (da->dynamicExport() != DefinedAtom::dynamicExportAlways &&
- !this->_ctx.isDynamicallyExportedSymbol(da->name()) &&
- !(this->_ctx.shouldExportDynamic() &&
- da->scope() == Atom::Scope::scopeGlobal))
- continue;
-
- this->_dynamicSymbolTable->addSymbol(atom->_atom, section->ordinal(),
- atom->_virtualAddr, atom);
- }
-
- for (const UndefinedAtom *a : file.undefined())
- // FIXME (simon): Consider to move this check to the
- // MipsELFUndefinedAtom class method. That allows to
- // handle more complex coditions in the future.
- if (_targetLayout.getGOTSection().hasGlobalGOTEntry(a))
- this->_dynamicSymbolTable->addSymbol(a, ELF::SHN_UNDEF);
-
- // Skip our immediate parent class method
- // ExecutableWriter<ELFT>::buildDynamicSymbolTable because we replaced it
- // with our own version. Call OutputELFWriter directly.
- OutputELFWriter<ELFT>::buildDynamicSymbolTable(file);
-}
-
-template <class ELFT>
-void MipsExecutableWriter<ELFT>::createImplicitFiles(
- std::vector<std::unique_ptr<File>> &result) {
- ExecutableWriter<ELFT>::createImplicitFiles(result);
- result.push_back(_writeHelper.createRuntimeFile());
-}
-
-template <class ELFT>
-void MipsExecutableWriter<ELFT>::finalizeDefaultAtomValues() {
- // Finalize the atom values that are part of the parent.
- ExecutableWriter<ELFT>::finalizeDefaultAtomValues();
- _writeHelper.finalizeMipsRuntimeAtomValues();
-}
-
-template <class ELFT> void MipsExecutableWriter<ELFT>::createDefaultSections() {
- ExecutableWriter<ELFT>::createDefaultSections();
- _reginfo = _writeHelper.createOptionsSection(this->_alloc);
- if (_reginfo)
- this->_layout.addSection(_reginfo.get());
- _abiFlags = _writeHelper.createAbiFlagsSection(this->_alloc);
- if (_abiFlags)
- this->_layout.addSection(_abiFlags.get());
-}
-
-template <class ELFT>
-unique_bump_ptr<SymbolTable<ELFT>>
-MipsExecutableWriter<ELFT>::createSymbolTable() {
- return unique_bump_ptr<SymbolTable<ELFT>>(
- new (this->_alloc) MipsSymbolTable<ELFT>(this->_ctx));
-}
-
-/// \brief create dynamic table
-template <class ELFT>
-unique_bump_ptr<DynamicTable<ELFT>>
-MipsExecutableWriter<ELFT>::createDynamicTable() {
- return unique_bump_ptr<DynamicTable<ELFT>>(
- new (this->_alloc) MipsDynamicTable<ELFT>(this->_ctx, _targetLayout));
-}
-
-/// \brief create dynamic symbol table
-template <class ELFT>
-unique_bump_ptr<DynamicSymbolTable<ELFT>>
-MipsExecutableWriter<ELFT>::createDynamicSymbolTable() {
- return unique_bump_ptr<DynamicSymbolTable<ELFT>>(new (
- this->_alloc) MipsDynamicSymbolTable<ELFT>(this->_ctx, _targetLayout));
-}
-
-template class MipsExecutableWriter<ELF32BE>;
-template class MipsExecutableWriter<ELF32LE>;
-template class MipsExecutableWriter<ELF64BE>;
-template class MipsExecutableWriter<ELF64LE>;
-
-} // elf
-} // lld
diff --git a/lib/ReaderWriter/ELF/Mips/MipsELFWriters.h b/lib/ReaderWriter/ELF/Mips/MipsELFWriters.h
deleted file mode 100644
index 31b84f947c95..000000000000
--- a/lib/ReaderWriter/ELF/Mips/MipsELFWriters.h
+++ /dev/null
@@ -1,102 +0,0 @@
-//===- lib/ReaderWriter/ELF/Mips/MipsELFWriters.h -------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_ELF_WRITERS_H
-#define LLD_READER_WRITER_ELF_MIPS_MIPS_ELF_WRITERS_H
-
-#include "DynamicLibraryWriter.h"
-#include "ExecutableWriter.h"
-#include "MipsAbiInfoHandler.h"
-#include "MipsLinkingContext.h"
-
-namespace lld {
-namespace elf {
-
-template <class ELFT> class MipsTargetLayout;
-
-template <typename ELFT> class MipsELFWriter {
-public:
- MipsELFWriter(MipsLinkingContext &ctx, MipsTargetLayout<ELFT> &targetLayout,
- const MipsAbiInfoHandler<ELFT> &abiInfo);
-
- void setELFHeader(ELFHeader<ELFT> &elfHeader);
-
- void finalizeMipsRuntimeAtomValues();
-
- std::unique_ptr<RuntimeFile<ELFT>> createRuntimeFile();
- unique_bump_ptr<Section<ELFT>>
- createOptionsSection(llvm::BumpPtrAllocator &alloc);
- unique_bump_ptr<Section<ELFT>>
- createAbiFlagsSection(llvm::BumpPtrAllocator &alloc);
-
-private:
- MipsLinkingContext &_ctx;
- MipsTargetLayout<ELFT> &_targetLayout;
- const MipsAbiInfoHandler<ELFT> &_abiInfo;
-
- void setAtomValue(StringRef name, uint64_t value);
-};
-
-template <class ELFT>
-class MipsDynamicLibraryWriter : public DynamicLibraryWriter<ELFT> {
-public:
- MipsDynamicLibraryWriter(MipsLinkingContext &ctx,
- MipsTargetLayout<ELFT> &layout,
- const MipsAbiInfoHandler<ELFT> &abiInfo);
-
-protected:
- // Add any runtime files and their atoms to the output
- void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
-
- void finalizeDefaultAtomValues() override;
- void createDefaultSections() override;
-
- std::error_code setELFHeader() override;
-
- unique_bump_ptr<SymbolTable<ELFT>> createSymbolTable() override;
- unique_bump_ptr<DynamicTable<ELFT>> createDynamicTable() override;
- unique_bump_ptr<DynamicSymbolTable<ELFT>> createDynamicSymbolTable() override;
-
-private:
- MipsELFWriter<ELFT> _writeHelper;
- MipsTargetLayout<ELFT> &_targetLayout;
- unique_bump_ptr<Section<ELFT>> _reginfo;
- unique_bump_ptr<Section<ELFT>> _abiFlags;
-};
-
-template <class ELFT>
-class MipsExecutableWriter : public ExecutableWriter<ELFT> {
-public:
- MipsExecutableWriter(MipsLinkingContext &ctx, MipsTargetLayout<ELFT> &layout,
- const MipsAbiInfoHandler<ELFT> &abiInfo);
-
-protected:
- void buildDynamicSymbolTable(const File &file) override;
-
- // Add any runtime files and their atoms to the output
- void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
-
- void finalizeDefaultAtomValues() override;
- void createDefaultSections() override;
- std::error_code setELFHeader() override;
-
- unique_bump_ptr<SymbolTable<ELFT>> createSymbolTable() override;
- unique_bump_ptr<DynamicTable<ELFT>> createDynamicTable() override;
- unique_bump_ptr<DynamicSymbolTable<ELFT>> createDynamicSymbolTable() override;
-
-private:
- MipsELFWriter<ELFT> _writeHelper;
- MipsTargetLayout<ELFT> &_targetLayout;
- unique_bump_ptr<Section<ELFT>> _reginfo;
- unique_bump_ptr<Section<ELFT>> _abiFlags;
-};
-
-} // elf
-} // lld
-
-#endif
diff --git a/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp b/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp
deleted file mode 100644
index b6cdd5c1487c..000000000000
--- a/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp
+++ /dev/null
@@ -1,164 +0,0 @@
-//===- lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp -------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "Atoms.h"
-#include "MipsCtorsOrderPass.h"
-#include "MipsLinkingContext.h"
-#include "MipsRelocationPass.h"
-#include "MipsTargetHandler.h"
-
-using namespace lld;
-using namespace lld::elf;
-
-std::unique_ptr<ELFLinkingContext>
-elf::createMipsLinkingContext(llvm::Triple triple) {
- if (triple.getArch() == llvm::Triple::mips ||
- triple.getArch() == llvm::Triple::mipsel ||
- triple.getArch() == llvm::Triple::mips64 ||
- triple.getArch() == llvm::Triple::mips64el)
- return llvm::make_unique<MipsLinkingContext>(triple);
- return nullptr;
-}
-
-static std::unique_ptr<TargetHandler> createTarget(llvm::Triple triple,
- MipsLinkingContext &ctx) {
- switch (triple.getArch()) {
- case llvm::Triple::mips:
- return llvm::make_unique<MipsTargetHandler<ELF32BE>>(ctx);
- case llvm::Triple::mipsel:
- return llvm::make_unique<MipsTargetHandler<ELF32LE>>(ctx);
- case llvm::Triple::mips64:
- return llvm::make_unique<MipsTargetHandler<ELF64BE>>(ctx);
- case llvm::Triple::mips64el:
- return llvm::make_unique<MipsTargetHandler<ELF64LE>>(ctx);
- default:
- llvm_unreachable("Unhandled arch");
- }
-}
-
-MipsLinkingContext::MipsLinkingContext(llvm::Triple triple)
- : ELFLinkingContext(triple, createTarget(triple, *this)) {}
-
-uint64_t MipsLinkingContext::getBaseAddress() const {
- if (_baseAddress != 0 || getOutputELFType() != llvm::ELF::ET_EXEC)
- return _baseAddress;
- switch (getAbi()) {
- case MipsAbi::O32:
- return 0x0400000;
- case MipsAbi::N32:
- return 0x10000000;
- case MipsAbi::N64:
- return 0x120000000;
- }
- llvm_unreachable("unknown MIPS ABI flag");
-}
-
-StringRef MipsLinkingContext::entrySymbolName() const {
- if (_outputELFType == elf::ET_EXEC && _entrySymbolName.empty())
- return "__start";
- return _entrySymbolName;
-}
-
-StringRef MipsLinkingContext::getDefaultInterpreter() const {
- switch (getAbi()) {
- case MipsAbi::O32:
- return "/lib/ld.so.1";
- case MipsAbi::N32:
- return "/lib32/ld.so.1";
- case MipsAbi::N64:
- return "/lib64/ld.so.1";
- }
- llvm_unreachable("unknown MIPS ABI flag");
-}
-
-void MipsLinkingContext::addPasses(PassManager &pm) {
- auto pass = createMipsRelocationPass(*this);
- if (pass)
- pm.add(std::move(pass));
- ELFLinkingContext::addPasses(pm);
- pm.add(llvm::make_unique<elf::MipsCtorsOrderPass>());
-}
-
-bool MipsLinkingContext::isDynamicRelocation(const Reference &r) const {
- if (r.kindNamespace() != Reference::KindNamespace::ELF)
- return false;
- assert(r.kindArch() == Reference::KindArch::Mips);
- switch (r.kindValue()) {
- case llvm::ELF::R_MIPS_COPY:
- case llvm::ELF::R_MIPS_REL32:
- return true;
- case llvm::ELF::R_MIPS_TLS_DTPMOD32:
- case llvm::ELF::R_MIPS_TLS_DTPREL32:
- case llvm::ELF::R_MIPS_TLS_TPREL32:
- case llvm::ELF::R_MIPS_TLS_DTPMOD64:
- case llvm::ELF::R_MIPS_TLS_DTPREL64:
- case llvm::ELF::R_MIPS_TLS_TPREL64:
- return isDynamic();
- default:
- return false;
- }
-}
-
-bool MipsLinkingContext::isCopyRelocation(const Reference &r) const {
- if (r.kindNamespace() != Reference::KindNamespace::ELF)
- return false;
- assert(r.kindArch() == Reference::KindArch::Mips);
- if (r.kindValue() == llvm::ELF::R_MIPS_COPY)
- return true;
- return false;
-}
-
-bool MipsLinkingContext::isPLTRelocation(const Reference &r) const {
- if (r.kindNamespace() != Reference::KindNamespace::ELF)
- return false;
- assert(r.kindArch() == Reference::KindArch::Mips);
- switch (r.kindValue()) {
- case llvm::ELF::R_MIPS_JUMP_SLOT:
- return true;
- default:
- return false;
- }
-}
-
-bool MipsLinkingContext::isRelativeReloc(const Reference &r) const {
- if (r.kindNamespace() != Reference::KindNamespace::ELF)
- return false;
- assert(r.kindArch() == Reference::KindArch::Mips);
- switch (r.kindValue()) {
- case llvm::ELF::R_MIPS_REL32:
- case llvm::ELF::R_MIPS_GPREL16:
- case llvm::ELF::R_MIPS_GPREL32:
- return true;
- default:
- return false;
- }
-}
-
-MipsAbi MipsLinkingContext::getAbi() const {
- auto &handler = static_cast<MipsBaseTargetHandler &>(getTargetHandler());
- return handler.getAbi();
-}
-
-const Registry::KindStrings kindStrings[] = {
-#define ELF_RELOC(name, value) LLD_KIND_STRING_ENTRY(name),
-#include "llvm/Support/ELFRelocs/Mips.def"
-#undef ELF_RELOC
- LLD_KIND_STRING_ENTRY(LLD_R_MIPS_GLOBAL_GOT),
- LLD_KIND_STRING_ENTRY(LLD_R_MIPS_32_HI16),
- LLD_KIND_STRING_ENTRY(LLD_R_MIPS_64_HI16),
- LLD_KIND_STRING_ENTRY(LLD_R_MIPS_GLOBAL_26),
- LLD_KIND_STRING_ENTRY(LLD_R_MIPS_STO_PLT),
- LLD_KIND_STRING_ENTRY(LLD_R_MICROMIPS_GLOBAL_26_S1),
- LLD_KIND_STRING_END
-};
-
-void MipsLinkingContext::registerRelocationNames(Registry &registry) {
- registry.addKindTable(Reference::KindNamespace::ELF,
- Reference::KindArch::Mips, kindStrings);
-}
diff --git a/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h b/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h
deleted file mode 100644
index 414d2c785e17..000000000000
--- a/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h
+++ /dev/null
@@ -1,56 +0,0 @@
-//===- lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h ---------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_LINKING_CONTEXT_H
-#define LLD_READER_WRITER_ELF_MIPS_MIPS_LINKING_CONTEXT_H
-
-#include "MipsAbiInfoHandler.h"
-#include "lld/ReaderWriter/ELFLinkingContext.h"
-
-namespace lld {
-namespace elf {
-
-/// \brief Mips internal references.
-enum {
- /// \brief Do nothing but mark GOT entry as a global one.
- LLD_R_MIPS_GLOBAL_GOT = 1024,
- /// \brief Apply high 16 bits of symbol + addend.
- LLD_R_MIPS_32_HI16 = 1025,
- /// \brief The same as R_MIPS_26 but for global symbols.
- LLD_R_MIPS_GLOBAL_26 = 1026,
- /// \brief Represents a reference between PLT and dynamic symbol.
- LLD_R_MIPS_STO_PLT = 1029,
- /// \brief The same as R_MICROMIPS_26_S1 but for global symbols.
- LLD_R_MICROMIPS_GLOBAL_26_S1 = 1030,
- /// \brief Apply high 32+16 bits of symbol + addend.
- LLD_R_MIPS_64_HI16 = 1031,
-};
-
-class MipsLinkingContext final : public ELFLinkingContext {
-public:
- MipsLinkingContext(llvm::Triple triple);
-
- void registerRelocationNames(Registry &r) override;
- int getMachineType() const override { return llvm::ELF::EM_MIPS; }
- uint64_t getBaseAddress() const override;
- StringRef entrySymbolName() const override;
- StringRef getDefaultInterpreter() const override;
- void addPasses(PassManager &pm) override;
- bool isRelaOutputFormat() const override { return false; }
- bool isDynamicRelocation(const Reference &r) const override;
- bool isCopyRelocation(const Reference &r) const override;
- bool isPLTRelocation(const Reference &r) const override;
- bool isRelativeReloc(const Reference &r) const override;
-
- MipsAbi getAbi() const;
-};
-
-} // elf
-} // lld
-
-#endif
diff --git a/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp b/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp
deleted file mode 100644
index c55a7a4116e6..000000000000
--- a/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp
+++ /dev/null
@@ -1,687 +0,0 @@
-//===- lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp ----------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "MipsLinkingContext.h"
-#include "MipsRelocationHandler.h"
-#include "MipsTargetLayout.h"
-#include "llvm/Support/Format.h"
-
-using namespace lld;
-using namespace elf;
-using namespace llvm::ELF;
-using namespace llvm::support;
-
-namespace {
-enum class CrossJumpMode {
- None, // Not a jump or non-isa-cross jump
- ToRegular, // cross isa jump to regular symbol
- ToMicro, // cross isa jump to microMips symbol
- ToMicroJalr// cross isa jump to microMips symbol referenced by R_MIPS_JALR
-};
-
-typedef std::function<std::error_code(int64_t, bool)> OverflowChecker;
-
-static std::error_code dummyCheck(int64_t, bool) {
- return std::error_code();
-}
-
-template <int BITS> static std::error_code signedCheck(int64_t res, bool) {
- if (llvm::isInt<BITS>(res))
- return std::error_code();
- return make_out_of_range_reloc_error();
-}
-
-template <int BITS>
-static std::error_code gpDispCheck(int64_t res, bool isGpDisp) {
- if (!isGpDisp || llvm::isInt<BITS>(res))
- return std::error_code();
- return make_out_of_range_reloc_error();
-}
-
-struct MipsRelocationParams {
- uint8_t _size; // Relocations's size in bytes
- uint64_t _mask; // Read/write mask of relocation
- uint8_t _shift; // Relocation's addendum left shift size
- bool _shuffle; // Relocation's addendum/result needs to be shuffled
- OverflowChecker _overflow; // Check the relocation result
-};
-
-template <class ELFT> class RelocationHandler : public TargetRelocationHandler {
-public:
- RelocationHandler(MipsLinkingContext &ctx, MipsTargetLayout<ELFT> &layout)
- : _ctx(ctx), _targetLayout(layout) {}
-
- std::error_code applyRelocation(ELFWriter &writer,
- llvm::FileOutputBuffer &buf,
- const AtomLayout &atom,
- const Reference &ref) const override;
-
-private:
- MipsLinkingContext &_ctx;
- MipsTargetLayout<ELFT> &_targetLayout;
-};
-}
-
-static MipsRelocationParams getRelocationParams(uint32_t rType) {
- switch (rType) {
- case R_MIPS_NONE:
- return {4, 0x0, 0, false, dummyCheck};
- case R_MIPS_64:
- case R_MIPS_SUB:
- return {8, 0xffffffffffffffffull, 0, false, dummyCheck};
- case R_MICROMIPS_SUB:
- return {8, 0xffffffffffffffffull, 0, true, dummyCheck};
- case R_MIPS_32:
- case R_MIPS_GPREL32:
- case R_MIPS_REL32:
- case R_MIPS_PC32:
- case R_MIPS_EH:
- return {4, 0xffffffff, 0, false, dummyCheck};
- case LLD_R_MIPS_32_HI16:
- return {4, 0xffff0000, 0, false, dummyCheck};
- case LLD_R_MIPS_64_HI16:
- return {8, 0xffffffffffff0000ull, 0, false, dummyCheck};
- case R_MIPS_26:
- case LLD_R_MIPS_GLOBAL_26:
- return {4, 0x3ffffff, 2, false, dummyCheck};
- case R_MIPS_PC16:
- return {4, 0xffff, 2, false, signedCheck<18>};
- case R_MIPS_PC18_S3:
- return {4, 0x3ffff, 3, false, signedCheck<21>};
- case R_MIPS_PC19_S2:
- return {4, 0x7ffff, 2, false, signedCheck<21>};
- case R_MIPS_PC21_S2:
- return {4, 0x1fffff, 2, false, signedCheck<23>};
- case R_MIPS_PC26_S2:
- return {4, 0x3ffffff, 2, false, signedCheck<28>};
- case R_MIPS_HI16:
- return {4, 0xffff, 0, false, gpDispCheck<16>};
- case R_MIPS_LO16:
- case R_MIPS_HIGHER:
- case R_MIPS_HIGHEST:
- return {4, 0xffff, 0, false, dummyCheck};
- case R_MIPS_16:
- case R_MIPS_PCHI16:
- case R_MIPS_PCLO16:
- case R_MIPS_GOT16:
- case R_MIPS_CALL16:
- case R_MIPS_GOT_DISP:
- case R_MIPS_GOT_PAGE:
- case R_MIPS_GOT_OFST:
- case R_MIPS_GPREL16:
- case R_MIPS_TLS_GD:
- case R_MIPS_TLS_LDM:
- case R_MIPS_TLS_GOTTPREL:
- case R_MIPS_LITERAL:
- return {4, 0xffff, 0, false, signedCheck<16>};
- case R_MIPS_GOT_HI16:
- case R_MIPS_GOT_LO16:
- case R_MIPS_CALL_HI16:
- case R_MIPS_CALL_LO16:
- case R_MIPS_TLS_DTPREL_HI16:
- case R_MIPS_TLS_DTPREL_LO16:
- case R_MIPS_TLS_TPREL_HI16:
- case R_MIPS_TLS_TPREL_LO16:
- return {4, 0xffff, 0, false, dummyCheck};
- case R_MICROMIPS_GPREL16:
- case R_MICROMIPS_LITERAL:
- return {4, 0xffff, 0, true, signedCheck<16>};
- case R_MICROMIPS_GPREL7_S2:
- return {4, 0x7f, 2, false, signedCheck<9>};
- case R_MICROMIPS_GOT_HI16:
- case R_MICROMIPS_GOT_LO16:
- case R_MICROMIPS_CALL_HI16:
- case R_MICROMIPS_CALL_LO16:
- case R_MICROMIPS_TLS_DTPREL_HI16:
- case R_MICROMIPS_TLS_DTPREL_LO16:
- case R_MICROMIPS_TLS_TPREL_HI16:
- case R_MICROMIPS_TLS_TPREL_LO16:
- return {4, 0xffff, 0, true, dummyCheck};
- case R_MICROMIPS_26_S1:
- case LLD_R_MICROMIPS_GLOBAL_26_S1:
- return {4, 0x3ffffff, 1, true, dummyCheck};
- case R_MICROMIPS_HI16:
- return {4, 0xffff, 0, true, gpDispCheck<16>};
- case R_MICROMIPS_LO16:
- case R_MICROMIPS_HI0_LO16:
- case R_MICROMIPS_HIGHER:
- case R_MICROMIPS_HIGHEST:
- return {4, 0xffff, 0, true, dummyCheck};
- case R_MICROMIPS_PC16_S1:
- return {4, 0xffff, 1, true, signedCheck<17>};
- case R_MICROMIPS_PC7_S1:
- return {4, 0x7f, 1, false, signedCheck<8>};
- case R_MICROMIPS_PC10_S1:
- return {4, 0x3ff, 1, false, signedCheck<11>};
- case R_MICROMIPS_PC23_S2:
- return {4, 0x7fffff, 2, true, signedCheck<25>};
- case R_MICROMIPS_PC18_S3:
- return {4, 0x3ffff, 3, true, signedCheck<21>};
- case R_MICROMIPS_PC19_S2:
- return {4, 0x7ffff, 2, true, signedCheck<21>};
- case R_MICROMIPS_PC21_S2:
- return {4, 0x1fffff, 2, true, signedCheck<23>};
- case R_MICROMIPS_PC26_S2:
- return {4, 0x3ffffff, 2, true, signedCheck<28>};
- case R_MICROMIPS_GOT16:
- case R_MICROMIPS_CALL16:
- case R_MICROMIPS_TLS_GD:
- case R_MICROMIPS_TLS_LDM:
- case R_MICROMIPS_TLS_GOTTPREL:
- case R_MICROMIPS_GOT_DISP:
- case R_MICROMIPS_GOT_PAGE:
- case R_MICROMIPS_GOT_OFST:
- return {4, 0xffff, 0, true, signedCheck<16>};
- case R_MIPS_JALR:
- return {4, 0xffffffff, 0, false, dummyCheck};
- case R_MICROMIPS_JALR:
- return {4, 0x0, 0, true, dummyCheck};
- case R_MIPS_JUMP_SLOT:
- case R_MIPS_COPY:
- case R_MIPS_TLS_DTPMOD32:
- case R_MIPS_TLS_DTPREL32:
- case R_MIPS_TLS_TPREL32:
- return {4, 0xffffffff, 0, false, dummyCheck};
- case R_MIPS_TLS_DTPMOD64:
- case R_MIPS_TLS_DTPREL64:
- case R_MIPS_TLS_TPREL64:
- return {8, 0xffffffffffffffffull, 0, false, dummyCheck};
- case LLD_R_MIPS_GLOBAL_GOT:
- case LLD_R_MIPS_STO_PLT:
- // Do nothing.
- return {4, 0x0, 0, false, dummyCheck};
- default:
- llvm_unreachable("Unknown relocation");
- }
-}
-
-template <class ELFT>
-static uint64_t relocRead(const MipsRelocationParams &params,
- const uint8_t *loc);
-
-static int64_t getHi16(int64_t value) {
- return ((value + 0x8000) >> 16) & 0xffff;
-}
-
-static int64_t getHigher16(int64_t value) {
- return ((value + 0x80008000ull) >> 32) & 0xffff;
-}
-
-static int64_t getHighest16(int64_t value) {
- return ((value + 0x800080008000ull) >> 48) & 0xffff;
-}
-
-static int64_t maskLow16(int64_t value) {
- return (value + 0x8000) & ~0xffff;
-}
-
-/// R_MIPS_GOT_OFST, R_MICROMIPS_GOT_OFST
-/// rel16 offset of (S+A) from the page pointer (verify)
-static int32_t relocGOTOfst(uint64_t S, int64_t A) {
- int64_t page = maskLow16(S + A);
- return S + A - page;
-}
-
-/// \brief R_MIPS_PC16
-/// local/external: (S + A - P) >> 2
-static ErrorOr<int64_t> relocPc16(uint64_t P, uint64_t S, int64_t A) {
- if ((S + A) & 3)
- return make_unaligned_range_reloc_error();
- return S + A - P;
-}
-
-/// \brief R_MIPS_PC18_S3, R_MICROMIPS_PC18_S3
-/// local/external: (S + A - P) >> 3 (P with cleared 3 less significant bits)
-static ErrorOr<int64_t> relocPc18(uint64_t P, uint64_t S, int64_t A) {
- if ((S + A) & 6)
- return make_unaligned_range_reloc_error();
- return S + A - ((P | 7) ^ 7);
-}
-
-/// \brief R_MIPS_PC19_S2, R_MICROMIPS_PC19_S2, R_MIPS_PC21_S2,
-/// R_MICROMIPS_PC21_S2, R_MIPS_PC26_S2, R_MICROMIPS_PC26_S2
-/// local/external: (S + A - P) >> 2
-static ErrorOr<int64_t> relocPcS2(uint64_t P, uint64_t S, int64_t A) {
- if ((S + A) & 2)
- return make_unaligned_range_reloc_error();
- return S + A - P;
-}
-
-template <class ELFT>
-static ErrorOr<int64_t> relocJalr(uint64_t P, uint64_t S, bool isCrossJump,
- uint8_t *location) {
- uint64_t ins = relocRead<ELFT>(getRelocationParams(R_MIPS_JALR), location);
- if (isCrossJump)
- return ins;
- int64_t off = S - P - 4;
- if (!llvm::isInt<18>(off))
- return ins;
- if (ins == 0x0320f809) // jalr t9
- return 0x04110000 | ((off >> 2) & 0xffff);
- if (ins == 0x03200008) // jr t9
- return 0x10000000 | ((off >> 2) & 0xffff);
- return ins;
-}
-
-static int64_t relocRel32(uint64_t S, int64_t A, bool isLocal) {
- // If output relocation format is REL and the input one is RELA, the only
- // method to transfer the relocation addend from the input relocation
- // to the output dynamic relocation is to save this addend to the location
- // modified by R_MIPS_REL32.
- return isLocal ? S + A : A;
-}
-
-static std::error_code adjustJumpOpCode(uint64_t &ins, uint64_t tgt,
- CrossJumpMode mode) {
- if (mode == CrossJumpMode::None || mode == CrossJumpMode::ToMicroJalr)
- return std::error_code();
-
- bool toMicro = mode == CrossJumpMode::ToMicro;
- uint32_t opNative = toMicro ? 0x03 : 0x3d;
- uint32_t opCross = toMicro ? 0x1d : 0x3c;
-
- if ((tgt & 1) != toMicro)
- return make_dynamic_error_code("Incorrect bit 0 for the jalx target");
-
- if (tgt & 2)
- return make_dynamic_error_code(Twine("The jalx target 0x") +
- Twine::utohexstr(tgt) +
- " is not word-aligned");
- uint8_t op = ins >> 26;
- if (op != opNative && op != opCross)
- return make_dynamic_error_code(Twine("Unsupported jump opcode (0x") +
- Twine::utohexstr(op) +
- ") for ISA modes cross call");
-
- ins = (ins & ~(0x3f << 26)) | (opCross << 26);
- return std::error_code();
-}
-
-static bool isMicroMipsAtom(const Atom *a) {
- if (const auto *da = dyn_cast<DefinedAtom>(a))
- return da->codeModel() == DefinedAtom::codeMipsMicro ||
- da->codeModel() == DefinedAtom::codeMipsMicroPIC;
- return false;
-}
-
-static CrossJumpMode getCrossJumpMode(const Reference &ref) {
- if (!isa<DefinedAtom>(ref.target()))
- return CrossJumpMode::None;
- bool isTgtMicro = isMicroMipsAtom(ref.target());
- switch (ref.kindValue()) {
- case R_MIPS_JALR:
- return isTgtMicro ? CrossJumpMode::ToMicroJalr : CrossJumpMode::None;
- case R_MIPS_26:
- case LLD_R_MIPS_GLOBAL_26:
- return isTgtMicro ? CrossJumpMode::ToMicro : CrossJumpMode::None;
- case R_MICROMIPS_26_S1:
- case LLD_R_MICROMIPS_GLOBAL_26_S1:
- return isTgtMicro ? CrossJumpMode::None : CrossJumpMode::ToRegular;
- default:
- return CrossJumpMode::None;
- }
-}
-
-template <class ELFT>
-static ErrorOr<int64_t>
-calculateRelocation(Reference::KindValue kind, Reference::Addend addend,
- uint64_t tgtAddr, uint64_t relAddr, uint64_t gpAddr,
- uint8_t *location, bool isGP, bool isCrossJump,
- bool isDynamic, bool isLocalSym) {
- switch (kind) {
- case R_MIPS_NONE:
- return 0;
- case R_MIPS_16:
- case R_MIPS_32:
- case R_MIPS_64:
- case R_MIPS_TLS_DTPREL_LO16:
- case R_MIPS_TLS_TPREL_LO16:
- case R_MICROMIPS_TLS_DTPREL_LO16:
- case R_MICROMIPS_TLS_TPREL_LO16:
- case LLD_R_MIPS_GLOBAL_26:
- case LLD_R_MICROMIPS_GLOBAL_26_S1:
- return tgtAddr + addend;
- case R_MIPS_SUB:
- case R_MICROMIPS_SUB:
- return tgtAddr - addend;
- case R_MIPS_26:
- return tgtAddr + (addend | (relAddr & 0xf0000000));
- case R_MICROMIPS_26_S1:
- return tgtAddr + (addend | (relAddr & 0xf8000000));
- case R_MIPS_HI16:
- case R_MICROMIPS_HI16:
- return getHi16(tgtAddr + addend - (isGP ? relAddr : 0));
- case R_MIPS_PCHI16:
- return getHi16(tgtAddr + addend - relAddr);
- case R_MIPS_LO16:
- return tgtAddr + addend - (isGP ? relAddr - 4 : 0);
- case R_MICROMIPS_LO16:
- case R_MICROMIPS_HI0_LO16:
- return tgtAddr + addend - (isGP ? relAddr - 3 : 0);
- case R_MIPS_GOT_HI16:
- case R_MIPS_CALL_HI16:
- case R_MICROMIPS_GOT_HI16:
- case R_MICROMIPS_CALL_HI16:
- return getHi16(tgtAddr - gpAddr);
- case R_MIPS_HIGHER:
- case R_MICROMIPS_HIGHER:
- return getHigher16(tgtAddr + addend);
- case R_MIPS_HIGHEST:
- case R_MICROMIPS_HIGHEST:
- return getHighest16(tgtAddr + addend);
- case R_MIPS_GOT_LO16:
- case R_MIPS_CALL_LO16:
- case R_MICROMIPS_GOT_LO16:
- case R_MICROMIPS_CALL_LO16:
- case R_MIPS_EH:
- case R_MIPS_GOT16:
- case R_MIPS_CALL16:
- case R_MIPS_GOT_DISP:
- case R_MIPS_GOT_PAGE:
- case R_MICROMIPS_GOT_DISP:
- case R_MICROMIPS_GOT_PAGE:
- case R_MICROMIPS_GOT16:
- case R_MICROMIPS_CALL16:
- case R_MIPS_TLS_GD:
- case R_MIPS_TLS_LDM:
- case R_MIPS_TLS_GOTTPREL:
- case R_MICROMIPS_TLS_GD:
- case R_MICROMIPS_TLS_LDM:
- case R_MICROMIPS_TLS_GOTTPREL:
- return tgtAddr - gpAddr;
- case R_MIPS_GPREL16:
- case R_MIPS_GPREL32:
- case R_MIPS_LITERAL:
- case R_MICROMIPS_GPREL16:
- case R_MICROMIPS_GPREL7_S2:
- case R_MICROMIPS_LITERAL:
- return tgtAddr + addend - gpAddr;
- case R_MIPS_GOT_OFST:
- case R_MICROMIPS_GOT_OFST:
- return relocGOTOfst(tgtAddr, addend);
- case R_MIPS_PC16:
- return relocPc16(relAddr, tgtAddr, addend);
- case R_MIPS_PC18_S3:
- case R_MICROMIPS_PC18_S3:
- return relocPc18(relAddr, tgtAddr, addend);
- case R_MIPS_PC19_S2:
- case R_MICROMIPS_PC19_S2:
- case R_MIPS_PC21_S2:
- case R_MICROMIPS_PC21_S2:
- case R_MIPS_PC26_S2:
- case R_MICROMIPS_PC26_S2:
- return relocPcS2(relAddr, tgtAddr, addend);
- case R_MIPS_PC32:
- case R_MIPS_PCLO16:
- case R_MICROMIPS_PC7_S1:
- case R_MICROMIPS_PC10_S1:
- case R_MICROMIPS_PC16_S1:
- case R_MICROMIPS_PC23_S2:
- return tgtAddr + addend - relAddr;
- case R_MIPS_TLS_DTPREL_HI16:
- case R_MIPS_TLS_TPREL_HI16:
- case R_MICROMIPS_TLS_DTPREL_HI16:
- case R_MICROMIPS_TLS_TPREL_HI16:
- return getHi16(tgtAddr + addend);
- case R_MIPS_JALR:
- return relocJalr<ELFT>(relAddr, tgtAddr, isCrossJump, location);
- case R_MICROMIPS_JALR:
- // We do not do JALR optimization now.
- return 0;
- case R_MIPS_REL32:
- return relocRel32(tgtAddr, addend, isLocalSym);
- case R_MIPS_JUMP_SLOT:
- case R_MIPS_COPY:
- // Ignore runtime relocations.
- return 0;
- case R_MIPS_TLS_DTPMOD32:
- case R_MIPS_TLS_DTPMOD64:
- return isDynamic ? 0 : 1;
- case R_MIPS_TLS_DTPREL32:
- case R_MIPS_TLS_DTPREL64:
- return isDynamic ? 0 : tgtAddr + addend - 0x8000;
- case R_MIPS_TLS_TPREL32:
- case R_MIPS_TLS_TPREL64:
- return isDynamic ? 0 : tgtAddr + addend - 0x7000;
- case LLD_R_MIPS_32_HI16:
- case LLD_R_MIPS_64_HI16:
- return maskLow16(tgtAddr + addend);
- case LLD_R_MIPS_STO_PLT:
- case LLD_R_MIPS_GLOBAL_GOT:
- // Do nothing.
- return 0;
- default:
- return make_unhandled_reloc_error();
- }
-}
-
-template <class ELFT>
-static uint64_t relocRead(const MipsRelocationParams &params,
- const uint8_t *loc) {
- assert((params._size == 4 || params._size == 8) && "Unexpected size");
- uint64_t data = 0;
- memcpy(&data, loc, params._size);
- if (params._shuffle) {
- using namespace endian;
- auto p = reinterpret_cast<const uint8_t *>(&data);
- uint32_t a = readNext<uint16_t, ELFT::TargetEndianness, unaligned>(p);
- uint32_t b = read<uint16_t, ELFT::TargetEndianness, unaligned>(p);
- write<uint32_t, ELFT::TargetEndianness, unaligned>(&data, a << 16 | b);
- }
- switch (params._size) {
- case 4:
- return endian::read<uint32_t, ELFT::TargetEndianness, unaligned>(&data);
- case 8:
- return endian::read<uint64_t, ELFT::TargetEndianness, unaligned>(&data);
- default:
- llvm_unreachable("Unexpected size");
- }
-}
-
-template <class ELFT>
-static void relocWrite(uint64_t data, const MipsRelocationParams &params,
- uint8_t *loc) {
- switch (params._size) {
- case 4:
- endian::write<uint32_t, ELFT::TargetEndianness, unaligned>(loc, data);
- break;
- case 8:
- endian::write<uint64_t, ELFT::TargetEndianness, unaligned>(loc, data);
- break;
- default:
- llvm_unreachable("Unexpected size");
- }
- if (params._shuffle) {
- uint32_t v = endian::read<uint32_t, ELFT::TargetEndianness, unaligned>(loc);
- uint16_t a = v >> 16;
- uint16_t b = v & 0xffff;
- endian::write<uint16_t, ELFT::TargetEndianness, unaligned>(loc, a);
- endian::write<uint16_t, ELFT::TargetEndianness, unaligned>(loc + 2, b);
- }
-}
-
-static uint32_t getRelKind(const Reference &ref, size_t num) {
- if (num == 0)
- return ref.kindValue();
- if (num > 2)
- return R_MIPS_NONE;
- return (ref.tag() >> (8 * (num - 1))) & 0xff;
-}
-
-static uint8_t getRelShift(Reference::KindValue kind,
- const MipsRelocationParams &params,
- bool isCrossJump) {
- uint8_t shift = params._shift;
- if (isCrossJump &&
- (kind == R_MICROMIPS_26_S1 || kind == LLD_R_MICROMIPS_GLOBAL_26_S1))
- return 2;
- return shift;
-}
-
-static bool isLocalTarget(const Atom *a) {
- if (auto *da = dyn_cast<DefinedAtom>(a))
- return da->scope() == Atom::scopeTranslationUnit;
- return false;
-}
-
-template <class ELFT>
-std::error_code RelocationHandler<ELFT>::applyRelocation(
- ELFWriter &writer, llvm::FileOutputBuffer &buf, const AtomLayout &atom,
- const Reference &ref) const {
- if (ref.kindNamespace() != Reference::KindNamespace::ELF)
- return std::error_code();
- assert(ref.kindArch() == Reference::KindArch::Mips);
-
- uint64_t gpAddr = _targetLayout.getGPAddr();
- bool isGpDisp = ref.target()->name() == "_gp_disp";
- bool isLocalSym = isLocalTarget(ref.target());
-
- uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset;
- uint8_t *location = atomContent + ref.offsetInAtom();
- uint64_t tgtAddr = writer.addressOfAtom(ref.target());
- uint64_t relAddr = atom._virtualAddr + ref.offsetInAtom();
-
- if (isMicroMipsAtom(ref.target()))
- tgtAddr |= 1;
-
- CrossJumpMode jumpMode = getCrossJumpMode(ref);
- bool isCrossJump = jumpMode != CrossJumpMode::None;
-
- uint64_t sym = tgtAddr;
- ErrorOr<int64_t> res = ref.addend();
- Reference::KindValue lastRel = R_MIPS_NONE;
-
- for (size_t relNum = 0; relNum < 3; ++relNum) {
- Reference::KindValue kind = getRelKind(ref, relNum);
- if (kind == R_MIPS_NONE)
- break;
- auto params = getRelocationParams(kind);
- res = calculateRelocation<ELFT>(kind, *res, sym, relAddr, gpAddr, location,
- isGpDisp, isCrossJump, _ctx.isDynamic(),
- isLocalSym);
- if (auto ec = res.getError())
- return ec;
- // Check result for the last relocation only.
- if (getRelKind(ref, relNum + 1) == R_MIPS_NONE) {
- if (auto ec = params._overflow(*res, isGpDisp))
- return ec;
- }
- res = *res >> getRelShift(kind, params, isCrossJump);
- // FIXME (simon): Handle r_ssym value.
- sym = 0;
- isGpDisp = false;
- isCrossJump = false;
- lastRel = kind;
- }
-
- auto params = getRelocationParams(lastRel);
- uint64_t ins = relocRead<ELFT>(params, location);
- if (auto ec = adjustJumpOpCode(ins, tgtAddr, jumpMode))
- return ec;
-
- ins = (ins & ~params._mask) | (*res & params._mask);
- relocWrite<ELFT>(ins, params, location);
-
- return std::error_code();
-}
-
-namespace lld {
-namespace elf {
-
-template <>
-std::unique_ptr<TargetRelocationHandler>
-createMipsRelocationHandler<ELF32BE>(MipsLinkingContext &ctx,
- MipsTargetLayout<ELF32BE> &layout) {
- return llvm::make_unique<RelocationHandler<ELF32BE>>(ctx, layout);
-}
-
-template <>
-std::unique_ptr<TargetRelocationHandler>
-createMipsRelocationHandler<ELF32LE>(MipsLinkingContext &ctx,
- MipsTargetLayout<ELF32LE> &layout) {
- return llvm::make_unique<RelocationHandler<ELF32LE>>(ctx, layout);
-}
-
-template <>
-std::unique_ptr<TargetRelocationHandler>
-createMipsRelocationHandler<ELF64BE>(MipsLinkingContext &ctx,
- MipsTargetLayout<ELF64BE> &layout) {
- return llvm::make_unique<RelocationHandler<ELF64BE>>(ctx, layout);
-}
-
-template <>
-std::unique_ptr<TargetRelocationHandler>
-createMipsRelocationHandler<ELF64LE>(MipsLinkingContext &ctx,
- MipsTargetLayout<ELF64LE> &layout) {
- return llvm::make_unique<RelocationHandler<ELF64LE>>(ctx, layout);
-}
-
-template <class ELFT>
-Reference::Addend readMipsRelocAddend(Reference::KindValue kind,
- const uint8_t *content) {
- auto params = getRelocationParams(kind);
- uint64_t ins = relocRead<ELFT>(params, content);
- int64_t res = (ins & params._mask) << params._shift;
- switch (kind) {
- case R_MIPS_GPREL16:
- case R_MICROMIPS_GPREL16:
- case R_MIPS_PCLO16:
- case R_MIPS_LITERAL:
- case R_MICROMIPS_LITERAL:
- return llvm::SignExtend32<16>(res);
- case R_MIPS_PC16:
- return llvm::SignExtend32<18>(res);
- case R_MICROMIPS_GPREL7_S2:
- return llvm::SignExtend32<9>(res);
- case R_MICROMIPS_PC7_S1:
- return llvm::SignExtend32<8>(res);
- case R_MICROMIPS_PC10_S1:
- return llvm::SignExtend32<11>(res);
- case R_MIPS_16:
- return llvm::SignExtend32<16>(res);
- case R_MICROMIPS_PC16_S1:
- return llvm::SignExtend32<17>(res);
- case R_MIPS_PC18_S3:
- case R_MIPS_PC19_S2:
- case R_MICROMIPS_PC18_S3:
- case R_MICROMIPS_PC19_S2:
- return llvm::SignExtend32<21>(res);
- case R_MIPS_PC21_S2:
- case R_MICROMIPS_PC21_S2:
- return llvm::SignExtend32<23>(res);
- case R_MICROMIPS_PC23_S2:
- return llvm::SignExtend32<25>(res);
- case R_MICROMIPS_26_S1:
- return llvm::SignExtend32<27>(res);
- case R_MIPS_26:
- case R_MIPS_PC26_S2:
- case R_MICROMIPS_PC26_S2:
- return llvm::SignExtend32<28>(res);
- default:
- // Nothing to do
- break;
- }
- return res;
-}
-
-template
-Reference::Addend readMipsRelocAddend<ELF32BE>(Reference::KindValue kind,
- const uint8_t *content);
-template
-Reference::Addend readMipsRelocAddend<ELF32LE>(Reference::KindValue kind,
- const uint8_t *content);
-template
-Reference::Addend readMipsRelocAddend<ELF64BE>(Reference::KindValue kind,
- const uint8_t *content);
-template
-Reference::Addend readMipsRelocAddend<ELF64LE>(Reference::KindValue kind,
- const uint8_t *content);
-
-} // elf
-} // lld
diff --git a/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.h b/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.h
deleted file mode 100644
index 62a7aee34496..000000000000
--- a/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.h
+++ /dev/null
@@ -1,31 +0,0 @@
-//===- lld/ReaderWriter/ELF/Mips/MipsRelocationHandler.h ------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_RELOCATION_HANDLER_H
-#define LLD_READER_WRITER_ELF_MIPS_MIPS_RELOCATION_HANDLER_H
-
-#include "lld/Core/Reference.h"
-
-namespace lld {
-namespace elf {
-
-class MipsLinkingContext;
-template<typename ELFT> class MipsTargetLayout;
-
-template <class ELFT>
-std::unique_ptr<TargetRelocationHandler>
-createMipsRelocationHandler(MipsLinkingContext &ctx,
- MipsTargetLayout<ELFT> &layout);
-
-template <class ELFT>
-Reference::Addend readMipsRelocAddend(Reference::KindValue kind,
- const uint8_t *content);
-} // elf
-} // lld
-
-#endif
diff --git a/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp b/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp
deleted file mode 100644
index b47c7d2210db..000000000000
--- a/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp
+++ /dev/null
@@ -1,1415 +0,0 @@
-//===- lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp -------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "MipsELFFile.h"
-#include "MipsLinkingContext.h"
-#include "MipsRelocationPass.h"
-#include "MipsTargetHandler.h"
-#include "llvm/ADT/DenseSet.h"
-
-using namespace lld;
-using namespace lld::elf;
-using namespace llvm::ELF;
-
-// Lazy resolver
-static const uint8_t mipsGot0AtomContent[] = {
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00
-};
-
-// Module pointer
-static const uint8_t mipsGotModulePointerAtomContent[] = {
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x80
-};
-
-// TLS GD Entry
-static const uint8_t mipsGotTlsGdAtomContent[] = {
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00
-};
-
-// Regular big-endian PLT0 entry
-static const uint8_t mipsBePlt0AtomContent[] = {
- 0x3c, 0x1c, 0x00, 0x00, // lui $28, %hi(&GOTPLT[0])
- 0x8f, 0x99, 0x00, 0x00, // lw $25, %lo(&GOTPLT[0])($28)
- 0x27, 0x9c, 0x00, 0x00, // addiu $28, $28, %lo(&GOTPLT[0])
- 0x03, 0x1c, 0xc0, 0x23, // subu $24, $24, $28
- 0x03, 0xe0, 0x78, 0x25, // move $15, $31
- 0x00, 0x18, 0xc0, 0x82, // srl $24, $24, 2
- 0x03, 0x20, 0xf8, 0x09, // jalr $25
- 0x27, 0x18, 0xff, 0xfe // subu $24, $24, 2
-};
-
-// Regular little-endian PLT0 entry
-static const uint8_t mipsLePlt0AtomContent[] = {
- 0x00, 0x00, 0x1c, 0x3c, // lui $28, %hi(&GOTPLT[0])
- 0x00, 0x00, 0x99, 0x8f, // lw $25, %lo(&GOTPLT[0])($28)
- 0x00, 0x00, 0x9c, 0x27, // addiu $28, $28, %lo(&GOTPLT[0])
- 0x23, 0xc0, 0x1c, 0x03, // subu $24, $24, $28
- 0x25, 0x78, 0xe0, 0x03, // move $15, $31
- 0x82, 0xc0, 0x18, 0x00, // srl $24, $24, 2
- 0x09, 0xf8, 0x20, 0x03, // jalr $25
- 0xfe, 0xff, 0x18, 0x27 // subu $24, $24, 2
-};
-
-// N32 big-endian PLT0 entry
-static const uint8_t mipsN32BePlt0AtomContent[] = {
- 0x3c, 0x0e, 0x00, 0x00, // lui $14, %hi(&GOTPLT[0])
- 0x8d, 0xd9, 0x00, 0x00, // lw $25, %lo(&GOTPLT[0])($14)
- 0x25, 0xce, 0x00, 0x00, // addiu $14, $14, %lo(&GOTPLT[0])
- 0x03, 0x0e, 0xc0, 0x23, // subu $24, $24, $14
- 0x03, 0xe0, 0x78, 0x25, // move $15, $31
- 0x00, 0x18, 0xc0, 0x82, // srl $24, $24, 2
- 0x03, 0x20, 0xf8, 0x09, // jalr $25
- 0x27, 0x18, 0xff, 0xfe // subu $24, $24, 2
-};
-
-// N32 little-endian PLT0 entry
-static const uint8_t mipsN32LePlt0AtomContent[] = {
- 0x00, 0x00, 0x0e, 0x3c, // lui $14, %hi(&GOTPLT[0])
- 0x00, 0x00, 0xd9, 0x8d, // lw $25, %lo(&GOTPLT[0])($14)
- 0x00, 0x00, 0xce, 0x25, // addiu $14, $14, %lo(&GOTPLT[0])
- 0x23, 0xc0, 0x0e, 0x03, // subu $24, $24, $14
- 0x25, 0x78, 0xe0, 0x03, // move $15, $31
- 0x82, 0xc0, 0x18, 0x00, // srl $24, $24, 2
- 0x09, 0xf8, 0x20, 0x03, // jalr $25
- 0xfe, 0xff, 0x18, 0x27 // subu $24, $24, 2
-};
-
-// microMIPS big-endian PLT0 entry
-static const uint8_t microMipsBePlt0AtomContent[] = {
- 0x79, 0x80, 0x00, 0x00, // addiupc $3, (&GOTPLT[0]) - .
- 0xff, 0x23, 0x00, 0x00, // lw $25, 0($3)
- 0x05, 0x35, // subu $2, $2, $3
- 0x25, 0x25, // srl $2, $2, 2
- 0x33, 0x02, 0xff, 0xfe, // subu $24, $2, 2
- 0x0d, 0xff, // move $15, $31
- 0x45, 0xf9, // jalrs $25
- 0x0f, 0x83, // move $28, $3
- 0x0c, 0x00 // nop
-};
-
-// microMIPS little-endian PLT0 entry
-static const uint8_t microMipsLePlt0AtomContent[] = {
- 0x80, 0x79, 0x00, 0x00, // addiupc $3, (&GOTPLT[0]) - .
- 0x23, 0xff, 0x00, 0x00, // lw $25, 0($3)
- 0x35, 0x05, // subu $2, $2, $3
- 0x25, 0x25, // srl $2, $2, 2
- 0x02, 0x33, 0xfe, 0xff, // subu $24, $2, 2
- 0xff, 0x0d, // move $15, $31
- 0xf9, 0x45, // jalrs $25
- 0x83, 0x0f, // move $28, $3
- 0x00, 0x0c // nop
-};
-
-// Regular big-endian PLT entry
-static const uint8_t mipsBePltAAtomContent[] = {
- 0x3c, 0x0f, 0x00, 0x00, // lui $15, %hi(.got.plt entry)
- 0x8d, 0xf9, 0x00, 0x00, // l[wd] $25, %lo(.got.plt entry)($15)
- 0x03, 0x20, 0x00, 0x08, // jr $25
- 0x25, 0xf8, 0x00, 0x00 // addiu $24, $15, %lo(.got.plt entry)
-};
-
-// Regular little-endian PLT entry
-static const uint8_t mipsLePltAAtomContent[] = {
- 0x00, 0x00, 0x0f, 0x3c, // lui $15, %hi(.got.plt entry)
- 0x00, 0x00, 0xf9, 0x8d, // l[wd] $25, %lo(.got.plt entry)($15)
- 0x08, 0x00, 0x20, 0x03, // jr $25
- 0x00, 0x00, 0xf8, 0x25 // addiu $24, $15, %lo(.got.plt entry)
-};
-
-// microMIPS big-endian PLT entry
-static const uint8_t microMipsBePltAAtomContent[] = {
- 0x79, 0x00, 0x00, 0x00, // addiupc $2, (.got.plt entry) - .
- 0xff, 0x22, 0x00, 0x00, // lw $25, 0($2)
- 0x45, 0x99, // jr $25
- 0x0f, 0x02 // move $24, $2
-};
-
-// microMIPS little-endian PLT entry
-static const uint8_t microMipsLePltAAtomContent[] = {
- 0x00, 0x79, 0x00, 0x00, // addiupc $2, (.got.plt entry) - .
- 0x22, 0xff, 0x00, 0x00, // lw $25, 0($2)
- 0x99, 0x45, // jr $25
- 0x02, 0x0f // move $24, $2
-};
-
-// R6 big-endian PLT entry
-static const uint8_t mipsR6BePltAAtomContent[] = {
- 0x3c, 0x0f, 0x00, 0x00, // lui $15, %hi(.got.plt entry)
- 0x8d, 0xf9, 0x00, 0x00, // l[wd] $25, %lo(.got.plt entry)($15)
- 0x03, 0x20, 0x00, 0x09, // jr $25
- 0x25, 0xf8, 0x00, 0x00 // addiu $24, $15, %lo(.got.plt entry)
-};
-
-// R6 little-endian PLT entry
-static const uint8_t mipsR6LePltAAtomContent[] = {
- 0x00, 0x00, 0x0f, 0x3c, // lui $15, %hi(.got.plt entry)
- 0x00, 0x00, 0xf9, 0x8d, // l[wd] $25, %lo(.got.plt entry)($15)
- 0x09, 0x00, 0x20, 0x03, // jr $25
- 0x00, 0x00, 0xf8, 0x25 // addiu $24, $15, %lo(.got.plt entry)
-};
-
-// LA25 big-endian stub entry
-static const uint8_t mipsBeLA25AtomContent[] = {
- 0x3c, 0x19, 0x00, 0x00, // lui $25, %hi(func)
- 0x08, 0x00, 0x00, 0x00, // j func
- 0x27, 0x39, 0x00, 0x00, // addiu $25, $25, %lo(func)
- 0x00, 0x00, 0x00, 0x00 // nop
-};
-
-// LA25 little-endian stub entry
-static const uint8_t mipsLeLA25AtomContent[] = {
- 0x00, 0x00, 0x19, 0x3c, // lui $25, %hi(func)
- 0x00, 0x00, 0x00, 0x08, // j func
- 0x00, 0x00, 0x39, 0x27, // addiu $25, $25, %lo(func)
- 0x00, 0x00, 0x00, 0x00 // nop
-};
-
-// microMIPS LA25 big-endian stub entry
-static const uint8_t microMipsBeLA25AtomContent[] = {
- 0x41, 0xbe, 0x00, 0x00, // lui $25, %hi(func)
- 0xd4, 0x00, 0x00, 0x00, // j func
- 0x33, 0x39, 0x00, 0x00, // addiu $25, $25, %lo(func)
- 0x00, 0x00, 0x00, 0x00 // nop
-};
-
-// microMIPS LA25 little-endian stub entry
-static const uint8_t microMipsLeLA25AtomContent[] = {
- 0xb9, 0x41, 0x00, 0x00, // lui $25, %hi(func)
- 0x00, 0xd4, 0x00, 0x00, // j func
- 0x39, 0x33, 0x00, 0x00, // addiu $25, $25, %lo(func)
- 0x00, 0x00, 0x00, 0x00 // nop
-};
-
-namespace {
-
-/// \brief Abstract base class represent MIPS GOT entries.
-class MipsGOTAtom : public GOTAtom {
-public:
- MipsGOTAtom(const File &f) : GOTAtom(f, ".got") {}
-
- Alignment alignment() const override { return 4; }
-};
-
-/// \brief MIPS GOT entry initialized by zero.
-template <typename ELFT> class GOT0Atom : public MipsGOTAtom {
-public:
- GOT0Atom(const File &f) : MipsGOTAtom(f) {}
-
- ArrayRef<uint8_t> rawContent() const override;
-};
-
-template <> ArrayRef<uint8_t> GOT0Atom<ELF32BE>::rawContent() const {
- return llvm::makeArrayRef(mipsGot0AtomContent).slice(4);
-}
-template <> ArrayRef<uint8_t> GOT0Atom<ELF32LE>::rawContent() const {
- return llvm::makeArrayRef(mipsGot0AtomContent).slice(4);
-}
-template <> ArrayRef<uint8_t> GOT0Atom<ELF64BE>::rawContent() const {
- return llvm::makeArrayRef(mipsGot0AtomContent);
-}
-template <> ArrayRef<uint8_t> GOT0Atom<ELF64LE>::rawContent() const {
- return llvm::makeArrayRef(mipsGot0AtomContent);
-}
-
-/// \brief MIPS GOT entry initialized by zero.
-template <typename ELFT> class GOTModulePointerAtom : public MipsGOTAtom {
-public:
- GOTModulePointerAtom(const File &f) : MipsGOTAtom(f) {}
-
- ArrayRef<uint8_t> rawContent() const override;
-};
-
-template <>
-ArrayRef<uint8_t> GOTModulePointerAtom<ELF32BE>::rawContent() const {
- return llvm::makeArrayRef(mipsGotModulePointerAtomContent).slice(4);
-}
-template <>
-ArrayRef<uint8_t> GOTModulePointerAtom<ELF32LE>::rawContent() const {
- return llvm::makeArrayRef(mipsGotModulePointerAtomContent).slice(4);
-}
-template <>
-ArrayRef<uint8_t> GOTModulePointerAtom<ELF64BE>::rawContent() const {
- return llvm::makeArrayRef(mipsGotModulePointerAtomContent);
-}
-template <>
-ArrayRef<uint8_t> GOTModulePointerAtom<ELF64LE>::rawContent() const {
- return llvm::makeArrayRef(mipsGotModulePointerAtomContent);
-}
-
-/// \brief MIPS GOT TLS GD entry.
-template <typename ELFT> class GOTTLSGdAtom : public MipsGOTAtom {
-public:
- GOTTLSGdAtom(const File &f) : MipsGOTAtom(f) {}
-
- ArrayRef<uint8_t> rawContent() const override;
-};
-
-template <> ArrayRef<uint8_t> GOTTLSGdAtom<ELF32BE>::rawContent() const {
- return llvm::makeArrayRef(mipsGotTlsGdAtomContent).slice(8);
-}
-template <> ArrayRef<uint8_t> GOTTLSGdAtom<ELF32LE>::rawContent() const {
- return llvm::makeArrayRef(mipsGotTlsGdAtomContent).slice(8);
-}
-template <> ArrayRef<uint8_t> GOTTLSGdAtom<ELF64BE>::rawContent() const {
- return llvm::makeArrayRef(mipsGotTlsGdAtomContent);
-}
-template <> ArrayRef<uint8_t> GOTTLSGdAtom<ELF64LE>::rawContent() const {
- return llvm::makeArrayRef(mipsGotTlsGdAtomContent);
-}
-
-class GOTPLTAtom : public GOTAtom {
-public:
- GOTPLTAtom(const File &f) : GOTAtom(f, ".got.plt") {}
- GOTPLTAtom(const Atom *a, const File &f) : GOTAtom(f, ".got.plt") {
- // Create dynamic relocation to adjust the .got.plt entry at runtime.
- addReferenceELF_Mips(R_MIPS_JUMP_SLOT, 0, a, 0);
- }
-
- /// Setup reference to assign initial value to the .got.plt entry.
- void setPLT0(const PLTAtom *plt0) {
- addReferenceELF_Mips(R_MIPS_32, 0, plt0, 0);
- }
-
- Alignment alignment() const override { return 4; }
-
- ArrayRef<uint8_t> rawContent() const override {
- return llvm::makeArrayRef(mipsGot0AtomContent).slice(4);
- }
-};
-
-template <class ELFT> class PLT0Atom : public PLTAtom {
-public:
- PLT0Atom(const Atom *got, const File &f) : PLTAtom(f, ".plt") {
- // Setup reference to fixup the PLT0 entry.
- addReferenceELF_Mips(R_MIPS_HI16, 0, got, 0);
- addReferenceELF_Mips(R_MIPS_LO16, 4, got, 0);
- addReferenceELF_Mips(R_MIPS_LO16, 8, got, 0);
- }
-
- ArrayRef<uint8_t> rawContent() const override {
- llvm_unreachable("PLT0 is not applicable for this target");
- }
-};
-
-template <> ArrayRef<uint8_t> PLT0Atom<ELF32BE>::rawContent() const {
- return llvm::makeArrayRef(mipsBePlt0AtomContent);
-}
-template <> ArrayRef<uint8_t> PLT0Atom<ELF32LE>::rawContent() const {
- return llvm::makeArrayRef(mipsLePlt0AtomContent);
-}
-
-template <class ELFT> class PLT0N32Atom : public PLTAtom {
-public:
- PLT0N32Atom(const Atom *got, const File &f) : PLTAtom(f, ".plt") {
- // Setup reference to fixup the PLT0 entry.
- addReferenceELF_Mips(R_MIPS_HI16, 0, got, 0);
- addReferenceELF_Mips(R_MIPS_LO16, 4, got, 0);
- addReferenceELF_Mips(R_MIPS_LO16, 8, got, 0);
- }
-
- ArrayRef<uint8_t> rawContent() const override {
- llvm_unreachable("PLT0 is not applicable for this target");
- }
-};
-
-template <> ArrayRef<uint8_t> PLT0N32Atom<ELF32BE>::rawContent() const {
- return llvm::makeArrayRef(mipsN32BePlt0AtomContent);
-}
-template <> ArrayRef<uint8_t> PLT0N32Atom<ELF32LE>::rawContent() const {
- return llvm::makeArrayRef(mipsN32LePlt0AtomContent);
-}
-
-template <class ELFT> class PLT0MicroAtom : public PLTAtom {
-public:
- PLT0MicroAtom(const Atom *got, const File &f) : PLTAtom(f, ".plt") {
- // Setup reference to fixup the PLT0 entry.
- addReferenceELF_Mips(R_MICROMIPS_PC23_S2, 0, got, 0);
- }
-
- CodeModel codeModel() const override { return codeMipsMicro; }
-
- ArrayRef<uint8_t> rawContent() const override {
- llvm_unreachable("PLT0 is not applicable for this target");
- }
-};
-
-template <> ArrayRef<uint8_t> PLT0MicroAtom<ELF32BE>::rawContent() const {
- return llvm::makeArrayRef(microMipsBePlt0AtomContent);
-}
-template <> ArrayRef<uint8_t> PLT0MicroAtom<ELF32LE>::rawContent() const {
- return llvm::makeArrayRef(microMipsLePlt0AtomContent);
-}
-
-class PLTAAtom : public PLTAtom {
-public:
- PLTAAtom(const GOTPLTAtom *got, const File &f) : PLTAtom(f, ".plt") {
- // Setup reference to fixup the PLT entry.
- addReferenceELF_Mips(R_MIPS_HI16, 0, got, 0);
- addReferenceELF_Mips(R_MIPS_LO16, 4, got, 0);
- addReferenceELF_Mips(R_MIPS_LO16, 12, got, 0);
- }
-};
-
-template <class ELFT> class PLTARegAtom : public PLTAAtom {
-public:
- PLTARegAtom(const GOTPLTAtom *got, const File &f) : PLTAAtom(got, f) {}
-
- ArrayRef<uint8_t> rawContent() const override {
- llvm_unreachable("PLT is not applicable for this target");
- }
-};
-
-template <> ArrayRef<uint8_t> PLTARegAtom<ELF32BE>::rawContent() const {
- return llvm::makeArrayRef(mipsBePltAAtomContent);
-}
-template <> ArrayRef<uint8_t> PLTARegAtom<ELF32LE>::rawContent() const {
- return llvm::makeArrayRef(mipsLePltAAtomContent);
-}
-
-template <class ELFT> class PLTR6Atom : public PLTAAtom {
-public:
- PLTR6Atom(const GOTPLTAtom *got, const File &f) : PLTAAtom(got, f) {}
-
- ArrayRef<uint8_t> rawContent() const override {
- llvm_unreachable("PLT is not applicable for this target");
- }
-};
-
-template <> ArrayRef<uint8_t> PLTR6Atom<ELF32BE>::rawContent() const {
- return llvm::makeArrayRef(mipsR6BePltAAtomContent);
-}
-template <> ArrayRef<uint8_t> PLTR6Atom<ELF32LE>::rawContent() const {
- return llvm::makeArrayRef(mipsR6LePltAAtomContent);
-}
-
-template <class ELFT> class PLTMicroAtom : public PLTAtom {
-public:
- PLTMicroAtom(const GOTPLTAtom *got, const File &f) : PLTAtom(f, ".plt") {
- // Setup reference to fixup the microMIPS PLT entry.
- addReferenceELF_Mips(R_MICROMIPS_PC23_S2, 0, got, 0);
- }
-
- Alignment alignment() const override { return 2; }
- CodeModel codeModel() const override { return codeMipsMicro; }
-
- ArrayRef<uint8_t> rawContent() const override {
- llvm_unreachable("PLT is not applicable for this target");
- }
-};
-
-template <> ArrayRef<uint8_t> PLTMicroAtom<ELF32BE>::rawContent() const {
- return llvm::makeArrayRef(microMipsBePltAAtomContent);
-}
-template <> ArrayRef<uint8_t> PLTMicroAtom<ELF32LE>::rawContent() const {
- return llvm::makeArrayRef(microMipsLePltAAtomContent);
-}
-
-class LA25Atom : public PLTAtom {
-public:
- LA25Atom(const File &f) : PLTAtom(f, ".text") {}
-};
-
-template <typename ELFT> class LA25RegAtom : public LA25Atom {
-public:
- LA25RegAtom(const Atom *a, const File &f) : LA25Atom(f) {
- // Setup reference to fixup the LA25 stub entry.
- addReferenceELF_Mips(R_MIPS_HI16, 0, a, 0);
- addReferenceELF_Mips(R_MIPS_26, 4, a, 0);
- addReferenceELF_Mips(R_MIPS_LO16, 8, a, 0);
- }
-
- ArrayRef<uint8_t> rawContent() const override {
- llvm_unreachable("LA25 stubs are not applicable for this target");
- }
-};
-
-template <> ArrayRef<uint8_t> LA25RegAtom<ELF32BE>::rawContent() const {
- return llvm::makeArrayRef(mipsBeLA25AtomContent);
-}
-template <> ArrayRef<uint8_t> LA25RegAtom<ELF32LE>::rawContent() const {
- return llvm::makeArrayRef(mipsLeLA25AtomContent);
-}
-
-template <typename ELFT> class LA25MicroAtom : public LA25Atom {
-public:
- LA25MicroAtom(const Atom *a, const File &f) : LA25Atom(f) {
- // Setup reference to fixup the microMIPS LA25 stub entry.
- addReferenceELF_Mips(R_MICROMIPS_HI16, 0, a, 0);
- addReferenceELF_Mips(R_MICROMIPS_26_S1, 4, a, 0);
- addReferenceELF_Mips(R_MICROMIPS_LO16, 8, a, 0);
- }
-
- CodeModel codeModel() const override { return codeMipsMicro; }
-
- ArrayRef<uint8_t> rawContent() const override {
- llvm_unreachable("LA25 stubs are not applicable for this target");
- }
-};
-
-template <> ArrayRef<uint8_t> LA25MicroAtom<ELF32BE>::rawContent() const {
- return llvm::makeArrayRef(microMipsBeLA25AtomContent);
-}
-template <> ArrayRef<uint8_t> LA25MicroAtom<ELF32LE>::rawContent() const {
- return llvm::makeArrayRef(microMipsLeLA25AtomContent);
-}
-
-class MipsGlobalOffsetTableAtom : public GlobalOffsetTableAtom {
-public:
- MipsGlobalOffsetTableAtom(const File &f) : GlobalOffsetTableAtom(f) {}
-
- StringRef customSectionName() const override { return ".got"; }
-};
-
-template <typename ELFT> class MipsRldAtom : public SimpleELFDefinedAtom {
-public:
- MipsRldAtom(const File &f) : SimpleELFDefinedAtom(f) {}
-
- Scope scope() const override { return scopeGlobal; }
- SectionChoice sectionChoice() const override { return sectionCustomRequired; }
- StringRef customSectionName() const override { return ".rld_map"; }
- ContentType contentType() const override { return typeData; }
- uint64_t size() const override { return rawContent().size(); }
- ContentPermissions permissions() const override { return permRW_; }
- Alignment alignment() const override { return rawContent().size(); }
- StringRef name() const override { return "__RLD_MAP"; }
- ArrayRef<uint8_t> rawContent() const override {
- return llvm::makeArrayRef(mipsGot0AtomContent)
- .slice(ELFT::Is64Bits ? 0 : 4);
- }
-};
-
-class RelocationPassFile : public SimpleFile {
-public:
- RelocationPassFile(const ELFLinkingContext &ctx)
- : SimpleFile("RelocationPassFile") {
- setOrdinal(ctx.getNextOrdinalAndIncrement());
- }
-
- llvm::BumpPtrAllocator _alloc;
-};
-
-template <typename ELFT> class RelocationPass : public Pass {
-public:
- RelocationPass(MipsLinkingContext &ctx);
-
- std::error_code perform(SimpleFile &mf) override;
-
-private:
- /// \brief Reference to the linking context.
- const MipsLinkingContext &_ctx;
-
- /// \brief Owner of all the Atoms created by this pass.
- RelocationPassFile _file;
-
- /// \brief Map Atoms and addend to local GOT entries.
- typedef std::pair<const Atom *, int64_t> LocalGotMapKeyT;
- llvm::DenseMap<LocalGotMapKeyT, GOTAtom *> _gotLocalMap;
- llvm::DenseMap<LocalGotMapKeyT, GOTAtom *> _gotLocalPageMap;
-
- /// \brief Map Atoms to global GOT entries.
- llvm::DenseMap<const Atom *, GOTAtom *> _gotGlobalMap;
-
- /// \brief Map Atoms to TLS GOT entries.
- llvm::DenseMap<const Atom *, GOTAtom *> _gotTLSMap;
-
- /// \brief Map Atoms to TLS GD GOT entries.
- llvm::DenseMap<const Atom *, GOTAtom *> _gotTLSGdMap;
-
- /// \brief GOT entry for the R_xxxMIPS_TLS_LDM relocations.
- GOTTLSGdAtom<ELFT> *_gotLDMEntry = nullptr;
-
- /// \brief the list of local GOT atoms.
- std::vector<GOTAtom *> _localGotVector;
-
- /// \brief the list of global GOT atoms.
- std::vector<GOTAtom *> _globalGotVector;
-
- /// \brief the list of TLS GOT atoms.
- std::vector<GOTAtom *> _tlsGotVector;
-
- /// \brief Map Atoms to their GOTPLT entries.
- llvm::DenseMap<const Atom *, GOTPLTAtom *> _gotpltMap;
-
- /// \brief Map Atoms to their PLT entries.
- llvm::DenseMap<const Atom *, PLTAAtom *> _pltRegMap;
- llvm::DenseMap<const Atom *, PLTMicroAtom<ELFT> *> _pltMicroMap;
-
- /// \brief Map Atoms to their Object entries.
- llvm::DenseMap<const Atom *, ObjectAtom *> _objectMap;
-
- /// \brief Map Atoms to their LA25 entries.
- llvm::DenseMap<const Atom *, LA25Atom *> _la25RegMap;
- llvm::DenseMap<const Atom *, LA25Atom *> _la25MicroMap;
-
- /// \brief Atoms referenced by static relocations.
- llvm::DenseSet<const Atom *> _hasStaticRelocations;
-
- /// \brief Atoms require pointers equality.
- llvm::DenseSet<const Atom *> _requiresPtrEquality;
-
- /// \brief References which are candidates for converting
- /// to the R_MIPS_REL32 relocation.
- std::vector<Reference *> _rel32Candidates;
-
- /// \brief the list of PLT atoms.
- std::vector<PLTAtom *> _pltRegVector;
- std::vector<PLTAtom *> _pltMicroVector;
-
- /// \brief the list of GOTPLT atoms.
- std::vector<GOTPLTAtom *> _gotpltVector;
-
- /// \brief the list of Object entries.
- std::vector<ObjectAtom *> _objectVector;
-
- /// \brief the list of LA25 entries.
- std::vector<LA25Atom *> _la25Vector;
-
- /// \brief Handle a specific reference.
- void handleReference(const MipsELFDefinedAtom<ELFT> &atom, Reference &ref);
-
- /// \brief Collect information about the reference to use it
- /// later in the handleReference() routine.
- std::error_code collectReferenceInfo(const MipsELFDefinedAtom<ELFT> &atom,
- Reference &ref);
-
- /// \brief Check that the relocation is valid for the current linking mode.
- std::error_code validateRelocation(const DefinedAtom &atom,
- const Reference &ref) const;
-
- void handlePlain(const MipsELFDefinedAtom<ELFT> &atom, Reference &ref);
- void handleBranch(const MipsELFDefinedAtom<ELFT> &atom, Reference &ref);
- void handleGOT(Reference &ref);
-
- const GOTAtom *getLocalGOTEntry(const Reference &ref);
- const GOTAtom *getLocalGOTPageEntry(const Reference &ref);
- const GOTAtom *getGlobalGOTEntry(const Atom *a);
- const GOTAtom *getTLSGOTEntry(const Atom *a, Reference::Addend addend);
- const GOTAtom *getTLSGdGOTEntry(const Atom *a, Reference::Addend addend);
- const GOTAtom *getTLSLdmGOTEntry(const Atom *a);
- const GOTPLTAtom *getGOTPLTEntry(const Atom *a);
- const PLTAtom *getPLTEntry(const Atom *a);
- const PLTAtom *getPLTRegEntry(const Atom *a);
- const PLTAtom *getPLTMicroEntry(const Atom *a);
- const LA25Atom *getLA25RegEntry(const Atom *a);
- const LA25Atom *getLA25MicroEntry(const Atom *a);
- const ObjectAtom *getObjectEntry(const SharedLibraryAtom *a);
-
- PLTAtom *createPLTHeader(bool isMicroMips);
-
- bool isLocal(const Atom *a) const;
- bool isLocalCall(const Atom *a) const;
- bool isDynamic(const Atom *atom) const;
- bool requireLA25Stub(const MipsELFDefinedAtom<ELFT> &atom,
- const Reference &ref) const;
- bool requirePLTEntry(const Atom *a) const;
- bool requireCopy(const Atom *a) const;
- bool mightBeDynamic(const MipsELFDefinedAtom<ELFT> &atom,
- Reference::KindValue refKind) const;
- bool hasPLTEntry(const Atom *atom) const;
-
- /// \brief Linked files contain microMIPS code.
- bool isMicroMips();
- /// \brief Linked files contain MIPS R6 code.
- bool isMipsR6();
-};
-
-template <typename ELFT>
-RelocationPass<ELFT>::RelocationPass(MipsLinkingContext &ctx)
- : _ctx(ctx), _file(ctx) {
- _localGotVector.push_back(new (_file._alloc) GOT0Atom<ELFT>(_file));
- _localGotVector.push_back(new (_file._alloc)
- GOTModulePointerAtom<ELFT>(_file));
-}
-
-template <typename ELFT>
-std::error_code RelocationPass<ELFT>::perform(SimpleFile &mf) {
- for (const auto &atom : mf.defined())
- for (const auto &ref : *atom) {
- const auto &da = *cast<MipsELFDefinedAtom<ELFT>>(atom);
- if (auto ec = collectReferenceInfo(da, const_cast<Reference &>(*ref)))
- return ec;
- }
-
- // Process all references.
- for (const auto &atom : mf.defined())
- for (const auto &ref : *atom)
- handleReference(*cast<MipsELFDefinedAtom<ELFT>>(atom),
- const_cast<Reference &>(*ref));
-
- // Create R_MIPS_REL32 relocations.
- for (auto *ref : _rel32Candidates) {
- bool forceRel = isLocal(ref->target()) && _ctx.getOutputELFType() == ET_DYN;
- if (!forceRel && (!isDynamic(ref->target()) || hasPLTEntry(ref->target())))
- continue;
- ref->setKindValue(R_MIPS_REL32);
- if (ELFT::Is64Bits)
- static_cast<MipsELFReference<ELFT> *>(ref)->setTag(R_MIPS_64);
- if (!isLocalCall(ref->target()))
- getGlobalGOTEntry(ref->target());
- }
-
- uint64_t ordinal = 0;
-
- if (_ctx.isDynamic() && _ctx.getOutputELFType() == ET_EXEC) {
- auto rlda = new (_file._alloc) MipsRldAtom<ELFT>(_file);
- rlda->setOrdinal(ordinal++);
- mf.addAtom(*rlda);
- }
-
- if (!_localGotVector.empty() || !_globalGotVector.empty() ||
- !_tlsGotVector.empty()) {
- SimpleDefinedAtom *ga = new (_file._alloc) MipsGlobalOffsetTableAtom(_file);
- ga->setOrdinal(ordinal++);
- mf.addAtom(*ga);
- }
-
- for (auto &got : _localGotVector) {
- got->setOrdinal(ordinal++);
- mf.addAtom(*got);
- }
-
- for (auto &got : _globalGotVector) {
- got->setOrdinal(ordinal++);
- mf.addAtom(*got);
- }
-
- for (auto &got : _tlsGotVector) {
- got->setOrdinal(ordinal++);
- mf.addAtom(*got);
- }
-
- // Create and emit PLT0 entry.
- PLTAtom *plt0Atom = nullptr;
- if (!_pltRegVector.empty())
- plt0Atom = createPLTHeader(false);
- else if (!_pltMicroVector.empty())
- plt0Atom = createPLTHeader(true);
-
- if (plt0Atom) {
- plt0Atom->setOrdinal(ordinal++);
- mf.addAtom(*plt0Atom);
- }
-
- // Emit regular PLT entries firts.
- for (auto &plt : _pltRegVector) {
- plt->setOrdinal(ordinal++);
- mf.addAtom(*plt);
- }
-
- // microMIPS PLT entries come after regular ones.
- for (auto &plt : _pltMicroVector) {
- plt->setOrdinal(ordinal++);
- mf.addAtom(*plt);
- }
-
- // Assign PLT0 to GOTPLT entries.
- assert(_gotpltMap.empty() || plt0Atom);
- for (auto &a: _gotpltMap)
- a.second->setPLT0(plt0Atom);
-
- for (auto &gotplt : _gotpltVector) {
- gotplt->setOrdinal(ordinal++);
- mf.addAtom(*gotplt);
- }
-
- for (auto obj : _objectVector) {
- obj->setOrdinal(ordinal++);
- mf.addAtom(*obj);
- }
-
- for (auto la25 : _la25Vector) {
- la25->setOrdinal(ordinal++);
- mf.addAtom(*la25);
- }
-
- return std::error_code();
-}
-
-static bool isMicroMipsReloc(Reference::KindValue kind) {
- return R_MICROMIPS_26_S1 <= kind && kind <= R_MICROMIPS_PC19_S2;
-}
-
-static bool isHiLo16Reloc(Reference::KindValue kind) {
- return kind == R_MIPS_HI16 || kind == R_MIPS_LO16 || kind == R_MIPS_PCHI16 ||
- kind == R_MIPS_PCLO16 || kind == R_MICROMIPS_HI16 ||
- kind == R_MICROMIPS_LO16 || kind == R_MICROMIPS_HI0_LO16;
-}
-
-static bool isBranchReloc(Reference::KindValue kind) {
- return kind == R_MIPS_26 || kind == R_MICROMIPS_26_S1 ||
- kind == R_MIPS_PC16 || kind == R_MIPS_PC21_S2 ||
- kind == R_MIPS_PC26_S2 || kind == R_MICROMIPS_PC7_S1 ||
- kind == R_MICROMIPS_PC10_S1 || kind == R_MICROMIPS_PC16_S1 ||
- kind == R_MICROMIPS_PC23_S2;
-}
-
-static bool isGotReloc(Reference::KindValue kind) {
- return kind == R_MIPS_GOT16 || kind == R_MICROMIPS_GOT16;
-}
-
-static bool isAllGotReloc(Reference::KindValue kind) {
- return isGotReloc(kind) || kind == R_MIPS_GOT_HI16 ||
- kind == R_MIPS_GOT_LO16 || kind == R_MICROMIPS_GOT_HI16 ||
- kind == R_MICROMIPS_GOT_LO16;
-}
-
-static bool isCallReloc(Reference::KindValue kind) {
- return kind == R_MIPS_CALL16 || kind == R_MICROMIPS_CALL16;
-}
-
-static bool isAllCallReloc(Reference::KindValue kind) {
- return isCallReloc(kind) || kind == R_MIPS_CALL_HI16 ||
- kind == R_MIPS_CALL_LO16 || kind == R_MICROMIPS_CALL_HI16 ||
- kind == R_MICROMIPS_CALL_LO16;
-}
-
-static bool isGotDispReloc(Reference::KindValue kind) {
- return kind == R_MIPS_GOT_DISP || kind == R_MICROMIPS_GOT_DISP;
-}
-
-static bool isGotPageReloc(Reference::KindValue kind) {
- return kind == R_MIPS_GOT_PAGE || kind == R_MICROMIPS_GOT_PAGE;
-}
-
-static bool isTlsDtpReloc(Reference::KindValue kind) {
- return kind == R_MIPS_TLS_DTPREL_HI16 || kind == R_MIPS_TLS_DTPREL_LO16 ||
- kind == R_MICROMIPS_TLS_DTPREL_HI16 ||
- kind == R_MICROMIPS_TLS_DTPREL_LO16;
-}
-
-static bool isTlsTpReloc(Reference::KindValue kind) {
- return kind == R_MIPS_TLS_TPREL_HI16 || kind == R_MIPS_TLS_TPREL_LO16 ||
- kind == R_MICROMIPS_TLS_TPREL_HI16 ||
- kind == R_MICROMIPS_TLS_TPREL_LO16;
-}
-
-static bool isTlsGdReloc(Reference::KindValue kind) {
- return kind == R_MIPS_TLS_GD || kind == R_MICROMIPS_TLS_GD;
-}
-
-static bool isTlsLdmReloc(Reference::KindValue kind) {
- return kind == R_MIPS_TLS_LDM || kind == R_MICROMIPS_TLS_LDM;
-}
-
-static bool isTlsGotTpReloc(Reference::KindValue kind) {
- return kind == R_MIPS_TLS_GOTTPREL || kind == R_MICROMIPS_TLS_GOTTPREL;
-}
-
-static bool isGpRelReloc(Reference::KindValue kind) {
- return kind == R_MIPS_GPREL32 || kind == R_MIPS_GPREL16 ||
- kind == R_MICROMIPS_GPREL16 || kind == R_MICROMIPS_GPREL7_S2 ||
- kind == R_MIPS_LITERAL || kind == R_MICROMIPS_LITERAL;
-}
-
-template <typename ELFT>
-void RelocationPass<ELFT>::handleReference(const MipsELFDefinedAtom<ELFT> &atom,
- Reference &ref) {
- if (!ref.target())
- return;
- if (ref.kindNamespace() != Reference::KindNamespace::ELF)
- return;
-
- assert(ref.kindArch() == Reference::KindArch::Mips);
- Reference::KindValue kind = ref.kindValue();
- if (isHiLo16Reloc(kind) || kind == R_MIPS_32 || kind == R_MIPS_PC32)
- handlePlain(atom, ref);
- else if (isBranchReloc(kind))
- handleBranch(atom, ref);
- else if (isAllGotReloc(kind) || isAllCallReloc(kind) ||
- isGotDispReloc(kind) || isGotPageReloc(kind) || kind == R_MIPS_EH)
- handleGOT(ref);
- else if (isTlsDtpReloc(kind))
- ref.setAddend(ref.addend() - atom.file().getDTPOffset());
- else if (isTlsTpReloc(kind))
- ref.setAddend(ref.addend() - atom.file().getTPOffset());
- else if (isTlsGdReloc(kind))
- ref.setTarget(getTLSGdGOTEntry(ref.target(), ref.addend()));
- else if (isTlsLdmReloc(kind))
- ref.setTarget(getTLSLdmGOTEntry(ref.target()));
- else if (isTlsGotTpReloc(kind))
- ref.setTarget(getTLSGOTEntry(ref.target(), ref.addend()));
- else if (kind == R_MIPS_GPREL32 || (isLocal(ref.target()) && isGpRelReloc(kind)))
- ref.setAddend(ref.addend() + atom.file().getGP0());
- else if (kind == R_MIPS_JALR) {
- if (_ctx.getOutputELFType() != ET_EXEC || !isLocalCall(ref.target()))
- ref.setKindValue(R_MIPS_NONE);
- }
-}
-
-template <typename ELFT>
-static bool isConstrainSym(const MipsELFDefinedAtom<ELFT> &atom,
- Reference::KindValue refKind) {
- if ((atom.section()->sh_flags & SHF_ALLOC) == 0)
- return false;
- switch (refKind) {
- case R_MIPS_NONE:
- case R_MIPS_JALR:
- case R_MICROMIPS_JALR:
- case R_MIPS_GPREL16:
- case R_MIPS_GPREL32:
- case R_MICROMIPS_GPREL16:
- case R_MICROMIPS_GPREL7_S2:
- case R_MIPS_LITERAL:
- case R_MICROMIPS_LITERAL:
- return false;
- default:
- return true;
- }
-}
-
-template <typename ELFT>
-std::error_code
-RelocationPass<ELFT>::collectReferenceInfo(const MipsELFDefinedAtom<ELFT> &atom,
- Reference &ref) {
- if (!ref.target())
- return std::error_code();
- if (ref.kindNamespace() != Reference::KindNamespace::ELF)
- return std::error_code();
-
- auto refKind = ref.kindValue();
- if (refKind == R_MIPS_EH && this->_ctx.mipsPcRelEhRel())
- ref.setKindValue(R_MIPS_PC32);
-
- if (auto ec = validateRelocation(atom, ref))
- return ec;
-
- if (!isConstrainSym(atom, refKind))
- return std::error_code();
-
- if (!mightBeDynamic(atom, refKind))
- _hasStaticRelocations.insert(ref.target());
- else if (refKind == R_MIPS_32 || refKind == R_MIPS_64)
- _rel32Candidates.push_back(&ref);
-
- if (!isBranchReloc(refKind) && !isAllCallReloc(refKind) &&
- refKind != R_MIPS_EH)
- _requiresPtrEquality.insert(ref.target());
-
- return std::error_code();
-}
-
-static std::error_code
-make_reject_for_shared_lib_reloc_error(const ELFLinkingContext &ctx,
- const DefinedAtom &atom,
- const Reference &ref) {
- StringRef kindValStr = "unknown";
- ctx.registry().referenceKindToString(ref.kindNamespace(), ref.kindArch(),
- ref.kindValue(), kindValStr);
-
- return make_dynamic_error_code(Twine(kindValStr) + " (" +
- Twine(ref.kindValue()) +
- ") relocation cannot be used "
- "when making a shared object, recompile " +
- atom.file().path() + " with -fPIC");
-}
-
-static std::error_code
-make_local_call16_reloc_error(const ELFLinkingContext &ctx,
- const DefinedAtom &atom, const Reference &ref) {
- return make_dynamic_error_code("R_MIPS_CALL16 (11) relocation cannot be used "
- "against local symbol " +
- ref.target()->name() + " in file " +
- atom.file().path());
-}
-
-template <typename ELFT>
-std::error_code
-RelocationPass<ELFT>::validateRelocation(const DefinedAtom &atom,
- const Reference &ref) const {
- if (!ref.target())
- return std::error_code();
-
- if (isCallReloc(ref.kindValue()) && isLocal(ref.target()))
- return make_local_call16_reloc_error(this->_ctx, atom, ref);
-
- if (this->_ctx.getOutputELFType() != ET_DYN)
- return std::error_code();
-
- switch (ref.kindValue()) {
- case R_MIPS16_HI16:
- case R_MIPS_HI16:
- case R_MIPS_HIGHER:
- case R_MIPS_HIGHEST:
- case R_MICROMIPS_HI16:
- case R_MICROMIPS_HIGHER:
- case R_MICROMIPS_HIGHEST:
- // For shared object we accepts "high" relocations
- // against the "_gp_disp" symbol only.
- if (ref.target()->name() != "_gp_disp")
- return make_reject_for_shared_lib_reloc_error(this->_ctx, atom, ref);
- break;
- case R_MIPS16_26:
- case R_MIPS_26:
- case R_MICROMIPS_26_S1:
- // These relocations are position dependent
- // and not acceptable in a shared object.
- return make_reject_for_shared_lib_reloc_error(this->_ctx, atom, ref);
- default:
- break;
- }
- return std::error_code();
-}
-
-template <typename ELFT>
-bool RelocationPass<ELFT>::isLocal(const Atom *a) const {
- if (auto *da = dyn_cast<DefinedAtom>(a))
- return da->scope() == Atom::scopeTranslationUnit;
- return false;
-}
-
-template <typename ELFT>
-static bool isMipsReadonly(const MipsELFDefinedAtom<ELFT> &atom) {
- auto secFlags = atom.section()->sh_flags;
- auto secType = atom.section()->sh_type;
-
- if ((secFlags & SHF_ALLOC) == 0)
- return false;
- if (secType == SHT_NOBITS)
- return false;
- if ((secFlags & SHF_WRITE) != 0)
- return false;
- return true;
-}
-
-template <typename ELFT>
-bool RelocationPass<ELFT>::mightBeDynamic(const MipsELFDefinedAtom<ELFT> &atom,
- Reference::KindValue refKind) const {
- if (isAllGotReloc(refKind) || isAllCallReloc(refKind))
- return true;
-
- if (refKind != R_MIPS_32 && refKind != R_MIPS_64)
- return false;
- if ((atom.section()->sh_flags & SHF_ALLOC) == 0)
- return false;
-
- if (_ctx.getOutputELFType() == ET_DYN)
- return true;
- if (!isMipsReadonly(atom))
- return true;
- if (atom.isPIC())
- return true;
-
- return false;
-}
-
-template <typename ELFT>
-bool RelocationPass<ELFT>::hasPLTEntry(const Atom *atom) const {
- return _pltRegMap.count(atom) || _pltMicroMap.count(atom);
-}
-
-template <typename ELFT> bool RelocationPass<ELFT>::isMicroMips() {
- TargetHandler &handler = this->_ctx.getTargetHandler();
- return static_cast<MipsTargetHandler<ELFT> &>(handler)
- .getAbiInfoHandler()
- .isMicroMips();
-}
-
-template <typename ELFT> bool RelocationPass<ELFT>::isMipsR6() {
- TargetHandler &handler = this->_ctx.getTargetHandler();
- return static_cast<MipsTargetHandler<ELFT> &>(handler)
- .getAbiInfoHandler()
- .isMipsR6();
-}
-
-template <typename ELFT>
-bool RelocationPass<ELFT>::requirePLTEntry(const Atom *a) const {
- if (!_hasStaticRelocations.count(a))
- return false;
- const auto *sa = dyn_cast<ELFDynamicAtom<ELFT>>(a);
- if (sa && sa->type() != SharedLibraryAtom::Type::Code)
- return false;
- const auto *da = dyn_cast<ELFDefinedAtom<ELFT>>(a);
- if (da && da->contentType() != DefinedAtom::typeCode)
- return false;
- if (isLocalCall(a))
- return false;
- return true;
-}
-
-template <typename ELFT>
-bool RelocationPass<ELFT>::requireCopy(const Atom *a) const {
- if (!_hasStaticRelocations.count(a))
- return false;
- const auto *sa = dyn_cast<ELFDynamicAtom<ELFT>>(a);
- return sa && sa->type() == SharedLibraryAtom::Type::Data;
-}
-
-template <typename ELFT>
-bool RelocationPass<ELFT>::isDynamic(const Atom *atom) const {
- const auto *da = dyn_cast<const DefinedAtom>(atom);
- if (da && da->dynamicExport() == DefinedAtom::dynamicExportAlways)
- return true;
- if (isa<SharedLibraryAtom>(atom))
- return true;
- if (_ctx.getOutputELFType() != ET_DYN)
- return false;
- if (da && da->scope() != DefinedAtom::scopeTranslationUnit)
- return true;
- return isa<UndefinedAtom>(atom);
-}
-
-template <typename ELFT>
-static bool isMicroMips(const MipsELFDefinedAtom<ELFT> &atom) {
- return atom.codeModel() == DefinedAtom::codeMipsMicro ||
- atom.codeModel() == DefinedAtom::codeMipsMicroPIC;
-}
-
-template <typename ELFT>
-const PLTAtom *RelocationPass<ELFT>::getPLTEntry(const Atom *a) {
- // If file contains microMIPS code try to reuse compressed PLT entry...
- if (isMicroMips()) {
- auto microPLT = _pltMicroMap.find(a);
- if (microPLT != _pltMicroMap.end())
- return microPLT->second;
- }
-
- // ... then try to reuse a regular PLT entry ...
- auto regPLT = _pltRegMap.find(a);
- if (regPLT != _pltRegMap.end())
- return regPLT->second;
-
- // ... and finally prefer to create new compressed PLT entry.
- return isMicroMips() ? getPLTMicroEntry(a) : getPLTRegEntry(a);
-}
-
-template <typename ELFT>
-void RelocationPass<ELFT>::handlePlain(const MipsELFDefinedAtom<ELFT> &atom,
- Reference &ref) {
- if (!isDynamic(ref.target()))
- return;
-
- if (requirePLTEntry(ref.target()))
- ref.setTarget(getPLTEntry(ref.target()));
- else if (requireCopy(ref.target()))
- ref.setTarget(getObjectEntry(cast<SharedLibraryAtom>(ref.target())));
-}
-
-template <typename ELFT>
-void RelocationPass<ELFT>::handleBranch(const MipsELFDefinedAtom<ELFT> &atom,
- Reference &ref) {
- bool isMicro = isMicroMipsReloc(ref.kindValue());
- if (const auto *sla = dyn_cast<SharedLibraryAtom>(ref.target())) {
- if (sla->type() == SharedLibraryAtom::Type::Code)
- ref.setTarget(isMicro ? getPLTMicroEntry(sla) : getPLTRegEntry(sla));
- } else if (requireLA25Stub(atom, ref)) {
- if (isMicro)
- ref.setTarget(getLA25MicroEntry(ref.target()));
- else
- ref.setTarget(getLA25RegEntry(ref.target()));
- }
-
- if (!isLocal(ref.target())) {
- if (ref.kindValue() == R_MICROMIPS_26_S1)
- ref.setKindValue(LLD_R_MICROMIPS_GLOBAL_26_S1);
- else if (ref.kindValue() == R_MIPS_26)
- ref.setKindValue(LLD_R_MIPS_GLOBAL_26);
- }
-}
-
-template <typename ELFT> void RelocationPass<ELFT>::handleGOT(Reference &ref) {
- if (!isLocalCall(ref.target()))
- ref.setTarget(getGlobalGOTEntry(ref.target()));
- else if (isGotPageReloc(ref.kindValue()))
- ref.setTarget(getLocalGOTPageEntry(ref));
- else if (isLocal(ref.target()) &&
- (isCallReloc(ref.kindValue()) || isGotReloc(ref.kindValue())))
- ref.setTarget(getLocalGOTPageEntry(ref));
- else
- ref.setTarget(getLocalGOTEntry(ref));
-}
-
-template <typename ELFT>
-bool RelocationPass<ELFT>::isLocalCall(const Atom *a) const {
- Atom::Scope scope;
- if (auto *da = dyn_cast<DefinedAtom>(a))
- scope = da->scope();
- else if (auto *aa = dyn_cast<AbsoluteAtom>(a))
- scope = aa->scope();
- else
- return false;
-
- // Local and hidden symbols must be local.
- if (scope == Atom::scopeTranslationUnit || scope == Atom::scopeLinkageUnit)
- return true;
-
- // Calls to external symbols defined in an executable file resolved locally.
- if (_ctx.getOutputELFType() == ET_EXEC)
- return true;
-
- return false;
-}
-
-template <typename ELFT>
-bool RelocationPass<ELFT>::requireLA25Stub(const MipsELFDefinedAtom<ELFT> &atom,
- const Reference &ref) const {
- if (atom.file().isPIC())
- return false;
- if (auto *da = dyn_cast<DefinedAtom>(ref.target()))
- return static_cast<const MipsELFDefinedAtom<ELFT> *>(da)->isPIC();
- return false;
-}
-
-template <typename ELFT>
-const GOTAtom *RelocationPass<ELFT>::getLocalGOTEntry(const Reference &ref) {
- const Atom *a = ref.target();
- LocalGotMapKeyT key(a, ref.addend());
-
- auto got = _gotLocalMap.find(key);
- if (got != _gotLocalMap.end())
- return got->second;
-
- auto ga = new (_file._alloc) GOT0Atom<ELFT>(_file);
- _gotLocalMap[key] = ga;
-
- _localGotVector.push_back(ga);
-
- Reference::KindValue relKind = ELFT::Is64Bits ? R_MIPS_64 : R_MIPS_32;
- ga->addReferenceELF_Mips(relKind, 0, a, 0);
-
- return ga;
-}
-
-template <typename ELFT>
-const GOTAtom *
-RelocationPass<ELFT>::getLocalGOTPageEntry(const Reference &ref) {
- const Atom *a = ref.target();
- LocalGotMapKeyT key(a, ref.addend());
-
- auto got = _gotLocalPageMap.find(key);
- if (got != _gotLocalPageMap.end())
- return got->second;
-
- auto ga = new (_file._alloc) GOT0Atom<ELFT>(_file);
- _gotLocalPageMap[key] = ga;
-
- _localGotVector.push_back(ga);
-
- Reference::KindValue relKind =
- ELFT::Is64Bits ? LLD_R_MIPS_64_HI16 : LLD_R_MIPS_32_HI16;
- ga->addReferenceELF_Mips(relKind, 0, a, ref.addend());
-
- return ga;
-}
-
-template <typename ELFT>
-const GOTAtom *RelocationPass<ELFT>::getGlobalGOTEntry(const Atom *a) {
- auto got = _gotGlobalMap.find(a);
- if (got != _gotGlobalMap.end())
- return got->second;
-
- auto ga = new (_file._alloc) GOT0Atom<ELFT>(_file);
- _gotGlobalMap[a] = ga;
-
- _globalGotVector.push_back(ga);
- ga->addReferenceELF_Mips(LLD_R_MIPS_GLOBAL_GOT, 0, a, 0);
-
- if (const DefinedAtom *da = dyn_cast<DefinedAtom>(a))
- ga->addReferenceELF_Mips(R_MIPS_32, 0, da, 0);
-
- return ga;
-}
-
-template <typename ELFT>
-const GOTAtom *RelocationPass<ELFT>::getTLSGOTEntry(const Atom *a,
- Reference::Addend addend) {
- auto got = _gotTLSMap.find(a);
- if (got != _gotTLSMap.end())
- return got->second;
-
- auto ga = new (_file._alloc) GOT0Atom<ELFT>(_file);
- _gotTLSMap[a] = ga;
-
- _tlsGotVector.push_back(ga);
- Reference::KindValue relKind =
- ELFT::Is64Bits ? R_MIPS_TLS_TPREL64 : R_MIPS_TLS_TPREL32;
- ga->addReferenceELF_Mips(relKind, 0, a, addend);
-
- return ga;
-}
-
-template <typename ELFT>
-const GOTAtom *
-RelocationPass<ELFT>::getTLSGdGOTEntry(const Atom *a,
- Reference::Addend addend) {
- auto got = _gotTLSGdMap.find(a);
- if (got != _gotTLSGdMap.end())
- return got->second;
-
- auto ga = new (_file._alloc) GOTTLSGdAtom<ELFT>(_file);
- _gotTLSGdMap[a] = ga;
-
- _tlsGotVector.push_back(ga);
- if (ELFT::Is64Bits) {
- ga->addReferenceELF_Mips(R_MIPS_TLS_DTPMOD64, 0, a, addend);
- ga->addReferenceELF_Mips(R_MIPS_TLS_DTPREL64, 8, a, addend);
- } else {
- ga->addReferenceELF_Mips(R_MIPS_TLS_DTPMOD32, 0, a, addend);
- ga->addReferenceELF_Mips(R_MIPS_TLS_DTPREL32, 4, a, addend);
- }
-
- return ga;
-}
-
-template <typename ELFT>
-const GOTAtom *RelocationPass<ELFT>::getTLSLdmGOTEntry(const Atom *a) {
- if (_gotLDMEntry)
- return _gotLDMEntry;
-
- _gotLDMEntry = new (_file._alloc) GOTTLSGdAtom<ELFT>(_file);
- _tlsGotVector.push_back(_gotLDMEntry);
- if (ELFT::Is64Bits)
- _gotLDMEntry->addReferenceELF_Mips(R_MIPS_TLS_DTPMOD64, 0, _gotLDMEntry, 0);
- else
- _gotLDMEntry->addReferenceELF_Mips(R_MIPS_TLS_DTPMOD32, 0, _gotLDMEntry, 0);
-
- return _gotLDMEntry;
-}
-
-template <typename ELFT>
-PLTAtom *RelocationPass<ELFT>::createPLTHeader(bool isMicroMips) {
- auto ga1 = new (_file._alloc) GOTPLTAtom(_file);
- _gotpltVector.insert(_gotpltVector.begin(), ga1);
- auto ga0 = new (_file._alloc) GOTPLTAtom(_file);
- _gotpltVector.insert(_gotpltVector.begin(), ga0);
-
- if (isMicroMips)
- return new (_file._alloc) PLT0MicroAtom<ELFT>(ga0, _file);
- if (_ctx.getAbi() == MipsAbi::N32)
- return new (_file._alloc) PLT0N32Atom<ELFT>(ga0, _file);
- return new (_file._alloc) PLT0Atom<ELFT>(ga0, _file);
-}
-
-template <typename ELFT>
-const GOTPLTAtom *RelocationPass<ELFT>::getGOTPLTEntry(const Atom *a) {
- auto it = _gotpltMap.find(a);
- if (it != _gotpltMap.end())
- return it->second;
-
- auto ga = new (_file._alloc) GOTPLTAtom(a, _file);
- _gotpltMap[a] = ga;
- _gotpltVector.push_back(ga);
- return ga;
-}
-
-template <typename ELFT>
-const PLTAtom *RelocationPass<ELFT>::getPLTRegEntry(const Atom *a) {
- auto plt = _pltRegMap.find(a);
- if (plt != _pltRegMap.end())
- return plt->second;
-
- PLTAAtom *pa = nullptr;
- if (isMipsR6())
- pa = new (_file._alloc) PLTR6Atom<ELFT>(getGOTPLTEntry(a), _file);
- else
- pa = new (_file._alloc) PLTARegAtom<ELFT>(getGOTPLTEntry(a), _file);
- _pltRegMap[a] = pa;
- _pltRegVector.push_back(pa);
-
- // Check that 'a' dynamic symbol table record should point to the PLT.
- if (_hasStaticRelocations.count(a) && _requiresPtrEquality.count(a))
- pa->addReferenceELF_Mips(LLD_R_MIPS_STO_PLT, 0, a, 0);
-
- return pa;
-}
-
-template <typename ELFT>
-const PLTAtom *RelocationPass<ELFT>::getPLTMicroEntry(const Atom *a) {
- auto plt = _pltMicroMap.find(a);
- if (plt != _pltMicroMap.end())
- return plt->second;
-
- auto pa = new (_file._alloc) PLTMicroAtom<ELFT>(getGOTPLTEntry(a), _file);
- _pltMicroMap[a] = pa;
- _pltMicroVector.push_back(pa);
-
- // Check that 'a' dynamic symbol table record should point to the PLT.
- if (_hasStaticRelocations.count(a) && _requiresPtrEquality.count(a))
- pa->addReferenceELF_Mips(LLD_R_MIPS_STO_PLT, 0, a, 0);
-
- return pa;
-}
-
-template <typename ELFT>
-const LA25Atom *RelocationPass<ELFT>::getLA25RegEntry(const Atom *a) {
- auto la25 = _la25RegMap.find(a);
- if (la25 != _la25RegMap.end())
- return la25->second;
-
- auto sa = new (_file._alloc) LA25RegAtom<ELFT>(a, _file);
- _la25RegMap[a] = sa;
- _la25Vector.push_back(sa);
-
- return sa;
-}
-
-template <typename ELFT>
-const LA25Atom *RelocationPass<ELFT>::getLA25MicroEntry(const Atom *a) {
- auto la25 = _la25MicroMap.find(a);
- if (la25 != _la25MicroMap.end())
- return la25->second;
-
- auto sa = new (_file._alloc) LA25MicroAtom<ELFT>(a, _file);
- _la25MicroMap[a] = sa;
- _la25Vector.push_back(sa);
-
- return sa;
-}
-
-template <typename ELFT>
-const ObjectAtom *
-RelocationPass<ELFT>::getObjectEntry(const SharedLibraryAtom *a) {
- auto obj = _objectMap.find(a);
- if (obj != _objectMap.end())
- return obj->second;
-
- auto oa = new (_file._alloc) ObjectAtom(_file);
- oa->addReferenceELF_Mips(R_MIPS_COPY, 0, oa, 0);
- oa->_name = a->name();
- oa->_size = a->size();
-
- _objectMap[a] = oa;
- _objectVector.push_back(oa);
-
- return oa;
-}
-
-} // end anon namespace
-
-static std::unique_ptr<Pass> createPass(MipsLinkingContext &ctx) {
- switch (ctx.getTriple().getArch()) {
- case llvm::Triple::mips:
- return llvm::make_unique<RelocationPass<ELF32BE>>(ctx);
- case llvm::Triple::mipsel:
- return llvm::make_unique<RelocationPass<ELF32LE>>(ctx);
- case llvm::Triple::mips64:
- return llvm::make_unique<RelocationPass<ELF64BE>>(ctx);
- case llvm::Triple::mips64el:
- return llvm::make_unique<RelocationPass<ELF64LE>>(ctx);
- default:
- llvm_unreachable("Unhandled arch");
- }
-}
-
-std::unique_ptr<Pass>
-lld::elf::createMipsRelocationPass(MipsLinkingContext &ctx) {
- switch (ctx.getOutputELFType()) {
- case ET_EXEC:
- case ET_DYN:
- return createPass(ctx);
- case ET_REL:
- return nullptr;
- default:
- llvm_unreachable("Unhandled output file type");
- }
-}
diff --git a/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.h b/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.h
deleted file mode 100644
index af343de5f027..000000000000
--- a/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.h
+++ /dev/null
@@ -1,25 +0,0 @@
-//===- lib/ReaderWriter/ELF/Mips/MipsRelocationPass.h ---------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_RELOCATION_PASS_H
-#define LLD_READER_WRITER_ELF_MIPS_MIPS_RELOCATION_PASS_H
-
-#include <memory>
-
-namespace lld {
-class Pass;
-
-namespace elf {
-class MipsLinkingContext;
-
-std::unique_ptr<Pass> createMipsRelocationPass(MipsLinkingContext &ctx);
-
-} // end namespace elf
-} // end namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.cpp b/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.cpp
deleted file mode 100644
index 98cc059787ef..000000000000
--- a/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.cpp
+++ /dev/null
@@ -1,264 +0,0 @@
-//===- lib/ReaderWriter/ELF/Mips/MipsSectionChunks.cpp --------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "MipsLinkingContext.h"
-#include "MipsSectionChunks.h"
-#include "MipsTargetLayout.h"
-
-namespace lld {
-namespace elf {
-
-template <class ELFT>
-MipsReginfoSection<ELFT>::MipsReginfoSection(
- const ELFLinkingContext &ctx, MipsTargetLayout<ELFT> &targetLayout,
- const Elf_Mips_RegInfo &reginfo)
- : Section<ELFT>(ctx, ".reginfo", "MipsReginfo"), _reginfo(reginfo),
- _targetLayout(targetLayout) {
- this->setOrder(MipsTargetLayout<ELFT>::ORDER_MIPS_REGINFO);
- this->_entSize = sizeof(Elf_Mips_RegInfo);
- this->_fsize = sizeof(Elf_Mips_RegInfo);
- this->_msize = sizeof(Elf_Mips_RegInfo);
- this->_alignment = 4;
- this->_type = SHT_MIPS_REGINFO;
- this->_flags = SHF_ALLOC;
-}
-
-template <class ELFT>
-void MipsReginfoSection<ELFT>::write(ELFWriter *writer,
- TargetLayout<ELFT> &layout,
- llvm::FileOutputBuffer &buffer) {
- uint8_t *dest = buffer.getBufferStart() + this->fileOffset();
- std::memcpy(dest, &_reginfo, this->_fsize);
-}
-
-template <class ELFT> void MipsReginfoSection<ELFT>::finalize() {
- _reginfo.ri_gp_value = _targetLayout.getGPAddr();
-
- if (this->_outputSection)
- this->_outputSection->setType(this->_type);
-}
-
-template class MipsReginfoSection<ELF32BE>;
-template class MipsReginfoSection<ELF32LE>;
-template class MipsReginfoSection<ELF64BE>;
-template class MipsReginfoSection<ELF64LE>;
-
-template <class ELFT>
-MipsOptionsSection<ELFT>::MipsOptionsSection(
- const ELFLinkingContext &ctx, MipsTargetLayout<ELFT> &targetLayout,
- const Elf_Mips_RegInfo &reginfo)
- : Section<ELFT>(ctx, ".MIPS.options", "MipsOptions"), _reginfo(reginfo),
- _targetLayout(targetLayout) {
- this->setOrder(MipsTargetLayout<ELFT>::ORDER_MIPS_OPTIONS);
- this->_entSize = 1;
- this->_alignment = 8;
- this->_fsize = llvm::RoundUpToAlignment(
- sizeof(Elf_Mips_Options) + sizeof(Elf_Mips_RegInfo), this->_alignment);
- this->_msize = this->_fsize;
- this->_type = SHT_MIPS_OPTIONS;
- this->_flags = SHF_ALLOC | SHF_MIPS_NOSTRIP;
-
- _header.kind = ODK_REGINFO;
- _header.size = this->_fsize;
- _header.section = 0;
- _header.info = 0;
-}
-
-template <class ELFT>
-void MipsOptionsSection<ELFT>::write(ELFWriter *writer,
- TargetLayout<ELFT> &layout,
- llvm::FileOutputBuffer &buffer) {
- uint8_t *dest = buffer.getBufferStart() + this->fileOffset();
- std::memset(dest, 0, this->_fsize);
- std::memcpy(dest, &_header, sizeof(_header));
- std::memcpy(dest + sizeof(_header), &_reginfo, sizeof(_reginfo));
-}
-
-template <class ELFT> void MipsOptionsSection<ELFT>::finalize() {
- _reginfo.ri_gp_value = _targetLayout.getGPAddr();
-
- if (this->_outputSection)
- this->_outputSection->setType(this->_type);
-}
-
-template class MipsOptionsSection<ELF32BE>;
-template class MipsOptionsSection<ELF32LE>;
-template class MipsOptionsSection<ELF64BE>;
-template class MipsOptionsSection<ELF64LE>;
-
-template <class ELFT>
-MipsAbiFlagsSection<ELFT>::MipsAbiFlagsSection(
- const ELFLinkingContext &ctx, MipsTargetLayout<ELFT> &targetLayout,
- const Elf_Mips_ABIFlags &abiFlags)
- : Section<ELFT>(ctx, ".MIPS.abiflags", "MipsAbiFlags"), _abiFlags(abiFlags),
- _targetLayout(targetLayout) {
- this->setOrder(MipsTargetLayout<ELFT>::ORDER_MIPS_ABI_FLAGS);
- this->_alignment = 8;
- this->_fsize = llvm::RoundUpToAlignment(sizeof(_abiFlags), this->_alignment);
- this->_msize = this->_fsize;
- this->_entSize = this->_fsize;
- this->_type = SHT_MIPS_ABIFLAGS;
- this->_flags = SHF_ALLOC;
-}
-
-template <class ELFT>
-void MipsAbiFlagsSection<ELFT>::write(ELFWriter *writer,
- TargetLayout<ELFT> &layout,
- llvm::FileOutputBuffer &buffer) {
- uint8_t *dest = buffer.getBufferStart() + this->fileOffset();
- std::memcpy(dest, &_abiFlags, this->_fsize);
-}
-
-template <class ELFT> void MipsAbiFlagsSection<ELFT>::finalize() {
- if (this->_outputSection)
- this->_outputSection->setType(this->_type);
-}
-
-template class MipsAbiFlagsSection<ELF32BE>;
-template class MipsAbiFlagsSection<ELF32LE>;
-template class MipsAbiFlagsSection<ELF64BE>;
-template class MipsAbiFlagsSection<ELF64LE>;
-
-template <class ELFT>
-MipsGOTSection<ELFT>::MipsGOTSection(const MipsLinkingContext &ctx)
- : AtomSection<ELFT>(ctx, ".got", DefinedAtom::typeGOT, DefinedAtom::permRW_,
- MipsTargetLayout<ELFT>::ORDER_GOT),
- _hasNonLocal(false), _localCount(0) {
- this->_flags |= SHF_MIPS_GPREL;
- this->_alignment = 4;
-}
-
-template <class ELFT>
-bool MipsGOTSection<ELFT>::compare(const Atom *a, const Atom *b) const {
- auto ia = _posMap.find(a);
- auto ib = _posMap.find(b);
-
- if (ia != _posMap.end() && ib != _posMap.end())
- return ia->second < ib->second;
-
- return ia == _posMap.end() && ib != _posMap.end();
-}
-
-template <class ELFT>
-const AtomLayout *MipsGOTSection<ELFT>::appendAtom(const Atom *atom) {
- const DefinedAtom *da = dyn_cast<DefinedAtom>(atom);
-
- if (atom->name() == "_GLOBAL_OFFSET_TABLE_")
- return AtomSection<ELFT>::appendAtom(atom);
-
- for (const auto &r : *da) {
- if (r->kindNamespace() != Reference::KindNamespace::ELF)
- continue;
- assert(r->kindArch() == Reference::KindArch::Mips);
- switch (r->kindValue()) {
- case LLD_R_MIPS_GLOBAL_GOT:
- _hasNonLocal = true;
- _posMap[r->target()] = _posMap.size();
- return AtomSection<ELFT>::appendAtom(atom);
- case R_MIPS_TLS_TPREL32:
- case R_MIPS_TLS_DTPREL32:
- case R_MIPS_TLS_TPREL64:
- case R_MIPS_TLS_DTPREL64:
- _hasNonLocal = true;
- _tlsMap[r->target()] = _tlsMap.size();
- return AtomSection<ELFT>::appendAtom(atom);
- case R_MIPS_TLS_DTPMOD32:
- case R_MIPS_TLS_DTPMOD64:
- _hasNonLocal = true;
- break;
- }
- }
-
- if (!_hasNonLocal)
- ++_localCount;
-
- return AtomSection<ELFT>::appendAtom(atom);
-}
-
-template class MipsGOTSection<ELF32BE>;
-template class MipsGOTSection<ELF32LE>;
-template class MipsGOTSection<ELF64BE>;
-template class MipsGOTSection<ELF64LE>;
-
-template <class ELFT>
-MipsPLTSection<ELFT>::MipsPLTSection(const MipsLinkingContext &ctx)
- : AtomSection<ELFT>(ctx, ".plt", DefinedAtom::typeGOT, DefinedAtom::permR_X,
- MipsTargetLayout<ELFT>::ORDER_PLT) {}
-
-template <class ELFT>
-const AtomLayout *MipsPLTSection<ELFT>::findPLTLayout(const Atom *plt) const {
- auto it = _pltLayoutMap.find(plt);
- return it != _pltLayoutMap.end() ? it->second : nullptr;
-}
-
-template <class ELFT>
-const AtomLayout *MipsPLTSection<ELFT>::appendAtom(const Atom *atom) {
- const auto *layout = AtomSection<ELFT>::appendAtom(atom);
-
- const DefinedAtom *da = cast<DefinedAtom>(atom);
-
- for (const auto &r : *da) {
- if (r->kindNamespace() != Reference::KindNamespace::ELF)
- continue;
- assert(r->kindArch() == Reference::KindArch::Mips);
- if (r->kindValue() == LLD_R_MIPS_STO_PLT) {
- _pltLayoutMap[r->target()] = layout;
- break;
- }
- }
-
- return layout;
-}
-
-template class MipsPLTSection<ELF32BE>;
-template class MipsPLTSection<ELF32LE>;
-template class MipsPLTSection<ELF64BE>;
-template class MipsPLTSection<ELF64LE>;
-
-template <class ELFT> static bool isMips64EL() {
- return ELFT::Is64Bits && ELFT::TargetEndianness == llvm::support::little;
-}
-
-template <class ELFT>
-MipsRelocationTable<ELFT>::MipsRelocationTable(const ELFLinkingContext &ctx,
- StringRef str, int32_t order)
- : RelocationTable<ELFT>(ctx, str, order) {}
-
-template <class ELFT>
-void MipsRelocationTable<ELFT>::writeRela(ELFWriter *writer, Elf_Rela &r,
- const DefinedAtom &atom,
- const Reference &ref) {
- uint32_t rType = ref.kindValue() | (ref.tag() << 8);
- r.setSymbolAndType(this->getSymbolIndex(ref.target()), rType,
- isMips64EL<ELFT>());
- r.r_offset = writer->addressOfAtom(&atom) + ref.offsetInAtom();
- // The addend is used only by relative relocations
- if (this->_ctx.isRelativeReloc(ref))
- r.r_addend = writer->addressOfAtom(ref.target()) + ref.addend();
- else
- r.r_addend = 0;
-}
-
-template <class ELFT>
-void MipsRelocationTable<ELFT>::writeRel(ELFWriter *writer, Elf_Rel &r,
- const DefinedAtom &atom,
- const Reference &ref) {
- uint32_t rType = ref.kindValue() | (ref.tag() << 8);
- r.setSymbolAndType(this->getSymbolIndex(ref.target()), rType,
- isMips64EL<ELFT>());
- r.r_offset = writer->addressOfAtom(&atom) + ref.offsetInAtom();
-}
-
-template class MipsRelocationTable<ELF32BE>;
-template class MipsRelocationTable<ELF32LE>;
-template class MipsRelocationTable<ELF64BE>;
-template class MipsRelocationTable<ELF64LE>;
-
-} // elf
-} // lld
diff --git a/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h b/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h
deleted file mode 100644
index e545f65dc419..000000000000
--- a/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h
+++ /dev/null
@@ -1,150 +0,0 @@
-//===- lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h ----------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_SECTION_CHUNKS_H
-#define LLD_READER_WRITER_ELF_MIPS_MIPS_SECTION_CHUNKS_H
-
-#include "SectionChunks.h"
-
-namespace lld {
-namespace elf {
-
-template <typename ELFT> class MipsTargetLayout;
-class MipsLinkingContext;
-
-/// \brief Handle Mips .reginfo section
-template <class ELFT> class MipsReginfoSection : public Section<ELFT> {
-public:
- typedef llvm::object::Elf_Mips_RegInfo<ELFT> Elf_Mips_RegInfo;
-
- MipsReginfoSection(const ELFLinkingContext &ctx,
- MipsTargetLayout<ELFT> &targetLayout,
- const Elf_Mips_RegInfo &reginfo);
-
- StringRef segmentKindToStr() const override { return "REGINFO"; }
- bool hasOutputSegment() const override { return true; }
-
- void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
- llvm::FileOutputBuffer &buffer) override;
- void finalize() override;
-
-private:
- Elf_Mips_RegInfo _reginfo;
- MipsTargetLayout<ELFT> &_targetLayout;
-};
-
-/// \brief Handle .MIPS.options section
-template <class ELFT> class MipsOptionsSection : public Section<ELFT> {
-public:
- typedef llvm::object::Elf_Mips_Options<ELFT> Elf_Mips_Options;
- typedef llvm::object::Elf_Mips_RegInfo<ELFT> Elf_Mips_RegInfo;
-
- MipsOptionsSection(const ELFLinkingContext &ctx,
- MipsTargetLayout<ELFT> &targetLayout,
- const Elf_Mips_RegInfo &reginfo);
-
- bool hasOutputSegment() const override { return true; }
-
- void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
- llvm::FileOutputBuffer &buffer) override;
- void finalize() override;
-
-private:
- Elf_Mips_Options _header;
- Elf_Mips_RegInfo _reginfo;
- MipsTargetLayout<ELFT> &_targetLayout;
-};
-
-/// \brief Handle .MIPS.abiflags section
-template <class ELFT> class MipsAbiFlagsSection : public Section<ELFT> {
-public:
- typedef llvm::object::Elf_Mips_ABIFlags<ELFT> Elf_Mips_ABIFlags;
-
- MipsAbiFlagsSection(const ELFLinkingContext &ctx,
- MipsTargetLayout<ELFT> &targetLayout,
- const Elf_Mips_ABIFlags &abiFlags);
-
- bool hasOutputSegment() const override { return true; }
-
- void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
- llvm::FileOutputBuffer &buffer) override;
- void finalize() override;
-
-private:
- Elf_Mips_ABIFlags _abiFlags;
- MipsTargetLayout<ELFT> &_targetLayout;
-};
-
-/// \brief Handle Mips GOT section
-template <class ELFT> class MipsGOTSection : public AtomSection<ELFT> {
-public:
- MipsGOTSection(const MipsLinkingContext &ctx);
-
- /// \brief Number of local GOT entries.
- std::size_t getLocalCount() const { return _localCount; }
-
- /// \brief Number of global GOT entries.
- std::size_t getGlobalCount() const { return _posMap.size(); }
-
- /// \brief Does the atom have a global GOT entry?
- bool hasGlobalGOTEntry(const Atom *a) const {
- return _posMap.count(a) || _tlsMap.count(a);
- }
-
- /// \brief Compare two atoms accordingly theirs positions in the GOT.
- bool compare(const Atom *a, const Atom *b) const;
-
- const AtomLayout *appendAtom(const Atom *atom) override;
-
-private:
- /// \brief True if the GOT contains non-local entries.
- bool _hasNonLocal;
-
- /// \brief Number of local GOT entries.
- std::size_t _localCount;
-
- /// \brief Map TLS Atoms to their GOT entry index.
- llvm::DenseMap<const Atom *, std::size_t> _tlsMap;
-
- /// \brief Map Atoms to their GOT entry index.
- llvm::DenseMap<const Atom *, std::size_t> _posMap;
-};
-
-/// \brief Handle Mips PLT section
-template <class ELFT> class MipsPLTSection : public AtomSection<ELFT> {
-public:
- MipsPLTSection(const MipsLinkingContext &ctx);
-
- const AtomLayout *findPLTLayout(const Atom *plt) const;
-
- const AtomLayout *appendAtom(const Atom *atom) override;
-
-private:
- /// \brief Map PLT Atoms to their layouts.
- std::unordered_map<const Atom *, const AtomLayout *> _pltLayoutMap;
-};
-
-template <class ELFT> class MipsRelocationTable : public RelocationTable<ELFT> {
- typedef llvm::object::Elf_Rel_Impl<ELFT, false> Elf_Rel;
- typedef llvm::object::Elf_Rel_Impl<ELFT, true> Elf_Rela;
-
-public:
- MipsRelocationTable(const ELFLinkingContext &ctx, StringRef str,
- int32_t order);
-
-protected:
- void writeRela(ELFWriter *writer, Elf_Rela &r, const DefinedAtom &atom,
- const Reference &ref) override;
- void writeRel(ELFWriter *writer, Elf_Rel &r, const DefinedAtom &atom,
- const Reference &ref) override;
-};
-
-} // elf
-} // lld
-
-#endif
diff --git a/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp b/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp
deleted file mode 100644
index 817e29444666..000000000000
--- a/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp
+++ /dev/null
@@ -1,166 +0,0 @@
-//===- lib/ReaderWriter/ELF/Mips/MipsTargetHandler32EL.cpp ----------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ELFReader.h"
-#include "MipsELFFile.h"
-#include "MipsELFWriters.h"
-#include "MipsTargetHandler.h"
-
-namespace lld {
-namespace elf {
-
-template <class ELFT>
-MipsTargetHandler<ELFT>::MipsTargetHandler(MipsLinkingContext &ctx)
- : _ctx(ctx), _targetLayout(new MipsTargetLayout<ELFT>(ctx, _abiInfoHandler)),
- _relocationHandler(
- createMipsRelocationHandler<ELFT>(ctx, *_targetLayout)) {}
-
-template <class ELFT>
-std::unique_ptr<Reader> MipsTargetHandler<ELFT>::getObjReader() {
- return llvm::make_unique<ELFReader<MipsELFFile<ELFT>>>(_ctx);
-}
-
-template <class ELFT>
-std::unique_ptr<Reader> MipsTargetHandler<ELFT>::getDSOReader() {
- return llvm::make_unique<ELFReader<DynamicFile<ELFT>>>(_ctx);
-}
-
-template <class ELFT>
-const TargetRelocationHandler &
-MipsTargetHandler<ELFT>::getRelocationHandler() const {
- return *_relocationHandler;
-}
-
-template <class ELFT>
-std::unique_ptr<Writer> MipsTargetHandler<ELFT>::getWriter() {
- switch (_ctx.getOutputELFType()) {
- case llvm::ELF::ET_EXEC:
- return llvm::make_unique<MipsExecutableWriter<ELFT>>(_ctx, *_targetLayout,
- _abiInfoHandler);
- case llvm::ELF::ET_DYN:
- return llvm::make_unique<MipsDynamicLibraryWriter<ELFT>>(
- _ctx, *_targetLayout, _abiInfoHandler);
- case llvm::ELF::ET_REL:
- llvm_unreachable("TODO: support -r mode");
- default:
- llvm_unreachable("unsupported output type");
- }
-}
-
-template <class ELFT> MipsAbi MipsTargetHandler<ELFT>::getAbi() const {
- return _abiInfoHandler.getAbi();
-}
-
-template class MipsTargetHandler<ELF32BE>;
-template class MipsTargetHandler<ELF32LE>;
-template class MipsTargetHandler<ELF64BE>;
-template class MipsTargetHandler<ELF64LE>;
-
-template <class ELFT>
-MipsSymbolTable<ELFT>::MipsSymbolTable(const ELFLinkingContext &ctx)
- : SymbolTable<ELFT>(ctx, ".symtab",
- TargetLayout<ELFT>::ORDER_SYMBOL_TABLE) {}
-
-template <class ELFT>
-void MipsSymbolTable<ELFT>::addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da,
- int64_t addr) {
- SymbolTable<ELFT>::addDefinedAtom(sym, da, addr);
-
- switch (da->codeModel()) {
- case DefinedAtom::codeMipsMicro:
- sym.st_other |= llvm::ELF::STO_MIPS_MICROMIPS;
- break;
- case DefinedAtom::codeMipsMicroPIC:
- sym.st_other |= llvm::ELF::STO_MIPS_MICROMIPS | llvm::ELF::STO_MIPS_PIC;
- break;
- default:
- break;
- }
-}
-
-template <class ELFT> void MipsSymbolTable<ELFT>::finalize(bool sort) {
- SymbolTable<ELFT>::finalize(sort);
-
- for (auto &ste : this->_symbolTable) {
- if (!ste._atom)
- continue;
- if (const auto *da = dyn_cast<DefinedAtom>(ste._atom)) {
- if (da->codeModel() == DefinedAtom::codeMipsMicro ||
- da->codeModel() == DefinedAtom::codeMipsMicroPIC) {
- // Adjust dynamic microMIPS symbol value. That allows a dynamic
- // linker to recognize and handle this symbol correctly.
- ste._symbol.st_value = ste._symbol.st_value | 1;
- }
- }
- }
-}
-
-template class MipsSymbolTable<ELF32BE>;
-template class MipsSymbolTable<ELF32LE>;
-template class MipsSymbolTable<ELF64BE>;
-template class MipsSymbolTable<ELF64LE>;
-
-template <class ELFT>
-MipsDynamicSymbolTable<ELFT>::MipsDynamicSymbolTable(
- const ELFLinkingContext &ctx, MipsTargetLayout<ELFT> &layout)
- : DynamicSymbolTable<ELFT>(ctx, layout, ".dynsym",
- TargetLayout<ELFT>::ORDER_DYNAMIC_SYMBOLS),
- _targetLayout(layout) {}
-
-template <class ELFT> void MipsDynamicSymbolTable<ELFT>::sortSymbols() {
- typedef typename DynamicSymbolTable<ELFT>::SymbolEntry SymbolEntry;
- std::stable_sort(this->_symbolTable.begin(), this->_symbolTable.end(),
- [this](const SymbolEntry &A, const SymbolEntry &B) {
- if (A._symbol.getBinding() != STB_GLOBAL &&
- B._symbol.getBinding() != STB_GLOBAL)
- return A._symbol.getBinding() < B._symbol.getBinding();
-
- return _targetLayout.getGOTSection().compare(A._atom,
- B._atom);
- });
-}
-
-template <class ELFT> void MipsDynamicSymbolTable<ELFT>::finalize() {
- DynamicSymbolTable<ELFT>::finalize();
-
- const auto &pltSection = _targetLayout.getPLTSection();
-
- for (auto &ste : this->_symbolTable) {
- const Atom *a = ste._atom;
- if (!a)
- continue;
- if (auto *layout = pltSection.findPLTLayout(a)) {
- a = layout->_atom;
- // Under some conditions a dynamic symbol table record should hold
- // a symbol value of the corresponding PLT entry. For details look
- // at the PLT entry creation code in the class MipsRelocationPass.
- // Let's update atomLayout fields for such symbols.
- assert(!ste._atomLayout);
- ste._symbol.st_value = layout->_virtualAddr;
- ste._symbol.st_other |= ELF::STO_MIPS_PLT;
- }
-
- if (const auto *da = dyn_cast<DefinedAtom>(a)) {
- if (da->codeModel() == DefinedAtom::codeMipsMicro ||
- da->codeModel() == DefinedAtom::codeMipsMicroPIC) {
- // Adjust dynamic microMIPS symbol value. That allows a dynamic
- // linker to recognize and handle this symbol correctly.
- ste._symbol.st_value = ste._symbol.st_value | 1;
- }
- }
- }
-}
-
-template class MipsDynamicSymbolTable<ELF32BE>;
-template class MipsDynamicSymbolTable<ELF32LE>;
-template class MipsDynamicSymbolTable<ELF64BE>;
-template class MipsDynamicSymbolTable<ELF64LE>;
-
-}
-}
diff --git a/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h b/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h
deleted file mode 100644
index e4a35bdd323d..000000000000
--- a/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h
+++ /dev/null
@@ -1,73 +0,0 @@
-//===- lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h ----------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_TARGET_HANDLER_H
-#define LLD_READER_WRITER_ELF_MIPS_MIPS_TARGET_HANDLER_H
-
-#include "MipsAbiInfoHandler.h"
-#include "MipsLinkingContext.h"
-#include "MipsTargetLayout.h"
-#include "TargetHandler.h"
-
-namespace lld {
-namespace elf {
-
-class MipsBaseTargetHandler : public TargetHandler {
-public:
- virtual MipsAbi getAbi() const = 0;
-};
-
-/// \brief TargetHandler for Mips
-template <class ELFT>
-class MipsTargetHandler final : public MipsBaseTargetHandler {
-public:
- MipsTargetHandler(MipsLinkingContext &ctx);
-
- MipsAbiInfoHandler<ELFT> &getAbiInfoHandler() { return _abiInfoHandler; }
-
- std::unique_ptr<Reader> getObjReader() override;
- std::unique_ptr<Reader> getDSOReader() override;
- const TargetRelocationHandler &getRelocationHandler() const override;
- std::unique_ptr<Writer> getWriter() override;
- MipsAbi getAbi() const override;
-
-private:
- MipsLinkingContext &_ctx;
- MipsAbiInfoHandler<ELFT> _abiInfoHandler;
- std::unique_ptr<MipsTargetLayout<ELFT>> _targetLayout;
- std::unique_ptr<TargetRelocationHandler> _relocationHandler;
-};
-
-template <class ELFT> class MipsSymbolTable : public SymbolTable<ELFT> {
-public:
- typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
-
- MipsSymbolTable(const ELFLinkingContext &ctx);
-
- void addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da,
- int64_t addr) override;
- void finalize(bool sort) override;
-};
-
-template <class ELFT>
-class MipsDynamicSymbolTable : public DynamicSymbolTable<ELFT> {
-public:
- MipsDynamicSymbolTable(const ELFLinkingContext &ctx,
- MipsTargetLayout<ELFT> &layout);
-
- void sortSymbols() override;
- void finalize() override;
-
-private:
- MipsTargetLayout<ELFT> &_targetLayout;
-};
-
-} // end namespace elf
-} // end namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/ELF/Mips/MipsTargetLayout.cpp b/lib/ReaderWriter/ELF/Mips/MipsTargetLayout.cpp
deleted file mode 100644
index 710f8320a8b9..000000000000
--- a/lib/ReaderWriter/ELF/Mips/MipsTargetLayout.cpp
+++ /dev/null
@@ -1,111 +0,0 @@
-//===- lib/ReaderWriter/ELF/Mips/MipsTargetLayout.cpp ---------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "MipsLinkingContext.h"
-#include "MipsTargetLayout.h"
-
-namespace lld {
-namespace elf {
-
-template <class ELFT>
-MipsTargetLayout<ELFT>::MipsTargetLayout(MipsLinkingContext &ctx,
- MipsAbiInfoHandler<ELFT> &abi)
- : TargetLayout<ELFT>(ctx), _abiInfo(abi),
- _gotSection(new (this->_allocator) MipsGOTSection<ELFT>(ctx)),
- _pltSection(new (this->_allocator) MipsPLTSection<ELFT>(ctx)) {}
-
-template <class ELFT>
-AtomSection<ELFT> *MipsTargetLayout<ELFT>::createSection(
- StringRef name, int32_t type, DefinedAtom::ContentPermissions permissions,
- typename TargetLayout<ELFT>::SectionOrder order) {
- if (type == DefinedAtom::typeGOT && name == ".got")
- return _gotSection;
- if (type == DefinedAtom::typeStub && name == ".plt")
- return _pltSection;
- return TargetLayout<ELFT>::createSection(name, type, permissions, order);
-}
-
-template <class ELFT>
-typename TargetLayout<ELFT>::SegmentType
-MipsTargetLayout<ELFT>::getSegmentType(const Section<ELFT> *section) const {
- switch (section->order()) {
- case ORDER_MIPS_REGINFO:
- return _abiInfo.hasMipsAbiSection() ? llvm::ELF::PT_LOAD
- : llvm::ELF::PT_MIPS_REGINFO;
- case ORDER_MIPS_OPTIONS:
- return llvm::ELF::PT_LOAD;
- case ORDER_MIPS_ABI_FLAGS:
- return llvm::ELF::PT_MIPS_ABIFLAGS;
- default:
- return TargetLayout<ELFT>::getSegmentType(section);
- }
-}
-
-template <class ELFT> uint64_t MipsTargetLayout<ELFT>::getGPAddr() {
- std::call_once(_gpOnce, [this]() {
- if (AtomLayout *a = this->findAbsoluteAtom("_gp"))
- _gpAddr = a->_virtualAddr;
- });
- return _gpAddr;
-}
-
-template <class ELFT>
-typename TargetLayout<ELFT>::SectionOrder
-MipsTargetLayout<ELFT>::getSectionOrder(StringRef name, int32_t contentType,
- int32_t contentPermissions) {
- if ((contentType == DefinedAtom::typeStub) && (name.startswith(".text")))
- return TargetLayout<ELFT>::ORDER_TEXT;
-
- return TargetLayout<ELFT>::getSectionOrder(name, contentType,
- contentPermissions);
-}
-
-template <class ELFT>
-unique_bump_ptr<RelocationTable<ELFT>>
-MipsTargetLayout<ELFT>::createRelocationTable(StringRef name, int32_t order) {
- return unique_bump_ptr<RelocationTable<ELFT>>(new (
- this->_allocator) MipsRelocationTable<ELFT>(this->_ctx, name, order));
-}
-
-template <class ELFT>
-uint64_t MipsTargetLayout<ELFT>::getLookupSectionFlags(
- const OutputSection<ELFT> *os) const {
- uint64_t flags = TargetLayout<ELFT>::getLookupSectionFlags(os);
- return flags & ~llvm::ELF::SHF_MIPS_NOSTRIP;
-}
-
-template <class ELFT> void MipsTargetLayout<ELFT>::sortSegments() {
- using namespace llvm::ELF;
- TargetLayout<ELFT>::sortSegments();
- // Move PT_MIPS_ABIFLAGS or PT_MIPS_REGINFO right after PT_INTERP.
- auto abiIt =
- std::find_if(this->_segments.begin(), this->_segments.end(),
- [](const Segment<ELFT> *s) {
- auto typ = s->segmentType();
- return typ == PT_MIPS_ABIFLAGS || typ == PT_MIPS_REGINFO;
- });
- if (abiIt == this->_segments.end())
- return;
- Segment<ELFT> *abiSeg = *abiIt;
- this->_segments.erase(abiIt);
- auto outIt = std::find_if(this->_segments.begin(), this->_segments.end(),
- [](const Segment<ELFT> *s) {
- auto typ = s->segmentType();
- return typ != PT_PHDR && typ != PT_INTERP;
- });
- this->_segments.insert(outIt, abiSeg);
-}
-
-template class MipsTargetLayout<ELF32BE>;
-template class MipsTargetLayout<ELF32LE>;
-template class MipsTargetLayout<ELF64BE>;
-template class MipsTargetLayout<ELF64LE>;
-
-} // end namespace elf
-} // end namespace lld
diff --git a/lib/ReaderWriter/ELF/Mips/MipsTargetLayout.h b/lib/ReaderWriter/ELF/Mips/MipsTargetLayout.h
deleted file mode 100644
index 08855438d20e..000000000000
--- a/lib/ReaderWriter/ELF/Mips/MipsTargetLayout.h
+++ /dev/null
@@ -1,71 +0,0 @@
-//===- lib/ReaderWriter/ELF/Mips/MipsTargetLayout.h -----------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_TARGET_LAYOUT_H
-#define LLD_READER_WRITER_ELF_MIPS_MIPS_TARGET_LAYOUT_H
-
-#include "MipsAbiInfoHandler.h"
-#include "MipsSectionChunks.h"
-#include "TargetLayout.h"
-
-namespace lld {
-namespace elf {
-
-class MipsLinkingContext;
-
-/// \brief TargetLayout for Mips
-template <class ELFT> class MipsTargetLayout final : public TargetLayout<ELFT> {
-public:
- enum MipsSectionOrder {
- ORDER_MIPS_ABI_FLAGS = TargetLayout<ELFT>::ORDER_RO_NOTE + 1,
- ORDER_MIPS_REGINFO,
- ORDER_MIPS_OPTIONS,
- };
-
- MipsTargetLayout(MipsLinkingContext &ctx, MipsAbiInfoHandler<ELFT> &abi);
-
- const MipsGOTSection<ELFT> &getGOTSection() const { return *_gotSection; }
- const MipsPLTSection<ELFT> &getPLTSection() const { return *_pltSection; }
-
- AtomSection<ELFT> *
- createSection(StringRef name, int32_t type,
- DefinedAtom::ContentPermissions permissions,
- typename TargetLayout<ELFT>::SectionOrder order) override;
-
- typename TargetLayout<ELFT>::SegmentType
- getSegmentType(const Section<ELFT> *section) const override;
-
- /// \brief GP offset relative to .got section.
- uint64_t getGPOffset() const { return 0x7FF0; }
-
- /// \brief Get '_gp' symbol address.
- uint64_t getGPAddr();
-
- /// \brief Return the section order for a input section
- typename TargetLayout<ELFT>::SectionOrder
- getSectionOrder(StringRef name, int32_t contentType,
- int32_t contentPermissions) override;
-
-protected:
- unique_bump_ptr<RelocationTable<ELFT>>
- createRelocationTable(StringRef name, int32_t order) override;
- uint64_t getLookupSectionFlags(const OutputSection<ELFT> *os) const override;
- void sortSegments() override;
-
-private:
- MipsAbiInfoHandler<ELFT> &_abiInfo;
- MipsGOTSection<ELFT> *_gotSection;
- MipsPLTSection<ELFT> *_pltSection;
- uint64_t _gpAddr = 0;
- std::once_flag _gpOnce;
-};
-
-} // end namespace elf
-} // end namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/ELF/OrderPass.h b/lib/ReaderWriter/ELF/OrderPass.h
deleted file mode 100644
index 11f88056c8c4..000000000000
--- a/lib/ReaderWriter/ELF/OrderPass.h
+++ /dev/null
@@ -1,31 +0,0 @@
-//===- lib/ReaderWriter/ELF/OrderPass.h -----------------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_ELF_ORDER_PASS_H
-#define LLD_READER_WRITER_ELF_ORDER_PASS_H
-
-#include "lld/Core/Parallel.h"
-#include <limits>
-
-namespace lld {
-namespace elf {
-
-/// \brief This pass sorts atoms by file and atom ordinals.
-class OrderPass : public Pass {
-public:
- std::error_code perform(SimpleFile &file) override {
- parallel_sort(file.definedAtoms().begin(), file.definedAtoms().end(),
- DefinedAtom::compareByPosition);
- return std::error_code();
- }
-};
-}
-}
-
-#endif
diff --git a/lib/ReaderWriter/ELF/OutputELFWriter.cpp b/lib/ReaderWriter/ELF/OutputELFWriter.cpp
deleted file mode 100644
index 4f8b0eac655f..000000000000
--- a/lib/ReaderWriter/ELF/OutputELFWriter.cpp
+++ /dev/null
@@ -1,514 +0,0 @@
-//===- lib/ReaderWriter/ELF/OutputELFWriter.cpp --------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "OutputELFWriter.h"
-#include "lld/Core/SharedLibraryFile.h"
-#include "lld/Core/Simple.h"
-#include "lld/ReaderWriter/ELFLinkingContext.h"
-#include "llvm/Support/Path.h"
-
-namespace lld {
-namespace elf {
-
-namespace {
-
-template <class ELFT> class SymbolFile : public RuntimeFile<ELFT> {
-public:
- SymbolFile(ELFLinkingContext &ctx)
- : RuntimeFile<ELFT>(ctx, "Dynamic absolute symbols") {}
-
- void addUndefinedAtom(StringRef) override {
- llvm_unreachable("Cannot add undefined atoms to resolve undefined symbols");
- }
-
- bool hasAtoms() const { return this->absolute().size(); }
-};
-
-template <class ELFT>
-class DynamicSymbolFile : public SimpleArchiveLibraryFile {
- typedef std::function<void(StringRef, RuntimeFile<ELFT> &)> Resolver;
-
-public:
- DynamicSymbolFile(ELFLinkingContext &ctx, Resolver resolver)
- : SimpleArchiveLibraryFile("Dynamically added runtime symbols"),
- _ctx(ctx), _resolver(resolver) {}
-
- File *find(StringRef sym, bool dataSymbolOnly) override {
- if (!_file)
- _file.reset(new (_alloc) SymbolFile<ELFT>(_ctx));
-
- assert(!_file->hasAtoms() && "The file shouldn't have atoms yet");
- _resolver(sym, *_file);
-
- if (!_file->hasAtoms())
- return nullptr;
-
- // If atoms were added - return the file but also store it for later
- // destruction.
- File *result = _file.get();
- _returnedFiles.push_back(std::move(_file));
- return result;
- }
-
-private:
- ELFLinkingContext &_ctx;
- Resolver _resolver;
-
- // The allocator should go before bump pointers because of
- // reversed destruction order.
- llvm::BumpPtrAllocator _alloc;
- unique_bump_ptr<SymbolFile<ELFT>> _file;
- std::vector<unique_bump_ptr<SymbolFile<ELFT>>> _returnedFiles;
-};
-
-} // end anon namespace
-
-template <class ELFT>
-OutputELFWriter<ELFT>::OutputELFWriter(ELFLinkingContext &ctx,
- TargetLayout<ELFT> &layout)
- : _ctx(ctx), _targetHandler(ctx.getTargetHandler()), _layout(layout) {}
-
-template <class ELFT>
-void OutputELFWriter<ELFT>::buildChunks(const File &file) {
- ScopedTask task(getDefaultDomain(), "buildChunks");
- for (const DefinedAtom *definedAtom : file.defined()) {
- DefinedAtom::ContentType contentType = definedAtom->contentType();
- // Dont add COMDAT group atoms and GNU linkonce atoms, as they are used for
- // symbol resolution.
- // TODO: handle partial linking.
- if (contentType == DefinedAtom::typeGroupComdat ||
- contentType == DefinedAtom::typeGnuLinkOnce)
- continue;
- _layout.addAtom(definedAtom);
- }
- for (const AbsoluteAtom *absoluteAtom : file.absolute())
- _layout.addAtom(absoluteAtom);
-}
-
-template <class ELFT>
-void OutputELFWriter<ELFT>::buildStaticSymbolTable(const File &file) {
- ScopedTask task(getDefaultDomain(), "buildStaticSymbolTable");
- for (auto sec : _layout.sections())
- if (auto section = dyn_cast<AtomSection<ELFT>>(sec))
- for (const auto &atom : section->atoms())
- _symtab->addSymbol(atom->_atom, section->ordinal(), atom->_virtualAddr);
- for (auto &atom : _layout.absoluteAtoms())
- _symtab->addSymbol(atom->_atom, ELF::SHN_ABS, atom->_virtualAddr);
- for (const UndefinedAtom *a : file.undefined())
- _symtab->addSymbol(a, ELF::SHN_UNDEF);
-}
-
-// Returns the DSO name for a given input file if it's a shared library
-// file and not marked as --as-needed.
-template <class ELFT>
-StringRef OutputELFWriter<ELFT>::maybeGetSOName(Node *node) {
- if (auto *fnode = dyn_cast<FileNode>(node))
- if (!fnode->asNeeded())
- if (auto *file = dyn_cast<SharedLibraryFile>(fnode->getFile()))
- return file->getDSOName();
- return "";
-}
-
-template <class ELFT>
-void OutputELFWriter<ELFT>::buildDynamicSymbolTable(const File &file) {
- ScopedTask task(getDefaultDomain(), "buildDynamicSymbolTable");
- for (const auto &sla : file.sharedLibrary()) {
- if (isDynSymEntryRequired(sla)) {
- _dynamicSymbolTable->addSymbol(sla, ELF::SHN_UNDEF);
- _soNeeded.insert(sla->loadName());
- continue;
- }
- if (isNeededTagRequired(sla))
- _soNeeded.insert(sla->loadName());
- }
- for (const std::unique_ptr<Node> &node : _ctx.getNodes()) {
- StringRef soname = maybeGetSOName(node.get());
- if (!soname.empty())
- _soNeeded.insert(soname);
- }
- // Never mark the dynamic linker as DT_NEEDED
- _soNeeded.erase(sys::path::filename(_ctx.getInterpreter()));
- for (const auto &loadName : _soNeeded)
- _dynamicTable->addEntry(DT_NEEDED,
- _dynamicStringTable->addString(loadName.getKey()));
- const auto &rpathList = _ctx.getRpathList();
- if (!rpathList.empty()) {
- auto rpath =
- new (_alloc) std::string(join(rpathList.begin(), rpathList.end(), ":"));
- _dynamicTable->addEntry(_ctx.getEnableNewDtags() ? DT_RUNPATH : DT_RPATH,
- _dynamicStringTable->addString(*rpath));
- }
- StringRef soname = _ctx.sharedObjectName();
- if (!soname.empty() && _ctx.getOutputELFType() == llvm::ELF::ET_DYN)
- _dynamicTable->addEntry(DT_SONAME, _dynamicStringTable->addString(soname));
-
- // Add DT_FLAGS/DT_FLAGS_1 entries if necessary.
- uint32_t dtflags = 0, dt1flags = 0;
- if (_ctx.getDTFlag(ELFLinkingContext::DTFlag::DT_NOW)) {
- dtflags |= DF_BIND_NOW;
- dt1flags |= DF_1_NOW;
- }
- if (_ctx.getDTFlag(ELFLinkingContext::DTFlag::DT_ORIGIN)) {
- dtflags |= DF_ORIGIN;
- dt1flags |= DF_1_ORIGIN;
- }
- if (dtflags != 0)
- _dynamicTable->addEntry(DT_FLAGS, dtflags);
- if (dt1flags != 0)
- _dynamicTable->addEntry(DT_FLAGS_1, dt1flags);
-
- // The dynamic symbol table need to be sorted earlier because the hash
- // table needs to be built using the dynamic symbol table. It would be
- // late to sort the symbols due to that in finalize. In the dynamic symbol
- // table finalize, we call the symbol table finalize and we don't want to
- // sort again
- _dynamicSymbolTable->sortSymbols();
-
- // Add the dynamic symbols into the hash table
- _dynamicSymbolTable->addSymbolsToHashTable();
-}
-
-template <class ELFT>
-void OutputELFWriter<ELFT>::buildAtomToAddressMap(const File &file) {
- ScopedTask task(getDefaultDomain(), "buildAtomToAddressMap");
- int64_t totalAbsAtoms = _layout.absoluteAtoms().size();
- int64_t totalUndefinedAtoms = file.undefined().size();
- int64_t totalDefinedAtoms = 0;
- for (auto sec : _layout.sections())
- if (auto section = dyn_cast<AtomSection<ELFT>>(sec)) {
- totalDefinedAtoms += section->atoms().size();
- for (const auto &atom : section->atoms())
- _atomToAddressMap[atom->_atom] = atom->_virtualAddr;
- }
- // build the atomToAddressMap that contains absolute symbols too
- for (auto &atom : _layout.absoluteAtoms())
- _atomToAddressMap[atom->_atom] = atom->_virtualAddr;
-
- // Set the total number of atoms in the symbol table, so that appropriate
- // resizing of the string table can be done.
- // There's no such thing as symbol table if we're stripping all the symbols
- if (!_ctx.stripSymbols())
- _symtab->setNumEntries(totalDefinedAtoms + totalAbsAtoms +
- totalUndefinedAtoms);
-}
-
-template <class ELFT> void OutputELFWriter<ELFT>::buildSectionHeaderTable() {
- ScopedTask task(getDefaultDomain(), "buildSectionHeaderTable");
- for (auto outputSection : _layout.outputSections()) {
- if (outputSection->kind() != Chunk<ELFT>::Kind::ELFSection &&
- outputSection->kind() != Chunk<ELFT>::Kind::AtomSection)
- continue;
- if (outputSection->hasSegment())
- _shdrtab->appendSection(outputSection);
- }
-}
-
-template <class ELFT>
-void OutputELFWriter<ELFT>::assignSectionsWithNoSegments() {
- ScopedTask task(getDefaultDomain(), "assignSectionsWithNoSegments");
- for (auto outputSection : _layout.outputSections()) {
- if (outputSection->kind() != Chunk<ELFT>::Kind::ELFSection &&
- outputSection->kind() != Chunk<ELFT>::Kind::AtomSection)
- continue;
- if (!outputSection->hasSegment())
- _shdrtab->appendSection(outputSection);
- }
- _layout.assignFileOffsetsForMiscSections();
- for (auto sec : _layout.sections())
- if (auto section = dyn_cast<Section<ELFT>>(sec))
- if (!TargetLayout<ELFT>::hasOutputSegment(section))
- _shdrtab->updateSection(section);
-}
-
-template <class ELFT>
-void OutputELFWriter<ELFT>::createImplicitFiles(
- std::vector<std::unique_ptr<File>> &result) {
- // Add the virtual archive to resolve undefined symbols.
- // The file will be added later in the linking context.
- auto callback = [this](StringRef sym, RuntimeFile<ELFT> &file) {
- processUndefinedSymbol(sym, file);
- };
- _ctx.setUndefinesResolver(
- llvm::make_unique<DynamicSymbolFile<ELFT>>(_ctx, std::move(callback)));
- // Add script defined symbols
- auto file =
- llvm::make_unique<RuntimeFile<ELFT>>(_ctx, "Linker script runtime");
- for (auto &sym : this->_ctx.linkerScriptSema().getScriptDefinedSymbols())
- file->addAbsoluteAtom(sym.getKey());
- result.push_back(std::move(file));
-}
-
-template <class ELFT> void OutputELFWriter<ELFT>::finalizeDefaultAtomValues() {
- const llvm::StringSet<> &symbols =
- _ctx.linkerScriptSema().getScriptDefinedSymbols();
- for (auto &sym : symbols) {
- uint64_t res =
- _ctx.linkerScriptSema().getLinkerScriptExprValue(sym.getKey());
- AtomLayout *a = _layout.findAbsoluteAtom(sym.getKey());
- assert(a);
- a->_virtualAddr = res;
- }
- // If there is a section named XXX, and XXX is a valid C identifier,
- // and there are undefined or weak __start_XXX/__stop_XXX symbols,
- // set the symbols values to the begin/end of the XXX section
- // correspondingly.
- for (const auto &name : _ctx.cidentSectionNames())
- updateScopeAtomValues((Twine("__start_") + name.getKey()).str(),
- (Twine("__stop_") + name.getKey()).str(),
- name.getKey());
-}
-
-template <class ELFT> void OutputELFWriter<ELFT>::createDefaultSections() {
- _elfHeader.reset(new (_alloc) ELFHeader<ELFT>(_ctx));
- _programHeader.reset(new (_alloc) ProgramHeader<ELFT>(_ctx));
- _layout.setHeader(_elfHeader.get());
- _layout.setProgramHeader(_programHeader.get());
-
- // Don't create .symtab and .strtab sections if we're going to
- // strip all the symbols.
- if (!_ctx.stripSymbols()) {
- _symtab = this->createSymbolTable();
- _strtab.reset(new (_alloc) StringTable<ELFT>(
- _ctx, ".strtab", TargetLayout<ELFT>::ORDER_STRING_TABLE));
- _layout.addSection(_symtab.get());
- _layout.addSection(_strtab.get());
- _symtab->setStringSection(_strtab.get());
- }
-
- _shstrtab.reset(new (_alloc) StringTable<ELFT>(
- _ctx, ".shstrtab", TargetLayout<ELFT>::ORDER_SECTION_STRINGS));
- _shdrtab.reset(new (_alloc) SectionHeader<ELFT>(
- _ctx, TargetLayout<ELFT>::ORDER_SECTION_HEADERS));
- _layout.addSection(_shstrtab.get());
- _shdrtab->setStringSection(_shstrtab.get());
- _layout.addSection(_shdrtab.get());
-
- for (auto sec : _layout.sections()) {
- // TODO: use findOutputSection
- auto section = dyn_cast<Section<ELFT>>(sec);
- if (!section || section->outputSectionName() != ".eh_frame")
- continue;
- _ehFrameHeader.reset(new (_alloc) EHFrameHeader<ELFT>(
- _ctx, ".eh_frame_hdr", _layout, TargetLayout<ELFT>::ORDER_EH_FRAMEHDR));
- _layout.addSection(_ehFrameHeader.get());
- break;
- }
-
- if (_ctx.isDynamic()) {
- _dynamicTable = createDynamicTable();
- _dynamicStringTable.reset(new (_alloc) StringTable<ELFT>(
- _ctx, ".dynstr", TargetLayout<ELFT>::ORDER_DYNAMIC_STRINGS, true));
- _dynamicSymbolTable = createDynamicSymbolTable();
- _hashTable.reset(new (_alloc) HashSection<ELFT>(
- _ctx, ".hash", TargetLayout<ELFT>::ORDER_HASH));
- // Set the hash table in the dynamic symbol table so that the entries in the
- // hash table can be created
- _dynamicSymbolTable->setHashTable(_hashTable.get());
- _hashTable->setSymbolTable(_dynamicSymbolTable.get());
- _layout.addSection(_dynamicTable.get());
- _layout.addSection(_dynamicStringTable.get());
- _layout.addSection(_dynamicSymbolTable.get());
- _layout.addSection(_hashTable.get());
- _dynamicSymbolTable->setStringSection(_dynamicStringTable.get());
- _dynamicTable->setSymbolTable(_dynamicSymbolTable.get());
- _dynamicTable->setHashTable(_hashTable.get());
- if (_layout.hasDynamicRelocationTable())
- _layout.getDynamicRelocationTable()->setSymbolTable(
- _dynamicSymbolTable.get());
- if (_layout.hasPLTRelocationTable())
- _layout.getPLTRelocationTable()->setSymbolTable(
- _dynamicSymbolTable.get());
- }
-}
-
-template <class ELFT>
-unique_bump_ptr<SymbolTable<ELFT>> OutputELFWriter<ELFT>::createSymbolTable() {
- return unique_bump_ptr<SymbolTable<ELFT>>(new (_alloc) SymbolTable<ELFT>(
- this->_ctx, ".symtab", TargetLayout<ELFT>::ORDER_SYMBOL_TABLE));
-}
-
-/// \brief create dynamic table
-template <class ELFT>
-unique_bump_ptr<DynamicTable<ELFT>>
-OutputELFWriter<ELFT>::createDynamicTable() {
- return unique_bump_ptr<DynamicTable<ELFT>>(new (_alloc) DynamicTable<ELFT>(
- this->_ctx, _layout, ".dynamic", TargetLayout<ELFT>::ORDER_DYNAMIC));
-}
-
-/// \brief create dynamic symbol table
-template <class ELFT>
-unique_bump_ptr<DynamicSymbolTable<ELFT>>
-OutputELFWriter<ELFT>::createDynamicSymbolTable() {
- return unique_bump_ptr<DynamicSymbolTable<ELFT>>(
- new (_alloc)
- DynamicSymbolTable<ELFT>(this->_ctx, _layout, ".dynsym",
- TargetLayout<ELFT>::ORDER_DYNAMIC_SYMBOLS));
-}
-
-template <class ELFT>
-std::error_code OutputELFWriter<ELFT>::buildOutput(const File &file) {
- ScopedTask buildTask(getDefaultDomain(), "ELF Writer buildOutput");
- buildChunks(file);
-
- // Create the default sections like the symbol table, string table, and the
- // section string table
- createDefaultSections();
-
- // Set the Layout
- _layout.assignSectionsToSegments();
-
- // Create the dynamic table entries
- if (_ctx.isDynamic()) {
- _dynamicTable->createDefaultEntries();
- buildDynamicSymbolTable(file);
- }
-
- // Call the preFlight callbacks to modify the sections and the atoms
- // contained in them, in anyway the targets may want
- _layout.doPreFlight();
-
- _layout.assignVirtualAddress();
-
- // Finalize the default value of symbols that the linker adds
- finalizeDefaultAtomValues();
-
- // Build the Atom To Address map for applying relocations
- buildAtomToAddressMap(file);
-
- // Create symbol table and section string table
- // Do it only if -s is not specified.
- if (!_ctx.stripSymbols())
- buildStaticSymbolTable(file);
-
- // Finalize the layout by calling the finalize() functions
- _layout.finalize();
-
- // build Section Header table
- buildSectionHeaderTable();
-
- // assign Offsets and virtual addresses
- // for sections with no segments
- assignSectionsWithNoSegments();
-
- if (_ctx.isDynamic())
- _dynamicTable->updateDynamicTable();
-
- return std::error_code();
-}
-
-template <class ELFT> std::error_code OutputELFWriter<ELFT>::setELFHeader() {
- _elfHeader->e_type(_ctx.getOutputELFType());
- _elfHeader->e_machine(_ctx.getOutputMachine());
- _elfHeader->e_ident(ELF::EI_VERSION, 1);
- _elfHeader->e_ident(ELF::EI_OSABI, 0);
- _elfHeader->e_version(1);
- _elfHeader->e_phoff(_programHeader->fileOffset());
- _elfHeader->e_shoff(_shdrtab->fileOffset());
- _elfHeader->e_phentsize(_programHeader->entsize());
- _elfHeader->e_phnum(_programHeader->numHeaders());
- _elfHeader->e_shentsize(_shdrtab->entsize());
- _elfHeader->e_shnum(_shdrtab->numHeaders());
- _elfHeader->e_shstrndx(_shstrtab->ordinal());
- if (const auto *al = _layout.findAtomLayoutByName(_ctx.entrySymbolName()))
- _elfHeader->e_entry(al->_virtualAddr);
- else
- _elfHeader->e_entry(0);
-
- return std::error_code();
-}
-
-template <class ELFT> uint64_t OutputELFWriter<ELFT>::outputFileSize() const {
- return _shdrtab->fileOffset() + _shdrtab->fileSize();
-}
-
-template <class ELFT>
-std::error_code OutputELFWriter<ELFT>::writeOutput(const File &file,
- StringRef path) {
-
- ScopedTask createOutputTask(getDefaultDomain(), "ELF Writer Create Output");
- ErrorOr<std::unique_ptr<FileOutputBuffer>> bufferOrErr =
- FileOutputBuffer::create(path, outputFileSize(),
- FileOutputBuffer::F_executable);
- if (std::error_code ec = bufferOrErr.getError())
- return ec;
- std::unique_ptr<FileOutputBuffer> &buffer = *bufferOrErr;
- createOutputTask.end();
-
- ScopedTask writeTask(getDefaultDomain(), "ELF Writer write to memory");
-
- // HACK: We have to write out the header and program header here even though
- // they are a member of a segment because only sections are written in the
- // following loop.
-
- // Finalize ELF Header / Program Headers.
- _elfHeader->finalize();
- _programHeader->finalize();
-
- _elfHeader->write(this, _layout, *buffer);
- _programHeader->write(this, _layout, *buffer);
-
- auto sections = _layout.sections();
- parallel_for_each(
- sections.begin(), sections.end(),
- [&](Chunk<ELFT> *section) { section->write(this, _layout, *buffer); });
- writeTask.end();
-
- ScopedTask commitTask(getDefaultDomain(), "ELF Writer commit to disk");
- return buffer->commit();
-}
-
-template <class ELFT>
-std::error_code OutputELFWriter<ELFT>::writeFile(const File &file,
- StringRef path) {
- if (std::error_code ec = buildOutput(file))
- return ec;
- if (std::error_code ec = setELFHeader())
- return ec;
- return writeOutput(file, path);
-}
-
-template <class ELFT>
-void OutputELFWriter<ELFT>::processUndefinedSymbol(
- StringRef symName, RuntimeFile<ELFT> &file) const {
- if (symName.startswith("__start_")) {
- if (_ctx.cidentSectionNames().count(symName.drop_front(8)))
- file.addAbsoluteAtom(symName);
- } else if (symName.startswith("__stop_")) {
- if (_ctx.cidentSectionNames().count(symName.drop_front(7)))
- file.addAbsoluteAtom(symName);
- }
-}
-
-template <class ELFT>
-void OutputELFWriter<ELFT>::updateScopeAtomValues(StringRef sym,
- StringRef sec) {
- updateScopeAtomValues(("__" + sym + "_start").str().c_str(),
- ("__" + sym + "_end").str().c_str(), sec);
-}
-
-template <class ELFT>
-void OutputELFWriter<ELFT>::updateScopeAtomValues(StringRef start,
- StringRef end,
- StringRef sec) {
- AtomLayout *s = _layout.findAbsoluteAtom(start);
- AtomLayout *e = _layout.findAbsoluteAtom(end);
- const OutputSection<ELFT> *section = _layout.findOutputSection(sec);
- if (s)
- s->_virtualAddr = section ? section->virtualAddr() : 0;
- if (e)
- e->_virtualAddr = section ? section->virtualAddr() + section->memSize() : 0;
-}
-
-template class OutputELFWriter<ELF32LE>;
-template class OutputELFWriter<ELF32BE>;
-template class OutputELFWriter<ELF64LE>;
-template class OutputELFWriter<ELF64BE>;
-
-} // namespace elf
-} // namespace lld
diff --git a/lib/ReaderWriter/ELF/OutputELFWriter.h b/lib/ReaderWriter/ELF/OutputELFWriter.h
deleted file mode 100644
index bb3901010634..000000000000
--- a/lib/ReaderWriter/ELF/OutputELFWriter.h
+++ /dev/null
@@ -1,153 +0,0 @@
-//===- lib/ReaderWriter/ELF/OutputELFWriter.h ----------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_ELF_OUTPUT_WRITER_H
-#define LLD_READER_WRITER_ELF_OUTPUT_WRITER_H
-
-#include "ELFFile.h"
-#include "TargetLayout.h"
-#include "lld/Core/Writer.h"
-#include "llvm/ADT/StringSet.h"
-
-namespace lld {
-class ELFLinkingContext;
-
-namespace elf {
-using namespace llvm;
-using namespace llvm::object;
-
-// OutputELFWriter Class
-//
-/// \brief This acts as the base class for all the ELF writers that are output
-/// for emitting an ELF output file. This class also acts as a common class for
-/// creating static and dynamic executables. All the function in this class
-/// can be overridden and an appropriate writer be created
-template<class ELFT>
-class OutputELFWriter : public ELFWriter {
-public:
- typedef Elf_Shdr_Impl<ELFT> Elf_Shdr;
- typedef Elf_Sym_Impl<ELFT> Elf_Sym;
- typedef Elf_Dyn_Impl<ELFT> Elf_Dyn;
-
- OutputELFWriter(ELFLinkingContext &ctx, TargetLayout<ELFT> &layout);
-
-protected:
- // build the sections that need to be created
- virtual void createDefaultSections();
-
- // Build all the output sections
- void buildChunks(const File &file) override;
-
- // Build the output file
- virtual std::error_code buildOutput(const File &file);
-
- // Setup the ELF header.
- virtual std::error_code setELFHeader();
-
- // Write the file to the path specified
- std::error_code writeFile(const File &File, StringRef path) override;
-
- // Write to the output file.
- virtual std::error_code writeOutput(const File &file, StringRef path);
-
- // Get the size of the output file that the linker would emit.
- virtual uint64_t outputFileSize() const;
-
- // Build the atom to address map, this has to be called
- // before applying relocations
- virtual void buildAtomToAddressMap(const File &file);
-
- // Build the symbol table for static linking
- virtual void buildStaticSymbolTable(const File &file);
-
- // Build the dynamic symbol table for dynamic linking
- virtual void buildDynamicSymbolTable(const File &file);
-
- // Build the section header table
- virtual void buildSectionHeaderTable();
-
- // Assign sections that have no segments such as the symbol table,
- // section header table, string table etc
- virtual void assignSectionsWithNoSegments();
-
- // Add any runtime files and their atoms to the output
- void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
-
- // Finalize the default atom values
- virtual void finalizeDefaultAtomValues();
-
- // This is called by the write section to apply relocations
- uint64_t addressOfAtom(const Atom *atom) override {
- auto addr = _atomToAddressMap.find(atom);
- return addr == _atomToAddressMap.end() ? 0 : addr->second;
- }
-
- // This is a hook for creating default dynamic entries
- virtual void createDefaultDynamicEntries() {}
-
- /// \brief Create symbol table.
- virtual unique_bump_ptr<SymbolTable<ELFT>> createSymbolTable();
-
- /// \brief create dynamic table.
- virtual unique_bump_ptr<DynamicTable<ELFT>> createDynamicTable();
-
- /// \brief create dynamic symbol table.
- virtual unique_bump_ptr<DynamicSymbolTable<ELFT>>
- createDynamicSymbolTable();
-
- /// \brief Create entry in the dynamic symbols table for this atom.
- virtual bool isDynSymEntryRequired(const SharedLibraryAtom *sla) const {
- return _layout.isReferencedByDefinedAtom(sla);
- }
-
- /// \brief Create DT_NEEDED dynamic tage for the shared library.
- virtual bool isNeededTagRequired(const SharedLibraryAtom *sla) const {
- return false;
- }
-
- /// \brief Process undefined symbols that left after resolution step.
- virtual void processUndefinedSymbol(StringRef symName,
- RuntimeFile<ELFT> &file) const;
-
- /// \brief Assign addresses to atoms marking section's start and end.
- void updateScopeAtomValues(StringRef sym, StringRef sec);
-
- llvm::BumpPtrAllocator _alloc;
-
- ELFLinkingContext &_ctx;
- TargetHandler &_targetHandler;
-
- typedef llvm::DenseMap<const Atom *, uint64_t> AtomToAddress;
- AtomToAddress _atomToAddressMap;
- TargetLayout<ELFT> &_layout;
- unique_bump_ptr<ELFHeader<ELFT>> _elfHeader;
- unique_bump_ptr<ProgramHeader<ELFT>> _programHeader;
- unique_bump_ptr<SymbolTable<ELFT>> _symtab;
- unique_bump_ptr<StringTable<ELFT>> _strtab;
- unique_bump_ptr<StringTable<ELFT>> _shstrtab;
- unique_bump_ptr<SectionHeader<ELFT>> _shdrtab;
- unique_bump_ptr<EHFrameHeader<ELFT>> _ehFrameHeader;
- /// \name Dynamic sections.
- /// @{
- unique_bump_ptr<DynamicTable<ELFT>> _dynamicTable;
- unique_bump_ptr<DynamicSymbolTable<ELFT>> _dynamicSymbolTable;
- unique_bump_ptr<StringTable<ELFT>> _dynamicStringTable;
- unique_bump_ptr<HashSection<ELFT>> _hashTable;
- llvm::StringSet<> _soNeeded;
- /// @}
-
-private:
- static StringRef maybeGetSOName(Node *node);
- void updateScopeAtomValues(StringRef start, StringRef end, StringRef sec);
-};
-
-} // namespace elf
-} // namespace lld
-
-#endif // LLD_READER_WRITER_ELF_OUTPUT_WRITER_H
diff --git a/lib/ReaderWriter/ELF/Reader.cpp b/lib/ReaderWriter/ELF/Reader.cpp
deleted file mode 100644
index 801f1abaed7a..000000000000
--- a/lib/ReaderWriter/ELF/Reader.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-//===- lib/ReaderWriter/ELF/Reader.cpp ------------------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// \brief Defines the ELF Reader and all helper sub classes to consume an ELF
-/// file and produces atoms out of it.
-///
-//===----------------------------------------------------------------------===//
-
-#include "ELFReader.h"
-#include <map>
-#include <vector>
-
-using llvm::support::endianness;
-using namespace llvm::object;
-
-namespace lld {
-
-// This dynamic registration of a handler causes support for all ELF
-// architectures to be pulled into the linker. If we want to support making a
-// linker that only supports one ELF architecture, we'd need to change this
-// to have a different registration method for each architecture.
-void Registry::addSupportELFObjects(ELFLinkingContext &ctx) {
-
- // Tell registry about the ELF object file parser.
- add(ctx.getTargetHandler().getObjReader());
-
- // Tell registry about the relocation name to number mapping for this arch.
- ctx.registerRelocationNames(*this);
-}
-
-void Registry::addSupportELFDynamicSharedObjects(ELFLinkingContext &ctx) {
- // Tell registry about the ELF dynamic shared library file parser.
- add(ctx.getTargetHandler().getDSOReader());
-}
-
-} // end namespace lld
diff --git a/lib/ReaderWriter/ELF/SectionChunks.cpp b/lib/ReaderWriter/ELF/SectionChunks.cpp
deleted file mode 100644
index 520fbe24af3b..000000000000
--- a/lib/ReaderWriter/ELF/SectionChunks.cpp
+++ /dev/null
@@ -1,996 +0,0 @@
-//===- lib/ReaderWriter/ELF/SectionChunks.h -------------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "SectionChunks.h"
-#include "TargetLayout.h"
-#include "lld/Core/Parallel.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/Support/Dwarf.h"
-
-namespace lld {
-namespace elf {
-
-template <class ELFT>
-Section<ELFT>::Section(const ELFLinkingContext &ctx, StringRef sectionName,
- StringRef chunkName, typename Chunk<ELFT>::Kind k)
- : Chunk<ELFT>(chunkName, k, ctx), _inputSectionName(sectionName),
- _outputSectionName(sectionName) {}
-
-template <class ELFT> int Section<ELFT>::getContentType() const {
- if (_flags & llvm::ELF::SHF_EXECINSTR)
- return Chunk<ELFT>::ContentType::Code;
- else if (_flags & llvm::ELF::SHF_WRITE)
- return Chunk<ELFT>::ContentType::Data;
- else if (_flags & llvm::ELF::SHF_ALLOC)
- return Chunk<ELFT>::ContentType::Code;
- else
- return Chunk<ELFT>::ContentType::Unknown;
-}
-
-template <class ELFT>
-AtomSection<ELFT>::AtomSection(const ELFLinkingContext &ctx,
- StringRef sectionName, int32_t contentType,
- int32_t permissions, int32_t order)
- : Section<ELFT>(ctx, sectionName, "AtomSection",
- Chunk<ELFT>::Kind::AtomSection),
- _contentType(contentType), _contentPermissions(permissions) {
- this->setOrder(order);
-
- switch (contentType) {
- case DefinedAtom::typeCode:
- case DefinedAtom::typeDataFast:
- case DefinedAtom::typeData:
- case DefinedAtom::typeConstant:
- case DefinedAtom::typeGOT:
- case DefinedAtom::typeStub:
- case DefinedAtom::typeResolver:
- case DefinedAtom::typeThreadData:
- this->_type = SHT_PROGBITS;
- break;
-
- case DefinedAtom::typeThreadZeroFill:
- case DefinedAtom::typeZeroFillFast:
- case DefinedAtom::typeZeroFill:
- this->_type = SHT_NOBITS;
- break;
-
- case DefinedAtom::typeRONote:
- case DefinedAtom::typeRWNote:
- this->_type = SHT_NOTE;
- break;
-
- case DefinedAtom::typeNoAlloc:
- this->_type = SHT_PROGBITS;
- this->_isLoadedInMemory = false;
- break;
- }
-
- switch (permissions) {
- case DefinedAtom::permR__:
- this->_flags = SHF_ALLOC;
- break;
- case DefinedAtom::permR_X:
- this->_flags = SHF_ALLOC | SHF_EXECINSTR;
- break;
- case DefinedAtom::permRW_:
- case DefinedAtom::permRW_L:
- this->_flags = SHF_ALLOC | SHF_WRITE;
- if (_contentType == DefinedAtom::typeThreadData ||
- _contentType == DefinedAtom::typeThreadZeroFill)
- this->_flags |= SHF_TLS;
- break;
- case DefinedAtom::permRWX:
- this->_flags = SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR;
- break;
- case DefinedAtom::perm___:
- this->_flags = 0;
- break;
- }
-}
-
-template <class ELFT>
-void AtomSection<ELFT>::assignVirtualAddress(uint64_t addr) {
- parallel_for_each(_atoms.begin(), _atoms.end(), [&](AtomLayout *ai) {
- ai->_virtualAddr = addr + ai->_fileOffset;
- });
-}
-
-template <class ELFT>
-void AtomSection<ELFT>::assignFileOffsets(uint64_t offset) {
- parallel_for_each(_atoms.begin(), _atoms.end(), [&](AtomLayout *ai) {
- ai->_fileOffset = offset + ai->_fileOffset;
- });
-}
-
-template <class ELFT>
-const AtomLayout *
-AtomSection<ELFT>::findAtomLayoutByName(StringRef name) const {
- for (auto ai : _atoms)
- if (ai->_atom->name() == name)
- return ai;
- return nullptr;
-}
-
-template <class ELFT>
-std::string AtomSection<ELFT>::formatError(const std::string &errorStr,
- const AtomLayout &atom,
- const Reference &ref) const {
- StringRef kindValStr;
- if (!this->_ctx.registry().referenceKindToString(
- ref.kindNamespace(), ref.kindArch(), ref.kindValue(), kindValStr)) {
- kindValStr = "unknown";
- }
-
- return
- (Twine(errorStr) + " in file " + atom._atom->file().path() +
- ": reference from " + atom._atom->name() + "+" +
- Twine(ref.offsetInAtom()) + " to " + ref.target()->name() + "+" +
- Twine(ref.addend()) + " of type " + Twine(ref.kindValue()) + " (" +
- kindValStr + ")\n")
- .str();
-}
-
-/// Align the offset to the required modulus defined by the atom alignment
-template <class ELFT>
-uint64_t AtomSection<ELFT>::alignOffset(uint64_t offset,
- DefinedAtom::Alignment &atomAlign) {
- uint64_t requiredModulus = atomAlign.modulus;
- uint64_t alignment = atomAlign.value;
- uint64_t currentModulus = (offset % alignment);
- uint64_t retOffset = offset;
- if (currentModulus != requiredModulus) {
- if (requiredModulus > currentModulus)
- retOffset += requiredModulus - currentModulus;
- else
- retOffset += alignment + requiredModulus - currentModulus;
- }
- return retOffset;
-}
-
-// \brief Append an atom to a Section. The atom gets pushed into a vector
-// contains the atom, the atom file offset, the atom virtual address
-// the atom file offset is aligned appropriately as set by the Reader
-template <class ELFT>
-const AtomLayout *AtomSection<ELFT>::appendAtom(const Atom *atom) {
- const DefinedAtom *definedAtom = cast<DefinedAtom>(atom);
-
- DefinedAtom::Alignment atomAlign = definedAtom->alignment();
- uint64_t alignment = atomAlign.value;
- // Align the atom to the required modulus/ align the file offset and the
- // memory offset separately this is required so that BSS symbols are handled
- // properly as the BSS symbols only occupy memory size and not file size
- uint64_t fOffset = alignOffset(this->fileSize(), atomAlign);
- uint64_t mOffset = alignOffset(this->memSize(), atomAlign);
- switch (definedAtom->contentType()) {
- case DefinedAtom::typeCode:
- case DefinedAtom::typeConstant:
- case DefinedAtom::typeData:
- case DefinedAtom::typeDataFast:
- case DefinedAtom::typeZeroFillFast:
- case DefinedAtom::typeGOT:
- case DefinedAtom::typeStub:
- case DefinedAtom::typeResolver:
- case DefinedAtom::typeThreadData:
- case DefinedAtom::typeRONote:
- case DefinedAtom::typeRWNote:
- _atoms.push_back(new (_alloc) AtomLayout(atom, fOffset, 0));
- this->_fsize = fOffset + definedAtom->size();
- this->_msize = mOffset + definedAtom->size();
- DEBUG_WITH_TYPE("Section", llvm::dbgs()
- << "[" << this->name() << " " << this << "] "
- << "Adding atom: " << atom->name() << "@"
- << fOffset << "\n");
- break;
- case DefinedAtom::typeNoAlloc:
- _atoms.push_back(new (_alloc) AtomLayout(atom, fOffset, 0));
- this->_fsize = fOffset + definedAtom->size();
- DEBUG_WITH_TYPE("Section", llvm::dbgs()
- << "[" << this->name() << " " << this << "] "
- << "Adding atom: " << atom->name() << "@"
- << fOffset << "\n");
- break;
- case DefinedAtom::typeThreadZeroFill:
- case DefinedAtom::typeZeroFill:
- _atoms.push_back(new (_alloc) AtomLayout(atom, mOffset, 0));
- this->_msize = mOffset + definedAtom->size();
- break;
- default:
- llvm::dbgs() << definedAtom->contentType() << "\n";
- llvm_unreachable("Uexpected content type.");
- }
- // Set the section alignment to the largest alignment
- // std::max doesn't support uint64_t
- if (this->_alignment < alignment)
- this->_alignment = alignment;
-
- if (_atoms.size())
- return _atoms.back();
- return nullptr;
-}
-
-/// \brief convert the segment type to a String for diagnostics
-/// and printing purposes
-template <class ELFT> StringRef Section<ELFT>::segmentKindToStr() const {
- switch (_segmentType) {
- case llvm::ELF::PT_DYNAMIC:
- return "DYNAMIC";
- case llvm::ELF::PT_INTERP:
- return "INTERP";
- case llvm::ELF::PT_LOAD:
- return "LOAD";
- case llvm::ELF::PT_GNU_EH_FRAME:
- return "EH_FRAME";
- case llvm::ELF::PT_GNU_RELRO:
- return "GNU_RELRO";
- case llvm::ELF::PT_NOTE:
- return "NOTE";
- case llvm::ELF::PT_NULL:
- return "NULL";
- case llvm::ELF::PT_TLS:
- return "TLS";
- default:
- return "UNKNOWN";
- }
-}
-
-/// \brief Write the section and the atom contents to the buffer
-template <class ELFT>
-void AtomSection<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout,
- llvm::FileOutputBuffer &buffer) {
- uint8_t *chunkBuffer = buffer.getBufferStart();
- bool success = true;
-
- // parallel_for_each() doesn't have deterministic order. To guarantee
- // deterministic error output, collect errors in this vector and sort it
- // by atom file offset before printing all errors.
- std::vector<std::pair<size_t, std::string>> errors;
- parallel_for_each(_atoms.begin(), _atoms.end(), [&](AtomLayout *ai) {
- DEBUG_WITH_TYPE("Section", llvm::dbgs()
- << "Writing atom: " << ai->_atom->name()
- << " | " << ai->_fileOffset << "\n");
- const DefinedAtom *definedAtom = cast<DefinedAtom>(ai->_atom);
- if (!definedAtom->occupiesDiskSpace())
- return;
- // Copy raw content of atom to file buffer.
- ArrayRef<uint8_t> content = definedAtom->rawContent();
- uint64_t contentSize = content.size();
- if (contentSize == 0)
- return;
- uint8_t *atomContent = chunkBuffer + ai->_fileOffset;
- std::memcpy(atomContent, content.data(), contentSize);
- const TargetRelocationHandler &relHandler =
- this->_ctx.getTargetHandler().getRelocationHandler();
- for (const auto ref : *definedAtom) {
- if (std::error_code ec =
- relHandler.applyRelocation(*writer, buffer, *ai, *ref)) {
- std::lock_guard<std::mutex> lock(_outputMutex);
- errors.push_back(std::make_pair(ai->_fileOffset,
- formatError(ec.message(), *ai, *ref)));
- success = false;
- }
- }
- });
- if (!success) {
- std::sort(errors.begin(), errors.end());
- for (auto &&error : errors)
- llvm::errs() << error.second;
- llvm::report_fatal_error("relocating output");
- }
-}
-
-template <class ELFT>
-void OutputSection<ELFT>::appendSection(Section<ELFT> *section) {
- if (section->alignment() > _alignment)
- _alignment = section->alignment();
- assert(!_link && "Section already has a link!");
- _link = section->getLink();
- _shInfo = section->getInfo();
- _entSize = section->getEntSize();
- _type = section->getType();
- if (_flags < section->getFlags())
- _flags = section->getFlags();
- section->setOutputSection(this, (_sections.size() == 0));
- _kind = section->kind();
- _sections.push_back(section);
-}
-
-template <class ELFT>
-StringTable<ELFT>::StringTable(const ELFLinkingContext &ctx, const char *str,
- int32_t order, bool dynamic)
- : Section<ELFT>(ctx, str, "StringTable") {
- // the string table has a NULL entry for which
- // add an empty string
- _strings.push_back("");
- this->_fsize = 1;
- this->_alignment = 1;
- this->setOrder(order);
- this->_type = SHT_STRTAB;
- if (dynamic) {
- this->_flags = SHF_ALLOC;
- this->_msize = this->_fsize;
- }
-}
-
-template <class ELFT> uint64_t StringTable<ELFT>::addString(StringRef symname) {
- if (symname.empty())
- return 0;
- StringMapTIter stringIter = _stringMap.find(symname);
- if (stringIter == _stringMap.end()) {
- _strings.push_back(symname);
- uint64_t offset = this->_fsize;
- this->_fsize += symname.size() + 1;
- if (this->_flags & SHF_ALLOC)
- this->_msize = this->_fsize;
- _stringMap[symname] = offset;
- return offset;
- }
- return stringIter->second;
-}
-
-template <class ELFT>
-void StringTable<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &,
- llvm::FileOutputBuffer &buffer) {
- uint8_t *chunkBuffer = buffer.getBufferStart();
- uint8_t *dest = chunkBuffer + this->fileOffset();
- for (auto si : _strings) {
- memcpy(dest, si.data(), si.size());
- dest += si.size();
- memcpy(dest, "", 1);
- dest += 1;
- }
-}
-
-/// ELF Symbol Table
-template <class ELFT>
-SymbolTable<ELFT>::SymbolTable(const ELFLinkingContext &ctx, const char *str,
- int32_t order)
- : Section<ELFT>(ctx, str, "SymbolTable") {
- this->setOrder(order);
- Elf_Sym symbol;
- std::memset(&symbol, 0, sizeof(Elf_Sym));
- _symbolTable.push_back(SymbolEntry(nullptr, symbol, nullptr));
- this->_entSize = sizeof(Elf_Sym);
- this->_fsize = sizeof(Elf_Sym);
- this->_alignment = sizeof(Elf_Addr);
- this->_type = SHT_SYMTAB;
-}
-
-template <class ELFT>
-void SymbolTable<ELFT>::addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da,
- int64_t addr) {
- unsigned char binding = 0, type = 0;
- sym.st_size = da->size();
- DefinedAtom::ContentType ct;
- switch (ct = da->contentType()) {
- case DefinedAtom::typeCode:
- case DefinedAtom::typeStub:
- sym.st_value = addr;
- type = llvm::ELF::STT_FUNC;
- break;
- case DefinedAtom::typeResolver:
- sym.st_value = addr;
- type = llvm::ELF::STT_GNU_IFUNC;
- break;
- case DefinedAtom::typeDataFast:
- case DefinedAtom::typeData:
- case DefinedAtom::typeConstant:
- sym.st_value = addr;
- type = llvm::ELF::STT_OBJECT;
- break;
- case DefinedAtom::typeGOT:
- sym.st_value = addr;
- type = llvm::ELF::STT_NOTYPE;
- break;
- case DefinedAtom::typeZeroFill:
- case DefinedAtom::typeZeroFillFast:
- type = llvm::ELF::STT_OBJECT;
- sym.st_value = addr;
- break;
- case DefinedAtom::typeThreadData:
- case DefinedAtom::typeThreadZeroFill:
- type = llvm::ELF::STT_TLS;
- sym.st_value = addr;
- break;
- default:
- type = llvm::ELF::STT_NOTYPE;
- }
- if (da->customSectionName() == da->name())
- type = llvm::ELF::STT_SECTION;
-
- if (da->scope() == DefinedAtom::scopeTranslationUnit)
- binding = llvm::ELF::STB_LOCAL;
- else
- binding = llvm::ELF::STB_GLOBAL;
-
- sym.setBindingAndType(binding, type);
-}
-
-template <class ELFT>
-void SymbolTable<ELFT>::addAbsoluteAtom(Elf_Sym &sym, const AbsoluteAtom *aa,
- int64_t addr) {
- unsigned char binding = 0, type = 0;
- type = llvm::ELF::STT_OBJECT;
- sym.st_shndx = llvm::ELF::SHN_ABS;
- switch (aa->scope()) {
- case AbsoluteAtom::scopeLinkageUnit:
- sym.setVisibility(llvm::ELF::STV_HIDDEN);
- binding = llvm::ELF::STB_LOCAL;
- break;
- case AbsoluteAtom::scopeTranslationUnit:
- binding = llvm::ELF::STB_LOCAL;
- break;
- case AbsoluteAtom::scopeGlobal:
- binding = llvm::ELF::STB_GLOBAL;
- break;
- }
- sym.st_value = addr;
- sym.setBindingAndType(binding, type);
-}
-
-template <class ELFT>
-void SymbolTable<ELFT>::addSharedLibAtom(Elf_Sym &sym,
- const SharedLibraryAtom *aa) {
- unsigned char binding = 0, type = 0;
- if (aa->type() == SharedLibraryAtom::Type::Data) {
- type = llvm::ELF::STT_OBJECT;
- sym.st_size = aa->size();
- } else
- type = llvm::ELF::STT_FUNC;
- sym.st_shndx = llvm::ELF::SHN_UNDEF;
- binding = llvm::ELF::STB_GLOBAL;
- sym.setBindingAndType(binding, type);
-}
-
-template <class ELFT>
-void SymbolTable<ELFT>::addUndefinedAtom(Elf_Sym &sym,
- const UndefinedAtom *ua) {
- unsigned char binding = 0, type = 0;
- sym.st_value = 0;
- type = llvm::ELF::STT_NOTYPE;
- if (ua->canBeNull())
- binding = llvm::ELF::STB_WEAK;
- else
- binding = llvm::ELF::STB_GLOBAL;
- sym.setBindingAndType(binding, type);
-}
-
-/// Add a symbol to the symbol Table, definedAtoms which get added to the symbol
-/// section don't have their virtual addresses set at the time of adding the
-/// symbol to the symbol table(Example: dynamic symbols), the addresses needs
-/// to be updated in the table before writing the dynamic symbol table
-/// information
-template <class ELFT>
-void SymbolTable<ELFT>::addSymbol(const Atom *atom, int32_t sectionIndex,
- uint64_t addr, const AtomLayout *atomLayout) {
- Elf_Sym symbol;
-
- if (atom->name().empty())
- return;
-
- symbol.st_name = _stringSection->addString(atom->name());
- symbol.st_size = 0;
- symbol.st_shndx = sectionIndex;
- symbol.st_value = 0;
- symbol.st_other = 0;
- symbol.setVisibility(llvm::ELF::STV_DEFAULT);
-
- // Add all the atoms
- if (const DefinedAtom *da = dyn_cast<const DefinedAtom>(atom))
- addDefinedAtom(symbol, da, addr);
- else if (const AbsoluteAtom *aa = dyn_cast<const AbsoluteAtom>(atom))
- addAbsoluteAtom(symbol, aa, addr);
- else if (isa<const SharedLibraryAtom>(atom))
- addSharedLibAtom(symbol, dyn_cast<SharedLibraryAtom>(atom));
- else
- addUndefinedAtom(symbol, dyn_cast<UndefinedAtom>(atom));
-
- // If --discard-all is on, don't add to the symbol table
- // symbols with local binding.
- if (this->_ctx.discardLocals() && symbol.getBinding() == llvm::ELF::STB_LOCAL)
- return;
-
- // Temporary locals are all the symbols which name starts with .L.
- // This is defined by the ELF standard.
- if (this->_ctx.discardTempLocals() && atom->name().startswith(".L"))
- return;
-
- _symbolTable.push_back(SymbolEntry(atom, symbol, atomLayout));
- this->_fsize += sizeof(Elf_Sym);
- if (this->_flags & SHF_ALLOC)
- this->_msize = this->_fsize;
-}
-
-template <class ELFT> void SymbolTable<ELFT>::finalize(bool sort) {
- // sh_info should be one greater than last symbol with STB_LOCAL binding
- // we sort the symbol table to keep all local symbols at the beginning
- if (sort)
- sortSymbols();
-
- uint16_t shInfo = 0;
- for (const auto &i : _symbolTable) {
- if (i._symbol.getBinding() != llvm::ELF::STB_LOCAL)
- break;
- shInfo++;
- }
- this->_info = shInfo;
- this->_link = _stringSection->ordinal();
- if (this->_outputSection) {
- this->_outputSection->setInfo(this->_info);
- this->_outputSection->setLink(this->_link);
- }
-}
-
-template <class ELFT>
-void SymbolTable<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &,
- llvm::FileOutputBuffer &buffer) {
- uint8_t *chunkBuffer = buffer.getBufferStart();
- uint8_t *dest = chunkBuffer + this->fileOffset();
- for (const auto &sti : _symbolTable) {
- memcpy(dest, &sti._symbol, sizeof(Elf_Sym));
- dest += sizeof(Elf_Sym);
- }
-}
-
-template <class ELFT>
-DynamicSymbolTable<ELFT>::DynamicSymbolTable(const ELFLinkingContext &ctx,
- TargetLayout<ELFT> &layout,
- const char *str, int32_t order)
- : SymbolTable<ELFT>(ctx, str, order), _layout(layout) {
- this->_type = SHT_DYNSYM;
- this->_flags = SHF_ALLOC;
- this->_msize = this->_fsize;
-}
-
-template <class ELFT> void DynamicSymbolTable<ELFT>::addSymbolsToHashTable() {
- int index = 0;
- for (auto &ste : this->_symbolTable) {
- if (!ste._atom)
- _hashTable->addSymbol("", index);
- else
- _hashTable->addSymbol(ste._atom->name(), index);
- ++index;
- }
-}
-
-template <class ELFT> void DynamicSymbolTable<ELFT>::finalize() {
- // Defined symbols which have been added into the dynamic symbol table
- // don't have their addresses known until addresses have been assigned
- // so let's update the symbol values after they have got assigned
- for (auto &ste : this->_symbolTable) {
- const AtomLayout *atomLayout = ste._atomLayout;
- if (!atomLayout)
- continue;
- ste._symbol.st_value = atomLayout->_virtualAddr;
- }
-
- // Don't sort the symbols
- SymbolTable<ELFT>::finalize(false);
-}
-
-template <class ELFT>
-RelocationTable<ELFT>::RelocationTable(const ELFLinkingContext &ctx,
- StringRef str, int32_t order)
- : Section<ELFT>(ctx, str, "RelocationTable") {
- this->setOrder(order);
- this->_flags = SHF_ALLOC;
- // Set the alignment properly depending on the target architecture
- this->_alignment = ELFT::Is64Bits ? 8 : 4;
- if (ctx.isRelaOutputFormat()) {
- this->_entSize = sizeof(Elf_Rela);
- this->_type = SHT_RELA;
- } else {
- this->_entSize = sizeof(Elf_Rel);
- this->_type = SHT_REL;
- }
-}
-
-template <class ELFT>
-uint32_t RelocationTable<ELFT>::addRelocation(const DefinedAtom &da,
- const Reference &r) {
- _relocs.emplace_back(&da, &r);
- this->_fsize = _relocs.size() * this->_entSize;
- this->_msize = this->_fsize;
- return _relocs.size() - 1;
-}
-
-template <class ELFT>
-bool RelocationTable<ELFT>::getRelocationIndex(const Reference &r,
- uint32_t &res) {
- auto rel = std::find_if(
- _relocs.begin(), _relocs.end(),
- [&](const std::pair<const DefinedAtom *, const Reference *> &p) {
- if (p.second == &r)
- return true;
- return false;
- });
- if (rel == _relocs.end())
- return false;
- res = std::distance(_relocs.begin(), rel);
- return true;
-}
-
-template <class ELFT>
-bool RelocationTable<ELFT>::canModifyReadonlySection() const {
- for (const auto &rel : _relocs) {
- const DefinedAtom *atom = rel.first;
- if ((atom->permissions() & DefinedAtom::permRW_) != DefinedAtom::permRW_)
- return true;
- }
- return false;
-}
-
-template <class ELFT> void RelocationTable<ELFT>::finalize() {
- this->_link = _symbolTable ? _symbolTable->ordinal() : 0;
- if (this->_outputSection)
- this->_outputSection->setLink(this->_link);
-}
-
-template <class ELFT>
-void RelocationTable<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout,
- llvm::FileOutputBuffer &buffer) {
- uint8_t *chunkBuffer = buffer.getBufferStart();
- uint8_t *dest = chunkBuffer + this->fileOffset();
- for (const auto &rel : _relocs) {
- if (this->_ctx.isRelaOutputFormat()) {
- auto &r = *reinterpret_cast<Elf_Rela *>(dest);
- writeRela(writer, r, *rel.first, *rel.second);
- DEBUG_WITH_TYPE("ELFRelocationTable",
- llvm::dbgs()
- << rel.second->kindValue() << " relocation at "
- << rel.first->name() << "@" << r.r_offset << " to "
- << rel.second->target()->name() << "@" << r.r_addend
- << "\n";);
- } else {
- auto &r = *reinterpret_cast<Elf_Rel *>(dest);
- writeRel(writer, r, *rel.first, *rel.second);
- DEBUG_WITH_TYPE("ELFRelocationTable",
- llvm::dbgs() << rel.second->kindValue()
- << " relocation at " << rel.first->name()
- << "@" << r.r_offset << " to "
- << rel.second->target()->name() << "\n";);
- }
- dest += this->_entSize;
- }
-}
-
-template <class ELFT>
-void RelocationTable<ELFT>::writeRela(ELFWriter *writer, Elf_Rela &r,
- const DefinedAtom &atom,
- const Reference &ref) {
- r.setSymbolAndType(getSymbolIndex(ref.target()), ref.kindValue(), false);
- r.r_offset = writer->addressOfAtom(&atom) + ref.offsetInAtom();
- // The addend is used only by relative relocations
- if (this->_ctx.isRelativeReloc(ref))
- r.r_addend = writer->addressOfAtom(ref.target()) + ref.addend();
- else
- r.r_addend = 0;
-}
-
-template <class ELFT>
-void RelocationTable<ELFT>::writeRel(ELFWriter *writer, Elf_Rel &r,
- const DefinedAtom &atom,
- const Reference &ref) {
- r.setSymbolAndType(getSymbolIndex(ref.target()), ref.kindValue(), false);
- r.r_offset = writer->addressOfAtom(&atom) + ref.offsetInAtom();
-}
-
-template <class ELFT>
-uint32_t RelocationTable<ELFT>::getSymbolIndex(const Atom *a) {
- return _symbolTable ? _symbolTable->getSymbolTableIndex(a)
- : (uint32_t)STN_UNDEF;
-}
-
-template <class ELFT>
-DynamicTable<ELFT>::DynamicTable(const ELFLinkingContext &ctx,
- TargetLayout<ELFT> &layout, StringRef str,
- int32_t order)
- : Section<ELFT>(ctx, str, "DynamicSection"), _layout(layout) {
- this->setOrder(order);
- this->_entSize = sizeof(Elf_Dyn);
- this->_alignment = ELFT::Is64Bits ? 8 : 4;
- // Reserve space for the DT_NULL entry.
- this->_fsize = sizeof(Elf_Dyn);
- this->_msize = sizeof(Elf_Dyn);
- this->_type = SHT_DYNAMIC;
- this->_flags = SHF_ALLOC;
-}
-
-template <class ELFT>
-std::size_t DynamicTable<ELFT>::addEntry(int64_t tag, uint64_t val) {
- Elf_Dyn dyn;
- dyn.d_tag = tag;
- dyn.d_un.d_val = val;
- _entries.push_back(dyn);
- this->_fsize = (_entries.size() * sizeof(Elf_Dyn)) + sizeof(Elf_Dyn);
- this->_msize = this->_fsize;
- return _entries.size() - 1;
-}
-
-template <class ELFT>
-void DynamicTable<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout,
- llvm::FileOutputBuffer &buffer) {
- uint8_t *chunkBuffer = buffer.getBufferStart();
- uint8_t *dest = chunkBuffer + this->fileOffset();
- // Add the null entry.
- Elf_Dyn d;
- d.d_tag = 0;
- d.d_un.d_val = 0;
- _entries.push_back(d);
- std::memcpy(dest, _entries.data(), this->_fsize);
-}
-
-template <class ELFT> void DynamicTable<ELFT>::createDefaultEntries() {
- bool isRela = this->_ctx.isRelaOutputFormat();
- _dt_hash = addEntry(DT_HASH, 0);
- _dt_strtab = addEntry(DT_STRTAB, 0);
- _dt_symtab = addEntry(DT_SYMTAB, 0);
- _dt_strsz = addEntry(DT_STRSZ, 0);
- _dt_syment = addEntry(DT_SYMENT, 0);
- if (_layout.hasDynamicRelocationTable()) {
- _dt_rela = addEntry(isRela ? DT_RELA : DT_REL, 0);
- _dt_relasz = addEntry(isRela ? DT_RELASZ : DT_RELSZ, 0);
- _dt_relaent = addEntry(isRela ? DT_RELAENT : DT_RELENT, 0);
- if (_layout.getDynamicRelocationTable()->canModifyReadonlySection())
- _dt_textrel = addEntry(DT_TEXTREL, 0);
- }
- if (_layout.hasPLTRelocationTable()) {
- _dt_pltrelsz = addEntry(DT_PLTRELSZ, 0);
- _dt_pltgot = addEntry(getGotPltTag(), 0);
- _dt_pltrel = addEntry(DT_PLTREL, isRela ? DT_RELA : DT_REL);
- _dt_jmprel = addEntry(DT_JMPREL, 0);
- }
-}
-
-template <class ELFT> void DynamicTable<ELFT>::doPreFlight() {
- auto initArray = _layout.findOutputSection(".init_array");
- auto finiArray = _layout.findOutputSection(".fini_array");
- if (initArray) {
- _dt_init_array = addEntry(DT_INIT_ARRAY, 0);
- _dt_init_arraysz = addEntry(DT_INIT_ARRAYSZ, 0);
- }
- if (finiArray) {
- _dt_fini_array = addEntry(DT_FINI_ARRAY, 0);
- _dt_fini_arraysz = addEntry(DT_FINI_ARRAYSZ, 0);
- }
- if (getInitAtomLayout())
- _dt_init = addEntry(DT_INIT, 0);
- if (getFiniAtomLayout())
- _dt_fini = addEntry(DT_FINI, 0);
-}
-
-template <class ELFT> void DynamicTable<ELFT>::finalize() {
- StringTable<ELFT> *dynamicStringTable = _dynamicSymbolTable->getStringTable();
- this->_link = dynamicStringTable->ordinal();
- if (this->_outputSection) {
- this->_outputSection->setType(this->_type);
- this->_outputSection->setInfo(this->_info);
- this->_outputSection->setLink(this->_link);
- }
-}
-
-template <class ELFT> void DynamicTable<ELFT>::updateDynamicTable() {
- StringTable<ELFT> *dynamicStringTable = _dynamicSymbolTable->getStringTable();
- _entries[_dt_hash].d_un.d_val = _hashTable->virtualAddr();
- _entries[_dt_strtab].d_un.d_val = dynamicStringTable->virtualAddr();
- _entries[_dt_symtab].d_un.d_val = _dynamicSymbolTable->virtualAddr();
- _entries[_dt_strsz].d_un.d_val = dynamicStringTable->memSize();
- _entries[_dt_syment].d_un.d_val = _dynamicSymbolTable->getEntSize();
- auto initArray = _layout.findOutputSection(".init_array");
- if (initArray) {
- _entries[_dt_init_array].d_un.d_val = initArray->virtualAddr();
- _entries[_dt_init_arraysz].d_un.d_val = initArray->memSize();
- }
- auto finiArray = _layout.findOutputSection(".fini_array");
- if (finiArray) {
- _entries[_dt_fini_array].d_un.d_val = finiArray->virtualAddr();
- _entries[_dt_fini_arraysz].d_un.d_val = finiArray->memSize();
- }
- if (const auto *al = getInitAtomLayout())
- _entries[_dt_init].d_un.d_val = getAtomVirtualAddress(al);
- if (const auto *al = getFiniAtomLayout())
- _entries[_dt_fini].d_un.d_val = getAtomVirtualAddress(al);
- if (_layout.hasDynamicRelocationTable()) {
- auto relaTbl = _layout.getDynamicRelocationTable();
- _entries[_dt_rela].d_un.d_val = relaTbl->virtualAddr();
- _entries[_dt_relasz].d_un.d_val = relaTbl->memSize();
- _entries[_dt_relaent].d_un.d_val = relaTbl->getEntSize();
- }
- if (_layout.hasPLTRelocationTable()) {
- auto relaTbl = _layout.getPLTRelocationTable();
- _entries[_dt_jmprel].d_un.d_val = relaTbl->virtualAddr();
- _entries[_dt_pltrelsz].d_un.d_val = relaTbl->memSize();
- auto gotplt = _layout.findOutputSection(".got.plt");
- _entries[_dt_pltgot].d_un.d_val = gotplt->virtualAddr();
- }
-}
-
-template <class ELFT>
-const AtomLayout *DynamicTable<ELFT>::getInitAtomLayout() {
- auto al = _layout.findAtomLayoutByName(this->_ctx.initFunction());
- if (al && isa<DefinedAtom>(al->_atom))
- return al;
- return nullptr;
-}
-
-template <class ELFT>
-const AtomLayout *DynamicTable<ELFT>::getFiniAtomLayout() {
- auto al = _layout.findAtomLayoutByName(this->_ctx.finiFunction());
- if (al && isa<DefinedAtom>(al->_atom))
- return al;
- return nullptr;
-}
-
-template <class ELFT>
-InterpSection<ELFT>::InterpSection(const ELFLinkingContext &ctx, StringRef str,
- int32_t order, StringRef interp)
- : Section<ELFT>(ctx, str, "Dynamic:Interp"), _interp(interp) {
- this->setOrder(order);
- this->_alignment = 1;
- // + 1 for null term.
- this->_fsize = interp.size() + 1;
- this->_msize = this->_fsize;
- this->_type = SHT_PROGBITS;
- this->_flags = SHF_ALLOC;
-}
-
-template <class ELFT>
-void InterpSection<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout,
- llvm::FileOutputBuffer &buffer) {
- uint8_t *chunkBuffer = buffer.getBufferStart();
- uint8_t *dest = chunkBuffer + this->fileOffset();
- std::memcpy(dest, _interp.data(), _interp.size());
-}
-
-template <class ELFT>
-HashSection<ELFT>::HashSection(const ELFLinkingContext &ctx, StringRef name,
- int32_t order)
- : Section<ELFT>(ctx, name, "Dynamic:Hash") {
- this->setOrder(order);
- this->_entSize = 4;
- this->_type = SHT_HASH;
- this->_flags = SHF_ALLOC;
- this->_alignment = ELFT::Is64Bits ? 8 : 4;
- this->_fsize = 0;
- this->_msize = 0;
-}
-
-template <class ELFT>
-void HashSection<ELFT>::addSymbol(StringRef name, uint32_t index) {
- SymbolTableEntry ste;
- ste._name = name;
- ste._index = index;
- _entries.push_back(ste);
-}
-
-/// \brief Set the dynamic symbol table
-template <class ELFT>
-void HashSection<ELFT>::setSymbolTable(
- const DynamicSymbolTable<ELFT> *symbolTable) {
- _symbolTable = symbolTable;
-}
-
-template <class ELFT> void HashSection<ELFT>::doPreFlight() {
- // The number of buckets to use for a certain number of symbols.
- // If there are less than 3 symbols, 1 bucket will be used. If
- // there are less than 17 symbols, 3 buckets will be used, and so
- // forth. The bucket numbers are defined by GNU ld. We use the
- // same rules here so we generate hash sections with the same
- // size as those generated by GNU ld.
- uint32_t hashBuckets[] = {1, 3, 17, 37, 67, 97, 131,
- 197, 263, 521, 1031, 2053, 4099, 8209,
- 16411, 32771, 65537, 131101, 262147};
- int hashBucketsCount = sizeof(hashBuckets) / sizeof(uint32_t);
-
- unsigned int bucketsCount = 0;
- unsigned int dynSymCount = _entries.size();
-
- // Get the number of buckes that we want to use
- for (int i = 0; i < hashBucketsCount; ++i) {
- if (dynSymCount < hashBuckets[i])
- break;
- bucketsCount = hashBuckets[i];
- }
- _buckets.resize(bucketsCount);
- _chains.resize(_entries.size());
-
- // Create the hash table for the dynamic linker
- for (auto ai : _entries) {
- unsigned int dynsymIndex = ai._index;
- unsigned int bucketpos = llvm::object::elf_hash(ai._name) % bucketsCount;
- _chains[dynsymIndex] = _buckets[bucketpos];
- _buckets[bucketpos] = dynsymIndex;
- }
-
- this->_fsize = (2 + _chains.size() + _buckets.size()) * sizeof(uint32_t);
- this->_msize = this->_fsize;
-}
-
-template <class ELFT> void HashSection<ELFT>::finalize() {
- this->_link = _symbolTable ? _symbolTable->ordinal() : 0;
- if (this->_outputSection)
- this->_outputSection->setLink(this->_link);
-}
-
-template <class ELFT>
-void HashSection<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout,
- llvm::FileOutputBuffer &buffer) {
- uint8_t *chunkBuffer = buffer.getBufferStart();
- uint8_t *dest = chunkBuffer + this->fileOffset();
- Elf_Word bucketChainCounts[2];
- bucketChainCounts[0] = _buckets.size();
- bucketChainCounts[1] = _chains.size();
- std::memcpy(dest, bucketChainCounts, sizeof(bucketChainCounts));
- dest += sizeof(bucketChainCounts);
- // write bucket values
- std::memcpy(dest, _buckets.data(), _buckets.size() * sizeof(Elf_Word));
- dest += _buckets.size() * sizeof(Elf_Word);
- // write chain values
- std::memcpy(dest, _chains.data(), _chains.size() * sizeof(Elf_Word));
-}
-
-template <class ELFT>
-EHFrameHeader<ELFT>::EHFrameHeader(const ELFLinkingContext &ctx, StringRef name,
- TargetLayout<ELFT> &layout, int32_t order)
- : Section<ELFT>(ctx, name, "EHFrameHeader"), _layout(layout) {
- this->setOrder(order);
- this->_entSize = 0;
- this->_type = SHT_PROGBITS;
- this->_flags = SHF_ALLOC;
- this->_alignment = ELFT::Is64Bits ? 8 : 4;
- // Minimum size for empty .eh_frame_hdr.
- this->_fsize = 1 + 1 + 1 + 1 + 4;
- this->_msize = this->_fsize;
-}
-
-template <class ELFT> void EHFrameHeader<ELFT>::doPreFlight() {
- // TODO: Generate a proper binary search table.
-}
-
-template <class ELFT> void EHFrameHeader<ELFT>::finalize() {
- OutputSection<ELFT> *s = _layout.findOutputSection(".eh_frame");
- OutputSection<ELFT> *h = _layout.findOutputSection(".eh_frame_hdr");
- if (s && h)
- _ehFrameOffset = s->virtualAddr() - (h->virtualAddr() + 4);
-}
-
-template <class ELFT>
-void EHFrameHeader<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout,
- llvm::FileOutputBuffer &buffer) {
- uint8_t *chunkBuffer = buffer.getBufferStart();
- uint8_t *dest = chunkBuffer + this->fileOffset();
- int pos = 0;
- dest[pos++] = 1; // version
- dest[pos++] = llvm::dwarf::DW_EH_PE_pcrel |
- llvm::dwarf::DW_EH_PE_sdata4; // eh_frame_ptr_enc
- dest[pos++] = llvm::dwarf::DW_EH_PE_omit; // fde_count_enc
- dest[pos++] = llvm::dwarf::DW_EH_PE_omit; // table_enc
- *reinterpret_cast<typename llvm::object::ELFFile<ELFT>::Elf_Sword *>(
- dest + pos) = _ehFrameOffset;
-}
-
-#define INSTANTIATE(klass) \
- template class klass<ELF32LE>; \
- template class klass<ELF32BE>; \
- template class klass<ELF64LE>; \
- template class klass<ELF64BE>
-
-INSTANTIATE(AtomSection);
-INSTANTIATE(DynamicSymbolTable);
-INSTANTIATE(DynamicTable);
-INSTANTIATE(EHFrameHeader);
-INSTANTIATE(HashSection);
-INSTANTIATE(InterpSection);
-INSTANTIATE(OutputSection);
-INSTANTIATE(RelocationTable);
-INSTANTIATE(Section);
-INSTANTIATE(StringTable);
-INSTANTIATE(SymbolTable);
-
-} // end namespace elf
-} // end namespace lld
diff --git a/lib/ReaderWriter/ELF/SectionChunks.h b/lib/ReaderWriter/ELF/SectionChunks.h
deleted file mode 100644
index b10ba05237ff..000000000000
--- a/lib/ReaderWriter/ELF/SectionChunks.h
+++ /dev/null
@@ -1,616 +0,0 @@
-//===- lib/ReaderWriter/ELF/SectionChunks.h -------------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_ELF_SECTION_CHUNKS_H
-#define LLD_READER_WRITER_ELF_SECTION_CHUNKS_H
-
-#include "Chunk.h"
-#include "TargetHandler.h"
-#include "Writer.h"
-#include "lld/Core/DefinedAtom.h"
-#include "lld/Core/range.h"
-#include "lld/ReaderWriter/AtomLayout.h"
-#include "lld/ReaderWriter/ELFLinkingContext.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/Object/ELF.h"
-#include "llvm/Support/Allocator.h"
-#include "llvm/Support/ELF.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/FileOutputBuffer.h"
-#include <memory>
-#include <mutex>
-
-namespace lld {
-namespace elf {
-template <class> class OutputSection;
-using namespace llvm::ELF;
-template <class ELFT> class Segment;
-template <class ELFT> class TargetLayout;
-
-/// \brief An ELF section.
-template <class ELFT> class Section : public Chunk<ELFT> {
-public:
- Section(const ELFLinkingContext &ctx, StringRef sectionName,
- StringRef chunkName,
- typename Chunk<ELFT>::Kind k = Chunk<ELFT>::Kind::ELFSection);
-
- /// \brief Modify the section contents before assigning virtual addresses
- // or assigning file offsets
-
- /// \brief Finalize the section contents before writing
-
- /// \brief Does this section have an output segment.
- virtual bool hasOutputSegment() const { return false; }
-
- /// Return if the section is a loadable section that occupies memory
- virtual bool isLoadableSection() const { return false; }
-
- /// \brief Assign file offsets starting at offset.
- virtual void assignFileOffsets(uint64_t offset) {}
-
- /// \brief Assign virtual addresses starting at addr.
- virtual void assignVirtualAddress(uint64_t addr) {}
-
- uint64_t getFlags() const { return _flags; }
- uint64_t getEntSize() const { return _entSize; }
- uint32_t getType() const { return _type; }
- uint32_t getLink() const { return _link; }
- uint32_t getInfo() const { return _info; }
-
- typename TargetLayout<ELFT>::SegmentType getSegmentType() const {
- return _segmentType;
- }
-
- /// \brief Return the type of content that the section contains
- int getContentType() const override;
-
- /// \brief convert the segment type to a String for diagnostics and printing
- /// purposes
- virtual StringRef segmentKindToStr() const;
-
- /// \brief Records the segmentType, that this section belongs to
- void
- setSegmentType(const typename TargetLayout<ELFT>::SegmentType segmentType) {
- this->_segmentType = segmentType;
- }
-
- virtual const AtomLayout *findAtomLayoutByName(StringRef) const {
- return nullptr;
- }
-
- const OutputSection<ELFT> *getOutputSection() const {
- return _outputSection;
- }
-
- void setOutputSection(OutputSection<ELFT> *os, bool isFirst = false) {
- _outputSection = os;
- _isFirstSectionInOutputSection = isFirst;
- }
-
- static bool classof(const Chunk<ELFT> *c) {
- return c->kind() == Chunk<ELFT>::Kind::ELFSection ||
- c->kind() == Chunk<ELFT>::Kind::AtomSection;
- }
-
- uint64_t alignment() const override {
- return _isFirstSectionInOutputSection ? _outputSection->alignment()
- : this->_alignment;
- }
-
- virtual StringRef inputSectionName() const { return _inputSectionName; }
-
- virtual StringRef outputSectionName() const { return _outputSectionName; }
-
- virtual void setOutputSectionName(StringRef outputSectionName) {
- _outputSectionName = outputSectionName;
- }
-
- void setArchiveNameOrPath(StringRef name) { _archivePath = name; }
-
- void setMemberNameOrPath(StringRef name) { _memberPath = name; }
-
- StringRef archivePath() { return _archivePath; }
-
- StringRef memberPath() { return _memberPath; }
-
-protected:
- /// \brief OutputSection this Section is a member of, or nullptr.
- OutputSection<ELFT> *_outputSection = nullptr;
- /// \brief ELF SHF_* flags.
- uint64_t _flags = 0;
- /// \brief The size of each entity.
- uint64_t _entSize = 0;
- /// \brief ELF SHT_* type.
- uint32_t _type = 0;
- /// \brief sh_link field.
- uint32_t _link = 0;
- /// \brief the sh_info field.
- uint32_t _info = 0;
- /// \brief Is this the first section in the output section.
- bool _isFirstSectionInOutputSection = false;
- /// \brief the output ELF segment type of this section.
- typename TargetLayout<ELFT>::SegmentType _segmentType = SHT_NULL;
- /// \brief Input section name.
- StringRef _inputSectionName;
- /// \brief Output section name.
- StringRef _outputSectionName;
- StringRef _archivePath;
- StringRef _memberPath;
-};
-
-/// \brief A section containing atoms.
-template <class ELFT> class AtomSection : public Section<ELFT> {
-public:
- AtomSection(const ELFLinkingContext &ctx, StringRef sectionName,
- int32_t contentType, int32_t permissions, int32_t order);
-
- /// Align the offset to the required modulus defined by the atom alignment
- uint64_t alignOffset(uint64_t offset, DefinedAtom::Alignment &atomAlign);
-
- /// Return if the section is a loadable section that occupies memory
- bool isLoadableSection() const override { return _isLoadedInMemory; }
-
- // \brief Append an atom to a Section. The atom gets pushed into a vector
- // contains the atom, the atom file offset, the atom virtual address
- // the atom file offset is aligned appropriately as set by the Reader
- virtual const AtomLayout *appendAtom(const Atom *atom);
-
- /// \brief Set the virtual address of each Atom in the Section. This
- /// routine gets called after the linker fixes up the virtual address
- /// of the section
- void assignVirtualAddress(uint64_t addr) override;
-
- /// \brief Set the file offset of each Atom in the section. This routine
- /// gets called after the linker fixes up the section offset
- void assignFileOffsets(uint64_t offset) override;
-
- /// \brief Find the Atom address given a name, this is needed to properly
- /// apply relocation. The section class calls this to find the atom address
- /// to fix the relocation
- const AtomLayout *findAtomLayoutByName(StringRef name) const override;
-
- /// \brief Return the raw flags, we need this to sort segments
- int64_t atomflags() const { return _contentPermissions; }
-
- /// Atom Iterators
- typedef typename std::vector<AtomLayout *>::iterator atom_iter;
-
- range<atom_iter> atoms() { return _atoms; }
-
- void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
- llvm::FileOutputBuffer &buffer) override;
-
- static bool classof(const Chunk<ELFT> *c) {
- return c->kind() == Chunk<ELFT>::Kind::AtomSection;
- }
-
-protected:
- llvm::BumpPtrAllocator _alloc;
- int32_t _contentType;
- int32_t _contentPermissions;
- bool _isLoadedInMemory = true;
- std::vector<AtomLayout *> _atoms;
- mutable std::mutex _outputMutex;
-
- std::string formatError(const std::string &errorStr, const AtomLayout &atom,
- const Reference &ref) const;
-};
-
-/// \brief A OutputSection represents a set of sections grouped by the same
-/// name. The output file that gets written by the linker has sections grouped
-/// by similar names
-template <class ELFT> class OutputSection {
-public:
- // Iterators
- typedef typename std::vector<Section<ELFT> *>::iterator SectionIter;
-
- OutputSection(StringRef name) : _name(name) {}
-
- // Appends a section into the list of sections that are part of this Output
- // Section
- void appendSection(Section<ELFT> *c);
-
- // Set the OutputSection is associated with a segment
- void setHasSegment() { _hasSegment = true; }
-
- /// Sets the ordinal
- void setOrdinal(uint64_t ordinal) { _ordinal = ordinal; }
-
- /// Sets the Memory size
- void setMemSize(uint64_t memsz) { _memSize = memsz; }
-
- /// Sets the size fo the output Section.
- void setSize(uint64_t fsiz) { _size = fsiz; }
-
- // The offset of the first section contained in the output section is
- // contained here.
- void setFileOffset(uint64_t foffset) { _fileOffset = foffset; }
-
- // Sets the starting address of the section
- void setAddr(uint64_t addr) { _virtualAddr = addr; }
-
- // Is the section loadable?
- bool isLoadableSection() const { return _isLoadableSection; }
-
- // Set section Loadable
- void setLoadableSection(bool isLoadable) {
- _isLoadableSection = isLoadable;
- }
-
- void setLink(uint64_t link) { _link = link; }
- void setInfo(uint64_t info) { _shInfo = info; }
- void setFlag(uint64_t flags) { _flags = flags; }
- void setType(int64_t type) { _type = type; }
- range<SectionIter> sections() { return _sections; }
-
- // The below functions returns the properties of the OutputSection.
- bool hasSegment() const { return _hasSegment; }
- StringRef name() const { return _name; }
- int64_t shinfo() const { return _shInfo; }
- uint64_t alignment() const { return _alignment; }
- int64_t link() const { return _link; }
- int64_t type() const { return _type; }
- uint64_t virtualAddr() const { return _virtualAddr; }
- int64_t ordinal() const { return _ordinal; }
- int64_t kind() const { return _kind; }
- uint64_t fileSize() const { return _size; }
- int64_t entsize() const { return _entSize; }
- uint64_t fileOffset() const { return _fileOffset; }
- uint64_t flags() const { return _flags; }
- uint64_t memSize() const { return _memSize; }
-
-private:
- StringRef _name;
- bool _hasSegment = false;
- uint64_t _ordinal = 0;
- uint64_t _flags = 0;
- uint64_t _size = 0;
- uint64_t _memSize = 0;
- uint64_t _fileOffset = 0;
- uint64_t _virtualAddr = 0;
- int64_t _shInfo = 0;
- int64_t _entSize = 0;
- int64_t _link = 0;
- uint64_t _alignment = 1;
- int64_t _kind = 0;
- int64_t _type = 0;
- bool _isLoadableSection = false;
- std::vector<Section<ELFT> *> _sections;
-};
-
-/// \brief The class represents the ELF String Table
-template <class ELFT> class StringTable : public Section<ELFT> {
-public:
- StringTable(const ELFLinkingContext &, const char *str, int32_t order,
- bool dynamic = false);
-
- uint64_t addString(StringRef symname);
-
- void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
- llvm::FileOutputBuffer &buffer) override;
-
- void setNumEntries(int64_t numEntries) { _stringMap.resize(numEntries); }
-
-private:
- std::vector<StringRef> _strings;
-
- struct StringRefMappingInfo {
- static StringRef getEmptyKey() { return StringRef(); }
- static StringRef getTombstoneKey() { return StringRef(" ", 1); }
- static unsigned getHashValue(StringRef const val) {
- return llvm::HashString(val);
- }
- static bool isEqual(StringRef const lhs, StringRef const rhs) {
- return lhs.equals(rhs);
- }
- };
- typedef typename llvm::DenseMap<StringRef, uint64_t, StringRefMappingInfo>
- StringMapT;
- typedef typename StringMapT::iterator StringMapTIter;
- StringMapT _stringMap;
-};
-
-/// \brief The SymbolTable class represents the symbol table in a ELF file
-template <class ELFT> class SymbolTable : public Section<ELFT> {
- typedef
- typename llvm::object::ELFDataTypeTypedefHelper<ELFT>::Elf_Addr Elf_Addr;
-
-public:
- typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
-
- SymbolTable(const ELFLinkingContext &ctx, const char *str, int32_t order);
-
- /// \brief set the number of entries that would exist in the symbol
- /// table for the current link
- void setNumEntries(int64_t numEntries) const {
- if (_stringSection)
- _stringSection->setNumEntries(numEntries);
- }
-
- /// \brief return number of entries
- std::size_t size() const { return _symbolTable.size(); }
-
- void addSymbol(const Atom *atom, int32_t sectionIndex, uint64_t addr = 0,
- const AtomLayout *layout = nullptr);
-
- /// \brief Get the symbol table index for an Atom. If it's not in the symbol
- /// table, return STN_UNDEF.
- uint32_t getSymbolTableIndex(const Atom *a) const {
- for (size_t i = 0, e = _symbolTable.size(); i < e; ++i)
- if (_symbolTable[i]._atom == a)
- return i;
- return STN_UNDEF;
- }
-
- void finalize() override { finalize(true); }
-
- virtual void sortSymbols() {
- std::stable_sort(_symbolTable.begin(), _symbolTable.end(),
- [](const SymbolEntry &A, const SymbolEntry &B) {
- return A._symbol.getBinding() < B._symbol.getBinding();
- });
- }
-
- virtual void addAbsoluteAtom(Elf_Sym &sym, const AbsoluteAtom *aa,
- int64_t addr);
-
- virtual void addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da,
- int64_t addr);
-
- virtual void addUndefinedAtom(Elf_Sym &sym, const UndefinedAtom *ua);
-
- virtual void addSharedLibAtom(Elf_Sym &sym, const SharedLibraryAtom *sla);
-
- virtual void finalize(bool sort);
-
- void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
- llvm::FileOutputBuffer &buffer) override;
-
- void setStringSection(StringTable<ELFT> *s) { _stringSection = s; }
-
- StringTable<ELFT> *getStringTable() const { return _stringSection; }
-
-protected:
- struct SymbolEntry {
- SymbolEntry(const Atom *a, const Elf_Sym &sym, const AtomLayout *layout)
- : _atom(a), _atomLayout(layout), _symbol(sym) {}
-
- const Atom *_atom;
- const AtomLayout *_atomLayout;
- Elf_Sym _symbol;
- };
-
- llvm::BumpPtrAllocator _symbolAllocate;
- StringTable<ELFT> *_stringSection;
- std::vector<SymbolEntry> _symbolTable;
-};
-
-template <class ELFT> class HashSection;
-
-template <class ELFT> class DynamicSymbolTable : public SymbolTable<ELFT> {
-public:
- DynamicSymbolTable(const ELFLinkingContext &ctx, TargetLayout<ELFT> &layout,
- const char *str, int32_t order);
-
- // Set the dynamic hash table for symbols to be added into
- void setHashTable(HashSection<ELFT> *hashTable) { _hashTable = hashTable; }
-
- // Add all the dynamic symbos to the hash table
- void addSymbolsToHashTable();
-
- void finalize() override;
-
-protected:
- HashSection<ELFT> *_hashTable = nullptr;
- TargetLayout<ELFT> &_layout;
-};
-
-template <class ELFT> class RelocationTable : public Section<ELFT> {
-public:
- typedef llvm::object::Elf_Rel_Impl<ELFT, false> Elf_Rel;
- typedef llvm::object::Elf_Rel_Impl<ELFT, true> Elf_Rela;
-
- RelocationTable(const ELFLinkingContext &ctx, StringRef str, int32_t order);
-
- /// \returns the index of the relocation added.
- uint32_t addRelocation(const DefinedAtom &da, const Reference &r);
-
- bool getRelocationIndex(const Reference &r, uint32_t &res);
-
- void setSymbolTable(const DynamicSymbolTable<ELFT> *symbolTable) {
- _symbolTable = symbolTable;
- }
-
- /// \brief Check if any relocation modifies a read-only section.
- bool canModifyReadonlySection() const;
-
- void finalize() override;
-
- void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
- llvm::FileOutputBuffer &buffer) override;
-
-protected:
- const DynamicSymbolTable<ELFT> *_symbolTable = nullptr;
-
- virtual void writeRela(ELFWriter *writer, Elf_Rela &r,
- const DefinedAtom &atom, const Reference &ref);
- virtual void writeRel(ELFWriter *writer, Elf_Rel &r, const DefinedAtom &atom,
- const Reference &ref);
- uint32_t getSymbolIndex(const Atom *a);
-
-private:
- std::vector<std::pair<const DefinedAtom *, const Reference *>> _relocs;
-};
-
-template <class ELFT> class HashSection;
-
-template <class ELFT> class DynamicTable : public Section<ELFT> {
-public:
- typedef llvm::object::Elf_Dyn_Impl<ELFT> Elf_Dyn;
- typedef std::vector<Elf_Dyn> EntriesT;
-
- DynamicTable(const ELFLinkingContext &ctx, TargetLayout<ELFT> &layout,
- StringRef str, int32_t order);
-
- range<typename EntriesT::iterator> entries() { return _entries; }
-
- /// \returns the index of the entry.
- std::size_t addEntry(int64_t tag, uint64_t val);
-
- void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
- llvm::FileOutputBuffer &buffer) override;
-
- virtual void createDefaultEntries();
- void doPreFlight() override;
-
- /// \brief Dynamic table tag for .got.plt section referencing.
- /// Usually but not always targets use DT_PLTGOT for that.
- virtual int64_t getGotPltTag() { return DT_PLTGOT; }
-
- void finalize() override;
-
- void setSymbolTable(DynamicSymbolTable<ELFT> *dynsym) {
- _dynamicSymbolTable = dynsym;
- }
-
- const DynamicSymbolTable<ELFT> *getSymbolTable() const {
- return _dynamicSymbolTable;
- }
-
- void setHashTable(HashSection<ELFT> *hsh) { _hashTable = hsh; }
-
- virtual void updateDynamicTable();
-
-protected:
- EntriesT _entries;
-
- /// \brief Return a virtual address (maybe adjusted) for the atom layout
- /// Some targets like microMIPS and ARM Thumb use the last bit
- /// of a symbol's value to mark 'compressed' code. This function allows
- /// to adjust a virtal address before using it in the dynamic table tag.
- virtual uint64_t getAtomVirtualAddress(const AtomLayout *al) const {
- return al->_virtualAddr;
- }
-
-private:
- std::size_t _dt_hash;
- std::size_t _dt_strtab;
- std::size_t _dt_symtab;
- std::size_t _dt_rela;
- std::size_t _dt_relasz;
- std::size_t _dt_relaent;
- std::size_t _dt_strsz;
- std::size_t _dt_syment;
- std::size_t _dt_pltrelsz;
- std::size_t _dt_pltgot;
- std::size_t _dt_pltrel;
- std::size_t _dt_jmprel;
- std::size_t _dt_init_array;
- std::size_t _dt_init_arraysz;
- std::size_t _dt_fini_array;
- std::size_t _dt_fini_arraysz;
- std::size_t _dt_textrel;
- std::size_t _dt_init;
- std::size_t _dt_fini;
- TargetLayout<ELFT> &_layout;
- DynamicSymbolTable<ELFT> *_dynamicSymbolTable;
- HashSection<ELFT> *_hashTable;
-
- const AtomLayout *getInitAtomLayout();
-
- const AtomLayout *getFiniAtomLayout();
-};
-
-template <class ELFT> class InterpSection : public Section<ELFT> {
-public:
- InterpSection(const ELFLinkingContext &ctx, StringRef str, int32_t order,
- StringRef interp);
-
- void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
- llvm::FileOutputBuffer &buffer) override;
-
-private:
- StringRef _interp;
-};
-
-/// The hash table in the dynamic linker is organized into
-///
-/// [ nbuckets ]
-/// [ nchains ]
-/// [ buckets[0] ]
-/// .........................
-/// [ buckets[nbuckets-1] ]
-/// [ chains[0] ]
-/// .........................
-/// [ chains[nchains - 1] ]
-///
-/// nbuckets - total number of hash buckets
-/// nchains is equal to the number of dynamic symbols.
-///
-/// The symbol is searched by the dynamic linker using the below approach.
-/// * Calculate the hash of the symbol that needs to be searched
-/// * Take the value from the buckets[hash % nbuckets] as the index of symbol
-/// * Compare the symbol's name, if true return, if false, look through the
-/// * array since there was a collision
-template <class ELFT> class HashSection : public Section<ELFT> {
- struct SymbolTableEntry {
- StringRef _name;
- uint32_t _index;
- };
-
-public:
- HashSection(const ELFLinkingContext &ctx, StringRef name, int32_t order);
-
- /// \brief add the dynamic symbol into the table so that the
- /// hash could be calculated
- void addSymbol(StringRef name, uint32_t index);
-
- /// \brief Set the dynamic symbol table
- void setSymbolTable(const DynamicSymbolTable<ELFT> *symbolTable);
-
- // The size of the section has to be determined so that fileoffsets
- // may be properly assigned. Let's calculate the buckets and the chains
- // and fill the chains and the buckets hash table used by the dynamic
- // linker and update the filesize and memory size accordingly
- void doPreFlight() override;
-
- void finalize() override;
-
- void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
- llvm::FileOutputBuffer &buffer) override;
-
-private:
- typedef
- typename llvm::object::ELFDataTypeTypedefHelper<ELFT>::Elf_Word Elf_Word;
-
- std::vector<SymbolTableEntry> _entries;
- std::vector<Elf_Word> _buckets;
- std::vector<Elf_Word> _chains;
- const DynamicSymbolTable<ELFT> *_symbolTable = nullptr;
-};
-
-template <class ELFT> class EHFrameHeader : public Section<ELFT> {
-public:
- EHFrameHeader(const ELFLinkingContext &ctx, StringRef name,
- TargetLayout<ELFT> &layout, int32_t order);
- void doPreFlight() override;
- void finalize() override;
- void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
- llvm::FileOutputBuffer &buffer) override;
-
-private:
- int32_t _ehFrameOffset = 0;
- TargetLayout<ELFT> &_layout;
-};
-
-} // end namespace elf
-} // end namespace lld
-
-#endif // LLD_READER_WRITER_ELF_SECTION_CHUNKS_H
diff --git a/lib/ReaderWriter/ELF/SegmentChunks.cpp b/lib/ReaderWriter/ELF/SegmentChunks.cpp
deleted file mode 100644
index 99449f7d45aa..000000000000
--- a/lib/ReaderWriter/ELF/SegmentChunks.cpp
+++ /dev/null
@@ -1,519 +0,0 @@
-//===- lib/ReaderWriter/ELF/SegmentChunks.h -------------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "SegmentChunks.h"
-#include "TargetLayout.h"
-
-namespace lld {
-namespace elf {
-
-template <class ELFT>
-bool SegmentSlice<ELFT>::compare_slices(SegmentSlice<ELFT> *a,
- SegmentSlice<ELFT> *b) {
- return a->startSection() < b->startSection();
-}
-
-template <class ELFT>
-Segment<ELFT>::Segment(const ELFLinkingContext &ctx, StringRef name,
- const typename TargetLayout<ELFT>::SegmentType type)
- : Chunk<ELFT>(name, Chunk<ELFT>::Kind::ELFSegment, ctx), _segmentType(type),
- _flags(0), _atomflags(0), _segmentFlags(false) {
- this->_alignment = 1;
- this->_fsize = 0;
- _outputMagic = ctx.getOutputMagic();
-}
-
-// This function actually is used, but not in all instantiations of Segment.
-LLVM_ATTRIBUTE_UNUSED
-static DefinedAtom::ContentPermissions toAtomPerms(uint64_t flags) {
- switch (flags & (SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR)) {
- case SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR:
- return DefinedAtom::permRWX;
- case SHF_ALLOC | SHF_EXECINSTR:
- return DefinedAtom::permR_X;
- case SHF_ALLOC:
- return DefinedAtom::permR__;
- case SHF_ALLOC | SHF_WRITE:
- return DefinedAtom::permRW_;
- default:
- return DefinedAtom::permUnknown;
- }
-}
-
-// This function actually is used, but not in all instantiations of Segment.
-LLVM_ATTRIBUTE_UNUSED
-static DefinedAtom::ContentPermissions toAtomPermsSegment(uint64_t flags) {
- switch (flags & (llvm::ELF::PF_R | llvm::ELF::PF_W | llvm::ELF::PF_X)) {
- case llvm::ELF::PF_R | llvm::ELF::PF_W | llvm::ELF::PF_X:
- return DefinedAtom::permRWX;
- case llvm::ELF::PF_R | llvm::ELF::PF_X:
- return DefinedAtom::permR_X;
- case llvm::ELF::PF_R:
- return DefinedAtom::permR__;
- case llvm::ELF::PF_R | llvm::ELF::PF_W:
- return DefinedAtom::permRW_;
- default:
- return DefinedAtom::permUnknown;
- }
-}
-
-template <class ELFT> void Segment<ELFT>::append(Chunk<ELFT> *chunk) {
- _sections.push_back(chunk);
- Section<ELFT> *section = dyn_cast<Section<ELFT>>(chunk);
- if (!section)
- return;
- if (this->_alignment < section->alignment())
- this->_alignment = section->alignment();
-
- if (_segmentFlags)
- return;
- if (_flags < section->getFlags())
- _flags |= section->getFlags();
- if (_atomflags < toAtomPerms(_flags))
- _atomflags = toAtomPerms(_flags);
-}
-
-template <class ELFT>
-bool Segment<ELFT>::compareSegments(Segment<ELFT> *sega, Segment<ELFT> *segb) {
- int64_t type1 = sega->segmentType();
- int64_t type2 = segb->segmentType();
-
- if (type1 == type2)
- return sega->atomflags() < segb->atomflags();
-
- // The single PT_PHDR segment is required to precede any loadable
- // segment. We simply make it always first.
- if (type1 == llvm::ELF::PT_PHDR)
- return true;
- if (type2 == llvm::ELF::PT_PHDR)
- return false;
-
- // The single PT_INTERP segment is required to precede any loadable
- // segment. We simply make it always second.
- if (type1 == llvm::ELF::PT_INTERP)
- return true;
- if (type2 == llvm::ELF::PT_INTERP)
- return false;
-
- // We then put PT_LOAD segments before any other segments.
- if (type1 == llvm::ELF::PT_LOAD)
- return true;
- if (type2 == llvm::ELF::PT_LOAD)
- return false;
-
- // We put the PT_GNU_RELRO segment last, because that is where the
- // dynamic linker expects to find it
- if (type1 == llvm::ELF::PT_GNU_RELRO)
- return false;
- if (type2 == llvm::ELF::PT_GNU_RELRO)
- return true;
-
- // We put the PT_TLS segment last except for the PT_GNU_RELRO
- // segment, because that is where the dynamic linker expects to find
- if (type1 == llvm::ELF::PT_TLS)
- return false;
- if (type2 == llvm::ELF::PT_TLS)
- return true;
-
- // Otherwise compare the types to establish an arbitrary ordering.
- // FIXME: Should figure out if we should just make all other types compare
- // equal, but if so, we should probably do the same for atom flags and change
- // users of this to use stable_sort.
- return type1 < type2;
-}
-
-template <class ELFT>
-void Segment<ELFT>::assignFileOffsets(uint64_t startOffset) {
- uint64_t fileOffset = startOffset;
- uint64_t curSliceFileOffset = fileOffset;
- bool isDataPageAlignedForNMagic = false;
- bool alignSegments = this->_ctx.alignSegments();
- uint64_t p_align = this->_ctx.getPageSize();
- uint64_t lastVirtualAddress = 0;
-
- this->setFileOffset(startOffset);
- bool changeOffset = false;
- uint64_t newOffset = 0;
- for (auto &slice : slices()) {
- bool isFirstSection = true;
- for (auto section : slice->sections()) {
- // Handle linker script expressions, which may change the offset
- if (auto expr = dyn_cast<ExpressionChunk<ELFT>>(section)) {
- if (!isFirstSection) {
- changeOffset = true;
- newOffset = fileOffset + expr->virtualAddr() - lastVirtualAddress;
- }
- continue;
- }
- if (changeOffset) {
- changeOffset = false;
- fileOffset = newOffset;
- }
- // Align fileoffset to the alignment of the section.
- fileOffset = llvm::RoundUpToAlignment(fileOffset, section->alignment());
- // If the linker outputmagic is set to OutputMagic::NMAGIC, align the Data
- // to a page boundary
- if (isFirstSection &&
- _outputMagic != ELFLinkingContext::OutputMagic::NMAGIC &&
- _outputMagic != ELFLinkingContext::OutputMagic::OMAGIC) {
- // Align to a page only if the output is not
- // OutputMagic::NMAGIC/OutputMagic::OMAGIC
- if (alignSegments)
- fileOffset = llvm::RoundUpToAlignment(fileOffset, p_align);
- // Align according to ELF spec.
- // in p75, http://www.sco.com/developers/devspecs/gabi41.pdf
- uint64_t virtualAddress = slice->virtualAddr();
- Section<ELFT> *sect = dyn_cast<Section<ELFT>>(section);
- if (sect && sect->isLoadableSection() &&
- ((virtualAddress & (p_align - 1)) != (fileOffset & (p_align - 1))))
- fileOffset = llvm::RoundUpToAlignment(fileOffset, p_align) +
- (virtualAddress % p_align);
- } else if (!isDataPageAlignedForNMagic && needAlign(section)) {
- fileOffset =
- llvm::RoundUpToAlignment(fileOffset, this->_ctx.getPageSize());
- isDataPageAlignedForNMagic = true;
- }
- if (isFirstSection) {
- slice->setFileOffset(fileOffset);
- isFirstSection = false;
- curSliceFileOffset = fileOffset;
- }
- section->setFileOffset(fileOffset);
- fileOffset += section->fileSize();
- lastVirtualAddress = section->virtualAddr() + section->memSize();
- }
- changeOffset = false;
- slice->setFileSize(fileOffset - curSliceFileOffset);
- }
- this->setFileSize(fileOffset - startOffset);
-}
-
-/// \brief Assign virtual addresses to the slices
-template <class ELFT> void Segment<ELFT>::assignVirtualAddress(uint64_t addr) {
- int startSection = 0;
- int currSection = 0;
- SectionIter startSectionIter;
-
- // slice align is set to the max alignment of the chunks that are
- // contained in the slice
- uint64_t sliceAlign = 0;
- // Current slice size
- uint64_t curSliceSize = 0;
- // Current Slice File Offset
- uint64_t curSliceAddress = 0;
-
- startSectionIter = _sections.begin();
- startSection = 0;
- bool isDataPageAlignedForNMagic = false;
- uint64_t startAddr = addr;
- SegmentSlice<ELFT> *slice = nullptr;
- uint64_t tlsStartAddr = 0;
- bool alignSegments = this->_ctx.alignSegments();
- StringRef prevOutputSectionName = StringRef();
- uint64_t tbssMemsize = 0;
-
- // If this is first section in the segment, page align the section start
- // address. The linker needs to align the data section to a page boundary
- // only if NMAGIC is set.
- auto si = _sections.begin();
- if (si != _sections.end()) {
- if (alignSegments &&
- _outputMagic != ELFLinkingContext::OutputMagic::NMAGIC &&
- _outputMagic != ELFLinkingContext::OutputMagic::OMAGIC) {
- // Align to a page only if the output is not
- // OutputMagic::NMAGIC/OutputMagic::OMAGIC
- startAddr = llvm::RoundUpToAlignment(startAddr, this->_ctx.getPageSize());
- } else if (needAlign(*si)) {
- // If the linker outputmagic is set to OutputMagic::NMAGIC, align the
- // Data to a page boundary.
- startAddr = llvm::RoundUpToAlignment(startAddr, this->_ctx.getPageSize());
- isDataPageAlignedForNMagic = true;
- }
- // align the startOffset to the section alignment
- uint64_t newAddr = llvm::RoundUpToAlignment(startAddr, (*si)->alignment());
- // Handle linker script expressions, which *may update newAddr* if the
- // expression assigns to "."
- if (auto expr = dyn_cast<ExpressionChunk<ELFT>>(*si))
- expr->evalExpr(newAddr);
- curSliceAddress = newAddr;
- sliceAlign = (*si)->alignment();
- (*si)->setVirtualAddr(curSliceAddress);
-
- // Handle TLS.
- if (auto section = dyn_cast<Section<ELFT>>(*si)) {
- if (section->getSegmentType() == llvm::ELF::PT_TLS) {
- tlsStartAddr =
- llvm::RoundUpToAlignment(tlsStartAddr, (*si)->alignment());
- section->assignVirtualAddress(tlsStartAddr);
- tlsStartAddr += (*si)->memSize();
- } else {
- section->assignVirtualAddress(newAddr);
- }
- }
- // TBSS section is special in that it doesn't contribute to memory of any
- // segment. If we see a tbss section, don't add memory size to addr The
- // fileOffset is automatically taken care of since TBSS section does not
- // end up using file size
- if ((*si)->order() != TargetLayout<ELFT>::ORDER_TBSS) {
- curSliceSize = (*si)->memSize();
- tbssMemsize = 0;
- } else {
- tbssMemsize = (*si)->memSize();
- }
- ++currSection;
- ++si;
- }
-
- uint64_t scriptAddr = 0;
- bool forceScriptAddr = false;
- for (auto e = _sections.end(); si != e; ++si) {
- uint64_t curAddr = curSliceAddress + curSliceSize;
- if (!isDataPageAlignedForNMagic && needAlign(*si)) {
- // If the linker outputmagic is set to OutputMagic::NMAGIC, align the
- // Data
- // to a page boundary
- curAddr = llvm::RoundUpToAlignment(curAddr, this->_ctx.getPageSize());
- isDataPageAlignedForNMagic = true;
- }
- uint64_t newAddr = llvm::RoundUpToAlignment(
- forceScriptAddr ? scriptAddr : curAddr, (*si)->alignment());
- forceScriptAddr = false;
-
- // Handle linker script expressions, which may force an address change if
- // the expression assigns to "."
- if (auto expr = dyn_cast<ExpressionChunk<ELFT>>(*si)) {
- uint64_t oldAddr = newAddr;
- expr->evalExpr(newAddr);
- if (oldAddr != newAddr) {
- forceScriptAddr = true;
- scriptAddr = newAddr;
- }
- (*si)->setVirtualAddr(newAddr);
- continue;
- }
- Section<ELFT> *sec = dyn_cast<Section<ELFT>>(*si);
- StringRef curOutputSectionName =
- sec ? sec->outputSectionName() : (*si)->name();
- bool autoCreateSlice = true;
- if (curOutputSectionName == prevOutputSectionName)
- autoCreateSlice = false;
- // If the newAddress computed is more than a page away, let's create
- // a separate segment, so that memory is not used up while running.
- // Dont create a slice, if the new section falls in the same output
- // section as the previous section.
- if (autoCreateSlice && ((newAddr - curAddr) > this->_ctx.getPageSize()) &&
- (_outputMagic != ELFLinkingContext::OutputMagic::NMAGIC &&
- _outputMagic != ELFLinkingContext::OutputMagic::OMAGIC)) {
- auto sliceIter =
- std::find_if(_segmentSlices.begin(), _segmentSlices.end(),
- [startSection](SegmentSlice<ELFT> *s) -> bool {
- return s->startSection() == startSection;
- });
- if (sliceIter == _segmentSlices.end()) {
- slice = new (_segmentAllocate.Allocate<SegmentSlice<ELFT>>())
- SegmentSlice<ELFT>();
- _segmentSlices.push_back(slice);
- } else {
- slice = *sliceIter;
- }
- slice->setStart(startSection);
- slice->setSections(make_range(startSectionIter, si));
- slice->setMemSize(curSliceSize);
- slice->setAlign(sliceAlign);
- slice->setVirtualAddr(curSliceAddress);
- // Start new slice
- curSliceAddress = newAddr;
- if ((*si)->order() == TargetLayout<ELFT>::ORDER_TBSS)
- curSliceAddress += tbssMemsize;
- (*si)->setVirtualAddr(curSliceAddress);
- startSectionIter = si;
- startSection = currSection;
- if (auto section = dyn_cast<Section<ELFT>>(*si))
- section->assignVirtualAddress(newAddr);
- curSliceSize = newAddr - curSliceAddress + (*si)->memSize();
- sliceAlign = (*si)->alignment();
- } else {
- if (sliceAlign < (*si)->alignment())
- sliceAlign = (*si)->alignment();
- if ((*si)->order() == TargetLayout<ELFT>::ORDER_TBSS)
- newAddr += tbssMemsize;
- (*si)->setVirtualAddr(newAddr);
- // Handle TLS.
- if (auto section = dyn_cast<Section<ELFT>>(*si)) {
- if (section->getSegmentType() == llvm::ELF::PT_TLS) {
- tlsStartAddr =
- llvm::RoundUpToAlignment(tlsStartAddr, (*si)->alignment());
- section->assignVirtualAddress(tlsStartAddr);
- tlsStartAddr += (*si)->memSize();
- } else {
- section->assignVirtualAddress(newAddr);
- }
- }
- // TBSS section is special in that it doesn't contribute to memory of
- // any segment. If we see a tbss section, don't add memory size to addr
- // The fileOffset is automatically taken care of since TBSS section does
- // not end up using file size.
- if ((*si)->order() != TargetLayout<ELFT>::ORDER_TBSS) {
- curSliceSize = newAddr - curSliceAddress + (*si)->memSize();
- tbssMemsize = 0;
- } else {
- // Although TBSS section does not contribute to memory of any segment,
- // we still need to keep track its total size to correct write it
- // down. Since it is done based on curSliceAddress, we need to add
- // add it to virtual address.
- tbssMemsize = (*si)->memSize();
- }
- }
- prevOutputSectionName = curOutputSectionName;
- ++currSection;
- }
-
- auto sliceIter = std::find_if(_segmentSlices.begin(), _segmentSlices.end(),
- [startSection](SegmentSlice<ELFT> *s) -> bool {
- return s->startSection() == startSection;
- });
- if (sliceIter == _segmentSlices.end()) {
- slice = new (_segmentAllocate.Allocate<SegmentSlice<ELFT>>())
- SegmentSlice<ELFT>();
- _segmentSlices.push_back(slice);
- } else {
- slice = *sliceIter;
- }
-
- slice->setStart(startSection);
- slice->setVirtualAddr(curSliceAddress);
- slice->setMemSize(curSliceSize);
- slice->setSections(make_range(startSectionIter, _sections.end()));
- slice->setAlign(sliceAlign);
-
- // Set the segment memory size and the virtual address.
- this->setMemSize(curSliceAddress - startAddr + curSliceSize);
- this->setVirtualAddr(startAddr);
- std::stable_sort(_segmentSlices.begin(), _segmentSlices.end(),
- SegmentSlice<ELFT>::compare_slices);
-}
-
-// Write the Segment
-template <class ELFT>
-void Segment<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout,
- llvm::FileOutputBuffer &buffer) {
- for (auto slice : slices())
- for (auto section : slice->sections())
- section->write(writer, layout, buffer);
-}
-
-template <class ELFT> int64_t Segment<ELFT>::flags() const {
- if (_segmentFlags)
- return (int64_t)_flags;
-
- int64_t fl = 0;
- if (_flags & llvm::ELF::SHF_ALLOC)
- fl |= llvm::ELF::PF_R;
- if (_flags & llvm::ELF::SHF_WRITE)
- fl |= llvm::ELF::PF_W;
- if (_flags & llvm::ELF::SHF_EXECINSTR)
- fl |= llvm::ELF::PF_X;
- return fl;
-}
-
-template <class ELFT> void Segment<ELFT>::setSegmentFlags(uint64_t flags) {
- assert(!_segmentFlags && "Segment flags have already been set");
- _segmentFlags = true;
- _flags = flags;
- _atomflags = toAtomPermsSegment(flags);
-}
-
-template <class ELFT> void Segment<ELFT>::finalize() {
- // We want to finalize the segment values for now only for non loadable
- // segments, since those values are not set in the Layout
- if (_segmentType == llvm::ELF::PT_LOAD)
- return;
- // The size is the difference of the
- // last section to the first section, especially for TLS because
- // the TLS segment contains both .tdata/.tbss
- this->setFileOffset(_sections.front()->fileOffset());
- this->setVirtualAddr(_sections.front()->virtualAddr());
- size_t startFileOffset = _sections.front()->fileOffset();
- size_t startAddr = _sections.front()->virtualAddr();
- for (auto ai : _sections) {
- this->_fsize = ai->fileOffset() + ai->fileSize() - startFileOffset;
- this->_msize = ai->virtualAddr() + ai->memSize() - startAddr;
- }
-}
-
-template <class ELFT> int Segment<ELFT>::getContentType() const {
- int64_t fl = flags();
- switch (_segmentType) {
- case llvm::ELF::PT_LOAD: {
- if (fl && llvm::ELF::PF_X)
- return Chunk<ELFT>::ContentType::Code;
- if (fl && llvm::ELF::PF_W)
- return Chunk<ELFT>::ContentType::Data;
- }
- case llvm::ELF::PT_TLS:
- return Chunk<ELFT>::ContentType::TLS;
- case llvm::ELF::PT_NOTE:
- return Chunk<ELFT>::ContentType::Note;
- default:
- return Chunk<ELFT>::ContentType::Unknown;
- }
-}
-
-template <class ELFT> int64_t Segment<ELFT>::atomflags() const {
- switch (_atomflags) {
- case DefinedAtom::permUnknown:
- return permUnknown;
- case DefinedAtom::permRWX:
- return permRWX;
- case DefinedAtom::permR_X:
- return permRX;
- case DefinedAtom::permR__:
- return permR;
- case DefinedAtom::permRW_L:
- return permRWL;
- case DefinedAtom::permRW_:
- return permRW;
- case DefinedAtom::perm___:
- default:
- return permNonAccess;
- }
-}
-
-/// \brief Check if the chunk needs to be aligned
-template <class ELFT> bool Segment<ELFT>::needAlign(Chunk<ELFT> *chunk) const {
- if (chunk->getContentType() == Chunk<ELFT>::ContentType::Data &&
- _outputMagic == ELFLinkingContext::OutputMagic::NMAGIC)
- return true;
- return false;
-}
-
-template <class ELFT> void ProgramHeaderSegment<ELFT>::finalize() {
- // If the segment is of type Program Header, then the values fileOffset
- // and the fileSize need to be picked up from the last section, the first
- // section points to the ELF header and the second chunk points to the
- // actual program headers
- this->setFileOffset(this->_sections.back()->fileOffset());
- this->setVirtualAddr(this->_sections.back()->virtualAddr());
- this->_fsize = this->_sections.back()->fileSize();
- this->_msize = this->_sections.back()->memSize();
-}
-
-#define INSTANTIATE(klass) \
- template class klass<ELF32LE>; \
- template class klass<ELF32BE>; \
- template class klass<ELF64LE>; \
- template class klass<ELF64BE>
-
-INSTANTIATE(ExpressionChunk);
-INSTANTIATE(ProgramHeaderSegment);
-INSTANTIATE(Segment);
-INSTANTIATE(SegmentSlice);
-
-} // end namespace elf
-} // end namespace lld
diff --git a/lib/ReaderWriter/ELF/SegmentChunks.h b/lib/ReaderWriter/ELF/SegmentChunks.h
deleted file mode 100644
index b444f44c04eb..000000000000
--- a/lib/ReaderWriter/ELF/SegmentChunks.h
+++ /dev/null
@@ -1,246 +0,0 @@
-//===- lib/ReaderWriter/ELF/SegmentChunks.h -------------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_ELF_SEGMENT_CHUNKS_H
-#define LLD_READER_WRITER_ELF_SEGMENT_CHUNKS_H
-
-#include "Chunk.h"
-#include "SectionChunks.h"
-#include "Writer.h"
-#include "lld/Core/range.h"
-#include "lld/Core/Writer.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Object/ELF.h"
-#include "llvm/Support/Allocator.h"
-#include "llvm/Support/ELF.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/FileOutputBuffer.h"
-#include <memory>
-
-namespace lld {
-namespace elf {
-
-template <typename ELFT> class TargetLayout;
-
-/// \brief A segment can be divided into segment slices
-/// depending on how the segments can be split
-template<class ELFT>
-class SegmentSlice {
-public:
- typedef typename std::vector<Chunk<ELFT> *>::iterator SectionIter;
-
- /// Set the start of the slice.
- void setStart(int32_t s) { _startSection = s; }
-
- // Set the segment slice start and end iterators. This is used to walk through
- // the sections that are part of the Segment slice
- void setSections(range<SectionIter> sections) { _sections = sections; }
-
- // Return the fileOffset of the slice
- uint64_t fileOffset() const { return _offset; }
- void setFileOffset(uint64_t offset) { _offset = offset; }
-
- // Return the size of the slice
- uint64_t fileSize() const { return _fsize; }
- void setFileSize(uint64_t filesz) { _fsize = filesz; }
-
- // Return the start of the slice
- int32_t startSection() const { return _startSection; }
-
- // Return the start address of the slice
- uint64_t virtualAddr() const { return _addr; }
-
- // Return the memory size of the slice
- uint64_t memSize() const { return _memSize; }
-
- // Return the alignment of the slice
- uint64_t alignment() const { return _alignment; }
-
- void setMemSize(uint64_t memsz) { _memSize = memsz; }
-
- void setVirtualAddr(uint64_t addr) { _addr = addr; }
-
- void setAlign(uint64_t align) { _alignment = align; }
-
- static bool compare_slices(SegmentSlice<ELFT> *a, SegmentSlice<ELFT> *b);
-
- range<SectionIter> sections() { return _sections; }
-
-private:
- range<SectionIter> _sections;
- int32_t _startSection;
- uint64_t _addr;
- uint64_t _offset;
- uint64_t _alignment;
- uint64_t _fsize;
- uint64_t _memSize;
-};
-
-/// \brief A segment contains a set of sections, that have similar properties
-// the sections are already separated based on different flags and properties
-// the segment is just a way to concatenate sections to segments
-template<class ELFT>
-class Segment : public Chunk<ELFT> {
-public:
- typedef typename std::vector<SegmentSlice<ELFT> *>::iterator SliceIter;
- typedef typename std::vector<Chunk<ELFT> *>::iterator SectionIter;
-
- Segment(const ELFLinkingContext &ctx, StringRef name,
- const typename TargetLayout<ELFT>::SegmentType type);
-
- /// \brief the Order of segments that appear in the output file
- enum SegmentOrder {
- permUnknown,
- permRWX,
- permRX,
- permR,
- permRWL,
- permRW,
- permNonAccess
- };
-
- /// append a section to a segment
- virtual void append(Chunk<ELFT> *chunk);
-
- /// Sort segments depending on the property
- /// If we have a Program Header segment, it should appear first
- /// If we have a INTERP segment, that should appear after the Program Header
- /// All Loadable segments appear next in this order
- /// All Read Write Execute segments follow
- /// All Read Execute segments appear next
- /// All Read only segments appear first
- /// All Write execute segments follow
- static bool compareSegments(Segment<ELFT> *sega, Segment<ELFT> *segb);
-
- /// \brief Start assigning file offset to the segment chunks The fileoffset
- /// needs to be page at the start of the segment and in addition the
- /// fileoffset needs to be aligned to the max section alignment within the
- /// segment. This is required so that the ELF property p_poffset % p_align =
- /// p_vaddr mod p_align holds true.
- /// The algorithm starts off by assigning the startOffset thats passed in as
- /// parameter to the first section in the segment, if the difference between
- /// the newly computed offset is greater than a page, then we create a segment
- /// slice, as it would be a waste of virtual memory just to be filled with
- /// zeroes
- void assignFileOffsets(uint64_t startOffset);
-
- /// \brief Assign virtual addresses to the slices
- void assignVirtualAddress(uint64_t addr);
-
- // Write the Segment
- void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
- llvm::FileOutputBuffer &buffer) override;
-
- int64_t flags() const;
-
- // Set segment flags directly.
- void setSegmentFlags(uint64_t flags);
-
- /// Prepend a generic chunk to the segment.
- void prepend(Chunk<ELFT> *c) {
- _sections.insert(_sections.begin(), c);
- }
-
- /// Finalize the segment, before we want to write the segment header
- /// information
- void finalize() override;
-
- // For LLVM RTTI
- static bool classof(const Chunk<ELFT> *c) {
- return c->kind() == Chunk<ELFT>::Kind::ELFSegment;
- }
-
- // Getters
- int32_t sectionCount() const { return _sections.size(); }
-
- /// \brief, this function returns the type of segment (PT_*)
- typename TargetLayout<ELFT>::SegmentType segmentType() const {
- return _segmentType;
- }
-
- /// \brief return the segment type depending on the content,
- /// If the content corresponds to Code, this will return Segment::Code
- /// If the content corresponds to Data, this will return Segment::Data
- /// If the content corresponds to TLS, this will return Segment::TLS
- int getContentType() const override;
-
- int pageSize() const { return this->_ctx.getPageSize(); }
- int rawflags() const { return _atomflags; }
- int64_t atomflags() const;
- int64_t numSlices() const { return _segmentSlices.size(); }
- range<SliceIter> slices() { return _segmentSlices; }
- Chunk<ELFT> *firstSection() { return _sections[0]; }
-
-private:
- /// \brief Check if the chunk needs to be aligned
- bool needAlign(Chunk<ELFT> *chunk) const;
-
- // Cached value of outputMagic
- ELFLinkingContext::OutputMagic _outputMagic;
-
-protected:
- /// \brief Section or some other chunk type.
- std::vector<Chunk<ELFT> *> _sections;
- std::vector<SegmentSlice<ELFT> *> _segmentSlices;
- typename TargetLayout<ELFT>::SegmentType _segmentType;
- uint64_t _flags;
- int64_t _atomflags;
- bool _segmentFlags;
- llvm::BumpPtrAllocator _segmentAllocate;
-};
-
-/// This chunk represents a linker script expression that needs to be calculated
-/// at the time the virtual addresses for the parent segment are being assigned.
-template <class ELFT> class ExpressionChunk : public Chunk<ELFT> {
-public:
- ExpressionChunk(ELFLinkingContext &ctx, const script::SymbolAssignment *expr)
- : Chunk<ELFT>(StringRef(), Chunk<ELFT>::Kind::Expression, ctx),
- _expr(expr), _linkerScriptSema(ctx.linkerScriptSema()) {
- this->_alignment = 1;
- }
-
- static bool classof(const Chunk<ELFT> *c) {
- return c->kind() == Chunk<ELFT>::Kind::Expression;
- }
-
- int getContentType() const override {
- return Chunk<ELFT>::ContentType::Unknown;
- }
-
- void write(ELFWriter *, TargetLayout<ELFT> &,
- llvm::FileOutputBuffer &) override {}
-
- std::error_code evalExpr(uint64_t &curPos) {
- return _linkerScriptSema.evalExpr(_expr, curPos);
- }
-
-private:
- const script::SymbolAssignment *_expr;
- script::Sema &_linkerScriptSema;
-};
-
-/// \brief A Program Header segment contains a set of chunks instead of sections
-/// The segment doesn't contain any slice
-template <class ELFT> class ProgramHeaderSegment : public Segment<ELFT> {
-public:
- ProgramHeaderSegment(const ELFLinkingContext &ctx)
- : Segment<ELFT>(ctx, "PHDR", llvm::ELF::PT_PHDR) {
- this->_alignment = 8;
- this->_flags = (llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR);
- }
-
- /// Finalize the segment, before we want to write the segment header
- /// information
- void finalize() override;
-};
-
-} // end namespace elf
-} // end namespace lld
-
-#endif // LLD_READER_WRITER_ELF_SEGMENT_CHUNKS_H
diff --git a/lib/ReaderWriter/ELF/TODO.txt b/lib/ReaderWriter/ELF/TODO.txt
deleted file mode 100644
index 90c334b781ba..000000000000
--- a/lib/ReaderWriter/ELF/TODO.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-lib/ReaderWriter/ELF
-~~~~~~~~~~~~~~~~~~~~
-
-- Implement processing of DT_NEEDED elements including -rpath-link /
- -rpath processing.
-
-- _GLOBAL_OFFSET_TABLE should be hidden and normally dropped from the output.
-
-- Merge SHT_NOTE sections only if applicable.
-
-- Do not create __got_* / __plt_* symbol table entries by default.
-
-- Weak references to symbols defined in a DSO should remain weak.
-
-- Fix section flags as they appear in input (update content permissions)
-
-- Check for errors in the ELFReader when creating atoms for LinkOnce
- sections/Group sections. Add tests to account for the change when it happens.
diff --git a/lib/ReaderWriter/ELF/TargetHandler.h b/lib/ReaderWriter/ELF/TargetHandler.h
deleted file mode 100644
index 406ac670fc83..000000000000
--- a/lib/ReaderWriter/ELF/TargetHandler.h
+++ /dev/null
@@ -1,35 +0,0 @@
-//===- lib/ReaderWriter/ELF/TargetHandler.h -------------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_ELF_TARGET_HANDLER_H
-#define LLD_READER_WRITER_ELF_TARGET_HANDLER_H
-
-#include "lld/Core/Error.h"
-#include "llvm/ADT/Twine.h"
-#include "llvm/Support/ErrorHandling.h"
-
-namespace lld {
-namespace elf {
-
-inline std::error_code make_unhandled_reloc_error() {
- return make_dynamic_error_code("Unhandled reference type");
-}
-
-inline std::error_code make_out_of_range_reloc_error() {
- return make_dynamic_error_code("Relocation out of range");
-}
-
-inline std::error_code make_unaligned_range_reloc_error() {
- return make_dynamic_error_code("Relocation not aligned");
-}
-
-} // end namespace elf
-} // end namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/ELF/TargetLayout.cpp b/lib/ReaderWriter/ELF/TargetLayout.cpp
deleted file mode 100644
index 09c49f62d64f..000000000000
--- a/lib/ReaderWriter/ELF/TargetLayout.cpp
+++ /dev/null
@@ -1,747 +0,0 @@
-//===- lib/ReaderWriter/ELF/TargetLayout.cpp ------------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "TargetLayout.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/StringSwitch.h"
-#include "llvm/Support/Errc.h"
-
-namespace lld {
-namespace elf {
-
-template <class ELFT>
-typename TargetLayout<ELFT>::SectionOrder
-TargetLayout<ELFT>::getSectionOrder(StringRef name, int32_t contentType,
- int32_t contentPermissions) {
- switch (contentType) {
- case DefinedAtom::typeResolver:
- case DefinedAtom::typeCode:
- return llvm::StringSwitch<typename TargetLayout<ELFT>::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<typename TargetLayout<ELFT>::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<typename TargetLayout<ELFT>::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 TargetLayout<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
-TargetLayout<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>
-typename TargetLayout<ELFT>::SegmentType
-TargetLayout<ELFT>::getSegmentType(const 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 TargetLayout<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> *
-TargetLayout<ELFT>::createSection(StringRef sectionName, int32_t contentType,
- DefinedAtom::ContentPermissions permissions,
- SectionOrder sectionOrder) {
- return new (_allocator) AtomSection<ELFT>(_ctx, sectionName, contentType,
- permissions, sectionOrder);
-}
-
-template <class ELFT>
-AtomSection<ELFT> *
-TargetLayout<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 AtomLayout *> TargetLayout<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 (_ctx.isDynamicRelocation(*reloc)) {
- getDynamicRelocationTable()->addRelocation(*definedAtom, *reloc);
- isLocalReloc = false;
- } else if (_ctx.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 (_ctx.isCopyRelocation(*reloc)) {
- _copiedDynSymNames.insert(definedAtom->name());
- continue;
- }
-
- _referencedDynAtoms.insert(reloc->target());
- }
- return section->appendAtom(atom);
- }
-
- const AbsoluteAtom *absoluteAtom = cast<AbsoluteAtom>(atom);
- // Absolute atoms are not part of any section, they are global for the whole
- // link
- _absoluteAtoms.push_back(
- new (_allocator) AtomLayout(absoluteAtom, 0, absoluteAtom->value()));
- return _absoluteAtoms.back();
-}
-
-/// Output sections with the same name into a OutputSection
-template <class ELFT> void TargetLayout<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(section);
- }
-}
-
-template <class ELFT>
-std::vector<typename TargetLayout<ELFT>::SegmentKey>
-TargetLayout<ELFT>::getSegmentsForSection(const OutputSection<ELFT> *os,
- const Section<ELFT> *sec) const {
- std::vector<SegmentKey> segKeys;
- auto phdrs = _linkerScriptSema.getPHDRsForOutputSection(os->name());
- if (!phdrs.empty()) {
- if (phdrs.size() == 1 && phdrs[0]->isNone()) {
- segKeys.emplace_back("NONE", llvm::ELF::PT_NULL, 0, false);
- return segKeys;
- }
-
- for (auto phdr : phdrs) {
- segKeys.emplace_back(phdr->name(), phdr->type(), phdr->flags(), true);
- }
- return segKeys;
- }
-
- uint64_t flags = getLookupSectionFlags(os);
- int64_t segmentType = getSegmentType(sec);
- StringRef segmentName = sec->segmentKindToStr();
-
- // We need a separate segment for sections that don't have
- // the segment type to be PT_LOAD
- if (segmentType != llvm::ELF::PT_LOAD)
- segKeys.emplace_back(segmentName, segmentType, flags, false);
-
- if (segmentType == llvm::ELF::PT_NULL)
- return segKeys;
-
- // If the output magic is set to OutputMagic::NMAGIC or
- // OutputMagic::OMAGIC, Place the data alongside text in one single
- // segment
- ELFLinkingContext::OutputMagic outputMagic = _ctx.getOutputMagic();
- if (outputMagic == ELFLinkingContext::OutputMagic::NMAGIC ||
- outputMagic == ELFLinkingContext::OutputMagic::OMAGIC)
- flags =
- llvm::ELF::SHF_EXECINSTR | llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE;
-
- segKeys.emplace_back("LOAD", llvm::ELF::PT_LOAD, flags, false);
- return segKeys;
-}
-
-template <class ELFT>
-uint64_t
-TargetLayout<ELFT>::getLookupSectionFlags(const OutputSection<ELFT> *os) const {
- uint64_t flags = os->flags();
- if (!(flags & llvm::ELF::SHF_WRITE) && _ctx.mergeRODataToTextSegment())
- flags &= ~llvm::ELF::SHF_EXECINSTR;
-
- // Merge string sections into Data segment itself
- flags &= ~(llvm::ELF::SHF_STRINGS | llvm::ELF::SHF_MERGE);
-
- // Merge the TLS section into the DATA segment itself
- flags &= ~(llvm::ELF::SHF_TLS);
- return flags;
-}
-
-template <class ELFT> void TargetLayout<ELFT>::assignSectionsToSegments() {
- ScopedTask task(getDefaultDomain(), "assignSectionsToSegments");
- // 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 section : osi->sections()) {
- if (!hasOutputSegment(section))
- continue;
-
- osi->setLoadableSection(section->isLoadableSection());
- osi->setHasSegment();
-
- auto segKeys = getSegmentsForSection(osi, section);
- assert(!segKeys.empty() && "Must always be at least one segment");
- section->setSegmentType(segKeys[0]._type);
-
- for (auto key : segKeys) {
- // Try to find non-load (real) segment type if possible
- if (key._type != llvm::ELF::PT_LOAD)
- section->setSegmentType(key._type);
-
- const std::pair<SegmentKey, Segment<ELFT> *> currentSegment(key,
- nullptr);
- std::pair<typename SegmentMapT::iterator, bool> segmentInsert(
- _segmentMap.insert(currentSegment));
- Segment<ELFT> *segment;
- if (!segmentInsert.second) {
- segment = segmentInsert.first->second;
- } else {
- segment = new (_allocator) Segment<ELFT>(_ctx, key._name, key._type);
- if (key._segmentFlags)
- segment->setSegmentFlags(key._flags);
- segmentInsert.first->second = segment;
- _segments.push_back(segment);
- }
- if (key._type == llvm::ELF::PT_LOAD) {
- // 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);
- }
- }
- }
-
- // Default values if no linker script is available
- bool hasProgramSegment = _ctx.isDynamic() && !_ctx.isDynamicLibrary();
- bool hasElfHeader = true;
- bool hasProgramHeader = true;
- uint64_t segmentFlags = 0;
-
- // Check if linker script has PHDRS and program segment defined
- if (_linkerScriptSema.hasPHDRs()) {
- if (auto p = _linkerScriptSema.getProgramPHDR()) {
- hasProgramSegment = true;
- hasElfHeader = p->hasFileHdr();
- hasProgramHeader = p->hasPHDRs();
- segmentFlags = p->flags();
- } else {
- hasProgramSegment = false;
- hasElfHeader = false;
- hasProgramHeader = false;
- }
- }
-
- if (hasProgramSegment) {
- Segment<ELFT> *segment = new (_allocator) ProgramHeaderSegment<ELFT>(_ctx);
- _segments.push_back(segment);
- if (segmentFlags)
- segment->setSegmentFlags(segmentFlags);
- if (hasElfHeader)
- segment->append(_elfHeader);
- if (hasProgramHeader)
- segment->append(_programHeader);
- }
-}
-
-template <class ELFT> void TargetLayout<ELFT>::sortSegments() {
- std::sort(_segments.begin(), _segments.end(), Segment<ELFT>::compareSegments);
-}
-
-template <class ELFT> void TargetLayout<ELFT>::assignVirtualAddress() {
- if (_segments.empty())
- return;
-
- sortSegments();
-
- uint64_t baseAddress = _ctx.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 && TargetLayout<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 TargetLayout<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 && TargetLayout<ELFT>::hasOutputSegment(section))
- continue;
- fileoffset = llvm::RoundUpToAlignment(fileoffset, si->alignment());
- si->setFileOffset(fileoffset);
- si->setVirtualAddr(0);
- fileoffset += si->fileSize();
- }
-}
-
-template <class ELFT> void TargetLayout<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>
-const AtomLayout *
-TargetLayout<ELFT>::findAtomLayoutByName(StringRef name) const {
- for (auto sec : _sections)
- if (auto section = dyn_cast<Section<ELFT>>(sec))
- if (auto *al = section->findAtomLayoutByName(name))
- return al;
- return nullptr;
-}
-
-template <class ELFT>
-void TargetLayout<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->_ctx, expr);
- segment->append(expChunk);
- }
-}
-
-template <class ELFT>
-RelocationTable<ELFT> *TargetLayout<ELFT>::getDynamicRelocationTable() {
- if (!_dynamicRelocationTable) {
- _dynamicRelocationTable = createRelocationTable(
- _ctx.isRelaOutputFormat() ? ".rela.dyn" : ".rel.dyn",
- ORDER_DYNAMIC_RELOCS);
- addSection(_dynamicRelocationTable.get());
- }
- return _dynamicRelocationTable.get();
-}
-
-template <class ELFT>
-RelocationTable<ELFT> *TargetLayout<ELFT>::getPLTRelocationTable() {
- if (!_pltRelocationTable) {
- _pltRelocationTable = createRelocationTable(
- _ctx.isRelaOutputFormat() ? ".rela.plt" : ".rel.plt",
- ORDER_DYNAMIC_PLT_RELOCS);
- addSection(_pltRelocationTable.get());
- }
- return _pltRelocationTable.get();
-}
-
-template <class ELFT> uint64_t TargetLayout<ELFT>::getTLSSize() const {
- for (const auto &phdr : *_programHeader)
- if (phdr->p_type == llvm::ELF::PT_TLS)
- return phdr->p_memsz;
- return 0;
-}
-
-template class TargetLayout<ELF32LE>;
-template class TargetLayout<ELF32BE>;
-template class TargetLayout<ELF64LE>;
-template class TargetLayout<ELF64BE>;
-
-} // end namespace elf
-} // end namespace lld
diff --git a/lib/ReaderWriter/ELF/TargetLayout.h b/lib/ReaderWriter/ELF/TargetLayout.h
deleted file mode 100644
index 52512f8e279e..000000000000
--- a/lib/ReaderWriter/ELF/TargetLayout.h
+++ /dev/null
@@ -1,327 +0,0 @@
-//===- lib/ReaderWriter/ELF/TargetLayout.h --------------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_ELF_DEFAULT_LAYOUT_H
-#define LLD_READER_WRITER_ELF_DEFAULT_LAYOUT_H
-
-#include "Atoms.h"
-#include "HeaderChunks.h"
-#include "SectionChunks.h"
-#include "SegmentChunks.h"
-#include "llvm/ADT/DenseSet.h"
-#include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/StringRef.h"
-#include <unordered_map>
-
-namespace lld {
-namespace elf {
-
-/// \brief The TargetLayout 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 TargetLayout
-/// class
-template <class ELFT> class TargetLayout {
-public:
- typedef uint32_t SectionOrder;
- typedef uint32_t SegmentType;
-
- // 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;
-
- // Properties used during segment creation
- struct SegmentKey {
- SegmentKey(StringRef name, int64_t type, uint64_t flags, bool segFlags)
- : _name(name), _type(type), _flags(flags),
- _segmentFlags(segFlags && flags != 0) {}
- StringRef _name = "";
- int64_t _type = 0;
- uint64_t _flags = 0;
- bool _segmentFlags = false;
- };
-
- struct SegmentKeyHash {
- int64_t operator()(const SegmentKey &k) const {
- return llvm::hash_combine(k._name, k._type, k._flags);
- }
- };
-
- struct SegmentKeyEq {
- bool operator()(const SegmentKey &lhs, const SegmentKey &rhs) const {
- return ((lhs._name == rhs._name) && (lhs._type == rhs._type) &&
- (lhs._flags == rhs._flags));
- }
- };
-
- // Output Sections contain the map of Section names 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<SegmentKey, Segment<ELFT> *, SegmentKeyHash,
- SegmentKeyEq> SegmentMapT;
-
- typedef typename std::vector<AtomLayout *>::iterator AbsoluteAtomIterT;
-
- typedef llvm::DenseSet<const Atom *> AtomSetT;
-
- TargetLayout(ELFLinkingContext &ctx)
- : _ctx(ctx), _linkerScriptSema(ctx.linkerScriptSema()) {}
-
- virtual ~TargetLayout() = default;
-
- /// \brief Return the section order for a input section
- virtual SectionOrder getSectionOrder(StringRef name, int32_t contentType,
- int32_t contentPermissions);
-
- /// \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 SegmentType getSegmentType(const 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);
-
- /// \brief Append the Atom to the layout and create appropriate sections.
- /// \returns A reference to the atom layout or an error. The atom layout will
- /// be updated as linking progresses.
- virtual ErrorOr<const AtomLayout *> addAtom(const Atom *atom);
-
- /// \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
- AtomLayout *findAbsoluteAtom(StringRef name) {
- auto iter = std::find_if(
- _absoluteAtoms.begin(), _absoluteAtoms.end(),
- [=](const AtomLayout *a) { return a->_atom->name() == name; });
- if (iter == _absoluteAtoms.end())
- return nullptr;
- return *iter;
- }
-
- // Output sections with the same name into a OutputSection
- void createOutputSections();
-
- // Query for segments based on output and input sections
- std::vector<SegmentKey> getSegmentsForSection(const OutputSection<ELFT> *os,
- const Section<ELFT> *sec) const;
-
- /// \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);
-
- /// \brief associates a section to a segment
- virtual void assignSectionsToSegments();
-
- /// \brief associates a virtual address to the segment, section, and the atom
- virtual void assignVirtualAddress();
-
- 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();
- }
-
- /// \brief find the Atom in the current layout
- virtual const AtomLayout *findAtomLayoutByName(StringRef name) const;
-
- 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();
-
- /// \brief Get or create the PLT relocation table. Referenced by DT_JMPREL.
- RelocationTable<ELFT> *getPLTRelocationTable();
-
- uint64_t getTLSSize() const;
-
- bool isReferencedByDefinedAtom(const Atom *a) const {
- return _referencedDynAtoms.count(a);
- }
-
- bool isCopied(const SharedLibraryAtom *sla) const {
- return _copiedDynSymNames.count(sla->name());
- }
-
-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>(_ctx, name, order));
- }
-
- virtual uint64_t getLookupSectionFlags(const OutputSection<ELFT> *os) const;
-
- /// \brief Sort segements stored in the _segments
- virtual void sortSegments();
-
-protected:
- llvm::BumpPtrAllocator _allocator;
- SectionMapT _sectionMap;
- OutputSectionMapT _outputSectionMap;
- 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<AtomLayout *> _absoluteAtoms;
- AtomSetT _referencedDynAtoms;
- llvm::StringSet<> _copiedDynSymNames;
- ELFLinkingContext &_ctx;
- script::Sema &_linkerScriptSema;
-};
-
-} // end namespace elf
-} // end namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/ELF/Writer.cpp b/lib/ReaderWriter/ELF/Writer.cpp
deleted file mode 100644
index 1c5d9766e9c5..000000000000
--- a/lib/ReaderWriter/ELF/Writer.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-//===- lib/ReaderWriter/ELF/WriterELF.cpp ---------------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "lld/Core/Writer.h"
-#include "DynamicLibraryWriter.h"
-#include "ExecutableWriter.h"
-
-using namespace llvm;
-using namespace llvm::object;
-
-namespace lld {
-
-std::unique_ptr<Writer> createWriterELF(const ELFLinkingContext &ctx) {
- return ctx.getTargetHandler().getWriter();
-}
-
-} // namespace lld
diff --git a/lib/ReaderWriter/ELF/Writer.h b/lib/ReaderWriter/ELF/Writer.h
deleted file mode 100644
index 8b3e8f90638a..000000000000
--- a/lib/ReaderWriter/ELF/Writer.h
+++ /dev/null
@@ -1,35 +0,0 @@
-//===- lib/ReaderWriter/ELF/Writer.h --------------------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_ELF_WRITER_H
-#define LLD_READER_WRITER_ELF_WRITER_H
-
-#include "lld/Core/File.h"
-#include "lld/Core/Writer.h"
-
-namespace lld {
-namespace elf {
-/// \brief The Writer class is a base class for the linker to write
-/// various kinds of ELF files.
-class ELFWriter : public Writer {
-public:
- /// \brief builds the chunks that needs to be written to the output
- /// ELF file
- virtual void buildChunks(const File &file) = 0;
-
- /// \brief Writes the chunks into the output file specified by path
- std::error_code writeFile(const File &file, StringRef path) override = 0;
-
- /// \brief Get the virtual address of \p atom after layout.
- virtual uint64_t addressOfAtom(const Atom *atom) = 0;
-};
-} // end namespace elf
-} // end namespace lld
-
-#endif // LLD_READER_WRITER_ELF_WRITER_H
diff --git a/lib/ReaderWriter/ELF/X86/CMakeLists.txt b/lib/ReaderWriter/ELF/X86/CMakeLists.txt
deleted file mode 100644
index 5e3fe64dc15d..000000000000
--- a/lib/ReaderWriter/ELF/X86/CMakeLists.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-add_lld_library(lldX86ELFTarget
- X86LinkingContext.cpp
- X86TargetHandler.cpp
- X86RelocationHandler.cpp
- LINK_LIBS
- lldELF
- lldReaderWriter
- lldCore
- LLVMObject
- LLVMSupport
- )
diff --git a/lib/ReaderWriter/ELF/X86/X86DynamicLibraryWriter.h b/lib/ReaderWriter/ELF/X86/X86DynamicLibraryWriter.h
deleted file mode 100644
index dd2184d7201e..000000000000
--- a/lib/ReaderWriter/ELF/X86/X86DynamicLibraryWriter.h
+++ /dev/null
@@ -1,44 +0,0 @@
-//===- lib/ReaderWriter/ELF/X86/X86DynamicLibraryWriter.h -----------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef X86_X86_DYNAMIC_LIBRARY_WRITER_H
-#define X86_X86_DYNAMIC_LIBRARY_WRITER_H
-
-#include "DynamicLibraryWriter.h"
-#include "X86LinkingContext.h"
-
-namespace lld {
-namespace elf {
-
-class X86DynamicLibraryWriter : public DynamicLibraryWriter<ELF32LE> {
-public:
- X86DynamicLibraryWriter(X86LinkingContext &ctx,
- TargetLayout<ELF32LE> &layout);
-
-protected:
- // Add any runtime files and their atoms to the output
- void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
-};
-
-X86DynamicLibraryWriter::X86DynamicLibraryWriter(X86LinkingContext &ctx,
- TargetLayout<ELF32LE> &layout)
- : DynamicLibraryWriter(ctx, layout) {}
-
-void X86DynamicLibraryWriter::createImplicitFiles(
- std::vector<std::unique_ptr<File>> &result) {
- DynamicLibraryWriter::createImplicitFiles(result);
- auto gotFile = llvm::make_unique<SimpleFile>("GOTFile");
- gotFile->addAtom(*new (gotFile->allocator()) GlobalOffsetTableAtom(*gotFile));
- gotFile->addAtom(*new (gotFile->allocator()) DynamicAtom(*gotFile));
- result.push_back(std::move(gotFile));
-}
-
-} // namespace elf
-} // namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/ELF/X86/X86ExecutableWriter.h b/lib/ReaderWriter/ELF/X86/X86ExecutableWriter.h
deleted file mode 100644
index 70aabde3ad2c..000000000000
--- a/lib/ReaderWriter/ELF/X86/X86ExecutableWriter.h
+++ /dev/null
@@ -1,39 +0,0 @@
-//===- lib/ReaderWriter/ELF/X86/X86ExecutableWriter.h ---------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef X86_X86_EXECUTABLE_WRITER_H
-#define X86_X86_EXECUTABLE_WRITER_H
-
-#include "ExecutableWriter.h"
-#include "X86LinkingContext.h"
-
-namespace lld {
-namespace elf {
-
-class X86ExecutableWriter : public ExecutableWriter<ELF32LE> {
-public:
- X86ExecutableWriter(X86LinkingContext &ctx, TargetLayout<ELF32LE> &layout);
-
-protected:
- // Add any runtime files and their atoms to the output
- void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
-};
-
-X86ExecutableWriter::X86ExecutableWriter(X86LinkingContext &ctx,
- TargetLayout<ELF32LE> &layout)
- : ExecutableWriter(ctx, layout) {}
-
-void X86ExecutableWriter::createImplicitFiles(
- std::vector<std::unique_ptr<File>> &result) {
- ExecutableWriter::createImplicitFiles(result);
-}
-
-} // namespace elf
-} // namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/ELF/X86/X86LinkingContext.cpp b/lib/ReaderWriter/ELF/X86/X86LinkingContext.cpp
deleted file mode 100644
index dc45efc390fd..000000000000
--- a/lib/ReaderWriter/ELF/X86/X86LinkingContext.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-//===- lib/ReaderWriter/ELF/X86/X86LinkingContext.cpp ---------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "X86LinkingContext.h"
-#include "X86TargetHandler.h"
-#include "lld/Core/LLVM.h"
-#include "llvm/ADT/StringSwitch.h"
-#include "llvm/Support/ErrorOr.h"
-
-using namespace lld;
-using namespace lld::elf;
-
-std::unique_ptr<ELFLinkingContext>
-elf::createX86LinkingContext(llvm::Triple triple) {
- if (triple.getArch() == llvm::Triple::x86)
- return llvm::make_unique<X86LinkingContext>(triple);
- return nullptr;
-}
-
-X86LinkingContext::X86LinkingContext(llvm::Triple triple)
- : ELFLinkingContext(triple, llvm::make_unique<X86TargetHandler>(*this)) {}
-
-static const Registry::KindStrings kindStrings[] = {
-#define ELF_RELOC(name, value) LLD_KIND_STRING_ENTRY(name),
-#include "llvm/Support/ELFRelocs/i386.def"
-#undef ELF_RELOC
- LLD_KIND_STRING_END
-};
-
-void X86LinkingContext::registerRelocationNames(Registry &registry) {
- registry.addKindTable(Reference::KindNamespace::ELF, Reference::KindArch::x86,
- kindStrings);
-}
diff --git a/lib/ReaderWriter/ELF/X86/X86LinkingContext.h b/lib/ReaderWriter/ELF/X86/X86LinkingContext.h
deleted file mode 100644
index f6ab3e980d7d..000000000000
--- a/lib/ReaderWriter/ELF/X86/X86LinkingContext.h
+++ /dev/null
@@ -1,44 +0,0 @@
-//===- lib/ReaderWriter/ELF/X86/X86LinkingContext.h -----------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_ELF_X86_TARGETINFO_H
-#define LLD_READER_WRITER_ELF_X86_TARGETINFO_H
-
-#include "lld/ReaderWriter/ELFLinkingContext.h"
-#include "llvm/Object/ELF.h"
-#include "llvm/Support/ELF.h"
-
-namespace lld {
-namespace elf {
-class X86LinkingContext final : public ELFLinkingContext {
-public:
- static std::unique_ptr<ELFLinkingContext> create(llvm::Triple);
- int getMachineType() const override { return llvm::ELF::EM_386; }
- X86LinkingContext(llvm::Triple);
- void registerRelocationNames(Registry &r) override;
-
- /// \brief X86 has only two relative relocation
- /// a) for supporting IFUNC relocs - R_386_IRELATIVE
- /// b) for supporting relative relocs - R_386_RELATIVE
- bool isRelativeReloc(const Reference &r) const override {
- if (r.kindNamespace() != Reference::KindNamespace::ELF)
- return false;
- assert(r.kindArch() == Reference::KindArch::x86);
- switch (r.kindValue()) {
- case llvm::ELF::R_386_IRELATIVE:
- case llvm::ELF::R_386_RELATIVE:
- return true;
- default:
- return false;
- }
- }
-};
-} // end namespace elf
-} // end namespace lld
-#endif
diff --git a/lib/ReaderWriter/ELF/X86/X86RelocationHandler.cpp b/lib/ReaderWriter/ELF/X86/X86RelocationHandler.cpp
deleted file mode 100644
index 15774bc33123..000000000000
--- a/lib/ReaderWriter/ELF/X86/X86RelocationHandler.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-//===- lib/ReaderWriter/ELF/X86/X86RelocationHandler.cpp ------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "X86LinkingContext.h"
-#include "X86TargetHandler.h"
-#include "llvm/Support/Endian.h"
-
-using namespace lld;
-using namespace lld::elf;
-using namespace llvm::support::endian;
-
-/// \brief R_386_32 - word32: S + A
-static int reloc32(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) {
- int32_t result = (uint32_t)(S + A);
- write32le(location, result | read32le(location));
- return 0;
-}
-
-/// \brief R_386_PC32 - word32: S + A - P
-static int relocPC32(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) {
- uint32_t result = (uint32_t)(S + A - P);
- write32le(location, result + read32le(location));
- return 0;
-}
-
-std::error_code X86TargetRelocationHandler::applyRelocation(
- ELFWriter &writer, llvm::FileOutputBuffer &buf, const AtomLayout &atom,
- const Reference &ref) const {
- uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset;
- uint8_t *loc = atomContent + ref.offsetInAtom();
- uint64_t target = writer.addressOfAtom(ref.target());
- uint64_t reloc = atom._virtualAddr + ref.offsetInAtom();
-
- if (ref.kindNamespace() != Reference::KindNamespace::ELF)
- return std::error_code();
- assert(ref.kindArch() == Reference::KindArch::x86);
- switch (ref.kindValue()) {
- case R_386_32:
- reloc32(loc, reloc, target, ref.addend());
- break;
- case R_386_PC32:
- relocPC32(loc, reloc, target, ref.addend());
- break;
- default:
- return make_unhandled_reloc_error();
- }
- return std::error_code();
-}
diff --git a/lib/ReaderWriter/ELF/X86/X86RelocationHandler.h b/lib/ReaderWriter/ELF/X86/X86RelocationHandler.h
deleted file mode 100644
index 1131635c6735..000000000000
--- a/lib/ReaderWriter/ELF/X86/X86RelocationHandler.h
+++ /dev/null
@@ -1,28 +0,0 @@
-//===- lib/ReaderWriter/ELF/X86/X86RelocationHandler.h --------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef X86_X86_RELOCATION_HANDLER_H
-#define X86_X86_RELOCATION_HANDLER_H
-
-#include "lld/ReaderWriter/ELFLinkingContext.h"
-
-namespace lld {
-namespace elf {
-
-class X86TargetRelocationHandler final : public TargetRelocationHandler {
-public:
- std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &,
- const AtomLayout &,
- const Reference &) const override;
-};
-
-} // end namespace elf
-} // end namespace lld
-
-#endif // X86_X86_RELOCATION_HANDLER_H
diff --git a/lib/ReaderWriter/ELF/X86/X86TargetHandler.cpp b/lib/ReaderWriter/ELF/X86/X86TargetHandler.cpp
deleted file mode 100644
index c01ed7258f1c..000000000000
--- a/lib/ReaderWriter/ELF/X86/X86TargetHandler.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-//===- lib/ReaderWriter/ELF/X86/X86TargetHandler.cpp ----------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "X86TargetHandler.h"
-#include "X86DynamicLibraryWriter.h"
-#include "X86ExecutableWriter.h"
-#include "X86LinkingContext.h"
-#include "X86RelocationHandler.h"
-
-using namespace lld;
-using namespace elf;
-
-using namespace llvm::ELF;
-
-std::unique_ptr<Writer> X86TargetHandler::getWriter() {
- switch (_ctx.getOutputELFType()) {
- case llvm::ELF::ET_EXEC:
- return llvm::make_unique<X86ExecutableWriter>(_ctx, *_targetLayout);
- case llvm::ELF::ET_DYN:
- return llvm::make_unique<X86DynamicLibraryWriter>(_ctx, *_targetLayout);
- case llvm::ELF::ET_REL:
- llvm_unreachable("TODO: support -r mode");
- default:
- llvm_unreachable("unsupported output type");
- }
-}
-
-X86TargetHandler::X86TargetHandler(X86LinkingContext &ctx)
- : _ctx(ctx), _targetLayout(new TargetLayout<ELF32LE>(ctx)),
- _relocationHandler(new X86TargetRelocationHandler()) {}
diff --git a/lib/ReaderWriter/ELF/X86/X86TargetHandler.h b/lib/ReaderWriter/ELF/X86/X86TargetHandler.h
deleted file mode 100644
index fecf9abfc678..000000000000
--- a/lib/ReaderWriter/ELF/X86/X86TargetHandler.h
+++ /dev/null
@@ -1,48 +0,0 @@
-//===- lib/ReaderWriter/ELF/X86/X86TargetHandler.h ------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_ELF_X86_TARGET_HANDLER_H
-#define LLD_READER_WRITER_ELF_X86_TARGET_HANDLER_H
-
-#include "TargetLayout.h"
-#include "ELFReader.h"
-#include "X86RelocationHandler.h"
-
-namespace lld {
-namespace elf {
-
-class X86LinkingContext;
-
-class X86TargetHandler final : public TargetHandler {
-public:
- X86TargetHandler(X86LinkingContext &ctx);
-
- const TargetRelocationHandler &getRelocationHandler() const override {
- return *_relocationHandler;
- }
-
- std::unique_ptr<Reader> getObjReader() override {
- return llvm::make_unique<ELFReader<ELFFile<ELF32LE>>>(_ctx);
- }
-
- std::unique_ptr<Reader> getDSOReader() override {
- return llvm::make_unique<ELFReader<DynamicFile<ELF32LE>>>(_ctx);
- }
-
- std::unique_ptr<Writer> getWriter() override;
-
-protected:
- X86LinkingContext &_ctx;
- std::unique_ptr<TargetLayout<ELF32LE>> _targetLayout;
- std::unique_ptr<X86TargetRelocationHandler> _relocationHandler;
-};
-} // end namespace elf
-} // end namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/ELF/X86_64/CMakeLists.txt b/lib/ReaderWriter/ELF/X86_64/CMakeLists.txt
deleted file mode 100644
index 61f4b4b524e8..000000000000
--- a/lib/ReaderWriter/ELF/X86_64/CMakeLists.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-add_lld_library(lldX86_64ELFTarget
- X86_64LinkingContext.cpp
- X86_64TargetHandler.cpp
- X86_64RelocationHandler.cpp
- X86_64RelocationPass.cpp
- X86_64SectionChunks.cpp
- LINK_LIBS
- lldELF
- lldReaderWriter
- lldCore
- LLVMObject
- LLVMSupport
- )
-
-include_directories(.)
-
-add_subdirectory(ExampleSubTarget)
diff --git a/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/CMakeLists.txt b/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/CMakeLists.txt
deleted file mode 100644
index 700b2550b119..000000000000
--- a/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/CMakeLists.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-add_lld_library(lldExampleSubTarget
- ExampleLinkingContext.cpp
- ExampleTargetHandler.cpp
- LINK_LIBS
- lldX86_64ELFTarget
- lldELF
- lldReaderWriter
- lldCore
- LLVMObject
- LLVMSupport
- )
diff --git a/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleLinkingContext.cpp b/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleLinkingContext.cpp
deleted file mode 100644
index cb3e819aff6b..000000000000
--- a/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleLinkingContext.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-//===- lib/ReaderWriter/ELF/X86_64/ExampleTarget/ExampleLinkingContext.cpp ----===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ExampleLinkingContext.h"
-#include "ExampleTargetHandler.h"
-
-using namespace lld;
-using namespace elf;
-
-std::unique_ptr<ELFLinkingContext>
-elf::createExampleLinkingContext(llvm::Triple triple) {
- if (triple.getVendorName() == "example")
- return llvm::make_unique<ExampleLinkingContext>(triple);
- return nullptr;
-}
-
-ExampleLinkingContext::ExampleLinkingContext(llvm::Triple triple)
- : X86_64LinkingContext(triple, std::unique_ptr<TargetHandler>(
- new ExampleTargetHandler(*this))) {
- _outputELFType = llvm::ELF::ET_LOPROC;
-}
-
-StringRef ExampleLinkingContext::entrySymbolName() const {
- return "_start";
-}
-
-void ExampleLinkingContext::addPasses(PassManager &p) {
- ELFLinkingContext::addPasses(p);
-}
diff --git a/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleLinkingContext.h b/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleLinkingContext.h
deleted file mode 100644
index 5bb11cd35b41..000000000000
--- a/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleLinkingContext.h
+++ /dev/null
@@ -1,31 +0,0 @@
-//===- lib/ReaderWriter/ELF/X86_64/ExampleTarget/ExampleLinkingContext.h --===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_ELF_X86_64_EXAMPLE_TARGET_EXAMPLE_LINKING_CONTEXT
-#define LLD_READER_WRITER_ELF_X86_64_EXAMPLE_TARGET_EXAMPLE_LINKING_CONTEXT
-
-#include "X86_64LinkingContext.h"
-#include "X86_64TargetHandler.h"
-
-namespace lld {
-namespace elf {
-
-class ExampleLinkingContext final : public X86_64LinkingContext {
-public:
- static std::unique_ptr<ELFLinkingContext> create(llvm::Triple);
- ExampleLinkingContext(llvm::Triple triple);
-
- StringRef entrySymbolName() const override;
- void addPasses(PassManager &) override;
-};
-
-} // end namespace elf
-} // end namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleTargetHandler.cpp b/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleTargetHandler.cpp
deleted file mode 100644
index 89ec6671f3a0..000000000000
--- a/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleTargetHandler.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-//===- lib/ReaderWriter/ELF/X86_64/ExampleTarget/ExampleTargetHandler.cpp -===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ExampleTargetHandler.h"
-#include "X86_64ExecutableWriter.h"
-#include "ExampleLinkingContext.h"
-
-using namespace lld;
-using namespace elf;
-
-ExampleTargetHandler::ExampleTargetHandler(ExampleLinkingContext &c)
- : X86_64TargetHandler(c), _ctx(c) {}
-
-std::unique_ptr<Writer> ExampleTargetHandler::getWriter() {
- return llvm::make_unique<X86_64ExecutableWriter>(_ctx, *_targetLayout);
-}
diff --git a/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleTargetHandler.h b/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleTargetHandler.h
deleted file mode 100644
index 46eade5864f9..000000000000
--- a/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleTargetHandler.h
+++ /dev/null
@@ -1,31 +0,0 @@
-//===- lib/ReaderWriter/ELF/X86_64/ExampleTarget/ExampleTargetHandler.h ---===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_ELF_X86_64_EXAMPLE_TARGET_EXAMPLE_TARGET_HANDLER_H
-#define LLD_READER_WRITER_ELF_X86_64_EXAMPLE_TARGET_EXAMPLE_TARGET_HANDLER_H
-
-#include "X86_64TargetHandler.h"
-
-namespace lld {
-namespace elf {
-class ExampleLinkingContext;
-
-class ExampleTargetHandler final : public X86_64TargetHandler {
-public:
- ExampleTargetHandler(ExampleLinkingContext &c);
-
- std::unique_ptr<Writer> getWriter() override;
-
-private:
- ExampleLinkingContext &_ctx;
-};
-} // end namespace elf
-} // end namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/ELF/X86_64/TODO.rst b/lib/ReaderWriter/ELF/X86_64/TODO.rst
deleted file mode 100644
index a2411a00d1ea..000000000000
--- a/lib/ReaderWriter/ELF/X86_64/TODO.rst
+++ /dev/null
@@ -1,46 +0,0 @@
-ELF x86-64
-~~~~~~~~~~
-
-Unimplemented Features
-######################
-
-* Code models other than the small code model
-* TLS strength reduction
-
-Unimplemented Relocations
-#########################
-
-All of these relocations are defined in:
-http://www.x86-64.org/documentation/abi.pdf
-
-Trivial Relocs
-<<<<<<<<<<<<<<
-
-These are very simple relocation calculations to implement.
-See lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp
-
-* R_X86_64_8
-* R_X86_64_PC8
-* R_X86_64_SIZE32
-* R_X86_64_SIZE64
-* R_X86_64_GOTPC32 (this relocation requires there to be a __GLOBAL_OFFSET_TABLE__)
-
-Global Offset Table Relocs
-<<<<<<<<<<<<<<<<<<<<<<<<<<
-
-* R_X86_64_GOTOFF32
-* R_X86_64_GOTOFF64
-
-Global Dynamic Thread Local Storage Relocs
-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
-
-These relocations take more effort to implement, but some of them are done.
-Their implementation lives in lib/ReaderWriter/ELF/X86_64/{X86_64RelocationPass.cpp,X86_64RelocationHandler.cpp}.
-
-Documentation on these relocations can be found in:
-http://www.akkadia.org/drepper/tls.pdf
-http://www.fsfla.org/~lxoliva/writeups/TLS/RFC-TLSDESC-x86.txt
-
-* R_X86_64_GOTPC32_TLSDESC
-* R_X86_64_TLSDESC_CALL
-* R_X86_64_TLSDESC
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64DynamicLibraryWriter.h b/lib/ReaderWriter/ELF/X86_64/X86_64DynamicLibraryWriter.h
deleted file mode 100644
index f84f85223bfb..000000000000
--- a/lib/ReaderWriter/ELF/X86_64/X86_64DynamicLibraryWriter.h
+++ /dev/null
@@ -1,45 +0,0 @@
-//===- lib/ReaderWriter/ELF/X86/X86_64DynamicLibraryWriter.h ---------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef X86_64_DYNAMIC_LIBRARY_WRITER_H
-#define X86_64_DYNAMIC_LIBRARY_WRITER_H
-
-#include "DynamicLibraryWriter.h"
-#include "X86_64LinkingContext.h"
-#include "X86_64TargetHandler.h"
-
-namespace lld {
-namespace elf {
-
-class X86_64DynamicLibraryWriter : public DynamicLibraryWriter<ELF64LE> {
-public:
- X86_64DynamicLibraryWriter(X86_64LinkingContext &ctx,
- X86_64TargetLayout &layout);
-
-protected:
- // Add any runtime files and their atoms to the output
- void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
-};
-
-X86_64DynamicLibraryWriter::X86_64DynamicLibraryWriter(
- X86_64LinkingContext &ctx, X86_64TargetLayout &layout)
- : DynamicLibraryWriter(ctx, layout) {}
-
-void X86_64DynamicLibraryWriter::createImplicitFiles(
- std::vector<std::unique_ptr<File>> &result) {
- DynamicLibraryWriter::createImplicitFiles(result);
- auto gotFile = llvm::make_unique<SimpleFile>("GOTFile");
- gotFile->addAtom(*new (gotFile->allocator()) GlobalOffsetTableAtom(*gotFile));
- gotFile->addAtom(*new (gotFile->allocator()) DynamicAtom(*gotFile));
- result.push_back(std::move(gotFile));
-}
-
-} // namespace elf
-} // namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64ExecutableWriter.h b/lib/ReaderWriter/ELF/X86_64/X86_64ExecutableWriter.h
deleted file mode 100644
index 930a2de2a9e8..000000000000
--- a/lib/ReaderWriter/ELF/X86_64/X86_64ExecutableWriter.h
+++ /dev/null
@@ -1,57 +0,0 @@
-//===- lib/ReaderWriter/ELF/X86/X86_64ExecutableWriter.h ------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef X86_64_EXECUTABLE_WRITER_H
-#define X86_64_EXECUTABLE_WRITER_H
-
-#include "ExecutableWriter.h"
-#include "X86_64LinkingContext.h"
-
-namespace lld {
-namespace elf {
-
-class X86_64ExecutableWriter : public ExecutableWriter<ELF64LE> {
-public:
- X86_64ExecutableWriter(X86_64LinkingContext &ctx, X86_64TargetLayout &layout)
- : ExecutableWriter(ctx, layout), _targetLayout(layout) {}
-
-protected:
- // Add any runtime files and their atoms to the output
- void
- createImplicitFiles(std::vector<std::unique_ptr<File>> &result) override {
- ExecutableWriter::createImplicitFiles(result);
- auto gotFile = llvm::make_unique<SimpleFile>("GOTFile");
- gotFile->addAtom(*new (gotFile->allocator())
- GlobalOffsetTableAtom(*gotFile));
- if (this->_ctx.isDynamic())
- gotFile->addAtom(*new (gotFile->allocator()) DynamicAtom(*gotFile));
- result.push_back(std::move(gotFile));
- }
-
- void buildDynamicSymbolTable(const File &file) override {
- for (auto sec : this->_layout.sections()) {
- if (auto section = dyn_cast<AtomSection<ELF64LE>>(sec)) {
- for (const auto &atom : section->atoms()) {
- if (_targetLayout.getGOTSection().hasGlobalGOTEntry(atom->_atom)) {
- this->_dynamicSymbolTable->addSymbol(atom->_atom, section->ordinal(),
- atom->_virtualAddr, atom);
- }
- }
- }
- }
-
- ExecutableWriter<ELF64LE>::buildDynamicSymbolTable(file);
- }
-
- X86_64TargetLayout &_targetLayout;
-};
-
-} // namespace elf
-} // namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp b/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp
deleted file mode 100644
index 0dcd6ac6fbed..000000000000
--- a/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-//===- lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp ---------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "X86_64LinkingContext.h"
-#include "X86_64RelocationPass.h"
-#include "X86_64TargetHandler.h"
-
-using namespace lld;
-using namespace lld::elf;
-
-X86_64LinkingContext::X86_64LinkingContext(
- llvm::Triple triple, std::unique_ptr<TargetHandler> handler)
- : ELFLinkingContext(triple, std::move(handler)) {}
-
-X86_64LinkingContext::X86_64LinkingContext(llvm::Triple triple)
- : X86_64LinkingContext(triple,
- llvm::make_unique<X86_64TargetHandler>(*this)) {}
-
-void X86_64LinkingContext::addPasses(PassManager &pm) {
- auto pass = createX86_64RelocationPass(*this);
- if (pass)
- pm.add(std::move(pass));
- ELFLinkingContext::addPasses(pm);
-}
-
-std::unique_ptr<ELFLinkingContext>
-elf::createX86_64LinkingContext(llvm::Triple triple) {
- if (triple.getArch() == llvm::Triple::x86_64)
- return llvm::make_unique<X86_64LinkingContext>(triple);
- return nullptr;
-}
-
-static const Registry::KindStrings kindStrings[] = {
-#define ELF_RELOC(name, value) LLD_KIND_STRING_ENTRY(name),
-#include "llvm/Support/ELFRelocs/x86_64.def"
-#undef ELF_RELOC
- LLD_KIND_STRING_ENTRY(LLD_R_X86_64_GOTRELINDEX),
- LLD_KIND_STRING_END
-};
-
-void X86_64LinkingContext::registerRelocationNames(Registry &registry) {
- registry.addKindTable(Reference::KindNamespace::ELF,
- Reference::KindArch::x86_64, kindStrings);
-}
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h b/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h
deleted file mode 100644
index a5a7b3d21f4e..000000000000
--- a/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h
+++ /dev/null
@@ -1,103 +0,0 @@
-//===- lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h -----------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_ELF_X86_64_X86_64_LINKING_CONTEXT_H
-#define LLD_READER_WRITER_ELF_X86_64_X86_64_LINKING_CONTEXT_H
-
-#include "lld/ReaderWriter/ELFLinkingContext.h"
-#include "llvm/Object/ELF.h"
-#include "llvm/Support/ELF.h"
-
-namespace lld {
-namespace elf {
-
-/// \brief x86-64 internal references.
-enum {
- /// \brief The 32 bit index of the relocation in the got this reference refers
- /// to.
- LLD_R_X86_64_GOTRELINDEX = 1024,
-};
-
-class X86_64LinkingContext : public ELFLinkingContext {
-protected:
- X86_64LinkingContext(llvm::Triple, std::unique_ptr<TargetHandler>);
-
-public:
- static std::unique_ptr<ELFLinkingContext> create(llvm::Triple);
- int getMachineType() const override { return llvm::ELF::EM_X86_64; }
- X86_64LinkingContext(llvm::Triple);
-
- void addPasses(PassManager &) override;
- void registerRelocationNames(Registry &r) override;
-
- uint64_t getBaseAddress() const override {
- if (_baseAddress == 0)
- return 0x400000;
- return _baseAddress;
- }
-
- bool isDynamicRelocation(const Reference &r) const override {
- if (r.kindNamespace() != Reference::KindNamespace::ELF)
- return false;
- assert(r.kindArch() == Reference::KindArch::x86_64);
- switch (r.kindValue()) {
- case llvm::ELF::R_X86_64_RELATIVE:
- case llvm::ELF::R_X86_64_GLOB_DAT:
- case llvm::ELF::R_X86_64_COPY:
- case llvm::ELF::R_X86_64_DTPMOD64:
- case llvm::ELF::R_X86_64_DTPOFF64:
- case llvm::ELF::R_X86_64_TPOFF64:
- return true;
- default:
- return false;
- }
- }
-
- bool isCopyRelocation(const Reference &r) const override {
- if (r.kindNamespace() != Reference::KindNamespace::ELF)
- return false;
- assert(r.kindArch() == Reference::KindArch::x86_64);
- if (r.kindValue() == llvm::ELF::R_X86_64_COPY)
- return true;
- return false;
- }
-
- bool isPLTRelocation(const Reference &r) const override {
- if (r.kindNamespace() != Reference::KindNamespace::ELF)
- return false;
- assert(r.kindArch() == Reference::KindArch::x86_64);
- switch (r.kindValue()) {
- case llvm::ELF::R_X86_64_JUMP_SLOT:
- case llvm::ELF::R_X86_64_IRELATIVE:
- return true;
- default:
- return false;
- }
- }
-
- /// \brief X86_64 has two relative relocations
- /// a) for supporting IFUNC - R_X86_64_IRELATIVE
- /// b) for supporting relative relocs - R_X86_64_RELATIVE
- bool isRelativeReloc(const Reference &r) const override {
- if (r.kindNamespace() != Reference::KindNamespace::ELF)
- return false;
- assert(r.kindArch() == Reference::KindArch::x86_64);
- switch (r.kindValue()) {
- case llvm::ELF::R_X86_64_IRELATIVE:
- case llvm::ELF::R_X86_64_RELATIVE:
- return true;
- default:
- return false;
- }
- }
-};
-} // end namespace elf
-} // end namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp b/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp
deleted file mode 100644
index d56983d1e382..000000000000
--- a/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp
+++ /dev/null
@@ -1,147 +0,0 @@
-//===- lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp ------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "X86_64LinkingContext.h"
-#include "X86_64TargetHandler.h"
-#include "llvm/Support/Endian.h"
-
-using namespace lld;
-using namespace lld::elf;
-using namespace llvm::support::endian;
-
-/// \brief R_X86_64_64 - word64: S + A
-static void reloc64(uint8_t *location, uint64_t P, uint64_t S, int64_t A) {
- uint64_t result = S + A;
- write64le(location, result | read64le(location));
-}
-
-/// \brief R_X86_64_PC32 - word32: S + A - P
-static void relocPC32(uint8_t *location, uint64_t P, uint64_t S, int64_t A) {
- uint32_t result = (uint32_t)(S + A - P);
- write32le(location, result + read32le(location));
-}
-
-/// \brief R_X86_64_32 - word32: S + A
-static void reloc32(uint8_t *location, uint64_t P, uint64_t S, int64_t A) {
- int32_t result = (uint32_t)(S + A);
- write32le(location, result | read32le(location));
- // TODO: Make sure that the result zero extends to the 64bit value.
-}
-
-/// \brief R_X86_64_32S - word32: S + A
-static void reloc32S(uint8_t *location, uint64_t P, uint64_t S, int64_t A) {
- int32_t result = (int32_t)(S + A);
- write32le(location, result | read32le(location));
- // TODO: Make sure that the result sign extends to the 64bit value.
-}
-
-/// \brief R_X86_64_16 - word16: S + A
-static void reloc16(uint8_t *location, uint64_t P, uint64_t S, int64_t A) {
- uint16_t result = (uint16_t)(S + A);
- write16le(location, result | read16le(location));
- // TODO: Check for overflow.
-}
-
-/// \brief R_X86_64_PC16 - word16: S + A - P
-static void relocPC16(uint8_t *location, uint64_t P, uint64_t S, int64_t A) {
- uint16_t result = (uint16_t)(S + A - P);
- write16le(location, result | read16le(location));
- // TODO: Check for overflow.
-}
-
-/// \brief R_X86_64_PC64 - word64: S + A - P
-static void relocPC64(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) {
- int64_t result = (uint64_t)(S + A - P);
- write64le(location, result | read64le(location));
-}
-
-std::error_code X86_64TargetRelocationHandler::applyRelocation(
- ELFWriter &writer, llvm::FileOutputBuffer &buf, const AtomLayout &atom,
- const Reference &ref) const {
- uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset;
- uint8_t *loc = atomContent + ref.offsetInAtom();
- uint64_t target = writer.addressOfAtom(ref.target());
- uint64_t reloc = atom._virtualAddr + ref.offsetInAtom();
-
- if (ref.kindNamespace() != Reference::KindNamespace::ELF)
- return std::error_code();
- assert(ref.kindArch() == Reference::KindArch::x86_64);
- switch (ref.kindValue()) {
- case R_X86_64_NONE:
- break;
- case R_X86_64_64:
- reloc64(loc, reloc, target, ref.addend());
- break;
- case R_X86_64_PC32:
- case R_X86_64_GOTPCREL:
- relocPC32(loc, reloc, target, ref.addend());
- break;
- case R_X86_64_32:
- reloc32(loc, reloc, target, ref.addend());
- break;
- case R_X86_64_32S:
- reloc32S(loc, reloc, target, ref.addend());
- break;
- case R_X86_64_16:
- reloc16(loc, reloc, target, ref.addend());
- break;
- case R_X86_64_PC16:
- relocPC16(loc, reloc, target, ref.addend());
- break;
- case R_X86_64_DTPOFF32:
- case R_X86_64_TPOFF32:
- _tlsSize = _layout.getTLSSize();
- write32le(loc, target - _tlsSize);
- break;
- case R_X86_64_GOTTPOFF:
- relocPC32(loc, reloc, target, ref.addend());
- break;
- case R_X86_64_TLSGD: {
- relocPC32(loc, reloc, target, ref.addend());
- break;
- }
- case R_X86_64_TLSLD: {
- // Rewrite to move %fs:0 into %rax. Technically we should verify that the
- // next relocation is a PC32 to __tls_get_addr...
- static uint8_t instr[] = { 0x66, 0x66, 0x66, 0x64, 0x48, 0x8b, 0x04, 0x25,
- 0x00, 0x00, 0x00, 0x00 };
- std::memcpy(loc - 3, instr, sizeof(instr));
- break;
- }
- case R_X86_64_PC64:
- relocPC64(loc, reloc, target, ref.addend());
- break;
- case LLD_R_X86_64_GOTRELINDEX: {
- const DefinedAtom *target = cast<const DefinedAtom>(ref.target());
- for (const Reference *r : *target) {
- if (r->kindValue() == R_X86_64_JUMP_SLOT) {
- uint32_t index;
- if (!_layout.getPLTRelocationTable()->getRelocationIndex(*r, index))
- llvm_unreachable("Relocation doesn't exist");
- reloc32(loc, 0, index, 0);
- break;
- }
- }
- break;
- }
- // Runtime only relocations. Ignore here.
- case R_X86_64_RELATIVE:
- case R_X86_64_IRELATIVE:
- case R_X86_64_JUMP_SLOT:
- case R_X86_64_GLOB_DAT:
- case R_X86_64_DTPMOD64:
- case R_X86_64_DTPOFF64:
- case R_X86_64_TPOFF64:
- break;
- default:
- return make_unhandled_reloc_error();
- }
-
- return std::error_code();
-}
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.h b/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.h
deleted file mode 100644
index 26382804549b..000000000000
--- a/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.h
+++ /dev/null
@@ -1,37 +0,0 @@
-//===- lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.h --------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef X86_64_RELOCATION_HANDLER_H
-#define X86_64_RELOCATION_HANDLER_H
-
-#include "lld/ReaderWriter/ELFLinkingContext.h"
-
-namespace lld {
-namespace elf {
-class X86_64TargetLayout;
-
-class X86_64TargetRelocationHandler final : public TargetRelocationHandler {
-public:
- X86_64TargetRelocationHandler(X86_64TargetLayout &layout)
- : _tlsSize(0), _layout(layout) {}
-
- std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &,
- const AtomLayout &,
- const Reference &) const override;
-
-private:
- // Cached size of the TLS segment.
- mutable uint64_t _tlsSize;
- X86_64TargetLayout &_layout;
-};
-
-} // end namespace elf
-} // end namespace lld
-
-#endif // X86_64_RELOCATION_HANDLER_H
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp b/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp
deleted file mode 100644
index a2f10dc08a4e..000000000000
--- a/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp
+++ /dev/null
@@ -1,513 +0,0 @@
-//===- lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp ---------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// \brief Defines the relocation processing pass for x86-64. This includes
-/// GOT and PLT entries, TLS, COPY, and ifunc.
-///
-/// This is based on section 4.4.1 of the AMD64 ABI (no stable URL as of Oct,
-/// 2013).
-///
-/// This also includes aditional behaivor that gnu-ld and gold implement but
-/// which is not specified anywhere.
-///
-//===----------------------------------------------------------------------===//
-
-#include "X86_64RelocationPass.h"
-#include "Atoms.h"
-#include "X86_64LinkingContext.h"
-#include "lld/Core/Simple.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/STLExtras.h"
-
-using namespace lld;
-using namespace lld::elf;
-using namespace llvm::ELF;
-
-// .got values
-static const uint8_t x86_64GotAtomContent[8] = {0};
-
-// .plt value (entry 0)
-static const uint8_t x86_64Plt0AtomContent[16] = {
- 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushq GOT+8(%rip)
- 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *GOT+16(%rip)
- 0x90, 0x90, 0x90, 0x90 // nopnopnop
-};
-
-// .plt values (other entries)
-static const uint8_t x86_64PltAtomContent[16] = {
- 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmpq *gotatom(%rip)
- 0x68, 0x00, 0x00, 0x00, 0x00, // pushq reloc-index
- 0xe9, 0x00, 0x00, 0x00, 0x00 // jmpq plt[-1]
-};
-
-// TLS GD Entry
-static const uint8_t x86_64GotTlsGdAtomContent[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
-
-namespace {
-/// \brief Atoms that are used by X86_64 dynamic linking
-class X86_64GOTAtom : public GOTAtom {
-public:
- X86_64GOTAtom(const File &f, StringRef secName) : GOTAtom(f, secName) {}
-
- ArrayRef<uint8_t> rawContent() const override {
- return ArrayRef<uint8_t>(x86_64GotAtomContent, 8);
- }
-};
-
-/// \brief X86_64 GOT TLS GD entry.
-class GOTTLSGdAtom : public X86_64GOTAtom {
-public:
- GOTTLSGdAtom(const File &f, StringRef secName) : X86_64GOTAtom(f, secName) {}
-
- ArrayRef<uint8_t> rawContent() const override {
- return llvm::makeArrayRef(x86_64GotTlsGdAtomContent);
- }
-};
-
-class X86_64PLT0Atom : public PLT0Atom {
-public:
- X86_64PLT0Atom(const File &f) : PLT0Atom(f) {}
- ArrayRef<uint8_t> rawContent() const override {
- return ArrayRef<uint8_t>(x86_64Plt0AtomContent, 16);
- }
-};
-
-class X86_64PLTAtom : public PLTAtom {
-public:
- X86_64PLTAtom(const File &f, StringRef secName) : PLTAtom(f, secName) {}
-
- ArrayRef<uint8_t> rawContent() const override {
- return ArrayRef<uint8_t>(x86_64PltAtomContent, 16);
- }
-};
-
-class ELFPassFile : public SimpleFile {
-public:
- ELFPassFile(const ELFLinkingContext &eti) : SimpleFile("ELFPassFile") {
- setOrdinal(eti.getNextOrdinalAndIncrement());
- }
-
- llvm::BumpPtrAllocator _alloc;
-};
-
-/// \brief CRTP base for handling relocations.
-template <class Derived> class RelocationPass : public Pass {
- /// \brief Handle a specific reference.
- void handleReference(const DefinedAtom &atom, const Reference &ref) {
- if (ref.kindNamespace() != Reference::KindNamespace::ELF)
- return;
- assert(ref.kindArch() == Reference::KindArch::x86_64);
- switch (ref.kindValue()) {
- case R_X86_64_16:
- case R_X86_64_32:
- case R_X86_64_32S:
- case R_X86_64_64:
- case R_X86_64_PC16:
- case R_X86_64_PC32:
- case R_X86_64_PC64:
- static_cast<Derived *>(this)->handlePlain(ref);
- break;
- case R_X86_64_PLT32:
- static_cast<Derived *>(this)->handlePLT32(ref);
- break;
- case R_X86_64_GOT32:
- case R_X86_64_GOTPC32:
- case R_X86_64_GOTPCREL:
- case R_X86_64_GOTOFF64:
- static_cast<Derived *>(this)->handleGOT(ref);
- break;
- case R_X86_64_GOTTPOFF: // GOT Thread Pointer Offset
- static_cast<Derived *>(this)->handleGOTTPOFF(ref);
- break;
- case R_X86_64_TLSGD:
- static_cast<Derived *>(this)->handleTLSGd(ref);
- break;
- }
- }
-
-protected:
- /// \brief get the PLT entry for a given IFUNC Atom.
- ///
- /// If the entry does not exist. Both the GOT and PLT entry is created.
- const PLTAtom *getIFUNCPLTEntry(const DefinedAtom *da) {
- auto plt = _pltMap.find(da);
- if (plt != _pltMap.end())
- return plt->second;
- auto ga = new (_file._alloc) X86_64GOTAtom(_file, ".got.plt");
- ga->addReferenceELF_x86_64(R_X86_64_IRELATIVE, 0, da, 0);
- auto pa = new (_file._alloc) X86_64PLTAtom(_file, ".plt");
- pa->addReferenceELF_x86_64(R_X86_64_PC32, 2, ga, -4);
-#ifndef NDEBUG
- ga->_name = "__got_ifunc_";
- ga->_name += da->name();
- pa->_name = "__plt_ifunc_";
- pa->_name += da->name();
-#endif
- _gotMap[da] = ga;
- _pltMap[da] = pa;
- _gotVector.push_back(ga);
- _pltVector.push_back(pa);
- return pa;
- }
-
- /// \brief Redirect the call to the PLT stub for the target IFUNC.
- ///
- /// This create a PLT and GOT entry for the IFUNC if one does not exist. The
- /// GOT entry and a IRELATIVE relocation to the original target resolver.
- std::error_code handleIFUNC(const Reference &ref) {
- auto target = dyn_cast_or_null<const DefinedAtom>(ref.target());
- if (target && target->contentType() == DefinedAtom::typeResolver)
- const_cast<Reference &>(ref).setTarget(getIFUNCPLTEntry(target));
- return std::error_code();
- }
-
- /// \brief Create a GOT entry for the TP offset of a TLS atom.
- const GOTAtom *getGOTTPOFF(const Atom *atom) {
- auto got = _gotMap.find(atom);
- if (got == _gotMap.end()) {
- auto g = new (_file._alloc) X86_64GOTAtom(_file, ".got");
- g->addReferenceELF_x86_64(R_X86_64_TPOFF64, 0, atom, 0);
-#ifndef NDEBUG
- g->_name = "__got_tls_";
- g->_name += atom->name();
-#endif
- _gotMap[atom] = g;
- _gotVector.push_back(g);
- return g;
- }
- return got->second;
- }
-
- /// \brief Create a TPOFF64 GOT entry.
- std::error_code handleGOTTPOFF(const Reference &ref) {
- if (isa<DefinedAtom>(ref.target())) {
- const_cast<Reference &>(ref).setTarget(getGOTTPOFF(ref.target()));
- }
- return std::error_code();
- }
-
- /// \brief Create a TLS GOT entry with DTPMOD64/DTPOFF64 dynamic relocations.
- void handleTLSGd(const Reference &ref) {
- const_cast<Reference &>(ref).setTarget(getTLSGdGOTEntry(ref.target()));
- }
-
- /// \brief Create a GOT entry containing 0.
- const GOTAtom *getNullGOT() {
- if (!_null) {
- _null = new (_file._alloc) X86_64GOTAtom(_file, ".got.plt");
-#ifndef NDEBUG
- _null->_name = "__got_null";
-#endif
- }
- return _null;
- }
-
- const GOTAtom *getGOT(const DefinedAtom *da) {
- auto got = _gotMap.find(da);
- if (got == _gotMap.end()) {
- auto g = new (_file._alloc) X86_64GOTAtom(_file, ".got");
- g->addReferenceELF_x86_64(R_X86_64_64, 0, da, 0);
-#ifndef NDEBUG
- g->_name = "__got_";
- g->_name += da->name();
-#endif
- _gotMap[da] = g;
- _gotVector.push_back(g);
- return g;
- }
- return got->second;
- }
-
- const GOTAtom *getTLSGdGOTEntry(const Atom *a) {
- auto got = _gotTLSGdMap.find(a);
- if (got != _gotTLSGdMap.end())
- return got->second;
-
- auto ga = new (_file._alloc) GOTTLSGdAtom(_file, ".got");
- _gotTLSGdMap[a] = ga;
-
- _tlsGotVector.push_back(ga);
- ga->addReferenceELF_x86_64(R_X86_64_DTPMOD64, 0, a, 0);
- ga->addReferenceELF_x86_64(R_X86_64_DTPOFF64, 8, a, 0);
-
- return ga;
- }
-
-public:
- RelocationPass(const ELFLinkingContext &ctx) : _file(ctx), _ctx(ctx) {}
-
- /// \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.
- std::error_code perform(SimpleFile &mf) override {
- ScopedTask task(getDefaultDomain(), "X86-64 GOT/PLT Pass");
- // Process all references.
- for (const auto &atom : mf.defined())
- for (const auto &ref : *atom)
- handleReference(*atom, *ref);
-
- // Add all created atoms to the link.
- uint64_t ordinal = 0;
- if (_plt0) {
- _plt0->setOrdinal(ordinal++);
- mf.addAtom(*_plt0);
- }
- for (auto &plt : _pltVector) {
- plt->setOrdinal(ordinal++);
- mf.addAtom(*plt);
- }
- if (_null) {
- _null->setOrdinal(ordinal++);
- mf.addAtom(*_null);
- }
- if (_plt0) {
- _got0->setOrdinal(ordinal++);
- _got1->setOrdinal(ordinal++);
- mf.addAtom(*_got0);
- mf.addAtom(*_got1);
- }
- for (auto &got : _gotVector) {
- got->setOrdinal(ordinal++);
- mf.addAtom(*got);
- }
- for (auto &got : _tlsGotVector) {
- got->setOrdinal(ordinal++);
- mf.addAtom(*got);
- }
- for (auto obj : _objectVector) {
- obj->setOrdinal(ordinal++);
- mf.addAtom(*obj);
- }
- return std::error_code();
- }
-
-protected:
- /// \brief Owner of all the Atoms created by this pass.
- ELFPassFile _file;
- const ELFLinkingContext &_ctx;
-
- /// \brief Map Atoms to their GOT entries.
- llvm::DenseMap<const Atom *, GOTAtom *> _gotMap;
-
- /// \brief Map Atoms to their PLT entries.
- llvm::DenseMap<const Atom *, PLTAtom *> _pltMap;
-
- /// \brief Map Atoms to TLS GD GOT entries.
- llvm::DenseMap<const Atom *, GOTAtom *> _gotTLSGdMap;
-
- /// \brief Map Atoms to their Object entries.
- llvm::DenseMap<const Atom *, ObjectAtom *> _objectMap;
-
- /// \brief the list of GOT/PLT atoms
- std::vector<GOTAtom *> _gotVector;
- std::vector<PLTAtom *> _pltVector;
- std::vector<ObjectAtom *> _objectVector;
-
- /// \brief the list of TLS GOT atoms.
- std::vector<GOTAtom *> _tlsGotVector;
-
- /// \brief GOT entry that is always 0. Used for undefined weaks.
- GOTAtom *_null = nullptr;
-
- /// \brief The got and plt entries for .PLT0. This is used to call into the
- /// dynamic linker for symbol resolution.
- /// @{
- PLT0Atom *_plt0 = nullptr;
- GOTAtom *_got0 = nullptr;
- GOTAtom *_got1 = nullptr;
- /// @}
-};
-
-/// This implements the static relocation model. Meaning GOT and PLT entries are
-/// not created for references that can be directly resolved. These are
-/// converted to a direct relocation. For entries that do require a GOT or PLT
-/// entry, that entry is statically bound.
-///
-/// TLS always assumes module 1 and attempts to remove indirection.
-class StaticRelocationPass final
- : public RelocationPass<StaticRelocationPass> {
-public:
- StaticRelocationPass(const elf::X86_64LinkingContext &ctx)
- : RelocationPass(ctx) {}
-
- std::error_code handlePlain(const Reference &ref) { return handleIFUNC(ref); }
-
- std::error_code handlePLT32(const Reference &ref) {
- // __tls_get_addr is handled elsewhere.
- if (ref.target() && ref.target()->name() == "__tls_get_addr") {
- const_cast<Reference &>(ref).setKindValue(R_X86_64_NONE);
- return std::error_code();
- }
- // Static code doesn't need PLTs.
- const_cast<Reference &>(ref).setKindValue(R_X86_64_PC32);
- // Handle IFUNC.
- if (const DefinedAtom *da =
- dyn_cast_or_null<const DefinedAtom>(ref.target()))
- if (da->contentType() == DefinedAtom::typeResolver)
- return handleIFUNC(ref);
- return std::error_code();
- }
-
- std::error_code handleGOT(const Reference &ref) {
- if (isa<UndefinedAtom>(ref.target()))
- const_cast<Reference &>(ref).setTarget(getNullGOT());
- else if (const DefinedAtom *da = dyn_cast<const DefinedAtom>(ref.target()))
- const_cast<Reference &>(ref).setTarget(getGOT(da));
- return std::error_code();
- }
-};
-
-class DynamicRelocationPass final
- : public RelocationPass<DynamicRelocationPass> {
-public:
- DynamicRelocationPass(const elf::X86_64LinkingContext &ctx)
- : RelocationPass(ctx) {}
-
- const PLT0Atom *getPLT0() {
- if (_plt0)
- return _plt0;
- // Fill in the null entry.
- getNullGOT();
- _plt0 = new (_file._alloc) X86_64PLT0Atom(_file);
- _got0 = new (_file._alloc) X86_64GOTAtom(_file, ".got.plt");
- _got1 = new (_file._alloc) X86_64GOTAtom(_file, ".got.plt");
- _plt0->addReferenceELF_x86_64(R_X86_64_PC32, 2, _got0, -4);
- _plt0->addReferenceELF_x86_64(R_X86_64_PC32, 8, _got1, -4);
-#ifndef NDEBUG
- _got0->_name = "__got0";
- _got1->_name = "__got1";
-#endif
- return _plt0;
- }
-
- const PLTAtom *getPLTEntry(const Atom *a) {
- auto plt = _pltMap.find(a);
- if (plt != _pltMap.end())
- return plt->second;
- auto ga = new (_file._alloc) X86_64GOTAtom(_file, ".got.plt");
- ga->addReferenceELF_x86_64(R_X86_64_JUMP_SLOT, 0, a, 0);
- auto pa = new (_file._alloc) X86_64PLTAtom(_file, ".plt");
- pa->addReferenceELF_x86_64(R_X86_64_PC32, 2, ga, -4);
- pa->addReferenceELF_x86_64(LLD_R_X86_64_GOTRELINDEX, 7, ga, 0);
- pa->addReferenceELF_x86_64(R_X86_64_PC32, 12, getPLT0(), -4);
- // Set the starting address of the got entry to the second instruction in
- // the plt entry.
- ga->addReferenceELF_x86_64(R_X86_64_64, 0, pa, 6);
-#ifndef NDEBUG
- ga->_name = "__got_";
- ga->_name += a->name();
- pa->_name = "__plt_";
- pa->_name += a->name();
-#endif
- _gotMap[a] = ga;
- _pltMap[a] = pa;
- _gotVector.push_back(ga);
- _pltVector.push_back(pa);
- return pa;
- }
-
- const ObjectAtom *getObjectEntry(const SharedLibraryAtom *a) {
- auto obj = _objectMap.find(a);
- if (obj != _objectMap.end())
- return obj->second;
-
- auto oa = new (_file._alloc) ObjectAtom(_file);
- // This needs to point to the atom that we just created.
- oa->addReferenceELF_x86_64(R_X86_64_COPY, 0, oa, 0);
-
- oa->_name = a->name();
- oa->_size = a->size();
-
- _objectMap[a] = oa;
- _objectVector.push_back(oa);
- return oa;
- }
-
- std::error_code handlePlain(const Reference &ref) {
- if (!ref.target())
- return std::error_code();
- if (auto sla = dyn_cast<SharedLibraryAtom>(ref.target())) {
- if (sla->type() == SharedLibraryAtom::Type::Data)
- const_cast<Reference &>(ref).setTarget(getObjectEntry(sla));
- else if (sla->type() == SharedLibraryAtom::Type::Code)
- const_cast<Reference &>(ref).setTarget(getPLTEntry(sla));
- } else
- return handleIFUNC(ref);
- return std::error_code();
- }
-
- std::error_code handlePLT32(const Reference &ref) {
- // Turn this into a PC32 to the PLT entry.
- const_cast<Reference &>(ref).setKindValue(R_X86_64_PC32);
- // Handle IFUNC.
- if (const DefinedAtom *da =
- dyn_cast_or_null<const DefinedAtom>(ref.target()))
- if (da->contentType() == DefinedAtom::typeResolver)
- return handleIFUNC(ref);
- // If it is undefined at link time, push the work to the dynamic linker by
- // creating a PLT entry
- if (isa<SharedLibraryAtom>(ref.target()) ||
- isa<UndefinedAtom>(ref.target()))
- const_cast<Reference &>(ref).setTarget(getPLTEntry(ref.target()));
- return std::error_code();
- }
-
- const GOTAtom *getSharedGOT(const Atom *a) {
- auto got = _gotMap.find(a);
- if (got == _gotMap.end()) {
- auto g = new (_file._alloc) X86_64GOTAtom(_file, ".got");
- g->addReferenceELF_x86_64(R_X86_64_GLOB_DAT, 0, a, 0);
-#ifndef NDEBUG
- g->_name = "__got_";
- g->_name += a->name();
-#endif
- _gotMap[a] = g;
- _gotVector.push_back(g);
- return g;
- }
- return got->second;
- }
-
- std::error_code handleGOT(const Reference &ref) {
- if (const DefinedAtom *da = dyn_cast<const DefinedAtom>(ref.target()))
- const_cast<Reference &>(ref).setTarget(getGOT(da));
- // Handle undefined atoms in the same way as shared lib atoms: to be
- // resolved at run time.
- else if (isa<SharedLibraryAtom>(ref.target()) ||
- isa<UndefinedAtom>(ref.target()))
- const_cast<Reference &>(ref).setTarget(getSharedGOT(ref.target()));
- return std::error_code();
- }
-};
-} // end anon namespace
-
-std::unique_ptr<Pass>
-lld::elf::createX86_64RelocationPass(const X86_64LinkingContext &ctx) {
- switch (ctx.getOutputELFType()) {
- case llvm::ELF::ET_EXEC:
- if (ctx.isDynamic())
- return llvm::make_unique<DynamicRelocationPass>(ctx);
- return llvm::make_unique<StaticRelocationPass>(ctx);
- case llvm::ELF::ET_DYN:
- return llvm::make_unique<DynamicRelocationPass>(ctx);
- case llvm::ELF::ET_REL:
- return nullptr;
- default:
- llvm_unreachable("Unhandled output file type");
- }
-}
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.h b/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.h
deleted file mode 100644
index 1635b5e5f57b..000000000000
--- a/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.h
+++ /dev/null
@@ -1,32 +0,0 @@
-//===- lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.h -----------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// \brief Declares the relocation processing pass for x86-64. This includes
-/// GOT and PLT entries, TLS, COPY, and ifunc.
-///
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_ELF_X86_64_X86_64_RELOCATION_PASS_H
-#define LLD_READER_WRITER_ELF_X86_64_X86_64_RELOCATION_PASS_H
-
-#include <memory>
-
-namespace lld {
-class Pass;
-namespace elf {
-class X86_64LinkingContext;
-
-/// \brief Create x86-64 relocation pass for the given linking context.
-std::unique_ptr<Pass>
-createX86_64RelocationPass(const X86_64LinkingContext &);
-}
-}
-
-#endif
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64SectionChunks.cpp b/lib/ReaderWriter/ELF/X86_64/X86_64SectionChunks.cpp
deleted file mode 100644
index 28eb3e4244b6..000000000000
--- a/lib/ReaderWriter/ELF/X86_64/X86_64SectionChunks.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-//===- lib/ReaderWriter/ELF/X86_64/X86_64SectionChunks.cpp --------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "X86_64SectionChunks.h"
-#include "TargetLayout.h"
-
-namespace lld {
-namespace elf {
-
-X86_64GOTSection::X86_64GOTSection(const ELFLinkingContext &ctx)
- : AtomSection<ELF64LE>(ctx, ".got", DefinedAtom::typeGOT, DefinedAtom::permRW_,
- TargetLayout<ELF64LE>::ORDER_GOT) {
- this->_alignment = 8;
-}
-
-const AtomLayout *X86_64GOTSection::appendAtom(const Atom *atom) {
- const DefinedAtom *da = dyn_cast<DefinedAtom>(atom);
-
- for (const auto &r : *da) {
- if (r->kindNamespace() != Reference::KindNamespace::ELF)
- continue;
- assert(r->kindArch() == Reference::KindArch::x86_64);
- if (r->kindValue() == R_X86_64_TPOFF64)
- _tlsMap[r->target()] = _tlsMap.size();
- }
-
- return AtomSection<ELF64LE>::appendAtom(atom);
-}
-
-} // elf
-} // lld
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64SectionChunks.h b/lib/ReaderWriter/ELF/X86_64/X86_64SectionChunks.h
deleted file mode 100644
index 5208491eee55..000000000000
--- a/lib/ReaderWriter/ELF/X86_64/X86_64SectionChunks.h
+++ /dev/null
@@ -1,36 +0,0 @@
-//===- lib/ReaderWriter/ELF/X86_64/X86_64SectionChunks.h ----------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_ELF_X86_64_X86_64_SECTION_CHUNKS_H
-#define LLD_READER_WRITER_ELF_X86_64_X86_64_SECTION_CHUNKS_H
-
-#include "TargetLayout.h"
-
-namespace lld {
-namespace elf {
-
-class X86_64GOTSection : public AtomSection<ELF64LE> {
-public:
- X86_64GOTSection(const ELFLinkingContext &ctx);
-
- bool hasGlobalGOTEntry(const Atom *a) const {
- return _tlsMap.count(a);
- }
-
- const AtomLayout *appendAtom(const Atom *atom) override;
-
-private:
- /// \brief Map TLS Atoms to their GOT entry index.
- llvm::DenseMap<const Atom *, std::size_t> _tlsMap;
-};
-
-} // elf
-} // lld
-
-#endif
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.cpp b/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.cpp
deleted file mode 100644
index 599077ac33c5..000000000000
--- a/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-//===- lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.cpp ----------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "Atoms.h"
-#include "X86_64DynamicLibraryWriter.h"
-#include "X86_64ExecutableWriter.h"
-#include "X86_64LinkingContext.h"
-#include "X86_64TargetHandler.h"
-
-using namespace lld;
-using namespace elf;
-
-X86_64TargetHandler::X86_64TargetHandler(X86_64LinkingContext &ctx)
- : _ctx(ctx), _targetLayout(new X86_64TargetLayout(ctx)),
- _relocationHandler(new X86_64TargetRelocationHandler(*_targetLayout)) {}
-
-std::unique_ptr<Writer> X86_64TargetHandler::getWriter() {
- switch (this->_ctx.getOutputELFType()) {
- case llvm::ELF::ET_EXEC:
- return llvm::make_unique<X86_64ExecutableWriter>(_ctx, *_targetLayout);
- case llvm::ELF::ET_DYN:
- return llvm::make_unique<X86_64DynamicLibraryWriter>(_ctx, *_targetLayout);
- case llvm::ELF::ET_REL:
- llvm_unreachable("TODO: support -r mode");
- default:
- llvm_unreachable("unsupported output type");
- }
-}
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h b/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h
deleted file mode 100644
index 6e3e58f8aed6..000000000000
--- a/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h
+++ /dev/null
@@ -1,104 +0,0 @@
-//===- lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h ------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_ELF_X86_64_X86_64_TARGET_HANDLER_H
-#define LLD_READER_WRITER_ELF_X86_64_X86_64_TARGET_HANDLER_H
-
-#include "ELFReader.h"
-#include "TargetLayout.h"
-#include "X86_64LinkingContext.h"
-#include "X86_64RelocationHandler.h"
-#include "X86_64SectionChunks.h"
-#include "lld/Core/Simple.h"
-
-namespace lld {
-namespace elf {
-
-
-class X86_64TargetLayout : public TargetLayout<ELF64LE> {
-public:
- X86_64TargetLayout(X86_64LinkingContext &ctx) : TargetLayout(ctx),
- _gotSection(new (this->_allocator) X86_64GOTSection(ctx)) {}
-
- AtomSection<ELF64LE> *
- createSection(StringRef name, int32_t type,
- DefinedAtom::ContentPermissions permissions,
- TargetLayout<ELF64LE>::SectionOrder order) override {
- if (type == DefinedAtom::typeGOT && name == ".got")
- return _gotSection;
- return TargetLayout<ELF64LE>::createSection(name, type, permissions, order);
- }
-
- void finalizeOutputSectionLayout() override {
- sortOutputSectionByPriority<ELF64LE>(".init_array");
- sortOutputSectionByPriority<ELF64LE>(".fini_array");
- }
-
- const X86_64GOTSection &getGOTSection() const { return *_gotSection; }
-
-private:
- uint32_t getPriority(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 <typename T> void sortOutputSectionByPriority(StringRef prefix) {
- OutputSection<T> *section = findOutputSection(prefix);
- if (!section)
- return;
- auto sections = section->sections();
- std::sort(sections.begin(), sections.end(),
- [&](Chunk<T> *lhs, Chunk<T> *rhs) {
- Section<T> *lhsSection = dyn_cast<Section<T>>(lhs);
- Section<T> *rhsSection = dyn_cast<Section<T>>(rhs);
- if (!lhsSection || !rhsSection)
- return false;
- StringRef lhsName = lhsSection->inputSectionName();
- StringRef rhsName = rhsSection->inputSectionName();
- if (!lhsName.startswith(prefix) || !rhsName.startswith(prefix))
- return false;
- return getPriority(lhsName) < getPriority(rhsName);
- });
- }
-
-private:
- X86_64GOTSection *_gotSection;
-};
-
-class X86_64TargetHandler : public TargetHandler {
-public:
- X86_64TargetHandler(X86_64LinkingContext &ctx);
-
- const TargetRelocationHandler &getRelocationHandler() const override {
- return *_relocationHandler;
- }
-
- std::unique_ptr<Reader> getObjReader() override {
- return llvm::make_unique<ELFReader<ELFFile<ELF64LE>>>(_ctx);
- }
-
- std::unique_ptr<Reader> getDSOReader() override {
- return llvm::make_unique<ELFReader<DynamicFile<ELF64LE>>>(_ctx);
- }
-
- std::unique_ptr<Writer> getWriter() override;
-
-protected:
- X86_64LinkingContext &_ctx;
- std::unique_ptr<X86_64TargetLayout> _targetLayout;
- std::unique_ptr<X86_64TargetRelocationHandler> _relocationHandler;
-};
-
-} // end namespace elf
-} // end namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/FileArchive.cpp b/lib/ReaderWriter/FileArchive.cpp
index a09923f57d07..eb7e7fb1837b 100644
--- a/lib/ReaderWriter/FileArchive.cpp
+++ b/lib/ReaderWriter/FileArchive.cpp
@@ -8,27 +8,28 @@
//===----------------------------------------------------------------------===//
#include "lld/Core/ArchiveLibraryFile.h"
+#include "lld/Core/File.h"
#include "lld/Core/LLVM.h"
-#include "lld/Core/LinkingContext.h"
-#include "lld/Core/Parallel.h"
-#include "lld/Driver/Driver.h"
-#include "llvm/ADT/Hashing.h"
+#include "lld/Core/Reader.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Object/Archive.h"
-#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Object/Error.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/raw_ostream.h"
#include <memory>
-#include <mutex>
#include <set>
+#include <string>
+#include <system_error>
#include <unordered_map>
+#include <utility>
+#include <vector>
using llvm::object::Archive;
-using llvm::object::ObjectFile;
-using llvm::object::SymbolRef;
-using llvm::object::symbol_iterator;
-using llvm::object::object_error;
namespace lld {
@@ -44,39 +45,23 @@ public:
/// \brief Check if any member of the archive contains an Atom with the
/// specified name and return the File object for that member, or nullptr.
- File *find(StringRef name, bool dataSymbolOnly) override {
+ File *find(StringRef name) override {
auto member = _symbolMemberMap.find(name);
if (member == _symbolMemberMap.end())
return nullptr;
- Archive::child_iterator ci = member->second;
- if (ci->getError())
- return nullptr;
+ Archive::Child c = member->second;
// Don't return a member already returned
- ErrorOr<StringRef> buf = (*ci)->getBuffer();
+ ErrorOr<StringRef> buf = c.getBuffer();
if (!buf)
return nullptr;
const char *memberStart = buf->data();
if (_membersInstantiated.count(memberStart))
return nullptr;
- if (dataSymbolOnly && !isDataSymbol(ci, name))
- return nullptr;
-
_membersInstantiated.insert(memberStart);
- // Check if a file is preloaded.
- {
- std::lock_guard<std::mutex> lock(_mutex);
- auto it = _preloaded.find(memberStart);
- if (it != _preloaded.end()) {
- std::unique_ptr<Future<File *>> &p = it->second;
- Future<File *> *future = p.get();
- return future->get();
- }
- }
-
std::unique_ptr<File> result;
- if (instantiateMember(ci, result))
+ if (instantiateMember(c, result))
return nullptr;
File *file = result.get();
@@ -86,97 +71,68 @@ public:
return file;
}
- // Instantiate a member file containing a given symbol name.
- void preload(TaskGroup &group, StringRef name) override {
- auto member = _symbolMemberMap.find(name);
- if (member == _symbolMemberMap.end())
- return;
- Archive::child_iterator ci = member->second;
- if (ci->getError())
- return;
-
- // Do nothing if a member is already instantiated.
- ErrorOr<StringRef> buf = (*ci)->getBuffer();
- if (!buf)
- return;
- const char *memberStart = buf->data();
- if (_membersInstantiated.count(memberStart))
- return;
-
- std::lock_guard<std::mutex> lock(_mutex);
- if (_preloaded.find(memberStart) != _preloaded.end())
- return;
-
- // Instantiate the member
- auto *future = new Future<File *>();
- _preloaded[memberStart] = std::unique_ptr<Future<File *>>(future);
-
- group.spawn([=] {
- std::unique_ptr<File> result;
- std::error_code ec = instantiateMember(ci, result);
- future->set(ec ? nullptr : result.release());
- });
- }
-
/// \brief parse each member
std::error_code
parseAllMembers(std::vector<std::unique_ptr<File>> &result) override {
if (std::error_code ec = parse())
return ec;
- for (auto mf = _archive->child_begin(), me = _archive->child_end();
+ llvm::Error err;
+ for (auto mf = _archive->child_begin(err), me = _archive->child_end();
mf != me; ++mf) {
std::unique_ptr<File> file;
- if (std::error_code ec = instantiateMember(mf, file))
+ if (std::error_code ec = instantiateMember(*mf, file)) {
+ // err is Success (or we wouldn't be in the loop body) but we can't
+ // return without testing or consuming it.
+ consumeError(std::move(err));
return ec;
+ }
result.push_back(std::move(file));
}
+ if (err)
+ return errorToErrorCode(std::move(err));
return std::error_code();
}
- const AtomVector<DefinedAtom> &defined() const override {
+ const AtomRange<DefinedAtom> defined() const override {
return _noDefinedAtoms;
}
- const AtomVector<UndefinedAtom> &undefined() const override {
+ const AtomRange<UndefinedAtom> undefined() const override {
return _noUndefinedAtoms;
}
- const AtomVector<SharedLibraryAtom> &sharedLibrary() const override {
+ const AtomRange<SharedLibraryAtom> sharedLibrary() const override {
return _noSharedLibraryAtoms;
}
- const AtomVector<AbsoluteAtom> &absolute() const override {
+ const AtomRange<AbsoluteAtom> absolute() const override {
return _noAbsoluteAtoms;
}
- /// Returns a set of all defined symbols in the archive.
- std::set<StringRef> getDefinedSymbols() override {
- parse();
- std::set<StringRef> ret;
- for (const auto &e : _symbolMemberMap)
- ret.insert(e.first);
- return ret;
+ void clearAtoms() override {
+ _noDefinedAtoms.clear();
+ _noUndefinedAtoms.clear();
+ _noSharedLibraryAtoms.clear();
+ _noAbsoluteAtoms.clear();
}
protected:
std::error_code doParse() override {
// Make Archive object which will be owned by FileArchive object.
+ llvm::Error Err;
+ _archive.reset(new Archive(_mb->getMemBufferRef(), Err));
+ if (Err)
+ return errorToErrorCode(std::move(Err));
std::error_code ec;
- _archive.reset(new Archive(_mb->getMemBufferRef(), ec));
- if (ec)
- return ec;
if ((ec = buildTableOfContents()))
return ec;
return std::error_code();
}
private:
- std::error_code instantiateMember(Archive::child_iterator cOrErr,
+ std::error_code instantiateMember(Archive::Child member,
std::unique_ptr<File> &result) const {
- if (std::error_code ec = cOrErr->getError())
- return ec;
- Archive::child_iterator member = cOrErr->get();
- ErrorOr<llvm::MemoryBufferRef> mbOrErr = (*member)->getMemoryBufferRef();
+ ErrorOr<llvm::MemoryBufferRef> mbOrErr = member.getMemoryBufferRef();
if (std::error_code ec = mbOrErr.getError())
return ec;
llvm::MemoryBufferRef mb = mbOrErr.get();
@@ -204,64 +160,27 @@ private:
return std::error_code();
}
- // Parses the given memory buffer as an object file, and returns true
- // code if the given symbol is a data symbol. If the symbol is not a data
- // symbol or does not exist, returns false.
- bool isDataSymbol(Archive::child_iterator cOrErr, StringRef symbol) const {
- if (cOrErr->getError())
- return false;
- Archive::child_iterator member = cOrErr->get();
- ErrorOr<llvm::MemoryBufferRef> buf = (*member)->getMemoryBufferRef();
- if (buf.getError())
- return false;
- std::unique_ptr<MemoryBuffer> mb(MemoryBuffer::getMemBuffer(
- buf.get().getBuffer(), buf.get().getBufferIdentifier(), false));
-
- auto objOrErr(ObjectFile::createObjectFile(mb->getMemBufferRef()));
- if (objOrErr.getError())
- return false;
- std::unique_ptr<ObjectFile> obj = std::move(objOrErr.get());
-
- for (SymbolRef sym : obj->symbols()) {
- // Skip until we find the symbol.
- ErrorOr<StringRef> name = sym.getName();
- if (!name)
- return false;
- if (*name != symbol)
- continue;
- uint32_t flags = sym.getFlags();
- if (flags <= SymbolRef::SF_Undefined)
- continue;
-
- // Returns true if it's a data symbol.
- SymbolRef::Type type = sym.getType();
- if (type == SymbolRef::ST_Data)
- return true;
- }
- return false;
- }
-
std::error_code buildTableOfContents() {
DEBUG_WITH_TYPE("FileArchive", llvm::dbgs()
<< "Table of contents for archive '"
<< _archive->getFileName() << "':\n");
for (const Archive::Symbol &sym : _archive->symbols()) {
StringRef name = sym.getName();
- ErrorOr<Archive::child_iterator> memberOrErr = sym.getMember();
+ ErrorOr<Archive::Child> memberOrErr = sym.getMember();
if (std::error_code ec = memberOrErr.getError())
return ec;
- Archive::child_iterator member = memberOrErr.get();
+ Archive::Child member = memberOrErr.get();
DEBUG_WITH_TYPE("FileArchive",
llvm::dbgs()
<< llvm::format("0x%08llX ",
- (*member)->getBuffer()->data())
+ member.getBuffer()->data())
<< "'" << name << "'\n");
_symbolMemberMap.insert(std::make_pair(name, member));
}
return std::error_code();
}
- typedef std::unordered_map<StringRef, Archive::child_iterator> MemberMap;
+ typedef std::unordered_map<StringRef, Archive::Child> MemberMap;
typedef std::set<const char *> InstantiatedSet;
std::shared_ptr<MemoryBuffer> _mb;
@@ -271,9 +190,7 @@ private:
InstantiatedSet _membersInstantiated;
bool _logLoading;
std::vector<std::unique_ptr<MemoryBuffer>> _memberBuffers;
- std::map<const char *, std::unique_ptr<Future<File *>>> _preloaded;
- std::mutex _mutex;
- FileVector _filesReturned;
+ std::vector<std::unique_ptr<File>> _filesReturned;
};
class ArchiveReader : public Reader {
@@ -302,4 +219,4 @@ void Registry::addSupportArchives(bool logLoading) {
add(std::unique_ptr<Reader>(new ArchiveReader(logLoading)));
}
-} // end namespace lld
+} // namespace lld
diff --git a/lib/ReaderWriter/LinkerScript.cpp b/lib/ReaderWriter/LinkerScript.cpp
deleted file mode 100644
index 67822dc48fe6..000000000000
--- a/lib/ReaderWriter/LinkerScript.cpp
+++ /dev/null
@@ -1,2895 +0,0 @@
-//===- ReaderWriter/LinkerScript.cpp ----------------------------*- C++ -*-===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// \brief Linker script parser.
-///
-//===----------------------------------------------------------------------===//
-
-#include "lld/ReaderWriter/LinkerScript.h"
-
-#include "llvm/ADT/APInt.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/Support/Errc.h"
-#include "llvm/Support/ELF.h"
-
-namespace lld {
-namespace script {
-void Token::dump(raw_ostream &os) const {
- switch (_kind) {
-#define CASE(name) \
- case Token::name: \
- os << #name ": "; \
- break;
- CASE(unknown)
- CASE(eof)
- CASE(exclaim)
- CASE(exclaimequal)
- CASE(amp)
- CASE(ampequal)
- CASE(l_paren)
- CASE(r_paren)
- CASE(star)
- CASE(starequal)
- CASE(plus)
- CASE(plusequal)
- CASE(comma)
- CASE(minus)
- CASE(minusequal)
- CASE(slash)
- CASE(slashequal)
- CASE(number)
- CASE(colon)
- CASE(semicolon)
- CASE(less)
- CASE(lessequal)
- CASE(lessless)
- CASE(lesslessequal)
- CASE(equal)
- CASE(equalequal)
- CASE(greater)
- CASE(greaterequal)
- CASE(greatergreater)
- CASE(greatergreaterequal)
- CASE(question)
- CASE(identifier)
- CASE(libname)
- CASE(kw_align)
- CASE(kw_align_with_input)
- CASE(kw_as_needed)
- CASE(kw_at)
- CASE(kw_discard)
- CASE(kw_entry)
- CASE(kw_exclude_file)
- CASE(kw_extern)
- CASE(kw_filehdr)
- CASE(kw_fill)
- CASE(kw_flags)
- CASE(kw_group)
- CASE(kw_hidden)
- CASE(kw_input)
- CASE(kw_keep)
- CASE(kw_length)
- CASE(kw_memory)
- CASE(kw_origin)
- CASE(kw_phdrs)
- CASE(kw_provide)
- CASE(kw_provide_hidden)
- CASE(kw_only_if_ro)
- CASE(kw_only_if_rw)
- CASE(kw_output)
- CASE(kw_output_arch)
- CASE(kw_output_format)
- CASE(kw_overlay)
- CASE(kw_search_dir)
- CASE(kw_sections)
- CASE(kw_sort_by_alignment)
- CASE(kw_sort_by_init_priority)
- CASE(kw_sort_by_name)
- CASE(kw_sort_none)
- CASE(kw_subalign)
- CASE(l_brace)
- CASE(pipe)
- CASE(pipeequal)
- CASE(r_brace)
- CASE(tilde)
-#undef CASE
- }
- os << _range << "\n";
-}
-
-static llvm::ErrorOr<uint64_t> parseDecimal(StringRef str) {
- uint64_t res = 0;
- for (auto &c : str) {
- res *= 10;
- if (c < '0' || c > '9')
- return llvm::ErrorOr<uint64_t>(make_error_code(llvm::errc::io_error));
- res += c - '0';
- }
- return res;
-}
-
-static llvm::ErrorOr<uint64_t> parseOctal(StringRef str) {
- uint64_t res = 0;
- for (auto &c : str) {
- res <<= 3;
- if (c < '0' || c > '7')
- return llvm::ErrorOr<uint64_t>(make_error_code(llvm::errc::io_error));
- res += c - '0';
- }
- return res;
-}
-
-static llvm::ErrorOr<uint64_t> parseBinary(StringRef str) {
- uint64_t res = 0;
- for (auto &c : str) {
- res <<= 1;
- if (c != '0' && c != '1')
- return llvm::ErrorOr<uint64_t>(make_error_code(llvm::errc::io_error));
- res += c - '0';
- }
- return res;
-}
-
-static llvm::ErrorOr<uint64_t> parseHex(StringRef str) {
- uint64_t res = 0;
- for (auto &c : str) {
- res <<= 4;
- if (c >= '0' && c <= '9')
- res += c - '0';
- else if (c >= 'a' && c <= 'f')
- res += c - 'a' + 10;
- else if (c >= 'A' && c <= 'F')
- res += c - 'A' + 10;
- else
- return llvm::ErrorOr<uint64_t>(make_error_code(llvm::errc::io_error));
- }
- return res;
-}
-
-static bool parseHexToByteStream(StringRef str, std::string &buf) {
- unsigned char byte = 0;
- bool dumpByte = str.size() % 2;
- for (auto &c : str) {
- byte <<= 4;
- if (c >= '0' && c <= '9')
- byte += c - '0';
- else if (c >= 'a' && c <= 'f')
- byte += c - 'a' + 10;
- else if (c >= 'A' && c <= 'F')
- byte += c - 'A' + 10;
- else
- return false;
- if (!dumpByte) {
- dumpByte = true;
- continue;
- }
- buf.push_back(byte);
- byte = 0;
- dumpByte = false;
- }
- return !dumpByte;
-}
-
-static void dumpByteStream(raw_ostream &os, StringRef stream) {
- os << "0x";
- for (auto &c : stream) {
- unsigned char firstNibble = c >> 4 & 0xF;
- if (firstNibble > 9)
- os << (char) ('A' + firstNibble - 10);
- else
- os << (char) ('0' + firstNibble);
- unsigned char secondNibble = c & 0xF;
- if (secondNibble > 9)
- os << (char) ('A' + secondNibble - 10);
- else
- os << (char) ('0' + secondNibble);
- }
-}
-
-static llvm::ErrorOr<uint64_t> parseNum(StringRef str) {
- unsigned multiplier = 1;
- enum NumKind { decimal, hex, octal, binary };
- NumKind kind = llvm::StringSwitch<NumKind>(str)
- .StartsWith("0x", hex)
- .StartsWith("0X", hex)
- .StartsWith("0", octal)
- .Default(decimal);
-
- // Parse scale
- if (str.endswith("K")) {
- multiplier = 1 << 10;
- str = str.drop_back();
- } else if (str.endswith("M")) {
- multiplier = 1 << 20;
- str = str.drop_back();
- }
-
- // Parse type
- if (str.endswith_lower("o")) {
- kind = octal;
- str = str.drop_back();
- } else if (str.endswith_lower("h")) {
- kind = hex;
- str = str.drop_back();
- } else if (str.endswith_lower("d")) {
- kind = decimal;
- str = str.drop_back();
- } else if (str.endswith_lower("b")) {
- kind = binary;
- str = str.drop_back();
- }
-
- llvm::ErrorOr<uint64_t> res(0);
- switch (kind) {
- case hex:
- if (str.startswith_lower("0x"))
- str = str.drop_front(2);
- res = parseHex(str);
- break;
- case octal:
- res = parseOctal(str);
- break;
- case decimal:
- res = parseDecimal(str);
- break;
- case binary:
- res = parseBinary(str);
- break;
- }
- if (res.getError())
- return res;
-
- *res = *res * multiplier;
- return res;
-}
-
-bool Lexer::canStartNumber(char c) const {
- return '0' <= c && c <= '9';
-}
-
-bool Lexer::canContinueNumber(char c) const {
- // [xX] = hex marker, [hHoO] = type suffix, [MK] = scale suffix.
- return strchr("0123456789ABCDEFabcdefxXhHoOMK", c);
-}
-
-bool Lexer::canStartName(char c) const {
- return strchr(
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_.$/\\*", c);
-}
-
-bool Lexer::canContinueName(char c) const {
- return strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
- "0123456789_.$/\\~=+[]*?-:", c);
-}
-
-/// Helper function to split a StringRef in two at the nth character.
-/// The StringRef s is updated, while the function returns the n first
-/// characters.
-static StringRef drop(StringRef &s, int n) {
- StringRef res = s.substr(0, n);
- s = s.drop_front(n);
- return res;
-}
-
-void Lexer::lex(Token &tok) {
- skipWhitespace();
- if (_buffer.empty()) {
- tok = Token(_buffer, Token::eof);
- return;
- }
- switch (_buffer[0]) {
- case 0:
- tok = Token(drop(_buffer, 1), Token::eof);
- return;
- case '(':
- tok = Token(drop(_buffer, 1), Token::l_paren);
- return;
- case ')':
- tok = Token(drop(_buffer, 1), Token::r_paren);
- return;
- case '{':
- tok = Token(drop(_buffer, 1), Token::l_brace);
- return;
- case '}':
- tok = Token(drop(_buffer, 1), Token::r_brace);
- return;
- case '=':
- if (_buffer.startswith("==")) {
- tok = Token(drop(_buffer, 2), Token::equalequal);
- return;
- }
- tok = Token(drop(_buffer, 1), Token::equal);
- return;
- case '!':
- if (_buffer.startswith("!=")) {
- tok = Token(drop(_buffer, 2), Token::exclaimequal);
- return;
- }
- tok = Token(drop(_buffer, 1), Token::exclaim);
- return;
- case ',':
- tok = Token(drop(_buffer, 1), Token::comma);
- return;
- case ';':
- tok = Token(drop(_buffer, 1), Token::semicolon);
- return;
- case ':':
- tok = Token(drop(_buffer, 1), Token::colon);
- return;
- case '&':
- if (_buffer.startswith("&=")) {
- tok = Token(drop(_buffer, 2), Token::ampequal);
- return;
- }
- tok = Token(drop(_buffer, 1), Token::amp);
- return;
- case '|':
- if (_buffer.startswith("|=")) {
- tok = Token(drop(_buffer, 2), Token::pipeequal);
- return;
- }
- tok = Token(drop(_buffer, 1), Token::pipe);
- return;
- case '+':
- if (_buffer.startswith("+=")) {
- tok = Token(drop(_buffer, 2), Token::plusequal);
- return;
- }
- tok = Token(drop(_buffer, 1), Token::plus);
- return;
- case '-': {
- if (_buffer.startswith("-=")) {
- tok = Token(drop(_buffer, 2), Token::minusequal);
- return;
- }
- if (!_buffer.startswith("-l")) {
- tok = Token(drop(_buffer, 1), Token::minus);
- return;
- }
- // -l<lib name>
- _buffer = _buffer.drop_front(2);
- StringRef::size_type start = 0;
- if (_buffer[start] == ':')
- ++start;
- if (!canStartName(_buffer[start]))
- // Create 'unknown' token.
- break;
- auto libNameEnd = std::find_if(_buffer.begin() + start + 1, _buffer.end(),
- [=](char c) { return !canContinueName(c); });
- StringRef::size_type libNameLen =
- std::distance(_buffer.begin(), libNameEnd);
- tok = Token(_buffer.substr(0, libNameLen), Token::libname);
- _buffer = _buffer.drop_front(libNameLen);
- return;
- }
- case '<':
- if (_buffer.startswith("<<=")) {
- tok = Token(drop(_buffer, 3), Token::lesslessequal);
- return;
- }
- if (_buffer.startswith("<<")) {
- tok = Token(drop(_buffer, 2), Token::lessless);
- return;
- }
- if (_buffer.startswith("<=")) {
- tok = Token(drop(_buffer, 2), Token::lessequal);
- return;
- }
- tok = Token(drop(_buffer, 1), Token::less);
- return;
- case '>':
- if (_buffer.startswith(">>=")) {
- tok = Token(drop(_buffer, 3), Token::greatergreaterequal);
- return;
- }
- if (_buffer.startswith(">>")) {
- tok = Token(drop(_buffer, 2), Token::greatergreater);
- return;
- }
- if (_buffer.startswith(">=")) {
- tok = Token(drop(_buffer, 2), Token::greaterequal);
- return;
- }
- tok = Token(drop(_buffer, 1), Token::greater);
- return;
- case '~':
- tok = Token(drop(_buffer, 1), Token::tilde);
- return;
- case '\"': case '\'': {
- // Handle quoted strings. They are treated as identifiers for
- // simplicity.
- char c = _buffer[0];
- _buffer = _buffer.drop_front();
- auto quotedStringEnd = _buffer.find(c);
- if (quotedStringEnd == StringRef::npos || quotedStringEnd == 0)
- break;
- StringRef word = _buffer.substr(0, quotedStringEnd);
- tok = Token(word, Token::identifier);
- _buffer = _buffer.drop_front(quotedStringEnd + 1);
- return;
- }
- default:
- // Handle literal numbers
- if (canStartNumber(_buffer[0])) {
- auto endIter = std::find_if(_buffer.begin(), _buffer.end(), [=](char c) {
- return !canContinueNumber(c);
- });
- StringRef::size_type end = endIter == _buffer.end()
- ? StringRef::npos
- : std::distance(_buffer.begin(), endIter);
- if (end == StringRef::npos || end == 0)
- break;
- StringRef word = _buffer.substr(0, end);
- tok = Token(word, Token::number);
- _buffer = _buffer.drop_front(end);
- return;
- }
- // Handle slashes '/', which can be either an operator inside an expression
- // or the beginning of an identifier
- if (_buffer.startswith("/=")) {
- tok = Token(drop(_buffer, 2), Token::slashequal);
- return;
- }
- if (_buffer[0] == '/' && _buffer.size() > 1 &&
- !canContinueName(_buffer[1])) {
- tok = Token(drop(_buffer, 1), Token::slash);
- return;
- }
- // Handle stars '*'
- if (_buffer.startswith("*=")) {
- tok = Token(drop(_buffer, 2), Token::starequal);
- return;
- }
- if (_buffer[0] == '*' && _buffer.size() > 1 &&
- !canContinueName(_buffer[1])) {
- tok = Token(drop(_buffer, 1), Token::star);
- return;
- }
- // Handle questions '?'
- if (_buffer[0] == '?' && _buffer.size() > 1 &&
- !canContinueName(_buffer[1])) {
- tok = Token(drop(_buffer, 1), Token::question);
- return;
- }
- // keyword or identifier.
- if (!canStartName(_buffer[0]))
- break;
- auto endIter = std::find_if(_buffer.begin() + 1, _buffer.end(),
- [=](char c) { return !canContinueName(c); });
- StringRef::size_type end = endIter == _buffer.end()
- ? StringRef::npos
- : std::distance(_buffer.begin(), endIter);
- if (end == StringRef::npos || end == 0)
- break;
- StringRef word = _buffer.substr(0, end);
- Token::Kind kind =
- llvm::StringSwitch<Token::Kind>(word)
- .Case("ALIGN", Token::kw_align)
- .Case("ALIGN_WITH_INPUT", Token::kw_align_with_input)
- .Case("AS_NEEDED", Token::kw_as_needed)
- .Case("AT", Token::kw_at)
- .Case("ENTRY", Token::kw_entry)
- .Case("EXCLUDE_FILE", Token::kw_exclude_file)
- .Case("EXTERN", Token::kw_extern)
- .Case("FILEHDR", Token::kw_filehdr)
- .Case("FILL", Token::kw_fill)
- .Case("FLAGS", Token::kw_flags)
- .Case("GROUP", Token::kw_group)
- .Case("HIDDEN", Token::kw_hidden)
- .Case("INPUT", Token::kw_input)
- .Case("KEEP", Token::kw_keep)
- .Case("LENGTH", Token::kw_length)
- .Case("l", Token::kw_length)
- .Case("len", Token::kw_length)
- .Case("MEMORY", Token::kw_memory)
- .Case("ONLY_IF_RO", Token::kw_only_if_ro)
- .Case("ONLY_IF_RW", Token::kw_only_if_rw)
- .Case("ORIGIN", Token::kw_origin)
- .Case("o", Token::kw_origin)
- .Case("org", Token::kw_origin)
- .Case("OUTPUT", Token::kw_output)
- .Case("OUTPUT_ARCH", Token::kw_output_arch)
- .Case("OUTPUT_FORMAT", Token::kw_output_format)
- .Case("OVERLAY", Token::kw_overlay)
- .Case("PHDRS", Token::kw_phdrs)
- .Case("PROVIDE", Token::kw_provide)
- .Case("PROVIDE_HIDDEN", Token::kw_provide_hidden)
- .Case("SEARCH_DIR", Token::kw_search_dir)
- .Case("SECTIONS", Token::kw_sections)
- .Case("SORT", Token::kw_sort_by_name)
- .Case("SORT_BY_ALIGNMENT", Token::kw_sort_by_alignment)
- .Case("SORT_BY_INIT_PRIORITY", Token::kw_sort_by_init_priority)
- .Case("SORT_BY_NAME", Token::kw_sort_by_name)
- .Case("SORT_NONE", Token::kw_sort_none)
- .Case("SUBALIGN", Token::kw_subalign)
- .Case("/DISCARD/", Token::kw_discard)
- .Default(Token::identifier);
- tok = Token(word, kind);
- _buffer = _buffer.drop_front(end);
- return;
- }
- tok = Token(drop(_buffer, 1), Token::unknown);
-}
-
-void Lexer::skipWhitespace() {
- while (true) {
- if (_buffer.empty())
- return;
- switch (_buffer[0]) {
- case ' ':
- case '\r':
- case '\n':
- case '\t':
- _buffer = _buffer.drop_front();
- break;
- // Potential comment.
- case '/':
- if (_buffer.size() <= 1 || _buffer[1] != '*')
- return;
- // Skip starting /*
- _buffer = _buffer.drop_front(2);
- // If the next char is also a /, it's not the end.
- if (!_buffer.empty() && _buffer[0] == '/')
- _buffer = _buffer.drop_front();
-
- // Scan for /'s. We're done if it is preceded by a *.
- while (true) {
- if (_buffer.empty())
- break;
- _buffer = _buffer.drop_front();
- if (_buffer.data()[-1] == '/' && _buffer.data()[-2] == '*')
- break;
- }
- break;
- default:
- return;
- }
- }
-}
-
-// Constant functions
-void Constant::dump(raw_ostream &os) const { os << _num; }
-
-ErrorOr<int64_t> Constant::evalExpr(const SymbolTableTy &symbolTable) const {
- return _num;
-}
-
-// Symbol functions
-void Symbol::dump(raw_ostream &os) const { os << _name; }
-
-ErrorOr<int64_t> Symbol::evalExpr(const SymbolTableTy &symbolTable) const {
- auto it = symbolTable.find(_name);
- if (it == symbolTable.end())
- return LinkerScriptReaderError::unknown_symbol_in_expr;
- return it->second;
-}
-
-// FunctionCall functions
-void FunctionCall::dump(raw_ostream &os) const {
- os << _name << "(";
- for (unsigned i = 0, e = _args.size(); i != e; ++i) {
- if (i)
- os << ", ";
- _args[i]->dump(os);
- }
- os << ")";
-}
-
-ErrorOr<int64_t>
-FunctionCall::evalExpr(const SymbolTableTy &symbolTable) const {
- return LinkerScriptReaderError::unrecognized_function_in_expr;
-}
-
-// Unary functions
-void Unary::dump(raw_ostream &os) const {
- os << "(";
- if (_op == Unary::Minus)
- os << "-";
- else
- os << "~";
- _child->dump(os);
- os << ")";
-}
-
-ErrorOr<int64_t> Unary::evalExpr(const SymbolTableTy &symbolTable) const {
- auto child = _child->evalExpr(symbolTable);
- if (child.getError())
- return child.getError();
-
- int64_t childRes = *child;
- switch (_op) {
- case Unary::Minus:
- return -childRes;
- case Unary::Not:
- return ~childRes;
- }
-
- llvm_unreachable("");
-}
-
-// BinOp functions
-void BinOp::dump(raw_ostream &os) const {
- os << "(";
- _lhs->dump(os);
- os << " ";
- switch (_op) {
- case Sum:
- os << "+";
- break;
- case Sub:
- os << "-";
- break;
- case Mul:
- os << "*";
- break;
- case Div:
- os << "/";
- break;
- case Shl:
- os << "<<";
- break;
- case Shr:
- os << ">>";
- break;
- case And:
- os << "&";
- break;
- case Or:
- os << "|";
- break;
- case CompareEqual:
- os << "==";
- break;
- case CompareDifferent:
- os << "!=";
- break;
- case CompareLess:
- os << "<";
- break;
- case CompareGreater:
- os << ">";
- break;
- case CompareLessEqual:
- os << "<=";
- break;
- case CompareGreaterEqual:
- os << ">=";
- break;
- }
- os << " ";
- _rhs->dump(os);
- os << ")";
-}
-
-ErrorOr<int64_t> BinOp::evalExpr(const SymbolTableTy &symbolTable) const {
- auto lhs = _lhs->evalExpr(symbolTable);
- if (lhs.getError())
- return lhs.getError();
- auto rhs = _rhs->evalExpr(symbolTable);
- if (rhs.getError())
- return rhs.getError();
-
- int64_t lhsRes = *lhs;
- int64_t rhsRes = *rhs;
-
- switch(_op) {
- case And: return lhsRes & rhsRes;
- case CompareDifferent: return lhsRes != rhsRes;
- case CompareEqual: return lhsRes == rhsRes;
- case CompareGreater: return lhsRes > rhsRes;
- case CompareGreaterEqual: return lhsRes >= rhsRes;
- case CompareLess: return lhsRes < rhsRes;
- case CompareLessEqual: return lhsRes <= rhsRes;
- case Div: return lhsRes / rhsRes;
- case Mul: return lhsRes * rhsRes;
- case Or: return lhsRes | rhsRes;
- case Shl: return lhsRes << rhsRes;
- case Shr: return lhsRes >> rhsRes;
- case Sub: return lhsRes - rhsRes;
- case Sum: return lhsRes + rhsRes;
- }
-
- llvm_unreachable("");
-}
-
-// TernaryConditional functions
-void TernaryConditional::dump(raw_ostream &os) const {
- _conditional->dump(os);
- os << " ? ";
- _trueExpr->dump(os);
- os << " : ";
- _falseExpr->dump(os);
-}
-
-ErrorOr<int64_t>
-TernaryConditional::evalExpr(const SymbolTableTy &symbolTable) const {
- auto conditional = _conditional->evalExpr(symbolTable);
- if (conditional.getError())
- return conditional.getError();
- if (*conditional)
- return _trueExpr->evalExpr(symbolTable);
- return _falseExpr->evalExpr(symbolTable);
-}
-
-// SymbolAssignment functions
-void SymbolAssignment::dump(raw_ostream &os) const {
- int numParen = 0;
-
- if (_assignmentVisibility != Default) {
- switch (_assignmentVisibility) {
- case Hidden:
- os << "HIDDEN(";
- break;
- case Provide:
- os << "PROVIDE(";
- break;
- case ProvideHidden:
- os << "PROVIDE_HIDDEN(";
- break;
- default:
- llvm_unreachable("Unknown visibility");
- }
- ++numParen;
- }
-
- os << _symbol << " ";
- switch (_assignmentKind) {
- case Simple:
- os << "=";
- break;
- case Sum:
- os << "+=";
- break;
- case Sub:
- os << "-=";
- break;
- case Mul:
- os << "*=";
- break;
- case Div:
- os << "/=";
- break;
- case Shl:
- os << "<<=";
- break;
- case Shr:
- os << ">>=";
- break;
- case And:
- os << "&=";
- break;
- case Or:
- os << "|=";
- break;
- }
-
- os << " ";
- _expression->dump(os);
- if (numParen)
- os << ")";
- os << ";";
-}
-
-static int dumpSortDirectives(raw_ostream &os, WildcardSortMode sortMode) {
- switch (sortMode) {
- case WildcardSortMode::NA:
- return 0;
- case WildcardSortMode::ByName:
- os << "SORT_BY_NAME(";
- return 1;
- case WildcardSortMode::ByAlignment:
- os << "SORT_BY_ALIGNMENT(";
- return 1;
- case WildcardSortMode::ByInitPriority:
- os << "SORT_BY_INIT_PRIORITY(";
- return 1;
- case WildcardSortMode::ByNameAndAlignment:
- os << "SORT_BY_NAME(SORT_BY_ALIGNMENT(";
- return 2;
- case WildcardSortMode::ByAlignmentAndName:
- os << "SORT_BY_ALIGNMENT(SORT_BY_NAME(";
- return 2;
- case WildcardSortMode::None:
- os << "SORT_NONE(";
- return 1;
- }
- return 0;
-}
-
-// InputSectionName functions
-void InputSectionName::dump(raw_ostream &os) const {
- os << _name;
-}
-
-// InputSectionSortedGroup functions
-static void dumpInputSections(raw_ostream &os,
- llvm::ArrayRef<const InputSection *> secs) {
- bool excludeFile = false;
- bool first = true;
-
- for (auto &secName : secs) {
- if (!first)
- os << " ";
- first = false;
- // Coalesce multiple input sections marked with EXCLUDE_FILE in the same
- // EXCLUDE_FILE() group
- if (auto inputSec = dyn_cast<InputSectionName>(secName)) {
- if (!excludeFile && inputSec->hasExcludeFile()) {
- excludeFile = true;
- os << "EXCLUDE_FILE(";
- } else if (excludeFile && !inputSec->hasExcludeFile()) {
- excludeFile = false;
- os << ") ";
- }
- }
- secName->dump(os);
- }
-
- if (excludeFile)
- os << ")";
-}
-
-void InputSectionSortedGroup::dump(raw_ostream &os) const {
- int numParen = dumpSortDirectives(os, _sortMode);
- dumpInputSections(os, _sections);
- for (int i = 0; i < numParen; ++i)
- os << ")";
-}
-
-// InputSectionsCmd functions
-void InputSectionsCmd::dump(raw_ostream &os) const {
- if (_keep)
- os << "KEEP(";
-
- int numParen = dumpSortDirectives(os, _fileSortMode);
- os << _memberName;
- for (int i = 0; i < numParen; ++i)
- os << ")";
-
- if (_archiveName.size() > 0) {
- os << ":";
- numParen = dumpSortDirectives(os, _archiveSortMode);
- os << _archiveName;
- for (int i = 0; i < numParen; ++i)
- os << ")";
- }
-
- if (_sections.size() > 0) {
- os << "(";
- dumpInputSections(os, _sections);
- os << ")";
- }
-
- if (_keep)
- os << ")";
-}
-
-void FillCmd::dump(raw_ostream &os) const {
- os << "FILL(";
- dumpByteStream(os, StringRef((const char *)_bytes.begin(), _bytes.size()));
- os << ")";
-}
-
-// OutputSectionDescription functions
-void OutputSectionDescription::dump(raw_ostream &os) const {
- if (_discard)
- os << "/DISCARD/";
- else
- os << _sectionName;
-
- if (_address) {
- os << " ";
- _address->dump(os);
- }
- os << " :\n";
-
- if (_at) {
- os << " AT(";
- _at->dump(os);
- os << ")\n";
- }
-
- if (_align) {
- os << " ALIGN(";
- _align->dump(os);
- os << ")\n";
- } else if (_alignWithInput) {
- os << " ALIGN_WITH_INPUT\n";
- }
-
- if (_subAlign) {
- os << " SUBALIGN(";
- _subAlign->dump(os);
- os << ")\n";
- }
-
- switch (_constraint) {
- case C_None:
- break;
- case C_OnlyIfRO:
- os << "ONLY_IF_RO";
- break;
- case C_OnlyIfRW:
- os << "ONLY_IF_RW";
- break;
- }
-
- os << " {\n";
- for (auto &command : _outputSectionCommands) {
- os << " ";
- command->dump(os);
- os << "\n";
- }
- os << " }";
-
- for (auto && phdr : _phdrs)
- os << " : " << phdr;
-
- if (_fillStream.size() > 0) {
- os << " =";
- dumpByteStream(os, _fillStream);
- } else if (_fillExpr) {
- os << " =";
- _fillExpr->dump(os);
- }
-}
-
-// Special header that discards output sections assigned to it.
-static const PHDR PHDR_NONE("NONE", 0, false, false, nullptr, 0);
-
-bool PHDR::isNone() const {
- return this == &PHDR_NONE;
-}
-
-void PHDR::dump(raw_ostream &os) const {
- os << _name << " " << _type;
- if (_includeFileHdr)
- os << " FILEHDR";
- if (_includePHDRs)
- os << " PHDRS";
- if (_at) {
- os << " AT (";
- _at->dump(os);
- os << ")";
- }
- if (_flags)
- os << " FLAGS (" << _flags << ")";
- os << ";\n";
-}
-
-void PHDRS::dump(raw_ostream &os) const {
- os << "PHDRS\n{\n";
- for (auto &&phdr : _phdrs) {
- phdr->dump(os);
- }
- os << "}\n";
-}
-
-// Sections functions
-void Sections::dump(raw_ostream &os) const {
- os << "SECTIONS\n{\n";
- for (auto &command : _sectionsCommands) {
- command->dump(os);
- os << "\n";
- }
- os << "}\n";
-}
-
-// Memory functions
-void MemoryBlock::dump(raw_ostream &os) const {
- os << _name;
-
- if (!_attr.empty())
- os << " (" << _attr << ")";
-
- os << " : ";
-
- os << "ORIGIN = ";
- _origin->dump(os);
- os << ", ";
-
- os << "LENGTH = ";
- _length->dump(os);
-}
-
-void Memory::dump(raw_ostream &os) const {
- os << "MEMORY\n{\n";
- for (auto &block : _blocks) {
- block->dump(os);
- os << "\n";
- }
- os << "}\n";
-}
-
-// Extern functions
-void Extern::dump(raw_ostream &os) const {
- os << "EXTERN(";
- for (unsigned i = 0, e = _symbols.size(); i != e; ++i) {
- if (i)
- os << " ";
- os << _symbols[i];
- }
- os << ")\n";
-}
-
-// Parser functions
-std::error_code Parser::parse() {
- // Get the first token.
- _lex.lex(_tok);
- // Parse top level commands.
- while (true) {
- switch (_tok._kind) {
- case Token::eof:
- return std::error_code();
- case Token::semicolon:
- consumeToken();
- break;
- case Token::kw_output: {
- auto output = parseOutput();
- if (!output)
- return LinkerScriptReaderError::parse_error;
- _script._commands.push_back(output);
- break;
- }
- case Token::kw_output_format: {
- auto outputFormat = parseOutputFormat();
- if (!outputFormat)
- return LinkerScriptReaderError::parse_error;
- _script._commands.push_back(outputFormat);
- break;
- }
- case Token::kw_output_arch: {
- auto outputArch = parseOutputArch();
- if (!outputArch)
- return LinkerScriptReaderError::parse_error;
- _script._commands.push_back(outputArch);
- break;
- }
- case Token::kw_input: {
- Input *input = parsePathList<Input>();
- if (!input)
- return LinkerScriptReaderError::parse_error;
- _script._commands.push_back(input);
- break;
- }
- case Token::kw_group: {
- Group *group = parsePathList<Group>();
- if (!group)
- return LinkerScriptReaderError::parse_error;
- _script._commands.push_back(group);
- break;
- }
- case Token::kw_as_needed:
- // Not allowed at top level.
- error(_tok, "AS_NEEDED not allowed at top level.");
- return LinkerScriptReaderError::parse_error;
- case Token::kw_entry: {
- Entry *entry = parseEntry();
- if (!entry)
- return LinkerScriptReaderError::parse_error;
- _script._commands.push_back(entry);
- break;
- }
- case Token::kw_phdrs: {
- PHDRS *phdrs = parsePHDRS();
- if (!phdrs)
- return LinkerScriptReaderError::parse_error;
- _script._commands.push_back(phdrs);
- break;
- }
- case Token::kw_search_dir: {
- SearchDir *searchDir = parseSearchDir();
- if (!searchDir)
- return LinkerScriptReaderError::parse_error;
- _script._commands.push_back(searchDir);
- break;
- }
- case Token::kw_sections: {
- Sections *sections = parseSections();
- if (!sections)
- return LinkerScriptReaderError::parse_error;
- _script._commands.push_back(sections);
- break;
- }
- case Token::identifier:
- case Token::kw_hidden:
- case Token::kw_provide:
- case Token::kw_provide_hidden: {
- const Command *cmd = parseSymbolAssignment();
- if (!cmd)
- return LinkerScriptReaderError::parse_error;
- _script._commands.push_back(cmd);
- break;
- }
- case Token::kw_memory: {
- const Command *cmd = parseMemory();
- if (!cmd)
- return LinkerScriptReaderError::parse_error;
- _script._commands.push_back(cmd);
- break;
- }
- case Token::kw_extern: {
- const Command *cmd = parseExtern();
- if (!cmd)
- return LinkerScriptReaderError::parse_error;
- _script._commands.push_back(cmd);
- break;
- }
- default:
- // Unexpected.
- error(_tok, "expected linker script command");
- return LinkerScriptReaderError::parse_error;
- }
- }
- return LinkerScriptReaderError::parse_error;
-}
-
-const Expression *Parser::parseFunctionCall() {
- assert((_tok._kind == Token::identifier || _tok._kind == Token::kw_align) &&
- "expected function call first tokens");
- SmallVector<const Expression *, 8> params;
- StringRef name = _tok._range;
-
- consumeToken();
- if (!expectAndConsume(Token::l_paren, "expected ("))
- return nullptr;
-
- if (_tok._kind == Token::r_paren) {
- consumeToken();
- return new (_alloc) FunctionCall(*this, _tok._range, params);
- }
-
- if (const Expression *firstParam = parseExpression())
- params.push_back(firstParam);
- else
- return nullptr;
-
- while (_tok._kind == Token::comma) {
- consumeToken();
- if (const Expression *param = parseExpression())
- params.push_back(param);
- else
- return nullptr;
- }
-
- if (!expectAndConsume(Token::r_paren, "expected )"))
- return nullptr;
- return new (_alloc) FunctionCall(*this, name, params);
-}
-
-bool Parser::expectExprOperand() {
- if (!(_tok._kind == Token::identifier || _tok._kind == Token::number ||
- _tok._kind == Token::kw_align || _tok._kind == Token::l_paren ||
- _tok._kind == Token::minus || _tok._kind == Token::tilde)) {
- error(_tok, "expected symbol, number, minus, tilde or left parenthesis.");
- return false;
- }
- return true;
-}
-
-const Expression *Parser::parseExprOperand() {
- if (!expectExprOperand())
- return nullptr;
-
- switch (_tok._kind) {
- case Token::identifier: {
- if (peek()._kind== Token::l_paren)
- return parseFunctionCall();
- auto *sym = new (_alloc) Symbol(*this, _tok._range);
- consumeToken();
- return sym;
- }
- case Token::kw_align:
- return parseFunctionCall();
- case Token::minus:
- consumeToken();
- return new (_alloc) Unary(*this, Unary::Minus, parseExprOperand());
- case Token::tilde:
- consumeToken();
- return new (_alloc) Unary(*this, Unary::Not, parseExprOperand());
- case Token::number: {
- auto val = parseNum(_tok._range);
- if (val.getError()) {
- error(_tok, "Unrecognized number constant");
- return nullptr;
- }
- auto *c = new (_alloc) Constant(*this, *val);
- consumeToken();
- return c;
- }
- case Token::l_paren: {
- consumeToken();
- const Expression *expr = parseExpression();
- if (!expectAndConsume(Token::r_paren, "expected )"))
- return nullptr;
- return expr;
- }
- default:
- llvm_unreachable("Unknown token");
- }
-}
-
-static bool TokenToBinOp(const Token &tok, BinOp::Operation &op,
- unsigned &precedence) {
- switch (tok._kind) {
- case Token::star:
- op = BinOp::Mul;
- precedence = 3;
- return true;
- case Token::slash:
- op = BinOp::Div;
- precedence = 3;
- return true;
- case Token::plus:
- op = BinOp::Sum;
- precedence = 4;
- return true;
- case Token::minus:
- op = BinOp::Sub;
- precedence = 4;
- return true;
- case Token::lessless:
- op = BinOp::Shl;
- precedence = 5;
- return true;
- case Token::greatergreater:
- op = BinOp::Shr;
- precedence = 5;
- return true;
- case Token::less:
- op = BinOp::CompareLess;
- precedence = 6;
- return true;
- case Token::greater:
- op = BinOp::CompareGreater;
- precedence = 6;
- return true;
- case Token::lessequal:
- op = BinOp::CompareLessEqual;
- precedence = 6;
- return true;
- case Token::greaterequal:
- op = BinOp::CompareGreaterEqual;
- precedence = 6;
- return true;
- case Token::equalequal:
- op = BinOp::CompareEqual;
- precedence = 7;
- return true;
- case Token::exclaimequal:
- op = BinOp::CompareDifferent;
- precedence = 7;
- return true;
- case Token::amp:
- op = BinOp::And;
- precedence = 8;
- return true;
- case Token::pipe:
- op = BinOp::Or;
- precedence = 10;
- return true;
- default:
- break;
- }
- return false;
-}
-
-static bool isExpressionOperator(Token tok) {
- switch (tok._kind) {
- case Token::star:
- case Token::slash:
- case Token::plus:
- case Token::minus:
- case Token::lessless:
- case Token::greatergreater:
- case Token::less:
- case Token::greater:
- case Token::lessequal:
- case Token::greaterequal:
- case Token::equalequal:
- case Token::exclaimequal:
- case Token::amp:
- case Token::pipe:
- case Token::question:
- return true;
- default:
- return false;
- }
-}
-
-const Expression *Parser::parseExpression(unsigned precedence) {
- assert(precedence <= 13 && "Invalid precedence value");
- if (!expectExprOperand())
- return nullptr;
-
- const Expression *expr = parseExprOperand();
- if (!expr)
- return nullptr;
-
- BinOp::Operation op;
- unsigned binOpPrecedence = 0;
- if (TokenToBinOp(_tok, op, binOpPrecedence)) {
- if (precedence >= binOpPrecedence)
- return parseOperatorOperandLoop(expr, precedence);
- return expr;
- }
-
- // Non-binary operators
- if (_tok._kind == Token::question && precedence >= 13)
- return parseOperatorOperandLoop(expr, precedence);
- return expr;
-}
-
-const Expression *Parser::parseOperatorOperandLoop(const Expression *lhs,
- unsigned highestPrecedence) {
- assert(highestPrecedence <= 13 && "Invalid precedence value");
- unsigned precedence = 0;
- const Expression *binOp = nullptr;
-
- while (1) {
- BinOp::Operation op;
- if (!TokenToBinOp(_tok, op, precedence)) {
- if (_tok._kind == Token::question && highestPrecedence >= 13)
- return parseTernaryCondOp(lhs);
- return binOp;
- }
-
- if (precedence > highestPrecedence)
- return binOp;
-
- consumeToken();
- const Expression *rhs = parseExpression(precedence - 1);
- if (!rhs)
- return nullptr;
- binOp = new (_alloc) BinOp(*this, lhs, op, rhs);
- lhs = binOp;
- }
-}
-
-const Expression *Parser::parseTernaryCondOp(const Expression *lhs) {
- assert(_tok._kind == Token::question && "Expected question mark");
-
- consumeToken();
-
- // The ternary conditional operator has right-to-left associativity.
- // To implement this, we allow our children to contain ternary conditional
- // operators themselves (precedence 13).
- const Expression *trueExpr = parseExpression(13);
- if (!trueExpr)
- return nullptr;
-
- if (!expectAndConsume(Token::colon, "expected :"))
- return nullptr;
-
- const Expression *falseExpr = parseExpression(13);
- if (!falseExpr)
- return nullptr;
-
- return new (_alloc) TernaryConditional(*this, lhs, trueExpr, falseExpr);
-}
-
-// Parse OUTPUT(ident)
-Output *Parser::parseOutput() {
- assert(_tok._kind == Token::kw_output && "Expected OUTPUT");
- consumeToken();
- if (!expectAndConsume(Token::l_paren, "expected ("))
- return nullptr;
-
- if (_tok._kind != Token::identifier) {
- error(_tok, "Expected identifier in OUTPUT.");
- return nullptr;
- }
-
- auto ret = new (_alloc) Output(*this, _tok._range);
- consumeToken();
-
- if (!expectAndConsume(Token::r_paren, "expected )"))
- return nullptr;
-
- return ret;
-}
-
-// Parse OUTPUT_FORMAT(ident)
-OutputFormat *Parser::parseOutputFormat() {
- assert(_tok._kind == Token::kw_output_format && "Expected OUTPUT_FORMAT!");
- consumeToken();
- if (!expectAndConsume(Token::l_paren, "expected ("))
- return nullptr;
-
- if (_tok._kind != Token::identifier) {
- error(_tok, "Expected identifier in OUTPUT_FORMAT.");
- return nullptr;
- }
-
- SmallVector<StringRef, 8> formats;
- formats.push_back(_tok._range);
-
- consumeToken();
-
- do {
- if (isNextToken(Token::comma))
- consumeToken();
- else
- break;
- if (_tok._kind != Token::identifier) {
- error(_tok, "Expected identifier in OUTPUT_FORMAT.");
- return nullptr;
- }
- formats.push_back(_tok._range);
- consumeToken();
- } while (isNextToken(Token::comma));
-
- if (!expectAndConsume(Token::r_paren, "expected )"))
- return nullptr;
-
- return new (_alloc) OutputFormat(*this, formats);
-}
-
-// Parse OUTPUT_ARCH(ident)
-OutputArch *Parser::parseOutputArch() {
- assert(_tok._kind == Token::kw_output_arch && "Expected OUTPUT_ARCH!");
- consumeToken();
- if (!expectAndConsume(Token::l_paren, "expected ("))
- return nullptr;
-
- if (_tok._kind != Token::identifier) {
- error(_tok, "Expected identifier in OUTPUT_ARCH.");
- return nullptr;
- }
-
- auto ret = new (_alloc) OutputArch(*this, _tok._range);
- consumeToken();
-
- if (!expectAndConsume(Token::r_paren, "expected )"))
- return nullptr;
-
- return ret;
-}
-
-// Parse file list for INPUT or GROUP
-template<class T> T *Parser::parsePathList() {
- consumeToken();
- if (!expectAndConsume(Token::l_paren, "expected ("))
- return nullptr;
-
- SmallVector<Path, 8> paths;
- while (_tok._kind == Token::identifier || _tok._kind == Token::libname ||
- _tok._kind == Token::kw_as_needed) {
- switch (_tok._kind) {
- case Token::identifier:
- paths.push_back(Path(_tok._range));
- consumeToken();
- break;
- case Token::libname:
- paths.push_back(Path(_tok._range, false, true));
- consumeToken();
- break;
- case Token::kw_as_needed:
- if (!parseAsNeeded(paths))
- return nullptr;
- break;
- default:
- llvm_unreachable("Invalid token.");
- }
- }
- if (!expectAndConsume(Token::r_paren, "expected )"))
- return nullptr;
- return new (_alloc) T(*this, paths);
-}
-
-// Parse AS_NEEDED(file ...)
-bool Parser::parseAsNeeded(SmallVectorImpl<Path> &paths) {
- assert(_tok._kind == Token::kw_as_needed && "Expected AS_NEEDED!");
- consumeToken();
- if (!expectAndConsume(Token::l_paren, "expected ("))
- return false;
-
- while (_tok._kind == Token::identifier || _tok._kind == Token::libname) {
- switch (_tok._kind) {
- case Token::identifier:
- paths.push_back(Path(_tok._range, true, false));
- consumeToken();
- break;
- case Token::libname:
- paths.push_back(Path(_tok._range, true, true));
- consumeToken();
- break;
- default:
- llvm_unreachable("Invalid token.");
- }
- }
-
- if (!expectAndConsume(Token::r_paren, "expected )"))
- return false;
- return true;
-}
-
-// Parse ENTRY(ident)
-Entry *Parser::parseEntry() {
- assert(_tok._kind == Token::kw_entry && "Expected ENTRY!");
- consumeToken();
- if (!expectAndConsume(Token::l_paren, "expected ("))
- return nullptr;
- if (_tok._kind != Token::identifier) {
- error(_tok, "expected identifier in ENTRY");
- return nullptr;
- }
- StringRef entryName(_tok._range);
- consumeToken();
- if (!expectAndConsume(Token::r_paren, "expected )"))
- return nullptr;
- return new (_alloc) Entry(*this, entryName);
-}
-
-// Parse SEARCH_DIR(ident)
-SearchDir *Parser::parseSearchDir() {
- assert(_tok._kind == Token::kw_search_dir && "Expected SEARCH_DIR!");
- consumeToken();
- if (!expectAndConsume(Token::l_paren, "expected ("))
- return nullptr;
- if (_tok._kind != Token::identifier) {
- error(_tok, "expected identifier in SEARCH_DIR");
- return nullptr;
- }
- StringRef searchPath(_tok._range);
- consumeToken();
- if (!expectAndConsume(Token::r_paren, "expected )"))
- return nullptr;
- return new (_alloc) SearchDir(*this, searchPath);
-}
-
-const SymbolAssignment *Parser::parseSymbolAssignment() {
- assert((_tok._kind == Token::identifier || _tok._kind == Token::kw_hidden ||
- _tok._kind == Token::kw_provide ||
- _tok._kind == Token::kw_provide_hidden) &&
- "Expected identifier!");
- SymbolAssignment::AssignmentVisibility visibility = SymbolAssignment::Default;
- SymbolAssignment::AssignmentKind kind;
- int numParen = 0;
-
- switch (_tok._kind) {
- case Token::kw_hidden:
- visibility = SymbolAssignment::Hidden;
- ++numParen;
- consumeToken();
- if (!expectAndConsume(Token::l_paren, "expected ("))
- return nullptr;
- break;
- case Token::kw_provide:
- visibility = SymbolAssignment::Provide;
- ++numParen;
- consumeToken();
- if (!expectAndConsume(Token::l_paren, "expected ("))
- return nullptr;
- break;
- case Token::kw_provide_hidden:
- visibility = SymbolAssignment::ProvideHidden;
- ++numParen;
- consumeToken();
- if (!expectAndConsume(Token::l_paren, "expected ("))
- return nullptr;
- break;
- default:
- break;
- }
-
- StringRef name = _tok._range;
- consumeToken();
-
- // Parse assignment operator (=, +=, -= etc.)
- switch (_tok._kind) {
- case Token::equal:
- kind = SymbolAssignment::Simple;
- break;
- case Token::plusequal:
- kind = SymbolAssignment::Sum;
- break;
- case Token::minusequal:
- kind = SymbolAssignment::Sub;
- break;
- case Token::starequal:
- kind = SymbolAssignment::Mul;
- break;
- case Token::slashequal:
- kind = SymbolAssignment::Div;
- break;
- case Token::ampequal:
- kind = SymbolAssignment::And;
- break;
- case Token::pipeequal:
- kind = SymbolAssignment::Or;
- break;
- case Token::lesslessequal:
- kind = SymbolAssignment::Shl;
- break;
- case Token::greatergreaterequal:
- kind = SymbolAssignment::Shr;
- break;
- default:
- error(_tok, "unexpected token");
- return nullptr;
- }
-
- consumeToken();
-
- const Expression *expr = nullptr;
- switch (_tok._kind) {
- case Token::number:
- case Token::kw_align:
- case Token::identifier:
- case Token::l_paren:
- expr = parseExpression();
- if (!expr)
- return nullptr;
- break;
- default:
- error(_tok, "unexpected token while parsing assignment value.");
- return nullptr;
- }
-
- for (int i = 0; i < numParen; ++i)
- if (!expectAndConsume(Token::r_paren, "expected )"))
- return nullptr;
-
- return new (_alloc) SymbolAssignment(*this, name, expr, kind, visibility);
-}
-
-llvm::ErrorOr<InputSectionsCmd::VectorTy> Parser::parseExcludeFile() {
- assert(_tok._kind == Token::kw_exclude_file && "Expected EXCLUDE_FILE!");
- InputSectionsCmd::VectorTy res;
- consumeToken();
-
- if (!expectAndConsume(Token::l_paren, "expected ("))
- return llvm::ErrorOr<InputSectionsCmd::VectorTy>(
- make_error_code(llvm::errc::io_error));
-
- while (_tok._kind == Token::identifier) {
- res.push_back(new (_alloc) InputSectionName(*this, _tok._range, true));
- consumeToken();
- }
-
- if (!expectAndConsume(Token::r_paren, "expected )"))
- return llvm::ErrorOr<InputSectionsCmd::VectorTy>(
- make_error_code(llvm::errc::io_error));
- return llvm::ErrorOr<InputSectionsCmd::VectorTy>(std::move(res));
-}
-
-int Parser::parseSortDirectives(WildcardSortMode &sortMode) {
- int numParsedDirectives = 0;
- sortMode = WildcardSortMode::NA;
-
- if (_tok._kind == Token::kw_sort_by_name) {
- consumeToken();
- if (!expectAndConsume(Token::l_paren, "expected ("))
- return -1;
- ++numParsedDirectives;
- sortMode = WildcardSortMode::ByName;
- }
-
- if (_tok._kind == Token::kw_sort_by_init_priority) {
- consumeToken();
- if (!expectAndConsume(Token::l_paren, "expected ("))
- return -1;
- ++numParsedDirectives;
- sortMode = WildcardSortMode::ByInitPriority;
- }
-
- if (_tok._kind == Token::kw_sort_by_alignment) {
- consumeToken();
- if (!expectAndConsume(Token::l_paren, "expected ("))
- return -1;
- ++numParsedDirectives;
- if (sortMode != WildcardSortMode::ByName)
- sortMode = WildcardSortMode::ByAlignment;
- else
- sortMode = WildcardSortMode::ByNameAndAlignment;
- }
-
- if (numParsedDirectives < 2 && _tok._kind == Token::kw_sort_by_name) {
- consumeToken();
- if (!expectAndConsume(Token::l_paren, "expected ("))
- return -1;
- ++numParsedDirectives;
- if (sortMode == WildcardSortMode::ByAlignment)
- sortMode = WildcardSortMode::ByAlignmentAndName;
- }
-
- if (numParsedDirectives < 2 && _tok._kind == Token::kw_sort_by_alignment) {
- consumeToken();
- if (!expectAndConsume(Token::l_paren, "expected ("))
- return -1;
- ++numParsedDirectives;
- }
-
- if (numParsedDirectives == 0 && _tok._kind == Token::kw_sort_none) {
- consumeToken();
- if (!expectAndConsume(Token::l_paren, "expected ("))
- return -1;
- ++numParsedDirectives;
- sortMode = WildcardSortMode::None;
- }
-
- return numParsedDirectives;
-}
-
-const InputSection *Parser::parseSortedInputSections() {
- assert((_tok._kind == Token::kw_sort_by_name ||
- _tok._kind == Token::kw_sort_by_alignment ||
- _tok._kind == Token::kw_sort_by_init_priority ||
- _tok._kind == Token::kw_sort_none) &&
- "Expected SORT directives!");
-
- WildcardSortMode sortMode = WildcardSortMode::NA;
- int numParen = parseSortDirectives(sortMode);
- if (numParen == -1)
- return nullptr;
-
- SmallVector<const InputSection *, 8> inputSections;
-
- while (_tok._kind == Token::identifier) {
- inputSections.push_back(new (_alloc)
- InputSectionName(*this, _tok._range, false));
- consumeToken();
- }
-
- // Eat "numParen" rparens
- for (int i = 0, e = numParen; i != e; ++i)
- if (!expectAndConsume(Token::r_paren, "expected )"))
- return nullptr;
-
- return new (_alloc) InputSectionSortedGroup(*this, sortMode, inputSections);
-}
-
-const InputSectionsCmd *Parser::parseInputSectionsCmd() {
- assert((_tok._kind == Token::identifier || _tok._kind == Token::colon ||
- _tok._kind == Token::star || _tok._kind == Token::kw_keep ||
- _tok._kind == Token::kw_sort_by_name ||
- _tok._kind == Token::kw_sort_by_alignment ||
- _tok._kind == Token::kw_sort_by_init_priority ||
- _tok._kind == Token::kw_sort_none) &&
- "Expected input section first tokens!");
- int numParen = 1;
- bool keep = false;
- WildcardSortMode fileSortMode = WildcardSortMode::NA;
- WildcardSortMode archiveSortMode = WildcardSortMode::NA;
- StringRef memberName;
- StringRef archiveName;
-
- if (_tok._kind == Token::kw_keep) {
- consumeToken();
- if (!expectAndConsume(Token::l_paren, "expected ("))
- return nullptr;
- ++numParen;
- keep = true;
- }
-
- // Input name
- if (_tok._kind != Token::colon) {
- int numParen = parseSortDirectives(fileSortMode);
- if (numParen == -1)
- return nullptr;
- memberName = _tok._range;
- consumeToken();
- if (numParen) {
- while (numParen--)
- if (!expectAndConsume(Token::r_paren, "expected )"))
- return nullptr;
- }
- }
- if (_tok._kind == Token::colon) {
- consumeToken();
- if (_tok._kind == Token::identifier ||
- _tok._kind == Token::kw_sort_by_name ||
- _tok._kind == Token::kw_sort_by_alignment ||
- _tok._kind == Token::kw_sort_by_init_priority ||
- _tok._kind == Token::kw_sort_none) {
- int numParen = parseSortDirectives(archiveSortMode);
- if (numParen == -1)
- return nullptr;
- archiveName = _tok._range;
- consumeToken();
- for (int i = 0; i != numParen; ++i)
- if (!expectAndConsume(Token::r_paren, "expected )"))
- return nullptr;
- }
- }
-
- SmallVector<const InputSection *, 8> inputSections;
-
- if (_tok._kind != Token::l_paren)
- return new (_alloc)
- InputSectionsCmd(*this, memberName, archiveName, keep, fileSortMode,
- archiveSortMode, inputSections);
- consumeToken();
-
- while (_tok._kind == Token::identifier ||
- _tok._kind == Token::kw_exclude_file ||
- _tok._kind == Token::kw_sort_by_name ||
- _tok._kind == Token::kw_sort_by_alignment ||
- _tok._kind == Token::kw_sort_by_init_priority ||
- _tok._kind == Token::kw_sort_none) {
- switch (_tok._kind) {
- case Token::kw_exclude_file: {
- auto vec = parseExcludeFile();
- if (vec.getError())
- return nullptr;
- inputSections.insert(inputSections.end(), vec->begin(), vec->end());
- break;
- }
- case Token::star:
- case Token::identifier: {
- inputSections.push_back(new (_alloc)
- InputSectionName(*this, _tok._range, false));
- consumeToken();
- break;
- }
- case Token::kw_sort_by_name:
- case Token::kw_sort_by_alignment:
- case Token::kw_sort_by_init_priority:
- case Token::kw_sort_none: {
- const InputSection *group = parseSortedInputSections();
- if (!group)
- return nullptr;
- inputSections.push_back(group);
- break;
- }
- default:
- llvm_unreachable("Unknown token");
- }
- }
-
- for (int i = 0; i < numParen; ++i)
- if (!expectAndConsume(Token::r_paren, "expected )"))
- return nullptr;
- return new (_alloc)
- InputSectionsCmd(*this, memberName, archiveName, keep, fileSortMode,
- archiveSortMode, inputSections);
-}
-
-const FillCmd *Parser::parseFillCmd() {
- assert(_tok._kind == Token::kw_fill && "Expected FILL!");
- consumeToken();
- if (!expectAndConsume(Token::l_paren, "expected ("))
- return nullptr;
-
- SmallVector<uint8_t, 8> storage;
-
- // If the expression is just a number, it's arbitrary length.
- if (_tok._kind == Token::number && peek()._kind == Token::r_paren) {
- if (_tok._range.size() > 2 && _tok._range.startswith("0x")) {
- StringRef num = _tok._range.substr(2);
- for (char c : num) {
- unsigned nibble = llvm::hexDigitValue(c);
- if (nibble == -1u)
- goto not_simple_hex;
- storage.push_back(nibble);
- }
-
- if (storage.size() % 2 != 0)
- storage.insert(storage.begin(), 0);
-
- // Collapse nibbles.
- for (std::size_t i = 0, e = storage.size() / 2; i != e; ++i)
- storage[i] = (storage[i * 2] << 4) + storage[(i * 2) + 1];
-
- storage.resize(storage.size() / 2);
- }
- }
-not_simple_hex:
-
- const Expression *expr = parseExpression();
- if (!expr)
- return nullptr;
- if (!expectAndConsume(Token::r_paren, "expected )"))
- return nullptr;
-
- return new(getAllocator()) FillCmd(*this, storage);
-}
-
-const OutputSectionDescription *Parser::parseOutputSectionDescription() {
- assert((_tok._kind == Token::kw_discard || _tok._kind == Token::identifier) &&
- "Expected /DISCARD/ or identifier!");
- StringRef sectionName;
- const Expression *address = nullptr;
- const Expression *align = nullptr;
- const Expression *subAlign = nullptr;
- const Expression *at = nullptr;
- const Expression *fillExpr = nullptr;
- StringRef fillStream;
- bool alignWithInput = false;
- bool discard = false;
- OutputSectionDescription::Constraint constraint =
- OutputSectionDescription::C_None;
- SmallVector<const Command *, 8> outputSectionCommands;
-
- if (_tok._kind == Token::kw_discard)
- discard = true;
- else
- sectionName = _tok._range;
- consumeToken();
-
- if (_tok._kind == Token::number || _tok._kind == Token::identifier ||
- _tok._kind == Token::kw_align || _tok._kind == Token::l_paren) {
- address = parseExpression();
- if (!address)
- return nullptr;
- }
-
- if (!expectAndConsume(Token::colon, "expected :"))
- return nullptr;
-
- if (_tok._kind == Token::kw_at) {
- consumeToken();
- at = parseExpression();
- if (!at)
- return nullptr;
- }
-
- if (_tok._kind == Token::kw_align) {
- consumeToken();
- align = parseExpression();
- if (!align)
- return nullptr;
- }
-
- if (_tok._kind == Token::kw_align_with_input) {
- consumeToken();
- alignWithInput = true;
- }
-
- if (_tok._kind == Token::kw_subalign) {
- consumeToken();
- subAlign = parseExpression();
- if (!subAlign)
- return nullptr;
- }
-
- if (_tok._kind == Token::kw_only_if_ro) {
- consumeToken();
- constraint = OutputSectionDescription::C_OnlyIfRO;
- } else if (_tok._kind == Token::kw_only_if_rw) {
- consumeToken();
- constraint = OutputSectionDescription::C_OnlyIfRW;
- }
-
- if (!expectAndConsume(Token::l_brace, "expected {"))
- return nullptr;
-
- // Parse zero or more output-section-commands
- while (_tok._kind != Token::r_brace) {
- switch (_tok._kind) {
- case Token::semicolon:
- consumeToken();
- break;
- case Token::identifier:
- switch (peek()._kind) {
- case Token::equal:
- case Token::plusequal:
- case Token::minusequal:
- case Token::starequal:
- case Token::slashequal:
- case Token::ampequal:
- case Token::pipeequal:
- case Token::lesslessequal:
- case Token::greatergreaterequal:
- if (const Command *cmd = parseSymbolAssignment())
- outputSectionCommands.push_back(cmd);
- else
- return nullptr;
- break;
- default:
- if (const Command *cmd = parseInputSectionsCmd())
- outputSectionCommands.push_back(cmd);
- else
- return nullptr;
- break;
- }
- break;
- case Token::kw_fill:
- if (const Command *cmd = parseFillCmd())
- outputSectionCommands.push_back(cmd);
- else
- return nullptr;
- break;
- case Token::kw_keep:
- case Token::star:
- case Token::colon:
- case Token::kw_sort_by_name:
- case Token::kw_sort_by_alignment:
- case Token::kw_sort_by_init_priority:
- case Token::kw_sort_none:
- if (const Command *cmd = parseInputSectionsCmd())
- outputSectionCommands.push_back(cmd);
- else
- return nullptr;
- break;
- case Token::kw_hidden:
- case Token::kw_provide:
- case Token::kw_provide_hidden:
- if (const Command *cmd = parseSymbolAssignment())
- outputSectionCommands.push_back(cmd);
- else
- return nullptr;
- break;
- default:
- error(_tok, "expected symbol assignment or input file name.");
- return nullptr;
- }
- }
-
- if (!expectAndConsume(Token::r_brace, "expected }"))
- return nullptr;
-
- SmallVector<StringRef, 2> phdrs;
- while (_tok._kind == Token::colon) {
- consumeToken();
- if (_tok._kind != Token::identifier) {
- error(_tok, "expected program header name");
- return nullptr;
- }
- phdrs.push_back(_tok._range);
- consumeToken();
- }
-
- if (_tok._kind == Token::equal) {
- consumeToken();
- if (_tok._kind != Token::number || !_tok._range.startswith_lower("0x")) {
- fillExpr = parseExpression();
- if (!fillExpr)
- return nullptr;
- } else {
- std::string strBuf;
- if (isExpressionOperator(peek()) ||
- !parseHexToByteStream(_tok._range.drop_front(2), strBuf)) {
- fillExpr = parseExpression();
- if(!fillExpr)
- return nullptr;
- } else {
- char *rawBuf = (char *) _alloc.Allocate(strBuf.size(), 1);
- memcpy(rawBuf, strBuf.c_str(), strBuf.size());
- fillStream = StringRef(rawBuf, strBuf.size());
- consumeToken();
- }
- }
- }
-
- return new (_alloc) OutputSectionDescription(
- *this, sectionName, address, align, subAlign, at, fillExpr, fillStream,
- alignWithInput, discard, constraint, outputSectionCommands, phdrs);
-}
-
-const Overlay *Parser::parseOverlay() {
- assert(_tok._kind == Token::kw_overlay && "Expected OVERLAY!");
- error(_tok, "Overlay description is not yet supported.");
- return nullptr;
-}
-
-const PHDR *Parser::parsePHDR() {
- assert(_tok._kind == Token::identifier && "Expected identifier!");
-
- StringRef name = _tok._range;
- consumeToken();
-
- uint64_t type;
-
- switch (_tok._kind) {
- case Token::identifier:
- case Token::number:
- case Token::l_paren: {
- const Expression *expr = parseExpression();
- if (!expr)
- return nullptr;
- Expression::SymbolTableTy PHDRTypes;
-#define PHDR_INSERT(x) PHDRTypes.insert(std::make_pair(#x, llvm::ELF::x))
- PHDR_INSERT(PT_NULL);
- PHDR_INSERT(PT_LOAD);
- PHDR_INSERT(PT_DYNAMIC);
- PHDR_INSERT(PT_INTERP);
- PHDR_INSERT(PT_NOTE);
- PHDR_INSERT(PT_SHLIB);
- PHDR_INSERT(PT_PHDR);
- PHDR_INSERT(PT_TLS);
- PHDR_INSERT(PT_LOOS);
- PHDR_INSERT(PT_GNU_EH_FRAME);
- PHDR_INSERT(PT_GNU_STACK);
- PHDR_INSERT(PT_GNU_RELRO);
- PHDR_INSERT(PT_SUNW_EH_FRAME);
- PHDR_INSERT(PT_SUNW_UNWIND);
- PHDR_INSERT(PT_HIOS);
- PHDR_INSERT(PT_LOPROC);
- PHDR_INSERT(PT_ARM_ARCHEXT);
- PHDR_INSERT(PT_ARM_EXIDX);
- PHDR_INSERT(PT_ARM_UNWIND);
- PHDR_INSERT(PT_MIPS_REGINFO);
- PHDR_INSERT(PT_MIPS_RTPROC);
- PHDR_INSERT(PT_MIPS_OPTIONS);
- PHDR_INSERT(PT_MIPS_ABIFLAGS);
- PHDR_INSERT(PT_HIPROC);
-#undef PHDR_INSERT
- auto t = expr->evalExpr(PHDRTypes);
- if (t == LinkerScriptReaderError::unknown_symbol_in_expr) {
- error(_tok, "Unknown type");
- return nullptr;
- }
- if (!t)
- return nullptr;
- type = *t;
- break;
- }
- default:
- error(_tok, "expected identifier or expression");
- return nullptr;
- }
-
- uint64_t flags = 0;
- const Expression *flagsExpr = nullptr;
- bool includeFileHdr = false;
- bool includePHDRs = false;
-
- while (_tok._kind != Token::semicolon) {
- switch (_tok._kind) {
- case Token::kw_filehdr:
- if (includeFileHdr) {
- error(_tok, "Duplicate FILEHDR attribute");
- return nullptr;
- }
- includeFileHdr = true;
- consumeToken();
- break;
- case Token::kw_phdrs:
- if (includePHDRs) {
- error(_tok, "Duplicate PHDRS attribute");
- return nullptr;
- }
- includePHDRs = true;
- consumeToken();
- break;
- case Token::kw_flags: {
- if (flagsExpr) {
- error(_tok, "Duplicate FLAGS attribute");
- return nullptr;
- }
- consumeToken();
- if (!expectAndConsume(Token::l_paren, "Expected ("))
- return nullptr;
- flagsExpr = parseExpression();
- if (!flagsExpr)
- return nullptr;
- auto f = flagsExpr->evalExpr();
- if (!f)
- return nullptr;
- flags = *f;
- if (!expectAndConsume(Token::r_paren, "Expected )"))
- return nullptr;
- } break;
- default:
- error(_tok, "Unexpected token");
- return nullptr;
- }
- }
-
- if (!expectAndConsume(Token::semicolon, "Expected ;"))
- return nullptr;
-
- return new (getAllocator())
- PHDR(name, type, includeFileHdr, includePHDRs, nullptr, flags);
-}
-
-PHDRS *Parser::parsePHDRS() {
- assert(_tok._kind == Token::kw_phdrs && "Expected PHDRS!");
- consumeToken();
- if (!expectAndConsume(Token::l_brace, "expected {"))
- return nullptr;
-
- SmallVector<const PHDR *, 8> phdrs;
-
- while (true) {
- if (_tok._kind == Token::identifier) {
- const PHDR *phdr = parsePHDR();
- if (!phdr)
- return nullptr;
- phdrs.push_back(phdr);
- } else
- break;
- }
-
- if (!expectAndConsume(Token::r_brace, "expected }"))
- return nullptr;
-
- return new (getAllocator()) PHDRS(*this, phdrs);
-}
-
-Sections *Parser::parseSections() {
- assert(_tok._kind == Token::kw_sections && "Expected SECTIONS!");
- consumeToken();
- if (!expectAndConsume(Token::l_brace, "expected {"))
- return nullptr;
- SmallVector<const Command *, 8> sectionsCommands;
-
- bool unrecognizedToken = false;
- // Parse zero or more sections-commands
- while (!unrecognizedToken) {
- switch (_tok._kind) {
- case Token::semicolon:
- consumeToken();
- break;
-
- case Token::identifier:
- switch (peek()._kind) {
- case Token::equal:
- case Token::plusequal:
- case Token::minusequal:
- case Token::starequal:
- case Token::slashequal:
- case Token::ampequal:
- case Token::pipeequal:
- case Token::lesslessequal:
- case Token::greatergreaterequal:
- if (const Command *cmd = parseSymbolAssignment())
- sectionsCommands.push_back(cmd);
- else
- return nullptr;
- break;
- default:
- if (const Command *cmd = parseOutputSectionDescription())
- sectionsCommands.push_back(cmd);
- else
- return nullptr;
- break;
- }
- break;
-
- case Token::kw_discard:
- case Token::star:
- if (const Command *cmd = parseOutputSectionDescription())
- sectionsCommands.push_back(cmd);
- else
- return nullptr;
- break;
-
- case Token::kw_entry:
- if (const Command *cmd = parseEntry())
- sectionsCommands.push_back(cmd);
- else
- return nullptr;
- break;
-
- case Token::kw_hidden:
- case Token::kw_provide:
- case Token::kw_provide_hidden:
- if (const Command *cmd = parseSymbolAssignment())
- sectionsCommands.push_back(cmd);
- else
- return nullptr;
- break;
-
- case Token::kw_overlay:
- if (const Command *cmd = parseOverlay())
- sectionsCommands.push_back(cmd);
- else
- return nullptr;
- break;
-
- default:
- unrecognizedToken = true;
- break;
- }
- }
-
- if (!expectAndConsume(
- Token::r_brace,
- "expected symbol assignment, entry, overlay or output section name."))
- return nullptr;
-
- return new (_alloc) Sections(*this, sectionsCommands);
-}
-
-Memory *Parser::parseMemory() {
- assert(_tok._kind == Token::kw_memory && "Expected MEMORY!");
- consumeToken();
- if (!expectAndConsume(Token::l_brace, "expected {"))
- return nullptr;
- SmallVector<const MemoryBlock *, 8> blocks;
-
- bool unrecognizedToken = false;
- // Parse zero or more memory block descriptors.
- while (!unrecognizedToken) {
- if (_tok._kind == Token::identifier) {
- StringRef name;
- StringRef attrs;
- const Expression *origin = nullptr;
- const Expression *length = nullptr;
-
- name = _tok._range;
- consumeToken();
-
- // Parse optional memory region attributes.
- if (_tok._kind == Token::l_paren) {
- consumeToken();
-
- if (_tok._kind != Token::identifier) {
- error(_tok, "Expected memory attribute string.");
- return nullptr;
- }
- attrs = _tok._range;
- consumeToken();
-
- if (!expectAndConsume(Token::r_paren, "expected )"))
- return nullptr;
- }
-
- if (!expectAndConsume(Token::colon, "expected :"))
- return nullptr;
-
- // Parse the ORIGIN (base address of memory block).
- if (!expectAndConsume(Token::kw_origin, "expected ORIGIN"))
- return nullptr;
-
- if (!expectAndConsume(Token::equal, "expected ="))
- return nullptr;
-
- origin = parseExpression();
- if (!origin)
- return nullptr;
-
- if (!expectAndConsume(Token::comma, "expected ,"))
- return nullptr;
-
- // Parse the LENGTH (length of memory block).
- if (!expectAndConsume(Token::kw_length, "expected LENGTH"))
- return nullptr;
-
- if (!expectAndConsume(Token::equal, "expected ="))
- return nullptr;
-
- length = parseExpression();
- if (!length)
- return nullptr;
-
- auto *block = new (_alloc) MemoryBlock(name, attrs, origin, length);
- blocks.push_back(block);
- } else {
- unrecognizedToken = true;
- }
- }
- if (!expectAndConsume(
- Token::r_brace,
- "expected memory block definition."))
- return nullptr;
-
- return new (_alloc) Memory(*this, blocks);
-}
-
-Extern *Parser::parseExtern() {
- assert(_tok._kind == Token::kw_extern && "Expected EXTERN!");
- consumeToken();
- if (!expectAndConsume(Token::l_paren, "expected ("))
- return nullptr;
-
- // Parse one or more symbols.
- SmallVector<StringRef, 8> symbols;
- if (_tok._kind != Token::identifier) {
- error(_tok, "expected one or more symbols in EXTERN.");
- return nullptr;
- }
- symbols.push_back(_tok._range);
- consumeToken();
- while (_tok._kind == Token::identifier) {
- symbols.push_back(_tok._range);
- consumeToken();
- }
-
- if (!expectAndConsume(Token::r_paren, "expected symbol in EXTERN."))
- return nullptr;
-
- return new (_alloc) Extern(*this, symbols);
-}
-
-// Sema member functions
-Sema::Sema() : _programPHDR(nullptr) {}
-
-std::error_code Sema::perform() {
- llvm::StringMap<const PHDR *> phdrs;
-
- for (auto &parser : _scripts) {
- for (const Command *c : parser->get()->_commands) {
- if (const auto *sec = dyn_cast<Sections>(c)) {
- linearizeAST(sec);
- } else if (const auto *ph = dyn_cast<PHDRS>(c)) {
- if (auto ec = collectPHDRs(ph, phdrs))
- return ec;
- }
- }
- }
- return buildSectionToPHDR(phdrs);
-}
-
-bool Sema::less(const SectionKey &lhs, const SectionKey &rhs) const {
- int a = getLayoutOrder(lhs, true);
- int b = getLayoutOrder(rhs, true);
-
- if (a != b) {
- if (a < 0)
- return false;
- if (b < 0)
- return true;
- return a < b;
- }
-
- // If both sections are not mapped anywhere, they have the same order
- if (a < 0)
- return false;
-
- // If both sections fall into the same layout order, we need to find their
- // relative position as written in the (InputSectionsCmd).
- return localCompare(a, lhs, rhs);
-}
-
-StringRef Sema::getOutputSection(const SectionKey &key) const {
- int layoutOrder = getLayoutOrder(key, true);
- if (layoutOrder < 0)
- return StringRef();
-
- for (int i = layoutOrder - 1; i >= 0; --i) {
- if (!isa<OutputSectionDescription>(_layoutCommands[i]))
- continue;
-
- const OutputSectionDescription *out =
- dyn_cast<OutputSectionDescription>(_layoutCommands[i]);
- return out->name();
- }
-
- return StringRef();
-}
-
-std::vector<const SymbolAssignment *>
-Sema::getExprs(const SectionKey &key) {
- int layoutOrder = getLayoutOrder(key, false);
- auto ans = std::vector<const SymbolAssignment *>();
-
- if (layoutOrder < 0 || _deliveredExprs.count(layoutOrder) > 0)
- return ans;
-
- for (int i = layoutOrder - 1; i >= 0; --i) {
- if (isa<InputSection>(_layoutCommands[i]))
- break;
- if (auto assgn = dyn_cast<SymbolAssignment>(_layoutCommands[i]))
- ans.push_back(assgn);
- }
-
- // Reverse this order so we evaluate the expressions in the original order
- // of the linker script
- std::reverse(ans.begin(), ans.end());
-
- // Mark this layout number as delivered
- _deliveredExprs.insert(layoutOrder);
- return ans;
-}
-
-std::error_code Sema::evalExpr(const SymbolAssignment *assgn,
- uint64_t &curPos) {
- _symbolTable[StringRef(".")] = curPos;
-
- auto ans = assgn->expr()->evalExpr(_symbolTable);
- if (ans.getError())
- return ans.getError();
- uint64_t result = *ans;
-
- if (assgn->symbol() == ".") {
- curPos = result;
- return std::error_code();
- }
-
- _symbolTable[assgn->symbol()] = result;
- return std::error_code();
-}
-
-const llvm::StringSet<> &Sema::getScriptDefinedSymbols() const {
- // Do we have cached results?
- if (!_definedSymbols.empty())
- return _definedSymbols;
-
- // Populate our defined set and return it
- for (auto cmd : _layoutCommands)
- if (auto sa = dyn_cast<SymbolAssignment>(cmd)) {
- StringRef symbol = sa->symbol();
- if (!symbol.empty() && symbol != ".")
- _definedSymbols.insert(symbol);
- }
-
- return _definedSymbols;
-}
-
-uint64_t Sema::getLinkerScriptExprValue(StringRef name) const {
- auto it = _symbolTable.find(name);
- assert (it != _symbolTable.end() && "Invalid symbol name!");
- return it->second;
-}
-
-bool Sema::hasPHDRs() const { return !_sectionToPHDR.empty(); }
-
-std::vector<const PHDR *> Sema::getPHDRsForOutputSection(StringRef name) const {
- auto vec = _sectionToPHDR.lookup(name);
- return std::vector<const PHDR *>(std::begin(vec), std::end(vec));
-}
-
-const PHDR *Sema::getProgramPHDR() const { return _programPHDR; }
-
-void Sema::dump() const {
- raw_ostream &os = llvm::outs();
- os << "Linker script semantics dump\n";
- int num = 0;
- for (auto &parser : _scripts) {
- os << "Dumping script #" << ++num << ":\n";
- parser->get()->dump(os);
- os << "\n";
- }
- os << "Dumping rule ids:\n";
- for (unsigned i = 0; i < _layoutCommands.size(); ++i) {
- os << "LayoutOrder " << i << ":\n";
- _layoutCommands[i]->dump(os);
- os << "\n\n";
- }
-}
-
-/// Given a string "pattern" with wildcard characters, return true if it
-/// matches "name". This function is useful when checking if a given name
-/// pattern written in the linker script, i.e. ".text*", should match
-/// ".text.anytext".
-static bool wildcardMatch(StringRef pattern, StringRef name) {
- auto i = name.begin();
-
- // Check if each char in pattern also appears in our input name, handling
- // special wildcard characters.
- for (auto j = pattern.begin(), e = pattern.end(); j != e; ++j) {
- if (i == name.end())
- return false;
-
- switch (*j) {
- case '*':
- while (!wildcardMatch(pattern.drop_front(j - pattern.begin() + 1),
- name.drop_front(i - name.begin()))) {
- if (i == name.end())
- return false;
- ++i;
- }
- break;
- case '?':
- // Matches any character
- ++i;
- break;
- case '[': {
- // Matches a range of characters specified between brackets
- size_t end = pattern.find(']', j - pattern.begin());
- if (end == pattern.size())
- return false;
-
- StringRef chars = pattern.slice(j - pattern.begin(), end);
- if (chars.find(i) == StringRef::npos)
- return false;
-
- j = pattern.begin() + end;
- ++i;
- break;
- }
- case '\\':
- ++j;
- if (*j != *i)
- return false;
- ++i;
- break;
- default:
- // No wildcard character means we must match exactly the same char
- if (*j != *i)
- return false;
- ++i;
- break;
- }
- }
-
- // If our pattern has't consumed the entire string, it is not a match
- return i == name.end();
-}
-
-int Sema::matchSectionName(int id, const SectionKey &key) const {
- const InputSectionsCmd *cmd = dyn_cast<InputSectionsCmd>(_layoutCommands[id]);
-
- if (!cmd || !wildcardMatch(cmd->archiveName(), key.archivePath))
- return -1;
-
- while ((size_t)++id < _layoutCommands.size() &&
- (isa<InputSection>(_layoutCommands[id]))) {
- if (isa<InputSectionSortedGroup>(_layoutCommands[id]))
- continue;
-
- const InputSectionName *in =
- dyn_cast<InputSectionName>(_layoutCommands[id]);
- if (wildcardMatch(in->name(), key.sectionName))
- return id;
- }
- return -1;
-}
-
-int Sema::getLayoutOrder(const SectionKey &key, bool coarse) const {
- // First check if we already answered this layout question
- if (coarse) {
- auto entry = _cacheSectionOrder.find(key);
- if (entry != _cacheSectionOrder.end())
- return entry->second;
- } else {
- auto entry = _cacheExpressionOrder.find(key);
- if (entry != _cacheExpressionOrder.end())
- return entry->second;
- }
-
- // Try to match exact file name
- auto range = _memberToLayoutOrder.equal_range(key.memberPath);
- for (auto I = range.first, E = range.second; I != E; ++I) {
- int order = I->second;
- int exprOrder = -1;
-
- if ((exprOrder = matchSectionName(order, key)) >= 0) {
- if (coarse) {
- _cacheSectionOrder.insert(std::make_pair(key, order));
- return order;
- }
- _cacheExpressionOrder.insert(std::make_pair(key, exprOrder));
- return exprOrder;
- }
- }
-
- // If we still couldn't find a rule for this input section, try to match
- // wildcards
- for (const auto &I : _memberNameWildcards) {
- if (!wildcardMatch(I.first, key.memberPath))
- continue;
- int order = I.second;
- int exprOrder = -1;
-
- if ((exprOrder = matchSectionName(order, key)) >= 0) {
- if (coarse) {
- _cacheSectionOrder.insert(std::make_pair(key, order));
- return order;
- }
- _cacheExpressionOrder.insert(std::make_pair(key, exprOrder));
- return exprOrder;
- }
- }
-
- _cacheSectionOrder.insert(std::make_pair(key, -1));
- _cacheExpressionOrder.insert(std::make_pair(key, -1));
- return -1;
-}
-
-static bool compareSortedNames(WildcardSortMode sortMode, StringRef lhs,
- StringRef rhs) {
- switch (sortMode) {
- case WildcardSortMode::None:
- case WildcardSortMode::NA:
- return false;
- case WildcardSortMode::ByAlignment:
- case WildcardSortMode::ByInitPriority:
- case WildcardSortMode::ByAlignmentAndName:
- assert(false && "Unimplemented sort order");
- break;
- case WildcardSortMode::ByName:
- return lhs.compare(rhs) < 0;
- case WildcardSortMode::ByNameAndAlignment:
- int compare = lhs.compare(rhs);
- if (compare != 0)
- return compare < 0;
- return compareSortedNames(WildcardSortMode::ByAlignment, lhs, rhs);
- }
- return false;
-}
-
-static bool sortedGroupContains(const InputSectionSortedGroup *cmd,
- const Sema::SectionKey &key) {
- for (const InputSection *child : *cmd) {
- if (auto i = dyn_cast<InputSectionName>(child)) {
- if (wildcardMatch(i->name(), key.sectionName))
- return true;
- continue;
- }
-
- auto *sortedGroup = dyn_cast<InputSectionSortedGroup>(child);
- assert(sortedGroup && "Expected InputSectionSortedGroup object");
-
- if (sortedGroupContains(sortedGroup, key))
- return true;
- }
-
- return false;
-}
-
-bool Sema::localCompare(int order, const SectionKey &lhs,
- const SectionKey &rhs) const {
- const InputSectionsCmd *cmd =
- dyn_cast<InputSectionsCmd>(_layoutCommands[order]);
-
- assert(cmd && "Invalid InputSectionsCmd index");
-
- if (lhs.archivePath != rhs.archivePath)
- return compareSortedNames(cmd->archiveSortMode(), lhs.archivePath,
- rhs.archivePath);
-
- if (lhs.memberPath != rhs.memberPath)
- return compareSortedNames(cmd->fileSortMode(), lhs.memberPath,
- rhs.memberPath);
-
- // Both sections come from the same exact same file and rule. Start walking
- // through input section names as written in the linker script and the
- // first one to match will have higher priority.
- for (const InputSection *inputSection : *cmd) {
- if (auto i = dyn_cast<InputSectionName>(inputSection)) {
- // If both match, return false (both have equal priority)
- // If rhs match, return false (rhs has higher priority)
- if (wildcardMatch(i->name(), rhs.sectionName))
- return false;
- // If lhs matches first, it has priority over rhs
- if (wildcardMatch(i->name(), lhs.sectionName))
- return true;
- continue;
- }
-
- // Handle sorted subgroups specially
- auto *sortedGroup = dyn_cast<InputSectionSortedGroup>(inputSection);
- assert(sortedGroup && "Expected InputSectionSortedGroup object");
-
- bool a = sortedGroupContains(sortedGroup, lhs);
- bool b = sortedGroupContains(sortedGroup, rhs);
- if (a && !b)
- return false;
- if (b && !a)
- return true;
- if (!a && !a)
- continue;
-
- return compareSortedNames(sortedGroup->sortMode(), lhs.sectionName,
- rhs.sectionName);
- }
-
- llvm_unreachable("");
- return false;
-}
-
-std::error_code Sema::collectPHDRs(const PHDRS *ph,
- llvm::StringMap<const PHDR *> &phdrs) {
- bool loadFound = false;
- for (auto *p : *ph) {
- phdrs[p->name()] = p;
-
- switch (p->type()) {
- case llvm::ELF::PT_PHDR:
- if (_programPHDR != nullptr)
- return LinkerScriptReaderError::extra_program_phdr;
- if (loadFound)
- return LinkerScriptReaderError::misplaced_program_phdr;
- if (!p->hasPHDRs())
- return LinkerScriptReaderError::program_phdr_wrong_phdrs;
- _programPHDR = p;
- break;
- case llvm::ELF::PT_LOAD:
- // Program header, if available, should have program header table
- // mapped in the first loadable segment.
- if (!loadFound && _programPHDR && !p->hasPHDRs())
- return LinkerScriptReaderError::program_phdr_wrong_phdrs;
- loadFound = true;
- break;
- }
- }
- return std::error_code();
-}
-
-std::error_code Sema::buildSectionToPHDR(llvm::StringMap<const PHDR *> &phdrs) {
- const bool noPhdrs = phdrs.empty();
-
- // Add NONE header to the map provided there's no user-defined
- // header with the same name.
- if (!phdrs.count(PHDR_NONE.name()))
- phdrs[PHDR_NONE.name()] = &PHDR_NONE;
-
- // Match output sections to available headers.
- llvm::SmallVector<const PHDR *, 2> phdrsCur, phdrsLast { &PHDR_NONE };
- for (const Command *cmd : _layoutCommands) {
- auto osd = dyn_cast<OutputSectionDescription>(cmd);
- if (!osd || osd->isDiscarded())
- continue;
-
- phdrsCur.clear();
- for (StringRef name : osd->PHDRs()) {
- auto it = phdrs.find(name);
- if (it == phdrs.end()) {
- return LinkerScriptReaderError::unknown_phdr_ids;
- }
- phdrsCur.push_back(it->second);
- }
-
- // If no headers and no errors - insert empty headers set.
- // If the current set of headers is empty, then use the last non-empty
- // set. Otherwise mark the current set to be the last non-empty set for
- // successors.
- if (noPhdrs)
- phdrsCur.clear();
- else if (phdrsCur.empty())
- phdrsCur = phdrsLast;
- else
- phdrsLast = phdrsCur;
-
- _sectionToPHDR[osd->name()] = phdrsCur;
- }
- return std::error_code();
-}
-
-static bool hasWildcard(StringRef name) {
- for (auto ch : name)
- if (ch == '*' || ch == '?' || ch == '[' || ch == '\\')
- return true;
- return false;
-}
-
-void Sema::linearizeAST(const InputSection *inputSection) {
- if (isa<InputSectionName>(inputSection)) {
- _layoutCommands.push_back(inputSection);
- return;
- }
-
- auto *sortedGroup = dyn_cast<InputSectionSortedGroup>(inputSection);
- assert(sortedGroup && "Expected InputSectionSortedGroup object");
-
- for (const InputSection *child : *sortedGroup) {
- linearizeAST(child);
- }
-}
-
-void Sema::linearizeAST(const InputSectionsCmd *inputSections) {
- StringRef memberName = inputSections->memberName();
- // Populate our maps for fast lookup of InputSectionsCmd
- if (hasWildcard(memberName))
- _memberNameWildcards.push_back(
- std::make_pair(memberName, (int)_layoutCommands.size()));
- else if (!memberName.empty())
- _memberToLayoutOrder.insert(
- std::make_pair(memberName.str(), (int)_layoutCommands.size()));
-
- _layoutCommands.push_back(inputSections);
- for (const InputSection *inputSection : *inputSections)
- linearizeAST(inputSection);
-}
-
-void Sema::linearizeAST(const Sections *sections) {
- for (const Command *sectionCommand : *sections) {
- if (isa<SymbolAssignment>(sectionCommand)) {
- _layoutCommands.push_back(sectionCommand);
- continue;
- }
-
- if (!isa<OutputSectionDescription>(sectionCommand))
- continue;
-
- _layoutCommands.push_back(sectionCommand);
- auto *outSection = dyn_cast<OutputSectionDescription>(sectionCommand);
-
- for (const Command *outSecCommand : *outSection) {
- if (isa<SymbolAssignment>(outSecCommand)) {
- _layoutCommands.push_back(outSecCommand);
- continue;
- }
-
- if (!isa<InputSectionsCmd>(outSecCommand))
- continue;
-
- linearizeAST(dyn_cast<InputSectionsCmd>(outSecCommand));
- }
- }
-}
-
-} // end namespace script
-} // end namespace lld
diff --git a/lib/ReaderWriter/MachO/ArchHandler.h b/lib/ReaderWriter/MachO/ArchHandler.h
index 120f5dfd4cd2..70a63bd1004b 100644
--- a/lib/ReaderWriter/MachO/ArchHandler.h
+++ b/lib/ReaderWriter/MachO/ArchHandler.h
@@ -7,18 +7,19 @@
//
//===----------------------------------------------------------------------===//
+#ifndef LLD_READER_WRITER_MACHO_ARCH_HANDLER_H
+#define LLD_READER_WRITER_MACHO_ARCH_HANDLER_H
+
#include "Atoms.h"
#include "File.h"
#include "MachONormalizedFile.h"
#include "lld/Core/LLVM.h"
+#include "lld/Core/Error.h"
#include "lld/Core/Reference.h"
#include "lld/Core/Simple.h"
#include "lld/ReaderWriter/MachOLinkingContext.h"
#include "llvm/ADT/Triple.h"
-#ifndef LLD_READER_WRITER_MACHO_ARCH_HANDLER_H
-#define LLD_READER_WRITER_MACHO_ARCH_HANDLER_H
-
namespace lld {
namespace mach_o {
@@ -78,6 +79,11 @@ public:
/// actually be used.
virtual uint32_t dwarfCompactUnwindType() = 0;
+ /// Reference from an __eh_frame CIE atom to its personality function it's
+ /// describing. Usually pointer-sized and PC-relative, but differs in whether
+ /// it needs to be in relocatable objects.
+ virtual Reference::KindValue unwindRefToPersonalityFunctionKind() = 0;
+
/// Reference from an __eh_frame FDE to the CIE it's based on.
virtual Reference::KindValue unwindRefToCIEKind() = 0;
@@ -92,6 +98,10 @@ public:
/// __eh_frame.
virtual Reference::KindValue unwindRefToEhFrameKind() = 0;
+ /// Returns a pointer sized reference kind. On 64-bit targets this will
+ /// likely be something like pointer64, and pointer32 on 32-bit targets.
+ virtual Reference::KindValue pointerKind() = 0;
+
virtual const Atom *fdeTargetFunction(const DefinedAtom *fde);
/// Used by normalizedFromAtoms() to know where to generated rebasing and
@@ -107,20 +117,20 @@ public:
/// Prototype for a helper function. Given a sectionIndex and address,
/// finds the atom and offset with that atom of that address.
- typedef std::function<std::error_code (uint32_t sectionIndex, uint64_t addr,
+ typedef std::function<llvm::Error (uint32_t sectionIndex, uint64_t addr,
const lld::Atom **, Reference::Addend *)>
FindAtomBySectionAndAddress;
/// Prototype for a helper function. Given a symbolIndex, finds the atom
/// representing that symbol.
- typedef std::function<std::error_code (uint32_t symbolIndex,
+ typedef std::function<llvm::Error (uint32_t symbolIndex,
const lld::Atom **)> FindAtomBySymbolIndex;
/// Analyzes a relocation from a .o file and returns the info
/// (kind, target, addend) needed to instantiate a Reference.
/// Two helper functions are passed as parameters to find the target atom
/// given a symbol index or address.
- virtual std::error_code
+ virtual llvm::Error
getReferenceInfo(const normalized::Relocation &reloc,
const DefinedAtom *inAtom,
uint32_t offsetInAtom,
@@ -135,7 +145,7 @@ public:
/// (kind, target, addend) needed to instantiate a Reference.
/// Two helper functions are passed as parameters to find the target atom
/// given a symbol index or address.
- virtual std::error_code
+ virtual llvm::Error
getPairReferenceInfo(const normalized::Relocation &reloc1,
const normalized::Relocation &reloc2,
const DefinedAtom *inAtom,
@@ -169,7 +179,7 @@ public:
FindAddressForAtom findAddress,
FindAddressForAtom findSectionAddress,
uint64_t imageBaseAddress,
- uint8_t *atomContentBuffer) = 0;
+ llvm::MutableArrayRef<uint8_t> atomContentBuffer) = 0;
/// Used in -r mode to convert a Reference to a mach-o relocation.
virtual void appendSectionRelocations(const DefinedAtom &atom,
@@ -251,7 +261,10 @@ public:
ReferenceInfo stubHelperReferenceToImm;
ReferenceInfo stubHelperReferenceToHelperCommon;
+ DefinedAtom::ContentType stubHelperImageCacheContentType;
+
uint32_t stubHelperCommonSize;
+ uint8_t stubHelperCommonAlignment;
uint8_t stubHelperCommonBytes[36];
ReferenceInfo stubHelperCommonReferenceToCache;
OptionalRefInfo optStubHelperCommonReferenceToCache;
diff --git a/lib/ReaderWriter/MachO/ArchHandler_arm.cpp b/lib/ReaderWriter/MachO/ArchHandler_arm.cpp
index 4e15a2d434c6..3286fe064535 100644
--- a/lib/ReaderWriter/MachO/ArchHandler_arm.cpp
+++ b/lib/ReaderWriter/MachO/ArchHandler_arm.cpp
@@ -51,6 +51,10 @@ public:
return invalid;
}
+ Reference::KindValue unwindRefToPersonalityFunctionKind() override {
+ return invalid;
+ }
+
Reference::KindValue unwindRefToCIEKind() override {
return invalid;
}
@@ -63,21 +67,25 @@ public:
return invalid;
}
+ Reference::KindValue pointerKind() override {
+ return invalid;
+ }
+
uint32_t dwarfCompactUnwindType() override {
// FIXME
return -1;
}
- std::error_code getReferenceInfo(const normalized::Relocation &reloc,
- const DefinedAtom *inAtom,
- uint32_t offsetInAtom,
- uint64_t fixupAddress, bool swap,
- FindAtomBySectionAndAddress atomFromAddress,
- FindAtomBySymbolIndex atomFromSymbolIndex,
- Reference::KindValue *kind,
- const lld::Atom **target,
- Reference::Addend *addend) override;
- std::error_code
+ llvm::Error getReferenceInfo(const normalized::Relocation &reloc,
+ const DefinedAtom *inAtom,
+ uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool swap,
+ FindAtomBySectionAndAddress atomFromAddress,
+ FindAtomBySymbolIndex atomFromSymbolIndex,
+ Reference::KindValue *kind,
+ const lld::Atom **target,
+ Reference::Addend *addend) override;
+ llvm::Error
getPairReferenceInfo(const normalized::Relocation &reloc1,
const normalized::Relocation &reloc2,
const DefinedAtom *inAtom,
@@ -93,7 +101,7 @@ public:
FindAddressForAtom findAddress,
FindAddressForAtom findSectionAddress,
uint64_t imageBaseAddress,
- uint8_t *atomContentBuffer) override;
+ llvm::MutableArrayRef<uint8_t> atomContentBuffer) override;
void appendSectionRelocations(const DefinedAtom &atom,
uint64_t atomSectionOffset,
@@ -256,8 +264,13 @@ const ArchHandler::StubInfo ArchHandler_arm::_sStubInfoArmPIC = {
{ Reference::KindArch::ARM, lazyImmediateLocation, 8, 0 },
{ Reference::KindArch::ARM, arm_b24, 4, 0 },
+ // Stub helper image cache content type
+ DefinedAtom::typeGOT,
+
// Stub Helper-Common size and code
36,
+ // Stub helper alignment
+ 2,
{ // push lazy-info-offset
0x04, 0xC0, 0x2D, 0xE5, // str ip, [sp, #-4]!
// push address of dyld_mageLoaderCache
@@ -505,13 +518,12 @@ uint32_t ArchHandler_arm::clearThumbBit(uint32_t value, const Atom *target) {
return value;
}
-std::error_code ArchHandler_arm::getReferenceInfo(
+llvm::Error ArchHandler_arm::getReferenceInfo(
const Relocation &reloc, const DefinedAtom *inAtom, uint32_t offsetInAtom,
uint64_t fixupAddress, bool isBig,
FindAtomBySectionAndAddress atomFromAddress,
FindAtomBySymbolIndex atomFromSymbolIndex, Reference::KindValue *kind,
const lld::Atom **target, Reference::Addend *addend) {
- typedef std::error_code E;
const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
uint64_t targetAddress;
uint32_t instruction = *(const ulittle32_t *)fixupContent;
@@ -523,12 +535,12 @@ std::error_code ArchHandler_arm::getReferenceInfo(
*kind = thumb_b22;
else
*kind = thumb_bl22;
- if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
// Instruction contains branch to addend.
displacement = getDisplacementFromThumbBranch(instruction, fixupAddress);
*addend = fixupAddress + 4 + displacement;
- return std::error_code();
+ return llvm::Error();
case ARM_THUMB_RELOC_BR22 | rPcRel | rLength4:
// ex: bl _foo (and _foo is defined)
if ((instruction & 0xD000F800) == 0x9000F000)
@@ -546,12 +558,12 @@ std::error_code ArchHandler_arm::getReferenceInfo(
*kind = thumb_bl22;
displacement = getDisplacementFromThumbBranch(instruction, fixupAddress);
targetAddress = fixupAddress + 4 + displacement;
- if (E ec = atomFromAddress(0, reloc.value, target, addend))
+ if (auto ec = atomFromAddress(0, reloc.value, target, addend))
return ec;
// reloc.value is target atom's address. Instruction contains branch
// to atom+addend.
*addend += (targetAddress - reloc.value);
- return std::error_code();
+ return llvm::Error();
case ARM_RELOC_BR24 | rPcRel | rExtern | rLength4:
// ex: bl _foo (and _foo is undefined)
if (((instruction & 0x0F000000) == 0x0A000000)
@@ -559,12 +571,12 @@ std::error_code ArchHandler_arm::getReferenceInfo(
*kind = arm_b24;
else
*kind = arm_bl24;
- if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
// Instruction contains branch to addend.
displacement = getDisplacementFromArmBranch(instruction);
*addend = fixupAddress + 8 + displacement;
- return std::error_code();
+ return llvm::Error();
case ARM_RELOC_BR24 | rPcRel | rLength4:
// ex: bl _foo (and _foo is defined)
if (((instruction & 0x0F000000) == 0x0A000000)
@@ -584,40 +596,40 @@ std::error_code ArchHandler_arm::getReferenceInfo(
*kind = arm_bl24;
displacement = getDisplacementFromArmBranch(instruction);
targetAddress = fixupAddress + 8 + displacement;
- if (E ec = atomFromAddress(0, reloc.value, target, addend))
+ if (auto ec = atomFromAddress(0, reloc.value, target, addend))
return ec;
// reloc.value is target atom's address. Instruction contains branch
// to atom+addend.
*addend += (targetAddress - reloc.value);
- return std::error_code();
+ return llvm::Error();
case ARM_RELOC_VANILLA | rExtern | rLength4:
// ex: .long _foo (and _foo is undefined)
*kind = pointer32;
- if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = instruction;
- return std::error_code();
+ return llvm::Error();
case ARM_RELOC_VANILLA | rLength4:
// ex: .long _foo (and _foo is defined)
*kind = pointer32;
- if (E ec = atomFromAddress(reloc.symbol, instruction, target, addend))
+ if (auto ec = atomFromAddress(reloc.symbol, instruction, target, addend))
return ec;
*addend = clearThumbBit((uint32_t) * addend, *target);
- return std::error_code();
+ return llvm::Error();
case ARM_RELOC_VANILLA | rScattered | rLength4:
// ex: .long _foo+a (and _foo is defined)
*kind = pointer32;
- if (E ec = atomFromAddress(0, reloc.value, target, addend))
+ if (auto ec = atomFromAddress(0, reloc.value, target, addend))
return ec;
*addend += (clearThumbBit(instruction, *target) - reloc.value);
- return std::error_code();
+ return llvm::Error();
default:
- return make_dynamic_error_code("unsupported arm relocation type");
+ return llvm::make_error<GenericError>("unsupported arm relocation type");
}
- return std::error_code();
+ return llvm::Error();
}
-std::error_code
+llvm::Error
ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1,
const normalized::Relocation &reloc2,
const DefinedAtom *inAtom,
@@ -770,10 +782,9 @@ ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1,
pointerDiff = true;
break;
default:
- return make_dynamic_error_code("unsupported arm relocation pair");
+ return llvm::make_error<GenericError>("unsupported arm relocation pair");
}
const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
- std::error_code ec;
uint32_t instruction = *(const ulittle32_t *)fixupContent;
uint32_t value;
uint32_t fromAddress;
@@ -786,14 +797,12 @@ ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1,
if (pointerDiff) {
toAddress = reloc1.value;
fromAddress = reloc2.value;
- ec = atomFromAddr(0, toAddress, target, &offsetInTo);
- if (ec)
+ if (auto ec = atomFromAddr(0, toAddress, target, &offsetInTo))
return ec;
- ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom);
- if (ec)
+ if (auto ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom))
return ec;
if (scatterable && (fromTarget != inAtom))
- return make_dynamic_error_code(
+ return llvm::make_error<GenericError>(
"SECTDIFF relocation where subtrahend label is not in atom");
*kind = delta32;
value = clearThumbBit(instruction, *target);
@@ -801,35 +810,33 @@ ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1,
} else if (funcRel) {
toAddress = reloc1.value;
fromAddress = reloc2.value;
- ec = atomFromAddr(0, toAddress, target, &offsetInTo);
- if (ec)
+ if (auto ec = atomFromAddr(0, toAddress, target, &offsetInTo))
return ec;
- ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom);
- if (ec)
+ if (auto ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom))
return ec;
if (fromTarget != inAtom)
- return make_dynamic_error_code("ARM_RELOC_HALF_SECTDIFF relocation "
- "where subtrahend label is not in atom");
+ return llvm::make_error<GenericError>("ARM_RELOC_HALF_SECTDIFF relocation"
+ " where subtrahend label is not in atom");
other16 = (reloc2.offset & 0xFFFF);
if (thumbReloc) {
if (top) {
if (!isThumbMovt(instruction))
- return make_dynamic_error_code("expected movt instruction");
+ return llvm::make_error<GenericError>("expected movt instruction");
}
else {
if (!isThumbMovw(instruction))
- return make_dynamic_error_code("expected movw instruction");
+ return llvm::make_error<GenericError>("expected movw instruction");
}
instruction16 = getWordFromThumbMov(instruction);
}
else {
if (top) {
if (!isArmMovt(instruction))
- return make_dynamic_error_code("expected movt instruction");
+ return llvm::make_error<GenericError>("expected movt instruction");
}
else {
if (!isArmMovw(instruction))
- return make_dynamic_error_code("expected movw instruction");
+ return llvm::make_error<GenericError>("expected movw instruction");
}
instruction16 = getWordFromArmMov(instruction);
}
@@ -840,28 +847,28 @@ ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1,
value = clearThumbBit(value, *target);
int64_t ta = (int64_t) value - (toAddress - fromAddress);
*addend = ta - offsetInFrom;
- return std::error_code();
+ return llvm::Error();
} else {
uint32_t sectIndex;
if (thumbReloc) {
if (top) {
if (!isThumbMovt(instruction))
- return make_dynamic_error_code("expected movt instruction");
+ return llvm::make_error<GenericError>("expected movt instruction");
}
else {
if (!isThumbMovw(instruction))
- return make_dynamic_error_code("expected movw instruction");
+ return llvm::make_error<GenericError>("expected movw instruction");
}
instruction16 = getWordFromThumbMov(instruction);
}
else {
if (top) {
if (!isArmMovt(instruction))
- return make_dynamic_error_code("expected movt instruction");
+ return llvm::make_error<GenericError>("expected movt instruction");
}
else {
if (!isArmMovw(instruction))
- return make_dynamic_error_code("expected movw instruction");
+ return llvm::make_error<GenericError>("expected movw instruction");
}
instruction16 = getWordFromArmMov(instruction);
}
@@ -871,8 +878,7 @@ ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1,
else
value = (other16 << 16) | instruction16;
if (reloc1.isExtern) {
- ec = atomFromSymbolIndex(reloc1.symbol, target);
- if (ec)
+ if (auto ec = atomFromSymbolIndex(reloc1.symbol, target))
return ec;
*addend = value;
} else {
@@ -883,14 +889,13 @@ ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1,
toAddress = value;
sectIndex = reloc1.symbol;
}
- ec = atomFromAddr(sectIndex, toAddress, target, &offsetInTo);
- if (ec)
+ if (auto ec = atomFromAddr(sectIndex, toAddress, target, &offsetInTo))
return ec;
*addend = value - toAddress;
}
}
- return std::error_code();
+ return llvm::Error();
}
void ArchHandler_arm::applyFixupFinal(const Reference &ref, uint8_t *loc,
@@ -1006,9 +1011,10 @@ void ArchHandler_arm::generateAtomContent(const DefinedAtom &atom,
FindAddressForAtom findAddress,
FindAddressForAtom findSectionAddress,
uint64_t imageBaseAddress,
- uint8_t *atomContentBuffer) {
+ llvm::MutableArrayRef<uint8_t> atomContentBuffer) {
// Copy raw bytes.
- memcpy(atomContentBuffer, atom.rawContent().data(), atom.size());
+ std::copy(atom.rawContent().begin(), atom.rawContent().end(),
+ atomContentBuffer.begin());
// Apply fix-ups.
bool thumbMode = false;
for (const Reference *ref : atom) {
@@ -1384,7 +1390,8 @@ void ArchHandler_arm::appendSectionRelocations(
void ArchHandler_arm::addAdditionalReferences(MachODefinedAtom &atom) {
if (atom.isThumb()) {
- atom.addReference(0, modeThumbCode, &atom, 0, Reference::KindArch::ARM);
+ atom.addReference(Reference::KindNamespace::mach_o,
+ Reference::KindArch::ARM, modeThumbCode, 0, &atom, 0);
}
}
@@ -1415,6 +1422,8 @@ public:
_name = tmp.copy(file.allocator());
}
+ ~Thumb2ToArmShimAtom() override = default;
+
StringRef name() const override {
return _name;
}
@@ -1458,6 +1467,8 @@ public:
_name = tmp.copy(file.allocator());
}
+ ~ArmToThumbShimAtom() override = default;
+
StringRef name() const override {
return _name;
}
diff --git a/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp b/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp
index 778f6f4add74..a61f6aac05e1 100644
--- a/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp
+++ b/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp
@@ -53,6 +53,9 @@ public:
case delta32ToGOT:
canBypassGOT = false;
return true;
+ case unwindCIEToPersonalityFunction:
+ canBypassGOT = false;
+ return true;
case imageOffsetGot:
canBypassGOT = false;
return true;
@@ -108,6 +111,10 @@ public:
return imageOffsetGot;
}
+ Reference::KindValue unwindRefToPersonalityFunctionKind() override {
+ return unwindCIEToPersonalityFunction;
+ }
+
Reference::KindValue unwindRefToCIEKind() override {
return negDelta32;
}
@@ -120,20 +127,24 @@ public:
return unwindInfoToEhFrame;
}
+ Reference::KindValue pointerKind() override {
+ return pointer64;
+ }
+
uint32_t dwarfCompactUnwindType() override {
return 0x03000000;
}
- std::error_code getReferenceInfo(const normalized::Relocation &reloc,
- const DefinedAtom *inAtom,
- uint32_t offsetInAtom,
- uint64_t fixupAddress, bool isBig,
- FindAtomBySectionAndAddress atomFromAddress,
- FindAtomBySymbolIndex atomFromSymbolIndex,
- Reference::KindValue *kind,
- const lld::Atom **target,
- Reference::Addend *addend) override;
- std::error_code
+ llvm::Error getReferenceInfo(const normalized::Relocation &reloc,
+ const DefinedAtom *inAtom,
+ uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool isBig,
+ FindAtomBySectionAndAddress atomFromAddress,
+ FindAtomBySymbolIndex atomFromSymbolIndex,
+ Reference::KindValue *kind,
+ const lld::Atom **target,
+ Reference::Addend *addend) override;
+ llvm::Error
getPairReferenceInfo(const normalized::Relocation &reloc1,
const normalized::Relocation &reloc2,
const DefinedAtom *inAtom,
@@ -153,7 +164,7 @@ public:
FindAddressForAtom findAddress,
FindAddressForAtom findSectionAddress,
uint64_t imageBaseAddress,
- uint8_t *atomContentBuffer) override;
+ llvm::MutableArrayRef<uint8_t> atomContentBuffer) override;
void appendSectionRelocations(const DefinedAtom &atom,
uint64_t atomSectionOffset,
@@ -197,6 +208,9 @@ private:
imageOffset, /// Location contains offset of atom in final image
imageOffsetGot, /// Location contains offset of GOT entry for atom in
/// final image (typically personality function).
+ unwindCIEToPersonalityFunction, /// Nearly delta32ToGOT, but cannot be
+ /// rematerialized in relocatable object
+ /// (yay for implicit contracts!).
unwindFDEToFunction, /// Nearly delta64, but cannot be rematerialized in
/// relocatable object (yay for implicit contracts!).
unwindInfoToEhFrame, /// Fix low 24 bits of compact unwind encoding to
@@ -244,6 +258,7 @@ const Registry::KindStrings ArchHandler_arm64::_sKindStrings[] = {
LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
LLD_KIND_STRING_ENTRY(imageOffset),
LLD_KIND_STRING_ENTRY(imageOffsetGot),
+ LLD_KIND_STRING_ENTRY(unwindCIEToPersonalityFunction),
LLD_KIND_STRING_ENTRY(unwindFDEToFunction),
LLD_KIND_STRING_ENTRY(unwindInfoToEhFrame),
@@ -279,8 +294,13 @@ const ArchHandler::StubInfo ArchHandler_arm64::_sStubInfo = {
{ Reference::KindArch::AArch64, lazyImmediateLocation, 8, 0 },
{ Reference::KindArch::AArch64, branch26, 4, 0 },
+ // Stub helper image cache content type
+ DefinedAtom::typeGOT,
+
// Stub Helper-Common size and code
24,
+ // Stub helper alignment
+ 2,
{ 0x11, 0x00, 0x00, 0x90, // ADRP X17, dyld_ImageLoaderCache@page
0x31, 0x02, 0x00, 0x91, // ADD X17, X17, dyld_ImageLoaderCache@pageoff
0xF0, 0x47, 0xBF, 0xA9, // STP X16/X17, [SP, #-16]!
@@ -355,7 +375,7 @@ uint32_t ArchHandler_arm64::setImm12(uint32_t instruction, uint32_t offset) {
return (instruction & 0xFFC003FF) | imm12;
}
-std::error_code ArchHandler_arm64::getReferenceInfo(
+llvm::Error ArchHandler_arm64::getReferenceInfo(
const Relocation &reloc, const DefinedAtom *inAtom, uint32_t offsetInAtom,
uint64_t fixupAddress, bool isBig,
FindAtomBySectionAndAddress atomFromAddress,
@@ -369,56 +389,56 @@ std::error_code ArchHandler_arm64::getReferenceInfo(
if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = 0;
- return std::error_code();
+ return llvm::Error();
case ARM64_RELOC_PAGE21 | rPcRel | rExtern | rLength4:
// ex: adrp x1, _foo@PAGE
*kind = page21;
if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = 0;
- return std::error_code();
+ return llvm::Error();
case ARM64_RELOC_PAGEOFF12 | rExtern | rLength4:
// ex: ldr x0, [x1, _foo@PAGEOFF]
*kind = offset12KindFromInstruction(*(const little32_t *)fixupContent);
if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = 0;
- return std::error_code();
+ return llvm::Error();
case ARM64_RELOC_GOT_LOAD_PAGE21 | rPcRel | rExtern | rLength4:
// ex: adrp x1, _foo@GOTPAGE
*kind = gotPage21;
if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = 0;
- return std::error_code();
+ return llvm::Error();
case ARM64_RELOC_GOT_LOAD_PAGEOFF12 | rExtern | rLength4:
// ex: ldr x0, [x1, _foo@GOTPAGEOFF]
*kind = gotOffset12;
if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = 0;
- return std::error_code();
+ return llvm::Error();
case ARM64_RELOC_TLVP_LOAD_PAGE21 | rPcRel | rExtern | rLength4:
// ex: adrp x1, _foo@TLVPAGE
*kind = tlvPage21;
if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = 0;
- return std::error_code();
+ return llvm::Error();
case ARM64_RELOC_TLVP_LOAD_PAGEOFF12 | rExtern | rLength4:
// ex: ldr x0, [x1, _foo@TLVPAGEOFF]
*kind = tlvOffset12;
if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = 0;
- return std::error_code();
+ return llvm::Error();
case ARM64_RELOC_UNSIGNED | rExtern | rLength8:
// ex: .quad _foo + N
*kind = pointer64;
if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = *(const little64_t *)fixupContent;
- return std::error_code();
+ return llvm::Error();
case ARM64_RELOC_UNSIGNED | rLength8:
// ex: .quad Lfoo + N
*kind = pointer64;
@@ -430,27 +450,33 @@ std::error_code ArchHandler_arm64::getReferenceInfo(
if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = 0;
- return std::error_code();
+ return llvm::Error();
case ARM64_RELOC_POINTER_TO_GOT | rPcRel | rExtern | rLength4:
// ex: .long _foo@GOT - .
- *kind = delta32ToGOT;
+
+ // If we are in an .eh_frame section, then the kind of the relocation should
+ // not be delta32ToGOT. It may instead be unwindCIEToPersonalityFunction.
+ if (inAtom->contentType() == DefinedAtom::typeCFI)
+ *kind = unwindCIEToPersonalityFunction;
+ else
+ *kind = delta32ToGOT;
+
if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = 0;
- return std::error_code();
+ return llvm::Error();
default:
- return make_dynamic_error_code("unsupported arm64 relocation type");
+ return llvm::make_error<GenericError>("unsupported arm64 relocation type");
}
}
-std::error_code ArchHandler_arm64::getPairReferenceInfo(
+llvm::Error ArchHandler_arm64::getPairReferenceInfo(
const normalized::Relocation &reloc1, const normalized::Relocation &reloc2,
const DefinedAtom *inAtom, uint32_t offsetInAtom, uint64_t fixupAddress,
bool swap, bool scatterable, FindAtomBySectionAndAddress atomFromAddress,
FindAtomBySymbolIndex atomFromSymbolIndex, Reference::KindValue *kind,
const lld::Atom **target, Reference::Addend *addend) {
const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
- const uint32_t *cont32 = reinterpret_cast<const uint32_t *>(fixupContent);
switch (relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
case ((ARM64_RELOC_ADDEND | rLength4) << 16 |
ARM64_RELOC_BRANCH26 | rPcRel | rExtern | rLength4):
@@ -459,7 +485,7 @@ std::error_code ArchHandler_arm64::getPairReferenceInfo(
if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
return ec;
*addend = reloc1.symbol;
- return std::error_code();
+ return llvm::Error();
case ((ARM64_RELOC_ADDEND | rLength4) << 16 |
ARM64_RELOC_PAGE21 | rPcRel | rExtern | rLength4):
// ex: adrp x1, _foo@PAGE
@@ -467,26 +493,36 @@ std::error_code ArchHandler_arm64::getPairReferenceInfo(
if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
return ec;
*addend = reloc1.symbol;
- return std::error_code();
+ return llvm::Error();
case ((ARM64_RELOC_ADDEND | rLength4) << 16 |
- ARM64_RELOC_PAGEOFF12 | rExtern | rLength4):
+ ARM64_RELOC_PAGEOFF12 | rExtern | rLength4): {
// ex: ldr w0, [x1, _foo@PAGEOFF]
- *kind = offset12KindFromInstruction(*cont32);
+ uint32_t cont32 = (int32_t)*(const little32_t *)fixupContent;
+ *kind = offset12KindFromInstruction(cont32);
if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
return ec;
*addend = reloc1.symbol;
- return std::error_code();
+ return llvm::Error();
+ }
case ((ARM64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 |
ARM64_RELOC_UNSIGNED | rExtern | rLength8):
// ex: .quad _foo - .
- *kind = delta64;
if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
return ec;
+
+ // If we are in an .eh_frame section, then the kind of the relocation should
+ // not be delta64. It may instead be unwindFDEToFunction.
+ if (inAtom->contentType() == DefinedAtom::typeCFI)
+ *kind = unwindFDEToFunction;
+ else
+ *kind = delta64;
+
// The offsets of the 2 relocations must match
if (reloc1.offset != reloc2.offset)
- return make_dynamic_error_code("paired relocs must have the same offset");
+ return llvm::make_error<GenericError>(
+ "paired relocs must have the same offset");
*addend = (int64_t)*(const little64_t *)fixupContent + offsetInAtom;
- return std::error_code();
+ return llvm::Error();
case ((ARM64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 |
ARM64_RELOC_UNSIGNED | rExtern | rLength4):
// ex: .quad _foo - .
@@ -494,18 +530,19 @@ std::error_code ArchHandler_arm64::getPairReferenceInfo(
if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
return ec;
*addend = (int32_t)*(const little32_t *)fixupContent + offsetInAtom;
- return std::error_code();
+ return llvm::Error();
default:
- return make_dynamic_error_code("unsupported arm64 relocation pair");
+ return llvm::make_error<GenericError>("unsupported arm64 relocation pair");
}
}
void ArchHandler_arm64::generateAtomContent(
const DefinedAtom &atom, bool relocatable, FindAddressForAtom findAddress,
FindAddressForAtom findSectionAddress, uint64_t imageBaseAddress,
- uint8_t *atomContentBuffer) {
+ llvm::MutableArrayRef<uint8_t> atomContentBuffer) {
// Copy raw bytes.
- memcpy(atomContentBuffer, atom.rawContent().data(), atom.size());
+ std::copy(atom.rawContent().begin(), atom.rawContent().end(),
+ atomContentBuffer.begin());
// Apply fix-ups.
#ifndef NDEBUG
if (atom.begin() != atom.end()) {
@@ -620,6 +657,7 @@ void ArchHandler_arm64::applyFixupFinal(const Reference &ref, uint8_t *loc,
return;
case delta32:
case delta32ToGOT:
+ case unwindCIEToPersonalityFunction:
*loc32 = (targetAddress - fixupAddress) + ref.addend();
return;
case negDelta32:
@@ -710,6 +748,13 @@ void ArchHandler_arm64::applyFixupRelocatable(const Reference &ref,
case delta32ToGOT:
*loc32 = inAtomAddress - fixupAddress;
return;
+ case unwindCIEToPersonalityFunction:
+ // We don't emit unwindCIEToPersonalityFunction in -r mode as they are
+ // implicitly generated from the data in the __eh_frame section. So here we
+ // need to use the targetAddress so that we can generate the full relocation
+ // when we parse again later.
+ *loc32 = targetAddress - fixupAddress;
+ return;
case addOffset12:
llvm_unreachable("lazy reference kind implies GOT pass was run");
case lazyPointer:
@@ -832,6 +877,7 @@ void ArchHandler_arm64::appendSectionRelocations(
case imageOffset:
case imageOffsetGot:
llvm_unreachable("deltas from mach_header can only be in final images");
+ case unwindCIEToPersonalityFunction:
case unwindFDEToFunction:
case unwindInfoToEhFrame:
case negDelta32:
diff --git a/lib/ReaderWriter/MachO/ArchHandler_x86.cpp b/lib/ReaderWriter/MachO/ArchHandler_x86.cpp
index 7aac2584d078..15f1f793b5d7 100644
--- a/lib/ReaderWriter/MachO/ArchHandler_x86.cpp
+++ b/lib/ReaderWriter/MachO/ArchHandler_x86.cpp
@@ -58,6 +58,10 @@ public:
return invalid;
}
+ Reference::KindValue unwindRefToPersonalityFunctionKind() override {
+ return invalid;
+ }
+
Reference::KindValue unwindRefToCIEKind() override {
return negDelta32;
}
@@ -70,20 +74,24 @@ public:
return invalid;
}
+ Reference::KindValue pointerKind() override {
+ return invalid;
+ }
+
uint32_t dwarfCompactUnwindType() override {
return 0x04000000U;
}
- std::error_code getReferenceInfo(const normalized::Relocation &reloc,
- const DefinedAtom *inAtom,
- uint32_t offsetInAtom,
- uint64_t fixupAddress, bool swap,
- FindAtomBySectionAndAddress atomFromAddress,
- FindAtomBySymbolIndex atomFromSymbolIndex,
- Reference::KindValue *kind,
- const lld::Atom **target,
- Reference::Addend *addend) override;
- std::error_code
+ llvm::Error getReferenceInfo(const normalized::Relocation &reloc,
+ const DefinedAtom *inAtom,
+ uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool swap,
+ FindAtomBySectionAndAddress atomFromAddress,
+ FindAtomBySymbolIndex atomFromSymbolIndex,
+ Reference::KindValue *kind,
+ const lld::Atom **target,
+ Reference::Addend *addend) override;
+ llvm::Error
getPairReferenceInfo(const normalized::Relocation &reloc1,
const normalized::Relocation &reloc2,
const DefinedAtom *inAtom,
@@ -99,7 +107,7 @@ public:
FindAddressForAtom findAddress,
FindAddressForAtom findSectionAddress,
uint64_t imageBaseAddress,
- uint8_t *atomContentBuffer) override;
+ llvm::MutableArrayRef<uint8_t> atomContentBuffer) override;
void appendSectionRelocations(const DefinedAtom &atom,
uint64_t atomSectionOffset,
@@ -212,8 +220,13 @@ const ArchHandler::StubInfo ArchHandler_x86::_sStubInfo = {
{ Reference::KindArch::x86, lazyImmediateLocation, 1, 0 },
{ Reference::KindArch::x86, branch32, 6, 0 },
+ // Stub helper image cache content type
+ DefinedAtom::typeNonLazyPointer,
+
// Stub Helper-Common size and code
12,
+ // Stub helper alignment
+ 2,
{ 0x68, 0x00, 0x00, 0x00, 0x00, // pushl $dyld_ImageLoaderCache
0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *_fast_lazy_bind
0x90 }, // nop
@@ -238,7 +251,7 @@ bool ArchHandler_x86::isPairedReloc(const Relocation &reloc) {
(reloc.type == GENERIC_RELOC_SECTDIFF);
}
-std::error_code
+llvm::Error
ArchHandler_x86::getReferenceInfo(const Relocation &reloc,
const DefinedAtom *inAtom,
uint32_t offsetInAtom,
@@ -248,7 +261,6 @@ ArchHandler_x86::getReferenceInfo(const Relocation &reloc,
Reference::KindValue *kind,
const lld::Atom **target,
Reference::Addend *addend) {
- typedef std::error_code E;
DefinedAtom::ContentPermissions perms;
const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
uint64_t targetAddress;
@@ -256,7 +268,7 @@ ArchHandler_x86::getReferenceInfo(const Relocation &reloc,
case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength4:
// ex: call _foo (and _foo undefined)
*kind = branch32;
- if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = fixupAddress + 4 + (int32_t)*(const little32_t *)fixupContent;
break;
@@ -272,14 +284,14 @@ ArchHandler_x86::getReferenceInfo(const Relocation &reloc,
*kind = branch32;
targetAddress =
fixupAddress + 4 + (int32_t) * (const little32_t *)fixupContent;
- if (E ec = atomFromAddress(0, reloc.value, target, addend))
+ if (auto ec = atomFromAddress(0, reloc.value, target, addend))
return ec;
*addend = targetAddress - reloc.value;
break;
case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength2:
// ex: callw _foo (and _foo undefined)
*kind = branch16;
- if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = fixupAddress + 2 + (int16_t)*(const little16_t *)fixupContent;
break;
@@ -295,7 +307,7 @@ ArchHandler_x86::getReferenceInfo(const Relocation &reloc,
*kind = branch16;
targetAddress =
fixupAddress + 2 + (int16_t) * (const little16_t *)fixupContent;
- if (E ec = atomFromAddress(0, reloc.value, target, addend))
+ if (auto ec = atomFromAddress(0, reloc.value, target, addend))
return ec;
*addend = targetAddress - reloc.value;
break;
@@ -306,7 +318,7 @@ ArchHandler_x86::getReferenceInfo(const Relocation &reloc,
*kind =
((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
: pointer32;
- if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = *(const ulittle32_t *)fixupContent;
break;
@@ -326,17 +338,17 @@ ArchHandler_x86::getReferenceInfo(const Relocation &reloc,
*kind =
((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
: pointer32;
- if (E ec = atomFromAddress(0, reloc.value, target, addend))
+ if (auto ec = atomFromAddress(0, reloc.value, target, addend))
return ec;
*addend = *(const ulittle32_t *)fixupContent - reloc.value;
break;
default:
- return make_dynamic_error_code("unsupported i386 relocation type");
+ return llvm::make_error<GenericError>("unsupported i386 relocation type");
}
- return std::error_code();
+ return llvm::Error();
}
-std::error_code
+llvm::Error
ArchHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1,
const normalized::Relocation &reloc2,
const DefinedAtom *inAtom,
@@ -349,7 +361,6 @@ ArchHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1,
const lld::Atom **target,
Reference::Addend *addend) {
const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
- std::error_code ec;
DefinedAtom::ContentPermissions perms = inAtom->permissions();
uint32_t fromAddress;
uint32_t toAddress;
@@ -365,15 +376,13 @@ ArchHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1,
toAddress = reloc1.value;
fromAddress = reloc2.value;
value = *(const little32_t *)fixupContent;
- ec = atomFromAddr(0, toAddress, target, &offsetInTo);
- if (ec)
+ if (auto ec = atomFromAddr(0, toAddress, target, &offsetInTo))
return ec;
- ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom);
- if (ec)
+ if (auto ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom))
return ec;
if (fromTarget != inAtom) {
if (*target != inAtom)
- return make_dynamic_error_code(
+ return llvm::make_error<GenericError>(
"SECTDIFF relocation where neither target is in atom");
*kind = negDelta32;
*addend = toAddress - value - fromAddress;
@@ -394,10 +403,10 @@ ArchHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1,
*addend = fromAddress + value - toAddress;
}
}
- return std::error_code();
+ return llvm::Error();
break;
default:
- return make_dynamic_error_code("unsupported i386 relocation type");
+ return llvm::make_error<GenericError>("unsupported i386 relocation type");
}
}
@@ -406,9 +415,10 @@ void ArchHandler_x86::generateAtomContent(const DefinedAtom &atom,
FindAddressForAtom findAddress,
FindAddressForAtom findSectionAddress,
uint64_t imageBaseAddress,
- uint8_t *atomContentBuffer) {
+ llvm::MutableArrayRef<uint8_t> atomContentBuffer) {
// Copy raw bytes.
- memcpy(atomContentBuffer, atom.rawContent().data(), atom.size());
+ std::copy(atom.rawContent().begin(), atom.rawContent().end(),
+ atomContentBuffer.begin());
// Apply fix-ups.
for (const Reference *ref : atom) {
uint32_t offset = ref->offsetInAtom();
diff --git a/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp b/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
index 8b4d1cf38cba..c36982a77b13 100644
--- a/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
+++ b/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
@@ -104,6 +104,10 @@ public:
return imageOffsetGot;
}
+ Reference::KindValue unwindRefToPersonalityFunctionKind() override {
+ return ripRel32Got;
+ }
+
Reference::KindValue unwindRefToCIEKind() override {
return negDelta32;
}
@@ -116,6 +120,10 @@ public:
return unwindInfoToEhFrame;
}
+ Reference::KindValue pointerKind() override {
+ return pointer64;
+ }
+
uint32_t dwarfCompactUnwindType() override {
return 0x04000000U;
}
@@ -130,16 +138,16 @@ public:
bool isPointer(const Reference &) override;
bool isPairedReloc(const normalized::Relocation &) override;
- std::error_code getReferenceInfo(const normalized::Relocation &reloc,
- const DefinedAtom *inAtom,
- uint32_t offsetInAtom,
- uint64_t fixupAddress, bool swap,
- FindAtomBySectionAndAddress atomFromAddress,
- FindAtomBySymbolIndex atomFromSymbolIndex,
- Reference::KindValue *kind,
- const lld::Atom **target,
- Reference::Addend *addend) override;
- std::error_code
+ llvm::Error getReferenceInfo(const normalized::Relocation &reloc,
+ const DefinedAtom *inAtom,
+ uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool swap,
+ FindAtomBySectionAndAddress atomFromAddress,
+ FindAtomBySymbolIndex atomFromSymbolIndex,
+ Reference::KindValue *kind,
+ const lld::Atom **target,
+ Reference::Addend *addend) override;
+ llvm::Error
getPairReferenceInfo(const normalized::Relocation &reloc1,
const normalized::Relocation &reloc2,
const DefinedAtom *inAtom,
@@ -159,7 +167,7 @@ public:
FindAddressForAtom findAddress,
FindAddressForAtom findSectionAddress,
uint64_t imageBase,
- uint8_t *atomContentBuffer) override;
+ llvm::MutableArrayRef<uint8_t> atomContentBuffer) override;
void appendSectionRelocations(const DefinedAtom &atom,
uint64_t atomSectionOffset,
@@ -195,6 +203,7 @@ private:
delta32, /// ex: .long _foo - .
delta64Anon, /// ex: .quad L1 - .
delta32Anon, /// ex: .long L1 - .
+ negDelta64, /// ex: .quad . - _foo
negDelta32, /// ex: .long . - _foo
// Kinds introduced by Passes:
@@ -216,8 +225,6 @@ private:
};
Reference::KindValue kindFromReloc(const normalized::Relocation &reloc);
- Reference::KindValue kindFromRelocPair(const normalized::Relocation &reloc1,
- const normalized::Relocation &reloc2);
void applyFixupFinal(const Reference &ref, uint8_t *location,
uint64_t fixupAddress, uint64_t targetAddress,
@@ -246,6 +253,7 @@ const Registry::KindStrings ArchHandler_x86_64::_sKindStrings[] = {
LLD_KIND_STRING_ENTRY(pointer64), LLD_KIND_STRING_ENTRY(pointer64Anon),
LLD_KIND_STRING_ENTRY(delta32), LLD_KIND_STRING_ENTRY(delta64),
LLD_KIND_STRING_ENTRY(delta32Anon), LLD_KIND_STRING_ENTRY(delta64Anon),
+ LLD_KIND_STRING_ENTRY(negDelta64),
LLD_KIND_STRING_ENTRY(negDelta32),
LLD_KIND_STRING_ENTRY(imageOffset), LLD_KIND_STRING_ENTRY(imageOffsetGot),
LLD_KIND_STRING_ENTRY(unwindFDEToFunction),
@@ -280,8 +288,13 @@ const ArchHandler::StubInfo ArchHandler_x86_64::_sStubInfo = {
{ Reference::KindArch::x86_64, lazyImmediateLocation, 1, 0 },
{ Reference::KindArch::x86_64, branch32, 6, 0 },
+ // Stub helper image cache content type
+ DefinedAtom::typeNonLazyPointer,
+
// Stub Helper-Common size and code
16,
+ // Stub helper alignment
+ 2,
{ 0x4C, 0x8D, 0x1D, 0x00, 0x00, 0x00, 0x00, // leaq cache(%rip),%r11
0x41, 0x53, // push %r11
0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *binder(%rip)
@@ -348,7 +361,7 @@ ArchHandler_x86_64::kindFromReloc(const Relocation &reloc) {
}
}
-std::error_code
+llvm::Error
ArchHandler_x86_64::getReferenceInfo(const Relocation &reloc,
const DefinedAtom *inAtom,
uint32_t offsetInAtom,
@@ -358,34 +371,33 @@ ArchHandler_x86_64::getReferenceInfo(const Relocation &reloc,
Reference::KindValue *kind,
const lld::Atom **target,
Reference::Addend *addend) {
- typedef std::error_code E;
*kind = kindFromReloc(reloc);
if (*kind == invalid)
- return make_dynamic_error_code("unknown type");
+ return llvm::make_error<GenericError>("unknown type");
const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
uint64_t targetAddress;
switch (*kind) {
case branch32:
case ripRel32:
- if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = *(const little32_t *)fixupContent;
- return std::error_code();
+ return llvm::Error();
case ripRel32Minus1:
- if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = (int32_t)*(const little32_t *)fixupContent + 1;
- return std::error_code();
+ return llvm::Error();
case ripRel32Minus2:
- if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = (int32_t)*(const little32_t *)fixupContent + 2;
- return std::error_code();
+ return llvm::Error();
case ripRel32Minus4:
- if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = (int32_t)*(const little32_t *)fixupContent + 4;
- return std::error_code();
+ return llvm::Error();
case ripRel32Anon:
targetAddress = fixupAddress + 4 + *(const little32_t *)fixupContent;
return atomFromAddress(reloc.symbol, targetAddress, target, addend);
@@ -401,13 +413,13 @@ ArchHandler_x86_64::getReferenceInfo(const Relocation &reloc,
case ripRel32GotLoad:
case ripRel32Got:
case ripRel32Tlv:
- if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = *(const little32_t *)fixupContent;
- return std::error_code();
+ return llvm::Error();
case tlvInitSectionOffset:
case pointer64:
- if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
// If this is the 3rd pointer of a tlv-thunk (i.e. the pointer to the TLV's
// initial value) we need to handle it specially.
@@ -417,7 +429,7 @@ ArchHandler_x86_64::getReferenceInfo(const Relocation &reloc,
assert(*addend == 0 && "TLV-init has non-zero addend?");
} else
*addend = *(const little64_t *)fixupContent;
- return std::error_code();
+ return llvm::Error();
case pointer64Anon:
targetAddress = *(const little64_t *)fixupContent;
return atomFromAddress(reloc.symbol, targetAddress, target, addend);
@@ -426,28 +438,7 @@ ArchHandler_x86_64::getReferenceInfo(const Relocation &reloc,
}
}
-Reference::KindValue
-ArchHandler_x86_64::kindFromRelocPair(const normalized::Relocation &reloc1,
- const normalized::Relocation &reloc2) {
- switch(relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
- case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 |
- X86_64_RELOC_UNSIGNED | rExtern | rLength8):
- return delta64;
- case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 |
- X86_64_RELOC_UNSIGNED | rExtern | rLength4):
- return delta32;
- case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 |
- X86_64_RELOC_UNSIGNED | rLength8):
- return delta64Anon;
- case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 |
- X86_64_RELOC_UNSIGNED | rLength4):
- return delta32Anon;
- default:
- llvm_unreachable("bad reloc pairs");
- }
-}
-
-std::error_code
+llvm::Error
ArchHandler_x86_64::getPairReferenceInfo(const normalized::Relocation &reloc1,
const normalized::Relocation &reloc2,
const DefinedAtom *inAtom,
@@ -459,45 +450,71 @@ ArchHandler_x86_64::getPairReferenceInfo(const normalized::Relocation &reloc1,
Reference::KindValue *kind,
const lld::Atom **target,
Reference::Addend *addend) {
- *kind = kindFromRelocPair(reloc1, reloc2);
- if (*kind == invalid)
- return make_dynamic_error_code("unknown pair");
const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
- typedef std::error_code E;
uint64_t targetAddress;
const lld::Atom *fromTarget;
- if (E ec = atomFromSymbolIndex(reloc1.symbol, &fromTarget))
+ if (auto ec = atomFromSymbolIndex(reloc1.symbol, &fromTarget))
return ec;
- if (fromTarget != inAtom)
- return make_dynamic_error_code("pointer diff not in base atom");
- switch (*kind) {
- case delta64:
- if (E ec = atomFromSymbolIndex(reloc2.symbol, target))
+
+ switch(relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
+ case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 |
+ X86_64_RELOC_UNSIGNED | rExtern | rLength8): {
+ if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
return ec;
- *addend = (int64_t)*(const little64_t *)fixupContent + offsetInAtom;
- return std::error_code();
- case delta32:
- if (E ec = atomFromSymbolIndex(reloc2.symbol, target))
+ uint64_t encodedAddend = (int64_t)*(const little64_t *)fixupContent;
+ if (inAtom == fromTarget) {
+ *kind = delta64;
+ *addend = encodedAddend + offsetInAtom;
+ } else if (inAtom == *target) {
+ *kind = negDelta64;
+ *addend = encodedAddend - offsetInAtom;
+ *target = fromTarget;
+ } else
+ return llvm::make_error<GenericError>("Invalid pointer diff");
+ return llvm::Error();
+ }
+ case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 |
+ X86_64_RELOC_UNSIGNED | rExtern | rLength4): {
+ if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
return ec;
- *addend = (int32_t)*(const little32_t *)fixupContent + offsetInAtom;
- return std::error_code();
- case delta64Anon:
+ uint32_t encodedAddend = (int32_t)*(const little32_t *)fixupContent;
+ if (inAtom == fromTarget) {
+ *kind = delta32;
+ *addend = encodedAddend + offsetInAtom;
+ } else if (inAtom == *target) {
+ *kind = negDelta32;
+ *addend = encodedAddend - offsetInAtom;
+ *target = fromTarget;
+ } else
+ return llvm::make_error<GenericError>("Invalid pointer diff");
+ return llvm::Error();
+ }
+ case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 |
+ X86_64_RELOC_UNSIGNED | rLength8):
+ if (fromTarget != inAtom)
+ return llvm::make_error<GenericError>("pointer diff not in base atom");
+ *kind = delta64Anon;
targetAddress = offsetInAtom + (int64_t)*(const little64_t *)fixupContent;
return atomFromAddress(reloc2.symbol, targetAddress, target, addend);
- case delta32Anon:
+ case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 |
+ X86_64_RELOC_UNSIGNED | rLength4):
+ if (fromTarget != inAtom)
+ return llvm::make_error<GenericError>("pointer diff not in base atom");
+ *kind = delta32Anon;
targetAddress = offsetInAtom + (int32_t)*(const little32_t *)fixupContent;
return atomFromAddress(reloc2.symbol, targetAddress, target, addend);
default:
- llvm_unreachable("bad reloc pair kind");
+ return llvm::make_error<GenericError>("unknown pair");
}
}
void ArchHandler_x86_64::generateAtomContent(
const DefinedAtom &atom, bool relocatable, FindAddressForAtom findAddress,
FindAddressForAtom findSectionAddress, uint64_t imageBaseAddress,
- uint8_t *atomContentBuffer) {
+ llvm::MutableArrayRef<uint8_t> atomContentBuffer) {
// Copy raw bytes.
- memcpy(atomContentBuffer, atom.rawContent().data(), atom.size());
+ std::copy(atom.rawContent().begin(), atom.rawContent().end(),
+ atomContentBuffer.begin());
// Apply fix-ups.
for (const Reference *ref : atom) {
uint32_t offset = ref->offsetInAtom();
@@ -571,6 +588,9 @@ void ArchHandler_x86_64::applyFixupFinal(
loc[-2] = 0x8D;
*loc32 = targetAddress - (fixupAddress + 4) + ref.addend();
return;
+ case negDelta64:
+ *loc64 = fixupAddress - targetAddress + ref.addend();
+ return;
case negDelta32:
*loc32 = fixupAddress - targetAddress + ref.addend();
return;
@@ -675,8 +695,11 @@ void ArchHandler_x86_64::applyFixupRelocatable(const Reference &ref,
// Then we want to encode the value (Ltarget + addend) - (LFixup - _base)
*loc64 = (targetAddress + ref.addend()) - (fixupAddress - inAtomAddress);
return;
+ case negDelta64:
+ *loc64 = ref.addend() + fixupAddress - inAtomAddress;
+ return;
case negDelta32:
- *loc32 = fixupAddress - targetAddress + ref.addend();
+ *loc32 = ref.addend() + fixupAddress - inAtomAddress;
return;
case ripRel32GotLoadNowLea:
llvm_unreachable("ripRel32GotLoadNowLea implies GOT pass was run");
@@ -796,7 +819,18 @@ void ArchHandler_x86_64::appendSectionRelocations(
return;
case unwindFDEToFunction:
case unwindInfoToEhFrame:
+ return;
case negDelta32:
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_SUBTRACTOR | rExtern | rLength4 );
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
+ X86_64_RELOC_UNSIGNED | rExtern | rLength4 );
+ return;
+ case negDelta64:
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_SUBTRACTOR | rExtern | rLength8 );
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
+ X86_64_RELOC_UNSIGNED | rExtern | rLength8 );
return;
case ripRel32GotLoadNowLea:
llvm_unreachable("ripRel32GotLoadNowLea implies GOT pass was run");
diff --git a/lib/ReaderWriter/MachO/Atoms.h b/lib/ReaderWriter/MachO/Atoms.h
index 9f2e5acad99a..573efca9f6f9 100644
--- a/lib/ReaderWriter/MachO/Atoms.h
+++ b/lib/ReaderWriter/MachO/Atoms.h
@@ -1,4 +1,4 @@
-//===- lib/ReaderWriter/MachO/Atoms.h -------------------------------------===//
+//===- lib/ReaderWriter/MachO/Atoms.h ---------------------------*- C++ -*-===//
//
// The LLVM Linker
//
@@ -10,10 +10,21 @@
#ifndef LLD_READER_WRITER_MACHO_ATOMS_H
#define LLD_READER_WRITER_MACHO_ATOMS_H
+#include "lld/Core/Atom.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/SharedLibraryAtom.h"
#include "lld/Core/Simple.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include <cstdint>
+#include <string>
namespace lld {
+
+class File;
+
namespace mach_o {
+
class MachODefinedAtom : public SimpleDefinedAtom {
public:
MachODefinedAtom(const File &f, const StringRef name, Scope scope,
@@ -32,6 +43,8 @@ public:
_contentType(type), _scope(scope), _merge(mergeNo), _thumb(false),
_noDeadStrip(noDeadStrip) {}
+ ~MachODefinedAtom() override = default;
+
uint64_t size() const override { return _content.size(); }
ContentType contentType() const override { return _contentType; }
@@ -61,15 +74,6 @@ public:
bool isThumb() const { return _thumb; }
- void addReference(uint32_t offsetInAtom, uint16_t relocType,
- const Atom *target, Reference::Addend addend,
- Reference::KindArch arch = Reference::KindArch::x86_64,
- Reference::KindNamespace ns
- = Reference::KindNamespace::mach_o) {
- SimpleDefinedAtom::addReference(ns, arch, relocType, offsetInAtom, target,
- addend);
- }
-
private:
const StringRef _name;
const ArrayRef<uint8_t> _content;
@@ -92,6 +96,8 @@ public:
content, align),
_sectionName(sectionName) {}
+ ~MachODefinedCustomSectionAtom() override = default;
+
SectionChoice sectionChoice() const override {
return DefinedAtom::sectionCustomRequired;
}
@@ -110,6 +116,8 @@ public:
: SimpleDefinedAtom(f), _name(name), _scope(scope), _size(size),
_align(align) {}
+ ~MachOTentativeDefAtom() override = default;
+
uint64_t size() const override { return _size; }
Merge merge() const override { return DefinedAtom::mergeAsTentative; }
@@ -167,7 +175,7 @@ private:
StringRef _dylibInstallName;
};
-} // namespace mach_o
-} // namespace lld
+} // end namespace mach_o
+} // end namespace lld
#endif // LLD_READER_WRITER_MACHO_ATOMS_H
diff --git a/lib/ReaderWriter/MachO/CMakeLists.txt b/lib/ReaderWriter/MachO/CMakeLists.txt
index a389ca51ddfd..70f451c997b3 100644
--- a/lib/ReaderWriter/MachO/CMakeLists.txt
+++ b/lib/ReaderWriter/MachO/CMakeLists.txt
@@ -13,6 +13,7 @@ add_lld_library(lldMachO
MachONormalizedFileFromAtoms.cpp
MachONormalizedFileToAtoms.cpp
MachONormalizedFileYAML.cpp
+ ObjCPass.cpp
ShimPass.cpp
StubsPass.cpp
TLVPass.cpp
@@ -22,6 +23,7 @@ add_lld_library(lldMachO
lldYAML
LLVMObject
LLVMSupport
+ ${PTHREAD_LIB}
)
include_directories(.)
diff --git a/lib/ReaderWriter/MachO/CompactUnwindPass.cpp b/lib/ReaderWriter/MachO/CompactUnwindPass.cpp
index 4b8644a67e70..6f5ab83dbda6 100644
--- a/lib/ReaderWriter/MachO/CompactUnwindPass.cpp
+++ b/lib/ReaderWriter/MachO/CompactUnwindPass.cpp
@@ -59,7 +59,7 @@ struct CompactUnwindEntry {
};
struct UnwindInfoPage {
- std::vector<CompactUnwindEntry> entries;
+ ArrayRef<CompactUnwindEntry> entries;
};
}
@@ -88,6 +88,8 @@ public:
addSecondLevelPages(pages);
}
+ ~UnwindInfoAtom() override = default;
+
ContentType contentType() const override {
return DefinedAtom::typeProcessedUnwindInfo;
}
@@ -179,7 +181,7 @@ public:
}
// Finally, write out the final sentinel index
- CompactUnwindEntry &finalEntry = pages[pages.size() - 1].entries.back();
+ auto &finalEntry = pages[pages.size() - 1].entries.back();
addImageReference(_topLevelIndexOffset +
3 * pages.size() * sizeof(uint32_t),
finalEntry.rangeStart, finalEntry.rangeLength);
@@ -273,11 +275,13 @@ class CompactUnwindPass : public Pass {
public:
CompactUnwindPass(const MachOLinkingContext &context)
: _ctx(context), _archHandler(_ctx.archHandler()),
- _file("<mach-o Compact Unwind Pass>"),
- _isBig(MachOLinkingContext::isBigEndian(_ctx.arch())) {}
+ _file(*_ctx.make_file<MachOFile>("<mach-o Compact Unwind Pass>")),
+ _isBig(MachOLinkingContext::isBigEndian(_ctx.arch())) {
+ _file.setOrdinal(_ctx.getNextOrdinalAndIncrement());
+ }
private:
- std::error_code perform(SimpleFile &mergedFile) override {
+ llvm::Error perform(SimpleFile &mergedFile) override {
DEBUG(llvm::dbgs() << "MachO Compact Unwind pass\n");
std::map<const Atom *, CompactUnwindEntry> unwindLocs;
@@ -294,7 +298,7 @@ private:
// Skip rest of pass if no unwind info.
if (unwindLocs.empty() && dwarfFrames.empty())
- return std::error_code();
+ return llvm::Error();
// FIXME: if there are more than 4 personality functions then we need to
// defer to DWARF info for the ones we don't put in the list. They should
@@ -321,26 +325,23 @@ private:
// boundaries. That might be worth doing, or perhaps we could perform some
// minor balancing for expected number of lookups.
std::vector<UnwindInfoPage> pages;
- unsigned pageStart = 0;
+ auto remainingInfos = llvm::makeArrayRef(unwindInfos);
do {
pages.push_back(UnwindInfoPage());
// FIXME: we only create regular pages at the moment. These can hold up to
// 1021 entries according to the documentation.
- unsigned entriesInPage =
- std::min(1021U, (unsigned)unwindInfos.size() - pageStart);
+ unsigned entriesInPage = std::min(1021U, (unsigned)remainingInfos.size());
- std::copy(unwindInfos.begin() + pageStart,
- unwindInfos.begin() + pageStart + entriesInPage,
- std::back_inserter(pages.back().entries));
- pageStart += entriesInPage;
+ pages.back().entries = remainingInfos.slice(0, entriesInPage);
+ remainingInfos = remainingInfos.slice(entriesInPage);
DEBUG(llvm::dbgs()
<< " Page from " << pages.back().entries[0].rangeStart->name()
<< " to " << pages.back().entries.back().rangeStart->name() << " + "
<< llvm::format("0x%x", pages.back().entries.back().rangeLength)
<< " has " << entriesInPage << " entries\n");
- } while (pageStart < unwindInfos.size());
+ } while (!remainingInfos.empty());
auto *unwind = new (_file.allocator())
UnwindInfoAtom(_archHandler, _file, _isBig, personalities,
@@ -352,7 +353,7 @@ private:
return atom->contentType() == DefinedAtom::typeCompactUnwindInfo;
});
- return std::error_code();
+ return llvm::Error();
}
void collectCompactUnwindEntries(
@@ -568,7 +569,7 @@ private:
const MachOLinkingContext &_ctx;
mach_o::ArchHandler &_archHandler;
- MachOFile _file;
+ MachOFile &_file;
bool _isBig;
};
diff --git a/lib/ReaderWriter/MachO/ExecutableAtoms.h b/lib/ReaderWriter/MachO/ExecutableAtoms.h
index 2e99af903dbd..acced33b7e74 100644
--- a/lib/ReaderWriter/MachO/ExecutableAtoms.h
+++ b/lib/ReaderWriter/MachO/ExecutableAtoms.h
@@ -11,10 +11,10 @@
#define LLD_READER_WRITER_MACHO_EXECUTABLE_ATOMS_H
#include "Atoms.h"
+#include "File.h"
#include "llvm/Support/MachO.h"
-#include "lld/Core/ArchiveLibraryFile.h"
#include "lld/Core/DefinedAtom.h"
#include "lld/Core/File.h"
#include "lld/Core/LinkingContext.h"
@@ -34,7 +34,7 @@ namespace mach_o {
class CEntryFile : public SimpleFile {
public:
CEntryFile(const MachOLinkingContext &context)
- : SimpleFile("C entry"),
+ : SimpleFile("C entry", kindCEntryObject),
_undefMain(*this, context.entrySymbolName()) {
this->addAtom(_undefMain);
}
@@ -51,7 +51,7 @@ private:
class StubHelperFile : public SimpleFile {
public:
StubHelperFile(const MachOLinkingContext &context)
- : SimpleFile("stub runtime"),
+ : SimpleFile("stub runtime", kindStubHelperObject),
_undefBinder(*this, context.binderSymbolName()) {
this->addAtom(_undefBinder);
}
@@ -65,66 +65,88 @@ private:
// MachHeaderAliasFile lazily instantiates the magic symbols that mark the start
// of the mach_header for final linked images.
//
-class MachHeaderAliasFile : public ArchiveLibraryFile {
+class MachHeaderAliasFile : public SimpleFile {
public:
MachHeaderAliasFile(const MachOLinkingContext &context)
- : ArchiveLibraryFile("mach_header symbols") {
- switch (context.outputMachOType()) {
- case llvm::MachO::MH_EXECUTE:
- _machHeaderSymbolName = "__mh_execute_header";
- break;
- case llvm::MachO::MH_DYLIB:
- _machHeaderSymbolName = "__mh_dylib_header";
- break;
- case llvm::MachO::MH_BUNDLE:
- _machHeaderSymbolName = "__mh_bundle_header";
- break;
- case llvm::MachO::MH_DYLINKER:
- _machHeaderSymbolName = "__mh_dylinker_header";
- break;
- case llvm::MachO::MH_PRELOAD:
- _machHeaderSymbolName = "__mh_preload_header";
- break;
- default:
- llvm_unreachable("no mach_header symbol for file type");
- }
- }
-
- std::error_code
- parseAllMembers(std::vector<std::unique_ptr<File>> &result) override {
- return std::error_code();
- }
-
- File *find(StringRef sym, bool dataSymbolOnly) override {
- if (sym.equals("___dso_handle") || sym.equals(_machHeaderSymbolName)) {
+ : SimpleFile("mach_header symbols", kindHeaderObject) {
+ StringRef machHeaderSymbolName;
+ DefinedAtom::Scope symbolScope = DefinedAtom::scopeLinkageUnit;
+ StringRef dsoHandleName;
+ switch (context.outputMachOType()) {
+ case llvm::MachO::MH_OBJECT:
+ machHeaderSymbolName = "__mh_object_header";
+ break;
+ case llvm::MachO::MH_EXECUTE:
+ machHeaderSymbolName = "__mh_execute_header";
+ symbolScope = DefinedAtom::scopeGlobal;
+ dsoHandleName = "___dso_handle";
+ break;
+ case llvm::MachO::MH_FVMLIB:
+ llvm_unreachable("no mach_header symbol for file type");
+ case llvm::MachO::MH_CORE:
+ llvm_unreachable("no mach_header symbol for file type");
+ case llvm::MachO::MH_PRELOAD:
+ llvm_unreachable("no mach_header symbol for file type");
+ case llvm::MachO::MH_DYLIB:
+ machHeaderSymbolName = "__mh_dylib_header";
+ dsoHandleName = "___dso_handle";
+ break;
+ case llvm::MachO::MH_DYLINKER:
+ machHeaderSymbolName = "__mh_dylinker_header";
+ dsoHandleName = "___dso_handle";
+ break;
+ case llvm::MachO::MH_BUNDLE:
+ machHeaderSymbolName = "__mh_bundle_header";
+ dsoHandleName = "___dso_handle";
+ break;
+ case llvm::MachO::MH_DYLIB_STUB:
+ llvm_unreachable("no mach_header symbol for file type");
+ case llvm::MachO::MH_DSYM:
+ llvm_unreachable("no mach_header symbol for file type");
+ case llvm::MachO::MH_KEXT_BUNDLE:
+ dsoHandleName = "___dso_handle";
+ break;
+ }
+ if (!machHeaderSymbolName.empty())
_definedAtoms.push_back(new (allocator()) MachODefinedAtom(
- *this, sym, DefinedAtom::scopeLinkageUnit,
- DefinedAtom::typeMachHeader, DefinedAtom::mergeNo, false, false,
+ *this, machHeaderSymbolName, symbolScope,
+ DefinedAtom::typeMachHeader, DefinedAtom::mergeNo, false,
+ true /* noDeadStrip */,
ArrayRef<uint8_t>(), DefinedAtom::Alignment(4096)));
- return this;
- }
- return nullptr;
+
+ if (!dsoHandleName.empty())
+ _definedAtoms.push_back(new (allocator()) MachODefinedAtom(
+ *this, dsoHandleName, DefinedAtom::scopeLinkageUnit,
+ DefinedAtom::typeDSOHandle, DefinedAtom::mergeNo, false,
+ true /* noDeadStrip */,
+ ArrayRef<uint8_t>(), DefinedAtom::Alignment(1)));
}
- const AtomVector<DefinedAtom> &defined() const override {
+ const AtomRange<DefinedAtom> defined() const override {
return _definedAtoms;
}
- const AtomVector<UndefinedAtom> &undefined() const override {
+ const AtomRange<UndefinedAtom> undefined() const override {
return _noUndefinedAtoms;
}
- const AtomVector<SharedLibraryAtom> &sharedLibrary() const override {
+ const AtomRange<SharedLibraryAtom> sharedLibrary() const override {
return _noSharedLibraryAtoms;
}
- const AtomVector<AbsoluteAtom> &absolute() const override {
+ const AtomRange<AbsoluteAtom> absolute() const override {
return _noAbsoluteAtoms;
}
+ void clearAtoms() override {
+ _definedAtoms.clear();
+ _noUndefinedAtoms.clear();
+ _noSharedLibraryAtoms.clear();
+ _noAbsoluteAtoms.clear();
+ }
+
private:
mutable AtomVector<DefinedAtom> _definedAtoms;
- StringRef _machHeaderSymbolName;
};
} // namespace mach_o
diff --git a/lib/ReaderWriter/MachO/File.h b/lib/ReaderWriter/MachO/File.h
index c97dfa142b8d..64a0fcf82844 100644
--- a/lib/ReaderWriter/MachO/File.h
+++ b/lib/ReaderWriter/MachO/File.h
@@ -14,6 +14,7 @@
#include "MachONormalizedFile.h"
#include "lld/Core/SharedLibraryFile.h"
#include "lld/Core/Simple.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringMap.h"
#include <unordered_map>
@@ -25,9 +26,10 @@ using lld::mach_o::normalized::Section;
class MachOFile : public SimpleFile {
public:
MachOFile(std::unique_ptr<MemoryBuffer> mb, MachOLinkingContext *ctx)
- : SimpleFile(mb->getBufferIdentifier()), _mb(std::move(mb)), _ctx(ctx) {}
+ : SimpleFile(mb->getBufferIdentifier(), File::kindMachObject),
+ _mb(std::move(mb)), _ctx(ctx) {}
- MachOFile(StringRef path) : SimpleFile(path) {}
+ MachOFile(StringRef path) : SimpleFile(path, File::kindMachObject) {}
void addDefinedAtom(StringRef name, Atom::Scope scope,
DefinedAtom::ContentType type, DefinedAtom::Merge merge,
@@ -187,16 +189,51 @@ public:
visitor(offAndAtom.atom, offAndAtom.offset);
}
+ MachOLinkingContext::Arch arch() const { return _arch; }
+ void setArch(MachOLinkingContext::Arch arch) { _arch = arch; }
+
+ MachOLinkingContext::OS OS() const { return _os; }
+ void setOS(MachOLinkingContext::OS os) { _os = os; }
+
+ MachOLinkingContext::ObjCConstraint objcConstraint() const {
+ return _objcConstraint;
+ }
+ void setObjcConstraint(MachOLinkingContext::ObjCConstraint v) {
+ _objcConstraint = v;
+ }
+
+ uint32_t minVersion() const { return _minVersion; }
+ void setMinVersion(uint32_t v) { _minVersion = v; }
+
+ LoadCommandType minVersionLoadCommandKind() const {
+ return _minVersionLoadCommandKind;
+ }
+ void setMinVersionLoadCommandKind(LoadCommandType v) {
+ _minVersionLoadCommandKind = v;
+ }
+
+ uint32_t swiftVersion() const { return _swiftVersion; }
+ void setSwiftVersion(uint32_t v) { _swiftVersion = v; }
+
+ bool subsectionsViaSymbols() const {
+ return _flags & llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS;
+ }
+ void setFlags(normalized::FileFlags v) { _flags = v; }
+
+ /// Methods for support type inquiry through isa, cast, and dyn_cast:
+ static inline bool classof(const File *F) {
+ return F->kind() == File::kindMachObject;
+ }
+
protected:
std::error_code doParse() override {
// Convert binary file to normalized mach-o.
auto normFile = normalized::readBinary(_mb, _ctx->arch());
- if (std::error_code ec = normFile.getError())
- return ec;
+ if (auto ec = normFile.takeError())
+ return llvm::errorToErrorCode(std::move(ec));
// Convert normalized mach-o to atoms.
- if (std::error_code ec = normalized::normalizedObjectToAtoms(
- this, **normFile, false))
- return ec;
+ if (auto ec = normalized::normalizedObjectToAtoms(this, **normFile, false))
+ return llvm::errorToErrorCode(std::move(ec));
return std::error_code();
}
@@ -220,6 +257,14 @@ private:
MachOLinkingContext *_ctx;
SectionToAtoms _sectionAtoms;
NameToAtom _undefAtoms;
+ MachOLinkingContext::Arch _arch = MachOLinkingContext::arch_unknown;
+ MachOLinkingContext::OS _os = MachOLinkingContext::OS::unknown;
+ uint32_t _minVersion = 0;
+ LoadCommandType _minVersionLoadCommandKind = (LoadCommandType)0;
+ MachOLinkingContext::ObjCConstraint _objcConstraint =
+ MachOLinkingContext::objc_unknown;
+ uint32_t _swiftVersion = 0;
+ normalized::FileFlags _flags = llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS;
};
class MachODylibFile : public SharedLibraryFile {
@@ -230,7 +275,7 @@ public:
MachODylibFile(StringRef path) : SharedLibraryFile(path) {}
- const SharedLibraryAtom *exports(StringRef name, bool isData) const override {
+ OwningAtomPtr<SharedLibraryAtom> exports(StringRef name) const override {
// Pass down _installName so that if this requested symbol
// is re-exported through this dylib, the SharedLibraryAtom's loadName()
// is this dylib installName and not the implementation dylib's.
@@ -273,35 +318,39 @@ public:
std::error_code doParse() override {
// Convert binary file to normalized mach-o.
auto normFile = normalized::readBinary(_mb, _ctx->arch());
- if (std::error_code ec = normFile.getError())
- return ec;
+ if (auto ec = normFile.takeError())
+ return llvm::errorToErrorCode(std::move(ec));
// Convert normalized mach-o to atoms.
- if (std::error_code ec = normalized::normalizedDylibToAtoms(
- this, **normFile, false))
- return ec;
+ if (auto ec = normalized::normalizedDylibToAtoms(this, **normFile, false))
+ return llvm::errorToErrorCode(std::move(ec));
return std::error_code();
}
private:
- const SharedLibraryAtom *exports(StringRef name,
+ OwningAtomPtr<SharedLibraryAtom> exports(StringRef name,
StringRef installName) const {
// First, check if requested symbol is directly implemented by this dylib.
auto entry = _nameToAtom.find(name);
if (entry != _nameToAtom.end()) {
- if (!entry->second.atom) {
- // Lazily create SharedLibraryAtom.
- entry->second.atom =
- new (allocator()) MachOSharedLibraryAtom(*this, name, installName,
- entry->second.weakDef);
- }
- return entry->second.atom;
+ // FIXME: Make this map a set and only used in assert builds.
+ // Note, its safe to assert here as the resolver is the only client of
+ // this API and it only requests exports for undefined symbols.
+ // If we return from here we are no longer undefined so we should never
+ // get here again.
+ assert(!entry->second.atom && "Duplicate shared library export");
+ bool weakDef = entry->second.weakDef;
+ auto *atom = new (allocator()) MachOSharedLibraryAtom(*this, name,
+ installName,
+ weakDef);
+ entry->second.atom = atom;
+ return atom;
}
// Next, check if symbol is implemented in some re-exported dylib.
for (const ReExportedDylib &dylib : _reExportedDylibs) {
assert(dylib.file);
auto atom = dylib.file->exports(name, installName);
- if (atom)
+ if (atom.get())
return atom;
}
diff --git a/lib/ReaderWriter/MachO/FlatNamespaceFile.h b/lib/ReaderWriter/MachO/FlatNamespaceFile.h
index 6c6a9262ba2e..76d295841c9d 100644
--- a/lib/ReaderWriter/MachO/FlatNamespaceFile.h
+++ b/lib/ReaderWriter/MachO/FlatNamespaceFile.h
@@ -25,34 +25,34 @@ public:
FlatNamespaceFile(const MachOLinkingContext &context)
: SharedLibraryFile("flat namespace") { }
- const SharedLibraryAtom *exports(StringRef name,
- bool dataSymbolOnly) const override {
- _sharedLibraryAtoms.push_back(
- new (allocator()) MachOSharedLibraryAtom(*this, name, getDSOName(),
- false));
-
- return _sharedLibraryAtoms.back();
+ OwningAtomPtr<SharedLibraryAtom> exports(StringRef name) const override {
+ return new (allocator()) MachOSharedLibraryAtom(*this, name, getDSOName(),
+ false);
}
StringRef getDSOName() const override { return "flat-namespace"; }
- const AtomVector<DefinedAtom> &defined() const override {
+ const AtomRange<DefinedAtom> defined() const override {
return _noDefinedAtoms;
}
- const AtomVector<UndefinedAtom> &undefined() const override {
+ const AtomRange<UndefinedAtom> undefined() const override {
return _noUndefinedAtoms;
}
- const AtomVector<SharedLibraryAtom> &sharedLibrary() const override {
- return _sharedLibraryAtoms;
+ const AtomRange<SharedLibraryAtom> sharedLibrary() const override {
+ return _noSharedLibraryAtoms;
}
- const AtomVector<AbsoluteAtom> &absolute() const override {
+ const AtomRange<AbsoluteAtom> absolute() const override {
return _noAbsoluteAtoms;
}
-private:
- mutable AtomVector<SharedLibraryAtom> _sharedLibraryAtoms;
+ void clearAtoms() override {
+ _noDefinedAtoms.clear();
+ _noUndefinedAtoms.clear();
+ _noSharedLibraryAtoms.clear();
+ _noAbsoluteAtoms.clear();
+ }
};
} // namespace mach_o
diff --git a/lib/ReaderWriter/MachO/GOTPass.cpp b/lib/ReaderWriter/MachO/GOTPass.cpp
index a5816277dd71..6cdca0a9e055 100644
--- a/lib/ReaderWriter/MachO/GOTPass.cpp
+++ b/lib/ReaderWriter/MachO/GOTPass.cpp
@@ -54,6 +54,8 @@ public:
GOTEntryAtom(const File &file, bool is64, StringRef name)
: SimpleDefinedAtom(file), _is64(is64), _name(name) { }
+ ~GOTEntryAtom() override = default;
+
ContentType contentType() const override {
return DefinedAtom::typeGOT;
}
@@ -91,10 +93,12 @@ class GOTPass : public Pass {
public:
GOTPass(const MachOLinkingContext &context)
: _ctx(context), _archHandler(_ctx.archHandler()),
- _file("<mach-o GOT Pass>") {}
+ _file(*_ctx.make_file<MachOFile>("<mach-o GOT Pass>")) {
+ _file.setOrdinal(_ctx.getNextOrdinalAndIncrement());
+ }
private:
- std::error_code perform(SimpleFile &mergedFile) override {
+ llvm::Error perform(SimpleFile &mergedFile) override {
// Scan all references in all atoms.
for (const DefinedAtom *atom : mergedFile.defined()) {
for (const Reference *ref : *atom) {
@@ -130,7 +134,7 @@ private:
for (const GOTEntryAtom *slot : entries)
mergedFile.addAtom(*slot);
- return std::error_code();
+ return llvm::Error();
}
bool shouldReplaceTargetWithGOTAtom(const Atom *target, bool canBypassGOT) {
@@ -167,7 +171,7 @@ private:
const MachOLinkingContext &_ctx;
mach_o::ArchHandler &_archHandler;
- MachOFile _file;
+ MachOFile &_file;
llvm::DenseMap<const Atom*, const GOTEntryAtom*> _targetToGOT;
};
diff --git a/lib/ReaderWriter/MachO/LayoutPass.cpp b/lib/ReaderWriter/MachO/LayoutPass.cpp
index 0c14ee9d39ab..dd2ee8567ec9 100644
--- a/lib/ReaderWriter/MachO/LayoutPass.cpp
+++ b/lib/ReaderWriter/MachO/LayoutPass.cpp
@@ -17,6 +17,7 @@
#include "llvm/Support/Debug.h"
#include <algorithm>
#include <set>
+#include <utility>
using namespace lld;
@@ -133,7 +134,7 @@ static void checkReachabilityFromRoot(AtomToAtomT &followOnRoots,
}
}
-static void printDefinedAtoms(const SimpleFile::DefinedAtomRange &atomRange) {
+static void printDefinedAtoms(const File::AtomRange<DefinedAtom> &atomRange) {
for (const DefinedAtom *atom : atomRange) {
llvm::dbgs() << " file=" << atom->file().path()
<< ", name=" << atom->name()
@@ -146,7 +147,7 @@ static void printDefinedAtoms(const SimpleFile::DefinedAtomRange &atomRange) {
/// Verify that the followon chain is sane. Should not be called in
/// release binary.
-void LayoutPass::checkFollowonChain(SimpleFile::DefinedAtomRange &range) {
+void LayoutPass::checkFollowonChain(const File::AtomRange<DefinedAtom> &range) {
ScopedTask task(getDefaultDomain(), "LayoutPass::checkFollowonChain");
// Verify that there's no cycle in follow-on chain.
@@ -176,8 +177,8 @@ static bool compareAtomsSub(const LayoutPass::SortKey &lc,
const LayoutPass::SortKey &rc,
LayoutPass::SortOverride customSorter,
std::string &reason) {
- const DefinedAtom *left = lc._atom;
- const DefinedAtom *right = rc._atom;
+ const DefinedAtom *left = lc._atom.get();
+ const DefinedAtom *right = rc._atom.get();
if (left == right) {
reason = "same";
return false;
@@ -252,14 +253,15 @@ static bool compareAtoms(const LayoutPass::SortKey &lc,
bool result = compareAtomsSub(lc, rc, customSorter, reason);
DEBUG({
StringRef comp = result ? "<" : ">=";
- llvm::dbgs() << "Layout: '" << lc._atom->name() << "' " << comp << " '"
- << rc._atom->name() << "' (" << reason << ")\n";
+ llvm::dbgs() << "Layout: '" << lc._atom.get()->name()
+ << "' " << comp << " '"
+ << rc._atom.get()->name() << "' (" << reason << ")\n";
});
return result;
}
LayoutPass::LayoutPass(const Registry &registry, SortOverride sorter)
- : _registry(registry), _customSorter(sorter) {}
+ : _registry(registry), _customSorter(std::move(sorter)) {}
// Returns the atom immediately followed by the given atom in the followon
// chain.
@@ -329,12 +331,12 @@ void LayoutPass::setChainRoot(const DefinedAtom *targetAtom,
/// d) If the targetAtom is part of a different chain and the root of the
/// targetAtom until the targetAtom has all atoms of size 0, then chain the
/// targetAtoms and its tree to the current chain
-void LayoutPass::buildFollowOnTable(SimpleFile::DefinedAtomRange &range) {
+void LayoutPass::buildFollowOnTable(const File::AtomRange<DefinedAtom> &range) {
ScopedTask task(getDefaultDomain(), "LayoutPass::buildFollowOnTable");
// Set the initial size of the followon and the followonNext hash to the
// number of atoms that we have.
- _followOnRoots.resize(range.size());
- _followOnNexts.resize(range.size());
+ _followOnRoots.reserve(range.size());
+ _followOnNexts.reserve(range.size());
for (const DefinedAtom *ai : range) {
for (const Reference *r : *ai) {
if (r->kindNamespace() != lld::Reference::KindNamespace::all ||
@@ -397,7 +399,8 @@ void LayoutPass::buildFollowOnTable(SimpleFile::DefinedAtomRange &range) {
/// assigning ordinals to each atom, if the atoms have their ordinals
/// already assigned skip the atom and move to the next. This is the
/// main map thats used to sort the atoms while comparing two atoms together
-void LayoutPass::buildOrdinalOverrideMap(SimpleFile::DefinedAtomRange &range) {
+void
+LayoutPass::buildOrdinalOverrideMap(const File::AtomRange<DefinedAtom> &range) {
ScopedTask task(getDefaultDomain(), "LayoutPass::buildOrdinalOverrideMap");
uint64_t index = 0;
for (const DefinedAtom *ai : range) {
@@ -417,31 +420,31 @@ void LayoutPass::buildOrdinalOverrideMap(SimpleFile::DefinedAtomRange &range) {
}
std::vector<LayoutPass::SortKey>
-LayoutPass::decorate(SimpleFile::DefinedAtomRange &atomRange) const {
+LayoutPass::decorate(File::AtomRange<DefinedAtom> &atomRange) const {
std::vector<SortKey> ret;
- for (const DefinedAtom *atom : atomRange) {
- auto ri = _followOnRoots.find(atom);
- auto oi = _ordinalOverrideMap.find(atom);
- const DefinedAtom *root = (ri == _followOnRoots.end()) ? atom : ri->second;
+ for (OwningAtomPtr<DefinedAtom> &atom : atomRange.owning_ptrs()) {
+ auto ri = _followOnRoots.find(atom.get());
+ auto oi = _ordinalOverrideMap.find(atom.get());
+ const auto *root = (ri == _followOnRoots.end()) ? atom.get() : ri->second;
uint64_t override = (oi == _ordinalOverrideMap.end()) ? 0 : oi->second;
- ret.push_back(SortKey(atom, root, override));
+ ret.push_back(SortKey(std::move(atom), root, override));
}
return ret;
}
-void LayoutPass::undecorate(SimpleFile::DefinedAtomRange &atomRange,
+void LayoutPass::undecorate(File::AtomRange<DefinedAtom> &atomRange,
std::vector<SortKey> &keys) const {
size_t i = 0;
for (SortKey &k : keys)
- atomRange[i++] = k._atom;
+ atomRange[i++] = std::move(k._atom);
}
/// Perform the actual pass
-std::error_code LayoutPass::perform(SimpleFile &mergedFile) {
+llvm::Error LayoutPass::perform(SimpleFile &mergedFile) {
DEBUG(llvm::dbgs() << "******** Laying out atoms:\n");
// sort the atoms
ScopedTask task(getDefaultDomain(), "LayoutPass");
- SimpleFile::DefinedAtomRange atomRange = mergedFile.definedAtoms();
+ File::AtomRange<DefinedAtom> atomRange = mergedFile.defined();
// Build follow on tables
buildFollowOnTable(atomRange);
@@ -471,7 +474,7 @@ std::error_code LayoutPass::perform(SimpleFile &mergedFile) {
});
DEBUG(llvm::dbgs() << "******** Finished laying out atoms\n");
- return std::error_code();
+ return llvm::Error();
}
void addLayoutPass(PassManager &pm, const MachOLinkingContext &ctx) {
diff --git a/lib/ReaderWriter/MachO/LayoutPass.h b/lib/ReaderWriter/MachO/LayoutPass.h
index d6072b0ca4fb..c18777eded0a 100644
--- a/lib/ReaderWriter/MachO/LayoutPass.h
+++ b/lib/ReaderWriter/MachO/LayoutPass.h
@@ -33,11 +33,31 @@ namespace mach_o {
class LayoutPass : public Pass {
public:
struct SortKey {
- SortKey(const DefinedAtom *atom, const DefinedAtom *root, uint64_t override)
- : _atom(atom), _root(root), _override(override) {}
- const DefinedAtom *_atom;
+ SortKey(OwningAtomPtr<DefinedAtom> &&atom,
+ const DefinedAtom *root, uint64_t override)
+ : _atom(std::move(atom)), _root(root), _override(override) {}
+ OwningAtomPtr<DefinedAtom> _atom;
const DefinedAtom *_root;
uint64_t _override;
+
+ // Note, these are only here to appease MSVC bots which didn't like
+ // the same methods being implemented/deleted in OwningAtomPtr.
+ SortKey(SortKey &&key) : _atom(std::move(key._atom)), _root(key._root),
+ _override(key._override) {
+ key._root = nullptr;
+ }
+
+ SortKey &operator=(SortKey &&key) {
+ _atom = std::move(key._atom);
+ _root = key._root;
+ key._root = nullptr;
+ _override = key._override;
+ return *this;
+ }
+
+ private:
+ SortKey(const SortKey &) = delete;
+ void operator=(const SortKey&) = delete;
};
typedef std::function<bool (const DefinedAtom *left, const DefinedAtom *right,
@@ -46,17 +66,17 @@ public:
LayoutPass(const Registry &registry, SortOverride sorter);
/// Sorts atoms in mergedFile by content type then by command line order.
- std::error_code perform(SimpleFile &mergedFile) override;
+ llvm::Error perform(SimpleFile &mergedFile) override;
~LayoutPass() override = default;
private:
// Build the followOn atoms chain as specified by the kindLayoutAfter
// reference type
- void buildFollowOnTable(SimpleFile::DefinedAtomRange &range);
+ void buildFollowOnTable(const File::AtomRange<DefinedAtom> &range);
// Build a map of Atoms to ordinals for sorting the atoms
- void buildOrdinalOverrideMap(SimpleFile::DefinedAtomRange &range);
+ void buildOrdinalOverrideMap(const File::AtomRange<DefinedAtom> &range);
const Registry &_registry;
SortOverride _customSorter;
@@ -84,12 +104,13 @@ private:
void setChainRoot(const DefinedAtom *targetAtom, const DefinedAtom *root);
- std::vector<SortKey> decorate(SimpleFile::DefinedAtomRange &atomRange) const;
- void undecorate(SimpleFile::DefinedAtomRange &atomRange,
+ std::vector<SortKey> decorate(File::AtomRange<DefinedAtom> &atomRange) const;
+
+ void undecorate(File::AtomRange<DefinedAtom> &atomRange,
std::vector<SortKey> &keys) const;
// Check if the follow-on graph is a correct structure. For debugging only.
- void checkFollowonChain(SimpleFile::DefinedAtomRange &range);
+ void checkFollowonChain(const File::AtomRange<DefinedAtom> &range);
};
} // namespace mach_o
diff --git a/lib/ReaderWriter/MachO/MachOLinkingContext.cpp b/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
index 1c97c5a39d3f..05375f145d34 100644
--- a/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
+++ b/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
@@ -35,6 +35,7 @@
#endif
using lld::mach_o::ArchHandler;
+using lld::mach_o::MachOFile;
using lld::mach_o::MachODylibFile;
using namespace llvm::MachO;
@@ -75,6 +76,35 @@ bool MachOLinkingContext::parsePackedVersion(StringRef str, uint32_t &result) {
return false;
}
+bool MachOLinkingContext::parsePackedVersion(StringRef str, uint64_t &result) {
+ result = 0;
+
+ if (str.empty())
+ return false;
+
+ SmallVector<StringRef, 5> parts;
+ llvm::SplitString(str, parts, ".");
+
+ unsigned long long num;
+ if (llvm::getAsUnsignedInteger(parts[0], 10, num))
+ return true;
+ if (num > 0xFFFFFF)
+ return true;
+ result = num << 40;
+
+ unsigned Shift = 30;
+ for (StringRef str : llvm::makeArrayRef(parts).slice(1)) {
+ if (llvm::getAsUnsignedInteger(str, 10, num))
+ return true;
+ if (num > 0x3FF)
+ return true;
+ result |= (num << Shift);
+ Shift -= 10;
+ }
+
+ return false;
+}
+
MachOLinkingContext::ArchInfo MachOLinkingContext::_s_archInfos[] = {
{ "x86_64", arch_x86_64, true, CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL },
{ "i386", arch_x86, true, CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL },
@@ -139,44 +169,52 @@ bool MachOLinkingContext::sliceFromFatFile(MemoryBufferRef mb, uint32_t &offset,
return mach_o::normalized::sliceFromFatFile(mb, _arch, offset, size);
}
-MachOLinkingContext::MachOLinkingContext()
- : _outputMachOType(MH_EXECUTE), _outputMachOTypeStatic(false),
- _doNothing(false), _pie(false), _arch(arch_unknown), _os(OS::macOSX),
- _osMinVersion(0), _pageZeroSize(0), _pageSize(4096), _baseAddress(0),
- _stackSize(0), _compatibilityVersion(0), _currentVersion(0),
- _flatNamespace(false), _undefinedMode(UndefinedMode::error),
- _deadStrippableDylib(false), _printAtoms(false), _testingFileUsage(false),
- _keepPrivateExterns(false), _demangle(false), _archHandler(nullptr),
- _exportMode(ExportMode::globals),
- _debugInfoMode(DebugInfoMode::addDebugMap), _orderFileEntries(0),
- _flatNamespaceFile(nullptr) {}
-
-MachOLinkingContext::~MachOLinkingContext() {}
+MachOLinkingContext::MachOLinkingContext() {}
+
+MachOLinkingContext::~MachOLinkingContext() {
+ // Atoms are allocated on BumpPtrAllocator's on File's.
+ // As we transfer atoms from one file to another, we need to clear all of the
+ // atoms before we remove any of the BumpPtrAllocator's.
+ auto &nodes = getNodes();
+ for (unsigned i = 0, e = nodes.size(); i != e; ++i) {
+ FileNode *node = dyn_cast<FileNode>(nodes[i].get());
+ if (!node)
+ continue;
+ File *file = node->getFile();
+ file->clearAtoms();
+ }
+}
void MachOLinkingContext::configure(HeaderFileType type, Arch arch, OS os,
- uint32_t minOSVersion) {
+ uint32_t minOSVersion,
+ bool exportDynamicSymbols) {
_outputMachOType = type;
_arch = arch;
_os = os;
_osMinVersion = minOSVersion;
// If min OS not specified on command line, use reasonable defaults.
- if (minOSVersion == 0) {
- switch (_arch) {
- case arch_x86_64:
- case arch_x86:
- parsePackedVersion("10.8", _osMinVersion);
- _os = MachOLinkingContext::OS::macOSX;
- break;
- case arch_armv6:
- case arch_armv7:
- case arch_armv7s:
- case arch_arm64:
- parsePackedVersion("7.0", _osMinVersion);
- _os = MachOLinkingContext::OS::iOS;
- break;
- default:
- break;
+ // Note that we only do sensible defaults when emitting something other than
+ // object and preload.
+ if (_outputMachOType != llvm::MachO::MH_OBJECT &&
+ _outputMachOType != llvm::MachO::MH_PRELOAD) {
+ if (minOSVersion == 0) {
+ switch (_arch) {
+ case arch_x86_64:
+ case arch_x86:
+ parsePackedVersion("10.8", _osMinVersion);
+ _os = MachOLinkingContext::OS::macOSX;
+ break;
+ case arch_armv6:
+ case arch_armv7:
+ case arch_armv7s:
+ case arch_arm64:
+ parsePackedVersion("7.0", _osMinVersion);
+ _os = MachOLinkingContext::OS::iOS;
+ break;
+ default:
+ break;
+ }
}
}
@@ -217,9 +255,10 @@ void MachOLinkingContext::configure(HeaderFileType type, Arch arch, OS os,
case OS::unknown:
break;
}
+ setGlobalsAreDeadStripRoots(exportDynamicSymbols);
break;
case llvm::MachO::MH_DYLIB:
- setGlobalsAreDeadStripRoots(true);
+ setGlobalsAreDeadStripRoots(exportDynamicSymbols);
break;
case llvm::MachO::MH_BUNDLE:
break;
@@ -325,6 +364,11 @@ bool MachOLinkingContext::needsCompactUnwindPass() const {
}
}
+bool MachOLinkingContext::needsObjCPass() const {
+ // ObjC pass is only needed if any of the inputs were ObjC.
+ return _objcConstraint != objc_unknown;
+}
+
bool MachOLinkingContext::needsShimPass() const {
// Shim pass only used in final executables.
if (_outputMachOType == MH_OBJECT)
@@ -368,9 +412,11 @@ bool MachOLinkingContext::minOS(StringRef mac, StringRef iOS) const {
return false;
return _osMinVersion >= parsedVersion;
case OS::unknown:
- break;
+ // If we don't know the target, then assume that we don't meet the min OS.
+ // This matches the ld64 behaviour
+ return false;
}
- llvm_unreachable("target not configured for iOS or MacOSX");
+ llvm_unreachable("invalid OS enum");
}
bool MachOLinkingContext::addEntryPointLoadCommand() const {
@@ -484,7 +530,7 @@ void MachOLinkingContext::addFrameworkSearchDir(StringRef fwPath,
_frameworkDirs.push_back(fwPath);
}
-ErrorOr<StringRef>
+llvm::Optional<StringRef>
MachOLinkingContext::searchDirForLibrary(StringRef path,
StringRef libName) const {
SmallString<256> fullPath;
@@ -494,7 +540,7 @@ MachOLinkingContext::searchDirForLibrary(StringRef path,
llvm::sys::path::append(fullPath, libName);
if (fileExists(fullPath))
return fullPath.str().copy(_allocator);
- return make_error_code(llvm::errc::no_such_file_or_directory);
+ return llvm::None;
}
// Search for dynamic library
@@ -509,21 +555,23 @@ MachOLinkingContext::searchDirForLibrary(StringRef path,
if (fileExists(fullPath))
return fullPath.str().copy(_allocator);
- return make_error_code(llvm::errc::no_such_file_or_directory);
+ return llvm::None;
}
-ErrorOr<StringRef> MachOLinkingContext::searchLibrary(StringRef libName) const {
+llvm::Optional<StringRef>
+MachOLinkingContext::searchLibrary(StringRef libName) const {
SmallString<256> path;
for (StringRef dir : searchDirs()) {
- ErrorOr<StringRef> ec = searchDirForLibrary(dir, libName);
- if (ec)
- return ec;
+ llvm::Optional<StringRef> searchDir = searchDirForLibrary(dir, libName);
+ if (searchDir)
+ return searchDir;
}
- return make_error_code(llvm::errc::no_such_file_or_directory);
+ return llvm::None;
}
-ErrorOr<StringRef> MachOLinkingContext::findPathForFramework(StringRef fwName) const{
+llvm::Optional<StringRef>
+MachOLinkingContext::findPathForFramework(StringRef fwName) const{
SmallString<256> fullPath;
for (StringRef dir : frameworkDirs()) {
fullPath.assign(dir);
@@ -532,7 +580,7 @@ ErrorOr<StringRef> MachOLinkingContext::findPathForFramework(StringRef fwName) c
return fullPath.str().copy(_allocator);
}
- return make_error_code(llvm::errc::no_such_file_or_directory);
+ return llvm::None;
}
bool MachOLinkingContext::validateImpl(raw_ostream &diagnostics) {
@@ -589,6 +637,10 @@ bool MachOLinkingContext::validateImpl(raw_ostream &diagnostics) {
}
void MachOLinkingContext::addPasses(PassManager &pm) {
+ // objc pass should be before layout pass. Otherwise test cases may contain
+ // no atoms which confuses the layout pass.
+ if (needsObjCPass())
+ mach_o::addObjCPass(pm, *this);
mach_o::addLayoutPass(pm, *this);
if (needsStubsPass())
mach_o::addStubsPass(pm, *this);
@@ -656,9 +708,8 @@ MachODylibFile* MachOLinkingContext::findIndirectDylib(StringRef path) {
if (leafName.startswith("lib") && leafName.endswith(".dylib")) {
// FIXME: Need to enhance searchLibrary() to only look for .dylib
auto libPath = searchLibrary(leafName);
- if (!libPath.getError()) {
- return loadIndirectDylib(libPath.get());
- }
+ if (libPath)
+ return loadIndirectDylib(libPath.getValue());
}
// Try full path with sysroot.
@@ -990,4 +1041,77 @@ void MachOLinkingContext::finalizeInputFiles() {
elements.push_back(llvm::make_unique<GroupEnd>(numLibs));
}
+llvm::Error MachOLinkingContext::handleLoadedFile(File &file) {
+ auto *machoFile = dyn_cast<MachOFile>(&file);
+ if (!machoFile)
+ return llvm::Error();
+
+ // Check that the arch of the context matches that of the file.
+ // Also set the arch of the context if it didn't have one.
+ if (_arch == arch_unknown) {
+ _arch = machoFile->arch();
+ } else if (machoFile->arch() != arch_unknown && machoFile->arch() != _arch) {
+ // Archs are different.
+ return llvm::make_error<GenericError>(file.path() +
+ Twine(" cannot be linked due to incompatible architecture"));
+ }
+
+ // Check that the OS of the context matches that of the file.
+ // Also set the OS of the context if it didn't have one.
+ if (_os == OS::unknown) {
+ _os = machoFile->OS();
+ } else if (machoFile->OS() != OS::unknown && machoFile->OS() != _os) {
+ // OSes are different.
+ return llvm::make_error<GenericError>(file.path() +
+ Twine(" cannot be linked due to incompatible operating systems"));
+ }
+
+ // Check that if the objc info exists, that it is compatible with the target
+ // OS.
+ switch (machoFile->objcConstraint()) {
+ case objc_unknown:
+ // The file is not compiled with objc, so skip the checks.
+ break;
+ case objc_gc_only:
+ case objc_supports_gc:
+ llvm_unreachable("GC support should already have thrown an error");
+ case objc_retainReleaseForSimulator:
+ // The file is built with simulator objc, so make sure that the context
+ // is also building with simulator support.
+ if (_os != OS::iOS_simulator)
+ return llvm::make_error<GenericError>(file.path() +
+ Twine(" cannot be linked. It contains ObjC built for the simulator"
+ " while we are linking a non-simulator target"));
+ assert((_objcConstraint == objc_unknown ||
+ _objcConstraint == objc_retainReleaseForSimulator) &&
+ "Must be linking with retain/release for the simulator");
+ _objcConstraint = objc_retainReleaseForSimulator;
+ break;
+ case objc_retainRelease:
+ // The file is built without simulator objc, so make sure that the
+ // context is also building without simulator support.
+ if (_os == OS::iOS_simulator)
+ return llvm::make_error<GenericError>(file.path() +
+ Twine(" cannot be linked. It contains ObjC built for a non-simulator"
+ " target while we are linking a simulator target"));
+ assert((_objcConstraint == objc_unknown ||
+ _objcConstraint == objc_retainRelease) &&
+ "Must be linking with retain/release for a non-simulator target");
+ _objcConstraint = objc_retainRelease;
+ break;
+ }
+
+ // Check that the swift version of the context matches that of the file.
+ // Also set the swift version of the context if it didn't have one.
+ if (!_swiftVersion) {
+ _swiftVersion = machoFile->swiftVersion();
+ } else if (machoFile->swiftVersion() &&
+ machoFile->swiftVersion() != _swiftVersion) {
+ // Swift versions are different.
+ return llvm::make_error<GenericError>("different swift versions");
+ }
+
+ return llvm::Error();
+}
+
} // end namespace lld
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFile.h b/lib/ReaderWriter/MachO/MachONormalizedFile.h
index cccf180f1043..92a21f7ef83d 100644
--- a/lib/ReaderWriter/MachO/MachONormalizedFile.h
+++ b/lib/ReaderWriter/MachO/MachONormalizedFile.h
@@ -39,6 +39,9 @@
/// +-------+
///
+#ifndef LLD_READER_WRITER_MACHO_NORMALIZE_FILE_H
+#define LLD_READER_WRITER_MACHO_NORMALIZE_FILE_H
+
#include "lld/Core/Error.h"
#include "lld/Core/LLVM.h"
#include "lld/ReaderWriter/MachOLinkingContext.h"
@@ -50,9 +53,6 @@
#include "llvm/Support/MachO.h"
#include "llvm/Support/YAMLTraits.h"
-#ifndef LLD_READER_WRITER_MACHO_NORMALIZE_FILE_H
-#define LLD_READER_WRITER_MACHO_NORMALIZE_FILE_H
-
using llvm::BumpPtrAllocator;
using llvm::yaml::Hex64;
using llvm::yaml::Hex32;
@@ -105,6 +105,9 @@ typedef std::vector<uint32_t> IndirectSymbols;
/// A typedef so that YAML I/O can encode/decode section attributes.
LLVM_YAML_STRONG_TYPEDEF(uint32_t, SectionAttr)
+/// A typedef so that YAML I/O can encode/decode section alignment.
+LLVM_YAML_STRONG_TYPEDEF(uint16_t, SectionAlignment)
+
/// Mach-O has a 32-bit and 64-bit section record. This normalized form
/// can support either kind.
struct Section {
@@ -115,7 +118,7 @@ struct Section {
StringRef sectionName;
SectionType type;
SectionAttr attributes;
- uint16_t alignment;
+ SectionAlignment alignment;
Hex64 address;
ArrayRef<uint8_t> content;
Relocations relocations;
@@ -172,7 +175,8 @@ struct Segment {
StringRef name;
Hex64 address;
Hex64 size;
- VMProtect access;
+ VMProtect init_access;
+ VMProtect max_access;
};
/// Only used in normalized final linked images to specify on which dylibs
@@ -245,6 +249,8 @@ struct NormalizedFile {
PackedVersion compatVersion = 0; // dylibs only
PackedVersion currentVersion = 0; // dylibs only
bool hasUUID = false;
+ bool hasMinVersionLoadCommand = false;
+ bool generateDataInCodeLoadCommand = false;
std::vector<StringRef> rpaths;
Hex64 entryAddress = 0;
Hex64 stackSize = 0;
@@ -252,6 +258,7 @@ struct NormalizedFile {
Hex64 sourceVersion = 0;
PackedVersion minOSverson = 0;
PackedVersion sdkVersion = 0;
+ LoadCommandType minOSVersionKind = (LoadCommandType)0;
// Maps to load commands with LINKEDIT content (final linked images only).
Hex32 pageSize = 0;
@@ -260,6 +267,7 @@ struct NormalizedFile {
std::vector<BindLocation> weakBindingInfo;
std::vector<BindLocation> lazyBindingInfo;
std::vector<Export> exportInfo;
+ std::vector<uint8_t> functionStarts;
std::vector<DataInCode> dataInCode;
// TODO:
@@ -281,40 +289,40 @@ bool sliceFromFatFile(MemoryBufferRef mb, MachOLinkingContext::Arch arch,
uint32_t &offset, uint32_t &size);
/// Reads a mach-o file and produces an in-memory normalized view.
-ErrorOr<std::unique_ptr<NormalizedFile>>
+llvm::Expected<std::unique_ptr<NormalizedFile>>
readBinary(std::unique_ptr<MemoryBuffer> &mb,
const MachOLinkingContext::Arch arch);
/// Takes in-memory normalized view and writes a mach-o object file.
-std::error_code writeBinary(const NormalizedFile &file, StringRef path);
+llvm::Error writeBinary(const NormalizedFile &file, StringRef path);
size_t headerAndLoadCommandsSize(const NormalizedFile &file);
/// Parses a yaml encoded mach-o file to produce an in-memory normalized view.
-ErrorOr<std::unique_ptr<NormalizedFile>>
+llvm::Expected<std::unique_ptr<NormalizedFile>>
readYaml(std::unique_ptr<MemoryBuffer> &mb);
/// Writes a yaml encoded mach-o files given an in-memory normalized view.
std::error_code writeYaml(const NormalizedFile &file, raw_ostream &out);
-std::error_code
+llvm::Error
normalizedObjectToAtoms(MachOFile *file,
const NormalizedFile &normalizedFile,
bool copyRefs);
-std::error_code
+llvm::Error
normalizedDylibToAtoms(MachODylibFile *file,
const NormalizedFile &normalizedFile,
bool copyRefs);
/// Takes in-memory normalized dylib or object and parses it into lld::File
-ErrorOr<std::unique_ptr<lld::File>>
+llvm::Expected<std::unique_ptr<lld::File>>
normalizedToAtoms(const NormalizedFile &normalizedFile, StringRef path,
bool copyRefs);
/// Takes atoms and generates a normalized macho-o view.
-ErrorOr<std::unique_ptr<NormalizedFile>>
+llvm::Expected<std::unique_ptr<NormalizedFile>>
normalizedFromAtoms(const lld::File &atomFile, const MachOLinkingContext &ctxt);
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
index 1013d3ddaef3..a17de5be1742 100644
--- a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
+++ b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
@@ -53,7 +53,7 @@ namespace mach_o {
namespace normalized {
// Utility to call a lambda expression on each load command.
-static std::error_code forEachLoadCommand(
+static llvm::Error forEachLoadCommand(
StringRef lcRange, unsigned lcCount, bool isBig, bool is64,
std::function<bool(uint32_t cmd, uint32_t size, const char *lc)> func) {
const char* p = lcRange.begin();
@@ -67,15 +67,15 @@ static std::error_code forEachLoadCommand(
slc = &lcCopy;
}
if ( (p + slc->cmdsize) > lcRange.end() )
- return make_error_code(llvm::errc::executable_format_error);
+ return llvm::make_error<GenericError>("Load command exceeds range");
if (func(slc->cmd, slc->cmdsize, p))
- return std::error_code();
+ return llvm::Error();
p += slc->cmdsize;
}
- return std::error_code();
+ return llvm::Error();
}
static std::error_code appendRelocations(Relocations &relocs, StringRef buffer,
@@ -199,7 +199,7 @@ bool sliceFromFatFile(MemoryBufferRef mb, MachOLinkingContext::Arch arch,
}
/// Reads a mach-o file and produces an in-memory normalized view.
-ErrorOr<std::unique_ptr<NormalizedFile>>
+llvm::Expected<std::unique_ptr<NormalizedFile>>
readBinary(std::unique_ptr<MemoryBuffer> &mb,
const MachOLinkingContext::Arch arch) {
// Make empty NormalizedFile.
@@ -220,7 +220,7 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb,
// Determine endianness and pointer size for mach-o file.
bool is64, isBig;
if (!isMachOHeader(mh, is64, isBig))
- return make_error_code(llvm::errc::executable_format_error);
+ return llvm::make_error<GenericError>("File is not a mach-o");
// Endian swap header, if needed.
mach_header headerCopy;
@@ -237,12 +237,13 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb,
start + (is64 ? sizeof(mach_header_64) : sizeof(mach_header));
StringRef lcRange(lcStart, smh->sizeofcmds);
if (lcRange.end() > (start + objSize))
- return make_error_code(llvm::errc::executable_format_error);
+ return llvm::make_error<GenericError>("Load commands exceed file size");
// Get architecture from mach_header.
f->arch = MachOLinkingContext::archFromCpuType(smh->cputype, smh->cpusubtype);
if (f->arch != arch) {
- return make_dynamic_error_code(Twine("file is wrong architecture. Expected "
+ return llvm::make_error<GenericError>(
+ Twine("file is wrong architecture. Expected "
"(" + MachOLinkingContext::nameFromArch(arch)
+ ") found ("
+ MachOLinkingContext::nameFromArch(f->arch)
@@ -256,9 +257,9 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb,
// Pre-scan load commands looking for indirect symbol table.
uint32_t indirectSymbolTableOffset = 0;
uint32_t indirectSymbolTableCount = 0;
- std::error_code ec = forEachLoadCommand(lcRange, lcCount, isBig, is64,
- [&](uint32_t cmd, uint32_t size,
- const char *lc) -> bool {
+ auto ec = forEachLoadCommand(lcRange, lcCount, isBig, is64,
+ [&](uint32_t cmd, uint32_t size,
+ const char *lc) -> bool {
if (cmd == LC_DYSYMTAB) {
const dysymtab_command *d = reinterpret_cast<const dysymtab_command*>(lc);
indirectSymbolTableOffset = read32(&d->indirectsymoff, isBig);
@@ -268,7 +269,7 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb,
return false;
});
if (ec)
- return ec;
+ return std::move(ec);
// Walk load commands looking for segments/sections and the symbol table.
const data_in_code_entry *dataInCode = nullptr;
@@ -380,11 +381,11 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb,
reinterpret_cast<const nlist_64 *>(start + symOffset);
// Convert each nlist_64 to a lld::mach_o::normalized::Symbol.
for(uint32_t i=0; i < symCount; ++i) {
- const nlist_64 *sin = &symbols[i];
nlist_64 tempSym;
- if (isBig != llvm::sys::IsBigEndianHost) {
- tempSym = *sin; swapStruct(tempSym); sin = &tempSym;
- }
+ memcpy(&tempSym, &symbols[i], sizeof(nlist_64));
+ const nlist_64 *sin = &tempSym;
+ if (isBig != llvm::sys::IsBigEndianHost)
+ swapStruct(tempSym);
Symbol sout;
if (sin->n_strx > strSize)
return true;
@@ -471,11 +472,20 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb,
case LC_DYLD_INFO_ONLY:
dyldInfo = reinterpret_cast<const dyld_info_command*>(lc);
break;
+ case LC_VERSION_MIN_MACOSX:
+ case LC_VERSION_MIN_IPHONEOS:
+ case LC_VERSION_MIN_WATCHOS:
+ case LC_VERSION_MIN_TVOS:
+ // If we are emitting an object file, then we may take the load command
+ // kind from these commands and pass it on to the output
+ // file.
+ f->minOSVersionKind = (LoadCommandType)cmd;
+ break;
}
return false;
});
if (ec)
- return ec;
+ return std::move(ec);
if (dataInCode) {
// Convert on-disk data_in_code_entry array to DataInCode vector.
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h
index 1226860b021e..86823efa33c9 100644
--- a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h
+++ b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h
@@ -7,6 +7,8 @@
//
//===----------------------------------------------------------------------===//
+#ifndef LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H
+#define LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H
#include "MachONormalizedFile.h"
#include "lld/Core/Error.h"
@@ -16,16 +18,54 @@
#include "llvm/Support/Endian.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Host.h"
+#include "llvm/Support/LEB128.h"
#include "llvm/Support/MachO.h"
#include <system_error>
-#ifndef LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H
-#define LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H
-
namespace lld {
namespace mach_o {
namespace normalized {
+class ByteBuffer {
+public:
+ ByteBuffer() : _ostream(_bytes) { }
+
+ void append_byte(uint8_t b) {
+ _ostream << b;
+ }
+ void append_uleb128(uint64_t value) {
+ llvm::encodeULEB128(value, _ostream);
+ }
+ void append_uleb128Fixed(uint64_t value, unsigned byteCount) {
+ unsigned min = llvm::getULEB128Size(value);
+ assert(min <= byteCount);
+ unsigned pad = byteCount - min;
+ llvm::encodeULEB128(value, _ostream, pad);
+ }
+ void append_sleb128(int64_t value) {
+ llvm::encodeSLEB128(value, _ostream);
+ }
+ void append_string(StringRef str) {
+ _ostream << str;
+ append_byte(0);
+ }
+ void align(unsigned alignment) {
+ while ( (_ostream.tell() % alignment) != 0 )
+ append_byte(0);
+ }
+ size_t size() {
+ return _ostream.tell();
+ }
+ const uint8_t *bytes() {
+ return reinterpret_cast<const uint8_t*>(_ostream.str().data());
+ }
+
+private:
+ SmallVector<char, 128> _bytes;
+ // Stream ivar must be after SmallVector ivar to construct properly.
+ llvm::raw_svector_ostream _ostream;
+};
+
using namespace llvm::support::endian;
using llvm::sys::getSwappedBytes;
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
index 4ecfece0629e..f3e159684e15 100644
--- a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
+++ b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
@@ -25,6 +25,8 @@
#include "MachONormalizedFileBinaryUtils.h"
#include "lld/Core/Error.h"
#include "lld/Core/LLVM.h"
+#include "llvm/ADT/ilist.h"
+#include "llvm/ADT/ilist_node.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
@@ -35,7 +37,6 @@
#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/Host.h"
-#include "llvm/Support/LEB128.h"
#include "llvm/Support/MachO.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
@@ -50,6 +51,72 @@ namespace lld {
namespace mach_o {
namespace normalized {
+struct TrieNode; // Forward declaration.
+
+struct TrieEdge : public llvm::ilist_node<TrieEdge> {
+ TrieEdge(StringRef s, TrieNode *node) : _subString(s), _child(node) {}
+
+ StringRef _subString;
+ struct TrieNode *_child;
+};
+
+} // namespace normalized
+} // namespace mach_o
+} // namespace lld
+
+
+namespace llvm {
+ using lld::mach_o::normalized::TrieEdge;
+ template <>
+ struct ilist_traits<TrieEdge>
+ : public ilist_default_traits<TrieEdge> {
+ private:
+ mutable ilist_half_node<TrieEdge> Sentinel;
+ public:
+ TrieEdge *createSentinel() const {
+ return static_cast<TrieEdge*>(&Sentinel);
+ }
+ void destroySentinel(TrieEdge *) const {}
+
+ TrieEdge *provideInitialHead() const { return createSentinel(); }
+ TrieEdge *ensureHead(TrieEdge*) const { return createSentinel(); }
+ static void noteHead(TrieEdge*, TrieEdge*) {}
+ void deleteNode(TrieEdge *N) {}
+
+ private:
+ void createNode(const TrieEdge &);
+ };
+} // namespace llvm
+
+
+namespace lld {
+namespace mach_o {
+namespace normalized {
+
+struct TrieNode {
+ typedef llvm::ilist<TrieEdge> TrieEdgeList;
+
+ TrieNode(StringRef s)
+ : _cummulativeString(s), _address(0), _flags(0), _other(0),
+ _trieOffset(0), _hasExportInfo(false) {}
+ ~TrieNode() = default;
+
+ void addSymbol(const Export &entry, BumpPtrAllocator &allocator,
+ std::vector<TrieNode *> &allNodes);
+ bool updateOffset(uint32_t &offset);
+ void appendToByteBuffer(ByteBuffer &out);
+
+private:
+ StringRef _cummulativeString;
+ TrieEdgeList _children;
+ uint64_t _address;
+ uint64_t _flags;
+ uint64_t _other;
+ StringRef _importedName;
+ uint32_t _trieOffset;
+ bool _hasExportInfo;
+};
+
/// Utility class for writing a mach-o binary file given an in-memory
/// normalized file.
class MachOFileLayout {
@@ -66,13 +133,13 @@ public:
/// Writes the normalized file as a binary mach-o file to the specified
/// path. This does not have a stream interface because the generated
/// file may need the 'x' bit set.
- std::error_code writeBinary(StringRef path);
+ llvm::Error writeBinary(StringRef path);
private:
uint32_t loadCommandsSize(uint32_t &count);
void buildFileOffsets();
void writeMachHeader();
- std::error_code writeLoadCommands();
+ llvm::Error writeLoadCommands();
void writeSectionContent();
void writeRelocations();
void writeSymbolTable();
@@ -80,6 +147,7 @@ private:
void writeBindingInfo();
void writeLazyBindingInfo();
void writeExportInfo();
+ void writeFunctionStartsInfo();
void writeDataInCodeInfo();
void writeLinkEditContent();
void buildLinkEditInfo();
@@ -87,6 +155,7 @@ private:
void buildBindInfo();
void buildLazyBindInfo();
void buildExportTrie();
+ void computeFunctionStartsSize();
void computeDataInCodeSize();
void computeSymbolTableSizes();
void buildSectionRelocations();
@@ -110,83 +179,12 @@ private:
};
template <typename T>
- std::error_code writeSingleSegmentLoadCommand(uint8_t *&lc);
- template <typename T> std::error_code writeSegmentLoadCommands(uint8_t *&lc);
+ llvm::Error writeSingleSegmentLoadCommand(uint8_t *&lc);
+ template <typename T> llvm::Error writeSegmentLoadCommands(uint8_t *&lc);
uint32_t pointerAlign(uint32_t value);
static StringRef dyldPath();
- class ByteBuffer {
- public:
- ByteBuffer() : _ostream(_bytes) { }
-
- void append_byte(uint8_t b) {
- _ostream << b;
- }
- void append_uleb128(uint64_t value) {
- llvm::encodeULEB128(value, _ostream);
- }
- void append_uleb128Fixed(uint64_t value, unsigned byteCount) {
- unsigned min = llvm::getULEB128Size(value);
- assert(min <= byteCount);
- unsigned pad = byteCount - min;
- llvm::encodeULEB128(value, _ostream, pad);
- }
- void append_sleb128(int64_t value) {
- llvm::encodeSLEB128(value, _ostream);
- }
- void append_string(StringRef str) {
- _ostream << str;
- append_byte(0);
- }
- void align(unsigned alignment) {
- while ( (_ostream.tell() % alignment) != 0 )
- append_byte(0);
- }
- size_t size() {
- return _ostream.tell();
- }
- const uint8_t *bytes() {
- return reinterpret_cast<const uint8_t*>(_ostream.str().data());
- }
-
- private:
- SmallVector<char, 128> _bytes;
- // Stream ivar must be after SmallVector ivar to construct properly.
- llvm::raw_svector_ostream _ostream;
- };
-
- struct TrieNode; // Forward declaration.
-
- struct TrieEdge {
- TrieEdge(StringRef s, TrieNode *node) : _subString(s), _child(node) {}
-
- StringRef _subString;
- struct TrieNode *_child;
- };
-
- struct TrieNode {
- TrieNode(StringRef s)
- : _cummulativeString(s), _address(0), _flags(0), _other(0),
- _trieOffset(0), _hasExportInfo(false) {}
- ~TrieNode() = default;
-
- void addSymbol(const Export &entry, BumpPtrAllocator &allocator,
- std::vector<TrieNode *> &allNodes);
- bool updateOffset(uint32_t &offset);
- void appendToByteBuffer(ByteBuffer &out);
-
- private:
- StringRef _cummulativeString;
- std::list<TrieEdge> _children;
- uint64_t _address;
- uint64_t _flags;
- uint64_t _other;
- StringRef _importedName;
- uint32_t _trieOffset;
- bool _hasExportInfo;
- };
-
struct SegExtraInfo {
uint32_t fileOffset;
uint32_t fileSize;
@@ -209,6 +207,7 @@ private:
uint32_t _countOfLoadCommands;
uint32_t _endOfLoadCommands;
uint32_t _startOfRelocations;
+ uint32_t _startOfFunctionStarts;
uint32_t _startOfDataInCode;
uint32_t _startOfSymbols;
uint32_t _startOfIndirectSymbols;
@@ -219,6 +218,7 @@ private:
uint32_t _symbolTableUndefinesStartIndex;
uint32_t _symbolStringPoolSize;
uint32_t _symbolTableSize;
+ uint32_t _functionStartsSize;
uint32_t _dataInCodeSize;
uint32_t _indirectSymbolTableCount;
// Used in object file creation only
@@ -255,7 +255,7 @@ StringRef MachOFileLayout::dyldPath() {
}
uint32_t MachOFileLayout::pointerAlign(uint32_t value) {
- return llvm::RoundUpToAlignment(value, _is64 ? 8 : 4);
+ return llvm::alignTo(value, _is64 ? 8 : 4);
}
@@ -280,7 +280,15 @@ MachOFileLayout::MachOFileLayout(const NormalizedFile &file)
+ file.sections.size() * sectsSize
+ sizeof(symtab_command);
_countOfLoadCommands = 2;
- if (!_file.dataInCode.empty()) {
+ if (file.hasMinVersionLoadCommand) {
+ _endOfLoadCommands += sizeof(version_min_command);
+ _countOfLoadCommands++;
+ }
+ if (!_file.functionStarts.empty()) {
+ _endOfLoadCommands += sizeof(linkedit_data_command);
+ _countOfLoadCommands++;
+ }
+ if (_file.generateDataInCodeLoadCommand) {
_endOfLoadCommands += sizeof(linkedit_data_command);
_countOfLoadCommands++;
}
@@ -292,7 +300,7 @@ MachOFileLayout::MachOFileLayout(const NormalizedFile &file)
if (isZeroFillSection(sect.type))
_sectInfo[&sect].fileOffset = 0;
else {
- offset = llvm::RoundUpToAlignment(offset, sect.alignment);
+ offset = llvm::alignTo(offset, sect.alignment);
_sectInfo[&sect].fileOffset = offset;
offset += sect.content.size();
}
@@ -301,11 +309,13 @@ MachOFileLayout::MachOFileLayout(const NormalizedFile &file)
_endOfSectionsContent = offset;
computeSymbolTableSizes();
+ computeFunctionStartsSize();
computeDataInCodeSize();
// Align start of relocations.
_startOfRelocations = pointerAlign(_endOfSectionsContent);
- _startOfDataInCode = _startOfRelocations + relocCount * 8;
+ _startOfFunctionStarts = _startOfRelocations + relocCount * 8;
+ _startOfDataInCode = _startOfFunctionStarts + _functionStartsSize;
_startOfSymbols = _startOfDataInCode + _dataInCodeSize;
// Add Indirect symbol table.
_startOfIndirectSymbols = _startOfSymbols + _symbolTableSize;
@@ -346,7 +356,8 @@ MachOFileLayout::MachOFileLayout(const NormalizedFile &file)
_endOfLazyBindingInfo = _startOfLazyBindingInfo + _lazyBindingInfo.size();
_startOfExportTrie = _endOfLazyBindingInfo;
_endOfExportTrie = _startOfExportTrie + _exportTrie.size();
- _startOfDataInCode = _endOfExportTrie;
+ _startOfFunctionStarts = _endOfExportTrie;
+ _startOfDataInCode = _startOfFunctionStarts + _functionStartsSize;
_startOfSymbols = _startOfDataInCode + _dataInCodeSize;
_startOfIndirectSymbols = _startOfSymbols + _symbolTableSize;
_startOfSymbolStrings = _startOfIndirectSymbols
@@ -368,6 +379,7 @@ MachOFileLayout::MachOFileLayout(const NormalizedFile &file)
<< " endOfLazyBindingInfo=" << _endOfLazyBindingInfo << "\n"
<< " startOfExportTrie=" << _startOfExportTrie << "\n"
<< " endOfExportTrie=" << _endOfExportTrie << "\n"
+ << " startOfFunctionStarts=" << _startOfFunctionStarts << "\n"
<< " startOfDataInCode=" << _startOfDataInCode << "\n"
<< " startOfSymbols=" << _startOfSymbols << "\n"
<< " startOfSymbolStrings=" << _startOfSymbolStrings << "\n"
@@ -389,9 +401,6 @@ uint32_t MachOFileLayout::loadCommandsSize(uint32_t &count) {
count += _file.segments.size();
// Add section record for each section.
size += _file.sections.size() * sectionSize;
- // Add one LC_SEGMENT for implicit __LINKEDIT segment
- size += segCommandSize;
- ++count;
// If creating a dylib, add LC_ID_DYLIB.
if (_file.fileType == llvm::MachO::MH_DYLIB) {
@@ -413,10 +422,25 @@ uint32_t MachOFileLayout::loadCommandsSize(uint32_t &count) {
++count;
}
- // If main executable add LC_LOAD_DYLINKER and LC_MAIN
+ // If main executable add LC_LOAD_DYLINKER
if (_file.fileType == llvm::MachO::MH_EXECUTE) {
size += pointerAlign(sizeof(dylinker_command) + dyldPath().size()+1);
++count;
+ }
+
+ // Add LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS, LC_VERSION_MIN_WATCHOS,
+ // LC_VERSION_MIN_TVOS
+ if (_file.hasMinVersionLoadCommand) {
+ size += sizeof(version_min_command);
+ ++count;
+ }
+
+ // Add LC_SOURCE_VERSION
+ size += sizeof(source_version_command);
+ ++count;
+
+ // If main executable add LC_MAIN
+ if (_file.fileType == llvm::MachO::MH_EXECUTE) {
size += sizeof(entry_point_command);
++count;
}
@@ -433,8 +457,15 @@ uint32_t MachOFileLayout::loadCommandsSize(uint32_t &count) {
++count;
}
- // Add LC_DATA_IN_CODE if needed
- if (!_file.dataInCode.empty()) {
+ // Add LC_FUNCTION_STARTS if needed
+ if (!_file.functionStarts.empty()) {
+ size += sizeof(linkedit_data_command);
+ ++count;
+ }
+
+ // Add LC_DATA_IN_CODE if requested. Note, we do encode zero length entries.
+ // FIXME: Zero length entries is only to match ld64. Should we change this?
+ if (_file.generateDataInCodeLoadCommand) {
size += sizeof(linkedit_data_command);
++count;
}
@@ -517,7 +548,7 @@ void MachOFileLayout::buildFileOffsets() {
llvm::dbgs() << "buildFileOffsets()\n");
for (const Segment &sg : _file.segments) {
_segInfo[&sg].fileOffset = fileOffset;
- if ((_seg1addr == INT64_MAX) && sg.access)
+ if ((_seg1addr == INT64_MAX) && sg.init_access)
_seg1addr = sg.address;
DEBUG_WITH_TYPE("MachOFileLayout",
llvm::dbgs() << " segment=" << sg.name
@@ -525,7 +556,7 @@ void MachOFileLayout::buildFileOffsets() {
uint32_t segFileSize = 0;
// A segment that is not zero-fill must use a least one page of disk space.
- if (sg.access)
+ if (sg.init_access)
segFileSize = _file.pageSize;
for (const Section *s : _segInfo[&sg].sections) {
uint32_t sectOffset = s->address - sg.address;
@@ -539,10 +570,11 @@ void MachOFileLayout::buildFileOffsets() {
<< ", fileOffset=" << fileOffset << "\n");
}
- _segInfo[&sg].fileSize = llvm::RoundUpToAlignment(segFileSize,
- _file.pageSize);
- fileOffset = llvm::RoundUpToAlignment(fileOffset + segFileSize,
- _file.pageSize);
+ // round up all segments to page aligned, except __LINKEDIT
+ if (!sg.name.equals("__LINKEDIT")) {
+ _segInfo[&sg].fileSize = llvm::alignTo(segFileSize, _file.pageSize);
+ fileOffset = llvm::alignTo(fileOffset + segFileSize, _file.pageSize);
+ }
_addressOfLinkEdit = sg.address + sg.size;
}
_startOfLinkEdit = fileOffset;
@@ -553,10 +585,23 @@ size_t MachOFileLayout::size() const {
}
void MachOFileLayout::writeMachHeader() {
+ auto cpusubtype = MachOLinkingContext::cpuSubtypeFromArch(_file.arch);
+ // dynamic x86 executables on newer OS version should also set the
+ // CPU_SUBTYPE_LIB64 mask in the CPU subtype.
+ // FIXME: Check that this is a dynamic executable, not a static one.
+ if (_file.fileType == llvm::MachO::MH_EXECUTE &&
+ cpusubtype == CPU_SUBTYPE_X86_64_ALL &&
+ _file.os == MachOLinkingContext::OS::macOSX) {
+ uint32_t version;
+ bool failed = MachOLinkingContext::parsePackedVersion("10.5", version);
+ if (!failed && _file.minOSverson >= version)
+ cpusubtype |= CPU_SUBTYPE_LIB64;
+ }
+
mach_header *mh = reinterpret_cast<mach_header*>(_buffer);
mh->magic = _is64 ? llvm::MachO::MH_MAGIC_64 : llvm::MachO::MH_MAGIC;
mh->cputype = MachOLinkingContext::cpuTypeFromArch(_file.arch);
- mh->cpusubtype = MachOLinkingContext::cpuSubtypeFromArch(_file.arch);
+ mh->cpusubtype = cpusubtype;
mh->filetype = _file.fileType;
mh->ncmds = _countOfLoadCommands;
mh->sizeofcmds = _endOfLoadCommands - _startOfLoadCommands;
@@ -583,7 +628,7 @@ uint32_t MachOFileLayout::indirectSymbolElementSize(const Section &sect) {
}
template <typename T>
-std::error_code MachOFileLayout::writeSingleSegmentLoadCommand(uint8_t *&lc) {
+llvm::Error MachOFileLayout::writeSingleSegmentLoadCommand(uint8_t *&lc) {
typename T::command* seg = reinterpret_cast<typename T::command*>(lc);
seg->cmd = T::LC;
seg->cmdsize = sizeof(typename T::command)
@@ -623,15 +668,37 @@ std::error_code MachOFileLayout::writeSingleSegmentLoadCommand(uint8_t *&lc) {
++sout;
}
lc = next;
- return std::error_code();
+ return llvm::Error();
}
template <typename T>
-std::error_code MachOFileLayout::writeSegmentLoadCommands(uint8_t *&lc) {
+llvm::Error MachOFileLayout::writeSegmentLoadCommands(uint8_t *&lc) {
uint32_t indirectSymRunningIndex = 0;
for (const Segment &seg : _file.segments) {
- // Write segment command with trailing sections.
+ // Link edit has no sections and a custom range of address, so handle it
+ // specially.
SegExtraInfo &segInfo = _segInfo[&seg];
+ if (seg.name.equals("__LINKEDIT")) {
+ size_t linkeditSize = _endOfLinkEdit - _startOfLinkEdit;
+ typename T::command* cmd = reinterpret_cast<typename T::command*>(lc);
+ cmd->cmd = T::LC;
+ cmd->cmdsize = sizeof(typename T::command);
+ uint8_t *next = lc + cmd->cmdsize;
+ setString16("__LINKEDIT", cmd->segname);
+ cmd->vmaddr = _addressOfLinkEdit;
+ cmd->vmsize = llvm::alignTo(linkeditSize, _file.pageSize);
+ cmd->fileoff = _startOfLinkEdit;
+ cmd->filesize = linkeditSize;
+ cmd->initprot = seg.init_access;
+ cmd->maxprot = seg.max_access;
+ cmd->nsects = 0;
+ cmd->flags = 0;
+ if (_swap)
+ swapStruct(*cmd);
+ lc = next;
+ continue;
+ }
+ // Write segment command with trailing sections.
typename T::command* cmd = reinterpret_cast<typename T::command*>(lc);
cmd->cmd = T::LC;
cmd->cmdsize = sizeof(typename T::command)
@@ -642,8 +709,8 @@ std::error_code MachOFileLayout::writeSegmentLoadCommands(uint8_t *&lc) {
cmd->vmsize = seg.size;
cmd->fileoff = segInfo.fileOffset;
cmd->filesize = segInfo.fileSize;
- cmd->maxprot = seg.access;
- cmd->initprot = seg.access;
+ cmd->initprot = seg.init_access;
+ cmd->maxprot = seg.max_access;
cmd->nsects = segInfo.sections.size();
cmd->flags = 0;
if (_swap)
@@ -671,36 +738,52 @@ std::error_code MachOFileLayout::writeSegmentLoadCommands(uint8_t *&lc) {
}
lc = reinterpret_cast<uint8_t*>(next);
}
- // Add implicit __LINKEDIT segment
- size_t linkeditSize = _endOfLinkEdit - _startOfLinkEdit;
- typename T::command* cmd = reinterpret_cast<typename T::command*>(lc);
- cmd->cmd = T::LC;
- cmd->cmdsize = sizeof(typename T::command);
- uint8_t *next = lc + cmd->cmdsize;
- setString16("__LINKEDIT", cmd->segname);
- cmd->vmaddr = _addressOfLinkEdit;
- cmd->vmsize = llvm::RoundUpToAlignment(linkeditSize, _file.pageSize);
- cmd->fileoff = _startOfLinkEdit;
- cmd->filesize = linkeditSize;
- cmd->maxprot = VM_PROT_READ;
- cmd->initprot = VM_PROT_READ;
- cmd->nsects = 0;
- cmd->flags = 0;
+ return llvm::Error();
+}
+
+static void writeVersionMinLoadCommand(const NormalizedFile &_file,
+ bool _swap,
+ uint8_t *&lc) {
+ if (!_file.hasMinVersionLoadCommand)
+ return;
+ version_min_command *vm = reinterpret_cast<version_min_command*>(lc);
+ switch (_file.os) {
+ case MachOLinkingContext::OS::unknown:
+ vm->cmd = _file.minOSVersionKind;
+ vm->cmdsize = sizeof(version_min_command);
+ vm->version = _file.minOSverson;
+ vm->sdk = 0;
+ break;
+ case MachOLinkingContext::OS::macOSX:
+ vm->cmd = LC_VERSION_MIN_MACOSX;
+ vm->cmdsize = sizeof(version_min_command);
+ vm->version = _file.minOSverson;
+ vm->sdk = _file.sdkVersion;
+ break;
+ case MachOLinkingContext::OS::iOS:
+ case MachOLinkingContext::OS::iOS_simulator:
+ vm->cmd = LC_VERSION_MIN_IPHONEOS;
+ vm->cmdsize = sizeof(version_min_command);
+ vm->version = _file.minOSverson;
+ vm->sdk = _file.sdkVersion;
+ break;
+ }
if (_swap)
- swapStruct(*cmd);
- lc = next;
- return std::error_code();
+ swapStruct(*vm);
+ lc += sizeof(version_min_command);
}
-std::error_code MachOFileLayout::writeLoadCommands() {
- std::error_code ec;
+llvm::Error MachOFileLayout::writeLoadCommands() {
uint8_t *lc = &_buffer[_startOfLoadCommands];
if (_file.fileType == llvm::MachO::MH_OBJECT) {
// Object files have one unnamed segment which holds all sections.
- if (_is64)
- ec = writeSingleSegmentLoadCommand<MachO64Trait>(lc);
- else
- ec = writeSingleSegmentLoadCommand<MachO32Trait>(lc);
+ if (_is64) {
+ if (auto ec = writeSingleSegmentLoadCommand<MachO64Trait>(lc))
+ return ec;
+ } else {
+ if (auto ec = writeSingleSegmentLoadCommand<MachO32Trait>(lc))
+ return ec;
+ }
// Add LC_SYMTAB with symbol table info
symtab_command* st = reinterpret_cast<symtab_command*>(lc);
st->cmd = LC_SYMTAB;
@@ -713,8 +796,25 @@ std::error_code MachOFileLayout::writeLoadCommands() {
if (_swap)
swapStruct(*st);
lc += sizeof(symtab_command);
- // Add LC_DATA_IN_CODE if needed.
- if (_dataInCodeSize != 0) {
+
+ // Add LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS,
+ // LC_VERSION_MIN_WATCHOS, LC_VERSION_MIN_TVOS
+ writeVersionMinLoadCommand(_file, _swap, lc);
+
+ // Add LC_FUNCTION_STARTS if needed.
+ if (_functionStartsSize != 0) {
+ linkedit_data_command* dl = reinterpret_cast<linkedit_data_command*>(lc);
+ dl->cmd = LC_FUNCTION_STARTS;
+ dl->cmdsize = sizeof(linkedit_data_command);
+ dl->dataoff = _startOfFunctionStarts;
+ dl->datasize = _functionStartsSize;
+ if (_swap)
+ swapStruct(*dl);
+ lc += sizeof(linkedit_data_command);
+ }
+
+ // Add LC_DATA_IN_CODE if requested.
+ if (_file.generateDataInCodeLoadCommand) {
linkedit_data_command* dl = reinterpret_cast<linkedit_data_command*>(lc);
dl->cmd = LC_DATA_IN_CODE;
dl->cmdsize = sizeof(linkedit_data_command);
@@ -726,10 +826,13 @@ std::error_code MachOFileLayout::writeLoadCommands() {
}
} else {
// Final linked images have sections under segments.
- if (_is64)
- ec = writeSegmentLoadCommands<MachO64Trait>(lc);
- else
- ec = writeSegmentLoadCommands<MachO32Trait>(lc);
+ if (_is64) {
+ if (auto ec = writeSegmentLoadCommands<MachO64Trait>(lc))
+ return ec;
+ } else {
+ if (auto ec = writeSegmentLoadCommands<MachO32Trait>(lc))
+ return ec;
+ }
// Add LC_ID_DYLIB command for dynamic libraries.
if (_file.fileType == llvm::MachO::MH_DYLIB) {
@@ -809,7 +912,7 @@ std::error_code MachOFileLayout::writeLoadCommands() {
lc += sizeof(dysymtab_command);
}
- // If main executable, add LC_LOAD_DYLINKER and LC_MAIN.
+ // If main executable, add LC_LOAD_DYLINKER
if (_file.fileType == llvm::MachO::MH_EXECUTE) {
// Build LC_LOAD_DYLINKER load command.
uint32_t size=pointerAlign(sizeof(dylinker_command)+dyldPath().size()+1);
@@ -822,14 +925,39 @@ std::error_code MachOFileLayout::writeLoadCommands() {
memcpy(lc+sizeof(dylinker_command), dyldPath().data(), dyldPath().size());
lc[sizeof(dylinker_command)+dyldPath().size()] = '\0';
lc += size;
+ }
+
+ // Add LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS, LC_VERSION_MIN_WATCHOS,
+ // LC_VERSION_MIN_TVOS
+ writeVersionMinLoadCommand(_file, _swap, lc);
+
+ // Add LC_SOURCE_VERSION
+ {
+ // Note, using a temporary here to appease UB as we may not be aligned
+ // enough for a struct containing a uint64_t when emitting a 32-bit binary
+ source_version_command sv;
+ sv.cmd = LC_SOURCE_VERSION;
+ sv.cmdsize = sizeof(source_version_command);
+ sv.version = _file.sourceVersion;
+ if (_swap)
+ swapStruct(sv);
+ memcpy(lc, &sv, sizeof(source_version_command));
+ lc += sizeof(source_version_command);
+ }
+
+ // If main executable, add LC_MAIN.
+ if (_file.fileType == llvm::MachO::MH_EXECUTE) {
// Build LC_MAIN load command.
- entry_point_command* ep = reinterpret_cast<entry_point_command*>(lc);
- ep->cmd = LC_MAIN;
- ep->cmdsize = sizeof(entry_point_command);
- ep->entryoff = _file.entryAddress - _seg1addr;
- ep->stacksize = _file.stackSize;
+ // Note, using a temporary here to appease UB as we may not be aligned
+ // enough for a struct containing a uint64_t when emitting a 32-bit binary
+ entry_point_command ep;
+ ep.cmd = LC_MAIN;
+ ep.cmdsize = sizeof(entry_point_command);
+ ep.entryoff = _file.entryAddress - _seg1addr;
+ ep.stacksize = _file.stackSize;
if (_swap)
- swapStruct(*ep);
+ swapStruct(ep);
+ memcpy(lc, &ep, sizeof(entry_point_command));
lc += sizeof(entry_point_command);
}
@@ -865,8 +993,20 @@ std::error_code MachOFileLayout::writeLoadCommands() {
lc += size;
}
- // Add LC_DATA_IN_CODE if needed.
- if (_dataInCodeSize != 0) {
+ // Add LC_FUNCTION_STARTS if needed.
+ if (_functionStartsSize != 0) {
+ linkedit_data_command* dl = reinterpret_cast<linkedit_data_command*>(lc);
+ dl->cmd = LC_FUNCTION_STARTS;
+ dl->cmdsize = sizeof(linkedit_data_command);
+ dl->dataoff = _startOfFunctionStarts;
+ dl->datasize = _functionStartsSize;
+ if (_swap)
+ swapStruct(*dl);
+ lc += sizeof(linkedit_data_command);
+ }
+
+ // Add LC_DATA_IN_CODE if requested.
+ if (_file.generateDataInCodeLoadCommand) {
linkedit_data_command* dl = reinterpret_cast<linkedit_data_command*>(lc);
dl->cmd = LC_DATA_IN_CODE;
dl->cmdsize = sizeof(linkedit_data_command);
@@ -877,7 +1017,7 @@ std::error_code MachOFileLayout::writeLoadCommands() {
lc += sizeof(linkedit_data_command);
}
}
- return ec;
+ return llvm::Error();
}
void MachOFileLayout::writeSectionContent() {
@@ -936,6 +1076,13 @@ void MachOFileLayout::appendSymbols(const std::vector<Symbol> &symbols,
}
}
+void MachOFileLayout::writeFunctionStartsInfo() {
+ if (!_functionStartsSize)
+ return;
+ memcpy(&_buffer[_startOfFunctionStarts], _file.functionStarts.data(),
+ _functionStartsSize);
+}
+
void MachOFileLayout::writeDataInCodeInfo() {
uint32_t offset = _startOfDataInCode;
for (const DataInCode &entry : _file.dataInCode) {
@@ -1011,6 +1158,7 @@ void MachOFileLayout::buildLinkEditInfo() {
buildLazyBindInfo();
buildExportTrie();
computeSymbolTableSizes();
+ computeFunctionStartsSize();
computeDataInCodeSize();
}
@@ -1079,9 +1227,9 @@ void MachOFileLayout::buildLazyBindInfo() {
_lazyBindingInfo.align(_is64 ? 8 : 4);
}
-void MachOFileLayout::TrieNode::addSymbol(const Export& entry,
- BumpPtrAllocator &allocator,
- std::vector<TrieNode*> &allNodes) {
+void TrieNode::addSymbol(const Export& entry,
+ BumpPtrAllocator &allocator,
+ std::vector<TrieNode*> &allNodes) {
StringRef partialStr = entry.name.drop_front(_cummulativeString.size());
for (TrieEdge &edge : _children) {
StringRef edgeStr = edge._subString;
@@ -1110,7 +1258,7 @@ void MachOFileLayout::TrieNode::addSymbol(const Export& entry,
abEdge._subString = abEdgeStr;
abEdge._child = bNode;
auto *bcEdge = new (allocator) TrieEdge(bcEdgeStr, cNode);
- bNode->_children.push_back(std::move(*bcEdge));
+ bNode->_children.insert(bNode->_children.end(), bcEdge);
bNode->addSymbol(entry, allocator, allNodes);
return;
}
@@ -1125,7 +1273,7 @@ void MachOFileLayout::TrieNode::addSymbol(const Export& entry,
// No commonality with any existing child, make a new edge.
auto *newNode = new (allocator) TrieNode(entry.name.copy(allocator));
auto *newEdge = new (allocator) TrieEdge(partialStr, newNode);
- _children.push_back(std::move(*newEdge));
+ _children.insert(_children.end(), newEdge);
DEBUG_WITH_TYPE("trie-builder", llvm::dbgs()
<< "new TrieNode('" << entry.name << "') with edge '"
<< partialStr << "' from node='"
@@ -1139,7 +1287,7 @@ void MachOFileLayout::TrieNode::addSymbol(const Export& entry,
allNodes.push_back(newNode);
}
-bool MachOFileLayout::TrieNode::updateOffset(uint32_t& offset) {
+bool TrieNode::updateOffset(uint32_t& offset) {
uint32_t nodeSize = 1; // Length when no export info
if (_hasExportInfo) {
if (_flags & EXPORT_SYMBOL_FLAGS_REEXPORT) {
@@ -1171,7 +1319,7 @@ bool MachOFileLayout::TrieNode::updateOffset(uint32_t& offset) {
return result;
}
-void MachOFileLayout::TrieNode::appendToByteBuffer(ByteBuffer &out) {
+void TrieNode::appendToByteBuffer(ByteBuffer &out) {
if (_hasExportInfo) {
if (_flags & EXPORT_SYMBOL_FLAGS_REEXPORT) {
if (!_importedName.empty()) {
@@ -1290,6 +1438,10 @@ void MachOFileLayout::computeSymbolTableSizes() {
}
}
+void MachOFileLayout::computeFunctionStartsSize() {
+ _functionStartsSize = _file.functionStarts.size();
+}
+
void MachOFileLayout::computeDataInCodeSize() {
_dataInCodeSize = _file.dataInCode.size() * sizeof(data_in_code_entry);
}
@@ -1297,6 +1449,7 @@ void MachOFileLayout::computeDataInCodeSize() {
void MachOFileLayout::writeLinkEditContent() {
if (_file.fileType == llvm::MachO::MH_OBJECT) {
writeRelocations();
+ writeFunctionStartsInfo();
writeDataInCodeInfo();
writeSymbolTable();
} else {
@@ -1305,15 +1458,16 @@ void MachOFileLayout::writeLinkEditContent() {
writeLazyBindingInfo();
// TODO: add weak binding info
writeExportInfo();
+ writeFunctionStartsInfo();
writeDataInCodeInfo();
writeSymbolTable();
}
}
-std::error_code MachOFileLayout::writeBinary(StringRef path) {
+llvm::Error MachOFileLayout::writeBinary(StringRef path) {
// Check for pending error from constructor.
if (_ec)
- return _ec;
+ return llvm::errorCodeToError(_ec);
// Create FileOutputBuffer with calculated size.
unsigned flags = 0;
if (_file.fileType != llvm::MachO::MH_OBJECT)
@@ -1321,23 +1475,22 @@ std::error_code MachOFileLayout::writeBinary(StringRef path) {
ErrorOr<std::unique_ptr<llvm::FileOutputBuffer>> fobOrErr =
llvm::FileOutputBuffer::create(path, size(), flags);
if (std::error_code ec = fobOrErr.getError())
- return ec;
+ return llvm::errorCodeToError(ec);
std::unique_ptr<llvm::FileOutputBuffer> &fob = *fobOrErr;
// Write content.
_buffer = fob->getBufferStart();
writeMachHeader();
- std::error_code ec = writeLoadCommands();
- if (ec)
+ if (auto ec = writeLoadCommands())
return ec;
writeSectionContent();
writeLinkEditContent();
fob->commit();
- return std::error_code();
+ return llvm::Error();
}
/// Takes in-memory normalized view and writes a mach-o object file.
-std::error_code writeBinary(const NormalizedFile &file, StringRef path) {
+llvm::Error writeBinary(const NormalizedFile &file, StringRef path) {
MachOFileLayout layout(file);
return layout.writeBinary(path);
}
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
index 575bc1a2b3a9..4775c75f7211 100644
--- a/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
+++ b/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
@@ -92,23 +92,27 @@ struct SegmentInfo {
StringRef name;
uint64_t address;
uint64_t size;
- uint32_t access;
+ uint32_t init_access;
+ uint32_t max_access;
std::vector<SectionInfo*> sections;
uint32_t normalizedSegmentIndex;
};
SegmentInfo::SegmentInfo(StringRef n)
- : name(n), address(0), size(0), access(0), normalizedSegmentIndex(0) {
+ : name(n), address(0), size(0), init_access(0), max_access(0),
+ normalizedSegmentIndex(0) {
}
class Util {
public:
Util(const MachOLinkingContext &ctxt)
: _ctx(ctxt), _archHandler(ctxt.archHandler()), _entryAtom(nullptr),
- _hasTLVDescriptors(false) {}
+ _hasTLVDescriptors(false), _subsectionsViaSymbols(true) {}
~Util();
- void assignAtomsToSections(const lld::File &atomFile);
+ void processDefinedAtoms(const lld::File &atomFile);
+ void processAtomAttributes(const DefinedAtom *atom);
+ void assignAtomToSection(const DefinedAtom *atom);
void organizeSections();
void assignAddressesToSections(const NormalizedFile &file);
uint32_t fileFlags();
@@ -116,16 +120,29 @@ public:
void copySectionInfo(NormalizedFile &file);
void updateSectionInfo(NormalizedFile &file);
void buildAtomToAddressMap();
- std::error_code addSymbols(const lld::File &atomFile, NormalizedFile &file);
+ llvm::Error addSymbols(const lld::File &atomFile, NormalizedFile &file);
void addIndirectSymbols(const lld::File &atomFile, NormalizedFile &file);
void addRebaseAndBindingInfo(const lld::File &, NormalizedFile &file);
void addExportInfo(const lld::File &, NormalizedFile &file);
void addSectionRelocs(const lld::File &, NormalizedFile &file);
+ void addFunctionStarts(const lld::File &, NormalizedFile &file);
void buildDataInCodeArray(const lld::File &, NormalizedFile &file);
void addDependentDylibs(const lld::File &, NormalizedFile &file);
void copyEntryPointAddress(NormalizedFile &file);
void copySectionContent(NormalizedFile &file);
+ bool allSourceFilesHaveMinVersions() const {
+ return _allSourceFilesHaveMinVersions;
+ }
+
+ uint32_t minVersion() const {
+ return _minVersion;
+ }
+
+ LoadCommandType minVersionCommandType() const {
+ return _minVersionCommandType;
+ }
+
private:
typedef std::map<DefinedAtom::ContentType, SectionInfo*> TypeToSection;
typedef llvm::DenseMap<const Atom*, uint64_t> AtomToAddress;
@@ -147,9 +164,9 @@ private:
uint8_t &segmentIndex, uint64_t &segmentStartAddr);
const Atom *targetOfLazyPointer(const DefinedAtom *lpAtom);
const Atom *targetOfStub(const DefinedAtom *stubAtom);
- std::error_code getSymbolTableRegion(const DefinedAtom* atom,
- bool &inGlobalsRegion,
- SymbolScope &symbolScope);
+ llvm::Error getSymbolTableRegion(const DefinedAtom* atom,
+ bool &inGlobalsRegion,
+ SymbolScope &symbolScope);
void appendSection(SectionInfo *si, NormalizedFile &file);
uint32_t sectionIndexForAtom(const Atom *atom);
@@ -180,6 +197,10 @@ private:
AtomToIndex _atomToSymbolIndex;
std::vector<const Atom *> _machHeaderAliasAtoms;
bool _hasTLVDescriptors;
+ bool _subsectionsViaSymbols;
+ bool _allSourceFilesHaveMinVersions = true;
+ LoadCommandType _minVersionCommandType = (LoadCommandType)0;
+ uint32_t _minVersion = 0;
};
Util::~Util() {
@@ -239,6 +260,7 @@ struct MachOFinalSectionFromAtomType {
const MachOFinalSectionFromAtomType sectsToAtomType[] = {
ENTRY("__TEXT", "__text", S_REGULAR, typeCode),
+ ENTRY("__TEXT", "__text", S_REGULAR, typeMachHeader),
ENTRY("__TEXT", "__cstring", S_CSTRING_LITERALS, typeCString),
ENTRY("__TEXT", "__ustring", S_REGULAR, typeUTF16String),
ENTRY("__TEXT", "__const", S_REGULAR, typeConstant),
@@ -261,6 +283,8 @@ const MachOFinalSectionFromAtomType sectsToAtomType[] = {
typeTerminatorPtr),
ENTRY("__DATA", "__got", S_NON_LAZY_SYMBOL_POINTERS,
typeGOT),
+ ENTRY("__DATA", "__nl_symbol_ptr", S_NON_LAZY_SYMBOL_POINTERS,
+ typeNonLazyPointer),
ENTRY("__DATA", "__thread_vars", S_THREAD_LOCAL_VARIABLES,
typeThunkTLV),
ENTRY("__DATA", "__thread_data", S_THREAD_LOCAL_REGULAR,
@@ -280,10 +304,11 @@ SectionInfo *Util::getFinalSection(DefinedAtom::ContentType atomType) {
continue;
SectionAttr sectionAttrs = 0;
switch (atomType) {
+ case DefinedAtom::typeMachHeader:
case DefinedAtom::typeCode:
case DefinedAtom::typeStub:
case DefinedAtom::typeStubHelper:
- sectionAttrs = S_ATTR_PURE_INSTRUCTIONS;
+ sectionAttrs = S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS;
break;
case DefinedAtom::typeThunkTLV:
_hasTLVDescriptors = true;
@@ -366,27 +391,85 @@ void Util::appendAtom(SectionInfo *sect, const DefinedAtom *atom) {
sect->size = offset + atom->size();
}
-void Util::assignAtomsToSections(const lld::File &atomFile) {
+void Util::processDefinedAtoms(const lld::File &atomFile) {
for (const DefinedAtom *atom : atomFile.defined()) {
- if (atom->contentType() == DefinedAtom::typeMachHeader)
- _machHeaderAliasAtoms.push_back(atom);
+ processAtomAttributes(atom);
+ assignAtomToSection(atom);
+ }
+}
+
+void Util::processAtomAttributes(const DefinedAtom *atom) {
+ if (auto *machoFile = dyn_cast<mach_o::MachOFile>(&atom->file())) {
+ // If the file doesn't use subsections via symbols, then make sure we don't
+ // add that flag to the final output file if we have a relocatable file.
+ if (!machoFile->subsectionsViaSymbols())
+ _subsectionsViaSymbols = false;
+
+ // All the source files must have min versions for us to output an object
+ // file with a min version.
+ if (auto v = machoFile->minVersion())
+ _minVersion = std::max(_minVersion, v);
else
- appendAtom(sectionForAtom(atom), atom);
+ _allSourceFilesHaveMinVersions = false;
+
+ // If we don't have a platform load command, but one of the source files
+ // does, then take the one from the file.
+ if (!_minVersionCommandType)
+ if (auto v = machoFile->minVersionLoadCommandKind())
+ _minVersionCommandType = v;
}
}
+void Util::assignAtomToSection(const DefinedAtom *atom) {
+ if (atom->contentType() == DefinedAtom::typeMachHeader) {
+ _machHeaderAliasAtoms.push_back(atom);
+ // Assign atom to this section with this offset.
+ AtomInfo ai = {atom, 0};
+ sectionForAtom(atom)->atomsAndOffsets.push_back(ai);
+ } else if (atom->contentType() == DefinedAtom::typeDSOHandle)
+ _machHeaderAliasAtoms.push_back(atom);
+ else
+ appendAtom(sectionForAtom(atom), atom);
+}
+
SegmentInfo *Util::segmentForName(StringRef segName) {
for (SegmentInfo *si : _segmentInfos) {
if ( si->name.equals(segName) )
return si;
}
auto *info = new (_allocator) SegmentInfo(segName);
+
+ // Set the initial segment protection.
if (segName.equals("__TEXT"))
- info->access = VM_PROT_READ | VM_PROT_EXECUTE;
- else if (segName.equals("__DATA"))
- info->access = VM_PROT_READ | VM_PROT_WRITE;
+ info->init_access = VM_PROT_READ | VM_PROT_EXECUTE;
else if (segName.equals("__PAGEZERO"))
- info->access = 0;
+ info->init_access = 0;
+ else if (segName.equals("__LINKEDIT"))
+ info->init_access = VM_PROT_READ;
+ else {
+ // All others default to read-write
+ info->init_access = VM_PROT_READ | VM_PROT_WRITE;
+ }
+
+ // Set max segment protection
+ // Note, its overkill to use a switch statement here, but makes it so much
+ // easier to use switch coverage to catch new cases.
+ switch (_ctx.os()) {
+ case lld::MachOLinkingContext::OS::unknown:
+ case lld::MachOLinkingContext::OS::macOSX:
+ case lld::MachOLinkingContext::OS::iOS_simulator:
+ if (segName.equals("__PAGEZERO")) {
+ info->max_access = 0;
+ break;
+ }
+ // All others default to all
+ info->max_access = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
+ break;
+ case lld::MachOLinkingContext::OS::iOS:
+ // iPhoneOS always uses same protection for max and initial
+ info->max_access = info->init_access;
+ break;
+ }
_segmentInfos.push_back(info);
return info;
}
@@ -436,6 +519,8 @@ void Util::organizeSections() {
default:
break;
}
+ segmentForName("__LINKEDIT");
+
// Group sections into segments.
for (SectionInfo *si : _sectionInfos) {
SegmentInfo *seg = segmentForName(si->segmentName);
@@ -465,10 +550,10 @@ void Util::organizeSections() {
void Util::layoutSectionsInSegment(SegmentInfo *seg, uint64_t &addr) {
seg->address = addr;
for (SectionInfo *sect : seg->sections) {
- sect->address = llvm::RoundUpToAlignment(addr, sect->alignment);
+ sect->address = llvm::alignTo(addr, sect->alignment);
addr = sect->address + sect->size;
}
- seg->size = llvm::RoundUpToAlignment(addr - seg->address, _ctx.pageSize());
+ seg->size = llvm::alignTo(addr - seg->address, _ctx.pageSize());
}
// __TEXT segment lays out backwards so padding is at front after load commands.
@@ -488,10 +573,10 @@ void Util::layoutSectionsInTextSegment(size_t hlcSize, SegmentInfo *seg,
// Start assigning section address starting at padded offset.
addr += (padding + hlcSize);
for (SectionInfo *sect : seg->sections) {
- sect->address = llvm::RoundUpToAlignment(addr, sect->alignment);
+ sect->address = llvm::alignTo(addr, sect->alignment);
addr = sect->address + sect->size;
}
- seg->size = llvm::RoundUpToAlignment(addr - seg->address, _ctx.pageSize());
+ seg->size = llvm::alignTo(addr - seg->address, _ctx.pageSize());
}
void Util::assignAddressesToSections(const NormalizedFile &file) {
@@ -511,7 +596,7 @@ void Util::assignAddressesToSections(const NormalizedFile &file) {
} else
layoutSectionsInSegment(seg, address);
- address = llvm::RoundUpToAlignment(address, _ctx.pageSize());
+ address = llvm::alignTo(address, _ctx.pageSize());
}
DEBUG_WITH_TYPE("WriterMachO-norm",
llvm::dbgs() << "assignAddressesToSections()\n";
@@ -536,7 +621,8 @@ void Util::copySegmentInfo(NormalizedFile &file) {
seg.name = sgi->name;
seg.address = sgi->address;
seg.size = sgi->size;
- seg.access = sgi->access;
+ seg.init_access = sgi->init_access;
+ seg.max_access = sgi->max_access;
file.segments.push_back(seg);
}
}
@@ -583,11 +669,20 @@ void Util::copySectionContent(NormalizedFile &file) {
continue;
}
// Copy content from atoms to content buffer for section.
- uint8_t *sectionContent = file.ownedAllocations.Allocate<uint8_t>(si->size);
- normSect->content = llvm::makeArrayRef(sectionContent, si->size);
+ llvm::MutableArrayRef<uint8_t> sectionContent;
+ if (si->size) {
+ uint8_t *sectContent = file.ownedAllocations.Allocate<uint8_t>(si->size);
+ sectionContent = llvm::MutableArrayRef<uint8_t>(sectContent, si->size);
+ normSect->content = sectionContent;
+ }
for (AtomInfo &ai : si->atomsAndOffsets) {
- uint8_t *atomContent = reinterpret_cast<uint8_t*>
- (&sectionContent[ai.offsetInSection]);
+ if (!ai.atom->size()) {
+ assert(ai.atom->begin() == ai.atom->end() &&
+ "Cannot have references without content");
+ continue;
+ }
+ auto atomContent = sectionContent.slice(ai.offsetInSection,
+ ai.atom->size());
_archHandler.generateAtomContent(*ai.atom, r, addrForAtom,
sectionAddrForAtom, _ctx.baseAddress(),
atomContent);
@@ -620,6 +715,11 @@ void Util::updateSectionInfo(NormalizedFile &file) {
}
void Util::copyEntryPointAddress(NormalizedFile &nFile) {
+ if (!_entryAtom) {
+ nFile.entryAddress = 0;
+ return;
+ }
+
if (_ctx.outputTypeHasEntry()) {
if (_archHandler.isThumbFunction(*_entryAtom))
nFile.entryAddress = (_atomToAddress[_entryAtom] | 1);
@@ -703,6 +803,8 @@ uint16_t Util::descBits(const DefinedAtom* atom) {
}
if (atom->contentType() == lld::DefinedAtom::typeResolver)
desc |= N_SYMBOL_RESOLVER;
+ if (atom->contentType() == lld::DefinedAtom::typeMachHeader)
+ desc |= REFERENCED_DYNAMICALLY;
if (_archHandler.isThumbFunction(*atom))
desc |= N_ARM_THUMB_DEF;
if (atom->deadStrip() == DefinedAtom::deadStripNever) {
@@ -718,56 +820,56 @@ bool Util::AtomSorter::operator()(const AtomAndIndex &left,
return (left.atom->name().compare(right.atom->name()) < 0);
}
-std::error_code Util::getSymbolTableRegion(const DefinedAtom* atom,
- bool &inGlobalsRegion,
- SymbolScope &scope) {
+llvm::Error Util::getSymbolTableRegion(const DefinedAtom* atom,
+ bool &inGlobalsRegion,
+ SymbolScope &scope) {
bool rMode = (_ctx.outputMachOType() == llvm::MachO::MH_OBJECT);
switch (atom->scope()) {
case Atom::scopeTranslationUnit:
scope = 0;
inGlobalsRegion = false;
- return std::error_code();
+ return llvm::Error();
case Atom::scopeLinkageUnit:
if ((_ctx.exportMode() == MachOLinkingContext::ExportMode::whiteList) &&
_ctx.exportSymbolNamed(atom->name())) {
- return make_dynamic_error_code(Twine("cannot export hidden symbol ")
- + atom->name());
+ return llvm::make_error<GenericError>(
+ Twine("cannot export hidden symbol ") + atom->name());
}
if (rMode) {
if (_ctx.keepPrivateExterns()) {
// -keep_private_externs means keep in globals region as N_PEXT.
scope = N_PEXT | N_EXT;
inGlobalsRegion = true;
- return std::error_code();
+ return llvm::Error();
}
}
// scopeLinkageUnit symbols are no longer global once linked.
scope = N_PEXT;
inGlobalsRegion = false;
- return std::error_code();
+ return llvm::Error();
case Atom::scopeGlobal:
if (_ctx.exportRestrictMode()) {
if (_ctx.exportSymbolNamed(atom->name())) {
scope = N_EXT;
inGlobalsRegion = true;
- return std::error_code();
+ return llvm::Error();
} else {
scope = N_PEXT;
inGlobalsRegion = false;
- return std::error_code();
+ return llvm::Error();
}
} else {
scope = N_EXT;
inGlobalsRegion = true;
- return std::error_code();
+ return llvm::Error();
}
break;
}
llvm_unreachable("atom->scope() unknown enum value");
}
-std::error_code Util::addSymbols(const lld::File &atomFile,
- NormalizedFile &file) {
+llvm::Error Util::addSymbols(const lld::File &atomFile,
+ NormalizedFile &file) {
bool rMode = (_ctx.outputMachOType() == llvm::MachO::MH_OBJECT);
// Mach-O symbol table has three regions: locals, globals, undefs.
@@ -863,7 +965,7 @@ std::error_code Util::addSymbols(const lld::File &atomFile,
file.undefinedSymbols.push_back(sym);
}
- return std::error_code();
+ return llvm::Error();
}
const Atom *Util::targetOfLazyPointer(const DefinedAtom *lpAtom) {
@@ -1055,7 +1157,53 @@ void Util::addSectionRelocs(const lld::File &, NormalizedFile &file) {
}
}
+void Util::addFunctionStarts(const lld::File &, NormalizedFile &file) {
+ if (!_ctx.generateFunctionStartsLoadCommand())
+ return;
+ file.functionStarts.reserve(8192);
+ // Delta compress function starts, starting with the mach header symbol.
+ const uint64_t badAddress = ~0ULL;
+ uint64_t addr = badAddress;
+ for (SectionInfo *si : _sectionInfos) {
+ for (const AtomInfo &info : si->atomsAndOffsets) {
+ auto type = info.atom->contentType();
+ if (type == DefinedAtom::typeMachHeader) {
+ addr = _atomToAddress[info.atom];
+ continue;
+ }
+ if (type != DefinedAtom::typeCode)
+ continue;
+ assert(addr != badAddress && "Missing mach header symbol");
+ // Skip atoms which have 0 size. This is so that LC_FUNCTION_STARTS
+ // can't spill in to the next section.
+ if (!info.atom->size())
+ continue;
+ uint64_t nextAddr = _atomToAddress[info.atom];
+ if (_archHandler.isThumbFunction(*info.atom))
+ nextAddr |= 1;
+ uint64_t delta = nextAddr - addr;
+ if (delta) {
+ ByteBuffer buffer;
+ buffer.append_uleb128(delta);
+ file.functionStarts.insert(file.functionStarts.end(), buffer.bytes(),
+ buffer.bytes() + buffer.size());
+ }
+ addr = nextAddr;
+ }
+ }
+
+ // Null terminate, and pad to pointer size for this arch.
+ file.functionStarts.push_back(0);
+
+ auto size = file.functionStarts.size();
+ for (unsigned i = size, e = llvm::alignTo(size, _ctx.is64Bit() ? 8 : 4);
+ i != e; ++i)
+ file.functionStarts.push_back(0);
+}
+
void Util::buildDataInCodeArray(const lld::File &, NormalizedFile &file) {
+ if (!_ctx.generateDataInCodeLoadCommand())
+ return;
for (SectionInfo *si : _sectionInfos) {
for (const AtomInfo &info : si->atomsAndOffsets) {
// Atoms that contain data-in-code have "transition" references
@@ -1183,7 +1331,7 @@ void Util::addExportInfo(const lld::File &atomFile, NormalizedFile &nFile) {
uint32_t Util::fileFlags() {
// FIXME: these need to determined at runtime.
if (_ctx.outputMachOType() == MH_OBJECT) {
- return MH_SUBSECTIONS_VIA_SYMBOLS;
+ return _subsectionsViaSymbols ? MH_SUBSECTIONS_VIA_SYMBOLS : 0;
} else {
uint32_t flags = MH_DYLDLINK;
if (!_ctx.useFlatNamespace())
@@ -1203,12 +1351,12 @@ namespace mach_o {
namespace normalized {
/// Convert a set of Atoms into a normalized mach-o file.
-ErrorOr<std::unique_ptr<NormalizedFile>>
+llvm::Expected<std::unique_ptr<NormalizedFile>>
normalizedFromAtoms(const lld::File &atomFile,
const MachOLinkingContext &context) {
// The util object buffers info until the normalized file can be made.
Util util(context);
- util.assignAtomsToSections(atomFile);
+ util.processDefinedAtoms(atomFile);
util.organizeSections();
std::unique_ptr<NormalizedFile> f(new NormalizedFile());
@@ -1220,6 +1368,35 @@ normalizedFromAtoms(const lld::File &atomFile,
normFile.installName = context.installName();
normFile.currentVersion = context.currentVersion();
normFile.compatVersion = context.compatibilityVersion();
+ normFile.os = context.os();
+
+ // If we are emitting an object file, then the min version is the maximum
+ // of the min's of all the source files and the cmdline.
+ if (normFile.fileType == llvm::MachO::MH_OBJECT)
+ normFile.minOSverson = std::max(context.osMinVersion(), util.minVersion());
+ else
+ normFile.minOSverson = context.osMinVersion();
+
+ normFile.minOSVersionKind = util.minVersionCommandType();
+
+ normFile.sdkVersion = context.sdkVersion();
+ normFile.sourceVersion = context.sourceVersion();
+
+ if (context.generateVersionLoadCommand() &&
+ context.os() != MachOLinkingContext::OS::unknown)
+ normFile.hasMinVersionLoadCommand = true;
+ else if (normFile.fileType == llvm::MachO::MH_OBJECT &&
+ util.allSourceFilesHaveMinVersions() &&
+ ((normFile.os != MachOLinkingContext::OS::unknown) ||
+ util.minVersionCommandType())) {
+ // If we emit an object file, then it should contain a min version load
+ // command if all of the source files also contained min version commands.
+ // Also, we either need to have a platform, or found a platform from the
+ // source object files.
+ normFile.hasMinVersionLoadCommand = true;
+ }
+ normFile.generateDataInCodeLoadCommand =
+ context.generateDataInCodeLoadCommand();
normFile.pageSize = context.pageSize();
normFile.rpaths = context.rpaths();
util.addDependentDylibs(atomFile, normFile);
@@ -1230,12 +1407,13 @@ normalizedFromAtoms(const lld::File &atomFile,
util.updateSectionInfo(normFile);
util.copySectionContent(normFile);
if (auto ec = util.addSymbols(atomFile, normFile)) {
- return ec;
+ return std::move(ec);
}
util.addIndirectSymbols(atomFile, normFile);
util.addRebaseAndBindingInfo(atomFile, normFile);
util.addExportInfo(atomFile, normFile);
util.addSectionRelocs(atomFile, normFile);
+ util.addFunctionStarts(atomFile, normFile);
util.buildDataInCodeArray(atomFile, normFile);
util.copyEntryPointAddress(normFile);
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
index f9499b603214..fc760a3eddd0 100644
--- a/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
+++ b/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
@@ -88,6 +88,8 @@ const MachORelocatableSectionToAtomType sectsToAtomType[] = {
ENTRY("__DATA", "__thread_data", S_THREAD_LOCAL_REGULAR, typeTLVInitialData),
ENTRY("__DATA", "__thread_bss", S_THREAD_LOCAL_ZEROFILL,
typeTLVInitialZeroFill),
+ ENTRY("__DATA", "__objc_imageinfo", S_REGULAR, typeObjCImageInfo),
+ ENTRY("__DATA", "__objc_catlist", S_REGULAR, typeObjC2CategoryList),
ENTRY("", "", S_INTERPOSING, typeInterposingTuples),
ENTRY("__LD", "__compact_unwind", S_REGULAR,
typeCompactUnwindInfo),
@@ -180,6 +182,8 @@ void sectionParseInfo(DefinedAtom::ContentType atomType,
atomizeCU),
ENTRY(typeGOT, 4, scopeLinkageUnit, mergeByContent,
atomizePointerSize),
+ ENTRY(typeObjC2CategoryList, 4, scopeTranslationUnit, mergeByContent,
+ atomizePointerSize),
ENTRY(typeUnknown, 1, scopeGlobal, mergeNo,
atomizeAtSymbols)
};
@@ -265,11 +269,11 @@ void atomFromSymbol(DefinedAtom::ContentType atomType, const Section &section,
}
}
-std::error_code processSymboledSection(DefinedAtom::ContentType atomType,
- const Section &section,
- const NormalizedFile &normalizedFile,
- MachOFile &file, bool scatterable,
- bool copyRefs) {
+llvm::Error processSymboledSection(DefinedAtom::ContentType atomType,
+ const Section &section,
+ const NormalizedFile &normalizedFile,
+ MachOFile &file, bool scatterable,
+ bool copyRefs) {
// Find section's index.
uint32_t sectIndex = 1;
for (auto &sect : normalizedFile.sections) {
@@ -316,7 +320,7 @@ std::error_code processSymboledSection(DefinedAtom::ContentType atomType,
// If section has no symbols and no content, there are no atoms.
if (symbols.empty() && section.content.empty())
- return std::error_code();
+ return llvm::Error();
if (symbols.empty()) {
// Section has no symbols, put all content in one anoymous atom.
@@ -360,22 +364,22 @@ std::error_code processSymboledSection(DefinedAtom::ContentType atomType,
file.eachAtomInSection(section,
[&](MachODefinedAtom *atom, uint64_t offset)->void {
if (prevAtom)
- prevAtom->addReference(0, Reference::kindLayoutAfter, atom, 0,
+ prevAtom->addReference(Reference::KindNamespace::all,
Reference::KindArch::all,
- Reference::KindNamespace::all);
+ Reference::kindLayoutAfter, 0, atom, 0);
prevAtom = atom;
});
}
- return std::error_code();
+ return llvm::Error();
}
-std::error_code processSection(DefinedAtom::ContentType atomType,
- const Section &section,
- bool customSectionName,
- const NormalizedFile &normalizedFile,
- MachOFile &file, bool scatterable,
- bool copyRefs) {
+llvm::Error processSection(DefinedAtom::ContentType atomType,
+ const Section &section,
+ bool customSectionName,
+ const NormalizedFile &normalizedFile,
+ MachOFile &file, bool scatterable,
+ bool copyRefs) {
const bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch);
const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
@@ -388,12 +392,13 @@ std::error_code processSection(DefinedAtom::ContentType atomType,
// Validate section size.
if ((section.content.size() % sizeMultiple) != 0)
- return make_dynamic_error_code(Twine("Section ") + section.segmentName
- + "/" + section.sectionName
- + " has size ("
- + Twine(section.content.size())
- + ") which is not a multiple of "
- + Twine(sizeMultiple) );
+ return llvm::make_error<GenericError>(Twine("Section ")
+ + section.segmentName
+ + "/" + section.sectionName
+ + " has size ("
+ + Twine(section.content.size())
+ + ") which is not a multiple of "
+ + Twine(sizeMultiple));
if (atomizeModel == atomizeAtSymbols) {
// Break section up into atoms each with a fixed size.
@@ -435,13 +440,13 @@ std::error_code processSection(DefinedAtom::ContentType atomType,
// Break section up into dwarf unwind CFIs (FDE or CIE).
size = read32(&section.content[offset], isBig) + 4;
if (offset+size > section.content.size()) {
- return make_dynamic_error_code(Twine(Twine("Section ")
- + section.segmentName
- + "/" + section.sectionName
- + " is malformed. Size of CFI "
- "starting at offset ("
- + Twine(offset)
- + ") is past end of section."));
+ return llvm::make_error<GenericError>(Twine("Section ")
+ + section.segmentName
+ + "/" + section.sectionName
+ + " is malformed. Size of CFI "
+ "starting at offset ("
+ + Twine(offset)
+ + ") is past end of section.");
}
break;
case atomizeCU:
@@ -456,10 +461,11 @@ std::error_code processSection(DefinedAtom::ContentType atomType,
break;
}
if (size == 0) {
- return make_dynamic_error_code(Twine("Section ") + section.segmentName
- + "/" + section.sectionName
- + " is malformed. The last atom is "
- "not zero terminated.");
+ return llvm::make_error<GenericError>(Twine("Section ")
+ + section.segmentName
+ + "/" + section.sectionName
+ + " is malformed. The last atom "
+ "is not zero terminated.");
}
if (customSectionName) {
// Mach-O needs a segment and section name. Concatentate those two
@@ -477,7 +483,7 @@ std::error_code processSection(DefinedAtom::ContentType atomType,
offset += size;
}
}
- return std::error_code();
+ return llvm::Error();
}
const Section* findSectionCoveringAddress(const NormalizedFile &normalizedFile,
@@ -509,23 +515,23 @@ findAtomCoveringAddress(const NormalizedFile &normalizedFile, MachOFile &file,
// Walks all relocations for a section in a normalized .o file and
// creates corresponding lld::Reference objects.
-std::error_code convertRelocs(const Section &section,
- const NormalizedFile &normalizedFile,
- bool scatterable,
- MachOFile &file,
- ArchHandler &handler) {
+llvm::Error convertRelocs(const Section &section,
+ const NormalizedFile &normalizedFile,
+ bool scatterable,
+ MachOFile &file,
+ ArchHandler &handler) {
// Utility function for ArchHandler to find atom by its address.
auto atomByAddr = [&] (uint32_t sectIndex, uint64_t addr,
const lld::Atom **atom, Reference::Addend *addend)
- -> std::error_code {
+ -> llvm::Error {
if (sectIndex > normalizedFile.sections.size())
- return make_dynamic_error_code(Twine("out of range section "
+ return llvm::make_error<GenericError>(Twine("out of range section "
"index (") + Twine(sectIndex) + ")");
const Section *sect = nullptr;
if (sectIndex == 0) {
sect = findSectionCoveringAddress(normalizedFile, addr);
if (!sect)
- return make_dynamic_error_code(Twine("address (" + Twine(addr)
+ return llvm::make_error<GenericError>(Twine("address (" + Twine(addr)
+ ") is not in any section"));
} else {
sect = &normalizedFile.sections[sectIndex-1];
@@ -534,12 +540,12 @@ std::error_code convertRelocs(const Section &section,
uint64_t offsetInSect = addr - sect->address;
*atom = file.findAtomCoveringAddress(*sect, offsetInSect, &offsetInTarget);
*addend = offsetInTarget;
- return std::error_code();
+ return llvm::Error();
};
// Utility function for ArchHandler to find atom by its symbol index.
auto atomBySymbol = [&] (uint32_t symbolIndex, const lld::Atom **result)
- -> std::error_code {
+ -> llvm::Error {
// Find symbol from index.
const Symbol *sym = nullptr;
uint32_t numLocal = normalizedFile.localSymbols.size();
@@ -552,13 +558,13 @@ std::error_code convertRelocs(const Section &section,
} else if (symbolIndex < numLocal+numGlobal+numUndef) {
sym = &normalizedFile.undefinedSymbols[symbolIndex-numLocal-numGlobal];
} else {
- return make_dynamic_error_code(Twine("symbol index (")
+ return llvm::make_error<GenericError>(Twine("symbol index (")
+ Twine(symbolIndex) + ") out of range");
}
// Find atom from symbol.
if ((sym->type & N_TYPE) == N_SECT) {
if (sym->sect > normalizedFile.sections.size())
- return make_dynamic_error_code(Twine("symbol section index (")
+ return llvm::make_error<GenericError>(Twine("symbol section index (")
+ Twine(sym->sect) + ") out of range ");
const Section &symSection = normalizedFile.sections[sym->sect-1];
uint64_t targetOffsetInSect = sym->value - symSection.address;
@@ -566,19 +572,19 @@ std::error_code convertRelocs(const Section &section,
targetOffsetInSect);
if (target) {
*result = target;
- return std::error_code();
+ return llvm::Error();
}
- return make_dynamic_error_code("no atom found for defined symbol");
+ return llvm::make_error<GenericError>("no atom found for defined symbol");
} else if ((sym->type & N_TYPE) == N_UNDF) {
const lld::Atom *target = file.findUndefAtom(sym->name);
if (target) {
*result = target;
- return std::error_code();
+ return llvm::Error();
}
- return make_dynamic_error_code("no undefined atom found for sym");
+ return llvm::make_error<GenericError>("no undefined atom found for sym");
} else {
// Search undefs
- return make_dynamic_error_code("no atom found for symbol");
+ return llvm::make_error<GenericError>("no atom found for symbol");
}
};
@@ -589,7 +595,8 @@ std::error_code convertRelocs(const Section &section,
const Relocation &reloc = *it;
// Find atom this relocation is in.
if (reloc.offset > section.content.size())
- return make_dynamic_error_code(Twine("r_address (") + Twine(reloc.offset)
+ return llvm::make_error<GenericError>(
+ Twine("r_address (") + Twine(reloc.offset)
+ ") is larger than section size ("
+ Twine(section.content.size()) + ")");
uint32_t offsetInAtom;
@@ -602,68 +609,74 @@ std::error_code convertRelocs(const Section &section,
const lld::Atom *target = nullptr;
Reference::Addend addend = 0;
Reference::KindValue kind;
- std::error_code relocErr;
if (handler.isPairedReloc(reloc)) {
// Handle paired relocations together.
const Relocation &reloc2 = *++it;
- relocErr = handler.getPairReferenceInfo(
+ auto relocErr = handler.getPairReferenceInfo(
reloc, reloc2, inAtom, offsetInAtom, fixupAddress, isBig, scatterable,
atomByAddr, atomBySymbol, &kind, &target, &addend);
if (relocErr) {
- return make_dynamic_error_code(
- Twine("bad relocation (") + relocErr.message()
- + ") in section "
- + section.segmentName + "/" + section.sectionName
- + " (r1_address=" + Twine::utohexstr(reloc.offset)
- + ", r1_type=" + Twine(reloc.type)
- + ", r1_extern=" + Twine(reloc.isExtern)
- + ", r1_length=" + Twine((int)reloc.length)
- + ", r1_pcrel=" + Twine(reloc.pcRel)
- + (!reloc.scattered ? (Twine(", r1_symbolnum=")
- + Twine(reloc.symbol))
- : (Twine(", r1_scattered=1, r1_value=")
- + Twine(reloc.value)))
- + ")"
- + ", (r2_address=" + Twine::utohexstr(reloc2.offset)
- + ", r2_type=" + Twine(reloc2.type)
- + ", r2_extern=" + Twine(reloc2.isExtern)
- + ", r2_length=" + Twine((int)reloc2.length)
- + ", r2_pcrel=" + Twine(reloc2.pcRel)
- + (!reloc2.scattered ? (Twine(", r2_symbolnum=")
- + Twine(reloc2.symbol))
- : (Twine(", r2_scattered=1, r2_value=")
- + Twine(reloc2.value)))
- + ")" );
+ return handleErrors(std::move(relocErr),
+ [&](std::unique_ptr<GenericError> GE) {
+ return llvm::make_error<GenericError>(
+ Twine("bad relocation (") + GE->getMessage()
+ + ") in section "
+ + section.segmentName + "/" + section.sectionName
+ + " (r1_address=" + Twine::utohexstr(reloc.offset)
+ + ", r1_type=" + Twine(reloc.type)
+ + ", r1_extern=" + Twine(reloc.isExtern)
+ + ", r1_length=" + Twine((int)reloc.length)
+ + ", r1_pcrel=" + Twine(reloc.pcRel)
+ + (!reloc.scattered ? (Twine(", r1_symbolnum=")
+ + Twine(reloc.symbol))
+ : (Twine(", r1_scattered=1, r1_value=")
+ + Twine(reloc.value)))
+ + ")"
+ + ", (r2_address=" + Twine::utohexstr(reloc2.offset)
+ + ", r2_type=" + Twine(reloc2.type)
+ + ", r2_extern=" + Twine(reloc2.isExtern)
+ + ", r2_length=" + Twine((int)reloc2.length)
+ + ", r2_pcrel=" + Twine(reloc2.pcRel)
+ + (!reloc2.scattered ? (Twine(", r2_symbolnum=")
+ + Twine(reloc2.symbol))
+ : (Twine(", r2_scattered=1, r2_value=")
+ + Twine(reloc2.value)))
+ + ")" );
+ });
}
}
else {
// Use ArchHandler to convert relocation record into information
// needed to instantiate an lld::Reference object.
- relocErr = handler.getReferenceInfo(
+ auto relocErr = handler.getReferenceInfo(
reloc, inAtom, offsetInAtom, fixupAddress, isBig, atomByAddr,
atomBySymbol, &kind, &target, &addend);
if (relocErr) {
- return make_dynamic_error_code(
- Twine("bad relocation (") + relocErr.message()
- + ") in section "
- + section.segmentName + "/" + section.sectionName
- + " (r_address=" + Twine::utohexstr(reloc.offset)
- + ", r_type=" + Twine(reloc.type)
- + ", r_extern=" + Twine(reloc.isExtern)
- + ", r_length=" + Twine((int)reloc.length)
- + ", r_pcrel=" + Twine(reloc.pcRel)
- + (!reloc.scattered ? (Twine(", r_symbolnum=") + Twine(reloc.symbol))
- : (Twine(", r_scattered=1, r_value=")
- + Twine(reloc.value)))
- + ")" );
+ return handleErrors(std::move(relocErr),
+ [&](std::unique_ptr<GenericError> GE) {
+ return llvm::make_error<GenericError>(
+ Twine("bad relocation (") + GE->getMessage()
+ + ") in section "
+ + section.segmentName + "/" + section.sectionName
+ + " (r_address=" + Twine::utohexstr(reloc.offset)
+ + ", r_type=" + Twine(reloc.type)
+ + ", r_extern=" + Twine(reloc.isExtern)
+ + ", r_length=" + Twine((int)reloc.length)
+ + ", r_pcrel=" + Twine(reloc.pcRel)
+ + (!reloc.scattered ? (Twine(", r_symbolnum=") + Twine(reloc.symbol))
+ : (Twine(", r_scattered=1, r_value=")
+ + Twine(reloc.value)))
+ + ")" );
+ });
}
}
// Instantiate an lld::Reference object and add to its atom.
- inAtom->addReference(offsetInAtom, kind, target, addend,
- handler.kindArch());
+ inAtom->addReference(Reference::KindNamespace::mach_o,
+ handler.kindArch(),
+ kind, offsetInAtom, target, addend);
}
- return std::error_code();
+ return llvm::Error();
}
bool isDebugInfoSection(const Section &section) {
@@ -684,44 +697,81 @@ static int64_t readSPtr(bool is64, bool isBig, const uint8_t *addr) {
struct CIEInfo {
bool _augmentationDataPresent = false;
- bool _mayHaveLSDA = false;
+ bool _mayHaveEH = false;
+ uint32_t _offsetOfLSDA = ~0U;
+ uint32_t _offsetOfPersonality = ~0U;
+ uint32_t _offsetOfFDEPointerEncoding = ~0U;
+ uint32_t _augmentationDataLength = ~0U;
};
typedef llvm::DenseMap<const MachODefinedAtom*, CIEInfo> CIEInfoMap;
-static std::error_code processAugmentationString(const uint8_t *augStr,
- CIEInfo &cieInfo,
- unsigned *len = nullptr) {
+static llvm::Error processAugmentationString(const uint8_t *augStr,
+ CIEInfo &cieInfo,
+ unsigned &len) {
if (augStr[0] == '\0') {
- if (len)
- *len = 1;
- return std::error_code();
+ len = 1;
+ return llvm::Error();
}
if (augStr[0] != 'z')
- return make_dynamic_error_code("expected 'z' at start of augmentation "
- "string");
+ return llvm::make_error<GenericError>("expected 'z' at start of "
+ "augmentation string");
cieInfo._augmentationDataPresent = true;
uint64_t idx = 1;
+ uint32_t offsetInAugmentationData = 0;
while (augStr[idx] != '\0') {
if (augStr[idx] == 'L') {
- cieInfo._mayHaveLSDA = true;
+ cieInfo._offsetOfLSDA = offsetInAugmentationData;
+ // This adds a single byte to the augmentation data.
+ ++offsetInAugmentationData;
+ ++idx;
+ continue;
+ }
+ if (augStr[idx] == 'P') {
+ cieInfo._offsetOfPersonality = offsetInAugmentationData;
+ // This adds a single byte to the augmentation data for the encoding,
+ // then a number of bytes for the pointer data.
+ // FIXME: We are assuming 4 is correct here for the pointer size as we
+ // always currently use delta32ToGOT.
+ offsetInAugmentationData += 5;
++idx;
- } else
+ continue;
+ }
+ if (augStr[idx] == 'R') {
+ cieInfo._offsetOfFDEPointerEncoding = offsetInAugmentationData;
+ // This adds a single byte to the augmentation data.
+ ++offsetInAugmentationData;
++idx;
+ continue;
+ }
+ if (augStr[idx] == 'e') {
+ if (augStr[idx + 1] != 'h')
+ return llvm::make_error<GenericError>("expected 'eh' in "
+ "augmentation string");
+ cieInfo._mayHaveEH = true;
+ idx += 2;
+ continue;
+ }
+ ++idx;
}
- if (len)
- *len = idx + 1;
- return std::error_code();
+ cieInfo._augmentationDataLength = offsetInAugmentationData;
+
+ len = idx + 1;
+ return llvm::Error();
}
-static std::error_code processCIE(const NormalizedFile &normalizedFile,
- MachODefinedAtom *atom,
- CIEInfoMap &cieInfos) {
+static llvm::Error processCIE(const NormalizedFile &normalizedFile,
+ MachOFile &file,
+ mach_o::ArchHandler &handler,
+ const Section *ehFrameSection,
+ MachODefinedAtom *atom,
+ uint64_t offset,
+ CIEInfoMap &cieInfos) {
const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
const uint8_t *frameData = atom->rawContent().data();
@@ -734,31 +784,170 @@ static std::error_code processCIE(const NormalizedFile &normalizedFile,
uint64_t versionField = cieIDField + sizeof(uint32_t);
uint64_t augmentationStringField = versionField + sizeof(uint8_t);
+ unsigned augmentationStringLength = 0;
if (auto err = processAugmentationString(frameData + augmentationStringField,
- cieInfo))
+ cieInfo, augmentationStringLength))
return err;
+ if (cieInfo._offsetOfPersonality != ~0U) {
+ // If we have augmentation data for the personality function, then we may
+ // need to implicitly generate its relocation.
+
+ // Parse the EH Data field which is pointer sized.
+ uint64_t EHDataField = augmentationStringField + augmentationStringLength;
+ const bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch);
+ unsigned EHDataFieldSize = (cieInfo._mayHaveEH ? (is64 ? 8 : 4) : 0);
+
+ // Parse Code Align Factor which is a ULEB128.
+ uint64_t CodeAlignField = EHDataField + EHDataFieldSize;
+ unsigned lengthFieldSize = 0;
+ llvm::decodeULEB128(frameData + CodeAlignField, &lengthFieldSize);
+
+ // Parse Data Align Factor which is a SLEB128.
+ uint64_t DataAlignField = CodeAlignField + lengthFieldSize;
+ llvm::decodeSLEB128(frameData + DataAlignField, &lengthFieldSize);
+
+ // Parse Return Address Register which is a byte.
+ uint64_t ReturnAddressField = DataAlignField + lengthFieldSize;
+
+ // Parse the augmentation length which is a ULEB128.
+ uint64_t AugmentationLengthField = ReturnAddressField + 1;
+ uint64_t AugmentationLength =
+ llvm::decodeULEB128(frameData + AugmentationLengthField,
+ &lengthFieldSize);
+
+ if (AugmentationLength != cieInfo._augmentationDataLength)
+ return llvm::make_error<GenericError>("CIE augmentation data length "
+ "mismatch");
+
+ // Get the start address of the augmentation data.
+ uint64_t AugmentationDataField = AugmentationLengthField + lengthFieldSize;
+
+ // Parse the personality function from the augmentation data.
+ uint64_t PersonalityField =
+ AugmentationDataField + cieInfo._offsetOfPersonality;
+
+ // Parse the personality encoding.
+ // FIXME: Verify that this is a 32-bit pcrel offset.
+ uint64_t PersonalityFunctionField = PersonalityField + 1;
+
+ if (atom->begin() != atom->end()) {
+ // If we have an explicit relocation, then make sure it matches this
+ // offset as this is where we'd expect it to be applied to.
+ DefinedAtom::reference_iterator CurrentRef = atom->begin();
+ if (CurrentRef->offsetInAtom() != PersonalityFunctionField)
+ return llvm::make_error<GenericError>("CIE personality reloc at "
+ "wrong offset");
+
+ if (++CurrentRef != atom->end())
+ return llvm::make_error<GenericError>("CIE contains too many relocs");
+ } else {
+ // Implicitly generate the personality function reloc. It's assumed to
+ // be a delta32 offset to a GOT entry.
+ // FIXME: Parse the encoding and check this.
+ int32_t funcDelta = read32(frameData + PersonalityFunctionField, isBig);
+ uint64_t funcAddress = ehFrameSection->address + offset +
+ PersonalityFunctionField;
+ funcAddress += funcDelta;
+
+ const MachODefinedAtom *func = nullptr;
+ Reference::Addend addend;
+ func = findAtomCoveringAddress(normalizedFile, file, funcAddress,
+ &addend);
+ atom->addReference(Reference::KindNamespace::mach_o, handler.kindArch(),
+ handler.unwindRefToPersonalityFunctionKind(),
+ PersonalityFunctionField, func, addend);
+ }
+ } else if (atom->begin() != atom->end()) {
+ // Otherwise, we expect there to be no relocations in this atom as the only
+ // relocation would have been to the personality function.
+ return llvm::make_error<GenericError>("unexpected relocation in CIE");
+ }
+
+
cieInfos[atom] = std::move(cieInfo);
- return std::error_code();
+ return llvm::Error();
}
-static std::error_code processFDE(const NormalizedFile &normalizedFile,
- MachOFile &file,
- mach_o::ArchHandler &handler,
- const Section *ehFrameSection,
- MachODefinedAtom *atom,
- uint64_t offset,
- const CIEInfoMap &cieInfos) {
+static llvm::Error processFDE(const NormalizedFile &normalizedFile,
+ MachOFile &file,
+ mach_o::ArchHandler &handler,
+ const Section *ehFrameSection,
+ MachODefinedAtom *atom,
+ uint64_t offset,
+ const CIEInfoMap &cieInfos) {
const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
const bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch);
// Compiler wasn't lazy and actually told us what it meant.
+ // Unfortunately, the compiler may not have generated references for all of
+ // [cie, func, lsda] and so we still need to parse the FDE and add references
+ // for any the compiler didn't generate.
if (atom->begin() != atom->end())
- return std::error_code();
+ atom->sortReferences();
+
+ DefinedAtom::reference_iterator CurrentRef = atom->begin();
+
+ // This helper returns the reference (if one exists) at the offset we are
+ // currently processing. It automatically increments the ref iterator if we
+ // do return a ref, and throws an error if we pass over a ref without
+ // comsuming it.
+ auto currentRefGetter = [&CurrentRef,
+ &atom](uint64_t Offset)->const Reference* {
+ // If there are no more refs found, then we are done.
+ if (CurrentRef == atom->end())
+ return nullptr;
+
+ const Reference *Ref = *CurrentRef;
+
+ // If we haven't reached the offset for this reference, then return that
+ // we don't yet have a reference to process.
+ if (Offset < Ref->offsetInAtom())
+ return nullptr;
+
+ // If the offset is equal, then we want to process this ref.
+ if (Offset == Ref->offsetInAtom()) {
+ ++CurrentRef;
+ return Ref;
+ }
+
+ // The current ref is at an offset which is earlier than the current
+ // offset, then we failed to consume it when we should have. In this case
+ // throw an error.
+ llvm::report_fatal_error("Skipped reference when processing FDE");
+ };
+
+ // Helper to either get the reference at this current location, and verify
+ // that it is of the expected type, or add a reference of that type.
+ // Returns the reference target.
+ auto verifyOrAddReference = [&](uint64_t targetAddress,
+ Reference::KindValue refKind,
+ uint64_t refAddress,
+ bool allowsAddend)->const Atom* {
+ if (auto *ref = currentRefGetter(refAddress)) {
+ // The compiler already emitted a relocation for the CIE ref. This should
+ // have been converted to the correct type of reference in
+ // get[Pair]ReferenceInfo().
+ assert(ref->kindValue() == refKind &&
+ "Incorrect EHFrame reference kind");
+ return ref->target();
+ }
+ Reference::Addend addend;
+ auto *target = findAtomCoveringAddress(normalizedFile, file,
+ targetAddress, &addend);
+ atom->addReference(Reference::KindNamespace::mach_o, handler.kindArch(),
+ refKind, refAddress, target, addend);
+
+ if (!allowsAddend)
+ assert(!addend && "EHFrame reference cannot have addend");
+ return target;
+ };
+
+ const uint8_t *startFrameData = atom->rawContent().data();
+ const uint8_t *frameData = startFrameData;
- const uint8_t *frameData = atom->rawContent().data();
uint32_t size = read32(frameData, isBig);
uint64_t cieFieldInFDE = size == 0xffffffffU
? sizeof(uint32_t) + sizeof(uint64_t)
@@ -770,13 +959,11 @@ static std::error_code processFDE(const NormalizedFile &normalizedFile,
uint64_t cieAddress = ehFrameSection->address + offset + cieFieldInFDE;
cieAddress -= cieDelta;
- Reference::Addend addend;
- const MachODefinedAtom *cie =
- findAtomCoveringAddress(normalizedFile, file, cieAddress, &addend);
- atom->addReference(cieFieldInFDE, handler.unwindRefToCIEKind(), cie,
- addend, handler.kindArch());
-
- assert(cie && cie->contentType() == DefinedAtom::typeCFI && !addend &&
+ auto *cieRefTarget = verifyOrAddReference(cieAddress,
+ handler.unwindRefToCIEKind(),
+ cieFieldInFDE, false);
+ const MachODefinedAtom *cie = dyn_cast<MachODefinedAtom>(cieRefTarget);
+ assert(cie && cie->contentType() == DefinedAtom::typeCFI &&
"FDE's CIE field does not point at the start of a CIE.");
const CIEInfo &cieInfo = cieInfos.find(cie)->second;
@@ -792,10 +979,9 @@ static std::error_code processFDE(const NormalizedFile &normalizedFile,
uint64_t rangeStart = ehFrameSection->address + offset + rangeFieldInFDE;
rangeStart += functionFromFDE;
- const Atom *func =
- findAtomCoveringAddress(normalizedFile, file, rangeStart, &addend);
- atom->addReference(rangeFieldInFDE, handler.unwindRefToFunctionKind(),
- func, addend, handler.kindArch());
+ verifyOrAddReference(rangeStart,
+ handler.unwindRefToFunctionKind(),
+ rangeFieldInFDE, true);
// Handle the augmentation data if there is any.
if (cieInfo._augmentationDataPresent) {
@@ -807,7 +993,7 @@ static std::error_code processFDE(const NormalizedFile &normalizedFile,
llvm::decodeULEB128(frameData + augmentationDataLengthFieldInFDE,
&lengthFieldSize);
- if (cieInfo._mayHaveLSDA && augmentationDataLength > 0) {
+ if (cieInfo._offsetOfLSDA != ~0U && augmentationDataLength > 0) {
// Look at the augmentation data field.
uint64_t augmentationDataFieldInFDE =
@@ -818,20 +1004,19 @@ static std::error_code processFDE(const NormalizedFile &normalizedFile,
uint64_t lsdaStart =
ehFrameSection->address + offset + augmentationDataFieldInFDE +
lsdaFromFDE;
- const Atom *lsda =
- findAtomCoveringAddress(normalizedFile, file, lsdaStart, &addend);
- atom->addReference(augmentationDataFieldInFDE,
- handler.unwindRefToFunctionKind(),
- lsda, addend, handler.kindArch());
+
+ verifyOrAddReference(lsdaStart,
+ handler.unwindRefToFunctionKind(),
+ augmentationDataFieldInFDE, true);
}
}
- return std::error_code();
+ return llvm::Error();
}
-std::error_code addEHFrameReferences(const NormalizedFile &normalizedFile,
- MachOFile &file,
- mach_o::ArchHandler &handler) {
+llvm::Error addEHFrameReferences(const NormalizedFile &normalizedFile,
+ MachOFile &file,
+ mach_o::ArchHandler &handler) {
const Section *ehFrameSection = nullptr;
for (auto &section : normalizedFile.sections)
@@ -843,9 +1028,9 @@ std::error_code addEHFrameReferences(const NormalizedFile &normalizedFile,
// No __eh_frame so nothing to do.
if (!ehFrameSection)
- return std::error_code();
+ return llvm::Error();
- std::error_code ehFrameErr;
+ llvm::Error ehFrameErr;
CIEInfoMap cieInfos;
file.eachAtomInSection(*ehFrameSection,
@@ -858,7 +1043,8 @@ std::error_code addEHFrameReferences(const NormalizedFile &normalizedFile,
const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
if (ArchHandler::isDwarfCIE(isBig, atom))
- ehFrameErr = processCIE(normalizedFile, atom, cieInfos);
+ ehFrameErr = processCIE(normalizedFile, file, handler, ehFrameSection,
+ atom, offset, cieInfos);
else
ehFrameErr = processFDE(normalizedFile, file, handler, ehFrameSection,
atom, offset, cieInfos);
@@ -867,24 +1053,66 @@ std::error_code addEHFrameReferences(const NormalizedFile &normalizedFile,
return ehFrameErr;
}
+llvm::Error parseObjCImageInfo(const Section &sect,
+ const NormalizedFile &normalizedFile,
+ MachOFile &file) {
+
+ // struct objc_image_info {
+ // uint32_t version; // initially 0
+ // uint32_t flags;
+ // };
+
+ ArrayRef<uint8_t> content = sect.content;
+ if (content.size() != 8)
+ return llvm::make_error<GenericError>(sect.segmentName + "/" +
+ sect.sectionName +
+ " in file " + file.path() +
+ " should be 8 bytes in size");
+
+ const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
+ uint32_t version = read32(content.data(), isBig);
+ if (version)
+ return llvm::make_error<GenericError>(sect.segmentName + "/" +
+ sect.sectionName +
+ " in file " + file.path() +
+ " should have version=0");
+
+ uint32_t flags = read32(content.data() + 4, isBig);
+ if (flags & (MachOLinkingContext::objc_supports_gc |
+ MachOLinkingContext::objc_gc_only))
+ return llvm::make_error<GenericError>(sect.segmentName + "/" +
+ sect.sectionName +
+ " in file " + file.path() +
+ " uses GC. This is not supported");
+
+ if (flags & MachOLinkingContext::objc_retainReleaseForSimulator)
+ file.setObjcConstraint(MachOLinkingContext::objc_retainReleaseForSimulator);
+ else
+ file.setObjcConstraint(MachOLinkingContext::objc_retainRelease);
+
+ file.setSwiftVersion((flags >> 8) & 0xFF);
+
+ return llvm::Error();
+}
+
/// Converts normalized mach-o file into an lld::File and lld::Atoms.
-ErrorOr<std::unique_ptr<lld::File>>
+llvm::Expected<std::unique_ptr<lld::File>>
objectToAtoms(const NormalizedFile &normalizedFile, StringRef path,
bool copyRefs) {
std::unique_ptr<MachOFile> file(new MachOFile(path));
- if (std::error_code ec = normalizedObjectToAtoms(
- file.get(), normalizedFile, copyRefs))
- return ec;
+ if (auto ec = normalizedObjectToAtoms(file.get(), normalizedFile, copyRefs))
+ return std::move(ec);
return std::unique_ptr<File>(std::move(file));
}
-ErrorOr<std::unique_ptr<lld::File>>
+llvm::Expected<std::unique_ptr<lld::File>>
dylibToAtoms(const NormalizedFile &normalizedFile, StringRef path,
bool copyRefs) {
// Instantiate SharedLibraryFile object.
std::unique_ptr<MachODylibFile> file(new MachODylibFile(path));
- normalizedDylibToAtoms(file.get(), normalizedFile, copyRefs);
+ if (auto ec = normalizedDylibToAtoms(file.get(), normalizedFile, copyRefs))
+ return std::move(ec);
return std::unique_ptr<File>(std::move(file));
}
@@ -892,7 +1120,12 @@ dylibToAtoms(const NormalizedFile &normalizedFile, StringRef path,
namespace normalized {
-std::error_code
+static bool isObjCImageInfo(const Section &sect) {
+ return (sect.segmentName == "__OBJC" && sect.sectionName == "__image_info") ||
+ (sect.segmentName == "__DATA" && sect.sectionName == "__objc_imageinfo");
+}
+
+llvm::Error
normalizedObjectToAtoms(MachOFile *file,
const NormalizedFile &normalizedFile,
bool copyRefs) {
@@ -905,12 +1138,23 @@ normalizedObjectToAtoms(MachOFile *file,
DEBUG(llvm::dbgs() << "Creating atoms: "; sect.dump());
if (isDebugInfoSection(sect))
continue;
+
+
+ // If the file contains an objc_image_info struct, then we should parse the
+ // ObjC flags and Swift version.
+ if (isObjCImageInfo(sect)) {
+ if (auto ec = parseObjCImageInfo(sect, normalizedFile, *file))
+ return ec;
+ // We then skip adding atoms for this section as we use the ObjCPass to
+ // re-emit this data after it has been aggregated for all files.
+ continue;
+ }
+
bool customSectionName;
DefinedAtom::ContentType atomType = atomTypeFromSection(sect,
customSectionName);
- if (std::error_code ec =
- processSection(atomType, sect, customSectionName, normalizedFile,
- *file, scatterable, copyRefs))
+ if (auto ec = processSection(atomType, sect, customSectionName,
+ normalizedFile, *file, scatterable, copyRefs))
return ec;
}
// Create atoms from undefined symbols.
@@ -931,9 +1175,9 @@ normalizedObjectToAtoms(MachOFile *file,
for (auto &sect : normalizedFile.sections) {
if (isDebugInfoSection(sect))
continue;
- if (std::error_code ec = convertRelocs(sect, normalizedFile, scatterable,
- *file, *handler))
- return ec;
+ if (llvm::Error ec = convertRelocs(sect, normalizedFile, scatterable,
+ *file, *handler))
+ return ec;
}
// Add additional arch-specific References
@@ -945,7 +1189,7 @@ normalizedObjectToAtoms(MachOFile *file,
// providing unwind info for) and itself (FDE -> CIE). These aren't
// represented in the relocations on some architectures, so we have to add
// them back in manually there.
- if (std::error_code ec = addEHFrameReferences(normalizedFile, *file, *handler))
+ if (auto ec = addEHFrameReferences(normalizedFile, *file, *handler))
return ec;
// Process mach-o data-in-code regions array. That information is encoded in
@@ -955,25 +1199,26 @@ normalizedObjectToAtoms(MachOFile *file,
++nextIndex;
const Section* s = findSectionCoveringAddress(normalizedFile, entry.offset);
if (!s) {
- return make_dynamic_error_code(Twine("LC_DATA_IN_CODE address ("
- + Twine(entry.offset)
- + ") is not in any section"));
+ return llvm::make_error<GenericError>(Twine("LC_DATA_IN_CODE address ("
+ + Twine(entry.offset)
+ + ") is not in any section"));
}
uint64_t offsetInSect = entry.offset - s->address;
uint32_t offsetInAtom;
MachODefinedAtom *atom = file->findAtomCoveringAddress(*s, offsetInSect,
&offsetInAtom);
if (offsetInAtom + entry.length > atom->size()) {
- return make_dynamic_error_code(Twine("LC_DATA_IN_CODE entry (offset="
- + Twine(entry.offset)
- + ", length="
- + Twine(entry.length)
- + ") crosses atom boundary."));
+ return llvm::make_error<GenericError>(Twine("LC_DATA_IN_CODE entry "
+ "(offset="
+ + Twine(entry.offset)
+ + ", length="
+ + Twine(entry.length)
+ + ") crosses atom boundary."));
}
// Add reference that marks start of data-in-code.
- atom->addReference(offsetInAtom,
- handler->dataInCodeTransitionStart(*atom), atom,
- entry.kind, handler->kindArch());
+ atom->addReference(Reference::KindNamespace::mach_o, handler->kindArch(),
+ handler->dataInCodeTransitionStart(*atom),
+ offsetInAtom, atom, entry.kind);
// Peek at next entry, if it starts where this one ends, skip ending ref.
if (nextIndex < normalizedFile.dataInCode.size()) {
@@ -987,19 +1232,26 @@ normalizedObjectToAtoms(MachOFile *file,
continue;
// Add reference that marks end of data-in-code.
- atom->addReference(offsetInAtom+entry.length,
- handler->dataInCodeTransitionEnd(*atom), atom, 0,
- handler->kindArch());
+ atom->addReference(Reference::KindNamespace::mach_o, handler->kindArch(),
+ handler->dataInCodeTransitionEnd(*atom),
+ offsetInAtom+entry.length, atom, 0);
}
+ // Cache some attributes on the file for use later.
+ file->setFlags(normalizedFile.flags);
+ file->setArch(normalizedFile.arch);
+ file->setOS(normalizedFile.os);
+ file->setMinVersion(normalizedFile.minOSverson);
+ file->setMinVersionLoadCommandKind(normalizedFile.minOSVersionKind);
+
// Sort references in each atom to their canonical order.
for (const DefinedAtom* defAtom : file->defined()) {
reinterpret_cast<const SimpleDefinedAtom*>(defAtom)->sortReferences();
}
- return std::error_code();
+ return llvm::Error();
}
-std::error_code
+llvm::Error
normalizedDylibToAtoms(MachODylibFile *file,
const NormalizedFile &normalizedFile,
bool copyRefs) {
@@ -1027,7 +1279,7 @@ normalizedDylibToAtoms(MachODylibFile *file,
if (dep.kind == llvm::MachO::LC_REEXPORT_DYLIB)
file->addReExportedDylib(dep.path);
}
- return std::error_code();
+ return llvm::Error();
}
void relocatableSectionInfoForContentType(DefinedAtom::ContentType atomType,
@@ -1058,7 +1310,7 @@ void relocatableSectionInfoForContentType(DefinedAtom::ContentType atomType,
llvm_unreachable("content type not yet supported");
}
-ErrorOr<std::unique_ptr<lld::File>>
+llvm::Expected<std::unique_ptr<lld::File>>
normalizedToAtoms(const NormalizedFile &normalizedFile, StringRef path,
bool copyRefs) {
switch (normalizedFile.fileType) {
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp
index 0b92a68eeae8..66be77173983 100644
--- a/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp
+++ b/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp
@@ -237,6 +237,29 @@ struct ScalarBitSetTraits<SectionAttr> {
}
};
+/// This is a custom formatter for SectionAlignment. Values are
+/// the power to raise by, ie, the n in 2^n.
+template <> struct ScalarTraits<SectionAlignment> {
+ static void output(const SectionAlignment &value, void *ctxt,
+ raw_ostream &out) {
+ out << llvm::format("%d", (uint32_t)value);
+ }
+
+ static StringRef input(StringRef scalar, void *ctxt,
+ SectionAlignment &value) {
+ uint32_t alignment;
+ if (scalar.getAsInteger(0, alignment)) {
+ return "malformed alignment value";
+ }
+ if (!llvm::isPowerOf2_32(alignment))
+ return "alignment must be a power of 2";
+ value = alignment;
+ return StringRef(); // returning empty string means success
+ }
+
+ static bool mustQuote(StringRef) { return false; }
+};
+
template <>
struct ScalarEnumerationTraits<NListType> {
static void enumeration(IO &io, NListType &value) {
@@ -276,7 +299,7 @@ struct MappingTraits<Section> {
io.mapRequired("section", sect.sectionName);
io.mapRequired("type", sect.type);
io.mapOptional("attributes", sect.attributes);
- io.mapOptional("alignment", sect.alignment, (uint16_t)1);
+ io.mapOptional("alignment", sect.alignment, (SectionAlignment)1);
io.mapRequired("address", sect.address);
if (isZeroFillSection(sect.type)) {
// S_ZEROFILL sections use "size:" instead of "content:"
@@ -311,6 +334,8 @@ struct MappingTraits<Section> {
NormalizedFile *file = info->_normalizeMachOFile;
assert(file != nullptr);
size_t size = _normalizedContent.size();
+ if (!size)
+ return None;
uint8_t *bytes = file->ownedAllocations.Allocate<uint8_t>(size);
std::copy(_normalizedContent.begin(), _normalizedContent.end(), bytes);
return makeArrayRef(bytes, size);
@@ -504,10 +529,11 @@ struct ScalarTraits<VMProtect> {
template <>
struct MappingTraits<Segment> {
static void mapping(IO &io, Segment& seg) {
- io.mapRequired("name", seg.name);
- io.mapRequired("address", seg.address);
- io.mapRequired("size", seg.size);
- io.mapRequired("access", seg.access);
+ io.mapRequired("name", seg.name);
+ io.mapRequired("address", seg.address);
+ io.mapRequired("size", seg.size);
+ io.mapRequired("init-access", seg.init_access);
+ io.mapRequired("max-access", seg.max_access);
}
};
@@ -524,6 +550,14 @@ struct ScalarEnumerationTraits<LoadCommandType> {
llvm::MachO::LC_LOAD_UPWARD_DYLIB);
io.enumCase(value, "LC_LAZY_LOAD_DYLIB",
llvm::MachO::LC_LAZY_LOAD_DYLIB);
+ io.enumCase(value, "LC_VERSION_MIN_MACOSX",
+ llvm::MachO::LC_VERSION_MIN_MACOSX);
+ io.enumCase(value, "LC_VERSION_MIN_IPHONEOS",
+ llvm::MachO::LC_VERSION_MIN_IPHONEOS);
+ io.enumCase(value, "LC_VERSION_MIN_TVOS",
+ llvm::MachO::LC_VERSION_MIN_TVOS);
+ io.enumCase(value, "LC_VERSION_MIN_WATCHOS",
+ llvm::MachO::LC_VERSION_MIN_WATCHOS);
}
};
@@ -692,6 +726,7 @@ struct MappingTraits<NormalizedFile> {
io.mapOptional("source-version", file.sourceVersion, Hex64(0));
io.mapOptional("OS", file.os);
io.mapOptional("min-os-version", file.minOSverson, PackedVersion(0));
+ io.mapOptional("min-os-version-kind", file.minOSVersionKind, (LoadCommandType)0);
io.mapOptional("sdk-version", file.sdkVersion, PackedVersion(0));
io.mapOptional("segments", file.segments);
io.mapOptional("sections", file.sections);
@@ -731,8 +766,21 @@ bool MachOYamlIOTaggedDocumentHandler::handledDocTag(llvm::yaml::IO &io,
info->_normalizeMachOFile = &nf;
MappingTraits<NormalizedFile>::mapping(io, nf);
// Step 2: parse normalized mach-o struct into atoms.
- ErrorOr<std::unique_ptr<lld::File>> foe = normalizedToAtoms(nf, info->_path,
- true);
+ auto fileOrError = normalizedToAtoms(nf, info->_path, true);
+
+ // Check that we parsed successfully.
+ if (!fileOrError) {
+ std::string buffer;
+ llvm::raw_string_ostream stream(buffer);
+ handleAllErrors(fileOrError.takeError(),
+ [&](const llvm::ErrorInfoBase &EI) {
+ EI.log(stream);
+ stream << "\n";
+ });
+ io.setError(stream.str());
+ return false;
+ }
+
if (nf.arch != _arch) {
io.setError(Twine("file is wrong architecture. Expected ("
+ MachOLinkingContext::nameFromArch(_arch)
@@ -742,16 +790,8 @@ bool MachOYamlIOTaggedDocumentHandler::handledDocTag(llvm::yaml::IO &io,
return false;
}
info->_normalizeMachOFile = nullptr;
-
- if (foe) {
- // Transfer ownership to "out" File parameter.
- std::unique_ptr<lld::File> f = std::move(foe.get());
- file = f.release();
- return true;
- } else {
- io.setError(foe.getError().message());
- return false;
- }
+ file = fileOrError->release();
+ return true;
}
@@ -759,7 +799,7 @@ bool MachOYamlIOTaggedDocumentHandler::handledDocTag(llvm::yaml::IO &io,
namespace normalized {
/// Parses a yaml encoded mach-o file to produce an in-memory normalized view.
-ErrorOr<std::unique_ptr<NormalizedFile>>
+llvm::Expected<std::unique_ptr<NormalizedFile>>
readYaml(std::unique_ptr<MemoryBuffer> &mb) {
// Make empty NormalizedFile.
std::unique_ptr<NormalizedFile> f(new NormalizedFile());
@@ -773,8 +813,9 @@ readYaml(std::unique_ptr<MemoryBuffer> &mb) {
yin >> *f;
// Return error if there were parsing problems.
- if (yin.error())
- return make_error_code(lld::YamlReaderError::illegal_value);
+ if (auto ec = yin.error())
+ return llvm::make_error<GenericError>(Twine("YAML parsing error: ")
+ + ec.message());
// Hand ownership of instantiated NormalizedFile to caller.
return std::move(f);
diff --git a/lib/ReaderWriter/MachO/MachOPasses.h b/lib/ReaderWriter/MachO/MachOPasses.h
index a73785418d5f..cd01d4aa2c93 100644
--- a/lib/ReaderWriter/MachO/MachOPasses.h
+++ b/lib/ReaderWriter/MachO/MachOPasses.h
@@ -21,6 +21,7 @@ void addStubsPass(PassManager &pm, const MachOLinkingContext &ctx);
void addGOTPass(PassManager &pm, const MachOLinkingContext &ctx);
void addTLVPass(PassManager &pm, const MachOLinkingContext &ctx);
void addCompactUnwindPass(PassManager &pm, const MachOLinkingContext &ctx);
+void addObjCPass(PassManager &pm, const MachOLinkingContext &ctx);
void addShimPass(PassManager &pm, const MachOLinkingContext &ctx);
} // namespace mach_o
diff --git a/lib/ReaderWriter/MachO/ObjCPass.cpp b/lib/ReaderWriter/MachO/ObjCPass.cpp
new file mode 100644
index 000000000000..ba24b3fecdf4
--- /dev/null
+++ b/lib/ReaderWriter/MachO/ObjCPass.cpp
@@ -0,0 +1,128 @@
+//===- lib/ReaderWriter/MachO/ObjCPass.cpp -------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+
+#include "ArchHandler.h"
+#include "File.h"
+#include "MachOPasses.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/Simple.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
+
+namespace lld {
+namespace mach_o {
+
+///
+/// ObjC Image Info Atom created by the ObjC pass.
+///
+class ObjCImageInfoAtom : public SimpleDefinedAtom {
+public:
+ ObjCImageInfoAtom(const File &file,
+ MachOLinkingContext::ObjCConstraint objCConstraint,
+ uint32_t swiftVersion)
+ : SimpleDefinedAtom(file) {
+
+ Data.info.version = 0;
+
+ switch (objCConstraint) {
+ case MachOLinkingContext::objc_unknown:
+ llvm_unreachable("Shouldn't run the objc pass without a constraint");
+ case MachOLinkingContext::objc_supports_gc:
+ case MachOLinkingContext::objc_gc_only:
+ llvm_unreachable("GC is not supported");
+ case MachOLinkingContext::objc_retainReleaseForSimulator:
+ // The retain/release for simulator flag is already the correct
+ // encoded value for the data so just set it here.
+ Data.info.flags = (uint32_t)objCConstraint;
+ break;
+ case MachOLinkingContext::objc_retainRelease:
+ // We don't need to encode this flag, so just leave the flags as 0.
+ Data.info.flags = 0;
+ break;
+ }
+
+ Data.info.flags |= (swiftVersion << 8);
+ }
+
+ ~ObjCImageInfoAtom() override = default;
+
+ ContentType contentType() const override {
+ return DefinedAtom::typeObjCImageInfo;
+ }
+
+ Alignment alignment() const override {
+ return 4;
+ }
+
+ uint64_t size() const override {
+ return 8;
+ }
+
+ ContentPermissions permissions() const override {
+ return DefinedAtom::permR__;
+ }
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return llvm::makeArrayRef(Data.bytes, size());
+ }
+
+private:
+
+ struct objc_image_info {
+ uint32_t version;
+ uint32_t flags;
+ };
+
+ union {
+ objc_image_info info;
+ uint8_t bytes[8];
+ } Data;
+};
+
+class ObjCPass : public Pass {
+public:
+ ObjCPass(const MachOLinkingContext &context)
+ : _ctx(context),
+ _file(*_ctx.make_file<MachOFile>("<mach-o objc pass>")) {
+ _file.setOrdinal(_ctx.getNextOrdinalAndIncrement());
+ }
+
+ llvm::Error perform(SimpleFile &mergedFile) override {
+ // Add the image info.
+ mergedFile.addAtom(*getImageInfo());
+
+ return llvm::Error();
+ }
+
+private:
+
+ const DefinedAtom* getImageInfo() {
+ return new (_file.allocator()) ObjCImageInfoAtom(_file,
+ _ctx.objcConstraint(),
+ _ctx.swiftVersion());
+ }
+
+ const MachOLinkingContext &_ctx;
+ MachOFile &_file;
+};
+
+
+
+void addObjCPass(PassManager &pm, const MachOLinkingContext &ctx) {
+ pm.add(llvm::make_unique<ObjCPass>(ctx));
+}
+
+} // end namespace mach_o
+} // end namespace lld
diff --git a/lib/ReaderWriter/MachO/SectCreateFile.h b/lib/ReaderWriter/MachO/SectCreateFile.h
index 2e6e97c5433f..49e65f63151d 100644
--- a/lib/ReaderWriter/MachO/SectCreateFile.h
+++ b/lib/ReaderWriter/MachO/SectCreateFile.h
@@ -31,6 +31,8 @@ public:
_combinedName((segName + "/" + sectName).str()),
_content(std::move(content)) {}
+ ~SectCreateAtom() override = default;
+
uint64_t size() const override { return _content->getBufferSize(); }
Scope scope() const override { return scopeGlobal; }
@@ -59,7 +61,7 @@ public:
std::unique_ptr<MemoryBuffer> _content;
};
- SectCreateFile() : File("sectcreate", kindObject) {}
+ SectCreateFile() : File("sectcreate", kindSectCreateObject) {}
void addSection(StringRef seg, StringRef sect,
std::unique_ptr<MemoryBuffer> content) {
@@ -67,22 +69,29 @@ public:
new (allocator()) SectCreateAtom(*this, seg, sect, std::move(content)));
}
- const AtomVector<DefinedAtom> &defined() const override {
+ const AtomRange<DefinedAtom> defined() const override {
return _definedAtoms;
}
- const AtomVector<UndefinedAtom> &undefined() const override {
+ const AtomRange<UndefinedAtom> undefined() const override {
return _noUndefinedAtoms;
}
- const AtomVector<SharedLibraryAtom> &sharedLibrary() const override {
+ const AtomRange<SharedLibraryAtom> sharedLibrary() const override {
return _noSharedLibraryAtoms;
}
- const AtomVector<AbsoluteAtom> &absolute() const override {
+ const AtomRange<AbsoluteAtom> absolute() const override {
return _noAbsoluteAtoms;
}
+ void clearAtoms() override {
+ _definedAtoms.clear();
+ _noUndefinedAtoms.clear();
+ _noSharedLibraryAtoms.clear();
+ _noAbsoluteAtoms.clear();
+ }
+
private:
AtomVector<DefinedAtom> _definedAtoms;
};
diff --git a/lib/ReaderWriter/MachO/ShimPass.cpp b/lib/ReaderWriter/MachO/ShimPass.cpp
index df29e37c183b..cd5367146658 100644
--- a/lib/ReaderWriter/MachO/ShimPass.cpp
+++ b/lib/ReaderWriter/MachO/ShimPass.cpp
@@ -42,9 +42,12 @@ class ShimPass : public Pass {
public:
ShimPass(const MachOLinkingContext &context)
: _ctx(context), _archHandler(_ctx.archHandler()),
- _stubInfo(_archHandler.stubInfo()), _file("<mach-o shim pass>") {}
+ _stubInfo(_archHandler.stubInfo()),
+ _file(*_ctx.make_file<MachOFile>("<mach-o shim pass>")) {
+ _file.setOrdinal(_ctx.getNextOrdinalAndIncrement());
+ }
- std::error_code perform(SimpleFile &mergedFile) override {
+ llvm::Error perform(SimpleFile &mergedFile) override {
// Scan all references in all atoms.
for (const DefinedAtom *atom : mergedFile.defined()) {
for (const Reference *ref : *atom) {
@@ -63,7 +66,7 @@ public:
}
// Exit early if no shims needed.
if (_targetToShim.empty())
- return std::error_code();
+ return llvm::Error();
// Sort shim atoms so the layout order is stable.
std::vector<const DefinedAtom *> shims;
@@ -80,7 +83,7 @@ public:
for (const DefinedAtom *shim : shims)
mergedFile.addAtom(*shim);
- return std::error_code();
+ return llvm::Error();
}
private:
@@ -112,7 +115,7 @@ private:
const MachOLinkingContext &_ctx;
mach_o::ArchHandler &_archHandler;
const ArchHandler::StubInfo &_stubInfo;
- MachOFile _file;
+ MachOFile &_file;
llvm::DenseMap<const Atom*, const DefinedAtom*> _targetToShim;
};
diff --git a/lib/ReaderWriter/MachO/StubsPass.cpp b/lib/ReaderWriter/MachO/StubsPass.cpp
index 1f61256a5b79..d53b78b24d14 100644
--- a/lib/ReaderWriter/MachO/StubsPass.cpp
+++ b/lib/ReaderWriter/MachO/StubsPass.cpp
@@ -37,6 +37,8 @@ public:
LazyPointerAtom(const File &file, bool is64)
: SimpleDefinedAtom(file), _is64(is64) { }
+ ~LazyPointerAtom() override = default;
+
ContentType contentType() const override {
return DefinedAtom::typeLazyPointer;
}
@@ -68,11 +70,13 @@ private:
//
class NonLazyPointerAtom : public SimpleDefinedAtom {
public:
- NonLazyPointerAtom(const File &file, bool is64)
- : SimpleDefinedAtom(file), _is64(is64) { }
+ NonLazyPointerAtom(const File &file, bool is64, ContentType contentType)
+ : SimpleDefinedAtom(file), _is64(is64), _contentType(contentType) { }
+
+ ~NonLazyPointerAtom() override = default;
ContentType contentType() const override {
- return DefinedAtom::typeGOT;
+ return _contentType;
}
Alignment alignment() const override {
@@ -95,6 +99,7 @@ public:
private:
const bool _is64;
+ const ContentType _contentType;
};
//
@@ -105,6 +110,8 @@ public:
StubAtom(const File &file, const ArchHandler::StubInfo &stubInfo)
: SimpleDefinedAtom(file), _stubInfo(stubInfo){ }
+ ~StubAtom() override = default;
+
ContentType contentType() const override {
return DefinedAtom::typeStub;
}
@@ -137,6 +144,8 @@ public:
StubHelperAtom(const File &file, const ArchHandler::StubInfo &stubInfo)
: SimpleDefinedAtom(file), _stubInfo(stubInfo) { }
+ ~StubHelperAtom() override = default;
+
ContentType contentType() const override {
return DefinedAtom::typeStubHelper;
}
@@ -170,12 +179,14 @@ public:
StubHelperCommonAtom(const File &file, const ArchHandler::StubInfo &stubInfo)
: SimpleDefinedAtom(file), _stubInfo(stubInfo) { }
+ ~StubHelperCommonAtom() override = default;
+
ContentType contentType() const override {
return DefinedAtom::typeStubHelper;
}
Alignment alignment() const override {
- return 1 << _stubInfo.codeAlignment;
+ return 1 << _stubInfo.stubHelperCommonAlignment;
}
uint64_t size() const override {
@@ -199,12 +210,15 @@ class StubsPass : public Pass {
public:
StubsPass(const MachOLinkingContext &context)
: _ctx(context), _archHandler(_ctx.archHandler()),
- _stubInfo(_archHandler.stubInfo()), _file("<mach-o Stubs pass>") {}
+ _stubInfo(_archHandler.stubInfo()),
+ _file(*_ctx.make_file<MachOFile>("<mach-o Stubs pass>")) {
+ _file.setOrdinal(_ctx.getNextOrdinalAndIncrement());
+ }
- std::error_code perform(SimpleFile &mergedFile) override {
+ llvm::Error perform(SimpleFile &mergedFile) override {
// Skip this pass if output format uses text relocations instead of stubs.
if (!this->noTextRelocs())
- return std::error_code();
+ return llvm::Error();
// Scan all references in all atoms.
for (const DefinedAtom *atom : mergedFile.defined()) {
@@ -231,15 +245,17 @@ public:
// Exit early if no stubs needed.
if (_targetToUses.empty())
- return std::error_code();
+ return llvm::Error();
// First add help-common and GOT slots used by lazy binding.
SimpleDefinedAtom *helperCommonAtom =
new (_file.allocator()) StubHelperCommonAtom(_file, _stubInfo);
SimpleDefinedAtom *helperCacheNLPAtom =
- new (_file.allocator()) NonLazyPointerAtom(_file, _ctx.is64Bit());
+ new (_file.allocator()) NonLazyPointerAtom(_file, _ctx.is64Bit(),
+ _stubInfo.stubHelperImageCacheContentType);
SimpleDefinedAtom *helperBinderNLPAtom =
- new (_file.allocator()) NonLazyPointerAtom(_file, _ctx.is64Bit());
+ new (_file.allocator()) NonLazyPointerAtom(_file, _ctx.is64Bit(),
+ _stubInfo.stubHelperImageCacheContentType);
addReference(helperCommonAtom, _stubInfo.stubHelperCommonReferenceToCache,
helperCacheNLPAtom);
addOptReference(
@@ -307,7 +323,7 @@ public:
lazyOffset += target->name().size() + 12;
}
- return std::error_code();
+ return llvm::Error();
}
private:
@@ -351,7 +367,7 @@ private:
const MachOLinkingContext &_ctx;
mach_o::ArchHandler &_archHandler;
const ArchHandler::StubInfo &_stubInfo;
- MachOFile _file;
+ MachOFile &_file;
TargetToUses _targetToUses;
};
diff --git a/lib/ReaderWriter/MachO/TLVPass.cpp b/lib/ReaderWriter/MachO/TLVPass.cpp
index aba222edcd27..7a8496c20a4e 100644
--- a/lib/ReaderWriter/MachO/TLVPass.cpp
+++ b/lib/ReaderWriter/MachO/TLVPass.cpp
@@ -30,6 +30,8 @@ public:
TLVPEntryAtom(const File &file, bool is64, StringRef name)
: SimpleDefinedAtom(file), _is64(is64), _name(name) {}
+ ~TLVPEntryAtom() override = default;
+
ContentType contentType() const override {
return DefinedAtom::typeTLVInitializerPtr;
}
@@ -65,10 +67,12 @@ class TLVPass : public Pass {
public:
TLVPass(const MachOLinkingContext &context)
: _ctx(context), _archHandler(_ctx.archHandler()),
- _file("<mach-o TLV Pass>") {}
+ _file(*_ctx.make_file<MachOFile>("<mach-o TLV pass>")) {
+ _file.setOrdinal(_ctx.getNextOrdinalAndIncrement());
+ }
private:
- std::error_code perform(SimpleFile &mergedFile) override {
+ llvm::Error perform(SimpleFile &mergedFile) override {
bool allowTLV = _ctx.minOS("10.7", "1.0");
for (const DefinedAtom *atom : mergedFile.defined()) {
@@ -77,7 +81,7 @@ private:
continue;
if (!allowTLV)
- return make_dynamic_error_code(
+ return llvm::make_error<GenericError>(
"targeted OS version does not support use of thread local "
"variables in " + atom->name() + " for architecture " +
_ctx.archName());
@@ -103,7 +107,7 @@ private:
for (const TLVPEntryAtom *slot : entries)
mergedFile.addAtom(*slot);
- return std::error_code();
+ return llvm::Error();
}
const DefinedAtom *makeTLVPEntry(const Atom *target) {
@@ -124,7 +128,7 @@ private:
const MachOLinkingContext &_ctx;
mach_o::ArchHandler &_archHandler;
- MachOFile _file;
+ MachOFile &_file;
llvm::DenseMap<const Atom*, const TLVPEntryAtom*> _targetToTLVP;
};
diff --git a/lib/ReaderWriter/MachO/WriterMachO.cpp b/lib/ReaderWriter/MachO/WriterMachO.cpp
index cce0a179608c..f08487f21ac1 100644
--- a/lib/ReaderWriter/MachO/WriterMachO.cpp
+++ b/lib/ReaderWriter/MachO/WriterMachO.cpp
@@ -28,17 +28,18 @@ class MachOWriter : public Writer {
public:
MachOWriter(const MachOLinkingContext &ctxt) : _ctx(ctxt) {}
- std::error_code writeFile(const lld::File &file, StringRef path) override {
+ llvm::Error writeFile(const lld::File &file, StringRef path) override {
// Construct empty normalized file from atoms.
- ErrorOr<std::unique_ptr<NormalizedFile>> nFile =
+ llvm::Expected<std::unique_ptr<NormalizedFile>> nFile =
normalized::normalizedFromAtoms(file, _ctx);
- if (std::error_code ec = nFile.getError())
+ if (auto ec = nFile.takeError())
return ec;
// For testing, write out yaml form of normalized file.
if (_ctx.printAtoms()) {
std::unique_ptr<Writer> yamlWriter = createWriterYAML(_ctx);
- yamlWriter->writeFile(file, "-");
+ if (auto ec = yamlWriter->writeFile(file, "-"))
+ return ec;
}
// Write normalized file as mach-o binary.
diff --git a/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp b/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp
index 78c6797b713f..ee2a9ec10883 100644
--- a/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp
+++ b/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp
@@ -7,30 +7,41 @@
//
//===----------------------------------------------------------------------===//
+#include "lld/Core/AbsoluteAtom.h"
#include "lld/Core/ArchiveLibraryFile.h"
+#include "lld/Core/Atom.h"
#include "lld/Core/DefinedAtom.h"
#include "lld/Core/Error.h"
#include "lld/Core/File.h"
-#include "lld/Core/LLVM.h"
+#include "lld/Core/LinkingContext.h"
#include "lld/Core/Reader.h"
#include "lld/Core/Reference.h"
+#include "lld/Core/SharedLibraryAtom.h"
#include "lld/Core/Simple.h"
+#include "lld/Core/UndefinedAtom.h"
#include "lld/Core/Writer.h"
#include "lld/ReaderWriter/YamlContext.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/Support/Allocator.h"
#include "llvm/Support/Debug.h"
-#include "llvm/Support/Errc.h"
-#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/Path.h"
#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <cstdint>
+#include <cstring>
#include <memory>
#include <string>
#include <system_error>
+#include <vector>
using llvm::yaml::MappingTraits;
using llvm::yaml::ScalarEnumerationTraits;
@@ -178,31 +189,10 @@ public:
return nullptr;
}
- /// \brief Lookup a group parent when there is a reference of type
- /// kindGroupChild. If there was no group-parent produce an appropriate
- /// error.
- const lld::Atom *lookupGroupParent(StringRef name) const {
- NameToAtom::const_iterator pos = _groupMap.find(name);
- if (pos != _groupMap.end())
- return pos->second;
- _io.setError(Twine("no such group name: ") + name);
- return nullptr;
- }
-
private:
typedef llvm::StringMap<const lld::Atom *> NameToAtom;
void add(StringRef name, const lld::Atom *atom) {
- if (const lld::DefinedAtom *da = dyn_cast<DefinedAtom>(atom)) {
- if (da->isGroupParent()) {
- if (_groupMap.count(name)) {
- _io.setError(Twine("duplicate group name: ") + name);
- } else {
- _groupMap[name] = atom;
- }
- return;
- }
- }
if (_nameMap.count(name)) {
_io.setError(Twine("duplicate atom name: ") + name);
} else {
@@ -212,12 +202,11 @@ private:
IO &_io;
NameToAtom _nameMap;
- NameToAtom _groupMap;
};
/// Mapping of Atoms.
template <typename T> class AtomList {
- typedef lld::File::AtomVector<T> Ty;
+ using Ty = std::vector<OwningAtomPtr<T>>;
public:
typename Ty::iterator begin() { return _atoms.begin(); }
@@ -229,7 +218,6 @@ public:
enum FileKinds {
fileKindObjectAtoms, // atom based object file encoded in yaml
fileKindArchive, // static archive library encoded in yaml
- fileKindObjectELF, // ELF object files encoded in yaml
fileKindObjectMachO // mach-o object files encoded in yaml
};
@@ -255,7 +243,7 @@ struct RefKind {
Reference::KindValue value;
};
-} // anonymous namespace
+} // end anonymous namespace
LLVM_YAML_IS_SEQUENCE_VECTOR(ArchMember)
LLVM_YAML_IS_SEQUENCE_VECTOR(const lld::Reference *)
@@ -294,7 +282,8 @@ template <> struct ScalarTraits<RefKind> {
template <> struct ScalarEnumerationTraits<lld::File::Kind> {
static void enumeration(IO &io, lld::File::Kind &value) {
- io.enumCase(value, "object", lld::File::kindObject);
+ io.enumCase(value, "error-object", lld::File::kindErrorObject);
+ io.enumCase(value, "object", lld::File::kindMachObject);
io.enumCase(value, "shared-library", lld::File::kindSharedLibrary);
io.enumCase(value, "static-library", lld::File::kindArchiveLibrary);
}
@@ -417,6 +406,10 @@ template <> struct ScalarEnumerationTraits<lld::DefinedAtom::ContentType> {
DefinedAtom::typeObjCClassPtr);
io.enumCase(value, "objc-category-list",
DefinedAtom::typeObjC2CategoryList);
+ io.enumCase(value, "objc-image-info",
+ DefinedAtom::typeObjCImageInfo);
+ io.enumCase(value, "objc-method-list",
+ DefinedAtom::typeObjCMethodList);
io.enumCase(value, "objc-class1", DefinedAtom::typeObjC1Class);
io.enumCase(value, "dtraceDOF", DefinedAtom::typeDTraceDOF);
io.enumCase(value, "interposing-tuples",
@@ -430,13 +423,7 @@ template <> struct ScalarEnumerationTraits<lld::DefinedAtom::ContentType> {
io.enumCase(value, "tlv-initializer-ptr",
DefinedAtom::typeTLVInitializerPtr);
io.enumCase(value, "mach_header", DefinedAtom::typeMachHeader);
- io.enumCase(value, "thread-data", DefinedAtom::typeThreadData);
- io.enumCase(value, "thread-zero-fill",DefinedAtom::typeThreadZeroFill);
- io.enumCase(value, "ro-note", DefinedAtom::typeRONote);
- io.enumCase(value, "rw-note", DefinedAtom::typeRWNote);
- io.enumCase(value, "no-alloc", DefinedAtom::typeNoAlloc);
- io.enumCase(value, "group-comdat", DefinedAtom::typeGroupComdat);
- io.enumCase(value, "gnu-linkonce", DefinedAtom::typeGnuLinkOnce);
+ io.enumCase(value, "dso_handle", DefinedAtom::typeDSOHandle);
io.enumCase(value, "sectcreate", DefinedAtom::typeSectCreate);
}
};
@@ -512,7 +499,6 @@ template <> struct ScalarEnumerationTraits<FileKinds> {
static void enumeration(IO &io, FileKinds &value) {
io.enumCase(value, "object", fileKindObjectAtoms);
io.enumCase(value, "archive", fileKindArchive);
- io.enumCase(value, "object-elf", fileKindObjectELF);
io.enumCase(value, "object-mach-o", fileKindObjectMachO);
}
};
@@ -528,10 +514,20 @@ template <> struct MappingTraits<ArchMember> {
// Declare that an AtomList is a yaml sequence.
template <typename T> struct SequenceTraits<AtomList<T> > {
static size_t size(IO &io, AtomList<T> &seq) { return seq._atoms.size(); }
- static const T *&element(IO &io, AtomList<T> &seq, size_t index) {
+ static T *&element(IO &io, AtomList<T> &seq, size_t index) {
if (index >= seq._atoms.size())
seq._atoms.resize(index + 1);
- return seq._atoms[index];
+ return seq._atoms[index].get();
+ }
+};
+
+// Declare that an AtomRange is a yaml sequence.
+template <typename T> struct SequenceTraits<File::AtomRange<T> > {
+ static size_t size(IO &io, File::AtomRange<T> &seq) { return seq.size(); }
+ static T *&element(IO &io, File::AtomRange<T> &seq, size_t index) {
+ assert(io.outputting() && "AtomRange only used when outputting");
+ assert(index < seq.size() && "Out of range access");
+ return seq[index].get();
}
};
@@ -583,39 +579,34 @@ template <> struct MappingTraits<const lld::File *> {
const lld::File *denormalize(IO &io) { return this; }
- const AtomVector<lld::DefinedAtom> &defined() const override {
+ const AtomRange<lld::DefinedAtom> defined() const override {
return _noDefinedAtoms;
}
- const AtomVector<lld::UndefinedAtom> &undefined() const override {
+ const AtomRange<lld::UndefinedAtom> undefined() const override {
return _noUndefinedAtoms;
}
- const AtomVector<lld::SharedLibraryAtom> &
- sharedLibrary() const override {
+ const AtomRange<lld::SharedLibraryAtom> sharedLibrary() const override {
return _noSharedLibraryAtoms;
}
- const AtomVector<lld::AbsoluteAtom> &absolute() const override {
+ const AtomRange<lld::AbsoluteAtom> absolute() const override {
return _noAbsoluteAtoms;
}
- File *find(StringRef name, bool dataSymbolOnly) override {
- for (const ArchMember &member : _members) {
- for (const lld::DefinedAtom *atom : member._content->defined()) {
- if (name == atom->name()) {
- if (!dataSymbolOnly)
- return const_cast<File *>(member._content);
- switch (atom->contentType()) {
- case lld::DefinedAtom::typeData:
- case lld::DefinedAtom::typeZeroFill:
- return const_cast<File *>(member._content);
- default:
- break;
- }
- }
- }
- }
+ void clearAtoms() override {
+ _noDefinedAtoms.clear();
+ _noUndefinedAtoms.clear();
+ _noSharedLibraryAtoms.clear();
+ _noAbsoluteAtoms.clear();
+ }
+
+ File *find(StringRef name) override {
+ for (const ArchMember &member : _members)
+ for (const lld::DefinedAtom *atom : member._content->defined())
+ if (name == atom->name())
+ return const_cast<File *>(member._content);
return nullptr;
}
@@ -630,36 +621,47 @@ template <> struct MappingTraits<const lld::File *> {
class NormalizedFile : public lld::File {
public:
- NormalizedFile(IO &io) : File("", kindObject), _io(io), _rnb(nullptr) {}
+ NormalizedFile(IO &io)
+ : File("", kindNormalizedObject), _io(io), _rnb(nullptr),
+ _definedAtomsRef(_definedAtoms._atoms),
+ _undefinedAtomsRef(_undefinedAtoms._atoms),
+ _sharedLibraryAtomsRef(_sharedLibraryAtoms._atoms),
+ _absoluteAtomsRef(_absoluteAtoms._atoms) {}
NormalizedFile(IO &io, const lld::File *file)
- : File(file->path(), kindObject), _io(io),
- _rnb(new RefNameBuilder(*file)), _path(file->path()) {
- for (const lld::DefinedAtom *a : file->defined())
- _definedAtoms._atoms.push_back(a);
- for (const lld::UndefinedAtom *a : file->undefined())
- _undefinedAtoms._atoms.push_back(a);
- for (const lld::SharedLibraryAtom *a : file->sharedLibrary())
- _sharedLibraryAtoms._atoms.push_back(a);
- for (const lld::AbsoluteAtom *a : file->absolute())
- _absoluteAtoms._atoms.push_back(a);
+ : File(file->path(), kindNormalizedObject), _io(io),
+ _rnb(new RefNameBuilder(*file)), _path(file->path()),
+ _definedAtomsRef(file->defined()),
+ _undefinedAtomsRef(file->undefined()),
+ _sharedLibraryAtomsRef(file->sharedLibrary()),
+ _absoluteAtomsRef(file->absolute()) {
}
+
+ ~NormalizedFile() override {
+ }
+
const lld::File *denormalize(IO &io);
- const AtomVector<lld::DefinedAtom> &defined() const override {
- return _definedAtoms._atoms;
+ const AtomRange<lld::DefinedAtom> defined() const override {
+ return _definedAtomsRef;
+ }
+
+ const AtomRange<lld::UndefinedAtom> undefined() const override {
+ return _undefinedAtomsRef;
}
- const AtomVector<lld::UndefinedAtom> &undefined() const override {
- return _undefinedAtoms._atoms;
+ const AtomRange<lld::SharedLibraryAtom> sharedLibrary() const override {
+ return _sharedLibraryAtomsRef;
}
- const AtomVector<lld::SharedLibraryAtom> &
- sharedLibrary() const override {
- return _sharedLibraryAtoms._atoms;
+ const AtomRange<lld::AbsoluteAtom> absolute() const override {
+ return _absoluteAtomsRef;
}
- const AtomVector<lld::AbsoluteAtom> &absolute() const override {
- return _absoluteAtoms._atoms;
+ void clearAtoms() override {
+ _definedAtoms._atoms.clear();
+ _undefinedAtoms._atoms.clear();
+ _sharedLibraryAtoms._atoms.clear();
+ _absoluteAtoms._atoms.clear();
}
// Allocate a new copy of this string in _storage, so the strings
@@ -677,6 +679,10 @@ template <> struct MappingTraits<const lld::File *> {
AtomList<lld::UndefinedAtom> _undefinedAtoms;
AtomList<lld::SharedLibraryAtom> _sharedLibraryAtoms;
AtomList<lld::AbsoluteAtom> _absoluteAtoms;
+ AtomRange<lld::DefinedAtom> _definedAtomsRef;
+ AtomRange<lld::UndefinedAtom> _undefinedAtomsRef;
+ AtomRange<lld::SharedLibraryAtom> _sharedLibraryAtomsRef;
+ AtomRange<lld::AbsoluteAtom> _absoluteAtomsRef;
llvm::BumpPtrAllocator _storage;
};
@@ -693,20 +699,31 @@ template <> struct MappingTraits<const lld::File *> {
}
static void mappingAtoms(IO &io, const lld::File *&file) {
- MappingNormalizationHeap<NormalizedFile, const lld::File *> keys(io, file);
YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+ MappingNormalizationHeap<NormalizedFile, const lld::File *>
+ keys(io, file, nullptr);
assert(info != nullptr);
info->_file = keys.operator->();
io.mapOptional("path", keys->_path);
- io.mapOptional("defined-atoms", keys->_definedAtoms);
- io.mapOptional("undefined-atoms", keys->_undefinedAtoms);
- io.mapOptional("shared-library-atoms", keys->_sharedLibraryAtoms);
- io.mapOptional("absolute-atoms", keys->_absoluteAtoms);
+
+ if (io.outputting()) {
+ io.mapOptional("defined-atoms", keys->_definedAtomsRef);
+ io.mapOptional("undefined-atoms", keys->_undefinedAtomsRef);
+ io.mapOptional("shared-library-atoms", keys->_sharedLibraryAtomsRef);
+ io.mapOptional("absolute-atoms", keys->_absoluteAtomsRef);
+ } else {
+ io.mapOptional("defined-atoms", keys->_definedAtoms);
+ io.mapOptional("undefined-atoms", keys->_undefinedAtoms);
+ io.mapOptional("shared-library-atoms", keys->_sharedLibraryAtoms);
+ io.mapOptional("absolute-atoms", keys->_absoluteAtoms);
+ }
}
static void mappingArchive(IO &io, const lld::File *&file) {
- MappingNormalizationHeap<NormArchiveFile, const lld::File *> keys(io, file);
+ YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+ MappingNormalizationHeap<NormArchiveFile, const lld::File *>
+ keys(io, file, &info->_file->allocator());
io.mapOptional("path", keys->_path);
io.mapOptional("members", keys->_members);
@@ -769,8 +786,9 @@ template <> struct MappingTraits<const lld::Reference *> {
};
static void mapping(IO &io, const lld::Reference *&ref) {
+ YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
MappingNormalizationHeap<NormalizedReference, const lld::Reference *> keys(
- io, ref);
+ io, ref, &info->_file->allocator());
io.mapRequired("kind", keys->_mappedKind);
io.mapOptional("offset", keys->_offset);
@@ -787,7 +805,7 @@ template <> struct MappingTraits<const lld::DefinedAtom *> {
public:
NormalizedAtom(IO &io)
: _file(fileFromContext(io)), _name(), _refName(), _contentType(),
- _alignment(1), _content(), _references(), _isGroupChild(false) {
+ _alignment(1), _content(), _references() {
static uint32_t ordinalCounter = 1;
_ordinal = ordinalCounter++;
}
@@ -810,6 +828,9 @@ template <> struct MappingTraits<const lld::DefinedAtom *> {
for (uint8_t x : cont)
_content.push_back(x);
}
+
+ ~NormalizedAtom() override = default;
+
const lld::DefinedAtom *denormalize(IO &io) {
YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
assert(info != nullptr);
@@ -827,7 +848,9 @@ template <> struct MappingTraits<const lld::DefinedAtom *> {
<< ", " << _name.size() << ")\n");
return this;
}
+
void bind(const RefNameResolver &);
+
// Extract current File object from YAML I/O parsing context
const lld::File &fileFromContext(IO &io) {
YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
@@ -851,8 +874,6 @@ template <> struct MappingTraits<const lld::DefinedAtom *> {
DynamicExport dynamicExport() const override { return _dynamicExport; }
CodeModel codeModel() const override { return _codeModel; }
ContentPermissions permissions() const override { return _permissions; }
- void setGroupChild(bool val) { _isGroupChild = val; }
- bool isGroupChild() const { return _isGroupChild; }
ArrayRef<uint8_t> rawContent() const override {
if (!occupiesDiskSpace())
return ArrayRef<uint8_t>();
@@ -883,6 +904,16 @@ template <> struct MappingTraits<const lld::DefinedAtom *> {
it = reinterpret_cast<const void *>(index);
}
+ void addReference(Reference::KindNamespace ns,
+ Reference::KindArch arch,
+ Reference::KindValue kindValue, uint64_t off,
+ const Atom *target, Reference::Addend a) override {
+ assert(target && "trying to create reference to nothing");
+ auto node = new (file().allocator()) SimpleReference(ns, arch, kindValue,
+ off, target, a);
+ _references.push_back(node);
+ }
+
const lld::File &_file;
StringRef _name;
StringRef _refName;
@@ -902,16 +933,15 @@ template <> struct MappingTraits<const lld::DefinedAtom *> {
StringRef _sectionName;
uint64_t _sectionSize;
std::vector<const lld::Reference *> _references;
- bool _isGroupChild;
};
static void mapping(IO &io, const lld::DefinedAtom *&atom) {
+ YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
MappingNormalizationHeap<NormalizedAtom, const lld::DefinedAtom *> keys(
- io, atom);
+ io, atom, &info->_file->allocator());
if (io.outputting()) {
// If writing YAML, check if atom needs a ref-name.
typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
- YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
assert(info != nullptr);
NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
assert(f);
@@ -951,18 +981,27 @@ template <> struct MappingTraits<const lld::DefinedAtom *> {
}
};
+template <> struct MappingTraits<lld::DefinedAtom *> {
+ static void mapping(IO &io, lld::DefinedAtom *&atom) {
+ const lld::DefinedAtom *atomPtr = atom;
+ MappingTraits<const lld::DefinedAtom *>::mapping(io, atomPtr);
+ atom = const_cast<lld::DefinedAtom *>(atomPtr);
+ }
+};
+
// YAML conversion for const lld::UndefinedAtom*
template <> struct MappingTraits<const lld::UndefinedAtom *> {
class NormalizedAtom : public lld::UndefinedAtom {
public:
NormalizedAtom(IO &io)
- : _file(fileFromContext(io)), _name(), _canBeNull(canBeNullNever),
- _fallback(nullptr) {}
+ : _file(fileFromContext(io)), _name(), _canBeNull(canBeNullNever) {}
NormalizedAtom(IO &io, const lld::UndefinedAtom *atom)
: _file(fileFromContext(io)), _name(atom->name()),
- _canBeNull(atom->canBeNull()), _fallback(atom->fallback()) {}
+ _canBeNull(atom->canBeNull()) {}
+
+ ~NormalizedAtom() override = default;
const lld::UndefinedAtom *denormalize(IO &io) {
YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
@@ -990,29 +1029,33 @@ template <> struct MappingTraits<const lld::UndefinedAtom *> {
const lld::File &file() const override { return _file; }
StringRef name() const override { return _name; }
CanBeNull canBeNull() const override { return _canBeNull; }
- const UndefinedAtom *fallback() const override { return _fallback; }
const lld::File &_file;
StringRef _name;
CanBeNull _canBeNull;
- const UndefinedAtom *_fallback;
};
static void mapping(IO &io, const lld::UndefinedAtom *&atom) {
+ YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
MappingNormalizationHeap<NormalizedAtom, const lld::UndefinedAtom *> keys(
- io, atom);
+ io, atom, &info->_file->allocator());
io.mapRequired("name", keys->_name);
io.mapOptional("can-be-null", keys->_canBeNull,
lld::UndefinedAtom::canBeNullNever);
- io.mapOptional("fallback", keys->_fallback,
- (const lld::UndefinedAtom *)nullptr);
+ }
+};
+
+template <> struct MappingTraits<lld::UndefinedAtom *> {
+ static void mapping(IO &io, lld::UndefinedAtom *&atom) {
+ const lld::UndefinedAtom *atomPtr = atom;
+ MappingTraits<const lld::UndefinedAtom *>::mapping(io, atomPtr);
+ atom = const_cast<lld::UndefinedAtom *>(atomPtr);
}
};
// YAML conversion for const lld::SharedLibraryAtom*
template <> struct MappingTraits<const lld::SharedLibraryAtom *> {
-
class NormalizedAtom : public lld::SharedLibraryAtom {
public:
NormalizedAtom(IO &io)
@@ -1023,6 +1066,8 @@ template <> struct MappingTraits<const lld::SharedLibraryAtom *> {
_loadName(atom->loadName()), _canBeNull(atom->canBeNullAtRuntime()),
_type(atom->type()), _size(atom->size()) {}
+ ~NormalizedAtom() override = default;
+
const lld::SharedLibraryAtom *denormalize(IO &io) {
YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
assert(info != nullptr);
@@ -1066,8 +1111,9 @@ template <> struct MappingTraits<const lld::SharedLibraryAtom *> {
static void mapping(IO &io, const lld::SharedLibraryAtom *&atom) {
+ YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
MappingNormalizationHeap<NormalizedAtom, const lld::SharedLibraryAtom *>
- keys(io, atom);
+ keys(io, atom, &info->_file->allocator());
io.mapRequired("name", keys->_name);
io.mapOptional("load-name", keys->_loadName);
@@ -1077,6 +1123,14 @@ template <> struct MappingTraits<const lld::SharedLibraryAtom *> {
}
};
+template <> struct MappingTraits<lld::SharedLibraryAtom *> {
+ static void mapping(IO &io, lld::SharedLibraryAtom *&atom) {
+ const lld::SharedLibraryAtom *atomPtr = atom;
+ MappingTraits<const lld::SharedLibraryAtom *>::mapping(io, atomPtr);
+ atom = const_cast<lld::SharedLibraryAtom *>(atomPtr);
+ }
+};
+
// YAML conversion for const lld::AbsoluteAtom*
template <> struct MappingTraits<const lld::AbsoluteAtom *> {
@@ -1087,6 +1141,9 @@ template <> struct MappingTraits<const lld::AbsoluteAtom *> {
NormalizedAtom(IO &io, const lld::AbsoluteAtom *atom)
: _file(fileFromContext(io)), _name(atom->name()),
_scope(atom->scope()), _value(atom->value()) {}
+
+ ~NormalizedAtom() override = default;
+
const lld::AbsoluteAtom *denormalize(IO &io) {
YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
assert(info != nullptr);
@@ -1122,8 +1179,9 @@ template <> struct MappingTraits<const lld::AbsoluteAtom *> {
};
static void mapping(IO &io, const lld::AbsoluteAtom *&atom) {
+ YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
MappingNormalizationHeap<NormalizedAtom, const lld::AbsoluteAtom *> keys(
- io, atom);
+ io, atom, &info->_file->allocator());
if (io.outputting()) {
typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
@@ -1144,8 +1202,16 @@ template <> struct MappingTraits<const lld::AbsoluteAtom *> {
}
};
-} // namespace llvm
-} // namespace yaml
+template <> struct MappingTraits<lld::AbsoluteAtom *> {
+ static void mapping(IO &io, lld::AbsoluteAtom *&atom) {
+ const lld::AbsoluteAtom *atomPtr = atom;
+ MappingTraits<const lld::AbsoluteAtom *>::mapping(io, atomPtr);
+ atom = const_cast<lld::AbsoluteAtom *>(atomPtr);
+ }
+};
+
+} // end namespace llvm
+} // end namespace yaml
RefNameResolver::RefNameResolver(const lld::File *file, IO &io) : _io(io) {
typedef MappingTraits<const lld::DefinedAtom *>::NormalizedAtom
@@ -1186,13 +1252,6 @@ MappingTraits<const lld::File *>::NormalizedFile::denormalize(IO &io) {
normAtom->bind(nameResolver);
}
- _definedAtoms._atoms.erase(
- std::remove_if(_definedAtoms._atoms.begin(), _definedAtoms._atoms.end(),
- [](const DefinedAtom *a) {
- return ((const NormalizedAtom *)a)->isGroupChild();
- }),
- _definedAtoms._atoms.end());
-
return this;
}
@@ -1208,14 +1267,7 @@ inline void MappingTraits<const lld::DefinedAtom *>::NormalizedAtom::bind(
inline void MappingTraits<const lld::Reference *>::NormalizedReference::bind(
const RefNameResolver &resolver) {
- typedef MappingTraits<const lld::DefinedAtom *>::NormalizedAtom NormalizedAtom;
-
_target = resolver.lookup(_targetName);
-
- if (_mappedKind.ns == lld::Reference::KindNamespace::all &&
- _mappedKind.value == lld::Reference::kindGroupChild) {
- ((NormalizedAtom *)const_cast<Atom *>(_target))->setGroupChild(true);
- }
}
inline StringRef
@@ -1240,12 +1292,12 @@ class Writer : public lld::Writer {
public:
Writer(const LinkingContext &context) : _ctx(context) {}
- std::error_code writeFile(const lld::File &file, StringRef outPath) override {
+ llvm::Error writeFile(const lld::File &file, StringRef outPath) override {
// Create stream to path.
std::error_code ec;
llvm::raw_fd_ostream out(outPath, ec, llvm::sys::fs::F_Text);
if (ec)
- return ec;
+ return llvm::errorCodeToError(ec);
// Create yaml Output writer, using yaml options for context.
YamlContext yamlContext;
@@ -1257,7 +1309,7 @@ public:
const lld::File *fileRef = &file;
yout << fileRef;
- return std::error_code();
+ return llvm::Error();
}
private:
@@ -1330,7 +1382,7 @@ private:
const Registry &_registry;
};
-} // anonymous namespace
+} // end anonymous namespace
void Registry::addSupportYamlFiles() {
add(std::unique_ptr<Reader>(new YAMLReader(*this)));