aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2015-12-30 11:57:38 +0000
committerDimitry Andric <dim@FreeBSD.org>2015-12-30 11:57:38 +0000
commit5a5c549fe9a3fef595297bd21d36bed8409dc37d (patch)
treea964c8f5ac85b7b641cac022c5f9bf4eed3d2b9b /lib
parentfb911942f1434f3d1750f83f25f5e42c80e60638 (diff)
downloadsrc-5a5c549fe9a3fef595297bd21d36bed8409dc37d.tar.gz
src-5a5c549fe9a3fef595297bd21d36bed8409dc37d.zip
Vendor import of lld trunk r256633:vendor/lld/lld-trunk-r256633
Notes
Notes: svn path=/vendor/lld/dist/; revision=292934 svn path=/vendor/lld/lld-trunk-r256633/; revision=292935; tag=vendor/lld/lld-trunk-r256633
Diffstat (limited to 'lib')
-rw-r--r--lib/Config/Makefile13
-rw-r--r--lib/Core/DefinedAtom.cpp1
-rw-r--r--lib/Core/Error.cpp52
-rw-r--r--lib/Core/File.cpp8
-rw-r--r--lib/Core/LinkingContext.cpp8
-rw-r--r--lib/Core/Makefile13
-rw-r--r--lib/Core/Reader.cpp16
-rw-r--r--lib/Core/Resolver.cpp57
-rw-r--r--lib/Core/SymbolTable.cpp13
-rw-r--r--lib/Core/TODO.txt18
-rw-r--r--lib/Core/Writer.cpp4
-rw-r--r--lib/Driver/CMakeLists.txt9
-rw-r--r--lib/Driver/CoreDriver.cpp23
-rw-r--r--lib/Driver/DarwinLdDriver.cpp234
-rw-r--r--lib/Driver/DarwinLdOptions.td22
-rw-r--r--lib/Driver/Driver.cpp82
-rw-r--r--lib/Driver/GnuLdDriver.cpp263
-rw-r--r--lib/Driver/GnuLdOptions.td67
-rw-r--r--lib/Driver/Makefile38
-rw-r--r--lib/Driver/TODO.rst2
-rw-r--r--lib/Driver/UniversalDriver.cpp71
-rw-r--r--lib/Driver/WinLinkDriver.cpp1371
-rw-r--r--lib/Driver/WinLinkModuleDef.cpp295
-rw-r--r--lib/Driver/WinLinkOptions.td120
-rw-r--r--lib/Makefile16
-rw-r--r--lib/ReaderWriter/CMakeLists.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
237 files changed, 14355 insertions, 19887 deletions
diff --git a/lib/Config/Makefile b/lib/Config/Makefile
deleted file mode 100644
index b3c57f81418f..000000000000
--- a/lib/Config/Makefile
+++ /dev/null
@@ -1,13 +0,0 @@
-##===- lib/Config/Makefile ---------------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LLD_LEVEL := ../..
-LIBRARYNAME := lldConfig
-
-include $(LLD_LEVEL)/Makefile
diff --git a/lib/Core/DefinedAtom.cpp b/lib/Core/DefinedAtom.cpp
index b3f81ca65a91..f1d308088ed4 100644
--- a/lib/Core/DefinedAtom.cpp
+++ b/lib/Core/DefinedAtom.cpp
@@ -76,6 +76,7 @@ DefinedAtom::ContentPermissions DefinedAtom::permissions(ContentType type) {
case typeGnuLinkOnce:
case typeUnknown:
case typeTempLTO:
+ case typeSectCreate:
return permUnknown;
}
llvm_unreachable("unknown content type");
diff --git a/lib/Core/Error.cpp b/lib/Core/Error.cpp
index 24809c3869e5..3b7733746dcd 100644
--- a/lib/Core/Error.cpp
+++ b/lib/Core/Error.cpp
@@ -16,39 +16,6 @@
using namespace lld;
-class _NativeReaderErrorCategory : public std::error_category {
-public:
- const char* name() const LLVM_NOEXCEPT override {
- return "lld.native.reader";
- }
-
- std::string message(int ev) const override {
- switch (static_cast<NativeReaderError>(ev)) {
- case NativeReaderError::success:
- return "Success";
- case NativeReaderError::unknown_file_format:
- return "Unknown file format";
- case NativeReaderError::file_too_short:
- return "file truncated";
- case NativeReaderError::file_malformed:
- return "file malformed";
- case NativeReaderError::memory_error:
- return "out of memory";
- case NativeReaderError::unknown_chunk_type:
- return "unknown chunk type";
- case NativeReaderError::conflicting_target_machine:
- return "conflicting target machine";
- }
- llvm_unreachable("An enumerator of NativeReaderError does not have a "
- "message defined.");
- }
-};
-
-const std::error_category &lld::native_reader_category() {
- static _NativeReaderErrorCategory o;
- return o;
-}
-
class _YamlReaderErrorCategory : public std::error_category {
public:
const char* name() const LLVM_NOEXCEPT override {
@@ -57,8 +24,6 @@ public:
std::string message(int ev) const override {
switch (static_cast<YamlReaderError>(ev)) {
- case YamlReaderError::success:
- return "Success";
case YamlReaderError::unknown_keyword:
return "Unknown keyword found in yaml file";
case YamlReaderError::illegal_value:
@@ -91,6 +56,14 @@ public:
case LinkerScriptReaderError::unrecognized_function_in_expr:
return "Unrecognized function call when evaluating linker script "
"expression";
+ case LinkerScriptReaderError::unknown_phdr_ids:
+ return "Unknown header identifiers (missing in PHDRS command) are used";
+ case LinkerScriptReaderError::extra_program_phdr:
+ return "Extra program header is found";
+ case LinkerScriptReaderError::misplaced_program_phdr:
+ return "Program header must precede load segments";
+ case LinkerScriptReaderError::program_phdr_wrong_phdrs:
+ return "Program header has invalid PHDRS attribute";
}
llvm_unreachable("An enumerator of LinkerScriptReaderError does not have a "
"message defined.");
@@ -102,7 +75,6 @@ const std::error_category &lld::LinkerScriptReaderCategory() {
return o;
}
-
namespace lld {
/// Temporary class to enable make_dynamic_error_code() until
@@ -110,7 +82,7 @@ namespace lld {
/// other than error_code.
class dynamic_error_category : public std::error_category {
public:
- ~dynamic_error_category() LLVM_NOEXCEPT {}
+ ~dynamic_error_category() override = default;
const char *name() const LLVM_NOEXCEPT override {
return "lld.dynamic_error";
@@ -140,6 +112,10 @@ private:
static dynamic_error_category categorySingleton;
+std::error_code make_dynamic_error_code(const char *msg) {
+ return make_dynamic_error_code(StringRef(msg));
+}
+
std::error_code make_dynamic_error_code(StringRef msg) {
return std::error_code(categorySingleton.add(msg), categorySingleton);
}
@@ -148,4 +124,4 @@ std::error_code make_dynamic_error_code(const Twine &msg) {
return std::error_code(categorySingleton.add(msg.str()), categorySingleton);
}
-}
+} // namespace lld
diff --git a/lib/Core/File.cpp b/lib/Core/File.cpp
index dbac86b368aa..ac95f1016797 100644
--- a/lib/Core/File.cpp
+++ b/lib/Core/File.cpp
@@ -15,10 +15,10 @@ namespace lld {
File::~File() {}
-File::atom_collection_empty<DefinedAtom> File::_noDefinedAtoms;
-File::atom_collection_empty<UndefinedAtom> File::_noUndefinedAtoms;
-File::atom_collection_empty<SharedLibraryAtom> File::_noSharedLibraryAtoms;
-File::atom_collection_empty<AbsoluteAtom> File::_noAbsoluteAtoms;
+File::AtomVector<DefinedAtom> File::_noDefinedAtoms;
+File::AtomVector<UndefinedAtom> File::_noUndefinedAtoms;
+File::AtomVector<SharedLibraryAtom> File::_noSharedLibraryAtoms;
+File::AtomVector<AbsoluteAtom> File::_noAbsoluteAtoms;
std::error_code File::parse() {
std::lock_guard<std::mutex> lock(_parseMutex);
diff --git a/lib/Core/LinkingContext.cpp b/lib/Core/LinkingContext.cpp
index c6656b935916..cbcf25c17df2 100644
--- a/lib/Core/LinkingContext.cpp
+++ b/lib/Core/LinkingContext.cpp
@@ -24,7 +24,7 @@ LinkingContext::LinkingContext()
_warnIfCoalesableAtomsHaveDifferentCanBeNull(false),
_warnIfCoalesableAtomsHaveDifferentLoadName(false),
_printRemainingUndefines(true), _allowRemainingUndefines(false),
- _logInputFiles(false), _allowShlibUndefines(false),
+ _logInputFiles(false), _allowShlibUndefines(true),
_outputFileType(OutputFileType::Default), _nextOrdinal(0) {}
LinkingContext::~LinkingContext() {}
@@ -37,9 +37,9 @@ std::error_code LinkingContext::writeFile(const File &linkedFile) const {
return this->writer().writeFile(linkedFile, _outputPath);
}
-bool LinkingContext::createImplicitFiles(
- std::vector<std::unique_ptr<File> > &result) {
- return this->writer().createImplicitFiles(result);
+void LinkingContext::createImplicitFiles(
+ std::vector<std::unique_ptr<File>> &result) {
+ this->writer().createImplicitFiles(result);
}
std::unique_ptr<File> LinkingContext::createEntrySymbolFile() const {
diff --git a/lib/Core/Makefile b/lib/Core/Makefile
deleted file mode 100644
index 042d01a1e1b3..000000000000
--- a/lib/Core/Makefile
+++ /dev/null
@@ -1,13 +0,0 @@
-##===- lld/lib/Core/Makefile ---------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LLD_LEVEL := ../..
-LIBRARYNAME := lldCore
-
-include $(LLD_LEVEL)/Makefile
diff --git a/lib/Core/Reader.cpp b/lib/Core/Reader.cpp
index 6f8b8cbd1bf8..6069093d211e 100644
--- a/lib/Core/Reader.cpp
+++ b/lib/Core/Reader.cpp
@@ -13,7 +13,6 @@
#include "llvm/Support/Errc.h"
#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/Path.h"
#include <memory>
#include <system_error>
@@ -29,22 +28,17 @@ void Registry::add(std::unique_ptr<YamlIOTaggedDocumentHandler> handler) {
_yamlHandlers.push_back(std::move(handler));
}
-std::error_code
-Registry::loadFile(std::unique_ptr<MemoryBuffer> mb,
- std::vector<std::unique_ptr<File>> &result) const {
- // Get file type.
+ErrorOr<std::unique_ptr<File>>
+Registry::loadFile(std::unique_ptr<MemoryBuffer> mb) const {
+ // Get file magic.
StringRef content(mb->getBufferStart(), mb->getBufferSize());
llvm::sys::fs::file_magic fileType = llvm::sys::fs::identify_magic(content);
- // Get file extension.
- StringRef extension = llvm::sys::path::extension(mb->getBufferIdentifier());
// Ask each registered reader if it can handle this file type or extension.
for (const std::unique_ptr<Reader> &reader : _readers) {
- if (!reader->canParse(fileType, extension, *mb))
+ if (!reader->canParse(fileType, mb->getMemBufferRef()))
continue;
- if (std::error_code ec = reader->loadFile(std::move(mb), *this, result))
- return ec;
- return std::error_code();
+ return reader->loadFile(std::move(mb), *this);
}
// No Reader could parse this file.
diff --git a/lib/Core/Resolver.cpp b/lib/Core/Resolver.cpp
index 393a7ef2bfc8..8f89856c4a47 100644
--- a/lib/Core/Resolver.cpp
+++ b/lib/Core/Resolver.cpp
@@ -153,7 +153,6 @@ void Resolver::maybeAddSectionGroupOrGnuLinkOnce(const DefinedAtom &atom) {
llvm::errs() << "SymbolTable: error while merging " << atom.name()
<< "\n";
llvm::report_fatal_error("duplicate symbol error");
- return;
}
for (const Reference *r : atom) {
@@ -180,6 +179,8 @@ void Resolver::doDefinedAtom(const DefinedAtom &atom) {
<< atom.ordinal()
<< ", name="
<< atom.name()
+ << ", type="
+ << atom.contentType()
<< "\n");
// add to list of known atoms
@@ -295,11 +296,15 @@ void Resolver::updatePreloadArchiveMap() {
// Keep adding atoms until _ctx.getNextFile() returns an error. This
// function is where undefined atoms are resolved.
bool Resolver::resolveUndefines() {
+ DEBUG_WITH_TYPE("resolver",
+ llvm::dbgs() << "******** Resolving undefines:\n");
ScopedTask task(getDefaultDomain(), "resolveUndefines");
int index = 0;
std::set<File *> seen;
for (;;) {
bool undefAdded = false;
+ DEBUG_WITH_TYPE("resolver",
+ llvm::dbgs() << "Loading file #" << index << "\n");
File *file = getFile(index);
if (!file)
return true;
@@ -308,6 +313,8 @@ bool Resolver::resolveUndefines() {
<< ": " << ec.message() << "\n";
return false;
}
+ DEBUG_WITH_TYPE("resolver",
+ llvm::dbgs() << "Loaded file: " << file->path() << "\n");
file->beforeLink();
updatePreloadArchiveMap();
switch (file->kind()) {
@@ -340,6 +347,8 @@ bool Resolver::resolveUndefines() {
// switch all references to undefined or coalesced away atoms
// to the new defined atom
void Resolver::updateReferences() {
+ DEBUG_WITH_TYPE("resolver",
+ llvm::dbgs() << "******** Updating references:\n");
ScopedTask task(getDefaultDomain(), "updateReferences");
for (const Atom *atom : _atoms) {
if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom)) {
@@ -388,6 +397,8 @@ static bool isBackref(const Reference *ref) {
// remove all atoms not actually used
void Resolver::deadStripOptimize() {
+ DEBUG_WITH_TYPE("resolver",
+ llvm::dbgs() << "******** Dead stripping unused atoms:\n");
ScopedTask task(getDefaultDomain(), "deadStripOptimize");
// only do this optimization with -dead_strip
if (!_ctx.deadStrip())
@@ -433,6 +444,9 @@ void Resolver::deadStripOptimize() {
// error out if some undefines remain
bool Resolver::checkUndefines() {
+ DEBUG_WITH_TYPE("resolver",
+ llvm::dbgs() << "******** Checking for undefines:\n");
+
// build vector of remaining undefined symbols
std::vector<const UndefinedAtom *> undefinedAtoms = _symbolTable.undefines();
if (_ctx.deadStrip()) {
@@ -479,6 +493,8 @@ bool Resolver::checkUndefines() {
// remove from _atoms all coaleseced away atoms
void Resolver::removeCoalescedAwayAtoms() {
+ DEBUG_WITH_TYPE("resolver",
+ llvm::dbgs() << "******** Removing coalesced away atoms:\n");
ScopedTask task(getDefaultDomain(), "removeCoalescedAwayAtoms");
_atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), [&](const Atom *a) {
return _symbolTable.isCoalescedAway(a) || _deadAtoms.count(a);
@@ -487,28 +503,53 @@ void Resolver::removeCoalescedAwayAtoms() {
}
bool Resolver::resolve() {
+ DEBUG_WITH_TYPE("resolver",
+ llvm::dbgs() << "******** Resolving atom references:\n");
updatePreloadArchiveMap();
if (!resolveUndefines())
return false;
updateReferences();
deadStripOptimize();
- if (checkUndefines())
- if (!_ctx.allowRemainingUndefines())
+ if (checkUndefines()) {
+ DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "Found undefines... ");
+ if (!_ctx.allowRemainingUndefines()) {
+ DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "which we don't allow\n");
return false;
+ }
+ DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "which we are ok with\n");
+ }
removeCoalescedAwayAtoms();
_result->addAtoms(_atoms);
+ DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "******** Finished resolver\n");
return true;
}
void Resolver::MergedFile::addAtoms(std::vector<const Atom *> &all) {
ScopedTask task(getDefaultDomain(), "addAtoms");
DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "Resolver final atom list:\n");
+
for (const Atom *atom : all) {
- DEBUG_WITH_TYPE("resolver", llvm::dbgs()
- << llvm::format(" 0x%09lX", atom)
- << ", name="
- << atom->name()
- << "\n");
+#ifndef NDEBUG
+ if (auto *definedAtom = dyn_cast<DefinedAtom>(atom)) {
+ DEBUG_WITH_TYPE("resolver", llvm::dbgs()
+ << llvm::format(" 0x%09lX", atom)
+ << ", file=#"
+ << definedAtom->file().ordinal()
+ << ", atom=#"
+ << definedAtom->ordinal()
+ << ", name="
+ << definedAtom->name()
+ << ", type="
+ << definedAtom->contentType()
+ << "\n");
+ } else {
+ DEBUG_WITH_TYPE("resolver", llvm::dbgs()
+ << llvm::format(" 0x%09lX", atom)
+ << ", name="
+ << atom->name()
+ << "\n");
+ }
+#endif
addAtom(*atom);
}
}
diff --git a/lib/Core/SymbolTable.cpp b/lib/Core/SymbolTable.cpp
index f3f2da9262e0..b85a83ffbfe6 100644
--- a/lib/Core/SymbolTable.cpp
+++ b/lib/Core/SymbolTable.cpp
@@ -28,7 +28,7 @@
#include <vector>
namespace lld {
-SymbolTable::SymbolTable(LinkingContext &context) : _context(context) {}
+SymbolTable::SymbolTable(LinkingContext &context) : _ctx(context) {}
bool SymbolTable::add(const UndefinedAtom &atom) { return addByName(atom); }
@@ -185,7 +185,7 @@ bool SymbolTable::addByName(const Atom &newAtom) {
// fallthrough
}
case MCR_Error:
- if (!_context.getAllowDuplicates()) {
+ if (!_ctx.getAllowDuplicates()) {
llvm::errs() << "Duplicate symbols: "
<< existing->name()
<< ":"
@@ -207,8 +207,7 @@ bool SymbolTable::addByName(const Atom &newAtom) {
const UndefinedAtom* newUndef = cast<UndefinedAtom>(&newAtom);
bool sameCanBeNull = (existingUndef->canBeNull() == newUndef->canBeNull());
- if (!sameCanBeNull &&
- _context.warnIfCoalesableAtomsHaveDifferentCanBeNull()) {
+ if (!sameCanBeNull && _ctx.warnIfCoalesableAtomsHaveDifferentCanBeNull()) {
llvm::errs() << "lld warning: undefined symbol "
<< existingUndef->name()
<< " has different weakness in "
@@ -244,14 +243,14 @@ bool SymbolTable::addByName(const Atom &newAtom) {
(curShLib->canBeNullAtRuntime() == newShLib->canBeNullAtRuntime());
bool sameName = curShLib->loadName().equals(newShLib->loadName());
if (sameName && !sameNullness &&
- _context.warnIfCoalesableAtomsHaveDifferentCanBeNull()) {
+ _ctx.warnIfCoalesableAtomsHaveDifferentCanBeNull()) {
// FIXME: need diagonstics interface for writing warning messages
llvm::errs() << "lld warning: shared library symbol "
<< curShLib->name() << " has different weakness in "
<< curShLib->file().path() << " and in "
<< newShLib->file().path();
}
- if (!sameName && _context.warnIfCoalesableAtomsHaveDifferentLoadName()) {
+ if (!sameName && _ctx.warnIfCoalesableAtomsHaveDifferentLoadName()) {
// FIXME: need diagonstics interface for writing warning messages
llvm::errs() << "lld warning: shared library symbol "
<< curShLib->name() << " has different load path in "
@@ -268,7 +267,7 @@ bool SymbolTable::addByName(const Atom &newAtom) {
}
// Give context a chance to change which is kept.
- _context.notifySymbolTableCoalesce(existing, &newAtom, useNew);
+ _ctx.notifySymbolTableCoalesce(existing, &newAtom, useNew);
if (useNew) {
// Update name table to use new atom.
diff --git a/lib/Core/TODO.txt b/lib/Core/TODO.txt
deleted file mode 100644
index 196a3e02c2fc..000000000000
--- a/lib/Core/TODO.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-lib/Core
-~~~~~~~~
-
-* Add endianness support to the native reader and writer.
-
-* The NativeReader has lots of similar code for converting arrays of ivar
- data in mapped memory into arrays of objects. The commonality can be
- factored out, maybe templatized.
-
-* The NativeFileFormat.h is old school C structs and constants. We scope
- things better by defining constants used with a struct inside the struct
- declaration.
-
-* The native reader and writer currently just blast in memory enumeration
- values (e.g. DefinedAtom::Scope) into a byte in the disk format. To support
- future changes to the enumerations, there should be a translation layer
- to map disk values to in-memory values.
-
diff --git a/lib/Core/Writer.cpp b/lib/Core/Writer.cpp
index 39bcc9e68523..93e6438a28f5 100644
--- a/lib/Core/Writer.cpp
+++ b/lib/Core/Writer.cpp
@@ -16,8 +16,4 @@ Writer::Writer() {
Writer::~Writer() {
}
-
-bool Writer::createImplicitFiles(std::vector<std::unique_ptr<File> > &) {
- return true;
-}
} // end namespace lld
diff --git a/lib/Driver/CMakeLists.txt b/lib/Driver/CMakeLists.txt
index 5a410e7eed7e..64498ccf78ba 100644
--- a/lib/Driver/CMakeLists.txt
+++ b/lib/Driver/CMakeLists.txt
@@ -6,8 +6,6 @@ set(LLVM_TARGET_DEFINITIONS CoreOptions.td)
tablegen(LLVM CoreOptions.inc -gen-opt-parser-defs)
set(LLVM_TARGET_DEFINITIONS DarwinLdOptions.td)
tablegen(LLVM DarwinLdOptions.inc -gen-opt-parser-defs)
-set(LLVM_TARGET_DEFINITIONS WinLinkOptions.td)
-tablegen(LLVM WinLinkOptions.inc -gen-opt-parser-defs)
add_public_tablegen_target(DriverOptionsTableGen)
add_llvm_library(lldDriver
@@ -16,14 +14,14 @@ add_llvm_library(lldDriver
Driver.cpp
GnuLdDriver.cpp
UniversalDriver.cpp
- WinLinkDriver.cpp
- WinLinkModuleDef.cpp
LINK_LIBS
lldConfig
lldMachO
- lldPECOFF
+ lldCOFF
lldELF
+ lldELF2
lldAArch64ELFTarget
+ lldAMDGPUELFTarget
lldARMELFTarget
lldHexagonELFTarget
lldMipsELFTarget
@@ -31,7 +29,6 @@ add_llvm_library(lldDriver
lldExampleSubTarget
lldX86_64ELFTarget
lldCore
- lldNative
lldReaderWriter
lldYAML
LLVMObject
diff --git a/lib/Driver/CoreDriver.cpp b/lib/Driver/CoreDriver.cpp
index b8adee55746f..ce8648595109 100644
--- a/lib/Driver/CoreDriver.cpp
+++ b/lib/Driver/CoreDriver.cpp
@@ -56,7 +56,7 @@ static const llvm::opt::OptTable::Info infoTable[] = {
// Create OptTable class for parsing actual command line arguments
class CoreOptTable : public llvm::opt::OptTable {
public:
- CoreOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable)){}
+ CoreOptTable() : OptTable(infoTable) {}
};
} // namespace anonymous
@@ -73,32 +73,31 @@ static const Registry::KindStrings coreKindStrings[] = {
LLD_KIND_STRING_END
};
-bool CoreDriver::link(int argc, const char *argv[], raw_ostream &diagnostics) {
+bool CoreDriver::link(llvm::ArrayRef<const char *> args,
+ raw_ostream &diagnostics) {
CoreLinkingContext ctx;
// Register possible input file parsers.
- ctx.registry().addSupportNativeObjects();
ctx.registry().addSupportYamlFiles();
ctx.registry().addKindTable(Reference::KindNamespace::testing,
Reference::KindArch::all, coreKindStrings);
- if (!parse(argc, argv, ctx))
+ if (!parse(args, ctx))
return false;
return Driver::link(ctx);
}
-bool CoreDriver::parse(int argc, const char *argv[], CoreLinkingContext &ctx,
- raw_ostream &diagnostics) {
+bool CoreDriver::parse(llvm::ArrayRef<const char *> args,
+ CoreLinkingContext &ctx, raw_ostream &diagnostics) {
// Parse command line options using CoreOptions.td
- std::unique_ptr<llvm::opt::InputArgList> parsedArgs;
CoreOptTable table;
unsigned missingIndex;
unsigned missingCount;
- parsedArgs.reset(
- table.ParseArgs(&argv[1], &argv[argc], missingIndex, missingCount));
+ llvm::opt::InputArgList parsedArgs =
+ table.ParseArgs(args.slice(1), missingIndex, missingCount);
if (missingCount) {
diagnostics << "error: missing arg value for '"
- << parsedArgs->getArgString(missingIndex) << "' expected "
+ << parsedArgs.getArgString(missingIndex) << "' expected "
<< missingCount << " argument(s).\n";
return false;
}
@@ -112,7 +111,7 @@ bool CoreDriver::parse(int argc, const char *argv[], CoreLinkingContext &ctx,
ctx.setSearchArchivesToOverrideTentativeDefinitions(false);
// Process all the arguments and create input files.
- for (auto inputArg : *parsedArgs) {
+ for (auto inputArg : parsedArgs) {
switch (inputArg->getOption().getID()) {
case OPT_mllvm:
ctx.appendLLVMOption(inputArg->getValue());
@@ -160,6 +159,8 @@ bool CoreDriver::parse(int argc, const char *argv[], CoreLinkingContext &ctx,
}
}
+ parseLLVMOptions(ctx);
+
if (ctx.getNodes().empty()) {
diagnostics << "No input files\n";
return false;
diff --git a/lib/Driver/DarwinLdDriver.cpp b/lib/Driver/DarwinLdDriver.cpp
index 2c64aeee38a5..40fad74c9529 100644
--- a/lib/Driver/DarwinLdDriver.cpp
+++ b/lib/Driver/DarwinLdDriver.cpp
@@ -20,6 +20,7 @@
#include "lld/ReaderWriter/MachOLinkingContext.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/Option.h"
@@ -68,7 +69,7 @@ static const llvm::opt::OptTable::Info infoTable[] = {
// Create OptTable class for parsing actual command line arguments
class DarwinLdOptTable : public llvm::opt::OptTable {
public:
- DarwinLdOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable)){}
+ DarwinLdOptTable() : OptTable(infoTable) {}
};
std::vector<std::unique_ptr<File>>
@@ -80,20 +81,23 @@ loadFile(MachOLinkingContext &ctx, StringRef path,
ErrorOr<std::unique_ptr<MemoryBuffer>> mbOrErr = ctx.getMemoryBuffer(path);
if (std::error_code ec = mbOrErr.getError())
return makeErrorFile(path, ec);
- std::vector<std::unique_ptr<File>> files;
- if (std::error_code ec = ctx.registry().loadFile(std::move(mbOrErr.get()), files))
+ ErrorOr<std::unique_ptr<File>> fileOrErr =
+ ctx.registry().loadFile(std::move(mbOrErr.get()));
+ if (std::error_code ec = fileOrErr.getError())
return makeErrorFile(path, ec);
- for (std::unique_ptr<File> &pf : files) {
- // If file is a dylib, inform LinkingContext about it.
- if (SharedLibraryFile *shl = dyn_cast<SharedLibraryFile>(pf.get())) {
- if (std::error_code ec = shl->parse())
- return makeErrorFile(path, ec);
- ctx.registerDylib(reinterpret_cast<mach_o::MachODylibFile*>(shl),
- upwardDylib);
- }
+ std::unique_ptr<File> &file = fileOrErr.get();
+
+ // If file is a dylib, inform LinkingContext about it.
+ if (SharedLibraryFile *shl = dyn_cast<SharedLibraryFile>(file.get())) {
+ if (std::error_code ec = shl->parse())
+ return makeErrorFile(path, ec);
+ ctx.registerDylib(reinterpret_cast<mach_o::MachODylibFile *>(shl),
+ upwardDylib);
}
if (wholeArchive)
- return parseMemberFiles(files);
+ return parseMemberFiles(std::move(file));
+ std::vector<std::unique_ptr<File>> files;
+ files.push_back(std::move(file));
return files;
}
@@ -263,42 +267,40 @@ static bool parseNumberBase16(StringRef numStr, uint64_t &baseAddress) {
namespace lld {
-bool DarwinLdDriver::linkMachO(int argc, const char *argv[],
+bool DarwinLdDriver::linkMachO(llvm::ArrayRef<const char *> args,
raw_ostream &diagnostics) {
MachOLinkingContext ctx;
- if (!parse(argc, argv, ctx, diagnostics))
+ if (!parse(args, ctx, diagnostics))
return false;
if (ctx.doNothing())
return true;
return link(ctx, diagnostics);
}
-bool DarwinLdDriver::parse(int argc, const char *argv[],
+bool DarwinLdDriver::parse(llvm::ArrayRef<const char *> args,
MachOLinkingContext &ctx, raw_ostream &diagnostics) {
// Parse command line options using DarwinLdOptions.td
- std::unique_ptr<llvm::opt::InputArgList> parsedArgs;
DarwinLdOptTable table;
unsigned missingIndex;
unsigned missingCount;
- bool globalWholeArchive = false;
- parsedArgs.reset(
- table.ParseArgs(&argv[1], &argv[argc], missingIndex, missingCount));
+ llvm::opt::InputArgList parsedArgs =
+ table.ParseArgs(args.slice(1), missingIndex, missingCount);
if (missingCount) {
diagnostics << "error: missing arg value for '"
- << parsedArgs->getArgString(missingIndex) << "' expected "
+ << parsedArgs.getArgString(missingIndex) << "' expected "
<< missingCount << " argument(s).\n";
return false;
}
- for (auto unknownArg : parsedArgs->filtered(OPT_UNKNOWN)) {
- diagnostics << "warning: ignoring unknown argument: "
- << unknownArg->getAsString(*parsedArgs) << "\n";
+ for (auto unknownArg : parsedArgs.filtered(OPT_UNKNOWN)) {
+ diagnostics << "warning: ignoring unknown argument: "
+ << unknownArg->getAsString(parsedArgs) << "\n";
}
// Figure out output kind ( -dylib, -r, -bundle, -preload, or -static )
llvm::MachO::HeaderFileType fileType = llvm::MachO::MH_EXECUTE;
- if ( llvm::opt::Arg *kind = parsedArgs->getLastArg(OPT_dylib, OPT_relocatable,
- OPT_bundle, OPT_static, OPT_preload)) {
+ if (llvm::opt::Arg *kind = parsedArgs.getLastArg(
+ OPT_dylib, OPT_relocatable, OPT_bundle, OPT_static, OPT_preload)) {
switch (kind->getOption().getID()) {
case OPT_dylib:
fileType = llvm::MachO::MH_DYLIB;
@@ -320,7 +322,7 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
// Handle -arch xxx
MachOLinkingContext::Arch arch = MachOLinkingContext::arch_unknown;
- if (llvm::opt::Arg *archStr = parsedArgs->getLastArg(OPT_arch)) {
+ if (llvm::opt::Arg *archStr = parsedArgs.getLastArg(OPT_arch)) {
arch = MachOLinkingContext::archFromName(archStr->getValue());
if (arch == MachOLinkingContext::arch_unknown) {
diagnostics << "error: unknown arch named '" << archStr->getValue()
@@ -330,17 +332,17 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
}
// If no -arch specified, scan input files to find first non-fat .o file.
if (arch == MachOLinkingContext::arch_unknown) {
- for (auto &inFile: parsedArgs->filtered(OPT_INPUT)) {
+ for (auto &inFile : parsedArgs.filtered(OPT_INPUT)) {
// This is expensive because it opens and maps the file. But that is
// ok because no -arch is rare.
if (MachOLinkingContext::isThinObjectFile(inFile->getValue(), arch))
break;
}
- if (arch == MachOLinkingContext::arch_unknown
- && !parsedArgs->getLastArg(OPT_test_file_usage)) {
+ if (arch == MachOLinkingContext::arch_unknown &&
+ !parsedArgs.getLastArg(OPT_test_file_usage)) {
// If no -arch and no options at all, print usage message.
- if (parsedArgs->size() == 0)
- table.PrintHelp(llvm::outs(), argv[0], "LLVM Linker", false);
+ if (parsedArgs.size() == 0)
+ table.PrintHelp(llvm::outs(), args[0], "LLVM Linker", false);
else
diagnostics << "error: -arch not specified and could not be inferred\n";
return false;
@@ -351,8 +353,8 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
MachOLinkingContext::OS os = MachOLinkingContext::OS::macOSX;
uint32_t minOSVersion = 0;
if (llvm::opt::Arg *minOS =
- parsedArgs->getLastArg(OPT_macosx_version_min, OPT_ios_version_min,
- OPT_ios_simulator_version_min)) {
+ parsedArgs.getLastArg(OPT_macosx_version_min, OPT_ios_version_min,
+ OPT_ios_simulator_version_min)) {
switch (minOS->getOption().getID()) {
case OPT_macosx_version_min:
os = MachOLinkingContext::OS::macOSX;
@@ -388,17 +390,17 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
ctx.configure(fileType, arch, os, minOSVersion);
// Handle -e xxx
- if (llvm::opt::Arg *entry = parsedArgs->getLastArg(OPT_entry))
+ if (llvm::opt::Arg *entry = parsedArgs.getLastArg(OPT_entry))
ctx.setEntrySymbolName(entry->getValue());
// Handle -o xxx
- if (llvm::opt::Arg *outpath = parsedArgs->getLastArg(OPT_output))
+ if (llvm::opt::Arg *outpath = parsedArgs.getLastArg(OPT_output))
ctx.setOutputPath(outpath->getValue());
else
ctx.setOutputPath("a.out");
// Handle -image_base XXX and -seg1addr XXXX
- if (llvm::opt::Arg *imageBase = parsedArgs->getLastArg(OPT_image_base)) {
+ if (llvm::opt::Arg *imageBase = parsedArgs.getLastArg(OPT_image_base)) {
uint64_t baseAddress;
if (parseNumberBase16(imageBase->getValue(), baseAddress)) {
diagnostics << "error: image_base expects a hex number\n";
@@ -408,7 +410,7 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
return false;
} else if (baseAddress % ctx.pageSize()) {
diagnostics << "error: image_base must be a multiple of page size ("
- << llvm::format("0x%" PRIx64, ctx.pageSize()) << ")\n";
+ << "0x" << llvm::utohexstr(ctx.pageSize()) << ")\n";
return false;
}
@@ -416,26 +418,26 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
}
// Handle -dead_strip
- if (parsedArgs->getLastArg(OPT_dead_strip))
+ if (parsedArgs.getLastArg(OPT_dead_strip))
ctx.setDeadStripping(true);
+ bool globalWholeArchive = false;
// Handle -all_load
- if (parsedArgs->getLastArg(OPT_all_load))
+ if (parsedArgs.getLastArg(OPT_all_load))
globalWholeArchive = true;
// Handle -install_name
- if (llvm::opt::Arg *installName = parsedArgs->getLastArg(OPT_install_name))
+ if (llvm::opt::Arg *installName = parsedArgs.getLastArg(OPT_install_name))
ctx.setInstallName(installName->getValue());
else
ctx.setInstallName(ctx.outputPath());
// Handle -mark_dead_strippable_dylib
- if (parsedArgs->getLastArg(OPT_mark_dead_strippable_dylib))
+ if (parsedArgs.getLastArg(OPT_mark_dead_strippable_dylib))
ctx.setDeadStrippableDylib(true);
// Handle -compatibility_version and -current_version
- if (llvm::opt::Arg *vers =
- parsedArgs->getLastArg(OPT_compatibility_version)) {
+ if (llvm::opt::Arg *vers = parsedArgs.getLastArg(OPT_compatibility_version)) {
if (ctx.outputMachOType() != llvm::MachO::MH_DYLIB) {
diagnostics
<< "error: -compatibility_version can only be used with -dylib\n";
@@ -449,7 +451,7 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
ctx.setCompatibilityVersion(parsedVers);
}
- if (llvm::opt::Arg *vers = parsedArgs->getLastArg(OPT_current_version)) {
+ if (llvm::opt::Arg *vers = parsedArgs.getLastArg(OPT_current_version)) {
if (ctx.outputMachOType() != llvm::MachO::MH_DYLIB) {
diagnostics << "-current_version can only be used with -dylib\n";
return false;
@@ -463,11 +465,11 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
}
// Handle -bundle_loader
- if (llvm::opt::Arg *loader = parsedArgs->getLastArg(OPT_bundle_loader))
+ if (llvm::opt::Arg *loader = parsedArgs.getLastArg(OPT_bundle_loader))
ctx.setBundleLoader(loader->getValue());
// Handle -sectalign segname sectname align
- for (auto &alignArg : parsedArgs->filtered(OPT_sectalign)) {
+ for (auto &alignArg : parsedArgs.filtered(OPT_sectalign)) {
const char* segName = alignArg->getValue(0);
const char* sectName = alignArg->getValue(1);
const char* alignStr = alignArg->getValue(2);
@@ -479,43 +481,43 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
<< alignStr << "' not a valid number\n";
return false;
}
- uint8_t align2 = llvm::countTrailingZeros(alignValue);
- if ( (unsigned long)(1 << align2) != alignValue ) {
+ uint16_t align = 1 << llvm::countTrailingZeros(alignValue);
+ if (!llvm::isPowerOf2_64(alignValue)) {
diagnostics << "warning: alignment for '-sectalign "
<< segName << " " << sectName
<< llvm::format(" 0x%llX", alignValue)
<< "' is not a power of two, using "
- << llvm::format("0x%08X", (1 << align2)) << "\n";
+ << llvm::format("0x%08X", align) << "\n";
}
- ctx.addSectionAlignment(segName, sectName, align2);
+ ctx.addSectionAlignment(segName, sectName, align);
}
// Handle -mllvm
- for (auto &llvmArg : parsedArgs->filtered(OPT_mllvm)) {
+ for (auto &llvmArg : parsedArgs.filtered(OPT_mllvm)) {
ctx.appendLLVMOption(llvmArg->getValue());
}
// Handle -print_atoms
- if (parsedArgs->getLastArg(OPT_print_atoms))
+ if (parsedArgs.getLastArg(OPT_print_atoms))
ctx.setPrintAtoms();
// Handle -t (trace) option.
- if (parsedArgs->getLastArg(OPT_t))
+ if (parsedArgs.getLastArg(OPT_t))
ctx.setLogInputFiles(true);
// Handle -demangle option.
- if (parsedArgs->getLastArg(OPT_demangle))
+ if (parsedArgs.getLastArg(OPT_demangle))
ctx.setDemangleSymbols(true);
// Handle -keep_private_externs
- if (parsedArgs->getLastArg(OPT_keep_private_externs)) {
+ if (parsedArgs.getLastArg(OPT_keep_private_externs)) {
ctx.setKeepPrivateExterns(true);
if (ctx.outputMachOType() != llvm::MachO::MH_OBJECT)
diagnostics << "warning: -keep_private_externs only used in -r mode\n";
}
// Handle -dependency_info <path> used by Xcode.
- if (llvm::opt::Arg *depInfo = parsedArgs->getLastArg(OPT_dependency_info)) {
+ if (llvm::opt::Arg *depInfo = parsedArgs.getLastArg(OPT_dependency_info)) {
if (std::error_code ec = ctx.createDependencyFile(depInfo->getValue())) {
diagnostics << "warning: " << ec.message()
<< ", processing '-dependency_info "
@@ -528,14 +530,14 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
// exist. We'll also be expected to print out information about how we located
// libraries and so on that the user specified, but not to actually do any
// linking.
- if (parsedArgs->getLastArg(OPT_test_file_usage)) {
+ if (parsedArgs.getLastArg(OPT_test_file_usage)) {
ctx.setTestingFileUsage();
// With paths existing by fiat, linking is not going to end well.
ctx.setDoNothing(true);
// Only bother looking for an existence override if we're going to use it.
- for (auto existingPath : parsedArgs->filtered(OPT_path_exists)) {
+ for (auto existingPath : parsedArgs.filtered(OPT_path_exists)) {
ctx.addExistingPathForDebug(existingPath->getValue());
}
}
@@ -544,7 +546,6 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
if (!ctx.doNothing()) {
ctx.registry().addSupportMachOObjects(ctx);
ctx.registry().addSupportArchives(ctx.logInputFiles());
- ctx.registry().addSupportNativeObjects();
ctx.registry().addSupportYamlFiles();
}
@@ -559,7 +560,7 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
// 3. If the last -syslibroot is "/", all of them are ignored entirely.
// 4. If { syslibroots } x path == {}, the original path is kept.
std::vector<StringRef> sysLibRoots;
- for (auto syslibRoot : parsedArgs->filtered(OPT_syslibroot)) {
+ for (auto syslibRoot : parsedArgs.filtered(OPT_syslibroot)) {
sysLibRoots.push_back(syslibRoot->getValue());
}
if (!sysLibRoots.empty()) {
@@ -570,17 +571,17 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
// Paths specified with -L come first, and are not considered system paths for
// the case where there is precisely 1 -syslibroot.
- for (auto libPath : parsedArgs->filtered(OPT_L)) {
+ for (auto libPath : parsedArgs.filtered(OPT_L)) {
ctx.addModifiedSearchDir(libPath->getValue());
}
// Process -F directories (where to look for frameworks).
- for (auto fwPath : parsedArgs->filtered(OPT_F)) {
+ for (auto fwPath : parsedArgs.filtered(OPT_F)) {
ctx.addFrameworkSearchDir(fwPath->getValue());
}
// -Z suppresses the standard search paths.
- if (!parsedArgs->hasArg(OPT_Z)) {
+ if (!parsedArgs.hasArg(OPT_Z)) {
ctx.addModifiedSearchDir("/usr/lib", true);
ctx.addModifiedSearchDir("/usr/local/lib", true);
ctx.addFrameworkSearchDir("/Library/Frameworks", true);
@@ -589,7 +590,7 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
// Now that we've constructed the final set of search paths, print out those
// search paths in verbose mode.
- if (parsedArgs->getLastArg(OPT_v)) {
+ if (parsedArgs.getLastArg(OPT_v)) {
diagnostics << "Library search paths:\n";
for (auto path : ctx.searchDirs()) {
diagnostics << " " << path << '\n';
@@ -601,7 +602,7 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
}
// Handle -exported_symbols_list <file>
- for (auto expFile : parsedArgs->filtered(OPT_exported_symbols_list)) {
+ for (auto expFile : parsedArgs.filtered(OPT_exported_symbols_list)) {
if (ctx.exportMode() == MachOLinkingContext::ExportMode::blackList) {
diagnostics << "error: -exported_symbols_list cannot be combined "
<< "with -unexported_symbol[s_list]\n";
@@ -619,7 +620,7 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
}
// Handle -exported_symbol <symbol>
- for (auto symbol : parsedArgs->filtered(OPT_exported_symbol)) {
+ for (auto symbol : parsedArgs.filtered(OPT_exported_symbol)) {
if (ctx.exportMode() == MachOLinkingContext::ExportMode::blackList) {
diagnostics << "error: -exported_symbol cannot be combined "
<< "with -unexported_symbol[s_list]\n";
@@ -630,7 +631,7 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
}
// Handle -unexported_symbols_list <file>
- for (auto expFile : parsedArgs->filtered(OPT_unexported_symbols_list)) {
+ for (auto expFile : parsedArgs.filtered(OPT_unexported_symbols_list)) {
if (ctx.exportMode() == MachOLinkingContext::ExportMode::whiteList) {
diagnostics << "error: -unexported_symbols_list cannot be combined "
<< "with -exported_symbol[s_list]\n";
@@ -648,7 +649,7 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
}
// Handle -unexported_symbol <symbol>
- for (auto symbol : parsedArgs->filtered(OPT_unexported_symbol)) {
+ for (auto symbol : parsedArgs.filtered(OPT_unexported_symbol)) {
if (ctx.exportMode() == MachOLinkingContext::ExportMode::whiteList) {
diagnostics << "error: -unexported_symbol cannot be combined "
<< "with -exported_symbol[s_list]\n";
@@ -659,8 +660,8 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
}
// Handle obosolete -multi_module and -single_module
- if (llvm::opt::Arg *mod = parsedArgs->getLastArg(OPT_multi_module,
- OPT_single_module)) {
+ if (llvm::opt::Arg *mod =
+ parsedArgs.getLastArg(OPT_multi_module, OPT_single_module)) {
if (mod->getOption().getID() == OPT_multi_module) {
diagnostics << "warning: -multi_module is obsolete and being ignored\n";
}
@@ -673,7 +674,7 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
}
// Handle -pie or -no_pie
- if (llvm::opt::Arg *pie = parsedArgs->getLastArg(OPT_pie, OPT_no_pie)) {
+ if (llvm::opt::Arg *pie = parsedArgs.getLastArg(OPT_pie, OPT_no_pie)) {
switch (ctx.outputMachOType()) {
case llvm::MachO::MH_EXECUTE:
switch (ctx.os()) {
@@ -718,12 +719,28 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
}
}
+ // Handle stack_size
+ if (llvm::opt::Arg *stackSize = parsedArgs.getLastArg(OPT_stack_size)) {
+ uint64_t stackSizeVal;
+ if (parseNumberBase16(stackSize->getValue(), stackSizeVal)) {
+ diagnostics << "error: stack_size expects a hex number\n";
+ return false;
+ }
+ if ((stackSizeVal % ctx.pageSize()) != 0) {
+ diagnostics << "error: stack_size must be a multiple of page size ("
+ << "0x" << llvm::utohexstr(ctx.pageSize()) << ")\n";
+ return false;
+ }
+
+ ctx.setStackSize(stackSizeVal);
+ }
+
// Handle debug info handling options: -S
- if (parsedArgs->hasArg(OPT_S))
+ if (parsedArgs.hasArg(OPT_S))
ctx.setDebugInfoMode(MachOLinkingContext::DebugInfoMode::noDebugMap);
// Handle -order_file <file>
- for (auto orderFile : parsedArgs->filtered(OPT_order_file)) {
+ for (auto orderFile : parsedArgs.filtered(OPT_order_file)) {
if (std::error_code ec = parseOrderFile(orderFile->getValue(), ctx,
diagnostics)) {
diagnostics << "error: " << ec.message()
@@ -734,8 +751,51 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
}
}
+ // Handle -flat_namespace.
+ if (llvm::opt::Arg *ns =
+ parsedArgs.getLastArg(OPT_flat_namespace, OPT_twolevel_namespace)) {
+ if (ns->getOption().getID() == OPT_flat_namespace)
+ ctx.setUseFlatNamespace(true);
+ }
+
+ // Handle -undefined
+ if (llvm::opt::Arg *undef = parsedArgs.getLastArg(OPT_undefined)) {
+ MachOLinkingContext::UndefinedMode UndefMode;
+ if (StringRef(undef->getValue()).equals("error"))
+ UndefMode = MachOLinkingContext::UndefinedMode::error;
+ else if (StringRef(undef->getValue()).equals("warning"))
+ UndefMode = MachOLinkingContext::UndefinedMode::warning;
+ else if (StringRef(undef->getValue()).equals("suppress"))
+ UndefMode = MachOLinkingContext::UndefinedMode::suppress;
+ else if (StringRef(undef->getValue()).equals("dynamic_lookup"))
+ UndefMode = MachOLinkingContext::UndefinedMode::dynamicLookup;
+ else {
+ diagnostics << "error: invalid option to -undefined "
+ "[ warning | error | suppress | dynamic_lookup ]\n";
+ return false;
+ }
+
+ if (ctx.useFlatNamespace()) {
+ // If we're using -flat_namespace then 'warning', 'suppress' and
+ // 'dynamic_lookup' are all equivalent, so map them to 'suppress'.
+ if (UndefMode != MachOLinkingContext::UndefinedMode::error)
+ UndefMode = MachOLinkingContext::UndefinedMode::suppress;
+ } else {
+ // If we're using -twolevel_namespace then 'warning' and 'suppress' are
+ // illegal. Emit a diagnostic if they've been (mis)used.
+ if (UndefMode == MachOLinkingContext::UndefinedMode::warning ||
+ UndefMode == MachOLinkingContext::UndefinedMode::suppress) {
+ diagnostics << "error: can't use -undefined warning or suppress with "
+ "-twolevel_namespace\n";
+ return false;
+ }
+ }
+
+ ctx.setUndefinedMode(UndefMode);
+ }
+
// Handle -rpath <path>
- if (parsedArgs->hasArg(OPT_rpath)) {
+ if (parsedArgs.hasArg(OPT_rpath)) {
switch (ctx.outputMachOType()) {
case llvm::MachO::MH_EXECUTE:
case llvm::MachO::MH_DYLIB:
@@ -757,13 +817,17 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
return false;
}
- for (auto rPath : parsedArgs->filtered(OPT_rpath)) {
+ for (auto rPath : parsedArgs.filtered(OPT_rpath)) {
ctx.addRpath(rPath->getValue());
}
}
- // Handle input files
- for (auto &arg : *parsedArgs) {
+ // Parse the LLVM options before we process files in case the file handling
+ // makes use of things like DEBUG().
+ parseLLVMOptions(ctx);
+
+ // Handle input files and sectcreate.
+ for (auto &arg : parsedArgs) {
bool upward;
ErrorOr<StringRef> resolvedPath = StringRef();
switch (arg->getOption().getID()) {
@@ -816,6 +880,22 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
return false;
}
break;
+ case OPT_sectcreate: {
+ const char* seg = arg->getValue(0);
+ const char* sect = arg->getValue(1);
+ const char* fileName = arg->getValue(2);
+
+ ErrorOr<std::unique_ptr<MemoryBuffer>> contentOrErr =
+ MemoryBuffer::getFile(fileName);
+
+ if (!contentOrErr) {
+ diagnostics << "error: can't open -sectcreate file " << fileName << "\n";
+ return false;
+ }
+
+ ctx.addSectCreateSection(seg, sect, std::move(*contentOrErr));
+ }
+ break;
}
}
diff --git a/lib/Driver/DarwinLdOptions.td b/lib/Driver/DarwinLdOptions.td
index 81dcc0a1d925..cbf6ac1d4a4b 100644
--- a/lib/Driver/DarwinLdOptions.td
+++ b/lib/Driver/DarwinLdOptions.td
@@ -55,6 +55,19 @@ def order_file : Separate<["-"], "order_file">,
MetaVarName<"<file-path>">,
HelpText<"re-order and move specified symbols to start of their section">,
Group<grp_opts>;
+def flat_namespace : Flag<["-"], "flat_namespace">,
+ HelpText<"Resolves symbols in any (transitively) linked dynamic libraries. "
+ "Source libraries are not recorded: dyld will re-search all "
+ "images at runtime and use the first definition found.">,
+ Group<grp_opts>;
+def twolevel_namespace : Flag<["-"], "twolevel_namespace">,
+ HelpText<"Resolves symbols in listed libraries only. Source libraries are "
+ "recorded in the symbol table.">,
+ Group<grp_opts>;
+def undefined : Separate<["-"], "undefined">,
+ MetaVarName<"<undefined>">,
+ HelpText<"Determines how undefined symbols are handled.">,
+ Group<grp_opts>;
// main executable options
def grp_main : OptionGroup<"opts">, HelpText<"MAIN EXECUTABLE OPTIONS">;
@@ -67,6 +80,10 @@ def pie : Flag<["-"], "pie">,
def no_pie : Flag<["-"], "no_pie">,
HelpText<"Do not create Position Independent Executable">,
Group<grp_main>;
+def stack_size : Separate<["-"], "stack_size">,
+ HelpText<"Specifies the maximum stack size for the main thread in a program. "
+ "Must be a page-size multiple. (default=8Mb)">,
+ Group<grp_main>;
// dylib executable options
def grp_dylib : OptionGroup<"opts">, HelpText<"DYLIB EXECUTABLE OPTIONS">;
@@ -160,7 +177,10 @@ def arch : Separate<["-"], "arch">,
HelpText<"Architecture to link">;
def sectalign : MultiArg<["-"], "sectalign", 3>,
MetaVarName<"<segname> <sectname> <alignment>">,
- HelpText<"alignment for segment/section">;
+ HelpText<"Alignment for segment/section">;
+def sectcreate : MultiArg<["-"], "sectcreate", 3>,
+ MetaVarName<"<segname> <sectname> <file>">,
+ HelpText<"Create section <segname>/<sectname> from contents of <file>">;
def image_base : Separate<["-"], "image_base">;
def seg1addr : Separate<["-"], "seg1addr">, Alias<image_base>;
def demangle : Flag<["-"], "demangle">,
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index d32bfa6e47be..6a7a26b3b0f6 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -1,4 +1,4 @@
-//===- lib/Driver/Driver.cpp - Linker Driver Emulator ---------------------===//
+//===- lib/Driver/Driver.cpp - Linker Driver Emulator -----------*- C++ -*-===//
//
// The LLVM Linker
//
@@ -36,15 +36,13 @@ FileVector makeErrorFile(StringRef path, std::error_code ec) {
return result;
}
-FileVector parseMemberFiles(FileVector &files) {
+FileVector parseMemberFiles(std::unique_ptr<File> file) {
std::vector<std::unique_ptr<File>> members;
- for (std::unique_ptr<File> &file : files) {
- if (auto *archive = dyn_cast<ArchiveLibraryFile>(file.get())) {
- if (std::error_code ec = archive->parseAllMembers(members))
- return makeErrorFile(file->path(), ec);
- } else {
- members.push_back(std::move(file));
- }
+ if (auto *archive = dyn_cast<ArchiveLibraryFile>(file.get())) {
+ if (std::error_code ec = archive->parseAllMembers(members))
+ return makeErrorFile(file->path(), ec);
+ } else {
+ members.push_back(std::move(file));
}
return members;
}
@@ -54,72 +52,86 @@ FileVector loadFile(LinkingContext &ctx, StringRef path, bool wholeArchive) {
= MemoryBuffer::getFileOrSTDIN(path);
if (std::error_code ec = mb.getError())
return makeErrorFile(path, ec);
- std::vector<std::unique_ptr<File>> files;
- if (std::error_code ec = ctx.registry().loadFile(std::move(mb.get()), files))
+ ErrorOr<std::unique_ptr<File>> fileOrErr =
+ ctx.registry().loadFile(std::move(mb.get()));
+ if (std::error_code ec = fileOrErr.getError())
return makeErrorFile(path, ec);
+ std::unique_ptr<File> &file = fileOrErr.get();
if (wholeArchive)
- return parseMemberFiles(files);
+ return parseMemberFiles(std::move(file));
+ std::vector<std::unique_ptr<File>> files;
+ files.push_back(std::move(file));
return files;
}
-/// This is where the link is actually performed.
-bool Driver::link(LinkingContext &context, raw_ostream &diagnostics) {
+void Driver::parseLLVMOptions(const LinkingContext &ctx) {
// Honor -mllvm
- if (!context.llvmOptions().empty()) {
- unsigned numArgs = context.llvmOptions().size();
- const char **args = new const char *[numArgs + 2];
+ if (!ctx.llvmOptions().empty()) {
+ unsigned numArgs = ctx.llvmOptions().size();
+ auto **args = new const char *[numArgs + 2];
args[0] = "lld (LLVM option parsing)";
for (unsigned i = 0; i != numArgs; ++i)
- args[i + 1] = context.llvmOptions()[i];
- args[numArgs + 1] = 0;
+ args[i + 1] = ctx.llvmOptions()[i];
+ args[numArgs + 1] = nullptr;
llvm::cl::ParseCommandLineOptions(numArgs + 1, args);
}
- if (context.getNodes().empty())
+}
+
+/// This is where the link is actually performed.
+bool Driver::link(LinkingContext &ctx, raw_ostream &diagnostics) {
+ if (ctx.getNodes().empty())
return false;
- for (std::unique_ptr<Node> &ie : context.getNodes())
+ for (std::unique_ptr<Node> &ie : ctx.getNodes())
if (FileNode *node = dyn_cast<FileNode>(ie.get()))
- context.getTaskGroup().spawn([node] { node->getFile()->parse(); });
+ ctx.getTaskGroup().spawn([node] { node->getFile()->parse(); });
std::vector<std::unique_ptr<File>> internalFiles;
- context.createInternalFiles(internalFiles);
+ ctx.createInternalFiles(internalFiles);
for (auto i = internalFiles.rbegin(), e = internalFiles.rend(); i != e; ++i) {
- auto &members = context.getNodes();
+ auto &members = ctx.getNodes();
members.insert(members.begin(), llvm::make_unique<FileNode>(std::move(*i)));
}
// Give target a chance to add files.
std::vector<std::unique_ptr<File>> implicitFiles;
- context.createImplicitFiles(implicitFiles);
+ ctx.createImplicitFiles(implicitFiles);
for (auto i = implicitFiles.rbegin(), e = implicitFiles.rend(); i != e; ++i) {
- auto &members = context.getNodes();
+ auto &members = ctx.getNodes();
members.insert(members.begin(), llvm::make_unique<FileNode>(std::move(*i)));
}
// Give target a chance to postprocess input files.
// Mach-O uses this chance to move all object files before library files.
// ELF adds specific undefined symbols resolver.
- context.finalizeInputFiles();
+ ctx.finalizeInputFiles();
// Do core linking.
ScopedTask resolveTask(getDefaultDomain(), "Resolve");
- Resolver resolver(context);
- if (!resolver.resolve())
+ Resolver resolver(ctx);
+ if (!resolver.resolve()) {
+ ctx.getTaskGroup().sync();
return false;
- std::unique_ptr<MutableFile> merged = resolver.resultFile();
+ }
+ std::unique_ptr<SimpleFile> merged = resolver.resultFile();
resolveTask.end();
// Run passes on linked atoms.
ScopedTask passTask(getDefaultDomain(), "Passes");
PassManager pm;
- context.addPasses(pm);
- pm.runOnFile(merged);
+ ctx.addPasses(pm);
+ if (std::error_code ec = pm.runOnFile(*merged)) {
+ diagnostics << "Failed to write file '" << ctx.outputPath()
+ << "': " << ec.message() << "\n";
+ return false;
+ }
+
passTask.end();
// Give linked atoms to Writer to generate output file.
ScopedTask writeTask(getDefaultDomain(), "Write");
- if (std::error_code ec = context.writeFile(*merged)) {
- diagnostics << "Failed to write file '" << context.outputPath()
+ if (std::error_code ec = ctx.writeFile(*merged)) {
+ diagnostics << "Failed to write file '" << ctx.outputPath()
<< "': " << ec.message() << "\n";
return false;
}
@@ -127,4 +139,4 @@ bool Driver::link(LinkingContext &context, raw_ostream &diagnostics) {
return true;
}
-} // namespace
+} // namespace lld
diff --git a/lib/Driver/GnuLdDriver.cpp b/lib/Driver/GnuLdDriver.cpp
index b9af04d4b615..8c75126d6d41 100644
--- a/lib/Driver/GnuLdDriver.cpp
+++ b/lib/Driver/GnuLdDriver.cpp
@@ -15,7 +15,6 @@
#include "lld/Driver/Driver.h"
#include "lld/ReaderWriter/ELFLinkingContext.h"
-#include "lld/ReaderWriter/ELFTargets.h"
#include "lld/ReaderWriter/LinkerScript.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Optional.h"
@@ -32,6 +31,7 @@
#include "llvm/Support/Path.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"
+#include "llvm/Support/StringSaver.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
#include <cstring>
@@ -72,21 +72,7 @@ static const llvm::opt::OptTable::Info infoTable[] = {
// Create OptTable class for parsing actual command line arguments
class GnuLdOptTable : public llvm::opt::OptTable {
public:
- GnuLdOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable)){}
-};
-
-class DriverStringSaver : public llvm::cl::StringSaver {
-public:
- DriverStringSaver(BumpPtrAllocator &alloc) : _alloc(alloc) {}
-
- const char *SaveString(const char *s) override {
- char *p = _alloc.Allocate<char>(strlen(s) + 1);
- strcpy(p, s);
- return p;
- }
-
-private:
- BumpPtrAllocator &_alloc;
+ GnuLdOptTable() : OptTable(infoTable){}
};
} // anonymous namespace
@@ -96,37 +82,21 @@ private:
// at the original @file position. If file cannot be read, @file is not expanded
// and left unmodified. @file can appear in a response file, so it's a recursive
// process.
-static std::tuple<int, const char **>
-maybeExpandResponseFiles(int argc, const char **argv, BumpPtrAllocator &alloc) {
+static llvm::ArrayRef<const char *>
+maybeExpandResponseFiles(llvm::ArrayRef<const char *> args,
+ BumpPtrAllocator &alloc) {
// Expand response files.
SmallVector<const char *, 256> smallvec;
- for (int i = 0; i < argc; ++i)
- smallvec.push_back(argv[i]);
- DriverStringSaver saver(alloc);
+ for (const char *arg : args)
+ smallvec.push_back(arg);
+ llvm::StringSaver saver(alloc);
llvm::cl::ExpandResponseFiles(saver, llvm::cl::TokenizeGNUCommandLine, smallvec);
// Pack the results to a C-array and return it.
- argc = smallvec.size();
- const char **copy = alloc.Allocate<const char *>(argc + 1);
+ const char **copy = alloc.Allocate<const char *>(smallvec.size() + 1);
std::copy(smallvec.begin(), smallvec.end(), copy);
- copy[argc] = nullptr;
- return std::make_tuple(argc, copy);
-}
-
-static std::error_code
-getFileMagic(StringRef path, llvm::sys::fs::file_magic &magic) {
- std::error_code ec = llvm::sys::fs::identify_magic(path, magic);
- if (ec)
- return ec;
- switch (magic) {
- case llvm::sys::fs::file_magic::archive:
- case llvm::sys::fs::file_magic::elf_relocatable:
- case llvm::sys::fs::file_magic::elf_shared_object:
- case llvm::sys::fs::file_magic::unknown:
- return std::error_code();
- default:
- return make_dynamic_error_code(StringRef("unknown type of object file"));
- }
+ copy[smallvec.size()] = nullptr;
+ return llvm::makeArrayRef(copy, smallvec.size() + 1);
}
// Parses an argument of --defsym=<sym>=<number>
@@ -164,11 +134,12 @@ static bool parseMaxPageSize(StringRef opt, uint64_t &val) {
return true;
}
-bool GnuLdDriver::linkELF(int argc, const char *argv[], raw_ostream &diag) {
+bool GnuLdDriver::linkELF(llvm::ArrayRef<const char *> args,
+ raw_ostream &diag) {
BumpPtrAllocator alloc;
- std::tie(argc, argv) = maybeExpandResponseFiles(argc, argv, alloc);
+ args = maybeExpandResponseFiles(args, alloc);
std::unique_ptr<ELFLinkingContext> options;
- if (!parse(argc, argv, options, diag))
+ if (!parse(args, options, diag))
return false;
if (!options)
return true;
@@ -193,13 +164,16 @@ getArchType(const llvm::Triple &triple, StringRef value) {
if (value == "elf_x86_64")
return llvm::Triple::x86_64;
return llvm::None;
+ case llvm::Triple::mips:
case llvm::Triple::mipsel:
+ case llvm::Triple::mips64:
case llvm::Triple::mips64el:
- if (value == "elf32ltsmip")
- return llvm::Triple::mipsel;
- if (value == "elf64ltsmip")
- return llvm::Triple::mips64el;
- return llvm::None;
+ return llvm::StringSwitch<llvm::Optional<llvm::Triple::ArchType>>(value)
+ .Cases("elf32btsmip", "elf32btsmipn32", llvm::Triple::mips)
+ .Cases("elf32ltsmip", "elf32ltsmipn32", llvm::Triple::mipsel)
+ .Case("elf64btsmip", llvm::Triple::mips64)
+ .Case("elf64ltsmip", llvm::Triple::mips64el)
+ .Default(llvm::None);
case llvm::Triple::aarch64:
if (value == "aarch64linux")
return llvm::Triple::aarch64;
@@ -215,9 +189,9 @@ getArchType(const llvm::Triple &triple, StringRef value) {
static bool isLinkerScript(StringRef path, raw_ostream &diag) {
llvm::sys::fs::file_magic magic = llvm::sys::fs::file_magic::unknown;
- std::error_code ec = getFileMagic(path, magic);
- if (ec) {
- diag << "unknown input file format for file " << path << "\n";
+ if (std::error_code ec = llvm::sys::fs::identify_magic(path, magic)) {
+ diag << "unknown input file format: " << path << ": "
+ << ec.message() << "\n";
return false;
}
return magic == llvm::sys::fs::file_magic::unknown;
@@ -350,17 +324,14 @@ void GnuLdDriver::addPlatformSearchDirs(ELFLinkingContext &ctx,
std::unique_ptr<ELFLinkingContext>
GnuLdDriver::createELFLinkingContext(llvm::Triple triple) {
std::unique_ptr<ELFLinkingContext> p;
- // FIXME: #include "llvm/Config/Targets.def"
-#define LLVM_TARGET(targetName) \
- if ((p = elf::targetName##LinkingContext::create(triple))) return p;
- LLVM_TARGET(AArch64)
- LLVM_TARGET(ARM)
- LLVM_TARGET(Hexagon)
- LLVM_TARGET(Mips)
- LLVM_TARGET(X86)
- LLVM_TARGET(Example)
- LLVM_TARGET(X86_64)
-#undef LLVM_TARGET
+ if ((p = elf::createAArch64LinkingContext(triple))) return p;
+ if ((p = elf::createAMDGPULinkingContext(triple))) return p;
+ if ((p = elf::createARMLinkingContext(triple))) return p;
+ if ((p = elf::createExampleLinkingContext(triple))) return p;
+ if ((p = elf::createHexagonLinkingContext(triple))) return p;
+ if ((p = elf::createMipsLinkingContext(triple))) return p;
+ if ((p = elf::createX86LinkingContext(triple))) return p;
+ if ((p = elf::createX86_64LinkingContext(triple))) return p;
return nullptr;
}
@@ -372,40 +343,39 @@ getBool(const llvm::opt::InputArgList &parsedArgs,
return llvm::None;
}
-bool GnuLdDriver::parse(int argc, const char *argv[],
+bool GnuLdDriver::parse(llvm::ArrayRef<const char *> args,
std::unique_ptr<ELFLinkingContext> &context,
raw_ostream &diag) {
// Parse command line options using GnuLdOptions.td
- std::unique_ptr<llvm::opt::InputArgList> parsedArgs;
GnuLdOptTable table;
unsigned missingIndex;
unsigned missingCount;
- parsedArgs.reset(
- table.ParseArgs(&argv[1], &argv[argc], missingIndex, missingCount));
+ llvm::opt::InputArgList parsedArgs =
+ table.ParseArgs(args.slice(1), missingIndex, missingCount);
if (missingCount) {
diag << "error: missing arg value for '"
- << parsedArgs->getArgString(missingIndex) << "' expected "
+ << parsedArgs.getArgString(missingIndex) << "' expected "
<< missingCount << " argument(s).\n";
return false;
}
// Handle --help
- if (parsedArgs->hasArg(OPT_help)) {
- table.PrintHelp(llvm::outs(), argv[0], "LLVM Linker", false);
+ if (parsedArgs.hasArg(OPT_help)) {
+ table.PrintHelp(llvm::outs(), args[0], "LLVM Linker", false);
return true;
}
// Use -target or use default target triple to instantiate LinkingContext
llvm::Triple baseTriple;
- if (auto *arg = parsedArgs->getLastArg(OPT_target)) {
+ if (auto *arg = parsedArgs.getLastArg(OPT_target)) {
baseTriple = llvm::Triple(arg->getValue());
} else {
- baseTriple = getDefaultTarget(argv[0]);
+ baseTriple = getDefaultTarget(args[0]);
}
llvm::Triple triple(baseTriple);
- if (!applyEmulation(triple, *parsedArgs, diag))
+ if (!applyEmulation(triple, parsedArgs, diag))
return false;
std::unique_ptr<ELFLinkingContext> ctx(createELFLinkingContext(triple));
@@ -416,39 +386,39 @@ bool GnuLdDriver::parse(int argc, const char *argv[],
}
// Copy mllvm
- for (auto *arg : parsedArgs->filtered(OPT_mllvm))
+ for (auto *arg : parsedArgs.filtered(OPT_mllvm))
ctx->appendLLVMOption(arg->getValue());
// Ignore unknown arguments.
- for (auto unknownArg : parsedArgs->filtered(OPT_UNKNOWN))
+ for (auto unknownArg : parsedArgs.filtered(OPT_UNKNOWN))
diag << "warning: ignoring unknown argument: "
<< unknownArg->getValue() << "\n";
// Set sys root path.
- if (auto *arg = parsedArgs->getLastArg(OPT_sysroot))
+ if (auto *arg = parsedArgs.getLastArg(OPT_sysroot))
ctx->setSysroot(arg->getValue());
// Handle --demangle option(For compatibility)
- if (parsedArgs->hasArg(OPT_demangle))
+ if (parsedArgs.hasArg(OPT_demangle))
ctx->setDemangleSymbols(true);
// Handle --no-demangle option.
- if (parsedArgs->hasArg(OPT_no_demangle))
+ if (parsedArgs.hasArg(OPT_no_demangle))
ctx->setDemangleSymbols(false);
// Figure out output kind (-r, -static, -shared)
- if (parsedArgs->hasArg(OPT_relocatable)) {
+ if (parsedArgs.hasArg(OPT_relocatable)) {
ctx->setOutputELFType(llvm::ELF::ET_REL);
ctx->setPrintRemainingUndefines(false);
ctx->setAllowRemainingUndefines(true);
}
- if (parsedArgs->hasArg(OPT_static)) {
+ if (parsedArgs.hasArg(OPT_static)) {
ctx->setOutputELFType(llvm::ELF::ET_EXEC);
ctx->setIsStaticExecutable(true);
}
- if (parsedArgs->hasArg(OPT_shared)) {
+ if (parsedArgs.hasArg(OPT_shared)) {
ctx->setOutputELFType(llvm::ELF::ET_DYN);
ctx->setAllowShlibUndefines(true);
ctx->setUseShlibUndefines(false);
@@ -457,13 +427,13 @@ bool GnuLdDriver::parse(int argc, const char *argv[],
}
// Handle --stats.
- if (parsedArgs->hasArg(OPT_stats)) {
+ if (parsedArgs.hasArg(OPT_stats)) {
ctx->setCollectStats(true);
}
// Figure out if the output type is nmagic/omagic
- if (auto *arg = parsedArgs->getLastArg(
- OPT_nmagic, OPT_omagic, OPT_no_omagic)) {
+ if (auto *arg =
+ parsedArgs.getLastArg(OPT_nmagic, OPT_omagic, OPT_no_omagic)) {
switch (arg->getOption().getID()) {
case OPT_nmagic:
ctx->setOutputMagic(ELFLinkingContext::OutputMagic::NMAGIC);
@@ -480,19 +450,25 @@ bool GnuLdDriver::parse(int argc, const char *argv[],
}
}
- if (parsedArgs->hasArg(OPT_strip_all))
+ if (parsedArgs.hasArg(OPT_discard_loc))
+ ctx->setDiscardLocals(true);
+
+ if (parsedArgs.hasArg(OPT_discard_temp_loc))
+ ctx->setDiscardTempLocals(true);
+
+ if (parsedArgs.hasArg(OPT_strip_all))
ctx->setStripSymbols(true);
- if (auto *arg = parsedArgs->getLastArg(OPT_soname))
+ if (auto *arg = parsedArgs.getLastArg(OPT_soname))
ctx->setSharedObjectName(arg->getValue());
- if (parsedArgs->hasArg(OPT_rosegment))
+ if (parsedArgs.hasArg(OPT_rosegment))
ctx->setCreateSeparateROSegment();
- if (parsedArgs->hasArg(OPT_no_align_segments))
+ if (parsedArgs.hasArg(OPT_no_align_segments))
ctx->setAlignSegments(false);
- if (auto *arg = parsedArgs->getLastArg(OPT_image_base)) {
+ if (auto *arg = parsedArgs.getLastArg(OPT_image_base)) {
uint64_t baseAddress = 0;
StringRef inputValue = arg->getValue();
if (inputValue.getAsInteger(0, baseAddress) || !baseAddress) {
@@ -502,58 +478,94 @@ bool GnuLdDriver::parse(int argc, const char *argv[],
ctx->setBaseAddress(baseAddress);
}
- if (parsedArgs->hasArg(OPT_merge_strings))
+ if (parsedArgs.hasArg(OPT_merge_strings))
ctx->setMergeCommonStrings(true);
- if (parsedArgs->hasArg(OPT_t))
+ if (parsedArgs.hasArg(OPT_t))
ctx->setLogInputFiles(true);
- if (parsedArgs->hasArg(OPT_use_shlib_undefs))
+ if (parsedArgs.hasArg(OPT_use_shlib_undefs))
ctx->setUseShlibUndefines(true);
- if (auto val = getBool(*parsedArgs, OPT_allow_shlib_undefs,
+ if (auto val = getBool(parsedArgs, OPT_allow_shlib_undefs,
OPT_no_allow_shlib_undefs))
ctx->setAllowShlibUndefines(*val);
- if (auto *arg = parsedArgs->getLastArg(OPT_e))
+ if (auto *arg = parsedArgs.getLastArg(OPT_e))
ctx->setEntrySymbolName(arg->getValue());
- if (auto *arg = parsedArgs->getLastArg(OPT_output))
+ if (auto *arg = parsedArgs.getLastArg(OPT_output))
ctx->setOutputPath(arg->getValue());
- if (parsedArgs->hasArg(OPT_noinhibit_exec))
+ if (parsedArgs.hasArg(OPT_noinhibit_exec))
ctx->setAllowRemainingUndefines(true);
- if (auto val = getBool(*parsedArgs, OPT_export_dynamic,
- OPT_no_export_dynamic))
+ if (auto val = getBool(parsedArgs, OPT_export_dynamic, OPT_no_export_dynamic))
ctx->setExportDynamic(*val);
- if (parsedArgs->hasArg(OPT_allow_multiple_definition))
+ if (parsedArgs.hasArg(OPT_allow_multiple_definition))
ctx->setAllowDuplicates(true);
- if (auto *arg = parsedArgs->getLastArg(OPT_dynamic_linker))
+ if (auto *arg = parsedArgs.getLastArg(OPT_dynamic_linker))
ctx->setInterpreter(arg->getValue());
- if (auto *arg = parsedArgs->getLastArg(OPT_init))
+ if (auto *arg = parsedArgs.getLastArg(OPT_init))
ctx->setInitFunction(arg->getValue());
- if (auto *arg = parsedArgs->getLastArg(OPT_fini))
+ if (auto *arg = parsedArgs.getLastArg(OPT_fini))
ctx->setFiniFunction(arg->getValue());
- if (auto *arg = parsedArgs->getLastArg(OPT_output_filetype))
+ if (auto *arg = parsedArgs.getLastArg(OPT_output_filetype))
ctx->setOutputFileType(arg->getValue());
- for (auto *arg : parsedArgs->filtered(OPT_L))
+ // Process ELF/ARM specific options
+ bool hasArmTarget1Rel = parsedArgs.hasArg(OPT_target1_rel);
+ bool hasArmTarget1Abs = parsedArgs.hasArg(OPT_target1_abs);
+ if (triple.getArch() == llvm::Triple::arm) {
+ if (hasArmTarget1Rel && hasArmTarget1Abs) {
+ diag << "error: options --target1-rel and --target1-abs"
+ " can't be used together.\n";
+ return false;
+ } else if (hasArmTarget1Rel || hasArmTarget1Abs) {
+ ctx->setArmTarget1Rel(hasArmTarget1Rel && !hasArmTarget1Abs);
+ }
+ } else {
+ for (const auto *arg : parsedArgs.filtered(OPT_grp_arm_targetopts)) {
+ diag << "warning: ignoring unsupported ARM/ELF specific argument: "
+ << arg->getSpelling() << "\n";
+ }
+ }
+
+ // Process MIPS specific options.
+ if (triple.getArch() == llvm::Triple::mips ||
+ triple.getArch() == llvm::Triple::mipsel ||
+ triple.getArch() == llvm::Triple::mips64 ||
+ triple.getArch() == llvm::Triple::mips64el) {
+ ctx->setMipsPcRelEhRel(parsedArgs.hasArg(OPT_pcrel_eh_reloc));
+ auto *hashArg = parsedArgs.getLastArg(OPT_hash_style);
+ if (hashArg && hashArg->getValue() != StringRef("sysv")) {
+ diag << "error: .gnu.hash is incompatible with the MIPS ABI\n";
+ return false;
+ }
+ }
+ else {
+ for (const auto *arg : parsedArgs.filtered(OPT_grp_mips_targetopts)) {
+ diag << "warning: ignoring unsupported MIPS specific argument: "
+ << arg->getSpelling() << "\n";
+ }
+ }
+
+ for (auto *arg : parsedArgs.filtered(OPT_L))
ctx->addSearchPath(arg->getValue());
// Add the default search directory specific to the target.
- if (!parsedArgs->hasArg(OPT_nostdlib))
+ if (!parsedArgs.hasArg(OPT_nostdlib))
addPlatformSearchDirs(*ctx, triple, baseTriple);
- for (auto *arg : parsedArgs->filtered(OPT_u))
+ for (auto *arg : parsedArgs.filtered(OPT_u))
ctx->addInitialUndefinedSymbol(arg->getValue());
- for (auto *arg : parsedArgs->filtered(OPT_defsym)) {
+ for (auto *arg : parsedArgs.filtered(OPT_defsym)) {
StringRef sym, target;
uint64_t addr;
if (parseDefsymAsAbsolute(arg->getValue(), sym, addr)) {
@@ -566,11 +578,15 @@ bool GnuLdDriver::parse(int argc, const char *argv[],
}
}
- for (auto *arg : parsedArgs->filtered(OPT_z)) {
+ for (auto *arg : parsedArgs.filtered(OPT_z)) {
StringRef opt = arg->getValue();
- if (opt == "muldefs") {
+ if (opt == "muldefs")
ctx->setAllowDuplicates(true);
- } else if (opt.startswith("max-page-size")) {
+ else if (opt == "now")
+ ctx->setDTFlag(ELFLinkingContext::DTFlag::DT_NOW);
+ else if (opt == "origin")
+ ctx->setDTFlag(ELFLinkingContext::DTFlag::DT_ORIGIN);
+ else if (opt.startswith("max-page-size")) {
// Parse -z max-page-size option.
// The default page size is considered the minimum page size the user
// can set, check the user input if its atleast the minimum page size
@@ -592,39 +608,46 @@ bool GnuLdDriver::parse(int argc, const char *argv[],
}
}
- for (auto *arg : parsedArgs->filtered(OPT_rpath)) {
+ for (auto *arg : parsedArgs.filtered(OPT_rpath)) {
SmallVector<StringRef, 2> rpaths;
StringRef(arg->getValue()).split(rpaths, ":");
for (auto path : rpaths)
ctx->addRpath(path);
}
- for (auto *arg : parsedArgs->filtered(OPT_rpath_link)) {
+ for (auto *arg : parsedArgs.filtered(OPT_rpath_link)) {
SmallVector<StringRef, 2> rpaths;
StringRef(arg->getValue()).split(rpaths, ":");
for (auto path : rpaths)
ctx->addRpathLink(path);
}
+ // Enable new dynamic tags.
+ if (parsedArgs.hasArg(OPT_enable_newdtags))
+ ctx->setEnableNewDtags(true);
+
// Support --wrap option.
- for (auto *arg : parsedArgs->filtered(OPT_wrap))
+ for (auto *arg : parsedArgs.filtered(OPT_wrap))
ctx->addWrapForSymbol(arg->getValue());
// Register possible input file parsers.
ctx->registry().addSupportELFObjects(*ctx);
ctx->registry().addSupportArchives(ctx->logInputFiles());
ctx->registry().addSupportYamlFiles();
- ctx->registry().addSupportNativeObjects();
if (ctx->allowLinkWithDynamicLibraries())
ctx->registry().addSupportELFDynamicSharedObjects(*ctx);
+ // Parse the LLVM options before we process files in case the file handling
+ // makes use of things like DEBUG().
+ parseLLVMOptions(*ctx);
+
std::stack<int> groupStack;
int numfiles = 0;
bool asNeeded = false;
bool wholeArchive = false;
// Process files
- for (auto arg : *parsedArgs) {
+ for (auto arg : parsedArgs) {
switch (arg->getOption().getID()) {
case OPT_no_whole_archive:
wholeArchive = false;
@@ -685,7 +708,7 @@ bool GnuLdDriver::parse(int argc, const char *argv[],
diag << "Cannot open " << path << ": " << ec.message() << "\n";
return false;
}
- bool nostdlib = parsedArgs->hasArg(OPT_nostdlib);
+ bool nostdlib = parsedArgs.hasArg(OPT_nostdlib);
std::error_code ec =
evalLinkerScript(*ctx, std::move(mb.get()), diag, nostdlib);
if (ec) {
@@ -721,9 +744,6 @@ bool GnuLdDriver::parse(int argc, const char *argv[],
case LinkingContext::OutputFileType::YAML:
ctx->setOutputPath("-");
break;
- case LinkingContext::OutputFileType::Native:
- ctx->setOutputPath("a.native");
- break;
default:
ctx->setOutputPath("a.out");
break;
@@ -735,7 +755,10 @@ bool GnuLdDriver::parse(int argc, const char *argv[],
return false;
// Perform linker script semantic actions
- ctx->linkerScriptSema().perform();
+ if (auto ec = ctx->linkerScriptSema().perform()) {
+ diag << "Error in the linker script's semantics: " << ec.message() << "\n";
+ return false;
+ }
context.swap(ctx);
return true;
diff --git a/lib/Driver/GnuLdOptions.td b/lib/Driver/GnuLdOptions.td
index 9d06f2935439..7d850d4d002e 100644
--- a/lib/Driver/GnuLdOptions.td
+++ b/lib/Driver/GnuLdOptions.td
@@ -25,6 +25,15 @@ multiclass dashEq<string opt1, string opt2, string help> {
Alias<!cast<Option>(opt1)>;
}
+// Support --<option>,--<option>=
+multiclass mDashEq<string opt1, string help> {
+ // Option
+ def "" : Separate<["--"], opt1>, HelpText<help>;
+ // Compatibility aliases
+ def opt2_eq : Joined<["--"], opt1#"=">,
+ Alias<!cast<Option>(opt1)>;
+}
+
//===----------------------------------------------------------------------===//
/// LLVM and Target options
//===----------------------------------------------------------------------===//
@@ -62,7 +71,7 @@ def grp_general : OptionGroup<"opts">,
def output : Separate<["-"], "o">, MetaVarName<"<path>">,
HelpText<"Path to file to write output">,
Group<grp_general>;
-def m : Separate<["-"], "m">, MetaVarName<"<emulation>">,
+def m : JoinedOrSeparate<["-"], "m">, MetaVarName<"<emulation>">,
HelpText<"Select target emulation">,
Group<grp_general>;
def build_id : Flag<["--"], "build-id">,
@@ -142,7 +151,7 @@ def grp_dynlibexec : OptionGroup<"opts">,
def dynamic_linker : Joined<["--"], "dynamic-linker=">,
HelpText<"Set the path to the dynamic linker">, Group<grp_dynlibexec>;
// Executable options - compatibility aliases
-def dynamic_linker_alias : Separate<["-"], "dynamic-linker">,
+def dynamic_linker_alias : Separate<["-", "--"], "dynamic-linker">,
Alias<dynamic_linker>;
defm rpath : dashEq<"rpath", "rpath",
"Add a directory to the runtime library search path">,
@@ -211,15 +220,23 @@ def use_shlib_undefs: Flag<["--"], "use-shlib-undefines">,
def allow_multiple_definition: Flag<["--"], "allow-multiple-definition">,
HelpText<"Allow multiple definitions">,
Group<grp_resolveropt>;
-def defsym : Joined<["--"], "defsym=">,
- HelpText<"Create a defined symbol">,
- Group<grp_resolveropt>;
+defm defsym : mDashEq<"defsym",
+ "Create a global symbol in the output file "
+ "containing the absolute address given by expression">,
+ MetaVarName<"symbol=<expression>">,
+ Group<grp_resolveropt>;
//===----------------------------------------------------------------------===//
/// Custom Options
//===----------------------------------------------------------------------===//
def grp_customopts : OptionGroup<"opts">,
HelpText<"CUSTOM OPTIONS">;
+def disable_newdtags: Flag<["--"], "disable-new-dtags">,
+ HelpText<"Disable new dynamic tags">,
+ Group<grp_customopts>;
+def enable_newdtags: Flag<["--"], "enable-new-dtags">,
+ HelpText<"Enable new dynamic tags">,
+ Group<grp_customopts>;
def rosegment: Flag<["--"], "rosegment">,
HelpText<"Put read-only non-executable sections in their own segment">,
Group<grp_customopts>;
@@ -238,6 +255,16 @@ def grp_symbolopts : OptionGroup<"opts">,
def demangle : Flag<["--"], "demangle">,
HelpText<"Demangle C++ symbols">,
Group<grp_symbolopts>;
+def discard_loc : Flag<["--"], "discard-all">,
+ HelpText<"Discard all local symbols">,
+ Group<grp_symbolopts>;
+def alias_discard_loc: Flag<["-"], "x">,
+ Alias<discard_loc>;
+def discard_temp_loc : Flag<["--"], "discard-locals">,
+ HelpText<"Discard temporary local symbols">,
+ Group<grp_symbolopts>;
+def alias_discard_temp_loc : Flag<["-"], "X">,
+ Alias<discard_temp_loc>;
def no_demangle : Flag<["--"], "no-demangle">,
HelpText<"Dont demangle C++ symbols">,
Group<grp_symbolopts>;
@@ -296,12 +323,37 @@ def stats : Flag<["--"], "stats">,
def grp_extns : OptionGroup<"opts">,
HelpText<"Extensions">;
def output_filetype: Separate<["--"], "output-filetype">,
- HelpText<"Specify what type of output file that lld creates, YAML/Native">,
+ HelpText<"Specify yaml to create an output in YAML format">,
Group<grp_extns>;
def alias_output_filetype: Joined<["--"], "output-filetype=">,
Alias<output_filetype>;
//===----------------------------------------------------------------------===//
+/// Target Specific Options
+//===----------------------------------------------------------------------===//
+def grp_targetopts : OptionGroup<"opts">,
+ HelpText<"ARCH SPECIFIC OPTIONS">;
+
+//===----------------------------------------------------------------------===//
+/// ARM Target Specific Options
+//===----------------------------------------------------------------------===//
+def grp_arm_targetopts : OptionGroup<"ARM SPECIFIC OPTIONS">,
+ Group<grp_targetopts>;
+def target1_rel : Flag<["--"], "target1-rel">,
+ Group<grp_arm_targetopts>, HelpText<"Interpret R_ARM_TARGET1 as R_ARM_REL32">;
+def target1_abs : Flag<["--"], "target1-abs">,
+ Group<grp_arm_targetopts>, HelpText<"Interpret R_ARM_TARGET1 as R_ARM_ABS32">;
+
+//===----------------------------------------------------------------------===//
+/// MIPS Target Specific Options
+//===----------------------------------------------------------------------===//
+def grp_mips_targetopts : OptionGroup<"MIPS SPECIFIC OPTIONS">,
+ Group<grp_targetopts>;
+def pcrel_eh_reloc : Flag<["-", "--"], "pcrel-eh-reloc">,
+ Group<grp_mips_targetopts>,
+ HelpText<"Interpret R_MIPS_EH as R_MIPS_PC32">;
+
+//===----------------------------------------------------------------------===//
/// Ignored options
//===----------------------------------------------------------------------===//
def grp_ignored: OptionGroup<"ignored">,
@@ -315,6 +367,9 @@ def Qy : Flag<["-"], "Qy">,
def qmagic : Flag<["-"], "qmagic">,
HelpText<"Ignored for Linux Compatibility">,
Group<grp_ignored>;
+def G : Separate<["-"], "G">,
+ HelpText<"Ignored for MIPS GNU Linker Compatibility">,
+ Group<grp_ignored>;
//===----------------------------------------------------------------------===//
/// Help
diff --git a/lib/Driver/Makefile b/lib/Driver/Makefile
deleted file mode 100644
index 19024cfab0f1..000000000000
--- a/lib/Driver/Makefile
+++ /dev/null
@@ -1,38 +0,0 @@
-##===- lld/lib/Driver/Makefile ---------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LLD_LEVEL := ../..
-LIBRARYNAME := lldDriver
-
-BUILT_SOURCES = CoreOptions.inc UniversalDriverOptions.inc DarwinLdOptions.inc \
- GnuLdOptions.inc WinLinkOptions.inc
-
-TABLEGEN_INC_FILES_COMMON = 1
-
-include $(LLD_LEVEL)/Makefile
-
-$(ObjDir)/CoreOptions.inc.tmp : CoreOptions.td $(LLVM_TBLGEN) $(ObjDir)/.dir
- $(Echo) "Building LLD CoreOptions Option tables with tblgen"
- $(Verb) $(LLVMTableGen) -gen-opt-parser-defs -o $(call SYSPATH, $@) $<
-
-$(ObjDir)/UniversalDriverOptions.inc.tmp : UniversalDriverOptions.td $(LLVM_TBLGEN) $(ObjDir)/.dir
- $(Echo) "Building LLD Universal Driver Options tables with tblgen"
- $(Verb) $(LLVMTableGen) -gen-opt-parser-defs -o $(call SYSPATH, $@) $<
-
-$(ObjDir)/DarwinLdOptions.inc.tmp : DarwinLdOptions.td $(LLVM_TBLGEN) $(ObjDir)/.dir
- $(Echo) "Building LLD Darwin ld Option tables with tblgen"
- $(Verb) $(LLVMTableGen) -gen-opt-parser-defs -o $(call SYSPATH, $@) $<
-
-$(ObjDir)/GnuLdOptions.inc.tmp : GnuLdOptions.td $(LLVM_TBLGEN) $(ObjDir)/.dir
- $(Echo) "Building LLD Gnu ld Option tables with tblgen"
- $(Verb) $(LLVMTableGen) -gen-opt-parser-defs -o $(call SYSPATH, $@) $<
-
-$(ObjDir)/WinLinkOptions.inc.tmp : WinLinkOptions.td $(LLVM_TBLGEN) $(ObjDir)/.dir
- $(Echo) "Building LLD WinLinkOptions Option tables with tblgen"
- $(Verb) $(LLVMTableGen) -gen-opt-parser-defs -o $(call SYSPATH, $@) $<
diff --git a/lib/Driver/TODO.rst b/lib/Driver/TODO.rst
index e03d829c232d..868eaf02290c 100644
--- a/lib/Driver/TODO.rst
+++ b/lib/Driver/TODO.rst
@@ -35,8 +35,6 @@ Missing Options
* -Ur
* --unique
* -v,--version,-V
-* -x,--discard-all
-* -X,--discard-locals
* -y,--trace-symbol
* -z (keywords need to be implemented)
* --accept-unknown-input-arch,--no-accept-unknown-input-arch
diff --git a/lib/Driver/UniversalDriver.cpp b/lib/Driver/UniversalDriver.cpp
index 7d42ad7b4bfc..3dea7ebfae89 100644
--- a/lib/Driver/UniversalDriver.cpp
+++ b/lib/Driver/UniversalDriver.cpp
@@ -63,15 +63,16 @@ static const llvm::opt::OptTable::Info infoTable[] = {
class UniversalDriverOptTable : public llvm::opt::OptTable {
public:
UniversalDriverOptTable()
- : OptTable(infoTable, llvm::array_lengthof(infoTable)) {}
+ : OptTable(infoTable) {}
};
enum class Flavor {
invalid,
- gnu_ld, // -flavor gnu
- win_link, // -flavor link
- darwin_ld, // -flavor darwin
- core // -flavor core OR -core
+ old_gnu_ld, // -flavor old-gnu
+ gnu_ld, // -flavor gnu
+ win_link, // -flavor link
+ darwin_ld, // -flavor darwin
+ core // -flavor core OR -core
};
struct ProgramNameParts {
@@ -83,7 +84,9 @@ struct ProgramNameParts {
static Flavor strToFlavor(StringRef str) {
return llvm::StringSwitch<Flavor>(str)
+ .Case("old-gnu", Flavor::old_gnu_ld)
.Case("gnu", Flavor::gnu_ld)
+ .Case("ld.lld", Flavor::gnu_ld)
.Case("link", Flavor::win_link)
.Case("lld-link", Flavor::win_link)
.Case("darwin", Flavor::darwin_ld)
@@ -124,27 +127,27 @@ static ProgramNameParts parseProgramName(StringRef programName) {
// Removes the argument from argv along with its value, if exists, and updates
// argc.
-static void removeArg(llvm::opt::Arg *arg, int &argc, const char **&argv) {
+static void removeArg(llvm::opt::Arg *arg,
+ llvm::MutableArrayRef<const char *> &args) {
unsigned int numToRemove = arg->getNumValues() + 1;
- unsigned int argIndex = arg->getIndex() + 1;
-
- std::rotate(&argv[argIndex], &argv[argIndex + numToRemove], argv + argc);
- argc -= numToRemove;
+ auto sub = args.slice(arg->getIndex() + 1);
+ std::rotate(sub.begin(), sub.begin() + numToRemove, sub.end());
+ args = args.drop_back(numToRemove);
}
-static Flavor getFlavor(int &argc, const char **&argv,
- std::unique_ptr<llvm::opt::InputArgList> &parsedArgs) {
- if (llvm::opt::Arg *argCore = parsedArgs->getLastArg(OPT_core)) {
- removeArg(argCore, argc, argv);
+static Flavor getFlavor(llvm::MutableArrayRef<const char *> &args,
+ const llvm::opt::InputArgList &parsedArgs) {
+ if (llvm::opt::Arg *argCore = parsedArgs.getLastArg(OPT_core)) {
+ removeArg(argCore, args);
return Flavor::core;
}
- if (llvm::opt::Arg *argFlavor = parsedArgs->getLastArg(OPT_flavor)) {
- removeArg(argFlavor, argc, argv);
+ if (llvm::opt::Arg *argFlavor = parsedArgs.getLastArg(OPT_flavor)) {
+ removeArg(argFlavor, args);
return strToFlavor(argFlavor->getValue());
}
#if LLVM_ON_UNIX
- if (llvm::sys::path::filename(argv[0]).equals("ld")) {
+ if (llvm::sys::path::filename(args[0]).equals("ld")) {
#if __APPLE__
// On a Darwin systems, if linker binary is named "ld", use Darwin driver.
return Flavor::darwin_ld;
@@ -154,59 +157,63 @@ static Flavor getFlavor(int &argc, const char **&argv,
}
#endif
- StringRef name = llvm::sys::path::stem(argv[0]);
+ StringRef name = llvm::sys::path::filename(args[0]);
+ if (name.endswith_lower(".exe"))
+ name = llvm::sys::path::stem(name);
return strToFlavor(parseProgramName(name)._flavor);
}
namespace lld {
-bool UniversalDriver::link(int argc, const char *argv[],
+bool UniversalDriver::link(llvm::MutableArrayRef<const char *> args,
raw_ostream &diagnostics) {
// Parse command line options using GnuLdOptions.td
- std::unique_ptr<llvm::opt::InputArgList> parsedArgs;
UniversalDriverOptTable table;
unsigned missingIndex;
unsigned missingCount;
// Program name
- StringRef programName = llvm::sys::path::stem(argv[0]);
+ StringRef programName = llvm::sys::path::stem(args[0]);
- parsedArgs.reset(
- table.ParseArgs(&argv[1], &argv[argc], missingIndex, missingCount));
+ llvm::opt::InputArgList parsedArgs =
+ table.ParseArgs(args.slice(1), missingIndex, missingCount);
if (missingCount) {
diagnostics << "error: missing arg value for '"
- << parsedArgs->getArgString(missingIndex) << "' expected "
+ << parsedArgs.getArgString(missingIndex) << "' expected "
<< missingCount << " argument(s).\n";
return false;
}
// Handle -help
- if (parsedArgs->getLastArg(OPT_help)) {
+ if (parsedArgs.getLastArg(OPT_help)) {
table.PrintHelp(llvm::outs(), programName.data(), "LLVM Linker", false);
return true;
}
// Handle -version
- if (parsedArgs->getLastArg(OPT_version)) {
+ if (parsedArgs.getLastArg(OPT_version)) {
diagnostics << "LLVM Linker Version: " << getLLDVersion()
<< getLLDRepositoryVersion() << "\n";
return true;
}
- Flavor flavor = getFlavor(argc, argv, parsedArgs);
- std::vector<const char *> args(argv, argv + argc);
+ Flavor flavor = getFlavor(args, parsedArgs);
// Switch to appropriate driver.
switch (flavor) {
+ case Flavor::old_gnu_ld:
+ return GnuLdDriver::linkELF(args, diagnostics);
case Flavor::gnu_ld:
- return GnuLdDriver::linkELF(args.size(), args.data(), diagnostics);
+ elf2::link(args);
+ return true;
case Flavor::darwin_ld:
- return DarwinLdDriver::linkMachO(args.size(), args.data(), diagnostics);
+ return DarwinLdDriver::linkMachO(args, diagnostics);
case Flavor::win_link:
- return WinLinkDriver::linkPECOFF(args.size(), args.data(), diagnostics);
+ coff::link(args);
+ return true;
case Flavor::core:
- return CoreDriver::link(args.size(), args.data(), diagnostics);
+ return CoreDriver::link(args, diagnostics);
case Flavor::invalid:
diagnostics << "Select the appropriate flavor\n";
table.PrintHelp(llvm::outs(), programName.data(), "LLVM Linker", false);
diff --git a/lib/Driver/WinLinkDriver.cpp b/lib/Driver/WinLinkDriver.cpp
deleted file mode 100644
index 6ee7a5a004b5..000000000000
--- a/lib/Driver/WinLinkDriver.cpp
+++ /dev/null
@@ -1,1371 +0,0 @@
-//===- lib/Driver/WinLinkDriver.cpp ---------------------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-///
-/// Concrete instance of the Driver for Windows link.exe.
-///
-//===----------------------------------------------------------------------===//
-
-#include "lld/Driver/Driver.h"
-#include "lld/Driver/WinLinkModuleDef.h"
-#include "lld/ReaderWriter/PECOFFLinkingContext.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/Optional.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/StringSwitch.h"
-#include "llvm/Object/COFF.h"
-#include "llvm/Option/Arg.h"
-#include "llvm/Option/Option.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/Process.h"
-#include "llvm/Support/Program.h"
-#include "llvm/Support/raw_ostream.h"
-#include <algorithm>
-#include <cctype>
-#include <map>
-#include <memory>
-#include <sstream>
-#include <tuple>
-
-namespace lld {
-
-//
-// Option definitions
-//
-
-// Create enum with OPT_xxx values for each option in WinLinkOptions.td
-enum {
- OPT_INVALID = 0,
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELP, META) \
- OPT_##ID,
-#include "WinLinkOptions.inc"
-#undef OPTION
-};
-
-// Create prefix string literals used in WinLinkOptions.td
-#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
-#include "WinLinkOptions.inc"
-#undef PREFIX
-
-// Create table mapping all options defined in WinLinkOptions.td
-static const llvm::opt::OptTable::Info infoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR) \
- { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \
- PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS },
-#include "WinLinkOptions.inc"
-#undef OPTION
-};
-
-namespace {
-
-// Create OptTable class for parsing actual command line arguments
-class WinLinkOptTable : public llvm::opt::OptTable {
-public:
- // link.exe's command line options are case insensitive, unlike
- // other driver's options for Unix.
- WinLinkOptTable()
- : OptTable(infoTable, llvm::array_lengthof(infoTable),
- /* ignoreCase */ true) {}
-};
-
-} // anonymous namespace
-
-//
-// Functions to parse each command line option
-//
-
-// Split the given string with spaces.
-static std::vector<std::string> splitArgList(const std::string &str) {
- std::stringstream stream(str);
- std::istream_iterator<std::string> begin(stream);
- std::istream_iterator<std::string> end;
- return std::vector<std::string>(begin, end);
-}
-
-// Split the given string with the path separator.
-static std::vector<StringRef> splitPathList(StringRef str) {
- std::vector<StringRef> ret;
- while (!str.empty()) {
- StringRef path;
- std::tie(path, str) = str.split(';');
- ret.push_back(path);
- }
- return ret;
-}
-
-// Parse an argument for /alternatename. The expected string is
-// "<string>=<string>".
-static bool parseAlternateName(StringRef arg, StringRef &weak, StringRef &def,
- raw_ostream &diag) {
- std::tie(weak, def) = arg.split('=');
- if (weak.empty() || def.empty()) {
- diag << "Error: malformed /alternatename option: " << arg << "\n";
- return false;
- }
- return true;
-}
-
-// Parse an argument for /base, /stack or /heap. The expected string
-// is "<integer>[,<integer>]".
-static bool parseMemoryOption(StringRef arg, uint64_t &reserve,
- uint64_t &commit) {
- StringRef reserveStr, commitStr;
- std::tie(reserveStr, commitStr) = arg.split(',');
- if (reserveStr.getAsInteger(0, reserve))
- return false;
- if (!commitStr.empty() && commitStr.getAsInteger(0, commit))
- return false;
- return true;
-}
-
-// Parse an argument for /version or /subsystem. The expected string is
-// "<integer>[.<integer>]".
-static bool parseVersion(StringRef arg, uint32_t &major, uint32_t &minor) {
- StringRef majorVersion, minorVersion;
- std::tie(majorVersion, minorVersion) = arg.split('.');
- if (minorVersion.empty())
- minorVersion = "0";
- if (majorVersion.getAsInteger(0, major))
- return false;
- if (minorVersion.getAsInteger(0, minor))
- return false;
- return true;
-}
-
-// Returns subsystem type for the given string.
-static llvm::COFF::WindowsSubsystem stringToWinSubsystem(StringRef str) {
- return llvm::StringSwitch<llvm::COFF::WindowsSubsystem>(str.lower())
- .Case("windows", llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_GUI)
- .Case("console", llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_CUI)
- .Case("boot_application",
- llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION)
- .Case("efi_application", llvm::COFF::IMAGE_SUBSYSTEM_EFI_APPLICATION)
- .Case("efi_boot_service_driver",
- llvm::COFF::IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER)
- .Case("efi_rom", llvm::COFF::IMAGE_SUBSYSTEM_EFI_ROM)
- .Case("efi_runtime_driver",
- llvm::COFF::IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER)
- .Case("native", llvm::COFF::IMAGE_SUBSYSTEM_NATIVE)
- .Case("posix", llvm::COFF::IMAGE_SUBSYSTEM_POSIX_CUI)
- .Default(llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN);
-}
-
-// Parse /subsystem command line option. The form of /subsystem is
-// "subsystem_name[,majorOSVersion[.minorOSVersion]]".
-static bool parseSubsystem(StringRef arg,
- llvm::COFF::WindowsSubsystem &subsystem,
- llvm::Optional<uint32_t> &major,
- llvm::Optional<uint32_t> &minor, raw_ostream &diag) {
- StringRef subsystemStr, osVersion;
- std::tie(subsystemStr, osVersion) = arg.split(',');
- if (!osVersion.empty()) {
- uint32_t v1, v2;
- if (!parseVersion(osVersion, v1, v2))
- return false;
- major = v1;
- minor = v2;
- }
- subsystem = stringToWinSubsystem(subsystemStr);
- if (subsystem == llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN) {
- diag << "error: unknown subsystem name: " << subsystemStr << "\n";
- return false;
- }
- return true;
-}
-
-static llvm::COFF::MachineTypes stringToMachineType(StringRef str) {
- // FIXME: we have no way to differentiate between ARM and ARMNT currently.
- // However, given that LLVM only supports ARM NT, default to that for now.
- return llvm::StringSwitch<llvm::COFF::MachineTypes>(str.lower())
- .Case("arm", llvm::COFF::IMAGE_FILE_MACHINE_ARMNT)
- .Case("x64", llvm::COFF::IMAGE_FILE_MACHINE_AMD64)
- .Case("x86", llvm::COFF::IMAGE_FILE_MACHINE_I386)
- .Default(llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN);
-}
-
-// Parse /section:name,[[!]{DEKPRSW}]
-//
-// /section option is to set non-default bits in the Characteristics fields of
-// the section header. D, E, K, P, R, S, and W represent discardable,
-// execute, not_cachable, not_pageable, read, shared, and write bits,
-// respectively. You can specify multiple flags in one /section option.
-//
-// If the flag starts with "!", the flags represent a mask that should be turned
-// off regardless of the default value. You can even create a section which is
-// not readable, writable nor executable with this -- although it's probably
-// useless.
-static bool parseSection(StringRef option, std::string &section,
- llvm::Optional<uint32_t> &flags,
- llvm::Optional<uint32_t> &mask) {
- StringRef flagString;
- std::tie(section, flagString) = option.split(",");
-
- bool negative = false;
- if (flagString.startswith("!")) {
- negative = true;
- flagString = flagString.substr(1);
- }
- if (flagString.empty())
- return false;
-
- uint32_t attribs = 0;
- for (size_t i = 0, e = flagString.size(); i < e; ++i) {
- switch (tolower(flagString[i])) {
-#define CASE(c, flag) \
- case c: \
- attribs |= flag; \
- break
- CASE('d', llvm::COFF::IMAGE_SCN_MEM_DISCARDABLE);
- CASE('e', llvm::COFF::IMAGE_SCN_MEM_EXECUTE);
- CASE('k', llvm::COFF::IMAGE_SCN_MEM_NOT_CACHED);
- CASE('p', llvm::COFF::IMAGE_SCN_MEM_NOT_PAGED);
- CASE('r', llvm::COFF::IMAGE_SCN_MEM_READ);
- CASE('s', llvm::COFF::IMAGE_SCN_MEM_SHARED);
- CASE('w', llvm::COFF::IMAGE_SCN_MEM_WRITE);
-#undef CASE
- default:
- return false;
- }
- }
-
- if (negative) {
- mask = attribs;
- } else {
- flags = attribs;
- }
- return true;
-}
-
-static bool readFile(PECOFFLinkingContext &ctx, StringRef path,
- ArrayRef<uint8_t> &result) {
- ErrorOr<std::unique_ptr<MemoryBuffer>> buf = MemoryBuffer::getFile(path);
- if (!buf)
- return false;
- StringRef Data = buf.get()->getBuffer();
- result = ctx.allocate(ArrayRef<uint8_t>(
- reinterpret_cast<const uint8_t *>(Data.begin()), Data.size()));
- return true;
-}
-
-// Parse /manifest:EMBED[,ID=#]|NO.
-static bool parseManifest(StringRef option, bool &enable, bool &embed,
- int &id) {
- if (option.equals_lower("no")) {
- enable = false;
- return true;
- }
- if (!option.startswith_lower("embed"))
- return false;
-
- embed = true;
- option = option.substr(strlen("embed"));
- if (option.empty())
- return true;
- if (!option.startswith_lower(",id="))
- return false;
- option = option.substr(strlen(",id="));
- if (option.getAsInteger(0, id))
- return false;
- return true;
-}
-
-static bool isLibraryFile(StringRef path) {
- return path.endswith_lower(".lib") || path.endswith_lower(".imp");
-}
-
-static StringRef getObjectPath(PECOFFLinkingContext &ctx, StringRef path) {
- std::string result;
- if (isLibraryFile(path)) {
- result = ctx.searchLibraryFile(path);
- } else if (llvm::sys::path::extension(path).empty()) {
- result = path.str() + ".obj";
- } else {
- result = path;
- }
- return ctx.allocate(result);
-}
-
-static StringRef getLibraryPath(PECOFFLinkingContext &ctx, StringRef path) {
- std::string result = isLibraryFile(path)
- ? ctx.searchLibraryFile(path)
- : ctx.searchLibraryFile(path.str() + ".lib");
- return ctx.allocate(result);
-}
-
-// Returns true if the given file is a Windows resource file.
-static bool isResoruceFile(StringRef path) {
- llvm::sys::fs::file_magic fileType;
- if (llvm::sys::fs::identify_magic(path, fileType)) {
- // If we cannot read the file, assume it's not a resource file.
- // The further stage will raise an error on this unreadable file.
- return false;
- }
- return fileType == llvm::sys::fs::file_magic::windows_resource;
-}
-
-// Merge Windows resource files and convert them to a single COFF file.
-// The temporary file path is set to result.
-static bool convertResourceFiles(PECOFFLinkingContext &ctx,
- std::vector<std::string> inFiles,
- std::string &result) {
- // Create an output file path.
- SmallString<128> outFile;
- if (llvm::sys::fs::createTemporaryFile("resource", "obj", outFile))
- return false;
- std::string outFileArg = ("/out:" + outFile).str();
-
- // Construct CVTRES.EXE command line and execute it.
- std::string program = "cvtres.exe";
- ErrorOr<std::string> programPathOrErr = llvm::sys::findProgramByName(program);
- if (!programPathOrErr) {
- llvm::errs() << "Unable to find " << program << " in PATH\n";
- return false;
- }
- const std::string &programPath = *programPathOrErr;
-
- std::vector<const char *> args;
- args.push_back(programPath.c_str());
- args.push_back(ctx.is64Bit() ? "/machine:x64" : "/machine:x86");
- args.push_back("/readonly");
- args.push_back("/nologo");
- args.push_back(outFileArg.c_str());
- for (const std::string &path : inFiles)
- args.push_back(path.c_str());
- args.push_back(nullptr);
-
- if (llvm::sys::ExecuteAndWait(programPath.c_str(), &args[0]) != 0) {
- llvm::errs() << program << " failed\n";
- return false;
- }
- result = outFile.str();
- return true;
-}
-
-// Parse /manifestuac:(level=<string>|uiAccess=<string>).
-//
-// The arguments will be embedded to the manifest XML file with no error check,
-// so the values given via the command line must be valid as XML attributes.
-// This may sound a bit odd, but that's how link.exe works, so we will follow.
-static bool parseManifestUAC(StringRef option,
- llvm::Optional<std::string> &level,
- llvm::Optional<std::string> &uiAccess) {
- for (;;) {
- option = option.ltrim();
- if (option.empty())
- return true;
- if (option.startswith_lower("level=")) {
- option = option.substr(strlen("level="));
- StringRef value;
- std::tie(value, option) = option.split(" ");
- level = value.str();
- continue;
- }
- if (option.startswith_lower("uiaccess=")) {
- option = option.substr(strlen("uiaccess="));
- StringRef value;
- std::tie(value, option) = option.split(" ");
- uiAccess = value.str();
- continue;
- }
- return false;
- }
-}
-
-// Returns the machine type (e.g. x86) of the given input file.
-// If the file is not COFF, returns false.
-static bool getMachineType(StringRef path, llvm::COFF::MachineTypes &result) {
- llvm::sys::fs::file_magic fileType;
- if (llvm::sys::fs::identify_magic(path, fileType))
- return false;
- if (fileType != llvm::sys::fs::file_magic::coff_object)
- return false;
- ErrorOr<std::unique_ptr<MemoryBuffer>> buf = MemoryBuffer::getFile(path);
- if (!buf)
- return false;
- std::error_code ec;
- llvm::object::COFFObjectFile obj(buf.get()->getMemBufferRef(), ec);
- if (ec)
- return false;
- result = static_cast<llvm::COFF::MachineTypes>(obj.getMachine());
- return true;
-}
-
-// Parse /export:entryname[=internalname][,@ordinal[,NONAME]][,DATA][,PRIVATE].
-//
-// MSDN doesn't say anything about /export:foo=bar style option or PRIVATE
-// attribtute, but link.exe actually accepts them.
-static bool parseExport(StringRef option,
- PECOFFLinkingContext::ExportDesc &ret) {
- StringRef name;
- StringRef rest;
- std::tie(name, rest) = option.split(",");
- if (name.empty())
- return false;
- if (name.find('=') == StringRef::npos) {
- ret.name = name;
- } else {
- std::tie(ret.externalName, ret.name) = name.split("=");
- if (ret.name.empty())
- return false;
- }
-
- for (;;) {
- if (rest.empty())
- return true;
- StringRef arg;
- std::tie(arg, rest) = rest.split(",");
- if (arg.equals_lower("noname")) {
- if (ret.ordinal < 0)
- return false;
- ret.noname = true;
- continue;
- }
- if (arg.equals_lower("data")) {
- ret.isData = true;
- continue;
- }
- if (arg.equals_lower("private")) {
- ret.isPrivate = true;
- continue;
- }
- if (arg.startswith("@")) {
- int ordinal;
- if (arg.substr(1).getAsInteger(0, ordinal))
- return false;
- if (ordinal <= 0 || 65535 < ordinal)
- return false;
- ret.ordinal = ordinal;
- continue;
- }
- return false;
- }
-}
-
-// Read module-definition file.
-static bool parseDef(StringRef option, llvm::BumpPtrAllocator &alloc,
- std::vector<moduledef::Directive *> &result) {
- ErrorOr<std::unique_ptr<MemoryBuffer>> buf = MemoryBuffer::getFile(option);
- if (!buf)
- return false;
- moduledef::Lexer lexer(std::move(buf.get()));
- moduledef::Parser parser(lexer, alloc);
- return parser.parse(result);
-}
-
-static StringRef replaceExtension(PECOFFLinkingContext &ctx, StringRef path,
- StringRef extension) {
- SmallString<128> val = path;
- llvm::sys::path::replace_extension(val, extension);
- return ctx.allocate(val.str());
-}
-
-// Create a manifest file contents.
-static std::string createManifestXml(PECOFFLinkingContext &ctx) {
- std::string ret;
- llvm::raw_string_ostream out(ret);
- // Emit the XML. Note that we do *not* verify that the XML attributes are
- // syntactically correct. This is intentional for link.exe compatibility.
- out << "<?xml version=\"1.0\" standalone=\"yes\"?>\n"
- "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\"\n"
- " manifestVersion=\"1.0\">\n";
- if (ctx.getManifestUAC()) {
- out << " <trustInfo>\n"
- " <security>\n"
- " <requestedPrivileges>\n"
- " <requestedExecutionLevel level=" << ctx.getManifestLevel()
- << " uiAccess=" << ctx.getManifestUiAccess()
- << "/>\n"
- " </requestedPrivileges>\n"
- " </security>\n"
- " </trustInfo>\n";
- const std::string &dependency = ctx.getManifestDependency();
- if (!dependency.empty()) {
- out << " <dependency>\n"
- " <dependentAssembly>\n"
- " <assemblyIdentity " << dependency
- << " />\n"
- " </dependentAssembly>\n"
- " </dependency>\n";
- }
- }
- out << "</assembly>\n";
- out.flush();
- return ret;
-}
-
-// Convert one doublequote to two doublequotes, so that we can embed the string
-// into a resource script file.
-static void quoteAndPrintXml(raw_ostream &out, StringRef str) {
- for (;;) {
- if (str.empty())
- return;
- StringRef line;
- std::tie(line, str) = str.split("\n");
- if (line.empty())
- continue;
- out << '\"';
- const char *p = line.data();
- for (int i = 0, size = line.size(); i < size; ++i) {
- switch (p[i]) {
- case '\"':
- out << '\"';
- // fallthrough
- default:
- out << p[i];
- }
- }
- out << "\"\n";
- }
-}
-
-// Create a resource file (.res file) containing the manifest XML. This is done
-// in two steps:
-//
-// 1. Create a resource script file containing the XML as a literal string.
-// 2. Run RC.EXE command to compile the script file to a resource file.
-//
-// The temporary file created in step 1 will be deleted on exit from this
-// function. The file created in step 2 will have the same lifetime as the
-// PECOFFLinkingContext.
-static bool createManifestResourceFile(PECOFFLinkingContext &ctx,
- raw_ostream &diag,
- std::string &resFile) {
- // Create a temporary file for the resource script file.
- SmallString<128> rcFileSmallString;
- if (llvm::sys::fs::createTemporaryFile("tmp", "rc", rcFileSmallString)) {
- diag << "Cannot create a temporary file\n";
- return false;
- }
- StringRef rcFile(rcFileSmallString.str());
- llvm::FileRemover rcFileRemover((Twine(rcFile)));
-
- // Open the temporary file for writing.
- std::error_code ec;
- llvm::raw_fd_ostream out(rcFileSmallString, ec, llvm::sys::fs::F_Text);
- if (ec) {
- diag << "Failed to open " << ctx.getManifestOutputPath() << ": "
- << ec.message() << "\n";
- return false;
- }
-
- // Write resource script to the RC file.
- out << "#define LANG_ENGLISH 9\n"
- << "#define SUBLANG_DEFAULT 1\n"
- << "#define APP_MANIFEST " << ctx.getManifestId() << "\n"
- << "#define RT_MANIFEST 24\n"
- << "LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT\n"
- << "APP_MANIFEST RT_MANIFEST {\n";
- quoteAndPrintXml(out, createManifestXml(ctx));
- out << "}\n";
- out.close();
-
- // Create output resource file.
- SmallString<128> resFileSmallString;
- if (llvm::sys::fs::createTemporaryFile("tmp", "res", resFileSmallString)) {
- diag << "Cannot create a temporary file";
- return false;
- }
- resFile = resFileSmallString.str();
-
- // Register the resource file path so that the file will be deleted when the
- // context's destructor is called.
- ctx.registerTemporaryFile(resFile);
-
- // Run RC.EXE /fo tmp.res tmp.rc
- std::string program = "rc.exe";
- ErrorOr<std::string> programPathOrErr = llvm::sys::findProgramByName(program);
- if (!programPathOrErr) {
- diag << "Unable to find " << program << " in PATH\n";
- return false;
- }
- const std::string &programPath = *programPathOrErr;
- std::vector<const char *> args;
- args.push_back(programPath.c_str());
- args.push_back("/fo");
- args.push_back(resFile.c_str());
- args.push_back("/nologo");
- args.push_back(rcFileSmallString.c_str());
- args.push_back(nullptr);
-
- if (llvm::sys::ExecuteAndWait(programPath.c_str(), &args[0]) != 0) {
- diag << program << " failed\n";
- return false;
- }
- return true;
-}
-
-
-// Create the a side-by-side manifest file.
-//
-// The manifest file will convey some information to the linker, such as whether
-// the binary needs to run as Administrator or not. Instead of being placed in
-// the PE/COFF header, it's in XML format for some reason -- I guess it's
-// probably because it's invented in the early dot-com era.
-//
-// The side-by-side manifest file is a separate XML file having ".manifest"
-// extension. It will be created in the same directory as the resulting
-// executable.
-static bool createSideBySideManifestFile(PECOFFLinkingContext &ctx,
- raw_ostream &diag) {
- std::string path = ctx.getManifestOutputPath();
- if (path.empty()) {
- // Default name of the manifest file is "foo.exe.manifest" where "foo.exe" is
- // the output path.
- path = ctx.outputPath();
- path.append(".manifest");
- }
-
- std::error_code ec;
- llvm::raw_fd_ostream out(path, ec, llvm::sys::fs::F_Text);
- if (ec) {
- diag << ec.message() << "\n";
- return false;
- }
- out << createManifestXml(ctx);
- return true;
-}
-
-// Handle /failifmismatch option.
-static bool
-handleFailIfMismatchOption(StringRef option,
- std::map<StringRef, StringRef> &mustMatch,
- raw_ostream &diag) {
- StringRef key, value;
- std::tie(key, value) = option.split('=');
- if (key.empty() || value.empty()) {
- diag << "error: malformed /failifmismatch option: " << option << "\n";
- return true;
- }
- auto it = mustMatch.find(key);
- if (it != mustMatch.end() && it->second != value) {
- diag << "error: mismatch detected: '" << it->second << "' and '" << value
- << "' for key '" << key << "'\n";
- return true;
- }
- mustMatch[key] = value;
- return false;
-}
-
-//
-// Environment variable
-//
-
-// Process "LINK" environment variable. If defined, the value of the variable
-// should be processed as command line arguments.
-static std::vector<const char *> processLinkEnv(PECOFFLinkingContext &ctx,
- int argc, const char **argv) {
- std::vector<const char *> ret;
- // The first argument is the name of the command. This should stay at the head
- // of the argument list.
- assert(argc > 0);
- ret.push_back(argv[0]);
-
- // Add arguments specified by the LINK environment variable.
- llvm::Optional<std::string> env = llvm::sys::Process::GetEnv("LINK");
- if (env.hasValue())
- for (std::string &arg : splitArgList(*env))
- ret.push_back(ctx.allocate(arg).data());
-
- // Add the rest of arguments passed via the command line.
- for (int i = 1; i < argc; ++i)
- ret.push_back(argv[i]);
- ret.push_back(nullptr);
- return ret;
-}
-
-// Process "LIB" environment variable. The variable contains a list of search
-// paths separated by semicolons.
-static void processLibEnv(PECOFFLinkingContext &ctx) {
- llvm::Optional<std::string> env = llvm::sys::Process::GetEnv("LIB");
- if (env.hasValue())
- for (StringRef path : splitPathList(*env))
- ctx.appendInputSearchPath(ctx.allocate(path));
-}
-
-namespace {
-class DriverStringSaver : public llvm::cl::StringSaver {
-public:
- DriverStringSaver(PECOFFLinkingContext &ctx) : _ctx(ctx) {}
-
- const char *SaveString(const char *s) override {
- return _ctx.allocate(StringRef(s)).data();
- }
-
-private:
- PECOFFLinkingContext &_ctx;
-};
-}
-
-// Tokenize command line options in a given file and add them to result.
-static bool readResponseFile(StringRef path, PECOFFLinkingContext &ctx,
- std::vector<const char *> &result) {
- ArrayRef<uint8_t> contents;
- if (!readFile(ctx, path, contents))
- return false;
- StringRef contentsStr(reinterpret_cast<const char *>(contents.data()),
- contents.size());
- DriverStringSaver saver(ctx);
- SmallVector<const char *, 0> args;
- llvm::cl::TokenizeWindowsCommandLine(contentsStr, saver, args);
- for (const char *s : args)
- result.push_back(s);
- return true;
-}
-
-// Expand arguments starting with "@". It's an error if a specified file does
-// not exist. Returns true on success.
-static bool expandResponseFiles(int &argc, const char **&argv,
- PECOFFLinkingContext &ctx, raw_ostream &diag,
- bool &expanded) {
- std::vector<const char *> newArgv;
- for (int i = 0; i < argc; ++i) {
- if (argv[i][0] != '@') {
- newArgv.push_back(argv[i]);
- continue;
- }
- StringRef filename = StringRef(argv[i] + 1);
- if (!readResponseFile(filename, ctx, newArgv)) {
- diag << "error: cannot read response file: " << filename << "\n";
- return false;
- }
- expanded = true;
- }
- if (!expanded)
- return true;
- argc = newArgv.size();
- newArgv.push_back(nullptr);
- argv = &ctx.allocateCopy(newArgv)[0];
- return true;
-}
-
-// Parses the given command line options and returns the result. Returns NULL if
-// there's an error in the options.
-static std::unique_ptr<llvm::opt::InputArgList>
-parseArgs(int argc, const char **argv, PECOFFLinkingContext &ctx,
- raw_ostream &diag, bool isReadingDirectiveSection) {
- // Expand arguments starting with "@".
- bool expanded = false;
- if (!expandResponseFiles(argc, argv, ctx, diag, expanded))
- return nullptr;
-
- // Parse command line options using WinLinkOptions.td
- std::unique_ptr<llvm::opt::InputArgList> parsedArgs;
- WinLinkOptTable table;
- unsigned missingIndex;
- unsigned missingCount;
- parsedArgs.reset(table.ParseArgs(&argv[1], &argv[argc],
- missingIndex, missingCount));
- if (missingCount) {
- diag << "error: missing arg value for '"
- << parsedArgs->getArgString(missingIndex) << "' expected "
- << missingCount << " argument(s).\n";
- return nullptr;
- }
-
- // Show warning for unknown arguments. In .drectve section, unknown options
- // starting with "-?" are silently ignored. This is a COFF's feature to embed a
- // new linker option to an object file while keeping backward compatibility.
- for (auto unknownArg : parsedArgs->filtered(OPT_UNKNOWN)) {
- StringRef arg = unknownArg->getSpelling();
- if (isReadingDirectiveSection && arg.startswith("-?"))
- continue;
- diag << "warning: ignoring unknown argument: " << arg << "\n";
- }
-
- // Copy mllvm
- for (auto arg : parsedArgs->filtered(OPT_mllvm))
- ctx.appendLLVMOption(arg->getValue());
-
- // If we have expaneded response files and /verbose is given, print out the
- // final command line.
- if (!isReadingDirectiveSection && expanded &&
- parsedArgs->getLastArg(OPT_verbose)) {
- diag << "Command line:";
- for (int i = 0; i < argc; ++i)
- diag << " " << argv[i];
- diag << "\n\n";
- }
-
- return parsedArgs;
-}
-
-// Returns true if the given file node has already been added to the input
-// graph.
-static bool hasLibrary(PECOFFLinkingContext &ctx, File *file) {
- StringRef path = file->path();
- for (std::unique_ptr<Node> &p : ctx.getNodes())
- if (auto *f = dyn_cast<FileNode>(p.get()))
- if (f->getFile()->path() == path)
- return true;
- return false;
-}
-
-// If the first command line argument is "/lib", link.exe acts as if it's
-// "lib.exe" command. This is for backward compatibility.
-// http://msdn.microsoft.com/en-us/library/h34w59b3.aspx
-static bool maybeRunLibCommand(int argc, const char **argv, raw_ostream &diag) {
- if (argc <= 1)
- return false;
- if (!StringRef(argv[1]).equals_lower("/lib"))
- return false;
- ErrorOr<std::string> pathOrErr = llvm::sys::findProgramByName("lib.exe");
- if (!pathOrErr) {
- diag << "Unable to find lib.exe in PATH\n";
- return true;
- }
- const std::string &path = *pathOrErr;
-
- // Run lib.exe
- std::vector<const char *> vec;
- vec.push_back(path.c_str());
- for (int i = 2; i < argc; ++i)
- vec.push_back(argv[i]);
- vec.push_back(nullptr);
-
- if (llvm::sys::ExecuteAndWait(path.c_str(), &vec[0]) != 0)
- diag << "lib.exe failed\n";
- return true;
-}
-
-/// \brief Parse the input file to lld::File.
-void addFiles(PECOFFLinkingContext &ctx, StringRef path, raw_ostream &diag,
- std::vector<std::unique_ptr<File>> &files) {
- for (std::unique_ptr<File> &file : loadFile(ctx, path, false)) {
- if (ctx.logInputFiles())
- diag << file->path() << "\n";
- files.push_back(std::move(file));
- }
-}
-
-//
-// Main driver
-//
-
-bool WinLinkDriver::linkPECOFF(int argc, const char **argv, raw_ostream &diag) {
- if (maybeRunLibCommand(argc, argv, diag))
- return true;
-
- PECOFFLinkingContext ctx;
- ctx.setParseDirectives(parseDirectives);
- ctx.registry().addSupportCOFFObjects(ctx);
- ctx.registry().addSupportCOFFImportLibraries(ctx);
- ctx.registry().addSupportArchives(ctx.logInputFiles());
- ctx.registry().addSupportNativeObjects();
- ctx.registry().addSupportYamlFiles();
-
- std::vector<const char *> newargv = processLinkEnv(ctx, argc, argv);
- processLibEnv(ctx);
- if (!parse(newargv.size() - 1, &newargv[0], ctx, diag))
- return false;
-
- // Create the file if needed.
- if (ctx.getCreateManifest() && !ctx.getEmbedManifest())
- if (!createSideBySideManifestFile(ctx, diag))
- return false;
-
- return link(ctx, diag);
-}
-
-bool WinLinkDriver::parse(int argc, const char *argv[],
- PECOFFLinkingContext &ctx, raw_ostream &diag,
- bool isReadingDirectiveSection) {
- // Parse may be called from multiple threads simultaneously to parse .drectve
- // sections. This function is not thread-safe because it mutates the context
- // object. So acquire the lock.
- std::lock_guard<std::recursive_mutex> lock(ctx.getMutex());
-
- std::map<StringRef, StringRef> failIfMismatchMap;
- // Parse the options.
- std::unique_ptr<llvm::opt::InputArgList> parsedArgs =
- parseArgs(argc, argv, ctx, diag, isReadingDirectiveSection);
- if (!parsedArgs)
- return false;
-
- // The list of input files.
- std::vector<std::unique_ptr<File>> files;
- std::vector<std::unique_ptr<File>> libraries;
-
- // Handle /help
- if (parsedArgs->hasArg(OPT_help)) {
- WinLinkOptTable table;
- table.PrintHelp(llvm::outs(), argv[0], "LLVM Linker", false);
- return false;
- }
-
- // Handle /machine before parsing all the other options, as the target machine
- // type affects how to handle other options. For example, x86 needs the
- // leading underscore to mangle symbols, while x64 doesn't need it.
- if (llvm::opt::Arg *inputArg = parsedArgs->getLastArg(OPT_machine)) {
- StringRef arg = inputArg->getValue();
- llvm::COFF::MachineTypes type = stringToMachineType(arg);
- if (type == llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN) {
- diag << "error: unknown machine type: " << arg << "\n";
- return false;
- }
- ctx.setMachineType(type);
- } else {
- // If /machine option is missing, we need to take a look at
- // the magic byte of the first object file to infer machine type.
- std::vector<StringRef> filePaths;
- for (auto arg : *parsedArgs)
- if (arg->getOption().getID() == OPT_INPUT)
- filePaths.push_back(arg->getValue());
- if (llvm::opt::Arg *arg = parsedArgs->getLastArg(OPT_DASH_DASH))
- filePaths.insert(filePaths.end(), arg->getValues().begin(),
- arg->getValues().end());
- for (StringRef path : filePaths) {
- llvm::COFF::MachineTypes type;
- if (!getMachineType(path, type))
- continue;
- if (type == llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN)
- continue;
- ctx.setMachineType(type);
- break;
- }
- }
-
- // Handle /nodefaultlib:<lib>. The same option without argument is handled in
- // the following for loop.
- for (auto *arg : parsedArgs->filtered(OPT_nodefaultlib))
- ctx.addNoDefaultLib(arg->getValue());
-
- // Handle /defaultlib. Argument of the option is added to the input file list
- // unless it's blacklisted by /nodefaultlib.
- std::vector<StringRef> defaultLibs;
- for (auto *arg : parsedArgs->filtered(OPT_defaultlib))
- defaultLibs.push_back(arg->getValue());
-
- // -alternatename:<alias>=<symbol>
- for (auto *arg : parsedArgs->filtered(OPT_alternatename)) {
- StringRef weak, def;
- if (!parseAlternateName(arg->getValue(), weak, def, diag))
- return false;
- ctx.addAlternateName(weak, def);
- }
-
- // Parse /base command line option. The argument for the parameter is in
- // the form of "<address>[:<size>]".
- if (auto *arg = parsedArgs->getLastArg(OPT_base)) {
- uint64_t addr, size;
- // Size should be set to SizeOfImage field in the COFF header, and if
- // it's smaller than the actual size, the linker should warn about that.
- // Currently we just ignore the value of size parameter.
- if (!parseMemoryOption(arg->getValue(), addr, size))
- return false;
- ctx.setBaseAddress(addr);
- }
-
- // Parse /dll command line option
- if (parsedArgs->hasArg(OPT_dll)) {
- ctx.setIsDll(true);
- // Default base address of a DLL is 0x10000000.
- if (!parsedArgs->hasArg(OPT_base))
- ctx.setBaseAddress(0x10000000);
- }
-
- // Parse /stack command line option
- if (auto *arg = parsedArgs->getLastArg(OPT_stack)) {
- uint64_t reserve;
- uint64_t commit = ctx.getStackCommit();
- if (!parseMemoryOption(arg->getValue(), reserve, commit))
- return false;
- ctx.setStackReserve(reserve);
- ctx.setStackCommit(commit);
- }
-
- // Parse /heap command line option
- if (auto *arg = parsedArgs->getLastArg(OPT_heap)) {
- uint64_t reserve;
- uint64_t commit = ctx.getHeapCommit();
- if (!parseMemoryOption(arg->getValue(), reserve, commit))
- return false;
- ctx.setHeapReserve(reserve);
- ctx.setHeapCommit(commit);
- }
-
- if (auto *arg = parsedArgs->getLastArg(OPT_align)) {
- uint32_t align;
- StringRef val = arg->getValue();
- if (val.getAsInteger(10, align)) {
- diag << "error: invalid value for /align: " << val << "\n";
- return false;
- }
- ctx.setSectionDefaultAlignment(align);
- }
-
- if (auto *arg = parsedArgs->getLastArg(OPT_version)) {
- uint32_t major, minor;
- if (!parseVersion(arg->getValue(), major, minor))
- return false;
- ctx.setImageVersion(PECOFFLinkingContext::Version(major, minor));
- }
-
- // Parse /merge:<from>=<to>.
- for (auto *arg : parsedArgs->filtered(OPT_merge)) {
- StringRef from, to;
- std::tie(from, to) = StringRef(arg->getValue()).split('=');
- if (from.empty() || to.empty()) {
- diag << "error: malformed /merge option: " << arg->getValue() << "\n";
- return false;
- }
- if (!ctx.addSectionRenaming(diag, from, to))
- return false;
- }
-
- // Parse /subsystem:<subsystem>[,<majorOSVersion>[.<minorOSVersion>]].
- if (auto *arg = parsedArgs->getLastArg(OPT_subsystem)) {
- llvm::COFF::WindowsSubsystem subsystem;
- llvm::Optional<uint32_t> major, minor;
- if (!parseSubsystem(arg->getValue(), subsystem, major, minor, diag))
- return false;
- ctx.setSubsystem(subsystem);
- if (major.hasValue())
- ctx.setMinOSVersion(PECOFFLinkingContext::Version(*major, *minor));
- }
-
- // Parse /section:name,[[!]{DEKPRSW}]
- for (auto *arg : parsedArgs->filtered(OPT_section)) {
- std::string section;
- llvm::Optional<uint32_t> flags, mask;
- if (!parseSection(arg->getValue(), section, flags, mask)) {
- diag << "Unknown argument for /section: " << arg->getValue() << "\n";
- return false;
- }
- if (flags.hasValue())
- ctx.setSectionSetMask(section, *flags);
- if (mask.hasValue())
- ctx.setSectionClearMask(section, *mask);
- }
-
- // Parse /manifest:EMBED[,ID=#]|NO.
- if (auto *arg = parsedArgs->getLastArg(OPT_manifest_colon)) {
- bool enable = true;
- bool embed = false;
- int id = 1;
- if (!parseManifest(arg->getValue(), enable, embed, id)) {
- diag << "Unknown argument for /manifest: " << arg->getValue() << "\n";
- return false;
- }
- ctx.setCreateManifest(enable);
- ctx.setEmbedManifest(embed);
- ctx.setManifestId(id);
- }
-
- // Parse /manifestuac.
- if (auto *arg = parsedArgs->getLastArg(OPT_manifestuac)) {
- if (StringRef(arg->getValue()).equals_lower("no")) {
- ctx.setManifestUAC(false);
- } else {
- llvm::Optional<std::string> privilegeLevel;
- llvm::Optional<std::string> uiAccess;
- if (!parseManifestUAC(arg->getValue(), privilegeLevel, uiAccess)) {
- diag << "Unknown argument for /manifestuac: " << arg->getValue()
- << "\n";
- return false;
- }
- if (privilegeLevel.hasValue())
- ctx.setManifestLevel(privilegeLevel.getValue());
- if (uiAccess.hasValue())
- ctx.setManifestUiAccess(uiAccess.getValue());
- }
- }
-
- if (auto *arg = parsedArgs->getLastArg(OPT_manifestfile))
- ctx.setManifestOutputPath(ctx.allocate(arg->getValue()));
-
- // /manifestdependency:<string> option. Note that the argument will be
- // embedded to the manifest XML file with no error check, for link.exe
- // compatibility. We do not gurantete that the resulting XML file is
- // valid.
- if (auto *arg = parsedArgs->getLastArg(OPT_manifestdependency))
- ctx.setManifestDependency(ctx.allocate(arg->getValue()));
-
- for (auto *arg : parsedArgs->filtered(OPT_failifmismatch))
- if (handleFailIfMismatchOption(arg->getValue(), failIfMismatchMap, diag))
- return false;
-
- if (auto *arg = parsedArgs->getLastArg(OPT_entry))
- ctx.setEntrySymbolName(ctx.allocate(arg->getValue()));
-
- for (auto *arg : parsedArgs->filtered(OPT_export)) {
- PECOFFLinkingContext::ExportDesc desc;
- if (!parseExport(arg->getValue(), desc)) {
- diag << "Error: malformed /export option: " << arg->getValue() << "\n";
- return false;
- }
-
- // Mangle the symbol name only if it is reading user-supplied command line
- // arguments. Because the symbol name in the .drectve section is already
- // mangled by the compiler, we shouldn't add a leading underscore in that
- // case. It's odd that the command line option has different semantics in
- // the .drectve section, but this behavior is needed for compatibility
- // with MSVC's link.exe.
- if (!isReadingDirectiveSection)
- desc.name = ctx.decorateSymbol(desc.name);
- ctx.addDllExport(desc);
- }
-
- for (auto *arg : parsedArgs->filtered(OPT_deffile)) {
- llvm::BumpPtrAllocator alloc;
- std::vector<moduledef::Directive *> dirs;
- if (!parseDef(arg->getValue(), alloc, dirs)) {
- diag << "Error: invalid module-definition file\n";
- return false;
- }
- for (moduledef::Directive *dir : dirs) {
- if (auto *exp = dyn_cast<moduledef::Exports>(dir)) {
- for (PECOFFLinkingContext::ExportDesc desc : exp->getExports()) {
- desc.name = ctx.decorateSymbol(desc.name);
- ctx.addDllExport(desc);
- }
- } else if (auto *hs = dyn_cast<moduledef::Heapsize>(dir)) {
- ctx.setHeapReserve(hs->getReserve());
- ctx.setHeapCommit(hs->getCommit());
- } else if (auto *lib = dyn_cast<moduledef::Library>(dir)) {
- ctx.setIsDll(true);
- ctx.setOutputPath(ctx.allocate(lib->getName()));
- if (lib->getBaseAddress() && !ctx.getBaseAddress())
- ctx.setBaseAddress(lib->getBaseAddress());
- } else if (auto *name = dyn_cast<moduledef::Name>(dir)) {
- if (!name->getOutputPath().empty() && ctx.outputPath().empty())
- ctx.setOutputPath(ctx.allocate(name->getOutputPath()));
- if (name->getBaseAddress() && ctx.getBaseAddress())
- ctx.setBaseAddress(name->getBaseAddress());
- } else if (auto *ver = dyn_cast<moduledef::Version>(dir)) {
- ctx.setImageVersion(PECOFFLinkingContext::Version(
- ver->getMajorVersion(), ver->getMinorVersion()));
- } else {
- llvm::dbgs() << static_cast<int>(dir->getKind()) << "\n";
- llvm_unreachable("Unknown module-definition directive.\n");
- }
- }
- }
-
- for (auto *arg : parsedArgs->filtered(OPT_libpath))
- ctx.appendInputSearchPath(ctx.allocate(arg->getValue()));
-
- for (auto *arg : parsedArgs->filtered(OPT_opt)) {
- std::string val = StringRef(arg->getValue()).lower();
- if (val == "noref") {
- ctx.setDeadStripping(false);
- } else if (val != "ref" && val != "icf" && val != "noicf" &&
- val != "lbr" && val != "nolbr" &&
- !StringRef(val).startswith("icf=")) {
- diag << "unknown option for /opt: " << val << "\n";
- return false;
- }
- }
-
- // LLD is not yet capable of creating a PDB file, so /debug does not have
- // any effect.
- // TODO: This should disable dead stripping. Currently we can't do that
- // because removal of associative sections depends on dead stripping.
- if (parsedArgs->hasArg(OPT_debug))
- ctx.setDebug(true);
-
- if (parsedArgs->hasArg(OPT_verbose))
- ctx.setLogInputFiles(true);
-
- // /force and /force:unresolved mean the same thing. We do not currently
- // support /force:multiple.
- if (parsedArgs->hasArg(OPT_force) ||
- parsedArgs->hasArg(OPT_force_unresolved)) {
- ctx.setAllowRemainingUndefines(true);
- }
-
- if (parsedArgs->hasArg(OPT_fixed)) {
- // /fixed is not compatible with /dynamicbase. Check for it.
- if (parsedArgs->hasArg(OPT_dynamicbase)) {
- diag << "/dynamicbase must not be specified with /fixed\n";
- return false;
- }
- ctx.setBaseRelocationEnabled(false);
- ctx.setDynamicBaseEnabled(false);
- }
-
- // /swaprun:{cd,net} options set IMAGE_FILE_{REMOVABLE,NET}_RUN_FROM_SWAP
- // bits in the COFF header, respectively. If one of the bits is on, the
- // Windows loader will copy the entire file to swap area then execute it,
- // so that the user can eject a CD or disconnect from the network.
- if (parsedArgs->hasArg(OPT_swaprun_cd))
- ctx.setSwapRunFromCD(true);
-
- if (parsedArgs->hasArg(OPT_swaprun_net))
- ctx.setSwapRunFromNet(true);
-
- if (parsedArgs->hasArg(OPT_profile)) {
- // /profile implies /opt:ref, /opt:noicf, /incremental:no and /fixed:no.
- ctx.setDeadStripping(true);
- ctx.setBaseRelocationEnabled(true);
- ctx.setDynamicBaseEnabled(true);
- }
-
- for (auto *arg : parsedArgs->filtered(OPT_implib))
- ctx.setOutputImportLibraryPath(arg->getValue());
-
- for (auto *arg : parsedArgs->filtered(OPT_delayload)) {
- ctx.addInitialUndefinedSymbol(ctx.getDelayLoadHelperName());
- ctx.addDelayLoadDLL(arg->getValue());
- }
-
- if (auto *arg = parsedArgs->getLastArg(OPT_stub)) {
- ArrayRef<uint8_t> contents;
- if (!readFile(ctx, arg->getValue(), contents)) {
- diag << "Failed to read DOS stub file " << arg->getValue() << "\n";
- return false;
- }
- ctx.setDosStub(contents);
- }
-
- for (auto *arg : parsedArgs->filtered(OPT_incl))
- ctx.addInitialUndefinedSymbol(ctx.allocate(arg->getValue()));
-
- if (parsedArgs->hasArg(OPT_noentry))
- ctx.setHasEntry(false);
-
- if (parsedArgs->hasArg(OPT_nodefaultlib_all))
- ctx.setNoDefaultLibAll(true);
-
- if (auto *arg = parsedArgs->getLastArg(OPT_out))
- ctx.setOutputPath(ctx.allocate(arg->getValue()));
-
- if (auto *arg = parsedArgs->getLastArg(OPT_pdb))
- ctx.setPDBFilePath(arg->getValue());
-
- if (auto *arg = parsedArgs->getLastArg(OPT_lldmoduledeffile))
- ctx.setModuleDefinitionFile(arg->getValue());
-
- std::vector<StringRef> inputFiles;
- for (auto *arg : parsedArgs->filtered(OPT_INPUT))
- inputFiles.push_back(ctx.allocate(arg->getValue()));
-
-#define BOOLEAN_FLAG(name, setter) \
- if (auto *arg = parsedArgs->getLastArg(OPT_##name, OPT_##name##_no)) \
- ctx.setter(arg->getOption().matches(OPT_##name));
-
- BOOLEAN_FLAG(nxcompat, setNxCompat);
- BOOLEAN_FLAG(largeaddressaware, setLargeAddressAware);
- BOOLEAN_FLAG(allowbind, setAllowBind);
- BOOLEAN_FLAG(allowisolation, setAllowIsolation);
- BOOLEAN_FLAG(dynamicbase, setDynamicBaseEnabled);
- BOOLEAN_FLAG(tsaware, setTerminalServerAware);
- BOOLEAN_FLAG(highentropyva, setHighEntropyVA);
- BOOLEAN_FLAG(safeseh, setSafeSEH);
-#undef BOOLEAN_FLAG
-
- // Arguments after "--" are interpreted as filenames even if they
- // start with a hypen or a slash. This is not compatible with link.exe
- // but useful for us to test lld on Unix.
- if (llvm::opt::Arg *dashdash = parsedArgs->getLastArg(OPT_DASH_DASH))
- for (const StringRef value : dashdash->getValues())
- inputFiles.push_back(value);
-
- // Compile Windows resource files to compiled resource file.
- if (ctx.getCreateManifest() && ctx.getEmbedManifest() &&
- !isReadingDirectiveSection) {
- std::string resFile;
- if (!createManifestResourceFile(ctx, diag, resFile))
- return false;
- inputFiles.push_back(ctx.allocate(resFile));
- }
-
- // A Windows Resource file is not an object file. It contains data,
- // such as an icon image, and is not in COFF file format. If resource
- // files are given, the linker merge them into one COFF file using
- // CVTRES.EXE and then link the resulting file.
- {
- auto it = std::partition(inputFiles.begin(), inputFiles.end(),
- isResoruceFile);
- if (it != inputFiles.begin()) {
- std::vector<std::string> resFiles(inputFiles.begin(), it);
- std::string resObj;
- if (!convertResourceFiles(ctx, resFiles, resObj)) {
- diag << "Failed to convert resource files\n";
- return false;
- }
- inputFiles = std::vector<StringRef>(it, inputFiles.end());
- inputFiles.push_back(ctx.allocate(resObj));
- ctx.registerTemporaryFile(resObj);
- }
- }
-
- // Prepare objects to add them to the list of input files.
- for (StringRef path : inputFiles) {
- path = ctx.allocate(path);
- if (isLibraryFile(path)) {
- addFiles(ctx, getLibraryPath(ctx, path), diag, libraries);
- } else {
- addFiles(ctx, getObjectPath(ctx, path), diag, files);
- }
- }
-
- // If dead-stripping is enabled, we need to add the entry symbol and
- // symbols given by /include to the dead strip root set, so that it
- // won't be removed from the output.
- if (ctx.deadStrip())
- for (const StringRef symbolName : ctx.initialUndefinedSymbols())
- ctx.addDeadStripRoot(symbolName);
-
- // Add the libraries specified by /defaultlib unless they are already added
- // nor blacklisted by /nodefaultlib.
- if (!ctx.getNoDefaultLibAll())
- for (const StringRef path : defaultLibs)
- if (!ctx.hasNoDefaultLib(path))
- addFiles(ctx, getLibraryPath(ctx, path.lower()), diag, libraries);
-
- if (files.empty() && !isReadingDirectiveSection) {
- diag << "No input files\n";
- return false;
- }
-
- // If /out option was not specified, the default output file name is
- // constructed by replacing an extension of the first input file
- // with ".exe".
- if (ctx.outputPath().empty()) {
- StringRef path = files[0]->path();
- ctx.setOutputPath(replaceExtension(ctx, path, ".exe"));
- }
-
- // Add the input files to the linking context.
- for (std::unique_ptr<File> &file : files) {
- if (isReadingDirectiveSection) {
- File *f = file.get();
- ctx.getTaskGroup().spawn([f] { f->parse(); });
- }
- ctx.getNodes().push_back(llvm::make_unique<FileNode>(std::move(file)));
- }
-
- // Add the library group to the linking context.
- if (!isReadingDirectiveSection) {
- // Add a group-end marker.
- ctx.getNodes().push_back(llvm::make_unique<GroupEnd>(0));
- }
-
- // Add the library files to the library group.
- for (std::unique_ptr<File> &file : libraries) {
- if (!hasLibrary(ctx, file.get())) {
- if (isReadingDirectiveSection) {
- File *f = file.get();
- ctx.getTaskGroup().spawn([f] { f->parse(); });
- }
- ctx.addLibraryFile(llvm::make_unique<FileNode>(std::move(file)));
- }
- }
-
- // Validate the combination of options used.
- return ctx.validate(diag);
-}
-
-} // namespace lld
diff --git a/lib/Driver/WinLinkModuleDef.cpp b/lib/Driver/WinLinkModuleDef.cpp
deleted file mode 100644
index e55a0bc5fe64..000000000000
--- a/lib/Driver/WinLinkModuleDef.cpp
+++ /dev/null
@@ -1,295 +0,0 @@
-//===- lib/Driver/WinLinkModuleDef.cpp ------------------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// \brief Windows module definition file parser.
-///
-//===----------------------------------------------------------------------===//
-
-#include "lld/Driver/WinLinkModuleDef.h"
-#include "llvm/ADT/StringSwitch.h"
-
-namespace lld {
-namespace moduledef {
-
-Token Lexer::lex() {
- for (;;) {
- _buffer = _buffer.trim();
- if (_buffer.empty() || _buffer[0] == '\0')
- return Token(Kind::eof, _buffer);
-
- switch (_buffer[0]) {
- case ';': {
- size_t end = _buffer.find('\n');
- _buffer = (end == _buffer.npos) ? "" : _buffer.drop_front(end);
- continue;
- }
- case '=':
- _buffer = _buffer.drop_front();
- return Token(Kind::equal, "=");
- case ',':
- _buffer = _buffer.drop_front();
- return Token(Kind::comma, ",");
- case '"': {
- size_t end = _buffer.find('"', 1);
- Token ret;
- if (end == _buffer.npos) {
- ret = Token(Kind::identifier, _buffer.substr(1, end));
- _buffer = "";
- } else {
- ret = Token(Kind::identifier, _buffer.substr(1, end - 1));
- _buffer = _buffer.drop_front(end + 1);
- }
- return ret;
- }
- default: {
- size_t end = _buffer.find_first_not_of(
- "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "0123456789_.*~+!@#$%^&*()/");
- StringRef word = _buffer.substr(0, end);
- Kind kind = llvm::StringSwitch<Kind>(word)
- .Case("BASE", Kind::kw_base)
- .Case("DATA", Kind::kw_data)
- .Case("EXPORTS", Kind::kw_exports)
- .Case("HEAPSIZE", Kind::kw_heapsize)
- .Case("LIBRARY", Kind::kw_library)
- .Case("NAME", Kind::kw_name)
- .Case("NONAME", Kind::kw_noname)
- .Case("PRIVATE", Kind::kw_private)
- .Case("STACKSIZE", Kind::kw_stacksize)
- .Case("VERSION", Kind::kw_version)
- .Default(Kind::identifier);
- _buffer = (end == _buffer.npos) ? "" : _buffer.drop_front(end);
- return Token(kind, word);
- }
- }
- }
-}
-
-void Parser::consumeToken() {
- if (_tokBuf.empty()) {
- _tok = _lex.lex();
- return;
- }
- _tok = _tokBuf.back();
- _tokBuf.pop_back();
-}
-
-bool Parser::consumeTokenAsInt(uint64_t &result) {
- consumeToken();
- if (_tok._kind != Kind::identifier) {
- ungetToken();
- error(_tok, "Integer expected");
- return false;
- }
- if (_tok._range.getAsInteger(10, result)) {
- error(_tok, "Integer expected");
- return false;
- }
- return true;
-}
-
-bool Parser::expectAndConsume(Kind kind, Twine msg) {
- consumeToken();
- if (_tok._kind != kind) {
- error(_tok, msg);
- return false;
- }
- return true;
-}
-
-void Parser::ungetToken() { _tokBuf.push_back(_tok); }
-
-void Parser::error(const Token &tok, Twine msg) {
- _lex.getSourceMgr().PrintMessage(
- llvm::SMLoc::getFromPointer(tok._range.data()), llvm::SourceMgr::DK_Error,
- msg);
-}
-
-bool Parser::parse(std::vector<Directive *> &ret) {
- for (;;) {
- Directive *dir = nullptr;
- if (!parseOne(dir))
- return false;
- if (!dir)
- return true;
- ret.push_back(dir);
- }
-}
-
-bool Parser::parseOne(Directive *&ret) {
- consumeToken();
- switch (_tok._kind) {
- case Kind::eof:
- return true;
- case Kind::kw_exports: {
- // EXPORTS
- std::vector<PECOFFLinkingContext::ExportDesc> exports;
- for (;;) {
- PECOFFLinkingContext::ExportDesc desc;
- if (!parseExport(desc))
- break;
- exports.push_back(desc);
- }
- ret = new (_alloc) Exports(exports);
- return true;
- }
- case Kind::kw_heapsize: {
- // HEAPSIZE
- uint64_t reserve, commit;
- if (!parseMemorySize(reserve, commit))
- return false;
- ret = new (_alloc) Heapsize(reserve, commit);
- return true;
- }
- case Kind::kw_library: {
- // LIBRARY
- std::string name;
- uint64_t baseaddr;
- if (!parseName(name, baseaddr))
- return false;
- if (!StringRef(name).endswith_lower(".dll"))
- name.append(".dll");
- ret = new (_alloc) Library(name, baseaddr);
- return true;
- }
- case Kind::kw_stacksize: {
- // STACKSIZE
- uint64_t reserve, commit;
- if (!parseMemorySize(reserve, commit))
- return false;
- ret = new (_alloc) Stacksize(reserve, commit);
- return true;
- }
- case Kind::kw_name: {
- // NAME
- std::string outputPath;
- uint64_t baseaddr;
- if (!parseName(outputPath, baseaddr))
- return false;
- ret = new (_alloc) Name(outputPath, baseaddr);
- return true;
- }
- case Kind::kw_version: {
- // VERSION
- int major, minor;
- if (!parseVersion(major, minor))
- return false;
- ret = new (_alloc) Version(major, minor);
- return true;
- }
- default:
- error(_tok, Twine("Unknown directive: ") + _tok._range);
- return false;
- }
-}
-
-bool Parser::parseExport(PECOFFLinkingContext::ExportDesc &result) {
- consumeToken();
- if (_tok._kind != Kind::identifier) {
- ungetToken();
- return false;
- }
- result.name = _tok._range;
-
- consumeToken();
- if (_tok._kind == Kind::equal) {
- consumeToken();
- if (_tok._kind != Kind::identifier)
- return false;
- result.externalName = result.name;
- result.name = _tok._range;
- } else {
- ungetToken();
- }
-
- for (;;) {
- consumeToken();
- if (_tok._kind == Kind::identifier && _tok._range[0] == '@') {
- _tok._range.drop_front().getAsInteger(10, result.ordinal);
- consumeToken();
- if (_tok._kind == Kind::kw_noname) {
- result.noname = true;
- } else {
- ungetToken();
- }
- continue;
- }
- if (_tok._kind == Kind::kw_data) {
- result.isData = true;
- continue;
- }
- if (_tok._kind == Kind::kw_private) {
- result.isPrivate = true;
- continue;
- }
- ungetToken();
- return true;
- }
-}
-
-// HEAPSIZE/STACKSIZE reserve[,commit]
-bool Parser::parseMemorySize(uint64_t &reserve, uint64_t &commit) {
- if (!consumeTokenAsInt(reserve))
- return false;
-
- consumeToken();
- if (_tok._kind != Kind::comma) {
- ungetToken();
- commit = 0;
- return true;
- }
-
- if (!consumeTokenAsInt(commit))
- return false;
- return true;
-}
-
-// NAME [outputPath] [BASE=address]
-bool Parser::parseName(std::string &outputPath, uint64_t &baseaddr) {
- consumeToken();
- if (_tok._kind == Kind::identifier) {
- outputPath = _tok._range;
- } else {
- outputPath = "";
- ungetToken();
- return true;
- }
- consumeToken();
- if (_tok._kind == Kind::kw_base) {
- if (!expectAndConsume(Kind::equal, "'=' expected"))
- return false;
- if (!consumeTokenAsInt(baseaddr))
- return false;
- } else {
- ungetToken();
- baseaddr = 0;
- }
- return true;
-}
-
-// VERSION major[.minor]
-bool Parser::parseVersion(int &major, int &minor) {
- consumeToken();
- if (_tok._kind != Kind::identifier)
- return false;
- StringRef v1, v2;
- std::tie(v1, v2) = _tok._range.split('.');
- if (v1.getAsInteger(10, major))
- return false;
- if (v2.empty()) {
- minor = 0;
- } else if (v2.getAsInteger(10, minor)) {
- return false;
- }
- return true;
-}
-
-} // moddef
-} // namespace lld
diff --git a/lib/Driver/WinLinkOptions.td b/lib/Driver/WinLinkOptions.td
deleted file mode 100644
index a545639b5bb2..000000000000
--- a/lib/Driver/WinLinkOptions.td
+++ /dev/null
@@ -1,120 +0,0 @@
-include "llvm/Option/OptParser.td"
-
-// link.exe accepts options starting with either a dash or a slash.
-
-// Flag that takes no arguments.
-class F<string name> : Flag<["/", "-", "-?"], name>;
-
-// Flag that takes one argument after ":".
-class P<string name, string help> :
- Joined<["/", "-", "-?"], name#":">, HelpText<help>;
-
-// Boolean flag suffixed by ":no".
-multiclass B<string name, string help> {
- def "" : F<name>;
- def _no : F<name#":no">, HelpText<help>;
-}
-
-def alternatename : P<"alternatename", "Define weak alias">;
-def base : P<"base", "Base address of the program">;
-def defaultlib : P<"defaultlib", "Add the library to the list of input files">;
-def nodefaultlib : P<"nodefaultlib", "Remove a default library">;
-def disallowlib : Joined<["/", "-", "-?"], "disallowlib:">, Alias<nodefaultlib>;
-def entry : P<"entry", "Name of entry point symbol">;
-// No help text because /failifmismatch is not intended to be used by the user.
-def export : P<"export", "Export a function">;
-def failifmismatch : P<"failifmismatch", "">;
-def heap : P<"heap", "Size of the heap">;
-def align : P<"align", "Section alignment">;
-def libpath : P<"libpath", "Additional library search path">;
-def mllvm : P<"mllvm", "Options to pass to LLVM">;
-def out : P<"out", "Path to file to write output">;
-def stack : P<"stack", "Size of the stack">;
-def machine : P<"machine", "Specify target platform">;
-def version : P<"version", "Specify a version number in the PE header">;
-def merge : P<"merge", "Combine sections">;
-def section : P<"section", "Specify section attributes">;
-def subsystem : P<"subsystem", "Specify subsystem">;
-def stub : P<"stub", "Specify DOS stub file">;
-def opt : P<"opt", "Control optimizations">;
-def implib : P<"implib", "Import library name">;
-def delayload : P<"delayload", "Delay loaded DLL name">;
-def pdb : P<"pdb", "PDB file path">;
-
-def manifest : F<"manifest">;
-def manifest_colon : P<"manifest", "Create manifest file">;
-def manifestuac : P<"manifestuac", "User access control">;
-def manifestfile : P<"manifestfile", "Manifest file path">;
-def manifestdependency : P<"manifestdependency",
- "Attributes for <dependency> in manifest file">;
-
-// We cannot use multiclass P because class name "incl" is different
-// from its command line option name. We do this because "include" is
-// a reserved keyword in tablegen.
-def incl : Joined<["/", "-"], "include:">,
- HelpText<"Force symbol to be added to symbol table as undefined one">;
-
-// "def" is also a keyword.
-def deffile : Joined<["/", "-"], "def:">,
- HelpText<"Use module-definition file">;
-
-def nodefaultlib_all : F<"nodefaultlib">;
-def noentry : F<"noentry">;
-def dll : F<"dll">;
-def verbose : F<"verbose">;
-def debug : F<"debug">;
-def swaprun_cd : F<"swaprun:cd">;
-def swaprun_net : F<"swaprun:net">;
-def profile : F<"profile">;
-
-def force : F<"force">,
- HelpText<"Allow undefined symbols when creating executables">;
-def force_unresolved : F<"force:unresolved">;
-
-defm nxcompat : B<"nxcompat", "Disable data execution provention">;
-defm largeaddressaware : B<"largeaddressaware", "Disable large addresses">;
-defm allowbind: B<"allowbind", "Disable DLL binding">;
-defm fixed : B<"fixed", "Enable base relocations">;
-defm tsaware : B<"tsaware", "Create non-Terminal Server aware executable">;
-defm allowisolation : B<"allowisolation", "Set NO_ISOLATION bit">;
-defm dynamicbase : B<"dynamicbase",
- "Disable address space layout randomization">;
-defm safeseh : B<"safeseh", "Produce an image with Safe Exception Handler">;
-defm highentropyva : B<"highentropyva", "Set HIGH_ENTROPY_VA bit">;
-
-def help : F<"help">;
-def help_q : Flag<["/?", "-?"], "">, Alias<help>;
-
-def DASH_DASH : Option<["--"], "", KIND_REMAINING_ARGS>;
-
-// Flag for debug
-def lldmoduledeffile : Joined<["/", "-"], "lldmoduledeffile:">;
-
-//==============================================================================
-// The flags below do nothing. They are defined only for link.exe compatibility.
-//==============================================================================
-
-class QF<string name> : Joined<["/", "-", "-?"], name#":">;
-
-multiclass QB<string name> {
- def "" : F<name>;
- def _no : F<name#":no">;
-}
-
-def functionpadmin : F<"functionpadmin">;
-def ignoreidl : F<"ignoreidl">;
-def incremental : F<"incremental">;
-def no_incremental : F<"incremental:no">;
-def nologo : F<"nologo">;
-
-def delay : QF<"delay">;
-def errorreport : QF<"errorreport">;
-def idlout : QF<"idlout">;
-def ignore : QF<"ignore">;
-def maxilksize : QF<"maxilksize">;
-def pdbaltpath : QF<"pdbaltpath">;
-def tlbid : QF<"tlbid">;
-def tlbout : QF<"tlbout">;
-def verbose_all : QF<"verbose">;
-
-defm wx : QB<"wx">;
diff --git a/lib/Makefile b/lib/Makefile
deleted file mode 100644
index 83112eaf972a..000000000000
--- a/lib/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-##===- lib/Makefile ----------------------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-LLD_LEVEL := ..
-
-# ARCMigrate and Rewrite are always needed because of libclang.
-PARALLEL_DIRS = Config Core Driver ReaderWriter
-
-include $(LLD_LEVEL)/../../Makefile.config
-
-include $(LLD_LEVEL)/Makefile
diff --git a/lib/ReaderWriter/CMakeLists.txt b/lib/ReaderWriter/CMakeLists.txt
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->