aboutsummaryrefslogtreecommitdiff
path: root/lib/ReaderWriter
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ReaderWriter')
-rw-r--r--lib/ReaderWriter/CMakeLists.txt2
-rw-r--r--lib/ReaderWriter/CoreLinkingContext.cpp135
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64DynamicLibraryWriter.h50
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64ELFFile.h41
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64ELFReader.h62
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.cpp52
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.h48
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.cpp26
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.h8
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.cpp546
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.h13
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.cpp241
-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.cpp45
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.h68
-rw-r--r--lib/ReaderWriter/ELF/AArch64/CMakeLists.txt2
-rw-r--r--lib/ReaderWriter/ELF/AArch64/Makefile15
-rw-r--r--lib/ReaderWriter/ELF/AMDGPU/AMDGPUExecutableWriter.cpp34
-rw-r--r--lib/ReaderWriter/ELF/AMDGPU/AMDGPUExecutableWriter.h41
-rw-r--r--lib/ReaderWriter/ELF/AMDGPU/AMDGPULinkingContext.cpp41
-rw-r--r--lib/ReaderWriter/ELF/AMDGPU/AMDGPULinkingContext.h36
-rw-r--r--lib/ReaderWriter/ELF/AMDGPU/AMDGPURelocationHandler.cpp19
-rw-r--r--lib/ReaderWriter/ELF/AMDGPU/AMDGPURelocationHandler.h31
-rw-r--r--lib/ReaderWriter/ELF/AMDGPU/AMDGPUSymbolTable.cpp32
-rw-r--r--lib/ReaderWriter/ELF/AMDGPU/AMDGPUSymbolTable.h32
-rw-r--r--lib/ReaderWriter/ELF/AMDGPU/AMDGPUTargetHandler.cpp65
-rw-r--r--lib/ReaderWriter/ELF/AMDGPU/AMDGPUTargetHandler.h80
-rw-r--r--lib/ReaderWriter/ELF/AMDGPU/CMakeLists.txt13
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMDynamicLibraryWriter.h49
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMELFFile.h143
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMELFReader.h62
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMELFWriters.h120
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h99
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp48
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h46
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp578
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h15
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp816
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h39
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp28
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h162
-rw-r--r--lib/ReaderWriter/ELF/ARM/Makefile15
-rw-r--r--lib/ReaderWriter/ELF/ARM/TODO.rst13
-rw-r--r--lib/ReaderWriter/ELF/Atoms.cpp297
-rw-r--r--lib/ReaderWriter/ELF/Atoms.h468
-rw-r--r--lib/ReaderWriter/ELF/CMakeLists.txt11
-rw-r--r--lib/ReaderWriter/ELF/Chunk.h73
-rw-r--r--lib/ReaderWriter/ELF/CreateELF.h118
-rw-r--r--lib/ReaderWriter/ELF/DefaultLayout.h1050
-rw-r--r--lib/ReaderWriter/ELF/DefaultTargetHandler.h38
-rw-r--r--lib/ReaderWriter/ELF/DynamicFile.cpp146
-rw-r--r--lib/ReaderWriter/ELF/DynamicFile.h92
-rw-r--r--lib/ReaderWriter/ELF/DynamicLibraryWriter.h40
-rw-r--r--lib/ReaderWriter/ELF/ELFFile.cpp829
-rw-r--r--lib/ReaderWriter/ELF/ELFFile.h946
-rw-r--r--lib/ReaderWriter/ELF/ELFLinkingContext.cpp86
-rw-r--r--lib/ReaderWriter/ELF/ELFReader.h85
-rw-r--r--lib/ReaderWriter/ELF/ExecutableWriter.h137
-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.h278
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonDynamicLibraryWriter.h62
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonELFFile.h127
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonELFReader.h62
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonELFWriters.h61
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonEncodings.h37
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonExecutableAtoms.h29
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonExecutableWriter.h75
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.cpp34
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.h22
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonRelocationFunctions.h49
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.cpp328
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.h14
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonSectionChunks.h86
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.cpp146
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.h123
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/Makefile16
-rw-r--r--lib/ReaderWriter/ELF/Layout.h59
-rw-r--r--lib/ReaderWriter/ELF/Makefile18
-rw-r--r--lib/ReaderWriter/ELF/Mips/CMakeLists.txt6
-rw-r--r--lib/ReaderWriter/ELF/Mips/Makefile15
-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.cpp7
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.h2
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsDynamicLibraryWriter.h101
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsDynamicTable.h89
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsELFFile.cpp348
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsELFFile.h291
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsELFFlagsMerger.cpp149
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsELFFlagsMerger.h36
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsELFReader.h93
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsELFWriters.cpp292
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsELFWriters.h122
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsExecutableWriter.h154
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp97
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h22
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp687
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.h14
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp783
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsSectionChunks.cpp264
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h174
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp171
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h224
-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.h5
-rw-r--r--lib/ReaderWriter/ELF/OutputELFWriter.cpp514
-rw-r--r--lib/ReaderWriter/ELF/OutputELFWriter.h488
-rw-r--r--lib/ReaderWriter/ELF/Reader.cpp6
-rw-r--r--lib/ReaderWriter/ELF/SectionChunks.cpp996
-rw-r--r--lib/ReaderWriter/ELF/SectionChunks.h1124
-rw-r--r--lib/ReaderWriter/ELF/SegmentChunks.cpp519
-rw-r--r--lib/ReaderWriter/ELF/SegmentChunks.h486
-rw-r--r--lib/ReaderWriter/ELF/TargetHandler.h67
-rw-r--r--lib/ReaderWriter/ELF/TargetLayout.cpp747
-rw-r--r--lib/ReaderWriter/ELF/TargetLayout.h317
-rw-r--r--lib/ReaderWriter/ELF/Writer.cpp4
-rw-r--r--lib/ReaderWriter/ELF/Writer.h7
-rw-r--r--lib/ReaderWriter/ELF/X86/Makefile15
-rw-r--r--lib/ReaderWriter/ELF/X86/X86DynamicLibraryWriter.h49
-rw-r--r--lib/ReaderWriter/ELF/X86/X86ELFFile.h41
-rw-r--r--lib/ReaderWriter/ELF/X86/X86ELFReader.h62
-rw-r--r--lib/ReaderWriter/ELF/X86/X86ExecutableWriter.h34
-rw-r--r--lib/ReaderWriter/ELF/X86/X86LinkingContext.cpp23
-rw-r--r--lib/ReaderWriter/ELF/X86/X86LinkingContext.h2
-rw-r--r--lib/ReaderWriter/ELF/X86/X86RelocationHandler.cpp17
-rw-r--r--lib/ReaderWriter/ELF/X86/X86RelocationHandler.h5
-rw-r--r--lib/ReaderWriter/ELF/X86/X86TargetHandler.cpp29
-rw-r--r--lib/ReaderWriter/ELF/X86/X86TargetHandler.h35
-rw-r--r--lib/ReaderWriter/ELF/X86_64/CMakeLists.txt1
-rw-r--r--lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleLinkingContext.cpp4
-rw-r--r--lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleTargetHandler.cpp5
-rw-r--r--lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleTargetHandler.h2
-rw-r--r--lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/Makefile15
-rw-r--r--lib/ReaderWriter/ELF/X86_64/Makefile19
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64DynamicLibraryWriter.h38
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64ELFFile.h41
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64ELFReader.h62
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64ElfType.h21
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64ExecutableWriter.h54
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp22
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h7
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp54
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.h10
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp62
-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.cpp30
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h83
-rw-r--r--lib/ReaderWriter/FileArchive.cpp106
-rw-r--r--lib/ReaderWriter/LinkerScript.cpp411
-rw-r--r--lib/ReaderWriter/MachO/ArchHandler.h6
-rw-r--r--lib/ReaderWriter/MachO/ArchHandler_arm.cpp52
-rw-r--r--lib/ReaderWriter/MachO/ArchHandler_arm64.cpp23
-rw-r--r--lib/ReaderWriter/MachO/ArchHandler_x86.cpp21
-rw-r--r--lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp113
-rw-r--r--lib/ReaderWriter/MachO/Atoms.h36
-rw-r--r--lib/ReaderWriter/MachO/CMakeLists.txt1
-rw-r--r--lib/ReaderWriter/MachO/CompactUnwindPass.cpp85
-rw-r--r--lib/ReaderWriter/MachO/ExecutableAtoms.h (renamed from lib/ReaderWriter/MachO/ExecutableAtoms.hpp)25
-rw-r--r--lib/ReaderWriter/MachO/File.h40
-rw-r--r--lib/ReaderWriter/MachO/FlatNamespaceFile.h61
-rw-r--r--lib/ReaderWriter/MachO/GOTPass.cpp29
-rw-r--r--lib/ReaderWriter/MachO/LayoutPass.cpp22
-rw-r--r--lib/ReaderWriter/MachO/LayoutPass.h17
-rw-r--r--lib/ReaderWriter/MachO/MachOLinkingContext.cpp100
-rw-r--r--lib/ReaderWriter/MachO/MachONormalizedFile.h59
-rw-r--r--lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp52
-rw-r--r--lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp75
-rw-r--r--lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp202
-rw-r--r--lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp302
-rw-r--r--lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp6
-rw-r--r--lib/ReaderWriter/MachO/MachOPasses.h1
-rw-r--r--lib/ReaderWriter/MachO/Makefile14
-rw-r--r--lib/ReaderWriter/MachO/SectCreateFile.h93
-rw-r--r--lib/ReaderWriter/MachO/ShimPass.cpp23
-rw-r--r--lib/ReaderWriter/MachO/StubsPass.cpp70
-rw-r--r--lib/ReaderWriter/MachO/TLVPass.cpp137
-rw-r--r--lib/ReaderWriter/MachO/WriterMachO.cpp28
-rw-r--r--lib/ReaderWriter/Makefile16
-rw-r--r--lib/ReaderWriter/Native/CMakeLists.txt7
-rw-r--r--lib/ReaderWriter/Native/Makefile14
-rw-r--r--lib/ReaderWriter/Native/NativeFileFormat.h258
-rw-r--r--lib/ReaderWriter/Native/ReaderNative.cpp1013
-rw-r--r--lib/ReaderWriter/Native/WriterNative.cpp566
-rw-r--r--lib/ReaderWriter/PECOFF/Atoms.h312
-rw-r--r--lib/ReaderWriter/PECOFF/CMakeLists.txt16
-rw-r--r--lib/ReaderWriter/PECOFF/EdataPass.cpp227
-rw-r--r--lib/ReaderWriter/PECOFF/EdataPass.h99
-rw-r--r--lib/ReaderWriter/PECOFF/IdataPass.cpp345
-rw-r--r--lib/ReaderWriter/PECOFF/IdataPass.h218
-rw-r--r--lib/ReaderWriter/PECOFF/InferSubsystemPass.h66
-rw-r--r--lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.cpp48
-rw-r--r--lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h309
-rw-r--r--lib/ReaderWriter/PECOFF/LoadConfigPass.cpp75
-rw-r--r--lib/ReaderWriter/PECOFF/LoadConfigPass.h63
-rw-r--r--lib/ReaderWriter/PECOFF/Makefile14
-rw-r--r--lib/ReaderWriter/PECOFF/OrderPass.h67
-rw-r--r--lib/ReaderWriter/PECOFF/PDBPass.h43
-rw-r--r--lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp352
-rw-r--r--lib/ReaderWriter/PECOFF/Pass.cpp95
-rw-r--r--lib/ReaderWriter/PECOFF/Pass.h34
-rw-r--r--lib/ReaderWriter/PECOFF/ReaderCOFF.cpp1140
-rw-r--r--lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp389
-rw-r--r--lib/ReaderWriter/PECOFF/WriterImportLibrary.cpp118
-rw-r--r--lib/ReaderWriter/PECOFF/WriterImportLibrary.h23
-rw-r--r--lib/ReaderWriter/PECOFF/WriterPECOFF.cpp1417
-rw-r--r--lib/ReaderWriter/YAML/Makefile14
-rw-r--r--lib/ReaderWriter/YAML/ReaderWriterYAML.cpp137
212 files changed, 13789 insertions, 17637 deletions
diff --git a/lib/ReaderWriter/CMakeLists.txt b/lib/ReaderWriter/CMakeLists.txt
index 1fd19eb73a75..588f0d85a586 100644
--- a/lib/ReaderWriter/CMakeLists.txt
+++ b/lib/ReaderWriter/CMakeLists.txt
@@ -1,7 +1,5 @@
add_subdirectory(ELF)
add_subdirectory(MachO)
-add_subdirectory(Native)
-add_subdirectory(PECOFF)
add_subdirectory(YAML)
if (MSVC)
diff --git a/lib/ReaderWriter/CoreLinkingContext.cpp b/lib/ReaderWriter/CoreLinkingContext.cpp
index 86fad4f6e77d..02f6263c0c3f 100644
--- a/lib/ReaderWriter/CoreLinkingContext.cpp
+++ b/lib/ReaderWriter/CoreLinkingContext.cpp
@@ -14,139 +14,19 @@
#include "lld/Core/Simple.h"
#include "lld/ReaderWriter/CoreLinkingContext.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
using namespace lld;
namespace {
-/// \brief Simple atom created by the stubs pass.
-class TestingStubAtom : public DefinedAtom {
-public:
- TestingStubAtom(const File &F, const Atom &) : _file(F) {
- static uint32_t lastOrdinal = 0;
- _ordinal = lastOrdinal++;
- }
-
- const File &file() const override { return _file; }
-
- StringRef name() const override { return StringRef(); }
-
- uint64_t ordinal() const override { return _ordinal; }
-
- uint64_t size() const override { return 0; }
-
- Scope scope() const override { return DefinedAtom::scopeLinkageUnit; }
-
- Interposable interposable() const override { return DefinedAtom::interposeNo; }
-
- Merge merge() const override { return DefinedAtom::mergeNo; }
-
- ContentType contentType() const override { return DefinedAtom::typeStub; }
-
- Alignment alignment() const override { return Alignment(0, 0); }
-
- SectionChoice sectionChoice() const override {
- return DefinedAtom::sectionBasedOnContent;
- }
-
- StringRef customSectionName() const override { return StringRef(); }
-
- DeadStripKind deadStrip() const override {
- return DefinedAtom::deadStripNormal;
- }
-
- ContentPermissions permissions() const override {
- return DefinedAtom::permR_X;
- }
-
- ArrayRef<uint8_t> rawContent() const override { return ArrayRef<uint8_t>(); }
-
- reference_iterator begin() const override {
- return reference_iterator(*this, nullptr);
- }
-
- reference_iterator end() const override {
- return reference_iterator(*this, nullptr);
- }
-
- const Reference *derefIterator(const void *iter) const override {
- return nullptr;
- }
-
- void incrementIterator(const void *&iter) const override {}
-
-private:
- const File &_file;
- uint32_t _ordinal;
-};
-
-/// \brief Simple atom created by the GOT pass.
-class TestingGOTAtom : public DefinedAtom {
-public:
- TestingGOTAtom(const File &F, const Atom &) : _file(F) {
- static uint32_t lastOrdinal = 0;
- _ordinal = lastOrdinal++;
- }
-
- const File &file() const override { return _file; }
-
- StringRef name() const override { return StringRef(); }
-
- uint64_t ordinal() const override { return _ordinal; }
-
- uint64_t size() const override { return 0; }
-
- Scope scope() const override { return DefinedAtom::scopeLinkageUnit; }
-
- Interposable interposable() const override { return DefinedAtom::interposeNo; }
-
- Merge merge() const override { return DefinedAtom::mergeNo; }
-
- ContentType contentType() const override { return DefinedAtom::typeGOT; }
-
- Alignment alignment() const override { return Alignment(3, 0); }
-
- SectionChoice sectionChoice() const override {
- return DefinedAtom::sectionBasedOnContent;
- }
-
- StringRef customSectionName() const override { return StringRef(); }
-
- DeadStripKind deadStrip() const override {
- return DefinedAtom::deadStripNormal;
- }
-
- ContentPermissions permissions() const override {
- return DefinedAtom::permRW_;
- }
-
- ArrayRef<uint8_t> rawContent() const override { return ArrayRef<uint8_t>(); }
-
- reference_iterator begin() const override {
- return reference_iterator(*this, nullptr);
- }
-
- reference_iterator end() const override {
- return reference_iterator(*this, nullptr);
- }
-
- const Reference *derefIterator(const void *iter) const override {
- return nullptr;
- }
-
- void incrementIterator(const void *&iter) const override {}
-
-private:
- const File &_file;
- uint32_t _ordinal;
-};
-
class OrderPass : public Pass {
public:
/// Sorts atoms by position
- void perform(std::unique_ptr<MutableFile> &file) override {
- MutableFile::DefinedAtomRange defined = file->definedAtoms();
+ std::error_code perform(SimpleFile &file) override {
+ SimpleFile::DefinedAtomRange defined = file.definedAtoms();
std::sort(defined.begin(), defined.end(), DefinedAtom::compareByPosition);
+ return std::error_code();
}
};
@@ -161,10 +41,9 @@ bool CoreLinkingContext::validateImpl(raw_ostream &) {
void CoreLinkingContext::addPasses(PassManager &pm) {
for (StringRef name : _passNames) {
- if (name.equals("order"))
- pm.add(std::unique_ptr<Pass>(new OrderPass()));
- else
- llvm_unreachable("bad pass name");
+ (void)name;
+ assert(name == "order" && "bad pass name");
+ pm.add(llvm::make_unique<OrderPass>());
}
}
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64DynamicLibraryWriter.h b/lib/ReaderWriter/ELF/AArch64/AArch64DynamicLibraryWriter.h
index 12ba52a38f38..73864d2b4c38 100644
--- a/lib/ReaderWriter/ELF/AArch64/AArch64DynamicLibraryWriter.h
+++ b/lib/ReaderWriter/ELF/AArch64/AArch64DynamicLibraryWriter.h
@@ -16,51 +16,27 @@
namespace lld {
namespace elf {
-template <class ELFT>
-class AArch64DynamicLibraryWriter : public DynamicLibraryWriter<ELFT> {
+class AArch64DynamicLibraryWriter : public DynamicLibraryWriter<ELF64LE> {
public:
- AArch64DynamicLibraryWriter(AArch64LinkingContext &context,
- AArch64TargetLayout<ELFT> &layout);
+ AArch64DynamicLibraryWriter(AArch64LinkingContext &ctx,
+ TargetLayout<ELF64LE> &layout);
protected:
// Add any runtime files and their atoms to the output
- virtual bool createImplicitFiles(std::vector<std::unique_ptr<File>> &);
-
- virtual void finalizeDefaultAtomValues() {
- return DynamicLibraryWriter<ELFT>::finalizeDefaultAtomValues();
- }
-
- virtual void addDefaultAtoms() {
- return DynamicLibraryWriter<ELFT>::addDefaultAtoms();
- }
-
-private:
- class GOTFile : public SimpleFile {
- public:
- GOTFile(const ELFLinkingContext &eti) : SimpleFile("GOTFile") {}
- llvm::BumpPtrAllocator _alloc;
- };
-
- std::unique_ptr<GOTFile> _gotFile;
- AArch64LinkingContext &_context;
- AArch64TargetLayout<ELFT> &_AArch64Layout;
+ void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
};
-template <class ELFT>
-AArch64DynamicLibraryWriter<ELFT>::AArch64DynamicLibraryWriter(
- AArch64LinkingContext &context, AArch64TargetLayout<ELFT> &layout)
- : DynamicLibraryWriter<ELFT>(context, layout),
- _gotFile(new GOTFile(context)), _context(context),
- _AArch64Layout(layout) {}
+AArch64DynamicLibraryWriter::AArch64DynamicLibraryWriter(
+ AArch64LinkingContext &ctx, TargetLayout<ELF64LE> &layout)
+ : DynamicLibraryWriter(ctx, layout) {}
-template <class ELFT>
-bool AArch64DynamicLibraryWriter<ELFT>::createImplicitFiles(
+void AArch64DynamicLibraryWriter::createImplicitFiles(
std::vector<std::unique_ptr<File>> &result) {
- DynamicLibraryWriter<ELFT>::createImplicitFiles(result);
- _gotFile->addAtom(*new (_gotFile->_alloc) GLOBAL_OFFSET_TABLEAtom(*_gotFile));
- _gotFile->addAtom(*new (_gotFile->_alloc) DYNAMICAtom(*_gotFile));
- result.push_back(std::move(_gotFile));
- return true;
+ 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
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64ELFFile.h b/lib/ReaderWriter/ELF/AArch64/AArch64ELFFile.h
deleted file mode 100644
index 9d5207c1c4b4..000000000000
--- a/lib/ReaderWriter/ELF/AArch64/AArch64ELFFile.h
+++ /dev/null
@@ -1,41 +0,0 @@
-//===- lib/ReaderWriter/ELF/AArch64/AArch64ELFFile.h ----------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_ELF_AARCH64_AARCH64_ELF_FILE_H
-#define LLD_READER_WRITER_ELF_AARCH64_AARCH64_ELF_FILE_H
-
-#include "ELFReader.h"
-
-namespace lld {
-namespace elf {
-
-class AArch64LinkingContext;
-
-template <class ELFT> class AArch64ELFFile : public ELFFile<ELFT> {
-public:
- AArch64ELFFile(std::unique_ptr<MemoryBuffer> mb, AArch64LinkingContext &ctx)
- : ELFFile<ELFT>(std::move(mb), ctx) {}
-
- static ErrorOr<std::unique_ptr<AArch64ELFFile>>
- create(std::unique_ptr<MemoryBuffer> mb, AArch64LinkingContext &ctx) {
- return std::unique_ptr<AArch64ELFFile<ELFT>>(
- new AArch64ELFFile<ELFT>(std::move(mb), ctx));
- }
-};
-
-template <class ELFT> class AArch64DynamicFile : public DynamicFile<ELFT> {
-public:
- AArch64DynamicFile(const AArch64LinkingContext &context, StringRef name)
- : DynamicFile<ELFT>(context, name) {}
-};
-
-} // elf
-} // lld
-
-#endif // LLD_READER_WRITER_ELF_AARCH64_AARCH64_ELF_FILE_H
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64ELFReader.h b/lib/ReaderWriter/ELF/AArch64/AArch64ELFReader.h
deleted file mode 100644
index 05f312db3e7b..000000000000
--- a/lib/ReaderWriter/ELF/AArch64/AArch64ELFReader.h
+++ /dev/null
@@ -1,62 +0,0 @@
-//===- lib/ReaderWriter/ELF/AArch64/AArch64ELFReader.h --------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_AARCH64_AARCH64_ELF_READER_H
-#define LLD_READER_WRITER_AARCH64_AARCH64_ELF_READER_H
-
-#include "AArch64ELFFile.h"
-#include "ELFReader.h"
-
-namespace lld {
-namespace elf {
-
-typedef llvm::object::ELFType<llvm::support::little, 2, true> AArch64ELFType;
-
-struct AArch64DynamicFileCreateELFTraits {
- typedef llvm::ErrorOr<std::unique_ptr<lld::SharedLibraryFile>> result_type;
-
- template <class ELFT>
- static result_type create(std::unique_ptr<llvm::MemoryBuffer> mb,
- AArch64LinkingContext &ctx) {
- return lld::elf::AArch64DynamicFile<ELFT>::create(std::move(mb), ctx);
- }
-};
-
-struct AArch64ELFFileCreateELFTraits {
- typedef llvm::ErrorOr<std::unique_ptr<lld::File>> result_type;
-
- template <class ELFT>
- static result_type create(std::unique_ptr<llvm::MemoryBuffer> mb,
- AArch64LinkingContext &ctx) {
- return lld::elf::AArch64ELFFile<ELFT>::create(std::move(mb), ctx);
- }
-};
-
-class AArch64ELFObjectReader
- : public ELFObjectReader<AArch64ELFType, AArch64ELFFileCreateELFTraits,
- AArch64LinkingContext> {
-public:
- AArch64ELFObjectReader(AArch64LinkingContext &ctx)
- : ELFObjectReader<AArch64ELFType, AArch64ELFFileCreateELFTraits,
- AArch64LinkingContext>(ctx, llvm::ELF::EM_AARCH64) {}
-};
-
-class AArch64ELFDSOReader
- : public ELFDSOReader<AArch64ELFType, AArch64DynamicFileCreateELFTraits,
- AArch64LinkingContext> {
-public:
- AArch64ELFDSOReader(AArch64LinkingContext &ctx)
- : ELFDSOReader<AArch64ELFType, AArch64DynamicFileCreateELFTraits,
- AArch64LinkingContext>(ctx, llvm::ELF::EM_AARCH64) {}
-};
-
-} // namespace elf
-} // namespace lld
-
-#endif // LLD_READER_WRITER_AARCH64_AARCH64_ELF_READER_H
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.cpp b/lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.cpp
new file mode 100644
index 000000000000..9a9ec6cba12b
--- /dev/null
+++ b/lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.cpp
@@ -0,0 +1,52 @@
+//===- 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
index 73963f56ef70..eef825040ffa 100644
--- a/lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.h
+++ b/lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.h
@@ -9,59 +9,29 @@
#ifndef AARCH64_EXECUTABLE_WRITER_H
#define AARCH64_EXECUTABLE_WRITER_H
-#include "AArch64LinkingContext.h"
#include "ExecutableWriter.h"
namespace lld {
namespace elf {
-template <class ELFT>
-class AArch64ExecutableWriter : public ExecutableWriter<ELFT> {
+class AArch64TargetLayout;
+class AArch64LinkingContext;
+
+class AArch64ExecutableWriter : public ExecutableWriter<ELF64LE> {
public:
- AArch64ExecutableWriter(AArch64LinkingContext &context,
- AArch64TargetLayout<ELFT> &layout);
+ AArch64ExecutableWriter(AArch64LinkingContext &ctx,
+ AArch64TargetLayout &layout);
protected:
// Add any runtime files and their atoms to the output
- bool createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
-
- void finalizeDefaultAtomValues() override {
- return ExecutableWriter<ELFT>::finalizeDefaultAtomValues();
- }
+ void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
- void addDefaultAtoms() override{
- return ExecutableWriter<ELFT>::addDefaultAtoms();
- }
+ void buildDynamicSymbolTable(const File &file) override;
private:
- class GOTFile : public SimpleFile {
- public:
- GOTFile(const ELFLinkingContext &eti) : SimpleFile("GOTFile") {}
- llvm::BumpPtrAllocator _alloc;
- };
-
- std::unique_ptr<GOTFile> _gotFile;
- AArch64LinkingContext &_context;
- AArch64TargetLayout<ELFT> &_AArch64Layout;
+ AArch64TargetLayout &_targetLayout;
};
-template <class ELFT>
-AArch64ExecutableWriter<ELFT>::AArch64ExecutableWriter(
- AArch64LinkingContext &context, AArch64TargetLayout<ELFT> &layout)
- : ExecutableWriter<ELFT>(context, layout), _gotFile(new GOTFile(context)),
- _context(context), _AArch64Layout(layout) {}
-
-template <class ELFT>
-bool AArch64ExecutableWriter<ELFT>::createImplicitFiles(
- std::vector<std::unique_ptr<File>> &result) {
- ExecutableWriter<ELFT>::createImplicitFiles(result);
- _gotFile->addAtom(*new (_gotFile->_alloc) GLOBAL_OFFSET_TABLEAtom(*_gotFile));
- if (_context.isDynamic())
- _gotFile->addAtom(*new (_gotFile->_alloc) DYNAMICAtom(*_gotFile));
- result.push_back(std::move(_gotFile));
- return true;
-}
-
} // namespace elf
} // namespace lld
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.cpp b/lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.cpp
index 9eb98f447709..ba883f7f59db 100644
--- a/lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.cpp
+++ b/lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.cpp
@@ -12,22 +12,34 @@
#include "AArch64TargetHandler.h"
using namespace lld;
+using namespace lld::elf;
std::unique_ptr<ELFLinkingContext>
-elf::AArch64LinkingContext::create(llvm::Triple triple) {
+elf::createAArch64LinkingContext(llvm::Triple triple) {
if (triple.getArch() == llvm::Triple::aarch64)
- return std::unique_ptr<ELFLinkingContext>(
- new elf::AArch64LinkingContext(triple));
+ return llvm::make_unique<AArch64LinkingContext>(triple);
return nullptr;
}
-elf::AArch64LinkingContext::AArch64LinkingContext(llvm::Triple triple)
- : ELFLinkingContext(triple, std::unique_ptr<TargetHandlerBase>(
- new AArch64TargetHandler(*this))) {}
+AArch64LinkingContext::AArch64LinkingContext(llvm::Triple triple)
+ : ELFLinkingContext(triple, std::unique_ptr<TargetHandler>(
+ new AArch64TargetHandler(*this))) {}
-void elf::AArch64LinkingContext::addPasses(PassManager &pm) {
+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
index ebd91fe0a95b..25a173158318 100644
--- a/lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.h
+++ b/lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.h
@@ -24,10 +24,11 @@ enum {
class AArch64LinkingContext final : public ELFLinkingContext {
public:
- static std::unique_ptr<ELFLinkingContext> create(llvm::Triple);
+ 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)
@@ -88,6 +89,11 @@ public:
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
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.cpp b/lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.cpp
index d1ecc7fa884b..ac7c769ec26d 100644
--- a/lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.cpp
+++ b/lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.cpp
@@ -13,11 +13,14 @@
#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;
-#define PAGE(X) ((X) & ~0x0FFFL)
+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) {
@@ -28,77 +31,130 @@ static bool withinSignedUnsignedRange(int64_t X, int bits) {
static void relocR_AARCH64_ABS64(uint8_t *location, uint64_t P, uint64_t S,
int64_t A) {
int64_t result = (int64_t)S + A;
- DEBUG_WITH_TYPE(
- "AArch64", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
- llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
- llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
- llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
+ 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 void relocR_AARCH64_PREL32(uint8_t *location, uint64_t P, uint64_t S,
- int64_t A) {
- int32_t result = (int32_t)((S + A) - P);
- write32le(location, result + (int32_t)read32le(location));
-}
-
/// \brief R_AARCH64_ABS32 - word32: S + A
static std::error_code relocR_AARCH64_ABS32(uint8_t *location, uint64_t P,
uint64_t S, int64_t A) {
int64_t result = S + A;
if (!withinSignedUnsignedRange(result, 32))
return make_out_of_range_reloc_error();
- DEBUG_WITH_TYPE(
- "AArch64", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
- llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
- llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
- llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
+ 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_ADR_PREL_PG_HI21 - Page(S+A) - Page(P)
-static void relocR_AARCH64_ADR_PREL_PG_HI21(uint8_t *location, uint64_t P,
+/// \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) {
- uint64_t result = (PAGE(S + A) - PAGE(P));
+ 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_WITH_TYPE(
- "AArch64", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: " << Twine::utohexstr(S);
- llvm::dbgs() << " A: " << Twine::utohexstr(A);
- llvm::dbgs() << " P: " << Twine::utohexstr(P);
- llvm::dbgs() << " immhi: " << Twine::utohexstr(immhi);
- llvm::dbgs() << " immlo: " << Twine::utohexstr(immlo);
- llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n");
+ 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));
- // TODO: Make sure this is correct!
+ return std::error_code();
}
/// \brief R_AARCH64_ADR_PREL_LO21 - S + A - P
-static void relocR_AARCH64_ADR_PREL_LO21(uint8_t *location, uint64_t P,
- uint64_t S, int64_t A) {
- uint64_t result = (S + A) - P;
+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_WITH_TYPE(
- "AArch64", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: " << Twine::utohexstr(S);
- llvm::dbgs() << " A: " << Twine::utohexstr(A);
- llvm::dbgs() << " P: " << Twine::utohexstr(P);
- llvm::dbgs() << " immhi: " << Twine::utohexstr(immhi);
- llvm::dbgs() << " immlo: " << Twine::utohexstr(immlo);
- llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n");
+ 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));
- // TODO: Make sure this is correct!
+ return std::error_code();
}
/// \brief R_AARCH64_ADD_ABS_LO12_NC
@@ -106,41 +162,46 @@ static void relocR_AARCH64_ADD_ABS_LO12_NC(uint8_t *location, uint64_t P,
uint64_t S, int64_t A) {
int32_t result = (int32_t)((S + A) & 0xFFF);
result <<= 10;
- DEBUG_WITH_TYPE(
- "AArch64", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: " << Twine::utohexstr(S);
- llvm::dbgs() << " A: " << Twine::utohexstr(A);
- llvm::dbgs() << " P: " << Twine::utohexstr(P);
- llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n");
+ 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 void relocJump26(uint8_t *location, uint64_t P, uint64_t S, int64_t A) {
- int32_t result = (int32_t)((S + A) - P);
+/// \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_WITH_TYPE(
- "AArch64", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: " << Twine::utohexstr(S);
- llvm::dbgs() << " A: " << Twine::utohexstr(A);
- llvm::dbgs() << " P: " << Twine::utohexstr(P);
- llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n");
+ 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 void relocR_AARCH64_CONDBR19(uint8_t *location, uint64_t P, uint64_t S,
- int64_t A) {
- int32_t result = (int32_t)((S + A) - P);
+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_WITH_TYPE(
- "AArch64", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: " << Twine::utohexstr(S);
- llvm::dbgs() << " A: " << Twine::utohexstr(A);
- llvm::dbgs() << " P: " << Twine::utohexstr(P);
- llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n");
+ 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
@@ -148,12 +209,11 @@ static void relocR_AARCH64_LDST8_ABS_LO12_NC(uint8_t *location, uint64_t P,
uint64_t S, int64_t A) {
int32_t result = (int32_t)((S + A) & 0xFFF);
result <<= 10;
- DEBUG_WITH_TYPE(
- "AArch64", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: " << Twine::utohexstr(S);
- llvm::dbgs() << " A: " << Twine::utohexstr(A);
- llvm::dbgs() << " P: " << Twine::utohexstr(P);
- llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n");
+ 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));
}
@@ -163,12 +223,11 @@ static void relocR_AARCH64_LDST16_ABS_LO12_NC(uint8_t *location, uint64_t P,
int32_t result = (int32_t)(S + A);
result &= 0x0FFC;
result <<= 9;
- DEBUG_WITH_TYPE(
- "AArch64", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: " << Twine::utohexstr(S);
- llvm::dbgs() << " A: " << Twine::utohexstr(A);
- llvm::dbgs() << " P: " << Twine::utohexstr(P);
- llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n");
+ 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));
}
@@ -178,12 +237,11 @@ static void relocR_AARCH64_LDST32_ABS_LO12_NC(uint8_t *location, uint64_t P,
int32_t result = (int32_t)(S + A);
result &= 0x0FFC;
result <<= 8;
- DEBUG_WITH_TYPE(
- "AArch64", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: " << Twine::utohexstr(S);
- llvm::dbgs() << " A: " << Twine::utohexstr(A);
- llvm::dbgs() << " P: " << Twine::utohexstr(P);
- llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n");
+ 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));
}
@@ -193,12 +251,11 @@ static void relocR_AARCH64_LDST64_ABS_LO12_NC(uint8_t *location, uint64_t P,
int32_t result = (int32_t)(S + A);
result &= 0x0FF8;
result <<= 7;
- DEBUG_WITH_TYPE(
- "AArch64", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: " << Twine::utohexstr(S);
- llvm::dbgs() << " A: " << Twine::utohexstr(A);
- llvm::dbgs() << " P: " << Twine::utohexstr(P);
- llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n");
+ 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));
}
@@ -208,83 +265,89 @@ static void relocR_AARCH64_LDST128_ABS_LO12_NC(uint8_t *location, uint64_t P,
int32_t result = (int32_t)(S + A);
result &= 0x0FF8;
result <<= 6;
- DEBUG_WITH_TYPE(
- "AArch64", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: " << Twine::utohexstr(S);
- llvm::dbgs() << " A: " << Twine::utohexstr(A);
- llvm::dbgs() << " P: " << Twine::utohexstr(P);
- llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n");
+ 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 void relocR_AARCH64_ADR_GOT_PAGE(uint8_t *location, uint64_t P,
- uint64_t S, int64_t A) {
- uint64_t result = PAGE(S + A) - PAGE(P);
- result >>= 12;
+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_WITH_TYPE(
- "AArch64", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: " << Twine::utohexstr(S);
- llvm::dbgs() << " A: " << Twine::utohexstr(A);
- llvm::dbgs() << " P: " << Twine::utohexstr(P);
- llvm::dbgs() << " immhi: " << Twine::utohexstr(immhi);
- llvm::dbgs() << " immlo: " << Twine::utohexstr(immlo);
- llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n");
- write32le(location, result | read32le(location));
+ 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 void relocR_AARCH64_LD64_GOT_LO12_NC(uint8_t *location, uint64_t P,
- uint64_t S, int64_t A) {
+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_WITH_TYPE(
- "AArch64", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: " << Twine::utohexstr(S);
- llvm::dbgs() << " A: " << Twine::utohexstr(A);
- llvm::dbgs() << " P: " << Twine::utohexstr(P);
- llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n");
+ 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_WITH_TYPE(
- "AArch64", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: " << Twine::utohexstr(S);
- llvm::dbgs() << " A: " << Twine::utohexstr(A);
- llvm::dbgs() << " P: " << Twine::utohexstr(P);
- llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n");
+ 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 void relocR_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21(uint8_t *location,
- uint64_t P, uint64_t S,
- int64_t A) {
- int64_t result = PAGE(S + A) - PAGE(P);
+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_WITH_TYPE(
- "AArch64", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: " << Twine::utohexstr(S);
- llvm::dbgs() << " A: " << Twine::utohexstr(A);
- llvm::dbgs() << " P: " << Twine::utohexstr(P);
- llvm::dbgs() << " immhi: " << Twine::utohexstr(immhi);
- llvm::dbgs() << " immlo: " << Twine::utohexstr(immlo);
- llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n");
+ 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
@@ -294,28 +357,31 @@ static void relocR_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC(uint8_t *location,
int32_t result = S + A;
result &= 0xFF8;
result <<= 7;
- DEBUG_WITH_TYPE(
- "AArch64", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: " << Twine::utohexstr(S);
- llvm::dbgs() << " A: " << Twine::utohexstr(A);
- llvm::dbgs() << " P: " << Twine::utohexstr(P);
- llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n");
+ 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 void relocR_AARCH64_TLSLE_ADD_TPREL_HI12(uint8_t *location, uint64_t P,
- uint64_t S, int64_t A) {
- int32_t result = S + A;
+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_WITH_TYPE(
- "AArch64", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: " << Twine::utohexstr(S);
- llvm::dbgs() << " A: " << Twine::utohexstr(A);
- llvm::dbgs() << " P: " << Twine::utohexstr(P);
- llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n");
+ 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
@@ -325,22 +391,76 @@ static void relocR_AARCH64_TLSLE_ADD_TPREL_LO12_NC(uint8_t *location,
int32_t result = S + A;
result &= 0x0FFF;
result <<= 10;
- DEBUG_WITH_TYPE(
- "AArch64", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: " << Twine::utohexstr(S);
- llvm::dbgs() << " A: " << Twine::utohexstr(A);
- llvm::dbgs() << " P: " << Twine::utohexstr(P);
- llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n");
+ 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 lld::AtomLayout &atom,
+ ELFWriter &writer, llvm::FileOutputBuffer &buf, const AtomLayout &atom,
const Reference &ref) const {
uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset;
- uint8_t *location = atomContent + ref.offsetInAtom();
- uint64_t targetVAddress = writer.addressOfAtom(ref.target());
- uint64_t relocVAddress = atom._virtualAddr + ref.offsetInAtom();
+ 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();
@@ -349,92 +469,88 @@ std::error_code AArch64TargetRelocationHandler::applyRelocation(
case R_AARCH64_NONE:
break;
case R_AARCH64_ABS64:
- relocR_AARCH64_ABS64(location, relocVAddress, targetVAddress, ref.addend());
- break;
- case R_AARCH64_PREL32:
- relocR_AARCH64_PREL32(location, relocVAddress, targetVAddress,
- ref.addend());
+ relocR_AARCH64_ABS64(loc, reloc, target, addend);
break;
case R_AARCH64_ABS32:
- return relocR_AARCH64_ABS32(location, relocVAddress, targetVAddress,
- ref.addend());
- // Runtime only relocations. Ignore here.
- case R_AARCH64_RELATIVE:
- case R_AARCH64_IRELATIVE:
- case R_AARCH64_JUMP_SLOT:
- case R_AARCH64_GLOB_DAT:
+ 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:
- relocR_AARCH64_ADR_PREL_PG_HI21(location, relocVAddress, targetVAddress,
- ref.addend());
- break;
+ return relocR_AARCH64_ADR_PREL_PG_HI21(loc, reloc, target, addend);
case R_AARCH64_ADR_PREL_LO21:
- relocR_AARCH64_ADR_PREL_LO21(location, relocVAddress, targetVAddress,
- ref.addend());
- break;
+ return relocR_AARCH64_ADR_PREL_LO21(loc, reloc, target, addend);
case R_AARCH64_ADD_ABS_LO12_NC:
- relocR_AARCH64_ADD_ABS_LO12_NC(location, relocVAddress, targetVAddress,
- ref.addend());
+ relocR_AARCH64_ADD_ABS_LO12_NC(loc, reloc, target, addend);
break;
case R_AARCH64_CALL26:
case R_AARCH64_JUMP26:
- relocJump26(location, relocVAddress, targetVAddress, ref.addend());
- break;
+ return relocJump26(loc, reloc, target, addend);
case R_AARCH64_CONDBR19:
- relocR_AARCH64_CONDBR19(location, relocVAddress, targetVAddress,
- ref.addend());
- break;
+ return relocR_AARCH64_CONDBR19(loc, reloc, target, addend);
case R_AARCH64_ADR_GOT_PAGE:
- relocR_AARCH64_ADR_GOT_PAGE(location, relocVAddress, targetVAddress,
- ref.addend());
- break;
+ return relocR_AARCH64_ADR_GOT_PAGE(loc, reloc, target, addend);
case R_AARCH64_LD64_GOT_LO12_NC:
- relocR_AARCH64_LD64_GOT_LO12_NC(location, relocVAddress, targetVAddress,
- ref.addend());
- break;
+ return relocR_AARCH64_LD64_GOT_LO12_NC(loc, reloc, target, addend);
case R_AARCH64_LDST8_ABS_LO12_NC:
- relocR_AARCH64_LDST8_ABS_LO12_NC(location, relocVAddress, targetVAddress,
- ref.addend());
+ relocR_AARCH64_LDST8_ABS_LO12_NC(loc, reloc, target, addend);
break;
case R_AARCH64_LDST16_ABS_LO12_NC:
- relocR_AARCH64_LDST16_ABS_LO12_NC(location, relocVAddress, targetVAddress,
- ref.addend());
+ relocR_AARCH64_LDST16_ABS_LO12_NC(loc, reloc, target, addend);
break;
case R_AARCH64_LDST32_ABS_LO12_NC:
- relocR_AARCH64_LDST32_ABS_LO12_NC(location, relocVAddress, targetVAddress,
- ref.addend());
+ relocR_AARCH64_LDST32_ABS_LO12_NC(loc, reloc, target, addend);
break;
case R_AARCH64_LDST64_ABS_LO12_NC:
- relocR_AARCH64_LDST64_ABS_LO12_NC(location, relocVAddress, targetVAddress,
- ref.addend());
+ relocR_AARCH64_LDST64_ABS_LO12_NC(loc, reloc, target, addend);
break;
case R_AARCH64_LDST128_ABS_LO12_NC:
- relocR_AARCH64_LDST128_ABS_LO12_NC(location, relocVAddress, targetVAddress,
- ref.addend());
+ relocR_AARCH64_LDST128_ABS_LO12_NC(loc, reloc, target, addend);
break;
case ADD_AARCH64_GOTRELINDEX:
- relocADD_AARCH64_GOTRELINDEX(location, relocVAddress, targetVAddress,
- ref.addend());
+ relocADD_AARCH64_GOTRELINDEX(loc, reloc, target, addend);
break;
case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
- relocR_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21(location, relocVAddress,
- targetVAddress, ref.addend());
- break;
+ 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(location, relocVAddress,
- targetVAddress, ref.addend());
+ relocR_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC(loc, reloc, target, addend);
break;
case R_AARCH64_TLSLE_ADD_TPREL_HI12:
- relocR_AARCH64_TLSLE_ADD_TPREL_HI12(location, relocVAddress, targetVAddress,
- ref.addend());
+ 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;
- case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
- relocR_AARCH64_TLSLE_ADD_TPREL_LO12_NC(location, relocVAddress,
- targetVAddress, ref.addend());
+ // Runtime only relocations. Ignore here.
+ case R_AARCH64_RELATIVE:
+ case R_AARCH64_IRELATIVE:
+ case R_AARCH64_JUMP_SLOT:
+ case R_AARCH64_GLOB_DAT:
+ 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
index b1d3c09dc936..8cde7a03e51a 100644
--- a/lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.h
+++ b/lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.h
@@ -10,21 +10,24 @@
#ifndef AARCH64_RELOCATION_HANDLER_H
#define AARCH64_RELOCATION_HANDLER_H
-#include "AArch64TargetHandler.h"
+#include "lld/ReaderWriter/ELFLinkingContext.h"
namespace lld {
namespace elf {
-typedef llvm::object::ELFType<llvm::support::little, 2, true> AArch64ELFType;
-template <class ELFT> class AArch64TargetLayout;
+class AArch64TargetLayout;
class AArch64TargetRelocationHandler final : public TargetRelocationHandler {
public:
+ AArch64TargetRelocationHandler(AArch64TargetLayout &layout)
+ : _layout(layout) {}
+
std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &,
- const lld::AtomLayout &,
+ const AtomLayout &,
const Reference &) const override;
- static const Registry::KindStrings kindStrings[];
+private:
+ AArch64TargetLayout &_layout;
};
} // end namespace elf
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.cpp b/lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.cpp
index 0bd12958b27b..4d94a793665c 100644
--- a/lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.cpp
+++ b/lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.cpp
@@ -28,52 +28,79 @@ using namespace lld;
using namespace lld::elf;
using namespace llvm::ELF;
-namespace {
// .got values
-const uint8_t AArch64GotAtomContent[8] = {0};
+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)
-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
+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)
-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
+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, StringRef secName) : GOTAtom(f, secName) {}
+ 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) {}
@@ -84,13 +111,22 @@ public:
class AArch64PLTAtom : public PLTAtom {
public:
- AArch64PLTAtom(const File &f, StringRef secName) : PLTAtom(f, secName) {}
+ 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") {
@@ -149,9 +185,16 @@ template <class Derived> class AArch64RelocationPass : public Pass {
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)->handleGOT(ref);
+ 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;
}
}
@@ -164,9 +207,9 @@ protected:
auto plt = _pltMap.find(da);
if (plt != _pltMap.end())
return plt->second;
- auto ga = new (_file._alloc) AArch64GOTAtom(_file, ".got.plt");
+ auto ga = new (_file._alloc) AArch64GOTPLTAtom(_file);
ga->addReferenceELF_AArch64(R_AARCH64_IRELATIVE, 0, da, 0);
- auto pa = new (_file._alloc) AArch64PLTAtom(_file, ".plt");
+ auto pa = new (_file._alloc) AArch64PLTAtom(_file);
pa->addReferenceELF_AArch64(R_AARCH64_PREL32, 2, ga, -4);
#ifndef NDEBUG
ga->_name = "__got_ifunc_";
@@ -193,11 +236,11 @@ protected:
}
/// \brief Create a GOT entry for the TP offset of a TLS atom.
- const GOTAtom *getGOTTPOFF(const Atom *atom) {
+ const GOTAtom *getGOTTPREL(const Atom *atom) {
auto got = _gotMap.find(atom);
if (got == _gotMap.end()) {
- auto g = new (_file._alloc) AArch64GOTAtom(_file, ".got");
- g->addReferenceELF_AArch64(R_AARCH64_GOTREL64, 0, atom, 0);
+ 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();
@@ -209,17 +252,53 @@ protected:
return got->second;
}
- /// \brief Create a TPOFF64 GOT entry and change the relocation to a PC32 to
- /// the GOT.
- void handleGOTTPOFF(const Reference &ref) {
- const_cast<Reference &>(ref).setTarget(getGOTTPOFF(ref.target()));
- const_cast<Reference &>(ref).setKindValue(R_AARCH64_PREL32);
+ /// \brief Create a GOT 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) AArch64GOTAtom(_file, ".got.plt");
+ _null = new (_file._alloc) AArch64GOTPLTAtom(_file);
#ifndef NDEBUG
_null->_name = "__got_null";
#endif
@@ -230,7 +309,7 @@ protected:
const GOTAtom *getGOT(const DefinedAtom *da) {
auto got = _gotMap.find(da);
if (got == _gotMap.end()) {
- auto g = new (_file._alloc) AArch64GOTAtom(_file, ".got");
+ auto g = new (_file._alloc) AArch64GOTAtom(_file);
g->addReferenceELF_AArch64(R_AARCH64_ABS64, 0, da, 0);
#ifndef NDEBUG
g->_name = "__got_";
@@ -244,9 +323,7 @@ protected:
}
public:
- AArch64RelocationPass(const ELFLinkingContext &ctx)
- : _file(ctx), _ctx(ctx), _null(nullptr), _PLT0(nullptr), _got0(nullptr),
- _got1(nullptr) {}
+ AArch64RelocationPass(const ELFLinkingContext &ctx) : _file(ctx), _ctx(ctx) {}
/// \brief Do the pass.
///
@@ -256,32 +333,32 @@ public:
///
/// After all references are handled, the atoms created during that are all
/// added to mf.
- void perform(std::unique_ptr<MutableFile> &mf) override {
+ 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()) {
+ : mf.undefined()) {
llvm::dbgs() << " Name of Atom: " << atom->name().str() << "\n";
} llvm::dbgs()
<< "Shared Library Atoms"
<< "\n";
for (const auto &atom
- : mf->sharedLibrary()) {
+ : mf.sharedLibrary()) {
llvm::dbgs() << " Name of Atom: " << atom->name().str() << "\n";
} llvm::dbgs()
<< "Absolute Atoms"
<< "\n";
for (const auto &atom
- : mf->absolute()) {
+ : 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 &atom : mf.defined()) {
for (const auto &ref : *atom) {
handleReference(*atom, *ref);
}
@@ -289,32 +366,39 @@ public:
// Add all created atoms to the link.
uint64_t ordinal = 0;
- if (_PLT0) {
- _PLT0->setOrdinal(ordinal++);
- mf->addAtom(*_PLT0);
+ if (_plt0) {
+ _plt0->setOrdinal(ordinal++);
+ mf.addAtom(*_plt0);
}
for (auto &plt : _pltVector) {
plt->setOrdinal(ordinal++);
- mf->addAtom(*plt);
+ mf.addAtom(*plt);
}
if (_null) {
_null->setOrdinal(ordinal++);
- mf->addAtom(*_null);
+ mf.addAtom(*_null);
}
- if (_PLT0) {
+ if (_plt0) {
_got0->setOrdinal(ordinal++);
_got1->setOrdinal(ordinal++);
- mf->addAtom(*_got0);
- mf->addAtom(*_got1);
+ mf.addAtom(*_got0);
+ mf.addAtom(*_got1);
}
for (auto &got : _gotVector) {
got->setOrdinal(ordinal++);
- mf->addAtom(*got);
+ 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);
+ mf.addAtom(*obj);
}
+
+ return std::error_code();
}
protected:
@@ -333,18 +417,19 @@ protected:
/// \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;
+ 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;
- GOTAtom *_got0;
- GOTAtom *_got1;
+ PLT0Atom *_plt0 = nullptr;
+ GOTAtom *_got0 = nullptr;
+ GOTAtom *_got1 = nullptr;
/// @}
};
@@ -394,31 +479,31 @@ public:
: AArch64RelocationPass(ctx) {}
const PLT0Atom *getPLT0() {
- if (_PLT0)
- return _PLT0;
+ if (_plt0)
+ return _plt0;
// Fill in the null entry.
getNullGOT();
- _PLT0 = new (_file._alloc) AArch64PLT0Atom(_file);
- _got0 = new (_file._alloc) AArch64GOTAtom(_file, ".got.plt");
- _got1 = new (_file._alloc) AArch64GOTAtom(_file, ".got.plt");
- _PLT0->addReferenceELF_AArch64(R_AARCH64_ADR_GOT_PAGE, 4, _got0, 0);
- _PLT0->addReferenceELF_AArch64(R_AARCH64_LD64_GOT_LO12_NC, 8, _got1, 0);
- _PLT0->addReferenceELF_AArch64(ADD_AARCH64_GOTRELINDEX, 12, _got1, 0);
+ _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";
+ _plt0->_name = "__PLT0";
_got0->_name = "__got0";
_got1->_name = "__got1";
#endif
- return _PLT0;
+ return _plt0;
}
const PLTAtom *getPLTEntry(const Atom *a) {
auto plt = _pltMap.find(a);
if (plt != _pltMap.end())
return plt->second;
- auto ga = new (_file._alloc) AArch64GOTAtom(_file, ".got.plt");
+ auto ga = new (_file._alloc) AArch64GOTPLTAtom(_file);
ga->addReferenceELF_AArch64(R_AARCH64_JUMP_SLOT, 0, a, 0);
- auto pa = new (_file._alloc) AArch64PLTAtom(_file, ".plt");
+ 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);
@@ -485,7 +570,7 @@ public:
const GOTAtom *getSharedGOT(const SharedLibraryAtom *sla) {
auto got = _gotMap.find(sla);
if (got == _gotMap.end()) {
- auto g = new (_file._alloc) AArch64GOTAtom(_file, ".got");
+ auto g = new (_file._alloc) AArch64GOTAtom(_file);
g->addReferenceELF_AArch64(R_AARCH64_GLOB_DAT, 0, sla, 0);
#ifndef NDEBUG
g->_name = "__got_";
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64SectionChunks.cpp b/lib/ReaderWriter/ELF/AArch64/AArch64SectionChunks.cpp
new file mode 100644
index 000000000000..2734bcdbda5f
--- /dev/null
+++ b/lib/ReaderWriter/ELF/AArch64/AArch64SectionChunks.cpp
@@ -0,0 +1,39 @@
+//===- 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
new file mode 100644
index 000000000000..2b7594c2db84
--- /dev/null
+++ b/lib/ReaderWriter/ELF/AArch64/AArch64SectionChunks.h
@@ -0,0 +1,37 @@
+//===- 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
index 607f767f8b8a..083b492c1607 100644
--- a/lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.cpp
+++ b/lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.cpp
@@ -12,41 +12,40 @@
#include "AArch64ExecutableWriter.h"
#include "AArch64LinkingContext.h"
#include "AArch64TargetHandler.h"
+#include "AArch64SectionChunks.h"
using namespace lld;
using namespace elf;
-AArch64TargetHandler::AArch64TargetHandler(AArch64LinkingContext &context)
- : _context(context),
- _AArch64TargetLayout(new AArch64TargetLayout<AArch64ELFType>(context)),
- _AArch64RelocationHandler(new AArch64TargetRelocationHandler()) {}
-
-void AArch64TargetHandler::registerRelocationNames(Registry &registry) {
- registry.addKindTable(Reference::KindNamespace::ELF,
- Reference::KindArch::AArch64, kindStrings);
+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->_context.getOutputELFType()) {
+ switch (this->_ctx.getOutputELFType()) {
case llvm::ELF::ET_EXEC:
- return std::unique_ptr<Writer>(new AArch64ExecutableWriter<AArch64ELFType>(
- _context, *_AArch64TargetLayout.get()));
+ return llvm::make_unique<AArch64ExecutableWriter>(_ctx, *_targetLayout);
case llvm::ELF::ET_DYN:
- return std::unique_ptr<Writer>(
- new AArch64DynamicLibraryWriter<AArch64ELFType>(
- _context, *_AArch64TargetLayout.get()));
+ return llvm::make_unique<AArch64DynamicLibraryWriter>(_ctx, *_targetLayout);
case llvm::ELF::ET_REL:
llvm_unreachable("TODO: support -r mode");
default:
llvm_unreachable("unsupported output type");
}
}
-
-#define ELF_RELOC(name, value) LLD_KIND_STRING_ENTRY(name),
-
-const Registry::KindStrings AArch64TargetHandler::kindStrings[] = {
-#include "llvm/Support/ELFRelocs/AArch64.def"
- LLD_KIND_STRING_END
-};
-
-#undef ELF_RELOC
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.h b/lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.h
index 4eb6786cdf1f..c0ecbfa9e44b 100644
--- a/lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.h
+++ b/lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.h
@@ -10,52 +10,78 @@
#ifndef LLD_READER_WRITER_ELF_AARCH64_AARCH64_TARGET_HANDLER_H
#define LLD_READER_WRITER_ELF_AARCH64_AARCH64_TARGET_HANDLER_H
-#include "AArch64ELFFile.h"
-#include "AArch64ELFReader.h"
#include "AArch64RelocationHandler.h"
-#include "DefaultTargetHandler.h"
+#include "ELFReader.h"
#include "TargetLayout.h"
#include "lld/Core/Simple.h"
namespace lld {
namespace elf {
+
class AArch64LinkingContext;
+class AArch64GOTSection;
-template <class ELFT> class AArch64TargetLayout : public TargetLayout<ELFT> {
-public:
- AArch64TargetLayout(AArch64LinkingContext &context)
- : TargetLayout<ELFT>(context) {}
-};
+class AArch64TargetLayout final : public TargetLayout<ELF64LE> {
+ typedef llvm::object::Elf_Shdr_Impl<ELF64LE> Elf_Shdr;
-class AArch64TargetHandler final : public DefaultTargetHandler<AArch64ELFType> {
public:
- AArch64TargetHandler(AArch64LinkingContext &context);
+ 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;
+ }
- AArch64TargetLayout<AArch64ELFType> &getTargetLayout() override {
- return *(_AArch64TargetLayout.get());
+ 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;
}
- void registerRelocationNames(Registry &registry) override;
+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 AArch64TargetRelocationHandler &getRelocationHandler() const override {
- return *(_AArch64RelocationHandler.get());
+ const TargetRelocationHandler &getRelocationHandler() const override {
+ return *_relocationHandler;
}
std::unique_ptr<Reader> getObjReader() override {
- return std::unique_ptr<Reader>(new AArch64ELFObjectReader(_context));
+ return llvm::make_unique<ELFReader<ELFFile<ELF64LE>>>(_ctx);
}
std::unique_ptr<Reader> getDSOReader() override {
- return std::unique_ptr<Reader>(new AArch64ELFDSOReader(_context));
+ return llvm::make_unique<ELFReader<DynamicFile<ELF64LE>>>(_ctx);
}
std::unique_ptr<Writer> getWriter() override;
private:
- static const Registry::KindStrings kindStrings[];
- AArch64LinkingContext &_context;
- std::unique_ptr<AArch64TargetLayout<AArch64ELFType>> _AArch64TargetLayout;
- std::unique_ptr<AArch64TargetRelocationHandler> _AArch64RelocationHandler;
+ AArch64LinkingContext &_ctx;
+ std::unique_ptr<AArch64TargetLayout> _targetLayout;
+ std::unique_ptr<AArch64TargetRelocationHandler> _relocationHandler;
};
} // end namespace elf
diff --git a/lib/ReaderWriter/ELF/AArch64/CMakeLists.txt b/lib/ReaderWriter/ELF/AArch64/CMakeLists.txt
index de94a4df5078..2347dda9adb0 100644
--- a/lib/ReaderWriter/ELF/AArch64/CMakeLists.txt
+++ b/lib/ReaderWriter/ELF/AArch64/CMakeLists.txt
@@ -3,6 +3,8 @@ add_llvm_library(lldAArch64ELFTarget
AArch64TargetHandler.cpp
AArch64RelocationHandler.cpp
AArch64RelocationPass.cpp
+ AArch64ExecutableWriter.cpp
+ AArch64SectionChunks.cpp
LINK_LIBS
lldELF
lldReaderWriter
diff --git a/lib/ReaderWriter/ELF/AArch64/Makefile b/lib/ReaderWriter/ELF/AArch64/Makefile
deleted file mode 100644
index 02cff4747d0d..000000000000
--- a/lib/ReaderWriter/ELF/AArch64/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-##===- lld/lib/ReaderWriter/ELF/AArch64/Makefile ----------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LLD_LEVEL := ../../../..
-LIBRARYNAME := lldAArch64ELFTarget
-USEDLIBS = lldCore.a
-CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF/AArch64 -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF
-
-include $(LLD_LEVEL)/Makefile
diff --git a/lib/ReaderWriter/ELF/AMDGPU/AMDGPUExecutableWriter.cpp b/lib/ReaderWriter/ELF/AMDGPU/AMDGPUExecutableWriter.cpp
new file mode 100644
index 000000000000..89efeb23d6f8
--- /dev/null
+++ b/lib/ReaderWriter/ELF/AMDGPU/AMDGPUExecutableWriter.cpp
@@ -0,0 +1,34 @@
+//===- lib/ReaderWriter/ELF/AMDGPU/AMDGPUExecutableWriter.cpp -------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AMDGPUExecutableWriter.h"
+
+using namespace lld;
+using namespace lld::elf;
+
+AMDGPUExecutableWriter::AMDGPUExecutableWriter(AMDGPULinkingContext &ctx,
+ AMDGPUTargetLayout &layout)
+ : ExecutableWriter(ctx, layout), _ctx(ctx) {}
+
+void AMDGPUExecutableWriter::createImplicitFiles(
+ std::vector<std::unique_ptr<File>> &Result) {
+ // ExecutableWriter::createImplicitFiles() adds C runtime symbols that we
+ // don't need, so we use the OutputELFWriter implementation instead.
+ OutputELFWriter<ELF64LE>::createImplicitFiles(Result);
+}
+
+void AMDGPUExecutableWriter::finalizeDefaultAtomValues() {
+
+ // ExecutableWriter::finalizeDefaultAtomValues() assumes the presence of
+ // C runtime symbols. However, since we skip the call to
+ // ExecutableWriter::createImplicitFiles(), these symbols are never added
+ // and ExectuableWriter::finalizeDefaultAtomValues() will crash if we call
+ // it.
+ OutputELFWriter<ELF64LE>::finalizeDefaultAtomValues();
+}
diff --git a/lib/ReaderWriter/ELF/AMDGPU/AMDGPUExecutableWriter.h b/lib/ReaderWriter/ELF/AMDGPU/AMDGPUExecutableWriter.h
new file mode 100644
index 000000000000..accc00b8a054
--- /dev/null
+++ b/lib/ReaderWriter/ELF/AMDGPU/AMDGPUExecutableWriter.h
@@ -0,0 +1,41 @@
+//===- lib/ReaderWriter/ELF/AMDGPU/AMDGPUExecutableWriter.h ---------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef AMDGPU_EXECUTABLE_WRITER_H
+#define AMDGPU_EXECUTABLE_WRITER_H
+
+#include "ExecutableWriter.h"
+#include "AMDGPULinkingContext.h"
+#include "AMDGPUSymbolTable.h"
+#include "AMDGPUTargetHandler.h"
+
+namespace lld {
+namespace elf {
+
+class AMDGPUTargetLayout;
+
+class AMDGPUExecutableWriter : public ExecutableWriter<ELF64LE> {
+public:
+ AMDGPUExecutableWriter(AMDGPULinkingContext &ctx, AMDGPUTargetLayout &layout);
+
+ unique_bump_ptr<SymbolTable<ELF64LE>> createSymbolTable() override {
+ return unique_bump_ptr<SymbolTable<ELF64LE>>(new (this->_alloc)
+ AMDGPUSymbolTable(_ctx));
+ }
+
+ void createImplicitFiles(std::vector<std::unique_ptr<File>> &Result) override;
+ void finalizeDefaultAtomValues() override;
+
+private:
+ AMDGPULinkingContext &_ctx;
+};
+
+} // namespace elf
+} // namespace lld
+
+#endif // AMDGPU_EXECUTABLE_WRITER_H
diff --git a/lib/ReaderWriter/ELF/AMDGPU/AMDGPULinkingContext.cpp b/lib/ReaderWriter/ELF/AMDGPU/AMDGPULinkingContext.cpp
new file mode 100644
index 000000000000..b1e83641fa82
--- /dev/null
+++ b/lib/ReaderWriter/ELF/AMDGPU/AMDGPULinkingContext.cpp
@@ -0,0 +1,41 @@
+//===- lib/ReaderWriter/ELF/AMDGPU/AMDGPULinkingContext.cpp ---------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===------------------------------------------------------------------------===//
+
+#include "AMDGPULinkingContext.h"
+#include "AMDGPUTargetHandler.h"
+
+namespace lld {
+namespace elf {
+
+std::unique_ptr<ELFLinkingContext>
+createAMDGPULinkingContext(llvm::Triple triple) {
+ if (triple.getArch() == llvm::Triple::amdgcn)
+ return llvm::make_unique<AMDGPULinkingContext>(triple);
+ return nullptr;
+}
+
+AMDGPULinkingContext::AMDGPULinkingContext(llvm::Triple triple)
+ : ELFLinkingContext(triple, llvm::make_unique<AMDGPUTargetHandler>(*this)) {
+}
+
+static const Registry::KindStrings kindStrings[] = {LLD_KIND_STRING_END};
+
+void AMDGPULinkingContext::registerRelocationNames(Registry &registry) {
+ registry.addKindTable(Reference::KindNamespace::ELF,
+ Reference::KindArch::AMDGPU, kindStrings);
+}
+
+void setAMDGPUELFHeader(ELFHeader<ELF64LE> &elfHeader) {
+ elfHeader.e_ident(llvm::ELF::EI_OSABI, ELFOSABI_AMDGPU_HSA);
+}
+
+StringRef AMDGPULinkingContext::entrySymbolName() const { return ""; }
+
+} // namespace elf
+} // namespace lld
diff --git a/lib/ReaderWriter/ELF/AMDGPU/AMDGPULinkingContext.h b/lib/ReaderWriter/ELF/AMDGPU/AMDGPULinkingContext.h
new file mode 100644
index 000000000000..1cc7a3c7694f
--- /dev/null
+++ b/lib/ReaderWriter/ELF/AMDGPU/AMDGPULinkingContext.h
@@ -0,0 +1,36 @@
+//===- lib/ReaderWriter/ELF/AMDGPU/AMDGPULinkingContext.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_AMDGPU_AMDGPU_LINKING_CONTEXT_H
+#define LLD_READER_WRITER_ELF_AMDGPU_AMDGPU_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 AMDGPULinkingContext final : public ELFLinkingContext {
+public:
+ AMDGPULinkingContext(llvm::Triple triple);
+ int getMachineType() const override { return llvm::ELF::EM_AMDGPU; }
+
+ void registerRelocationNames(Registry &r) override;
+
+ StringRef entrySymbolName() const override;
+};
+
+void setAMDGPUELFHeader(ELFHeader<ELF64LE> &elfHeader);
+
+} // elf
+} // lld
+
+#endif // LLD_READER_WRITER_ELF_AMDGPU_AMDGPU_LINKING_CONTEXT_H
diff --git a/lib/ReaderWriter/ELF/AMDGPU/AMDGPURelocationHandler.cpp b/lib/ReaderWriter/ELF/AMDGPU/AMDGPURelocationHandler.cpp
new file mode 100644
index 000000000000..ca5a77db9177
--- /dev/null
+++ b/lib/ReaderWriter/ELF/AMDGPU/AMDGPURelocationHandler.cpp
@@ -0,0 +1,19 @@
+//===- lib/ReaderWriter/ELF/AMDGPU/AMDGPURelocationHandler.cpp -----------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AMDGPURelocationHandler.h"
+
+using namespace lld;
+using namespace lld::elf;
+
+std::error_code AMDGPUTargetRelocationHandler::applyRelocation(
+ ELFWriter &writer, llvm::FileOutputBuffer &buf, const AtomLayout &atom,
+ const Reference &ref) const {
+ return std::error_code();
+}
diff --git a/lib/ReaderWriter/ELF/AMDGPU/AMDGPURelocationHandler.h b/lib/ReaderWriter/ELF/AMDGPU/AMDGPURelocationHandler.h
new file mode 100644
index 000000000000..90d37274aebf
--- /dev/null
+++ b/lib/ReaderWriter/ELF/AMDGPU/AMDGPURelocationHandler.h
@@ -0,0 +1,31 @@
+//===- lld/ReaderWriter/ELF/AMDGPU/AMDGPURelocationHandler.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_AMDGPU_AMDGPU_RELOCATION_HANDLER_H
+#define LLD_READER_WRITER_ELF_AMDGPU_AMDGPU_RELOCATION_HANDLER_H
+
+#include "lld/ReaderWriter/ELFLinkingContext.h"
+#include <system_error>
+
+namespace lld {
+namespace elf {
+class AMDGPUTargetHandler;
+class AMDGPUTargetLayout;
+
+class AMDGPUTargetRelocationHandler final : public TargetRelocationHandler {
+public:
+ AMDGPUTargetRelocationHandler(AMDGPUTargetLayout &layout) { }
+
+ std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &,
+ const AtomLayout &,
+ const Reference &) const override;
+
+};
+} // elf
+} // lld
+#endif
diff --git a/lib/ReaderWriter/ELF/AMDGPU/AMDGPUSymbolTable.cpp b/lib/ReaderWriter/ELF/AMDGPU/AMDGPUSymbolTable.cpp
new file mode 100644
index 000000000000..0824974d4602
--- /dev/null
+++ b/lib/ReaderWriter/ELF/AMDGPU/AMDGPUSymbolTable.cpp
@@ -0,0 +1,32 @@
+//===--------- lib/ReaderWriter/ELF/AMDGPU/AMDGPUSymbolTable.cpp ----------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AMDGPUSymbolTable.h"
+#include "ELFFile.h"
+#include "Atoms.h"
+#include "SectionChunks.h"
+
+using namespace lld;
+using namespace lld::elf;
+
+AMDGPUSymbolTable::AMDGPUSymbolTable(const ELFLinkingContext &ctx)
+ : SymbolTable(ctx, ".symtab", TargetLayout<ELF64LE>::ORDER_SYMBOL_TABLE) {}
+
+void AMDGPUSymbolTable::addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da,
+ int64_t addr) {
+ SymbolTable::addDefinedAtom(sym, da, addr);
+
+ // FIXME: Only do this for kernel functions.
+ sym.setType(STT_AMDGPU_HSA_KERNEL);
+
+ // Make st_value section relative.
+ // FIXME: This is hack to give kernel symbols a section relative offset.
+ // Because of this hack only on kernel can be included in a binary file.
+ sym.st_value = 0;
+}
diff --git a/lib/ReaderWriter/ELF/AMDGPU/AMDGPUSymbolTable.h b/lib/ReaderWriter/ELF/AMDGPU/AMDGPUSymbolTable.h
new file mode 100644
index 000000000000..41c3be5cb38f
--- /dev/null
+++ b/lib/ReaderWriter/ELF/AMDGPU/AMDGPUSymbolTable.h
@@ -0,0 +1,32 @@
+//===--------- lib/ReaderWriter/ELF/AMDGPU/AMDGPUSymbolTable.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_AMDGPU_AMDGPU_SYMBOL_TABLE_H
+#define LLD_READER_WRITER_ELF_AMDGPU_AMDGPU_SYMBOL_TABLE_H
+
+#include "TargetLayout.h"
+
+namespace lld {
+namespace elf {
+
+/// \brief The SymbolTable class represents the symbol table in a ELF file
+class AMDGPUSymbolTable : public SymbolTable<ELF64LE> {
+public:
+ typedef llvm::object::Elf_Sym_Impl<ELF64LE> Elf_Sym;
+
+ AMDGPUSymbolTable(const ELFLinkingContext &ctx);
+
+ void addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da,
+ int64_t addr) override;
+};
+
+} // elf
+} // lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/AMDGPU/AMDGPUTargetHandler.cpp b/lib/ReaderWriter/ELF/AMDGPU/AMDGPUTargetHandler.cpp
new file mode 100644
index 000000000000..ff4b600158bd
--- /dev/null
+++ b/lib/ReaderWriter/ELF/AMDGPU/AMDGPUTargetHandler.cpp
@@ -0,0 +1,65 @@
+//===- lib/ReaderWriter/ELF/AMDGPU/AMDGPUTargetHandler.cpp -------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TargetLayout.h"
+#include "AMDGPUExecutableWriter.h"
+#include "AMDGPULinkingContext.h"
+#include "AMDGPUTargetHandler.h"
+#include "llvm/Support/ELF.h"
+
+namespace lld {
+namespace elf {
+
+AMDGPUTargetHandler::AMDGPUTargetHandler(AMDGPULinkingContext &ctx)
+ : _ctx(ctx), _targetLayout(new AMDGPUTargetLayout(ctx)),
+ _relocationHandler(new AMDGPUTargetRelocationHandler(*_targetLayout)) {}
+
+std::unique_ptr<Writer> AMDGPUTargetHandler::getWriter() {
+ switch (_ctx.getOutputELFType()) {
+ case llvm::ELF::ET_EXEC:
+ return llvm::make_unique<AMDGPUExecutableWriter>(_ctx, *_targetLayout);
+ case llvm::ELF::ET_DYN:
+ llvm_unreachable("TODO: support dynamic libraries");
+ case llvm::ELF::ET_REL:
+ llvm_unreachable("TODO: support -r mode");
+ default:
+ llvm_unreachable("unsupported output type");
+ }
+}
+
+HSATextSection::HSATextSection(const ELFLinkingContext &ctx)
+ : AtomSection(ctx, ".hsatext", DefinedAtom::typeCode, 0, 0) {
+ _type = SHT_PROGBITS;
+ _flags = SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR | SHF_AMDGPU_HSA_AGENT |
+ SHF_AMDGPU_HSA_CODE;
+
+ // FIXME: What alignment should we use here?
+ _alignment = 4096;
+}
+
+void AMDGPUTargetLayout::assignSectionsToSegments() {
+
+ TargetLayout::assignSectionsToSegments();
+ for (OutputSection<ELF64LE> *osi : _outputSections) {
+ for (Section<ELF64LE> *section : osi->sections()) {
+ StringRef InputSectionName = section->inputSectionName();
+ if (InputSectionName != ".hsatext")
+ continue;
+
+ auto *segment = new (_allocator) Segment<ELF64LE>(
+ _ctx, "PT_AMDGPU_HSA_LOAD_CODE_AGENT", PT_AMDGPU_HSA_LOAD_CODE_AGENT);
+ _segments.push_back(segment);
+ assert(segment);
+ segment->append(section);
+ }
+ }
+}
+
+} // namespace elf
+} // namespace lld
diff --git a/lib/ReaderWriter/ELF/AMDGPU/AMDGPUTargetHandler.h b/lib/ReaderWriter/ELF/AMDGPU/AMDGPUTargetHandler.h
new file mode 100644
index 000000000000..8d0f70b6e7f7
--- /dev/null
+++ b/lib/ReaderWriter/ELF/AMDGPU/AMDGPUTargetHandler.h
@@ -0,0 +1,80 @@
+//===- lib/ReaderWriter/ELF/AMDGPU/AMDGPUTargetHandler.h ------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef AMDGPU_TARGET_HANDLER_H
+#define AMDGPU_TARGET_HANDLER_H
+
+#include "ELFFile.h"
+#include "ELFReader.h"
+#include "AMDGPURelocationHandler.h"
+#include "TargetLayout.h"
+
+namespace lld {
+namespace elf {
+class AMDGPULinkingContext;
+
+class HSATextSection : public AtomSection<ELF64LE> {
+public:
+ HSATextSection(const ELFLinkingContext &ctx);
+};
+
+/// \brief TargetLayout for AMDGPU
+class AMDGPUTargetLayout final : public TargetLayout<ELF64LE> {
+public:
+ AMDGPUTargetLayout(AMDGPULinkingContext &ctx) : TargetLayout(ctx) {}
+
+ void assignSectionsToSegments() override;
+
+ /// \brief Gets or creates a section.
+ AtomSection<ELF64LE> *
+ createSection(StringRef name, int32_t contentType,
+ DefinedAtom::ContentPermissions contentPermissions,
+ TargetLayout::SectionOrder sectionOrder) override {
+ if (name == ".hsatext")
+ return new (_allocator) HSATextSection(_ctx);
+
+ if (name == ".note")
+ contentType = DefinedAtom::typeRONote;
+
+ return TargetLayout::createSection(name, contentType, contentPermissions,
+ sectionOrder);
+ }
+};
+
+/// \brief TargetHandler for AMDGPU
+class AMDGPUTargetHandler final : public TargetHandler {
+public:
+ AMDGPUTargetHandler(AMDGPULinkingContext &targetInfo);
+
+ 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:
+ AMDGPULinkingContext &_ctx;
+ std::unique_ptr<AMDGPUTargetLayout> _targetLayout;
+ std::unique_ptr<AMDGPUTargetRelocationHandler> _relocationHandler;
+};
+
+void finalizeAMDGPURuntimeAtomValues(AMDGPUTargetLayout &layout);
+
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/AMDGPU/CMakeLists.txt b/lib/ReaderWriter/ELF/AMDGPU/CMakeLists.txt
new file mode 100644
index 000000000000..9c9cc10fe397
--- /dev/null
+++ b/lib/ReaderWriter/ELF/AMDGPU/CMakeLists.txt
@@ -0,0 +1,13 @@
+add_llvm_library(lldAMDGPUELFTarget
+ AMDGPUExecutableWriter.cpp
+ AMDGPULinkingContext.cpp
+ AMDGPURelocationHandler.cpp
+ AMDGPUSymbolTable.cpp
+ AMDGPUTargetHandler.cpp
+ LINK_LIBS
+ lldELF
+ lldReaderWriter
+ lldCore
+ LLVMObject
+ LLVMSupport
+ )
diff --git a/lib/ReaderWriter/ELF/ARM/ARMDynamicLibraryWriter.h b/lib/ReaderWriter/ELF/ARM/ARMDynamicLibraryWriter.h
new file mode 100644
index 000000000000..da843b97abc0
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ARM/ARMDynamicLibraryWriter.h
@@ -0,0 +1,49 @@
+//===- 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
index bc5ee35b8213..8f5477017e55 100644
--- a/lib/ReaderWriter/ELF/ARM/ARMELFFile.h
+++ b/lib/ReaderWriter/ELF/ARM/ARMELFFile.h
@@ -17,53 +17,95 @@ namespace elf {
class ARMLinkingContext;
-template <class ELFT> class ARMELFDefinedAtom : public ELFDefinedAtom<ELFT> {
- typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
- typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr;
+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:
- ARMELFDefinedAtom(const ELFFile<ELFT> &file, StringRef symbolName,
- StringRef sectionName, const Elf_Sym *symbol,
- const Elf_Shdr *section, ArrayRef<uint8_t> contentData,
- unsigned int referenceStart, unsigned int referenceEnd,
- std::vector<ELFReference<ELFT> *> &referenceList)
- : ELFDefinedAtom<ELFT>(file, symbolName, sectionName, symbol, section,
- contentData, referenceStart, referenceEnd,
- referenceList) {}
-
- bool isThumbFunc(const Elf_Sym *symbol) const {
+ 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);
+ (static_cast<uint64_t>(symbol->st_value) & 0x1);
}
/// Correct st_value for symbols addressing Thumb instructions
/// by removing its zero bit.
- uint64_t getSymbolValue(const Elf_Sym *symbol) const override {
- const auto value = static_cast<uint64_t>(symbol->st_value);
- return isThumbFunc(symbol) ? value & ~0x1 : value;
+ 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 {
- if (isThumbFunc(this->_symbol))
- return DefinedAtom::codeARMThumb;
- return DefinedAtom::codeNA;
+ return isThumbFunc() ? DefinedAtom::codeARMThumb : DefinedAtom::codeNA;
}
};
-template <class ELFT> class ARMELFFile : public ELFFile<ELFT> {
-public:
- ARMELFFile(std::unique_ptr<MemoryBuffer> mb, ARMLinkingContext &ctx)
- : ELFFile<ELFT>(std::move(mb), ctx) {}
+class ARMELFFile : public ELFFile<ELF32LE> {
+ typedef llvm::object::Elf_Rel_Impl<ELF32LE, false> Elf_Rel;
- static ErrorOr<std::unique_ptr<ARMELFFile>>
- create(std::unique_ptr<MemoryBuffer> mb, ARMLinkingContext &ctx) {
- return std::unique_ptr<ARMELFFile<ELFT>>(
- new ARMELFFile<ELFT>(std::move(mb), ctx));
+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<ELFT> Elf_Sym;
- typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr;
+ 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.
@@ -73,24 +115,39 @@ private:
}
/// Process the Defined symbol and create an atom for it.
- ErrorOr<ELFDefinedAtom<ELFT> *> handleDefinedSymbol(StringRef symName,
- StringRef sectionName,
- const Elf_Sym *sym, const Elf_Shdr *sectionHdr,
- ArrayRef<uint8_t> contentData,
- unsigned int referenceStart, unsigned int referenceEnd,
- std::vector<ELFReference<ELFT> *> &referenceList) override {
- return new (this->_readerStorage) ARMELFDefinedAtom<ELFT>(
+ 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);
}
};
-template <class ELFT> class ARMDynamicFile : public DynamicFile<ELFT> {
-public:
- ARMDynamicFile(const ARMLinkingContext &context, StringRef name)
- : DynamicFile<ELFT>(context, name) {}
-};
-
} // elf
} // lld
diff --git a/lib/ReaderWriter/ELF/ARM/ARMELFReader.h b/lib/ReaderWriter/ELF/ARM/ARMELFReader.h
deleted file mode 100644
index 31af531563ea..000000000000
--- a/lib/ReaderWriter/ELF/ARM/ARMELFReader.h
+++ /dev/null
@@ -1,62 +0,0 @@
-//===--------- lib/ReaderWriter/ELF/ARM/ARMELFReader.h --------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_ARM_ARM_ELF_READER_H
-#define LLD_READER_WRITER_ARM_ARM_ELF_READER_H
-
-#include "ARMELFFile.h"
-#include "ELFReader.h"
-
-namespace lld {
-namespace elf {
-
-typedef llvm::object::ELFType<llvm::support::little, 2, false> ARMELFType;
-
-struct ARMDynamicFileCreateELFTraits {
- typedef llvm::ErrorOr<std::unique_ptr<lld::SharedLibraryFile>> result_type;
-
- template <class ELFT>
- static result_type create(std::unique_ptr<llvm::MemoryBuffer> mb,
- ARMLinkingContext &ctx) {
- return lld::elf::ARMDynamicFile<ELFT>::create(std::move(mb), ctx);
- }
-};
-
-struct ARMELFFileCreateELFTraits {
- typedef llvm::ErrorOr<std::unique_ptr<lld::File>> result_type;
-
- template <class ELFT>
- static result_type create(std::unique_ptr<llvm::MemoryBuffer> mb,
- ARMLinkingContext &ctx) {
- return lld::elf::ARMELFFile<ELFT>::create(std::move(mb), ctx);
- }
-};
-
-class ARMELFObjectReader
- : public ELFObjectReader<ARMELFType, ARMELFFileCreateELFTraits,
- ARMLinkingContext> {
-public:
- ARMELFObjectReader(ARMLinkingContext &ctx)
- : ELFObjectReader<ARMELFType, ARMELFFileCreateELFTraits,
- ARMLinkingContext>(ctx, llvm::ELF::EM_ARM) {}
-};
-
-class ARMELFDSOReader
- : public ELFDSOReader<ARMELFType, ARMDynamicFileCreateELFTraits,
- ARMLinkingContext> {
-public:
- ARMELFDSOReader(ARMLinkingContext &ctx)
- : ELFDSOReader<ARMELFType, ARMDynamicFileCreateELFTraits,
- ARMLinkingContext>(ctx, llvm::ELF::EM_ARM) {}
-};
-
-} // namespace elf
-} // namespace lld
-
-#endif // LLD_READER_WRITER_ARM_ARM_ELF_READER_H
diff --git a/lib/ReaderWriter/ELF/ARM/ARMELFWriters.h b/lib/ReaderWriter/ELF/ARM/ARMELFWriters.h
new file mode 100644
index 000000000000..a842ebe53038
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ARM/ARMELFWriters.h
@@ -0,0 +1,120 @@
+//===- 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
index 19311d516e4d..974dab63a126 100644
--- a/lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h
+++ b/lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h
@@ -10,111 +10,58 @@
#define LLD_READER_WRITER_ELF_ARM_ARM_EXECUTABLE_WRITER_H
#include "ExecutableWriter.h"
+#include "ARMELFWriters.h"
#include "ARMLinkingContext.h"
#include "ARMTargetHandler.h"
-#include "ARMSymbolTable.h"
-
-namespace {
-const char *gotSymbol = "_GLOBAL_OFFSET_TABLE_";
-}
namespace lld {
namespace elf {
-template <class ELFT>
-class ARMExecutableWriter : public ExecutableWriter<ELFT> {
+class ARMExecutableWriter : public ARMELFWriter<ExecutableWriter<ELF32LE>> {
public:
- ARMExecutableWriter(ARMLinkingContext &context,
- ARMTargetLayout<ELFT> &layout);
+ ARMExecutableWriter(ARMLinkingContext &ctx, ARMTargetLayout &layout);
protected:
// Add any runtime files and their atoms to the output
- bool createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
-
- void finalizeDefaultAtomValues() override;
-
- void addDefaultAtoms() override {
- ExecutableWriter<ELFT>::addDefaultAtoms();
- }
-
- /// \brief Create symbol table.
- unique_bump_ptr<SymbolTable<ELFT>> createSymbolTable() override;
+ void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
void processUndefinedSymbol(StringRef symName,
- RuntimeFile<ELFT> &file) const override;
-
- // Setup the ELF header.
- std::error_code setELFHeader() override;
+ RuntimeFile<ELF32LE> &file) const override;
private:
- ARMLinkingContext &_context;
- ARMTargetLayout<ELFT> &_armLayout;
+ ARMLinkingContext &_ctx;
};
-template <class ELFT>
-ARMExecutableWriter<ELFT>::ARMExecutableWriter(ARMLinkingContext &context,
- ARMTargetLayout<ELFT> &layout)
- : ExecutableWriter<ELFT>(context, layout), _context(context),
- _armLayout(layout) {}
+ARMExecutableWriter::ARMExecutableWriter(ARMLinkingContext &ctx,
+ ARMTargetLayout &layout)
+ : ARMELFWriter(ctx, layout), _ctx(ctx) {}
-template <class ELFT>
-bool ARMExecutableWriter<ELFT>::createImplicitFiles(
+void ARMExecutableWriter::createImplicitFiles(
std::vector<std::unique_ptr<File>> &result) {
- ExecutableWriter<ELFT>::createImplicitFiles(result);
- return true;
-}
-
-template <class ELFT>
-void ARMExecutableWriter<ELFT>::finalizeDefaultAtomValues() {
- // Finalize the atom values that are part of the parent.
- ExecutableWriter<ELFT>::finalizeDefaultAtomValues();
- auto gotAtomIter = _armLayout.findAbsoluteAtom(gotSymbol);
- if (gotAtomIter != _armLayout.absoluteAtoms().end()) {
- auto *gotAtom = *gotAtomIter;
- if (auto gotpltSection = _armLayout.findOutputSection(".got.plt"))
- gotAtom->_virtualAddr = gotpltSection->virtualAddr();
- else if (auto gotSection = _armLayout.findOutputSection(".got"))
- gotAtom->_virtualAddr = gotSection->virtualAddr();
- else
- gotAtom->_virtualAddr = 0;
+ 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));
}
- // TODO: resolve addresses of __exidx_start/_end atoms
-}
-
-template <class ELFT>
-unique_bump_ptr<SymbolTable<ELFT>>
- ARMExecutableWriter<ELFT>::createSymbolTable() {
- return unique_bump_ptr<SymbolTable<ELFT>>(
- new (this->_alloc) ARMSymbolTable<ELFT>(this->_context));
}
-template <class ELFT>
-void ARMExecutableWriter<ELFT>::processUndefinedSymbol(
- StringRef symName, RuntimeFile<ELFT> &file) const {
+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");
}
}
-template <class ELFT>
-std::error_code ARMExecutableWriter<ELFT>::setELFHeader() {
- if (std::error_code ec = ExecutableWriter<ELFT>::setELFHeader())
- return ec;
-
- // Fixup entry point for Thumb code.
- StringRef entryName = _context.entrySymbolName();
- if (const AtomLayout *al = _armLayout.findAtomLayoutByName(entryName)) {
- const auto *ea = dyn_cast<DefinedAtom>(al->_atom);
- if (ea && ea->codeModel() == DefinedAtom::codeARMThumb)
- this->_elfHeader->e_entry(al->_virtualAddr | 0x1);
- }
-
- return std::error_code();
-}
-
} // namespace elf
} // namespace lld
diff --git a/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp b/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp
index 5f2436674268..74905b47820f 100644
--- a/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp
+++ b/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp
@@ -11,24 +11,54 @@
#include "ARMRelocationPass.h"
#include "ARMTargetHandler.h"
-using namespace lld;
-using namespace lld::elf;
+namespace lld {
+namespace elf {
std::unique_ptr<ELFLinkingContext>
-elf::ARMLinkingContext::create(llvm::Triple triple) {
+createARMLinkingContext(llvm::Triple triple) {
if (triple.getArch() == llvm::Triple::arm)
- return std::unique_ptr<ELFLinkingContext>(
- new elf::ARMLinkingContext(triple));
+ return llvm::make_unique<ARMLinkingContext>(triple);
return nullptr;
}
-elf::ARMLinkingContext::ARMLinkingContext(llvm::Triple triple)
- : ELFLinkingContext(triple, std::unique_ptr<TargetHandlerBase>(
- new ARMTargetHandler(*this))) {}
+ARMLinkingContext::ARMLinkingContext(llvm::Triple triple)
+ : ELFLinkingContext(triple, llvm::make_unique<ARMTargetHandler>(*this)) {}
-void elf::ARMLinkingContext::addPasses(PassManager &pm) {
+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
index 249b79c4f07d..f687713b25b8 100644
--- a/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h
+++ b/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h
@@ -19,17 +19,61 @@ namespace elf {
class ARMLinkingContext final : public ELFLinkingContext {
public:
- static std::unique_ptr<ELFLinkingContext> create(llvm::Triple);
+ 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
diff --git a/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp b/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp
index d24fdf0fa410..97b149133ff2 100644
--- a/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp
+++ b/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp
@@ -14,6 +14,8 @@
#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;
@@ -74,7 +76,7 @@ static Reference::Addend readAddend_THM_JUMP11(const uint8_t *location) {
const auto value = read16le(location);
const uint16_t imm11 = value & 0x7FF;
- return llvm::SignExtend32<12>(imm11 << 1);
+ return llvm::SignExtend64<12>(imm11 << 1);
}
static Reference::Addend readAddend(const uint8_t *location,
@@ -82,11 +84,15 @@ static Reference::Addend readAddend(const uint8_t *location,
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 (int32_t)(read32le(location) & 0x7FFFFFFF);
+ return llvm::SignExtend64<31>(read32le(location) & 0x7FFFFFFF);
case R_ARM_THM_CALL:
case R_ARM_THM_JUMP24:
return readAddend_THM_CALL(location);
@@ -106,81 +112,98 @@ static Reference::Addend readAddend(const uint8_t *location,
}
}
-static inline void applyArmReloc(uint8_t *location, uint32_t result,
- uint32_t mask = 0xFFFFFFFF) {
+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 void applyThmReloc(uint8_t *location, uint16_t resHi,
- uint16_t resLo, uint16_t maskHi,
- uint16_t maskLo = 0xFFFF) {
+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 void applyThumb16Reloc(uint8_t *location, uint16_t result,
- uint16_t mask = 0xFFFF) {
+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 void relocR_ARM_ABS32(uint8_t *location, uint64_t P, uint64_t S,
- int64_t A, bool addressesThumb) {
+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_WITH_TYPE(
- "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
- llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
- llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
- llvm::dbgs() << " T: 0x" << Twine::utohexstr(T);
- llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
- applyArmReloc(location, result);
+ 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 void relocR_ARM_REL32(uint8_t *location, uint64_t P, uint64_t S,
- int64_t A, bool addressesThumb) {
+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_WITH_TYPE(
- "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
- llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
- llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
- llvm::dbgs() << " T: 0x" << Twine::utohexstr(T);
- llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
- applyArmReloc(location, result);
+ 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 void relocR_ARM_PREL31(uint8_t *location, uint64_t P, uint64_t S,
- int64_t A, bool addressesThumb) {
+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_WITH_TYPE(
- "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
- llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
- llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
- llvm::dbgs() << " T: 0x" << Twine::utohexstr(T);
- llvm::dbgs() << " result: 0x" << Twine::utohexstr(result);
- llvm::dbgs() << " rel31: 0x" << Twine::utohexstr(rel31) << "\n");
+ 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");
- applyArmReloc(location, rel31, mask);
+ return applyArmReloc(location, rel31, mask);
}
/// \brief Relocate B/BL instructions. useJs defines whether J1 & J2 are used
-static void relocR_ARM_THM_B_L(uint8_t *location, uint32_t result, bool useJs) {
+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;
@@ -194,12 +217,13 @@ static void relocR_ARM_THM_B_L(uint8_t *location, uint32_t result, bool useJs) {
const uint16_t bitI1 = (~(bitJ1 ^ bitS)) & 0x1;
const uint16_t resLo = (bitI1 << 13) | (bitI2 << 11) | imm11;
- applyThmReloc(location, resHi, resLo, 0x7FF, 0x2FFF);
+ return applyThumb32Reloc(location, resHi, resLo, 0x7FF, 0x2FFF);
}
/// \brief R_ARM_THM_CALL - ((S + A) | T) - P
-static void relocR_ARM_THM_CALL(uint8_t *location, uint64_t P, uint64_t S,
- int64_t A, bool useJs, bool addressesThumb) {
+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;
@@ -209,137 +233,171 @@ static void relocR_ARM_THM_CALL(uint8_t *location, uint64_t P, uint64_t S,
uint32_t result = (uint32_t)(((S + A) | T) - P);
- DEBUG_WITH_TYPE(
- "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
- llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
- llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
- llvm::dbgs() << " T: 0x" << Twine::utohexstr(T);
- llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
- relocR_ARM_THM_B_L(location, result, useJs);
+ 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) {
- applyThmReloc(location, 0, 0, 0, 0x1001);
+ return applyThumb32Reloc(location, 0, 0, 0, 0x1001);
}
+ return std::error_code();
}
/// \brief R_ARM_THM_JUMP24 - ((S + A) | T) - P
-static void relocR_ARM_THM_JUMP24(uint8_t *location, uint64_t P, uint64_t S,
- int64_t A, bool addressesThumb) {
+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_WITH_TYPE(
- "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
- llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
- llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
- llvm::dbgs() << " T: 0x" << Twine::utohexstr(T);
- llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
- relocR_ARM_THM_B_L(location, result, true);
+ 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 void relocR_ARM_THM_JUMP11(uint8_t *location, uint64_t P, uint64_t S,
- int64_t A) {
+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_WITH_TYPE(
- "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
- llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
- llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
- llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
+ 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");
- //we cut off first bit because it is always 1 according to p. 4.5.3
+ 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);
+}
- applyThumb16Reloc(location, result, 0x7FF);
+/// \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 void relocR_ARM_CALL(uint8_t *location, uint64_t P, uint64_t S,
- int64_t A, bool addressesThumb) {
+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_WITH_TYPE(
- "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
- llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
- llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
- llvm::dbgs() << " T: 0x" << Twine::utohexstr(T);
- llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
- applyArmReloc(location, imm24, 0xFFFFFF);
+ 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;
- applyArmReloc(location, (0xFA | bitH) << 24, 0xFF000000);
+ return applyArmReloc(location, (0xFA | bitH) << 24, 0xFF000000);
}
+ return std::error_code();
}
/// \brief R_ARM_JUMP24 - ((S + A) | T) - P
-static void relocR_ARM_JUMP24(uint8_t *location, uint64_t P, uint64_t S,
- int64_t A, bool addressesThumb) {
+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_WITH_TYPE(
- "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
- llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
- llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
- llvm::dbgs() << " T: 0x" << Twine::utohexstr(T);
- llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
- applyArmReloc(location, imm24, 0xFFFFFF);
+ 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 void relocR_ARM_MOV(uint8_t *location, uint32_t result) {
+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;
- applyArmReloc(location, (imm4 << 16) | imm12, 0xF0FFF);
+ return applyArmReloc(location, (imm4 << 16) | imm12, 0xF0FFF);
}
/// \brief R_ARM_MOVW_ABS_NC - (S + A) | T
-static void relocR_ARM_MOVW_ABS_NC(uint8_t *location, uint64_t P, uint64_t S,
- int64_t A, bool addressesThumb) {
+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_WITH_TYPE(
- "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
- llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
- llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
- llvm::dbgs() << " T: 0x" << Twine::utohexstr(T);
- llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
+ 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 void relocR_ARM_MOVT_ABS(uint8_t *location, uint64_t P, uint64_t S,
- int64_t 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_WITH_TYPE(
- "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
- llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
- llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
- llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
+ 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 void relocR_ARM_THM_MOV(uint8_t *location, uint32_t result) {
+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;
@@ -348,153 +406,275 @@ static void relocR_ARM_THM_MOV(uint8_t *location, uint32_t result) {
const uint16_t bitI = (result >> 11) & 0x1;
const uint16_t resHi = (bitI << 10) | imm4;
- applyThmReloc(location, resHi, resLo, 0x40F, 0x70FF);
+ return applyThumb32Reloc(location, resHi, resLo, 0x40F, 0x70FF);
}
/// \brief R_ARM_THM_MOVW_ABS_NC - (S + A) | T
-static void relocR_ARM_THM_MOVW_ABS_NC(uint8_t *location, uint64_t P,
- uint64_t S, int64_t A,
- bool addressesThumb) {
+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_WITH_TYPE(
- "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
- llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
- llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
- llvm::dbgs() << " T: 0x" << Twine::utohexstr(T);
- llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
+ 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 void relocR_ARM_THM_MOVT_ABS(uint8_t *location, uint64_t P, uint64_t S,
- int64_t 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_WITH_TYPE(
- "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
- llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
- llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
- llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
+ 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 void relocR_ARM_TLS_IE32(uint8_t *location, uint64_t P, uint64_t S,
- int64_t A) {
+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_WITH_TYPE(
- "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
- llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
- llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
- llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
- applyArmReloc(location, result);
+ 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 void relocR_ARM_TLS_LE32(uint8_t *location, uint64_t P, uint64_t S,
- int64_t A, uint64_t 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_WITH_TYPE(
- "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
- llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
- llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
- llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
- llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
- applyArmReloc(location, result);
+ 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 lld::AtomLayout &atom,
+ ELFWriter &writer, llvm::FileOutputBuffer &buf, const AtomLayout &atom,
const Reference &ref) const {
uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset;
- uint8_t *location = atomContent + ref.offsetInAtom();
- uint64_t targetVAddress = writer.addressOfAtom(ref.target());
- uint64_t relocVAddress = atom._virtualAddr + ref.offsetInAtom();
+ 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(location, ref.kindValue());
+ readAddend(loc, ref.kindValue()) + ref.addend();
// Flags that the relocation addresses Thumb instruction
- bool addressesThumb = false;
-
+ bool thumb = false;
if (const auto *definedAtom = dyn_cast<DefinedAtom>(ref.target())) {
- addressesThumb = (DefinedAtom::codeARMThumb == definedAtom->codeModel());
+ thumb = isThumbCode(definedAtom);
}
switch (ref.kindValue()) {
case R_ARM_NONE:
- break;
+ return std::error_code();
case R_ARM_ABS32:
- relocR_ARM_ABS32(location, relocVAddress, targetVAddress, addend,
- addressesThumb);
- break;
+ return relocR_ARM_ABS32(loc, reloc, target, addend, thumb);
case R_ARM_REL32:
- relocR_ARM_REL32(location, relocVAddress, targetVAddress, addend,
- addressesThumb);
- break;
+ 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
- relocR_ARM_THM_CALL(location, relocVAddress, targetVAddress, addend, true,
- addressesThumb);
- break;
+ return relocR_ARM_THM_CALL(loc, reloc, target, addend, true, thumb);
case R_ARM_CALL:
- relocR_ARM_CALL(location, relocVAddress, targetVAddress, addend,
- addressesThumb);
- break;
+ return relocR_ARM_CALL(loc, reloc, target, addend, thumb);
case R_ARM_JUMP24:
- relocR_ARM_JUMP24(location, relocVAddress, targetVAddress, addend,
- addressesThumb);
- break;
+ return relocR_ARM_JUMP24(loc, reloc, target, addend, thumb);
case R_ARM_THM_JUMP24:
- relocR_ARM_THM_JUMP24(location, relocVAddress, targetVAddress, addend,
- addressesThumb);
- break;
+ return relocR_ARM_THM_JUMP24(loc, reloc, target, addend, thumb);
case R_ARM_THM_JUMP11:
- relocR_ARM_THM_JUMP11(location, relocVAddress, targetVAddress, addend);
- break;
+ return relocR_ARM_THM_JUMP11(loc, reloc, target, addend);
case R_ARM_MOVW_ABS_NC:
- relocR_ARM_MOVW_ABS_NC(location, relocVAddress, targetVAddress, addend,
- addressesThumb);
- break;
+ return relocR_ARM_MOVW_ABS_NC(loc, reloc, target, addend, thumb);
case R_ARM_MOVT_ABS:
- relocR_ARM_MOVT_ABS(location, relocVAddress, targetVAddress, addend);
- break;
+ return relocR_ARM_MOVT_ABS(loc, reloc, target, addend);
case R_ARM_THM_MOVW_ABS_NC:
- relocR_ARM_THM_MOVW_ABS_NC(location, relocVAddress, targetVAddress, addend,
- addressesThumb);
- break;
+ return relocR_ARM_THM_MOVW_ABS_NC(loc, reloc, target, addend, thumb);
case R_ARM_THM_MOVT_ABS:
- relocR_ARM_THM_MOVT_ABS(location, relocVAddress, targetVAddress, addend);
- break;
+ return relocR_ARM_THM_MOVT_ABS(loc, reloc, target, addend);
case R_ARM_PREL31:
- relocR_ARM_PREL31(location, relocVAddress, targetVAddress, addend,
- addressesThumb);
- break;
+ return relocR_ARM_PREL31(loc, reloc, target, addend, thumb);
case R_ARM_TLS_IE32:
- relocR_ARM_TLS_IE32(location, relocVAddress, targetVAddress, addend);
- break;
+ return relocR_ARM_TLS_IE32(loc, reloc, target, addend);
case R_ARM_TLS_LE32:
- relocR_ARM_TLS_LE32(location, relocVAddress, targetVAddress, addend,
- _armLayout.getTPOffset());
- break;
+ 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();
}
- return std::error_code();
+ llvm_unreachable("All switch cases must return directly");
}
diff --git a/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h b/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h
index 227d68617bf9..a1f3d091f204 100644
--- a/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h
+++ b/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h
@@ -10,26 +10,23 @@
#ifndef LLD_READER_WRITER_ELF_ARM_ARM_RELOCATION_HANDLER_H
#define LLD_READER_WRITER_ELF_ARM_ARM_RELOCATION_HANDLER_H
-#include "ARMTargetHandler.h"
+#include "lld/ReaderWriter/ELFLinkingContext.h"
namespace lld {
namespace elf {
-typedef llvm::object::ELFType<llvm::support::little, 2, false> ARMELFType;
-template <class ELFT> class ARMTargetLayout;
+class ARMTargetLayout;
-class ARMTargetRelocationHandler final
- : public TargetRelocationHandler {
+class ARMTargetRelocationHandler final : public TargetRelocationHandler {
public:
- ARMTargetRelocationHandler(ARMTargetLayout<ARMELFType> &layout)
- : _armLayout(layout) {}
+ ARMTargetRelocationHandler(ARMTargetLayout &layout) : _armLayout(layout) {}
std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &,
- const lld::AtomLayout &,
+ const AtomLayout &,
const Reference &) const override;
private:
- ARMTargetLayout<ARMELFType> &_armLayout;
+ ARMTargetLayout &_armLayout;
};
} // end namespace elf
diff --git a/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp b/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp
index 27ec66ac5557..fc2ae75cd7a7 100644
--- a/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp
+++ b/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp
@@ -20,7 +20,7 @@
#include "ARMLinkingContext.h"
#include "Atoms.h"
#include "lld/Core/Simple.h"
-#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Debug.h"
@@ -28,34 +28,77 @@ using namespace lld;
using namespace lld::elf;
using namespace llvm::ELF;
-// ARM B/BL instructions of static relocation veneer.
+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_StaticAtomContent[8] = {
- 0x04, 0xf0, 0x1f, 0xe5, // ldr pc, [pc, #-4]
+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 static relocation veneer.
+// 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_StaticAtomContent[8] = {
+static const uint8_t Veneer_THM_B_BL_Abs_t_AtomContent[4] = {
0x78, 0x47, // bx pc
- 0x00, 0x00, // nop
+ 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};
-namespace {
+// .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)
- : SimpleELFDefinedAtom(f), _section(secName) {}
+ VeneerAtom(const File &f, StringRef secName, const std::string &name = "")
+ : SimpleELFDefinedAtom(f), _section(secName), _name(name) {}
Scope scope() const override { return DefinedAtom::scopeTranslationUnit; }
@@ -65,58 +108,208 @@ public:
StringRef customSectionName() const override { return _section; }
- ContentType contentType() const override {
- return DefinedAtom::typeCode;
- }
+ ContentType contentType() const override { return DefinedAtom::typeCode; }
uint64_t size() const override { return rawContent().size(); }
ContentPermissions permissions() const override { return permR_X; }
- Alignment alignment() const override { return Alignment(2); }
+ Alignment alignment() const override { return 4; }
StringRef name() const override { return _name; }
+
+private:
std::string _name;
};
-/// \brief Atoms that hold veneer for statically relocated
-/// ARM B/BL instructions.
-class Veneer_ARM_B_BL_StaticAtom : public VeneerAtom {
+/// \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_StaticAtom(const File &f, StringRef secName)
- : VeneerAtom(f, secName) {}
+ 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_StaticAtomContent);
+ return llvm::makeArrayRef(Veneer_ARM_B_BL_Abs_a_AtomContent);
}
};
-/// \brief Atoms that hold veneer for statically relocated
-/// Thumb B/BL instructions.
-class Veneer_THM_B_BL_StaticAtom : public VeneerAtom {
+class Veneer_ARM_B_BL_Abs_d_Atom : public VeneerAtom {
public:
- Veneer_THM_B_BL_StaticAtom(const File &f, StringRef secName)
+ 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_StaticAtomContent);
+ 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, StringRef secName) : GOTAtom(f, secName) {}
+ ARMGOTAtom(const File &f) : GOTAtom(f, ".got") {}
ArrayRef<uint8_t> rawContent() const override {
return llvm::makeArrayRef(ARMGotAtomContent);
}
- Alignment alignment() const override { return Alignment(2); }
+ 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 {
@@ -140,30 +333,92 @@ template <class Derived> class ARMRelocationPass : public Pass {
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:
- static_cast<Derived *>(this)->handleVeneer(atom, ref);
- break;
+ 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:
- std::error_code handleVeneer(const DefinedAtom &atom, const Reference &ref) {
+ /// \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 || target->codeModel() == atom.codeModel())
+ if (!target || isThumbCode(target) == isThumbCode(&atom))
return std::error_code();
- // TODO: For unconditional jump instructions (R_ARM_CALL and R_ARM_THM_CALL)
- // fixup isn't possible without veneer generation for archs below ARMv5.
-
// Veneers may only be generated for STT_FUNC target symbols
// or for symbols located in sections different to the place of relocation.
- const auto kindValue = ref.kindValue();
StringRef secName = atom.customSectionName();
if (DefinedAtom::typeCode != target->contentType() &&
!target->customSectionName().equals(secName)) {
@@ -182,29 +437,69 @@ protected:
llvm_unreachable(errStr.c_str());
}
- const Atom *veneer = nullptr;
- switch (kindValue) {
- case R_ARM_JUMP24:
- veneer = static_cast<Derived *>(this)
- ->getVeneer_ARM_B_BL(target, secName);
- break;
- case R_ARM_THM_JUMP24:
- veneer = static_cast<Derived *>(this)
- ->getVeneer_THM_B_BL(target, secName);
- break;
- default:
- llvm_unreachable("Unhandled reference type for veneer generation");
- }
+ assert(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));
+ 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");
@@ -213,20 +508,160 @@ protected:
/// \brief Create a GOT entry for TLS with reloc type and addend specified.
template <Reference::KindValue R_ARM_TLS, Reference::Addend A = 0>
const GOTAtom *getGOTTLSEntry(const DefinedAtom *da) {
- auto got = _gotMap.find(da);
- if (got != _gotMap.end())
- return got->second;
- auto g = new (_file._alloc) ARMGOTAtom(_file, ".got");
- g->addReferenceELF_ARM(R_ARM_TLS, 0, da, A);
+ StringRef source;
#ifndef NDEBUG
- g->_name = "__got_tls_";
+ 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
- _gotMap[da] = g;
- _gotVector.push_back(g);
+ _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) {}
@@ -238,35 +673,35 @@ public:
///
/// After all references are handled, the atoms created during that are all
/// added to mf.
- void perform(std::unique_ptr<MutableFile> &mf) override {
+ 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()) {
+ : mf.undefined()) {
llvm::dbgs() << " Name of Atom: " << atom->name().str() << "\n";
}
llvm::dbgs() << "Shared Library Atoms" << "\n";
for (const auto &atom
- : mf->sharedLibrary()) {
+ : mf.sharedLibrary()) {
llvm::dbgs() << " Name of Atom: " << atom->name().str() << "\n";
}
llvm::dbgs() << "Absolute Atoms" << "\n";
for (const auto &atom
- : mf->absolute()) {
+ : mf.absolute()) {
llvm::dbgs() << " Name of Atom: " << atom->name().str() << "\n";
}
llvm::dbgs() << "Defined Atoms" << "\n";
for (const auto &atom
- : mf->defined()) {
+ : mf.defined()) {
llvm::dbgs() << " Name of Atom: " << atom->name().str() << "\n";
});
// Process all references.
- for (const auto &atom : mf->defined()) {
+ for (const auto &atom : mf.defined()) {
for (const auto &ref : *atom) {
handleReference(*atom, *ref);
}
@@ -274,14 +709,58 @@ public:
// Add all created atoms to the link.
uint64_t ordinal = 0;
- for (auto &got : _gotVector) {
+ 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);
+ 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 &veneer : _veneerVector) {
- veneer->setOrdinal(ordinal++);
- mf->addAtom(*veneer);
+ 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:
@@ -290,16 +769,56 @@ protected:
const ELFLinkingContext &_ctx;
/// \brief Map Atoms to their GOT entries.
- llvm::DenseMap<const Atom *, GOTAtom *> _gotMap;
+ llvm::MapVector<const Atom *, GOTAtom *> _gotAtoms;
- /// \brief Map Atoms to their veneers.
- llvm::DenseMap<const Atom *, VeneerAtom *> _veneerMap;
+ /// \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 the list of GOT/PLT atoms
- std::vector<GOTAtom *> _gotVector;
+ /// \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) {}
- /// \brief the list of veneer atoms.
- std::vector<VeneerAtom *> _veneerVector;
+ 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
@@ -314,47 +833,138 @@ 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) {
- auto veneer = _veneerMap.find(da);
- if (_veneerMap.end() != veneer)
- return veneer->second;
+ 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 v = new (_file._alloc) Veneer_ARM_B_BL_StaticAtom(_file, secName);
- v->addReferenceELF_ARM(R_ARM_ABS32, 4, da, 0);
+ auto oa = new (_file._alloc) ARMObjectAtom(_file);
+ oa->addReferenceELF_ARM(R_ARM_COPY, 0, oa, 0);
- v->_name = "__";
- v->_name += da->name();
- v->_name += "_from_arm";
+ oa->_name = a->name();
+ oa->_size = a->size();
+
+ _objectAtoms[a] = oa;
+ return oa;
+ }
- _veneerMap[da] = v;
- _veneerVector.push_back(v);
- return v;
+ /// \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) {
- auto veneer = _veneerMap.find(da);
- if (_veneerMap.end() != veneer)
- return veneer->second;
+ if (_ctx.getOutputELFType() == llvm::ELF::ET_EXEC) {
+ return getVeneer_THM_B_BL_Abs(da, secName);
+ }
+ llvm_unreachable("Handle Thumb veneer for DSOs");
+ }
- auto v = new (_file._alloc) Veneer_THM_B_BL_StaticAtom(_file, secName);
- v->addReferenceELF_ARM(R_ARM_JUMP24, 4, da, 0);
+ /// \brief Create a GOT entry for R_ARM_TLS_TPOFF32 reloc.
+ const GOTAtom *getTLSTPOFF32(const DefinedAtom *da) {
+ return getGOTTLSEntry<R_ARM_TLS_TPOFF32>(da);
+ }
- v->_name = "__";
- v->_name += da->name();
- v->_name += "_from_thumb";
+ 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;
+ }
- _veneerMap[da] = v;
- _veneerVector.push_back(v);
- return v;
+ const GOTAtom *getSharedGOTEntry(const SharedLibraryAtom *sla) {
+ return getGOT<R_ARM_GLOB_DAT>(sla);
}
- /// \brief Create a GOT entry for R_ARM_TLS_TPOFF32 reloc.
- const GOTAtom *getTLSTPOFF32(const DefinedAtom *da) {
- return getGOTTLSEntry<R_ARM_TLS_LE32>(da);
+ 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);
}
};
@@ -365,8 +975,10 @@ lld::elf::createARMRelocationPass(const ARMLinkingContext &ctx) {
switch (ctx.getOutputELFType()) {
case llvm::ELF::ET_EXEC:
if (ctx.isDynamic())
- llvm_unreachable("Unhandled output file type");
+ return llvm::make_unique<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/ARMSymbolTable.h b/lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h
index 540a480421a8..85b9c9162589 100644
--- a/lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h
+++ b/lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h
@@ -10,34 +10,47 @@
#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
-template<class ELFT>
-class ARMSymbolTable : public SymbolTable<ELFT> {
+class ARMSymbolTable : public SymbolTable<ELF32LE> {
public:
- typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+ typedef llvm::object::Elf_Sym_Impl<ELF32LE> Elf_Sym;
- ARMSymbolTable(const ELFLinkingContext &context);
+ ARMSymbolTable(const ELFLinkingContext &ctx);
void addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da,
int64_t addr) override;
};
-template <class ELFT>
-ARMSymbolTable<ELFT>::ARMSymbolTable(const ELFLinkingContext &context)
- : SymbolTable<ELFT>(context, ".symtab",
- DefaultLayout<ELFT>::ORDER_SYMBOL_TABLE) {}
+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);
-template <class ELFT>
-void ARMSymbolTable<ELFT>::addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da,
- int64_t addr) {
- SymbolTable<ELFT>::addDefinedAtom(sym, da, addr);
+ if ((ARMELFDefinedAtom::ARMContentType)da->contentType() ==
+ ARMELFDefinedAtom::typeARMExidx)
+ sym.st_value = addr;
- // Set zero bit to distinguish symbols addressing Thumb instructions
+ // 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
diff --git a/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp b/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp
index de90f490f621..e1f5eadbe789 100644
--- a/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp
+++ b/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp
@@ -9,36 +9,24 @@
#include "Atoms.h"
#include "ARMExecutableWriter.h"
+#include "ARMDynamicLibraryWriter.h"
#include "ARMTargetHandler.h"
#include "ARMLinkingContext.h"
using namespace lld;
using namespace elf;
-ARMTargetHandler::ARMTargetHandler(ARMLinkingContext &context)
- : _context(context), _armTargetLayout(
- new ARMTargetLayout<ARMELFType>(context)),
- _armRelocationHandler(new ARMTargetRelocationHandler(
- *_armTargetLayout.get())) {}
-
-void ARMTargetHandler::registerRelocationNames(Registry &registry) {
- registry.addKindTable(Reference::KindNamespace::ELF, Reference::KindArch::ARM,
- kindStrings);
-}
+ARMTargetHandler::ARMTargetHandler(ARMLinkingContext &ctx)
+ : _ctx(ctx), _targetLayout(new ARMTargetLayout(ctx)),
+ _relocationHandler(new ARMTargetRelocationHandler(*_targetLayout)) {}
std::unique_ptr<Writer> ARMTargetHandler::getWriter() {
- switch (this->_context.getOutputELFType()) {
+ switch (this->_ctx.getOutputELFType()) {
case llvm::ELF::ET_EXEC:
- return std::unique_ptr<Writer>(
- new ARMExecutableWriter<ARMELFType>(_context, *_armTargetLayout.get()));
+ 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");
}
}
-
-#define ELF_RELOC(name, value) LLD_KIND_STRING_ENTRY(name),
-
-const Registry::KindStrings ARMTargetHandler::kindStrings[] = {
-#include "llvm/Support/ELFRelocs/ARM.def"
- LLD_KIND_STRING_END
-};
diff --git a/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h b/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h
index 10641954da25..0352e81a1f61 100644
--- a/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h
+++ b/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h
@@ -11,75 +11,161 @@
#define LLD_READER_WRITER_ELF_ARM_ARM_TARGET_HANDLER_H
#include "ARMELFFile.h"
-#include "ARMELFReader.h"
#include "ARMRelocationHandler.h"
-#include "DefaultTargetHandler.h"
+#include "ELFReader.h"
#include "TargetLayout.h"
-#include "lld/Core/Simple.h"
-#include "llvm/ADT/Optional.h"
-#include <map>
-
namespace lld {
+class ELFLinkingContext;
+
namespace elf {
-typedef llvm::object::ELFType<llvm::support::little, 2, false> ARMELFType;
-class ARMLinkingContext;
-template <class ELFT> class ARMTargetLayout : public TargetLayout<ELFT> {
+/// \brief ARM specific section (.ARM.exidx) with indexes to exception handlers
+class ARMExidxSection : public AtomSection<ELF32LE> {
+ typedef AtomSection<ELF32LE> Base;
+
public:
- ARMTargetLayout(ARMLinkingContext &context)
- : TargetLayout<ELFT>(context) {}
+ 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;
+ }
- uint64_t getTPOffset() {
- if (_tpOff.hasValue())
- return *_tpOff;
+ bool hasOutputSegment() const override { return true; }
- for (const auto &phdr : *this->_programHeader) {
- if (phdr->p_type == llvm::ELF::PT_TLS) {
- _tpOff = llvm::RoundUpToAlignment(TCB_SIZE, phdr->p_align);
- return *_tpOff;
- }
+ 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);
}
- llvm_unreachable("TLS segment not found");
}
+ 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 };
- // Cached value of the TLS offset from the $tp pointer.
- llvm::Optional<uint64_t> _tpOff;
+private:
+ uint64_t _gotSymAddr = 0;
+ uint64_t _tpOff = 0;
+ std::once_flag _gotSymOnce;
+ std::once_flag _tpOffOnce;
};
-class ARMTargetHandler final : public DefaultTargetHandler<ARMELFType> {
+class ARMTargetHandler final : public TargetHandler {
public:
- ARMTargetHandler(ARMLinkingContext &context);
-
- ARMTargetLayout<ARMELFType> &getTargetLayout() override {
- return *(_armTargetLayout.get());
- }
-
- void registerRelocationNames(Registry &registry) override;
+ ARMTargetHandler(ARMLinkingContext &ctx);
- const ARMTargetRelocationHandler &getRelocationHandler() const override {
- return *(_armRelocationHandler.get());
+ const TargetRelocationHandler &getRelocationHandler() const override {
+ return *_relocationHandler;
}
std::unique_ptr<Reader> getObjReader() override {
- return std::unique_ptr<Reader>(new ARMELFObjectReader(_context));
+ return llvm::make_unique<ELFReader<ARMELFFile>>(_ctx);
}
std::unique_ptr<Reader> getDSOReader() override {
- return std::unique_ptr<Reader>(new ARMELFDSOReader(_context));
+ return llvm::make_unique<ELFReader<DynamicFile<ELF32LE>>>(_ctx);
}
std::unique_ptr<Writer> getWriter() override;
private:
- static const Registry::KindStrings kindStrings[];
- ARMLinkingContext &_context;
- std::unique_ptr<ARMTargetLayout<ARMELFType>> _armTargetLayout;
- std::unique_ptr<ARMTargetRelocationHandler> _armRelocationHandler;
+ ARMLinkingContext &_ctx;
+ std::unique_ptr<ARMTargetLayout> _targetLayout;
+ std::unique_ptr<ARMTargetRelocationHandler> _relocationHandler;
};
} // end namespace elf
diff --git a/lib/ReaderWriter/ELF/ARM/Makefile b/lib/ReaderWriter/ELF/ARM/Makefile
deleted file mode 100644
index f67d36a1b612..000000000000
--- a/lib/ReaderWriter/ELF/ARM/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-##===------ lld/lib/ReaderWriter/ELF/ARM/Makefile ----------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LLD_LEVEL := ../../../..
-LIBRARYNAME := lldARMELFTarget
-USEDLIBS = lldCore.a
-CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF/ARM -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF
-
-include $(LLD_LEVEL)/Makefile
diff --git a/lib/ReaderWriter/ELF/ARM/TODO.rst b/lib/ReaderWriter/ELF/ARM/TODO.rst
index d05419decb78..61b585ae698c 100644
--- a/lib/ReaderWriter/ELF/ARM/TODO.rst
+++ b/lib/ReaderWriter/ELF/ARM/TODO.rst
@@ -4,14 +4,15 @@ ELF ARM
Unimplemented Features
######################
-* Static executable linking - in progress
-* Dynamic executable linking
* DSO linking
-* PLT entries' generation for images larger than 2^28 bytes (see Sec. A.3 of the ELF reference)
-* ARM and Thumb interworking (see http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0203j/Bcghfebi.html)
-* .ARM.exidx section handling
+* 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
-* Lots of relocations
+* Proper debug information (DWARF data)
+* TLS relocations for dynamic models
+* Lots of other relocations
Unimplemented Relocations
#########################
diff --git a/lib/ReaderWriter/ELF/Atoms.cpp b/lib/ReaderWriter/ELF/Atoms.cpp
new file mode 100644
index 000000000000..639633393161
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Atoms.cpp
@@ -0,0 +1,297 @@
+//===- 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
index 6a506d21d938..390c0e16baf8 100644
--- a/lib/ReaderWriter/ELF/Atoms.h
+++ b/lib/ReaderWriter/ELF/Atoms.h
@@ -13,6 +13,7 @@
#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>
@@ -41,19 +42,16 @@ public:
ELFReference(const Elf_Rela *rela, uint64_t off, Reference::KindArch arch,
Reference::KindValue relocType, uint32_t idx)
: Reference(Reference::KindNamespace::ELF, arch, relocType),
- _target(nullptr), _targetSymbolIndex(idx), _offsetInAtom(off),
- _addend(rela->r_addend) {}
+ _targetSymbolIndex(idx), _offsetInAtom(off), _addend(rela->r_addend) {}
ELFReference(uint64_t off, Reference::KindArch arch,
Reference::KindValue relocType, uint32_t idx)
: Reference(Reference::KindNamespace::ELF, arch, relocType),
- _target(nullptr), _targetSymbolIndex(idx), _offsetInAtom(off),
- _addend(0) {}
+ _targetSymbolIndex(idx), _offsetInAtom(off) {}
ELFReference(uint32_t edgeKind)
: Reference(Reference::KindNamespace::all, Reference::KindArch::all,
- edgeKind),
- _target(nullptr), _targetSymbolIndex(0), _offsetInAtom(0), _addend(0) {}
+ edgeKind) {}
uint64_t offsetInAtom() const override { return _offsetInAtom; }
@@ -73,10 +71,10 @@ public:
void setTarget(const Atom *newAtom) override { _target = newAtom; }
private:
- const Atom *_target;
- uint64_t _targetSymbolIndex;
- uint64_t _offsetInAtom;
- Addend _addend;
+ 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.
@@ -88,21 +86,11 @@ template <class ELFT> class ELFAbsoluteAtom : public AbsoluteAtom {
public:
ELFAbsoluteAtom(const ELFFile<ELFT> &file, StringRef name,
const Elf_Sym *symbol, uint64_t value)
- : _owningFile(file), _name(name), _symbol(symbol), _value(value) {
- }
+ : _owningFile(file), _name(name), _symbol(symbol), _value(value) {}
const ELFFile<ELFT> &file() const override { return _owningFile; }
-
- Scope scope() const override {
- if (_symbol->getVisibility() == llvm::ELF::STV_HIDDEN)
- return scopeLinkageUnit;
- if (_symbol->getBinding() == llvm::ELF::STB_LOCAL)
- return scopeTranslationUnit;
- return scopeGlobal;
- }
-
+ Scope scope() const override;
StringRef name() const override { return _name; }
-
uint64_t value() const override { return _value; }
private:
@@ -114,7 +102,7 @@ private:
/// \brief ELFUndefinedAtom: These atoms store undefined symbols and are place
/// holders that will be replaced by defined atoms later in the linking process.
-template <class ELFT> class ELFUndefinedAtom : public lld::UndefinedAtom {
+template <class ELFT> class ELFUndefinedAtom : public UndefinedAtom {
typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
public:
@@ -122,16 +110,11 @@ public:
: _owningFile(file), _name(name), _symbol(symbol) {}
const File &file() const override { return _owningFile; }
-
StringRef name() const override { return _name; }
// A symbol in ELF can be undefined at build time if the symbol is a undefined
// weak symbol.
- CanBeNull canBeNull() const override {
- if (_symbol->getBinding() == llvm::ELF::STB_WEAK)
- return CanBeNull::canBeNullAtBuildtime;
- return CanBeNull::canBeNullNever;
- }
+ CanBeNull canBeNull() const override;
private:
const File &_owningFile;
@@ -157,283 +140,49 @@ public:
_referenceList(referenceList), _contentType(typeUnknown),
_permissions(permUnknown) {}
- ~ELFDefinedAtom() {}
+ ~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 {
- // Common symbols are not allocated in object files,
- // so use st_size to tell how many bytes are required.
- if (_symbol && (_symbol->getType() == llvm::ELF::STT_COMMON ||
- _symbol->st_shndx == llvm::ELF::SHN_COMMON))
- return (uint64_t) _symbol->st_size;
-
- return _contentData.size();
- }
-
- Scope scope() const override {
- if (!_symbol)
- return scopeGlobal;
- if (_symbol->getVisibility() == llvm::ELF::STV_HIDDEN)
- return scopeLinkageUnit;
- if (_symbol->getBinding() != llvm::ELF::STB_LOCAL)
- return scopeGlobal;
- return scopeTranslationUnit;
- }
+ 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 {
- if (!_symbol)
- return mergeNo;
-
- if (_symbol->getBinding() == llvm::ELF::STB_WEAK)
- return mergeAsWeak;
-
- if ((_symbol->getType() == llvm::ELF::STT_COMMON) ||
- _symbol->st_shndx == llvm::ELF::SHN_COMMON)
- return mergeAsTentative;
-
- return mergeNo;
- }
-
- ContentType contentType() const override {
- if (_contentType != typeUnknown)
- return _contentType;
-
- ContentType ret = typeUnknown;
- uint64_t flags = _section->sh_flags;
-
- if (_section->sh_type == llvm::ELF::SHT_GROUP)
- return typeGroupComdat;
-
- if (!_symbol && _sectionName.startswith(".gnu.linkonce"))
- return typeGnuLinkOnce;
-
- if (!(flags & llvm::ELF::SHF_ALLOC))
- return _contentType = typeNoAlloc;
-
- if (_section->sh_flags ==
- (llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE | llvm::ELF::SHF_TLS)) {
- return _contentType = _section->sh_type == llvm::ELF::SHT_NOBITS ? typeThreadZeroFill
- : typeThreadData;
- }
-
- if ((_section->sh_flags == llvm::ELF::SHF_ALLOC) &&
- (_section->sh_type == llvm::ELF::SHT_PROGBITS))
- return _contentType = typeConstant;
-
- if (_symbol->getType() == llvm::ELF::STT_GNU_IFUNC)
- return _contentType = typeResolver;
-
- if (_symbol->st_shndx == llvm::ELF::SHN_COMMON)
- return _contentType = typeZeroFill;
-
- switch (_section->sh_type) {
- case llvm::ELF::SHT_PROGBITS:
- flags &= ~llvm::ELF::SHF_ALLOC;
- flags &= ~llvm::ELF::SHF_GROUP;
- switch (flags) {
- case llvm::ELF::SHF_EXECINSTR:
- case (llvm::ELF::SHF_WRITE|llvm::ELF::SHF_EXECINSTR):
- ret = typeCode;
- break;
- case llvm::ELF::SHF_WRITE:
- ret = typeData;
- break;
- case (llvm::ELF::SHF_MERGE|llvm::ELF::SHF_STRINGS):
- case llvm::ELF::SHF_STRINGS:
- case llvm::ELF::SHF_MERGE:
- ret = typeConstant;
- break;
- default:
- ret = typeCode;
- break;
- }
- break;
- case llvm::ELF::SHT_NOTE:
- flags &= ~llvm::ELF::SHF_ALLOC;
- switch (flags) {
- case llvm::ELF::SHF_WRITE:
- ret = typeRWNote;
- break;
- default:
- ret = typeRONote;
- break;
- }
- break;
- case llvm::ELF::SHT_NOBITS:
- ret = typeZeroFill;
- break;
- case llvm::ELF::SHT_NULL:
- if ((_symbol->getType() == llvm::ELF::STT_COMMON)
- || _symbol->st_shndx == llvm::ELF::SHN_COMMON)
- ret = typeZeroFill;
- break;
- case llvm::ELF::SHT_INIT_ARRAY:
- case llvm::ELF::SHT_FINI_ARRAY:
- ret = typeData;
- break;
- }
-
- return _contentType = ret;
- }
-
- Alignment alignment() const override {
- if (!_symbol)
- return Alignment(0);
-
- // Obtain proper value of st_value field.
- const auto symValue = getSymbolValue(_symbol);
-
- // Unallocated common symbols specify their alignment constraints in
- // st_value.
- if ((_symbol->getType() == llvm::ELF::STT_COMMON) ||
- _symbol->st_shndx == llvm::ELF::SHN_COMMON) {
- return Alignment(llvm::Log2_64(symValue));
- }
- if (_section->sh_addralign == 0) {
- // sh_addralign of 0 means no alignment
- return Alignment(0, symValue);
- }
- return Alignment(llvm::Log2_64(_section->sh_addralign),
- symValue % _section->sh_addralign);
- }
-
- // Do we have a choice for ELF? All symbols live in explicit sections.
- SectionChoice sectionChoice() const override {
- switch (contentType()) {
- case typeCode:
- case typeData:
- case typeZeroFill:
- case typeThreadZeroFill:
- case typeThreadData:
- case typeConstant:
- if ((_sectionName == ".text") || (_sectionName == ".data") ||
- (_sectionName == ".bss") || (_sectionName == ".rodata") ||
- (_sectionName == ".tdata") || (_sectionName == ".tbss"))
- return sectionBasedOnContent;
- default:
- break;
- }
- return sectionCustomRequired;
- }
-
- StringRef customSectionName() const override {
- if ((contentType() == typeZeroFill) ||
- (_symbol && _symbol->st_shndx == llvm::ELF::SHN_COMMON))
- return ".bss";
- return _sectionName;
- }
+ 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 {
- 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___;
- }
- }
-
+ ContentPermissions permissions() const override;
ArrayRef<uint8_t> rawContent() const override { return _contentData; }
- DefinedAtom::reference_iterator begin() const override {
- uintptr_t index = _referenceStartIndex;
- const void *it = reinterpret_cast<const void*>(index);
- return reference_iterator(*this, it);
- }
-
- DefinedAtom::reference_iterator end() const override {
- uintptr_t index = _referenceEndIndex;
- const void *it = reinterpret_cast<const void*>(index);
- return reference_iterator(*this, it);
- }
-
- const Reference *derefIterator(const void *It) const override {
- uintptr_t index = reinterpret_cast<uintptr_t>(It);
- assert(index >= _referenceStartIndex);
- assert(index < _referenceEndIndex);
- return ((_referenceList)[index]);
- }
-
- void incrementIterator(const void *&It) const override {
- uintptr_t index = reinterpret_cast<uintptr_t>(It);
- ++index;
- It = reinterpret_cast<const void *>(index);
- }
-
- void addReference(ELFReference<ELFT> *reference) {
- _referenceList.push_back(reference);
- _referenceEndIndex = _referenceList.size();
- }
+ 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 Elf_Sym *symbol) const {
- return symbol->st_value;
+ virtual uint64_t getSymbolValue() const {
+ return _symbol->st_value;
}
-protected:
+ ContentType doContentType() const;
+
const ELFFile<ELFT> &_owningFile;
StringRef _symbolName;
StringRef _sectionName;
@@ -463,39 +212,25 @@ public:
}
const ELFFile<ELFT> &file() const override { return _owningFile; }
-
StringRef name() const override { return ""; }
-
virtual uint64_t section() const { return _section->sh_name; }
-
virtual uint64_t offset() const { return _offset; }
-
virtual void setOrdinal(uint64_t ord) { _ordinal = ord; }
-
uint64_t ordinal() const override { return _ordinal; }
-
uint64_t size() const override { return _contentData.size(); }
-
Scope scope() const override { return scopeTranslationUnit; }
-
Interposable interposable() const override { return interposeNo; }
-
Merge merge() const override { return mergeByContent; }
-
ContentType contentType() const override { return typeConstant; }
Alignment alignment() const override {
- return Alignment(llvm::Log2_64(_section->sh_addralign));
+ 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 {
@@ -517,7 +252,6 @@ public:
void incrementIterator(const void *&It) const override {}
private:
-
const ELFFile<ELFT> &_owningFile;
StringRef _sectionName;
const Elf_Shdr *_section;
@@ -530,21 +264,14 @@ private:
template <class ELFT> class ELFCommonAtom : public DefinedAtom {
typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
public:
- ELFCommonAtom(const ELFFile<ELFT> &file,
- StringRef symbolName,
+ ELFCommonAtom(const ELFFile<ELFT> &file, StringRef symbolName,
const Elf_Sym *symbol)
- : _owningFile(file),
- _symbolName(symbolName),
- _symbol(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 {
@@ -556,23 +283,13 @@ public:
}
Interposable interposable() const override { return interposeNo; }
-
Merge merge() const override { return mergeAsTentative; }
-
ContentType contentType() const override { return typeZeroFill; }
-
- Alignment alignment() const override {
- return Alignment(llvm::Log2_64(_symbol->st_value));
- }
-
+ 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 {
@@ -608,42 +325,19 @@ public:
ELFDynamicAtom(const DynamicFile<ELFT> &file, StringRef symbolName,
StringRef loadName, const Elf_Sym *symbol)
: _owningFile(file), _symbolName(symbolName), _loadName(loadName),
- _symbol(symbol) {
- }
+ _symbol(symbol) {}
const DynamicFile<ELFT> &file() const override { return _owningFile; }
-
StringRef name() const override { return _symbolName; }
-
- virtual Scope scope() const {
- if (_symbol->getVisibility() == llvm::ELF::STV_HIDDEN)
- return scopeLinkageUnit;
- if (_symbol->getBinding() != llvm::ELF::STB_LOCAL)
- return scopeGlobal;
- return scopeTranslationUnit;
- }
-
+ 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 {
- switch (_symbol->getType()) {
- case llvm::ELF::STT_FUNC:
- case llvm::ELF::STT_GNU_IFUNC:
- return Type::Code;
- case llvm::ELF::STT_OBJECT:
- return Type::Data;
- default:
- return Type::Unknown;
- }
- }
-
- uint64_t size() const override {
- return _symbol->st_size;
- }
+ Type type() const override;
+ uint64_t size() const override { return _symbol->st_size; }
private:
@@ -658,35 +352,33 @@ public:
SimpleELFDefinedAtom(const File &f) : SimpleDefinedAtom(f) {}
void addReferenceELF(Reference::KindArch arch, Reference::KindValue kindValue,
- uint64_t off, const Atom *target,
- Reference::Addend addend) {
- this->addReference(Reference::KindNamespace::ELF, arch, kindValue, off,
- target, addend);
+ 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) {
- this->addReferenceELF(Reference::KindArch::Hexagon, relocType, off, t, 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) {
- this->addReferenceELF(Reference::KindArch::x86_64, relocType, off, t, 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) {
- this->addReferenceELF(Reference::KindArch::Mips, relocType, off, t, a);
+ addReferenceELF(Reference::KindArch::Mips, relocType, off, t, a);
}
void addReferenceELF_AArch64(Reference::KindValue relocType, uint64_t off,
const Atom *t, Reference::Addend a) {
- this->addReferenceELF(Reference::KindArch::AArch64, relocType, off, t, a);
+ addReferenceELF(Reference::KindArch::AArch64, relocType, off, t, a);
}
void addReferenceELF_ARM(Reference::KindValue relocType, uint64_t off,
const Atom *t, Reference::Addend a) {
- this->addReferenceELF(Reference::KindArch::ARM, relocType, off, t, a);
+ addReferenceELF(Reference::KindArch::ARM, relocType, off, t, a);
}
};
@@ -695,26 +387,14 @@ public:
class ObjectAtom : public SimpleELFDefinedAtom {
public:
ObjectAtom(const File &f) : SimpleELFDefinedAtom(f) {}
-
Scope scope() const override { return scopeGlobal; }
-
SectionChoice sectionChoice() const override { return sectionBasedOnContent; }
-
ContentType contentType() const override { return typeZeroFill; }
-
uint64_t size() const override { return _size; }
-
DynamicExport dynamicExport() const override { return dynamicExportAlways; }
-
ContentPermissions permissions() const override { return permRW_; }
-
ArrayRef<uint8_t> rawContent() const override { return ArrayRef<uint8_t>(); }
-
- Alignment alignment() const override {
- // The alignment should be 8 byte aligned
- return Alignment(3);
- }
-
+ Alignment alignment() const override { return 8; }
StringRef name() const override { return _name; }
std::string _name;
@@ -729,21 +409,12 @@ public:
: SimpleELFDefinedAtom(f), _section(secName) {}
Scope scope() const override { return scopeTranslationUnit; }
-
SectionChoice sectionChoice() const override { return sectionCustomRequired; }
-
StringRef customSectionName() const override { return _section; }
-
ContentType contentType() const override { return typeGOT; }
-
uint64_t size() const override { return rawContent().size(); }
-
ContentPermissions permissions() const override { return permRW_; }
-
- Alignment alignment() const override {
- // The alignment should be 8 byte aligned
- return Alignment(3);
- }
+ Alignment alignment() const override { return 8; }
#ifndef NDEBUG
StringRef name() const override { return _name; }
@@ -761,20 +432,12 @@ public:
: SimpleELFDefinedAtom(f), _section(secName) {}
Scope scope() const override { return scopeTranslationUnit; }
-
SectionChoice sectionChoice() const override { return sectionCustomRequired; }
-
StringRef customSectionName() const override { return _section; }
-
ContentType contentType() const override { return typeStub; }
-
uint64_t size() const override { return rawContent().size(); }
-
ContentPermissions permissions() const override { return permR_X; }
-
- Alignment alignment() const override {
- return Alignment(4); // 16
- }
+ Alignment alignment() const override { return 16; }
#ifndef NDEBUG
StringRef name() const override { return _name; }
@@ -793,57 +456,38 @@ public:
}
};
-class GLOBAL_OFFSET_TABLEAtom : public SimpleELFDefinedAtom {
+class GlobalOffsetTableAtom : public SimpleELFDefinedAtom {
public:
- GLOBAL_OFFSET_TABLEAtom(const File &f) : SimpleELFDefinedAtom(f) {}
+ 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 {
- // Needs 8 byte alignment
- return Alignment(3);
- }
-
+ Alignment alignment() const override { return 8; }
ArrayRef<uint8_t> rawContent() const override { return ArrayRef<uint8_t>(); }
};
-class DYNAMICAtom : public SimpleELFDefinedAtom {
+class DynamicAtom : public SimpleELFDefinedAtom {
public:
- DYNAMICAtom(const File &f) : SimpleELFDefinedAtom(f) {}
+ DynamicAtom(const File &f) : SimpleELFDefinedAtom(f) {}
StringRef name() const override { return "_DYNAMIC"; }
-
Scope scope() const override { return scopeLinkageUnit; }
-
Merge merge() const override { return mergeNo; }
-
SectionChoice sectionChoice() const override { return sectionCustomRequired; }
-
StringRef customSectionName() const override { return ".dynamic"; }
-
ContentType contentType() const override { return typeData; }
-
uint64_t size() const override { return 0; }
-
ContentPermissions permissions() const override { return permRW_; }
-
- Alignment alignment() const override { return Alignment(0); }
-
+ Alignment alignment() const override { return 1; }
ArrayRef<uint8_t> rawContent() const override { return ArrayRef<uint8_t>(); }
};
+
} // end namespace elf
} // end namespace lld
-#endif
+#endif // LLD_READER_WRITER_ELF_ATOMS_H
diff --git a/lib/ReaderWriter/ELF/CMakeLists.txt b/lib/ReaderWriter/ELF/CMakeLists.txt
index fd4cb669904d..e3e4a02b2810 100644
--- a/lib/ReaderWriter/ELF/CMakeLists.txt
+++ b/lib/ReaderWriter/ELF/CMakeLists.txt
@@ -1,11 +1,21 @@
add_llvm_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
)
@@ -17,3 +27,4 @@ add_subdirectory(Mips)
add_subdirectory(Hexagon)
add_subdirectory(AArch64)
add_subdirectory(ARM)
+add_subdirectory(AMDGPU)
diff --git a/lib/ReaderWriter/ELF/Chunk.h b/lib/ReaderWriter/ELF/Chunk.h
index 2658d023b3a9..f223b6c54163 100644
--- a/lib/ReaderWriter/ELF/Chunk.h
+++ b/lib/ReaderWriter/ELF/Chunk.h
@@ -25,32 +25,33 @@ 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 {
+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
+ 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 };
+ enum ContentType : uint8_t { Unknown, Header, Code, Data, Note, TLS };
+
+ Chunk(StringRef name, Kind kind, const ELFLinkingContext &ctx)
+ : _name(name), _kind(kind), _ctx(ctx) {}
- Chunk(StringRef name, Kind kind, const ELFLinkingContext &context)
- : _name(name), _kind(kind), _fsize(0), _msize(0), _alignment(0), _order(0),
- _ordinal(1), _start(0), _fileoffset(0), _context(context) {}
virtual ~Chunk() {}
+
// The name of the chunk
StringRef name() const { return _name; }
+
// Kind of chunk
Kind kind() const { return _kind; }
virtual uint64_t fileSize() const { return _fsize; }
@@ -59,41 +60,49 @@ public:
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;}
+ 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; }
+ 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; }
+ uint64_t fileOffset() const { return _fileoffset; }
+ void setFileOffset(uint64_t offset) { _fileoffset = offset; }
+
// Output start address of the chunk
virtual void setVirtualAddr(uint64_t start) { _start = start; }
virtual uint64_t virtualAddr() const { return _start; }
+
// Memory size of the chunk
uint64_t memSize() const { return _msize; }
void setMemSize(uint64_t msize) { _msize = msize; }
- // Whats the contentType of the chunk?
+
+ // 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() = 0;
+ virtual void doPreFlight() {}
+
// Finalize the chunk before writing
- virtual void finalize() = 0;
+ virtual void finalize() {}
protected:
StringRef _name;
Kind _kind;
- uint64_t _fsize;
- uint64_t _msize;
- uint64_t _alignment;
- uint32_t _order;
- uint64_t _ordinal;
- uint64_t _start;
- uint64_t _fileoffset;
- const ELFLinkingContext &_context;
+ 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
diff --git a/lib/ReaderWriter/ELF/CreateELF.h b/lib/ReaderWriter/ELF/CreateELF.h
deleted file mode 100644
index ad34dddb24d3..000000000000
--- a/lib/ReaderWriter/ELF/CreateELF.h
+++ /dev/null
@@ -1,118 +0,0 @@
-//===- lib/ReaderWriter/ELF/CreateELF.h -----------------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// \brief This file provides a simple way to create an object templated on
-/// ELFType depending on the runtime type needed.
-///
-//===----------------------------------------------------------------------===//
-#ifndef LLD_READER_WRITER_ELF_CREATE_ELF_H
-#define LLD_READER_WRITER_ELF_CREATE_ELF_H
-
-#include "llvm/Object/ELF.h"
-#include "llvm/Support/Compiler.h"
-
-namespace {
-using llvm::object::ELFType;
-
-/// \func createELF
-/// \brief Create an object depending on the runtime attributes and alignment
-/// of an ELF file.
-///
-/// \param Traits
-/// Traits::result_type must be a type convertable from what create returns.
-/// Traits::create must be a template function which takes an ELFType and
-/// returns something convertable to Traits::result_type.
-///
-/// \param ident pair of EI_CLASS and EI_DATA.
-/// \param maxAlignment the maximum alignment of the file.
-/// \param args arguments forwarded to CreateELFTraits<T>::create.
-
-#define LLVM_CREATE_ELF_CreateELFTraits(endian, align, is64, ...) \
- Traits::template create<ELFType<llvm::support::endian, align, is64>>( \
- __VA_ARGS__);
-
-#if !LLVM_IS_UNALIGNED_ACCESS_FAST
-# define LLVM_CREATE_ELF_MaxAlignCheck(normal, low, endian, is64, ...) \
- if (maxAlignment >= normal) \
- return LLVM_CREATE_ELF_CreateELFTraits(endian, normal, is64, __VA_ARGS__) \
- else if (maxAlignment >= low) \
- return LLVM_CREATE_ELF_CreateELFTraits(endian, low, is64, __VA_ARGS__) \
- else \
- llvm_unreachable("Invalid alignment for ELF file!");
-#else
-# define LLVM_CREATE_ELF_MaxAlignCheck(normal, low, endian, is64, ...) \
- if (maxAlignment >= low) \
- return LLVM_CREATE_ELF_CreateELFTraits(endian, low, is64, __VA_ARGS__) \
- else \
- llvm_unreachable("Invalid alignment for ELF file!");
-#endif
-
-#define LLVM_CREATE_ELF_IMPL(...) \
- if (ident.first == llvm::ELF::ELFCLASS32 && \
- ident.second == llvm::ELF::ELFDATA2LSB) { \
- LLVM_CREATE_ELF_MaxAlignCheck(4, 2, little, false, __VA_ARGS__) \
- } else if (ident.first == llvm::ELF::ELFCLASS32 && \
- ident.second == llvm::ELF::ELFDATA2MSB) { \
- LLVM_CREATE_ELF_MaxAlignCheck(4, 2, big, false, __VA_ARGS__) \
- } else if (ident.first == llvm::ELF::ELFCLASS64 && \
- ident.second == llvm::ELF::ELFDATA2MSB) { \
- LLVM_CREATE_ELF_MaxAlignCheck(8, 2, big, true, __VA_ARGS__) \
- } else if (ident.first == llvm::ELF::ELFCLASS64 && \
- ident.second == llvm::ELF::ELFDATA2LSB) { \
- LLVM_CREATE_ELF_MaxAlignCheck(8, 2, little, true, __VA_ARGS__) \
- } \
- llvm_unreachable("Invalid ELF type!");
-
-#if LLVM_HAS_VARIADIC_TEMPLATES
-template <class Traits, class ...Args>
-typename Traits::result_type createELF(
- std::pair<unsigned char, unsigned char> ident, std::size_t maxAlignment,
- Args &&...args) {
- LLVM_CREATE_ELF_IMPL(std::forward<Args>(args)...)
-}
-#else
-template <class Traits, class T1>
-typename Traits::result_type createELF(
- std::pair<unsigned char, unsigned char> ident, std::size_t maxAlignment,
- T1 &&t1) {
- LLVM_CREATE_ELF_IMPL(std::forward<T1>(t1))
-}
-
-template <class Traits, class T1, class T2>
-typename Traits::result_type createELF(
- std::pair<unsigned char, unsigned char> ident, std::size_t maxAlignment,
- T1 &&t1, T2 &&t2) {
- LLVM_CREATE_ELF_IMPL(std::forward<T1>(t1), std::forward<T2>(t2))
-}
-
-template <class Traits, class T1, class T2, class T3>
-typename Traits::result_type createELF(
- std::pair<unsigned char, unsigned char> ident, std::size_t maxAlignment,
- T1 &&t1, T2 &&t2, T3 &&t3) {
- LLVM_CREATE_ELF_IMPL(std::forward<T1>(t1), std::forward<T2>(t2),
- std::forward<T3>(t3))
-}
-
-template <class Traits, class T1, class T2, class T3, class T4>
-typename Traits::result_type createELF(
- std::pair<unsigned char, unsigned char> ident, std::size_t maxAlignment,
- T1 &&t1, T2 &&t2, T3 &&t3, T4 &&t4) {
- LLVM_CREATE_ELF_IMPL(std::forward<T1>(t1), std::forward<T2>(t2),
- std::forward<T3>(t3), std::forward<T4>(t4))
-}
-
-#endif // LLVM_HAS_VARIADIC_TEMPLATES
-} // end anon namespace
-
-#undef LLVM_CREATE_ELF_CreateELFTraits
-#undef LLVM_CREATE_ELF_MaxAlignCheck
-#undef LLVM_CREATE_ELF_IMPL
-
-#endif
diff --git a/lib/ReaderWriter/ELF/DefaultLayout.h b/lib/ReaderWriter/ELF/DefaultLayout.h
deleted file mode 100644
index 9af3b8eb8dc6..000000000000
--- a/lib/ReaderWriter/ELF/DefaultLayout.h
+++ /dev/null
@@ -1,1050 +0,0 @@
-//===- lib/ReaderWriter/ELF/DefaultLayout.h -------------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_ELF_DEFAULT_LAYOUT_H
-#define LLD_READER_WRITER_ELF_DEFAULT_LAYOUT_H
-
-#include "Atoms.h"
-#include "Chunk.h"
-#include "HeaderChunks.h"
-#include "Layout.h"
-#include "SectionChunks.h"
-#include "SegmentChunks.h"
-#include "lld/Core/Instrumentation.h"
-#include "lld/Core/STDExtras.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/DenseSet.h"
-#include "llvm/ADT/Hashing.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/StringSwitch.h"
-#include "llvm/Support/Errc.h"
-#include "llvm/Support/Format.h"
-#include <map>
-#include <unordered_map>
-
-namespace lld {
-namespace elf {
-/// \brief The DefaultLayout class is used by the Writer to arrange
-/// sections and segments in the order determined by the target ELF
-/// format. The writer creates a single instance of the DefaultLayout
-/// class
-template<class ELFT>
-class DefaultLayout : public Layout {
-public:
-
- // The order in which the sections appear in the output file
- // If its determined, that the layout needs to change
- // just changing the order of enumerations would essentially
- // change the layout in the output file
- // Change the enumerations so that Target can override and stick
- // a section anywhere it wants to
- enum DefaultSectionOrder {
- ORDER_NOT_DEFINED = 0,
- ORDER_INTERP = 10,
- ORDER_RO_NOTE = 15,
- ORDER_HASH = 30,
- ORDER_DYNAMIC_SYMBOLS = 40,
- ORDER_DYNAMIC_STRINGS = 50,
- ORDER_DYNAMIC_RELOCS = 52,
- ORDER_DYNAMIC_PLT_RELOCS = 54,
- ORDER_INIT = 60,
- ORDER_PLT = 70,
- ORDER_TEXT = 80,
- ORDER_FINI = 90,
- ORDER_REL = 95,
- ORDER_RODATA = 100,
- ORDER_EH_FRAME = 110,
- ORDER_EH_FRAMEHDR = 120,
- ORDER_TDATA = 124,
- ORDER_TBSS = 128,
- ORDER_CTORS = 130,
- ORDER_DTORS = 140,
- ORDER_INIT_ARRAY = 150,
- ORDER_FINI_ARRAY = 160,
- ORDER_DYNAMIC = 170,
- ORDER_GOT = 180,
- ORDER_GOT_PLT = 190,
- ORDER_DATA = 200,
- ORDER_RW_NOTE = 205,
- ORDER_BSS = 210,
- ORDER_NOALLOC = 215,
- ORDER_OTHER = 220,
- ORDER_SECTION_STRINGS = 230,
- ORDER_SYMBOL_TABLE = 240,
- ORDER_STRING_TABLE = 250,
- ORDER_SECTION_HEADERS = 260
- };
-
-public:
-
- // The Key used for creating Sections
- // The sections are created using
- // SectionName, contentPermissions
- struct SectionKey {
- SectionKey(StringRef name, DefinedAtom::ContentPermissions perm,
- StringRef path)
- : _name(name), _perm(perm), _path(path) {}
-
- // Data members
- StringRef _name;
- DefinedAtom::ContentPermissions _perm;
- StringRef _path;
- };
-
- struct SectionKeyHash {
- int64_t operator()(const SectionKey &k) const {
- return llvm::hash_combine(k._name, k._perm, k._path);
- }
- };
-
- struct SectionKeyEq {
- bool operator()(const SectionKey &lhs, const SectionKey &rhs) const {
- return ((lhs._name == rhs._name) && (lhs._perm == rhs._perm) &&
- (lhs._path == rhs._path));
- }
- };
-
- typedef typename std::vector<Chunk<ELFT> *>::iterator ChunkIter;
- typedef typename std::vector<Segment<ELFT> *>::iterator SegmentIter;
-
- // The additional segments are used to figure out
- // if there is a segment by that type already created
- // For example : PT_TLS, we have two sections .tdata/.tbss
- // that are part of PT_TLS, we need to create this additional
- // segment only once
- typedef std::pair<int64_t, int64_t> AdditionalSegmentKey;
- // The segments are created using
- // SegmentName, Segment flags
- typedef std::pair<StringRef, int64_t> SegmentKey;
-
- // HashKey for the Segment
- class SegmentHashKey {
- public:
- int64_t operator() (const SegmentKey &k) const {
- // k.first = SegmentName
- // k.second = SegmentFlags
- return llvm::hash_combine(k.first, k.second);
- }
- };
-
- class AdditionalSegmentHashKey {
- public:
- int64_t operator()(const AdditionalSegmentKey &k) const {
- // k.first = SegmentName
- // k.second = SegmentFlags
- return llvm::hash_combine(k.first, k.second);
- }
- };
-
- // Output Sections contain the map of Sectionnames to a vector of sections,
- // that have been merged to form a single section
- typedef llvm::StringMap<OutputSection<ELFT> *> OutputSectionMapT;
- typedef
- typename std::vector<OutputSection<ELFT> *>::iterator OutputSectionIter;
-
- typedef std::unordered_map<SectionKey, AtomSection<ELFT> *, SectionKeyHash,
- SectionKeyEq> SectionMapT;
- typedef std::unordered_map<AdditionalSegmentKey, Segment<ELFT> *,
- AdditionalSegmentHashKey> AdditionalSegmentMapT;
- typedef std::unordered_map<SegmentKey, Segment<ELFT> *, SegmentHashKey>
- SegmentMapT;
-
- /// \brief find a absolute atom pair given a absolute atom name
- struct FindByName {
- const std::string _name;
- FindByName(StringRef name) : _name(name) {}
- bool operator()(const lld::AtomLayout *j) { return j->_atom->name() == _name; }
- };
-
- typedef typename std::vector<lld::AtomLayout *>::iterator AbsoluteAtomIterT;
-
- typedef llvm::DenseSet<const Atom *> AtomSetT;
-
- DefaultLayout(ELFLinkingContext &context)
- : _context(context), _linkerScriptSema(context.linkerScriptSema()) {}
-
- /// \brief Return the section order for a input section
- SectionOrder getSectionOrder(StringRef name, int32_t contentType,
- int32_t contentPermissions) override;
-
- /// \brief Return the name of the input section by decoding the input
- /// sectionChoice.
- virtual StringRef getInputSectionName(const DefinedAtom *da) const;
-
- /// \brief Return the name of the output section from the input section.
- virtual StringRef getOutputSectionName(StringRef archivePath,
- StringRef memberPath,
- StringRef inputSectionName) const;
-
- /// \brief Gets or creates a section.
- AtomSection<ELFT> *
- getSection(StringRef name, int32_t contentType,
- DefinedAtom::ContentPermissions contentPermissions,
- const DefinedAtom *da);
-
- /// \brief Gets the segment for a output section
- virtual Layout::SegmentType getSegmentType(Section<ELFT> *section) const;
-
- /// \brief Returns true/false depending on whether the section has a Output
- // segment or not
- static bool hasOutputSegment(Section<ELFT> *section);
-
- // Adds an atom to the section
- ErrorOr<const lld::AtomLayout *> addAtom(const Atom *atom) override;
-
- /// \brief Find an output Section given a section name.
- OutputSection<ELFT> *findOutputSection(StringRef name) {
- auto iter = _outputSectionMap.find(name);
- if (iter == _outputSectionMap.end())
- return nullptr;
- return iter->second;
- }
-
- /// \brief find a absolute atom given a name
- AbsoluteAtomIterT findAbsoluteAtom(StringRef name) {
- return std::find_if(_absoluteAtoms.begin(), _absoluteAtoms.end(),
- FindByName(name));
- }
-
- // Output sections with the same name into a OutputSection
- void createOutputSections();
-
- /// \brief Sort the sections by their order as defined by the layout,
- /// preparing all sections to be assigned to a segment.
- virtual void sortInputSections();
-
- /// \brief Add extra chunks to a segment just before including the input
- /// section given by <archivePath, memberPath, sectionName>. This
- /// is used to add linker script expressions before each section.
- virtual void addExtraChunksToSegment(Segment<ELFT> *segment,
- StringRef archivePath,
- StringRef memberPath,
- StringRef sectionName);
-
- void assignSectionsToSegments() override;
-
- void assignVirtualAddress() override;
-
- void assignFileOffsetsForMiscSections();
-
- range<AbsoluteAtomIterT> absoluteAtoms() { return _absoluteAtoms; }
-
- void addSection(Chunk<ELFT> *c) { _sections.push_back(c); }
-
- void finalize() {
- ScopedTask task(getDefaultDomain(), "Finalize layout");
- for (auto &si : _sections)
- si->finalize();
- }
-
- void doPreFlight() {
- for (auto &si : _sections)
- si->doPreFlight();
- }
-
- const AtomLayout *findAtomLayoutByName(StringRef name) const override {
- for (auto sec : _sections)
- if (auto section = dyn_cast<Section<ELFT>>(sec))
- if (auto *al = section->findAtomLayoutByName(name))
- return al;
- return nullptr;
- }
-
- void setHeader(ELFHeader<ELFT> *elfHeader) { _elfHeader = elfHeader; }
-
- void setProgramHeader(ProgramHeader<ELFT> *p) {
- _programHeader = p;
- }
-
- range<OutputSectionIter> outputSections() { return _outputSections; }
-
- range<ChunkIter> sections() { return _sections; }
-
- range<SegmentIter> segments() { return _segments; }
-
- ELFHeader<ELFT> *getHeader() { return _elfHeader; }
-
- bool hasDynamicRelocationTable() const { return !!_dynamicRelocationTable; }
-
- bool hasPLTRelocationTable() const { return !!_pltRelocationTable; }
-
- /// \brief Get or create the dynamic relocation table. All relocations in this
- /// table are processed at startup.
- RelocationTable<ELFT> *getDynamicRelocationTable() {
- if (!_dynamicRelocationTable) {
- _dynamicRelocationTable = std::move(createRelocationTable(
- _context.isRelaOutputFormat() ? ".rela.dyn" : ".rel.dyn",
- ORDER_DYNAMIC_RELOCS));
- addSection(_dynamicRelocationTable.get());
- }
- return _dynamicRelocationTable.get();
- }
-
- /// \brief Get or create the PLT relocation table. Referenced by DT_JMPREL.
- RelocationTable<ELFT> *getPLTRelocationTable() {
- if (!_pltRelocationTable) {
- _pltRelocationTable = std::move(createRelocationTable(
- _context.isRelaOutputFormat() ? ".rela.plt" : ".rel.plt",
- ORDER_DYNAMIC_PLT_RELOCS));
- addSection(_pltRelocationTable.get());
- }
- return _pltRelocationTable.get();
- }
-
- uint64_t getTLSSize() const {
- for (const auto &phdr : *_programHeader)
- if (phdr->p_type == llvm::ELF::PT_TLS)
- return phdr->p_memsz;
- return 0;
- }
-
- bool isReferencedByDefinedAtom(const Atom *a) const {
- return _referencedDynAtoms.count(a);
- }
-
- bool isCopied(const SharedLibraryAtom *sla) const {
- return _copiedDynSymNames.count(sla->name());
- }
-
- /// \brief Handle SORT_BY_PRIORITY.
- void sortOutputSectionByPriority(StringRef outputSectionName,
- StringRef prefix);
-
-protected:
- /// \brief TargetLayouts may use these functions to reorder the input sections
- /// in a order defined by their ABI.
- virtual void finalizeOutputSectionLayout() {}
-
- /// \brief Allocate a new section.
- virtual AtomSection<ELFT> *createSection(
- StringRef name, int32_t contentType,
- DefinedAtom::ContentPermissions contentPermissions,
- SectionOrder sectionOrder);
-
- /// \brief Create a new relocation table.
- virtual unique_bump_ptr<RelocationTable<ELFT>>
- createRelocationTable(StringRef name, int32_t order) {
- return unique_bump_ptr<RelocationTable<ELFT>>(
- new (_allocator) RelocationTable<ELFT>(_context, name, order));
- }
-
-private:
- /// Helper function that returns the priority value from an input section.
- uint32_t getPriorityFromSectionName(StringRef sectionName) const;
-
-protected:
- llvm::BumpPtrAllocator _allocator;
- SectionMapT _sectionMap;
- OutputSectionMapT _outputSectionMap;
- AdditionalSegmentMapT _additionalSegmentMap;
- SegmentMapT _segmentMap;
- std::vector<Chunk<ELFT> *> _sections;
- std::vector<Segment<ELFT> *> _segments;
- std::vector<OutputSection<ELFT> *> _outputSections;
- ELFHeader<ELFT> *_elfHeader;
- ProgramHeader<ELFT> *_programHeader;
- unique_bump_ptr<RelocationTable<ELFT>> _dynamicRelocationTable;
- unique_bump_ptr<RelocationTable<ELFT>> _pltRelocationTable;
- std::vector<lld::AtomLayout *> _absoluteAtoms;
- AtomSetT _referencedDynAtoms;
- llvm::StringSet<> _copiedDynSymNames;
- ELFLinkingContext &_context;
- script::Sema &_linkerScriptSema;
-};
-
-template <class ELFT>
-Layout::SectionOrder DefaultLayout<ELFT>::getSectionOrder(
- StringRef name, int32_t contentType, int32_t contentPermissions) {
- switch (contentType) {
- case DefinedAtom::typeResolver:
- case DefinedAtom::typeCode:
- return llvm::StringSwitch<Layout::SectionOrder>(name)
- .StartsWith(".eh_frame_hdr", ORDER_EH_FRAMEHDR)
- .StartsWith(".eh_frame", ORDER_EH_FRAME)
- .StartsWith(".init", ORDER_INIT)
- .StartsWith(".fini", ORDER_FINI)
- .StartsWith(".hash", ORDER_HASH)
- .Default(ORDER_TEXT);
-
- case DefinedAtom::typeConstant:
- return ORDER_RODATA;
-
- case DefinedAtom::typeData:
- case DefinedAtom::typeDataFast:
- return llvm::StringSwitch<Layout::SectionOrder>(name)
- .StartsWith(".init_array", ORDER_INIT_ARRAY)
- .StartsWith(".fini_array", ORDER_FINI_ARRAY)
- .StartsWith(".dynamic", ORDER_DYNAMIC)
- .StartsWith(".ctors", ORDER_CTORS)
- .StartsWith(".dtors", ORDER_DTORS)
- .Default(ORDER_DATA);
-
- case DefinedAtom::typeZeroFill:
- case DefinedAtom::typeZeroFillFast:
- return ORDER_BSS;
-
- case DefinedAtom::typeGOT:
- return llvm::StringSwitch<Layout::SectionOrder>(name)
- .StartsWith(".got.plt", ORDER_GOT_PLT)
- .Default(ORDER_GOT);
-
- case DefinedAtom::typeStub:
- return ORDER_PLT;
-
- case DefinedAtom::typeRONote:
- return ORDER_RO_NOTE;
-
- case DefinedAtom::typeRWNote:
- return ORDER_RW_NOTE;
-
- case DefinedAtom::typeNoAlloc:
- return ORDER_NOALLOC;
-
- case DefinedAtom::typeThreadData:
- return ORDER_TDATA;
- case DefinedAtom::typeThreadZeroFill:
- return ORDER_TBSS;
- default:
- // If we get passed in a section push it to OTHER
- if (contentPermissions == DefinedAtom::perm___)
- return ORDER_OTHER;
-
- return ORDER_NOT_DEFINED;
- }
-}
-
-/// \brief This maps the input sections to the output section names
-template <class ELFT>
-StringRef
-DefaultLayout<ELFT>::getInputSectionName(const DefinedAtom *da) const {
- if (da->sectionChoice() == DefinedAtom::sectionBasedOnContent) {
- switch (da->contentType()) {
- case DefinedAtom::typeCode:
- return ".text";
- case DefinedAtom::typeData:
- return ".data";
- case DefinedAtom::typeConstant:
- return ".rodata";
- case DefinedAtom::typeZeroFill:
- return ".bss";
- case DefinedAtom::typeThreadData:
- return ".tdata";
- case DefinedAtom::typeThreadZeroFill:
- return ".tbss";
- default:
- break;
- }
- }
- return da->customSectionName();
-}
-
-/// \brief This maps the input sections to the output section names.
-template <class ELFT>
-StringRef
-DefaultLayout<ELFT>::getOutputSectionName(StringRef archivePath,
- StringRef memberPath,
- StringRef inputSectionName) const {
- StringRef outputSectionName;
- if (_linkerScriptSema.hasLayoutCommands()) {
- script::Sema::SectionKey key = {archivePath, memberPath, inputSectionName};
- outputSectionName = _linkerScriptSema.getOutputSection(key);
- if (!outputSectionName.empty())
- return outputSectionName;
- }
- return llvm::StringSwitch<StringRef>(inputSectionName)
- .StartsWith(".text", ".text")
- .StartsWith(".ctors", ".ctors")
- .StartsWith(".dtors", ".dtors")
- .StartsWith(".rodata", ".rodata")
- .StartsWith(".gcc_except_table", ".gcc_except_table")
- .StartsWith(".data.rel.ro", ".data.rel.ro")
- .StartsWith(".data.rel.local", ".data.rel.local")
- .StartsWith(".data", ".data")
- .StartsWith(".tdata", ".tdata")
- .StartsWith(".tbss", ".tbss")
- .StartsWith(".init_array", ".init_array")
- .StartsWith(".fini_array", ".fini_array")
- .Default(inputSectionName);
-}
-
-/// \brief Gets the segment for a output section
-template <class ELFT>
-Layout::SegmentType DefaultLayout<ELFT>::getSegmentType(
- Section<ELFT> *section) const {
-
- switch (section->order()) {
- case ORDER_INTERP:
- return llvm::ELF::PT_INTERP;
-
- case ORDER_TEXT:
- case ORDER_HASH:
- case ORDER_DYNAMIC_SYMBOLS:
- case ORDER_DYNAMIC_STRINGS:
- case ORDER_DYNAMIC_RELOCS:
- case ORDER_DYNAMIC_PLT_RELOCS:
- case ORDER_REL:
- case ORDER_INIT:
- case ORDER_PLT:
- case ORDER_FINI:
- case ORDER_RODATA:
- case ORDER_EH_FRAME:
- case ORDER_CTORS:
- case ORDER_DTORS:
- return llvm::ELF::PT_LOAD;
-
- case ORDER_RO_NOTE:
- case ORDER_RW_NOTE:
- return llvm::ELF::PT_NOTE;
-
- case ORDER_DYNAMIC:
- return llvm::ELF::PT_DYNAMIC;
-
- case ORDER_EH_FRAMEHDR:
- return llvm::ELF::PT_GNU_EH_FRAME;
-
- case ORDER_GOT:
- case ORDER_GOT_PLT:
- case ORDER_DATA:
- case ORDER_BSS:
- case ORDER_INIT_ARRAY:
- case ORDER_FINI_ARRAY:
- return llvm::ELF::PT_LOAD;
-
- case ORDER_TDATA:
- case ORDER_TBSS:
- return llvm::ELF::PT_TLS;
-
- default:
- return llvm::ELF::PT_NULL;
- }
-}
-
-template <class ELFT>
-bool DefaultLayout<ELFT>::hasOutputSegment(Section<ELFT> *section) {
- switch (section->order()) {
- case ORDER_INTERP:
- case ORDER_HASH:
- case ORDER_DYNAMIC_SYMBOLS:
- case ORDER_DYNAMIC_STRINGS:
- case ORDER_DYNAMIC_RELOCS:
- case ORDER_DYNAMIC_PLT_RELOCS:
- case ORDER_REL:
- case ORDER_INIT:
- case ORDER_PLT:
- case ORDER_TEXT:
- case ORDER_FINI:
- case ORDER_RODATA:
- case ORDER_EH_FRAME:
- case ORDER_EH_FRAMEHDR:
- case ORDER_TDATA:
- case ORDER_TBSS:
- case ORDER_RO_NOTE:
- case ORDER_RW_NOTE:
- case ORDER_DYNAMIC:
- case ORDER_CTORS:
- case ORDER_DTORS:
- case ORDER_GOT:
- case ORDER_GOT_PLT:
- case ORDER_DATA:
- case ORDER_INIT_ARRAY:
- case ORDER_FINI_ARRAY:
- case ORDER_BSS:
- case ORDER_NOALLOC:
- return true;
- default:
- return section->hasOutputSegment();
- }
-}
-
-template <class ELFT>
-AtomSection<ELFT> *DefaultLayout<ELFT>::createSection(
- StringRef sectionName, int32_t contentType,
- DefinedAtom::ContentPermissions permissions, SectionOrder sectionOrder) {
- return new (_allocator) AtomSection<ELFT>(_context, sectionName, contentType,
- permissions, sectionOrder);
-}
-
-template <class ELFT>
-AtomSection<ELFT> *
-DefaultLayout<ELFT>::getSection(StringRef sectionName, int32_t contentType,
- DefinedAtom::ContentPermissions permissions,
- const DefinedAtom *da) {
- const SectionKey sectionKey(sectionName, permissions, da->file().path());
- SectionOrder sectionOrder = getSectionOrder(sectionName, contentType, permissions);
- auto sec = _sectionMap.find(sectionKey);
- if (sec != _sectionMap.end())
- return sec->second;
- AtomSection<ELFT> *newSec =
- createSection(sectionName, contentType, permissions, sectionOrder);
-
- newSec->setOutputSectionName(getOutputSectionName(
- da->file().archivePath(), da->file().memberPath(), sectionName));
- newSec->setOrder(sectionOrder);
- newSec->setArchiveNameOrPath(da->file().archivePath());
- newSec->setMemberNameOrPath(da->file().memberPath());
- _sections.push_back(newSec);
- _sectionMap.insert(std::make_pair(sectionKey, newSec));
- return newSec;
-}
-
-template <class ELFT>
-ErrorOr<const lld::AtomLayout *>
-DefaultLayout<ELFT>::addAtom(const Atom *atom) {
- if (const DefinedAtom *definedAtom = dyn_cast<DefinedAtom>(atom)) {
- // HACK: Ignore undefined atoms. We need to adjust the interface so that
- // undefined atoms can still be included in the output symbol table for
- // -noinhibit-exec.
- if (definedAtom->contentType() == DefinedAtom::typeUnknown)
- return make_error_code(llvm::errc::invalid_argument);
- const DefinedAtom::ContentPermissions permissions =
- definedAtom->permissions();
- const DefinedAtom::ContentType contentType = definedAtom->contentType();
-
- StringRef sectionName = getInputSectionName(definedAtom);
- AtomSection<ELFT> *section =
- getSection(sectionName, contentType, permissions, definedAtom);
-
- // Add runtime relocations to the .rela section.
- for (const auto &reloc : *definedAtom) {
- bool isLocalReloc = true;
- if (_context.isDynamicRelocation(*reloc)) {
- getDynamicRelocationTable()->addRelocation(*definedAtom, *reloc);
- isLocalReloc = false;
- } else if (_context.isPLTRelocation(*reloc)) {
- getPLTRelocationTable()->addRelocation(*definedAtom, *reloc);
- isLocalReloc = false;
- }
-
- if (!reloc->target())
- continue;
-
- //Ignore undefined atoms that are not target of dynamic relocations
- if (isa<UndefinedAtom>(reloc->target()) && isLocalReloc)
- continue;
-
- if (_context.isCopyRelocation(*reloc)) {
- _copiedDynSymNames.insert(definedAtom->name());
- continue;
- }
-
- _referencedDynAtoms.insert(reloc->target());
- }
-
- return section->appendAtom(atom);
- } else if (const AbsoluteAtom *absoluteAtom = dyn_cast<AbsoluteAtom>(atom)) {
- // Absolute atoms are not part of any section, they are global for the whole
- // link
- _absoluteAtoms.push_back(new (_allocator)
- lld::AtomLayout(absoluteAtom, 0, absoluteAtom->value()));
- return _absoluteAtoms.back();
- } else {
- llvm_unreachable("Only absolute / defined atoms can be added here");
- }
-}
-
-/// Output sections with the same name into a OutputSection
-template <class ELFT> void DefaultLayout<ELFT>::createOutputSections() {
- OutputSection<ELFT> *outputSection;
-
- for (auto &si : _sections) {
- Section<ELFT> *section = dyn_cast<Section<ELFT>>(si);
- if (!section)
- continue;
- const std::pair<StringRef, OutputSection<ELFT> *> currentOutputSection(
- section->outputSectionName(), nullptr);
- std::pair<typename OutputSectionMapT::iterator, bool> outputSectionInsert(
- _outputSectionMap.insert(currentOutputSection));
- if (!outputSectionInsert.second) {
- outputSection = outputSectionInsert.first->second;
- } else {
- outputSection = new (_allocator.Allocate<OutputSection<ELFT>>())
- OutputSection<ELFT>(section->outputSectionName());
- _outputSections.push_back(outputSection);
- outputSectionInsert.first->second = outputSection;
- }
- outputSection->appendSection(si);
- }
-}
-
-template <class ELFT>
-uint32_t
-DefaultLayout<ELFT>::getPriorityFromSectionName(StringRef sectionName) const {
- StringRef priority = sectionName.drop_front().rsplit('.').second;
- uint32_t prio;
- if (priority.getAsInteger(10, prio))
- return std::numeric_limits<uint32_t>::max();
- return prio;
-}
-
-template <class ELFT>
-void DefaultLayout<ELFT>::sortOutputSectionByPriority(
- StringRef outputSectionName, StringRef prefix) {
- OutputSection<ELFT> *outputSection = findOutputSection(outputSectionName);
- if (!outputSection)
- return;
-
- auto sections = outputSection->sections();
-
- std::sort(sections.begin(), sections.end(),
- [&](Chunk<ELFT> *lhs, Chunk<ELFT> *rhs) {
- Section<ELFT> *lhsSection = dyn_cast<Section<ELFT>>(lhs);
- Section<ELFT> *rhsSection = dyn_cast<Section<ELFT>>(rhs);
- if (!lhsSection || !rhsSection)
- return false;
- StringRef lhsSectionName = lhsSection->inputSectionName();
- StringRef rhsSectionName = rhsSection->inputSectionName();
-
- if (!prefix.empty()) {
- if (!lhsSectionName.startswith(prefix) ||
- !rhsSectionName.startswith(prefix))
- return false;
- }
- return getPriorityFromSectionName(lhsSectionName) <
- getPriorityFromSectionName(rhsSectionName);
- });
-}
-
-template <class ELFT> void DefaultLayout<ELFT>::assignSectionsToSegments() {
- ScopedTask task(getDefaultDomain(), "assignSectionsToSegments");
- ELFLinkingContext::OutputMagic outputMagic = _context.getOutputMagic();
- // sort the sections by their order as defined by the layout
- sortInputSections();
-
- // Create output sections.
- createOutputSections();
-
- // Finalize output section layout.
- finalizeOutputSectionLayout();
-
- // Set the ordinal after sorting the sections
- int ordinal = 1;
- for (auto osi : _outputSections) {
- osi->setOrdinal(ordinal);
- for (auto ai : osi->sections()) {
- ai->setOrdinal(ordinal);
- }
- ++ordinal;
- }
- for (auto osi : _outputSections) {
- for (auto ai : osi->sections()) {
- if (auto section = dyn_cast<Section<ELFT> >(ai)) {
- if (!hasOutputSegment(section))
- continue;
-
- osi->setLoadableSection(section->isLoadableSection());
-
- // Get the segment type for the section
- int64_t segmentType = getSegmentType(section);
-
- osi->setHasSegment();
- section->setSegmentType(segmentType);
- StringRef segmentName = section->segmentKindToStr();
-
- int64_t lookupSectionFlag = osi->flags();
- if ((!(lookupSectionFlag & llvm::ELF::SHF_WRITE)) &&
- (_context.mergeRODataToTextSegment()))
- lookupSectionFlag &= ~llvm::ELF::SHF_EXECINSTR;
-
- // Merge string sections into Data segment itself
- lookupSectionFlag &= ~(llvm::ELF::SHF_STRINGS | llvm::ELF::SHF_MERGE);
-
- // Merge the TLS section into the DATA segment itself
- lookupSectionFlag &= ~(llvm::ELF::SHF_TLS);
-
- Segment<ELFT> *segment;
- // We need a separate segment for sections that don't have
- // the segment type to be PT_LOAD
- if (segmentType != llvm::ELF::PT_LOAD) {
- const AdditionalSegmentKey key(segmentType, lookupSectionFlag);
- const std::pair<AdditionalSegmentKey, Segment<ELFT> *>
- additionalSegment(key, nullptr);
- std::pair<typename AdditionalSegmentMapT::iterator, bool>
- additionalSegmentInsert(
- _additionalSegmentMap.insert(additionalSegment));
- if (!additionalSegmentInsert.second) {
- segment = additionalSegmentInsert.first->second;
- } else {
- segment = new (_allocator)
- Segment<ELFT>(_context, segmentName, segmentType);
- additionalSegmentInsert.first->second = segment;
- _segments.push_back(segment);
- }
- segment->append(section);
- }
- if (segmentType == llvm::ELF::PT_NULL)
- continue;
-
- // If the output magic is set to OutputMagic::NMAGIC or
- // OutputMagic::OMAGIC, Place the data alongside text in one single
- // segment
- if (outputMagic == ELFLinkingContext::OutputMagic::NMAGIC ||
- outputMagic == ELFLinkingContext::OutputMagic::OMAGIC)
- lookupSectionFlag = llvm::ELF::SHF_EXECINSTR | llvm::ELF::SHF_ALLOC |
- llvm::ELF::SHF_WRITE;
-
- // Use the flags of the merged Section for the segment
- const SegmentKey key("PT_LOAD", lookupSectionFlag);
- const std::pair<SegmentKey, Segment<ELFT> *> currentSegment(key,
- nullptr);
- std::pair<typename SegmentMapT::iterator, bool> segmentInsert(
- _segmentMap.insert(currentSegment));
- if (!segmentInsert.second) {
- segment = segmentInsert.first->second;
- } else {
- segment = new (_allocator)
- Segment<ELFT>(_context, "PT_LOAD", llvm::ELF::PT_LOAD);
- segmentInsert.first->second = segment;
- _segments.push_back(segment);
- }
- // Insert chunks with linker script expressions that occur at this
- // point, just before appending a new input section
- addExtraChunksToSegment(segment, section->archivePath(),
- section->memberPath(),
- section->inputSectionName());
- segment->append(section);
- }
- }
- }
- if (_context.isDynamic() && !_context.isDynamicLibrary()) {
- Segment<ELFT> *segment =
- new (_allocator) ProgramHeaderSegment<ELFT>(_context);
- _segments.push_back(segment);
- segment->append(_elfHeader);
- segment->append(_programHeader);
- }
-}
-
-template<class ELFT>
-void
-DefaultLayout<ELFT>::assignVirtualAddress() {
- if (_segments.empty())
- return;
-
- std::sort(_segments.begin(), _segments.end(), Segment<ELFT>::compareSegments);
-
- uint64_t baseAddress = _context.getBaseAddress();
-
- // HACK: This is a super dirty hack. The elf header and program header are
- // not part of a section, but we need them to be loaded at the base address
- // so that AT_PHDR is set correctly by the loader and so they are accessible
- // at runtime. To do this we simply prepend them to the first loadable Segment
- // and let the layout logic take care of it.
- Segment<ELFT> *firstLoadSegment = nullptr;
- for (auto si : _segments) {
- if (si->segmentType() == llvm::ELF::PT_LOAD) {
- firstLoadSegment = si;
- si->firstSection()->setAlign(si->alignment());
- break;
- }
- }
- assert(firstLoadSegment != nullptr && "No loadable segment!");
- firstLoadSegment->prepend(_programHeader);
- firstLoadSegment->prepend(_elfHeader);
- bool newSegmentHeaderAdded = true;
- bool virtualAddressAssigned = false;
- bool fileOffsetAssigned = false;
- while (true) {
- for (auto si : _segments) {
- si->finalize();
- // Don't add PT_NULL segments into the program header
- if (si->segmentType() != llvm::ELF::PT_NULL)
- newSegmentHeaderAdded = _programHeader->addSegment(si);
- }
- if (!newSegmentHeaderAdded && virtualAddressAssigned)
- break;
- uint64_t address = baseAddress;
- // start assigning virtual addresses
- for (auto &si : _segments) {
- if ((si->segmentType() != llvm::ELF::PT_LOAD) &&
- (si->segmentType() != llvm::ELF::PT_NULL))
- continue;
-
- if (si->segmentType() == llvm::ELF::PT_NULL) {
- si->assignVirtualAddress(0 /*non loadable*/);
- } else {
- if (virtualAddressAssigned && (address != baseAddress) &&
- (address == si->virtualAddr()))
- break;
- si->assignVirtualAddress(address);
- }
- address = si->virtualAddr() + si->memSize();
- }
- uint64_t baseFileOffset = 0;
- uint64_t fileoffset = baseFileOffset;
- for (auto &si : _segments) {
- if ((si->segmentType() != llvm::ELF::PT_LOAD) &&
- (si->segmentType() != llvm::ELF::PT_NULL))
- continue;
- if (fileOffsetAssigned && (fileoffset != baseFileOffset) &&
- (fileoffset == si->fileOffset()))
- break;
- si->assignFileOffsets(fileoffset);
- fileoffset = si->fileOffset() + si->fileSize();
- }
- virtualAddressAssigned = true;
- fileOffsetAssigned = true;
- _programHeader->resetProgramHeaders();
- }
- Section<ELFT> *section;
- // Fix the offsets of all the atoms within a section
- for (auto &si : _sections) {
- section = dyn_cast<Section<ELFT>>(si);
- if (section && DefaultLayout<ELFT>::hasOutputSegment(section))
- section->assignFileOffsets(section->fileOffset());
- }
- // Set the size of the merged Sections
- for (auto osi : _outputSections) {
- uint64_t sectionfileoffset = 0;
- uint64_t startFileOffset = 0;
- uint64_t sectionsize = 0;
- bool isFirstSection = true;
- for (auto si : osi->sections()) {
- if (isFirstSection) {
- startFileOffset = si->fileOffset();
- isFirstSection = false;
- }
- sectionfileoffset = si->fileOffset();
- sectionsize = si->fileSize();
- }
- sectionsize = (sectionfileoffset - startFileOffset) + sectionsize;
- osi->setFileOffset(startFileOffset);
- osi->setSize(sectionsize);
- }
- // Set the virtual addr of the merged Sections
- for (auto osi : _outputSections) {
- uint64_t sectionstartaddr = 0;
- uint64_t startaddr = 0;
- uint64_t sectionsize = 0;
- bool isFirstSection = true;
- for (auto si : osi->sections()) {
- if (isFirstSection) {
- startaddr = si->virtualAddr();
- isFirstSection = false;
- }
- sectionstartaddr = si->virtualAddr();
- sectionsize = si->memSize();
- }
- sectionsize = (sectionstartaddr - startaddr) + sectionsize;
- osi->setMemSize(sectionsize);
- osi->setAddr(startaddr);
- }
-}
-
-template <class ELFT>
-void DefaultLayout<ELFT>::assignFileOffsetsForMiscSections() {
- uint64_t fileoffset = 0;
- uint64_t size = 0;
- for (auto si : _segments) {
- // Don't calculate offsets from non loadable segments
- if ((si->segmentType() != llvm::ELF::PT_LOAD) &&
- (si->segmentType() != llvm::ELF::PT_NULL))
- continue;
- fileoffset = si->fileOffset();
- size = si->fileSize();
- }
- fileoffset = fileoffset + size;
- Section<ELFT> *section;
- for (auto si : _sections) {
- section = dyn_cast<Section<ELFT>>(si);
- if (section && DefaultLayout<ELFT>::hasOutputSegment(section))
- continue;
- fileoffset = llvm::RoundUpToAlignment(fileoffset, si->alignment());
- si->setFileOffset(fileoffset);
- si->setVirtualAddr(0);
- fileoffset += si->fileSize();
- }
-}
-
-template <class ELFT> void DefaultLayout<ELFT>::sortInputSections() {
- // First, sort according to default layout's order
- std::stable_sort(
- _sections.begin(), _sections.end(),
- [](Chunk<ELFT> *A, Chunk<ELFT> *B) { return A->order() < B->order(); });
-
- if (!_linkerScriptSema.hasLayoutCommands())
- return;
-
- // Sort the sections by their order as defined by the linker script
- std::stable_sort(this->_sections.begin(), this->_sections.end(),
- [this](Chunk<ELFT> *A, Chunk<ELFT> *B) {
- auto *a = dyn_cast<Section<ELFT>>(A);
- auto *b = dyn_cast<Section<ELFT>>(B);
-
- if (a == nullptr)
- return false;
- if (b == nullptr)
- return true;
-
- return _linkerScriptSema.less(
- {a->archivePath(), a->memberPath(),
- a->inputSectionName()},
- {b->archivePath(), b->memberPath(),
- b->inputSectionName()});
- });
- // Now try to arrange sections with no mapping rules to sections with
- // similar content
- auto p = this->_sections.begin();
- // Find first section that has no assigned rule id
- while (p != this->_sections.end()) {
- auto *sect = dyn_cast<AtomSection<ELFT>>(*p);
- if (!sect)
- break;
-
- if (!_linkerScriptSema.hasMapping({sect->archivePath(),
- sect->memberPath(),
- sect->inputSectionName()}))
- break;
-
- ++p;
- }
- // For all sections that have no assigned rule id, try to move them near a
- // section with similar contents
- if (p != this->_sections.begin()) {
- for (; p != this->_sections.end(); ++p) {
- auto q = p;
- --q;
- while (q != this->_sections.begin() &&
- (*q)->getContentType() != (*p)->getContentType())
- --q;
- if ((*q)->getContentType() != (*p)->getContentType())
- continue;
- ++q;
- for (auto i = p; i != q;) {
- auto next = i--;
- std::iter_swap(i, next);
- }
- }
- }
-}
-
-template <class ELFT>
-void DefaultLayout<ELFT>::addExtraChunksToSegment(Segment<ELFT> *segment,
- StringRef archivePath,
- StringRef memberPath,
- StringRef sectionName) {
- if (!_linkerScriptSema.hasLayoutCommands())
- return;
-
- std::vector<const script::SymbolAssignment *> exprs =
- _linkerScriptSema.getExprs({archivePath, memberPath, sectionName});
- for (auto expr : exprs) {
- auto expChunk =
- new (this->_allocator) ExpressionChunk<ELFT>(this->_context, expr);
- segment->append(expChunk);
- }
-}
-
-} // end namespace elf
-} // end namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/ELF/DefaultTargetHandler.h b/lib/ReaderWriter/ELF/DefaultTargetHandler.h
deleted file mode 100644
index 16668f2df618..000000000000
--- a/lib/ReaderWriter/ELF/DefaultTargetHandler.h
+++ /dev/null
@@ -1,38 +0,0 @@
-//===- lib/ReaderWriter/ELF/DefaultTargetHandler.h ------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_ELF_DEFAULT_TARGET_HANDLER_H
-#define LLD_READER_WRITER_ELF_DEFAULT_TARGET_HANDLER_H
-
-#include "DefaultLayout.h"
-#include "DynamicLibraryWriter.h"
-#include "ELFReader.h"
-#include "ExecutableWriter.h"
-#include "TargetHandler.h"
-#include "lld/ReaderWriter/ELFLinkingContext.h"
-#include "llvm/ADT/Triple.h"
-#include "llvm/Support/ELF.h"
-
-namespace lld {
-namespace elf {
-template <class ELFT>
-class DefaultTargetHandler : public TargetHandler<ELFT> {
-public:
- const TargetRelocationHandler &getRelocationHandler() const = 0;
-
- virtual std::unique_ptr<Reader> getObjReader() = 0;
-
- virtual std::unique_ptr<Reader> getDSOReader() = 0;
-
- virtual std::unique_ptr<Writer> getWriter() = 0;
-};
-
-} // end namespace elf
-} // end namespace lld
-#endif
diff --git a/lib/ReaderWriter/ELF/DynamicFile.cpp b/lib/ReaderWriter/ELF/DynamicFile.cpp
new file mode 100644
index 000000000000..5339c7d66577
--- /dev/null
+++ b/lib/ReaderWriter/ELF/DynamicFile.cpp
@@ -0,0 +1,146 @@
+//===- 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
index c4e3e7165efd..a155900de781 100644
--- a/lib/ReaderWriter/ELF/DynamicFile.h
+++ b/lib/ReaderWriter/ELF/DynamicFile.h
@@ -12,96 +12,39 @@
#include "Atoms.h"
#include "lld/Core/SharedLibraryFile.h"
-#include "lld/ReaderWriter/ELFLinkingContext.h"
-#include "llvm/Object/ELF.h"
-#include "llvm/Support/Path.h"
#include <unordered_map>
namespace lld {
+class ELFLinkingContext;
+
namespace elf {
+
template <class ELFT> class DynamicFile : public SharedLibraryFile {
public:
- static ErrorOr<std::unique_ptr<DynamicFile>>
- create(std::unique_ptr<llvm::MemoryBuffer> mb, ELFLinkingContext &ctx);
-
- const SharedLibraryAtom *exports(StringRef name,
- bool dataSymbolOnly) const override {
- assert(!dataSymbolOnly && "Invalid option for ELF exports!");
- // See if we have the symbol.
- auto sym = _nameToSym.find(name);
- if (sym == _nameToSym.end())
- return nullptr;
- // Have we already created a SharedLibraryAtom for it?
- if (sym->second._atom)
- return sym->second._atom;
- // Create a SharedLibraryAtom for this symbol.
- return sym->second._atom = new (_alloc) ELFDynamicAtom<ELFT>(
- *this, name, _soname, sym->second._symbol);
- }
-
- StringRef getDSOName() const override { return _soname; }
-
-protected:
- std::error_code doParse() override {
- std::error_code ec;
- _objFile.reset(
- new llvm::object::ELFFile<ELFT>(_mb->getBuffer(), ec));
- if (ec)
- return ec;
-
- llvm::object::ELFFile<ELFT> &obj = *_objFile;
+ DynamicFile(std::unique_ptr<MemoryBuffer> mb, ELFLinkingContext &ctx);
- _soname = obj.getLoadName();
- if (_soname.empty())
- _soname = llvm::sys::path::filename(path());
+ static std::error_code isCompatible(MemoryBufferRef mb,
+ ELFLinkingContext &ctx);
- // Create a map from names to dynamic symbol table entries.
- // TODO: This should use the object file's build in hash table instead if
- // it exists.
- for (auto i = obj.begin_dynamic_symbols(), e = obj.end_dynamic_symbols();
- i != e; ++i) {
- auto name = obj.getSymbolName(i);
- if ((ec = name.getError()))
- return ec;
+ const SharedLibraryAtom *exports(StringRef name,
+ bool dataSymbolOnly) const override;
- // 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;
+ StringRef getDSOName() const override;
- // TODO: Add absolute symbols
- if (i->st_shndx == llvm::ELF::SHN_ABS)
- continue;
+ static bool canParse(file_magic magic);
- if (i->st_shndx == llvm::ELF::SHN_UNDEF) {
- if (!_useShlibUndefines)
- continue;
- // Create an undefined atom.
- if (!name->empty()) {
- auto *newAtom = new (_alloc) ELFUndefinedAtom<ELFT>(*this, *name, &*i);
- _undefinedAtoms._atoms.push_back(newAtom);
- }
- continue;
- }
- _nameToSym[*name]._symbol = &*i;
- }
- return std::error_code();
- }
+protected:
+ std::error_code doParse() override;
private:
- DynamicFile(std::unique_ptr<MemoryBuffer> mb, ELFLinkingContext &ctx)
- : SharedLibraryFile(mb->getBufferIdentifier()), _mb(std::move(mb)),
- _ctx(ctx), _useShlibUndefines(ctx.useShlibUndefines()) {}
-
mutable llvm::BumpPtrAllocator _alloc;
std::unique_ptr<llvm::object::ELFFile<ELFT>> _objFile;
/// \brief DT_SONAME
StringRef _soname;
struct SymAtomPair {
- SymAtomPair() : _symbol(nullptr), _atom(nullptr) {}
- const typename llvm::object::ELFFile<ELFT>::Elf_Sym *_symbol;
- const SharedLibraryAtom *_atom;
+ const typename llvm::object::ELFFile<ELFT>::Elf_Sym *_symbol = nullptr;
+ const SharedLibraryAtom *_atom = nullptr;
};
std::unique_ptr<MemoryBuffer> _mb;
@@ -110,13 +53,6 @@ private:
mutable std::unordered_map<StringRef, SymAtomPair> _nameToSym;
};
-template <class ELFT>
-ErrorOr<std::unique_ptr<DynamicFile<ELFT>>>
-DynamicFile<ELFT>::create(std::unique_ptr<llvm::MemoryBuffer> mb,
- ELFLinkingContext &ctx) {
- return std::unique_ptr<DynamicFile>(new DynamicFile(std::move(mb), ctx));
-}
-
} // end namespace elf
} // end namespace lld
diff --git a/lib/ReaderWriter/ELF/DynamicLibraryWriter.h b/lib/ReaderWriter/ELF/DynamicLibraryWriter.h
index f97514b525c0..5f2c1d1a8288 100644
--- a/lib/ReaderWriter/ELF/DynamicLibraryWriter.h
+++ b/lib/ReaderWriter/ELF/DynamicLibraryWriter.h
@@ -16,27 +16,19 @@ namespace elf {
using namespace llvm;
using namespace llvm::object;
-template<class ELFT>
-class DynamicLibraryWriter;
-
//===----------------------------------------------------------------------===//
// DynamicLibraryWriter Class
//===----------------------------------------------------------------------===//
template<class ELFT>
class DynamicLibraryWriter : public OutputELFWriter<ELFT> {
public:
- DynamicLibraryWriter(ELFLinkingContext &context, TargetLayout<ELFT> &layout)
- : OutputELFWriter<ELFT>(context, layout),
- _runtimeFile(new RuntimeFile<ELFT>(context, "C runtime")) {}
-
-protected:
- virtual void buildDynamicSymbolTable(const File &file);
- virtual void addDefaultAtoms();
- virtual bool createImplicitFiles(std::vector<std::unique_ptr<File> > &);
- virtual void finalizeDefaultAtomValues();
+ DynamicLibraryWriter(ELFLinkingContext &ctx, TargetLayout<ELFT> &layout)
+ : OutputELFWriter<ELFT>(ctx, layout) {}
protected:
- std::unique_ptr<RuntimeFile<ELFT> > _runtimeFile;
+ void buildDynamicSymbolTable(const File &file) override;
+ void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
+ void finalizeDefaultAtomValues() override;
};
//===----------------------------------------------------------------------===//
@@ -62,30 +54,28 @@ void DynamicLibraryWriter<ELFT>::buildDynamicSymbolTable(const File &file) {
OutputELFWriter<ELFT>::buildDynamicSymbolTable(file);
}
-template <class ELFT> void DynamicLibraryWriter<ELFT>::addDefaultAtoms() {
- _runtimeFile->addAbsoluteAtom("_end");
-}
-
/// \brief Hook in lld to add CRuntime file
template <class ELFT>
-bool DynamicLibraryWriter<ELFT>::createImplicitFiles(
+void DynamicLibraryWriter<ELFT>::createImplicitFiles(
std::vector<std::unique_ptr<File> > &result) {
- // Add the default atoms as defined by executables
- DynamicLibraryWriter<ELFT>::addDefaultAtoms();
OutputELFWriter<ELFT>::createImplicitFiles(result);
- result.push_back(std::move(_runtimeFile));
- return true;
+ // 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() {
- auto underScoreEndAtomIter = this->_layout.findAbsoluteAtom("_end");
+ OutputELFWriter<ELFT>::finalizeDefaultAtomValues();
+ AtomLayout *underScoreEndAtom = this->_layout.findAbsoluteAtom("_end");
+ assert(underScoreEndAtom);
if (auto bssSection = this->_layout.findOutputSection(".bss")) {
- (*underScoreEndAtomIter)->_virtualAddr =
+ underScoreEndAtom->_virtualAddr =
bssSection->virtualAddr() + bssSection->memSize();
} else if (auto dataSection = this->_layout.findOutputSection(".data")) {
- (*underScoreEndAtomIter)->_virtualAddr =
+ underScoreEndAtom->_virtualAddr =
dataSection->virtualAddr() + dataSection->memSize();
}
}
diff --git a/lib/ReaderWriter/ELF/ELFFile.cpp b/lib/ReaderWriter/ELF/ELFFile.cpp
new file mode 100644
index 000000000000..1488f1862b8d
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ELFFile.cpp
@@ -0,0 +1,829 @@
+//===- 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
index 11f4ee4fc633..5e0c2fc75a87 100644
--- a/lib/ReaderWriter/ELF/ELFFile.h
+++ b/lib/ReaderWriter/ELF/ELFFile.h
@@ -1,4 +1,4 @@
-//===- lib/ReaderWriter/ELF/ELFFile.h -------------------------------------===//
+//===- lib/ReaderWriter/ELF/ELFFile.h ---------------------------*- C++ -*-===//
//
// The LLVM Linker
//
@@ -11,7 +11,8 @@
#define LLD_READER_WRITER_ELF_FILE_H
#include "Atoms.h"
-#include <llvm/ADT/MapVector.h>
+#include "FileCommon.h"
+#include "llvm/ADT/MapVector.h"
#include <map>
#include <unordered_map>
@@ -20,26 +21,20 @@ namespace lld {
namespace elf {
/// \brief Read a binary, find out based on the symbol table contents what kind
/// of symbol it is and create corresponding atoms for it
-template <class ELFT> class ELFFile : public File {
-
+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_Sym_Iter Elf_Sym_Iter;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela_Iter Elf_Rela_Iter;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel_Iter Elf_Rel_Iter;
typedef typename llvm::object::ELFFile<ELFT>::Elf_Word Elf_Word;
// A Map is used to hold the atoms that have been divided up
// after reading the section that contains Merge String attributes
struct MergeSectionKey {
- MergeSectionKey(const Elf_Shdr *shdr, int64_t offset)
- : _shdr(shdr), _offset(offset) {}
- // Data members
const Elf_Shdr *_shdr;
int64_t _offset;
};
+
struct MergeSectionEq {
int64_t operator()(const MergeSectionKey &k) const {
return llvm::hash_combine((int64_t)(k._shdr->sh_name),
@@ -71,23 +66,15 @@ template <class ELFT> class ELFFile : public File {
// offset
typedef std::vector<ELFMergeAtom<ELFT> *> MergeAtomsT;
- /// \brief find a mergeAtom given a start offset
- struct FindByOffset {
- const Elf_Shdr *_shdr;
- int64_t _offset;
- FindByOffset(const Elf_Shdr *shdr, int64_t offset)
- : _shdr(shdr), _offset(offset) {}
- bool operator()(const ELFMergeAtom<ELFT> *a) {
- int64_t off = a->offset();
- return (_shdr->sh_name == a->section()) &&
- ((_offset >= off) && (_offset <= off + (int64_t)a->size()));
- }
- };
-
/// \brief find a merge atom given a offset
- ELFMergeAtom<ELFT> *findMergeAtom(const Elf_Shdr *shdr, uint64_t offset) {
+ ELFMergeAtom<ELFT> *findMergeAtom(const Elf_Shdr *shdr, int64_t offset) {
auto it = std::find_if(_mergeAtoms.begin(), _mergeAtoms.end(),
- FindByOffset(shdr, offset));
+ [=](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;
}
@@ -97,19 +84,15 @@ template <class ELFT> class ELFFile : public File {
typedef typename MergedSectionMapT::iterator MergedSectionMapIterT;
public:
- ELFFile(StringRef name, ELFLinkingContext &ctx)
- : File(name, kindObject), _ordinal(0),
- _doStringsMerge(ctx.mergeCommonStrings()), _useWrap(false), _ctx(ctx) {
- setLastError(std::error_code());
- }
+ ELFFile(StringRef name, ELFLinkingContext &ctx);
+ ELFFile(std::unique_ptr<MemoryBuffer> mb, ELFLinkingContext &ctx);
- ELFFile(std::unique_ptr<MemoryBuffer> mb, ELFLinkingContext &ctx)
- : File(mb->getBufferIdentifier(), kindObject), _mb(std::move(mb)),
- _ordinal(0), _doStringsMerge(ctx.mergeCommonStrings()),
- _useWrap(ctx.wrapCalls().size()), _ctx(ctx) {}
+ static std::error_code isCompatible(MemoryBufferRef mb,
+ ELFLinkingContext &ctx);
- static ErrorOr<std::unique_ptr<ELFFile>>
- create(std::unique_ptr<MemoryBuffer> mb, ELFLinkingContext &ctx);
+ static bool canParse(file_magic magic) {
+ return magic == file_magic::elf_relocatable;
+ }
virtual Reference::KindArch kindArch();
@@ -132,41 +115,14 @@ public:
/// \brief Create individual atoms
std::error_code createAtoms();
- const atom_collection<DefinedAtom> &defined() const override {
- return _definedAtoms;
- }
-
- const atom_collection<UndefinedAtom> &undefined() const override {
- return _undefinedAtoms;
- }
-
- const atom_collection<SharedLibraryAtom> &sharedLibrary() const override {
- return _sharedLibraryAtoms;
- }
-
- const atom_collection<AbsoluteAtom> &absolute() const override {
- return _absoluteAtoms;
- }
-
- Atom *findAtom(const Elf_Sym *sourceSymbol, const Elf_Sym *targetSymbol) {
- // All references to atoms inside a group are through undefined atoms.
- Atom *targetAtom = _symbolToAtomMapping.lookup(targetSymbol);
- StringRef targetSymbolName = targetAtom->name();
- if (targetAtom->definition() != Atom::definitionRegular)
- return targetAtom;
- if ((llvm::dyn_cast<DefinedAtom>(targetAtom))->scope() ==
- DefinedAtom::scopeTranslationUnit)
- return targetAtom;
- if (!redirectReferenceUsingUndefAtom(sourceSymbol, targetSymbol))
- return targetAtom;
- auto undefForGroupchild = _undefAtomsForGroupChild.find(targetSymbolName);
- if (undefForGroupchild != _undefAtomsForGroupChild.end())
- return undefForGroupchild->getValue();
- auto undefGroupChildAtom =
- new (_readerStorage) SimpleUndefinedAtom(*this, targetSymbolName);
- _undefinedAtoms._atoms.push_back(undefGroupChildAtom);
- return (_undefAtomsForGroupChild[targetSymbolName] = undefGroupChildAtom);
- }
+ // 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(
@@ -179,13 +135,13 @@ protected:
/// \brief Iterate over Elf_Rela relocations list and create references.
virtual void createRelocationReferences(const Elf_Sym *symbol,
ArrayRef<uint8_t> content,
- range<Elf_Rela_Iter> rels);
+ 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,
- range<Elf_Rel_Iter> rels);
+ 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.
@@ -224,11 +180,7 @@ protected:
uint32_t edgeKind);
/// Get the section name for a section.
- ErrorOr<StringRef> getSectionName(const Elf_Shdr *shdr) const {
- if (!shdr)
- return StringRef();
- return _objFile->getSectionName(shdr);
- }
+ ErrorOr<StringRef> getSectionName(const Elf_Shdr *shdr) const;
/// Determines if the section occupy memory space.
bool sectionOccupiesMemorySpace(const Elf_Shdr *shdr) const {
@@ -242,45 +194,38 @@ protected:
return _objFile->getSectionContents(shdr);
}
- /// Returns true if the symbol is a undefined symbol.
- bool isUndefinedSymbol(const Elf_Sym *sym) const {
- return (sym->st_shndx == llvm::ELF::SHN_UNDEF);
- }
-
/// Determines if the target wants to create an atom for a section that has no
/// symbol references.
- bool handleSectionWithNoSymbols(const Elf_Shdr *shdr,
- std::vector<Elf_Sym_Iter> &syms) const {
- return shdr && (shdr->sh_type == llvm::ELF::SHT_PROGBITS) && syms.empty();
+ 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(
- StringRef sectionName,
- llvm::StringMap<std::vector<ELFDefinedAtom<ELFT> *>> &atomsForSection,
- const Elf_Shdr *shdr);
+ const Elf_Shdr *section,
+ llvm::StringMap<std::vector<ELFDefinedAtom<ELFT> *>> &atomsForSection);
- // Handle Section groups/COMDAT scetions.
+ // Handle COMDAT scetions.
std::error_code handleSectionGroup(
- StringRef signature, StringRef groupSectionName,
- llvm::StringMap<std::vector<ELFDefinedAtom<ELFT> *>> &atomsForSection,
- llvm::DenseMap<const Elf_Shdr *, std::vector<StringRef>> &comdatSections,
- const Elf_Shdr *shdr);
+ const Elf_Shdr *section,
+ llvm::StringMap<std::vector<ELFDefinedAtom<ELFT> *>> &atomsForSection);
/// Process the Undefined symbol and create an atom for it.
- ErrorOr<ELFUndefinedAtom<ELFT> *>
- handleUndefinedSymbol(StringRef symName, const Elf_Sym *sym) {
+ ELFUndefinedAtom<ELFT> *createUndefinedAtom(StringRef symName,
+ const Elf_Sym *sym) {
return new (_readerStorage) ELFUndefinedAtom<ELFT>(*this, symName, sym);
}
- /// Returns true if the symbol is a absolute symbol.
- bool isAbsoluteSymbol(const Elf_Sym *sym) const {
- return (sym->st_shndx == llvm::ELF::SHN_ABS);
- }
-
/// Process the Absolute symbol and create an atom for it.
- ErrorOr<ELFAbsoluteAtom<ELFT> *>
- handleAbsoluteSymbol(StringRef symName, const Elf_Sym *sym, int64_t value) {
+ ELFAbsoluteAtom<ELFT> *createAbsoluteAtom(StringRef symName,
+ const Elf_Sym *sym, int64_t value) {
return new (_readerStorage)
ELFAbsoluteAtom<ELFT>(*this, symName, sym, value);
}
@@ -316,42 +261,39 @@ protected:
return symbol->st_value;
}
- /// Process the common symbol and create an atom for it.
- virtual ErrorOr<ELFCommonAtom<ELFT> *>
- handleCommonSymbol(StringRef symName, const Elf_Sym *sym) {
- return new (_readerStorage) ELFCommonAtom<ELFT>(*this, symName, sym);
+ /// Returns 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);
}
- /// Returns true if the symbol is a defined symbol.
- virtual bool isDefinedSymbol(const Elf_Sym *sym) const {
- return (sym->getType() == llvm::ELF::STT_NOTYPE ||
- sym->getType() == llvm::ELF::STT_OBJECT ||
- sym->getType() == llvm::ELF::STT_FUNC ||
- sym->getType() == llvm::ELF::STT_GNU_IFUNC ||
- sym->getType() == llvm::ELF::STT_SECTION ||
- sym->getType() == llvm::ELF::STT_FILE ||
- sym->getType() == llvm::ELF::STT_TLS);
+ /// Process the 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);
}
- /// Process the Defined symbol and create an atom for it.
- virtual ErrorOr<ELFDefinedAtom<ELFT> *>
- handleDefinedSymbol(StringRef symName, StringRef sectionName,
- const Elf_Sym *sym, const Elf_Shdr *sectionHdr,
- ArrayRef<uint8_t> contentData,
- unsigned int referenceStart, unsigned int referenceEnd,
- std::vector<ELFReference<ELFT> *> &referenceList) {
+ /// 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.
- ErrorOr<ELFMergeAtom<ELFT> *>
- handleMergeString(StringRef sectionName, const Elf_Shdr *sectionHdr,
- ArrayRef<uint8_t> contentData, unsigned int offset) {
- ELFMergeAtom<ELFT> *mergeAtom = new (_readerStorage)
+ 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);
+ const MergeSectionKey mergedSectionKey = {sectionHdr, offset};
if (_mergedSectionMap.find(mergedSectionKey) == _mergedSectionMap.end())
_mergedSectionMap.insert(std::make_pair(mergedSectionKey, mergeAtom));
return mergeAtom;
@@ -380,19 +322,17 @@ protected:
llvm::BumpPtrAllocator _readerStorage;
std::unique_ptr<llvm::object::ELFFile<ELFT> > _objFile;
- atom_collection_vector<DefinedAtom> _definedAtoms;
- atom_collection_vector<UndefinedAtom> _undefinedAtoms;
- atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
- atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
+ 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<StringRef, range<Elf_Rela_Iter>>
- _relocationAddendReferences;
+ std::unordered_map<const Elf_Shdr *, range<const Elf_Rela *>>
+ _relocationAddendReferences;
MergedSectionMapT _mergedSectionMap;
- std::unordered_map<StringRef, range<Elf_Rel_Iter>> _relocationReferences;
+ 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 *>
@@ -409,7 +349,8 @@ protected:
/// \brief the section and the symbols that are contained within it to create
/// used to create atoms
- llvm::MapVector<const Elf_Shdr *, std::vector<Elf_Sym_Iter>> _sectionSymbols;
+ llvm::MapVector<const Elf_Shdr *, std::vector<const Elf_Sym *>>
+ _sectionSymbols;
/// \brief Sections that have merge string property
std::vector<const Elf_Shdr *> _mergeStringSections;
@@ -438,741 +379,16 @@ protected:
template <class ELFT> class RuntimeFile : public ELFFile<ELFT> {
public:
typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
- RuntimeFile(ELFLinkingContext &context, StringRef name)
- : ELFFile<ELFT>(name, context) {}
+ RuntimeFile(ELFLinkingContext &ctx, StringRef name)
+ : ELFFile<ELFT>(name, ctx) {}
/// \brief add a global absolute atom
- virtual Atom *addAbsoluteAtom(StringRef symbolName) {
- assert(!symbolName.empty() && "AbsoluteAtoms must have a name");
- Elf_Sym *symbol = new (this->_readerStorage) Elf_Sym;
- symbol->st_name = 0;
- symbol->st_value = 0;
- symbol->st_shndx = llvm::ELF::SHN_ABS;
- symbol->setBindingAndType(llvm::ELF::STB_GLOBAL, llvm::ELF::STT_OBJECT);
- symbol->setVisibility(llvm::ELF::STV_DEFAULT);
- symbol->st_size = 0;
- auto newAtom = this->handleAbsoluteSymbol(symbolName, symbol, -1);
- this->_absoluteAtoms._atoms.push_back(*newAtom);
- return *newAtom;
- }
+ virtual void addAbsoluteAtom(StringRef symbolName, bool isHidden = false);
/// \brief add an undefined atom
- virtual Atom *addUndefinedAtom(StringRef symbolName) {
- assert(!symbolName.empty() && "UndefinedAtoms must have a name");
- Elf_Sym *symbol = new (this->_readerStorage) Elf_Sym;
- symbol->st_name = 0;
- symbol->st_value = 0;
- symbol->st_shndx = llvm::ELF::SHN_UNDEF;
- symbol->setBindingAndType(llvm::ELF::STB_GLOBAL, llvm::ELF::STT_NOTYPE);
- symbol->setVisibility(llvm::ELF::STV_DEFAULT);
- symbol->st_size = 0;
- auto newAtom = this->handleUndefinedSymbol(symbolName, symbol);
- this->_undefinedAtoms._atoms.push_back(*newAtom);
- return *newAtom;
- }
-
- // cannot add atoms to Runtime file
- virtual void addAtom(const Atom &) {
- llvm_unreachable("cannot add atoms to Runtime files");
- }
+ virtual void addUndefinedAtom(StringRef symbolName);
};
-template <class ELFT>
-ErrorOr<std::unique_ptr<ELFFile<ELFT>>>
-ELFFile<ELFT>::create(std::unique_ptr<MemoryBuffer> mb,
- ELFLinkingContext &ctx) {
- std::unique_ptr<ELFFile<ELFT>> file(new ELFFile<ELFT>(std::move(mb), ctx));
- return std::move(file);
-}
-
-template <class ELFT>
-std::error_code ELFFile<ELFT>::doParse() {
- std::error_code ec;
- _objFile.reset(new llvm::object::ELFFile<ELFT>(_mb->getBuffer(), ec));
- if (ec)
- return ec;
-
- if ((ec = createAtomsFromContext()))
- return ec;
-
- // Read input sections from the input file that need to be converted to
- // atoms
- if ((ec = createAtomizableSections()))
- return ec;
-
- // For mergeable strings, we would need to split the section into various
- // atoms
- if ((ec = createMergeableAtoms()))
- return ec;
-
- // Create the necessary symbols that are part of the section that we
- // created in createAtomizableSections function
- if ((ec = createSymbolsFromAtomizableSections()))
- return ec;
-
- // Create the appropriate atoms from the file
- if ((ec = createAtoms()))
- return ec;
- return std::error_code();
-}
-
-template <class ELFT> Reference::KindArch ELFFile<ELFT>::kindArch() {
- switch (_objFile->getHeader()->e_machine) {
- case llvm::ELF::EM_X86_64:
- return Reference::KindArch::x86_64;
- case llvm::ELF::EM_386:
- return Reference::KindArch::x86;
- case llvm::ELF::EM_ARM:
- return Reference::KindArch::ARM;
- case llvm::ELF::EM_HEXAGON:
- return Reference::KindArch::Hexagon;
- case llvm::ELF::EM_MIPS:
- return Reference::KindArch::Mips;
- case llvm::ELF::EM_AARCH64:
- return Reference::KindArch::AArch64;
- }
- llvm_unreachable("unsupported e_machine value");
-}
-
-template <class ELFT>
-std::error_code ELFFile<ELFT>::createAtomizableSections() {
- // Handle: SHT_REL and SHT_RELA sections:
- // Increment over the sections, when REL/RELA section types are found add
- // the contents to the RelocationReferences map.
- // Record the number of relocs to guess at preallocating the buffer.
- uint64_t totalRelocs = 0;
- for (const Elf_Shdr &section : _objFile->sections()) {
- if (isIgnoredSection(&section))
- continue;
-
- if (isMergeableStringSection(&section)) {
- _mergeStringSections.push_back(&section);
- continue;
- }
-
- if (section.sh_type == llvm::ELF::SHT_RELA) {
- auto sHdr = _objFile->getSection(section.sh_info);
-
- auto sectionName = _objFile->getSectionName(sHdr);
- if (std::error_code ec = sectionName.getError())
- return ec;
-
- auto rai(_objFile->begin_rela(&section));
- auto rae(_objFile->end_rela(&section));
-
- _relocationAddendReferences[*sectionName] = make_range(rai, rae);
- totalRelocs += std::distance(rai, rae);
- } else if (section.sh_type == llvm::ELF::SHT_REL) {
- auto sHdr = _objFile->getSection(section.sh_info);
-
- auto sectionName = _objFile->getSectionName(sHdr);
- if (std::error_code ec = sectionName.getError())
- return ec;
-
- auto ri(_objFile->begin_rel(&section));
- auto re(_objFile->end_rel(&section));
-
- _relocationReferences[*sectionName] = make_range(ri, re);
- totalRelocs += std::distance(ri, re);
- } else {
- _sectionSymbols[&section];
- }
- }
- _references.reserve(totalRelocs);
- return std::error_code();
-}
-
-template <class ELFT> std::error_code ELFFile<ELFT>::createMergeableAtoms() {
- // Divide the section that contains mergeable strings into tokens
- // TODO
- // a) add resolver support to recognize multibyte chars
- // b) Create a separate section chunk to write mergeable atoms
- std::vector<MergeString *> tokens;
- for (const Elf_Shdr *msi : _mergeStringSections) {
- auto sectionName = getSectionName(msi);
- if (std::error_code ec = sectionName.getError())
- return ec;
-
- auto sectionContents = getSectionContents(msi);
- if (std::error_code ec = sectionContents.getError())
- return ec;
-
- StringRef secCont(reinterpret_cast<const char *>(sectionContents->begin()),
- sectionContents->size());
-
- unsigned int prev = 0;
- for (std::size_t i = 0, e = sectionContents->size(); i != e; ++i) {
- if ((*sectionContents)[i] == '\0') {
- tokens.push_back(new (_readerStorage) MergeString(
- prev, secCont.slice(prev, i + 1), msi, *sectionName));
- prev = i + 1;
- }
- }
- }
-
- // Create Mergeable atoms
- for (const MergeString *tai : tokens) {
- ArrayRef<uint8_t> content((const uint8_t *)tai->_string.data(),
- tai->_string.size());
- ErrorOr<ELFMergeAtom<ELFT> *> mergeAtom =
- handleMergeString(tai->_sectionName, tai->_shdr, content, tai->_offset);
- (*mergeAtom)->setOrdinal(++_ordinal);
- _definedAtoms._atoms.push_back(*mergeAtom);
- _mergeAtoms.push_back(*mergeAtom);
- }
- return std::error_code();
-}
-
-template <class ELFT>
-std::error_code ELFFile<ELFT>::createSymbolsFromAtomizableSections() {
- // Increment over all the symbols collecting atoms and symbol names for
- // later use.
- auto SymI = _objFile->begin_symbols(), SymE = _objFile->end_symbols();
-
- // Skip over dummy sym.
- if (SymI != SymE)
- ++SymI;
-
- for (; SymI != SymE; ++SymI) {
- const Elf_Shdr *section = _objFile->getSection(&*SymI);
-
- auto symbolName = _objFile->getSymbolName(SymI);
- if (std::error_code ec = symbolName.getError())
- return ec;
-
- if (isAbsoluteSymbol(&*SymI)) {
- ErrorOr<ELFAbsoluteAtom<ELFT> *> absAtom =
- handleAbsoluteSymbol(*symbolName, &*SymI, (int64_t)getSymbolValue(&*SymI));
- _absoluteAtoms._atoms.push_back(*absAtom);
- _symbolToAtomMapping.insert(std::make_pair(&*SymI, *absAtom));
- } else if (isUndefinedSymbol(&*SymI)) {
- if (_useWrap &&
- (_wrapSymbolMap.find(*symbolName) != _wrapSymbolMap.end())) {
- auto wrapAtom = _wrapSymbolMap.find(*symbolName);
- _symbolToAtomMapping.insert(
- std::make_pair(&*SymI, wrapAtom->getValue()));
- continue;
- }
- ErrorOr<ELFUndefinedAtom<ELFT> *> undefAtom =
- handleUndefinedSymbol(*symbolName, &*SymI);
- _undefinedAtoms._atoms.push_back(*undefAtom);
- _symbolToAtomMapping.insert(std::make_pair(&*SymI, *undefAtom));
- } else if (isCommonSymbol(&*SymI)) {
- ErrorOr<ELFCommonAtom<ELFT> *> commonAtom =
- handleCommonSymbol(*symbolName, &*SymI);
- (*commonAtom)->setOrdinal(++_ordinal);
- _definedAtoms._atoms.push_back(*commonAtom);
- _symbolToAtomMapping.insert(std::make_pair(&*SymI, *commonAtom));
- } else if (isDefinedSymbol(&*SymI)) {
- _sectionSymbols[section].push_back(SymI);
- } else {
- llvm::errs() << "Unable to create atom for: " << *symbolName << "\n";
- return llvm::object::object_error::parse_failed;
- }
- }
-
- return std::error_code();
-}
-
-template <class ELFT> std::error_code ELFFile<ELFT>::createAtoms() {
- // Holds all the atoms that are part of the section. They are the targets of
- // the kindGroupChild reference.
- llvm::StringMap<std::vector<ELFDefinedAtom<ELFT> *>> atomsForSection;
- // group sections have a mapping of the section header to the
- // signature/section.
- llvm::DenseMap<const Elf_Shdr *, std::pair<StringRef, StringRef>>
- groupSections;
- // Contains a list of comdat sections for a group.
- llvm::DenseMap<const Elf_Shdr *, std::vector<StringRef>> comdatSections;
- for (auto &i : _sectionSymbols) {
- const Elf_Shdr *section = i.first;
- std::vector<Elf_Sym_Iter> &symbols = i.second;
-
- // Sort symbols by position.
- std::stable_sort(symbols.begin(), symbols.end(),
- [this](Elf_Sym_Iter a, Elf_Sym_Iter b) {
- return getSymbolValue(&*a) < getSymbolValue(&*b);
- });
-
- ErrorOr<StringRef> sectionName = this->getSectionName(section);
- if (std::error_code ec = sectionName.getError())
- return ec;
-
- auto sectionContents = getSectionContents(section);
- if (std::error_code ec = sectionContents.getError())
- return ec;
-
- bool addAtoms = true;
-
- // A section of type SHT_GROUP defines a grouping of sections. The name of a
- // symbol from one of the containing object's symbol tables provides a
- // signature
- // for the section group. The section header of the SHT_GROUP section
- // specifies
- // the identifying symbol entry, as described : the sh_link member contains
- // the section header index of the symbol table section that contains the
- // entry.
- // The sh_info member contains the symbol table index of the identifying
- // entry.
- // The sh_flags member of the section header contains 0. The name of the
- // section
- // (sh_name) is not specified.
- if (isGroupSection(section)) {
- const Elf_Word *groupMembers =
- reinterpret_cast<const Elf_Word *>(sectionContents->data());
- const long count = (section->sh_size) / sizeof(Elf_Word);
- for (int i = 1; i < count; i++) {
- const Elf_Shdr *sHdr = _objFile->getSection(groupMembers[i]);
- ErrorOr<StringRef> sectionName = _objFile->getSectionName(sHdr);
- if (std::error_code ec = sectionName.getError())
- return ec;
- comdatSections[section].push_back(*sectionName);
- }
- const Elf_Sym *symbol = _objFile->getSymbol(section->sh_info);
- const Elf_Shdr *symtab = _objFile->getSection(section->sh_link);
- ErrorOr<StringRef> symbolName = _objFile->getSymbolName(symtab, symbol);
- if (std::error_code ec = symbolName.getError())
- return ec;
- groupSections.insert(
- std::make_pair(section, std::make_pair(*symbolName, *sectionName)));
- continue;
- }
-
- if (isGnuLinkOnceSection(*sectionName)) {
- groupSections.insert(
- std::make_pair(section, std::make_pair(*sectionName, *sectionName)));
- addAtoms = false;
- }
-
- if (isSectionMemberOfGroup(section))
- addAtoms = false;
-
- if (handleSectionWithNoSymbols(section, symbols)) {
- ELFDefinedAtom<ELFT> *newAtom =
- createSectionAtom(section, *sectionName, *sectionContents);
- newAtom->setOrdinal(++_ordinal);
- if (addAtoms)
- _definedAtoms._atoms.push_back(newAtom);
- else
- atomsForSection[*sectionName].push_back(newAtom);
- continue;
- }
-
- ELFDefinedAtom<ELFT> *previousAtom = nullptr;
- ELFReference<ELFT> *anonFollowedBy = nullptr;
-
- for (auto si = symbols.begin(), se = symbols.end(); si != se; ++si) {
- auto symbol = *si;
- StringRef symbolName = "";
- if (symbol->getType() != llvm::ELF::STT_SECTION) {
- auto symName = _objFile->getSymbolName(symbol);
- if (std::error_code ec = symName.getError())
- return ec;
- symbolName = *symName;
- }
-
- uint64_t contentSize = symbolContentSize(
- section, &*symbol, (si + 1 == se) ? nullptr : &**(si + 1));
-
- // Check to see if we need to add the FollowOn Reference
- ELFReference<ELFT> *followOn = nullptr;
- if (previousAtom) {
- // Replace the followon atom with the anonymous atom that we created,
- // so that the next symbol that we create is a followon from the
- // anonymous atom.
- if (anonFollowedBy) {
- followOn = anonFollowedBy;
- } else {
- followOn = new (_readerStorage)
- ELFReference<ELFT>(lld::Reference::kindLayoutAfter);
- previousAtom->addReference(followOn);
- }
- }
-
- ArrayRef<uint8_t> symbolData((const uint8_t *)sectionContents->data() +
- getSymbolValue(&*symbol),
- contentSize);
-
- // If the linker finds that a section has global atoms that are in a
- // mergeable section, treat them as defined atoms as they shouldn't be
- // merged away as well as these symbols have to be part of symbol
- // resolution
- if (isMergeableStringSection(section)) {
- if (symbol->getBinding() == llvm::ELF::STB_GLOBAL) {
- auto definedMergeAtom = handleDefinedSymbol(
- symbolName, *sectionName, &**si, section, symbolData,
- _references.size(), _references.size(), _references);
- (*definedMergeAtom)->setOrdinal(++_ordinal);
- if (addAtoms)
- _definedAtoms._atoms.push_back(*definedMergeAtom);
- else
- atomsForSection[*sectionName].push_back(*definedMergeAtom);
- }
- continue;
- }
-
- // Don't allocate content to a weak symbol, as they may be merged away.
- // Create an anonymous atom to hold the data.
- ELFDefinedAtom<ELFT> *anonAtom = nullptr;
- anonFollowedBy = nullptr;
- if (symbol->getBinding() == llvm::ELF::STB_WEAK) {
- // Create anonymous new non-weak ELF symbol that holds the symbol
- // data.
- auto sym = new (_readerStorage) Elf_Sym(*symbol);
- sym->setBinding(llvm::ELF::STB_GLOBAL);
- anonAtom = createDefinedAtomAndAssignRelocations(
- "", *sectionName, sym, section, symbolData, *sectionContents);
- symbolData = ArrayRef<uint8_t>();
-
- // If this is the last atom, let's not create a followon reference.
- if (anonAtom && (si + 1) != se) {
- anonFollowedBy = new (_readerStorage)
- ELFReference<ELFT>(lld::Reference::kindLayoutAfter);
- anonAtom->addReference(anonFollowedBy);
- }
- }
-
- ELFDefinedAtom<ELFT> *newAtom = createDefinedAtomAndAssignRelocations(
- symbolName, *sectionName, &*symbol, section, symbolData,
- *sectionContents);
- newAtom->setOrdinal(++_ordinal);
-
- // If the atom was a weak symbol, let's create a followon reference to
- // the anonymous atom that we created.
- if (anonAtom)
- createEdge(newAtom, anonAtom, Reference::kindLayoutAfter);
-
- if (previousAtom) {
- // Set the followon atom to the weak atom that we have created, so
- // that they would alias when the file gets written.
- followOn->setTarget(anonAtom ? anonAtom : newAtom);
- }
-
- // The previous atom is always the atom created before unless the atom
- // is a weak atom.
- previousAtom = anonAtom ? anonAtom : newAtom;
-
- if (addAtoms)
- _definedAtoms._atoms.push_back(newAtom);
- else
- atomsForSection[*sectionName].push_back(newAtom);
-
- _symbolToAtomMapping.insert(std::make_pair(&*symbol, newAtom));
- if (anonAtom) {
- anonAtom->setOrdinal(++_ordinal);
- if (addAtoms)
- _definedAtoms._atoms.push_back(anonAtom);
- else
- atomsForSection[*sectionName].push_back(anonAtom);
- }
- }
- }
-
- // Iterate over all the group sections to create parent atoms pointing to
- // group-child atoms.
- for (auto &sect : groupSections) {
- StringRef signature = sect.second.first;
- StringRef groupSectionName = sect.second.second;
- if (isGnuLinkOnceSection(signature))
- handleGnuLinkOnceSection(signature, atomsForSection, sect.first);
- else if (isGroupSection(sect.first))
- handleSectionGroup(signature, groupSectionName, atomsForSection,
- comdatSections, sect.first);
- }
-
- updateReferences();
- return std::error_code();
-}
-
-template <class ELFT>
-std::error_code ELFFile<ELFT>::handleGnuLinkOnceSection(
- StringRef signature,
- llvm::StringMap<std::vector<ELFDefinedAtom<ELFT> *>> &atomsForSection,
- const Elf_Shdr *shdr) {
- // TODO: Check for errors.
- unsigned int referenceStart = _references.size();
- std::vector<ELFReference<ELFT> *> refs;
- for (auto ha : atomsForSection[signature]) {
- _groupChild[ha->symbol()] = std::make_pair(signature, shdr);
- ELFReference<ELFT> *ref =
- new (_readerStorage) ELFReference<ELFT>(lld::Reference::kindGroupChild);
- ref->setTarget(ha);
- refs.push_back(ref);
- }
- atomsForSection[signature].clear();
- // Create a gnu linkonce atom.
- auto gnuLinkOnceAtom = handleDefinedSymbol(
- signature, signature, nullptr, shdr, ArrayRef<uint8_t>(), referenceStart,
- _references.size(), _references);
- (*gnuLinkOnceAtom)->setOrdinal(++_ordinal);
- _definedAtoms._atoms.push_back(*gnuLinkOnceAtom);
- for (auto reference : refs)
- (*gnuLinkOnceAtom)->addReference(reference);
- return std::error_code();
-}
-
-template <class ELFT>
-std::error_code ELFFile<ELFT>::handleSectionGroup(
- StringRef signature, StringRef groupSectionName,
- llvm::StringMap<std::vector<ELFDefinedAtom<ELFT> *>> &atomsForSection,
- llvm::DenseMap<const Elf_Shdr *, std::vector<StringRef>> &comdatSections,
- const Elf_Shdr *shdr) {
- // TODO: Check for errors.
- unsigned int referenceStart = _references.size();
- std::vector<ELFReference<ELFT> *> refs;
- auto sectionNamesInGroup = comdatSections[shdr];
- for (auto sectionName : sectionNamesInGroup) {
- for (auto ha : atomsForSection[sectionName]) {
- _groupChild[ha->symbol()] = std::make_pair(signature, shdr);
- ELFReference<ELFT> *ref = new (_readerStorage)
- ELFReference<ELFT>(lld::Reference::kindGroupChild);
- ref->setTarget(ha);
- refs.push_back(ref);
- }
- atomsForSection[sectionName].clear();
- }
- // Create a gnu linkonce atom.
- auto sectionGroupAtom = handleDefinedSymbol(
- signature, groupSectionName, nullptr, shdr, ArrayRef<uint8_t>(),
- referenceStart, _references.size(), _references);
- (*sectionGroupAtom)->setOrdinal(++_ordinal);
- _definedAtoms._atoms.push_back(*sectionGroupAtom);
- for (auto reference : refs)
- (*sectionGroupAtom)->addReference(reference);
- return std::error_code();
-}
-
-template <class ELFT> std::error_code ELFFile<ELFT>::createAtomsFromContext() {
- if (!_useWrap)
- return std::error_code();
- // Steps :-
- // a) Create an undefined atom for the symbol specified by the --wrap option,
- // as that
- // may be needed to be pulled from an archive.
- // b) Create an undefined atom for __wrap_<symbolname>.
- // c) All references to the symbol specified by wrap should point to
- // __wrap_<symbolname>
- // d) All references to __real_symbol should point to the <symbol>
- for (auto &wrapsym : _ctx.wrapCalls()) {
- StringRef wrapStr = wrapsym.getKey();
- // Create a undefined symbol fror the wrap symbol.
- UndefinedAtom *wrapSymAtom =
- new (_readerStorage) SimpleUndefinedAtom(*this, wrapStr);
- StringRef wrapCallSym =
- _ctx.allocateString((llvm::Twine("__wrap_") + wrapStr).str());
- StringRef realCallSym =
- _ctx.allocateString((llvm::Twine("__real_") + wrapStr).str());
- UndefinedAtom *wrapCallAtom =
- new (_readerStorage) SimpleUndefinedAtom(*this, wrapCallSym);
- // Create maps, when there is call to sym, it should point to wrapCallSym.
- _wrapSymbolMap.insert(std::make_pair(wrapStr, wrapCallAtom));
- // Whenever there is a reference to realCall it should point to the symbol
- // created for each wrap usage.
- _wrapSymbolMap.insert(std::make_pair(realCallSym, wrapSymAtom));
- _undefinedAtoms._atoms.push_back(wrapSymAtom);
- _undefinedAtoms._atoms.push_back(wrapCallAtom);
- }
- return std::error_code();
-}
-
-template <class ELFT>
-ELFDefinedAtom<ELFT> *ELFFile<ELFT>::createDefinedAtomAndAssignRelocations(
- StringRef symbolName, StringRef sectionName, const Elf_Sym *symbol,
- const Elf_Shdr *section, ArrayRef<uint8_t> symContent,
- ArrayRef<uint8_t> secContent) {
- unsigned int referenceStart = _references.size();
-
- // Add Rela (those with r_addend) references:
- auto rari = _relocationAddendReferences.find(sectionName);
- if (rari != _relocationAddendReferences.end())
- createRelocationReferences(symbol, symContent, rari->second);
-
- // Add Rel references.
- auto rri = _relocationReferences.find(sectionName);
- if (rri != _relocationReferences.end())
- createRelocationReferences(symbol, symContent, secContent, rri->second);
-
- // Create the DefinedAtom and add it to the list of DefinedAtoms.
- return *handleDefinedSymbol(symbolName, sectionName, symbol, section,
- symContent, referenceStart, _references.size(),
- _references);
-}
-
-template <class ELFT>
-void ELFFile<ELFT>::createRelocationReferences(const Elf_Sym *symbol,
- ArrayRef<uint8_t> content,
- range<Elf_Rela_Iter> rels) {
- bool isMips64EL = _objFile->isMips64EL();
- const auto symValue = getSymbolValue(symbol);
- for (const auto &rel : rels) {
- if (rel.r_offset < symValue ||
- symValue + content.size() <= rel.r_offset)
- continue;
- auto elfRelocation = new (_readerStorage)
- ELFReference<ELFT>(&rel, rel.r_offset - symValue, kindArch(),
- rel.getType(isMips64EL), rel.getSymbol(isMips64EL));
- addReferenceToSymbol(elfRelocation, symbol);
- _references.push_back(elfRelocation);
- }
-}
-
-template <class ELFT>
-void ELFFile<ELFT>::createRelocationReferences(const Elf_Sym *symbol,
- ArrayRef<uint8_t> symContent,
- ArrayRef<uint8_t> secContent,
- range<Elf_Rel_Iter> rels) {
- bool isMips64EL = _objFile->isMips64EL();
- const auto symValue = getSymbolValue(symbol);
- for (const auto &rel : rels) {
- if (rel.r_offset < symValue ||
- symValue + symContent.size() <= rel.r_offset)
- continue;
- auto elfRelocation = new (_readerStorage)
- ELFReference<ELFT>(rel.r_offset - symValue, kindArch(),
- rel.getType(isMips64EL), rel.getSymbol(isMips64EL));
- int32_t addend = *(symContent.data() + rel.r_offset - symValue);
- elfRelocation->setAddend(addend);
- addReferenceToSymbol(elfRelocation, symbol);
- _references.push_back(elfRelocation);
- }
-}
-
-template <class ELFT>
-void ELFFile<ELFT>::updateReferenceForMergeStringAccess(ELFReference<ELFT> *ref,
- const Elf_Sym *symbol,
- const Elf_Shdr *shdr) {
- // If the target atom is mergeable strefng atom, the atom might have been
- // merged with other atom having the same contents. Try to find the
- // merged one if that's the case.
- int64_t addend = ref->addend();
- if (addend < 0)
- addend = 0;
-
- const MergeSectionKey ms(shdr, addend);
- auto msec = _mergedSectionMap.find(ms);
- if (msec != _mergedSectionMap.end()) {
- ref->setTarget(msec->second);
- return;
- }
-
- // The target atom was not merged. Mergeable atoms are not in
- // _symbolToAtomMapping, so we cannot find it by calling findAtom(). We
- // instead call findMergeAtom().
- if (symbol->getType() != llvm::ELF::STT_SECTION)
- addend = getSymbolValue(symbol) + addend;
- ELFMergeAtom<ELFT> *mergedAtom = findMergeAtom(shdr, addend);
- ref->setOffset(addend - mergedAtom->offset());
- ref->setAddend(0);
- ref->setTarget(mergedAtom);
-}
-
-template <class ELFT> void ELFFile<ELFT>::updateReferences() {
- for (auto &ri : _references) {
- if (ri->kindNamespace() != lld::Reference::KindNamespace::ELF)
- continue;
- const Elf_Sym *symbol = _objFile->getSymbol(ri->targetSymbolIndex());
- const Elf_Shdr *shdr = _objFile->getSection(symbol);
-
- // If the atom is not in mergeable string section, the target atom is
- // simply that atom.
- if (isMergeableStringSection(shdr))
- updateReferenceForMergeStringAccess(ri, symbol, shdr);
- else
- ri->setTarget(findAtom(findSymbolForReference(ri), symbol));
- }
-}
-
-template <class ELFT>
-bool ELFFile<ELFT>::isIgnoredSection(const Elf_Shdr *section) {
- switch (section->sh_type) {
- case llvm::ELF::SHT_NULL:
- case llvm::ELF::SHT_STRTAB:
- case llvm::ELF::SHT_SYMTAB:
- case llvm::ELF::SHT_SYMTAB_SHNDX:
- return true;
- default:
- break;
- }
- return false;
-}
-
-template <class ELFT>
-bool ELFFile<ELFT>::isMergeableStringSection(const Elf_Shdr *section) {
- if (_doStringsMerge && section) {
- int64_t sectionFlags = section->sh_flags;
- sectionFlags &= ~llvm::ELF::SHF_ALLOC;
- // Mergeable string sections have both SHF_MERGE and SHF_STRINGS flags
- // set. sh_entsize is the size of each character which is normally 1.
- if ((section->sh_entsize < 2) &&
- (sectionFlags == (llvm::ELF::SHF_MERGE | llvm::ELF::SHF_STRINGS))) {
- return true;
- }
- }
- return false;
-}
-
-template <class ELFT>
-ELFDefinedAtom<ELFT> *
-ELFFile<ELFT>::createSectionAtom(const Elf_Shdr *section, StringRef sectionName,
- ArrayRef<uint8_t> content) {
- Elf_Sym *sym = new (_readerStorage) Elf_Sym;
- sym->st_name = 0;
- sym->setBindingAndType(llvm::ELF::STB_LOCAL, llvm::ELF::STT_SECTION);
- sym->st_other = 0;
- sym->st_shndx = 0;
- sym->st_value = 0;
- sym->st_size = 0;
- auto *newAtom = createDefinedAtomAndAssignRelocations(
- "", sectionName, sym, section, content, content);
- newAtom->setOrdinal(++_ordinal);
- return newAtom;
-}
-
-template <class ELFT>
-uint64_t ELFFile<ELFT>::symbolContentSize(const Elf_Shdr *section,
- const Elf_Sym *symbol,
- const Elf_Sym *nextSymbol) {
- const auto symValue = getSymbolValue(symbol);
- // if this is the last symbol, take up the remaining data.
- return nextSymbol ? getSymbolValue(nextSymbol) - symValue
- : section->sh_size - symValue;
-}
-
-template <class ELFT>
-void ELFFile<ELFT>::createEdge(ELFDefinedAtom<ELFT> *from,
- ELFDefinedAtom<ELFT> *to, uint32_t edgeKind) {
- auto reference = new (_readerStorage) ELFReference<ELFT>(edgeKind);
- reference->setTarget(to);
- from->addReference(reference);
-}
-
-/// Does the atom need to be redirected using a separate undefined atom?
-template <class ELFT>
-bool ELFFile<ELFT>::redirectReferenceUsingUndefAtom(
- const Elf_Sym *sourceSymbol, const Elf_Sym *targetSymbol) const {
- auto groupChildTarget = _groupChild.find(targetSymbol);
-
- // If the reference is not to a group child atom, there is no need to redirect
- // using a undefined atom. Its also not needed if the source and target are
- // from the same section.
- if ((groupChildTarget == _groupChild.end()) ||
- (sourceSymbol->st_shndx == targetSymbol->st_shndx))
- return false;
-
- auto groupChildSource = _groupChild.find(sourceSymbol);
-
- // If the source symbol is not in a group, use a undefined symbol too.
- if (groupChildSource == _groupChild.end())
- return true;
-
- // If the source and child are from the same group, we dont need the
- // relocation to go through a undefined symbol.
- if (groupChildSource->second.second == groupChildTarget->second.second)
- return false;
-
- return true;
-}
-
} // end namespace elf
} // end namespace lld
diff --git a/lib/ReaderWriter/ELF/ELFLinkingContext.cpp b/lib/ReaderWriter/ELF/ELFLinkingContext.cpp
index c7dffda8a463..2904c7b0dae0 100644
--- a/lib/ReaderWriter/ELF/ELFLinkingContext.cpp
+++ b/lib/ReaderWriter/ELF/ELFLinkingContext.cpp
@@ -25,6 +25,9 @@
#include <cxxabi.h>
#endif
+using llvm::sys::fs::exists;
+using llvm::sys::path::is_absolute;
+
namespace lld {
class CommandLineUndefinedAtom : public SimpleUndefinedAtom {
@@ -37,18 +40,6 @@ public:
}
};
-ELFLinkingContext::ELFLinkingContext(
- llvm::Triple triple, std::unique_ptr<TargetHandlerBase> targetHandler)
- : _outputELFType(llvm::ELF::ET_EXEC), _triple(triple),
- _targetHandler(std::move(targetHandler)), _baseAddress(0),
- _isStaticExecutable(false), _noInhibitExec(false), _exportDynamic(false),
- _mergeCommonStrings(false), _useShlibUndefines(true),
- _dynamicLinkerArg(false), _noAllowDynamicLibraries(false),
- _mergeRODataToTextSegment(true), _demangle(true),
- _stripSymbols(false), _alignSegments(true), _collectStats(false),
- _outputMagic(OutputMagic::DEFAULT), _initFunction("_init"),
- _finiFunction("_fini"), _sysrootPath(""), _linkerScriptSema() {}
-
void ELFLinkingContext::addPasses(PassManager &pm) {
pm.add(llvm::make_unique<elf::OrderPass>());
}
@@ -61,13 +52,17 @@ uint16_t ELFLinkingContext::getOutputMachine() const {
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;
+ case llvm::Triple::amdgcn:
+ return llvm::ELF::EM_AMDGPU;
default:
llvm_unreachable("Unhandled arch");
}
@@ -84,11 +79,8 @@ bool ELFLinkingContext::validateImpl(raw_ostream &diagnostics) {
case LinkingContext::OutputFileType::YAML:
_writer = createWriterYAML(*this);
break;
- case LinkingContext::OutputFileType::Native:
- llvm_unreachable("Unimplemented");
- break;
default:
- _writer = createWriterELF(this->targetHandler());
+ _writer = createWriterELF(*this);
break;
}
@@ -116,11 +108,13 @@ Writer &ELFLinkingContext::writer() const { return *_writer; }
static void buildSearchPath(SmallString<128> &path, StringRef dir,
StringRef sysRoot) {
- if (!dir.startswith("=/"))
- path.assign(dir);
- else {
+ 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);
}
}
@@ -134,18 +128,18 @@ ErrorOr<StringRef> ELFLinkingContext::searchLibrary(StringRef libName) const {
llvm::sys::path::append(path, hasColonPrefix
? libName.drop_front()
: Twine("lib", libName) + ".so");
- if (llvm::sys::fs::exists(path.str()))
- return StringRef(*new (_allocator) std::string(path.str()));
+ 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 (llvm::sys::fs::exists(path.str()))
- return StringRef(*new (_allocator) std::string(path.str()));
+ if (exists(path.str()))
+ return path.str().copy(_allocator);
}
- if (hasColonPrefix && llvm::sys::fs::exists(libName.drop_front()))
+ if (hasColonPrefix && exists(libName.drop_front()))
return libName.drop_front();
return make_error_code(llvm::errc::no_such_file_or_directory);
@@ -154,22 +148,23 @@ ErrorOr<StringRef> ELFLinkingContext::searchLibrary(StringRef libName) const {
ErrorOr<StringRef> ELFLinkingContext::searchFile(StringRef fileName,
bool isSysRooted) const {
SmallString<128> path;
- if (llvm::sys::path::is_absolute(fileName) && isSysRooted) {
+ if (is_absolute(fileName) && isSysRooted) {
path.assign(_sysrootPath);
path.append(fileName);
- if (llvm::sys::fs::exists(path.str()))
- return StringRef(*new (_allocator) std::string(path.str()));
- } else if (llvm::sys::fs::exists(fileName))
+ if (exists(path.str()))
+ return path.str().copy(_allocator);
+ } else if (exists(fileName)) {
return fileName;
+ }
- if (llvm::sys::path::is_absolute(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 (llvm::sys::fs::exists(path.str()))
- return StringRef(*new (_allocator) std::string(path.str()));
+ if (exists(path.str()))
+ return path.str().copy(_allocator);
}
return make_error_code(llvm::errc::no_such_file_or_directory);
}
@@ -227,6 +222,7 @@ void ELFLinkingContext::notifySymbolTableCoalesce(const Atom *existingAtom,
}
std::string ELFLinkingContext::demangle(StringRef symbolName) const {
+#if defined(HAVE_CXXABI_H)
if (!demangleSymbols())
return symbolName;
@@ -234,21 +230,20 @@ std::string ELFLinkingContext::demangle(StringRef symbolName) const {
if (!symbolName.startswith("_Z"))
return symbolName;
-#if defined(HAVE_CXXABI_H)
SmallString<256> symBuff;
StringRef nullTermSym = Twine(symbolName).toNullTerminatedStringRef(symBuff);
const char *cstr = nullTermSym.data();
int status;
char *demangled = abi::__cxa_demangle(cstr, nullptr, nullptr, &status);
- if (demangled != NULL) {
- std::string result(demangled);
- // __cxa_demangle() always uses a malloc'ed buffer to return the result.
- free(demangled);
- return result;
- }
-#endif
-
+ 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) {
@@ -256,4 +251,15 @@ void ELFLinkingContext::setUndefinesResolver(std::unique_ptr<File> resolver) {
_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
index 43f218115c66..60af6dff9980 100644
--- a/lib/ReaderWriter/ELF/ELFReader.h
+++ b/lib/ReaderWriter/ELF/ELFReader.h
@@ -10,90 +10,35 @@
#ifndef LLD_READER_WRITER_ELF_READER_H
#define LLD_READER_WRITER_ELF_READER_H
-#include "CreateELF.h"
#include "DynamicFile.h"
#include "ELFFile.h"
+#include "lld/Core/File.h"
#include "lld/Core/Reader.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Object/ELF.h"
namespace lld {
namespace elf {
-template <typename ELFT, typename ELFTraitsT, typename ContextT>
-class ELFObjectReader : public Reader {
+template <typename FileT> class ELFReader : public Reader {
public:
- typedef llvm::object::Elf_Ehdr_Impl<ELFT> Elf_Ehdr;
+ ELFReader(ELFLinkingContext &ctx) : _ctx(ctx) {}
- ELFObjectReader(ContextT &ctx, uint64_t machine)
- : _ctx(ctx), _machine(machine) {}
-
- bool canParse(file_magic magic, StringRef,
- const MemoryBuffer &buf) const override {
- return (magic == llvm::sys::fs::file_magic::elf_relocatable &&
- elfHeader(buf)->e_machine == _machine);
+ bool canParse(file_magic magic, MemoryBufferRef mb) const override {
+ return FileT::canParse(magic);
}
- std::error_code
- loadFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &,
- std::vector<std::unique_ptr<File>> &result) const override {
- std::size_t maxAlignment =
- 1ULL << llvm::countTrailingZeros(uintptr_t(mb->getBufferStart()));
- auto f =
- createELF<ELFTraitsT>(llvm::object::getElfArchType(mb->getBuffer()),
- maxAlignment, std::move(mb), _ctx);
- if (std::error_code ec = f.getError())
+ 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;
- result.push_back(std::move(*f));
- return std::error_code();
- }
-
- const Elf_Ehdr *elfHeader(const MemoryBuffer &buf) const {
- const uint8_t *data =
- reinterpret_cast<const uint8_t *>(buf.getBuffer().data());
- return (reinterpret_cast<const Elf_Ehdr *>(data));
- }
-
-protected:
- ContextT &_ctx;
- uint64_t _machine;
-};
-
-template <typename ELFT, typename ELFTraitsT, typename ContextT>
-class ELFDSOReader : public Reader {
-public:
- typedef llvm::object::Elf_Ehdr_Impl<ELFT> Elf_Ehdr;
-
- ELFDSOReader(ContextT &ctx, uint64_t machine)
- : _ctx(ctx), _machine(machine) {}
-
- bool canParse(file_magic magic, StringRef,
- const MemoryBuffer &buf) const override {
- return (magic == llvm::sys::fs::file_magic::elf_shared_object &&
- elfHeader(buf)->e_machine == _machine);
- }
-
- std::error_code
- loadFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &,
- std::vector<std::unique_ptr<File>> &result) const override {
- std::size_t maxAlignment =
- 1ULL << llvm::countTrailingZeros(uintptr_t(mb->getBufferStart()));
- auto f =
- createELF<ELFTraitsT>(llvm::object::getElfArchType(mb->getBuffer()),
- maxAlignment, std::move(mb), _ctx);
- if (std::error_code ec = f.getError())
- return ec;
- result.push_back(std::move(*f));
- return std::error_code();
- }
-
- const Elf_Ehdr *elfHeader(const MemoryBuffer &buf) const {
- const uint8_t *data =
- reinterpret_cast<const uint8_t *>(buf.getBuffer().data());
- return (reinterpret_cast<const Elf_Ehdr *>(data));
+ std::unique_ptr<File> ret = llvm::make_unique<FileT>(std::move(mb), _ctx);
+ return std::move(ret);
}
-protected:
- ContextT &_ctx;
- uint64_t _machine;
+private:
+ ELFLinkingContext &_ctx;
};
} // namespace elf
diff --git a/lib/ReaderWriter/ELF/ExecutableWriter.h b/lib/ReaderWriter/ELF/ExecutableWriter.h
index 477e3920abae..9d9f4d9ce0a5 100644
--- a/lib/ReaderWriter/ELF/ExecutableWriter.h
+++ b/lib/ReaderWriter/ELF/ExecutableWriter.h
@@ -16,32 +16,29 @@ namespace elf {
using namespace llvm;
using namespace llvm::object;
-template<class ELFT>
-class ExecutableWriter;
-
//===----------------------------------------------------------------------===//
// ExecutableWriter Class
//===----------------------------------------------------------------------===//
template<class ELFT>
class ExecutableWriter : public OutputELFWriter<ELFT> {
public:
- ExecutableWriter(ELFLinkingContext &context, TargetLayout<ELFT> &layout)
- : OutputELFWriter<ELFT>(context, layout),
- _runtimeFile(new RuntimeFile<ELFT>(context, "C runtime")) {}
+ ExecutableWriter(ELFLinkingContext &ctx, TargetLayout<ELFT> &layout)
+ : OutputELFWriter<ELFT>(ctx, layout) {}
protected:
- virtual void buildDynamicSymbolTable(const File &file);
- virtual void addDefaultAtoms();
- virtual bool createImplicitFiles(std::vector<std::unique_ptr<File> > &);
- virtual void finalizeDefaultAtomValues();
- virtual void createDefaultSections();
+ void buildDynamicSymbolTable(const File &file) override;
+ void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
+ void finalizeDefaultAtomValues() override;
+ void createDefaultSections() override;
- virtual bool isNeededTagRequired(const SharedLibraryAtom *sla) const {
+ bool isNeededTagRequired(const SharedLibraryAtom *sla) const override {
return this->_layout.isCopied(sla);
}
unique_bump_ptr<InterpSection<ELFT>> _interpSection;
- std::unique_ptr<RuntimeFile<ELFT> > _runtimeFile;
+
+private:
+ std::unique_ptr<RuntimeFile<ELFT>> createRuntimeFile();
};
//===----------------------------------------------------------------------===//
@@ -56,8 +53,8 @@ void ExecutableWriter<ELFT>::buildDynamicSymbolTable(const File &file) {
if (!da)
continue;
if (da->dynamicExport() != DefinedAtom::dynamicExportAlways &&
- !this->_context.isDynamicallyExportedSymbol(da->name()) &&
- !(this->_context.shouldExportDynamic() &&
+ !this->_ctx.isDynamicallyExportedSymbol(da->name()) &&
+ !(this->_ctx.shouldExportDynamic() &&
da->scope() == Atom::Scope::scopeGlobal))
continue;
this->_dynamicSymbolTable->addSymbol(atom->_atom, section->ordinal(),
@@ -65,7 +62,7 @@ void ExecutableWriter<ELFT>::buildDynamicSymbolTable(const File &file) {
}
// Put weak symbols in the dynamic symbol table.
- if (this->_context.isDynamic()) {
+ if (this->_ctx.isDynamic()) {
for (const UndefinedAtom *a : file.undefined()) {
if (this->_layout.isReferencedByDefinedAtom(a) &&
a->canBeNull() != UndefinedAtom::canBeNullNever)
@@ -76,48 +73,44 @@ void ExecutableWriter<ELFT>::buildDynamicSymbolTable(const File &file) {
OutputELFWriter<ELFT>::buildDynamicSymbolTable(file);
}
-/// \brief Add absolute symbols by default. These are linker added
-/// absolute symbols
template<class ELFT>
-void ExecutableWriter<ELFT>::addDefaultAtoms() {
- OutputELFWriter<ELFT>::addDefaultAtoms();
- _runtimeFile->addUndefinedAtom(this->_context.entrySymbolName());
- _runtimeFile->addAbsoluteAtom("__bss_start");
- _runtimeFile->addAbsoluteAtom("__bss_end");
- _runtimeFile->addAbsoluteAtom("_end");
- _runtimeFile->addAbsoluteAtom("end");
- _runtimeFile->addAbsoluteAtom("__preinit_array_start");
- _runtimeFile->addAbsoluteAtom("__preinit_array_end");
- _runtimeFile->addAbsoluteAtom("__init_array_start");
- _runtimeFile->addAbsoluteAtom("__init_array_end");
- if (this->_context.isRelaOutputFormat()) {
- _runtimeFile->addAbsoluteAtom("__rela_iplt_start");
- _runtimeFile->addAbsoluteAtom("__rela_iplt_end");
+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 {
- _runtimeFile->addAbsoluteAtom("__rel_iplt_start");
- _runtimeFile->addAbsoluteAtom("__rel_iplt_end");
+ file->addAbsoluteAtom("__rel_iplt_start");
+ file->addAbsoluteAtom("__rel_iplt_end");
}
- _runtimeFile->addAbsoluteAtom("__fini_array_start");
- _runtimeFile->addAbsoluteAtom("__fini_array_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>
-bool ExecutableWriter<ELFT>::createImplicitFiles(
+void ExecutableWriter<ELFT>::createImplicitFiles(
std::vector<std::unique_ptr<File> > &result) {
- // Add the default atoms as defined by executables
- ExecutableWriter<ELFT>::addDefaultAtoms();
OutputELFWriter<ELFT>::createImplicitFiles(result);
- result.push_back(std::move(_runtimeFile));
- return true;
+ result.push_back(createRuntimeFile());
}
template <class ELFT> void ExecutableWriter<ELFT>::createDefaultSections() {
OutputELFWriter<ELFT>::createDefaultSections();
- if (this->_context.isDynamic()) {
+ if (this->_ctx.isDynamic()) {
_interpSection.reset(new (this->_alloc) InterpSection<ELFT>(
- this->_context, ".interp", DefaultLayout<ELFT>::ORDER_INTERP,
- this->_context.getInterpreter()));
+ this->_ctx, ".interp", TargetLayout<ELFT>::ORDER_INTERP,
+ this->_ctx.getInterpreter()));
this->_layout.addSection(_interpSection.get());
}
}
@@ -126,53 +119,35 @@ template <class ELFT> void ExecutableWriter<ELFT>::createDefaultSections() {
/// created
template <class ELFT> void ExecutableWriter<ELFT>::finalizeDefaultAtomValues() {
OutputELFWriter<ELFT>::finalizeDefaultAtomValues();
- auto bssStartAtomIter = this->_layout.findAbsoluteAtom("__bss_start");
- auto bssEndAtomIter = this->_layout.findAbsoluteAtom("__bss_end");
- auto underScoreEndAtomIter = this->_layout.findAbsoluteAtom("_end");
- auto endAtomIter = this->_layout.findAbsoluteAtom("end");
-
- auto startEnd = [&](StringRef sym, StringRef sec) -> void {
- std::string start = ("__" + sym + "_start").str();
- std::string end = ("__" + sym + "_end").str();
- auto s = this->_layout.findAbsoluteAtom(start);
- auto e = this->_layout.findAbsoluteAtom(end);
- auto section = this->_layout.findOutputSection(sec);
- if (section) {
- (*s)->_virtualAddr = section->virtualAddr();
- (*e)->_virtualAddr = section->virtualAddr() + section->memSize();
- } else {
- (*s)->_virtualAddr = 0;
- (*e)->_virtualAddr = 0;
- }
- };
+ 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");
- startEnd("preinit_array", ".preinit_array");
- startEnd("init_array", ".init_array");
- if (this->_context.isRelaOutputFormat())
- startEnd("rela_iplt", ".rela.plt");
- else
- startEnd("rel_iplt", ".rel.plt");
- startEnd("fini_array", ".fini_array");
-
- assert(!(bssStartAtomIter == this->_layout.absoluteAtoms().end() ||
- bssEndAtomIter == this->_layout.absoluteAtoms().end() ||
- underScoreEndAtomIter == this->_layout.absoluteAtoms().end() ||
- endAtomIter == this->_layout.absoluteAtoms().end()) &&
+ 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) {
- (*bssStartAtomIter)->_virtualAddr = bssSection->virtualAddr();
- (*bssEndAtomIter)->_virtualAddr =
+ bssStartAtom->_virtualAddr = bssSection->virtualAddr();
+ bssEndAtom->_virtualAddr =
bssSection->virtualAddr() + bssSection->memSize();
- (*underScoreEndAtomIter)->_virtualAddr = (*bssEndAtomIter)->_virtualAddr;
- (*endAtomIter)->_virtualAddr = (*bssEndAtomIter)->_virtualAddr;
+ underScoreEndAtom->_virtualAddr = bssEndAtom->_virtualAddr;
+ endAtom->_virtualAddr = bssEndAtom->_virtualAddr;
} else if (auto dataSection = this->_layout.findOutputSection(".data")) {
- (*underScoreEndAtomIter)->_virtualAddr =
+ underScoreEndAtom->_virtualAddr =
dataSection->virtualAddr() + dataSection->memSize();
- (*endAtomIter)->_virtualAddr = (*underScoreEndAtomIter)->_virtualAddr;
+ endAtom->_virtualAddr = underScoreEndAtom->_virtualAddr;
}
}
diff --git a/lib/ReaderWriter/ELF/FileCommon.cpp b/lib/ReaderWriter/ELF/FileCommon.cpp
new file mode 100644
index 000000000000..c23e3f6656cd
--- /dev/null
+++ b/lib/ReaderWriter/ELF/FileCommon.cpp
@@ -0,0 +1,66 @@
+//===- 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
new file mode 100644
index 000000000000..eaff12afe72f
--- /dev/null
+++ b/lib/ReaderWriter/ELF/FileCommon.h
@@ -0,0 +1,45 @@
+//===- 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
new file mode 100644
index 000000000000..193937c18061
--- /dev/null
+++ b/lib/ReaderWriter/ELF/HeaderChunks.cpp
@@ -0,0 +1,205 @@
+//===- 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
index eab132b9b2f6..51fbe38f1a00 100644
--- a/lib/ReaderWriter/ELF/HeaderChunks.h
+++ b/lib/ReaderWriter/ELF/HeaderChunks.h
@@ -11,18 +11,18 @@
#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/Debug.h"
#include "llvm/Support/ELF.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileOutputBuffer.h"
-#include "llvm/Support/Format.h"
/// \brief An Header represents the Elf[32/64]_Ehdr structure at the
/// start of an ELF executable file.
namespace lld {
namespace elf {
+
template <class ELFT> class ELFHeader : public Chunk<ELFT> {
public:
typedef llvm::object::Elf_Ehdr_Impl<ELFT> Elf_Ehdr;
@@ -33,9 +33,9 @@ public:
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_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; }
@@ -43,57 +43,25 @@ public:
void e_shentsize(uint16_t shentsize) { _eh.e_shentsize = shentsize; }
void e_shnum(uint16_t shnum) { _eh.e_shnum = shnum; }
void e_shstrndx(uint16_t shstrndx) { _eh.e_shstrndx = shstrndx; }
- uint64_t fileSize() const { return sizeof(Elf_Ehdr); }
+ uint64_t fileSize() const override { return sizeof(Elf_Ehdr); }
static bool classof(const Chunk<ELFT> *c) {
- return c->Kind() == Chunk<ELFT>::Kind::ELFHeader;
+ return c->kind() == Chunk<ELFT>::Kind::ELFHeader;
}
- int getContentType() const { return Chunk<ELFT>::ContentType::Header; }
+ int getContentType() const override {
+ return Chunk<ELFT>::ContentType::Header;
+ }
void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
- llvm::FileOutputBuffer &buffer);
-
- virtual void doPreFlight() {}
-
- void finalize() {
- _eh.e_ident[llvm::ELF::EI_CLASS] =
- (ELFT::Is64Bits) ? llvm::ELF::ELFCLASS64 : llvm::ELF::ELFCLASS32;
- _eh.e_ident[llvm::ELF::EI_DATA] =
- (ELFT::TargetEndianness == llvm::support::little)
- ? llvm::ELF::ELFDATA2LSB
- : llvm::ELF::ELFDATA2MSB;
- _eh.e_type = this->_context.getOutputELFType();
- _eh.e_machine = this->_context.getOutputMachine();
- }
+ llvm::FileOutputBuffer &buffer) override;
+
+ void finalize() override;
private:
Elf_Ehdr _eh;
};
-template <class ELFT>
-ELFHeader<ELFT>::ELFHeader(const ELFLinkingContext &context)
- : Chunk<ELFT>("elfhdr", Chunk<ELFT>::Kind::ELFHeader, context) {
- this->_alignment = ELFT::Is64Bits ? 8 : 4;
- this->_fsize = sizeof(Elf_Ehdr);
- this->_msize = sizeof(Elf_Ehdr);
- memset(_eh.e_ident, 0, llvm::ELF::EI_NIDENT);
- e_ident(llvm::ELF::EI_MAG0, 0x7f);
- e_ident(llvm::ELF::EI_MAG1, 'E');
- e_ident(llvm::ELF::EI_MAG2, 'L');
- e_ident(llvm::ELF::EI_MAG3, 'F');
- e_ehsize(sizeof(Elf_Ehdr));
- e_flags(0);
-}
-
-template <class ELFT>
-void ELFHeader<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout,
- llvm::FileOutputBuffer &buffer) {
- uint8_t *chunkBuffer = buffer.getBufferStart();
- uint8_t *atomContent = chunkBuffer + this->fileOffset();
- memcpy(atomContent, &_eh, fileSize());
-}
-
/// \brief An ProgramHeader represents the Elf[32/64]_Phdr structure at the
/// start of an ELF executable file.
template<class ELFT>
@@ -103,160 +71,43 @@ public:
typedef typename std::vector<Elf_Phdr *>::iterator PhIterT;
typedef typename std::reverse_iterator<PhIterT> ReversePhIterT;
- /// \brief Find a program header entry, given the type of entry that
- /// we are looking for
- class FindPhdr {
- public:
- FindPhdr(uint64_t type, uint64_t flags, uint64_t flagsClear)
- : _type(type)
- , _flags(flags)
- , _flagsClear(flagsClear) {
- }
-
- bool operator()(const llvm::object::Elf_Phdr_Impl<ELFT> *j) const {
- return ((j->p_type == _type) &&
- ((j->p_flags & _flags) == _flags) &&
- (!(j->p_flags & _flagsClear)));
- }
- private:
- uint64_t _type;
- uint64_t _flags;
- uint64_t _flagsClear;
- };
-
- ProgramHeader(const ELFLinkingContext &context)
- : Chunk<ELFT>("elfphdr", Chunk<ELFT>::Kind::ProgramHeader, context) {
+ 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 { return sizeof(Elf_Phdr) * _ph.size(); }
+ 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;
+ return c->kind() == Chunk<ELFT>::Kind::ProgramHeader;
}
void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
- llvm::FileOutputBuffer &buffer);
-
- /// \brief find a program header entry in the list of program headers
- ReversePhIterT
- findProgramHeader(uint64_t type, uint64_t flags, uint64_t flagClear) {
- return std::find_if(_ph.rbegin(), _ph.rend(),
- FindPhdr(type, flags, flagClear));
- }
-
- PhIterT begin() {
- return _ph.begin();
- }
-
- PhIterT end() {
- return _ph.end();
- }
+ llvm::FileOutputBuffer &buffer) override;
+ PhIterT begin() { return _ph.begin(); }
+ PhIterT end() { return _ph.end(); }
ReversePhIterT rbegin() { return _ph.rbegin(); }
-
ReversePhIterT rend() { return _ph.rend(); }
- virtual void doPreFlight() {}
-
- void finalize() {}
-
int64_t entsize() { return sizeof(Elf_Phdr); }
+ int64_t numHeaders() { return _ph.size(); }
- int64_t numHeaders() {
- return _ph.size();
+ int getContentType() const override {
+ return Chunk<ELFT>::ContentType::Header;
}
- int getContentType() const { return Chunk<ELFT>::ContentType::Header; }
-
private:
- Elf_Phdr *allocateProgramHeader(bool &allocatedNew) {
- Elf_Phdr *phdr;
- if (_phi == _ph.end()) {
- phdr = new (_allocator) Elf_Phdr;
- _ph.push_back(phdr);
- _phi = _ph.end();
- allocatedNew = true;
- } else {
- phdr = (*_phi);
- ++_phi;
- }
- return phdr;
- }
+ Elf_Phdr *allocateProgramHeader(bool &allocatedNew);
std::vector<Elf_Phdr *> _ph;
PhIterT _phi;
llvm::BumpPtrAllocator _allocator;
};
-template <class ELFT>
-bool ProgramHeader<ELFT>::addSegment(Segment<ELFT> *segment) {
- bool allocatedNew = false;
- ELFLinkingContext::OutputMagic outputMagic = this->_context.getOutputMagic();
- // For segments that are not a loadable segment, we
- // just pick the values directly from the segment as there
- // wouldnt be any slices within that
- if (segment->segmentType() != llvm::ELF::PT_LOAD) {
- Elf_Phdr *phdr = allocateProgramHeader(allocatedNew);
- phdr->p_type = segment->segmentType();
- phdr->p_offset = segment->fileOffset();
- phdr->p_vaddr = segment->virtualAddr();
- phdr->p_paddr = segment->virtualAddr();
- phdr->p_filesz = segment->fileSize();
- phdr->p_memsz = segment->memSize();
- phdr->p_flags = segment->flags();
- phdr->p_align = segment->alignment();
- this->_fsize = fileSize();
- this->_msize = this->_fsize;
- return allocatedNew;
- }
- // For all other segments, use the slice
- // to derive program headers
- for (auto slice : segment->slices()) {
- Elf_Phdr *phdr = allocateProgramHeader(allocatedNew);
- phdr->p_type = segment->segmentType();
- phdr->p_offset = slice->fileOffset();
- phdr->p_vaddr = slice->virtualAddr();
- phdr->p_paddr = slice->virtualAddr();
- phdr->p_filesz = slice->fileSize();
- phdr->p_memsz = slice->memSize();
- phdr->p_flags = segment->flags();
- phdr->p_align = slice->alignment();
- uint64_t segPageSize = segment->pageSize();
- uint64_t sliceAlign = slice->alignment();
- // Alignment of PT_LOAD segments are set to the page size, but if the
- // alignment of the slice is greater than the page size, set the alignment
- // of the segment appropriately.
- if (outputMagic != ELFLinkingContext::OutputMagic::NMAGIC &&
- outputMagic != ELFLinkingContext::OutputMagic::OMAGIC) {
- phdr->p_align = (phdr->p_type == llvm::ELF::PT_LOAD)
- ? (segPageSize < sliceAlign) ? sliceAlign : segPageSize
- : sliceAlign;
- } else
- phdr->p_align = slice->alignment();
- }
- this->_fsize = fileSize();
- this->_msize = this->_fsize;
-
- return allocatedNew;
-}
-
-template <class ELFT>
-void ProgramHeader<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout,
- llvm::FileOutputBuffer &buffer) {
- uint8_t *chunkBuffer = buffer.getBufferStart();
- uint8_t *dest = chunkBuffer + this->fileOffset();
- for (auto phi : _ph) {
- memcpy(dest, phi, sizeof(Elf_Phdr));
- dest += sizeof(Elf_Phdr);
- }
-}
-
/// \brief An SectionHeader represents the Elf[32/64]_Shdr structure
/// at the end of the file
template<class ELFT>
@@ -265,13 +116,11 @@ public:
typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr;
SectionHeader(const ELFLinkingContext &, int32_t order);
-
void appendSection(OutputSection<ELFT> *section);
-
void updateSection(Section<ELFT> *section);
static bool classof(const Chunk<ELFT> *c) {
- return c->getChunkKind() == Chunk<ELFT>::Kind::SectionHeader;
+ return c->kind() == Chunk<ELFT>::Kind::SectionHeader;
}
void setStringSection(StringTable<ELFT> *s) {
@@ -279,85 +128,26 @@ public:
}
void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
- llvm::FileOutputBuffer &buffer);
+ llvm::FileOutputBuffer &buffer) override;
- virtual void doPreFlight() {}
-
- void finalize() {}
-
- uint64_t fileSize() const { return sizeof(Elf_Shdr) * _sectionInfo.size(); }
+ uint64_t fileSize() const override {
+ return sizeof(Elf_Shdr) * _sectionInfo.size();
+ }
uint64_t entsize() { return sizeof(Elf_Shdr); }
- int getContentType() const { return Chunk<ELFT>::ContentType::Header; }
+ 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;
+ std::vector<Elf_Shdr *> _sectionInfo;
+ llvm::BumpPtrAllocator _sectionAllocate;
};
-template <class ELFT>
-SectionHeader<ELFT>::SectionHeader(const ELFLinkingContext &context,
- int32_t order)
- : Chunk<ELFT>("shdr", Chunk<ELFT>::Kind::SectionHeader, context) {
- this->_fsize = 0;
- this->_alignment = 8;
- this->setOrder(order);
- // The first element in the list is always NULL
- Elf_Shdr *nullshdr = new (_sectionAllocate.Allocate<Elf_Shdr>()) Elf_Shdr;
- ::memset(nullshdr, 0, sizeof (Elf_Shdr));
- _sectionInfo.push_back(nullshdr);
- this->_fsize += sizeof (Elf_Shdr);
-}
-
-template <class ELFT>
-void SectionHeader<ELFT>::appendSection(OutputSection<ELFT> *section) {
- Elf_Shdr *shdr = new (_sectionAllocate.Allocate<Elf_Shdr>()) Elf_Shdr;
- shdr->sh_name = _stringSection->addString(section->name());
- shdr->sh_type = section->type();
- shdr->sh_flags = section->flags();
- shdr->sh_offset = section->fileOffset();
- shdr->sh_addr = section->virtualAddr();
- if (section->isLoadableSection())
- shdr->sh_size = section->memSize();
- else
- shdr->sh_size = section->fileSize();
- shdr->sh_link = section->link();
- shdr->sh_info = section->shinfo();
- shdr->sh_addralign = section->alignment();
- shdr->sh_entsize = section->entsize();
- _sectionInfo.push_back(shdr);
-}
-
-template<class ELFT>
-void
-SectionHeader<ELFT>::updateSection(Section<ELFT> *section) {
- Elf_Shdr *shdr = _sectionInfo[section->ordinal()];
- shdr->sh_type = section->getType();
- shdr->sh_flags = section->getFlags();
- shdr->sh_offset = section->fileOffset();
- shdr->sh_addr = section->virtualAddr();
- shdr->sh_size = section->fileSize();
- shdr->sh_link = section->getLink();
- shdr->sh_info = section->getInfo();
- shdr->sh_addralign = section->alignment();
- shdr->sh_entsize = section->getEntSize();
-}
-
-template <class ELFT>
-void SectionHeader<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout,
- llvm::FileOutputBuffer &buffer) {
- uint8_t *chunkBuffer = buffer.getBufferStart();
- uint8_t *dest = chunkBuffer + this->fileOffset();
- for (auto shi : _sectionInfo) {
- memcpy(dest, shi, sizeof(Elf_Shdr));
- dest += sizeof(Elf_Shdr);
- }
- _stringSection->write(writer, layout, buffer);
-}
} // end namespace elf
} // end namespace lld
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonDynamicLibraryWriter.h b/lib/ReaderWriter/ELF/Hexagon/HexagonDynamicLibraryWriter.h
index e2d3193045b7..84415b273f44 100644
--- a/lib/ReaderWriter/ELF/Hexagon/HexagonDynamicLibraryWriter.h
+++ b/lib/ReaderWriter/ELF/Hexagon/HexagonDynamicLibraryWriter.h
@@ -10,67 +10,55 @@
#define HEXAGON_DYNAMIC_LIBRARY_WRITER_H
#include "DynamicLibraryWriter.h"
-#include "HexagonExecutableAtoms.h"
#include "HexagonLinkingContext.h"
namespace lld {
namespace elf {
-template <typename ELFT> class HexagonTargetLayout;
+class HexagonTargetLayout;
-template <class ELFT>
-class HexagonDynamicLibraryWriter : public DynamicLibraryWriter<ELFT>,
- public HexagonELFWriter<ELFT> {
+class HexagonDynamicLibraryWriter : public DynamicLibraryWriter<ELF32LE> {
public:
- HexagonDynamicLibraryWriter(HexagonLinkingContext &context,
- HexagonTargetLayout<ELFT> &layout);
+ HexagonDynamicLibraryWriter(HexagonLinkingContext &ctx,
+ HexagonTargetLayout &layout);
protected:
// Add any runtime files and their atoms to the output
- virtual bool createImplicitFiles(std::vector<std::unique_ptr<File>> &);
+ void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
- virtual void finalizeDefaultAtomValues();
+ void finalizeDefaultAtomValues() override;
- virtual std::error_code setELFHeader() {
- DynamicLibraryWriter<ELFT>::setELFHeader();
- HexagonELFWriter<ELFT>::setELFHeader(*this->_elfHeader);
+ std::error_code setELFHeader() override {
+ DynamicLibraryWriter::setELFHeader();
+ setHexagonELFHeader(*_elfHeader);
return std::error_code();
}
private:
- void addDefaultAtoms() {
- _hexagonRuntimeFile->addAbsoluteAtom("_GLOBAL_OFFSET_TABLE_");
- _hexagonRuntimeFile->addAbsoluteAtom("_DYNAMIC");
- }
-
- HexagonLinkingContext &_hexagonLinkingContext;
- HexagonTargetLayout<ELFT> &_hexagonTargetLayout;
- std::unique_ptr<HexagonRuntimeFile<ELFT>> _hexagonRuntimeFile;
+ HexagonLinkingContext &_ctx;
+ HexagonTargetLayout &_targetLayout;
};
-template <class ELFT>
-HexagonDynamicLibraryWriter<ELFT>::HexagonDynamicLibraryWriter(
- HexagonLinkingContext &context, HexagonTargetLayout<ELFT> &layout)
- : DynamicLibraryWriter<ELFT>(context, layout),
- HexagonELFWriter<ELFT>(context, layout), _hexagonLinkingContext(context),
- _hexagonTargetLayout(layout),
- _hexagonRuntimeFile(new HexagonRuntimeFile<ELFT>(context)) {}
+HexagonDynamicLibraryWriter::HexagonDynamicLibraryWriter(
+ HexagonLinkingContext &ctx, HexagonTargetLayout &layout)
+ : DynamicLibraryWriter(ctx, layout), _ctx(ctx), _targetLayout(layout) {}
-template <class ELFT>
-bool HexagonDynamicLibraryWriter<ELFT>::createImplicitFiles(
+void HexagonDynamicLibraryWriter::createImplicitFiles(
std::vector<std::unique_ptr<File>> &result) {
- DynamicLibraryWriter<ELFT>::createImplicitFiles(result);
+ DynamicLibraryWriter::createImplicitFiles(result);
// Add the default atoms as defined for hexagon
- addDefaultAtoms();
- result.push_back(std::move(_hexagonRuntimeFile));
- return true;
+ 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));
}
-template <class ELFT>
-void HexagonDynamicLibraryWriter<ELFT>::finalizeDefaultAtomValues() {
+void HexagonDynamicLibraryWriter::finalizeDefaultAtomValues() {
// Finalize the atom values that are part of the parent.
- DynamicLibraryWriter<ELFT>::finalizeDefaultAtomValues();
- HexagonELFWriter<ELFT>::finalizeHexagonRuntimeAtomValues();
+ DynamicLibraryWriter::finalizeDefaultAtomValues();
+ if (_ctx.isDynamic())
+ finalizeHexagonRuntimeAtomValues(_targetLayout);
}
} // namespace elf
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonELFFile.h b/lib/ReaderWriter/ELF/Hexagon/HexagonELFFile.h
index ab0b9b432b43..3d0d38f387dd 100644
--- a/lib/ReaderWriter/ELF/Hexagon/HexagonELFFile.h
+++ b/lib/ReaderWriter/ELF/Hexagon/HexagonELFFile.h
@@ -16,53 +16,46 @@
namespace lld {
namespace elf {
-template <class ELFT> class HexagonELFFile;
+class HexagonELFFile;
-template <class ELFT>
-class HexagonELFDefinedAtom : public ELFDefinedAtom<ELFT> {
- typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
- typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr;
+class HexagonELFDefinedAtom : public ELFDefinedAtom<ELF32LE> {
+ typedef llvm::object::Elf_Sym_Impl<ELF32LE> Elf_Sym;
+ typedef llvm::object::Elf_Shdr_Impl<ELF32LE> Elf_Shdr;
public:
- HexagonELFDefinedAtom(const HexagonELFFile<ELFT> &file, StringRef symbolName,
- StringRef sectionName, const Elf_Sym *symbol,
- const Elf_Shdr *section, ArrayRef<uint8_t> contentData,
- unsigned int referenceStart, unsigned int referenceEnd,
- std::vector<ELFReference<ELFT> *> &referenceList)
- : ELFDefinedAtom<ELFT>(file, symbolName, sectionName, symbol, section,
- contentData, referenceStart, referenceEnd,
- referenceList) {}
-
- virtual DefinedAtom::ContentType contentType() const {
- if (this->_contentType != DefinedAtom::typeUnknown)
- return this->_contentType;
- else if (this->_section->sh_flags & llvm::ELF::SHF_HEX_GPREL) {
- if (this->_section->sh_type == llvm::ELF::SHT_NOBITS)
- return (this->_contentType = DefinedAtom::typeZeroFillFast);
- else
- return (this->_contentType = DefinedAtom::typeDataFast);
+ 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<ELFT>::contentType();
+ return ELFDefinedAtom::contentType();
}
- virtual DefinedAtom::ContentPermissions permissions() const {
- if (this->_section->sh_flags & llvm::ELF::SHF_HEX_GPREL)
+ DefinedAtom::ContentPermissions permissions() const override {
+ if (_section->sh_flags & llvm::ELF::SHF_HEX_GPREL)
return DefinedAtom::permRW_;
- return ELFDefinedAtom<ELFT>::permissions();
+ return ELFDefinedAtom::permissions();
}
};
-template <class ELFT> class HexagonELFCommonAtom : public ELFCommonAtom<ELFT> {
- typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
- typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr;
+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 HexagonELFFile<ELFT> &file, StringRef symbolName,
+ HexagonELFCommonAtom(const ELFFile<ELF32LE> &file, StringRef symbolName,
const Elf_Sym *symbol)
- : ELFCommonAtom<ELFT>(file, symbolName, symbol) {}
+ : ELFCommonAtom(file, symbolName, symbol) {}
virtual bool isSmallCommonSymbol() const {
- switch (this->_symbol->st_shndx) {
+ switch (_symbol->st_shndx) {
// Common symbols
case llvm::ELF::SHN_HEXAGON_SCOMMON:
case llvm::ELF::SHN_HEXAGON_SCOMMON_1:
@@ -76,52 +69,46 @@ public:
return false;
}
- virtual uint64_t size() const {
+ uint64_t size() const override {
if (isSmallCommonSymbol())
- return this->_symbol->st_size;
- return ELFCommonAtom<ELFT>::size();
+ return _symbol->st_size;
+ return ELFCommonAtom::size();
}
- virtual DefinedAtom::Merge merge() const {
- if (this->_symbol->getBinding() == llvm::ELF::STB_WEAK)
+ DefinedAtom::Merge merge() const override {
+ if (_symbol->getBinding() == llvm::ELF::STB_WEAK)
return DefinedAtom::mergeAsWeak;
if (isSmallCommonSymbol())
return DefinedAtom::mergeAsTentative;
- return ELFCommonAtom<ELFT>::merge();
+ return ELFCommonAtom::merge();
}
- virtual DefinedAtom::ContentType contentType() const {
+ DefinedAtom::ContentType contentType() const override {
if (isSmallCommonSymbol())
return DefinedAtom::typeZeroFillFast;
- return ELFCommonAtom<ELFT>::contentType();
+ return ELFCommonAtom::contentType();
}
- virtual DefinedAtom::Alignment alignment() const {
+ DefinedAtom::Alignment alignment() const override {
if (isSmallCommonSymbol())
- return DefinedAtom::Alignment(llvm::Log2_64(this->_symbol->st_value));
- return ELFCommonAtom<ELFT>::alignment();
+ return DefinedAtom::Alignment(_symbol->st_value);
+ return 1;
}
- virtual DefinedAtom::ContentPermissions permissions() const {
+ DefinedAtom::ContentPermissions permissions() const override {
if (isSmallCommonSymbol())
return DefinedAtom::permRW_;
- return ELFCommonAtom<ELFT>::permissions();
+ return ELFCommonAtom::permissions();
}
};
-template <class ELFT> class HexagonELFFile : public ELFFile<ELFT> {
- typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
- typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr;
+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, HexagonLinkingContext &ctx)
- : ELFFile<ELFT>(std::move(mb), ctx) {}
-
- static ErrorOr<std::unique_ptr<HexagonELFFile>>
- create(std::unique_ptr<MemoryBuffer> mb, HexagonLinkingContext &ctx) {
- return std::unique_ptr<HexagonELFFile<ELFT>>(
- new HexagonELFFile<ELFT>(std::move(mb), ctx));
- }
+ 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) {
@@ -135,35 +122,27 @@ public:
default:
break;
}
- return ELFFile<ELFT>::isCommonSymbol(symbol);
+ return ELFFile::isCommonSymbol(symbol);
}
/// Process the Defined symbol and create an atom for it.
- ErrorOr<ELFDefinedAtom<ELFT> *>
- handleDefinedSymbol(StringRef symName, StringRef sectionName,
- const Elf_Sym *sym, const Elf_Shdr *sectionHdr,
- ArrayRef<uint8_t> contentData,
- unsigned int referenceStart, unsigned int referenceEnd,
- std::vector<ELFReference<ELFT> *> &referenceList) override {
- return new (this->_readerStorage) HexagonELFDefinedAtom<ELFT>(
+ 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.
- ErrorOr<ELFCommonAtom<ELFT> *>
- handleCommonSymbol(StringRef symName, const Elf_Sym *sym) override {
- return new (this->_readerStorage)
- HexagonELFCommonAtom<ELFT>(*this, symName, sym);
+ ELFCommonAtom<ELF32LE> *createCommonAtom(StringRef symName,
+ const Elf_Sym *sym) override {
+ return new (_readerStorage) HexagonELFCommonAtom(*this, symName, sym);
}
};
-template <class ELFT> class HexagonDynamicFile : public DynamicFile<ELFT> {
-public:
- HexagonDynamicFile(const HexagonLinkingContext &context, StringRef name)
- : DynamicFile<ELFT>(context, name) {}
-};
-
} // elf
} // lld
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonELFReader.h b/lib/ReaderWriter/ELF/Hexagon/HexagonELFReader.h
deleted file mode 100644
index 1a4f891df799..000000000000
--- a/lib/ReaderWriter/ELF/Hexagon/HexagonELFReader.h
+++ /dev/null
@@ -1,62 +0,0 @@
-//===- lib/ReaderWriter/ELF/HexagonELFReader.h ----------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_HEXAGON_ELF_READER_H
-#define LLD_READER_WRITER_HEXAGON_ELF_READER_H
-
-#include "ELFReader.h"
-#include "HexagonELFFile.h"
-
-namespace lld {
-namespace elf {
-
-typedef llvm::object::ELFType<llvm::support::little, 2, false> HexagonELFType;
-
-struct HexagonDynamicFileCreateELFTraits {
- typedef llvm::ErrorOr<std::unique_ptr<lld::SharedLibraryFile>> result_type;
-
- template <class ELFT>
- static result_type create(std::unique_ptr<llvm::MemoryBuffer> mb,
- HexagonLinkingContext &ctx) {
- return lld::elf::HexagonDynamicFile<ELFT>::create(std::move(mb), ctx);
- }
-};
-
-struct HexagonELFFileCreateELFTraits {
- typedef llvm::ErrorOr<std::unique_ptr<lld::File>> result_type;
-
- template <class ELFT>
- static result_type create(std::unique_ptr<llvm::MemoryBuffer> mb,
- HexagonLinkingContext &ctx) {
- return lld::elf::HexagonELFFile<ELFT>::create(std::move(mb), ctx);
- }
-};
-
-class HexagonELFObjectReader
- : public ELFObjectReader<HexagonELFType, HexagonELFFileCreateELFTraits,
- HexagonLinkingContext> {
-public:
- HexagonELFObjectReader(HexagonLinkingContext &ctx)
- : ELFObjectReader<HexagonELFType, HexagonELFFileCreateELFTraits,
- HexagonLinkingContext>(ctx, llvm::ELF::EM_HEXAGON) {}
-};
-
-class HexagonELFDSOReader
- : public ELFDSOReader<HexagonELFType, HexagonDynamicFileCreateELFTraits,
- HexagonLinkingContext> {
-public:
- HexagonELFDSOReader(HexagonLinkingContext &ctx)
- : ELFDSOReader<HexagonELFType, HexagonDynamicFileCreateELFTraits,
- HexagonLinkingContext>(ctx, llvm::ELF::EM_HEXAGON) {}
-};
-
-} // namespace elf
-} // namespace lld
-
-#endif // LLD_READER_WRITER_ELF_READER_H
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonELFWriters.h b/lib/ReaderWriter/ELF/Hexagon/HexagonELFWriters.h
deleted file mode 100644
index 96c74f72222d..000000000000
--- a/lib/ReaderWriter/ELF/Hexagon/HexagonELFWriters.h
+++ /dev/null
@@ -1,61 +0,0 @@
-//===- lib/ReaderWriter/ELF/Hexagon/HexagonELFWriters.h -------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef HEXAGON_ELF_WRITERS_H
-#define HEXAGON_ELF_WRITERS_H
-
-#include "HexagonLinkingContext.h"
-#include "OutputELFWriter.h"
-
-namespace lld {
-namespace elf {
-
-template <class ELFT> class HexagonTargetLayout;
-
-template <typename ELFT> class HexagonELFWriter {
-public:
- HexagonELFWriter(HexagonLinkingContext &context,
- HexagonTargetLayout<ELFT> &targetLayout)
- : _hexagonLinkingContext(context), _hexagonTargetLayout(targetLayout) {}
-
-protected:
- bool setELFHeader(ELFHeader<ELFT> &elfHeader) {
- elfHeader.e_ident(llvm::ELF::EI_VERSION, 1);
- elfHeader.e_ident(llvm::ELF::EI_OSABI, 0);
- elfHeader.e_version(1);
- elfHeader.e_flags(0x3);
- return true;
- }
-
- void finalizeHexagonRuntimeAtomValues() {
- if (_hexagonLinkingContext.isDynamic()) {
- auto gotAtomIter =
- _hexagonTargetLayout.findAbsoluteAtom("_GLOBAL_OFFSET_TABLE_");
- auto gotpltSection = _hexagonTargetLayout.findOutputSection(".got.plt");
- if (gotpltSection)
- (*gotAtomIter)->_virtualAddr = gotpltSection->virtualAddr();
- else
- (*gotAtomIter)->_virtualAddr = 0;
- auto dynamicAtomIter = _hexagonTargetLayout.findAbsoluteAtom("_DYNAMIC");
- auto dynamicSection = _hexagonTargetLayout.findOutputSection(".dynamic");
- if (dynamicSection)
- (*dynamicAtomIter)->_virtualAddr = dynamicSection->virtualAddr();
- else
- (*dynamicAtomIter)->_virtualAddr = 0;
- }
- }
-
-private:
- HexagonLinkingContext &_hexagonLinkingContext;
- HexagonTargetLayout<ELFT> &_hexagonTargetLayout;
-};
-
-} // elf
-} // lld
-#endif // HEXAGON_ELF_WRITERS_H
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonEncodings.h b/lib/ReaderWriter/ELF/Hexagon/HexagonEncodings.h
index 3e12786704a2..6af43d88afbb 100644
--- a/lib/ReaderWriter/ELF/Hexagon/HexagonEncodings.h
+++ b/lib/ReaderWriter/ELF/Hexagon/HexagonEncodings.h
@@ -6,7 +6,27 @@
// 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 },
@@ -599,3 +619,20 @@ Instruction insn_encodings[] = {
{ 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/HexagonExecutableAtoms.h b/lib/ReaderWriter/ELF/Hexagon/HexagonExecutableAtoms.h
deleted file mode 100644
index a2505aa460c5..000000000000
--- a/lib/ReaderWriter/ELF/Hexagon/HexagonExecutableAtoms.h
+++ /dev/null
@@ -1,29 +0,0 @@
-//===- lib/ReaderWriter/ELF/Hexagon/HexagonExecutableAtoms.h --------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_EXECUTABLE_ATOM_H
-#define LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_EXECUTABLE_ATOM_H
-
-#include "ELFFile.h"
-
-namespace lld {
-namespace elf {
-typedef llvm::object::ELFType<llvm::support::little, 2, false> HexagonELFType;
-class HexagonLinkingContext;
-
-template <class HexagonELFType> class HexagonRuntimeFile
- : public RuntimeFile<HexagonELFType> {
-public:
- HexagonRuntimeFile(HexagonLinkingContext &context)
- : RuntimeFile<HexagonELFType>(context, "Hexagon runtime file") {}
-};
-} // elf
-} // lld
-
-#endif // LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_EXECUTABLE_ATOM_H
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonExecutableWriter.h b/lib/ReaderWriter/ELF/Hexagon/HexagonExecutableWriter.h
index 0848e64166fa..390694954a75 100644
--- a/lib/ReaderWriter/ELF/Hexagon/HexagonExecutableWriter.h
+++ b/lib/ReaderWriter/ELF/Hexagon/HexagonExecutableWriter.h
@@ -10,74 +10,61 @@
#define HEXAGON_EXECUTABLE_WRITER_H
#include "ExecutableWriter.h"
-#include "HexagonELFWriters.h"
-#include "HexagonExecutableAtoms.h"
#include "HexagonLinkingContext.h"
+#include "HexagonTargetHandler.h"
namespace lld {
namespace elf {
-template <typename ELFT> class HexagonTargetLayout;
+class HexagonTargetLayout;
-template <class ELFT>
-class HexagonExecutableWriter : public ExecutableWriter<ELFT>,
- public HexagonELFWriter<ELFT> {
+class HexagonExecutableWriter : public ExecutableWriter<ELF32LE> {
public:
- HexagonExecutableWriter(HexagonLinkingContext &context,
- HexagonTargetLayout<ELFT> &layout);
+ HexagonExecutableWriter(HexagonLinkingContext &ctx,
+ HexagonTargetLayout &layout);
protected:
// Add any runtime files and their atoms to the output
- virtual bool createImplicitFiles(std::vector<std::unique_ptr<File>> &);
+ void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
- virtual void finalizeDefaultAtomValues();
+ void finalizeDefaultAtomValues() override;
- virtual std::error_code setELFHeader() {
- ExecutableWriter<ELFT>::setELFHeader();
- HexagonELFWriter<ELFT>::setELFHeader(*this->_elfHeader);
+ std::error_code setELFHeader() override {
+ ExecutableWriter::setELFHeader();
+ setHexagonELFHeader(*_elfHeader);
return std::error_code();
}
private:
- void addDefaultAtoms() {
- _hexagonRuntimeFile->addAbsoluteAtom("_SDA_BASE_");
- if (this->_context.isDynamic()) {
- _hexagonRuntimeFile->addAbsoluteAtom("_GLOBAL_OFFSET_TABLE_");
- _hexagonRuntimeFile->addAbsoluteAtom("_DYNAMIC");
- }
- }
-
- HexagonLinkingContext &_hexagonLinkingContext;
- HexagonTargetLayout<ELFT> &_hexagonTargetLayout;
- std::unique_ptr<HexagonRuntimeFile<ELFT>> _hexagonRuntimeFile;
+ HexagonLinkingContext &_ctx;
+ HexagonTargetLayout &_targetLayout;
};
-template <class ELFT>
-HexagonExecutableWriter<ELFT>::HexagonExecutableWriter(
- HexagonLinkingContext &context, HexagonTargetLayout<ELFT> &layout)
- : ExecutableWriter<ELFT>(context, layout),
- HexagonELFWriter<ELFT>(context, layout), _hexagonLinkingContext(context),
- _hexagonTargetLayout(layout),
- _hexagonRuntimeFile(new HexagonRuntimeFile<ELFT>(context)) {}
+HexagonExecutableWriter::HexagonExecutableWriter(HexagonLinkingContext &ctx,
+ HexagonTargetLayout &layout)
+ : ExecutableWriter(ctx, layout), _ctx(ctx), _targetLayout(layout) {}
-template <class ELFT>
-bool HexagonExecutableWriter<ELFT>::createImplicitFiles(
+void HexagonExecutableWriter::createImplicitFiles(
std::vector<std::unique_ptr<File>> &result) {
- ExecutableWriter<ELFT>::createImplicitFiles(result);
+ ExecutableWriter::createImplicitFiles(result);
// Add the default atoms as defined for hexagon
- addDefaultAtoms();
- result.push_back(std::move(_hexagonRuntimeFile));
- return true;
+ 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));
}
-template <class ELFT>
-void HexagonExecutableWriter<ELFT>::finalizeDefaultAtomValues() {
+void HexagonExecutableWriter::finalizeDefaultAtomValues() {
// Finalize the atom values that are part of the parent.
- ExecutableWriter<ELFT>::finalizeDefaultAtomValues();
- auto sdabaseAtomIter = _hexagonTargetLayout.findAbsoluteAtom("_SDA_BASE_");
- (*sdabaseAtomIter)->_virtualAddr =
- _hexagonTargetLayout.getSDataSection()->virtualAddr();
- HexagonELFWriter<ELFT>::finalizeHexagonRuntimeAtomValues();
+ ExecutableWriter::finalizeDefaultAtomValues();
+ AtomLayout *sdabaseAtom = _targetLayout.findAbsoluteAtom("_SDA_BASE_");
+ sdabaseAtom->_virtualAddr = _targetLayout.getSDataSection()->virtualAddr();
+ if (_ctx.isDynamic())
+ finalizeHexagonRuntimeAtomValues(_targetLayout);
}
} // namespace elf
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.cpp b/lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.cpp
index 7eacb2b44c3b..11eabf7e26fc 100644
--- a/lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.cpp
+++ b/lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.cpp
@@ -10,16 +10,38 @@
#include "HexagonLinkingContext.h"
#include "HexagonTargetHandler.h"
-using namespace lld::elf;
+namespace lld {
+namespace elf {
-std::unique_ptr<lld::ELFLinkingContext>
-HexagonLinkingContext::create(llvm::Triple triple) {
+std::unique_ptr<ELFLinkingContext>
+createHexagonLinkingContext(llvm::Triple triple) {
if (triple.getArch() == llvm::Triple::hexagon)
- return std::unique_ptr<lld::ELFLinkingContext>(
- new HexagonLinkingContext(triple));
+ return llvm::make_unique<HexagonLinkingContext>(triple);
return nullptr;
}
HexagonLinkingContext::HexagonLinkingContext(llvm::Triple triple)
- : ELFLinkingContext(triple, std::unique_ptr<TargetHandlerBase>(
+ : 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
index c920cdf153aa..ab91e405fd56 100644
--- a/lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.h
+++ b/lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.h
@@ -10,6 +10,7 @@
#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"
@@ -17,14 +18,13 @@
namespace lld {
namespace elf {
-typedef llvm::object::ELFType<llvm::support::little, 2, false> HexagonELFType;
-
class HexagonLinkingContext final : public ELFLinkingContext {
public:
- static std::unique_ptr<ELFLinkingContext> create(llvm::Triple);
+ 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)
@@ -41,12 +41,7 @@ public:
bool isPLTRelocation(const Reference &r) const override {
if (r.kindNamespace() != Reference::KindNamespace::ELF)
return false;
- switch (r.kindValue()) {
- case llvm::ELF::R_HEX_JMP_SLOT:
- return true;
- default:
- return false;
- }
+ return r.kindValue() == llvm::ELF::R_HEX_JMP_SLOT;
}
/// \brief Hexagon has only one relative relocation
@@ -54,15 +49,12 @@ public:
bool isRelativeReloc(const Reference &r) const override {
if (r.kindNamespace() != Reference::KindNamespace::ELF)
return false;
- switch (r.kindValue()) {
- case llvm::ELF::R_HEX_RELATIVE:
- return true;
- default:
- return false;
- }
+ return r.kindValue() == llvm::ELF::R_HEX_RELATIVE;
}
};
+void setHexagonELFHeader(ELFHeader<ELF32LE> &elfHeader);
+
} // elf
} // lld
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationFunctions.h b/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationFunctions.h
deleted file mode 100644
index 2b9e25ce363b..000000000000
--- a/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationFunctions.h
+++ /dev/null
@@ -1,49 +0,0 @@
-//===- HexagonRelocationFunction.h ----------------------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_RELOCATION_FUNCTIONS_H
-#define LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_RELOCATION_FUNCTIONS_H
-
-namespace lld {
-namespace elf {
-
-/// \brief HexagonInstruction which is used to store various values
-typedef struct {
- uint32_t insnMask;
- uint32_t insnCmpMask;
- uint32_t insnBitMask;
- bool isDuplex;
-} Instruction;
-
-#include "HexagonEncodings.h"
-
-#define FINDV4BITMASK(INSN) \
- findBitMask((uint32_t) * ((llvm::support::ulittle32_t *) INSN), \
- insn_encodings, \
- sizeof(insn_encodings) / sizeof(Instruction))
-
-/// \brief finds the scatter Bits that need to be used to apply relocations
-inline uint32_t
-findBitMask(uint32_t insn, Instruction *encodings, int32_t numInsns) {
- for (int32_t i = 0; i < numInsns; i++) {
- if (((insn & 0xc000) == 0) && !(encodings[i].isDuplex))
- continue;
-
- if (((insn & 0xc000) != 0) && (encodings[i].isDuplex))
- continue;
-
- if (((encodings[i].insnMask) & insn) == encodings[i].insnCmpMask)
- return encodings[i].insnBitMask;
- }
- llvm_unreachable("found unknown instruction");
-}
-
-} // elf
-} // lld
-
-#endif // LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_RELOCATION_FUNCTIONS_H
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.cpp b/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.cpp
index 21967d356a31..0a201b32b5f1 100644
--- a/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.cpp
+++ b/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.cpp
@@ -7,10 +7,10 @@
//
//===----------------------------------------------------------------------===//
+#include "HexagonEncodings.h"
#include "HexagonLinkingContext.h"
-#include "HexagonRelocationFunctions.h"
-#include "HexagonTargetHandler.h"
#include "HexagonRelocationHandler.h"
+#include "HexagonTargetHandler.h"
#include "llvm/Support/Endian.h"
using namespace lld;
@@ -18,263 +18,250 @@ using namespace lld::elf;
using namespace llvm::ELF;
using namespace llvm::support::endian;
-#define APPLY_RELOC(result) \
- write32le(location, result | read32le(location));
+// 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 int relocBNPCREL(uint8_t *location, uint64_t P, uint64_t S, uint64_t A,
- int32_t nBits) {
- int32_t result = (uint32_t)(((S + A) - P) >> 2);
+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 = lld::scatterBits<int32_t>(result, FINDV4BITMASK(location));
- APPLY_RELOC(result);
- return 0;
+ result = scatterBits(result, findv4bitmask(loc));
+ write32le(loc, result | read32le(loc));
}
- return 1;
}
/// \brief Word32_LO: 0x00c03fff : (S + A) : Truncate
-static int relocLO16(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) {
- uint32_t result = (uint32_t)(S + A);
- result = lld::scatterBits<int32_t>(result, 0x00c03fff);
- APPLY_RELOC(result);
- return 0;
+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 int relocHI16(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) {
- uint32_t result = (uint32_t)((S + A) >> 16);
- result = lld::scatterBits<int32_t>(result, 0x00c03fff);
- APPLY_RELOC(result);
- return 0;
+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 int reloc32(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) {
- uint32_t result = (uint32_t)(S + A);
- APPLY_RELOC(result);
- return 0;
+static 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 int reloc32_6_X(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) {
- int64_t result = ((S + A) >> 6);
- int64_t range = ((int64_t)1) << 32;
+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)
- return 1;
- result = lld::scatterBits<int32_t>(result, 0xfff3fff);
- APPLY_RELOC(result);
- return 0;
+ result = scatterBits(result, 0xfff3fff);
+ write32le(loc, result | read32le(loc));
}
// R_HEX_B32_PCREL_X
-static int relocHexB32PCRELX(uint8_t *location, uint64_t P, uint64_t S,
- uint64_t A) {
- int64_t result = ((S + A - P) >> 6);
- result = lld::scatterBits<int32_t>(result, 0xfff3fff);
- APPLY_RELOC(result);
- return 0;
+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 int relocHexBNPCRELX(uint8_t *location, uint64_t P, uint64_t S,
- uint64_t A, int nbits) {
- int32_t result = ((S + A - P) & 0x3f);
+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 = lld::scatterBits<int32_t>(result, FINDV4BITMASK(location));
- APPLY_RELOC(result);
- return 0;
+ result = scatterBits(result, findv4bitmask(loc));
+ write32le(loc, result | read32le(loc));
}
- return 1;
}
// R_HEX_6_PCREL_X
-static int relocHex6PCRELX(uint8_t *location, uint64_t P, uint64_t S,
- uint64_t A) {
- int32_t result = (S + A - P);
- result = lld::scatterBits<int32_t>(result, FINDV4BITMASK(location));
- APPLY_RELOC(result);
- return 0;
+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 int relocHex_N_X(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) {
- uint32_t result = (S + A);
- result = lld::scatterBits<uint32_t>(result, FINDV4BITMASK(location));
- APPLY_RELOC(result);
- return 0;
+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 relocations
-static int relocHexGPRELN(uint8_t *location, uint64_t P, uint64_t S, uint64_t A,
- uint64_t GP, int nShiftBits) {
- int32_t result = (int64_t)((S + A - GP) >> nShiftBits);
+// 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 = lld::scatterBits<uint32_t>(result, FINDV4BITMASK(location));
- APPLY_RELOC(result);
- return 0;
+ result = scatterBits(result, findv4bitmask(loc));
+ write32le(loc, result | read32le(loc));
}
- return 1;
}
/// \brief Word32_LO: 0x00c03fff : (G) : Truncate
-static int relocHexGOTLO16(uint8_t *location, uint64_t A, uint64_t GOT) {
- int32_t result = (int32_t)(A-GOT);
- result = lld::scatterBits<int32_t>(result, 0x00c03fff);
- APPLY_RELOC(result);
- return 0;
+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 int relocHexGOTHI16(uint8_t *location, uint64_t A, uint64_t GOT) {
- int32_t result = (int32_t)((A-GOT) >> 16);
- result = lld::scatterBits<int32_t>(result, 0x00c03fff);
- APPLY_RELOC(result);
- return 0;
+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 int relocHexGOT32(uint8_t *location, uint64_t A, uint64_t GOT) {
- int32_t result = (int32_t)(GOT - A);
- APPLY_RELOC(result);
- return 0;
+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 int relocHexGOT16(uint8_t *location, uint64_t A, uint64_t GOT) {
- int32_t result = (int32_t)(GOT-A);
+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 = lld::scatterBits<int32_t>(result, FINDV4BITMASK(location));
- APPLY_RELOC(result);
- return 0;
+ result = scatterBits(result, findv4bitmask(loc));
+ write32le(loc, result | read32le(loc));
}
- return 1;
}
-static int relocHexGOT32_6_X(uint8_t *location, uint64_t A, uint64_t GOT) {
- int32_t result = (int32_t)((A-GOT) >> 6);
- result = lld::scatterBits<int32_t>(result, FINDV4BITMASK(location));
- APPLY_RELOC(result);
- return 0;
+static 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 int relocHexGOT16_X(uint8_t *location, uint64_t A, uint64_t GOT) {
- int32_t result = (int32_t)(A-GOT);
+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 = lld::scatterBits<int32_t>(result, FINDV4BITMASK(location));
- APPLY_RELOC(result);
- return 0;
+ result = scatterBits(result, findv4bitmask(loc));
+ write32le(loc, result | read32le(loc));
}
- return 1;
}
-static int relocHexGOT11_X(uint8_t *location, uint64_t A, uint64_t GOT) {
- uint32_t result = (uint32_t)(A-GOT);
- result = lld::scatterBits<uint32_t>(result, FINDV4BITMASK(location));
- APPLY_RELOC(result);
- return 0;
+static 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 int relocHexGOTRELSigned(uint8_t *location, uint64_t P, uint64_t S,
- uint64_t A, uint64_t GOT, int shiftBits = 0) {
- int32_t result = (int32_t)((S + A - GOT) >> shiftBits);
- result = lld::scatterBits<int32_t>(result, FINDV4BITMASK(location));
- APPLY_RELOC(result);
- return 0;
+static 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 int relocHexGOTRELUnsigned(uint8_t *location, uint64_t P, uint64_t S,
- uint64_t A, uint64_t GOT, int shiftBits = 0) {
- uint32_t result = (uint32_t)((S + A - GOT) >> shiftBits);
- result = lld::scatterBits<uint32_t>(result, FINDV4BITMASK(location));
- APPLY_RELOC(result);
- return 0;
+static 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 int relocHexGOTREL_HILO16(uint8_t *location, uint64_t P, uint64_t S,
- uint64_t A, uint64_t GOT, int shiftBits = 0) {
- int32_t result = (int32_t)((S + A - GOT) >> shiftBits);
- result = lld::scatterBits<int32_t>(result, 0x00c03fff);
- APPLY_RELOC(result);
- return 0;
+static 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 int relocHexGOTREL_32(uint8_t *location, uint64_t P, uint64_t S,
- uint64_t A, uint64_t GOT) {
- int32_t result = (int32_t)(S + A - GOT);
- APPLY_RELOC(result);
- return 0;
+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 lld::AtomLayout &atom,
+ ELFWriter &writer, llvm::FileOutputBuffer &buf, const AtomLayout &atom,
const Reference &ref) const {
uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset;
- uint8_t *location = atomContent + ref.offsetInAtom();
- uint64_t targetVAddress = writer.addressOfAtom(ref.target());
- uint64_t relocVAddress = atom._virtualAddr + ref.offsetInAtom();
+ 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(location, relocVAddress, targetVAddress, ref.addend(), 21);
+ relocBNPCREL(loc, reloc, target, ref.addend(), 21);
break;
case R_HEX_B15_PCREL:
- relocBNPCREL(location, relocVAddress, targetVAddress, ref.addend(), 14);
+ relocBNPCREL(loc, reloc, target, ref.addend(), 14);
break;
case R_HEX_B9_PCREL:
- relocBNPCREL(location, relocVAddress, targetVAddress, ref.addend(), 8);
+ relocBNPCREL(loc, reloc, target, ref.addend(), 8);
break;
case R_HEX_LO16:
- relocLO16(location, relocVAddress, targetVAddress, ref.addend());
+ relocLO16(loc, reloc, target, ref.addend());
break;
case R_HEX_HI16:
- relocHI16(location, relocVAddress, targetVAddress, ref.addend());
+ relocHI16(loc, reloc, target, ref.addend());
break;
case R_HEX_32:
- reloc32(location, relocVAddress, targetVAddress, ref.addend());
+ reloc32(loc, reloc, target, ref.addend());
break;
case R_HEX_32_6_X:
- reloc32_6_X(location, relocVAddress, targetVAddress, ref.addend());
+ reloc32_6_X(loc, reloc, target, ref.addend());
break;
case R_HEX_B32_PCREL_X:
- relocHexB32PCRELX(location, relocVAddress, targetVAddress, ref.addend());
+ relocHexB32PCRELX(loc, reloc, target, ref.addend());
break;
case R_HEX_B22_PCREL_X:
- relocHexBNPCRELX(location, relocVAddress, targetVAddress, ref.addend(), 21);
+ relocHexBNPCRELX(loc, reloc, target, ref.addend(), 21);
break;
case R_HEX_B15_PCREL_X:
- relocHexBNPCRELX(location, relocVAddress, targetVAddress, ref.addend(), 14);
+ relocHexBNPCRELX(loc, reloc, target, ref.addend(), 14);
break;
case R_HEX_B13_PCREL_X:
- relocHexBNPCRELX(location, relocVAddress, targetVAddress, ref.addend(), 12);
+ relocHexBNPCRELX(loc, reloc, target, ref.addend(), 12);
break;
case R_HEX_B9_PCREL_X:
- relocHexBNPCRELX(location, relocVAddress, targetVAddress, ref.addend(), 8);
+ relocHexBNPCRELX(loc, reloc, target, ref.addend(), 8);
break;
case R_HEX_B7_PCREL_X:
- relocHexBNPCRELX(location, relocVAddress, targetVAddress, ref.addend(), 6);
+ relocHexBNPCRELX(loc, reloc, target, ref.addend(), 6);
break;
case R_HEX_GPREL16_0:
- relocHexGPRELN(location, relocVAddress, targetVAddress, ref.addend(),
- _hexagonTargetLayout.getSDataSection()->virtualAddr(), 0);
+ relocHexGPRELN(loc, reloc, target, ref.addend(),
+ _targetLayout.getSDataSection()->virtualAddr(), 0);
break;
case R_HEX_GPREL16_1:
- relocHexGPRELN(location, relocVAddress, targetVAddress, ref.addend(),
- _hexagonTargetLayout.getSDataSection()->virtualAddr(), 1);
+ relocHexGPRELN(loc, reloc, target, ref.addend(),
+ _targetLayout.getSDataSection()->virtualAddr(), 1);
break;
case R_HEX_GPREL16_2:
- relocHexGPRELN(location, relocVAddress, targetVAddress, ref.addend(),
- _hexagonTargetLayout.getSDataSection()->virtualAddr(), 2);
+ relocHexGPRELN(loc, reloc, target, ref.addend(),
+ _targetLayout.getSDataSection()->virtualAddr(), 2);
break;
case R_HEX_GPREL16_3:
- relocHexGPRELN(location, relocVAddress, targetVAddress, ref.addend(),
- _hexagonTargetLayout.getSDataSection()->virtualAddr(), 3);
+ relocHexGPRELN(loc, reloc, target, ref.addend(),
+ _targetLayout.getSDataSection()->virtualAddr(), 3);
break;
case R_HEX_16_X:
case R_HEX_12_X:
@@ -284,62 +271,55 @@ std::error_code HexagonTargetRelocationHandler::applyRelocation(
case R_HEX_8_X:
case R_HEX_7_X:
case R_HEX_6_X:
- relocHex_N_X(location, relocVAddress, targetVAddress, ref.addend());
+ relocHex_N_X(loc, reloc, target, ref.addend());
break;
case R_HEX_6_PCREL_X:
- relocHex6PCRELX(location, relocVAddress, targetVAddress, ref.addend());
+ 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(location, relocVAddress, targetVAddress, ref.addend(),
- _hexagonTargetLayout.getGOTSymAddr());
+ relocHexGOTREL_32(loc, reloc, target, ref.addend(),
+ _targetLayout.getGOTSymAddr());
break;
case R_HEX_GOTREL_LO16:
- relocHexGOTREL_HILO16(location, relocVAddress, targetVAddress, ref.addend(),
- _hexagonTargetLayout.getGOTSymAddr());
+ relocHexGOTREL_HILO16(loc, reloc, target, ref.addend(),
+ _targetLayout.getGOTSymAddr(), 0);
break;
case R_HEX_GOTREL_HI16:
- relocHexGOTREL_HILO16(location, relocVAddress, targetVAddress, ref.addend(),
- _hexagonTargetLayout.getGOTSymAddr(), 16);
+ relocHexGOTREL_HILO16(loc, reloc, target, ref.addend(),
+ _targetLayout.getGOTSymAddr(), 16);
break;
case R_HEX_GOT_LO16:
- relocHexGOTLO16(location, targetVAddress,
- _hexagonTargetLayout.getGOTSymAddr());
+ relocHexGOTLO16(loc, target, _targetLayout.getGOTSymAddr());
break;
case R_HEX_GOT_HI16:
- relocHexGOTHI16(location, targetVAddress,
- _hexagonTargetLayout.getGOTSymAddr());
+ relocHexGOTHI16(loc, target, _targetLayout.getGOTSymAddr());
break;
case R_HEX_GOT_32:
- relocHexGOT32(location, targetVAddress,
- _hexagonTargetLayout.getGOTSymAddr());
+ relocHexGOT32(loc, target, _targetLayout.getGOTSymAddr());
break;
case R_HEX_GOT_16:
- relocHexGOT16(location, targetVAddress,
- _hexagonTargetLayout.getGOTSymAddr());
+ relocHexGOT16(loc, target, _targetLayout.getGOTSymAddr());
break;
case R_HEX_GOT_32_6_X:
- relocHexGOT32_6_X(location, targetVAddress,
- _hexagonTargetLayout.getGOTSymAddr());
+ relocHexGOT32_6_X(loc, target, _targetLayout.getGOTSymAddr());
break;
case R_HEX_GOT_16_X:
- relocHexGOT16_X(location, targetVAddress,
- _hexagonTargetLayout.getGOTSymAddr());
+ relocHexGOT16_X(loc, target, _targetLayout.getGOTSymAddr());
break;
case R_HEX_GOT_11_X:
- relocHexGOT11_X(location, targetVAddress,
- _hexagonTargetLayout.getGOTSymAddr());
+ relocHexGOT11_X(loc, target, _targetLayout.getGOTSymAddr());
break;
case R_HEX_GOTREL_32_6_X:
- relocHexGOTRELSigned(location, relocVAddress, targetVAddress, ref.addend(),
- _hexagonTargetLayout.getGOTSymAddr(), 6);
+ relocHexGOTRELSigned(loc, reloc, target, ref.addend(),
+ _targetLayout.getGOTSymAddr(), 6);
break;
case R_HEX_GOTREL_16_X:
case R_HEX_GOTREL_11_X:
- relocHexGOTRELUnsigned(location, relocVAddress, targetVAddress,
- ref.addend(), _hexagonTargetLayout.getGOTSymAddr());
+ relocHexGOTRELUnsigned(loc, reloc, target, ref.addend(),
+ _targetLayout.getGOTSymAddr());
break;
default:
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.h b/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.h
index 4795d0264b9c..6afba0ddb8f3 100644
--- a/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.h
+++ b/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.h
@@ -9,26 +9,24 @@
#ifndef LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_RELOCATION_HANDLER_H
#define LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_RELOCATION_HANDLER_H
-#include "HexagonSectionChunks.h"
-#include "HexagonTargetHandler.h"
-#include "lld/ReaderWriter/RelocationHelperFunctions.h"
+#include "lld/ReaderWriter/ELFLinkingContext.h"
namespace lld {
namespace elf {
-
class HexagonTargetHandler;
+class HexagonTargetLayout;
class HexagonTargetRelocationHandler final : public TargetRelocationHandler {
public:
- HexagonTargetRelocationHandler(HexagonTargetLayout<HexagonELFType> &layout)
- : _hexagonTargetLayout(layout) {}
+ HexagonTargetRelocationHandler(HexagonTargetLayout &layout)
+ : _targetLayout(layout) {}
std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &,
- const lld::AtomLayout &,
+ const AtomLayout &,
const Reference &) const override;
private:
- HexagonTargetLayout<HexagonELFType> &_hexagonTargetLayout;
+ HexagonTargetLayout &_targetLayout;
};
} // elf
} // lld
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonSectionChunks.h b/lib/ReaderWriter/ELF/Hexagon/HexagonSectionChunks.h
deleted file mode 100644
index 5b3fbbbd899b..000000000000
--- a/lib/ReaderWriter/ELF/Hexagon/HexagonSectionChunks.h
+++ /dev/null
@@ -1,86 +0,0 @@
-//===- lib/ReaderWriter/ELF/Hexagon/HexagonSectionChunks.h-----------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef HEXAGON_SECTION_CHUNKS_H
-#define HEXAGON_SECTION_CHUNKS_H
-
-#include "HexagonTargetHandler.h"
-
-namespace lld {
-namespace elf {
-template <typename ELFT> class HexagonTargetLayout;
-class HexagonLinkingContext;
-
-/// \brief Handle Hexagon SData section
-template <class HexagonELFType>
-class SDataSection : public AtomSection<HexagonELFType> {
-public:
- SDataSection(const HexagonLinkingContext &context)
- : AtomSection<HexagonELFType>(
- context, ".sdata", DefinedAtom::typeDataFast, 0,
- HexagonTargetLayout<HexagonELFType>::ORDER_SDATA) {
- this->_type = SHT_PROGBITS;
- this->_flags = SHF_ALLOC | SHF_WRITE;
- this->_alignment = 4096;
- }
-
- /// \brief Finalize the section contents before writing
- virtual void doPreFlight();
-
- /// \brief Does this section have an output segment.
- virtual bool hasOutputSegment() { return true; }
-
- const lld::AtomLayout *appendAtom(const Atom *atom) {
- const DefinedAtom *definedAtom = cast<DefinedAtom>(atom);
- DefinedAtom::Alignment atomAlign = definedAtom->alignment();
- uint64_t alignment = 1u << atomAlign.powerOf2;
- this->_atoms.push_back(new (this->_alloc) lld::AtomLayout(atom, 0, 0));
- // Set the section alignment to the largest alignment
- // std::max doesn't support uint64_t
- if (this->_alignment < alignment)
- this->_alignment = alignment;
- return (this->_atoms.back());
- }
-
-}; // SDataSection
-
-template <class HexagonELFType>
-void SDataSection<HexagonELFType>::doPreFlight() {
- // sort the atoms on the alignments they have been set
- std::stable_sort(this->_atoms.begin(), this->_atoms.end(),
- [](const lld::AtomLayout * A,
- const lld::AtomLayout * B) {
- const DefinedAtom *definedAtomA = cast<DefinedAtom>(A->_atom);
- const DefinedAtom *definedAtomB = cast<DefinedAtom>(B->_atom);
- int64_t alignmentA = 1 << definedAtomA->alignment().powerOf2;
- int64_t alignmentB = 1 << definedAtomB->alignment().powerOf2;
- if (alignmentA == alignmentB) {
- if (definedAtomA->merge() == DefinedAtom::mergeAsTentative)
- return false;
- if (definedAtomB->merge() == DefinedAtom::mergeAsTentative)
- return true;
- }
- return alignmentA < alignmentB;
- });
-
- // Set the fileOffset, and the appropriate size of the section
- for (auto &ai : this->_atoms) {
- const DefinedAtom *definedAtom = cast<DefinedAtom>(ai->_atom);
- DefinedAtom::Alignment atomAlign = definedAtom->alignment();
- uint64_t fOffset = this->alignOffset(this->fileSize(), atomAlign);
- uint64_t mOffset = this->alignOffset(this->memSize(), atomAlign);
- ai->_fileOffset = fOffset;
- this->_fsize = fOffset + definedAtom->size();
- this->_msize = mOffset + definedAtom->size();
- }
-} // finalize
-
-} // elf
-} // lld
-
-#endif // LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_SECTION_CHUNKS_H
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.cpp b/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.cpp
index 9b10c2f160f4..6c0360c310f4 100644
--- a/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.cpp
+++ b/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.cpp
@@ -12,29 +12,23 @@
#include "HexagonLinkingContext.h"
#include "HexagonTargetHandler.h"
-using namespace lld;
-using namespace elf;
using namespace llvm::ELF;
using llvm::makeArrayRef;
-HexagonTargetHandler::HexagonTargetHandler(HexagonLinkingContext &context)
- : _hexagonLinkingContext(context),
- _hexagonRuntimeFile(new HexagonRuntimeFile<HexagonELFType>(context)),
- _hexagonTargetLayout(new HexagonTargetLayout<HexagonELFType>(context)),
- _hexagonRelocationHandler(new HexagonTargetRelocationHandler(
- *_hexagonTargetLayout.get())) {}
+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 (_hexagonLinkingContext.getOutputELFType()) {
+ switch (_ctx.getOutputELFType()) {
case llvm::ELF::ET_EXEC:
- return std::unique_ptr<Writer>(
- new elf::HexagonExecutableWriter<HexagonELFType>(
- _hexagonLinkingContext, *_hexagonTargetLayout.get()));
+ return llvm::make_unique<HexagonExecutableWriter>(_ctx, *_targetLayout);
case llvm::ELF::ET_DYN:
- return std::unique_ptr<Writer>(
- new elf::HexagonDynamicLibraryWriter<HexagonELFType>(
- _hexagonLinkingContext, *_hexagonTargetLayout.get()));
+ return llvm::make_unique<HexagonDynamicLibraryWriter>(_ctx, *_targetLayout);
case llvm::ELF::ET_REL:
llvm_unreachable("TODO: support -r mode");
default:
@@ -77,7 +71,7 @@ public:
return makeArrayRef(hexagonGotAtomContent);
}
- Alignment alignment() const override { return Alignment(2); }
+ Alignment alignment() const override { return 4; }
};
class HexagonGOTPLTAtom : public GOTAtom {
@@ -88,7 +82,7 @@ public:
return makeArrayRef(hexagonGotPltAtomContent);
}
- Alignment alignment() const override { return Alignment(2); }
+ Alignment alignment() const override { return 4; }
};
class HexagonGOTPLT0Atom : public GOTAtom {
@@ -99,7 +93,7 @@ public:
return makeArrayRef(hexagonGotPlt0AtomContent);
}
- Alignment alignment() const override { return Alignment(3); }
+ Alignment alignment() const override { return 8; }
};
class HexagonPLT0Atom : public PLT0Atom {
@@ -165,8 +159,7 @@ protected:
}
public:
- GOTPLTPass(const ELFLinkingContext &ctx)
- : _file(ctx), _null(nullptr), _PLT0(nullptr), _got0(nullptr) {}
+ GOTPLTPass(const ELFLinkingContext &ctx) : _file(ctx) {}
/// \brief Do the pass.
///
@@ -176,34 +169,36 @@ public:
///
/// After all references are handled, the atoms created during that are all
/// added to mf.
- void perform(std::unique_ptr<MutableFile> &mf) override {
+ std::error_code perform(SimpleFile &mf) override {
// Process all references.
- for (const auto &atom : mf->defined())
+ 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);
+ if (_plt0) {
+ _plt0->setOrdinal(ordinal++);
+ mf.addAtom(*_plt0);
}
for (auto &plt : _pltVector) {
plt->setOrdinal(ordinal++);
- mf->addAtom(*plt);
+ mf.addAtom(*plt);
}
if (_null) {
_null->setOrdinal(ordinal++);
- mf->addAtom(*_null);
+ mf.addAtom(*_null);
}
if (_got0) {
_got0->setOrdinal(ordinal++);
- mf->addAtom(*_got0);
+ mf.addAtom(*_got0);
}
for (auto &got : _gotVector) {
got->setOrdinal(ordinal++);
- mf->addAtom(*got);
+ mf.addAtom(*got);
}
+
+ return std::error_code();
}
protected:
@@ -221,19 +216,19 @@ protected:
std::vector<PLTAtom *> _pltVector;
/// \brief GOT entry that is always 0. Used for undefined weaks.
- GOTAtom *_null;
+ 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;
- GOTAtom *_got0;
+ PLT0Atom *_plt0 = nullptr;
+ GOTAtom *_got0 = nullptr;
/// @}
};
class DynamicGOTPLTPass final : public GOTPLTPass<DynamicGOTPLTPass> {
public:
- DynamicGOTPLTPass(const elf::HexagonLinkingContext &ctx) : GOTPLTPass(ctx) {
+ DynamicGOTPLTPass(const HexagonLinkingContext &ctx) : GOTPLTPass(ctx) {
_got0 = new (_file._alloc) HexagonGOTPLT0Atom(_file);
#ifndef NDEBUG
_got0->_name = "__got0";
@@ -241,14 +236,14 @@ public:
}
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);
+ 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;
+ return _plt0;
}
const PLTAtom *getPLTEntry(const Atom *a) {
@@ -313,22 +308,75 @@ public:
}
};
-void elf::HexagonLinkingContext::addPasses(PassManager &pm) {
+void HexagonLinkingContext::addPasses(PassManager &pm) {
if (isDynamic())
pm.add(llvm::make_unique<DynamicGOTPLTPass>(*this));
ELFLinkingContext::addPasses(pm);
}
-void HexagonTargetHandler::registerRelocationNames(Registry &registry) {
- registry.addKindTable(Reference::KindNamespace::ELF,
- Reference::KindArch::Hexagon, kindStrings);
+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;
}
-#define ELF_RELOC(name, value) LLD_KIND_STRING_ENTRY(name),
+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();
+}
-const Registry::KindStrings HexagonTargetHandler::kindStrings[] = {
-#include "llvm/Support/ELFRelocs/Hexagon.def"
- LLD_KIND_STRING_END
-};
+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;
+}
-#undef ELF_RELOC
+} // namespace elf
+} // namespace lld
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.h b/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.h
index f4315f710ec7..b1366bed09ea 100644
--- a/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.h
+++ b/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.h
@@ -10,44 +10,51 @@
#ifndef HEXAGON_TARGET_HANDLER_H
#define HEXAGON_TARGET_HANDLER_H
-#include "DefaultTargetHandler.h"
-#include "HexagonELFReader.h"
-#include "HexagonExecutableAtoms.h"
+#include "ELFReader.h"
+#include "HexagonELFFile.h"
#include "HexagonRelocationHandler.h"
-#include "HexagonSectionChunks.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
-template <class HexagonELFType>
-class HexagonTargetLayout final : public TargetLayout<HexagonELFType> {
+class HexagonTargetLayout final : public TargetLayout<ELF32LE> {
public:
enum HexagonSectionOrder {
ORDER_SDATA = 205
};
- HexagonTargetLayout(HexagonLinkingContext &hti)
- : TargetLayout<HexagonELFType>(hti), _sdataSection(nullptr),
- _gotSymAtom(nullptr), _cachedGotSymAtom(false) {
- _sdataSection = new (_alloc) SDataSection<HexagonELFType>(hti);
- }
+ HexagonTargetLayout(HexagonLinkingContext &ctx)
+ : TargetLayout(ctx), _sdataSection(ctx) {}
/// \brief Return the section order for a input section
- virtual Layout::SectionOrder getSectionOrder(
- StringRef name, int32_t contentType, int32_t contentPermissions) {
- if ((contentType == DefinedAtom::typeDataFast) ||
- (contentType == DefinedAtom::typeZeroFillFast))
+ TargetLayout::SectionOrder
+ getSectionOrder(StringRef name, int32_t contentType,
+ int32_t contentPermissions) override {
+ if (contentType == DefinedAtom::typeDataFast ||
+ contentType == DefinedAtom::typeZeroFillFast)
return ORDER_SDATA;
-
- return DefaultLayout<HexagonELFType>::getSectionOrder(name, contentType,
- contentPermissions);
+ return TargetLayout::getSectionOrder(name, contentType, contentPermissions);
}
/// \brief Return the appropriate input section name.
- virtual StringRef getInputSectionName(const DefinedAtom *da) const {
+ StringRef getInputSectionName(const DefinedAtom *da) const override {
switch (da->contentType()) {
case DefinedAtom::typeDataFast:
case DefinedAtom::typeZeroFillFast:
@@ -55,88 +62,72 @@ public:
default:
break;
}
- return DefaultLayout<HexagonELFType>::getInputSectionName(da);
+ return TargetLayout::getInputSectionName(da);
}
/// \brief Gets or creates a section.
- virtual AtomSection<HexagonELFType> *
+ AtomSection<ELF32LE> *
createSection(StringRef name, int32_t contentType,
DefinedAtom::ContentPermissions contentPermissions,
- Layout::SectionOrder sectionOrder) {
- if ((contentType == DefinedAtom::typeDataFast) ||
- (contentType == DefinedAtom::typeZeroFillFast))
- return _sdataSection;
- return DefaultLayout<HexagonELFType>::createSection(
- name, contentType, contentPermissions, sectionOrder);
+ 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
- virtual Layout::SegmentType
- getSegmentType(Section<HexagonELFType> *section) const {
+ TargetLayout::SegmentType
+ getSegmentType(const Section<ELF32LE> *section) const override {
if (section->order() == ORDER_SDATA)
return PT_LOAD;
-
- return DefaultLayout<HexagonELFType>::getSegmentType(section);
+ return TargetLayout::getSegmentType(section);
}
- Section<HexagonELFType> *getSDataSection() const {
- return _sdataSection;
- }
+ Section<ELF32LE> *getSDataSection() { return &_sdataSection; }
uint64_t getGOTSymAddr() {
- if (!_cachedGotSymAtom) {
- auto gotAtomIter = this->findAbsoluteAtom("_GLOBAL_OFFSET_TABLE_");
- _gotSymAtom = (*gotAtomIter);
- _cachedGotSymAtom = true;
- }
- if (_gotSymAtom)
- return _gotSymAtom->_virtualAddr;
- return 0;
+ std::call_once(_gotOnce, [this]() {
+ if (AtomLayout *got = findAbsoluteAtom("_GLOBAL_OFFSET_TABLE_"))
+ _gotAddr = got->_virtualAddr;
+ });
+ return _gotAddr;
}
private:
- llvm::BumpPtrAllocator _alloc;
- SDataSection<HexagonELFType> *_sdataSection;
- AtomLayout *_gotSymAtom;
- bool _cachedGotSymAtom;
+ SDataSection _sdataSection;
+ uint64_t _gotAddr = 0;
+ std::once_flag _gotOnce;
};
/// \brief TargetHandler for Hexagon
-class HexagonTargetHandler final :
- public DefaultTargetHandler<HexagonELFType> {
+class HexagonTargetHandler final : public TargetHandler {
public:
HexagonTargetHandler(HexagonLinkingContext &targetInfo);
- void registerRelocationNames(Registry &registry) override;
-
- const HexagonTargetRelocationHandler &getRelocationHandler() const override {
- return *(_hexagonRelocationHandler.get());
- }
-
- HexagonTargetLayout<HexagonELFType> &getTargetLayout() override {
- return *(_hexagonTargetLayout.get());
+ const TargetRelocationHandler &getRelocationHandler() const override {
+ return *_relocationHandler;
}
std::unique_ptr<Reader> getObjReader() override {
- return std::unique_ptr<Reader>(
- new HexagonELFObjectReader(_hexagonLinkingContext));
+ return llvm::make_unique<ELFReader<HexagonELFFile>>(_ctx);
}
std::unique_ptr<Reader> getDSOReader() override {
- return std::unique_ptr<Reader>(
- new HexagonELFDSOReader(_hexagonLinkingContext));
+ return llvm::make_unique<ELFReader<DynamicFile<ELF32LE>>>(_ctx);
}
std::unique_ptr<Writer> getWriter() override;
private:
- llvm::BumpPtrAllocator _alloc;
- static const Registry::KindStrings kindStrings[];
- HexagonLinkingContext &_hexagonLinkingContext;
- std::unique_ptr<HexagonRuntimeFile<HexagonELFType> > _hexagonRuntimeFile;
- std::unique_ptr<HexagonTargetLayout<HexagonELFType>> _hexagonTargetLayout;
- std::unique_ptr<HexagonTargetRelocationHandler> _hexagonRelocationHandler;
+ HexagonLinkingContext &_ctx;
+ std::unique_ptr<HexagonTargetLayout> _targetLayout;
+ std::unique_ptr<HexagonTargetRelocationHandler> _relocationHandler;
};
+
+void finalizeHexagonRuntimeAtomValues(HexagonTargetLayout &layout);
+
} // end namespace elf
} // end namespace lld
diff --git a/lib/ReaderWriter/ELF/Hexagon/Makefile b/lib/ReaderWriter/ELF/Hexagon/Makefile
deleted file mode 100644
index 8d6f1a0a3b1e..000000000000
--- a/lib/ReaderWriter/ELF/Hexagon/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-##===- lld/lib/ReaderWriter/ELF/Hexagon/Makefile ----------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LLD_LEVEL := ../../../..
-LIBRARYNAME := lldHexagonELFTarget
-USEDLIBS = lldCore.a
-
-CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF/Hexagon -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF
-
-include $(LLD_LEVEL)/Makefile
diff --git a/lib/ReaderWriter/ELF/Layout.h b/lib/ReaderWriter/ELF/Layout.h
deleted file mode 100644
index 826cf5035d59..000000000000
--- a/lib/ReaderWriter/ELF/Layout.h
+++ /dev/null
@@ -1,59 +0,0 @@
-//===- lib/ReaderWriter/ELF/Layout.h --------------------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_ELF_LAYOUT_H
-#define LLD_READER_WRITER_ELF_LAYOUT_H
-
-#include "lld/Core/DefinedAtom.h"
-#include "lld/ReaderWriter/AtomLayout.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Object/ELF.h"
-#include "llvm/Support/Allocator.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/ELF.h"
-#include "llvm/Support/ErrorOr.h"
-
-namespace lld {
-namespace elf {
-
-/// \brief The ELFLayout is an abstract class for managing the final layout for
-/// the kind of binaries(Shared Libraries / Relocatables / Executables 0
-/// Each architecture (Hexagon, MIPS) would have a concrete
-/// subclass derived from Layout for generating each binary thats
-// needed by the lld linker
-class Layout {
-public:
- typedef uint32_t SectionOrder;
- typedef uint32_t SegmentType;
- typedef uint32_t Flags;
-
-public:
- /// Return the order the section would appear in the output file
- virtual SectionOrder getSectionOrder(StringRef name, int32_t contentType,
- int32_t contentPerm) = 0;
- /// \brief Append the Atom to the layout and create appropriate sections.
- /// \returns A reference to the atom layout or an error. The atom layout will
- /// be updated as linking progresses.
- virtual ErrorOr<const lld::AtomLayout *> addAtom(const Atom *atom) = 0;
- /// find the Atom in the current layout
- virtual const AtomLayout *findAtomLayoutByName(StringRef name) const = 0;
- /// associates a section to a segment
- virtual void assignSectionsToSegments() = 0;
- /// associates a virtual address to the segment, section, and the atom
- virtual void assignVirtualAddress() = 0;
-
-public:
- Layout() {}
-
- virtual ~Layout() { }
-};
-} // end namespace elf
-} // end namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/ELF/Makefile b/lib/ReaderWriter/ELF/Makefile
deleted file mode 100644
index 5791ecb9733d..000000000000
--- a/lib/ReaderWriter/ELF/Makefile
+++ /dev/null
@@ -1,18 +0,0 @@
-##===- lld/lib/ReaderWriter/ELF/Makefile --------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LLD_LEVEL := ../../..
-LIBRARYNAME := lldELF
-
-CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF
-
-# these link against this lib
-PARALLEL_DIRS := Hexagon X86 X86_64 Mips AArch64 ARM
-
-include $(LLD_LEVEL)/Makefile
diff --git a/lib/ReaderWriter/ELF/Mips/CMakeLists.txt b/lib/ReaderWriter/ELF/Mips/CMakeLists.txt
index d982508b7ddc..434e310640bd 100644
--- a/lib/ReaderWriter/ELF/Mips/CMakeLists.txt
+++ b/lib/ReaderWriter/ELF/Mips/CMakeLists.txt
@@ -1,10 +1,14 @@
add_llvm_library(lldMipsELFTarget
+ MipsAbiInfoHandler.cpp
MipsCtorsOrderPass.cpp
- MipsELFFlagsMerger.cpp
+ MipsELFFile.cpp
+ MipsELFWriters.cpp
MipsLinkingContext.cpp
MipsRelocationHandler.cpp
MipsRelocationPass.cpp
+ MipsSectionChunks.cpp
MipsTargetHandler.cpp
+ MipsTargetLayout.cpp
LINK_LIBS
lldELF
lldReaderWriter
diff --git a/lib/ReaderWriter/ELF/Mips/Makefile b/lib/ReaderWriter/ELF/Mips/Makefile
deleted file mode 100644
index 0b2f4ff82279..000000000000
--- a/lib/ReaderWriter/ELF/Mips/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-##===- lld/lib/ReaderWriter/ELF/Mips/Makefile ----------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LLD_LEVEL := ../../../..
-LIBRARYNAME := lldMipsELFTarget
-USEDLIBS = lldCore.a
-CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF
-
-include $(LLD_LEVEL)/Makefile
diff --git a/lib/ReaderWriter/ELF/Mips/MipsAbiInfoHandler.cpp b/lib/ReaderWriter/ELF/Mips/MipsAbiInfoHandler.cpp
new file mode 100644
index 000000000000..ad4e62e64680
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsAbiInfoHandler.cpp
@@ -0,0 +1,675 @@
+//===- 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
new file mode 100644
index 000000000000..44da29f09214
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsAbiInfoHandler.h
@@ -0,0 +1,83 @@
+//===- 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
index 8bf80257fc89..a7062813df42 100644
--- a/lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.cpp
+++ b/lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include "MipsCtorsOrderPass.h"
+#include "lld/Core/Simple.h"
#include <algorithm>
#include <climits>
@@ -48,8 +49,8 @@ static int32_t getSectionPriority(StringRef path, StringRef sectionName) {
return priority;
}
-void MipsCtorsOrderPass::perform(std::unique_ptr<MutableFile> &f) {
- auto definedAtoms = f->definedAtoms();
+std::error_code MipsCtorsOrderPass::perform(SimpleFile &f) {
+ auto definedAtoms = f.definedAtoms();
auto last = std::stable_partition(definedAtoms.begin(), definedAtoms.end(),
[](const DefinedAtom *atom) {
@@ -70,4 +71,6 @@ void MipsCtorsOrderPass::perform(std::unique_ptr<MutableFile> &f) {
return leftPriority < rightPriority;
});
+
+ return std::error_code();
}
diff --git a/lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.h b/lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.h
index eeb1a194f9c7..5b12b7de0fa2 100644
--- a/lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.h
+++ b/lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.h
@@ -17,7 +17,7 @@ namespace elf {
/// \brief This pass sorts atoms in .{ctors,dtors}.<priority> sections.
class MipsCtorsOrderPass : public Pass {
public:
- void perform(std::unique_ptr<MutableFile> &mergedFile) override;
+ std::error_code perform(SimpleFile &mergedFile) override;
};
}
}
diff --git a/lib/ReaderWriter/ELF/Mips/MipsDynamicLibraryWriter.h b/lib/ReaderWriter/ELF/Mips/MipsDynamicLibraryWriter.h
deleted file mode 100644
index 30b5b0ba6dae..000000000000
--- a/lib/ReaderWriter/ELF/Mips/MipsDynamicLibraryWriter.h
+++ /dev/null
@@ -1,101 +0,0 @@
-//===- lib/ReaderWriter/ELF/Mips/MipsDynamicLibraryWriter.h ---------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_DYNAMIC_LIBRARY_WRITER_H
-#define LLD_READER_WRITER_ELF_MIPS_MIPS_DYNAMIC_LIBRARY_WRITER_H
-
-#include "DynamicLibraryWriter.h"
-#include "MipsDynamicTable.h"
-#include "MipsELFWriters.h"
-#include "MipsLinkingContext.h"
-
-namespace lld {
-namespace elf {
-
-template <typename ELFT> class MipsSymbolTable;
-template <typename ELFT> class MipsDynamicSymbolTable;
-template <typename ELFT> class MipsTargetLayout;
-
-template <class ELFT>
-class MipsDynamicLibraryWriter : public DynamicLibraryWriter<ELFT> {
-public:
- MipsDynamicLibraryWriter(MipsLinkingContext &ctx,
- MipsTargetLayout<ELFT> &layout);
-
-protected:
- // Add any runtime files and their atoms to the output
- bool createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
-
- void finalizeDefaultAtomValues() override;
-
- std::error_code setELFHeader() override {
- DynamicLibraryWriter<ELFT>::setELFHeader();
- _writeHelper.setELFHeader(*this->_elfHeader);
- return std::error_code();
- }
-
- unique_bump_ptr<SymbolTable<ELFT>> createSymbolTable() override;
- unique_bump_ptr<DynamicTable<ELFT>> createDynamicTable() override;
-
- unique_bump_ptr<DynamicSymbolTable<ELFT>>
- createDynamicSymbolTable() override;
-
-private:
- MipsELFWriter<ELFT> _writeHelper;
- MipsTargetLayout<ELFT> &_mipsTargetLayout;
-};
-
-template <class ELFT>
-MipsDynamicLibraryWriter<ELFT>::MipsDynamicLibraryWriter(
- MipsLinkingContext &ctx, MipsTargetLayout<ELFT> &layout)
- : DynamicLibraryWriter<ELFT>(ctx, layout), _writeHelper(ctx, layout),
- _mipsTargetLayout(layout) {}
-
-template <class ELFT>
-bool MipsDynamicLibraryWriter<ELFT>::createImplicitFiles(
- std::vector<std::unique_ptr<File>> &result) {
- DynamicLibraryWriter<ELFT>::createImplicitFiles(result);
- result.push_back(std::move(_writeHelper.createRuntimeFile()));
- return true;
-}
-
-template <class ELFT>
-void MipsDynamicLibraryWriter<ELFT>::finalizeDefaultAtomValues() {
- // Finalize the atom values that are part of the parent.
- DynamicLibraryWriter<ELFT>::finalizeDefaultAtomValues();
- _writeHelper.finalizeMipsRuntimeAtomValues();
-}
-
-template <class ELFT>
-unique_bump_ptr<SymbolTable<ELFT>>
- MipsDynamicLibraryWriter<ELFT>::createSymbolTable() {
- return unique_bump_ptr<SymbolTable<ELFT>>(new (
- this->_alloc) MipsSymbolTable<ELFT>(this->_context));
-}
-
-/// \brief create dynamic table
-template <class ELFT>
-unique_bump_ptr<DynamicTable<ELFT>>
- MipsDynamicLibraryWriter<ELFT>::createDynamicTable() {
- return unique_bump_ptr<DynamicTable<ELFT>>(new (
- this->_alloc) MipsDynamicTable<ELFT>(this->_context, _mipsTargetLayout));
-}
-
-/// \brief create dynamic symbol table
-template <class ELFT>
-unique_bump_ptr<DynamicSymbolTable<ELFT>>
- MipsDynamicLibraryWriter<ELFT>::createDynamicSymbolTable() {
- return unique_bump_ptr<DynamicSymbolTable<ELFT>>(
- new (this->_alloc) MipsDynamicSymbolTable<ELFT>(
- this->_context, _mipsTargetLayout));
-}
-
-} // namespace elf
-} // namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/ELF/Mips/MipsDynamicTable.h b/lib/ReaderWriter/ELF/Mips/MipsDynamicTable.h
index 2b9562f42b57..480c69cf4600 100644
--- a/lib/ReaderWriter/ELF/Mips/MipsDynamicTable.h
+++ b/lib/ReaderWriter/ELF/Mips/MipsDynamicTable.h
@@ -9,83 +9,89 @@
#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_DYNAMIC_TABLE_H
#define LLD_READER_WRITER_ELF_MIPS_MIPS_DYNAMIC_TABLE_H
-#include "DefaultLayout.h"
+#include "TargetLayout.h"
#include "SectionChunks.h"
namespace lld {
namespace elf {
-template <class ELFType> class MipsTargetLayout;
+template <class ELFT> class MipsTargetLayout;
-template <class MipsELFType>
-class MipsDynamicTable : public DynamicTable<MipsELFType> {
+template <class ELFT> class MipsDynamicTable : public DynamicTable<ELFT> {
public:
- MipsDynamicTable(const ELFLinkingContext &ctx,
- MipsTargetLayout<MipsELFType> &layout)
- : DynamicTable<MipsELFType>(ctx, layout, ".dynamic",
- DefaultLayout<MipsELFType>::ORDER_DYNAMIC),
- _mipsTargetLayout(layout) {}
+ MipsDynamicTable(const ELFLinkingContext &ctx, MipsTargetLayout<ELFT> &layout)
+ : DynamicTable<ELFT>(ctx, layout, ".dynamic",
+ TargetLayout<ELFT>::ORDER_DYNAMIC),
+ _targetLayout(layout) {}
void createDefaultEntries() override {
- DynamicTable<MipsELFType>::createDefaultEntries();
-
- typename DynamicTable<MipsELFType>::Elf_Dyn dyn;
+ DynamicTable<ELFT>::createDefaultEntries();
// Version id for the Runtime Linker Interface.
- dyn.d_un.d_val = 1;
- dyn.d_tag = DT_MIPS_RLD_VERSION;
- this->addEntry(dyn);
+ 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.
- dyn.d_un.d_val = RHF_NOTPOT;
- dyn.d_tag = DT_MIPS_FLAGS;
- this->addEntry(dyn);
+ this->addEntry(DT_MIPS_FLAGS, RHF_NOTPOT);
// The base address of the segment.
- dyn.d_un.d_ptr = 0;
- dyn.d_tag = DT_MIPS_BASE_ADDRESS;
- _dt_baseaddr = this->addEntry(dyn);
+ _dt_baseaddr = this->addEntry(DT_MIPS_BASE_ADDRESS, 0);
// Number of local global offset table entries.
- dyn.d_un.d_val = 0;
- dyn.d_tag = DT_MIPS_LOCAL_GOTNO;
- _dt_localgot = this->addEntry(dyn);
+ _dt_localgot = this->addEntry(DT_MIPS_LOCAL_GOTNO, 0);
// Number of entries in the .dynsym section.
- dyn.d_un.d_val = 0;
- dyn.d_tag = DT_MIPS_SYMTABNO;
- _dt_symtabno = this->addEntry(dyn);
+ _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.
- dyn.d_un.d_val = 0;
- dyn.d_tag = DT_MIPS_GOTSYM;
- _dt_gotsym = this->addEntry(dyn);
+ _dt_gotsym = this->addEntry(DT_MIPS_GOTSYM, 0);
// Address of the .got section.
- dyn.d_un.d_val = 0;
- dyn.d_tag = DT_PLTGOT;
- _dt_pltgot = this->addEntry(dyn);
+ _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<MipsELFType>::updateDynamicTable();
+ 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 : _mipsTargetLayout.segments())
+ 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 = _mipsTargetLayout.getGOTSection();
+ 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->getSymbolTable()->size() - got.getGlobalCount();
this->_entries[_dt_localgot].d_un.d_val = got.getLocalCount();
- this->_entries[_dt_pltgot].d_un.d_ptr =
- _mipsTargetLayout.findOutputSection(".got")->virtualAddr();
+ 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; }
@@ -106,7 +112,10 @@ private:
std::size_t _dt_gotsym;
std::size_t _dt_pltgot;
std::size_t _dt_baseaddr;
- MipsTargetLayout<MipsELFType> &_mipsTargetLayout;
+ std::size_t _dt_options;
+ std::size_t _dt_rldmap;
+ std::size_t _dt_rldmaprel;
+ MipsTargetLayout<ELFT> &_targetLayout;
};
} // end namespace elf
diff --git a/lib/ReaderWriter/ELF/Mips/MipsELFFile.cpp b/lib/ReaderWriter/ELF/Mips/MipsELFFile.cpp
new file mode 100644
index 000000000000..b081b63d77f7
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsELFFile.cpp
@@ -0,0 +1,348 @@
+//===- 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
index 7381c7e977bf..934934b539cc 100644
--- a/lib/ReaderWriter/ELF/Mips/MipsELFFile.h
+++ b/lib/ReaderWriter/ELF/Mips/MipsELFFile.h
@@ -12,42 +12,7 @@
#include "ELFReader.h"
#include "MipsLinkingContext.h"
#include "MipsRelocationHandler.h"
-
-namespace llvm {
-namespace object {
-
-template <class ELFT>
-struct Elf_RegInfo;
-
-template <llvm::support::endianness TargetEndianness, std::size_t MaxAlign>
-struct Elf_RegInfo<ELFType<TargetEndianness, MaxAlign, false>> {
- LLVM_ELF_IMPORT_TYPES(TargetEndianness, MaxAlign, false)
- Elf_Word ri_gprmask; // bit-mask of used general registers
- Elf_Word ri_cprmask[4]; // bit-mask of used co-processor registers
- Elf_Addr ri_gp_value; // gp register value
-};
-
-template <llvm::support::endianness TargetEndianness, std::size_t MaxAlign>
-struct Elf_RegInfo<ELFType<TargetEndianness, MaxAlign, true>> {
- LLVM_ELF_IMPORT_TYPES(TargetEndianness, MaxAlign, true)
- Elf_Word ri_gprmask; // bit-mask of used general registers
- Elf_Word ri_pad; // unused padding field
- Elf_Word ri_cprmask[4]; // bit-mask of used co-processor registers
- Elf_Addr ri_gp_value; // gp register value
-};
-
-template <class ELFT> struct Elf_Mips_Options {
- LLVM_ELF_IMPORT_TYPES(ELFT::TargetEndianness, ELFT::MaxAlignment,
- ELFT::Is64Bits)
- uint8_t kind; // Determines interpretation of variable part of descriptor
- uint8_t size; // Byte size of descriptor, including this header
- Elf_Half section; // Section header index of section affected,
- // or 0 for global options
- Elf_Word info; // Kind-specific information
-};
-
-} // end namespace object.
-} // end namespace llvm.
+#include "llvm/ADT/STLExtras.h"
namespace lld {
namespace elf {
@@ -64,50 +29,21 @@ public:
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) {}
+ std::vector<ELFReference<ELFT> *> &referenceList);
- const MipsELFFile<ELFT>& file() const override {
- return static_cast<const MipsELFFile<ELFT> &>(this->_owningFile);
- }
+ const MipsELFFile<ELFT>& file() const override;
+ DefinedAtom::CodeModel codeModel() const override;
- DefinedAtom::CodeModel codeModel() const override {
- switch (this->_symbol->st_other & llvm::ELF::STO_MIPS_MIPS16) {
- case llvm::ELF::STO_MIPS_MIPS16:
- return DefinedAtom::codeMips16;
- case llvm::ELF::STO_MIPS_PIC:
- return DefinedAtom::codeMipsPIC;
- case llvm::ELF::STO_MIPS_MICROMIPS:
- return DefinedAtom::codeMipsMicro;
- case llvm::ELF::STO_MIPS_MICROMIPS | llvm::ELF::STO_MIPS_PIC:
- return DefinedAtom::codeMipsMicroPIC;
- default:
- return DefinedAtom::codeNA;
- }
- }
+ 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;
- static const bool _isMips64EL =
- ELFT::Is64Bits && ELFT::TargetEndianness == llvm::support::little;
-
public:
- MipsELFReference(uint64_t symValue, const Elf_Rela &rel)
- : ELFReference<ELFT>(
- &rel, rel.r_offset - symValue, Reference::KindArch::Mips,
- rel.getType(_isMips64EL) & 0xff, rel.getSymbol(_isMips64EL)),
- _tag(uint32_t(rel.getType(_isMips64EL)) >> 8) {}
-
- MipsELFReference(uint64_t symValue, const Elf_Rel &rel)
- : ELFReference<ELFT>(rel.r_offset - symValue, Reference::KindArch::Mips,
- rel.getType(_isMips64EL) & 0xff,
- rel.getSymbol(_isMips64EL)),
- _tag(uint32_t(rel.getType(_isMips64EL)) >> 8) {}
+ 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; }
@@ -118,211 +54,70 @@ private:
template <class ELFT> class MipsELFFile : public ELFFile<ELFT> {
public:
- MipsELFFile(std::unique_ptr<MemoryBuffer> mb, MipsLinkingContext &ctx)
- : ELFFile<ELFT>(std::move(mb), ctx) {}
+ MipsELFFile(std::unique_ptr<MemoryBuffer> mb, ELFLinkingContext &ctx);
- static ErrorOr<std::unique_ptr<MipsELFFile>>
- create(std::unique_ptr<MemoryBuffer> mb, MipsLinkingContext &ctx) {
- return std::unique_ptr<MipsELFFile<ELFT>>(
- new MipsELFFile<ELFT>(std::move(mb), ctx));
- }
-
- bool isPIC() const {
- return this->_objFile->getHeader()->e_flags & llvm::ELF::EF_MIPS_PIC;
- }
+ bool isPIC() const;
/// \brief gp register value stored in the .reginfo section.
- int64_t getGP0() const { return _gp0 ? *_gp0 : 0; }
+ 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; }
+ uint64_t getTPOffset() const { return _tpOff; }
+ uint64_t getDTPOffset() const { return _dtpOff; }
protected:
- std::error_code doParse() override {
- if (std::error_code ec = ELFFile<ELFT>::doParse())
- return ec;
- // Retrieve some auxiliary data like GP value, TLS section address etc
- // from the object file.
- return readAuxData();
- }
+ 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 llvm::object::Elf_Rel_Impl<ELFT, false> Elf_Rel;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel_Iter Elf_Rel_Iter;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela_Iter Elf_Rela_Iter;
+ 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 };
- static const bool _isMips64EL =
- ELFT::Is64Bits && ELFT::TargetEndianness == llvm::support::little;
-
- llvm::Optional<int64_t> _gp0;
- llvm::Optional<uint64_t> _tpOff;
- llvm::Optional<uint64_t> _dtpOff;
+ int64_t _gp0 = 0;
+ uint64_t _tpOff = 0;
+ uint64_t _dtpOff = 0;
- ErrorOr<ELFDefinedAtom<ELFT> *> handleDefinedSymbol(
- StringRef symName, StringRef sectionName, const Elf_Sym *sym,
- const Elf_Shdr *sectionHdr, ArrayRef<uint8_t> contentData,
- unsigned int referenceStart, unsigned int referenceEnd,
- std::vector<ELFReference<ELFT> *> &referenceList) override {
- return new (this->_readerStorage) MipsELFDefinedAtom<ELFT>(
- *this, symName, sectionName, sym, sectionHdr, contentData,
- referenceStart, referenceEnd, referenceList);
- }
-
- const Elf_Shdr *findSectionByType(uint64_t type) {
- for (const Elf_Shdr &section : this->_objFile->sections())
- if (section.sh_type == type)
- return &section;
- return nullptr;
- }
-
- const Elf_Shdr *findSectionByFlags(uint64_t flags) {
- for (const Elf_Shdr &section : this->_objFile->sections())
- if (section.sh_flags & flags)
- return &section;
- return nullptr;
- }
-
- std::error_code readAuxData() {
- using namespace llvm::ELF;
- if (const Elf_Shdr *sec = findSectionByFlags(SHF_TLS)) {
- _tpOff = sec->sh_addr + TP_OFFSET;
- _dtpOff = sec->sh_addr + DTP_OFFSET;
- }
-
- typedef llvm::object::Elf_RegInfo<ELFT> Elf_RegInfo;
- typedef llvm::object::Elf_Mips_Options<ELFT> Elf_Mips_Options;
-
- if (const Elf_Shdr *sec = findSectionByType(SHT_MIPS_OPTIONS)) {
- auto contents = this->getSectionContents(sec);
- if (std::error_code ec = contents.getError())
- return ec;
-
- ArrayRef<uint8_t> raw = contents.get();
- while (!raw.empty()) {
- if (raw.size() < sizeof(Elf_Mips_Options))
- return make_dynamic_error_code(
- StringRef("Invalid size of MIPS_OPTIONS section"));
-
- const auto *opt = reinterpret_cast<const Elf_Mips_Options *>(raw.data());
- if (opt->kind == ODK_REGINFO) {
- _gp0 = reinterpret_cast<const Elf_RegInfo *>(opt + 1)->ri_gp_value;
- break;
- }
- raw = raw.slice(opt->size);
- }
- } else if (const Elf_Shdr *sec = findSectionByType(SHT_MIPS_REGINFO)) {
- auto contents = this->getSectionContents(sec);
- if (std::error_code ec = contents.getError())
- return ec;
-
- ArrayRef<uint8_t> raw = contents.get();
- if (raw.size() != sizeof(Elf_RegInfo))
- return make_dynamic_error_code(
- StringRef("Invalid size of MIPS_REGINFO section"));
-
- _gp0 = reinterpret_cast<const Elf_RegInfo *>(raw.data())->ri_gp_value;
- }
- return std::error_code();
- }
+ 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<Elf_Rela_Iter> rels) override {
- const auto value = this->getSymbolValue(symbol);
- for (const auto &rel : rels) {
- if (rel.r_offset < value || value + content.size() <= rel.r_offset)
- continue;
- auto r = new (this->_readerStorage) MipsELFReference<ELFT>(value, rel);
- this->addReferenceToSymbol(r, symbol);
- this->_references.push_back(r);
- }
- }
-
+ range<const Elf_Rela *> rels) override;
void createRelocationReferences(const Elf_Sym *symbol,
ArrayRef<uint8_t> symContent,
ArrayRef<uint8_t> secContent,
- range<Elf_Rel_Iter> rels) override {
- const auto value = this->getSymbolValue(symbol);
- for (Elf_Rel_Iter rit = rels.begin(), eit = rels.end(); rit != eit; ++rit) {
- if (rit->r_offset < value || value + symContent.size() <= rit->r_offset)
- continue;
+ const Elf_Shdr *RelSec) override;
- auto r = new (this->_readerStorage) MipsELFReference<ELFT>(value, *rit);
- this->addReferenceToSymbol(r, symbol);
- this->_references.push_back(r);
+ const Elf_Shdr *findSectionByType(uint64_t type) const;
+ const Elf_Shdr *findSectionByFlags(uint64_t flags) const;
- auto addend = readAddend(*rit, secContent);
- auto pairRelType = getPairRelocation(*rit);
- if (pairRelType != llvm::ELF::R_MIPS_NONE) {
- addend <<= 16;
- auto mit = findMatchingRelocation(pairRelType, rit, eit);
- if (mit != eit)
- addend += int16_t(readAddend(*mit, secContent));
- else
- // FIXME (simon): Show detailed warning.
- llvm::errs() << "lld warning: cannot matching LO16 relocation\n";
- }
- this->_references.back()->setAddend(addend);
- }
- }
+ 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;
- Reference::Addend readAddend(const Elf_Rel &ri,
- const ArrayRef<uint8_t> content) const {
- const auto &rh =
- this->_ctx.template getTargetHandler<ELFT>().getRelocationHandler();
- return static_cast<const MipsRelocationHandler &>(rh)
- .readAddend(getPrimaryType(ri), content.data() + ri.r_offset);
- }
+ ErrorOr<const Elf_Mips_RegInfo *> findRegInfoSec() const;
+ ErrorOr<const Elf_Mips_ABIFlags*> findAbiFlagsSec() const;
- uint32_t getPairRelocation(const Elf_Rel &rel) const {
- switch (getPrimaryType(rel)) {
- case llvm::ELF::R_MIPS_HI16:
- return llvm::ELF::R_MIPS_LO16;
- case llvm::ELF::R_MIPS_PCHI16:
- return llvm::ELF::R_MIPS_PCLO16;
- case llvm::ELF::R_MIPS_GOT16:
- if (isLocalBinding(rel))
- return llvm::ELF::R_MIPS_LO16;
- break;
- case llvm::ELF::R_MICROMIPS_HI16:
- return llvm::ELF::R_MICROMIPS_LO16;
- case llvm::ELF::R_MICROMIPS_GOT16:
- if (isLocalBinding(rel))
- return llvm::ELF::R_MICROMIPS_LO16;
- break;
- default:
- // Nothing to do.
- break;
- }
- return llvm::ELF::R_MIPS_NONE;
- }
+ std::error_code readAuxData();
- Elf_Rel_Iter findMatchingRelocation(uint32_t pairRelType, Elf_Rel_Iter rit,
- Elf_Rel_Iter eit) const {
- return std::find_if(rit, eit, [&](const Elf_Rel &rel) {
- return getPrimaryType(rel) == pairRelType &&
- rel.getSymbol(_isMips64EL) == rit->getSymbol(_isMips64EL);
- });
- }
+ Reference::Addend readAddend(const Elf_Rel &ri,
+ const ArrayRef<uint8_t> content) const;
- static uint8_t getPrimaryType(const Elf_Rel &rel) {
- return rel.getType(_isMips64EL) & 0xff;
- }
- bool isLocalBinding(const Elf_Rel &rel) const {
- return this->_objFile->getSymbol(rel.getSymbol(_isMips64EL))
- ->getBinding() == llvm::ELF::STB_LOCAL;
- }
-};
+ uint32_t getPairRelocation(const Elf_Shdr *Symtab, const Elf_Rel &rel) const;
-template <class ELFT> class MipsDynamicFile : public DynamicFile<ELFT> {
-public:
- MipsDynamicFile(const MipsLinkingContext &context, StringRef name)
- : DynamicFile<ELFT>(context, name) {}
+ 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
diff --git a/lib/ReaderWriter/ELF/Mips/MipsELFFlagsMerger.cpp b/lib/ReaderWriter/ELF/Mips/MipsELFFlagsMerger.cpp
deleted file mode 100644
index 0ef2c70b8156..000000000000
--- a/lib/ReaderWriter/ELF/Mips/MipsELFFlagsMerger.cpp
+++ /dev/null
@@ -1,149 +0,0 @@
-//===- lib/ReaderWriter/ELF/MipsELFFlagsMerger.cpp ------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "MipsELFFlagsMerger.h"
-#include "lld/Core/Error.h"
-#include "llvm/ADT/Twine.h"
-#include "llvm/Support/ELF.h"
-#include "llvm/Support/raw_ostream.h"
-
-using namespace lld;
-using namespace lld::elf;
-using namespace llvm::ELF;
-
-struct MipsISATreeEdge {
- unsigned child;
- unsigned parent;
-};
-
-static MipsISATreeEdge isaTree[] = {
- // MIPS32R6 and MIPS64R6 are not compatible with other extensions
-
- // MIPS64 extensions.
- {EF_MIPS_ARCH_64R2, EF_MIPS_ARCH_64},
- // MIPS V extensions.
- {EF_MIPS_ARCH_64, EF_MIPS_ARCH_5},
- // MIPS IV extensions.
- {EF_MIPS_ARCH_5, EF_MIPS_ARCH_4},
- // MIPS III extensions.
- {EF_MIPS_ARCH_4, EF_MIPS_ARCH_3},
- // MIPS32 extensions.
- {EF_MIPS_ARCH_32R2, EF_MIPS_ARCH_32},
- // MIPS II extensions.
- {EF_MIPS_ARCH_3, EF_MIPS_ARCH_2},
- {EF_MIPS_ARCH_32, EF_MIPS_ARCH_2},
- // MIPS I extensions.
- {EF_MIPS_ARCH_2, EF_MIPS_ARCH_1},
-};
-
-static bool matchMipsISA(unsigned base, unsigned ext) {
- if (base == ext)
- return true;
- if (base == EF_MIPS_ARCH_32 && matchMipsISA(EF_MIPS_ARCH_64, ext))
- return true;
- if (base == EF_MIPS_ARCH_32R2 && matchMipsISA(EF_MIPS_ARCH_64R2, ext))
- return true;
- for (const auto &edge : isaTree) {
- if (ext == edge.child) {
- ext = edge.parent;
- if (ext == base)
- return true;
- }
- }
- return false;
-}
-
-MipsELFFlagsMerger::MipsELFFlagsMerger(bool is64Bits)
- : _is64Bit(is64Bits), _flags(0) {}
-
-uint32_t MipsELFFlagsMerger::getMergedELFFlags() const { return _flags; }
-
-std::error_code MipsELFFlagsMerger::merge(uint8_t newClass, uint32_t newFlags) {
- // Check bitness.
- if (_is64Bit != (newClass == ELFCLASS64))
- return make_dynamic_error_code(
- Twine("Bitness is incompatible with that of the selected target"));
-
- // We support two ABI: O32 and N64. The last one does not have
- // the corresponding ELF flag.
- uint32_t inAbi = newFlags & EF_MIPS_ABI;
- uint32_t supportedAbi = _is64Bit ? 0 : uint32_t(EF_MIPS_ABI_O32);
- if (inAbi != supportedAbi)
- return make_dynamic_error_code(Twine("Unsupported ABI"));
-
- // ... and reduced set of architectures ...
- uint32_t newArch = newFlags & EF_MIPS_ARCH;
- switch (newArch) {
- case EF_MIPS_ARCH_1:
- case EF_MIPS_ARCH_2:
- case EF_MIPS_ARCH_3:
- case EF_MIPS_ARCH_4:
- case EF_MIPS_ARCH_5:
- case EF_MIPS_ARCH_32:
- case EF_MIPS_ARCH_64:
- case EF_MIPS_ARCH_32R2:
- case EF_MIPS_ARCH_64R2:
- case EF_MIPS_ARCH_32R6:
- case EF_MIPS_ARCH_64R6:
- break;
- default:
- return make_dynamic_error_code(Twine("Unsupported instruction set"));
- }
-
- // ... and still do not support MIPS-16 extension.
- if (newFlags & EF_MIPS_ARCH_ASE_M16)
- return make_dynamic_error_code(Twine("Unsupported extension: MIPS16"));
-
- // PIC code is inherently CPIC and may not set CPIC flag explicitly.
- // Ensure that this flag will exist in the linked file.
- if (newFlags & EF_MIPS_PIC)
- newFlags |= EF_MIPS_CPIC;
-
- std::lock_guard<std::mutex> lock(_mutex);
-
- // If the old set of flags is empty, use the new one as a result.
- if (!_flags) {
- _flags = newFlags;
- return std::error_code();
- }
-
- // Check PIC / CPIC flags compatibility.
- uint32_t newPic = newFlags & (EF_MIPS_PIC | EF_MIPS_CPIC);
- uint32_t oldPic = _flags & (EF_MIPS_PIC | EF_MIPS_CPIC);
-
- if ((newPic != 0) != (oldPic != 0))
- llvm::errs() << "lld warning: linking abicalls and non-abicalls files\n";
-
- if (!(newPic & EF_MIPS_PIC))
- _flags &= ~EF_MIPS_PIC;
- if (newPic)
- _flags |= EF_MIPS_CPIC;
-
- // Check mixing -mnan=2008 / -mnan=legacy modules.
- if ((newFlags & EF_MIPS_NAN2008) != (_flags & EF_MIPS_NAN2008))
- return make_dynamic_error_code(
- Twine("Linking -mnan=2008 and -mnan=legacy modules"));
-
- // Check ISA compatibility and update the extension flag.
- uint32_t oldArch = _flags & EF_MIPS_ARCH;
- if (!matchMipsISA(newArch, oldArch)) {
- if (!matchMipsISA(oldArch, newArch))
- return make_dynamic_error_code(
- Twine("Linking modules with incompatible ISA"));
- _flags &= ~EF_MIPS_ARCH;
- _flags |= newArch;
- }
-
- _flags |= newFlags & EF_MIPS_NOREORDER;
- _flags |= newFlags & EF_MIPS_MICROMIPS;
- _flags |= newFlags & EF_MIPS_NAN2008;
- _flags |= newFlags & EF_MIPS_32BITMODE;
-
- return std::error_code();
-}
diff --git a/lib/ReaderWriter/ELF/Mips/MipsELFFlagsMerger.h b/lib/ReaderWriter/ELF/Mips/MipsELFFlagsMerger.h
deleted file mode 100644
index 6ade86f0163c..000000000000
--- a/lib/ReaderWriter/ELF/Mips/MipsELFFlagsMerger.h
+++ /dev/null
@@ -1,36 +0,0 @@
-//===- lib/ReaderWriter/ELF/MipsELFFlagsMerger.h --------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_ELF_FLAGS_MERGER_H
-#define LLD_READER_WRITER_ELF_MIPS_MIPS_ELF_FLAGS_MERGER_H
-
-#include <mutex>
-#include <system_error>
-
-namespace lld {
-namespace elf {
-
-class MipsELFFlagsMerger {
-public:
- MipsELFFlagsMerger(bool is64Bits);
-
- uint32_t getMergedELFFlags() const;
-
- /// \brief Merge saved ELF header flags and the new set of flags.
- std::error_code merge(uint8_t newClass, uint32_t newFlags);
-
-private:
- const bool _is64Bit;
- std::mutex _mutex;
- uint32_t _flags;
-};
-
-} // namespace elf
-} // namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/ELF/Mips/MipsELFReader.h b/lib/ReaderWriter/ELF/Mips/MipsELFReader.h
deleted file mode 100644
index 8b325b38bb52..000000000000
--- a/lib/ReaderWriter/ELF/Mips/MipsELFReader.h
+++ /dev/null
@@ -1,93 +0,0 @@
-//===- lib/ReaderWriter/ELF/MipsELFReader.h -------------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_ELF_READER_H
-#define LLD_READER_WRITER_ELF_MIPS_MIPS_ELF_READER_H
-
-#include "ELFReader.h"
-#include "MipsELFFile.h"
-#include "MipsELFFlagsMerger.h"
-#include "MipsLinkingContext.h"
-
-namespace lld {
-namespace elf {
-
-struct MipsELFFileCreateTraits {
- typedef llvm::ErrorOr<std::unique_ptr<lld::File>> result_type;
-
- template <class ELFT>
- static result_type create(std::unique_ptr<llvm::MemoryBuffer> mb,
- MipsLinkingContext &ctx) {
- return lld::elf::MipsELFFile<ELFT>::create(std::move(mb), ctx);
- }
-};
-
-struct MipsDynamicFileCreateELFTraits {
- typedef llvm::ErrorOr<std::unique_ptr<lld::SharedLibraryFile>> result_type;
-
- template <class ELFT>
- static result_type create(std::unique_ptr<llvm::MemoryBuffer> mb,
- MipsLinkingContext &ctx) {
- return lld::elf::MipsDynamicFile<ELFT>::create(std::move(mb), ctx);
- }
-};
-
-template <class ELFT>
-class MipsELFObjectReader
- : public ELFObjectReader<ELFT, MipsELFFileCreateTraits,
- MipsLinkingContext> {
- typedef ELFObjectReader<ELFT, MipsELFFileCreateTraits, MipsLinkingContext>
- BaseReaderType;
-
-public:
- MipsELFObjectReader(MipsLinkingContext &ctx)
- : BaseReaderType(ctx, llvm::ELF::EM_MIPS),
- _flagMerger(ctx.getELFFlagsMerger()) {}
-
- std::error_code
- loadFile(std::unique_ptr<MemoryBuffer> mb, const Registry &registry,
- std::vector<std::unique_ptr<File>> &result) const override {
- auto &hdr = *this->elfHeader(*mb);
- if (std::error_code ec = _flagMerger.merge(hdr.getFileClass(), hdr.e_flags))
- return ec;
- return BaseReaderType::loadFile(std::move(mb), registry, result);
- }
-
-private:
- MipsELFFlagsMerger &_flagMerger;
-};
-
-template <class ELFT>
-class MipsELFDSOReader
- : public ELFDSOReader<ELFT, MipsDynamicFileCreateELFTraits,
- MipsLinkingContext> {
- typedef ELFDSOReader<ELFT, MipsDynamicFileCreateELFTraits, MipsLinkingContext>
- BaseReaderType;
-
-public:
- MipsELFDSOReader(MipsLinkingContext &ctx)
- : BaseReaderType(ctx, llvm::ELF::EM_MIPS),
- _flagMerger(ctx.getELFFlagsMerger()) {}
-
- std::error_code
- loadFile(std::unique_ptr<MemoryBuffer> mb, const Registry &registry,
- std::vector<std::unique_ptr<File>> &result) const override {
- auto &hdr = *this->elfHeader(*mb);
- if (std::error_code ec = _flagMerger.merge(hdr.getFileClass(), hdr.e_flags))
- return ec;
- return BaseReaderType::loadFile(std::move(mb), registry, result);
- }
-
-private:
- MipsELFFlagsMerger &_flagMerger;
-};
-
-} // namespace elf
-} // namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/ELF/Mips/MipsELFWriters.cpp b/lib/ReaderWriter/ELF/Mips/MipsELFWriters.cpp
new file mode 100644
index 000000000000..b97a4f5a9070
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsELFWriters.cpp
@@ -0,0 +1,292 @@
+//===- 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
index d94dd757a0f3..31b84f947c95 100644
--- a/lib/ReaderWriter/ELF/Mips/MipsELFWriters.h
+++ b/lib/ReaderWriter/ELF/Mips/MipsELFWriters.h
@@ -9,71 +9,91 @@
#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"
-#include "OutputELFWriter.h"
namespace lld {
namespace elf {
-template <class ELFT> class MipsRuntimeFile;
-
template <class ELFT> class MipsTargetLayout;
template <typename ELFT> class MipsELFWriter {
public:
- MipsELFWriter(MipsLinkingContext &ctx, MipsTargetLayout<ELFT> &targetLayout)
- : _ctx(ctx), _targetLayout(targetLayout) {}
-
- void setELFHeader(ELFHeader<ELFT> &elfHeader) {
- elfHeader.e_version(1);
- elfHeader.e_ident(llvm::ELF::EI_VERSION, llvm::ELF::EV_CURRENT);
- elfHeader.e_ident(llvm::ELF::EI_OSABI, llvm::ELF::ELFOSABI_NONE);
- if (_targetLayout.findOutputSection(".got.plt"))
- elfHeader.e_ident(llvm::ELF::EI_ABIVERSION, 1);
- else
- elfHeader.e_ident(llvm::ELF::EI_ABIVERSION, 0);
-
- elfHeader.e_flags(_ctx.getMergedELFFlags());
- }
-
- void finalizeMipsRuntimeAtomValues() {
- if (!_ctx.isDynamic())
- return;
-
- auto gotSection = _targetLayout.findOutputSection(".got");
- auto got = gotSection ? gotSection->virtualAddr() : 0;
- auto gp = gotSection ? got + _targetLayout.getGPOffset() : 0;
-
- setAtomValue("_GLOBAL_OFFSET_TABLE_", got);
- setAtomValue("_gp", gp);
- setAtomValue("_gp_disp", gp);
- setAtomValue("__gnu_local_gp", gp);
- }
-
- bool hasGlobalGOTEntry(const Atom *a) const {
- return _targetLayout.getGOTSection().hasGlobalGOTEntry(a);
- }
-
- std::unique_ptr<MipsRuntimeFile<ELFT>> createRuntimeFile() {
- auto file = llvm::make_unique<MipsRuntimeFile<ELFT>>(_ctx);
- if (_ctx.isDynamic()) {
- file->addAbsoluteAtom("_GLOBAL_OFFSET_TABLE_");
- file->addAbsoluteAtom("_gp");
- file->addAbsoluteAtom("_gp_disp");
- file->addAbsoluteAtom("__gnu_local_gp");
- }
- return file;
- }
+ 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);
- void setAtomValue(StringRef name, uint64_t value) {
- auto atom = _targetLayout.findAbsoluteAtom(name);
- assert(atom != _targetLayout.absoluteAtoms().end());
- (*atom)->_virtualAddr = value;
- }
+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
diff --git a/lib/ReaderWriter/ELF/Mips/MipsExecutableWriter.h b/lib/ReaderWriter/ELF/Mips/MipsExecutableWriter.h
deleted file mode 100644
index 1a85bba3bd0f..000000000000
--- a/lib/ReaderWriter/ELF/Mips/MipsExecutableWriter.h
+++ /dev/null
@@ -1,154 +0,0 @@
-//===- lib/ReaderWriter/ELF/Mips/MipsExecutableWriter.h -------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_EXECUTABLE_WRITER_H
-#define LLD_READER_WRITER_ELF_MIPS_MIPS_EXECUTABLE_WRITER_H
-
-#include "ExecutableWriter.h"
-#include "MipsDynamicTable.h"
-#include "MipsELFWriters.h"
-#include "MipsLinkingContext.h"
-
-namespace lld {
-namespace elf {
-
-template <typename ELFT> class MipsTargetLayout;
-
-template <class ELFT>
-class MipsExecutableWriter : public ExecutableWriter<ELFT> {
-public:
- MipsExecutableWriter(MipsLinkingContext &ctx, MipsTargetLayout<ELFT> &layout);
-
-protected:
- void buildDynamicSymbolTable(const File &file) override;
-
- // Add any runtime files and their atoms to the output
- bool createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
-
- void finalizeDefaultAtomValues() override;
- std::error_code setELFHeader() override;
-
- unique_bump_ptr<SymbolTable<ELFT>> createSymbolTable() override;
- unique_bump_ptr<DynamicTable<ELFT>> createDynamicTable() override;
-
- unique_bump_ptr<DynamicSymbolTable<ELFT>>
- createDynamicSymbolTable() override;
-
-private:
- MipsELFWriter<ELFT> _writeHelper;
- MipsTargetLayout<ELFT> &_mipsTargetLayout;
-};
-
-template <class ELFT>
-MipsExecutableWriter<ELFT>::MipsExecutableWriter(MipsLinkingContext &ctx,
- MipsTargetLayout<ELFT> &layout)
- : ExecutableWriter<ELFT>(ctx, layout), _writeHelper(ctx, layout),
- _mipsTargetLayout(layout) {}
-
-template <class ELFT>
-std::error_code MipsExecutableWriter<ELFT>::setELFHeader() {
- std::error_code ec = ExecutableWriter<ELFT>::setELFHeader();
- if (ec)
- return ec;
-
- StringRef entryName = this->_context.entrySymbolName();
- if (const AtomLayout *al = this->_layout.findAtomLayoutByName(entryName)) {
- const auto *ea = cast<DefinedAtom>(al->_atom);
- if (ea->codeModel() == DefinedAtom::codeMipsMicro ||
- ea->codeModel() == DefinedAtom::codeMipsMicroPIC)
- // Adjust entry symbol value if this symbol is microMIPS encoded.
- this->_elfHeader->e_entry(al->_virtualAddr | 1);
- }
-
- _writeHelper.setELFHeader(*this->_elfHeader);
- return std::error_code();
-}
-
-template <class ELFT>
-void MipsExecutableWriter<ELFT>::buildDynamicSymbolTable(const File &file) {
- // MIPS ABI requires to add to dynsym even undefined symbols
- // if they have a corresponding entries in a global part of GOT.
- for (auto sec : this->_layout.sections())
- if (auto section = dyn_cast<AtomSection<ELFT>>(sec))
- for (const auto &atom : section->atoms()) {
- if (_writeHelper.hasGlobalGOTEntry(atom->_atom)) {
- this->_dynamicSymbolTable->addSymbol(atom->_atom, section->ordinal(),
- atom->_virtualAddr, atom);
- continue;
- }
-
- const DefinedAtom *da = dyn_cast<const DefinedAtom>(atom->_atom);
- if (!da)
- continue;
-
- if (da->dynamicExport() != DefinedAtom::dynamicExportAlways &&
- !this->_context.isDynamicallyExportedSymbol(da->name()) &&
- !(this->_context.shouldExportDynamic() &&
- da->scope() == Atom::Scope::scopeGlobal))
- continue;
-
- this->_dynamicSymbolTable->addSymbol(atom->_atom, section->ordinal(),
- atom->_virtualAddr, atom);
- }
-
- for (const UndefinedAtom *a : file.undefined())
- // FIXME (simon): Consider to move this check to the
- // MipsELFUndefinedAtom class method. That allows to
- // handle more complex coditions in the future.
- if (_writeHelper.hasGlobalGOTEntry(a))
- this->_dynamicSymbolTable->addSymbol(a, ELF::SHN_UNDEF);
-
- // Skip our immediate parent class method
- // ExecutableWriter<ELFT>::buildDynamicSymbolTable because we replaced it
- // with our own version. Call OutputELFWriter directly.
- OutputELFWriter<ELFT>::buildDynamicSymbolTable(file);
-}
-
-template <class ELFT>
-bool MipsExecutableWriter<ELFT>::createImplicitFiles(
- std::vector<std::unique_ptr<File>> &result) {
- ExecutableWriter<ELFT>::createImplicitFiles(result);
- result.push_back(std::move(_writeHelper.createRuntimeFile()));
- return true;
-}
-
-template <class ELFT>
-void MipsExecutableWriter<ELFT>::finalizeDefaultAtomValues() {
- // Finalize the atom values that are part of the parent.
- ExecutableWriter<ELFT>::finalizeDefaultAtomValues();
- _writeHelper.finalizeMipsRuntimeAtomValues();
-}
-
-template <class ELFT>
-unique_bump_ptr<SymbolTable<ELFT>>
- MipsExecutableWriter<ELFT>::createSymbolTable() {
- return unique_bump_ptr<SymbolTable<ELFT>>(new (
- this->_alloc) MipsSymbolTable<ELFT>(this->_context));
-}
-
-/// \brief create dynamic table
-template <class ELFT>
-unique_bump_ptr<DynamicTable<ELFT>>
- MipsExecutableWriter<ELFT>::createDynamicTable() {
- return unique_bump_ptr<DynamicTable<ELFT>>(new (
- this->_alloc) MipsDynamicTable<ELFT>(this->_context, _mipsTargetLayout));
-}
-
-/// \brief create dynamic symbol table
-template <class ELFT>
-unique_bump_ptr<DynamicSymbolTable<ELFT>>
- MipsExecutableWriter<ELFT>::createDynamicSymbolTable() {
- return unique_bump_ptr<DynamicSymbolTable<ELFT>>(
- new (this->_alloc) MipsDynamicSymbolTable<ELFT>(
- this->_context, _mipsTargetLayout));
-}
-
-} // namespace elf
-} // namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp b/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp
index 7bffcbeb5c08..b6cdd5c1487c 100644
--- a/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp
+++ b/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp
@@ -17,43 +17,46 @@ using namespace lld;
using namespace lld::elf;
std::unique_ptr<ELFLinkingContext>
-MipsLinkingContext::create(llvm::Triple triple) {
- if (triple.getArch() == llvm::Triple::mipsel ||
+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 std::unique_ptr<ELFLinkingContext>(new MipsLinkingContext(triple));
+ return llvm::make_unique<MipsLinkingContext>(triple);
return nullptr;
}
-typedef std::unique_ptr<TargetHandlerBase> TargetHandlerBasePtr;
-
-static TargetHandlerBasePtr createTarget(llvm::Triple triple,
- MipsLinkingContext &ctx) {
+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 TargetHandlerBasePtr(new MipsTargetHandler<Mips32ELType>(ctx));
+ return llvm::make_unique<MipsTargetHandler<ELF32LE>>(ctx);
+ case llvm::Triple::mips64:
+ return llvm::make_unique<MipsTargetHandler<ELF64BE>>(ctx);
case llvm::Triple::mips64el:
- return TargetHandlerBasePtr(new MipsTargetHandler<Mips64ELType>(ctx));
+ return llvm::make_unique<MipsTargetHandler<ELF64LE>>(ctx);
default:
llvm_unreachable("Unhandled arch");
}
}
MipsLinkingContext::MipsLinkingContext(llvm::Triple triple)
- : ELFLinkingContext(triple, createTarget(triple, *this)),
- _flagsMerger(triple.isArch64Bit()) {}
-
-uint32_t MipsLinkingContext::getMergedELFFlags() const {
- return _flagsMerger.getMergedELFFlags();
-}
-
-MipsELFFlagsMerger &MipsLinkingContext::getELFFlagsMerger() {
- return _flagsMerger;
-}
+ : ELFLinkingContext(triple, createTarget(triple, *this)) {}
uint64_t MipsLinkingContext::getBaseAddress() const {
- if (_baseAddress == 0 && getOutputELFType() == llvm::ELF::ET_EXEC)
- return getTriple().isArch64Bit() ? 0x120000000 : 0x400000;
- return _baseAddress;
+ 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 {
@@ -63,7 +66,15 @@ StringRef MipsLinkingContext::entrySymbolName() const {
}
StringRef MipsLinkingContext::getDefaultInterpreter() const {
- return getTriple().isArch64Bit() ? "/lib64/ld.so.1" : "/lib/ld.so.1";
+ 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) {
@@ -81,13 +92,14 @@ bool MipsLinkingContext::isDynamicRelocation(const Reference &r) const {
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 true;
+ return isDynamic();
default:
return false;
}
@@ -113,3 +125,40 @@ bool MipsLinkingContext::isPLTRelocation(const Reference &r) const {
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
index 824605f5fa7f..414d2c785e17 100644
--- a/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h
+++ b/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h
@@ -9,7 +9,7 @@
#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_LINKING_CONTEXT_H
#define LLD_READER_WRITER_ELF_MIPS_MIPS_LINKING_CONTEXT_H
-#include "MipsELFFlagsMerger.h"
+#include "MipsAbiInfoHandler.h"
#include "lld/ReaderWriter/ELFLinkingContext.h"
namespace lld {
@@ -23,10 +23,6 @@ enum {
LLD_R_MIPS_32_HI16 = 1025,
/// \brief The same as R_MIPS_26 but for global symbols.
LLD_R_MIPS_GLOBAL_26 = 1026,
- /// \brief Setup hi 16 bits using the symbol this reference refers to.
- LLD_R_MIPS_HI16 = 1027,
- /// \brief Setup low 16 bits using the symbol this reference refers to.
- LLD_R_MIPS_LO16 = 1028,
/// \brief Represents a reference between PLT and dynamic symbol.
LLD_R_MIPS_STO_PLT = 1029,
/// \brief The same as R_MICROMIPS_26_S1 but for global symbols.
@@ -35,20 +31,12 @@ enum {
LLD_R_MIPS_64_HI16 = 1031,
};
-typedef llvm::object::ELFType<llvm::support::little, 2, false> Mips32ELType;
-typedef llvm::object::ELFType<llvm::support::little, 2, true> Mips64ELType;
-typedef llvm::object::ELFType<llvm::support::big, 2, false> Mips32BEType;
-typedef llvm::object::ELFType<llvm::support::big, 2, true> Mips64BEType;
-
class MipsLinkingContext final : public ELFLinkingContext {
public:
- static std::unique_ptr<ELFLinkingContext> create(llvm::Triple);
MipsLinkingContext(llvm::Triple triple);
- uint32_t getMergedELFFlags() const;
- MipsELFFlagsMerger &getELFFlagsMerger();
-
- // ELFLinkingContext
+ 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;
@@ -57,9 +45,9 @@ public:
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;
-private:
- MipsELFFlagsMerger _flagsMerger;
+ MipsAbi getAbi() const;
};
} // elf
diff --git a/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp b/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp
index 173ce0e6b1a8..c55a7a4116e6 100644
--- a/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp
+++ b/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp
@@ -7,9 +7,10 @@
//
//===----------------------------------------------------------------------===//
-#include "MipsTargetHandler.h"
#include "MipsLinkingContext.h"
#include "MipsRelocationHandler.h"
+#include "MipsTargetLayout.h"
+#include "llvm/Support/Format.h"
using namespace lld;
using namespace elf;
@@ -20,306 +21,265 @@ 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
+ 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 MipsRelocationHandler {
+template <class ELFT> class RelocationHandler : public TargetRelocationHandler {
public:
- RelocationHandler(MipsLinkingContext &ctx) : _ctx(ctx) {}
+ RelocationHandler(MipsLinkingContext &ctx, MipsTargetLayout<ELFT> &layout)
+ : _ctx(ctx), _targetLayout(layout) {}
std::error_code applyRelocation(ELFWriter &writer,
llvm::FileOutputBuffer &buf,
- const lld::AtomLayout &atom,
+ const AtomLayout &atom,
const Reference &ref) const override;
- Reference::Addend readAddend(Reference::KindValue kind,
- const uint8_t *content) 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};
+ return {4, 0x0, 0, false, dummyCheck};
case R_MIPS_64:
case R_MIPS_SUB:
- return {8, 0xffffffffffffffffull, 0, false};
+ 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:
- return {4, 0xffffffff, 0, false};
+ case R_MIPS_EH:
+ return {4, 0xffffffff, 0, false, dummyCheck};
case LLD_R_MIPS_32_HI16:
- return {4, 0xffff0000, 0, false};
+ return {4, 0xffff0000, 0, false, dummyCheck};
case LLD_R_MIPS_64_HI16:
- return {8, 0xffffffffffff0000ull, 0, false};
+ return {8, 0xffffffffffff0000ull, 0, false, dummyCheck};
case R_MIPS_26:
case LLD_R_MIPS_GLOBAL_26:
- return {4, 0x3ffffff, 2, false};
+ 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};
+ return {4, 0x3ffff, 3, false, signedCheck<21>};
case R_MIPS_PC19_S2:
- return {4, 0x7ffff, 2, false};
+ return {4, 0x7ffff, 2, false, signedCheck<21>};
case R_MIPS_PC21_S2:
- return {4, 0x1fffff, 2, false};
+ return {4, 0x1fffff, 2, false, signedCheck<23>};
case R_MIPS_PC26_S2:
- return {4, 0x3ffffff, 2, false};
+ 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_GPREL16:
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:
- case LLD_R_MIPS_HI16:
- case LLD_R_MIPS_LO16:
- return {4, 0xffff, 0, false};
+ 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};
+ return {4, 0xffff, 0, true, dummyCheck};
case R_MICROMIPS_26_S1:
case LLD_R_MICROMIPS_GLOBAL_26_S1:
- return {4, 0x3ffffff, 1, true};
+ return {4, 0x3ffffff, 1, true, dummyCheck};
case R_MICROMIPS_HI16:
+ return {4, 0xffff, 0, true, gpDispCheck<16>};
case R_MICROMIPS_LO16:
- case R_MICROMIPS_GOT16:
- return {4, 0xffff, 0, true};
+ 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};
+ return {4, 0xffff, 1, true, signedCheck<17>};
case R_MICROMIPS_PC7_S1:
- return {4, 0x7f, 1, false};
+ return {4, 0x7f, 1, false, signedCheck<8>};
case R_MICROMIPS_PC10_S1:
- return {4, 0x3ff, 1, false};
+ return {4, 0x3ff, 1, false, signedCheck<11>};
case R_MICROMIPS_PC23_S2:
- return {4, 0x7fffff, 2, true};
- case R_MIPS_CALL16:
- case R_MIPS_TLS_GD:
- case R_MIPS_TLS_LDM:
- case R_MIPS_TLS_GOTTPREL:
- return {4, 0xffff, 0, false};
+ 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:
- return {4, 0xffff, 0, true};
+ 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, 0x0, 0, false};
+ return {4, 0xffffffff, 0, false, dummyCheck};
case R_MICROMIPS_JALR:
- return {4, 0x0, 0, true};
- case R_MIPS_REL32:
+ 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:
- // Ignore runtime relocations.
- return {4, 0x0, 0, false};
+ return {4, 0xffffffff, 0, false, dummyCheck};
case R_MIPS_TLS_DTPMOD64:
case R_MIPS_TLS_DTPREL64:
case R_MIPS_TLS_TPREL64:
- return {8, 0x0, 0, false};
+ 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};
+ return {4, 0x0, 0, false, dummyCheck};
default:
llvm_unreachable("Unknown relocation");
}
}
-/// \brief R_MIPS_32
-/// local/external: word32 S + A (truncate)
-static uint32_t reloc32(uint64_t S, int64_t A) { return S + A; }
-
-/// \brief R_MIPS_64
-/// local/external: word64 S + A (truncate)
-static uint64_t reloc64(uint64_t S, int64_t A) { return S + A; }
-
-/// \brief R_MIPS_SUB
-/// local/external: word64 S - A (truncate)
-static uint64_t relocSub(uint64_t S, int64_t A) { return S - A; }
-
-/// \brief R_MIPS_PC32
-/// local/external: word32 S + A i- P (truncate)
-static uint32_t relocpc32(uint64_t P, uint64_t S, int64_t A) {
- return S + A - P;
-}
-
-/// \brief R_MIPS_26, R_MICROMIPS_26_S1
-/// local : ((A | ((P + 4) & 0x3F000000)) + S) >> 2
-static uint32_t reloc26loc(uint64_t P, uint64_t S, int32_t A, uint32_t shift) {
- uint32_t result = (A | ((P + 4) & (0xfc000000 << shift))) + S;
- return result >> shift;
-}
-
-/// \brief LLD_R_MIPS_GLOBAL_26, LLD_R_MICROMIPS_GLOBAL_26_S1
-/// external: (sign-extend(A) + S) >> 2
-static uint32_t reloc26ext(uint64_t S, int32_t A, uint32_t shift) {
- int32_t result =
- shift == 1 ? llvm::SignExtend32<27>(A) : llvm::SignExtend32<28>(A);
- return (result + S) >> shift;
-}
-
-/// \brief R_MIPS_HI16, R_MIPS_TLS_DTPREL_HI16, R_MIPS_TLS_TPREL_HI16,
-/// R_MICROMIPS_HI16, R_MICROMIPS_TLS_DTPREL_HI16, R_MICROMIPS_TLS_TPREL_HI16,
-/// LLD_R_MIPS_HI16
-/// local/external: hi16 (AHL + S) - (short)(AHL + S) (truncate)
-/// _gp_disp : hi16 (AHL + GP - P) - (short)(AHL + GP - P) (verify)
-static uint32_t relocHi16(uint64_t P, uint64_t S, int64_t AHL, bool isGPDisp) {
- int32_t result = isGPDisp ? AHL + S - P : AHL + S;
- return (result + 0x8000) >> 16;
-}
+template <class ELFT>
+static uint64_t relocRead(const MipsRelocationParams &params,
+ const uint8_t *loc);
-/// \brief R_MIPS_PCHI16
-/// local/external: hi16 (S + AHL - P)
-static uint32_t relocPcHi16(uint64_t P, uint64_t S, int64_t AHL) {
- int32_t result = S + AHL - P;
- return (result + 0x8000) >> 16;
+static int64_t getHi16(int64_t value) {
+ return ((value + 0x8000) >> 16) & 0xffff;
}
-/// \brief R_MIPS_LO16, R_MIPS_TLS_DTPREL_LO16, R_MIPS_TLS_TPREL_LO16,
-/// R_MICROMIPS_LO16, R_MICROMIPS_TLS_DTPREL_LO16, R_MICROMIPS_TLS_TPREL_LO16,
-/// LLD_R_MIPS_LO16
-/// local/external: lo16 AHL + S (truncate)
-/// _gp_disp : lo16 AHL + GP - P + 4 (verify)
-static uint32_t relocLo16(uint64_t P, uint64_t S, int64_t AHL, bool isGPDisp,
- bool micro) {
- int32_t result = isGPDisp ? AHL + S - P + (micro ? 3 : 4) : AHL + S;
- return result;
+static int64_t getHigher16(int64_t value) {
+ return ((value + 0x80008000ull) >> 32) & 0xffff;
}
-/// \brief R_MIPS_PCLO16
-/// local/external: lo16 (S + AHL - P)
-static uint32_t relocPcLo16(uint64_t P, uint64_t S, int64_t AHL) {
- AHL = llvm::SignExtend32<16>(AHL);
- int32_t result = S + AHL - P;
- return result;
+static int64_t getHighest16(int64_t value) {
+ return ((value + 0x800080008000ull) >> 48) & 0xffff;
}
-/// \brief R_MIPS_GOT16, R_MIPS_CALL16, R_MICROMIPS_GOT16, R_MICROMIPS_CALL16
-/// rel16 G (verify)
-static uint64_t relocGOT(uint64_t S, uint64_t GP) {
- int64_t G = (int64_t)(S - GP);
- return G;
+static int64_t maskLow16(int64_t value) {
+ return (value + 0x8000) & ~0xffff;
}
-/// R_MIPS_GOT_OFST
+/// R_MIPS_GOT_OFST, R_MICROMIPS_GOT_OFST
/// rel16 offset of (S+A) from the page pointer (verify)
-static uint32_t relocGOTOfst(uint64_t S, int64_t A) {
- uint64_t page = (S + A + 0x8000) & ~0xffff;
+static int32_t relocGOTOfst(uint64_t S, int64_t A) {
+ int64_t page = maskLow16(S + A);
return S + A - page;
}
-/// \brief R_MIPS_GPREL16
-/// local: sign-extend(A) + S + GP0 - GP
-/// external: sign-extend(A) + S - GP
-static uint64_t relocGPRel16(uint64_t S, int64_t A, uint64_t GP) {
- // We added GP0 to addendum for a local symbol during a Relocation pass.
- return llvm::SignExtend32<16>(A) + S - GP;
-}
-
-/// \brief R_MIPS_GPREL32
-/// local: rel32 A + S + GP0 - GP (truncate)
-static uint64_t relocGPRel32(uint64_t S, int64_t A, uint64_t GP) {
- // We added GP0 to addendum for a local symbol during a Relocation pass.
- return A + S - GP;
-}
-
-/// \brief R_MIPS_PC18_S3
-/// local/external: (S + A - P) >> 3 (P with cleared 3 less significant bits)
-static uint32_t relocPc18(uint64_t P, uint64_t S, int64_t A) {
- A = llvm::SignExtend32<21>(A);
- // FIXME (simon): Check that S + A has 8-byte alignment
- int32_t result = S + A - ((P | 7) ^ 7);
- return result >> 3;
-}
-
-/// \brief R_MIPS_PC19_S2
+/// \brief R_MIPS_PC16
/// local/external: (S + A - P) >> 2
-static uint32_t relocPc19(uint64_t P, uint64_t S, int64_t A) {
- A = llvm::SignExtend32<21>(A);
- // FIXME (simon): Check that S + A has 4-byte alignment
- int32_t result = S + A - P;
- return result >> 2;
+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_PC21_S2
-/// local/external: (S + A - P) >> 2
-static uint32_t relocPc21(uint64_t P, uint64_t S, int64_t A) {
- A = llvm::SignExtend32<23>(A);
- // FIXME (simon): Check that S + A has 4-byte alignment
- int32_t result = S + A - P;
- return result >> 2;
+/// \brief R_MIPS_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_PC26_S2
+/// \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 uint32_t relocPc26(uint64_t P, uint64_t S, int64_t A) {
- A = llvm::SignExtend32<28>(A);
- // FIXME (simon): Check that S + A has 4-byte alignment
- int32_t result = S + A - P;
- return result >> 2;
-}
-
-/// \brief R_MICROMIPS_PC7_S1
-static uint32_t relocPc7(uint64_t P, uint64_t S, int64_t A) {
- A = llvm::SignExtend32<8>(A);
- int32_t result = S + A - P;
- return result >> 1;
-}
-
-/// \brief R_MICROMIPS_PC10_S1
-static uint32_t relocPc10(uint64_t P, uint64_t S, int64_t A) {
- A = llvm::SignExtend32<11>(A);
- int32_t result = S + A - P;
- return result >> 1;
-}
-
-/// \brief R_MICROMIPS_PC16_S1
-static uint32_t relocPc16(uint64_t P, uint64_t S, int64_t A) {
- A = llvm::SignExtend32<17>(A);
- int32_t result = S + A - P;
- return result >> 1;
-}
-
-/// \brief R_MICROMIPS_PC23_S2
-static uint32_t relocPc23(uint64_t P, uint64_t S, int64_t A) {
- A = llvm::SignExtend32<25>(A);
- int32_t result = S + A - P;
-
- // Check addiupc 16MB range.
- if (result + 0x1000000 >= 0x2000000)
- llvm::errs() << "The addiupc instruction immediate "
- << llvm::format_hex(result, 10) << " is out of range.\n";
-
- return result >> 2;
+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;
}
-/// \brief LLD_R_MIPS_32_HI16, LLD_R_MIPS_64_HI16
-static uint64_t relocMaskLow16(uint64_t S, int64_t A) {
- return S + A + 0x8000;
+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)
+ if (mode == CrossJumpMode::None || mode == CrossJumpMode::ToMicroJalr)
return std::error_code();
bool toMicro = mode == CrossJumpMode::ToMicro;
@@ -327,8 +287,7 @@ static std::error_code adjustJumpOpCode(uint64_t &ins, uint64_t tgt,
uint32_t opCross = toMicro ? 0x1d : 0x3c;
if ((tgt & 1) != toMicro)
- return make_dynamic_error_code(
- Twine("Incorrect bit 0 for the jalx target"));
+ 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") +
@@ -356,6 +315,8 @@ static CrossJumpMode getCrossJumpMode(const Reference &ref) {
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;
@@ -367,44 +328,64 @@ static CrossJumpMode getCrossJumpMode(const Reference &ref) {
}
}
-static uint32_t microShuffle(uint32_t ins) {
- return ((ins & 0xffff) << 16) | ((ins & 0xffff0000) >> 16);
-}
-
-static ErrorOr<uint64_t> calculateRelocation(Reference::KindValue kind,
- Reference::Addend addend,
- uint64_t tgtAddr, uint64_t relAddr,
- uint64_t gpAddr, bool isGP,
- CrossJumpMode jumpMode) {
- bool isCrossJump = jumpMode != CrossJumpMode::None;
+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:
- return reloc32(tgtAddr, addend);
case R_MIPS_64:
- return reloc64(tgtAddr, addend);
+ 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:
- return relocSub(tgtAddr, addend);
+ case R_MICROMIPS_SUB:
+ return tgtAddr - addend;
case R_MIPS_26:
- return reloc26loc(relAddr, tgtAddr, addend, 2);
+ return tgtAddr + (addend | (relAddr & 0xf0000000));
case R_MICROMIPS_26_S1:
- return reloc26loc(relAddr, tgtAddr, addend, isCrossJump ? 2 : 1);
+ return tgtAddr + (addend | (relAddr & 0xf8000000));
case R_MIPS_HI16:
case R_MICROMIPS_HI16:
- return relocHi16(relAddr, tgtAddr, addend, isGP);
+ return getHi16(tgtAddr + addend - (isGP ? relAddr : 0));
case R_MIPS_PCHI16:
- return relocPcHi16(relAddr, tgtAddr, addend);
+ return getHi16(tgtAddr + addend - relAddr);
case R_MIPS_LO16:
- return relocLo16(relAddr, tgtAddr, addend, isGP, false);
- case R_MIPS_PCLO16:
- return relocPcLo16(relAddr, tgtAddr, addend);
+ return tgtAddr + addend - (isGP ? relAddr - 4 : 0);
case R_MICROMIPS_LO16:
- return relocLo16(relAddr, tgtAddr, addend, isGP, true);
+ 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:
@@ -413,71 +394,66 @@ static ErrorOr<uint64_t> calculateRelocation(Reference::KindValue kind,
case R_MICROMIPS_TLS_GD:
case R_MICROMIPS_TLS_LDM:
case R_MICROMIPS_TLS_GOTTPREL:
- return relocGOT(tgtAddr, gpAddr);
+ 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:
- return relocPc19(relAddr, tgtAddr, addend);
+ case R_MICROMIPS_PC19_S2:
case R_MIPS_PC21_S2:
- return relocPc21(relAddr, tgtAddr, addend);
+ case R_MICROMIPS_PC21_S2:
case R_MIPS_PC26_S2:
- return relocPc26(relAddr, tgtAddr, addend);
+ case R_MICROMIPS_PC26_S2:
+ return relocPcS2(relAddr, tgtAddr, addend);
+ case R_MIPS_PC32:
+ case R_MIPS_PCLO16:
case R_MICROMIPS_PC7_S1:
- return relocPc7(relAddr, tgtAddr, addend);
case R_MICROMIPS_PC10_S1:
- return relocPc10(relAddr, tgtAddr, addend);
case R_MICROMIPS_PC16_S1:
- return relocPc16(relAddr, tgtAddr, addend);
case R_MICROMIPS_PC23_S2:
- return relocPc23(relAddr, tgtAddr, addend);
+ 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 relocHi16(0, tgtAddr, addend, false);
- case R_MIPS_TLS_DTPREL_LO16:
- case R_MIPS_TLS_TPREL_LO16:
- return relocLo16(0, tgtAddr, addend, false, false);
- case R_MICROMIPS_TLS_DTPREL_LO16:
- case R_MICROMIPS_TLS_TPREL_LO16:
- return relocLo16(0, tgtAddr, addend, false, true);
- case R_MIPS_GPREL16:
- return relocGPRel16(tgtAddr, addend, gpAddr);
- case R_MIPS_GPREL32:
- return relocGPRel32(tgtAddr, addend, gpAddr);
+ 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_DTPREL32:
- case R_MIPS_TLS_TPREL32:
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:
- // Ignore runtime relocations.
- return 0;
- case R_MIPS_PC32:
- return relocpc32(relAddr, tgtAddr, addend);
- case LLD_R_MIPS_GLOBAL_GOT:
- // Do nothing.
+ return isDynamic ? 0 : tgtAddr + addend - 0x7000;
case LLD_R_MIPS_32_HI16:
case LLD_R_MIPS_64_HI16:
- return relocMaskLow16(tgtAddr, addend);
- case LLD_R_MIPS_GLOBAL_26:
- return reloc26ext(tgtAddr, addend, 2);
- case LLD_R_MICROMIPS_GLOBAL_26_S1:
- return reloc26ext(tgtAddr, addend, isCrossJump ? 2 : 1);
- case LLD_R_MIPS_HI16:
- return relocHi16(0, tgtAddr, 0, false);
- case LLD_R_MIPS_LO16:
- return relocLo16(0, tgtAddr, 0, false, false);
+ return maskLow16(tgtAddr + addend);
case LLD_R_MIPS_STO_PLT:
+ case LLD_R_MIPS_GLOBAL_GOT:
// Do nothing.
return 0;
default:
@@ -488,27 +464,29 @@ static ErrorOr<uint64_t> calculateRelocation(Reference::KindValue kind,
template <class ELFT>
static uint64_t relocRead(const MipsRelocationParams &params,
const uint8_t *loc) {
- uint64_t data;
+ 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:
- data = endian::read<uint32_t, ELFT::TargetEndianness, unaligned>(loc);
- break;
+ return endian::read<uint32_t, ELFT::TargetEndianness, unaligned>(&data);
case 8:
- data = endian::read<uint64_t, ELFT::TargetEndianness, unaligned>(loc);
- break;
+ return endian::read<uint64_t, ELFT::TargetEndianness, unaligned>(&data);
default:
llvm_unreachable("Unexpected size");
}
- if (params._shuffle)
- data = microShuffle(data);
- return data;
}
template <class ELFT>
static void relocWrite(uint64_t data, const MipsRelocationParams &params,
uint8_t *loc) {
- if (params._shuffle)
- data = microShuffle(data);
switch (params._size) {
case 4:
endian::write<uint32_t, ELFT::TargetEndianness, unaligned>(loc, data);
@@ -519,24 +497,50 @@ static void relocWrite(uint64_t data, const MipsRelocationParams &params,
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 lld::AtomLayout &atom,
+ ELFWriter &writer, llvm::FileOutputBuffer &buf, const AtomLayout &atom,
const Reference &ref) const {
- if (ref.kindNamespace() != lld::Reference::KindNamespace::ELF)
+ if (ref.kindNamespace() != Reference::KindNamespace::ELF)
return std::error_code();
assert(ref.kindArch() == Reference::KindArch::Mips);
- auto &targetLayout = static_cast<MipsTargetLayout<ELFT> &>(
- _ctx.getTargetHandler<ELFT>().getTargetLayout());
-
- AtomLayout *gpAtom = targetLayout.getGP();
- uint64_t gpAddr = gpAtom ? gpAtom->_virtualAddr : 0;
-
- AtomLayout *gpDispAtom = targetLayout.getGPDisp();
- bool isGpDisp = gpDispAtom && ref.target() == gpDispAtom->_atom;
+ 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();
@@ -547,26 +551,37 @@ std::error_code RelocationHandler<ELFT>::applyRelocation(
tgtAddr |= 1;
CrossJumpMode jumpMode = getCrossJumpMode(ref);
-
- ErrorOr<uint64_t> res =
- calculateRelocation(ref.kindValue(), ref.addend(), tgtAddr, relAddr,
- gpAddr, isGpDisp, jumpMode);
- if (auto ec = res.getError())
- return ec;
-
- Reference::KindValue op = ref.kindValue();
-
- // FIXME (simon): Handle r_ssym value.
- for (auto tag = (ref.tag() & 0xffff); tag & 0xff; tag >>= 8) {
- op = tag & 0xff;
- res = calculateRelocation(op, *res, 0, relAddr, gpAddr, isGpDisp, jumpMode);
+ 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(op);
+ auto params = getRelocationParams(lastRel);
uint64_t ins = relocRead<ELFT>(params, location);
-
if (auto ec = adjustJumpOpCode(ins, tgtAddr, jumpMode))
return ec;
@@ -576,31 +591,97 @@ std::error_code RelocationHandler<ELFT>::applyRelocation(
return std::error_code();
}
-template <class ELFT>
-Reference::Addend
-RelocationHandler<ELFT>::readAddend(Reference::KindValue kind,
- const uint8_t *content) const {
- auto params = getRelocationParams(kind);
- uint64_t ins = relocRead<ELFT>(params, content);
- return (ins & params._mask) << params._shift;
-}
-
namespace lld {
namespace elf {
template <>
std::unique_ptr<TargetRelocationHandler>
-createMipsRelocationHandler<Mips32ELType>(MipsLinkingContext &ctx) {
- return std::unique_ptr<TargetRelocationHandler>(
- new RelocationHandler<Mips32ELType>(ctx));
+createMipsRelocationHandler<ELF32BE>(MipsLinkingContext &ctx,
+ MipsTargetLayout<ELF32BE> &layout) {
+ return llvm::make_unique<RelocationHandler<ELF32BE>>(ctx, layout);
}
template <>
std::unique_ptr<TargetRelocationHandler>
-createMipsRelocationHandler<Mips64ELType>(MipsLinkingContext &ctx) {
- return std::unique_ptr<TargetRelocationHandler>(
- new RelocationHandler<Mips64ELType>(ctx));
+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
index 87066b2b5c10..62a7aee34496 100644
--- a/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.h
+++ b/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.h
@@ -9,22 +9,22 @@
#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_RELOCATION_HANDLER_H
#define LLD_READER_WRITER_ELF_MIPS_MIPS_RELOCATION_HANDLER_H
-#include "TargetHandler.h"
#include "lld/Core/Reference.h"
namespace lld {
namespace elf {
-class MipsRelocationHandler : public TargetRelocationHandler {
-public:
- virtual Reference::Addend readAddend(Reference::KindValue kind,
- const uint8_t *content) const = 0;
-};
+class MipsLinkingContext;
+template<typename ELFT> class MipsTargetLayout;
template <class ELFT>
std::unique_ptr<TargetRelocationHandler>
-createMipsRelocationHandler(MipsLinkingContext &ctx);
+createMipsRelocationHandler(MipsLinkingContext &ctx,
+ MipsTargetLayout<ELFT> &layout);
+template <class ELFT>
+Reference::Addend readMipsRelocAddend(Reference::KindValue kind,
+ const uint8_t *content);
} // elf
} // lld
diff --git a/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp b/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp
index a1b3530dfcdf..b47c7d2210db 100644
--- a/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp
+++ b/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp
@@ -37,20 +37,69 @@ static const uint8_t mipsGotTlsGdAtomContent[] = {
0x00, 0x00, 0x00, 0x00
};
-// Regular PLT0 entry
-static const uint8_t mipsPlt0AtomContent[] = {
+// 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
- 0x21, 0x78, 0xe0, 0x03, // move $15, $31
+ 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 PLT0 entry
-static const uint8_t micromipsPlt0AtomContent[] = {
+// 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
@@ -62,40 +111,80 @@ static const uint8_t micromipsPlt0AtomContent[] = {
0x00, 0x0c // nop
};
-// Regular PLT entry
-static const uint8_t mipsPltAAtomContent[] = {
+// 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 PLT entry
-static const uint8_t micromipsPltAtomContent[] = {
+// 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 PLT entry
-static const uint8_t mipsR6PltAAtomContent[] = {
+// 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 stub entry
-static const uint8_t mipsLA25AtomContent[] = {
+// 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 stub entry
-static const uint8_t micromipsLA25AtomContent[] = {
+// 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)
@@ -109,7 +198,7 @@ class MipsGOTAtom : public GOTAtom {
public:
MipsGOTAtom(const File &f) : GOTAtom(f, ".got") {}
- Alignment alignment() const override { return Alignment(2); }
+ Alignment alignment() const override { return 4; }
};
/// \brief MIPS GOT entry initialized by zero.
@@ -120,10 +209,16 @@ public:
ArrayRef<uint8_t> rawContent() const override;
};
-template <> ArrayRef<uint8_t> GOT0Atom<Mips32ELType>::rawContent() const {
+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<Mips64ELType>::rawContent() const {
+template <> ArrayRef<uint8_t> GOT0Atom<ELF64BE>::rawContent() const {
+ return llvm::makeArrayRef(mipsGot0AtomContent);
+}
+template <> ArrayRef<uint8_t> GOT0Atom<ELF64LE>::rawContent() const {
return llvm::makeArrayRef(mipsGot0AtomContent);
}
@@ -136,11 +231,19 @@ public:
};
template <>
-ArrayRef<uint8_t> GOTModulePointerAtom<Mips32ELType>::rawContent() const {
+ArrayRef<uint8_t> GOTModulePointerAtom<ELF32BE>::rawContent() const {
return llvm::makeArrayRef(mipsGotModulePointerAtomContent).slice(4);
}
template <>
-ArrayRef<uint8_t> GOTModulePointerAtom<Mips64ELType>::rawContent() const {
+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);
}
@@ -152,12 +255,17 @@ public:
ArrayRef<uint8_t> rawContent() const override;
};
-template <> ArrayRef<uint8_t> GOTTLSGdAtom<Mips32ELType>::rawContent() const {
- return llvm::makeArrayRef(mipsGotTlsGdAtomContent).slice(8);
+template <> ArrayRef<uint8_t> GOTTLSGdAtom<ELF32BE>::rawContent() const {
+ return llvm::makeArrayRef(mipsGotTlsGdAtomContent).slice(8);
}
-
-template <> ArrayRef<uint8_t> GOTTLSGdAtom<Mips64ELType>::rawContent() const {
- return llvm::makeArrayRef(mipsGotTlsGdAtomContent);
+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 {
@@ -173,28 +281,56 @@ public:
addReferenceELF_Mips(R_MIPS_32, 0, plt0, 0);
}
- Alignment alignment() const override { return Alignment(2); }
+ Alignment alignment() const override { return 4; }
ArrayRef<uint8_t> rawContent() const override {
return llvm::makeArrayRef(mipsGot0AtomContent).slice(4);
}
};
-class PLT0Atom : public PLTAtom {
+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(LLD_R_MIPS_HI16, 0, got, 0);
- addReferenceELF_Mips(LLD_R_MIPS_LO16, 4, got, 0);
- addReferenceELF_Mips(LLD_R_MIPS_LO16, 8, got, 0);
+ 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 {
- return llvm::makeArrayRef(mipsPlt0AtomContent);
+ llvm_unreachable("PLT0 is not applicable for this target");
}
};
-class PLT0MicroAtom : public PLTAtom {
+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.
@@ -204,54 +340,87 @@ public:
CodeModel codeModel() const override { return codeMipsMicro; }
ArrayRef<uint8_t> rawContent() const override {
- return llvm::makeArrayRef(micromipsPlt0AtomContent);
+ 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(LLD_R_MIPS_HI16, 0, got, 0);
- addReferenceELF_Mips(LLD_R_MIPS_LO16, 4, got, 0);
- addReferenceELF_Mips(LLD_R_MIPS_LO16, 12, got, 0);
+ 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 {
- return llvm::makeArrayRef(mipsPltAAtomContent);
+ llvm_unreachable("PLT is not applicable for this target");
}
};
-class PLTR6Atom : public PLTAAtom {
+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 {
- return llvm::makeArrayRef(mipsR6PltAAtomContent);
+ llvm_unreachable("PLT is not applicable for this target");
}
};
-class PLTMicroAtom : public PLTAtom {
+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 Alignment(1); }
+ Alignment alignment() const override { return 2; }
CodeModel codeModel() const override { return codeMipsMicro; }
ArrayRef<uint8_t> rawContent() const override {
- return llvm::makeArrayRef(micromipsPltAtomContent);
+ 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") {}
};
-class LA25RegAtom : public LA25Atom {
+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.
@@ -261,11 +430,18 @@ public:
}
ArrayRef<uint8_t> rawContent() const override {
- return llvm::makeArrayRef(mipsLA25AtomContent);
+ llvm_unreachable("LA25 stubs are not applicable for this target");
}
};
-class LA25MicroAtom : public LA25Atom {
+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.
@@ -277,7 +453,39 @@ public:
CodeModel codeModel() const override { return codeMipsMicro; }
ArrayRef<uint8_t> rawContent() const override {
- return llvm::makeArrayRef(micromipsLA25AtomContent);
+ 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);
}
};
@@ -295,7 +503,7 @@ template <typename ELFT> class RelocationPass : public Pass {
public:
RelocationPass(MipsLinkingContext &ctx);
- void perform(std::unique_ptr<MutableFile> &mf) override;
+ std::error_code perform(SimpleFile &mf) override;
private:
/// \brief Reference to the linking context.
@@ -319,7 +527,7 @@ private:
llvm::DenseMap<const Atom *, GOTAtom *> _gotTLSGdMap;
/// \brief GOT entry for the R_xxxMIPS_TLS_LDM relocations.
- GOTTLSGdAtom<ELFT> *_gotLDMEntry;
+ GOTTLSGdAtom<ELFT> *_gotLDMEntry = nullptr;
/// \brief the list of local GOT atoms.
std::vector<GOTAtom *> _localGotVector;
@@ -335,14 +543,14 @@ private:
/// \brief Map Atoms to their PLT entries.
llvm::DenseMap<const Atom *, PLTAAtom *> _pltRegMap;
- llvm::DenseMap<const Atom *, PLTMicroAtom *> _pltMicroMap;
+ 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 *, LA25RegAtom *> _la25RegMap;
- llvm::DenseMap<const Atom *, LA25MicroAtom *> _la25MicroMap;
+ llvm::DenseMap<const Atom *, LA25Atom *> _la25RegMap;
+ llvm::DenseMap<const Atom *, LA25Atom *> _la25MicroMap;
/// \brief Atoms referenced by static relocations.
llvm::DenseSet<const Atom *> _hasStaticRelocations;
@@ -372,24 +580,27 @@ private:
/// \brief Collect information about the reference to use it
/// later in the handleReference() routine.
- void collectReferenceInfo(const MipsELFDefinedAtom<ELFT> &atom,
- Reference &ref);
+ 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 handle26(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);
- const GOTAtom *getTLSGdGOTEntry(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 *getLA25Entry(const Atom *target, bool isMicroMips);
const LA25Atom *getLA25RegEntry(const Atom *a);
const LA25Atom *getLA25MicroEntry(const Atom *a);
const ObjectAtom *getObjectEntry(const SharedLibraryAtom *a);
@@ -399,40 +610,47 @@ private:
bool isLocal(const Atom *a) const;
bool isLocalCall(const Atom *a) const;
bool isDynamic(const Atom *atom) const;
- bool requireLA25Stub(const Atom *a) const;
+ bool 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;
- bool isR6Target() 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), _gotLDMEntry(nullptr) {
+ : _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>
-void RelocationPass<ELFT>::perform(std::unique_ptr<MutableFile> &mf) {
- for (const auto &atom : mf->defined())
- for (const auto &ref : *atom)
- collectReferenceInfo(*cast<MipsELFDefinedAtom<ELFT>>(atom),
- const_cast<Reference &>(*ref));
+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 &atom : mf.defined())
for (const auto &ref : *atom)
handleReference(*cast<MipsELFDefinedAtom<ELFT>>(atom),
const_cast<Reference &>(*ref));
// Create R_MIPS_REL32 relocations.
for (auto *ref : _rel32Candidates) {
- if (!isDynamic(ref->target()) || hasPLTEntry(ref->target()))
+ 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)
@@ -443,19 +661,32 @@ void RelocationPass<ELFT>::perform(std::unique_ptr<MutableFile> &mf) {
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);
+ mf.addAtom(*got);
}
for (auto &got : _globalGotVector) {
got->setOrdinal(ordinal++);
- mf->addAtom(*got);
+ mf.addAtom(*got);
}
for (auto &got : _tlsGotVector) {
got->setOrdinal(ordinal++);
- mf->addAtom(*got);
+ mf.addAtom(*got);
}
// Create and emit PLT0 entry.
@@ -467,19 +698,19 @@ void RelocationPass<ELFT>::perform(std::unique_ptr<MutableFile> &mf) {
if (plt0Atom) {
plt0Atom->setOrdinal(ordinal++);
- mf->addAtom(*plt0Atom);
+ mf.addAtom(*plt0Atom);
}
// Emit regular PLT entries firts.
for (auto &plt : _pltRegVector) {
plt->setOrdinal(ordinal++);
- mf->addAtom(*plt);
+ mf.addAtom(*plt);
}
// microMIPS PLT entries come after regular ones.
for (auto &plt : _pltMicroVector) {
plt->setOrdinal(ordinal++);
- mf->addAtom(*plt);
+ mf.addAtom(*plt);
}
// Assign PLT0 to GOTPLT entries.
@@ -489,18 +720,96 @@ void RelocationPass<ELFT>::perform(std::unique_ptr<MutableFile> &mf) {
for (auto &gotplt : _gotpltVector) {
gotplt->setOrdinal(ordinal++);
- mf->addAtom(*gotplt);
+ mf.addAtom(*gotplt);
}
for (auto obj : _objectVector) {
obj->setOrdinal(ordinal++);
- mf->addAtom(*obj);
+ mf.addAtom(*obj);
}
for (auto la25 : _la25Vector) {
la25->setOrdinal(ordinal++);
- mf->addAtom(*la25);
+ 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>
@@ -508,67 +817,33 @@ void RelocationPass<ELFT>::handleReference(const MipsELFDefinedAtom<ELFT> &atom,
Reference &ref) {
if (!ref.target())
return;
- if (ref.kindNamespace() != lld::Reference::KindNamespace::ELF)
+ if (ref.kindNamespace() != Reference::KindNamespace::ELF)
return;
+
assert(ref.kindArch() == Reference::KindArch::Mips);
- switch (ref.kindValue()) {
- case R_MIPS_32:
- case R_MIPS_PC32:
- case R_MIPS_HI16:
- case R_MIPS_LO16:
- case R_MIPS_PCHI16:
- case R_MIPS_PCLO16:
- case R_MICROMIPS_HI16:
- case R_MICROMIPS_LO16:
- // FIXME (simon): Handle dynamic/static linking differently.
+ Reference::KindValue kind = ref.kindValue();
+ if (isHiLo16Reloc(kind) || kind == R_MIPS_32 || kind == R_MIPS_PC32)
handlePlain(atom, ref);
- break;
- case R_MIPS_26:
- case R_MICROMIPS_26_S1:
- handle26(atom, ref);
- break;
- case R_MIPS_GOT16:
- case R_MIPS_CALL16:
- case R_MICROMIPS_GOT16:
- case R_MICROMIPS_CALL16:
- case R_MIPS_GOT_DISP:
- case R_MIPS_GOT_PAGE:
+ else if (isBranchReloc(kind))
+ handleBranch(atom, ref);
+ else if (isAllGotReloc(kind) || isAllCallReloc(kind) ||
+ isGotDispReloc(kind) || isGotPageReloc(kind) || kind == R_MIPS_EH)
handleGOT(ref);
- break;
- case R_MIPS_GOT_OFST:
- // Nothing to do. We create GOT page entry in the R_MIPS_GOT_PAGE handler.
- break;
- case R_MIPS_GPREL16:
- if (isLocal(ref.target()))
- ref.setAddend(ref.addend() + atom.file().getGP0());
- break;
- case R_MIPS_GPREL32:
- ref.setAddend(ref.addend() + atom.file().getGP0());
- break;
- case R_MIPS_TLS_DTPREL_HI16:
- case R_MIPS_TLS_DTPREL_LO16:
- case R_MICROMIPS_TLS_DTPREL_HI16:
- case R_MICROMIPS_TLS_DTPREL_LO16:
+ else if (isTlsDtpReloc(kind))
ref.setAddend(ref.addend() - atom.file().getDTPOffset());
- break;
- case R_MIPS_TLS_TPREL_HI16:
- case R_MIPS_TLS_TPREL_LO16:
- case R_MICROMIPS_TLS_TPREL_HI16:
- case R_MICROMIPS_TLS_TPREL_LO16:
+ else if (isTlsTpReloc(kind))
ref.setAddend(ref.addend() - atom.file().getTPOffset());
- break;
- case R_MIPS_TLS_GD:
- case R_MICROMIPS_TLS_GD:
- ref.setTarget(getTLSGdGOTEntry(ref.target()));
- break;
- case R_MIPS_TLS_LDM:
- case R_MICROMIPS_TLS_LDM:
+ else if (isTlsGdReloc(kind))
+ ref.setTarget(getTLSGdGOTEntry(ref.target(), ref.addend()));
+ else if (isTlsLdmReloc(kind))
ref.setTarget(getTLSLdmGOTEntry(ref.target()));
- break;
- case R_MIPS_TLS_GOTTPREL:
- case R_MICROMIPS_TLS_GOTTPREL:
- ref.setTarget(getTLSGOTEntry(ref.target()));
- break;
+ 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);
}
}
@@ -583,6 +858,10 @@ static bool isConstrainSym(const MipsELFDefinedAtom<ELFT> &atom,
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;
@@ -590,25 +869,96 @@ static bool isConstrainSym(const MipsELFDefinedAtom<ELFT> &atom,
}
template <typename ELFT>
-void RelocationPass<ELFT>::collectReferenceInfo(
- const MipsELFDefinedAtom<ELFT> &atom, Reference &ref) {
+std::error_code
+RelocationPass<ELFT>::collectReferenceInfo(const MipsELFDefinedAtom<ELFT> &atom,
+ Reference &ref) {
if (!ref.target())
- return;
- if (ref.kindNamespace() != lld::Reference::KindNamespace::ELF)
- return;
+ 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;
+ return std::error_code();
- if (mightBeDynamic(atom, refKind))
- _rel32Candidates.push_back(&ref);
- else
+ if (!mightBeDynamic(atom, refKind))
_hasStaticRelocations.insert(ref.target());
+ else if (refKind == R_MIPS_32 || refKind == R_MIPS_64)
+ _rel32Candidates.push_back(&ref);
- if (refKind != R_MIPS_CALL16 && refKind != R_MICROMIPS_CALL16 &&
- refKind != R_MIPS_26 && refKind != R_MICROMIPS_26_S1)
+ 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>
@@ -635,8 +985,7 @@ static bool isMipsReadonly(const MipsELFDefinedAtom<ELFT> &atom) {
template <typename ELFT>
bool RelocationPass<ELFT>::mightBeDynamic(const MipsELFDefinedAtom<ELFT> &atom,
Reference::KindValue refKind) const {
- if (refKind == R_MIPS_CALL16 || refKind == R_MIPS_GOT16 ||
- refKind == R_MICROMIPS_CALL16 || refKind == R_MICROMIPS_GOT16)
+ if (isAllGotReloc(refKind) || isAllCallReloc(refKind))
return true;
if (refKind != R_MIPS_32 && refKind != R_MIPS_64)
@@ -648,7 +997,7 @@ bool RelocationPass<ELFT>::mightBeDynamic(const MipsELFDefinedAtom<ELFT> &atom,
return true;
if (!isMipsReadonly(atom))
return true;
- if (atom.file().isPIC())
+ if (atom.isPIC())
return true;
return false;
@@ -659,14 +1008,18 @@ bool RelocationPass<ELFT>::hasPLTEntry(const Atom *atom) const {
return _pltRegMap.count(atom) || _pltMicroMap.count(atom);
}
-template <typename ELFT> bool RelocationPass<ELFT>::isR6Target() const {
- switch (_ctx.getMergedELFFlags() & EF_MIPS_ARCH) {
- case EF_MIPS_ARCH_32R6:
- case EF_MIPS_ARCH_64R6:
- return true;
- default:
- return false;
- }
+template <typename ELFT> bool RelocationPass<ELFT>::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>
@@ -697,21 +1050,13 @@ bool RelocationPass<ELFT>::isDynamic(const Atom *atom) const {
const auto *da = dyn_cast<const DefinedAtom>(atom);
if (da && da->dynamicExport() == DefinedAtom::dynamicExportAlways)
return true;
-
- const auto *sa = dyn_cast<SharedLibraryAtom>(atom);
- if (sa)
+ if (isa<SharedLibraryAtom>(atom))
return true;
-
- if (_ctx.getOutputELFType() == ET_DYN) {
- if (da && da->scope() != DefinedAtom::scopeTranslationUnit)
- return true;
-
- const auto *ua = dyn_cast<UndefinedAtom>(atom);
- if (ua)
- return true;
- }
-
- return false;
+ if (_ctx.getOutputELFType() != ET_DYN)
+ return false;
+ if (da && da->scope() != DefinedAtom::scopeTranslationUnit)
+ return true;
+ return isa<UndefinedAtom>(atom);
}
template <typename ELFT>
@@ -721,17 +1066,9 @@ static bool isMicroMips(const MipsELFDefinedAtom<ELFT> &atom) {
}
template <typename ELFT>
-const LA25Atom *RelocationPass<ELFT>::getLA25Entry(const Atom *target,
- bool isMicroMips) {
- return isMicroMips ? getLA25MicroEntry(target) : getLA25RegEntry(target);
-}
-
-template <typename ELFT>
const PLTAtom *RelocationPass<ELFT>::getPLTEntry(const Atom *a) {
- bool hasMicroCode = _ctx.getMergedELFFlags() & EF_MIPS_MICROMIPS;
-
// If file contains microMIPS code try to reuse compressed PLT entry...
- if (hasMicroCode) {
+ if (isMicroMips()) {
auto microPLT = _pltMicroMap.find(a);
if (microPLT != _pltMicroMap.end())
return microPLT->second;
@@ -743,7 +1080,7 @@ const PLTAtom *RelocationPass<ELFT>::getPLTEntry(const Atom *a) {
return regPLT->second;
// ... and finally prefer to create new compressed PLT entry.
- return hasMicroCode ? getPLTMicroEntry(a) : getPLTRegEntry(a);
+ return isMicroMips() ? getPLTMicroEntry(a) : getPLTRegEntry(a);
}
template <typename ELFT>
@@ -759,37 +1096,34 @@ void RelocationPass<ELFT>::handlePlain(const MipsELFDefinedAtom<ELFT> &atom,
}
template <typename ELFT>
-void RelocationPass<ELFT>::handle26(const MipsELFDefinedAtom<ELFT> &atom,
- Reference &ref) {
- bool isMicro = ref.kindValue() == R_MICROMIPS_26_S1;
- assert((isMicro || ref.kindValue() == R_MIPS_26) && "Unexpected relocation");
-
- const auto *sla = dyn_cast<SharedLibraryAtom>(ref.target());
- if (sla && sla->type() == SharedLibraryAtom::Type::Code)
- ref.setTarget(isMicro ? getPLTMicroEntry(sla) : getPLTRegEntry(sla));
-
- if (requireLA25Stub(ref.target()))
- ref.setTarget(getLA25Entry(ref.target(), isMicro));
+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 (isMicro)
+ if (ref.kindValue() == R_MICROMIPS_26_S1)
ref.setKindValue(LLD_R_MICROMIPS_GLOBAL_26_S1);
- else
+ 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())) {
+ if (!isLocalCall(ref.target()))
ref.setTarget(getGlobalGOTEntry(ref.target()));
- return;
- }
-
- if (ref.kindValue() == R_MIPS_GOT_PAGE)
+ else if (isGotPageReloc(ref.kindValue()))
ref.setTarget(getLocalGOTPageEntry(ref));
- else if (ref.kindValue() == R_MIPS_GOT_DISP)
- ref.setTarget(getLocalGOTEntry(ref));
- else if (isLocal(ref.target()))
+ else if (isLocal(ref.target()) &&
+ (isCallReloc(ref.kindValue()) || isGotReloc(ref.kindValue())))
ref.setTarget(getLocalGOTPageEntry(ref));
else
ref.setTarget(getLocalGOTEntry(ref));
@@ -817,11 +1151,12 @@ bool RelocationPass<ELFT>::isLocalCall(const Atom *a) const {
}
template <typename ELFT>
-bool RelocationPass<ELFT>::requireLA25Stub(const Atom *a) const {
- if (isLocal(a))
+bool RelocationPass<ELFT>::requireLA25Stub(const MipsELFDefinedAtom<ELFT> &atom,
+ const Reference &ref) const {
+ if (atom.file().isPIC())
return false;
- if (auto *da = dyn_cast<DefinedAtom>(a))
- return static_cast<const MipsELFDefinedAtom<ELFT> *>(da)->file().isPIC();
+ if (auto *da = dyn_cast<DefinedAtom>(ref.target()))
+ return static_cast<const MipsELFDefinedAtom<ELFT> *>(da)->isPIC();
return false;
}
@@ -886,7 +1221,8 @@ const GOTAtom *RelocationPass<ELFT>::getGlobalGOTEntry(const Atom *a) {
}
template <typename ELFT>
-const GOTAtom *RelocationPass<ELFT>::getTLSGOTEntry(const Atom *a) {
+const GOTAtom *RelocationPass<ELFT>::getTLSGOTEntry(const Atom *a,
+ Reference::Addend addend) {
auto got = _gotTLSMap.find(a);
if (got != _gotTLSMap.end())
return got->second;
@@ -897,13 +1233,15 @@ const GOTAtom *RelocationPass<ELFT>::getTLSGOTEntry(const Atom *a) {
_tlsGotVector.push_back(ga);
Reference::KindValue relKind =
ELFT::Is64Bits ? R_MIPS_TLS_TPREL64 : R_MIPS_TLS_TPREL32;
- ga->addReferenceELF_Mips(relKind, 0, a, 0);
+ ga->addReferenceELF_Mips(relKind, 0, a, addend);
return ga;
}
template <typename ELFT>
-const GOTAtom *RelocationPass<ELFT>::getTLSGdGOTEntry(const Atom *a) {
+const GOTAtom *
+RelocationPass<ELFT>::getTLSGdGOTEntry(const Atom *a,
+ Reference::Addend addend) {
auto got = _gotTLSGdMap.find(a);
if (got != _gotTLSGdMap.end())
return got->second;
@@ -913,11 +1251,11 @@ const GOTAtom *RelocationPass<ELFT>::getTLSGdGOTEntry(const Atom *a) {
_tlsGotVector.push_back(ga);
if (ELFT::Is64Bits) {
- ga->addReferenceELF_Mips(R_MIPS_TLS_DTPMOD64, 0, a, 0);
- ga->addReferenceELF_Mips(R_MIPS_TLS_DTPREL64, 8, a, 0);
+ 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, 0);
- ga->addReferenceELF_Mips(R_MIPS_TLS_DTPREL32, 4, a, 0);
+ ga->addReferenceELF_Mips(R_MIPS_TLS_DTPMOD32, 0, a, addend);
+ ga->addReferenceELF_Mips(R_MIPS_TLS_DTPREL32, 4, a, addend);
}
return ga;
@@ -946,9 +1284,10 @@ PLTAtom *RelocationPass<ELFT>::createPLTHeader(bool isMicroMips) {
_gotpltVector.insert(_gotpltVector.begin(), ga0);
if (isMicroMips)
- return new (_file._alloc) PLT0MicroAtom(ga0, _file);
- else
- return new (_file._alloc) PLT0Atom(ga0, _file);
+ 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>
@@ -969,9 +1308,11 @@ const PLTAtom *RelocationPass<ELFT>::getPLTRegEntry(const Atom *a) {
if (plt != _pltRegMap.end())
return plt->second;
- PLTAAtom *pa = isR6Target()
- ? new (_file._alloc) PLTR6Atom(getGOTPLTEntry(a), _file)
- : new (_file._alloc) PLTAAtom(getGOTPLTEntry(a), _file);
+ 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);
@@ -988,7 +1329,7 @@ const PLTAtom *RelocationPass<ELFT>::getPLTMicroEntry(const Atom *a) {
if (plt != _pltMicroMap.end())
return plt->second;
- auto pa = new (_file._alloc) PLTMicroAtom(getGOTPLTEntry(a), _file);
+ auto pa = new (_file._alloc) PLTMicroAtom<ELFT>(getGOTPLTEntry(a), _file);
_pltMicroMap[a] = pa;
_pltMicroVector.push_back(pa);
@@ -1005,7 +1346,7 @@ const LA25Atom *RelocationPass<ELFT>::getLA25RegEntry(const Atom *a) {
if (la25 != _la25RegMap.end())
return la25->second;
- auto sa = new (_file._alloc) LA25RegAtom(a, _file);
+ auto sa = new (_file._alloc) LA25RegAtom<ELFT>(a, _file);
_la25RegMap[a] = sa;
_la25Vector.push_back(sa);
@@ -1018,7 +1359,7 @@ const LA25Atom *RelocationPass<ELFT>::getLA25MicroEntry(const Atom *a) {
if (la25 != _la25MicroMap.end())
return la25->second;
- auto sa = new (_file._alloc) LA25MicroAtom(a, _file);
+ auto sa = new (_file._alloc) LA25MicroAtom<ELFT>(a, _file);
_la25MicroMap[a] = sa;
_la25Vector.push_back(sa);
@@ -1047,10 +1388,14 @@ RelocationPass<ELFT>::getObjectEntry(const SharedLibraryAtom *a) {
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<Mips32ELType>>(ctx);
+ 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<Mips64ELType>>(ctx);
+ return llvm::make_unique<RelocationPass<ELF64LE>>(ctx);
default:
llvm_unreachable("Unhandled arch");
}
diff --git a/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.cpp b/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.cpp
new file mode 100644
index 000000000000..98cc059787ef
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.cpp
@@ -0,0 +1,264 @@
+//===- 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
index de9390f2b307..e545f65dc419 100644
--- a/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h
+++ b/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h
@@ -9,23 +9,81 @@
#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 ELFType> class MipsGOTSection : public AtomSection<ELFType> {
+template <class ELFT> class MipsGOTSection : public AtomSection<ELFT> {
public:
- MipsGOTSection(const MipsLinkingContext &ctx)
- : AtomSection<ELFType>(ctx, ".got", DefinedAtom::typeGOT,
- DefinedAtom::permRW_,
- MipsTargetLayout<ELFType>::ORDER_GOT),
- _hasNonLocal(false), _localCount(0) {
- this->_flags |= SHF_MIPS_GPREL;
- this->_alignment = 4;
- }
+ MipsGOTSection(const MipsLinkingContext &ctx);
/// \brief Number of local GOT entries.
std::size_t getLocalCount() const { return _localCount; }
@@ -39,47 +97,9 @@ public:
}
/// \brief Compare two atoms accordingly theirs positions in the GOT.
- bool compare(const Atom *a, const Atom *b) const {
- auto ia = _posMap.find(a);
- auto ib = _posMap.find(b);
+ bool compare(const Atom *a, const Atom *b) const;
- if (ia != _posMap.end() && ib != _posMap.end())
- return ia->second < ib->second;
-
- return ia == _posMap.end() && ib != _posMap.end();
- }
-
- const lld::AtomLayout *appendAtom(const Atom *atom) override {
- const DefinedAtom *da = dyn_cast<DefinedAtom>(atom);
-
- for (const auto &r : *da) {
- if (r->kindNamespace() != lld::Reference::KindNamespace::ELF)
- continue;
- assert(r->kindArch() == Reference::KindArch::Mips);
- switch (r->kindValue()) {
- case LLD_R_MIPS_GLOBAL_GOT:
- _hasNonLocal = true;
- _posMap[r->target()] = _posMap.size();
- return AtomSection<ELFType>::appendAtom(atom);
- case R_MIPS_TLS_TPREL32:
- case R_MIPS_TLS_DTPREL32:
- case R_MIPS_TLS_TPREL64:
- case R_MIPS_TLS_DTPREL64:
- _hasNonLocal = true;
- _tlsMap[r->target()] = _tlsMap.size();
- return AtomSection<ELFType>::appendAtom(atom);
- case R_MIPS_TLS_DTPMOD32:
- case R_MIPS_TLS_DTPMOD64:
- _hasNonLocal = true;
- break;
- }
- }
-
- if (!_hasNonLocal)
- ++_localCount;
-
- return AtomSection<ELFType>::appendAtom(atom);
- }
+ const AtomLayout *appendAtom(const Atom *atom) override;
private:
/// \brief True if the GOT contains non-local entries.
@@ -96,35 +116,13 @@ private:
};
/// \brief Handle Mips PLT section
-template <class ELFType> class MipsPLTSection : public AtomSection<ELFType> {
+template <class ELFT> class MipsPLTSection : public AtomSection<ELFT> {
public:
- MipsPLTSection(const MipsLinkingContext &ctx)
- : AtomSection<ELFType>(ctx, ".plt", DefinedAtom::typeGOT,
- DefinedAtom::permR_X,
- MipsTargetLayout<ELFType>::ORDER_PLT) {}
-
- const AtomLayout *findPLTLayout(const Atom *plt) const {
- auto it = _pltLayoutMap.find(plt);
- return it != _pltLayoutMap.end() ? it->second : nullptr;
- }
-
- const lld::AtomLayout *appendAtom(const Atom *atom) override {
- const auto *layout = AtomSection<ELFType>::appendAtom(atom);
+ MipsPLTSection(const MipsLinkingContext &ctx);
- const DefinedAtom *da = cast<DefinedAtom>(atom);
+ const AtomLayout *findPLTLayout(const Atom *plt) const;
- for (const auto &r : *da) {
- if (r->kindNamespace() != lld::Reference::KindNamespace::ELF)
- continue;
- assert(r->kindArch() == Reference::KindArch::Mips);
- if (r->kindValue() == LLD_R_MIPS_STO_PLT) {
- _pltLayoutMap[r->target()] = layout;
- break;
- }
- }
-
- return layout;
- }
+ const AtomLayout *appendAtom(const Atom *atom) override;
private:
/// \brief Map PLT Atoms to their layouts.
@@ -135,33 +133,15 @@ template <class ELFT> class MipsRelocationTable : public RelocationTable<ELFT> {
typedef llvm::object::Elf_Rel_Impl<ELFT, false> Elf_Rel;
typedef llvm::object::Elf_Rel_Impl<ELFT, true> Elf_Rela;
- static const bool _isMips64EL =
- ELFT::Is64Bits && ELFT::TargetEndianness == llvm::support::little;
-
public:
- MipsRelocationTable(const ELFLinkingContext &context, StringRef str,
- int32_t order)
- : RelocationTable<ELFT>(context, str, order) {}
+ MipsRelocationTable(const ELFLinkingContext &ctx, StringRef str,
+ int32_t order);
protected:
void writeRela(ELFWriter *writer, Elf_Rela &r, const DefinedAtom &atom,
- const Reference &ref) override {
- uint32_t rType = ref.kindValue() | (ref.tag() << 8);
- r.setSymbolAndType(this->getSymbolIndex(ref.target()), rType, _isMips64EL);
- r.r_offset = writer->addressOfAtom(&atom) + ref.offsetInAtom();
- // The addend is used only by relative relocations
- if (this->_context.isRelativeReloc(ref))
- r.r_addend = writer->addressOfAtom(ref.target()) + ref.addend();
- else
- r.r_addend = 0;
- }
-
+ const Reference &ref) override;
void writeRel(ELFWriter *writer, Elf_Rel &r, const DefinedAtom &atom,
- const Reference &ref) override {
- uint32_t rType = ref.kindValue() | (ref.tag() << 8);
- r.setSymbolAndType(this->getSymbolIndex(ref.target()), rType, _isMips64EL);
- r.r_offset = writer->addressOfAtom(&atom) + ref.offsetInAtom();
- }
+ const Reference &ref) override;
};
} // elf
diff --git a/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp b/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp
index f60ab63c6af7..817e29444666 100644
--- a/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp
+++ b/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp
@@ -1,4 +1,4 @@
-//===- lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp --------------------===//
+//===- lib/ReaderWriter/ELF/Mips/MipsTargetHandler32EL.cpp ----------------===//
//
// The LLVM Linker
//
@@ -7,29 +7,160 @@
//
//===----------------------------------------------------------------------===//
+#include "ELFReader.h"
+#include "MipsELFFile.h"
+#include "MipsELFWriters.h"
#include "MipsTargetHandler.h"
-using namespace lld;
-using namespace elf;
+namespace lld {
+namespace elf {
-void MipsRelocationStringTable::registerTable(Registry &registry) {
- registry.addKindTable(Reference::KindNamespace::ELF,
- Reference::KindArch::Mips, kindStrings);
+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;
+ }
}
-#define ELF_RELOC(name, value) LLD_KIND_STRING_ENTRY(name),
+template <class ELFT> void MipsSymbolTable<ELFT>::finalize(bool sort) {
+ SymbolTable<ELFT>::finalize(sort);
-const Registry::KindStrings MipsRelocationStringTable::kindStrings[] = {
-#include "llvm/Support/ELFRelocs/Mips.def"
- LLD_KIND_STRING_ENTRY(LLD_R_MIPS_GLOBAL_GOT),
- LLD_KIND_STRING_ENTRY(LLD_R_MIPS_32_HI16),
- LLD_KIND_STRING_ENTRY(LLD_R_MIPS_64_HI16),
- LLD_KIND_STRING_ENTRY(LLD_R_MIPS_GLOBAL_26),
- LLD_KIND_STRING_ENTRY(LLD_R_MIPS_HI16),
- LLD_KIND_STRING_ENTRY(LLD_R_MIPS_LO16),
- LLD_KIND_STRING_ENTRY(LLD_R_MIPS_STO_PLT),
- LLD_KIND_STRING_ENTRY(LLD_R_MICROMIPS_GLOBAL_26_S1),
- LLD_KIND_STRING_END
-};
+ 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();
-#undef ELF_RELOC
+ 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
index 79509addf40b..e4a35bdd323d 100644
--- a/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h
+++ b/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h
@@ -9,146 +9,36 @@
#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_TARGET_HANDLER_H
#define LLD_READER_WRITER_ELF_MIPS_MIPS_TARGET_HANDLER_H
-#include "DefaultTargetHandler.h"
-#include "MipsDynamicLibraryWriter.h"
-#include "MipsELFReader.h"
-#include "MipsExecutableWriter.h"
+#include "MipsAbiInfoHandler.h"
#include "MipsLinkingContext.h"
-#include "MipsRelocationHandler.h"
-#include "MipsSectionChunks.h"
-#include "TargetLayout.h"
-#include "llvm/ADT/DenseSet.h"
+#include "MipsTargetLayout.h"
+#include "TargetHandler.h"
namespace lld {
namespace elf {
-/// \brief TargetLayout for Mips
-template <class ELFT> class MipsTargetLayout final : public TargetLayout<ELFT> {
+class MipsBaseTargetHandler : public TargetHandler {
public:
- MipsTargetLayout(MipsLinkingContext &ctx)
- : TargetLayout<ELFT>(ctx),
- _gotSection(new (this->_allocator) MipsGOTSection<ELFT>(ctx)),
- _pltSection(new (this->_allocator) MipsPLTSection<ELFT>(ctx)) {}
-
- const MipsGOTSection<ELFT> &getGOTSection() const { return *_gotSection; }
- const MipsPLTSection<ELFT> &getPLTSection() const { return *_pltSection; }
-
- AtomSection<ELFT> *createSection(StringRef name, int32_t type,
- DefinedAtom::ContentPermissions permissions,
- Layout::SectionOrder order) override {
- if (type == DefinedAtom::typeGOT && name == ".got")
- return _gotSection;
- if (type == DefinedAtom::typeStub && name == ".plt")
- return _pltSection;
- return DefaultLayout<ELFT>::createSection(name, type, permissions, order);
- }
-
- /// \brief GP offset relative to .got section.
- uint64_t getGPOffset() const { return 0x7FF0; }
-
- /// \brief Get '_gp' symbol atom layout.
- AtomLayout *getGP() {
- if (!_gpAtom.hasValue()) {
- auto atom = this->findAbsoluteAtom("_gp");
- _gpAtom = atom != this->absoluteAtoms().end() ? *atom : nullptr;
- }
- return *_gpAtom;
- }
-
- /// \brief Get '_gp_disp' symbol atom layout.
- AtomLayout *getGPDisp() {
- if (!_gpDispAtom.hasValue()) {
- auto atom = this->findAbsoluteAtom("_gp_disp");
- _gpDispAtom = atom != this->absoluteAtoms().end() ? *atom : nullptr;
- }
- return *_gpDispAtom;
- }
-
- /// \brief Return the section order for a input section
- Layout::SectionOrder getSectionOrder(StringRef name, int32_t contentType,
- int32_t contentPermissions) override {
- if ((contentType == DefinedAtom::typeStub) && (name.startswith(".text")))
- return DefaultLayout<ELFT>::ORDER_TEXT;
-
- return DefaultLayout<ELFT>::getSectionOrder(name, contentType,
- contentPermissions);
- }
-
-protected:
- unique_bump_ptr<RelocationTable<ELFT>>
- createRelocationTable(StringRef name, int32_t order) override {
- return unique_bump_ptr<RelocationTable<ELFT>>(
- new (this->_allocator)
- MipsRelocationTable<ELFT>(this->_context, name, order));
- }
-
-private:
- MipsGOTSection<ELFT> *_gotSection;
- MipsPLTSection<ELFT> *_pltSection;
- llvm::Optional<AtomLayout *> _gpAtom;
- llvm::Optional<AtomLayout *> _gpDispAtom;
-};
-
-/// \brief Mips Runtime file.
-template <class ELFT> class MipsRuntimeFile final : public RuntimeFile<ELFT> {
-public:
- MipsRuntimeFile(MipsLinkingContext &ctx)
- : RuntimeFile<ELFT>(ctx, "Mips runtime file") {}
-};
-
-/// \brief Auxiliary class holds relocation's names table.
-class MipsRelocationStringTable {
- static const Registry::KindStrings kindStrings[];
-
-public:
- static void registerTable(Registry &registry);
+ virtual MipsAbi getAbi() const = 0;
};
/// \brief TargetHandler for Mips
template <class ELFT>
-class MipsTargetHandler final : public DefaultTargetHandler<ELFT> {
+class MipsTargetHandler final : public MipsBaseTargetHandler {
public:
- MipsTargetHandler(MipsLinkingContext &ctx)
- : _ctx(ctx), _runtimeFile(new MipsRuntimeFile<ELFT>(ctx)),
- _targetLayout(new MipsTargetLayout<ELFT>(ctx)),
- _relocationHandler(createMipsRelocationHandler<ELFT>(ctx)) {}
-
- MipsTargetLayout<ELFT> &getTargetLayout() override { return *_targetLayout; }
-
- std::unique_ptr<Reader> getObjReader() override {
- return std::unique_ptr<Reader>(new MipsELFObjectReader<ELFT>(_ctx));
- }
+ MipsTargetHandler(MipsLinkingContext &ctx);
- std::unique_ptr<Reader> getDSOReader() override {
- return std::unique_ptr<Reader>(new MipsELFDSOReader<ELFT>(_ctx));
- }
+ MipsAbiInfoHandler<ELFT> &getAbiInfoHandler() { return _abiInfoHandler; }
- const TargetRelocationHandler &getRelocationHandler() const override {
- return *_relocationHandler;
- }
-
- std::unique_ptr<Writer> getWriter() override {
- switch (_ctx.getOutputELFType()) {
- case llvm::ELF::ET_EXEC:
- return std::unique_ptr<Writer>(
- new MipsExecutableWriter<ELFT>(_ctx, *_targetLayout));
- case llvm::ELF::ET_DYN:
- return std::unique_ptr<Writer>(
- new MipsDynamicLibraryWriter<ELFT>(_ctx, *_targetLayout));
- case llvm::ELF::ET_REL:
- llvm_unreachable("TODO: support -r mode");
- default:
- llvm_unreachable("unsupported output type");
- }
- }
-
- void registerRelocationNames(Registry &registry) override {
- MipsRelocationStringTable::registerTable(registry);
- }
+ 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;
- std::unique_ptr<MipsRuntimeFile<ELFT>> _runtimeFile;
+ MipsAbiInfoHandler<ELFT> _abiInfoHandler;
std::unique_ptr<MipsTargetLayout<ELFT>> _targetLayout;
std::unique_ptr<TargetRelocationHandler> _relocationHandler;
};
@@ -157,95 +47,21 @@ template <class ELFT> class MipsSymbolTable : public SymbolTable<ELFT> {
public:
typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
- MipsSymbolTable(const ELFLinkingContext &ctx)
- : SymbolTable<ELFT>(ctx, ".symtab",
- DefaultLayout<ELFT>::ORDER_SYMBOL_TABLE) {}
+ MipsSymbolTable(const ELFLinkingContext &ctx);
void addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da,
- int64_t addr) override {
- SymbolTable<ELFT>::addDefinedAtom(sym, da, addr);
-
- switch (da->codeModel()) {
- case DefinedAtom::codeMipsMicro:
- sym.st_other |= llvm::ELF::STO_MIPS_MICROMIPS;
- break;
- case DefinedAtom::codeMipsMicroPIC:
- sym.st_other |= llvm::ELF::STO_MIPS_MICROMIPS | llvm::ELF::STO_MIPS_PIC;
- break;
- default:
- break;
- }
- }
-
- void finalize(bool sort) override {
- SymbolTable<ELFT>::finalize(sort);
-
- for (auto &ste : this->_symbolTable) {
- if (!ste._atom)
- continue;
- if (const auto *da = dyn_cast<DefinedAtom>(ste._atom)) {
- if (da->codeModel() == DefinedAtom::codeMipsMicro ||
- da->codeModel() == DefinedAtom::codeMipsMicroPIC) {
- // Adjust dynamic microMIPS symbol value. That allows a dynamic
- // linker to recognize and handle this symbol correctly.
- ste._symbol.st_value = ste._symbol.st_value | 1;
- }
- }
- }
- }
+ 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)
- : DynamicSymbolTable<ELFT>(ctx, layout, ".dynsym",
- DefaultLayout<ELFT>::ORDER_DYNAMIC_SYMBOLS),
- _targetLayout(layout) {}
-
- void sortSymbols() override {
- typedef typename DynamicSymbolTable<ELFT>::SymbolEntry SymbolEntry;
- std::stable_sort(this->_symbolTable.begin(), this->_symbolTable.end(),
- [this](const SymbolEntry &A, const SymbolEntry &B) {
- if (A._symbol.getBinding() != STB_GLOBAL &&
- B._symbol.getBinding() != STB_GLOBAL)
- return A._symbol.getBinding() < B._symbol.getBinding();
-
- return _targetLayout.getGOTSection().compare(A._atom, B._atom);
- });
- }
-
- void finalize() override {
- DynamicSymbolTable<ELFT>::finalize();
-
- const auto &pltSection = _targetLayout.getPLTSection();
-
- for (auto &ste : this->_symbolTable) {
- const Atom *a = ste._atom;
- if (!a)
- continue;
- if (auto *layout = pltSection.findPLTLayout(a)) {
- a = layout->_atom;
- // Under some conditions a dynamic symbol table record should hold
- // a symbol value of the corresponding PLT entry. For details look
- // at the PLT entry creation code in the class MipsRelocationPass.
- // Let's update atomLayout fields for such symbols.
- assert(!ste._atomLayout);
- ste._symbol.st_value = layout->_virtualAddr;
- ste._symbol.st_other |= ELF::STO_MIPS_PLT;
- }
+ MipsTargetLayout<ELFT> &layout);
- 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;
- }
- }
- }
- }
+ void sortSymbols() override;
+ void finalize() override;
private:
MipsTargetLayout<ELFT> &_targetLayout;
diff --git a/lib/ReaderWriter/ELF/Mips/MipsTargetLayout.cpp b/lib/ReaderWriter/ELF/Mips/MipsTargetLayout.cpp
new file mode 100644
index 000000000000..710f8320a8b9
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsTargetLayout.cpp
@@ -0,0 +1,111 @@
+//===- 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
new file mode 100644
index 000000000000..08855438d20e
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsTargetLayout.h
@@ -0,0 +1,71 @@
+//===- 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
index d126b830db96..11f88056c8c4 100644
--- a/lib/ReaderWriter/ELF/OrderPass.h
+++ b/lib/ReaderWriter/ELF/OrderPass.h
@@ -19,9 +19,10 @@ namespace elf {
/// \brief This pass sorts atoms by file and atom ordinals.
class OrderPass : public Pass {
public:
- void perform(std::unique_ptr<MutableFile> &file) override {
- parallel_sort(file->definedAtoms().begin(), file->definedAtoms().end(),
+ std::error_code perform(SimpleFile &file) override {
+ parallel_sort(file.definedAtoms().begin(), file.definedAtoms().end(),
DefinedAtom::compareByPosition);
+ return std::error_code();
}
};
}
diff --git a/lib/ReaderWriter/ELF/OutputELFWriter.cpp b/lib/ReaderWriter/ELF/OutputELFWriter.cpp
new file mode 100644
index 000000000000..4f8b0eac655f
--- /dev/null
+++ b/lib/ReaderWriter/ELF/OutputELFWriter.cpp
@@ -0,0 +1,514 @@
+//===- 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
index c137905b936b..bb3901010634 100644
--- a/lib/ReaderWriter/ELF/OutputELFWriter.h
+++ b/lib/ReaderWriter/ELF/OutputELFWriter.h
@@ -6,88 +6,24 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
+
#ifndef LLD_READER_WRITER_ELF_OUTPUT_WRITER_H
#define LLD_READER_WRITER_ELF_OUTPUT_WRITER_H
-#include "DefaultLayout.h"
#include "ELFFile.h"
#include "TargetLayout.h"
-#include "lld/Core/Instrumentation.h"
-#include "lld/Core/Parallel.h"
-#include "lld/Core/SharedLibraryFile.h"
-#include "lld/ReaderWriter/ELFLinkingContext.h"
-#include "lld/Core/Simple.h"
#include "lld/Core/Writer.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringSet.h"
-#include "llvm/Support/Path.h"
namespace lld {
+class ELFLinkingContext;
+
namespace elf {
using namespace llvm;
using namespace llvm::object;
-template <class ELFT> class OutputELFWriter;
-template <class ELFT> class TargetLayout;
-
-namespace {
-
-template<class ELFT>
-class SymbolFile : public RuntimeFile<ELFT> {
-public:
- SymbolFile(ELFLinkingContext &context)
- : RuntimeFile<ELFT>(context, "Dynamic absolute symbols"),
- _atomsAdded(false) {}
-
- Atom *addAbsoluteAtom(StringRef symbolName) override {
- auto *a = RuntimeFile<ELFT>::addAbsoluteAtom(symbolName);
- if (a) _atomsAdded = true;
- return a;
- }
-
- Atom *addUndefinedAtom(StringRef) override {
- llvm_unreachable("Cannot add undefined atoms to resolve undefined symbols");
- }
-
- bool hasAtoms() const { return _atomsAdded; }
-
-private:
- bool _atomsAdded;
-};
-
-template<class ELFT>
-class DynamicSymbolFile : public SimpleArchiveLibraryFile {
- typedef std::function<void(StringRef, RuntimeFile<ELFT> &)> Resolver;
-public:
- DynamicSymbolFile(ELFLinkingContext &context, Resolver resolver)
- : SimpleArchiveLibraryFile("Dynamically added runtime symbols"),
- _context(context), _resolver(resolver) {}
-
- File *find(StringRef sym, bool dataSymbolOnly) override {
- if (!_file)
- _file.reset(new (_alloc) SymbolFile<ELFT>(_context));
-
- assert(!_file->hasAtoms() && "The file shouldn't have atoms yet");
- _resolver(sym, *_file);
- // If atoms were added - release the file to the caller.
- return _file->hasAtoms() ? _file.release() : nullptr;
- }
-
-private:
- ELFLinkingContext &_context;
- Resolver _resolver;
-
- // The allocator should go before bump pointers because of
- // reversed destruction order.
- llvm::BumpPtrAllocator _alloc;
- unique_bump_ptr<SymbolFile<ELFT>> _file;
-};
-
-} // end anon namespace
-
-//===----------------------------------------------------------------------===//
// OutputELFWriter Class
-//===----------------------------------------------------------------------===//
+//
/// \brief This acts as the base class for all the ELF writers that are output
/// for emitting an ELF output file. This class also acts as a common class for
/// creating static and dynamic executables. All the function in this class
@@ -99,7 +35,7 @@ public:
typedef Elf_Sym_Impl<ELFT> Elf_Sym;
typedef Elf_Dyn_Impl<ELFT> Elf_Dyn;
- OutputELFWriter(ELFLinkingContext &context, TargetLayout<ELFT> &layout);
+ OutputELFWriter(ELFLinkingContext &ctx, TargetLayout<ELFT> &layout);
protected:
// build the sections that need to be created
@@ -140,11 +76,8 @@ protected:
// section header table, string table etc
virtual void assignSectionsWithNoSegments();
- // Add default atoms that need to be present in the output file
- virtual void addDefaultAtoms();
-
// Add any runtime files and their atoms to the output
- bool createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
+ void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
// Finalize the default atom values
virtual void finalizeDefaultAtomValues();
@@ -180,12 +113,15 @@ protected:
/// \brief Process undefined symbols that left after resolution step.
virtual void processUndefinedSymbol(StringRef symName,
- RuntimeFile<ELFT> &file) const {}
+ 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 &_context;
- TargetHandler<ELFT> &_targetHandler;
+ ELFLinkingContext &_ctx;
+ TargetHandler &_targetHandler;
typedef llvm::DenseMap<const Atom *, uint64_t> AtomToAddress;
AtomToAddress _atomToAddressMap;
@@ -205,410 +141,12 @@ protected:
unique_bump_ptr<HashSection<ELFT>> _hashTable;
llvm::StringSet<> _soNeeded;
/// @}
- std::unique_ptr<RuntimeFile<ELFT>> _scriptFile;
private:
static StringRef maybeGetSOName(Node *node);
+ void updateScopeAtomValues(StringRef start, StringRef end, StringRef sec);
};
-//===----------------------------------------------------------------------===//
-// OutputELFWriter
-//===----------------------------------------------------------------------===//
-template <class ELFT>
-OutputELFWriter<ELFT>::OutputELFWriter(ELFLinkingContext &context,
- TargetLayout<ELFT> &layout)
- : _context(context), _targetHandler(context.getTargetHandler<ELFT>()),
- _layout(layout),
- _scriptFile(new RuntimeFile<ELFT>(context, "Linker script runtime")) {}
-
-template <class ELFT>
-void OutputELFWriter<ELFT>::buildChunks(const File &file) {
- ScopedTask task(getDefaultDomain(), "buildChunks");
- for (const DefinedAtom *definedAtom : file.defined()) {
- DefinedAtom::ContentType contentType = definedAtom->contentType();
- // Dont add COMDAT group atoms and GNU linkonce atoms, as they are used for
- // symbol resolution.
- // TODO: handle partial linking.
- if (contentType == DefinedAtom::typeGroupComdat ||
- contentType == DefinedAtom::typeGnuLinkOnce)
- continue;
- _layout.addAtom(definedAtom);
- }
- for (const AbsoluteAtom *absoluteAtom : file.absolute())
- _layout.addAtom(absoluteAtom);
-}
-
-template <class ELFT>
-void OutputELFWriter<ELFT>::buildStaticSymbolTable(const File &file) {
- ScopedTask task(getDefaultDomain(), "buildStaticSymbolTable");
- for (auto sec : _layout.sections())
- if (auto section = dyn_cast<AtomSection<ELFT>>(sec))
- for (const auto &atom : section->atoms())
- _symtab->addSymbol(atom->_atom, section->ordinal(), atom->_virtualAddr);
- for (auto &atom : _layout.absoluteAtoms())
- _symtab->addSymbol(atom->_atom, ELF::SHN_ABS, atom->_virtualAddr);
- for (const UndefinedAtom *a : file.undefined())
- _symtab->addSymbol(a, ELF::SHN_UNDEF);
-}
-
-// Returns the DSO name for a given input file if it's a shared library
-// file and not marked as --as-needed.
-template <class ELFT>
-StringRef OutputELFWriter<ELFT>::maybeGetSOName(Node *node) {
- if (auto *fnode = dyn_cast<FileNode>(node))
- if (!fnode->asNeeded())
- if (auto *file = dyn_cast<SharedLibraryFile>(fnode->getFile()))
- return file->getDSOName();
- return "";
-}
-
-template <class ELFT>
-void OutputELFWriter<ELFT>::buildDynamicSymbolTable(const File &file) {
- ScopedTask task(getDefaultDomain(), "buildDynamicSymbolTable");
- for (const auto &sla : file.sharedLibrary()) {
- if (isDynSymEntryRequired(sla)) {
- _dynamicSymbolTable->addSymbol(sla, ELF::SHN_UNDEF);
- _soNeeded.insert(sla->loadName());
- continue;
- }
- if (isNeededTagRequired(sla))
- _soNeeded.insert(sla->loadName());
- }
- for (const std::unique_ptr<Node> &node : _context.getNodes()) {
- StringRef soname = maybeGetSOName(node.get());
- if (!soname.empty())
- _soNeeded.insert(soname);
- }
- // Never mark the dynamic linker as DT_NEEDED
- _soNeeded.erase(sys::path::filename(_context.getInterpreter()));
- for (const auto &loadName : _soNeeded) {
- Elf_Dyn dyn;
- dyn.d_tag = DT_NEEDED;
- dyn.d_un.d_val = _dynamicStringTable->addString(loadName.getKey());
- _dynamicTable->addEntry(dyn);
- }
- const auto &rpathList = _context.getRpathList();
- if (!rpathList.empty()) {
- auto rpath = new (_alloc) std::string(join(rpathList.begin(),
- rpathList.end(), ":"));
- Elf_Dyn dyn;
- dyn.d_tag = DT_RPATH;
- dyn.d_un.d_val = _dynamicStringTable->addString(*rpath);
- _dynamicTable->addEntry(dyn);
- }
- StringRef soname = _context.sharedObjectName();
- if (!soname.empty() && _context.getOutputELFType() == llvm::ELF::ET_DYN) {
- Elf_Dyn dyn;
- dyn.d_tag = DT_SONAME;
- dyn.d_un.d_val = _dynamicStringTable->addString(soname);
- _dynamicTable->addEntry(dyn);
- }
- // The dynamic symbol table need to be sorted earlier because the hash
- // table needs to be built using the dynamic symbol table. It would be
- // late to sort the symbols due to that in finalize. In the dynamic symbol
- // table finalize, we call the symbol table finalize and we don't want to
- // sort again
- _dynamicSymbolTable->sortSymbols();
-
- // Add the dynamic symbols into the hash table
- _dynamicSymbolTable->addSymbolsToHashTable();
-}
-
-template <class ELFT>
-void OutputELFWriter<ELFT>::buildAtomToAddressMap(const File &file) {
- ScopedTask task(getDefaultDomain(), "buildAtomToAddressMap");
- int64_t totalAbsAtoms = _layout.absoluteAtoms().size();
- int64_t totalUndefinedAtoms = file.undefined().size();
- int64_t totalDefinedAtoms = 0;
- for (auto sec : _layout.sections())
- if (auto section = dyn_cast<AtomSection<ELFT> >(sec)) {
- totalDefinedAtoms += section->atoms().size();
- for (const auto &atom : section->atoms())
- _atomToAddressMap[atom->_atom] = atom->_virtualAddr;
- }
- // build the atomToAddressMap that contains absolute symbols too
- for (auto &atom : _layout.absoluteAtoms())
- _atomToAddressMap[atom->_atom] = atom->_virtualAddr;
-
- // Set the total number of atoms in the symbol table, so that appropriate
- // resizing of the string table can be done
- _symtab->setNumEntries(totalDefinedAtoms + totalAbsAtoms +
- totalUndefinedAtoms);
-}
-
-template<class ELFT>
-void OutputELFWriter<ELFT>::buildSectionHeaderTable() {
- ScopedTask task(getDefaultDomain(), "buildSectionHeaderTable");
- for (auto outputSection : _layout.outputSections()) {
- if (outputSection->kind() != Chunk<ELFT>::Kind::ELFSection &&
- outputSection->kind() != Chunk<ELFT>::Kind::AtomSection)
- continue;
- if (outputSection->hasSegment())
- _shdrtab->appendSection(outputSection);
- }
-}
-
-template<class ELFT>
-void OutputELFWriter<ELFT>::assignSectionsWithNoSegments() {
- ScopedTask task(getDefaultDomain(), "assignSectionsWithNoSegments");
- for (auto outputSection : _layout.outputSections()) {
- if (outputSection->kind() != Chunk<ELFT>::Kind::ELFSection &&
- outputSection->kind() != Chunk<ELFT>::Kind::AtomSection)
- continue;
- if (!outputSection->hasSegment())
- _shdrtab->appendSection(outputSection);
- }
- _layout.assignFileOffsetsForMiscSections();
- for (auto sec : _layout.sections())
- if (auto section = dyn_cast<Section<ELFT>>(sec))
- if (!DefaultLayout<ELFT>::hasOutputSegment(section))
- _shdrtab->updateSection(section);
-}
-
-template <class ELFT> void OutputELFWriter<ELFT>::addDefaultAtoms() {
- const llvm::StringSet<> &symbols =
- _context.linkerScriptSema().getScriptDefinedSymbols();
- for (auto &sym : symbols)
- _scriptFile->addAbsoluteAtom(sym.getKey());
-}
-
-template <class ELFT>
-bool OutputELFWriter<ELFT>::createImplicitFiles(
- std::vector<std::unique_ptr<File>> &result) {
- // Add the virtual archive to resolve undefined symbols.
- // The file will be added later in the linking context.
- auto callback = [this](StringRef sym, RuntimeFile<ELFT> &file) {
- processUndefinedSymbol(sym, file);
- };
- auto &ctx = const_cast<ELFLinkingContext &>(_context);
- ctx.setUndefinesResolver(
- llvm::make_unique<DynamicSymbolFile<ELFT>>(ctx, std::move(callback)));
- // Add script defined symbols
- result.push_back(std::move(_scriptFile));
- return true;
-}
-
-template <class ELFT>
-void OutputELFWriter<ELFT>::finalizeDefaultAtomValues() {
- const llvm::StringSet<> &symbols =
- _context.linkerScriptSema().getScriptDefinedSymbols();
- for (auto &sym : symbols) {
- uint64_t res =
- _context.linkerScriptSema().getLinkerScriptExprValue(sym.getKey());
- auto a = _layout.findAbsoluteAtom(sym.getKey());
- (*a)->_virtualAddr = res;
- }
-}
-
-template <class ELFT> void OutputELFWriter<ELFT>::createDefaultSections() {
- _elfHeader.reset(new (_alloc) ELFHeader<ELFT>(_context));
- _programHeader.reset(new (_alloc) ProgramHeader<ELFT>(_context));
- _layout.setHeader(_elfHeader.get());
- _layout.setProgramHeader(_programHeader.get());
-
- _symtab = std::move(this->createSymbolTable());
- _strtab.reset(new (_alloc) StringTable<ELFT>(
- _context, ".strtab", DefaultLayout<ELFT>::ORDER_STRING_TABLE));
- _shstrtab.reset(new (_alloc) StringTable<ELFT>(
- _context, ".shstrtab", DefaultLayout<ELFT>::ORDER_SECTION_STRINGS));
- _shdrtab.reset(new (_alloc) SectionHeader<ELFT>(
- _context, DefaultLayout<ELFT>::ORDER_SECTION_HEADERS));
- _layout.addSection(_symtab.get());
- _layout.addSection(_strtab.get());
- _layout.addSection(_shstrtab.get());
- _shdrtab->setStringSection(_shstrtab.get());
- _symtab->setStringSection(_strtab.get());
- _layout.addSection(_shdrtab.get());
-
- for (auto sec : _layout.sections()) {
- // TODO: use findOutputSection
- auto section = dyn_cast<Section<ELFT>>(sec);
- if (!section || section->outputSectionName() != ".eh_frame")
- continue;
- _ehFrameHeader.reset(new (_alloc) EHFrameHeader<ELFT>(
- _context, ".eh_frame_hdr", _layout,
- DefaultLayout<ELFT>::ORDER_EH_FRAMEHDR));
- _layout.addSection(_ehFrameHeader.get());
- break;
- }
-
- if (_context.isDynamic()) {
- _dynamicTable = std::move(createDynamicTable());
- _dynamicStringTable.reset(new (_alloc) StringTable<ELFT>(
- _context, ".dynstr", DefaultLayout<ELFT>::ORDER_DYNAMIC_STRINGS, true));
- _dynamicSymbolTable = std::move(createDynamicSymbolTable());
- _hashTable.reset(new (_alloc) HashSection<ELFT>(
- _context, ".hash", DefaultLayout<ELFT>::ORDER_HASH));
- // Set the hash table in the dynamic symbol table so that the entries in the
- // hash table can be created
- _dynamicSymbolTable->setHashTable(_hashTable.get());
- _hashTable->setSymbolTable(_dynamicSymbolTable.get());
- _layout.addSection(_dynamicTable.get());
- _layout.addSection(_dynamicStringTable.get());
- _layout.addSection(_dynamicSymbolTable.get());
- _layout.addSection(_hashTable.get());
- _dynamicSymbolTable->setStringSection(_dynamicStringTable.get());
- _dynamicTable->setSymbolTable(_dynamicSymbolTable.get());
- _dynamicTable->setHashTable(_hashTable.get());
- if (_layout.hasDynamicRelocationTable())
- _layout.getDynamicRelocationTable()->setSymbolTable(
- _dynamicSymbolTable.get());
- if (_layout.hasPLTRelocationTable())
- _layout.getPLTRelocationTable()->setSymbolTable(
- _dynamicSymbolTable.get());
- }
-}
-
-template <class ELFT>
-unique_bump_ptr<SymbolTable<ELFT>>
- OutputELFWriter<ELFT>::createSymbolTable() {
- return unique_bump_ptr<SymbolTable<ELFT>>(new (_alloc) SymbolTable<ELFT>(
- this->_context, ".symtab", DefaultLayout<ELFT>::ORDER_SYMBOL_TABLE));
-}
-
-/// \brief create dynamic table
-template <class ELFT>
-unique_bump_ptr<DynamicTable<ELFT>>
- OutputELFWriter<ELFT>::createDynamicTable() {
- return unique_bump_ptr<DynamicTable<ELFT>>(
- new (_alloc) DynamicTable<ELFT>(
- this->_context, _layout, ".dynamic", DefaultLayout<ELFT>::ORDER_DYNAMIC));
-}
-
-/// \brief create dynamic symbol table
-template <class ELFT>
-unique_bump_ptr<DynamicSymbolTable<ELFT>>
- OutputELFWriter<ELFT>::createDynamicSymbolTable() {
- return unique_bump_ptr<DynamicSymbolTable<ELFT>>(
- new (_alloc) DynamicSymbolTable<ELFT>(
- this->_context, _layout, ".dynsym",
- DefaultLayout<ELFT>::ORDER_DYNAMIC_SYMBOLS));
-}
-
-template <class ELFT>
-std::error_code OutputELFWriter<ELFT>::buildOutput(const File &file) {
- ScopedTask buildTask(getDefaultDomain(), "ELF Writer buildOutput");
- buildChunks(file);
-
- // Create the default sections like the symbol table, string table, and the
- // section string table
- createDefaultSections();
-
- // Set the Layout
- _layout.assignSectionsToSegments();
-
- // Create the dynamic table entries
- if (_context.isDynamic()) {
- _dynamicTable->createDefaultEntries();
- buildDynamicSymbolTable(file);
- }
-
- // Call the preFlight callbacks to modify the sections and the atoms
- // contained in them, in anyway the targets may want
- _layout.doPreFlight();
-
- _layout.assignVirtualAddress();
-
- // Finalize the default value of symbols that the linker adds
- finalizeDefaultAtomValues();
-
- // Build the Atom To Address map for applying relocations
- buildAtomToAddressMap(file);
-
- // Create symbol table and section string table
- // Do it only if -s is not specified.
- if (!_context.stripSymbols())
- buildStaticSymbolTable(file);
-
- // Finalize the layout by calling the finalize() functions
- _layout.finalize();
-
- // build Section Header table
- buildSectionHeaderTable();
-
- // assign Offsets and virtual addresses
- // for sections with no segments
- assignSectionsWithNoSegments();
-
- if (_context.isDynamic())
- _dynamicTable->updateDynamicTable();
-
- return std::error_code();
-}
-
-template <class ELFT> std::error_code OutputELFWriter<ELFT>::setELFHeader() {
- _elfHeader->e_type(_context.getOutputELFType());
- _elfHeader->e_machine(_context.getOutputMachine());
- _elfHeader->e_ident(ELF::EI_VERSION, 1);
- _elfHeader->e_ident(ELF::EI_OSABI, 0);
- _elfHeader->e_version(1);
- _elfHeader->e_phoff(_programHeader->fileOffset());
- _elfHeader->e_shoff(_shdrtab->fileOffset());
- _elfHeader->e_phentsize(_programHeader->entsize());
- _elfHeader->e_phnum(_programHeader->numHeaders());
- _elfHeader->e_shentsize(_shdrtab->entsize());
- _elfHeader->e_shnum(_shdrtab->numHeaders());
- _elfHeader->e_shstrndx(_shstrtab->ordinal());
- if (const auto *al = _layout.findAtomLayoutByName(_context.entrySymbolName()))
- _elfHeader->e_entry(al->_virtualAddr);
- else
- _elfHeader->e_entry(0);
-
- return std::error_code();
-}
-
-template <class ELFT> uint64_t OutputELFWriter<ELFT>::outputFileSize() const {
- return _shdrtab->fileOffset() + _shdrtab->fileSize();
-}
-
-template <class ELFT>
-std::error_code OutputELFWriter<ELFT>::writeOutput(const File &file,
- StringRef path) {
- std::unique_ptr<FileOutputBuffer> buffer;
- ScopedTask createOutputTask(getDefaultDomain(), "ELF Writer Create Output");
- std::error_code ec = FileOutputBuffer::create(path, outputFileSize(), buffer,
- FileOutputBuffer::F_executable);
- createOutputTask.end();
-
- if (ec)
- return ec;
-
- ScopedTask writeTask(getDefaultDomain(), "ELF Writer write to memory");
-
- // HACK: We have to write out the header and program header here even though
- // they are a member of a segment because only sections are written in the
- // following loop.
-
- // Finalize ELF Header / Program Headers.
- _elfHeader->finalize();
- _programHeader->finalize();
-
- _elfHeader->write(this, _layout, *buffer);
- _programHeader->write(this, _layout, *buffer);
-
- auto sections = _layout.sections();
- parallel_for_each(
- sections.begin(), sections.end(),
- [&](Chunk<ELFT> *section) { section->write(this, _layout, *buffer); });
- writeTask.end();
-
- ScopedTask commitTask(getDefaultDomain(), "ELF Writer commit to disk");
- return buffer->commit();
-}
-
-template <class ELFT>
-std::error_code OutputELFWriter<ELFT>::writeFile(const File &file,
- StringRef path) {
- std::error_code ec = buildOutput(file);
- if (ec)
- return ec;
-
- ec = setELFHeader();
- if (ec)
- return ec;
-
- return writeOutput(file, path);
-}
} // namespace elf
} // namespace lld
diff --git a/lib/ReaderWriter/ELF/Reader.cpp b/lib/ReaderWriter/ELF/Reader.cpp
index fc113d478913..801f1abaed7a 100644
--- a/lib/ReaderWriter/ELF/Reader.cpp
+++ b/lib/ReaderWriter/ELF/Reader.cpp
@@ -29,15 +29,15 @@ namespace lld {
void Registry::addSupportELFObjects(ELFLinkingContext &ctx) {
// Tell registry about the ELF object file parser.
- add(std::move(ctx.targetHandler()->getObjReader()));
+ add(ctx.getTargetHandler().getObjReader());
// Tell registry about the relocation name to number mapping for this arch.
- ctx.targetHandler()->registerRelocationNames(*this);
+ ctx.registerRelocationNames(*this);
}
void Registry::addSupportELFDynamicSharedObjects(ELFLinkingContext &ctx) {
// Tell registry about the ELF dynamic shared library file parser.
- add(ctx.targetHandler()->getDSOReader());
+ add(ctx.getTargetHandler().getDSOReader());
}
} // end namespace lld
diff --git a/lib/ReaderWriter/ELF/SectionChunks.cpp b/lib/ReaderWriter/ELF/SectionChunks.cpp
new file mode 100644
index 000000000000..520fbe24af3b
--- /dev/null
+++ b/lib/ReaderWriter/ELF/SectionChunks.cpp
@@ -0,0 +1,996 @@
+//===- 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
index 03bdb59e6568..b10ba05237ff 100644
--- a/lib/ReaderWriter/ELF/SectionChunks.h
+++ b/lib/ReaderWriter/ELF/SectionChunks.h
@@ -11,19 +11,16 @@
#define LLD_READER_WRITER_ELF_SECTION_CHUNKS_H
#include "Chunk.h"
-#include "Layout.h"
#include "TargetHandler.h"
#include "Writer.h"
#include "lld/Core/DefinedAtom.h"
-#include "lld/Core/Parallel.h"
#include "lld/Core/range.h"
-#include "llvm/ADT/ArrayRef.h"
+#include "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/Debug.h"
-#include "llvm/Support/Dwarf.h"
#include "llvm/Support/ELF.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileOutputBuffer.h"
@@ -35,29 +32,22 @@ 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 &context, StringRef sectionName,
+ Section(const ELFLinkingContext &ctx, StringRef sectionName,
StringRef chunkName,
- typename Chunk<ELFT>::Kind k = Chunk<ELFT>::Kind::ELFSection)
- : Chunk<ELFT>(chunkName, k, context), _outputSection(nullptr), _flags(0),
- _entSize(0), _type(0), _link(0), _info(0),
- _isFirstSectionInOutputSection(false), _segmentType(SHT_NULL),
- _inputSectionName(sectionName), _outputSectionName(sectionName) {}
+ typename Chunk<ELFT>::Kind k = Chunk<ELFT>::Kind::ELFSection);
/// \brief Modify the section contents before assigning virtual addresses
// or assigning file offsets
- void doPreFlight() override {}
/// \brief Finalize the section contents before writing
- void finalize() override {}
/// \brief Does this section have an output segment.
- virtual bool hasOutputSegment() {
- return false;
- }
+ virtual bool hasOutputSegment() const { return false; }
/// Return if the section is a loadable section that occupies memory
virtual bool isLoadableSection() const { return false; }
@@ -73,26 +63,21 @@ public:
uint32_t getType() const { return _type; }
uint32_t getLink() const { return _link; }
uint32_t getInfo() const { return _info; }
- Layout::SegmentType getSegmentType() const { return _segmentType; }
- /// \brief Return the type of content that the section contains
- virtual int getContentType() const override {
- if (_flags & llvm::ELF::SHF_EXECINSTR)
- return Chunk<ELFT>::ContentType::Code;
- else if (_flags & llvm::ELF::SHF_WRITE)
- return Chunk<ELFT>::ContentType::Data;
- else if (_flags & llvm::ELF::SHF_ALLOC)
- return Chunk<ELFT>::ContentType::Code;
- else
- return Chunk<ELFT>::ContentType::Unknown;
+ 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
- StringRef segmentKindToStr() const;
+ virtual StringRef segmentKindToStr() const;
/// \brief Records the segmentType, that this section belongs to
- void setSegmentType(const Layout::SegmentType segmentType) {
+ void
+ setSegmentType(const typename TargetLayout<ELFT>::SegmentType segmentType) {
this->_segmentType = segmentType;
}
@@ -100,6 +85,10 @@ public:
return nullptr;
}
+ const OutputSection<ELFT> *getOutputSection() const {
+ return _outputSection;
+ }
+
void setOutputSection(OutputSection<ELFT> *os, bool isFirst = false) {
_outputSection = os;
_isFirstSectionInOutputSection = isFirst;
@@ -133,21 +122,21 @@ public:
protected:
/// \brief OutputSection this Section is a member of, or nullptr.
- OutputSection<ELFT> *_outputSection;
+ OutputSection<ELFT> *_outputSection = nullptr;
/// \brief ELF SHF_* flags.
- uint64_t _flags;
+ uint64_t _flags = 0;
/// \brief The size of each entity.
- uint64_t _entSize;
+ uint64_t _entSize = 0;
/// \brief ELF SHT_* type.
- uint32_t _type;
+ uint32_t _type = 0;
/// \brief sh_link field.
- uint32_t _link;
+ uint32_t _link = 0;
/// \brief the sh_info field.
- uint32_t _info;
+ uint32_t _info = 0;
/// \brief Is this the first section in the output section.
- bool _isFirstSectionInOutputSection;
+ bool _isFirstSectionInOutputSection = false;
/// \brief the output ELF segment type of this section.
- Layout::SegmentType _segmentType;
+ typename TargetLayout<ELFT>::SegmentType _segmentType = SHT_NULL;
/// \brief Input section name.
StringRef _inputSectionName;
/// \brief Output section name.
@@ -159,65 +148,8 @@ protected:
/// \brief A section containing atoms.
template <class ELFT> class AtomSection : public Section<ELFT> {
public:
- AtomSection(const ELFLinkingContext &context, StringRef sectionName,
- int32_t contentType, int32_t permissions, int32_t order)
- : Section<ELFT>(context, sectionName, "AtomSection",
- Chunk<ELFT>::Kind::AtomSection),
- _contentType(contentType), _contentPermissions(permissions),
- _isLoadedInMemory(true) {
- this->setOrder(order);
-
- switch (contentType) {
- case DefinedAtom::typeCode:
- case DefinedAtom::typeDataFast:
- case DefinedAtom::typeData:
- case DefinedAtom::typeConstant:
- case DefinedAtom::typeGOT:
- case DefinedAtom::typeStub:
- case DefinedAtom::typeResolver:
- case DefinedAtom::typeThreadData:
- this->_type = SHT_PROGBITS;
- break;
-
- case DefinedAtom::typeThreadZeroFill:
- case DefinedAtom::typeZeroFillFast:
- case DefinedAtom::typeZeroFill:
- this->_type = SHT_NOBITS;
- break;
-
- case DefinedAtom::typeRONote:
- case DefinedAtom::typeRWNote:
- this->_type = SHT_NOTE;
- break;
-
- case DefinedAtom::typeNoAlloc:
- this->_type = SHT_PROGBITS;
- this->_isLoadedInMemory = false;
- break;
- }
-
- switch (permissions) {
- case DefinedAtom::permR__:
- this->_flags = SHF_ALLOC;
- break;
- case DefinedAtom::permR_X:
- this->_flags = SHF_ALLOC | SHF_EXECINSTR;
- break;
- case DefinedAtom::permRW_:
- case DefinedAtom::permRW_L:
- this->_flags = SHF_ALLOC | SHF_WRITE;
- if (_contentType == DefinedAtom::typeThreadData ||
- _contentType == DefinedAtom::typeThreadZeroFill)
- this->_flags |= SHF_TLS;
- break;
- case DefinedAtom::permRWX:
- this->_flags = SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR;
- break;
- case DefinedAtom::perm___:
- this->_flags = 0;
- break;
- }
- }
+ 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);
@@ -228,40 +160,27 @@ public:
// \brief Append an atom to a Section. The atom gets pushed into a vector
// contains the atom, the atom file offset, the atom virtual address
// the atom file offset is aligned appropriately as set by the Reader
- virtual const lld::AtomLayout *appendAtom(const Atom *atom);
+ 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
- virtual void assignVirtualAddress(uint64_t addr) override {
- parallel_for_each(_atoms.begin(), _atoms.end(), [&](AtomLayout *ai) {
- ai->_virtualAddr = addr + ai->_fileOffset;
- });
- }
+ 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 {
- parallel_for_each(_atoms.begin(), _atoms.end(), [&](AtomLayout *ai) {
- ai->_fileOffset = offset + ai->_fileOffset;
- });
- }
+ 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 {
- for (auto ai : _atoms)
- if (ai->_atom->name() == name)
- return ai;
- return nullptr;
- }
+ 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<lld::AtomLayout *>::iterator atom_iter;
+ typedef typename std::vector<AtomLayout *>::iterator atom_iter;
range<atom_iter> atoms() { return _atoms; }
@@ -276,185 +195,27 @@ protected:
llvm::BumpPtrAllocator _alloc;
int32_t _contentType;
int32_t _contentPermissions;
- bool _isLoadedInMemory;
- std::vector<lld::AtomLayout *> _atoms;
+ bool _isLoadedInMemory = true;
+ std::vector<AtomLayout *> _atoms;
mutable std::mutex _outputMutex;
- void printError(const std::string &errorStr, const AtomLayout &atom,
- const Reference &ref) const {
- StringRef kindValStr;
- if (!this->_context.registry().referenceKindToString(ref.kindNamespace(),
- ref.kindArch(),
- ref.kindValue(),
- kindValStr)) {
- kindValStr = "unknown";
- }
-
- std::string errStr = (Twine(errorStr) + " in file " +
- atom._atom->file().path() +
- ": reference from " + atom._atom->name() +
- "+" + Twine(ref.offsetInAtom()) +
- " to " + ref.target()->name() +
- "+" + Twine(ref.addend()) +
- " of type " + Twine(ref.kindValue()) +
- " (" + kindValStr + ")\n").str();
-
- // Take the lock to prevent output getting interleaved between threads
- std::lock_guard<std::mutex> lock(_outputMutex);
- llvm::errs() << errStr;
- }
+ std::string formatError(const std::string &errorStr, const AtomLayout &atom,
+ const Reference &ref) const;
};
-/// Align the offset to the required modulus defined by the atom alignment
-template <class ELFT>
-uint64_t AtomSection<ELFT>::alignOffset(uint64_t offset,
- DefinedAtom::Alignment &atomAlign) {
- uint64_t requiredModulus = atomAlign.modulus;
- uint64_t alignment = 1u << atomAlign.powerOf2;
- uint64_t currentModulus = (offset % alignment);
- uint64_t retOffset = offset;
- if (currentModulus != requiredModulus) {
- if (requiredModulus > currentModulus)
- retOffset += requiredModulus - currentModulus;
- else
- retOffset += alignment + requiredModulus - currentModulus;
- }
- return retOffset;
-}
-
-// \brief Append an atom to a Section. The atom gets pushed into a vector
-// contains the atom, the atom file offset, the atom virtual address
-// the atom file offset is aligned appropriately as set by the Reader
-template <class ELFT>
-const lld::AtomLayout *AtomSection<ELFT>::appendAtom(const Atom *atom) {
- const DefinedAtom *definedAtom = cast<DefinedAtom>(atom);
-
- DefinedAtom::Alignment atomAlign = definedAtom->alignment();
- uint64_t alignment = 1u << atomAlign.powerOf2;
- // Align the atom to the required modulus/ align the file offset and the
- // memory offset separately this is required so that BSS symbols are handled
- // properly as the BSS symbols only occupy memory size and not file size
- uint64_t fOffset = alignOffset(this->fileSize(), atomAlign);
- uint64_t mOffset = alignOffset(this->memSize(), atomAlign);
- switch(definedAtom->contentType()) {
- case DefinedAtom::typeCode:
- case DefinedAtom::typeConstant:
- case DefinedAtom::typeData:
- case DefinedAtom::typeDataFast:
- case DefinedAtom::typeZeroFillFast:
- case DefinedAtom::typeGOT:
- case DefinedAtom::typeStub:
- case DefinedAtom::typeResolver:
- case DefinedAtom::typeThreadData:
- case DefinedAtom::typeRONote:
- case DefinedAtom::typeRWNote:
- _atoms.push_back(new (_alloc) lld::AtomLayout(atom, fOffset, 0));
- this->_fsize = fOffset + definedAtom->size();
- this->_msize = mOffset + definedAtom->size();
- DEBUG_WITH_TYPE("Section",
- llvm::dbgs() << "[" << this->name() << " " << this << "] "
- << "Adding atom: " << atom->name() << "@"
- << fOffset << "\n");
- break;
- case DefinedAtom::typeNoAlloc:
- _atoms.push_back(new (_alloc) lld::AtomLayout(atom, fOffset, 0));
- this->_fsize = fOffset + definedAtom->size();
- DEBUG_WITH_TYPE("Section", llvm::dbgs() << "[" << this->name() << " "
- << this << "] "
- << "Adding atom: " << atom->name()
- << "@" << fOffset << "\n");
- break;
- case DefinedAtom::typeThreadZeroFill:
- case DefinedAtom::typeZeroFill:
- _atoms.push_back(new (_alloc) lld::AtomLayout(atom, mOffset, 0));
- this->_msize = mOffset + definedAtom->size();
- break;
- default:
- llvm::dbgs() << definedAtom->contentType() << "\n";
- llvm_unreachable("Uexpected content type.");
- }
- // Set the section alignment to the largest alignment
- // std::max doesn't support uint64_t
- if (this->_alignment < alignment)
- this->_alignment = alignment;
-
- if (_atoms.size())
- return _atoms.back();
- return nullptr;
-}
-
-/// \brief convert the segment type to a String for diagnostics
-/// and printing purposes
-template <class ELFT> StringRef Section<ELFT>::segmentKindToStr() const {
- switch(_segmentType) {
- case llvm::ELF::PT_DYNAMIC:
- return "DYNAMIC";
- case llvm::ELF::PT_INTERP:
- return "INTERP";
- case llvm::ELF::PT_LOAD:
- return "LOAD";
- case llvm::ELF::PT_GNU_EH_FRAME:
- return "EH_FRAME";
- case llvm::ELF::PT_GNU_RELRO:
- return "GNU_RELRO";
- case llvm::ELF::PT_NOTE:
- return "NOTE";
- case llvm::ELF::PT_NULL:
- return "NULL";
- case llvm::ELF::PT_TLS:
- return "TLS";
- default:
- return "UNKNOWN";
- }
-}
-
-/// \brief Write the section and the atom contents to the buffer
-template <class ELFT>
-void AtomSection<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout,
- llvm::FileOutputBuffer &buffer) {
- uint8_t *chunkBuffer = buffer.getBufferStart();
- bool success = true;
- parallel_for_each(_atoms.begin(), _atoms.end(), [&](lld::AtomLayout * ai) {
- DEBUG_WITH_TYPE("Section",
- llvm::dbgs() << "Writing atom: " << ai->_atom->name()
- << " | " << ai->_fileOffset << "\n");
- const DefinedAtom *definedAtom = cast<DefinedAtom>(ai->_atom);
- if (!definedAtom->occupiesDiskSpace())
- return;
- // Copy raw content of atom to file buffer.
- ArrayRef<uint8_t> content = definedAtom->rawContent();
- uint64_t contentSize = content.size();
- if (contentSize == 0)
- return;
- uint8_t *atomContent = chunkBuffer + ai->_fileOffset;
- std::memcpy(atomContent, content.data(), contentSize);
- const TargetRelocationHandler &relHandler =
- this->_context.template getTargetHandler<ELFT>().getRelocationHandler();
- for (const auto ref : *definedAtom) {
- if (std::error_code ec = relHandler.applyRelocation(*writer, buffer,
- *ai, *ref)) {
- printError(ec.message(), *ai, *ref);
- success = false;
- }
- }
- });
- if (!success)
- llvm::report_fatal_error("relocating output");
-}
-
/// \brief A OutputSection represents a set of sections grouped by the same
/// name. The output file that gets written by the linker has sections grouped
/// by similar names
template <class ELFT> class OutputSection {
public:
// Iterators
- typedef typename std::vector<Chunk<ELFT> *>::iterator ChunkIter;
+ typedef typename std::vector<Section<ELFT> *>::iterator SectionIter;
- OutputSection(StringRef name);
+ OutputSection(StringRef name) : _name(name) {}
// Appends a section into the list of sections that are part of this Output
// Section
- void appendSection(Chunk<ELFT> *c);
+ void appendSection(Section<ELFT> *c);
// Set the OutputSection is associated with a segment
void setHasSegment() { _hasSegment = true; }
@@ -484,90 +245,48 @@ public:
}
void setLink(uint64_t link) { _link = link; }
-
void setInfo(uint64_t info) { _shInfo = info; }
-
void setFlag(uint64_t flags) { _flags = flags; }
-
- void setType(int16_t type) { _type = type; }
-
- range<ChunkIter> sections() { return _sections; }
+ 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; }
-
- int64_t flags() const { return _flags; }
-
- uint64_t memSize() { return _memSize; }
+ uint64_t flags() const { return _flags; }
+ uint64_t memSize() const { return _memSize; }
private:
StringRef _name;
- bool _hasSegment;
- uint64_t _ordinal;
- uint64_t _flags;
- uint64_t _size;
- uint64_t _memSize;
- uint64_t _fileOffset;
- uint64_t _virtualAddr;
- int64_t _shInfo;
- int64_t _entSize;
- int64_t _link;
- uint64_t _alignment;
- int64_t _kind;
- int64_t _type;
- bool _isLoadableSection;
- std::vector<Chunk<ELFT> *> _sections;
+ 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;
};
-/// OutputSection
-template <class ELFT>
-OutputSection<ELFT>::OutputSection(StringRef name)
- : _name(name), _hasSegment(false), _ordinal(0), _flags(0), _size(0),
- _memSize(0), _fileOffset(0), _virtualAddr(0), _shInfo(0), _entSize(0),
- _link(0), _alignment(0), _kind(0), _type(0), _isLoadableSection(false) {}
-
-template <class ELFT> void OutputSection<ELFT>::appendSection(Chunk<ELFT> *c) {
- if (c->alignment() > _alignment)
- _alignment = c->alignment();
- if (const auto section = dyn_cast<Section<ELFT>>(c)) {
- assert(!_link && "Section already has a link!");
- _link = section->getLink();
- _shInfo = section->getInfo();
- _entSize = section->getEntSize();
- _type = section->getType();
- if (_flags < section->getFlags())
- _flags = section->getFlags();
- section->setOutputSection(this, (_sections.size() == 0));
- }
- _kind = c->kind();
- _sections.push_back(c);
-}
-
/// \brief The class represents the ELF String Table
-template<class ELFT>
-class StringTable : public Section<ELFT> {
+template <class ELFT> class StringTable : public Section<ELFT> {
public:
StringTable(const ELFLinkingContext &, const char *str, int32_t order,
bool dynamic = false);
@@ -592,68 +311,21 @@ private:
return lhs.equals(rhs);
}
};
- typedef typename llvm::DenseMap<StringRef, uint64_t,
- StringRefMappingInfo> StringMapT;
+ typedef typename llvm::DenseMap<StringRef, uint64_t, StringRefMappingInfo>
+ StringMapT;
typedef typename StringMapT::iterator StringMapTIter;
StringMapT _stringMap;
};
-template <class ELFT>
-StringTable<ELFT>::StringTable(const ELFLinkingContext &context,
- const char *str, int32_t order, bool dynamic)
- : Section<ELFT>(context, str, "StringTable") {
- // the string table has a NULL entry for which
- // add an empty string
- _strings.push_back("");
- this->_fsize = 1;
- this->_alignment = 1;
- this->setOrder(order);
- this->_type = SHT_STRTAB;
- if (dynamic) {
- this->_flags = SHF_ALLOC;
- this->_msize = this->_fsize;
- }
-}
-
-template <class ELFT> uint64_t StringTable<ELFT>::addString(StringRef symname) {
- if (symname.empty())
- return 0;
- StringMapTIter stringIter = _stringMap.find(symname);
- if (stringIter == _stringMap.end()) {
- _strings.push_back(symname);
- uint64_t offset = this->_fsize;
- this->_fsize += symname.size() + 1;
- if (this->_flags & SHF_ALLOC)
- this->_msize = this->_fsize;
- _stringMap[symname] = offset;
- return offset;
- }
- return stringIter->second;
-}
-
-template <class ELFT>
-void StringTable<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &,
- llvm::FileOutputBuffer &buffer) {
- uint8_t *chunkBuffer = buffer.getBufferStart();
- uint8_t *dest = chunkBuffer + this->fileOffset();
- for (auto si : _strings) {
- memcpy(dest, si.data(), si.size());
- dest += si.size();
- memcpy(dest, "", 1);
- dest += 1;
- }
-}
-
/// \brief The SymbolTable class represents the symbol table in a ELF file
-template<class ELFT>
-class SymbolTable : public Section<ELFT> {
- typedef typename llvm::object::ELFDataTypeTypedefHelper<ELFT>::Elf_Addr
- Elf_Addr;
+template <class ELFT> class SymbolTable : public Section<ELFT> {
+ typedef
+ typename llvm::object::ELFDataTypeTypedefHelper<ELFT>::Elf_Addr Elf_Addr;
public:
typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
- SymbolTable(const ELFLinkingContext &context, const char *str, int32_t order);
+ 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
@@ -666,7 +338,7 @@ public:
std::size_t size() const { return _symbolTable.size(); }
void addSymbol(const Atom *atom, int32_t sectionIndex, uint64_t addr = 0,
- const lld::AtomLayout *layout = nullptr);
+ const AtomLayout *layout = nullptr);
/// \brief Get the symbol table index for an Atom. If it's not in the symbol
/// table, return STN_UNDEF.
@@ -681,9 +353,9 @@ public:
virtual void sortSymbols() {
std::stable_sort(_symbolTable.begin(), _symbolTable.end(),
- [](const SymbolEntry & A, const SymbolEntry & B) {
- return A._symbol.getBinding() < B._symbol.getBinding();
- });
+ [](const SymbolEntry &A, const SymbolEntry &B) {
+ return A._symbol.getBinding() < B._symbol.getBinding();
+ });
}
virtual void addAbsoluteAtom(Elf_Sym &sym, const AbsoluteAtom *aa,
@@ -707,12 +379,11 @@ public:
protected:
struct SymbolEntry {
- SymbolEntry(const Atom *a, const Elf_Sym &sym,
- const lld::AtomLayout *layout)
+ SymbolEntry(const Atom *a, const Elf_Sym &sym, const AtomLayout *layout)
: _atom(a), _atomLayout(layout), _symbol(sym) {}
const Atom *_atom;
- const lld::AtomLayout *_atomLayout;
+ const AtomLayout *_atomLayout;
Elf_Sym _symbol;
};
@@ -721,233 +392,23 @@ protected:
std::vector<SymbolEntry> _symbolTable;
};
-/// ELF Symbol Table
-template <class ELFT>
-SymbolTable<ELFT>::SymbolTable(const ELFLinkingContext &context,
- const char *str, int32_t order)
- : Section<ELFT>(context, str, "SymbolTable") {
- this->setOrder(order);
- Elf_Sym symbol;
- std::memset(&symbol, 0, sizeof(Elf_Sym));
- _symbolTable.push_back(SymbolEntry(nullptr, symbol, nullptr));
- this->_entSize = sizeof(Elf_Sym);
- this->_fsize = sizeof(Elf_Sym);
- this->_alignment = sizeof(Elf_Addr);
- this->_type = SHT_SYMTAB;
-}
-
-template <class ELFT>
-void SymbolTable<ELFT>::addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da,
- int64_t addr) {
- unsigned char binding = 0, type = 0;
- sym.st_size = da->size();
- DefinedAtom::ContentType ct;
- switch (ct = da->contentType()) {
- case DefinedAtom::typeCode:
- case DefinedAtom::typeStub:
- sym.st_value = addr;
- type = llvm::ELF::STT_FUNC;
- break;
- case DefinedAtom::typeResolver:
- sym.st_value = addr;
- type = llvm::ELF::STT_GNU_IFUNC;
- break;
- case DefinedAtom::typeDataFast:
- case DefinedAtom::typeData:
- case DefinedAtom::typeConstant:
- sym.st_value = addr;
- type = llvm::ELF::STT_OBJECT;
- break;
- case DefinedAtom::typeGOT:
- sym.st_value = addr;
- type = llvm::ELF::STT_NOTYPE;
- break;
- case DefinedAtom::typeZeroFill:
- case DefinedAtom::typeZeroFillFast:
- type = llvm::ELF::STT_OBJECT;
- sym.st_value = addr;
- break;
- case DefinedAtom::typeThreadData:
- case DefinedAtom::typeThreadZeroFill:
- type = llvm::ELF::STT_TLS;
- sym.st_value = addr;
- break;
- default:
- type = llvm::ELF::STT_NOTYPE;
- }
- if (da->customSectionName() == da->name())
- type = llvm::ELF::STT_SECTION;
-
- if (da->scope() == DefinedAtom::scopeTranslationUnit)
- binding = llvm::ELF::STB_LOCAL;
- else
- binding = llvm::ELF::STB_GLOBAL;
-
- sym.setBindingAndType(binding, type);
-}
-
-template <class ELFT>
-void SymbolTable<ELFT>::addAbsoluteAtom(Elf_Sym &sym, const AbsoluteAtom *aa,
- int64_t addr) {
- unsigned char binding = 0, type = 0;
- type = llvm::ELF::STT_OBJECT;
- sym.st_shndx = llvm::ELF::SHN_ABS;
- switch (aa->scope()) {
- case AbsoluteAtom::scopeLinkageUnit:
- sym.setVisibility(llvm::ELF::STV_HIDDEN);
- binding = llvm::ELF::STB_LOCAL;
- break;
- case AbsoluteAtom::scopeTranslationUnit:
- binding = llvm::ELF::STB_LOCAL;
- break;
- case AbsoluteAtom::scopeGlobal:
- binding = llvm::ELF::STB_GLOBAL;
- break;
- }
- sym.st_value = addr;
- sym.setBindingAndType(binding, type);
-}
-
-template <class ELFT>
-void SymbolTable<ELFT>::addSharedLibAtom(Elf_Sym &sym,
- const SharedLibraryAtom *aa) {
- unsigned char binding = 0, type = 0;
- if (aa->type() == SharedLibraryAtom::Type::Data) {
- type = llvm::ELF::STT_OBJECT;
- sym.st_size = aa->size();
- } else
- type = llvm::ELF::STT_FUNC;
- sym.st_shndx = llvm::ELF::SHN_UNDEF;
- binding = llvm::ELF::STB_GLOBAL;
- sym.setBindingAndType(binding, type);
-}
-
-template <class ELFT>
-void SymbolTable<ELFT>::addUndefinedAtom(Elf_Sym &sym,
- const UndefinedAtom *ua) {
- unsigned char binding = 0, type = 0;
- sym.st_value = 0;
- type = llvm::ELF::STT_NOTYPE;
- if (ua->canBeNull())
- binding = llvm::ELF::STB_WEAK;
- else
- binding = llvm::ELF::STB_GLOBAL;
- sym.setBindingAndType(binding, type);
-}
-
-/// Add a symbol to the symbol Table, definedAtoms which get added to the symbol
-/// section don't have their virtual addresses set at the time of adding the
-/// symbol to the symbol table(Example: dynamic symbols), the addresses needs
-/// to be updated in the table before writing the dynamic symbol table
-/// information
-template <class ELFT>
-void SymbolTable<ELFT>::addSymbol(const Atom *atom, int32_t sectionIndex,
- uint64_t addr,
- const lld::AtomLayout *atomLayout) {
- Elf_Sym symbol;
-
- if (atom->name().empty())
- return;
-
- symbol.st_name = _stringSection->addString(atom->name());
- symbol.st_size = 0;
- symbol.st_shndx = sectionIndex;
- symbol.st_value = 0;
- symbol.st_other = 0;
- symbol.setVisibility(llvm::ELF::STV_DEFAULT);
-
- // Add all the atoms
- if (const DefinedAtom *da = dyn_cast<const DefinedAtom>(atom))
- addDefinedAtom(symbol, da, addr);
- else if (const AbsoluteAtom *aa = dyn_cast<const AbsoluteAtom>(atom))
- addAbsoluteAtom(symbol, aa, addr);
- else if (isa<const SharedLibraryAtom>(atom))
- addSharedLibAtom(symbol, dyn_cast<SharedLibraryAtom>(atom));
- else
- addUndefinedAtom(symbol, dyn_cast<UndefinedAtom>(atom));
-
- _symbolTable.push_back(SymbolEntry(atom, symbol, atomLayout));
- this->_fsize += sizeof(Elf_Sym);
- if (this->_flags & SHF_ALLOC)
- this->_msize = this->_fsize;
-}
-
-template <class ELFT> void SymbolTable<ELFT>::finalize(bool sort) {
- // sh_info should be one greater than last symbol with STB_LOCAL binding
- // we sort the symbol table to keep all local symbols at the beginning
- if (sort)
- sortSymbols();
-
- uint16_t shInfo = 0;
- for (const auto &i : _symbolTable) {
- if (i._symbol.getBinding() != llvm::ELF::STB_LOCAL)
- break;
- shInfo++;
- }
- this->_info = shInfo;
- this->_link = _stringSection->ordinal();
- if (this->_outputSection) {
- this->_outputSection->setInfo(this->_info);
- this->_outputSection->setLink(this->_link);
- }
-}
-
-template <class ELFT>
-void SymbolTable<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &,
- llvm::FileOutputBuffer &buffer) {
- uint8_t *chunkBuffer = buffer.getBufferStart();
- uint8_t *dest = chunkBuffer + this->fileOffset();
- for (const auto &sti : _symbolTable) {
- memcpy(dest, &sti._symbol, sizeof(Elf_Sym));
- dest += sizeof(Elf_Sym);
- }
-}
-
template <class ELFT> class HashSection;
template <class ELFT> class DynamicSymbolTable : public SymbolTable<ELFT> {
public:
- DynamicSymbolTable(const ELFLinkingContext &context,
- TargetLayout<ELFT> &layout, const char *str, int32_t order)
- : SymbolTable<ELFT>(context, str, order), _hashTable(nullptr),
- _layout(layout) {
- this->_type = SHT_DYNSYM;
- this->_flags = SHF_ALLOC;
- this->_msize = this->_fsize;
- }
+ 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() {
- int index = 0;
- for (auto &ste : this->_symbolTable) {
- if (!ste._atom)
- _hashTable->addSymbol("", index);
- else
- _hashTable->addSymbol(ste._atom->name(), index);
- ++index;
- }
- }
+ void addSymbolsToHashTable();
- void finalize() override {
- // Defined symbols which have been added into the dynamic symbol table
- // don't have their addresses known until addresses have been assigned
- // so let's update the symbol values after they have got assigned
- for (auto &ste: this->_symbolTable) {
- const lld::AtomLayout *atomLayout = ste._atomLayout;
- if (!atomLayout)
- continue;
- ste._symbol.st_value = atomLayout->_virtualAddr;
- }
-
- // Don't sort the symbols
- SymbolTable<ELFT>::finalize(false);
- }
+ void finalize() override;
protected:
- HashSection<ELFT> *_hashTable;
+ HashSection<ELFT> *_hashTable = nullptr;
TargetLayout<ELFT> &_layout;
};
@@ -956,118 +417,36 @@ public:
typedef llvm::object::Elf_Rel_Impl<ELFT, false> Elf_Rel;
typedef llvm::object::Elf_Rel_Impl<ELFT, true> Elf_Rela;
- RelocationTable(const ELFLinkingContext &context, StringRef str,
- int32_t order)
- : Section<ELFT>(context, str, "RelocationTable"), _symbolTable(nullptr) {
- this->setOrder(order);
- this->_flags = SHF_ALLOC;
- // Set the alignment properly depending on the target architecture
- this->_alignment = ELFT::Is64Bits ? 8 : 4;
- if (context.isRelaOutputFormat()) {
- this->_entSize = sizeof(Elf_Rela);
- this->_type = SHT_RELA;
- } else {
- this->_entSize = sizeof(Elf_Rel);
- this->_type = SHT_REL;
- }
- }
+ 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) {
- _relocs.emplace_back(&da, &r);
- this->_fsize = _relocs.size() * this->_entSize;
- this->_msize = this->_fsize;
- return _relocs.size() - 1;
- }
+ uint32_t addRelocation(const DefinedAtom &da, const Reference &r);
- bool getRelocationIndex(const Reference &r, uint32_t &res) {
- auto rel = std::find_if(
- _relocs.begin(), _relocs.end(),
- [&](const std::pair<const DefinedAtom *, const Reference *> &p) {
- if (p.second == &r)
- return true;
- return false;
- });
- if (rel == _relocs.end())
- return false;
- res = std::distance(_relocs.begin(), rel);
- return true;
- }
+ 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 {
- for (const auto &rel : _relocs) {
- const DefinedAtom *atom = rel.first;
- if ((atom->permissions() & DefinedAtom::permRW_) != DefinedAtom::permRW_)
- return true;
- }
- return false;
- }
+ bool canModifyReadonlySection() const;
- void finalize() override {
- this->_link = _symbolTable ? _symbolTable->ordinal() : 0;
- if (this->_outputSection)
- this->_outputSection->setLink(this->_link);
- }
+ void finalize() override;
void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
- llvm::FileOutputBuffer &buffer) override {
- uint8_t *chunkBuffer = buffer.getBufferStart();
- uint8_t *dest = chunkBuffer + this->fileOffset();
- for (const auto &rel : _relocs) {
- if (this->_context.isRelaOutputFormat()) {
- auto &r = *reinterpret_cast<Elf_Rela *>(dest);
- writeRela(writer, r, *rel.first, *rel.second);
- DEBUG_WITH_TYPE("ELFRelocationTable",
- llvm::dbgs()
- << rel.second->kindValue() << " relocation at "
- << rel.first->name() << "@" << r.r_offset << " to "
- << rel.second->target()->name() << "@" << r.r_addend
- << "\n";);
- } else {
- auto &r = *reinterpret_cast<Elf_Rel *>(dest);
- writeRel(writer, r, *rel.first, *rel.second);
- DEBUG_WITH_TYPE("ELFRelocationTable",
- llvm::dbgs() << rel.second->kindValue()
- << " relocation at " << rel.first->name()
- << "@" << r.r_offset << " to "
- << rel.second->target()->name() << "\n";);
- }
- dest += this->_entSize;
- }
- }
+ llvm::FileOutputBuffer &buffer) override;
protected:
- const DynamicSymbolTable<ELFT> *_symbolTable;
+ const DynamicSymbolTable<ELFT> *_symbolTable = nullptr;
virtual void writeRela(ELFWriter *writer, Elf_Rela &r,
- const DefinedAtom &atom, const Reference &ref) {
- r.setSymbolAndType(getSymbolIndex(ref.target()), ref.kindValue(), false);
- r.r_offset = writer->addressOfAtom(&atom) + ref.offsetInAtom();
- // The addend is used only by relative relocations
- if (this->_context.isRelativeReloc(ref))
- r.r_addend = writer->addressOfAtom(ref.target()) + ref.addend();
- else
- r.r_addend = 0;
- }
-
+ const DefinedAtom &atom, const Reference &ref);
virtual void writeRel(ELFWriter *writer, Elf_Rel &r, const DefinedAtom &atom,
- const Reference &ref) {
- r.setSymbolAndType(getSymbolIndex(ref.target()), ref.kindValue(), false);
- r.r_offset = writer->addressOfAtom(&atom) + ref.offsetInAtom();
- }
-
- uint32_t getSymbolIndex(const Atom *a) {
- return _symbolTable ? _symbolTable->getSymbolTableIndex(a)
- : (uint32_t)STN_UNDEF;
- }
+ const Reference &ref);
+ uint32_t getSymbolIndex(const Atom *a);
private:
- std::vector<std::pair<const DefinedAtom *, const Reference *> > _relocs;
+ std::vector<std::pair<const DefinedAtom *, const Reference *>> _relocs;
};
template <class ELFT> class HashSection;
@@ -1077,125 +456,25 @@ public:
typedef llvm::object::Elf_Dyn_Impl<ELFT> Elf_Dyn;
typedef std::vector<Elf_Dyn> EntriesT;
- DynamicTable(const ELFLinkingContext &context, TargetLayout<ELFT> &layout,
- StringRef str, int32_t order)
- : Section<ELFT>(context, str, "DynamicSection"), _layout(layout) {
- this->setOrder(order);
- this->_entSize = sizeof(Elf_Dyn);
- this->_alignment = ELFT::Is64Bits ? 8 : 4;
- // Reserve space for the DT_NULL entry.
- this->_fsize = sizeof(Elf_Dyn);
- this->_msize = sizeof(Elf_Dyn);
- this->_type = SHT_DYNAMIC;
- this->_flags = SHF_ALLOC;
- }
+ 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(Elf_Dyn e) {
- _entries.push_back(e);
- this->_fsize = (_entries.size() * sizeof(Elf_Dyn)) + sizeof(Elf_Dyn);
- this->_msize = this->_fsize;
- return _entries.size() - 1;
- }
+ std::size_t addEntry(int64_t tag, uint64_t val);
void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
- llvm::FileOutputBuffer &buffer) override {
- uint8_t *chunkBuffer = buffer.getBufferStart();
- uint8_t *dest = chunkBuffer + this->fileOffset();
- // Add the null entry.
- Elf_Dyn d;
- d.d_tag = 0;
- d.d_un.d_val = 0;
- _entries.push_back(d);
- std::memcpy(dest, _entries.data(), this->_fsize);
- }
-
- virtual void createDefaultEntries() {
- bool isRela = this->_context.isRelaOutputFormat();
-
- Elf_Dyn dyn;
- dyn.d_un.d_val = 0;
-
- dyn.d_tag = DT_HASH;
- _dt_hash = addEntry(dyn);
- dyn.d_tag = DT_STRTAB;
- _dt_strtab = addEntry(dyn);
- dyn.d_tag = DT_SYMTAB;
- _dt_symtab = addEntry(dyn);
- dyn.d_tag = DT_STRSZ;
- _dt_strsz = addEntry(dyn);
- dyn.d_tag = DT_SYMENT;
- _dt_syment = addEntry(dyn);
- if (_layout.hasDynamicRelocationTable()) {
- dyn.d_tag = isRela ? DT_RELA : DT_REL;
- _dt_rela = addEntry(dyn);
- dyn.d_tag = isRela ? DT_RELASZ : DT_RELSZ;
- _dt_relasz = addEntry(dyn);
- dyn.d_tag = isRela ? DT_RELAENT : DT_RELENT;
- _dt_relaent = addEntry(dyn);
-
- if (_layout.getDynamicRelocationTable()->canModifyReadonlySection()) {
- dyn.d_tag = DT_TEXTREL;
- _dt_textrel = addEntry(dyn);
- }
- }
- if (_layout.hasPLTRelocationTable()) {
- dyn.d_tag = DT_PLTRELSZ;
- _dt_pltrelsz = addEntry(dyn);
- dyn.d_tag = getGotPltTag();
- _dt_pltgot = addEntry(dyn);
- dyn.d_tag = DT_PLTREL;
- dyn.d_un.d_val = isRela ? DT_RELA : DT_REL;
- _dt_pltrel = addEntry(dyn);
- dyn.d_un.d_val = 0;
- dyn.d_tag = DT_JMPREL;
- _dt_jmprel = addEntry(dyn);
- }
- }
+ llvm::FileOutputBuffer &buffer) override;
- void doPreFlight() override {
- Elf_Dyn dyn;
- dyn.d_un.d_val = 0;
- auto initArray = _layout.findOutputSection(".init_array");
- auto finiArray = _layout.findOutputSection(".fini_array");
- if (initArray) {
- dyn.d_tag = DT_INIT_ARRAY;
- _dt_init_array = addEntry(dyn);
- dyn.d_tag = DT_INIT_ARRAYSZ;
- _dt_init_arraysz = addEntry(dyn);
- }
- if (finiArray) {
- dyn.d_tag = DT_FINI_ARRAY;
- _dt_fini_array = addEntry(dyn);
- dyn.d_tag = DT_FINI_ARRAYSZ;
- _dt_fini_arraysz = addEntry(dyn);
- }
- if (getInitAtomLayout()) {
- dyn.d_tag = DT_INIT;
- _dt_init = addEntry(dyn);
- }
- if (getFiniAtomLayout()) {
- dyn.d_tag = DT_FINI;
- _dt_fini = addEntry(dyn);
- }
- }
+ 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 {
- StringTable<ELFT> *dynamicStringTable =
- _dynamicSymbolTable->getStringTable();
- this->_link = dynamicStringTable->ordinal();
- if (this->_outputSection) {
- this->_outputSection->setType(this->_type);
- this->_outputSection->setInfo(this->_info);
- this->_outputSection->setLink(this->_link);
- }
- }
+ void finalize() override;
void setSymbolTable(DynamicSymbolTable<ELFT> *dynsym) {
_dynamicSymbolTable = dynsym;
@@ -1207,42 +486,7 @@ public:
void setHashTable(HashSection<ELFT> *hsh) { _hashTable = hsh; }
- virtual void updateDynamicTable() {
- StringTable<ELFT> *dynamicStringTable =
- _dynamicSymbolTable->getStringTable();
- _entries[_dt_hash].d_un.d_val = _hashTable->virtualAddr();
- _entries[_dt_strtab].d_un.d_val = dynamicStringTable->virtualAddr();
- _entries[_dt_symtab].d_un.d_val = _dynamicSymbolTable->virtualAddr();
- _entries[_dt_strsz].d_un.d_val = dynamicStringTable->memSize();
- _entries[_dt_syment].d_un.d_val = _dynamicSymbolTable->getEntSize();
- auto initArray = _layout.findOutputSection(".init_array");
- if (initArray) {
- _entries[_dt_init_array].d_un.d_val = initArray->virtualAddr();
- _entries[_dt_init_arraysz].d_un.d_val = initArray->memSize();
- }
- auto finiArray = _layout.findOutputSection(".fini_array");
- if (finiArray) {
- _entries[_dt_fini_array].d_un.d_val = finiArray->virtualAddr();
- _entries[_dt_fini_arraysz].d_un.d_val = finiArray->memSize();
- }
- if (const auto *al = getInitAtomLayout())
- _entries[_dt_init].d_un.d_val = getAtomVirtualAddress(al);
- if (const auto *al = getFiniAtomLayout())
- _entries[_dt_fini].d_un.d_val = getAtomVirtualAddress(al);
- if (_layout.hasDynamicRelocationTable()) {
- auto relaTbl = _layout.getDynamicRelocationTable();
- _entries[_dt_rela].d_un.d_val = relaTbl->virtualAddr();
- _entries[_dt_relasz].d_un.d_val = relaTbl->memSize();
- _entries[_dt_relaent].d_un.d_val = relaTbl->getEntSize();
- }
- if (_layout.hasPLTRelocationTable()) {
- auto relaTbl = _layout.getPLTRelocationTable();
- _entries[_dt_jmprel].d_un.d_val = relaTbl->virtualAddr();
- _entries[_dt_pltrelsz].d_un.d_val = relaTbl->memSize();
- auto gotplt = _layout.findOutputSection(".got.plt");
- _entries[_dt_pltgot].d_un.d_val = gotplt->virtualAddr();
- }
- }
+ virtual void updateDynamicTable();
protected:
EntriesT _entries;
@@ -1279,41 +523,18 @@ private:
DynamicSymbolTable<ELFT> *_dynamicSymbolTable;
HashSection<ELFT> *_hashTable;
- const AtomLayout *getInitAtomLayout() {
- auto al = _layout.findAtomLayoutByName(this->_context.initFunction());
- if (al && isa<DefinedAtom>(al->_atom))
- return al;
- return nullptr;
- }
+ const AtomLayout *getInitAtomLayout();
- const AtomLayout *getFiniAtomLayout() {
- auto al = _layout.findAtomLayoutByName(this->_context.finiFunction());
- if (al && isa<DefinedAtom>(al->_atom))
- return al;
- return nullptr;
- }
+ const AtomLayout *getFiniAtomLayout();
};
template <class ELFT> class InterpSection : public Section<ELFT> {
public:
- InterpSection(const ELFLinkingContext &context, StringRef str, int32_t order,
- StringRef interp)
- : Section<ELFT>(context, str, "Dynamic:Interp"), _interp(interp) {
- this->setOrder(order);
- this->_alignment = 1;
- // + 1 for null term.
- this->_fsize = interp.size() + 1;
- this->_msize = this->_fsize;
- this->_type = SHT_PROGBITS;
- this->_flags = SHF_ALLOC;
- }
+ InterpSection(const ELFLinkingContext &ctx, StringRef str, int32_t order,
+ StringRef interp);
void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
- llvm::FileOutputBuffer &buffer) {
- uint8_t *chunkBuffer = buffer.getBufferStart();
- uint8_t *dest = chunkBuffer + this->fileOffset();
- std::memcpy(dest, _interp.data(), _interp.size());
- }
+ llvm::FileOutputBuffer &buffer) override;
private:
StringRef _interp;
@@ -1338,7 +559,6 @@ private:
/// * 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;
@@ -1346,153 +566,51 @@ template <class ELFT> class HashSection : public Section<ELFT> {
};
public:
- HashSection(const ELFLinkingContext &context, StringRef name, int32_t order)
- : Section<ELFT>(context, name, "Dynamic:Hash"), _symbolTable(nullptr) {
- this->setOrder(order);
- this->_entSize = 4;
- this->_type = SHT_HASH;
- this->_flags = SHF_ALLOC;
- this->_alignment = ELFT::Is64Bits ? 8 : 4;
- this->_fsize = 0;
- this->_msize = 0;
- }
+ 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) {
- SymbolTableEntry ste;
- ste._name = name;
- ste._index = index;
- _entries.push_back(ste);
- }
+ void addSymbol(StringRef name, uint32_t index);
/// \brief Set the dynamic symbol table
- void setSymbolTable(const DynamicSymbolTable<ELFT> *symbolTable) {
- _symbolTable = symbolTable;
- }
+ 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 {
- // 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;
- }
+ void doPreFlight() override;
- this->_fsize = (2 + _chains.size() + _buckets.size()) * sizeof(uint32_t);
- this->_msize = this->_fsize;
- }
-
- void finalize() override {
- this->_link = _symbolTable ? _symbolTable->ordinal() : 0;
- if (this->_outputSection)
- this->_outputSection->setLink(this->_link);
- }
+ void finalize() override;
void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
- llvm::FileOutputBuffer &buffer) override {
- uint8_t *chunkBuffer = buffer.getBufferStart();
- uint8_t *dest = chunkBuffer + this->fileOffset();
- uint32_t bucketChainCounts[2];
- bucketChainCounts[0] = _buckets.size();
- bucketChainCounts[1] = _chains.size();
- std::memcpy(dest, (char *)bucketChainCounts, sizeof(bucketChainCounts));
- dest += sizeof(bucketChainCounts);
- // write bucket values
- for (auto bi : _buckets) {
- uint32_t val = (bi);
- std::memcpy(dest, &val, sizeof(uint32_t));
- dest += sizeof(uint32_t);
- }
- // write chain values
- for (auto ci : _chains) {
- uint32_t val = (ci);
- std::memcpy(dest, &val, sizeof(uint32_t));
- dest += sizeof(uint32_t);
- }
- }
+ llvm::FileOutputBuffer &buffer) override;
private:
+ typedef
+ typename llvm::object::ELFDataTypeTypedefHelper<ELFT>::Elf_Word Elf_Word;
+
std::vector<SymbolTableEntry> _entries;
- std::vector<uint32_t> _buckets;
- std::vector<uint32_t> _chains;
- const DynamicSymbolTable<ELFT> *_symbolTable;
+ 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 &context, StringRef name,
- TargetLayout<ELFT> &layout, int32_t order)
- : Section<ELFT>(context, name, "EHFrameHeader"), _ehFrameOffset(0),
- _layout(layout) {
- this->setOrder(order);
- this->_entSize = 0;
- this->_type = SHT_PROGBITS;
- this->_flags = SHF_ALLOC;
- this->_alignment = ELFT::Is64Bits ? 8 : 4;
- // Minimum size for empty .eh_frame_hdr.
- this->_fsize = 1 + 1 + 1 + 1 + 4;
- this->_msize = this->_fsize;
- }
-
- void doPreFlight() override {
- // TODO: Generate a proper binary search table.
- }
-
- void finalize() override {
- OutputSection<ELFT> *s = _layout.findOutputSection(".eh_frame");
- OutputSection<ELFT> *h = _layout.findOutputSection(".eh_frame_hdr");
- if (s && h)
- _ehFrameOffset = s->virtualAddr() - (h->virtualAddr() + 4);
- }
-
+ 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 {
- 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;
- }
+ llvm::FileOutputBuffer &buffer) override;
private:
- int32_t _ehFrameOffset;
+ int32_t _ehFrameOffset = 0;
TargetLayout<ELFT> &_layout;
};
+
} // end namespace elf
} // end namespace lld
-#endif
+#endif // LLD_READER_WRITER_ELF_SECTION_CHUNKS_H
diff --git a/lib/ReaderWriter/ELF/SegmentChunks.cpp b/lib/ReaderWriter/ELF/SegmentChunks.cpp
new file mode 100644
index 000000000000..99449f7d45aa
--- /dev/null
+++ b/lib/ReaderWriter/ELF/SegmentChunks.cpp
@@ -0,0 +1,519 @@
+//===- 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
index f2a975aaeed0..b444f44c04eb 100644
--- a/lib/ReaderWriter/ELF/SegmentChunks.h
+++ b/lib/ReaderWriter/ELF/SegmentChunks.h
@@ -11,16 +11,13 @@
#define LLD_READER_WRITER_ELF_SEGMENT_CHUNKS_H
#include "Chunk.h"
-#include "Layout.h"
#include "SectionChunks.h"
#include "Writer.h"
#include "lld/Core/range.h"
#include "lld/Core/Writer.h"
-#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Object/ELF.h"
#include "llvm/Support/Allocator.h"
-#include "llvm/Support/Debug.h"
#include "llvm/Support/ELF.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileOutputBuffer.h"
@@ -29,7 +26,7 @@
namespace lld {
namespace elf {
-template <typename ELFT> class DefaultLayout;
+template <typename ELFT> class TargetLayout;
/// \brief A segment can be divided into segment slices
/// depending on how the segments can be split
@@ -38,8 +35,6 @@ class SegmentSlice {
public:
typedef typename std::vector<Chunk<ELFT> *>::iterator SectionIter;
- SegmentSlice() { }
-
/// Set the start of the slice.
void setStart(int32_t s) { _startSection = s; }
@@ -49,12 +44,10 @@ public:
// 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
@@ -75,9 +68,7 @@ public:
void setAlign(uint64_t align) { _alignment = align; }
- static bool compare_slices(SegmentSlice<ELFT> *a, SegmentSlice<ELFT> *b) {
- return a->startSection() < b->startSection();
- }
+ static bool compare_slices(SegmentSlice<ELFT> *a, SegmentSlice<ELFT> *b);
range<SectionIter> sections() { return _sections; }
@@ -100,8 +91,8 @@ public:
typedef typename std::vector<SegmentSlice<ELFT> *>::iterator SliceIter;
typedef typename std::vector<Chunk<ELFT> *>::iterator SectionIter;
- Segment(const ELFLinkingContext &context, StringRef name,
- const Layout::SegmentType type);
+ 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 {
@@ -144,37 +135,21 @@ public:
// Write the Segment
void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
- llvm::FileOutputBuffer &buffer);
+ 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 assigning File Offsets / Virtual addresses
- void doPreFlight() {}
-
/// Finalize the segment, before we want to write the segment header
/// information
- void finalize() {
- // We want to finalize the segment values for now only for non loadable
- // segments, since those values are not set in the Layout
- if (_segmentType == llvm::ELF::PT_LOAD)
- return;
- // The size is the difference of the
- // last section to the first section, especially for TLS because
- // the TLS segment contains both .tdata/.tbss
- this->setFileOffset(_sections.front()->fileOffset());
- this->setVirtualAddr(_sections.front()->virtualAddr());
- size_t startFileOffset = _sections.front()->fileOffset();
- size_t startAddr = _sections.front()->virtualAddr();
- for (auto ai : _sections) {
- this->_fsize = ai->fileOffset() + ai->fileSize() - startFileOffset;
- this->_msize = ai->virtualAddr() + ai->memSize() - startAddr;
- }
- }
+ void finalize() override;
// For LLVM RTTI
static bool classof(const Chunk<ELFT> *c) {
@@ -185,76 +160,26 @@ public:
int32_t sectionCount() const { return _sections.size(); }
/// \brief, this function returns the type of segment (PT_*)
- Layout::SegmentType segmentType() { return _segmentType; }
+ 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
- virtual int getContentType() const {
- int64_t fl = flags();
- switch (_segmentType) {
- case llvm::ELF::PT_LOAD: {
- if (fl && llvm::ELF::PF_X)
- return Chunk<ELFT>::ContentType::Code;
- if (fl && llvm::ELF::PF_W)
- return Chunk<ELFT>::ContentType::Data;
- }
- case llvm::ELF::PT_TLS:
- return Chunk<ELFT>::ContentType::TLS;
- case llvm::ELF::PT_NOTE:
- return Chunk<ELFT>::ContentType::Note;
- default:
- return Chunk<ELFT>::ContentType::Unknown;
- }
- }
-
- int pageSize() const { return this->_context.getPageSize(); }
+ int getContentType() const override;
+ int pageSize() const { return this->_ctx.getPageSize(); }
int rawflags() const { return _atomflags; }
-
- int64_t atomflags() const {
- switch (_atomflags) {
-
- case DefinedAtom::permUnknown:
- return permUnknown;
-
- case DefinedAtom::permRWX:
- return permRWX;
-
- case DefinedAtom::permR_X:
- return permRX;
-
- case DefinedAtom::permR__:
- return permR;
-
- case DefinedAtom::permRW_L:
- return permRWL;
-
- case DefinedAtom::permRW_:
- return permRW;
-
- case DefinedAtom::perm___:
- default:
- return permNonAccess;
- }
- }
-
+ int64_t 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 {
- if (chunk->getContentType() == Chunk<ELFT>::ContentType::Data &&
- _outputMagic == ELFLinkingContext::OutputMagic::NMAGIC)
- return true;
- return false;
- }
+ bool needAlign(Chunk<ELFT> *chunk) const;
// Cached value of outputMagic
ELFLinkingContext::OutputMagic _outputMagic;
@@ -263,9 +188,10 @@ protected:
/// \brief Section or some other chunk type.
std::vector<Chunk<ELFT> *> _sections;
std::vector<SegmentSlice<ELFT> *> _segmentSlices;
- Layout::SegmentType _segmentType;
+ typename TargetLayout<ELFT>::SegmentType _segmentType;
uint64_t _flags;
int64_t _atomflags;
+ bool _segmentFlags;
llvm::BumpPtrAllocator _segmentAllocate;
};
@@ -286,10 +212,9 @@ public:
int getContentType() const override {
return Chunk<ELFT>::ContentType::Unknown;
}
+
void write(ELFWriter *, TargetLayout<ELFT> &,
llvm::FileOutputBuffer &) override {}
- void doPreFlight() override {}
- void finalize() override {}
std::error_code evalExpr(uint64_t &curPos) {
return _linkerScriptSema.evalExpr(_expr, curPos);
@@ -304,383 +229,18 @@ private:
/// The segment doesn't contain any slice
template <class ELFT> class ProgramHeaderSegment : public Segment<ELFT> {
public:
- ProgramHeaderSegment(const ELFLinkingContext &context)
- : Segment<ELFT>(context, "PHDR", llvm::ELF::PT_PHDR) {
+ 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() {
- // 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();
- }
-
+ void finalize() override;
};
-template <class ELFT>
-Segment<ELFT>::Segment(const ELFLinkingContext &context, StringRef name,
- const Layout::SegmentType type)
- : Chunk<ELFT>(name, Chunk<ELFT>::Kind::ELFSegment, context),
- _segmentType(type), _flags(0), _atomflags(0) {
- this->_alignment = 0;
- this->_fsize = 0;
- _outputMagic = context.getOutputMagic();
-}
-
-// This function actually is used, but not in all instantiations of Segment.
-LLVM_ATTRIBUTE_UNUSED
-static DefinedAtom::ContentPermissions toAtomPerms(uint64_t flags) {
- switch (flags & (SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR)) {
- case SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR:
- return DefinedAtom::permRWX;
- case SHF_ALLOC | SHF_EXECINSTR:
- return DefinedAtom::permR_X;
- case SHF_ALLOC:
- return DefinedAtom::permR__;
- case SHF_ALLOC | SHF_WRITE:
- return DefinedAtom::permRW_;
- default:
- return DefinedAtom::permUnknown;
- }
-}
-
-template <class ELFT> void Segment<ELFT>::append(Chunk<ELFT> *chunk) {
- _sections.push_back(chunk);
- Section<ELFT> *section = dyn_cast<Section<ELFT>>(chunk);
- if (!section)
- return;
- if (_flags < section->getFlags())
- _flags |= section->getFlags();
- if (_atomflags < toAtomPerms(_flags))
- _atomflags = toAtomPerms(_flags);
- if (this->_alignment < section->alignment())
- this->_alignment = section->alignment();
-}
-
-template <class ELFT>
-bool Segment<ELFT>::compareSegments(Segment<ELFT> *sega, Segment<ELFT> *segb) {
- int64_t type1 = sega->segmentType();
- int64_t type2 = segb->segmentType();
-
- if (type1 == type2)
- return sega->atomflags() < segb->atomflags();
-
- // The single PT_PHDR segment is required to precede any loadable
- // segment. We simply make it always first.
- if (type1 == llvm::ELF::PT_PHDR)
- return true;
- if (type2 == llvm::ELF::PT_PHDR)
- return false;
-
- // The single PT_INTERP segment is required to precede any loadable
- // segment. We simply make it always second.
- if (type1 == llvm::ELF::PT_INTERP)
- return true;
- if (type2 == llvm::ELF::PT_INTERP)
- return false;
-
- // We then put PT_LOAD segments before any other segments.
- if (type1 == llvm::ELF::PT_LOAD)
- return true;
- if (type2 == llvm::ELF::PT_LOAD)
- return false;
-
- // We put the PT_GNU_RELRO segment last, because that is where the
- // dynamic linker expects to find it
- if (type1 == llvm::ELF::PT_GNU_RELRO)
- return false;
- if (type2 == llvm::ELF::PT_GNU_RELRO)
- return true;
-
- // We put the PT_TLS segment last except for the PT_GNU_RELRO
- // segment, because that is where the dynamic linker expects to find
- if (type1 == llvm::ELF::PT_TLS)
- return false;
- if (type2 == llvm::ELF::PT_TLS)
- return true;
-
- // Otherwise compare the types to establish an arbitrary ordering.
- // FIXME: Should figure out if we should just make all other types compare
- // equal, but if so, we should probably do the same for atom flags and change
- // users of this to use stable_sort.
- return type1 < type2;
-}
-
-template <class ELFT>
-void Segment<ELFT>::assignFileOffsets(uint64_t startOffset) {
- uint64_t fileOffset = startOffset;
- uint64_t curSliceFileOffset = fileOffset;
- bool isDataPageAlignedForNMagic = false;
- bool alignSegments = this->_context.alignSegments();
- uint64_t p_align = this->_context.getPageSize();
- uint64_t lastVirtualAddress = 0;
-
- this->setFileOffset(startOffset);
- for (auto &slice : slices()) {
- bool isFirstSection = true;
- for (auto section : slice->sections()) {
- // Handle linker script expressions, which may change the offset
- if (!isFirstSection)
- if (auto expr = dyn_cast<ExpressionChunk<ELFT>>(section))
- fileOffset += expr->virtualAddr() - lastVirtualAddress;
- // Align fileoffset to the alignment of the section.
- fileOffset = llvm::RoundUpToAlignment(fileOffset, section->alignment());
- // If the linker outputmagic is set to OutputMagic::NMAGIC, align the Data
- // to a page boundary
- if (isFirstSection &&
- _outputMagic != ELFLinkingContext::OutputMagic::NMAGIC &&
- _outputMagic != ELFLinkingContext::OutputMagic::OMAGIC) {
- // Align to a page only if the output is not
- // OutputMagic::NMAGIC/OutputMagic::OMAGIC
- if (alignSegments)
- fileOffset = llvm::RoundUpToAlignment(fileOffset, p_align);
- else {
- // Align according to ELF spec.
- // in p75, http://www.sco.com/developers/devspecs/gabi41.pdf
- uint64_t virtualAddress = slice->virtualAddr();
- Section<ELFT> *sect = dyn_cast<Section<ELFT>>(section);
- if (sect && sect->isLoadableSection() &&
- ((virtualAddress & (p_align - 1)) !=
- (fileOffset & (p_align - 1))))
- fileOffset = llvm::RoundUpToAlignment(fileOffset, p_align) +
- (virtualAddress % p_align);
- }
- } else if (!isDataPageAlignedForNMagic && needAlign(section)) {
- fileOffset =
- llvm::RoundUpToAlignment(fileOffset, this->_context.getPageSize());
- isDataPageAlignedForNMagic = true;
- }
- if (isFirstSection) {
- slice->setFileOffset(fileOffset);
- isFirstSection = false;
- curSliceFileOffset = fileOffset;
- }
- section->setFileOffset(fileOffset);
- fileOffset += section->fileSize();
- lastVirtualAddress = section->virtualAddr() + section->memSize();
- }
- slice->setFileSize(fileOffset - curSliceFileOffset);
- }
- this->setFileSize(fileOffset - startOffset);
-}
-
-/// \brief Assign virtual addresses to the slices
-template <class ELFT> void Segment<ELFT>::assignVirtualAddress(uint64_t addr) {
- int startSection = 0;
- int currSection = 0;
- SectionIter startSectionIter;
-
- // slice align is set to the max alignment of the chunks that are
- // contained in the slice
- uint64_t sliceAlign = 0;
- // Current slice size
- uint64_t curSliceSize = 0;
- // Current Slice File Offset
- uint64_t curSliceAddress = 0;
-
- startSectionIter = _sections.begin();
- startSection = 0;
- bool isFirstSection = true;
- bool isDataPageAlignedForNMagic = false;
- uint64_t startAddr = addr;
- SegmentSlice<ELFT> *slice = nullptr;
- uint64_t tlsStartAddr = 0;
- bool alignSegments = this->_context.alignSegments();
- StringRef prevOutputSectionName = StringRef();
-
- for (auto si = _sections.begin(); si != _sections.end(); ++si) {
- // If this is first section in the segment, page align the section start
- // address. The linker needs to align the data section to a page boundary
- // only if NMAGIC is set.
- if (isFirstSection) {
- isFirstSection = false;
- if (alignSegments &&
- _outputMagic != ELFLinkingContext::OutputMagic::NMAGIC &&
- _outputMagic != ELFLinkingContext::OutputMagic::OMAGIC)
- // Align to a page only if the output is not
- // OutputMagic::NMAGIC/OutputMagic::OMAGIC
- startAddr =
- llvm::RoundUpToAlignment(startAddr, this->_context.getPageSize());
- else if (!isDataPageAlignedForNMagic && needAlign(*si)) {
- // If the linker outputmagic is set to OutputMagic::NMAGIC, align the
- // Data to a page boundary.
- startAddr =
- llvm::RoundUpToAlignment(startAddr, this->_context.getPageSize());
- isDataPageAlignedForNMagic = true;
- }
- // align the startOffset to the section alignment
- uint64_t newAddr = llvm::RoundUpToAlignment(startAddr, (*si)->alignment());
- // Handle linker script expressions, which *may update newAddr* if the
- // expression assigns to "."
- if (auto expr = dyn_cast<ExpressionChunk<ELFT>>(*si))
- expr->evalExpr(newAddr);
- curSliceAddress = newAddr;
- sliceAlign = (*si)->alignment();
- (*si)->setVirtualAddr(curSliceAddress);
-
- // Handle TLS.
- if (auto section = dyn_cast<Section<ELFT>>(*si)) {
- if (section->getSegmentType() == llvm::ELF::PT_TLS) {
- tlsStartAddr =
- llvm::RoundUpToAlignment(tlsStartAddr, (*si)->alignment());
- section->assignVirtualAddress(tlsStartAddr);
- tlsStartAddr += (*si)->memSize();
- } else {
- section->assignVirtualAddress(newAddr);
- }
- }
- // TBSS section is special in that it doesn't contribute to memory of any
- // segment. If we see a tbss section, don't add memory size to addr The
- // fileOffset is automatically taken care of since TBSS section does not
- // end up using file size
- if ((*si)->order() != DefaultLayout<ELFT>::ORDER_TBSS)
- curSliceSize = (*si)->memSize();
- } else {
- uint64_t curAddr = curSliceAddress + curSliceSize;
- if (!isDataPageAlignedForNMagic && needAlign(*si)) {
- // If the linker outputmagic is set to OutputMagic::NMAGIC, align the
- // Data
- // to a page boundary
- curAddr =
- llvm::RoundUpToAlignment(curAddr, this->_context.getPageSize());
- isDataPageAlignedForNMagic = true;
- }
- uint64_t newAddr = llvm::RoundUpToAlignment(curAddr, (*si)->alignment());
- // Handle linker script expressions, which *may update newAddr* if the
- // expression assigns to "."
- if (auto expr = dyn_cast<ExpressionChunk<ELFT>>(*si))
- expr->evalExpr(newAddr);
- Section<ELFT> *sec = dyn_cast<Section<ELFT>>(*si);
- StringRef curOutputSectionName;
- if (sec)
- curOutputSectionName = sec->outputSectionName();
- else {
- // If this is a linker script expression, propagate the name of the
- // previous section instead
- if (isa<ExpressionChunk<ELFT>>(*si))
- curOutputSectionName = prevOutputSectionName;
- else
- curOutputSectionName = (*si)->name();
- }
- bool autoCreateSlice = true;
- if (curOutputSectionName == prevOutputSectionName)
- autoCreateSlice = false;
- // If the newAddress computed is more than a page away, let's create
- // a separate segment, so that memory is not used up while running.
- // Dont create a slice, if the new section falls in the same output
- // section as the previous section.
- if (autoCreateSlice &&
- ((newAddr - curAddr) > this->_context.getPageSize()) &&
- (_outputMagic != ELFLinkingContext::OutputMagic::NMAGIC &&
- _outputMagic != ELFLinkingContext::OutputMagic::OMAGIC)) {
- auto sliceIter =
- std::find_if(_segmentSlices.begin(), _segmentSlices.end(),
- [startSection](SegmentSlice<ELFT> *s) -> bool {
- return s->startSection() == startSection;
- });
- if (sliceIter == _segmentSlices.end()) {
- slice = new (_segmentAllocate.Allocate<SegmentSlice<ELFT>>())
- SegmentSlice<ELFT>();
- _segmentSlices.push_back(slice);
- } else {
- slice = (*sliceIter);
- }
- slice->setStart(startSection);
- slice->setSections(make_range(startSectionIter, si));
- slice->setMemSize(curSliceSize);
- slice->setAlign(sliceAlign);
- slice->setVirtualAddr(curSliceAddress);
- // Start new slice
- curSliceAddress = newAddr;
- (*si)->setVirtualAddr(curSliceAddress);
- startSectionIter = si;
- startSection = currSection;
- if (auto section = dyn_cast<Section<ELFT>>(*si))
- section->assignVirtualAddress(newAddr);
- curSliceSize = newAddr - curSliceAddress + (*si)->memSize();
- sliceAlign = (*si)->alignment();
- } else {
- if (sliceAlign < (*si)->alignment())
- sliceAlign = (*si)->alignment();
- (*si)->setVirtualAddr(newAddr);
- // Handle TLS.
- if (auto section = dyn_cast<Section<ELFT>>(*si)) {
- if (section->getSegmentType() == llvm::ELF::PT_TLS) {
- tlsStartAddr =
- llvm::RoundUpToAlignment(tlsStartAddr, (*si)->alignment());
- section->assignVirtualAddress(tlsStartAddr);
- tlsStartAddr += (*si)->memSize();
- } else {
- section->assignVirtualAddress(newAddr);
- }
- }
- // TBSS section is special in that it doesn't contribute to memory of
- // any segment. If we see a tbss section, don't add memory size to addr
- // The fileOffset is automatically taken care of since TBSS section does
- // not end up using file size.
- if ((*si)->order() != DefaultLayout<ELFT>::ORDER_TBSS)
- curSliceSize = newAddr - curSliceAddress + (*si)->memSize();
- else
- curSliceSize = newAddr - curSliceAddress;
- }
- prevOutputSectionName = curOutputSectionName;
- }
- currSection++;
- }
- auto sliceIter = std::find_if(_segmentSlices.begin(), _segmentSlices.end(),
- [startSection](SegmentSlice<ELFT> *s) -> bool {
- return s->startSection() == startSection;
- });
- if (sliceIter == _segmentSlices.end()) {
- slice = new (_segmentAllocate.Allocate<SegmentSlice<ELFT>>())
- SegmentSlice<ELFT>();
- _segmentSlices.push_back(slice);
- } else {
- slice = (*sliceIter);
- }
- slice->setStart(startSection);
- slice->setVirtualAddr(curSliceAddress);
- slice->setMemSize(curSliceSize);
- slice->setSections(make_range(startSectionIter, _sections.end()));
- slice->setAlign(sliceAlign);
-
- // Set the segment memory size and the virtual address.
- this->setMemSize(curSliceAddress - startAddr + curSliceSize);
- this->setVirtualAddr(curSliceAddress);
- std::stable_sort(_segmentSlices.begin(), _segmentSlices.end(),
- SegmentSlice<ELFT>::compare_slices);
-}
-
-// Write the Segment
-template <class ELFT>
-void Segment<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout,
- llvm::FileOutputBuffer &buffer) {
- for (auto slice : slices())
- for (auto section : slice->sections())
- section->write(writer, layout, buffer);
-}
-
-template<class ELFT>
-int64_t
-Segment<ELFT>::flags() const {
- int64_t fl = 0;
- if (_flags & llvm::ELF::SHF_ALLOC)
- fl |= llvm::ELF::PF_R;
- if (_flags & llvm::ELF::SHF_WRITE)
- fl |= llvm::ELF::PF_W;
- if (_flags & llvm::ELF::SHF_EXECINSTR)
- fl |= llvm::ELF::PF_X;
- return fl;
-}
} // end namespace elf
} // end namespace lld
-#endif
+#endif // LLD_READER_WRITER_ELF_SEGMENT_CHUNKS_H
diff --git a/lib/ReaderWriter/ELF/TargetHandler.h b/lib/ReaderWriter/ELF/TargetHandler.h
index ca7a442276d1..406ac670fc83 100644
--- a/lib/ReaderWriter/ELF/TargetHandler.h
+++ b/lib/ReaderWriter/ELF/TargetHandler.h
@@ -6,78 +6,27 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-///
-/// \file
-/// \brief These interfaces provide target specific hooks to change the linker's
-/// behaivor.
-///
-//===----------------------------------------------------------------------===//
#ifndef LLD_READER_WRITER_ELF_TARGET_HANDLER_H
#define LLD_READER_WRITER_ELF_TARGET_HANDLER_H
-#include "Layout.h"
-#include "lld/Core/Atom.h"
-#include "lld/Core/LLVM.h"
-#include "lld/Core/LinkingContext.h"
-#include "lld/Core/STDExtras.h"
-#include "lld/ReaderWriter/ELFLinkingContext.h"
-#include "llvm/ADT/Hashing.h"
-#include "llvm/ADT/StringRef.h"
+#include "lld/Core/Error.h"
+#include "llvm/ADT/Twine.h"
#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/FileOutputBuffer.h"
-#include <memory>
-#include <vector>
namespace lld {
namespace elf {
-template <class ELFT> class DynamicTable;
-template <class ELFT> class DynamicSymbolTable;
-template <class ELFT> class ELFDefinedAtom;
-template <class ELFT> class ELFReference;
-class ELFWriter;
-template <class ELFT> class ELFHeader;
-template <class ELFT> class Section;
-template <class ELFT> class TargetLayout;
-
-class TargetRelocationHandler {
-public:
- /// Constructor
- TargetRelocationHandler() {}
- virtual ~TargetRelocationHandler() {}
-
- virtual std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &,
- const lld::AtomLayout &,
- const Reference &) const = 0;
-};
-
-/// \brief TargetHandler contains all the information responsible to handle a
-/// a particular target on ELF. A target might wish to override implementation
-/// of creating atoms and how the atoms are written to the output file.
-template <class ELFT> class TargetHandler : public TargetHandlerBase {
-public:
- /// The layout determined completely by the Target.
- virtual TargetLayout<ELFT> &getTargetLayout() = 0;
-
- /// Determine how relocations need to be applied.
- virtual const TargetRelocationHandler &getRelocationHandler() const = 0;
-
- /// How does the target deal with reading input files.
- virtual std::unique_ptr<Reader> getObjReader() = 0;
-
- /// How does the target deal with reading dynamic libraries.
- virtual std::unique_ptr<Reader> getDSOReader() = 0;
-
- /// How does the target deal with writing ELF output.
- virtual std::unique_ptr<Writer> getWriter() = 0;
-};
inline std::error_code make_unhandled_reloc_error() {
- return make_dynamic_error_code(Twine("Unhandled reference type"));
+ return make_dynamic_error_code("Unhandled reference type");
}
inline std::error_code make_out_of_range_reloc_error() {
- return make_dynamic_error_code(Twine("Relocation out of range"));
+ 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
diff --git a/lib/ReaderWriter/ELF/TargetLayout.cpp b/lib/ReaderWriter/ELF/TargetLayout.cpp
new file mode 100644
index 000000000000..09c49f62d64f
--- /dev/null
+++ b/lib/ReaderWriter/ELF/TargetLayout.cpp
@@ -0,0 +1,747 @@
+//===- 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
index ab7a7890a274..52512f8e279e 100644
--- a/lib/ReaderWriter/ELF/TargetLayout.h
+++ b/lib/ReaderWriter/ELF/TargetLayout.h
@@ -7,21 +7,320 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLD_READER_WRITER_ELF_TARGET_LAYOUT_H
-#define LLD_READER_WRITER_ELF_TARGET_LAYOUT_H
+#ifndef LLD_READER_WRITER_ELF_DEFAULT_LAYOUT_H
+#define LLD_READER_WRITER_ELF_DEFAULT_LAYOUT_H
-#include "DefaultLayout.h"
-#include "lld/Core/LLVM.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 target can override certain functions in the DefaultLayout
-/// class so that the order, the name of the section and the segment type could
-/// be changed in the final layout
-template <class ELFT> class TargetLayout : public DefaultLayout<ELFT> {
+
+/// \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:
- TargetLayout(ELFLinkingContext &context) : DefaultLayout<ELFT>(context) {}
+
+ // 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
diff --git a/lib/ReaderWriter/ELF/Writer.cpp b/lib/ReaderWriter/ELF/Writer.cpp
index 3071827e07d0..1c5d9766e9c5 100644
--- a/lib/ReaderWriter/ELF/Writer.cpp
+++ b/lib/ReaderWriter/ELF/Writer.cpp
@@ -16,8 +16,8 @@ using namespace llvm::object;
namespace lld {
-std::unique_ptr<Writer> createWriterELF(TargetHandlerBase *handler) {
- return std::move(handler->getWriter());
+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
index 1e819467c558..8b3e8f90638a 100644
--- a/lib/ReaderWriter/ELF/Writer.h
+++ b/lib/ReaderWriter/ELF/Writer.h
@@ -19,15 +19,12 @@ namespace elf {
/// various kinds of ELF files.
class ELFWriter : public Writer {
public:
- ELFWriter() { }
-
-public:
/// \brief builds the chunks that needs to be written to the output
/// ELF file
virtual void buildChunks(const File &file) = 0;
/// \brief Writes the chunks into the output file specified by path
- virtual std::error_code writeFile(const File &file, StringRef path) = 0;
+ 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;
@@ -35,4 +32,4 @@ public:
} // end namespace elf
} // end namespace lld
-#endif
+#endif // LLD_READER_WRITER_ELF_WRITER_H
diff --git a/lib/ReaderWriter/ELF/X86/Makefile b/lib/ReaderWriter/ELF/X86/Makefile
deleted file mode 100644
index 058d5133eaba..000000000000
--- a/lib/ReaderWriter/ELF/X86/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-##===- lld/lib/ReaderWriter/ELF/X86/Makefile ----------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LLD_LEVEL := ../../../..
-LIBRARYNAME := lldX86ELFTarget
-USEDLIBS = lldCore.a
-CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF
-
-include $(LLD_LEVEL)/Makefile
diff --git a/lib/ReaderWriter/ELF/X86/X86DynamicLibraryWriter.h b/lib/ReaderWriter/ELF/X86/X86DynamicLibraryWriter.h
index 86376295bec4..dd2184d7201e 100644
--- a/lib/ReaderWriter/ELF/X86/X86DynamicLibraryWriter.h
+++ b/lib/ReaderWriter/ELF/X86/X86DynamicLibraryWriter.h
@@ -15,50 +15,27 @@
namespace lld {
namespace elf {
-template <class ELFT>
-class X86DynamicLibraryWriter : public DynamicLibraryWriter<ELFT> {
+class X86DynamicLibraryWriter : public DynamicLibraryWriter<ELF32LE> {
public:
- X86DynamicLibraryWriter(X86LinkingContext &context,
- X86TargetLayout<ELFT> &layout);
+ X86DynamicLibraryWriter(X86LinkingContext &ctx,
+ TargetLayout<ELF32LE> &layout);
protected:
// Add any runtime files and their atoms to the output
- virtual bool createImplicitFiles(std::vector<std::unique_ptr<File>> &);
-
- virtual void finalizeDefaultAtomValues() {
- return DynamicLibraryWriter<ELFT>::finalizeDefaultAtomValues();
- }
-
- virtual void addDefaultAtoms() {
- return DynamicLibraryWriter<ELFT>::addDefaultAtoms();
- }
-
-private:
- class GOTFile : public SimpleFile {
- public:
- GOTFile(const ELFLinkingContext &eti) : SimpleFile("GOTFile") {}
- llvm::BumpPtrAllocator _alloc;
- };
-
- std::unique_ptr<GOTFile> _gotFile;
- X86LinkingContext &_context;
- X86TargetLayout<ELFT> &_x86Layout;
+ void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
};
-template <class ELFT>
-X86DynamicLibraryWriter<ELFT>::X86DynamicLibraryWriter(
- X86LinkingContext &context, X86TargetLayout<ELFT> &layout)
- : DynamicLibraryWriter<ELFT>(context, layout),
- _gotFile(new GOTFile(context)), _context(context), _x86Layout(layout) {}
+X86DynamicLibraryWriter::X86DynamicLibraryWriter(X86LinkingContext &ctx,
+ TargetLayout<ELF32LE> &layout)
+ : DynamicLibraryWriter(ctx, layout) {}
-template <class ELFT>
-bool X86DynamicLibraryWriter<ELFT>::createImplicitFiles(
+void X86DynamicLibraryWriter::createImplicitFiles(
std::vector<std::unique_ptr<File>> &result) {
- DynamicLibraryWriter<ELFT>::createImplicitFiles(result);
- _gotFile->addAtom(*new (_gotFile->_alloc) GLOBAL_OFFSET_TABLEAtom(*_gotFile));
- _gotFile->addAtom(*new (_gotFile->_alloc) DYNAMICAtom(*_gotFile));
- result.push_back(std::move(_gotFile));
- return true;
+ 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
diff --git a/lib/ReaderWriter/ELF/X86/X86ELFFile.h b/lib/ReaderWriter/ELF/X86/X86ELFFile.h
deleted file mode 100644
index 621c38c43505..000000000000
--- a/lib/ReaderWriter/ELF/X86/X86ELFFile.h
+++ /dev/null
@@ -1,41 +0,0 @@
-//===- lib/ReaderWriter/ELF/X86/X86ELFFile.h ------------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_ELF_X86_X86_ELF_FILE_H
-#define LLD_READER_WRITER_ELF_X86_X86_ELF_FILE_H
-
-#include "ELFReader.h"
-
-namespace lld {
-namespace elf {
-
-class X86LinkingContext;
-
-template <class ELFT> class X86ELFFile : public ELFFile<ELFT> {
-public:
- X86ELFFile(std::unique_ptr<MemoryBuffer> mb, X86LinkingContext &ctx)
- : ELFFile<ELFT>(std::move(mb), ctx) {}
-
- static ErrorOr<std::unique_ptr<X86ELFFile>>
- create(std::unique_ptr<MemoryBuffer> mb, X86LinkingContext &ctx) {
- return std::unique_ptr<X86ELFFile<ELFT>>(
- new X86ELFFile<ELFT>(std::move(mb), ctx));
- }
-};
-
-template <class ELFT> class X86DynamicFile : public DynamicFile<ELFT> {
-public:
- X86DynamicFile(const X86LinkingContext &context, StringRef name)
- : DynamicFile<ELFT>(context, name) {}
-};
-
-} // elf
-} // lld
-
-#endif // LLD_READER_WRITER_ELF_X86_X86_ELF_FILE_H
diff --git a/lib/ReaderWriter/ELF/X86/X86ELFReader.h b/lib/ReaderWriter/ELF/X86/X86ELFReader.h
deleted file mode 100644
index 96186c5eb024..000000000000
--- a/lib/ReaderWriter/ELF/X86/X86ELFReader.h
+++ /dev/null
@@ -1,62 +0,0 @@
-//===- lib/ReaderWriter/ELF/X86/X86ELFReader.h ----------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_X86_X86_ELF_READER_H
-#define LLD_READER_WRITER_X86_X86_ELF_READER_H
-
-#include "ELFReader.h"
-#include "X86ELFFile.h"
-
-namespace lld {
-namespace elf {
-
-typedef llvm::object::ELFType<llvm::support::little, 2, false> X86ELFType;
-
-struct X86DynamicFileCreateELFTraits {
- typedef llvm::ErrorOr<std::unique_ptr<lld::SharedLibraryFile>> result_type;
-
- template <class ELFT>
- static result_type create(std::unique_ptr<llvm::MemoryBuffer> mb,
- X86LinkingContext &ctx) {
- return lld::elf::X86DynamicFile<ELFT>::create(std::move(mb), ctx);
- }
-};
-
-struct X86ELFFileCreateELFTraits {
- typedef llvm::ErrorOr<std::unique_ptr<lld::File>> result_type;
-
- template <class ELFT>
- static result_type create(std::unique_ptr<llvm::MemoryBuffer> mb,
- X86LinkingContext &ctx) {
- return lld::elf::X86ELFFile<ELFT>::create(std::move(mb), ctx);
- }
-};
-
-class X86ELFObjectReader
- : public ELFObjectReader<X86ELFType, X86ELFFileCreateELFTraits,
- X86LinkingContext> {
-public:
- X86ELFObjectReader(X86LinkingContext &ctx)
- : ELFObjectReader<X86ELFType, X86ELFFileCreateELFTraits,
- X86LinkingContext>(ctx, llvm::ELF::EM_386) {}
-};
-
-class X86ELFDSOReader
- : public ELFDSOReader<X86ELFType, X86DynamicFileCreateELFTraits,
- X86LinkingContext> {
-public:
- X86ELFDSOReader(X86LinkingContext &ctx)
- : ELFDSOReader<X86ELFType, X86DynamicFileCreateELFTraits,
- X86LinkingContext>(ctx, llvm::ELF::EM_386) {}
-};
-
-} // namespace elf
-} // namespace lld
-
-#endif // LLD_READER_WRITER_X86_X86_ELF_READER_H
diff --git a/lib/ReaderWriter/ELF/X86/X86ExecutableWriter.h b/lib/ReaderWriter/ELF/X86/X86ExecutableWriter.h
index 68acc06c2261..70aabde3ad2c 100644
--- a/lib/ReaderWriter/ELF/X86/X86ExecutableWriter.h
+++ b/lib/ReaderWriter/ELF/X86/X86ExecutableWriter.h
@@ -15,40 +15,22 @@
namespace lld {
namespace elf {
-template <class ELFT>
-class X86ExecutableWriter : public ExecutableWriter<ELFT> {
+class X86ExecutableWriter : public ExecutableWriter<ELF32LE> {
public:
- X86ExecutableWriter(X86LinkingContext &context,
- X86TargetLayout<ELFT> &layout);
+ X86ExecutableWriter(X86LinkingContext &ctx, TargetLayout<ELF32LE> &layout);
protected:
// Add any runtime files and their atoms to the output
- virtual bool createImplicitFiles(std::vector<std::unique_ptr<File>> &);
-
- virtual void finalizeDefaultAtomValues() {
- return ExecutableWriter<ELFT>::finalizeDefaultAtomValues();
- }
-
- virtual void addDefaultAtoms() {
- return ExecutableWriter<ELFT>::addDefaultAtoms();
- }
-
-private:
- X86LinkingContext &_context;
- X86TargetLayout<ELFT> &_x86Layout;
+ void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
};
-template <class ELFT>
-X86ExecutableWriter<ELFT>::X86ExecutableWriter(X86LinkingContext &context,
- X86TargetLayout<ELFT> &layout)
- : ExecutableWriter<ELFT>(context, layout), _context(context),
- _x86Layout(layout) {}
+X86ExecutableWriter::X86ExecutableWriter(X86LinkingContext &ctx,
+ TargetLayout<ELF32LE> &layout)
+ : ExecutableWriter(ctx, layout) {}
-template <class ELFT>
-bool X86ExecutableWriter<ELFT>::createImplicitFiles(
+void X86ExecutableWriter::createImplicitFiles(
std::vector<std::unique_ptr<File>> &result) {
- ExecutableWriter<ELFT>::createImplicitFiles(result);
- return true;
+ ExecutableWriter::createImplicitFiles(result);
}
} // namespace elf
diff --git a/lib/ReaderWriter/ELF/X86/X86LinkingContext.cpp b/lib/ReaderWriter/ELF/X86/X86LinkingContext.cpp
index 26d715cf2953..dc45efc390fd 100644
--- a/lib/ReaderWriter/ELF/X86/X86LinkingContext.cpp
+++ b/lib/ReaderWriter/ELF/X86/X86LinkingContext.cpp
@@ -14,15 +14,26 @@
#include "llvm/Support/ErrorOr.h"
using namespace lld;
+using namespace lld::elf;
std::unique_ptr<ELFLinkingContext>
-elf::X86LinkingContext::create(llvm::Triple triple) {
+elf::createX86LinkingContext(llvm::Triple triple) {
if (triple.getArch() == llvm::Triple::x86)
- return std::unique_ptr<ELFLinkingContext>(
- new elf::X86LinkingContext(triple));
+ return llvm::make_unique<X86LinkingContext>(triple);
return nullptr;
}
-elf::X86LinkingContext::X86LinkingContext(llvm::Triple triple)
- : ELFLinkingContext(triple, std::unique_ptr<TargetHandlerBase>(
- new X86TargetHandler(*this))) {}
+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
index ff424f411aae..f6ab3e980d7d 100644
--- a/lib/ReaderWriter/ELF/X86/X86LinkingContext.h
+++ b/lib/ReaderWriter/ELF/X86/X86LinkingContext.h
@@ -19,7 +19,9 @@ 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
diff --git a/lib/ReaderWriter/ELF/X86/X86RelocationHandler.cpp b/lib/ReaderWriter/ELF/X86/X86RelocationHandler.cpp
index da5a24c6ec37..15774bc33123 100644
--- a/lib/ReaderWriter/ELF/X86/X86RelocationHandler.cpp
+++ b/lib/ReaderWriter/ELF/X86/X86RelocationHandler.cpp
@@ -15,7 +15,6 @@ using namespace lld;
using namespace lld::elf;
using namespace llvm::support::endian;
-namespace {
/// \brief R_386_32 - word32: S + A
static int reloc32(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) {
int32_t result = (uint32_t)(S + A);
@@ -25,33 +24,31 @@ static int reloc32(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) {
/// \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);
+ uint32_t result = (uint32_t)(S + A - P);
write32le(location, result + read32le(location));
return 0;
}
-}
std::error_code X86TargetRelocationHandler::applyRelocation(
- ELFWriter &writer, llvm::FileOutputBuffer &buf, const lld::AtomLayout &atom,
+ ELFWriter &writer, llvm::FileOutputBuffer &buf, const AtomLayout &atom,
const Reference &ref) const {
uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset;
- uint8_t *location = atomContent + ref.offsetInAtom();
- uint64_t targetVAddress = writer.addressOfAtom(ref.target());
- uint64_t relocVAddress = atom._virtualAddr + ref.offsetInAtom();
+ 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(location, relocVAddress, targetVAddress, ref.addend());
+ reloc32(loc, reloc, target, ref.addend());
break;
case R_386_PC32:
- relocPC32(location, relocVAddress, targetVAddress, ref.addend());
+ 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
index f161cdd55983..1131635c6735 100644
--- a/lib/ReaderWriter/ELF/X86/X86RelocationHandler.h
+++ b/lib/ReaderWriter/ELF/X86/X86RelocationHandler.h
@@ -10,16 +10,15 @@
#ifndef X86_X86_RELOCATION_HANDLER_H
#define X86_X86_RELOCATION_HANDLER_H
-#include "X86TargetHandler.h"
+#include "lld/ReaderWriter/ELFLinkingContext.h"
namespace lld {
namespace elf {
-typedef llvm::object::ELFType<llvm::support::little, 2, false> X86ELFType;
class X86TargetRelocationHandler final : public TargetRelocationHandler {
public:
std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &,
- const lld::AtomLayout &,
+ const AtomLayout &,
const Reference &) const override;
};
diff --git a/lib/ReaderWriter/ELF/X86/X86TargetHandler.cpp b/lib/ReaderWriter/ELF/X86/X86TargetHandler.cpp
index 22d918231424..c01ed7258f1c 100644
--- a/lib/ReaderWriter/ELF/X86/X86TargetHandler.cpp
+++ b/lib/ReaderWriter/ELF/X86/X86TargetHandler.cpp
@@ -19,13 +19,11 @@ using namespace elf;
using namespace llvm::ELF;
std::unique_ptr<Writer> X86TargetHandler::getWriter() {
- switch (_x86LinkingContext.getOutputELFType()) {
+ switch (_ctx.getOutputELFType()) {
case llvm::ELF::ET_EXEC:
- return std::unique_ptr<Writer>(new X86ExecutableWriter<X86ELFType>(
- _x86LinkingContext, *_x86TargetLayout.get()));
+ return llvm::make_unique<X86ExecutableWriter>(_ctx, *_targetLayout);
case llvm::ELF::ET_DYN:
- return std::unique_ptr<Writer>(new X86DynamicLibraryWriter<X86ELFType>(
- _x86LinkingContext, *_x86TargetLayout.get()));
+ return llvm::make_unique<X86DynamicLibraryWriter>(_ctx, *_targetLayout);
case llvm::ELF::ET_REL:
llvm_unreachable("TODO: support -r mode");
default:
@@ -33,21 +31,6 @@ std::unique_ptr<Writer> X86TargetHandler::getWriter() {
}
}
-#define ELF_RELOC(name, value) LLD_KIND_STRING_ENTRY(name),
-
-const Registry::KindStrings X86TargetHandler::kindStrings[] = {
-#include "llvm/Support/ELFRelocs/i386.def"
- LLD_KIND_STRING_END
-};
-
-#undef ELF_RELOC
-
-void X86TargetHandler::registerRelocationNames(Registry &registry) {
- registry.addKindTable(Reference::KindNamespace::ELF, Reference::KindArch::x86,
- kindStrings);
-}
-
-X86TargetHandler::X86TargetHandler(X86LinkingContext &context)
- : _x86LinkingContext(context),
- _x86TargetLayout(new X86TargetLayout<X86ELFType>(context)),
- _x86RelocationHandler(new X86TargetRelocationHandler()) {}
+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
index 6c4026735419..fecf9abfc678 100644
--- a/lib/ReaderWriter/ELF/X86/X86TargetHandler.h
+++ b/lib/ReaderWriter/ELF/X86/X86TargetHandler.h
@@ -10,10 +10,8 @@
#ifndef LLD_READER_WRITER_ELF_X86_TARGET_HANDLER_H
#define LLD_READER_WRITER_ELF_X86_TARGET_HANDLER_H
-#include "DefaultTargetHandler.h"
#include "TargetLayout.h"
-#include "X86ELFFile.h"
-#include "X86ELFReader.h"
+#include "ELFReader.h"
#include "X86RelocationHandler.h"
namespace lld {
@@ -21,41 +19,28 @@ namespace elf {
class X86LinkingContext;
-template <class ELFT> class X86TargetLayout : public TargetLayout<ELFT> {
+class X86TargetHandler final : public TargetHandler {
public:
- X86TargetLayout(X86LinkingContext &context) : TargetLayout<ELFT>(context) {}
-};
-
-class X86TargetHandler final
- : public DefaultTargetHandler<X86ELFType> {
-public:
- X86TargetHandler(X86LinkingContext &context);
-
- X86TargetLayout<X86ELFType> &getTargetLayout() override {
- return *(_x86TargetLayout.get());
- }
-
- void registerRelocationNames(Registry &registry) override;
+ X86TargetHandler(X86LinkingContext &ctx);
- const X86TargetRelocationHandler &getRelocationHandler() const override {
- return *(_x86RelocationHandler.get());
+ const TargetRelocationHandler &getRelocationHandler() const override {
+ return *_relocationHandler;
}
std::unique_ptr<Reader> getObjReader() override {
- return std::unique_ptr<Reader>(new X86ELFObjectReader(_x86LinkingContext));
+ return llvm::make_unique<ELFReader<ELFFile<ELF32LE>>>(_ctx);
}
std::unique_ptr<Reader> getDSOReader() override {
- return std::unique_ptr<Reader>(new X86ELFDSOReader(_x86LinkingContext));
+ return llvm::make_unique<ELFReader<DynamicFile<ELF32LE>>>(_ctx);
}
std::unique_ptr<Writer> getWriter() override;
protected:
- static const Registry::KindStrings kindStrings[];
- X86LinkingContext &_x86LinkingContext;
- std::unique_ptr<X86TargetLayout<X86ELFType>> _x86TargetLayout;
- std::unique_ptr<X86TargetRelocationHandler> _x86RelocationHandler;
+ X86LinkingContext &_ctx;
+ std::unique_ptr<TargetLayout<ELF32LE>> _targetLayout;
+ std::unique_ptr<X86TargetRelocationHandler> _relocationHandler;
};
} // end namespace elf
} // end namespace lld
diff --git a/lib/ReaderWriter/ELF/X86_64/CMakeLists.txt b/lib/ReaderWriter/ELF/X86_64/CMakeLists.txt
index a85d2b504630..36ea839aa674 100644
--- a/lib/ReaderWriter/ELF/X86_64/CMakeLists.txt
+++ b/lib/ReaderWriter/ELF/X86_64/CMakeLists.txt
@@ -3,6 +3,7 @@ add_llvm_library(lldX86_64ELFTarget
X86_64TargetHandler.cpp
X86_64RelocationHandler.cpp
X86_64RelocationPass.cpp
+ X86_64SectionChunks.cpp
LINK_LIBS
lldELF
lldReaderWriter
diff --git a/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleLinkingContext.cpp b/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleLinkingContext.cpp
index dbbb3ad3bc90..cb3e819aff6b 100644
--- a/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleLinkingContext.cpp
+++ b/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleLinkingContext.cpp
@@ -14,14 +14,14 @@ using namespace lld;
using namespace elf;
std::unique_ptr<ELFLinkingContext>
-ExampleLinkingContext::create(llvm::Triple triple) {
+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<TargetHandlerBase>(
+ : X86_64LinkingContext(triple, std::unique_ptr<TargetHandler>(
new ExampleTargetHandler(*this))) {
_outputELFType = llvm::ELF::ET_LOPROC;
}
diff --git a/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleTargetHandler.cpp b/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleTargetHandler.cpp
index b66b0d903f6a..89ec6671f3a0 100644
--- a/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleTargetHandler.cpp
+++ b/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleTargetHandler.cpp
@@ -15,9 +15,8 @@ using namespace lld;
using namespace elf;
ExampleTargetHandler::ExampleTargetHandler(ExampleLinkingContext &c)
- : X86_64TargetHandler(c), _exampleContext(c) {}
+ : X86_64TargetHandler(c), _ctx(c) {}
std::unique_ptr<Writer> ExampleTargetHandler::getWriter() {
- return std::unique_ptr<Writer>(
- new X86_64ExecutableWriter(_exampleContext, *_x86_64TargetLayout));
+ 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
index 19a642113359..46eade5864f9 100644
--- a/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleTargetHandler.h
+++ b/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleTargetHandler.h
@@ -23,7 +23,7 @@ public:
std::unique_ptr<Writer> getWriter() override;
private:
- ExampleLinkingContext &_exampleContext;
+ ExampleLinkingContext &_ctx;
};
} // end namespace elf
} // end namespace lld
diff --git a/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/Makefile b/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/Makefile
deleted file mode 100644
index 8f0b0fead1f6..000000000000
--- a/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-##===- lld/lib/ReaderWriter/ELF/X86_64/Makefile ----------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LLD_LEVEL := ../../../../..
-LIBRARYNAME := lldExampleSubTarget
-USEDLIBS = lldX86_64ELFTarget.a
-CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF
-
-include $(LLD_LEVEL)/Makefile
diff --git a/lib/ReaderWriter/ELF/X86_64/Makefile b/lib/ReaderWriter/ELF/X86_64/Makefile
deleted file mode 100644
index dbeb4d227050..000000000000
--- a/lib/ReaderWriter/ELF/X86_64/Makefile
+++ /dev/null
@@ -1,19 +0,0 @@
-##===- lld/lib/ReaderWriter/ELF/X86_64/Makefile ----------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LLD_LEVEL := ../../../..
-LIBRARYNAME := lldX86_64ELFTarget
-USEDLIBS = lldCore.a
-
-CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF
-CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF/X86_64/
-
-PARALLEL_DIRS := ExampleSubTarget
-
-include $(LLD_LEVEL)/Makefile
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64DynamicLibraryWriter.h b/lib/ReaderWriter/ELF/X86_64/X86_64DynamicLibraryWriter.h
index b996186115b6..f84f85223bfb 100644
--- a/lib/ReaderWriter/ELF/X86_64/X86_64DynamicLibraryWriter.h
+++ b/lib/ReaderWriter/ELF/X86_64/X86_64DynamicLibraryWriter.h
@@ -10,51 +10,33 @@
#define X86_64_DYNAMIC_LIBRARY_WRITER_H
#include "DynamicLibraryWriter.h"
-#include "X86_64ElfType.h"
#include "X86_64LinkingContext.h"
#include "X86_64TargetHandler.h"
namespace lld {
namespace elf {
-class X86_64DynamicLibraryWriter : public DynamicLibraryWriter<X86_64ELFType> {
+class X86_64DynamicLibraryWriter : public DynamicLibraryWriter<ELF64LE> {
public:
- X86_64DynamicLibraryWriter(X86_64LinkingContext &context,
+ X86_64DynamicLibraryWriter(X86_64LinkingContext &ctx,
X86_64TargetLayout &layout);
protected:
// Add any runtime files and their atoms to the output
- virtual bool createImplicitFiles(std::vector<std::unique_ptr<File>> &);
-
- virtual void finalizeDefaultAtomValues() {
- return DynamicLibraryWriter::finalizeDefaultAtomValues();
- }
-
- virtual void addDefaultAtoms() {
- return DynamicLibraryWriter::addDefaultAtoms();
- }
-
-private:
- class GOTFile : public SimpleFile {
- public:
- GOTFile(const ELFLinkingContext &eti) : SimpleFile("GOTFile") {}
- llvm::BumpPtrAllocator _alloc;
- };
-
- std::unique_ptr<GOTFile> _gotFile;
+ void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
};
X86_64DynamicLibraryWriter::X86_64DynamicLibraryWriter(
- X86_64LinkingContext &context, X86_64TargetLayout &layout)
- : DynamicLibraryWriter(context, layout), _gotFile(new GOTFile(context)) {}
+ X86_64LinkingContext &ctx, X86_64TargetLayout &layout)
+ : DynamicLibraryWriter(ctx, layout) {}
-bool X86_64DynamicLibraryWriter::createImplicitFiles(
+void X86_64DynamicLibraryWriter::createImplicitFiles(
std::vector<std::unique_ptr<File>> &result) {
DynamicLibraryWriter::createImplicitFiles(result);
- _gotFile->addAtom(*new (_gotFile->_alloc) GLOBAL_OFFSET_TABLEAtom(*_gotFile));
- _gotFile->addAtom(*new (_gotFile->_alloc) DYNAMICAtom(*_gotFile));
- result.push_back(std::move(_gotFile));
- return true;
+ 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
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64ELFFile.h b/lib/ReaderWriter/ELF/X86_64/X86_64ELFFile.h
deleted file mode 100644
index d43840a63e7e..000000000000
--- a/lib/ReaderWriter/ELF/X86_64/X86_64ELFFile.h
+++ /dev/null
@@ -1,41 +0,0 @@
-//===- lib/ReaderWriter/ELF/X86_64/X86_64ELFFile.h ------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_ELF_X86_64_ELF_FILE_H
-#define LLD_READER_WRITER_ELF_X86_64_ELF_FILE_H
-
-#include "ELFReader.h"
-
-namespace lld {
-namespace elf {
-
-class X86_64LinkingContext;
-
-template <class ELFT> class X86_64ELFFile : public ELFFile<ELFT> {
-public:
- X86_64ELFFile(std::unique_ptr<MemoryBuffer> mb, X86_64LinkingContext &ctx)
- : ELFFile<ELFT>(std::move(mb), ctx) {}
-
- static ErrorOr<std::unique_ptr<X86_64ELFFile>>
- create(std::unique_ptr<MemoryBuffer> mb, X86_64LinkingContext &ctx) {
- return std::unique_ptr<X86_64ELFFile<ELFT>>(
- new X86_64ELFFile<ELFT>(std::move(mb), ctx));
- }
-};
-
-template <class ELFT> class X86_64DynamicFile : public DynamicFile<ELFT> {
-public:
- X86_64DynamicFile(const X86_64LinkingContext &context, StringRef name)
- : DynamicFile<ELFT>(context, name) {}
-};
-
-} // elf
-} // lld
-
-#endif // LLD_READER_WRITER_ELF_X86_64_ELF_FILE_H
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64ELFReader.h b/lib/ReaderWriter/ELF/X86_64/X86_64ELFReader.h
deleted file mode 100644
index 9b1284c6dfa8..000000000000
--- a/lib/ReaderWriter/ELF/X86_64/X86_64ELFReader.h
+++ /dev/null
@@ -1,62 +0,0 @@
-//===- lib/ReaderWriter/ELF/X86_64/X86_64ELFReader.h ----------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_X86_64_X86_64_ELF_READER_H
-#define LLD_READER_WRITER_X86_64_X86_64_ELF_READER_H
-
-#include "ELFReader.h"
-#include "X86_64ELFFile.h"
-
-namespace lld {
-namespace elf {
-
-typedef llvm::object::ELFType<llvm::support::little, 2, true> X86_64ELFType;
-
-struct X86_64DynamicFileCreateELFTraits {
- typedef llvm::ErrorOr<std::unique_ptr<lld::SharedLibraryFile>> result_type;
-
- template <class ELFT>
- static result_type create(std::unique_ptr<llvm::MemoryBuffer> mb,
- X86_64LinkingContext &ctx) {
- return lld::elf::X86_64DynamicFile<ELFT>::create(std::move(mb), ctx);
- }
-};
-
-struct X86_64ELFFileCreateELFTraits {
- typedef llvm::ErrorOr<std::unique_ptr<lld::File>> result_type;
-
- template <class ELFT>
- static result_type create(std::unique_ptr<llvm::MemoryBuffer> mb,
- X86_64LinkingContext &ctx) {
- return lld::elf::X86_64ELFFile<ELFT>::create(std::move(mb), ctx);
- }
-};
-
-class X86_64ELFObjectReader
- : public ELFObjectReader<X86_64ELFType, X86_64ELFFileCreateELFTraits,
- X86_64LinkingContext> {
-public:
- X86_64ELFObjectReader(X86_64LinkingContext &ctx)
- : ELFObjectReader<X86_64ELFType, X86_64ELFFileCreateELFTraits,
- X86_64LinkingContext>(ctx, llvm::ELF::EM_X86_64) {}
-};
-
-class X86_64ELFDSOReader
- : public ELFDSOReader<X86_64ELFType, X86_64DynamicFileCreateELFTraits,
- X86_64LinkingContext> {
-public:
- X86_64ELFDSOReader(X86_64LinkingContext &ctx)
- : ELFDSOReader<X86_64ELFType, X86_64DynamicFileCreateELFTraits,
- X86_64LinkingContext>(ctx, llvm::ELF::EM_X86_64) {}
-};
-
-} // namespace elf
-} // namespace lld
-
-#endif // LLD_READER_WRITER_ELF_X86_64_X86_64_READER_H
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64ElfType.h b/lib/ReaderWriter/ELF/X86_64/X86_64ElfType.h
deleted file mode 100644
index 0b982e7754e2..000000000000
--- a/lib/ReaderWriter/ELF/X86_64/X86_64ElfType.h
+++ /dev/null
@@ -1,21 +0,0 @@
-//===- lib/ReaderWriter/ELF/X86_64/X86_64ElfType.h ------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_ELF_X86_64_X86_64_ELF_TYPE_H
-#define LLD_READER_WRITER_ELF_X86_64_X86_64_ELF_TYPE_H
-
-#include "llvm/Object/ELF.h"
-
-namespace lld {
-namespace elf {
-typedef llvm::object::ELFType<llvm::support::little, 2, true> X86_64ELFType;
-}
-}
-
-#endif
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64ExecutableWriter.h b/lib/ReaderWriter/ELF/X86_64/X86_64ExecutableWriter.h
index f549ed6dcfcb..930a2de2a9e8 100644
--- a/lib/ReaderWriter/ELF/X86_64/X86_64ExecutableWriter.h
+++ b/lib/ReaderWriter/ELF/X86_64/X86_64ExecutableWriter.h
@@ -10,49 +10,45 @@
#define X86_64_EXECUTABLE_WRITER_H
#include "ExecutableWriter.h"
-#include "X86_64ElfType.h"
#include "X86_64LinkingContext.h"
namespace lld {
namespace elf {
-class X86_64ExecutableWriter : public ExecutableWriter<X86_64ELFType> {
+class X86_64ExecutableWriter : public ExecutableWriter<ELF64LE> {
public:
- X86_64ExecutableWriter(X86_64LinkingContext &context,
- X86_64TargetLayout &layout)
- : ExecutableWriter(context, layout), _gotFile(new GOTFile(context)),
- _context(context) {}
+ X86_64ExecutableWriter(X86_64LinkingContext &ctx, X86_64TargetLayout &layout)
+ : ExecutableWriter(ctx, layout), _targetLayout(layout) {}
protected:
// Add any runtime files and their atoms to the output
- virtual bool
- createImplicitFiles(std::vector<std::unique_ptr<File>> &result) {
+ void
+ createImplicitFiles(std::vector<std::unique_ptr<File>> &result) override {
ExecutableWriter::createImplicitFiles(result);
- _gotFile->addAtom(*new (_gotFile->_alloc)
- GLOBAL_OFFSET_TABLEAtom(*_gotFile));
- if (_context.isDynamic())
- _gotFile->addAtom(*new (_gotFile->_alloc) DYNAMICAtom(*_gotFile));
- result.push_back(std::move(_gotFile));
- return true;
+ 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));
}
- virtual void finalizeDefaultAtomValues() {
- return ExecutableWriter::finalizeDefaultAtomValues();
+ 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);
}
- virtual void addDefaultAtoms() {
- return ExecutableWriter::addDefaultAtoms();
- }
-
-private:
- class GOTFile : public SimpleFile {
- public:
- GOTFile(const ELFLinkingContext &eti) : SimpleFile("GOTFile") {}
- llvm::BumpPtrAllocator _alloc;
- };
-
- std::unique_ptr<GOTFile> _gotFile;
- X86_64LinkingContext &_context;
+ X86_64TargetLayout &_targetLayout;
};
} // namespace elf
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp b/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp
index 6a8ce8bd6496..0dcd6ac6fbed 100644
--- a/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp
+++ b/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp
@@ -12,10 +12,10 @@
#include "X86_64TargetHandler.h"
using namespace lld;
-using namespace elf;
+using namespace lld::elf;
X86_64LinkingContext::X86_64LinkingContext(
- llvm::Triple triple, std::unique_ptr<TargetHandlerBase> handler)
+ llvm::Triple triple, std::unique_ptr<TargetHandler> handler)
: ELFLinkingContext(triple, std::move(handler)) {}
X86_64LinkingContext::X86_64LinkingContext(llvm::Triple triple)
@@ -30,9 +30,21 @@ void X86_64LinkingContext::addPasses(PassManager &pm) {
}
std::unique_ptr<ELFLinkingContext>
-X86_64LinkingContext::create(llvm::Triple triple) {
+elf::createX86_64LinkingContext(llvm::Triple triple) {
if (triple.getArch() == llvm::Triple::x86_64)
- return std::unique_ptr<ELFLinkingContext>(
- new elf::X86_64LinkingContext(triple));
+ 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
index 2cc799a9c810..a5a7b3d21f4e 100644
--- a/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h
+++ b/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h
@@ -26,12 +26,15 @@ enum {
class X86_64LinkingContext : public ELFLinkingContext {
protected:
- X86_64LinkingContext(llvm::Triple, std::unique_ptr<TargetHandlerBase>);
+ 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)
@@ -65,7 +68,7 @@ public:
return false;
}
- virtual bool isPLTRelocation(const Reference &r) const override {
+ bool isPLTRelocation(const Reference &r) const override {
if (r.kindNamespace() != Reference::KindNamespace::ELF)
return false;
assert(r.kindArch() == Reference::KindArch::x86_64);
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp b/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp
index 8fd74f43bbd2..d56983d1e382 100644
--- a/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp
+++ b/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp
@@ -23,7 +23,7 @@ static void reloc64(uint8_t *location, uint64_t P, uint64_t S, int64_t A) {
/// \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);
+ uint32_t result = (uint32_t)(S + A - P);
write32le(location, result + read32le(location));
}
@@ -50,24 +50,24 @@ static void reloc16(uint8_t *location, uint64_t P, uint64_t S, int64_t A) {
/// \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);
+ 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);
+ int64_t result = (uint64_t)(S + A - P);
write64le(location, result | read64le(location));
}
std::error_code X86_64TargetRelocationHandler::applyRelocation(
- ELFWriter &writer, llvm::FileOutputBuffer &buf, const lld::AtomLayout &atom,
+ ELFWriter &writer, llvm::FileOutputBuffer &buf, const AtomLayout &atom,
const Reference &ref) const {
uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset;
- uint8_t *location = atomContent + ref.offsetInAtom();
- uint64_t targetVAddress = writer.addressOfAtom(ref.target());
- uint64_t relocVAddress = atom._virtualAddr + ref.offsetInAtom();
+ 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();
@@ -76,38 +76,34 @@ std::error_code X86_64TargetRelocationHandler::applyRelocation(
case R_X86_64_NONE:
break;
case R_X86_64_64:
- reloc64(location, relocVAddress, targetVAddress, ref.addend());
+ reloc64(loc, reloc, target, ref.addend());
break;
case R_X86_64_PC32:
case R_X86_64_GOTPCREL:
- relocPC32(location, relocVAddress, targetVAddress, ref.addend());
+ relocPC32(loc, reloc, target, ref.addend());
break;
case R_X86_64_32:
- reloc32(location, relocVAddress, targetVAddress, ref.addend());
+ reloc32(loc, reloc, target, ref.addend());
break;
case R_X86_64_32S:
- reloc32S(location, relocVAddress, targetVAddress, ref.addend());
+ reloc32S(loc, reloc, target, ref.addend());
break;
case R_X86_64_16:
- reloc16(location, relocVAddress, targetVAddress, ref.addend());
+ reloc16(loc, reloc, target, ref.addend());
break;
case R_X86_64_PC16:
- relocPC16(location, relocVAddress, targetVAddress, ref.addend());
+ relocPC16(loc, reloc, target, ref.addend());
break;
- case R_X86_64_TPOFF64:
case R_X86_64_DTPOFF32:
- case R_X86_64_TPOFF32: {
- _tlsSize = _x86_64Layout.getTLSSize();
- if (ref.kindValue() == R_X86_64_TPOFF32 ||
- ref.kindValue() == R_X86_64_DTPOFF32) {
- write32le(location, targetVAddress - _tlsSize);
- } else {
- write64le(location, targetVAddress - _tlsSize);
- }
+ 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(location, relocVAddress, targetVAddress, ref.addend());
+ relocPC32(loc, reloc, target, ref.addend());
break;
}
case R_X86_64_TLSLD: {
@@ -115,21 +111,20 @@ std::error_code X86_64TargetRelocationHandler::applyRelocation(
// next relocation is a PC32 to __tls_get_addr...
static uint8_t instr[] = { 0x66, 0x66, 0x66, 0x64, 0x48, 0x8b, 0x04, 0x25,
0x00, 0x00, 0x00, 0x00 };
- std::memcpy(location - 3, instr, sizeof(instr));
+ std::memcpy(loc - 3, instr, sizeof(instr));
break;
}
case R_X86_64_PC64:
- relocPC64(location, relocVAddress, targetVAddress, ref.addend());
+ 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 (!_x86_64Layout.getPLTRelocationTable()->getRelocationIndex(*r,
- index))
+ if (!_layout.getPLTRelocationTable()->getRelocationIndex(*r, index))
llvm_unreachable("Relocation doesn't exist");
- reloc32(location, 0, index, 0);
+ reloc32(loc, 0, index, 0);
break;
}
}
@@ -142,6 +137,7 @@ std::error_code X86_64TargetRelocationHandler::applyRelocation(
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();
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.h b/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.h
index 9e2c2171015d..26382804549b 100644
--- a/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.h
+++ b/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.h
@@ -10,27 +10,25 @@
#ifndef X86_64_RELOCATION_HANDLER_H
#define X86_64_RELOCATION_HANDLER_H
-#include "X86_64TargetHandler.h"
+#include "lld/ReaderWriter/ELFLinkingContext.h"
namespace lld {
namespace elf {
-typedef llvm::object::ELFType<llvm::support::little, 2, true> X86_64ELFType;
-
class X86_64TargetLayout;
class X86_64TargetRelocationHandler final : public TargetRelocationHandler {
public:
X86_64TargetRelocationHandler(X86_64TargetLayout &layout)
- : _tlsSize(0), _x86_64Layout(layout) {}
+ : _tlsSize(0), _layout(layout) {}
std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &,
- const lld::AtomLayout &,
+ const AtomLayout &,
const Reference &) const override;
private:
// Cached size of the TLS segment.
mutable uint64_t _tlsSize;
- X86_64TargetLayout &_x86_64Layout;
+ X86_64TargetLayout &_layout;
};
} // end namespace elf
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp b/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp
index 0703927fd56c..a2f10dc08a4e 100644
--- a/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp
+++ b/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp
@@ -188,11 +188,12 @@ protected:
return got->second;
}
- /// \brief Create a TPOFF64 GOT entry and change the relocation to a PC32 to
- /// the GOT.
- void handleGOTTPOFF(const Reference &ref) {
- const_cast<Reference &>(ref).setTarget(getGOTTPOFF(ref.target()));
- const_cast<Reference &>(ref).setKindValue(R_X86_64_PC32);
+ /// \brief Create a 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.
@@ -243,9 +244,7 @@ protected:
}
public:
- RelocationPass(const ELFLinkingContext &ctx)
- : _file(ctx), _ctx(ctx), _null(nullptr), _PLT0(nullptr), _got0(nullptr),
- _got1(nullptr) {}
+ RelocationPass(const ELFLinkingContext &ctx) : _file(ctx), _ctx(ctx) {}
/// \brief Do the pass.
///
@@ -255,45 +254,46 @@ public:
///
/// After all references are handled, the atoms created during that are all
/// added to mf.
- void perform(std::unique_ptr<MutableFile> &mf) override {
+ 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 &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);
+ if (_plt0) {
+ _plt0->setOrdinal(ordinal++);
+ mf.addAtom(*_plt0);
}
for (auto &plt : _pltVector) {
plt->setOrdinal(ordinal++);
- mf->addAtom(*plt);
+ mf.addAtom(*plt);
}
if (_null) {
_null->setOrdinal(ordinal++);
- mf->addAtom(*_null);
+ mf.addAtom(*_null);
}
- if (_PLT0) {
+ if (_plt0) {
_got0->setOrdinal(ordinal++);
_got1->setOrdinal(ordinal++);
- mf->addAtom(*_got0);
- mf->addAtom(*_got1);
+ mf.addAtom(*_got0);
+ mf.addAtom(*_got1);
}
for (auto &got : _gotVector) {
got->setOrdinal(ordinal++);
- mf->addAtom(*got);
+ mf.addAtom(*got);
}
for (auto &got : _tlsGotVector) {
got->setOrdinal(ordinal++);
- mf->addAtom(*got);
+ mf.addAtom(*got);
}
for (auto obj : _objectVector) {
obj->setOrdinal(ordinal++);
- mf->addAtom(*obj);
+ mf.addAtom(*obj);
}
+ return std::error_code();
}
protected:
@@ -322,14 +322,14 @@ protected:
std::vector<GOTAtom *> _tlsGotVector;
/// \brief GOT entry that is always 0. Used for undefined weaks.
- GOTAtom *_null;
+ 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;
- GOTAtom *_got0;
- GOTAtom *_got1;
+ PLT0Atom *_plt0 = nullptr;
+ GOTAtom *_got0 = nullptr;
+ GOTAtom *_got1 = nullptr;
/// @}
};
@@ -379,20 +379,20 @@ public:
: RelocationPass(ctx) {}
const PLT0Atom *getPLT0() {
- if (_PLT0)
- return _PLT0;
+ if (_plt0)
+ return _plt0;
// Fill in the null entry.
getNullGOT();
- _PLT0 = new (_file._alloc) X86_64PLT0Atom(_file);
+ _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);
+ _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;
+ return _plt0;
}
const PLTAtom *getPLTEntry(const Atom *a) {
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64SectionChunks.cpp b/lib/ReaderWriter/ELF/X86_64/X86_64SectionChunks.cpp
new file mode 100644
index 000000000000..28eb3e4244b6
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/X86_64SectionChunks.cpp
@@ -0,0 +1,37 @@
+//===- 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
new file mode 100644
index 000000000000..5208491eee55
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/X86_64SectionChunks.h
@@ -0,0 +1,36 @@
+//===- 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
index f35330eb25c0..599077ac33c5 100644
--- a/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.cpp
+++ b/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.cpp
@@ -16,37 +16,19 @@
using namespace lld;
using namespace elf;
-X86_64TargetHandler::X86_64TargetHandler(X86_64LinkingContext &context)
- : _context(context), _x86_64TargetLayout(new X86_64TargetLayout(context)),
- _x86_64RelocationHandler(
- new X86_64TargetRelocationHandler(*_x86_64TargetLayout.get())) {}
-
-void X86_64TargetHandler::registerRelocationNames(Registry &registry) {
- registry.addKindTable(Reference::KindNamespace::ELF,
- Reference::KindArch::x86_64, kindStrings);
-}
+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->_context.getOutputELFType()) {
+ switch (this->_ctx.getOutputELFType()) {
case llvm::ELF::ET_EXEC:
- return std::unique_ptr<Writer>(
- new X86_64ExecutableWriter(_context, *_x86_64TargetLayout.get()));
+ return llvm::make_unique<X86_64ExecutableWriter>(_ctx, *_targetLayout);
case llvm::ELF::ET_DYN:
- return std::unique_ptr<Writer>(
- new X86_64DynamicLibraryWriter(_context, *_x86_64TargetLayout.get()));
+ 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");
}
}
-
-#define ELF_RELOC(name, value) LLD_KIND_STRING_ENTRY(name),
-
-const Registry::KindStrings X86_64TargetHandler::kindStrings[] = {
-#include "llvm/Support/ELFRelocs/x86_64.def"
- LLD_KIND_STRING_ENTRY(LLD_R_X86_64_GOTRELINDEX),
- LLD_KIND_STRING_END
-};
-
-#undef ELF_RELOC
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h b/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h
index 57da7bca01e6..6e3e58f8aed6 100644
--- a/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h
+++ b/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h
@@ -10,57 +10,92 @@
#ifndef LLD_READER_WRITER_ELF_X86_64_X86_64_TARGET_HANDLER_H
#define LLD_READER_WRITER_ELF_X86_64_X86_64_TARGET_HANDLER_H
-#include "DefaultTargetHandler.h"
+#include "ELFReader.h"
#include "TargetLayout.h"
-#include "X86_64ELFFile.h"
-#include "X86_64ELFReader.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<X86_64ELFType> {
+
+
+class X86_64TargetLayout : public TargetLayout<ELF64LE> {
public:
- X86_64TargetLayout(X86_64LinkingContext &context)
- : TargetLayout(context) {}
+ 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(".init_array", ".init_array");
- sortOutputSectionByPriority(".fini_array", ".fini_array");
+ sortOutputSectionByPriority<ELF64LE>(".init_array");
+ sortOutputSectionByPriority<ELF64LE>(".fini_array");
}
-};
-class X86_64TargetHandler
- : public DefaultTargetHandler<X86_64ELFType> {
-public:
- X86_64TargetHandler(X86_64LinkingContext &context);
+ const X86_64GOTSection &getGOTSection() const { return *_gotSection; }
- X86_64TargetLayout &getTargetLayout() override {
- return *(_x86_64TargetLayout.get());
+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;
}
- void registerRelocationNames(Registry &registry) override;
+ 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 X86_64TargetRelocationHandler &getRelocationHandler() const override {
- return *(_x86_64RelocationHandler.get());
+ const TargetRelocationHandler &getRelocationHandler() const override {
+ return *_relocationHandler;
}
std::unique_ptr<Reader> getObjReader() override {
- return std::unique_ptr<Reader>(new X86_64ELFObjectReader(_context));
+ return llvm::make_unique<ELFReader<ELFFile<ELF64LE>>>(_ctx);
}
std::unique_ptr<Reader> getDSOReader() override {
- return std::unique_ptr<Reader>(new X86_64ELFDSOReader(_context));
+ return llvm::make_unique<ELFReader<DynamicFile<ELF64LE>>>(_ctx);
}
std::unique_ptr<Writer> getWriter() override;
protected:
- static const Registry::KindStrings kindStrings[];
- X86_64LinkingContext &_context;
- std::unique_ptr<X86_64TargetLayout> _x86_64TargetLayout;
- std::unique_ptr<X86_64TargetRelocationHandler> _x86_64RelocationHandler;
+ X86_64LinkingContext &_ctx;
+ std::unique_ptr<X86_64TargetLayout> _targetLayout;
+ std::unique_ptr<X86_64TargetRelocationHandler> _relocationHandler;
};
} // end namespace elf
diff --git a/lib/ReaderWriter/FileArchive.cpp b/lib/ReaderWriter/FileArchive.cpp
index 3f38814ae18e..a09923f57d07 100644
--- a/lib/ReaderWriter/FileArchive.cpp
+++ b/lib/ReaderWriter/FileArchive.cpp
@@ -11,6 +11,7 @@
#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 "llvm/ADT/StringRef.h"
#include "llvm/Object/Archive.h"
@@ -48,9 +49,14 @@ public:
if (member == _symbolMemberMap.end())
return nullptr;
Archive::child_iterator ci = member->second;
+ if (ci->getError())
+ return nullptr;
// Don't return a member already returned
- const char *memberStart = ci->getBuffer().data();
+ ErrorOr<StringRef> buf = (*ci)->getBuffer();
+ if (!buf)
+ return nullptr;
+ const char *memberStart = buf->data();
if (_membersInstantiated.count(memberStart))
return nullptr;
if (dataSymbolOnly && !isDataSymbol(ci, name))
@@ -73,8 +79,11 @@ public:
if (instantiateMember(ci, result))
return nullptr;
- // give up the pointer so that this object no longer manages it
- return result.release();
+ File *file = result.get();
+ _filesReturned.push_back(std::move(result));
+
+ // Give up the file pointer. It was stored and will be destroyed with destruction of FileArchive
+ return file;
}
// Instantiate a member file containing a given symbol name.
@@ -83,9 +92,14 @@ public:
if (member == _symbolMemberMap.end())
return;
Archive::child_iterator ci = member->second;
+ if (ci->getError())
+ return;
// Do nothing if a member is already instantiated.
- const char *memberStart = ci->getBuffer().data();
+ ErrorOr<StringRef> buf = (*ci)->getBuffer();
+ if (!buf)
+ return;
+ const char *memberStart = buf->data();
if (_membersInstantiated.count(memberStart))
return;
@@ -119,20 +133,20 @@ public:
return std::error_code();
}
- const atom_collection<DefinedAtom> &defined() const override {
- return _definedAtoms;
+ const AtomVector<DefinedAtom> &defined() const override {
+ return _noDefinedAtoms;
}
- const atom_collection<UndefinedAtom> &undefined() const override {
- return _undefinedAtoms;
+ const AtomVector<UndefinedAtom> &undefined() const override {
+ return _noUndefinedAtoms;
}
- const atom_collection<SharedLibraryAtom> &sharedLibrary() const override {
- return _sharedLibraryAtoms;
+ const AtomVector<SharedLibraryAtom> &sharedLibrary() const override {
+ return _noSharedLibraryAtoms;
}
- const atom_collection<AbsoluteAtom> &absolute() const override {
- return _absoluteAtoms;
+ const AtomVector<AbsoluteAtom> &absolute() const override {
+ return _noAbsoluteAtoms;
}
/// Returns a set of all defined symbols in the archive.
@@ -157,10 +171,12 @@ protected:
}
private:
- std::error_code
- instantiateMember(Archive::child_iterator member,
- std::unique_ptr<File> &result) const {
- ErrorOr<llvm::MemoryBufferRef> mbOrErr = member->getMemoryBufferRef();
+ std::error_code instantiateMember(Archive::child_iterator cOrErr,
+ 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();
if (std::error_code ec = mbOrErr.getError())
return ec;
llvm::MemoryBufferRef mb = mbOrErr.get();
@@ -173,11 +189,11 @@ private:
std::unique_ptr<MemoryBuffer> memberMB(MemoryBuffer::getMemBuffer(
mb.getBuffer(), mb.getBufferIdentifier(), false));
- std::vector<std::unique_ptr<File>> files;
- if (std::error_code ec = _registry.loadFile(std::move(memberMB), files))
+ ErrorOr<std::unique_ptr<File>> fileOrErr =
+ _registry.loadFile(std::move(memberMB));
+ if (std::error_code ec = fileOrErr.getError())
return ec;
- assert(files.size() == 1);
- result = std::move(files[0]);
+ result = std::move(fileOrErr.get());
if (std::error_code ec = result->parse())
return ec;
result->setArchivePath(_archive->getFileName());
@@ -191,8 +207,11 @@ private:
// 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 member, StringRef symbol) const {
- ErrorOr<llvm::MemoryBufferRef> buf = member->getMemoryBufferRef();
+ 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(
@@ -205,19 +224,17 @@ private:
for (SymbolRef sym : obj->symbols()) {
// Skip until we find the symbol.
- StringRef name;
- if (sym.getName(name))
+ ErrorOr<StringRef> name = sym.getName();
+ if (!name)
return false;
- if (name != symbol)
+ 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;
- if (sym.getType(type))
- return false;
+ SymbolRef::Type type = sym.getType();
if (type == SymbolRef::ST_Data)
return true;
}
@@ -234,11 +251,12 @@ private:
if (std::error_code ec = memberOrErr.getError())
return ec;
Archive::child_iterator member = memberOrErr.get();
- DEBUG_WITH_TYPE(
- "FileArchive",
- llvm::dbgs() << llvm::format("0x%08llX ", member->getBuffer().data())
- << "'" << name << "'\n");
- _symbolMemberMap[name] = member;
+ DEBUG_WITH_TYPE("FileArchive",
+ llvm::dbgs()
+ << llvm::format("0x%08llX ",
+ (*member)->getBuffer()->data())
+ << "'" << name << "'\n");
+ _symbolMemberMap.insert(std::make_pair(name, member));
}
return std::error_code();
}
@@ -251,33 +269,27 @@ private:
std::unique_ptr<Archive> _archive;
MemberMap _symbolMemberMap;
InstantiatedSet _membersInstantiated;
- atom_collection_vector<DefinedAtom> _definedAtoms;
- atom_collection_vector<UndefinedAtom> _undefinedAtoms;
- atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
- atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
bool _logLoading;
std::vector<std::unique_ptr<MemoryBuffer>> _memberBuffers;
std::map<const char *, std::unique_ptr<Future<File *>>> _preloaded;
std::mutex _mutex;
+ FileVector _filesReturned;
};
class ArchiveReader : public Reader {
public:
ArchiveReader(bool logLoading) : _logLoading(logLoading) {}
- bool canParse(file_magic magic, StringRef,
- const MemoryBuffer &) const override {
- return (magic == llvm::sys::fs::file_magic::archive);
+ bool canParse(file_magic magic, MemoryBufferRef) const override {
+ return magic == llvm::sys::fs::file_magic::archive;
}
- std::error_code
- loadFile(std::unique_ptr<MemoryBuffer> mb, const Registry &reg,
- std::vector<std::unique_ptr<File>> &result) const override {
+ ErrorOr<std::unique_ptr<File>> loadFile(std::unique_ptr<MemoryBuffer> mb,
+ const Registry &reg) const override {
StringRef path = mb->getBufferIdentifier();
- std::unique_ptr<FileArchive> file(
- new FileArchive(std::move(mb), reg, path, _logLoading));
- result.push_back(std::move(file));
- return std::error_code();
+ std::unique_ptr<File> ret =
+ llvm::make_unique<FileArchive>(std::move(mb), reg, path, _logLoading);
+ return std::move(ret);
}
private:
diff --git a/lib/ReaderWriter/LinkerScript.cpp b/lib/ReaderWriter/LinkerScript.cpp
index 56194cae5e72..67822dc48fe6 100644
--- a/lib/ReaderWriter/LinkerScript.cpp
+++ b/lib/ReaderWriter/LinkerScript.cpp
@@ -1,4 +1,4 @@
-//===- ReaderWriter/LinkerScript.cpp --------------------------------------===//
+//===- ReaderWriter/LinkerScript.cpp ----------------------------*- C++ -*-===//
//
// The LLVM Linker
//
@@ -14,6 +14,11 @@
#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 {
@@ -63,6 +68,9 @@ void Token::dump(raw_ostream &os) const {
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)
@@ -70,6 +78,7 @@ void Token::dump(raw_ostream &os) const {
CASE(kw_length)
CASE(kw_memory)
CASE(kw_origin)
+ CASE(kw_phdrs)
CASE(kw_provide)
CASE(kw_provide_hidden)
CASE(kw_only_if_ro)
@@ -100,7 +109,7 @@ static llvm::ErrorOr<uint64_t> parseDecimal(StringRef str) {
for (auto &c : str) {
res *= 10;
if (c < '0' || c > '9')
- return llvm::ErrorOr<uint64_t>(std::make_error_code(std::errc::io_error));
+ return llvm::ErrorOr<uint64_t>(make_error_code(llvm::errc::io_error));
res += c - '0';
}
return res;
@@ -111,7 +120,7 @@ static llvm::ErrorOr<uint64_t> parseOctal(StringRef str) {
for (auto &c : str) {
res <<= 3;
if (c < '0' || c > '7')
- return llvm::ErrorOr<uint64_t>(std::make_error_code(std::errc::io_error));
+ return llvm::ErrorOr<uint64_t>(make_error_code(llvm::errc::io_error));
res += c - '0';
}
return res;
@@ -122,7 +131,7 @@ static llvm::ErrorOr<uint64_t> parseBinary(StringRef str) {
for (auto &c : str) {
res <<= 1;
if (c != '0' && c != '1')
- return llvm::ErrorOr<uint64_t>(std::make_error_code(std::errc::io_error));
+ return llvm::ErrorOr<uint64_t>(make_error_code(llvm::errc::io_error));
res += c - '0';
}
return res;
@@ -139,7 +148,7 @@ static llvm::ErrorOr<uint64_t> parseHex(StringRef str) {
else if (c >= 'A' && c <= 'F')
res += c - 'A' + 10;
else
- return llvm::ErrorOr<uint64_t>(std::make_error_code(std::errc::io_error));
+ return llvm::ErrorOr<uint64_t>(make_error_code(llvm::errc::io_error));
}
return res;
}
@@ -469,6 +478,9 @@ void Lexer::lex(Token &tok) {
.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)
@@ -486,6 +498,7 @@ void Lexer::lex(Token &tok) {
.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)
@@ -544,14 +557,14 @@ void Lexer::skipWhitespace() {
// Constant functions
void Constant::dump(raw_ostream &os) const { os << _num; }
-ErrorOr<int64_t> Constant::evalExpr(SymbolTableTy &symbolTable) const {
+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(SymbolTableTy &symbolTable) const {
+ErrorOr<int64_t> Symbol::evalExpr(const SymbolTableTy &symbolTable) const {
auto it = symbolTable.find(_name);
if (it == symbolTable.end())
return LinkerScriptReaderError::unknown_symbol_in_expr;
@@ -569,7 +582,8 @@ void FunctionCall::dump(raw_ostream &os) const {
os << ")";
}
-ErrorOr<int64_t> FunctionCall::evalExpr(SymbolTableTy &symbolTable) const {
+ErrorOr<int64_t>
+FunctionCall::evalExpr(const SymbolTableTy &symbolTable) const {
return LinkerScriptReaderError::unrecognized_function_in_expr;
}
@@ -584,7 +598,7 @@ void Unary::dump(raw_ostream &os) const {
os << ")";
}
-ErrorOr<int64_t> Unary::evalExpr(SymbolTableTy &symbolTable) const {
+ErrorOr<int64_t> Unary::evalExpr(const SymbolTableTy &symbolTable) const {
auto child = _child->evalExpr(symbolTable);
if (child.getError())
return child.getError();
@@ -654,7 +668,7 @@ void BinOp::dump(raw_ostream &os) const {
os << ")";
}
-ErrorOr<int64_t> BinOp::evalExpr(SymbolTableTy &symbolTable) const {
+ErrorOr<int64_t> BinOp::evalExpr(const SymbolTableTy &symbolTable) const {
auto lhs = _lhs->evalExpr(symbolTable);
if (lhs.getError())
return lhs.getError();
@@ -695,7 +709,7 @@ void TernaryConditional::dump(raw_ostream &os) const {
}
ErrorOr<int64_t>
-TernaryConditional::evalExpr(SymbolTableTy &symbolTable) const {
+TernaryConditional::evalExpr(const SymbolTableTy &symbolTable) const {
auto conditional = _conditional->evalExpr(symbolTable);
if (conditional.getError())
return conditional.getError();
@@ -857,6 +871,12 @@ void InputSectionsCmd::dump(raw_ostream &os) const {
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)
@@ -909,6 +929,9 @@ void OutputSectionDescription::dump(raw_ostream &os) const {
}
os << " }";
+ for (auto && phdr : _phdrs)
+ os << " : " << phdr;
+
if (_fillStream.size() > 0) {
os << " =";
dumpByteStream(os, _fillStream);
@@ -918,6 +941,37 @@ void OutputSectionDescription::dump(raw_ostream &os) const {
}
}
+// 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";
@@ -965,7 +1019,6 @@ void Extern::dump(raw_ostream &os) const {
os << ")\n";
}
-
// Parser functions
std::error_code Parser::parse() {
// Get the first token.
@@ -1024,6 +1077,13 @@ std::error_code Parser::parse() {
_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)
@@ -1122,7 +1182,7 @@ const Expression *Parser::parseExprOperand() {
case Token::identifier: {
if (peek()._kind== Token::l_paren)
return parseFunctionCall();
- Symbol *sym = new (_alloc) Symbol(*this, _tok._range);
+ auto *sym = new (_alloc) Symbol(*this, _tok._range);
consumeToken();
return sym;
}
@@ -1140,7 +1200,7 @@ const Expression *Parser::parseExprOperand() {
error(_tok, "Unrecognized number constant");
return nullptr;
}
- Constant *c = new (_alloc) Constant(*this, *val);
+ auto *c = new (_alloc) Constant(*this, *val);
consumeToken();
return c;
}
@@ -1588,7 +1648,7 @@ llvm::ErrorOr<InputSectionsCmd::VectorTy> Parser::parseExcludeFile() {
if (!expectAndConsume(Token::l_paren, "expected ("))
return llvm::ErrorOr<InputSectionsCmd::VectorTy>(
- std::make_error_code(std::errc::io_error));
+ make_error_code(llvm::errc::io_error));
while (_tok._kind == Token::identifier) {
res.push_back(new (_alloc) InputSectionName(*this, _tok._range, true));
@@ -1597,7 +1657,7 @@ llvm::ErrorOr<InputSectionsCmd::VectorTy> Parser::parseExcludeFile() {
if (!expectAndConsume(Token::r_paren, "expected )"))
return llvm::ErrorOr<InputSectionsCmd::VectorTy>(
- std::make_error_code(std::errc::io_error));
+ make_error_code(llvm::errc::io_error));
return llvm::ErrorOr<InputSectionsCmd::VectorTy>(std::move(res));
}
@@ -1793,6 +1853,46 @@ const InputSectionsCmd *Parser::parseInputSectionsCmd() {
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!");
@@ -1892,6 +1992,12 @@ const OutputSectionDescription *Parser::parseOutputSectionDescription() {
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:
@@ -1921,6 +2027,17 @@ const OutputSectionDescription *Parser::parseOutputSectionDescription() {
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")) {
@@ -1945,7 +2062,7 @@ const OutputSectionDescription *Parser::parseOutputSectionDescription() {
return new (_alloc) OutputSectionDescription(
*this, sectionName, address, align, subAlign, at, fillExpr, fillStream,
- alignWithInput, discard, constraint, outputSectionCommands);
+ alignWithInput, discard, constraint, outputSectionCommands, phdrs);
}
const Overlay *Parser::parseOverlay() {
@@ -1954,6 +2071,141 @@ const Overlay *Parser::parseOverlay() {
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();
@@ -2101,8 +2353,7 @@ Memory *Parser::parseMemory() {
if (!length)
return nullptr;
- MemoryBlock *block =
- new (_alloc) MemoryBlock(name, attrs, origin, length);
+ auto *block = new (_alloc) MemoryBlock(name, attrs, origin, length);
blocks.push_back(block);
} else {
unrecognizedToken = true;
@@ -2142,14 +2393,22 @@ Extern *Parser::parseExtern() {
}
// Sema member functions
-Sema::Sema()
- : _scripts(), _layoutCommands(), _memberToLayoutOrder(),
- _memberNameWildcards(), _cacheSectionOrder(), _cacheExpressionOrder(),
- _deliveredExprs(), _symbolTable() {}
+Sema::Sema() : _programPHDR(nullptr) {}
+
+std::error_code Sema::perform() {
+ llvm::StringMap<const PHDR *> phdrs;
-void Sema::perform() {
- for (auto &parser : _scripts)
- perform(parser->get());
+ 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 {
@@ -2254,6 +2513,15 @@ uint64_t Sema::getLinkerScriptExprValue(StringRef name) const {
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";
@@ -2287,7 +2555,7 @@ static bool wildcardMatch(StringRef pattern, StringRef name) {
switch (*j) {
case '*':
while (!wildcardMatch(pattern.drop_front(j - pattern.begin() + 1),
- name.drop_front(i - name.begin() + 1))) {
+ name.drop_front(i - name.begin()))) {
if (i == name.end())
return false;
++i;
@@ -2295,6 +2563,7 @@ static bool wildcardMatch(StringRef pattern, StringRef name) {
break;
case '?':
// Matches any character
+ ++i;
break;
case '[': {
// Matches a range of characters specified between brackets
@@ -2307,20 +2576,22 @@ static bool wildcardMatch(StringRef pattern, StringRef name) {
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;
}
- ++i;
}
// If our pattern has't consumed the entire string, it is not a match
@@ -2376,11 +2647,10 @@ int Sema::getLayoutOrder(const SectionKey &key, bool coarse) const {
// If we still couldn't find a rule for this input section, try to match
// wildcards
- for (auto I = _memberNameWildcards.begin(), E = _memberNameWildcards.end();
- I != E; ++I) {
- if (!wildcardMatch(I->first, key.memberPath))
+ for (const auto &I : _memberNameWildcards) {
+ if (!wildcardMatch(I.first, key.memberPath))
continue;
- int order = I->second;
+ int order = I.second;
int exprOrder = -1;
if ((exprOrder = matchSectionName(order, key)) >= 0) {
@@ -2490,6 +2760,74 @@ bool Sema::localCompare(int order, const SectionKey &lhs,
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 == '\\')
@@ -2553,12 +2891,5 @@ void Sema::linearizeAST(const Sections *sections) {
}
}
-void Sema::perform(const LinkerScript *ls) {
- for (const Command *c : ls->_commands) {
- if (const Sections *sec = dyn_cast<Sections>(c))
- linearizeAST(sec);
- }
-}
-
-} // End namespace script
+} // end namespace script
} // end namespace lld
diff --git a/lib/ReaderWriter/MachO/ArchHandler.h b/lib/ReaderWriter/MachO/ArchHandler.h
index 7f0961ebc807..120f5dfd4cd2 100644
--- a/lib/ReaderWriter/MachO/ArchHandler.h
+++ b/lib/ReaderWriter/MachO/ArchHandler.h
@@ -49,6 +49,12 @@ public:
return false;
}
+ /// Used by TLVPass to locate TLV References.
+ virtual bool isTLVAccess(const Reference &) const { return false; }
+
+ /// Used by the TLVPass to update TLV References.
+ virtual void updateReferenceToTLV(const Reference *) {}
+
/// Used by ShimPass to insert shims in branches that switch mode.
virtual bool isNonCallBranch(const Reference &) = 0;
diff --git a/lib/ReaderWriter/MachO/ArchHandler_arm.cpp b/lib/ReaderWriter/MachO/ArchHandler_arm.cpp
index 43f88a1d30d8..4e15a2d434c6 100644
--- a/lib/ReaderWriter/MachO/ArchHandler_arm.cpp
+++ b/lib/ReaderWriter/MachO/ArchHandler_arm.cpp
@@ -28,8 +28,8 @@ using llvm::support::little32_t;
class ArchHandler_arm : public ArchHandler {
public:
- ArchHandler_arm();
- virtual ~ArchHandler_arm();
+ ArchHandler_arm() = default;
+ ~ArchHandler_arm() override = default;
const Registry::KindStrings *kindStrings() override { return _sKindStrings; }
@@ -202,10 +202,6 @@ private:
// ArchHandler_arm
//===----------------------------------------------------------------------===//
-ArchHandler_arm::ArchHandler_arm() { }
-
-ArchHandler_arm::~ArchHandler_arm() { }
-
const Registry::KindStrings ArchHandler_arm::_sKindStrings[] = {
LLD_KIND_STRING_ENTRY(invalid),
LLD_KIND_STRING_ENTRY(modeThumbCode),
@@ -463,7 +459,6 @@ bool ArchHandler_arm::isArmMovt(uint32_t instruction) {
return (instruction & 0x0FF00000) == 0x03400000;
}
-
uint16_t ArchHandler_arm::getWordFromThumbMov(uint32_t instruction) {
assert(isThumbMovw(instruction) || isThumbMovt(instruction));
uint32_t i = ((instruction & 0x00000400) >> 10);
@@ -480,7 +475,6 @@ uint16_t ArchHandler_arm::getWordFromArmMov(uint32_t instruction) {
return (imm4 << 12) | imm12;
}
-
uint32_t ArchHandler_arm::setWordFromThumbMov(uint32_t instr, uint16_t word) {
assert(isThumbMovw(instr) || isThumbMovt(instr));
uint32_t imm4 = (word & 0xF000) >> 12;
@@ -497,7 +491,6 @@ uint32_t ArchHandler_arm::setWordFromArmMov(uint32_t instr, uint16_t word) {
return (instr & 0xFFF0F000) | (imm4 << 16) | imm12;
}
-
uint32_t ArchHandler_arm::clearThumbBit(uint32_t value, const Atom *target) {
// The assembler often adds one to the address of a thumb function.
// We need to undo that so it does not look like an addend.
@@ -619,7 +612,7 @@ std::error_code ArchHandler_arm::getReferenceInfo(
*addend += (clearThumbBit(instruction, *target) - reloc.value);
return std::error_code();
default:
- return make_dynamic_error_code(Twine("unsupported arm relocation type"));
+ return make_dynamic_error_code("unsupported arm relocation type");
}
return std::error_code();
}
@@ -777,7 +770,7 @@ ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1,
pointerDiff = true;
break;
default:
- return make_dynamic_error_code(Twine("unsupported arm relocation pair"));
+ return make_dynamic_error_code("unsupported arm relocation pair");
}
const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
std::error_code ec;
@@ -800,8 +793,8 @@ ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1,
if (ec)
return ec;
if (scatterable && (fromTarget != inAtom))
- return make_dynamic_error_code(Twine("SECTDIFF relocation where "
- "subtrahend label is not in atom"));
+ return make_dynamic_error_code(
+ "SECTDIFF relocation where subtrahend label is not in atom");
*kind = delta32;
value = clearThumbBit(instruction, *target);
*addend = (int32_t)(value - (toAddress - fixupAddress));
@@ -815,29 +808,28 @@ ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1,
if (ec)
return ec;
if (fromTarget != inAtom)
- return make_dynamic_error_code(
- Twine("ARM_RELOC_HALF_SECTDIFF relocation "
- "where subtrahend label is not in atom"));
+ return make_dynamic_error_code("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(Twine("expected movt instruction"));
+ return make_dynamic_error_code("expected movt instruction");
}
else {
if (!isThumbMovw(instruction))
- return make_dynamic_error_code(Twine("expected movw instruction"));
+ return make_dynamic_error_code("expected movw instruction");
}
instruction16 = getWordFromThumbMov(instruction);
}
else {
if (top) {
if (!isArmMovt(instruction))
- return make_dynamic_error_code(Twine("expected movt instruction"));
+ return make_dynamic_error_code("expected movt instruction");
}
else {
if (!isArmMovw(instruction))
- return make_dynamic_error_code(Twine("expected movw instruction"));
+ return make_dynamic_error_code("expected movw instruction");
}
instruction16 = getWordFromArmMov(instruction);
}
@@ -854,22 +846,22 @@ ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1,
if (thumbReloc) {
if (top) {
if (!isThumbMovt(instruction))
- return make_dynamic_error_code(Twine("expected movt instruction"));
+ return make_dynamic_error_code("expected movt instruction");
}
else {
if (!isThumbMovw(instruction))
- return make_dynamic_error_code(Twine("expected movw instruction"));
+ return make_dynamic_error_code("expected movw instruction");
}
instruction16 = getWordFromThumbMov(instruction);
}
else {
if (top) {
if (!isArmMovt(instruction))
- return make_dynamic_error_code(Twine("expected movt instruction"));
+ return make_dynamic_error_code("expected movt instruction");
}
else {
if (!isArmMovw(instruction))
- return make_dynamic_error_code(Twine("expected movw instruction"));
+ return make_dynamic_error_code("expected movw instruction");
}
instruction16 = getWordFromArmMov(instruction);
}
@@ -1041,7 +1033,6 @@ void ArchHandler_arm::generateAtomContent(const DefinedAtom &atom,
}
}
-
bool ArchHandler_arm::useExternalRelocationTo(const Atom &target) {
// Undefined symbols are referenced via external relocations.
if (isa<UndefinedAtom>(&target))
@@ -1410,7 +1401,6 @@ bool ArchHandler_arm::isThumbFunction(const DefinedAtom &atom) {
return false;
}
-
class Thumb2ToArmShimAtom : public SimpleDefinedAtom {
public:
Thumb2ToArmShimAtom(MachOFile &file, StringRef targetName,
@@ -1433,9 +1423,7 @@ public:
return DefinedAtom::typeCode;
}
- Alignment alignment() const override {
- return Alignment(2);
- }
+ Alignment alignment() const override { return 4; }
uint64_t size() const override {
return 12;
@@ -1458,7 +1446,6 @@ private:
StringRef _name;
};
-
class ArmToThumbShimAtom : public SimpleDefinedAtom {
public:
ArmToThumbShimAtom(MachOFile &file, StringRef targetName,
@@ -1479,9 +1466,7 @@ public:
return DefinedAtom::typeCode;
}
- Alignment alignment() const override {
- return Alignment(2);
- }
+ Alignment alignment() const override { return 4; }
uint64_t size() const override {
return 16;
@@ -1515,7 +1500,6 @@ const DefinedAtom *ArchHandler_arm::createShim(MachOFile &file,
return new (file.allocator()) ArmToThumbShimAtom(file, targetName, target);
}
-
std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_arm() {
return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_arm());
}
diff --git a/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp b/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp
index fd9984b89ce6..5e5a426b310b 100644
--- a/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp
+++ b/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp
@@ -31,8 +31,8 @@ using llvm::support::little64_t;
class ArchHandler_arm64 : public ArchHandler {
public:
- ArchHandler_arm64();
- virtual ~ArchHandler_arm64();
+ ArchHandler_arm64() = default;
+ ~ArchHandler_arm64() override = default;
const Registry::KindStrings *kindStrings() override { return _sKindStrings; }
@@ -50,6 +50,9 @@ public:
case gotOffset12:
canBypassGOT = true;
return true;
+ case delta32ToGOT:
+ canBypassGOT = false;
+ return true;
case imageOffsetGot:
canBypassGOT = false;
return true;
@@ -74,6 +77,9 @@ public:
const_cast<Reference *>(ref)->setKindValue(targetNowGOT ?
offset12scale8 : addOffset12);
break;
+ case delta32ToGOT:
+ const_cast<Reference *>(ref)->setKindValue(delta32);
+ break;
case imageOffsetGot:
const_cast<Reference *>(ref)->setKindValue(imageOffset);
break;
@@ -213,10 +219,6 @@ private:
static uint32_t setImm12(uint32_t instr, uint32_t offset);
};
-ArchHandler_arm64::ArchHandler_arm64() {}
-
-ArchHandler_arm64::~ArchHandler_arm64() {}
-
const Registry::KindStrings ArchHandler_arm64::_sKindStrings[] = {
LLD_KIND_STRING_ENTRY(invalid),
LLD_KIND_STRING_ENTRY(branch26),
@@ -437,7 +439,7 @@ std::error_code ArchHandler_arm64::getReferenceInfo(
*addend = 0;
return std::error_code();
default:
- return make_dynamic_error_code(Twine("unsupported arm64 relocation type"));
+ return make_dynamic_error_code("unsupported arm64 relocation type");
}
}
@@ -480,6 +482,9 @@ std::error_code ArchHandler_arm64::getPairReferenceInfo(
*kind = delta64;
if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
return ec;
+ // 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");
*addend = (int64_t)*(const little64_t *)fixupContent + offsetInAtom;
return std::error_code();
case ((ARM64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 |
@@ -491,7 +496,7 @@ std::error_code ArchHandler_arm64::getPairReferenceInfo(
*addend = (int32_t)*(const little32_t *)fixupContent + offsetInAtom;
return std::error_code();
default:
- return make_dynamic_error_code(Twine("unsupported arm64 relocation pair"));
+ return make_dynamic_error_code("unsupported arm64 relocation pair");
}
}
@@ -669,7 +674,7 @@ void ArchHandler_arm64::applyFixupRelocatable(const Reference &ref,
*loc32 = ref.addend() + inAtomAddress - fixupAddress;
return;
case negDelta32:
- *loc32 = fixupAddress - inAtomAddress + ref.addend();
+ *loc32 = fixupAddress - targetAddress + ref.addend();
return;
case pointer64ToGOT:
*loc64 = 0;
diff --git a/lib/ReaderWriter/MachO/ArchHandler_x86.cpp b/lib/ReaderWriter/MachO/ArchHandler_x86.cpp
index 19c8780e707a..7aac2584d078 100644
--- a/lib/ReaderWriter/MachO/ArchHandler_x86.cpp
+++ b/lib/ReaderWriter/MachO/ArchHandler_x86.cpp
@@ -30,8 +30,8 @@ using llvm::support::little32_t;
class ArchHandler_x86 : public ArchHandler {
public:
- ArchHandler_x86();
- virtual ~ArchHandler_x86();
+ ArchHandler_x86() = default;
+ ~ArchHandler_x86() override = default;
const Registry::KindStrings *kindStrings() override { return _sKindStrings; }
@@ -49,9 +49,11 @@ public:
bool needsCompactUnwind() override {
return false;
}
+
Reference::KindValue imageOffsetKind() override {
return invalid;
}
+
Reference::KindValue imageOffsetKindIndirect() override {
return invalid;
}
@@ -68,7 +70,6 @@ public:
return invalid;
}
-
uint32_t dwarfCompactUnwindType() override {
return 0x04000000U;
}
@@ -169,10 +170,6 @@ private:
// ArchHandler_x86
//===----------------------------------------------------------------------===//
-ArchHandler_x86::ArchHandler_x86() {}
-
-ArchHandler_x86::~ArchHandler_x86() { }
-
const Registry::KindStrings ArchHandler_x86::_sKindStrings[] = {
LLD_KIND_STRING_ENTRY(invalid),
LLD_KIND_STRING_ENTRY(modeCode),
@@ -334,7 +331,7 @@ ArchHandler_x86::getReferenceInfo(const Relocation &reloc,
*addend = *(const ulittle32_t *)fixupContent - reloc.value;
break;
default:
- return make_dynamic_error_code(Twine("unsupported i386 relocation type"));
+ return make_dynamic_error_code("unsupported i386 relocation type");
}
return std::error_code();
}
@@ -376,8 +373,8 @@ ArchHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1,
return ec;
if (fromTarget != inAtom) {
if (*target != inAtom)
- return make_dynamic_error_code(Twine("SECTDIFF relocation where "
- "neither target is in atom"));
+ return make_dynamic_error_code(
+ "SECTDIFF relocation where neither target is in atom");
*kind = negDelta32;
*addend = toAddress - value - fromAddress;
*target = fromTarget;
@@ -400,7 +397,7 @@ ArchHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1,
return std::error_code();
break;
default:
- return make_dynamic_error_code(Twine("unsupported i386 relocation type"));
+ return make_dynamic_error_code("unsupported i386 relocation type");
}
}
@@ -545,7 +542,6 @@ bool ArchHandler_x86::useExternalRelocationTo(const Atom &target) {
return false;
}
-
void ArchHandler_x86::appendSectionRelocations(
const DefinedAtom &atom,
uint64_t atomSectionOffset,
@@ -633,7 +629,6 @@ void ArchHandler_x86::appendSectionRelocations(
}
}
-
std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_x86() {
return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_x86());
}
diff --git a/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp b/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
index 81fe1af42d7e..c57a00359e33 100644
--- a/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
+++ b/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
@@ -30,8 +30,8 @@ using llvm::support::little64_t;
class ArchHandler_x86_64 : public ArchHandler {
public:
- ArchHandler_x86_64();
- virtual ~ArchHandler_x86_64();
+ ArchHandler_x86_64() = default;
+ ~ArchHandler_x86_64() override = default;
const Registry::KindStrings *kindStrings() override { return _sKindStrings; }
@@ -59,6 +59,19 @@ public:
}
}
+ bool isTLVAccess(const Reference &ref) const override {
+ assert(ref.kindNamespace() == Reference::KindNamespace::mach_o);
+ assert(ref.kindArch() == Reference::KindArch::x86_64);
+ return ref.kindValue() == ripRel32Tlv;
+ }
+
+ void updateReferenceToTLV(const Reference *ref) override {
+ assert(ref->kindNamespace() == Reference::KindNamespace::mach_o);
+ assert(ref->kindArch() == Reference::KindArch::x86_64);
+ assert(ref->kindValue() == ripRel32Tlv);
+ const_cast<Reference*>(ref)->setKindValue(ripRel32);
+ }
+
/// Used by GOTPass to update GOT References
void updateReferenceToGOT(const Reference *ref, bool targetNowGOT) override {
assert(ref->kindNamespace() == Reference::KindNamespace::mach_o);
@@ -82,9 +95,11 @@ public:
bool needsCompactUnwind() override {
return true;
}
+
Reference::KindValue imageOffsetKind() override {
return imageOffset;
}
+
Reference::KindValue imageOffsetKindIndirect() override {
return imageOffsetGot;
}
@@ -168,8 +183,12 @@ private:
ripRel32Minus2, /// ex: movw $0x1234, _foo(%rip)
ripRel32Minus4, /// ex: movl $0x12345678, _foo(%rip)
ripRel32Anon, /// ex: movq L1(%rip), %rax
+ ripRel32Minus1Anon, /// ex: movb $0x12, L1(%rip)
+ ripRel32Minus2Anon, /// ex: movw $0x1234, L1(%rip)
+ ripRel32Minus4Anon, /// ex: movw $0x12345678, L1(%rip)
ripRel32GotLoad, /// ex: movq _foo@GOTPCREL(%rip), %rax
ripRel32Got, /// ex: pushq _foo@GOTPCREL(%rip)
+ ripRel32Tlv, /// ex: movq _foo@TLVP(%rip), %rdi
pointer64, /// ex: .quad _foo
pointer64Anon, /// ex: .quad L1
delta64, /// ex: .quad _foo - .
@@ -192,6 +211,8 @@ private:
/// relocatable object (yay for implicit contracts!).
unwindInfoToEhFrame, /// Fix low 24 bits of compact unwind encoding to
/// refer to __eh_frame entry.
+ tlvInitSectionOffset /// Location contains offset tlv init-value atom
+ /// within the __thread_data section.
};
Reference::KindValue kindFromReloc(const normalized::Relocation &reloc);
@@ -209,18 +230,18 @@ private:
uint64_t inAtomAddress);
};
-
-ArchHandler_x86_64::ArchHandler_x86_64() { }
-
-ArchHandler_x86_64::~ArchHandler_x86_64() { }
-
const Registry::KindStrings ArchHandler_x86_64::_sKindStrings[] = {
LLD_KIND_STRING_ENTRY(invalid), LLD_KIND_STRING_ENTRY(branch32),
LLD_KIND_STRING_ENTRY(ripRel32), LLD_KIND_STRING_ENTRY(ripRel32Minus1),
LLD_KIND_STRING_ENTRY(ripRel32Minus2), LLD_KIND_STRING_ENTRY(ripRel32Minus4),
- LLD_KIND_STRING_ENTRY(ripRel32Anon), LLD_KIND_STRING_ENTRY(ripRel32GotLoad),
+ LLD_KIND_STRING_ENTRY(ripRel32Anon),
+ LLD_KIND_STRING_ENTRY(ripRel32Minus1Anon),
+ LLD_KIND_STRING_ENTRY(ripRel32Minus2Anon),
+ LLD_KIND_STRING_ENTRY(ripRel32Minus4Anon),
+ LLD_KIND_STRING_ENTRY(ripRel32GotLoad),
LLD_KIND_STRING_ENTRY(ripRel32GotLoadNowLea),
- LLD_KIND_STRING_ENTRY(ripRel32Got), LLD_KIND_STRING_ENTRY(lazyPointer),
+ LLD_KIND_STRING_ENTRY(ripRel32Got), LLD_KIND_STRING_ENTRY(ripRel32Tlv),
+ LLD_KIND_STRING_ENTRY(lazyPointer),
LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
LLD_KIND_STRING_ENTRY(pointer64), LLD_KIND_STRING_ENTRY(pointer64Anon),
LLD_KIND_STRING_ENTRY(delta32), LLD_KIND_STRING_ENTRY(delta64),
@@ -229,6 +250,7 @@ const Registry::KindStrings ArchHandler_x86_64::_sKindStrings[] = {
LLD_KIND_STRING_ENTRY(imageOffset), LLD_KIND_STRING_ENTRY(imageOffsetGot),
LLD_KIND_STRING_ENTRY(unwindFDEToFunction),
LLD_KIND_STRING_ENTRY(unwindInfoToEhFrame),
+ LLD_KIND_STRING_ENTRY(tlvInitSectionOffset),
LLD_KIND_STRING_END
};
@@ -301,14 +323,22 @@ ArchHandler_x86_64::kindFromReloc(const Relocation &reloc) {
return ripRel32Anon;
case X86_64_RELOC_SIGNED_1 | rPcRel | rExtern | rLength4:
return ripRel32Minus1;
+ case X86_64_RELOC_SIGNED_1 | rPcRel | rLength4:
+ return ripRel32Minus1Anon;
case X86_64_RELOC_SIGNED_2 | rPcRel | rExtern | rLength4:
return ripRel32Minus2;
+ case X86_64_RELOC_SIGNED_2 | rPcRel | rLength4:
+ return ripRel32Minus2Anon;
case X86_64_RELOC_SIGNED_4 | rPcRel | rExtern | rLength4:
return ripRel32Minus4;
+ case X86_64_RELOC_SIGNED_4 | rPcRel | rLength4:
+ return ripRel32Minus4Anon;
case X86_64_RELOC_GOT_LOAD | rPcRel | rExtern | rLength4:
return ripRel32GotLoad;
case X86_64_RELOC_GOT | rPcRel | rExtern | rLength4:
return ripRel32Got;
+ case X86_64_RELOC_TLV | rPcRel | rExtern | rLength4:
+ return ripRel32Tlv;
case X86_64_RELOC_UNSIGNED | rExtern | rLength8:
return pointer64;
case X86_64_RELOC_UNSIGNED | rLength8:
@@ -331,7 +361,7 @@ ArchHandler_x86_64::getReferenceInfo(const Relocation &reloc,
typedef std::error_code E;
*kind = kindFromReloc(reloc);
if (*kind == invalid)
- return make_dynamic_error_code(Twine("unknown type"));
+ return make_dynamic_error_code("unknown type");
const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
uint64_t targetAddress;
switch (*kind) {
@@ -359,16 +389,34 @@ ArchHandler_x86_64::getReferenceInfo(const Relocation &reloc,
case ripRel32Anon:
targetAddress = fixupAddress + 4 + *(const little32_t *)fixupContent;
return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+ case ripRel32Minus1Anon:
+ targetAddress = fixupAddress + 5 + *(const little32_t *)fixupContent;
+ return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+ case ripRel32Minus2Anon:
+ targetAddress = fixupAddress + 6 + *(const little32_t *)fixupContent;
+ return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+ case ripRel32Minus4Anon:
+ targetAddress = fixupAddress + 8 + *(const little32_t *)fixupContent;
+ return atomFromAddress(reloc.symbol, targetAddress, target, addend);
case ripRel32GotLoad:
case ripRel32Got:
+ case ripRel32Tlv:
if (E ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = *(const little32_t *)fixupContent;
return std::error_code();
+ case tlvInitSectionOffset:
case pointer64:
if (E ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
- *addend = *(const little64_t *)fixupContent;
+ // 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.
+ if (inAtom->contentType() == DefinedAtom::typeThunkTLV &&
+ offsetInAtom == 16) {
+ *kind = tlvInitSectionOffset;
+ assert(*addend == 0 && "TLV-init has non-zero addend?");
+ } else
+ *addend = *(const little64_t *)fixupContent;
return std::error_code();
case pointer64Anon:
targetAddress = *(const little64_t *)fixupContent;
@@ -413,7 +461,7 @@ ArchHandler_x86_64::getPairReferenceInfo(const normalized::Relocation &reloc1,
Reference::Addend *addend) {
*kind = kindFromRelocPair(reloc1, reloc2);
if (*kind == invalid)
- return make_dynamic_error_code(Twine("unknown pair"));
+ return make_dynamic_error_code("unknown pair");
const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
typedef std::error_code E;
uint64_t targetAddress;
@@ -421,7 +469,7 @@ ArchHandler_x86_64::getPairReferenceInfo(const normalized::Relocation &reloc1,
if (E ec = atomFromSymbolIndex(reloc1.symbol, &fromTarget))
return ec;
if (fromTarget != inAtom)
- return make_dynamic_error_code(Twine("pointer diff not in base atom"));
+ return make_dynamic_error_code("pointer diff not in base atom");
switch (*kind) {
case delta64:
if (E ec = atomFromSymbolIndex(reloc2.symbol, target))
@@ -486,19 +534,26 @@ void ArchHandler_x86_64::applyFixupFinal(
case ripRel32Anon:
case ripRel32Got:
case ripRel32GotLoad:
+ case ripRel32Tlv:
*loc32 = targetAddress - (fixupAddress + 4) + ref.addend();
return;
case pointer64:
case pointer64Anon:
*loc64 = targetAddress + ref.addend();
return;
+ case tlvInitSectionOffset:
+ *loc64 = targetAddress - findSectionAddress(*ref.target()) + ref.addend();
+ return;
case ripRel32Minus1:
+ case ripRel32Minus1Anon:
*loc32 = targetAddress - (fixupAddress + 5) + ref.addend();
return;
case ripRel32Minus2:
+ case ripRel32Minus2Anon:
*loc32 = targetAddress - (fixupAddress + 6) + ref.addend();
return;
case ripRel32Minus4:
+ case ripRel32Minus4Anon:
*loc32 = targetAddress - (fixupAddress + 8) + ref.addend();
return;
case delta32:
@@ -542,7 +597,6 @@ void ArchHandler_x86_64::applyFixupFinal(
llvm_unreachable("invalid x86_64 Reference Kind");
}
-
void ArchHandler_x86_64::applyFixupRelocatable(const Reference &ref,
uint8_t *loc,
uint64_t fixupAddress,
@@ -558,11 +612,13 @@ void ArchHandler_x86_64::applyFixupRelocatable(const Reference &ref,
case ripRel32:
case ripRel32Got:
case ripRel32GotLoad:
+ case ripRel32Tlv:
*loc32 = ref.addend();
return;
case ripRel32Anon:
*loc32 = (targetAddress - (fixupAddress + 4)) + ref.addend();
return;
+ case tlvInitSectionOffset:
case pointer64:
*loc64 = ref.addend();
return;
@@ -572,12 +628,21 @@ void ArchHandler_x86_64::applyFixupRelocatable(const Reference &ref,
case ripRel32Minus1:
*loc32 = ref.addend() - 1;
return;
+ case ripRel32Minus1Anon:
+ *loc32 = (targetAddress - (fixupAddress + 5)) + ref.addend();
+ return;
case ripRel32Minus2:
*loc32 = ref.addend() - 2;
return;
+ case ripRel32Minus2Anon:
+ *loc32 = (targetAddress - (fixupAddress + 6)) + ref.addend();
+ return;
case ripRel32Minus4:
*loc32 = ref.addend() - 4;
return;
+ case ripRel32Minus4Anon:
+ *loc32 = (targetAddress - (fixupAddress + 8)) + ref.addend();
+ return;
case delta32:
*loc32 = ref.addend() + inAtomAddress - fixupAddress;
return;
@@ -638,7 +703,7 @@ void ArchHandler_x86_64::appendSectionRelocations(
return;
case ripRel32Anon:
appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
- X86_64_RELOC_SIGNED | rPcRel | rLength4 );
+ X86_64_RELOC_SIGNED | rPcRel | rLength4 );
return;
case ripRel32Got:
appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
@@ -648,6 +713,11 @@ void ArchHandler_x86_64::appendSectionRelocations(
appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
X86_64_RELOC_GOT_LOAD | rPcRel | rExtern | rLength4 );
return;
+ case ripRel32Tlv:
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_TLV | rPcRel | rExtern | rLength4 );
+ return;
+ case tlvInitSectionOffset:
case pointer64:
appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
X86_64_RELOC_UNSIGNED | rExtern | rLength8);
@@ -660,14 +730,26 @@ void ArchHandler_x86_64::appendSectionRelocations(
appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
X86_64_RELOC_SIGNED_1 | rPcRel | rExtern | rLength4 );
return;
+ case ripRel32Minus1Anon:
+ appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_SIGNED_1 | rPcRel | rLength4 );
+ return;
case ripRel32Minus2:
appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
X86_64_RELOC_SIGNED_2 | rPcRel | rExtern | rLength4 );
return;
+ case ripRel32Minus2Anon:
+ appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_SIGNED_2 | rPcRel | rLength4 );
+ return;
case ripRel32Minus4:
appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
X86_64_RELOC_SIGNED_4 | rPcRel | rExtern | rLength4 );
return;
+ case ripRel32Minus4Anon:
+ appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_SIGNED_4 | rPcRel | rLength4 );
+ return;
case delta32:
appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
X86_64_RELOC_SUBTRACTOR | rExtern | rLength4 );
@@ -714,7 +796,6 @@ void ArchHandler_x86_64::appendSectionRelocations(
llvm_unreachable("unknown x86_64 Reference Kind");
}
-
std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_x86_64() {
return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_x86_64());
}
diff --git a/lib/ReaderWriter/MachO/Atoms.h b/lib/ReaderWriter/MachO/Atoms.h
index 8d60c1a163a6..9f2e5acad99a 100644
--- a/lib/ReaderWriter/MachO/Atoms.h
+++ b/lib/ReaderWriter/MachO/Atoms.h
@@ -25,11 +25,11 @@ public:
// Constructor for zero-fill content
MachODefinedAtom(const File &f, const StringRef name, Scope scope,
- uint64_t size, bool noDeadStrip, Alignment align)
+ ContentType type, uint64_t size, bool noDeadStrip,
+ Alignment align)
: SimpleDefinedAtom(f), _name(name),
_content(ArrayRef<uint8_t>(nullptr, size)), _align(align),
- _contentType(DefinedAtom::typeZeroFill),
- _scope(scope), _merge(mergeNo), _thumb(false),
+ _contentType(type), _scope(scope), _merge(mergeNo), _thumb(false),
_noDeadStrip(noDeadStrip) {}
uint64_t size() const override { return _content.size(); }
@@ -103,7 +103,6 @@ private:
StringRef _sectionName;
};
-
class MachOTentativeDefAtom : public SimpleDefinedAtom {
public:
MachOTentativeDefAtom(const File &f, const StringRef name, Scope scope,
@@ -126,7 +125,7 @@ public:
ArrayRef<uint8_t> rawContent() const override { return ArrayRef<uint8_t>(); }
private:
- const StringRef _name;
+ const std::string _name;
const Scope _scope;
const uint64_t _size;
const DefinedAtom::Alignment _align;
@@ -138,32 +137,26 @@ public:
StringRef dylibInstallName, bool weakDef)
: SharedLibraryAtom(), _file(file), _name(name),
_dylibInstallName(dylibInstallName) {}
- virtual ~MachOSharedLibraryAtom() {}
+ ~MachOSharedLibraryAtom() override = default;
- virtual StringRef loadName() const override {
- return _dylibInstallName;
- }
+ StringRef loadName() const override { return _dylibInstallName; }
- virtual bool canBeNullAtRuntime() const override {
+ bool canBeNullAtRuntime() const override {
// FIXME: this may actually be changeable. For now, all symbols are strongly
// defined though.
return false;
}
- virtual const File& file() const override {
- return _file;
- }
+ const File &file() const override { return _file; }
- virtual StringRef name() const override {
- return _name;
- }
+ StringRef name() const override { return _name; }
- virtual Type type() const override {
+ Type type() const override {
// Unused in MachO (I think).
return Type::Unknown;
}
- virtual uint64_t size() const override {
+ uint64_t size() const override {
// Unused in MachO (I think)
return 0;
}
@@ -174,8 +167,7 @@ private:
StringRef _dylibInstallName;
};
+} // namespace mach_o
+} // namespace lld
-} // mach_o
-} // lld
-
-#endif
+#endif // LLD_READER_WRITER_MACHO_ATOMS_H
diff --git a/lib/ReaderWriter/MachO/CMakeLists.txt b/lib/ReaderWriter/MachO/CMakeLists.txt
index e396537c63c8..7ce782af6f99 100644
--- a/lib/ReaderWriter/MachO/CMakeLists.txt
+++ b/lib/ReaderWriter/MachO/CMakeLists.txt
@@ -15,6 +15,7 @@ add_llvm_library(lldMachO
MachONormalizedFileYAML.cpp
ShimPass.cpp
StubsPass.cpp
+ TLVPass.cpp
WriterMachO.cpp
LINK_LIBS
lldCore
diff --git a/lib/ReaderWriter/MachO/CompactUnwindPass.cpp b/lib/ReaderWriter/MachO/CompactUnwindPass.cpp
index fc8608383e5d..4b8644a67e70 100644
--- a/lib/ReaderWriter/MachO/CompactUnwindPass.cpp
+++ b/lib/ReaderWriter/MachO/CompactUnwindPass.cpp
@@ -1,4 +1,4 @@
-//===- lib/ReaderWriter/MachO/CompactUnwindPass.cpp -----------------------===//
+//===- lib/ReaderWriter/MachO/CompactUnwindPass.cpp -------------*- C++ -*-===//
//
// The LLVM Linker
//
@@ -92,7 +92,7 @@ public:
return DefinedAtom::typeProcessedUnwindInfo;
}
- Alignment alignment() const override { return Alignment(2); }
+ Alignment alignment() const override { return 4; }
uint64_t size() const override { return _contents.size(); }
@@ -272,12 +272,12 @@ private:
class CompactUnwindPass : public Pass {
public:
CompactUnwindPass(const MachOLinkingContext &context)
- : _context(context), _archHandler(_context.archHandler()),
+ : _ctx(context), _archHandler(_ctx.archHandler()),
_file("<mach-o Compact Unwind Pass>"),
- _isBig(MachOLinkingContext::isBigEndian(_context.arch())) {}
+ _isBig(MachOLinkingContext::isBigEndian(_ctx.arch())) {}
private:
- void perform(std::unique_ptr<MutableFile> &mergedFile) override {
+ std::error_code perform(SimpleFile &mergedFile) override {
DEBUG(llvm::dbgs() << "MachO Compact Unwind pass\n");
std::map<const Atom *, CompactUnwindEntry> unwindLocs;
@@ -294,7 +294,7 @@ private:
// Skip rest of pass if no unwind info.
if (unwindLocs.empty() && dwarfFrames.empty())
- return;
+ return std::error_code();
// 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
@@ -310,6 +310,9 @@ private:
std::vector<CompactUnwindEntry> unwindInfos = createUnwindInfoEntries(
mergedFile, unwindLocs, personalities, dwarfFrames);
+ // Remove any unused eh-frame atoms.
+ pruneUnusedEHFrames(mergedFile, unwindInfos, unwindLocs, dwarfFrames);
+
// Finally, we can start creating pages based on these entries.
DEBUG(llvm::dbgs() << " Splitting entries into pages\n");
@@ -339,24 +342,26 @@ private:
<< " has " << entriesInPage << " entries\n");
} while (pageStart < unwindInfos.size());
- UnwindInfoAtom *unwind = new (_file.allocator())
+ auto *unwind = new (_file.allocator())
UnwindInfoAtom(_archHandler, _file, _isBig, personalities,
commonEncodings, pages, numLSDAs);
- mergedFile->addAtom(*unwind);
+ mergedFile.addAtom(*unwind);
// Finally, remove all __compact_unwind atoms now that we've processed them.
- mergedFile->removeDefinedAtomsIf([](const DefinedAtom *atom) {
+ mergedFile.removeDefinedAtomsIf([](const DefinedAtom *atom) {
return atom->contentType() == DefinedAtom::typeCompactUnwindInfo;
});
+
+ return std::error_code();
}
void collectCompactUnwindEntries(
- std::unique_ptr<MutableFile> &mergedFile,
+ const SimpleFile &mergedFile,
std::map<const Atom *, CompactUnwindEntry> &unwindLocs,
std::vector<const Atom *> &personalities, uint32_t &numLSDAs) {
DEBUG(llvm::dbgs() << " Collecting __compact_unwind entries\n");
- for (const DefinedAtom *atom : mergedFile->defined()) {
+ for (const DefinedAtom *atom : mergedFile.defined()) {
if (atom->contentType() != DefinedAtom::typeCompactUnwindInfo)
continue;
@@ -422,9 +427,9 @@ private:
}
void
- collectDwarfFrameEntries(std::unique_ptr<MutableFile> &mergedFile,
+ collectDwarfFrameEntries(const SimpleFile &mergedFile,
std::map<const Atom *, const Atom *> &dwarfFrames) {
- for (const DefinedAtom *ehFrameAtom : mergedFile->defined()) {
+ for (const DefinedAtom *ehFrameAtom : mergedFile.defined()) {
if (ehFrameAtom->contentType() != DefinedAtom::typeCFI)
continue;
if (ArchHandler::isDwarfCIE(_isBig, ehFrameAtom))
@@ -442,7 +447,7 @@ private:
/// + A synthesised reference to __eh_frame if there's no __compact_unwind
/// or too many personality functions to be accommodated.
std::vector<CompactUnwindEntry> createUnwindInfoEntries(
- const std::unique_ptr<MutableFile> &mergedFile,
+ const SimpleFile &mergedFile,
const std::map<const Atom *, CompactUnwindEntry> &unwindLocs,
const std::vector<const Atom *> &personalities,
const std::map<const Atom *, const Atom *> &dwarfFrames) {
@@ -452,7 +457,7 @@ private:
// The final order in the __unwind_info section must be derived from the
// order of typeCode atoms, since that's how they'll be put into the object
// file eventually (yuck!).
- for (const DefinedAtom *atom : mergedFile->defined()) {
+ for (const DefinedAtom *atom : mergedFile.defined()) {
if (atom->contentType() != DefinedAtom::typeCode)
continue;
@@ -468,6 +473,53 @@ private:
return unwindInfos;
}
+ /// Remove unused EH frames.
+ ///
+ /// An EH frame is considered unused if there is a corresponding compact
+ /// unwind atom that doesn't require the EH frame.
+ void pruneUnusedEHFrames(
+ SimpleFile &mergedFile,
+ const std::vector<CompactUnwindEntry> &unwindInfos,
+ const std::map<const Atom *, CompactUnwindEntry> &unwindLocs,
+ const std::map<const Atom *, const Atom *> &dwarfFrames) {
+
+ // Worklist of all 'used' FDEs.
+ std::vector<const DefinedAtom *> usedDwarfWorklist;
+
+ // We have to check two conditions when building the worklist:
+ // (1) EH frames used by compact unwind entries.
+ for (auto &entry : unwindInfos)
+ if (entry.ehFrame)
+ usedDwarfWorklist.push_back(cast<DefinedAtom>(entry.ehFrame));
+
+ // (2) EH frames that reference functions with no corresponding compact
+ // unwind info.
+ for (auto &entry : dwarfFrames)
+ if (!unwindLocs.count(entry.first))
+ usedDwarfWorklist.push_back(cast<DefinedAtom>(entry.second));
+
+ // Add all transitively referenced CFI atoms by processing the worklist.
+ std::set<const Atom *> usedDwarfFrames;
+ while (!usedDwarfWorklist.empty()) {
+ const DefinedAtom *cfiAtom = usedDwarfWorklist.back();
+ usedDwarfWorklist.pop_back();
+ usedDwarfFrames.insert(cfiAtom);
+ for (const auto *ref : *cfiAtom) {
+ const DefinedAtom *cfiTarget = dyn_cast<DefinedAtom>(ref->target());
+ if (cfiTarget->contentType() == DefinedAtom::typeCFI)
+ usedDwarfWorklist.push_back(cfiTarget);
+ }
+ }
+
+ // Finally, delete all unreferenced CFI atoms.
+ mergedFile.removeDefinedAtomsIf([&](const DefinedAtom *atom) {
+ if ((atom->contentType() == DefinedAtom::typeCFI) &&
+ !usedDwarfFrames.count(atom))
+ return true;
+ return false;
+ });
+ }
+
CompactUnwindEntry finalizeUnwindInfoEntryForAtom(
const DefinedAtom *function,
const std::map<const Atom *, CompactUnwindEntry> &unwindLocs,
@@ -496,7 +548,6 @@ private:
}
}
-
auto personality = std::find(personalities.begin(), personalities.end(),
entry.personalityFunction);
uint32_t personalityIdx = personality == personalities.end()
@@ -515,7 +566,7 @@ private:
return entry;
}
- const MachOLinkingContext &_context;
+ const MachOLinkingContext &_ctx;
mach_o::ArchHandler &_archHandler;
MachOFile _file;
bool _isBig;
diff --git a/lib/ReaderWriter/MachO/ExecutableAtoms.hpp b/lib/ReaderWriter/MachO/ExecutableAtoms.h
index cd562de216d9..2e99af903dbd 100644
--- a/lib/ReaderWriter/MachO/ExecutableAtoms.hpp
+++ b/lib/ReaderWriter/MachO/ExecutableAtoms.h
@@ -1,4 +1,4 @@
-//===- lib/ReaderWriter/MachO/ExecutableAtoms.hpp -------------------------===//
+//===- lib/ReaderWriter/MachO/ExecutableAtoms.h ---------------------------===//
//
// The LLVM Linker
//
@@ -97,36 +97,33 @@ public:
File *find(StringRef sym, bool dataSymbolOnly) override {
if (sym.equals("___dso_handle") || sym.equals(_machHeaderSymbolName)) {
- _definedAtoms._atoms.push_back(new (allocator()) MachODefinedAtom(
+ _definedAtoms.push_back(new (allocator()) MachODefinedAtom(
*this, sym, DefinedAtom::scopeLinkageUnit,
DefinedAtom::typeMachHeader, DefinedAtom::mergeNo, false, false,
- ArrayRef<uint8_t>(), DefinedAtom::Alignment(12,0)));
+ ArrayRef<uint8_t>(), DefinedAtom::Alignment(4096)));
return this;
}
return nullptr;
}
- const atom_collection<DefinedAtom> &defined() const override {
+ const AtomVector<DefinedAtom> &defined() const override {
return _definedAtoms;
}
- const atom_collection<UndefinedAtom> &undefined() const override {
- return _undefinedAtoms;
+ const AtomVector<UndefinedAtom> &undefined() const override {
+ return _noUndefinedAtoms;
}
- const atom_collection<SharedLibraryAtom> &sharedLibrary() const override {
- return _sharedLibraryAtoms;
+ const AtomVector<SharedLibraryAtom> &sharedLibrary() const override {
+ return _noSharedLibraryAtoms;
}
- const atom_collection<AbsoluteAtom> &absolute() const override {
- return _absoluteAtoms;
+ const AtomVector<AbsoluteAtom> &absolute() const override {
+ return _noAbsoluteAtoms;
}
private:
- mutable atom_collection_vector<DefinedAtom> _definedAtoms;
- atom_collection_vector<UndefinedAtom> _undefinedAtoms;
- atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
- atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
+ mutable AtomVector<DefinedAtom> _definedAtoms;
StringRef _machHeaderSymbolName;
};
diff --git a/lib/ReaderWriter/MachO/File.h b/lib/ReaderWriter/MachO/File.h
index 913644ec1fc0..c97dfa142b8d 100644
--- a/lib/ReaderWriter/MachO/File.h
+++ b/lib/ReaderWriter/MachO/File.h
@@ -1,4 +1,4 @@
-//===- lib/ReaderWriter/MachO/File.h --------------------------------------===//
+//===- lib/ReaderWriter/MachO/File.h ----------------------------*- C++ -*-===//
//
// The LLVM Linker
//
@@ -44,8 +44,8 @@ public:
}
DefinedAtom::Alignment align(
inSection->alignment,
- sectionOffset % ((uint64_t)1 << inSection->alignment));
- MachODefinedAtom *atom =
+ sectionOffset % inSection->alignment);
+ auto *atom =
new (allocator()) MachODefinedAtom(*this, name, scope, type, merge,
thumb, noDeadStrip, content, align);
addAtomForSection(inSection, atom, sectionOffset);
@@ -67,8 +67,8 @@ public:
}
DefinedAtom::Alignment align(
inSection->alignment,
- sectionOffset % ((uint64_t)1 << inSection->alignment));
- MachODefinedCustomSectionAtom *atom =
+ sectionOffset % inSection->alignment);
+ auto *atom =
new (allocator()) MachODefinedCustomSectionAtom(*this, name, scope, type,
merge, thumb,
noDeadStrip, content,
@@ -86,10 +86,23 @@ public:
}
DefinedAtom::Alignment align(
inSection->alignment,
- sectionOffset % ((uint64_t)1 << inSection->alignment));
- MachODefinedAtom *atom =
- new (allocator()) MachODefinedAtom(*this, name, scope, size, noDeadStrip,
- align);
+ sectionOffset % inSection->alignment);
+
+ DefinedAtom::ContentType type = DefinedAtom::typeUnknown;
+ switch (inSection->type) {
+ case llvm::MachO::S_ZEROFILL:
+ type = DefinedAtom::typeZeroFill;
+ break;
+ case llvm::MachO::S_THREAD_LOCAL_ZEROFILL:
+ type = DefinedAtom::typeTLVInitialZeroFill;
+ break;
+ default:
+ llvm_unreachable("Unrecognized zero-fill section");
+ }
+
+ auto *atom =
+ new (allocator()) MachODefinedAtom(*this, name, scope, type, size,
+ noDeadStrip, align);
addAtomForSection(inSection, atom, sectionOffset);
}
@@ -98,8 +111,7 @@ public:
// Make a copy of the atom's name that is owned by this file.
name = name.copy(allocator());
}
- SimpleUndefinedAtom *atom =
- new (allocator()) SimpleUndefinedAtom(*this, name);
+ auto *atom = new (allocator()) SimpleUndefinedAtom(*this, name);
addAtom(*atom);
_undefAtoms[name] = atom;
}
@@ -110,7 +122,7 @@ public:
// Make a copy of the atom's name that is owned by this file.
name = name.copy(allocator());
}
- MachOTentativeDefAtom *atom =
+ auto *atom =
new (allocator()) MachOTentativeDefAtom(*this, name, scope, size, align);
addAtom(*atom);
_undefAtoms[name] = atom;
@@ -200,7 +212,6 @@ private:
addAtom(*atom);
}
-
typedef llvm::DenseMap<const normalized::Section *,
std::vector<SectionOffsetAndAtom>> SectionToAtoms;
typedef llvm::StringMap<const lld::Atom *> NameToAtom;
@@ -298,7 +309,6 @@ private:
return nullptr;
}
-
struct ReExportedDylib {
ReExportedDylib(StringRef p) : path(p), file(nullptr) { }
StringRef path;
@@ -324,4 +334,4 @@ private:
} // end namespace mach_o
} // end namespace lld
-#endif
+#endif // LLD_READER_WRITER_MACHO_FILE_H
diff --git a/lib/ReaderWriter/MachO/FlatNamespaceFile.h b/lib/ReaderWriter/MachO/FlatNamespaceFile.h
new file mode 100644
index 000000000000..6c6a9262ba2e
--- /dev/null
+++ b/lib/ReaderWriter/MachO/FlatNamespaceFile.h
@@ -0,0 +1,61 @@
+//===- lib/ReaderWriter/MachO/FlatNamespaceFile.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_MACHO_FLAT_NAMESPACE_FILE_H
+#define LLD_READER_WRITER_MACHO_FLAT_NAMESPACE_FILE_H
+
+#include "lld/Core/SharedLibraryFile.h"
+#include "llvm/Support/Debug.h"
+
+namespace lld {
+namespace mach_o {
+
+//
+// A FlateNamespaceFile instance may be added as a resolution source of last
+// resort, depending on how -flat_namespace and -undefined are set.
+//
+class FlatNamespaceFile : public SharedLibraryFile {
+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();
+ }
+
+ StringRef getDSOName() const override { return "flat-namespace"; }
+
+ const AtomVector<DefinedAtom> &defined() const override {
+ return _noDefinedAtoms;
+ }
+ const AtomVector<UndefinedAtom> &undefined() const override {
+ return _noUndefinedAtoms;
+ }
+
+ const AtomVector<SharedLibraryAtom> &sharedLibrary() const override {
+ return _sharedLibraryAtoms;
+ }
+
+ const AtomVector<AbsoluteAtom> &absolute() const override {
+ return _noAbsoluteAtoms;
+ }
+
+private:
+ mutable AtomVector<SharedLibraryAtom> _sharedLibraryAtoms;
+};
+
+} // namespace mach_o
+} // namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_FLAT_NAMESPACE_FILE_H
diff --git a/lib/ReaderWriter/MachO/GOTPass.cpp b/lib/ReaderWriter/MachO/GOTPass.cpp
index 1ddec4003cbd..a5816277dd71 100644
--- a/lib/ReaderWriter/MachO/GOTPass.cpp
+++ b/lib/ReaderWriter/MachO/GOTPass.cpp
@@ -1,4 +1,4 @@
-//===- lib/ReaderWriter/MachO/GOTPass.cpp ---------------------------------===//
+//===- lib/ReaderWriter/MachO/GOTPass.cpp -----------------------*- C++ -*-===//
//
// The LLVM Linker
//
@@ -46,7 +46,6 @@
namespace lld {
namespace mach_o {
-
//
// GOT Entry Atom created by the GOT pass.
//
@@ -60,7 +59,7 @@ public:
}
Alignment alignment() const override {
- return Alignment(_is64 ? 3 : 2);
+ return _is64 ? 8 : 4;
}
uint64_t size() const override {
@@ -86,20 +85,18 @@ private:
StringRef _name;
};
-
/// Pass for instantiating and optimizing GOT slots.
///
class GOTPass : public Pass {
public:
GOTPass(const MachOLinkingContext &context)
- : _context(context), _archHandler(_context.archHandler()),
- _file("<mach-o GOT Pass>") { }
+ : _ctx(context), _archHandler(_ctx.archHandler()),
+ _file("<mach-o GOT Pass>") {}
private:
-
- void perform(std::unique_ptr<MutableFile> &mergedFile) override {
+ std::error_code perform(SimpleFile &mergedFile) override {
// Scan all references in all atoms.
- for (const DefinedAtom *atom : mergedFile->defined()) {
+ for (const DefinedAtom *atom : mergedFile.defined()) {
for (const Reference *ref : *atom) {
// Look at instructions accessing the GOT.
bool canBypassGOT;
@@ -131,7 +128,9 @@ private:
return (left->slotName().compare(right->slotName()) < 0);
});
for (const GOTEntryAtom *slot : entries)
- mergedFile->addAtom(*slot);
+ mergedFile.addAtom(*slot);
+
+ return std::error_code();
}
bool shouldReplaceTargetWithGOTAtom(const Atom *target, bool canBypassGOT) {
@@ -154,8 +153,8 @@ private:
const DefinedAtom *makeGOTEntry(const Atom *target) {
auto pos = _targetToGOT.find(target);
if (pos == _targetToGOT.end()) {
- GOTEntryAtom *gotEntry = new (_file.allocator())
- GOTEntryAtom(_file, _context.is64Bit(), target->name());
+ auto *gotEntry = new (_file.allocator())
+ GOTEntryAtom(_file, _ctx.is64Bit(), target->name());
_targetToGOT[target] = gotEntry;
const ArchHandler::ReferenceInfo &nlInfo = _archHandler.stubInfo().
nonLazyPointerReferenceToBinder;
@@ -166,20 +165,16 @@ private:
return pos->second;
}
-
- const MachOLinkingContext &_context;
+ const MachOLinkingContext &_ctx;
mach_o::ArchHandler &_archHandler;
MachOFile _file;
llvm::DenseMap<const Atom*, const GOTEntryAtom*> _targetToGOT;
};
-
-
void addGOTPass(PassManager &pm, const MachOLinkingContext &ctx) {
assert(ctx.needsGOTPass());
pm.add(llvm::make_unique<GOTPass>(ctx));
}
-
} // end namesapce mach_o
} // end namesapce lld
diff --git a/lib/ReaderWriter/MachO/LayoutPass.cpp b/lib/ReaderWriter/MachO/LayoutPass.cpp
index 2d096e4c1a6a..0c14ee9d39ab 100644
--- a/lib/ReaderWriter/MachO/LayoutPass.cpp
+++ b/lib/ReaderWriter/MachO/LayoutPass.cpp
@@ -133,7 +133,7 @@ static void checkReachabilityFromRoot(AtomToAtomT &followOnRoots,
}
}
-static void printDefinedAtoms(const MutableFile::DefinedAtomRange &atomRange) {
+static void printDefinedAtoms(const SimpleFile::DefinedAtomRange &atomRange) {
for (const DefinedAtom *atom : atomRange) {
llvm::dbgs() << " file=" << atom->file().path()
<< ", name=" << atom->name()
@@ -146,7 +146,7 @@ static void printDefinedAtoms(const MutableFile::DefinedAtomRange &atomRange) {
/// Verify that the followon chain is sane. Should not be called in
/// release binary.
-void LayoutPass::checkFollowonChain(MutableFile::DefinedAtomRange &range) {
+void LayoutPass::checkFollowonChain(SimpleFile::DefinedAtomRange &range) {
ScopedTask task(getDefaultDomain(), "LayoutPass::checkFollowonChain");
// Verify that there's no cycle in follow-on chain.
@@ -329,7 +329,7 @@ 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(MutableFile::DefinedAtomRange &range) {
+void LayoutPass::buildFollowOnTable(SimpleFile::DefinedAtomRange &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.
@@ -397,7 +397,7 @@ void LayoutPass::buildFollowOnTable(MutableFile::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(MutableFile::DefinedAtomRange &range) {
+void LayoutPass::buildOrdinalOverrideMap(SimpleFile::DefinedAtomRange &range) {
ScopedTask task(getDefaultDomain(), "LayoutPass::buildOrdinalOverrideMap");
uint64_t index = 0;
for (const DefinedAtom *ai : range) {
@@ -407,7 +407,7 @@ void LayoutPass::buildOrdinalOverrideMap(MutableFile::DefinedAtomRange &range) {
AtomToAtomT::iterator start = _followOnRoots.find(atom);
if (start == _followOnRoots.end())
continue;
- for (const DefinedAtom *nextAtom = start->second; nextAtom != NULL;
+ for (const DefinedAtom *nextAtom = start->second; nextAtom;
nextAtom = _followOnNexts[nextAtom]) {
AtomToOrdinalT::iterator pos = _ordinalOverrideMap.find(nextAtom);
if (pos == _ordinalOverrideMap.end())
@@ -417,7 +417,7 @@ void LayoutPass::buildOrdinalOverrideMap(MutableFile::DefinedAtomRange &range) {
}
std::vector<LayoutPass::SortKey>
-LayoutPass::decorate(MutableFile::DefinedAtomRange &atomRange) const {
+LayoutPass::decorate(SimpleFile::DefinedAtomRange &atomRange) const {
std::vector<SortKey> ret;
for (const DefinedAtom *atom : atomRange) {
auto ri = _followOnRoots.find(atom);
@@ -429,7 +429,7 @@ LayoutPass::decorate(MutableFile::DefinedAtomRange &atomRange) const {
return ret;
}
-void LayoutPass::undecorate(MutableFile::DefinedAtomRange &atomRange,
+void LayoutPass::undecorate(SimpleFile::DefinedAtomRange &atomRange,
std::vector<SortKey> &keys) const {
size_t i = 0;
for (SortKey &k : keys)
@@ -437,10 +437,11 @@ void LayoutPass::undecorate(MutableFile::DefinedAtomRange &atomRange,
}
/// Perform the actual pass
-void LayoutPass::perform(std::unique_ptr<MutableFile> &mergedFile) {
+std::error_code LayoutPass::perform(SimpleFile &mergedFile) {
+ DEBUG(llvm::dbgs() << "******** Laying out atoms:\n");
// sort the atoms
ScopedTask task(getDefaultDomain(), "LayoutPass");
- MutableFile::DefinedAtomRange atomRange = mergedFile->definedAtoms();
+ SimpleFile::DefinedAtomRange atomRange = mergedFile.definedAtoms();
// Build follow on tables
buildFollowOnTable(atomRange);
@@ -468,6 +469,9 @@ void LayoutPass::perform(std::unique_ptr<MutableFile> &mergedFile) {
llvm::dbgs() << "sorted atoms:\n";
printDefinedAtoms(atomRange);
});
+
+ DEBUG(llvm::dbgs() << "******** Finished laying out atoms\n");
+ return std::error_code();
}
void addLayoutPass(PassManager &pm, const MachOLinkingContext &ctx) {
diff --git a/lib/ReaderWriter/MachO/LayoutPass.h b/lib/ReaderWriter/MachO/LayoutPass.h
index 186f29be0719..d6072b0ca4fb 100644
--- a/lib/ReaderWriter/MachO/LayoutPass.h
+++ b/lib/ReaderWriter/MachO/LayoutPass.h
@@ -13,6 +13,7 @@
#include "lld/Core/File.h"
#include "lld/Core/Pass.h"
#include "lld/Core/Reader.h"
+#include "lld/Core/Simple.h"
#include "llvm/ADT/DenseMap.h"
#include <map>
#include <string>
@@ -20,7 +21,7 @@
namespace lld {
class DefinedAtom;
-class MutableFile;
+class SimpleFile;
namespace mach_o {
@@ -45,17 +46,17 @@ public:
LayoutPass(const Registry &registry, SortOverride sorter);
/// Sorts atoms in mergedFile by content type then by command line order.
- void perform(std::unique_ptr<MutableFile> &mergedFile) override;
+ std::error_code perform(SimpleFile &mergedFile) override;
- virtual ~LayoutPass() {}
+ ~LayoutPass() override = default;
private:
// Build the followOn atoms chain as specified by the kindLayoutAfter
// reference type
- void buildFollowOnTable(MutableFile::DefinedAtomRange &range);
+ void buildFollowOnTable(SimpleFile::DefinedAtomRange &range);
// Build a map of Atoms to ordinals for sorting the atoms
- void buildOrdinalOverrideMap(MutableFile::DefinedAtomRange &range);
+ void buildOrdinalOverrideMap(SimpleFile::DefinedAtomRange &range);
const Registry &_registry;
SortOverride _customSorter;
@@ -83,12 +84,12 @@ private:
void setChainRoot(const DefinedAtom *targetAtom, const DefinedAtom *root);
- std::vector<SortKey> decorate(MutableFile::DefinedAtomRange &atomRange) const;
- void undecorate(MutableFile::DefinedAtomRange &atomRange,
+ std::vector<SortKey> decorate(SimpleFile::DefinedAtomRange &atomRange) const;
+ void undecorate(SimpleFile::DefinedAtomRange &atomRange,
std::vector<SortKey> &keys) const;
// Check if the follow-on graph is a correct structure. For debugging only.
- void checkFollowonChain(MutableFile::DefinedAtomRange &range);
+ void checkFollowonChain(SimpleFile::DefinedAtomRange &range);
};
} // namespace mach_o
diff --git a/lib/ReaderWriter/MachO/MachOLinkingContext.cpp b/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
index 92385cf3e820..1c97c5a39d3f 100644
--- a/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
+++ b/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
@@ -10,8 +10,10 @@
#include "lld/ReaderWriter/MachOLinkingContext.h"
#include "ArchHandler.h"
#include "File.h"
+#include "FlatNamespaceFile.h"
#include "MachONormalizedFile.h"
#include "MachOPasses.h"
+#include "SectCreateFile.h"
#include "lld/Core/ArchiveLibraryFile.h"
#include "lld/Core/PassManager.h"
#include "lld/Core/Reader.h"
@@ -73,7 +75,6 @@ bool MachOLinkingContext::parsePackedVersion(StringRef str, uint32_t &result) {
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 },
@@ -133,8 +134,7 @@ bool MachOLinkingContext::isThinObjectFile(StringRef path, Arch &arch) {
return mach_o::normalized::isThinObjectFile(path, arch);
}
-bool MachOLinkingContext::sliceFromFatFile(const MemoryBuffer &mb,
- uint32_t &offset,
+bool MachOLinkingContext::sliceFromFatFile(MemoryBufferRef mb, uint32_t &offset,
uint32_t &size) {
return mach_o::normalized::sliceFromFatFile(mb, _arch, offset, size);
}
@@ -143,11 +143,13 @@ 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),
- _compatibilityVersion(0), _currentVersion(0), _deadStrippableDylib(false),
- _printAtoms(false), _testingFileUsage(false), _keepPrivateExterns(false),
- _demangle(false), _archHandler(nullptr),
+ _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) {}
+ _debugInfoMode(DebugInfoMode::addDebugMap), _orderFileEntries(0),
+ _flatNamespaceFile(nullptr) {}
MachOLinkingContext::~MachOLinkingContext() {}
@@ -196,6 +198,9 @@ void MachOLinkingContext::configure(HeaderFileType type, Arch arch, OS os,
_pageZeroSize = 0x1000;
}
+ // Initial base address is __PAGEZERO size.
+ _baseAddress = _pageZeroSize;
+
// Make PIE by default when targetting newer OSs.
switch (os) {
case OS::macOSX:
@@ -268,8 +273,6 @@ bool MachOLinkingContext::isBigEndian(Arch arch) {
llvm_unreachable("Unknown arch type");
}
-
-
bool MachOLinkingContext::is64Bit() const {
return is64Bit(_arch);
}
@@ -337,13 +340,21 @@ bool MachOLinkingContext::needsShimPass() const {
}
}
+bool MachOLinkingContext::needsTLVPass() const {
+ switch (_outputMachOType) {
+ case MH_BUNDLE:
+ case MH_EXECUTE:
+ case MH_DYLIB:
+ return true;
+ default:
+ return false;
+ }
+}
+
StringRef MachOLinkingContext::binderSymbolName() const {
return archHandler().stubInfo().binderSymbolName;
}
-
-
-
bool MachOLinkingContext::minOS(StringRef mac, StringRef iOS) const {
uint32_t parsedVersion;
switch (_os) {
@@ -473,7 +484,6 @@ void MachOLinkingContext::addFrameworkSearchDir(StringRef fwPath,
_frameworkDirs.push_back(fwPath);
}
-
ErrorOr<StringRef>
MachOLinkingContext::searchDirForLibrary(StringRef path,
StringRef libName) const {
@@ -502,8 +512,6 @@ MachOLinkingContext::searchDirForLibrary(StringRef path,
return make_error_code(llvm::errc::no_such_file_or_directory);
}
-
-
ErrorOr<StringRef> MachOLinkingContext::searchLibrary(StringRef libName) const {
SmallString<256> path;
for (StringRef dir : searchDirs()) {
@@ -515,7 +523,6 @@ ErrorOr<StringRef> MachOLinkingContext::searchLibrary(StringRef libName) const {
return make_error_code(llvm::errc::no_such_file_or_directory);
}
-
ErrorOr<StringRef> MachOLinkingContext::findPathForFramework(StringRef fwName) const{
SmallString<256> fullPath;
for (StringRef dir : frameworkDirs()) {
@@ -589,6 +596,8 @@ void MachOLinkingContext::addPasses(PassManager &pm) {
mach_o::addCompactUnwindPass(pm, *this);
if (needsGOTPass())
mach_o::addGOTPass(pm, *this);
+ if (needsTLVPass())
+ mach_o::addTLVPass(pm, *this);
if (needsShimPass())
mach_o::addShimPass(pm, *this); // Shim pass must run after stubs pass.
}
@@ -613,7 +622,7 @@ MachOLinkingContext::getMemoryBuffer(StringRef path) {
// and switch buffer to point to just that required slice.
uint32_t offset;
uint32_t size;
- if (sliceFromFatFile(*mb, offset, size))
+ if (sliceFromFatFile(mb->getMemBufferRef(), offset, size))
return MemoryBuffer::getFileSlice(path, size, offset);
return std::move(mb);
}
@@ -623,18 +632,18 @@ MachODylibFile* MachOLinkingContext::loadIndirectDylib(StringRef path) {
if (mbOrErr.getError())
return nullptr;
- std::vector<std::unique_ptr<File>> files;
- if (registry().loadFile(std::move(mbOrErr.get()), files))
+ ErrorOr<std::unique_ptr<File>> fileOrErr =
+ registry().loadFile(std::move(mbOrErr.get()));
+ if (!fileOrErr)
return nullptr;
- assert(files.size() == 1 && "expected one file in dylib");
- files[0]->parse();
- MachODylibFile* result = reinterpret_cast<MachODylibFile*>(files[0].get());
+ std::unique_ptr<File> &file = fileOrErr.get();
+ file->parse();
+ MachODylibFile *result = reinterpret_cast<MachODylibFile *>(file.get());
// Node object now owned by _indirectDylibs vector.
- _indirectDylibs.push_back(std::move(files[0]));
+ _indirectDylibs.push_back(std::move(file));
return result;
}
-
MachODylibFile* MachOLinkingContext::findIndirectDylib(StringRef path) {
// See if already loaded.
auto pos = _pathToDylibMap.find(path);
@@ -685,7 +694,7 @@ uint32_t MachOLinkingContext::dylibCompatVersion(StringRef installName) const {
return 0x1000; // 1.0
}
-bool MachOLinkingContext::createImplicitFiles(
+void MachOLinkingContext::createImplicitFiles(
std::vector<std::unique_ptr<File> > &result) {
// Add indirect dylibs by asking each linked dylib to add its indirects.
// Iterate until no more dylibs get loaded.
@@ -699,12 +708,19 @@ bool MachOLinkingContext::createImplicitFiles(
}
// Let writer add output type specific extras.
- return writer().createImplicitFiles(result);
-}
+ writer().createImplicitFiles(result);
+ // If undefinedMode is != error, add a FlatNamespaceFile instance. This will
+ // provide a SharedLibraryAtom for symbols that aren't defined elsewhere.
+ if (undefinedMode() != UndefinedMode::error) {
+ result.emplace_back(new mach_o::FlatNamespaceFile(*this));
+ _flatNamespaceFile = result.back().get();
+ }
+}
void MachOLinkingContext::registerDylib(MachODylibFile *dylib,
bool upward) const {
+ std::lock_guard<std::mutex> lock(_dylibsMutex);
_allDylibs.insert(dylib);
_pathToDylibMap[dylib->installName()] = dylib;
// If path is different than install name, register path too.
@@ -714,7 +730,6 @@ void MachOLinkingContext::registerDylib(MachODylibFile *dylib,
_upwardDylibs.insert(dylib);
}
-
bool MachOLinkingContext::isUpwardDylib(StringRef installName) const {
for (MachODylibFile *dylib : _upwardDylibs) {
if (dylib->installName().equals(installName))
@@ -729,28 +744,37 @@ ArchHandler &MachOLinkingContext::archHandler() const {
return *_archHandler;
}
-
void MachOLinkingContext::addSectionAlignment(StringRef seg, StringRef sect,
- uint8_t align2) {
- SectionAlign entry;
- entry.segmentName = seg;
- entry.sectionName = sect;
- entry.align2 = align2;
+ uint16_t align) {
+ SectionAlign entry = { seg, sect, align };
_sectAligns.push_back(entry);
}
+void MachOLinkingContext::addSectCreateSection(
+ StringRef seg, StringRef sect,
+ std::unique_ptr<MemoryBuffer> content) {
+
+ if (!_sectCreateFile) {
+ auto sectCreateFile = llvm::make_unique<mach_o::SectCreateFile>();
+ _sectCreateFile = sectCreateFile.get();
+ getNodes().push_back(llvm::make_unique<FileNode>(std::move(sectCreateFile)));
+ }
+
+ assert(_sectCreateFile && "sectcreate file does not exist.");
+ _sectCreateFile->addSection(seg, sect, std::move(content));
+}
+
bool MachOLinkingContext::sectionAligned(StringRef seg, StringRef sect,
- uint8_t &align2) const {
+ uint16_t &align) const {
for (const SectionAlign &entry : _sectAligns) {
if (seg.equals(entry.segmentName) && sect.equals(entry.sectionName)) {
- align2 = entry.align2;
+ align = entry.align;
return true;
}
}
return false;
}
-
void MachOLinkingContext::addExportSymbol(StringRef sym) {
// Support old crufty export lists with bogus entries.
if (sym.endswith(".eh") || sym.startswith(".objc_category_name_")) {
@@ -805,7 +829,7 @@ std::string MachOLinkingContext::demangle(StringRef symbolName) const {
const char *cstr = nullTermSym.data() + 1;
int status;
char *demangled = abi::__cxa_demangle(cstr, nullptr, nullptr, &status);
- if (demangled != NULL) {
+ if (demangled) {
std::string result(demangled);
// __cxa_demangle() always uses a malloc'ed buffer to return the result.
free(demangled);
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFile.h b/lib/ReaderWriter/MachO/MachONormalizedFile.h
index 70bcde2dea22..cccf180f1043 100644
--- a/lib/ReaderWriter/MachO/MachONormalizedFile.h
+++ b/lib/ReaderWriter/MachO/MachONormalizedFile.h
@@ -45,6 +45,7 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/MachO.h"
#include "llvm/Support/YAMLTraits.h"
@@ -108,17 +109,26 @@ LLVM_YAML_STRONG_TYPEDEF(uint32_t, SectionAttr)
/// can support either kind.
struct Section {
Section() : type(llvm::MachO::S_REGULAR),
- attributes(0), alignment(0), address(0) { }
+ attributes(0), alignment(1), address(0) { }
StringRef segmentName;
StringRef sectionName;
SectionType type;
SectionAttr attributes;
- uint32_t alignment;
+ uint16_t alignment;
Hex64 address;
ArrayRef<uint8_t> content;
Relocations relocations;
IndirectSymbols indirectSymbols;
+
+#ifndef NDEBUG
+ raw_ostream& operator<<(raw_ostream &OS) const {
+ dump(OS);
+ return OS;
+ }
+
+ void dump(raw_ostream &OS = llvm::dbgs()) const;
+#endif
};
@@ -142,6 +152,14 @@ struct Symbol {
Hex64 value;
};
+/// Check whether the given section type indicates a zero-filled section.
+// FIXME: Utility functions of this kind should probably be moved into
+// llvm/Support.
+inline bool isZeroFillSection(SectionType T) {
+ return (T == llvm::MachO::S_ZEROFILL ||
+ T == llvm::MachO::S_THREAD_LOCAL_ZEROFILL);
+}
+
/// A typedef so that YAML I/O can (de/en)code the protection bits of a segment.
LLVM_YAML_STRONG_TYPEDEF(uint32_t, VMProtect)
@@ -210,15 +228,9 @@ LLVM_YAML_STRONG_TYPEDEF(uint32_t, FileFlags)
///
struct NormalizedFile {
- NormalizedFile() : arch(MachOLinkingContext::arch_unknown),
- fileType(llvm::MachO::MH_OBJECT),
- flags(0),
- hasUUID(false),
- os(MachOLinkingContext::OS::unknown) { }
-
- MachOLinkingContext::Arch arch;
- HeaderFileType fileType;
- FileFlags flags;
+ MachOLinkingContext::Arch arch = MachOLinkingContext::arch_unknown;
+ HeaderFileType fileType = llvm::MachO::MH_OBJECT;
+ FileFlags flags = 0;
std::vector<Segment> segments; // Not used in object files.
std::vector<Section> sections;
@@ -229,19 +241,20 @@ struct NormalizedFile {
// Maps to load commands with no LINKEDIT content (final linked images only).
std::vector<DependentDylib> dependentDylibs;
- StringRef installName; // dylibs only
- PackedVersion compatVersion; // dylibs only
- PackedVersion currentVersion; // dylibs only
- bool hasUUID;
+ StringRef installName; // dylibs only
+ PackedVersion compatVersion = 0; // dylibs only
+ PackedVersion currentVersion = 0; // dylibs only
+ bool hasUUID = false;
std::vector<StringRef> rpaths;
- Hex64 entryAddress;
- MachOLinkingContext::OS os;
- Hex64 sourceVersion;
- PackedVersion minOSverson;
- PackedVersion sdkVersion;
+ Hex64 entryAddress = 0;
+ Hex64 stackSize = 0;
+ MachOLinkingContext::OS os = MachOLinkingContext::OS::unknown;
+ Hex64 sourceVersion = 0;
+ PackedVersion minOSverson = 0;
+ PackedVersion sdkVersion = 0;
// Maps to load commands with LINKEDIT content (final linked images only).
- Hex32 pageSize;
+ Hex32 pageSize = 0;
std::vector<RebaseLocation> rebasingInfo;
std::vector<BindLocation> bindingInfo;
std::vector<BindLocation> weakBindingInfo;
@@ -264,8 +277,8 @@ bool isThinObjectFile(StringRef path, MachOLinkingContext::Arch &arch);
/// If the buffer is a fat file with the request arch, then this function
/// returns true with 'offset' and 'size' set to location of the arch slice
/// within the buffer. Otherwise returns false;
-bool sliceFromFatFile(const MemoryBuffer &mb, MachOLinkingContext::Arch arch,
- uint32_t &offset, uint32_t &size);
+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>>
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
index 07a6dbfe569b..1013d3ddaef3 100644
--- a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
+++ b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
@@ -30,6 +30,7 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Object/MachO.h"
#include "llvm/Support/Casting.h"
@@ -169,9 +170,8 @@ bool isThinObjectFile(StringRef path, MachOLinkingContext::Arch &arch) {
return true;
}
-
-bool sliceFromFatFile(const MemoryBuffer &mb, MachOLinkingContext::Arch arch,
- uint32_t &offset, uint32_t &size) {
+bool sliceFromFatFile(MemoryBufferRef mb, MachOLinkingContext::Arch arch,
+ uint32_t &offset, uint32_t &size) {
const char *start = mb.getBufferStart();
const llvm::MachO::fat_header *fh =
reinterpret_cast<const llvm::MachO::fat_header *>(start);
@@ -211,7 +211,7 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb,
uint32_t sliceOffset;
uint32_t sliceSize;
- if (sliceFromFatFile(*mb, arch, sliceOffset, sliceSize)) {
+ if (sliceFromFatFile(mb->getMemBufferRef(), arch, sliceOffset, sliceSize)) {
start = &start[sliceOffset];
objSize = sliceSize;
mh = reinterpret_cast<const mach_header *>(start);
@@ -297,7 +297,7 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb,
section.type = (SectionType)(read32(&sect->flags, isBig) &
SECTION_TYPE);
section.attributes = read32(&sect->flags, isBig) & SECTION_ATTRIBUTES;
- section.alignment = read32(&sect->align, isBig);
+ section.alignment = 1 << read32(&sect->align, isBig);
section.address = read64(&sect->addr, isBig);
const uint8_t *content =
(const uint8_t *)start + read32(&sect->offset, isBig);
@@ -341,7 +341,7 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb,
SECTION_TYPE);
section.attributes =
read32((const uint8_t *)&sect->flags, isBig) & SECTION_ATTRIBUTES;
- section.alignment = read32(&sect->align, isBig);
+ section.alignment = 1 << read32(&sect->align, isBig);
section.address = read32(&sect->addr, isBig);
const uint8_t *content =
(const uint8_t *)start + read32(&sect->offset, isBig);
@@ -516,22 +516,17 @@ class MachOObjectReader : public Reader {
public:
MachOObjectReader(MachOLinkingContext &ctx) : _ctx(ctx) {}
- bool canParse(file_magic magic, StringRef ext,
- const MemoryBuffer &mb) const override {
- switch (magic) {
- case llvm::sys::fs::file_magic::macho_object:
- return (mb.getBufferSize() > 32);
- default:
- return false;
- }
+ bool canParse(file_magic magic, MemoryBufferRef mb) const override {
+ return (magic == llvm::sys::fs::file_magic::macho_object &&
+ mb.getBufferSize() > 32);
}
- std::error_code
- loadFile(std::unique_ptr<MemoryBuffer> mb, const Registry &registry,
- std::vector<std::unique_ptr<File>> &result) const override {
- auto *file = new MachOFile(std::move(mb), &_ctx);
- result.push_back(std::unique_ptr<MachOFile>(file));
- return std::error_code();
+ ErrorOr<std::unique_ptr<File>>
+ loadFile(std::unique_ptr<MemoryBuffer> mb,
+ const Registry &registry) const override {
+ std::unique_ptr<File> ret =
+ llvm::make_unique<MachOFile>(std::move(mb), &_ctx);
+ return std::move(ret);
}
private:
@@ -542,23 +537,22 @@ class MachODylibReader : public Reader {
public:
MachODylibReader(MachOLinkingContext &ctx) : _ctx(ctx) {}
- bool canParse(file_magic magic, StringRef ext,
- const MemoryBuffer &mb) const override {
+ bool canParse(file_magic magic, MemoryBufferRef mb) const override {
switch (magic) {
case llvm::sys::fs::file_magic::macho_dynamically_linked_shared_lib:
case llvm::sys::fs::file_magic::macho_dynamically_linked_shared_lib_stub:
- return (mb.getBufferSize() > 32);
+ return mb.getBufferSize() > 32;
default:
return false;
}
}
- std::error_code
- loadFile(std::unique_ptr<MemoryBuffer> mb, const Registry &registry,
- std::vector<std::unique_ptr<File>> &result) const override {
- auto *file = new MachODylibFile(std::move(mb), &_ctx);
- result.push_back(std::unique_ptr<MachODylibFile>(file));
- return std::error_code();
+ ErrorOr<std::unique_ptr<File>>
+ loadFile(std::unique_ptr<MemoryBuffer> mb,
+ const Registry &registry) const override {
+ std::unique_ptr<File> ret =
+ llvm::make_unique<MachODylibFile>(std::move(mb), &_ctx);
+ return std::move(ret);
}
private:
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
index be7acf9d4d60..4ecfece0629e 100644
--- a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
+++ b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
@@ -149,6 +149,7 @@ private:
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.
@@ -159,7 +160,6 @@ private:
struct TrieEdge {
TrieEdge(StringRef s, TrieNode *node) : _subString(s), _child(node) {}
- ~TrieEdge() {}
StringRef _subString;
struct TrieNode *_child;
@@ -169,14 +169,14 @@ private:
TrieNode(StringRef s)
: _cummulativeString(s), _address(0), _flags(0), _other(0),
_trieOffset(0), _hasExportInfo(false) {}
- ~TrieNode() {}
+ ~TrieNode() = default;
void addSymbol(const Export &entry, BumpPtrAllocator &allocator,
std::vector<TrieNode *> &allNodes);
bool updateOffset(uint32_t &offset);
void appendToByteBuffer(ByteBuffer &out);
-private:
+ private:
StringRef _cummulativeString;
std::list<TrieEdge> _children;
uint64_t _address;
@@ -263,7 +263,6 @@ size_t MachOFileLayout::headerAndLoadCommandsSize() const {
return _endOfLoadCommands;
}
-
MachOFileLayout::MachOFileLayout(const NormalizedFile &file)
: _file(file),
_is64(MachOLinkingContext::is64Bit(file.arch)),
@@ -290,12 +289,12 @@ MachOFileLayout::MachOFileLayout(const NormalizedFile &file)
unsigned relocCount = 0;
uint64_t offset = _startOfSectionsContent;
for (const Section &sect : file.sections) {
- if (sect.type != llvm::MachO::S_ZEROFILL) {
- offset = llvm::RoundUpToAlignment(offset, 1 << sect.alignment);
+ if (isZeroFillSection(sect.type))
+ _sectInfo[&sect].fileOffset = 0;
+ else {
+ offset = llvm::RoundUpToAlignment(offset, sect.alignment);
_sectInfo[&sect].fileOffset = offset;
offset += sect.content.size();
- } else {
- _sectInfo[&sect].fileOffset = 0;
}
relocCount += sect.relocations.size();
}
@@ -430,7 +429,7 @@ uint32_t MachOFileLayout::loadCommandsSize(uint32_t &count) {
// Add LC_RPATH
for (const StringRef &path : _file.rpaths) {
- size += sizeof(rpath_command) + pointerAlign(path.size()+1);
+ size += pointerAlign(sizeof(rpath_command) + path.size() + 1);
++count;
}
@@ -531,7 +530,7 @@ void MachOFileLayout::buildFileOffsets() {
for (const Section *s : _segInfo[&sg].sections) {
uint32_t sectOffset = s->address - sg.address;
uint32_t sectFileSize =
- s->type == llvm::MachO::S_ZEROFILL ? 0 : s->content.size();
+ isZeroFillSection(s->type) ? 0 : s->content.size();
segFileSize = std::max(segFileSize, sectOffset + sectFileSize);
_sectInfo[s].fileOffset = _segInfo[&sg].fileOffset + sectOffset;
@@ -549,7 +548,6 @@ void MachOFileLayout::buildFileOffsets() {
_startOfLinkEdit = fileOffset;
}
-
size_t MachOFileLayout::size() const {
return _endOfSymbolStrings;
}
@@ -613,7 +611,7 @@ std::error_code MachOFileLayout::writeSingleSegmentLoadCommand(uint8_t *&lc) {
sout->addr = sin.address;
sout->size = sin.content.size();
sout->offset = _sectInfo[&sin].fileOffset;
- sout->align = sin.alignment;
+ sout->align = llvm::Log2_32(sin.alignment);
sout->reloff = sin.relocations.empty() ? 0 : relOffset;
sout->nreloc = sin.relocations.size();
sout->flags = sin.type | sin.attributes;
@@ -657,11 +655,11 @@ std::error_code MachOFileLayout::writeSegmentLoadCommands(uint8_t *&lc) {
setString16(section->segmentName, sect->segname);
sect->addr = section->address;
sect->size = section->content.size();
- if (section->type == llvm::MachO::S_ZEROFILL)
+ if (isZeroFillSection(section->type))
sect->offset = 0;
else
sect->offset = section->address - seg.address + segInfo.fileOffset;
- sect->align = section->alignment;
+ sect->align = llvm::Log2_32(section->alignment);
sect->reloff = 0;
sect->nreloc = 0;
sect->flags = section->type | section->attributes;
@@ -829,7 +827,7 @@ std::error_code MachOFileLayout::writeLoadCommands() {
ep->cmd = LC_MAIN;
ep->cmdsize = sizeof(entry_point_command);
ep->entryoff = _file.entryAddress - _seg1addr;
- ep->stacksize = 0;
+ ep->stacksize = _file.stackSize;
if (_swap)
swapStruct(*ep);
lc += sizeof(entry_point_command);
@@ -856,7 +854,7 @@ std::error_code MachOFileLayout::writeLoadCommands() {
// Add LC_RPATH
for (const StringRef &path : _file.rpaths) {
rpath_command *rpc = reinterpret_cast<rpath_command *>(lc);
- uint32_t size = sizeof(rpath_command) + pointerAlign(path.size()+1);
+ uint32_t size = pointerAlign(sizeof(rpath_command) + path.size() + 1);
rpc->cmd = LC_RPATH;
rpc->cmdsize = size;
rpc->path = sizeof(rpath_command); // offset
@@ -882,11 +880,10 @@ std::error_code MachOFileLayout::writeLoadCommands() {
return ec;
}
-
void MachOFileLayout::writeSectionContent() {
for (const Section &s : _file.sections) {
// Copy all section content to output buffer.
- if (s.type == llvm::MachO::S_ZEROFILL)
+ if (isZeroFillSection(s.type))
continue;
if (s.content.empty())
continue;
@@ -909,7 +906,6 @@ void MachOFileLayout::writeRelocations() {
}
}
-
void MachOFileLayout::appendSymbols(const std::vector<Symbol> &symbols,
uint32_t &symOffset, uint32_t &strOffset) {
for (const Symbol &sym : symbols) {
@@ -1043,7 +1039,12 @@ void MachOFileLayout::buildBindInfo() {
_bindingInfo.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
| entry.segIndex);
_bindingInfo.append_uleb128(entry.segOffset);
- _bindingInfo.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | entry.ordinal);
+ if (entry.ordinal > 0)
+ _bindingInfo.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM |
+ (entry.ordinal & 0xF));
+ else
+ _bindingInfo.append_byte(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM |
+ (entry.ordinal & 0xF));
_bindingInfo.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM);
_bindingInfo.append_string(entry.symbolName);
if (entry.addend != lastAddend) {
@@ -1063,7 +1064,12 @@ void MachOFileLayout::buildLazyBindInfo() {
_lazyBindingInfo.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
| entry.segIndex);
_lazyBindingInfo.append_uleb128Fixed(entry.segOffset, 5);
- _lazyBindingInfo.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | entry.ordinal);
+ if (entry.ordinal > 0)
+ _lazyBindingInfo.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM |
+ (entry.ordinal & 0xF));
+ else
+ _lazyBindingInfo.append_byte(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM |
+ (entry.ordinal & 0xF));
_lazyBindingInfo.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM);
_lazyBindingInfo.append_string(entry.symbolName);
_lazyBindingInfo.append_byte(BIND_OPCODE_DO_BIND);
@@ -1090,7 +1096,7 @@ void MachOFileLayout::TrieNode::addSymbol(const Export& entry,
// Splice in new node: was A -> C, now A -> B -> C
StringRef bNodeStr = edge._child->_cummulativeString;
bNodeStr = bNodeStr.drop_back(edgeStr.size()-n).copy(allocator);
- TrieNode* bNode = new (allocator) TrieNode(bNodeStr);
+ auto *bNode = new (allocator) TrieNode(bNodeStr);
allNodes.push_back(bNode);
TrieNode* cNode = edge._child;
StringRef abEdgeStr = edgeStr.substr(0,n).copy(allocator);
@@ -1103,7 +1109,7 @@ void MachOFileLayout::TrieNode::addSymbol(const Export& entry,
TrieEdge& abEdge = edge;
abEdge._subString = abEdgeStr;
abEdge._child = bNode;
- TrieEdge *bcEdge = new (allocator) TrieEdge(bcEdgeStr, cNode);
+ auto *bcEdge = new (allocator) TrieEdge(bcEdgeStr, cNode);
bNode->_children.push_back(std::move(*bcEdge));
bNode->addSymbol(entry, allocator, allNodes);
return;
@@ -1117,8 +1123,8 @@ void MachOFileLayout::TrieNode::addSymbol(const Export& entry,
assert(entry.otherOffset != 0);
}
// No commonality with any existing child, make a new edge.
- TrieNode* newNode = new (allocator) TrieNode(entry.name.copy(allocator));
- TrieEdge *newEdge = new (allocator) TrieEdge(partialStr, newNode);
+ auto *newNode = new (allocator) TrieNode(entry.name.copy(allocator));
+ auto *newEdge = new (allocator) TrieEdge(partialStr, newNode);
_children.push_back(std::move(*newEdge));
DEBUG_WITH_TYPE("trie-builder", llvm::dbgs()
<< "new TrieNode('" << entry.name << "') with edge '"
@@ -1230,7 +1236,7 @@ void MachOFileLayout::buildExportTrie() {
BumpPtrAllocator allocator;
// Build trie of all exported symbols.
- TrieNode* rootNode = new (allocator) TrieNode(StringRef());
+ auto *rootNode = new (allocator) TrieNode(StringRef());
std::vector<TrieNode*> allNodes;
allNodes.reserve(_file.exportInfo.size()*2);
allNodes.push_back(rootNode);
@@ -1257,14 +1263,13 @@ void MachOFileLayout::buildExportTrie() {
_exportTrie.align(_is64 ? 8 : 4);
}
-
void MachOFileLayout::computeSymbolTableSizes() {
// MachO symbol tables have three ranges: locals, globals, and undefines
const size_t nlistSize = (_is64 ? sizeof(nlist_64) : sizeof(nlist));
_symbolTableSize = nlistSize * (_file.localSymbols.size()
+ _file.globalSymbols.size()
+ _file.undefinedSymbols.size());
- _symbolStringPoolSize = 0;
+ _symbolStringPoolSize = 1; // Always reserve 1-byte for the empty string.
for (const Symbol &sym : _file.localSymbols) {
_symbolStringPoolSize += (sym.name.size()+1);
}
@@ -1310,19 +1315,18 @@ std::error_code MachOFileLayout::writeBinary(StringRef path) {
if (_ec)
return _ec;
// Create FileOutputBuffer with calculated size.
- std::unique_ptr<llvm::FileOutputBuffer> fob;
unsigned flags = 0;
if (_file.fileType != llvm::MachO::MH_OBJECT)
flags = llvm::FileOutputBuffer::F_executable;
- std::error_code ec;
- ec = llvm::FileOutputBuffer::create(path, size(), fob, flags);
- if (ec)
+ ErrorOr<std::unique_ptr<llvm::FileOutputBuffer>> fobOrErr =
+ llvm::FileOutputBuffer::create(path, size(), flags);
+ if (std::error_code ec = fobOrErr.getError())
return ec;
-
+ std::unique_ptr<llvm::FileOutputBuffer> &fob = *fobOrErr;
// Write content.
_buffer = fob->getBufferStart();
writeMachHeader();
- ec = writeLoadCommands();
+ std::error_code ec = writeLoadCommands();
if (ec)
return ec;
writeSectionContent();
@@ -1332,15 +1336,12 @@ std::error_code MachOFileLayout::writeBinary(StringRef path) {
return std::error_code();
}
-
/// Takes in-memory normalized view and writes a mach-o object file.
std::error_code writeBinary(const NormalizedFile &file, StringRef path) {
MachOFileLayout layout(file);
return layout.writeBinary(path);
}
-
} // namespace normalized
} // namespace mach_o
} // namespace lld
-
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
index 4d6183f71df7..f80e2ac467fc 100644
--- a/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
+++ b/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
@@ -58,7 +58,7 @@ struct SectionInfo {
uint32_t attributes;
uint64_t address;
uint64_t size;
- uint32_t alignment;
+ uint16_t alignment;
std::vector<AtomInfo> atomsAndOffsets;
uint32_t normalizedSectionIndex;
uint32_t finalSectionIndex;
@@ -67,9 +67,9 @@ struct SectionInfo {
SectionInfo::SectionInfo(StringRef sg, StringRef sct, SectionType t,
const MachOLinkingContext &ctxt, uint32_t attrs)
: segmentName(sg), sectionName(sct), type(t), attributes(attrs),
- address(0), size(0), alignment(0),
+ address(0), size(0), alignment(1),
normalizedSectionIndex(0), finalSectionIndex(0) {
- uint8_t align;
+ uint16_t align = 1;
if (ctxt.sectionAligned(segmentName, sectionName, align)) {
alignment = align;
}
@@ -90,11 +90,11 @@ SegmentInfo::SegmentInfo(StringRef n)
: name(n), address(0), size(0), access(0), normalizedSegmentIndex(0) {
}
-
class Util {
public:
Util(const MachOLinkingContext &ctxt)
- : _context(ctxt), _archHandler(ctxt.archHandler()), _entryAtom(nullptr) {}
+ : _ctx(ctxt), _archHandler(ctxt.archHandler()), _entryAtom(nullptr),
+ _hasTLVDescriptors(false) {}
~Util();
void assignAtomsToSections(const lld::File &atomFile);
@@ -142,7 +142,6 @@ private:
void appendSection(SectionInfo *si, NormalizedFile &file);
uint32_t sectionIndexForAtom(const Atom *atom);
- static uint64_t alignTo(uint64_t value, uint8_t align2);
typedef llvm::DenseMap<const Atom*, uint32_t> AtomToIndex;
struct AtomAndIndex { const Atom *atom; uint32_t index; SymbolScope scope; };
struct AtomSorter {
@@ -157,7 +156,7 @@ private:
static unsigned weight(const SectionInfo *);
};
- const MachOLinkingContext &_context;
+ const MachOLinkingContext &_ctx;
mach_o::ArchHandler &_archHandler;
llvm::BumpPtrAllocator _allocator;
std::vector<SectionInfo*> _sectionInfos;
@@ -169,6 +168,7 @@ private:
const DefinedAtom *_entryAtom;
AtomToIndex _atomToSymbolIndex;
std::vector<const Atom *> _machHeaderAliasAtoms;
+ bool _hasTLVDescriptors;
};
Util::~Util() {
@@ -206,9 +206,8 @@ SectionInfo *Util::getRelocatableSection(DefinedAtom::ContentType type) {
}
}
// Otherwise allocate new SectionInfo object.
- SectionInfo *sect = new (_allocator) SectionInfo(segmentName, sectionName,
- sectionType, _context,
- sectionAttrs);
+ auto *sect = new (_allocator)
+ SectionInfo(segmentName, sectionName, sectionType, _ctx, sectionAttrs);
_sectionInfos.push_back(sect);
_sectionMap[type] = sect;
return sect;
@@ -248,12 +247,19 @@ const MachOFinalSectionFromAtomType sectsToAtomType[] = {
typeTerminatorPtr),
ENTRY("__DATA", "__got", S_NON_LAZY_SYMBOL_POINTERS,
typeGOT),
+ ENTRY("__DATA", "__thread_vars", S_THREAD_LOCAL_VARIABLES,
+ typeThunkTLV),
+ ENTRY("__DATA", "__thread_data", S_THREAD_LOCAL_REGULAR,
+ typeTLVInitialData),
+ ENTRY("__DATA", "__thread_ptrs", S_THREAD_LOCAL_VARIABLE_POINTERS,
+ typeTLVInitializerPtr),
+ ENTRY("__DATA", "__thread_bss", S_THREAD_LOCAL_ZEROFILL,
+ typeTLVInitialZeroFill),
ENTRY("__DATA", "__bss", S_ZEROFILL, typeZeroFill),
ENTRY("__DATA", "__interposing", S_INTERPOSING, typeInterposingTuples),
};
#undef ENTRY
-
SectionInfo *Util::getFinalSection(DefinedAtom::ContentType atomType) {
for (auto &p : sectsToAtomType) {
if (p.atomType != atomType)
@@ -265,6 +271,9 @@ SectionInfo *Util::getFinalSection(DefinedAtom::ContentType atomType) {
case DefinedAtom::typeStubHelper:
sectionAttrs = S_ATTR_PURE_INSTRUCTIONS;
break;
+ case DefinedAtom::typeThunkTLV:
+ _hasTLVDescriptors = true;
+ break;
default:
break;
}
@@ -277,11 +286,8 @@ SectionInfo *Util::getFinalSection(DefinedAtom::ContentType atomType) {
}
}
// Otherwise allocate new SectionInfo object.
- SectionInfo *sect = new (_allocator) SectionInfo(p.segmentName,
- p.sectionName,
- p.sectionType,
- _context,
- sectionAttrs);
+ auto *sect = new (_allocator) SectionInfo(
+ p.segmentName, p.sectionName, p.sectionType, _ctx, sectionAttrs);
_sectionInfos.push_back(sect);
_sectionMap[atomType] = sect;
return sect;
@@ -289,8 +295,6 @@ SectionInfo *Util::getFinalSection(DefinedAtom::ContentType atomType) {
llvm_unreachable("content type not yet supported");
}
-
-
SectionInfo *Util::sectionForAtom(const DefinedAtom *atom) {
if (atom->sectionChoice() == DefinedAtom::sectionBasedOnContent) {
// Section for this atom is derived from content type.
@@ -298,7 +302,7 @@ SectionInfo *Util::sectionForAtom(const DefinedAtom *atom) {
auto pos = _sectionMap.find(type);
if ( pos != _sectionMap.end() )
return pos->second;
- bool rMode = (_context.outputMachOType() == llvm::MachO::MH_OBJECT);
+ bool rMode = (_ctx.outputMachOType() == llvm::MachO::MH_OBJECT);
return rMode ? getRelocatableSection(type) : getFinalSection(type);
} else {
// This atom needs to be in a custom section.
@@ -315,31 +319,30 @@ SectionInfo *Util::sectionForAtom(const DefinedAtom *atom) {
assert(seperatorIndex != StringRef::npos);
StringRef segName = customName.slice(0, seperatorIndex);
StringRef sectName = customName.drop_front(seperatorIndex + 1);
- SectionInfo *sect = new (_allocator) SectionInfo(segName, sectName,
- S_REGULAR, _context);
+ auto *sect =
+ new (_allocator) SectionInfo(segName, sectName, S_REGULAR, _ctx);
_customSections.push_back(sect);
_sectionInfos.push_back(sect);
return sect;
}
}
-
void Util::appendAtom(SectionInfo *sect, const DefinedAtom *atom) {
// Figure out offset for atom in this section given alignment constraints.
uint64_t offset = sect->size;
DefinedAtom::Alignment atomAlign = atom->alignment();
- uint64_t align2 = 1 << atomAlign.powerOf2;
+ uint64_t align = atomAlign.value;
uint64_t requiredModulus = atomAlign.modulus;
- uint64_t currentModulus = (offset % align2);
+ uint64_t currentModulus = (offset % align);
if ( currentModulus != requiredModulus ) {
if ( requiredModulus > currentModulus )
offset += requiredModulus-currentModulus;
else
- offset += align2+requiredModulus-currentModulus;
+ offset += align+requiredModulus-currentModulus;
}
// Record max alignment of any atom in this section.
- if ( atomAlign.powerOf2 > sect->alignment )
- sect->alignment = atomAlign.powerOf2;
+ if (align > sect->alignment)
+ sect->alignment = atomAlign.value;
// Assign atom to this section with this offset.
AtomInfo ai = {atom, offset};
sect->atomsAndOffsets.push_back(ai);
@@ -361,7 +364,7 @@ SegmentInfo *Util::segmentForName(StringRef segName) {
if ( si->name.equals(segName) )
return si;
}
- SegmentInfo *info = new (_allocator) SegmentInfo(segName);
+ auto *info = new (_allocator) SegmentInfo(segName);
if (segName.equals("__TEXT"))
info->access = VM_PROT_READ | VM_PROT_EXECUTE;
else if (segName.equals("__DATA"))
@@ -402,16 +405,15 @@ bool Util::TextSectionSorter::operator()(const SectionInfo *left,
return (weight(left) < weight(right));
}
-
void Util::organizeSections() {
- if (_context.outputMachOType() == llvm::MachO::MH_OBJECT) {
+ if (_ctx.outputMachOType() == llvm::MachO::MH_OBJECT) {
// Leave sections ordered as normalized file specified.
uint32_t sectionIndex = 1;
for (SectionInfo *si : _sectionInfos) {
si->finalSectionIndex = sectionIndex++;
}
} else {
- switch (_context.outputMachOType()){
+ switch (_ctx.outputMachOType()) {
case llvm::MachO::MH_EXECUTE:
// Main executables, need a zero-page segment
segmentForName("__PAGEZERO");
@@ -450,24 +452,17 @@ void Util::organizeSections() {
}
}
}
-
}
-uint64_t Util::alignTo(uint64_t value, uint8_t align2) {
- return llvm::RoundUpToAlignment(value, 1 << align2);
-}
-
-
void Util::layoutSectionsInSegment(SegmentInfo *seg, uint64_t &addr) {
seg->address = addr;
for (SectionInfo *sect : seg->sections) {
- sect->address = alignTo(addr, sect->alignment);
+ sect->address = llvm::RoundUpToAlignment(addr, sect->alignment);
addr = sect->address + sect->size;
}
- seg->size = llvm::RoundUpToAlignment(addr - seg->address,_context.pageSize());
+ seg->size = llvm::RoundUpToAlignment(addr - seg->address, _ctx.pageSize());
}
-
// __TEXT segment lays out backwards so padding is at front after load commands.
void Util::layoutSectionsInTextSegment(size_t hlcSize, SegmentInfo *seg,
uint64_t &addr) {
@@ -477,39 +472,38 @@ void Util::layoutSectionsInTextSegment(size_t hlcSize, SegmentInfo *seg,
for (auto it = seg->sections.rbegin(); it != seg->sections.rend(); ++it) {
SectionInfo *sect = *it;
taddr -= sect->size;
- taddr = taddr & (0 - (1 << sect->alignment));
+ taddr = taddr & (0 - sect->alignment);
}
int64_t padding = taddr - hlcSize;
while (padding < 0)
- padding += _context.pageSize();
+ padding += _ctx.pageSize();
// Start assigning section address starting at padded offset.
addr += (padding + hlcSize);
for (SectionInfo *sect : seg->sections) {
- sect->address = alignTo(addr, sect->alignment);
+ sect->address = llvm::RoundUpToAlignment(addr, sect->alignment);
addr = sect->address + sect->size;
}
- seg->size = llvm::RoundUpToAlignment(addr - seg->address,_context.pageSize());
+ seg->size = llvm::RoundUpToAlignment(addr - seg->address, _ctx.pageSize());
}
-
void Util::assignAddressesToSections(const NormalizedFile &file) {
size_t hlcSize = headerAndLoadCommandsSize(file);
uint64_t address = 0;
- if (_context.outputMachOType() != llvm::MachO::MH_OBJECT) {
+ if (_ctx.outputMachOType() != llvm::MachO::MH_OBJECT) {
for (SegmentInfo *seg : _segmentInfos) {
if (seg->name.equals("__PAGEZERO")) {
- seg->size = _context.pageZeroSize();
+ seg->size = _ctx.pageZeroSize();
address += seg->size;
}
else if (seg->name.equals("__TEXT")) {
- // _context.baseAddress() == 0 implies it was either unspecified or
+ // _ctx.baseAddress() == 0 implies it was either unspecified or
// pageZeroSize is also 0. In either case resetting address is safe.
- address = _context.baseAddress() ? _context.baseAddress() : address;
+ address = _ctx.baseAddress() ? _ctx.baseAddress() : address;
layoutSectionsInTextSegment(hlcSize, seg, address);
} else
layoutSectionsInSegment(seg, address);
- address = llvm::RoundUpToAlignment(address, _context.pageSize());
+ address = llvm::RoundUpToAlignment(address, _ctx.pageSize());
}
DEBUG_WITH_TYPE("WriterMachO-norm",
llvm::dbgs() << "assignAddressesToSections()\n";
@@ -528,7 +522,7 @@ void Util::assignAddressesToSections(const NormalizedFile &file) {
);
} else {
for (SectionInfo *sect : _sectionInfos) {
- sect->address = alignTo(address, sect->alignment);
+ sect->address = llvm::RoundUpToAlignment(address, sect->alignment);
address = sect->address + sect->size;
}
DEBUG_WITH_TYPE("WriterMachO-norm",
@@ -543,7 +537,6 @@ void Util::assignAddressesToSections(const NormalizedFile &file) {
}
}
-
void Util::copySegmentInfo(NormalizedFile &file) {
for (SegmentInfo *sgi : _segmentInfos) {
Segment seg;
@@ -572,7 +565,7 @@ void Util::appendSection(SectionInfo *si, NormalizedFile &file) {
}
void Util::copySectionContent(NormalizedFile &file) {
- const bool r = (_context.outputMachOType() == llvm::MachO::MH_OBJECT);
+ const bool r = (_ctx.outputMachOType() == llvm::MachO::MH_OBJECT);
// Utility function for ArchHandler to find address of atom in output file.
auto addrForAtom = [&] (const Atom &atom) -> uint64_t {
@@ -591,7 +584,7 @@ void Util::copySectionContent(NormalizedFile &file) {
for (SectionInfo *si : _sectionInfos) {
Section *normSect = &file.sections[si->normalizedSectionIndex];
- if (si->type == llvm::MachO::S_ZEROFILL) {
+ if (isZeroFillSection(si->type)) {
const uint8_t *empty = nullptr;
normSect->content = llvm::makeArrayRef(empty, si->size);
continue;
@@ -603,17 +596,16 @@ void Util::copySectionContent(NormalizedFile &file) {
uint8_t *atomContent = reinterpret_cast<uint8_t*>
(&sectionContent[ai.offsetInSection]);
_archHandler.generateAtomContent(*ai.atom, r, addrForAtom,
- sectionAddrForAtom,
- _context.baseAddress(), atomContent);
+ sectionAddrForAtom, _ctx.baseAddress(),
+ atomContent);
}
}
}
-
void Util::copySectionInfo(NormalizedFile &file) {
file.sections.reserve(_sectionInfos.size());
// For final linked images, write sections grouped by segment.
- if (_context.outputMachOType() != llvm::MachO::MH_OBJECT) {
+ if (_ctx.outputMachOType() != llvm::MachO::MH_OBJECT) {
for (SegmentInfo *sgi : _segmentInfos) {
for (SectionInfo *si : sgi->sections) {
appendSection(si, file);
@@ -629,7 +621,7 @@ void Util::copySectionInfo(NormalizedFile &file) {
void Util::updateSectionInfo(NormalizedFile &file) {
file.sections.reserve(_sectionInfos.size());
- if (_context.outputMachOType() != llvm::MachO::MH_OBJECT) {
+ if (_ctx.outputMachOType() != llvm::MachO::MH_OBJECT) {
// For final linked images, sections grouped by segment.
for (SegmentInfo *sgi : _segmentInfos) {
Segment *normSeg = &file.segments[sgi->normalizedSegmentIndex];
@@ -650,7 +642,7 @@ void Util::updateSectionInfo(NormalizedFile &file) {
}
void Util::copyEntryPointAddress(NormalizedFile &nFile) {
- if (_context.outputTypeHasEntry()) {
+ if (_ctx.outputTypeHasEntry()) {
if (_archHandler.isThumbFunction(*_entryAtom))
nFile.entryAddress = (_atomToAddress[_entryAtom] | 1);
else
@@ -661,13 +653,13 @@ void Util::copyEntryPointAddress(NormalizedFile &nFile) {
void Util::buildAtomToAddressMap() {
DEBUG_WITH_TYPE("WriterMachO-address", llvm::dbgs()
<< "assign atom addresses:\n");
- const bool lookForEntry = _context.outputTypeHasEntry();
+ const bool lookForEntry = _ctx.outputTypeHasEntry();
for (SectionInfo *sect : _sectionInfos) {
for (const AtomInfo &info : sect->atomsAndOffsets) {
_atomToAddress[info.atom] = sect->address + info.offsetInSection;
if (lookForEntry && (info.atom->contentType() == DefinedAtom::typeCode) &&
(info.atom->size() != 0) &&
- info.atom->name() == _context.entrySymbolName()) {
+ info.atom->name() == _ctx.entrySymbolName()) {
_entryAtom = info.atom;
}
DEBUG_WITH_TYPE("WriterMachO-address", llvm::dbgs()
@@ -678,7 +670,7 @@ void Util::buildAtomToAddressMap() {
}
}
for (const Atom *atom : _machHeaderAliasAtoms) {
- _atomToAddress[atom] = _context.baseAddress();
+ _atomToAddress[atom] = _ctx.baseAddress();
DEBUG_WITH_TYPE("WriterMachO-address", llvm::dbgs()
<< " address="
<< llvm::format("0x%016X", _atomToAddress[atom])
@@ -715,30 +707,28 @@ uint16_t Util::descBits(const DefinedAtom* atom) {
return desc;
}
-
bool Util::AtomSorter::operator()(const AtomAndIndex &left,
const AtomAndIndex &right) {
return (left.atom->name().compare(right.atom->name()) < 0);
}
-
std::error_code Util::getSymbolTableRegion(const DefinedAtom* atom,
bool &inGlobalsRegion,
SymbolScope &scope) {
- bool rMode = (_context.outputMachOType() == llvm::MachO::MH_OBJECT);
+ bool rMode = (_ctx.outputMachOType() == llvm::MachO::MH_OBJECT);
switch (atom->scope()) {
case Atom::scopeTranslationUnit:
scope = 0;
inGlobalsRegion = false;
return std::error_code();
case Atom::scopeLinkageUnit:
- if ((_context.exportMode() == MachOLinkingContext::ExportMode::whiteList)
- && _context.exportSymbolNamed(atom->name())) {
+ if ((_ctx.exportMode() == MachOLinkingContext::ExportMode::whiteList) &&
+ _ctx.exportSymbolNamed(atom->name())) {
return make_dynamic_error_code(Twine("cannot export hidden symbol ")
+ atom->name());
}
if (rMode) {
- if (_context.keepPrivateExterns()) {
+ if (_ctx.keepPrivateExterns()) {
// -keep_private_externs means keep in globals region as N_PEXT.
scope = N_PEXT | N_EXT;
inGlobalsRegion = true;
@@ -750,8 +740,8 @@ std::error_code Util::getSymbolTableRegion(const DefinedAtom* atom,
inGlobalsRegion = false;
return std::error_code();
case Atom::scopeGlobal:
- if (_context.exportRestrictMode()) {
- if (_context.exportSymbolNamed(atom->name())) {
+ if (_ctx.exportRestrictMode()) {
+ if (_ctx.exportSymbolNamed(atom->name())) {
scope = N_EXT;
inGlobalsRegion = true;
return std::error_code();
@@ -772,7 +762,7 @@ std::error_code Util::getSymbolTableRegion(const DefinedAtom* atom,
std::error_code Util::addSymbols(const lld::File &atomFile,
NormalizedFile &file) {
- bool rMode = (_context.outputMachOType() == llvm::MachO::MH_OBJECT);
+ bool rMode = (_ctx.outputMachOType() == llvm::MachO::MH_OBJECT);
// Mach-O symbol table has three regions: locals, globals, undefs.
// Add all local (non-global) symbols in address order
@@ -835,7 +825,6 @@ std::error_code Util::addSymbols(const lld::File &atomFile,
file.globalSymbols.push_back(sym);
}
-
// Sort undefined symbol alphabetically, then add to symbol table.
std::vector<AtomAndIndex> undefs;
undefs.reserve(128);
@@ -853,7 +842,9 @@ std::error_code Util::addSymbols(const lld::File &atomFile,
Symbol sym;
uint16_t desc = 0;
if (!rMode) {
- uint8_t ordinal = dylibOrdinal(dyn_cast<SharedLibraryAtom>(ai.atom));
+ uint8_t ordinal = 0;
+ if (!_ctx.useFlatNamespace())
+ ordinal = dylibOrdinal(dyn_cast<SharedLibraryAtom>(ai.atom));
llvm::MachO::SET_LIBRARY_ORDINAL(desc, ordinal);
}
sym.name = ai.atom->name();
@@ -891,7 +882,6 @@ const Atom *Util::targetOfStub(const DefinedAtom *stubAtom) {
return nullptr;
}
-
void Util::addIndirectSymbols(const lld::File &atomFile, NormalizedFile &file) {
for (SectionInfo *si : _sectionInfos) {
Section &normSect = file.sections[si->normalizedSectionIndex];
@@ -940,7 +930,6 @@ void Util::addIndirectSymbols(const lld::File &atomFile, NormalizedFile &file) {
break;
}
}
-
}
void Util::addDependentDylibs(const lld::File &atomFile,NormalizedFile &nFile) {
@@ -951,16 +940,28 @@ void Util::addDependentDylibs(const lld::File &atomFile,NormalizedFile &nFile) {
DylibPathToInfo::iterator pos = _dylibInfo.find(loadPath);
if (pos == _dylibInfo.end()) {
DylibInfo info;
- info.ordinal = ordinal++;
+ bool flatNamespaceAtom = &slAtom->file() == _ctx.flatNamespaceFile();
+
+ // If we're in -flat_namespace mode (or this atom came from the flat
+ // namespace file under -undefined dynamic_lookup) then use the flat
+ // lookup ordinal.
+ if (flatNamespaceAtom || _ctx.useFlatNamespace())
+ info.ordinal = BIND_SPECIAL_DYLIB_FLAT_LOOKUP;
+ else
+ info.ordinal = ordinal++;
info.hasWeak = slAtom->canBeNullAtRuntime();
info.hasNonWeak = !info.hasWeak;
_dylibInfo[loadPath] = info;
- DependentDylib depInfo;
- depInfo.path = loadPath;
- depInfo.kind = llvm::MachO::LC_LOAD_DYLIB;
- depInfo.currentVersion = _context.dylibCurrentVersion(loadPath);
- depInfo.compatVersion = _context.dylibCompatVersion(loadPath);
- nFile.dependentDylibs.push_back(depInfo);
+
+ // Unless this was a flat_namespace atom, record the source dylib.
+ if (!flatNamespaceAtom) {
+ DependentDylib depInfo;
+ depInfo.path = loadPath;
+ depInfo.kind = llvm::MachO::LC_LOAD_DYLIB;
+ depInfo.currentVersion = _ctx.dylibCurrentVersion(loadPath);
+ depInfo.compatVersion = _ctx.dylibCompatVersion(loadPath);
+ nFile.dependentDylibs.push_back(depInfo);
+ }
} else {
if ( slAtom->canBeNullAtRuntime() )
pos->second.hasWeak = true;
@@ -973,12 +974,11 @@ void Util::addDependentDylibs(const lld::File &atomFile,NormalizedFile &nFile) {
DylibInfo &info = _dylibInfo[dep.path];
if (info.hasWeak && !info.hasNonWeak)
dep.kind = llvm::MachO::LC_LOAD_WEAK_DYLIB;
- else if (_context.isUpwardDylib(dep.path))
+ else if (_ctx.isUpwardDylib(dep.path))
dep.kind = llvm::MachO::LC_LOAD_UPWARD_DYLIB;
}
}
-
int Util::dylibOrdinal(const SharedLibraryAtom *sa) {
return _dylibInfo[sa->loadName()].ordinal;
}
@@ -997,7 +997,6 @@ void Util::segIndexForSection(const SectionInfo *sect, uint8_t &segmentIndex,
llvm_unreachable("section not in any segment");
}
-
uint32_t Util::sectionIndexForAtom(const Atom *atom) {
uint64_t address = _atomToAddress[atom];
uint32_t index = 1;
@@ -1010,10 +1009,9 @@ uint32_t Util::sectionIndexForAtom(const Atom *atom) {
}
void Util::addSectionRelocs(const lld::File &, NormalizedFile &file) {
- if (_context.outputMachOType() != llvm::MachO::MH_OBJECT)
+ if (_ctx.outputMachOType() != llvm::MachO::MH_OBJECT)
return;
-
// Utility function for ArchHandler to find symbol index for an atom.
auto symIndexForAtom = [&] (const Atom &atom) -> uint32_t {
auto pos = _atomToSymbolIndex.find(&atom);
@@ -1090,7 +1088,7 @@ void Util::buildDataInCodeArray(const lld::File &, NormalizedFile &file) {
void Util::addRebaseAndBindingInfo(const lld::File &atomFile,
NormalizedFile &nFile) {
- if (_context.outputMachOType() == llvm::MachO::MH_OBJECT)
+ if (_ctx.outputMachOType() == llvm::MachO::MH_OBJECT)
return;
uint8_t segmentIndex;
@@ -1146,7 +1144,7 @@ void Util::addRebaseAndBindingInfo(const lld::File &atomFile,
}
void Util::addExportInfo(const lld::File &atomFile, NormalizedFile &nFile) {
- if (_context.outputMachOType() == llvm::MachO::MH_OBJECT)
+ if (_ctx.outputMachOType() == llvm::MachO::MH_OBJECT)
return;
for (SectionInfo *sect : _sectionInfos) {
@@ -1154,13 +1152,13 @@ void Util::addExportInfo(const lld::File &atomFile, NormalizedFile &nFile) {
const DefinedAtom *atom = info.atom;
if (atom->scope() != Atom::scopeGlobal)
continue;
- if (_context.exportRestrictMode()) {
- if (!_context.exportSymbolNamed(atom->name()))
+ if (_ctx.exportRestrictMode()) {
+ if (!_ctx.exportSymbolNamed(atom->name()))
continue;
}
Export exprt;
exprt.name = atom->name();
- exprt.offset = _atomToAddress[atom]; // FIXME: subtract base address
+ exprt.offset = _atomToAddress[atom] - _ctx.baseAddress();
exprt.kind = EXPORT_SYMBOL_FLAGS_KIND_REGULAR;
if (atom->merge() == DefinedAtom::mergeAsWeak)
exprt.flags = EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION;
@@ -1175,19 +1173,22 @@ void Util::addExportInfo(const lld::File &atomFile, NormalizedFile &nFile) {
uint32_t Util::fileFlags() {
// FIXME: these need to determined at runtime.
- if (_context.outputMachOType() == MH_OBJECT) {
+ if (_ctx.outputMachOType() == MH_OBJECT) {
return MH_SUBSECTIONS_VIA_SYMBOLS;
} else {
- if ((_context.outputMachOType() == MH_EXECUTE) && _context.PIE())
- return MH_DYLDLINK | MH_NOUNDEFS | MH_TWOLEVEL | MH_PIE;
- else
- return MH_DYLDLINK | MH_NOUNDEFS | MH_TWOLEVEL;
+ uint32_t flags = MH_DYLDLINK;
+ if (!_ctx.useFlatNamespace())
+ flags |= MH_TWOLEVEL | MH_NOUNDEFS;
+ if ((_ctx.outputMachOType() == MH_EXECUTE) && _ctx.PIE())
+ flags |= MH_PIE;
+ if (_hasTLVDescriptors)
+ flags |= (MH_PIE | MH_HAS_TLV_DESCRIPTORS);
+ return flags;
}
}
} // end anonymous namespace
-
namespace lld {
namespace mach_o {
namespace normalized {
@@ -1206,6 +1207,7 @@ normalizedFromAtoms(const lld::File &atomFile,
normFile.arch = context.arch();
normFile.fileType = context.outputMachOType();
normFile.flags = util.fileFlags();
+ normFile.stackSize = context.stackSize();
normFile.installName = context.installName();
normFile.currentVersion = context.currentVersion();
normFile.compatVersion = context.compatibilityVersion();
@@ -1231,8 +1233,6 @@ normalizedFromAtoms(const lld::File &atomFile,
return std::move(f);
}
-
} // namespace normalized
} // namespace mach_o
} // namespace lld
-
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
index 124e0eaffeeb..1c4bb1d4f6a3 100644
--- a/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
+++ b/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
@@ -27,12 +27,17 @@
#include "MachONormalizedFileBinaryUtils.h"
#include "lld/Core/Error.h"
#include "lld/Core/LLVM.h"
+#include "llvm/Support/Debug.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/MachO.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/raw_ostream.h"
using namespace llvm::MachO;
using namespace lld::mach_o::normalized;
+#define DEBUG_TYPE "normalized-file-to-atoms"
+
namespace lld {
namespace mach_o {
@@ -78,6 +83,11 @@ const MachORelocatableSectionToAtomType sectsToAtomType[] = {
ENTRY("", "", S_NON_LAZY_SYMBOL_POINTERS,
typeGOT),
ENTRY("__DATA", "__interposing", S_INTERPOSING, typeInterposingTuples),
+ ENTRY("__DATA", "__thread_vars", S_THREAD_LOCAL_VARIABLES,
+ typeThunkTLV),
+ ENTRY("__DATA", "__thread_data", S_THREAD_LOCAL_REGULAR, typeTLVInitialData),
+ ENTRY("__DATA", "__thread_bss", S_THREAD_LOCAL_ZEROFILL,
+ typeTLVInitialZeroFill),
ENTRY("", "", S_INTERPOSING, typeInterposingTuples),
ENTRY("__LD", "__compact_unwind", S_REGULAR,
typeCompactUnwindInfo),
@@ -228,7 +238,7 @@ void atomFromSymbol(DefinedAtom::ContentType atomType, const Section &section,
uint64_t size = nextSymbolAddr - symbolAddr;
uint64_t offset = symbolAddr - section.address;
bool noDeadStrip = (symbolDescFlags & N_NO_DEAD_STRIP) || !scatterable;
- if (section.type == llvm::MachO::S_ZEROFILL) {
+ if (isZeroFillSection(section.type)) {
file.addZeroFillDefinedAtom(symbolName, symbolScope, offset, size,
noDeadStrip, copyRefs, &section);
} else {
@@ -558,17 +568,17 @@ std::error_code convertRelocs(const Section &section,
*result = target;
return std::error_code();
}
- return make_dynamic_error_code(Twine("no atom found for defined symbol"));
+ return make_dynamic_error_code("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 make_dynamic_error_code(Twine("no undefined atom found for sym"));
+ return make_dynamic_error_code("no undefined atom found for sym");
} else {
// Search undefs
- return make_dynamic_error_code(Twine("no atom found for symbol"));
+ return make_dynamic_error_code("no atom found for symbol");
}
};
@@ -594,10 +604,37 @@ std::error_code convertRelocs(const Section &section,
Reference::KindValue kind;
std::error_code relocErr;
if (handler.isPairedReloc(reloc)) {
- // Handle paired relocations together.
+ // Handle paired relocations together.
+ const Relocation &reloc2 = *++it;
relocErr = handler.getPairReferenceInfo(
- reloc, *++it, inAtom, offsetInAtom, fixupAddress, isBig, scatterable,
+ 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)))
+ + ")" );
+ }
}
else {
// Use ArchHandler to convert relocation record into information
@@ -605,26 +642,25 @@ std::error_code convertRelocs(const Section &section,
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)))
+ + ")" );
+ }
}
- 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)))
- + ")" );
- } else {
- // Instantiate an lld::Reference object and add to its atom.
- inAtom->addReference(offsetInAtom, kind, target, addend,
- handler.kindArch());
- }
+ // Instantiate an lld::Reference object and add to its atom.
+ inAtom->addReference(offsetInAtom, kind, target, addend,
+ handler.kindArch());
}
return std::error_code();
@@ -644,11 +680,158 @@ static int64_t readSPtr(bool is64, bool isBig, const uint8_t *addr) {
return res;
}
+/// --- Augmentation String Processing ---
+
+struct CIEInfo {
+ bool _augmentationDataPresent = false;
+ bool _mayHaveLSDA = false;
+};
+
+typedef llvm::DenseMap<const MachODefinedAtom*, CIEInfo> CIEInfoMap;
+
+static std::error_code processAugmentationString(const uint8_t *augStr,
+ CIEInfo &cieInfo,
+ unsigned *len = nullptr) {
+
+ if (augStr[0] == '\0') {
+ if (len)
+ *len = 1;
+ return std::error_code();
+ }
+
+ if (augStr[0] != 'z')
+ return make_dynamic_error_code("expected 'z' at start of augmentation "
+ "string");
+
+ cieInfo._augmentationDataPresent = true;
+ uint64_t idx = 1;
+
+ while (augStr[idx] != '\0') {
+ if (augStr[idx] == 'L') {
+ cieInfo._mayHaveLSDA = true;
+ ++idx;
+ } else
+ ++idx;
+ }
+
+ if (len)
+ *len = idx + 1;
+ return std::error_code();
+}
+
+static std::error_code processCIE(const NormalizedFile &normalizedFile,
+ MachODefinedAtom *atom,
+ CIEInfoMap &cieInfos) {
+ const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
+ const uint8_t *frameData = atom->rawContent().data();
+
+ CIEInfo cieInfo;
+
+ uint32_t size = read32(frameData, isBig);
+ uint64_t cieIDField = size == 0xffffffffU
+ ? sizeof(uint32_t) + sizeof(uint64_t)
+ : sizeof(uint32_t);
+ uint64_t versionField = cieIDField + sizeof(uint32_t);
+ uint64_t augmentationStringField = versionField + sizeof(uint8_t);
+
+ if (auto err = processAugmentationString(frameData + augmentationStringField,
+ cieInfo))
+ return err;
+
+ cieInfos[atom] = std::move(cieInfo);
+
+ return std::error_code();
+}
+
+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) {
+
+ 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.
+ if (atom->begin() != atom->end())
+ return std::error_code();
+
+ const uint8_t *frameData = atom->rawContent().data();
+ uint32_t size = read32(frameData, isBig);
+ uint64_t cieFieldInFDE = size == 0xffffffffU
+ ? sizeof(uint32_t) + sizeof(uint64_t)
+ : sizeof(uint32_t);
+
+ // Linker needs to fixup a reference from the FDE to its parent CIE (a
+ // 32-bit byte offset backwards in the __eh_frame section).
+ uint32_t cieDelta = read32(frameData + cieFieldInFDE, isBig);
+ 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 &&
+ "FDE's CIE field does not point at the start of a CIE.");
+
+ const CIEInfo &cieInfo = cieInfos.find(cie)->second;
+
+ // Linker needs to fixup reference from the FDE to the function it's
+ // describing. FIXME: there are actually different ways to do this, and the
+ // particular method used is specified in the CIE's augmentation fields
+ // (hopefully)
+ uint64_t rangeFieldInFDE = cieFieldInFDE + sizeof(uint32_t);
+
+ int64_t functionFromFDE = readSPtr(is64, isBig,
+ frameData + rangeFieldInFDE);
+ 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());
+
+ // Handle the augmentation data if there is any.
+ if (cieInfo._augmentationDataPresent) {
+ // First process the augmentation data length field.
+ uint64_t augmentationDataLengthFieldInFDE =
+ rangeFieldInFDE + 2 * (is64 ? sizeof(uint64_t) : sizeof(uint32_t));
+ unsigned lengthFieldSize = 0;
+ uint64_t augmentationDataLength =
+ llvm::decodeULEB128(frameData + augmentationDataLengthFieldInFDE,
+ &lengthFieldSize);
+
+ if (cieInfo._mayHaveLSDA && augmentationDataLength > 0) {
+
+ // Look at the augmentation data field.
+ uint64_t augmentationDataFieldInFDE =
+ augmentationDataLengthFieldInFDE + lengthFieldSize;
+
+ int64_t lsdaFromFDE = readSPtr(is64, isBig,
+ frameData + augmentationDataFieldInFDE);
+ 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());
+ }
+ }
+
+ return std::error_code();
+}
+
std::error_code addEHFrameReferences(const NormalizedFile &normalizedFile,
MachOFile &file,
mach_o::ArchHandler &handler) {
- const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
- const bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch);
const Section *ehFrameSection = nullptr;
for (auto &section : normalizedFile.sections)
@@ -662,51 +845,26 @@ std::error_code addEHFrameReferences(const NormalizedFile &normalizedFile,
if (!ehFrameSection)
return std::error_code();
+ std::error_code ehFrameErr;
+ CIEInfoMap cieInfos;
+
file.eachAtomInSection(*ehFrameSection,
[&](MachODefinedAtom *atom, uint64_t offset) -> void {
assert(atom->contentType() == DefinedAtom::typeCFI);
- if (ArchHandler::isDwarfCIE(isBig, atom))
+ // Bail out if we've encountered an error.
+ if (ehFrameErr)
return;
- // Compiler wasn't lazy and actually told us what it meant.
- if (atom->begin() != atom->end())
- return;
-
- const uint8_t *frameData = atom->rawContent().data();
- uint32_t size = read32(frameData, isBig);
- uint64_t cieFieldInFDE = size == 0xffffffffU
- ? sizeof(uint32_t) + sizeof(uint64_t)
- : sizeof(uint32_t);
-
- // Linker needs to fixup a reference from the FDE to its parent CIE (a
- // 32-bit byte offset backwards in the __eh_frame section).
- uint32_t cieDelta = read32(frameData + cieFieldInFDE, isBig);
- uint64_t cieAddress = ehFrameSection->address + offset + cieFieldInFDE;
- cieAddress -= cieDelta;
-
- Reference::Addend addend;
- const Atom *cie =
- findAtomCoveringAddress(normalizedFile, file, cieAddress, &addend);
- atom->addReference(cieFieldInFDE, handler.unwindRefToCIEKind(), cie,
- addend, handler.kindArch());
-
- // Linker needs to fixup reference from the FDE to the function it's
- // describing. FIXME: there are actually different ways to do this, and the
- // particular method used is specified in the CIE's augmentation fields
- // (hopefully)
- uint64_t rangeFieldInFDE = cieFieldInFDE + sizeof(uint32_t);
-
- int64_t functionFromFDE = readSPtr(is64, isBig, frameData + rangeFieldInFDE);
- 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());
+ const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
+ if (ArchHandler::isDwarfCIE(isBig, atom))
+ ehFrameErr = processCIE(normalizedFile, atom, cieInfos);
+ else
+ ehFrameErr = processFDE(normalizedFile, file, handler, ehFrameSection,
+ atom, offset, cieInfos);
});
- return std::error_code();
+
+ return ehFrameErr;
}
@@ -738,10 +896,13 @@ std::error_code
normalizedObjectToAtoms(MachOFile *file,
const NormalizedFile &normalizedFile,
bool copyRefs) {
+ DEBUG(llvm::dbgs() << "******** Normalizing file to atoms: "
+ << file->path() << "\n");
bool scatterable = ((normalizedFile.flags & MH_SUBSECTIONS_VIA_SYMBOLS) != 0);
// Create atoms from each section.
for (auto &sect : normalizedFile.sections) {
+ DEBUG(llvm::dbgs() << "Creating atoms: "; sect.dump());
if (isDebugInfoSection(sect))
continue;
bool customSectionName;
@@ -759,7 +920,8 @@ normalizedObjectToAtoms(MachOFile *file,
file->addUndefinedAtom(sym.name, copyRefs);
} else {
file->addTentativeDefAtom(sym.name, atomScope(sym.scope), sym.value,
- DefinedAtom::Alignment(sym.desc >> 8), copyRefs);
+ DefinedAtom::Alignment(1 << (sym.desc >> 8)),
+ copyRefs);
}
}
@@ -906,6 +1068,14 @@ normalizedToAtoms(const NormalizedFile &normalizedFile, StringRef path,
}
}
+#ifndef NDEBUG
+void Section::dump(llvm::raw_ostream &OS) const {
+ OS << "Section (\"" << segmentName << ", " << sectionName << "\"";
+ OS << ", addr: " << llvm::format_hex(address, 16, true);
+ OS << ", size: " << llvm::format_hex(content.size(), 8, true) << ")\n";
+}
+#endif
+
} // namespace normalized
} // namespace mach_o
} // namespace lld
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp
index ae14d755e2b9..0b92a68eeae8 100644
--- a/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp
+++ b/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp
@@ -276,9 +276,9 @@ struct MappingTraits<Section> {
io.mapRequired("section", sect.sectionName);
io.mapRequired("type", sect.type);
io.mapOptional("attributes", sect.attributes);
- io.mapOptional("alignment", sect.alignment, 0U);
+ io.mapOptional("alignment", sect.alignment, (uint16_t)1);
io.mapRequired("address", sect.address);
- if (sect.type == llvm::MachO::S_ZEROFILL) {
+ if (isZeroFillSection(sect.type)) {
// S_ZEROFILL sections use "size:" instead of "content:"
uint64_t size = sect.content.size();
io.mapOptional("size", size);
@@ -688,6 +688,7 @@ struct MappingTraits<NormalizedFile> {
io.mapOptional("has-UUID", file.hasUUID, true);
io.mapOptional("rpaths", file.rpaths);
io.mapOptional("entry-point", file.entryAddress, Hex64(0));
+ io.mapOptional("stack-size", file.stackSize, Hex64(0));
io.mapOptional("source-version", file.sourceVersion, Hex64(0));
io.mapOptional("OS", file.os);
io.mapOptional("min-os-version", file.minOSverson, PackedVersion(0));
@@ -799,4 +800,3 @@ std::error_code writeYaml(const NormalizedFile &file, raw_ostream &out) {
} // namespace normalized
} // namespace mach_o
} // namespace lld
-
diff --git a/lib/ReaderWriter/MachO/MachOPasses.h b/lib/ReaderWriter/MachO/MachOPasses.h
index 86f4bc0f5d54..a73785418d5f 100644
--- a/lib/ReaderWriter/MachO/MachOPasses.h
+++ b/lib/ReaderWriter/MachO/MachOPasses.h
@@ -19,6 +19,7 @@ namespace mach_o {
void addLayoutPass(PassManager &pm, const MachOLinkingContext &ctx);
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 addShimPass(PassManager &pm, const MachOLinkingContext &ctx);
diff --git a/lib/ReaderWriter/MachO/Makefile b/lib/ReaderWriter/MachO/Makefile
deleted file mode 100644
index 1acd578ba9d3..000000000000
--- a/lib/ReaderWriter/MachO/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-##===- lld/lib/ReaderWriter/MachO/Makefile --------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LLD_LEVEL := ../../..
-LIBRARYNAME := lldMachO
-USEDLIBS = lldCore.a
-
-include $(LLD_LEVEL)/Makefile
diff --git a/lib/ReaderWriter/MachO/SectCreateFile.h b/lib/ReaderWriter/MachO/SectCreateFile.h
new file mode 100644
index 000000000000..2e6e97c5433f
--- /dev/null
+++ b/lib/ReaderWriter/MachO/SectCreateFile.h
@@ -0,0 +1,93 @@
+//===---- lib/ReaderWriter/MachO/SectCreateFile.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_MACHO_SECTCREATE_FILE_H
+#define LLD_READER_WRITER_MACHO_SECTCREATE_FILE_H
+
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/Simple.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+
+namespace lld {
+namespace mach_o {
+
+//
+// A FlateNamespaceFile instance may be added as a resolution source of last
+// resort, depending on how -flat_namespace and -undefined are set.
+//
+class SectCreateFile : public File {
+public:
+ class SectCreateAtom : public SimpleDefinedAtom {
+ public:
+ SectCreateAtom(const File &file, StringRef segName, StringRef sectName,
+ std::unique_ptr<MemoryBuffer> content)
+ : SimpleDefinedAtom(file),
+ _combinedName((segName + "/" + sectName).str()),
+ _content(std::move(content)) {}
+
+ uint64_t size() const override { return _content->getBufferSize(); }
+
+ Scope scope() const override { return scopeGlobal; }
+
+ ContentType contentType() const override { return typeSectCreate; }
+
+ SectionChoice sectionChoice() const override { return sectionCustomRequired; }
+
+ StringRef customSectionName() const override { return _combinedName; }
+
+ DeadStripKind deadStrip() const override { return deadStripNever; }
+
+ ArrayRef<uint8_t> rawContent() const override {
+ const uint8_t *data =
+ reinterpret_cast<const uint8_t*>(_content->getBufferStart());
+ return ArrayRef<uint8_t>(data, _content->getBufferSize());
+ }
+
+ StringRef segmentName() const { return _segName; }
+ StringRef sectionName() const { return _sectName; }
+
+ private:
+ std::string _combinedName;
+ StringRef _segName;
+ StringRef _sectName;
+ std::unique_ptr<MemoryBuffer> _content;
+ };
+
+ SectCreateFile() : File("sectcreate", kindObject) {}
+
+ void addSection(StringRef seg, StringRef sect,
+ std::unique_ptr<MemoryBuffer> content) {
+ _definedAtoms.push_back(
+ new (allocator()) SectCreateAtom(*this, seg, sect, std::move(content)));
+ }
+
+ const AtomVector<DefinedAtom> &defined() const override {
+ return _definedAtoms;
+ }
+
+ const AtomVector<UndefinedAtom> &undefined() const override {
+ return _noUndefinedAtoms;
+ }
+
+ const AtomVector<SharedLibraryAtom> &sharedLibrary() const override {
+ return _noSharedLibraryAtoms;
+ }
+
+ const AtomVector<AbsoluteAtom> &absolute() const override {
+ return _noAbsoluteAtoms;
+ }
+
+private:
+ AtomVector<DefinedAtom> _definedAtoms;
+};
+
+} // namespace mach_o
+} // namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_SECTCREATE_FILE_H
diff --git a/lib/ReaderWriter/MachO/ShimPass.cpp b/lib/ReaderWriter/MachO/ShimPass.cpp
index a8c69f8ceace..df29e37c183b 100644
--- a/lib/ReaderWriter/MachO/ShimPass.cpp
+++ b/lib/ReaderWriter/MachO/ShimPass.cpp
@@ -41,16 +41,12 @@ namespace mach_o {
class ShimPass : public Pass {
public:
ShimPass(const MachOLinkingContext &context)
- : _context(context)
- , _archHandler(_context.archHandler())
- , _stubInfo(_archHandler.stubInfo())
- , _file("<mach-o shim pass>") {
- }
-
+ : _ctx(context), _archHandler(_ctx.archHandler()),
+ _stubInfo(_archHandler.stubInfo()), _file("<mach-o shim pass>") {}
- void perform(std::unique_ptr<MutableFile> &mergedFile) override {
+ std::error_code perform(SimpleFile &mergedFile) override {
// Scan all references in all atoms.
- for (const DefinedAtom *atom : mergedFile->defined()) {
+ for (const DefinedAtom *atom : mergedFile.defined()) {
for (const Reference *ref : *atom) {
// Look at non-call branches.
if (!_archHandler.isNonCallBranch(*ref))
@@ -67,7 +63,7 @@ public:
}
// Exit early if no shims needed.
if (_targetToShim.empty())
- return;
+ return std::error_code();
// Sort shim atoms so the layout order is stable.
std::vector<const DefinedAtom *> shims;
@@ -81,9 +77,10 @@ public:
});
// Add all shims to master file.
- for (const DefinedAtom *shim : shims) {
- mergedFile->addAtom(*shim);
- }
+ for (const DefinedAtom *shim : shims)
+ mergedFile.addAtom(*shim);
+
+ return std::error_code();
}
private:
@@ -112,7 +109,7 @@ private:
}
}
- const MachOLinkingContext &_context;
+ const MachOLinkingContext &_ctx;
mach_o::ArchHandler &_archHandler;
const ArchHandler::StubInfo &_stubInfo;
MachOFile _file;
diff --git a/lib/ReaderWriter/MachO/StubsPass.cpp b/lib/ReaderWriter/MachO/StubsPass.cpp
index bc4d9c2087f3..1f61256a5b79 100644
--- a/lib/ReaderWriter/MachO/StubsPass.cpp
+++ b/lib/ReaderWriter/MachO/StubsPass.cpp
@@ -1,4 +1,4 @@
-//===- lib/ReaderWriter/MachO/StubsPass.cpp -------------------------------===//
+//===- lib/ReaderWriter/MachO/StubsPass.cpp ---------------------*- C++ -*-===//
//
// The LLVM Linker
//
@@ -26,11 +26,9 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
-
namespace lld {
namespace mach_o {
-
//
// Lazy Pointer Atom created by the stubs pass.
//
@@ -44,7 +42,7 @@ public:
}
Alignment alignment() const override {
- return Alignment(_is64 ? 3 : 2);
+ return _is64 ? 8 : 4;
}
uint64_t size() const override {
@@ -65,7 +63,6 @@ private:
const bool _is64;
};
-
//
// NonLazyPointer (GOT) Atom created by the stubs pass.
//
@@ -79,7 +76,7 @@ public:
}
Alignment alignment() const override {
- return Alignment(_is64 ? 3 : 2);
+ return _is64 ? 8 : 4;
}
uint64_t size() const override {
@@ -100,8 +97,6 @@ private:
const bool _is64;
};
-
-
//
// Stub Atom created by the stubs pass.
//
@@ -115,7 +110,7 @@ public:
}
Alignment alignment() const override {
- return Alignment(_stubInfo.codeAlignment);
+ return 1 << _stubInfo.codeAlignment;
}
uint64_t size() const override {
@@ -134,7 +129,6 @@ private:
const ArchHandler::StubInfo &_stubInfo;
};
-
//
// Stub Helper Atom created by the stubs pass.
//
@@ -148,7 +142,7 @@ public:
}
Alignment alignment() const override {
- return Alignment(_stubInfo.codeAlignment);
+ return 1 << _stubInfo.codeAlignment;
}
uint64_t size() const override {
@@ -168,7 +162,6 @@ private:
const ArchHandler::StubInfo &_stubInfo;
};
-
//
// Stub Helper Common Atom created by the stubs pass.
//
@@ -182,7 +175,7 @@ public:
}
Alignment alignment() const override {
- return Alignment(_stubInfo.codeAlignment);
+ return 1 << _stubInfo.codeAlignment;
}
uint64_t size() const override {
@@ -202,21 +195,19 @@ private:
const ArchHandler::StubInfo &_stubInfo;
};
-
class StubsPass : public Pass {
public:
StubsPass(const MachOLinkingContext &context)
- : _context(context), _archHandler(_context.archHandler()),
- _stubInfo(_archHandler.stubInfo()), _file("<mach-o Stubs pass>") { }
+ : _ctx(context), _archHandler(_ctx.archHandler()),
+ _stubInfo(_archHandler.stubInfo()), _file("<mach-o Stubs pass>") {}
-
- void perform(std::unique_ptr<MutableFile> &mergedFile) override {
+ std::error_code perform(SimpleFile &mergedFile) override {
// Skip this pass if output format uses text relocations instead of stubs.
if (!this->noTextRelocs())
- return;
+ return std::error_code();
// Scan all references in all atoms.
- for (const DefinedAtom *atom : mergedFile->defined()) {
+ for (const DefinedAtom *atom : mergedFile.defined()) {
for (const Reference *ref : *atom) {
// Look at call-sites.
if (!this->isCallSite(*ref))
@@ -240,15 +231,15 @@ public:
// Exit early if no stubs needed.
if (_targetToUses.empty())
- return;
+ return std::error_code();
// 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, _context.is64Bit());
+ new (_file.allocator()) NonLazyPointerAtom(_file, _ctx.is64Bit());
SimpleDefinedAtom *helperBinderNLPAtom =
- new (_file.allocator()) NonLazyPointerAtom(_file, _context.is64Bit());
+ new (_file.allocator()) NonLazyPointerAtom(_file, _ctx.is64Bit());
addReference(helperCommonAtom, _stubInfo.stubHelperCommonReferenceToCache,
helperCacheNLPAtom);
addOptReference(
@@ -259,17 +250,18 @@ public:
addOptReference(
helperCommonAtom, _stubInfo.stubHelperCommonReferenceToBinder,
_stubInfo.optStubHelperCommonReferenceToBinder, helperBinderNLPAtom);
- mergedFile->addAtom(*helperCommonAtom);
- mergedFile->addAtom(*helperBinderNLPAtom);
- mergedFile->addAtom(*helperCacheNLPAtom);
+ mergedFile.addAtom(*helperCommonAtom);
+ mergedFile.addAtom(*helperBinderNLPAtom);
+ mergedFile.addAtom(*helperCacheNLPAtom);
// Add reference to dyld_stub_binder in libSystem.dylib
auto I = std::find_if(
- mergedFile->sharedLibrary().begin(), mergedFile->sharedLibrary().end(),
+ mergedFile.sharedLibrary().begin(), mergedFile.sharedLibrary().end(),
[&](const SharedLibraryAtom *atom) {
return atom->name().equals(_stubInfo.binderSymbolName);
});
- assert(I != mergedFile->sharedLibrary().end() && "dyld_stub_binder not found");
+ assert(I != mergedFile.sharedLibrary().end() &&
+ "dyld_stub_binder not found");
addReference(helperBinderNLPAtom, _stubInfo.nonLazyPointerReferenceToBinder, *I);
// Sort targets by name, so stubs and lazy pointers are consistent
@@ -284,11 +276,10 @@ public:
// Make and append stubs, lazy pointers, and helpers in alphabetical order.
unsigned lazyOffset = 0;
for (const Atom *target : targetsNeedingStubs) {
- StubAtom *stub = new (_file.allocator()) StubAtom(_file, _stubInfo);
- LazyPointerAtom *lp =
- new (_file.allocator()) LazyPointerAtom(_file, _context.is64Bit());
- StubHelperAtom *helper =
- new (_file.allocator()) StubHelperAtom(_file, _stubInfo);
+ auto *stub = new (_file.allocator()) StubAtom(_file, _stubInfo);
+ auto *lp =
+ new (_file.allocator()) LazyPointerAtom(_file, _ctx.is64Bit());
+ auto *helper = new (_file.allocator()) StubHelperAtom(_file, _stubInfo);
addReference(stub, _stubInfo.stubReferenceToLP, lp);
addOptReference(stub, _stubInfo.stubReferenceToLP,
@@ -301,9 +292,9 @@ public:
addReference(helper, _stubInfo.stubHelperReferenceToHelperCommon,
helperCommonAtom);
- mergedFile->addAtom(*stub);
- mergedFile->addAtom(*lp);
- mergedFile->addAtom(*helper);
+ mergedFile.addAtom(*stub);
+ mergedFile.addAtom(*lp);
+ mergedFile.addAtom(*helper);
// Update each reference to use stub.
for (const Reference *ref : _targetToUses[target]) {
@@ -315,10 +306,11 @@ public:
// Calculate new offset
lazyOffset += target->name().size() + 12;
}
+
+ return std::error_code();
}
private:
-
bool noTextRelocs() {
return true;
}
@@ -356,15 +348,13 @@ private:
typedef llvm::DenseMap<const Atom*,
llvm::SmallVector<const Reference *, 8>> TargetToUses;
- const MachOLinkingContext &_context;
+ const MachOLinkingContext &_ctx;
mach_o::ArchHandler &_archHandler;
const ArchHandler::StubInfo &_stubInfo;
MachOFile _file;
TargetToUses _targetToUses;
};
-
-
void addStubsPass(PassManager &pm, const MachOLinkingContext &ctx) {
pm.add(std::unique_ptr<Pass>(new StubsPass(ctx)));
}
diff --git a/lib/ReaderWriter/MachO/TLVPass.cpp b/lib/ReaderWriter/MachO/TLVPass.cpp
new file mode 100644
index 000000000000..aba222edcd27
--- /dev/null
+++ b/lib/ReaderWriter/MachO/TLVPass.cpp
@@ -0,0 +1,137 @@
+//===- lib/ReaderWriter/MachO/TLVPass.cpp -----------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This linker pass transforms all TLV references to real references.
+///
+//===----------------------------------------------------------------------===//
+
+#include "ArchHandler.h"
+#include "File.h"
+#include "MachOPasses.h"
+#include "lld/Core/Simple.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Debug.h"
+
+namespace lld {
+namespace mach_o {
+
+//
+// TLVP Entry Atom created by the TLV pass.
+//
+class TLVPEntryAtom : public SimpleDefinedAtom {
+public:
+ TLVPEntryAtom(const File &file, bool is64, StringRef name)
+ : SimpleDefinedAtom(file), _is64(is64), _name(name) {}
+
+ ContentType contentType() const override {
+ return DefinedAtom::typeTLVInitializerPtr;
+ }
+
+ Alignment alignment() const override {
+ return _is64 ? 8 : 4;
+ }
+
+ uint64_t size() const override {
+ return _is64 ? 8 : 4;
+ }
+
+ ContentPermissions permissions() const override {
+ return DefinedAtom::permRW_;
+ }
+
+ ArrayRef<uint8_t> rawContent() const override {
+ static const uint8_t zeros[] =
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ return llvm::makeArrayRef(zeros, size());
+ }
+
+ StringRef slotName() const {
+ return _name;
+ }
+
+private:
+ const bool _is64;
+ StringRef _name;
+};
+
+class TLVPass : public Pass {
+public:
+ TLVPass(const MachOLinkingContext &context)
+ : _ctx(context), _archHandler(_ctx.archHandler()),
+ _file("<mach-o TLV Pass>") {}
+
+private:
+ std::error_code perform(SimpleFile &mergedFile) override {
+ bool allowTLV = _ctx.minOS("10.7", "1.0");
+
+ for (const DefinedAtom *atom : mergedFile.defined()) {
+ for (const Reference *ref : *atom) {
+ if (!_archHandler.isTLVAccess(*ref))
+ continue;
+
+ if (!allowTLV)
+ return make_dynamic_error_code(
+ "targeted OS version does not support use of thread local "
+ "variables in " + atom->name() + " for architecture " +
+ _ctx.archName());
+
+ const Atom *target = ref->target();
+ assert(target != nullptr);
+
+ const DefinedAtom *tlvpEntry = makeTLVPEntry(target);
+ const_cast<Reference*>(ref)->setTarget(tlvpEntry);
+ _archHandler.updateReferenceToTLV(ref);
+ }
+ }
+
+ std::vector<const TLVPEntryAtom*> entries;
+ entries.reserve(_targetToTLVP.size());
+ for (auto &it : _targetToTLVP)
+ entries.push_back(it.second);
+ std::sort(entries.begin(), entries.end(),
+ [](const TLVPEntryAtom *lhs, const TLVPEntryAtom *rhs) {
+ return (lhs->slotName().compare(rhs->slotName()) < 0);
+ });
+
+ for (const TLVPEntryAtom *slot : entries)
+ mergedFile.addAtom(*slot);
+
+ return std::error_code();
+ }
+
+ const DefinedAtom *makeTLVPEntry(const Atom *target) {
+ auto pos = _targetToTLVP.find(target);
+
+ if (pos != _targetToTLVP.end())
+ return pos->second;
+
+ auto *tlvpEntry = new (_file.allocator())
+ TLVPEntryAtom(_file, _ctx.is64Bit(), target->name());
+ _targetToTLVP[target] = tlvpEntry;
+ const ArchHandler::ReferenceInfo &nlInfo =
+ _archHandler.stubInfo().nonLazyPointerReferenceToBinder;
+ tlvpEntry->addReference(Reference::KindNamespace::mach_o, nlInfo.arch,
+ nlInfo.kind, 0, target, 0);
+ return tlvpEntry;
+ }
+
+ const MachOLinkingContext &_ctx;
+ mach_o::ArchHandler &_archHandler;
+ MachOFile _file;
+ llvm::DenseMap<const Atom*, const TLVPEntryAtom*> _targetToTLVP;
+};
+
+void addTLVPass(PassManager &pm, const MachOLinkingContext &ctx) {
+ assert(ctx.needsTLVPass());
+ pm.add(llvm::make_unique<TLVPass>(ctx));
+}
+
+} // end namesapce mach_o
+} // end namesapce lld
diff --git a/lib/ReaderWriter/MachO/WriterMachO.cpp b/lib/ReaderWriter/MachO/WriterMachO.cpp
index de1c0e38063b..cce0a179608c 100644
--- a/lib/ReaderWriter/MachO/WriterMachO.cpp
+++ b/lib/ReaderWriter/MachO/WriterMachO.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
-#include "ExecutableAtoms.hpp"
+#include "ExecutableAtoms.h"
#include "MachONormalizedFile.h"
#include "lld/Core/File.h"
#include "lld/Core/Writer.h"
@@ -26,18 +26,18 @@ namespace mach_o {
class MachOWriter : public Writer {
public:
- MachOWriter(const MachOLinkingContext &ctxt) : _context(ctxt) { }
+ MachOWriter(const MachOLinkingContext &ctxt) : _ctx(ctxt) {}
std::error_code writeFile(const lld::File &file, StringRef path) override {
// Construct empty normalized file from atoms.
ErrorOr<std::unique_ptr<NormalizedFile>> nFile =
- normalized::normalizedFromAtoms(file, _context);
+ normalized::normalizedFromAtoms(file, _ctx);
if (std::error_code ec = nFile.getError())
return ec;
// For testing, write out yaml form of normalized file.
- if (_context.printAtoms()) {
- std::unique_ptr<Writer> yamlWriter = createWriterYAML(_context);
+ if (_ctx.printAtoms()) {
+ std::unique_ptr<Writer> yamlWriter = createWriterYAML(_ctx);
yamlWriter->writeFile(file, "-");
}
@@ -45,21 +45,19 @@ public:
return writeBinary(*nFile->get(), path);
}
- bool createImplicitFiles(std::vector<std::unique_ptr<File> > &r) override {
+ void createImplicitFiles(std::vector<std::unique_ptr<File>> &r) override {
// When building main executables, add _main as required entry point.
- if (_context.outputTypeHasEntry())
- r.emplace_back(new CEntryFile(_context));
+ if (_ctx.outputTypeHasEntry())
+ r.emplace_back(new CEntryFile(_ctx));
// If this can link with dylibs, need helper function (dyld_stub_binder).
- if (_context.needsStubsPass())
- r.emplace_back(new StubHelperFile(_context));
+ if (_ctx.needsStubsPass())
+ r.emplace_back(new StubHelperFile(_ctx));
// Final linked images can access a symbol for their mach_header.
- if (_context.outputMachOType() != llvm::MachO::MH_OBJECT)
- r.emplace_back(new MachHeaderAliasFile(_context));
-
- return true;
+ if (_ctx.outputMachOType() != llvm::MachO::MH_OBJECT)
+ r.emplace_back(new MachHeaderAliasFile(_ctx));
}
private:
- const MachOLinkingContext &_context;
+ const MachOLinkingContext &_ctx;
};
diff --git a/lib/ReaderWriter/Makefile b/lib/ReaderWriter/Makefile
deleted file mode 100644
index 23587440805f..000000000000
--- a/lib/ReaderWriter/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-##===- lld/lib/ReaderWriter/Makefile ---------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LLD_LEVEL := ../..
-LIBRARYNAME := lldReaderWriter
-
-# these link against this lib
-PARALLEL_DIRS := ELF MachO Native PECOFF YAML
-
-include $(LLD_LEVEL)/Makefile
diff --git a/lib/ReaderWriter/Native/CMakeLists.txt b/lib/ReaderWriter/Native/CMakeLists.txt
deleted file mode 100644
index e15f3d60e89c..000000000000
--- a/lib/ReaderWriter/Native/CMakeLists.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-add_llvm_library(lldNative
- ReaderNative.cpp
- WriterNative.cpp
- LINK_LIBS
- lldCore
- LLVMSupport
- )
diff --git a/lib/ReaderWriter/Native/Makefile b/lib/ReaderWriter/Native/Makefile
deleted file mode 100644
index 6aba37868900..000000000000
--- a/lib/ReaderWriter/Native/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-##===- lld/lib/ReaderWriter/Native/Makefile --------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LLD_LEVEL := ../../..
-LIBRARYNAME := lldNative
-USEDLIBS = lldCore.a
-
-include $(LLD_LEVEL)/Makefile
diff --git a/lib/ReaderWriter/Native/NativeFileFormat.h b/lib/ReaderWriter/Native/NativeFileFormat.h
deleted file mode 100644
index 535072fe2314..000000000000
--- a/lib/ReaderWriter/Native/NativeFileFormat.h
+++ /dev/null
@@ -1,258 +0,0 @@
-//===- lib/ReaderWriter/Native/NativeFileFormat.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_NATIVE_NATIVE_FILE_FORMAT_H
-#define LLD_READER_WRITER_NATIVE_NATIVE_FILE_FORMAT_H
-
-#include "llvm/Support/DataTypes.h"
-#include <cstdint>
-
-namespace lld {
-
-//
-// Overview:
-//
-// The number one design goal of this file format is enable the linker to
-// read object files into in-memory Atom objects extremely quickly.
-// The second design goal is to enable future modifications to the
-// Atom attribute model.
-//
-// The llvm native object file format is not like traditional object file
-// formats (e.g. ELF, COFF, mach-o). There is no symbol table and no
-// sections. Instead the file is essentially an array of archived Atoms.
-// It is *not* serialized Atoms which would require deserialization into
-// in memory objects. Instead it is an array of read-only info about each
-// Atom. The NativeReader bulk creates in-memory Atoms which just have
-// an ivar which points to the read-only info for that Atom. No additional
-// processing is done to construct the in-memory Atoms. All Atom attribute
-// getter methods are virtual calls which dig up the info they need from the
-// ivar data.
-//
-// To support the gradual evolution of Atom attributes, the Atom read-only
-// data is versioned. The NativeReader chooses which in-memory Atom class
-// to use based on the version. What this means is that if new attributes
-// are added (or changed) in the Atom model, a new native atom class and
-// read-only atom info struct needs to be defined. Then, all the existing
-// native reader atom classes need to be modified to do their best effort
-// to map their old style read-only data to the new Atom model. At some point
-// some classes to support old versions may be dropped.
-//
-//
-// Details:
-//
-// The native object file format consists of a header that specifies the
-// endianness of the file and the architecture along with a list of "chunks"
-// in the file. A Chunk is simply a tagged range of the file. There is
-// one chunk for the array of atom infos. There is another chunk for the
-// string pool, and another for the content pool.
-//
-// It turns out there most atoms have very similar sets of attributes, only
-// the name and content attribute vary. To exploit this fact to reduce the file
-// size, the atom read-only info contains just the name and content info plus
-// a reference to which attribute set it uses. The attribute sets are stored
-// in another chunk.
-//
-
-
-//
-// An entry in the NativeFileHeader that describes one chunk of the file.
-//
-struct NativeChunk {
- uint32_t signature;
- uint32_t fileOffset;
- uint32_t fileSize;
- uint32_t elementCount;
-};
-
-
-//
-// The header in a native object file
-//
-struct NativeFileHeader {
- uint8_t magic[16];
- uint32_t endian;
- uint32_t architecture;
- uint32_t fileSize;
- uint32_t chunkCount;
- // NativeChunk chunks[]
-};
-
-//
-// Possible values for NativeChunk.signature field
-//
-enum NativeChunkSignatures {
- NCS_DefinedAtomsV1 = 1,
- NCS_AttributesArrayV1 = 2,
- NCS_AbsoluteAttributesV1 = 12,
- NCS_UndefinedAtomsV1 = 3,
- NCS_SharedLibraryAtomsV1 = 4,
- NCS_AbsoluteAtomsV1 = 5,
- NCS_Strings = 6,
- NCS_ReferencesArrayV1 = 7,
- NCS_ReferencesArrayV2 = 8,
- NCS_TargetsTable = 9,
- NCS_AddendsTable = 10,
- NCS_Content = 11,
-};
-
-//
-// The 16-bytes at the start of a native object file
-//
-#define NATIVE_FILE_HEADER_MAGIC "llvm nat obj v1 "
-
-//
-// Possible values for the NativeFileHeader.endian field
-//
-enum {
- NFH_BigEndian = 0x42696745,
- NFH_LittleEndian = 0x4574696c
-};
-
-
-//
-// Possible values for the NativeFileHeader.architecture field
-//
-enum {
- NFA_x86 = 1,
- NFA_x86_64 = 2,
- NFA_armv6 = 3,
- NFA_armv7 = 4,
-};
-
-
-//
-// The NCS_DefinedAtomsV1 chunk contains an array of these structs
-//
-struct NativeDefinedAtomIvarsV1 {
- uint32_t nameOffset;
- uint32_t attributesOffset;
- uint32_t referencesStartIndex;
- uint32_t referencesCount;
- uint32_t contentOffset;
- uint32_t contentSize;
- uint64_t sectionSize;
-};
-
-
-//
-// The NCS_AttributesArrayV1 chunk contains an array of these structs
-//
-struct NativeAtomAttributesV1 {
- uint32_t sectionNameOffset;
- uint16_t align2;
- uint16_t alignModulus;
- uint8_t scope;
- uint8_t interposable;
- uint8_t merge;
- uint8_t contentType;
- uint8_t sectionChoice;
- uint8_t deadStrip;
- uint8_t dynamicExport;
- uint8_t permissions;
- uint8_t alias;
- uint8_t codeModel;
-};
-
-
-
-//
-// The NCS_UndefinedAtomsV1 chunk contains an array of these structs
-//
-struct NativeUndefinedAtomIvarsV1 {
- uint32_t nameOffset;
- uint32_t flags;
- uint32_t fallbackNameOffset;
-};
-
-
-//
-// The NCS_SharedLibraryAtomsV1 chunk contains an array of these structs
-//
-struct NativeSharedLibraryAtomIvarsV1 {
- uint64_t size;
- uint32_t nameOffset;
- uint32_t loadNameOffset;
- uint32_t type;
- uint32_t flags;
-};
-
-
-
-//
-// The NCS_AbsoluteAtomsV1 chunk contains an array of these structs
-//
-struct NativeAbsoluteAtomIvarsV1 {
- uint32_t nameOffset;
- uint32_t attributesOffset;
- uint32_t reserved;
- uint64_t value;
-};
-
-
-
-//
-// The NCS_ReferencesArrayV1 chunk contains an array of these structs
-//
-struct NativeReferenceIvarsV1 {
- enum {
- noTarget = UINT16_MAX
- };
- uint32_t offsetInAtom;
- uint16_t kindValue;
- uint8_t kindNamespace;
- uint8_t kindArch;
- uint16_t targetIndex;
- uint16_t addendIndex;
-};
-
-
-//
-// The NCS_ReferencesArrayV2 chunk contains an array of these structs
-//
-struct NativeReferenceIvarsV2 {
- enum : unsigned {
- noTarget = UINT32_MAX
- };
- uint64_t offsetInAtom;
- int64_t addend;
- uint16_t kindValue;
- uint8_t kindNamespace;
- uint8_t kindArch;
- uint32_t targetIndex;
- uint32_t tag;
-};
-
-
-//
-// The NCS_TargetsTable chunk contains an array of uint32_t entries.
-// The C++ class Reference has a target() method that returns a
-// pointer to another Atom. We can't have pointers in object files,
-// so instead NativeReferenceIvarsV1 contains an index to the target.
-// The index is into this NCS_TargetsTable of uint32_t entries.
-// The values in this table are the index of the (target) atom in this file.
-// For DefinedAtoms the value is from 0 to NCS_DefinedAtomsV1.elementCount.
-// For UndefinedAtoms the value is from NCS_DefinedAtomsV1.elementCount to
-// NCS_DefinedAtomsV1.elementCount+NCS_UndefinedAtomsV1.elementCount.
-//
-
-
-//
-// The NCS_AddendsTable chunk contains an array of int64_t entries.
-// If we allocated space for addends directly in NativeReferenceIvarsV1
-// it would double the size of that struct. But since addends are rare,
-// we instead just keep a pool of addends and have NativeReferenceIvarsV1
-// (if it needs an addend) just store the index (into the pool) of the
-// addend it needs.
-//
-
-
-
-} // namespace lld
-
-#endif // LLD_READER_WRITER_NATIVE_NATIVE_FILE_FORMAT_H
diff --git a/lib/ReaderWriter/Native/ReaderNative.cpp b/lib/ReaderWriter/Native/ReaderNative.cpp
deleted file mode 100644
index 84cdb4b997e8..000000000000
--- a/lib/ReaderWriter/Native/ReaderNative.cpp
+++ /dev/null
@@ -1,1013 +0,0 @@
-//===- lib/ReaderWriter/Native/ReaderNative.cpp ---------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "NativeFileFormat.h"
-#include "lld/Core/Atom.h"
-#include "lld/Core/Error.h"
-#include "lld/Core/File.h"
-#include "lld/Core/Reader.h"
-#include "lld/Core/Simple.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/Format.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/raw_ostream.h"
-#include <memory>
-#include <vector>
-
-namespace lld {
-namespace native {
-
-// forward reference
-class File;
-
-//
-// An object of this class is instantied for each NativeDefinedAtomIvarsV1
-// struct in the NCS_DefinedAtomsV1 chunk.
-//
-class NativeDefinedAtomV1 : public DefinedAtom {
-public:
- NativeDefinedAtomV1(const File& f,
- const NativeDefinedAtomIvarsV1* ivarData)
- : _file(&f), _ivarData(ivarData) { }
-
- const lld::File& file() const override;
-
- uint64_t ordinal() const override;
-
- StringRef name() const override;
-
- uint64_t size() const override { return _ivarData->contentSize; }
-
- uint64_t sectionSize() const override { return _ivarData->sectionSize; }
-
- DefinedAtom::Scope scope() const override {
- return (DefinedAtom::Scope)(attributes().scope);
- }
-
- DefinedAtom::Interposable interposable() const override {
- return (DefinedAtom::Interposable)(attributes().interposable);
- }
-
- DefinedAtom::Merge merge() const override {
- return (DefinedAtom::Merge)(attributes().merge);
- }
-
- DefinedAtom::ContentType contentType() const override {
- const NativeAtomAttributesV1& attr = attributes();
- return (DefinedAtom::ContentType)(attr.contentType);
- }
-
- DefinedAtom::Alignment alignment() const override {
- return DefinedAtom::Alignment(attributes().align2, attributes().alignModulus);
- }
-
- DefinedAtom::SectionChoice sectionChoice() const override {
- return (DefinedAtom::SectionChoice)(attributes().sectionChoice);
- }
-
- StringRef customSectionName() const override;
-
- DefinedAtom::DeadStripKind deadStrip() const override {
- return (DefinedAtom::DeadStripKind)(attributes().deadStrip);
- }
-
- DynamicExport dynamicExport() const override {
- return (DynamicExport)attributes().dynamicExport;
- }
-
- DefinedAtom::CodeModel codeModel() const override {
- return DefinedAtom::CodeModel(attributes().codeModel);
- }
-
- DefinedAtom::ContentPermissions permissions() const override {
- return (DefinedAtom::ContentPermissions)(attributes().permissions);
- }
-
- ArrayRef<uint8_t> rawContent() const override;
-
- reference_iterator begin() const override;
-
- reference_iterator end() const override;
-
- const Reference* derefIterator(const void*) const override;
-
- void incrementIterator(const void*& it) const override;
-
-private:
- const NativeAtomAttributesV1& attributes() const;
-
- const File *_file;
- const NativeDefinedAtomIvarsV1 *_ivarData;
-};
-
-
-
-//
-// An object of this class is instantied for each NativeUndefinedAtomIvarsV1
-// struct in the NCS_UndefinedAtomsV1 chunk.
-//
-class NativeUndefinedAtomV1 : public UndefinedAtom {
-public:
- NativeUndefinedAtomV1(const File& f,
- const NativeUndefinedAtomIvarsV1* ivarData)
- : _file(&f), _ivarData(ivarData) { }
-
- const lld::File& file() const override;
- StringRef name() const override;
-
- CanBeNull canBeNull() const override {
- return (CanBeNull)(_ivarData->flags & 0x3);
- }
-
- const UndefinedAtom *fallback() const override;
-
-private:
- const File *_file;
- const NativeUndefinedAtomIvarsV1 *_ivarData;
- mutable std::unique_ptr<const SimpleUndefinedAtom> _fallback;
-};
-
-
-//
-// An object of this class is instantied for each NativeUndefinedAtomIvarsV1
-// struct in the NCS_SharedLibraryAtomsV1 chunk.
-//
-class NativeSharedLibraryAtomV1 : public SharedLibraryAtom {
-public:
- NativeSharedLibraryAtomV1(const File& f,
- const NativeSharedLibraryAtomIvarsV1* ivarData)
- : _file(&f), _ivarData(ivarData) { }
-
- const lld::File& file() const override;
- StringRef name() const override;
- StringRef loadName() const override;
-
- bool canBeNullAtRuntime() const override {
- return (_ivarData->flags & 0x1);
- }
-
- Type type() const override {
- return (Type)_ivarData->type;
- }
-
- uint64_t size() const override {
- return _ivarData->size;
- }
-
-private:
- const File *_file;
- const NativeSharedLibraryAtomIvarsV1 *_ivarData;
-};
-
-
-//
-// An object of this class is instantied for each NativeAbsoluteAtomIvarsV1
-// struct in the NCS_AbsoluteAtomsV1 chunk.
-//
-class NativeAbsoluteAtomV1 : public AbsoluteAtom {
-public:
- NativeAbsoluteAtomV1(const File& f,
- const NativeAbsoluteAtomIvarsV1* ivarData)
- : _file(&f), _ivarData(ivarData) { }
-
- const lld::File& file() const override;
- StringRef name() const override;
- Scope scope() const override {
- const NativeAtomAttributesV1& attr = absAttributes();
- return (Scope)(attr.scope);
- }
- uint64_t value() const override {
- return _ivarData->value;
- }
-
-private:
- const NativeAtomAttributesV1& absAttributes() const;
- const File *_file;
- const NativeAbsoluteAtomIvarsV1 *_ivarData;
-};
-
-
-//
-// An object of this class is instantied for each NativeReferenceIvarsV1
-// struct in the NCS_ReferencesArrayV1 chunk.
-//
-class NativeReferenceV1 : public Reference {
-public:
- NativeReferenceV1(const File &f, const NativeReferenceIvarsV1 *ivarData)
- : Reference((KindNamespace)ivarData->kindNamespace,
- (KindArch)ivarData->kindArch, ivarData->kindValue),
- _file(&f), _ivarData(ivarData) {}
-
- uint64_t offsetInAtom() const override {
- return _ivarData->offsetInAtom;
- }
-
- const Atom* target() const override;
- Addend addend() const override;
- void setTarget(const Atom* newAtom) override;
- void setAddend(Addend a) override;
-
-private:
- const File *_file;
- const NativeReferenceIvarsV1 *_ivarData;
-};
-
-
-//
-// An object of this class is instantied for each NativeReferenceIvarsV1
-// struct in the NCS_ReferencesArrayV1 chunk.
-//
-class NativeReferenceV2 : public Reference {
-public:
- NativeReferenceV2(const File &f, const NativeReferenceIvarsV2 *ivarData)
- : Reference((KindNamespace)ivarData->kindNamespace,
- (KindArch)ivarData->kindArch, ivarData->kindValue),
- _file(&f), _ivarData(ivarData) {}
-
- uint64_t offsetInAtom() const override {
- return _ivarData->offsetInAtom;
- }
-
- const Atom* target() const override;
- Addend addend() const override;
- void setTarget(const Atom* newAtom) override;
- void setAddend(Addend a) override;
- uint32_t tag() const override;
-
-private:
- const File *_file;
- const NativeReferenceIvarsV2 *_ivarData;
-};
-
-
-//
-// lld::File object for native llvm object file
-//
-class File : public lld::File {
-public:
- File(std::unique_ptr<MemoryBuffer> mb)
- : lld::File(mb->getBufferIdentifier(), kindObject),
- _mb(std::move(mb)), // Reader now takes ownership of buffer
- _header(nullptr), _targetsTable(nullptr), _targetsTableCount(0),
- _strings(nullptr), _stringsMaxOffset(0), _addends(nullptr),
- _addendsMaxIndex(0), _contentStart(nullptr), _contentEnd(nullptr) {
- _header =
- reinterpret_cast<const NativeFileHeader *>(_mb->getBufferStart());
- }
-
- /// Parses a File object from a native object file.
- std::error_code doParse() override {
- const uint8_t *const base =
- reinterpret_cast<const uint8_t *>(_mb->getBufferStart());
- StringRef path(_mb->getBufferIdentifier());
- const NativeFileHeader *const header =
- reinterpret_cast<const NativeFileHeader *>(base);
- const NativeChunk *const chunks =
- reinterpret_cast<const NativeChunk *>(base + sizeof(NativeFileHeader));
- // make sure magic matches
- if (memcmp(header->magic, NATIVE_FILE_HEADER_MAGIC,
- sizeof(header->magic)) != 0)
- return make_error_code(NativeReaderError::unknown_file_format);
-
- // make sure mapped file contains all needed data
- const size_t fileSize = _mb->getBufferSize();
- if (header->fileSize > fileSize)
- return make_error_code(NativeReaderError::file_too_short);
-
- DEBUG_WITH_TYPE("ReaderNative",
- llvm::dbgs() << " Native File Header:" << " fileSize="
- << header->fileSize << " chunkCount="
- << header->chunkCount << "\n");
-
- // process each chunk
- for (uint32_t i = 0; i < header->chunkCount; ++i) {
- std::error_code ec;
- const NativeChunk* chunk = &chunks[i];
- // sanity check chunk is within file
- if ( chunk->fileOffset > fileSize )
- return make_error_code(NativeReaderError::file_malformed);
- if ( (chunk->fileOffset + chunk->fileSize) > fileSize)
- return make_error_code(NativeReaderError::file_malformed);
- // process chunk, based on signature
- switch ( chunk->signature ) {
- case NCS_DefinedAtomsV1:
- ec = processDefinedAtomsV1(base, chunk);
- break;
- case NCS_AttributesArrayV1:
- ec = processAttributesV1(base, chunk);
- break;
- case NCS_UndefinedAtomsV1:
- ec = processUndefinedAtomsV1(base, chunk);
- break;
- case NCS_SharedLibraryAtomsV1:
- ec = processSharedLibraryAtomsV1(base, chunk);
- break;
- case NCS_AbsoluteAtomsV1:
- ec = processAbsoluteAtomsV1(base, chunk);
- break;
- case NCS_AbsoluteAttributesV1:
- ec = processAbsoluteAttributesV1(base, chunk);
- break;
- case NCS_ReferencesArrayV1:
- ec = processReferencesV1(base, chunk);
- break;
- case NCS_ReferencesArrayV2:
- ec = processReferencesV2(base, chunk);
- break;
- case NCS_TargetsTable:
- ec = processTargetsTable(base, chunk);
- break;
- case NCS_AddendsTable:
- ec = processAddendsTable(base, chunk);
- break;
- case NCS_Content:
- ec = processContent(base, chunk);
- break;
- case NCS_Strings:
- ec = processStrings(base, chunk);
- break;
- default:
- return make_error_code(NativeReaderError::unknown_chunk_type);
- }
- if ( ec ) {
- return ec;
- }
- }
- // TO DO: validate enough chunks were used
-
- DEBUG_WITH_TYPE("ReaderNative", {
- llvm::dbgs() << " ReaderNative DefinedAtoms:\n";
- for (const DefinedAtom *a : defined()) {
- llvm::dbgs() << llvm::format(" 0x%09lX", a)
- << ", name=" << a->name()
- << ", size=" << a->size() << "\n";
- for (const Reference *r : *a) {
- llvm::dbgs() << " offset="
- << llvm::format("0x%03X", r->offsetInAtom())
- << ", kind=" << r->kindValue()
- << ", target=" << r->target() << "\n";
- }
- }
- });
- return make_error_code(NativeReaderError::success);
- }
-
- virtual ~File() {
- // _mb is automatically deleted because of std::unique_ptr<>
-
- // All other ivar pointers are pointers into the MemoryBuffer, except
- // the _definedAtoms array which was allocated to contain an array
- // of Atom objects. The atoms have empty destructors, so it is ok
- // to just delete the memory.
- delete _definedAtoms._arrayStart;
- delete _undefinedAtoms._arrayStart;
- delete _sharedLibraryAtoms._arrayStart;
- delete _absoluteAtoms._arrayStart;
- delete _referencesV1.arrayStart;
- delete _referencesV2.arrayStart;
- delete [] _targetsTable;
- }
-
- const atom_collection<DefinedAtom>& defined() const override {
- return _definedAtoms;
- }
- const atom_collection<UndefinedAtom>& undefined() const override {
- return _undefinedAtoms;
- }
- const atom_collection<SharedLibraryAtom>& sharedLibrary() const override {
- return _sharedLibraryAtoms;
- }
- const atom_collection<AbsoluteAtom> &absolute() const override {
- return _absoluteAtoms;
- }
-
-private:
- friend NativeDefinedAtomV1;
- friend NativeUndefinedAtomV1;
- friend NativeSharedLibraryAtomV1;
- friend NativeAbsoluteAtomV1;
- friend NativeReferenceV1;
- friend NativeReferenceV2;
-
- // instantiate array of DefinedAtoms from v1 ivar data in file
- std::error_code processDefinedAtomsV1(const uint8_t *base,
- const NativeChunk *chunk) {
- const size_t atomSize = sizeof(NativeDefinedAtomV1);
- size_t atomsArraySize = chunk->elementCount * atomSize;
- uint8_t* atomsStart = reinterpret_cast<uint8_t*>
- (operator new(atomsArraySize, std::nothrow));
- if (atomsStart == nullptr)
- return make_error_code(NativeReaderError::memory_error);
- const size_t ivarElementSize = chunk->fileSize
- / chunk->elementCount;
- if ( ivarElementSize != sizeof(NativeDefinedAtomIvarsV1) )
- return make_error_code(NativeReaderError::file_malformed);
- uint8_t* atomsEnd = atomsStart + atomsArraySize;
- const NativeDefinedAtomIvarsV1* ivarData =
- reinterpret_cast<const NativeDefinedAtomIvarsV1*>
- (base + chunk->fileOffset);
- for(uint8_t* s = atomsStart; s != atomsEnd; s += atomSize) {
- NativeDefinedAtomV1* atomAllocSpace =
- reinterpret_cast<NativeDefinedAtomV1*>(s);
- new (atomAllocSpace) NativeDefinedAtomV1(*this, ivarData);
- ++ivarData;
- }
- this->_definedAtoms._arrayStart = atomsStart;
- this->_definedAtoms._arrayEnd = atomsEnd;
- this->_definedAtoms._elementSize = atomSize;
- this->_definedAtoms._elementCount = chunk->elementCount;
- DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs()
- << " chunk DefinedAtomsV1: "
- << " count=" << chunk->elementCount
- << " chunkSize=" << chunk->fileSize
- << "\n");
- return make_error_code(NativeReaderError::success);
- }
-
-
-
- // set up pointers to attributes array
- std::error_code processAttributesV1(const uint8_t *base,
- const NativeChunk *chunk) {
- this->_attributes = base + chunk->fileOffset;
- this->_attributesMaxOffset = chunk->fileSize;
- DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs()
- << " chunk AttributesV1: "
- << " count=" << chunk->elementCount
- << " chunkSize=" << chunk->fileSize
- << "\n");
- return make_error_code(NativeReaderError::success);
- }
-
- // set up pointers to attributes array
- std::error_code processAbsoluteAttributesV1(const uint8_t *base,
- const NativeChunk *chunk) {
- this->_absAttributes = base + chunk->fileOffset;
- this->_absAbsoluteMaxOffset = chunk->fileSize;
- DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs()
- << " chunk AbsoluteAttributesV1: "
- << " count=" << chunk->elementCount
- << " chunkSize=" << chunk->fileSize
- << "\n");
- return make_error_code(NativeReaderError::success);
- }
-
- // instantiate array of UndefinedAtoms from v1 ivar data in file
- std::error_code processUndefinedAtomsV1(const uint8_t *base,
- const NativeChunk *chunk) {
- const size_t atomSize = sizeof(NativeUndefinedAtomV1);
- size_t atomsArraySize = chunk->elementCount * atomSize;
- uint8_t* atomsStart = reinterpret_cast<uint8_t*>
- (operator new(atomsArraySize, std::nothrow));
- if (atomsStart == nullptr)
- return make_error_code(NativeReaderError::memory_error);
- const size_t ivarElementSize = chunk->fileSize
- / chunk->elementCount;
- if ( ivarElementSize != sizeof(NativeUndefinedAtomIvarsV1) )
- return make_error_code(NativeReaderError::file_malformed);
- uint8_t* atomsEnd = atomsStart + atomsArraySize;
- const NativeUndefinedAtomIvarsV1* ivarData =
- reinterpret_cast<const NativeUndefinedAtomIvarsV1*>
- (base + chunk->fileOffset);
- for(uint8_t* s = atomsStart; s != atomsEnd; s += atomSize) {
- NativeUndefinedAtomV1* atomAllocSpace =
- reinterpret_cast<NativeUndefinedAtomV1*>(s);
- new (atomAllocSpace) NativeUndefinedAtomV1(*this, ivarData);
- ++ivarData;
- }
- this->_undefinedAtoms._arrayStart = atomsStart;
- this->_undefinedAtoms._arrayEnd = atomsEnd;
- this->_undefinedAtoms._elementSize = atomSize;
- this->_undefinedAtoms._elementCount = chunk->elementCount;
- DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs()
- << " chunk UndefinedAtomsV1:"
- << " count=" << chunk->elementCount
- << " chunkSize=" << chunk->fileSize
- << "\n");
- return make_error_code(NativeReaderError::success);
- }
-
-
- // instantiate array of ShareLibraryAtoms from v1 ivar data in file
- std::error_code processSharedLibraryAtomsV1(const uint8_t *base,
- const NativeChunk *chunk) {
- const size_t atomSize = sizeof(NativeSharedLibraryAtomV1);
- size_t atomsArraySize = chunk->elementCount * atomSize;
- uint8_t* atomsStart = reinterpret_cast<uint8_t*>
- (operator new(atomsArraySize, std::nothrow));
- if (atomsStart == nullptr)
- return make_error_code(NativeReaderError::memory_error);
- const size_t ivarElementSize = chunk->fileSize
- / chunk->elementCount;
- if ( ivarElementSize != sizeof(NativeSharedLibraryAtomIvarsV1) )
- return make_error_code(NativeReaderError::file_malformed);
- uint8_t* atomsEnd = atomsStart + atomsArraySize;
- const NativeSharedLibraryAtomIvarsV1* ivarData =
- reinterpret_cast<const NativeSharedLibraryAtomIvarsV1*>
- (base + chunk->fileOffset);
- for(uint8_t* s = atomsStart; s != atomsEnd; s += atomSize) {
- NativeSharedLibraryAtomV1* atomAllocSpace =
- reinterpret_cast<NativeSharedLibraryAtomV1*>(s);
- new (atomAllocSpace) NativeSharedLibraryAtomV1(*this, ivarData);
- ++ivarData;
- }
- this->_sharedLibraryAtoms._arrayStart = atomsStart;
- this->_sharedLibraryAtoms._arrayEnd = atomsEnd;
- this->_sharedLibraryAtoms._elementSize = atomSize;
- this->_sharedLibraryAtoms._elementCount = chunk->elementCount;
- DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs()
- << " chunk SharedLibraryAtomsV1:"
- << " count=" << chunk->elementCount
- << " chunkSize=" << chunk->fileSize
- << "\n");
- return make_error_code(NativeReaderError::success);
- }
-
-
- // instantiate array of AbsoluteAtoms from v1 ivar data in file
- std::error_code processAbsoluteAtomsV1(const uint8_t *base,
- const NativeChunk *chunk) {
- const size_t atomSize = sizeof(NativeAbsoluteAtomV1);
- size_t atomsArraySize = chunk->elementCount * atomSize;
- uint8_t* atomsStart = reinterpret_cast<uint8_t*>
- (operator new(atomsArraySize, std::nothrow));
- if (atomsStart == nullptr)
- return make_error_code(NativeReaderError::memory_error);
- const size_t ivarElementSize = chunk->fileSize
- / chunk->elementCount;
- if ( ivarElementSize != sizeof(NativeAbsoluteAtomIvarsV1) )
- return make_error_code(NativeReaderError::file_malformed);
- uint8_t* atomsEnd = atomsStart + atomsArraySize;
- const NativeAbsoluteAtomIvarsV1* ivarData =
- reinterpret_cast<const NativeAbsoluteAtomIvarsV1*>
- (base + chunk->fileOffset);
- for(uint8_t* s = atomsStart; s != atomsEnd; s += atomSize) {
- NativeAbsoluteAtomV1* atomAllocSpace =
- reinterpret_cast<NativeAbsoluteAtomV1*>(s);
- new (atomAllocSpace) NativeAbsoluteAtomV1(*this, ivarData);
- ++ivarData;
- }
- this->_absoluteAtoms._arrayStart = atomsStart;
- this->_absoluteAtoms._arrayEnd = atomsEnd;
- this->_absoluteAtoms._elementSize = atomSize;
- this->_absoluteAtoms._elementCount = chunk->elementCount;
- DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs()
- << " chunk AbsoluteAtomsV1: "
- << " count=" << chunk->elementCount
- << " chunkSize=" << chunk->fileSize
- << "\n");
- return make_error_code(NativeReaderError::success);
- }
-
- template <class T, class U>
- std::error_code
- processReferences(const uint8_t *base, const NativeChunk *chunk,
- uint8_t *&refsStart, uint8_t *&refsEnd) const {
- if (chunk->elementCount == 0)
- return make_error_code(NativeReaderError::success);
- size_t refsArraySize = chunk->elementCount * sizeof(T);
- refsStart = reinterpret_cast<uint8_t *>(
- operator new(refsArraySize, std::nothrow));
- if (refsStart == nullptr)
- return make_error_code(NativeReaderError::memory_error);
- const size_t ivarElementSize = chunk->fileSize / chunk->elementCount;
- if (ivarElementSize != sizeof(U))
- return make_error_code(NativeReaderError::file_malformed);
- refsEnd = refsStart + refsArraySize;
- const U* ivarData = reinterpret_cast<const U *>(base + chunk->fileOffset);
- for (uint8_t *s = refsStart; s != refsEnd; s += sizeof(T), ++ivarData) {
- T *atomAllocSpace = reinterpret_cast<T *>(s);
- new (atomAllocSpace) T(*this, ivarData);
- }
- return make_error_code(NativeReaderError::success);
- }
-
- // instantiate array of References from v1 ivar data in file
- std::error_code processReferencesV1(const uint8_t *base,
- const NativeChunk *chunk) {
- uint8_t *refsStart, *refsEnd;
- if (std::error_code ec =
- processReferences<NativeReferenceV1, NativeReferenceIvarsV1>(
- base, chunk, refsStart, refsEnd))
- return ec;
- this->_referencesV1.arrayStart = refsStart;
- this->_referencesV1.arrayEnd = refsEnd;
- this->_referencesV1.elementSize = sizeof(NativeReferenceV1);
- this->_referencesV1.elementCount = chunk->elementCount;
- DEBUG_WITH_TYPE("ReaderNative", {
- llvm::dbgs() << " chunk ReferencesV1: "
- << " count=" << chunk->elementCount
- << " chunkSize=" << chunk->fileSize << "\n";
- });
- return make_error_code(NativeReaderError::success);
- }
-
- // instantiate array of References from v2 ivar data in file
- std::error_code processReferencesV2(const uint8_t *base,
- const NativeChunk *chunk) {
- uint8_t *refsStart, *refsEnd;
- if (std::error_code ec =
- processReferences<NativeReferenceV2, NativeReferenceIvarsV2>(
- base, chunk, refsStart, refsEnd))
- return ec;
- this->_referencesV2.arrayStart = refsStart;
- this->_referencesV2.arrayEnd = refsEnd;
- this->_referencesV2.elementSize = sizeof(NativeReferenceV2);
- this->_referencesV2.elementCount = chunk->elementCount;
- DEBUG_WITH_TYPE("ReaderNative", {
- llvm::dbgs() << " chunk ReferencesV2: "
- << " count=" << chunk->elementCount
- << " chunkSize=" << chunk->fileSize << "\n";
- });
- return make_error_code(NativeReaderError::success);
- }
-
- // set up pointers to target table
- std::error_code processTargetsTable(const uint8_t *base,
- const NativeChunk *chunk) {
- const uint32_t* targetIndexes = reinterpret_cast<const uint32_t*>
- (base + chunk->fileOffset);
- this->_targetsTableCount = chunk->elementCount;
- this->_targetsTable = new const Atom*[chunk->elementCount];
- for (uint32_t i=0; i < chunk->elementCount; ++i) {
- const uint32_t index = targetIndexes[i];
- if ( index < _definedAtoms._elementCount ) {
- const uint8_t* p = _definedAtoms._arrayStart
- + index * _definedAtoms._elementSize;
- this->_targetsTable[i] = reinterpret_cast<const DefinedAtom*>(p);
- continue;
- }
- const uint32_t undefIndex = index - _definedAtoms._elementCount;
- if ( undefIndex < _undefinedAtoms._elementCount ) {
- const uint8_t* p = _undefinedAtoms._arrayStart
- + undefIndex * _undefinedAtoms._elementSize;
- this->_targetsTable[i] = reinterpret_cast<const UndefinedAtom*>(p);
- continue;
- }
- const uint32_t slIndex = index - _definedAtoms._elementCount
- - _undefinedAtoms._elementCount;
- if ( slIndex < _sharedLibraryAtoms._elementCount ) {
- const uint8_t* p = _sharedLibraryAtoms._arrayStart
- + slIndex * _sharedLibraryAtoms._elementSize;
- this->_targetsTable[i] = reinterpret_cast<const SharedLibraryAtom*>(p);
- continue;
- }
- const uint32_t abIndex = index - _definedAtoms._elementCount
- - _undefinedAtoms._elementCount
- - _sharedLibraryAtoms._elementCount;
- if ( abIndex < _absoluteAtoms._elementCount ) {
- const uint8_t* p = _absoluteAtoms._arrayStart
- + abIndex * _absoluteAtoms._elementSize;
- this->_targetsTable[i] = reinterpret_cast<const AbsoluteAtom*>(p);
- continue;
- }
- return make_error_code(NativeReaderError::file_malformed);
- }
- DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs()
- << " chunk Targets Table: "
- << " count=" << chunk->elementCount
- << " chunkSize=" << chunk->fileSize
- << "\n");
- return make_error_code(NativeReaderError::success);
- }
-
-
- // set up pointers to addend pool in file
- std::error_code processAddendsTable(const uint8_t *base,
- const NativeChunk *chunk) {
- this->_addends = reinterpret_cast<const Reference::Addend*>
- (base + chunk->fileOffset);
- this->_addendsMaxIndex = chunk->elementCount;
- DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs()
- << " chunk Addends: "
- << " count=" << chunk->elementCount
- << " chunkSize=" << chunk->fileSize
- << "\n");
- return make_error_code(NativeReaderError::success);
- }
-
- // set up pointers to string pool in file
- std::error_code processStrings(const uint8_t *base,
- const NativeChunk *chunk) {
- this->_strings = reinterpret_cast<const char*>(base + chunk->fileOffset);
- this->_stringsMaxOffset = chunk->fileSize;
- DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs()
- << " chunk Strings: "
- << " chunkSize=" << chunk->fileSize
- << "\n");
- return make_error_code(NativeReaderError::success);
- }
-
- // set up pointers to content area in file
- std::error_code processContent(const uint8_t *base,
- const NativeChunk *chunk) {
- this->_contentStart = base + chunk->fileOffset;
- this->_contentEnd = base + chunk->fileOffset + chunk->fileSize;
- DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs()
- << " chunk content: "
- << " chunkSize=" << chunk->fileSize
- << "\n");
- return make_error_code(NativeReaderError::success);
- }
-
- StringRef string(uint32_t offset) const {
- assert(offset < _stringsMaxOffset);
- return StringRef(&_strings[offset]);
- }
-
- Reference::Addend addend(uint32_t index) const {
- if ( index == 0 )
- return 0; // addend index zero is used to mean "no addend"
- assert(index <= _addendsMaxIndex);
- return _addends[index-1]; // one-based indexing
- }
-
- const NativeAtomAttributesV1& attribute(uint32_t off) const {
- assert(off < _attributesMaxOffset);
- return *reinterpret_cast<const NativeAtomAttributesV1*>(_attributes + off);
- }
-
- const NativeAtomAttributesV1& absAttribute(uint32_t off) const {
- assert(off < _absAbsoluteMaxOffset);
- return *reinterpret_cast<const NativeAtomAttributesV1*>(_absAttributes + off);
- }
-
- const uint8_t* content(uint32_t offset, uint32_t size) const {
- const uint8_t* result = _contentStart + offset;
- assert((result+size) <= _contentEnd);
- return result;
- }
-
- const Reference* referenceByIndex(uintptr_t index) const {
- if (index < _referencesV1.elementCount) {
- return reinterpret_cast<const NativeReferenceV1*>(
- _referencesV1.arrayStart + index * _referencesV1.elementSize);
- }
- assert(index < _referencesV2.elementCount);
- return reinterpret_cast<const NativeReferenceV2*>(
- _referencesV2.arrayStart + index * _referencesV2.elementSize);
- }
-
- const Atom* targetV1(uint16_t index) const {
- if ( index == NativeReferenceIvarsV1::noTarget )
- return nullptr;
- assert(index < _targetsTableCount);
- return _targetsTable[index];
- }
-
- void setTargetV1(uint16_t index, const Atom* newAtom) const {
- assert(index != NativeReferenceIvarsV1::noTarget);
- assert(index > _targetsTableCount);
- _targetsTable[index] = newAtom;
- }
-
- const Atom* targetV2(uint32_t index) const {
- if (index == NativeReferenceIvarsV2::noTarget)
- return nullptr;
- assert(index < _targetsTableCount);
- return _targetsTable[index];
- }
-
- void setTargetV2(uint32_t index, const Atom* newAtom) const {
- assert(index != NativeReferenceIvarsV2::noTarget);
- assert(index > _targetsTableCount);
- _targetsTable[index] = newAtom;
- }
-
- template <typename T>
- class AtomArray : public File::atom_collection<T> {
- public:
- AtomArray() : _arrayStart(nullptr), _arrayEnd(nullptr),
- _elementSize(0), _elementCount(0) { }
-
- virtual atom_iterator<T> begin() const {
- return atom_iterator<T>(*this, reinterpret_cast<const void*>(_arrayStart));
- }
- virtual atom_iterator<T> end() const{
- return atom_iterator<T>(*this, reinterpret_cast<const void*>(_arrayEnd));
- }
- virtual const T* deref(const void* it) const {
- return reinterpret_cast<const T*>(it);
- }
- virtual void next(const void*& it) const {
- const uint8_t* p = reinterpret_cast<const uint8_t*>(it);
- p += _elementSize;
- it = reinterpret_cast<const void*>(p);
- }
- virtual uint64_t size() const { return _elementCount; }
- const uint8_t *_arrayStart;
- const uint8_t *_arrayEnd;
- uint32_t _elementSize;
- uint32_t _elementCount;
- };
-
- struct IvarArray {
- IvarArray() :
- arrayStart(nullptr),
- arrayEnd(nullptr),
- elementSize(0),
- elementCount(0) { }
-
- const uint8_t* arrayStart;
- const uint8_t* arrayEnd;
- uint32_t elementSize;
- uint32_t elementCount;
- };
-
- std::unique_ptr<MemoryBuffer> _mb;
- const NativeFileHeader* _header;
- AtomArray<DefinedAtom> _definedAtoms;
- AtomArray<UndefinedAtom> _undefinedAtoms;
- AtomArray<SharedLibraryAtom> _sharedLibraryAtoms;
- AtomArray<AbsoluteAtom> _absoluteAtoms;
- const uint8_t* _absAttributes;
- uint32_t _absAbsoluteMaxOffset;
- const uint8_t* _attributes;
- uint32_t _attributesMaxOffset;
- IvarArray _referencesV1;
- IvarArray _referencesV2;
- const Atom** _targetsTable;
- uint32_t _targetsTableCount;
- const char* _strings;
- uint32_t _stringsMaxOffset;
- const Reference::Addend* _addends;
- uint32_t _addendsMaxIndex;
- const uint8_t *_contentStart;
- const uint8_t *_contentEnd;
-};
-
-inline const lld::File &NativeDefinedAtomV1::file() const {
- return *_file;
-}
-
-inline uint64_t NativeDefinedAtomV1:: ordinal() const {
- const uint8_t* p = reinterpret_cast<const uint8_t*>(_ivarData);
- return p - _file->_definedAtoms._arrayStart;
-}
-
-inline StringRef NativeDefinedAtomV1::name() const {
- return _file->string(_ivarData->nameOffset);
-}
-
-inline const NativeAtomAttributesV1& NativeDefinedAtomV1::attributes() const {
- return _file->attribute(_ivarData->attributesOffset);
-}
-
-inline ArrayRef<uint8_t> NativeDefinedAtomV1::rawContent() const {
- if (!occupiesDiskSpace())
- return ArrayRef<uint8_t>();
- const uint8_t* p = _file->content(_ivarData->contentOffset,
- _ivarData->contentSize);
- return ArrayRef<uint8_t>(p, _ivarData->contentSize);
-}
-
-inline StringRef NativeDefinedAtomV1::customSectionName() const {
- uint32_t offset = attributes().sectionNameOffset;
- return _file->string(offset);
-}
-
-DefinedAtom::reference_iterator NativeDefinedAtomV1::begin() const {
- uintptr_t index = _ivarData->referencesStartIndex;
- const void* it = reinterpret_cast<const void*>(index);
- return reference_iterator(*this, it);
-}
-
-DefinedAtom::reference_iterator NativeDefinedAtomV1::end() const {
- uintptr_t index = _ivarData->referencesStartIndex+_ivarData->referencesCount;
- const void* it = reinterpret_cast<const void*>(index);
- return reference_iterator(*this, it);
-}
-
-const Reference* NativeDefinedAtomV1::derefIterator(const void* it) const {
- uintptr_t index = reinterpret_cast<uintptr_t>(it);
- return _file->referenceByIndex(index);
-}
-
-void NativeDefinedAtomV1::incrementIterator(const void*& it) const {
- uintptr_t index = reinterpret_cast<uintptr_t>(it);
- ++index;
- it = reinterpret_cast<const void*>(index);
-}
-
-inline const lld::File& NativeUndefinedAtomV1::file() const {
- return *_file;
-}
-
-inline StringRef NativeUndefinedAtomV1::name() const {
- return _file->string(_ivarData->nameOffset);
-}
-
-inline const UndefinedAtom *NativeUndefinedAtomV1::fallback() const {
- if (!_ivarData->fallbackNameOffset)
- return nullptr;
- if (!_fallback)
- _fallback.reset(new SimpleUndefinedAtom(
- *_file, _file->string(_ivarData->fallbackNameOffset)));
- return _fallback.get();
-}
-
-inline const lld::File& NativeSharedLibraryAtomV1::file() const {
- return *_file;
-}
-
-inline StringRef NativeSharedLibraryAtomV1::name() const {
- return _file->string(_ivarData->nameOffset);
-}
-
-inline StringRef NativeSharedLibraryAtomV1::loadName() const {
- return _file->string(_ivarData->loadNameOffset);
-}
-
-
-
-inline const lld::File& NativeAbsoluteAtomV1::file() const {
- return *_file;
-}
-
-inline StringRef NativeAbsoluteAtomV1::name() const {
- return _file->string(_ivarData->nameOffset);
-}
-
-inline const NativeAtomAttributesV1& NativeAbsoluteAtomV1::absAttributes() const {
- return _file->absAttribute(_ivarData->attributesOffset);
-}
-
-inline const Atom* NativeReferenceV1::target() const {
- return _file->targetV1(_ivarData->targetIndex);
-}
-
-inline Reference::Addend NativeReferenceV1::addend() const {
- return _file->addend(_ivarData->addendIndex);
-}
-
-inline void NativeReferenceV1::setTarget(const Atom* newAtom) {
- return _file->setTargetV1(_ivarData->targetIndex, newAtom);
-}
-
-inline void NativeReferenceV1::setAddend(Addend a) {
- // Do nothing if addend value is not being changed.
- if (addend() == a)
- return;
- llvm_unreachable("setAddend() not supported");
-}
-
-inline const Atom* NativeReferenceV2::target() const {
- return _file->targetV2(_ivarData->targetIndex);
-}
-
-inline Reference::Addend NativeReferenceV2::addend() const {
- return _ivarData->addend;
-}
-
-inline void NativeReferenceV2::setTarget(const Atom* newAtom) {
- return _file->setTargetV2(_ivarData->targetIndex, newAtom);
-}
-
-inline void NativeReferenceV2::setAddend(Addend a) {
- // Do nothing if addend value is not being changed.
- if (addend() == a)
- return;
- llvm_unreachable("setAddend() not supported");
-}
-
-uint32_t NativeReferenceV2::tag() const { return _ivarData->tag; }
-
-} // end namespace native
-
-namespace {
-
-class NativeReader : public Reader {
-public:
- virtual bool canParse(file_magic magic, StringRef,
- const MemoryBuffer &mb) const override {
- const NativeFileHeader *const header =
- reinterpret_cast<const NativeFileHeader *>(mb.getBufferStart());
- return (memcmp(header->magic, NATIVE_FILE_HEADER_MAGIC,
- sizeof(header->magic)) == 0);
- }
-
- virtual std::error_code
- loadFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &,
- std::vector<std::unique_ptr<File>> &result) const override {
- auto *file = new lld::native::File(std::move(mb));
- result.push_back(std::unique_ptr<File>(file));
- return std::error_code();
- }
-};
-
-}
-
-void Registry::addSupportNativeObjects() {
- add(std::unique_ptr<Reader>(new NativeReader()));
-}
-
-} // end namespace lld
diff --git a/lib/ReaderWriter/Native/WriterNative.cpp b/lib/ReaderWriter/Native/WriterNative.cpp
deleted file mode 100644
index 5e01a6ce1c7c..000000000000
--- a/lib/ReaderWriter/Native/WriterNative.cpp
+++ /dev/null
@@ -1,566 +0,0 @@
-//===- lib/ReaderWriter/Native/WriterNative.cpp ---------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "NativeFileFormat.h"
-#include "lld/Core/File.h"
-#include "lld/Core/LinkingContext.h"
-#include "lld/Core/Writer.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/raw_ostream.h"
-#include <cstdint>
-#include <set>
-#include <system_error>
-#include <vector>
-
-namespace lld {
-namespace native {
-
-///
-/// Class for writing native object files.
-///
-class Writer : public lld::Writer {
-public:
- std::error_code writeFile(const lld::File &file, StringRef outPath) override {
- // reserve first byte for unnamed atoms
- _stringPool.push_back('\0');
- // visit all atoms
- for ( const DefinedAtom *defAtom : file.defined() ) {
- this->addIVarsForDefinedAtom(*defAtom);
- // We are trying to process all atoms, but the defined() iterator does not
- // return group children. So, when a group parent is found, we need to
- // handle each child atom.
- if (defAtom->isGroupParent()) {
- for (const Reference *r : *defAtom) {
- if (r->kindNamespace() != lld::Reference::KindNamespace::all)
- continue;
- if (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");
- this->addIVarsForDefinedAtom(*target);
- }
- }
- }
- }
- for ( const UndefinedAtom *undefAtom : file.undefined() ) {
- this->addIVarsForUndefinedAtom(*undefAtom);
- }
- for ( const SharedLibraryAtom *shlibAtom : file.sharedLibrary() ) {
- this->addIVarsForSharedLibraryAtom(*shlibAtom);
- }
- for ( const AbsoluteAtom *absAtom : file.absolute() ) {
- this->addIVarsForAbsoluteAtom(*absAtom);
- }
-
- maybeConvertReferencesToV1();
-
- // construct file header based on atom information accumulated
- this->makeHeader();
-
- std::error_code ec;
- llvm::raw_fd_ostream out(outPath, ec, llvm::sys::fs::F_None);
- if (ec)
- return ec;
-
- this->write(out);
-
- return std::error_code();
- }
-
- virtual ~Writer() {
- }
-
-private:
-
- // write the lld::File in native format to the specified stream
- void write(raw_ostream &out) {
- assert(out.tell() == 0);
- out.write((char*)_headerBuffer, _headerBufferSize);
-
- writeChunk(out, _definedAtomIvars, NCS_DefinedAtomsV1);
- writeChunk(out, _attributes, NCS_AttributesArrayV1);
- writeChunk(out, _undefinedAtomIvars, NCS_UndefinedAtomsV1);
- writeChunk(out, _sharedLibraryAtomIvars, NCS_SharedLibraryAtomsV1);
- writeChunk(out, _absoluteAtomIvars, NCS_AbsoluteAtomsV1);
- writeChunk(out, _absAttributes, NCS_AbsoluteAttributesV1);
- writeChunk(out, _stringPool, NCS_Strings);
- writeChunk(out, _referencesV1, NCS_ReferencesArrayV1);
- writeChunk(out, _referencesV2, NCS_ReferencesArrayV2);
-
- if (!_targetsTableIndex.empty()) {
- assert(out.tell() == findChunk(NCS_TargetsTable).fileOffset);
- writeTargetTable(out);
- }
-
- if (!_addendsTableIndex.empty()) {
- assert(out.tell() == findChunk(NCS_AddendsTable).fileOffset);
- writeAddendTable(out);
- }
-
- writeChunk(out, _contentPool, NCS_Content);
- }
-
- template<class T>
- void writeChunk(raw_ostream &out, std::vector<T> &vector, uint32_t signature) {
- if (vector.empty())
- return;
- assert(out.tell() == findChunk(signature).fileOffset);
- out.write((char*)&vector[0], vector.size() * sizeof(T));
- }
-
- void addIVarsForDefinedAtom(const DefinedAtom& atom) {
- _definedAtomIndex[&atom] = _definedAtomIvars.size();
- NativeDefinedAtomIvarsV1 ivar;
- unsigned refsCount;
- ivar.nameOffset = getNameOffset(atom);
- ivar.attributesOffset = getAttributeOffset(atom);
- ivar.referencesStartIndex = getReferencesIndex(atom, refsCount);
- ivar.referencesCount = refsCount;
- ivar.contentOffset = getContentOffset(atom);
- ivar.contentSize = atom.size();
- ivar.sectionSize = atom.sectionSize();
- _definedAtomIvars.push_back(ivar);
- }
-
- void addIVarsForUndefinedAtom(const UndefinedAtom& atom) {
- _undefinedAtomIndex[&atom] = _undefinedAtomIvars.size();
- NativeUndefinedAtomIvarsV1 ivar;
- ivar.nameOffset = getNameOffset(atom);
- ivar.flags = (atom.canBeNull() & 0x03);
- ivar.fallbackNameOffset = 0;
- if (atom.fallback())
- ivar.fallbackNameOffset = getNameOffset(*atom.fallback());
- _undefinedAtomIvars.push_back(ivar);
- }
-
- void addIVarsForSharedLibraryAtom(const SharedLibraryAtom& atom) {
- _sharedLibraryAtomIndex[&atom] = _sharedLibraryAtomIvars.size();
- NativeSharedLibraryAtomIvarsV1 ivar;
- ivar.size = atom.size();
- ivar.nameOffset = getNameOffset(atom);
- ivar.loadNameOffset = getSharedLibraryNameOffset(atom.loadName());
- ivar.type = (uint32_t)atom.type();
- ivar.flags = atom.canBeNullAtRuntime();
- _sharedLibraryAtomIvars.push_back(ivar);
- }
-
- void addIVarsForAbsoluteAtom(const AbsoluteAtom& atom) {
- _absoluteAtomIndex[&atom] = _absoluteAtomIvars.size();
- NativeAbsoluteAtomIvarsV1 ivar;
- ivar.nameOffset = getNameOffset(atom);
- ivar.attributesOffset = getAttributeOffset(atom);
- ivar.reserved = 0;
- ivar.value = atom.value();
- _absoluteAtomIvars.push_back(ivar);
- }
-
- void convertReferencesToV1() {
- for (const NativeReferenceIvarsV2 &v2 : _referencesV2) {
- NativeReferenceIvarsV1 v1;
- v1.offsetInAtom = v2.offsetInAtom;
- v1.kindNamespace = v2.kindNamespace;
- v1.kindArch = v2.kindArch;
- v1.kindValue = v2.kindValue;
- v1.targetIndex = (v2.targetIndex == NativeReferenceIvarsV2::noTarget) ?
- (uint16_t)NativeReferenceIvarsV1::noTarget : v2.targetIndex;
- v1.addendIndex = this->getAddendIndex(v2.addend);
- _referencesV1.push_back(v1);
- }
- _referencesV2.clear();
- }
-
- bool canConvertReferenceToV1(const NativeReferenceIvarsV2 &ref) {
- bool validOffset = (ref.offsetInAtom == NativeReferenceIvarsV2::noTarget) ||
- ref.offsetInAtom < NativeReferenceIvarsV1::noTarget;
- return validOffset && ref.targetIndex < UINT16_MAX;
- }
-
- // Convert vector of NativeReferenceIvarsV2 to NativeReferenceIvarsV1 if
- // possible.
- void maybeConvertReferencesToV1() {
- std::set<int64_t> addends;
- for (const NativeReferenceIvarsV2 &ref : _referencesV2) {
- if (!canConvertReferenceToV1(ref))
- return;
- addends.insert(ref.addend);
- if (addends.size() >= UINT16_MAX)
- return;
- }
- convertReferencesToV1();
- }
-
- // fill out native file header and chunk directory
- void makeHeader() {
- const bool hasDefines = !_definedAtomIvars.empty();
- const bool hasUndefines = !_undefinedAtomIvars.empty();
- const bool hasSharedLibraries = !_sharedLibraryAtomIvars.empty();
- const bool hasAbsolutes = !_absoluteAtomIvars.empty();
- const bool hasReferencesV1 = !_referencesV1.empty();
- const bool hasReferencesV2 = !_referencesV2.empty();
- const bool hasTargetsTable = !_targetsTableIndex.empty();
- const bool hasAddendTable = !_addendsTableIndex.empty();
- const bool hasContent = !_contentPool.empty();
-
- int chunkCount = 1; // always have string pool chunk
- if ( hasDefines ) chunkCount += 2;
- if ( hasUndefines ) ++chunkCount;
- if ( hasSharedLibraries ) ++chunkCount;
- if ( hasAbsolutes ) chunkCount += 2;
- if ( hasReferencesV1 ) ++chunkCount;
- if ( hasReferencesV2 ) ++chunkCount;
- if ( hasTargetsTable ) ++chunkCount;
- if ( hasAddendTable ) ++chunkCount;
- if ( hasContent ) ++chunkCount;
-
- _headerBufferSize = sizeof(NativeFileHeader)
- + chunkCount*sizeof(NativeChunk);
- _headerBuffer = reinterpret_cast<NativeFileHeader*>
- (operator new(_headerBufferSize, std::nothrow));
- NativeChunk *chunks =
- reinterpret_cast<NativeChunk*>(reinterpret_cast<char*>(_headerBuffer)
- + sizeof(NativeFileHeader));
- memcpy(_headerBuffer->magic, NATIVE_FILE_HEADER_MAGIC,
- sizeof(_headerBuffer->magic));
- _headerBuffer->endian = NFH_LittleEndian;
- _headerBuffer->architecture = 0;
- _headerBuffer->fileSize = 0;
- _headerBuffer->chunkCount = chunkCount;
-
- // create chunk for defined atom ivar array
- int nextIndex = 0;
- uint32_t nextFileOffset = _headerBufferSize;
- if (hasDefines) {
- fillChunkHeader(chunks[nextIndex++], nextFileOffset, _definedAtomIvars,
- NCS_DefinedAtomsV1);
-
- // create chunk for attributes
- fillChunkHeader(chunks[nextIndex++], nextFileOffset, _attributes,
- NCS_AttributesArrayV1);
- }
-
- // create chunk for undefined atom array
- if (hasUndefines)
- fillChunkHeader(chunks[nextIndex++], nextFileOffset, _undefinedAtomIvars,
- NCS_UndefinedAtomsV1);
-
- // create chunk for shared library atom array
- if (hasSharedLibraries)
- fillChunkHeader(chunks[nextIndex++], nextFileOffset,
- _sharedLibraryAtomIvars, NCS_SharedLibraryAtomsV1);
-
- // create chunk for shared library atom array
- if (hasAbsolutes) {
- fillChunkHeader(chunks[nextIndex++], nextFileOffset, _absoluteAtomIvars,
- NCS_AbsoluteAtomsV1);
-
- // create chunk for attributes
- fillChunkHeader(chunks[nextIndex++], nextFileOffset, _absAttributes,
- NCS_AbsoluteAttributesV1);
- }
-
- // create chunk for symbol strings
- // pad end of string pool to 4-bytes
- while ((_stringPool.size() % 4) != 0)
- _stringPool.push_back('\0');
- fillChunkHeader(chunks[nextIndex++], nextFileOffset, _stringPool,
- NCS_Strings);
-
- // create chunk for referencesV2
- if (hasReferencesV1)
- fillChunkHeader(chunks[nextIndex++], nextFileOffset, _referencesV1,
- NCS_ReferencesArrayV1);
-
- // create chunk for referencesV2
- if (hasReferencesV2)
- fillChunkHeader(chunks[nextIndex++], nextFileOffset, _referencesV2,
- NCS_ReferencesArrayV2);
-
- // create chunk for target table
- if (hasTargetsTable) {
- NativeChunk& cht = chunks[nextIndex++];
- cht.signature = NCS_TargetsTable;
- cht.fileOffset = nextFileOffset;
- cht.fileSize = _targetsTableIndex.size() * sizeof(uint32_t);
- cht.elementCount = _targetsTableIndex.size();
- nextFileOffset = cht.fileOffset + cht.fileSize;
- }
-
- // create chunk for addend table
- if (hasAddendTable) {
- NativeChunk& chad = chunks[nextIndex++];
- chad.signature = NCS_AddendsTable;
- chad.fileOffset = nextFileOffset;
- chad.fileSize = _addendsTableIndex.size() * sizeof(Reference::Addend);
- chad.elementCount = _addendsTableIndex.size();
- nextFileOffset = chad.fileOffset + chad.fileSize;
- }
-
- // create chunk for content
- if (hasContent)
- fillChunkHeader(chunks[nextIndex++], nextFileOffset, _contentPool,
- NCS_Content);
-
- _headerBuffer->fileSize = nextFileOffset;
- }
-
- template<class T>
- void fillChunkHeader(NativeChunk &chunk, uint32_t &nextFileOffset,
- const std::vector<T> &data, uint32_t signature) {
- chunk.signature = signature;
- chunk.fileOffset = nextFileOffset;
- chunk.fileSize = data.size() * sizeof(T);
- chunk.elementCount = data.size();
- nextFileOffset = chunk.fileOffset + chunk.fileSize;
- }
-
- // scan header to find particular chunk
- NativeChunk& findChunk(uint32_t signature) {
- const uint32_t chunkCount = _headerBuffer->chunkCount;
- NativeChunk* chunks =
- reinterpret_cast<NativeChunk*>(reinterpret_cast<char*>(_headerBuffer)
- + sizeof(NativeFileHeader));
- for (uint32_t i=0; i < chunkCount; ++i) {
- if ( chunks[i].signature == signature )
- return chunks[i];
- }
- llvm_unreachable("findChunk() signature not found");
- }
-
- // append atom name to string pool and return offset
- uint32_t getNameOffset(const Atom& atom) {
- return this->getNameOffset(atom.name());
- }
-
- // check if name is already in pool or append and return offset
- uint32_t getSharedLibraryNameOffset(StringRef name) {
- assert(!name.empty());
- // look to see if this library name was used by another atom
- for (auto &it : _sharedLibraryNames)
- if (name.equals(it.first))
- return it.second;
- // first use of this library name
- uint32_t result = this->getNameOffset(name);
- _sharedLibraryNames.push_back(std::make_pair(name, result));
- return result;
- }
-
- // append atom name to string pool and return offset
- uint32_t getNameOffset(StringRef name) {
- if ( name.empty() )
- return 0;
- uint32_t result = _stringPool.size();
- _stringPool.insert(_stringPool.end(), name.begin(), name.end());
- _stringPool.push_back(0);
- return result;
- }
-
- // append atom cotent to content pool and return offset
- uint32_t getContentOffset(const DefinedAtom& atom) {
- if (!atom.occupiesDiskSpace())
- return 0;
- uint32_t result = _contentPool.size();
- ArrayRef<uint8_t> cont = atom.rawContent();
- _contentPool.insert(_contentPool.end(), cont.begin(), cont.end());
- return result;
- }
-
- // reuse existing attributes entry or create a new one and return offet
- uint32_t getAttributeOffset(const DefinedAtom& atom) {
- NativeAtomAttributesV1 attrs = computeAttributesV1(atom);
- return getOrPushAttribute(_attributes, attrs);
- }
-
- uint32_t getAttributeOffset(const AbsoluteAtom& atom) {
- NativeAtomAttributesV1 attrs = computeAbsoluteAttributes(atom);
- return getOrPushAttribute(_absAttributes, attrs);
- }
-
- uint32_t getOrPushAttribute(std::vector<NativeAtomAttributesV1> &dest,
- const NativeAtomAttributesV1 &attrs) {
- for (size_t i = 0, e = dest.size(); i < e; ++i) {
- if (!memcmp(&dest[i], &attrs, sizeof(attrs))) {
- // found that this set of attributes already used, so re-use
- return i * sizeof(attrs);
- }
- }
- // append new attribute set to end
- uint32_t result = dest.size() * sizeof(attrs);
- dest.push_back(attrs);
- return result;
- }
-
- uint32_t sectionNameOffset(const DefinedAtom& atom) {
- // if section based on content, then no custom section name available
- if (atom.sectionChoice() == DefinedAtom::sectionBasedOnContent)
- return 0;
- StringRef name = atom.customSectionName();
- assert(!name.empty());
- // look to see if this section name was used by another atom
- for (auto &it : _sectionNames)
- if (name.equals(it.first))
- return it.second;
- // first use of this section name
- uint32_t result = this->getNameOffset(name);
- _sectionNames.push_back(std::make_pair(name, result));
- return result;
- }
-
- NativeAtomAttributesV1 computeAttributesV1(const DefinedAtom& atom) {
- NativeAtomAttributesV1 attrs;
- attrs.sectionNameOffset = sectionNameOffset(atom);
- attrs.align2 = atom.alignment().powerOf2;
- attrs.alignModulus = atom.alignment().modulus;
- attrs.scope = atom.scope();
- attrs.interposable = atom.interposable();
- attrs.merge = atom.merge();
- attrs.contentType = atom.contentType();
- attrs.sectionChoice = atom.sectionChoice();
- attrs.deadStrip = atom.deadStrip();
- attrs.dynamicExport = atom.dynamicExport();
- attrs.codeModel = atom.codeModel();
- attrs.permissions = atom.permissions();
- return attrs;
- }
-
- NativeAtomAttributesV1 computeAbsoluteAttributes(const AbsoluteAtom& atom) {
- NativeAtomAttributesV1 attrs;
- attrs.scope = atom.scope();
- return attrs;
- }
-
- // add references for this atom in a contiguous block in NCS_ReferencesArrayV2
- uint32_t getReferencesIndex(const DefinedAtom& atom, unsigned& refsCount) {
- size_t startRefSize = _referencesV2.size();
- uint32_t result = startRefSize;
- for (const Reference *ref : atom) {
- NativeReferenceIvarsV2 nref;
- nref.offsetInAtom = ref->offsetInAtom();
- nref.kindNamespace = (uint8_t)ref->kindNamespace();
- nref.kindArch = (uint8_t)ref->kindArch();
- nref.kindValue = ref->kindValue();
- nref.targetIndex = this->getTargetIndex(ref->target());
- nref.addend = ref->addend();
- nref.tag = ref->tag();
- _referencesV2.push_back(nref);
- }
- refsCount = _referencesV2.size() - startRefSize;
- return (refsCount == 0) ? 0 : result;
- }
-
- uint32_t getTargetIndex(const Atom* target) {
- if ( target == nullptr )
- return NativeReferenceIvarsV2::noTarget;
- TargetToIndex::const_iterator pos = _targetsTableIndex.find(target);
- if ( pos != _targetsTableIndex.end() ) {
- return pos->second;
- }
- uint32_t result = _targetsTableIndex.size();
- _targetsTableIndex[target] = result;
- return result;
- }
-
- void writeTargetTable(raw_ostream &out) {
- // Build table of target indexes
- uint32_t maxTargetIndex = _targetsTableIndex.size();
- assert(maxTargetIndex > 0);
- std::vector<uint32_t> targetIndexes(maxTargetIndex);
- for (auto &it : _targetsTableIndex) {
- const Atom* atom = it.first;
- uint32_t targetIndex = it.second;
- assert(targetIndex < maxTargetIndex);
-
- TargetToIndex::iterator pos = _definedAtomIndex.find(atom);
- if (pos != _definedAtomIndex.end()) {
- targetIndexes[targetIndex] = pos->second;
- continue;
- }
- uint32_t base = _definedAtomIvars.size();
-
- pos = _undefinedAtomIndex.find(atom);
- if (pos != _undefinedAtomIndex.end()) {
- targetIndexes[targetIndex] = pos->second + base;
- continue;
- }
- base += _undefinedAtomIndex.size();
-
- pos = _sharedLibraryAtomIndex.find(atom);
- if (pos != _sharedLibraryAtomIndex.end()) {
- targetIndexes[targetIndex] = pos->second + base;
- continue;
- }
- base += _sharedLibraryAtomIndex.size();
-
- pos = _absoluteAtomIndex.find(atom);
- assert(pos != _absoluteAtomIndex.end());
- targetIndexes[targetIndex] = pos->second + base;
- }
- // write table
- out.write((char*)&targetIndexes[0], maxTargetIndex * sizeof(uint32_t));
- }
-
- uint32_t getAddendIndex(Reference::Addend addend) {
- if ( addend == 0 )
- return 0; // addend index zero is used to mean "no addend"
- AddendToIndex::const_iterator pos = _addendsTableIndex.find(addend);
- if ( pos != _addendsTableIndex.end() ) {
- return pos->second;
- }
- uint32_t result = _addendsTableIndex.size() + 1; // one-based index
- _addendsTableIndex[addend] = result;
- return result;
- }
-
- void writeAddendTable(raw_ostream &out) {
- // Build table of addends
- uint32_t maxAddendIndex = _addendsTableIndex.size();
- std::vector<Reference::Addend> addends(maxAddendIndex);
- for (auto &it : _addendsTableIndex) {
- Reference::Addend addend = it.first;
- uint32_t index = it.second;
- assert(index <= maxAddendIndex);
- addends[index-1] = addend;
- }
- // write table
- out.write((char*)&addends[0], maxAddendIndex*sizeof(Reference::Addend));
- }
-
- typedef std::vector<std::pair<StringRef, uint32_t>> NameToOffsetVector;
-
- typedef llvm::DenseMap<const Atom*, uint32_t> TargetToIndex;
- typedef llvm::DenseMap<Reference::Addend, uint32_t> AddendToIndex;
-
- NativeFileHeader* _headerBuffer;
- size_t _headerBufferSize;
- std::vector<char> _stringPool;
- std::vector<uint8_t> _contentPool;
- std::vector<NativeDefinedAtomIvarsV1> _definedAtomIvars;
- std::vector<NativeAtomAttributesV1> _attributes;
- std::vector<NativeAtomAttributesV1> _absAttributes;
- std::vector<NativeUndefinedAtomIvarsV1> _undefinedAtomIvars;
- std::vector<NativeSharedLibraryAtomIvarsV1> _sharedLibraryAtomIvars;
- std::vector<NativeAbsoluteAtomIvarsV1> _absoluteAtomIvars;
- std::vector<NativeReferenceIvarsV1> _referencesV1;
- std::vector<NativeReferenceIvarsV2> _referencesV2;
- TargetToIndex _targetsTableIndex;
- TargetToIndex _definedAtomIndex;
- TargetToIndex _undefinedAtomIndex;
- TargetToIndex _sharedLibraryAtomIndex;
- TargetToIndex _absoluteAtomIndex;
- AddendToIndex _addendsTableIndex;
- NameToOffsetVector _sectionNames;
- NameToOffsetVector _sharedLibraryNames;
-};
-} // end namespace native
-
-std::unique_ptr<Writer> createWriterNative() {
- return std::unique_ptr<Writer>(new native::Writer());
-}
-} // end namespace lld
diff --git a/lib/ReaderWriter/PECOFF/Atoms.h b/lib/ReaderWriter/PECOFF/Atoms.h
deleted file mode 100644
index 257edc17884b..000000000000
--- a/lib/ReaderWriter/PECOFF/Atoms.h
+++ /dev/null
@@ -1,312 +0,0 @@
-//===- lib/ReaderWriter/PECOFF/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_PE_COFF_ATOMS_H
-#define LLD_READER_WRITER_PE_COFF_ATOMS_H
-
-#include "lld/Core/File.h"
-#include "lld/Core/Simple.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/Object/COFF.h"
-#include <vector>
-
-namespace lld {
-namespace pecoff {
-class COFFDefinedAtom;
-
-class COFFUndefinedAtom : public UndefinedAtom {
-public:
- COFFUndefinedAtom(const File &file, StringRef name,
- const UndefinedAtom *fallback = nullptr)
- : _owningFile(file), _name(name), _fallback(fallback) {}
-
- const File &file() const override { return _owningFile; }
- StringRef name() const override { return _name; }
- CanBeNull canBeNull() const override { return CanBeNull::canBeNullNever; }
- const UndefinedAtom *fallback() const override { return _fallback; }
-
-private:
- const File &_owningFile;
- StringRef _name;
- const UndefinedAtom *_fallback;
-};
-
-/// The base class of all COFF defined atoms. A derived class of
-/// COFFBaseDefinedAtom may represent atoms read from a file or atoms created
-/// by the linker. An example of the latter case is the jump table for symbols
-/// in a DLL.
-class COFFBaseDefinedAtom : public DefinedAtom {
-public:
- enum class Kind {
- File,
- Internal
- };
-
- const File &file() const override { return _file; }
- StringRef name() const override { return _name; }
- Interposable interposable() const override { return interposeNo; }
- Merge merge() const override { return mergeNo; }
- Alignment alignment() const override { return Alignment(0); }
- StringRef customSectionName() const override { return ""; }
- DeadStripKind deadStrip() const override { return deadStripNormal; }
-
- Kind getKind() const { return _kind; }
-
- void addReference(std::unique_ptr<SimpleReference> reference) {
- _references.push_back(std::move(reference));
- }
-
- reference_iterator begin() const override {
- return reference_iterator(*this, reinterpret_cast<const void *>(0));
- }
-
- reference_iterator end() const override {
- return reference_iterator(
- *this, reinterpret_cast<const void *>(_references.size()));
- }
-
-protected:
- COFFBaseDefinedAtom(const File &file, StringRef name, Kind kind)
- : _file(file), _name(name), _kind(kind) {}
-
-private:
- const Reference *derefIterator(const void *iter) const override {
- size_t index = reinterpret_cast<size_t>(iter);
- return _references[index].get();
- }
-
- void incrementIterator(const void *&iter) const override {
- size_t index = reinterpret_cast<size_t>(iter);
- iter = reinterpret_cast<const void *>(index + 1);
- }
-
- const File &_file;
- StringRef _name;
- Kind _kind;
- std::vector<std::unique_ptr<SimpleReference>> _references;
-};
-
-/// This is the root class of the atom read from a file. This class have two
-/// subclasses; one for the regular atom and another for the BSS atom.
-class COFFDefinedFileAtom : public COFFBaseDefinedAtom {
-public:
- COFFDefinedFileAtom(const File &file, StringRef name, StringRef sectionName,
- uint64_t sectionSize, Scope scope,
- ContentType contentType, ContentPermissions perms,
- uint64_t ordinal)
- : COFFBaseDefinedAtom(file, name, Kind::File), _sectionName(sectionName),
- _sectionSize(sectionSize), _scope(scope), _contentType(contentType),
- _permissions(perms), _ordinal(ordinal), _alignment(0) {}
-
- static bool classof(const COFFBaseDefinedAtom *atom) {
- return atom->getKind() == Kind::File;
- }
-
- void setAlignment(Alignment val) { _alignment = val; }
- SectionChoice sectionChoice() const override { return sectionCustomRequired; }
- StringRef customSectionName() const override { return _sectionName; }
- uint64_t sectionSize() const override { return _sectionSize; }
- Scope scope() const override { return _scope; }
- ContentType contentType() const override { return _contentType; }
- ContentPermissions permissions() const override { return _permissions; }
- uint64_t ordinal() const override { return _ordinal; }
- Alignment alignment() const override { return _alignment; }
-
- void addAssociate(const DefinedAtom *other) {
- auto *ref = new SimpleReference(Reference::KindNamespace::all,
- Reference::KindArch::all,
- lld::Reference::kindAssociate, 0, other, 0);
- addReference(std::unique_ptr<SimpleReference>(ref));
- }
-
-private:
- StringRef _sectionName;
- uint64_t _sectionSize;
- Scope _scope;
- ContentType _contentType;
- ContentPermissions _permissions;
- uint64_t _ordinal;
- Alignment _alignment;
- std::vector<std::unique_ptr<SimpleReference>> _references;
-};
-
-// A COFFDefinedAtom represents an atom read from a file and has contents.
-class COFFDefinedAtom : public COFFDefinedFileAtom {
-public:
- COFFDefinedAtom(const File &file, StringRef name, StringRef sectionName,
- uint64_t sectionSize, Scope scope, ContentType type,
- bool isComdat, ContentPermissions perms, Merge merge,
- ArrayRef<uint8_t> data, uint64_t ordinal)
- : COFFDefinedFileAtom(file, name, sectionName, sectionSize,
- scope, type, perms, ordinal),
- _isComdat(isComdat), _merge(merge), _dataref(data) {}
-
- Merge merge() const override { return _merge; }
- uint64_t size() const override { return _dataref.size(); }
- ArrayRef<uint8_t> rawContent() const override { return _dataref; }
-
- DeadStripKind deadStrip() const override {
- // Only COMDAT symbols would be dead-stripped.
- return _isComdat ? deadStripNormal : deadStripNever;
- }
-
-private:
- bool _isComdat;
- Merge _merge;
- ArrayRef<uint8_t> _dataref;
-};
-
-// A COFFDefinedAtom represents an atom for BSS section.
-class COFFBSSAtom : public COFFDefinedFileAtom {
-public:
- COFFBSSAtom(const File &file, StringRef name, Scope scope,
- ContentPermissions perms, Merge merge, uint32_t size,
- uint64_t ordinal)
- : COFFDefinedFileAtom(file, name, ".bss", 0, scope, typeZeroFill,
- perms, ordinal),
- _merge(merge), _size(size) {}
-
- Merge merge() const override { return _merge; }
- uint64_t size() const override { return _size; }
- ArrayRef<uint8_t> rawContent() const override { return _contents; }
-
-private:
- Merge _merge;
- uint32_t _size;
- std::vector<uint8_t> _contents;
-};
-
-/// A COFFLinkerInternalAtom represents a defined atom created by the linker,
-/// not read from file.
-class COFFLinkerInternalAtom : public COFFBaseDefinedAtom {
-public:
- SectionChoice sectionChoice() const override { return sectionBasedOnContent; }
- uint64_t ordinal() const override { return _ordinal; }
- Scope scope() const override { return scopeGlobal; }
- Alignment alignment() const override { return Alignment(0); }
- uint64_t size() const override { return _data.size(); }
- ArrayRef<uint8_t> rawContent() const override { return _data; }
-
-protected:
- COFFLinkerInternalAtom(const File &file, uint64_t ordinal,
- std::vector<uint8_t> data, StringRef symbolName = "")
- : COFFBaseDefinedAtom(file, symbolName, Kind::Internal),
- _ordinal(ordinal), _data(std::move(data)) {}
-
-private:
- uint64_t _ordinal;
- std::vector<uint8_t> _data;
-};
-
-class COFFStringAtom : public COFFLinkerInternalAtom {
-public:
- COFFStringAtom(const File &file, uint64_t ordinal, StringRef sectionName,
- StringRef contents)
- : COFFLinkerInternalAtom(file, ordinal, stringRefToVector(contents)),
- _sectionName(sectionName) {}
-
- SectionChoice sectionChoice() const override { return sectionCustomRequired; }
- StringRef customSectionName() const override { return _sectionName; }
- ContentType contentType() const override { return typeData; }
- ContentPermissions permissions() const override { return permR__; }
-
-private:
- StringRef _sectionName;
-
- std::vector<uint8_t> stringRefToVector(StringRef name) const {
- std::vector<uint8_t> ret(name.size() + 1);
- memcpy(&ret[0], name.data(), name.size());
- ret[name.size()] = 0;
- return ret;
- }
-};
-
-// A COFFSharedLibraryAtom represents a symbol for data in an import library. A
-// reference to a COFFSharedLibraryAtom will be transformed to a real reference
-// to an import address table entry in Idata pass.
-class COFFSharedLibraryAtom : public SharedLibraryAtom {
-public:
- COFFSharedLibraryAtom(const File &file, uint16_t hint, StringRef symbolName,
- StringRef importName, StringRef dllName)
- : _file(file), _hint(hint), _mangledName(addImpPrefix(symbolName)),
- _importName(importName), _dllName(dllName), _importTableEntry(nullptr) {
- }
-
- const File &file() const override { return _file; }
- uint16_t hint() const { return _hint; }
-
- /// Returns the symbol name to be used by the core linker.
- StringRef name() const override { return _mangledName; }
-
- /// Returns the symbol name to be used in the import description table in the
- /// COFF header.
- virtual StringRef importName() const { return _importName; }
-
- StringRef loadName() const override { return _dllName; }
- bool canBeNullAtRuntime() const override { return false; }
- Type type() const override { return Type::Unknown; }
- uint64_t size() const override { return 0; }
-
- void setImportTableEntry(const DefinedAtom *atom) {
- _importTableEntry = atom;
- }
-
- const DefinedAtom *getImportTableEntry() const { return _importTableEntry; }
-
-private:
- /// Mangle the symbol name by adding "__imp_" prefix. See the file comment of
- /// ReaderImportHeader.cpp for details about the prefix.
- std::string addImpPrefix(StringRef symbolName) {
- std::string ret("__imp_");
- ret.append(symbolName);
- return ret;
- }
-
- const File &_file;
- uint16_t _hint;
- std::string _mangledName;
- std::string _importName;
- StringRef _dllName;
- const DefinedAtom *_importTableEntry;
-};
-
-// An instance of this class represents "input file" for atoms created in a
-// pass. Atoms need to be associated to an input file even if it's not read from
-// a file, so we use this class for that.
-class VirtualFile : public SimpleFile {
-public:
- VirtualFile(const LinkingContext &ctx)
- : SimpleFile("<virtual-file>"), _nextOrdinal(0) {
- setOrdinal(ctx.getNextOrdinalAndIncrement());
- }
-
- uint64_t getNextOrdinal() { return _nextOrdinal++; }
-
-private:
- uint64_t _nextOrdinal;
-};
-
-//===----------------------------------------------------------------------===//
-//
-// Utility functions to handle layout edges.
-//
-//===----------------------------------------------------------------------===//
-
-template <typename T, typename U>
-void addLayoutEdge(T *a, U *b, uint32_t which) {
- auto ref = new SimpleReference(Reference::KindNamespace::all,
- Reference::KindArch::all,
- which, 0, b, 0);
- a->addReference(std::unique_ptr<SimpleReference>(ref));
-}
-
-} // namespace pecoff
-} // namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/PECOFF/CMakeLists.txt b/lib/ReaderWriter/PECOFF/CMakeLists.txt
deleted file mode 100644
index 86b49b79f194..000000000000
--- a/lib/ReaderWriter/PECOFF/CMakeLists.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-add_llvm_library(lldPECOFF
- EdataPass.cpp
- IdataPass.cpp
- LinkerGeneratedSymbolFile.cpp
- LoadConfigPass.cpp
- PECOFFLinkingContext.cpp
- Pass.cpp
- ReaderCOFF.cpp
- ReaderImportHeader.cpp
- WriterImportLibrary.cpp
- WriterPECOFF.cpp
- LINK_LIBS
- lldCore
- LLVMObject
- LLVMSupport
- )
diff --git a/lib/ReaderWriter/PECOFF/EdataPass.cpp b/lib/ReaderWriter/PECOFF/EdataPass.cpp
deleted file mode 100644
index ad79f171f3c9..000000000000
--- a/lib/ReaderWriter/PECOFF/EdataPass.cpp
+++ /dev/null
@@ -1,227 +0,0 @@
-//===- lib/ReaderWriter/PECOFF/EdataPass.cpp ------------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "Pass.h"
-#include "EdataPass.h"
-#include "lld/Core/File.h"
-#include "lld/Core/Pass.h"
-#include "lld/Core/Simple.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/Path.h"
-#include <climits>
-#include <ctime>
-#include <utility>
-
-using lld::pecoff::edata::EdataAtom;
-using lld::pecoff::edata::TableEntry;
-using llvm::object::export_address_table_entry;
-using llvm::object::export_directory_table_entry;
-
-namespace lld {
-namespace pecoff {
-
-typedef PECOFFLinkingContext::ExportDesc ExportDesc;
-
-// dedupExports removes duplicate export entries. If two exports are
-// referring the same symbol, they are considered duplicates.
-// This could happen if the same symbol name is specified as an argument
-// to /export more than once, or an unmangled and mangled name of the
-// same symbol are given to /export. In the latter case, we choose
-// unmangled (shorter) name.
-static void dedupExports(PECOFFLinkingContext &ctx) {
- std::vector<ExportDesc> &exports = ctx.getDllExports();
- // Pass 1: find duplicate entries
- std::set<const ExportDesc *> dup;
- std::map<StringRef, ExportDesc *> map;
- for (ExportDesc &exp : exports) {
- if (!exp.externalName.empty())
- continue;
- StringRef symbol = exp.getRealName();
- auto it = map.find(symbol);
- if (it == map.end()) {
- map[symbol] = &exp;
- } else if (symbol.size() < it->second->getRealName().size()) {
- map[symbol] = &exp;
- dup.insert(it->second);
- } else {
- dup.insert(&exp);
- }
- }
- // Pass 2: remove duplicate entries
- auto pred = [&](const ExportDesc &exp) {
- return dup.count(&exp) == 1;
- };
- exports.erase(std::remove_if(exports.begin(), exports.end(), pred),
- exports.end());
-}
-
-static void assignOrdinals(PECOFFLinkingContext &ctx) {
- std::vector<ExportDesc> &exports = ctx.getDllExports();
- int maxOrdinal = -1;
- for (ExportDesc &desc : exports)
- maxOrdinal = std::max(maxOrdinal, desc.ordinal);
-
- std::sort(exports.begin(), exports.end(),
- [](const ExportDesc &a, const ExportDesc &b) {
- return a.getExternalName().compare(b.getExternalName()) < 0;
- });
-
- int nextOrdinal = (maxOrdinal == -1) ? 1 : (maxOrdinal + 1);
- for (ExportDesc &desc : exports)
- if (desc.ordinal == -1)
- desc.ordinal = nextOrdinal++;
-}
-
-static bool getExportedAtoms(PECOFFLinkingContext &ctx, MutableFile *file,
- std::vector<TableEntry> &ret) {
- std::map<StringRef, const DefinedAtom *> definedAtoms;
- for (const DefinedAtom *atom : file->defined())
- definedAtoms[atom->name()] = atom;
-
- for (PECOFFLinkingContext::ExportDesc &desc : ctx.getDllExports()) {
- auto it = definedAtoms.find(desc.getRealName());
- if (it == definedAtoms.end()) {
- llvm::errs() << "Symbol <" << desc.name
- << "> is exported but not defined.\n";
- return false;
- }
- const DefinedAtom *atom = it->second;
-
- // One can export a symbol with a different name than the symbol
- // name used in DLL. If such name is specified, use it in the
- // .edata section.
- ret.push_back(TableEntry(ctx.undecorateSymbol(desc.getExternalName()),
- desc.ordinal, atom, desc.noname));
- }
- std::sort(ret.begin(), ret.end(),
- [](const TableEntry &a, const TableEntry &b) {
- return a.exportName.compare(b.exportName) < 0;
- });
-
- return true;
-}
-
-static std::pair<int, int> getOrdinalBase(std::vector<TableEntry> &entries) {
- int ordinalBase = INT_MAX;
- int maxOrdinal = -1;
- for (TableEntry &e : entries) {
- ordinalBase = std::min(ordinalBase, e.ordinal);
- maxOrdinal = std::max(maxOrdinal, e.ordinal);
- }
- return std::pair<int, int>(ordinalBase, maxOrdinal);
-}
-
-edata::EdataAtom *
-EdataPass::createAddressTable(const std::vector<TableEntry> &entries,
- int ordinalBase, int maxOrdinal) {
- EdataAtom *addressTable =
- new (_alloc) EdataAtom(_file, sizeof(export_address_table_entry) *
- (maxOrdinal - ordinalBase + 1));
-
- for (const TableEntry &e : entries) {
- int index = e.ordinal - ordinalBase;
- size_t offset = index * sizeof(export_address_table_entry);
- addDir32NBReloc(addressTable, e.atom, _ctx.getMachineType(), offset);
- }
- return addressTable;
-}
-
-edata::EdataAtom *
-EdataPass::createNamePointerTable(const PECOFFLinkingContext &ctx,
- const std::vector<TableEntry> &entries,
- MutableFile *file) {
- EdataAtom *table =
- new (_alloc) EdataAtom(_file, sizeof(uint32_t) * entries.size());
-
- size_t offset = 0;
- for (const TableEntry &e : entries) {
- auto *stringAtom = new (_alloc) COFFStringAtom(
- _file, _stringOrdinal++, ".edata", e.exportName);
- file->addAtom(*stringAtom);
- addDir32NBReloc(table, stringAtom, _ctx.getMachineType(), offset);
- offset += sizeof(uint32_t);
- }
- return table;
-}
-
-edata::EdataAtom *EdataPass::createExportDirectoryTable(
- const std::vector<edata::TableEntry> &namedEntries, int ordinalBase,
- int maxOrdinal) {
- EdataAtom *ret =
- new (_alloc) EdataAtom(_file, sizeof(export_directory_table_entry));
- auto *data = ret->getContents<export_directory_table_entry>();
- data->TimeDateStamp = time(nullptr);
- data->OrdinalBase = ordinalBase;
- data->AddressTableEntries = maxOrdinal - ordinalBase + 1;
- data->NumberOfNamePointers = namedEntries.size();
- return ret;
-}
-
-edata::EdataAtom *
-EdataPass::createOrdinalTable(const std::vector<TableEntry> &entries,
- int ordinalBase) {
- EdataAtom *ret =
- new (_alloc) EdataAtom(_file, sizeof(uint16_t) * entries.size());
- uint16_t *data = ret->getContents<uint16_t>();
- int i = 0;
- for (const TableEntry &e : entries)
- data[i++] = e.ordinal - ordinalBase;
- return ret;
-}
-
-void EdataPass::perform(std::unique_ptr<MutableFile> &file) {
- dedupExports(_ctx);
- assignOrdinals(_ctx);
-
- std::vector<TableEntry> entries;
- if (!getExportedAtoms(_ctx, file.get(), entries))
- return;
- if (entries.empty())
- return;
-
- int ordinalBase, maxOrdinal;
- std::tie(ordinalBase, maxOrdinal) = getOrdinalBase(entries);
-
- std::vector<TableEntry> namedEntries;
- for (TableEntry &e : entries)
- if (!e.noname)
- namedEntries.push_back(e);
-
- EdataAtom *table =
- createExportDirectoryTable(namedEntries, ordinalBase, maxOrdinal);
- file->addAtom(*table);
-
- COFFStringAtom *dllName =
- new (_alloc) COFFStringAtom(_file, _stringOrdinal++, ".edata",
- llvm::sys::path::filename(_ctx.outputPath()));
- file->addAtom(*dllName);
- addDir32NBReloc(table, dllName, _ctx.getMachineType(),
- offsetof(export_directory_table_entry, NameRVA));
-
- EdataAtom *addressTable =
- createAddressTable(entries, ordinalBase, maxOrdinal);
- file->addAtom(*addressTable);
- addDir32NBReloc(
- table, addressTable, _ctx.getMachineType(),
- offsetof(export_directory_table_entry, ExportAddressTableRVA));
-
- EdataAtom *namePointerTable =
- createNamePointerTable(_ctx, namedEntries, file.get());
- file->addAtom(*namePointerTable);
- addDir32NBReloc(table, namePointerTable, _ctx.getMachineType(),
- offsetof(export_directory_table_entry, NamePointerRVA));
-
- EdataAtom *ordinalTable = createOrdinalTable(namedEntries, ordinalBase);
- file->addAtom(*ordinalTable);
- addDir32NBReloc(table, ordinalTable, _ctx.getMachineType(),
- offsetof(export_directory_table_entry, OrdinalTableRVA));
-}
-
-} // namespace pecoff
-} // namespace lld
diff --git a/lib/ReaderWriter/PECOFF/EdataPass.h b/lib/ReaderWriter/PECOFF/EdataPass.h
deleted file mode 100644
index 442be3ca24aa..000000000000
--- a/lib/ReaderWriter/PECOFF/EdataPass.h
+++ /dev/null
@@ -1,99 +0,0 @@
-//===- lib/ReaderWriter/PECOFF/EdataPass.h --------------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file \brief This linker pass creates atoms for the DLL export
-/// information. The defined atoms constructed in this pass will go into .edata
-/// section.
-///
-/// For the details of the .edata section format, see Microsoft PE/COFF
-/// Specification section 5.3, The .edata Section.
-///
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_PE_COFF_EDATA_PASS_H
-#define LLD_READER_WRITER_PE_COFF_EDATA_PASS_H
-
-#include "Atoms.h"
-#include "lld/Core/File.h"
-#include "lld/Core/Pass.h"
-#include "lld/Core/Simple.h"
-#include "lld/ReaderWriter/PECOFFLinkingContext.h"
-#include "llvm/Support/COFF.h"
-#include <map>
-
-using llvm::COFF::ImportDirectoryTableEntry;
-
-namespace lld {
-namespace pecoff {
-namespace edata {
-
-struct TableEntry {
- TableEntry(StringRef exp, int ord, const DefinedAtom *a, bool n)
- : exportName(exp), ordinal(ord), atom(a), noname(n) {}
- std::string exportName;
- int ordinal;
- const DefinedAtom *atom;
- bool noname;
-};
-
-/// The root class of all edata atoms.
-class EdataAtom : public COFFLinkerInternalAtom {
-public:
- EdataAtom(VirtualFile &file, size_t size)
- : COFFLinkerInternalAtom(file, file.getNextOrdinal(),
- std::vector<uint8_t>(size)) {}
-
- SectionChoice sectionChoice() const override { return sectionCustomRequired; }
- StringRef customSectionName() const override { return ".edata"; }
- ContentType contentType() const override { return typeData; }
- ContentPermissions permissions() const override { return permR__; }
-
- template <typename T> T *getContents() const {
- return (T *)const_cast<uint8_t *>(rawContent().data());
- }
-};
-
-} // namespace edata
-
-class EdataPass : public lld::Pass {
-public:
- EdataPass(PECOFFLinkingContext &ctx)
- : _ctx(ctx), _file(ctx), _is64(ctx.is64Bit()), _stringOrdinal(1024) {}
-
- void perform(std::unique_ptr<MutableFile> &file) override;
-
-private:
- edata::EdataAtom *
- createExportDirectoryTable(const std::vector<edata::TableEntry> &namedEntries,
- int ordinalBase, int maxOrdinal);
-
- edata::EdataAtom *
- createAddressTable(const std::vector<edata::TableEntry> &entries,
- int ordinalBase, int maxOrdinal);
-
- edata::EdataAtom *
- createNamePointerTable(const PECOFFLinkingContext &ctx,
- const std::vector<edata::TableEntry> &entries,
- MutableFile *file);
-
- edata::EdataAtom *
- createOrdinalTable(const std::vector<edata::TableEntry> &entries,
- int ordinalBase);
-
- PECOFFLinkingContext &_ctx;
- VirtualFile _file;
- bool _is64;
- int _stringOrdinal;
- mutable llvm::BumpPtrAllocator _alloc;
-};
-
-} // namespace pecoff
-} // namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/PECOFF/IdataPass.cpp b/lib/ReaderWriter/PECOFF/IdataPass.cpp
deleted file mode 100644
index d41ef581f7fa..000000000000
--- a/lib/ReaderWriter/PECOFF/IdataPass.cpp
+++ /dev/null
@@ -1,345 +0,0 @@
-//===- lib/ReaderWriter/PECOFF/IdataPass.cpp ------------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "IdataPass.h"
-#include "Pass.h"
-#include "lld/Core/File.h"
-#include "lld/Core/Pass.h"
-#include "lld/Core/Simple.h"
-#include "llvm/Support/COFF.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/Endian.h"
-#include <algorithm>
-#include <cstddef>
-#include <cstring>
-#include <map>
-#include <vector>
-
-using namespace llvm::support::endian;
-using llvm::object::delay_import_directory_table_entry;
-
-namespace lld {
-namespace pecoff {
-namespace idata {
-
-IdataAtom::IdataAtom(IdataContext &context, std::vector<uint8_t> data)
- : COFFLinkerInternalAtom(context.dummyFile,
- context.dummyFile.getNextOrdinal(), data) {
- context.file.addAtom(*this);
-}
-
-HintNameAtom::HintNameAtom(IdataContext &context, uint16_t hint,
- StringRef importName)
- : IdataAtom(context, assembleRawContent(hint, importName)),
- _importName(importName) {}
-
-std::vector<uint8_t> HintNameAtom::assembleRawContent(uint16_t hint,
- StringRef importName) {
- size_t size =
- llvm::RoundUpToAlignment(sizeof(hint) + importName.size() + 1, 2);
- std::vector<uint8_t> ret(size);
- ret[importName.size()] = 0;
- ret[importName.size() - 1] = 0;
- write16le(&ret[0], hint);
- std::memcpy(&ret[2], importName.data(), importName.size());
- return ret;
-}
-
-std::vector<uint8_t>
-ImportTableEntryAtom::assembleRawContent(uint64_t rva, bool is64) {
- // The element size of the import table is 32 bit in PE and 64 bit
- // in PE+. In PE+, bits 62-31 are filled with zero.
- if (is64) {
- std::vector<uint8_t> ret(8);
- write64le(&ret[0], rva);
- return ret;
- }
- std::vector<uint8_t> ret(4);
- write32le(&ret[0], rva);
- return ret;
-}
-
-static std::vector<ImportTableEntryAtom *>
-createImportTableAtoms(IdataContext &context,
- const std::vector<COFFSharedLibraryAtom *> &sharedAtoms,
- bool shouldAddReference, StringRef sectionName,
- llvm::BumpPtrAllocator &alloc) {
- std::vector<ImportTableEntryAtom *> ret;
- for (COFFSharedLibraryAtom *atom : sharedAtoms) {
- ImportTableEntryAtom *entry = nullptr;
- if (atom->importName().empty()) {
- // Import by ordinal
- uint64_t hint = atom->hint();
- hint |= context.ctx.is64Bit() ? (uint64_t(1) << 63) : (uint64_t(1) << 31);
- entry = new (alloc) ImportTableEntryAtom(context, hint, sectionName);
- } else {
- // Import by name
- entry = new (alloc) ImportTableEntryAtom(context, 0, sectionName);
- HintNameAtom *hintName =
- new (alloc) HintNameAtom(context, atom->hint(), atom->importName());
- addDir32NBReloc(entry, hintName, context.ctx.getMachineType(), 0);
- }
- ret.push_back(entry);
- if (shouldAddReference)
- atom->setImportTableEntry(entry);
- }
- // Add the NULL entry.
- ret.push_back(new (alloc) ImportTableEntryAtom(context, 0, sectionName));
- return ret;
-}
-
-// Creates atoms for an import lookup table. The import lookup table is an
-// array of pointers to hint/name atoms. The array needs to be terminated with
-// the NULL entry.
-void ImportDirectoryAtom::addRelocations(
- IdataContext &context, StringRef loadName,
- const std::vector<COFFSharedLibraryAtom *> &sharedAtoms) {
- // Create parallel arrays. The contents of the two are initially the
- // same. The PE/COFF loader overwrites the import address tables with the
- // pointers to the referenced items after loading the executable into
- // memory.
- std::vector<ImportTableEntryAtom *> importLookupTables =
- createImportTableAtoms(context, sharedAtoms, false, ".idata.t", _alloc);
- std::vector<ImportTableEntryAtom *> importAddressTables =
- createImportTableAtoms(context, sharedAtoms, true, ".idata.a", _alloc);
-
- addDir32NBReloc(this, importLookupTables[0], context.ctx.getMachineType(),
- offsetof(ImportDirectoryTableEntry, ImportLookupTableRVA));
- addDir32NBReloc(this, importAddressTables[0], context.ctx.getMachineType(),
- offsetof(ImportDirectoryTableEntry, ImportAddressTableRVA));
- auto *atom = new (_alloc)
- COFFStringAtom(context.dummyFile, context.dummyFile.getNextOrdinal(),
- ".idata", loadName);
- context.file.addAtom(*atom);
- addDir32NBReloc(this, atom, context.ctx.getMachineType(),
- offsetof(ImportDirectoryTableEntry, NameRVA));
-}
-
-// Create the contents for the delay-import table.
-std::vector<uint8_t> DelayImportDirectoryAtom::createContent() {
- std::vector<uint8_t> r(sizeof(delay_import_directory_table_entry), 0);
- auto entry = reinterpret_cast<delay_import_directory_table_entry *>(&r[0]);
- // link.exe seems to set 1 to Attributes field, so do we.
- entry->Attributes = 1;
- return r;
-}
-
-// Find "___delayLoadHelper2@8" (or "__delayLoadHelper2" on x64).
-// This is not efficient but should be OK for now.
-static const Atom *
-findDelayLoadHelper(MutableFile &file, const PECOFFLinkingContext &ctx) {
- StringRef sym = ctx.getDelayLoadHelperName();
- for (const DefinedAtom *atom : file.defined())
- if (atom->name() == sym)
- return atom;
- std::string msg = (sym + " was not found").str();
- llvm_unreachable(msg.c_str());
-}
-
-// Create the data referred by the delay-import table.
-void DelayImportDirectoryAtom::addRelocations(
- IdataContext &context, StringRef loadName,
- const std::vector<COFFSharedLibraryAtom *> &sharedAtoms) {
- // "ModuleHandle" field. This points to an array of pointer-size data
- // in ".data" section. Initially the array is initialized with zero.
- // The delay-load import helper will set DLL base address at runtime.
- auto *hmodule = new (_alloc) DelayImportAddressAtom(context);
- addDir32NBReloc(this, hmodule, context.ctx.getMachineType(),
- offsetof(delay_import_directory_table_entry, ModuleHandle));
-
- // "NameTable" field. The data structure of this field is the same
- // as (non-delay) import table's Import Lookup Table. Contains
- // imported function names. This is a parallel array of AddressTable
- // field.
- std::vector<ImportTableEntryAtom *> nameTable =
- createImportTableAtoms(context, sharedAtoms, false, ".didat", _alloc);
- addDir32NBReloc(
- this, nameTable[0], context.ctx.getMachineType(),
- offsetof(delay_import_directory_table_entry, DelayImportNameTable));
-
- // "Name" field. This points to the NUL-terminated DLL name string.
- auto *name = new (_alloc)
- COFFStringAtom(context.dummyFile, context.dummyFile.getNextOrdinal(),
- ".didat", loadName);
- context.file.addAtom(*name);
- addDir32NBReloc(this, name, context.ctx.getMachineType(),
- offsetof(delay_import_directory_table_entry, Name));
-
- // "AddressTable" field. This points to an array of pointers, which
- // in turn pointing to delay-load functions.
- std::vector<DelayImportAddressAtom *> addrTable;
- for (int i = 0, e = sharedAtoms.size() + 1; i < e; ++i)
- addrTable.push_back(new (_alloc) DelayImportAddressAtom(context));
- for (int i = 0, e = sharedAtoms.size(); i < e; ++i)
- sharedAtoms[i]->setImportTableEntry(addrTable[i]);
- addDir32NBReloc(
- this, addrTable[0], context.ctx.getMachineType(),
- offsetof(delay_import_directory_table_entry, DelayImportAddressTable));
-
- const Atom *delayLoadHelper = findDelayLoadHelper(context.file, context.ctx);
- for (int i = 0, e = sharedAtoms.size(); i < e; ++i) {
- const DefinedAtom *loader = new (_alloc) DelayLoaderAtom(
- context, addrTable[i], this, delayLoadHelper);
- if (context.ctx.is64Bit())
- addDir64Reloc(addrTable[i], loader, context.ctx.getMachineType(), 0);
- else
- addDir32Reloc(addrTable[i], loader, context.ctx.getMachineType(), 0);
- }
-}
-
-DelayLoaderAtom::DelayLoaderAtom(IdataContext &context, const Atom *impAtom,
- const Atom *descAtom, const Atom *delayLoadHelperAtom)
- : IdataAtom(context, createContent(context.ctx.getMachineType())) {
- MachineTypes machine = context.ctx.getMachineType();
- switch (machine) {
- case llvm::COFF::IMAGE_FILE_MACHINE_I386:
- addDir32Reloc(this, impAtom, machine, 3);
- addDir32Reloc(this, descAtom, machine, 8);
- addRel32Reloc(this, delayLoadHelperAtom, machine, 13);
- break;
- case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
- addRel32Reloc(this, impAtom, machine, 36);
- addRel32Reloc(this, descAtom, machine, 43);
- addRel32Reloc(this, delayLoadHelperAtom, machine, 48);
- break;
- default:
- llvm::report_fatal_error("unsupported machine type");
- }
-}
-
-// DelayLoaderAtom contains a wrapper function for __delayLoadHelper2.
-//
-// __delayLoadHelper2 takes two pointers: a pointer to the delay-load
-// table descripter and a pointer to _imp_ symbol for the function
-// to be resolved.
-//
-// __delayLoadHelper2 looks at the table descriptor to know the DLL
-// name, calls dlopen()-like function to load it, resolves all
-// imported symbols, and then writes the resolved addresses to the
-// import address table. It returns a pointer to the resolved
-// function.
-//
-// __delayLoadHelper2 is defined in delayimp.lib.
-std::vector<uint8_t>
-DelayLoaderAtom::createContent(MachineTypes machine) const {
- static const uint8_t x86[] = {
- 0x51, // push ecx
- 0x52, // push edx
- 0x68, 0, 0, 0, 0, // push offset ___imp__<FUNCNAME>
- 0x68, 0, 0, 0, 0, // push offset ___DELAY_IMPORT_DESCRIPTOR_<DLLNAME>_dll
- 0xE8, 0, 0, 0, 0, // call ___delayLoadHelper2@8
- 0x5A, // pop edx
- 0x59, // pop ecx
- 0xFF, 0xE0, // jmp eax
- };
- static const uint8_t x64[] = {
- 0x51, // push rcx
- 0x52, // push rdx
- 0x41, 0x50, // push r8
- 0x41, 0x51, // push r9
- 0x48, 0x83, 0xEC, 0x48, // sub rsp, 48h
- 0x66, 0x0F, 0x7F, 0x04, 0x24, // movdqa xmmword ptr [rsp], xmm0
- 0x66, 0x0F, 0x7F, 0x4C, 0x24, 0x10, // movdqa xmmword ptr [rsp+10h], xmm1
- 0x66, 0x0F, 0x7F, 0x54, 0x24, 0x20, // movdqa xmmword ptr [rsp+20h], xmm2
- 0x66, 0x0F, 0x7F, 0x5C, 0x24, 0x30, // movdqa xmmword ptr [rsp+30h], xmm3
- 0x48, 0x8D, 0x15, 0, 0, 0, 0, // lea rdx, [__imp_<FUNCNAME>]
- 0x48, 0x8D, 0x0D, 0, 0, 0, 0, // lea rcx, [___DELAY_IMPORT_...]
- 0xE8, 0, 0, 0, 0, // call __delayLoadHelper2
- 0x66, 0x0F, 0x6F, 0x04, 0x24, // movdqa xmm0, xmmword ptr [rsp]
- 0x66, 0x0F, 0x6F, 0x4C, 0x24, 0x10, // movdqa xmm1, xmmword ptr [rsp+10h]
- 0x66, 0x0F, 0x6F, 0x54, 0x24, 0x20, // movdqa xmm2, xmmword ptr [rsp+20h]
- 0x66, 0x0F, 0x6F, 0x5C, 0x24, 0x30, // movdqa xmm3, xmmword ptr [rsp+30h]
- 0x48, 0x83, 0xC4, 0x48, // add rsp, 48h
- 0x41, 0x59, // pop r9
- 0x41, 0x58, // pop r8
- 0x5A, // pop rdx
- 0x59, // pop rcx
- 0xFF, 0xE0, // jmp rax
- };
- switch (machine) {
- case llvm::COFF::IMAGE_FILE_MACHINE_I386:
- return std::vector<uint8_t>(x86, x86 + sizeof(x86));
- case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
- return std::vector<uint8_t>(x64, x64 + sizeof(x64));
- default:
- llvm::report_fatal_error("unsupported machine type");
- }
-}
-
-} // namespace idata
-
-void IdataPass::perform(std::unique_ptr<MutableFile> &file) {
- if (file->sharedLibrary().empty())
- return;
-
- idata::IdataContext context(*file, _dummyFile, _ctx);
- std::map<StringRef, std::vector<COFFSharedLibraryAtom *>> sharedAtoms =
- groupByLoadName(*file);
- bool hasImports = false;
- bool hasDelayImports = false;
-
- // Create the import table and terminate it with the null entry.
- for (auto i : sharedAtoms) {
- StringRef loadName = i.first;
- if (_ctx.isDelayLoadDLL(loadName))
- continue;
- hasImports = true;
- std::vector<COFFSharedLibraryAtom *> &atoms = i.second;
- new (_alloc) idata::ImportDirectoryAtom(context, loadName, atoms);
- }
- if (hasImports)
- new (_alloc) idata::NullImportDirectoryAtom(context);
-
- // Create the delay import table and terminate it with the null entry.
- for (auto i : sharedAtoms) {
- StringRef loadName = i.first;
- if (!_ctx.isDelayLoadDLL(loadName))
- continue;
- hasDelayImports = true;
- std::vector<COFFSharedLibraryAtom *> &atoms = i.second;
- new (_alloc) idata::DelayImportDirectoryAtom(context, loadName, atoms);
- }
- if (hasDelayImports)
- new (_alloc) idata::DelayNullImportDirectoryAtom(context);
-
- replaceSharedLibraryAtoms(*file);
-}
-
-std::map<StringRef, std::vector<COFFSharedLibraryAtom *> >
-IdataPass::groupByLoadName(MutableFile &file) {
- std::map<StringRef, COFFSharedLibraryAtom *> uniqueAtoms;
- for (const SharedLibraryAtom *atom : file.sharedLibrary())
- uniqueAtoms[atom->name()] =
- (COFFSharedLibraryAtom *)const_cast<SharedLibraryAtom *>(atom);
-
- std::map<StringRef, std::vector<COFFSharedLibraryAtom *> > ret;
- for (auto i : uniqueAtoms) {
- COFFSharedLibraryAtom *atom = i.second;
- ret[atom->loadName()].push_back(atom);
- }
- return ret;
-}
-
-/// Transforms a reference to a COFFSharedLibraryAtom to a real reference.
-void IdataPass::replaceSharedLibraryAtoms(MutableFile &file) {
- for (const DefinedAtom *atom : file.defined()) {
- for (const Reference *ref : *atom) {
- const Atom *target = ref->target();
- auto *sharedAtom = dyn_cast<SharedLibraryAtom>(target);
- if (!sharedAtom)
- continue;
- const auto *coffSharedAtom = (const COFFSharedLibraryAtom *)sharedAtom;
- const DefinedAtom *entry = coffSharedAtom->getImportTableEntry();
- const_cast<Reference *>(ref)->setTarget(entry);
- }
- }
-}
-
-} // namespace pecoff
-} // namespace lld
diff --git a/lib/ReaderWriter/PECOFF/IdataPass.h b/lib/ReaderWriter/PECOFF/IdataPass.h
deleted file mode 100644
index 9db82160339a..000000000000
--- a/lib/ReaderWriter/PECOFF/IdataPass.h
+++ /dev/null
@@ -1,218 +0,0 @@
-//===- lib/ReaderWriter/PECOFF/IdataPass.h---------------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file \brief This linker pass creates atoms for the DLL import
-/// information. The defined atoms constructed in this pass will go into .idata
-/// section, unless .idata section is merged with other section such as .data.
-///
-/// For the details of the .idata section format, see Microsoft PE/COFF
-/// Specification section 5.4, The .idata Section.
-///
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_PE_COFF_IDATA_PASS_H
-#define LLD_READER_WRITER_PE_COFF_IDATA_PASS_H
-
-#include "Atoms.h"
-#include "lld/Core/File.h"
-#include "lld/Core/Pass.h"
-#include "lld/Core/Simple.h"
-#include "lld/ReaderWriter/PECOFFLinkingContext.h"
-#include "llvm/Support/COFF.h"
-#include <algorithm>
-#include <map>
-
-using llvm::COFF::ImportDirectoryTableEntry;
-
-namespace lld {
-namespace pecoff {
-namespace idata {
-
-class DLLNameAtom;
-class HintNameAtom;
-class ImportTableEntryAtom;
-
-// A state object of this pass.
-struct IdataContext {
- IdataContext(MutableFile &f, VirtualFile &g, const PECOFFLinkingContext &c)
- : file(f), dummyFile(g), ctx(c) {}
- MutableFile &file;
- VirtualFile &dummyFile;
- const PECOFFLinkingContext &ctx;
-};
-
-/// The root class of all idata atoms.
-class IdataAtom : public COFFLinkerInternalAtom {
-public:
- SectionChoice sectionChoice() const override { return sectionCustomRequired; }
- StringRef customSectionName() const override { return ".idata"; }
- ContentType contentType() const override { return typeData; }
- ContentPermissions permissions() const override { return permR__; }
-
-protected:
- IdataAtom(IdataContext &context, std::vector<uint8_t> data);
-};
-
-/// A HintNameAtom represents a symbol that will be imported from a DLL at
-/// runtime. It consists with an optional hint, which is a small integer, and a
-/// symbol name.
-///
-/// A hint is an index of the export pointer table in a DLL. If the import
-/// library and DLL is in sync (i.e., ".lib" and ".dll" is for the same version
-/// or the symbol ordinal is maintained by hand with ".exp" file), the PE/COFF
-/// loader can find the symbol quickly.
-class HintNameAtom : public IdataAtom {
-public:
- HintNameAtom(IdataContext &context, uint16_t hint, StringRef importName);
-
- StringRef getContentString() { return _importName; }
-
-private:
- std::vector<uint8_t> assembleRawContent(uint16_t hint, StringRef importName);
- StringRef _importName;
-};
-
-class ImportTableEntryAtom : public IdataAtom {
-public:
- ImportTableEntryAtom(IdataContext &ctx, uint64_t contents,
- StringRef sectionName)
- : IdataAtom(ctx, assembleRawContent(contents, ctx.ctx.is64Bit())),
- _sectionName(sectionName) {}
-
- StringRef customSectionName() const override {
- return _sectionName;
- };
-
-private:
- std::vector<uint8_t> assembleRawContent(uint64_t contents, bool is64);
- StringRef _sectionName;
-};
-
-/// An ImportDirectoryAtom includes information to load a DLL, including a DLL
-/// name, symbols that will be resolved from the DLL, and the import address
-/// table that are overwritten by the loader with the pointers to the referenced
-/// items. The executable has one ImportDirectoryAtom per one imported DLL.
-class ImportDirectoryAtom : public IdataAtom {
-public:
- ImportDirectoryAtom(IdataContext &context, StringRef loadName,
- const std::vector<COFFSharedLibraryAtom *> &sharedAtoms)
- : IdataAtom(context, std::vector<uint8_t>(20, 0)) {
- addRelocations(context, loadName, sharedAtoms);
- }
-
- StringRef customSectionName() const override { return ".idata.d"; }
-
-private:
- void addRelocations(IdataContext &context, StringRef loadName,
- const std::vector<COFFSharedLibraryAtom *> &sharedAtoms);
-
- mutable llvm::BumpPtrAllocator _alloc;
-};
-
-/// The last NULL entry in the import directory.
-class NullImportDirectoryAtom : public IdataAtom {
-public:
- explicit NullImportDirectoryAtom(IdataContext &context)
- : IdataAtom(context, std::vector<uint8_t>(20, 0)) {}
-
- StringRef customSectionName() const override { return ".idata.d"; }
-};
-
-/// The class for the the delay-load import table.
-class DelayImportDirectoryAtom : public IdataAtom {
-public:
- DelayImportDirectoryAtom(
- IdataContext &context, StringRef loadName,
- const std::vector<COFFSharedLibraryAtom *> &sharedAtoms)
- : IdataAtom(context, createContent()) {
- addRelocations(context, loadName, sharedAtoms);
- }
-
- StringRef customSectionName() const override { return ".didat.d"; }
-
-private:
- std::vector<uint8_t> createContent();
- void addRelocations(IdataContext &context, StringRef loadName,
- const std::vector<COFFSharedLibraryAtom *> &sharedAtoms);
-
- mutable llvm::BumpPtrAllocator _alloc;
-};
-
-/// Terminator of the delay-load import table. The content of this atom is all
-/// zero.
-class DelayNullImportDirectoryAtom : public IdataAtom {
-public:
- explicit DelayNullImportDirectoryAtom(IdataContext &context)
- : IdataAtom(context, createContent()) {}
- StringRef customSectionName() const override { return ".didat.d"; }
-
-private:
- std::vector<uint8_t> createContent() const {
- return std::vector<uint8_t>(
- sizeof(llvm::object::delay_import_directory_table_entry), 0);
- }
-};
-
-class DelayImportAddressAtom : public IdataAtom {
-public:
- explicit DelayImportAddressAtom(IdataContext &context)
- : IdataAtom(context, createContent(context.ctx)),
- _align(Alignment(context.ctx.is64Bit() ? 3 : 2)) {}
- StringRef customSectionName() const override { return ".data"; }
- ContentPermissions permissions() const override { return permRW_; }
- Alignment alignment() const override { return _align; }
-
-private:
- std::vector<uint8_t> createContent(const PECOFFLinkingContext &ctx) const {
- return std::vector<uint8_t>(ctx.is64Bit() ? 8 : 4, 0);
- }
-
- Alignment _align;
-};
-
-// DelayLoaderAtom contains a wrapper function for __delayLoadHelper2.
-class DelayLoaderAtom : public IdataAtom {
-public:
- DelayLoaderAtom(IdataContext &context, const Atom *impAtom,
- const Atom *descAtom, const Atom *delayLoadHelperAtom);
- StringRef customSectionName() const override { return ".text"; }
- ContentPermissions permissions() const override { return permR_X; }
- Alignment alignment() const override { return Alignment(0); }
-
-private:
- std::vector<uint8_t> createContent(MachineTypes machine) const;
-};
-
-} // namespace idata
-
-class IdataPass : public lld::Pass {
-public:
- IdataPass(const PECOFFLinkingContext &ctx) : _dummyFile(ctx), _ctx(ctx) {}
-
- void perform(std::unique_ptr<MutableFile> &file) override;
-
-private:
- std::map<StringRef, std::vector<COFFSharedLibraryAtom *>>
- groupByLoadName(MutableFile &file);
-
- void replaceSharedLibraryAtoms(MutableFile &file);
-
- // A dummy file with which all the atoms created in the pass will be
- // associated. Atoms need to be associated to an input file even if it's not
- // read from a file, so we use this object.
- VirtualFile _dummyFile;
-
- const PECOFFLinkingContext &_ctx;
- llvm::BumpPtrAllocator _alloc;
-};
-
-} // namespace pecoff
-} // namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/PECOFF/InferSubsystemPass.h b/lib/ReaderWriter/PECOFF/InferSubsystemPass.h
deleted file mode 100644
index cbf863ee4784..000000000000
--- a/lib/ReaderWriter/PECOFF/InferSubsystemPass.h
+++ /dev/null
@@ -1,66 +0,0 @@
-//===- lib/ReaderWriter/PECOFF/InferSubsystemPass.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_PE_COFF_INFER_SUBSYSTEM_PASS_H
-#define LLD_READER_WRITER_PE_COFF_INFER_SUBSYSTEM_PASS_H
-
-#include "Atoms.h"
-#include "lld/Core/Pass.h"
-#include <vector>
-
-namespace lld {
-namespace pecoff {
-
-// Infers subsystem from entry point function name.
-class InferSubsystemPass : public lld::Pass {
-public:
- InferSubsystemPass(PECOFFLinkingContext &ctx) : _ctx(ctx) {}
-
- void perform(std::unique_ptr<MutableFile> &file) override {
- if (_ctx.getSubsystem() != WindowsSubsystem::IMAGE_SUBSYSTEM_UNKNOWN)
- return;
-
- if (_ctx.isDll()) {
- _ctx.setSubsystem(WindowsSubsystem::IMAGE_SUBSYSTEM_WINDOWS_GUI);
- return;
- }
-
- // Scan the resolved symbols to infer the subsystem.
- const std::string wWinMain = _ctx.decorateSymbol("wWinMainCRTStartup");
- const std::string wWinMainAt = _ctx.decorateSymbol("wWinMainCRTStartup@");
- const std::string winMain = _ctx.decorateSymbol("WinMainCRTStartup");
- const std::string winMainAt = _ctx.decorateSymbol("WinMainCRTStartup@");
- const std::string wmain = _ctx.decorateSymbol("wmainCRTStartup");
- const std::string wmainAt = _ctx.decorateSymbol("wmainCRTStartup@");
- const std::string main = _ctx.decorateSymbol("mainCRTStartup");
- const std::string mainAt = _ctx.decorateSymbol("mainCRTStartup@");
-
- for (const DefinedAtom *atom : file->definedAtoms()) {
- if (atom->name() == wWinMain || atom->name().startswith(wWinMainAt) ||
- atom->name() == winMain || atom->name().startswith(winMainAt)) {
- _ctx.setSubsystem(WindowsSubsystem::IMAGE_SUBSYSTEM_WINDOWS_GUI);
- return;
- }
- if (atom->name() == wmain || atom->name().startswith(wmainAt) ||
- atom->name() == main || atom->name().startswith(mainAt)) {
- _ctx.setSubsystem(WindowsSubsystem::IMAGE_SUBSYSTEM_WINDOWS_CUI);
- return;
- }
- }
- llvm::report_fatal_error("Failed to infer subsystem");
- }
-
-private:
- PECOFFLinkingContext &_ctx;
-};
-
-} // namespace pecoff
-} // namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.cpp b/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.cpp
deleted file mode 100644
index a11410784b8c..000000000000
--- a/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-//===- lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.cpp --------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "LinkerGeneratedSymbolFile.h"
-
-namespace lld {
-namespace pecoff {
-
-// Find decorated symbol, namely /sym@[0-9]+/ or /\?sym@@.+/.
-bool findDecoratedSymbol(PECOFFLinkingContext *ctx,
- std::string sym, std::string &res) {
- const std::set<std::string> &defined = ctx->definedSymbols();
- // Search for /sym@[0-9]+/
- {
- std::string s = sym + '@';
- auto it = defined.lower_bound(s);
- for (auto e = defined.end(); it != e; ++it) {
- if (!StringRef(*it).startswith(s))
- break;
- if (it->size() == s.size())
- continue;
- StringRef suffix = StringRef(*it).substr(s.size());
- if (suffix.find_first_not_of("0123456789") != StringRef::npos)
- continue;
- res = *it;
- return true;
- }
- }
- // Search for /\?sym@@.+/
- {
- std::string s = "?" + ctx->undecorateSymbol(sym).str() + "@@";
- auto it = defined.lower_bound(s);
- if (it != defined.end() && StringRef(*it).startswith(s)) {
- res = *it;
- return true;
- }
- }
- return false;
-}
-
-} // namespace pecoff
-} // namespace lld
diff --git a/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h b/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h
deleted file mode 100644
index b9764d70bb3b..000000000000
--- a/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h
+++ /dev/null
@@ -1,309 +0,0 @@
-//===- lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h ----------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "Atoms.h"
-#include "lld/Core/Simple.h"
-#include "lld/ReaderWriter/PECOFFLinkingContext.h"
-#include "llvm/Support/Allocator.h"
-#include <algorithm>
-#include <mutex>
-
-using llvm::COFF::WindowsSubsystem;
-
-namespace lld {
-namespace pecoff {
-
-bool findDecoratedSymbol(PECOFFLinkingContext *ctx,
- std::string sym, std::string &res);
-
-namespace impl {
-
-/// The defined atom for dllexported symbols with __imp_ prefix.
-class ImpPointerAtom : public COFFLinkerInternalAtom {
-public:
- ImpPointerAtom(const File &file, StringRef symbolName, uint64_t ordinal)
- : COFFLinkerInternalAtom(file, /*oridnal*/ 0, std::vector<uint8_t>(4),
- symbolName),
- _ordinal(ordinal) {}
-
- uint64_t ordinal() const override { return _ordinal; }
- Scope scope() const override { return scopeGlobal; }
- ContentType contentType() const override { return typeData; }
- Alignment alignment() const override { return Alignment(4); }
- ContentPermissions permissions() const override { return permR__; }
-
-private:
- uint64_t _ordinal;
-};
-
-class ImpSymbolFile : public SimpleFile {
-public:
- ImpSymbolFile(StringRef defsym, StringRef undefsym, uint64_t ordinal,
- bool is64)
- : SimpleFile(defsym), _undefined(*this, undefsym),
- _defined(*this, defsym, ordinal) {
- SimpleReference *ref;
- if (is64) {
- ref = new SimpleReference(Reference::KindNamespace::COFF,
- Reference::KindArch::x86_64,
- llvm::COFF::IMAGE_REL_AMD64_ADDR32,
- 0, &_undefined, 0);
- } else {
- ref = new SimpleReference(Reference::KindNamespace::COFF,
- Reference::KindArch::x86,
- llvm::COFF::IMAGE_REL_I386_DIR32,
- 0, &_undefined, 0);
- }
- _defined.addReference(std::unique_ptr<SimpleReference>(ref));
- addAtom(_defined);
- addAtom(_undefined);
- };
-
-private:
- SimpleUndefinedAtom _undefined;
- ImpPointerAtom _defined;
-};
-
-// A file to make Resolver to resolve a symbol TO instead of a symbol FROM,
-// using fallback mechanism for an undefined symbol. One can virtually rename an
-// undefined symbol using this file.
-class SymbolRenameFile : public SimpleFile {
-public:
- SymbolRenameFile(StringRef from, StringRef to)
- : SimpleFile("<symbol-rename>"), _fromSym(from), _toSym(to),
- _from(*this, _fromSym, &_to), _to(*this, _toSym) {
- addAtom(_from);
- };
-
-private:
- std::string _fromSym;
- std::string _toSym;
- COFFUndefinedAtom _from;
- COFFUndefinedAtom _to;
-};
-
-} // namespace impl
-
-// A virtual file containing absolute symbol __ImageBase. __ImageBase (or
-// ___ImageBase on x86) is a linker-generated symbol whose address is the same
-// as the image base address.
-class LinkerGeneratedSymbolFile : public SimpleFile {
-public:
- LinkerGeneratedSymbolFile(const PECOFFLinkingContext &ctx)
- : SimpleFile("<linker-internal-file>"),
- _imageBaseAtom(*this, ctx.decorateSymbol("__ImageBase"),
- Atom::scopeGlobal, ctx.getBaseAddress()) {
- addAtom(_imageBaseAtom);
- };
-
-private:
- SimpleAbsoluteAtom _imageBaseAtom;
-};
-
-// A LocallyImporteSymbolFile is an archive file containing __imp_
-// symbols for local use.
-//
-// For each defined symbol, linker creates an implicit defined symbol
-// by appending "__imp_" prefix to the original name. The content of
-// the implicit symbol is a pointer to the original symbol
-// content. This feature allows one to compile and link the following
-// code without error, although _imp__hello is not defined in the
-// code. (the leading "_" in this example is automatically appended,
-// assuming it's x86.)
-//
-// void hello() { printf("Hello\n"); }
-// extern void (*_imp__hello)();
-// int main() {
-// _imp__hello();
-// return 0;
-// }
-//
-// This odd feature is for the compatibility with MSVC link.exe.
-class LocallyImportedSymbolFile : public SimpleArchiveLibraryFile {
-public:
- LocallyImportedSymbolFile(const PECOFFLinkingContext &ctx)
- : SimpleArchiveLibraryFile("__imp_"), _is64(ctx.is64Bit()),
- _ordinal(0) {}
-
- File *find(StringRef sym, bool dataSymbolOnly) override {
- std::string prefix = "__imp_";
- if (!sym.startswith(prefix))
- return nullptr;
- StringRef undef = sym.substr(prefix.size());
- return new (_alloc) impl::ImpSymbolFile(sym, undef, _ordinal++, _is64);
- }
-
-private:
- bool _is64;
- uint64_t _ordinal;
- llvm::BumpPtrAllocator _alloc;
-};
-
-// A ExportedSymbolRenameFile is a virtual archive file for dllexported symbols.
-//
-// One usually has to specify the exact symbol name to resolve it. That's true
-// in most cases for PE/COFF, except the one described below.
-//
-// DLLExported symbols can be specified using a module definition file. In a
-// file, one can write an EXPORT directive followed by symbol names. Such
-// symbols may not be fully decorated.
-//
-// If a symbol FOO is specified to be dllexported by a module definition file,
-// linker has to search not only for /FOO/ but also for /FOO@[0-9]+/ for stdcall
-// and for /\?FOO@@.+/ for C++. This ambiguous matching semantics does not fit
-// well with Resolver.
-//
-// We could probably modify Resolver to resolve ambiguous symbols, but I think
-// we don't want to do that because it'd be rarely used, and only this Windows
-// specific feature would use it. It's probably not a good idea to make the core
-// linker to be able to deal with it.
-//
-// So, instead of tweaking Resolver, we chose to do some hack here. An
-// ExportedSymbolRenameFile maintains a set containing all possibly defined
-// symbol names. That set would be a union of (1) all the defined symbols that
-// are already parsed and read and (2) all the defined symbols in archive files
-// that are not yet be parsed.
-//
-// If Resolver asks this file to return an atom for a dllexported symbol, find()
-// looks up the set, doing ambiguous matching. If there's a symbol with @
-// prefix, it returns an atom to rename the dllexported symbol, hoping that
-// Resolver will find the new symbol with atsign from an archive file at the
-// next visit.
-class ExportedSymbolRenameFile : public SimpleArchiveLibraryFile {
-public:
- ExportedSymbolRenameFile(const PECOFFLinkingContext &ctx)
- : SimpleArchiveLibraryFile("<export>"),
- _ctx(const_cast<PECOFFLinkingContext *>(&ctx)) {
- for (PECOFFLinkingContext::ExportDesc &desc : _ctx->getDllExports())
- _exportedSyms.insert(desc.name);
- }
-
- File *find(StringRef sym, bool dataSymbolOnly) override {
- typedef PECOFFLinkingContext::ExportDesc ExportDesc;
- if (_exportedSyms.count(sym) == 0)
- return nullptr;
- std::string replace;
- if (!findDecoratedSymbol(_ctx, sym.str(), replace))
- return nullptr;
-
- for (ExportDesc &exp : _ctx->getDllExports())
- if (exp.name == sym)
- exp.mangledName = replace;
- if (_ctx->deadStrip())
- _ctx->addDeadStripRoot(_ctx->allocate(replace));
- return new (_alloc) impl::SymbolRenameFile(sym, replace);
- }
-
-private:
- std::set<std::string> _exportedSyms;
- llvm::BumpPtrAllocator _alloc;
- PECOFFLinkingContext *_ctx;
-};
-
-// Windows has not only one but many entry point functions. The
-// appropriate one is automatically selected based on the subsystem
-// setting and the user-supplied entry point function.
-//
-// http://msdn.microsoft.com/en-us/library/f9t8842e.aspx
-class EntryPointFile : public SimpleFile {
-public:
- EntryPointFile(const PECOFFLinkingContext &ctx)
- : SimpleFile("<entry>"), _ctx(const_cast<PECOFFLinkingContext *>(&ctx)),
- _firstTime(true) {}
-
- const atom_collection<UndefinedAtom> &undefined() const override {
- return const_cast<EntryPointFile *>(this)->getUndefinedAtoms();
- }
-
-private:
- const atom_collection<UndefinedAtom> &getUndefinedAtoms() {
- std::lock_guard<std::mutex> lock(_mutex);
- if (!_firstTime)
- return _undefinedAtoms;
- _firstTime = false;
-
- if (_ctx->hasEntry()) {
- StringRef entrySym = _ctx->allocate(getEntry());
- _undefinedAtoms._atoms.push_back(
- new (_alloc) SimpleUndefinedAtom(*this, entrySym));
- _ctx->setHasEntry(true);
- _ctx->setEntrySymbolName(entrySym);
- if (_ctx->deadStrip())
- _ctx->addDeadStripRoot(entrySym);
- }
- return _undefinedAtoms;
- }
-
- // Returns the entry point function name.
- std::string getEntry() const {
- StringRef opt = _ctx->getEntrySymbolName();
- if (!opt.empty()) {
- std::string mangled;
- if (findDecoratedSymbol(_ctx, opt, mangled))
- return mangled;
- return _ctx->decorateSymbol(opt);
- }
- return _ctx->decorateSymbol(getDefaultEntry());
- }
-
- std::string getDefaultEntry() const {
- const std::string wWinMainCRTStartup = "wWinMainCRTStartup";
- const std::string WinMainCRTStartup = "WinMainCRTStartup";
- const std::string wmainCRTStartup = "wmainCRTStartup";
- const std::string mainCRTStartup = "mainCRTStartup";
-
- if (_ctx->isDll()) {
- if (_ctx->getMachineType() == llvm::COFF::IMAGE_FILE_MACHINE_I386)
- return "_DllMainCRTStartup@12";
- return "_DllMainCRTStartup";
- }
-
- // Returns true if a given name exists in an input object file.
- auto defined = [&](StringRef name) -> bool {
- StringRef sym = _ctx->decorateSymbol(name);
- if (_ctx->definedSymbols().count(sym))
- return true;
- std::string ignore;
- return findDecoratedSymbol(_ctx, sym, ignore);
- };
-
- switch (_ctx->getSubsystem()) {
- case WindowsSubsystem::IMAGE_SUBSYSTEM_UNKNOWN: {
- if (defined("wWinMain"))
- return wWinMainCRTStartup;
- if (defined("WinMain"))
- return WinMainCRTStartup;
- if (defined("wmain"))
- return wmainCRTStartup;
- if (!defined("main"))
- llvm::errs() << "Cannot infer subsystem; assuming /subsystem:console\n";
- return mainCRTStartup;
- }
- case WindowsSubsystem::IMAGE_SUBSYSTEM_WINDOWS_GUI:
- if (defined("WinMain"))
- return WinMainCRTStartup;
- return wWinMainCRTStartup;
- case WindowsSubsystem::IMAGE_SUBSYSTEM_WINDOWS_CUI:
- if (defined("wmain"))
- return wmainCRTStartup;
- return mainCRTStartup;
- default:
- return mainCRTStartup;
- }
- }
-
- PECOFFLinkingContext *_ctx;
- atom_collection_vector<UndefinedAtom> _undefinedAtoms;
- std::mutex _mutex;
- llvm::BumpPtrAllocator _alloc;
- bool _firstTime;
-};
-
-} // end namespace pecoff
-} // end namespace lld
diff --git a/lib/ReaderWriter/PECOFF/LoadConfigPass.cpp b/lib/ReaderWriter/PECOFF/LoadConfigPass.cpp
deleted file mode 100644
index be2f5627f4ea..000000000000
--- a/lib/ReaderWriter/PECOFF/LoadConfigPass.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
-//===- lib/ReaderWriter/PECOFF/LoadConfigPass.cpp -------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// A Load Configuration is a data structure for x86 containing an address of the
-// SEH handler table. The Data Directory in the file header points to a load
-// configuration. Technically that indirection is not needed but exists for
-// historical reasons.
-//
-// If the file being handled has .sxdata section containing SEH handler table,
-// this pass will create a Load Configuration atom.
-//
-//===----------------------------------------------------------------------===//
-
-#include "Pass.h"
-#include "LoadConfigPass.h"
-#include "lld/Core/File.h"
-#include "lld/Core/Pass.h"
-#include "lld/Core/Simple.h"
-#include "llvm/Object/COFF.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/Path.h"
-#include <climits>
-#include <ctime>
-#include <utility>
-
-using llvm::object::coff_load_configuration32;
-
-namespace lld {
-namespace pecoff {
-namespace loadcfg {
-
-LoadConfigAtom::LoadConfigAtom(VirtualFile &file, const DefinedAtom *sxdata,
- int count)
- : COFFLinkerInternalAtom(
- file, file.getNextOrdinal(),
- std::vector<uint8_t>(sizeof(coff_load_configuration32))) {
- addDir32Reloc(
- this, sxdata, llvm::COFF::IMAGE_FILE_MACHINE_I386,
- offsetof(llvm::object::coff_load_configuration32, SEHandlerTable));
- auto *data = getContents<llvm::object::coff_load_configuration32>();
- data->SEHandlerCount = count;
-}
-
-} // namespace loadcfg
-
-void LoadConfigPass::perform(std::unique_ptr<MutableFile> &file) {
- if (_ctx.noSEH())
- return;
-
- // Find the first atom in .sxdata section.
- const DefinedAtom *sxdata = nullptr;
- int sectionSize = 0;
- for (const DefinedAtom *atom : file->defined()) {
- if (atom->customSectionName() == ".sxdata") {
- if (!sxdata)
- sxdata = atom;
- sectionSize += sxdata->size();
- }
- }
- if (!sxdata)
- return;
-
- auto *loadcfg = new (_alloc)
- loadcfg::LoadConfigAtom(_file, sxdata, sectionSize / sizeof(uint32_t));
- file->addAtom(*loadcfg);
-}
-
-} // namespace pecoff
-} // namespace lld
diff --git a/lib/ReaderWriter/PECOFF/LoadConfigPass.h b/lib/ReaderWriter/PECOFF/LoadConfigPass.h
deleted file mode 100644
index 9f4a25f2b10e..000000000000
--- a/lib/ReaderWriter/PECOFF/LoadConfigPass.h
+++ /dev/null
@@ -1,63 +0,0 @@
-//===- lib/ReaderWriter/PECOFF/LoadConfigPass.h ---------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file \brief This linker pass creates an atom for Load Configuration
-/// structure.
-///
-/// For the details of the Load Configuration structure, see Microsoft PE/COFF
-/// Specification section 5.8. The Load Configuration Structure (Image Only).
-///
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_PE_COFF_LOAD_CONFIG_PASS_H
-#define LLD_READER_WRITER_PE_COFF_LOAD_CONFIG_PASS_H
-
-#include "Atoms.h"
-#include "lld/Core/File.h"
-#include "lld/Core/Pass.h"
-#include "lld/Core/Simple.h"
-#include "lld/ReaderWriter/PECOFFLinkingContext.h"
-#include <map>
-
-namespace lld {
-namespace pecoff {
-namespace loadcfg {
-
-class LoadConfigAtom : public COFFLinkerInternalAtom {
-public:
- LoadConfigAtom(VirtualFile &file, const DefinedAtom *sxdata, int count);
-
- SectionChoice sectionChoice() const override { return sectionCustomRequired; }
- StringRef customSectionName() const override { return ".loadcfg"; }
- ContentType contentType() const override { return typeData; }
- ContentPermissions permissions() const override { return permR__; }
-
- template <typename T> T *getContents() const {
- return (T *)const_cast<uint8_t *>(rawContent().data());
- }
-};
-
-} // namespace loadcfg
-
-class LoadConfigPass : public lld::Pass {
-public:
- LoadConfigPass(PECOFFLinkingContext &ctx) : _ctx(ctx), _file(ctx) {}
-
- void perform(std::unique_ptr<MutableFile> &file) override;
-
-private:
- PECOFFLinkingContext &_ctx;
- VirtualFile _file;
- mutable llvm::BumpPtrAllocator _alloc;
-};
-
-} // namespace pecoff
-} // namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/PECOFF/Makefile b/lib/ReaderWriter/PECOFF/Makefile
deleted file mode 100644
index 3ad16969bba7..000000000000
--- a/lib/ReaderWriter/PECOFF/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-##===- lld/lib/ReaderWriter/PECOFF/Makefile --------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LLD_LEVEL := ../../..
-LIBRARYNAME := lldPECOFF
-USEDLIBS = lldCore.a
-
-include $(LLD_LEVEL)/Makefile
diff --git a/lib/ReaderWriter/PECOFF/OrderPass.h b/lib/ReaderWriter/PECOFF/OrderPass.h
deleted file mode 100644
index 73133ff73638..000000000000
--- a/lib/ReaderWriter/PECOFF/OrderPass.h
+++ /dev/null
@@ -1,67 +0,0 @@
-//===- lib/ReaderWriter/PECOFF/OrderPass.h -------------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file \brief This pass sorts atoms by section name, so that they will appear
-/// in the correct order in the output.
-///
-/// In COFF, sections will be merged into one section by the linker if their
-/// names are the same after discarding the "$" character and all characters
-/// follow it from their names. The characters following the "$" character
-/// determines the merge order. Assume there's an object file containing four
-/// data sections in the following order.
-///
-/// - .data$2
-/// - .data$3
-/// - .data$1
-/// - .data
-///
-/// In this case, the resulting binary should have ".data" section with the
-/// contents of ".data", ".data$1", ".data$2" and ".data$3" in that order.
-///
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_PE_COFF_ORDER_PASS_H
-#define LLD_READER_WRITER_PE_COFF_ORDER_PASS_H
-
-#include "Atoms.h"
-#include "lld/Core/Parallel.h"
-#include "lld/Core/Pass.h"
-#include <algorithm>
-
-namespace lld {
-namespace pecoff {
-
-static bool compare(const DefinedAtom *lhs, const DefinedAtom *rhs) {
- bool lhsCustom = (lhs->sectionChoice() == DefinedAtom::sectionCustomRequired);
- bool rhsCustom = (rhs->sectionChoice() == DefinedAtom::sectionCustomRequired);
- if (lhsCustom && rhsCustom) {
- int cmp = lhs->customSectionName().compare(rhs->customSectionName());
- if (cmp != 0)
- return cmp < 0;
- return DefinedAtom::compareByPosition(lhs, rhs);
- }
- if (lhsCustom && !rhsCustom)
- return true;
- if (!lhsCustom && rhsCustom)
- return false;
- return DefinedAtom::compareByPosition(lhs, rhs);
-}
-
-class OrderPass : public lld::Pass {
-public:
- void perform(std::unique_ptr<MutableFile> &file) override {
- MutableFile::DefinedAtomRange defined = file->definedAtoms();
- parallel_sort(defined.begin(), defined.end(), compare);
- }
-};
-
-} // namespace pecoff
-} // namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/PECOFF/PDBPass.h b/lib/ReaderWriter/PECOFF/PDBPass.h
deleted file mode 100644
index 0efa054db823..000000000000
--- a/lib/ReaderWriter/PECOFF/PDBPass.h
+++ /dev/null
@@ -1,43 +0,0 @@
-//===- lib/ReaderWriter/PECOFF/PDBPass.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_PE_COFF_PDB_PASS_H
-#define LLD_READER_WRITER_PE_COFF_PDB_PASS_H
-
-#include "lld/Core/Pass.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/Process.h"
-
-namespace lld {
-namespace pecoff {
-
-class PDBPass : public lld::Pass {
-public:
- PDBPass(PECOFFLinkingContext &ctx) : _ctx(ctx) {}
-
- void perform(std::unique_ptr<MutableFile> &file) override {
- if (_ctx.getDebug())
- touch(_ctx.getPDBFilePath());
- }
-
-private:
- void touch(StringRef path) {
- int fd;
- if (llvm::sys::fs::openFileForWrite(path, fd, llvm::sys::fs::F_Append))
- llvm::report_fatal_error("failed to create a PDB file");
- llvm::sys::Process::SafelyCloseFileDescriptor(fd);
- }
-
- PECOFFLinkingContext &_ctx;
-};
-
-} // namespace pecoff
-} // namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp b/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp
deleted file mode 100644
index 6a657e33541d..000000000000
--- a/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp
+++ /dev/null
@@ -1,352 +0,0 @@
-//===- lib/ReaderWriter/PECOFF/PECOFFLinkingContext.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 "EdataPass.h"
-#include "IdataPass.h"
-#include "InferSubsystemPass.h"
-#include "LinkerGeneratedSymbolFile.h"
-#include "LoadConfigPass.h"
-#include "OrderPass.h"
-#include "PDBPass.h"
-#include "lld/Core/PassManager.h"
-#include "lld/Core/Reader.h"
-#include "lld/Core/Simple.h"
-#include "lld/Core/Writer.h"
-#include "lld/ReaderWriter/PECOFFLinkingContext.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/Support/Allocator.h"
-#include "llvm/Support/Path.h"
-#include <bitset>
-#include <climits>
-#include <set>
-
-namespace lld {
-
-bool PECOFFLinkingContext::validateImpl(raw_ostream &diagnostics) {
- if (_stackReserve < _stackCommit) {
- diagnostics << "Invalid stack size: reserve size must be equal to or "
- << "greater than commit size, but got " << _stackCommit
- << " and " << _stackReserve << ".\n";
- return false;
- }
-
- if (_heapReserve < _heapCommit) {
- diagnostics << "Invalid heap size: reserve size must be equal to or "
- << "greater than commit size, but got " << _heapCommit
- << " and " << _heapReserve << ".\n";
- return false;
- }
-
- // It's an error if the base address is not multiple of 64K.
- if (getBaseAddress() & 0xffff) {
- diagnostics << "Base address have to be multiple of 64K, but got "
- << getBaseAddress() << "\n";
- return false;
- }
-
- // Specifing /noentry without /dll is an error.
- if (!hasEntry() && !isDll()) {
- diagnostics << "/noentry must be specified with /dll\n";
- return false;
- }
-
- // Check for duplicate export ordinals.
- std::set<int> exports;
- for (const PECOFFLinkingContext::ExportDesc &desc : getDllExports()) {
- if (desc.ordinal == -1)
- continue;
- if (exports.count(desc.ordinal) == 1) {
- diagnostics << "Duplicate export ordinals: " << desc.ordinal << "\n";
- return false;
- }
- exports.insert(desc.ordinal);
- }
-
- // Check for /align.
- std::bitset<64> alignment(_sectionDefaultAlignment);
- if (alignment.count() != 1) {
- diagnostics << "Section alignment must be a power of 2, but got "
- << _sectionDefaultAlignment << "\n";
- return false;
- }
-
- _writer = createWriterPECOFF(*this);
- return true;
-}
-
-const std::set<std::string> &PECOFFLinkingContext::definedSymbols() {
- std::lock_guard<std::recursive_mutex> lock(_mutex);
- for (std::unique_ptr<Node> &node : getNodes()) {
- if (_seen.count(node.get()) > 0)
- continue;
- FileNode *fnode = dyn_cast<FileNode>(node.get());
- if (!fnode)
- continue;
- File *file = fnode->getFile();
- if (file->parse())
- continue;
- if (auto *archive = dyn_cast<ArchiveLibraryFile>(file)) {
- for (const std::string &sym : archive->getDefinedSymbols())
- _definedSyms.insert(sym);
- continue;
- }
- for (const DefinedAtom *atom : file->defined())
- if (!atom->name().empty())
- _definedSyms.insert(atom->name());
- }
- return _definedSyms;
-}
-
-std::unique_ptr<File> PECOFFLinkingContext::createEntrySymbolFile() const {
- return LinkingContext::createEntrySymbolFile("<command line option /entry>");
-}
-
-std::unique_ptr<File> PECOFFLinkingContext::createUndefinedSymbolFile() const {
- return LinkingContext::createUndefinedSymbolFile(
- "<command line option /include>");
-}
-
-static int getGroupStartPos(std::vector<std::unique_ptr<Node>> &nodes) {
- for (int i = 0, e = nodes.size(); i < e; ++i)
- if (GroupEnd *group = dyn_cast<GroupEnd>(nodes[i].get()))
- return i - group->getSize();
- llvm::report_fatal_error("internal error");
-}
-
-void PECOFFLinkingContext::addLibraryFile(std::unique_ptr<FileNode> file) {
- GroupEnd *currentGroupEnd;
- int pos = -1;
- std::vector<std::unique_ptr<Node>> &elements = getNodes();
- for (int i = 0, e = elements.size(); i < e; ++i) {
- if ((currentGroupEnd = dyn_cast<GroupEnd>(elements[i].get()))) {
- pos = i;
- break;
- }
- }
- assert(pos >= 0);
- elements.insert(elements.begin() + pos, std::move(file));
- elements[pos + 1] = llvm::make_unique<GroupEnd>(
- currentGroupEnd->getSize() + 1);
-}
-
-bool PECOFFLinkingContext::createImplicitFiles(
- std::vector<std::unique_ptr<File>> &) {
- std::vector<std::unique_ptr<Node>> &members = getNodes();
-
- // Create a file for the entry point function.
- std::unique_ptr<FileNode> entry(new FileNode(
- llvm::make_unique<pecoff::EntryPointFile>(*this)));
- members.insert(members.begin() + getGroupStartPos(members), std::move(entry));
-
- // Create a file for __ImageBase.
- std::unique_ptr<FileNode> fileNode(new FileNode(
- llvm::make_unique<pecoff::LinkerGeneratedSymbolFile>(*this)));
- members.push_back(std::move(fileNode));
-
- // Create a file for _imp_ symbols.
- std::unique_ptr<FileNode> impFileNode(new FileNode(
- llvm::make_unique<pecoff::LocallyImportedSymbolFile>(*this)));
- members.push_back(std::move(impFileNode));
-
- // Create a file for dllexported symbols.
- std::unique_ptr<FileNode> exportNode(new FileNode(
- llvm::make_unique<pecoff::ExportedSymbolRenameFile>(*this)));
- addLibraryFile(std::move(exportNode));
-
- return true;
-}
-
-/// Returns the section name in the resulting executable.
-///
-/// Sections in object files are usually output to the executable with the same
-/// name, but you can rename by command line option. /merge:from=to makes the
-/// linker to combine "from" section contents to "to" section in the
-/// executable. We have a mapping for the renaming. This method looks up the
-/// table and returns a new section name if renamed.
-StringRef
-PECOFFLinkingContext::getOutputSectionName(StringRef sectionName) const {
- auto it = _renamedSections.find(sectionName);
- if (it == _renamedSections.end())
- return sectionName;
- return getOutputSectionName(it->second);
-}
-
-/// Adds a mapping to the section renaming table. This method will be used for
-/// /merge command line option.
-bool PECOFFLinkingContext::addSectionRenaming(raw_ostream &diagnostics,
- StringRef from, StringRef to) {
- auto it = _renamedSections.find(from);
- if (it != _renamedSections.end()) {
- if (it->second == to)
- // There's already the same mapping.
- return true;
- diagnostics << "Section \"" << from << "\" is already mapped to \""
- << it->second << ", so it cannot be mapped to \"" << to << "\".";
- return true;
- }
-
- // Add a mapping, and check if there's no cycle in the renaming mapping. The
- // cycle detection algorithm we use here is naive, but that's OK because the
- // number of mapping is usually less than 10.
- _renamedSections[from] = to;
- for (auto elem : _renamedSections) {
- StringRef sectionName = elem.first;
- std::set<StringRef> visited;
- visited.insert(sectionName);
- for (;;) {
- auto pos = _renamedSections.find(sectionName);
- if (pos == _renamedSections.end())
- break;
- if (visited.count(pos->second)) {
- diagnostics << "/merge:" << from << "=" << to << " makes a cycle";
- return false;
- }
- sectionName = pos->second;
- visited.insert(sectionName);
- }
- }
- return true;
-}
-
-/// Try to find the input library file from the search paths and append it to
-/// the input file list. Returns true if the library file is found.
-StringRef PECOFFLinkingContext::searchLibraryFile(StringRef filename) const {
- // Current directory always takes precedence over the search paths.
- if (llvm::sys::path::is_absolute(filename) || llvm::sys::fs::exists(filename))
- return filename;
- // Iterate over the search paths.
- for (StringRef dir : _inputSearchPaths) {
- SmallString<128> path = dir;
- llvm::sys::path::append(path, filename);
- if (llvm::sys::fs::exists(path.str()))
- return allocate(path.str());
- }
- return filename;
-}
-
-/// Returns the decorated name of the given symbol name. On 32-bit x86, it
-/// adds "_" at the beginning of the string. On other architectures, the
-/// return value is the same as the argument.
-StringRef PECOFFLinkingContext::decorateSymbol(StringRef name) const {
- if (_machineType != llvm::COFF::IMAGE_FILE_MACHINE_I386)
- return name;
- std::string str = "_";
- str.append(name);
- return allocate(str);
-}
-
-StringRef PECOFFLinkingContext::undecorateSymbol(StringRef name) const {
- if (_machineType != llvm::COFF::IMAGE_FILE_MACHINE_I386)
- return name;
- if (!name.startswith("_"))
- return name;
- return name.substr(1);
-}
-
-uint64_t PECOFFLinkingContext::getBaseAddress() const {
- if (_baseAddress == invalidBaseAddress)
- return is64Bit() ? pe32PlusDefaultBaseAddress : pe32DefaultBaseAddress;
- return _baseAddress;
-}
-
-Writer &PECOFFLinkingContext::writer() const { return *_writer; }
-
-void PECOFFLinkingContext::setSectionSetMask(StringRef sectionName,
- uint32_t newFlags) {
- _sectionSetMask[sectionName] |= newFlags;
- _sectionClearMask[sectionName] &= ~newFlags;
- const uint32_t rwx = (llvm::COFF::IMAGE_SCN_MEM_READ |
- llvm::COFF::IMAGE_SCN_MEM_WRITE |
- llvm::COFF::IMAGE_SCN_MEM_EXECUTE);
- if (newFlags & rwx)
- _sectionClearMask[sectionName] |= ~_sectionSetMask[sectionName] & rwx;
- assert((_sectionSetMask[sectionName] & _sectionClearMask[sectionName]) == 0);
-}
-
-void PECOFFLinkingContext::setSectionClearMask(StringRef sectionName,
- uint32_t newFlags) {
- _sectionClearMask[sectionName] |= newFlags;
- _sectionSetMask[sectionName] &= ~newFlags;
- assert((_sectionSetMask[sectionName] & _sectionClearMask[sectionName]) == 0);
-}
-
-uint32_t PECOFFLinkingContext::getSectionAttributes(StringRef sectionName,
- uint32_t flags) const {
- auto si = _sectionSetMask.find(sectionName);
- uint32_t setMask = (si == _sectionSetMask.end()) ? 0 : si->second;
- auto ci = _sectionClearMask.find(sectionName);
- uint32_t clearMask = (ci == _sectionClearMask.end()) ? 0 : ci->second;
- return (flags | setMask) & ~clearMask;
-}
-
-// Returns true if two export descriptors are the same.
-static bool sameExportDesc(const PECOFFLinkingContext::ExportDesc &a,
- const PECOFFLinkingContext::ExportDesc &b) {
- return a.ordinal == b.ordinal && a.ordinal == b.ordinal &&
- a.noname == b.noname && a.isData == b.isData;
-}
-
-void PECOFFLinkingContext::addDllExport(ExportDesc &desc) {
- addInitialUndefinedSymbol(allocate(desc.name));
-
- // MSVC link.exe silently drops characters after the first atsign.
- // For example, /export:foo@4=bar is equivalent to /export:foo=bar.
- // We do the same thing for compatibility.
- if (!desc.externalName.empty()) {
- StringRef s(desc.externalName);
- size_t pos = s.find('@');
- if (pos != s.npos)
- desc.externalName = s.substr(0, pos);
- }
-
- // Scan the vector to look for existing entry. It's not very fast,
- // but because the number of exported symbol is usually not that
- // much, it should be okay.
- for (ExportDesc &e : _dllExports) {
- if (e.name != desc.name)
- continue;
- if (!sameExportDesc(e, desc))
- llvm::errs() << "Export symbol '" << desc.name
- << "' specified more than once.\n";
- return;
- }
- _dllExports.push_back(desc);
-}
-
-static std::string replaceExtension(StringRef path, StringRef ext) {
- SmallString<128> ss = path;
- llvm::sys::path::replace_extension(ss, ext);
- return ss.str();
-}
-
-std::string PECOFFLinkingContext::getOutputImportLibraryPath() const {
- if (!_implib.empty())
- return _implib;
- return replaceExtension(outputPath(), ".lib");
-}
-
-std::string PECOFFLinkingContext::getPDBFilePath() const {
- assert(_debug);
- if (!_pdbFilePath.empty())
- return _pdbFilePath;
- return replaceExtension(outputPath(), ".pdb");
-}
-
-void PECOFFLinkingContext::addPasses(PassManager &pm) {
- pm.add(llvm::make_unique<pecoff::PDBPass>(*this));
- pm.add(llvm::make_unique<pecoff::EdataPass>(*this));
- pm.add(llvm::make_unique<pecoff::IdataPass>(*this));
- pm.add(llvm::make_unique<pecoff::OrderPass>());
- pm.add(llvm::make_unique<pecoff::LoadConfigPass>(*this));
- pm.add(llvm::make_unique<pecoff::InferSubsystemPass>(*this));
-}
-
-} // end namespace lld
diff --git a/lib/ReaderWriter/PECOFF/Pass.cpp b/lib/ReaderWriter/PECOFF/Pass.cpp
deleted file mode 100644
index ed731984e378..000000000000
--- a/lib/ReaderWriter/PECOFF/Pass.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-//===- lib/ReaderWriter/PECOFF/Pass.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 "Pass.h"
-#include "lld/Core/File.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/Support/COFF.h"
-
-namespace lld {
-namespace pecoff {
-
-static void addReloc(COFFBaseDefinedAtom *atom, const Atom *target,
- size_t offsetInAtom, Reference::KindArch arch,
- Reference::KindValue relType) {
- atom->addReference(llvm::make_unique<SimpleReference>(
- Reference::KindNamespace::COFF, arch, relType, offsetInAtom, target, 0));
-}
-
-void addDir64Reloc(COFFBaseDefinedAtom *atom, const Atom *target,
- llvm::COFF::MachineTypes machine, size_t offsetInAtom) {
- switch (machine) {
- case llvm::COFF::IMAGE_FILE_MACHINE_I386:
- addReloc(atom, target, offsetInAtom, Reference::KindArch::x86,
- llvm::COFF::IMAGE_REL_I386_DIR32);
- return;
- case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
- addReloc(atom, target, offsetInAtom, Reference::KindArch::x86_64,
- llvm::COFF::IMAGE_REL_AMD64_ADDR64);
- return;
- default:
- llvm_unreachable("unsupported machine type");
- }
-}
-
-void addDir32Reloc(COFFBaseDefinedAtom *atom, const Atom *target,
- llvm::COFF::MachineTypes machine, size_t offsetInAtom) {
- switch (machine) {
- case llvm::COFF::IMAGE_FILE_MACHINE_I386:
- addReloc(atom, target, offsetInAtom, Reference::KindArch::x86,
- llvm::COFF::IMAGE_REL_I386_DIR32);
- return;
- case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
- addReloc(atom, target, offsetInAtom, Reference::KindArch::x86_64,
- llvm::COFF::IMAGE_REL_AMD64_ADDR32);
- return;
- default:
- llvm_unreachable("unsupported machine type");
- }
-}
-
-void addDir32NBReloc(COFFBaseDefinedAtom *atom, const Atom *target,
- llvm::COFF::MachineTypes machine, size_t offsetInAtom) {
- switch (machine) {
- case llvm::COFF::IMAGE_FILE_MACHINE_I386:
- addReloc(atom, target, offsetInAtom, Reference::KindArch::x86,
- llvm::COFF::IMAGE_REL_I386_DIR32NB);
- return;
- case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
- addReloc(atom, target, offsetInAtom, Reference::KindArch::x86_64,
- llvm::COFF::IMAGE_REL_AMD64_ADDR32NB);
- return;
- case llvm::COFF::IMAGE_FILE_MACHINE_ARMNT:
- addReloc(atom, target, offsetInAtom, Reference::KindArch::ARM,
- llvm::COFF::IMAGE_REL_ARM_ADDR32NB);
- return;
- default:
- llvm_unreachable("unsupported machine type");
- }
-}
-
-void addRel32Reloc(COFFBaseDefinedAtom *atom, const Atom *target,
- llvm::COFF::MachineTypes machine, size_t offsetInAtom) {
- switch (machine) {
- case llvm::COFF::IMAGE_FILE_MACHINE_I386:
- addReloc(atom, target, offsetInAtom, Reference::KindArch::x86,
- llvm::COFF::IMAGE_REL_I386_REL32);
- return;
- case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
- addReloc(atom, target, offsetInAtom, Reference::KindArch::x86_64,
- llvm::COFF::IMAGE_REL_AMD64_REL32);
- return;
- default:
- llvm_unreachable("unsupported machine type");
- }
-}
-
-} // end namespace pecoff
-} // end namespace lld
diff --git a/lib/ReaderWriter/PECOFF/Pass.h b/lib/ReaderWriter/PECOFF/Pass.h
deleted file mode 100644
index 22466f77859e..000000000000
--- a/lib/ReaderWriter/PECOFF/Pass.h
+++ /dev/null
@@ -1,34 +0,0 @@
-//===- lib/ReaderWriter/PECOFF/Pass.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_PE_COFF_PASS_H
-#define LLD_READER_WRITER_PE_COFF_PASS_H
-
-#include "Atoms.h"
-#include "llvm/Support/COFF.h"
-
-namespace lld {
-namespace pecoff {
-
-void addDir64Reloc(COFFBaseDefinedAtom *atom, const Atom *target,
- llvm::COFF::MachineTypes machine, size_t offsetInAtom);
-
-void addDir32Reloc(COFFBaseDefinedAtom *atom, const Atom *target,
- llvm::COFF::MachineTypes machine, size_t offsetInAtom);
-
-void addDir32NBReloc(COFFBaseDefinedAtom *atom, const Atom *target,
- llvm::COFF::MachineTypes machine, size_t offsetInAtom);
-
-void addRel32Reloc(COFFBaseDefinedAtom *atom, const Atom *target,
- llvm::COFF::MachineTypes machine, size_t offsetInAtom);
-
-} // namespace pecoff
-} // namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp b/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp
deleted file mode 100644
index f060bd8dc0bc..000000000000
--- a/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp
+++ /dev/null
@@ -1,1140 +0,0 @@
-//===- lib/ReaderWriter/PECOFF/ReaderCOFF.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 "lld/Core/Alias.h"
-#include "lld/Core/File.h"
-#include "lld/Core/Reader.h"
-#include "lld/Driver/Driver.h"
-#include "lld/ReaderWriter/PECOFFLinkingContext.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/Object/COFF.h"
-#include "llvm/Support/Casting.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/Endian.h"
-#include "llvm/Support/Errc.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/FileOutputBuffer.h"
-#include "llvm/Support/FileUtilities.h"
-#include "llvm/Support/Memory.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/Program.h"
-#include "llvm/Support/raw_ostream.h"
-#include <algorithm>
-#include <map>
-#include <mutex>
-#include <set>
-#include <system_error>
-#include <vector>
-
-#define DEBUG_TYPE "ReaderCOFF"
-
-using lld::pecoff::COFFBSSAtom;
-using lld::pecoff::COFFDefinedAtom;
-using lld::pecoff::COFFDefinedFileAtom;
-using lld::pecoff::COFFUndefinedAtom;
-using llvm::object::coff_aux_section_definition;
-using llvm::object::coff_aux_weak_external;
-using llvm::object::coff_relocation;
-using llvm::object::coff_section;
-using llvm::object::coff_symbol;
-using llvm::support::ulittle32_t;
-
-using namespace lld;
-
-namespace {
-
-class BumpPtrStringSaver : public llvm::cl::StringSaver {
-public:
- const char *SaveString(const char *str) override {
- size_t len = strlen(str);
- std::lock_guard<std::mutex> lock(_allocMutex);
- char *copy = _alloc.Allocate<char>(len + 1);
- memcpy(copy, str, len + 1);
- return copy;
- }
-
-private:
- llvm::BumpPtrAllocator _alloc;
- std::mutex _allocMutex;
-};
-
-class FileCOFF : public File {
-private:
- typedef std::vector<llvm::object::COFFSymbolRef> SymbolVectorT;
- typedef std::map<const coff_section *, SymbolVectorT> SectionToSymbolsT;
-
-public:
- FileCOFF(std::unique_ptr<MemoryBuffer> mb, PECOFFLinkingContext &ctx)
- : File(mb->getBufferIdentifier(), kindObject), _mb(std::move(mb)),
- _compatibleWithSEH(false), _ordinal(1),
- _machineType(llvm::COFF::MT_Invalid), _ctx(ctx) {}
-
- std::error_code doParse() override;
- bool isCompatibleWithSEH() const { return _compatibleWithSEH; }
- llvm::COFF::MachineTypes getMachineType() { return _machineType; }
-
- const atom_collection<DefinedAtom> &defined() const override {
- return _definedAtoms;
- }
-
- const atom_collection<UndefinedAtom> &undefined() const override {
- return _undefinedAtoms;
- }
-
- const atom_collection<SharedLibraryAtom> &sharedLibrary() const override {
- return _sharedLibraryAtoms;
- }
-
- const atom_collection<AbsoluteAtom> &absolute() const override {
- return _absoluteAtoms;
- }
-
- void beforeLink() override;
-
- void addUndefinedSymbol(StringRef sym) {
- _undefinedAtoms._atoms.push_back(new (_alloc) COFFUndefinedAtom(*this, sym));
- }
-
- AliasAtom *createAlias(StringRef name, const DefinedAtom *target, int cnt);
- void createAlternateNameAtoms();
- std::error_code parseDirectiveSection(StringRef directives);
-
- mutable llvm::BumpPtrAllocator _alloc;
-
-private:
- std::error_code readSymbolTable(SymbolVectorT &result);
-
- void createAbsoluteAtoms(const SymbolVectorT &symbols,
- std::vector<const AbsoluteAtom *> &result);
-
- std::error_code
- createUndefinedAtoms(const SymbolVectorT &symbols,
- std::vector<const UndefinedAtom *> &result);
-
- std::error_code
- createDefinedSymbols(const SymbolVectorT &symbols,
- std::vector<const DefinedAtom *> &result);
-
- std::error_code cacheSectionAttributes();
- std::error_code maybeCreateSXDataAtoms();
-
- std::error_code
- AtomizeDefinedSymbolsInSection(const coff_section *section,
- SymbolVectorT &symbols,
- std::vector<COFFDefinedFileAtom *> &atoms);
-
- std::error_code
- AtomizeDefinedSymbols(SectionToSymbolsT &definedSymbols,
- std::vector<const DefinedAtom *> &definedAtoms);
-
- std::error_code findAtomAt(const coff_section *section,
- uint32_t targetAddress,
- COFFDefinedFileAtom *&result,
- uint32_t &offsetInAtom);
-
- std::error_code getAtomBySymbolIndex(uint32_t index, Atom *&ret);
-
- std::error_code
- addRelocationReference(const coff_relocation *rel,
- const coff_section *section);
-
- std::error_code getSectionContents(StringRef sectionName,
- ArrayRef<uint8_t> &result);
- std::error_code getReferenceArch(Reference::KindArch &result);
- std::error_code addRelocationReferenceToAtoms();
- std::error_code findSection(StringRef name, const coff_section *&result);
- StringRef ArrayRefToString(ArrayRef<uint8_t> array);
- uint64_t getNextOrdinal();
-
- std::unique_ptr<const llvm::object::COFFObjectFile> _obj;
- std::unique_ptr<MemoryBuffer> _mb;
- atom_collection_vector<DefinedAtom> _definedAtoms;
- atom_collection_vector<UndefinedAtom> _undefinedAtoms;
- atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
- atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
-
- // The target type of the object.
- Reference::KindArch _referenceArch;
-
- // True if the object has "@feat.00" symbol.
- bool _compatibleWithSEH;
-
- // A map from symbol to its name. All symbols should be in this map except
- // unnamed ones.
- std::map<llvm::object::COFFSymbolRef, StringRef> _symbolName;
-
- // A map from symbol to its resultant atom.
- std::map<llvm::object::COFFSymbolRef, Atom *> _symbolAtom;
-
- // A map from symbol to its aux symbol.
- std::map<llvm::object::COFFSymbolRef, llvm::object::COFFSymbolRef> _auxSymbol;
-
- // A map from section to its atoms.
- std::map<const coff_section *, std::vector<COFFDefinedFileAtom *>>
- _sectionAtoms;
-
- // A set of COMDAT sections.
- std::set<const coff_section *> _comdatSections;
-
- // A map to get whether the section allows its contents to be merged or not.
- std::map<const coff_section *, DefinedAtom::Merge> _merge;
-
- // COMDAT associative sections
- std::multimap<const coff_section *, const coff_section *> _association;
-
- // A sorted map to find an atom from a section and an offset within
- // the section.
- std::map<const coff_section *, std::multimap<uint32_t, COFFDefinedAtom *>>
- _definedAtomLocations;
-
- uint64_t _ordinal;
- llvm::COFF::MachineTypes _machineType;
- PECOFFLinkingContext &_ctx;
- mutable BumpPtrStringSaver _stringSaver;
-};
-
-// Converts the COFF symbol attribute to the LLD's atom attribute.
-Atom::Scope getScope(llvm::object::COFFSymbolRef symbol) {
- switch (symbol.getStorageClass()) {
- case llvm::COFF::IMAGE_SYM_CLASS_EXTERNAL:
- return Atom::scopeGlobal;
- case llvm::COFF::IMAGE_SYM_CLASS_STATIC:
- case llvm::COFF::IMAGE_SYM_CLASS_LABEL:
- return Atom::scopeTranslationUnit;
- }
- llvm_unreachable("Unknown scope");
-}
-
-DefinedAtom::ContentType getContentType(const coff_section *section) {
- if (section->Characteristics & llvm::COFF::IMAGE_SCN_CNT_CODE)
- return DefinedAtom::typeCode;
- if (section->Characteristics & llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA)
- return DefinedAtom::typeData;
- if (section->Characteristics & llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)
- return DefinedAtom::typeZeroFill;
- return DefinedAtom::typeUnknown;
-}
-
-DefinedAtom::ContentPermissions getPermissions(const coff_section *section) {
- if (section->Characteristics & llvm::COFF::IMAGE_SCN_MEM_READ &&
- section->Characteristics & llvm::COFF::IMAGE_SCN_MEM_WRITE)
- return DefinedAtom::permRW_;
- if (section->Characteristics & llvm::COFF::IMAGE_SCN_MEM_READ &&
- section->Characteristics & llvm::COFF::IMAGE_SCN_MEM_EXECUTE)
- return DefinedAtom::permR_X;
- if (section->Characteristics & llvm::COFF::IMAGE_SCN_MEM_READ)
- return DefinedAtom::permR__;
- return DefinedAtom::perm___;
-}
-
-/// Returns the alignment of the section. The contents of the section must be
-/// aligned by this value in the resulting executable/DLL.
-DefinedAtom::Alignment getAlignment(const coff_section *section) {
- if (section->Characteristics & llvm::COFF::IMAGE_SCN_TYPE_NO_PAD)
- return DefinedAtom::Alignment(0);
-
- // Bit [20:24] contains section alignment information. We need to decrease
- // the value stored by 1 in order to get the real exponent (e.g, ALIGN_1BYTE
- // is 0x00100000, but the exponent should be 0)
- uint32_t characteristics = (section->Characteristics >> 20) & 0xf;
-
- // If all bits are off, we treat it as if ALIGN_1BYTE was on. The PE/COFF spec
- // does not say anything about this case, but CVTRES.EXE does not set any bit
- // in characteristics[20:24], and its output is intended to be copied to .rsrc
- // section with no padding, so I think doing this is the right thing.
- if (characteristics == 0)
- return DefinedAtom::Alignment(0);
-
- uint32_t powerOf2 = characteristics - 1;
- return DefinedAtom::Alignment(powerOf2);
-}
-
-DefinedAtom::Merge getMerge(const coff_aux_section_definition *auxsym) {
- switch (auxsym->Selection) {
- case llvm::COFF::IMAGE_COMDAT_SELECT_NODUPLICATES:
- return DefinedAtom::mergeNo;
- case llvm::COFF::IMAGE_COMDAT_SELECT_ANY:
- return DefinedAtom::mergeAsWeakAndAddressUsed;
- case llvm::COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH:
- // TODO: This mapping is wrong. Fix it.
- return DefinedAtom::mergeByContent;
- case llvm::COFF::IMAGE_COMDAT_SELECT_SAME_SIZE:
- return DefinedAtom::mergeSameNameAndSize;
- case llvm::COFF::IMAGE_COMDAT_SELECT_LARGEST:
- return DefinedAtom::mergeByLargestSection;
- case llvm::COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE:
- case llvm::COFF::IMAGE_COMDAT_SELECT_NEWEST:
- // FIXME: These attributes has more complicated semantics than the regular
- // weak symbol. These are mapped to mergeAsWeakAndAddressUsed for now
- // because the core linker does not support them yet. We eventually have
- // to implement them for full COFF support.
- return DefinedAtom::mergeAsWeakAndAddressUsed;
- default:
- llvm_unreachable("Unknown merge type");
- }
-}
-
-StringRef getMachineName(llvm::COFF::MachineTypes Type) {
- switch (Type) {
- default: llvm_unreachable("unsupported machine type");
- case llvm::COFF::IMAGE_FILE_MACHINE_ARMNT:
- return "ARM";
- case llvm::COFF::IMAGE_FILE_MACHINE_I386:
- return "X86";
- case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
- return "X64";
- }
-}
-
-std::error_code FileCOFF::doParse() {
- auto binaryOrErr = llvm::object::createBinary(_mb->getMemBufferRef());
- if (std::error_code ec = binaryOrErr.getError())
- return ec;
- std::unique_ptr<llvm::object::Binary> bin = std::move(binaryOrErr.get());
-
- _obj.reset(dyn_cast<const llvm::object::COFFObjectFile>(bin.get()));
- if (!_obj)
- return make_error_code(llvm::object::object_error::invalid_file_type);
- bin.release();
-
- _machineType = static_cast<llvm::COFF::MachineTypes>(_obj->getMachine());
-
- if (getMachineType() != llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN &&
- getMachineType() != _ctx.getMachineType()) {
- llvm::errs() << "module machine type '"
- << getMachineName(getMachineType())
- << "' conflicts with target machine type '"
- << getMachineName(_ctx.getMachineType()) << "'\n";
- return NativeReaderError::conflicting_target_machine;
- }
-
- if (std::error_code ec = getReferenceArch(_referenceArch))
- return ec;
-
- // Read the symbol table and atomize them if possible. Defined atoms
- // cannot be atomized in one pass, so they will be not be atomized but
- // added to symbolToAtom.
- SymbolVectorT symbols;
- if (std::error_code ec = readSymbolTable(symbols))
- return ec;
-
- createAbsoluteAtoms(symbols, _absoluteAtoms._atoms);
- if (std::error_code ec =
- createUndefinedAtoms(symbols, _undefinedAtoms._atoms))
- return ec;
- if (std::error_code ec = createDefinedSymbols(symbols, _definedAtoms._atoms))
- return ec;
- if (std::error_code ec = addRelocationReferenceToAtoms())
- return ec;
- if (std::error_code ec = maybeCreateSXDataAtoms())
- return ec;
-
- // Check for /SAFESEH.
- if (_ctx.requireSEH() && !isCompatibleWithSEH()) {
- llvm::errs() << "/SAFESEH is specified, but "
- << _mb->getBufferIdentifier()
- << " is not compatible with SEH.\n";
- return llvm::object::object_error::parse_failed;
- }
- return std::error_code();
-}
-
-void FileCOFF::beforeLink() {
- // Acquire the mutex to mutate _ctx.
- std::lock_guard<std::recursive_mutex> lock(_ctx.getMutex());
- std::set<StringRef> undefSyms;
-
- // Interpret .drectve section if the section has contents.
- ArrayRef<uint8_t> directives;
- if (getSectionContents(".drectve", directives))
- return;
- if (!directives.empty()) {
- std::set<StringRef> orig;
- for (StringRef sym : _ctx.initialUndefinedSymbols())
- orig.insert(sym);
- if (parseDirectiveSection(ArrayRefToString(directives)))
- return;
- for (StringRef sym : _ctx.initialUndefinedSymbols())
- if (orig.count(sym) == 0)
- undefSyms.insert(sym);
- }
-
- // Add /INCLUDE'ed symbols to the file as if they existed in the
- // file as undefined symbols.
- for (StringRef sym : undefSyms) {
- addUndefinedSymbol(sym);
- _ctx.addDeadStripRoot(sym);
- }
-
- // One can define alias symbols using /alternatename:<sym>=<sym> option.
- // The mapping for /alternatename is in the context object. This helper
- // function iterate over defined atoms and create alias atoms if needed.
- createAlternateNameAtoms();
-
- // In order to emit SEH table, all input files need to be compatible with
- // SEH. Disable SEH if the file being read is not compatible.
- if (!isCompatibleWithSEH())
- _ctx.setSafeSEH(false);
-}
-
-/// Iterate over the symbol table to retrieve all symbols.
-std::error_code
-FileCOFF::readSymbolTable(SymbolVectorT &result) {
- for (uint32_t i = 0, e = _obj->getNumberOfSymbols(); i != e; ++i) {
- // Retrieve the symbol.
- ErrorOr<llvm::object::COFFSymbolRef> sym = _obj->getSymbol(i);
- StringRef name;
- if (std::error_code ec = sym.getError())
- return ec;
- if (sym->getSectionNumber() == llvm::COFF::IMAGE_SYM_DEBUG)
- goto next;
- result.push_back(*sym);
-
- if (std::error_code ec = _obj->getSymbolName(*sym, name))
- return ec;
-
- // Existence of the symbol @feat.00 indicates that object file is compatible
- // with Safe Exception Handling.
- if (name == "@feat.00") {
- _compatibleWithSEH = true;
- goto next;
- }
-
- // Cache the name.
- _symbolName[*sym] = name;
-
- // Symbol may be followed by auxiliary symbol table records. The aux
- // record can be in any format, but the size is always the same as the
- // regular symbol. The aux record supplies additional information for the
- // standard symbol. We do not interpret the aux record here, but just
- // store it to _auxSymbol.
- if (sym->getNumberOfAuxSymbols() > 0) {
- ErrorOr<llvm::object::COFFSymbolRef> aux = _obj->getSymbol(i + 1);
- if (std::error_code ec = aux.getError())
- return ec;
- _auxSymbol[*sym] = *aux;
- }
- next:
- i += sym->getNumberOfAuxSymbols();
- }
- return std::error_code();
-}
-
-/// Create atoms for the absolute symbols.
-void FileCOFF::createAbsoluteAtoms(const SymbolVectorT &symbols,
- std::vector<const AbsoluteAtom *> &result) {
- for (llvm::object::COFFSymbolRef sym : symbols) {
- if (sym.getSectionNumber() != llvm::COFF::IMAGE_SYM_ABSOLUTE)
- continue;
- auto *atom = new (_alloc) SimpleAbsoluteAtom(*this, _symbolName[sym],
- getScope(sym), sym.getValue());
- result.push_back(atom);
- _symbolAtom[sym] = atom;
- }
-}
-
-/// Create atoms for the undefined symbols. This code is bit complicated
-/// because it supports "weak externals" mechanism of COFF. If an undefined
-/// symbol (sym1) has auxiliary data, the data contains a symbol table index
-/// at which the "second symbol" (sym2) for sym1 exists. If sym1 is resolved,
-/// it's linked normally. If not, sym1 is resolved as if it has sym2's
-/// name. This relationship between sym1 and sym2 is represented using
-/// fallback mechanism of undefined symbol.
-std::error_code
-FileCOFF::createUndefinedAtoms(const SymbolVectorT &symbols,
- std::vector<const UndefinedAtom *> &result) {
- std::map<llvm::object::COFFSymbolRef, llvm::object::COFFSymbolRef>
- weakExternal;
- std::set<llvm::object::COFFSymbolRef> fallback;
- for (llvm::object::COFFSymbolRef sym : symbols) {
- if (sym.getSectionNumber() != llvm::COFF::IMAGE_SYM_UNDEFINED)
- continue;
- // Create a mapping from sym1 to sym2, if the undefined symbol has
- // auxiliary data.
- auto iter = _auxSymbol.find(sym);
- if (iter == _auxSymbol.end())
- continue;
- const coff_aux_weak_external *aux =
- reinterpret_cast<const coff_aux_weak_external *>(
- iter->second.getRawPtr());
- ErrorOr<llvm::object::COFFSymbolRef> sym2 = _obj->getSymbol(aux->TagIndex);
- if (std::error_code ec = sym2.getError())
- return ec;
- weakExternal[sym] = *sym2;
- fallback.insert(*sym2);
- }
-
- // Create atoms for the undefined symbols.
- for (llvm::object::COFFSymbolRef sym : symbols) {
- if (sym.getSectionNumber() != llvm::COFF::IMAGE_SYM_UNDEFINED)
- continue;
- if (fallback.count(sym) > 0)
- continue;
-
- // If the symbol has sym2, create an undefiend atom for sym2, so that we
- // can pass it as a fallback atom.
- UndefinedAtom *fallback = nullptr;
- auto iter = weakExternal.find(sym);
- if (iter != weakExternal.end()) {
- llvm::object::COFFSymbolRef sym2 = iter->second;
- fallback = new (_alloc) COFFUndefinedAtom(*this, _symbolName[sym2]);
- _symbolAtom[sym2] = fallback;
- }
-
- // Create an atom for the symbol.
- auto *atom =
- new (_alloc) COFFUndefinedAtom(*this, _symbolName[sym], fallback);
- result.push_back(atom);
- _symbolAtom[sym] = atom;
- }
- return std::error_code();
-}
-
-/// Create atoms for the defined symbols. This pass is a bit complicated than
-/// the other two, because in order to create the atom for the defined symbol
-/// we need to know the adjacent symbols.
-std::error_code
-FileCOFF::createDefinedSymbols(const SymbolVectorT &symbols,
- std::vector<const DefinedAtom *> &result) {
- // A defined atom can be merged if its section attribute allows its contents
- // to be merged. In COFF, it's not very easy to get the section attribute
- // for the symbol, so scan all sections in advance and cache the attributes
- // for later use.
- if (std::error_code ec = cacheSectionAttributes())
- return ec;
-
- // Filter non-defined atoms, and group defined atoms by its section.
- SectionToSymbolsT definedSymbols;
- for (llvm::object::COFFSymbolRef sym : symbols) {
- // A symbol with section number 0 and non-zero value represents a common
- // symbol. The MS COFF spec did not give a definition of what the common
- // symbol is. We should probably follow ELF's definition shown below.
- //
- // - If one object file has a common symbol and another has a definition,
- // the common symbol is treated as an undefined reference.
- // - If there is no definition for a common symbol, the program linker
- // acts as though it saw a definition initialized to zero of the
- // appropriate size.
- // - Two object files may have common symbols of
- // different sizes, in which case the program linker will use the
- // largest size.
- //
- // FIXME: We are currently treating the common symbol as a normal
- // mergeable atom. Implement the above semantcis.
- if (sym.getSectionNumber() == llvm::COFF::IMAGE_SYM_UNDEFINED &&
- sym.getValue() > 0) {
- StringRef name = _symbolName[sym];
- uint32_t size = sym.getValue();
- auto *atom = new (_alloc)
- COFFBSSAtom(*this, name, getScope(sym), DefinedAtom::permRW_,
- DefinedAtom::mergeAsWeakAndAddressUsed, size, getNextOrdinal());
-
- // Common symbols should be aligned on natural boundaries with the maximum
- // of 32 byte. It's not documented anywhere, but it's what MSVC link.exe
- // seems to be doing.
- uint64_t alignment = std::min((uint64_t)32, llvm::NextPowerOf2(size));
- atom->setAlignment(
- DefinedAtom::Alignment(llvm::countTrailingZeros(alignment)));
- result.push_back(atom);
- continue;
- }
-
- // Skip if it's not for defined atom.
- if (sym.getSectionNumber() == llvm::COFF::IMAGE_SYM_DEBUG ||
- sym.getSectionNumber() == llvm::COFF::IMAGE_SYM_ABSOLUTE ||
- sym.getSectionNumber() == llvm::COFF::IMAGE_SYM_UNDEFINED)
- continue;
-
- const coff_section *sec;
- if (std::error_code ec = _obj->getSection(sym.getSectionNumber(), sec))
- return ec;
- assert(sec && "SectionIndex > 0, Sec must be non-null!");
-
- uint8_t sc = sym.getStorageClass();
- if (sc != llvm::COFF::IMAGE_SYM_CLASS_EXTERNAL &&
- sc != llvm::COFF::IMAGE_SYM_CLASS_STATIC &&
- sc != llvm::COFF::IMAGE_SYM_CLASS_FUNCTION &&
- sc != llvm::COFF::IMAGE_SYM_CLASS_LABEL) {
- llvm::errs() << "Unable to create atom for: " << _symbolName[sym] << " ("
- << static_cast<int>(sc) << ")\n";
- return llvm::object::object_error::parse_failed;
- }
-
- definedSymbols[sec].push_back(sym);
- }
-
- // Atomize the defined symbols.
- if (std::error_code ec = AtomizeDefinedSymbols(definedSymbols, result))
- return ec;
-
- return std::error_code();
-}
-
-// Cache the COMDAT attributes, which indicate whether the symbols in the
-// section can be merged or not.
-std::error_code FileCOFF::cacheSectionAttributes() {
- // The COMDAT section attribute is not an attribute of coff_section, but is
- // stored in the auxiliary symbol for the first symbol referring a COMDAT
- // section. It feels to me that it's unnecessarily complicated, but this is
- // how COFF works.
- for (auto i : _auxSymbol) {
- // Read a section from the file
- llvm::object::COFFSymbolRef sym = i.first;
- if (sym.getSectionNumber() == llvm::COFF::IMAGE_SYM_ABSOLUTE ||
- sym.getSectionNumber() == llvm::COFF::IMAGE_SYM_UNDEFINED)
- continue;
-
- const coff_section *sec;
- if (std::error_code ec = _obj->getSection(sym.getSectionNumber(), sec))
- return ec;
- const coff_aux_section_definition *aux =
- reinterpret_cast<const coff_aux_section_definition *>(
- i.second.getRawPtr());
-
- if (sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_COMDAT) {
- // Read aux symbol data.
- _comdatSections.insert(sec);
- _merge[sec] = getMerge(aux);
- }
-
- // Handle associative sections.
- if (aux->Selection == llvm::COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
- const coff_section *parent;
- if (std::error_code ec =
- _obj->getSection(aux->getNumber(sym.isBigObj()), parent))
- return ec;
- _association.insert(std::make_pair(parent, sec));
- }
- }
-
- // The sections that does not have auxiliary symbol are regular sections, in
- // which symbols are not allowed to be merged.
- for (const auto &section : _obj->sections()) {
- const coff_section *sec = _obj->getCOFFSection(section);
- if (!_merge.count(sec))
- _merge[sec] = DefinedAtom::mergeNo;
- }
- return std::error_code();
-}
-
-/// Atomize \p symbols and append the results to \p atoms. The symbols are
-/// assumed to have been defined in the \p section.
-std::error_code FileCOFF::AtomizeDefinedSymbolsInSection(
- const coff_section *section, SymbolVectorT &symbols,
- std::vector<COFFDefinedFileAtom *> &atoms) {
- // Sort symbols by position.
- std::stable_sort(
- symbols.begin(), symbols.end(),
- [](llvm::object::COFFSymbolRef a, llvm::object::COFFSymbolRef b)
- -> bool { return a.getValue() < b.getValue(); });
-
- StringRef sectionName;
- if (std::error_code ec = _obj->getSectionName(section, sectionName))
- return ec;
-
- // BSS section does not have contents. If this is the BSS section, create
- // COFFBSSAtom instead of COFFDefinedAtom.
- if (section->Characteristics & llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) {
- for (auto si = symbols.begin(), se = symbols.end(); si != se; ++si) {
- llvm::object::COFFSymbolRef sym = *si;
- uint32_t size = (si + 1 == se) ? section->SizeOfRawData - sym.getValue()
- : si[1].getValue() - sym.getValue();
- auto *atom = new (_alloc) COFFBSSAtom(
- *this, _symbolName[sym], getScope(sym), getPermissions(section),
- DefinedAtom::mergeAsWeakAndAddressUsed, size, getNextOrdinal());
- atoms.push_back(atom);
- _symbolAtom[sym] = atom;
- }
- return std::error_code();
- }
-
- ArrayRef<uint8_t> secData;
- if (std::error_code ec = _obj->getSectionContents(section, secData))
- return ec;
-
- // A section with IMAGE_SCN_LNK_{INFO,REMOVE} attribute will never become
- // a part of the output image. That's what the COFF spec says.
- if (section->Characteristics & llvm::COFF::IMAGE_SCN_LNK_INFO ||
- section->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE)
- return std::error_code();
-
- // Supporting debug info needs more work than just linking and combining
- // .debug sections. We don't support it yet. Let's discard .debug sections at
- // the very beginning of the process so that we don't spend time on linking
- // blobs that nobody would understand.
- if ((section->Characteristics & llvm::COFF::IMAGE_SCN_MEM_DISCARDABLE) &&
- (sectionName == ".debug" || sectionName.startswith(".debug$"))) {
- return std::error_code();
- }
-
- DefinedAtom::ContentType type = getContentType(section);
- DefinedAtom::ContentPermissions perms = getPermissions(section);
- uint64_t sectionSize = section->SizeOfRawData;
- bool isComdat = (_comdatSections.count(section) == 1);
-
- // Create an atom for the entire section.
- if (symbols.empty()) {
- ArrayRef<uint8_t> data(secData.data(), secData.size());
- auto *atom = new (_alloc) COFFDefinedAtom(
- *this, "", sectionName, sectionSize, Atom::scopeTranslationUnit,
- type, isComdat, perms, _merge[section], data, getNextOrdinal());
- atoms.push_back(atom);
- _definedAtomLocations[section].insert(std::make_pair(0, atom));
- return std::error_code();
- }
-
- // Create an unnamed atom if the first atom isn't at the start of the
- // section.
- if (symbols[0].getValue() != 0) {
- uint64_t size = symbols[0].getValue();
- ArrayRef<uint8_t> data(secData.data(), size);
- auto *atom = new (_alloc) COFFDefinedAtom(
- *this, "", sectionName, sectionSize, Atom::scopeTranslationUnit,
- type, isComdat, perms, _merge[section], data, getNextOrdinal());
- atoms.push_back(atom);
- _definedAtomLocations[section].insert(std::make_pair(0, atom));
- }
-
- for (auto si = symbols.begin(), se = symbols.end(); si != se; ++si) {
- const uint8_t *start = secData.data() + si->getValue();
- // if this is the last symbol, take up the remaining data.
- const uint8_t *end = (si + 1 == se) ? secData.data() + secData.size()
- : secData.data() + (si + 1)->getValue();
- ArrayRef<uint8_t> data(start, end);
- auto *atom = new (_alloc) COFFDefinedAtom(
- *this, _symbolName[*si], sectionName, sectionSize, getScope(*si),
- type, isComdat, perms, _merge[section], data, getNextOrdinal());
- atoms.push_back(atom);
- _symbolAtom[*si] = atom;
- _definedAtomLocations[section].insert(std::make_pair(si->getValue(), atom));
- }
- return std::error_code();
-}
-
-std::error_code FileCOFF::AtomizeDefinedSymbols(
- SectionToSymbolsT &definedSymbols,
- std::vector<const DefinedAtom *> &definedAtoms) {
- // For each section, make atoms for all the symbols defined in the
- // section, and append the atoms to the result objects.
- for (auto &i : definedSymbols) {
- const coff_section *section = i.first;
- SymbolVectorT &symbols = i.second;
- std::vector<COFFDefinedFileAtom *> atoms;
- if (std::error_code ec =
- AtomizeDefinedSymbolsInSection(section, symbols, atoms))
- return ec;
-
- // Set alignment to the first atom so that the section contents
- // will be aligned as specified by the object section header.
- if (atoms.size() > 0)
- atoms[0]->setAlignment(getAlignment(section));
-
- // Connect atoms with layout-after edges. It prevents atoms
- // from being GC'ed if there is a reference to one of the atoms
- // in the same layout-after chain. In such case we want to emit
- // all the atoms appeared in the same chain, because the "live"
- // atom may reference other atoms in the same chain.
- if (atoms.size() >= 2)
- for (auto it = atoms.begin(), e = atoms.end(); it + 1 != e; ++it)
- addLayoutEdge(*it, *(it + 1), lld::Reference::kindLayoutAfter);
-
- for (COFFDefinedFileAtom *atom : atoms) {
- _sectionAtoms[section].push_back(atom);
- definedAtoms.push_back(atom);
- }
- }
-
- // A COMDAT section with SELECT_ASSOCIATIVE attribute refer to other
- // section. If the referred section is linked to a binary, the
- // referring section needs to be linked too. A typical use case of
- // this attribute is a static initializer; a parent is a comdat BSS
- // section, and a child is a static initializer code for the data.
- //
- // We add referring section contents to the referred section's
- // associate list, so that Resolver takes care of them.
- for (auto i : _association) {
- const coff_section *parent = i.first;
- const coff_section *child = i.second;
- if (_sectionAtoms.count(child)) {
- COFFDefinedFileAtom *p = _sectionAtoms[parent][0];
- p->addAssociate(_sectionAtoms[child][0]);
- }
- }
-
- return std::error_code();
-}
-
-/// Find the atom that is at \p targetAddress in \p section.
-std::error_code FileCOFF::findAtomAt(const coff_section *section,
- uint32_t targetAddress,
- COFFDefinedFileAtom *&result,
- uint32_t &offsetInAtom) {
- auto loc = _definedAtomLocations.find(section);
- if (loc == _definedAtomLocations.end())
- return llvm::object::object_error::parse_failed;
- std::multimap<uint32_t, COFFDefinedAtom *> &map = loc->second;
-
- auto it = map.upper_bound(targetAddress);
- if (it == map.begin())
- return llvm::object::object_error::parse_failed;
- --it;
- uint32_t atomAddress = it->first;
- result = it->second;
- offsetInAtom = targetAddress - atomAddress;
- return std::error_code();
-}
-
-/// Find the atom for the symbol that was at the \p index in the symbol
-/// table.
-std::error_code FileCOFF::getAtomBySymbolIndex(uint32_t index, Atom *&ret) {
- ErrorOr<llvm::object::COFFSymbolRef> symbol = _obj->getSymbol(index);
- if (std::error_code ec = symbol.getError())
- return ec;
- ret = _symbolAtom[*symbol];
- assert(ret);
- return std::error_code();
-}
-
-/// Add relocation information to an atom based on \p rel. \p rel is an
-/// relocation entry for the \p section, and \p atoms are all the atoms
-/// defined in the \p section.
-std::error_code FileCOFF::addRelocationReference(
- const coff_relocation *rel, const coff_section *section) {
- // The address of the item which relocation is applied. Section's
- // VirtualAddress needs to be added for historical reasons, but the value
- // is usually just zero, so adding it is usually no-op.
- uint32_t itemAddress = rel->VirtualAddress + section->VirtualAddress;
-
- Atom *targetAtom = nullptr;
- if (std::error_code ec =
- getAtomBySymbolIndex(rel->SymbolTableIndex, targetAtom))
- return ec;
-
- COFFDefinedFileAtom *atom;
- uint32_t offsetInAtom;
- if (std::error_code ec = findAtomAt(section, itemAddress, atom, offsetInAtom))
- return ec;
- atom->addReference(llvm::make_unique<SimpleReference>(
- Reference::KindNamespace::COFF, _referenceArch, rel->Type, offsetInAtom,
- targetAtom, 0));
- return std::error_code();
-}
-
-// Read section contents.
-std::error_code FileCOFF::getSectionContents(StringRef sectionName,
- ArrayRef<uint8_t> &result) {
- const coff_section *section = nullptr;
- if (std::error_code ec = findSection(sectionName, section))
- return ec;
- if (!section)
- return std::error_code();
- if (std::error_code ec = _obj->getSectionContents(section, result))
- return ec;
- return std::error_code();
-}
-
-AliasAtom *
-FileCOFF::createAlias(StringRef name, const DefinedAtom *target, int cnt) {
- AliasAtom *alias = new (_alloc) AliasAtom(*this, name);
- alias->addReference(Reference::KindNamespace::all, Reference::KindArch::all,
- Reference::kindLayoutAfter, 0, target, 0);
- alias->setMerge(DefinedAtom::mergeAsWeak);
- if (target->contentType() == DefinedAtom::typeCode)
- alias->setDeadStrip(DefinedAtom::deadStripNever);
- alias->setOrdinal(target->ordinal() - cnt);
- return alias;
-}
-
-void FileCOFF::createAlternateNameAtoms() {
- std::vector<AliasAtom *> aliases;
- for (const DefinedAtom *atom : defined()) {
- int cnt = 1;
- for (StringRef alias : _ctx.getAlternateNames(atom->name()))
- aliases.push_back(createAlias(alias, atom, cnt++));
- }
- for (AliasAtom *alias : aliases)
- _definedAtoms._atoms.push_back(alias);
-}
-
-// Interpret the contents of .drectve section. If exists, the section contains
-// a string containing command line options. The linker is expected to
-// interpret the options as if they were given via the command line.
-//
-// The section mainly contains /defaultlib (-l in Unix), but can contain any
-// options as long as they are valid.
-std::error_code
-FileCOFF::parseDirectiveSection(StringRef directives) {
- DEBUG(llvm::dbgs() << ".drectve: " << directives << "\n");
-
- // Split the string into tokens, as the shell would do for argv.
- SmallVector<const char *, 16> tokens;
- tokens.push_back("link"); // argv[0] is the command name. Will be ignored.
- llvm::cl::TokenizeWindowsCommandLine(directives, _stringSaver, tokens);
- tokens.push_back(nullptr);
-
- // Calls the command line parser to interpret the token string as if they
- // were given via the command line.
- int argc = tokens.size() - 1;
- const char **argv = &tokens[0];
- std::string errorMessage;
- llvm::raw_string_ostream stream(errorMessage);
- PECOFFLinkingContext::ParseDirectives parseDirectives =
- _ctx.getParseDirectives();
- bool parseFailed = !parseDirectives(argc, argv, _ctx, stream);
- stream.flush();
- // Print error message if error.
- if (parseFailed) {
- return make_dynamic_error_code(
- Twine("Failed to parse '") + directives + "'\n"
- + "Reason: " + errorMessage);
- }
- if (!errorMessage.empty()) {
- llvm::errs() << "lld warning: " << errorMessage << "\n";
- }
- return std::error_code();
-}
-
-/// Returns the target machine type of the current object file.
-std::error_code FileCOFF::getReferenceArch(Reference::KindArch &result) {
- switch (_obj->getMachine()) {
- case llvm::COFF::IMAGE_FILE_MACHINE_I386:
- result = Reference::KindArch::x86;
- return std::error_code();
- case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
- result = Reference::KindArch::x86_64;
- return std::error_code();
- case llvm::COFF::IMAGE_FILE_MACHINE_ARMNT:
- result = Reference::KindArch::ARM;
- return std::error_code();
- case llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN:
- result = Reference::KindArch::all;
- return std::error_code();
- }
- llvm::errs() << "Unsupported machine type: 0x"
- << llvm::utohexstr(_obj->getMachine()) << '\n';
- return llvm::object::object_error::parse_failed;
-}
-
-/// Add relocation information to atoms.
-std::error_code FileCOFF::addRelocationReferenceToAtoms() {
- // Relocation entries are defined for each section.
- for (const auto &sec : _obj->sections()) {
- const coff_section *section = _obj->getCOFFSection(sec);
-
- // Skip if there's no atom for the section. Currently we do not create any
- // atoms for some sections, such as "debug$S", and such sections need to
- // be skipped here too.
- if (_sectionAtoms.find(section) == _sectionAtoms.end())
- continue;
-
- for (const auto &reloc : sec.relocations()) {
- const coff_relocation *rel = _obj->getCOFFRelocation(reloc);
- if (auto ec = addRelocationReference(rel, section))
- return ec;
- }
- }
- return std::error_code();
-}
-
-// Read .sxdata section if exists. .sxdata is a x86-only section that contains a
-// vector of symbol offsets. The symbols pointed by this section are SEH handler
-// functions contained in the same object file. The linker needs to construct a
-// SEH table and emit it to executable.
-//
-// On x86, exception handler addresses are in stack, so they are vulnerable to
-// stack overflow attack. In order to protect against it, Windows runtime uses
-// the SEH table to check if a SEH handler address in stack is a real address of
-// a handler created by compiler.
-//
-// What we want to emit from the linker is a vector of SEH handler VAs, but here
-// we have a vector of offsets to the symbol table. So we convert the latter to
-// the former.
-std::error_code FileCOFF::maybeCreateSXDataAtoms() {
- ArrayRef<uint8_t> sxdata;
- if (std::error_code ec = getSectionContents(".sxdata", sxdata))
- return ec;
- if (sxdata.empty())
- return std::error_code();
-
- auto *atom = new (_alloc) COFFDefinedAtom(
- *this, "", ".sxdata", 0, Atom::scopeTranslationUnit,
- DefinedAtom::typeData, false /*isComdat*/, DefinedAtom::permR__,
- DefinedAtom::mergeNo, sxdata, getNextOrdinal());
-
- const ulittle32_t *symbolIndex =
- reinterpret_cast<const ulittle32_t *>(sxdata.data());
- int numSymbols = sxdata.size() / sizeof(uint32_t);
-
- for (int i = 0; i < numSymbols; ++i) {
- Atom *handlerFunc;
- if (std::error_code ec = getAtomBySymbolIndex(symbolIndex[i], handlerFunc))
- return ec;
- int offsetInAtom = i * sizeof(uint32_t);
-
- uint16_t rtype;
- switch (_obj->getMachine()) {
- case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
- rtype = llvm::COFF::IMAGE_REL_AMD64_ADDR32;
- break;
- case llvm::COFF::IMAGE_FILE_MACHINE_I386:
- rtype = llvm::COFF::IMAGE_REL_I386_DIR32;
- break;
- default:
- llvm_unreachable("unsupported machine type");
- }
-
- atom->addReference(llvm::make_unique<SimpleReference>(
- Reference::KindNamespace::COFF, _referenceArch, rtype, offsetInAtom,
- handlerFunc, 0));
- }
-
- _definedAtoms._atoms.push_back(atom);
- return std::error_code();
-}
-
-/// Find a section by name.
-std::error_code FileCOFF::findSection(StringRef name,
- const coff_section *&result) {
- for (const auto &sec : _obj->sections()) {
- const coff_section *section = _obj->getCOFFSection(sec);
- StringRef sectionName;
- if (auto ec = _obj->getSectionName(section, sectionName))
- return ec;
- if (sectionName == name) {
- result = section;
- return std::error_code();
- }
- }
- // Section was not found, but it's not an error. This method returns
- // an error only when there's a read error.
- return std::error_code();
-}
-
-// Convert ArrayRef<uint8_t> to std::string. The array contains a string which
-// may not be terminated by NUL.
-StringRef FileCOFF::ArrayRefToString(ArrayRef<uint8_t> array) {
- // .drectve sections are encoded in either ASCII or UTF-8 with BOM.
- // The PE/COFF spec allows ANSI (Windows-1252 encoding), but seems
- // it's no longer in use.
- // Skip a UTF-8 byte marker if exists.
- if (array.size() >= 3 && array[0] == 0xEF && array[1] == 0xBB &&
- array[2] == 0xBF) {
- array = array.slice(3);
- }
- if (array.empty())
- return "";
- StringRef s(reinterpret_cast<const char *>(array.data()), array.size());
- s = s.substr(0, s.find_first_of('\0'));
- std::string *contents = new (_alloc) std::string(s.data(), s.size());
- return StringRef(*contents).trim();
-}
-
-// getNextOrdinal returns a monotonically increasaing uint64_t number
-// starting from 1. There's a large gap between two numbers returned
-// from this function, so that you can put other atoms between them.
-uint64_t FileCOFF::getNextOrdinal() {
- return _ordinal++ << 32;
-}
-
-class COFFObjectReader : public Reader {
-public:
- COFFObjectReader(PECOFFLinkingContext &ctx) : _ctx(ctx) {}
-
- bool canParse(file_magic magic, StringRef ext,
- const MemoryBuffer &) const override {
- return magic == llvm::sys::fs::file_magic::coff_object;
- }
-
- std::error_code
- loadFile(std::unique_ptr<MemoryBuffer> mb, const Registry &,
- std::vector<std::unique_ptr<File>> &result) const override {
- // Parse the memory buffer as PECOFF file.
- auto *file = new FileCOFF(std::move(mb), _ctx);
- result.push_back(std::unique_ptr<File>(file));
- return std::error_code();
- }
-
-private:
- PECOFFLinkingContext &_ctx;
-};
-
-using namespace llvm::COFF;
-
-const Registry::KindStrings kindStringsI386[] = {
- LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_ABSOLUTE),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_DIR16),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_REL16),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_DIR32),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_DIR32NB),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_SEG12),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_SECTION),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_SECREL),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_TOKEN),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_SECREL7),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_REL32),
- LLD_KIND_STRING_END};
-
-const Registry::KindStrings kindStringsAMD64[] = {
- LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_ABSOLUTE),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_ADDR64),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_ADDR32),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_ADDR32NB),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_REL32),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_REL32_1),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_REL32_2),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_REL32_3),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_REL32_4),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_REL32_5),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_SECTION),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_SECREL),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_SECREL7),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_TOKEN),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_SREL32),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_PAIR),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_SSPAN32),
- LLD_KIND_STRING_END};
-
-const Registry::KindStrings kindStringsARMNT[] = {
- LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_ABSOLUTE),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_ADDR32),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_ADDR32NB),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_BRANCH24),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_BRANCH11),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_TOKEN),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_BLX24),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_BLX11),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_SECTION),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_SECREL),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_MOV32A),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_MOV32T),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_BRANCH20T),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_BRANCH24T),
- LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_BLX23T),
-};
-
-} // end namespace anonymous
-
-namespace lld {
-
-void Registry::addSupportCOFFObjects(PECOFFLinkingContext &ctx) {
- add(std::unique_ptr<Reader>(new COFFObjectReader(ctx)));
- addKindTable(Reference::KindNamespace::COFF, Reference::KindArch::x86,
- kindStringsI386);
- addKindTable(Reference::KindNamespace::COFF, Reference::KindArch::x86_64,
- kindStringsAMD64);
- addKindTable(Reference::KindNamespace::COFF, Reference::KindArch::ARM,
- kindStringsARMNT);
-}
-
-}
diff --git a/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp b/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp
deleted file mode 100644
index 8c9641376a0d..000000000000
--- a/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp
+++ /dev/null
@@ -1,389 +0,0 @@
-//===- lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp ---------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file \brief This file provides a way to read an import library member in a
-/// .lib file.
-///
-/// Archive Files in Windows
-/// ========================
-///
-/// In Windows, archive files with .lib file extension serve two different
-/// purposes.
-///
-/// - For static linking: An archive file in this use case contains multiple
-/// regular .obj files and is used for static linking. This is the same
-/// usage as .a file in Unix.
-///
-/// - For dynamic linking: An archive file in this use case contains pseudo
-/// .obj files to describe exported symbols of a DLL. Each pseudo .obj file
-/// in an archive has a name of an exported symbol and a DLL filename from
-/// which the symbol can be imported. When you link a DLL on Windows, you
-/// pass the name of the .lib file for the DLL instead of the DLL filename
-/// itself. That is the Windows way of linking against a shared library.
-///
-/// This file contains a function to handle the pseudo object file.
-///
-/// Windows Loader and Import Address Table
-/// =======================================
-///
-/// Windows supports a GOT-like mechanism for DLLs. The executable using DLLs
-/// contains a list of DLL names and list of symbols that need to be resolved by
-/// the loader. Windows loader maps the executable and all the DLLs to memory,
-/// resolves the symbols referencing items in DLLs, and updates the import
-/// address table (IAT) in memory. The IAT is an array of pointers to all of the
-/// data or functions in DLL referenced by the executable. You cannot access
-/// items in DLLs directly. They have to be accessed through an extra level of
-/// indirection.
-///
-/// So, if you want to access an item in DLL, you have to go through a
-/// pointer. How do you actually do that? You need a symbol for a pointer in the
-/// IAT. For each symbol defined in a DLL, a symbol with "__imp_" prefix is
-/// exported from the DLL for an IAT entry. For example, if you have a global
-/// variable "foo" in a DLL, a pointer to the variable is available as
-/// "_imp__foo". The IAT is an array of _imp__ symbols.
-///
-/// Is this OK? That's not that complicated. Because items in a DLL are not
-/// directly accessible, you need to access through a pointer, and the pointer
-/// is available as a symbol with _imp__ prefix.
-///
-/// Note 1: Although you can write code with _imp__ prefix, today's compiler and
-/// linker let you write code as if there's no extra level of indirection.
-/// That's why you haven't seen lots of _imp__ in your code. A variable or a
-/// function declared with "dllimport" attribute is treated as an item in a DLL,
-/// and the compiler automatically mangles its name and inserts the extra level
-/// of indirection when accessing the item. Here are some examples:
-///
-/// __declspec(dllimport) int var_in_dll;
-/// var_in_dll = 3; // is equivalent to *_imp__var_in_dll = 3;
-///
-/// __declspec(dllimport) int fn_in_dll(void);
-/// fn_in_dll(); // is equivalent to (*_imp__fn_in_dll)();
-///
-/// It's just the compiler rewrites code for you so that you don't need to
-/// handle the indirection yourself.
-///
-/// Note 2: __declspec(dllimport) is mandatory for data but optional for
-/// function. For a function, the linker creates a jump table with the original
-/// symbol name, so that the function is accessible without _imp__ prefix. The
-/// same function in a DLL can be called through two different symbols if it's
-/// not dllimport'ed.
-///
-/// (*_imp__fn)()
-/// fn()
-///
-/// The above functions do the same thing. fn's content is a JMP instruction to
-/// branch to the address pointed by _imp__fn. The latter may be a little bit
-/// slower than the former because it will execute the extra JMP instruction,
-/// but that's usually negligible.
-///
-/// If a function is dllimport'ed, which is usually done in a header file,
-/// mangled name will be used at compile time so the jump table will not be
-/// used.
-///
-/// Because there's no way to hide the indirection for data access at link time,
-/// data has to be accessed through dllimport'ed symbols or explicit _imp__
-/// prefix.
-///
-/// Idata Sections in the Pseudo Object File
-/// ========================================
-///
-/// The object file created by cl.exe has several sections whose name starts
-/// with ".idata$" followed by a number. The contents of the sections seem the
-/// fragments of a complete ".idata" section. These sections has relocations for
-/// the data referenced from the idata secton. Generally, the linker discards
-/// "$" and all characters that follow from the section name and merges their
-/// contents to one section. So, it looks like if everything would work fine,
-/// the idata section would naturally be constructed without having any special
-/// code for doing that.
-///
-/// However, the LLD linker cannot do that. An idata section constructed in that
-/// way was never be in valid format. We don't know the reason yet. Our
-/// assumption on the idata fragment could simply be wrong, or the LLD linker is
-/// not powerful enough to do the job. Meanwhile, we construct the idata section
-/// ourselves. All the "idata$" sections in the pseudo object file are currently
-/// ignored.
-///
-/// Creating Atoms for the Import Address Table
-/// ===========================================
-///
-/// The function in this file reads a pseudo object file and creates at most two
-/// atoms. One is a shared library atom for _imp__ symbol. The another is a
-/// defined atom for the JMP instruction if the symbol is for a function.
-///
-//===----------------------------------------------------------------------===//
-
-#include "Atoms.h"
-#include "lld/Core/Error.h"
-#include "lld/Core/File.h"
-#include "lld/Core/SharedLibraryAtom.h"
-#include "lld/ReaderWriter/PECOFFLinkingContext.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/Object/COFF.h"
-#include "llvm/Support/COFF.h"
-#include "llvm/Support/Casting.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/Endian.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/Memory.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/raw_ostream.h"
-#include <cstring>
-#include <map>
-#include <system_error>
-#include <vector>
-
-using namespace lld;
-using namespace lld::pecoff;
-using namespace llvm;
-using namespace llvm::support::endian;
-
-#define DEBUG_TYPE "ReaderImportHeader"
-
-namespace lld {
-
-namespace {
-
-// This code is valid both in x86 and x64.
-const uint8_t FuncAtomContentX86[] = {
- 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // JMP *0x0
- 0xcc, 0xcc // INT 3; INT 3
-};
-
-const uint8_t FuncAtomContentARMNT[] = {
- 0x40, 0xf2, 0x00, 0x0c, // mov.w ip, #0
- 0xc0, 0xf2, 0x00, 0x0c, // mov.t ip, #0
- 0xdc, 0xf8, 0x00, 0xf0, // ldr.w pc, [ip]
-};
-
-static void setJumpInstTarget(COFFLinkerInternalAtom *src, const Atom *dst,
- int off, MachineTypes machine) {
- SimpleReference *ref;
-
- switch (machine) {
- default: llvm::report_fatal_error("unsupported machine type");
- case llvm::COFF::IMAGE_FILE_MACHINE_I386:
- ref = new SimpleReference(Reference::KindNamespace::COFF,
- Reference::KindArch::x86,
- llvm::COFF::IMAGE_REL_I386_DIR32,
- off, dst, 0);
- break;
- case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
- ref = new SimpleReference(Reference::KindNamespace::COFF,
- Reference::KindArch::x86_64,
- llvm::COFF::IMAGE_REL_AMD64_REL32,
- off, dst, 0);
- break;
- case llvm::COFF::IMAGE_FILE_MACHINE_ARMNT:
- ref = new SimpleReference(Reference::KindNamespace::COFF,
- Reference::KindArch::ARM,
- llvm::COFF::IMAGE_REL_ARM_MOV32T,
- off, dst, 0);
- break;
- }
- src->addReference(std::unique_ptr<SimpleReference>(ref));
-}
-
-/// The defined atom for jump table.
-class FuncAtom : public COFFLinkerInternalAtom {
-public:
- FuncAtom(const File &file, StringRef symbolName,
- const COFFSharedLibraryAtom *impAtom, MachineTypes machine)
- : COFFLinkerInternalAtom(file, /*oridnal*/ 0, createContent(machine),
- symbolName) {
- size_t Offset;
-
- switch (machine) {
- default: llvm::report_fatal_error("unsupported machine type");
- case llvm::COFF::IMAGE_FILE_MACHINE_I386:
- case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
- Offset = 2;
- break;
- case llvm::COFF::IMAGE_FILE_MACHINE_ARMNT:
- Offset = 0;
- break;
- }
-
- setJumpInstTarget(this, impAtom, Offset, machine);
- }
-
- uint64_t ordinal() const override { return 0; }
- Scope scope() const override { return scopeGlobal; }
- ContentType contentType() const override { return typeCode; }
- Alignment alignment() const override { return Alignment(1); }
- ContentPermissions permissions() const override { return permR_X; }
-
-private:
- std::vector<uint8_t> createContent(MachineTypes machine) const {
- const uint8_t *Data;
- size_t Size;
-
- switch (machine) {
- default: llvm::report_fatal_error("unsupported machine type");
- case llvm::COFF::IMAGE_FILE_MACHINE_I386:
- case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
- Data = FuncAtomContentX86;
- Size = sizeof(FuncAtomContentX86);
- break;
- case llvm::COFF::IMAGE_FILE_MACHINE_ARMNT:
- Data = FuncAtomContentARMNT;
- Size = sizeof(FuncAtomContentARMNT);
- break;
- }
-
- return std::vector<uint8_t>(Data, Data + Size);
- }
-};
-
-class FileImportLibrary : public File {
-public:
- FileImportLibrary(std::unique_ptr<MemoryBuffer> mb, MachineTypes machine)
- : File(mb->getBufferIdentifier(), kindSharedLibrary),
- _mb(std::move(mb)), _machine(machine) {}
-
- std::error_code doParse() override {
- const char *buf = _mb->getBufferStart();
- const char *end = _mb->getBufferEnd();
-
- // The size of the string that follows the header.
- uint32_t dataSize
- = read32le(buf + offsetof(COFF::ImportHeader, SizeOfData));
-
- // Check if the total size is valid.
- if (std::size_t(end - buf) != sizeof(COFF::ImportHeader) + dataSize)
- return make_error_code(NativeReaderError::unknown_file_format);
-
- uint16_t hint = read16le(buf + offsetof(COFF::ImportHeader, OrdinalHint));
- StringRef symbolName(buf + sizeof(COFF::ImportHeader));
- StringRef dllName(buf + sizeof(COFF::ImportHeader) + symbolName.size() + 1);
-
- // TypeInfo is a bitfield. The least significant 2 bits are import
- // type, followed by 3 bit import name type.
- uint16_t typeInfo = read16le(buf + offsetof(COFF::ImportHeader, TypeInfo));
- int type = typeInfo & 0x3;
- int nameType = (typeInfo >> 2) & 0x7;
-
- // Symbol name used by the linker may be different from the symbol name used
- // by the loader. The latter may lack symbol decorations, or may not even
- // have name if it's imported by ordinal.
- StringRef importName = symbolNameToImportName(symbolName, nameType);
-
- const COFFSharedLibraryAtom *dataAtom =
- addSharedLibraryAtom(hint, symbolName, importName, dllName);
- if (type == llvm::COFF::IMPORT_CODE)
- addFuncAtom(symbolName, dllName, dataAtom);
-
- return std::error_code();
- }
-
- const atom_collection<DefinedAtom> &defined() const override {
- return _definedAtoms;
- }
-
- const atom_collection<UndefinedAtom> &undefined() const override {
- return _noUndefinedAtoms;
- }
-
- const atom_collection<SharedLibraryAtom> &sharedLibrary() const override {
- return _sharedLibraryAtoms;
- }
-
- const atom_collection<AbsoluteAtom> &absolute() const override {
- return _noAbsoluteAtoms;
- }
-
-private:
- const COFFSharedLibraryAtom *addSharedLibraryAtom(uint16_t hint,
- StringRef symbolName,
- StringRef importName,
- StringRef dllName) {
- auto *atom = new (_alloc)
- COFFSharedLibraryAtom(*this, hint, symbolName, importName, dllName);
- _sharedLibraryAtoms._atoms.push_back(atom);
- return atom;
- }
-
- void addFuncAtom(StringRef symbolName, StringRef dllName,
- const COFFSharedLibraryAtom *impAtom) {
- auto *atom = new (_alloc) FuncAtom(*this, symbolName, impAtom, _machine);
- _definedAtoms._atoms.push_back(atom);
- }
-
- atom_collection_vector<DefinedAtom> _definedAtoms;
- atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
- mutable llvm::BumpPtrAllocator _alloc;
-
- // Does the same thing as StringRef::ltrim() but removes at most one
- // character.
- StringRef ltrim1(StringRef str, const char *chars) const {
- if (!str.empty() && strchr(chars, str[0]))
- return str.substr(1);
- return str;
- }
-
- // Convert the given symbol name to the import symbol name exported by the
- // DLL.
- StringRef symbolNameToImportName(StringRef symbolName, int nameType) const {
- StringRef ret;
- switch (nameType) {
- case llvm::COFF::IMPORT_ORDINAL:
- // The import is by ordinal. No symbol name will be used to identify the
- // item in the DLL. Only its ordinal will be used.
- return "";
- case llvm::COFF::IMPORT_NAME:
- // The import name in this case is identical to the symbol name.
- return symbolName;
- case llvm::COFF::IMPORT_NAME_NOPREFIX:
- // The import name is the symbol name without leading ?, @ or _.
- ret = ltrim1(symbolName, "?@_");
- break;
- case llvm::COFF::IMPORT_NAME_UNDECORATE:
- // Similar to NOPREFIX, but we also need to truncate at the first @.
- ret = ltrim1(symbolName, "?@_");
- ret = ret.substr(0, ret.find('@'));
- break;
- }
- std::string *str = new (_alloc) std::string(ret);
- return *str;
- }
-
- std::unique_ptr<MemoryBuffer> _mb;
- MachineTypes _machine;
-};
-
-class COFFImportLibraryReader : public Reader {
-public:
- COFFImportLibraryReader(PECOFFLinkingContext &ctx) : _ctx(ctx) {}
-
- bool canParse(file_magic magic, StringRef,
- const MemoryBuffer &mb) const override {
- if (mb.getBufferSize() < sizeof(COFF::ImportHeader))
- return false;
- return (magic == llvm::sys::fs::file_magic::coff_import_library);
- }
-
- std::error_code
- loadFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &,
- std::vector<std::unique_ptr<File> > &result) const override {
- auto *file = new FileImportLibrary(std::move(mb), _ctx.getMachineType());
- result.push_back(std::unique_ptr<File>(file));
- return std::error_code();
- }
-
-private:
- PECOFFLinkingContext &_ctx;
-};
-
-} // end anonymous namespace
-
-void Registry::addSupportCOFFImportLibraries(PECOFFLinkingContext &ctx) {
- add(llvm::make_unique<COFFImportLibraryReader>(ctx));
-}
-
-} // end namespace lld
diff --git a/lib/ReaderWriter/PECOFF/WriterImportLibrary.cpp b/lib/ReaderWriter/PECOFF/WriterImportLibrary.cpp
deleted file mode 100644
index fd3360f018b6..000000000000
--- a/lib/ReaderWriter/PECOFF/WriterImportLibrary.cpp
+++ /dev/null
@@ -1,118 +0,0 @@
-//===- lib/ReaderWriter/PECOFF/WriterImportLibrary.cpp --------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-///
-/// This file is responsible for creating the Import Library file.
-///
-//===----------------------------------------------------------------------===//
-
-#include "lld/ReaderWriter/PECOFFLinkingContext.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/FileUtilities.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/Program.h"
-#include "llvm/Support/raw_ostream.h"
-
-namespace lld {
-namespace pecoff {
-
-/// Creates a .def file containing the list of exported symbols.
-static std::string
-createModuleDefinitionFile(const PECOFFLinkingContext &ctx) {
- std::string ret;
- llvm::raw_string_ostream os(ret);
- os << "LIBRARY \"" << llvm::sys::path::filename(ctx.outputPath()) << "\"\n"
- << "EXPORTS\n";
-
- for (const PECOFFLinkingContext::ExportDesc &desc : ctx.getDllExports()) {
- // Symbol names in a module-definition file will be mangled by lib.exe,
- // so we need to demangle them before writing to a .def file.
- os << " ";
- if (!desc.externalName.empty()) {
- os << desc.externalName;
- } else if (!desc.mangledName.empty()) {
- os << ctx.undecorateSymbol(desc.mangledName);
- } else {
- os << ctx.undecorateSymbol(desc.name);
- }
-
- if (!desc.isPrivate)
- os << " @" << desc.ordinal;
- if (desc.noname)
- os << " NONAME";
- if (desc.isData)
- os << " DATA";
- if (desc.isPrivate)
- os << " PRIVATE";
- os << "\n";
- }
- os.flush();
- return ret;
-}
-
-static std::string writeToTempFile(StringRef contents) {
- SmallString<128> path;
- int fd;
- if (llvm::sys::fs::createTemporaryFile("tmp", "def", fd, path)) {
- llvm::errs() << "Failed to create temporary file\n";
- return "";
- }
- llvm::raw_fd_ostream os(fd, /*shouldClose*/ true);
- os << contents;
- return path.str();
-}
-
-static void writeTo(StringRef path, StringRef contents) {
- int fd;
- if (llvm::sys::fs::openFileForWrite(path, fd, llvm::sys::fs::F_Text)) {
- llvm::errs() << "Failed to open " << path << "\n";
- return;
- }
- llvm::raw_fd_ostream os(fd, /*shouldClose*/ true);
- os << contents;
-}
-
-/// Creates a .def file and runs lib.exe on it to create an import library.
-void writeImportLibrary(const PECOFFLinkingContext &ctx) {
- std::string fileContents = createModuleDefinitionFile(ctx);
-
- std::string program = "lib.exe";
- ErrorOr<std::string> programPathOrErr = llvm::sys::findProgramByName(program);
- if (!programPathOrErr) {
- llvm::errs() << "Unable to find " << program << " in PATH\n";
- } else {
- const std::string &programPath = *programPathOrErr;
-
- std::string defPath = writeToTempFile(fileContents);
- llvm::FileRemover tmpFile(defPath);
-
- std::string defArg = "/def:";
- defArg.append(defPath);
- std::string outputArg = "/out:";
- outputArg.append(ctx.getOutputImportLibraryPath());
-
- std::vector<const char *> args;
- args.push_back(programPath.c_str());
- args.push_back("/nologo");
- args.push_back(ctx.is64Bit() ? "/machine:x64" : "/machine:x86");
- args.push_back(defArg.c_str());
- args.push_back(outputArg.c_str());
- args.push_back(nullptr);
-
- if (llvm::sys::ExecuteAndWait(programPath.c_str(), &args[0]) != 0)
- llvm::errs() << program << " failed\n";
- }
-
- // If /lldmoduledeffile:<filename> is given, make a copy of the
- // temporary module definition file. This feature is for unit tests.
- if (!ctx.getModuleDefinitionFile().empty())
- writeTo(ctx.getModuleDefinitionFile(), fileContents);
-}
-
-} // end namespace pecoff
-} // end namespace lld
diff --git a/lib/ReaderWriter/PECOFF/WriterImportLibrary.h b/lib/ReaderWriter/PECOFF/WriterImportLibrary.h
deleted file mode 100644
index a51b9a3648c5..000000000000
--- a/lib/ReaderWriter/PECOFF/WriterImportLibrary.h
+++ /dev/null
@@ -1,23 +0,0 @@
-//===- lib/ReaderWriter/PECOFF/WriterImportLibrary.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_PE_COFF_WRITER_IMPORT_LIBRARY_H
-#define LLD_READER_WRITER_PE_COFF_WRITER_IMPORT_LIBRARY_H
-
-namespace lld {
-class PECOFFLinkingContext;
-
-namespace pecoff {
-
-void writeImportLibrary(const PECOFFLinkingContext &ctx);
-
-} // end namespace pecoff
-} // end namespace lld
-
-#endif
diff --git a/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp b/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp
deleted file mode 100644
index d34e2d3d63fd..000000000000
--- a/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp
+++ /dev/null
@@ -1,1417 +0,0 @@
-//===- lib/ReaderWriter/PECOFF/WriterPECOFF.cpp ---------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-///
-/// PE/COFF file consists of DOS Header, PE Header, COFF Header and Section
-/// Tables followed by raw section data.
-///
-/// This writer is responsible for writing Core Linker results to an Windows
-/// executable file.
-///
-/// This writer currently supports 32 bit PE/COFF for x86 processor only.
-///
-//===----------------------------------------------------------------------===//
-
-#include "Atoms.h"
-#include "WriterImportLibrary.h"
-#include "lld/Core/DefinedAtom.h"
-#include "lld/Core/File.h"
-#include "lld/Core/Writer.h"
-#include "lld/ReaderWriter/AtomLayout.h"
-#include "lld/ReaderWriter/PECOFFLinkingContext.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/Object/COFF.h"
-#include "llvm/Support/COFF.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/Endian.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/ErrorOr.h"
-#include "llvm/Support/FileOutputBuffer.h"
-#include "llvm/Support/Format.h"
-#include <algorithm>
-#include <cstdlib>
-#include <map>
-#include <time.h>
-#include <vector>
-
-#define DEBUG_TYPE "WriterPECOFF"
-
-using namespace llvm::support::endian;
-
-using llvm::COFF::DataDirectoryIndex;
-using llvm::object::coff_runtime_function_x64;
-using llvm::support::ulittle16_t;
-using llvm::support::ulittle32_t;
-using llvm::support::ulittle64_t;
-
-namespace lld {
-namespace pecoff {
-
-// Disk sector size. Some data needs to be aligned at disk sector boundary in
-// file.
-static const int SECTOR_SIZE = 512;
-
-namespace {
-class SectionChunk;
-
-/// A Chunk is an abstract contiguous range in an output file.
-class Chunk {
-public:
- enum Kind {
- kindHeader,
- kindSection,
- kindStringTable,
- kindAtomChunk
- };
-
- explicit Chunk(Kind kind) : _kind(kind), _size(0) {}
- virtual ~Chunk() {}
- virtual void write(uint8_t *buffer) = 0;
- virtual uint64_t size() const { return _size; }
- virtual uint64_t onDiskSize() const { return size(); }
- virtual uint64_t align() const { return 1; }
-
- uint64_t fileOffset() const { return _fileOffset; }
- void setFileOffset(uint64_t fileOffset) { _fileOffset = fileOffset; }
- Kind getKind() const { return _kind; }
-
-protected:
- Kind _kind;
- uint64_t _size;
- uint64_t _fileOffset;
-};
-
-/// A HeaderChunk is an abstract class to represent a file header for
-/// PE/COFF. The data in the header chunk is metadata about program and will
-/// be consumed by the windows loader. HeaderChunks are not mapped to memory
-/// when executed.
-class HeaderChunk : public Chunk {
-public:
- HeaderChunk() : Chunk(kindHeader) {}
-
- static bool classof(const Chunk *c) { return c->getKind() == kindHeader; }
-};
-
-/// A DOSStubChunk represents the DOS compatible header at the beginning
-/// of PE/COFF files.
-class DOSStubChunk : public HeaderChunk {
-public:
- explicit DOSStubChunk(const PECOFFLinkingContext &ctx)
- : HeaderChunk(), _context(ctx) {
- // Minimum size of DOS stub is 64 bytes. The next block (PE header) needs to
- // be aligned on 8 byte boundary.
- size_t size = std::max(_context.getDosStub().size(), (size_t)64);
- _size = llvm::RoundUpToAlignment(size, 8);
- }
-
- void write(uint8_t *buffer) override {
- ArrayRef<uint8_t> array = _context.getDosStub();
- std::memcpy(buffer, array.data(), array.size());
- auto *header = reinterpret_cast<llvm::object::dos_header *>(buffer);
- header->AddressOfRelocationTable = sizeof(llvm::object::dos_header);
- header->AddressOfNewExeHeader = _size;
- }
-
-private:
- const PECOFFLinkingContext &_context;
-};
-
-/// A PEHeaderChunk represents PE header including COFF header.
-template <class PEHeader>
-class PEHeaderChunk : public HeaderChunk {
-public:
- explicit PEHeaderChunk(const PECOFFLinkingContext &ctx);
-
- void write(uint8_t *buffer) override;
-
- void setSizeOfHeaders(uint64_t size) {
- // Must be multiple of FileAlignment.
- _peHeader.SizeOfHeaders = llvm::RoundUpToAlignment(size, SECTOR_SIZE);
- }
-
- void setSizeOfCode(uint64_t size) { _peHeader.SizeOfCode = size; }
- void setBaseOfCode(uint32_t rva) { _peHeader.BaseOfCode = rva; }
- void setBaseOfData(uint32_t rva);
- void setSizeOfImage(uint32_t size) { _peHeader.SizeOfImage = size; }
-
- void setSizeOfInitializedData(uint64_t size) {
- _peHeader.SizeOfInitializedData = size;
- }
-
- void setSizeOfUninitializedData(uint64_t size) {
- _peHeader.SizeOfUninitializedData = size;
- }
-
- void setNumberOfSections(uint32_t num) { _coffHeader.NumberOfSections = num; }
- void setNumberOfSymbols(uint32_t num) { _coffHeader.NumberOfSymbols = num; }
-
- void setAddressOfEntryPoint(uint32_t address) {
- _peHeader.AddressOfEntryPoint = address;
- }
-
- void setPointerToSymbolTable(uint32_t rva) {
- _coffHeader.PointerToSymbolTable = rva;
- }
-
-private:
- llvm::object::coff_file_header _coffHeader;
- PEHeader _peHeader;
-};
-
-/// A SectionHeaderTableChunk represents Section Table Header of PE/COFF
-/// format, which is a list of section headers.
-class SectionHeaderTableChunk : public HeaderChunk {
-public:
- SectionHeaderTableChunk() : HeaderChunk() {}
- void addSection(SectionChunk *chunk);
- uint64_t size() const override;
- void write(uint8_t *buffer) override;
-
-private:
- static llvm::object::coff_section createSectionHeader(SectionChunk *chunk);
-
- std::vector<SectionChunk *> _sections;
-};
-
-class StringTableChunk : public Chunk {
-public:
- StringTableChunk() : Chunk(kindStringTable) {}
-
- static bool classof(const Chunk *c) {
- return c->getKind() == kindStringTable;
- }
-
- uint32_t addSectionName(StringRef sectionName) {
- if (_stringTable.empty()) {
- // The string table immediately follows the symbol table.
- // We don't really need a symbol table, but some tools (e.g. dumpbin)
- // don't like zero-length symbol table.
- // Make room for the empty symbol slot, which occupies 18 byte.
- // We also need to reserve 4 bytes for the string table header.
- int size = sizeof(llvm::object::coff_symbol16) + 4;
- _stringTable.insert(_stringTable.begin(), size, 0);
- // Set the name of the dummy symbol to the first string table entry.
- // It's better than letting dumpbin print out a garabage as a symbol name.
- char *off = _stringTable.data() + 4;
- write32le(off, 4);
- }
- uint32_t offset = _stringTable.size();
- _stringTable.insert(_stringTable.end(), sectionName.begin(),
- sectionName.end());
- _stringTable.push_back('\0');
- return offset - sizeof(llvm::object::coff_symbol16);
- }
-
- uint64_t size() const override { return _stringTable.size(); }
-
- void write(uint8_t *buffer) override {
- if (_stringTable.empty())
- return;
- char *off = _stringTable.data() + sizeof(llvm::object::coff_symbol16);
- write32le(off, _stringTable.size());
- std::memcpy(buffer, _stringTable.data(), _stringTable.size());
- }
-
-private:
- std::vector<char> _stringTable;
-};
-
-class SectionChunk : public Chunk {
-public:
- uint64_t onDiskSize() const override {
- if (_characteristics & llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)
- return 0;
- return llvm::RoundUpToAlignment(size(), SECTOR_SIZE);
- }
-
- uint64_t align() const override { return SECTOR_SIZE; }
- uint32_t getCharacteristics() const { return _characteristics; }
- StringRef getSectionName() const { return _sectionName; }
- virtual uint64_t memAlign() const { return _memAlign; }
-
- static bool classof(const Chunk *c) {
- Kind kind = c->getKind();
- return kind == kindSection || kind == kindAtomChunk;
- }
-
- uint64_t getVirtualAddress() { return _virtualAddress; }
- virtual void setVirtualAddress(uint32_t rva) { _virtualAddress = rva; }
-
- uint32_t getStringTableOffset() const { return _stringTableOffset; }
- void setStringTableOffset(uint32_t offset) { _stringTableOffset = offset; }
-
-protected:
- SectionChunk(Kind kind, StringRef sectionName, uint32_t characteristics,
- const PECOFFLinkingContext &ctx)
- : Chunk(kind), _sectionName(sectionName),
- _characteristics(characteristics), _virtualAddress(0),
- _stringTableOffset(0), _memAlign(ctx.getPageSize()) {}
-
-private:
- StringRef _sectionName;
- const uint32_t _characteristics;
- uint64_t _virtualAddress;
- uint32_t _stringTableOffset;
- uint64_t _memAlign;
-};
-
-struct BaseReloc {
- BaseReloc(uint64_t a, llvm::COFF::BaseRelocationType t) : addr(a), type(t) {}
- uint64_t addr;
- llvm::COFF::BaseRelocationType type;
-};
-
-/// An AtomChunk represents a section containing atoms.
-class AtomChunk : public SectionChunk {
-public:
- AtomChunk(const PECOFFLinkingContext &ctx, StringRef name,
- const std::vector<const DefinedAtom *> &atoms);
-
- void write(uint8_t *buffer) override;
-
- uint64_t memAlign() const override;
- void appendAtom(const DefinedAtom *atom);
- void buildAtomRvaMap(std::map<const Atom *, uint64_t> &atomRva) const;
-
- void applyRelocationsARM(uint8_t *buffer,
- std::map<const Atom *, uint64_t> &atomRva,
- std::vector<uint64_t> &sectionRva,
- uint64_t imageBaseAddress);
- void applyRelocationsX86(uint8_t *buffer,
- std::map<const Atom *, uint64_t> &atomRva,
- std::vector<uint64_t> &sectionRva,
- uint64_t imageBaseAddress);
- void applyRelocationsX64(uint8_t *buffer,
- std::map<const Atom *, uint64_t> &atomRva,
- std::vector<uint64_t> &sectionRva,
- uint64_t imageBaseAddress);
-
- void printAtomAddresses(uint64_t baseAddr) const;
- void addBaseRelocations(std::vector<BaseReloc> &relocSites) const;
-
- void setVirtualAddress(uint32_t rva) override;
- uint64_t getAtomVirtualAddress(StringRef name) const;
-
- static bool classof(const Chunk *c) { return c->getKind() == kindAtomChunk; }
-
-protected:
- std::vector<AtomLayout *> _atomLayouts;
- uint64_t _virtualAddress;
-
-private:
- uint32_t
- computeCharacteristics(const PECOFFLinkingContext &ctx, StringRef name,
- const std::vector<const DefinedAtom *> &atoms) const {
- return ctx.getSectionAttributes(name,
- getDefaultCharacteristics(name, atoms));
- }
-
- uint32_t getDefaultCharacteristics(
- StringRef name, const std::vector<const DefinedAtom *> &atoms) const;
-
- mutable llvm::BumpPtrAllocator _alloc;
- llvm::COFF::MachineTypes _machineType;
- const PECOFFLinkingContext &_ctx;
-};
-
-/// A DataDirectoryChunk represents data directory entries that follows the PE
-/// header in the output file. An entry consists of an 8 byte field that
-/// indicates a relative virtual address (the starting address of the entry data
-/// in memory) and 8 byte entry data size.
-class DataDirectoryChunk : public HeaderChunk {
-public:
- DataDirectoryChunk()
- : HeaderChunk(), _data(std::vector<llvm::object::data_directory>(16)) {}
-
- uint64_t size() const override {
- return sizeof(llvm::object::data_directory) * _data.size();
- }
-
- void setField(DataDirectoryIndex index, uint32_t addr, uint32_t size);
- void write(uint8_t *buffer) override;
-
-private:
- std::vector<llvm::object::data_directory> _data;
-};
-
-/// A BaseRelocChunk represents ".reloc" section.
-///
-/// .reloc section contains a list of addresses. If the PE/COFF loader decides
-/// to load the binary at a memory address different from its preferred base
-/// address, which is specified by ImageBase field in the COFF header, the
-/// loader needs to relocate the binary, so that all the addresses in the binary
-/// point to new locations. The loader will do that by fixing up the addresses
-/// specified by .reloc section.
-///
-/// The executable is almost always loaded at the preferred base address because
-/// it's loaded into an empty address space. The DLL is however an subject of
-/// load-time relocation because it may conflict with other DLLs or the
-/// executable.
-class BaseRelocChunk : public SectionChunk {
- typedef std::vector<std::unique_ptr<Chunk> > ChunkVectorT;
-
-public:
- BaseRelocChunk(ChunkVectorT &chunks, const PECOFFLinkingContext &ctx)
- : SectionChunk(kindSection, ".reloc", characteristics, ctx),
- _ctx(ctx), _contents(createContents(chunks)) {}
-
- void write(uint8_t *buffer) override {
- std::memcpy(buffer, &_contents[0], _contents.size());
- }
-
- uint64_t size() const override { return _contents.size(); }
-
-private:
- // When loaded into memory, reloc section should be readable and writable.
- static const uint32_t characteristics =
- llvm::COFF::IMAGE_SCN_MEM_READ |
- llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
- llvm::COFF::IMAGE_SCN_MEM_DISCARDABLE;
-
- std::vector<uint8_t> createContents(ChunkVectorT &chunks) const;
-
- // Returns a list of RVAs that needs to be relocated if the binary is loaded
- // at an address different from its preferred one.
- std::vector<BaseReloc> listRelocSites(ChunkVectorT &chunks) const;
-
- // Create the content of a relocation block.
- std::vector<uint8_t>
- createBaseRelocBlock(uint64_t pageAddr, const BaseReloc *begin,
- const BaseReloc *end) const;
-
- const PECOFFLinkingContext &_ctx;
- std::vector<uint8_t> _contents;
-};
-
-template <class PEHeader>
-PEHeaderChunk<PEHeader>::PEHeaderChunk(const PECOFFLinkingContext &ctx)
- : HeaderChunk() {
- // Set the size of the chunk and initialize the header with null bytes.
- _size = sizeof(llvm::COFF::PEMagic) + sizeof(_coffHeader) + sizeof(_peHeader);
- std::memset(&_coffHeader, 0, sizeof(_coffHeader));
- std::memset(&_peHeader, 0, sizeof(_peHeader));
-
- _coffHeader.Machine = ctx.getMachineType();
- _coffHeader.TimeDateStamp = time(nullptr);
-
- // Attributes of the executable.
- uint16_t characteristics = llvm::COFF::IMAGE_FILE_EXECUTABLE_IMAGE;
- if (!ctx.is64Bit())
- characteristics |= llvm::COFF::IMAGE_FILE_32BIT_MACHINE;
- if (ctx.isDll())
- characteristics |= llvm::COFF::IMAGE_FILE_DLL;
- if (ctx.getLargeAddressAware() || ctx.is64Bit())
- characteristics |= llvm::COFF::IMAGE_FILE_LARGE_ADDRESS_AWARE;
- if (ctx.getSwapRunFromCD())
- characteristics |= llvm::COFF::IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP;
- if (ctx.getSwapRunFromNet())
- characteristics |= llvm::COFF::IMAGE_FILE_NET_RUN_FROM_SWAP;
- if (!ctx.getBaseRelocationEnabled())
- characteristics |= llvm::COFF::IMAGE_FILE_RELOCS_STRIPPED;
-
- _coffHeader.Characteristics = characteristics;
-
- _peHeader.Magic = ctx.is64Bit() ? llvm::COFF::PE32Header::PE32_PLUS
- : llvm::COFF::PE32Header::PE32;
-
- // The address of the executable when loaded into memory. The default for
- // DLLs is 0x10000000. The default for executables is 0x400000.
- _peHeader.ImageBase = ctx.getBaseAddress();
-
- // Sections should be page-aligned when loaded into memory, which is 4KB on
- // x86.
- _peHeader.SectionAlignment = ctx.getSectionDefaultAlignment();
-
- // Sections in an executable file on disk should be sector-aligned (512 byte).
- _peHeader.FileAlignment = SECTOR_SIZE;
-
- // The version number of the resultant executable/DLL. The number is purely
- // informative, and neither the linker nor the loader won't use it. User can
- // set the value using /version command line option. Default is 0.0.
- PECOFFLinkingContext::Version imageVersion = ctx.getImageVersion();
- _peHeader.MajorImageVersion = imageVersion.majorVersion;
- _peHeader.MinorImageVersion = imageVersion.minorVersion;
-
- // The required Windows version number. This is the internal version and
- // shouldn't be confused with product name. Windows 7 is version 6.1 and
- // Windows 8 is 6.2, for example.
- PECOFFLinkingContext::Version minOSVersion = ctx.getMinOSVersion();
- _peHeader.MajorOperatingSystemVersion = minOSVersion.majorVersion;
- _peHeader.MinorOperatingSystemVersion = minOSVersion.minorVersion;
- _peHeader.MajorSubsystemVersion = minOSVersion.majorVersion;
- _peHeader.MinorSubsystemVersion = minOSVersion.minorVersion;
-
- _peHeader.Subsystem = ctx.getSubsystem();
-
- // Despite its name, DLL characteristics field has meaning both for
- // executables and DLLs. We are not very sure if the following bits must
- // be set, but regular binaries seem to have these bits, so we follow
- // them.
- uint16_t dllCharacteristics = 0;
- if (ctx.noSEH())
- dllCharacteristics |= llvm::COFF::IMAGE_DLL_CHARACTERISTICS_NO_SEH;
- if (ctx.isTerminalServerAware())
- dllCharacteristics |=
- llvm::COFF::IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE;
- if (ctx.isNxCompat())
- dllCharacteristics |= llvm::COFF::IMAGE_DLL_CHARACTERISTICS_NX_COMPAT;
- if (ctx.getDynamicBaseEnabled())
- dllCharacteristics |= llvm::COFF::IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE;
- if (!ctx.getAllowBind())
- dllCharacteristics |= llvm::COFF::IMAGE_DLL_CHARACTERISTICS_NO_BIND;
- if (!ctx.getAllowIsolation())
- dllCharacteristics |= llvm::COFF::IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION;
- if (ctx.getHighEntropyVA() && ctx.is64Bit())
- dllCharacteristics |= llvm::COFF::IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA;
- _peHeader.DLLCharacteristics = dllCharacteristics;
-
- _peHeader.SizeOfStackReserve = ctx.getStackReserve();
- _peHeader.SizeOfStackCommit = ctx.getStackCommit();
- _peHeader.SizeOfHeapReserve = ctx.getHeapReserve();
- _peHeader.SizeOfHeapCommit = ctx.getHeapCommit();
-
- // The number of data directory entries. We always have 16 entries.
- _peHeader.NumberOfRvaAndSize = 16;
-
- // The size of PE header including optional data directory.
- _coffHeader.SizeOfOptionalHeader = sizeof(PEHeader) +
- _peHeader.NumberOfRvaAndSize * sizeof(llvm::object::data_directory);
-}
-
-template <>
-void PEHeaderChunk<llvm::object::pe32_header>::setBaseOfData(uint32_t rva) {
- _peHeader.BaseOfData = rva;
-}
-
-template <>
-void PEHeaderChunk<llvm::object::pe32plus_header>::setBaseOfData(uint32_t rva) {
- // BaseOfData field does not exist in PE32+ header.
-}
-
-template <class PEHeader>
-void PEHeaderChunk<PEHeader>::write(uint8_t *buffer) {
- std::memcpy(buffer, llvm::COFF::PEMagic, sizeof(llvm::COFF::PEMagic));
- buffer += sizeof(llvm::COFF::PEMagic);
- std::memcpy(buffer, &_coffHeader, sizeof(_coffHeader));
- buffer += sizeof(_coffHeader);
- std::memcpy(buffer, &_peHeader, sizeof(_peHeader));
-}
-
-AtomChunk::AtomChunk(const PECOFFLinkingContext &ctx, StringRef sectionName,
- const std::vector<const DefinedAtom *> &atoms)
- : SectionChunk(kindAtomChunk, sectionName,
- computeCharacteristics(ctx, sectionName, atoms), ctx),
- _virtualAddress(0), _machineType(ctx.getMachineType()), _ctx(ctx) {
- for (auto *a : atoms)
- appendAtom(a);
-}
-
-void AtomChunk::write(uint8_t *buffer) {
- if (_atomLayouts.empty())
- return;
- if (getCharacteristics() & llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)
- return;
- if (getCharacteristics() & llvm::COFF::IMAGE_SCN_CNT_CODE) {
- // Fill the section with INT 3 (0xCC) rather than NUL, so that the
- // disassembler will not interpret a garbage between atoms as the beginning
- // of multi-byte machine code. This does not change the behavior of
- // resulting binary but help debugging.
- uint8_t *start = buffer + _atomLayouts.front()->_fileOffset;
- uint8_t *end = buffer + _atomLayouts.back()->_fileOffset;
- memset(start, 0xCC, end - start);
- }
-
- for (const auto *layout : _atomLayouts) {
- const DefinedAtom *atom = cast<DefinedAtom>(layout->_atom);
- ArrayRef<uint8_t> rawContent = atom->rawContent();
- std::memcpy(buffer + layout->_fileOffset, rawContent.data(),
- rawContent.size());
- }
-}
-
-// Add all atoms to the given map. This data will be used to do relocation.
-void
-AtomChunk::buildAtomRvaMap(std::map<const Atom *, uint64_t> &atomRva) const {
- for (const auto *layout : _atomLayouts)
- atomRva[layout->_atom] = layout->_virtualAddr;
-}
-
-static int getSectionIndex(uint64_t targetAddr,
- const std::vector<uint64_t> &sectionRva) {
- int i = 1;
- for (uint64_t rva : sectionRva) {
- if (targetAddr < rva)
- return i;
- ++i;
- }
- return i;
-}
-
-static uint32_t getSectionStartAddr(uint64_t targetAddr,
- const std::vector<uint64_t> &sectionRva) {
- // Scan the list of section start addresses to find the section start address
- // for the given RVA.
- for (int i = 0, e = sectionRva.size(); i < e; ++i)
- if (i == e - 1 || (sectionRva[i] <= targetAddr && targetAddr < sectionRva[i + 1]))
- return sectionRva[i];
- llvm_unreachable("Section missing");
-}
-
-static void applyThumbMoveImmediate(ulittle16_t *mov, uint16_t imm) {
- // MOVW(T3): |11110|i|10|0|1|0|0|imm4|0|imm3|Rd|imm8|
- // imm32 = zext imm4:i:imm3:imm8
- // MOVT(T1): |11110|i|10|1|1|0|0|imm4|0|imm3|Rd|imm8|
- // imm16 = imm4:i:imm3:imm8
- mov[0] =
- mov[0] | (((imm & 0x0800) >> 11) << 10) | (((imm & 0xf000) >> 12) << 0);
- mov[1] =
- mov[1] | (((imm & 0x0700) >> 8) << 12) | (((imm & 0x00ff) >> 0) << 0);
-}
-
-static void applyThumbBranchImmediate(ulittle16_t *bl, int32_t imm) {
- // BL(T1): |11110|S|imm10|11|J1|1|J2|imm11|
- // imm32 = sext S:I1:I2:imm10:imm11:'0'
- // B.W(T4): |11110|S|imm10|10|J1|1|J2|imm11|
- // imm32 = sext S:I1:I2:imm10:imm11:'0'
- //
- // I1 = ~(J1 ^ S), I2 = ~(J2 ^ S)
-
- assert((~abs(imm) & (-1 << 24)) && "bl/b.w out of range");
-
- uint32_t S = (imm < 0 ? 1 : 0);
- uint32_t J1 = ((~imm & 0x00800000) >> 23) ^ S;
- uint32_t J2 = ((~imm & 0x00400000) >> 22) ^ S;
-
- bl[0] = bl[0] | (((imm & 0x003ff000) >> 12) << 0) | (S << 10);
- bl[1] = bl[1] | (((imm & 0x00000ffe) >> 1) << 0) | (J2 << 11) | (J1 << 13);
-}
-
-void AtomChunk::applyRelocationsARM(uint8_t *Buffer,
- std::map<const Atom *, uint64_t> &AtomRVA,
- std::vector<uint64_t> &SectionRVA,
- uint64_t ImageBase) {
- Buffer = Buffer + _fileOffset;
- parallel_for_each(_atomLayouts.begin(), _atomLayouts.end(),
- [&](const AtomLayout *layout) {
- const DefinedAtom *Atom = cast<DefinedAtom>(layout->_atom);
- for (const Reference *R : *Atom) {
- if (R->kindNamespace() != Reference::KindNamespace::COFF)
- continue;
-
- bool AssumeTHUMBCode = false;
- if (auto Target = dyn_cast<DefinedAtom>(R->target()))
- AssumeTHUMBCode = Target->permissions() == DefinedAtom::permR_X ||
- Target->permissions() == DefinedAtom::permRWX;
-
- const auto AtomOffset = R->offsetInAtom();
- const auto FileOffset = layout->_fileOffset;
- const auto TargetAddr = AtomRVA[R->target()] | (AssumeTHUMBCode ? 1 : 0);
- auto RelocSite16 =
- reinterpret_cast<ulittle16_t *>(Buffer + FileOffset + AtomOffset);
- auto RelocSite32 =
- reinterpret_cast<ulittle32_t *>(Buffer + FileOffset + AtomOffset);
-
- switch (R->kindValue()) {
- default: llvm_unreachable("unsupported relocation type");
- case llvm::COFF::IMAGE_REL_ARM_ADDR32:
- *RelocSite32 = *RelocSite32 + TargetAddr + ImageBase;
- break;
- case llvm::COFF::IMAGE_REL_ARM_ADDR32NB:
- *RelocSite32 = *RelocSite32 + TargetAddr;
- break;
- case llvm::COFF::IMAGE_REL_ARM_MOV32T:
- applyThumbMoveImmediate(&RelocSite16[0], (TargetAddr + ImageBase) >> 0);
- applyThumbMoveImmediate(&RelocSite16[2], (TargetAddr + ImageBase) >> 16);
- break;
- case llvm::COFF::IMAGE_REL_ARM_BRANCH24T:
- // NOTE: the thumb bit will implicitly be truncated properly
- applyThumbBranchImmediate(RelocSite16,
- TargetAddr - AtomRVA[Atom] - AtomOffset - 4);
- break;
- case llvm::COFF::IMAGE_REL_ARM_BLX23T:
- // NOTE: the thumb bit will implicitly be truncated properly
- applyThumbBranchImmediate(RelocSite16,
- TargetAddr - AtomRVA[Atom] - AtomOffset - 4);
- break;
- }
- }
- });
-}
-
-void AtomChunk::applyRelocationsX86(uint8_t *buffer,
- std::map<const Atom *, uint64_t> &atomRva,
- std::vector<uint64_t> &sectionRva,
- uint64_t imageBaseAddress) {
- buffer += _fileOffset;
- parallel_for_each(_atomLayouts.begin(), _atomLayouts.end(),
- [&](const AtomLayout *layout) {
- const DefinedAtom *atom = cast<DefinedAtom>(layout->_atom);
- for (const Reference *ref : *atom) {
- // Skip if this reference is not for COFF relocation.
- if (ref->kindNamespace() != Reference::KindNamespace::COFF)
- continue;
- auto relocSite32 = reinterpret_cast<ulittle32_t *>(
- buffer + layout->_fileOffset + ref->offsetInAtom());
- auto relocSite16 = reinterpret_cast<ulittle16_t *>(relocSite32);
- const Atom *target = ref->target();
- uint64_t targetAddr = atomRva[target];
- // Also account for whatever offset is already stored at the relocation
- // site.
- switch (ref->kindValue()) {
- case llvm::COFF::IMAGE_REL_I386_ABSOLUTE:
- // This relocation is no-op.
- break;
- case llvm::COFF::IMAGE_REL_I386_DIR32:
- // Set target's 32-bit VA.
- if (auto *abs = dyn_cast<AbsoluteAtom>(target))
- *relocSite32 += abs->value();
- else
- *relocSite32 += targetAddr + imageBaseAddress;
- break;
- case llvm::COFF::IMAGE_REL_I386_DIR32NB:
- // Set target's 32-bit RVA.
- *relocSite32 += targetAddr;
- break;
- case llvm::COFF::IMAGE_REL_I386_REL32: {
- // Set 32-bit relative address of the target. This relocation is
- // usually used for relative branch or call instruction.
- uint32_t disp = atomRva[atom] + ref->offsetInAtom() + 4;
- *relocSite32 += targetAddr - disp;
- break;
- }
- case llvm::COFF::IMAGE_REL_I386_SECTION:
- // The 16-bit section index that contains the target symbol.
- *relocSite16 += getSectionIndex(targetAddr, sectionRva);
- break;
- case llvm::COFF::IMAGE_REL_I386_SECREL:
- // The 32-bit relative address from the beginning of the section that
- // contains the target symbol.
- *relocSite32 +=
- targetAddr - getSectionStartAddr(targetAddr, sectionRva);
- break;
- default:
- llvm::report_fatal_error("Unsupported relocation kind");
- }
- }
- });
-}
-
-void AtomChunk::applyRelocationsX64(uint8_t *buffer,
- std::map<const Atom *, uint64_t> &atomRva,
- std::vector<uint64_t> &sectionRva,
- uint64_t imageBase) {
- buffer += _fileOffset;
- parallel_for_each(_atomLayouts.begin(), _atomLayouts.end(),
- [&](const AtomLayout *layout) {
- const DefinedAtom *atom = cast<DefinedAtom>(layout->_atom);
- for (const Reference *ref : *atom) {
- if (ref->kindNamespace() != Reference::KindNamespace::COFF)
- continue;
-
- uint8_t *loc = buffer + layout->_fileOffset + ref->offsetInAtom();
- auto relocSite16 = reinterpret_cast<ulittle16_t *>(loc);
- auto relocSite32 = reinterpret_cast<ulittle32_t *>(loc);
- auto relocSite64 = reinterpret_cast<ulittle64_t *>(loc);
- uint64_t targetAddr = atomRva[ref->target()];
-
- switch (ref->kindValue()) {
- case llvm::COFF::IMAGE_REL_AMD64_ADDR64:
- *relocSite64 += targetAddr + imageBase;
- break;
- case llvm::COFF::IMAGE_REL_AMD64_ADDR32:
- *relocSite32 += targetAddr + imageBase;
- break;
- case llvm::COFF::IMAGE_REL_AMD64_ADDR32NB:
- *relocSite32 += targetAddr;
- break;
- case llvm::COFF::IMAGE_REL_AMD64_REL32:
- *relocSite32 += targetAddr - atomRva[atom] - ref->offsetInAtom() - 4;
- break;
- case llvm::COFF::IMAGE_REL_AMD64_REL32_1:
- *relocSite32 += targetAddr - atomRva[atom] - ref->offsetInAtom() - 5;
- break;
- case llvm::COFF::IMAGE_REL_AMD64_REL32_2:
- *relocSite32 += targetAddr - atomRva[atom] - ref->offsetInAtom() - 6;
- break;
- case llvm::COFF::IMAGE_REL_AMD64_REL32_3:
- *relocSite32 += targetAddr - atomRva[atom] - ref->offsetInAtom() - 7;
- break;
- case llvm::COFF::IMAGE_REL_AMD64_REL32_4:
- *relocSite32 += targetAddr - atomRva[atom] - ref->offsetInAtom() - 8;
- break;
- case llvm::COFF::IMAGE_REL_AMD64_REL32_5:
- *relocSite32 += targetAddr - atomRva[atom] - ref->offsetInAtom() - 9;
- break;
- case llvm::COFF::IMAGE_REL_AMD64_SECTION:
- *relocSite16 += getSectionIndex(targetAddr, sectionRva) - 1;
- break;
- case llvm::COFF::IMAGE_REL_AMD64_SECREL:
- *relocSite32 +=
- targetAddr - getSectionStartAddr(targetAddr, sectionRva);
- break;
- default:
- llvm::errs() << "Kind: " << (int)ref->kindValue() << "\n";
- llvm::report_fatal_error("Unsupported relocation kind");
- }
- }
- });
-}
-
-/// Print atom VAs. Used only for debugging.
-void AtomChunk::printAtomAddresses(uint64_t baseAddr) const {
- for (const auto *layout : _atomLayouts) {
- const DefinedAtom *atom = cast<DefinedAtom>(layout->_atom);
- uint64_t addr = layout->_virtualAddr;
- llvm::dbgs() << llvm::format("0x%08llx: ", addr + baseAddr)
- << (atom->name().empty() ? "(anonymous)" : atom->name())
- << "\n";
- }
-}
-
-/// List all virtual addresses (and not relative virtual addresses) that need
-/// to be fixed up if image base is relocated. The only relocation type that
-/// needs to be fixed is DIR32 on i386. REL32 is not (and should not be)
-/// fixed up because it's PC-relative.
-void AtomChunk::addBaseRelocations(std::vector<BaseReloc> &relocSites) const {
- for (const auto *layout : _atomLayouts) {
- const DefinedAtom *atom = cast<DefinedAtom>(layout->_atom);
- for (const Reference *ref : *atom) {
- if (ref->kindNamespace() != Reference::KindNamespace::COFF)
- continue;
-
- // An absolute symbol points to a fixed location in memory. Their
- // address should not be fixed at load time. One exception is ImageBase
- // because that's relative to run-time image base address.
- if (auto *abs = dyn_cast<AbsoluteAtom>(ref->target()))
- if (!abs->name().equals("__ImageBase") &&
- !abs->name().equals("___ImageBase"))
- continue;
-
- uint64_t address = layout->_virtualAddr + ref->offsetInAtom();
- switch (_machineType) {
- default: llvm_unreachable("unsupported machine type");
- case llvm::COFF::IMAGE_FILE_MACHINE_I386:
- if (ref->kindValue() == llvm::COFF::IMAGE_REL_I386_DIR32)
- relocSites.push_back(
- BaseReloc(address, llvm::COFF::IMAGE_REL_BASED_HIGHLOW));
- break;
- case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
- if (ref->kindValue() == llvm::COFF::IMAGE_REL_AMD64_ADDR64)
- relocSites.push_back(
- BaseReloc(address, llvm::COFF::IMAGE_REL_BASED_DIR64));
- break;
- case llvm::COFF::IMAGE_FILE_MACHINE_ARMNT:
- if (ref->kindValue() == llvm::COFF::IMAGE_REL_ARM_ADDR32)
- relocSites.push_back(
- BaseReloc(address, llvm::COFF::IMAGE_REL_BASED_HIGHLOW));
- else if (ref->kindValue() == llvm::COFF::IMAGE_REL_ARM_MOV32T)
- relocSites.push_back(
- BaseReloc(address, llvm::COFF::IMAGE_REL_BASED_ARM_MOV32T));
- break;
- }
- }
- }
-}
-
-void AtomChunk::setVirtualAddress(uint32_t rva) {
- SectionChunk::setVirtualAddress(rva);
- for (AtomLayout *layout : _atomLayouts)
- layout->_virtualAddr += rva;
-}
-
-uint64_t AtomChunk::getAtomVirtualAddress(StringRef name) const {
- for (auto atomLayout : _atomLayouts)
- if (atomLayout->_atom->name() == name)
- return atomLayout->_virtualAddr;
- return 0;
-}
-
-void DataDirectoryChunk::setField(DataDirectoryIndex index, uint32_t addr,
- uint32_t size) {
- llvm::object::data_directory &dir = _data[index];
- dir.RelativeVirtualAddress = addr;
- dir.Size = size;
-}
-
-void DataDirectoryChunk::write(uint8_t *buffer) {
- std::memcpy(buffer, &_data[0], size());
-}
-
-uint64_t AtomChunk::memAlign() const {
- // ReaderCOFF propagated the section alignment to the first atom in
- // the section. We restore that here.
- if (_atomLayouts.empty())
- return _ctx.getPageSize();
- int align = _ctx.getPageSize();
- for (auto atomLayout : _atomLayouts) {
- auto *atom = cast<const DefinedAtom>(atomLayout->_atom);
- align = std::max(align, 1 << atom->alignment().powerOf2);
- }
- return align;
-}
-
-void AtomChunk::appendAtom(const DefinedAtom *atom) {
- // Atom may have to be at a proper alignment boundary. If so, move the
- // pointer to make a room after the last atom before adding new one.
- _size = llvm::RoundUpToAlignment(_size, 1 << atom->alignment().powerOf2);
-
- // Create an AtomLayout and move the current pointer.
- auto *layout = new (_alloc) AtomLayout(atom, _size, _size);
- _atomLayouts.push_back(layout);
- _size += atom->size();
-}
-
-uint32_t AtomChunk::getDefaultCharacteristics(
- StringRef name, const std::vector<const DefinedAtom *> &atoms) const {
- const uint32_t code = llvm::COFF::IMAGE_SCN_CNT_CODE;
- const uint32_t execute = llvm::COFF::IMAGE_SCN_MEM_EXECUTE;
- const uint32_t read = llvm::COFF::IMAGE_SCN_MEM_READ;
- const uint32_t write = llvm::COFF::IMAGE_SCN_MEM_WRITE;
- const uint32_t data = llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
- const uint32_t bss = llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA;
- if (name == ".text")
- return code | execute | read;
- if (name == ".data")
- return data | read | write;
- if (name == ".rdata")
- return data | read;
- if (name == ".bss")
- return bss | read | write;
- assert(atoms.size() > 0);
- switch (atoms[0]->permissions()) {
- case DefinedAtom::permR__:
- return data | read;
- case DefinedAtom::permRW_:
- return data | read | write;
- case DefinedAtom::permR_X:
- return code | execute | read;
- case DefinedAtom::permRWX:
- return code | execute | read | write;
- default:
- llvm_unreachable("Unsupported permission");
- }
-}
-
-void SectionHeaderTableChunk::addSection(SectionChunk *chunk) {
- _sections.push_back(chunk);
-}
-
-uint64_t SectionHeaderTableChunk::size() const {
- return _sections.size() * sizeof(llvm::object::coff_section);
-}
-
-void SectionHeaderTableChunk::write(uint8_t *buffer) {
- uint64_t offset = 0;
- for (SectionChunk *chunk : _sections) {
- llvm::object::coff_section header = createSectionHeader(chunk);
- std::memcpy(buffer + offset, &header, sizeof(header));
- offset += sizeof(header);
- }
-}
-
-llvm::object::coff_section
-SectionHeaderTableChunk::createSectionHeader(SectionChunk *chunk) {
- llvm::object::coff_section header;
-
- // We have extended the COFF specification by allowing section names to be
- // greater than eight characters. We achieve this by adding the section names
- // to the string table. Binutils' linker, ld, performs the same trick.
- StringRef sectionName = chunk->getSectionName();
- std::memset(header.Name, 0, llvm::COFF::NameSize);
- if (uint32_t stringTableOffset = chunk->getStringTableOffset())
- sprintf(header.Name, "/%u", stringTableOffset);
- else
- std::strncpy(header.Name, sectionName.data(), sectionName.size());
-
- uint32_t characteristics = chunk->getCharacteristics();
- header.VirtualSize = chunk->size();
- header.VirtualAddress = chunk->getVirtualAddress();
- header.SizeOfRawData = chunk->onDiskSize();
- header.PointerToRelocations = 0;
- header.PointerToLinenumbers = 0;
- header.NumberOfRelocations = 0;
- header.NumberOfLinenumbers = 0;
- header.Characteristics = characteristics;
-
- if (characteristics & llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) {
- header.PointerToRawData = 0;
- } else {
- header.PointerToRawData = chunk->fileOffset();
- }
- return header;
-}
-
-/// Creates .reloc section content from the other sections. The content of
-/// .reloc is basically a list of relocation sites. The relocation sites are
-/// divided into blocks. Each block represents the base relocation for a 4K
-/// page.
-///
-/// By dividing 32 bit RVAs into blocks, COFF saves disk and memory space for
-/// the base relocation. A block consists of a 32 bit page RVA and 16 bit
-/// relocation entries which represent offsets in the page. That is a more
-/// compact representation than a simple vector of 32 bit RVAs.
-std::vector<uint8_t>
-BaseRelocChunk::createContents(ChunkVectorT &chunks) const {
- std::vector<uint8_t> contents;
- std::vector<BaseReloc> relocSites = listRelocSites(chunks);
-
- uint64_t mask = _ctx.getPageSize() - 1;
- parallel_sort(relocSites.begin(), relocSites.end(),
- [=](const BaseReloc &a, const BaseReloc &b) {
- return (a.addr & ~mask) < (b.addr & ~mask);
- });
-
- // Base relocations for the same memory page are grouped together
- // and passed to createBaseRelocBlock.
- for (auto it = relocSites.begin(), e = relocSites.end(); it != e;) {
- auto beginIt = it;
- uint64_t pageAddr = (beginIt->addr & ~mask);
- for (++it; it != e; ++it)
- if ((it->addr & ~mask) != pageAddr)
- break;
- const BaseReloc *begin = &*beginIt;
- const BaseReloc *end = begin + (it - beginIt);
- std::vector<uint8_t> block = createBaseRelocBlock(pageAddr, begin, end);
- contents.insert(contents.end(), block.begin(), block.end());
- }
- return contents;
-}
-
-// Returns a list of RVAs that needs to be relocated if the binary is loaded
-// at an address different from its preferred one.
-std::vector<BaseReloc>
-BaseRelocChunk::listRelocSites(ChunkVectorT &chunks) const {
- std::vector<BaseReloc> ret;
- for (auto &cp : chunks)
- if (AtomChunk *chunk = dyn_cast<AtomChunk>(&*cp))
- chunk->addBaseRelocations(ret);
- return ret;
-}
-
-// Create the content of a relocation block.
-std::vector<uint8_t>
-BaseRelocChunk::createBaseRelocBlock(uint64_t pageAddr,
- const BaseReloc *begin,
- const BaseReloc *end) const {
- // Relocation blocks should be padded with IMAGE_REL_I386_ABSOLUTE to be
- // aligned to a DWORD size boundary.
- uint32_t size = llvm::RoundUpToAlignment(
- sizeof(ulittle32_t) * 2 + sizeof(ulittle16_t) * (end - begin),
- sizeof(ulittle32_t));
- std::vector<uint8_t> contents(size);
- uint8_t *ptr = &contents[0];
-
- // The first four bytes is the page RVA.
- write32le(ptr, pageAddr);
- ptr += sizeof(ulittle32_t);
-
- // The second four bytes is the size of the block, including the the page
- // RVA and this size field.
- write32le(ptr, size);
- ptr += sizeof(ulittle32_t);
-
- uint64_t mask = _ctx.getPageSize() - 1;
- for (const BaseReloc *i = begin; i < end; ++i) {
- write16le(ptr, (i->type << 12) | (i->addr & mask));
- ptr += sizeof(ulittle16_t);
- }
- return contents;
-}
-
-} // end anonymous namespace
-
-class PECOFFWriter : public Writer {
-public:
- explicit PECOFFWriter(const PECOFFLinkingContext &context)
- : _ctx(context), _numSections(0), _imageSizeInMemory(_ctx.getPageSize()),
- _imageSizeOnDisk(0) {}
-
- template <class PEHeader> void build(const File &linkedFile);
- std::error_code writeFile(const File &linkedFile, StringRef path) override;
-
-private:
- void applyAllRelocations(uint8_t *bufferStart);
- void printAllAtomAddresses() const;
- void reorderSEHTableEntries(uint8_t *bufferStart);
- void reorderSEHTableEntriesX86(uint8_t *bufferStart);
- void reorderSEHTableEntriesX64(uint8_t *bufferStart);
-
- void addChunk(Chunk *chunk);
- void addSectionChunk(std::unique_ptr<SectionChunk> chunk,
- SectionHeaderTableChunk *table,
- StringTableChunk *stringTable);
- void setImageSizeOnDisk();
- uint64_t
- calcSectionSize(llvm::COFF::SectionCharacteristics sectionType) const;
-
- uint64_t calcSizeOfInitializedData() const {
- return calcSectionSize(llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA);
- }
-
- uint64_t calcSizeOfUninitializedData() const {
- return calcSectionSize(llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA);
- }
-
- uint64_t calcSizeOfCode() const {
- return calcSectionSize(llvm::COFF::IMAGE_SCN_CNT_CODE);
- }
-
- std::vector<std::unique_ptr<Chunk> > _chunks;
- const PECOFFLinkingContext &_ctx;
- uint32_t _numSections;
-
- // The size of the image in memory. This is initialized with
- // _ctx.getPageSize(), as the first page starting at ImageBase is usually left
- // unmapped. IIUC there's no technical reason to do so, but we'll follow that
- // convention so that we don't produce odd-looking binary.
- uint32_t _imageSizeInMemory;
-
- // The size of the image on disk. This is basically the sum of all chunks in
- // the output file with paddings between them.
- uint32_t _imageSizeOnDisk;
-
- // The map from atom to its relative virtual address.
- std::map<const Atom *, uint64_t> _atomRva;
-};
-
-StringRef customSectionName(const DefinedAtom *atom) {
- assert(atom->sectionChoice() == DefinedAtom::sectionCustomRequired);
- StringRef s = atom->customSectionName();
- size_t pos = s.find('$');
- return (pos == StringRef::npos) ? s : s.substr(0, pos);
-}
-
-StringRef chooseSectionByContent(const DefinedAtom *atom) {
- switch (atom->contentType()) {
- case DefinedAtom::typeCode:
- return ".text";
- case DefinedAtom::typeZeroFill:
- return ".bss";
- case DefinedAtom::typeData:
- if (atom->permissions() == DefinedAtom::permR__)
- return ".rdata";
- if (atom->permissions() == DefinedAtom::permRW_)
- return ".data";
- break;
- default:
- break;
- }
- llvm::errs() << "Atom: contentType=" << atom->contentType()
- << " permission=" << atom->permissions() << "\n";
- llvm::report_fatal_error("Failed to choose section based on content");
-}
-
-typedef std::map<StringRef, std::vector<const DefinedAtom *> > AtomVectorMap;
-
-void groupAtoms(const PECOFFLinkingContext &ctx, const File &file,
- AtomVectorMap &result) {
- for (const DefinedAtom *atom : file.defined()) {
- if (atom->sectionChoice() == DefinedAtom::sectionCustomRequired) {
- StringRef section = customSectionName(atom);
- result[ctx.getOutputSectionName(section)].push_back(atom);
- continue;
- }
- if (atom->sectionChoice() == DefinedAtom::sectionBasedOnContent) {
- StringRef section = chooseSectionByContent(atom);
- result[ctx.getOutputSectionName(section)].push_back(atom);
- continue;
- }
- llvm_unreachable("Unknown section choice");
- }
-}
-
-static const DefinedAtom *findTLSUsedSymbol(const PECOFFLinkingContext &ctx,
- const File &file) {
- StringRef sym = ctx.decorateSymbol("_tls_used");
- for (const DefinedAtom *atom : file.defined())
- if (atom->name() == sym)
- return atom;
- return nullptr;
-}
-
-// Create all chunks that consist of the output file.
-template <class PEHeader>
-void PECOFFWriter::build(const File &linkedFile) {
- AtomVectorMap atoms;
- groupAtoms(_ctx, linkedFile, atoms);
-
- // Create file chunks and add them to the list.
- auto *dosStub = new DOSStubChunk(_ctx);
- auto *peHeader = new PEHeaderChunk<PEHeader>(_ctx);
- auto *dataDirectory = new DataDirectoryChunk();
- auto *sectionTable = new SectionHeaderTableChunk();
- auto *stringTable = new StringTableChunk();
- addChunk(dosStub);
- addChunk(peHeader);
- addChunk(dataDirectory);
- addChunk(sectionTable);
- addChunk(stringTable);
-
- // Create sections and add the atoms to them.
- for (auto i : atoms) {
- StringRef sectionName = i.first;
- std::vector<const DefinedAtom *> &contents = i.second;
- std::unique_ptr<SectionChunk> section(
- new AtomChunk(_ctx, sectionName, contents));
- if (section->size() > 0)
- addSectionChunk(std::move(section), sectionTable, stringTable);
- }
-
- // Build atom to its RVA map.
- for (std::unique_ptr<Chunk> &cp : _chunks)
- if (AtomChunk *chunk = dyn_cast<AtomChunk>(&*cp))
- chunk->buildAtomRvaMap(_atomRva);
-
- // We know the addresses of all defined atoms that needs to be
- // relocated. So we can create the ".reloc" section which contains
- // all the relocation sites.
- if (_ctx.getBaseRelocationEnabled()) {
- std::unique_ptr<SectionChunk> baseReloc(new BaseRelocChunk(_chunks, _ctx));
- if (baseReloc->size()) {
- SectionChunk &ref = *baseReloc;
- addSectionChunk(std::move(baseReloc), sectionTable, stringTable);
- dataDirectory->setField(DataDirectoryIndex::BASE_RELOCATION_TABLE,
- ref.getVirtualAddress(), ref.size());
- }
- }
-
- setImageSizeOnDisk();
-
- if (stringTable->size()) {
- peHeader->setPointerToSymbolTable(stringTable->fileOffset());
- peHeader->setNumberOfSymbols(1);
- }
-
- for (std::unique_ptr<Chunk> &chunk : _chunks) {
- SectionChunk *section = dyn_cast<SectionChunk>(chunk.get());
- if (!section)
- continue;
- if (section->getSectionName() == ".text") {
- peHeader->setBaseOfCode(section->getVirtualAddress());
-
- // Find the virtual address of the entry point symbol if any. PECOFF spec
- // says that entry point for dll images is optional, in which case it must
- // be set to 0.
- if (_ctx.hasEntry()) {
- AtomChunk *atom = cast<AtomChunk>(section);
- uint64_t entryPointAddress =
- atom->getAtomVirtualAddress(_ctx.getEntrySymbolName());
-
- if (entryPointAddress) {
- // NOTE: ARM NT assumes a pure THUMB execution, so adjust the entry
- // point accordingly
- if (_ctx.getMachineType() == llvm::COFF::IMAGE_FILE_MACHINE_ARMNT)
- entryPointAddress |= 1;
- peHeader->setAddressOfEntryPoint(entryPointAddress);
- }
- } else {
- peHeader->setAddressOfEntryPoint(0);
- }
- }
- StringRef name = section->getSectionName();
- if (name == ".data") {
- peHeader->setBaseOfData(section->getVirtualAddress());
- continue;
- }
- DataDirectoryIndex ignore = DataDirectoryIndex(-1);
- DataDirectoryIndex idx = llvm::StringSwitch<DataDirectoryIndex>(name)
- .Case(".pdata", DataDirectoryIndex::EXCEPTION_TABLE)
- .Case(".rsrc", DataDirectoryIndex::RESOURCE_TABLE)
- .Case(".idata.a", DataDirectoryIndex::IAT)
- .Case(".idata.d", DataDirectoryIndex::IMPORT_TABLE)
- .Case(".edata", DataDirectoryIndex::EXPORT_TABLE)
- .Case(".loadcfg", DataDirectoryIndex::LOAD_CONFIG_TABLE)
- .Case(".didat.d", DataDirectoryIndex::DELAY_IMPORT_DESCRIPTOR)
- .Default(ignore);
- if (idx == ignore)
- continue;
- dataDirectory->setField(idx, section->getVirtualAddress(), section->size());
- }
-
- if (const DefinedAtom *atom = findTLSUsedSymbol(_ctx, linkedFile)) {
- dataDirectory->setField(DataDirectoryIndex::TLS_TABLE, _atomRva[atom],
- 0x18);
- }
-
- // Now that we know the size and file offset of sections. Set the file
- // header accordingly.
- peHeader->setSizeOfCode(calcSizeOfCode());
- peHeader->setSizeOfInitializedData(calcSizeOfInitializedData());
- peHeader->setSizeOfUninitializedData(calcSizeOfUninitializedData());
- peHeader->setNumberOfSections(_numSections);
- peHeader->setSizeOfImage(_imageSizeInMemory);
- peHeader->setSizeOfHeaders(sectionTable->fileOffset() + sectionTable->size());
-}
-
-std::error_code PECOFFWriter::writeFile(const File &linkedFile,
- StringRef path) {
- if (_ctx.is64Bit()) {
- this->build<llvm::object::pe32plus_header>(linkedFile);
- } else {
- this->build<llvm::object::pe32_header>(linkedFile);
- }
-
- uint64_t totalSize =
- _chunks.back()->fileOffset() + _chunks.back()->onDiskSize();
- std::unique_ptr<llvm::FileOutputBuffer> buffer;
- std::error_code ec = llvm::FileOutputBuffer::create(
- path, totalSize, buffer, llvm::FileOutputBuffer::F_executable);
- if (ec)
- return ec;
-
- for (std::unique_ptr<Chunk> &chunk : _chunks)
- chunk->write(buffer->getBufferStart() + chunk->fileOffset());
- applyAllRelocations(buffer->getBufferStart());
- reorderSEHTableEntries(buffer->getBufferStart());
- DEBUG(printAllAtomAddresses());
-
- if (_ctx.isDll())
- writeImportLibrary(_ctx);
-
- return buffer->commit();
-}
-
-/// Apply relocations to the output file buffer. This two pass. In the first
-/// pass, we visit all atoms to create a map from atom to its virtual
-/// address. In the second pass, we visit all relocation references to fix
-/// up addresses in the buffer.
-void PECOFFWriter::applyAllRelocations(uint8_t *bufferStart) {
- // Create the list of section start addresses. It's needed for
- // relocations of SECREL type.
- std::vector<uint64_t> sectionRva;
- for (auto &cp : _chunks)
- if (SectionChunk *section = dyn_cast<SectionChunk>(&*cp))
- sectionRva.push_back(section->getVirtualAddress());
-
- uint64_t base = _ctx.getBaseAddress();
- for (auto &cp : _chunks) {
- if (AtomChunk *chunk = dyn_cast<AtomChunk>(&*cp)) {
- switch (_ctx.getMachineType()) {
- default: llvm_unreachable("unsupported machine type");
- case llvm::COFF::IMAGE_FILE_MACHINE_ARMNT:
- chunk->applyRelocationsARM(bufferStart, _atomRva, sectionRva, base);
- break;
- case llvm::COFF::IMAGE_FILE_MACHINE_I386:
- chunk->applyRelocationsX86(bufferStart, _atomRva, sectionRva, base);
- break;
- case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
- chunk->applyRelocationsX64(bufferStart, _atomRva, sectionRva, base);
- break;
- }
- }
- }
-}
-
-/// Print atom VAs. Used only for debugging.
-void PECOFFWriter::printAllAtomAddresses() const {
- for (auto &cp : _chunks)
- if (AtomChunk *chunk = dyn_cast<AtomChunk>(&*cp))
- chunk->printAtomAddresses(_ctx.getBaseAddress());
-}
-
-void PECOFFWriter::reorderSEHTableEntries(uint8_t *bufferStart) {
- auto machineType = _ctx.getMachineType();
- if (machineType == llvm::COFF::IMAGE_FILE_MACHINE_I386)
- reorderSEHTableEntriesX86(bufferStart);
- if (machineType == llvm::COFF::IMAGE_FILE_MACHINE_AMD64)
- reorderSEHTableEntriesX64(bufferStart);
-}
-
-/// It seems that the entries in .sxdata must be sorted. This function is called
-/// after a COFF file image is created in memory and before it is written to
-/// disk. It is safe to reorder entries at this stage because the contents of
-/// the entries are RVAs and there's no reference to a .sxdata entry other than
-/// to the beginning of the section.
-void PECOFFWriter::reorderSEHTableEntriesX86(uint8_t *bufferStart) {
- for (std::unique_ptr<Chunk> &chunk : _chunks) {
- if (SectionChunk *section = dyn_cast<SectionChunk>(chunk.get())) {
- if (section->getSectionName() == ".sxdata") {
- int numEntries = section->size() / sizeof(ulittle32_t);
- ulittle32_t *begin = reinterpret_cast<ulittle32_t *>(bufferStart + section->fileOffset());
- ulittle32_t *end = begin + numEntries;
- std::sort(begin, end);
- }
- }
- }
-}
-
-/// The entries in .pdata must be sorted according to its BeginAddress field
-/// value. It's safe to do it because of the same reason as .sxdata.
-void PECOFFWriter::reorderSEHTableEntriesX64(uint8_t *bufferStart) {
- for (std::unique_ptr<Chunk> &chunk : _chunks) {
- if (SectionChunk *section = dyn_cast<SectionChunk>(chunk.get())) {
- if (section->getSectionName() != ".pdata")
- continue;
- int numEntries = section->size() / sizeof(coff_runtime_function_x64);
- coff_runtime_function_x64 *begin =
- (coff_runtime_function_x64 *)(bufferStart + section->fileOffset());
- coff_runtime_function_x64 *end = begin + numEntries;
- std::sort(begin, end, [](const coff_runtime_function_x64 &lhs,
- const coff_runtime_function_x64 &rhs) {
- return lhs.BeginAddress < rhs.BeginAddress;
- });
- }
- }
-}
-
-void PECOFFWriter::addChunk(Chunk *chunk) {
- _chunks.push_back(std::unique_ptr<Chunk>(chunk));
-}
-
-void PECOFFWriter::addSectionChunk(std::unique_ptr<SectionChunk> chunk,
- SectionHeaderTableChunk *table,
- StringTableChunk *stringTable) {
- table->addSection(chunk.get());
- _numSections++;
-
- StringRef sectionName = chunk->getSectionName();
- if (sectionName.size() > llvm::COFF::NameSize) {
- uint32_t stringTableOffset = stringTable->addSectionName(sectionName);
- chunk->setStringTableOffset(stringTableOffset);
- }
-
- // Compute and set the starting address of sections when loaded in
- // memory. They are different from positions on disk because sections need
- // to be sector-aligned on disk but page-aligned in memory.
- _imageSizeInMemory = llvm::RoundUpToAlignment(
- _imageSizeInMemory, chunk->memAlign());
- chunk->setVirtualAddress(_imageSizeInMemory);
- _imageSizeInMemory = llvm::RoundUpToAlignment(
- _imageSizeInMemory + chunk->size(), _ctx.getPageSize());
- _chunks.push_back(std::move(chunk));
-}
-
-void PECOFFWriter::setImageSizeOnDisk() {
- for (auto &chunk : _chunks) {
- // Compute and set the offset of the chunk in the output file.
- _imageSizeOnDisk =
- llvm::RoundUpToAlignment(_imageSizeOnDisk, chunk->align());
- chunk->setFileOffset(_imageSizeOnDisk);
- _imageSizeOnDisk += chunk->onDiskSize();
- }
-}
-
-uint64_t PECOFFWriter::calcSectionSize(
- llvm::COFF::SectionCharacteristics sectionType) const {
- uint64_t ret = 0;
- for (auto &cp : _chunks)
- if (SectionChunk *chunk = dyn_cast<SectionChunk>(&*cp))
- if (chunk->getCharacteristics() & sectionType)
- ret += chunk->onDiskSize();
- return ret;
-}
-
-} // end namespace pecoff
-
-std::unique_ptr<Writer> createWriterPECOFF(const PECOFFLinkingContext &info) {
- return std::unique_ptr<Writer>(new pecoff::PECOFFWriter(info));
-}
-
-} // end namespace lld
diff --git a/lib/ReaderWriter/YAML/Makefile b/lib/ReaderWriter/YAML/Makefile
deleted file mode 100644
index 739b6eae747a..000000000000
--- a/lib/ReaderWriter/YAML/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-##===- lld/lib/ReaderWriter/YAML/Makefile --------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LLD_LEVEL := ../../..
-LIBRARYNAME := lldYAML
-USEDLIBS = lldCore.a
-
-include $(LLD_LEVEL)/Makefile
diff --git a/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp b/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp
index 868b9497c4cc..78c6797b713f 100644
--- a/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp
+++ b/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp
@@ -25,6 +25,7 @@
#include "llvm/Support/ErrorHandling.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 <memory>
@@ -214,30 +215,14 @@ private:
NameToAtom _groupMap;
};
-// Used in NormalizedFile to hold the atoms lists.
-template <typename T> class AtomList : public lld::File::atom_collection<T> {
+/// Mapping of Atoms.
+template <typename T> class AtomList {
+ typedef lld::File::AtomVector<T> Ty;
+
public:
- virtual lld::File::atom_iterator<T> begin() const {
- return lld::File::atom_iterator<T>(
- *this,
- _atoms.empty() ? 0 : reinterpret_cast<const void *>(_atoms.data()));
- }
- virtual lld::File::atom_iterator<T> end() const {
- return lld::File::atom_iterator<T>(
- *this, _atoms.empty() ? 0 : reinterpret_cast<const void *>(
- _atoms.data() + _atoms.size()));
- }
- virtual const T *deref(const void *it) const {
- return *reinterpret_cast<const T *const *>(it);
- }
- virtual void next(const void *&it) const {
- const T *const *p = reinterpret_cast<const T *const *>(it);
- ++p;
- it = reinterpret_cast<const void *>(p);
- }
- virtual void push_back(const T *element) { _atoms.push_back(element); }
- virtual uint64_t size() const { return _atoms.size(); }
- std::vector<const T *> _atoms;
+ typename Ty::iterator begin() { return _atoms.begin(); }
+ typename Ty::iterator end() { return _atoms.end(); }
+ Ty _atoms;
};
/// Mapping of kind: field in yaml files.
@@ -270,7 +255,7 @@ struct RefKind {
Reference::KindValue value;
};
-} // namespace anon
+} // anonymous namespace
LLVM_YAML_IS_SEQUENCE_VECTOR(ArchMember)
LLVM_YAML_IS_SEQUENCE_VECTOR(const lld::Reference *)
@@ -377,6 +362,9 @@ template <> struct ScalarEnumerationTraits<lld::DefinedAtom::CodeModel> {
io.enumCase(value, "mips-micro-pic", lld::DefinedAtom::codeMipsMicroPIC);
io.enumCase(value, "mips-16", lld::DefinedAtom::codeMips16);
io.enumCase(value, "arm-thumb", lld::DefinedAtom::codeARMThumb);
+ io.enumCase(value, "arm-a", lld::DefinedAtom::codeARM_a);
+ io.enumCase(value, "arm-d", lld::DefinedAtom::codeARM_d);
+ io.enumCase(value, "arm-t", lld::DefinedAtom::codeARM_t);
}
};
@@ -449,6 +437,7 @@ template <> struct ScalarEnumerationTraits<lld::DefinedAtom::ContentType> {
io.enumCase(value, "no-alloc", DefinedAtom::typeNoAlloc);
io.enumCase(value, "group-comdat", DefinedAtom::typeGroupComdat);
io.enumCase(value, "gnu-linkonce", DefinedAtom::typeGnuLinkOnce);
+ io.enumCase(value, "sectcreate", DefinedAtom::typeSectCreate);
}
};
@@ -478,15 +467,15 @@ struct ScalarEnumerationTraits<lld::SharedLibraryAtom::Type> {
/// This is a custom formatter for lld::DefinedAtom::Alignment. Values look
/// like:
-/// 2^3 # 8-byte aligned
-/// 7 mod 2^4 # 16-byte aligned plus 7 bytes
+/// 8 # 8-byte aligned
+/// 7 mod 16 # 16-byte aligned plus 7 bytes
template <> struct ScalarTraits<lld::DefinedAtom::Alignment> {
static void output(const lld::DefinedAtom::Alignment &value, void *ctxt,
raw_ostream &out) {
if (value.modulus == 0) {
- out << llvm::format("2^%d", value.powerOf2);
+ out << llvm::format("%d", value.value);
} else {
- out << llvm::format("%d mod 2^%d", value.modulus, value.powerOf2);
+ out << llvm::format("%d mod %d", value.modulus, value.value);
}
}
@@ -505,16 +494,12 @@ template <> struct ScalarTraits<lld::DefinedAtom::Alignment> {
scalar = scalar.drop_front(modStart + 3);
scalar = scalar.ltrim();
}
- if (!scalar.startswith("2^")) {
- return "malformed alignment";
- }
- StringRef powerStr = scalar.drop_front(2);
unsigned int power;
- if (powerStr.getAsInteger(0, power)) {
+ if (scalar.getAsInteger(0, power)) {
return "malformed alignment power";
}
- value.powerOf2 = power;
- if (value.modulus > (1 << value.powerOf2)) {
+ value.value = power;
+ if (value.modulus >= power) {
return "malformed alignment, modulus too large for power";
}
return StringRef(); // returning empty string means success
@@ -598,19 +583,23 @@ template <> struct MappingTraits<const lld::File *> {
const lld::File *denormalize(IO &io) { return this; }
- const atom_collection<lld::DefinedAtom> &defined() const override {
+ const AtomVector<lld::DefinedAtom> &defined() const override {
return _noDefinedAtoms;
}
- const atom_collection<lld::UndefinedAtom> &undefined() const override {
+
+ const AtomVector<lld::UndefinedAtom> &undefined() const override {
return _noUndefinedAtoms;
}
- virtual const atom_collection<lld::SharedLibraryAtom> &
+
+ const AtomVector<lld::SharedLibraryAtom> &
sharedLibrary() const override {
return _noSharedLibraryAtoms;
}
- const atom_collection<lld::AbsoluteAtom> &absolute() const override {
+
+ const AtomVector<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()) {
@@ -630,7 +619,7 @@ template <> struct MappingTraits<const lld::File *> {
return nullptr;
}
- virtual std::error_code
+ std::error_code
parseAllMembers(std::vector<std::unique_ptr<File>> &result) override {
return std::error_code();
}
@@ -646,28 +635,31 @@ template <> struct MappingTraits<const lld::File *> {
: File(file->path(), kindObject), _io(io),
_rnb(new RefNameBuilder(*file)), _path(file->path()) {
for (const lld::DefinedAtom *a : file->defined())
- _definedAtoms.push_back(a);
+ _definedAtoms._atoms.push_back(a);
for (const lld::UndefinedAtom *a : file->undefined())
- _undefinedAtoms.push_back(a);
+ _undefinedAtoms._atoms.push_back(a);
for (const lld::SharedLibraryAtom *a : file->sharedLibrary())
- _sharedLibraryAtoms.push_back(a);
+ _sharedLibraryAtoms._atoms.push_back(a);
for (const lld::AbsoluteAtom *a : file->absolute())
- _absoluteAtoms.push_back(a);
+ _absoluteAtoms._atoms.push_back(a);
}
const lld::File *denormalize(IO &io);
- const atom_collection<lld::DefinedAtom> &defined() const override {
- return _definedAtoms;
+ const AtomVector<lld::DefinedAtom> &defined() const override {
+ return _definedAtoms._atoms;
}
- const atom_collection<lld::UndefinedAtom> &undefined() const override {
- return _undefinedAtoms;
+
+ const AtomVector<lld::UndefinedAtom> &undefined() const override {
+ return _undefinedAtoms._atoms;
}
- virtual const atom_collection<lld::SharedLibraryAtom> &
+
+ const AtomVector<lld::SharedLibraryAtom> &
sharedLibrary() const override {
- return _sharedLibraryAtoms;
+ return _sharedLibraryAtoms._atoms;
}
- const atom_collection<lld::AbsoluteAtom> &absolute() const override {
- return _absoluteAtoms;
+
+ const AtomVector<lld::AbsoluteAtom> &absolute() const override {
+ return _absoluteAtoms._atoms;
}
// Allocate a new copy of this string in _storage, so the strings
@@ -795,7 +787,7 @@ template <> struct MappingTraits<const lld::DefinedAtom *> {
public:
NormalizedAtom(IO &io)
: _file(fileFromContext(io)), _name(), _refName(), _contentType(),
- _alignment(0), _content(), _references(), _isGroupChild(false) {
+ _alignment(1), _content(), _references(), _isGroupChild(false) {
static uint32_t ordinalCounter = 1;
_ordinal = ordinalCounter++;
}
@@ -941,7 +933,7 @@ template <> struct MappingTraits<const lld::DefinedAtom *> {
DefinedAtom::interposeNo);
io.mapOptional("merge", keys->_merge, DefinedAtom::mergeNo);
io.mapOptional("alignment", keys->_alignment,
- DefinedAtom::Alignment(0));
+ DefinedAtom::Alignment(1));
io.mapOptional("section-choice", keys->_sectionChoice,
DefinedAtom::sectionBasedOnContent);
io.mapOptional("section-name", keys->_sectionName, StringRef());
@@ -1246,7 +1238,7 @@ namespace yaml {
class Writer : public lld::Writer {
public:
- Writer(const LinkingContext &context) : _context(context) {}
+ Writer(const LinkingContext &context) : _ctx(context) {}
std::error_code writeFile(const lld::File &file, StringRef outPath) override {
// Create stream to path.
@@ -1257,8 +1249,8 @@ public:
// Create yaml Output writer, using yaml options for context.
YamlContext yamlContext;
- yamlContext._linkingContext = &_context;
- yamlContext._registry = &_context.registry();
+ yamlContext._ctx = &_ctx;
+ yamlContext._registry = &_ctx.registry();
llvm::yaml::Output yout(out, &yamlContext);
// Write yaml output.
@@ -1269,7 +1261,7 @@ public:
}
private:
- const LinkingContext &_context;
+ const LinkingContext &_ctx;
};
} // end namespace yaml
@@ -1287,7 +1279,6 @@ class NativeYamlIOTaggedDocumentHandler : public YamlIOTaggedDocumentHandler {
}
};
-
/// Handles !archive tagged yaml documents.
class ArchiveYamlIOTaggedDocumentHandler : public YamlIOTaggedDocumentHandler {
bool handledDocTag(llvm::yaml::IO &io, const lld::File *&file) const override {
@@ -1299,19 +1290,18 @@ class ArchiveYamlIOTaggedDocumentHandler : public YamlIOTaggedDocumentHandler {
}
};
-
-
class YAMLReader : public Reader {
public:
YAMLReader(const Registry &registry) : _registry(registry) {}
- bool canParse(file_magic, StringRef ext, const MemoryBuffer &) const override {
- return (ext.equals(".objtxt") || ext.equals(".yaml"));
+ bool canParse(file_magic magic, MemoryBufferRef mb) const override {
+ StringRef name = mb.getBufferIdentifier();
+ return name.endswith(".objtxt") || name.endswith(".yaml");
}
- std::error_code
- loadFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &,
- std::vector<std::unique_ptr<File>> &result) const override {
+ ErrorOr<std::unique_ptr<File>>
+ loadFile(std::unique_ptr<MemoryBuffer> mb,
+ const class Registry &) const override {
// Create YAML Input Reader.
YamlContext yamlContext;
yamlContext._registry = &_registry;
@@ -1321,20 +1311,19 @@ public:
// Fill vector with File objects created by parsing yaml.
std::vector<const lld::File *> createdFiles;
yin >> createdFiles;
+ assert(createdFiles.size() == 1);
// Error out now if there were parsing errors.
if (yin.error())
return make_error_code(lld::YamlReaderError::illegal_value);
std::shared_ptr<MemoryBuffer> smb(mb.release());
- for (const File *file : createdFiles) {
- // Note: loadFile() should return vector of *const* File
- File *f = const_cast<File *>(file);
- f->setLastError(std::error_code());
- f->setSharedMemoryBuffer(smb);
- result.emplace_back(f);
- }
- return make_error_code(lld::YamlReaderError::success);
+ const File *file = createdFiles[0];
+ // Note: loadFile() should return vector of *const* File
+ File *f = const_cast<File *>(file);
+ f->setLastError(std::error_code());
+ f->setSharedMemoryBuffer(smb);
+ return std::unique_ptr<File>(f);
}
private: