aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm/tools/lld
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/lld')
-rw-r--r--contrib/llvm/tools/lld/.arcconfig4
-rw-r--r--contrib/llvm/tools/lld/.clang-format1
-rw-r--r--contrib/llvm/tools/lld/.gitignore24
-rw-r--r--contrib/llvm/tools/lld/CMakeLists.txt226
-rw-r--r--contrib/llvm/tools/lld/CODE_OWNERS.TXT22
-rw-r--r--contrib/llvm/tools/lld/COFF/CMakeLists.txt47
-rw-r--r--contrib/llvm/tools/lld/COFF/Chunks.cpp883
-rw-r--r--contrib/llvm/tools/lld/COFF/Chunks.h527
-rw-r--r--contrib/llvm/tools/lld/COFF/Config.h212
-rw-r--r--contrib/llvm/tools/lld/COFF/DLL.cpp645
-rw-r--r--contrib/llvm/tools/lld/COFF/DLL.h82
-rw-r--r--contrib/llvm/tools/lld/COFF/Driver.cpp1681
-rw-r--r--contrib/llvm/tools/lld/COFF/Driver.h197
-rw-r--r--contrib/llvm/tools/lld/COFF/DriverUtils.cpp872
-rw-r--r--contrib/llvm/tools/lld/COFF/ICF.cpp318
-rw-r--r--contrib/llvm/tools/lld/COFF/ICF.h26
-rw-r--r--contrib/llvm/tools/lld/COFF/InputFiles.cpp590
-rw-r--r--contrib/llvm/tools/lld/COFF/InputFiles.h280
-rw-r--r--contrib/llvm/tools/lld/COFF/LTO.cpp152
-rw-r--r--contrib/llvm/tools/lld/COFF/LTO.h57
-rw-r--r--contrib/llvm/tools/lld/COFF/MapFile.cpp125
-rw-r--r--contrib/llvm/tools/lld/COFF/MapFile.h22
-rw-r--r--contrib/llvm/tools/lld/COFF/MarkLive.cpp74
-rw-r--r--contrib/llvm/tools/lld/COFF/MarkLive.h24
-rw-r--r--contrib/llvm/tools/lld/COFF/MinGW.cpp176
-rw-r--r--contrib/llvm/tools/lld/COFF/MinGW.h44
-rw-r--r--contrib/llvm/tools/lld/COFF/Options.td194
-rw-r--r--contrib/llvm/tools/lld/COFF/PDB.cpp1771
-rw-r--r--contrib/llvm/tools/lld/COFF/PDB.h38
-rw-r--r--contrib/llvm/tools/lld/COFF/README.md1
-rw-r--r--contrib/llvm/tools/lld/COFF/SymbolTable.cpp548
-rw-r--r--contrib/llvm/tools/lld/COFF/SymbolTable.h131
-rw-r--r--contrib/llvm/tools/lld/COFF/Symbols.cpp107
-rw-r--r--contrib/llvm/tools/lld/COFF/Symbols.h436
-rw-r--r--contrib/llvm/tools/lld/COFF/Writer.cpp1745
-rw-r--r--contrib/llvm/tools/lld/COFF/Writer.h75
-rw-r--r--contrib/llvm/tools/lld/Common/Args.cpp73
-rw-r--r--contrib/llvm/tools/lld/Common/CMakeLists.txt33
-rw-r--r--contrib/llvm/tools/lld/Common/ErrorHandler.cpp144
-rw-r--r--contrib/llvm/tools/lld/Common/Memory.cpp23
-rw-r--r--contrib/llvm/tools/lld/Common/Reproduce.cpp66
-rw-r--r--contrib/llvm/tools/lld/Common/Strings.cpp104
-rw-r--r--contrib/llvm/tools/lld/Common/TargetOptionsCommandFlags.cpp35
-rw-r--r--contrib/llvm/tools/lld/Common/Threads.cpp12
-rw-r--r--contrib/llvm/tools/lld/Common/Timer.cpp80
-rw-r--r--contrib/llvm/tools/lld/Common/Version.cpp43
-rw-r--r--contrib/llvm/tools/lld/ELF/AArch64ErrataFix.cpp652
-rw-r--r--contrib/llvm/tools/lld/ELF/AArch64ErrataFix.h51
-rw-r--r--contrib/llvm/tools/lld/ELF/Arch/AArch64.cpp440
-rw-r--r--contrib/llvm/tools/lld/ELF/Arch/AMDGPU.cpp105
-rw-r--r--contrib/llvm/tools/lld/ELF/Arch/ARM.cpp612
-rw-r--r--contrib/llvm/tools/lld/ELF/Arch/AVR.cpp77
-rw-r--r--contrib/llvm/tools/lld/ELF/Arch/Hexagon.cpp292
-rw-r--r--contrib/llvm/tools/lld/ELF/Arch/MSP430.cpp94
-rw-r--r--contrib/llvm/tools/lld/ELF/Arch/Mips.cpp676
-rw-r--r--contrib/llvm/tools/lld/ELF/Arch/MipsArchTree.cpp390
-rw-r--r--contrib/llvm/tools/lld/ELF/Arch/PPC.cpp81
-rw-r--r--contrib/llvm/tools/lld/ELF/Arch/PPC64.cpp931
-rw-r--r--contrib/llvm/tools/lld/ELF/Arch/RISCV.cpp279
-rw-r--r--contrib/llvm/tools/lld/ELF/Arch/SPARCV9.cpp149
-rw-r--r--contrib/llvm/tools/lld/ELF/Arch/X86.cpp554
-rw-r--r--contrib/llvm/tools/lld/ELF/Arch/X86_64.cpp677
-rw-r--r--contrib/llvm/tools/lld/ELF/Bits.h35
-rw-r--r--contrib/llvm/tools/lld/ELF/CMakeLists.txt68
-rw-r--r--contrib/llvm/tools/lld/ELF/CallGraphSort.cpp240
-rw-r--r--contrib/llvm/tools/lld/ELF/CallGraphSort.h23
-rw-r--r--contrib/llvm/tools/lld/ELF/Config.h295
-rw-r--r--contrib/llvm/tools/lld/ELF/DWARF.cpp109
-rw-r--r--contrib/llvm/tools/lld/ELF/DWARF.h93
-rw-r--r--contrib/llvm/tools/lld/ELF/Driver.cpp1651
-rw-r--r--contrib/llvm/tools/lld/ELF/Driver.h73
-rw-r--r--contrib/llvm/tools/lld/ELF/DriverUtils.cpp238
-rw-r--r--contrib/llvm/tools/lld/ELF/EhFrame.cpp198
-rw-r--r--contrib/llvm/tools/lld/ELF/EhFrame.h25
-rw-r--r--contrib/llvm/tools/lld/ELF/Filesystem.cpp86
-rw-r--r--contrib/llvm/tools/lld/ELF/Filesystem.h23
-rw-r--r--contrib/llvm/tools/lld/ELF/ICF.cpp512
-rw-r--r--contrib/llvm/tools/lld/ELF/ICF.h21
-rw-r--r--contrib/llvm/tools/lld/ELF/InputFiles.cpp1345
-rw-r--r--contrib/llvm/tools/lld/ELF/InputFiles.h382
-rw-r--r--contrib/llvm/tools/lld/ELF/InputSection.cpp1283
-rw-r--r--contrib/llvm/tools/lld/ELF/InputSection.h369
-rw-r--r--contrib/llvm/tools/lld/ELF/LTO.cpp296
-rw-r--r--contrib/llvm/tools/lld/ELF/LTO.h63
-rw-r--r--contrib/llvm/tools/lld/ELF/LinkerScript.cpp1144
-rw-r--r--contrib/llvm/tools/lld/ELF/LinkerScript.h314
-rw-r--r--contrib/llvm/tools/lld/ELF/MapFile.cpp263
-rw-r--r--contrib/llvm/tools/lld/ELF/MapFile.h20
-rw-r--r--contrib/llvm/tools/lld/ELF/MarkLive.cpp324
-rw-r--r--contrib/llvm/tools/lld/ELF/MarkLive.h21
-rw-r--r--contrib/llvm/tools/lld/ELF/Options.td521
-rw-r--r--contrib/llvm/tools/lld/ELF/OutputSections.cpp437
-rw-r--r--contrib/llvm/tools/lld/ELF/OutputSections.h153
-rw-r--r--contrib/llvm/tools/lld/ELF/README.md1
-rw-r--r--contrib/llvm/tools/lld/ELF/Relocations.cpp1520
-rw-r--r--contrib/llvm/tools/lld/ELF/Relocations.h219
-rw-r--r--contrib/llvm/tools/lld/ELF/ScriptLexer.cpp298
-rw-r--r--contrib/llvm/tools/lld/ELF/ScriptLexer.h56
-rw-r--r--contrib/llvm/tools/lld/ELF/ScriptParser.cpp1545
-rw-r--r--contrib/llvm/tools/lld/ELF/ScriptParser.h34
-rw-r--r--contrib/llvm/tools/lld/ELF/SymbolTable.cpp817
-rw-r--r--contrib/llvm/tools/lld/ELF/SymbolTable.h127
-rw-r--r--contrib/llvm/tools/lld/ELF/Symbols.cpp305
-rw-r--r--contrib/llvm/tools/lld/ELF/Symbols.h419
-rw-r--r--contrib/llvm/tools/lld/ELF/SyntheticSections.cpp3226
-rw-r--r--contrib/llvm/tools/lld/ELF/SyntheticSections.h1043
-rw-r--r--contrib/llvm/tools/lld/ELF/Target.cpp184
-rw-r--r--contrib/llvm/tools/lld/ELF/Target.h260
-rw-r--r--contrib/llvm/tools/lld/ELF/Thunks.cpp846
-rw-r--r--contrib/llvm/tools/lld/ELF/Thunks.h71
-rw-r--r--contrib/llvm/tools/lld/ELF/Writer.cpp2530
-rw-r--r--contrib/llvm/tools/lld/ELF/Writer.h64
-rw-r--r--contrib/llvm/tools/lld/FREEBSD-Xlist7
-rw-r--r--contrib/llvm/tools/lld/LICENSE.TXT62
-rw-r--r--contrib/llvm/tools/lld/README.md19
-rw-r--r--contrib/llvm/tools/lld/docs/AtomLLD.rst62
-rw-r--r--contrib/llvm/tools/lld/docs/CMakeLists.txt8
-rw-r--r--contrib/llvm/tools/lld/docs/Driver.rst82
-rw-r--r--contrib/llvm/tools/lld/docs/NewLLD.rst309
-rw-r--r--contrib/llvm/tools/lld/docs/README.txt9
-rw-r--r--contrib/llvm/tools/lld/docs/Readers.rst174
-rw-r--r--contrib/llvm/tools/lld/docs/ReleaseNotes.rst126
-rw-r--r--contrib/llvm/tools/lld/docs/WebAssembly.rst114
-rw-r--r--contrib/llvm/tools/lld/docs/_static/favicon.icobin0 -> 1150 bytes
-rw-r--r--contrib/llvm/tools/lld/docs/_templates/indexsidebar.html4
-rw-r--r--contrib/llvm/tools/lld/docs/_templates/layout.html12
-rw-r--r--contrib/llvm/tools/lld/docs/conf.py255
-rw-r--r--contrib/llvm/tools/lld/docs/design.rst421
-rw-r--r--contrib/llvm/tools/lld/docs/development.rst45
-rw-r--r--contrib/llvm/tools/lld/docs/getting_started.rst106
-rw-r--r--contrib/llvm/tools/lld/docs/hello.pngbin0 -> 27616 bytes
-rw-r--r--contrib/llvm/tools/lld/docs/index.rst177
-rw-r--r--contrib/llvm/tools/lld/docs/ld.lld.1626
-rw-r--r--contrib/llvm/tools/lld/docs/llvm-theme/layout.html22
-rw-r--r--contrib/llvm/tools/lld/docs/llvm-theme/static/contents.pngbin0 -> 202 bytes
-rw-r--r--contrib/llvm/tools/lld/docs/llvm-theme/static/llvm.css345
-rw-r--r--contrib/llvm/tools/lld/docs/llvm-theme/static/logo.pngbin0 -> 9865 bytes
-rw-r--r--contrib/llvm/tools/lld/docs/llvm-theme/static/navigation.pngbin0 -> 218 bytes
-rw-r--r--contrib/llvm/tools/lld/docs/llvm-theme/theme.conf4
-rw-r--r--contrib/llvm/tools/lld/docs/make.bat190
-rw-r--r--contrib/llvm/tools/lld/docs/missingkeyfunction.rst84
-rw-r--r--contrib/llvm/tools/lld/docs/open_projects.rst9
-rw-r--r--contrib/llvm/tools/lld/docs/sphinx_intro.rst127
-rw-r--r--contrib/llvm/tools/lld/docs/windows_support.rst97
-rw-r--r--contrib/llvm/tools/lld/include/lld/Common/Args.h38
-rw-r--r--contrib/llvm/tools/lld/include/lld/Common/Driver.h43
-rw-r--r--contrib/llvm/tools/lld/include/lld/Common/ErrorHandler.h160
-rw-r--r--contrib/llvm/tools/lld/include/lld/Common/LLVM.h99
-rw-r--r--contrib/llvm/tools/lld/include/lld/Common/Memory.h60
-rw-r--r--contrib/llvm/tools/lld/include/lld/Common/Reproduce.h39
-rw-r--r--contrib/llvm/tools/lld/include/lld/Common/Strings.h46
-rw-r--r--contrib/llvm/tools/lld/include/lld/Common/TargetOptionsCommandFlags.h23
-rw-r--r--contrib/llvm/tools/lld/include/lld/Common/Threads.h86
-rw-r--r--contrib/llvm/tools/lld/include/lld/Common/Timer.h59
-rw-r--r--contrib/llvm/tools/lld/include/lld/Common/Version.h25
-rw-r--r--contrib/llvm/tools/lld/include/lld/Common/Version.inc.in6
-rw-r--r--contrib/llvm/tools/lld/include/lld/Core/AbsoluteAtom.h43
-rw-r--r--contrib/llvm/tools/lld/include/lld/Core/ArchiveLibraryFile.h47
-rw-r--r--contrib/llvm/tools/lld/include/lld/Core/Atom.h131
-rw-r--r--contrib/llvm/tools/lld/include/lld/Core/DefinedAtom.h374
-rw-r--r--contrib/llvm/tools/lld/include/lld/Core/Error.h68
-rw-r--r--contrib/llvm/tools/lld/include/lld/Core/File.h276
-rw-r--r--contrib/llvm/tools/lld/include/lld/Core/Instrumentation.h132
-rw-r--r--contrib/llvm/tools/lld/include/lld/Core/LinkingContext.h257
-rw-r--r--contrib/llvm/tools/lld/include/lld/Core/Node.h75
-rw-r--r--contrib/llvm/tools/lld/include/lld/Core/Pass.h43
-rw-r--r--contrib/llvm/tools/lld/include/lld/Core/PassManager.h48
-rw-r--r--contrib/llvm/tools/lld/include/lld/Core/Reader.h155
-rw-r--r--contrib/llvm/tools/lld/include/lld/Core/Reference.h119
-rw-r--r--contrib/llvm/tools/lld/include/lld/Core/Resolver.h106
-rw-r--r--contrib/llvm/tools/lld/include/lld/Core/SharedLibraryAtom.h53
-rw-r--r--contrib/llvm/tools/lld/include/lld/Core/SharedLibraryFile.h70
-rw-r--r--contrib/llvm/tools/lld/include/lld/Core/Simple.h271
-rw-r--r--contrib/llvm/tools/lld/include/lld/Core/SymbolTable.h96
-rw-r--r--contrib/llvm/tools/lld/include/lld/Core/UndefinedAtom.h68
-rw-r--r--contrib/llvm/tools/lld/include/lld/Core/Writer.h47
-rw-r--r--contrib/llvm/tools/lld/include/lld/ReaderWriter/MachOLinkingContext.h508
-rw-r--r--contrib/llvm/tools/lld/include/lld/ReaderWriter/YamlContext.h43
-rw-r--r--contrib/llvm/tools/lld/lib/CMakeLists.txt3
-rw-r--r--contrib/llvm/tools/lld/lib/Core/CMakeLists.txt28
-rw-r--r--contrib/llvm/tools/lld/lib/Core/DefinedAtom.cpp82
-rw-r--r--contrib/llvm/tools/lld/lib/Core/Error.cpp93
-rw-r--r--contrib/llvm/tools/lld/lib/Core/File.cpp29
-rw-r--r--contrib/llvm/tools/lld/lib/Core/LinkingContext.cpp70
-rw-r--r--contrib/llvm/tools/lld/lib/Core/Reader.cpp114
-rw-r--r--contrib/llvm/tools/lld/lib/Core/Resolver.cpp505
-rw-r--r--contrib/llvm/tools/lld/lib/Core/SymbolTable.cpp291
-rw-r--r--contrib/llvm/tools/lld/lib/Core/Writer.cpp18
-rw-r--r--contrib/llvm/tools/lld/lib/Driver/CMakeLists.txt23
-rw-r--r--contrib/llvm/tools/lld/lib/Driver/DarwinLdDriver.cpp1230
-rw-r--r--contrib/llvm/tools/lld/lib/Driver/DarwinLdOptions.td250
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/CMakeLists.txt20
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/FileArchive.cpp228
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler.cpp172
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler.h323
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp1523
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp898
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp644
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp866
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/Atoms.h181
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/CMakeLists.txt35
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/CompactUnwindPass.cpp585
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/DebugInfo.h106
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ExecutableAtoms.h155
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/File.h400
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/FlatNamespaceFile.h63
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/GOTPass.cpp184
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/LayoutPass.cpp490
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/LayoutPass.h119
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp1101
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFile.h336
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp594
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h214
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp1552
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp1657
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp1635
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp843
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachOPasses.h30
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ObjCPass.cpp132
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/SectCreateFile.h102
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ShimPass.cpp129
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/StubsPass.cpp379
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/TLVPass.cpp141
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/WriterMachO.cpp71
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/YAML/CMakeLists.txt9
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp1404
-rw-r--r--contrib/llvm/tools/lld/tools/lld/CMakeLists.txt27
-rw-r--r--contrib/llvm/tools/lld/tools/lld/lld.cpp148
228 files changed, 70662 insertions, 0 deletions
diff --git a/contrib/llvm/tools/lld/.arcconfig b/contrib/llvm/tools/lld/.arcconfig
new file mode 100644
index 000000000000..c8a8e079023f
--- /dev/null
+++ b/contrib/llvm/tools/lld/.arcconfig
@@ -0,0 +1,4 @@
+{
+ "repository.callsign" : "LLD",
+ "conduit_uri" : "https://reviews.llvm.org/"
+}
diff --git a/contrib/llvm/tools/lld/.clang-format b/contrib/llvm/tools/lld/.clang-format
new file mode 100644
index 000000000000..9b3aa8b7213b
--- /dev/null
+++ b/contrib/llvm/tools/lld/.clang-format
@@ -0,0 +1 @@
+BasedOnStyle: LLVM
diff --git a/contrib/llvm/tools/lld/.gitignore b/contrib/llvm/tools/lld/.gitignore
new file mode 100644
index 000000000000..0a288ee8ce96
--- /dev/null
+++ b/contrib/llvm/tools/lld/.gitignore
@@ -0,0 +1,24 @@
+#==============================================================================#
+# This file specifies intentionally untracked files that git should ignore.
+# See: http://www.kernel.org/pub/software/scm/git/docs/gitignore.html
+#==============================================================================#
+
+#==============================================================================#
+# File extensions to be ignored anywhere in the tree.
+#==============================================================================#
+# Temp files created by most text editors.
+*~
+# Merge files created by git.
+*.orig
+# Byte compiled python modules.
+*.pyc
+# vim swap files
+.*.swp
+# Mac OS X Finder layout info
+.DS_Store
+
+#==============================================================================#
+# Directories to be ignored.
+#==============================================================================#
+# Sphinx build files.
+docs/_build
diff --git a/contrib/llvm/tools/lld/CMakeLists.txt b/contrib/llvm/tools/lld/CMakeLists.txt
new file mode 100644
index 000000000000..e2fbdbfbbb47
--- /dev/null
+++ b/contrib/llvm/tools/lld/CMakeLists.txt
@@ -0,0 +1,226 @@
+# Check if lld is built as a standalone project.
+if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
+ project(lld)
+ cmake_minimum_required(VERSION 3.4.3)
+
+ set(CMAKE_INCLUDE_CURRENT_DIR ON)
+ set(LLD_BUILT_STANDALONE TRUE)
+
+ find_program(LLVM_CONFIG_PATH "llvm-config" DOC "Path to llvm-config binary")
+ if(NOT LLVM_CONFIG_PATH)
+ message(FATAL_ERROR "llvm-config not found: specify LLVM_CONFIG_PATH")
+ endif()
+
+ execute_process(COMMAND "${LLVM_CONFIG_PATH}"
+ "--obj-root"
+ "--includedir"
+ "--cmakedir"
+ "--src-root"
+ RESULT_VARIABLE HAD_ERROR
+ OUTPUT_VARIABLE LLVM_CONFIG_OUTPUT
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if(HAD_ERROR)
+ message(FATAL_ERROR "llvm-config failed with status ${HAD_ERROR}")
+ endif()
+
+ string(REGEX REPLACE "[ \t]*[\r\n]+[ \t]*" ";" LLVM_CONFIG_OUTPUT "${LLVM_CONFIG_OUTPUT}")
+
+ list(GET LLVM_CONFIG_OUTPUT 0 OBJ_ROOT)
+ list(GET LLVM_CONFIG_OUTPUT 1 MAIN_INCLUDE_DIR)
+ list(GET LLVM_CONFIG_OUTPUT 2 LLVM_CMAKE_PATH)
+ list(GET LLVM_CONFIG_OUTPUT 3 MAIN_SRC_DIR)
+
+ set(LLVM_OBJ_ROOT ${OBJ_ROOT} CACHE PATH "path to LLVM build tree")
+ set(LLVM_MAIN_INCLUDE_DIR ${MAIN_INCLUDE_DIR} CACHE PATH "path to llvm/include")
+ set(LLVM_MAIN_SRC_DIR ${MAIN_SRC_DIR} CACHE PATH "Path to LLVM source tree")
+
+ file(TO_CMAKE_PATH ${LLVM_OBJ_ROOT} LLVM_BINARY_DIR)
+
+ if(NOT EXISTS "${LLVM_CMAKE_PATH}/LLVMConfig.cmake")
+ message(FATAL_ERROR "LLVMConfig.cmake not found")
+ endif()
+ include("${LLVM_CMAKE_PATH}/LLVMConfig.cmake")
+
+ list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_PATH}")
+
+ set(PACKAGE_VERSION "${LLVM_PACKAGE_VERSION}")
+ include_directories("${LLVM_BINARY_DIR}/include" ${LLVM_INCLUDE_DIRS})
+ link_directories(${LLVM_LIBRARY_DIRS})
+
+ set(LLVM_LIBRARY_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${LLVM_LIBDIR_SUFFIX})
+ set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/bin)
+ find_program(LLVM_TABLEGEN_EXE "llvm-tblgen" ${LLVM_TOOLS_BINARY_DIR} NO_DEFAULT_PATH)
+
+ include(AddLLVM)
+ include(TableGen)
+ include(HandleLLVMOptions)
+
+ if(LLVM_INCLUDE_TESTS)
+ set(Python_ADDITIONAL_VERSIONS 2.7)
+ include(FindPythonInterp)
+ if(NOT PYTHONINTERP_FOUND)
+ message(FATAL_ERROR
+"Unable to find Python interpreter, required for testing.
+
+Please install Python or specify the PYTHON_EXECUTABLE CMake variable.")
+ endif()
+
+ if(${PYTHON_VERSION_STRING} VERSION_LESS 2.7)
+ message(FATAL_ERROR "Python 2.7 or newer is required")
+ endif()
+
+ # Check prebuilt llvm/utils.
+ if(EXISTS ${LLVM_TOOLS_BINARY_DIR}/FileCheck${CMAKE_EXECUTABLE_SUFFIX}
+ AND EXISTS ${LLVM_TOOLS_BINARY_DIR}/not${CMAKE_EXECUTABLE_SUFFIX})
+ set(LLVM_UTILS_PROVIDED ON)
+ endif()
+
+ if(EXISTS ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py)
+ # Note: path not really used, except for checking if lit was found
+ set(LLVM_LIT ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py)
+ if(NOT LLVM_UTILS_PROVIDED)
+ add_subdirectory(${LLVM_MAIN_SRC_DIR}/utils/FileCheck utils/FileCheck)
+ add_subdirectory(${LLVM_MAIN_SRC_DIR}/utils/not utils/not)
+ set(LLVM_UTILS_PROVIDED ON)
+ set(LLD_TEST_DEPS FileCheck not)
+ endif()
+ set(UNITTEST_DIR ${LLVM_MAIN_SRC_DIR}/utils/unittest)
+ if(EXISTS ${UNITTEST_DIR}/googletest/include/gtest/gtest.h
+ AND NOT EXISTS ${LLVM_LIBRARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}gtest${CMAKE_STATIC_LIBRARY_SUFFIX}
+ AND EXISTS ${UNITTEST_DIR}/CMakeLists.txt)
+ add_subdirectory(${UNITTEST_DIR} utils/unittest)
+ endif()
+ else()
+ # Seek installed Lit.
+ find_program(LLVM_LIT
+ NAMES llvm-lit lit.py lit
+ PATHS "${LLVM_MAIN_SRC_DIR}/utils/lit"
+ DOC "Path to lit.py")
+ endif()
+
+ if(LLVM_LIT)
+ # Define the default arguments to use with 'lit', and an option for the user
+ # to override.
+ set(LIT_ARGS_DEFAULT "-sv")
+ if (MSVC OR XCODE)
+ set(LIT_ARGS_DEFAULT "${LIT_ARGS_DEFAULT} --no-progress-bar")
+ endif()
+ set(LLVM_LIT_ARGS "${LIT_ARGS_DEFAULT}" CACHE STRING "Default options for lit")
+
+ # On Win32 hosts, provide an option to specify the path to the GnuWin32 tools.
+ if(WIN32 AND NOT CYGWIN)
+ set(LLVM_LIT_TOOLS_DIR "" CACHE PATH "Path to GnuWin32 tools")
+ endif()
+ else()
+ set(LLVM_INCLUDE_TESTS OFF)
+ endif()
+ endif()
+endif()
+
+set(LLD_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
+set(LLD_INCLUDE_DIR ${LLD_SOURCE_DIR}/include )
+set(LLD_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
+
+# Compute the LLD version from the LLVM version.
+string(REGEX MATCH "[0-9]+\\.[0-9]+(\\.[0-9]+)?" LLD_VERSION
+ ${PACKAGE_VERSION})
+message(STATUS "LLD version: ${LLD_VERSION}")
+
+string(REGEX REPLACE "([0-9]+)\\.[0-9]+(\\.[0-9]+)?" "\\1" LLD_VERSION_MAJOR
+ ${LLD_VERSION})
+string(REGEX REPLACE "[0-9]+\\.([0-9]+)(\\.[0-9]+)?" "\\1" LLD_VERSION_MINOR
+ ${LLD_VERSION})
+
+# Determine LLD revision and repository.
+# TODO: Figure out a way to get the revision and the repository on windows.
+if ( NOT CMAKE_SYSTEM_NAME MATCHES "Windows" )
+ execute_process(COMMAND ${CMAKE_SOURCE_DIR}/utils/GetSourceVersion ${LLD_SOURCE_DIR}
+ OUTPUT_VARIABLE LLD_REVISION)
+
+ execute_process(COMMAND ${CMAKE_SOURCE_DIR}/utils/GetRepositoryPath ${LLD_SOURCE_DIR}
+ OUTPUT_VARIABLE LLD_REPOSITORY)
+ if ( LLD_REPOSITORY )
+ # Replace newline characters with spaces
+ string(REGEX REPLACE "(\r?\n)+" " " LLD_REPOSITORY ${LLD_REPOSITORY})
+ # Remove leading spaces
+ STRING(REGEX REPLACE "^[ \t\r\n]+" "" LLD_REPOSITORY "${LLD_REPOSITORY}" )
+ # Remove trailing spaces
+ string(REGEX REPLACE "(\ )+$" "" LLD_REPOSITORY ${LLD_REPOSITORY})
+ endif()
+
+ if ( LLD_REVISION )
+ # Replace newline characters with spaces
+ string(REGEX REPLACE "(\r?\n)+" " " LLD_REVISION ${LLD_REVISION})
+ # Remove leading spaces
+ STRING(REGEX REPLACE "^[ \t\r\n]+" "" LLD_REVISION "${LLD_REVISION}" )
+ # Remove trailing spaces
+ string(REGEX REPLACE "(\ )+$" "" LLD_REVISION ${LLD_REVISION})
+ endif()
+endif ()
+
+# Configure the Version.inc file.
+configure_file(
+ ${CMAKE_CURRENT_SOURCE_DIR}/include/lld/Common/Version.inc.in
+ ${CMAKE_CURRENT_BINARY_DIR}/include/lld/Common/Version.inc)
+
+
+if (CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
+ message(FATAL_ERROR "In-source builds are not allowed. CMake would overwrite "
+"the makefiles distributed with LLVM. Please create a directory and run cmake "
+"from there, passing the path to this source directory as the last argument. "
+"This process created the file `CMakeCache.txt' and the directory "
+"`CMakeFiles'. Please delete them.")
+endif()
+
+list (APPEND CMAKE_MODULE_PATH "${LLD_SOURCE_DIR}/cmake/modules")
+
+include(AddLLD)
+
+option(LLD_USE_VTUNE
+ "Enable VTune user task tracking."
+ OFF)
+if (LLD_USE_VTUNE)
+ find_package(VTune)
+ if (VTUNE_FOUND)
+ include_directories(${VTune_INCLUDE_DIRS})
+ list(APPEND LLVM_COMMON_LIBS ${VTune_LIBRARIES})
+ add_definitions(-DLLD_HAS_VTUNE)
+ endif()
+endif()
+
+option(LLD_BUILD_TOOLS
+ "Build the lld tools. If OFF, just generate build targets." ON)
+
+if (MSVC)
+ add_definitions(-wd4530) # Suppress 'warning C4530: C++ exception handler used, but unwind semantics are not enabled.'
+ add_definitions(-wd4062) # Suppress 'warning C4062: enumerator X in switch of enum Y is not handled' from system header.
+endif()
+
+include_directories(BEFORE
+ ${CMAKE_CURRENT_BINARY_DIR}/include
+ ${CMAKE_CURRENT_SOURCE_DIR}/include
+ )
+
+if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
+ install(DIRECTORY include/
+ DESTINATION include
+ FILES_MATCHING
+ PATTERN "*.h"
+ PATTERN ".svn" EXCLUDE
+ )
+endif()
+
+add_subdirectory(Common)
+add_subdirectory(lib)
+add_subdirectory(tools/lld)
+
+if (LLVM_INCLUDE_TESTS)
+ add_subdirectory(test)
+ add_subdirectory(unittests)
+endif()
+
+add_subdirectory(docs)
+add_subdirectory(COFF)
+add_subdirectory(ELF)
+add_subdirectory(MinGW)
+add_subdirectory(wasm)
diff --git a/contrib/llvm/tools/lld/CODE_OWNERS.TXT b/contrib/llvm/tools/lld/CODE_OWNERS.TXT
new file mode 100644
index 000000000000..f019a87553aa
--- /dev/null
+++ b/contrib/llvm/tools/lld/CODE_OWNERS.TXT
@@ -0,0 +1,22 @@
+This file is a list of the people responsible for ensuring that patches for a
+particular part of LLD are reviewed, either by themself or by someone else.
+They are also the gatekeepers for their part of LLD, with the final word on
+what goes in or not.
+
+The list is sorted by surname and formatted to allow easy grepping and
+beautification by scripts. The fields are: name (N), email (E), web-address
+(W), PGP key ID and fingerprint (P), description (D), and snail-mail address
+(S). Each entry should contain at least the (N), (E) and (D) fields.
+
+
+N: Rui Ueyama
+E: ruiu@google.com
+D: COFF, ELF backends (COFF/* ELF/*)
+
+N: Lang Hames, Nick Kledzik
+E: lhames@gmail.com, kledzik@apple.com
+D: Mach-O backend
+
+N: Sam Clegg
+E: sbc@chromium.org
+D: WebAssembly backend (wasm/*)
diff --git a/contrib/llvm/tools/lld/COFF/CMakeLists.txt b/contrib/llvm/tools/lld/COFF/CMakeLists.txt
new file mode 100644
index 000000000000..bb241e788c19
--- /dev/null
+++ b/contrib/llvm/tools/lld/COFF/CMakeLists.txt
@@ -0,0 +1,47 @@
+set(LLVM_TARGET_DEFINITIONS Options.td)
+tablegen(LLVM Options.inc -gen-opt-parser-defs)
+add_public_tablegen_target(COFFOptionsTableGen)
+
+if(NOT LLD_BUILT_STANDALONE)
+ set(tablegen_deps intrinsics_gen)
+endif()
+
+add_lld_library(lldCOFF
+ Chunks.cpp
+ DLL.cpp
+ Driver.cpp
+ DriverUtils.cpp
+ ICF.cpp
+ InputFiles.cpp
+ LTO.cpp
+ MapFile.cpp
+ MarkLive.cpp
+ MinGW.cpp
+ PDB.cpp
+ SymbolTable.cpp
+ Symbols.cpp
+ Writer.cpp
+
+ LINK_COMPONENTS
+ ${LLVM_TARGETS_TO_BUILD}
+ BinaryFormat
+ Core
+ DebugInfoCodeView
+ DebugInfoMSF
+ DebugInfoPDB
+ LibDriver
+ LTO
+ MC
+ Object
+ Option
+ Support
+ WindowsManifest
+
+ LINK_LIBS
+ lldCommon
+ ${LLVM_PTHREAD_LIB}
+
+ DEPENDS
+ COFFOptionsTableGen
+ ${tablegen_deps}
+ )
diff --git a/contrib/llvm/tools/lld/COFF/Chunks.cpp b/contrib/llvm/tools/lld/COFF/Chunks.cpp
new file mode 100644
index 000000000000..2bb9aa01e539
--- /dev/null
+++ b/contrib/llvm/tools/lld/COFF/Chunks.cpp
@@ -0,0 +1,883 @@
+//===- Chunks.cpp ---------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Chunks.h"
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "Writer.h"
+#include "SymbolTable.h"
+#include "lld/Common/ErrorHandler.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+using namespace llvm::COFF;
+using llvm::support::ulittle32_t;
+
+namespace lld {
+namespace coff {
+
+SectionChunk::SectionChunk(ObjFile *F, const coff_section *H)
+ : Chunk(SectionKind), Repl(this), Header(H), File(F),
+ Relocs(File->getCOFFObj()->getRelocations(Header)) {
+ // Initialize SectionName.
+ File->getCOFFObj()->getSectionName(Header, SectionName);
+
+ Alignment = Header->getAlignment();
+
+ // If linker GC is disabled, every chunk starts out alive. If linker GC is
+ // enabled, treat non-comdat sections as roots. Generally optimized object
+ // files will be built with -ffunction-sections or /Gy, so most things worth
+ // stripping will be in a comdat.
+ Live = !Config->DoGC || !isCOMDAT();
+}
+
+// Initialize the RelocTargets vector, to allow redirecting certain relocations
+// to a thunk instead of the actual symbol the relocation's symbol table index
+// indicates.
+void SectionChunk::readRelocTargets() {
+ assert(RelocTargets.empty());
+ RelocTargets.reserve(Relocs.size());
+ for (const coff_relocation &Rel : Relocs)
+ RelocTargets.push_back(File->getSymbol(Rel.SymbolTableIndex));
+}
+
+// Reset RelocTargets to their original targets before thunks were added.
+void SectionChunk::resetRelocTargets() {
+ for (size_t I = 0, E = Relocs.size(); I < E; ++I)
+ RelocTargets[I] = File->getSymbol(Relocs[I].SymbolTableIndex);
+}
+
+static void add16(uint8_t *P, int16_t V) { write16le(P, read16le(P) + V); }
+static void add32(uint8_t *P, int32_t V) { write32le(P, read32le(P) + V); }
+static void add64(uint8_t *P, int64_t V) { write64le(P, read64le(P) + V); }
+static void or16(uint8_t *P, uint16_t V) { write16le(P, read16le(P) | V); }
+static void or32(uint8_t *P, uint32_t V) { write32le(P, read32le(P) | V); }
+
+// Verify that given sections are appropriate targets for SECREL
+// relocations. This check is relaxed because unfortunately debug
+// sections have section-relative relocations against absolute symbols.
+static bool checkSecRel(const SectionChunk *Sec, OutputSection *OS) {
+ if (OS)
+ return true;
+ if (Sec->isCodeView())
+ return false;
+ error("SECREL relocation cannot be applied to absolute symbols");
+ return false;
+}
+
+static void applySecRel(const SectionChunk *Sec, uint8_t *Off,
+ OutputSection *OS, uint64_t S) {
+ if (!checkSecRel(Sec, OS))
+ return;
+ uint64_t SecRel = S - OS->getRVA();
+ if (SecRel > UINT32_MAX) {
+ error("overflow in SECREL relocation in section: " + Sec->getSectionName());
+ return;
+ }
+ add32(Off, SecRel);
+}
+
+static void applySecIdx(uint8_t *Off, OutputSection *OS) {
+ // Absolute symbol doesn't have section index, but section index relocation
+ // against absolute symbol should be resolved to one plus the last output
+ // section index. This is required for compatibility with MSVC.
+ if (OS)
+ add16(Off, OS->SectionIndex);
+ else
+ add16(Off, DefinedAbsolute::NumOutputSections + 1);
+}
+
+void SectionChunk::applyRelX64(uint8_t *Off, uint16_t Type, OutputSection *OS,
+ uint64_t S, uint64_t P) const {
+ switch (Type) {
+ case IMAGE_REL_AMD64_ADDR32: add32(Off, S + Config->ImageBase); break;
+ case IMAGE_REL_AMD64_ADDR64: add64(Off, S + Config->ImageBase); break;
+ case IMAGE_REL_AMD64_ADDR32NB: add32(Off, S); break;
+ case IMAGE_REL_AMD64_REL32: add32(Off, S - P - 4); break;
+ case IMAGE_REL_AMD64_REL32_1: add32(Off, S - P - 5); break;
+ case IMAGE_REL_AMD64_REL32_2: add32(Off, S - P - 6); break;
+ case IMAGE_REL_AMD64_REL32_3: add32(Off, S - P - 7); break;
+ case IMAGE_REL_AMD64_REL32_4: add32(Off, S - P - 8); break;
+ case IMAGE_REL_AMD64_REL32_5: add32(Off, S - P - 9); break;
+ case IMAGE_REL_AMD64_SECTION: applySecIdx(Off, OS); break;
+ case IMAGE_REL_AMD64_SECREL: applySecRel(this, Off, OS, S); break;
+ default:
+ error("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " +
+ toString(File));
+ }
+}
+
+void SectionChunk::applyRelX86(uint8_t *Off, uint16_t Type, OutputSection *OS,
+ uint64_t S, uint64_t P) const {
+ switch (Type) {
+ case IMAGE_REL_I386_ABSOLUTE: break;
+ case IMAGE_REL_I386_DIR32: add32(Off, S + Config->ImageBase); break;
+ case IMAGE_REL_I386_DIR32NB: add32(Off, S); break;
+ case IMAGE_REL_I386_REL32: add32(Off, S - P - 4); break;
+ case IMAGE_REL_I386_SECTION: applySecIdx(Off, OS); break;
+ case IMAGE_REL_I386_SECREL: applySecRel(this, Off, OS, S); break;
+ default:
+ error("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " +
+ toString(File));
+ }
+}
+
+static void applyMOV(uint8_t *Off, uint16_t V) {
+ write16le(Off, (read16le(Off) & 0xfbf0) | ((V & 0x800) >> 1) | ((V >> 12) & 0xf));
+ write16le(Off + 2, (read16le(Off + 2) & 0x8f00) | ((V & 0x700) << 4) | (V & 0xff));
+}
+
+static uint16_t readMOV(uint8_t *Off, bool MOVT) {
+ uint16_t Op1 = read16le(Off);
+ if ((Op1 & 0xfbf0) != (MOVT ? 0xf2c0 : 0xf240))
+ error("unexpected instruction in " + Twine(MOVT ? "MOVT" : "MOVW") +
+ " instruction in MOV32T relocation");
+ uint16_t Op2 = read16le(Off + 2);
+ if ((Op2 & 0x8000) != 0)
+ error("unexpected instruction in " + Twine(MOVT ? "MOVT" : "MOVW") +
+ " instruction in MOV32T relocation");
+ return (Op2 & 0x00ff) | ((Op2 >> 4) & 0x0700) | ((Op1 << 1) & 0x0800) |
+ ((Op1 & 0x000f) << 12);
+}
+
+void applyMOV32T(uint8_t *Off, uint32_t V) {
+ uint16_t ImmW = readMOV(Off, false); // read MOVW operand
+ uint16_t ImmT = readMOV(Off + 4, true); // read MOVT operand
+ uint32_t Imm = ImmW | (ImmT << 16);
+ V += Imm; // add the immediate offset
+ applyMOV(Off, V); // set MOVW operand
+ applyMOV(Off + 4, V >> 16); // set MOVT operand
+}
+
+static void applyBranch20T(uint8_t *Off, int32_t V) {
+ if (!isInt<21>(V))
+ error("relocation out of range");
+ uint32_t S = V < 0 ? 1 : 0;
+ uint32_t J1 = (V >> 19) & 1;
+ uint32_t J2 = (V >> 18) & 1;
+ or16(Off, (S << 10) | ((V >> 12) & 0x3f));
+ or16(Off + 2, (J1 << 13) | (J2 << 11) | ((V >> 1) & 0x7ff));
+}
+
+void applyBranch24T(uint8_t *Off, int32_t V) {
+ if (!isInt<25>(V))
+ error("relocation out of range");
+ uint32_t S = V < 0 ? 1 : 0;
+ uint32_t J1 = ((~V >> 23) & 1) ^ S;
+ uint32_t J2 = ((~V >> 22) & 1) ^ S;
+ or16(Off, (S << 10) | ((V >> 12) & 0x3ff));
+ // Clear out the J1 and J2 bits which may be set.
+ write16le(Off + 2, (read16le(Off + 2) & 0xd000) | (J1 << 13) | (J2 << 11) | ((V >> 1) & 0x7ff));
+}
+
+void SectionChunk::applyRelARM(uint8_t *Off, uint16_t Type, OutputSection *OS,
+ uint64_t S, uint64_t P) const {
+ // Pointer to thumb code must have the LSB set.
+ uint64_t SX = S;
+ if (OS && (OS->Header.Characteristics & IMAGE_SCN_MEM_EXECUTE))
+ SX |= 1;
+ switch (Type) {
+ case IMAGE_REL_ARM_ADDR32: add32(Off, SX + Config->ImageBase); break;
+ case IMAGE_REL_ARM_ADDR32NB: add32(Off, SX); break;
+ case IMAGE_REL_ARM_MOV32T: applyMOV32T(Off, SX + Config->ImageBase); break;
+ case IMAGE_REL_ARM_BRANCH20T: applyBranch20T(Off, SX - P - 4); break;
+ case IMAGE_REL_ARM_BRANCH24T: applyBranch24T(Off, SX - P - 4); break;
+ case IMAGE_REL_ARM_BLX23T: applyBranch24T(Off, SX - P - 4); break;
+ case IMAGE_REL_ARM_SECTION: applySecIdx(Off, OS); break;
+ case IMAGE_REL_ARM_SECREL: applySecRel(this, Off, OS, S); break;
+ default:
+ error("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " +
+ toString(File));
+ }
+}
+
+// Interpret the existing immediate value as a byte offset to the
+// target symbol, then update the instruction with the immediate as
+// the page offset from the current instruction to the target.
+void applyArm64Addr(uint8_t *Off, uint64_t S, uint64_t P, int Shift) {
+ uint32_t Orig = read32le(Off);
+ uint64_t Imm = ((Orig >> 29) & 0x3) | ((Orig >> 3) & 0x1FFFFC);
+ S += Imm;
+ Imm = (S >> Shift) - (P >> Shift);
+ uint32_t ImmLo = (Imm & 0x3) << 29;
+ uint32_t ImmHi = (Imm & 0x1FFFFC) << 3;
+ uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3);
+ write32le(Off, (Orig & ~Mask) | ImmLo | ImmHi);
+}
+
+// Update the immediate field in a AARCH64 ldr, str, and add instruction.
+// Optionally limit the range of the written immediate by one or more bits
+// (RangeLimit).
+void applyArm64Imm(uint8_t *Off, uint64_t Imm, uint32_t RangeLimit) {
+ uint32_t Orig = read32le(Off);
+ Imm += (Orig >> 10) & 0xFFF;
+ Orig &= ~(0xFFF << 10);
+ write32le(Off, Orig | ((Imm & (0xFFF >> RangeLimit)) << 10));
+}
+
+// Add the 12 bit page offset to the existing immediate.
+// Ldr/str instructions store the opcode immediate scaled
+// by the load/store size (giving a larger range for larger
+// loads/stores). The immediate is always (both before and after
+// fixing up the relocation) stored scaled similarly.
+// Even if larger loads/stores have a larger range, limit the
+// effective offset to 12 bit, since it is intended to be a
+// page offset.
+static void applyArm64Ldr(uint8_t *Off, uint64_t Imm) {
+ uint32_t Orig = read32le(Off);
+ uint32_t Size = Orig >> 30;
+ // 0x04000000 indicates SIMD/FP registers
+ // 0x00800000 indicates 128 bit
+ if ((Orig & 0x4800000) == 0x4800000)
+ Size += 4;
+ if ((Imm & ((1 << Size) - 1)) != 0)
+ error("misaligned ldr/str offset");
+ applyArm64Imm(Off, Imm >> Size, Size);
+}
+
+static void applySecRelLow12A(const SectionChunk *Sec, uint8_t *Off,
+ OutputSection *OS, uint64_t S) {
+ if (checkSecRel(Sec, OS))
+ applyArm64Imm(Off, (S - OS->getRVA()) & 0xfff, 0);
+}
+
+static void applySecRelHigh12A(const SectionChunk *Sec, uint8_t *Off,
+ OutputSection *OS, uint64_t S) {
+ if (!checkSecRel(Sec, OS))
+ return;
+ uint64_t SecRel = (S - OS->getRVA()) >> 12;
+ if (0xfff < SecRel) {
+ error("overflow in SECREL_HIGH12A relocation in section: " +
+ Sec->getSectionName());
+ return;
+ }
+ applyArm64Imm(Off, SecRel & 0xfff, 0);
+}
+
+static void applySecRelLdr(const SectionChunk *Sec, uint8_t *Off,
+ OutputSection *OS, uint64_t S) {
+ if (checkSecRel(Sec, OS))
+ applyArm64Ldr(Off, (S - OS->getRVA()) & 0xfff);
+}
+
+void applyArm64Branch26(uint8_t *Off, int64_t V) {
+ if (!isInt<28>(V))
+ error("relocation out of range");
+ or32(Off, (V & 0x0FFFFFFC) >> 2);
+}
+
+static void applyArm64Branch19(uint8_t *Off, int64_t V) {
+ if (!isInt<21>(V))
+ error("relocation out of range");
+ or32(Off, (V & 0x001FFFFC) << 3);
+}
+
+static void applyArm64Branch14(uint8_t *Off, int64_t V) {
+ if (!isInt<16>(V))
+ error("relocation out of range");
+ or32(Off, (V & 0x0000FFFC) << 3);
+}
+
+void SectionChunk::applyRelARM64(uint8_t *Off, uint16_t Type, OutputSection *OS,
+ uint64_t S, uint64_t P) const {
+ switch (Type) {
+ case IMAGE_REL_ARM64_PAGEBASE_REL21: applyArm64Addr(Off, S, P, 12); break;
+ case IMAGE_REL_ARM64_REL21: applyArm64Addr(Off, S, P, 0); break;
+ case IMAGE_REL_ARM64_PAGEOFFSET_12A: applyArm64Imm(Off, S & 0xfff, 0); break;
+ case IMAGE_REL_ARM64_PAGEOFFSET_12L: applyArm64Ldr(Off, S & 0xfff); break;
+ case IMAGE_REL_ARM64_BRANCH26: applyArm64Branch26(Off, S - P); break;
+ case IMAGE_REL_ARM64_BRANCH19: applyArm64Branch19(Off, S - P); break;
+ case IMAGE_REL_ARM64_BRANCH14: applyArm64Branch14(Off, S - P); break;
+ case IMAGE_REL_ARM64_ADDR32: add32(Off, S + Config->ImageBase); break;
+ case IMAGE_REL_ARM64_ADDR32NB: add32(Off, S); break;
+ case IMAGE_REL_ARM64_ADDR64: add64(Off, S + Config->ImageBase); break;
+ case IMAGE_REL_ARM64_SECREL: applySecRel(this, Off, OS, S); break;
+ case IMAGE_REL_ARM64_SECREL_LOW12A: applySecRelLow12A(this, Off, OS, S); break;
+ case IMAGE_REL_ARM64_SECREL_HIGH12A: applySecRelHigh12A(this, Off, OS, S); break;
+ case IMAGE_REL_ARM64_SECREL_LOW12L: applySecRelLdr(this, Off, OS, S); break;
+ case IMAGE_REL_ARM64_SECTION: applySecIdx(Off, OS); break;
+ default:
+ error("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " +
+ toString(File));
+ }
+}
+
+static void maybeReportRelocationToDiscarded(const SectionChunk *FromChunk,
+ Defined *Sym,
+ const coff_relocation &Rel) {
+ // Don't report these errors when the relocation comes from a debug info
+ // section or in mingw mode. MinGW mode object files (built by GCC) can
+ // have leftover sections with relocations against discarded comdat
+ // sections. Such sections are left as is, with relocations untouched.
+ if (FromChunk->isCodeView() || FromChunk->isDWARF() || Config->MinGW)
+ return;
+
+ // Get the name of the symbol. If it's null, it was discarded early, so we
+ // have to go back to the object file.
+ ObjFile *File = FromChunk->File;
+ StringRef Name;
+ if (Sym) {
+ Name = Sym->getName();
+ } else {
+ COFFSymbolRef COFFSym =
+ check(File->getCOFFObj()->getSymbol(Rel.SymbolTableIndex));
+ File->getCOFFObj()->getSymbolName(COFFSym, Name);
+ }
+
+ error("relocation against symbol in discarded section: " + Name +
+ getSymbolLocations(File, Rel.SymbolTableIndex));
+}
+
+void SectionChunk::writeTo(uint8_t *Buf) const {
+ if (!hasData())
+ return;
+ // Copy section contents from source object file to output file.
+ ArrayRef<uint8_t> A = getContents();
+ if (!A.empty())
+ memcpy(Buf + OutputSectionOff, A.data(), A.size());
+
+ // Apply relocations.
+ size_t InputSize = getSize();
+ for (size_t I = 0, E = Relocs.size(); I < E; I++) {
+ const coff_relocation &Rel = Relocs[I];
+
+ // Check for an invalid relocation offset. This check isn't perfect, because
+ // we don't have the relocation size, which is only known after checking the
+ // machine and relocation type. As a result, a relocation may overwrite the
+ // beginning of the following input section.
+ if (Rel.VirtualAddress >= InputSize) {
+ error("relocation points beyond the end of its parent section");
+ continue;
+ }
+
+ uint8_t *Off = Buf + OutputSectionOff + Rel.VirtualAddress;
+
+ // Use the potentially remapped Symbol instead of the one that the
+ // relocation points to.
+ auto *Sym = dyn_cast_or_null<Defined>(RelocTargets[I]);
+
+ // Get the output section of the symbol for this relocation. The output
+ // section is needed to compute SECREL and SECTION relocations used in debug
+ // info.
+ Chunk *C = Sym ? Sym->getChunk() : nullptr;
+ OutputSection *OS = C ? C->getOutputSection() : nullptr;
+
+ // Skip the relocation if it refers to a discarded section, and diagnose it
+ // as an error if appropriate. If a symbol was discarded early, it may be
+ // null. If it was discarded late, the output section will be null, unless
+ // it was an absolute or synthetic symbol.
+ if (!Sym ||
+ (!OS && !isa<DefinedAbsolute>(Sym) && !isa<DefinedSynthetic>(Sym))) {
+ maybeReportRelocationToDiscarded(this, Sym, Rel);
+ continue;
+ }
+
+ uint64_t S = Sym->getRVA();
+
+ // Compute the RVA of the relocation for relative relocations.
+ uint64_t P = RVA + Rel.VirtualAddress;
+ switch (Config->Machine) {
+ case AMD64:
+ applyRelX64(Off, Rel.Type, OS, S, P);
+ break;
+ case I386:
+ applyRelX86(Off, Rel.Type, OS, S, P);
+ break;
+ case ARMNT:
+ applyRelARM(Off, Rel.Type, OS, S, P);
+ break;
+ case ARM64:
+ applyRelARM64(Off, Rel.Type, OS, S, P);
+ break;
+ default:
+ llvm_unreachable("unknown machine type");
+ }
+ }
+}
+
+void SectionChunk::addAssociative(SectionChunk *Child) {
+ AssocChildren.push_back(Child);
+}
+
+static uint8_t getBaserelType(const coff_relocation &Rel) {
+ switch (Config->Machine) {
+ case AMD64:
+ if (Rel.Type == IMAGE_REL_AMD64_ADDR64)
+ return IMAGE_REL_BASED_DIR64;
+ return IMAGE_REL_BASED_ABSOLUTE;
+ case I386:
+ if (Rel.Type == IMAGE_REL_I386_DIR32)
+ return IMAGE_REL_BASED_HIGHLOW;
+ return IMAGE_REL_BASED_ABSOLUTE;
+ case ARMNT:
+ if (Rel.Type == IMAGE_REL_ARM_ADDR32)
+ return IMAGE_REL_BASED_HIGHLOW;
+ if (Rel.Type == IMAGE_REL_ARM_MOV32T)
+ return IMAGE_REL_BASED_ARM_MOV32T;
+ return IMAGE_REL_BASED_ABSOLUTE;
+ case ARM64:
+ if (Rel.Type == IMAGE_REL_ARM64_ADDR64)
+ return IMAGE_REL_BASED_DIR64;
+ return IMAGE_REL_BASED_ABSOLUTE;
+ default:
+ llvm_unreachable("unknown machine type");
+ }
+}
+
+// Windows-specific.
+// Collect all locations that contain absolute addresses, which need to be
+// fixed by the loader if load-time relocation is needed.
+// Only called when base relocation is enabled.
+void SectionChunk::getBaserels(std::vector<Baserel> *Res) {
+ for (size_t I = 0, E = Relocs.size(); I < E; I++) {
+ const coff_relocation &Rel = Relocs[I];
+ uint8_t Ty = getBaserelType(Rel);
+ if (Ty == IMAGE_REL_BASED_ABSOLUTE)
+ continue;
+ // Use the potentially remapped Symbol instead of the one that the
+ // relocation points to.
+ Symbol *Target = RelocTargets[I];
+ if (!Target || isa<DefinedAbsolute>(Target))
+ continue;
+ Res->emplace_back(RVA + Rel.VirtualAddress, Ty);
+ }
+}
+
+// MinGW specific.
+// Check whether a static relocation of type Type can be deferred and
+// handled at runtime as a pseudo relocation (for references to a module
+// local variable, which turned out to actually need to be imported from
+// another DLL) This returns the size the relocation is supposed to update,
+// in bits, or 0 if the relocation cannot be handled as a runtime pseudo
+// relocation.
+static int getRuntimePseudoRelocSize(uint16_t Type) {
+ // Relocations that either contain an absolute address, or a plain
+ // relative offset, since the runtime pseudo reloc implementation
+ // adds 8/16/32/64 bit values to a memory address.
+ //
+ // Given a pseudo relocation entry,
+ //
+ // typedef struct {
+ // DWORD sym;
+ // DWORD target;
+ // DWORD flags;
+ // } runtime_pseudo_reloc_item_v2;
+ //
+ // the runtime relocation performs this adjustment:
+ // *(base + .target) += *(base + .sym) - (base + .sym)
+ //
+ // This works for both absolute addresses (IMAGE_REL_*_ADDR32/64,
+ // IMAGE_REL_I386_DIR32, where the memory location initially contains
+ // the address of the IAT slot, and for relative addresses (IMAGE_REL*_REL32),
+ // where the memory location originally contains the relative offset to the
+ // IAT slot.
+ //
+ // This requires the target address to be writable, either directly out of
+ // the image, or temporarily changed at runtime with VirtualProtect.
+ // Since this only operates on direct address values, it doesn't work for
+ // ARM/ARM64 relocations, other than the plain ADDR32/ADDR64 relocations.
+ switch (Config->Machine) {
+ case AMD64:
+ switch (Type) {
+ case IMAGE_REL_AMD64_ADDR64:
+ return 64;
+ case IMAGE_REL_AMD64_ADDR32:
+ case IMAGE_REL_AMD64_REL32:
+ case IMAGE_REL_AMD64_REL32_1:
+ case IMAGE_REL_AMD64_REL32_2:
+ case IMAGE_REL_AMD64_REL32_3:
+ case IMAGE_REL_AMD64_REL32_4:
+ case IMAGE_REL_AMD64_REL32_5:
+ return 32;
+ default:
+ return 0;
+ }
+ case I386:
+ switch (Type) {
+ case IMAGE_REL_I386_DIR32:
+ case IMAGE_REL_I386_REL32:
+ return 32;
+ default:
+ return 0;
+ }
+ case ARMNT:
+ switch (Type) {
+ case IMAGE_REL_ARM_ADDR32:
+ return 32;
+ default:
+ return 0;
+ }
+ case ARM64:
+ switch (Type) {
+ case IMAGE_REL_ARM64_ADDR64:
+ return 64;
+ case IMAGE_REL_ARM64_ADDR32:
+ return 32;
+ default:
+ return 0;
+ }
+ default:
+ llvm_unreachable("unknown machine type");
+ }
+}
+
+// MinGW specific.
+// Append information to the provided vector about all relocations that
+// need to be handled at runtime as runtime pseudo relocations (references
+// to a module local variable, which turned out to actually need to be
+// imported from another DLL).
+void SectionChunk::getRuntimePseudoRelocs(
+ std::vector<RuntimePseudoReloc> &Res) {
+ for (const coff_relocation &Rel : Relocs) {
+ auto *Target =
+ dyn_cast_or_null<Defined>(File->getSymbol(Rel.SymbolTableIndex));
+ if (!Target || !Target->IsRuntimePseudoReloc)
+ continue;
+ int SizeInBits = getRuntimePseudoRelocSize(Rel.Type);
+ if (SizeInBits == 0) {
+ error("unable to automatically import from " + Target->getName() +
+ " with relocation type " +
+ File->getCOFFObj()->getRelocationTypeName(Rel.Type) + " in " +
+ toString(File));
+ continue;
+ }
+ // SizeInBits is used to initialize the Flags field; currently no
+ // other flags are defined.
+ Res.emplace_back(
+ RuntimePseudoReloc(Target, this, Rel.VirtualAddress, SizeInBits));
+ }
+}
+
+bool SectionChunk::hasData() const {
+ return !(Header->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA);
+}
+
+uint32_t SectionChunk::getOutputCharacteristics() const {
+ return Header->Characteristics & (PermMask | TypeMask);
+}
+
+bool SectionChunk::isCOMDAT() const {
+ return Header->Characteristics & IMAGE_SCN_LNK_COMDAT;
+}
+
+void SectionChunk::printDiscardedMessage() const {
+ // Removed by dead-stripping. If it's removed by ICF, ICF already
+ // printed out the name, so don't repeat that here.
+ if (Sym && this == Repl)
+ message("Discarded " + Sym->getName());
+}
+
+StringRef SectionChunk::getDebugName() {
+ if (Sym)
+ return Sym->getName();
+ return "";
+}
+
+ArrayRef<uint8_t> SectionChunk::getContents() const {
+ ArrayRef<uint8_t> A;
+ File->getCOFFObj()->getSectionContents(Header, A);
+ return A;
+}
+
+void SectionChunk::replace(SectionChunk *Other) {
+ Alignment = std::max(Alignment, Other->Alignment);
+ Other->Repl = Repl;
+ Other->Live = false;
+}
+
+uint32_t SectionChunk::getSectionNumber() const {
+ DataRefImpl R;
+ R.p = reinterpret_cast<uintptr_t>(Header);
+ SectionRef S(R, File->getCOFFObj());
+ return S.getIndex() + 1;
+}
+
+CommonChunk::CommonChunk(const COFFSymbolRef S) : Sym(S) {
+ // Common symbols are aligned on natural boundaries up to 32 bytes.
+ // This is what MSVC link.exe does.
+ Alignment = std::min(uint64_t(32), PowerOf2Ceil(Sym.getValue()));
+}
+
+uint32_t CommonChunk::getOutputCharacteristics() const {
+ return IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ |
+ IMAGE_SCN_MEM_WRITE;
+}
+
+void StringChunk::writeTo(uint8_t *Buf) const {
+ memcpy(Buf + OutputSectionOff, Str.data(), Str.size());
+ Buf[OutputSectionOff + Str.size()] = '\0';
+}
+
+ImportThunkChunkX64::ImportThunkChunkX64(Defined *S) : ImpSymbol(S) {
+ // Intel Optimization Manual says that all branch targets
+ // should be 16-byte aligned. MSVC linker does this too.
+ Alignment = 16;
+}
+
+void ImportThunkChunkX64::writeTo(uint8_t *Buf) const {
+ memcpy(Buf + OutputSectionOff, ImportThunkX86, sizeof(ImportThunkX86));
+ // The first two bytes is a JMP instruction. Fill its operand.
+ write32le(Buf + OutputSectionOff + 2, ImpSymbol->getRVA() - RVA - getSize());
+}
+
+void ImportThunkChunkX86::getBaserels(std::vector<Baserel> *Res) {
+ Res->emplace_back(getRVA() + 2);
+}
+
+void ImportThunkChunkX86::writeTo(uint8_t *Buf) const {
+ memcpy(Buf + OutputSectionOff, ImportThunkX86, sizeof(ImportThunkX86));
+ // The first two bytes is a JMP instruction. Fill its operand.
+ write32le(Buf + OutputSectionOff + 2,
+ ImpSymbol->getRVA() + Config->ImageBase);
+}
+
+void ImportThunkChunkARM::getBaserels(std::vector<Baserel> *Res) {
+ Res->emplace_back(getRVA(), IMAGE_REL_BASED_ARM_MOV32T);
+}
+
+void ImportThunkChunkARM::writeTo(uint8_t *Buf) const {
+ memcpy(Buf + OutputSectionOff, ImportThunkARM, sizeof(ImportThunkARM));
+ // Fix mov.w and mov.t operands.
+ applyMOV32T(Buf + OutputSectionOff, ImpSymbol->getRVA() + Config->ImageBase);
+}
+
+void ImportThunkChunkARM64::writeTo(uint8_t *Buf) const {
+ int64_t Off = ImpSymbol->getRVA() & 0xfff;
+ memcpy(Buf + OutputSectionOff, ImportThunkARM64, sizeof(ImportThunkARM64));
+ applyArm64Addr(Buf + OutputSectionOff, ImpSymbol->getRVA(), RVA, 12);
+ applyArm64Ldr(Buf + OutputSectionOff + 4, Off);
+}
+
+// A Thumb2, PIC, non-interworking range extension thunk.
+const uint8_t ArmThunk[] = {
+ 0x40, 0xf2, 0x00, 0x0c, // P: movw ip,:lower16:S - (P + (L1-P) + 4)
+ 0xc0, 0xf2, 0x00, 0x0c, // movt ip,:upper16:S - (P + (L1-P) + 4)
+ 0xe7, 0x44, // L1: add pc, ip
+};
+
+size_t RangeExtensionThunkARM::getSize() const {
+ assert(Config->Machine == ARMNT);
+ return sizeof(ArmThunk);
+}
+
+void RangeExtensionThunkARM::writeTo(uint8_t *Buf) const {
+ assert(Config->Machine == ARMNT);
+ uint64_t Offset = Target->getRVA() - RVA - 12;
+ memcpy(Buf + OutputSectionOff, ArmThunk, sizeof(ArmThunk));
+ applyMOV32T(Buf + OutputSectionOff, uint32_t(Offset));
+}
+
+// A position independent ARM64 adrp+add thunk, with a maximum range of
+// +/- 4 GB, which is enough for any PE-COFF.
+const uint8_t Arm64Thunk[] = {
+ 0x10, 0x00, 0x00, 0x90, // adrp x16, Dest
+ 0x10, 0x02, 0x00, 0x91, // add x16, x16, :lo12:Dest
+ 0x00, 0x02, 0x1f, 0xd6, // br x16
+};
+
+size_t RangeExtensionThunkARM64::getSize() const {
+ assert(Config->Machine == ARM64);
+ return sizeof(Arm64Thunk);
+}
+
+void RangeExtensionThunkARM64::writeTo(uint8_t *Buf) const {
+ assert(Config->Machine == ARM64);
+ memcpy(Buf + OutputSectionOff, Arm64Thunk, sizeof(Arm64Thunk));
+ applyArm64Addr(Buf + OutputSectionOff + 0, Target->getRVA(), RVA, 12);
+ applyArm64Imm(Buf + OutputSectionOff + 4, Target->getRVA() & 0xfff, 0);
+}
+
+void LocalImportChunk::getBaserels(std::vector<Baserel> *Res) {
+ Res->emplace_back(getRVA());
+}
+
+size_t LocalImportChunk::getSize() const { return Config->Wordsize; }
+
+void LocalImportChunk::writeTo(uint8_t *Buf) const {
+ if (Config->is64()) {
+ write64le(Buf + OutputSectionOff, Sym->getRVA() + Config->ImageBase);
+ } else {
+ write32le(Buf + OutputSectionOff, Sym->getRVA() + Config->ImageBase);
+ }
+}
+
+void RVATableChunk::writeTo(uint8_t *Buf) const {
+ ulittle32_t *Begin = reinterpret_cast<ulittle32_t *>(Buf + OutputSectionOff);
+ size_t Cnt = 0;
+ for (const ChunkAndOffset &CO : Syms)
+ Begin[Cnt++] = CO.InputChunk->getRVA() + CO.Offset;
+ std::sort(Begin, Begin + Cnt);
+ assert(std::unique(Begin, Begin + Cnt) == Begin + Cnt &&
+ "RVA tables should be de-duplicated");
+}
+
+// MinGW specific, for the "automatic import of variables from DLLs" feature.
+size_t PseudoRelocTableChunk::getSize() const {
+ if (Relocs.empty())
+ return 0;
+ return 12 + 12 * Relocs.size();
+}
+
+// MinGW specific.
+void PseudoRelocTableChunk::writeTo(uint8_t *Buf) const {
+ if (Relocs.empty())
+ return;
+
+ ulittle32_t *Table = reinterpret_cast<ulittle32_t *>(Buf + OutputSectionOff);
+ // This is the list header, to signal the runtime pseudo relocation v2
+ // format.
+ Table[0] = 0;
+ Table[1] = 0;
+ Table[2] = 1;
+
+ size_t Idx = 3;
+ for (const RuntimePseudoReloc &RPR : Relocs) {
+ Table[Idx + 0] = RPR.Sym->getRVA();
+ Table[Idx + 1] = RPR.Target->getRVA() + RPR.TargetOffset;
+ Table[Idx + 2] = RPR.Flags;
+ Idx += 3;
+ }
+}
+
+// Windows-specific. This class represents a block in .reloc section.
+// The format is described here.
+//
+// On Windows, each DLL is linked against a fixed base address and
+// usually loaded to that address. However, if there's already another
+// DLL that overlaps, the loader has to relocate it. To do that, DLLs
+// contain .reloc sections which contain offsets that need to be fixed
+// up at runtime. If the loader finds that a DLL cannot be loaded to its
+// desired base address, it loads it to somewhere else, and add <actual
+// base address> - <desired base address> to each offset that is
+// specified by the .reloc section. In ELF terms, .reloc sections
+// contain relative relocations in REL format (as opposed to RELA.)
+//
+// This already significantly reduces the size of relocations compared
+// to ELF .rel.dyn, but Windows does more to reduce it (probably because
+// it was invented for PCs in the late '80s or early '90s.) Offsets in
+// .reloc are grouped by page where the page size is 12 bits, and
+// offsets sharing the same page address are stored consecutively to
+// represent them with less space. This is very similar to the page
+// table which is grouped by (multiple stages of) pages.
+//
+// For example, let's say we have 0x00030, 0x00500, 0x00700, 0x00A00,
+// 0x20004, and 0x20008 in a .reloc section for x64. The uppermost 4
+// bits have a type IMAGE_REL_BASED_DIR64 or 0xA. In the section, they
+// are represented like this:
+//
+// 0x00000 -- page address (4 bytes)
+// 16 -- size of this block (4 bytes)
+// 0xA030 -- entries (2 bytes each)
+// 0xA500
+// 0xA700
+// 0xAA00
+// 0x20000 -- page address (4 bytes)
+// 12 -- size of this block (4 bytes)
+// 0xA004 -- entries (2 bytes each)
+// 0xA008
+//
+// Usually we have a lot of relocations for each page, so the number of
+// bytes for one .reloc entry is close to 2 bytes on average.
+BaserelChunk::BaserelChunk(uint32_t Page, Baserel *Begin, Baserel *End) {
+ // Block header consists of 4 byte page RVA and 4 byte block size.
+ // Each entry is 2 byte. Last entry may be padding.
+ Data.resize(alignTo((End - Begin) * 2 + 8, 4));
+ uint8_t *P = Data.data();
+ write32le(P, Page);
+ write32le(P + 4, Data.size());
+ P += 8;
+ for (Baserel *I = Begin; I != End; ++I) {
+ write16le(P, (I->Type << 12) | (I->RVA - Page));
+ P += 2;
+ }
+}
+
+void BaserelChunk::writeTo(uint8_t *Buf) const {
+ memcpy(Buf + OutputSectionOff, Data.data(), Data.size());
+}
+
+uint8_t Baserel::getDefaultType() {
+ switch (Config->Machine) {
+ case AMD64:
+ case ARM64:
+ return IMAGE_REL_BASED_DIR64;
+ case I386:
+ case ARMNT:
+ return IMAGE_REL_BASED_HIGHLOW;
+ default:
+ llvm_unreachable("unknown machine type");
+ }
+}
+
+std::map<uint32_t, MergeChunk *> MergeChunk::Instances;
+
+MergeChunk::MergeChunk(uint32_t Alignment)
+ : Builder(StringTableBuilder::RAW, Alignment) {
+ this->Alignment = Alignment;
+}
+
+void MergeChunk::addSection(SectionChunk *C) {
+ auto *&MC = Instances[C->Alignment];
+ if (!MC)
+ MC = make<MergeChunk>(C->Alignment);
+ MC->Sections.push_back(C);
+}
+
+void MergeChunk::finalizeContents() {
+ if (!Finalized) {
+ for (SectionChunk *C : Sections)
+ if (C->Live)
+ Builder.add(toStringRef(C->getContents()));
+ Builder.finalize();
+ Finalized = true;
+ }
+
+ for (SectionChunk *C : Sections) {
+ if (!C->Live)
+ continue;
+ size_t Off = Builder.getOffset(toStringRef(C->getContents()));
+ C->setOutputSection(Out);
+ C->setRVA(RVA + Off);
+ C->OutputSectionOff = OutputSectionOff + Off;
+ }
+}
+
+uint32_t MergeChunk::getOutputCharacteristics() const {
+ return IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA;
+}
+
+size_t MergeChunk::getSize() const {
+ return Builder.getSize();
+}
+
+void MergeChunk::writeTo(uint8_t *Buf) const {
+ Builder.write(Buf + OutputSectionOff);
+}
+
+// MinGW specific.
+size_t AbsolutePointerChunk::getSize() const { return Config->Wordsize; }
+
+void AbsolutePointerChunk::writeTo(uint8_t *Buf) const {
+ if (Config->is64()) {
+ write64le(Buf + OutputSectionOff, Value);
+ } else {
+ write32le(Buf + OutputSectionOff, Value);
+ }
+}
+
+} // namespace coff
+} // namespace lld
diff --git a/contrib/llvm/tools/lld/COFF/Chunks.h b/contrib/llvm/tools/lld/COFF/Chunks.h
new file mode 100644
index 000000000000..e132fdf8adfa
--- /dev/null
+++ b/contrib/llvm/tools/lld/COFF/Chunks.h
@@ -0,0 +1,527 @@
+//===- Chunks.h -------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_CHUNKS_H
+#define LLD_COFF_CHUNKS_H
+
+#include "Config.h"
+#include "InputFiles.h"
+#include "lld/Common/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/iterator.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/MC/StringTableBuilder.h"
+#include "llvm/Object/COFF.h"
+#include <utility>
+#include <vector>
+
+namespace lld {
+namespace coff {
+
+using llvm::COFF::ImportDirectoryTableEntry;
+using llvm::object::COFFSymbolRef;
+using llvm::object::SectionRef;
+using llvm::object::coff_relocation;
+using llvm::object::coff_section;
+
+class Baserel;
+class Defined;
+class DefinedImportData;
+class DefinedRegular;
+class ObjFile;
+class OutputSection;
+class RuntimePseudoReloc;
+class Symbol;
+
+// Mask for permissions (discardable, writable, readable, executable, etc).
+const uint32_t PermMask = 0xFE000000;
+
+// Mask for section types (code, data, bss).
+const uint32_t TypeMask = 0x000000E0;
+
+// A Chunk represents a chunk of data that will occupy space in the
+// output (if the resolver chose that). It may or may not be backed by
+// a section of an input file. It could be linker-created data, or
+// doesn't even have actual data (if common or bss).
+class Chunk {
+public:
+ enum Kind { SectionKind, OtherKind };
+ Kind kind() const { return ChunkKind; }
+ virtual ~Chunk() = default;
+
+ // Returns the size of this chunk (even if this is a common or BSS.)
+ virtual size_t getSize() const = 0;
+
+ // Write this chunk to a mmap'ed file, assuming Buf is pointing to
+ // beginning of the file. Because this function may use RVA values
+ // of other chunks for relocations, you need to set them properly
+ // before calling this function.
+ virtual void writeTo(uint8_t *Buf) const {}
+
+ // Called by the writer once before assigning addresses and writing
+ // the output.
+ virtual void readRelocTargets() {}
+
+ // Called if restarting thunk addition.
+ virtual void resetRelocTargets() {}
+
+ // Called by the writer after an RVA is assigned, but before calling
+ // getSize().
+ virtual void finalizeContents() {}
+
+ // The writer sets and uses the addresses.
+ uint64_t getRVA() const { return RVA; }
+ void setRVA(uint64_t V) { RVA = V; }
+
+ // Returns true if this has non-zero data. BSS chunks return
+ // false. If false is returned, the space occupied by this chunk
+ // will be filled with zeros.
+ virtual bool hasData() const { return true; }
+
+ // Returns readable/writable/executable bits.
+ virtual uint32_t getOutputCharacteristics() const { return 0; }
+
+ // Returns the section name if this is a section chunk.
+ // It is illegal to call this function on non-section chunks.
+ virtual StringRef getSectionName() const {
+ llvm_unreachable("unimplemented getSectionName");
+ }
+
+ // An output section has pointers to chunks in the section, and each
+ // chunk has a back pointer to an output section.
+ void setOutputSection(OutputSection *O) { Out = O; }
+ OutputSection *getOutputSection() const { return Out; }
+
+ // Windows-specific.
+ // Collect all locations that contain absolute addresses for base relocations.
+ virtual void getBaserels(std::vector<Baserel> *Res) {}
+
+ // Returns a human-readable name of this chunk. Chunks are unnamed chunks of
+ // bytes, so this is used only for logging or debugging.
+ virtual StringRef getDebugName() { return ""; }
+
+ // The alignment of this chunk. The writer uses the value.
+ uint32_t Alignment = 1;
+
+protected:
+ Chunk(Kind K = OtherKind) : ChunkKind(K) {}
+ const Kind ChunkKind;
+
+ // The RVA of this chunk in the output. The writer sets a value.
+ uint64_t RVA = 0;
+
+ // The output section for this chunk.
+ OutputSection *Out = nullptr;
+
+public:
+ // The offset from beginning of the output section. The writer sets a value.
+ uint64_t OutputSectionOff = 0;
+
+ // Whether this section needs to be kept distinct from other sections during
+ // ICF. This is set by the driver using address-significance tables.
+ bool KeepUnique = false;
+};
+
+// A chunk corresponding a section of an input file.
+class SectionChunk final : public Chunk {
+ // Identical COMDAT Folding feature accesses section internal data.
+ friend class ICF;
+
+public:
+ class symbol_iterator : public llvm::iterator_adaptor_base<
+ symbol_iterator, const coff_relocation *,
+ std::random_access_iterator_tag, Symbol *> {
+ friend SectionChunk;
+
+ ObjFile *File;
+
+ symbol_iterator(ObjFile *File, const coff_relocation *I)
+ : symbol_iterator::iterator_adaptor_base(I), File(File) {}
+
+ public:
+ symbol_iterator() = default;
+
+ Symbol *operator*() const { return File->getSymbol(I->SymbolTableIndex); }
+ };
+
+ SectionChunk(ObjFile *File, const coff_section *Header);
+ static bool classof(const Chunk *C) { return C->kind() == SectionKind; }
+ void readRelocTargets() override;
+ void resetRelocTargets() override;
+ size_t getSize() const override { return Header->SizeOfRawData; }
+ ArrayRef<uint8_t> getContents() const;
+ void writeTo(uint8_t *Buf) const override;
+ bool hasData() const override;
+ uint32_t getOutputCharacteristics() const override;
+ StringRef getSectionName() const override { return SectionName; }
+ void getBaserels(std::vector<Baserel> *Res) override;
+ bool isCOMDAT() const;
+ void applyRelX64(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S,
+ uint64_t P) const;
+ void applyRelX86(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S,
+ uint64_t P) const;
+ void applyRelARM(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S,
+ uint64_t P) const;
+ void applyRelARM64(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S,
+ uint64_t P) const;
+
+ void getRuntimePseudoRelocs(std::vector<RuntimePseudoReloc> &Res);
+
+ // Called if the garbage collector decides to not include this chunk
+ // in a final output. It's supposed to print out a log message to stdout.
+ void printDiscardedMessage() const;
+
+ // Adds COMDAT associative sections to this COMDAT section. A chunk
+ // and its children are treated as a group by the garbage collector.
+ void addAssociative(SectionChunk *Child);
+
+ StringRef getDebugName() override;
+
+ // True if this is a codeview debug info chunk. These will not be laid out in
+ // the image. Instead they will end up in the PDB, if one is requested.
+ bool isCodeView() const {
+ return SectionName == ".debug" || SectionName.startswith(".debug$");
+ }
+
+ // True if this is a DWARF debug info or exception handling chunk.
+ bool isDWARF() const {
+ return SectionName.startswith(".debug_") || SectionName == ".eh_frame";
+ }
+
+ // Allow iteration over the bodies of this chunk's relocated symbols.
+ llvm::iterator_range<symbol_iterator> symbols() const {
+ return llvm::make_range(symbol_iterator(File, Relocs.begin()),
+ symbol_iterator(File, Relocs.end()));
+ }
+
+ // Allow iteration over the associated child chunks for this section.
+ ArrayRef<SectionChunk *> children() const { return AssocChildren; }
+
+ // The section ID this chunk belongs to in its Obj.
+ uint32_t getSectionNumber() const;
+
+ // A pointer pointing to a replacement for this chunk.
+ // Initially it points to "this" object. If this chunk is merged
+ // with other chunk by ICF, it points to another chunk,
+ // and this chunk is considered as dead.
+ SectionChunk *Repl;
+
+ // The CRC of the contents as described in the COFF spec 4.5.5.
+ // Auxiliary Format 5: Section Definitions. Used for ICF.
+ uint32_t Checksum = 0;
+
+ const coff_section *Header;
+
+ // The file that this chunk was created from.
+ ObjFile *File;
+
+ // The COMDAT leader symbol if this is a COMDAT chunk.
+ DefinedRegular *Sym = nullptr;
+
+ ArrayRef<coff_relocation> Relocs;
+
+ // Used by the garbage collector.
+ bool Live;
+
+ // When inserting a thunk, we need to adjust a relocation to point to
+ // the thunk instead of the actual original target Symbol.
+ std::vector<Symbol *> RelocTargets;
+
+private:
+ StringRef SectionName;
+ std::vector<SectionChunk *> AssocChildren;
+
+ // Used for ICF (Identical COMDAT Folding)
+ void replace(SectionChunk *Other);
+ uint32_t Class[2] = {0, 0};
+};
+
+// This class is used to implement an lld-specific feature (not implemented in
+// MSVC) that minimizes the output size by finding string literals sharing tail
+// parts and merging them.
+//
+// If string tail merging is enabled and a section is identified as containing a
+// string literal, it is added to a MergeChunk with an appropriate alignment.
+// The MergeChunk then tail merges the strings using the StringTableBuilder
+// class and assigns RVAs and section offsets to each of the member chunks based
+// on the offsets assigned by the StringTableBuilder.
+class MergeChunk : public Chunk {
+public:
+ MergeChunk(uint32_t Alignment);
+ static void addSection(SectionChunk *C);
+ void finalizeContents() override;
+
+ uint32_t getOutputCharacteristics() const override;
+ StringRef getSectionName() const override { return ".rdata"; }
+ size_t getSize() const override;
+ void writeTo(uint8_t *Buf) const override;
+
+ static std::map<uint32_t, MergeChunk *> Instances;
+ std::vector<SectionChunk *> Sections;
+
+private:
+ llvm::StringTableBuilder Builder;
+ bool Finalized = false;
+};
+
+// A chunk for common symbols. Common chunks don't have actual data.
+class CommonChunk : public Chunk {
+public:
+ CommonChunk(const COFFSymbolRef Sym);
+ size_t getSize() const override { return Sym.getValue(); }
+ bool hasData() const override { return false; }
+ uint32_t getOutputCharacteristics() const override;
+ StringRef getSectionName() const override { return ".bss"; }
+
+private:
+ const COFFSymbolRef Sym;
+};
+
+// A chunk for linker-created strings.
+class StringChunk : public Chunk {
+public:
+ explicit StringChunk(StringRef S) : Str(S) {}
+ size_t getSize() const override { return Str.size() + 1; }
+ void writeTo(uint8_t *Buf) const override;
+
+private:
+ StringRef Str;
+};
+
+static const uint8_t ImportThunkX86[] = {
+ 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // JMP *0x0
+};
+
+static const uint8_t ImportThunkARM[] = {
+ 0x40, 0xf2, 0x00, 0x0c, // mov.w ip, #0
+ 0xc0, 0xf2, 0x00, 0x0c, // mov.t ip, #0
+ 0xdc, 0xf8, 0x00, 0xf0, // ldr.w pc, [ip]
+};
+
+static const uint8_t ImportThunkARM64[] = {
+ 0x10, 0x00, 0x00, 0x90, // adrp x16, #0
+ 0x10, 0x02, 0x40, 0xf9, // ldr x16, [x16]
+ 0x00, 0x02, 0x1f, 0xd6, // br x16
+};
+
+// Windows-specific.
+// A chunk for DLL import jump table entry. In a final output, its
+// contents will be a JMP instruction to some __imp_ symbol.
+class ImportThunkChunkX64 : public Chunk {
+public:
+ explicit ImportThunkChunkX64(Defined *S);
+ size_t getSize() const override { return sizeof(ImportThunkX86); }
+ void writeTo(uint8_t *Buf) const override;
+
+private:
+ Defined *ImpSymbol;
+};
+
+class ImportThunkChunkX86 : public Chunk {
+public:
+ explicit ImportThunkChunkX86(Defined *S) : ImpSymbol(S) {}
+ size_t getSize() const override { return sizeof(ImportThunkX86); }
+ void getBaserels(std::vector<Baserel> *Res) override;
+ void writeTo(uint8_t *Buf) const override;
+
+private:
+ Defined *ImpSymbol;
+};
+
+class ImportThunkChunkARM : public Chunk {
+public:
+ explicit ImportThunkChunkARM(Defined *S) : ImpSymbol(S) {}
+ size_t getSize() const override { return sizeof(ImportThunkARM); }
+ void getBaserels(std::vector<Baserel> *Res) override;
+ void writeTo(uint8_t *Buf) const override;
+
+private:
+ Defined *ImpSymbol;
+};
+
+class ImportThunkChunkARM64 : public Chunk {
+public:
+ explicit ImportThunkChunkARM64(Defined *S) : ImpSymbol(S) {}
+ size_t getSize() const override { return sizeof(ImportThunkARM64); }
+ void writeTo(uint8_t *Buf) const override;
+
+private:
+ Defined *ImpSymbol;
+};
+
+class RangeExtensionThunkARM : public Chunk {
+public:
+ explicit RangeExtensionThunkARM(Defined *T) : Target(T) {}
+ size_t getSize() const override;
+ void writeTo(uint8_t *Buf) const override;
+
+ Defined *Target;
+};
+
+class RangeExtensionThunkARM64 : public Chunk {
+public:
+ explicit RangeExtensionThunkARM64(Defined *T) : Target(T) {}
+ size_t getSize() const override;
+ void writeTo(uint8_t *Buf) const override;
+
+ Defined *Target;
+};
+
+// Windows-specific.
+// See comments for DefinedLocalImport class.
+class LocalImportChunk : public Chunk {
+public:
+ explicit LocalImportChunk(Defined *S) : Sym(S) {
+ Alignment = Config->Wordsize;
+ }
+ size_t getSize() const override;
+ void getBaserels(std::vector<Baserel> *Res) override;
+ void writeTo(uint8_t *Buf) const override;
+
+private:
+ Defined *Sym;
+};
+
+// Duplicate RVAs are not allowed in RVA tables, so unique symbols by chunk and
+// offset into the chunk. Order does not matter as the RVA table will be sorted
+// later.
+struct ChunkAndOffset {
+ Chunk *InputChunk;
+ uint32_t Offset;
+
+ struct DenseMapInfo {
+ static ChunkAndOffset getEmptyKey() {
+ return {llvm::DenseMapInfo<Chunk *>::getEmptyKey(), 0};
+ }
+ static ChunkAndOffset getTombstoneKey() {
+ return {llvm::DenseMapInfo<Chunk *>::getTombstoneKey(), 0};
+ }
+ static unsigned getHashValue(const ChunkAndOffset &CO) {
+ return llvm::DenseMapInfo<std::pair<Chunk *, uint32_t>>::getHashValue(
+ {CO.InputChunk, CO.Offset});
+ }
+ static bool isEqual(const ChunkAndOffset &LHS, const ChunkAndOffset &RHS) {
+ return LHS.InputChunk == RHS.InputChunk && LHS.Offset == RHS.Offset;
+ }
+ };
+};
+
+using SymbolRVASet = llvm::DenseSet<ChunkAndOffset>;
+
+// Table which contains symbol RVAs. Used for /safeseh and /guard:cf.
+class RVATableChunk : public Chunk {
+public:
+ explicit RVATableChunk(SymbolRVASet S) : Syms(std::move(S)) {}
+ size_t getSize() const override { return Syms.size() * 4; }
+ void writeTo(uint8_t *Buf) const override;
+
+private:
+ SymbolRVASet Syms;
+};
+
+// Windows-specific.
+// This class represents a block in .reloc section.
+// See the PE/COFF spec 5.6 for details.
+class BaserelChunk : public Chunk {
+public:
+ BaserelChunk(uint32_t Page, Baserel *Begin, Baserel *End);
+ size_t getSize() const override { return Data.size(); }
+ void writeTo(uint8_t *Buf) const override;
+
+private:
+ std::vector<uint8_t> Data;
+};
+
+class Baserel {
+public:
+ Baserel(uint32_t V, uint8_t Ty) : RVA(V), Type(Ty) {}
+ explicit Baserel(uint32_t V) : Baserel(V, getDefaultType()) {}
+ uint8_t getDefaultType();
+
+ uint32_t RVA;
+ uint8_t Type;
+};
+
+// This is a placeholder Chunk, to allow attaching a DefinedSynthetic to a
+// specific place in a section, without any data. This is used for the MinGW
+// specific symbol __RUNTIME_PSEUDO_RELOC_LIST_END__, even though the concept
+// of an empty chunk isn't MinGW specific.
+class EmptyChunk : public Chunk {
+public:
+ EmptyChunk() {}
+ size_t getSize() const override { return 0; }
+ void writeTo(uint8_t *Buf) const override {}
+};
+
+// MinGW specific, for the "automatic import of variables from DLLs" feature.
+// This provides the table of runtime pseudo relocations, for variable
+// references that turned out to need to be imported from a DLL even though
+// the reference didn't use the dllimport attribute. The MinGW runtime will
+// process this table after loading, before handling control over to user
+// code.
+class PseudoRelocTableChunk : public Chunk {
+public:
+ PseudoRelocTableChunk(std::vector<RuntimePseudoReloc> &Relocs)
+ : Relocs(std::move(Relocs)) {
+ Alignment = 4;
+ }
+ size_t getSize() const override;
+ void writeTo(uint8_t *Buf) const override;
+
+private:
+ std::vector<RuntimePseudoReloc> Relocs;
+};
+
+// MinGW specific; information about one individual location in the image
+// that needs to be fixed up at runtime after loading. This represents
+// one individual element in the PseudoRelocTableChunk table.
+class RuntimePseudoReloc {
+public:
+ RuntimePseudoReloc(Defined *Sym, SectionChunk *Target, uint32_t TargetOffset,
+ int Flags)
+ : Sym(Sym), Target(Target), TargetOffset(TargetOffset), Flags(Flags) {}
+
+ Defined *Sym;
+ SectionChunk *Target;
+ uint32_t TargetOffset;
+ // The Flags field contains the size of the relocation, in bits. No other
+ // flags are currently defined.
+ int Flags;
+};
+
+// MinGW specific. A Chunk that contains one pointer-sized absolute value.
+class AbsolutePointerChunk : public Chunk {
+public:
+ AbsolutePointerChunk(uint64_t Value) : Value(Value) {
+ Alignment = getSize();
+ }
+ size_t getSize() const override;
+ void writeTo(uint8_t *Buf) const override;
+
+private:
+ uint64_t Value;
+};
+
+void applyMOV32T(uint8_t *Off, uint32_t V);
+void applyBranch24T(uint8_t *Off, int32_t V);
+
+void applyArm64Addr(uint8_t *Off, uint64_t S, uint64_t P, int Shift);
+void applyArm64Imm(uint8_t *Off, uint64_t Imm, uint32_t RangeLimit);
+void applyArm64Branch26(uint8_t *Off, int64_t V);
+
+} // namespace coff
+} // namespace lld
+
+namespace llvm {
+template <>
+struct DenseMapInfo<lld::coff::ChunkAndOffset>
+ : lld::coff::ChunkAndOffset::DenseMapInfo {};
+}
+
+#endif
diff --git a/contrib/llvm/tools/lld/COFF/Config.h b/contrib/llvm/tools/lld/COFF/Config.h
new file mode 100644
index 000000000000..8915b6a3bdd8
--- /dev/null
+++ b/contrib/llvm/tools/lld/COFF/Config.h
@@ -0,0 +1,212 @@
+//===- Config.h -------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_CONFIG_H
+#define LLD_COFF_CONFIG_H
+
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/CachePruning.h"
+#include <cstdint>
+#include <map>
+#include <set>
+#include <string>
+
+namespace lld {
+namespace coff {
+
+using llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN;
+using llvm::COFF::WindowsSubsystem;
+using llvm::StringRef;
+class DefinedAbsolute;
+class DefinedRelative;
+class StringChunk;
+class Symbol;
+
+// Short aliases.
+static const auto AMD64 = llvm::COFF::IMAGE_FILE_MACHINE_AMD64;
+static const auto ARM64 = llvm::COFF::IMAGE_FILE_MACHINE_ARM64;
+static const auto ARMNT = llvm::COFF::IMAGE_FILE_MACHINE_ARMNT;
+static const auto I386 = llvm::COFF::IMAGE_FILE_MACHINE_I386;
+
+// Represents an /export option.
+struct Export {
+ StringRef Name; // N in /export:N or /export:E=N
+ StringRef ExtName; // E in /export:E=N
+ Symbol *Sym = nullptr;
+ uint16_t Ordinal = 0;
+ bool Noname = false;
+ bool Data = false;
+ bool Private = false;
+ bool Constant = false;
+
+ // If an export is a form of /export:foo=dllname.bar, that means
+ // that foo should be exported as an alias to bar in the DLL.
+ // ForwardTo is set to "dllname.bar" part. Usually empty.
+ StringRef ForwardTo;
+ StringChunk *ForwardChunk = nullptr;
+
+ // True if this /export option was in .drectves section.
+ bool Directives = false;
+ StringRef SymbolName;
+ StringRef ExportName; // Name in DLL
+
+ bool operator==(const Export &E) {
+ return (Name == E.Name && ExtName == E.ExtName &&
+ Ordinal == E.Ordinal && Noname == E.Noname &&
+ Data == E.Data && Private == E.Private);
+ }
+};
+
+enum class DebugType {
+ None = 0x0,
+ CV = 0x1, /// CodeView
+ PData = 0x2, /// Procedure Data
+ Fixup = 0x4, /// Relocation Table
+};
+
+enum class GuardCFLevel {
+ Off,
+ NoLongJmp, // Emit gfids but no longjmp tables
+ Full, // Enable all protections.
+};
+
+// Global configuration.
+struct Configuration {
+ enum ManifestKind { SideBySide, Embed, No };
+ bool is64() { return Machine == AMD64 || Machine == ARM64; }
+
+ llvm::COFF::MachineTypes Machine = IMAGE_FILE_MACHINE_UNKNOWN;
+ size_t Wordsize;
+ bool Verbose = false;
+ WindowsSubsystem Subsystem = llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN;
+ Symbol *Entry = nullptr;
+ bool NoEntry = false;
+ std::string OutputFile;
+ std::string ImportName;
+ bool DoGC = true;
+ bool DoICF = true;
+ bool TailMerge;
+ bool Relocatable = true;
+ bool ForceMultiple = false;
+ bool ForceUnresolved = false;
+ bool Debug = false;
+ bool DebugDwarf = false;
+ bool DebugGHashes = false;
+ bool DebugSymtab = false;
+ bool ShowTiming = false;
+ unsigned DebugTypes = static_cast<unsigned>(DebugType::None);
+ std::vector<std::string> NatvisFiles;
+ llvm::SmallString<128> PDBAltPath;
+ llvm::SmallString<128> PDBPath;
+ llvm::SmallString<128> PDBSourcePath;
+ std::vector<llvm::StringRef> Argv;
+
+ // Symbols in this set are considered as live by the garbage collector.
+ std::vector<Symbol *> GCRoot;
+
+ std::set<StringRef> NoDefaultLibs;
+ bool NoDefaultLibAll = false;
+
+ // True if we are creating a DLL.
+ bool DLL = false;
+ StringRef Implib;
+ std::vector<Export> Exports;
+ std::set<std::string> DelayLoads;
+ std::map<std::string, int> DLLOrder;
+ Symbol *DelayLoadHelper = nullptr;
+
+ bool SaveTemps = false;
+
+ // /guard:cf
+ GuardCFLevel GuardCF = GuardCFLevel::Off;
+
+ // Used for SafeSEH.
+ Symbol *SEHTable = nullptr;
+ Symbol *SEHCount = nullptr;
+
+ // Used for /opt:lldlto=N
+ unsigned LTOO = 2;
+
+ // Used for /opt:lldltojobs=N
+ unsigned ThinLTOJobs = 0;
+ // Used for /opt:lldltopartitions=N
+ unsigned LTOPartitions = 1;
+
+ // Used for /opt:lldltocache=path
+ StringRef LTOCache;
+ // Used for /opt:lldltocachepolicy=policy
+ llvm::CachePruningPolicy LTOCachePolicy;
+
+ // Used for /merge:from=to (e.g. /merge:.rdata=.text)
+ std::map<StringRef, StringRef> Merge;
+
+ // Used for /section=.name,{DEKPRSW} to set section attributes.
+ std::map<StringRef, uint32_t> Section;
+
+ // Options for manifest files.
+ ManifestKind Manifest = No;
+ int ManifestID = 1;
+ StringRef ManifestDependency;
+ bool ManifestUAC = true;
+ std::vector<std::string> ManifestInput;
+ StringRef ManifestLevel = "'asInvoker'";
+ StringRef ManifestUIAccess = "'false'";
+ StringRef ManifestFile;
+
+ // Used for /aligncomm.
+ std::map<std::string, int> AlignComm;
+
+ // Used for /failifmismatch.
+ std::map<StringRef, StringRef> MustMatch;
+
+ // Used for /alternatename.
+ std::map<StringRef, StringRef> AlternateNames;
+
+ // Used for /order.
+ llvm::StringMap<int> Order;
+
+ // Used for /lldmap.
+ std::string MapFile;
+
+ uint64_t ImageBase = -1;
+ uint64_t StackReserve = 1024 * 1024;
+ uint64_t StackCommit = 4096;
+ uint64_t HeapReserve = 1024 * 1024;
+ uint64_t HeapCommit = 4096;
+ uint32_t MajorImageVersion = 0;
+ uint32_t MinorImageVersion = 0;
+ uint32_t MajorOSVersion = 6;
+ uint32_t MinorOSVersion = 0;
+ uint32_t Timestamp = 0;
+ bool DynamicBase = true;
+ bool AllowBind = true;
+ bool NxCompat = true;
+ bool AllowIsolation = true;
+ bool TerminalServerAware = true;
+ bool LargeAddressAware = false;
+ bool HighEntropyVA = false;
+ bool AppContainer = false;
+ bool MinGW = false;
+ bool WarnMissingOrderSymbol = true;
+ bool WarnLocallyDefinedImported = true;
+ bool WarnDebugInfoUnusable = true;
+ bool Incremental = true;
+ bool IntegrityCheck = false;
+ bool KillAt = false;
+ bool Repro = false;
+};
+
+extern Configuration *Config;
+
+} // namespace coff
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/COFF/DLL.cpp b/contrib/llvm/tools/lld/COFF/DLL.cpp
new file mode 100644
index 000000000000..c06027d3e5c3
--- /dev/null
+++ b/contrib/llvm/tools/lld/COFF/DLL.cpp
@@ -0,0 +1,645 @@
+//===- DLL.cpp ------------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines various types of chunks for the DLL import or export
+// descriptor tables. They are inherently Windows-specific.
+// You need to read Microsoft PE/COFF spec to understand details
+// about the data structures.
+//
+// If you are not particularly interested in linking against Windows
+// DLL, you can skip this file, and you should still be able to
+// understand the rest of the linker.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DLL.h"
+#include "Chunks.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Path.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+using namespace llvm::COFF;
+
+namespace lld {
+namespace coff {
+namespace {
+
+// Import table
+
+// A chunk for the import descriptor table.
+class HintNameChunk : public Chunk {
+public:
+ HintNameChunk(StringRef N, uint16_t H) : Name(N), Hint(H) {}
+
+ size_t getSize() const override {
+ // Starts with 2 byte Hint field, followed by a null-terminated string,
+ // ends with 0 or 1 byte padding.
+ return alignTo(Name.size() + 3, 2);
+ }
+
+ void writeTo(uint8_t *Buf) const override {
+ memset(Buf + OutputSectionOff, 0, getSize());
+ write16le(Buf + OutputSectionOff, Hint);
+ memcpy(Buf + OutputSectionOff + 2, Name.data(), Name.size());
+ }
+
+private:
+ StringRef Name;
+ uint16_t Hint;
+};
+
+// A chunk for the import descriptor table.
+class LookupChunk : public Chunk {
+public:
+ explicit LookupChunk(Chunk *C) : HintName(C) { Alignment = Config->Wordsize; }
+ size_t getSize() const override { return Config->Wordsize; }
+
+ void writeTo(uint8_t *Buf) const override {
+ if (Config->is64())
+ write64le(Buf + OutputSectionOff, HintName->getRVA());
+ else
+ write32le(Buf + OutputSectionOff, HintName->getRVA());
+ }
+
+ Chunk *HintName;
+};
+
+// A chunk for the import descriptor table.
+// This chunk represent import-by-ordinal symbols.
+// See Microsoft PE/COFF spec 7.1. Import Header for details.
+class OrdinalOnlyChunk : public Chunk {
+public:
+ explicit OrdinalOnlyChunk(uint16_t V) : Ordinal(V) {
+ Alignment = Config->Wordsize;
+ }
+ size_t getSize() const override { return Config->Wordsize; }
+
+ void writeTo(uint8_t *Buf) const override {
+ // An import-by-ordinal slot has MSB 1 to indicate that
+ // this is import-by-ordinal (and not import-by-name).
+ if (Config->is64()) {
+ write64le(Buf + OutputSectionOff, (1ULL << 63) | Ordinal);
+ } else {
+ write32le(Buf + OutputSectionOff, (1ULL << 31) | Ordinal);
+ }
+ }
+
+ uint16_t Ordinal;
+};
+
+// A chunk for the import descriptor table.
+class ImportDirectoryChunk : public Chunk {
+public:
+ explicit ImportDirectoryChunk(Chunk *N) : DLLName(N) {}
+ size_t getSize() const override { return sizeof(ImportDirectoryTableEntry); }
+
+ void writeTo(uint8_t *Buf) const override {
+ memset(Buf + OutputSectionOff, 0, getSize());
+
+ auto *E = (coff_import_directory_table_entry *)(Buf + OutputSectionOff);
+ E->ImportLookupTableRVA = LookupTab->getRVA();
+ E->NameRVA = DLLName->getRVA();
+ E->ImportAddressTableRVA = AddressTab->getRVA();
+ }
+
+ Chunk *DLLName;
+ Chunk *LookupTab;
+ Chunk *AddressTab;
+};
+
+// A chunk representing null terminator in the import table.
+// Contents of this chunk is always null bytes.
+class NullChunk : public Chunk {
+public:
+ explicit NullChunk(size_t N) : Size(N) {}
+ bool hasData() const override { return false; }
+ size_t getSize() const override { return Size; }
+
+ void writeTo(uint8_t *Buf) const override {
+ memset(Buf + OutputSectionOff, 0, Size);
+ }
+
+private:
+ size_t Size;
+};
+
+static std::vector<std::vector<DefinedImportData *>>
+binImports(const std::vector<DefinedImportData *> &Imports) {
+ // Group DLL-imported symbols by DLL name because that's how
+ // symbols are layed out in the import descriptor table.
+ auto Less = [](const std::string &A, const std::string &B) {
+ return Config->DLLOrder[A] < Config->DLLOrder[B];
+ };
+ std::map<std::string, std::vector<DefinedImportData *>,
+ bool(*)(const std::string &, const std::string &)> M(Less);
+ for (DefinedImportData *Sym : Imports)
+ M[Sym->getDLLName().lower()].push_back(Sym);
+
+ std::vector<std::vector<DefinedImportData *>> V;
+ for (auto &KV : M) {
+ // Sort symbols by name for each group.
+ std::vector<DefinedImportData *> &Syms = KV.second;
+ std::sort(Syms.begin(), Syms.end(),
+ [](DefinedImportData *A, DefinedImportData *B) {
+ return A->getName() < B->getName();
+ });
+ V.push_back(std::move(Syms));
+ }
+ return V;
+}
+
+// Export table
+// See Microsoft PE/COFF spec 4.3 for details.
+
+// A chunk for the delay import descriptor table etnry.
+class DelayDirectoryChunk : public Chunk {
+public:
+ explicit DelayDirectoryChunk(Chunk *N) : DLLName(N) {}
+
+ size_t getSize() const override {
+ return sizeof(delay_import_directory_table_entry);
+ }
+
+ void writeTo(uint8_t *Buf) const override {
+ memset(Buf + OutputSectionOff, 0, getSize());
+
+ auto *E = (delay_import_directory_table_entry *)(Buf + OutputSectionOff);
+ E->Attributes = 1;
+ E->Name = DLLName->getRVA();
+ E->ModuleHandle = ModuleHandle->getRVA();
+ E->DelayImportAddressTable = AddressTab->getRVA();
+ E->DelayImportNameTable = NameTab->getRVA();
+ }
+
+ Chunk *DLLName;
+ Chunk *ModuleHandle;
+ Chunk *AddressTab;
+ Chunk *NameTab;
+};
+
+// Initial contents for delay-loaded functions.
+// This code calls __delayLoadHelper2 function to resolve a symbol
+// and then overwrites its jump table slot with the result
+// for subsequent function calls.
+static const uint8_t ThunkX64[] = {
+ 0x51, // push rcx
+ 0x52, // push rdx
+ 0x41, 0x50, // push r8
+ 0x41, 0x51, // push r9
+ 0x48, 0x83, 0xEC, 0x48, // sub rsp, 48h
+ 0x66, 0x0F, 0x7F, 0x04, 0x24, // movdqa xmmword ptr [rsp], xmm0
+ 0x66, 0x0F, 0x7F, 0x4C, 0x24, 0x10, // movdqa xmmword ptr [rsp+10h], xmm1
+ 0x66, 0x0F, 0x7F, 0x54, 0x24, 0x20, // movdqa xmmword ptr [rsp+20h], xmm2
+ 0x66, 0x0F, 0x7F, 0x5C, 0x24, 0x30, // movdqa xmmword ptr [rsp+30h], xmm3
+ 0x48, 0x8D, 0x15, 0, 0, 0, 0, // lea rdx, [__imp_<FUNCNAME>]
+ 0x48, 0x8D, 0x0D, 0, 0, 0, 0, // lea rcx, [___DELAY_IMPORT_...]
+ 0xE8, 0, 0, 0, 0, // call __delayLoadHelper2
+ 0x66, 0x0F, 0x6F, 0x04, 0x24, // movdqa xmm0, xmmword ptr [rsp]
+ 0x66, 0x0F, 0x6F, 0x4C, 0x24, 0x10, // movdqa xmm1, xmmword ptr [rsp+10h]
+ 0x66, 0x0F, 0x6F, 0x54, 0x24, 0x20, // movdqa xmm2, xmmword ptr [rsp+20h]
+ 0x66, 0x0F, 0x6F, 0x5C, 0x24, 0x30, // movdqa xmm3, xmmword ptr [rsp+30h]
+ 0x48, 0x83, 0xC4, 0x48, // add rsp, 48h
+ 0x41, 0x59, // pop r9
+ 0x41, 0x58, // pop r8
+ 0x5A, // pop rdx
+ 0x59, // pop rcx
+ 0xFF, 0xE0, // jmp rax
+};
+
+static const uint8_t ThunkX86[] = {
+ 0x51, // push ecx
+ 0x52, // push edx
+ 0x68, 0, 0, 0, 0, // push offset ___imp__<FUNCNAME>
+ 0x68, 0, 0, 0, 0, // push offset ___DELAY_IMPORT_DESCRIPTOR_<DLLNAME>_dll
+ 0xE8, 0, 0, 0, 0, // call ___delayLoadHelper2@8
+ 0x5A, // pop edx
+ 0x59, // pop ecx
+ 0xFF, 0xE0, // jmp eax
+};
+
+static const uint8_t ThunkARM[] = {
+ 0x40, 0xf2, 0x00, 0x0c, // mov.w ip, #0 __imp_<FUNCNAME>
+ 0xc0, 0xf2, 0x00, 0x0c, // mov.t ip, #0 __imp_<FUNCNAME>
+ 0x2d, 0xe9, 0x0f, 0x48, // push.w {r0, r1, r2, r3, r11, lr}
+ 0x0d, 0xf2, 0x10, 0x0b, // addw r11, sp, #16
+ 0x2d, 0xed, 0x10, 0x0b, // vpush {d0, d1, d2, d3, d4, d5, d6, d7}
+ 0x61, 0x46, // mov r1, ip
+ 0x40, 0xf2, 0x00, 0x00, // mov.w r0, #0 DELAY_IMPORT_DESCRIPTOR
+ 0xc0, 0xf2, 0x00, 0x00, // mov.t r0, #0 DELAY_IMPORT_DESCRIPTOR
+ 0x00, 0xf0, 0x00, 0xd0, // bl #0 __delayLoadHelper2
+ 0x84, 0x46, // mov ip, r0
+ 0xbd, 0xec, 0x10, 0x0b, // vpop {d0, d1, d2, d3, d4, d5, d6, d7}
+ 0xbd, 0xe8, 0x0f, 0x48, // pop.w {r0, r1, r2, r3, r11, lr}
+ 0x60, 0x47, // bx ip
+};
+
+static const uint8_t ThunkARM64[] = {
+ 0x11, 0x00, 0x00, 0x90, // adrp x17, #0 __imp_<FUNCNAME>
+ 0x31, 0x02, 0x00, 0x91, // add x17, x17, #0 :lo12:__imp_<FUNCNAME>
+ 0xfd, 0x7b, 0xb3, 0xa9, // stp x29, x30, [sp, #-208]!
+ 0xfd, 0x03, 0x00, 0x91, // mov x29, sp
+ 0xe0, 0x07, 0x01, 0xa9, // stp x0, x1, [sp, #16]
+ 0xe2, 0x0f, 0x02, 0xa9, // stp x2, x3, [sp, #32]
+ 0xe4, 0x17, 0x03, 0xa9, // stp x4, x5, [sp, #48]
+ 0xe6, 0x1f, 0x04, 0xa9, // stp x6, x7, [sp, #64]
+ 0xe0, 0x87, 0x02, 0xad, // stp q0, q1, [sp, #80]
+ 0xe2, 0x8f, 0x03, 0xad, // stp q2, q3, [sp, #112]
+ 0xe4, 0x97, 0x04, 0xad, // stp q4, q5, [sp, #144]
+ 0xe6, 0x9f, 0x05, 0xad, // stp q6, q7, [sp, #176]
+ 0xe1, 0x03, 0x11, 0xaa, // mov x1, x17
+ 0x00, 0x00, 0x00, 0x90, // adrp x0, #0 DELAY_IMPORT_DESCRIPTOR
+ 0x00, 0x00, 0x00, 0x91, // add x0, x0, #0 :lo12:DELAY_IMPORT_DESCRIPTOR
+ 0x00, 0x00, 0x00, 0x94, // bl #0 __delayLoadHelper2
+ 0xf0, 0x03, 0x00, 0xaa, // mov x16, x0
+ 0xe6, 0x9f, 0x45, 0xad, // ldp q6, q7, [sp, #176]
+ 0xe4, 0x97, 0x44, 0xad, // ldp q4, q5, [sp, #144]
+ 0xe2, 0x8f, 0x43, 0xad, // ldp q2, q3, [sp, #112]
+ 0xe0, 0x87, 0x42, 0xad, // ldp q0, q1, [sp, #80]
+ 0xe6, 0x1f, 0x44, 0xa9, // ldp x6, x7, [sp, #64]
+ 0xe4, 0x17, 0x43, 0xa9, // ldp x4, x5, [sp, #48]
+ 0xe2, 0x0f, 0x42, 0xa9, // ldp x2, x3, [sp, #32]
+ 0xe0, 0x07, 0x41, 0xa9, // ldp x0, x1, [sp, #16]
+ 0xfd, 0x7b, 0xcd, 0xa8, // ldp x29, x30, [sp], #208
+ 0x00, 0x02, 0x1f, 0xd6, // br x16
+};
+
+// A chunk for the delay import thunk.
+class ThunkChunkX64 : public Chunk {
+public:
+ ThunkChunkX64(Defined *I, Chunk *D, Defined *H)
+ : Imp(I), Desc(D), Helper(H) {}
+
+ size_t getSize() const override { return sizeof(ThunkX64); }
+
+ void writeTo(uint8_t *Buf) const override {
+ memcpy(Buf + OutputSectionOff, ThunkX64, sizeof(ThunkX64));
+ write32le(Buf + OutputSectionOff + 36, Imp->getRVA() - RVA - 40);
+ write32le(Buf + OutputSectionOff + 43, Desc->getRVA() - RVA - 47);
+ write32le(Buf + OutputSectionOff + 48, Helper->getRVA() - RVA - 52);
+ }
+
+ Defined *Imp = nullptr;
+ Chunk *Desc = nullptr;
+ Defined *Helper = nullptr;
+};
+
+class ThunkChunkX86 : public Chunk {
+public:
+ ThunkChunkX86(Defined *I, Chunk *D, Defined *H)
+ : Imp(I), Desc(D), Helper(H) {}
+
+ size_t getSize() const override { return sizeof(ThunkX86); }
+
+ void writeTo(uint8_t *Buf) const override {
+ memcpy(Buf + OutputSectionOff, ThunkX86, sizeof(ThunkX86));
+ write32le(Buf + OutputSectionOff + 3, Imp->getRVA() + Config->ImageBase);
+ write32le(Buf + OutputSectionOff + 8, Desc->getRVA() + Config->ImageBase);
+ write32le(Buf + OutputSectionOff + 13, Helper->getRVA() - RVA - 17);
+ }
+
+ void getBaserels(std::vector<Baserel> *Res) override {
+ Res->emplace_back(RVA + 3);
+ Res->emplace_back(RVA + 8);
+ }
+
+ Defined *Imp = nullptr;
+ Chunk *Desc = nullptr;
+ Defined *Helper = nullptr;
+};
+
+class ThunkChunkARM : public Chunk {
+public:
+ ThunkChunkARM(Defined *I, Chunk *D, Defined *H)
+ : Imp(I), Desc(D), Helper(H) {}
+
+ size_t getSize() const override { return sizeof(ThunkARM); }
+
+ void writeTo(uint8_t *Buf) const override {
+ memcpy(Buf + OutputSectionOff, ThunkARM, sizeof(ThunkARM));
+ applyMOV32T(Buf + OutputSectionOff + 0, Imp->getRVA() + Config->ImageBase);
+ applyMOV32T(Buf + OutputSectionOff + 22, Desc->getRVA() + Config->ImageBase);
+ applyBranch24T(Buf + OutputSectionOff + 30, Helper->getRVA() - RVA - 34);
+ }
+
+ void getBaserels(std::vector<Baserel> *Res) override {
+ Res->emplace_back(RVA + 0, IMAGE_REL_BASED_ARM_MOV32T);
+ Res->emplace_back(RVA + 22, IMAGE_REL_BASED_ARM_MOV32T);
+ }
+
+ Defined *Imp = nullptr;
+ Chunk *Desc = nullptr;
+ Defined *Helper = nullptr;
+};
+
+class ThunkChunkARM64 : public Chunk {
+public:
+ ThunkChunkARM64(Defined *I, Chunk *D, Defined *H)
+ : Imp(I), Desc(D), Helper(H) {}
+
+ size_t getSize() const override { return sizeof(ThunkARM64); }
+
+ void writeTo(uint8_t *Buf) const override {
+ memcpy(Buf + OutputSectionOff, ThunkARM64, sizeof(ThunkARM64));
+ applyArm64Addr(Buf + OutputSectionOff + 0, Imp->getRVA(), RVA + 0, 12);
+ applyArm64Imm(Buf + OutputSectionOff + 4, Imp->getRVA() & 0xfff, 0);
+ applyArm64Addr(Buf + OutputSectionOff + 52, Desc->getRVA(), RVA + 52, 12);
+ applyArm64Imm(Buf + OutputSectionOff + 56, Desc->getRVA() & 0xfff, 0);
+ applyArm64Branch26(Buf + OutputSectionOff + 60,
+ Helper->getRVA() - RVA - 60);
+ }
+
+ Defined *Imp = nullptr;
+ Chunk *Desc = nullptr;
+ Defined *Helper = nullptr;
+};
+
+// A chunk for the import descriptor table.
+class DelayAddressChunk : public Chunk {
+public:
+ explicit DelayAddressChunk(Chunk *C) : Thunk(C) {
+ Alignment = Config->Wordsize;
+ }
+ size_t getSize() const override { return Config->Wordsize; }
+
+ void writeTo(uint8_t *Buf) const override {
+ if (Config->is64()) {
+ write64le(Buf + OutputSectionOff, Thunk->getRVA() + Config->ImageBase);
+ } else {
+ uint32_t Bit = 0;
+ // Pointer to thumb code must have the LSB set, so adjust it.
+ if (Config->Machine == ARMNT)
+ Bit = 1;
+ write32le(Buf + OutputSectionOff, (Thunk->getRVA() + Config->ImageBase) | Bit);
+ }
+ }
+
+ void getBaserels(std::vector<Baserel> *Res) override {
+ Res->emplace_back(RVA);
+ }
+
+ Chunk *Thunk;
+};
+
+// Export table
+// Read Microsoft PE/COFF spec 5.3 for details.
+
+// A chunk for the export descriptor table.
+class ExportDirectoryChunk : public Chunk {
+public:
+ ExportDirectoryChunk(int I, int J, Chunk *D, Chunk *A, Chunk *N, Chunk *O)
+ : MaxOrdinal(I), NameTabSize(J), DLLName(D), AddressTab(A), NameTab(N),
+ OrdinalTab(O) {}
+
+ size_t getSize() const override {
+ return sizeof(export_directory_table_entry);
+ }
+
+ void writeTo(uint8_t *Buf) const override {
+ memset(Buf + OutputSectionOff, 0, getSize());
+
+ auto *E = (export_directory_table_entry *)(Buf + OutputSectionOff);
+ E->NameRVA = DLLName->getRVA();
+ E->OrdinalBase = 0;
+ E->AddressTableEntries = MaxOrdinal + 1;
+ E->NumberOfNamePointers = NameTabSize;
+ E->ExportAddressTableRVA = AddressTab->getRVA();
+ E->NamePointerRVA = NameTab->getRVA();
+ E->OrdinalTableRVA = OrdinalTab->getRVA();
+ }
+
+ uint16_t MaxOrdinal;
+ uint16_t NameTabSize;
+ Chunk *DLLName;
+ Chunk *AddressTab;
+ Chunk *NameTab;
+ Chunk *OrdinalTab;
+};
+
+class AddressTableChunk : public Chunk {
+public:
+ explicit AddressTableChunk(size_t MaxOrdinal) : Size(MaxOrdinal + 1) {}
+ size_t getSize() const override { return Size * 4; }
+
+ void writeTo(uint8_t *Buf) const override {
+ memset(Buf + OutputSectionOff, 0, getSize());
+
+ for (const Export &E : Config->Exports) {
+ uint8_t *P = Buf + OutputSectionOff + E.Ordinal * 4;
+ uint32_t Bit = 0;
+ // Pointer to thumb code must have the LSB set, so adjust it.
+ if (Config->Machine == ARMNT && !E.Data)
+ Bit = 1;
+ if (E.ForwardChunk) {
+ write32le(P, E.ForwardChunk->getRVA() | Bit);
+ } else {
+ write32le(P, cast<Defined>(E.Sym)->getRVA() | Bit);
+ }
+ }
+ }
+
+private:
+ size_t Size;
+};
+
+class NamePointersChunk : public Chunk {
+public:
+ explicit NamePointersChunk(std::vector<Chunk *> &V) : Chunks(V) {}
+ size_t getSize() const override { return Chunks.size() * 4; }
+
+ void writeTo(uint8_t *Buf) const override {
+ uint8_t *P = Buf + OutputSectionOff;
+ for (Chunk *C : Chunks) {
+ write32le(P, C->getRVA());
+ P += 4;
+ }
+ }
+
+private:
+ std::vector<Chunk *> Chunks;
+};
+
+class ExportOrdinalChunk : public Chunk {
+public:
+ explicit ExportOrdinalChunk(size_t I) : Size(I) {}
+ size_t getSize() const override { return Size * 2; }
+
+ void writeTo(uint8_t *Buf) const override {
+ uint8_t *P = Buf + OutputSectionOff;
+ for (Export &E : Config->Exports) {
+ if (E.Noname)
+ continue;
+ write16le(P, E.Ordinal);
+ P += 2;
+ }
+ }
+
+private:
+ size_t Size;
+};
+
+} // anonymous namespace
+
+void IdataContents::create() {
+ std::vector<std::vector<DefinedImportData *>> V = binImports(Imports);
+
+ // Create .idata contents for each DLL.
+ for (std::vector<DefinedImportData *> &Syms : V) {
+ // Create lookup and address tables. If they have external names,
+ // we need to create HintName chunks to store the names.
+ // If they don't (if they are import-by-ordinals), we store only
+ // ordinal values to the table.
+ size_t Base = Lookups.size();
+ for (DefinedImportData *S : Syms) {
+ uint16_t Ord = S->getOrdinal();
+ if (S->getExternalName().empty()) {
+ Lookups.push_back(make<OrdinalOnlyChunk>(Ord));
+ Addresses.push_back(make<OrdinalOnlyChunk>(Ord));
+ continue;
+ }
+ auto *C = make<HintNameChunk>(S->getExternalName(), Ord);
+ Lookups.push_back(make<LookupChunk>(C));
+ Addresses.push_back(make<LookupChunk>(C));
+ Hints.push_back(C);
+ }
+ // Terminate with null values.
+ Lookups.push_back(make<NullChunk>(Config->Wordsize));
+ Addresses.push_back(make<NullChunk>(Config->Wordsize));
+
+ for (int I = 0, E = Syms.size(); I < E; ++I)
+ Syms[I]->setLocation(Addresses[Base + I]);
+
+ // Create the import table header.
+ DLLNames.push_back(make<StringChunk>(Syms[0]->getDLLName()));
+ auto *Dir = make<ImportDirectoryChunk>(DLLNames.back());
+ Dir->LookupTab = Lookups[Base];
+ Dir->AddressTab = Addresses[Base];
+ Dirs.push_back(Dir);
+ }
+ // Add null terminator.
+ Dirs.push_back(make<NullChunk>(sizeof(ImportDirectoryTableEntry)));
+}
+
+std::vector<Chunk *> DelayLoadContents::getChunks() {
+ std::vector<Chunk *> V;
+ V.insert(V.end(), Dirs.begin(), Dirs.end());
+ V.insert(V.end(), Names.begin(), Names.end());
+ V.insert(V.end(), HintNames.begin(), HintNames.end());
+ V.insert(V.end(), DLLNames.begin(), DLLNames.end());
+ return V;
+}
+
+std::vector<Chunk *> DelayLoadContents::getDataChunks() {
+ std::vector<Chunk *> V;
+ V.insert(V.end(), ModuleHandles.begin(), ModuleHandles.end());
+ V.insert(V.end(), Addresses.begin(), Addresses.end());
+ return V;
+}
+
+uint64_t DelayLoadContents::getDirSize() {
+ return Dirs.size() * sizeof(delay_import_directory_table_entry);
+}
+
+void DelayLoadContents::create(Defined *H) {
+ Helper = H;
+ std::vector<std::vector<DefinedImportData *>> V = binImports(Imports);
+
+ // Create .didat contents for each DLL.
+ for (std::vector<DefinedImportData *> &Syms : V) {
+ // Create the delay import table header.
+ DLLNames.push_back(make<StringChunk>(Syms[0]->getDLLName()));
+ auto *Dir = make<DelayDirectoryChunk>(DLLNames.back());
+
+ size_t Base = Addresses.size();
+ for (DefinedImportData *S : Syms) {
+ Chunk *T = newThunkChunk(S, Dir);
+ auto *A = make<DelayAddressChunk>(T);
+ Addresses.push_back(A);
+ Thunks.push_back(T);
+ StringRef ExtName = S->getExternalName();
+ if (ExtName.empty()) {
+ Names.push_back(make<OrdinalOnlyChunk>(S->getOrdinal()));
+ } else {
+ auto *C = make<HintNameChunk>(ExtName, 0);
+ Names.push_back(make<LookupChunk>(C));
+ HintNames.push_back(C);
+ }
+ }
+ // Terminate with null values.
+ Addresses.push_back(make<NullChunk>(8));
+ Names.push_back(make<NullChunk>(8));
+
+ for (int I = 0, E = Syms.size(); I < E; ++I)
+ Syms[I]->setLocation(Addresses[Base + I]);
+ auto *MH = make<NullChunk>(8);
+ MH->Alignment = 8;
+ ModuleHandles.push_back(MH);
+
+ // Fill the delay import table header fields.
+ Dir->ModuleHandle = MH;
+ Dir->AddressTab = Addresses[Base];
+ Dir->NameTab = Names[Base];
+ Dirs.push_back(Dir);
+ }
+ // Add null terminator.
+ Dirs.push_back(make<NullChunk>(sizeof(delay_import_directory_table_entry)));
+}
+
+Chunk *DelayLoadContents::newThunkChunk(DefinedImportData *S, Chunk *Dir) {
+ switch (Config->Machine) {
+ case AMD64:
+ return make<ThunkChunkX64>(S, Dir, Helper);
+ case I386:
+ return make<ThunkChunkX86>(S, Dir, Helper);
+ case ARMNT:
+ return make<ThunkChunkARM>(S, Dir, Helper);
+ case ARM64:
+ return make<ThunkChunkARM64>(S, Dir, Helper);
+ default:
+ llvm_unreachable("unsupported machine type");
+ }
+}
+
+EdataContents::EdataContents() {
+ uint16_t MaxOrdinal = 0;
+ for (Export &E : Config->Exports)
+ MaxOrdinal = std::max(MaxOrdinal, E.Ordinal);
+
+ auto *DLLName = make<StringChunk>(sys::path::filename(Config->OutputFile));
+ auto *AddressTab = make<AddressTableChunk>(MaxOrdinal);
+ std::vector<Chunk *> Names;
+ for (Export &E : Config->Exports)
+ if (!E.Noname)
+ Names.push_back(make<StringChunk>(E.ExportName));
+
+ std::vector<Chunk *> Forwards;
+ for (Export &E : Config->Exports) {
+ if (E.ForwardTo.empty())
+ continue;
+ E.ForwardChunk = make<StringChunk>(E.ForwardTo);
+ Forwards.push_back(E.ForwardChunk);
+ }
+
+ auto *NameTab = make<NamePointersChunk>(Names);
+ auto *OrdinalTab = make<ExportOrdinalChunk>(Names.size());
+ auto *Dir = make<ExportDirectoryChunk>(MaxOrdinal, Names.size(), DLLName,
+ AddressTab, NameTab, OrdinalTab);
+ Chunks.push_back(Dir);
+ Chunks.push_back(DLLName);
+ Chunks.push_back(AddressTab);
+ Chunks.push_back(NameTab);
+ Chunks.push_back(OrdinalTab);
+ Chunks.insert(Chunks.end(), Names.begin(), Names.end());
+ Chunks.insert(Chunks.end(), Forwards.begin(), Forwards.end());
+}
+
+} // namespace coff
+} // namespace lld
diff --git a/contrib/llvm/tools/lld/COFF/DLL.h b/contrib/llvm/tools/lld/COFF/DLL.h
new file mode 100644
index 000000000000..a298271e2c0d
--- /dev/null
+++ b/contrib/llvm/tools/lld/COFF/DLL.h
@@ -0,0 +1,82 @@
+//===- DLL.h ----------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_DLL_H
+#define LLD_COFF_DLL_H
+
+#include "Chunks.h"
+#include "Symbols.h"
+
+namespace lld {
+namespace coff {
+
+// Windows-specific.
+// IdataContents creates all chunks for the DLL import table.
+// You are supposed to call add() to add symbols and then
+// call create() to populate the chunk vectors.
+class IdataContents {
+public:
+ void add(DefinedImportData *Sym) { Imports.push_back(Sym); }
+ bool empty() { return Imports.empty(); }
+
+ void create();
+
+ std::vector<DefinedImportData *> Imports;
+ std::vector<Chunk *> Dirs;
+ std::vector<Chunk *> Lookups;
+ std::vector<Chunk *> Addresses;
+ std::vector<Chunk *> Hints;
+ std::vector<Chunk *> DLLNames;
+};
+
+// Windows-specific.
+// DelayLoadContents creates all chunks for the delay-load DLL import table.
+class DelayLoadContents {
+public:
+ void add(DefinedImportData *Sym) { Imports.push_back(Sym); }
+ bool empty() { return Imports.empty(); }
+ void create(Defined *Helper);
+ std::vector<Chunk *> getChunks();
+ std::vector<Chunk *> getDataChunks();
+ ArrayRef<Chunk *> getCodeChunks() { return Thunks; }
+
+ uint64_t getDirRVA() { return Dirs[0]->getRVA(); }
+ uint64_t getDirSize();
+
+private:
+ Chunk *newThunkChunk(DefinedImportData *S, Chunk *Dir);
+
+ Defined *Helper;
+ std::vector<DefinedImportData *> Imports;
+ std::vector<Chunk *> Dirs;
+ std::vector<Chunk *> ModuleHandles;
+ std::vector<Chunk *> Addresses;
+ std::vector<Chunk *> Names;
+ std::vector<Chunk *> HintNames;
+ std::vector<Chunk *> Thunks;
+ std::vector<Chunk *> DLLNames;
+};
+
+// Windows-specific.
+// EdataContents creates all chunks for the DLL export table.
+class EdataContents {
+public:
+ EdataContents();
+ std::vector<Chunk *> Chunks;
+
+ uint64_t getRVA() { return Chunks[0]->getRVA(); }
+ uint64_t getSize() {
+ return Chunks.back()->getRVA() + Chunks.back()->getSize() - getRVA();
+ }
+};
+
+} // namespace coff
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/COFF/Driver.cpp b/contrib/llvm/tools/lld/COFF/Driver.cpp
new file mode 100644
index 000000000000..2e4b1e6d3147
--- /dev/null
+++ b/contrib/llvm/tools/lld/COFF/Driver.cpp
@@ -0,0 +1,1681 @@
+//===- Driver.cpp ---------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Driver.h"
+#include "Config.h"
+#include "ICF.h"
+#include "InputFiles.h"
+#include "MarkLive.h"
+#include "MinGW.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+#include "Writer.h"
+#include "lld/Common/Args.h"
+#include "lld/Common/Driver.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Memory.h"
+#include "lld/Common/Timer.h"
+#include "lld/Common/Version.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/Object/ArchiveWriter.h"
+#include "llvm/Object/COFFImportFile.h"
+#include "llvm/Object/COFFModuleDefinition.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/TarWriter.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/ToolDrivers/llvm-lib/LibDriver.h"
+#include <algorithm>
+#include <future>
+#include <memory>
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::COFF;
+using llvm::sys::Process;
+
+namespace lld {
+namespace coff {
+
+static Timer InputFileTimer("Input File Reading", Timer::root());
+
+Configuration *Config;
+LinkerDriver *Driver;
+
+bool link(ArrayRef<const char *> Args, bool CanExitEarly, raw_ostream &Diag) {
+ errorHandler().LogName = args::getFilenameWithoutExe(Args[0]);
+ errorHandler().ErrorOS = &Diag;
+ errorHandler().ColorDiagnostics = Diag.has_colors();
+ errorHandler().ErrorLimitExceededMsg =
+ "too many errors emitted, stopping now"
+ " (use /errorlimit:0 to see all errors)";
+ errorHandler().ExitEarly = CanExitEarly;
+ Config = make<Configuration>();
+
+ Symtab = make<SymbolTable>();
+
+ Driver = make<LinkerDriver>();
+ Driver->link(Args);
+
+ // Call exit() if we can to avoid calling destructors.
+ if (CanExitEarly)
+ exitLld(errorCount() ? 1 : 0);
+
+ freeArena();
+ ObjFile::Instances.clear();
+ ImportFile::Instances.clear();
+ BitcodeFile::Instances.clear();
+ return !errorCount();
+}
+
+// Drop directory components and replace extension with ".exe" or ".dll".
+static std::string getOutputPath(StringRef Path) {
+ auto P = Path.find_last_of("\\/");
+ StringRef S = (P == StringRef::npos) ? Path : Path.substr(P + 1);
+ const char* E = Config->DLL ? ".dll" : ".exe";
+ return (S.substr(0, S.rfind('.')) + E).str();
+}
+
+// ErrorOr is not default constructible, so it cannot be used as the type
+// parameter of a future.
+// FIXME: We could open the file in createFutureForFile and avoid needing to
+// return an error here, but for the moment that would cost us a file descriptor
+// (a limited resource on Windows) for the duration that the future is pending.
+typedef std::pair<std::unique_ptr<MemoryBuffer>, std::error_code> MBErrPair;
+
+// Create a std::future that opens and maps a file using the best strategy for
+// the host platform.
+static std::future<MBErrPair> createFutureForFile(std::string Path) {
+#if _WIN32
+ // On Windows, file I/O is relatively slow so it is best to do this
+ // asynchronously.
+ auto Strategy = std::launch::async;
+#else
+ auto Strategy = std::launch::deferred;
+#endif
+ return std::async(Strategy, [=]() {
+ auto MBOrErr = MemoryBuffer::getFile(Path,
+ /*FileSize*/ -1,
+ /*RequiresNullTerminator*/ false);
+ if (!MBOrErr)
+ return MBErrPair{nullptr, MBOrErr.getError()};
+ return MBErrPair{std::move(*MBOrErr), std::error_code()};
+ });
+}
+
+// Symbol names are mangled by prepending "_" on x86.
+static StringRef mangle(StringRef Sym) {
+ assert(Config->Machine != IMAGE_FILE_MACHINE_UNKNOWN);
+ if (Config->Machine == I386)
+ return Saver.save("_" + Sym);
+ return Sym;
+}
+
+static bool findUnderscoreMangle(StringRef Sym) {
+ StringRef Entry = Symtab->findMangle(mangle(Sym));
+ return !Entry.empty() && !isa<Undefined>(Symtab->find(Entry));
+}
+
+MemoryBufferRef LinkerDriver::takeBuffer(std::unique_ptr<MemoryBuffer> MB) {
+ MemoryBufferRef MBRef = *MB;
+ make<std::unique_ptr<MemoryBuffer>>(std::move(MB)); // take ownership
+
+ if (Driver->Tar)
+ Driver->Tar->append(relativeToRoot(MBRef.getBufferIdentifier()),
+ MBRef.getBuffer());
+ return MBRef;
+}
+
+void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> MB,
+ bool WholeArchive) {
+ StringRef Filename = MB->getBufferIdentifier();
+
+ MemoryBufferRef MBRef = takeBuffer(std::move(MB));
+ FilePaths.push_back(Filename);
+
+ // File type is detected by contents, not by file extension.
+ switch (identify_magic(MBRef.getBuffer())) {
+ case file_magic::windows_resource:
+ Resources.push_back(MBRef);
+ break;
+ case file_magic::archive:
+ if (WholeArchive) {
+ std::unique_ptr<Archive> File =
+ CHECK(Archive::create(MBRef), Filename + ": failed to parse archive");
+
+ for (MemoryBufferRef M : getArchiveMembers(File.get()))
+ addArchiveBuffer(M, "<whole-archive>", Filename);
+ return;
+ }
+ Symtab->addFile(make<ArchiveFile>(MBRef));
+ break;
+ case file_magic::bitcode:
+ Symtab->addFile(make<BitcodeFile>(MBRef));
+ break;
+ case file_magic::coff_object:
+ case file_magic::coff_import_library:
+ Symtab->addFile(make<ObjFile>(MBRef));
+ break;
+ case file_magic::coff_cl_gl_object:
+ error(Filename + ": is not a native COFF file. Recompile without /GL");
+ break;
+ case file_magic::pecoff_executable:
+ if (Filename.endswith_lower(".dll")) {
+ error(Filename + ": bad file type. Did you specify a DLL instead of an "
+ "import library?");
+ break;
+ }
+ LLVM_FALLTHROUGH;
+ default:
+ error(MBRef.getBufferIdentifier() + ": unknown file type");
+ break;
+ }
+}
+
+void LinkerDriver::enqueuePath(StringRef Path, bool WholeArchive) {
+ auto Future =
+ std::make_shared<std::future<MBErrPair>>(createFutureForFile(Path));
+ std::string PathStr = Path;
+ enqueueTask([=]() {
+ auto MBOrErr = Future->get();
+ if (MBOrErr.second)
+ error("could not open " + PathStr + ": " + MBOrErr.second.message());
+ else
+ Driver->addBuffer(std::move(MBOrErr.first), WholeArchive);
+ });
+}
+
+void LinkerDriver::addArchiveBuffer(MemoryBufferRef MB, StringRef SymName,
+ StringRef ParentName) {
+ file_magic Magic = identify_magic(MB.getBuffer());
+ if (Magic == file_magic::coff_import_library) {
+ Symtab->addFile(make<ImportFile>(MB));
+ return;
+ }
+
+ InputFile *Obj;
+ if (Magic == file_magic::coff_object) {
+ Obj = make<ObjFile>(MB);
+ } else if (Magic == file_magic::bitcode) {
+ Obj = make<BitcodeFile>(MB);
+ } else {
+ error("unknown file type: " + MB.getBufferIdentifier());
+ return;
+ }
+
+ Obj->ParentName = ParentName;
+ Symtab->addFile(Obj);
+ log("Loaded " + toString(Obj) + " for " + SymName);
+}
+
+void LinkerDriver::enqueueArchiveMember(const Archive::Child &C,
+ StringRef SymName,
+ StringRef ParentName) {
+ if (!C.getParent()->isThin()) {
+ MemoryBufferRef MB = CHECK(
+ C.getMemoryBufferRef(),
+ "could not get the buffer for the member defining symbol " + SymName);
+ enqueueTask([=]() { Driver->addArchiveBuffer(MB, SymName, ParentName); });
+ return;
+ }
+
+ auto Future = std::make_shared<std::future<MBErrPair>>(createFutureForFile(
+ CHECK(C.getFullName(),
+ "could not get the filename for the member defining symbol " +
+ SymName)));
+ enqueueTask([=]() {
+ auto MBOrErr = Future->get();
+ if (MBOrErr.second)
+ fatal("could not get the buffer for the member defining " + SymName +
+ ": " + MBOrErr.second.message());
+ Driver->addArchiveBuffer(takeBuffer(std::move(MBOrErr.first)), SymName,
+ ParentName);
+ });
+}
+
+static bool isDecorated(StringRef Sym) {
+ return Sym.startswith("@") || Sym.contains("@@") || Sym.startswith("?") ||
+ (!Config->MinGW && Sym.contains('@'));
+}
+
+// Parses .drectve section contents and returns a list of files
+// specified by /defaultlib.
+void LinkerDriver::parseDirectives(StringRef S) {
+ ArgParser Parser;
+ // .drectve is always tokenized using Windows shell rules.
+ // /EXPORT: option can appear too many times, processing in fastpath.
+ opt::InputArgList Args;
+ std::vector<StringRef> Exports;
+ std::tie(Args, Exports) = Parser.parseDirectives(S);
+
+ for (StringRef E : Exports) {
+ // If a common header file contains dllexported function
+ // declarations, many object files may end up with having the
+ // same /EXPORT options. In order to save cost of parsing them,
+ // we dedup them first.
+ if (!DirectivesExports.insert(E).second)
+ continue;
+
+ Export Exp = parseExport(E);
+ if (Config->Machine == I386 && Config->MinGW) {
+ if (!isDecorated(Exp.Name))
+ Exp.Name = Saver.save("_" + Exp.Name);
+ if (!Exp.ExtName.empty() && !isDecorated(Exp.ExtName))
+ Exp.ExtName = Saver.save("_" + Exp.ExtName);
+ }
+ Exp.Directives = true;
+ Config->Exports.push_back(Exp);
+ }
+
+ for (auto *Arg : Args) {
+ switch (Arg->getOption().getUnaliasedOption().getID()) {
+ case OPT_aligncomm:
+ parseAligncomm(Arg->getValue());
+ break;
+ case OPT_alternatename:
+ parseAlternateName(Arg->getValue());
+ break;
+ case OPT_defaultlib:
+ if (Optional<StringRef> Path = findLib(Arg->getValue()))
+ enqueuePath(*Path, false);
+ break;
+ case OPT_entry:
+ Config->Entry = addUndefined(mangle(Arg->getValue()));
+ break;
+ case OPT_failifmismatch:
+ checkFailIfMismatch(Arg->getValue());
+ break;
+ case OPT_incl:
+ addUndefined(Arg->getValue());
+ break;
+ case OPT_merge:
+ parseMerge(Arg->getValue());
+ break;
+ case OPT_nodefaultlib:
+ Config->NoDefaultLibs.insert(doFindLib(Arg->getValue()));
+ break;
+ case OPT_section:
+ parseSection(Arg->getValue());
+ break;
+ case OPT_subsystem:
+ parseSubsystem(Arg->getValue(), &Config->Subsystem,
+ &Config->MajorOSVersion, &Config->MinorOSVersion);
+ break;
+ case OPT_editandcontinue:
+ case OPT_fastfail:
+ case OPT_guardsym:
+ case OPT_natvis:
+ case OPT_throwingnew:
+ break;
+ default:
+ error(Arg->getSpelling() + " is not allowed in .drectve");
+ }
+ }
+}
+
+// Find file from search paths. You can omit ".obj", this function takes
+// care of that. Note that the returned path is not guaranteed to exist.
+StringRef LinkerDriver::doFindFile(StringRef Filename) {
+ bool HasPathSep = (Filename.find_first_of("/\\") != StringRef::npos);
+ if (HasPathSep)
+ return Filename;
+ bool HasExt = Filename.contains('.');
+ for (StringRef Dir : SearchPaths) {
+ SmallString<128> Path = Dir;
+ sys::path::append(Path, Filename);
+ if (sys::fs::exists(Path.str()))
+ return Saver.save(Path.str());
+ if (!HasExt) {
+ Path.append(".obj");
+ if (sys::fs::exists(Path.str()))
+ return Saver.save(Path.str());
+ }
+ }
+ return Filename;
+}
+
+static Optional<sys::fs::UniqueID> getUniqueID(StringRef Path) {
+ sys::fs::UniqueID Ret;
+ if (sys::fs::getUniqueID(Path, Ret))
+ return None;
+ return Ret;
+}
+
+// Resolves a file path. This never returns the same path
+// (in that case, it returns None).
+Optional<StringRef> LinkerDriver::findFile(StringRef Filename) {
+ StringRef Path = doFindFile(Filename);
+
+ if (Optional<sys::fs::UniqueID> ID = getUniqueID(Path)) {
+ bool Seen = !VisitedFiles.insert(*ID).second;
+ if (Seen)
+ return None;
+ }
+
+ if (Path.endswith_lower(".lib"))
+ VisitedLibs.insert(sys::path::filename(Path));
+ return Path;
+}
+
+// MinGW specific. If an embedded directive specified to link to
+// foo.lib, but it isn't found, try libfoo.a instead.
+StringRef LinkerDriver::doFindLibMinGW(StringRef Filename) {
+ if (Filename.contains('/') || Filename.contains('\\'))
+ return Filename;
+
+ SmallString<128> S = Filename;
+ sys::path::replace_extension(S, ".a");
+ StringRef LibName = Saver.save("lib" + S.str());
+ return doFindFile(LibName);
+}
+
+// Find library file from search path.
+StringRef LinkerDriver::doFindLib(StringRef Filename) {
+ // Add ".lib" to Filename if that has no file extension.
+ bool HasExt = Filename.contains('.');
+ if (!HasExt)
+ Filename = Saver.save(Filename + ".lib");
+ StringRef Ret = doFindFile(Filename);
+ // For MinGW, if the find above didn't turn up anything, try
+ // looking for a MinGW formatted library name.
+ if (Config->MinGW && Ret == Filename)
+ return doFindLibMinGW(Filename);
+ return Ret;
+}
+
+// Resolves a library path. /nodefaultlib options are taken into
+// consideration. This never returns the same path (in that case,
+// it returns None).
+Optional<StringRef> LinkerDriver::findLib(StringRef Filename) {
+ if (Config->NoDefaultLibAll)
+ return None;
+ if (!VisitedLibs.insert(Filename.lower()).second)
+ return None;
+
+ StringRef Path = doFindLib(Filename);
+ if (Config->NoDefaultLibs.count(Path))
+ return None;
+
+ if (Optional<sys::fs::UniqueID> ID = getUniqueID(Path))
+ if (!VisitedFiles.insert(*ID).second)
+ return None;
+ return Path;
+}
+
+// Parses LIB environment which contains a list of search paths.
+void LinkerDriver::addLibSearchPaths() {
+ Optional<std::string> EnvOpt = Process::GetEnv("LIB");
+ if (!EnvOpt.hasValue())
+ return;
+ StringRef Env = Saver.save(*EnvOpt);
+ while (!Env.empty()) {
+ StringRef Path;
+ std::tie(Path, Env) = Env.split(';');
+ SearchPaths.push_back(Path);
+ }
+}
+
+Symbol *LinkerDriver::addUndefined(StringRef Name) {
+ Symbol *B = Symtab->addUndefined(Name);
+ if (!B->IsGCRoot) {
+ B->IsGCRoot = true;
+ Config->GCRoot.push_back(B);
+ }
+ return B;
+}
+
+// Windows specific -- find default entry point name.
+//
+// There are four different entry point functions for Windows executables,
+// each of which corresponds to a user-defined "main" function. This function
+// infers an entry point from a user-defined "main" function.
+StringRef LinkerDriver::findDefaultEntry() {
+ assert(Config->Subsystem != IMAGE_SUBSYSTEM_UNKNOWN &&
+ "must handle /subsystem before calling this");
+
+ if (Config->MinGW)
+ return mangle(Config->Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI
+ ? "WinMainCRTStartup"
+ : "mainCRTStartup");
+
+ if (Config->Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) {
+ if (findUnderscoreMangle("wWinMain")) {
+ if (!findUnderscoreMangle("WinMain"))
+ return mangle("wWinMainCRTStartup");
+ warn("found both wWinMain and WinMain; using latter");
+ }
+ return mangle("WinMainCRTStartup");
+ }
+ if (findUnderscoreMangle("wmain")) {
+ if (!findUnderscoreMangle("main"))
+ return mangle("wmainCRTStartup");
+ warn("found both wmain and main; using latter");
+ }
+ return mangle("mainCRTStartup");
+}
+
+WindowsSubsystem LinkerDriver::inferSubsystem() {
+ if (Config->DLL)
+ return IMAGE_SUBSYSTEM_WINDOWS_GUI;
+ if (Config->MinGW)
+ return IMAGE_SUBSYSTEM_WINDOWS_CUI;
+ // Note that link.exe infers the subsystem from the presence of these
+ // functions even if /entry: or /nodefaultlib are passed which causes them
+ // to not be called.
+ bool HaveMain = findUnderscoreMangle("main");
+ bool HaveWMain = findUnderscoreMangle("wmain");
+ bool HaveWinMain = findUnderscoreMangle("WinMain");
+ bool HaveWWinMain = findUnderscoreMangle("wWinMain");
+ if (HaveMain || HaveWMain) {
+ if (HaveWinMain || HaveWWinMain) {
+ warn(std::string("found ") + (HaveMain ? "main" : "wmain") + " and " +
+ (HaveWinMain ? "WinMain" : "wWinMain") +
+ "; defaulting to /subsystem:console");
+ }
+ return IMAGE_SUBSYSTEM_WINDOWS_CUI;
+ }
+ if (HaveWinMain || HaveWWinMain)
+ return IMAGE_SUBSYSTEM_WINDOWS_GUI;
+ return IMAGE_SUBSYSTEM_UNKNOWN;
+}
+
+static uint64_t getDefaultImageBase() {
+ if (Config->is64())
+ return Config->DLL ? 0x180000000 : 0x140000000;
+ return Config->DLL ? 0x10000000 : 0x400000;
+}
+
+static std::string createResponseFile(const opt::InputArgList &Args,
+ ArrayRef<StringRef> FilePaths,
+ ArrayRef<StringRef> SearchPaths) {
+ SmallString<0> Data;
+ raw_svector_ostream OS(Data);
+
+ for (auto *Arg : Args) {
+ switch (Arg->getOption().getID()) {
+ case OPT_linkrepro:
+ case OPT_INPUT:
+ case OPT_defaultlib:
+ case OPT_libpath:
+ case OPT_manifest:
+ case OPT_manifest_colon:
+ case OPT_manifestdependency:
+ case OPT_manifestfile:
+ case OPT_manifestinput:
+ case OPT_manifestuac:
+ break;
+ default:
+ OS << toString(*Arg) << "\n";
+ }
+ }
+
+ for (StringRef Path : SearchPaths) {
+ std::string RelPath = relativeToRoot(Path);
+ OS << "/libpath:" << quote(RelPath) << "\n";
+ }
+
+ for (StringRef Path : FilePaths)
+ OS << quote(relativeToRoot(Path)) << "\n";
+
+ return Data.str();
+}
+
+enum class DebugKind { Unknown, None, Full, FastLink, GHash, Dwarf, Symtab };
+
+static DebugKind parseDebugKind(const opt::InputArgList &Args) {
+ auto *A = Args.getLastArg(OPT_debug, OPT_debug_opt);
+ if (!A)
+ return DebugKind::None;
+ if (A->getNumValues() == 0)
+ return DebugKind::Full;
+
+ DebugKind Debug = StringSwitch<DebugKind>(A->getValue())
+ .CaseLower("none", DebugKind::None)
+ .CaseLower("full", DebugKind::Full)
+ .CaseLower("fastlink", DebugKind::FastLink)
+ // LLD extensions
+ .CaseLower("ghash", DebugKind::GHash)
+ .CaseLower("dwarf", DebugKind::Dwarf)
+ .CaseLower("symtab", DebugKind::Symtab)
+ .Default(DebugKind::Unknown);
+
+ if (Debug == DebugKind::FastLink) {
+ warn("/debug:fastlink unsupported; using /debug:full");
+ return DebugKind::Full;
+ }
+ if (Debug == DebugKind::Unknown) {
+ error("/debug: unknown option: " + Twine(A->getValue()));
+ return DebugKind::None;
+ }
+ return Debug;
+}
+
+static unsigned parseDebugTypes(const opt::InputArgList &Args) {
+ unsigned DebugTypes = static_cast<unsigned>(DebugType::None);
+
+ if (auto *A = Args.getLastArg(OPT_debugtype)) {
+ SmallVector<StringRef, 3> Types;
+ A->getSpelling().split(Types, ',', /*KeepEmpty=*/false);
+
+ for (StringRef Type : Types) {
+ unsigned V = StringSwitch<unsigned>(Type.lower())
+ .Case("cv", static_cast<unsigned>(DebugType::CV))
+ .Case("pdata", static_cast<unsigned>(DebugType::PData))
+ .Case("fixup", static_cast<unsigned>(DebugType::Fixup))
+ .Default(0);
+ if (V == 0) {
+ warn("/debugtype: unknown option: " + Twine(A->getValue()));
+ continue;
+ }
+ DebugTypes |= V;
+ }
+ return DebugTypes;
+ }
+
+ // Default debug types
+ DebugTypes = static_cast<unsigned>(DebugType::CV);
+ if (Args.hasArg(OPT_driver))
+ DebugTypes |= static_cast<unsigned>(DebugType::PData);
+ if (Args.hasArg(OPT_profile))
+ DebugTypes |= static_cast<unsigned>(DebugType::Fixup);
+
+ return DebugTypes;
+}
+
+static std::string getMapFile(const opt::InputArgList &Args) {
+ auto *Arg = Args.getLastArg(OPT_lldmap, OPT_lldmap_file);
+ if (!Arg)
+ return "";
+ if (Arg->getOption().getID() == OPT_lldmap_file)
+ return Arg->getValue();
+
+ assert(Arg->getOption().getID() == OPT_lldmap);
+ StringRef OutFile = Config->OutputFile;
+ return (OutFile.substr(0, OutFile.rfind('.')) + ".map").str();
+}
+
+static std::string getImplibPath() {
+ if (!Config->Implib.empty())
+ return Config->Implib;
+ SmallString<128> Out = StringRef(Config->OutputFile);
+ sys::path::replace_extension(Out, ".lib");
+ return Out.str();
+}
+
+//
+// The import name is caculated as the following:
+//
+// | LIBRARY w/ ext | LIBRARY w/o ext | no LIBRARY
+// -----+----------------+---------------------+------------------
+// LINK | {value} | {value}.{.dll/.exe} | {output name}
+// LIB | {value} | {value}.dll | {output name}.dll
+//
+static std::string getImportName(bool AsLib) {
+ SmallString<128> Out;
+
+ if (Config->ImportName.empty()) {
+ Out.assign(sys::path::filename(Config->OutputFile));
+ if (AsLib)
+ sys::path::replace_extension(Out, ".dll");
+ } else {
+ Out.assign(Config->ImportName);
+ if (!sys::path::has_extension(Out))
+ sys::path::replace_extension(Out,
+ (Config->DLL || AsLib) ? ".dll" : ".exe");
+ }
+
+ return Out.str();
+}
+
+static void createImportLibrary(bool AsLib) {
+ std::vector<COFFShortExport> Exports;
+ for (Export &E1 : Config->Exports) {
+ COFFShortExport E2;
+ E2.Name = E1.Name;
+ E2.SymbolName = E1.SymbolName;
+ E2.ExtName = E1.ExtName;
+ E2.Ordinal = E1.Ordinal;
+ E2.Noname = E1.Noname;
+ E2.Data = E1.Data;
+ E2.Private = E1.Private;
+ E2.Constant = E1.Constant;
+ Exports.push_back(E2);
+ }
+
+ auto HandleError = [](Error &&E) {
+ handleAllErrors(std::move(E),
+ [](ErrorInfoBase &EIB) { error(EIB.message()); });
+ };
+ std::string LibName = getImportName(AsLib);
+ std::string Path = getImplibPath();
+
+ if (!Config->Incremental) {
+ HandleError(writeImportLibrary(LibName, Path, Exports, Config->Machine,
+ Config->MinGW));
+ return;
+ }
+
+ // If the import library already exists, replace it only if the contents
+ // have changed.
+ ErrorOr<std::unique_ptr<MemoryBuffer>> OldBuf = MemoryBuffer::getFile(
+ Path, /*FileSize*/ -1, /*RequiresNullTerminator*/ false);
+ if (!OldBuf) {
+ HandleError(writeImportLibrary(LibName, Path, Exports, Config->Machine,
+ Config->MinGW));
+ return;
+ }
+
+ SmallString<128> TmpName;
+ if (std::error_code EC =
+ sys::fs::createUniqueFile(Path + ".tmp-%%%%%%%%.lib", TmpName))
+ fatal("cannot create temporary file for import library " + Path + ": " +
+ EC.message());
+
+ if (Error E = writeImportLibrary(LibName, TmpName, Exports, Config->Machine,
+ Config->MinGW)) {
+ HandleError(std::move(E));
+ return;
+ }
+
+ std::unique_ptr<MemoryBuffer> NewBuf = check(MemoryBuffer::getFile(
+ TmpName, /*FileSize*/ -1, /*RequiresNullTerminator*/ false));
+ if ((*OldBuf)->getBuffer() != NewBuf->getBuffer()) {
+ OldBuf->reset();
+ HandleError(errorCodeToError(sys::fs::rename(TmpName, Path)));
+ } else {
+ sys::fs::remove(TmpName);
+ }
+}
+
+static void parseModuleDefs(StringRef Path) {
+ std::unique_ptr<MemoryBuffer> MB = CHECK(
+ MemoryBuffer::getFile(Path, -1, false, true), "could not open " + Path);
+ COFFModuleDefinition M = check(parseCOFFModuleDefinition(
+ MB->getMemBufferRef(), Config->Machine, Config->MinGW));
+
+ if (Config->OutputFile.empty())
+ Config->OutputFile = Saver.save(M.OutputFile);
+ Config->ImportName = Saver.save(M.ImportName);
+ if (M.ImageBase)
+ Config->ImageBase = M.ImageBase;
+ if (M.StackReserve)
+ Config->StackReserve = M.StackReserve;
+ if (M.StackCommit)
+ Config->StackCommit = M.StackCommit;
+ if (M.HeapReserve)
+ Config->HeapReserve = M.HeapReserve;
+ if (M.HeapCommit)
+ Config->HeapCommit = M.HeapCommit;
+ if (M.MajorImageVersion)
+ Config->MajorImageVersion = M.MajorImageVersion;
+ if (M.MinorImageVersion)
+ Config->MinorImageVersion = M.MinorImageVersion;
+ if (M.MajorOSVersion)
+ Config->MajorOSVersion = M.MajorOSVersion;
+ if (M.MinorOSVersion)
+ Config->MinorOSVersion = M.MinorOSVersion;
+
+ for (COFFShortExport E1 : M.Exports) {
+ Export E2;
+ // In simple cases, only Name is set. Renamed exports are parsed
+ // and set as "ExtName = Name". If Name has the form "OtherDll.Func",
+ // it shouldn't be a normal exported function but a forward to another
+ // DLL instead. This is supported by both MS and GNU linkers.
+ if (E1.ExtName != E1.Name && StringRef(E1.Name).contains('.')) {
+ E2.Name = Saver.save(E1.ExtName);
+ E2.ForwardTo = Saver.save(E1.Name);
+ Config->Exports.push_back(E2);
+ continue;
+ }
+ E2.Name = Saver.save(E1.Name);
+ E2.ExtName = Saver.save(E1.ExtName);
+ E2.Ordinal = E1.Ordinal;
+ E2.Noname = E1.Noname;
+ E2.Data = E1.Data;
+ E2.Private = E1.Private;
+ E2.Constant = E1.Constant;
+ Config->Exports.push_back(E2);
+ }
+}
+
+void LinkerDriver::enqueueTask(std::function<void()> Task) {
+ TaskQueue.push_back(std::move(Task));
+}
+
+bool LinkerDriver::run() {
+ ScopedTimer T(InputFileTimer);
+
+ bool DidWork = !TaskQueue.empty();
+ while (!TaskQueue.empty()) {
+ TaskQueue.front()();
+ TaskQueue.pop_front();
+ }
+ return DidWork;
+}
+
+// Parse an /order file. If an option is given, the linker places
+// COMDAT sections in the same order as their names appear in the
+// given file.
+static void parseOrderFile(StringRef Arg) {
+ // For some reason, the MSVC linker requires a filename to be
+ // preceded by "@".
+ if (!Arg.startswith("@")) {
+ error("malformed /order option: '@' missing");
+ return;
+ }
+
+ // Get a list of all comdat sections for error checking.
+ DenseSet<StringRef> Set;
+ for (Chunk *C : Symtab->getChunks())
+ if (auto *Sec = dyn_cast<SectionChunk>(C))
+ if (Sec->Sym)
+ Set.insert(Sec->Sym->getName());
+
+ // Open a file.
+ StringRef Path = Arg.substr(1);
+ std::unique_ptr<MemoryBuffer> MB = CHECK(
+ MemoryBuffer::getFile(Path, -1, false, true), "could not open " + Path);
+
+ // Parse a file. An order file contains one symbol per line.
+ // All symbols that were not present in a given order file are
+ // considered to have the lowest priority 0 and are placed at
+ // end of an output section.
+ for (std::string S : args::getLines(MB->getMemBufferRef())) {
+ if (Config->Machine == I386 && !isDecorated(S))
+ S = "_" + S;
+
+ if (Set.count(S) == 0) {
+ if (Config->WarnMissingOrderSymbol)
+ warn("/order:" + Arg + ": missing symbol: " + S + " [LNK4037]");
+ }
+ else
+ Config->Order[S] = INT_MIN + Config->Order.size();
+ }
+}
+
+static void markAddrsig(Symbol *S) {
+ if (auto *D = dyn_cast_or_null<Defined>(S))
+ if (Chunk *C = D->getChunk())
+ C->KeepUnique = true;
+}
+
+static void findKeepUniqueSections() {
+ // Exported symbols could be address-significant in other executables or DSOs,
+ // so we conservatively mark them as address-significant.
+ for (Export &R : Config->Exports)
+ markAddrsig(R.Sym);
+
+ // Visit the address-significance table in each object file and mark each
+ // referenced symbol as address-significant.
+ for (ObjFile *Obj : ObjFile::Instances) {
+ ArrayRef<Symbol *> Syms = Obj->getSymbols();
+ if (Obj->AddrsigSec) {
+ ArrayRef<uint8_t> Contents;
+ Obj->getCOFFObj()->getSectionContents(Obj->AddrsigSec, Contents);
+ const uint8_t *Cur = Contents.begin();
+ while (Cur != Contents.end()) {
+ unsigned Size;
+ const char *Err;
+ uint64_t SymIndex = decodeULEB128(Cur, &Size, Contents.end(), &Err);
+ if (Err)
+ fatal(toString(Obj) + ": could not decode addrsig section: " + Err);
+ if (SymIndex >= Syms.size())
+ fatal(toString(Obj) + ": invalid symbol index in addrsig section");
+ markAddrsig(Syms[SymIndex]);
+ Cur += Size;
+ }
+ } else {
+ // If an object file does not have an address-significance table,
+ // conservatively mark all of its symbols as address-significant.
+ for (Symbol *S : Syms)
+ markAddrsig(S);
+ }
+ }
+}
+
+// link.exe replaces each %foo% in AltPath with the contents of environment
+// variable foo, and adds the two magic env vars _PDB (expands to the basename
+// of pdb's output path) and _EXT (expands to the extension of the output
+// binary).
+// lld only supports %_PDB% and %_EXT% and warns on references to all other env
+// vars.
+static void parsePDBAltPath(StringRef AltPath) {
+ SmallString<128> Buf;
+ StringRef PDBBasename =
+ sys::path::filename(Config->PDBPath, sys::path::Style::windows);
+ StringRef BinaryExtension =
+ sys::path::extension(Config->OutputFile, sys::path::Style::windows);
+ if (!BinaryExtension.empty())
+ BinaryExtension = BinaryExtension.substr(1); // %_EXT% does not include '.'.
+
+ // Invariant:
+ // +--------- Cursor ('a...' might be the empty string).
+ // | +----- FirstMark
+ // | | +- SecondMark
+ // v v v
+ // a...%...%...
+ size_t Cursor = 0;
+ while (Cursor < AltPath.size()) {
+ size_t FirstMark, SecondMark;
+ if ((FirstMark = AltPath.find('%', Cursor)) == StringRef::npos ||
+ (SecondMark = AltPath.find('%', FirstMark + 1)) == StringRef::npos) {
+ // Didn't find another full fragment, treat rest of string as literal.
+ Buf.append(AltPath.substr(Cursor));
+ break;
+ }
+
+ // Found a full fragment. Append text in front of first %, and interpret
+ // text between first and second % as variable name.
+ Buf.append(AltPath.substr(Cursor, FirstMark - Cursor));
+ StringRef Var = AltPath.substr(FirstMark, SecondMark - FirstMark + 1);
+ if (Var.equals_lower("%_pdb%"))
+ Buf.append(PDBBasename);
+ else if (Var.equals_lower("%_ext%"))
+ Buf.append(BinaryExtension);
+ else {
+ warn("only %_PDB% and %_EXT% supported in /pdbaltpath:, keeping " +
+ Var + " as literal");
+ Buf.append(Var);
+ }
+
+ Cursor = SecondMark + 1;
+ }
+
+ Config->PDBAltPath = Buf;
+}
+
+void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
+ // If the first command line argument is "/lib", link.exe acts like lib.exe.
+ // We call our own implementation of lib.exe that understands bitcode files.
+ if (ArgsArr.size() > 1 && StringRef(ArgsArr[1]).equals_lower("/lib")) {
+ if (llvm::libDriverMain(ArgsArr.slice(1)) != 0)
+ fatal("lib failed");
+ return;
+ }
+
+ // Needed for LTO.
+ InitializeAllTargetInfos();
+ InitializeAllTargets();
+ InitializeAllTargetMCs();
+ InitializeAllAsmParsers();
+ InitializeAllAsmPrinters();
+
+ // Parse command line options.
+ ArgParser Parser;
+ opt::InputArgList Args = Parser.parseLINK(ArgsArr);
+
+ // Parse and evaluate -mllvm options.
+ std::vector<const char *> V;
+ V.push_back("lld-link (LLVM option parsing)");
+ for (auto *Arg : Args.filtered(OPT_mllvm))
+ V.push_back(Arg->getValue());
+ cl::ParseCommandLineOptions(V.size(), V.data());
+
+ // Handle /errorlimit early, because error() depends on it.
+ if (auto *Arg = Args.getLastArg(OPT_errorlimit)) {
+ int N = 20;
+ StringRef S = Arg->getValue();
+ if (S.getAsInteger(10, N))
+ error(Arg->getSpelling() + " number expected, but got " + S);
+ errorHandler().ErrorLimit = N;
+ }
+
+ // Handle /help
+ if (Args.hasArg(OPT_help)) {
+ printHelp(ArgsArr[0]);
+ return;
+ }
+
+ if (Args.hasArg(OPT_show_timing))
+ Config->ShowTiming = true;
+
+ ScopedTimer T(Timer::root());
+ // Handle --version, which is an lld extension. This option is a bit odd
+ // because it doesn't start with "/", but we deliberately chose "--" to
+ // avoid conflict with /version and for compatibility with clang-cl.
+ if (Args.hasArg(OPT_dash_dash_version)) {
+ outs() << getLLDVersion() << "\n";
+ return;
+ }
+
+ // Handle /lldmingw early, since it can potentially affect how other
+ // options are handled.
+ Config->MinGW = Args.hasArg(OPT_lldmingw);
+
+ if (auto *Arg = Args.getLastArg(OPT_linkrepro)) {
+ SmallString<64> Path = StringRef(Arg->getValue());
+ sys::path::append(Path, "repro.tar");
+
+ Expected<std::unique_ptr<TarWriter>> ErrOrWriter =
+ TarWriter::create(Path, "repro");
+
+ if (ErrOrWriter) {
+ Tar = std::move(*ErrOrWriter);
+ } else {
+ error("/linkrepro: failed to open " + Path + ": " +
+ toString(ErrOrWriter.takeError()));
+ }
+ }
+
+ if (!Args.hasArg(OPT_INPUT)) {
+ if (Args.hasArg(OPT_deffile))
+ Config->NoEntry = true;
+ else
+ fatal("no input files");
+ }
+
+ // Construct search path list.
+ SearchPaths.push_back("");
+ for (auto *Arg : Args.filtered(OPT_libpath))
+ SearchPaths.push_back(Arg->getValue());
+ addLibSearchPaths();
+
+ // Handle /ignore
+ for (auto *Arg : Args.filtered(OPT_ignore)) {
+ SmallVector<StringRef, 8> Vec;
+ StringRef(Arg->getValue()).split(Vec, ',');
+ for (StringRef S : Vec) {
+ if (S == "4037")
+ Config->WarnMissingOrderSymbol = false;
+ else if (S == "4099")
+ Config->WarnDebugInfoUnusable = false;
+ else if (S == "4217")
+ Config->WarnLocallyDefinedImported = false;
+ // Other warning numbers are ignored.
+ }
+ }
+
+ // Handle /out
+ if (auto *Arg = Args.getLastArg(OPT_out))
+ Config->OutputFile = Arg->getValue();
+
+ // Handle /verbose
+ if (Args.hasArg(OPT_verbose))
+ Config->Verbose = true;
+ errorHandler().Verbose = Config->Verbose;
+
+ // Handle /force or /force:unresolved
+ if (Args.hasArg(OPT_force, OPT_force_unresolved))
+ Config->ForceUnresolved = true;
+
+ // Handle /force or /force:multiple
+ if (Args.hasArg(OPT_force, OPT_force_multiple))
+ Config->ForceMultiple = true;
+
+ // Handle /debug
+ DebugKind Debug = parseDebugKind(Args);
+ if (Debug == DebugKind::Full || Debug == DebugKind::Dwarf ||
+ Debug == DebugKind::GHash) {
+ Config->Debug = true;
+ Config->Incremental = true;
+ }
+
+ // Handle /debugtype
+ Config->DebugTypes = parseDebugTypes(Args);
+
+ // Handle /pdb
+ bool ShouldCreatePDB =
+ (Debug == DebugKind::Full || Debug == DebugKind::GHash);
+ if (ShouldCreatePDB) {
+ if (auto *Arg = Args.getLastArg(OPT_pdb))
+ Config->PDBPath = Arg->getValue();
+ if (auto *Arg = Args.getLastArg(OPT_pdbaltpath))
+ Config->PDBAltPath = Arg->getValue();
+ if (Args.hasArg(OPT_natvis))
+ Config->NatvisFiles = Args.getAllArgValues(OPT_natvis);
+
+ if (auto *Arg = Args.getLastArg(OPT_pdb_source_path))
+ Config->PDBSourcePath = Arg->getValue();
+ }
+
+ // Handle /noentry
+ if (Args.hasArg(OPT_noentry)) {
+ if (Args.hasArg(OPT_dll))
+ Config->NoEntry = true;
+ else
+ error("/noentry must be specified with /dll");
+ }
+
+ // Handle /dll
+ if (Args.hasArg(OPT_dll)) {
+ Config->DLL = true;
+ Config->ManifestID = 2;
+ }
+
+ // Handle /dynamicbase and /fixed. We can't use hasFlag for /dynamicbase
+ // because we need to explicitly check whether that option or its inverse was
+ // present in the argument list in order to handle /fixed.
+ auto *DynamicBaseArg = Args.getLastArg(OPT_dynamicbase, OPT_dynamicbase_no);
+ if (DynamicBaseArg &&
+ DynamicBaseArg->getOption().getID() == OPT_dynamicbase_no)
+ Config->DynamicBase = false;
+
+ // MSDN claims "/FIXED:NO is the default setting for a DLL, and /FIXED is the
+ // default setting for any other project type.", but link.exe defaults to
+ // /FIXED:NO for exe outputs as well. Match behavior, not docs.
+ bool Fixed = Args.hasFlag(OPT_fixed, OPT_fixed_no, false);
+ if (Fixed) {
+ if (DynamicBaseArg &&
+ DynamicBaseArg->getOption().getID() == OPT_dynamicbase) {
+ error("/fixed must not be specified with /dynamicbase");
+ } else {
+ Config->Relocatable = false;
+ Config->DynamicBase = false;
+ }
+ }
+
+ // Handle /appcontainer
+ Config->AppContainer =
+ Args.hasFlag(OPT_appcontainer, OPT_appcontainer_no, false);
+
+ // Handle /machine
+ if (auto *Arg = Args.getLastArg(OPT_machine))
+ Config->Machine = getMachineType(Arg->getValue());
+
+ // Handle /nodefaultlib:<filename>
+ for (auto *Arg : Args.filtered(OPT_nodefaultlib))
+ Config->NoDefaultLibs.insert(doFindLib(Arg->getValue()));
+
+ // Handle /nodefaultlib
+ if (Args.hasArg(OPT_nodefaultlib_all))
+ Config->NoDefaultLibAll = true;
+
+ // Handle /base
+ if (auto *Arg = Args.getLastArg(OPT_base))
+ parseNumbers(Arg->getValue(), &Config->ImageBase);
+
+ // Handle /stack
+ if (auto *Arg = Args.getLastArg(OPT_stack))
+ parseNumbers(Arg->getValue(), &Config->StackReserve, &Config->StackCommit);
+
+ // Handle /guard:cf
+ if (auto *Arg = Args.getLastArg(OPT_guard))
+ parseGuard(Arg->getValue());
+
+ // Handle /heap
+ if (auto *Arg = Args.getLastArg(OPT_heap))
+ parseNumbers(Arg->getValue(), &Config->HeapReserve, &Config->HeapCommit);
+
+ // Handle /version
+ if (auto *Arg = Args.getLastArg(OPT_version))
+ parseVersion(Arg->getValue(), &Config->MajorImageVersion,
+ &Config->MinorImageVersion);
+
+ // Handle /subsystem
+ if (auto *Arg = Args.getLastArg(OPT_subsystem))
+ parseSubsystem(Arg->getValue(), &Config->Subsystem, &Config->MajorOSVersion,
+ &Config->MinorOSVersion);
+
+ // Handle /timestamp
+ if (llvm::opt::Arg *Arg = Args.getLastArg(OPT_timestamp, OPT_repro)) {
+ if (Arg->getOption().getID() == OPT_repro) {
+ Config->Timestamp = 0;
+ Config->Repro = true;
+ } else {
+ Config->Repro = false;
+ StringRef Value(Arg->getValue());
+ if (Value.getAsInteger(0, Config->Timestamp))
+ fatal(Twine("invalid timestamp: ") + Value +
+ ". Expected 32-bit integer");
+ }
+ } else {
+ Config->Repro = false;
+ Config->Timestamp = time(nullptr);
+ }
+
+ // Handle /alternatename
+ for (auto *Arg : Args.filtered(OPT_alternatename))
+ parseAlternateName(Arg->getValue());
+
+ // Handle /include
+ for (auto *Arg : Args.filtered(OPT_incl))
+ addUndefined(Arg->getValue());
+
+ // Handle /implib
+ if (auto *Arg = Args.getLastArg(OPT_implib))
+ Config->Implib = Arg->getValue();
+
+ // Handle /opt.
+ bool DoGC = Debug == DebugKind::None || Args.hasArg(OPT_profile);
+ unsigned ICFLevel =
+ Args.hasArg(OPT_profile) ? 0 : 1; // 0: off, 1: limited, 2: on
+ unsigned TailMerge = 1;
+ for (auto *Arg : Args.filtered(OPT_opt)) {
+ std::string Str = StringRef(Arg->getValue()).lower();
+ SmallVector<StringRef, 1> Vec;
+ StringRef(Str).split(Vec, ',');
+ for (StringRef S : Vec) {
+ if (S == "ref") {
+ DoGC = true;
+ } else if (S == "noref") {
+ DoGC = false;
+ } else if (S == "icf" || S.startswith("icf=")) {
+ ICFLevel = 2;
+ } else if (S == "noicf") {
+ ICFLevel = 0;
+ } else if (S == "lldtailmerge") {
+ TailMerge = 2;
+ } else if (S == "nolldtailmerge") {
+ TailMerge = 0;
+ } else if (S.startswith("lldlto=")) {
+ StringRef OptLevel = S.substr(7);
+ if (OptLevel.getAsInteger(10, Config->LTOO) || Config->LTOO > 3)
+ error("/opt:lldlto: invalid optimization level: " + OptLevel);
+ } else if (S.startswith("lldltojobs=")) {
+ StringRef Jobs = S.substr(11);
+ if (Jobs.getAsInteger(10, Config->ThinLTOJobs) ||
+ Config->ThinLTOJobs == 0)
+ error("/opt:lldltojobs: invalid job count: " + Jobs);
+ } else if (S.startswith("lldltopartitions=")) {
+ StringRef N = S.substr(17);
+ if (N.getAsInteger(10, Config->LTOPartitions) ||
+ Config->LTOPartitions == 0)
+ error("/opt:lldltopartitions: invalid partition count: " + N);
+ } else if (S != "lbr" && S != "nolbr")
+ error("/opt: unknown option: " + S);
+ }
+ }
+
+ // Limited ICF is enabled if GC is enabled and ICF was never mentioned
+ // explicitly.
+ // FIXME: LLD only implements "limited" ICF, i.e. it only merges identical
+ // code. If the user passes /OPT:ICF explicitly, LLD should merge identical
+ // comdat readonly data.
+ if (ICFLevel == 1 && !DoGC)
+ ICFLevel = 0;
+ Config->DoGC = DoGC;
+ Config->DoICF = ICFLevel > 0;
+ Config->TailMerge = (TailMerge == 1 && Config->DoICF) || TailMerge == 2;
+
+ // Handle /lldsavetemps
+ if (Args.hasArg(OPT_lldsavetemps))
+ Config->SaveTemps = true;
+
+ // Handle /kill-at
+ if (Args.hasArg(OPT_kill_at))
+ Config->KillAt = true;
+
+ // Handle /lldltocache
+ if (auto *Arg = Args.getLastArg(OPT_lldltocache))
+ Config->LTOCache = Arg->getValue();
+
+ // Handle /lldsavecachepolicy
+ if (auto *Arg = Args.getLastArg(OPT_lldltocachepolicy))
+ Config->LTOCachePolicy = CHECK(
+ parseCachePruningPolicy(Arg->getValue()),
+ Twine("/lldltocachepolicy: invalid cache policy: ") + Arg->getValue());
+
+ // Handle /failifmismatch
+ for (auto *Arg : Args.filtered(OPT_failifmismatch))
+ checkFailIfMismatch(Arg->getValue());
+
+ // Handle /merge
+ for (auto *Arg : Args.filtered(OPT_merge))
+ parseMerge(Arg->getValue());
+
+ // Add default section merging rules after user rules. User rules take
+ // precedence, but we will emit a warning if there is a conflict.
+ parseMerge(".idata=.rdata");
+ parseMerge(".didat=.rdata");
+ parseMerge(".edata=.rdata");
+ parseMerge(".xdata=.rdata");
+ parseMerge(".bss=.data");
+
+ if (Config->MinGW) {
+ parseMerge(".ctors=.rdata");
+ parseMerge(".dtors=.rdata");
+ parseMerge(".CRT=.rdata");
+ }
+
+ // Handle /section
+ for (auto *Arg : Args.filtered(OPT_section))
+ parseSection(Arg->getValue());
+
+ // Handle /aligncomm
+ for (auto *Arg : Args.filtered(OPT_aligncomm))
+ parseAligncomm(Arg->getValue());
+
+ // Handle /manifestdependency. This enables /manifest unless /manifest:no is
+ // also passed.
+ if (auto *Arg = Args.getLastArg(OPT_manifestdependency)) {
+ Config->ManifestDependency = Arg->getValue();
+ Config->Manifest = Configuration::SideBySide;
+ }
+
+ // Handle /manifest and /manifest:
+ if (auto *Arg = Args.getLastArg(OPT_manifest, OPT_manifest_colon)) {
+ if (Arg->getOption().getID() == OPT_manifest)
+ Config->Manifest = Configuration::SideBySide;
+ else
+ parseManifest(Arg->getValue());
+ }
+
+ // Handle /manifestuac
+ if (auto *Arg = Args.getLastArg(OPT_manifestuac))
+ parseManifestUAC(Arg->getValue());
+
+ // Handle /manifestfile
+ if (auto *Arg = Args.getLastArg(OPT_manifestfile))
+ Config->ManifestFile = Arg->getValue();
+
+ // Handle /manifestinput
+ for (auto *Arg : Args.filtered(OPT_manifestinput))
+ Config->ManifestInput.push_back(Arg->getValue());
+
+ if (!Config->ManifestInput.empty() &&
+ Config->Manifest != Configuration::Embed) {
+ fatal("/manifestinput: requires /manifest:embed");
+ }
+
+ // Handle miscellaneous boolean flags.
+ Config->AllowBind = Args.hasFlag(OPT_allowbind, OPT_allowbind_no, true);
+ Config->AllowIsolation =
+ Args.hasFlag(OPT_allowisolation, OPT_allowisolation_no, true);
+ Config->Incremental =
+ Args.hasFlag(OPT_incremental, OPT_incremental_no,
+ !Config->DoGC && !Config->DoICF && !Args.hasArg(OPT_order) &&
+ !Args.hasArg(OPT_profile));
+ Config->IntegrityCheck =
+ Args.hasFlag(OPT_integritycheck, OPT_integritycheck_no, false);
+ Config->NxCompat = Args.hasFlag(OPT_nxcompat, OPT_nxcompat_no, true);
+ Config->TerminalServerAware =
+ !Config->DLL && Args.hasFlag(OPT_tsaware, OPT_tsaware_no, true);
+ Config->DebugDwarf = Debug == DebugKind::Dwarf;
+ Config->DebugGHashes = Debug == DebugKind::GHash;
+ Config->DebugSymtab = Debug == DebugKind::Symtab;
+
+ Config->MapFile = getMapFile(Args);
+
+ if (Config->Incremental && Args.hasArg(OPT_profile)) {
+ warn("ignoring '/incremental' due to '/profile' specification");
+ Config->Incremental = false;
+ }
+
+ if (Config->Incremental && Args.hasArg(OPT_order)) {
+ warn("ignoring '/incremental' due to '/order' specification");
+ Config->Incremental = false;
+ }
+
+ if (Config->Incremental && Config->DoGC) {
+ warn("ignoring '/incremental' because REF is enabled; use '/opt:noref' to "
+ "disable");
+ Config->Incremental = false;
+ }
+
+ if (Config->Incremental && Config->DoICF) {
+ warn("ignoring '/incremental' because ICF is enabled; use '/opt:noicf' to "
+ "disable");
+ Config->Incremental = false;
+ }
+
+ if (errorCount())
+ return;
+
+ std::set<sys::fs::UniqueID> WholeArchives;
+ AutoExporter Exporter;
+ for (auto *Arg : Args.filtered(OPT_wholearchive_file)) {
+ if (Optional<StringRef> Path = doFindFile(Arg->getValue())) {
+ if (Optional<sys::fs::UniqueID> ID = getUniqueID(*Path))
+ WholeArchives.insert(*ID);
+ Exporter.addWholeArchive(*Path);
+ }
+ }
+
+ // A predicate returning true if a given path is an argument for
+ // /wholearchive:, or /wholearchive is enabled globally.
+ // This function is a bit tricky because "foo.obj /wholearchive:././foo.obj"
+ // needs to be handled as "/wholearchive:foo.obj foo.obj".
+ auto IsWholeArchive = [&](StringRef Path) -> bool {
+ if (Args.hasArg(OPT_wholearchive_flag))
+ return true;
+ if (Optional<sys::fs::UniqueID> ID = getUniqueID(Path))
+ return WholeArchives.count(*ID);
+ return false;
+ };
+
+ // Create a list of input files. Files can be given as arguments
+ // for /defaultlib option.
+ for (auto *Arg : Args.filtered(OPT_INPUT, OPT_wholearchive_file))
+ if (Optional<StringRef> Path = findFile(Arg->getValue()))
+ enqueuePath(*Path, IsWholeArchive(*Path));
+
+ for (auto *Arg : Args.filtered(OPT_defaultlib))
+ if (Optional<StringRef> Path = findLib(Arg->getValue()))
+ enqueuePath(*Path, false);
+
+ // Windows specific -- Create a resource file containing a manifest file.
+ if (Config->Manifest == Configuration::Embed)
+ addBuffer(createManifestRes(), false);
+
+ // Read all input files given via the command line.
+ run();
+
+ if (errorCount())
+ return;
+
+ // We should have inferred a machine type by now from the input files, but if
+ // not we assume x64.
+ if (Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN) {
+ warn("/machine is not specified. x64 is assumed");
+ Config->Machine = AMD64;
+ }
+ Config->Wordsize = Config->is64() ? 8 : 4;
+
+ // Input files can be Windows resource files (.res files). We use
+ // WindowsResource to convert resource files to a regular COFF file,
+ // then link the resulting file normally.
+ if (!Resources.empty())
+ Symtab->addFile(make<ObjFile>(convertResToCOFF(Resources)));
+
+ if (Tar)
+ Tar->append("response.txt",
+ createResponseFile(Args, FilePaths,
+ ArrayRef<StringRef>(SearchPaths).slice(1)));
+
+ // Handle /largeaddressaware
+ Config->LargeAddressAware = Args.hasFlag(
+ OPT_largeaddressaware, OPT_largeaddressaware_no, Config->is64());
+
+ // Handle /highentropyva
+ Config->HighEntropyVA =
+ Config->is64() &&
+ Args.hasFlag(OPT_highentropyva, OPT_highentropyva_no, true);
+
+ if (!Config->DynamicBase &&
+ (Config->Machine == ARMNT || Config->Machine == ARM64))
+ error("/dynamicbase:no is not compatible with " +
+ machineToStr(Config->Machine));
+
+ // Handle /export
+ for (auto *Arg : Args.filtered(OPT_export)) {
+ Export E = parseExport(Arg->getValue());
+ if (Config->Machine == I386) {
+ if (!isDecorated(E.Name))
+ E.Name = Saver.save("_" + E.Name);
+ if (!E.ExtName.empty() && !isDecorated(E.ExtName))
+ E.ExtName = Saver.save("_" + E.ExtName);
+ }
+ Config->Exports.push_back(E);
+ }
+
+ // Handle /def
+ if (auto *Arg = Args.getLastArg(OPT_deffile)) {
+ // parseModuleDefs mutates Config object.
+ parseModuleDefs(Arg->getValue());
+ }
+
+ // Handle generation of import library from a def file.
+ if (!Args.hasArg(OPT_INPUT)) {
+ fixupExports();
+ createImportLibrary(/*AsLib=*/true);
+ return;
+ }
+
+ // Windows specific -- if no /subsystem is given, we need to infer
+ // that from entry point name. Must happen before /entry handling,
+ // and after the early return when just writing an import library.
+ if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) {
+ Config->Subsystem = inferSubsystem();
+ if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN)
+ fatal("subsystem must be defined");
+ }
+
+ // Handle /entry and /dll
+ if (auto *Arg = Args.getLastArg(OPT_entry)) {
+ Config->Entry = addUndefined(mangle(Arg->getValue()));
+ } else if (!Config->Entry && !Config->NoEntry) {
+ if (Args.hasArg(OPT_dll)) {
+ StringRef S = (Config->Machine == I386) ? "__DllMainCRTStartup@12"
+ : "_DllMainCRTStartup";
+ Config->Entry = addUndefined(S);
+ } else {
+ // Windows specific -- If entry point name is not given, we need to
+ // infer that from user-defined entry name.
+ StringRef S = findDefaultEntry();
+ if (S.empty())
+ fatal("entry point must be defined");
+ Config->Entry = addUndefined(S);
+ log("Entry name inferred: " + S);
+ }
+ }
+
+ // Handle /delayload
+ for (auto *Arg : Args.filtered(OPT_delayload)) {
+ Config->DelayLoads.insert(StringRef(Arg->getValue()).lower());
+ if (Config->Machine == I386) {
+ Config->DelayLoadHelper = addUndefined("___delayLoadHelper2@8");
+ } else {
+ Config->DelayLoadHelper = addUndefined("__delayLoadHelper2");
+ }
+ }
+
+ // Set default image name if neither /out or /def set it.
+ if (Config->OutputFile.empty()) {
+ Config->OutputFile =
+ getOutputPath((*Args.filtered(OPT_INPUT).begin())->getValue());
+ }
+
+ if (ShouldCreatePDB) {
+ // Put the PDB next to the image if no /pdb flag was passed.
+ if (Config->PDBPath.empty()) {
+ Config->PDBPath = Config->OutputFile;
+ sys::path::replace_extension(Config->PDBPath, ".pdb");
+ }
+
+ // The embedded PDB path should be the absolute path to the PDB if no
+ // /pdbaltpath flag was passed.
+ if (Config->PDBAltPath.empty()) {
+ Config->PDBAltPath = Config->PDBPath;
+
+ // It's important to make the path absolute and remove dots. This path
+ // will eventually be written into the PE header, and certain Microsoft
+ // tools won't work correctly if these assumptions are not held.
+ sys::fs::make_absolute(Config->PDBAltPath);
+ sys::path::remove_dots(Config->PDBAltPath);
+ } else {
+ // Don't do this earlier, so that Config->OutputFile is ready.
+ parsePDBAltPath(Config->PDBAltPath);
+ }
+ }
+
+ // Set default image base if /base is not given.
+ if (Config->ImageBase == uint64_t(-1))
+ Config->ImageBase = getDefaultImageBase();
+
+ Symtab->addSynthetic(mangle("__ImageBase"), nullptr);
+ if (Config->Machine == I386) {
+ Symtab->addAbsolute("___safe_se_handler_table", 0);
+ Symtab->addAbsolute("___safe_se_handler_count", 0);
+ }
+
+ Symtab->addAbsolute(mangle("__guard_fids_count"), 0);
+ Symtab->addAbsolute(mangle("__guard_fids_table"), 0);
+ Symtab->addAbsolute(mangle("__guard_flags"), 0);
+ Symtab->addAbsolute(mangle("__guard_iat_count"), 0);
+ Symtab->addAbsolute(mangle("__guard_iat_table"), 0);
+ Symtab->addAbsolute(mangle("__guard_longjmp_count"), 0);
+ Symtab->addAbsolute(mangle("__guard_longjmp_table"), 0);
+ // Needed for MSVC 2017 15.5 CRT.
+ Symtab->addAbsolute(mangle("__enclave_config"), 0);
+
+ if (Config->MinGW) {
+ Symtab->addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST__"), 0);
+ Symtab->addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST_END__"), 0);
+ Symtab->addAbsolute(mangle("__CTOR_LIST__"), 0);
+ Symtab->addAbsolute(mangle("__DTOR_LIST__"), 0);
+ }
+
+ // This code may add new undefined symbols to the link, which may enqueue more
+ // symbol resolution tasks, so we need to continue executing tasks until we
+ // converge.
+ do {
+ // Windows specific -- if entry point is not found,
+ // search for its mangled names.
+ if (Config->Entry)
+ Symtab->mangleMaybe(Config->Entry);
+
+ // Windows specific -- Make sure we resolve all dllexported symbols.
+ for (Export &E : Config->Exports) {
+ if (!E.ForwardTo.empty())
+ continue;
+ E.Sym = addUndefined(E.Name);
+ if (!E.Directives)
+ Symtab->mangleMaybe(E.Sym);
+ }
+
+ // Add weak aliases. Weak aliases is a mechanism to give remaining
+ // undefined symbols final chance to be resolved successfully.
+ for (auto Pair : Config->AlternateNames) {
+ StringRef From = Pair.first;
+ StringRef To = Pair.second;
+ Symbol *Sym = Symtab->find(From);
+ if (!Sym)
+ continue;
+ if (auto *U = dyn_cast<Undefined>(Sym))
+ if (!U->WeakAlias)
+ U->WeakAlias = Symtab->addUndefined(To);
+ }
+
+ // Windows specific -- if __load_config_used can be resolved, resolve it.
+ if (Symtab->findUnderscore("_load_config_used"))
+ addUndefined(mangle("_load_config_used"));
+ } while (run());
+
+ if (errorCount())
+ return;
+
+ // Do LTO by compiling bitcode input files to a set of native COFF files then
+ // link those files.
+ Symtab->addCombinedLTOObjects();
+ run();
+
+ if (Config->MinGW) {
+ // Load any further object files that might be needed for doing automatic
+ // imports.
+ //
+ // For cases with no automatically imported symbols, this iterates once
+ // over the symbol table and doesn't do anything.
+ //
+ // For the normal case with a few automatically imported symbols, this
+ // should only need to be run once, since each new object file imported
+ // is an import library and wouldn't add any new undefined references,
+ // but there's nothing stopping the __imp_ symbols from coming from a
+ // normal object file as well (although that won't be used for the
+ // actual autoimport later on). If this pass adds new undefined references,
+ // we won't iterate further to resolve them.
+ Symtab->loadMinGWAutomaticImports();
+ run();
+ }
+
+ // Make sure we have resolved all symbols.
+ Symtab->reportRemainingUndefines();
+ if (errorCount())
+ return;
+
+ // Handle /safeseh.
+ if (Args.hasFlag(OPT_safeseh, OPT_safeseh_no, false)) {
+ for (ObjFile *File : ObjFile::Instances)
+ if (!File->hasSafeSEH())
+ error("/safeseh: " + File->getName() + " is not compatible with SEH");
+ if (errorCount())
+ return;
+ }
+
+ // In MinGW, all symbols are automatically exported if no symbols
+ // are chosen to be exported.
+ if (Config->DLL && ((Config->MinGW && Config->Exports.empty()) ||
+ Args.hasArg(OPT_export_all_symbols))) {
+ Exporter.initSymbolExcludes();
+
+ Symtab->forEachSymbol([=](Symbol *S) {
+ auto *Def = dyn_cast<Defined>(S);
+ if (!Exporter.shouldExport(Def))
+ return;
+ Export E;
+ E.Name = Def->getName();
+ E.Sym = Def;
+ if (Def->getChunk() &&
+ !(Def->getChunk()->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE))
+ E.Data = true;
+ Config->Exports.push_back(E);
+ });
+ }
+
+ // Windows specific -- when we are creating a .dll file, we also
+ // need to create a .lib file.
+ if (!Config->Exports.empty() || Config->DLL) {
+ fixupExports();
+ createImportLibrary(/*AsLib=*/false);
+ assignExportOrdinals();
+ }
+
+ // Handle /output-def (MinGW specific).
+ if (auto *Arg = Args.getLastArg(OPT_output_def))
+ writeDefFile(Arg->getValue());
+
+ // Set extra alignment for .comm symbols
+ for (auto Pair : Config->AlignComm) {
+ StringRef Name = Pair.first;
+ uint32_t Alignment = Pair.second;
+
+ Symbol *Sym = Symtab->find(Name);
+ if (!Sym) {
+ warn("/aligncomm symbol " + Name + " not found");
+ continue;
+ }
+
+ // If the symbol isn't common, it must have been replaced with a regular
+ // symbol, which will carry its own alignment.
+ auto *DC = dyn_cast<DefinedCommon>(Sym);
+ if (!DC)
+ continue;
+
+ CommonChunk *C = DC->getChunk();
+ C->Alignment = std::max(C->Alignment, Alignment);
+ }
+
+ // Windows specific -- Create a side-by-side manifest file.
+ if (Config->Manifest == Configuration::SideBySide)
+ createSideBySideManifest();
+
+ // Handle /order. We want to do this at this moment because we
+ // need a complete list of comdat sections to warn on nonexistent
+ // functions.
+ if (auto *Arg = Args.getLastArg(OPT_order))
+ parseOrderFile(Arg->getValue());
+
+ // Identify unreferenced COMDAT sections.
+ if (Config->DoGC)
+ markLive(Symtab->getChunks());
+
+ // Identify identical COMDAT sections to merge them.
+ if (Config->DoICF) {
+ findKeepUniqueSections();
+ doICF(Symtab->getChunks());
+ }
+
+ // Write the result.
+ writeResult();
+
+ // Stop early so we can print the results.
+ Timer::root().stop();
+ if (Config->ShowTiming)
+ Timer::root().print();
+}
+
+} // namespace coff
+} // namespace lld
diff --git a/contrib/llvm/tools/lld/COFF/Driver.h b/contrib/llvm/tools/lld/COFF/Driver.h
new file mode 100644
index 000000000000..e779721ab75d
--- /dev/null
+++ b/contrib/llvm/tools/lld/COFF/Driver.h
@@ -0,0 +1,197 @@
+//===- Driver.h -------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_DRIVER_H
+#define LLD_COFF_DRIVER_H
+
+#include "Config.h"
+#include "SymbolTable.h"
+#include "lld/Common/LLVM.h"
+#include "lld/Common/Reproduce.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/TarWriter.h"
+#include <memory>
+#include <set>
+#include <vector>
+
+namespace lld {
+namespace coff {
+
+class LinkerDriver;
+extern LinkerDriver *Driver;
+
+using llvm::COFF::MachineTypes;
+using llvm::COFF::WindowsSubsystem;
+using llvm::Optional;
+
+class COFFOptTable : public llvm::opt::OptTable {
+public:
+ COFFOptTable();
+};
+
+class ArgParser {
+public:
+ // Concatenate LINK environment variable and given arguments and parse them.
+ llvm::opt::InputArgList parseLINK(std::vector<const char *> Args);
+
+ // Tokenizes a given string and then parses as command line options.
+ llvm::opt::InputArgList parse(StringRef S) { return parse(tokenize(S)); }
+
+ // Tokenizes a given string and then parses as command line options in
+ // .drectve section. /EXPORT options are returned in second element
+ // to be processed in fastpath.
+ std::pair<llvm::opt::InputArgList, std::vector<StringRef>>
+ parseDirectives(StringRef S);
+
+private:
+ // Parses command line options.
+ llvm::opt::InputArgList parse(llvm::ArrayRef<const char *> Args);
+
+ std::vector<const char *> tokenize(StringRef S);
+
+ COFFOptTable Table;
+};
+
+class LinkerDriver {
+public:
+ void link(llvm::ArrayRef<const char *> Args);
+
+ // Used by the resolver to parse .drectve section contents.
+ void parseDirectives(StringRef S);
+
+ // Used by ArchiveFile to enqueue members.
+ void enqueueArchiveMember(const Archive::Child &C, StringRef SymName,
+ StringRef ParentName);
+
+ MemoryBufferRef takeBuffer(std::unique_ptr<MemoryBuffer> MB);
+
+private:
+ std::unique_ptr<llvm::TarWriter> Tar; // for /linkrepro
+
+ // Opens a file. Path has to be resolved already.
+ MemoryBufferRef openFile(StringRef Path);
+
+ // Searches a file from search paths.
+ Optional<StringRef> findFile(StringRef Filename);
+ Optional<StringRef> findLib(StringRef Filename);
+ StringRef doFindFile(StringRef Filename);
+ StringRef doFindLib(StringRef Filename);
+ StringRef doFindLibMinGW(StringRef Filename);
+
+ // Parses LIB environment which contains a list of search paths.
+ void addLibSearchPaths();
+
+ // Library search path. The first element is always "" (current directory).
+ std::vector<StringRef> SearchPaths;
+
+ // We don't want to add the same file more than once.
+ // Files are uniquified by their filesystem and file number.
+ std::set<llvm::sys::fs::UniqueID> VisitedFiles;
+
+ std::set<std::string> VisitedLibs;
+
+ Symbol *addUndefined(StringRef Sym);
+
+ // Windows specific -- "main" is not the only main function in Windows.
+ // You can choose one from these four -- {w,}{WinMain,main}.
+ // There are four different entry point functions for them,
+ // {w,}{WinMain,main}CRTStartup, respectively. The linker needs to
+ // choose the right one depending on which "main" function is defined.
+ // This function looks up the symbol table and resolve corresponding
+ // entry point name.
+ StringRef findDefaultEntry();
+ WindowsSubsystem inferSubsystem();
+
+ void addBuffer(std::unique_ptr<MemoryBuffer> MB, bool WholeArchive);
+ void addArchiveBuffer(MemoryBufferRef MBRef, StringRef SymName,
+ StringRef ParentName);
+
+ void enqueuePath(StringRef Path, bool WholeArchive);
+
+ void enqueueTask(std::function<void()> Task);
+ bool run();
+
+ std::list<std::function<void()>> TaskQueue;
+ std::vector<StringRef> FilePaths;
+ std::vector<MemoryBufferRef> Resources;
+
+ llvm::StringSet<> DirectivesExports;
+};
+
+// Functions below this line are defined in DriverUtils.cpp.
+
+void printHelp(const char *Argv0);
+
+// For /machine option.
+MachineTypes getMachineType(StringRef Arg);
+StringRef machineToStr(MachineTypes MT);
+
+// Parses a string in the form of "<integer>[,<integer>]".
+void parseNumbers(StringRef Arg, uint64_t *Addr, uint64_t *Size = nullptr);
+
+void parseGuard(StringRef Arg);
+
+// Parses a string in the form of "<integer>[.<integer>]".
+// Minor's default value is 0.
+void parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor);
+
+// Parses a string in the form of "<subsystem>[,<integer>[.<integer>]]".
+void parseSubsystem(StringRef Arg, WindowsSubsystem *Sys, uint32_t *Major,
+ uint32_t *Minor);
+
+void parseAlternateName(StringRef);
+void parseMerge(StringRef);
+void parseSection(StringRef);
+void parseAligncomm(StringRef);
+
+// Parses a string in the form of "EMBED[,=<integer>]|NO".
+void parseManifest(StringRef Arg);
+
+// Parses a string in the form of "level=<string>|uiAccess=<string>"
+void parseManifestUAC(StringRef Arg);
+
+// Create a resource file containing a manifest XML.
+std::unique_ptr<MemoryBuffer> createManifestRes();
+void createSideBySideManifest();
+
+// Used for dllexported symbols.
+Export parseExport(StringRef Arg);
+void fixupExports();
+void assignExportOrdinals();
+
+// Parses a string in the form of "key=value" and check
+// if value matches previous values for the key.
+// This feature used in the directive section to reject
+// incompatible objects.
+void checkFailIfMismatch(StringRef Arg);
+
+// Convert Windows resource files (.res files) to a .obj file.
+MemoryBufferRef convertResToCOFF(ArrayRef<MemoryBufferRef> MBs);
+
+void runMSVCLinker(std::string Rsp, ArrayRef<StringRef> Objects);
+
+// Create enum with OPT_xxx values for each option in Options.td
+enum {
+ OPT_INVALID = 0,
+#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID,
+#include "Options.inc"
+#undef OPTION
+};
+
+} // namespace coff
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/COFF/DriverUtils.cpp b/contrib/llvm/tools/lld/COFF/DriverUtils.cpp
new file mode 100644
index 000000000000..3a11895497a4
--- /dev/null
+++ b/contrib/llvm/tools/lld/COFF/DriverUtils.cpp
@@ -0,0 +1,872 @@
+//===- DriverUtils.cpp ----------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains utility functions for the driver. Because there
+// are so many small functions, we created this separate file to make
+// Driver.cpp less cluttered.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Config.h"
+#include "Driver.h"
+#include "Symbols.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Memory.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Object/WindowsResource.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileUtilities.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/WindowsManifest/WindowsManifestMerger.h"
+#include <memory>
+
+using namespace llvm::COFF;
+using namespace llvm;
+using llvm::sys::Process;
+
+namespace lld {
+namespace coff {
+namespace {
+
+const uint16_t SUBLANG_ENGLISH_US = 0x0409;
+const uint16_t RT_MANIFEST = 24;
+
+class Executor {
+public:
+ explicit Executor(StringRef S) : Prog(Saver.save(S)) {}
+ void add(StringRef S) { Args.push_back(Saver.save(S)); }
+ void add(std::string &S) { Args.push_back(Saver.save(S)); }
+ void add(Twine S) { Args.push_back(Saver.save(S)); }
+ void add(const char *S) { Args.push_back(Saver.save(S)); }
+
+ void run() {
+ ErrorOr<std::string> ExeOrErr = sys::findProgramByName(Prog);
+ if (auto EC = ExeOrErr.getError())
+ fatal("unable to find " + Prog + " in PATH: " + EC.message());
+ StringRef Exe = Saver.save(*ExeOrErr);
+ Args.insert(Args.begin(), Exe);
+
+ if (sys::ExecuteAndWait(Args[0], Args) != 0)
+ fatal("ExecuteAndWait failed: " +
+ llvm::join(Args.begin(), Args.end(), " "));
+ }
+
+private:
+ StringRef Prog;
+ std::vector<StringRef> Args;
+};
+
+} // anonymous namespace
+
+// Returns /machine's value.
+MachineTypes getMachineType(StringRef S) {
+ MachineTypes MT = StringSwitch<MachineTypes>(S.lower())
+ .Cases("x64", "amd64", AMD64)
+ .Cases("x86", "i386", I386)
+ .Case("arm", ARMNT)
+ .Case("arm64", ARM64)
+ .Default(IMAGE_FILE_MACHINE_UNKNOWN);
+ if (MT != IMAGE_FILE_MACHINE_UNKNOWN)
+ return MT;
+ fatal("unknown /machine argument: " + S);
+}
+
+StringRef machineToStr(MachineTypes MT) {
+ switch (MT) {
+ case ARMNT:
+ return "arm";
+ case ARM64:
+ return "arm64";
+ case AMD64:
+ return "x64";
+ case I386:
+ return "x86";
+ default:
+ llvm_unreachable("unknown machine type");
+ }
+}
+
+// Parses a string in the form of "<integer>[,<integer>]".
+void parseNumbers(StringRef Arg, uint64_t *Addr, uint64_t *Size) {
+ StringRef S1, S2;
+ std::tie(S1, S2) = Arg.split(',');
+ if (S1.getAsInteger(0, *Addr))
+ fatal("invalid number: " + S1);
+ if (Size && !S2.empty() && S2.getAsInteger(0, *Size))
+ fatal("invalid number: " + S2);
+}
+
+// Parses a string in the form of "<integer>[.<integer>]".
+// If second number is not present, Minor is set to 0.
+void parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor) {
+ StringRef S1, S2;
+ std::tie(S1, S2) = Arg.split('.');
+ if (S1.getAsInteger(0, *Major))
+ fatal("invalid number: " + S1);
+ *Minor = 0;
+ if (!S2.empty() && S2.getAsInteger(0, *Minor))
+ fatal("invalid number: " + S2);
+}
+
+void parseGuard(StringRef FullArg) {
+ SmallVector<StringRef, 1> SplitArgs;
+ FullArg.split(SplitArgs, ",");
+ for (StringRef Arg : SplitArgs) {
+ if (Arg.equals_lower("no"))
+ Config->GuardCF = GuardCFLevel::Off;
+ else if (Arg.equals_lower("nolongjmp"))
+ Config->GuardCF = GuardCFLevel::NoLongJmp;
+ else if (Arg.equals_lower("cf") || Arg.equals_lower("longjmp"))
+ Config->GuardCF = GuardCFLevel::Full;
+ else
+ fatal("invalid argument to /guard: " + Arg);
+ }
+}
+
+// Parses a string in the form of "<subsystem>[,<integer>[.<integer>]]".
+void parseSubsystem(StringRef Arg, WindowsSubsystem *Sys, uint32_t *Major,
+ uint32_t *Minor) {
+ StringRef SysStr, Ver;
+ std::tie(SysStr, Ver) = Arg.split(',');
+ *Sys = StringSwitch<WindowsSubsystem>(SysStr.lower())
+ .Case("boot_application", IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION)
+ .Case("console", IMAGE_SUBSYSTEM_WINDOWS_CUI)
+ .Case("efi_application", IMAGE_SUBSYSTEM_EFI_APPLICATION)
+ .Case("efi_boot_service_driver", IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER)
+ .Case("efi_rom", IMAGE_SUBSYSTEM_EFI_ROM)
+ .Case("efi_runtime_driver", IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER)
+ .Case("native", IMAGE_SUBSYSTEM_NATIVE)
+ .Case("posix", IMAGE_SUBSYSTEM_POSIX_CUI)
+ .Case("windows", IMAGE_SUBSYSTEM_WINDOWS_GUI)
+ .Default(IMAGE_SUBSYSTEM_UNKNOWN);
+ if (*Sys == IMAGE_SUBSYSTEM_UNKNOWN)
+ fatal("unknown subsystem: " + SysStr);
+ if (!Ver.empty())
+ parseVersion(Ver, Major, Minor);
+}
+
+// Parse a string of the form of "<from>=<to>".
+// Results are directly written to Config.
+void parseAlternateName(StringRef S) {
+ StringRef From, To;
+ std::tie(From, To) = S.split('=');
+ if (From.empty() || To.empty())
+ fatal("/alternatename: invalid argument: " + S);
+ auto It = Config->AlternateNames.find(From);
+ if (It != Config->AlternateNames.end() && It->second != To)
+ fatal("/alternatename: conflicts: " + S);
+ Config->AlternateNames.insert(It, std::make_pair(From, To));
+}
+
+// Parse a string of the form of "<from>=<to>".
+// Results are directly written to Config.
+void parseMerge(StringRef S) {
+ StringRef From, To;
+ std::tie(From, To) = S.split('=');
+ if (From.empty() || To.empty())
+ fatal("/merge: invalid argument: " + S);
+ if (From == ".rsrc" || To == ".rsrc")
+ fatal("/merge: cannot merge '.rsrc' with any section");
+ if (From == ".reloc" || To == ".reloc")
+ fatal("/merge: cannot merge '.reloc' with any section");
+ auto Pair = Config->Merge.insert(std::make_pair(From, To));
+ bool Inserted = Pair.second;
+ if (!Inserted) {
+ StringRef Existing = Pair.first->second;
+ if (Existing != To)
+ warn(S + ": already merged into " + Existing);
+ }
+}
+
+static uint32_t parseSectionAttributes(StringRef S) {
+ uint32_t Ret = 0;
+ for (char C : S.lower()) {
+ switch (C) {
+ case 'd':
+ Ret |= IMAGE_SCN_MEM_DISCARDABLE;
+ break;
+ case 'e':
+ Ret |= IMAGE_SCN_MEM_EXECUTE;
+ break;
+ case 'k':
+ Ret |= IMAGE_SCN_MEM_NOT_CACHED;
+ break;
+ case 'p':
+ Ret |= IMAGE_SCN_MEM_NOT_PAGED;
+ break;
+ case 'r':
+ Ret |= IMAGE_SCN_MEM_READ;
+ break;
+ case 's':
+ Ret |= IMAGE_SCN_MEM_SHARED;
+ break;
+ case 'w':
+ Ret |= IMAGE_SCN_MEM_WRITE;
+ break;
+ default:
+ fatal("/section: invalid argument: " + S);
+ }
+ }
+ return Ret;
+}
+
+// Parses /section option argument.
+void parseSection(StringRef S) {
+ StringRef Name, Attrs;
+ std::tie(Name, Attrs) = S.split(',');
+ if (Name.empty() || Attrs.empty())
+ fatal("/section: invalid argument: " + S);
+ Config->Section[Name] = parseSectionAttributes(Attrs);
+}
+
+// Parses /aligncomm option argument.
+void parseAligncomm(StringRef S) {
+ StringRef Name, Align;
+ std::tie(Name, Align) = S.split(',');
+ if (Name.empty() || Align.empty()) {
+ error("/aligncomm: invalid argument: " + S);
+ return;
+ }
+ int V;
+ if (Align.getAsInteger(0, V)) {
+ error("/aligncomm: invalid argument: " + S);
+ return;
+ }
+ Config->AlignComm[Name] = std::max(Config->AlignComm[Name], 1 << V);
+}
+
+// Parses a string in the form of "EMBED[,=<integer>]|NO".
+// Results are directly written to Config.
+void parseManifest(StringRef Arg) {
+ if (Arg.equals_lower("no")) {
+ Config->Manifest = Configuration::No;
+ return;
+ }
+ if (!Arg.startswith_lower("embed"))
+ fatal("invalid option " + Arg);
+ Config->Manifest = Configuration::Embed;
+ Arg = Arg.substr(strlen("embed"));
+ if (Arg.empty())
+ return;
+ if (!Arg.startswith_lower(",id="))
+ fatal("invalid option " + Arg);
+ Arg = Arg.substr(strlen(",id="));
+ if (Arg.getAsInteger(0, Config->ManifestID))
+ fatal("invalid option " + Arg);
+}
+
+// Parses a string in the form of "level=<string>|uiAccess=<string>|NO".
+// Results are directly written to Config.
+void parseManifestUAC(StringRef Arg) {
+ if (Arg.equals_lower("no")) {
+ Config->ManifestUAC = false;
+ return;
+ }
+ for (;;) {
+ Arg = Arg.ltrim();
+ if (Arg.empty())
+ return;
+ if (Arg.startswith_lower("level=")) {
+ Arg = Arg.substr(strlen("level="));
+ std::tie(Config->ManifestLevel, Arg) = Arg.split(" ");
+ continue;
+ }
+ if (Arg.startswith_lower("uiaccess=")) {
+ Arg = Arg.substr(strlen("uiaccess="));
+ std::tie(Config->ManifestUIAccess, Arg) = Arg.split(" ");
+ continue;
+ }
+ fatal("invalid option " + Arg);
+ }
+}
+
+// An RAII temporary file class that automatically removes a temporary file.
+namespace {
+class TemporaryFile {
+public:
+ TemporaryFile(StringRef Prefix, StringRef Extn, StringRef Contents = "") {
+ SmallString<128> S;
+ if (auto EC = sys::fs::createTemporaryFile("lld-" + Prefix, Extn, S))
+ fatal("cannot create a temporary file: " + EC.message());
+ Path = S.str();
+
+ if (!Contents.empty()) {
+ std::error_code EC;
+ raw_fd_ostream OS(Path, EC, sys::fs::F_None);
+ if (EC)
+ fatal("failed to open " + Path + ": " + EC.message());
+ OS << Contents;
+ }
+ }
+
+ TemporaryFile(TemporaryFile &&Obj) {
+ std::swap(Path, Obj.Path);
+ }
+
+ ~TemporaryFile() {
+ if (Path.empty())
+ return;
+ if (sys::fs::remove(Path))
+ fatal("failed to remove " + Path);
+ }
+
+ // Returns a memory buffer of this temporary file.
+ // Note that this function does not leave the file open,
+ // so it is safe to remove the file immediately after this function
+ // is called (you cannot remove an opened file on Windows.)
+ std::unique_ptr<MemoryBuffer> getMemoryBuffer() {
+ // IsVolatileSize=true forces MemoryBuffer to not use mmap().
+ return CHECK(MemoryBuffer::getFile(Path, /*FileSize=*/-1,
+ /*RequiresNullTerminator=*/false,
+ /*IsVolatileSize=*/true),
+ "could not open " + Path);
+ }
+
+ std::string Path;
+};
+}
+
+static std::string createDefaultXml() {
+ std::string Ret;
+ raw_string_ostream OS(Ret);
+
+ // Emit the XML. Note that we do *not* verify that the XML attributes are
+ // syntactically correct. This is intentional for link.exe compatibility.
+ OS << "<?xml version=\"1.0\" standalone=\"yes\"?>\n"
+ << "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\"\n"
+ << " manifestVersion=\"1.0\">\n";
+ if (Config->ManifestUAC) {
+ OS << " <trustInfo>\n"
+ << " <security>\n"
+ << " <requestedPrivileges>\n"
+ << " <requestedExecutionLevel level=" << Config->ManifestLevel
+ << " uiAccess=" << Config->ManifestUIAccess << "/>\n"
+ << " </requestedPrivileges>\n"
+ << " </security>\n"
+ << " </trustInfo>\n";
+ }
+ if (!Config->ManifestDependency.empty()) {
+ OS << " <dependency>\n"
+ << " <dependentAssembly>\n"
+ << " <assemblyIdentity " << Config->ManifestDependency << " />\n"
+ << " </dependentAssembly>\n"
+ << " </dependency>\n";
+ }
+ OS << "</assembly>\n";
+ return OS.str();
+}
+
+static std::string createManifestXmlWithInternalMt(StringRef DefaultXml) {
+ std::unique_ptr<MemoryBuffer> DefaultXmlCopy =
+ MemoryBuffer::getMemBufferCopy(DefaultXml);
+
+ windows_manifest::WindowsManifestMerger Merger;
+ if (auto E = Merger.merge(*DefaultXmlCopy.get()))
+ fatal("internal manifest tool failed on default xml: " +
+ toString(std::move(E)));
+
+ for (StringRef Filename : Config->ManifestInput) {
+ std::unique_ptr<MemoryBuffer> Manifest =
+ check(MemoryBuffer::getFile(Filename));
+ if (auto E = Merger.merge(*Manifest.get()))
+ fatal("internal manifest tool failed on file " + Filename + ": " +
+ toString(std::move(E)));
+ }
+
+ return Merger.getMergedManifest().get()->getBuffer();
+}
+
+static std::string createManifestXmlWithExternalMt(StringRef DefaultXml) {
+ // Create the default manifest file as a temporary file.
+ TemporaryFile Default("defaultxml", "manifest");
+ std::error_code EC;
+ raw_fd_ostream OS(Default.Path, EC, sys::fs::F_Text);
+ if (EC)
+ fatal("failed to open " + Default.Path + ": " + EC.message());
+ OS << DefaultXml;
+ OS.close();
+
+ // Merge user-supplied manifests if they are given. Since libxml2 is not
+ // enabled, we must shell out to Microsoft's mt.exe tool.
+ TemporaryFile User("user", "manifest");
+
+ Executor E("mt.exe");
+ E.add("/manifest");
+ E.add(Default.Path);
+ for (StringRef Filename : Config->ManifestInput) {
+ E.add("/manifest");
+ E.add(Filename);
+ }
+ E.add("/nologo");
+ E.add("/out:" + StringRef(User.Path));
+ E.run();
+
+ return CHECK(MemoryBuffer::getFile(User.Path), "could not open " + User.Path)
+ .get()
+ ->getBuffer();
+}
+
+static std::string createManifestXml() {
+ std::string DefaultXml = createDefaultXml();
+ if (Config->ManifestInput.empty())
+ return DefaultXml;
+
+ if (windows_manifest::isAvailable())
+ return createManifestXmlWithInternalMt(DefaultXml);
+
+ return createManifestXmlWithExternalMt(DefaultXml);
+}
+
+static std::unique_ptr<WritableMemoryBuffer>
+createMemoryBufferForManifestRes(size_t ManifestSize) {
+ size_t ResSize = alignTo(
+ object::WIN_RES_MAGIC_SIZE + object::WIN_RES_NULL_ENTRY_SIZE +
+ sizeof(object::WinResHeaderPrefix) + sizeof(object::WinResIDs) +
+ sizeof(object::WinResHeaderSuffix) + ManifestSize,
+ object::WIN_RES_DATA_ALIGNMENT);
+ return WritableMemoryBuffer::getNewMemBuffer(ResSize, Config->OutputFile +
+ ".manifest.res");
+}
+
+static void writeResFileHeader(char *&Buf) {
+ memcpy(Buf, COFF::WinResMagic, sizeof(COFF::WinResMagic));
+ Buf += sizeof(COFF::WinResMagic);
+ memset(Buf, 0, object::WIN_RES_NULL_ENTRY_SIZE);
+ Buf += object::WIN_RES_NULL_ENTRY_SIZE;
+}
+
+static void writeResEntryHeader(char *&Buf, size_t ManifestSize) {
+ // Write the prefix.
+ auto *Prefix = reinterpret_cast<object::WinResHeaderPrefix *>(Buf);
+ Prefix->DataSize = ManifestSize;
+ Prefix->HeaderSize = sizeof(object::WinResHeaderPrefix) +
+ sizeof(object::WinResIDs) +
+ sizeof(object::WinResHeaderSuffix);
+ Buf += sizeof(object::WinResHeaderPrefix);
+
+ // Write the Type/Name IDs.
+ auto *IDs = reinterpret_cast<object::WinResIDs *>(Buf);
+ IDs->setType(RT_MANIFEST);
+ IDs->setName(Config->ManifestID);
+ Buf += sizeof(object::WinResIDs);
+
+ // Write the suffix.
+ auto *Suffix = reinterpret_cast<object::WinResHeaderSuffix *>(Buf);
+ Suffix->DataVersion = 0;
+ Suffix->MemoryFlags = object::WIN_RES_PURE_MOVEABLE;
+ Suffix->Language = SUBLANG_ENGLISH_US;
+ Suffix->Version = 0;
+ Suffix->Characteristics = 0;
+ Buf += sizeof(object::WinResHeaderSuffix);
+}
+
+// Create a resource file containing a manifest XML.
+std::unique_ptr<MemoryBuffer> createManifestRes() {
+ std::string Manifest = createManifestXml();
+
+ std::unique_ptr<WritableMemoryBuffer> Res =
+ createMemoryBufferForManifestRes(Manifest.size());
+
+ char *Buf = Res->getBufferStart();
+ writeResFileHeader(Buf);
+ writeResEntryHeader(Buf, Manifest.size());
+
+ // Copy the manifest data into the .res file.
+ std::copy(Manifest.begin(), Manifest.end(), Buf);
+ return std::move(Res);
+}
+
+void createSideBySideManifest() {
+ std::string Path = Config->ManifestFile;
+ if (Path == "")
+ Path = Config->OutputFile + ".manifest";
+ std::error_code EC;
+ raw_fd_ostream Out(Path, EC, sys::fs::F_Text);
+ if (EC)
+ fatal("failed to create manifest: " + EC.message());
+ Out << createManifestXml();
+}
+
+// Parse a string in the form of
+// "<name>[=<internalname>][,@ordinal[,NONAME]][,DATA][,PRIVATE]"
+// or "<name>=<dllname>.<name>".
+// Used for parsing /export arguments.
+Export parseExport(StringRef Arg) {
+ Export E;
+ StringRef Rest;
+ std::tie(E.Name, Rest) = Arg.split(",");
+ if (E.Name.empty())
+ goto err;
+
+ if (E.Name.contains('=')) {
+ StringRef X, Y;
+ std::tie(X, Y) = E.Name.split("=");
+
+ // If "<name>=<dllname>.<name>".
+ if (Y.contains(".")) {
+ E.Name = X;
+ E.ForwardTo = Y;
+ return E;
+ }
+
+ E.ExtName = X;
+ E.Name = Y;
+ if (E.Name.empty())
+ goto err;
+ }
+
+ // If "<name>=<internalname>[,@ordinal[,NONAME]][,DATA][,PRIVATE]"
+ while (!Rest.empty()) {
+ StringRef Tok;
+ std::tie(Tok, Rest) = Rest.split(",");
+ if (Tok.equals_lower("noname")) {
+ if (E.Ordinal == 0)
+ goto err;
+ E.Noname = true;
+ continue;
+ }
+ if (Tok.equals_lower("data")) {
+ E.Data = true;
+ continue;
+ }
+ if (Tok.equals_lower("constant")) {
+ E.Constant = true;
+ continue;
+ }
+ if (Tok.equals_lower("private")) {
+ E.Private = true;
+ continue;
+ }
+ if (Tok.startswith("@")) {
+ int32_t Ord;
+ if (Tok.substr(1).getAsInteger(0, Ord))
+ goto err;
+ if (Ord <= 0 || 65535 < Ord)
+ goto err;
+ E.Ordinal = Ord;
+ continue;
+ }
+ goto err;
+ }
+ return E;
+
+err:
+ fatal("invalid /export: " + Arg);
+}
+
+static StringRef undecorate(StringRef Sym) {
+ if (Config->Machine != I386)
+ return Sym;
+ // In MSVC mode, a fully decorated stdcall function is exported
+ // as-is with the leading underscore (with type IMPORT_NAME).
+ // In MinGW mode, a decorated stdcall function gets the underscore
+ // removed, just like normal cdecl functions.
+ if (Sym.startswith("_") && Sym.contains('@') && !Config->MinGW)
+ return Sym;
+ return Sym.startswith("_") ? Sym.substr(1) : Sym;
+}
+
+// Convert stdcall/fastcall style symbols into unsuffixed symbols,
+// with or without a leading underscore. (MinGW specific.)
+static StringRef killAt(StringRef Sym, bool Prefix) {
+ if (Sym.empty())
+ return Sym;
+ // Strip any trailing stdcall suffix
+ Sym = Sym.substr(0, Sym.find('@', 1));
+ if (!Sym.startswith("@")) {
+ if (Prefix && !Sym.startswith("_"))
+ return Saver.save("_" + Sym);
+ return Sym;
+ }
+ // For fastcall, remove the leading @ and replace it with an
+ // underscore, if prefixes are used.
+ Sym = Sym.substr(1);
+ if (Prefix)
+ Sym = Saver.save("_" + Sym);
+ return Sym;
+}
+
+// Performs error checking on all /export arguments.
+// It also sets ordinals.
+void fixupExports() {
+ // Symbol ordinals must be unique.
+ std::set<uint16_t> Ords;
+ for (Export &E : Config->Exports) {
+ if (E.Ordinal == 0)
+ continue;
+ if (!Ords.insert(E.Ordinal).second)
+ fatal("duplicate export ordinal: " + E.Name);
+ }
+
+ for (Export &E : Config->Exports) {
+ Symbol *Sym = E.Sym;
+ if (!E.ForwardTo.empty() || !Sym) {
+ E.SymbolName = E.Name;
+ } else {
+ if (auto *U = dyn_cast<Undefined>(Sym))
+ if (U->WeakAlias)
+ Sym = U->WeakAlias;
+ E.SymbolName = Sym->getName();
+ }
+ }
+
+ for (Export &E : Config->Exports) {
+ if (!E.ForwardTo.empty()) {
+ E.ExportName = undecorate(E.Name);
+ } else {
+ E.ExportName = undecorate(E.ExtName.empty() ? E.Name : E.ExtName);
+ }
+ }
+
+ if (Config->KillAt && Config->Machine == I386) {
+ for (Export &E : Config->Exports) {
+ E.Name = killAt(E.Name, true);
+ E.ExportName = killAt(E.ExportName, false);
+ E.ExtName = killAt(E.ExtName, true);
+ E.SymbolName = killAt(E.SymbolName, true);
+ }
+ }
+
+ // Uniquefy by name.
+ DenseMap<StringRef, Export *> Map(Config->Exports.size());
+ std::vector<Export> V;
+ for (Export &E : Config->Exports) {
+ auto Pair = Map.insert(std::make_pair(E.ExportName, &E));
+ bool Inserted = Pair.second;
+ if (Inserted) {
+ V.push_back(E);
+ continue;
+ }
+ Export *Existing = Pair.first->second;
+ if (E == *Existing || E.Name != Existing->Name)
+ continue;
+ warn("duplicate /export option: " + E.Name);
+ }
+ Config->Exports = std::move(V);
+
+ // Sort by name.
+ std::sort(Config->Exports.begin(), Config->Exports.end(),
+ [](const Export &A, const Export &B) {
+ return A.ExportName < B.ExportName;
+ });
+}
+
+void assignExportOrdinals() {
+ // Assign unique ordinals if default (= 0).
+ uint16_t Max = 0;
+ for (Export &E : Config->Exports)
+ Max = std::max(Max, E.Ordinal);
+ for (Export &E : Config->Exports)
+ if (E.Ordinal == 0)
+ E.Ordinal = ++Max;
+}
+
+// Parses a string in the form of "key=value" and check
+// if value matches previous values for the same key.
+void checkFailIfMismatch(StringRef Arg) {
+ StringRef K, V;
+ std::tie(K, V) = Arg.split('=');
+ if (K.empty() || V.empty())
+ fatal("/failifmismatch: invalid argument: " + Arg);
+ StringRef Existing = Config->MustMatch[K];
+ if (!Existing.empty() && V != Existing)
+ fatal("/failifmismatch: mismatch detected: " + Existing + " and " + V +
+ " for key " + K);
+ Config->MustMatch[K] = V;
+}
+
+// Convert Windows resource files (.res files) to a .obj file.
+MemoryBufferRef convertResToCOFF(ArrayRef<MemoryBufferRef> MBs) {
+ object::WindowsResourceParser Parser;
+
+ for (MemoryBufferRef MB : MBs) {
+ std::unique_ptr<object::Binary> Bin = check(object::createBinary(MB));
+ object::WindowsResource *RF = dyn_cast<object::WindowsResource>(Bin.get());
+ if (!RF)
+ fatal("cannot compile non-resource file as resource");
+ if (auto EC = Parser.parse(RF))
+ fatal("failed to parse .res file: " + toString(std::move(EC)));
+ }
+
+ Expected<std::unique_ptr<MemoryBuffer>> E =
+ llvm::object::writeWindowsResourceCOFF(Config->Machine, Parser);
+ if (!E)
+ fatal("failed to write .res to COFF: " + toString(E.takeError()));
+
+ MemoryBufferRef MBRef = **E;
+ make<std::unique_ptr<MemoryBuffer>>(std::move(*E)); // take ownership
+ return MBRef;
+}
+
+// Create OptTable
+
+// Create prefix string literals used in Options.td
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#include "Options.inc"
+#undef PREFIX
+
+// Create table mapping all options defined in Options.td
+static const llvm::opt::OptTable::Info InfoTable[] = {
+#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \
+ {X1, X2, X10, X11, OPT_##ID, llvm::opt::Option::KIND##Class, \
+ X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12},
+#include "Options.inc"
+#undef OPTION
+};
+
+COFFOptTable::COFFOptTable() : OptTable(InfoTable, true) {}
+
+// Set color diagnostics according to --color-diagnostics={auto,always,never}
+// or --no-color-diagnostics flags.
+static void handleColorDiagnostics(opt::InputArgList &Args) {
+ auto *Arg = Args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq,
+ OPT_no_color_diagnostics);
+ if (!Arg)
+ return;
+ if (Arg->getOption().getID() == OPT_color_diagnostics) {
+ errorHandler().ColorDiagnostics = true;
+ } else if (Arg->getOption().getID() == OPT_no_color_diagnostics) {
+ errorHandler().ColorDiagnostics = false;
+ } else {
+ StringRef S = Arg->getValue();
+ if (S == "always")
+ errorHandler().ColorDiagnostics = true;
+ else if (S == "never")
+ errorHandler().ColorDiagnostics = false;
+ else if (S != "auto")
+ error("unknown option: --color-diagnostics=" + S);
+ }
+}
+
+static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &Args) {
+ if (auto *Arg = Args.getLastArg(OPT_rsp_quoting)) {
+ StringRef S = Arg->getValue();
+ if (S != "windows" && S != "posix")
+ error("invalid response file quoting: " + S);
+ if (S == "windows")
+ return cl::TokenizeWindowsCommandLine;
+ return cl::TokenizeGNUCommandLine;
+ }
+ // The COFF linker always defaults to Windows quoting.
+ return cl::TokenizeWindowsCommandLine;
+}
+
+// Parses a given list of options.
+opt::InputArgList ArgParser::parse(ArrayRef<const char *> Argv) {
+ // Make InputArgList from string vectors.
+ unsigned MissingIndex;
+ unsigned MissingCount;
+
+ // We need to get the quoting style for response files before parsing all
+ // options so we parse here before and ignore all the options but
+ // --rsp-quoting.
+ opt::InputArgList Args = Table.ParseArgs(Argv, MissingIndex, MissingCount);
+
+ // Expand response files (arguments in the form of @<filename>)
+ // and then parse the argument again.
+ SmallVector<const char *, 256> ExpandedArgv(Argv.data(), Argv.data() + Argv.size());
+ cl::ExpandResponseFiles(Saver, getQuotingStyle(Args), ExpandedArgv);
+ Args = Table.ParseArgs(makeArrayRef(ExpandedArgv).drop_front(), MissingIndex,
+ MissingCount);
+
+ // Print the real command line if response files are expanded.
+ if (Args.hasArg(OPT_verbose) && Argv.size() != ExpandedArgv.size()) {
+ std::string Msg = "Command line:";
+ for (const char *S : ExpandedArgv)
+ Msg += " " + std::string(S);
+ message(Msg);
+ }
+
+ // Save the command line after response file expansion so we can write it to
+ // the PDB if necessary.
+ Config->Argv = {ExpandedArgv.begin(), ExpandedArgv.end()};
+
+ // Handle /WX early since it converts missing argument warnings to errors.
+ errorHandler().FatalWarnings = Args.hasFlag(OPT_WX, OPT_WX_no, false);
+
+ if (MissingCount)
+ fatal(Twine(Args.getArgString(MissingIndex)) + ": missing argument");
+
+ handleColorDiagnostics(Args);
+
+ for (auto *Arg : Args.filtered(OPT_UNKNOWN))
+ warn("ignoring unknown argument: " + Arg->getSpelling());
+
+ if (Args.hasArg(OPT_lib))
+ warn("ignoring /lib since it's not the first argument");
+
+ return Args;
+}
+
+// Tokenizes and parses a given string as command line in .drective section.
+// /EXPORT options are processed in fastpath.
+std::pair<opt::InputArgList, std::vector<StringRef>>
+ArgParser::parseDirectives(StringRef S) {
+ std::vector<StringRef> Exports;
+ SmallVector<const char *, 16> Rest;
+
+ for (StringRef Tok : tokenize(S)) {
+ if (Tok.startswith_lower("/export:") || Tok.startswith_lower("-export:"))
+ Exports.push_back(Tok.substr(strlen("/export:")));
+ else
+ Rest.push_back(Tok.data());
+ }
+
+ // Make InputArgList from unparsed string vectors.
+ unsigned MissingIndex;
+ unsigned MissingCount;
+
+ opt::InputArgList Args = Table.ParseArgs(Rest, MissingIndex, MissingCount);
+
+ if (MissingCount)
+ fatal(Twine(Args.getArgString(MissingIndex)) + ": missing argument");
+ for (auto *Arg : Args.filtered(OPT_UNKNOWN))
+ warn("ignoring unknown argument: " + Arg->getSpelling());
+ return {std::move(Args), std::move(Exports)};
+}
+
+// link.exe has an interesting feature. If LINK or _LINK_ environment
+// variables exist, their contents are handled as command line strings.
+// So you can pass extra arguments using them.
+opt::InputArgList ArgParser::parseLINK(std::vector<const char *> Argv) {
+ // Concatenate LINK env and command line arguments, and then parse them.
+ if (Optional<std::string> S = Process::GetEnv("LINK")) {
+ std::vector<const char *> V = tokenize(*S);
+ Argv.insert(std::next(Argv.begin()), V.begin(), V.end());
+ }
+ if (Optional<std::string> S = Process::GetEnv("_LINK_")) {
+ std::vector<const char *> V = tokenize(*S);
+ Argv.insert(std::next(Argv.begin()), V.begin(), V.end());
+ }
+ return parse(Argv);
+}
+
+std::vector<const char *> ArgParser::tokenize(StringRef S) {
+ SmallVector<const char *, 16> Tokens;
+ cl::TokenizeWindowsCommandLine(S, Saver, Tokens);
+ return std::vector<const char *>(Tokens.begin(), Tokens.end());
+}
+
+void printHelp(const char *Argv0) {
+ COFFOptTable().PrintHelp(outs(),
+ (std::string(Argv0) + " [options] file...").c_str(),
+ "LLVM Linker", false);
+}
+
+} // namespace coff
+} // namespace lld
diff --git a/contrib/llvm/tools/lld/COFF/ICF.cpp b/contrib/llvm/tools/lld/COFF/ICF.cpp
new file mode 100644
index 000000000000..f6904eb7d24f
--- /dev/null
+++ b/contrib/llvm/tools/lld/COFF/ICF.cpp
@@ -0,0 +1,318 @@
+//===- ICF.cpp ------------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// ICF is short for Identical Code Folding. That is a size optimization to
+// identify and merge two or more read-only sections (typically functions)
+// that happened to have the same contents. It usually reduces output size
+// by a few percent.
+//
+// On Windows, ICF is enabled by default.
+//
+// See ELF/ICF.cpp for the details about the algortihm.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ICF.h"
+#include "Chunks.h"
+#include "Symbols.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Threads.h"
+#include "lld/Common/Timer.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Parallel.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/xxhash.h"
+#include <algorithm>
+#include <atomic>
+#include <vector>
+
+using namespace llvm;
+
+namespace lld {
+namespace coff {
+
+static Timer ICFTimer("ICF", Timer::root());
+
+class ICF {
+public:
+ void run(ArrayRef<Chunk *> V);
+
+private:
+ void segregate(size_t Begin, size_t End, bool Constant);
+
+ bool assocEquals(const SectionChunk *A, const SectionChunk *B);
+
+ bool equalsConstant(const SectionChunk *A, const SectionChunk *B);
+ bool equalsVariable(const SectionChunk *A, const SectionChunk *B);
+
+ uint32_t getHash(SectionChunk *C);
+ bool isEligible(SectionChunk *C);
+
+ size_t findBoundary(size_t Begin, size_t End);
+
+ void forEachClassRange(size_t Begin, size_t End,
+ std::function<void(size_t, size_t)> Fn);
+
+ void forEachClass(std::function<void(size_t, size_t)> Fn);
+
+ std::vector<SectionChunk *> Chunks;
+ int Cnt = 0;
+ std::atomic<bool> Repeat = {false};
+};
+
+// Returns true if section S is subject of ICF.
+//
+// Microsoft's documentation
+// (https://msdn.microsoft.com/en-us/library/bxwfs976.aspx; visited April
+// 2017) says that /opt:icf folds both functions and read-only data.
+// Despite that, the MSVC linker folds only functions. We found
+// a few instances of programs that are not safe for data merging.
+// Therefore, we merge only functions just like the MSVC tool. However, we also
+// merge read-only sections in a couple of cases where the address of the
+// section is insignificant to the user program and the behaviour matches that
+// of the Visual C++ linker.
+bool ICF::isEligible(SectionChunk *C) {
+ // Non-comdat chunks, dead chunks, and writable chunks are not elegible.
+ bool Writable = C->getOutputCharacteristics() & llvm::COFF::IMAGE_SCN_MEM_WRITE;
+ if (!C->isCOMDAT() || !C->Live || Writable)
+ return false;
+
+ // Code sections are eligible.
+ if (C->getOutputCharacteristics() & llvm::COFF::IMAGE_SCN_MEM_EXECUTE)
+ return true;
+
+ // .pdata and .xdata unwind info sections are eligible.
+ StringRef OutSecName = C->getSectionName().split('$').first;
+ if (OutSecName == ".pdata" || OutSecName == ".xdata")
+ return true;
+
+ // So are vtables.
+ if (C->Sym && C->Sym->getName().startswith("??_7"))
+ return true;
+
+ // Anything else not in an address-significance table is eligible.
+ return !C->KeepUnique;
+}
+
+// Split an equivalence class into smaller classes.
+void ICF::segregate(size_t Begin, size_t End, bool Constant) {
+ while (Begin < End) {
+ // Divide [Begin, End) into two. Let Mid be the start index of the
+ // second group.
+ auto Bound = std::stable_partition(
+ Chunks.begin() + Begin + 1, Chunks.begin() + End, [&](SectionChunk *S) {
+ if (Constant)
+ return equalsConstant(Chunks[Begin], S);
+ return equalsVariable(Chunks[Begin], S);
+ });
+ size_t Mid = Bound - Chunks.begin();
+
+ // Split [Begin, End) into [Begin, Mid) and [Mid, End). We use Mid as an
+ // equivalence class ID because every group ends with a unique index.
+ for (size_t I = Begin; I < Mid; ++I)
+ Chunks[I]->Class[(Cnt + 1) % 2] = Mid;
+
+ // If we created a group, we need to iterate the main loop again.
+ if (Mid != End)
+ Repeat = true;
+
+ Begin = Mid;
+ }
+}
+
+// Returns true if two sections' associative children are equal.
+bool ICF::assocEquals(const SectionChunk *A, const SectionChunk *B) {
+ auto ChildClasses = [&](const SectionChunk *SC) {
+ std::vector<uint32_t> Classes;
+ for (const SectionChunk *C : SC->children())
+ if (!C->SectionName.startswith(".debug") &&
+ C->SectionName != ".gfids$y" && C->SectionName != ".gljmp$y")
+ Classes.push_back(C->Class[Cnt % 2]);
+ return Classes;
+ };
+ return ChildClasses(A) == ChildClasses(B);
+}
+
+// Compare "non-moving" part of two sections, namely everything
+// except relocation targets.
+bool ICF::equalsConstant(const SectionChunk *A, const SectionChunk *B) {
+ if (A->Relocs.size() != B->Relocs.size())
+ return false;
+
+ // Compare relocations.
+ auto Eq = [&](const coff_relocation &R1, const coff_relocation &R2) {
+ if (R1.Type != R2.Type ||
+ R1.VirtualAddress != R2.VirtualAddress) {
+ return false;
+ }
+ Symbol *B1 = A->File->getSymbol(R1.SymbolTableIndex);
+ Symbol *B2 = B->File->getSymbol(R2.SymbolTableIndex);
+ if (B1 == B2)
+ return true;
+ if (auto *D1 = dyn_cast<DefinedRegular>(B1))
+ if (auto *D2 = dyn_cast<DefinedRegular>(B2))
+ return D1->getValue() == D2->getValue() &&
+ D1->getChunk()->Class[Cnt % 2] == D2->getChunk()->Class[Cnt % 2];
+ return false;
+ };
+ if (!std::equal(A->Relocs.begin(), A->Relocs.end(), B->Relocs.begin(), Eq))
+ return false;
+
+ // Compare section attributes and contents.
+ return A->getOutputCharacteristics() == B->getOutputCharacteristics() &&
+ A->SectionName == B->SectionName &&
+ A->Header->SizeOfRawData == B->Header->SizeOfRawData &&
+ A->Checksum == B->Checksum && A->getContents() == B->getContents() &&
+ assocEquals(A, B);
+}
+
+// Compare "moving" part of two sections, namely relocation targets.
+bool ICF::equalsVariable(const SectionChunk *A, const SectionChunk *B) {
+ // Compare relocations.
+ auto Eq = [&](const coff_relocation &R1, const coff_relocation &R2) {
+ Symbol *B1 = A->File->getSymbol(R1.SymbolTableIndex);
+ Symbol *B2 = B->File->getSymbol(R2.SymbolTableIndex);
+ if (B1 == B2)
+ return true;
+ if (auto *D1 = dyn_cast<DefinedRegular>(B1))
+ if (auto *D2 = dyn_cast<DefinedRegular>(B2))
+ return D1->getChunk()->Class[Cnt % 2] == D2->getChunk()->Class[Cnt % 2];
+ return false;
+ };
+ return std::equal(A->Relocs.begin(), A->Relocs.end(), B->Relocs.begin(),
+ Eq) &&
+ assocEquals(A, B);
+}
+
+// Find the first Chunk after Begin that has a different class from Begin.
+size_t ICF::findBoundary(size_t Begin, size_t End) {
+ for (size_t I = Begin + 1; I < End; ++I)
+ if (Chunks[Begin]->Class[Cnt % 2] != Chunks[I]->Class[Cnt % 2])
+ return I;
+ return End;
+}
+
+void ICF::forEachClassRange(size_t Begin, size_t End,
+ std::function<void(size_t, size_t)> Fn) {
+ while (Begin < End) {
+ size_t Mid = findBoundary(Begin, End);
+ Fn(Begin, Mid);
+ Begin = Mid;
+ }
+}
+
+// Call Fn on each class group.
+void ICF::forEachClass(std::function<void(size_t, size_t)> Fn) {
+ // If the number of sections are too small to use threading,
+ // call Fn sequentially.
+ if (Chunks.size() < 1024) {
+ forEachClassRange(0, Chunks.size(), Fn);
+ ++Cnt;
+ return;
+ }
+
+ // Shard into non-overlapping intervals, and call Fn in parallel.
+ // The sharding must be completed before any calls to Fn are made
+ // so that Fn can modify the Chunks in its shard without causing data
+ // races.
+ const size_t NumShards = 256;
+ size_t Step = Chunks.size() / NumShards;
+ size_t Boundaries[NumShards + 1];
+ Boundaries[0] = 0;
+ Boundaries[NumShards] = Chunks.size();
+ parallelForEachN(1, NumShards, [&](size_t I) {
+ Boundaries[I] = findBoundary((I - 1) * Step, Chunks.size());
+ });
+ parallelForEachN(1, NumShards + 1, [&](size_t I) {
+ if (Boundaries[I - 1] < Boundaries[I]) {
+ forEachClassRange(Boundaries[I - 1], Boundaries[I], Fn);
+ }
+ });
+ ++Cnt;
+}
+
+// Merge identical COMDAT sections.
+// Two sections are considered the same if their section headers,
+// contents and relocations are all the same.
+void ICF::run(ArrayRef<Chunk *> Vec) {
+ ScopedTimer T(ICFTimer);
+
+ // Collect only mergeable sections and group by hash value.
+ uint32_t NextId = 1;
+ for (Chunk *C : Vec) {
+ if (auto *SC = dyn_cast<SectionChunk>(C)) {
+ if (isEligible(SC))
+ Chunks.push_back(SC);
+ else
+ SC->Class[0] = NextId++;
+ }
+ }
+
+ // Make sure that ICF doesn't merge sections that are being handled by string
+ // tail merging.
+ for (auto &P : MergeChunk::Instances)
+ for (SectionChunk *SC : P.second->Sections)
+ SC->Class[0] = NextId++;
+
+ // Initially, we use hash values to partition sections.
+ parallelForEach(Chunks, [&](SectionChunk *SC) {
+ SC->Class[0] = xxHash64(SC->getContents());
+ });
+
+ // Combine the hashes of the sections referenced by each section into its
+ // hash.
+ for (unsigned Cnt = 0; Cnt != 2; ++Cnt) {
+ parallelForEach(Chunks, [&](SectionChunk *SC) {
+ uint32_t Hash = SC->Class[Cnt % 2];
+ for (Symbol *B : SC->symbols())
+ if (auto *Sym = dyn_cast_or_null<DefinedRegular>(B))
+ Hash += Sym->getChunk()->Class[Cnt % 2];
+ // Set MSB to 1 to avoid collisions with non-hash classs.
+ SC->Class[(Cnt + 1) % 2] = Hash | (1U << 31);
+ });
+ }
+
+ // From now on, sections in Chunks are ordered so that sections in
+ // the same group are consecutive in the vector.
+ std::stable_sort(Chunks.begin(), Chunks.end(),
+ [](SectionChunk *A, SectionChunk *B) {
+ return A->Class[0] < B->Class[0];
+ });
+
+ // Compare static contents and assign unique IDs for each static content.
+ forEachClass([&](size_t Begin, size_t End) { segregate(Begin, End, true); });
+
+ // Split groups by comparing relocations until convergence is obtained.
+ do {
+ Repeat = false;
+ forEachClass(
+ [&](size_t Begin, size_t End) { segregate(Begin, End, false); });
+ } while (Repeat);
+
+ log("ICF needed " + Twine(Cnt) + " iterations");
+
+ // Merge sections in the same classs.
+ forEachClass([&](size_t Begin, size_t End) {
+ if (End - Begin == 1)
+ return;
+
+ log("Selected " + Chunks[Begin]->getDebugName());
+ for (size_t I = Begin + 1; I < End; ++I) {
+ log(" Removed " + Chunks[I]->getDebugName());
+ Chunks[Begin]->replace(Chunks[I]);
+ }
+ });
+}
+
+// Entry point to ICF.
+void doICF(ArrayRef<Chunk *> Chunks) { ICF().run(Chunks); }
+
+} // namespace coff
+} // namespace lld
diff --git a/contrib/llvm/tools/lld/COFF/ICF.h b/contrib/llvm/tools/lld/COFF/ICF.h
new file mode 100644
index 000000000000..9c54e0c9ec2d
--- /dev/null
+++ b/contrib/llvm/tools/lld/COFF/ICF.h
@@ -0,0 +1,26 @@
+//===- ICF.h --------------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_ICF_H
+#define LLD_COFF_ICF_H
+
+#include "lld/Common/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+
+namespace lld {
+namespace coff {
+
+class Chunk;
+
+void doICF(ArrayRef<Chunk *> Chunks);
+
+} // namespace coff
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/COFF/InputFiles.cpp b/contrib/llvm/tools/lld/COFF/InputFiles.cpp
new file mode 100644
index 000000000000..236c90ef0388
--- /dev/null
+++ b/contrib/llvm/tools/lld/COFF/InputFiles.cpp
@@ -0,0 +1,590 @@
+//===- InputFiles.cpp -----------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InputFiles.h"
+#include "Chunks.h"
+#include "Config.h"
+#include "Driver.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Memory.h"
+#include "llvm-c/lto.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/Object/Binary.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Target/TargetOptions.h"
+#include <cstring>
+#include <system_error>
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::COFF;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+
+using llvm::Triple;
+using llvm::support::ulittle32_t;
+
+namespace lld {
+namespace coff {
+
+std::vector<ObjFile *> ObjFile::Instances;
+std::vector<ImportFile *> ImportFile::Instances;
+std::vector<BitcodeFile *> BitcodeFile::Instances;
+
+/// Checks that Source is compatible with being a weak alias to Target.
+/// If Source is Undefined and has no weak alias set, makes it a weak
+/// alias to Target.
+static void checkAndSetWeakAlias(SymbolTable *Symtab, InputFile *F,
+ Symbol *Source, Symbol *Target) {
+ if (auto *U = dyn_cast<Undefined>(Source)) {
+ if (U->WeakAlias && U->WeakAlias != Target) {
+ // Weak aliases as produced by GCC are named in the form
+ // .weak.<weaksymbol>.<othersymbol>, where <othersymbol> is the name
+ // of another symbol emitted near the weak symbol.
+ // Just use the definition from the first object file that defined
+ // this weak symbol.
+ if (Config->MinGW)
+ return;
+ Symtab->reportDuplicate(Source, F);
+ }
+ U->WeakAlias = Target;
+ }
+}
+
+ArchiveFile::ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {}
+
+void ArchiveFile::parse() {
+ // Parse a MemoryBufferRef as an archive file.
+ File = CHECK(Archive::create(MB), this);
+
+ // Read the symbol table to construct Lazy objects.
+ for (const Archive::Symbol &Sym : File->symbols())
+ Symtab->addLazy(this, Sym);
+}
+
+// Returns a buffer pointing to a member file containing a given symbol.
+void ArchiveFile::addMember(const Archive::Symbol *Sym) {
+ const Archive::Child &C =
+ CHECK(Sym->getMember(),
+ "could not get the member for symbol " + Sym->getName());
+
+ // Return an empty buffer if we have already returned the same buffer.
+ if (!Seen.insert(C.getChildOffset()).second)
+ return;
+
+ Driver->enqueueArchiveMember(C, Sym->getName(), getName());
+}
+
+std::vector<MemoryBufferRef> getArchiveMembers(Archive *File) {
+ std::vector<MemoryBufferRef> V;
+ Error Err = Error::success();
+ for (const ErrorOr<Archive::Child> &COrErr : File->children(Err)) {
+ Archive::Child C =
+ CHECK(COrErr,
+ File->getFileName() + ": could not get the child of the archive");
+ MemoryBufferRef MBRef =
+ CHECK(C.getMemoryBufferRef(),
+ File->getFileName() +
+ ": could not get the buffer for a child of the archive");
+ V.push_back(MBRef);
+ }
+ if (Err)
+ fatal(File->getFileName() +
+ ": Archive::children failed: " + toString(std::move(Err)));
+ return V;
+}
+
+void ObjFile::parse() {
+ // Parse a memory buffer as a COFF file.
+ std::unique_ptr<Binary> Bin = CHECK(createBinary(MB), this);
+
+ if (auto *Obj = dyn_cast<COFFObjectFile>(Bin.get())) {
+ Bin.release();
+ COFFObj.reset(Obj);
+ } else {
+ fatal(toString(this) + " is not a COFF file");
+ }
+
+ // Read section and symbol tables.
+ initializeChunks();
+ initializeSymbols();
+}
+
+// We set SectionChunk pointers in the SparseChunks vector to this value
+// temporarily to mark comdat sections as having an unknown resolution. As we
+// walk the object file's symbol table, once we visit either a leader symbol or
+// an associative section definition together with the parent comdat's leader,
+// we set the pointer to either nullptr (to mark the section as discarded) or a
+// valid SectionChunk for that section.
+static SectionChunk *const PendingComdat = reinterpret_cast<SectionChunk *>(1);
+
+void ObjFile::initializeChunks() {
+ uint32_t NumSections = COFFObj->getNumberOfSections();
+ Chunks.reserve(NumSections);
+ SparseChunks.resize(NumSections + 1);
+ for (uint32_t I = 1; I < NumSections + 1; ++I) {
+ const coff_section *Sec;
+ if (auto EC = COFFObj->getSection(I, Sec))
+ fatal("getSection failed: #" + Twine(I) + ": " + EC.message());
+
+ if (Sec->Characteristics & IMAGE_SCN_LNK_COMDAT)
+ SparseChunks[I] = PendingComdat;
+ else
+ SparseChunks[I] = readSection(I, nullptr, "");
+ }
+}
+
+SectionChunk *ObjFile::readSection(uint32_t SectionNumber,
+ const coff_aux_section_definition *Def,
+ StringRef LeaderName) {
+ const coff_section *Sec;
+ if (auto EC = COFFObj->getSection(SectionNumber, Sec))
+ fatal("getSection failed: #" + Twine(SectionNumber) + ": " + EC.message());
+
+ StringRef Name;
+ if (auto EC = COFFObj->getSectionName(Sec, Name))
+ fatal("getSectionName failed: #" + Twine(SectionNumber) + ": " +
+ EC.message());
+
+ if (Name == ".drectve") {
+ ArrayRef<uint8_t> Data;
+ COFFObj->getSectionContents(Sec, Data);
+ Directives = std::string((const char *)Data.data(), Data.size());
+ return nullptr;
+ }
+
+ if (Name == ".llvm_addrsig") {
+ AddrsigSec = Sec;
+ return nullptr;
+ }
+
+ // Object files may have DWARF debug info or MS CodeView debug info
+ // (or both).
+ //
+ // DWARF sections don't need any special handling from the perspective
+ // of the linker; they are just a data section containing relocations.
+ // We can just link them to complete debug info.
+ //
+ // CodeView needs linker support. We need to interpret debug info,
+ // and then write it to a separate .pdb file.
+
+ // Ignore DWARF debug info unless /debug is given.
+ if (!Config->Debug && Name.startswith(".debug_"))
+ return nullptr;
+
+ if (Sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE)
+ return nullptr;
+ auto *C = make<SectionChunk>(this, Sec);
+ if (Def)
+ C->Checksum = Def->CheckSum;
+
+ // CodeView sections are stored to a different vector because they are not
+ // linked in the regular manner.
+ if (C->isCodeView())
+ DebugChunks.push_back(C);
+ else if (Config->GuardCF != GuardCFLevel::Off && Name == ".gfids$y")
+ GuardFidChunks.push_back(C);
+ else if (Config->GuardCF != GuardCFLevel::Off && Name == ".gljmp$y")
+ GuardLJmpChunks.push_back(C);
+ else if (Name == ".sxdata")
+ SXDataChunks.push_back(C);
+ else if (Config->TailMerge && Sec->NumberOfRelocations == 0 &&
+ Name == ".rdata" && LeaderName.startswith("??_C@"))
+ // COFF sections that look like string literal sections (i.e. no
+ // relocations, in .rdata, leader symbol name matches the MSVC name mangling
+ // for string literals) are subject to string tail merging.
+ MergeChunk::addSection(C);
+ else
+ Chunks.push_back(C);
+
+ return C;
+}
+
+void ObjFile::readAssociativeDefinition(
+ COFFSymbolRef Sym, const coff_aux_section_definition *Def) {
+ readAssociativeDefinition(Sym, Def, Def->getNumber(Sym.isBigObj()));
+}
+
+void ObjFile::readAssociativeDefinition(COFFSymbolRef Sym,
+ const coff_aux_section_definition *Def,
+ uint32_t ParentSection) {
+ SectionChunk *Parent = SparseChunks[ParentSection];
+
+ // If the parent is pending, it probably means that its section definition
+ // appears after us in the symbol table. Leave the associated section as
+ // pending; we will handle it during the second pass in initializeSymbols().
+ if (Parent == PendingComdat)
+ return;
+
+ // Check whether the parent is prevailing. If it is, so are we, and we read
+ // the section; otherwise mark it as discarded.
+ int32_t SectionNumber = Sym.getSectionNumber();
+ if (Parent) {
+ SparseChunks[SectionNumber] = readSection(SectionNumber, Def, "");
+ if (SparseChunks[SectionNumber])
+ Parent->addAssociative(SparseChunks[SectionNumber]);
+ } else {
+ SparseChunks[SectionNumber] = nullptr;
+ }
+}
+
+void ObjFile::recordPrevailingSymbolForMingw(
+ COFFSymbolRef Sym, DenseMap<StringRef, uint32_t> &PrevailingSectionMap) {
+ // For comdat symbols in executable sections, where this is the copy
+ // of the section chunk we actually include instead of discarding it,
+ // add the symbol to a map to allow using it for implicitly
+ // associating .[px]data$<func> sections to it.
+ int32_t SectionNumber = Sym.getSectionNumber();
+ SectionChunk *SC = SparseChunks[SectionNumber];
+ if (SC && SC->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE) {
+ StringRef Name;
+ COFFObj->getSymbolName(Sym, Name);
+ PrevailingSectionMap[Name] = SectionNumber;
+ }
+}
+
+void ObjFile::maybeAssociateSEHForMingw(
+ COFFSymbolRef Sym, const coff_aux_section_definition *Def,
+ const DenseMap<StringRef, uint32_t> &PrevailingSectionMap) {
+ StringRef Name;
+ COFFObj->getSymbolName(Sym, Name);
+ if (Name.consume_front(".pdata$") || Name.consume_front(".xdata$")) {
+ // For MinGW, treat .[px]data$<func> as implicitly associative to
+ // the symbol <func>.
+ auto ParentSym = PrevailingSectionMap.find(Name);
+ if (ParentSym != PrevailingSectionMap.end())
+ readAssociativeDefinition(Sym, Def, ParentSym->second);
+ }
+}
+
+Symbol *ObjFile::createRegular(COFFSymbolRef Sym) {
+ SectionChunk *SC = SparseChunks[Sym.getSectionNumber()];
+ if (Sym.isExternal()) {
+ StringRef Name;
+ COFFObj->getSymbolName(Sym, Name);
+ if (SC)
+ return Symtab->addRegular(this, Name, Sym.getGeneric(), SC);
+ // For MinGW symbols named .weak.* that point to a discarded section,
+ // don't create an Undefined symbol. If nothing ever refers to the symbol,
+ // everything should be fine. If something actually refers to the symbol
+ // (e.g. the undefined weak alias), linking will fail due to undefined
+ // references at the end.
+ if (Config->MinGW && Name.startswith(".weak."))
+ return nullptr;
+ return Symtab->addUndefined(Name, this, false);
+ }
+ if (SC)
+ return make<DefinedRegular>(this, /*Name*/ "", /*IsCOMDAT*/ false,
+ /*IsExternal*/ false, Sym.getGeneric(), SC);
+ return nullptr;
+}
+
+void ObjFile::initializeSymbols() {
+ uint32_t NumSymbols = COFFObj->getNumberOfSymbols();
+ Symbols.resize(NumSymbols);
+
+ SmallVector<std::pair<Symbol *, uint32_t>, 8> WeakAliases;
+ std::vector<uint32_t> PendingIndexes;
+ PendingIndexes.reserve(NumSymbols);
+
+ DenseMap<StringRef, uint32_t> PrevailingSectionMap;
+ std::vector<const coff_aux_section_definition *> ComdatDefs(
+ COFFObj->getNumberOfSections() + 1);
+
+ for (uint32_t I = 0; I < NumSymbols; ++I) {
+ COFFSymbolRef COFFSym = check(COFFObj->getSymbol(I));
+ bool PrevailingComdat;
+ if (COFFSym.isUndefined()) {
+ Symbols[I] = createUndefined(COFFSym);
+ } else if (COFFSym.isWeakExternal()) {
+ Symbols[I] = createUndefined(COFFSym);
+ uint32_t TagIndex = COFFSym.getAux<coff_aux_weak_external>()->TagIndex;
+ WeakAliases.emplace_back(Symbols[I], TagIndex);
+ } else if (Optional<Symbol *> OptSym =
+ createDefined(COFFSym, ComdatDefs, PrevailingComdat)) {
+ Symbols[I] = *OptSym;
+ if (Config->MinGW && PrevailingComdat)
+ recordPrevailingSymbolForMingw(COFFSym, PrevailingSectionMap);
+ } else {
+ // createDefined() returns None if a symbol belongs to a section that
+ // was pending at the point when the symbol was read. This can happen in
+ // two cases:
+ // 1) section definition symbol for a comdat leader;
+ // 2) symbol belongs to a comdat section associated with a section whose
+ // section definition symbol appears later in the symbol table.
+ // In both of these cases, we can expect the section to be resolved by
+ // the time we finish visiting the remaining symbols in the symbol
+ // table. So we postpone the handling of this symbol until that time.
+ PendingIndexes.push_back(I);
+ }
+ I += COFFSym.getNumberOfAuxSymbols();
+ }
+
+ for (uint32_t I : PendingIndexes) {
+ COFFSymbolRef Sym = check(COFFObj->getSymbol(I));
+ if (const coff_aux_section_definition *Def = Sym.getSectionDefinition()) {
+ if (Def->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE)
+ readAssociativeDefinition(Sym, Def);
+ else if (Config->MinGW)
+ maybeAssociateSEHForMingw(Sym, Def, PrevailingSectionMap);
+ }
+ if (SparseChunks[Sym.getSectionNumber()] == PendingComdat) {
+ StringRef Name;
+ COFFObj->getSymbolName(Sym, Name);
+ log("comdat section " + Name +
+ " without leader and unassociated, discarding");
+ continue;
+ }
+ Symbols[I] = createRegular(Sym);
+ }
+
+ for (auto &KV : WeakAliases) {
+ Symbol *Sym = KV.first;
+ uint32_t Idx = KV.second;
+ checkAndSetWeakAlias(Symtab, this, Sym, Symbols[Idx]);
+ }
+}
+
+Symbol *ObjFile::createUndefined(COFFSymbolRef Sym) {
+ StringRef Name;
+ COFFObj->getSymbolName(Sym, Name);
+ return Symtab->addUndefined(Name, this, Sym.isWeakExternal());
+}
+
+Optional<Symbol *> ObjFile::createDefined(
+ COFFSymbolRef Sym,
+ std::vector<const coff_aux_section_definition *> &ComdatDefs,
+ bool &Prevailing) {
+ Prevailing = false;
+ auto GetName = [&]() {
+ StringRef S;
+ COFFObj->getSymbolName(Sym, S);
+ return S;
+ };
+
+ if (Sym.isCommon()) {
+ auto *C = make<CommonChunk>(Sym);
+ Chunks.push_back(C);
+ return Symtab->addCommon(this, GetName(), Sym.getValue(), Sym.getGeneric(),
+ C);
+ }
+
+ if (Sym.isAbsolute()) {
+ StringRef Name = GetName();
+
+ // Skip special symbols.
+ if (Name == "@comp.id")
+ return nullptr;
+ if (Name == "@feat.00") {
+ Feat00Flags = Sym.getValue();
+ return nullptr;
+ }
+
+ if (Sym.isExternal())
+ return Symtab->addAbsolute(Name, Sym);
+ return make<DefinedAbsolute>(Name, Sym);
+ }
+
+ int32_t SectionNumber = Sym.getSectionNumber();
+ if (SectionNumber == llvm::COFF::IMAGE_SYM_DEBUG)
+ return nullptr;
+
+ if (llvm::COFF::isReservedSectionNumber(SectionNumber))
+ fatal(toString(this) + ": " + GetName() +
+ " should not refer to special section " + Twine(SectionNumber));
+
+ if ((uint32_t)SectionNumber >= SparseChunks.size())
+ fatal(toString(this) + ": " + GetName() +
+ " should not refer to non-existent section " + Twine(SectionNumber));
+
+ // Handle comdat leader symbols.
+ if (const coff_aux_section_definition *Def = ComdatDefs[SectionNumber]) {
+ ComdatDefs[SectionNumber] = nullptr;
+ Symbol *Leader;
+ if (Sym.isExternal()) {
+ std::tie(Leader, Prevailing) =
+ Symtab->addComdat(this, GetName(), Sym.getGeneric());
+ } else {
+ Leader = make<DefinedRegular>(this, /*Name*/ "", /*IsCOMDAT*/ false,
+ /*IsExternal*/ false, Sym.getGeneric());
+ Prevailing = true;
+ }
+
+ if (Prevailing) {
+ SectionChunk *C = readSection(SectionNumber, Def, GetName());
+ SparseChunks[SectionNumber] = C;
+ C->Sym = cast<DefinedRegular>(Leader);
+ cast<DefinedRegular>(Leader)->Data = &C->Repl;
+ } else {
+ SparseChunks[SectionNumber] = nullptr;
+ }
+ return Leader;
+ }
+
+ // Read associative section definitions and prepare to handle the comdat
+ // leader symbol by setting the section's ComdatDefs pointer if we encounter a
+ // non-associative comdat.
+ if (SparseChunks[SectionNumber] == PendingComdat) {
+ if (const coff_aux_section_definition *Def = Sym.getSectionDefinition()) {
+ if (Def->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE)
+ readAssociativeDefinition(Sym, Def);
+ else
+ ComdatDefs[SectionNumber] = Def;
+ }
+ }
+
+ // readAssociativeDefinition() writes to SparseChunks, so need to check again.
+ if (SparseChunks[SectionNumber] == PendingComdat)
+ return None;
+
+ return createRegular(Sym);
+}
+
+MachineTypes ObjFile::getMachineType() {
+ if (COFFObj)
+ return static_cast<MachineTypes>(COFFObj->getMachine());
+ return IMAGE_FILE_MACHINE_UNKNOWN;
+}
+
+StringRef ltrim1(StringRef S, const char *Chars) {
+ if (!S.empty() && strchr(Chars, S[0]))
+ return S.substr(1);
+ return S;
+}
+
+void ImportFile::parse() {
+ const char *Buf = MB.getBufferStart();
+ const char *End = MB.getBufferEnd();
+ const auto *Hdr = reinterpret_cast<const coff_import_header *>(Buf);
+
+ // Check if the total size is valid.
+ if ((size_t)(End - Buf) != (sizeof(*Hdr) + Hdr->SizeOfData))
+ fatal("broken import library");
+
+ // Read names and create an __imp_ symbol.
+ StringRef Name = Saver.save(StringRef(Buf + sizeof(*Hdr)));
+ StringRef ImpName = Saver.save("__imp_" + Name);
+ const char *NameStart = Buf + sizeof(coff_import_header) + Name.size() + 1;
+ DLLName = StringRef(NameStart);
+ StringRef ExtName;
+ switch (Hdr->getNameType()) {
+ case IMPORT_ORDINAL:
+ ExtName = "";
+ break;
+ case IMPORT_NAME:
+ ExtName = Name;
+ break;
+ case IMPORT_NAME_NOPREFIX:
+ ExtName = ltrim1(Name, "?@_");
+ break;
+ case IMPORT_NAME_UNDECORATE:
+ ExtName = ltrim1(Name, "?@_");
+ ExtName = ExtName.substr(0, ExtName.find('@'));
+ break;
+ }
+
+ this->Hdr = Hdr;
+ ExternalName = ExtName;
+
+ ImpSym = Symtab->addImportData(ImpName, this);
+ // If this was a duplicate, we logged an error but may continue;
+ // in this case, ImpSym is nullptr.
+ if (!ImpSym)
+ return;
+
+ if (Hdr->getType() == llvm::COFF::IMPORT_CONST)
+ static_cast<void>(Symtab->addImportData(Name, this));
+
+ // If type is function, we need to create a thunk which jump to an
+ // address pointed by the __imp_ symbol. (This allows you to call
+ // DLL functions just like regular non-DLL functions.)
+ if (Hdr->getType() == llvm::COFF::IMPORT_CODE)
+ ThunkSym = Symtab->addImportThunk(
+ Name, cast_or_null<DefinedImportData>(ImpSym), Hdr->Machine);
+}
+
+void BitcodeFile::parse() {
+ Obj = check(lto::InputFile::create(MemoryBufferRef(
+ MB.getBuffer(), Saver.save(ParentName + MB.getBufferIdentifier()))));
+ std::vector<std::pair<Symbol *, bool>> Comdat(Obj->getComdatTable().size());
+ for (size_t I = 0; I != Obj->getComdatTable().size(); ++I)
+ Comdat[I] = Symtab->addComdat(this, Saver.save(Obj->getComdatTable()[I]));
+ for (const lto::InputFile::Symbol &ObjSym : Obj->symbols()) {
+ StringRef SymName = Saver.save(ObjSym.getName());
+ int ComdatIndex = ObjSym.getComdatIndex();
+ Symbol *Sym;
+ if (ObjSym.isUndefined()) {
+ Sym = Symtab->addUndefined(SymName, this, false);
+ } else if (ObjSym.isCommon()) {
+ Sym = Symtab->addCommon(this, SymName, ObjSym.getCommonSize());
+ } else if (ObjSym.isWeak() && ObjSym.isIndirect()) {
+ // Weak external.
+ Sym = Symtab->addUndefined(SymName, this, true);
+ std::string Fallback = ObjSym.getCOFFWeakExternalFallback();
+ Symbol *Alias = Symtab->addUndefined(Saver.save(Fallback));
+ checkAndSetWeakAlias(Symtab, this, Sym, Alias);
+ } else if (ComdatIndex != -1) {
+ if (SymName == Obj->getComdatTable()[ComdatIndex])
+ Sym = Comdat[ComdatIndex].first;
+ else if (Comdat[ComdatIndex].second)
+ Sym = Symtab->addRegular(this, SymName);
+ else
+ Sym = Symtab->addUndefined(SymName, this, false);
+ } else {
+ Sym = Symtab->addRegular(this, SymName);
+ }
+ Symbols.push_back(Sym);
+ }
+ Directives = Obj->getCOFFLinkerOpts();
+}
+
+MachineTypes BitcodeFile::getMachineType() {
+ switch (Triple(Obj->getTargetTriple()).getArch()) {
+ case Triple::x86_64:
+ return AMD64;
+ case Triple::x86:
+ return I386;
+ case Triple::arm:
+ return ARMNT;
+ case Triple::aarch64:
+ return ARM64;
+ default:
+ return IMAGE_FILE_MACHINE_UNKNOWN;
+ }
+}
+} // namespace coff
+} // namespace lld
+
+// Returns the last element of a path, which is supposed to be a filename.
+static StringRef getBasename(StringRef Path) {
+ return sys::path::filename(Path, sys::path::Style::windows);
+}
+
+// Returns a string in the format of "foo.obj" or "foo.obj(bar.lib)".
+std::string lld::toString(const coff::InputFile *File) {
+ if (!File)
+ return "<internal>";
+ if (File->ParentName.empty())
+ return File->getName();
+
+ return (getBasename(File->ParentName) + "(" + getBasename(File->getName()) +
+ ")")
+ .str();
+}
diff --git a/contrib/llvm/tools/lld/COFF/InputFiles.h b/contrib/llvm/tools/lld/COFF/InputFiles.h
new file mode 100644
index 000000000000..ec802f2d0300
--- /dev/null
+++ b/contrib/llvm/tools/lld/COFF/InputFiles.h
@@ -0,0 +1,280 @@
+//===- InputFiles.h ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_INPUT_FILES_H
+#define LLD_COFF_INPUT_FILES_H
+
+#include "Config.h"
+#include "lld/Common/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/LTO/LTO.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/StringSaver.h"
+#include <memory>
+#include <set>
+#include <vector>
+
+namespace llvm {
+namespace pdb {
+class DbiModuleDescriptorBuilder;
+}
+}
+
+namespace lld {
+namespace coff {
+
+std::vector<MemoryBufferRef> getArchiveMembers(llvm::object::Archive *File);
+
+using llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN;
+using llvm::COFF::MachineTypes;
+using llvm::object::Archive;
+using llvm::object::COFFObjectFile;
+using llvm::object::COFFSymbolRef;
+using llvm::object::coff_import_header;
+using llvm::object::coff_section;
+
+class Chunk;
+class Defined;
+class DefinedImportData;
+class DefinedImportThunk;
+class Lazy;
+class SectionChunk;
+class Symbol;
+class Undefined;
+
+// The root class of input files.
+class InputFile {
+public:
+ enum Kind { ArchiveKind, ObjectKind, ImportKind, BitcodeKind };
+ Kind kind() const { return FileKind; }
+ virtual ~InputFile() {}
+
+ // Returns the filename.
+ StringRef getName() const { return MB.getBufferIdentifier(); }
+
+ // Reads a file (the constructor doesn't do that).
+ virtual void parse() = 0;
+
+ // Returns the CPU type this file was compiled to.
+ virtual MachineTypes getMachineType() { return IMAGE_FILE_MACHINE_UNKNOWN; }
+
+ MemoryBufferRef MB;
+
+ // An archive file name if this file is created from an archive.
+ StringRef ParentName;
+
+ // Returns .drectve section contents if exist.
+ StringRef getDirectives() { return StringRef(Directives).trim(); }
+
+protected:
+ InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {}
+
+ std::string Directives;
+
+private:
+ const Kind FileKind;
+};
+
+// .lib or .a file.
+class ArchiveFile : public InputFile {
+public:
+ explicit ArchiveFile(MemoryBufferRef M);
+ static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; }
+ void parse() override;
+
+ // Enqueues an archive member load for the given symbol. If we've already
+ // enqueued a load for the same archive member, this function does nothing,
+ // which ensures that we don't load the same member more than once.
+ void addMember(const Archive::Symbol *Sym);
+
+private:
+ std::unique_ptr<Archive> File;
+ std::string Filename;
+ llvm::DenseSet<uint64_t> Seen;
+};
+
+// .obj or .o file. This may be a member of an archive file.
+class ObjFile : public InputFile {
+public:
+ explicit ObjFile(MemoryBufferRef M) : InputFile(ObjectKind, M) {}
+ static bool classof(const InputFile *F) { return F->kind() == ObjectKind; }
+ void parse() override;
+ MachineTypes getMachineType() override;
+ ArrayRef<Chunk *> getChunks() { return Chunks; }
+ ArrayRef<SectionChunk *> getDebugChunks() { return DebugChunks; }
+ ArrayRef<SectionChunk *> getSXDataChunks() { return SXDataChunks; }
+ ArrayRef<SectionChunk *> getGuardFidChunks() { return GuardFidChunks; }
+ ArrayRef<SectionChunk *> getGuardLJmpChunks() { return GuardLJmpChunks; }
+ ArrayRef<Symbol *> getSymbols() { return Symbols; }
+
+ // Returns a Symbol object for the SymbolIndex'th symbol in the
+ // underlying object file.
+ Symbol *getSymbol(uint32_t SymbolIndex) {
+ return Symbols[SymbolIndex];
+ }
+
+ // Returns the underlying COFF file.
+ COFFObjectFile *getCOFFObj() { return COFFObj.get(); }
+
+ // Whether the object was already merged into the final PDB or not
+ bool wasProcessedForPDB() const { return !!ModuleDBI; }
+
+ static std::vector<ObjFile *> Instances;
+
+ // Flags in the absolute @feat.00 symbol if it is present. These usually
+ // indicate if an object was compiled with certain security features enabled
+ // like stack guard, safeseh, /guard:cf, or other things.
+ uint32_t Feat00Flags = 0;
+
+ // True if this object file is compatible with SEH. COFF-specific and
+ // x86-only. COFF spec 5.10.1. The .sxdata section.
+ bool hasSafeSEH() { return Feat00Flags & 0x1; }
+
+ // True if this file was compiled with /guard:cf.
+ bool hasGuardCF() { return Feat00Flags & 0x800; }
+
+ // Pointer to the PDB module descriptor builder. Various debug info records
+ // will reference object files by "module index", which is here. Things like
+ // source files and section contributions are also recorded here. Will be null
+ // if we are not producing a PDB.
+ llvm::pdb::DbiModuleDescriptorBuilder *ModuleDBI = nullptr;
+
+ const coff_section *AddrsigSec = nullptr;
+
+ // When using Microsoft precompiled headers, this is the PCH's key.
+ // The same key is used by both the precompiled object, and objects using the
+ // precompiled object. Any difference indicates out-of-date objects.
+ llvm::Optional<uint32_t> PCHSignature;
+
+private:
+ void initializeChunks();
+ void initializeSymbols();
+
+ SectionChunk *
+ readSection(uint32_t SectionNumber,
+ const llvm::object::coff_aux_section_definition *Def,
+ StringRef LeaderName);
+
+ void readAssociativeDefinition(
+ COFFSymbolRef COFFSym,
+ const llvm::object::coff_aux_section_definition *Def);
+
+ void readAssociativeDefinition(
+ COFFSymbolRef COFFSym,
+ const llvm::object::coff_aux_section_definition *Def,
+ uint32_t ParentSection);
+
+ void recordPrevailingSymbolForMingw(
+ COFFSymbolRef COFFSym,
+ llvm::DenseMap<StringRef, uint32_t> &PrevailingSectionMap);
+
+ void maybeAssociateSEHForMingw(
+ COFFSymbolRef Sym, const llvm::object::coff_aux_section_definition *Def,
+ const llvm::DenseMap<StringRef, uint32_t> &PrevailingSectionMap);
+
+ llvm::Optional<Symbol *>
+ createDefined(COFFSymbolRef Sym,
+ std::vector<const llvm::object::coff_aux_section_definition *>
+ &ComdatDefs,
+ bool &PrevailingComdat);
+ Symbol *createRegular(COFFSymbolRef Sym);
+ Symbol *createUndefined(COFFSymbolRef Sym);
+
+ std::unique_ptr<COFFObjectFile> COFFObj;
+
+ // List of all chunks defined by this file. This includes both section
+ // chunks and non-section chunks for common symbols.
+ std::vector<Chunk *> Chunks;
+
+ // CodeView debug info sections.
+ std::vector<SectionChunk *> DebugChunks;
+
+ // Chunks containing symbol table indices of exception handlers. Only used for
+ // 32-bit x86.
+ std::vector<SectionChunk *> SXDataChunks;
+
+ // Chunks containing symbol table indices of address taken symbols and longjmp
+ // targets. These are not linked into the final binary when /guard:cf is set.
+ std::vector<SectionChunk *> GuardFidChunks;
+ std::vector<SectionChunk *> GuardLJmpChunks;
+
+ // This vector contains the same chunks as Chunks, but they are
+ // indexed such that you can get a SectionChunk by section index.
+ // Nonexistent section indices are filled with null pointers.
+ // (Because section number is 1-based, the first slot is always a
+ // null pointer.)
+ std::vector<SectionChunk *> SparseChunks;
+
+ // This vector contains a list of all symbols defined or referenced by this
+ // file. They are indexed such that you can get a Symbol by symbol
+ // index. Nonexistent indices (which are occupied by auxiliary
+ // symbols in the real symbol table) are filled with null pointers.
+ std::vector<Symbol *> Symbols;
+};
+
+// This type represents import library members that contain DLL names
+// and symbols exported from the DLLs. See Microsoft PE/COFF spec. 7
+// for details about the format.
+class ImportFile : public InputFile {
+public:
+ explicit ImportFile(MemoryBufferRef M) : InputFile(ImportKind, M) {}
+
+ static bool classof(const InputFile *F) { return F->kind() == ImportKind; }
+
+ static std::vector<ImportFile *> Instances;
+
+ Symbol *ImpSym = nullptr;
+ Symbol *ThunkSym = nullptr;
+ std::string DLLName;
+
+private:
+ void parse() override;
+
+public:
+ StringRef ExternalName;
+ const coff_import_header *Hdr;
+ Chunk *Location = nullptr;
+
+ // We want to eliminate dllimported symbols if no one actually refers them.
+ // These "Live" bits are used to keep track of which import library members
+ // are actually in use.
+ //
+ // If the Live bit is turned off by MarkLive, Writer will ignore dllimported
+ // symbols provided by this import library member. We also track whether the
+ // imported symbol is used separately from whether the thunk is used in order
+ // to avoid creating unnecessary thunks.
+ bool Live = !Config->DoGC;
+ bool ThunkLive = !Config->DoGC;
+};
+
+// Used for LTO.
+class BitcodeFile : public InputFile {
+public:
+ explicit BitcodeFile(MemoryBufferRef M) : InputFile(BitcodeKind, M) {}
+ static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; }
+ ArrayRef<Symbol *> getSymbols() { return Symbols; }
+ MachineTypes getMachineType() override;
+ static std::vector<BitcodeFile *> Instances;
+ std::unique_ptr<llvm::lto::InputFile> Obj;
+
+private:
+ void parse() override;
+
+ std::vector<Symbol *> Symbols;
+};
+} // namespace coff
+
+std::string toString(const coff::InputFile *File);
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/COFF/LTO.cpp b/contrib/llvm/tools/lld/COFF/LTO.cpp
new file mode 100644
index 000000000000..92d9ff0937c0
--- /dev/null
+++ b/contrib/llvm/tools/lld/COFF/LTO.cpp
@@ -0,0 +1,152 @@
+//===- LTO.cpp ------------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LTO.h"
+#include "Config.h"
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Strings.h"
+#include "lld/Common/TargetOptionsCommandFlags.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/IR/DiagnosticPrinter.h"
+#include "llvm/LTO/Caching.h"
+#include "llvm/LTO/Config.h"
+#include "llvm/LTO/LTO.h"
+#include "llvm/Object/SymbolicFile.h"
+#include "llvm/Support/CodeGen.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cstddef>
+#include <memory>
+#include <string>
+#include <system_error>
+#include <vector>
+
+using namespace llvm;
+using namespace llvm::object;
+
+using namespace lld;
+using namespace lld::coff;
+
+static std::unique_ptr<lto::LTO> createLTO() {
+ lto::Config C;
+ C.Options = InitTargetOptionsFromCodeGenFlags();
+
+ // Always emit a section per function/datum with LTO. LLVM LTO should get most
+ // of the benefit of linker GC, but there are still opportunities for ICF.
+ C.Options.FunctionSections = true;
+ C.Options.DataSections = true;
+
+ // Use static reloc model on 32-bit x86 because it usually results in more
+ // compact code, and because there are also known code generation bugs when
+ // using the PIC model (see PR34306).
+ if (Config->Machine == COFF::IMAGE_FILE_MACHINE_I386)
+ C.RelocModel = Reloc::Static;
+ else
+ C.RelocModel = Reloc::PIC_;
+ C.DisableVerify = true;
+ C.DiagHandler = diagnosticHandler;
+ C.OptLevel = Config->LTOO;
+ C.CPU = GetCPUStr();
+ C.MAttrs = GetMAttrs();
+
+ if (Config->SaveTemps)
+ checkError(C.addSaveTemps(std::string(Config->OutputFile) + ".",
+ /*UseInputModulePath*/ true));
+ lto::ThinBackend Backend;
+ if (Config->ThinLTOJobs != 0)
+ Backend = lto::createInProcessThinBackend(Config->ThinLTOJobs);
+ return llvm::make_unique<lto::LTO>(std::move(C), Backend,
+ Config->LTOPartitions);
+}
+
+BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) {}
+
+BitcodeCompiler::~BitcodeCompiler() = default;
+
+static void undefine(Symbol *S) { replaceSymbol<Undefined>(S, S->getName()); }
+
+void BitcodeCompiler::add(BitcodeFile &F) {
+ lto::InputFile &Obj = *F.Obj;
+ unsigned SymNum = 0;
+ std::vector<Symbol *> SymBodies = F.getSymbols();
+ std::vector<lto::SymbolResolution> Resols(SymBodies.size());
+
+ // Provide a resolution to the LTO API for each symbol.
+ for (const lto::InputFile::Symbol &ObjSym : Obj.symbols()) {
+ Symbol *Sym = SymBodies[SymNum];
+ lto::SymbolResolution &R = Resols[SymNum];
+ ++SymNum;
+
+ // Ideally we shouldn't check for SF_Undefined but currently IRObjectFile
+ // reports two symbols for module ASM defined. Without this check, lld
+ // flags an undefined in IR with a definition in ASM as prevailing.
+ // Once IRObjectFile is fixed to report only one symbol this hack can
+ // be removed.
+ R.Prevailing = !ObjSym.isUndefined() && Sym->getFile() == &F;
+ R.VisibleToRegularObj = Sym->IsUsedInRegularObj;
+ if (R.Prevailing)
+ undefine(Sym);
+ }
+ checkError(LTOObj->add(std::move(F.Obj), Resols));
+}
+
+// Merge all the bitcode files we have seen, codegen the result
+// and return the resulting objects.
+std::vector<StringRef> BitcodeCompiler::compile() {
+ unsigned MaxTasks = LTOObj->getMaxTasks();
+ Buf.resize(MaxTasks);
+ Files.resize(MaxTasks);
+
+ // The /lldltocache option specifies the path to a directory in which to cache
+ // native object files for ThinLTO incremental builds. If a path was
+ // specified, configure LTO to use it as the cache directory.
+ lto::NativeObjectCache Cache;
+ if (!Config->LTOCache.empty())
+ Cache = check(lto::localCache(
+ Config->LTOCache, [&](size_t Task, std::unique_ptr<MemoryBuffer> MB) {
+ Files[Task] = std::move(MB);
+ }));
+
+ checkError(LTOObj->run(
+ [&](size_t Task) {
+ return llvm::make_unique<lto::NativeObjectStream>(
+ llvm::make_unique<raw_svector_ostream>(Buf[Task]));
+ },
+ Cache));
+
+ if (!Config->LTOCache.empty())
+ pruneCache(Config->LTOCache, Config->LTOCachePolicy);
+
+ std::vector<StringRef> Ret;
+ for (unsigned I = 0; I != MaxTasks; ++I) {
+ if (Buf[I].empty())
+ continue;
+ if (Config->SaveTemps) {
+ if (I == 0)
+ saveBuffer(Buf[I], Config->OutputFile + ".lto.obj");
+ else
+ saveBuffer(Buf[I], Config->OutputFile + Twine(I) + ".lto.obj");
+ }
+ Ret.emplace_back(Buf[I].data(), Buf[I].size());
+ }
+
+ for (std::unique_ptr<MemoryBuffer> &File : Files)
+ if (File)
+ Ret.push_back(File->getBuffer());
+
+ return Ret;
+}
diff --git a/contrib/llvm/tools/lld/COFF/LTO.h b/contrib/llvm/tools/lld/COFF/LTO.h
new file mode 100644
index 000000000000..f00924654780
--- /dev/null
+++ b/contrib/llvm/tools/lld/COFF/LTO.h
@@ -0,0 +1,57 @@
+//===- LTO.h ----------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides a way to combine bitcode files into one COFF
+// file by compiling them using LLVM.
+//
+// If LTO is in use, your input files are not in regular COFF files
+// but instead LLVM bitcode files. In that case, the linker has to
+// convert bitcode files into the native format so that we can create
+// a COFF file that contains native code. This file provides that
+// functionality.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_LTO_H
+#define LLD_COFF_LTO_H
+
+#include "lld/Common/LLVM.h"
+#include "llvm/ADT/SmallString.h"
+#include <memory>
+#include <vector>
+
+namespace llvm {
+namespace lto {
+class LTO;
+}
+}
+
+namespace lld {
+namespace coff {
+
+class BitcodeFile;
+class InputFile;
+
+class BitcodeCompiler {
+public:
+ BitcodeCompiler();
+ ~BitcodeCompiler();
+
+ void add(BitcodeFile &F);
+ std::vector<StringRef> compile();
+
+private:
+ std::unique_ptr<llvm::lto::LTO> LTOObj;
+ std::vector<SmallString<0>> Buf;
+ std::vector<std::unique_ptr<MemoryBuffer>> Files;
+};
+}
+}
+
+#endif
diff --git a/contrib/llvm/tools/lld/COFF/MapFile.cpp b/contrib/llvm/tools/lld/COFF/MapFile.cpp
new file mode 100644
index 000000000000..fd4894250223
--- /dev/null
+++ b/contrib/llvm/tools/lld/COFF/MapFile.cpp
@@ -0,0 +1,125 @@
+//===- MapFile.cpp --------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the /lldmap option. It shows lists in order and
+// hierarchically the output sections, input sections, input files and
+// symbol:
+//
+// Address Size Align Out File Symbol
+// 00201000 00000015 4 .text
+// 00201000 0000000e 4 test.o:(.text)
+// 0020100e 00000000 0 local
+// 00201005 00000000 0 f(int)
+//
+//===----------------------------------------------------------------------===//
+
+#include "MapFile.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+#include "Writer.h"
+#include "lld/Common/ErrorHandler.h"
+#include "llvm/Support/Parallel.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace llvm::object;
+
+using namespace lld;
+using namespace lld::coff;
+
+typedef DenseMap<const SectionChunk *, SmallVector<DefinedRegular *, 4>>
+ SymbolMapTy;
+
+static const std::string Indent8 = " "; // 8 spaces
+static const std::string Indent16 = " "; // 16 spaces
+
+// Print out the first three columns of a line.
+static void writeHeader(raw_ostream &OS, uint64_t Addr, uint64_t Size,
+ uint64_t Align) {
+ OS << format("%08llx %08llx %5lld ", Addr, Size, Align);
+}
+
+// Returns a list of all symbols that we want to print out.
+static std::vector<DefinedRegular *> getSymbols() {
+ std::vector<DefinedRegular *> V;
+ for (ObjFile *File : ObjFile::Instances)
+ for (Symbol *B : File->getSymbols())
+ if (auto *Sym = dyn_cast_or_null<DefinedRegular>(B))
+ if (Sym && !Sym->getCOFFSymbol().isSectionDefinition())
+ V.push_back(Sym);
+ return V;
+}
+
+// Returns a map from sections to their symbols.
+static SymbolMapTy getSectionSyms(ArrayRef<DefinedRegular *> Syms) {
+ SymbolMapTy Ret;
+ for (DefinedRegular *S : Syms)
+ Ret[S->getChunk()].push_back(S);
+
+ // Sort symbols by address.
+ for (auto &It : Ret) {
+ SmallVectorImpl<DefinedRegular *> &V = It.second;
+ std::sort(V.begin(), V.end(), [](DefinedRegular *A, DefinedRegular *B) {
+ return A->getRVA() < B->getRVA();
+ });
+ }
+ return Ret;
+}
+
+// Construct a map from symbols to their stringified representations.
+static DenseMap<DefinedRegular *, std::string>
+getSymbolStrings(ArrayRef<DefinedRegular *> Syms) {
+ std::vector<std::string> Str(Syms.size());
+ for_each_n(parallel::par, (size_t)0, Syms.size(), [&](size_t I) {
+ raw_string_ostream OS(Str[I]);
+ writeHeader(OS, Syms[I]->getRVA(), 0, 0);
+ OS << Indent16 << toString(*Syms[I]);
+ });
+
+ DenseMap<DefinedRegular *, std::string> Ret;
+ for (size_t I = 0, E = Syms.size(); I < E; ++I)
+ Ret[Syms[I]] = std::move(Str[I]);
+ return Ret;
+}
+
+void coff::writeMapFile(ArrayRef<OutputSection *> OutputSections) {
+ if (Config->MapFile.empty())
+ return;
+
+ std::error_code EC;
+ raw_fd_ostream OS(Config->MapFile, EC, sys::fs::F_None);
+ if (EC)
+ fatal("cannot open " + Config->MapFile + ": " + EC.message());
+
+ // Collect symbol info that we want to print out.
+ std::vector<DefinedRegular *> Syms = getSymbols();
+ SymbolMapTy SectionSyms = getSectionSyms(Syms);
+ DenseMap<DefinedRegular *, std::string> SymStr = getSymbolStrings(Syms);
+
+ // Print out the header line.
+ OS << "Address Size Align Out In Symbol\n";
+
+ // Print out file contents.
+ for (OutputSection *Sec : OutputSections) {
+ writeHeader(OS, Sec->getRVA(), Sec->getVirtualSize(), /*Align=*/PageSize);
+ OS << Sec->Name << '\n';
+
+ for (Chunk *C : Sec->Chunks) {
+ auto *SC = dyn_cast<SectionChunk>(C);
+ if (!SC)
+ continue;
+
+ writeHeader(OS, SC->getRVA(), SC->getSize(), SC->Alignment);
+ OS << Indent8 << SC->File->getName() << ":(" << SC->getSectionName()
+ << ")\n";
+ for (DefinedRegular *Sym : SectionSyms[SC])
+ OS << SymStr[Sym] << '\n';
+ }
+ }
+}
diff --git a/contrib/llvm/tools/lld/COFF/MapFile.h b/contrib/llvm/tools/lld/COFF/MapFile.h
new file mode 100644
index 000000000000..0d0d68ce3ead
--- /dev/null
+++ b/contrib/llvm/tools/lld/COFF/MapFile.h
@@ -0,0 +1,22 @@
+//===- MapFile.h ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_MAPFILE_H
+#define LLD_COFF_MAPFILE_H
+
+#include "llvm/ADT/ArrayRef.h"
+
+namespace lld {
+namespace coff {
+class OutputSection;
+void writeMapFile(llvm::ArrayRef<OutputSection *> OutputSections);
+}
+}
+
+#endif
diff --git a/contrib/llvm/tools/lld/COFF/MarkLive.cpp b/contrib/llvm/tools/lld/COFF/MarkLive.cpp
new file mode 100644
index 000000000000..18b1c9c2529f
--- /dev/null
+++ b/contrib/llvm/tools/lld/COFF/MarkLive.cpp
@@ -0,0 +1,74 @@
+//===- MarkLive.cpp -------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Chunks.h"
+#include "Symbols.h"
+#include "lld/Common/Timer.h"
+#include "llvm/ADT/STLExtras.h"
+#include <vector>
+
+namespace lld {
+namespace coff {
+
+static Timer GCTimer("GC", Timer::root());
+
+// Set live bit on for each reachable chunk. Unmarked (unreachable)
+// COMDAT chunks will be ignored by Writer, so they will be excluded
+// from the final output.
+void markLive(ArrayRef<Chunk *> Chunks) {
+ ScopedTimer T(GCTimer);
+
+ // We build up a worklist of sections which have been marked as live. We only
+ // push into the worklist when we discover an unmarked section, and we mark
+ // as we push, so sections never appear twice in the list.
+ SmallVector<SectionChunk *, 256> Worklist;
+
+ // COMDAT section chunks are dead by default. Add non-COMDAT chunks.
+ for (Chunk *C : Chunks)
+ if (auto *SC = dyn_cast<SectionChunk>(C))
+ if (SC->Live)
+ Worklist.push_back(SC);
+
+ auto Enqueue = [&](SectionChunk *C) {
+ if (C->Live)
+ return;
+ C->Live = true;
+ Worklist.push_back(C);
+ };
+
+ auto AddSym = [&](Symbol *B) {
+ if (auto *Sym = dyn_cast<DefinedRegular>(B))
+ Enqueue(Sym->getChunk());
+ else if (auto *Sym = dyn_cast<DefinedImportData>(B))
+ Sym->File->Live = true;
+ else if (auto *Sym = dyn_cast<DefinedImportThunk>(B))
+ Sym->WrappedSym->File->Live = Sym->WrappedSym->File->ThunkLive = true;
+ };
+
+ // Add GC root chunks.
+ for (Symbol *B : Config->GCRoot)
+ AddSym(B);
+
+ while (!Worklist.empty()) {
+ SectionChunk *SC = Worklist.pop_back_val();
+ assert(SC->Live && "We mark as live when pushing onto the worklist!");
+
+ // Mark all symbols listed in the relocation table for this section.
+ for (Symbol *B : SC->symbols())
+ if (B)
+ AddSym(B);
+
+ // Mark associative sections if any.
+ for (SectionChunk *C : SC->children())
+ Enqueue(C);
+ }
+}
+
+}
+}
diff --git a/contrib/llvm/tools/lld/COFF/MarkLive.h b/contrib/llvm/tools/lld/COFF/MarkLive.h
new file mode 100644
index 000000000000..5b652dd48196
--- /dev/null
+++ b/contrib/llvm/tools/lld/COFF/MarkLive.h
@@ -0,0 +1,24 @@
+//===- MarkLive.h -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_MARKLIVE_H
+#define LLD_COFF_MARKLIVE_H
+
+#include "lld/Common/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+
+namespace lld {
+namespace coff {
+
+void markLive(ArrayRef<Chunk *> Chunks);
+
+} // namespace coff
+} // namespace lld
+
+#endif // LLD_COFF_MARKLIVE_H
diff --git a/contrib/llvm/tools/lld/COFF/MinGW.cpp b/contrib/llvm/tools/lld/COFF/MinGW.cpp
new file mode 100644
index 000000000000..b2c8c4eadca4
--- /dev/null
+++ b/contrib/llvm/tools/lld/COFF/MinGW.cpp
@@ -0,0 +1,176 @@
+//===- MinGW.cpp ----------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MinGW.h"
+#include "SymbolTable.h"
+#include "lld/Common/ErrorHandler.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace lld;
+using namespace lld::coff;
+using namespace llvm;
+using namespace llvm::COFF;
+
+void AutoExporter::initSymbolExcludes() {
+ ExcludeSymbolPrefixes = {
+ // Import symbols
+ "__imp_",
+ "__IMPORT_DESCRIPTOR_",
+ // Extra import symbols from GNU import libraries
+ "__nm_",
+ // C++ symbols
+ "__rtti_",
+ "__builtin_",
+ // Artifical symbols such as .refptr
+ ".",
+ };
+ ExcludeSymbolSuffixes = {
+ "_iname",
+ "_NULL_THUNK_DATA",
+ };
+ if (Config->Machine == I386) {
+ ExcludeSymbols = {
+ "__NULL_IMPORT_DESCRIPTOR",
+ "__pei386_runtime_relocator",
+ "_do_pseudo_reloc",
+ "_impure_ptr",
+ "__impure_ptr",
+ "__fmode",
+ "_environ",
+ "___dso_handle",
+ // These are the MinGW names that differ from the standard
+ // ones (lacking an extra underscore).
+ "_DllMain@12",
+ "_DllEntryPoint@12",
+ "_DllMainCRTStartup@12",
+ };
+ ExcludeSymbolPrefixes.insert("__head_");
+ } else {
+ ExcludeSymbols = {
+ "__NULL_IMPORT_DESCRIPTOR",
+ "_pei386_runtime_relocator",
+ "do_pseudo_reloc",
+ "impure_ptr",
+ "_impure_ptr",
+ "_fmode",
+ "environ",
+ "__dso_handle",
+ // These are the MinGW names that differ from the standard
+ // ones (lacking an extra underscore).
+ "DllMain",
+ "DllEntryPoint",
+ "DllMainCRTStartup",
+ };
+ ExcludeSymbolPrefixes.insert("_head_");
+ }
+}
+
+AutoExporter::AutoExporter() {
+ ExcludeLibs = {
+ "libgcc",
+ "libgcc_s",
+ "libstdc++",
+ "libmingw32",
+ "libmingwex",
+ "libg2c",
+ "libsupc++",
+ "libobjc",
+ "libgcj",
+ "libclang_rt.builtins",
+ "libclang_rt.builtins-aarch64",
+ "libclang_rt.builtins-arm",
+ "libclang_rt.builtins-i386",
+ "libclang_rt.builtins-x86_64",
+ "libc++",
+ "libc++abi",
+ "libunwind",
+ "libmsvcrt",
+ "libucrtbase",
+ };
+ ExcludeObjects = {
+ "crt0.o",
+ "crt1.o",
+ "crt1u.o",
+ "crt2.o",
+ "crt2u.o",
+ "dllcrt1.o",
+ "dllcrt2.o",
+ "gcrt0.o",
+ "gcrt1.o",
+ "gcrt2.o",
+ "crtbegin.o",
+ "crtend.o",
+ };
+}
+
+void AutoExporter::addWholeArchive(StringRef Path) {
+ StringRef LibName = sys::path::filename(Path);
+ // Drop the file extension, to match the processing below.
+ LibName = LibName.substr(0, LibName.rfind('.'));
+ ExcludeLibs.erase(LibName);
+}
+
+bool AutoExporter::shouldExport(Defined *Sym) const {
+ if (!Sym || !Sym->isLive() || !Sym->getChunk())
+ return false;
+
+ // Only allow the symbol kinds that make sense to export; in particular,
+ // disallow import symbols.
+ if (!isa<DefinedRegular>(Sym) && !isa<DefinedCommon>(Sym))
+ return false;
+ if (ExcludeSymbols.count(Sym->getName()))
+ return false;
+
+ for (StringRef Prefix : ExcludeSymbolPrefixes.keys())
+ if (Sym->getName().startswith(Prefix))
+ return false;
+ for (StringRef Suffix : ExcludeSymbolSuffixes.keys())
+ if (Sym->getName().endswith(Suffix))
+ return false;
+
+ // If a corresponding __imp_ symbol exists and is defined, don't export it.
+ if (Symtab->find(("__imp_" + Sym->getName()).str()))
+ return false;
+
+ // Check that file is non-null before dereferencing it, symbols not
+ // originating in regular object files probably shouldn't be exported.
+ if (!Sym->getFile())
+ return false;
+
+ StringRef LibName = sys::path::filename(Sym->getFile()->ParentName);
+
+ // Drop the file extension.
+ LibName = LibName.substr(0, LibName.rfind('.'));
+ if (!LibName.empty())
+ return !ExcludeLibs.count(LibName);
+
+ StringRef FileName = sys::path::filename(Sym->getFile()->getName());
+ return !ExcludeObjects.count(FileName);
+}
+
+void coff::writeDefFile(StringRef Name) {
+ std::error_code EC;
+ raw_fd_ostream OS(Name, EC, sys::fs::F_None);
+ if (EC)
+ fatal("cannot open " + Name + ": " + EC.message());
+
+ OS << "EXPORTS\n";
+ for (Export &E : Config->Exports) {
+ OS << " " << E.ExportName << " "
+ << "@" << E.Ordinal;
+ if (auto *Def = dyn_cast_or_null<Defined>(E.Sym)) {
+ if (Def && Def->getChunk() &&
+ !(Def->getChunk()->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE))
+ OS << " DATA";
+ }
+ OS << "\n";
+ }
+}
diff --git a/contrib/llvm/tools/lld/COFF/MinGW.h b/contrib/llvm/tools/lld/COFF/MinGW.h
new file mode 100644
index 000000000000..f9c5e3e5c2cc
--- /dev/null
+++ b/contrib/llvm/tools/lld/COFF/MinGW.h
@@ -0,0 +1,44 @@
+//===- MinGW.h --------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_MINGW_H
+#define LLD_COFF_MINGW_H
+
+#include "Config.h"
+#include "Symbols.h"
+#include "lld/Common/LLVM.h"
+
+namespace lld {
+namespace coff {
+
+// Logic for deciding what symbols to export, when exporting all
+// symbols for MinGW.
+class AutoExporter {
+public:
+ AutoExporter();
+
+ void initSymbolExcludes();
+
+ void addWholeArchive(StringRef Path);
+
+ llvm::StringSet<> ExcludeSymbols;
+ llvm::StringSet<> ExcludeSymbolPrefixes;
+ llvm::StringSet<> ExcludeSymbolSuffixes;
+ llvm::StringSet<> ExcludeLibs;
+ llvm::StringSet<> ExcludeObjects;
+
+ bool shouldExport(Defined *Sym) const;
+};
+
+void writeDefFile(StringRef Name);
+
+} // namespace coff
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/COFF/Options.td b/contrib/llvm/tools/lld/COFF/Options.td
new file mode 100644
index 000000000000..acf1bc5c8b1d
--- /dev/null
+++ b/contrib/llvm/tools/lld/COFF/Options.td
@@ -0,0 +1,194 @@
+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 which can be suffixed by ":no". Using it unsuffixed turns the
+// flag on and using it suffixed by ":no" turns it off.
+multiclass B<string name, string help_on, string help_off> {
+ def "" : F<name>, HelpText<help_on>;
+ def _no : F<name#":no">, HelpText<help_off>;
+}
+
+def align : P<"align", "Section alignment">;
+def aligncomm : P<"aligncomm", "Set common symbol alignment">;
+def alternatename : P<"alternatename", "Define weak alias">;
+def base : P<"base", "Base address of the program">;
+def color_diagnostics: Flag<["--"], "color-diagnostics">,
+ HelpText<"Use colors in diagnostics">;
+def color_diagnostics_eq: Joined<["--"], "color-diagnostics=">,
+ HelpText<"Use colors in diagnostics; one of 'always', 'never', 'auto'">;
+def defaultlib : P<"defaultlib", "Add the library to the list of input files">;
+def delayload : P<"delayload", "Delay loaded DLL name">;
+def entry : P<"entry", "Name of entry point symbol">;
+def errorlimit : P<"errorlimit",
+ "Maximum number of errors to emit before stopping (0 = no limit)">;
+def export : P<"export", "Export a function">;
+// No help text because /failifmismatch is not intended to be used by the user.
+def failifmismatch : P<"failifmismatch", "">;
+def guard : P<"guard", "Control flow guard">;
+def heap : P<"heap", "Size of the heap">;
+def ignore : P<"ignore", "Specify warning codes to ignore">;
+def implib : P<"implib", "Import library name">;
+def lib : F<"lib">,
+ HelpText<"Act like lib.exe; must be first argument if present">;
+def libpath : P<"libpath", "Additional library search path">;
+def linkrepro : P<"linkrepro", "Dump linker invocation and input files for debugging">;
+def lldltocache : P<"lldltocache", "Path to ThinLTO cached object file directory">;
+def lldltocachepolicy : P<"lldltocachepolicy", "Pruning policy for the ThinLTO cache">;
+def lldsavetemps : F<"lldsavetemps">,
+ HelpText<"Save temporary files instead of deleting them">;
+def machine : P<"machine", "Specify target platform">;
+def merge : P<"merge", "Combine sections">;
+def mllvm : P<"mllvm", "Options to pass to LLVM">;
+def nodefaultlib : P<"nodefaultlib", "Remove a default library">;
+def opt : P<"opt", "Control optimizations">;
+def order : P<"order", "Put functions in order">;
+def out : P<"out", "Path to file to write output">;
+def natvis : P<"natvis", "Path to natvis file to embed in the PDB">;
+def no_color_diagnostics: F<"no-color-diagnostics">,
+ HelpText<"Do not use colors in diagnostics">;
+def pdb : P<"pdb", "PDB file path">;
+def pdbaltpath : P<"pdbaltpath", "PDB file path to embed in the image">;
+def section : P<"section", "Specify section attributes">;
+def stack : P<"stack", "Size of the stack">;
+def stub : P<"stub", "Specify DOS stub file">;
+def subsystem : P<"subsystem", "Specify subsystem">;
+def timestamp : P<"timestamp", "Specify the PE header timestamp">;
+def version : P<"version", "Specify a version number in the PE header">;
+def wholearchive_file : P<"wholearchive", "Include all object files from this archive">;
+
+def disallowlib : Joined<["/", "-", "-?"], "disallowlib:">, Alias<nodefaultlib>;
+
+def manifest : F<"manifest">, HelpText<"Create .manifest file">;
+def manifest_colon : P<
+ "manifest",
+ "NO disables manifest output; EMBED[,ID=#] embeds manifest as resource in the image">;
+def manifestuac : P<"manifestuac", "User access control">;
+def manifestfile : P<"manifestfile", "Manifest output path, with /manifest">;
+def manifestdependency : P<
+ "manifestdependency",
+ "Attributes for <dependency> element in manifest file; implies /manifest">;
+def manifestinput : P<
+ "manifestinput",
+ "Additional manifest inputs; only valid with /manifest:embed">;
+
+// 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 debug : F<"debug">, HelpText<"Embed a symbol table in the image">;
+def debug_opt : P<"debug", "Embed a symbol table in the image with option">;
+def debugtype : P<"debugtype", "Debug Info Options">;
+def dll : F<"dll">, HelpText<"Create a DLL">;
+def driver : P<"driver", "Generate a Windows NT Kernel Mode Driver">;
+def nodefaultlib_all : F<"nodefaultlib">,
+ HelpText<"Remove all default libraries">;
+def noentry : F<"noentry">,
+ HelpText<"Don't add reference to DllMainCRTStartup; only valid with /dll">;
+def profile : F<"profile">;
+def repro : F<"Brepro">,
+ HelpText<"Use a hash of the executable as the PE header timestamp">;
+def swaprun_cd : F<"swaprun:cd">;
+def swaprun_net : F<"swaprun:net">;
+def verbose : F<"verbose">;
+def wholearchive_flag : F<"wholearchive">;
+
+def force : F<"force">,
+ HelpText<"Allow undefined and multiply defined symbols when creating executables">;
+def force_unresolved : F<"force:unresolved">,
+ HelpText<"Allow undefined symbols when creating executables">;
+def force_multiple : F<"force:multiple">,
+ HelpText<"Allow multiply defined symbols when creating executables">;
+defm WX : B<"WX", "Treat warnings as errors", "Don't treat warnings as errors">;
+
+defm allowbind : B<"allowbind", "Enable DLL binding (default)",
+ "Disable DLL binding">;
+defm allowisolation : B<"allowisolation", "Enable DLL isolation (default)",
+ "Disable DLL isolation">;
+defm appcontainer : B<"appcontainer",
+ "Image can only be run in an app container",
+ "Image can run outside an app container (default)">;
+defm dynamicbase : B<"dynamicbase", "Enable ASLR (default unless /fixed)",
+ "Disable ASLR (default when /fixed)">;
+defm fixed : B<"fixed", "Disable base relocations",
+ "Enable base relocations (default)">;
+defm highentropyva : B<"highentropyva",
+ "Enable 64-bit ASLR (default on 64-bit)",
+ "Disable 64-bit ASLR">;
+defm incremental : B<"incremental",
+ "Keep original import library if contents are unchanged",
+ "Overwrite import library even if contents are unchanged">;
+defm integritycheck : B<"integritycheck",
+ "Set FORCE_INTEGRITY bit in PE header",
+ "No effect (default)">;
+defm largeaddressaware : B<"largeaddressaware",
+ "Enable large addresses (default on 64-bit)",
+ "Disable large addresses (default on 32-bit)">;
+defm nxcompat : B<"nxcompat", "Enable data execution prevention (default)",
+ "Disable data execution provention">;
+defm safeseh : B<"safeseh",
+ "Produce an image with Safe Exception Handler (only for x86)",
+ "Don't produce an image with Safe Exception Handler">;
+defm tsaware : B<"tsaware",
+ "Create Terminal Server aware executable (default)",
+ "Create non-Terminal Server aware executable">;
+
+def help : F<"help">;
+def help_q : Flag<["/?", "-?"], "">, Alias<help>;
+
+// LLD extensions
+def export_all_symbols : F<"export-all-symbols">;
+def kill_at : F<"kill-at">;
+def lldmingw : F<"lldmingw">;
+def output_def : Joined<["/", "-"], "output-def:">;
+def pdb_source_path : P<"pdbsourcepath",
+ "Base path used to make relative source file path absolute in PDB">;
+def rsp_quoting : Joined<["--"], "rsp-quoting=">,
+ HelpText<"Quoting style for response files, 'windows' (default) or 'posix'">;
+def dash_dash_version : Flag<["--"], "version">,
+ HelpText<"Print version information">;
+
+// Flags for debugging
+def lldmap : F<"lldmap">;
+def lldmap_file : Joined<["/", "-"], "lldmap:">;
+def show_timing : F<"time">;
+
+//==============================================================================
+// 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 nologo : F<"nologo">;
+def throwingnew : F<"throwingnew">;
+def editandcontinue : F<"editandcontinue">;
+def fastfail : F<"fastfail">;
+
+def delay : QF<"delay">;
+def errorreport : QF<"errorreport">;
+def idlout : QF<"idlout">;
+def maxilksize : QF<"maxilksize">;
+def tlbid : QF<"tlbid">;
+def tlbout : QF<"tlbout">;
+def verbose_all : QF<"verbose">;
+def guardsym : QF<"guardsym">;
diff --git a/contrib/llvm/tools/lld/COFF/PDB.cpp b/contrib/llvm/tools/lld/COFF/PDB.cpp
new file mode 100644
index 000000000000..7757b89e2b36
--- /dev/null
+++ b/contrib/llvm/tools/lld/COFF/PDB.cpp
@@ -0,0 +1,1771 @@
+//===- PDB.cpp ------------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PDB.h"
+#include "Chunks.h"
+#include "Config.h"
+#include "Driver.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+#include "Writer.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Timer.h"
+#include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"
+#include "llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h"
+#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
+#include "llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h"
+#include "llvm/DebugInfo/CodeView/RecordName.h"
+#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecordHelpers.h"
+#include "llvm/DebugInfo/CodeView/SymbolSerializer.h"
+#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
+#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
+#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
+#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
+#include "llvm/DebugInfo/MSF/MSFBuilder.h"
+#include "llvm/DebugInfo/MSF/MSFCommon.h"
+#include "llvm/DebugInfo/PDB/GenericError.h"
+#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/TpiHashing.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h"
+#include "llvm/DebugInfo/PDB/PDB.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Object/CVDebugRecord.h"
+#include "llvm/Support/BinaryByteStream.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/JamCRC.h"
+#include "llvm/Support/Parallel.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/ScopedPrinter.h"
+#include <memory>
+
+using namespace lld;
+using namespace lld::coff;
+using namespace llvm;
+using namespace llvm::codeview;
+
+using llvm::object::coff_section;
+
+static ExitOnError ExitOnErr;
+
+static Timer TotalPdbLinkTimer("PDB Emission (Cumulative)", Timer::root());
+
+static Timer AddObjectsTimer("Add Objects", TotalPdbLinkTimer);
+static Timer TypeMergingTimer("Type Merging", AddObjectsTimer);
+static Timer SymbolMergingTimer("Symbol Merging", AddObjectsTimer);
+static Timer GlobalsLayoutTimer("Globals Stream Layout", TotalPdbLinkTimer);
+static Timer TpiStreamLayoutTimer("TPI Stream Layout", TotalPdbLinkTimer);
+static Timer DiskCommitTimer("Commit to Disk", TotalPdbLinkTimer);
+
+namespace {
+/// Map from type index and item index in a type server PDB to the
+/// corresponding index in the destination PDB.
+struct CVIndexMap {
+ SmallVector<TypeIndex, 0> TPIMap;
+ SmallVector<TypeIndex, 0> IPIMap;
+ bool IsTypeServerMap = false;
+ bool IsPrecompiledTypeMap = false;
+};
+
+class DebugSHandler;
+
+class PDBLinker {
+ friend DebugSHandler;
+
+public:
+ PDBLinker(SymbolTable *Symtab)
+ : Alloc(), Symtab(Symtab), Builder(Alloc), TypeTable(Alloc),
+ IDTable(Alloc), GlobalTypeTable(Alloc), GlobalIDTable(Alloc) {
+ // This isn't strictly necessary, but link.exe usually puts an empty string
+ // as the first "valid" string in the string table, so we do the same in
+ // order to maintain as much byte-for-byte compatibility as possible.
+ PDBStrTab.insert("");
+ }
+
+ /// Emit the basic PDB structure: initial streams, headers, etc.
+ void initialize(llvm::codeview::DebugInfo *BuildId);
+
+ /// Add natvis files specified on the command line.
+ void addNatvisFiles();
+
+ /// Link CodeView from each object file in the symbol table into the PDB.
+ void addObjectsToPDB();
+
+ /// Link CodeView from a single object file into the target (output) PDB.
+ /// When a precompiled headers object is linked, its TPI map might be provided
+ /// externally.
+ void addObjFile(ObjFile *File, CVIndexMap *ExternIndexMap = nullptr);
+
+ /// Produce a mapping from the type and item indices used in the object
+ /// file to those in the destination PDB.
+ ///
+ /// If the object file uses a type server PDB (compiled with /Zi), merge TPI
+ /// and IPI from the type server PDB and return a map for it. Each unique type
+ /// server PDB is merged at most once, so this may return an existing index
+ /// mapping.
+ ///
+ /// If the object does not use a type server PDB (compiled with /Z7), we merge
+ /// all the type and item records from the .debug$S stream and fill in the
+ /// caller-provided ObjectIndexMap.
+ Expected<const CVIndexMap &> mergeDebugT(ObjFile *File,
+ CVIndexMap *ObjectIndexMap);
+
+ /// Reads and makes available a PDB.
+ Expected<const CVIndexMap &> maybeMergeTypeServerPDB(ObjFile *File,
+ const CVType &FirstType);
+
+ /// Merges a precompiled headers TPI map into the current TPI map. The
+ /// precompiled headers object will also be loaded and remapped in the
+ /// process.
+ Expected<const CVIndexMap &>
+ mergeInPrecompHeaderObj(ObjFile *File, const CVType &FirstType,
+ CVIndexMap *ObjectIndexMap);
+
+ /// Reads and makes available a precompiled headers object.
+ ///
+ /// This is a requirement for objects compiled with cl.exe /Yu. In that
+ /// case, the referenced object (which was compiled with /Yc) has to be loaded
+ /// first. This is mainly because the current object's TPI stream has external
+ /// references to the precompiled headers object.
+ ///
+ /// If the precompiled headers object was already loaded, this function will
+ /// simply return its (remapped) TPI map.
+ Expected<const CVIndexMap &> aquirePrecompObj(ObjFile *File,
+ PrecompRecord Precomp);
+
+ /// Adds a precompiled headers object signature -> TPI mapping.
+ std::pair<CVIndexMap &, bool /*already there*/>
+ registerPrecompiledHeaders(uint32_t Signature);
+
+ void mergeSymbolRecords(ObjFile *File, const CVIndexMap &IndexMap,
+ std::vector<ulittle32_t *> &StringTableRefs,
+ BinaryStreamRef SymData);
+
+ /// Add the section map and section contributions to the PDB.
+ void addSections(ArrayRef<OutputSection *> OutputSections,
+ ArrayRef<uint8_t> SectionTable);
+
+ /// Get the type table or the global type table if /DEBUG:GHASH is enabled.
+ TypeCollection &getTypeTable() {
+ if (Config->DebugGHashes)
+ return GlobalTypeTable;
+ return TypeTable;
+ }
+
+ /// Get the ID table or the global ID table if /DEBUG:GHASH is enabled.
+ TypeCollection &getIDTable() {
+ if (Config->DebugGHashes)
+ return GlobalIDTable;
+ return IDTable;
+ }
+
+ /// Write the PDB to disk and store the Guid generated for it in *Guid.
+ void commit(codeview::GUID *Guid);
+
+private:
+ BumpPtrAllocator Alloc;
+
+ SymbolTable *Symtab;
+
+ pdb::PDBFileBuilder Builder;
+
+ /// Type records that will go into the PDB TPI stream.
+ MergingTypeTableBuilder TypeTable;
+
+ /// Item records that will go into the PDB IPI stream.
+ MergingTypeTableBuilder IDTable;
+
+ /// Type records that will go into the PDB TPI stream (for /DEBUG:GHASH)
+ GlobalTypeTableBuilder GlobalTypeTable;
+
+ /// Item records that will go into the PDB IPI stream (for /DEBUG:GHASH)
+ GlobalTypeTableBuilder GlobalIDTable;
+
+ /// PDBs use a single global string table for filenames in the file checksum
+ /// table.
+ DebugStringTableSubsection PDBStrTab;
+
+ llvm::SmallString<128> NativePath;
+
+ /// A list of other PDBs which are loaded during the linking process and which
+ /// we need to keep around since the linking operation may reference pointers
+ /// inside of these PDBs.
+ llvm::SmallVector<std::unique_ptr<pdb::NativeSession>, 2> LoadedPDBs;
+
+ std::vector<pdb::SecMapEntry> SectionMap;
+
+ /// Type index mappings of type server PDBs that we've loaded so far.
+ std::map<codeview::GUID, CVIndexMap> TypeServerIndexMappings;
+
+ /// Type index mappings of precompiled objects type map that we've loaded so
+ /// far.
+ std::map<uint32_t, CVIndexMap> PrecompTypeIndexMappings;
+
+ /// List of TypeServer PDBs which cannot be loaded.
+ /// Cached to prevent repeated load attempts.
+ std::map<codeview::GUID, std::string> MissingTypeServerPDBs;
+};
+
+class DebugSHandler {
+ PDBLinker &Linker;
+
+ /// The object file whose .debug$S sections we're processing.
+ ObjFile &File;
+
+ /// The result of merging type indices.
+ const CVIndexMap &IndexMap;
+
+ /// The DEBUG_S_STRINGTABLE subsection. These strings are referred to by
+ /// index from other records in the .debug$S section. All of these strings
+ /// need to be added to the global PDB string table, and all references to
+ /// these strings need to have their indices re-written to refer to the
+ /// global PDB string table.
+ DebugStringTableSubsectionRef CVStrTab;
+
+ /// The DEBUG_S_FILECHKSMS subsection. As above, these are referred to
+ /// by other records in the .debug$S section and need to be merged into the
+ /// PDB.
+ DebugChecksumsSubsectionRef Checksums;
+
+ /// The DEBUG_S_FRAMEDATA subsection(s). There can be more than one of
+ /// these and they need not appear in any specific order. However, they
+ /// contain string table references which need to be re-written, so we
+ /// collect them all here and re-write them after all subsections have been
+ /// discovered and processed.
+ std::vector<DebugFrameDataSubsectionRef> NewFpoFrames;
+
+ /// Pointers to raw memory that we determine have string table references
+ /// that need to be re-written. We first process all .debug$S subsections
+ /// to ensure that we can handle subsections written in any order, building
+ /// up this list as we go. At the end, we use the string table (which must
+ /// have been discovered by now else it is an error) to re-write these
+ /// references.
+ std::vector<ulittle32_t *> StringTableReferences;
+
+public:
+ DebugSHandler(PDBLinker &Linker, ObjFile &File, const CVIndexMap &IndexMap)
+ : Linker(Linker), File(File), IndexMap(IndexMap) {}
+
+ void handleDebugS(lld::coff::SectionChunk &DebugS);
+ void finish();
+};
+}
+
+// Visual Studio's debugger requires absolute paths in various places in the
+// PDB to work without additional configuration:
+// https://docs.microsoft.com/en-us/visualstudio/debugger/debug-source-files-common-properties-solution-property-pages-dialog-box
+static void pdbMakeAbsolute(SmallVectorImpl<char> &FileName) {
+ // The default behavior is to produce paths that are valid within the context
+ // of the machine that you perform the link on. If the linker is running on
+ // a POSIX system, we will output absolute POSIX paths. If the linker is
+ // running on a Windows system, we will output absolute Windows paths. If the
+ // user desires any other kind of behavior, they should explicitly pass
+ // /pdbsourcepath, in which case we will treat the exact string the user
+ // passed in as the gospel and not normalize, canonicalize it.
+ if (sys::path::is_absolute(FileName, sys::path::Style::windows) ||
+ sys::path::is_absolute(FileName, sys::path::Style::posix))
+ return;
+
+ // It's not absolute in any path syntax. Relative paths necessarily refer to
+ // the local file system, so we can make it native without ending up with a
+ // nonsensical path.
+ if (Config->PDBSourcePath.empty()) {
+ sys::path::native(FileName);
+ sys::fs::make_absolute(FileName);
+ return;
+ }
+
+ // Try to guess whether /PDBSOURCEPATH is a unix path or a windows path.
+ // Since PDB's are more of a Windows thing, we make this conservative and only
+ // decide that it's a unix path if we're fairly certain. Specifically, if
+ // it starts with a forward slash.
+ SmallString<128> AbsoluteFileName = Config->PDBSourcePath;
+ sys::path::Style GuessedStyle = AbsoluteFileName.startswith("/")
+ ? sys::path::Style::posix
+ : sys::path::Style::windows;
+ sys::path::append(AbsoluteFileName, GuessedStyle, FileName);
+ sys::path::native(AbsoluteFileName, GuessedStyle);
+ sys::path::remove_dots(AbsoluteFileName, true, GuessedStyle);
+
+ FileName = std::move(AbsoluteFileName);
+}
+
+static SectionChunk *findByName(ArrayRef<SectionChunk *> Sections,
+ StringRef Name) {
+ for (SectionChunk *C : Sections)
+ if (C->getSectionName() == Name)
+ return C;
+ return nullptr;
+}
+
+static ArrayRef<uint8_t> consumeDebugMagic(ArrayRef<uint8_t> Data,
+ StringRef SecName) {
+ // First 4 bytes are section magic.
+ if (Data.size() < 4)
+ fatal(SecName + " too short");
+ if (support::endian::read32le(Data.data()) != COFF::DEBUG_SECTION_MAGIC)
+ fatal(SecName + " has an invalid magic");
+ return Data.slice(4);
+}
+
+static ArrayRef<uint8_t> getDebugSection(ObjFile *File, StringRef SecName) {
+ if (SectionChunk *Sec = findByName(File->getDebugChunks(), SecName))
+ return consumeDebugMagic(Sec->getContents(), SecName);
+ return {};
+}
+
+// A COFF .debug$H section is currently a clang extension. This function checks
+// if a .debug$H section is in a format that we expect / understand, so that we
+// can ignore any sections which are coincidentally also named .debug$H but do
+// not contain a format we recognize.
+static bool canUseDebugH(ArrayRef<uint8_t> DebugH) {
+ if (DebugH.size() < sizeof(object::debug_h_header))
+ return false;
+ auto *Header =
+ reinterpret_cast<const object::debug_h_header *>(DebugH.data());
+ DebugH = DebugH.drop_front(sizeof(object::debug_h_header));
+ return Header->Magic == COFF::DEBUG_HASHES_SECTION_MAGIC &&
+ Header->Version == 0 &&
+ Header->HashAlgorithm == uint16_t(GlobalTypeHashAlg::SHA1_8) &&
+ (DebugH.size() % 8 == 0);
+}
+
+static Optional<ArrayRef<uint8_t>> getDebugH(ObjFile *File) {
+ SectionChunk *Sec = findByName(File->getDebugChunks(), ".debug$H");
+ if (!Sec)
+ return llvm::None;
+ ArrayRef<uint8_t> Contents = Sec->getContents();
+ if (!canUseDebugH(Contents))
+ return None;
+ return Contents;
+}
+
+static ArrayRef<GloballyHashedType>
+getHashesFromDebugH(ArrayRef<uint8_t> DebugH) {
+ assert(canUseDebugH(DebugH));
+
+ DebugH = DebugH.drop_front(sizeof(object::debug_h_header));
+ uint32_t Count = DebugH.size() / sizeof(GloballyHashedType);
+ return {reinterpret_cast<const GloballyHashedType *>(DebugH.data()), Count};
+}
+
+static void addTypeInfo(pdb::TpiStreamBuilder &TpiBuilder,
+ TypeCollection &TypeTable) {
+ // Start the TPI or IPI stream header.
+ TpiBuilder.setVersionHeader(pdb::PdbTpiV80);
+
+ // Flatten the in memory type table and hash each type.
+ TypeTable.ForEachRecord([&](TypeIndex TI, const CVType &Type) {
+ auto Hash = pdb::hashTypeRecord(Type);
+ if (auto E = Hash.takeError())
+ fatal("type hashing error");
+ TpiBuilder.addTypeRecord(Type.RecordData, *Hash);
+ });
+}
+
+// OBJs usually start their symbol stream with a S_OBJNAME record. This record
+// also contains the signature/key of the current PCH session. The signature
+// must be same for all objects which depend on the precompiled object.
+// Recompiling the precompiled headers will generate a new PCH key and thus
+// invalidate all the dependent objects.
+static uint32_t extractPCHSignature(ObjFile *File) {
+ auto DbgIt = find_if(File->getDebugChunks(), [](SectionChunk *C) {
+ return C->getSectionName() == ".debug$S";
+ });
+ if (!DbgIt)
+ return 0;
+
+ ArrayRef<uint8_t> Contents =
+ consumeDebugMagic((*DbgIt)->getContents(), ".debug$S");
+ DebugSubsectionArray Subsections;
+ BinaryStreamReader Reader(Contents, support::little);
+ ExitOnErr(Reader.readArray(Subsections, Contents.size()));
+
+ for (const DebugSubsectionRecord &SS : Subsections) {
+ if (SS.kind() != DebugSubsectionKind::Symbols)
+ continue;
+
+ // If it's there, the S_OBJNAME record shall come first in the stream.
+ Expected<CVSymbol> Sym = readSymbolFromStream(SS.getRecordData(), 0);
+ if (!Sym) {
+ consumeError(Sym.takeError());
+ continue;
+ }
+ if (auto ObjName = SymbolDeserializer::deserializeAs<ObjNameSym>(Sym.get()))
+ return ObjName->Signature;
+ }
+ return 0;
+}
+
+Expected<const CVIndexMap &>
+PDBLinker::mergeDebugT(ObjFile *File, CVIndexMap *ObjectIndexMap) {
+ ScopedTimer T(TypeMergingTimer);
+
+ bool IsPrecompiledHeader = false;
+
+ ArrayRef<uint8_t> Data = getDebugSection(File, ".debug$T");
+ if (Data.empty()) {
+ // Try again, Microsoft precompiled headers use .debug$P instead of
+ // .debug$T
+ Data = getDebugSection(File, ".debug$P");
+ IsPrecompiledHeader = true;
+ }
+ if (Data.empty())
+ return *ObjectIndexMap; // no debug info
+
+ // Precompiled headers objects need to save the index map for further
+ // reference by other objects which use the precompiled headers.
+ if (IsPrecompiledHeader) {
+ uint32_t PCHSignature = extractPCHSignature(File);
+ if (PCHSignature == 0)
+ fatal("No signature found for the precompiled headers OBJ (" +
+ File->getName() + ")");
+
+ // When a precompiled headers object comes first on the command-line, we
+ // update the mapping here. Otherwise, if an object referencing the
+ // precompiled headers object comes first, the mapping is created in
+ // aquirePrecompObj(), thus we would skip this block.
+ if (!ObjectIndexMap->IsPrecompiledTypeMap) {
+ auto R = registerPrecompiledHeaders(PCHSignature);
+ if (R.second)
+ fatal(
+ "A precompiled headers OBJ with the same signature was already "
+ "provided! (" +
+ File->getName() + ")");
+
+ ObjectIndexMap = &R.first;
+ }
+ }
+
+ BinaryByteStream Stream(Data, support::little);
+ CVTypeArray Types;
+ BinaryStreamReader Reader(Stream);
+ if (auto EC = Reader.readArray(Types, Reader.getLength()))
+ fatal("Reader::readArray failed: " + toString(std::move(EC)));
+
+ auto FirstType = Types.begin();
+ if (FirstType == Types.end())
+ return *ObjectIndexMap;
+
+ if (FirstType->kind() == LF_TYPESERVER2) {
+ // Look through type servers. If we've already seen this type server,
+ // don't merge any type information.
+ return maybeMergeTypeServerPDB(File, *FirstType);
+ } else if (FirstType->kind() == LF_PRECOMP) {
+ // This object was compiled with /Yu, so process the corresponding
+ // precompiled headers object (/Yc) first. Some type indices in the current
+ // object are referencing data in the precompiled headers object, so we need
+ // both to be loaded.
+ auto E = mergeInPrecompHeaderObj(File, *FirstType, ObjectIndexMap);
+ if (!E)
+ return E.takeError();
+
+ // Drop LF_PRECOMP record from the input stream, as it needs to be replaced
+ // with the precompiled headers object type stream.
+ // Note that we can't just call Types.drop_front(), as we explicitly want to
+ // rebase the stream.
+ Types.setUnderlyingStream(
+ Types.getUnderlyingStream().drop_front(FirstType->RecordData.size()));
+ }
+
+ // Fill in the temporary, caller-provided ObjectIndexMap.
+ if (Config->DebugGHashes) {
+ ArrayRef<GloballyHashedType> Hashes;
+ std::vector<GloballyHashedType> OwnedHashes;
+ if (Optional<ArrayRef<uint8_t>> DebugH = getDebugH(File))
+ Hashes = getHashesFromDebugH(*DebugH);
+ else {
+ OwnedHashes = GloballyHashedType::hashTypes(Types);
+ Hashes = OwnedHashes;
+ }
+
+ if (auto Err = mergeTypeAndIdRecords(GlobalIDTable, GlobalTypeTable,
+ ObjectIndexMap->TPIMap, Types, Hashes,
+ File->PCHSignature))
+ fatal("codeview::mergeTypeAndIdRecords failed: " +
+ toString(std::move(Err)));
+ } else {
+ if (auto Err =
+ mergeTypeAndIdRecords(IDTable, TypeTable, ObjectIndexMap->TPIMap,
+ Types, File->PCHSignature))
+ fatal("codeview::mergeTypeAndIdRecords failed: " +
+ toString(std::move(Err)));
+ }
+ return *ObjectIndexMap;
+}
+
+static Expected<std::unique_ptr<pdb::NativeSession>>
+tryToLoadPDB(const codeview::GUID &GuidFromObj, StringRef TSPath) {
+ // Ensure the file exists before anything else. We want to return ENOENT,
+ // "file not found", even if the path points to a removable device (in which
+ // case the return message would be EAGAIN, "resource unavailable try again")
+ if (!llvm::sys::fs::exists(TSPath))
+ return errorCodeToError(std::error_code(ENOENT, std::generic_category()));
+
+ ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr = MemoryBuffer::getFile(
+ TSPath, /*FileSize=*/-1, /*RequiresNullTerminator=*/false);
+ if (!MBOrErr)
+ return errorCodeToError(MBOrErr.getError());
+
+ std::unique_ptr<pdb::IPDBSession> ThisSession;
+ if (auto EC = pdb::NativeSession::createFromPdb(
+ MemoryBuffer::getMemBuffer(Driver->takeBuffer(std::move(*MBOrErr)),
+ /*RequiresNullTerminator=*/false),
+ ThisSession))
+ return std::move(EC);
+
+ std::unique_ptr<pdb::NativeSession> NS(
+ static_cast<pdb::NativeSession *>(ThisSession.release()));
+ pdb::PDBFile &File = NS->getPDBFile();
+ auto ExpectedInfo = File.getPDBInfoStream();
+ // All PDB Files should have an Info stream.
+ if (!ExpectedInfo)
+ return ExpectedInfo.takeError();
+
+ // Just because a file with a matching name was found and it was an actual
+ // PDB file doesn't mean it matches. For it to match the InfoStream's GUID
+ // must match the GUID specified in the TypeServer2 record.
+ if (ExpectedInfo->getGuid() != GuidFromObj)
+ return make_error<pdb::PDBError>(pdb::pdb_error_code::signature_out_of_date);
+
+ return std::move(NS);
+}
+
+Expected<const CVIndexMap &>
+PDBLinker::maybeMergeTypeServerPDB(ObjFile *File, const CVType &FirstType) {
+ TypeServer2Record TS;
+ if (auto EC =
+ TypeDeserializer::deserializeAs(const_cast<CVType &>(FirstType), TS))
+ fatal("error reading record: " + toString(std::move(EC)));
+
+ const codeview::GUID &TSId = TS.getGuid();
+ StringRef TSPath = TS.getName();
+
+ // First, check if the PDB has previously failed to load.
+ auto PrevErr = MissingTypeServerPDBs.find(TSId);
+ if (PrevErr != MissingTypeServerPDBs.end())
+ return createFileError(
+ TSPath,
+ make_error<StringError>(PrevErr->second, inconvertibleErrorCode()));
+
+ // Second, check if we already loaded a PDB with this GUID. Return the type
+ // index mapping if we have it.
+ auto Insertion = TypeServerIndexMappings.insert({TSId, CVIndexMap()});
+ CVIndexMap &IndexMap = Insertion.first->second;
+ if (!Insertion.second)
+ return IndexMap;
+
+ // Mark this map as a type server map.
+ IndexMap.IsTypeServerMap = true;
+
+ // Check for a PDB at:
+ // 1. The given file path
+ // 2. Next to the object file or archive file
+ auto ExpectedSession = handleExpected(
+ tryToLoadPDB(TSId, TSPath),
+ [&]() {
+ StringRef LocalPath =
+ !File->ParentName.empty() ? File->ParentName : File->getName();
+ SmallString<128> Path = sys::path::parent_path(LocalPath);
+ // Currently, type server PDBs are only created by cl, which only runs
+ // on Windows, so we can assume type server paths are Windows style.
+ sys::path::append(
+ Path, sys::path::filename(TSPath, sys::path::Style::windows));
+ return tryToLoadPDB(TSId, Path);
+ },
+ [&](std::unique_ptr<ECError> EC) -> Error {
+ auto SysErr = EC->convertToErrorCode();
+ // Only re-try loading if the previous error was "No such file or
+ // directory"
+ if (SysErr.category() == std::generic_category() &&
+ SysErr.value() == ENOENT)
+ return Error::success();
+ return Error(std::move(EC));
+ });
+
+ if (auto E = ExpectedSession.takeError()) {
+ TypeServerIndexMappings.erase(TSId);
+
+ // Flatten the error to a string, for later display, if the error occurs
+ // again on the same PDB.
+ std::string ErrMsg;
+ raw_string_ostream S(ErrMsg);
+ S << E;
+ MissingTypeServerPDBs.emplace(TSId, S.str());
+
+ return createFileError(TSPath, std::move(E));
+ }
+
+ pdb::NativeSession *Session = ExpectedSession->get();
+
+ // Keep a strong reference to this PDB, so that it's safe to hold pointers
+ // into the file.
+ LoadedPDBs.push_back(std::move(*ExpectedSession));
+
+ auto ExpectedTpi = Session->getPDBFile().getPDBTpiStream();
+ if (auto E = ExpectedTpi.takeError())
+ fatal("Type server does not have TPI stream: " + toString(std::move(E)));
+ auto ExpectedIpi = Session->getPDBFile().getPDBIpiStream();
+ if (auto E = ExpectedIpi.takeError())
+ fatal("Type server does not have TPI stream: " + toString(std::move(E)));
+
+ if (Config->DebugGHashes) {
+ // PDBs do not actually store global hashes, so when merging a type server
+ // PDB we have to synthesize global hashes. To do this, we first synthesize
+ // global hashes for the TPI stream, since it is independent, then we
+ // synthesize hashes for the IPI stream, using the hashes for the TPI stream
+ // as inputs.
+ auto TpiHashes = GloballyHashedType::hashTypes(ExpectedTpi->typeArray());
+ auto IpiHashes =
+ GloballyHashedType::hashIds(ExpectedIpi->typeArray(), TpiHashes);
+
+ Optional<uint32_t> EndPrecomp;
+ // Merge TPI first, because the IPI stream will reference type indices.
+ if (auto Err = mergeTypeRecords(GlobalTypeTable, IndexMap.TPIMap,
+ ExpectedTpi->typeArray(), TpiHashes, EndPrecomp))
+ fatal("codeview::mergeTypeRecords failed: " + toString(std::move(Err)));
+
+ // Merge IPI.
+ if (auto Err =
+ mergeIdRecords(GlobalIDTable, IndexMap.TPIMap, IndexMap.IPIMap,
+ ExpectedIpi->typeArray(), IpiHashes))
+ fatal("codeview::mergeIdRecords failed: " + toString(std::move(Err)));
+ } else {
+ // Merge TPI first, because the IPI stream will reference type indices.
+ if (auto Err = mergeTypeRecords(TypeTable, IndexMap.TPIMap,
+ ExpectedTpi->typeArray()))
+ fatal("codeview::mergeTypeRecords failed: " + toString(std::move(Err)));
+
+ // Merge IPI.
+ if (auto Err = mergeIdRecords(IDTable, IndexMap.TPIMap, IndexMap.IPIMap,
+ ExpectedIpi->typeArray()))
+ fatal("codeview::mergeIdRecords failed: " + toString(std::move(Err)));
+ }
+
+ return IndexMap;
+}
+
+Expected<const CVIndexMap &>
+PDBLinker::mergeInPrecompHeaderObj(ObjFile *File, const CVType &FirstType,
+ CVIndexMap *ObjectIndexMap) {
+ PrecompRecord Precomp;
+ if (auto EC = TypeDeserializer::deserializeAs(const_cast<CVType &>(FirstType),
+ Precomp))
+ fatal("error reading record: " + toString(std::move(EC)));
+
+ auto E = aquirePrecompObj(File, Precomp);
+ if (!E)
+ return E.takeError();
+
+ const CVIndexMap &PrecompIndexMap = *E;
+ assert(PrecompIndexMap.IsPrecompiledTypeMap);
+
+ if (PrecompIndexMap.TPIMap.empty())
+ return PrecompIndexMap;
+
+ assert(Precomp.getStartTypeIndex() == TypeIndex::FirstNonSimpleIndex);
+ assert(Precomp.getTypesCount() <= PrecompIndexMap.TPIMap.size());
+ // Use the previously remapped index map from the precompiled headers.
+ ObjectIndexMap->TPIMap.append(PrecompIndexMap.TPIMap.begin(),
+ PrecompIndexMap.TPIMap.begin() +
+ Precomp.getTypesCount());
+ return *ObjectIndexMap;
+}
+
+static bool equals_path(StringRef path1, StringRef path2) {
+#if defined(_WIN32)
+ return path1.equals_lower(path2);
+#else
+ return path1.equals(path2);
+#endif
+}
+
+// Find by name an OBJ provided on the command line
+static ObjFile *findObjByName(StringRef FileNameOnly) {
+ SmallString<128> CurrentPath;
+
+ for (ObjFile *F : ObjFile::Instances) {
+ StringRef CurrentFileName = sys::path::filename(F->getName());
+
+ // Compare based solely on the file name (link.exe behavior)
+ if (equals_path(CurrentFileName, FileNameOnly))
+ return F;
+ }
+ return nullptr;
+}
+
+std::pair<CVIndexMap &, bool /*already there*/>
+PDBLinker::registerPrecompiledHeaders(uint32_t Signature) {
+ auto Insertion = PrecompTypeIndexMappings.insert({Signature, CVIndexMap()});
+ CVIndexMap &IndexMap = Insertion.first->second;
+ if (!Insertion.second)
+ return {IndexMap, true};
+ // Mark this map as a precompiled types map.
+ IndexMap.IsPrecompiledTypeMap = true;
+ return {IndexMap, false};
+}
+
+Expected<const CVIndexMap &>
+PDBLinker::aquirePrecompObj(ObjFile *File, PrecompRecord Precomp) {
+ // First, check if we already loaded the precompiled headers object with this
+ // signature. Return the type index mapping if we've already seen it.
+ auto R = registerPrecompiledHeaders(Precomp.getSignature());
+ if (R.second)
+ return R.first;
+
+ CVIndexMap &IndexMap = R.first;
+
+ // Cross-compile warning: given that Clang doesn't generate LF_PRECOMP
+ // records, we assume the OBJ comes from a Windows build of cl.exe. Thusly,
+ // the paths embedded in the OBJs are in the Windows format.
+ SmallString<128> PrecompFileName = sys::path::filename(
+ Precomp.getPrecompFilePath(), sys::path::Style::windows);
+
+ // link.exe requires that a precompiled headers object must always be provided
+ // on the command-line, even if that's not necessary.
+ auto PrecompFile = findObjByName(PrecompFileName);
+ if (!PrecompFile)
+ return createFileError(
+ PrecompFileName.str(),
+ make_error<pdb::PDBError>(pdb::pdb_error_code::external_cmdline_ref));
+
+ addObjFile(PrecompFile, &IndexMap);
+
+ if (!PrecompFile->PCHSignature)
+ fatal(PrecompFile->getName() + " is not a precompiled headers object");
+
+ if (Precomp.getSignature() != PrecompFile->PCHSignature.getValueOr(0))
+ return createFileError(
+ Precomp.getPrecompFilePath().str(),
+ make_error<pdb::PDBError>(pdb::pdb_error_code::signature_out_of_date));
+
+ return IndexMap;
+}
+
+static bool remapTypeIndex(TypeIndex &TI, ArrayRef<TypeIndex> TypeIndexMap) {
+ if (TI.isSimple())
+ return true;
+ if (TI.toArrayIndex() >= TypeIndexMap.size())
+ return false;
+ TI = TypeIndexMap[TI.toArrayIndex()];
+ return true;
+}
+
+static void remapTypesInSymbolRecord(ObjFile *File, SymbolKind SymKind,
+ MutableArrayRef<uint8_t> RecordBytes,
+ const CVIndexMap &IndexMap,
+ ArrayRef<TiReference> TypeRefs) {
+ MutableArrayRef<uint8_t> Contents =
+ RecordBytes.drop_front(sizeof(RecordPrefix));
+ for (const TiReference &Ref : TypeRefs) {
+ unsigned ByteSize = Ref.Count * sizeof(TypeIndex);
+ if (Contents.size() < Ref.Offset + ByteSize)
+ fatal("symbol record too short");
+
+ // This can be an item index or a type index. Choose the appropriate map.
+ ArrayRef<TypeIndex> TypeOrItemMap = IndexMap.TPIMap;
+ bool IsItemIndex = Ref.Kind == TiRefKind::IndexRef;
+ if (IsItemIndex && IndexMap.IsTypeServerMap)
+ TypeOrItemMap = IndexMap.IPIMap;
+
+ MutableArrayRef<TypeIndex> TIs(
+ reinterpret_cast<TypeIndex *>(Contents.data() + Ref.Offset), Ref.Count);
+ for (TypeIndex &TI : TIs) {
+ if (!remapTypeIndex(TI, TypeOrItemMap)) {
+ log("ignoring symbol record of kind 0x" + utohexstr(SymKind) + " in " +
+ File->getName() + " with bad " + (IsItemIndex ? "item" : "type") +
+ " index 0x" + utohexstr(TI.getIndex()));
+ TI = TypeIndex(SimpleTypeKind::NotTranslated);
+ continue;
+ }
+ }
+ }
+}
+
+static void
+recordStringTableReferenceAtOffset(MutableArrayRef<uint8_t> Contents,
+ uint32_t Offset,
+ std::vector<ulittle32_t *> &StrTableRefs) {
+ Contents =
+ Contents.drop_front(Offset).take_front(sizeof(support::ulittle32_t));
+ ulittle32_t *Index = reinterpret_cast<ulittle32_t *>(Contents.data());
+ StrTableRefs.push_back(Index);
+}
+
+static void
+recordStringTableReferences(SymbolKind Kind, MutableArrayRef<uint8_t> Contents,
+ std::vector<ulittle32_t *> &StrTableRefs) {
+ // For now we only handle S_FILESTATIC, but we may need the same logic for
+ // S_DEFRANGE and S_DEFRANGE_SUBFIELD. However, I cannot seem to generate any
+ // PDBs that contain these types of records, so because of the uncertainty
+ // they are omitted here until we can prove that it's necessary.
+ switch (Kind) {
+ case SymbolKind::S_FILESTATIC:
+ // FileStaticSym::ModFileOffset
+ recordStringTableReferenceAtOffset(Contents, 8, StrTableRefs);
+ break;
+ case SymbolKind::S_DEFRANGE:
+ case SymbolKind::S_DEFRANGE_SUBFIELD:
+ log("Not fixing up string table reference in S_DEFRANGE / "
+ "S_DEFRANGE_SUBFIELD record");
+ break;
+ default:
+ break;
+ }
+}
+
+static SymbolKind symbolKind(ArrayRef<uint8_t> RecordData) {
+ const RecordPrefix *Prefix =
+ reinterpret_cast<const RecordPrefix *>(RecordData.data());
+ return static_cast<SymbolKind>(uint16_t(Prefix->RecordKind));
+}
+
+/// MSVC translates S_PROC_ID_END to S_END, and S_[LG]PROC32_ID to S_[LG]PROC32
+static void translateIdSymbols(MutableArrayRef<uint8_t> &RecordData,
+ TypeCollection &IDTable) {
+ RecordPrefix *Prefix = reinterpret_cast<RecordPrefix *>(RecordData.data());
+
+ SymbolKind Kind = symbolKind(RecordData);
+
+ if (Kind == SymbolKind::S_PROC_ID_END) {
+ Prefix->RecordKind = SymbolKind::S_END;
+ return;
+ }
+
+ // In an object file, GPROC32_ID has an embedded reference which refers to the
+ // single object file type index namespace. This has already been translated
+ // to the PDB file's ID stream index space, but we need to convert this to a
+ // symbol that refers to the type stream index space. So we remap again from
+ // ID index space to type index space.
+ if (Kind == SymbolKind::S_GPROC32_ID || Kind == SymbolKind::S_LPROC32_ID) {
+ SmallVector<TiReference, 1> Refs;
+ auto Content = RecordData.drop_front(sizeof(RecordPrefix));
+ CVSymbol Sym(Kind, RecordData);
+ discoverTypeIndicesInSymbol(Sym, Refs);
+ assert(Refs.size() == 1);
+ assert(Refs.front().Count == 1);
+
+ TypeIndex *TI =
+ reinterpret_cast<TypeIndex *>(Content.data() + Refs[0].Offset);
+ // `TI` is the index of a FuncIdRecord or MemberFuncIdRecord which lives in
+ // the IPI stream, whose `FunctionType` member refers to the TPI stream.
+ // Note that LF_FUNC_ID and LF_MEMFUNC_ID have the same record layout, and
+ // in both cases we just need the second type index.
+ if (!TI->isSimple() && !TI->isNoneType()) {
+ CVType FuncIdData = IDTable.getType(*TI);
+ SmallVector<TypeIndex, 2> Indices;
+ discoverTypeIndices(FuncIdData, Indices);
+ assert(Indices.size() == 2);
+ *TI = Indices[1];
+ }
+
+ Kind = (Kind == SymbolKind::S_GPROC32_ID) ? SymbolKind::S_GPROC32
+ : SymbolKind::S_LPROC32;
+ Prefix->RecordKind = uint16_t(Kind);
+ }
+}
+
+/// Copy the symbol record. In a PDB, symbol records must be 4 byte aligned.
+/// The object file may not be aligned.
+static MutableArrayRef<uint8_t>
+copyAndAlignSymbol(const CVSymbol &Sym, MutableArrayRef<uint8_t> &AlignedMem) {
+ size_t Size = alignTo(Sym.length(), alignOf(CodeViewContainer::Pdb));
+ assert(Size >= 4 && "record too short");
+ assert(Size <= MaxRecordLength && "record too long");
+ assert(AlignedMem.size() >= Size && "didn't preallocate enough");
+
+ // Copy the symbol record and zero out any padding bytes.
+ MutableArrayRef<uint8_t> NewData = AlignedMem.take_front(Size);
+ AlignedMem = AlignedMem.drop_front(Size);
+ memcpy(NewData.data(), Sym.data().data(), Sym.length());
+ memset(NewData.data() + Sym.length(), 0, Size - Sym.length());
+
+ // Update the record prefix length. It should point to the beginning of the
+ // next record.
+ auto *Prefix = reinterpret_cast<RecordPrefix *>(NewData.data());
+ Prefix->RecordLen = Size - 2;
+ return NewData;
+}
+
+struct ScopeRecord {
+ ulittle32_t PtrParent;
+ ulittle32_t PtrEnd;
+};
+
+struct SymbolScope {
+ ScopeRecord *OpeningRecord;
+ uint32_t ScopeOffset;
+};
+
+static void scopeStackOpen(SmallVectorImpl<SymbolScope> &Stack,
+ uint32_t CurOffset, CVSymbol &Sym) {
+ assert(symbolOpensScope(Sym.kind()));
+ SymbolScope S;
+ S.ScopeOffset = CurOffset;
+ S.OpeningRecord = const_cast<ScopeRecord *>(
+ reinterpret_cast<const ScopeRecord *>(Sym.content().data()));
+ S.OpeningRecord->PtrParent = Stack.empty() ? 0 : Stack.back().ScopeOffset;
+ Stack.push_back(S);
+}
+
+static void scopeStackClose(SmallVectorImpl<SymbolScope> &Stack,
+ uint32_t CurOffset, ObjFile *File) {
+ if (Stack.empty()) {
+ warn("symbol scopes are not balanced in " + File->getName());
+ return;
+ }
+ SymbolScope S = Stack.pop_back_val();
+ S.OpeningRecord->PtrEnd = CurOffset;
+}
+
+static bool symbolGoesInModuleStream(const CVSymbol &Sym, bool IsGlobalScope) {
+ switch (Sym.kind()) {
+ case SymbolKind::S_GDATA32:
+ case SymbolKind::S_CONSTANT:
+ // We really should not be seeing S_PROCREF and S_LPROCREF in the first place
+ // since they are synthesized by the linker in response to S_GPROC32 and
+ // S_LPROC32, but if we do see them, don't put them in the module stream I
+ // guess.
+ case SymbolKind::S_PROCREF:
+ case SymbolKind::S_LPROCREF:
+ return false;
+ // S_UDT records go in the module stream if it is not a global S_UDT.
+ case SymbolKind::S_UDT:
+ return !IsGlobalScope;
+ // S_GDATA32 does not go in the module stream, but S_LDATA32 does.
+ case SymbolKind::S_LDATA32:
+ default:
+ return true;
+ }
+}
+
+static bool symbolGoesInGlobalsStream(const CVSymbol &Sym, bool IsGlobalScope) {
+ switch (Sym.kind()) {
+ case SymbolKind::S_CONSTANT:
+ case SymbolKind::S_GDATA32:
+ // S_LDATA32 goes in both the module stream and the globals stream.
+ case SymbolKind::S_LDATA32:
+ case SymbolKind::S_GPROC32:
+ case SymbolKind::S_LPROC32:
+ // We really should not be seeing S_PROCREF and S_LPROCREF in the first place
+ // since they are synthesized by the linker in response to S_GPROC32 and
+ // S_LPROC32, but if we do see them, copy them straight through.
+ case SymbolKind::S_PROCREF:
+ case SymbolKind::S_LPROCREF:
+ return true;
+ // S_UDT records go in the globals stream if it is a global S_UDT.
+ case SymbolKind::S_UDT:
+ return IsGlobalScope;
+ default:
+ return false;
+ }
+}
+
+static void addGlobalSymbol(pdb::GSIStreamBuilder &Builder, uint16_t ModIndex,
+ unsigned SymOffset, const CVSymbol &Sym) {
+ switch (Sym.kind()) {
+ case SymbolKind::S_CONSTANT:
+ case SymbolKind::S_UDT:
+ case SymbolKind::S_GDATA32:
+ case SymbolKind::S_LDATA32:
+ case SymbolKind::S_PROCREF:
+ case SymbolKind::S_LPROCREF:
+ Builder.addGlobalSymbol(Sym);
+ break;
+ case SymbolKind::S_GPROC32:
+ case SymbolKind::S_LPROC32: {
+ SymbolRecordKind K = SymbolRecordKind::ProcRefSym;
+ if (Sym.kind() == SymbolKind::S_LPROC32)
+ K = SymbolRecordKind::LocalProcRef;
+ ProcRefSym PS(K);
+ PS.Module = ModIndex;
+ // For some reason, MSVC seems to add one to this value.
+ ++PS.Module;
+ PS.Name = getSymbolName(Sym);
+ PS.SumName = 0;
+ PS.SymOffset = SymOffset;
+ Builder.addGlobalSymbol(PS);
+ break;
+ }
+ default:
+ llvm_unreachable("Invalid symbol kind!");
+ }
+}
+
+void PDBLinker::mergeSymbolRecords(ObjFile *File, const CVIndexMap &IndexMap,
+ std::vector<ulittle32_t *> &StringTableRefs,
+ BinaryStreamRef SymData) {
+ ArrayRef<uint8_t> SymsBuffer;
+ cantFail(SymData.readBytes(0, SymData.getLength(), SymsBuffer));
+ SmallVector<SymbolScope, 4> Scopes;
+
+ // Iterate every symbol to check if any need to be realigned, and if so, how
+ // much space we need to allocate for them.
+ bool NeedsRealignment = false;
+ unsigned TotalRealignedSize = 0;
+ auto EC = forEachCodeViewRecord<CVSymbol>(
+ SymsBuffer, [&](CVSymbol Sym) -> llvm::Error {
+ unsigned RealignedSize =
+ alignTo(Sym.length(), alignOf(CodeViewContainer::Pdb));
+ NeedsRealignment |= RealignedSize != Sym.length();
+ TotalRealignedSize += RealignedSize;
+ return Error::success();
+ });
+
+ // If any of the symbol record lengths was corrupt, ignore them all, warn
+ // about it, and move on.
+ if (EC) {
+ warn("corrupt symbol records in " + File->getName());
+ consumeError(std::move(EC));
+ return;
+ }
+
+ // If any symbol needed realignment, allocate enough contiguous memory for
+ // them all. Typically symbol subsections are small enough that this will not
+ // cause fragmentation.
+ MutableArrayRef<uint8_t> AlignedSymbolMem;
+ if (NeedsRealignment) {
+ void *AlignedData =
+ Alloc.Allocate(TotalRealignedSize, alignOf(CodeViewContainer::Pdb));
+ AlignedSymbolMem = makeMutableArrayRef(
+ reinterpret_cast<uint8_t *>(AlignedData), TotalRealignedSize);
+ }
+
+ // Iterate again, this time doing the real work.
+ unsigned CurSymOffset = File->ModuleDBI->getNextSymbolOffset();
+ ArrayRef<uint8_t> BulkSymbols;
+ cantFail(forEachCodeViewRecord<CVSymbol>(
+ SymsBuffer, [&](CVSymbol Sym) -> llvm::Error {
+ // Align the record if required.
+ MutableArrayRef<uint8_t> RecordBytes;
+ if (NeedsRealignment) {
+ RecordBytes = copyAndAlignSymbol(Sym, AlignedSymbolMem);
+ Sym = CVSymbol(Sym.kind(), RecordBytes);
+ } else {
+ // Otherwise, we can actually mutate the symbol directly, since we
+ // copied it to apply relocations.
+ RecordBytes = makeMutableArrayRef(
+ const_cast<uint8_t *>(Sym.data().data()), Sym.length());
+ }
+
+ // Discover type index references in the record. Skip it if we don't
+ // know where they are.
+ SmallVector<TiReference, 32> TypeRefs;
+ if (!discoverTypeIndicesInSymbol(Sym, TypeRefs)) {
+ log("ignoring unknown symbol record with kind 0x" +
+ utohexstr(Sym.kind()));
+ return Error::success();
+ }
+
+ // Re-map all the type index references.
+ remapTypesInSymbolRecord(File, Sym.kind(), RecordBytes, IndexMap,
+ TypeRefs);
+
+ // An object file may have S_xxx_ID symbols, but these get converted to
+ // "real" symbols in a PDB.
+ translateIdSymbols(RecordBytes, getIDTable());
+ Sym = CVSymbol(symbolKind(RecordBytes), RecordBytes);
+
+ // If this record refers to an offset in the object file's string table,
+ // add that item to the global PDB string table and re-write the index.
+ recordStringTableReferences(Sym.kind(), RecordBytes, StringTableRefs);
+
+ // Fill in "Parent" and "End" fields by maintaining a stack of scopes.
+ if (symbolOpensScope(Sym.kind()))
+ scopeStackOpen(Scopes, CurSymOffset, Sym);
+ else if (symbolEndsScope(Sym.kind()))
+ scopeStackClose(Scopes, CurSymOffset, File);
+
+ // Add the symbol to the globals stream if necessary. Do this before
+ // adding the symbol to the module since we may need to get the next
+ // symbol offset, and writing to the module's symbol stream will update
+ // that offset.
+ if (symbolGoesInGlobalsStream(Sym, Scopes.empty()))
+ addGlobalSymbol(Builder.getGsiBuilder(),
+ File->ModuleDBI->getModuleIndex(), CurSymOffset, Sym);
+
+ if (symbolGoesInModuleStream(Sym, Scopes.empty())) {
+ // Add symbols to the module in bulk. If this symbol is contiguous
+ // with the previous run of symbols to add, combine the ranges. If
+ // not, close the previous range of symbols and start a new one.
+ if (Sym.data().data() == BulkSymbols.end()) {
+ BulkSymbols = makeArrayRef(BulkSymbols.data(),
+ BulkSymbols.size() + Sym.length());
+ } else {
+ File->ModuleDBI->addSymbolsInBulk(BulkSymbols);
+ BulkSymbols = RecordBytes;
+ }
+ CurSymOffset += Sym.length();
+ }
+ return Error::success();
+ }));
+
+ // Add any remaining symbols we've accumulated.
+ File->ModuleDBI->addSymbolsInBulk(BulkSymbols);
+}
+
+// Allocate memory for a .debug$S / .debug$F section and relocate it.
+static ArrayRef<uint8_t> relocateDebugChunk(BumpPtrAllocator &Alloc,
+ SectionChunk &DebugChunk) {
+ uint8_t *Buffer = Alloc.Allocate<uint8_t>(DebugChunk.getSize());
+ assert(DebugChunk.OutputSectionOff == 0 &&
+ "debug sections should not be in output sections");
+ DebugChunk.readRelocTargets();
+ DebugChunk.writeTo(Buffer);
+ return makeArrayRef(Buffer, DebugChunk.getSize());
+}
+
+static pdb::SectionContrib createSectionContrib(const Chunk *C, uint32_t Modi) {
+ OutputSection *OS = C->getOutputSection();
+ pdb::SectionContrib SC;
+ memset(&SC, 0, sizeof(SC));
+ SC.ISect = OS->SectionIndex;
+ SC.Off = C->getRVA() - OS->getRVA();
+ SC.Size = C->getSize();
+ if (auto *SecChunk = dyn_cast<SectionChunk>(C)) {
+ SC.Characteristics = SecChunk->Header->Characteristics;
+ SC.Imod = SecChunk->File->ModuleDBI->getModuleIndex();
+ ArrayRef<uint8_t> Contents = SecChunk->getContents();
+ JamCRC CRC(0);
+ ArrayRef<char> CharContents = makeArrayRef(
+ reinterpret_cast<const char *>(Contents.data()), Contents.size());
+ CRC.update(CharContents);
+ SC.DataCrc = CRC.getCRC();
+ } else {
+ SC.Characteristics = OS->Header.Characteristics;
+ // FIXME: When we start creating DBI for import libraries, use those here.
+ SC.Imod = Modi;
+ }
+ SC.RelocCrc = 0; // FIXME
+
+ return SC;
+}
+
+static uint32_t
+translateStringTableIndex(uint32_t ObjIndex,
+ const DebugStringTableSubsectionRef &ObjStrTable,
+ DebugStringTableSubsection &PdbStrTable) {
+ auto ExpectedString = ObjStrTable.getString(ObjIndex);
+ if (!ExpectedString) {
+ warn("Invalid string table reference");
+ consumeError(ExpectedString.takeError());
+ return 0;
+ }
+
+ return PdbStrTable.insert(*ExpectedString);
+}
+
+void DebugSHandler::handleDebugS(lld::coff::SectionChunk &DebugS) {
+ DebugSubsectionArray Subsections;
+
+ ArrayRef<uint8_t> RelocatedDebugContents = consumeDebugMagic(
+ relocateDebugChunk(Linker.Alloc, DebugS), DebugS.getSectionName());
+
+ BinaryStreamReader Reader(RelocatedDebugContents, support::little);
+ ExitOnErr(Reader.readArray(Subsections, RelocatedDebugContents.size()));
+
+ for (const DebugSubsectionRecord &SS : Subsections) {
+ switch (SS.kind()) {
+ case DebugSubsectionKind::StringTable: {
+ assert(!CVStrTab.valid() &&
+ "Encountered multiple string table subsections!");
+ ExitOnErr(CVStrTab.initialize(SS.getRecordData()));
+ break;
+ }
+ case DebugSubsectionKind::FileChecksums:
+ assert(!Checksums.valid() &&
+ "Encountered multiple checksum subsections!");
+ ExitOnErr(Checksums.initialize(SS.getRecordData()));
+ break;
+ case DebugSubsectionKind::Lines:
+ // We can add the relocated line table directly to the PDB without
+ // modification because the file checksum offsets will stay the same.
+ File.ModuleDBI->addDebugSubsection(SS);
+ break;
+ case DebugSubsectionKind::FrameData: {
+ // We need to re-write string table indices here, so save off all
+ // frame data subsections until we've processed the entire list of
+ // subsections so that we can be sure we have the string table.
+ DebugFrameDataSubsectionRef FDS;
+ ExitOnErr(FDS.initialize(SS.getRecordData()));
+ NewFpoFrames.push_back(std::move(FDS));
+ break;
+ }
+ case DebugSubsectionKind::Symbols: {
+ Linker.mergeSymbolRecords(&File, IndexMap, StringTableReferences,
+ SS.getRecordData());
+ break;
+ }
+ default:
+ // FIXME: Process the rest of the subsections.
+ break;
+ }
+ }
+}
+
+void DebugSHandler::finish() {
+ pdb::DbiStreamBuilder &DbiBuilder = Linker.Builder.getDbiBuilder();
+
+ // We should have seen all debug subsections across the entire object file now
+ // which means that if a StringTable subsection and Checksums subsection were
+ // present, now is the time to handle them.
+ if (!CVStrTab.valid()) {
+ if (Checksums.valid())
+ fatal(".debug$S sections with a checksums subsection must also contain a "
+ "string table subsection");
+
+ if (!StringTableReferences.empty())
+ warn("No StringTable subsection was encountered, but there are string "
+ "table references");
+ return;
+ }
+
+ // Rewrite string table indices in the Fpo Data and symbol records to refer to
+ // the global PDB string table instead of the object file string table.
+ for (DebugFrameDataSubsectionRef &FDS : NewFpoFrames) {
+ const ulittle32_t *Reloc = FDS.getRelocPtr();
+ for (codeview::FrameData FD : FDS) {
+ FD.RvaStart += *Reloc;
+ FD.FrameFunc =
+ translateStringTableIndex(FD.FrameFunc, CVStrTab, Linker.PDBStrTab);
+ DbiBuilder.addNewFpoData(FD);
+ }
+ }
+
+ for (ulittle32_t *Ref : StringTableReferences)
+ *Ref = translateStringTableIndex(*Ref, CVStrTab, Linker.PDBStrTab);
+
+ // Make a new file checksum table that refers to offsets in the PDB-wide
+ // string table. Generally the string table subsection appears after the
+ // checksum table, so we have to do this after looping over all the
+ // subsections.
+ auto NewChecksums = make_unique<DebugChecksumsSubsection>(Linker.PDBStrTab);
+ for (FileChecksumEntry &FC : Checksums) {
+ SmallString<128> FileName =
+ ExitOnErr(CVStrTab.getString(FC.FileNameOffset));
+ pdbMakeAbsolute(FileName);
+ ExitOnErr(Linker.Builder.getDbiBuilder().addModuleSourceFile(
+ *File.ModuleDBI, FileName));
+ NewChecksums->addChecksum(FileName, FC.Kind, FC.Checksum);
+ }
+ File.ModuleDBI->addDebugSubsection(std::move(NewChecksums));
+}
+
+void PDBLinker::addObjFile(ObjFile *File, CVIndexMap *ExternIndexMap) {
+ if (File->wasProcessedForPDB())
+ return;
+ // Add a module descriptor for every object file. We need to put an absolute
+ // path to the object into the PDB. If this is a plain object, we make its
+ // path absolute. If it's an object in an archive, we make the archive path
+ // absolute.
+ bool InArchive = !File->ParentName.empty();
+ SmallString<128> Path = InArchive ? File->ParentName : File->getName();
+ pdbMakeAbsolute(Path);
+ StringRef Name = InArchive ? File->getName() : StringRef(Path);
+
+ pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder();
+ File->ModuleDBI = &ExitOnErr(DbiBuilder.addModuleInfo(Name));
+ File->ModuleDBI->setObjFileName(Path);
+
+ auto Chunks = File->getChunks();
+ uint32_t Modi = File->ModuleDBI->getModuleIndex();
+ for (Chunk *C : Chunks) {
+ auto *SecChunk = dyn_cast<SectionChunk>(C);
+ if (!SecChunk || !SecChunk->Live)
+ continue;
+ pdb::SectionContrib SC = createSectionContrib(SecChunk, Modi);
+ File->ModuleDBI->setFirstSectionContrib(SC);
+ break;
+ }
+
+ // Before we can process symbol substreams from .debug$S, we need to process
+ // type information, file checksums, and the string table. Add type info to
+ // the PDB first, so that we can get the map from object file type and item
+ // indices to PDB type and item indices.
+ CVIndexMap ObjectIndexMap;
+ auto IndexMapResult =
+ mergeDebugT(File, ExternIndexMap ? ExternIndexMap : &ObjectIndexMap);
+
+ // If the .debug$T sections fail to merge, assume there is no debug info.
+ if (!IndexMapResult) {
+ if (!Config->WarnDebugInfoUnusable) {
+ consumeError(IndexMapResult.takeError());
+ return;
+ }
+ StringRef FileName = sys::path::filename(Path);
+ warn("Cannot use debug info for '" + FileName + "' [LNK4099]\n" +
+ ">>> failed to load reference " +
+ StringRef(toString(IndexMapResult.takeError())));
+ return;
+ }
+
+ ScopedTimer T(SymbolMergingTimer);
+
+ DebugSHandler DSH(*this, *File, *IndexMapResult);
+ // Now do all live .debug$S and .debug$F sections.
+ for (SectionChunk *DebugChunk : File->getDebugChunks()) {
+ if (!DebugChunk->Live || DebugChunk->getSize() == 0)
+ continue;
+
+ if (DebugChunk->getSectionName() == ".debug$S") {
+ DSH.handleDebugS(*DebugChunk);
+ continue;
+ }
+
+ if (DebugChunk->getSectionName() == ".debug$F") {
+ ArrayRef<uint8_t> RelocatedDebugContents =
+ relocateDebugChunk(Alloc, *DebugChunk);
+
+ FixedStreamArray<object::FpoData> FpoRecords;
+ BinaryStreamReader Reader(RelocatedDebugContents, support::little);
+ uint32_t Count = RelocatedDebugContents.size() / sizeof(object::FpoData);
+ ExitOnErr(Reader.readArray(FpoRecords, Count));
+
+ // These are already relocated and don't refer to the string table, so we
+ // can just copy it.
+ for (const object::FpoData &FD : FpoRecords)
+ DbiBuilder.addOldFpoData(FD);
+ continue;
+ }
+ }
+
+ // Do any post-processing now that all .debug$S sections have been processed.
+ DSH.finish();
+}
+
+static PublicSym32 createPublic(Defined *Def) {
+ PublicSym32 Pub(SymbolKind::S_PUB32);
+ Pub.Name = Def->getName();
+ if (auto *D = dyn_cast<DefinedCOFF>(Def)) {
+ if (D->getCOFFSymbol().isFunctionDefinition())
+ Pub.Flags = PublicSymFlags::Function;
+ } else if (isa<DefinedImportThunk>(Def)) {
+ Pub.Flags = PublicSymFlags::Function;
+ }
+
+ OutputSection *OS = Def->getChunk()->getOutputSection();
+ assert(OS && "all publics should be in final image");
+ Pub.Offset = Def->getRVA() - OS->getRVA();
+ Pub.Segment = OS->SectionIndex;
+ return Pub;
+}
+
+// Add all object files to the PDB. Merge .debug$T sections into IpiData and
+// TpiData.
+void PDBLinker::addObjectsToPDB() {
+ ScopedTimer T1(AddObjectsTimer);
+ for (ObjFile *File : ObjFile::Instances)
+ addObjFile(File);
+
+ Builder.getStringTableBuilder().setStrings(PDBStrTab);
+ T1.stop();
+
+ // Construct TPI and IPI stream contents.
+ ScopedTimer T2(TpiStreamLayoutTimer);
+ addTypeInfo(Builder.getTpiBuilder(), getTypeTable());
+ addTypeInfo(Builder.getIpiBuilder(), getIDTable());
+ T2.stop();
+
+ ScopedTimer T3(GlobalsLayoutTimer);
+ // Compute the public and global symbols.
+ auto &GsiBuilder = Builder.getGsiBuilder();
+ std::vector<PublicSym32> Publics;
+ Symtab->forEachSymbol([&Publics](Symbol *S) {
+ // Only emit defined, live symbols that have a chunk.
+ auto *Def = dyn_cast<Defined>(S);
+ if (Def && Def->isLive() && Def->getChunk())
+ Publics.push_back(createPublic(Def));
+ });
+
+ if (!Publics.empty()) {
+ // Sort the public symbols and add them to the stream.
+ sort(parallel::par, Publics.begin(), Publics.end(),
+ [](const PublicSym32 &L, const PublicSym32 &R) {
+ return L.Name < R.Name;
+ });
+ for (const PublicSym32 &Pub : Publics)
+ GsiBuilder.addPublicSymbol(Pub);
+ }
+}
+
+void PDBLinker::addNatvisFiles() {
+ for (StringRef File : Config->NatvisFiles) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> DataOrErr =
+ MemoryBuffer::getFile(File);
+ if (!DataOrErr) {
+ warn("Cannot open input file: " + File);
+ continue;
+ }
+ Builder.addInjectedSource(File, std::move(*DataOrErr));
+ }
+}
+
+static codeview::CPUType toCodeViewMachine(COFF::MachineTypes Machine) {
+ switch (Machine) {
+ case COFF::IMAGE_FILE_MACHINE_AMD64:
+ return codeview::CPUType::X64;
+ case COFF::IMAGE_FILE_MACHINE_ARM:
+ return codeview::CPUType::ARM7;
+ case COFF::IMAGE_FILE_MACHINE_ARM64:
+ return codeview::CPUType::ARM64;
+ case COFF::IMAGE_FILE_MACHINE_ARMNT:
+ return codeview::CPUType::ARMNT;
+ case COFF::IMAGE_FILE_MACHINE_I386:
+ return codeview::CPUType::Intel80386;
+ default:
+ llvm_unreachable("Unsupported CPU Type");
+ }
+}
+
+// Mimic MSVC which surrounds arguments containing whitespace with quotes.
+// Double double-quotes are handled, so that the resulting string can be
+// executed again on the cmd-line.
+static std::string quote(ArrayRef<StringRef> Args) {
+ std::string R;
+ R.reserve(256);
+ for (StringRef A : Args) {
+ if (!R.empty())
+ R.push_back(' ');
+ bool HasWS = A.find(' ') != StringRef::npos;
+ bool HasQ = A.find('"') != StringRef::npos;
+ if (HasWS || HasQ)
+ R.push_back('"');
+ if (HasQ) {
+ SmallVector<StringRef, 4> S;
+ A.split(S, '"');
+ R.append(join(S, "\"\""));
+ } else {
+ R.append(A);
+ }
+ if (HasWS || HasQ)
+ R.push_back('"');
+ }
+ return R;
+}
+
+static void addCommonLinkerModuleSymbols(StringRef Path,
+ pdb::DbiModuleDescriptorBuilder &Mod,
+ BumpPtrAllocator &Allocator) {
+ ObjNameSym ONS(SymbolRecordKind::ObjNameSym);
+ Compile3Sym CS(SymbolRecordKind::Compile3Sym);
+ EnvBlockSym EBS(SymbolRecordKind::EnvBlockSym);
+
+ ONS.Name = "* Linker *";
+ ONS.Signature = 0;
+
+ CS.Machine = toCodeViewMachine(Config->Machine);
+ // Interestingly, if we set the string to 0.0.0.0, then when trying to view
+ // local variables WinDbg emits an error that private symbols are not present.
+ // By setting this to a valid MSVC linker version string, local variables are
+ // displayed properly. As such, even though it is not representative of
+ // LLVM's version information, we need this for compatibility.
+ CS.Flags = CompileSym3Flags::None;
+ CS.VersionBackendBuild = 25019;
+ CS.VersionBackendMajor = 14;
+ CS.VersionBackendMinor = 10;
+ CS.VersionBackendQFE = 0;
+
+ // MSVC also sets the frontend to 0.0.0.0 since this is specifically for the
+ // linker module (which is by definition a backend), so we don't need to do
+ // anything here. Also, it seems we can use "LLVM Linker" for the linker name
+ // without any problems. Only the backend version has to be hardcoded to a
+ // magic number.
+ CS.VersionFrontendBuild = 0;
+ CS.VersionFrontendMajor = 0;
+ CS.VersionFrontendMinor = 0;
+ CS.VersionFrontendQFE = 0;
+ CS.Version = "LLVM Linker";
+ CS.setLanguage(SourceLanguage::Link);
+
+ ArrayRef<StringRef> Args = makeArrayRef(Config->Argv).drop_front();
+ std::string ArgStr = quote(Args);
+ EBS.Fields.push_back("cwd");
+ SmallString<64> cwd;
+ if (Config->PDBSourcePath.empty())
+ sys::fs::current_path(cwd);
+ else
+ cwd = Config->PDBSourcePath;
+ EBS.Fields.push_back(cwd);
+ EBS.Fields.push_back("exe");
+ SmallString<64> exe = Config->Argv[0];
+ pdbMakeAbsolute(exe);
+ EBS.Fields.push_back(exe);
+ EBS.Fields.push_back("pdb");
+ EBS.Fields.push_back(Path);
+ EBS.Fields.push_back("cmd");
+ EBS.Fields.push_back(ArgStr);
+ Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol(
+ ONS, Allocator, CodeViewContainer::Pdb));
+ Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol(
+ CS, Allocator, CodeViewContainer::Pdb));
+ Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol(
+ EBS, Allocator, CodeViewContainer::Pdb));
+}
+
+static void addLinkerModuleSectionSymbol(pdb::DbiModuleDescriptorBuilder &Mod,
+ OutputSection &OS,
+ BumpPtrAllocator &Allocator) {
+ SectionSym Sym(SymbolRecordKind::SectionSym);
+ Sym.Alignment = 12; // 2^12 = 4KB
+ Sym.Characteristics = OS.Header.Characteristics;
+ Sym.Length = OS.getVirtualSize();
+ Sym.Name = OS.Name;
+ Sym.Rva = OS.getRVA();
+ Sym.SectionNumber = OS.SectionIndex;
+ Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol(
+ Sym, Allocator, CodeViewContainer::Pdb));
+}
+
+// Creates a PDB file.
+void coff::createPDB(SymbolTable *Symtab,
+ ArrayRef<OutputSection *> OutputSections,
+ ArrayRef<uint8_t> SectionTable,
+ llvm::codeview::DebugInfo *BuildId) {
+ ScopedTimer T1(TotalPdbLinkTimer);
+ PDBLinker PDB(Symtab);
+
+ PDB.initialize(BuildId);
+ PDB.addObjectsToPDB();
+ PDB.addSections(OutputSections, SectionTable);
+ PDB.addNatvisFiles();
+
+ ScopedTimer T2(DiskCommitTimer);
+ codeview::GUID Guid;
+ PDB.commit(&Guid);
+ memcpy(&BuildId->PDB70.Signature, &Guid, 16);
+}
+
+void PDBLinker::initialize(llvm::codeview::DebugInfo *BuildId) {
+ ExitOnErr(Builder.initialize(4096)); // 4096 is blocksize
+
+ BuildId->Signature.CVSignature = OMF::Signature::PDB70;
+ // Signature is set to a hash of the PDB contents when the PDB is done.
+ memset(BuildId->PDB70.Signature, 0, 16);
+ BuildId->PDB70.Age = 1;
+
+ // Create streams in MSF for predefined streams, namely
+ // PDB, TPI, DBI and IPI.
+ for (int I = 0; I < (int)pdb::kSpecialStreamCount; ++I)
+ ExitOnErr(Builder.getMsfBuilder().addStream(0));
+
+ // Add an Info stream.
+ auto &InfoBuilder = Builder.getInfoBuilder();
+ InfoBuilder.setVersion(pdb::PdbRaw_ImplVer::PdbImplVC70);
+ InfoBuilder.setHashPDBContentsToGUID(true);
+
+ // Add an empty DBI stream.
+ pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder();
+ DbiBuilder.setAge(BuildId->PDB70.Age);
+ DbiBuilder.setVersionHeader(pdb::PdbDbiV70);
+ DbiBuilder.setMachineType(Config->Machine);
+ // Technically we are not link.exe 14.11, but there are known cases where
+ // debugging tools on Windows expect Microsoft-specific version numbers or
+ // they fail to work at all. Since we know we produce PDBs that are
+ // compatible with LINK 14.11, we set that version number here.
+ DbiBuilder.setBuildNumber(14, 11);
+}
+
+void PDBLinker::addSections(ArrayRef<OutputSection *> OutputSections,
+ ArrayRef<uint8_t> SectionTable) {
+ // It's not entirely clear what this is, but the * Linker * module uses it.
+ pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder();
+ NativePath = Config->PDBPath;
+ pdbMakeAbsolute(NativePath);
+ uint32_t PdbFilePathNI = DbiBuilder.addECName(NativePath);
+ auto &LinkerModule = ExitOnErr(DbiBuilder.addModuleInfo("* Linker *"));
+ LinkerModule.setPdbFilePathNI(PdbFilePathNI);
+ addCommonLinkerModuleSymbols(NativePath, LinkerModule, Alloc);
+
+ // Add section contributions. They must be ordered by ascending RVA.
+ for (OutputSection *OS : OutputSections) {
+ addLinkerModuleSectionSymbol(LinkerModule, *OS, Alloc);
+ for (Chunk *C : OS->Chunks) {
+ pdb::SectionContrib SC =
+ createSectionContrib(C, LinkerModule.getModuleIndex());
+ Builder.getDbiBuilder().addSectionContrib(SC);
+ }
+ }
+
+ // Add Section Map stream.
+ ArrayRef<object::coff_section> Sections = {
+ (const object::coff_section *)SectionTable.data(),
+ SectionTable.size() / sizeof(object::coff_section)};
+ SectionMap = pdb::DbiStreamBuilder::createSectionMap(Sections);
+ DbiBuilder.setSectionMap(SectionMap);
+
+ // Add COFF section header stream.
+ ExitOnErr(
+ DbiBuilder.addDbgStream(pdb::DbgHeaderType::SectionHdr, SectionTable));
+}
+
+void PDBLinker::commit(codeview::GUID *Guid) {
+ // Write to a file.
+ ExitOnErr(Builder.commit(Config->PDBPath, Guid));
+}
+
+static Expected<StringRef>
+getFileName(const DebugStringTableSubsectionRef &Strings,
+ const DebugChecksumsSubsectionRef &Checksums, uint32_t FileID) {
+ auto Iter = Checksums.getArray().at(FileID);
+ if (Iter == Checksums.getArray().end())
+ return make_error<CodeViewError>(cv_error_code::no_records);
+ uint32_t Offset = Iter->FileNameOffset;
+ return Strings.getString(Offset);
+}
+
+static uint32_t getSecrelReloc() {
+ switch (Config->Machine) {
+ case AMD64:
+ return COFF::IMAGE_REL_AMD64_SECREL;
+ case I386:
+ return COFF::IMAGE_REL_I386_SECREL;
+ case ARMNT:
+ return COFF::IMAGE_REL_ARM_SECREL;
+ case ARM64:
+ return COFF::IMAGE_REL_ARM64_SECREL;
+ default:
+ llvm_unreachable("unknown machine type");
+ }
+}
+
+// Try to find a line table for the given offset Addr into the given chunk C.
+// If a line table was found, the line table, the string and checksum tables
+// that are used to interpret the line table, and the offset of Addr in the line
+// table are stored in the output arguments. Returns whether a line table was
+// found.
+static bool findLineTable(const SectionChunk *C, uint32_t Addr,
+ DebugStringTableSubsectionRef &CVStrTab,
+ DebugChecksumsSubsectionRef &Checksums,
+ DebugLinesSubsectionRef &Lines,
+ uint32_t &OffsetInLinetable) {
+ ExitOnError ExitOnErr;
+ uint32_t SecrelReloc = getSecrelReloc();
+
+ for (SectionChunk *DbgC : C->File->getDebugChunks()) {
+ if (DbgC->getSectionName() != ".debug$S")
+ continue;
+
+ // Build a mapping of SECREL relocations in DbgC that refer to C.
+ DenseMap<uint32_t, uint32_t> Secrels;
+ for (const coff_relocation &R : DbgC->Relocs) {
+ if (R.Type != SecrelReloc)
+ continue;
+
+ if (auto *S = dyn_cast_or_null<DefinedRegular>(
+ C->File->getSymbols()[R.SymbolTableIndex]))
+ if (S->getChunk() == C)
+ Secrels[R.VirtualAddress] = S->getValue();
+ }
+
+ ArrayRef<uint8_t> Contents =
+ consumeDebugMagic(DbgC->getContents(), ".debug$S");
+ DebugSubsectionArray Subsections;
+ BinaryStreamReader Reader(Contents, support::little);
+ ExitOnErr(Reader.readArray(Subsections, Contents.size()));
+
+ for (const DebugSubsectionRecord &SS : Subsections) {
+ switch (SS.kind()) {
+ case DebugSubsectionKind::StringTable: {
+ assert(!CVStrTab.valid() &&
+ "Encountered multiple string table subsections!");
+ ExitOnErr(CVStrTab.initialize(SS.getRecordData()));
+ break;
+ }
+ case DebugSubsectionKind::FileChecksums:
+ assert(!Checksums.valid() &&
+ "Encountered multiple checksum subsections!");
+ ExitOnErr(Checksums.initialize(SS.getRecordData()));
+ break;
+ case DebugSubsectionKind::Lines: {
+ ArrayRef<uint8_t> Bytes;
+ auto Ref = SS.getRecordData();
+ ExitOnErr(Ref.readLongestContiguousChunk(0, Bytes));
+ size_t OffsetInDbgC = Bytes.data() - DbgC->getContents().data();
+
+ // Check whether this line table refers to C.
+ auto I = Secrels.find(OffsetInDbgC);
+ if (I == Secrels.end())
+ break;
+
+ // Check whether this line table covers Addr in C.
+ DebugLinesSubsectionRef LinesTmp;
+ ExitOnErr(LinesTmp.initialize(BinaryStreamReader(Ref)));
+ uint32_t OffsetInC = I->second + LinesTmp.header()->RelocOffset;
+ if (Addr < OffsetInC || Addr >= OffsetInC + LinesTmp.header()->CodeSize)
+ break;
+
+ assert(!Lines.header() &&
+ "Encountered multiple line tables for function!");
+ ExitOnErr(Lines.initialize(BinaryStreamReader(Ref)));
+ OffsetInLinetable = Addr - OffsetInC;
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (CVStrTab.valid() && Checksums.valid() && Lines.header())
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Use CodeView line tables to resolve a file and line number for the given
+// offset into the given chunk and return them, or {"", 0} if a line table was
+// not found.
+std::pair<StringRef, uint32_t> coff::getFileLine(const SectionChunk *C,
+ uint32_t Addr) {
+ ExitOnError ExitOnErr;
+
+ DebugStringTableSubsectionRef CVStrTab;
+ DebugChecksumsSubsectionRef Checksums;
+ DebugLinesSubsectionRef Lines;
+ uint32_t OffsetInLinetable;
+
+ if (!findLineTable(C, Addr, CVStrTab, Checksums, Lines, OffsetInLinetable))
+ return {"", 0};
+
+ Optional<uint32_t> NameIndex;
+ Optional<uint32_t> LineNumber;
+ for (LineColumnEntry &Entry : Lines) {
+ for (const LineNumberEntry &LN : Entry.LineNumbers) {
+ LineInfo LI(LN.Flags);
+ if (LN.Offset > OffsetInLinetable) {
+ if (!NameIndex) {
+ NameIndex = Entry.NameIndex;
+ LineNumber = LI.getStartLine();
+ }
+ StringRef Filename =
+ ExitOnErr(getFileName(CVStrTab, Checksums, *NameIndex));
+ return {Filename, *LineNumber};
+ }
+ NameIndex = Entry.NameIndex;
+ LineNumber = LI.getStartLine();
+ }
+ }
+ if (!NameIndex)
+ return {"", 0};
+ StringRef Filename = ExitOnErr(getFileName(CVStrTab, Checksums, *NameIndex));
+ return {Filename, *LineNumber};
+}
diff --git a/contrib/llvm/tools/lld/COFF/PDB.h b/contrib/llvm/tools/lld/COFF/PDB.h
new file mode 100644
index 000000000000..ea7a9996f415
--- /dev/null
+++ b/contrib/llvm/tools/lld/COFF/PDB.h
@@ -0,0 +1,38 @@
+//===- PDB.h ----------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_PDB_H
+#define LLD_COFF_PDB_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace llvm {
+namespace codeview {
+union DebugInfo;
+}
+}
+
+namespace lld {
+namespace coff {
+class OutputSection;
+class SectionChunk;
+class SymbolTable;
+
+void createPDB(SymbolTable *Symtab,
+ llvm::ArrayRef<OutputSection *> OutputSections,
+ llvm::ArrayRef<uint8_t> SectionTable,
+ llvm::codeview::DebugInfo *BuildId);
+
+std::pair<llvm::StringRef, uint32_t> getFileLine(const SectionChunk *C,
+ uint32_t Addr);
+}
+}
+
+#endif
diff --git a/contrib/llvm/tools/lld/COFF/README.md b/contrib/llvm/tools/lld/COFF/README.md
new file mode 100644
index 000000000000..f1bfc9c15263
--- /dev/null
+++ b/contrib/llvm/tools/lld/COFF/README.md
@@ -0,0 +1 @@
+See docs/NewLLD.rst
diff --git a/contrib/llvm/tools/lld/COFF/SymbolTable.cpp b/contrib/llvm/tools/lld/COFF/SymbolTable.cpp
new file mode 100644
index 000000000000..1a9e0455dc1d
--- /dev/null
+++ b/contrib/llvm/tools/lld/COFF/SymbolTable.cpp
@@ -0,0 +1,548 @@
+//===- SymbolTable.cpp ----------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolTable.h"
+#include "Config.h"
+#include "Driver.h"
+#include "LTO.h"
+#include "PDB.h"
+#include "Symbols.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Memory.h"
+#include "lld/Common/Timer.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+#include <utility>
+
+using namespace llvm;
+
+namespace lld {
+namespace coff {
+
+static Timer LTOTimer("LTO", Timer::root());
+
+SymbolTable *Symtab;
+
+void SymbolTable::addFile(InputFile *File) {
+ log("Reading " + toString(File));
+ File->parse();
+
+ MachineTypes MT = File->getMachineType();
+ if (Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN) {
+ Config->Machine = MT;
+ } else if (MT != IMAGE_FILE_MACHINE_UNKNOWN && Config->Machine != MT) {
+ error(toString(File) + ": machine type " + machineToStr(MT) +
+ " conflicts with " + machineToStr(Config->Machine));
+ return;
+ }
+
+ if (auto *F = dyn_cast<ObjFile>(File)) {
+ ObjFile::Instances.push_back(F);
+ } else if (auto *F = dyn_cast<BitcodeFile>(File)) {
+ BitcodeFile::Instances.push_back(F);
+ } else if (auto *F = dyn_cast<ImportFile>(File)) {
+ ImportFile::Instances.push_back(F);
+ }
+
+ StringRef S = File->getDirectives();
+ if (S.empty())
+ return;
+
+ log("Directives: " + toString(File) + ": " + S);
+ Driver->parseDirectives(S);
+}
+
+static void errorOrWarn(const Twine &S) {
+ if (Config->ForceUnresolved)
+ warn(S);
+ else
+ error(S);
+}
+
+// Returns the symbol in SC whose value is <= Addr that is closest to Addr.
+// This is generally the global variable or function whose definition contains
+// Addr.
+static Symbol *getSymbol(SectionChunk *SC, uint32_t Addr) {
+ DefinedRegular *Candidate = nullptr;
+
+ for (Symbol *S : SC->File->getSymbols()) {
+ auto *D = dyn_cast_or_null<DefinedRegular>(S);
+ if (!D || D->getChunk() != SC || D->getValue() > Addr ||
+ (Candidate && D->getValue() < Candidate->getValue()))
+ continue;
+
+ Candidate = D;
+ }
+
+ return Candidate;
+}
+
+std::string getSymbolLocations(ObjFile *File, uint32_t SymIndex) {
+ struct Location {
+ Symbol *Sym;
+ std::pair<StringRef, uint32_t> FileLine;
+ };
+ std::vector<Location> Locations;
+
+ for (Chunk *C : File->getChunks()) {
+ auto *SC = dyn_cast<SectionChunk>(C);
+ if (!SC)
+ continue;
+ for (const coff_relocation &R : SC->Relocs) {
+ if (R.SymbolTableIndex != SymIndex)
+ continue;
+ std::pair<StringRef, uint32_t> FileLine =
+ getFileLine(SC, R.VirtualAddress);
+ Symbol *Sym = getSymbol(SC, R.VirtualAddress);
+ if (!FileLine.first.empty() || Sym)
+ Locations.push_back({Sym, FileLine});
+ }
+ }
+
+ if (Locations.empty())
+ return "\n>>> referenced by " + toString(File);
+
+ std::string Out;
+ llvm::raw_string_ostream OS(Out);
+ for (Location Loc : Locations) {
+ OS << "\n>>> referenced by ";
+ if (!Loc.FileLine.first.empty())
+ OS << Loc.FileLine.first << ":" << Loc.FileLine.second
+ << "\n>>> ";
+ OS << toString(File);
+ if (Loc.Sym)
+ OS << ":(" << toString(*Loc.Sym) << ')';
+ }
+ return OS.str();
+}
+
+void SymbolTable::loadMinGWAutomaticImports() {
+ for (auto &I : SymMap) {
+ Symbol *Sym = I.second;
+ auto *Undef = dyn_cast<Undefined>(Sym);
+ if (!Undef)
+ continue;
+ if (!Sym->IsUsedInRegularObj)
+ continue;
+
+ StringRef Name = Undef->getName();
+
+ if (Name.startswith("__imp_"))
+ continue;
+ // If we have an undefined symbol, but we have a Lazy representing a
+ // symbol we could load from file, make sure to load that.
+ Lazy *L = dyn_cast_or_null<Lazy>(find(("__imp_" + Name).str()));
+ if (!L || L->PendingArchiveLoad)
+ continue;
+
+ log("Loading lazy " + L->getName() + " from " + L->File->getName() +
+ " for automatic import");
+ L->PendingArchiveLoad = true;
+ L->File->addMember(&L->Sym);
+ }
+}
+
+bool SymbolTable::handleMinGWAutomaticImport(Symbol *Sym, StringRef Name) {
+ if (Name.startswith("__imp_"))
+ return false;
+ Defined *Imp = dyn_cast_or_null<Defined>(find(("__imp_" + Name).str()));
+ if (!Imp)
+ return false;
+
+ // Replace the reference directly to a variable with a reference
+ // to the import address table instead. This obviously isn't right,
+ // but we mark the symbol as IsRuntimePseudoReloc, and a later pass
+ // will add runtime pseudo relocations for every relocation against
+ // this Symbol. The runtime pseudo relocation framework expects the
+ // reference itself to point at the IAT entry.
+ size_t ImpSize = 0;
+ if (isa<DefinedImportData>(Imp)) {
+ log("Automatically importing " + Name + " from " +
+ cast<DefinedImportData>(Imp)->getDLLName());
+ ImpSize = sizeof(DefinedImportData);
+ } else if (isa<DefinedRegular>(Imp)) {
+ log("Automatically importing " + Name + " from " +
+ toString(cast<DefinedRegular>(Imp)->File));
+ ImpSize = sizeof(DefinedRegular);
+ } else {
+ warn("unable to automatically import " + Name + " from " + Imp->getName() +
+ " from " + toString(cast<DefinedRegular>(Imp)->File) +
+ "; unexpected symbol type");
+ return false;
+ }
+ Sym->replaceKeepingName(Imp, ImpSize);
+ Sym->IsRuntimePseudoReloc = true;
+
+ // There may exist symbols named .refptr.<name> which only consist
+ // of a single pointer to <name>. If it turns out <name> is
+ // automatically imported, we don't need to keep the .refptr.<name>
+ // pointer at all, but redirect all accesses to it to the IAT entry
+ // for __imp_<name> instead, and drop the whole .refptr.<name> chunk.
+ DefinedRegular *Refptr =
+ dyn_cast_or_null<DefinedRegular>(find((".refptr." + Name).str()));
+ if (Refptr && Refptr->getChunk()->getSize() == Config->Wordsize) {
+ SectionChunk *SC = dyn_cast_or_null<SectionChunk>(Refptr->getChunk());
+ if (SC && SC->Relocs.size() == 1 && *SC->symbols().begin() == Sym) {
+ log("Replacing .refptr." + Name + " with " + Imp->getName());
+ Refptr->getChunk()->Live = false;
+ Refptr->replaceKeepingName(Imp, ImpSize);
+ }
+ }
+ return true;
+}
+
+void SymbolTable::reportRemainingUndefines() {
+ SmallPtrSet<Symbol *, 8> Undefs;
+ DenseMap<Symbol *, Symbol *> LocalImports;
+
+ for (auto &I : SymMap) {
+ Symbol *Sym = I.second;
+ auto *Undef = dyn_cast<Undefined>(Sym);
+ if (!Undef)
+ continue;
+ if (!Sym->IsUsedInRegularObj)
+ continue;
+
+ StringRef Name = Undef->getName();
+
+ // A weak alias may have been resolved, so check for that.
+ if (Defined *D = Undef->getWeakAlias()) {
+ // We want to replace Sym with D. However, we can't just blindly
+ // copy sizeof(SymbolUnion) bytes from D to Sym because D may be an
+ // internal symbol, and internal symbols are stored as "unparented"
+ // Symbols. For that reason we need to check which type of symbol we
+ // are dealing with and copy the correct number of bytes.
+ if (isa<DefinedRegular>(D))
+ memcpy(Sym, D, sizeof(DefinedRegular));
+ else if (isa<DefinedAbsolute>(D))
+ memcpy(Sym, D, sizeof(DefinedAbsolute));
+ else
+ memcpy(Sym, D, sizeof(SymbolUnion));
+ continue;
+ }
+
+ // If we can resolve a symbol by removing __imp_ prefix, do that.
+ // This odd rule is for compatibility with MSVC linker.
+ if (Name.startswith("__imp_")) {
+ Symbol *Imp = find(Name.substr(strlen("__imp_")));
+ if (Imp && isa<Defined>(Imp)) {
+ auto *D = cast<Defined>(Imp);
+ replaceSymbol<DefinedLocalImport>(Sym, Name, D);
+ LocalImportChunks.push_back(cast<DefinedLocalImport>(Sym)->getChunk());
+ LocalImports[Sym] = D;
+ continue;
+ }
+ }
+
+ // We don't want to report missing Microsoft precompiled headers symbols.
+ // A proper message will be emitted instead in PDBLinker::aquirePrecompObj
+ if (Name.contains("_PchSym_"))
+ continue;
+
+ if (Config->MinGW && handleMinGWAutomaticImport(Sym, Name))
+ continue;
+
+ // Remaining undefined symbols are not fatal if /force is specified.
+ // They are replaced with dummy defined symbols.
+ if (Config->ForceUnresolved)
+ replaceSymbol<DefinedAbsolute>(Sym, Name, 0);
+ Undefs.insert(Sym);
+ }
+
+ if (Undefs.empty() && LocalImports.empty())
+ return;
+
+ for (Symbol *B : Config->GCRoot) {
+ if (Undefs.count(B))
+ errorOrWarn("<root>: undefined symbol: " + toString(*B));
+ if (Config->WarnLocallyDefinedImported)
+ if (Symbol *Imp = LocalImports.lookup(B))
+ warn("<root>: locally defined symbol imported: " + toString(*Imp) +
+ " (defined in " + toString(Imp->getFile()) + ") [LNK4217]");
+ }
+
+ for (ObjFile *File : ObjFile::Instances) {
+ size_t SymIndex = (size_t)-1;
+ for (Symbol *Sym : File->getSymbols()) {
+ ++SymIndex;
+ if (!Sym)
+ continue;
+ if (Undefs.count(Sym))
+ errorOrWarn("undefined symbol: " + toString(*Sym) +
+ getSymbolLocations(File, SymIndex));
+ if (Config->WarnLocallyDefinedImported)
+ if (Symbol *Imp = LocalImports.lookup(Sym))
+ warn(toString(File) +
+ ": locally defined symbol imported: " + toString(*Imp) +
+ " (defined in " + toString(Imp->getFile()) + ") [LNK4217]");
+ }
+ }
+}
+
+std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) {
+ bool Inserted = false;
+ Symbol *&Sym = SymMap[CachedHashStringRef(Name)];
+ if (!Sym) {
+ Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
+ Sym->IsUsedInRegularObj = false;
+ Sym->PendingArchiveLoad = false;
+ Inserted = true;
+ }
+ return {Sym, Inserted};
+}
+
+std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name, InputFile *File) {
+ std::pair<Symbol *, bool> Result = insert(Name);
+ if (!File || !isa<BitcodeFile>(File))
+ Result.first->IsUsedInRegularObj = true;
+ return Result;
+}
+
+Symbol *SymbolTable::addUndefined(StringRef Name, InputFile *F,
+ bool IsWeakAlias) {
+ Symbol *S;
+ bool WasInserted;
+ std::tie(S, WasInserted) = insert(Name, F);
+ if (WasInserted || (isa<Lazy>(S) && IsWeakAlias)) {
+ replaceSymbol<Undefined>(S, Name);
+ return S;
+ }
+ if (auto *L = dyn_cast<Lazy>(S)) {
+ if (!S->PendingArchiveLoad) {
+ S->PendingArchiveLoad = true;
+ L->File->addMember(&L->Sym);
+ }
+ }
+ return S;
+}
+
+void SymbolTable::addLazy(ArchiveFile *F, const Archive::Symbol Sym) {
+ StringRef Name = Sym.getName();
+ Symbol *S;
+ bool WasInserted;
+ std::tie(S, WasInserted) = insert(Name);
+ if (WasInserted) {
+ replaceSymbol<Lazy>(S, F, Sym);
+ return;
+ }
+ auto *U = dyn_cast<Undefined>(S);
+ if (!U || U->WeakAlias || S->PendingArchiveLoad)
+ return;
+ S->PendingArchiveLoad = true;
+ F->addMember(&Sym);
+}
+
+void SymbolTable::reportDuplicate(Symbol *Existing, InputFile *NewFile) {
+ std::string Msg = "duplicate symbol: " + toString(*Existing) + " in " +
+ toString(Existing->getFile()) + " and in " +
+ toString(NewFile);
+
+ if (Config->ForceMultiple)
+ warn(Msg);
+ else
+ error(Msg);
+}
+
+Symbol *SymbolTable::addAbsolute(StringRef N, COFFSymbolRef Sym) {
+ Symbol *S;
+ bool WasInserted;
+ std::tie(S, WasInserted) = insert(N, nullptr);
+ S->IsUsedInRegularObj = true;
+ if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S))
+ replaceSymbol<DefinedAbsolute>(S, N, Sym);
+ else if (!isa<DefinedCOFF>(S))
+ reportDuplicate(S, nullptr);
+ return S;
+}
+
+Symbol *SymbolTable::addAbsolute(StringRef N, uint64_t VA) {
+ Symbol *S;
+ bool WasInserted;
+ std::tie(S, WasInserted) = insert(N, nullptr);
+ S->IsUsedInRegularObj = true;
+ if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S))
+ replaceSymbol<DefinedAbsolute>(S, N, VA);
+ else if (!isa<DefinedCOFF>(S))
+ reportDuplicate(S, nullptr);
+ return S;
+}
+
+Symbol *SymbolTable::addSynthetic(StringRef N, Chunk *C) {
+ Symbol *S;
+ bool WasInserted;
+ std::tie(S, WasInserted) = insert(N, nullptr);
+ S->IsUsedInRegularObj = true;
+ if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S))
+ replaceSymbol<DefinedSynthetic>(S, N, C);
+ else if (!isa<DefinedCOFF>(S))
+ reportDuplicate(S, nullptr);
+ return S;
+}
+
+Symbol *SymbolTable::addRegular(InputFile *F, StringRef N,
+ const coff_symbol_generic *Sym,
+ SectionChunk *C) {
+ Symbol *S;
+ bool WasInserted;
+ std::tie(S, WasInserted) = insert(N, F);
+ if (WasInserted || !isa<DefinedRegular>(S))
+ replaceSymbol<DefinedRegular>(S, F, N, /*IsCOMDAT*/ false,
+ /*IsExternal*/ true, Sym, C);
+ else
+ reportDuplicate(S, F);
+ return S;
+}
+
+std::pair<Symbol *, bool>
+SymbolTable::addComdat(InputFile *F, StringRef N,
+ const coff_symbol_generic *Sym) {
+ Symbol *S;
+ bool WasInserted;
+ std::tie(S, WasInserted) = insert(N, F);
+ if (WasInserted || !isa<DefinedRegular>(S)) {
+ replaceSymbol<DefinedRegular>(S, F, N, /*IsCOMDAT*/ true,
+ /*IsExternal*/ true, Sym, nullptr);
+ return {S, true};
+ }
+ if (!cast<DefinedRegular>(S)->isCOMDAT())
+ reportDuplicate(S, F);
+ return {S, false};
+}
+
+Symbol *SymbolTable::addCommon(InputFile *F, StringRef N, uint64_t Size,
+ const coff_symbol_generic *Sym, CommonChunk *C) {
+ Symbol *S;
+ bool WasInserted;
+ std::tie(S, WasInserted) = insert(N, F);
+ if (WasInserted || !isa<DefinedCOFF>(S))
+ replaceSymbol<DefinedCommon>(S, F, N, Size, Sym, C);
+ else if (auto *DC = dyn_cast<DefinedCommon>(S))
+ if (Size > DC->getSize())
+ replaceSymbol<DefinedCommon>(S, F, N, Size, Sym, C);
+ return S;
+}
+
+Symbol *SymbolTable::addImportData(StringRef N, ImportFile *F) {
+ Symbol *S;
+ bool WasInserted;
+ std::tie(S, WasInserted) = insert(N, nullptr);
+ S->IsUsedInRegularObj = true;
+ if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S)) {
+ replaceSymbol<DefinedImportData>(S, N, F);
+ return S;
+ }
+
+ reportDuplicate(S, F);
+ return nullptr;
+}
+
+Symbol *SymbolTable::addImportThunk(StringRef Name, DefinedImportData *ID,
+ uint16_t Machine) {
+ Symbol *S;
+ bool WasInserted;
+ std::tie(S, WasInserted) = insert(Name, nullptr);
+ S->IsUsedInRegularObj = true;
+ if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S)) {
+ replaceSymbol<DefinedImportThunk>(S, Name, ID, Machine);
+ return S;
+ }
+
+ reportDuplicate(S, ID->File);
+ return nullptr;
+}
+
+std::vector<Chunk *> SymbolTable::getChunks() {
+ std::vector<Chunk *> Res;
+ for (ObjFile *File : ObjFile::Instances) {
+ ArrayRef<Chunk *> V = File->getChunks();
+ Res.insert(Res.end(), V.begin(), V.end());
+ }
+ return Res;
+}
+
+Symbol *SymbolTable::find(StringRef Name) {
+ return SymMap.lookup(CachedHashStringRef(Name));
+}
+
+Symbol *SymbolTable::findUnderscore(StringRef Name) {
+ if (Config->Machine == I386)
+ return find(("_" + Name).str());
+ return find(Name);
+}
+
+StringRef SymbolTable::findByPrefix(StringRef Prefix) {
+ for (auto Pair : SymMap) {
+ StringRef Name = Pair.first.val();
+ if (Name.startswith(Prefix))
+ return Name;
+ }
+ return "";
+}
+
+StringRef SymbolTable::findMangle(StringRef Name) {
+ if (Symbol *Sym = find(Name))
+ if (!isa<Undefined>(Sym))
+ return Name;
+ if (Config->Machine != I386)
+ return findByPrefix(("?" + Name + "@@Y").str());
+ if (!Name.startswith("_"))
+ return "";
+ // Search for x86 stdcall function.
+ StringRef S = findByPrefix((Name + "@").str());
+ if (!S.empty())
+ return S;
+ // Search for x86 fastcall function.
+ S = findByPrefix(("@" + Name.substr(1) + "@").str());
+ if (!S.empty())
+ return S;
+ // Search for x86 vectorcall function.
+ S = findByPrefix((Name.substr(1) + "@@").str());
+ if (!S.empty())
+ return S;
+ // Search for x86 C++ non-member function.
+ return findByPrefix(("?" + Name.substr(1) + "@@Y").str());
+}
+
+void SymbolTable::mangleMaybe(Symbol *B) {
+ auto *U = dyn_cast<Undefined>(B);
+ if (!U || U->WeakAlias)
+ return;
+ StringRef Alias = findMangle(U->getName());
+ if (!Alias.empty()) {
+ log(U->getName() + " aliased to " + Alias);
+ U->WeakAlias = addUndefined(Alias);
+ }
+}
+
+Symbol *SymbolTable::addUndefined(StringRef Name) {
+ return addUndefined(Name, nullptr, false);
+}
+
+std::vector<StringRef> SymbolTable::compileBitcodeFiles() {
+ LTO.reset(new BitcodeCompiler);
+ for (BitcodeFile *F : BitcodeFile::Instances)
+ LTO->add(*F);
+ return LTO->compile();
+}
+
+void SymbolTable::addCombinedLTOObjects() {
+ if (BitcodeFile::Instances.empty())
+ return;
+
+ ScopedTimer T(LTOTimer);
+ for (StringRef Object : compileBitcodeFiles()) {
+ auto *Obj = make<ObjFile>(MemoryBufferRef(Object, "lto.tmp"));
+ Obj->parse();
+ ObjFile::Instances.push_back(Obj);
+ }
+}
+
+} // namespace coff
+} // namespace lld
diff --git a/contrib/llvm/tools/lld/COFF/SymbolTable.h b/contrib/llvm/tools/lld/COFF/SymbolTable.h
new file mode 100644
index 000000000000..00e55dbb7a02
--- /dev/null
+++ b/contrib/llvm/tools/lld/COFF/SymbolTable.h
@@ -0,0 +1,131 @@
+//===- SymbolTable.h --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_SYMBOL_TABLE_H
+#define LLD_COFF_SYMBOL_TABLE_H
+
+#include "InputFiles.h"
+#include "LTO.h"
+#include "llvm/ADT/CachedHashString.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+struct LTOCodeGenerator;
+}
+
+namespace lld {
+namespace coff {
+
+class Chunk;
+class CommonChunk;
+class Defined;
+class DefinedAbsolute;
+class DefinedRelative;
+class Lazy;
+class SectionChunk;
+class Symbol;
+
+// SymbolTable is a bucket of all known symbols, including defined,
+// undefined, or lazy symbols (the last one is symbols in archive
+// files whose archive members are not yet loaded).
+//
+// We put all symbols of all files to a SymbolTable, and the
+// SymbolTable selects the "best" symbols if there are name
+// conflicts. For example, obviously, a defined symbol is better than
+// an undefined symbol. Or, if there's a conflict between a lazy and a
+// undefined, it'll read an archive member to read a real definition
+// to replace the lazy symbol. The logic is implemented in the
+// add*() functions, which are called by input files as they are parsed.
+// There is one add* function per symbol type.
+class SymbolTable {
+public:
+ void addFile(InputFile *File);
+
+ // Try to resolve any undefined symbols and update the symbol table
+ // accordingly, then print an error message for any remaining undefined
+ // symbols.
+ void reportRemainingUndefines();
+
+ void loadMinGWAutomaticImports();
+ bool handleMinGWAutomaticImport(Symbol *Sym, StringRef Name);
+
+ // Returns a list of chunks of selected symbols.
+ std::vector<Chunk *> getChunks();
+
+ // Returns a symbol for a given name. Returns a nullptr if not found.
+ Symbol *find(StringRef Name);
+ Symbol *findUnderscore(StringRef Name);
+
+ // Occasionally we have to resolve an undefined symbol to its
+ // mangled symbol. This function tries to find a mangled name
+ // for U from the symbol table, and if found, set the symbol as
+ // a weak alias for U.
+ void mangleMaybe(Symbol *B);
+ StringRef findMangle(StringRef Name);
+
+ // Build a set of COFF objects representing the combined contents of
+ // BitcodeFiles and add them to the symbol table. Called after all files are
+ // added and before the writer writes results to a file.
+ void addCombinedLTOObjects();
+ std::vector<StringRef> compileBitcodeFiles();
+
+ // Creates an Undefined symbol for a given name.
+ Symbol *addUndefined(StringRef Name);
+
+ Symbol *addSynthetic(StringRef N, Chunk *C);
+ Symbol *addAbsolute(StringRef N, uint64_t VA);
+
+ Symbol *addUndefined(StringRef Name, InputFile *F, bool IsWeakAlias);
+ void addLazy(ArchiveFile *F, const Archive::Symbol Sym);
+ Symbol *addAbsolute(StringRef N, COFFSymbolRef S);
+ Symbol *addRegular(InputFile *F, StringRef N,
+ const llvm::object::coff_symbol_generic *S = nullptr,
+ SectionChunk *C = nullptr);
+ std::pair<Symbol *, bool>
+ addComdat(InputFile *F, StringRef N,
+ const llvm::object::coff_symbol_generic *S = nullptr);
+ Symbol *addCommon(InputFile *F, StringRef N, uint64_t Size,
+ const llvm::object::coff_symbol_generic *S = nullptr,
+ CommonChunk *C = nullptr);
+ Symbol *addImportData(StringRef N, ImportFile *F);
+ Symbol *addImportThunk(StringRef Name, DefinedImportData *S,
+ uint16_t Machine);
+
+ void reportDuplicate(Symbol *Existing, InputFile *NewFile);
+
+ // A list of chunks which to be added to .rdata.
+ std::vector<Chunk *> LocalImportChunks;
+
+ // Iterates symbols in non-determinstic hash table order.
+ template <typename T> void forEachSymbol(T Callback) {
+ for (auto &Pair : SymMap)
+ Callback(Pair.second);
+ }
+
+private:
+ /// Inserts symbol if not already present.
+ std::pair<Symbol *, bool> insert(StringRef Name);
+ /// Same as insert(Name), but also sets IsUsedInRegularObj.
+ std::pair<Symbol *, bool> insert(StringRef Name, InputFile *F);
+ StringRef findByPrefix(StringRef Prefix);
+
+ llvm::DenseMap<llvm::CachedHashStringRef, Symbol *> SymMap;
+ std::unique_ptr<BitcodeCompiler> LTO;
+};
+
+extern SymbolTable *Symtab;
+
+std::string getSymbolLocations(ObjFile *File, uint32_t SymIndex);
+
+} // namespace coff
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/COFF/Symbols.cpp b/contrib/llvm/tools/lld/COFF/Symbols.cpp
new file mode 100644
index 000000000000..ccaf86417f10
--- /dev/null
+++ b/contrib/llvm/tools/lld/COFF/Symbols.cpp
@@ -0,0 +1,107 @@
+//===- Symbols.cpp --------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Symbols.h"
+#include "InputFiles.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Memory.h"
+#include "lld/Common/Strings.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace llvm::object;
+
+// Returns a symbol name for an error message.
+std::string lld::toString(coff::Symbol &B) {
+ if (Optional<std::string> S = lld::demangleMSVC(B.getName()))
+ return ("\"" + *S + "\" (" + B.getName() + ")").str();
+ return B.getName();
+}
+
+namespace lld {
+namespace coff {
+
+StringRef Symbol::getName() {
+ // COFF symbol names are read lazily for a performance reason.
+ // Non-external symbol names are never used by the linker except for logging
+ // or debugging. Their internal references are resolved not by name but by
+ // symbol index. And because they are not external, no one can refer them by
+ // name. Object files contain lots of non-external symbols, and creating
+ // StringRefs for them (which involves lots of strlen() on the string table)
+ // is a waste of time.
+ if (Name.empty()) {
+ auto *D = cast<DefinedCOFF>(this);
+ cast<ObjFile>(D->File)->getCOFFObj()->getSymbolName(D->Sym, Name);
+ }
+ return Name;
+}
+
+InputFile *Symbol::getFile() {
+ if (auto *Sym = dyn_cast<DefinedCOFF>(this))
+ return Sym->File;
+ if (auto *Sym = dyn_cast<Lazy>(this))
+ return Sym->File;
+ return nullptr;
+}
+
+bool Symbol::isLive() const {
+ if (auto *R = dyn_cast<DefinedRegular>(this))
+ return R->getChunk()->Live;
+ if (auto *Imp = dyn_cast<DefinedImportData>(this))
+ return Imp->File->Live;
+ if (auto *Imp = dyn_cast<DefinedImportThunk>(this))
+ return Imp->WrappedSym->File->ThunkLive;
+ // Assume any other kind of symbol is live.
+ return true;
+}
+
+// MinGW specific.
+void Symbol::replaceKeepingName(Symbol *Other, size_t Size) {
+ StringRef OrigName = Name;
+ memcpy(this, Other, Size);
+ Name = OrigName;
+}
+
+COFFSymbolRef DefinedCOFF::getCOFFSymbol() {
+ size_t SymSize = cast<ObjFile>(File)->getCOFFObj()->getSymbolTableEntrySize();
+ if (SymSize == sizeof(coff_symbol16))
+ return COFFSymbolRef(reinterpret_cast<const coff_symbol16 *>(Sym));
+ assert(SymSize == sizeof(coff_symbol32));
+ return COFFSymbolRef(reinterpret_cast<const coff_symbol32 *>(Sym));
+}
+
+uint16_t DefinedAbsolute::NumOutputSections;
+
+static Chunk *makeImportThunk(DefinedImportData *S, uint16_t Machine) {
+ if (Machine == AMD64)
+ return make<ImportThunkChunkX64>(S);
+ if (Machine == I386)
+ return make<ImportThunkChunkX86>(S);
+ if (Machine == ARM64)
+ return make<ImportThunkChunkARM64>(S);
+ assert(Machine == ARMNT);
+ return make<ImportThunkChunkARM>(S);
+}
+
+DefinedImportThunk::DefinedImportThunk(StringRef Name, DefinedImportData *S,
+ uint16_t Machine)
+ : Defined(DefinedImportThunkKind, Name), WrappedSym(S),
+ Data(makeImportThunk(S, Machine)) {}
+
+Defined *Undefined::getWeakAlias() {
+ // A weak alias may be a weak alias to another symbol, so check recursively.
+ for (Symbol *A = WeakAlias; A; A = cast<Undefined>(A)->WeakAlias)
+ if (auto *D = dyn_cast<Defined>(A))
+ return D;
+ return nullptr;
+}
+} // namespace coff
+} // namespace lld
diff --git a/contrib/llvm/tools/lld/COFF/Symbols.h b/contrib/llvm/tools/lld/COFF/Symbols.h
new file mode 100644
index 000000000000..4a8693e22e3c
--- /dev/null
+++ b/contrib/llvm/tools/lld/COFF/Symbols.h
@@ -0,0 +1,436 @@
+//===- Symbols.h ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_SYMBOLS_H
+#define LLD_COFF_SYMBOLS_H
+
+#include "Chunks.h"
+#include "Config.h"
+#include "lld/Common/LLVM.h"
+#include "lld/Common/Memory.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/COFF.h"
+#include <atomic>
+#include <memory>
+#include <vector>
+
+namespace lld {
+namespace coff {
+
+using llvm::object::Archive;
+using llvm::object::COFFSymbolRef;
+using llvm::object::coff_import_header;
+using llvm::object::coff_symbol_generic;
+
+class ArchiveFile;
+class InputFile;
+class ObjFile;
+class SymbolTable;
+
+// The base class for real symbol classes.
+class Symbol {
+public:
+ enum Kind {
+ // The order of these is significant. We start with the regular defined
+ // symbols as those are the most prevalent and the zero tag is the cheapest
+ // to set. Among the defined kinds, the lower the kind is preferred over
+ // the higher kind when testing whether one symbol should take precedence
+ // over another.
+ DefinedRegularKind = 0,
+ DefinedCommonKind,
+ DefinedLocalImportKind,
+ DefinedImportThunkKind,
+ DefinedImportDataKind,
+ DefinedAbsoluteKind,
+ DefinedSyntheticKind,
+
+ UndefinedKind,
+ LazyKind,
+
+ LastDefinedCOFFKind = DefinedCommonKind,
+ LastDefinedKind = DefinedSyntheticKind,
+ };
+
+ Kind kind() const { return static_cast<Kind>(SymbolKind); }
+
+ // Returns true if this is an external symbol.
+ bool isExternal() { return IsExternal; }
+
+ // Returns the symbol name.
+ StringRef getName();
+
+ void replaceKeepingName(Symbol *Other, size_t Size);
+
+ // Returns the file from which this symbol was created.
+ InputFile *getFile();
+
+ // Indicates that this symbol will be included in the final image. Only valid
+ // after calling markLive.
+ bool isLive() const;
+
+protected:
+ friend SymbolTable;
+ explicit Symbol(Kind K, StringRef N = "")
+ : SymbolKind(K), IsExternal(true), IsCOMDAT(false),
+ WrittenToSymtab(false), PendingArchiveLoad(false), IsGCRoot(false),
+ IsRuntimePseudoReloc(false), Name(N) {}
+
+ const unsigned SymbolKind : 8;
+ unsigned IsExternal : 1;
+
+ // This bit is used by the \c DefinedRegular subclass.
+ unsigned IsCOMDAT : 1;
+
+public:
+ // This bit is used by Writer::createSymbolAndStringTable() to prevent
+ // symbols from being written to the symbol table more than once.
+ unsigned WrittenToSymtab : 1;
+
+ // True if this symbol was referenced by a regular (non-bitcode) object.
+ unsigned IsUsedInRegularObj : 1;
+
+ // True if we've seen both a lazy and an undefined symbol with this symbol
+ // name, which means that we have enqueued an archive member load and should
+ // not load any more archive members to resolve the same symbol.
+ unsigned PendingArchiveLoad : 1;
+
+ /// True if we've already added this symbol to the list of GC roots.
+ unsigned IsGCRoot : 1;
+
+ unsigned IsRuntimePseudoReloc : 1;
+
+protected:
+ StringRef Name;
+};
+
+// The base class for any defined symbols, including absolute symbols,
+// etc.
+class Defined : public Symbol {
+public:
+ Defined(Kind K, StringRef N) : Symbol(K, N) {}
+
+ static bool classof(const Symbol *S) { return S->kind() <= LastDefinedKind; }
+
+ // Returns the RVA (relative virtual address) of this symbol. The
+ // writer sets and uses RVAs.
+ uint64_t getRVA();
+
+ // Returns the chunk containing this symbol. Absolute symbols and __ImageBase
+ // do not have chunks, so this may return null.
+ Chunk *getChunk();
+};
+
+// Symbols defined via a COFF object file or bitcode file. For COFF files, this
+// stores a coff_symbol_generic*, and names of internal symbols are lazily
+// loaded through that. For bitcode files, Sym is nullptr and the name is stored
+// as a StringRef.
+class DefinedCOFF : public Defined {
+ friend Symbol;
+
+public:
+ DefinedCOFF(Kind K, InputFile *F, StringRef N, const coff_symbol_generic *S)
+ : Defined(K, N), File(F), Sym(S) {}
+
+ static bool classof(const Symbol *S) {
+ return S->kind() <= LastDefinedCOFFKind;
+ }
+
+ InputFile *getFile() { return File; }
+
+ COFFSymbolRef getCOFFSymbol();
+
+ InputFile *File;
+
+protected:
+ const coff_symbol_generic *Sym;
+};
+
+// Regular defined symbols read from object file symbol tables.
+class DefinedRegular : public DefinedCOFF {
+public:
+ DefinedRegular(InputFile *F, StringRef N, bool IsCOMDAT,
+ bool IsExternal = false,
+ const coff_symbol_generic *S = nullptr,
+ SectionChunk *C = nullptr)
+ : DefinedCOFF(DefinedRegularKind, F, N, S), Data(C ? &C->Repl : nullptr) {
+ this->IsExternal = IsExternal;
+ this->IsCOMDAT = IsCOMDAT;
+ }
+
+ static bool classof(const Symbol *S) {
+ return S->kind() == DefinedRegularKind;
+ }
+
+ uint64_t getRVA() const { return (*Data)->getRVA() + Sym->Value; }
+ bool isCOMDAT() const { return IsCOMDAT; }
+ SectionChunk *getChunk() const { return *Data; }
+ uint32_t getValue() const { return Sym->Value; }
+
+ SectionChunk **Data;
+};
+
+class DefinedCommon : public DefinedCOFF {
+public:
+ DefinedCommon(InputFile *F, StringRef N, uint64_t Size,
+ const coff_symbol_generic *S = nullptr,
+ CommonChunk *C = nullptr)
+ : DefinedCOFF(DefinedCommonKind, F, N, S), Data(C), Size(Size) {
+ this->IsExternal = true;
+ }
+
+ static bool classof(const Symbol *S) {
+ return S->kind() == DefinedCommonKind;
+ }
+
+ uint64_t getRVA() { return Data->getRVA(); }
+ CommonChunk *getChunk() { return Data; }
+
+private:
+ friend SymbolTable;
+ uint64_t getSize() const { return Size; }
+ CommonChunk *Data;
+ uint64_t Size;
+};
+
+// Absolute symbols.
+class DefinedAbsolute : public Defined {
+public:
+ DefinedAbsolute(StringRef N, COFFSymbolRef S)
+ : Defined(DefinedAbsoluteKind, N), VA(S.getValue()) {
+ IsExternal = S.isExternal();
+ }
+
+ DefinedAbsolute(StringRef N, uint64_t V)
+ : Defined(DefinedAbsoluteKind, N), VA(V) {}
+
+ static bool classof(const Symbol *S) {
+ return S->kind() == DefinedAbsoluteKind;
+ }
+
+ uint64_t getRVA() { return VA - Config->ImageBase; }
+ void setVA(uint64_t V) { VA = V; }
+
+ // Section index relocations against absolute symbols resolve to
+ // this 16 bit number, and it is the largest valid section index
+ // plus one. This variable keeps it.
+ static uint16_t NumOutputSections;
+
+private:
+ uint64_t VA;
+};
+
+// This symbol is used for linker-synthesized symbols like __ImageBase and
+// __safe_se_handler_table.
+class DefinedSynthetic : public Defined {
+public:
+ explicit DefinedSynthetic(StringRef Name, Chunk *C)
+ : Defined(DefinedSyntheticKind, Name), C(C) {}
+
+ static bool classof(const Symbol *S) {
+ return S->kind() == DefinedSyntheticKind;
+ }
+
+ // A null chunk indicates that this is __ImageBase. Otherwise, this is some
+ // other synthesized chunk, like SEHTableChunk.
+ uint32_t getRVA() { return C ? C->getRVA() : 0; }
+ Chunk *getChunk() { return C; }
+
+private:
+ Chunk *C;
+};
+
+// This class represents a symbol defined in an archive file. It is
+// created from an archive file header, and it knows how to load an
+// object file from an archive to replace itself with a defined
+// symbol. If the resolver finds both Undefined and Lazy for
+// the same name, it will ask the Lazy to load a file.
+class Lazy : public Symbol {
+public:
+ Lazy(ArchiveFile *F, const Archive::Symbol S)
+ : Symbol(LazyKind, S.getName()), File(F), Sym(S) {}
+
+ static bool classof(const Symbol *S) { return S->kind() == LazyKind; }
+
+ ArchiveFile *File;
+
+private:
+ friend SymbolTable;
+
+private:
+ const Archive::Symbol Sym;
+};
+
+// Undefined symbols.
+class Undefined : public Symbol {
+public:
+ explicit Undefined(StringRef N) : Symbol(UndefinedKind, N) {}
+
+ static bool classof(const Symbol *S) { return S->kind() == UndefinedKind; }
+
+ // An undefined symbol can have a fallback symbol which gives an
+ // undefined symbol a second chance if it would remain undefined.
+ // If it remains undefined, it'll be replaced with whatever the
+ // Alias pointer points to.
+ Symbol *WeakAlias = nullptr;
+
+ // If this symbol is external weak, try to resolve it to a defined
+ // symbol by searching the chain of fallback symbols. Returns the symbol if
+ // successful, otherwise returns null.
+ Defined *getWeakAlias();
+};
+
+// Windows-specific classes.
+
+// This class represents a symbol imported from a DLL. This has two
+// names for internal use and external use. The former is used for
+// name resolution, and the latter is used for the import descriptor
+// table in an output. The former has "__imp_" prefix.
+class DefinedImportData : public Defined {
+public:
+ DefinedImportData(StringRef N, ImportFile *F)
+ : Defined(DefinedImportDataKind, N), File(F) {
+ }
+
+ static bool classof(const Symbol *S) {
+ return S->kind() == DefinedImportDataKind;
+ }
+
+ uint64_t getRVA() { return File->Location->getRVA(); }
+ Chunk *getChunk() { return File->Location; }
+ void setLocation(Chunk *AddressTable) { File->Location = AddressTable; }
+
+ StringRef getDLLName() { return File->DLLName; }
+ StringRef getExternalName() { return File->ExternalName; }
+ uint16_t getOrdinal() { return File->Hdr->OrdinalHint; }
+
+ ImportFile *File;
+};
+
+// This class represents a symbol for a jump table entry which jumps
+// to a function in a DLL. Linker are supposed to create such symbols
+// without "__imp_" prefix for all function symbols exported from
+// DLLs, so that you can call DLL functions as regular functions with
+// a regular name. A function pointer is given as a DefinedImportData.
+class DefinedImportThunk : public Defined {
+public:
+ DefinedImportThunk(StringRef Name, DefinedImportData *S, uint16_t Machine);
+
+ static bool classof(const Symbol *S) {
+ return S->kind() == DefinedImportThunkKind;
+ }
+
+ uint64_t getRVA() { return Data->getRVA(); }
+ Chunk *getChunk() { return Data; }
+
+ DefinedImportData *WrappedSym;
+
+private:
+ Chunk *Data;
+};
+
+// If you have a symbol "foo" in your object file, a symbol name
+// "__imp_foo" becomes automatically available as a pointer to "foo".
+// This class is for such automatically-created symbols.
+// Yes, this is an odd feature. We didn't intend to implement that.
+// This is here just for compatibility with MSVC.
+class DefinedLocalImport : public Defined {
+public:
+ DefinedLocalImport(StringRef N, Defined *S)
+ : Defined(DefinedLocalImportKind, N), Data(make<LocalImportChunk>(S)) {}
+
+ static bool classof(const Symbol *S) {
+ return S->kind() == DefinedLocalImportKind;
+ }
+
+ uint64_t getRVA() { return Data->getRVA(); }
+ Chunk *getChunk() { return Data; }
+
+private:
+ LocalImportChunk *Data;
+};
+
+inline uint64_t Defined::getRVA() {
+ switch (kind()) {
+ case DefinedAbsoluteKind:
+ return cast<DefinedAbsolute>(this)->getRVA();
+ case DefinedSyntheticKind:
+ return cast<DefinedSynthetic>(this)->getRVA();
+ case DefinedImportDataKind:
+ return cast<DefinedImportData>(this)->getRVA();
+ case DefinedImportThunkKind:
+ return cast<DefinedImportThunk>(this)->getRVA();
+ case DefinedLocalImportKind:
+ return cast<DefinedLocalImport>(this)->getRVA();
+ case DefinedCommonKind:
+ return cast<DefinedCommon>(this)->getRVA();
+ case DefinedRegularKind:
+ return cast<DefinedRegular>(this)->getRVA();
+ case LazyKind:
+ case UndefinedKind:
+ llvm_unreachable("Cannot get the address for an undefined symbol.");
+ }
+ llvm_unreachable("unknown symbol kind");
+}
+
+inline Chunk *Defined::getChunk() {
+ switch (kind()) {
+ case DefinedRegularKind:
+ return cast<DefinedRegular>(this)->getChunk();
+ case DefinedAbsoluteKind:
+ return nullptr;
+ case DefinedSyntheticKind:
+ return cast<DefinedSynthetic>(this)->getChunk();
+ case DefinedImportDataKind:
+ return cast<DefinedImportData>(this)->getChunk();
+ case DefinedImportThunkKind:
+ return cast<DefinedImportThunk>(this)->getChunk();
+ case DefinedLocalImportKind:
+ return cast<DefinedLocalImport>(this)->getChunk();
+ case DefinedCommonKind:
+ return cast<DefinedCommon>(this)->getChunk();
+ case LazyKind:
+ case UndefinedKind:
+ llvm_unreachable("Cannot get the chunk of an undefined symbol.");
+ }
+ llvm_unreachable("unknown symbol kind");
+}
+
+// A buffer class that is large enough to hold any Symbol-derived
+// object. We allocate memory using this class and instantiate a symbol
+// using the placement new.
+union SymbolUnion {
+ alignas(DefinedRegular) char A[sizeof(DefinedRegular)];
+ alignas(DefinedCommon) char B[sizeof(DefinedCommon)];
+ alignas(DefinedAbsolute) char C[sizeof(DefinedAbsolute)];
+ alignas(DefinedSynthetic) char D[sizeof(DefinedSynthetic)];
+ alignas(Lazy) char E[sizeof(Lazy)];
+ alignas(Undefined) char F[sizeof(Undefined)];
+ alignas(DefinedImportData) char G[sizeof(DefinedImportData)];
+ alignas(DefinedImportThunk) char H[sizeof(DefinedImportThunk)];
+ alignas(DefinedLocalImport) char I[sizeof(DefinedLocalImport)];
+};
+
+template <typename T, typename... ArgT>
+void replaceSymbol(Symbol *S, ArgT &&... Arg) {
+ static_assert(std::is_trivially_destructible<T>(),
+ "Symbol types must be trivially destructible");
+ static_assert(sizeof(T) <= sizeof(SymbolUnion), "Symbol too small");
+ static_assert(alignof(T) <= alignof(SymbolUnion),
+ "SymbolUnion not aligned enough");
+ assert(static_cast<Symbol *>(static_cast<T *>(nullptr)) == nullptr &&
+ "Not a Symbol");
+ new (S) T(std::forward<ArgT>(Arg)...);
+}
+} // namespace coff
+
+std::string toString(coff::Symbol &B);
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/COFF/Writer.cpp b/contrib/llvm/tools/lld/COFF/Writer.cpp
new file mode 100644
index 000000000000..6acfaf9a4454
--- /dev/null
+++ b/contrib/llvm/tools/lld/COFF/Writer.cpp
@@ -0,0 +1,1745 @@
+//===- Writer.cpp ---------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Writer.h"
+#include "Config.h"
+#include "DLL.h"
+#include "InputFiles.h"
+#include "MapFile.h"
+#include "PDB.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Memory.h"
+#include "lld/Common/Timer.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/Parallel.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/RandomNumberGenerator.h"
+#include "llvm/Support/xxhash.h"
+#include <algorithm>
+#include <cstdio>
+#include <map>
+#include <memory>
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::COFF;
+using namespace llvm::object;
+using namespace llvm::support;
+using namespace llvm::support::endian;
+using namespace lld;
+using namespace lld::coff;
+
+/* To re-generate DOSProgram:
+$ cat > /tmp/DOSProgram.asm
+org 0
+ ; Copy cs to ds.
+ push cs
+ pop ds
+ ; Point ds:dx at the $-terminated string.
+ mov dx, str
+ ; Int 21/AH=09h: Write string to standard output.
+ mov ah, 0x9
+ int 0x21
+ ; Int 21/AH=4Ch: Exit with return code (in AL).
+ mov ax, 0x4C01
+ int 0x21
+str:
+ db 'This program cannot be run in DOS mode.$'
+align 8, db 0
+$ nasm -fbin /tmp/DOSProgram.asm -o /tmp/DOSProgram.bin
+$ xxd -i /tmp/DOSProgram.bin
+*/
+static unsigned char DOSProgram[] = {
+ 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c,
+ 0xcd, 0x21, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72,
+ 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x65,
+ 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20,
+ 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x24, 0x00, 0x00
+};
+static_assert(sizeof(DOSProgram) % 8 == 0,
+ "DOSProgram size must be multiple of 8");
+
+static const int SectorSize = 512;
+static const int DOSStubSize = sizeof(dos_header) + sizeof(DOSProgram);
+static_assert(DOSStubSize % 8 == 0, "DOSStub size must be multiple of 8");
+
+static const int NumberOfDataDirectory = 16;
+
+namespace {
+
+class DebugDirectoryChunk : public Chunk {
+public:
+ DebugDirectoryChunk(const std::vector<Chunk *> &R, bool WriteRepro)
+ : Records(R), WriteRepro(WriteRepro) {}
+
+ size_t getSize() const override {
+ return (Records.size() + int(WriteRepro)) * sizeof(debug_directory);
+ }
+
+ void writeTo(uint8_t *B) const override {
+ auto *D = reinterpret_cast<debug_directory *>(B + OutputSectionOff);
+
+ for (const Chunk *Record : Records) {
+ OutputSection *OS = Record->getOutputSection();
+ uint64_t Offs = OS->getFileOff() + (Record->getRVA() - OS->getRVA());
+ fillEntry(D, COFF::IMAGE_DEBUG_TYPE_CODEVIEW, Record->getSize(),
+ Record->getRVA(), Offs);
+ ++D;
+ }
+
+ if (WriteRepro) {
+ // FIXME: The COFF spec allows either a 0-sized entry to just say
+ // "the timestamp field is really a hash", or a 4-byte size field
+ // followed by that many bytes containing a longer hash (with the
+ // lowest 4 bytes usually being the timestamp in little-endian order).
+ // Consider storing the full 8 bytes computed by xxHash64 here.
+ fillEntry(D, COFF::IMAGE_DEBUG_TYPE_REPRO, 0, 0, 0);
+ }
+ }
+
+ void setTimeDateStamp(uint32_t TimeDateStamp) {
+ for (support::ulittle32_t *TDS : TimeDateStamps)
+ *TDS = TimeDateStamp;
+ }
+
+private:
+ void fillEntry(debug_directory *D, COFF::DebugType DebugType, size_t Size,
+ uint64_t RVA, uint64_t Offs) const {
+ D->Characteristics = 0;
+ D->TimeDateStamp = 0;
+ D->MajorVersion = 0;
+ D->MinorVersion = 0;
+ D->Type = DebugType;
+ D->SizeOfData = Size;
+ D->AddressOfRawData = RVA;
+ D->PointerToRawData = Offs;
+
+ TimeDateStamps.push_back(&D->TimeDateStamp);
+ }
+
+ mutable std::vector<support::ulittle32_t *> TimeDateStamps;
+ const std::vector<Chunk *> &Records;
+ bool WriteRepro;
+};
+
+class CVDebugRecordChunk : public Chunk {
+public:
+ size_t getSize() const override {
+ return sizeof(codeview::DebugInfo) + Config->PDBAltPath.size() + 1;
+ }
+
+ void writeTo(uint8_t *B) const override {
+ // Save off the DebugInfo entry to backfill the file signature (build id)
+ // in Writer::writeBuildId
+ BuildId = reinterpret_cast<codeview::DebugInfo *>(B + OutputSectionOff);
+
+ // variable sized field (PDB Path)
+ char *P = reinterpret_cast<char *>(B + OutputSectionOff + sizeof(*BuildId));
+ if (!Config->PDBAltPath.empty())
+ memcpy(P, Config->PDBAltPath.data(), Config->PDBAltPath.size());
+ P[Config->PDBAltPath.size()] = '\0';
+ }
+
+ mutable codeview::DebugInfo *BuildId = nullptr;
+};
+
+// The writer writes a SymbolTable result to a file.
+class Writer {
+public:
+ Writer() : Buffer(errorHandler().OutputBuffer) {}
+ void run();
+
+private:
+ void createSections();
+ void createMiscChunks();
+ void createImportTables();
+ void appendImportThunks();
+ void locateImportTables(
+ std::map<std::pair<StringRef, uint32_t>, std::vector<Chunk *>> &Map);
+ void createExportTable();
+ void mergeSections();
+ void readRelocTargets();
+ void removeUnusedSections();
+ void assignAddresses();
+ void finalizeAddresses();
+ void removeEmptySections();
+ void createSymbolAndStringTable();
+ void openFile(StringRef OutputPath);
+ template <typename PEHeaderTy> void writeHeader();
+ void createSEHTable();
+ void createRuntimePseudoRelocs();
+ void insertCtorDtorSymbols();
+ void createGuardCFTables();
+ void markSymbolsForRVATable(ObjFile *File,
+ ArrayRef<SectionChunk *> SymIdxChunks,
+ SymbolRVASet &TableSymbols);
+ void maybeAddRVATable(SymbolRVASet TableSymbols, StringRef TableSym,
+ StringRef CountSym);
+ void setSectionPermissions();
+ void writeSections();
+ void writeBuildId();
+ void sortExceptionTable();
+ void sortCRTSectionChunks(std::vector<Chunk *> &Chunks);
+
+ llvm::Optional<coff_symbol16> createSymbol(Defined *D);
+ size_t addEntryToStringTable(StringRef Str);
+
+ OutputSection *findSection(StringRef Name);
+ void addBaserels();
+ void addBaserelBlocks(std::vector<Baserel> &V);
+
+ uint32_t getSizeOfInitializedData();
+ std::map<StringRef, std::vector<DefinedImportData *>> binImports();
+
+ std::unique_ptr<FileOutputBuffer> &Buffer;
+ std::vector<OutputSection *> OutputSections;
+ std::vector<char> Strtab;
+ std::vector<llvm::object::coff_symbol16> OutputSymtab;
+ IdataContents Idata;
+ Chunk *ImportTableStart = nullptr;
+ uint64_t ImportTableSize = 0;
+ Chunk *IATStart = nullptr;
+ uint64_t IATSize = 0;
+ DelayLoadContents DelayIdata;
+ EdataContents Edata;
+ bool SetNoSEHCharacteristic = false;
+
+ DebugDirectoryChunk *DebugDirectory = nullptr;
+ std::vector<Chunk *> DebugRecords;
+ CVDebugRecordChunk *BuildId = nullptr;
+ ArrayRef<uint8_t> SectionTable;
+
+ uint64_t FileSize;
+ uint32_t PointerToSymbolTable = 0;
+ uint64_t SizeOfImage;
+ uint64_t SizeOfHeaders;
+
+ OutputSection *TextSec;
+ OutputSection *RdataSec;
+ OutputSection *BuildidSec;
+ OutputSection *DataSec;
+ OutputSection *PdataSec;
+ OutputSection *IdataSec;
+ OutputSection *EdataSec;
+ OutputSection *DidatSec;
+ OutputSection *RsrcSec;
+ OutputSection *RelocSec;
+ OutputSection *CtorsSec;
+ OutputSection *DtorsSec;
+
+ // The first and last .pdata sections in the output file.
+ //
+ // We need to keep track of the location of .pdata in whichever section it
+ // gets merged into so that we can sort its contents and emit a correct data
+ // directory entry for the exception table. This is also the case for some
+ // other sections (such as .edata) but because the contents of those sections
+ // are entirely linker-generated we can keep track of their locations using
+ // the chunks that the linker creates. All .pdata chunks come from input
+ // files, so we need to keep track of them separately.
+ Chunk *FirstPdata = nullptr;
+ Chunk *LastPdata;
+};
+} // anonymous namespace
+
+namespace lld {
+namespace coff {
+
+static Timer CodeLayoutTimer("Code Layout", Timer::root());
+static Timer DiskCommitTimer("Commit Output File", Timer::root());
+
+void writeResult() { Writer().run(); }
+
+void OutputSection::addChunk(Chunk *C) {
+ Chunks.push_back(C);
+ C->setOutputSection(this);
+}
+
+void OutputSection::insertChunkAtStart(Chunk *C) {
+ Chunks.insert(Chunks.begin(), C);
+ C->setOutputSection(this);
+}
+
+void OutputSection::setPermissions(uint32_t C) {
+ Header.Characteristics &= ~PermMask;
+ Header.Characteristics |= C;
+}
+
+void OutputSection::merge(OutputSection *Other) {
+ for (Chunk *C : Other->Chunks)
+ C->setOutputSection(this);
+ Chunks.insert(Chunks.end(), Other->Chunks.begin(), Other->Chunks.end());
+ Other->Chunks.clear();
+}
+
+// Write the section header to a given buffer.
+void OutputSection::writeHeaderTo(uint8_t *Buf) {
+ auto *Hdr = reinterpret_cast<coff_section *>(Buf);
+ *Hdr = Header;
+ if (StringTableOff) {
+ // If name is too long, write offset into the string table as a name.
+ sprintf(Hdr->Name, "/%d", StringTableOff);
+ } else {
+ assert(!Config->Debug || Name.size() <= COFF::NameSize ||
+ (Hdr->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0);
+ strncpy(Hdr->Name, Name.data(),
+ std::min(Name.size(), (size_t)COFF::NameSize));
+ }
+}
+
+} // namespace coff
+} // namespace lld
+
+// Check whether the target address S is in range from a relocation
+// of type RelType at address P.
+static bool isInRange(uint16_t RelType, uint64_t S, uint64_t P, int Margin) {
+ if (Config->Machine == ARMNT) {
+ int64_t Diff = AbsoluteDifference(S, P + 4) + Margin;
+ switch (RelType) {
+ case IMAGE_REL_ARM_BRANCH20T:
+ return isInt<21>(Diff);
+ case IMAGE_REL_ARM_BRANCH24T:
+ case IMAGE_REL_ARM_BLX23T:
+ return isInt<25>(Diff);
+ default:
+ return true;
+ }
+ } else if (Config->Machine == ARM64) {
+ int64_t Diff = AbsoluteDifference(S, P) + Margin;
+ switch (RelType) {
+ case IMAGE_REL_ARM64_BRANCH26:
+ return isInt<28>(Diff);
+ case IMAGE_REL_ARM64_BRANCH19:
+ return isInt<21>(Diff);
+ case IMAGE_REL_ARM64_BRANCH14:
+ return isInt<16>(Diff);
+ default:
+ return true;
+ }
+ } else {
+ llvm_unreachable("Unexpected architecture");
+ }
+}
+
+// Return the last thunk for the given target if it is in range,
+// or create a new one.
+static std::pair<Defined *, bool>
+getThunk(DenseMap<uint64_t, Defined *> &LastThunks, Defined *Target, uint64_t P,
+ uint16_t Type, int Margin) {
+ Defined *&LastThunk = LastThunks[Target->getRVA()];
+ if (LastThunk && isInRange(Type, LastThunk->getRVA(), P, Margin))
+ return {LastThunk, false};
+ Chunk *C;
+ switch (Config->Machine) {
+ case ARMNT:
+ C = make<RangeExtensionThunkARM>(Target);
+ break;
+ case ARM64:
+ C = make<RangeExtensionThunkARM64>(Target);
+ break;
+ default:
+ llvm_unreachable("Unexpected architecture");
+ }
+ Defined *D = make<DefinedSynthetic>("", C);
+ LastThunk = D;
+ return {D, true};
+}
+
+// This checks all relocations, and for any relocation which isn't in range
+// it adds a thunk after the section chunk that contains the relocation.
+// If the latest thunk for the specific target is in range, that is used
+// instead of creating a new thunk. All range checks are done with the
+// specified margin, to make sure that relocations that originally are in
+// range, but only barely, also get thunks - in case other added thunks makes
+// the target go out of range.
+//
+// After adding thunks, we verify that all relocations are in range (with
+// no extra margin requirements). If this failed, we restart (throwing away
+// the previously created thunks) and retry with a wider margin.
+static bool createThunks(OutputSection *OS, int Margin) {
+ bool AddressesChanged = false;
+ DenseMap<uint64_t, Defined *> LastThunks;
+ size_t ThunksSize = 0;
+ // Recheck Chunks.size() each iteration, since we can insert more
+ // elements into it.
+ for (size_t I = 0; I != OS->Chunks.size(); ++I) {
+ SectionChunk *SC = dyn_cast_or_null<SectionChunk>(OS->Chunks[I]);
+ if (!SC)
+ continue;
+ size_t ThunkInsertionSpot = I + 1;
+
+ // Try to get a good enough estimate of where new thunks will be placed.
+ // Offset this by the size of the new thunks added so far, to make the
+ // estimate slightly better.
+ size_t ThunkInsertionRVA = SC->getRVA() + SC->getSize() + ThunksSize;
+ for (size_t J = 0, E = SC->Relocs.size(); J < E; ++J) {
+ const coff_relocation &Rel = SC->Relocs[J];
+ Symbol *&RelocTarget = SC->RelocTargets[J];
+
+ // The estimate of the source address P should be pretty accurate,
+ // but we don't know whether the target Symbol address should be
+ // offset by ThunkSize or not (or by some of ThunksSize but not all of
+ // it), giving us some uncertainty once we have added one thunk.
+ uint64_t P = SC->getRVA() + Rel.VirtualAddress + ThunksSize;
+
+ Defined *Sym = dyn_cast_or_null<Defined>(RelocTarget);
+ if (!Sym)
+ continue;
+
+ uint64_t S = Sym->getRVA();
+
+ if (isInRange(Rel.Type, S, P, Margin))
+ continue;
+
+ // If the target isn't in range, hook it up to an existing or new
+ // thunk.
+ Defined *Thunk;
+ bool WasNew;
+ std::tie(Thunk, WasNew) = getThunk(LastThunks, Sym, P, Rel.Type, Margin);
+ if (WasNew) {
+ Chunk *ThunkChunk = Thunk->getChunk();
+ ThunkChunk->setRVA(
+ ThunkInsertionRVA); // Estimate of where it will be located.
+ ThunkChunk->setOutputSection(OS);
+ OS->Chunks.insert(OS->Chunks.begin() + ThunkInsertionSpot, ThunkChunk);
+ ThunkInsertionSpot++;
+ ThunksSize += ThunkChunk->getSize();
+ ThunkInsertionRVA += ThunkChunk->getSize();
+ AddressesChanged = true;
+ }
+ RelocTarget = Thunk;
+ }
+ }
+ return AddressesChanged;
+}
+
+// Verify that all relocations are in range, with no extra margin requirements.
+static bool verifyRanges(const std::vector<Chunk *> Chunks) {
+ for (Chunk *C : Chunks) {
+ SectionChunk *SC = dyn_cast_or_null<SectionChunk>(C);
+ if (!SC)
+ continue;
+
+ for (size_t J = 0, E = SC->Relocs.size(); J < E; ++J) {
+ const coff_relocation &Rel = SC->Relocs[J];
+ Symbol *RelocTarget = SC->RelocTargets[J];
+
+ Defined *Sym = dyn_cast_or_null<Defined>(RelocTarget);
+ if (!Sym)
+ continue;
+
+ uint64_t P = SC->getRVA() + Rel.VirtualAddress;
+ uint64_t S = Sym->getRVA();
+
+ if (!isInRange(Rel.Type, S, P, 0))
+ return false;
+ }
+ }
+ return true;
+}
+
+// Assign addresses and add thunks if necessary.
+void Writer::finalizeAddresses() {
+ assignAddresses();
+ if (Config->Machine != ARMNT && Config->Machine != ARM64)
+ return;
+
+ size_t OrigNumChunks = 0;
+ for (OutputSection *Sec : OutputSections) {
+ Sec->OrigChunks = Sec->Chunks;
+ OrigNumChunks += Sec->Chunks.size();
+ }
+
+ int Pass = 0;
+ int Margin = 1024 * 100;
+ while (true) {
+ // First check whether we need thunks at all, or if the previous pass of
+ // adding them turned out ok.
+ bool RangesOk = true;
+ size_t NumChunks = 0;
+ for (OutputSection *Sec : OutputSections) {
+ if (!verifyRanges(Sec->Chunks)) {
+ RangesOk = false;
+ break;
+ }
+ NumChunks += Sec->Chunks.size();
+ }
+ if (RangesOk) {
+ if (Pass > 0)
+ log("Added " + Twine(NumChunks - OrigNumChunks) + " thunks with " +
+ "margin " + Twine(Margin) + " in " + Twine(Pass) + " passes");
+ return;
+ }
+
+ if (Pass >= 10)
+ fatal("adding thunks hasn't converged after " + Twine(Pass) + " passes");
+
+ if (Pass > 0) {
+ // If the previous pass didn't work out, reset everything back to the
+ // original conditions before retrying with a wider margin. This should
+ // ideally never happen under real circumstances.
+ for (OutputSection *Sec : OutputSections) {
+ Sec->Chunks = Sec->OrigChunks;
+ for (Chunk *C : Sec->Chunks)
+ C->resetRelocTargets();
+ }
+ Margin *= 2;
+ }
+
+ // Try adding thunks everywhere where it is needed, with a margin
+ // to avoid things going out of range due to the added thunks.
+ bool AddressesChanged = false;
+ for (OutputSection *Sec : OutputSections)
+ AddressesChanged |= createThunks(Sec, Margin);
+ // If the verification above thought we needed thunks, we should have
+ // added some.
+ assert(AddressesChanged);
+
+ // Recalculate the layout for the whole image (and verify the ranges at
+ // the start of the next round).
+ assignAddresses();
+
+ Pass++;
+ }
+}
+
+// The main function of the writer.
+void Writer::run() {
+ ScopedTimer T1(CodeLayoutTimer);
+
+ createImportTables();
+ createSections();
+ createMiscChunks();
+ appendImportThunks();
+ createExportTable();
+ mergeSections();
+ readRelocTargets();
+ removeUnusedSections();
+ finalizeAddresses();
+ removeEmptySections();
+ setSectionPermissions();
+ createSymbolAndStringTable();
+
+ if (FileSize > UINT32_MAX)
+ fatal("image size (" + Twine(FileSize) + ") " +
+ "exceeds maximum allowable size (" + Twine(UINT32_MAX) + ")");
+
+ openFile(Config->OutputFile);
+ if (Config->is64()) {
+ writeHeader<pe32plus_header>();
+ } else {
+ writeHeader<pe32_header>();
+ }
+ writeSections();
+ sortExceptionTable();
+
+ T1.stop();
+
+ if (!Config->PDBPath.empty() && Config->Debug) {
+ assert(BuildId);
+ createPDB(Symtab, OutputSections, SectionTable, BuildId->BuildId);
+ }
+ writeBuildId();
+
+ writeMapFile(OutputSections);
+
+ ScopedTimer T2(DiskCommitTimer);
+ if (auto E = Buffer->commit())
+ fatal("failed to write the output file: " + toString(std::move(E)));
+}
+
+static StringRef getOutputSectionName(StringRef Name) {
+ StringRef S = Name.split('$').first;
+
+ // Treat a later period as a separator for MinGW, for sections like
+ // ".ctors.01234".
+ return S.substr(0, S.find('.', 1));
+}
+
+// For /order.
+static void sortBySectionOrder(std::vector<Chunk *> &Chunks) {
+ auto GetPriority = [](const Chunk *C) {
+ if (auto *Sec = dyn_cast<SectionChunk>(C))
+ if (Sec->Sym)
+ return Config->Order.lookup(Sec->Sym->getName());
+ return 0;
+ };
+
+ std::stable_sort(Chunks.begin(), Chunks.end(),
+ [=](const Chunk *A, const Chunk *B) {
+ return GetPriority(A) < GetPriority(B);
+ });
+}
+
+// Sort concrete section chunks from GNU import libraries.
+//
+// GNU binutils doesn't use short import files, but instead produces import
+// libraries that consist of object files, with section chunks for the .idata$*
+// sections. These are linked just as regular static libraries. Each import
+// library consists of one header object, one object file for every imported
+// symbol, and one trailer object. In order for the .idata tables/lists to
+// be formed correctly, the section chunks within each .idata$* section need
+// to be grouped by library, and sorted alphabetically within each library
+// (which makes sure the header comes first and the trailer last).
+static bool fixGnuImportChunks(
+ std::map<std::pair<StringRef, uint32_t>, std::vector<Chunk *>> &Map) {
+ uint32_t RDATA = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
+
+ // Make sure all .idata$* section chunks are mapped as RDATA in order to
+ // be sorted into the same sections as our own synthesized .idata chunks.
+ for (auto &Pair : Map) {
+ StringRef SectionName = Pair.first.first;
+ uint32_t OutChars = Pair.first.second;
+ if (!SectionName.startswith(".idata"))
+ continue;
+ if (OutChars == RDATA)
+ continue;
+ std::vector<Chunk *> &SrcVect = Pair.second;
+ std::vector<Chunk *> &DestVect = Map[{SectionName, RDATA}];
+ DestVect.insert(DestVect.end(), SrcVect.begin(), SrcVect.end());
+ SrcVect.clear();
+ }
+
+ bool HasIdata = false;
+ // Sort all .idata$* chunks, grouping chunks from the same library,
+ // with alphabetical ordering of the object fils within a library.
+ for (auto &Pair : Map) {
+ StringRef SectionName = Pair.first.first;
+ if (!SectionName.startswith(".idata"))
+ continue;
+
+ std::vector<Chunk *> &Chunks = Pair.second;
+ if (!Chunks.empty())
+ HasIdata = true;
+ std::stable_sort(Chunks.begin(), Chunks.end(), [&](Chunk *S, Chunk *T) {
+ SectionChunk *SC1 = dyn_cast_or_null<SectionChunk>(S);
+ SectionChunk *SC2 = dyn_cast_or_null<SectionChunk>(T);
+ if (!SC1 || !SC2) {
+ // if SC1, order them ascending. If SC2 or both null,
+ // S is not less than T.
+ return SC1 != nullptr;
+ }
+ // Make a string with "libraryname/objectfile" for sorting, achieving
+ // both grouping by library and sorting of objects within a library,
+ // at once.
+ std::string Key1 =
+ (SC1->File->ParentName + "/" + SC1->File->getName()).str();
+ std::string Key2 =
+ (SC2->File->ParentName + "/" + SC2->File->getName()).str();
+ return Key1 < Key2;
+ });
+ }
+ return HasIdata;
+}
+
+// Add generated idata chunks, for imported symbols and DLLs, and a
+// terminator in .idata$2.
+static void addSyntheticIdata(
+ IdataContents &Idata,
+ std::map<std::pair<StringRef, uint32_t>, std::vector<Chunk *>> &Map) {
+ uint32_t RDATA = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
+ Idata.create();
+
+ // Add the .idata content in the right section groups, to allow
+ // chunks from other linked in object files to be grouped together.
+ // See Microsoft PE/COFF spec 5.4 for details.
+ auto Add = [&](StringRef N, std::vector<Chunk *> &V) {
+ std::vector<Chunk *> &DestVect = Map[{N, RDATA}];
+ DestVect.insert(DestVect.end(), V.begin(), V.end());
+ };
+
+ // The loader assumes a specific order of data.
+ // Add each type in the correct order.
+ Add(".idata$2", Idata.Dirs);
+ Add(".idata$4", Idata.Lookups);
+ Add(".idata$5", Idata.Addresses);
+ Add(".idata$6", Idata.Hints);
+ Add(".idata$7", Idata.DLLNames);
+}
+
+// Locate the first Chunk and size of the import directory list and the
+// IAT.
+void Writer::locateImportTables(
+ std::map<std::pair<StringRef, uint32_t>, std::vector<Chunk *>> &Map) {
+ uint32_t RDATA = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
+ std::vector<Chunk *> &ImportTables = Map[{".idata$2", RDATA}];
+ if (!ImportTables.empty())
+ ImportTableStart = ImportTables.front();
+ for (Chunk *C : ImportTables)
+ ImportTableSize += C->getSize();
+
+ std::vector<Chunk *> &IAT = Map[{".idata$5", RDATA}];
+ if (!IAT.empty())
+ IATStart = IAT.front();
+ for (Chunk *C : IAT)
+ IATSize += C->getSize();
+}
+
+// Create output section objects and add them to OutputSections.
+void Writer::createSections() {
+ // First, create the builtin sections.
+ const uint32_t DATA = IMAGE_SCN_CNT_INITIALIZED_DATA;
+ const uint32_t BSS = IMAGE_SCN_CNT_UNINITIALIZED_DATA;
+ const uint32_t CODE = IMAGE_SCN_CNT_CODE;
+ const uint32_t DISCARDABLE = IMAGE_SCN_MEM_DISCARDABLE;
+ const uint32_t R = IMAGE_SCN_MEM_READ;
+ const uint32_t W = IMAGE_SCN_MEM_WRITE;
+ const uint32_t X = IMAGE_SCN_MEM_EXECUTE;
+
+ SmallDenseMap<std::pair<StringRef, uint32_t>, OutputSection *> Sections;
+ auto CreateSection = [&](StringRef Name, uint32_t OutChars) {
+ OutputSection *&Sec = Sections[{Name, OutChars}];
+ if (!Sec) {
+ Sec = make<OutputSection>(Name, OutChars);
+ OutputSections.push_back(Sec);
+ }
+ return Sec;
+ };
+
+ // Try to match the section order used by link.exe.
+ TextSec = CreateSection(".text", CODE | R | X);
+ CreateSection(".bss", BSS | R | W);
+ RdataSec = CreateSection(".rdata", DATA | R);
+ BuildidSec = CreateSection(".buildid", DATA | R);
+ DataSec = CreateSection(".data", DATA | R | W);
+ PdataSec = CreateSection(".pdata", DATA | R);
+ IdataSec = CreateSection(".idata", DATA | R);
+ EdataSec = CreateSection(".edata", DATA | R);
+ DidatSec = CreateSection(".didat", DATA | R);
+ RsrcSec = CreateSection(".rsrc", DATA | R);
+ RelocSec = CreateSection(".reloc", DATA | DISCARDABLE | R);
+ CtorsSec = CreateSection(".ctors", DATA | R | W);
+ DtorsSec = CreateSection(".dtors", DATA | R | W);
+
+ // Then bin chunks by name and output characteristics.
+ std::map<std::pair<StringRef, uint32_t>, std::vector<Chunk *>> Map;
+ for (Chunk *C : Symtab->getChunks()) {
+ auto *SC = dyn_cast<SectionChunk>(C);
+ if (SC && !SC->Live) {
+ if (Config->Verbose)
+ SC->printDiscardedMessage();
+ continue;
+ }
+ Map[{C->getSectionName(), C->getOutputCharacteristics()}].push_back(C);
+ }
+
+ // Even in non MinGW cases, we might need to link against GNU import
+ // libraries.
+ bool HasIdata = fixGnuImportChunks(Map);
+ if (!Idata.empty())
+ HasIdata = true;
+
+ if (HasIdata)
+ addSyntheticIdata(Idata, Map);
+
+ // Process an /order option.
+ if (!Config->Order.empty())
+ for (auto &Pair : Map)
+ sortBySectionOrder(Pair.second);
+
+ if (HasIdata)
+ locateImportTables(Map);
+
+ // Then create an OutputSection for each section.
+ // '$' and all following characters in input section names are
+ // discarded when determining output section. So, .text$foo
+ // contributes to .text, for example. See PE/COFF spec 3.2.
+ for (auto &Pair : Map) {
+ StringRef Name = getOutputSectionName(Pair.first.first);
+ uint32_t OutChars = Pair.first.second;
+
+ if (Name == ".CRT") {
+ // In link.exe, there is a special case for the I386 target where .CRT
+ // sections are treated as if they have output characteristics DATA | R if
+ // their characteristics are DATA | R | W. This implements the same
+ // special case for all architectures.
+ OutChars = DATA | R;
+
+ log("Processing section " + Pair.first.first + " -> " + Name);
+
+ sortCRTSectionChunks(Pair.second);
+ }
+
+ OutputSection *Sec = CreateSection(Name, OutChars);
+ std::vector<Chunk *> &Chunks = Pair.second;
+ for (Chunk *C : Chunks)
+ Sec->addChunk(C);
+ }
+
+ // Finally, move some output sections to the end.
+ auto SectionOrder = [&](OutputSection *S) {
+ // Move DISCARDABLE (or non-memory-mapped) sections to the end of file because
+ // the loader cannot handle holes. Stripping can remove other discardable ones
+ // than .reloc, which is first of them (created early).
+ if (S->Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE)
+ return 2;
+ // .rsrc should come at the end of the non-discardable sections because its
+ // size may change by the Win32 UpdateResources() function, causing
+ // subsequent sections to move (see https://crbug.com/827082).
+ if (S == RsrcSec)
+ return 1;
+ return 0;
+ };
+ std::stable_sort(OutputSections.begin(), OutputSections.end(),
+ [&](OutputSection *S, OutputSection *T) {
+ return SectionOrder(S) < SectionOrder(T);
+ });
+}
+
+void Writer::createMiscChunks() {
+ for (auto &P : MergeChunk::Instances)
+ RdataSec->addChunk(P.second);
+
+ // Create thunks for locally-dllimported symbols.
+ if (!Symtab->LocalImportChunks.empty()) {
+ for (Chunk *C : Symtab->LocalImportChunks)
+ RdataSec->addChunk(C);
+ }
+
+ // Create Debug Information Chunks
+ OutputSection *DebugInfoSec = Config->MinGW ? BuildidSec : RdataSec;
+ if (Config->Debug || Config->Repro) {
+ DebugDirectory = make<DebugDirectoryChunk>(DebugRecords, Config->Repro);
+ DebugInfoSec->addChunk(DebugDirectory);
+ }
+
+ if (Config->Debug) {
+ // Make a CVDebugRecordChunk even when /DEBUG:CV is not specified. We
+ // output a PDB no matter what, and this chunk provides the only means of
+ // allowing a debugger to match a PDB and an executable. So we need it even
+ // if we're ultimately not going to write CodeView data to the PDB.
+ BuildId = make<CVDebugRecordChunk>();
+ DebugRecords.push_back(BuildId);
+
+ for (Chunk *C : DebugRecords)
+ DebugInfoSec->addChunk(C);
+ }
+
+ // Create SEH table. x86-only.
+ if (Config->Machine == I386)
+ createSEHTable();
+
+ // Create /guard:cf tables if requested.
+ if (Config->GuardCF != GuardCFLevel::Off)
+ createGuardCFTables();
+
+ if (Config->MinGW) {
+ createRuntimePseudoRelocs();
+
+ insertCtorDtorSymbols();
+ }
+}
+
+// Create .idata section for the DLL-imported symbol table.
+// The format of this section is inherently Windows-specific.
+// IdataContents class abstracted away the details for us,
+// so we just let it create chunks and add them to the section.
+void Writer::createImportTables() {
+ // Initialize DLLOrder so that import entries are ordered in
+ // the same order as in the command line. (That affects DLL
+ // initialization order, and this ordering is MSVC-compatible.)
+ for (ImportFile *File : ImportFile::Instances) {
+ if (!File->Live)
+ continue;
+
+ std::string DLL = StringRef(File->DLLName).lower();
+ if (Config->DLLOrder.count(DLL) == 0)
+ Config->DLLOrder[DLL] = Config->DLLOrder.size();
+
+ if (File->ImpSym && !isa<DefinedImportData>(File->ImpSym))
+ fatal(toString(*File->ImpSym) + " was replaced");
+ DefinedImportData *ImpSym = cast_or_null<DefinedImportData>(File->ImpSym);
+ if (Config->DelayLoads.count(StringRef(File->DLLName).lower())) {
+ if (!File->ThunkSym)
+ fatal("cannot delay-load " + toString(File) +
+ " due to import of data: " + toString(*ImpSym));
+ DelayIdata.add(ImpSym);
+ } else {
+ Idata.add(ImpSym);
+ }
+ }
+}
+
+void Writer::appendImportThunks() {
+ if (ImportFile::Instances.empty())
+ return;
+
+ for (ImportFile *File : ImportFile::Instances) {
+ if (!File->Live)
+ continue;
+
+ if (!File->ThunkSym)
+ continue;
+
+ if (!isa<DefinedImportThunk>(File->ThunkSym))
+ fatal(toString(*File->ThunkSym) + " was replaced");
+ DefinedImportThunk *Thunk = cast<DefinedImportThunk>(File->ThunkSym);
+ if (File->ThunkLive)
+ TextSec->addChunk(Thunk->getChunk());
+ }
+
+ if (!DelayIdata.empty()) {
+ Defined *Helper = cast<Defined>(Config->DelayLoadHelper);
+ DelayIdata.create(Helper);
+ for (Chunk *C : DelayIdata.getChunks())
+ DidatSec->addChunk(C);
+ for (Chunk *C : DelayIdata.getDataChunks())
+ DataSec->addChunk(C);
+ for (Chunk *C : DelayIdata.getCodeChunks())
+ TextSec->addChunk(C);
+ }
+}
+
+void Writer::createExportTable() {
+ if (Config->Exports.empty())
+ return;
+ for (Chunk *C : Edata.Chunks)
+ EdataSec->addChunk(C);
+}
+
+void Writer::removeUnusedSections() {
+ // Remove sections that we can be sure won't get content, to avoid
+ // allocating space for their section headers.
+ auto IsUnused = [this](OutputSection *S) {
+ if (S == RelocSec)
+ return false; // This section is populated later.
+ // MergeChunks have zero size at this point, as their size is finalized
+ // later. Only remove sections that have no Chunks at all.
+ return S->Chunks.empty();
+ };
+ OutputSections.erase(
+ std::remove_if(OutputSections.begin(), OutputSections.end(), IsUnused),
+ OutputSections.end());
+}
+
+// The Windows loader doesn't seem to like empty sections,
+// so we remove them if any.
+void Writer::removeEmptySections() {
+ auto IsEmpty = [](OutputSection *S) { return S->getVirtualSize() == 0; };
+ OutputSections.erase(
+ std::remove_if(OutputSections.begin(), OutputSections.end(), IsEmpty),
+ OutputSections.end());
+ uint32_t Idx = 1;
+ for (OutputSection *Sec : OutputSections)
+ Sec->SectionIndex = Idx++;
+}
+
+size_t Writer::addEntryToStringTable(StringRef Str) {
+ assert(Str.size() > COFF::NameSize);
+ size_t OffsetOfEntry = Strtab.size() + 4; // +4 for the size field
+ Strtab.insert(Strtab.end(), Str.begin(), Str.end());
+ Strtab.push_back('\0');
+ return OffsetOfEntry;
+}
+
+Optional<coff_symbol16> Writer::createSymbol(Defined *Def) {
+ coff_symbol16 Sym;
+ switch (Def->kind()) {
+ case Symbol::DefinedAbsoluteKind:
+ Sym.Value = Def->getRVA();
+ Sym.SectionNumber = IMAGE_SYM_ABSOLUTE;
+ break;
+ case Symbol::DefinedSyntheticKind:
+ // Relative symbols are unrepresentable in a COFF symbol table.
+ return None;
+ default: {
+ // Don't write symbols that won't be written to the output to the symbol
+ // table.
+ Chunk *C = Def->getChunk();
+ if (!C)
+ return None;
+ OutputSection *OS = C->getOutputSection();
+ if (!OS)
+ return None;
+
+ Sym.Value = Def->getRVA() - OS->getRVA();
+ Sym.SectionNumber = OS->SectionIndex;
+ break;
+ }
+ }
+
+ StringRef Name = Def->getName();
+ if (Name.size() > COFF::NameSize) {
+ Sym.Name.Offset.Zeroes = 0;
+ Sym.Name.Offset.Offset = addEntryToStringTable(Name);
+ } else {
+ memset(Sym.Name.ShortName, 0, COFF::NameSize);
+ memcpy(Sym.Name.ShortName, Name.data(), Name.size());
+ }
+
+ if (auto *D = dyn_cast<DefinedCOFF>(Def)) {
+ COFFSymbolRef Ref = D->getCOFFSymbol();
+ Sym.Type = Ref.getType();
+ Sym.StorageClass = Ref.getStorageClass();
+ } else {
+ Sym.Type = IMAGE_SYM_TYPE_NULL;
+ Sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL;
+ }
+ Sym.NumberOfAuxSymbols = 0;
+ return Sym;
+}
+
+void Writer::createSymbolAndStringTable() {
+ // PE/COFF images are limited to 8 byte section names. Longer names can be
+ // supported by writing a non-standard string table, but this string table is
+ // not mapped at runtime and the long names will therefore be inaccessible.
+ // link.exe always truncates section names to 8 bytes, whereas binutils always
+ // preserves long section names via the string table. LLD adopts a hybrid
+ // solution where discardable sections have long names preserved and
+ // non-discardable sections have their names truncated, to ensure that any
+ // section which is mapped at runtime also has its name mapped at runtime.
+ for (OutputSection *Sec : OutputSections) {
+ if (Sec->Name.size() <= COFF::NameSize)
+ continue;
+ if ((Sec->Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0)
+ continue;
+ Sec->setStringTableOff(addEntryToStringTable(Sec->Name));
+ }
+
+ if (Config->DebugDwarf || Config->DebugSymtab) {
+ for (ObjFile *File : ObjFile::Instances) {
+ for (Symbol *B : File->getSymbols()) {
+ auto *D = dyn_cast_or_null<Defined>(B);
+ if (!D || D->WrittenToSymtab)
+ continue;
+ D->WrittenToSymtab = true;
+
+ if (Optional<coff_symbol16> Sym = createSymbol(D))
+ OutputSymtab.push_back(*Sym);
+ }
+ }
+ }
+
+ if (OutputSymtab.empty() && Strtab.empty())
+ return;
+
+ // We position the symbol table to be adjacent to the end of the last section.
+ uint64_t FileOff = FileSize;
+ PointerToSymbolTable = FileOff;
+ FileOff += OutputSymtab.size() * sizeof(coff_symbol16);
+ FileOff += 4 + Strtab.size();
+ FileSize = alignTo(FileOff, SectorSize);
+}
+
+void Writer::mergeSections() {
+ if (!PdataSec->Chunks.empty()) {
+ FirstPdata = PdataSec->Chunks.front();
+ LastPdata = PdataSec->Chunks.back();
+ }
+
+ for (auto &P : Config->Merge) {
+ StringRef ToName = P.second;
+ if (P.first == ToName)
+ continue;
+ StringSet<> Names;
+ while (1) {
+ if (!Names.insert(ToName).second)
+ fatal("/merge: cycle found for section '" + P.first + "'");
+ auto I = Config->Merge.find(ToName);
+ if (I == Config->Merge.end())
+ break;
+ ToName = I->second;
+ }
+ OutputSection *From = findSection(P.first);
+ OutputSection *To = findSection(ToName);
+ if (!From)
+ continue;
+ if (!To) {
+ From->Name = ToName;
+ continue;
+ }
+ To->merge(From);
+ }
+}
+
+// Visits all sections to initialize their relocation targets.
+void Writer::readRelocTargets() {
+ for (OutputSection *Sec : OutputSections)
+ for_each(parallel::par, Sec->Chunks.begin(), Sec->Chunks.end(),
+ [&](Chunk *C) { C->readRelocTargets(); });
+}
+
+// Visits all sections to assign incremental, non-overlapping RVAs and
+// file offsets.
+void Writer::assignAddresses() {
+ SizeOfHeaders = DOSStubSize + sizeof(PEMagic) + sizeof(coff_file_header) +
+ sizeof(data_directory) * NumberOfDataDirectory +
+ sizeof(coff_section) * OutputSections.size();
+ SizeOfHeaders +=
+ Config->is64() ? sizeof(pe32plus_header) : sizeof(pe32_header);
+ SizeOfHeaders = alignTo(SizeOfHeaders, SectorSize);
+ uint64_t RVA = PageSize; // The first page is kept unmapped.
+ FileSize = SizeOfHeaders;
+
+ for (OutputSection *Sec : OutputSections) {
+ if (Sec == RelocSec)
+ addBaserels();
+ uint64_t RawSize = 0, VirtualSize = 0;
+ Sec->Header.VirtualAddress = RVA;
+ for (Chunk *C : Sec->Chunks) {
+ VirtualSize = alignTo(VirtualSize, C->Alignment);
+ C->setRVA(RVA + VirtualSize);
+ C->OutputSectionOff = VirtualSize;
+ C->finalizeContents();
+ VirtualSize += C->getSize();
+ if (C->hasData())
+ RawSize = alignTo(VirtualSize, SectorSize);
+ }
+ if (VirtualSize > UINT32_MAX)
+ error("section larger than 4 GiB: " + Sec->Name);
+ Sec->Header.VirtualSize = VirtualSize;
+ Sec->Header.SizeOfRawData = RawSize;
+ if (RawSize != 0)
+ Sec->Header.PointerToRawData = FileSize;
+ RVA += alignTo(VirtualSize, PageSize);
+ FileSize += alignTo(RawSize, SectorSize);
+ }
+ SizeOfImage = alignTo(RVA, PageSize);
+}
+
+template <typename PEHeaderTy> void Writer::writeHeader() {
+ // Write DOS header. For backwards compatibility, the first part of a PE/COFF
+ // executable consists of an MS-DOS MZ executable. If the executable is run
+ // under DOS, that program gets run (usually to just print an error message).
+ // When run under Windows, the loader looks at AddressOfNewExeHeader and uses
+ // the PE header instead.
+ uint8_t *Buf = Buffer->getBufferStart();
+ auto *DOS = reinterpret_cast<dos_header *>(Buf);
+ Buf += sizeof(dos_header);
+ DOS->Magic[0] = 'M';
+ DOS->Magic[1] = 'Z';
+ DOS->UsedBytesInTheLastPage = DOSStubSize % 512;
+ DOS->FileSizeInPages = divideCeil(DOSStubSize, 512);
+ DOS->HeaderSizeInParagraphs = sizeof(dos_header) / 16;
+
+ DOS->AddressOfRelocationTable = sizeof(dos_header);
+ DOS->AddressOfNewExeHeader = DOSStubSize;
+
+ // Write DOS program.
+ memcpy(Buf, DOSProgram, sizeof(DOSProgram));
+ Buf += sizeof(DOSProgram);
+
+ // Write PE magic
+ memcpy(Buf, PEMagic, sizeof(PEMagic));
+ Buf += sizeof(PEMagic);
+
+ // Write COFF header
+ auto *COFF = reinterpret_cast<coff_file_header *>(Buf);
+ Buf += sizeof(*COFF);
+ COFF->Machine = Config->Machine;
+ COFF->NumberOfSections = OutputSections.size();
+ COFF->Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE;
+ if (Config->LargeAddressAware)
+ COFF->Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE;
+ if (!Config->is64())
+ COFF->Characteristics |= IMAGE_FILE_32BIT_MACHINE;
+ if (Config->DLL)
+ COFF->Characteristics |= IMAGE_FILE_DLL;
+ if (!Config->Relocatable)
+ COFF->Characteristics |= IMAGE_FILE_RELOCS_STRIPPED;
+ COFF->SizeOfOptionalHeader =
+ sizeof(PEHeaderTy) + sizeof(data_directory) * NumberOfDataDirectory;
+
+ // Write PE header
+ auto *PE = reinterpret_cast<PEHeaderTy *>(Buf);
+ Buf += sizeof(*PE);
+ PE->Magic = Config->is64() ? PE32Header::PE32_PLUS : PE32Header::PE32;
+
+ // If {Major,Minor}LinkerVersion is left at 0.0, then for some
+ // reason signing the resulting PE file with Authenticode produces a
+ // signature that fails to validate on Windows 7 (but is OK on 10).
+ // Set it to 14.0, which is what VS2015 outputs, and which avoids
+ // that problem.
+ PE->MajorLinkerVersion = 14;
+ PE->MinorLinkerVersion = 0;
+
+ PE->ImageBase = Config->ImageBase;
+ PE->SectionAlignment = PageSize;
+ PE->FileAlignment = SectorSize;
+ PE->MajorImageVersion = Config->MajorImageVersion;
+ PE->MinorImageVersion = Config->MinorImageVersion;
+ PE->MajorOperatingSystemVersion = Config->MajorOSVersion;
+ PE->MinorOperatingSystemVersion = Config->MinorOSVersion;
+ PE->MajorSubsystemVersion = Config->MajorOSVersion;
+ PE->MinorSubsystemVersion = Config->MinorOSVersion;
+ PE->Subsystem = Config->Subsystem;
+ PE->SizeOfImage = SizeOfImage;
+ PE->SizeOfHeaders = SizeOfHeaders;
+ if (!Config->NoEntry) {
+ Defined *Entry = cast<Defined>(Config->Entry);
+ PE->AddressOfEntryPoint = Entry->getRVA();
+ // Pointer to thumb code must have the LSB set, so adjust it.
+ if (Config->Machine == ARMNT)
+ PE->AddressOfEntryPoint |= 1;
+ }
+ PE->SizeOfStackReserve = Config->StackReserve;
+ PE->SizeOfStackCommit = Config->StackCommit;
+ PE->SizeOfHeapReserve = Config->HeapReserve;
+ PE->SizeOfHeapCommit = Config->HeapCommit;
+ if (Config->AppContainer)
+ PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_APPCONTAINER;
+ if (Config->DynamicBase)
+ PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE;
+ if (Config->HighEntropyVA)
+ PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA;
+ if (!Config->AllowBind)
+ PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_BIND;
+ if (Config->NxCompat)
+ PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NX_COMPAT;
+ if (!Config->AllowIsolation)
+ PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION;
+ if (Config->GuardCF != GuardCFLevel::Off)
+ PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_GUARD_CF;
+ if (Config->IntegrityCheck)
+ PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY;
+ if (SetNoSEHCharacteristic)
+ PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_SEH;
+ if (Config->TerminalServerAware)
+ PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE;
+ PE->NumberOfRvaAndSize = NumberOfDataDirectory;
+ if (TextSec->getVirtualSize()) {
+ PE->BaseOfCode = TextSec->getRVA();
+ PE->SizeOfCode = TextSec->getRawSize();
+ }
+ PE->SizeOfInitializedData = getSizeOfInitializedData();
+
+ // Write data directory
+ auto *Dir = reinterpret_cast<data_directory *>(Buf);
+ Buf += sizeof(*Dir) * NumberOfDataDirectory;
+ if (!Config->Exports.empty()) {
+ Dir[EXPORT_TABLE].RelativeVirtualAddress = Edata.getRVA();
+ Dir[EXPORT_TABLE].Size = Edata.getSize();
+ }
+ if (ImportTableStart) {
+ Dir[IMPORT_TABLE].RelativeVirtualAddress = ImportTableStart->getRVA();
+ Dir[IMPORT_TABLE].Size = ImportTableSize;
+ }
+ if (IATStart) {
+ Dir[IAT].RelativeVirtualAddress = IATStart->getRVA();
+ Dir[IAT].Size = IATSize;
+ }
+ if (RsrcSec->getVirtualSize()) {
+ Dir[RESOURCE_TABLE].RelativeVirtualAddress = RsrcSec->getRVA();
+ Dir[RESOURCE_TABLE].Size = RsrcSec->getVirtualSize();
+ }
+ if (FirstPdata) {
+ Dir[EXCEPTION_TABLE].RelativeVirtualAddress = FirstPdata->getRVA();
+ Dir[EXCEPTION_TABLE].Size =
+ LastPdata->getRVA() + LastPdata->getSize() - FirstPdata->getRVA();
+ }
+ if (RelocSec->getVirtualSize()) {
+ Dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = RelocSec->getRVA();
+ Dir[BASE_RELOCATION_TABLE].Size = RelocSec->getVirtualSize();
+ }
+ if (Symbol *Sym = Symtab->findUnderscore("_tls_used")) {
+ if (Defined *B = dyn_cast<Defined>(Sym)) {
+ Dir[TLS_TABLE].RelativeVirtualAddress = B->getRVA();
+ Dir[TLS_TABLE].Size = Config->is64()
+ ? sizeof(object::coff_tls_directory64)
+ : sizeof(object::coff_tls_directory32);
+ }
+ }
+ if (DebugDirectory) {
+ Dir[DEBUG_DIRECTORY].RelativeVirtualAddress = DebugDirectory->getRVA();
+ Dir[DEBUG_DIRECTORY].Size = DebugDirectory->getSize();
+ }
+ if (Symbol *Sym = Symtab->findUnderscore("_load_config_used")) {
+ if (auto *B = dyn_cast<DefinedRegular>(Sym)) {
+ SectionChunk *SC = B->getChunk();
+ assert(B->getRVA() >= SC->getRVA());
+ uint64_t OffsetInChunk = B->getRVA() - SC->getRVA();
+ if (!SC->hasData() || OffsetInChunk + 4 > SC->getSize())
+ fatal("_load_config_used is malformed");
+
+ ArrayRef<uint8_t> SecContents = SC->getContents();
+ uint32_t LoadConfigSize =
+ *reinterpret_cast<const ulittle32_t *>(&SecContents[OffsetInChunk]);
+ if (OffsetInChunk + LoadConfigSize > SC->getSize())
+ fatal("_load_config_used is too large");
+ Dir[LOAD_CONFIG_TABLE].RelativeVirtualAddress = B->getRVA();
+ Dir[LOAD_CONFIG_TABLE].Size = LoadConfigSize;
+ }
+ }
+ if (!DelayIdata.empty()) {
+ Dir[DELAY_IMPORT_DESCRIPTOR].RelativeVirtualAddress =
+ DelayIdata.getDirRVA();
+ Dir[DELAY_IMPORT_DESCRIPTOR].Size = DelayIdata.getDirSize();
+ }
+
+ // Write section table
+ for (OutputSection *Sec : OutputSections) {
+ Sec->writeHeaderTo(Buf);
+ Buf += sizeof(coff_section);
+ }
+ SectionTable = ArrayRef<uint8_t>(
+ Buf - OutputSections.size() * sizeof(coff_section), Buf);
+
+ if (OutputSymtab.empty() && Strtab.empty())
+ return;
+
+ COFF->PointerToSymbolTable = PointerToSymbolTable;
+ uint32_t NumberOfSymbols = OutputSymtab.size();
+ COFF->NumberOfSymbols = NumberOfSymbols;
+ auto *SymbolTable = reinterpret_cast<coff_symbol16 *>(
+ Buffer->getBufferStart() + COFF->PointerToSymbolTable);
+ for (size_t I = 0; I != NumberOfSymbols; ++I)
+ SymbolTable[I] = OutputSymtab[I];
+ // Create the string table, it follows immediately after the symbol table.
+ // The first 4 bytes is length including itself.
+ Buf = reinterpret_cast<uint8_t *>(&SymbolTable[NumberOfSymbols]);
+ write32le(Buf, Strtab.size() + 4);
+ if (!Strtab.empty())
+ memcpy(Buf + 4, Strtab.data(), Strtab.size());
+}
+
+void Writer::openFile(StringRef Path) {
+ Buffer = CHECK(
+ FileOutputBuffer::create(Path, FileSize, FileOutputBuffer::F_executable),
+ "failed to open " + Path);
+}
+
+void Writer::createSEHTable() {
+ // Set the no SEH characteristic on x86 binaries unless we find exception
+ // handlers.
+ SetNoSEHCharacteristic = true;
+
+ SymbolRVASet Handlers;
+ for (ObjFile *File : ObjFile::Instances) {
+ // FIXME: We should error here instead of earlier unless /safeseh:no was
+ // passed.
+ if (!File->hasSafeSEH())
+ return;
+
+ markSymbolsForRVATable(File, File->getSXDataChunks(), Handlers);
+ }
+
+ // Remove the "no SEH" characteristic if all object files were built with
+ // safeseh, we found some exception handlers, and there is a load config in
+ // the object.
+ SetNoSEHCharacteristic =
+ Handlers.empty() || !Symtab->findUnderscore("_load_config_used");
+
+ maybeAddRVATable(std::move(Handlers), "__safe_se_handler_table",
+ "__safe_se_handler_count");
+}
+
+// Add a symbol to an RVA set. Two symbols may have the same RVA, but an RVA set
+// cannot contain duplicates. Therefore, the set is uniqued by Chunk and the
+// symbol's offset into that Chunk.
+static void addSymbolToRVASet(SymbolRVASet &RVASet, Defined *S) {
+ Chunk *C = S->getChunk();
+ if (auto *SC = dyn_cast<SectionChunk>(C))
+ C = SC->Repl; // Look through ICF replacement.
+ uint32_t Off = S->getRVA() - (C ? C->getRVA() : 0);
+ RVASet.insert({C, Off});
+}
+
+// Given a symbol, add it to the GFIDs table if it is a live, defined, function
+// symbol in an executable section.
+static void maybeAddAddressTakenFunction(SymbolRVASet &AddressTakenSyms,
+ Symbol *S) {
+ auto *D = dyn_cast_or_null<DefinedCOFF>(S);
+
+ // Ignore undefined symbols and references to non-functions (e.g. globals and
+ // labels).
+ if (!D ||
+ D->getCOFFSymbol().getComplexType() != COFF::IMAGE_SYM_DTYPE_FUNCTION)
+ return;
+
+ // Mark the symbol as address taken if it's in an executable section.
+ Chunk *RefChunk = D->getChunk();
+ OutputSection *OS = RefChunk ? RefChunk->getOutputSection() : nullptr;
+ if (OS && OS->Header.Characteristics & IMAGE_SCN_MEM_EXECUTE)
+ addSymbolToRVASet(AddressTakenSyms, D);
+}
+
+// Visit all relocations from all section contributions of this object file and
+// mark the relocation target as address-taken.
+static void markSymbolsWithRelocations(ObjFile *File,
+ SymbolRVASet &UsedSymbols) {
+ for (Chunk *C : File->getChunks()) {
+ // We only care about live section chunks. Common chunks and other chunks
+ // don't generally contain relocations.
+ SectionChunk *SC = dyn_cast<SectionChunk>(C);
+ if (!SC || !SC->Live)
+ continue;
+
+ for (const coff_relocation &Reloc : SC->Relocs) {
+ if (Config->Machine == I386 && Reloc.Type == COFF::IMAGE_REL_I386_REL32)
+ // Ignore relative relocations on x86. On x86_64 they can't be ignored
+ // since they're also used to compute absolute addresses.
+ continue;
+
+ Symbol *Ref = SC->File->getSymbol(Reloc.SymbolTableIndex);
+ maybeAddAddressTakenFunction(UsedSymbols, Ref);
+ }
+ }
+}
+
+// Create the guard function id table. This is a table of RVAs of all
+// address-taken functions. It is sorted and uniqued, just like the safe SEH
+// table.
+void Writer::createGuardCFTables() {
+ SymbolRVASet AddressTakenSyms;
+ SymbolRVASet LongJmpTargets;
+ for (ObjFile *File : ObjFile::Instances) {
+ // If the object was compiled with /guard:cf, the address taken symbols
+ // are in .gfids$y sections, and the longjmp targets are in .gljmp$y
+ // sections. If the object was not compiled with /guard:cf, we assume there
+ // were no setjmp targets, and that all code symbols with relocations are
+ // possibly address-taken.
+ if (File->hasGuardCF()) {
+ markSymbolsForRVATable(File, File->getGuardFidChunks(), AddressTakenSyms);
+ markSymbolsForRVATable(File, File->getGuardLJmpChunks(), LongJmpTargets);
+ } else {
+ markSymbolsWithRelocations(File, AddressTakenSyms);
+ }
+ }
+
+ // Mark the image entry as address-taken.
+ if (Config->Entry)
+ maybeAddAddressTakenFunction(AddressTakenSyms, Config->Entry);
+
+ // Mark exported symbols in executable sections as address-taken.
+ for (Export &E : Config->Exports)
+ maybeAddAddressTakenFunction(AddressTakenSyms, E.Sym);
+
+ // Ensure sections referenced in the gfid table are 16-byte aligned.
+ for (const ChunkAndOffset &C : AddressTakenSyms)
+ if (C.InputChunk->Alignment < 16)
+ C.InputChunk->Alignment = 16;
+
+ maybeAddRVATable(std::move(AddressTakenSyms), "__guard_fids_table",
+ "__guard_fids_count");
+
+ // Add the longjmp target table unless the user told us not to.
+ if (Config->GuardCF == GuardCFLevel::Full)
+ maybeAddRVATable(std::move(LongJmpTargets), "__guard_longjmp_table",
+ "__guard_longjmp_count");
+
+ // Set __guard_flags, which will be used in the load config to indicate that
+ // /guard:cf was enabled.
+ uint32_t GuardFlags = uint32_t(coff_guard_flags::CFInstrumented) |
+ uint32_t(coff_guard_flags::HasFidTable);
+ if (Config->GuardCF == GuardCFLevel::Full)
+ GuardFlags |= uint32_t(coff_guard_flags::HasLongJmpTable);
+ Symbol *FlagSym = Symtab->findUnderscore("__guard_flags");
+ cast<DefinedAbsolute>(FlagSym)->setVA(GuardFlags);
+}
+
+// Take a list of input sections containing symbol table indices and add those
+// symbols to an RVA table. The challenge is that symbol RVAs are not known and
+// depend on the table size, so we can't directly build a set of integers.
+void Writer::markSymbolsForRVATable(ObjFile *File,
+ ArrayRef<SectionChunk *> SymIdxChunks,
+ SymbolRVASet &TableSymbols) {
+ for (SectionChunk *C : SymIdxChunks) {
+ // Skip sections discarded by linker GC. This comes up when a .gfids section
+ // is associated with something like a vtable and the vtable is discarded.
+ // In this case, the associated gfids section is discarded, and we don't
+ // mark the virtual member functions as address-taken by the vtable.
+ if (!C->Live)
+ continue;
+
+ // Validate that the contents look like symbol table indices.
+ ArrayRef<uint8_t> Data = C->getContents();
+ if (Data.size() % 4 != 0) {
+ warn("ignoring " + C->getSectionName() +
+ " symbol table index section in object " + toString(File));
+ continue;
+ }
+
+ // Read each symbol table index and check if that symbol was included in the
+ // final link. If so, add it to the table symbol set.
+ ArrayRef<ulittle32_t> SymIndices(
+ reinterpret_cast<const ulittle32_t *>(Data.data()), Data.size() / 4);
+ ArrayRef<Symbol *> ObjSymbols = File->getSymbols();
+ for (uint32_t SymIndex : SymIndices) {
+ if (SymIndex >= ObjSymbols.size()) {
+ warn("ignoring invalid symbol table index in section " +
+ C->getSectionName() + " in object " + toString(File));
+ continue;
+ }
+ if (Symbol *S = ObjSymbols[SymIndex]) {
+ if (S->isLive())
+ addSymbolToRVASet(TableSymbols, cast<Defined>(S));
+ }
+ }
+ }
+}
+
+// Replace the absolute table symbol with a synthetic symbol pointing to
+// TableChunk so that we can emit base relocations for it and resolve section
+// relative relocations.
+void Writer::maybeAddRVATable(SymbolRVASet TableSymbols, StringRef TableSym,
+ StringRef CountSym) {
+ if (TableSymbols.empty())
+ return;
+
+ RVATableChunk *TableChunk = make<RVATableChunk>(std::move(TableSymbols));
+ RdataSec->addChunk(TableChunk);
+
+ Symbol *T = Symtab->findUnderscore(TableSym);
+ Symbol *C = Symtab->findUnderscore(CountSym);
+ replaceSymbol<DefinedSynthetic>(T, T->getName(), TableChunk);
+ cast<DefinedAbsolute>(C)->setVA(TableChunk->getSize() / 4);
+}
+
+// MinGW specific. Gather all relocations that are imported from a DLL even
+// though the code didn't expect it to, produce the table that the runtime
+// uses for fixing them up, and provide the synthetic symbols that the
+// runtime uses for finding the table.
+void Writer::createRuntimePseudoRelocs() {
+ std::vector<RuntimePseudoReloc> Rels;
+
+ for (Chunk *C : Symtab->getChunks()) {
+ auto *SC = dyn_cast<SectionChunk>(C);
+ if (!SC || !SC->Live)
+ continue;
+ SC->getRuntimePseudoRelocs(Rels);
+ }
+
+ if (!Rels.empty())
+ log("Writing " + Twine(Rels.size()) + " runtime pseudo relocations");
+ PseudoRelocTableChunk *Table = make<PseudoRelocTableChunk>(Rels);
+ RdataSec->addChunk(Table);
+ EmptyChunk *EndOfList = make<EmptyChunk>();
+ RdataSec->addChunk(EndOfList);
+
+ Symbol *HeadSym = Symtab->findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST__");
+ Symbol *EndSym = Symtab->findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST_END__");
+ replaceSymbol<DefinedSynthetic>(HeadSym, HeadSym->getName(), Table);
+ replaceSymbol<DefinedSynthetic>(EndSym, EndSym->getName(), EndOfList);
+}
+
+// MinGW specific.
+// The MinGW .ctors and .dtors lists have sentinels at each end;
+// a (uintptr_t)-1 at the start and a (uintptr_t)0 at the end.
+// There's a symbol pointing to the start sentinel pointer, __CTOR_LIST__
+// and __DTOR_LIST__ respectively.
+void Writer::insertCtorDtorSymbols() {
+ AbsolutePointerChunk *CtorListHead = make<AbsolutePointerChunk>(-1);
+ AbsolutePointerChunk *CtorListEnd = make<AbsolutePointerChunk>(0);
+ AbsolutePointerChunk *DtorListHead = make<AbsolutePointerChunk>(-1);
+ AbsolutePointerChunk *DtorListEnd = make<AbsolutePointerChunk>(0);
+ CtorsSec->insertChunkAtStart(CtorListHead);
+ CtorsSec->addChunk(CtorListEnd);
+ DtorsSec->insertChunkAtStart(DtorListHead);
+ DtorsSec->addChunk(DtorListEnd);
+
+ Symbol *CtorListSym = Symtab->findUnderscore("__CTOR_LIST__");
+ Symbol *DtorListSym = Symtab->findUnderscore("__DTOR_LIST__");
+ replaceSymbol<DefinedSynthetic>(CtorListSym, CtorListSym->getName(),
+ CtorListHead);
+ replaceSymbol<DefinedSynthetic>(DtorListSym, DtorListSym->getName(),
+ DtorListHead);
+}
+
+// Handles /section options to allow users to overwrite
+// section attributes.
+void Writer::setSectionPermissions() {
+ for (auto &P : Config->Section) {
+ StringRef Name = P.first;
+ uint32_t Perm = P.second;
+ for (OutputSection *Sec : OutputSections)
+ if (Sec->Name == Name)
+ Sec->setPermissions(Perm);
+ }
+}
+
+// Write section contents to a mmap'ed file.
+void Writer::writeSections() {
+ // Record the number of sections to apply section index relocations
+ // against absolute symbols. See applySecIdx in Chunks.cpp..
+ DefinedAbsolute::NumOutputSections = OutputSections.size();
+
+ uint8_t *Buf = Buffer->getBufferStart();
+ for (OutputSection *Sec : OutputSections) {
+ uint8_t *SecBuf = Buf + Sec->getFileOff();
+ // Fill gaps between functions in .text with INT3 instructions
+ // instead of leaving as NUL bytes (which can be interpreted as
+ // ADD instructions).
+ if (Sec->Header.Characteristics & IMAGE_SCN_CNT_CODE)
+ memset(SecBuf, 0xCC, Sec->getRawSize());
+ for_each(parallel::par, Sec->Chunks.begin(), Sec->Chunks.end(),
+ [&](Chunk *C) { C->writeTo(SecBuf); });
+ }
+}
+
+void Writer::writeBuildId() {
+ // There are two important parts to the build ID.
+ // 1) If building with debug info, the COFF debug directory contains a
+ // timestamp as well as a Guid and Age of the PDB.
+ // 2) In all cases, the PE COFF file header also contains a timestamp.
+ // For reproducibility, instead of a timestamp we want to use a hash of the
+ // PE contents.
+ if (Config->Debug) {
+ assert(BuildId && "BuildId is not set!");
+ // BuildId->BuildId was filled in when the PDB was written.
+ }
+
+ // At this point the only fields in the COFF file which remain unset are the
+ // "timestamp" in the COFF file header, and the ones in the coff debug
+ // directory. Now we can hash the file and write that hash to the various
+ // timestamp fields in the file.
+ StringRef OutputFileData(
+ reinterpret_cast<const char *>(Buffer->getBufferStart()),
+ Buffer->getBufferSize());
+
+ uint32_t Timestamp = Config->Timestamp;
+ uint64_t Hash = 0;
+ bool GenerateSyntheticBuildId =
+ Config->MinGW && Config->Debug && Config->PDBPath.empty();
+
+ if (Config->Repro || GenerateSyntheticBuildId)
+ Hash = xxHash64(OutputFileData);
+
+ if (Config->Repro)
+ Timestamp = static_cast<uint32_t>(Hash);
+
+ if (GenerateSyntheticBuildId) {
+ // For MinGW builds without a PDB file, we still generate a build id
+ // to allow associating a crash dump to the executable.
+ BuildId->BuildId->PDB70.CVSignature = OMF::Signature::PDB70;
+ BuildId->BuildId->PDB70.Age = 1;
+ memcpy(BuildId->BuildId->PDB70.Signature, &Hash, 8);
+ // xxhash only gives us 8 bytes, so put some fixed data in the other half.
+ memcpy(&BuildId->BuildId->PDB70.Signature[8], "LLD PDB.", 8);
+ }
+
+ if (DebugDirectory)
+ DebugDirectory->setTimeDateStamp(Timestamp);
+
+ uint8_t *Buf = Buffer->getBufferStart();
+ Buf += DOSStubSize + sizeof(PEMagic);
+ object::coff_file_header *CoffHeader =
+ reinterpret_cast<coff_file_header *>(Buf);
+ CoffHeader->TimeDateStamp = Timestamp;
+}
+
+// Sort .pdata section contents according to PE/COFF spec 5.5.
+void Writer::sortExceptionTable() {
+ if (!FirstPdata)
+ return;
+ // We assume .pdata contains function table entries only.
+ auto BufAddr = [&](Chunk *C) {
+ return Buffer->getBufferStart() + C->getOutputSection()->getFileOff() +
+ C->getRVA() - C->getOutputSection()->getRVA();
+ };
+ uint8_t *Begin = BufAddr(FirstPdata);
+ uint8_t *End = BufAddr(LastPdata) + LastPdata->getSize();
+ if (Config->Machine == AMD64) {
+ struct Entry { ulittle32_t Begin, End, Unwind; };
+ sort(parallel::par, (Entry *)Begin, (Entry *)End,
+ [](const Entry &A, const Entry &B) { return A.Begin < B.Begin; });
+ return;
+ }
+ if (Config->Machine == ARMNT || Config->Machine == ARM64) {
+ struct Entry { ulittle32_t Begin, Unwind; };
+ sort(parallel::par, (Entry *)Begin, (Entry *)End,
+ [](const Entry &A, const Entry &B) { return A.Begin < B.Begin; });
+ return;
+ }
+ errs() << "warning: don't know how to handle .pdata.\n";
+}
+
+// The CRT section contains, among other things, the array of function
+// pointers that initialize every global variable that is not trivially
+// constructed. The CRT calls them one after the other prior to invoking
+// main().
+//
+// As per C++ spec, 3.6.2/2.3,
+// "Variables with ordered initialization defined within a single
+// translation unit shall be initialized in the order of their definitions
+// in the translation unit"
+//
+// It is therefore critical to sort the chunks containing the function
+// pointers in the order that they are listed in the object file (top to
+// bottom), otherwise global objects might not be initialized in the
+// correct order.
+void Writer::sortCRTSectionChunks(std::vector<Chunk *> &Chunks) {
+ auto SectionChunkOrder = [](const Chunk *A, const Chunk *B) {
+ auto SA = dyn_cast<SectionChunk>(A);
+ auto SB = dyn_cast<SectionChunk>(B);
+ assert(SA && SB && "Non-section chunks in CRT section!");
+
+ StringRef SAObj = SA->File->MB.getBufferIdentifier();
+ StringRef SBObj = SB->File->MB.getBufferIdentifier();
+
+ return SAObj == SBObj && SA->getSectionNumber() < SB->getSectionNumber();
+ };
+ std::stable_sort(Chunks.begin(), Chunks.end(), SectionChunkOrder);
+
+ if (Config->Verbose) {
+ for (auto &C : Chunks) {
+ auto SC = dyn_cast<SectionChunk>(C);
+ log(" " + SC->File->MB.getBufferIdentifier().str() +
+ ", SectionID: " + Twine(SC->getSectionNumber()));
+ }
+ }
+}
+
+OutputSection *Writer::findSection(StringRef Name) {
+ for (OutputSection *Sec : OutputSections)
+ if (Sec->Name == Name)
+ return Sec;
+ return nullptr;
+}
+
+uint32_t Writer::getSizeOfInitializedData() {
+ uint32_t Res = 0;
+ for (OutputSection *S : OutputSections)
+ if (S->Header.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
+ Res += S->getRawSize();
+ return Res;
+}
+
+// Add base relocations to .reloc section.
+void Writer::addBaserels() {
+ if (!Config->Relocatable)
+ return;
+ RelocSec->Chunks.clear();
+ std::vector<Baserel> V;
+ for (OutputSection *Sec : OutputSections) {
+ if (Sec->Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE)
+ continue;
+ // Collect all locations for base relocations.
+ for (Chunk *C : Sec->Chunks)
+ C->getBaserels(&V);
+ // Add the addresses to .reloc section.
+ if (!V.empty())
+ addBaserelBlocks(V);
+ V.clear();
+ }
+}
+
+// Add addresses to .reloc section. Note that addresses are grouped by page.
+void Writer::addBaserelBlocks(std::vector<Baserel> &V) {
+ const uint32_t Mask = ~uint32_t(PageSize - 1);
+ uint32_t Page = V[0].RVA & Mask;
+ size_t I = 0, J = 1;
+ for (size_t E = V.size(); J < E; ++J) {
+ uint32_t P = V[J].RVA & Mask;
+ if (P == Page)
+ continue;
+ RelocSec->addChunk(make<BaserelChunk>(Page, &V[I], &V[0] + J));
+ I = J;
+ Page = P;
+ }
+ if (I == J)
+ return;
+ RelocSec->addChunk(make<BaserelChunk>(Page, &V[I], &V[0] + J));
+}
diff --git a/contrib/llvm/tools/lld/COFF/Writer.h b/contrib/llvm/tools/lld/COFF/Writer.h
new file mode 100644
index 000000000000..727582480c91
--- /dev/null
+++ b/contrib/llvm/tools/lld/COFF/Writer.h
@@ -0,0 +1,75 @@
+//===- Writer.h -------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_WRITER_H
+#define LLD_COFF_WRITER_H
+
+#include "Chunks.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/COFF.h"
+#include <chrono>
+#include <cstdint>
+#include <vector>
+
+namespace lld {
+namespace coff {
+static const int PageSize = 4096;
+
+void writeResult();
+
+// OutputSection represents a section in an output file. It's a
+// container of chunks. OutputSection and Chunk are 1:N relationship.
+// Chunks cannot belong to more than one OutputSections. The writer
+// creates multiple OutputSections and assign them unique,
+// non-overlapping file offsets and RVAs.
+class OutputSection {
+public:
+ OutputSection(llvm::StringRef N, uint32_t Chars) : Name(N) {
+ Header.Characteristics = Chars;
+ }
+ void addChunk(Chunk *C);
+ void insertChunkAtStart(Chunk *C);
+ void merge(OutputSection *Other);
+ void addPermissions(uint32_t C);
+ void setPermissions(uint32_t C);
+ uint64_t getRVA() { return Header.VirtualAddress; }
+ uint64_t getFileOff() { return Header.PointerToRawData; }
+ void writeHeaderTo(uint8_t *Buf);
+
+ // Returns the size of this section in an executable memory image.
+ // This may be smaller than the raw size (the raw size is multiple
+ // of disk sector size, so there may be padding at end), or may be
+ // larger (if that's the case, the loader reserves spaces after end
+ // of raw data).
+ uint64_t getVirtualSize() { return Header.VirtualSize; }
+
+ // Returns the size of the section in the output file.
+ uint64_t getRawSize() { return Header.SizeOfRawData; }
+
+ // Set offset into the string table storing this section name.
+ // Used only when the name is longer than 8 bytes.
+ void setStringTableOff(uint32_t V) { StringTableOff = V; }
+
+ // N.B. The section index is one based.
+ uint32_t SectionIndex = 0;
+
+ llvm::StringRef Name;
+ llvm::object::coff_section Header = {};
+
+ std::vector<Chunk *> Chunks;
+ std::vector<Chunk *> OrigChunks;
+
+private:
+ uint32_t StringTableOff = 0;
+};
+
+}
+}
+
+#endif
diff --git a/contrib/llvm/tools/lld/Common/Args.cpp b/contrib/llvm/tools/lld/Common/Args.cpp
new file mode 100644
index 000000000000..3f0671d72a66
--- /dev/null
+++ b/contrib/llvm/tools/lld/Common/Args.cpp
@@ -0,0 +1,73 @@
+//===- Args.cpp -----------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Common/Args.h"
+#include "lld/Common/ErrorHandler.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/Path.h"
+
+using namespace llvm;
+using namespace lld;
+
+int lld::args::getInteger(opt::InputArgList &Args, unsigned Key, int Default) {
+ auto *A = Args.getLastArg(Key);
+ if (!A)
+ return Default;
+
+ int V;
+ if (to_integer(A->getValue(), V, 10))
+ return V;
+
+ StringRef Spelling = Args.getArgString(A->getIndex());
+ error(Spelling + ": number expected, but got '" + A->getValue() + "'");
+ return 0;
+}
+
+std::vector<StringRef> lld::args::getStrings(opt::InputArgList &Args, int Id) {
+ std::vector<StringRef> V;
+ for (auto *Arg : Args.filtered(Id))
+ V.push_back(Arg->getValue());
+ return V;
+}
+
+uint64_t lld::args::getZOptionValue(opt::InputArgList &Args, int Id,
+ StringRef Key, uint64_t Default) {
+ for (auto *Arg : Args.filtered_reverse(Id)) {
+ std::pair<StringRef, StringRef> KV = StringRef(Arg->getValue()).split('=');
+ if (KV.first == Key) {
+ uint64_t Result = Default;
+ if (!to_integer(KV.second, Result))
+ error("invalid " + Key + ": " + KV.second);
+ return Result;
+ }
+ }
+ return Default;
+}
+
+std::vector<StringRef> lld::args::getLines(MemoryBufferRef MB) {
+ SmallVector<StringRef, 0> Arr;
+ MB.getBuffer().split(Arr, '\n');
+
+ std::vector<StringRef> Ret;
+ for (StringRef S : Arr) {
+ S = S.trim();
+ if (!S.empty() && S[0] != '#')
+ Ret.push_back(S);
+ }
+ return Ret;
+}
+
+StringRef lld::args::getFilenameWithoutExe(StringRef Path) {
+ if (Path.endswith_lower(".exe"))
+ return sys::path::stem(Path);
+ return sys::path::filename(Path);
+}
diff --git a/contrib/llvm/tools/lld/Common/CMakeLists.txt b/contrib/llvm/tools/lld/Common/CMakeLists.txt
new file mode 100644
index 000000000000..a45fe209f06f
--- /dev/null
+++ b/contrib/llvm/tools/lld/Common/CMakeLists.txt
@@ -0,0 +1,33 @@
+if(NOT LLD_BUILT_STANDALONE)
+ set(tablegen_deps intrinsics_gen)
+endif()
+
+add_lld_library(lldCommon
+ Args.cpp
+ ErrorHandler.cpp
+ Memory.cpp
+ Reproduce.cpp
+ Strings.cpp
+ TargetOptionsCommandFlags.cpp
+ Threads.cpp
+ Timer.cpp
+ Version.cpp
+
+ ADDITIONAL_HEADER_DIRS
+ ${LLD_INCLUDE_DIR}/lld/Common
+
+ LINK_COMPONENTS
+ Codegen
+ Core
+ Demangle
+ MC
+ Option
+ Support
+ Target
+
+ LINK_LIBS
+ ${LLVM_PTHREAD_LIB}
+
+ DEPENDS
+ ${tablegen_deps}
+ )
diff --git a/contrib/llvm/tools/lld/Common/ErrorHandler.cpp b/contrib/llvm/tools/lld/Common/ErrorHandler.cpp
new file mode 100644
index 000000000000..c059516daf94
--- /dev/null
+++ b/contrib/llvm/tools/lld/Common/ErrorHandler.cpp
@@ -0,0 +1,144 @@
+//===- ErrorHandler.cpp ---------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Common/ErrorHandler.h"
+
+#include "lld/Common/Threads.h"
+
+#include "llvm/ADT/Twine.h"
+#include "llvm/IR/DiagnosticInfo.h"
+#include "llvm/IR/DiagnosticPrinter.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/raw_ostream.h"
+#include <mutex>
+
+#if !defined(_MSC_VER) && !defined(__MINGW32__)
+#include <unistd.h>
+#endif
+
+using namespace llvm;
+using namespace lld;
+
+// The functions defined in this file can be called from multiple threads,
+// but outs() or errs() are not thread-safe. We protect them using a mutex.
+static std::mutex Mu;
+
+// Prints "\n" or does nothing, depending on Msg contents of
+// the previous call of this function.
+static void newline(raw_ostream *ErrorOS, const Twine &Msg) {
+ // True if the previous error message contained "\n".
+ // We want to separate multi-line error messages with a newline.
+ static bool Flag;
+
+ if (Flag)
+ *ErrorOS << "\n";
+ Flag = StringRef(Msg.str()).contains('\n');
+}
+
+ErrorHandler &lld::errorHandler() {
+ static ErrorHandler Handler;
+ return Handler;
+}
+
+void lld::exitLld(int Val) {
+ // Delete any temporary file, while keeping the memory mapping open.
+ if (errorHandler().OutputBuffer)
+ errorHandler().OutputBuffer->discard();
+
+ // Dealloc/destroy ManagedStatic variables before calling
+ // _exit(). In a non-LTO build, this is a nop. In an LTO
+ // build allows us to get the output of -time-passes.
+ llvm_shutdown();
+
+ outs().flush();
+ errs().flush();
+ _exit(Val);
+}
+
+void lld::diagnosticHandler(const DiagnosticInfo &DI) {
+ SmallString<128> S;
+ raw_svector_ostream OS(S);
+ DiagnosticPrinterRawOStream DP(OS);
+ DI.print(DP);
+ switch (DI.getSeverity()) {
+ case DS_Error:
+ error(S);
+ break;
+ case DS_Warning:
+ warn(S);
+ break;
+ case DS_Remark:
+ case DS_Note:
+ message(S);
+ break;
+ }
+}
+
+void lld::checkError(Error E) {
+ handleAllErrors(std::move(E),
+ [&](ErrorInfoBase &EIB) { error(EIB.message()); });
+}
+
+void ErrorHandler::print(StringRef S, raw_ostream::Colors C) {
+ *ErrorOS << LogName << ": ";
+ if (ColorDiagnostics) {
+ ErrorOS->changeColor(C, true);
+ *ErrorOS << S;
+ ErrorOS->resetColor();
+ } else {
+ *ErrorOS << S;
+ }
+}
+
+void ErrorHandler::log(const Twine &Msg) {
+ if (Verbose) {
+ std::lock_guard<std::mutex> Lock(Mu);
+ *ErrorOS << LogName << ": " << Msg << "\n";
+ }
+}
+
+void ErrorHandler::message(const Twine &Msg) {
+ std::lock_guard<std::mutex> Lock(Mu);
+ outs() << Msg << "\n";
+ outs().flush();
+}
+
+void ErrorHandler::warn(const Twine &Msg) {
+ if (FatalWarnings) {
+ error(Msg);
+ return;
+ }
+
+ std::lock_guard<std::mutex> Lock(Mu);
+ newline(ErrorOS, Msg);
+ print("warning: ", raw_ostream::MAGENTA);
+ *ErrorOS << Msg << "\n";
+}
+
+void ErrorHandler::error(const Twine &Msg) {
+ std::lock_guard<std::mutex> Lock(Mu);
+ newline(ErrorOS, Msg);
+
+ if (ErrorLimit == 0 || ErrorCount < ErrorLimit) {
+ print("error: ", raw_ostream::RED);
+ *ErrorOS << Msg << "\n";
+ } else if (ErrorCount == ErrorLimit) {
+ print("error: ", raw_ostream::RED);
+ *ErrorOS << ErrorLimitExceededMsg << "\n";
+ if (ExitEarly)
+ exitLld(1);
+ }
+
+ ++ErrorCount;
+}
+
+void ErrorHandler::fatal(const Twine &Msg) {
+ error(Msg);
+ exitLld(1);
+}
diff --git a/contrib/llvm/tools/lld/Common/Memory.cpp b/contrib/llvm/tools/lld/Common/Memory.cpp
new file mode 100644
index 000000000000..efc5bcc2218b
--- /dev/null
+++ b/contrib/llvm/tools/lld/Common/Memory.cpp
@@ -0,0 +1,23 @@
+//===- Memory.cpp ---------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Common/Memory.h"
+
+using namespace llvm;
+using namespace lld;
+
+BumpPtrAllocator lld::BAlloc;
+StringSaver lld::Saver{BAlloc};
+std::vector<SpecificAllocBase *> lld::SpecificAllocBase::Instances;
+
+void lld::freeArena() {
+ for (SpecificAllocBase *Alloc : SpecificAllocBase::Instances)
+ Alloc->reset();
+ BAlloc.Reset();
+}
diff --git a/contrib/llvm/tools/lld/Common/Reproduce.cpp b/contrib/llvm/tools/lld/Common/Reproduce.cpp
new file mode 100644
index 000000000000..7be4ea6bb98b
--- /dev/null
+++ b/contrib/llvm/tools/lld/Common/Reproduce.cpp
@@ -0,0 +1,66 @@
+//===- Reproduce.cpp - Utilities for creating reproducers -----------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Common/Reproduce.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+
+using namespace lld;
+using namespace llvm;
+using namespace llvm::sys;
+
+// Makes a given pathname an absolute path first, and then remove
+// beginning /. For example, "../foo.o" is converted to "home/john/foo.o",
+// assuming that the current directory is "/home/john/bar".
+// Returned string is a forward slash separated path even on Windows to avoid
+// a mess with backslash-as-escape and backslash-as-path-separator.
+std::string lld::relativeToRoot(StringRef Path) {
+ SmallString<128> Abs = Path;
+ if (fs::make_absolute(Abs))
+ return Path;
+ path::remove_dots(Abs, /*remove_dot_dot=*/true);
+
+ // This is Windows specific. root_name() returns a drive letter
+ // (e.g. "c:") or a UNC name (//net). We want to keep it as part
+ // of the result.
+ SmallString<128> Res;
+ StringRef Root = path::root_name(Abs);
+ if (Root.endswith(":"))
+ Res = Root.drop_back();
+ else if (Root.startswith("//"))
+ Res = Root.substr(2);
+
+ path::append(Res, path::relative_path(Abs));
+ return path::convert_to_slash(Res);
+}
+
+// Quote a given string if it contains a space character.
+std::string lld::quote(StringRef S) {
+ if (S.contains(' '))
+ return ("\"" + S + "\"").str();
+ return S;
+}
+
+std::string lld::rewritePath(StringRef S) {
+ if (fs::exists(S))
+ return relativeToRoot(S);
+ return S;
+}
+
+std::string lld::toString(const opt::Arg &Arg) {
+ std::string K = Arg.getSpelling();
+ if (Arg.getNumValues() == 0)
+ return K;
+ std::string V = quote(Arg.getValue());
+ if (Arg.getOption().getRenderStyle() == opt::Option::RenderJoinedStyle)
+ return K + V;
+ return K + " " + V;
+}
diff --git a/contrib/llvm/tools/lld/Common/Strings.cpp b/contrib/llvm/tools/lld/Common/Strings.cpp
new file mode 100644
index 000000000000..6f74865b7f42
--- /dev/null
+++ b/contrib/llvm/tools/lld/Common/Strings.cpp
@@ -0,0 +1,104 @@
+//===- Strings.cpp -------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Common/Strings.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/LLVM.h"
+#include "llvm/Demangle/Demangle.h"
+#include "llvm/Support/GlobPattern.h"
+#include <algorithm>
+#include <mutex>
+#include <vector>
+
+using namespace llvm;
+using namespace lld;
+
+// Returns the demangled C++ symbol name for Name.
+Optional<std::string> lld::demangleItanium(StringRef Name) {
+ // itaniumDemangle can be used to demangle strings other than symbol
+ // names which do not necessarily start with "_Z". Name can be
+ // either a C or C++ symbol. Don't call itaniumDemangle if the name
+ // does not look like a C++ symbol name to avoid getting unexpected
+ // result for a C symbol that happens to match a mangled type name.
+ if (!Name.startswith("_Z"))
+ return None;
+
+ char *Buf = itaniumDemangle(Name.str().c_str(), nullptr, nullptr, nullptr);
+ if (!Buf)
+ return None;
+ std::string S(Buf);
+ free(Buf);
+ return S;
+}
+
+Optional<std::string> lld::demangleMSVC(StringRef Name) {
+ std::string Prefix;
+ if (Name.consume_front("__imp_"))
+ Prefix = "__declspec(dllimport) ";
+
+ // Demangle only C++ names.
+ if (!Name.startswith("?"))
+ return None;
+
+ char *Buf = microsoftDemangle(Name.str().c_str(), nullptr, nullptr, nullptr);
+ if (!Buf)
+ return None;
+ std::string S(Buf);
+ free(Buf);
+ return Prefix + S;
+}
+
+StringMatcher::StringMatcher(ArrayRef<StringRef> Pat) {
+ for (StringRef S : Pat) {
+ Expected<GlobPattern> Pat = GlobPattern::create(S);
+ if (!Pat)
+ error(toString(Pat.takeError()));
+ else
+ Patterns.push_back(*Pat);
+ }
+}
+
+bool StringMatcher::match(StringRef S) const {
+ for (const GlobPattern &Pat : Patterns)
+ if (Pat.match(S))
+ return true;
+ return false;
+}
+
+// Converts a hex string (e.g. "deadbeef") to a vector.
+std::vector<uint8_t> lld::parseHex(StringRef S) {
+ std::vector<uint8_t> Hex;
+ while (!S.empty()) {
+ StringRef B = S.substr(0, 2);
+ S = S.substr(2);
+ uint8_t H;
+ if (!to_integer(B, H, 16)) {
+ error("not a hexadecimal value: " + B);
+ return {};
+ }
+ Hex.push_back(H);
+ }
+ return Hex;
+}
+
+// Returns true if S is valid as a C language identifier.
+bool lld::isValidCIdentifier(StringRef S) {
+ return !S.empty() && (isAlpha(S[0]) || S[0] == '_') &&
+ std::all_of(S.begin() + 1, S.end(),
+ [](char C) { return C == '_' || isAlnum(C); });
+}
+
+// Write the contents of the a buffer to a file
+void lld::saveBuffer(StringRef Buffer, const Twine &Path) {
+ std::error_code EC;
+ raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::F_None);
+ if (EC)
+ error("cannot create " + Path + ": " + EC.message());
+ OS << Buffer;
+}
diff --git a/contrib/llvm/tools/lld/Common/TargetOptionsCommandFlags.cpp b/contrib/llvm/tools/lld/Common/TargetOptionsCommandFlags.cpp
new file mode 100644
index 000000000000..7a3fc510704f
--- /dev/null
+++ b/contrib/llvm/tools/lld/Common/TargetOptionsCommandFlags.cpp
@@ -0,0 +1,35 @@
+//===-- TargetOptionsCommandFlags.cpp ---------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file exists as a place for global variables defined in LLVM's
+// CodeGen/CommandFlags.inc. By putting the resulting object file in
+// an archive and linking with it, the definitions will automatically be
+// included when needed and skipped when already present.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Common/TargetOptionsCommandFlags.h"
+
+#include "llvm/CodeGen/CommandFlags.inc"
+#include "llvm/Target/TargetOptions.h"
+
+// Define an externally visible version of
+// InitTargetOptionsFromCodeGenFlags, so that its functionality can be
+// used without having to include llvm/CodeGen/CommandFlags.inc, which
+// would lead to multiple definitions of the command line flags.
+llvm::TargetOptions lld::InitTargetOptionsFromCodeGenFlags() {
+ return ::InitTargetOptionsFromCodeGenFlags();
+}
+
+llvm::Optional<llvm::CodeModel::Model> lld::GetCodeModelFromCMModel() {
+ return getCodeModel();
+}
+
+std::string lld::GetCPUStr() { return ::getCPUStr(); }
+std::vector<std::string> lld::GetMAttrs() { return ::MAttrs; }
diff --git a/contrib/llvm/tools/lld/Common/Threads.cpp b/contrib/llvm/tools/lld/Common/Threads.cpp
new file mode 100644
index 000000000000..c64b8c38b909
--- /dev/null
+++ b/contrib/llvm/tools/lld/Common/Threads.cpp
@@ -0,0 +1,12 @@
+//===- Threads.cpp --------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Common/Threads.h"
+
+bool lld::ThreadsEnabled = true;
diff --git a/contrib/llvm/tools/lld/Common/Timer.cpp b/contrib/llvm/tools/lld/Common/Timer.cpp
new file mode 100644
index 000000000000..89f9829b47cf
--- /dev/null
+++ b/contrib/llvm/tools/lld/Common/Timer.cpp
@@ -0,0 +1,80 @@
+//===- Timer.cpp ----------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Common/Timer.h"
+#include "lld/Common/ErrorHandler.h"
+#include "llvm/Support/Format.h"
+
+using namespace lld;
+using namespace llvm;
+
+ScopedTimer::ScopedTimer(Timer &T) : T(&T) { T.start(); }
+
+void ScopedTimer::stop() {
+ if (!T)
+ return;
+ T->stop();
+ T = nullptr;
+}
+
+ScopedTimer::~ScopedTimer() { stop(); }
+
+Timer::Timer(llvm::StringRef Name) : Name(Name), Parent(nullptr) {}
+Timer::Timer(llvm::StringRef Name, Timer &Parent)
+ : Name(Name), Parent(&Parent) {}
+
+void Timer::start() {
+ if (Parent && Total.count() == 0)
+ Parent->Children.push_back(this);
+ StartTime = std::chrono::high_resolution_clock::now();
+}
+
+void Timer::stop() {
+ Total += (std::chrono::high_resolution_clock::now() - StartTime);
+}
+
+Timer &Timer::root() {
+ static Timer RootTimer("Total Link Time");
+ return RootTimer;
+}
+
+void Timer::print() {
+ double TotalDuration = static_cast<double>(root().millis());
+
+ // We want to print the grand total under all the intermediate phases, so we
+ // print all children first, then print the total under that.
+ for (const auto &Child : Children)
+ Child->print(1, TotalDuration);
+
+ message(std::string(49, '-'));
+
+ root().print(0, root().millis(), false);
+}
+
+double Timer::millis() const {
+ return std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(
+ Total)
+ .count();
+}
+
+void Timer::print(int Depth, double TotalDuration, bool Recurse) const {
+ double P = 100.0 * millis() / TotalDuration;
+
+ SmallString<32> Str;
+ llvm::raw_svector_ostream Stream(Str);
+ std::string S = std::string(Depth * 2, ' ') + Name + std::string(":");
+ Stream << format("%-30s%5d ms (%5.1f%%)", S.c_str(), (int)millis(), P);
+
+ message(Str);
+
+ if (Recurse) {
+ for (const auto &Child : Children)
+ Child->print(Depth + 1, TotalDuration);
+ }
+}
diff --git a/contrib/llvm/tools/lld/Common/Version.cpp b/contrib/llvm/tools/lld/Common/Version.cpp
new file mode 100644
index 000000000000..6226c9a2fac6
--- /dev/null
+++ b/contrib/llvm/tools/lld/Common/Version.cpp
@@ -0,0 +1,43 @@
+//===- lib/Common/Version.cpp - LLD Version Number ---------------*- C++-=====//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines several version-related utility functions for LLD.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Common/Version.h"
+
+using namespace llvm;
+
+// Returns an SVN repository path, which is usually "trunk".
+static std::string getRepositoryPath() {
+ StringRef S = LLD_REPOSITORY_STRING;
+ size_t Pos = S.find("lld/");
+ if (Pos != StringRef::npos)
+ return S.substr(Pos + 4);
+ return S;
+}
+
+// Returns an SVN repository name, e.g., " (trunk 284614)"
+// or an empty string if no repository info is available.
+static std::string getRepository() {
+ std::string Repo = getRepositoryPath();
+ std::string Rev = LLD_REVISION_STRING;
+
+ if (Repo.empty() && Rev.empty())
+ return "";
+ if (!Repo.empty() && !Rev.empty())
+ return " (" + Repo + " " + Rev + ")";
+ return " (" + Repo + Rev + ")";
+}
+
+// Returns a version string, e.g., "LLD 4.0 (lld/trunk 284614)".
+std::string lld::getLLDVersion() {
+ return "LLD " + std::string(LLD_VERSION_STRING) + getRepository();
+}
diff --git a/contrib/llvm/tools/lld/ELF/AArch64ErrataFix.cpp b/contrib/llvm/tools/lld/ELF/AArch64ErrataFix.cpp
new file mode 100644
index 000000000000..ac753cb58265
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/AArch64ErrataFix.cpp
@@ -0,0 +1,652 @@
+//===- AArch64ErrataFix.cpp -----------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// This file implements Section Patching for the purpose of working around
+// errata in CPUs. The general principle is that an erratum sequence of one or
+// more instructions is detected in the instruction stream, one of the
+// instructions in the sequence is replaced with a branch to a patch sequence
+// of replacement instructions. At the end of the replacement sequence the
+// patch branches back to the instruction stream.
+
+// This technique is only suitable for fixing an erratum when:
+// - There is a set of necessary conditions required to trigger the erratum that
+// can be detected at static link time.
+// - There is a set of replacement instructions that can be used to remove at
+// least one of the necessary conditions that trigger the erratum.
+// - We can overwrite an instruction in the erratum sequence with a branch to
+// the replacement sequence.
+// - We can place the replacement sequence within range of the branch.
+
+// FIXME:
+// - The implementation here only supports one patch, the AArch64 Cortex-53
+// errata 843419 that affects r0p0, r0p1, r0p2 and r0p4 versions of the core.
+// To keep the initial version simple there is no support for multiple
+// architectures or selection of different patches.
+//===----------------------------------------------------------------------===//
+
+#include "AArch64ErrataFix.h"
+#include "Config.h"
+#include "LinkerScript.h"
+#include "OutputSections.h"
+#include "Relocations.h"
+#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "lld/Common/Memory.h"
+#include "lld/Common/Strings.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+
+using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::object;
+using namespace llvm::support;
+using namespace llvm::support::endian;
+
+using namespace lld;
+using namespace lld::elf;
+
+// Helper functions to identify instructions and conditions needed to trigger
+// the Cortex-A53-843419 erratum.
+
+// ADRP
+// | 1 | immlo (2) | 1 | 0 0 0 0 | immhi (19) | Rd (5) |
+static bool isADRP(uint32_t Instr) {
+ return (Instr & 0x9f000000) == 0x90000000;
+}
+
+// Load and store bit patterns from ARMv8-A ARM ARM.
+// Instructions appear in order of appearance starting from table in
+// C4.1.3 Loads and Stores.
+
+// All loads and stores have 1 (at bit postion 27), (0 at bit position 25).
+// | op0 x op1 (2) | 1 op2 0 op3 (2) | x | op4 (5) | xxxx | op5 (2) | x (10) |
+static bool isLoadStoreClass(uint32_t Instr) {
+ return (Instr & 0x0a000000) == 0x08000000;
+}
+
+// LDN/STN multiple no offset
+// | 0 Q 00 | 1100 | 0 L 00 | 0000 | opcode (4) | size (2) | Rn (5) | Rt (5) |
+// LDN/STN multiple post-indexed
+// | 0 Q 00 | 1100 | 1 L 0 | Rm (5)| opcode (4) | size (2) | Rn (5) | Rt (5) |
+// L == 0 for stores.
+
+// Utility routine to decode opcode field of LDN/STN multiple structure
+// instructions to find the ST1 instructions.
+// opcode == 0010 ST1 4 registers.
+// opcode == 0110 ST1 3 registers.
+// opcode == 0111 ST1 1 register.
+// opcode == 1010 ST1 2 registers.
+static bool isST1MultipleOpcode(uint32_t Instr) {
+ return (Instr & 0x0000f000) == 0x00002000 ||
+ (Instr & 0x0000f000) == 0x00006000 ||
+ (Instr & 0x0000f000) == 0x00007000 ||
+ (Instr & 0x0000f000) == 0x0000a000;
+}
+
+static bool isST1Multiple(uint32_t Instr) {
+ return (Instr & 0xbfff0000) == 0x0c000000 && isST1MultipleOpcode(Instr);
+}
+
+// Writes to Rn (writeback).
+static bool isST1MultiplePost(uint32_t Instr) {
+ return (Instr & 0xbfe00000) == 0x0c800000 && isST1MultipleOpcode(Instr);
+}
+
+// LDN/STN single no offset
+// | 0 Q 00 | 1101 | 0 L R 0 | 0000 | opc (3) S | size (2) | Rn (5) | Rt (5)|
+// LDN/STN single post-indexed
+// | 0 Q 00 | 1101 | 1 L R | Rm (5) | opc (3) S | size (2) | Rn (5) | Rt (5)|
+// L == 0 for stores
+
+// Utility routine to decode opcode field of LDN/STN single structure
+// instructions to find the ST1 instructions.
+// R == 0 for ST1 and ST3, R == 1 for ST2 and ST4.
+// opcode == 000 ST1 8-bit.
+// opcode == 010 ST1 16-bit.
+// opcode == 100 ST1 32 or 64-bit (Size determines which).
+static bool isST1SingleOpcode(uint32_t Instr) {
+ return (Instr & 0x0040e000) == 0x00000000 ||
+ (Instr & 0x0040e000) == 0x00004000 ||
+ (Instr & 0x0040e000) == 0x00008000;
+}
+
+static bool isST1Single(uint32_t Instr) {
+ return (Instr & 0xbfff0000) == 0x0d000000 && isST1SingleOpcode(Instr);
+}
+
+// Writes to Rn (writeback).
+static bool isST1SinglePost(uint32_t Instr) {
+ return (Instr & 0xbfe00000) == 0x0d800000 && isST1SingleOpcode(Instr);
+}
+
+static bool isST1(uint32_t Instr) {
+ return isST1Multiple(Instr) || isST1MultiplePost(Instr) ||
+ isST1Single(Instr) || isST1SinglePost(Instr);
+}
+
+// Load/store exclusive
+// | size (2) 00 | 1000 | o2 L o1 | Rs (5) | o0 | Rt2 (5) | Rn (5) | Rt (5) |
+// L == 0 for Stores.
+static bool isLoadStoreExclusive(uint32_t Instr) {
+ return (Instr & 0x3f000000) == 0x08000000;
+}
+
+static bool isLoadExclusive(uint32_t Instr) {
+ return (Instr & 0x3f400000) == 0x08400000;
+}
+
+// Load register literal
+// | opc (2) 01 | 1 V 00 | imm19 | Rt (5) |
+static bool isLoadLiteral(uint32_t Instr) {
+ return (Instr & 0x3b000000) == 0x18000000;
+}
+
+// Load/store no-allocate pair
+// (offset)
+// | opc (2) 10 | 1 V 00 | 0 L | imm7 | Rt2 (5) | Rn (5) | Rt (5) |
+// L == 0 for stores.
+// Never writes to register
+static bool isSTNP(uint32_t Instr) {
+ return (Instr & 0x3bc00000) == 0x28000000;
+}
+
+// Load/store register pair
+// (post-indexed)
+// | opc (2) 10 | 1 V 00 | 1 L | imm7 | Rt2 (5) | Rn (5) | Rt (5) |
+// L == 0 for stores, V == 0 for Scalar, V == 1 for Simd/FP
+// Writes to Rn.
+static bool isSTPPost(uint32_t Instr) {
+ return (Instr & 0x3bc00000) == 0x28800000;
+}
+
+// (offset)
+// | opc (2) 10 | 1 V 01 | 0 L | imm7 | Rt2 (5) | Rn (5) | Rt (5) |
+static bool isSTPOffset(uint32_t Instr) {
+ return (Instr & 0x3bc00000) == 0x29000000;
+}
+
+// (pre-index)
+// | opc (2) 10 | 1 V 01 | 1 L | imm7 | Rt2 (5) | Rn (5) | Rt (5) |
+// Writes to Rn.
+static bool isSTPPre(uint32_t Instr) {
+ return (Instr & 0x3bc00000) == 0x29800000;
+}
+
+static bool isSTP(uint32_t Instr) {
+ return isSTPPost(Instr) || isSTPOffset(Instr) || isSTPPre(Instr);
+}
+
+// Load/store register (unscaled immediate)
+// | size (2) 11 | 1 V 00 | opc (2) 0 | imm9 | 00 | Rn (5) | Rt (5) |
+// V == 0 for Scalar, V == 1 for Simd/FP.
+static bool isLoadStoreUnscaled(uint32_t Instr) {
+ return (Instr & 0x3b000c00) == 0x38000000;
+}
+
+// Load/store register (immediate post-indexed)
+// | size (2) 11 | 1 V 00 | opc (2) 0 | imm9 | 01 | Rn (5) | Rt (5) |
+static bool isLoadStoreImmediatePost(uint32_t Instr) {
+ return (Instr & 0x3b200c00) == 0x38000400;
+}
+
+// Load/store register (unprivileged)
+// | size (2) 11 | 1 V 00 | opc (2) 0 | imm9 | 10 | Rn (5) | Rt (5) |
+static bool isLoadStoreUnpriv(uint32_t Instr) {
+ return (Instr & 0x3b200c00) == 0x38000800;
+}
+
+// Load/store register (immediate pre-indexed)
+// | size (2) 11 | 1 V 00 | opc (2) 0 | imm9 | 11 | Rn (5) | Rt (5) |
+static bool isLoadStoreImmediatePre(uint32_t Instr) {
+ return (Instr & 0x3b200c00) == 0x38000c00;
+}
+
+// Load/store register (register offset)
+// | size (2) 11 | 1 V 00 | opc (2) 1 | Rm (5) | option (3) S | 10 | Rn | Rt |
+static bool isLoadStoreRegisterOff(uint32_t Instr) {
+ return (Instr & 0x3b200c00) == 0x38200800;
+}
+
+// Load/store register (unsigned immediate)
+// | size (2) 11 | 1 V 01 | opc (2) | imm12 | Rn (5) | Rt (5) |
+static bool isLoadStoreRegisterUnsigned(uint32_t Instr) {
+ return (Instr & 0x3b000000) == 0x39000000;
+}
+
+// Rt is always in bit position 0 - 4.
+static uint32_t getRt(uint32_t Instr) { return (Instr & 0x1f); }
+
+// Rn is always in bit position 5 - 9.
+static uint32_t getRn(uint32_t Instr) { return (Instr >> 5) & 0x1f; }
+
+// C4.1.2 Branches, Exception Generating and System instructions
+// | op0 (3) 1 | 01 op1 (4) | x (22) |
+// op0 == 010 101 op1 == 0xxx Conditional Branch.
+// op0 == 110 101 op1 == 1xxx Unconditional Branch Register.
+// op0 == x00 101 op1 == xxxx Unconditional Branch immediate.
+// op0 == x01 101 op1 == 0xxx Compare and branch immediate.
+// op0 == x01 101 op1 == 1xxx Test and branch immediate.
+static bool isBranch(uint32_t Instr) {
+ return ((Instr & 0xfe000000) == 0xd6000000) || // Cond branch.
+ ((Instr & 0xfe000000) == 0x54000000) || // Uncond branch reg.
+ ((Instr & 0x7c000000) == 0x14000000) || // Uncond branch imm.
+ ((Instr & 0x7c000000) == 0x34000000); // Compare and test branch.
+}
+
+static bool isV8SingleRegisterNonStructureLoadStore(uint32_t Instr) {
+ return isLoadStoreUnscaled(Instr) || isLoadStoreImmediatePost(Instr) ||
+ isLoadStoreUnpriv(Instr) || isLoadStoreImmediatePre(Instr) ||
+ isLoadStoreRegisterOff(Instr) || isLoadStoreRegisterUnsigned(Instr);
+}
+
+// Note that this function refers to v8.0 only and does not include the
+// additional load and store instructions added for in later revisions of
+// the architecture such as the Atomic memory operations introduced
+// in v8.1.
+static bool isV8NonStructureLoad(uint32_t Instr) {
+ if (isLoadExclusive(Instr))
+ return true;
+ if (isLoadLiteral(Instr))
+ return true;
+ else if (isV8SingleRegisterNonStructureLoadStore(Instr)) {
+ // For Load and Store single register, Loads are derived from a
+ // combination of the Size, V and Opc fields.
+ uint32_t Size = (Instr >> 30) & 0xff;
+ uint32_t V = (Instr >> 26) & 0x1;
+ uint32_t Opc = (Instr >> 22) & 0x3;
+ // For the load and store instructions that we are decoding.
+ // Opc == 0 are all stores.
+ // Opc == 1 with a couple of exceptions are loads. The exceptions are:
+ // Size == 00 (0), V == 1, Opc == 10 (2) which is a store and
+ // Size == 11 (3), V == 0, Opc == 10 (2) which is a prefetch.
+ return Opc != 0 && !(Size == 0 && V == 1 && Opc == 2) &&
+ !(Size == 3 && V == 0 && Opc == 2);
+ }
+ return false;
+}
+
+// The following decode instructions are only complete up to the instructions
+// needed for errata 843419.
+
+// Instruction with writeback updates the index register after the load/store.
+static bool hasWriteback(uint32_t Instr) {
+ return isLoadStoreImmediatePre(Instr) || isLoadStoreImmediatePost(Instr) ||
+ isSTPPre(Instr) || isSTPPost(Instr) || isST1SinglePost(Instr) ||
+ isST1MultiplePost(Instr);
+}
+
+// For the load and store class of instructions, a load can write to the
+// destination register, a load and a store can write to the base register when
+// the instruction has writeback.
+static bool doesLoadStoreWriteToReg(uint32_t Instr, uint32_t Reg) {
+ return (isV8NonStructureLoad(Instr) && getRt(Instr) == Reg) ||
+ (hasWriteback(Instr) && getRn(Instr) == Reg);
+}
+
+// Scanner for Cortex-A53 errata 843419
+// Full details are available in the Cortex A53 MPCore revision 0 Software
+// Developers Errata Notice (ARM-EPM-048406).
+//
+// The instruction sequence that triggers the erratum is common in compiled
+// AArch64 code, however it is sensitive to the offset of the sequence within
+// a 4k page. This means that by scanning and fixing the patch after we have
+// assigned addresses we only need to disassemble and fix instances of the
+// sequence in the range of affected offsets.
+//
+// In summary the erratum conditions are a series of 4 instructions:
+// 1.) An ADRP instruction that writes to register Rn with low 12 bits of
+// address of instruction either 0xff8 or 0xffc.
+// 2.) A load or store instruction that can be:
+// - A single register load or store, of either integer or vector registers.
+// - An STP or STNP, of either integer or vector registers.
+// - An Advanced SIMD ST1 store instruction.
+// - Must not write to Rn, but may optionally read from it.
+// 3.) An optional instruction that is not a branch and does not write to Rn.
+// 4.) A load or store from the Load/store register (unsigned immediate) class
+// that uses Rn as the base address register.
+//
+// Note that we do not attempt to scan for Sequence 2 as described in the
+// Software Developers Errata Notice as this has been assessed to be extremely
+// unlikely to occur in compiled code. This matches gold and ld.bfd behavior.
+
+// Return true if the Instruction sequence Adrp, Instr2, and Instr4 match
+// the erratum sequence. The Adrp, Instr2 and Instr4 correspond to 1.), 2.),
+// and 4.) in the Scanner for Cortex-A53 errata comment above.
+static bool is843419ErratumSequence(uint32_t Instr1, uint32_t Instr2,
+ uint32_t Instr4) {
+ if (!isADRP(Instr1))
+ return false;
+
+ uint32_t Rn = getRt(Instr1);
+ return isLoadStoreClass(Instr2) &&
+ (isLoadStoreExclusive(Instr2) || isLoadLiteral(Instr2) ||
+ isV8SingleRegisterNonStructureLoadStore(Instr2) || isSTP(Instr2) ||
+ isSTNP(Instr2) || isST1(Instr2)) &&
+ !doesLoadStoreWriteToReg(Instr2, Rn) &&
+ isLoadStoreRegisterUnsigned(Instr4) && getRn(Instr4) == Rn;
+}
+
+// Scan the instruction sequence starting at Offset Off from the base of
+// InputSection IS. We update Off in this function rather than in the caller as
+// we can skip ahead much further into the section when we know how many
+// instructions we've scanned.
+// Return the offset of the load or store instruction in IS that we want to
+// patch or 0 if no patch required.
+static uint64_t scanCortexA53Errata843419(InputSection *IS, uint64_t &Off,
+ uint64_t Limit) {
+ uint64_t ISAddr = IS->getVA(0);
+
+ // Advance Off so that (ISAddr + Off) modulo 0x1000 is at least 0xff8.
+ uint64_t InitialPageOff = (ISAddr + Off) & 0xfff;
+ if (InitialPageOff < 0xff8)
+ Off += 0xff8 - InitialPageOff;
+
+ bool OptionalAllowed = Limit - Off > 12;
+ if (Off >= Limit || Limit - Off < 12) {
+ // Need at least 3 4-byte sized instructions to trigger erratum.
+ Off = Limit;
+ return 0;
+ }
+
+ uint64_t PatchOff = 0;
+ const uint8_t *Buf = IS->data().begin();
+ const ulittle32_t *InstBuf = reinterpret_cast<const ulittle32_t *>(Buf + Off);
+ uint32_t Instr1 = *InstBuf++;
+ uint32_t Instr2 = *InstBuf++;
+ uint32_t Instr3 = *InstBuf++;
+ if (is843419ErratumSequence(Instr1, Instr2, Instr3)) {
+ PatchOff = Off + 8;
+ } else if (OptionalAllowed && !isBranch(Instr3)) {
+ uint32_t Instr4 = *InstBuf++;
+ if (is843419ErratumSequence(Instr1, Instr2, Instr4))
+ PatchOff = Off + 12;
+ }
+ if (((ISAddr + Off) & 0xfff) == 0xff8)
+ Off += 4;
+ else
+ Off += 0xffc;
+ return PatchOff;
+}
+
+class lld::elf::Patch843419Section : public SyntheticSection {
+public:
+ Patch843419Section(InputSection *P, uint64_t Off);
+
+ void writeTo(uint8_t *Buf) override;
+
+ size_t getSize() const override { return 8; }
+
+ uint64_t getLDSTAddr() const;
+
+ // The Section we are patching.
+ const InputSection *Patchee;
+ // The offset of the instruction in the Patchee section we are patching.
+ uint64_t PatcheeOffset;
+ // A label for the start of the Patch that we can use as a relocation target.
+ Symbol *PatchSym;
+};
+
+lld::elf::Patch843419Section::Patch843419Section(InputSection *P, uint64_t Off)
+ : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 4,
+ ".text.patch"),
+ Patchee(P), PatcheeOffset(Off) {
+ this->Parent = P->getParent();
+ PatchSym = addSyntheticLocal(
+ Saver.save("__CortexA53843419_" + utohexstr(getLDSTAddr())), STT_FUNC, 0,
+ getSize(), *this);
+ addSyntheticLocal(Saver.save("$x"), STT_NOTYPE, 0, 0, *this);
+}
+
+uint64_t lld::elf::Patch843419Section::getLDSTAddr() const {
+ return Patchee->getVA(PatcheeOffset);
+}
+
+void lld::elf::Patch843419Section::writeTo(uint8_t *Buf) {
+ // Copy the instruction that we will be replacing with a branch in the
+ // Patchee Section.
+ write32le(Buf, read32le(Patchee->data().begin() + PatcheeOffset));
+
+ // Apply any relocation transferred from the original PatcheeSection.
+ // For a SyntheticSection Buf already has OutSecOff added, but relocateAlloc
+ // also adds OutSecOff so we need to subtract to avoid double counting.
+ this->relocateAlloc(Buf - OutSecOff, Buf - OutSecOff + getSize());
+
+ // Return address is the next instruction after the one we have just copied.
+ uint64_t S = getLDSTAddr() + 4;
+ uint64_t P = PatchSym->getVA() + 4;
+ Target->relocateOne(Buf + 4, R_AARCH64_JUMP26, S - P);
+}
+
+void AArch64Err843419Patcher::init() {
+ // The AArch64 ABI permits data in executable sections. We must avoid scanning
+ // this data as if it were instructions to avoid false matches. We use the
+ // mapping symbols in the InputObjects to identify this data, caching the
+ // results in SectionMap so we don't have to recalculate it each pass.
+
+ // The ABI Section 4.5.4 Mapping symbols; defines local symbols that describe
+ // half open intervals [Symbol Value, Next Symbol Value) of code and data
+ // within sections. If there is no next symbol then the half open interval is
+ // [Symbol Value, End of section). The type, code or data, is determined by
+ // the mapping symbol name, $x for code, $d for data.
+ auto IsCodeMapSymbol = [](const Symbol *B) {
+ return B->getName() == "$x" || B->getName().startswith("$x.");
+ };
+ auto IsDataMapSymbol = [](const Symbol *B) {
+ return B->getName() == "$d" || B->getName().startswith("$d.");
+ };
+
+ // Collect mapping symbols for every executable InputSection.
+ for (InputFile *File : ObjectFiles) {
+ auto *F = cast<ObjFile<ELF64LE>>(File);
+ for (Symbol *B : F->getLocalSymbols()) {
+ auto *Def = dyn_cast<Defined>(B);
+ if (!Def)
+ continue;
+ if (!IsCodeMapSymbol(Def) && !IsDataMapSymbol(Def))
+ continue;
+ if (auto *Sec = dyn_cast_or_null<InputSection>(Def->Section))
+ if (Sec->Flags & SHF_EXECINSTR)
+ SectionMap[Sec].push_back(Def);
+ }
+ }
+ // For each InputSection make sure the mapping symbols are in sorted in
+ // ascending order and free from consecutive runs of mapping symbols with
+ // the same type. For example we must remove the redundant $d.1 from $x.0
+ // $d.0 $d.1 $x.1.
+ for (auto &KV : SectionMap) {
+ std::vector<const Defined *> &MapSyms = KV.second;
+ if (MapSyms.size() <= 1)
+ continue;
+ std::stable_sort(
+ MapSyms.begin(), MapSyms.end(),
+ [](const Defined *A, const Defined *B) { return A->Value < B->Value; });
+ MapSyms.erase(
+ std::unique(MapSyms.begin(), MapSyms.end(),
+ [=](const Defined *A, const Defined *B) {
+ return (IsCodeMapSymbol(A) && IsCodeMapSymbol(B)) ||
+ (IsDataMapSymbol(A) && IsDataMapSymbol(B));
+ }),
+ MapSyms.end());
+ }
+ Initialized = true;
+}
+
+// Insert the PatchSections we have created back into the
+// InputSectionDescription. As inserting patches alters the addresses of
+// InputSections that follow them, we try and place the patches after all the
+// executable sections, although we may need to insert them earlier if the
+// InputSectionDescription is larger than the maximum branch range.
+void AArch64Err843419Patcher::insertPatches(
+ InputSectionDescription &ISD, std::vector<Patch843419Section *> &Patches) {
+ uint64_t ISLimit;
+ uint64_t PrevISLimit = ISD.Sections.front()->OutSecOff;
+ uint64_t PatchUpperBound = PrevISLimit + Target->getThunkSectionSpacing();
+ uint64_t OutSecAddr = ISD.Sections.front()->getParent()->Addr;
+
+ // Set the OutSecOff of patches to the place where we want to insert them.
+ // We use a similar strategy to Thunk placement. Place patches roughly
+ // every multiple of maximum branch range.
+ auto PatchIt = Patches.begin();
+ auto PatchEnd = Patches.end();
+ for (const InputSection *IS : ISD.Sections) {
+ ISLimit = IS->OutSecOff + IS->getSize();
+ if (ISLimit > PatchUpperBound) {
+ while (PatchIt != PatchEnd) {
+ if ((*PatchIt)->getLDSTAddr() - OutSecAddr >= PrevISLimit)
+ break;
+ (*PatchIt)->OutSecOff = PrevISLimit;
+ ++PatchIt;
+ }
+ PatchUpperBound = PrevISLimit + Target->getThunkSectionSpacing();
+ }
+ PrevISLimit = ISLimit;
+ }
+ for (; PatchIt != PatchEnd; ++PatchIt) {
+ (*PatchIt)->OutSecOff = ISLimit;
+ }
+
+ // merge all patch sections. We use the OutSecOff assigned above to
+ // determine the insertion point. This is ok as we only merge into an
+ // InputSectionDescription once per pass, and at the end of the pass
+ // assignAddresses() will recalculate all the OutSecOff values.
+ std::vector<InputSection *> Tmp;
+ Tmp.reserve(ISD.Sections.size() + Patches.size());
+ auto MergeCmp = [](const InputSection *A, const InputSection *B) {
+ if (A->OutSecOff < B->OutSecOff)
+ return true;
+ if (A->OutSecOff == B->OutSecOff && isa<Patch843419Section>(A) &&
+ !isa<Patch843419Section>(B))
+ return true;
+ return false;
+ };
+ std::merge(ISD.Sections.begin(), ISD.Sections.end(), Patches.begin(),
+ Patches.end(), std::back_inserter(Tmp), MergeCmp);
+ ISD.Sections = std::move(Tmp);
+}
+
+// Given an erratum sequence that starts at address AdrpAddr, with an
+// instruction that we need to patch at PatcheeOffset from the start of
+// InputSection IS, create a Patch843419 Section and add it to the
+// Patches that we need to insert.
+static void implementPatch(uint64_t AdrpAddr, uint64_t PatcheeOffset,
+ InputSection *IS,
+ std::vector<Patch843419Section *> &Patches) {
+ // There may be a relocation at the same offset that we are patching. There
+ // are four cases that we need to consider.
+ // Case 1: R_AARCH64_JUMP26 branch relocation. We have already patched this
+ // instance of the erratum on a previous patch and altered the relocation. We
+ // have nothing more to do.
+ // Case 2: A TLS Relaxation R_RELAX_TLS_IE_TO_LE. In this case the ADRP that
+ // we read will be transformed into a MOVZ later so we actually don't match
+ // the sequence and have nothing more to do.
+ // Case 3: A load/store register (unsigned immediate) class relocation. There
+ // are two of these R_AARCH_LD64_ABS_LO12_NC and R_AARCH_LD64_GOT_LO12_NC and
+ // they are both absolute. We need to add the same relocation to the patch,
+ // and replace the relocation with a R_AARCH_JUMP26 branch relocation.
+ // Case 4: No relocation. We must create a new R_AARCH64_JUMP26 branch
+ // relocation at the offset.
+ auto RelIt = std::find_if(
+ IS->Relocations.begin(), IS->Relocations.end(),
+ [=](const Relocation &R) { return R.Offset == PatcheeOffset; });
+ if (RelIt != IS->Relocations.end() &&
+ (RelIt->Type == R_AARCH64_JUMP26 || RelIt->Expr == R_RELAX_TLS_IE_TO_LE))
+ return;
+
+ log("detected cortex-a53-843419 erratum sequence starting at " +
+ utohexstr(AdrpAddr) + " in unpatched output.");
+
+ auto *PS = make<Patch843419Section>(IS, PatcheeOffset);
+ Patches.push_back(PS);
+
+ auto MakeRelToPatch = [](uint64_t Offset, Symbol *PatchSym) {
+ return Relocation{R_PC, R_AARCH64_JUMP26, Offset, 0, PatchSym};
+ };
+
+ if (RelIt != IS->Relocations.end()) {
+ PS->Relocations.push_back(
+ {RelIt->Expr, RelIt->Type, 0, RelIt->Addend, RelIt->Sym});
+ *RelIt = MakeRelToPatch(PatcheeOffset, PS->PatchSym);
+ } else
+ IS->Relocations.push_back(MakeRelToPatch(PatcheeOffset, PS->PatchSym));
+}
+
+// Scan all the instructions in InputSectionDescription, for each instance of
+// the erratum sequence create a Patch843419Section. We return the list of
+// Patch843419Sections that need to be applied to ISD.
+std::vector<Patch843419Section *>
+AArch64Err843419Patcher::patchInputSectionDescription(
+ InputSectionDescription &ISD) {
+ std::vector<Patch843419Section *> Patches;
+ for (InputSection *IS : ISD.Sections) {
+ // LLD doesn't use the erratum sequence in SyntheticSections.
+ if (isa<SyntheticSection>(IS))
+ continue;
+ // Use SectionMap to make sure we only scan code and not inline data.
+ // We have already sorted MapSyms in ascending order and removed consecutive
+ // mapping symbols of the same type. Our range of executable instructions to
+ // scan is therefore [CodeSym->Value, DataSym->Value) or [CodeSym->Value,
+ // section size).
+ std::vector<const Defined *> &MapSyms = SectionMap[IS];
+
+ auto CodeSym = llvm::find_if(MapSyms, [&](const Defined *MS) {
+ return MS->getName().startswith("$x");
+ });
+
+ while (CodeSym != MapSyms.end()) {
+ auto DataSym = std::next(CodeSym);
+ uint64_t Off = (*CodeSym)->Value;
+ uint64_t Limit =
+ (DataSym == MapSyms.end()) ? IS->data().size() : (*DataSym)->Value;
+
+ while (Off < Limit) {
+ uint64_t StartAddr = IS->getVA(Off);
+ if (uint64_t PatcheeOffset = scanCortexA53Errata843419(IS, Off, Limit))
+ implementPatch(StartAddr, PatcheeOffset, IS, Patches);
+ }
+ if (DataSym == MapSyms.end())
+ break;
+ CodeSym = std::next(DataSym);
+ }
+ }
+ return Patches;
+}
+
+// For each InputSectionDescription make one pass over the executable sections
+// looking for the erratum sequence; creating a synthetic Patch843419Section
+// for each instance found. We insert these synthetic patch sections after the
+// executable code in each InputSectionDescription.
+//
+// PreConditions:
+// The Output and Input Sections have had their final addresses assigned.
+//
+// PostConditions:
+// Returns true if at least one patch was added. The addresses of the
+// Ouptut and Input Sections may have been changed.
+// Returns false if no patches were required and no changes were made.
+bool AArch64Err843419Patcher::createFixes() {
+ if (Initialized == false)
+ init();
+
+ bool AddressesChanged = false;
+ for (OutputSection *OS : OutputSections) {
+ if (!(OS->Flags & SHF_ALLOC) || !(OS->Flags & SHF_EXECINSTR))
+ continue;
+ for (BaseCommand *BC : OS->SectionCommands)
+ if (auto *ISD = dyn_cast<InputSectionDescription>(BC)) {
+ std::vector<Patch843419Section *> Patches =
+ patchInputSectionDescription(*ISD);
+ if (!Patches.empty()) {
+ insertPatches(*ISD, Patches);
+ AddressesChanged = true;
+ }
+ }
+ }
+ return AddressesChanged;
+}
diff --git a/contrib/llvm/tools/lld/ELF/AArch64ErrataFix.h b/contrib/llvm/tools/lld/ELF/AArch64ErrataFix.h
new file mode 100644
index 000000000000..edd154d4cab3
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/AArch64ErrataFix.h
@@ -0,0 +1,51 @@
+//===- AArch64ErrataFix.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_AARCH64ERRATAFIX_H
+#define LLD_ELF_AARCH64ERRATAFIX_H
+
+#include "lld/Common/LLVM.h"
+#include <map>
+#include <vector>
+
+namespace lld {
+namespace elf {
+
+class Defined;
+class InputSection;
+struct InputSectionDescription;
+class OutputSection;
+class Patch843419Section;
+
+class AArch64Err843419Patcher {
+public:
+ // return true if Patches have been added to the OutputSections.
+ bool createFixes();
+
+private:
+ std::vector<Patch843419Section *>
+ patchInputSectionDescription(InputSectionDescription &ISD);
+
+ void insertPatches(InputSectionDescription &ISD,
+ std::vector<Patch843419Section *> &Patches);
+
+ void init();
+
+ // A cache of the mapping symbols defined by the InputSecion sorted in order
+ // of ascending value with redundant symbols removed. These describe
+ // the ranges of code and data in an executable InputSection.
+ std::map<InputSection *, std::vector<const Defined *>> SectionMap;
+
+ bool Initialized = false;
+};
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/ELF/Arch/AArch64.cpp b/contrib/llvm/tools/lld/ELF/Arch/AArch64.cpp
new file mode 100644
index 000000000000..08ffe2a08c0f
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Arch/AArch64.cpp
@@ -0,0 +1,440 @@
+//===- AArch64.cpp --------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "Thunks.h"
+#include "lld/Common/ErrorHandler.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+// Page(Expr) is the page address of the expression Expr, defined
+// as (Expr & ~0xFFF). (This applies even if the machine page size
+// supported by the platform has a different value.)
+uint64_t elf::getAArch64Page(uint64_t Expr) {
+ return Expr & ~static_cast<uint64_t>(0xFFF);
+}
+
+namespace {
+class AArch64 final : public TargetInfo {
+public:
+ AArch64();
+ RelExpr getRelExpr(RelType Type, const Symbol &S,
+ const uint8_t *Loc) const override;
+ RelType getDynRel(RelType Type) const override;
+ void writeGotPlt(uint8_t *Buf, const Symbol &S) const override;
+ void writePltHeader(uint8_t *Buf) const override;
+ void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
+ int32_t Index, unsigned RelOff) const override;
+ bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
+ uint64_t BranchAddr, const Symbol &S) const override;
+ uint32_t getThunkSectionSpacing() const override;
+ bool inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const override;
+ bool usesOnlyLowPageBits(RelType Type) const override;
+ void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+ RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data,
+ RelExpr Expr) const override;
+ void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+ void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+ void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+};
+} // namespace
+
+AArch64::AArch64() {
+ CopyRel = R_AARCH64_COPY;
+ RelativeRel = R_AARCH64_RELATIVE;
+ IRelativeRel = R_AARCH64_IRELATIVE;
+ GotRel = R_AARCH64_GLOB_DAT;
+ NoneRel = R_AARCH64_NONE;
+ PltRel = R_AARCH64_JUMP_SLOT;
+ TlsDescRel = R_AARCH64_TLSDESC;
+ TlsGotRel = R_AARCH64_TLS_TPREL64;
+ GotEntrySize = 8;
+ GotPltEntrySize = 8;
+ PltEntrySize = 16;
+ PltHeaderSize = 32;
+ DefaultMaxPageSize = 65536;
+
+ // Align to the 2 MiB page size (known as a superpage or huge page).
+ // FreeBSD automatically promotes 2 MiB-aligned allocations.
+ DefaultImageBase = 0x200000;
+
+ NeedsThunks = true;
+}
+
+RelExpr AArch64::getRelExpr(RelType Type, const Symbol &S,
+ const uint8_t *Loc) const {
+ switch (Type) {
+ case R_AARCH64_TLSDESC_ADR_PAGE21:
+ return R_AARCH64_TLSDESC_PAGE;
+ case R_AARCH64_TLSDESC_LD64_LO12:
+ case R_AARCH64_TLSDESC_ADD_LO12:
+ return R_TLSDESC;
+ case R_AARCH64_TLSDESC_CALL:
+ return R_TLSDESC_CALL;
+ case R_AARCH64_TLSLE_ADD_TPREL_HI12:
+ case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
+ case R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC:
+ case R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC:
+ case R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC:
+ case R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC:
+ case R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC:
+ return R_TLS;
+ case R_AARCH64_CALL26:
+ case R_AARCH64_CONDBR19:
+ case R_AARCH64_JUMP26:
+ case R_AARCH64_TSTBR14:
+ return R_PLT_PC;
+ case R_AARCH64_PREL16:
+ case R_AARCH64_PREL32:
+ case R_AARCH64_PREL64:
+ case R_AARCH64_ADR_PREL_LO21:
+ case R_AARCH64_LD_PREL_LO19:
+ return R_PC;
+ case R_AARCH64_ADR_PREL_PG_HI21:
+ return R_AARCH64_PAGE_PC;
+ case R_AARCH64_LD64_GOT_LO12_NC:
+ case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
+ return R_GOT;
+ case R_AARCH64_ADR_GOT_PAGE:
+ case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
+ return R_AARCH64_GOT_PAGE_PC;
+ case R_AARCH64_NONE:
+ return R_NONE;
+ default:
+ return R_ABS;
+ }
+}
+
+RelExpr AArch64::adjustRelaxExpr(RelType Type, const uint8_t *Data,
+ RelExpr Expr) const {
+ if (Expr == R_RELAX_TLS_GD_TO_IE) {
+ if (Type == R_AARCH64_TLSDESC_ADR_PAGE21)
+ return R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC;
+ return R_RELAX_TLS_GD_TO_IE_ABS;
+ }
+ return Expr;
+}
+
+bool AArch64::usesOnlyLowPageBits(RelType Type) const {
+ switch (Type) {
+ default:
+ return false;
+ case R_AARCH64_ADD_ABS_LO12_NC:
+ case R_AARCH64_LD64_GOT_LO12_NC:
+ case R_AARCH64_LDST128_ABS_LO12_NC:
+ case R_AARCH64_LDST16_ABS_LO12_NC:
+ case R_AARCH64_LDST32_ABS_LO12_NC:
+ case R_AARCH64_LDST64_ABS_LO12_NC:
+ case R_AARCH64_LDST8_ABS_LO12_NC:
+ case R_AARCH64_TLSDESC_ADD_LO12:
+ case R_AARCH64_TLSDESC_LD64_LO12:
+ case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
+ return true;
+ }
+}
+
+RelType AArch64::getDynRel(RelType Type) const {
+ if (Type == R_AARCH64_ABS32 || Type == R_AARCH64_ABS64)
+ return Type;
+ return R_AARCH64_NONE;
+}
+
+void AArch64::writeGotPlt(uint8_t *Buf, const Symbol &) const {
+ write64le(Buf, In.Plt->getVA());
+}
+
+void AArch64::writePltHeader(uint8_t *Buf) const {
+ const uint8_t PltData[] = {
+ 0xf0, 0x7b, 0xbf, 0xa9, // stp x16, x30, [sp,#-16]!
+ 0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.plt.got[2]))
+ 0x11, 0x02, 0x40, 0xf9, // ldr x17, [x16, Offset(&(.plt.got[2]))]
+ 0x10, 0x02, 0x00, 0x91, // add x16, x16, Offset(&(.plt.got[2]))
+ 0x20, 0x02, 0x1f, 0xd6, // br x17
+ 0x1f, 0x20, 0x03, 0xd5, // nop
+ 0x1f, 0x20, 0x03, 0xd5, // nop
+ 0x1f, 0x20, 0x03, 0xd5 // nop
+ };
+ memcpy(Buf, PltData, sizeof(PltData));
+
+ uint64_t Got = In.GotPlt->getVA();
+ uint64_t Plt = In.Plt->getVA();
+ relocateOne(Buf + 4, R_AARCH64_ADR_PREL_PG_HI21,
+ getAArch64Page(Got + 16) - getAArch64Page(Plt + 4));
+ relocateOne(Buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, Got + 16);
+ relocateOne(Buf + 12, R_AARCH64_ADD_ABS_LO12_NC, Got + 16);
+}
+
+void AArch64::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const {
+ const uint8_t Inst[] = {
+ 0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.plt.got[n]))
+ 0x11, 0x02, 0x40, 0xf9, // ldr x17, [x16, Offset(&(.plt.got[n]))]
+ 0x10, 0x02, 0x00, 0x91, // add x16, x16, Offset(&(.plt.got[n]))
+ 0x20, 0x02, 0x1f, 0xd6 // br x17
+ };
+ memcpy(Buf, Inst, sizeof(Inst));
+
+ relocateOne(Buf, R_AARCH64_ADR_PREL_PG_HI21,
+ getAArch64Page(GotPltEntryAddr) - getAArch64Page(PltEntryAddr));
+ relocateOne(Buf + 4, R_AARCH64_LDST64_ABS_LO12_NC, GotPltEntryAddr);
+ relocateOne(Buf + 8, R_AARCH64_ADD_ABS_LO12_NC, GotPltEntryAddr);
+}
+
+bool AArch64::needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
+ uint64_t BranchAddr, const Symbol &S) const {
+ // ELF for the ARM 64-bit architecture, section Call and Jump relocations
+ // only permits range extension thunks for R_AARCH64_CALL26 and
+ // R_AARCH64_JUMP26 relocation types.
+ if (Type != R_AARCH64_CALL26 && Type != R_AARCH64_JUMP26)
+ return false;
+ uint64_t Dst = (Expr == R_PLT_PC) ? S.getPltVA() : S.getVA();
+ return !inBranchRange(Type, BranchAddr, Dst);
+}
+
+uint32_t AArch64::getThunkSectionSpacing() const {
+ // See comment in Arch/ARM.cpp for a more detailed explanation of
+ // getThunkSectionSpacing(). For AArch64 the only branches we are permitted to
+ // Thunk have a range of +/- 128 MiB
+ return (128 * 1024 * 1024) - 0x30000;
+}
+
+bool AArch64::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const {
+ if (Type != R_AARCH64_CALL26 && Type != R_AARCH64_JUMP26)
+ return true;
+ // The AArch64 call and unconditional branch instructions have a range of
+ // +/- 128 MiB.
+ uint64_t Range = 128 * 1024 * 1024;
+ if (Dst > Src) {
+ // Immediate of branch is signed.
+ Range -= 4;
+ return Dst - Src <= Range;
+ }
+ return Src - Dst <= Range;
+}
+
+static void write32AArch64Addr(uint8_t *L, uint64_t Imm) {
+ uint32_t ImmLo = (Imm & 0x3) << 29;
+ uint32_t ImmHi = (Imm & 0x1FFFFC) << 3;
+ uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3);
+ write32le(L, (read32le(L) & ~Mask) | ImmLo | ImmHi);
+}
+
+// Return the bits [Start, End] from Val shifted Start bits.
+// For instance, getBits(0xF0, 4, 8) returns 0xF.
+static uint64_t getBits(uint64_t Val, int Start, int End) {
+ uint64_t Mask = ((uint64_t)1 << (End + 1 - Start)) - 1;
+ return (Val >> Start) & Mask;
+}
+
+static void or32le(uint8_t *P, int32_t V) { write32le(P, read32le(P) | V); }
+
+// Update the immediate field in a AARCH64 ldr, str, and add instruction.
+static void or32AArch64Imm(uint8_t *L, uint64_t Imm) {
+ or32le(L, (Imm & 0xFFF) << 10);
+}
+
+void AArch64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
+ switch (Type) {
+ case R_AARCH64_ABS16:
+ case R_AARCH64_PREL16:
+ checkIntUInt(Loc, Val, 16, Type);
+ write16le(Loc, Val);
+ break;
+ case R_AARCH64_ABS32:
+ case R_AARCH64_PREL32:
+ checkIntUInt(Loc, Val, 32, Type);
+ write32le(Loc, Val);
+ break;
+ case R_AARCH64_ABS64:
+ case R_AARCH64_GLOB_DAT:
+ case R_AARCH64_PREL64:
+ write64le(Loc, Val);
+ break;
+ case R_AARCH64_ADD_ABS_LO12_NC:
+ or32AArch64Imm(Loc, Val);
+ break;
+ case R_AARCH64_ADR_GOT_PAGE:
+ case R_AARCH64_ADR_PREL_PG_HI21:
+ case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
+ case R_AARCH64_TLSDESC_ADR_PAGE21:
+ checkInt(Loc, Val, 33, Type);
+ write32AArch64Addr(Loc, Val >> 12);
+ break;
+ case R_AARCH64_ADR_PREL_LO21:
+ checkInt(Loc, Val, 21, Type);
+ write32AArch64Addr(Loc, Val);
+ break;
+ case R_AARCH64_JUMP26:
+ // Normally we would just write the bits of the immediate field, however
+ // when patching instructions for the cpu errata fix -fix-cortex-a53-843419
+ // we want to replace a non-branch instruction with a branch immediate
+ // instruction. By writing all the bits of the instruction including the
+ // opcode and the immediate (0 001 | 01 imm26) we can do this
+ // transformation by placing a R_AARCH64_JUMP26 relocation at the offset of
+ // the instruction we want to patch.
+ write32le(Loc, 0x14000000);
+ LLVM_FALLTHROUGH;
+ case R_AARCH64_CALL26:
+ checkInt(Loc, Val, 28, Type);
+ or32le(Loc, (Val & 0x0FFFFFFC) >> 2);
+ break;
+ case R_AARCH64_CONDBR19:
+ case R_AARCH64_LD_PREL_LO19:
+ checkAlignment(Loc, Val, 4, Type);
+ checkInt(Loc, Val, 21, Type);
+ or32le(Loc, (Val & 0x1FFFFC) << 3);
+ break;
+ case R_AARCH64_LDST8_ABS_LO12_NC:
+ case R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC:
+ or32AArch64Imm(Loc, getBits(Val, 0, 11));
+ break;
+ case R_AARCH64_LDST16_ABS_LO12_NC:
+ case R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC:
+ checkAlignment(Loc, Val, 2, Type);
+ or32AArch64Imm(Loc, getBits(Val, 1, 11));
+ break;
+ case R_AARCH64_LDST32_ABS_LO12_NC:
+ case R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC:
+ checkAlignment(Loc, Val, 4, Type);
+ or32AArch64Imm(Loc, getBits(Val, 2, 11));
+ break;
+ case R_AARCH64_LDST64_ABS_LO12_NC:
+ case R_AARCH64_LD64_GOT_LO12_NC:
+ case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
+ case R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC:
+ case R_AARCH64_TLSDESC_LD64_LO12:
+ checkAlignment(Loc, Val, 8, Type);
+ or32AArch64Imm(Loc, getBits(Val, 3, 11));
+ break;
+ case R_AARCH64_LDST128_ABS_LO12_NC:
+ case R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC:
+ checkAlignment(Loc, Val, 16, Type);
+ or32AArch64Imm(Loc, getBits(Val, 4, 11));
+ break;
+ case R_AARCH64_MOVW_UABS_G0_NC:
+ or32le(Loc, (Val & 0xFFFF) << 5);
+ break;
+ case R_AARCH64_MOVW_UABS_G1_NC:
+ or32le(Loc, (Val & 0xFFFF0000) >> 11);
+ break;
+ case R_AARCH64_MOVW_UABS_G2_NC:
+ or32le(Loc, (Val & 0xFFFF00000000) >> 27);
+ break;
+ case R_AARCH64_MOVW_UABS_G3:
+ or32le(Loc, (Val & 0xFFFF000000000000) >> 43);
+ break;
+ case R_AARCH64_TSTBR14:
+ checkInt(Loc, Val, 16, Type);
+ or32le(Loc, (Val & 0xFFFC) << 3);
+ break;
+ case R_AARCH64_TLSLE_ADD_TPREL_HI12:
+ checkUInt(Loc, Val, 24, Type);
+ or32AArch64Imm(Loc, Val >> 12);
+ break;
+ case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
+ case R_AARCH64_TLSDESC_ADD_LO12:
+ or32AArch64Imm(Loc, Val);
+ break;
+ default:
+ error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
+ }
+}
+
+void AArch64::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
+ // TLSDESC Global-Dynamic relocation are in the form:
+ // adrp x0, :tlsdesc:v [R_AARCH64_TLSDESC_ADR_PAGE21]
+ // ldr x1, [x0, #:tlsdesc_lo12:v [R_AARCH64_TLSDESC_LD64_LO12]
+ // add x0, x0, :tlsdesc_los:v [R_AARCH64_TLSDESC_ADD_LO12]
+ // .tlsdesccall [R_AARCH64_TLSDESC_CALL]
+ // blr x1
+ // And it can optimized to:
+ // movz x0, #0x0, lsl #16
+ // movk x0, #0x10
+ // nop
+ // nop
+ checkUInt(Loc, Val, 32, Type);
+
+ switch (Type) {
+ case R_AARCH64_TLSDESC_ADD_LO12:
+ case R_AARCH64_TLSDESC_CALL:
+ write32le(Loc, 0xd503201f); // nop
+ return;
+ case R_AARCH64_TLSDESC_ADR_PAGE21:
+ write32le(Loc, 0xd2a00000 | (((Val >> 16) & 0xffff) << 5)); // movz
+ return;
+ case R_AARCH64_TLSDESC_LD64_LO12:
+ write32le(Loc, 0xf2800000 | ((Val & 0xffff) << 5)); // movk
+ return;
+ default:
+ llvm_unreachable("unsupported relocation for TLS GD to LE relaxation");
+ }
+}
+
+void AArch64::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const {
+ // TLSDESC Global-Dynamic relocation are in the form:
+ // adrp x0, :tlsdesc:v [R_AARCH64_TLSDESC_ADR_PAGE21]
+ // ldr x1, [x0, #:tlsdesc_lo12:v [R_AARCH64_TLSDESC_LD64_LO12]
+ // add x0, x0, :tlsdesc_los:v [R_AARCH64_TLSDESC_ADD_LO12]
+ // .tlsdesccall [R_AARCH64_TLSDESC_CALL]
+ // blr x1
+ // And it can optimized to:
+ // adrp x0, :gottprel:v
+ // ldr x0, [x0, :gottprel_lo12:v]
+ // nop
+ // nop
+
+ switch (Type) {
+ case R_AARCH64_TLSDESC_ADD_LO12:
+ case R_AARCH64_TLSDESC_CALL:
+ write32le(Loc, 0xd503201f); // nop
+ break;
+ case R_AARCH64_TLSDESC_ADR_PAGE21:
+ write32le(Loc, 0x90000000); // adrp
+ relocateOne(Loc, R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21, Val);
+ break;
+ case R_AARCH64_TLSDESC_LD64_LO12:
+ write32le(Loc, 0xf9400000); // ldr
+ relocateOne(Loc, R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC, Val);
+ break;
+ default:
+ llvm_unreachable("unsupported relocation for TLS GD to LE relaxation");
+ }
+}
+
+void AArch64::relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
+ checkUInt(Loc, Val, 32, Type);
+
+ if (Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21) {
+ // Generate MOVZ.
+ uint32_t RegNo = read32le(Loc) & 0x1f;
+ write32le(Loc, (0xd2a00000 | RegNo) | (((Val >> 16) & 0xffff) << 5));
+ return;
+ }
+ if (Type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC) {
+ // Generate MOVK.
+ uint32_t RegNo = read32le(Loc) & 0x1f;
+ write32le(Loc, (0xf2800000 | RegNo) | ((Val & 0xffff) << 5));
+ return;
+ }
+ llvm_unreachable("invalid relocation for TLS IE to LE relaxation");
+}
+
+TargetInfo *elf::getAArch64TargetInfo() {
+ static AArch64 Target;
+ return &Target;
+}
diff --git a/contrib/llvm/tools/lld/ELF/Arch/AMDGPU.cpp b/contrib/llvm/tools/lld/ELF/Arch/AMDGPU.cpp
new file mode 100644
index 000000000000..a7c6c84ceecd
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Arch/AMDGPU.cpp
@@ -0,0 +1,105 @@
+//===- AMDGPU.cpp ---------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "Target.h"
+#include "lld/Common/ErrorHandler.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+class AMDGPU final : public TargetInfo {
+public:
+ AMDGPU();
+ uint32_t calcEFlags() const override;
+ void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+ RelExpr getRelExpr(RelType Type, const Symbol &S,
+ const uint8_t *Loc) const override;
+};
+} // namespace
+
+AMDGPU::AMDGPU() {
+ RelativeRel = R_AMDGPU_RELATIVE64;
+ GotRel = R_AMDGPU_ABS64;
+ NoneRel = R_AMDGPU_NONE;
+ GotEntrySize = 8;
+}
+
+static uint32_t getEFlags(InputFile *File) {
+ return cast<ObjFile<ELF64LE>>(File)->getObj().getHeader()->e_flags;
+}
+
+uint32_t AMDGPU::calcEFlags() const {
+ assert(!ObjectFiles.empty());
+ uint32_t Ret = getEFlags(ObjectFiles[0]);
+
+ // Verify that all input files have the same e_flags.
+ for (InputFile *F : makeArrayRef(ObjectFiles).slice(1)) {
+ if (Ret == getEFlags(F))
+ continue;
+ error("incompatible e_flags: " + toString(F));
+ return 0;
+ }
+ return Ret;
+}
+
+void AMDGPU::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
+ switch (Type) {
+ case R_AMDGPU_ABS32:
+ case R_AMDGPU_GOTPCREL:
+ case R_AMDGPU_GOTPCREL32_LO:
+ case R_AMDGPU_REL32:
+ case R_AMDGPU_REL32_LO:
+ write32le(Loc, Val);
+ break;
+ case R_AMDGPU_ABS64:
+ case R_AMDGPU_REL64:
+ write64le(Loc, Val);
+ break;
+ case R_AMDGPU_GOTPCREL32_HI:
+ case R_AMDGPU_REL32_HI:
+ write32le(Loc, Val >> 32);
+ break;
+ default:
+ error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
+ }
+}
+
+RelExpr AMDGPU::getRelExpr(RelType Type, const Symbol &S,
+ const uint8_t *Loc) const {
+ switch (Type) {
+ case R_AMDGPU_ABS32:
+ case R_AMDGPU_ABS64:
+ return R_ABS;
+ case R_AMDGPU_REL32:
+ case R_AMDGPU_REL32_LO:
+ case R_AMDGPU_REL32_HI:
+ case R_AMDGPU_REL64:
+ return R_PC;
+ case R_AMDGPU_GOTPCREL:
+ case R_AMDGPU_GOTPCREL32_LO:
+ case R_AMDGPU_GOTPCREL32_HI:
+ return R_GOT_PC;
+ default:
+ return R_INVALID;
+ }
+}
+
+TargetInfo *elf::getAMDGPUTargetInfo() {
+ static AMDGPU Target;
+ return &Target;
+}
diff --git a/contrib/llvm/tools/lld/ELF/Arch/ARM.cpp b/contrib/llvm/tools/lld/ELF/Arch/ARM.cpp
new file mode 100644
index 000000000000..120caca671af
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Arch/ARM.cpp
@@ -0,0 +1,612 @@
+//===- ARM.cpp ------------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "Thunks.h"
+#include "lld/Common/ErrorHandler.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+class ARM final : public TargetInfo {
+public:
+ ARM();
+ uint32_t calcEFlags() const override;
+ RelExpr getRelExpr(RelType Type, const Symbol &S,
+ const uint8_t *Loc) const override;
+ RelType getDynRel(RelType Type) const override;
+ int64_t getImplicitAddend(const uint8_t *Buf, RelType Type) const override;
+ void writeGotPlt(uint8_t *Buf, const Symbol &S) const override;
+ void writeIgotPlt(uint8_t *Buf, const Symbol &S) const override;
+ void writePltHeader(uint8_t *Buf) const override;
+ void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
+ int32_t Index, unsigned RelOff) const override;
+ void addPltSymbols(InputSection &IS, uint64_t Off) const override;
+ void addPltHeaderSymbols(InputSection &ISD) const override;
+ bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
+ uint64_t BranchAddr, const Symbol &S) const override;
+ uint32_t getThunkSectionSpacing() const override;
+ bool inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const override;
+ void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+};
+} // namespace
+
+ARM::ARM() {
+ CopyRel = R_ARM_COPY;
+ RelativeRel = R_ARM_RELATIVE;
+ IRelativeRel = R_ARM_IRELATIVE;
+ GotRel = R_ARM_GLOB_DAT;
+ NoneRel = R_ARM_NONE;
+ PltRel = R_ARM_JUMP_SLOT;
+ TlsGotRel = R_ARM_TLS_TPOFF32;
+ TlsModuleIndexRel = R_ARM_TLS_DTPMOD32;
+ TlsOffsetRel = R_ARM_TLS_DTPOFF32;
+ GotBaseSymInGotPlt = false;
+ GotEntrySize = 4;
+ GotPltEntrySize = 4;
+ PltEntrySize = 16;
+ PltHeaderSize = 32;
+ TrapInstr = {0xd4, 0xd4, 0xd4, 0xd4};
+ NeedsThunks = true;
+}
+
+uint32_t ARM::calcEFlags() const {
+ // The ABIFloatType is used by loaders to detect the floating point calling
+ // convention.
+ uint32_t ABIFloatType = 0;
+ if (Config->ARMVFPArgs == ARMVFPArgKind::Base ||
+ Config->ARMVFPArgs == ARMVFPArgKind::Default)
+ ABIFloatType = EF_ARM_ABI_FLOAT_SOFT;
+ else if (Config->ARMVFPArgs == ARMVFPArgKind::VFP)
+ ABIFloatType = EF_ARM_ABI_FLOAT_HARD;
+
+ // We don't currently use any features incompatible with EF_ARM_EABI_VER5,
+ // but we don't have any firm guarantees of conformance. Linux AArch64
+ // kernels (as of 2016) require an EABI version to be set.
+ return EF_ARM_EABI_VER5 | ABIFloatType;
+}
+
+RelExpr ARM::getRelExpr(RelType Type, const Symbol &S,
+ const uint8_t *Loc) const {
+ switch (Type) {
+ case R_ARM_THM_JUMP11:
+ return R_PC;
+ case R_ARM_CALL:
+ case R_ARM_JUMP24:
+ case R_ARM_PC24:
+ case R_ARM_PLT32:
+ case R_ARM_PREL31:
+ case R_ARM_THM_JUMP19:
+ case R_ARM_THM_JUMP24:
+ case R_ARM_THM_CALL:
+ return R_PLT_PC;
+ case R_ARM_GOTOFF32:
+ // (S + A) - GOT_ORG
+ return R_GOTREL;
+ case R_ARM_GOT_BREL:
+ // GOT(S) + A - GOT_ORG
+ return R_GOT_OFF;
+ case R_ARM_GOT_PREL:
+ case R_ARM_TLS_IE32:
+ // GOT(S) + A - P
+ return R_GOT_PC;
+ case R_ARM_SBREL32:
+ return R_ARM_SBREL;
+ case R_ARM_TARGET1:
+ return Config->Target1Rel ? R_PC : R_ABS;
+ case R_ARM_TARGET2:
+ if (Config->Target2 == Target2Policy::Rel)
+ return R_PC;
+ if (Config->Target2 == Target2Policy::Abs)
+ return R_ABS;
+ return R_GOT_PC;
+ case R_ARM_TLS_GD32:
+ return R_TLSGD_PC;
+ case R_ARM_TLS_LDM32:
+ return R_TLSLD_PC;
+ case R_ARM_BASE_PREL:
+ // B(S) + A - P
+ // FIXME: currently B(S) assumed to be .got, this may not hold for all
+ // platforms.
+ return R_GOTONLY_PC;
+ case R_ARM_MOVW_PREL_NC:
+ case R_ARM_MOVT_PREL:
+ case R_ARM_REL32:
+ case R_ARM_THM_MOVW_PREL_NC:
+ case R_ARM_THM_MOVT_PREL:
+ return R_PC;
+ case R_ARM_NONE:
+ return R_NONE;
+ case R_ARM_TLS_LE32:
+ return R_TLS;
+ case R_ARM_V4BX:
+ // V4BX is just a marker to indicate there's a "bx rN" instruction at the
+ // given address. It can be used to implement a special linker mode which
+ // rewrites ARMv4T inputs to ARMv4. Since we support only ARMv4 input and
+ // not ARMv4 output, we can just ignore it.
+ return R_HINT;
+ default:
+ return R_ABS;
+ }
+}
+
+RelType ARM::getDynRel(RelType Type) const {
+ if ((Type == R_ARM_ABS32) || (Type == R_ARM_TARGET1 && !Config->Target1Rel))
+ return R_ARM_ABS32;
+ return R_ARM_NONE;
+}
+
+void ARM::writeGotPlt(uint8_t *Buf, const Symbol &) const {
+ write32le(Buf, In.Plt->getVA());
+}
+
+void ARM::writeIgotPlt(uint8_t *Buf, const Symbol &S) const {
+ // An ARM entry is the address of the ifunc resolver function.
+ write32le(Buf, S.getVA());
+}
+
+// Long form PLT Header that does not have any restrictions on the displacement
+// of the .plt from the .plt.got.
+static void writePltHeaderLong(uint8_t *Buf) {
+ const uint8_t PltData[] = {
+ 0x04, 0xe0, 0x2d, 0xe5, // str lr, [sp,#-4]!
+ 0x04, 0xe0, 0x9f, 0xe5, // ldr lr, L2
+ 0x0e, 0xe0, 0x8f, 0xe0, // L1: add lr, pc, lr
+ 0x08, 0xf0, 0xbe, 0xe5, // ldr pc, [lr, #8]
+ 0x00, 0x00, 0x00, 0x00, // L2: .word &(.got.plt) - L1 - 8
+ 0xd4, 0xd4, 0xd4, 0xd4, // Pad to 32-byte boundary
+ 0xd4, 0xd4, 0xd4, 0xd4, // Pad to 32-byte boundary
+ 0xd4, 0xd4, 0xd4, 0xd4};
+ memcpy(Buf, PltData, sizeof(PltData));
+ uint64_t GotPlt = In.GotPlt->getVA();
+ uint64_t L1 = In.Plt->getVA() + 8;
+ write32le(Buf + 16, GotPlt - L1 - 8);
+}
+
+// The default PLT header requires the .plt.got to be within 128 Mb of the
+// .plt in the positive direction.
+void ARM::writePltHeader(uint8_t *Buf) const {
+ // Use a similar sequence to that in writePlt(), the difference is the calling
+ // conventions mean we use lr instead of ip. The PLT entry is responsible for
+ // saving lr on the stack, the dynamic loader is responsible for reloading
+ // it.
+ const uint32_t PltData[] = {
+ 0xe52de004, // L1: str lr, [sp,#-4]!
+ 0xe28fe600, // add lr, pc, #0x0NN00000 &(.got.plt - L1 - 4)
+ 0xe28eea00, // add lr, lr, #0x000NN000 &(.got.plt - L1 - 4)
+ 0xe5bef000, // ldr pc, [lr, #0x00000NNN] &(.got.plt -L1 - 4)
+ };
+
+ uint64_t Offset = In.GotPlt->getVA() - In.Plt->getVA() - 4;
+ if (!llvm::isUInt<27>(Offset)) {
+ // We cannot encode the Offset, use the long form.
+ writePltHeaderLong(Buf);
+ return;
+ }
+ write32le(Buf + 0, PltData[0]);
+ write32le(Buf + 4, PltData[1] | ((Offset >> 20) & 0xff));
+ write32le(Buf + 8, PltData[2] | ((Offset >> 12) & 0xff));
+ write32le(Buf + 12, PltData[3] | (Offset & 0xfff));
+ memcpy(Buf + 16, TrapInstr.data(), 4); // Pad to 32-byte boundary
+ memcpy(Buf + 20, TrapInstr.data(), 4);
+ memcpy(Buf + 24, TrapInstr.data(), 4);
+ memcpy(Buf + 28, TrapInstr.data(), 4);
+}
+
+void ARM::addPltHeaderSymbols(InputSection &IS) const {
+ addSyntheticLocal("$a", STT_NOTYPE, 0, 0, IS);
+ addSyntheticLocal("$d", STT_NOTYPE, 16, 0, IS);
+}
+
+// Long form PLT entries that do not have any restrictions on the displacement
+// of the .plt from the .plt.got.
+static void writePltLong(uint8_t *Buf, uint64_t GotPltEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) {
+ const uint8_t PltData[] = {
+ 0x04, 0xc0, 0x9f, 0xe5, // ldr ip, L2
+ 0x0f, 0xc0, 0x8c, 0xe0, // L1: add ip, ip, pc
+ 0x00, 0xf0, 0x9c, 0xe5, // ldr pc, [ip]
+ 0x00, 0x00, 0x00, 0x00, // L2: .word Offset(&(.plt.got) - L1 - 8
+ };
+ memcpy(Buf, PltData, sizeof(PltData));
+ uint64_t L1 = PltEntryAddr + 4;
+ write32le(Buf + 12, GotPltEntryAddr - L1 - 8);
+}
+
+// The default PLT entries require the .plt.got to be within 128 Mb of the
+// .plt in the positive direction.
+void ARM::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const {
+ // The PLT entry is similar to the example given in Appendix A of ELF for
+ // the Arm Architecture. Instead of using the Group Relocations to find the
+ // optimal rotation for the 8-bit immediate used in the add instructions we
+ // hard code the most compact rotations for simplicity. This saves a load
+ // instruction over the long plt sequences.
+ const uint32_t PltData[] = {
+ 0xe28fc600, // L1: add ip, pc, #0x0NN00000 Offset(&(.plt.got) - L1 - 8
+ 0xe28cca00, // add ip, ip, #0x000NN000 Offset(&(.plt.got) - L1 - 8
+ 0xe5bcf000, // ldr pc, [ip, #0x00000NNN] Offset(&(.plt.got) - L1 - 8
+ };
+
+ uint64_t Offset = GotPltEntryAddr - PltEntryAddr - 8;
+ if (!llvm::isUInt<27>(Offset)) {
+ // We cannot encode the Offset, use the long form.
+ writePltLong(Buf, GotPltEntryAddr, PltEntryAddr, Index, RelOff);
+ return;
+ }
+ write32le(Buf + 0, PltData[0] | ((Offset >> 20) & 0xff));
+ write32le(Buf + 4, PltData[1] | ((Offset >> 12) & 0xff));
+ write32le(Buf + 8, PltData[2] | (Offset & 0xfff));
+ memcpy(Buf + 12, TrapInstr.data(), 4); // Pad to 16-byte boundary
+}
+
+void ARM::addPltSymbols(InputSection &IS, uint64_t Off) const {
+ addSyntheticLocal("$a", STT_NOTYPE, Off, 0, IS);
+ addSyntheticLocal("$d", STT_NOTYPE, Off + 12, 0, IS);
+}
+
+bool ARM::needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
+ uint64_t BranchAddr, const Symbol &S) const {
+ // If S is an undefined weak symbol and does not have a PLT entry then it
+ // will be resolved as a branch to the next instruction.
+ if (S.isUndefWeak() && !S.isInPlt())
+ return false;
+ // A state change from ARM to Thumb and vice versa must go through an
+ // interworking thunk if the relocation type is not R_ARM_CALL or
+ // R_ARM_THM_CALL.
+ switch (Type) {
+ case R_ARM_PC24:
+ case R_ARM_PLT32:
+ case R_ARM_JUMP24:
+ // Source is ARM, all PLT entries are ARM so no interworking required.
+ // Otherwise we need to interwork if Symbol has bit 0 set (Thumb).
+ if (Expr == R_PC && ((S.getVA() & 1) == 1))
+ return true;
+ LLVM_FALLTHROUGH;
+ case R_ARM_CALL: {
+ uint64_t Dst = (Expr == R_PLT_PC) ? S.getPltVA() : S.getVA();
+ return !inBranchRange(Type, BranchAddr, Dst);
+ }
+ case R_ARM_THM_JUMP19:
+ case R_ARM_THM_JUMP24:
+ // Source is Thumb, all PLT entries are ARM so interworking is required.
+ // Otherwise we need to interwork if Symbol has bit 0 clear (ARM).
+ if (Expr == R_PLT_PC || ((S.getVA() & 1) == 0))
+ return true;
+ LLVM_FALLTHROUGH;
+ case R_ARM_THM_CALL: {
+ uint64_t Dst = (Expr == R_PLT_PC) ? S.getPltVA() : S.getVA();
+ return !inBranchRange(Type, BranchAddr, Dst);
+ }
+ }
+ return false;
+}
+
+uint32_t ARM::getThunkSectionSpacing() const {
+ // The placing of pre-created ThunkSections is controlled by the value
+ // ThunkSectionSpacing returned by getThunkSectionSpacing(). The aim is to
+ // place the ThunkSection such that all branches from the InputSections
+ // prior to the ThunkSection can reach a Thunk placed at the end of the
+ // ThunkSection. Graphically:
+ // | up to ThunkSectionSpacing .text input sections |
+ // | ThunkSection |
+ // | up to ThunkSectionSpacing .text input sections |
+ // | ThunkSection |
+
+ // Pre-created ThunkSections are spaced roughly 16MiB apart on ARMv7. This
+ // is to match the most common expected case of a Thumb 2 encoded BL, BLX or
+ // B.W:
+ // ARM B, BL, BLX range +/- 32MiB
+ // Thumb B.W, BL, BLX range +/- 16MiB
+ // Thumb B<cc>.W range +/- 1MiB
+ // If a branch cannot reach a pre-created ThunkSection a new one will be
+ // created so we can handle the rare cases of a Thumb 2 conditional branch.
+ // We intentionally use a lower size for ThunkSectionSpacing than the maximum
+ // branch range so the end of the ThunkSection is more likely to be within
+ // range of the branch instruction that is furthest away. The value we shorten
+ // ThunkSectionSpacing by is set conservatively to allow us to create 16,384
+ // 12 byte Thunks at any offset in a ThunkSection without risk of a branch to
+ // one of the Thunks going out of range.
+
+ // On Arm the ThunkSectionSpacing depends on the range of the Thumb Branch
+ // range. On earlier Architectures such as ARMv4, ARMv5 and ARMv6 (except
+ // ARMv6T2) the range is +/- 4MiB.
+
+ return (Config->ARMJ1J2BranchEncoding) ? 0x1000000 - 0x30000
+ : 0x400000 - 0x7500;
+}
+
+bool ARM::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const {
+ uint64_t Range;
+ uint64_t InstrSize;
+
+ switch (Type) {
+ case R_ARM_PC24:
+ case R_ARM_PLT32:
+ case R_ARM_JUMP24:
+ case R_ARM_CALL:
+ Range = 0x2000000;
+ InstrSize = 4;
+ break;
+ case R_ARM_THM_JUMP19:
+ Range = 0x100000;
+ InstrSize = 2;
+ break;
+ case R_ARM_THM_JUMP24:
+ case R_ARM_THM_CALL:
+ Range = Config->ARMJ1J2BranchEncoding ? 0x1000000 : 0x400000;
+ InstrSize = 2;
+ break;
+ default:
+ return true;
+ }
+ // PC at Src is 2 instructions ahead, immediate of branch is signed
+ if (Src > Dst)
+ Range -= 2 * InstrSize;
+ else
+ Range += InstrSize;
+
+ if ((Dst & 0x1) == 0)
+ // Destination is ARM, if ARM caller then Src is already 4-byte aligned.
+ // If Thumb Caller (BLX) the Src address has bottom 2 bits cleared to ensure
+ // destination will be 4 byte aligned.
+ Src &= ~0x3;
+ else
+ // Bit 0 == 1 denotes Thumb state, it is not part of the range
+ Dst &= ~0x1;
+
+ uint64_t Distance = (Src > Dst) ? Src - Dst : Dst - Src;
+ return Distance <= Range;
+}
+
+void ARM::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
+ switch (Type) {
+ case R_ARM_ABS32:
+ case R_ARM_BASE_PREL:
+ case R_ARM_GLOB_DAT:
+ case R_ARM_GOTOFF32:
+ case R_ARM_GOT_BREL:
+ case R_ARM_GOT_PREL:
+ case R_ARM_REL32:
+ case R_ARM_RELATIVE:
+ case R_ARM_SBREL32:
+ case R_ARM_TARGET1:
+ case R_ARM_TARGET2:
+ case R_ARM_TLS_GD32:
+ case R_ARM_TLS_IE32:
+ case R_ARM_TLS_LDM32:
+ case R_ARM_TLS_LDO32:
+ case R_ARM_TLS_LE32:
+ case R_ARM_TLS_TPOFF32:
+ case R_ARM_TLS_DTPOFF32:
+ write32le(Loc, Val);
+ break;
+ case R_ARM_TLS_DTPMOD32:
+ write32le(Loc, 1);
+ break;
+ case R_ARM_PREL31:
+ checkInt(Loc, Val, 31, Type);
+ write32le(Loc, (read32le(Loc) & 0x80000000) | (Val & ~0x80000000));
+ break;
+ case R_ARM_CALL:
+ // R_ARM_CALL is used for BL and BLX instructions, depending on the
+ // value of bit 0 of Val, we must select a BL or BLX instruction
+ if (Val & 1) {
+ // If bit 0 of Val is 1 the target is Thumb, we must select a BLX.
+ // The BLX encoding is 0xfa:H:imm24 where Val = imm24:H:'1'
+ checkInt(Loc, Val, 26, Type);
+ write32le(Loc, 0xfa000000 | // opcode
+ ((Val & 2) << 23) | // H
+ ((Val >> 2) & 0x00ffffff)); // imm24
+ break;
+ }
+ if ((read32le(Loc) & 0xfe000000) == 0xfa000000)
+ // BLX (always unconditional) instruction to an ARM Target, select an
+ // unconditional BL.
+ write32le(Loc, 0xeb000000 | (read32le(Loc) & 0x00ffffff));
+ // fall through as BL encoding is shared with B
+ LLVM_FALLTHROUGH;
+ case R_ARM_JUMP24:
+ case R_ARM_PC24:
+ case R_ARM_PLT32:
+ checkInt(Loc, Val, 26, Type);
+ write32le(Loc, (read32le(Loc) & ~0x00ffffff) | ((Val >> 2) & 0x00ffffff));
+ break;
+ case R_ARM_THM_JUMP11:
+ checkInt(Loc, Val, 12, Type);
+ write16le(Loc, (read32le(Loc) & 0xf800) | ((Val >> 1) & 0x07ff));
+ break;
+ case R_ARM_THM_JUMP19:
+ // Encoding T3: Val = S:J2:J1:imm6:imm11:0
+ checkInt(Loc, Val, 21, Type);
+ write16le(Loc,
+ (read16le(Loc) & 0xfbc0) | // opcode cond
+ ((Val >> 10) & 0x0400) | // S
+ ((Val >> 12) & 0x003f)); // imm6
+ write16le(Loc + 2,
+ 0x8000 | // opcode
+ ((Val >> 8) & 0x0800) | // J2
+ ((Val >> 5) & 0x2000) | // J1
+ ((Val >> 1) & 0x07ff)); // imm11
+ break;
+ case R_ARM_THM_CALL:
+ // R_ARM_THM_CALL is used for BL and BLX instructions, depending on the
+ // value of bit 0 of Val, we must select a BL or BLX instruction
+ if ((Val & 1) == 0) {
+ // Ensure BLX destination is 4-byte aligned. As BLX instruction may
+ // only be two byte aligned. This must be done before overflow check
+ Val = alignTo(Val, 4);
+ }
+ // Bit 12 is 0 for BLX, 1 for BL
+ write16le(Loc + 2, (read16le(Loc + 2) & ~0x1000) | (Val & 1) << 12);
+ if (!Config->ARMJ1J2BranchEncoding) {
+ // Older Arm architectures do not support R_ARM_THM_JUMP24 and have
+ // different encoding rules and range due to J1 and J2 always being 1.
+ checkInt(Loc, Val, 23, Type);
+ write16le(Loc,
+ 0xf000 | // opcode
+ ((Val >> 12) & 0x07ff)); // imm11
+ write16le(Loc + 2,
+ (read16le(Loc + 2) & 0xd000) | // opcode
+ 0x2800 | // J1 == J2 == 1
+ ((Val >> 1) & 0x07ff)); // imm11
+ break;
+ }
+ // Fall through as rest of encoding is the same as B.W
+ LLVM_FALLTHROUGH;
+ case R_ARM_THM_JUMP24:
+ // Encoding B T4, BL T1, BLX T2: Val = S:I1:I2:imm10:imm11:0
+ checkInt(Loc, Val, 25, Type);
+ write16le(Loc,
+ 0xf000 | // opcode
+ ((Val >> 14) & 0x0400) | // S
+ ((Val >> 12) & 0x03ff)); // imm10
+ write16le(Loc + 2,
+ (read16le(Loc + 2) & 0xd000) | // opcode
+ (((~(Val >> 10)) ^ (Val >> 11)) & 0x2000) | // J1
+ (((~(Val >> 11)) ^ (Val >> 13)) & 0x0800) | // J2
+ ((Val >> 1) & 0x07ff)); // imm11
+ break;
+ case R_ARM_MOVW_ABS_NC:
+ case R_ARM_MOVW_PREL_NC:
+ write32le(Loc, (read32le(Loc) & ~0x000f0fff) | ((Val & 0xf000) << 4) |
+ (Val & 0x0fff));
+ break;
+ case R_ARM_MOVT_ABS:
+ case R_ARM_MOVT_PREL:
+ write32le(Loc, (read32le(Loc) & ~0x000f0fff) |
+ (((Val >> 16) & 0xf000) << 4) | ((Val >> 16) & 0xfff));
+ break;
+ case R_ARM_THM_MOVT_ABS:
+ case R_ARM_THM_MOVT_PREL:
+ // Encoding T1: A = imm4:i:imm3:imm8
+ write16le(Loc,
+ 0xf2c0 | // opcode
+ ((Val >> 17) & 0x0400) | // i
+ ((Val >> 28) & 0x000f)); // imm4
+ write16le(Loc + 2,
+ (read16le(Loc + 2) & 0x8f00) | // opcode
+ ((Val >> 12) & 0x7000) | // imm3
+ ((Val >> 16) & 0x00ff)); // imm8
+ break;
+ case R_ARM_THM_MOVW_ABS_NC:
+ case R_ARM_THM_MOVW_PREL_NC:
+ // Encoding T3: A = imm4:i:imm3:imm8
+ write16le(Loc,
+ 0xf240 | // opcode
+ ((Val >> 1) & 0x0400) | // i
+ ((Val >> 12) & 0x000f)); // imm4
+ write16le(Loc + 2,
+ (read16le(Loc + 2) & 0x8f00) | // opcode
+ ((Val << 4) & 0x7000) | // imm3
+ (Val & 0x00ff)); // imm8
+ break;
+ default:
+ error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
+ }
+}
+
+int64_t ARM::getImplicitAddend(const uint8_t *Buf, RelType Type) const {
+ switch (Type) {
+ default:
+ return 0;
+ case R_ARM_ABS32:
+ case R_ARM_BASE_PREL:
+ case R_ARM_GOTOFF32:
+ case R_ARM_GOT_BREL:
+ case R_ARM_GOT_PREL:
+ case R_ARM_REL32:
+ case R_ARM_TARGET1:
+ case R_ARM_TARGET2:
+ case R_ARM_TLS_GD32:
+ case R_ARM_TLS_LDM32:
+ case R_ARM_TLS_LDO32:
+ case R_ARM_TLS_IE32:
+ case R_ARM_TLS_LE32:
+ return SignExtend64<32>(read32le(Buf));
+ case R_ARM_PREL31:
+ return SignExtend64<31>(read32le(Buf));
+ case R_ARM_CALL:
+ case R_ARM_JUMP24:
+ case R_ARM_PC24:
+ case R_ARM_PLT32:
+ return SignExtend64<26>(read32le(Buf) << 2);
+ case R_ARM_THM_JUMP11:
+ return SignExtend64<12>(read16le(Buf) << 1);
+ case R_ARM_THM_JUMP19: {
+ // Encoding T3: A = S:J2:J1:imm10:imm6:0
+ uint16_t Hi = read16le(Buf);
+ uint16_t Lo = read16le(Buf + 2);
+ return SignExtend64<20>(((Hi & 0x0400) << 10) | // S
+ ((Lo & 0x0800) << 8) | // J2
+ ((Lo & 0x2000) << 5) | // J1
+ ((Hi & 0x003f) << 12) | // imm6
+ ((Lo & 0x07ff) << 1)); // imm11:0
+ }
+ case R_ARM_THM_CALL:
+ if (!Config->ARMJ1J2BranchEncoding) {
+ // Older Arm architectures do not support R_ARM_THM_JUMP24 and have
+ // different encoding rules and range due to J1 and J2 always being 1.
+ uint16_t Hi = read16le(Buf);
+ uint16_t Lo = read16le(Buf + 2);
+ return SignExtend64<22>(((Hi & 0x7ff) << 12) | // imm11
+ ((Lo & 0x7ff) << 1)); // imm11:0
+ break;
+ }
+ LLVM_FALLTHROUGH;
+ case R_ARM_THM_JUMP24: {
+ // Encoding B T4, BL T1, BLX T2: A = S:I1:I2:imm10:imm11:0
+ // I1 = NOT(J1 EOR S), I2 = NOT(J2 EOR S)
+ uint16_t Hi = read16le(Buf);
+ uint16_t Lo = read16le(Buf + 2);
+ return SignExtend64<24>(((Hi & 0x0400) << 14) | // S
+ (~((Lo ^ (Hi << 3)) << 10) & 0x00800000) | // I1
+ (~((Lo ^ (Hi << 1)) << 11) & 0x00400000) | // I2
+ ((Hi & 0x003ff) << 12) | // imm0
+ ((Lo & 0x007ff) << 1)); // imm11:0
+ }
+ // ELF for the ARM Architecture 4.6.1.1 the implicit addend for MOVW and
+ // MOVT is in the range -32768 <= A < 32768
+ case R_ARM_MOVW_ABS_NC:
+ case R_ARM_MOVT_ABS:
+ case R_ARM_MOVW_PREL_NC:
+ case R_ARM_MOVT_PREL: {
+ uint64_t Val = read32le(Buf) & 0x000f0fff;
+ return SignExtend64<16>(((Val & 0x000f0000) >> 4) | (Val & 0x00fff));
+ }
+ case R_ARM_THM_MOVW_ABS_NC:
+ case R_ARM_THM_MOVT_ABS:
+ case R_ARM_THM_MOVW_PREL_NC:
+ case R_ARM_THM_MOVT_PREL: {
+ // Encoding T3: A = imm4:i:imm3:imm8
+ uint16_t Hi = read16le(Buf);
+ uint16_t Lo = read16le(Buf + 2);
+ return SignExtend64<16>(((Hi & 0x000f) << 12) | // imm4
+ ((Hi & 0x0400) << 1) | // i
+ ((Lo & 0x7000) >> 4) | // imm3
+ (Lo & 0x00ff)); // imm8
+ }
+ }
+}
+
+TargetInfo *elf::getARMTargetInfo() {
+ static ARM Target;
+ return &Target;
+}
diff --git a/contrib/llvm/tools/lld/ELF/Arch/AVR.cpp b/contrib/llvm/tools/lld/ELF/Arch/AVR.cpp
new file mode 100644
index 000000000000..637da3778bd2
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Arch/AVR.cpp
@@ -0,0 +1,77 @@
+//===- AVR.cpp ------------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// AVR is a Harvard-architecture 8-bit micrcontroller designed for small
+// baremetal programs. All AVR-family processors have 32 8-bit registers.
+// The tiniest AVR has 32 byte RAM and 1 KiB program memory, and the largest
+// one supports up to 2^24 data address space and 2^22 code address space.
+//
+// Since it is a baremetal programming, there's usually no loader to load
+// ELF files on AVRs. You are expected to link your program against address
+// 0 and pull out a .text section from the result using objcopy, so that you
+// can write the linked code to on-chip flush memory. You can do that with
+// the following commands:
+//
+// ld.lld -Ttext=0 -o foo foo.o
+// objcopy -O binary --only-section=.text foo output.bin
+//
+// Note that the current AVR support is very preliminary so you can't
+// link any useful program yet, though.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "Target.h"
+#include "lld/Common/ErrorHandler.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+class AVR final : public TargetInfo {
+public:
+ AVR();
+ RelExpr getRelExpr(RelType Type, const Symbol &S,
+ const uint8_t *Loc) const override;
+ void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+};
+} // namespace
+
+AVR::AVR() { NoneRel = R_AVR_NONE; }
+
+RelExpr AVR::getRelExpr(RelType Type, const Symbol &S,
+ const uint8_t *Loc) const {
+ return R_ABS;
+}
+
+void AVR::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
+ switch (Type) {
+ case R_AVR_CALL: {
+ uint16_t Hi = Val >> 17;
+ uint16_t Lo = Val >> 1;
+ write16le(Loc, read16le(Loc) | ((Hi >> 1) << 4) | (Hi & 1));
+ write16le(Loc + 2, Lo);
+ break;
+ }
+ default:
+ error(getErrorLocation(Loc) + "unrecognized reloc " + toString(Type));
+ }
+}
+
+TargetInfo *elf::getAVRTargetInfo() {
+ static AVR Target;
+ return &Target;
+}
diff --git a/contrib/llvm/tools/lld/ELF/Arch/Hexagon.cpp b/contrib/llvm/tools/lld/ELF/Arch/Hexagon.cpp
new file mode 100644
index 000000000000..b4d33be2ad39
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Arch/Hexagon.cpp
@@ -0,0 +1,292 @@
+//===-- Hexagon.cpp -------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "lld/Common/ErrorHandler.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+class Hexagon final : public TargetInfo {
+public:
+ Hexagon();
+ uint32_t calcEFlags() const override;
+ RelExpr getRelExpr(RelType Type, const Symbol &S,
+ const uint8_t *Loc) const override;
+ void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+ void writePltHeader(uint8_t *Buf) const override;
+ void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
+ int32_t Index, unsigned RelOff) const override;
+};
+} // namespace
+
+Hexagon::Hexagon() {
+ PltRel = R_HEX_JMP_SLOT;
+ RelativeRel = R_HEX_RELATIVE;
+ GotRel = R_HEX_GLOB_DAT;
+ GotEntrySize = 4;
+ // The zero'th GOT entry is reserved for the address of _DYNAMIC. The
+ // next 3 are reserved for the dynamic loader.
+ GotPltHeaderEntriesNum = 4;
+ GotPltEntrySize = 4;
+
+ PltEntrySize = 16;
+ PltHeaderSize = 32;
+
+ // Hexagon Linux uses 64K pages by default.
+ DefaultMaxPageSize = 0x10000;
+ NoneRel = R_HEX_NONE;
+}
+
+uint32_t Hexagon::calcEFlags() const {
+ assert(!ObjectFiles.empty());
+
+ // The architecture revision must always be equal to or greater than
+ // greatest revision in the list of inputs.
+ uint32_t Ret = 0;
+ for (InputFile *F : ObjectFiles) {
+ uint32_t EFlags = cast<ObjFile<ELF32LE>>(F)->getObj().getHeader()->e_flags;
+ if (EFlags > Ret)
+ Ret = EFlags;
+ }
+ return Ret;
+}
+
+static uint32_t applyMask(uint32_t Mask, uint32_t Data) {
+ uint32_t Result = 0;
+ size_t Off = 0;
+
+ for (size_t Bit = 0; Bit != 32; ++Bit) {
+ uint32_t ValBit = (Data >> Off) & 1;
+ uint32_t MaskBit = (Mask >> Bit) & 1;
+ if (MaskBit) {
+ Result |= (ValBit << Bit);
+ ++Off;
+ }
+ }
+ return Result;
+}
+
+RelExpr Hexagon::getRelExpr(RelType Type, const Symbol &S,
+ const uint8_t *Loc) const {
+ switch (Type) {
+ case R_HEX_B9_PCREL:
+ case R_HEX_B9_PCREL_X:
+ case R_HEX_B13_PCREL:
+ case R_HEX_B15_PCREL:
+ case R_HEX_B15_PCREL_X:
+ case R_HEX_6_PCREL_X:
+ case R_HEX_32_PCREL:
+ return R_PC;
+ case R_HEX_B22_PCREL:
+ case R_HEX_PLT_B22_PCREL:
+ case R_HEX_B22_PCREL_X:
+ case R_HEX_B32_PCREL_X:
+ return R_PLT_PC;
+ case R_HEX_GOT_11_X:
+ case R_HEX_GOT_16_X:
+ case R_HEX_GOT_32_6_X:
+ return R_HEXAGON_GOT;
+ default:
+ return R_ABS;
+ }
+}
+
+static uint32_t findMaskR6(uint32_t Insn) {
+ // There are (arguably too) many relocation masks for the DSP's
+ // R_HEX_6_X type. The table below is used to select the correct mask
+ // for the given instruction.
+ struct InstructionMask {
+ uint32_t CmpMask;
+ uint32_t RelocMask;
+ };
+
+ static const InstructionMask R6[] = {
+ {0x38000000, 0x0000201f}, {0x39000000, 0x0000201f},
+ {0x3e000000, 0x00001f80}, {0x3f000000, 0x00001f80},
+ {0x40000000, 0x000020f8}, {0x41000000, 0x000007e0},
+ {0x42000000, 0x000020f8}, {0x43000000, 0x000007e0},
+ {0x44000000, 0x000020f8}, {0x45000000, 0x000007e0},
+ {0x46000000, 0x000020f8}, {0x47000000, 0x000007e0},
+ {0x6a000000, 0x00001f80}, {0x7c000000, 0x001f2000},
+ {0x9a000000, 0x00000f60}, {0x9b000000, 0x00000f60},
+ {0x9c000000, 0x00000f60}, {0x9d000000, 0x00000f60},
+ {0x9f000000, 0x001f0100}, {0xab000000, 0x0000003f},
+ {0xad000000, 0x0000003f}, {0xaf000000, 0x00030078},
+ {0xd7000000, 0x006020e0}, {0xd8000000, 0x006020e0},
+ {0xdb000000, 0x006020e0}, {0xdf000000, 0x006020e0}};
+
+ // Duplex forms have a fixed mask and parse bits 15:14 are always
+ // zero. Non-duplex insns will always have at least one bit set in the
+ // parse field.
+ if ((0xC000 & Insn) == 0x0)
+ return 0x03f00000;
+
+ for (InstructionMask I : R6)
+ if ((0xff000000 & Insn) == I.CmpMask)
+ return I.RelocMask;
+
+ error("unrecognized instruction for R_HEX_6 relocation: 0x" +
+ utohexstr(Insn));
+ return 0;
+}
+
+static uint32_t findMaskR8(uint32_t Insn) {
+ if ((0xff000000 & Insn) == 0xde000000)
+ return 0x00e020e8;
+ if ((0xff000000 & Insn) == 0x3c000000)
+ return 0x0000207f;
+ return 0x00001fe0;
+}
+
+static uint32_t findMaskR11(uint32_t Insn) {
+ if ((0xff000000 & Insn) == 0xa1000000)
+ return 0x060020ff;
+ return 0x06003fe0;
+}
+
+static uint32_t findMaskR16(uint32_t Insn) {
+ if ((0xff000000 & Insn) == 0x48000000)
+ return 0x061f20ff;
+ if ((0xff000000 & Insn) == 0x49000000)
+ return 0x061f3fe0;
+ if ((0xff000000 & Insn) == 0x78000000)
+ return 0x00df3fe0;
+ if ((0xff000000 & Insn) == 0xb0000000)
+ return 0x0fe03fe0;
+
+ error("unrecognized instruction for R_HEX_16_X relocation: 0x" +
+ utohexstr(Insn));
+ return 0;
+}
+
+static void or32le(uint8_t *P, int32_t V) { write32le(P, read32le(P) | V); }
+
+void Hexagon::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
+ switch (Type) {
+ case R_HEX_NONE:
+ break;
+ case R_HEX_6_PCREL_X:
+ case R_HEX_6_X:
+ or32le(Loc, applyMask(findMaskR6(read32le(Loc)), Val));
+ break;
+ case R_HEX_8_X:
+ or32le(Loc, applyMask(findMaskR8(read32le(Loc)), Val));
+ break;
+ case R_HEX_9_X:
+ or32le(Loc, applyMask(0x00003fe0, Val & 0x3f));
+ break;
+ case R_HEX_10_X:
+ or32le(Loc, applyMask(0x00203fe0, Val & 0x3f));
+ break;
+ case R_HEX_11_X:
+ case R_HEX_GOT_11_X:
+ or32le(Loc, applyMask(findMaskR11(read32le(Loc)), Val & 0x3f));
+ break;
+ case R_HEX_12_X:
+ or32le(Loc, applyMask(0x000007e0, Val));
+ break;
+ case R_HEX_16_X: // These relocs only have 6 effective bits.
+ case R_HEX_GOT_16_X:
+ or32le(Loc, applyMask(findMaskR16(read32le(Loc)), Val & 0x3f));
+ break;
+ case R_HEX_32:
+ case R_HEX_32_PCREL:
+ or32le(Loc, Val);
+ break;
+ case R_HEX_32_6_X:
+ case R_HEX_GOT_32_6_X:
+ or32le(Loc, applyMask(0x0fff3fff, Val >> 6));
+ break;
+ case R_HEX_B9_PCREL:
+ or32le(Loc, applyMask(0x003000fe, Val >> 2));
+ break;
+ case R_HEX_B9_PCREL_X:
+ or32le(Loc, applyMask(0x003000fe, Val & 0x3f));
+ break;
+ case R_HEX_B13_PCREL:
+ or32le(Loc, applyMask(0x00202ffe, Val >> 2));
+ break;
+ case R_HEX_B15_PCREL:
+ or32le(Loc, applyMask(0x00df20fe, Val >> 2));
+ break;
+ case R_HEX_B15_PCREL_X:
+ or32le(Loc, applyMask(0x00df20fe, Val & 0x3f));
+ break;
+ case R_HEX_B22_PCREL:
+ case R_HEX_PLT_B22_PCREL:
+ or32le(Loc, applyMask(0x1ff3ffe, Val >> 2));
+ break;
+ case R_HEX_B22_PCREL_X:
+ or32le(Loc, applyMask(0x1ff3ffe, Val & 0x3f));
+ break;
+ case R_HEX_B32_PCREL_X:
+ or32le(Loc, applyMask(0x0fff3fff, Val >> 6));
+ break;
+ case R_HEX_HI16:
+ or32le(Loc, applyMask(0x00c03fff, Val >> 16));
+ break;
+ case R_HEX_LO16:
+ or32le(Loc, applyMask(0x00c03fff, Val));
+ break;
+ default:
+ error(getErrorLocation(Loc) + "unrecognized reloc " + toString(Type));
+ break;
+ }
+}
+
+void Hexagon::writePltHeader(uint8_t *Buf) const {
+ const uint8_t PltData[] = {
+ 0x00, 0x40, 0x00, 0x00, // { immext (#0)
+ 0x1c, 0xc0, 0x49, 0x6a, // r28 = add (pc, ##GOT0@PCREL) } # @GOT0
+ 0x0e, 0x42, 0x9c, 0xe2, // { r14 -= add (r28, #16) # offset of GOTn
+ 0x4f, 0x40, 0x9c, 0x91, // r15 = memw (r28 + #8) # object ID at GOT2
+ 0x3c, 0xc0, 0x9c, 0x91, // r28 = memw (r28 + #4) }# dynamic link at GOT1
+ 0x0e, 0x42, 0x0e, 0x8c, // { r14 = asr (r14, #2) # index of PLTn
+ 0x00, 0xc0, 0x9c, 0x52, // jumpr r28 } # call dynamic linker
+ 0x0c, 0xdb, 0x00, 0x54, // trap0(#0xdb) # bring plt0 into 16byte alignment
+ };
+ memcpy(Buf, PltData, sizeof(PltData));
+
+ // Offset from PLT0 to the GOT.
+ uint64_t Off = In.GotPlt->getVA() - In.Plt->getVA();
+ relocateOne(Buf, R_HEX_B32_PCREL_X, Off);
+ relocateOne(Buf + 4, R_HEX_6_PCREL_X, Off);
+}
+
+void Hexagon::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const {
+ const uint8_t Inst[] = {
+ 0x00, 0x40, 0x00, 0x00, // { immext (#0)
+ 0x0e, 0xc0, 0x49, 0x6a, // r14 = add (pc, ##GOTn@PCREL) }
+ 0x1c, 0xc0, 0x8e, 0x91, // r28 = memw (r14)
+ 0x00, 0xc0, 0x9c, 0x52, // jumpr r28
+ };
+ memcpy(Buf, Inst, sizeof(Inst));
+
+ relocateOne(Buf, R_HEX_B32_PCREL_X, GotPltEntryAddr - PltEntryAddr);
+ relocateOne(Buf + 4, R_HEX_6_PCREL_X, GotPltEntryAddr - PltEntryAddr);
+}
+
+TargetInfo *elf::getHexagonTargetInfo() {
+ static Hexagon Target;
+ return &Target;
+}
diff --git a/contrib/llvm/tools/lld/ELF/Arch/MSP430.cpp b/contrib/llvm/tools/lld/ELF/Arch/MSP430.cpp
new file mode 100644
index 000000000000..fe0c0fe64daf
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Arch/MSP430.cpp
@@ -0,0 +1,94 @@
+//===- MSP430.cpp ---------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// The MSP430 is a 16-bit microcontroller RISC architecture. The instruction set
+// has only 27 core instructions orthogonally augmented with a variety
+// of addressing modes for source and destination operands. Entire address space
+// of MSP430 is 64KB (the extended MSP430X architecture is not considered here).
+// A typical MSP430 MCU has several kilobytes of RAM and ROM, plenty
+// of peripherals and is generally optimized for a low power consumption.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "Target.h"
+#include "lld/Common/ErrorHandler.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+class MSP430 final : public TargetInfo {
+public:
+ MSP430();
+ RelExpr getRelExpr(RelType Type, const Symbol &S,
+ const uint8_t *Loc) const override;
+ void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+};
+} // namespace
+
+MSP430::MSP430() {
+ // mov.b #0, r3
+ TrapInstr = {0x43, 0x43, 0x43, 0x43};
+}
+
+RelExpr MSP430::getRelExpr(RelType Type, const Symbol &S,
+ const uint8_t *Loc) const {
+ switch (Type) {
+ case R_MSP430_10_PCREL:
+ case R_MSP430_16_PCREL:
+ case R_MSP430_16_PCREL_BYTE:
+ case R_MSP430_2X_PCREL:
+ case R_MSP430_RL_PCREL:
+ case R_MSP430_SYM_DIFF:
+ return R_PC;
+ default:
+ return R_ABS;
+ }
+}
+
+void MSP430::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
+ switch (Type) {
+ case R_MSP430_8:
+ checkIntUInt(Loc, Val, 8, Type);
+ *Loc = Val;
+ break;
+ case R_MSP430_16:
+ case R_MSP430_16_PCREL:
+ case R_MSP430_16_BYTE:
+ case R_MSP430_16_PCREL_BYTE:
+ checkIntUInt(Loc, Val, 16, Type);
+ write16le(Loc, Val);
+ break;
+ case R_MSP430_32:
+ checkIntUInt(Loc, Val, 32, Type);
+ write32le(Loc, Val);
+ break;
+ case R_MSP430_10_PCREL: {
+ int16_t Offset = ((int16_t)Val >> 1) - 1;
+ checkInt(Loc, Offset, 10, Type);
+ write16le(Loc, (read16le(Loc) & 0xFC00) | (Offset & 0x3FF));
+ break;
+ }
+ default:
+ error(getErrorLocation(Loc) + "unrecognized reloc " + toString(Type));
+ }
+}
+
+TargetInfo *elf::getMSP430TargetInfo() {
+ static MSP430 Target;
+ return &Target;
+}
diff --git a/contrib/llvm/tools/lld/ELF/Arch/Mips.cpp b/contrib/llvm/tools/lld/ELF/Arch/Mips.cpp
new file mode 100644
index 000000000000..23b0c1dd8a2d
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Arch/Mips.cpp
@@ -0,0 +1,676 @@
+//===- MIPS.cpp -----------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InputFiles.h"
+#include "OutputSections.h"
+#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "Thunks.h"
+#include "lld/Common/ErrorHandler.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+template <class ELFT> class MIPS final : public TargetInfo {
+public:
+ MIPS();
+ uint32_t calcEFlags() const override;
+ RelExpr getRelExpr(RelType Type, const Symbol &S,
+ const uint8_t *Loc) const override;
+ int64_t getImplicitAddend(const uint8_t *Buf, RelType Type) const override;
+ RelType getDynRel(RelType Type) const override;
+ void writeGotPlt(uint8_t *Buf, const Symbol &S) const override;
+ void writePltHeader(uint8_t *Buf) const override;
+ void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
+ int32_t Index, unsigned RelOff) const override;
+ bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
+ uint64_t BranchAddr, const Symbol &S) const override;
+ void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+ bool usesOnlyLowPageBits(RelType Type) const override;
+};
+} // namespace
+
+template <class ELFT> MIPS<ELFT>::MIPS() {
+ GotPltHeaderEntriesNum = 2;
+ DefaultMaxPageSize = 65536;
+ GotEntrySize = sizeof(typename ELFT::uint);
+ GotPltEntrySize = sizeof(typename ELFT::uint);
+ GotBaseSymInGotPlt = false;
+ PltEntrySize = 16;
+ PltHeaderSize = 32;
+ CopyRel = R_MIPS_COPY;
+ NoneRel = R_MIPS_NONE;
+ PltRel = R_MIPS_JUMP_SLOT;
+ NeedsThunks = true;
+
+ // Set `sigrie 1` as a trap instruction.
+ write32(TrapInstr.data(), 0x04170001);
+
+ if (ELFT::Is64Bits) {
+ RelativeRel = (R_MIPS_64 << 8) | R_MIPS_REL32;
+ TlsGotRel = R_MIPS_TLS_TPREL64;
+ TlsModuleIndexRel = R_MIPS_TLS_DTPMOD64;
+ TlsOffsetRel = R_MIPS_TLS_DTPREL64;
+ } else {
+ RelativeRel = R_MIPS_REL32;
+ TlsGotRel = R_MIPS_TLS_TPREL32;
+ TlsModuleIndexRel = R_MIPS_TLS_DTPMOD32;
+ TlsOffsetRel = R_MIPS_TLS_DTPREL32;
+ }
+}
+
+template <class ELFT> uint32_t MIPS<ELFT>::calcEFlags() const {
+ return calcMipsEFlags<ELFT>();
+}
+
+template <class ELFT>
+RelExpr MIPS<ELFT>::getRelExpr(RelType Type, const Symbol &S,
+ const uint8_t *Loc) const {
+ // See comment in the calculateMipsRelChain.
+ if (ELFT::Is64Bits || Config->MipsN32Abi)
+ Type &= 0xff;
+
+ switch (Type) {
+ case R_MIPS_JALR:
+ case R_MICROMIPS_JALR:
+ return R_HINT;
+ case R_MIPS_GPREL16:
+ case R_MIPS_GPREL32:
+ case R_MICROMIPS_GPREL16:
+ case R_MICROMIPS_GPREL7_S2:
+ return R_MIPS_GOTREL;
+ case R_MIPS_26:
+ case R_MICROMIPS_26_S1:
+ return R_PLT;
+ case R_MICROMIPS_PC26_S1:
+ return R_PLT_PC;
+ case R_MIPS_HI16:
+ case R_MIPS_LO16:
+ case R_MIPS_HIGHER:
+ case R_MIPS_HIGHEST:
+ case R_MICROMIPS_HI16:
+ case R_MICROMIPS_LO16:
+ // R_MIPS_HI16/R_MIPS_LO16 relocations against _gp_disp calculate
+ // offset between start of function and 'gp' value which by default
+ // equal to the start of .got section. In that case we consider these
+ // relocations as relative.
+ if (&S == ElfSym::MipsGpDisp)
+ return R_MIPS_GOT_GP_PC;
+ if (&S == ElfSym::MipsLocalGp)
+ return R_MIPS_GOT_GP;
+ LLVM_FALLTHROUGH;
+ case R_MIPS_32:
+ case R_MIPS_64:
+ case R_MIPS_GOT_OFST:
+ case R_MIPS_SUB:
+ case R_MIPS_TLS_DTPREL_HI16:
+ case R_MIPS_TLS_DTPREL_LO16:
+ case R_MIPS_TLS_DTPREL32:
+ case R_MIPS_TLS_DTPREL64:
+ case R_MIPS_TLS_TPREL_HI16:
+ case R_MIPS_TLS_TPREL_LO16:
+ case R_MIPS_TLS_TPREL32:
+ case R_MIPS_TLS_TPREL64:
+ case R_MICROMIPS_TLS_DTPREL_HI16:
+ case R_MICROMIPS_TLS_DTPREL_LO16:
+ case R_MICROMIPS_TLS_TPREL_HI16:
+ case R_MICROMIPS_TLS_TPREL_LO16:
+ return R_ABS;
+ case R_MIPS_PC32:
+ case R_MIPS_PC16:
+ case R_MIPS_PC19_S2:
+ case R_MIPS_PC21_S2:
+ case R_MIPS_PC26_S2:
+ case R_MIPS_PCHI16:
+ case R_MIPS_PCLO16:
+ case R_MICROMIPS_PC7_S1:
+ case R_MICROMIPS_PC10_S1:
+ case R_MICROMIPS_PC16_S1:
+ case R_MICROMIPS_PC18_S3:
+ case R_MICROMIPS_PC19_S2:
+ case R_MICROMIPS_PC23_S2:
+ case R_MICROMIPS_PC21_S1:
+ return R_PC;
+ case R_MIPS_GOT16:
+ case R_MICROMIPS_GOT16:
+ if (S.isLocal())
+ return R_MIPS_GOT_LOCAL_PAGE;
+ LLVM_FALLTHROUGH;
+ case R_MIPS_CALL16:
+ case R_MIPS_GOT_DISP:
+ case R_MIPS_TLS_GOTTPREL:
+ case R_MICROMIPS_CALL16:
+ case R_MICROMIPS_TLS_GOTTPREL:
+ return R_MIPS_GOT_OFF;
+ case R_MIPS_CALL_HI16:
+ case R_MIPS_CALL_LO16:
+ case R_MIPS_GOT_HI16:
+ case R_MIPS_GOT_LO16:
+ case R_MICROMIPS_CALL_HI16:
+ case R_MICROMIPS_CALL_LO16:
+ case R_MICROMIPS_GOT_HI16:
+ case R_MICROMIPS_GOT_LO16:
+ return R_MIPS_GOT_OFF32;
+ case R_MIPS_GOT_PAGE:
+ return R_MIPS_GOT_LOCAL_PAGE;
+ case R_MIPS_TLS_GD:
+ case R_MICROMIPS_TLS_GD:
+ return R_MIPS_TLSGD;
+ case R_MIPS_TLS_LDM:
+ case R_MICROMIPS_TLS_LDM:
+ return R_MIPS_TLSLD;
+ case R_MIPS_NONE:
+ return R_NONE;
+ default:
+ return R_INVALID;
+ }
+}
+
+template <class ELFT> RelType MIPS<ELFT>::getDynRel(RelType Type) const {
+ if (Type == R_MIPS_32 || Type == R_MIPS_64)
+ return RelativeRel;
+ return R_MIPS_NONE;
+}
+
+template <class ELFT>
+void MIPS<ELFT>::writeGotPlt(uint8_t *Buf, const Symbol &) const {
+ uint64_t VA = In.Plt->getVA();
+ if (isMicroMips())
+ VA |= 1;
+ write32<ELFT::TargetEndianness>(Buf, VA);
+}
+
+template <endianness E> static uint32_t readShuffle(const uint8_t *Loc) {
+ // The major opcode of a microMIPS instruction needs to appear
+ // in the first 16-bit word (lowest address) for efficient hardware
+ // decode so that it knows if the instruction is 16-bit or 32-bit
+ // as early as possible. To do so, little-endian binaries keep 16-bit
+ // words in a big-endian order. That is why we have to swap these
+ // words to get a correct value.
+ uint32_t V = read32<E>(Loc);
+ if (E == support::little)
+ return (V << 16) | (V >> 16);
+ return V;
+}
+
+template <endianness E>
+static void writeValue(uint8_t *Loc, uint64_t V, uint8_t BitsSize,
+ uint8_t Shift) {
+ uint32_t Instr = read32<E>(Loc);
+ uint32_t Mask = 0xffffffff >> (32 - BitsSize);
+ uint32_t Data = (Instr & ~Mask) | ((V >> Shift) & Mask);
+ write32<E>(Loc, Data);
+}
+
+template <endianness E>
+static void writeShuffleValue(uint8_t *Loc, uint64_t V, uint8_t BitsSize,
+ uint8_t Shift) {
+ // See comments in readShuffle for purpose of this code.
+ uint16_t *Words = (uint16_t *)Loc;
+ if (E == support::little)
+ std::swap(Words[0], Words[1]);
+
+ writeValue<E>(Loc, V, BitsSize, Shift);
+
+ if (E == support::little)
+ std::swap(Words[0], Words[1]);
+}
+
+template <endianness E>
+static void writeMicroRelocation16(uint8_t *Loc, uint64_t V, uint8_t BitsSize,
+ uint8_t Shift) {
+ uint16_t Instr = read16<E>(Loc);
+ uint16_t Mask = 0xffff >> (16 - BitsSize);
+ uint16_t Data = (Instr & ~Mask) | ((V >> Shift) & Mask);
+ write16<E>(Loc, Data);
+}
+
+template <class ELFT> void MIPS<ELFT>::writePltHeader(uint8_t *Buf) const {
+ const endianness E = ELFT::TargetEndianness;
+ if (isMicroMips()) {
+ uint64_t GotPlt = In.GotPlt->getVA();
+ uint64_t Plt = In.Plt->getVA();
+ // Overwrite trap instructions written by Writer::writeTrapInstr.
+ memset(Buf, 0, PltHeaderSize);
+
+ write16<E>(Buf, isMipsR6() ? 0x7860 : 0x7980); // addiupc v1, (GOTPLT) - .
+ write16<E>(Buf + 4, 0xff23); // lw $25, 0($3)
+ write16<E>(Buf + 8, 0x0535); // subu16 $2, $2, $3
+ write16<E>(Buf + 10, 0x2525); // srl16 $2, $2, 2
+ write16<E>(Buf + 12, 0x3302); // addiu $24, $2, -2
+ write16<E>(Buf + 14, 0xfffe);
+ write16<E>(Buf + 16, 0x0dff); // move $15, $31
+ if (isMipsR6()) {
+ write16<E>(Buf + 18, 0x0f83); // move $28, $3
+ write16<E>(Buf + 20, 0x472b); // jalrc $25
+ write16<E>(Buf + 22, 0x0c00); // nop
+ relocateOne(Buf, R_MICROMIPS_PC19_S2, GotPlt - Plt);
+ } else {
+ write16<E>(Buf + 18, 0x45f9); // jalrc $25
+ write16<E>(Buf + 20, 0x0f83); // move $28, $3
+ write16<E>(Buf + 22, 0x0c00); // nop
+ relocateOne(Buf, R_MICROMIPS_PC23_S2, GotPlt - Plt);
+ }
+ return;
+ }
+
+ if (Config->MipsN32Abi) {
+ write32<E>(Buf, 0x3c0e0000); // lui $14, %hi(&GOTPLT[0])
+ write32<E>(Buf + 4, 0x8dd90000); // lw $25, %lo(&GOTPLT[0])($14)
+ write32<E>(Buf + 8, 0x25ce0000); // addiu $14, $14, %lo(&GOTPLT[0])
+ write32<E>(Buf + 12, 0x030ec023); // subu $24, $24, $14
+ write32<E>(Buf + 16, 0x03e07825); // move $15, $31
+ write32<E>(Buf + 20, 0x0018c082); // srl $24, $24, 2
+ } else if (ELFT::Is64Bits) {
+ write32<E>(Buf, 0x3c0e0000); // lui $14, %hi(&GOTPLT[0])
+ write32<E>(Buf + 4, 0xddd90000); // ld $25, %lo(&GOTPLT[0])($14)
+ write32<E>(Buf + 8, 0x25ce0000); // addiu $14, $14, %lo(&GOTPLT[0])
+ write32<E>(Buf + 12, 0x030ec023); // subu $24, $24, $14
+ write32<E>(Buf + 16, 0x03e07825); // move $15, $31
+ write32<E>(Buf + 20, 0x0018c0c2); // srl $24, $24, 3
+ } else {
+ write32<E>(Buf, 0x3c1c0000); // lui $28, %hi(&GOTPLT[0])
+ write32<E>(Buf + 4, 0x8f990000); // lw $25, %lo(&GOTPLT[0])($28)
+ write32<E>(Buf + 8, 0x279c0000); // addiu $28, $28, %lo(&GOTPLT[0])
+ write32<E>(Buf + 12, 0x031cc023); // subu $24, $24, $28
+ write32<E>(Buf + 16, 0x03e07825); // move $15, $31
+ write32<E>(Buf + 20, 0x0018c082); // srl $24, $24, 2
+ }
+
+ uint32_t JalrInst = Config->ZHazardplt ? 0x0320fc09 : 0x0320f809;
+ write32<E>(Buf + 24, JalrInst); // jalr.hb $25 or jalr $25
+ write32<E>(Buf + 28, 0x2718fffe); // subu $24, $24, 2
+
+ uint64_t GotPlt = In.GotPlt->getVA();
+ writeValue<E>(Buf, GotPlt + 0x8000, 16, 16);
+ writeValue<E>(Buf + 4, GotPlt, 16, 0);
+ writeValue<E>(Buf + 8, GotPlt, 16, 0);
+}
+
+template <class ELFT>
+void MIPS<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const {
+ const endianness E = ELFT::TargetEndianness;
+ if (isMicroMips()) {
+ // Overwrite trap instructions written by Writer::writeTrapInstr.
+ memset(Buf, 0, PltEntrySize);
+
+ if (isMipsR6()) {
+ write16<E>(Buf, 0x7840); // addiupc $2, (GOTPLT) - .
+ write16<E>(Buf + 4, 0xff22); // lw $25, 0($2)
+ write16<E>(Buf + 8, 0x0f02); // move $24, $2
+ write16<E>(Buf + 10, 0x4723); // jrc $25 / jr16 $25
+ relocateOne(Buf, R_MICROMIPS_PC19_S2, GotPltEntryAddr - PltEntryAddr);
+ } else {
+ write16<E>(Buf, 0x7900); // addiupc $2, (GOTPLT) - .
+ write16<E>(Buf + 4, 0xff22); // lw $25, 0($2)
+ write16<E>(Buf + 8, 0x4599); // jrc $25 / jr16 $25
+ write16<E>(Buf + 10, 0x0f02); // move $24, $2
+ relocateOne(Buf, R_MICROMIPS_PC23_S2, GotPltEntryAddr - PltEntryAddr);
+ }
+ return;
+ }
+
+ uint32_t JrInst = isMipsR6() ? (Config->ZHazardplt ? 0x03200409 : 0x03200009)
+ : (Config->ZHazardplt ? 0x03200408 : 0x03200008);
+
+ write32<E>(Buf, 0x3c0f0000); // lui $15, %hi(.got.plt entry)
+ write32<E>(Buf + 4, 0x8df90000); // l[wd] $25, %lo(.got.plt entry)($15)
+ write32<E>(Buf + 8, JrInst); // jr $25 / jr.hb $25
+ write32<E>(Buf + 12, 0x25f80000); // addiu $24, $15, %lo(.got.plt entry)
+ writeValue<E>(Buf, GotPltEntryAddr + 0x8000, 16, 16);
+ writeValue<E>(Buf + 4, GotPltEntryAddr, 16, 0);
+ writeValue<E>(Buf + 12, GotPltEntryAddr, 16, 0);
+}
+
+template <class ELFT>
+bool MIPS<ELFT>::needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
+ uint64_t BranchAddr, const Symbol &S) const {
+ // Any MIPS PIC code function is invoked with its address in register $t9.
+ // So if we have a branch instruction from non-PIC code to the PIC one
+ // we cannot make the jump directly and need to create a small stubs
+ // to save the target function address.
+ // See page 3-38 ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+ if (Type != R_MIPS_26 && Type != R_MICROMIPS_26_S1 &&
+ Type != R_MICROMIPS_PC26_S1)
+ return false;
+ auto *F = dyn_cast_or_null<ELFFileBase<ELFT>>(File);
+ if (!F)
+ return false;
+ // If current file has PIC code, LA25 stub is not required.
+ if (F->getObj().getHeader()->e_flags & EF_MIPS_PIC)
+ return false;
+ auto *D = dyn_cast<Defined>(&S);
+ // LA25 is required if target file has PIC code
+ // or target symbol is a PIC symbol.
+ return D && isMipsPIC<ELFT>(D);
+}
+
+template <class ELFT>
+int64_t MIPS<ELFT>::getImplicitAddend(const uint8_t *Buf, RelType Type) const {
+ const endianness E = ELFT::TargetEndianness;
+ switch (Type) {
+ case R_MIPS_32:
+ case R_MIPS_GPREL32:
+ case R_MIPS_TLS_DTPREL32:
+ case R_MIPS_TLS_TPREL32:
+ return SignExtend64<32>(read32<E>(Buf));
+ case R_MIPS_26:
+ // FIXME (simon): If the relocation target symbol is not a PLT entry
+ // we should use another expression for calculation:
+ // ((A << 2) | (P & 0xf0000000)) >> 2
+ return SignExtend64<28>(read32<E>(Buf) << 2);
+ case R_MIPS_GOT16:
+ case R_MIPS_HI16:
+ case R_MIPS_PCHI16:
+ return SignExtend64<16>(read32<E>(Buf)) << 16;
+ case R_MIPS_GPREL16:
+ case R_MIPS_LO16:
+ case R_MIPS_PCLO16:
+ case R_MIPS_TLS_DTPREL_HI16:
+ case R_MIPS_TLS_DTPREL_LO16:
+ case R_MIPS_TLS_TPREL_HI16:
+ case R_MIPS_TLS_TPREL_LO16:
+ return SignExtend64<16>(read32<E>(Buf));
+ case R_MICROMIPS_GOT16:
+ case R_MICROMIPS_HI16:
+ return SignExtend64<16>(readShuffle<E>(Buf)) << 16;
+ case R_MICROMIPS_GPREL16:
+ case R_MICROMIPS_LO16:
+ case R_MICROMIPS_TLS_DTPREL_HI16:
+ case R_MICROMIPS_TLS_DTPREL_LO16:
+ case R_MICROMIPS_TLS_TPREL_HI16:
+ case R_MICROMIPS_TLS_TPREL_LO16:
+ return SignExtend64<16>(readShuffle<E>(Buf));
+ case R_MICROMIPS_GPREL7_S2:
+ return SignExtend64<9>(readShuffle<E>(Buf) << 2);
+ case R_MIPS_PC16:
+ return SignExtend64<18>(read32<E>(Buf) << 2);
+ case R_MIPS_PC19_S2:
+ return SignExtend64<21>(read32<E>(Buf) << 2);
+ case R_MIPS_PC21_S2:
+ return SignExtend64<23>(read32<E>(Buf) << 2);
+ case R_MIPS_PC26_S2:
+ return SignExtend64<28>(read32<E>(Buf) << 2);
+ case R_MIPS_PC32:
+ return SignExtend64<32>(read32<E>(Buf));
+ case R_MICROMIPS_26_S1:
+ return SignExtend64<27>(readShuffle<E>(Buf) << 1);
+ case R_MICROMIPS_PC7_S1:
+ return SignExtend64<8>(read16<E>(Buf) << 1);
+ case R_MICROMIPS_PC10_S1:
+ return SignExtend64<11>(read16<E>(Buf) << 1);
+ case R_MICROMIPS_PC16_S1:
+ return SignExtend64<17>(readShuffle<E>(Buf) << 1);
+ case R_MICROMIPS_PC18_S3:
+ return SignExtend64<21>(readShuffle<E>(Buf) << 3);
+ case R_MICROMIPS_PC19_S2:
+ return SignExtend64<21>(readShuffle<E>(Buf) << 2);
+ case R_MICROMIPS_PC21_S1:
+ return SignExtend64<22>(readShuffle<E>(Buf) << 1);
+ case R_MICROMIPS_PC23_S2:
+ return SignExtend64<25>(readShuffle<E>(Buf) << 2);
+ case R_MICROMIPS_PC26_S1:
+ return SignExtend64<27>(readShuffle<E>(Buf) << 1);
+ default:
+ return 0;
+ }
+}
+
+static std::pair<uint32_t, uint64_t>
+calculateMipsRelChain(uint8_t *Loc, RelType Type, uint64_t Val) {
+ // MIPS N64 ABI packs multiple relocations into the single relocation
+ // record. In general, all up to three relocations can have arbitrary
+ // types. In fact, Clang and GCC uses only a few combinations. For now,
+ // we support two of them. That is allow to pass at least all LLVM
+ // test suite cases.
+ // <any relocation> / R_MIPS_SUB / R_MIPS_HI16 | R_MIPS_LO16
+ // <any relocation> / R_MIPS_64 / R_MIPS_NONE
+ // The first relocation is a 'real' relocation which is calculated
+ // using the corresponding symbol's value. The second and the third
+ // relocations used to modify result of the first one: extend it to
+ // 64-bit, extract high or low part etc. For details, see part 2.9 Relocation
+ // at the https://dmz-portal.mips.com/mw/images/8/82/007-4658-001.pdf
+ RelType Type2 = (Type >> 8) & 0xff;
+ RelType Type3 = (Type >> 16) & 0xff;
+ if (Type2 == R_MIPS_NONE && Type3 == R_MIPS_NONE)
+ return std::make_pair(Type, Val);
+ if (Type2 == R_MIPS_64 && Type3 == R_MIPS_NONE)
+ return std::make_pair(Type2, Val);
+ if (Type2 == R_MIPS_SUB && (Type3 == R_MIPS_HI16 || Type3 == R_MIPS_LO16))
+ return std::make_pair(Type3, -Val);
+ error(getErrorLocation(Loc) + "unsupported relocations combination " +
+ Twine(Type));
+ return std::make_pair(Type & 0xff, Val);
+}
+
+template <class ELFT>
+void MIPS<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
+ const endianness E = ELFT::TargetEndianness;
+
+ if (ELFT::Is64Bits || Config->MipsN32Abi)
+ std::tie(Type, Val) = calculateMipsRelChain(Loc, Type, Val);
+
+ // Thread pointer and DRP offsets from the start of TLS data area.
+ // https://www.linux-mips.org/wiki/NPTL
+ if (Type == R_MIPS_TLS_DTPREL_HI16 || Type == R_MIPS_TLS_DTPREL_LO16 ||
+ Type == R_MIPS_TLS_DTPREL32 || Type == R_MIPS_TLS_DTPREL64 ||
+ Type == R_MICROMIPS_TLS_DTPREL_HI16 ||
+ Type == R_MICROMIPS_TLS_DTPREL_LO16) {
+ Val -= 0x8000;
+ } else if (Type == R_MIPS_TLS_TPREL_HI16 || Type == R_MIPS_TLS_TPREL_LO16 ||
+ Type == R_MIPS_TLS_TPREL32 || Type == R_MIPS_TLS_TPREL64 ||
+ Type == R_MICROMIPS_TLS_TPREL_HI16 ||
+ Type == R_MICROMIPS_TLS_TPREL_LO16) {
+ Val -= 0x7000;
+ }
+
+ switch (Type) {
+ case R_MIPS_32:
+ case R_MIPS_GPREL32:
+ case R_MIPS_TLS_DTPREL32:
+ case R_MIPS_TLS_TPREL32:
+ write32<E>(Loc, Val);
+ break;
+ case R_MIPS_64:
+ case R_MIPS_TLS_DTPREL64:
+ case R_MIPS_TLS_TPREL64:
+ write64<E>(Loc, Val);
+ break;
+ case R_MIPS_26:
+ writeValue<E>(Loc, Val, 26, 2);
+ break;
+ case R_MIPS_GOT16:
+ // The R_MIPS_GOT16 relocation's value in "relocatable" linking mode
+ // is updated addend (not a GOT index). In that case write high 16 bits
+ // to store a correct addend value.
+ if (Config->Relocatable) {
+ writeValue<E>(Loc, Val + 0x8000, 16, 16);
+ } else {
+ checkInt(Loc, Val, 16, Type);
+ writeValue<E>(Loc, Val, 16, 0);
+ }
+ break;
+ case R_MICROMIPS_GOT16:
+ if (Config->Relocatable) {
+ writeShuffleValue<E>(Loc, Val + 0x8000, 16, 16);
+ } else {
+ checkInt(Loc, Val, 16, Type);
+ writeShuffleValue<E>(Loc, Val, 16, 0);
+ }
+ break;
+ case R_MIPS_CALL16:
+ case R_MIPS_GOT_DISP:
+ case R_MIPS_GOT_PAGE:
+ case R_MIPS_GPREL16:
+ case R_MIPS_TLS_GD:
+ case R_MIPS_TLS_GOTTPREL:
+ case R_MIPS_TLS_LDM:
+ checkInt(Loc, Val, 16, Type);
+ LLVM_FALLTHROUGH;
+ case R_MIPS_CALL_LO16:
+ case R_MIPS_GOT_LO16:
+ case R_MIPS_GOT_OFST:
+ case R_MIPS_LO16:
+ case R_MIPS_PCLO16:
+ case R_MIPS_TLS_DTPREL_LO16:
+ case R_MIPS_TLS_TPREL_LO16:
+ writeValue<E>(Loc, Val, 16, 0);
+ break;
+ case R_MICROMIPS_GPREL16:
+ case R_MICROMIPS_TLS_GD:
+ case R_MICROMIPS_TLS_LDM:
+ checkInt(Loc, Val, 16, Type);
+ writeShuffleValue<E>(Loc, Val, 16, 0);
+ break;
+ case R_MICROMIPS_CALL16:
+ case R_MICROMIPS_CALL_LO16:
+ case R_MICROMIPS_LO16:
+ case R_MICROMIPS_TLS_DTPREL_LO16:
+ case R_MICROMIPS_TLS_GOTTPREL:
+ case R_MICROMIPS_TLS_TPREL_LO16:
+ writeShuffleValue<E>(Loc, Val, 16, 0);
+ break;
+ case R_MICROMIPS_GPREL7_S2:
+ checkInt(Loc, Val, 7, Type);
+ writeShuffleValue<E>(Loc, Val, 7, 2);
+ break;
+ case R_MIPS_CALL_HI16:
+ case R_MIPS_GOT_HI16:
+ case R_MIPS_HI16:
+ case R_MIPS_PCHI16:
+ case R_MIPS_TLS_DTPREL_HI16:
+ case R_MIPS_TLS_TPREL_HI16:
+ writeValue<E>(Loc, Val + 0x8000, 16, 16);
+ break;
+ case R_MICROMIPS_CALL_HI16:
+ case R_MICROMIPS_GOT_HI16:
+ case R_MICROMIPS_HI16:
+ case R_MICROMIPS_TLS_DTPREL_HI16:
+ case R_MICROMIPS_TLS_TPREL_HI16:
+ writeShuffleValue<E>(Loc, Val + 0x8000, 16, 16);
+ break;
+ case R_MIPS_HIGHER:
+ writeValue<E>(Loc, Val + 0x80008000, 16, 32);
+ break;
+ case R_MIPS_HIGHEST:
+ writeValue<E>(Loc, Val + 0x800080008000, 16, 48);
+ break;
+ case R_MIPS_JALR:
+ case R_MICROMIPS_JALR:
+ // Ignore this optimization relocation for now
+ break;
+ case R_MIPS_PC16:
+ checkAlignment(Loc, Val, 4, Type);
+ checkInt(Loc, Val, 18, Type);
+ writeValue<E>(Loc, Val, 16, 2);
+ break;
+ case R_MIPS_PC19_S2:
+ checkAlignment(Loc, Val, 4, Type);
+ checkInt(Loc, Val, 21, Type);
+ writeValue<E>(Loc, Val, 19, 2);
+ break;
+ case R_MIPS_PC21_S2:
+ checkAlignment(Loc, Val, 4, Type);
+ checkInt(Loc, Val, 23, Type);
+ writeValue<E>(Loc, Val, 21, 2);
+ break;
+ case R_MIPS_PC26_S2:
+ checkAlignment(Loc, Val, 4, Type);
+ checkInt(Loc, Val, 28, Type);
+ writeValue<E>(Loc, Val, 26, 2);
+ break;
+ case R_MIPS_PC32:
+ writeValue<E>(Loc, Val, 32, 0);
+ break;
+ case R_MICROMIPS_26_S1:
+ case R_MICROMIPS_PC26_S1:
+ checkInt(Loc, Val, 27, Type);
+ writeShuffleValue<E>(Loc, Val, 26, 1);
+ break;
+ case R_MICROMIPS_PC7_S1:
+ checkInt(Loc, Val, 8, Type);
+ writeMicroRelocation16<E>(Loc, Val, 7, 1);
+ break;
+ case R_MICROMIPS_PC10_S1:
+ checkInt(Loc, Val, 11, Type);
+ writeMicroRelocation16<E>(Loc, Val, 10, 1);
+ break;
+ case R_MICROMIPS_PC16_S1:
+ checkInt(Loc, Val, 17, Type);
+ writeShuffleValue<E>(Loc, Val, 16, 1);
+ break;
+ case R_MICROMIPS_PC18_S3:
+ checkInt(Loc, Val, 21, Type);
+ writeShuffleValue<E>(Loc, Val, 18, 3);
+ break;
+ case R_MICROMIPS_PC19_S2:
+ checkInt(Loc, Val, 21, Type);
+ writeShuffleValue<E>(Loc, Val, 19, 2);
+ break;
+ case R_MICROMIPS_PC21_S1:
+ checkInt(Loc, Val, 22, Type);
+ writeShuffleValue<E>(Loc, Val, 21, 1);
+ break;
+ case R_MICROMIPS_PC23_S2:
+ checkInt(Loc, Val, 25, Type);
+ writeShuffleValue<E>(Loc, Val, 23, 2);
+ break;
+ default:
+ error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
+ }
+}
+
+template <class ELFT> bool MIPS<ELFT>::usesOnlyLowPageBits(RelType Type) const {
+ return Type == R_MIPS_LO16 || Type == R_MIPS_GOT_OFST ||
+ Type == R_MICROMIPS_LO16;
+}
+
+// Return true if the symbol is a PIC function.
+template <class ELFT> bool elf::isMipsPIC(const Defined *Sym) {
+ if (!Sym->isFunc())
+ return false;
+
+ if (Sym->StOther & STO_MIPS_PIC)
+ return true;
+
+ if (!Sym->Section)
+ return false;
+
+ ObjFile<ELFT> *File =
+ cast<InputSectionBase>(Sym->Section)->template getFile<ELFT>();
+ if (!File)
+ return false;
+
+ return File->getObj().getHeader()->e_flags & EF_MIPS_PIC;
+}
+
+template <class ELFT> TargetInfo *elf::getMipsTargetInfo() {
+ static MIPS<ELFT> Target;
+ return &Target;
+}
+
+template TargetInfo *elf::getMipsTargetInfo<ELF32LE>();
+template TargetInfo *elf::getMipsTargetInfo<ELF32BE>();
+template TargetInfo *elf::getMipsTargetInfo<ELF64LE>();
+template TargetInfo *elf::getMipsTargetInfo<ELF64BE>();
+
+template bool elf::isMipsPIC<ELF32LE>(const Defined *);
+template bool elf::isMipsPIC<ELF32BE>(const Defined *);
+template bool elf::isMipsPIC<ELF64LE>(const Defined *);
+template bool elf::isMipsPIC<ELF64BE>(const Defined *);
diff --git a/contrib/llvm/tools/lld/ELF/Arch/MipsArchTree.cpp b/contrib/llvm/tools/lld/ELF/Arch/MipsArchTree.cpp
new file mode 100644
index 000000000000..98ceac3075e0
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Arch/MipsArchTree.cpp
@@ -0,0 +1,390 @@
+//===- MipsArchTree.cpp --------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+//
+// This file contains a helper function for the Writer.
+//
+//===---------------------------------------------------------------------===//
+
+#include "InputFiles.h"
+#include "SymbolTable.h"
+#include "Writer.h"
+
+#include "lld/Common/ErrorHandler.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/MipsABIFlags.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::ELF;
+
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+struct ArchTreeEdge {
+ uint32_t Child;
+ uint32_t Parent;
+};
+
+struct FileFlags {
+ InputFile *File;
+ uint32_t Flags;
+};
+} // namespace
+
+static StringRef getAbiName(uint32_t Flags) {
+ switch (Flags) {
+ case 0:
+ return "n64";
+ case EF_MIPS_ABI2:
+ return "n32";
+ case EF_MIPS_ABI_O32:
+ return "o32";
+ case EF_MIPS_ABI_O64:
+ return "o64";
+ case EF_MIPS_ABI_EABI32:
+ return "eabi32";
+ case EF_MIPS_ABI_EABI64:
+ return "eabi64";
+ default:
+ return "unknown";
+ }
+}
+
+static StringRef getNanName(bool IsNan2008) {
+ return IsNan2008 ? "2008" : "legacy";
+}
+
+static StringRef getFpName(bool IsFp64) { return IsFp64 ? "64" : "32"; }
+
+static void checkFlags(ArrayRef<FileFlags> Files) {
+ assert(!Files.empty() && "expected non-empty file list");
+
+ uint32_t ABI = Files[0].Flags & (EF_MIPS_ABI | EF_MIPS_ABI2);
+ bool Nan = Files[0].Flags & EF_MIPS_NAN2008;
+ bool Fp = Files[0].Flags & EF_MIPS_FP64;
+
+ for (const FileFlags &F : Files) {
+ if (Config->Is64 && F.Flags & EF_MIPS_MICROMIPS)
+ error(toString(F.File) + ": microMIPS 64-bit is not supported");
+
+ uint32_t ABI2 = F.Flags & (EF_MIPS_ABI | EF_MIPS_ABI2);
+ if (ABI != ABI2)
+ error(toString(F.File) + ": ABI '" + getAbiName(ABI2) +
+ "' is incompatible with target ABI '" + getAbiName(ABI) + "'");
+
+ bool Nan2 = F.Flags & EF_MIPS_NAN2008;
+ if (Nan != Nan2)
+ error(toString(F.File) + ": -mnan=" + getNanName(Nan2) +
+ " is incompatible with target -mnan=" + getNanName(Nan));
+
+ bool Fp2 = F.Flags & EF_MIPS_FP64;
+ if (Fp != Fp2)
+ error(toString(F.File) + ": -mfp" + getFpName(Fp2) +
+ " is incompatible with target -mfp" + getFpName(Fp));
+ }
+}
+
+static uint32_t getMiscFlags(ArrayRef<FileFlags> Files) {
+ uint32_t Ret = 0;
+ for (const FileFlags &F : Files)
+ Ret |= F.Flags &
+ (EF_MIPS_ABI | EF_MIPS_ABI2 | EF_MIPS_ARCH_ASE | EF_MIPS_NOREORDER |
+ EF_MIPS_MICROMIPS | EF_MIPS_NAN2008 | EF_MIPS_32BITMODE);
+ return Ret;
+}
+
+static uint32_t getPicFlags(ArrayRef<FileFlags> Files) {
+ // Check PIC/non-PIC compatibility.
+ bool IsPic = Files[0].Flags & (EF_MIPS_PIC | EF_MIPS_CPIC);
+ for (const FileFlags &F : Files.slice(1)) {
+ bool IsPic2 = F.Flags & (EF_MIPS_PIC | EF_MIPS_CPIC);
+ if (IsPic && !IsPic2)
+ warn(toString(F.File) +
+ ": linking non-abicalls code with abicalls code " +
+ toString(Files[0].File));
+ if (!IsPic && IsPic2)
+ warn(toString(F.File) +
+ ": linking abicalls code with non-abicalls code " +
+ toString(Files[0].File));
+ }
+
+ // Compute the result PIC/non-PIC flag.
+ uint32_t Ret = Files[0].Flags & (EF_MIPS_PIC | EF_MIPS_CPIC);
+ for (const FileFlags &F : Files.slice(1))
+ Ret &= F.Flags & (EF_MIPS_PIC | EF_MIPS_CPIC);
+
+ // PIC code is inherently CPIC and may not set CPIC flag explicitly.
+ if (Ret & EF_MIPS_PIC)
+ Ret |= EF_MIPS_CPIC;
+ return Ret;
+}
+
+static ArchTreeEdge ArchTree[] = {
+ // MIPS32R6 and MIPS64R6 are not compatible with other extensions
+ // MIPS64R2 extensions.
+ {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON3, EF_MIPS_ARCH_64R2},
+ {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON2, EF_MIPS_ARCH_64R2},
+ {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON, EF_MIPS_ARCH_64R2},
+ {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_LS3A, EF_MIPS_ARCH_64R2},
+ // MIPS64 extensions.
+ {EF_MIPS_ARCH_64 | EF_MIPS_MACH_SB1, EF_MIPS_ARCH_64},
+ {EF_MIPS_ARCH_64 | EF_MIPS_MACH_XLR, EF_MIPS_ARCH_64},
+ {EF_MIPS_ARCH_64R2, EF_MIPS_ARCH_64},
+ // MIPS V extensions.
+ {EF_MIPS_ARCH_64, EF_MIPS_ARCH_5},
+ // R5000 extensions.
+ {EF_MIPS_ARCH_4 | EF_MIPS_MACH_5500, EF_MIPS_ARCH_4 | EF_MIPS_MACH_5400},
+ // MIPS IV extensions.
+ {EF_MIPS_ARCH_4 | EF_MIPS_MACH_5400, EF_MIPS_ARCH_4},
+ {EF_MIPS_ARCH_4 | EF_MIPS_MACH_9000, EF_MIPS_ARCH_4},
+ {EF_MIPS_ARCH_5, EF_MIPS_ARCH_4},
+ // VR4100 extensions.
+ {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4111, EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100},
+ {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4120, EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100},
+ // MIPS III extensions.
+ {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4010, EF_MIPS_ARCH_3},
+ {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100, EF_MIPS_ARCH_3},
+ {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4650, EF_MIPS_ARCH_3},
+ {EF_MIPS_ARCH_3 | EF_MIPS_MACH_5900, EF_MIPS_ARCH_3},
+ {EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2E, EF_MIPS_ARCH_3},
+ {EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2F, EF_MIPS_ARCH_3},
+ {EF_MIPS_ARCH_4, EF_MIPS_ARCH_3},
+ // MIPS32 extensions.
+ {EF_MIPS_ARCH_32R2, EF_MIPS_ARCH_32},
+ // MIPS II extensions.
+ {EF_MIPS_ARCH_3, EF_MIPS_ARCH_2},
+ {EF_MIPS_ARCH_32, EF_MIPS_ARCH_2},
+ // MIPS I extensions.
+ {EF_MIPS_ARCH_1 | EF_MIPS_MACH_3900, EF_MIPS_ARCH_1},
+ {EF_MIPS_ARCH_2, EF_MIPS_ARCH_1},
+};
+
+static bool isArchMatched(uint32_t New, uint32_t Res) {
+ if (New == Res)
+ return true;
+ if (New == EF_MIPS_ARCH_32 && isArchMatched(EF_MIPS_ARCH_64, Res))
+ return true;
+ if (New == EF_MIPS_ARCH_32R2 && isArchMatched(EF_MIPS_ARCH_64R2, Res))
+ return true;
+ for (const auto &Edge : ArchTree) {
+ if (Res == Edge.Child) {
+ Res = Edge.Parent;
+ if (Res == New)
+ return true;
+ }
+ }
+ return false;
+}
+
+static StringRef getMachName(uint32_t Flags) {
+ switch (Flags & EF_MIPS_MACH) {
+ case EF_MIPS_MACH_NONE:
+ return "";
+ case EF_MIPS_MACH_3900:
+ return "r3900";
+ case EF_MIPS_MACH_4010:
+ return "r4010";
+ case EF_MIPS_MACH_4100:
+ return "r4100";
+ case EF_MIPS_MACH_4650:
+ return "r4650";
+ case EF_MIPS_MACH_4120:
+ return "r4120";
+ case EF_MIPS_MACH_4111:
+ return "r4111";
+ case EF_MIPS_MACH_5400:
+ return "vr5400";
+ case EF_MIPS_MACH_5900:
+ return "vr5900";
+ case EF_MIPS_MACH_5500:
+ return "vr5500";
+ case EF_MIPS_MACH_9000:
+ return "rm9000";
+ case EF_MIPS_MACH_LS2E:
+ return "loongson2e";
+ case EF_MIPS_MACH_LS2F:
+ return "loongson2f";
+ case EF_MIPS_MACH_LS3A:
+ return "loongson3a";
+ case EF_MIPS_MACH_OCTEON:
+ return "octeon";
+ case EF_MIPS_MACH_OCTEON2:
+ return "octeon2";
+ case EF_MIPS_MACH_OCTEON3:
+ return "octeon3";
+ case EF_MIPS_MACH_SB1:
+ return "sb1";
+ case EF_MIPS_MACH_XLR:
+ return "xlr";
+ default:
+ return "unknown machine";
+ }
+}
+
+static StringRef getArchName(uint32_t Flags) {
+ switch (Flags & EF_MIPS_ARCH) {
+ case EF_MIPS_ARCH_1:
+ return "mips1";
+ case EF_MIPS_ARCH_2:
+ return "mips2";
+ case EF_MIPS_ARCH_3:
+ return "mips3";
+ case EF_MIPS_ARCH_4:
+ return "mips4";
+ case EF_MIPS_ARCH_5:
+ return "mips5";
+ case EF_MIPS_ARCH_32:
+ return "mips32";
+ case EF_MIPS_ARCH_64:
+ return "mips64";
+ case EF_MIPS_ARCH_32R2:
+ return "mips32r2";
+ case EF_MIPS_ARCH_64R2:
+ return "mips64r2";
+ case EF_MIPS_ARCH_32R6:
+ return "mips32r6";
+ case EF_MIPS_ARCH_64R6:
+ return "mips64r6";
+ default:
+ return "unknown arch";
+ }
+}
+
+static std::string getFullArchName(uint32_t Flags) {
+ StringRef Arch = getArchName(Flags);
+ StringRef Mach = getMachName(Flags);
+ if (Mach.empty())
+ return Arch.str();
+ return (Arch + " (" + Mach + ")").str();
+}
+
+// There are (arguably too) many MIPS ISAs out there. Their relationships
+// can be represented as a forest. If all input files have ISAs which
+// reachable by repeated proceeding from the single child to the parent,
+// these input files are compatible. In that case we need to return "highest"
+// ISA. If there are incompatible input files, we show an error.
+// For example, mips1 is a "parent" of mips2 and such files are compatible.
+// Output file gets EF_MIPS_ARCH_2 flag. From the other side mips3 and mips32
+// are incompatible because nor mips3 is a parent for misp32, nor mips32
+// is a parent for mips3.
+static uint32_t getArchFlags(ArrayRef<FileFlags> Files) {
+ uint32_t Ret = Files[0].Flags & (EF_MIPS_ARCH | EF_MIPS_MACH);
+
+ for (const FileFlags &F : Files.slice(1)) {
+ uint32_t New = F.Flags & (EF_MIPS_ARCH | EF_MIPS_MACH);
+
+ // Check ISA compatibility.
+ if (isArchMatched(New, Ret))
+ continue;
+ if (!isArchMatched(Ret, New)) {
+ error("incompatible target ISA:\n>>> " + toString(Files[0].File) + ": " +
+ getFullArchName(Ret) + "\n>>> " + toString(F.File) + ": " +
+ getFullArchName(New));
+ return 0;
+ }
+ Ret = New;
+ }
+ return Ret;
+}
+
+template <class ELFT> uint32_t elf::calcMipsEFlags() {
+ std::vector<FileFlags> V;
+ for (InputFile *F : ObjectFiles)
+ V.push_back({F, cast<ObjFile<ELFT>>(F)->getObj().getHeader()->e_flags});
+ if (V.empty())
+ return 0;
+ checkFlags(V);
+ return getMiscFlags(V) | getPicFlags(V) | getArchFlags(V);
+}
+
+static int compareMipsFpAbi(uint8_t FpA, uint8_t FpB) {
+ if (FpA == FpB)
+ return 0;
+ if (FpB == Mips::Val_GNU_MIPS_ABI_FP_ANY)
+ return 1;
+ if (FpB == Mips::Val_GNU_MIPS_ABI_FP_64A &&
+ FpA == Mips::Val_GNU_MIPS_ABI_FP_64)
+ return 1;
+ if (FpB != Mips::Val_GNU_MIPS_ABI_FP_XX)
+ return -1;
+ if (FpA == Mips::Val_GNU_MIPS_ABI_FP_DOUBLE ||
+ FpA == Mips::Val_GNU_MIPS_ABI_FP_64 ||
+ FpA == Mips::Val_GNU_MIPS_ABI_FP_64A)
+ return 1;
+ return -1;
+}
+
+static StringRef getMipsFpAbiName(uint8_t FpAbi) {
+ switch (FpAbi) {
+ case Mips::Val_GNU_MIPS_ABI_FP_ANY:
+ return "any";
+ case Mips::Val_GNU_MIPS_ABI_FP_DOUBLE:
+ return "-mdouble-float";
+ case Mips::Val_GNU_MIPS_ABI_FP_SINGLE:
+ return "-msingle-float";
+ case Mips::Val_GNU_MIPS_ABI_FP_SOFT:
+ return "-msoft-float";
+ case Mips::Val_GNU_MIPS_ABI_FP_OLD_64:
+ return "-mgp32 -mfp64 (old)";
+ case Mips::Val_GNU_MIPS_ABI_FP_XX:
+ return "-mfpxx";
+ case Mips::Val_GNU_MIPS_ABI_FP_64:
+ return "-mgp32 -mfp64";
+ case Mips::Val_GNU_MIPS_ABI_FP_64A:
+ return "-mgp32 -mfp64 -mno-odd-spreg";
+ default:
+ return "unknown";
+ }
+}
+
+uint8_t elf::getMipsFpAbiFlag(uint8_t OldFlag, uint8_t NewFlag,
+ StringRef FileName) {
+ if (compareMipsFpAbi(NewFlag, OldFlag) >= 0)
+ return NewFlag;
+ if (compareMipsFpAbi(OldFlag, NewFlag) < 0)
+ error(FileName + ": floating point ABI '" + getMipsFpAbiName(NewFlag) +
+ "' is incompatible with target floating point ABI '" +
+ getMipsFpAbiName(OldFlag) + "'");
+ return OldFlag;
+}
+
+template <class ELFT> static bool isN32Abi(const InputFile *F) {
+ if (auto *EF = dyn_cast<ELFFileBase<ELFT>>(F))
+ return EF->getObj().getHeader()->e_flags & EF_MIPS_ABI2;
+ return false;
+}
+
+bool elf::isMipsN32Abi(const InputFile *F) {
+ switch (Config->EKind) {
+ case ELF32LEKind:
+ return isN32Abi<ELF32LE>(F);
+ case ELF32BEKind:
+ return isN32Abi<ELF32BE>(F);
+ case ELF64LEKind:
+ return isN32Abi<ELF64LE>(F);
+ case ELF64BEKind:
+ return isN32Abi<ELF64BE>(F);
+ default:
+ llvm_unreachable("unknown Config->EKind");
+ }
+}
+
+bool elf::isMicroMips() { return Config->EFlags & EF_MIPS_MICROMIPS; }
+
+bool elf::isMipsR6() {
+ uint32_t Arch = Config->EFlags & EF_MIPS_ARCH;
+ return Arch == EF_MIPS_ARCH_32R6 || Arch == EF_MIPS_ARCH_64R6;
+}
+
+template uint32_t elf::calcMipsEFlags<ELF32LE>();
+template uint32_t elf::calcMipsEFlags<ELF32BE>();
+template uint32_t elf::calcMipsEFlags<ELF64LE>();
+template uint32_t elf::calcMipsEFlags<ELF64BE>();
diff --git a/contrib/llvm/tools/lld/ELF/Arch/PPC.cpp b/contrib/llvm/tools/lld/ELF/Arch/PPC.cpp
new file mode 100644
index 000000000000..767378067341
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Arch/PPC.cpp
@@ -0,0 +1,81 @@
+//===- PPC.cpp ------------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Symbols.h"
+#include "Target.h"
+#include "lld/Common/ErrorHandler.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+class PPC final : public TargetInfo {
+public:
+ PPC();
+ void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+ RelExpr getRelExpr(RelType Type, const Symbol &S,
+ const uint8_t *Loc) const override;
+};
+} // namespace
+
+PPC::PPC() {
+ NoneRel = R_PPC_NONE;
+ GotBaseSymOff = 0x8000;
+ GotBaseSymInGotPlt = false;
+}
+
+RelExpr PPC::getRelExpr(RelType Type, const Symbol &S,
+ const uint8_t *Loc) const {
+ switch (Type) {
+ case R_PPC_REL14:
+ case R_PPC_REL24:
+ case R_PPC_REL32:
+ return R_PC;
+ case R_PPC_PLTREL24:
+ return R_PLT_PC;
+ default:
+ return R_ABS;
+ }
+}
+
+void PPC::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
+ switch (Type) {
+ case R_PPC_ADDR16_HA:
+ write16be(Loc, (Val + 0x8000) >> 16);
+ break;
+ case R_PPC_ADDR16_HI:
+ write16be(Loc, Val >> 16);
+ break;
+ case R_PPC_ADDR16_LO:
+ write16be(Loc, Val);
+ break;
+ case R_PPC_ADDR32:
+ case R_PPC_REL32:
+ write32be(Loc, Val);
+ break;
+ case R_PPC_REL14:
+ write32be(Loc, read32be(Loc) | (Val & 0xFFFC));
+ break;
+ case R_PPC_PLTREL24:
+ case R_PPC_REL24:
+ write32be(Loc, read32be(Loc) | (Val & 0x3FFFFFC));
+ break;
+ default:
+ error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
+ }
+}
+
+TargetInfo *elf::getPPCTargetInfo() {
+ static PPC Target;
+ return &Target;
+}
diff --git a/contrib/llvm/tools/lld/ELF/Arch/PPC64.cpp b/contrib/llvm/tools/lld/ELF/Arch/PPC64.cpp
new file mode 100644
index 000000000000..8a320c9a4e9e
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Arch/PPC64.cpp
@@ -0,0 +1,931 @@
+//===- PPC64.cpp ----------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "lld/Common/ErrorHandler.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+static uint64_t PPC64TocOffset = 0x8000;
+static uint64_t DynamicThreadPointerOffset = 0x8000;
+
+// The instruction encoding of bits 21-30 from the ISA for the Xform and Dform
+// instructions that can be used as part of the initial exec TLS sequence.
+enum XFormOpcd {
+ LBZX = 87,
+ LHZX = 279,
+ LWZX = 23,
+ LDX = 21,
+ STBX = 215,
+ STHX = 407,
+ STWX = 151,
+ STDX = 149,
+ ADD = 266,
+};
+
+enum DFormOpcd {
+ LBZ = 34,
+ LBZU = 35,
+ LHZ = 40,
+ LHZU = 41,
+ LHAU = 43,
+ LWZ = 32,
+ LWZU = 33,
+ LFSU = 49,
+ LD = 58,
+ LFDU = 51,
+ STB = 38,
+ STBU = 39,
+ STH = 44,
+ STHU = 45,
+ STW = 36,
+ STWU = 37,
+ STFSU = 53,
+ STFDU = 55,
+ STD = 62,
+ ADDI = 14
+};
+
+uint64_t elf::getPPC64TocBase() {
+ // The TOC consists of sections .got, .toc, .tocbss, .plt in that order. The
+ // TOC starts where the first of these sections starts. We always create a
+ // .got when we see a relocation that uses it, so for us the start is always
+ // the .got.
+ uint64_t TocVA = In.Got->getVA();
+
+ // Per the ppc64-elf-linux ABI, The TOC base is TOC value plus 0x8000
+ // thus permitting a full 64 Kbytes segment. Note that the glibc startup
+ // code (crt1.o) assumes that you can get from the TOC base to the
+ // start of the .toc section with only a single (signed) 16-bit relocation.
+ return TocVA + PPC64TocOffset;
+}
+
+unsigned elf::getPPC64GlobalEntryToLocalEntryOffset(uint8_t StOther) {
+ // The offset is encoded into the 3 most significant bits of the st_other
+ // field, with some special values described in section 3.4.1 of the ABI:
+ // 0 --> Zero offset between the GEP and LEP, and the function does NOT use
+ // the TOC pointer (r2). r2 will hold the same value on returning from
+ // the function as it did on entering the function.
+ // 1 --> Zero offset between the GEP and LEP, and r2 should be treated as a
+ // caller-saved register for all callers.
+ // 2-6 --> The binary logarithm of the offset eg:
+ // 2 --> 2^2 = 4 bytes --> 1 instruction.
+ // 6 --> 2^6 = 64 bytes --> 16 instructions.
+ // 7 --> Reserved.
+ uint8_t GepToLep = (StOther >> 5) & 7;
+ if (GepToLep < 2)
+ return 0;
+
+ // The value encoded in the st_other bits is the
+ // log-base-2(offset).
+ if (GepToLep < 7)
+ return 1 << GepToLep;
+
+ error("reserved value of 7 in the 3 most-significant-bits of st_other");
+ return 0;
+}
+
+namespace {
+class PPC64 final : public TargetInfo {
+public:
+ PPC64();
+ uint32_t calcEFlags() const override;
+ RelExpr getRelExpr(RelType Type, const Symbol &S,
+ const uint8_t *Loc) const override;
+ void writePltHeader(uint8_t *Buf) const override;
+ void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
+ int32_t Index, unsigned RelOff) const override;
+ void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+ void writeGotHeader(uint8_t *Buf) const override;
+ bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
+ uint64_t BranchAddr, const Symbol &S) const override;
+ bool inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const override;
+ RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data,
+ RelExpr Expr) const override;
+ void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+ void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+ void relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+ void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+
+ bool adjustPrologueForCrossSplitStack(uint8_t *Loc, uint8_t *End,
+ uint8_t StOther) const override;
+};
+} // namespace
+
+// Relocation masks following the #lo(value), #hi(value), #ha(value),
+// #higher(value), #highera(value), #highest(value), and #highesta(value)
+// macros defined in section 4.5.1. Relocation Types of the PPC-elf64abi
+// document.
+static uint16_t lo(uint64_t V) { return V; }
+static uint16_t hi(uint64_t V) { return V >> 16; }
+static uint16_t ha(uint64_t V) { return (V + 0x8000) >> 16; }
+static uint16_t higher(uint64_t V) { return V >> 32; }
+static uint16_t highera(uint64_t V) { return (V + 0x8000) >> 32; }
+static uint16_t highest(uint64_t V) { return V >> 48; }
+static uint16_t highesta(uint64_t V) { return (V + 0x8000) >> 48; }
+
+// Extracts the 'PO' field of an instruction encoding.
+static uint8_t getPrimaryOpCode(uint32_t Encoding) { return (Encoding >> 26); }
+
+static bool isDQFormInstruction(uint32_t Encoding) {
+ switch (getPrimaryOpCode(Encoding)) {
+ default:
+ return false;
+ case 56:
+ // The only instruction with a primary opcode of 56 is `lq`.
+ return true;
+ case 61:
+ // There are both DS and DQ instruction forms with this primary opcode.
+ // Namely `lxv` and `stxv` are the DQ-forms that use it.
+ // The DS 'XO' bits being set to 01 is restricted to DQ form.
+ return (Encoding & 3) == 0x1;
+ }
+}
+
+static bool isInstructionUpdateForm(uint32_t Encoding) {
+ switch (getPrimaryOpCode(Encoding)) {
+ default:
+ return false;
+ case LBZU:
+ case LHAU:
+ case LHZU:
+ case LWZU:
+ case LFSU:
+ case LFDU:
+ case STBU:
+ case STHU:
+ case STWU:
+ case STFSU:
+ case STFDU:
+ return true;
+ // LWA has the same opcode as LD, and the DS bits is what differentiates
+ // between LD/LDU/LWA
+ case LD:
+ case STD:
+ return (Encoding & 3) == 1;
+ }
+}
+
+// There are a number of places when we either want to read or write an
+// instruction when handling a half16 relocation type. On big-endian the buffer
+// pointer is pointing into the middle of the word we want to extract, and on
+// little-endian it is pointing to the start of the word. These 2 helpers are to
+// simplify reading and writing in that context.
+static void writeInstrFromHalf16(uint8_t *Loc, uint32_t Instr) {
+ write32(Loc - (Config->EKind == ELF64BEKind ? 2 : 0), Instr);
+}
+
+static uint32_t readInstrFromHalf16(const uint8_t *Loc) {
+ return read32(Loc - (Config->EKind == ELF64BEKind ? 2 : 0));
+}
+
+PPC64::PPC64() {
+ GotRel = R_PPC64_GLOB_DAT;
+ NoneRel = R_PPC64_NONE;
+ PltRel = R_PPC64_JMP_SLOT;
+ RelativeRel = R_PPC64_RELATIVE;
+ IRelativeRel = R_PPC64_IRELATIVE;
+ GotEntrySize = 8;
+ PltEntrySize = 4;
+ GotPltEntrySize = 8;
+ GotBaseSymInGotPlt = false;
+ GotBaseSymOff = 0x8000;
+ GotHeaderEntriesNum = 1;
+ GotPltHeaderEntriesNum = 2;
+ PltHeaderSize = 60;
+ NeedsThunks = true;
+
+ TlsModuleIndexRel = R_PPC64_DTPMOD64;
+ TlsOffsetRel = R_PPC64_DTPREL64;
+
+ TlsGotRel = R_PPC64_TPREL64;
+
+ NeedsMoreStackNonSplit = false;
+
+ // We need 64K pages (at least under glibc/Linux, the loader won't
+ // set different permissions on a finer granularity than that).
+ DefaultMaxPageSize = 65536;
+
+ // The PPC64 ELF ABI v1 spec, says:
+ //
+ // It is normally desirable to put segments with different characteristics
+ // in separate 256 Mbyte portions of the address space, to give the
+ // operating system full paging flexibility in the 64-bit address space.
+ //
+ // And because the lowest non-zero 256M boundary is 0x10000000, PPC64 linkers
+ // use 0x10000000 as the starting address.
+ DefaultImageBase = 0x10000000;
+
+ write32(TrapInstr.data(), 0x7fe00008);
+}
+
+static uint32_t getEFlags(InputFile *File) {
+ if (Config->EKind == ELF64BEKind)
+ return cast<ObjFile<ELF64BE>>(File)->getObj().getHeader()->e_flags;
+ return cast<ObjFile<ELF64LE>>(File)->getObj().getHeader()->e_flags;
+}
+
+// This file implements v2 ABI. This function makes sure that all
+// object files have v2 or an unspecified version as an ABI version.
+uint32_t PPC64::calcEFlags() const {
+ for (InputFile *F : ObjectFiles) {
+ uint32_t Flag = getEFlags(F);
+ if (Flag == 1)
+ error(toString(F) + ": ABI version 1 is not supported");
+ else if (Flag > 2)
+ error(toString(F) + ": unrecognized e_flags: " + Twine(Flag));
+ }
+ return 2;
+}
+
+void PPC64::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
+ // Reference: 3.7.4.2 of the 64-bit ELF V2 abi supplement.
+ // The general dynamic code sequence for a global `x` will look like:
+ // Instruction Relocation Symbol
+ // addis r3, r2, x@got@tlsgd@ha R_PPC64_GOT_TLSGD16_HA x
+ // addi r3, r3, x@got@tlsgd@l R_PPC64_GOT_TLSGD16_LO x
+ // bl __tls_get_addr(x@tlsgd) R_PPC64_TLSGD x
+ // R_PPC64_REL24 __tls_get_addr
+ // nop None None
+
+ // Relaxing to local exec entails converting:
+ // addis r3, r2, x@got@tlsgd@ha into nop
+ // addi r3, r3, x@got@tlsgd@l into addis r3, r13, x@tprel@ha
+ // bl __tls_get_addr(x@tlsgd) into nop
+ // nop into addi r3, r3, x@tprel@l
+
+ switch (Type) {
+ case R_PPC64_GOT_TLSGD16_HA:
+ writeInstrFromHalf16(Loc, 0x60000000); // nop
+ break;
+ case R_PPC64_GOT_TLSGD16:
+ case R_PPC64_GOT_TLSGD16_LO:
+ writeInstrFromHalf16(Loc, 0x3c6d0000); // addis r3, r13
+ relocateOne(Loc, R_PPC64_TPREL16_HA, Val);
+ break;
+ case R_PPC64_TLSGD:
+ write32(Loc, 0x60000000); // nop
+ write32(Loc + 4, 0x38630000); // addi r3, r3
+ // Since we are relocating a half16 type relocation and Loc + 4 points to
+ // the start of an instruction we need to advance the buffer by an extra
+ // 2 bytes on BE.
+ relocateOne(Loc + 4 + (Config->EKind == ELF64BEKind ? 2 : 0),
+ R_PPC64_TPREL16_LO, Val);
+ break;
+ default:
+ llvm_unreachable("unsupported relocation for TLS GD to LE relaxation");
+ }
+}
+
+void PPC64::relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
+ // Reference: 3.7.4.3 of the 64-bit ELF V2 abi supplement.
+ // The local dynamic code sequence for a global `x` will look like:
+ // Instruction Relocation Symbol
+ // addis r3, r2, x@got@tlsld@ha R_PPC64_GOT_TLSLD16_HA x
+ // addi r3, r3, x@got@tlsld@l R_PPC64_GOT_TLSLD16_LO x
+ // bl __tls_get_addr(x@tlsgd) R_PPC64_TLSLD x
+ // R_PPC64_REL24 __tls_get_addr
+ // nop None None
+
+ // Relaxing to local exec entails converting:
+ // addis r3, r2, x@got@tlsld@ha into nop
+ // addi r3, r3, x@got@tlsld@l into addis r3, r13, 0
+ // bl __tls_get_addr(x@tlsgd) into nop
+ // nop into addi r3, r3, 4096
+
+ switch (Type) {
+ case R_PPC64_GOT_TLSLD16_HA:
+ writeInstrFromHalf16(Loc, 0x60000000); // nop
+ break;
+ case R_PPC64_GOT_TLSLD16_LO:
+ writeInstrFromHalf16(Loc, 0x3c6d0000); // addis r3, r13, 0
+ break;
+ case R_PPC64_TLSLD:
+ write32(Loc, 0x60000000); // nop
+ write32(Loc + 4, 0x38631000); // addi r3, r3, 4096
+ break;
+ case R_PPC64_DTPREL16:
+ case R_PPC64_DTPREL16_HA:
+ case R_PPC64_DTPREL16_HI:
+ case R_PPC64_DTPREL16_DS:
+ case R_PPC64_DTPREL16_LO:
+ case R_PPC64_DTPREL16_LO_DS:
+ case R_PPC64_GOT_DTPREL16_HA:
+ case R_PPC64_GOT_DTPREL16_LO_DS:
+ case R_PPC64_GOT_DTPREL16_DS:
+ case R_PPC64_GOT_DTPREL16_HI:
+ relocateOne(Loc, Type, Val);
+ break;
+ default:
+ llvm_unreachable("unsupported relocation for TLS LD to LE relaxation");
+ }
+}
+
+static unsigned getDFormOp(unsigned SecondaryOp) {
+ switch (SecondaryOp) {
+ case LBZX:
+ return LBZ;
+ case LHZX:
+ return LHZ;
+ case LWZX:
+ return LWZ;
+ case LDX:
+ return LD;
+ case STBX:
+ return STB;
+ case STHX:
+ return STH;
+ case STWX:
+ return STW;
+ case STDX:
+ return STD;
+ case ADD:
+ return ADDI;
+ default:
+ error("unrecognized instruction for IE to LE R_PPC64_TLS");
+ return 0;
+ }
+}
+
+void PPC64::relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
+ // The initial exec code sequence for a global `x` will look like:
+ // Instruction Relocation Symbol
+ // addis r9, r2, x@got@tprel@ha R_PPC64_GOT_TPREL16_HA x
+ // ld r9, x@got@tprel@l(r9) R_PPC64_GOT_TPREL16_LO_DS x
+ // add r9, r9, x@tls R_PPC64_TLS x
+
+ // Relaxing to local exec entails converting:
+ // addis r9, r2, x@got@tprel@ha into nop
+ // ld r9, x@got@tprel@l(r9) into addis r9, r13, x@tprel@ha
+ // add r9, r9, x@tls into addi r9, r9, x@tprel@l
+
+ // x@tls R_PPC64_TLS is a relocation which does not compute anything,
+ // it is replaced with r13 (thread pointer).
+
+ // The add instruction in the initial exec sequence has multiple variations
+ // that need to be handled. If we are building an address it will use an add
+ // instruction, if we are accessing memory it will use any of the X-form
+ // indexed load or store instructions.
+
+ unsigned Offset = (Config->EKind == ELF64BEKind) ? 2 : 0;
+ switch (Type) {
+ case R_PPC64_GOT_TPREL16_HA:
+ write32(Loc - Offset, 0x60000000); // nop
+ break;
+ case R_PPC64_GOT_TPREL16_LO_DS:
+ case R_PPC64_GOT_TPREL16_DS: {
+ uint32_t RegNo = read32(Loc - Offset) & 0x03E00000; // bits 6-10
+ write32(Loc - Offset, 0x3C0D0000 | RegNo); // addis RegNo, r13
+ relocateOne(Loc, R_PPC64_TPREL16_HA, Val);
+ break;
+ }
+ case R_PPC64_TLS: {
+ uint32_t PrimaryOp = getPrimaryOpCode(read32(Loc));
+ if (PrimaryOp != 31)
+ error("unrecognized instruction for IE to LE R_PPC64_TLS");
+ uint32_t SecondaryOp = (read32(Loc) & 0x000007FE) >> 1; // bits 21-30
+ uint32_t DFormOp = getDFormOp(SecondaryOp);
+ write32(Loc, ((DFormOp << 26) | (read32(Loc) & 0x03FFFFFF)));
+ relocateOne(Loc + Offset, R_PPC64_TPREL16_LO, Val);
+ break;
+ }
+ default:
+ llvm_unreachable("unknown relocation for IE to LE");
+ break;
+ }
+}
+
+RelExpr PPC64::getRelExpr(RelType Type, const Symbol &S,
+ const uint8_t *Loc) const {
+ switch (Type) {
+ case R_PPC64_GOT16:
+ case R_PPC64_GOT16_DS:
+ case R_PPC64_GOT16_HA:
+ case R_PPC64_GOT16_HI:
+ case R_PPC64_GOT16_LO:
+ case R_PPC64_GOT16_LO_DS:
+ return R_GOT_OFF;
+ case R_PPC64_TOC16:
+ case R_PPC64_TOC16_DS:
+ case R_PPC64_TOC16_HA:
+ case R_PPC64_TOC16_HI:
+ case R_PPC64_TOC16_LO:
+ case R_PPC64_TOC16_LO_DS:
+ return R_GOTREL;
+ case R_PPC64_TOC:
+ return R_PPC_TOC;
+ case R_PPC64_REL14:
+ case R_PPC64_REL24:
+ return R_PPC_CALL_PLT;
+ case R_PPC64_REL16_LO:
+ case R_PPC64_REL16_HA:
+ case R_PPC64_REL32:
+ case R_PPC64_REL64:
+ return R_PC;
+ case R_PPC64_GOT_TLSGD16:
+ case R_PPC64_GOT_TLSGD16_HA:
+ case R_PPC64_GOT_TLSGD16_HI:
+ case R_PPC64_GOT_TLSGD16_LO:
+ return R_TLSGD_GOT;
+ case R_PPC64_GOT_TLSLD16:
+ case R_PPC64_GOT_TLSLD16_HA:
+ case R_PPC64_GOT_TLSLD16_HI:
+ case R_PPC64_GOT_TLSLD16_LO:
+ return R_TLSLD_GOT;
+ case R_PPC64_GOT_TPREL16_HA:
+ case R_PPC64_GOT_TPREL16_LO_DS:
+ case R_PPC64_GOT_TPREL16_DS:
+ case R_PPC64_GOT_TPREL16_HI:
+ return R_GOT_OFF;
+ case R_PPC64_GOT_DTPREL16_HA:
+ case R_PPC64_GOT_DTPREL16_LO_DS:
+ case R_PPC64_GOT_DTPREL16_DS:
+ case R_PPC64_GOT_DTPREL16_HI:
+ return R_TLSLD_GOT_OFF;
+ case R_PPC64_TPREL16:
+ case R_PPC64_TPREL16_HA:
+ case R_PPC64_TPREL16_LO:
+ case R_PPC64_TPREL16_HI:
+ case R_PPC64_TPREL16_DS:
+ case R_PPC64_TPREL16_LO_DS:
+ case R_PPC64_TPREL16_HIGHER:
+ case R_PPC64_TPREL16_HIGHERA:
+ case R_PPC64_TPREL16_HIGHEST:
+ case R_PPC64_TPREL16_HIGHESTA:
+ return R_TLS;
+ case R_PPC64_DTPREL16:
+ case R_PPC64_DTPREL16_DS:
+ case R_PPC64_DTPREL16_HA:
+ case R_PPC64_DTPREL16_HI:
+ case R_PPC64_DTPREL16_HIGHER:
+ case R_PPC64_DTPREL16_HIGHERA:
+ case R_PPC64_DTPREL16_HIGHEST:
+ case R_PPC64_DTPREL16_HIGHESTA:
+ case R_PPC64_DTPREL16_LO:
+ case R_PPC64_DTPREL16_LO_DS:
+ case R_PPC64_DTPREL64:
+ return R_ABS;
+ case R_PPC64_TLSGD:
+ return R_TLSDESC_CALL;
+ case R_PPC64_TLSLD:
+ return R_TLSLD_HINT;
+ case R_PPC64_TLS:
+ return R_TLSIE_HINT;
+ default:
+ return R_ABS;
+ }
+}
+
+void PPC64::writeGotHeader(uint8_t *Buf) const {
+ write64(Buf, getPPC64TocBase());
+}
+
+void PPC64::writePltHeader(uint8_t *Buf) const {
+ // The generic resolver stub goes first.
+ write32(Buf + 0, 0x7c0802a6); // mflr r0
+ write32(Buf + 4, 0x429f0005); // bcl 20,4*cr7+so,8 <_glink+0x8>
+ write32(Buf + 8, 0x7d6802a6); // mflr r11
+ write32(Buf + 12, 0x7c0803a6); // mtlr r0
+ write32(Buf + 16, 0x7d8b6050); // subf r12, r11, r12
+ write32(Buf + 20, 0x380cffcc); // subi r0,r12,52
+ write32(Buf + 24, 0x7800f082); // srdi r0,r0,62,2
+ write32(Buf + 28, 0xe98b002c); // ld r12,44(r11)
+ write32(Buf + 32, 0x7d6c5a14); // add r11,r12,r11
+ write32(Buf + 36, 0xe98b0000); // ld r12,0(r11)
+ write32(Buf + 40, 0xe96b0008); // ld r11,8(r11)
+ write32(Buf + 44, 0x7d8903a6); // mtctr r12
+ write32(Buf + 48, 0x4e800420); // bctr
+
+ // The 'bcl' instruction will set the link register to the address of the
+ // following instruction ('mflr r11'). Here we store the offset from that
+ // instruction to the first entry in the GotPlt section.
+ int64_t GotPltOffset = In.GotPlt->getVA() - (In.Plt->getVA() + 8);
+ write64(Buf + 52, GotPltOffset);
+}
+
+void PPC64::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const {
+ int32_t Offset = PltHeaderSize + Index * PltEntrySize;
+ // bl __glink_PLTresolve
+ write32(Buf, 0x48000000 | ((-Offset) & 0x03FFFFFc));
+}
+
+static std::pair<RelType, uint64_t> toAddr16Rel(RelType Type, uint64_t Val) {
+ // Relocations relative to the toc-base need to be adjusted by the Toc offset.
+ uint64_t TocBiasedVal = Val - PPC64TocOffset;
+ // Relocations relative to dtv[dtpmod] need to be adjusted by the DTP offset.
+ uint64_t DTPBiasedVal = Val - DynamicThreadPointerOffset;
+
+ switch (Type) {
+ // TOC biased relocation.
+ case R_PPC64_GOT16:
+ case R_PPC64_GOT_TLSGD16:
+ case R_PPC64_GOT_TLSLD16:
+ case R_PPC64_TOC16:
+ return {R_PPC64_ADDR16, TocBiasedVal};
+ case R_PPC64_GOT16_DS:
+ case R_PPC64_TOC16_DS:
+ case R_PPC64_GOT_TPREL16_DS:
+ case R_PPC64_GOT_DTPREL16_DS:
+ return {R_PPC64_ADDR16_DS, TocBiasedVal};
+ case R_PPC64_GOT16_HA:
+ case R_PPC64_GOT_TLSGD16_HA:
+ case R_PPC64_GOT_TLSLD16_HA:
+ case R_PPC64_GOT_TPREL16_HA:
+ case R_PPC64_GOT_DTPREL16_HA:
+ case R_PPC64_TOC16_HA:
+ return {R_PPC64_ADDR16_HA, TocBiasedVal};
+ case R_PPC64_GOT16_HI:
+ case R_PPC64_GOT_TLSGD16_HI:
+ case R_PPC64_GOT_TLSLD16_HI:
+ case R_PPC64_GOT_TPREL16_HI:
+ case R_PPC64_GOT_DTPREL16_HI:
+ case R_PPC64_TOC16_HI:
+ return {R_PPC64_ADDR16_HI, TocBiasedVal};
+ case R_PPC64_GOT16_LO:
+ case R_PPC64_GOT_TLSGD16_LO:
+ case R_PPC64_GOT_TLSLD16_LO:
+ case R_PPC64_TOC16_LO:
+ return {R_PPC64_ADDR16_LO, TocBiasedVal};
+ case R_PPC64_GOT16_LO_DS:
+ case R_PPC64_TOC16_LO_DS:
+ case R_PPC64_GOT_TPREL16_LO_DS:
+ case R_PPC64_GOT_DTPREL16_LO_DS:
+ return {R_PPC64_ADDR16_LO_DS, TocBiasedVal};
+
+ // Dynamic Thread pointer biased relocation types.
+ case R_PPC64_DTPREL16:
+ return {R_PPC64_ADDR16, DTPBiasedVal};
+ case R_PPC64_DTPREL16_DS:
+ return {R_PPC64_ADDR16_DS, DTPBiasedVal};
+ case R_PPC64_DTPREL16_HA:
+ return {R_PPC64_ADDR16_HA, DTPBiasedVal};
+ case R_PPC64_DTPREL16_HI:
+ return {R_PPC64_ADDR16_HI, DTPBiasedVal};
+ case R_PPC64_DTPREL16_HIGHER:
+ return {R_PPC64_ADDR16_HIGHER, DTPBiasedVal};
+ case R_PPC64_DTPREL16_HIGHERA:
+ return {R_PPC64_ADDR16_HIGHERA, DTPBiasedVal};
+ case R_PPC64_DTPREL16_HIGHEST:
+ return {R_PPC64_ADDR16_HIGHEST, DTPBiasedVal};
+ case R_PPC64_DTPREL16_HIGHESTA:
+ return {R_PPC64_ADDR16_HIGHESTA, DTPBiasedVal};
+ case R_PPC64_DTPREL16_LO:
+ return {R_PPC64_ADDR16_LO, DTPBiasedVal};
+ case R_PPC64_DTPREL16_LO_DS:
+ return {R_PPC64_ADDR16_LO_DS, DTPBiasedVal};
+ case R_PPC64_DTPREL64:
+ return {R_PPC64_ADDR64, DTPBiasedVal};
+
+ default:
+ return {Type, Val};
+ }
+}
+
+static bool isTocOptType(RelType Type) {
+ switch (Type) {
+ case R_PPC64_GOT16_HA:
+ case R_PPC64_GOT16_LO_DS:
+ case R_PPC64_TOC16_HA:
+ case R_PPC64_TOC16_LO_DS:
+ case R_PPC64_TOC16_LO:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void PPC64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
+ // We need to save the original relocation type to use in diagnostics, and
+ // use the original type to determine if we should toc-optimize the
+ // instructions being relocated.
+ RelType OriginalType = Type;
+ bool ShouldTocOptimize = isTocOptType(Type);
+ // For dynamic thread pointer relative, toc-relative, and got-indirect
+ // relocations, proceed in terms of the corresponding ADDR16 relocation type.
+ std::tie(Type, Val) = toAddr16Rel(Type, Val);
+
+ switch (Type) {
+ case R_PPC64_ADDR14: {
+ checkAlignment(Loc, Val, 4, Type);
+ // Preserve the AA/LK bits in the branch instruction
+ uint8_t AALK = Loc[3];
+ write16(Loc + 2, (AALK & 3) | (Val & 0xfffc));
+ break;
+ }
+ case R_PPC64_ADDR16:
+ case R_PPC64_TPREL16:
+ checkInt(Loc, Val, 16, OriginalType);
+ write16(Loc, Val);
+ break;
+ case R_PPC64_ADDR16_DS:
+ case R_PPC64_TPREL16_DS: {
+ checkInt(Loc, Val, 16, OriginalType);
+ // DQ-form instructions use bits 28-31 as part of the instruction encoding
+ // DS-form instructions only use bits 30-31.
+ uint16_t Mask = isDQFormInstruction(readInstrFromHalf16(Loc)) ? 0xF : 0x3;
+ checkAlignment(Loc, lo(Val), Mask + 1, OriginalType);
+ write16(Loc, (read16(Loc) & Mask) | lo(Val));
+ } break;
+ case R_PPC64_ADDR16_HA:
+ case R_PPC64_REL16_HA:
+ case R_PPC64_TPREL16_HA:
+ if (Config->TocOptimize && ShouldTocOptimize && ha(Val) == 0)
+ writeInstrFromHalf16(Loc, 0x60000000);
+ else
+ write16(Loc, ha(Val));
+ break;
+ case R_PPC64_ADDR16_HI:
+ case R_PPC64_REL16_HI:
+ case R_PPC64_TPREL16_HI:
+ write16(Loc, hi(Val));
+ break;
+ case R_PPC64_ADDR16_HIGHER:
+ case R_PPC64_TPREL16_HIGHER:
+ write16(Loc, higher(Val));
+ break;
+ case R_PPC64_ADDR16_HIGHERA:
+ case R_PPC64_TPREL16_HIGHERA:
+ write16(Loc, highera(Val));
+ break;
+ case R_PPC64_ADDR16_HIGHEST:
+ case R_PPC64_TPREL16_HIGHEST:
+ write16(Loc, highest(Val));
+ break;
+ case R_PPC64_ADDR16_HIGHESTA:
+ case R_PPC64_TPREL16_HIGHESTA:
+ write16(Loc, highesta(Val));
+ break;
+ case R_PPC64_ADDR16_LO:
+ case R_PPC64_REL16_LO:
+ case R_PPC64_TPREL16_LO:
+ // When the high-adjusted part of a toc relocation evalutes to 0, it is
+ // changed into a nop. The lo part then needs to be updated to use the
+ // toc-pointer register r2, as the base register.
+ if (Config->TocOptimize && ShouldTocOptimize && ha(Val) == 0) {
+ uint32_t Instr = readInstrFromHalf16(Loc);
+ if (isInstructionUpdateForm(Instr))
+ error(getErrorLocation(Loc) +
+ "can't toc-optimize an update instruction: 0x" +
+ utohexstr(Instr));
+ Instr = (Instr & 0xFFE00000) | 0x00020000;
+ writeInstrFromHalf16(Loc, Instr);
+ }
+ write16(Loc, lo(Val));
+ break;
+ case R_PPC64_ADDR16_LO_DS:
+ case R_PPC64_TPREL16_LO_DS: {
+ // DQ-form instructions use bits 28-31 as part of the instruction encoding
+ // DS-form instructions only use bits 30-31.
+ uint32_t Inst = readInstrFromHalf16(Loc);
+ uint16_t Mask = isDQFormInstruction(Inst) ? 0xF : 0x3;
+ checkAlignment(Loc, lo(Val), Mask + 1, OriginalType);
+ if (Config->TocOptimize && ShouldTocOptimize && ha(Val) == 0) {
+ // When the high-adjusted part of a toc relocation evalutes to 0, it is
+ // changed into a nop. The lo part then needs to be updated to use the toc
+ // pointer register r2, as the base register.
+ if (isInstructionUpdateForm(Inst))
+ error(getErrorLocation(Loc) +
+ "Can't toc-optimize an update instruction: 0x" +
+ Twine::utohexstr(Inst));
+ Inst = (Inst & 0xFFE0000F) | 0x00020000;
+ writeInstrFromHalf16(Loc, Inst);
+ }
+ write16(Loc, (read16(Loc) & Mask) | lo(Val));
+ } break;
+ case R_PPC64_ADDR32:
+ case R_PPC64_REL32:
+ checkInt(Loc, Val, 32, Type);
+ write32(Loc, Val);
+ break;
+ case R_PPC64_ADDR64:
+ case R_PPC64_REL64:
+ case R_PPC64_TOC:
+ write64(Loc, Val);
+ break;
+ case R_PPC64_REL14: {
+ uint32_t Mask = 0x0000FFFC;
+ checkInt(Loc, Val, 16, Type);
+ checkAlignment(Loc, Val, 4, Type);
+ write32(Loc, (read32(Loc) & ~Mask) | (Val & Mask));
+ break;
+ }
+ case R_PPC64_REL24: {
+ uint32_t Mask = 0x03FFFFFC;
+ checkInt(Loc, Val, 26, Type);
+ checkAlignment(Loc, Val, 4, Type);
+ write32(Loc, (read32(Loc) & ~Mask) | (Val & Mask));
+ break;
+ }
+ case R_PPC64_DTPREL64:
+ write64(Loc, Val - DynamicThreadPointerOffset);
+ break;
+ default:
+ error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
+ }
+}
+
+bool PPC64::needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
+ uint64_t BranchAddr, const Symbol &S) const {
+ if (Type != R_PPC64_REL14 && Type != R_PPC64_REL24)
+ return false;
+
+ // If a function is in the Plt it needs to be called with a call-stub.
+ if (S.isInPlt())
+ return true;
+
+ // If a symbol is a weak undefined and we are compiling an executable
+ // it doesn't need a range-extending thunk since it can't be called.
+ if (S.isUndefWeak() && !Config->Shared)
+ return false;
+
+ // If the offset exceeds the range of the branch type then it will need
+ // a range-extending thunk.
+ return !inBranchRange(Type, BranchAddr, S.getVA());
+}
+
+bool PPC64::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const {
+ int64_t Offset = Dst - Src;
+ if (Type == R_PPC64_REL14)
+ return isInt<16>(Offset);
+ if (Type == R_PPC64_REL24)
+ return isInt<26>(Offset);
+ llvm_unreachable("unsupported relocation type used in branch");
+}
+
+RelExpr PPC64::adjustRelaxExpr(RelType Type, const uint8_t *Data,
+ RelExpr Expr) const {
+ if (Expr == R_RELAX_TLS_GD_TO_IE)
+ return R_RELAX_TLS_GD_TO_IE_GOT_OFF;
+ if (Expr == R_RELAX_TLS_LD_TO_LE)
+ return R_RELAX_TLS_LD_TO_LE_ABS;
+ return Expr;
+}
+
+// Reference: 3.7.4.1 of the 64-bit ELF V2 abi supplement.
+// The general dynamic code sequence for a global `x` uses 4 instructions.
+// Instruction Relocation Symbol
+// addis r3, r2, x@got@tlsgd@ha R_PPC64_GOT_TLSGD16_HA x
+// addi r3, r3, x@got@tlsgd@l R_PPC64_GOT_TLSGD16_LO x
+// bl __tls_get_addr(x@tlsgd) R_PPC64_TLSGD x
+// R_PPC64_REL24 __tls_get_addr
+// nop None None
+//
+// Relaxing to initial-exec entails:
+// 1) Convert the addis/addi pair that builds the address of the tls_index
+// struct for 'x' to an addis/ld pair that loads an offset from a got-entry.
+// 2) Convert the call to __tls_get_addr to a nop.
+// 3) Convert the nop following the call to an add of the loaded offset to the
+// thread pointer.
+// Since the nop must directly follow the call, the R_PPC64_TLSGD relocation is
+// used as the relaxation hint for both steps 2 and 3.
+void PPC64::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const {
+ switch (Type) {
+ case R_PPC64_GOT_TLSGD16_HA:
+ // This is relaxed from addis rT, r2, sym@got@tlsgd@ha to
+ // addis rT, r2, sym@got@tprel@ha.
+ relocateOne(Loc, R_PPC64_GOT_TPREL16_HA, Val);
+ return;
+ case R_PPC64_GOT_TLSGD16_LO: {
+ // Relax from addi r3, rA, sym@got@tlsgd@l to
+ // ld r3, sym@got@tprel@l(rA)
+ uint32_t InputRegister = (readInstrFromHalf16(Loc) & (0x1f << 16));
+ writeInstrFromHalf16(Loc, 0xE8600000 | InputRegister);
+ relocateOne(Loc, R_PPC64_GOT_TPREL16_LO_DS, Val);
+ return;
+ }
+ case R_PPC64_TLSGD:
+ write32(Loc, 0x60000000); // bl __tls_get_addr(sym@tlsgd) --> nop
+ write32(Loc + 4, 0x7c636A14); // nop --> add r3, r3, r13
+ return;
+ default:
+ llvm_unreachable("unsupported relocation for TLS GD to IE relaxation");
+ }
+}
+
+// The prologue for a split-stack function is expected to look roughly
+// like this:
+// .Lglobal_entry_point:
+// # TOC pointer initalization.
+// ...
+// .Llocal_entry_point:
+// # load the __private_ss member of the threads tcbhead.
+// ld r0,-0x7000-64(r13)
+// # subtract the functions stack size from the stack pointer.
+// addis r12, r1, ha(-stack-frame size)
+// addi r12, r12, l(-stack-frame size)
+// # compare needed to actual and branch to allocate_more_stack if more
+// # space is needed, otherwise fallthrough to 'normal' function body.
+// cmpld cr7,r12,r0
+// blt- cr7, .Lallocate_more_stack
+//
+// -) The allocate_more_stack block might be placed after the split-stack
+// prologue and the `blt-` replaced with a `bge+ .Lnormal_func_body`
+// instead.
+// -) If either the addis or addi is not needed due to the stack size being
+// smaller then 32K or a multiple of 64K they will be replaced with a nop,
+// but there will always be 2 instructions the linker can overwrite for the
+// adjusted stack size.
+//
+// The linkers job here is to increase the stack size used in the addis/addi
+// pair by split-stack-size-adjust.
+// addis r12, r1, ha(-stack-frame size - split-stack-adjust-size)
+// addi r12, r12, l(-stack-frame size - split-stack-adjust-size)
+bool PPC64::adjustPrologueForCrossSplitStack(uint8_t *Loc, uint8_t *End,
+ uint8_t StOther) const {
+ // If the caller has a global entry point adjust the buffer past it. The start
+ // of the split-stack prologue will be at the local entry point.
+ Loc += getPPC64GlobalEntryToLocalEntryOffset(StOther);
+
+ // At the very least we expect to see a load of some split-stack data from the
+ // tcb, and 2 instructions that calculate the ending stack address this
+ // function will require. If there is not enough room for at least 3
+ // instructions it can't be a split-stack prologue.
+ if (Loc + 12 >= End)
+ return false;
+
+ // First instruction must be `ld r0, -0x7000-64(r13)`
+ if (read32(Loc) != 0xe80d8fc0)
+ return false;
+
+ int16_t HiImm = 0;
+ int16_t LoImm = 0;
+ // First instruction can be either an addis if the frame size is larger then
+ // 32K, or an addi if the size is less then 32K.
+ int32_t FirstInstr = read32(Loc + 4);
+ if (getPrimaryOpCode(FirstInstr) == 15) {
+ HiImm = FirstInstr & 0xFFFF;
+ } else if (getPrimaryOpCode(FirstInstr) == 14) {
+ LoImm = FirstInstr & 0xFFFF;
+ } else {
+ return false;
+ }
+
+ // Second instruction is either an addi or a nop. If the first instruction was
+ // an addi then LoImm is set and the second instruction must be a nop.
+ uint32_t SecondInstr = read32(Loc + 8);
+ if (!LoImm && getPrimaryOpCode(SecondInstr) == 14) {
+ LoImm = SecondInstr & 0xFFFF;
+ } else if (SecondInstr != 0x60000000) {
+ return false;
+ }
+
+ // The register operands of the first instruction should be the stack-pointer
+ // (r1) as the input (RA) and r12 as the output (RT). If the second
+ // instruction is not a nop, then it should use r12 as both input and output.
+ auto CheckRegOperands = [](uint32_t Instr, uint8_t ExpectedRT,
+ uint8_t ExpectedRA) {
+ return ((Instr & 0x3E00000) >> 21 == ExpectedRT) &&
+ ((Instr & 0x1F0000) >> 16 == ExpectedRA);
+ };
+ if (!CheckRegOperands(FirstInstr, 12, 1))
+ return false;
+ if (SecondInstr != 0x60000000 && !CheckRegOperands(SecondInstr, 12, 12))
+ return false;
+
+ int32_t StackFrameSize = (HiImm * 65536) + LoImm;
+ // Check that the adjusted size doesn't overflow what we can represent with 2
+ // instructions.
+ if (StackFrameSize < Config->SplitStackAdjustSize + INT32_MIN) {
+ error(getErrorLocation(Loc) + "split-stack prologue adjustment overflows");
+ return false;
+ }
+
+ int32_t AdjustedStackFrameSize =
+ StackFrameSize - Config->SplitStackAdjustSize;
+
+ LoImm = AdjustedStackFrameSize & 0xFFFF;
+ HiImm = (AdjustedStackFrameSize + 0x8000) >> 16;
+ if (HiImm) {
+ write32(Loc + 4, 0x3D810000 | (uint16_t)HiImm);
+ // If the low immediate is zero the second instruction will be a nop.
+ SecondInstr = LoImm ? 0x398C0000 | (uint16_t)LoImm : 0x60000000;
+ write32(Loc + 8, SecondInstr);
+ } else {
+ // addi r12, r1, imm
+ write32(Loc + 4, (0x39810000) | (uint16_t)LoImm);
+ write32(Loc + 8, 0x60000000);
+ }
+
+ return true;
+}
+
+TargetInfo *elf::getPPC64TargetInfo() {
+ static PPC64 Target;
+ return &Target;
+}
diff --git a/contrib/llvm/tools/lld/ELF/Arch/RISCV.cpp b/contrib/llvm/tools/lld/ELF/Arch/RISCV.cpp
new file mode 100644
index 000000000000..461e8d35c3e6
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Arch/RISCV.cpp
@@ -0,0 +1,279 @@
+//===- RISCV.cpp ----------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InputFiles.h"
+#include "Target.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+
+class RISCV final : public TargetInfo {
+public:
+ RISCV();
+ uint32_t calcEFlags() const override;
+ RelExpr getRelExpr(RelType Type, const Symbol &S,
+ const uint8_t *Loc) const override;
+ void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+};
+
+} // end anonymous namespace
+
+RISCV::RISCV() { NoneRel = R_RISCV_NONE; }
+
+static uint32_t getEFlags(InputFile *F) {
+ if (Config->Is64)
+ return cast<ObjFile<ELF64LE>>(F)->getObj().getHeader()->e_flags;
+ return cast<ObjFile<ELF32LE>>(F)->getObj().getHeader()->e_flags;
+}
+
+uint32_t RISCV::calcEFlags() const {
+ assert(!ObjectFiles.empty());
+
+ uint32_t Target = getEFlags(ObjectFiles.front());
+
+ for (InputFile *F : ObjectFiles) {
+ uint32_t EFlags = getEFlags(F);
+ if (EFlags & EF_RISCV_RVC)
+ Target |= EF_RISCV_RVC;
+
+ if ((EFlags & EF_RISCV_FLOAT_ABI) != (Target & EF_RISCV_FLOAT_ABI))
+ error(toString(F) +
+ ": cannot link object files with different floating-point ABI");
+
+ if ((EFlags & EF_RISCV_RVE) != (Target & EF_RISCV_RVE))
+ error(toString(F) +
+ ": cannot link object files with different EF_RISCV_RVE");
+ }
+
+ return Target;
+}
+
+RelExpr RISCV::getRelExpr(const RelType Type, const Symbol &S,
+ const uint8_t *Loc) const {
+ switch (Type) {
+ case R_RISCV_JAL:
+ case R_RISCV_BRANCH:
+ case R_RISCV_CALL:
+ case R_RISCV_PCREL_HI20:
+ case R_RISCV_RVC_BRANCH:
+ case R_RISCV_RVC_JUMP:
+ case R_RISCV_32_PCREL:
+ return R_PC;
+ case R_RISCV_PCREL_LO12_I:
+ case R_RISCV_PCREL_LO12_S:
+ return R_RISCV_PC_INDIRECT;
+ case R_RISCV_RELAX:
+ case R_RISCV_ALIGN:
+ return R_HINT;
+ default:
+ return R_ABS;
+ }
+}
+
+// Extract bits V[Begin:End], where range is inclusive, and Begin must be < 63.
+static uint32_t extractBits(uint64_t V, uint32_t Begin, uint32_t End) {
+ return (V & ((1ULL << (Begin + 1)) - 1)) >> End;
+}
+
+void RISCV::relocateOne(uint8_t *Loc, const RelType Type,
+ const uint64_t Val) const {
+ switch (Type) {
+ case R_RISCV_32:
+ write32le(Loc, Val);
+ return;
+ case R_RISCV_64:
+ write64le(Loc, Val);
+ return;
+
+ case R_RISCV_RVC_BRANCH: {
+ checkInt(Loc, static_cast<int64_t>(Val) >> 1, 8, Type);
+ checkAlignment(Loc, Val, 2, Type);
+ uint16_t Insn = read16le(Loc) & 0xE383;
+ uint16_t Imm8 = extractBits(Val, 8, 8) << 12;
+ uint16_t Imm4_3 = extractBits(Val, 4, 3) << 10;
+ uint16_t Imm7_6 = extractBits(Val, 7, 6) << 5;
+ uint16_t Imm2_1 = extractBits(Val, 2, 1) << 3;
+ uint16_t Imm5 = extractBits(Val, 5, 5) << 2;
+ Insn |= Imm8 | Imm4_3 | Imm7_6 | Imm2_1 | Imm5;
+
+ write16le(Loc, Insn);
+ return;
+ }
+
+ case R_RISCV_RVC_JUMP: {
+ checkInt(Loc, static_cast<int64_t>(Val) >> 1, 11, Type);
+ checkAlignment(Loc, Val, 2, Type);
+ uint16_t Insn = read16le(Loc) & 0xE003;
+ uint16_t Imm11 = extractBits(Val, 11, 11) << 12;
+ uint16_t Imm4 = extractBits(Val, 4, 4) << 11;
+ uint16_t Imm9_8 = extractBits(Val, 9, 8) << 9;
+ uint16_t Imm10 = extractBits(Val, 10, 10) << 8;
+ uint16_t Imm6 = extractBits(Val, 6, 6) << 7;
+ uint16_t Imm7 = extractBits(Val, 7, 7) << 6;
+ uint16_t Imm3_1 = extractBits(Val, 3, 1) << 3;
+ uint16_t Imm5 = extractBits(Val, 5, 5) << 2;
+ Insn |= Imm11 | Imm4 | Imm9_8 | Imm10 | Imm6 | Imm7 | Imm3_1 | Imm5;
+
+ write16le(Loc, Insn);
+ return;
+ }
+
+ case R_RISCV_RVC_LUI: {
+ int32_t Imm = ((Val + 0x800) >> 12);
+ checkUInt(Loc, Imm, 6, Type);
+ if (Imm == 0) { // `c.lui rd, 0` is illegal, convert to `c.li rd, 0`
+ write16le(Loc, (read16le(Loc) & 0x0F83) | 0x4000);
+ } else {
+ uint16_t Imm17 = extractBits(Val + 0x800, 17, 17) << 12;
+ uint16_t Imm16_12 = extractBits(Val + 0x800, 16, 12) << 2;
+ write16le(Loc, (read16le(Loc) & 0xEF83) | Imm17 | Imm16_12);
+ }
+ return;
+ }
+
+ case R_RISCV_JAL: {
+ checkInt(Loc, static_cast<int64_t>(Val) >> 1, 20, Type);
+ checkAlignment(Loc, Val, 2, Type);
+
+ uint32_t Insn = read32le(Loc) & 0xFFF;
+ uint32_t Imm20 = extractBits(Val, 20, 20) << 31;
+ uint32_t Imm10_1 = extractBits(Val, 10, 1) << 21;
+ uint32_t Imm11 = extractBits(Val, 11, 11) << 20;
+ uint32_t Imm19_12 = extractBits(Val, 19, 12) << 12;
+ Insn |= Imm20 | Imm10_1 | Imm11 | Imm19_12;
+
+ write32le(Loc, Insn);
+ return;
+ }
+
+ case R_RISCV_BRANCH: {
+ checkInt(Loc, static_cast<int64_t>(Val) >> 1, 12, Type);
+ checkAlignment(Loc, Val, 2, Type);
+
+ uint32_t Insn = read32le(Loc) & 0x1FFF07F;
+ uint32_t Imm12 = extractBits(Val, 12, 12) << 31;
+ uint32_t Imm10_5 = extractBits(Val, 10, 5) << 25;
+ uint32_t Imm4_1 = extractBits(Val, 4, 1) << 8;
+ uint32_t Imm11 = extractBits(Val, 11, 11) << 7;
+ Insn |= Imm12 | Imm10_5 | Imm4_1 | Imm11;
+
+ write32le(Loc, Insn);
+ return;
+ }
+
+ // auipc + jalr pair
+ case R_RISCV_CALL: {
+ checkInt(Loc, Val, 32, Type);
+ if (isInt<32>(Val)) {
+ relocateOne(Loc, R_RISCV_PCREL_HI20, Val);
+ relocateOne(Loc + 4, R_RISCV_PCREL_LO12_I, Val);
+ }
+ return;
+ }
+
+ case R_RISCV_PCREL_HI20:
+ case R_RISCV_HI20: {
+ checkInt(Loc, Val, 32, Type);
+ uint32_t Hi = Val + 0x800;
+ write32le(Loc, (read32le(Loc) & 0xFFF) | (Hi & 0xFFFFF000));
+ return;
+ }
+
+ case R_RISCV_PCREL_LO12_I:
+ case R_RISCV_LO12_I: {
+ checkInt(Loc, Val, 32, Type);
+ uint32_t Hi = Val + 0x800;
+ uint32_t Lo = Val - (Hi & 0xFFFFF000);
+ write32le(Loc, (read32le(Loc) & 0xFFFFF) | ((Lo & 0xFFF) << 20));
+ return;
+ }
+
+ case R_RISCV_PCREL_LO12_S:
+ case R_RISCV_LO12_S: {
+ checkInt(Loc, Val, 32, Type);
+ uint32_t Hi = Val + 0x800;
+ uint32_t Lo = Val - (Hi & 0xFFFFF000);
+ uint32_t Imm11_5 = extractBits(Lo, 11, 5) << 25;
+ uint32_t Imm4_0 = extractBits(Lo, 4, 0) << 7;
+ write32le(Loc, (read32le(Loc) & 0x1FFF07F) | Imm11_5 | Imm4_0);
+ return;
+ }
+
+ case R_RISCV_ADD8:
+ *Loc += Val;
+ return;
+ case R_RISCV_ADD16:
+ write16le(Loc, read16le(Loc) + Val);
+ return;
+ case R_RISCV_ADD32:
+ write32le(Loc, read32le(Loc) + Val);
+ return;
+ case R_RISCV_ADD64:
+ write64le(Loc, read64le(Loc) + Val);
+ return;
+ case R_RISCV_SUB6:
+ *Loc = (*Loc & 0xc0) | (((*Loc & 0x3f) - Val) & 0x3f);
+ return;
+ case R_RISCV_SUB8:
+ *Loc -= Val;
+ return;
+ case R_RISCV_SUB16:
+ write16le(Loc, read16le(Loc) - Val);
+ return;
+ case R_RISCV_SUB32:
+ write32le(Loc, read32le(Loc) - Val);
+ return;
+ case R_RISCV_SUB64:
+ write64le(Loc, read64le(Loc) - Val);
+ return;
+ case R_RISCV_SET6:
+ *Loc = (*Loc & 0xc0) | (Val & 0x3f);
+ return;
+ case R_RISCV_SET8:
+ *Loc = Val;
+ return;
+ case R_RISCV_SET16:
+ write16le(Loc, Val);
+ return;
+ case R_RISCV_SET32:
+ case R_RISCV_32_PCREL:
+ write32le(Loc, Val);
+ return;
+
+ case R_RISCV_ALIGN:
+ case R_RISCV_RELAX:
+ return; // Ignored (for now)
+ case R_RISCV_NONE:
+ return; // Do nothing
+
+ // These are handled by the dynamic linker
+ case R_RISCV_RELATIVE:
+ case R_RISCV_COPY:
+ case R_RISCV_JUMP_SLOT:
+ // GP-relative relocations are only produced after relaxation, which
+ // we don't support for now
+ case R_RISCV_GPREL_I:
+ case R_RISCV_GPREL_S:
+ default:
+ error(getErrorLocation(Loc) +
+ "unimplemented relocation: " + toString(Type));
+ return;
+ }
+}
+
+TargetInfo *elf::getRISCVTargetInfo() {
+ static RISCV Target;
+ return &Target;
+}
diff --git a/contrib/llvm/tools/lld/ELF/Arch/SPARCV9.cpp b/contrib/llvm/tools/lld/ELF/Arch/SPARCV9.cpp
new file mode 100644
index 000000000000..831aa2028e7f
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Arch/SPARCV9.cpp
@@ -0,0 +1,149 @@
+//===- SPARCV9.cpp --------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "lld/Common/ErrorHandler.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+class SPARCV9 final : public TargetInfo {
+public:
+ SPARCV9();
+ RelExpr getRelExpr(RelType Type, const Symbol &S,
+ const uint8_t *Loc) const override;
+ void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
+ int32_t Index, unsigned RelOff) const override;
+ void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+};
+} // namespace
+
+SPARCV9::SPARCV9() {
+ CopyRel = R_SPARC_COPY;
+ GotRel = R_SPARC_GLOB_DAT;
+ NoneRel = R_SPARC_NONE;
+ PltRel = R_SPARC_JMP_SLOT;
+ RelativeRel = R_SPARC_RELATIVE;
+ GotEntrySize = 8;
+ PltEntrySize = 32;
+ PltHeaderSize = 4 * PltEntrySize;
+
+ PageSize = 8192;
+ DefaultMaxPageSize = 0x100000;
+ DefaultImageBase = 0x100000;
+}
+
+RelExpr SPARCV9::getRelExpr(RelType Type, const Symbol &S,
+ const uint8_t *Loc) const {
+ switch (Type) {
+ case R_SPARC_32:
+ case R_SPARC_UA32:
+ case R_SPARC_64:
+ case R_SPARC_UA64:
+ return R_ABS;
+ case R_SPARC_PC10:
+ case R_SPARC_PC22:
+ case R_SPARC_DISP32:
+ case R_SPARC_WDISP30:
+ return R_PC;
+ case R_SPARC_GOT10:
+ return R_GOT_OFF;
+ case R_SPARC_GOT22:
+ return R_GOT_OFF;
+ case R_SPARC_WPLT30:
+ return R_PLT_PC;
+ case R_SPARC_NONE:
+ return R_NONE;
+ default:
+ return R_INVALID;
+ }
+}
+
+void SPARCV9::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
+ switch (Type) {
+ case R_SPARC_32:
+ case R_SPARC_UA32:
+ // V-word32
+ checkUInt(Loc, Val, 32, Type);
+ write32be(Loc, Val);
+ break;
+ case R_SPARC_DISP32:
+ // V-disp32
+ checkInt(Loc, Val, 32, Type);
+ write32be(Loc, Val);
+ break;
+ case R_SPARC_WDISP30:
+ case R_SPARC_WPLT30:
+ // V-disp30
+ checkInt(Loc, Val, 32, Type);
+ write32be(Loc, (read32be(Loc) & ~0x3fffffff) | ((Val >> 2) & 0x3fffffff));
+ break;
+ case R_SPARC_22:
+ // V-imm22
+ checkUInt(Loc, Val, 22, Type);
+ write32be(Loc, (read32be(Loc) & ~0x003fffff) | (Val & 0x003fffff));
+ break;
+ case R_SPARC_GOT22:
+ case R_SPARC_PC22:
+ // T-imm22
+ write32be(Loc, (read32be(Loc) & ~0x003fffff) | ((Val >> 10) & 0x003fffff));
+ break;
+ case R_SPARC_WDISP19:
+ // V-disp19
+ checkInt(Loc, Val, 21, Type);
+ write32be(Loc, (read32be(Loc) & ~0x0007ffff) | ((Val >> 2) & 0x0007ffff));
+ break;
+ case R_SPARC_GOT10:
+ case R_SPARC_PC10:
+ // T-simm10
+ write32be(Loc, (read32be(Loc) & ~0x000003ff) | (Val & 0x000003ff));
+ break;
+ case R_SPARC_64:
+ case R_SPARC_UA64:
+ case R_SPARC_GLOB_DAT:
+ // V-xword64
+ write64be(Loc, Val);
+ break;
+ default:
+ error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
+ }
+}
+
+void SPARCV9::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const {
+ const uint8_t PltData[] = {
+ 0x03, 0x00, 0x00, 0x00, // sethi (. - .PLT0), %g1
+ 0x30, 0x68, 0x00, 0x00, // ba,a %xcc, .PLT1
+ 0x01, 0x00, 0x00, 0x00, // nop
+ 0x01, 0x00, 0x00, 0x00, // nop
+ 0x01, 0x00, 0x00, 0x00, // nop
+ 0x01, 0x00, 0x00, 0x00, // nop
+ 0x01, 0x00, 0x00, 0x00, // nop
+ 0x01, 0x00, 0x00, 0x00 // nop
+ };
+ memcpy(Buf, PltData, sizeof(PltData));
+
+ uint64_t Off = getPltEntryOffset(Index);
+ relocateOne(Buf, R_SPARC_22, Off);
+ relocateOne(Buf + 4, R_SPARC_WDISP19, -(Off + 4 - PltEntrySize));
+}
+
+TargetInfo *elf::getSPARCV9TargetInfo() {
+ static SPARCV9 Target;
+ return &Target;
+}
diff --git a/contrib/llvm/tools/lld/ELF/Arch/X86.cpp b/contrib/llvm/tools/lld/ELF/Arch/X86.cpp
new file mode 100644
index 000000000000..e910375d2fc7
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Arch/X86.cpp
@@ -0,0 +1,554 @@
+//===- X86.cpp ------------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "lld/Common/ErrorHandler.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+class X86 : public TargetInfo {
+public:
+ X86();
+ RelExpr getRelExpr(RelType Type, const Symbol &S,
+ const uint8_t *Loc) const override;
+ int64_t getImplicitAddend(const uint8_t *Buf, RelType Type) const override;
+ void writeGotPltHeader(uint8_t *Buf) const override;
+ RelType getDynRel(RelType Type) const override;
+ void writeGotPlt(uint8_t *Buf, const Symbol &S) const override;
+ void writeIgotPlt(uint8_t *Buf, const Symbol &S) const override;
+ void writePltHeader(uint8_t *Buf) const override;
+ void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
+ int32_t Index, unsigned RelOff) const override;
+ void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+
+ RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data,
+ RelExpr Expr) const override;
+ void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+ void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+ void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+ void relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+};
+} // namespace
+
+X86::X86() {
+ CopyRel = R_386_COPY;
+ GotRel = R_386_GLOB_DAT;
+ NoneRel = R_386_NONE;
+ PltRel = R_386_JUMP_SLOT;
+ IRelativeRel = R_386_IRELATIVE;
+ RelativeRel = R_386_RELATIVE;
+ TlsGotRel = R_386_TLS_TPOFF;
+ TlsModuleIndexRel = R_386_TLS_DTPMOD32;
+ TlsOffsetRel = R_386_TLS_DTPOFF32;
+ GotEntrySize = 4;
+ GotPltEntrySize = 4;
+ PltEntrySize = 16;
+ PltHeaderSize = 16;
+ TlsGdRelaxSkip = 2;
+ TrapInstr = {0xcc, 0xcc, 0xcc, 0xcc}; // 0xcc = INT3
+
+ // Align to the non-PAE large page size (known as a superpage or huge page).
+ // FreeBSD automatically promotes large, superpage-aligned allocations.
+ DefaultImageBase = 0x400000;
+}
+
+static bool hasBaseReg(uint8_t ModRM) { return (ModRM & 0xc7) != 0x5; }
+
+RelExpr X86::getRelExpr(RelType Type, const Symbol &S,
+ const uint8_t *Loc) const {
+ switch (Type) {
+ case R_386_8:
+ case R_386_16:
+ case R_386_32:
+ case R_386_TLS_LDO_32:
+ return R_ABS;
+ case R_386_TLS_GD:
+ return R_TLSGD_GOT_FROM_END;
+ case R_386_TLS_LDM:
+ return R_TLSLD_GOT_FROM_END;
+ case R_386_PLT32:
+ return R_PLT_PC;
+ case R_386_PC8:
+ case R_386_PC16:
+ case R_386_PC32:
+ return R_PC;
+ case R_386_GOTPC:
+ return R_GOTONLY_PC_FROM_END;
+ case R_386_TLS_IE:
+ return R_GOT;
+ case R_386_GOT32:
+ case R_386_GOT32X:
+ // These relocations are arguably mis-designed because their calculations
+ // depend on the instructions they are applied to. This is bad because we
+ // usually don't care about whether the target section contains valid
+ // machine instructions or not. But this is part of the documented ABI, so
+ // we had to implement as the standard requires.
+ //
+ // x86 does not support PC-relative data access. Therefore, in order to
+ // access GOT contents, a GOT address needs to be known at link-time
+ // (which means non-PIC) or compilers have to emit code to get a GOT
+ // address at runtime (which means code is position-independent but
+ // compilers need to emit extra code for each GOT access.) This decision
+ // is made at compile-time. In the latter case, compilers emit code to
+ // load an GOT address to a register, which is usually %ebx.
+ //
+ // So, there are two ways to refer to symbol foo's GOT entry: foo@GOT or
+ // foo@GOT(%reg).
+ //
+ // foo@GOT is not usable in PIC. If we are creating a PIC output and if we
+ // find such relocation, we should report an error. foo@GOT is resolved to
+ // an *absolute* address of foo's GOT entry, because both GOT address and
+ // foo's offset are known. In other words, it's G + A.
+ //
+ // foo@GOT(%reg) needs to be resolved to a *relative* offset from a GOT to
+ // foo's GOT entry in the table, because GOT address is not known but foo's
+ // offset in the table is known. It's G + A - GOT.
+ //
+ // It's unfortunate that compilers emit the same relocation for these
+ // different use cases. In order to distinguish them, we have to read a
+ // machine instruction.
+ //
+ // The following code implements it. We assume that Loc[0] is the first
+ // byte of a displacement or an immediate field of a valid machine
+ // instruction. That means a ModRM byte is at Loc[-1]. By taking a look at
+ // the byte, we can determine whether the instruction is register-relative
+ // (i.e. it was generated for foo@GOT(%reg)) or absolute (i.e. foo@GOT).
+ return hasBaseReg(Loc[-1]) ? R_GOT_FROM_END : R_GOT;
+ case R_386_TLS_GOTIE:
+ return R_GOT_FROM_END;
+ case R_386_GOTOFF:
+ return R_GOTREL_FROM_END;
+ case R_386_TLS_LE:
+ return R_TLS;
+ case R_386_TLS_LE_32:
+ return R_NEG_TLS;
+ case R_386_NONE:
+ return R_NONE;
+ default:
+ return R_INVALID;
+ }
+}
+
+RelExpr X86::adjustRelaxExpr(RelType Type, const uint8_t *Data,
+ RelExpr Expr) const {
+ switch (Expr) {
+ default:
+ return Expr;
+ case R_RELAX_TLS_GD_TO_IE:
+ return R_RELAX_TLS_GD_TO_IE_END;
+ case R_RELAX_TLS_GD_TO_LE:
+ return R_RELAX_TLS_GD_TO_LE_NEG;
+ }
+}
+
+void X86::writeGotPltHeader(uint8_t *Buf) const {
+ write32le(Buf, In.Dynamic->getVA());
+}
+
+void X86::writeGotPlt(uint8_t *Buf, const Symbol &S) const {
+ // Entries in .got.plt initially points back to the corresponding
+ // PLT entries with a fixed offset to skip the first instruction.
+ write32le(Buf, S.getPltVA() + 6);
+}
+
+void X86::writeIgotPlt(uint8_t *Buf, const Symbol &S) const {
+ // An x86 entry is the address of the ifunc resolver function.
+ write32le(Buf, S.getVA());
+}
+
+RelType X86::getDynRel(RelType Type) const {
+ if (Type == R_386_TLS_LE)
+ return R_386_TLS_TPOFF;
+ if (Type == R_386_TLS_LE_32)
+ return R_386_TLS_TPOFF32;
+ return Type;
+}
+
+void X86::writePltHeader(uint8_t *Buf) const {
+ if (Config->Pic) {
+ const uint8_t V[] = {
+ 0xff, 0xb3, 0x04, 0x00, 0x00, 0x00, // pushl GOTPLT+4(%ebx)
+ 0xff, 0xa3, 0x08, 0x00, 0x00, 0x00, // jmp *GOTPLT+8(%ebx)
+ 0x90, 0x90, 0x90, 0x90 // nop
+ };
+ memcpy(Buf, V, sizeof(V));
+
+ uint32_t Ebx = In.Got->getVA() + In.Got->getSize();
+ uint32_t GotPlt = In.GotPlt->getVA() - Ebx;
+ write32le(Buf + 2, GotPlt + 4);
+ write32le(Buf + 8, GotPlt + 8);
+ return;
+ }
+
+ const uint8_t PltData[] = {
+ 0xff, 0x35, 0, 0, 0, 0, // pushl (GOTPLT+4)
+ 0xff, 0x25, 0, 0, 0, 0, // jmp *(GOTPLT+8)
+ 0x90, 0x90, 0x90, 0x90, // nop
+ };
+ memcpy(Buf, PltData, sizeof(PltData));
+ uint32_t GotPlt = In.GotPlt->getVA();
+ write32le(Buf + 2, GotPlt + 4);
+ write32le(Buf + 8, GotPlt + 8);
+}
+
+void X86::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const {
+ const uint8_t Inst[] = {
+ 0xff, 0x00, 0, 0, 0, 0, // jmp *foo_in_GOT or jmp *foo@GOT(%ebx)
+ 0x68, 0, 0, 0, 0, // pushl $reloc_offset
+ 0xe9, 0, 0, 0, 0, // jmp .PLT0@PC
+ };
+ memcpy(Buf, Inst, sizeof(Inst));
+
+ if (Config->Pic) {
+ // jmp *foo@GOT(%ebx)
+ uint32_t Ebx = In.Got->getVA() + In.Got->getSize();
+ Buf[1] = 0xa3;
+ write32le(Buf + 2, GotPltEntryAddr - Ebx);
+ } else {
+ // jmp *foo_in_GOT
+ Buf[1] = 0x25;
+ write32le(Buf + 2, GotPltEntryAddr);
+ }
+
+ write32le(Buf + 7, RelOff);
+ write32le(Buf + 12, -getPltEntryOffset(Index) - 16);
+}
+
+int64_t X86::getImplicitAddend(const uint8_t *Buf, RelType Type) const {
+ switch (Type) {
+ case R_386_8:
+ case R_386_PC8:
+ return SignExtend64<8>(*Buf);
+ case R_386_16:
+ case R_386_PC16:
+ return SignExtend64<16>(read16le(Buf));
+ case R_386_32:
+ case R_386_GOT32:
+ case R_386_GOT32X:
+ case R_386_GOTOFF:
+ case R_386_GOTPC:
+ case R_386_PC32:
+ case R_386_PLT32:
+ case R_386_TLS_LDO_32:
+ case R_386_TLS_LE:
+ return SignExtend64<32>(read32le(Buf));
+ default:
+ return 0;
+ }
+}
+
+void X86::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
+ switch (Type) {
+ case R_386_8:
+ // R_386_{PC,}{8,16} are not part of the i386 psABI, but they are
+ // being used for some 16-bit programs such as boot loaders, so
+ // we want to support them.
+ checkIntUInt(Loc, Val, 8, Type);
+ *Loc = Val;
+ break;
+ case R_386_PC8:
+ checkInt(Loc, Val, 8, Type);
+ *Loc = Val;
+ break;
+ case R_386_16:
+ checkIntUInt(Loc, Val, 16, Type);
+ write16le(Loc, Val);
+ break;
+ case R_386_PC16:
+ // R_386_PC16 is normally used with 16 bit code. In that situation
+ // the PC is 16 bits, just like the addend. This means that it can
+ // point from any 16 bit address to any other if the possibility
+ // of wrapping is included.
+ // The only restriction we have to check then is that the destination
+ // address fits in 16 bits. That is impossible to do here. The problem is
+ // that we are passed the final value, which already had the
+ // current location subtracted from it.
+ // We just check that Val fits in 17 bits. This misses some cases, but
+ // should have no false positives.
+ checkInt(Loc, Val, 17, Type);
+ write16le(Loc, Val);
+ break;
+ case R_386_32:
+ case R_386_GLOB_DAT:
+ case R_386_GOT32:
+ case R_386_GOT32X:
+ case R_386_GOTOFF:
+ case R_386_GOTPC:
+ case R_386_PC32:
+ case R_386_PLT32:
+ case R_386_RELATIVE:
+ case R_386_TLS_DTPMOD32:
+ case R_386_TLS_DTPOFF32:
+ case R_386_TLS_GD:
+ case R_386_TLS_GOTIE:
+ case R_386_TLS_IE:
+ case R_386_TLS_LDM:
+ case R_386_TLS_LDO_32:
+ case R_386_TLS_LE:
+ case R_386_TLS_LE_32:
+ case R_386_TLS_TPOFF:
+ case R_386_TLS_TPOFF32:
+ checkInt(Loc, Val, 32, Type);
+ write32le(Loc, Val);
+ break;
+ default:
+ error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
+ }
+}
+
+void X86::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
+ // Convert
+ // leal x@tlsgd(, %ebx, 1),
+ // call __tls_get_addr@plt
+ // to
+ // movl %gs:0,%eax
+ // subl $x@ntpoff,%eax
+ const uint8_t Inst[] = {
+ 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax
+ 0x81, 0xe8, 0, 0, 0, 0, // subl Val(%ebx), %eax
+ };
+ memcpy(Loc - 3, Inst, sizeof(Inst));
+ write32le(Loc + 5, Val);
+}
+
+void X86::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const {
+ // Convert
+ // leal x@tlsgd(, %ebx, 1),
+ // call __tls_get_addr@plt
+ // to
+ // movl %gs:0, %eax
+ // addl x@gotntpoff(%ebx), %eax
+ const uint8_t Inst[] = {
+ 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax
+ 0x03, 0x83, 0, 0, 0, 0, // addl Val(%ebx), %eax
+ };
+ memcpy(Loc - 3, Inst, sizeof(Inst));
+ write32le(Loc + 5, Val);
+}
+
+// In some conditions, relocations can be optimized to avoid using GOT.
+// This function does that for Initial Exec to Local Exec case.
+void X86::relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
+ // Ulrich's document section 6.2 says that @gotntpoff can
+ // be used with MOVL or ADDL instructions.
+ // @indntpoff is similar to @gotntpoff, but for use in
+ // position dependent code.
+ uint8_t Reg = (Loc[-1] >> 3) & 7;
+
+ if (Type == R_386_TLS_IE) {
+ if (Loc[-1] == 0xa1) {
+ // "movl foo@indntpoff,%eax" -> "movl $foo,%eax"
+ // This case is different from the generic case below because
+ // this is a 5 byte instruction while below is 6 bytes.
+ Loc[-1] = 0xb8;
+ } else if (Loc[-2] == 0x8b) {
+ // "movl foo@indntpoff,%reg" -> "movl $foo,%reg"
+ Loc[-2] = 0xc7;
+ Loc[-1] = 0xc0 | Reg;
+ } else {
+ // "addl foo@indntpoff,%reg" -> "addl $foo,%reg"
+ Loc[-2] = 0x81;
+ Loc[-1] = 0xc0 | Reg;
+ }
+ } else {
+ assert(Type == R_386_TLS_GOTIE);
+ if (Loc[-2] == 0x8b) {
+ // "movl foo@gottpoff(%rip),%reg" -> "movl $foo,%reg"
+ Loc[-2] = 0xc7;
+ Loc[-1] = 0xc0 | Reg;
+ } else {
+ // "addl foo@gotntpoff(%rip),%reg" -> "leal foo(%reg),%reg"
+ Loc[-2] = 0x8d;
+ Loc[-1] = 0x80 | (Reg << 3) | Reg;
+ }
+ }
+ write32le(Loc, Val);
+}
+
+void X86::relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
+ if (Type == R_386_TLS_LDO_32) {
+ write32le(Loc, Val);
+ return;
+ }
+
+ // Convert
+ // leal foo(%reg),%eax
+ // call ___tls_get_addr
+ // to
+ // movl %gs:0,%eax
+ // nop
+ // leal 0(%esi,1),%esi
+ const uint8_t Inst[] = {
+ 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0,%eax
+ 0x90, // nop
+ 0x8d, 0x74, 0x26, 0x00, // leal 0(%esi,1),%esi
+ };
+ memcpy(Loc - 2, Inst, sizeof(Inst));
+}
+
+namespace {
+class RetpolinePic : public X86 {
+public:
+ RetpolinePic();
+ void writeGotPlt(uint8_t *Buf, const Symbol &S) const override;
+ void writePltHeader(uint8_t *Buf) const override;
+ void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
+ int32_t Index, unsigned RelOff) const override;
+};
+
+class RetpolineNoPic : public X86 {
+public:
+ RetpolineNoPic();
+ void writeGotPlt(uint8_t *Buf, const Symbol &S) const override;
+ void writePltHeader(uint8_t *Buf) const override;
+ void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
+ int32_t Index, unsigned RelOff) const override;
+};
+} // namespace
+
+RetpolinePic::RetpolinePic() {
+ PltHeaderSize = 48;
+ PltEntrySize = 32;
+}
+
+void RetpolinePic::writeGotPlt(uint8_t *Buf, const Symbol &S) const {
+ write32le(Buf, S.getPltVA() + 17);
+}
+
+void RetpolinePic::writePltHeader(uint8_t *Buf) const {
+ const uint8_t Insn[] = {
+ 0xff, 0xb3, 0, 0, 0, 0, // 0: pushl GOTPLT+4(%ebx)
+ 0x50, // 6: pushl %eax
+ 0x8b, 0x83, 0, 0, 0, 0, // 7: mov GOTPLT+8(%ebx), %eax
+ 0xe8, 0x0e, 0x00, 0x00, 0x00, // d: call next
+ 0xf3, 0x90, // 12: loop: pause
+ 0x0f, 0xae, 0xe8, // 14: lfence
+ 0xeb, 0xf9, // 17: jmp loop
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 19: int3; .align 16
+ 0x89, 0x0c, 0x24, // 20: next: mov %ecx, (%esp)
+ 0x8b, 0x4c, 0x24, 0x04, // 23: mov 0x4(%esp), %ecx
+ 0x89, 0x44, 0x24, 0x04, // 27: mov %eax ,0x4(%esp)
+ 0x89, 0xc8, // 2b: mov %ecx, %eax
+ 0x59, // 2d: pop %ecx
+ 0xc3, // 2e: ret
+ 0xcc, // 2f: int3; padding
+ };
+ memcpy(Buf, Insn, sizeof(Insn));
+
+ uint32_t Ebx = In.Got->getVA() + In.Got->getSize();
+ uint32_t GotPlt = In.GotPlt->getVA() - Ebx;
+ write32le(Buf + 2, GotPlt + 4);
+ write32le(Buf + 9, GotPlt + 8);
+}
+
+void RetpolinePic::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const {
+ const uint8_t Insn[] = {
+ 0x50, // pushl %eax
+ 0x8b, 0x83, 0, 0, 0, 0, // mov foo@GOT(%ebx), %eax
+ 0xe8, 0, 0, 0, 0, // call plt+0x20
+ 0xe9, 0, 0, 0, 0, // jmp plt+0x12
+ 0x68, 0, 0, 0, 0, // pushl $reloc_offset
+ 0xe9, 0, 0, 0, 0, // jmp plt+0
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // int3; padding
+ };
+ memcpy(Buf, Insn, sizeof(Insn));
+
+ uint32_t Ebx = In.Got->getVA() + In.Got->getSize();
+ unsigned Off = getPltEntryOffset(Index);
+ write32le(Buf + 3, GotPltEntryAddr - Ebx);
+ write32le(Buf + 8, -Off - 12 + 32);
+ write32le(Buf + 13, -Off - 17 + 18);
+ write32le(Buf + 18, RelOff);
+ write32le(Buf + 23, -Off - 27);
+}
+
+RetpolineNoPic::RetpolineNoPic() {
+ PltHeaderSize = 48;
+ PltEntrySize = 32;
+}
+
+void RetpolineNoPic::writeGotPlt(uint8_t *Buf, const Symbol &S) const {
+ write32le(Buf, S.getPltVA() + 16);
+}
+
+void RetpolineNoPic::writePltHeader(uint8_t *Buf) const {
+ const uint8_t Insn[] = {
+ 0xff, 0x35, 0, 0, 0, 0, // 0: pushl GOTPLT+4
+ 0x50, // 6: pushl %eax
+ 0xa1, 0, 0, 0, 0, // 7: mov GOTPLT+8, %eax
+ 0xe8, 0x0f, 0x00, 0x00, 0x00, // c: call next
+ 0xf3, 0x90, // 11: loop: pause
+ 0x0f, 0xae, 0xe8, // 13: lfence
+ 0xeb, 0xf9, // 16: jmp loop
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 18: int3
+ 0xcc, 0xcc, 0xcc, // 1f: int3; .align 16
+ 0x89, 0x0c, 0x24, // 20: next: mov %ecx, (%esp)
+ 0x8b, 0x4c, 0x24, 0x04, // 23: mov 0x4(%esp), %ecx
+ 0x89, 0x44, 0x24, 0x04, // 27: mov %eax ,0x4(%esp)
+ 0x89, 0xc8, // 2b: mov %ecx, %eax
+ 0x59, // 2d: pop %ecx
+ 0xc3, // 2e: ret
+ 0xcc, // 2f: int3; padding
+ };
+ memcpy(Buf, Insn, sizeof(Insn));
+
+ uint32_t GotPlt = In.GotPlt->getVA();
+ write32le(Buf + 2, GotPlt + 4);
+ write32le(Buf + 8, GotPlt + 8);
+}
+
+void RetpolineNoPic::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const {
+ const uint8_t Insn[] = {
+ 0x50, // 0: pushl %eax
+ 0xa1, 0, 0, 0, 0, // 1: mov foo_in_GOT, %eax
+ 0xe8, 0, 0, 0, 0, // 6: call plt+0x20
+ 0xe9, 0, 0, 0, 0, // b: jmp plt+0x11
+ 0x68, 0, 0, 0, 0, // 10: pushl $reloc_offset
+ 0xe9, 0, 0, 0, 0, // 15: jmp plt+0
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 1a: int3; padding
+ 0xcc, // 1f: int3; padding
+ };
+ memcpy(Buf, Insn, sizeof(Insn));
+
+ unsigned Off = getPltEntryOffset(Index);
+ write32le(Buf + 2, GotPltEntryAddr);
+ write32le(Buf + 7, -Off - 11 + 32);
+ write32le(Buf + 12, -Off - 16 + 17);
+ write32le(Buf + 17, RelOff);
+ write32le(Buf + 22, -Off - 26);
+}
+
+TargetInfo *elf::getX86TargetInfo() {
+ if (Config->ZRetpolineplt) {
+ if (Config->Pic) {
+ static RetpolinePic T;
+ return &T;
+ }
+ static RetpolineNoPic T;
+ return &T;
+ }
+
+ static X86 T;
+ return &T;
+}
diff --git a/contrib/llvm/tools/lld/ELF/Arch/X86_64.cpp b/contrib/llvm/tools/lld/ELF/Arch/X86_64.cpp
new file mode 100644
index 000000000000..a000eeb079d9
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Arch/X86_64.cpp
@@ -0,0 +1,677 @@
+//===- X86_64.cpp ---------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "lld/Common/ErrorHandler.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+template <class ELFT> class X86_64 : public TargetInfo {
+public:
+ X86_64();
+ RelExpr getRelExpr(RelType Type, const Symbol &S,
+ const uint8_t *Loc) const override;
+ RelType getDynRel(RelType Type) const override;
+ void writeGotPltHeader(uint8_t *Buf) const override;
+ void writeGotPlt(uint8_t *Buf, const Symbol &S) const override;
+ void writePltHeader(uint8_t *Buf) const override;
+ void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
+ int32_t Index, unsigned RelOff) const override;
+ void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+
+ RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data,
+ RelExpr Expr) const override;
+ void relaxGot(uint8_t *Loc, uint64_t Val) const override;
+ void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+ void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+ void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+ void relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+ bool adjustPrologueForCrossSplitStack(uint8_t *Loc, uint8_t *End,
+ uint8_t StOther) const override;
+
+private:
+ void relaxGotNoPic(uint8_t *Loc, uint64_t Val, uint8_t Op,
+ uint8_t ModRm) const;
+};
+} // namespace
+
+template <class ELFT> X86_64<ELFT>::X86_64() {
+ CopyRel = R_X86_64_COPY;
+ GotRel = R_X86_64_GLOB_DAT;
+ NoneRel = R_X86_64_NONE;
+ PltRel = R_X86_64_JUMP_SLOT;
+ RelativeRel = R_X86_64_RELATIVE;
+ IRelativeRel = R_X86_64_IRELATIVE;
+ TlsGotRel = R_X86_64_TPOFF64;
+ TlsModuleIndexRel = R_X86_64_DTPMOD64;
+ TlsOffsetRel = R_X86_64_DTPOFF64;
+ GotEntrySize = 8;
+ GotPltEntrySize = 8;
+ PltEntrySize = 16;
+ PltHeaderSize = 16;
+ TlsGdRelaxSkip = 2;
+ TrapInstr = {0xcc, 0xcc, 0xcc, 0xcc}; // 0xcc = INT3
+
+ // Align to the large page size (known as a superpage or huge page).
+ // FreeBSD automatically promotes large, superpage-aligned allocations.
+ DefaultImageBase = 0x200000;
+}
+
+template <class ELFT>
+RelExpr X86_64<ELFT>::getRelExpr(RelType Type, const Symbol &S,
+ const uint8_t *Loc) const {
+ switch (Type) {
+ case R_X86_64_8:
+ case R_X86_64_16:
+ case R_X86_64_32:
+ case R_X86_64_32S:
+ case R_X86_64_64:
+ case R_X86_64_DTPOFF32:
+ case R_X86_64_DTPOFF64:
+ return R_ABS;
+ case R_X86_64_TPOFF32:
+ return R_TLS;
+ case R_X86_64_TLSLD:
+ return R_TLSLD_PC;
+ case R_X86_64_TLSGD:
+ return R_TLSGD_PC;
+ case R_X86_64_SIZE32:
+ case R_X86_64_SIZE64:
+ return R_SIZE;
+ case R_X86_64_PLT32:
+ return R_PLT_PC;
+ case R_X86_64_PC32:
+ case R_X86_64_PC64:
+ return R_PC;
+ case R_X86_64_GOT32:
+ case R_X86_64_GOT64:
+ return R_GOT_FROM_END;
+ case R_X86_64_GOTPCREL:
+ case R_X86_64_GOTPCRELX:
+ case R_X86_64_REX_GOTPCRELX:
+ case R_X86_64_GOTTPOFF:
+ return R_GOT_PC;
+ case R_X86_64_GOTOFF64:
+ return R_GOTREL_FROM_END;
+ case R_X86_64_GOTPC32:
+ case R_X86_64_GOTPC64:
+ return R_GOTONLY_PC_FROM_END;
+ case R_X86_64_NONE:
+ return R_NONE;
+ default:
+ return R_INVALID;
+ }
+}
+
+template <class ELFT> void X86_64<ELFT>::writeGotPltHeader(uint8_t *Buf) const {
+ // The first entry holds the value of _DYNAMIC. It is not clear why that is
+ // required, but it is documented in the psabi and the glibc dynamic linker
+ // seems to use it (note that this is relevant for linking ld.so, not any
+ // other program).
+ write64le(Buf, In.Dynamic->getVA());
+}
+
+template <class ELFT>
+void X86_64<ELFT>::writeGotPlt(uint8_t *Buf, const Symbol &S) const {
+ // See comments in X86::writeGotPlt.
+ write64le(Buf, S.getPltVA() + 6);
+}
+
+template <class ELFT> void X86_64<ELFT>::writePltHeader(uint8_t *Buf) const {
+ const uint8_t PltData[] = {
+ 0xff, 0x35, 0, 0, 0, 0, // pushq GOTPLT+8(%rip)
+ 0xff, 0x25, 0, 0, 0, 0, // jmp *GOTPLT+16(%rip)
+ 0x0f, 0x1f, 0x40, 0x00, // nop
+ };
+ memcpy(Buf, PltData, sizeof(PltData));
+ uint64_t GotPlt = In.GotPlt->getVA();
+ uint64_t Plt = In.Plt->getVA();
+ write32le(Buf + 2, GotPlt - Plt + 2); // GOTPLT+8
+ write32le(Buf + 8, GotPlt - Plt + 4); // GOTPLT+16
+}
+
+template <class ELFT>
+void X86_64<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const {
+ const uint8_t Inst[] = {
+ 0xff, 0x25, 0, 0, 0, 0, // jmpq *got(%rip)
+ 0x68, 0, 0, 0, 0, // pushq <relocation index>
+ 0xe9, 0, 0, 0, 0, // jmpq plt[0]
+ };
+ memcpy(Buf, Inst, sizeof(Inst));
+
+ write32le(Buf + 2, GotPltEntryAddr - PltEntryAddr - 6);
+ write32le(Buf + 7, Index);
+ write32le(Buf + 12, -getPltEntryOffset(Index) - 16);
+}
+
+template <class ELFT> RelType X86_64<ELFT>::getDynRel(RelType Type) const {
+ if (Type == R_X86_64_64 || Type == R_X86_64_PC64 || Type == R_X86_64_SIZE32 ||
+ Type == R_X86_64_SIZE64)
+ return Type;
+ return R_X86_64_NONE;
+}
+
+template <class ELFT>
+void X86_64<ELFT>::relaxTlsGdToLe(uint8_t *Loc, RelType Type,
+ uint64_t Val) const {
+ // Convert
+ // .byte 0x66
+ // leaq x@tlsgd(%rip), %rdi
+ // .word 0x6666
+ // rex64
+ // call __tls_get_addr@plt
+ // to
+ // mov %fs:0x0,%rax
+ // lea x@tpoff,%rax
+ const uint8_t Inst[] = {
+ 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0x0,%rax
+ 0x48, 0x8d, 0x80, 0, 0, 0, 0, // lea x@tpoff,%rax
+ };
+ memcpy(Loc - 4, Inst, sizeof(Inst));
+
+ // The original code used a pc relative relocation and so we have to
+ // compensate for the -4 in had in the addend.
+ write32le(Loc + 8, Val + 4);
+}
+
+template <class ELFT>
+void X86_64<ELFT>::relaxTlsGdToIe(uint8_t *Loc, RelType Type,
+ uint64_t Val) const {
+ // Convert
+ // .byte 0x66
+ // leaq x@tlsgd(%rip), %rdi
+ // .word 0x6666
+ // rex64
+ // call __tls_get_addr@plt
+ // to
+ // mov %fs:0x0,%rax
+ // addq x@tpoff,%rax
+ const uint8_t Inst[] = {
+ 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0x0,%rax
+ 0x48, 0x03, 0x05, 0, 0, 0, 0, // addq x@tpoff,%rax
+ };
+ memcpy(Loc - 4, Inst, sizeof(Inst));
+
+ // Both code sequences are PC relatives, but since we are moving the constant
+ // forward by 8 bytes we have to subtract the value by 8.
+ write32le(Loc + 8, Val - 8);
+}
+
+// In some conditions, R_X86_64_GOTTPOFF relocation can be optimized to
+// R_X86_64_TPOFF32 so that it does not use GOT.
+template <class ELFT>
+void X86_64<ELFT>::relaxTlsIeToLe(uint8_t *Loc, RelType Type,
+ uint64_t Val) const {
+ uint8_t *Inst = Loc - 3;
+ uint8_t Reg = Loc[-1] >> 3;
+ uint8_t *RegSlot = Loc - 1;
+
+ // Note that ADD with RSP or R12 is converted to ADD instead of LEA
+ // because LEA with these registers needs 4 bytes to encode and thus
+ // wouldn't fit the space.
+
+ if (memcmp(Inst, "\x48\x03\x25", 3) == 0) {
+ // "addq foo@gottpoff(%rip),%rsp" -> "addq $foo,%rsp"
+ memcpy(Inst, "\x48\x81\xc4", 3);
+ } else if (memcmp(Inst, "\x4c\x03\x25", 3) == 0) {
+ // "addq foo@gottpoff(%rip),%r12" -> "addq $foo,%r12"
+ memcpy(Inst, "\x49\x81\xc4", 3);
+ } else if (memcmp(Inst, "\x4c\x03", 2) == 0) {
+ // "addq foo@gottpoff(%rip),%r[8-15]" -> "leaq foo(%r[8-15]),%r[8-15]"
+ memcpy(Inst, "\x4d\x8d", 2);
+ *RegSlot = 0x80 | (Reg << 3) | Reg;
+ } else if (memcmp(Inst, "\x48\x03", 2) == 0) {
+ // "addq foo@gottpoff(%rip),%reg -> "leaq foo(%reg),%reg"
+ memcpy(Inst, "\x48\x8d", 2);
+ *RegSlot = 0x80 | (Reg << 3) | Reg;
+ } else if (memcmp(Inst, "\x4c\x8b", 2) == 0) {
+ // "movq foo@gottpoff(%rip),%r[8-15]" -> "movq $foo,%r[8-15]"
+ memcpy(Inst, "\x49\xc7", 2);
+ *RegSlot = 0xc0 | Reg;
+ } else if (memcmp(Inst, "\x48\x8b", 2) == 0) {
+ // "movq foo@gottpoff(%rip),%reg" -> "movq $foo,%reg"
+ memcpy(Inst, "\x48\xc7", 2);
+ *RegSlot = 0xc0 | Reg;
+ } else {
+ error(getErrorLocation(Loc - 3) +
+ "R_X86_64_GOTTPOFF must be used in MOVQ or ADDQ instructions only");
+ }
+
+ // The original code used a PC relative relocation.
+ // Need to compensate for the -4 it had in the addend.
+ write32le(Loc, Val + 4);
+}
+
+template <class ELFT>
+void X86_64<ELFT>::relaxTlsLdToLe(uint8_t *Loc, RelType Type,
+ uint64_t Val) const {
+ if (Type == R_X86_64_DTPOFF64) {
+ write64le(Loc, Val);
+ return;
+ }
+ if (Type == R_X86_64_DTPOFF32) {
+ write32le(Loc, Val);
+ return;
+ }
+
+ const uint8_t Inst[] = {
+ 0x66, 0x66, // .word 0x6666
+ 0x66, // .byte 0x66
+ 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0,%rax
+ };
+
+ if (Loc[4] == 0xe8) {
+ // Convert
+ // leaq bar@tlsld(%rip), %rdi # 48 8d 3d <Loc>
+ // callq __tls_get_addr@PLT # e8 <disp32>
+ // leaq bar@dtpoff(%rax), %rcx
+ // to
+ // .word 0x6666
+ // .byte 0x66
+ // mov %fs:0,%rax
+ // leaq bar@tpoff(%rax), %rcx
+ memcpy(Loc - 3, Inst, sizeof(Inst));
+ return;
+ }
+
+ if (Loc[4] == 0xff && Loc[5] == 0x15) {
+ // Convert
+ // leaq x@tlsld(%rip),%rdi # 48 8d 3d <Loc>
+ // call *__tls_get_addr@GOTPCREL(%rip) # ff 15 <disp32>
+ // to
+ // .long 0x66666666
+ // movq %fs:0,%rax
+ // See "Table 11.9: LD -> LE Code Transition (LP64)" in
+ // https://raw.githubusercontent.com/wiki/hjl-tools/x86-psABI/x86-64-psABI-1.0.pdf
+ Loc[-3] = 0x66;
+ memcpy(Loc - 2, Inst, sizeof(Inst));
+ return;
+ }
+
+ error(getErrorLocation(Loc - 3) +
+ "expected R_X86_64_PLT32 or R_X86_64_GOTPCRELX after R_X86_64_TLSLD");
+}
+
+template <class ELFT>
+void X86_64<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
+ switch (Type) {
+ case R_X86_64_8:
+ checkUInt(Loc, Val, 8, Type);
+ *Loc = Val;
+ break;
+ case R_X86_64_16:
+ checkUInt(Loc, Val, 16, Type);
+ write16le(Loc, Val);
+ break;
+ case R_X86_64_32:
+ checkUInt(Loc, Val, 32, Type);
+ write32le(Loc, Val);
+ break;
+ case R_X86_64_32S:
+ case R_X86_64_TPOFF32:
+ case R_X86_64_GOT32:
+ case R_X86_64_GOTPC32:
+ case R_X86_64_GOTPCREL:
+ case R_X86_64_GOTPCRELX:
+ case R_X86_64_REX_GOTPCRELX:
+ case R_X86_64_PC32:
+ case R_X86_64_GOTTPOFF:
+ case R_X86_64_PLT32:
+ case R_X86_64_TLSGD:
+ case R_X86_64_TLSLD:
+ case R_X86_64_DTPOFF32:
+ case R_X86_64_SIZE32:
+ checkInt(Loc, Val, 32, Type);
+ write32le(Loc, Val);
+ break;
+ case R_X86_64_64:
+ case R_X86_64_DTPOFF64:
+ case R_X86_64_GLOB_DAT:
+ case R_X86_64_PC64:
+ case R_X86_64_SIZE64:
+ case R_X86_64_GOT64:
+ case R_X86_64_GOTOFF64:
+ case R_X86_64_GOTPC64:
+ write64le(Loc, Val);
+ break;
+ default:
+ error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
+ }
+}
+
+template <class ELFT>
+RelExpr X86_64<ELFT>::adjustRelaxExpr(RelType Type, const uint8_t *Data,
+ RelExpr RelExpr) const {
+ if (Type != R_X86_64_GOTPCRELX && Type != R_X86_64_REX_GOTPCRELX)
+ return RelExpr;
+ const uint8_t Op = Data[-2];
+ const uint8_t ModRm = Data[-1];
+
+ // FIXME: When PIC is disabled and foo is defined locally in the
+ // lower 32 bit address space, memory operand in mov can be converted into
+ // immediate operand. Otherwise, mov must be changed to lea. We support only
+ // latter relaxation at this moment.
+ if (Op == 0x8b)
+ return R_RELAX_GOT_PC;
+
+ // Relax call and jmp.
+ if (Op == 0xff && (ModRm == 0x15 || ModRm == 0x25))
+ return R_RELAX_GOT_PC;
+
+ // Relaxation of test, adc, add, and, cmp, or, sbb, sub, xor.
+ // If PIC then no relaxation is available.
+ // We also don't relax test/binop instructions without REX byte,
+ // they are 32bit operations and not common to have.
+ assert(Type == R_X86_64_REX_GOTPCRELX);
+ return Config->Pic ? RelExpr : R_RELAX_GOT_PC_NOPIC;
+}
+
+// A subset of relaxations can only be applied for no-PIC. This method
+// handles such relaxations. Instructions encoding information was taken from:
+// "Intel 64 and IA-32 Architectures Software Developer's Manual V2"
+// (http://www.intel.com/content/dam/www/public/us/en/documents/manuals/
+// 64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf)
+template <class ELFT>
+void X86_64<ELFT>::relaxGotNoPic(uint8_t *Loc, uint64_t Val, uint8_t Op,
+ uint8_t ModRm) const {
+ const uint8_t Rex = Loc[-3];
+ // Convert "test %reg, foo@GOTPCREL(%rip)" to "test $foo, %reg".
+ if (Op == 0x85) {
+ // See "TEST-Logical Compare" (4-428 Vol. 2B),
+ // TEST r/m64, r64 uses "full" ModR / M byte (no opcode extension).
+
+ // ModR/M byte has form XX YYY ZZZ, where
+ // YYY is MODRM.reg(register 2), ZZZ is MODRM.rm(register 1).
+ // XX has different meanings:
+ // 00: The operand's memory address is in reg1.
+ // 01: The operand's memory address is reg1 + a byte-sized displacement.
+ // 10: The operand's memory address is reg1 + a word-sized displacement.
+ // 11: The operand is reg1 itself.
+ // If an instruction requires only one operand, the unused reg2 field
+ // holds extra opcode bits rather than a register code
+ // 0xC0 == 11 000 000 binary.
+ // 0x38 == 00 111 000 binary.
+ // We transfer reg2 to reg1 here as operand.
+ // See "2.1.3 ModR/M and SIB Bytes" (Vol. 2A 2-3).
+ Loc[-1] = 0xc0 | (ModRm & 0x38) >> 3; // ModR/M byte.
+
+ // Change opcode from TEST r/m64, r64 to TEST r/m64, imm32
+ // See "TEST-Logical Compare" (4-428 Vol. 2B).
+ Loc[-2] = 0xf7;
+
+ // Move R bit to the B bit in REX byte.
+ // REX byte is encoded as 0100WRXB, where
+ // 0100 is 4bit fixed pattern.
+ // REX.W When 1, a 64-bit operand size is used. Otherwise, when 0, the
+ // default operand size is used (which is 32-bit for most but not all
+ // instructions).
+ // REX.R This 1-bit value is an extension to the MODRM.reg field.
+ // REX.X This 1-bit value is an extension to the SIB.index field.
+ // REX.B This 1-bit value is an extension to the MODRM.rm field or the
+ // SIB.base field.
+ // See "2.2.1.2 More on REX Prefix Fields " (2-8 Vol. 2A).
+ Loc[-3] = (Rex & ~0x4) | (Rex & 0x4) >> 2;
+ write32le(Loc, Val);
+ return;
+ }
+
+ // If we are here then we need to relax the adc, add, and, cmp, or, sbb, sub
+ // or xor operations.
+
+ // Convert "binop foo@GOTPCREL(%rip), %reg" to "binop $foo, %reg".
+ // Logic is close to one for test instruction above, but we also
+ // write opcode extension here, see below for details.
+ Loc[-1] = 0xc0 | (ModRm & 0x38) >> 3 | (Op & 0x3c); // ModR/M byte.
+
+ // Primary opcode is 0x81, opcode extension is one of:
+ // 000b = ADD, 001b is OR, 010b is ADC, 011b is SBB,
+ // 100b is AND, 101b is SUB, 110b is XOR, 111b is CMP.
+ // This value was wrote to MODRM.reg in a line above.
+ // See "3.2 INSTRUCTIONS (A-M)" (Vol. 2A 3-15),
+ // "INSTRUCTION SET REFERENCE, N-Z" (Vol. 2B 4-1) for
+ // descriptions about each operation.
+ Loc[-2] = 0x81;
+ Loc[-3] = (Rex & ~0x4) | (Rex & 0x4) >> 2;
+ write32le(Loc, Val);
+}
+
+template <class ELFT>
+void X86_64<ELFT>::relaxGot(uint8_t *Loc, uint64_t Val) const {
+ const uint8_t Op = Loc[-2];
+ const uint8_t ModRm = Loc[-1];
+
+ // Convert "mov foo@GOTPCREL(%rip),%reg" to "lea foo(%rip),%reg".
+ if (Op == 0x8b) {
+ Loc[-2] = 0x8d;
+ write32le(Loc, Val);
+ return;
+ }
+
+ if (Op != 0xff) {
+ // We are relaxing a rip relative to an absolute, so compensate
+ // for the old -4 addend.
+ assert(!Config->Pic);
+ relaxGotNoPic(Loc, Val + 4, Op, ModRm);
+ return;
+ }
+
+ // Convert call/jmp instructions.
+ if (ModRm == 0x15) {
+ // ABI says we can convert "call *foo@GOTPCREL(%rip)" to "nop; call foo".
+ // Instead we convert to "addr32 call foo" where addr32 is an instruction
+ // prefix. That makes result expression to be a single instruction.
+ Loc[-2] = 0x67; // addr32 prefix
+ Loc[-1] = 0xe8; // call
+ write32le(Loc, Val);
+ return;
+ }
+
+ // Convert "jmp *foo@GOTPCREL(%rip)" to "jmp foo; nop".
+ // jmp doesn't return, so it is fine to use nop here, it is just a stub.
+ assert(ModRm == 0x25);
+ Loc[-2] = 0xe9; // jmp
+ Loc[3] = 0x90; // nop
+ write32le(Loc - 1, Val + 1);
+}
+
+// This anonymous namespace works around a warning bug in
+// old versions of gcc. See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480
+namespace {
+
+// A split-stack prologue starts by checking the amount of stack remaining
+// in one of two ways:
+// A) Comparing of the stack pointer to a field in the tcb.
+// B) Or a load of a stack pointer offset with an lea to r10 or r11.
+template <>
+bool X86_64<ELF64LE>::adjustPrologueForCrossSplitStack(uint8_t *Loc,
+ uint8_t *End,
+ uint8_t StOther) const {
+ if (Loc + 8 >= End)
+ return false;
+
+ // Replace "cmp %fs:0x70,%rsp" and subsequent branch
+ // with "stc, nopl 0x0(%rax,%rax,1)"
+ if (memcmp(Loc, "\x64\x48\x3b\x24\x25", 5) == 0) {
+ memcpy(Loc, "\xf9\x0f\x1f\x84\x00\x00\x00\x00", 8);
+ return true;
+ }
+
+ // Adjust "lea X(%rsp),%rYY" to lea "(X - 0x4000)(%rsp),%rYY" where rYY could
+ // be r10 or r11. The lea instruction feeds a subsequent compare which checks
+ // if there is X available stack space. Making X larger effectively reserves
+ // that much additional space. The stack grows downward so subtract the value.
+ if (memcmp(Loc, "\x4c\x8d\x94\x24", 4) == 0 ||
+ memcmp(Loc, "\x4c\x8d\x9c\x24", 4) == 0) {
+ // The offset bytes are encoded four bytes after the start of the
+ // instruction.
+ write32le(Loc + 4, read32le(Loc + 4) - 0x4000);
+ return true;
+ }
+ return false;
+}
+
+template <>
+bool X86_64<ELF32LE>::adjustPrologueForCrossSplitStack(uint8_t *Loc,
+ uint8_t *End,
+ uint8_t StOther) const {
+ llvm_unreachable("Target doesn't support split stacks.");
+}
+
+} // namespace
+
+// These nonstandard PLT entries are to migtigate Spectre v2 security
+// vulnerability. In order to mitigate Spectre v2, we want to avoid indirect
+// branch instructions such as `jmp *GOTPLT(%rip)`. So, in the following PLT
+// entries, we use a CALL followed by MOV and RET to do the same thing as an
+// indirect jump. That instruction sequence is so-called "retpoline".
+//
+// We have two types of retpoline PLTs as a size optimization. If `-z now`
+// is specified, all dynamic symbols are resolved at load-time. Thus, when
+// that option is given, we can omit code for symbol lazy resolution.
+namespace {
+template <class ELFT> class Retpoline : public X86_64<ELFT> {
+public:
+ Retpoline();
+ void writeGotPlt(uint8_t *Buf, const Symbol &S) const override;
+ void writePltHeader(uint8_t *Buf) const override;
+ void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
+ int32_t Index, unsigned RelOff) const override;
+};
+
+template <class ELFT> class RetpolineZNow : public X86_64<ELFT> {
+public:
+ RetpolineZNow();
+ void writeGotPlt(uint8_t *Buf, const Symbol &S) const override {}
+ void writePltHeader(uint8_t *Buf) const override;
+ void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
+ int32_t Index, unsigned RelOff) const override;
+};
+} // namespace
+
+template <class ELFT> Retpoline<ELFT>::Retpoline() {
+ TargetInfo::PltHeaderSize = 48;
+ TargetInfo::PltEntrySize = 32;
+}
+
+template <class ELFT>
+void Retpoline<ELFT>::writeGotPlt(uint8_t *Buf, const Symbol &S) const {
+ write64le(Buf, S.getPltVA() + 17);
+}
+
+template <class ELFT> void Retpoline<ELFT>::writePltHeader(uint8_t *Buf) const {
+ const uint8_t Insn[] = {
+ 0xff, 0x35, 0, 0, 0, 0, // 0: pushq GOTPLT+8(%rip)
+ 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // 6: mov GOTPLT+16(%rip), %r11
+ 0xe8, 0x0e, 0x00, 0x00, 0x00, // d: callq next
+ 0xf3, 0x90, // 12: loop: pause
+ 0x0f, 0xae, 0xe8, // 14: lfence
+ 0xeb, 0xf9, // 17: jmp loop
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 19: int3; .align 16
+ 0x4c, 0x89, 0x1c, 0x24, // 20: next: mov %r11, (%rsp)
+ 0xc3, // 24: ret
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 25: int3; padding
+ 0xcc, 0xcc, 0xcc, 0xcc, // 2c: int3; padding
+ };
+ memcpy(Buf, Insn, sizeof(Insn));
+
+ uint64_t GotPlt = In.GotPlt->getVA();
+ uint64_t Plt = In.Plt->getVA();
+ write32le(Buf + 2, GotPlt - Plt - 6 + 8);
+ write32le(Buf + 9, GotPlt - Plt - 13 + 16);
+}
+
+template <class ELFT>
+void Retpoline<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const {
+ const uint8_t Insn[] = {
+ 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // 0: mov foo@GOTPLT(%rip), %r11
+ 0xe8, 0, 0, 0, 0, // 7: callq plt+0x20
+ 0xe9, 0, 0, 0, 0, // c: jmp plt+0x12
+ 0x68, 0, 0, 0, 0, // 11: pushq <relocation index>
+ 0xe9, 0, 0, 0, 0, // 16: jmp plt+0
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 1b: int3; padding
+ };
+ memcpy(Buf, Insn, sizeof(Insn));
+
+ uint64_t Off = getPltEntryOffset(Index);
+
+ write32le(Buf + 3, GotPltEntryAddr - PltEntryAddr - 7);
+ write32le(Buf + 8, -Off - 12 + 32);
+ write32le(Buf + 13, -Off - 17 + 18);
+ write32le(Buf + 18, Index);
+ write32le(Buf + 23, -Off - 27);
+}
+
+template <class ELFT> RetpolineZNow<ELFT>::RetpolineZNow() {
+ TargetInfo::PltHeaderSize = 32;
+ TargetInfo::PltEntrySize = 16;
+}
+
+template <class ELFT>
+void RetpolineZNow<ELFT>::writePltHeader(uint8_t *Buf) const {
+ const uint8_t Insn[] = {
+ 0xe8, 0x0b, 0x00, 0x00, 0x00, // 0: call next
+ 0xf3, 0x90, // 5: loop: pause
+ 0x0f, 0xae, 0xe8, // 7: lfence
+ 0xeb, 0xf9, // a: jmp loop
+ 0xcc, 0xcc, 0xcc, 0xcc, // c: int3; .align 16
+ 0x4c, 0x89, 0x1c, 0x24, // 10: next: mov %r11, (%rsp)
+ 0xc3, // 14: ret
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 15: int3; padding
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 1a: int3; padding
+ 0xcc, // 1f: int3; padding
+ };
+ memcpy(Buf, Insn, sizeof(Insn));
+}
+
+template <class ELFT>
+void RetpolineZNow<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const {
+ const uint8_t Insn[] = {
+ 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // mov foo@GOTPLT(%rip), %r11
+ 0xe9, 0, 0, 0, 0, // jmp plt+0
+ 0xcc, 0xcc, 0xcc, 0xcc, // int3; padding
+ };
+ memcpy(Buf, Insn, sizeof(Insn));
+
+ write32le(Buf + 3, GotPltEntryAddr - PltEntryAddr - 7);
+ write32le(Buf + 8, -getPltEntryOffset(Index) - 12);
+}
+
+template <class ELFT> static TargetInfo *getTargetInfo() {
+ if (Config->ZRetpolineplt) {
+ if (Config->ZNow) {
+ static RetpolineZNow<ELFT> T;
+ return &T;
+ }
+ static Retpoline<ELFT> T;
+ return &T;
+ }
+
+ static X86_64<ELFT> T;
+ return &T;
+}
+
+TargetInfo *elf::getX32TargetInfo() { return getTargetInfo<ELF32LE>(); }
+TargetInfo *elf::getX86_64TargetInfo() { return getTargetInfo<ELF64LE>(); }
diff --git a/contrib/llvm/tools/lld/ELF/Bits.h b/contrib/llvm/tools/lld/ELF/Bits.h
new file mode 100644
index 000000000000..13d40322265e
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Bits.h
@@ -0,0 +1,35 @@
+//===- Bits.h ---------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_BITS_H
+#define LLD_ELF_BITS_H
+
+#include "Config.h"
+#include "llvm/Support/Endian.h"
+
+namespace lld {
+namespace elf {
+
+inline uint64_t readUint(uint8_t *Buf) {
+ if (Config->Is64)
+ return llvm::support::endian::read64(Buf, Config->Endianness);
+ return llvm::support::endian::read32(Buf, Config->Endianness);
+}
+
+inline void writeUint(uint8_t *Buf, uint64_t Val) {
+ if (Config->Is64)
+ llvm::support::endian::write64(Buf, Val, Config->Endianness);
+ else
+ llvm::support::endian::write32(Buf, Val, Config->Endianness);
+}
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/ELF/CMakeLists.txt b/contrib/llvm/tools/lld/ELF/CMakeLists.txt
new file mode 100644
index 000000000000..a1c23b0d49ac
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/CMakeLists.txt
@@ -0,0 +1,68 @@
+set(LLVM_TARGET_DEFINITIONS Options.td)
+tablegen(LLVM Options.inc -gen-opt-parser-defs)
+add_public_tablegen_target(ELFOptionsTableGen)
+
+if(NOT LLD_BUILT_STANDALONE)
+ set(tablegen_deps intrinsics_gen)
+endif()
+
+add_lld_library(lldELF
+ AArch64ErrataFix.cpp
+ Arch/AArch64.cpp
+ Arch/AMDGPU.cpp
+ Arch/ARM.cpp
+ Arch/AVR.cpp
+ Arch/Hexagon.cpp
+ Arch/Mips.cpp
+ Arch/MipsArchTree.cpp
+ Arch/MSP430.cpp
+ Arch/PPC.cpp
+ Arch/PPC64.cpp
+ Arch/RISCV.cpp
+ Arch/SPARCV9.cpp
+ Arch/X86.cpp
+ Arch/X86_64.cpp
+ CallGraphSort.cpp
+ DWARF.cpp
+ Driver.cpp
+ DriverUtils.cpp
+ EhFrame.cpp
+ Filesystem.cpp
+ ICF.cpp
+ InputFiles.cpp
+ InputSection.cpp
+ LTO.cpp
+ LinkerScript.cpp
+ MapFile.cpp
+ MarkLive.cpp
+ OutputSections.cpp
+ Relocations.cpp
+ ScriptLexer.cpp
+ ScriptParser.cpp
+ SymbolTable.cpp
+ Symbols.cpp
+ SyntheticSections.cpp
+ Target.cpp
+ Thunks.cpp
+ Writer.cpp
+
+ LINK_COMPONENTS
+ ${LLVM_TARGETS_TO_BUILD}
+ BinaryFormat
+ BitWriter
+ Core
+ DebugInfoDWARF
+ LTO
+ MC
+ Object
+ Option
+ Support
+
+ LINK_LIBS
+ lldCommon
+ ${LLVM_PTHREAD_LIB}
+
+ DEPENDS
+ ELFOptionsTableGen
+ ${tablegen_deps}
+ )
diff --git a/contrib/llvm/tools/lld/ELF/CallGraphSort.cpp b/contrib/llvm/tools/lld/ELF/CallGraphSort.cpp
new file mode 100644
index 000000000000..2a7d78664b8e
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/CallGraphSort.cpp
@@ -0,0 +1,240 @@
+//===- CallGraphSort.cpp --------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// Implementation of Call-Chain Clustering from: Optimizing Function Placement
+/// for Large-Scale Data-Center Applications
+/// https://research.fb.com/wp-content/uploads/2017/01/cgo2017-hfsort-final1.pdf
+///
+/// The goal of this algorithm is to improve runtime performance of the final
+/// executable by arranging code sections such that page table and i-cache
+/// misses are minimized.
+///
+/// Definitions:
+/// * Cluster
+/// * An ordered list of input sections which are layed out as a unit. At the
+/// beginning of the algorithm each input section has its own cluster and
+/// the weight of the cluster is the sum of the weight of all incomming
+/// edges.
+/// * Call-Chain Clustering (C³) Heuristic
+/// * Defines when and how clusters are combined. Pick the highest weighted
+/// input section then add it to its most likely predecessor if it wouldn't
+/// penalize it too much.
+/// * Density
+/// * The weight of the cluster divided by the size of the cluster. This is a
+/// proxy for the ammount of execution time spent per byte of the cluster.
+///
+/// It does so given a call graph profile by the following:
+/// * Build a weighted call graph from the call graph profile
+/// * Sort input sections by weight
+/// * For each input section starting with the highest weight
+/// * Find its most likely predecessor cluster
+/// * Check if the combined cluster would be too large, or would have too low
+/// a density.
+/// * If not, then combine the clusters.
+/// * Sort non-empty clusters by density
+///
+//===----------------------------------------------------------------------===//
+
+#include "CallGraphSort.h"
+#include "OutputSections.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+
+using namespace llvm;
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+struct Edge {
+ int From;
+ uint64_t Weight;
+};
+
+struct Cluster {
+ Cluster(int Sec, size_t S) : Sections{Sec}, Size(S) {}
+
+ double getDensity() const {
+ if (Size == 0)
+ return 0;
+ return double(Weight) / double(Size);
+ }
+
+ std::vector<int> Sections;
+ size_t Size = 0;
+ uint64_t Weight = 0;
+ uint64_t InitialWeight = 0;
+ Edge BestPred = {-1, 0};
+};
+
+class CallGraphSort {
+public:
+ CallGraphSort();
+
+ DenseMap<const InputSectionBase *, int> run();
+
+private:
+ std::vector<Cluster> Clusters;
+ std::vector<const InputSectionBase *> Sections;
+
+ void groupClusters();
+};
+
+// Maximum ammount the combined cluster density can be worse than the original
+// cluster to consider merging.
+constexpr int MAX_DENSITY_DEGRADATION = 8;
+
+// Maximum cluster size in bytes.
+constexpr uint64_t MAX_CLUSTER_SIZE = 1024 * 1024;
+} // end anonymous namespace
+
+typedef std::pair<const InputSectionBase *, const InputSectionBase *>
+ SectionPair;
+
+// Take the edge list in Config->CallGraphProfile, resolve symbol names to
+// Symbols, and generate a graph between InputSections with the provided
+// weights.
+CallGraphSort::CallGraphSort() {
+ MapVector<SectionPair, uint64_t> &Profile = Config->CallGraphProfile;
+ DenseMap<const InputSectionBase *, int> SecToCluster;
+
+ auto GetOrCreateNode = [&](const InputSectionBase *IS) -> int {
+ auto Res = SecToCluster.insert(std::make_pair(IS, Clusters.size()));
+ if (Res.second) {
+ Sections.push_back(IS);
+ Clusters.emplace_back(Clusters.size(), IS->getSize());
+ }
+ return Res.first->second;
+ };
+
+ // Create the graph.
+ for (std::pair<SectionPair, uint64_t> &C : Profile) {
+ const auto *FromSB = cast<InputSectionBase>(C.first.first->Repl);
+ const auto *ToSB = cast<InputSectionBase>(C.first.second->Repl);
+ uint64_t Weight = C.second;
+
+ // Ignore edges between input sections belonging to different output
+ // sections. This is done because otherwise we would end up with clusters
+ // containing input sections that can't actually be placed adjacently in the
+ // output. This messes with the cluster size and density calculations. We
+ // would also end up moving input sections in other output sections without
+ // moving them closer to what calls them.
+ if (FromSB->getOutputSection() != ToSB->getOutputSection())
+ continue;
+
+ int From = GetOrCreateNode(FromSB);
+ int To = GetOrCreateNode(ToSB);
+
+ Clusters[To].Weight += Weight;
+
+ if (From == To)
+ continue;
+
+ // Remember the best edge.
+ Cluster &ToC = Clusters[To];
+ if (ToC.BestPred.From == -1 || ToC.BestPred.Weight < Weight) {
+ ToC.BestPred.From = From;
+ ToC.BestPred.Weight = Weight;
+ }
+ }
+ for (Cluster &C : Clusters)
+ C.InitialWeight = C.Weight;
+}
+
+// It's bad to merge clusters which would degrade the density too much.
+static bool isNewDensityBad(Cluster &A, Cluster &B) {
+ double NewDensity = double(A.Weight + B.Weight) / double(A.Size + B.Size);
+ return NewDensity < A.getDensity() / MAX_DENSITY_DEGRADATION;
+}
+
+static void mergeClusters(Cluster &Into, Cluster &From) {
+ Into.Sections.insert(Into.Sections.end(), From.Sections.begin(),
+ From.Sections.end());
+ Into.Size += From.Size;
+ Into.Weight += From.Weight;
+ From.Sections.clear();
+ From.Size = 0;
+ From.Weight = 0;
+}
+
+// Group InputSections into clusters using the Call-Chain Clustering heuristic
+// then sort the clusters by density.
+void CallGraphSort::groupClusters() {
+ std::vector<int> SortedSecs(Clusters.size());
+ std::vector<Cluster *> SecToCluster(Clusters.size());
+
+ for (size_t I = 0; I < Clusters.size(); ++I) {
+ SortedSecs[I] = I;
+ SecToCluster[I] = &Clusters[I];
+ }
+
+ std::stable_sort(SortedSecs.begin(), SortedSecs.end(), [&](int A, int B) {
+ return Clusters[B].getDensity() < Clusters[A].getDensity();
+ });
+
+ for (int SI : SortedSecs) {
+ // Clusters[SI] is the same as SecToClusters[SI] here because it has not
+ // been merged into another cluster yet.
+ Cluster &C = Clusters[SI];
+
+ // Don't consider merging if the edge is unlikely.
+ if (C.BestPred.From == -1 || C.BestPred.Weight * 10 <= C.InitialWeight)
+ continue;
+
+ Cluster *PredC = SecToCluster[C.BestPred.From];
+ if (PredC == &C)
+ continue;
+
+ if (C.Size + PredC->Size > MAX_CLUSTER_SIZE)
+ continue;
+
+ if (isNewDensityBad(*PredC, C))
+ continue;
+
+ // NOTE: Consider using a disjoint-set to track section -> cluster mapping
+ // if this is ever slow.
+ for (int SI : C.Sections)
+ SecToCluster[SI] = PredC;
+
+ mergeClusters(*PredC, C);
+ }
+
+ // Remove empty or dead nodes. Invalidates all cluster indices.
+ llvm::erase_if(Clusters, [](const Cluster &C) {
+ return C.Size == 0 || C.Sections.empty();
+ });
+
+ // Sort by density.
+ std::stable_sort(Clusters.begin(), Clusters.end(),
+ [](const Cluster &A, const Cluster &B) {
+ return A.getDensity() > B.getDensity();
+ });
+}
+
+DenseMap<const InputSectionBase *, int> CallGraphSort::run() {
+ groupClusters();
+
+ // Generate order.
+ DenseMap<const InputSectionBase *, int> OrderMap;
+ ssize_t CurOrder = 1;
+
+ for (const Cluster &C : Clusters)
+ for (int SecIndex : C.Sections)
+ OrderMap[Sections[SecIndex]] = CurOrder++;
+
+ return OrderMap;
+}
+
+// Sort sections by the profile data provided by -callgraph-profile-file
+//
+// This first builds a call graph based on the profile data then merges sections
+// according to the C³ huristic. All clusters are then sorted by a density
+// metric to further improve locality.
+DenseMap<const InputSectionBase *, int> elf::computeCallGraphProfileOrder() {
+ return CallGraphSort().run();
+}
diff --git a/contrib/llvm/tools/lld/ELF/CallGraphSort.h b/contrib/llvm/tools/lld/ELF/CallGraphSort.h
new file mode 100644
index 000000000000..3f96dc88f435
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/CallGraphSort.h
@@ -0,0 +1,23 @@
+//===- CallGraphSort.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_CALL_GRAPH_SORT_H
+#define LLD_ELF_CALL_GRAPH_SORT_H
+
+#include "llvm/ADT/DenseMap.h"
+
+namespace lld {
+namespace elf {
+class InputSectionBase;
+
+llvm::DenseMap<const InputSectionBase *, int> computeCallGraphProfileOrder();
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/ELF/Config.h b/contrib/llvm/tools/lld/ELF/Config.h
new file mode 100644
index 000000000000..588d5a6c3b4e
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Config.h
@@ -0,0 +1,295 @@
+//===- Config.h -------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_CONFIG_H
+#define LLD_ELF_CONFIG_H
+
+#include "lld/Common/ErrorHandler.h"
+#include "llvm/ADT/MapVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Support/CachePruning.h"
+#include "llvm/Support/CodeGen.h"
+#include "llvm/Support/Endian.h"
+#include <vector>
+
+namespace lld {
+namespace elf {
+
+class InputFile;
+class InputSectionBase;
+
+enum ELFKind {
+ ELFNoneKind,
+ ELF32LEKind,
+ ELF32BEKind,
+ ELF64LEKind,
+ ELF64BEKind
+};
+
+// For --build-id.
+enum class BuildIdKind { None, Fast, Md5, Sha1, Hexstring, Uuid };
+
+// For --discard-{all,locals,none}.
+enum class DiscardPolicy { Default, All, Locals, None };
+
+// For --icf={none,safe,all}.
+enum class ICFLevel { None, Safe, All };
+
+// For --strip-{all,debug}.
+enum class StripPolicy { None, All, Debug };
+
+// For --unresolved-symbols.
+enum class UnresolvedPolicy { ReportError, Warn, Ignore };
+
+// For --orphan-handling.
+enum class OrphanHandlingPolicy { Place, Warn, Error };
+
+// For --sort-section and linkerscript sorting rules.
+enum class SortSectionPolicy { Default, None, Alignment, Name, Priority };
+
+// For --target2
+enum class Target2Policy { Abs, Rel, GotRel };
+
+// For tracking ARM Float Argument PCS
+enum class ARMVFPArgKind { Default, Base, VFP, ToolChain };
+
+struct SymbolVersion {
+ llvm::StringRef Name;
+ bool IsExternCpp;
+ bool HasWildcard;
+};
+
+// This struct contains symbols version definition that
+// can be found in version script if it is used for link.
+struct VersionDefinition {
+ llvm::StringRef Name;
+ uint16_t Id = 0;
+ std::vector<SymbolVersion> Globals;
+ size_t NameOff = 0; // Offset in the string table
+};
+
+// This struct contains the global configuration for the linker.
+// Most fields are direct mapping from the command line options
+// and such fields have the same name as the corresponding options.
+// Most fields are initialized by the driver.
+struct Configuration {
+ uint8_t OSABI = 0;
+ llvm::CachePruningPolicy ThinLTOCachePolicy;
+ llvm::StringMap<uint64_t> SectionStartMap;
+ llvm::StringRef Chroot;
+ llvm::StringRef DynamicLinker;
+ llvm::StringRef DwoDir;
+ llvm::StringRef Entry;
+ llvm::StringRef Emulation;
+ llvm::StringRef Fini;
+ llvm::StringRef Init;
+ llvm::StringRef LTOAAPipeline;
+ llvm::StringRef LTONewPmPasses;
+ llvm::StringRef LTOObjPath;
+ llvm::StringRef LTOSampleProfile;
+ llvm::StringRef MapFile;
+ llvm::StringRef OutputFile;
+ llvm::StringRef OptRemarksFilename;
+ llvm::StringRef ProgName;
+ llvm::StringRef SoName;
+ llvm::StringRef Sysroot;
+ llvm::StringRef ThinLTOCacheDir;
+ llvm::StringRef ThinLTOIndexOnlyArg;
+ std::pair<llvm::StringRef, llvm::StringRef> ThinLTOObjectSuffixReplace;
+ std::pair<llvm::StringRef, llvm::StringRef> ThinLTOPrefixReplace;
+ std::string Rpath;
+ std::vector<VersionDefinition> VersionDefinitions;
+ std::vector<llvm::StringRef> AuxiliaryList;
+ std::vector<llvm::StringRef> FilterList;
+ std::vector<llvm::StringRef> SearchPaths;
+ std::vector<llvm::StringRef> SymbolOrderingFile;
+ std::vector<llvm::StringRef> Undefined;
+ std::vector<SymbolVersion> DynamicList;
+ std::vector<SymbolVersion> VersionScriptGlobals;
+ std::vector<SymbolVersion> VersionScriptLocals;
+ std::vector<uint8_t> BuildIdVector;
+ llvm::MapVector<std::pair<const InputSectionBase *, const InputSectionBase *>,
+ uint64_t>
+ CallGraphProfile;
+ bool AllowMultipleDefinition;
+ bool AndroidPackDynRelocs;
+ bool ARMHasBlx = false;
+ bool ARMHasMovtMovw = false;
+ bool ARMJ1J2BranchEncoding = false;
+ bool AsNeeded = false;
+ bool Bsymbolic;
+ bool BsymbolicFunctions;
+ bool CallGraphProfileSort;
+ bool CheckSections;
+ bool CompressDebugSections;
+ bool Cref;
+ bool DefineCommon;
+ bool Demangle = true;
+ bool DisableVerify;
+ bool EhFrameHdr;
+ bool EmitLLVM;
+ bool EmitRelocs;
+ bool EnableNewDtags;
+ bool ExecuteOnly;
+ bool ExportDynamic;
+ bool FixCortexA53Errata843419;
+ bool FormatBinary = false;
+ bool GcSections;
+ bool GdbIndex;
+ bool GnuHash = false;
+ bool GnuUnique;
+ bool HasDynamicList = false;
+ bool HasDynSymTab;
+ bool IgnoreDataAddressEquality;
+ bool IgnoreFunctionAddressEquality;
+ bool LTODebugPassManager;
+ bool LTONewPassManager;
+ bool MergeArmExidx;
+ bool MipsN32Abi = false;
+ bool NoinhibitExec;
+ bool Nostdlib;
+ bool OFormatBinary;
+ bool Omagic;
+ bool OptRemarksWithHotness;
+ bool PicThunk;
+ bool Pie;
+ bool PrintGcSections;
+ bool PrintIcfSections;
+ bool Relocatable;
+ bool RelrPackDynRelocs;
+ bool SaveTemps;
+ bool SingleRoRx;
+ bool Shared;
+ bool Static = false;
+ bool SysvHash = false;
+ bool Target1Rel;
+ bool Trace;
+ bool ThinLTOEmitImportsFiles;
+ bool ThinLTOIndexOnly;
+ bool TocOptimize;
+ bool UndefinedVersion;
+ bool UseAndroidRelrTags = false;
+ bool WarnBackrefs;
+ bool WarnCommon;
+ bool WarnIfuncTextrel;
+ bool WarnMissingEntry;
+ bool WarnSymbolOrdering;
+ bool WriteAddends;
+ bool ZCombreloc;
+ bool ZCopyreloc;
+ bool ZExecstack;
+ bool ZGlobal;
+ bool ZHazardplt;
+ bool ZIfuncnoplt;
+ bool ZInitfirst;
+ bool ZInterpose;
+ bool ZKeepTextSectionPrefix;
+ bool ZNodefaultlib;
+ bool ZNodelete;
+ bool ZNodlopen;
+ bool ZNow;
+ bool ZOrigin;
+ bool ZRelro;
+ bool ZRodynamic;
+ bool ZText;
+ bool ZRetpolineplt;
+ bool ZWxneeded;
+ DiscardPolicy Discard;
+ ICFLevel ICF;
+ OrphanHandlingPolicy OrphanHandling;
+ SortSectionPolicy SortSection;
+ StripPolicy Strip;
+ UnresolvedPolicy UnresolvedSymbols;
+ Target2Policy Target2;
+ ARMVFPArgKind ARMVFPArgs = ARMVFPArgKind::Default;
+ BuildIdKind BuildId = BuildIdKind::None;
+ ELFKind EKind = ELFNoneKind;
+ uint16_t DefaultSymbolVersion = llvm::ELF::VER_NDX_GLOBAL;
+ uint16_t EMachine = llvm::ELF::EM_NONE;
+ llvm::Optional<uint64_t> ImageBase;
+ uint64_t MaxPageSize;
+ uint64_t MipsGotSize;
+ uint64_t ZStackSize;
+ unsigned LTOPartitions;
+ unsigned LTOO;
+ unsigned Optimize;
+ unsigned ThinLTOJobs;
+ int32_t SplitStackAdjustSize;
+
+ // The following config options do not directly correspond to any
+ // particualr command line options.
+
+ // True if we need to pass through relocations in input files to the
+ // output file. Usually false because we consume relocations.
+ bool CopyRelocs;
+
+ // True if the target is ELF64. False if ELF32.
+ bool Is64;
+
+ // True if the target is little-endian. False if big-endian.
+ bool IsLE;
+
+ // endianness::little if IsLE is true. endianness::big otherwise.
+ llvm::support::endianness Endianness;
+
+ // True if the target is the little-endian MIPS64.
+ //
+ // The reason why we have this variable only for the MIPS is because
+ // we use this often. Some ELF headers for MIPS64EL are in a
+ // mixed-endian (which is horrible and I'd say that's a serious spec
+ // bug), and we need to know whether we are reading MIPS ELF files or
+ // not in various places.
+ //
+ // (Note that MIPS64EL is not a typo for MIPS64LE. This is the official
+ // name whatever that means. A fun hypothesis is that "EL" is short for
+ // little-endian written in the little-endian order, but I don't know
+ // if that's true.)
+ bool IsMips64EL;
+
+ // Holds set of ELF header flags for the target.
+ uint32_t EFlags = 0;
+
+ // The ELF spec defines two types of relocation table entries, RELA and
+ // REL. RELA is a triplet of (offset, info, addend) while REL is a
+ // tuple of (offset, info). Addends for REL are implicit and read from
+ // the location where the relocations are applied. So, REL is more
+ // compact than RELA but requires a bit of more work to process.
+ //
+ // (From the linker writer's view, this distinction is not necessary.
+ // If the ELF had chosen whichever and sticked with it, it would have
+ // been easier to write code to process relocations, but it's too late
+ // to change the spec.)
+ //
+ // Each ABI defines its relocation type. IsRela is true if target
+ // uses RELA. As far as we know, all 64-bit ABIs are using RELA. A
+ // few 32-bit ABIs are using RELA too.
+ bool IsRela;
+
+ // True if we are creating position-independent code.
+ bool Pic;
+
+ // 4 for ELF32, 8 for ELF64.
+ int Wordsize;
+};
+
+// The only instance of Configuration struct.
+extern Configuration *Config;
+
+static inline void errorOrWarn(const Twine &Msg) {
+ if (!Config->NoinhibitExec)
+ error(Msg);
+ else
+ warn(Msg);
+}
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/ELF/DWARF.cpp b/contrib/llvm/tools/lld/ELF/DWARF.cpp
new file mode 100644
index 000000000000..17e1a4d600eb
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/DWARF.cpp
@@ -0,0 +1,109 @@
+//===- DWARF.cpp ----------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// The -gdb-index option instructs the linker to emit a .gdb_index section.
+// The section contains information to make gdb startup faster.
+// The format of the section is described at
+// https://sourceware.org/gdb/onlinedocs/gdb/Index-Section-Format.html.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARF.h"
+#include "Symbols.h"
+#include "Target.h"
+#include "lld/Common/Memory.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h"
+#include "llvm/Object/ELFObjectFile.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace lld;
+using namespace lld::elf;
+
+template <class ELFT> LLDDwarfObj<ELFT>::LLDDwarfObj(ObjFile<ELFT> *Obj) {
+ for (InputSectionBase *Sec : Obj->getSections()) {
+ if (!Sec)
+ continue;
+
+ if (LLDDWARFSection *M =
+ StringSwitch<LLDDWARFSection *>(Sec->Name)
+ .Case(".debug_addr", &AddrSection)
+ .Case(".debug_gnu_pubnames", &GnuPubNamesSection)
+ .Case(".debug_gnu_pubtypes", &GnuPubTypesSection)
+ .Case(".debug_info", &InfoSection)
+ .Case(".debug_ranges", &RangeSection)
+ .Case(".debug_rnglists", &RngListsSection)
+ .Case(".debug_line", &LineSection)
+ .Default(nullptr)) {
+ M->Data = toStringRef(Sec->data());
+ M->Sec = Sec;
+ continue;
+ }
+
+ if (Sec->Name == ".debug_abbrev")
+ AbbrevSection = toStringRef(Sec->data());
+ else if (Sec->Name == ".debug_str")
+ StrSection = toStringRef(Sec->data());
+ else if (Sec->Name == ".debug_line_str")
+ LineStringSection = toStringRef(Sec->data());
+ }
+}
+
+// Find if there is a relocation at Pos in Sec. The code is a bit
+// more complicated than usual because we need to pass a section index
+// to llvm since it has no idea about InputSection.
+template <class ELFT>
+template <class RelTy>
+Optional<RelocAddrEntry>
+LLDDwarfObj<ELFT>::findAux(const InputSectionBase &Sec, uint64_t Pos,
+ ArrayRef<RelTy> Rels) const {
+ auto It = std::lower_bound(
+ Rels.begin(), Rels.end(), Pos,
+ [](const RelTy &A, uint64_t B) { return A.r_offset < B; });
+ if (It == Rels.end() || It->r_offset != Pos)
+ return None;
+ const RelTy &Rel = *It;
+
+ const ObjFile<ELFT> *File = Sec.getFile<ELFT>();
+ uint32_t SymIndex = Rel.getSymbol(Config->IsMips64EL);
+ const typename ELFT::Sym &Sym = File->getELFSyms()[SymIndex];
+ uint32_t SecIndex = File->getSectionIndex(Sym);
+
+ // Broken debug info can point to a non-Defined symbol.
+ auto *DR = dyn_cast<Defined>(&File->getRelocTargetSym(Rel));
+ if (!DR) {
+ RelType Type = Rel.getType(Config->IsMips64EL);
+ if (Type != Target->NoneRel)
+ error(toString(File) + ": relocation " + lld::toString(Type) + " at 0x" +
+ llvm::utohexstr(Rel.r_offset) + " has unsupported target");
+ return None;
+ }
+ uint64_t Val = DR->Value + getAddend<ELFT>(Rel);
+
+ // FIXME: We should be consistent about always adding the file
+ // offset or not.
+ if (DR->Section->Flags & ELF::SHF_ALLOC)
+ Val += cast<InputSection>(DR->Section)->getOffsetInFile();
+
+ return RelocAddrEntry{SecIndex, Val};
+}
+
+template <class ELFT>
+Optional<RelocAddrEntry> LLDDwarfObj<ELFT>::find(const llvm::DWARFSection &S,
+ uint64_t Pos) const {
+ auto &Sec = static_cast<const LLDDWARFSection &>(S);
+ if (Sec.Sec->AreRelocsRela)
+ return findAux(*Sec.Sec, Pos, Sec.Sec->template relas<ELFT>());
+ return findAux(*Sec.Sec, Pos, Sec.Sec->template rels<ELFT>());
+}
+
+template class elf::LLDDwarfObj<ELF32LE>;
+template class elf::LLDDwarfObj<ELF32BE>;
+template class elf::LLDDwarfObj<ELF64LE>;
+template class elf::LLDDwarfObj<ELF64BE>;
diff --git a/contrib/llvm/tools/lld/ELF/DWARF.h b/contrib/llvm/tools/lld/ELF/DWARF.h
new file mode 100644
index 000000000000..8ecf02c77fb4
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/DWARF.h
@@ -0,0 +1,93 @@
+//===- DWARF.h -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===-------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_DWARF_H
+#define LLD_ELF_DWARF_H
+
+#include "InputFiles.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/Object/ELF.h"
+
+namespace lld {
+namespace elf {
+
+class InputSection;
+
+struct LLDDWARFSection final : public llvm::DWARFSection {
+ InputSectionBase *Sec = nullptr;
+};
+
+template <class ELFT> class LLDDwarfObj final : public llvm::DWARFObject {
+public:
+ explicit LLDDwarfObj(ObjFile<ELFT> *Obj);
+
+ void forEachInfoSections(
+ llvm::function_ref<void(const llvm::DWARFSection &)> F) const override {
+ F(InfoSection);
+ }
+
+ const llvm::DWARFSection &getRangeSection() const override {
+ return RangeSection;
+ }
+
+ const llvm::DWARFSection &getRnglistsSection() const override {
+ return RngListsSection;
+ }
+
+ const llvm::DWARFSection &getLineSection() const override {
+ return LineSection;
+ }
+
+ const llvm::DWARFSection &getAddrSection() const override {
+ return AddrSection;
+ }
+
+ const llvm::DWARFSection &getGnuPubNamesSection() const override {
+ return GnuPubNamesSection;
+ }
+
+ const llvm::DWARFSection &getGnuPubTypesSection() const override {
+ return GnuPubTypesSection;
+ }
+
+ StringRef getFileName() const override { return ""; }
+ StringRef getAbbrevSection() const override { return AbbrevSection; }
+ StringRef getStringSection() const override { return StrSection; }
+ StringRef getLineStringSection() const override { return LineStringSection; }
+
+ bool isLittleEndian() const override {
+ return ELFT::TargetEndianness == llvm::support::little;
+ }
+
+ llvm::Optional<llvm::RelocAddrEntry> find(const llvm::DWARFSection &Sec,
+ uint64_t Pos) const override;
+
+private:
+ template <class RelTy>
+ llvm::Optional<llvm::RelocAddrEntry> findAux(const InputSectionBase &Sec,
+ uint64_t Pos,
+ ArrayRef<RelTy> Rels) const;
+
+ LLDDWARFSection GnuPubNamesSection;
+ LLDDWARFSection GnuPubTypesSection;
+ LLDDWARFSection InfoSection;
+ LLDDWARFSection RangeSection;
+ LLDDWARFSection RngListsSection;
+ LLDDWARFSection LineSection;
+ LLDDWARFSection AddrSection;
+ StringRef AbbrevSection;
+ StringRef StrSection;
+ StringRef LineStringSection;
+};
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/ELF/Driver.cpp b/contrib/llvm/tools/lld/ELF/Driver.cpp
new file mode 100644
index 000000000000..407f1734f143
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Driver.cpp
@@ -0,0 +1,1651 @@
+//===- Driver.cpp ---------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// The driver drives the entire linking process. It is responsible for
+// parsing command line options and doing whatever it is instructed to do.
+//
+// One notable thing in the LLD's driver when compared to other linkers is
+// that the LLD's driver is agnostic on the host operating system.
+// Other linkers usually have implicit default values (such as a dynamic
+// linker path or library paths) for each host OS.
+//
+// I don't think implicit default values are useful because they are
+// usually explicitly specified by the compiler driver. They can even
+// be harmful when you are doing cross-linking. Therefore, in LLD, we
+// simply trust the compiler driver to pass all required options and
+// don't try to make effort on our side.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Driver.h"
+#include "Config.h"
+#include "Filesystem.h"
+#include "ICF.h"
+#include "InputFiles.h"
+#include "InputSection.h"
+#include "LinkerScript.h"
+#include "MarkLive.h"
+#include "OutputSections.h"
+#include "ScriptParser.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "Writer.h"
+#include "lld/Common/Args.h"
+#include "lld/Common/Driver.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Memory.h"
+#include "lld/Common/Strings.h"
+#include "lld/Common/TargetOptionsCommandFlags.h"
+#include "lld/Common/Threads.h"
+#include "lld/Common/Version.h"
+#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Compression.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/TarWriter.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstdlib>
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::object;
+using namespace llvm::sys;
+using namespace llvm::support;
+
+using namespace lld;
+using namespace lld::elf;
+
+Configuration *elf::Config;
+LinkerDriver *elf::Driver;
+
+static void setConfigs(opt::InputArgList &Args);
+
+bool elf::link(ArrayRef<const char *> Args, bool CanExitEarly,
+ raw_ostream &Error) {
+ errorHandler().LogName = args::getFilenameWithoutExe(Args[0]);
+ errorHandler().ErrorLimitExceededMsg =
+ "too many errors emitted, stopping now (use "
+ "-error-limit=0 to see all errors)";
+ errorHandler().ErrorOS = &Error;
+ errorHandler().ExitEarly = CanExitEarly;
+ errorHandler().ColorDiagnostics = Error.has_colors();
+
+ InputSections.clear();
+ OutputSections.clear();
+ BinaryFiles.clear();
+ BitcodeFiles.clear();
+ ObjectFiles.clear();
+ SharedFiles.clear();
+
+ Config = make<Configuration>();
+ Driver = make<LinkerDriver>();
+ Script = make<LinkerScript>();
+ Symtab = make<SymbolTable>();
+
+ Tar = nullptr;
+ memset(&In, 0, sizeof(In));
+
+ Config->ProgName = Args[0];
+
+ Driver->main(Args);
+
+ // Exit immediately if we don't need to return to the caller.
+ // This saves time because the overhead of calling destructors
+ // for all globally-allocated objects is not negligible.
+ if (CanExitEarly)
+ exitLld(errorCount() ? 1 : 0);
+
+ freeArena();
+ return !errorCount();
+}
+
+// Parses a linker -m option.
+static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef Emul) {
+ uint8_t OSABI = 0;
+ StringRef S = Emul;
+ if (S.endswith("_fbsd")) {
+ S = S.drop_back(5);
+ OSABI = ELFOSABI_FREEBSD;
+ }
+
+ std::pair<ELFKind, uint16_t> Ret =
+ StringSwitch<std::pair<ELFKind, uint16_t>>(S)
+ .Cases("aarch64elf", "aarch64linux", "aarch64_elf64_le_vec",
+ {ELF64LEKind, EM_AARCH64})
+ .Cases("armelf", "armelf_linux_eabi", {ELF32LEKind, EM_ARM})
+ .Case("elf32_x86_64", {ELF32LEKind, EM_X86_64})
+ .Cases("elf32btsmip", "elf32btsmipn32", {ELF32BEKind, EM_MIPS})
+ .Cases("elf32ltsmip", "elf32ltsmipn32", {ELF32LEKind, EM_MIPS})
+ .Case("elf32lriscv", {ELF32LEKind, EM_RISCV})
+ .Cases("elf32ppc", "elf32ppclinux", {ELF32BEKind, EM_PPC})
+ .Case("elf64btsmip", {ELF64BEKind, EM_MIPS})
+ .Case("elf64ltsmip", {ELF64LEKind, EM_MIPS})
+ .Case("elf64lriscv", {ELF64LEKind, EM_RISCV})
+ .Case("elf64ppc", {ELF64BEKind, EM_PPC64})
+ .Case("elf64lppc", {ELF64LEKind, EM_PPC64})
+ .Cases("elf_amd64", "elf_x86_64", {ELF64LEKind, EM_X86_64})
+ .Case("elf_i386", {ELF32LEKind, EM_386})
+ .Case("elf_iamcu", {ELF32LEKind, EM_IAMCU})
+ .Default({ELFNoneKind, EM_NONE});
+
+ if (Ret.first == ELFNoneKind)
+ error("unknown emulation: " + Emul);
+ return std::make_tuple(Ret.first, Ret.second, OSABI);
+}
+
+// Returns slices of MB by parsing MB as an archive file.
+// Each slice consists of a member file in the archive.
+std::vector<std::pair<MemoryBufferRef, uint64_t>> static getArchiveMembers(
+ MemoryBufferRef MB) {
+ std::unique_ptr<Archive> File =
+ CHECK(Archive::create(MB),
+ MB.getBufferIdentifier() + ": failed to parse archive");
+
+ std::vector<std::pair<MemoryBufferRef, uint64_t>> V;
+ Error Err = Error::success();
+ bool AddToTar = File->isThin() && Tar;
+ for (const ErrorOr<Archive::Child> &COrErr : File->children(Err)) {
+ Archive::Child C =
+ CHECK(COrErr, MB.getBufferIdentifier() +
+ ": could not get the child of the archive");
+ MemoryBufferRef MBRef =
+ CHECK(C.getMemoryBufferRef(),
+ MB.getBufferIdentifier() +
+ ": could not get the buffer for a child of the archive");
+ if (AddToTar)
+ Tar->append(relativeToRoot(check(C.getFullName())), MBRef.getBuffer());
+ V.push_back(std::make_pair(MBRef, C.getChildOffset()));
+ }
+ if (Err)
+ fatal(MB.getBufferIdentifier() + ": Archive::children failed: " +
+ toString(std::move(Err)));
+
+ // Take ownership of memory buffers created for members of thin archives.
+ for (std::unique_ptr<MemoryBuffer> &MB : File->takeThinBuffers())
+ make<std::unique_ptr<MemoryBuffer>>(std::move(MB));
+
+ return V;
+}
+
+// Opens a file and create a file object. Path has to be resolved already.
+void LinkerDriver::addFile(StringRef Path, bool WithLOption) {
+ using namespace sys::fs;
+
+ Optional<MemoryBufferRef> Buffer = readFile(Path);
+ if (!Buffer.hasValue())
+ return;
+ MemoryBufferRef MBRef = *Buffer;
+
+ if (Config->FormatBinary) {
+ Files.push_back(make<BinaryFile>(MBRef));
+ return;
+ }
+
+ switch (identify_magic(MBRef.getBuffer())) {
+ case file_magic::unknown:
+ readLinkerScript(MBRef);
+ return;
+ case file_magic::archive: {
+ // Handle -whole-archive.
+ if (InWholeArchive) {
+ for (const auto &P : getArchiveMembers(MBRef))
+ Files.push_back(createObjectFile(P.first, Path, P.second));
+ return;
+ }
+
+ std::unique_ptr<Archive> File =
+ CHECK(Archive::create(MBRef), Path + ": failed to parse archive");
+
+ // If an archive file has no symbol table, it is likely that a user
+ // is attempting LTO and using a default ar command that doesn't
+ // understand the LLVM bitcode file. It is a pretty common error, so
+ // we'll handle it as if it had a symbol table.
+ if (!File->isEmpty() && !File->hasSymbolTable()) {
+ for (const auto &P : getArchiveMembers(MBRef))
+ Files.push_back(make<LazyObjFile>(P.first, Path, P.second));
+ return;
+ }
+
+ // Handle the regular case.
+ Files.push_back(make<ArchiveFile>(std::move(File)));
+ return;
+ }
+ case file_magic::elf_shared_object:
+ if (Config->Static || Config->Relocatable) {
+ error("attempted static link of dynamic object " + Path);
+ return;
+ }
+
+ // DSOs usually have DT_SONAME tags in their ELF headers, and the
+ // sonames are used to identify DSOs. But if they are missing,
+ // they are identified by filenames. We don't know whether the new
+ // file has a DT_SONAME or not because we haven't parsed it yet.
+ // Here, we set the default soname for the file because we might
+ // need it later.
+ //
+ // If a file was specified by -lfoo, the directory part is not
+ // significant, as a user did not specify it. This behavior is
+ // compatible with GNU.
+ Files.push_back(
+ createSharedFile(MBRef, WithLOption ? path::filename(Path) : Path));
+ return;
+ case file_magic::bitcode:
+ case file_magic::elf_relocatable:
+ if (InLib)
+ Files.push_back(make<LazyObjFile>(MBRef, "", 0));
+ else
+ Files.push_back(createObjectFile(MBRef));
+ break;
+ default:
+ error(Path + ": unknown file type");
+ }
+}
+
+// Add a given library by searching it from input search paths.
+void LinkerDriver::addLibrary(StringRef Name) {
+ if (Optional<std::string> Path = searchLibrary(Name))
+ addFile(*Path, /*WithLOption=*/true);
+ else
+ error("unable to find library -l" + Name);
+}
+
+// This function is called on startup. We need this for LTO since
+// LTO calls LLVM functions to compile bitcode files to native code.
+// Technically this can be delayed until we read bitcode files, but
+// we don't bother to do lazily because the initialization is fast.
+static void initLLVM() {
+ InitializeAllTargets();
+ InitializeAllTargetMCs();
+ InitializeAllAsmPrinters();
+ InitializeAllAsmParsers();
+}
+
+// Some command line options or some combinations of them are not allowed.
+// This function checks for such errors.
+static void checkOptions() {
+ // The MIPS ABI as of 2016 does not support the GNU-style symbol lookup
+ // table which is a relatively new feature.
+ if (Config->EMachine == EM_MIPS && Config->GnuHash)
+ error("the .gnu.hash section is not compatible with the MIPS target");
+
+ if (Config->FixCortexA53Errata843419 && Config->EMachine != EM_AARCH64)
+ error("--fix-cortex-a53-843419 is only supported on AArch64 targets");
+
+ if (Config->TocOptimize && Config->EMachine != EM_PPC64)
+ error("--toc-optimize is only supported on the PowerPC64 target");
+
+ if (Config->Pie && Config->Shared)
+ error("-shared and -pie may not be used together");
+
+ if (!Config->Shared && !Config->FilterList.empty())
+ error("-F may not be used without -shared");
+
+ if (!Config->Shared && !Config->AuxiliaryList.empty())
+ error("-f may not be used without -shared");
+
+ if (!Config->Relocatable && !Config->DefineCommon)
+ error("-no-define-common not supported in non relocatable output");
+
+ if (Config->Relocatable) {
+ if (Config->Shared)
+ error("-r and -shared may not be used together");
+ if (Config->GcSections)
+ error("-r and --gc-sections may not be used together");
+ if (Config->GdbIndex)
+ error("-r and --gdb-index may not be used together");
+ if (Config->ICF != ICFLevel::None)
+ error("-r and --icf may not be used together");
+ if (Config->Pie)
+ error("-r and -pie may not be used together");
+ }
+
+ if (Config->ExecuteOnly) {
+ if (Config->EMachine != EM_AARCH64)
+ error("-execute-only is only supported on AArch64 targets");
+
+ if (Config->SingleRoRx && !Script->HasSectionsCommand)
+ error("-execute-only and -no-rosegment cannot be used together");
+ }
+}
+
+static const char *getReproduceOption(opt::InputArgList &Args) {
+ if (auto *Arg = Args.getLastArg(OPT_reproduce))
+ return Arg->getValue();
+ return getenv("LLD_REPRODUCE");
+}
+
+static bool hasZOption(opt::InputArgList &Args, StringRef Key) {
+ for (auto *Arg : Args.filtered(OPT_z))
+ if (Key == Arg->getValue())
+ return true;
+ return false;
+}
+
+static bool getZFlag(opt::InputArgList &Args, StringRef K1, StringRef K2,
+ bool Default) {
+ for (auto *Arg : Args.filtered_reverse(OPT_z)) {
+ if (K1 == Arg->getValue())
+ return true;
+ if (K2 == Arg->getValue())
+ return false;
+ }
+ return Default;
+}
+
+static bool isKnownZFlag(StringRef S) {
+ return S == "combreloc" || S == "copyreloc" || S == "defs" ||
+ S == "execstack" || S == "global" || S == "hazardplt" ||
+ S == "ifunc-noplt" ||
+ S == "initfirst" || S == "interpose" ||
+ S == "keep-text-section-prefix" || S == "lazy" || S == "muldefs" ||
+ S == "nocombreloc" || S == "nocopyreloc" || S == "nodefaultlib" ||
+ S == "nodelete" || S == "nodlopen" || S == "noexecstack" ||
+ S == "nokeep-text-section-prefix" || S == "norelro" || S == "notext" ||
+ S == "now" || S == "origin" || S == "relro" || S == "retpolineplt" ||
+ S == "rodynamic" || S == "text" || S == "wxneeded" ||
+ S.startswith("max-page-size=") || S.startswith("stack-size=");
+}
+
+// Report an error for an unknown -z option.
+static void checkZOptions(opt::InputArgList &Args) {
+ for (auto *Arg : Args.filtered(OPT_z))
+ if (!isKnownZFlag(Arg->getValue()))
+ error("unknown -z value: " + StringRef(Arg->getValue()));
+}
+
+void LinkerDriver::main(ArrayRef<const char *> ArgsArr) {
+ ELFOptTable Parser;
+ opt::InputArgList Args = Parser.parse(ArgsArr.slice(1));
+
+ // Interpret this flag early because error() depends on them.
+ errorHandler().ErrorLimit = args::getInteger(Args, OPT_error_limit, 20);
+
+ // Handle -help
+ if (Args.hasArg(OPT_help)) {
+ printHelp();
+ return;
+ }
+
+ // Handle -v or -version.
+ //
+ // A note about "compatible with GNU linkers" message: this is a hack for
+ // scripts generated by GNU Libtool 2.4.6 (released in February 2014 and
+ // still the newest version in March 2017) or earlier to recognize LLD as
+ // a GNU compatible linker. As long as an output for the -v option
+ // contains "GNU" or "with BFD", they recognize us as GNU-compatible.
+ //
+ // This is somewhat ugly hack, but in reality, we had no choice other
+ // than doing this. Considering the very long release cycle of Libtool,
+ // it is not easy to improve it to recognize LLD as a GNU compatible
+ // linker in a timely manner. Even if we can make it, there are still a
+ // lot of "configure" scripts out there that are generated by old version
+ // of Libtool. We cannot convince every software developer to migrate to
+ // the latest version and re-generate scripts. So we have this hack.
+ if (Args.hasArg(OPT_v) || Args.hasArg(OPT_version))
+ message(getLLDVersion() + " (compatible with GNU linkers)");
+
+ if (const char *Path = getReproduceOption(Args)) {
+ // Note that --reproduce is a debug option so you can ignore it
+ // if you are trying to understand the whole picture of the code.
+ Expected<std::unique_ptr<TarWriter>> ErrOrWriter =
+ TarWriter::create(Path, path::stem(Path));
+ if (ErrOrWriter) {
+ Tar = std::move(*ErrOrWriter);
+ Tar->append("response.txt", createResponseFile(Args));
+ Tar->append("version.txt", getLLDVersion() + "\n");
+ } else {
+ error("--reproduce: " + toString(ErrOrWriter.takeError()));
+ }
+ }
+
+ readConfigs(Args);
+ checkZOptions(Args);
+
+ // The behavior of -v or --version is a bit strange, but this is
+ // needed for compatibility with GNU linkers.
+ if (Args.hasArg(OPT_v) && !Args.hasArg(OPT_INPUT))
+ return;
+ if (Args.hasArg(OPT_version))
+ return;
+
+ initLLVM();
+ createFiles(Args);
+ if (errorCount())
+ return;
+
+ inferMachineType();
+ setConfigs(Args);
+ checkOptions();
+ if (errorCount())
+ return;
+
+ switch (Config->EKind) {
+ case ELF32LEKind:
+ link<ELF32LE>(Args);
+ return;
+ case ELF32BEKind:
+ link<ELF32BE>(Args);
+ return;
+ case ELF64LEKind:
+ link<ELF64LE>(Args);
+ return;
+ case ELF64BEKind:
+ link<ELF64BE>(Args);
+ return;
+ default:
+ llvm_unreachable("unknown Config->EKind");
+ }
+}
+
+static std::string getRpath(opt::InputArgList &Args) {
+ std::vector<StringRef> V = args::getStrings(Args, OPT_rpath);
+ return llvm::join(V.begin(), V.end(), ":");
+}
+
+// Determines what we should do if there are remaining unresolved
+// symbols after the name resolution.
+static UnresolvedPolicy getUnresolvedSymbolPolicy(opt::InputArgList &Args) {
+ UnresolvedPolicy ErrorOrWarn = Args.hasFlag(OPT_error_unresolved_symbols,
+ OPT_warn_unresolved_symbols, true)
+ ? UnresolvedPolicy::ReportError
+ : UnresolvedPolicy::Warn;
+
+ // Process the last of -unresolved-symbols, -no-undefined or -z defs.
+ for (auto *Arg : llvm::reverse(Args)) {
+ switch (Arg->getOption().getID()) {
+ case OPT_unresolved_symbols: {
+ StringRef S = Arg->getValue();
+ if (S == "ignore-all" || S == "ignore-in-object-files")
+ return UnresolvedPolicy::Ignore;
+ if (S == "ignore-in-shared-libs" || S == "report-all")
+ return ErrorOrWarn;
+ error("unknown --unresolved-symbols value: " + S);
+ continue;
+ }
+ case OPT_no_undefined:
+ return ErrorOrWarn;
+ case OPT_z:
+ if (StringRef(Arg->getValue()) == "defs")
+ return ErrorOrWarn;
+ continue;
+ }
+ }
+
+ // -shared implies -unresolved-symbols=ignore-all because missing
+ // symbols are likely to be resolved at runtime using other DSOs.
+ if (Config->Shared)
+ return UnresolvedPolicy::Ignore;
+ return ErrorOrWarn;
+}
+
+static Target2Policy getTarget2(opt::InputArgList &Args) {
+ StringRef S = Args.getLastArgValue(OPT_target2, "got-rel");
+ if (S == "rel")
+ return Target2Policy::Rel;
+ if (S == "abs")
+ return Target2Policy::Abs;
+ if (S == "got-rel")
+ return Target2Policy::GotRel;
+ error("unknown --target2 option: " + S);
+ return Target2Policy::GotRel;
+}
+
+static bool isOutputFormatBinary(opt::InputArgList &Args) {
+ StringRef S = Args.getLastArgValue(OPT_oformat, "elf");
+ if (S == "binary")
+ return true;
+ if (!S.startswith("elf"))
+ error("unknown --oformat value: " + S);
+ return false;
+}
+
+static DiscardPolicy getDiscard(opt::InputArgList &Args) {
+ if (Args.hasArg(OPT_relocatable))
+ return DiscardPolicy::None;
+
+ auto *Arg =
+ Args.getLastArg(OPT_discard_all, OPT_discard_locals, OPT_discard_none);
+ if (!Arg)
+ return DiscardPolicy::Default;
+ if (Arg->getOption().getID() == OPT_discard_all)
+ return DiscardPolicy::All;
+ if (Arg->getOption().getID() == OPT_discard_locals)
+ return DiscardPolicy::Locals;
+ return DiscardPolicy::None;
+}
+
+static StringRef getDynamicLinker(opt::InputArgList &Args) {
+ auto *Arg = Args.getLastArg(OPT_dynamic_linker, OPT_no_dynamic_linker);
+ if (!Arg || Arg->getOption().getID() == OPT_no_dynamic_linker)
+ return "";
+ return Arg->getValue();
+}
+
+static ICFLevel getICF(opt::InputArgList &Args) {
+ auto *Arg = Args.getLastArg(OPT_icf_none, OPT_icf_safe, OPT_icf_all);
+ if (!Arg || Arg->getOption().getID() == OPT_icf_none)
+ return ICFLevel::None;
+ if (Arg->getOption().getID() == OPT_icf_safe)
+ return ICFLevel::Safe;
+ return ICFLevel::All;
+}
+
+static StripPolicy getStrip(opt::InputArgList &Args) {
+ if (Args.hasArg(OPT_relocatable))
+ return StripPolicy::None;
+
+ auto *Arg = Args.getLastArg(OPT_strip_all, OPT_strip_debug);
+ if (!Arg)
+ return StripPolicy::None;
+ if (Arg->getOption().getID() == OPT_strip_all)
+ return StripPolicy::All;
+ return StripPolicy::Debug;
+}
+
+static uint64_t parseSectionAddress(StringRef S, const opt::Arg &Arg) {
+ uint64_t VA = 0;
+ if (S.startswith("0x"))
+ S = S.drop_front(2);
+ if (!to_integer(S, VA, 16))
+ error("invalid argument: " + toString(Arg));
+ return VA;
+}
+
+static StringMap<uint64_t> getSectionStartMap(opt::InputArgList &Args) {
+ StringMap<uint64_t> Ret;
+ for (auto *Arg : Args.filtered(OPT_section_start)) {
+ StringRef Name;
+ StringRef Addr;
+ std::tie(Name, Addr) = StringRef(Arg->getValue()).split('=');
+ Ret[Name] = parseSectionAddress(Addr, *Arg);
+ }
+
+ if (auto *Arg = Args.getLastArg(OPT_Ttext))
+ Ret[".text"] = parseSectionAddress(Arg->getValue(), *Arg);
+ if (auto *Arg = Args.getLastArg(OPT_Tdata))
+ Ret[".data"] = parseSectionAddress(Arg->getValue(), *Arg);
+ if (auto *Arg = Args.getLastArg(OPT_Tbss))
+ Ret[".bss"] = parseSectionAddress(Arg->getValue(), *Arg);
+ return Ret;
+}
+
+static SortSectionPolicy getSortSection(opt::InputArgList &Args) {
+ StringRef S = Args.getLastArgValue(OPT_sort_section);
+ if (S == "alignment")
+ return SortSectionPolicy::Alignment;
+ if (S == "name")
+ return SortSectionPolicy::Name;
+ if (!S.empty())
+ error("unknown --sort-section rule: " + S);
+ return SortSectionPolicy::Default;
+}
+
+static OrphanHandlingPolicy getOrphanHandling(opt::InputArgList &Args) {
+ StringRef S = Args.getLastArgValue(OPT_orphan_handling, "place");
+ if (S == "warn")
+ return OrphanHandlingPolicy::Warn;
+ if (S == "error")
+ return OrphanHandlingPolicy::Error;
+ if (S != "place")
+ error("unknown --orphan-handling mode: " + S);
+ return OrphanHandlingPolicy::Place;
+}
+
+// Parse --build-id or --build-id=<style>. We handle "tree" as a
+// synonym for "sha1" because all our hash functions including
+// -build-id=sha1 are actually tree hashes for performance reasons.
+static std::pair<BuildIdKind, std::vector<uint8_t>>
+getBuildId(opt::InputArgList &Args) {
+ auto *Arg = Args.getLastArg(OPT_build_id, OPT_build_id_eq);
+ if (!Arg)
+ return {BuildIdKind::None, {}};
+
+ if (Arg->getOption().getID() == OPT_build_id)
+ return {BuildIdKind::Fast, {}};
+
+ StringRef S = Arg->getValue();
+ if (S == "fast")
+ return {BuildIdKind::Fast, {}};
+ if (S == "md5")
+ return {BuildIdKind::Md5, {}};
+ if (S == "sha1" || S == "tree")
+ return {BuildIdKind::Sha1, {}};
+ if (S == "uuid")
+ return {BuildIdKind::Uuid, {}};
+ if (S.startswith("0x"))
+ return {BuildIdKind::Hexstring, parseHex(S.substr(2))};
+
+ if (S != "none")
+ error("unknown --build-id style: " + S);
+ return {BuildIdKind::None, {}};
+}
+
+static std::pair<bool, bool> getPackDynRelocs(opt::InputArgList &Args) {
+ StringRef S = Args.getLastArgValue(OPT_pack_dyn_relocs, "none");
+ if (S == "android")
+ return {true, false};
+ if (S == "relr")
+ return {false, true};
+ if (S == "android+relr")
+ return {true, true};
+
+ if (S != "none")
+ error("unknown -pack-dyn-relocs format: " + S);
+ return {false, false};
+}
+
+static void readCallGraph(MemoryBufferRef MB) {
+ // Build a map from symbol name to section
+ DenseMap<StringRef, Symbol *> Map;
+ for (InputFile *File : ObjectFiles)
+ for (Symbol *Sym : File->getSymbols())
+ Map[Sym->getName()] = Sym;
+
+ auto FindSection = [&](StringRef Name) -> InputSectionBase * {
+ Symbol *Sym = Map.lookup(Name);
+ if (!Sym) {
+ if (Config->WarnSymbolOrdering)
+ warn(MB.getBufferIdentifier() + ": no such symbol: " + Name);
+ return nullptr;
+ }
+ maybeWarnUnorderableSymbol(Sym);
+
+ if (Defined *DR = dyn_cast_or_null<Defined>(Sym))
+ return dyn_cast_or_null<InputSectionBase>(DR->Section);
+ return nullptr;
+ };
+
+ for (StringRef Line : args::getLines(MB)) {
+ SmallVector<StringRef, 3> Fields;
+ Line.split(Fields, ' ');
+ uint64_t Count;
+
+ if (Fields.size() != 3 || !to_integer(Fields[2], Count)) {
+ error(MB.getBufferIdentifier() + ": parse error");
+ return;
+ }
+
+ if (InputSectionBase *From = FindSection(Fields[0]))
+ if (InputSectionBase *To = FindSection(Fields[1]))
+ Config->CallGraphProfile[std::make_pair(From, To)] += Count;
+ }
+}
+
+template <class ELFT> static void readCallGraphsFromObjectFiles() {
+ for (auto File : ObjectFiles) {
+ auto *Obj = cast<ObjFile<ELFT>>(File);
+
+ for (const Elf_CGProfile_Impl<ELFT> &CGPE : Obj->CGProfile) {
+ auto *FromSym = dyn_cast<Defined>(&Obj->getSymbol(CGPE.cgp_from));
+ auto *ToSym = dyn_cast<Defined>(&Obj->getSymbol(CGPE.cgp_to));
+ if (!FromSym || !ToSym)
+ continue;
+
+ auto *From = dyn_cast_or_null<InputSectionBase>(FromSym->Section);
+ auto *To = dyn_cast_or_null<InputSectionBase>(ToSym->Section);
+ if (From && To)
+ Config->CallGraphProfile[{From, To}] += CGPE.cgp_weight;
+ }
+ }
+}
+
+static bool getCompressDebugSections(opt::InputArgList &Args) {
+ StringRef S = Args.getLastArgValue(OPT_compress_debug_sections, "none");
+ if (S == "none")
+ return false;
+ if (S != "zlib")
+ error("unknown --compress-debug-sections value: " + S);
+ if (!zlib::isAvailable())
+ error("--compress-debug-sections: zlib is not available");
+ return true;
+}
+
+static std::pair<StringRef, StringRef> getOldNewOptions(opt::InputArgList &Args,
+ unsigned Id) {
+ auto *Arg = Args.getLastArg(Id);
+ if (!Arg)
+ return {"", ""};
+
+ StringRef S = Arg->getValue();
+ std::pair<StringRef, StringRef> Ret = S.split(';');
+ if (Ret.second.empty())
+ error(Arg->getSpelling() + " expects 'old;new' format, but got " + S);
+ return Ret;
+}
+
+// Parse the symbol ordering file and warn for any duplicate entries.
+static std::vector<StringRef> getSymbolOrderingFile(MemoryBufferRef MB) {
+ SetVector<StringRef> Names;
+ for (StringRef S : args::getLines(MB))
+ if (!Names.insert(S) && Config->WarnSymbolOrdering)
+ warn(MB.getBufferIdentifier() + ": duplicate ordered symbol: " + S);
+
+ return Names.takeVector();
+}
+
+static void parseClangOption(StringRef Opt, const Twine &Msg) {
+ std::string Err;
+ raw_string_ostream OS(Err);
+
+ const char *Argv[] = {Config->ProgName.data(), Opt.data()};
+ if (cl::ParseCommandLineOptions(2, Argv, "", &OS))
+ return;
+ OS.flush();
+ error(Msg + ": " + StringRef(Err).trim());
+}
+
+// Initializes Config members by the command line options.
+void LinkerDriver::readConfigs(opt::InputArgList &Args) {
+ errorHandler().Verbose = Args.hasArg(OPT_verbose);
+ errorHandler().FatalWarnings =
+ Args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false);
+ ThreadsEnabled = Args.hasFlag(OPT_threads, OPT_no_threads, true);
+
+ Config->AllowMultipleDefinition =
+ Args.hasFlag(OPT_allow_multiple_definition,
+ OPT_no_allow_multiple_definition, false) ||
+ hasZOption(Args, "muldefs");
+ Config->AuxiliaryList = args::getStrings(Args, OPT_auxiliary);
+ Config->Bsymbolic = Args.hasArg(OPT_Bsymbolic);
+ Config->BsymbolicFunctions = Args.hasArg(OPT_Bsymbolic_functions);
+ Config->CheckSections =
+ Args.hasFlag(OPT_check_sections, OPT_no_check_sections, true);
+ Config->Chroot = Args.getLastArgValue(OPT_chroot);
+ Config->CompressDebugSections = getCompressDebugSections(Args);
+ Config->Cref = Args.hasFlag(OPT_cref, OPT_no_cref, false);
+ Config->DefineCommon = Args.hasFlag(OPT_define_common, OPT_no_define_common,
+ !Args.hasArg(OPT_relocatable));
+ Config->Demangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, true);
+ Config->DisableVerify = Args.hasArg(OPT_disable_verify);
+ Config->Discard = getDiscard(Args);
+ Config->DwoDir = Args.getLastArgValue(OPT_plugin_opt_dwo_dir_eq);
+ Config->DynamicLinker = getDynamicLinker(Args);
+ Config->EhFrameHdr =
+ Args.hasFlag(OPT_eh_frame_hdr, OPT_no_eh_frame_hdr, false);
+ Config->EmitLLVM = Args.hasArg(OPT_plugin_opt_emit_llvm, false);
+ Config->EmitRelocs = Args.hasArg(OPT_emit_relocs);
+ Config->CallGraphProfileSort = Args.hasFlag(
+ OPT_call_graph_profile_sort, OPT_no_call_graph_profile_sort, true);
+ Config->EnableNewDtags =
+ Args.hasFlag(OPT_enable_new_dtags, OPT_disable_new_dtags, true);
+ Config->Entry = Args.getLastArgValue(OPT_entry);
+ Config->ExecuteOnly =
+ Args.hasFlag(OPT_execute_only, OPT_no_execute_only, false);
+ Config->ExportDynamic =
+ Args.hasFlag(OPT_export_dynamic, OPT_no_export_dynamic, false);
+ Config->FilterList = args::getStrings(Args, OPT_filter);
+ Config->Fini = Args.getLastArgValue(OPT_fini, "_fini");
+ Config->FixCortexA53Errata843419 = Args.hasArg(OPT_fix_cortex_a53_843419);
+ Config->GcSections = Args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, false);
+ Config->GnuUnique = Args.hasFlag(OPT_gnu_unique, OPT_no_gnu_unique, true);
+ Config->GdbIndex = Args.hasFlag(OPT_gdb_index, OPT_no_gdb_index, false);
+ Config->ICF = getICF(Args);
+ Config->IgnoreDataAddressEquality =
+ Args.hasArg(OPT_ignore_data_address_equality);
+ Config->IgnoreFunctionAddressEquality =
+ Args.hasArg(OPT_ignore_function_address_equality);
+ Config->Init = Args.getLastArgValue(OPT_init, "_init");
+ Config->LTOAAPipeline = Args.getLastArgValue(OPT_lto_aa_pipeline);
+ Config->LTODebugPassManager = Args.hasArg(OPT_lto_debug_pass_manager);
+ Config->LTONewPassManager = Args.hasArg(OPT_lto_new_pass_manager);
+ Config->LTONewPmPasses = Args.getLastArgValue(OPT_lto_newpm_passes);
+ Config->LTOO = args::getInteger(Args, OPT_lto_O, 2);
+ Config->LTOObjPath = Args.getLastArgValue(OPT_plugin_opt_obj_path_eq);
+ Config->LTOPartitions = args::getInteger(Args, OPT_lto_partitions, 1);
+ Config->LTOSampleProfile = Args.getLastArgValue(OPT_lto_sample_profile);
+ Config->MapFile = Args.getLastArgValue(OPT_Map);
+ Config->MipsGotSize = args::getInteger(Args, OPT_mips_got_size, 0xfff0);
+ Config->MergeArmExidx =
+ Args.hasFlag(OPT_merge_exidx_entries, OPT_no_merge_exidx_entries, true);
+ Config->NoinhibitExec = Args.hasArg(OPT_noinhibit_exec);
+ Config->Nostdlib = Args.hasArg(OPT_nostdlib);
+ Config->OFormatBinary = isOutputFormatBinary(Args);
+ Config->Omagic = Args.hasFlag(OPT_omagic, OPT_no_omagic, false);
+ Config->OptRemarksFilename = Args.getLastArgValue(OPT_opt_remarks_filename);
+ Config->OptRemarksWithHotness = Args.hasArg(OPT_opt_remarks_with_hotness);
+ Config->Optimize = args::getInteger(Args, OPT_O, 1);
+ Config->OrphanHandling = getOrphanHandling(Args);
+ Config->OutputFile = Args.getLastArgValue(OPT_o);
+ Config->Pie = Args.hasFlag(OPT_pie, OPT_no_pie, false);
+ Config->PrintIcfSections =
+ Args.hasFlag(OPT_print_icf_sections, OPT_no_print_icf_sections, false);
+ Config->PrintGcSections =
+ Args.hasFlag(OPT_print_gc_sections, OPT_no_print_gc_sections, false);
+ Config->Rpath = getRpath(Args);
+ Config->Relocatable = Args.hasArg(OPT_relocatable);
+ Config->SaveTemps = Args.hasArg(OPT_save_temps);
+ Config->SearchPaths = args::getStrings(Args, OPT_library_path);
+ Config->SectionStartMap = getSectionStartMap(Args);
+ Config->Shared = Args.hasArg(OPT_shared);
+ Config->SingleRoRx = Args.hasArg(OPT_no_rosegment);
+ Config->SoName = Args.getLastArgValue(OPT_soname);
+ Config->SortSection = getSortSection(Args);
+ Config->SplitStackAdjustSize = args::getInteger(Args, OPT_split_stack_adjust_size, 16384);
+ Config->Strip = getStrip(Args);
+ Config->Sysroot = Args.getLastArgValue(OPT_sysroot);
+ Config->Target1Rel = Args.hasFlag(OPT_target1_rel, OPT_target1_abs, false);
+ Config->Target2 = getTarget2(Args);
+ Config->ThinLTOCacheDir = Args.getLastArgValue(OPT_thinlto_cache_dir);
+ Config->ThinLTOCachePolicy = CHECK(
+ parseCachePruningPolicy(Args.getLastArgValue(OPT_thinlto_cache_policy)),
+ "--thinlto-cache-policy: invalid cache policy");
+ Config->ThinLTOEmitImportsFiles =
+ Args.hasArg(OPT_plugin_opt_thinlto_emit_imports_files);
+ Config->ThinLTOIndexOnly = Args.hasArg(OPT_plugin_opt_thinlto_index_only) ||
+ Args.hasArg(OPT_plugin_opt_thinlto_index_only_eq);
+ Config->ThinLTOIndexOnlyArg =
+ Args.getLastArgValue(OPT_plugin_opt_thinlto_index_only_eq);
+ Config->ThinLTOJobs = args::getInteger(Args, OPT_thinlto_jobs, -1u);
+ Config->ThinLTOObjectSuffixReplace =
+ getOldNewOptions(Args, OPT_plugin_opt_thinlto_object_suffix_replace_eq);
+ Config->ThinLTOPrefixReplace =
+ getOldNewOptions(Args, OPT_plugin_opt_thinlto_prefix_replace_eq);
+ Config->Trace = Args.hasArg(OPT_trace);
+ Config->Undefined = args::getStrings(Args, OPT_undefined);
+ Config->UndefinedVersion =
+ Args.hasFlag(OPT_undefined_version, OPT_no_undefined_version, true);
+ Config->UseAndroidRelrTags = Args.hasFlag(
+ OPT_use_android_relr_tags, OPT_no_use_android_relr_tags, false);
+ Config->UnresolvedSymbols = getUnresolvedSymbolPolicy(Args);
+ Config->WarnBackrefs =
+ Args.hasFlag(OPT_warn_backrefs, OPT_no_warn_backrefs, false);
+ Config->WarnCommon = Args.hasFlag(OPT_warn_common, OPT_no_warn_common, false);
+ Config->WarnIfuncTextrel =
+ Args.hasFlag(OPT_warn_ifunc_textrel, OPT_no_warn_ifunc_textrel, false);
+ Config->WarnSymbolOrdering =
+ Args.hasFlag(OPT_warn_symbol_ordering, OPT_no_warn_symbol_ordering, true);
+ Config->ZCombreloc = getZFlag(Args, "combreloc", "nocombreloc", true);
+ Config->ZCopyreloc = getZFlag(Args, "copyreloc", "nocopyreloc", true);
+ Config->ZExecstack = getZFlag(Args, "execstack", "noexecstack", false);
+ Config->ZGlobal = hasZOption(Args, "global");
+ Config->ZHazardplt = hasZOption(Args, "hazardplt");
+ Config->ZIfuncnoplt = hasZOption(Args, "ifunc-noplt");
+ Config->ZInitfirst = hasZOption(Args, "initfirst");
+ Config->ZInterpose = hasZOption(Args, "interpose");
+ Config->ZKeepTextSectionPrefix = getZFlag(
+ Args, "keep-text-section-prefix", "nokeep-text-section-prefix", false);
+ Config->ZNodefaultlib = hasZOption(Args, "nodefaultlib");
+ Config->ZNodelete = hasZOption(Args, "nodelete");
+ Config->ZNodlopen = hasZOption(Args, "nodlopen");
+ Config->ZNow = getZFlag(Args, "now", "lazy", false);
+ Config->ZOrigin = hasZOption(Args, "origin");
+ Config->ZRelro = getZFlag(Args, "relro", "norelro", true);
+ Config->ZRetpolineplt = hasZOption(Args, "retpolineplt");
+ Config->ZRodynamic = hasZOption(Args, "rodynamic");
+ Config->ZStackSize = args::getZOptionValue(Args, OPT_z, "stack-size", 0);
+ Config->ZText = getZFlag(Args, "text", "notext", true);
+ Config->ZWxneeded = hasZOption(Args, "wxneeded");
+
+ // Parse LTO options.
+ if (auto *Arg = Args.getLastArg(OPT_plugin_opt_mcpu_eq))
+ parseClangOption(Saver.save("-mcpu=" + StringRef(Arg->getValue())),
+ Arg->getSpelling());
+
+ for (auto *Arg : Args.filtered(OPT_plugin_opt))
+ parseClangOption(Arg->getValue(), Arg->getSpelling());
+
+ // Parse -mllvm options.
+ for (auto *Arg : Args.filtered(OPT_mllvm))
+ parseClangOption(Arg->getValue(), Arg->getSpelling());
+
+ if (Config->LTOO > 3)
+ error("invalid optimization level for LTO: " + Twine(Config->LTOO));
+ if (Config->LTOPartitions == 0)
+ error("--lto-partitions: number of threads must be > 0");
+ if (Config->ThinLTOJobs == 0)
+ error("--thinlto-jobs: number of threads must be > 0");
+
+ if (Config->SplitStackAdjustSize < 0)
+ error("--split-stack-adjust-size: size must be >= 0");
+
+ // Parse ELF{32,64}{LE,BE} and CPU type.
+ if (auto *Arg = Args.getLastArg(OPT_m)) {
+ StringRef S = Arg->getValue();
+ std::tie(Config->EKind, Config->EMachine, Config->OSABI) =
+ parseEmulation(S);
+ Config->MipsN32Abi = (S == "elf32btsmipn32" || S == "elf32ltsmipn32");
+ Config->Emulation = S;
+ }
+
+ // Parse -hash-style={sysv,gnu,both}.
+ if (auto *Arg = Args.getLastArg(OPT_hash_style)) {
+ StringRef S = Arg->getValue();
+ if (S == "sysv")
+ Config->SysvHash = true;
+ else if (S == "gnu")
+ Config->GnuHash = true;
+ else if (S == "both")
+ Config->SysvHash = Config->GnuHash = true;
+ else
+ error("unknown -hash-style: " + S);
+ }
+
+ if (Args.hasArg(OPT_print_map))
+ Config->MapFile = "-";
+
+ // --omagic is an option to create old-fashioned executables in which
+ // .text segments are writable. Today, the option is still in use to
+ // create special-purpose programs such as boot loaders. It doesn't
+ // make sense to create PT_GNU_RELRO for such executables.
+ if (Config->Omagic)
+ Config->ZRelro = false;
+
+ std::tie(Config->BuildId, Config->BuildIdVector) = getBuildId(Args);
+
+ std::tie(Config->AndroidPackDynRelocs, Config->RelrPackDynRelocs) =
+ getPackDynRelocs(Args);
+
+ if (auto *Arg = Args.getLastArg(OPT_symbol_ordering_file))
+ if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
+ Config->SymbolOrderingFile = getSymbolOrderingFile(*Buffer);
+
+ // If --retain-symbol-file is used, we'll keep only the symbols listed in
+ // the file and discard all others.
+ if (auto *Arg = Args.getLastArg(OPT_retain_symbols_file)) {
+ Config->DefaultSymbolVersion = VER_NDX_LOCAL;
+ if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
+ for (StringRef S : args::getLines(*Buffer))
+ Config->VersionScriptGlobals.push_back(
+ {S, /*IsExternCpp*/ false, /*HasWildcard*/ false});
+ }
+
+ bool HasExportDynamic =
+ Args.hasFlag(OPT_export_dynamic, OPT_no_export_dynamic, false);
+
+ // Parses -dynamic-list and -export-dynamic-symbol. They make some
+ // symbols private. Note that -export-dynamic takes precedence over them
+ // as it says all symbols should be exported.
+ if (!HasExportDynamic) {
+ for (auto *Arg : Args.filtered(OPT_dynamic_list))
+ if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
+ readDynamicList(*Buffer);
+
+ for (auto *Arg : Args.filtered(OPT_export_dynamic_symbol))
+ Config->DynamicList.push_back(
+ {Arg->getValue(), /*IsExternCpp*/ false, /*HasWildcard*/ false});
+ }
+
+ // If --export-dynamic-symbol=foo is given and symbol foo is defined in
+ // an object file in an archive file, that object file should be pulled
+ // out and linked. (It doesn't have to behave like that from technical
+ // point of view, but this is needed for compatibility with GNU.)
+ for (auto *Arg : Args.filtered(OPT_export_dynamic_symbol))
+ Config->Undefined.push_back(Arg->getValue());
+
+ for (auto *Arg : Args.filtered(OPT_version_script))
+ if (Optional<std::string> Path = searchScript(Arg->getValue())) {
+ if (Optional<MemoryBufferRef> Buffer = readFile(*Path))
+ readVersionScript(*Buffer);
+ } else {
+ error(Twine("cannot find version script ") + Arg->getValue());
+ }
+}
+
+// Some Config members do not directly correspond to any particular
+// command line options, but computed based on other Config values.
+// This function initialize such members. See Config.h for the details
+// of these values.
+static void setConfigs(opt::InputArgList &Args) {
+ ELFKind K = Config->EKind;
+ uint16_t M = Config->EMachine;
+
+ Config->CopyRelocs = (Config->Relocatable || Config->EmitRelocs);
+ Config->Is64 = (K == ELF64LEKind || K == ELF64BEKind);
+ Config->IsLE = (K == ELF32LEKind || K == ELF64LEKind);
+ Config->Endianness = Config->IsLE ? endianness::little : endianness::big;
+ Config->IsMips64EL = (K == ELF64LEKind && M == EM_MIPS);
+ Config->Pic = Config->Pie || Config->Shared;
+ Config->PicThunk = Args.hasArg(OPT_pic_veneer, Config->Pic);
+ Config->Wordsize = Config->Is64 ? 8 : 4;
+
+ // ELF defines two different ways to store relocation addends as shown below:
+ //
+ // Rel: Addends are stored to the location where relocations are applied.
+ // Rela: Addends are stored as part of relocation entry.
+ //
+ // In other words, Rela makes it easy to read addends at the price of extra
+ // 4 or 8 byte for each relocation entry. We don't know why ELF defined two
+ // different mechanisms in the first place, but this is how the spec is
+ // defined.
+ //
+ // You cannot choose which one, Rel or Rela, you want to use. Instead each
+ // ABI defines which one you need to use. The following expression expresses
+ // that.
+ Config->IsRela = M == EM_AARCH64 || M == EM_AMDGPU || M == EM_HEXAGON ||
+ M == EM_PPC || M == EM_PPC64 || M == EM_RISCV ||
+ M == EM_X86_64;
+
+ // If the output uses REL relocations we must store the dynamic relocation
+ // addends to the output sections. We also store addends for RELA relocations
+ // if --apply-dynamic-relocs is used.
+ // We default to not writing the addends when using RELA relocations since
+ // any standard conforming tool can find it in r_addend.
+ Config->WriteAddends = Args.hasFlag(OPT_apply_dynamic_relocs,
+ OPT_no_apply_dynamic_relocs, false) ||
+ !Config->IsRela;
+
+ Config->TocOptimize =
+ Args.hasFlag(OPT_toc_optimize, OPT_no_toc_optimize, M == EM_PPC64);
+}
+
+// Returns a value of "-format" option.
+static bool isFormatBinary(StringRef S) {
+ if (S == "binary")
+ return true;
+ if (S == "elf" || S == "default")
+ return false;
+ error("unknown -format value: " + S +
+ " (supported formats: elf, default, binary)");
+ return false;
+}
+
+void LinkerDriver::createFiles(opt::InputArgList &Args) {
+ // For --{push,pop}-state.
+ std::vector<std::tuple<bool, bool, bool>> Stack;
+
+ // Iterate over argv to process input files and positional arguments.
+ for (auto *Arg : Args) {
+ switch (Arg->getOption().getUnaliasedOption().getID()) {
+ case OPT_library:
+ addLibrary(Arg->getValue());
+ break;
+ case OPT_INPUT:
+ addFile(Arg->getValue(), /*WithLOption=*/false);
+ break;
+ case OPT_defsym: {
+ StringRef From;
+ StringRef To;
+ std::tie(From, To) = StringRef(Arg->getValue()).split('=');
+ if (From.empty() || To.empty())
+ error("-defsym: syntax error: " + StringRef(Arg->getValue()));
+ else
+ readDefsym(From, MemoryBufferRef(To, "-defsym"));
+ break;
+ }
+ case OPT_script:
+ if (Optional<std::string> Path = searchScript(Arg->getValue())) {
+ if (Optional<MemoryBufferRef> MB = readFile(*Path))
+ readLinkerScript(*MB);
+ break;
+ }
+ error(Twine("cannot find linker script ") + Arg->getValue());
+ break;
+ case OPT_as_needed:
+ Config->AsNeeded = true;
+ break;
+ case OPT_format:
+ Config->FormatBinary = isFormatBinary(Arg->getValue());
+ break;
+ case OPT_no_as_needed:
+ Config->AsNeeded = false;
+ break;
+ case OPT_Bstatic:
+ Config->Static = true;
+ break;
+ case OPT_Bdynamic:
+ Config->Static = false;
+ break;
+ case OPT_whole_archive:
+ InWholeArchive = true;
+ break;
+ case OPT_no_whole_archive:
+ InWholeArchive = false;
+ break;
+ case OPT_just_symbols:
+ if (Optional<MemoryBufferRef> MB = readFile(Arg->getValue())) {
+ Files.push_back(createObjectFile(*MB));
+ Files.back()->JustSymbols = true;
+ }
+ break;
+ case OPT_start_group:
+ if (InputFile::IsInGroup)
+ error("nested --start-group");
+ InputFile::IsInGroup = true;
+ break;
+ case OPT_end_group:
+ if (!InputFile::IsInGroup)
+ error("stray --end-group");
+ InputFile::IsInGroup = false;
+ ++InputFile::NextGroupId;
+ break;
+ case OPT_start_lib:
+ if (InLib)
+ error("nested --start-lib");
+ if (InputFile::IsInGroup)
+ error("may not nest --start-lib in --start-group");
+ InLib = true;
+ InputFile::IsInGroup = true;
+ break;
+ case OPT_end_lib:
+ if (!InLib)
+ error("stray --end-lib");
+ InLib = false;
+ InputFile::IsInGroup = false;
+ ++InputFile::NextGroupId;
+ break;
+ case OPT_push_state:
+ Stack.emplace_back(Config->AsNeeded, Config->Static, InWholeArchive);
+ break;
+ case OPT_pop_state:
+ if (Stack.empty()) {
+ error("unbalanced --push-state/--pop-state");
+ break;
+ }
+ std::tie(Config->AsNeeded, Config->Static, InWholeArchive) = Stack.back();
+ Stack.pop_back();
+ break;
+ }
+ }
+
+ if (Files.empty() && errorCount() == 0)
+ error("no input files");
+}
+
+// If -m <machine_type> was not given, infer it from object files.
+void LinkerDriver::inferMachineType() {
+ if (Config->EKind != ELFNoneKind)
+ return;
+
+ for (InputFile *F : Files) {
+ if (F->EKind == ELFNoneKind)
+ continue;
+ Config->EKind = F->EKind;
+ Config->EMachine = F->EMachine;
+ Config->OSABI = F->OSABI;
+ Config->MipsN32Abi = Config->EMachine == EM_MIPS && isMipsN32Abi(F);
+ return;
+ }
+ error("target emulation unknown: -m or at least one .o file required");
+}
+
+// Parse -z max-page-size=<value>. The default value is defined by
+// each target.
+static uint64_t getMaxPageSize(opt::InputArgList &Args) {
+ uint64_t Val = args::getZOptionValue(Args, OPT_z, "max-page-size",
+ Target->DefaultMaxPageSize);
+ if (!isPowerOf2_64(Val))
+ error("max-page-size: value isn't a power of 2");
+ return Val;
+}
+
+// Parses -image-base option.
+static Optional<uint64_t> getImageBase(opt::InputArgList &Args) {
+ // Because we are using "Config->MaxPageSize" here, this function has to be
+ // called after the variable is initialized.
+ auto *Arg = Args.getLastArg(OPT_image_base);
+ if (!Arg)
+ return None;
+
+ StringRef S = Arg->getValue();
+ uint64_t V;
+ if (!to_integer(S, V)) {
+ error("-image-base: number expected, but got " + S);
+ return 0;
+ }
+ if ((V % Config->MaxPageSize) != 0)
+ warn("-image-base: address isn't multiple of page size: " + S);
+ return V;
+}
+
+// Parses `--exclude-libs=lib,lib,...`.
+// The library names may be delimited by commas or colons.
+static DenseSet<StringRef> getExcludeLibs(opt::InputArgList &Args) {
+ DenseSet<StringRef> Ret;
+ for (auto *Arg : Args.filtered(OPT_exclude_libs)) {
+ StringRef S = Arg->getValue();
+ for (;;) {
+ size_t Pos = S.find_first_of(",:");
+ if (Pos == StringRef::npos)
+ break;
+ Ret.insert(S.substr(0, Pos));
+ S = S.substr(Pos + 1);
+ }
+ Ret.insert(S);
+ }
+ return Ret;
+}
+
+// Handles the -exclude-libs option. If a static library file is specified
+// by the -exclude-libs option, all public symbols from the archive become
+// private unless otherwise specified by version scripts or something.
+// A special library name "ALL" means all archive files.
+//
+// This is not a popular option, but some programs such as bionic libc use it.
+template <class ELFT>
+static void excludeLibs(opt::InputArgList &Args) {
+ DenseSet<StringRef> Libs = getExcludeLibs(Args);
+ bool All = Libs.count("ALL");
+
+ auto Visit = [&](InputFile *File) {
+ if (!File->ArchiveName.empty())
+ if (All || Libs.count(path::filename(File->ArchiveName)))
+ for (Symbol *Sym : File->getSymbols())
+ if (!Sym->isLocal() && Sym->File == File)
+ Sym->VersionId = VER_NDX_LOCAL;
+ };
+
+ for (InputFile *File : ObjectFiles)
+ Visit(File);
+
+ for (BitcodeFile *File : BitcodeFiles)
+ Visit(File);
+}
+
+// Force Sym to be entered in the output. Used for -u or equivalent.
+template <class ELFT> static void handleUndefined(StringRef Name) {
+ Symbol *Sym = Symtab->find(Name);
+ if (!Sym)
+ return;
+
+ // Since symbol S may not be used inside the program, LTO may
+ // eliminate it. Mark the symbol as "used" to prevent it.
+ Sym->IsUsedInRegularObj = true;
+
+ if (Sym->isLazy())
+ Symtab->fetchLazy<ELFT>(Sym);
+}
+
+template <class ELFT> static void handleLibcall(StringRef Name) {
+ Symbol *Sym = Symtab->find(Name);
+ if (!Sym || !Sym->isLazy())
+ return;
+
+ MemoryBufferRef MB;
+ if (auto *LO = dyn_cast<LazyObject>(Sym))
+ MB = LO->File->MB;
+ else
+ MB = cast<LazyArchive>(Sym)->getMemberBuffer();
+
+ if (isBitcode(MB))
+ Symtab->fetchLazy<ELFT>(Sym);
+}
+
+// If all references to a DSO happen to be weak, the DSO is not added
+// to DT_NEEDED. If that happens, we need to eliminate shared symbols
+// created from the DSO. Otherwise, they become dangling references
+// that point to a non-existent DSO.
+template <class ELFT> static void demoteSharedSymbols() {
+ for (Symbol *Sym : Symtab->getSymbols()) {
+ if (auto *S = dyn_cast<SharedSymbol>(Sym)) {
+ if (!S->getFile<ELFT>().IsNeeded) {
+ bool Used = S->Used;
+ replaceSymbol<Undefined>(S, nullptr, S->getName(), STB_WEAK, S->StOther,
+ S->Type);
+ S->Used = Used;
+ }
+ }
+ }
+}
+
+// The section referred to by S is considered address-significant. Set the
+// KeepUnique flag on the section if appropriate.
+static void markAddrsig(Symbol *S) {
+ if (auto *D = dyn_cast_or_null<Defined>(S))
+ if (D->Section)
+ // We don't need to keep text sections unique under --icf=all even if they
+ // are address-significant.
+ if (Config->ICF == ICFLevel::Safe || !(D->Section->Flags & SHF_EXECINSTR))
+ D->Section->KeepUnique = true;
+}
+
+// Record sections that define symbols mentioned in --keep-unique <symbol>
+// and symbols referred to by address-significance tables. These sections are
+// ineligible for ICF.
+template <class ELFT>
+static void findKeepUniqueSections(opt::InputArgList &Args) {
+ for (auto *Arg : Args.filtered(OPT_keep_unique)) {
+ StringRef Name = Arg->getValue();
+ auto *D = dyn_cast_or_null<Defined>(Symtab->find(Name));
+ if (!D || !D->Section) {
+ warn("could not find symbol " + Name + " to keep unique");
+ continue;
+ }
+ D->Section->KeepUnique = true;
+ }
+
+ // --icf=all --ignore-data-address-equality means that we can ignore
+ // the dynsym and address-significance tables entirely.
+ if (Config->ICF == ICFLevel::All && Config->IgnoreDataAddressEquality)
+ return;
+
+ // Symbols in the dynsym could be address-significant in other executables
+ // or DSOs, so we conservatively mark them as address-significant.
+ for (Symbol *S : Symtab->getSymbols())
+ if (S->includeInDynsym())
+ markAddrsig(S);
+
+ // Visit the address-significance table in each object file and mark each
+ // referenced symbol as address-significant.
+ for (InputFile *F : ObjectFiles) {
+ auto *Obj = cast<ObjFile<ELFT>>(F);
+ ArrayRef<Symbol *> Syms = Obj->getSymbols();
+ if (Obj->AddrsigSec) {
+ ArrayRef<uint8_t> Contents =
+ check(Obj->getObj().getSectionContents(Obj->AddrsigSec));
+ const uint8_t *Cur = Contents.begin();
+ while (Cur != Contents.end()) {
+ unsigned Size;
+ const char *Err;
+ uint64_t SymIndex = decodeULEB128(Cur, &Size, Contents.end(), &Err);
+ if (Err)
+ fatal(toString(F) + ": could not decode addrsig section: " + Err);
+ markAddrsig(Syms[SymIndex]);
+ Cur += Size;
+ }
+ } else {
+ // If an object file does not have an address-significance table,
+ // conservatively mark all of its symbols as address-significant.
+ for (Symbol *S : Syms)
+ markAddrsig(S);
+ }
+ }
+}
+
+template <class ELFT> static Symbol *addUndefined(StringRef Name) {
+ return Symtab->addUndefined<ELFT>(Name, STB_GLOBAL, STV_DEFAULT, 0, false,
+ nullptr);
+}
+
+// The --wrap option is a feature to rename symbols so that you can write
+// wrappers for existing functions. If you pass `-wrap=foo`, all
+// occurrences of symbol `foo` are resolved to `wrap_foo` (so, you are
+// expected to write `wrap_foo` function as a wrapper). The original
+// symbol becomes accessible as `real_foo`, so you can call that from your
+// wrapper.
+//
+// This data structure is instantiated for each -wrap option.
+struct WrappedSymbol {
+ Symbol *Sym;
+ Symbol *Real;
+ Symbol *Wrap;
+};
+
+// Handles -wrap option.
+//
+// This function instantiates wrapper symbols. At this point, they seem
+// like they are not being used at all, so we explicitly set some flags so
+// that LTO won't eliminate them.
+template <class ELFT>
+static std::vector<WrappedSymbol> addWrappedSymbols(opt::InputArgList &Args) {
+ std::vector<WrappedSymbol> V;
+ DenseSet<StringRef> Seen;
+
+ for (auto *Arg : Args.filtered(OPT_wrap)) {
+ StringRef Name = Arg->getValue();
+ if (!Seen.insert(Name).second)
+ continue;
+
+ Symbol *Sym = Symtab->find(Name);
+ if (!Sym)
+ continue;
+
+ Symbol *Real = addUndefined<ELFT>(Saver.save("__real_" + Name));
+ Symbol *Wrap = addUndefined<ELFT>(Saver.save("__wrap_" + Name));
+ V.push_back({Sym, Real, Wrap});
+
+ // We want to tell LTO not to inline symbols to be overwritten
+ // because LTO doesn't know the final symbol contents after renaming.
+ Real->CanInline = false;
+ Sym->CanInline = false;
+
+ // Tell LTO not to eliminate these symbols.
+ Sym->IsUsedInRegularObj = true;
+ Wrap->IsUsedInRegularObj = true;
+ }
+ return V;
+}
+
+// Do renaming for -wrap by updating pointers to symbols.
+//
+// When this function is executed, only InputFiles and symbol table
+// contain pointers to symbol objects. We visit them to replace pointers,
+// so that wrapped symbols are swapped as instructed by the command line.
+template <class ELFT> static void wrapSymbols(ArrayRef<WrappedSymbol> Wrapped) {
+ DenseMap<Symbol *, Symbol *> Map;
+ for (const WrappedSymbol &W : Wrapped) {
+ Map[W.Sym] = W.Wrap;
+ Map[W.Real] = W.Sym;
+ }
+
+ // Update pointers in input files.
+ parallelForEach(ObjectFiles, [&](InputFile *File) {
+ std::vector<Symbol *> &Syms = File->getMutableSymbols();
+ for (size_t I = 0, E = Syms.size(); I != E; ++I)
+ if (Symbol *S = Map.lookup(Syms[I]))
+ Syms[I] = S;
+ });
+
+ // Update pointers in the symbol table.
+ for (const WrappedSymbol &W : Wrapped)
+ Symtab->wrap(W.Sym, W.Real, W.Wrap);
+}
+
+static const char *LibcallRoutineNames[] = {
+#define HANDLE_LIBCALL(code, name) name,
+#include "llvm/IR/RuntimeLibcalls.def"
+#undef HANDLE_LIBCALL
+};
+
+// Do actual linking. Note that when this function is called,
+// all linker scripts have already been parsed.
+template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
+ Target = getTarget();
+ InX<ELFT>::VerSym = nullptr;
+ InX<ELFT>::VerNeed = nullptr;
+
+ Config->MaxPageSize = getMaxPageSize(Args);
+ Config->ImageBase = getImageBase(Args);
+
+ // If a -hash-style option was not given, set to a default value,
+ // which varies depending on the target.
+ if (!Args.hasArg(OPT_hash_style)) {
+ if (Config->EMachine == EM_MIPS)
+ Config->SysvHash = true;
+ else
+ Config->SysvHash = Config->GnuHash = true;
+ }
+
+ // Default output filename is "a.out" by the Unix tradition.
+ if (Config->OutputFile.empty())
+ Config->OutputFile = "a.out";
+
+ // Fail early if the output file or map file is not writable. If a user has a
+ // long link, e.g. due to a large LTO link, they do not wish to run it and
+ // find that it failed because there was a mistake in their command-line.
+ if (auto E = tryCreateFile(Config->OutputFile))
+ error("cannot open output file " + Config->OutputFile + ": " + E.message());
+ if (auto E = tryCreateFile(Config->MapFile))
+ error("cannot open map file " + Config->MapFile + ": " + E.message());
+ if (errorCount())
+ return;
+
+ // Use default entry point name if no name was given via the command
+ // line nor linker scripts. For some reason, MIPS entry point name is
+ // different from others.
+ Config->WarnMissingEntry =
+ (!Config->Entry.empty() || (!Config->Shared && !Config->Relocatable));
+ if (Config->Entry.empty() && !Config->Relocatable)
+ Config->Entry = (Config->EMachine == EM_MIPS) ? "__start" : "_start";
+
+ // Handle --trace-symbol.
+ for (auto *Arg : Args.filtered(OPT_trace_symbol))
+ Symtab->trace(Arg->getValue());
+
+ // Add all files to the symbol table. This will add almost all
+ // symbols that we need to the symbol table.
+ for (InputFile *F : Files)
+ Symtab->addFile<ELFT>(F);
+
+ // Now that we have every file, we can decide if we will need a
+ // dynamic symbol table.
+ // We need one if we were asked to export dynamic symbols or if we are
+ // producing a shared library.
+ // We also need one if any shared libraries are used and for pie executables
+ // (probably because the dynamic linker needs it).
+ Config->HasDynSymTab =
+ !SharedFiles.empty() || Config->Pic || Config->ExportDynamic;
+
+ // Some symbols (such as __ehdr_start) are defined lazily only when there
+ // are undefined symbols for them, so we add these to trigger that logic.
+ for (StringRef Name : Script->ReferencedSymbols)
+ addUndefined<ELFT>(Name);
+
+ // Handle the `--undefined <sym>` options.
+ for (StringRef S : Config->Undefined)
+ handleUndefined<ELFT>(S);
+
+ // If an entry symbol is in a static archive, pull out that file now.
+ handleUndefined<ELFT>(Config->Entry);
+
+ // If any of our inputs are bitcode files, the LTO code generator may create
+ // references to certain library functions that might not be explicit in the
+ // bitcode file's symbol table. If any of those library functions are defined
+ // in a bitcode file in an archive member, we need to arrange to use LTO to
+ // compile those archive members by adding them to the link beforehand.
+ //
+ // However, adding all libcall symbols to the link can have undesired
+ // consequences. For example, the libgcc implementation of
+ // __sync_val_compare_and_swap_8 on 32-bit ARM pulls in an .init_array entry
+ // that aborts the program if the Linux kernel does not support 64-bit
+ // atomics, which would prevent the program from running even if it does not
+ // use 64-bit atomics.
+ //
+ // Therefore, we only add libcall symbols to the link before LTO if we have
+ // to, i.e. if the symbol's definition is in bitcode. Any other required
+ // libcall symbols will be added to the link after LTO when we add the LTO
+ // object file to the link.
+ if (!BitcodeFiles.empty())
+ for (const char *S : LibcallRoutineNames)
+ handleLibcall<ELFT>(S);
+
+ // Return if there were name resolution errors.
+ if (errorCount())
+ return;
+
+ // Now when we read all script files, we want to finalize order of linker
+ // script commands, which can be not yet final because of INSERT commands.
+ Script->processInsertCommands();
+
+ // We want to declare linker script's symbols early,
+ // so that we can version them.
+ // They also might be exported if referenced by DSOs.
+ Script->declareSymbols();
+
+ // Handle the -exclude-libs option.
+ if (Args.hasArg(OPT_exclude_libs))
+ excludeLibs<ELFT>(Args);
+
+ // Create ElfHeader early. We need a dummy section in
+ // addReservedSymbols to mark the created symbols as not absolute.
+ Out::ElfHeader = make<OutputSection>("", 0, SHF_ALLOC);
+ Out::ElfHeader->Size = sizeof(typename ELFT::Ehdr);
+
+ // Create wrapped symbols for -wrap option.
+ std::vector<WrappedSymbol> Wrapped = addWrappedSymbols<ELFT>(Args);
+
+ // We need to create some reserved symbols such as _end. Create them.
+ if (!Config->Relocatable)
+ addReservedSymbols();
+
+ // Apply version scripts.
+ //
+ // For a relocatable output, version scripts don't make sense, and
+ // parsing a symbol version string (e.g. dropping "@ver1" from a symbol
+ // name "foo@ver1") rather do harm, so we don't call this if -r is given.
+ if (!Config->Relocatable)
+ Symtab->scanVersionScript();
+
+ // Do link-time optimization if given files are LLVM bitcode files.
+ // This compiles bitcode files into real object files.
+ //
+ // With this the symbol table should be complete. After this, no new names
+ // except a few linker-synthesized ones will be added to the symbol table.
+ Symtab->addCombinedLTOObject<ELFT>();
+ if (errorCount())
+ return;
+
+ // If -thinlto-index-only is given, we should create only "index
+ // files" and not object files. Index file creation is already done
+ // in addCombinedLTOObject, so we are done if that's the case.
+ if (Config->ThinLTOIndexOnly)
+ return;
+
+ // Likewise, --plugin-opt=emit-llvm is an option to make LTO create
+ // an output file in bitcode and exit, so that you can just get a
+ // combined bitcode file.
+ if (Config->EmitLLVM)
+ return;
+
+ // Apply symbol renames for -wrap.
+ if (!Wrapped.empty())
+ wrapSymbols<ELFT>(Wrapped);
+
+ // Now that we have a complete list of input files.
+ // Beyond this point, no new files are added.
+ // Aggregate all input sections into one place.
+ for (InputFile *F : ObjectFiles)
+ for (InputSectionBase *S : F->getSections())
+ if (S && S != &InputSection::Discarded)
+ InputSections.push_back(S);
+ for (BinaryFile *F : BinaryFiles)
+ for (InputSectionBase *S : F->getSections())
+ InputSections.push_back(cast<InputSection>(S));
+
+ // We do not want to emit debug sections if --strip-all
+ // or -strip-debug are given.
+ if (Config->Strip != StripPolicy::None)
+ llvm::erase_if(InputSections, [](InputSectionBase *S) {
+ return S->Name.startswith(".debug") || S->Name.startswith(".zdebug");
+ });
+
+ Config->EFlags = Target->calcEFlags();
+
+ if (Config->EMachine == EM_ARM) {
+ // FIXME: These warnings can be removed when lld only uses these features
+ // when the input objects have been compiled with an architecture that
+ // supports them.
+ if (Config->ARMHasBlx == false)
+ warn("lld uses blx instruction, no object with architecture supporting "
+ "feature detected");
+ }
+
+ // This adds a .comment section containing a version string. We have to add it
+ // before mergeSections because the .comment section is a mergeable section.
+ if (!Config->Relocatable)
+ InputSections.push_back(createCommentSection());
+
+ // Do size optimizations: garbage collection, merging of SHF_MERGE sections
+ // and identical code folding.
+ splitSections<ELFT>();
+ markLive<ELFT>();
+ demoteSharedSymbols<ELFT>();
+ mergeSections();
+ if (Config->ICF != ICFLevel::None) {
+ findKeepUniqueSections<ELFT>(Args);
+ doIcf<ELFT>();
+ }
+
+ // Read the callgraph now that we know what was gced or icfed
+ if (Config->CallGraphProfileSort) {
+ if (auto *Arg = Args.getLastArg(OPT_call_graph_ordering_file))
+ if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
+ readCallGraph(*Buffer);
+ readCallGraphsFromObjectFiles<ELFT>();
+ }
+
+ // Write the result to the file.
+ writeResult<ELFT>();
+}
diff --git a/contrib/llvm/tools/lld/ELF/Driver.h b/contrib/llvm/tools/lld/ELF/Driver.h
new file mode 100644
index 000000000000..81d7f608e588
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Driver.h
@@ -0,0 +1,73 @@
+//===- Driver.h -------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_DRIVER_H
+#define LLD_ELF_DRIVER_H
+
+#include "SymbolTable.h"
+#include "lld/Common/LLVM.h"
+#include "lld/Common/Reproduce.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace lld {
+namespace elf {
+
+extern class LinkerDriver *Driver;
+
+class LinkerDriver {
+public:
+ void main(ArrayRef<const char *> Args);
+ void addFile(StringRef Path, bool WithLOption);
+ void addLibrary(StringRef Name);
+
+private:
+ void readConfigs(llvm::opt::InputArgList &Args);
+ void createFiles(llvm::opt::InputArgList &Args);
+ void inferMachineType();
+ template <class ELFT> void link(llvm::opt::InputArgList &Args);
+
+ // True if we are in --whole-archive and --no-whole-archive.
+ bool InWholeArchive = false;
+
+ // True if we are in --start-lib and --end-lib.
+ bool InLib = false;
+
+ std::vector<InputFile *> Files;
+};
+
+// Parses command line options.
+class ELFOptTable : public llvm::opt::OptTable {
+public:
+ ELFOptTable();
+ llvm::opt::InputArgList parse(ArrayRef<const char *> Argv);
+};
+
+// Create enum with OPT_xxx values for each option in Options.td
+enum {
+ OPT_INVALID = 0,
+#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID,
+#include "Options.inc"
+#undef OPTION
+};
+
+void printHelp();
+std::string createResponseFile(const llvm::opt::InputArgList &Args);
+
+llvm::Optional<std::string> findFromSearchPaths(StringRef Path);
+llvm::Optional<std::string> searchScript(StringRef Path);
+llvm::Optional<std::string> searchLibrary(StringRef Path);
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/ELF/DriverUtils.cpp b/contrib/llvm/tools/lld/ELF/DriverUtils.cpp
new file mode 100644
index 000000000000..e51d02e38da1
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/DriverUtils.cpp
@@ -0,0 +1,238 @@
+//===- DriverUtils.cpp ----------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains utility functions for the driver. Because there
+// are so many small functions, we created this separate file to make
+// Driver.cpp less cluttered.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Driver.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Memory.h"
+#include "lld/Common/Reproduce.h"
+#include "lld/Common/Version.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
+
+using namespace llvm;
+using namespace llvm::sys;
+using namespace llvm::opt;
+
+using namespace lld;
+using namespace lld::elf;
+
+// Create OptTable
+
+// Create prefix string literals used in Options.td
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#include "Options.inc"
+#undef PREFIX
+
+// Create table mapping all options defined in Options.td
+static const opt::OptTable::Info OptInfo[] = {
+#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \
+ {X1, X2, X10, X11, OPT_##ID, opt::Option::KIND##Class, \
+ X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12},
+#include "Options.inc"
+#undef OPTION
+};
+
+ELFOptTable::ELFOptTable() : OptTable(OptInfo) {}
+
+// Set color diagnostics according to -color-diagnostics={auto,always,never}
+// or -no-color-diagnostics flags.
+static void handleColorDiagnostics(opt::InputArgList &Args) {
+ auto *Arg = Args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq,
+ OPT_no_color_diagnostics);
+ if (!Arg)
+ return;
+ if (Arg->getOption().getID() == OPT_color_diagnostics) {
+ errorHandler().ColorDiagnostics = true;
+ } else if (Arg->getOption().getID() == OPT_no_color_diagnostics) {
+ errorHandler().ColorDiagnostics = false;
+ } else {
+ StringRef S = Arg->getValue();
+ if (S == "always")
+ errorHandler().ColorDiagnostics = true;
+ else if (S == "never")
+ errorHandler().ColorDiagnostics = false;
+ else if (S != "auto")
+ error("unknown option: --color-diagnostics=" + S);
+ }
+}
+
+static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &Args) {
+ if (auto *Arg = Args.getLastArg(OPT_rsp_quoting)) {
+ StringRef S = Arg->getValue();
+ if (S != "windows" && S != "posix")
+ error("invalid response file quoting: " + S);
+ if (S == "windows")
+ return cl::TokenizeWindowsCommandLine;
+ return cl::TokenizeGNUCommandLine;
+ }
+ if (Triple(sys::getProcessTriple()).getOS() == Triple::Win32)
+ return cl::TokenizeWindowsCommandLine;
+ return cl::TokenizeGNUCommandLine;
+}
+
+// Gold LTO plugin takes a `--plugin-opt foo=bar` option as an alias for
+// `--plugin-opt=foo=bar`. We want to handle `--plugin-opt=foo=` as an
+// option name and `bar` as a value. Unfortunately, OptParser cannot
+// handle an option with a space in it.
+//
+// In this function, we concatenate command line arguments so that
+// `--plugin-opt <foo>` is converted to `--plugin-opt=<foo>`. This is a
+// bit hacky, but looks like it is still better than handling --plugin-opt
+// options by hand.
+static void concatLTOPluginOptions(SmallVectorImpl<const char *> &Args) {
+ SmallVector<const char *, 256> V;
+ for (size_t I = 0, E = Args.size(); I != E; ++I) {
+ StringRef S = Args[I];
+ if ((S == "-plugin-opt" || S == "--plugin-opt") && I + 1 != E) {
+ V.push_back(Saver.save(S + "=" + Args[I + 1]).data());
+ ++I;
+ } else {
+ V.push_back(Args[I]);
+ }
+ }
+ Args = std::move(V);
+}
+
+// Parses a given list of options.
+opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> Argv) {
+ // Make InputArgList from string vectors.
+ unsigned MissingIndex;
+ unsigned MissingCount;
+ SmallVector<const char *, 256> Vec(Argv.data(), Argv.data() + Argv.size());
+
+ // We need to get the quoting style for response files before parsing all
+ // options so we parse here before and ignore all the options but
+ // --rsp-quoting.
+ opt::InputArgList Args = this->ParseArgs(Vec, MissingIndex, MissingCount);
+
+ // Expand response files (arguments in the form of @<filename>)
+ // and then parse the argument again.
+ cl::ExpandResponseFiles(Saver, getQuotingStyle(Args), Vec);
+ concatLTOPluginOptions(Vec);
+ Args = this->ParseArgs(Vec, MissingIndex, MissingCount);
+
+ handleColorDiagnostics(Args);
+ if (MissingCount)
+ error(Twine(Args.getArgString(MissingIndex)) + ": missing argument");
+
+ for (auto *Arg : Args.filtered(OPT_UNKNOWN))
+ error("unknown argument: " + Arg->getSpelling());
+ return Args;
+}
+
+void elf::printHelp() {
+ ELFOptTable().PrintHelp(
+ outs(), (Config->ProgName + " [options] file...").str().c_str(), "lld",
+ false /*ShowHidden*/, true /*ShowAllAliases*/);
+ outs() << "\n";
+
+ // Scripts generated by Libtool versions up to at least 2.4.6 (the most
+ // recent version as of March 2017) expect /: supported targets:.* elf/
+ // in a message for the -help option. If it doesn't match, the scripts
+ // assume that the linker doesn't support very basic features such as
+ // shared libraries. Therefore, we need to print out at least "elf".
+ outs() << Config->ProgName << ": supported targets: elf\n";
+}
+
+// Reconstructs command line arguments so that so that you can re-run
+// the same command with the same inputs. This is for --reproduce.
+std::string elf::createResponseFile(const opt::InputArgList &Args) {
+ SmallString<0> Data;
+ raw_svector_ostream OS(Data);
+ OS << "--chroot .\n";
+
+ // Copy the command line to the output while rewriting paths.
+ for (auto *Arg : Args) {
+ switch (Arg->getOption().getUnaliasedOption().getID()) {
+ case OPT_reproduce:
+ break;
+ case OPT_INPUT:
+ OS << quote(rewritePath(Arg->getValue())) << "\n";
+ break;
+ case OPT_o:
+ // If -o path contains directories, "lld @response.txt" will likely
+ // fail because the archive we are creating doesn't contain empty
+ // directories for the output path (-o doesn't create directories).
+ // Strip directories to prevent the issue.
+ OS << "-o " << quote(sys::path::filename(Arg->getValue())) << "\n";
+ break;
+ case OPT_dynamic_list:
+ case OPT_library_path:
+ case OPT_rpath:
+ case OPT_script:
+ case OPT_symbol_ordering_file:
+ case OPT_sysroot:
+ case OPT_version_script:
+ OS << Arg->getSpelling() << " " << quote(rewritePath(Arg->getValue()))
+ << "\n";
+ break;
+ default:
+ OS << toString(*Arg) << "\n";
+ }
+ }
+ return Data.str();
+}
+
+// Find a file by concatenating given paths. If a resulting path
+// starts with "=", the character is replaced with a --sysroot value.
+static Optional<std::string> findFile(StringRef Path1, const Twine &Path2) {
+ SmallString<128> S;
+ if (Path1.startswith("="))
+ path::append(S, Config->Sysroot, Path1.substr(1), Path2);
+ else
+ path::append(S, Path1, Path2);
+
+ if (fs::exists(S))
+ return S.str().str();
+ return None;
+}
+
+Optional<std::string> elf::findFromSearchPaths(StringRef Path) {
+ for (StringRef Dir : Config->SearchPaths)
+ if (Optional<std::string> S = findFile(Dir, Path))
+ return S;
+ return None;
+}
+
+// This is for -lfoo. We'll look for libfoo.so or libfoo.a from
+// search paths.
+Optional<std::string> elf::searchLibrary(StringRef Name) {
+ if (Name.startswith(":"))
+ return findFromSearchPaths(Name.substr(1));
+
+ for (StringRef Dir : Config->SearchPaths) {
+ if (!Config->Static)
+ if (Optional<std::string> S = findFile(Dir, "lib" + Name + ".so"))
+ return S;
+ if (Optional<std::string> S = findFile(Dir, "lib" + Name + ".a"))
+ return S;
+ }
+ return None;
+}
+
+// If a linker/version script doesn't exist in the current directory, we also
+// look for the script in the '-L' search paths. This matches the behaviour of
+// '-T', --version-script=, and linker script INPUT() command in ld.bfd.
+Optional<std::string> elf::searchScript(StringRef Name) {
+ if (fs::exists(Name))
+ return Name.str();
+ return findFromSearchPaths(Name);
+}
diff --git a/contrib/llvm/tools/lld/ELF/EhFrame.cpp b/contrib/llvm/tools/lld/ELF/EhFrame.cpp
new file mode 100644
index 000000000000..95d444bdc2a1
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/EhFrame.cpp
@@ -0,0 +1,198 @@
+//===- EhFrame.cpp -------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// .eh_frame section contains information on how to unwind the stack when
+// an exception is thrown. The section consists of sequence of CIE and FDE
+// records. The linker needs to merge CIEs and associate FDEs to CIEs.
+// That means the linker has to understand the format of the section.
+//
+// This file contains a few utility functions to read .eh_frame contents.
+//
+//===----------------------------------------------------------------------===//
+
+#include "EhFrame.h"
+#include "Config.h"
+#include "InputSection.h"
+#include "Relocations.h"
+#include "Target.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Strings.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/Object/ELF.h"
+
+using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::dwarf;
+using namespace llvm::object;
+
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+class EhReader {
+public:
+ EhReader(InputSectionBase *S, ArrayRef<uint8_t> D) : IS(S), D(D) {}
+ size_t readEhRecordSize();
+ uint8_t getFdeEncoding();
+
+private:
+ template <class P> void failOn(const P *Loc, const Twine &Msg) {
+ fatal("corrupted .eh_frame: " + Msg + "\n>>> defined in " +
+ IS->getObjMsg((const uint8_t *)Loc - IS->data().data()));
+ }
+
+ uint8_t readByte();
+ void skipBytes(size_t Count);
+ StringRef readString();
+ void skipLeb128();
+ void skipAugP();
+
+ InputSectionBase *IS;
+ ArrayRef<uint8_t> D;
+};
+}
+
+size_t elf::readEhRecordSize(InputSectionBase *S, size_t Off) {
+ return EhReader(S, S->data().slice(Off)).readEhRecordSize();
+}
+
+// .eh_frame section is a sequence of records. Each record starts with
+// a 4 byte length field. This function reads the length.
+size_t EhReader::readEhRecordSize() {
+ if (D.size() < 4)
+ failOn(D.data(), "CIE/FDE too small");
+
+ // First 4 bytes of CIE/FDE is the size of the record.
+ // If it is 0xFFFFFFFF, the next 8 bytes contain the size instead,
+ // but we do not support that format yet.
+ uint64_t V = read32(D.data());
+ if (V == UINT32_MAX)
+ failOn(D.data(), "CIE/FDE too large");
+ uint64_t Size = V + 4;
+ if (Size > D.size())
+ failOn(D.data(), "CIE/FDE ends past the end of the section");
+ return Size;
+}
+
+// Read a byte and advance D by one byte.
+uint8_t EhReader::readByte() {
+ if (D.empty())
+ failOn(D.data(), "unexpected end of CIE");
+ uint8_t B = D.front();
+ D = D.slice(1);
+ return B;
+}
+
+void EhReader::skipBytes(size_t Count) {
+ if (D.size() < Count)
+ failOn(D.data(), "CIE is too small");
+ D = D.slice(Count);
+}
+
+// Read a null-terminated string.
+StringRef EhReader::readString() {
+ const uint8_t *End = std::find(D.begin(), D.end(), '\0');
+ if (End == D.end())
+ failOn(D.data(), "corrupted CIE (failed to read string)");
+ StringRef S = toStringRef(D.slice(0, End - D.begin()));
+ D = D.slice(S.size() + 1);
+ return S;
+}
+
+// Skip an integer encoded in the LEB128 format.
+// Actual number is not of interest because only the runtime needs it.
+// But we need to be at least able to skip it so that we can read
+// the field that follows a LEB128 number.
+void EhReader::skipLeb128() {
+ const uint8_t *ErrPos = D.data();
+ while (!D.empty()) {
+ uint8_t Val = D.front();
+ D = D.slice(1);
+ if ((Val & 0x80) == 0)
+ return;
+ }
+ failOn(ErrPos, "corrupted CIE (failed to read LEB128)");
+}
+
+static size_t getAugPSize(unsigned Enc) {
+ switch (Enc & 0x0f) {
+ case DW_EH_PE_absptr:
+ case DW_EH_PE_signed:
+ return Config->Wordsize;
+ case DW_EH_PE_udata2:
+ case DW_EH_PE_sdata2:
+ return 2;
+ case DW_EH_PE_udata4:
+ case DW_EH_PE_sdata4:
+ return 4;
+ case DW_EH_PE_udata8:
+ case DW_EH_PE_sdata8:
+ return 8;
+ }
+ return 0;
+}
+
+void EhReader::skipAugP() {
+ uint8_t Enc = readByte();
+ if ((Enc & 0xf0) == DW_EH_PE_aligned)
+ failOn(D.data() - 1, "DW_EH_PE_aligned encoding is not supported");
+ size_t Size = getAugPSize(Enc);
+ if (Size == 0)
+ failOn(D.data() - 1, "unknown FDE encoding");
+ if (Size >= D.size())
+ failOn(D.data() - 1, "corrupted CIE");
+ D = D.slice(Size);
+}
+
+uint8_t elf::getFdeEncoding(EhSectionPiece *P) {
+ return EhReader(P->Sec, P->data()).getFdeEncoding();
+}
+
+uint8_t EhReader::getFdeEncoding() {
+ skipBytes(8);
+ int Version = readByte();
+ if (Version != 1 && Version != 3)
+ failOn(D.data() - 1,
+ "FDE version 1 or 3 expected, but got " + Twine(Version));
+
+ StringRef Aug = readString();
+
+ // Skip code and data alignment factors.
+ skipLeb128();
+ skipLeb128();
+
+ // Skip the return address register. In CIE version 1 this is a single
+ // byte. In CIE version 3 this is an unsigned LEB128.
+ if (Version == 1)
+ readByte();
+ else
+ skipLeb128();
+
+ // We only care about an 'R' value, but other records may precede an 'R'
+ // record. Unfortunately records are not in TLV (type-length-value) format,
+ // so we need to teach the linker how to skip records for each type.
+ for (char C : Aug) {
+ if (C == 'R')
+ return readByte();
+ if (C == 'z') {
+ skipLeb128();
+ continue;
+ }
+ if (C == 'P') {
+ skipAugP();
+ continue;
+ }
+ if (C == 'L') {
+ readByte();
+ continue;
+ }
+ failOn(Aug.data(), "unknown .eh_frame augmentation string: " + Aug);
+ }
+ return DW_EH_PE_absptr;
+}
diff --git a/contrib/llvm/tools/lld/ELF/EhFrame.h b/contrib/llvm/tools/lld/ELF/EhFrame.h
new file mode 100644
index 000000000000..5112891a911e
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/EhFrame.h
@@ -0,0 +1,25 @@
+//===- EhFrame.h ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_EHFRAME_H
+#define LLD_ELF_EHFRAME_H
+
+#include "lld/Common/LLVM.h"
+
+namespace lld {
+namespace elf {
+class InputSectionBase;
+struct EhSectionPiece;
+
+size_t readEhRecordSize(InputSectionBase *S, size_t Off);
+uint8_t getFdeEncoding(EhSectionPiece *P);
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/ELF/Filesystem.cpp b/contrib/llvm/tools/lld/ELF/Filesystem.cpp
new file mode 100644
index 000000000000..5cf240eeca56
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Filesystem.cpp
@@ -0,0 +1,86 @@
+//===- Filesystem.cpp -----------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains a few utility functions to handle files.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Filesystem.h"
+#include "Config.h"
+#include "lld/Common/Threads.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/FileSystem.h"
+#if LLVM_ON_UNIX
+#include <unistd.h>
+#endif
+#include <thread>
+
+using namespace llvm;
+
+using namespace lld;
+using namespace lld::elf;
+
+// Removes a given file asynchronously. This is a performance hack,
+// so remove this when operating systems are improved.
+//
+// On Linux (and probably on other Unix-like systems), unlink(2) is a
+// noticeably slow system call. As of 2016, unlink takes 250
+// milliseconds to remove a 1 GB file on ext4 filesystem on my machine.
+//
+// To create a new result file, we first remove existing file. So, if
+// you repeatedly link a 1 GB program in a regular compile-link-debug
+// cycle, every cycle wastes 250 milliseconds only to remove a file.
+// Since LLD can link a 1 GB binary in about 5 seconds, that waste
+// actually counts.
+//
+// This function spawns a background thread to remove the file.
+// The calling thread returns almost immediately.
+void elf::unlinkAsync(StringRef Path) {
+// Removing a file is async on windows.
+#if defined(_WIN32)
+ sys::fs::remove(Path);
+#else
+ if (!ThreadsEnabled || !sys::fs::exists(Path) ||
+ !sys::fs::is_regular_file(Path))
+ return;
+
+ // We cannot just remove path from a different thread because we are now going
+ // to create path as a new file.
+ // Instead we open the file and unlink it on this thread. The unlink is fast
+ // since the open fd guarantees that it is not removing the last reference.
+ int FD;
+ std::error_code EC = sys::fs::openFileForRead(Path, FD);
+ sys::fs::remove(Path);
+
+ // close and therefore remove TempPath in background.
+ if (!EC)
+ std::thread([=] { ::close(FD); }).detach();
+#endif
+}
+
+// Simulate file creation to see if Path is writable.
+//
+// Determining whether a file is writable or not is amazingly hard,
+// and after all the only reliable way of doing that is to actually
+// create a file. But we don't want to do that in this function
+// because LLD shouldn't update any file if it will end in a failure.
+// We also don't want to reimplement heuristics to determine if a
+// file is writable. So we'll let FileOutputBuffer do the work.
+//
+// FileOutputBuffer doesn't touch a desitnation file until commit()
+// is called. We use that class without calling commit() to predict
+// if the given file is writable.
+std::error_code elf::tryCreateFile(StringRef Path) {
+ if (Path.empty())
+ return std::error_code();
+ if (Path == "-")
+ return std::error_code();
+ return errorToErrorCode(FileOutputBuffer::create(Path, 1).takeError());
+}
diff --git a/contrib/llvm/tools/lld/ELF/Filesystem.h b/contrib/llvm/tools/lld/ELF/Filesystem.h
new file mode 100644
index 000000000000..987a74a6bcb6
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Filesystem.h
@@ -0,0 +1,23 @@
+//===- Filesystem.h ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_FILESYSTEM_H
+#define LLD_ELF_FILESYSTEM_H
+
+#include "lld/Common/LLVM.h"
+#include <system_error>
+
+namespace lld {
+namespace elf {
+void unlinkAsync(StringRef Path);
+std::error_code tryCreateFile(StringRef Path);
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/ELF/ICF.cpp b/contrib/llvm/tools/lld/ELF/ICF.cpp
new file mode 100644
index 000000000000..d08ac73ded80
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/ICF.cpp
@@ -0,0 +1,512 @@
+//===- ICF.cpp ------------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// ICF is short for Identical Code Folding. This is a size optimization to
+// identify and merge two or more read-only sections (typically functions)
+// that happened to have the same contents. It usually reduces output size
+// by a few percent.
+//
+// In ICF, two sections are considered identical if they have the same
+// section flags, section data, and relocations. Relocations are tricky,
+// because two relocations are considered the same if they have the same
+// relocation types, values, and if they point to the same sections *in
+// terms of ICF*.
+//
+// Here is an example. If foo and bar defined below are compiled to the
+// same machine instructions, ICF can and should merge the two, although
+// their relocations point to each other.
+//
+// void foo() { bar(); }
+// void bar() { foo(); }
+//
+// If you merge the two, their relocations point to the same section and
+// thus you know they are mergeable, but how do you know they are
+// mergeable in the first place? This is not an easy problem to solve.
+//
+// What we are doing in LLD is to partition sections into equivalence
+// classes. Sections in the same equivalence class when the algorithm
+// terminates are considered identical. Here are details:
+//
+// 1. First, we partition sections using their hash values as keys. Hash
+// values contain section types, section contents and numbers of
+// relocations. During this step, relocation targets are not taken into
+// account. We just put sections that apparently differ into different
+// equivalence classes.
+//
+// 2. Next, for each equivalence class, we visit sections to compare
+// relocation targets. Relocation targets are considered equivalent if
+// their targets are in the same equivalence class. Sections with
+// different relocation targets are put into different equivalence
+// clases.
+//
+// 3. If we split an equivalence class in step 2, two relocations
+// previously target the same equivalence class may now target
+// different equivalence classes. Therefore, we repeat step 2 until a
+// convergence is obtained.
+//
+// 4. For each equivalence class C, pick an arbitrary section in C, and
+// merge all the other sections in C with it.
+//
+// For small programs, this algorithm needs 3-5 iterations. For large
+// programs such as Chromium, it takes more than 20 iterations.
+//
+// This algorithm was mentioned as an "optimistic algorithm" in [1],
+// though gold implements a different algorithm than this.
+//
+// We parallelize each step so that multiple threads can work on different
+// equivalence classes concurrently. That gave us a large performance
+// boost when applying ICF on large programs. For example, MSVC link.exe
+// or GNU gold takes 10-20 seconds to apply ICF on Chromium, whose output
+// size is about 1.5 GB, but LLD can finish it in less than 2 seconds on a
+// 2.8 GHz 40 core machine. Even without threading, LLD's ICF is still
+// faster than MSVC or gold though.
+//
+// [1] Safe ICF: Pointer Safe and Unwinding aware Identical Code Folding
+// in the Gold Linker
+// http://static.googleusercontent.com/media/research.google.com/en//pubs/archive/36912.pdf
+//
+//===----------------------------------------------------------------------===//
+
+#include "ICF.h"
+#include "Config.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "Writer.h"
+#include "lld/Common/Threads.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/xxhash.h"
+#include <algorithm>
+#include <atomic>
+
+using namespace lld;
+using namespace lld::elf;
+using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::object;
+
+namespace {
+template <class ELFT> class ICF {
+public:
+ void run();
+
+private:
+ void segregate(size_t Begin, size_t End, bool Constant);
+
+ template <class RelTy>
+ bool constantEq(const InputSection *A, ArrayRef<RelTy> RelsA,
+ const InputSection *B, ArrayRef<RelTy> RelsB);
+
+ template <class RelTy>
+ bool variableEq(const InputSection *A, ArrayRef<RelTy> RelsA,
+ const InputSection *B, ArrayRef<RelTy> RelsB);
+
+ bool equalsConstant(const InputSection *A, const InputSection *B);
+ bool equalsVariable(const InputSection *A, const InputSection *B);
+
+ size_t findBoundary(size_t Begin, size_t End);
+
+ void forEachClassRange(size_t Begin, size_t End,
+ llvm::function_ref<void(size_t, size_t)> Fn);
+
+ void forEachClass(llvm::function_ref<void(size_t, size_t)> Fn);
+
+ std::vector<InputSection *> Sections;
+
+ // We repeat the main loop while `Repeat` is true.
+ std::atomic<bool> Repeat;
+
+ // The main loop counter.
+ int Cnt = 0;
+
+ // We have two locations for equivalence classes. On the first iteration
+ // of the main loop, Class[0] has a valid value, and Class[1] contains
+ // garbage. We read equivalence classes from slot 0 and write to slot 1.
+ // So, Class[0] represents the current class, and Class[1] represents
+ // the next class. On each iteration, we switch their roles and use them
+ // alternately.
+ //
+ // Why are we doing this? Recall that other threads may be working on
+ // other equivalence classes in parallel. They may read sections that we
+ // are updating. We cannot update equivalence classes in place because
+ // it breaks the invariance that all possibly-identical sections must be
+ // in the same equivalence class at any moment. In other words, the for
+ // loop to update equivalence classes is not atomic, and that is
+ // observable from other threads. By writing new classes to other
+ // places, we can keep the invariance.
+ //
+ // Below, `Current` has the index of the current class, and `Next` has
+ // the index of the next class. If threading is enabled, they are either
+ // (0, 1) or (1, 0).
+ //
+ // Note on single-thread: if that's the case, they are always (0, 0)
+ // because we can safely read the next class without worrying about race
+ // conditions. Using the same location makes this algorithm converge
+ // faster because it uses results of the same iteration earlier.
+ int Current = 0;
+ int Next = 0;
+};
+}
+
+// Returns true if section S is subject of ICF.
+static bool isEligible(InputSection *S) {
+ if (!S->Live || S->KeepUnique || !(S->Flags & SHF_ALLOC))
+ return false;
+
+ // Don't merge writable sections. .data.rel.ro sections are marked as writable
+ // but are semantically read-only.
+ if ((S->Flags & SHF_WRITE) && S->Name != ".data.rel.ro" &&
+ !S->Name.startswith(".data.rel.ro."))
+ return false;
+
+ // SHF_LINK_ORDER sections are ICF'd as a unit with their dependent sections,
+ // so we don't consider them for ICF individually.
+ if (S->Flags & SHF_LINK_ORDER)
+ return false;
+
+ // Don't merge synthetic sections as their Data member is not valid and empty.
+ // The Data member needs to be valid for ICF as it is used by ICF to determine
+ // the equality of section contents.
+ if (isa<SyntheticSection>(S))
+ return false;
+
+ // .init and .fini contains instructions that must be executed to initialize
+ // and finalize the process. They cannot and should not be merged.
+ if (S->Name == ".init" || S->Name == ".fini")
+ return false;
+
+ // A user program may enumerate sections named with a C identifier using
+ // __start_* and __stop_* symbols. We cannot ICF any such sections because
+ // that could change program semantics.
+ if (isValidCIdentifier(S->Name))
+ return false;
+
+ return true;
+}
+
+// Split an equivalence class into smaller classes.
+template <class ELFT>
+void ICF<ELFT>::segregate(size_t Begin, size_t End, bool Constant) {
+ // This loop rearranges sections in [Begin, End) so that all sections
+ // that are equal in terms of equals{Constant,Variable} are contiguous
+ // in [Begin, End).
+ //
+ // The algorithm is quadratic in the worst case, but that is not an
+ // issue in practice because the number of the distinct sections in
+ // each range is usually very small.
+
+ while (Begin < End) {
+ // Divide [Begin, End) into two. Let Mid be the start index of the
+ // second group.
+ auto Bound =
+ std::stable_partition(Sections.begin() + Begin + 1,
+ Sections.begin() + End, [&](InputSection *S) {
+ if (Constant)
+ return equalsConstant(Sections[Begin], S);
+ return equalsVariable(Sections[Begin], S);
+ });
+ size_t Mid = Bound - Sections.begin();
+
+ // Now we split [Begin, End) into [Begin, Mid) and [Mid, End) by
+ // updating the sections in [Begin, Mid). We use Mid as an equivalence
+ // class ID because every group ends with a unique index.
+ for (size_t I = Begin; I < Mid; ++I)
+ Sections[I]->Class[Next] = Mid;
+
+ // If we created a group, we need to iterate the main loop again.
+ if (Mid != End)
+ Repeat = true;
+
+ Begin = Mid;
+ }
+}
+
+// Compare two lists of relocations.
+template <class ELFT>
+template <class RelTy>
+bool ICF<ELFT>::constantEq(const InputSection *SecA, ArrayRef<RelTy> RA,
+ const InputSection *SecB, ArrayRef<RelTy> RB) {
+ for (size_t I = 0; I < RA.size(); ++I) {
+ if (RA[I].r_offset != RB[I].r_offset ||
+ RA[I].getType(Config->IsMips64EL) != RB[I].getType(Config->IsMips64EL))
+ return false;
+
+ uint64_t AddA = getAddend<ELFT>(RA[I]);
+ uint64_t AddB = getAddend<ELFT>(RB[I]);
+
+ Symbol &SA = SecA->template getFile<ELFT>()->getRelocTargetSym(RA[I]);
+ Symbol &SB = SecB->template getFile<ELFT>()->getRelocTargetSym(RB[I]);
+ if (&SA == &SB) {
+ if (AddA == AddB)
+ continue;
+ return false;
+ }
+
+ auto *DA = dyn_cast<Defined>(&SA);
+ auto *DB = dyn_cast<Defined>(&SB);
+
+ // Placeholder symbols generated by linker scripts look the same now but
+ // may have different values later.
+ if (!DA || !DB || DA->ScriptDefined || DB->ScriptDefined)
+ return false;
+
+ // Relocations referring to absolute symbols are constant-equal if their
+ // values are equal.
+ if (!DA->Section && !DB->Section && DA->Value + AddA == DB->Value + AddB)
+ continue;
+ if (!DA->Section || !DB->Section)
+ return false;
+
+ if (DA->Section->kind() != DB->Section->kind())
+ return false;
+
+ // Relocations referring to InputSections are constant-equal if their
+ // section offsets are equal.
+ if (isa<InputSection>(DA->Section)) {
+ if (DA->Value + AddA == DB->Value + AddB)
+ continue;
+ return false;
+ }
+
+ // Relocations referring to MergeInputSections are constant-equal if their
+ // offsets in the output section are equal.
+ auto *X = dyn_cast<MergeInputSection>(DA->Section);
+ if (!X)
+ return false;
+ auto *Y = cast<MergeInputSection>(DB->Section);
+ if (X->getParent() != Y->getParent())
+ return false;
+
+ uint64_t OffsetA =
+ SA.isSection() ? X->getOffset(AddA) : X->getOffset(DA->Value) + AddA;
+ uint64_t OffsetB =
+ SB.isSection() ? Y->getOffset(AddB) : Y->getOffset(DB->Value) + AddB;
+ if (OffsetA != OffsetB)
+ return false;
+ }
+
+ return true;
+}
+
+// Compare "non-moving" part of two InputSections, namely everything
+// except relocation targets.
+template <class ELFT>
+bool ICF<ELFT>::equalsConstant(const InputSection *A, const InputSection *B) {
+ if (A->NumRelocations != B->NumRelocations || A->Flags != B->Flags ||
+ A->getSize() != B->getSize() || A->data() != B->data())
+ return false;
+
+ // If two sections have different output sections, we cannot merge them.
+ // FIXME: This doesn't do the right thing in the case where there is a linker
+ // script. We probably need to move output section assignment before ICF to
+ // get the correct behaviour here.
+ if (getOutputSectionName(A) != getOutputSectionName(B))
+ return false;
+
+ if (A->AreRelocsRela)
+ return constantEq(A, A->template relas<ELFT>(), B,
+ B->template relas<ELFT>());
+ return constantEq(A, A->template rels<ELFT>(), B, B->template rels<ELFT>());
+}
+
+// Compare two lists of relocations. Returns true if all pairs of
+// relocations point to the same section in terms of ICF.
+template <class ELFT>
+template <class RelTy>
+bool ICF<ELFT>::variableEq(const InputSection *SecA, ArrayRef<RelTy> RA,
+ const InputSection *SecB, ArrayRef<RelTy> RB) {
+ assert(RA.size() == RB.size());
+
+ for (size_t I = 0; I < RA.size(); ++I) {
+ // The two sections must be identical.
+ Symbol &SA = SecA->template getFile<ELFT>()->getRelocTargetSym(RA[I]);
+ Symbol &SB = SecB->template getFile<ELFT>()->getRelocTargetSym(RB[I]);
+ if (&SA == &SB)
+ continue;
+
+ auto *DA = cast<Defined>(&SA);
+ auto *DB = cast<Defined>(&SB);
+
+ // We already dealt with absolute and non-InputSection symbols in
+ // constantEq, and for InputSections we have already checked everything
+ // except the equivalence class.
+ if (!DA->Section)
+ continue;
+ auto *X = dyn_cast<InputSection>(DA->Section);
+ if (!X)
+ continue;
+ auto *Y = cast<InputSection>(DB->Section);
+
+ // Ineligible sections are in the special equivalence class 0.
+ // They can never be the same in terms of the equivalence class.
+ if (X->Class[Current] == 0)
+ return false;
+ if (X->Class[Current] != Y->Class[Current])
+ return false;
+ };
+
+ return true;
+}
+
+// Compare "moving" part of two InputSections, namely relocation targets.
+template <class ELFT>
+bool ICF<ELFT>::equalsVariable(const InputSection *A, const InputSection *B) {
+ if (A->AreRelocsRela)
+ return variableEq(A, A->template relas<ELFT>(), B,
+ B->template relas<ELFT>());
+ return variableEq(A, A->template rels<ELFT>(), B, B->template rels<ELFT>());
+}
+
+template <class ELFT> size_t ICF<ELFT>::findBoundary(size_t Begin, size_t End) {
+ uint32_t Class = Sections[Begin]->Class[Current];
+ for (size_t I = Begin + 1; I < End; ++I)
+ if (Class != Sections[I]->Class[Current])
+ return I;
+ return End;
+}
+
+// Sections in the same equivalence class are contiguous in Sections
+// vector. Therefore, Sections vector can be considered as contiguous
+// groups of sections, grouped by the class.
+//
+// This function calls Fn on every group within [Begin, End).
+template <class ELFT>
+void ICF<ELFT>::forEachClassRange(size_t Begin, size_t End,
+ llvm::function_ref<void(size_t, size_t)> Fn) {
+ while (Begin < End) {
+ size_t Mid = findBoundary(Begin, End);
+ Fn(Begin, Mid);
+ Begin = Mid;
+ }
+}
+
+// Call Fn on each equivalence class.
+template <class ELFT>
+void ICF<ELFT>::forEachClass(llvm::function_ref<void(size_t, size_t)> Fn) {
+ // If threading is disabled or the number of sections are
+ // too small to use threading, call Fn sequentially.
+ if (!ThreadsEnabled || Sections.size() < 1024) {
+ forEachClassRange(0, Sections.size(), Fn);
+ ++Cnt;
+ return;
+ }
+
+ Current = Cnt % 2;
+ Next = (Cnt + 1) % 2;
+
+ // Shard into non-overlapping intervals, and call Fn in parallel.
+ // The sharding must be completed before any calls to Fn are made
+ // so that Fn can modify the Chunks in its shard without causing data
+ // races.
+ const size_t NumShards = 256;
+ size_t Step = Sections.size() / NumShards;
+ size_t Boundaries[NumShards + 1];
+ Boundaries[0] = 0;
+ Boundaries[NumShards] = Sections.size();
+
+ parallelForEachN(1, NumShards, [&](size_t I) {
+ Boundaries[I] = findBoundary((I - 1) * Step, Sections.size());
+ });
+
+ parallelForEachN(1, NumShards + 1, [&](size_t I) {
+ if (Boundaries[I - 1] < Boundaries[I])
+ forEachClassRange(Boundaries[I - 1], Boundaries[I], Fn);
+ });
+ ++Cnt;
+}
+
+// Combine the hashes of the sections referenced by the given section into its
+// hash.
+template <class ELFT, class RelTy>
+static void combineRelocHashes(unsigned Cnt, InputSection *IS,
+ ArrayRef<RelTy> Rels) {
+ uint32_t Hash = IS->Class[Cnt % 2];
+ for (RelTy Rel : Rels) {
+ Symbol &S = IS->template getFile<ELFT>()->getRelocTargetSym(Rel);
+ if (auto *D = dyn_cast<Defined>(&S))
+ if (auto *RelSec = dyn_cast_or_null<InputSection>(D->Section))
+ Hash += RelSec->Class[Cnt % 2];
+ }
+ // Set MSB to 1 to avoid collisions with non-hash IDs.
+ IS->Class[(Cnt + 1) % 2] = Hash | (1U << 31);
+}
+
+static void print(const Twine &S) {
+ if (Config->PrintIcfSections)
+ message(S);
+}
+
+// The main function of ICF.
+template <class ELFT> void ICF<ELFT>::run() {
+ // Collect sections to merge.
+ for (InputSectionBase *Sec : InputSections)
+ if (auto *S = dyn_cast<InputSection>(Sec))
+ if (isEligible(S))
+ Sections.push_back(S);
+
+ // Initially, we use hash values to partition sections.
+ parallelForEach(Sections, [&](InputSection *S) {
+ S->Class[0] = xxHash64(S->data());
+ });
+
+ for (unsigned Cnt = 0; Cnt != 2; ++Cnt) {
+ parallelForEach(Sections, [&](InputSection *S) {
+ if (S->AreRelocsRela)
+ combineRelocHashes<ELFT>(Cnt, S, S->template relas<ELFT>());
+ else
+ combineRelocHashes<ELFT>(Cnt, S, S->template rels<ELFT>());
+ });
+ }
+
+ // From now on, sections in Sections vector are ordered so that sections
+ // in the same equivalence class are consecutive in the vector.
+ std::stable_sort(Sections.begin(), Sections.end(),
+ [](InputSection *A, InputSection *B) {
+ return A->Class[0] < B->Class[0];
+ });
+
+ // Compare static contents and assign unique IDs for each static content.
+ forEachClass([&](size_t Begin, size_t End) { segregate(Begin, End, true); });
+
+ // Split groups by comparing relocations until convergence is obtained.
+ do {
+ Repeat = false;
+ forEachClass(
+ [&](size_t Begin, size_t End) { segregate(Begin, End, false); });
+ } while (Repeat);
+
+ log("ICF needed " + Twine(Cnt) + " iterations");
+
+ // Merge sections by the equivalence class.
+ forEachClassRange(0, Sections.size(), [&](size_t Begin, size_t End) {
+ if (End - Begin == 1)
+ return;
+ print("selected section " + toString(Sections[Begin]));
+ for (size_t I = Begin + 1; I < End; ++I) {
+ print(" removing identical section " + toString(Sections[I]));
+ Sections[Begin]->replace(Sections[I]);
+
+ // At this point we know sections merged are fully identical and hence
+ // we want to remove duplicate implicit dependencies such as link order
+ // and relocation sections.
+ for (InputSection *IS : Sections[I]->DependentSections)
+ IS->Live = false;
+ }
+ });
+}
+
+// ICF entry point function.
+template <class ELFT> void elf::doIcf() { ICF<ELFT>().run(); }
+
+template void elf::doIcf<ELF32LE>();
+template void elf::doIcf<ELF32BE>();
+template void elf::doIcf<ELF64LE>();
+template void elf::doIcf<ELF64BE>();
diff --git a/contrib/llvm/tools/lld/ELF/ICF.h b/contrib/llvm/tools/lld/ELF/ICF.h
new file mode 100644
index 000000000000..a6c8636ead6d
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/ICF.h
@@ -0,0 +1,21 @@
+//===- ICF.h --------------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_ICF_H
+#define LLD_ELF_ICF_H
+
+namespace lld {
+namespace elf {
+
+template <class ELFT> void doIcf();
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/ELF/InputFiles.cpp b/contrib/llvm/tools/lld/ELF/InputFiles.cpp
new file mode 100644
index 000000000000..bc7e61072e64
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/InputFiles.cpp
@@ -0,0 +1,1345 @@
+//===- InputFiles.cpp -----------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InputFiles.h"
+#include "InputSection.h"
+#include "LinkerScript.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Memory.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/CodeGen/Analysis.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/LTO/LTO.h"
+#include "llvm/MC/StringTableBuilder.h"
+#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Support/ARMAttributeParser.h"
+#include "llvm/Support/ARMBuildAttributes.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/TarWriter.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::object;
+using namespace llvm::sys;
+using namespace llvm::sys::fs;
+
+using namespace lld;
+using namespace lld::elf;
+
+bool InputFile::IsInGroup;
+uint32_t InputFile::NextGroupId;
+std::vector<BinaryFile *> elf::BinaryFiles;
+std::vector<BitcodeFile *> elf::BitcodeFiles;
+std::vector<LazyObjFile *> elf::LazyObjFiles;
+std::vector<InputFile *> elf::ObjectFiles;
+std::vector<InputFile *> elf::SharedFiles;
+
+std::unique_ptr<TarWriter> elf::Tar;
+
+InputFile::InputFile(Kind K, MemoryBufferRef M)
+ : MB(M), GroupId(NextGroupId), FileKind(K) {
+ // All files within the same --{start,end}-group get the same group ID.
+ // Otherwise, a new file will get a new group ID.
+ if (!IsInGroup)
+ ++NextGroupId;
+}
+
+Optional<MemoryBufferRef> elf::readFile(StringRef Path) {
+ // The --chroot option changes our virtual root directory.
+ // This is useful when you are dealing with files created by --reproduce.
+ if (!Config->Chroot.empty() && Path.startswith("/"))
+ Path = Saver.save(Config->Chroot + Path);
+
+ log(Path);
+
+ auto MBOrErr = MemoryBuffer::getFile(Path, -1, false);
+ if (auto EC = MBOrErr.getError()) {
+ error("cannot open " + Path + ": " + EC.message());
+ return None;
+ }
+
+ std::unique_ptr<MemoryBuffer> &MB = *MBOrErr;
+ MemoryBufferRef MBRef = MB->getMemBufferRef();
+ make<std::unique_ptr<MemoryBuffer>>(std::move(MB)); // take MB ownership
+
+ if (Tar)
+ Tar->append(relativeToRoot(Path), MBRef.getBuffer());
+ return MBRef;
+}
+
+// Concatenates arguments to construct a string representing an error location.
+static std::string createFileLineMsg(StringRef Path, unsigned Line) {
+ std::string Filename = path::filename(Path);
+ std::string Lineno = ":" + std::to_string(Line);
+ if (Filename == Path)
+ return Filename + Lineno;
+ return Filename + Lineno + " (" + Path.str() + Lineno + ")";
+}
+
+template <class ELFT>
+static std::string getSrcMsgAux(ObjFile<ELFT> &File, const Symbol &Sym,
+ InputSectionBase &Sec, uint64_t Offset) {
+ // In DWARF, functions and variables are stored to different places.
+ // First, lookup a function for a given offset.
+ if (Optional<DILineInfo> Info = File.getDILineInfo(&Sec, Offset))
+ return createFileLineMsg(Info->FileName, Info->Line);
+
+ // If it failed, lookup again as a variable.
+ if (Optional<std::pair<std::string, unsigned>> FileLine =
+ File.getVariableLoc(Sym.getName()))
+ return createFileLineMsg(FileLine->first, FileLine->second);
+
+ // File.SourceFile contains STT_FILE symbol, and that is a last resort.
+ return File.SourceFile;
+}
+
+std::string InputFile::getSrcMsg(const Symbol &Sym, InputSectionBase &Sec,
+ uint64_t Offset) {
+ if (kind() != ObjKind)
+ return "";
+ switch (Config->EKind) {
+ default:
+ llvm_unreachable("Invalid kind");
+ case ELF32LEKind:
+ return getSrcMsgAux(cast<ObjFile<ELF32LE>>(*this), Sym, Sec, Offset);
+ case ELF32BEKind:
+ return getSrcMsgAux(cast<ObjFile<ELF32BE>>(*this), Sym, Sec, Offset);
+ case ELF64LEKind:
+ return getSrcMsgAux(cast<ObjFile<ELF64LE>>(*this), Sym, Sec, Offset);
+ case ELF64BEKind:
+ return getSrcMsgAux(cast<ObjFile<ELF64BE>>(*this), Sym, Sec, Offset);
+ }
+}
+
+template <class ELFT> void ObjFile<ELFT>::initializeDwarf() {
+ Dwarf = llvm::make_unique<DWARFContext>(make_unique<LLDDwarfObj<ELFT>>(this));
+ for (std::unique_ptr<DWARFUnit> &CU : Dwarf->compile_units()) {
+ auto Report = [](Error Err) {
+ handleAllErrors(std::move(Err),
+ [](ErrorInfoBase &Info) { warn(Info.message()); });
+ };
+ Expected<const DWARFDebugLine::LineTable *> ExpectedLT =
+ Dwarf->getLineTableForUnit(CU.get(), Report);
+ const DWARFDebugLine::LineTable *LT = nullptr;
+ if (ExpectedLT)
+ LT = *ExpectedLT;
+ else
+ Report(ExpectedLT.takeError());
+ if (!LT)
+ continue;
+ LineTables.push_back(LT);
+
+ // Loop over variable records and insert them to VariableLoc.
+ for (const auto &Entry : CU->dies()) {
+ DWARFDie Die(CU.get(), &Entry);
+ // Skip all tags that are not variables.
+ if (Die.getTag() != dwarf::DW_TAG_variable)
+ continue;
+
+ // Skip if a local variable because we don't need them for generating
+ // error messages. In general, only non-local symbols can fail to be
+ // linked.
+ if (!dwarf::toUnsigned(Die.find(dwarf::DW_AT_external), 0))
+ continue;
+
+ // Get the source filename index for the variable.
+ unsigned File = dwarf::toUnsigned(Die.find(dwarf::DW_AT_decl_file), 0);
+ if (!LT->hasFileAtIndex(File))
+ continue;
+
+ // Get the line number on which the variable is declared.
+ unsigned Line = dwarf::toUnsigned(Die.find(dwarf::DW_AT_decl_line), 0);
+
+ // Here we want to take the variable name to add it into VariableLoc.
+ // Variable can have regular and linkage name associated. At first, we try
+ // to get linkage name as it can be different, for example when we have
+ // two variables in different namespaces of the same object. Use common
+ // name otherwise, but handle the case when it also absent in case if the
+ // input object file lacks some debug info.
+ StringRef Name =
+ dwarf::toString(Die.find(dwarf::DW_AT_linkage_name),
+ dwarf::toString(Die.find(dwarf::DW_AT_name), ""));
+ if (!Name.empty())
+ VariableLoc.insert({Name, {LT, File, Line}});
+ }
+ }
+}
+
+// Returns the pair of file name and line number describing location of data
+// object (variable, array, etc) definition.
+template <class ELFT>
+Optional<std::pair<std::string, unsigned>>
+ObjFile<ELFT>::getVariableLoc(StringRef Name) {
+ llvm::call_once(InitDwarfLine, [this]() { initializeDwarf(); });
+
+ // Return if we have no debug information about data object.
+ auto It = VariableLoc.find(Name);
+ if (It == VariableLoc.end())
+ return None;
+
+ // Take file name string from line table.
+ std::string FileName;
+ if (!It->second.LT->getFileNameByIndex(
+ It->second.File, nullptr,
+ DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, FileName))
+ return None;
+
+ return std::make_pair(FileName, It->second.Line);
+}
+
+// Returns source line information for a given offset
+// using DWARF debug info.
+template <class ELFT>
+Optional<DILineInfo> ObjFile<ELFT>::getDILineInfo(InputSectionBase *S,
+ uint64_t Offset) {
+ llvm::call_once(InitDwarfLine, [this]() { initializeDwarf(); });
+
+ // Use fake address calcuated by adding section file offset and offset in
+ // section. See comments for ObjectInfo class.
+ DILineInfo Info;
+ for (const llvm::DWARFDebugLine::LineTable *LT : LineTables)
+ if (LT->getFileLineInfoForAddress(
+ S->getOffsetInFile() + Offset, nullptr,
+ DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, Info))
+ return Info;
+ return None;
+}
+
+// Returns "<internal>", "foo.a(bar.o)" or "baz.o".
+std::string lld::toString(const InputFile *F) {
+ if (!F)
+ return "<internal>";
+
+ if (F->ToStringCache.empty()) {
+ if (F->ArchiveName.empty())
+ F->ToStringCache = F->getName();
+ else
+ F->ToStringCache = (F->ArchiveName + "(" + F->getName() + ")").str();
+ }
+ return F->ToStringCache;
+}
+
+template <class ELFT>
+ELFFileBase<ELFT>::ELFFileBase(Kind K, MemoryBufferRef MB) : InputFile(K, MB) {
+ if (ELFT::TargetEndianness == support::little)
+ EKind = ELFT::Is64Bits ? ELF64LEKind : ELF32LEKind;
+ else
+ EKind = ELFT::Is64Bits ? ELF64BEKind : ELF32BEKind;
+
+ EMachine = getObj().getHeader()->e_machine;
+ OSABI = getObj().getHeader()->e_ident[llvm::ELF::EI_OSABI];
+}
+
+template <class ELFT>
+typename ELFT::SymRange ELFFileBase<ELFT>::getGlobalELFSyms() {
+ return makeArrayRef(ELFSyms.begin() + FirstGlobal, ELFSyms.end());
+}
+
+template <class ELFT>
+uint32_t ELFFileBase<ELFT>::getSectionIndex(const Elf_Sym &Sym) const {
+ return CHECK(getObj().getSectionIndex(&Sym, ELFSyms, SymtabSHNDX), this);
+}
+
+template <class ELFT>
+void ELFFileBase<ELFT>::initSymtab(ArrayRef<Elf_Shdr> Sections,
+ const Elf_Shdr *Symtab) {
+ FirstGlobal = Symtab->sh_info;
+ ELFSyms = CHECK(getObj().symbols(Symtab), this);
+ if (FirstGlobal == 0 || FirstGlobal > ELFSyms.size())
+ fatal(toString(this) + ": invalid sh_info in symbol table");
+
+ StringTable =
+ CHECK(getObj().getStringTableForSymtab(*Symtab, Sections), this);
+}
+
+template <class ELFT>
+ObjFile<ELFT>::ObjFile(MemoryBufferRef M, StringRef ArchiveName)
+ : ELFFileBase<ELFT>(Base::ObjKind, M) {
+ this->ArchiveName = ArchiveName;
+}
+
+template <class ELFT> ArrayRef<Symbol *> ObjFile<ELFT>::getLocalSymbols() {
+ if (this->Symbols.empty())
+ return {};
+ return makeArrayRef(this->Symbols).slice(1, this->FirstGlobal - 1);
+}
+
+template <class ELFT> ArrayRef<Symbol *> ObjFile<ELFT>::getGlobalSymbols() {
+ return makeArrayRef(this->Symbols).slice(this->FirstGlobal);
+}
+
+template <class ELFT>
+void ObjFile<ELFT>::parse(DenseSet<CachedHashStringRef> &ComdatGroups) {
+ // Read a section table. JustSymbols is usually false.
+ if (this->JustSymbols)
+ initializeJustSymbols();
+ else
+ initializeSections(ComdatGroups);
+
+ // Read a symbol table.
+ initializeSymbols();
+}
+
+// Sections with SHT_GROUP and comdat bits define comdat section groups.
+// They are identified and deduplicated by group name. This function
+// returns a group name.
+template <class ELFT>
+StringRef ObjFile<ELFT>::getShtGroupSignature(ArrayRef<Elf_Shdr> Sections,
+ const Elf_Shdr &Sec) {
+ // Group signatures are stored as symbol names in object files.
+ // sh_info contains a symbol index, so we fetch a symbol and read its name.
+ if (this->ELFSyms.empty())
+ this->initSymtab(
+ Sections, CHECK(object::getSection<ELFT>(Sections, Sec.sh_link), this));
+
+ const Elf_Sym *Sym =
+ CHECK(object::getSymbol<ELFT>(this->ELFSyms, Sec.sh_info), this);
+ StringRef Signature = CHECK(Sym->getName(this->StringTable), this);
+
+ // As a special case, if a symbol is a section symbol and has no name,
+ // we use a section name as a signature.
+ //
+ // Such SHT_GROUP sections are invalid from the perspective of the ELF
+ // standard, but GNU gold 1.14 (the newest version as of July 2017) or
+ // older produce such sections as outputs for the -r option, so we need
+ // a bug-compatibility.
+ if (Signature.empty() && Sym->getType() == STT_SECTION)
+ return getSectionName(Sec);
+ return Signature;
+}
+
+template <class ELFT> bool ObjFile<ELFT>::shouldMerge(const Elf_Shdr &Sec) {
+ // On a regular link we don't merge sections if -O0 (default is -O1). This
+ // sometimes makes the linker significantly faster, although the output will
+ // be bigger.
+ //
+ // Doing the same for -r would create a problem as it would combine sections
+ // with different sh_entsize. One option would be to just copy every SHF_MERGE
+ // section as is to the output. While this would produce a valid ELF file with
+ // usable SHF_MERGE sections, tools like (llvm-)?dwarfdump get confused when
+ // they see two .debug_str. We could have separate logic for combining
+ // SHF_MERGE sections based both on their name and sh_entsize, but that seems
+ // to be more trouble than it is worth. Instead, we just use the regular (-O1)
+ // logic for -r.
+ if (Config->Optimize == 0 && !Config->Relocatable)
+ return false;
+
+ // A mergeable section with size 0 is useless because they don't have
+ // any data to merge. A mergeable string section with size 0 can be
+ // argued as invalid because it doesn't end with a null character.
+ // We'll avoid a mess by handling them as if they were non-mergeable.
+ if (Sec.sh_size == 0)
+ return false;
+
+ // Check for sh_entsize. The ELF spec is not clear about the zero
+ // sh_entsize. It says that "the member [sh_entsize] contains 0 if
+ // the section does not hold a table of fixed-size entries". We know
+ // that Rust 1.13 produces a string mergeable section with a zero
+ // sh_entsize. Here we just accept it rather than being picky about it.
+ uint64_t EntSize = Sec.sh_entsize;
+ if (EntSize == 0)
+ return false;
+ if (Sec.sh_size % EntSize)
+ fatal(toString(this) +
+ ": SHF_MERGE section size must be a multiple of sh_entsize");
+
+ uint64_t Flags = Sec.sh_flags;
+ if (!(Flags & SHF_MERGE))
+ return false;
+ if (Flags & SHF_WRITE)
+ fatal(toString(this) + ": writable SHF_MERGE section is not supported");
+
+ return true;
+}
+
+// This is for --just-symbols.
+//
+// --just-symbols is a very minor feature that allows you to link your
+// output against other existing program, so that if you load both your
+// program and the other program into memory, your output can refer the
+// other program's symbols.
+//
+// When the option is given, we link "just symbols". The section table is
+// initialized with null pointers.
+template <class ELFT> void ObjFile<ELFT>::initializeJustSymbols() {
+ ArrayRef<Elf_Shdr> ObjSections = CHECK(this->getObj().sections(), this);
+ this->Sections.resize(ObjSections.size());
+
+ for (const Elf_Shdr &Sec : ObjSections) {
+ if (Sec.sh_type != SHT_SYMTAB)
+ continue;
+ this->initSymtab(ObjSections, &Sec);
+ return;
+ }
+}
+
+template <class ELFT>
+void ObjFile<ELFT>::initializeSections(
+ DenseSet<CachedHashStringRef> &ComdatGroups) {
+ const ELFFile<ELFT> &Obj = this->getObj();
+
+ ArrayRef<Elf_Shdr> ObjSections = CHECK(Obj.sections(), this);
+ uint64_t Size = ObjSections.size();
+ this->Sections.resize(Size);
+ this->SectionStringTable =
+ CHECK(Obj.getSectionStringTable(ObjSections), this);
+
+ for (size_t I = 0, E = ObjSections.size(); I < E; I++) {
+ if (this->Sections[I] == &InputSection::Discarded)
+ continue;
+ const Elf_Shdr &Sec = ObjSections[I];
+
+ if (Sec.sh_type == ELF::SHT_LLVM_CALL_GRAPH_PROFILE)
+ CGProfile = check(
+ this->getObj().template getSectionContentsAsArray<Elf_CGProfile>(
+ &Sec));
+
+ // SHF_EXCLUDE'ed sections are discarded by the linker. However,
+ // if -r is given, we'll let the final link discard such sections.
+ // This is compatible with GNU.
+ if ((Sec.sh_flags & SHF_EXCLUDE) && !Config->Relocatable) {
+ if (Sec.sh_type == SHT_LLVM_ADDRSIG) {
+ // We ignore the address-significance table if we know that the object
+ // file was created by objcopy or ld -r. This is because these tools
+ // will reorder the symbols in the symbol table, invalidating the data
+ // in the address-significance table, which refers to symbols by index.
+ if (Sec.sh_link != 0)
+ this->AddrsigSec = &Sec;
+ else if (Config->ICF == ICFLevel::Safe)
+ warn(toString(this) + ": --icf=safe is incompatible with object "
+ "files created using objcopy or ld -r");
+ }
+ this->Sections[I] = &InputSection::Discarded;
+ continue;
+ }
+
+ switch (Sec.sh_type) {
+ case SHT_GROUP: {
+ // De-duplicate section groups by their signatures.
+ StringRef Signature = getShtGroupSignature(ObjSections, Sec);
+ this->Sections[I] = &InputSection::Discarded;
+
+
+ ArrayRef<Elf_Word> Entries =
+ CHECK(Obj.template getSectionContentsAsArray<Elf_Word>(&Sec), this);
+ if (Entries.empty())
+ fatal(toString(this) + ": empty SHT_GROUP");
+
+ // The first word of a SHT_GROUP section contains flags. Currently,
+ // the standard defines only "GRP_COMDAT" flag for the COMDAT group.
+ // An group with the empty flag doesn't define anything; such sections
+ // are just skipped.
+ if (Entries[0] == 0)
+ continue;
+
+ if (Entries[0] != GRP_COMDAT)
+ fatal(toString(this) + ": unsupported SHT_GROUP format");
+
+ bool IsNew = ComdatGroups.insert(CachedHashStringRef(Signature)).second;
+ if (IsNew) {
+ if (Config->Relocatable)
+ this->Sections[I] = createInputSection(Sec);
+ continue;
+ }
+
+
+ // Otherwise, discard group members.
+ for (uint32_t SecIndex : Entries.slice(1)) {
+ if (SecIndex >= Size)
+ fatal(toString(this) +
+ ": invalid section index in group: " + Twine(SecIndex));
+ this->Sections[SecIndex] = &InputSection::Discarded;
+ }
+ break;
+ }
+ case SHT_SYMTAB:
+ this->initSymtab(ObjSections, &Sec);
+ break;
+ case SHT_SYMTAB_SHNDX:
+ this->SymtabSHNDX = CHECK(Obj.getSHNDXTable(Sec, ObjSections), this);
+ break;
+ case SHT_STRTAB:
+ case SHT_NULL:
+ break;
+ default:
+ this->Sections[I] = createInputSection(Sec);
+ }
+
+ // .ARM.exidx sections have a reverse dependency on the InputSection they
+ // have a SHF_LINK_ORDER dependency, this is identified by the sh_link.
+ if (Sec.sh_flags & SHF_LINK_ORDER) {
+ InputSectionBase *LinkSec = nullptr;
+ if (Sec.sh_link < this->Sections.size())
+ LinkSec = this->Sections[Sec.sh_link];
+ if (!LinkSec)
+ fatal(toString(this) +
+ ": invalid sh_link index: " + Twine(Sec.sh_link));
+
+ InputSection *IS = cast<InputSection>(this->Sections[I]);
+ LinkSec->DependentSections.push_back(IS);
+ if (!isa<InputSection>(LinkSec))
+ error("a section " + IS->Name +
+ " with SHF_LINK_ORDER should not refer a non-regular "
+ "section: " +
+ toString(LinkSec));
+ }
+ }
+}
+
+// For ARM only, to set the EF_ARM_ABI_FLOAT_SOFT or EF_ARM_ABI_FLOAT_HARD
+// flag in the ELF Header we need to look at Tag_ABI_VFP_args to find out how
+// the input objects have been compiled.
+static void updateARMVFPArgs(const ARMAttributeParser &Attributes,
+ const InputFile *F) {
+ if (!Attributes.hasAttribute(ARMBuildAttrs::ABI_VFP_args))
+ // If an ABI tag isn't present then it is implicitly given the value of 0
+ // which maps to ARMBuildAttrs::BaseAAPCS. However many assembler files,
+ // including some in glibc that don't use FP args (and should have value 3)
+ // don't have the attribute so we do not consider an implicit value of 0
+ // as a clash.
+ return;
+
+ unsigned VFPArgs = Attributes.getAttributeValue(ARMBuildAttrs::ABI_VFP_args);
+ ARMVFPArgKind Arg;
+ switch (VFPArgs) {
+ case ARMBuildAttrs::BaseAAPCS:
+ Arg = ARMVFPArgKind::Base;
+ break;
+ case ARMBuildAttrs::HardFPAAPCS:
+ Arg = ARMVFPArgKind::VFP;
+ break;
+ case ARMBuildAttrs::ToolChainFPPCS:
+ // Tool chain specific convention that conforms to neither AAPCS variant.
+ Arg = ARMVFPArgKind::ToolChain;
+ break;
+ case ARMBuildAttrs::CompatibleFPAAPCS:
+ // Object compatible with all conventions.
+ return;
+ default:
+ error(toString(F) + ": unknown Tag_ABI_VFP_args value: " + Twine(VFPArgs));
+ return;
+ }
+ // Follow ld.bfd and error if there is a mix of calling conventions.
+ if (Config->ARMVFPArgs != Arg && Config->ARMVFPArgs != ARMVFPArgKind::Default)
+ error(toString(F) + ": incompatible Tag_ABI_VFP_args");
+ else
+ Config->ARMVFPArgs = Arg;
+}
+
+// The ARM support in lld makes some use of instructions that are not available
+// on all ARM architectures. Namely:
+// - Use of BLX instruction for interworking between ARM and Thumb state.
+// - Use of the extended Thumb branch encoding in relocation.
+// - Use of the MOVT/MOVW instructions in Thumb Thunks.
+// The ARM Attributes section contains information about the architecture chosen
+// at compile time. We follow the convention that if at least one input object
+// is compiled with an architecture that supports these features then lld is
+// permitted to use them.
+static void updateSupportedARMFeatures(const ARMAttributeParser &Attributes) {
+ if (!Attributes.hasAttribute(ARMBuildAttrs::CPU_arch))
+ return;
+ auto Arch = Attributes.getAttributeValue(ARMBuildAttrs::CPU_arch);
+ switch (Arch) {
+ case ARMBuildAttrs::Pre_v4:
+ case ARMBuildAttrs::v4:
+ case ARMBuildAttrs::v4T:
+ // Architectures prior to v5 do not support BLX instruction
+ break;
+ case ARMBuildAttrs::v5T:
+ case ARMBuildAttrs::v5TE:
+ case ARMBuildAttrs::v5TEJ:
+ case ARMBuildAttrs::v6:
+ case ARMBuildAttrs::v6KZ:
+ case ARMBuildAttrs::v6K:
+ Config->ARMHasBlx = true;
+ // Architectures used in pre-Cortex processors do not support
+ // The J1 = 1 J2 = 1 Thumb branch range extension, with the exception
+ // of Architecture v6T2 (arm1156t2-s and arm1156t2f-s) that do.
+ break;
+ default:
+ // All other Architectures have BLX and extended branch encoding
+ Config->ARMHasBlx = true;
+ Config->ARMJ1J2BranchEncoding = true;
+ if (Arch != ARMBuildAttrs::v6_M && Arch != ARMBuildAttrs::v6S_M)
+ // All Architectures used in Cortex processors with the exception
+ // of v6-M and v6S-M have the MOVT and MOVW instructions.
+ Config->ARMHasMovtMovw = true;
+ break;
+ }
+}
+
+template <class ELFT>
+InputSectionBase *ObjFile<ELFT>::getRelocTarget(const Elf_Shdr &Sec) {
+ uint32_t Idx = Sec.sh_info;
+ if (Idx >= this->Sections.size())
+ fatal(toString(this) + ": invalid relocated section index: " + Twine(Idx));
+ InputSectionBase *Target = this->Sections[Idx];
+
+ // Strictly speaking, a relocation section must be included in the
+ // group of the section it relocates. However, LLVM 3.3 and earlier
+ // would fail to do so, so we gracefully handle that case.
+ if (Target == &InputSection::Discarded)
+ return nullptr;
+
+ if (!Target)
+ fatal(toString(this) + ": unsupported relocation reference");
+ return Target;
+}
+
+// Create a regular InputSection class that has the same contents
+// as a given section.
+static InputSection *toRegularSection(MergeInputSection *Sec) {
+ return make<InputSection>(Sec->File, Sec->Flags, Sec->Type, Sec->Alignment,
+ Sec->data(), Sec->Name);
+}
+
+template <class ELFT>
+InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
+ StringRef Name = getSectionName(Sec);
+
+ switch (Sec.sh_type) {
+ case SHT_ARM_ATTRIBUTES: {
+ if (Config->EMachine != EM_ARM)
+ break;
+ ARMAttributeParser Attributes;
+ ArrayRef<uint8_t> Contents = check(this->getObj().getSectionContents(&Sec));
+ Attributes.Parse(Contents, /*isLittle*/ Config->EKind == ELF32LEKind);
+ updateSupportedARMFeatures(Attributes);
+ updateARMVFPArgs(Attributes, this);
+
+ // FIXME: Retain the first attribute section we see. The eglibc ARM
+ // dynamic loaders require the presence of an attribute section for dlopen
+ // to work. In a full implementation we would merge all attribute sections.
+ if (In.ARMAttributes == nullptr) {
+ In.ARMAttributes = make<InputSection>(*this, Sec, Name);
+ return In.ARMAttributes;
+ }
+ return &InputSection::Discarded;
+ }
+ case SHT_RELA:
+ case SHT_REL: {
+ // Find a relocation target section and associate this section with that.
+ // Target may have been discarded if it is in a different section group
+ // and the group is discarded, even though it's a violation of the
+ // spec. We handle that situation gracefully by discarding dangling
+ // relocation sections.
+ InputSectionBase *Target = getRelocTarget(Sec);
+ if (!Target)
+ return nullptr;
+
+ // This section contains relocation information.
+ // If -r is given, we do not interpret or apply relocation
+ // but just copy relocation sections to output.
+ if (Config->Relocatable) {
+ InputSection *RelocSec = make<InputSection>(*this, Sec, Name);
+ // We want to add a dependency to target, similar like we do for
+ // -emit-relocs below. This is useful for the case when linker script
+ // contains the "/DISCARD/". It is perhaps uncommon to use a script with
+ // -r, but we faced it in the Linux kernel and have to handle such case
+ // and not to crash.
+ Target->DependentSections.push_back(RelocSec);
+ return RelocSec;
+ }
+
+ if (Target->FirstRelocation)
+ fatal(toString(this) +
+ ": multiple relocation sections to one section are not supported");
+
+ // ELF spec allows mergeable sections with relocations, but they are
+ // rare, and it is in practice hard to merge such sections by contents,
+ // because applying relocations at end of linking changes section
+ // contents. So, we simply handle such sections as non-mergeable ones.
+ // Degrading like this is acceptable because section merging is optional.
+ if (auto *MS = dyn_cast<MergeInputSection>(Target)) {
+ Target = toRegularSection(MS);
+ this->Sections[Sec.sh_info] = Target;
+ }
+
+ if (Sec.sh_type == SHT_RELA) {
+ ArrayRef<Elf_Rela> Rels = CHECK(this->getObj().relas(&Sec), this);
+ Target->FirstRelocation = Rels.begin();
+ Target->NumRelocations = Rels.size();
+ Target->AreRelocsRela = true;
+ } else {
+ ArrayRef<Elf_Rel> Rels = CHECK(this->getObj().rels(&Sec), this);
+ Target->FirstRelocation = Rels.begin();
+ Target->NumRelocations = Rels.size();
+ Target->AreRelocsRela = false;
+ }
+ assert(isUInt<31>(Target->NumRelocations));
+
+ // Relocation sections processed by the linker are usually removed
+ // from the output, so returning `nullptr` for the normal case.
+ // However, if -emit-relocs is given, we need to leave them in the output.
+ // (Some post link analysis tools need this information.)
+ if (Config->EmitRelocs) {
+ InputSection *RelocSec = make<InputSection>(*this, Sec, Name);
+ // We will not emit relocation section if target was discarded.
+ Target->DependentSections.push_back(RelocSec);
+ return RelocSec;
+ }
+ return nullptr;
+ }
+ }
+
+ // The GNU linker uses .note.GNU-stack section as a marker indicating
+ // that the code in the object file does not expect that the stack is
+ // executable (in terms of NX bit). If all input files have the marker,
+ // the GNU linker adds a PT_GNU_STACK segment to tells the loader to
+ // make the stack non-executable. Most object files have this section as
+ // of 2017.
+ //
+ // But making the stack non-executable is a norm today for security
+ // reasons. Failure to do so may result in a serious security issue.
+ // Therefore, we make LLD always add PT_GNU_STACK unless it is
+ // explicitly told to do otherwise (by -z execstack). Because the stack
+ // executable-ness is controlled solely by command line options,
+ // .note.GNU-stack sections are simply ignored.
+ if (Name == ".note.GNU-stack")
+ return &InputSection::Discarded;
+
+ // Split stacks is a feature to support a discontiguous stack,
+ // commonly used in the programming language Go. For the details,
+ // see https://gcc.gnu.org/wiki/SplitStacks. An object file compiled
+ // for split stack will include a .note.GNU-split-stack section.
+ if (Name == ".note.GNU-split-stack") {
+ if (Config->Relocatable) {
+ error("cannot mix split-stack and non-split-stack in a relocatable link");
+ return &InputSection::Discarded;
+ }
+ this->SplitStack = true;
+ return &InputSection::Discarded;
+ }
+
+ // An object file cmpiled for split stack, but where some of the
+ // functions were compiled with the no_split_stack_attribute will
+ // include a .note.GNU-no-split-stack section.
+ if (Name == ".note.GNU-no-split-stack") {
+ this->SomeNoSplitStack = true;
+ return &InputSection::Discarded;
+ }
+
+ // The linkonce feature is a sort of proto-comdat. Some glibc i386 object
+ // files contain definitions of symbol "__x86.get_pc_thunk.bx" in linkonce
+ // sections. Drop those sections to avoid duplicate symbol errors.
+ // FIXME: This is glibc PR20543, we should remove this hack once that has been
+ // fixed for a while.
+ if (Name == ".gnu.linkonce.t.__x86.get_pc_thunk.bx" ||
+ Name == ".gnu.linkonce.t.__i686.get_pc_thunk.bx")
+ return &InputSection::Discarded;
+
+ // If we are creating a new .build-id section, strip existing .build-id
+ // sections so that the output won't have more than one .build-id.
+ // This is not usually a problem because input object files normally don't
+ // have .build-id sections, but you can create such files by
+ // "ld.{bfd,gold,lld} -r --build-id", and we want to guard against it.
+ if (Name == ".note.gnu.build-id" && Config->BuildId != BuildIdKind::None)
+ return &InputSection::Discarded;
+
+ // The linker merges EH (exception handling) frames and creates a
+ // .eh_frame_hdr section for runtime. So we handle them with a special
+ // class. For relocatable outputs, they are just passed through.
+ if (Name == ".eh_frame" && !Config->Relocatable)
+ return make<EhInputSection>(*this, Sec, Name);
+
+ if (shouldMerge(Sec))
+ return make<MergeInputSection>(*this, Sec, Name);
+ return make<InputSection>(*this, Sec, Name);
+}
+
+template <class ELFT>
+StringRef ObjFile<ELFT>::getSectionName(const Elf_Shdr &Sec) {
+ return CHECK(this->getObj().getSectionName(&Sec, SectionStringTable), this);
+}
+
+template <class ELFT> void ObjFile<ELFT>::initializeSymbols() {
+ this->Symbols.reserve(this->ELFSyms.size());
+ for (const Elf_Sym &Sym : this->ELFSyms)
+ this->Symbols.push_back(createSymbol(&Sym));
+}
+
+template <class ELFT> Symbol *ObjFile<ELFT>::createSymbol(const Elf_Sym *Sym) {
+ int Binding = Sym->getBinding();
+
+ uint32_t SecIdx = this->getSectionIndex(*Sym);
+ if (SecIdx >= this->Sections.size())
+ fatal(toString(this) + ": invalid section index: " + Twine(SecIdx));
+
+ InputSectionBase *Sec = this->Sections[SecIdx];
+ uint8_t StOther = Sym->st_other;
+ uint8_t Type = Sym->getType();
+ uint64_t Value = Sym->st_value;
+ uint64_t Size = Sym->st_size;
+
+ if (Binding == STB_LOCAL) {
+ if (Sym->getType() == STT_FILE)
+ SourceFile = CHECK(Sym->getName(this->StringTable), this);
+
+ if (this->StringTable.size() <= Sym->st_name)
+ fatal(toString(this) + ": invalid symbol name offset");
+
+ StringRefZ Name = this->StringTable.data() + Sym->st_name;
+ if (Sym->st_shndx == SHN_UNDEF)
+ return make<Undefined>(this, Name, Binding, StOther, Type);
+
+ return make<Defined>(this, Name, Binding, StOther, Type, Value, Size, Sec);
+ }
+
+ StringRef Name = CHECK(Sym->getName(this->StringTable), this);
+
+ switch (Sym->st_shndx) {
+ case SHN_UNDEF:
+ return Symtab->addUndefined<ELFT>(Name, Binding, StOther, Type,
+ /*CanOmitFromDynSym=*/false, this);
+ case SHN_COMMON:
+ if (Value == 0 || Value >= UINT32_MAX)
+ fatal(toString(this) + ": common symbol '" + Name +
+ "' has invalid alignment: " + Twine(Value));
+ return Symtab->addCommon(Name, Size, Value, Binding, StOther, Type, *this);
+ }
+
+ switch (Binding) {
+ default:
+ fatal(toString(this) + ": unexpected binding: " + Twine(Binding));
+ case STB_GLOBAL:
+ case STB_WEAK:
+ case STB_GNU_UNIQUE:
+ if (Sec == &InputSection::Discarded)
+ return Symtab->addUndefined<ELFT>(Name, Binding, StOther, Type,
+ /*CanOmitFromDynSym=*/false, this);
+ return Symtab->addDefined(Name, StOther, Type, Value, Size, Binding, Sec,
+ this);
+ }
+}
+
+ArchiveFile::ArchiveFile(std::unique_ptr<Archive> &&File)
+ : InputFile(ArchiveKind, File->getMemoryBufferRef()),
+ File(std::move(File)) {}
+
+template <class ELFT> void ArchiveFile::parse() {
+ for (const Archive::Symbol &Sym : File->symbols())
+ Symtab->addLazyArchive<ELFT>(Sym.getName(), *this, Sym);
+}
+
+// Returns a buffer pointing to a member file containing a given symbol.
+InputFile *ArchiveFile::fetch(const Archive::Symbol &Sym) {
+ Archive::Child C =
+ CHECK(Sym.getMember(), toString(this) +
+ ": could not get the member for symbol " +
+ Sym.getName());
+
+ if (!Seen.insert(C.getChildOffset()).second)
+ return nullptr;
+
+ MemoryBufferRef MB =
+ CHECK(C.getMemoryBufferRef(),
+ toString(this) +
+ ": could not get the buffer for the member defining symbol " +
+ Sym.getName());
+
+ if (Tar && C.getParent()->isThin())
+ Tar->append(relativeToRoot(CHECK(C.getFullName(), this)), MB.getBuffer());
+
+ InputFile *File = createObjectFile(
+ MB, getName(), C.getParent()->isThin() ? 0 : C.getChildOffset());
+ File->GroupId = GroupId;
+ return File;
+}
+
+template <class ELFT>
+SharedFile<ELFT>::SharedFile(MemoryBufferRef M, StringRef DefaultSoName)
+ : ELFFileBase<ELFT>(Base::SharedKind, M), SoName(DefaultSoName),
+ IsNeeded(!Config->AsNeeded) {}
+
+// Partially parse the shared object file so that we can call
+// getSoName on this object.
+template <class ELFT> void SharedFile<ELFT>::parseSoName() {
+ const Elf_Shdr *DynamicSec = nullptr;
+ const ELFFile<ELFT> Obj = this->getObj();
+ ArrayRef<Elf_Shdr> Sections = CHECK(Obj.sections(), this);
+
+ // Search for .dynsym, .dynamic, .symtab, .gnu.version and .gnu.version_d.
+ for (const Elf_Shdr &Sec : Sections) {
+ switch (Sec.sh_type) {
+ default:
+ continue;
+ case SHT_DYNSYM:
+ this->initSymtab(Sections, &Sec);
+ break;
+ case SHT_DYNAMIC:
+ DynamicSec = &Sec;
+ break;
+ case SHT_SYMTAB_SHNDX:
+ this->SymtabSHNDX = CHECK(Obj.getSHNDXTable(Sec, Sections), this);
+ break;
+ case SHT_GNU_versym:
+ this->VersymSec = &Sec;
+ break;
+ case SHT_GNU_verdef:
+ this->VerdefSec = &Sec;
+ break;
+ }
+ }
+
+ if (this->VersymSec && this->ELFSyms.empty())
+ error("SHT_GNU_versym should be associated with symbol table");
+
+ // Search for a DT_SONAME tag to initialize this->SoName.
+ if (!DynamicSec)
+ return;
+ ArrayRef<Elf_Dyn> Arr =
+ CHECK(Obj.template getSectionContentsAsArray<Elf_Dyn>(DynamicSec), this);
+ for (const Elf_Dyn &Dyn : Arr) {
+ if (Dyn.d_tag == DT_SONAME) {
+ uint64_t Val = Dyn.getVal();
+ if (Val >= this->StringTable.size())
+ fatal(toString(this) + ": invalid DT_SONAME entry");
+ SoName = this->StringTable.data() + Val;
+ return;
+ }
+ }
+}
+
+// Parses ".gnu.version" section which is a parallel array for the symbol table.
+// If a given file doesn't have ".gnu.version" section, returns VER_NDX_GLOBAL.
+template <class ELFT> std::vector<uint32_t> SharedFile<ELFT>::parseVersyms() {
+ size_t Size = this->ELFSyms.size() - this->FirstGlobal;
+ if (!VersymSec)
+ return std::vector<uint32_t>(Size, VER_NDX_GLOBAL);
+
+ const char *Base = this->MB.getBuffer().data();
+ const Elf_Versym *Versym =
+ reinterpret_cast<const Elf_Versym *>(Base + VersymSec->sh_offset) +
+ this->FirstGlobal;
+
+ std::vector<uint32_t> Ret(Size);
+ for (size_t I = 0; I < Size; ++I)
+ Ret[I] = Versym[I].vs_index;
+ return Ret;
+}
+
+// Parse the version definitions in the object file if present. Returns a vector
+// whose nth element contains a pointer to the Elf_Verdef for version identifier
+// n. Version identifiers that are not definitions map to nullptr.
+template <class ELFT>
+std::vector<const typename ELFT::Verdef *> SharedFile<ELFT>::parseVerdefs() {
+ if (!VerdefSec)
+ return {};
+
+ // We cannot determine the largest verdef identifier without inspecting
+ // every Elf_Verdef, but both bfd and gold assign verdef identifiers
+ // sequentially starting from 1, so we predict that the largest identifier
+ // will be VerdefCount.
+ unsigned VerdefCount = VerdefSec->sh_info;
+ std::vector<const Elf_Verdef *> Verdefs(VerdefCount + 1);
+
+ // Build the Verdefs array by following the chain of Elf_Verdef objects
+ // from the start of the .gnu.version_d section.
+ const char *Base = this->MB.getBuffer().data();
+ const char *Verdef = Base + VerdefSec->sh_offset;
+ for (unsigned I = 0; I != VerdefCount; ++I) {
+ auto *CurVerdef = reinterpret_cast<const Elf_Verdef *>(Verdef);
+ Verdef += CurVerdef->vd_next;
+ unsigned VerdefIndex = CurVerdef->vd_ndx;
+ Verdefs.resize(VerdefIndex + 1);
+ Verdefs[VerdefIndex] = CurVerdef;
+ }
+
+ return Verdefs;
+}
+
+// We do not usually care about alignments of data in shared object
+// files because the loader takes care of it. However, if we promote a
+// DSO symbol to point to .bss due to copy relocation, we need to keep
+// the original alignment requirements. We infer it in this function.
+template <class ELFT>
+uint32_t SharedFile<ELFT>::getAlignment(ArrayRef<Elf_Shdr> Sections,
+ const Elf_Sym &Sym) {
+ uint64_t Ret = UINT64_MAX;
+ if (Sym.st_value)
+ Ret = 1ULL << countTrailingZeros((uint64_t)Sym.st_value);
+ if (0 < Sym.st_shndx && Sym.st_shndx < Sections.size())
+ Ret = std::min<uint64_t>(Ret, Sections[Sym.st_shndx].sh_addralign);
+ return (Ret > UINT32_MAX) ? 0 : Ret;
+}
+
+// Fully parse the shared object file. This must be called after parseSoName().
+//
+// This function parses symbol versions. If a DSO has version information,
+// the file has a ".gnu.version_d" section which contains symbol version
+// definitions. Each symbol is associated to one version through a table in
+// ".gnu.version" section. That table is a parallel array for the symbol
+// table, and each table entry contains an index in ".gnu.version_d".
+//
+// The special index 0 is reserved for VERF_NDX_LOCAL and 1 is for
+// VER_NDX_GLOBAL. There's no table entry for these special versions in
+// ".gnu.version_d".
+//
+// The file format for symbol versioning is perhaps a bit more complicated
+// than necessary, but you can easily understand the code if you wrap your
+// head around the data structure described above.
+template <class ELFT> void SharedFile<ELFT>::parseRest() {
+ Verdefs = parseVerdefs(); // parse .gnu.version_d
+ std::vector<uint32_t> Versyms = parseVersyms(); // parse .gnu.version
+ ArrayRef<Elf_Shdr> Sections = CHECK(this->getObj().sections(), this);
+
+ // System libraries can have a lot of symbols with versions. Using a
+ // fixed buffer for computing the versions name (foo@ver) can save a
+ // lot of allocations.
+ SmallString<0> VersionedNameBuffer;
+
+ // Add symbols to the symbol table.
+ ArrayRef<Elf_Sym> Syms = this->getGlobalELFSyms();
+ for (size_t I = 0; I < Syms.size(); ++I) {
+ const Elf_Sym &Sym = Syms[I];
+
+ // ELF spec requires that all local symbols precede weak or global
+ // symbols in each symbol table, and the index of first non-local symbol
+ // is stored to sh_info. If a local symbol appears after some non-local
+ // symbol, that's a violation of the spec.
+ StringRef Name = CHECK(Sym.getName(this->StringTable), this);
+ if (Sym.getBinding() == STB_LOCAL) {
+ warn("found local symbol '" + Name +
+ "' in global part of symbol table in file " + toString(this));
+ continue;
+ }
+
+ if (Sym.isUndefined()) {
+ Symbol *S = Symtab->addUndefined<ELFT>(Name, Sym.getBinding(),
+ Sym.st_other, Sym.getType(),
+ /*CanOmitFromDynSym=*/false, this);
+ S->ExportDynamic = true;
+ continue;
+ }
+
+ // MIPS BFD linker puts _gp_disp symbol into DSO files and incorrectly
+ // assigns VER_NDX_LOCAL to this section global symbol. Here is a
+ // workaround for this bug.
+ uint32_t Idx = Versyms[I] & ~VERSYM_HIDDEN;
+ if (Config->EMachine == EM_MIPS && Idx == VER_NDX_LOCAL &&
+ Name == "_gp_disp")
+ continue;
+
+ uint64_t Alignment = getAlignment(Sections, Sym);
+ if (!(Versyms[I] & VERSYM_HIDDEN))
+ Symtab->addShared(Name, *this, Sym, Alignment, Idx);
+
+ // Also add the symbol with the versioned name to handle undefined symbols
+ // with explicit versions.
+ if (Idx == VER_NDX_GLOBAL)
+ continue;
+
+ if (Idx >= Verdefs.size() || Idx == VER_NDX_LOCAL) {
+ error("corrupt input file: version definition index " + Twine(Idx) +
+ " for symbol " + Name + " is out of bounds\n>>> defined in " +
+ toString(this));
+ continue;
+ }
+
+ StringRef VerName =
+ this->StringTable.data() + Verdefs[Idx]->getAux()->vda_name;
+ VersionedNameBuffer.clear();
+ Name = (Name + "@" + VerName).toStringRef(VersionedNameBuffer);
+ Symtab->addShared(Saver.save(Name), *this, Sym, Alignment, Idx);
+ }
+}
+
+static ELFKind getBitcodeELFKind(const Triple &T) {
+ if (T.isLittleEndian())
+ return T.isArch64Bit() ? ELF64LEKind : ELF32LEKind;
+ return T.isArch64Bit() ? ELF64BEKind : ELF32BEKind;
+}
+
+static uint8_t getBitcodeMachineKind(StringRef Path, const Triple &T) {
+ switch (T.getArch()) {
+ case Triple::aarch64:
+ return EM_AARCH64;
+ case Triple::amdgcn:
+ case Triple::r600:
+ return EM_AMDGPU;
+ case Triple::arm:
+ case Triple::thumb:
+ return EM_ARM;
+ case Triple::avr:
+ return EM_AVR;
+ case Triple::mips:
+ case Triple::mipsel:
+ case Triple::mips64:
+ case Triple::mips64el:
+ return EM_MIPS;
+ case Triple::msp430:
+ return EM_MSP430;
+ case Triple::ppc:
+ return EM_PPC;
+ case Triple::ppc64:
+ case Triple::ppc64le:
+ return EM_PPC64;
+ case Triple::x86:
+ return T.isOSIAMCU() ? EM_IAMCU : EM_386;
+ case Triple::x86_64:
+ return EM_X86_64;
+ default:
+ error(Path + ": could not infer e_machine from bitcode target triple " +
+ T.str());
+ return EM_NONE;
+ }
+}
+
+BitcodeFile::BitcodeFile(MemoryBufferRef MB, StringRef ArchiveName,
+ uint64_t OffsetInArchive)
+ : InputFile(BitcodeKind, MB) {
+ this->ArchiveName = ArchiveName;
+
+ std::string Path = MB.getBufferIdentifier().str();
+ if (Config->ThinLTOIndexOnly)
+ Path = replaceThinLTOSuffix(MB.getBufferIdentifier());
+
+ // ThinLTO assumes that all MemoryBufferRefs given to it have a unique
+ // name. If two archives define two members with the same name, this
+ // causes a collision which result in only one of the objects being taken
+ // into consideration at LTO time (which very likely causes undefined
+ // symbols later in the link stage). So we append file offset to make
+ // filename unique.
+ MemoryBufferRef MBRef(
+ MB.getBuffer(),
+ Saver.save(ArchiveName + Path +
+ (ArchiveName.empty() ? "" : utostr(OffsetInArchive))));
+
+ Obj = CHECK(lto::InputFile::create(MBRef), this);
+
+ Triple T(Obj->getTargetTriple());
+ EKind = getBitcodeELFKind(T);
+ EMachine = getBitcodeMachineKind(MB.getBufferIdentifier(), T);
+}
+
+static uint8_t mapVisibility(GlobalValue::VisibilityTypes GvVisibility) {
+ switch (GvVisibility) {
+ case GlobalValue::DefaultVisibility:
+ return STV_DEFAULT;
+ case GlobalValue::HiddenVisibility:
+ return STV_HIDDEN;
+ case GlobalValue::ProtectedVisibility:
+ return STV_PROTECTED;
+ }
+ llvm_unreachable("unknown visibility");
+}
+
+template <class ELFT>
+static Symbol *createBitcodeSymbol(const std::vector<bool> &KeptComdats,
+ const lto::InputFile::Symbol &ObjSym,
+ BitcodeFile &F) {
+ StringRef Name = Saver.save(ObjSym.getName());
+ uint32_t Binding = ObjSym.isWeak() ? STB_WEAK : STB_GLOBAL;
+
+ uint8_t Type = ObjSym.isTLS() ? STT_TLS : STT_NOTYPE;
+ uint8_t Visibility = mapVisibility(ObjSym.getVisibility());
+ bool CanOmitFromDynSym = ObjSym.canBeOmittedFromSymbolTable();
+
+ int C = ObjSym.getComdatIndex();
+ if (C != -1 && !KeptComdats[C])
+ return Symtab->addUndefined<ELFT>(Name, Binding, Visibility, Type,
+ CanOmitFromDynSym, &F);
+
+ if (ObjSym.isUndefined())
+ return Symtab->addUndefined<ELFT>(Name, Binding, Visibility, Type,
+ CanOmitFromDynSym, &F);
+
+ if (ObjSym.isCommon())
+ return Symtab->addCommon(Name, ObjSym.getCommonSize(),
+ ObjSym.getCommonAlignment(), Binding, Visibility,
+ STT_OBJECT, F);
+
+ return Symtab->addBitcode(Name, Binding, Visibility, Type, CanOmitFromDynSym,
+ F);
+}
+
+template <class ELFT>
+void BitcodeFile::parse(DenseSet<CachedHashStringRef> &ComdatGroups) {
+ std::vector<bool> KeptComdats;
+ for (StringRef S : Obj->getComdatTable())
+ KeptComdats.push_back(ComdatGroups.insert(CachedHashStringRef(S)).second);
+
+ for (const lto::InputFile::Symbol &ObjSym : Obj->symbols())
+ Symbols.push_back(createBitcodeSymbol<ELFT>(KeptComdats, ObjSym, *this));
+}
+
+static ELFKind getELFKind(MemoryBufferRef MB) {
+ unsigned char Size;
+ unsigned char Endian;
+ std::tie(Size, Endian) = getElfArchType(MB.getBuffer());
+
+ if (Endian != ELFDATA2LSB && Endian != ELFDATA2MSB)
+ fatal(MB.getBufferIdentifier() + ": invalid data encoding");
+ if (Size != ELFCLASS32 && Size != ELFCLASS64)
+ fatal(MB.getBufferIdentifier() + ": invalid file class");
+
+ size_t BufSize = MB.getBuffer().size();
+ if ((Size == ELFCLASS32 && BufSize < sizeof(Elf32_Ehdr)) ||
+ (Size == ELFCLASS64 && BufSize < sizeof(Elf64_Ehdr)))
+ fatal(MB.getBufferIdentifier() + ": file is too short");
+
+ if (Size == ELFCLASS32)
+ return (Endian == ELFDATA2LSB) ? ELF32LEKind : ELF32BEKind;
+ return (Endian == ELFDATA2LSB) ? ELF64LEKind : ELF64BEKind;
+}
+
+void BinaryFile::parse() {
+ ArrayRef<uint8_t> Data = arrayRefFromStringRef(MB.getBuffer());
+ auto *Section = make<InputSection>(this, SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
+ 8, Data, ".data");
+ Sections.push_back(Section);
+
+ // For each input file foo that is embedded to a result as a binary
+ // blob, we define _binary_foo_{start,end,size} symbols, so that
+ // user programs can access blobs by name. Non-alphanumeric
+ // characters in a filename are replaced with underscore.
+ std::string S = "_binary_" + MB.getBufferIdentifier().str();
+ for (size_t I = 0; I < S.size(); ++I)
+ if (!isAlnum(S[I]))
+ S[I] = '_';
+
+ Symtab->addDefined(Saver.save(S + "_start"), STV_DEFAULT, STT_OBJECT, 0, 0,
+ STB_GLOBAL, Section, nullptr);
+ Symtab->addDefined(Saver.save(S + "_end"), STV_DEFAULT, STT_OBJECT,
+ Data.size(), 0, STB_GLOBAL, Section, nullptr);
+ Symtab->addDefined(Saver.save(S + "_size"), STV_DEFAULT, STT_OBJECT,
+ Data.size(), 0, STB_GLOBAL, nullptr, nullptr);
+}
+
+InputFile *elf::createObjectFile(MemoryBufferRef MB, StringRef ArchiveName,
+ uint64_t OffsetInArchive) {
+ if (isBitcode(MB))
+ return make<BitcodeFile>(MB, ArchiveName, OffsetInArchive);
+
+ switch (getELFKind(MB)) {
+ case ELF32LEKind:
+ return make<ObjFile<ELF32LE>>(MB, ArchiveName);
+ case ELF32BEKind:
+ return make<ObjFile<ELF32BE>>(MB, ArchiveName);
+ case ELF64LEKind:
+ return make<ObjFile<ELF64LE>>(MB, ArchiveName);
+ case ELF64BEKind:
+ return make<ObjFile<ELF64BE>>(MB, ArchiveName);
+ default:
+ llvm_unreachable("getELFKind");
+ }
+}
+
+InputFile *elf::createSharedFile(MemoryBufferRef MB, StringRef DefaultSoName) {
+ switch (getELFKind(MB)) {
+ case ELF32LEKind:
+ return make<SharedFile<ELF32LE>>(MB, DefaultSoName);
+ case ELF32BEKind:
+ return make<SharedFile<ELF32BE>>(MB, DefaultSoName);
+ case ELF64LEKind:
+ return make<SharedFile<ELF64LE>>(MB, DefaultSoName);
+ case ELF64BEKind:
+ return make<SharedFile<ELF64BE>>(MB, DefaultSoName);
+ default:
+ llvm_unreachable("getELFKind");
+ }
+}
+
+MemoryBufferRef LazyObjFile::getBuffer() {
+ if (AddedToLink)
+ return MemoryBufferRef();
+ AddedToLink = true;
+ return MB;
+}
+
+InputFile *LazyObjFile::fetch() {
+ MemoryBufferRef MBRef = getBuffer();
+ if (MBRef.getBuffer().empty())
+ return nullptr;
+
+ InputFile *File = createObjectFile(MBRef, ArchiveName, OffsetInArchive);
+ File->GroupId = GroupId;
+ return File;
+}
+
+template <class ELFT> void LazyObjFile::parse() {
+ // A lazy object file wraps either a bitcode file or an ELF file.
+ if (isBitcode(this->MB)) {
+ std::unique_ptr<lto::InputFile> Obj =
+ CHECK(lto::InputFile::create(this->MB), this);
+ for (const lto::InputFile::Symbol &Sym : Obj->symbols())
+ if (!Sym.isUndefined())
+ Symtab->addLazyObject<ELFT>(Saver.save(Sym.getName()), *this);
+ return;
+ }
+
+ if (getELFKind(this->MB) != Config->EKind) {
+ error("incompatible file: " + this->MB.getBufferIdentifier());
+ return;
+ }
+
+ ELFFile<ELFT> Obj = check(ELFFile<ELFT>::create(MB.getBuffer()));
+ ArrayRef<typename ELFT::Shdr> Sections = CHECK(Obj.sections(), this);
+
+ for (const typename ELFT::Shdr &Sec : Sections) {
+ if (Sec.sh_type != SHT_SYMTAB)
+ continue;
+
+ typename ELFT::SymRange Syms = CHECK(Obj.symbols(&Sec), this);
+ uint32_t FirstGlobal = Sec.sh_info;
+ StringRef StringTable =
+ CHECK(Obj.getStringTableForSymtab(Sec, Sections), this);
+
+ for (const typename ELFT::Sym &Sym : Syms.slice(FirstGlobal))
+ if (Sym.st_shndx != SHN_UNDEF)
+ Symtab->addLazyObject<ELFT>(CHECK(Sym.getName(StringTable), this),
+ *this);
+ return;
+ }
+}
+
+std::string elf::replaceThinLTOSuffix(StringRef Path) {
+ StringRef Suffix = Config->ThinLTOObjectSuffixReplace.first;
+ StringRef Repl = Config->ThinLTOObjectSuffixReplace.second;
+
+ if (Path.consume_back(Suffix))
+ return (Path + Repl).str();
+ return Path;
+}
+
+template void ArchiveFile::parse<ELF32LE>();
+template void ArchiveFile::parse<ELF32BE>();
+template void ArchiveFile::parse<ELF64LE>();
+template void ArchiveFile::parse<ELF64BE>();
+
+template void BitcodeFile::parse<ELF32LE>(DenseSet<CachedHashStringRef> &);
+template void BitcodeFile::parse<ELF32BE>(DenseSet<CachedHashStringRef> &);
+template void BitcodeFile::parse<ELF64LE>(DenseSet<CachedHashStringRef> &);
+template void BitcodeFile::parse<ELF64BE>(DenseSet<CachedHashStringRef> &);
+
+template void LazyObjFile::parse<ELF32LE>();
+template void LazyObjFile::parse<ELF32BE>();
+template void LazyObjFile::parse<ELF64LE>();
+template void LazyObjFile::parse<ELF64BE>();
+
+template class elf::ELFFileBase<ELF32LE>;
+template class elf::ELFFileBase<ELF32BE>;
+template class elf::ELFFileBase<ELF64LE>;
+template class elf::ELFFileBase<ELF64BE>;
+
+template class elf::ObjFile<ELF32LE>;
+template class elf::ObjFile<ELF32BE>;
+template class elf::ObjFile<ELF64LE>;
+template class elf::ObjFile<ELF64BE>;
+
+template class elf::SharedFile<ELF32LE>;
+template class elf::SharedFile<ELF32BE>;
+template class elf::SharedFile<ELF64LE>;
+template class elf::SharedFile<ELF64BE>;
diff --git a/contrib/llvm/tools/lld/ELF/InputFiles.h b/contrib/llvm/tools/lld/ELF/InputFiles.h
new file mode 100644
index 000000000000..d7cbbc67a365
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/InputFiles.h
@@ -0,0 +1,382 @@
+//===- InputFiles.h ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_INPUT_FILES_H
+#define LLD_ELF_INPUT_FILES_H
+
+#include "Config.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/LLVM.h"
+#include "lld/Common/Reproduce.h"
+#include "llvm/ADT/CachedHashString.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
+#include "llvm/IR/Comdat.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Object/IRObjectFile.h"
+#include "llvm/Support/Threading.h"
+#include <map>
+
+namespace llvm {
+class TarWriter;
+struct DILineInfo;
+namespace lto {
+class InputFile;
+}
+} // namespace llvm
+
+namespace lld {
+namespace elf {
+class InputFile;
+class InputSectionBase;
+}
+
+// Returns "<internal>", "foo.a(bar.o)" or "baz.o".
+std::string toString(const elf::InputFile *F);
+
+namespace elf {
+
+using llvm::object::Archive;
+
+class Symbol;
+
+// If -reproduce option is given, all input files are written
+// to this tar archive.
+extern std::unique_ptr<llvm::TarWriter> Tar;
+
+// Opens a given file.
+llvm::Optional<MemoryBufferRef> readFile(StringRef Path);
+
+// The root class of input files.
+class InputFile {
+public:
+ enum Kind {
+ ObjKind,
+ SharedKind,
+ LazyObjKind,
+ ArchiveKind,
+ BitcodeKind,
+ BinaryKind,
+ };
+
+ Kind kind() const { return FileKind; }
+
+ bool isElf() const {
+ Kind K = kind();
+ return K == ObjKind || K == SharedKind;
+ }
+
+ StringRef getName() const { return MB.getBufferIdentifier(); }
+ MemoryBufferRef MB;
+
+ // Returns sections. It is a runtime error to call this function
+ // on files that don't have the notion of sections.
+ ArrayRef<InputSectionBase *> getSections() const {
+ assert(FileKind == ObjKind || FileKind == BinaryKind);
+ return Sections;
+ }
+
+ // Returns object file symbols. It is a runtime error to call this
+ // function on files of other types.
+ ArrayRef<Symbol *> getSymbols() { return getMutableSymbols(); }
+
+ std::vector<Symbol *> &getMutableSymbols() {
+ assert(FileKind == BinaryKind || FileKind == ObjKind ||
+ FileKind == BitcodeKind);
+ return Symbols;
+ }
+
+ // Filename of .a which contained this file. If this file was
+ // not in an archive file, it is the empty string. We use this
+ // string for creating error messages.
+ std::string ArchiveName;
+
+ // If this is an architecture-specific file, the following members
+ // have ELF type (i.e. ELF{32,64}{LE,BE}) and target machine type.
+ ELFKind EKind = ELFNoneKind;
+ uint16_t EMachine = llvm::ELF::EM_NONE;
+ uint8_t OSABI = 0;
+
+ // Cache for toString(). Only toString() should use this member.
+ mutable std::string ToStringCache;
+
+ std::string getSrcMsg(const Symbol &Sym, InputSectionBase &Sec,
+ uint64_t Offset);
+
+ // True if this is an argument for --just-symbols. Usually false.
+ bool JustSymbols = false;
+
+ // GroupId is used for --warn-backrefs which is an optional error
+ // checking feature. All files within the same --{start,end}-group or
+ // --{start,end}-lib get the same group ID. Otherwise, each file gets a new
+ // group ID. For more info, see checkDependency() in SymbolTable.cpp.
+ uint32_t GroupId;
+ static bool IsInGroup;
+ static uint32_t NextGroupId;
+
+ // Index of MIPS GOT built for this file.
+ llvm::Optional<size_t> MipsGotIndex;
+
+protected:
+ InputFile(Kind K, MemoryBufferRef M);
+ std::vector<InputSectionBase *> Sections;
+ std::vector<Symbol *> Symbols;
+
+private:
+ const Kind FileKind;
+};
+
+template <typename ELFT> class ELFFileBase : public InputFile {
+public:
+ typedef typename ELFT::Shdr Elf_Shdr;
+ typedef typename ELFT::Sym Elf_Sym;
+ typedef typename ELFT::Word Elf_Word;
+ typedef typename ELFT::SymRange Elf_Sym_Range;
+
+ ELFFileBase(Kind K, MemoryBufferRef M);
+ static bool classof(const InputFile *F) { return F->isElf(); }
+
+ llvm::object::ELFFile<ELFT> getObj() const {
+ return check(llvm::object::ELFFile<ELFT>::create(MB.getBuffer()));
+ }
+
+ StringRef getStringTable() const { return StringTable; }
+
+ uint32_t getSectionIndex(const Elf_Sym &Sym) const;
+
+ Elf_Sym_Range getGlobalELFSyms();
+ Elf_Sym_Range getELFSyms() const { return ELFSyms; }
+
+protected:
+ ArrayRef<Elf_Sym> ELFSyms;
+ uint32_t FirstGlobal = 0;
+ ArrayRef<Elf_Word> SymtabSHNDX;
+ StringRef StringTable;
+ void initSymtab(ArrayRef<Elf_Shdr> Sections, const Elf_Shdr *Symtab);
+};
+
+// .o file.
+template <class ELFT> class ObjFile : public ELFFileBase<ELFT> {
+ typedef ELFFileBase<ELFT> Base;
+ typedef typename ELFT::Rel Elf_Rel;
+ typedef typename ELFT::Rela Elf_Rela;
+ typedef typename ELFT::Sym Elf_Sym;
+ typedef typename ELFT::Shdr Elf_Shdr;
+ typedef typename ELFT::Word Elf_Word;
+ typedef typename ELFT::CGProfile Elf_CGProfile;
+
+ StringRef getShtGroupSignature(ArrayRef<Elf_Shdr> Sections,
+ const Elf_Shdr &Sec);
+
+public:
+ static bool classof(const InputFile *F) { return F->kind() == Base::ObjKind; }
+
+ ArrayRef<Symbol *> getLocalSymbols();
+ ArrayRef<Symbol *> getGlobalSymbols();
+
+ ObjFile(MemoryBufferRef M, StringRef ArchiveName);
+ void parse(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups);
+
+ Symbol &getSymbol(uint32_t SymbolIndex) const {
+ if (SymbolIndex >= this->Symbols.size())
+ fatal(toString(this) + ": invalid symbol index");
+ return *this->Symbols[SymbolIndex];
+ }
+
+ template <typename RelT> Symbol &getRelocTargetSym(const RelT &Rel) const {
+ uint32_t SymIndex = Rel.getSymbol(Config->IsMips64EL);
+ return getSymbol(SymIndex);
+ }
+
+ llvm::Optional<llvm::DILineInfo> getDILineInfo(InputSectionBase *, uint64_t);
+ llvm::Optional<std::pair<std::string, unsigned>> getVariableLoc(StringRef Name);
+
+ // MIPS GP0 value defined by this file. This value represents the gp value
+ // used to create the relocatable object and required to support
+ // R_MIPS_GPREL16 / R_MIPS_GPREL32 relocations.
+ uint32_t MipsGp0 = 0;
+
+ // Name of source file obtained from STT_FILE symbol value,
+ // or empty string if there is no such symbol in object file
+ // symbol table.
+ StringRef SourceFile;
+
+ // True if the file defines functions compiled with
+ // -fsplit-stack. Usually false.
+ bool SplitStack = false;
+
+ // True if the file defines functions compiled with -fsplit-stack,
+ // but had one or more functions with the no_split_stack attribute.
+ bool SomeNoSplitStack = false;
+
+ // Pointer to this input file's .llvm_addrsig section, if it has one.
+ const Elf_Shdr *AddrsigSec = nullptr;
+
+ // SHT_LLVM_CALL_GRAPH_PROFILE table
+ ArrayRef<Elf_CGProfile> CGProfile;
+
+private:
+ void
+ initializeSections(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups);
+ void initializeSymbols();
+ void initializeJustSymbols();
+ void initializeDwarf();
+ InputSectionBase *getRelocTarget(const Elf_Shdr &Sec);
+ InputSectionBase *createInputSection(const Elf_Shdr &Sec);
+ StringRef getSectionName(const Elf_Shdr &Sec);
+
+ bool shouldMerge(const Elf_Shdr &Sec);
+ Symbol *createSymbol(const Elf_Sym *Sym);
+
+ // .shstrtab contents.
+ StringRef SectionStringTable;
+
+ // Debugging information to retrieve source file and line for error
+ // reporting. Linker may find reasonable number of errors in a
+ // single object file, so we cache debugging information in order to
+ // parse it only once for each object file we link.
+ std::unique_ptr<llvm::DWARFContext> Dwarf;
+ std::vector<const llvm::DWARFDebugLine::LineTable *> LineTables;
+ struct VarLoc {
+ const llvm::DWARFDebugLine::LineTable *LT;
+ unsigned File;
+ unsigned Line;
+ };
+ llvm::DenseMap<StringRef, VarLoc> VariableLoc;
+ llvm::once_flag InitDwarfLine;
+};
+
+// LazyObjFile is analogous to ArchiveFile in the sense that
+// the file contains lazy symbols. The difference is that
+// LazyObjFile wraps a single file instead of multiple files.
+//
+// This class is used for --start-lib and --end-lib options which
+// instruct the linker to link object files between them with the
+// archive file semantics.
+class LazyObjFile : public InputFile {
+public:
+ LazyObjFile(MemoryBufferRef M, StringRef ArchiveName,
+ uint64_t OffsetInArchive)
+ : InputFile(LazyObjKind, M), OffsetInArchive(OffsetInArchive) {
+ this->ArchiveName = ArchiveName;
+ }
+
+ static bool classof(const InputFile *F) { return F->kind() == LazyObjKind; }
+
+ template <class ELFT> void parse();
+ MemoryBufferRef getBuffer();
+ InputFile *fetch();
+ bool AddedToLink = false;
+
+private:
+ uint64_t OffsetInArchive;
+};
+
+// An ArchiveFile object represents a .a file.
+class ArchiveFile : public InputFile {
+public:
+ explicit ArchiveFile(std::unique_ptr<Archive> &&File);
+ static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; }
+ template <class ELFT> void parse();
+
+ // Pulls out an object file that contains a definition for Sym and
+ // returns it. If the same file was instantiated before, this
+ // function returns a nullptr (so we don't instantiate the same file
+ // more than once.)
+ InputFile *fetch(const Archive::Symbol &Sym);
+
+private:
+ std::unique_ptr<Archive> File;
+ llvm::DenseSet<uint64_t> Seen;
+};
+
+class BitcodeFile : public InputFile {
+public:
+ BitcodeFile(MemoryBufferRef M, StringRef ArchiveName,
+ uint64_t OffsetInArchive);
+ static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; }
+ template <class ELFT>
+ void parse(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups);
+ std::unique_ptr<llvm::lto::InputFile> Obj;
+};
+
+// .so file.
+template <class ELFT> class SharedFile : public ELFFileBase<ELFT> {
+ typedef ELFFileBase<ELFT> Base;
+ typedef typename ELFT::Dyn Elf_Dyn;
+ typedef typename ELFT::Shdr Elf_Shdr;
+ typedef typename ELFT::Sym Elf_Sym;
+ typedef typename ELFT::SymRange Elf_Sym_Range;
+ typedef typename ELFT::Verdef Elf_Verdef;
+ typedef typename ELFT::Versym Elf_Versym;
+
+ const Elf_Shdr *VersymSec = nullptr;
+ const Elf_Shdr *VerdefSec = nullptr;
+
+public:
+ std::vector<const Elf_Verdef *> Verdefs;
+ std::string SoName;
+
+ static bool classof(const InputFile *F) {
+ return F->kind() == Base::SharedKind;
+ }
+
+ SharedFile(MemoryBufferRef M, StringRef DefaultSoName);
+
+ void parseSoName();
+ void parseRest();
+ uint32_t getAlignment(ArrayRef<Elf_Shdr> Sections, const Elf_Sym &Sym);
+ std::vector<const Elf_Verdef *> parseVerdefs();
+ std::vector<uint32_t> parseVersyms();
+
+ struct NeededVer {
+ // The string table offset of the version name in the output file.
+ size_t StrTab;
+
+ // The version identifier for this version name.
+ uint16_t Index;
+ };
+
+ // Mapping from Elf_Verdef data structures to information about Elf_Vernaux
+ // data structures in the output file.
+ std::map<const Elf_Verdef *, NeededVer> VerdefMap;
+
+ // Used for --as-needed
+ bool IsNeeded;
+};
+
+class BinaryFile : public InputFile {
+public:
+ explicit BinaryFile(MemoryBufferRef M) : InputFile(BinaryKind, M) {}
+ static bool classof(const InputFile *F) { return F->kind() == BinaryKind; }
+ void parse();
+};
+
+InputFile *createObjectFile(MemoryBufferRef MB, StringRef ArchiveName = "",
+ uint64_t OffsetInArchive = 0);
+InputFile *createSharedFile(MemoryBufferRef MB, StringRef DefaultSoName);
+
+inline bool isBitcode(MemoryBufferRef MB) {
+ return identify_magic(MB.getBuffer()) == llvm::file_magic::bitcode;
+}
+
+std::string replaceThinLTOSuffix(StringRef Path);
+
+extern std::vector<BinaryFile *> BinaryFiles;
+extern std::vector<BitcodeFile *> BitcodeFiles;
+extern std::vector<LazyObjFile *> LazyObjFiles;
+extern std::vector<InputFile *> ObjectFiles;
+extern std::vector<InputFile *> SharedFiles;
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/ELF/InputSection.cpp b/contrib/llvm/tools/lld/ELF/InputSection.cpp
new file mode 100644
index 000000000000..839bff7011eb
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/InputSection.cpp
@@ -0,0 +1,1283 @@
+//===- InputSection.cpp ---------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InputSection.h"
+#include "Config.h"
+#include "EhFrame.h"
+#include "InputFiles.h"
+#include "LinkerScript.h"
+#include "OutputSections.h"
+#include "Relocations.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "Thunks.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Memory.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Compression.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Threading.h"
+#include "llvm/Support/xxhash.h"
+#include <algorithm>
+#include <mutex>
+#include <set>
+#include <vector>
+
+using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::object;
+using namespace llvm::support;
+using namespace llvm::support::endian;
+using namespace llvm::sys;
+
+using namespace lld;
+using namespace lld::elf;
+
+std::vector<InputSectionBase *> elf::InputSections;
+
+// Returns a string to construct an error message.
+std::string lld::toString(const InputSectionBase *Sec) {
+ return (toString(Sec->File) + ":(" + Sec->Name + ")").str();
+}
+
+template <class ELFT>
+static ArrayRef<uint8_t> getSectionContents(ObjFile<ELFT> &File,
+ const typename ELFT::Shdr &Hdr) {
+ if (Hdr.sh_type == SHT_NOBITS)
+ return makeArrayRef<uint8_t>(nullptr, Hdr.sh_size);
+ return check(File.getObj().getSectionContents(&Hdr));
+}
+
+InputSectionBase::InputSectionBase(InputFile *File, uint64_t Flags,
+ uint32_t Type, uint64_t Entsize,
+ uint32_t Link, uint32_t Info,
+ uint32_t Alignment, ArrayRef<uint8_t> Data,
+ StringRef Name, Kind SectionKind)
+ : SectionBase(SectionKind, Name, Flags, Entsize, Alignment, Type, Info,
+ Link),
+ File(File), RawData(Data) {
+ // In order to reduce memory allocation, we assume that mergeable
+ // sections are smaller than 4 GiB, which is not an unreasonable
+ // assumption as of 2017.
+ if (SectionKind == SectionBase::Merge && RawData.size() > UINT32_MAX)
+ error(toString(this) + ": section too large");
+
+ NumRelocations = 0;
+ AreRelocsRela = false;
+
+ // The ELF spec states that a value of 0 means the section has
+ // no alignment constraits.
+ uint32_t V = std::max<uint64_t>(Alignment, 1);
+ if (!isPowerOf2_64(V))
+ fatal(toString(File) + ": section sh_addralign is not a power of 2");
+ this->Alignment = V;
+
+ // In ELF, each section can be compressed by zlib, and if compressed,
+ // section name may be mangled by appending "z" (e.g. ".zdebug_info").
+ // If that's the case, demangle section name so that we can handle a
+ // section as if it weren't compressed.
+ if ((Flags & SHF_COMPRESSED) || Name.startswith(".zdebug")) {
+ if (!zlib::isAvailable())
+ error(toString(File) + ": contains a compressed section, " +
+ "but zlib is not available");
+ parseCompressedHeader();
+ }
+}
+
+// Drop SHF_GROUP bit unless we are producing a re-linkable object file.
+// SHF_GROUP is a marker that a section belongs to some comdat group.
+// That flag doesn't make sense in an executable.
+static uint64_t getFlags(uint64_t Flags) {
+ Flags &= ~(uint64_t)SHF_INFO_LINK;
+ if (!Config->Relocatable)
+ Flags &= ~(uint64_t)SHF_GROUP;
+ return Flags;
+}
+
+// GNU assembler 2.24 and LLVM 4.0.0's MC (the newest release as of
+// March 2017) fail to infer section types for sections starting with
+// ".init_array." or ".fini_array.". They set SHT_PROGBITS instead of
+// SHF_INIT_ARRAY. As a result, the following assembler directive
+// creates ".init_array.100" with SHT_PROGBITS, for example.
+//
+// .section .init_array.100, "aw"
+//
+// This function forces SHT_{INIT,FINI}_ARRAY so that we can handle
+// incorrect inputs as if they were correct from the beginning.
+static uint64_t getType(uint64_t Type, StringRef Name) {
+ if (Type == SHT_PROGBITS && Name.startswith(".init_array."))
+ return SHT_INIT_ARRAY;
+ if (Type == SHT_PROGBITS && Name.startswith(".fini_array."))
+ return SHT_FINI_ARRAY;
+ return Type;
+}
+
+template <class ELFT>
+InputSectionBase::InputSectionBase(ObjFile<ELFT> &File,
+ const typename ELFT::Shdr &Hdr,
+ StringRef Name, Kind SectionKind)
+ : InputSectionBase(&File, getFlags(Hdr.sh_flags),
+ getType(Hdr.sh_type, Name), Hdr.sh_entsize, Hdr.sh_link,
+ Hdr.sh_info, Hdr.sh_addralign,
+ getSectionContents(File, Hdr), Name, SectionKind) {
+ // We reject object files having insanely large alignments even though
+ // they are allowed by the spec. I think 4GB is a reasonable limitation.
+ // We might want to relax this in the future.
+ if (Hdr.sh_addralign > UINT32_MAX)
+ fatal(toString(&File) + ": section sh_addralign is too large");
+}
+
+size_t InputSectionBase::getSize() const {
+ if (auto *S = dyn_cast<SyntheticSection>(this))
+ return S->getSize();
+ if (UncompressedSize >= 0)
+ return UncompressedSize;
+ return RawData.size();
+}
+
+void InputSectionBase::uncompress() const {
+ size_t Size = UncompressedSize;
+ UncompressedBuf.reset(new char[Size]);
+
+ if (Error E =
+ zlib::uncompress(toStringRef(RawData), UncompressedBuf.get(), Size))
+ fatal(toString(this) +
+ ": uncompress failed: " + llvm::toString(std::move(E)));
+ RawData = makeArrayRef((uint8_t *)UncompressedBuf.get(), Size);
+}
+
+uint64_t InputSectionBase::getOffsetInFile() const {
+ const uint8_t *FileStart = (const uint8_t *)File->MB.getBufferStart();
+ const uint8_t *SecStart = data().begin();
+ return SecStart - FileStart;
+}
+
+uint64_t SectionBase::getOffset(uint64_t Offset) const {
+ switch (kind()) {
+ case Output: {
+ auto *OS = cast<OutputSection>(this);
+ // For output sections we treat offset -1 as the end of the section.
+ return Offset == uint64_t(-1) ? OS->Size : Offset;
+ }
+ case Regular:
+ case Synthetic:
+ return cast<InputSection>(this)->getOffset(Offset);
+ case EHFrame:
+ // The file crtbeginT.o has relocations pointing to the start of an empty
+ // .eh_frame that is known to be the first in the link. It does that to
+ // identify the start of the output .eh_frame.
+ return Offset;
+ case Merge:
+ const MergeInputSection *MS = cast<MergeInputSection>(this);
+ if (InputSection *IS = MS->getParent())
+ return IS->getOffset(MS->getParentOffset(Offset));
+ return MS->getParentOffset(Offset);
+ }
+ llvm_unreachable("invalid section kind");
+}
+
+uint64_t SectionBase::getVA(uint64_t Offset) const {
+ const OutputSection *Out = getOutputSection();
+ return (Out ? Out->Addr : 0) + getOffset(Offset);
+}
+
+OutputSection *SectionBase::getOutputSection() {
+ InputSection *Sec;
+ if (auto *IS = dyn_cast<InputSection>(this))
+ Sec = IS;
+ else if (auto *MS = dyn_cast<MergeInputSection>(this))
+ Sec = MS->getParent();
+ else if (auto *EH = dyn_cast<EhInputSection>(this))
+ Sec = EH->getParent();
+ else
+ return cast<OutputSection>(this);
+ return Sec ? Sec->getParent() : nullptr;
+}
+
+// When a section is compressed, `RawData` consists with a header followed
+// by zlib-compressed data. This function parses a header to initialize
+// `UncompressedSize` member and remove the header from `RawData`.
+void InputSectionBase::parseCompressedHeader() {
+ typedef typename ELF64LE::Chdr Chdr64;
+ typedef typename ELF32LE::Chdr Chdr32;
+
+ // Old-style header
+ if (Name.startswith(".zdebug")) {
+ if (!toStringRef(RawData).startswith("ZLIB")) {
+ error(toString(this) + ": corrupted compressed section header");
+ return;
+ }
+ RawData = RawData.slice(4);
+
+ if (RawData.size() < 8) {
+ error(toString(this) + ": corrupted compressed section header");
+ return;
+ }
+
+ UncompressedSize = read64be(RawData.data());
+ RawData = RawData.slice(8);
+
+ // Restore the original section name.
+ // (e.g. ".zdebug_info" -> ".debug_info")
+ Name = Saver.save("." + Name.substr(2));
+ return;
+ }
+
+ assert(Flags & SHF_COMPRESSED);
+ Flags &= ~(uint64_t)SHF_COMPRESSED;
+
+ // New-style 64-bit header
+ if (Config->Is64) {
+ if (RawData.size() < sizeof(Chdr64)) {
+ error(toString(this) + ": corrupted compressed section");
+ return;
+ }
+
+ auto *Hdr = reinterpret_cast<const Chdr64 *>(RawData.data());
+ if (Hdr->ch_type != ELFCOMPRESS_ZLIB) {
+ error(toString(this) + ": unsupported compression type");
+ return;
+ }
+
+ UncompressedSize = Hdr->ch_size;
+ RawData = RawData.slice(sizeof(*Hdr));
+ return;
+ }
+
+ // New-style 32-bit header
+ if (RawData.size() < sizeof(Chdr32)) {
+ error(toString(this) + ": corrupted compressed section");
+ return;
+ }
+
+ auto *Hdr = reinterpret_cast<const Chdr32 *>(RawData.data());
+ if (Hdr->ch_type != ELFCOMPRESS_ZLIB) {
+ error(toString(this) + ": unsupported compression type");
+ return;
+ }
+
+ UncompressedSize = Hdr->ch_size;
+ RawData = RawData.slice(sizeof(*Hdr));
+}
+
+InputSection *InputSectionBase::getLinkOrderDep() const {
+ assert(Link);
+ assert(Flags & SHF_LINK_ORDER);
+ return cast<InputSection>(File->getSections()[Link]);
+}
+
+// Find a function symbol that encloses a given location.
+template <class ELFT>
+Defined *InputSectionBase::getEnclosingFunction(uint64_t Offset) {
+ for (Symbol *B : File->getSymbols())
+ if (Defined *D = dyn_cast<Defined>(B))
+ if (D->Section == this && D->Type == STT_FUNC && D->Value <= Offset &&
+ Offset < D->Value + D->Size)
+ return D;
+ return nullptr;
+}
+
+// Returns a source location string. Used to construct an error message.
+template <class ELFT>
+std::string InputSectionBase::getLocation(uint64_t Offset) {
+ std::string SecAndOffset = (Name + "+0x" + utohexstr(Offset)).str();
+
+ // We don't have file for synthetic sections.
+ if (getFile<ELFT>() == nullptr)
+ return (Config->OutputFile + ":(" + SecAndOffset + ")")
+ .str();
+
+ // First check if we can get desired values from debugging information.
+ if (Optional<DILineInfo> Info = getFile<ELFT>()->getDILineInfo(this, Offset))
+ return Info->FileName + ":" + std::to_string(Info->Line) + ":(" +
+ SecAndOffset + ")";
+
+ // File->SourceFile contains STT_FILE symbol that contains a
+ // source file name. If it's missing, we use an object file name.
+ std::string SrcFile = getFile<ELFT>()->SourceFile;
+ if (SrcFile.empty())
+ SrcFile = toString(File);
+
+ if (Defined *D = getEnclosingFunction<ELFT>(Offset))
+ return SrcFile + ":(function " + toString(*D) + ": " + SecAndOffset + ")";
+
+ // If there's no symbol, print out the offset in the section.
+ return (SrcFile + ":(" + SecAndOffset + ")");
+}
+
+// This function is intended to be used for constructing an error message.
+// The returned message looks like this:
+//
+// foo.c:42 (/home/alice/possibly/very/long/path/foo.c:42)
+//
+// Returns an empty string if there's no way to get line info.
+std::string InputSectionBase::getSrcMsg(const Symbol &Sym, uint64_t Offset) {
+ return File->getSrcMsg(Sym, *this, Offset);
+}
+
+// Returns a filename string along with an optional section name. This
+// function is intended to be used for constructing an error
+// message. The returned message looks like this:
+//
+// path/to/foo.o:(function bar)
+//
+// or
+//
+// path/to/foo.o:(function bar) in archive path/to/bar.a
+std::string InputSectionBase::getObjMsg(uint64_t Off) {
+ std::string Filename = File->getName();
+
+ std::string Archive;
+ if (!File->ArchiveName.empty())
+ Archive = " in archive " + File->ArchiveName;
+
+ // Find a symbol that encloses a given location.
+ for (Symbol *B : File->getSymbols())
+ if (auto *D = dyn_cast<Defined>(B))
+ if (D->Section == this && D->Value <= Off && Off < D->Value + D->Size)
+ return Filename + ":(" + toString(*D) + ")" + Archive;
+
+ // If there's no symbol, print out the offset in the section.
+ return (Filename + ":(" + Name + "+0x" + utohexstr(Off) + ")" + Archive)
+ .str();
+}
+
+InputSection InputSection::Discarded(nullptr, 0, 0, 0, ArrayRef<uint8_t>(), "");
+
+InputSection::InputSection(InputFile *F, uint64_t Flags, uint32_t Type,
+ uint32_t Alignment, ArrayRef<uint8_t> Data,
+ StringRef Name, Kind K)
+ : InputSectionBase(F, Flags, Type,
+ /*Entsize*/ 0, /*Link*/ 0, /*Info*/ 0, Alignment, Data,
+ Name, K) {}
+
+template <class ELFT>
+InputSection::InputSection(ObjFile<ELFT> &F, const typename ELFT::Shdr &Header,
+ StringRef Name)
+ : InputSectionBase(F, Header, Name, InputSectionBase::Regular) {}
+
+bool InputSection::classof(const SectionBase *S) {
+ return S->kind() == SectionBase::Regular ||
+ S->kind() == SectionBase::Synthetic;
+}
+
+OutputSection *InputSection::getParent() const {
+ return cast_or_null<OutputSection>(Parent);
+}
+
+// Copy SHT_GROUP section contents. Used only for the -r option.
+template <class ELFT> void InputSection::copyShtGroup(uint8_t *Buf) {
+ // ELFT::Word is the 32-bit integral type in the target endianness.
+ typedef typename ELFT::Word u32;
+ ArrayRef<u32> From = getDataAs<u32>();
+ auto *To = reinterpret_cast<u32 *>(Buf);
+
+ // The first entry is not a section number but a flag.
+ *To++ = From[0];
+
+ // Adjust section numbers because section numbers in an input object
+ // files are different in the output.
+ ArrayRef<InputSectionBase *> Sections = File->getSections();
+ for (uint32_t Idx : From.slice(1))
+ *To++ = Sections[Idx]->getOutputSection()->SectionIndex;
+}
+
+InputSectionBase *InputSection::getRelocatedSection() const {
+ if (!File || (Type != SHT_RELA && Type != SHT_REL))
+ return nullptr;
+ ArrayRef<InputSectionBase *> Sections = File->getSections();
+ return Sections[Info];
+}
+
+// This is used for -r and --emit-relocs. We can't use memcpy to copy
+// relocations because we need to update symbol table offset and section index
+// for each relocation. So we copy relocations one by one.
+template <class ELFT, class RelTy>
+void InputSection::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) {
+ InputSectionBase *Sec = getRelocatedSection();
+
+ for (const RelTy &Rel : Rels) {
+ RelType Type = Rel.getType(Config->IsMips64EL);
+ Symbol &Sym = getFile<ELFT>()->getRelocTargetSym(Rel);
+
+ auto *P = reinterpret_cast<typename ELFT::Rela *>(Buf);
+ Buf += sizeof(RelTy);
+
+ if (RelTy::IsRela)
+ P->r_addend = getAddend<ELFT>(Rel);
+
+ // Output section VA is zero for -r, so r_offset is an offset within the
+ // section, but for --emit-relocs it is an virtual address.
+ P->r_offset = Sec->getVA(Rel.r_offset);
+ P->setSymbolAndType(In.SymTab->getSymbolIndex(&Sym), Type,
+ Config->IsMips64EL);
+
+ if (Sym.Type == STT_SECTION) {
+ // We combine multiple section symbols into only one per
+ // section. This means we have to update the addend. That is
+ // trivial for Elf_Rela, but for Elf_Rel we have to write to the
+ // section data. We do that by adding to the Relocation vector.
+
+ // .eh_frame is horribly special and can reference discarded sections. To
+ // avoid having to parse and recreate .eh_frame, we just replace any
+ // relocation in it pointing to discarded sections with R_*_NONE, which
+ // hopefully creates a frame that is ignored at runtime.
+ auto *D = dyn_cast<Defined>(&Sym);
+ if (!D) {
+ error("STT_SECTION symbol should be defined");
+ continue;
+ }
+ SectionBase *Section = D->Section->Repl;
+ if (!Section->Live) {
+ P->setSymbolAndType(0, 0, false);
+ continue;
+ }
+
+ int64_t Addend = getAddend<ELFT>(Rel);
+ const uint8_t *BufLoc = Sec->data().begin() + Rel.r_offset;
+ if (!RelTy::IsRela)
+ Addend = Target->getImplicitAddend(BufLoc, Type);
+
+ if (Config->EMachine == EM_MIPS && Config->Relocatable &&
+ Target->getRelExpr(Type, Sym, BufLoc) == R_MIPS_GOTREL) {
+ // Some MIPS relocations depend on "gp" value. By default,
+ // this value has 0x7ff0 offset from a .got section. But
+ // relocatable files produced by a complier or a linker
+ // might redefine this default value and we must use it
+ // for a calculation of the relocation result. When we
+ // generate EXE or DSO it's trivial. Generating a relocatable
+ // output is more difficult case because the linker does
+ // not calculate relocations in this mode and loses
+ // individual "gp" values used by each input object file.
+ // As a workaround we add the "gp" value to the relocation
+ // addend and save it back to the file.
+ Addend += Sec->getFile<ELFT>()->MipsGp0;
+ }
+
+ if (RelTy::IsRela)
+ P->r_addend = Sym.getVA(Addend) - Section->getOutputSection()->Addr;
+ else if (Config->Relocatable)
+ Sec->Relocations.push_back({R_ABS, Type, Rel.r_offset, Addend, &Sym});
+ }
+ }
+}
+
+// The ARM and AArch64 ABI handle pc-relative relocations to undefined weak
+// references specially. The general rule is that the value of the symbol in
+// this context is the address of the place P. A further special case is that
+// branch relocations to an undefined weak reference resolve to the next
+// instruction.
+static uint32_t getARMUndefinedRelativeWeakVA(RelType Type, uint32_t A,
+ uint32_t P) {
+ switch (Type) {
+ // Unresolved branch relocations to weak references resolve to next
+ // instruction, this will be either 2 or 4 bytes on from P.
+ case R_ARM_THM_JUMP11:
+ return P + 2 + A;
+ case R_ARM_CALL:
+ case R_ARM_JUMP24:
+ case R_ARM_PC24:
+ case R_ARM_PLT32:
+ case R_ARM_PREL31:
+ case R_ARM_THM_JUMP19:
+ case R_ARM_THM_JUMP24:
+ return P + 4 + A;
+ case R_ARM_THM_CALL:
+ // We don't want an interworking BLX to ARM
+ return P + 5 + A;
+ // Unresolved non branch pc-relative relocations
+ // R_ARM_TARGET2 which can be resolved relatively is not present as it never
+ // targets a weak-reference.
+ case R_ARM_MOVW_PREL_NC:
+ case R_ARM_MOVT_PREL:
+ case R_ARM_REL32:
+ case R_ARM_THM_MOVW_PREL_NC:
+ case R_ARM_THM_MOVT_PREL:
+ return P + A;
+ }
+ llvm_unreachable("ARM pc-relative relocation expected\n");
+}
+
+// The comment above getARMUndefinedRelativeWeakVA applies to this function.
+static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t Type, uint64_t A,
+ uint64_t P) {
+ switch (Type) {
+ // Unresolved branch relocations to weak references resolve to next
+ // instruction, this is 4 bytes on from P.
+ case R_AARCH64_CALL26:
+ case R_AARCH64_CONDBR19:
+ case R_AARCH64_JUMP26:
+ case R_AARCH64_TSTBR14:
+ return P + 4 + A;
+ // Unresolved non branch pc-relative relocations
+ case R_AARCH64_PREL16:
+ case R_AARCH64_PREL32:
+ case R_AARCH64_PREL64:
+ case R_AARCH64_ADR_PREL_LO21:
+ case R_AARCH64_LD_PREL_LO19:
+ return P + A;
+ }
+ llvm_unreachable("AArch64 pc-relative relocation expected\n");
+}
+
+// ARM SBREL relocations are of the form S + A - B where B is the static base
+// The ARM ABI defines base to be "addressing origin of the output segment
+// defining the symbol S". We defined the "addressing origin"/static base to be
+// the base of the PT_LOAD segment containing the Sym.
+// The procedure call standard only defines a Read Write Position Independent
+// RWPI variant so in practice we should expect the static base to be the base
+// of the RW segment.
+static uint64_t getARMStaticBase(const Symbol &Sym) {
+ OutputSection *OS = Sym.getOutputSection();
+ if (!OS || !OS->PtLoad || !OS->PtLoad->FirstSec)
+ fatal("SBREL relocation to " + Sym.getName() + " without static base");
+ return OS->PtLoad->FirstSec->Addr;
+}
+
+// For R_RISCV_PC_INDIRECT (R_RISCV_PCREL_LO12_{I,S}), the symbol actually
+// points the corresponding R_RISCV_PCREL_HI20 relocation, and the target VA
+// is calculated using PCREL_HI20's symbol.
+//
+// This function returns the R_RISCV_PCREL_HI20 relocation from
+// R_RISCV_PCREL_LO12's symbol and addend.
+static Relocation *getRISCVPCRelHi20(const Symbol *Sym, uint64_t Addend) {
+ const Defined *D = cast<Defined>(Sym);
+ InputSection *IS = cast<InputSection>(D->Section);
+
+ if (Addend != 0)
+ warn("Non-zero addend in R_RISCV_PCREL_LO12 relocation to " +
+ IS->getObjMsg(D->Value) + " is ignored");
+
+ // Relocations are sorted by offset, so we can use std::equal_range to do
+ // binary search.
+ auto Range = std::equal_range(IS->Relocations.begin(), IS->Relocations.end(),
+ D->Value, RelocationOffsetComparator{});
+ for (auto It = std::get<0>(Range); It != std::get<1>(Range); ++It)
+ if (isRelExprOneOf<R_PC>(It->Expr))
+ return &*It;
+
+ error("R_RISCV_PCREL_LO12 relocation points to " + IS->getObjMsg(D->Value) +
+ " without an associated R_RISCV_PCREL_HI20 relocation");
+ return nullptr;
+}
+
+// A TLS symbol's virtual address is relative to the TLS segment. Add a
+// target-specific adjustment to produce a thread-pointer-relative offset.
+static int64_t getTlsTpOffset() {
+ switch (Config->EMachine) {
+ case EM_ARM:
+ case EM_AARCH64:
+ // Variant 1. The thread pointer points to a TCB with a fixed 2-word size,
+ // followed by a variable amount of alignment padding, followed by the TLS
+ // segment.
+ //
+ // NB: While the ARM/AArch64 ABI formally has a 2-word TCB size, lld
+ // effectively increases the TCB size to 8 words for Android compatibility.
+ // It accomplishes this by increasing the segment's alignment.
+ return alignTo(Config->Wordsize * 2, Out::TlsPhdr->p_align);
+ case EM_386:
+ case EM_X86_64:
+ // Variant 2. The TLS segment is located just before the thread pointer.
+ return -Out::TlsPhdr->p_memsz;
+ case EM_PPC64:
+ // The thread pointer points to a fixed offset from the start of the
+ // executable's TLS segment. An offset of 0x7000 allows a signed 16-bit
+ // offset to reach 0x1000 of TCB/thread-library data and 0xf000 of the
+ // program's TLS segment.
+ return -0x7000;
+ default:
+ llvm_unreachable("unhandled Config->EMachine");
+ }
+}
+
+static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, int64_t A,
+ uint64_t P, const Symbol &Sym, RelExpr Expr) {
+ switch (Expr) {
+ case R_INVALID:
+ return 0;
+ case R_ABS:
+ case R_RELAX_TLS_LD_TO_LE_ABS:
+ case R_RELAX_GOT_PC_NOPIC:
+ return Sym.getVA(A);
+ case R_ADDEND:
+ return A;
+ case R_ARM_SBREL:
+ return Sym.getVA(A) - getARMStaticBase(Sym);
+ case R_GOT:
+ case R_GOT_PLT:
+ case R_RELAX_TLS_GD_TO_IE_ABS:
+ return Sym.getGotVA() + A;
+ case R_GOTONLY_PC:
+ return In.Got->getVA() + A - P;
+ case R_GOTONLY_PC_FROM_END:
+ return In.Got->getVA() + A - P + In.Got->getSize();
+ case R_GOTREL:
+ return Sym.getVA(A) - In.Got->getVA();
+ case R_GOTREL_FROM_END:
+ return Sym.getVA(A) - In.Got->getVA() - In.Got->getSize();
+ case R_GOT_FROM_END:
+ case R_RELAX_TLS_GD_TO_IE_END:
+ return Sym.getGotOffset() + A - In.Got->getSize();
+ case R_TLSLD_GOT_OFF:
+ case R_GOT_OFF:
+ case R_RELAX_TLS_GD_TO_IE_GOT_OFF:
+ return Sym.getGotOffset() + A;
+ case R_AARCH64_GOT_PAGE_PC:
+ case R_AARCH64_GOT_PAGE_PC_PLT:
+ case R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC:
+ return getAArch64Page(Sym.getGotVA() + A) - getAArch64Page(P);
+ case R_GOT_PC:
+ case R_RELAX_TLS_GD_TO_IE:
+ return Sym.getGotVA() + A - P;
+ case R_HEXAGON_GOT:
+ return Sym.getGotVA() - In.GotPlt->getVA();
+ case R_MIPS_GOTREL:
+ return Sym.getVA(A) - In.MipsGot->getGp(File);
+ case R_MIPS_GOT_GP:
+ return In.MipsGot->getGp(File) + A;
+ case R_MIPS_GOT_GP_PC: {
+ // R_MIPS_LO16 expression has R_MIPS_GOT_GP_PC type iif the target
+ // is _gp_disp symbol. In that case we should use the following
+ // formula for calculation "AHL + GP - P + 4". For details see p. 4-19 at
+ // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+ // microMIPS variants of these relocations use slightly different
+ // expressions: AHL + GP - P + 3 for %lo() and AHL + GP - P - 1 for %hi()
+ // to correctly handle less-sugnificant bit of the microMIPS symbol.
+ uint64_t V = In.MipsGot->getGp(File) + A - P;
+ if (Type == R_MIPS_LO16 || Type == R_MICROMIPS_LO16)
+ V += 4;
+ if (Type == R_MICROMIPS_LO16 || Type == R_MICROMIPS_HI16)
+ V -= 1;
+ return V;
+ }
+ case R_MIPS_GOT_LOCAL_PAGE:
+ // If relocation against MIPS local symbol requires GOT entry, this entry
+ // should be initialized by 'page address'. This address is high 16-bits
+ // of sum the symbol's value and the addend.
+ return In.MipsGot->getVA() + In.MipsGot->getPageEntryOffset(File, Sym, A) -
+ In.MipsGot->getGp(File);
+ case R_MIPS_GOT_OFF:
+ case R_MIPS_GOT_OFF32:
+ // In case of MIPS if a GOT relocation has non-zero addend this addend
+ // should be applied to the GOT entry content not to the GOT entry offset.
+ // That is why we use separate expression type.
+ return In.MipsGot->getVA() + In.MipsGot->getSymEntryOffset(File, Sym, A) -
+ In.MipsGot->getGp(File);
+ case R_MIPS_TLSGD:
+ return In.MipsGot->getVA() + In.MipsGot->getGlobalDynOffset(File, Sym) -
+ In.MipsGot->getGp(File);
+ case R_MIPS_TLSLD:
+ return In.MipsGot->getVA() + In.MipsGot->getTlsIndexOffset(File) -
+ In.MipsGot->getGp(File);
+ case R_AARCH64_PAGE_PC: {
+ uint64_t Val = Sym.isUndefWeak() ? P + A : Sym.getVA(A);
+ return getAArch64Page(Val) - getAArch64Page(P);
+ }
+ case R_AARCH64_PLT_PAGE_PC: {
+ uint64_t Val = Sym.isUndefWeak() ? P + A : Sym.getPltVA() + A;
+ return getAArch64Page(Val) - getAArch64Page(P);
+ }
+ case R_RISCV_PC_INDIRECT: {
+ if (const Relocation *HiRel = getRISCVPCRelHi20(&Sym, A))
+ return getRelocTargetVA(File, HiRel->Type, HiRel->Addend, Sym.getVA(),
+ *HiRel->Sym, HiRel->Expr);
+ return 0;
+ }
+ case R_PC: {
+ uint64_t Dest;
+ if (Sym.isUndefWeak()) {
+ // On ARM and AArch64 a branch to an undefined weak resolves to the
+ // next instruction, otherwise the place.
+ if (Config->EMachine == EM_ARM)
+ Dest = getARMUndefinedRelativeWeakVA(Type, A, P);
+ else if (Config->EMachine == EM_AARCH64)
+ Dest = getAArch64UndefinedRelativeWeakVA(Type, A, P);
+ else
+ Dest = Sym.getVA(A);
+ } else {
+ Dest = Sym.getVA(A);
+ }
+ return Dest - P;
+ }
+ case R_PLT:
+ return Sym.getPltVA() + A;
+ case R_PLT_PC:
+ case R_PPC_CALL_PLT:
+ return Sym.getPltVA() + A - P;
+ case R_PPC_CALL: {
+ uint64_t SymVA = Sym.getVA(A);
+ // If we have an undefined weak symbol, we might get here with a symbol
+ // address of zero. That could overflow, but the code must be unreachable,
+ // so don't bother doing anything at all.
+ if (!SymVA)
+ return 0;
+
+ // PPC64 V2 ABI describes two entry points to a function. The global entry
+ // point is used for calls where the caller and callee (may) have different
+ // TOC base pointers and r2 needs to be modified to hold the TOC base for
+ // the callee. For local calls the caller and callee share the same
+ // TOC base and so the TOC pointer initialization code should be skipped by
+ // branching to the local entry point.
+ return SymVA - P + getPPC64GlobalEntryToLocalEntryOffset(Sym.StOther);
+ }
+ case R_PPC_TOC:
+ return getPPC64TocBase() + A;
+ case R_RELAX_GOT_PC:
+ return Sym.getVA(A) - P;
+ case R_RELAX_TLS_GD_TO_LE:
+ case R_RELAX_TLS_IE_TO_LE:
+ case R_RELAX_TLS_LD_TO_LE:
+ case R_TLS:
+ // A weak undefined TLS symbol resolves to the base of the TLS
+ // block, i.e. gets a value of zero. If we pass --gc-sections to
+ // lld and .tbss is not referenced, it gets reclaimed and we don't
+ // create a TLS program header. Therefore, we resolve this
+ // statically to zero.
+ if (Sym.isTls() && Sym.isUndefWeak())
+ return 0;
+ return Sym.getVA(A) + getTlsTpOffset();
+ case R_RELAX_TLS_GD_TO_LE_NEG:
+ case R_NEG_TLS:
+ return Out::TlsPhdr->p_memsz - Sym.getVA(A);
+ case R_SIZE:
+ return Sym.getSize() + A;
+ case R_TLSDESC:
+ return In.Got->getGlobalDynAddr(Sym) + A;
+ case R_AARCH64_TLSDESC_PAGE:
+ return getAArch64Page(In.Got->getGlobalDynAddr(Sym) + A) -
+ getAArch64Page(P);
+ case R_TLSGD_GOT:
+ return In.Got->getGlobalDynOffset(Sym) + A;
+ case R_TLSGD_GOT_FROM_END:
+ return In.Got->getGlobalDynOffset(Sym) + A - In.Got->getSize();
+ case R_TLSGD_PC:
+ return In.Got->getGlobalDynAddr(Sym) + A - P;
+ case R_TLSLD_GOT_FROM_END:
+ return In.Got->getTlsIndexOff() + A - In.Got->getSize();
+ case R_TLSLD_GOT:
+ return In.Got->getTlsIndexOff() + A;
+ case R_TLSLD_PC:
+ return In.Got->getTlsIndexVA() + A - P;
+ default:
+ llvm_unreachable("invalid expression");
+ }
+}
+
+// This function applies relocations to sections without SHF_ALLOC bit.
+// Such sections are never mapped to memory at runtime. Debug sections are
+// an example. Relocations in non-alloc sections are much easier to
+// handle than in allocated sections because it will never need complex
+// treatement such as GOT or PLT (because at runtime no one refers them).
+// So, we handle relocations for non-alloc sections directly in this
+// function as a performance optimization.
+template <class ELFT, class RelTy>
+void InputSection::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) {
+ const unsigned Bits = sizeof(typename ELFT::uint) * 8;
+
+ for (const RelTy &Rel : Rels) {
+ RelType Type = Rel.getType(Config->IsMips64EL);
+
+ // GCC 8.0 or earlier have a bug that they emit R_386_GOTPC relocations
+ // against _GLOBAL_OFFSET_TABLE_ for .debug_info. The bug has been fixed
+ // in 2017 (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82630), but we
+ // need to keep this bug-compatible code for a while.
+ if (Config->EMachine == EM_386 && Type == R_386_GOTPC)
+ continue;
+
+ uint64_t Offset = getOffset(Rel.r_offset);
+ uint8_t *BufLoc = Buf + Offset;
+ int64_t Addend = getAddend<ELFT>(Rel);
+ if (!RelTy::IsRela)
+ Addend += Target->getImplicitAddend(BufLoc, Type);
+
+ Symbol &Sym = getFile<ELFT>()->getRelocTargetSym(Rel);
+ RelExpr Expr = Target->getRelExpr(Type, Sym, BufLoc);
+ if (Expr == R_NONE)
+ continue;
+
+ if (Expr != R_ABS) {
+ std::string Msg = getLocation<ELFT>(Offset) +
+ ": has non-ABS relocation " + toString(Type) +
+ " against symbol '" + toString(Sym) + "'";
+ if (Expr != R_PC) {
+ error(Msg);
+ return;
+ }
+
+ // If the control reaches here, we found a PC-relative relocation in a
+ // non-ALLOC section. Since non-ALLOC section is not loaded into memory
+ // at runtime, the notion of PC-relative doesn't make sense here. So,
+ // this is a usage error. However, GNU linkers historically accept such
+ // relocations without any errors and relocate them as if they were at
+ // address 0. For bug-compatibilty, we accept them with warnings. We
+ // know Steel Bank Common Lisp as of 2018 have this bug.
+ warn(Msg);
+ Target->relocateOne(BufLoc, Type,
+ SignExtend64<Bits>(Sym.getVA(Addend - Offset)));
+ continue;
+ }
+
+ if (Sym.isTls() && !Out::TlsPhdr)
+ Target->relocateOne(BufLoc, Type, 0);
+ else
+ Target->relocateOne(BufLoc, Type, SignExtend64<Bits>(Sym.getVA(Addend)));
+ }
+}
+
+// This is used when '-r' is given.
+// For REL targets, InputSection::copyRelocations() may store artificial
+// relocations aimed to update addends. They are handled in relocateAlloc()
+// for allocatable sections, and this function does the same for
+// non-allocatable sections, such as sections with debug information.
+static void relocateNonAllocForRelocatable(InputSection *Sec, uint8_t *Buf) {
+ const unsigned Bits = Config->Is64 ? 64 : 32;
+
+ for (const Relocation &Rel : Sec->Relocations) {
+ // InputSection::copyRelocations() adds only R_ABS relocations.
+ assert(Rel.Expr == R_ABS);
+ uint8_t *BufLoc = Buf + Rel.Offset + Sec->OutSecOff;
+ uint64_t TargetVA = SignExtend64(Rel.Sym->getVA(Rel.Addend), Bits);
+ Target->relocateOne(BufLoc, Rel.Type, TargetVA);
+ }
+}
+
+template <class ELFT>
+void InputSectionBase::relocate(uint8_t *Buf, uint8_t *BufEnd) {
+ if (Flags & SHF_EXECINSTR)
+ adjustSplitStackFunctionPrologues<ELFT>(Buf, BufEnd);
+
+ if (Flags & SHF_ALLOC) {
+ relocateAlloc(Buf, BufEnd);
+ return;
+ }
+
+ auto *Sec = cast<InputSection>(this);
+ if (Config->Relocatable)
+ relocateNonAllocForRelocatable(Sec, Buf);
+ else if (Sec->AreRelocsRela)
+ Sec->relocateNonAlloc<ELFT>(Buf, Sec->template relas<ELFT>());
+ else
+ Sec->relocateNonAlloc<ELFT>(Buf, Sec->template rels<ELFT>());
+}
+
+void InputSectionBase::relocateAlloc(uint8_t *Buf, uint8_t *BufEnd) {
+ assert(Flags & SHF_ALLOC);
+ const unsigned Bits = Config->Wordsize * 8;
+
+ for (const Relocation &Rel : Relocations) {
+ uint64_t Offset = Rel.Offset;
+ if (auto *Sec = dyn_cast<InputSection>(this))
+ Offset += Sec->OutSecOff;
+ uint8_t *BufLoc = Buf + Offset;
+ RelType Type = Rel.Type;
+
+ uint64_t AddrLoc = getOutputSection()->Addr + Offset;
+ RelExpr Expr = Rel.Expr;
+ uint64_t TargetVA = SignExtend64(
+ getRelocTargetVA(File, Type, Rel.Addend, AddrLoc, *Rel.Sym, Expr),
+ Bits);
+
+ switch (Expr) {
+ case R_RELAX_GOT_PC:
+ case R_RELAX_GOT_PC_NOPIC:
+ Target->relaxGot(BufLoc, TargetVA);
+ break;
+ case R_RELAX_TLS_IE_TO_LE:
+ Target->relaxTlsIeToLe(BufLoc, Type, TargetVA);
+ break;
+ case R_RELAX_TLS_LD_TO_LE:
+ case R_RELAX_TLS_LD_TO_LE_ABS:
+ Target->relaxTlsLdToLe(BufLoc, Type, TargetVA);
+ break;
+ case R_RELAX_TLS_GD_TO_LE:
+ case R_RELAX_TLS_GD_TO_LE_NEG:
+ Target->relaxTlsGdToLe(BufLoc, Type, TargetVA);
+ break;
+ case R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC:
+ case R_RELAX_TLS_GD_TO_IE:
+ case R_RELAX_TLS_GD_TO_IE_ABS:
+ case R_RELAX_TLS_GD_TO_IE_GOT_OFF:
+ case R_RELAX_TLS_GD_TO_IE_END:
+ Target->relaxTlsGdToIe(BufLoc, Type, TargetVA);
+ break;
+ case R_PPC_CALL:
+ // If this is a call to __tls_get_addr, it may be part of a TLS
+ // sequence that has been relaxed and turned into a nop. In this
+ // case, we don't want to handle it as a call.
+ if (read32(BufLoc) == 0x60000000) // nop
+ break;
+
+ // Patch a nop (0x60000000) to a ld.
+ if (Rel.Sym->NeedsTocRestore) {
+ if (BufLoc + 8 > BufEnd || read32(BufLoc + 4) != 0x60000000) {
+ error(getErrorLocation(BufLoc) + "call lacks nop, can't restore toc");
+ break;
+ }
+ write32(BufLoc + 4, 0xe8410018); // ld %r2, 24(%r1)
+ }
+ Target->relocateOne(BufLoc, Type, TargetVA);
+ break;
+ default:
+ Target->relocateOne(BufLoc, Type, TargetVA);
+ break;
+ }
+ }
+}
+
+// For each function-defining prologue, find any calls to __morestack,
+// and replace them with calls to __morestack_non_split.
+static void switchMorestackCallsToMorestackNonSplit(
+ DenseSet<Defined *> &Prologues, std::vector<Relocation *> &MorestackCalls) {
+
+ // If the target adjusted a function's prologue, all calls to
+ // __morestack inside that function should be switched to
+ // __morestack_non_split.
+ Symbol *MoreStackNonSplit = Symtab->find("__morestack_non_split");
+ if (!MoreStackNonSplit) {
+ error("Mixing split-stack objects requires a definition of "
+ "__morestack_non_split");
+ return;
+ }
+
+ // Sort both collections to compare addresses efficiently.
+ llvm::sort(MorestackCalls, [](const Relocation *L, const Relocation *R) {
+ return L->Offset < R->Offset;
+ });
+ std::vector<Defined *> Functions(Prologues.begin(), Prologues.end());
+ llvm::sort(Functions, [](const Defined *L, const Defined *R) {
+ return L->Value < R->Value;
+ });
+
+ auto It = MorestackCalls.begin();
+ for (Defined *F : Functions) {
+ // Find the first call to __morestack within the function.
+ while (It != MorestackCalls.end() && (*It)->Offset < F->Value)
+ ++It;
+ // Adjust all calls inside the function.
+ while (It != MorestackCalls.end() && (*It)->Offset < F->Value + F->Size) {
+ (*It)->Sym = MoreStackNonSplit;
+ ++It;
+ }
+ }
+}
+
+static bool enclosingPrologueAttempted(uint64_t Offset,
+ const DenseSet<Defined *> &Prologues) {
+ for (Defined *F : Prologues)
+ if (F->Value <= Offset && Offset < F->Value + F->Size)
+ return true;
+ return false;
+}
+
+// If a function compiled for split stack calls a function not
+// compiled for split stack, then the caller needs its prologue
+// adjusted to ensure that the called function will have enough stack
+// available. Find those functions, and adjust their prologues.
+template <class ELFT>
+void InputSectionBase::adjustSplitStackFunctionPrologues(uint8_t *Buf,
+ uint8_t *End) {
+ if (!getFile<ELFT>()->SplitStack)
+ return;
+ DenseSet<Defined *> Prologues;
+ std::vector<Relocation *> MorestackCalls;
+
+ for (Relocation &Rel : Relocations) {
+ // Local symbols can't possibly be cross-calls, and should have been
+ // resolved long before this line.
+ if (Rel.Sym->isLocal())
+ continue;
+
+ // Ignore calls into the split-stack api.
+ if (Rel.Sym->getName().startswith("__morestack")) {
+ if (Rel.Sym->getName().equals("__morestack"))
+ MorestackCalls.push_back(&Rel);
+ continue;
+ }
+
+ // A relocation to non-function isn't relevant. Sometimes
+ // __morestack is not marked as a function, so this check comes
+ // after the name check.
+ if (Rel.Sym->Type != STT_FUNC)
+ continue;
+
+ // If the callee's-file was compiled with split stack, nothing to do. In
+ // this context, a "Defined" symbol is one "defined by the binary currently
+ // being produced". So an "undefined" symbol might be provided by a shared
+ // library. It is not possible to tell how such symbols were compiled, so be
+ // conservative.
+ if (Defined *D = dyn_cast<Defined>(Rel.Sym))
+ if (InputSection *IS = cast_or_null<InputSection>(D->Section))
+ if (!IS || !IS->getFile<ELFT>() || IS->getFile<ELFT>()->SplitStack)
+ continue;
+
+ if (enclosingPrologueAttempted(Rel.Offset, Prologues))
+ continue;
+
+ if (Defined *F = getEnclosingFunction<ELFT>(Rel.Offset)) {
+ Prologues.insert(F);
+ if (Target->adjustPrologueForCrossSplitStack(Buf + getOffset(F->Value),
+ End, F->StOther))
+ continue;
+ if (!getFile<ELFT>()->SomeNoSplitStack)
+ error(lld::toString(this) + ": " + F->getName() +
+ " (with -fsplit-stack) calls " + Rel.Sym->getName() +
+ " (without -fsplit-stack), but couldn't adjust its prologue");
+ }
+ }
+
+ if (Target->NeedsMoreStackNonSplit)
+ switchMorestackCallsToMorestackNonSplit(Prologues, MorestackCalls);
+}
+
+template <class ELFT> void InputSection::writeTo(uint8_t *Buf) {
+ if (Type == SHT_NOBITS)
+ return;
+
+ if (auto *S = dyn_cast<SyntheticSection>(this)) {
+ S->writeTo(Buf + OutSecOff);
+ return;
+ }
+
+ // If -r or --emit-relocs is given, then an InputSection
+ // may be a relocation section.
+ if (Type == SHT_RELA) {
+ copyRelocations<ELFT>(Buf + OutSecOff, getDataAs<typename ELFT::Rela>());
+ return;
+ }
+ if (Type == SHT_REL) {
+ copyRelocations<ELFT>(Buf + OutSecOff, getDataAs<typename ELFT::Rel>());
+ return;
+ }
+
+ // If -r is given, we may have a SHT_GROUP section.
+ if (Type == SHT_GROUP) {
+ copyShtGroup<ELFT>(Buf + OutSecOff);
+ return;
+ }
+
+ // If this is a compressed section, uncompress section contents directly
+ // to the buffer.
+ if (UncompressedSize >= 0 && !UncompressedBuf) {
+ size_t Size = UncompressedSize;
+ if (Error E = zlib::uncompress(toStringRef(RawData),
+ (char *)(Buf + OutSecOff), Size))
+ fatal(toString(this) +
+ ": uncompress failed: " + llvm::toString(std::move(E)));
+ uint8_t *BufEnd = Buf + OutSecOff + Size;
+ relocate<ELFT>(Buf, BufEnd);
+ return;
+ }
+
+ // Copy section contents from source object file to output file
+ // and then apply relocations.
+ memcpy(Buf + OutSecOff, data().data(), data().size());
+ uint8_t *BufEnd = Buf + OutSecOff + data().size();
+ relocate<ELFT>(Buf, BufEnd);
+}
+
+void InputSection::replace(InputSection *Other) {
+ Alignment = std::max(Alignment, Other->Alignment);
+ Other->Repl = Repl;
+ Other->Live = false;
+}
+
+template <class ELFT>
+EhInputSection::EhInputSection(ObjFile<ELFT> &F,
+ const typename ELFT::Shdr &Header,
+ StringRef Name)
+ : InputSectionBase(F, Header, Name, InputSectionBase::EHFrame) {}
+
+SyntheticSection *EhInputSection::getParent() const {
+ return cast_or_null<SyntheticSection>(Parent);
+}
+
+// Returns the index of the first relocation that points to a region between
+// Begin and Begin+Size.
+template <class IntTy, class RelTy>
+static unsigned getReloc(IntTy Begin, IntTy Size, const ArrayRef<RelTy> &Rels,
+ unsigned &RelocI) {
+ // Start search from RelocI for fast access. That works because the
+ // relocations are sorted in .eh_frame.
+ for (unsigned N = Rels.size(); RelocI < N; ++RelocI) {
+ const RelTy &Rel = Rels[RelocI];
+ if (Rel.r_offset < Begin)
+ continue;
+
+ if (Rel.r_offset < Begin + Size)
+ return RelocI;
+ return -1;
+ }
+ return -1;
+}
+
+// .eh_frame is a sequence of CIE or FDE records.
+// This function splits an input section into records and returns them.
+template <class ELFT> void EhInputSection::split() {
+ if (AreRelocsRela)
+ split<ELFT>(relas<ELFT>());
+ else
+ split<ELFT>(rels<ELFT>());
+}
+
+template <class ELFT, class RelTy>
+void EhInputSection::split(ArrayRef<RelTy> Rels) {
+ unsigned RelI = 0;
+ for (size_t Off = 0, End = data().size(); Off != End;) {
+ size_t Size = readEhRecordSize(this, Off);
+ Pieces.emplace_back(Off, this, Size, getReloc(Off, Size, Rels, RelI));
+ // The empty record is the end marker.
+ if (Size == 4)
+ break;
+ Off += Size;
+ }
+}
+
+static size_t findNull(StringRef S, size_t EntSize) {
+ // Optimize the common case.
+ if (EntSize == 1)
+ return S.find(0);
+
+ for (unsigned I = 0, N = S.size(); I != N; I += EntSize) {
+ const char *B = S.begin() + I;
+ if (std::all_of(B, B + EntSize, [](char C) { return C == 0; }))
+ return I;
+ }
+ return StringRef::npos;
+}
+
+SyntheticSection *MergeInputSection::getParent() const {
+ return cast_or_null<SyntheticSection>(Parent);
+}
+
+// Split SHF_STRINGS section. Such section is a sequence of
+// null-terminated strings.
+void MergeInputSection::splitStrings(ArrayRef<uint8_t> Data, size_t EntSize) {
+ size_t Off = 0;
+ bool IsAlloc = Flags & SHF_ALLOC;
+ StringRef S = toStringRef(Data);
+
+ while (!S.empty()) {
+ size_t End = findNull(S, EntSize);
+ if (End == StringRef::npos)
+ fatal(toString(this) + ": string is not null terminated");
+ size_t Size = End + EntSize;
+
+ Pieces.emplace_back(Off, xxHash64(S.substr(0, Size)), !IsAlloc);
+ S = S.substr(Size);
+ Off += Size;
+ }
+}
+
+// Split non-SHF_STRINGS section. Such section is a sequence of
+// fixed size records.
+void MergeInputSection::splitNonStrings(ArrayRef<uint8_t> Data,
+ size_t EntSize) {
+ size_t Size = Data.size();
+ assert((Size % EntSize) == 0);
+ bool IsAlloc = Flags & SHF_ALLOC;
+
+ for (size_t I = 0; I != Size; I += EntSize)
+ Pieces.emplace_back(I, xxHash64(Data.slice(I, EntSize)), !IsAlloc);
+}
+
+template <class ELFT>
+MergeInputSection::MergeInputSection(ObjFile<ELFT> &F,
+ const typename ELFT::Shdr &Header,
+ StringRef Name)
+ : InputSectionBase(F, Header, Name, InputSectionBase::Merge) {}
+
+MergeInputSection::MergeInputSection(uint64_t Flags, uint32_t Type,
+ uint64_t Entsize, ArrayRef<uint8_t> Data,
+ StringRef Name)
+ : InputSectionBase(nullptr, Flags, Type, Entsize, /*Link*/ 0, /*Info*/ 0,
+ /*Alignment*/ Entsize, Data, Name, SectionBase::Merge) {}
+
+// This function is called after we obtain a complete list of input sections
+// that need to be linked. This is responsible to split section contents
+// into small chunks for further processing.
+//
+// Note that this function is called from parallelForEach. This must be
+// thread-safe (i.e. no memory allocation from the pools).
+void MergeInputSection::splitIntoPieces() {
+ assert(Pieces.empty());
+
+ if (Flags & SHF_STRINGS)
+ splitStrings(data(), Entsize);
+ else
+ splitNonStrings(data(), Entsize);
+}
+
+SectionPiece *MergeInputSection::getSectionPiece(uint64_t Offset) {
+ if (this->data().size() <= Offset)
+ fatal(toString(this) + ": offset is outside the section");
+
+ // If Offset is not at beginning of a section piece, it is not in the map.
+ // In that case we need to do a binary search of the original section piece vector.
+ auto It2 =
+ llvm::upper_bound(Pieces, Offset, [](uint64_t Offset, SectionPiece P) {
+ return Offset < P.InputOff;
+ });
+ return &It2[-1];
+}
+
+// Returns the offset in an output section for a given input offset.
+// Because contents of a mergeable section is not contiguous in output,
+// it is not just an addition to a base output offset.
+uint64_t MergeInputSection::getParentOffset(uint64_t Offset) const {
+ // If Offset is not at beginning of a section piece, it is not in the map.
+ // In that case we need to search from the original section piece vector.
+ const SectionPiece &Piece =
+ *(const_cast<MergeInputSection *>(this)->getSectionPiece (Offset));
+ uint64_t Addend = Offset - Piece.InputOff;
+ return Piece.OutputOff + Addend;
+}
+
+template InputSection::InputSection(ObjFile<ELF32LE> &, const ELF32LE::Shdr &,
+ StringRef);
+template InputSection::InputSection(ObjFile<ELF32BE> &, const ELF32BE::Shdr &,
+ StringRef);
+template InputSection::InputSection(ObjFile<ELF64LE> &, const ELF64LE::Shdr &,
+ StringRef);
+template InputSection::InputSection(ObjFile<ELF64BE> &, const ELF64BE::Shdr &,
+ StringRef);
+
+template std::string InputSectionBase::getLocation<ELF32LE>(uint64_t);
+template std::string InputSectionBase::getLocation<ELF32BE>(uint64_t);
+template std::string InputSectionBase::getLocation<ELF64LE>(uint64_t);
+template std::string InputSectionBase::getLocation<ELF64BE>(uint64_t);
+
+template void InputSection::writeTo<ELF32LE>(uint8_t *);
+template void InputSection::writeTo<ELF32BE>(uint8_t *);
+template void InputSection::writeTo<ELF64LE>(uint8_t *);
+template void InputSection::writeTo<ELF64BE>(uint8_t *);
+
+template MergeInputSection::MergeInputSection(ObjFile<ELF32LE> &,
+ const ELF32LE::Shdr &, StringRef);
+template MergeInputSection::MergeInputSection(ObjFile<ELF32BE> &,
+ const ELF32BE::Shdr &, StringRef);
+template MergeInputSection::MergeInputSection(ObjFile<ELF64LE> &,
+ const ELF64LE::Shdr &, StringRef);
+template MergeInputSection::MergeInputSection(ObjFile<ELF64BE> &,
+ const ELF64BE::Shdr &, StringRef);
+
+template EhInputSection::EhInputSection(ObjFile<ELF32LE> &,
+ const ELF32LE::Shdr &, StringRef);
+template EhInputSection::EhInputSection(ObjFile<ELF32BE> &,
+ const ELF32BE::Shdr &, StringRef);
+template EhInputSection::EhInputSection(ObjFile<ELF64LE> &,
+ const ELF64LE::Shdr &, StringRef);
+template EhInputSection::EhInputSection(ObjFile<ELF64BE> &,
+ const ELF64BE::Shdr &, StringRef);
+
+template void EhInputSection::split<ELF32LE>();
+template void EhInputSection::split<ELF32BE>();
+template void EhInputSection::split<ELF64LE>();
+template void EhInputSection::split<ELF64BE>();
diff --git a/contrib/llvm/tools/lld/ELF/InputSection.h b/contrib/llvm/tools/lld/ELF/InputSection.h
new file mode 100644
index 000000000000..34f411e87200
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/InputSection.h
@@ -0,0 +1,369 @@
+//===- InputSection.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_INPUT_SECTION_H
+#define LLD_ELF_INPUT_SECTION_H
+
+#include "Config.h"
+#include "Relocations.h"
+#include "Thunks.h"
+#include "lld/Common/LLVM.h"
+#include "llvm/ADT/CachedHashString.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/TinyPtrVector.h"
+#include "llvm/Object/ELF.h"
+
+namespace lld {
+namespace elf {
+
+class Symbol;
+struct SectionPiece;
+
+class Defined;
+class SyntheticSection;
+class MergeSyntheticSection;
+template <class ELFT> class ObjFile;
+class OutputSection;
+
+// This is the base class of all sections that lld handles. Some are sections in
+// input files, some are sections in the produced output file and some exist
+// just as a convenience for implementing special ways of combining some
+// sections.
+class SectionBase {
+public:
+ enum Kind { Regular, EHFrame, Merge, Synthetic, Output };
+
+ Kind kind() const { return (Kind)SectionKind; }
+
+ StringRef Name;
+
+ // This pointer points to the "real" instance of this instance.
+ // Usually Repl == this. However, if ICF merges two sections,
+ // Repl pointer of one section points to another section. So,
+ // if you need to get a pointer to this instance, do not use
+ // this but instead this->Repl.
+ SectionBase *Repl;
+
+ unsigned SectionKind : 3;
+
+ // The next two bit fields are only used by InputSectionBase, but we
+ // put them here so the struct packs better.
+
+ // The garbage collector sets sections' Live bits.
+ // If GC is disabled, all sections are considered live by default.
+ unsigned Live : 1;
+
+ unsigned Bss : 1;
+
+ // Set for sections that should not be folded by ICF.
+ unsigned KeepUnique : 1;
+
+ // These corresponds to the fields in Elf_Shdr.
+ uint32_t Alignment;
+ uint64_t Flags;
+ uint64_t Entsize;
+ uint32_t Type;
+ uint32_t Link;
+ uint32_t Info;
+
+ OutputSection *getOutputSection();
+ const OutputSection *getOutputSection() const {
+ return const_cast<SectionBase *>(this)->getOutputSection();
+ }
+
+ // Translate an offset in the input section to an offset in the output
+ // section.
+ uint64_t getOffset(uint64_t Offset) const;
+
+ uint64_t getVA(uint64_t Offset = 0) const;
+
+protected:
+ SectionBase(Kind SectionKind, StringRef Name, uint64_t Flags,
+ uint64_t Entsize, uint64_t Alignment, uint32_t Type,
+ uint32_t Info, uint32_t Link)
+ : Name(Name), Repl(this), SectionKind(SectionKind), Live(false),
+ Bss(false), KeepUnique(false), Alignment(Alignment), Flags(Flags),
+ Entsize(Entsize), Type(Type), Link(Link), Info(Info) {}
+};
+
+// This corresponds to a section of an input file.
+class InputSectionBase : public SectionBase {
+public:
+ template <class ELFT>
+ InputSectionBase(ObjFile<ELFT> &File, const typename ELFT::Shdr &Header,
+ StringRef Name, Kind SectionKind);
+
+ InputSectionBase(InputFile *File, uint64_t Flags, uint32_t Type,
+ uint64_t Entsize, uint32_t Link, uint32_t Info,
+ uint32_t Alignment, ArrayRef<uint8_t> Data, StringRef Name,
+ Kind SectionKind);
+
+ static bool classof(const SectionBase *S) { return S->kind() != Output; }
+
+ // The file which contains this section. Its dynamic type is always
+ // ObjFile<ELFT>, but in order to avoid ELFT, we use InputFile as
+ // its static type.
+ InputFile *File;
+
+ template <class ELFT> ObjFile<ELFT> *getFile() const {
+ return cast_or_null<ObjFile<ELFT>>(File);
+ }
+
+ ArrayRef<uint8_t> data() const {
+ if (UncompressedSize >= 0 && !UncompressedBuf)
+ uncompress();
+ return RawData;
+ }
+
+ uint64_t getOffsetInFile() const;
+
+ // True if this section has already been placed to a linker script
+ // output section. This is needed because, in a linker script, you
+ // can refer to the same section more than once. For example, in
+ // the following linker script,
+ //
+ // .foo : { *(.text) }
+ // .bar : { *(.text) }
+ //
+ // .foo takes all .text sections, and .bar becomes empty. To achieve
+ // this, we need to memorize whether a section has been placed or
+ // not for each input section.
+ bool Assigned = false;
+
+ // Input sections are part of an output section. Special sections
+ // like .eh_frame and merge sections are first combined into a
+ // synthetic section that is then added to an output section. In all
+ // cases this points one level up.
+ SectionBase *Parent = nullptr;
+
+ // Relocations that refer to this section.
+ const void *FirstRelocation = nullptr;
+ unsigned NumRelocations : 31;
+ unsigned AreRelocsRela : 1;
+
+ template <class ELFT> ArrayRef<typename ELFT::Rel> rels() const {
+ assert(!AreRelocsRela);
+ return llvm::makeArrayRef(
+ static_cast<const typename ELFT::Rel *>(FirstRelocation),
+ NumRelocations);
+ }
+
+ template <class ELFT> ArrayRef<typename ELFT::Rela> relas() const {
+ assert(AreRelocsRela);
+ return llvm::makeArrayRef(
+ static_cast<const typename ELFT::Rela *>(FirstRelocation),
+ NumRelocations);
+ }
+
+ // InputSections that are dependent on us (reverse dependency for GC)
+ llvm::TinyPtrVector<InputSection *> DependentSections;
+
+ // Returns the size of this section (even if this is a common or BSS.)
+ size_t getSize() const;
+
+ InputSection *getLinkOrderDep() const;
+
+ // Get the function symbol that encloses this offset from within the
+ // section.
+ template <class ELFT>
+ Defined *getEnclosingFunction(uint64_t Offset);
+
+ // Returns a source location string. Used to construct an error message.
+ template <class ELFT> std::string getLocation(uint64_t Offset);
+ std::string getSrcMsg(const Symbol &Sym, uint64_t Offset);
+ std::string getObjMsg(uint64_t Offset);
+
+ // Each section knows how to relocate itself. These functions apply
+ // relocations, assuming that Buf points to this section's copy in
+ // the mmap'ed output buffer.
+ template <class ELFT> void relocate(uint8_t *Buf, uint8_t *BufEnd);
+ void relocateAlloc(uint8_t *Buf, uint8_t *BufEnd);
+
+ // The native ELF reloc data type is not very convenient to handle.
+ // So we convert ELF reloc records to our own records in Relocations.cpp.
+ // This vector contains such "cooked" relocations.
+ std::vector<Relocation> Relocations;
+
+ // A function compiled with -fsplit-stack calling a function
+ // compiled without -fsplit-stack needs its prologue adjusted. Find
+ // such functions and adjust their prologues. This is very similar
+ // to relocation. See https://gcc.gnu.org/wiki/SplitStacks for more
+ // information.
+ template <typename ELFT>
+ void adjustSplitStackFunctionPrologues(uint8_t *Buf, uint8_t *End);
+
+
+ template <typename T> llvm::ArrayRef<T> getDataAs() const {
+ size_t S = data().size();
+ assert(S % sizeof(T) == 0);
+ return llvm::makeArrayRef<T>((const T *)data().data(), S / sizeof(T));
+ }
+
+protected:
+ void parseCompressedHeader();
+ void uncompress() const;
+
+ mutable ArrayRef<uint8_t> RawData;
+
+ // A pointer that owns uncompressed data if a section is compressed by zlib.
+ // Since the feature is not used often, this is usually a nullptr.
+ mutable std::unique_ptr<char[]> UncompressedBuf;
+ int64_t UncompressedSize = -1;
+};
+
+// SectionPiece represents a piece of splittable section contents.
+// We allocate a lot of these and binary search on them. This means that they
+// have to be as compact as possible, which is why we don't store the size (can
+// be found by looking at the next one).
+struct SectionPiece {
+ SectionPiece(size_t Off, uint32_t Hash, bool Live)
+ : InputOff(Off), Hash(Hash), OutputOff(0),
+ Live(Live || !Config->GcSections) {}
+
+ uint32_t InputOff;
+ uint32_t Hash;
+ int64_t OutputOff : 63;
+ uint64_t Live : 1;
+};
+
+static_assert(sizeof(SectionPiece) == 16, "SectionPiece is too big");
+
+// This corresponds to a SHF_MERGE section of an input file.
+class MergeInputSection : public InputSectionBase {
+public:
+ template <class ELFT>
+ MergeInputSection(ObjFile<ELFT> &F, const typename ELFT::Shdr &Header,
+ StringRef Name);
+ MergeInputSection(uint64_t Flags, uint32_t Type, uint64_t Entsize,
+ ArrayRef<uint8_t> Data, StringRef Name);
+
+ static bool classof(const SectionBase *S) { return S->kind() == Merge; }
+ void splitIntoPieces();
+
+ // Translate an offset in the input section to an offset in the parent
+ // MergeSyntheticSection.
+ uint64_t getParentOffset(uint64_t Offset) const;
+
+ // Splittable sections are handled as a sequence of data
+ // rather than a single large blob of data.
+ std::vector<SectionPiece> Pieces;
+
+ // Returns I'th piece's data. This function is very hot when
+ // string merging is enabled, so we want to inline.
+ LLVM_ATTRIBUTE_ALWAYS_INLINE
+ llvm::CachedHashStringRef getData(size_t I) const {
+ size_t Begin = Pieces[I].InputOff;
+ size_t End =
+ (Pieces.size() - 1 == I) ? data().size() : Pieces[I + 1].InputOff;
+ return {toStringRef(data().slice(Begin, End - Begin)), Pieces[I].Hash};
+ }
+
+ // Returns the SectionPiece at a given input section offset.
+ SectionPiece *getSectionPiece(uint64_t Offset);
+ const SectionPiece *getSectionPiece(uint64_t Offset) const {
+ return const_cast<MergeInputSection *>(this)->getSectionPiece(Offset);
+ }
+
+ SyntheticSection *getParent() const;
+
+private:
+ void splitStrings(ArrayRef<uint8_t> A, size_t Size);
+ void splitNonStrings(ArrayRef<uint8_t> A, size_t Size);
+};
+
+struct EhSectionPiece {
+ EhSectionPiece(size_t Off, InputSectionBase *Sec, uint32_t Size,
+ unsigned FirstRelocation)
+ : InputOff(Off), Sec(Sec), Size(Size), FirstRelocation(FirstRelocation) {}
+
+ ArrayRef<uint8_t> data() {
+ return {Sec->data().data() + this->InputOff, Size};
+ }
+
+ size_t InputOff;
+ ssize_t OutputOff = -1;
+ InputSectionBase *Sec;
+ uint32_t Size;
+ unsigned FirstRelocation;
+};
+
+// This corresponds to a .eh_frame section of an input file.
+class EhInputSection : public InputSectionBase {
+public:
+ template <class ELFT>
+ EhInputSection(ObjFile<ELFT> &F, const typename ELFT::Shdr &Header,
+ StringRef Name);
+ static bool classof(const SectionBase *S) { return S->kind() == EHFrame; }
+ template <class ELFT> void split();
+ template <class ELFT, class RelTy> void split(ArrayRef<RelTy> Rels);
+
+ // Splittable sections are handled as a sequence of data
+ // rather than a single large blob of data.
+ std::vector<EhSectionPiece> Pieces;
+
+ SyntheticSection *getParent() const;
+};
+
+// This is a section that is added directly to an output section
+// instead of needing special combination via a synthetic section. This
+// includes all input sections with the exceptions of SHF_MERGE and
+// .eh_frame. It also includes the synthetic sections themselves.
+class InputSection : public InputSectionBase {
+public:
+ InputSection(InputFile *F, uint64_t Flags, uint32_t Type, uint32_t Alignment,
+ ArrayRef<uint8_t> Data, StringRef Name, Kind K = Regular);
+ template <class ELFT>
+ InputSection(ObjFile<ELFT> &F, const typename ELFT::Shdr &Header,
+ StringRef Name);
+
+ // Write this section to a mmap'ed file, assuming Buf is pointing to
+ // beginning of the output section.
+ template <class ELFT> void writeTo(uint8_t *Buf);
+
+ uint64_t getOffset(uint64_t Offset) const { return OutSecOff + Offset; }
+
+ OutputSection *getParent() const;
+
+ // This variable has two usages. Initially, it represents an index in the
+ // OutputSection's InputSection list, and is used when ordering SHF_LINK_ORDER
+ // sections. After assignAddresses is called, it represents the offset from
+ // the beginning of the output section this section was assigned to.
+ uint64_t OutSecOff = 0;
+
+ static bool classof(const SectionBase *S);
+
+ InputSectionBase *getRelocatedSection() const;
+
+ template <class ELFT, class RelTy>
+ void relocateNonAlloc(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels);
+
+ // Used by ICF.
+ uint32_t Class[2] = {0, 0};
+
+ // Called by ICF to merge two input sections.
+ void replace(InputSection *Other);
+
+ static InputSection Discarded;
+
+private:
+ template <class ELFT, class RelTy>
+ void copyRelocations(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels);
+
+ template <class ELFT> void copyShtGroup(uint8_t *Buf);
+};
+
+// The list of all input sections.
+extern std::vector<InputSectionBase *> InputSections;
+
+} // namespace elf
+
+std::string toString(const elf::InputSectionBase *);
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/ELF/LTO.cpp b/contrib/llvm/tools/lld/ELF/LTO.cpp
new file mode 100644
index 000000000000..ca44581780e4
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/LTO.cpp
@@ -0,0 +1,296 @@
+//===- LTO.cpp ------------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LTO.h"
+#include "Config.h"
+#include "InputFiles.h"
+#include "LinkerScript.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/TargetOptionsCommandFlags.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Bitcode/BitcodeReader.h"
+#include "llvm/Bitcode/BitcodeWriter.h"
+#include "llvm/IR/DiagnosticPrinter.h"
+#include "llvm/LTO/Caching.h"
+#include "llvm/LTO/Config.h"
+#include "llvm/LTO/LTO.h"
+#include "llvm/Object/SymbolicFile.h"
+#include "llvm/Support/CodeGen.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <algorithm>
+#include <cstddef>
+#include <memory>
+#include <string>
+#include <system_error>
+#include <vector>
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::ELF;
+
+using namespace lld;
+using namespace lld::elf;
+
+// Creates an empty file to store a list of object files for final
+// linking of distributed ThinLTO.
+static std::unique_ptr<raw_fd_ostream> openFile(StringRef File) {
+ std::error_code EC;
+ auto Ret =
+ llvm::make_unique<raw_fd_ostream>(File, EC, sys::fs::OpenFlags::F_None);
+ if (EC) {
+ error("cannot open " + File + ": " + EC.message());
+ return nullptr;
+ }
+ return Ret;
+}
+
+static std::string getThinLTOOutputFile(StringRef ModulePath) {
+ return lto::getThinLTOOutputFile(ModulePath,
+ Config->ThinLTOPrefixReplace.first,
+ Config->ThinLTOPrefixReplace.second);
+}
+
+static lto::Config createConfig() {
+ lto::Config C;
+
+ // LLD supports the new relocations and address-significance tables.
+ C.Options = InitTargetOptionsFromCodeGenFlags();
+ C.Options.RelaxELFRelocations = true;
+ C.Options.EmitAddrsig = true;
+
+ // Always emit a section per function/datum with LTO.
+ C.Options.FunctionSections = true;
+ C.Options.DataSections = true;
+
+ if (Config->Relocatable)
+ C.RelocModel = None;
+ else if (Config->Pic)
+ C.RelocModel = Reloc::PIC_;
+ else
+ C.RelocModel = Reloc::Static;
+
+ C.CodeModel = GetCodeModelFromCMModel();
+ C.DisableVerify = Config->DisableVerify;
+ C.DiagHandler = diagnosticHandler;
+ C.OptLevel = Config->LTOO;
+ C.CPU = GetCPUStr();
+ C.MAttrs = GetMAttrs();
+
+ // Set up a custom pipeline if we've been asked to.
+ C.OptPipeline = Config->LTONewPmPasses;
+ C.AAPipeline = Config->LTOAAPipeline;
+
+ // Set up optimization remarks if we've been asked to.
+ C.RemarksFilename = Config->OptRemarksFilename;
+ C.RemarksWithHotness = Config->OptRemarksWithHotness;
+
+ C.SampleProfile = Config->LTOSampleProfile;
+ C.UseNewPM = Config->LTONewPassManager;
+ C.DebugPassManager = Config->LTODebugPassManager;
+ C.DwoDir = Config->DwoDir;
+
+ if (Config->EmitLLVM) {
+ C.PostInternalizeModuleHook = [](size_t Task, const Module &M) {
+ if (std::unique_ptr<raw_fd_ostream> OS = openFile(Config->OutputFile))
+ WriteBitcodeToFile(M, *OS, false);
+ return false;
+ };
+ }
+
+ if (Config->SaveTemps)
+ checkError(C.addSaveTemps(Config->OutputFile.str() + ".",
+ /*UseInputModulePath*/ true));
+ return C;
+}
+
+BitcodeCompiler::BitcodeCompiler() {
+ // Initialize IndexFile.
+ if (!Config->ThinLTOIndexOnlyArg.empty())
+ IndexFile = openFile(Config->ThinLTOIndexOnlyArg);
+
+ // Initialize LTOObj.
+ lto::ThinBackend Backend;
+ if (Config->ThinLTOIndexOnly) {
+ auto OnIndexWrite = [&](StringRef S) { ThinIndices.erase(S); };
+ Backend = lto::createWriteIndexesThinBackend(
+ Config->ThinLTOPrefixReplace.first, Config->ThinLTOPrefixReplace.second,
+ Config->ThinLTOEmitImportsFiles, IndexFile.get(), OnIndexWrite);
+ } else if (Config->ThinLTOJobs != -1U) {
+ Backend = lto::createInProcessThinBackend(Config->ThinLTOJobs);
+ }
+
+ LTOObj = llvm::make_unique<lto::LTO>(createConfig(), Backend,
+ Config->LTOPartitions);
+
+ // Initialize UsedStartStop.
+ for (Symbol *Sym : Symtab->getSymbols()) {
+ StringRef S = Sym->getName();
+ for (StringRef Prefix : {"__start_", "__stop_"})
+ if (S.startswith(Prefix))
+ UsedStartStop.insert(S.substr(Prefix.size()));
+ }
+}
+
+BitcodeCompiler::~BitcodeCompiler() = default;
+
+static void undefine(Symbol *S) {
+ replaceSymbol<Undefined>(S, nullptr, S->getName(), STB_GLOBAL, STV_DEFAULT,
+ S->Type);
+}
+
+void BitcodeCompiler::add(BitcodeFile &F) {
+ lto::InputFile &Obj = *F.Obj;
+ bool IsExec = !Config->Shared && !Config->Relocatable;
+
+ if (Config->ThinLTOIndexOnly)
+ ThinIndices.insert(Obj.getName());
+
+ ArrayRef<Symbol *> Syms = F.getSymbols();
+ ArrayRef<lto::InputFile::Symbol> ObjSyms = Obj.symbols();
+ std::vector<lto::SymbolResolution> Resols(Syms.size());
+
+ // Provide a resolution to the LTO API for each symbol.
+ for (size_t I = 0, E = Syms.size(); I != E; ++I) {
+ Symbol *Sym = Syms[I];
+ const lto::InputFile::Symbol &ObjSym = ObjSyms[I];
+ lto::SymbolResolution &R = Resols[I];
+
+ // Ideally we shouldn't check for SF_Undefined but currently IRObjectFile
+ // reports two symbols for module ASM defined. Without this check, lld
+ // flags an undefined in IR with a definition in ASM as prevailing.
+ // Once IRObjectFile is fixed to report only one symbol this hack can
+ // be removed.
+ R.Prevailing = !ObjSym.isUndefined() && Sym->File == &F;
+
+ // We ask LTO to preserve following global symbols:
+ // 1) All symbols when doing relocatable link, so that them can be used
+ // for doing final link.
+ // 2) Symbols that are used in regular objects.
+ // 3) C named sections if we have corresponding __start_/__stop_ symbol.
+ // 4) Symbols that are defined in bitcode files and used for dynamic linking.
+ R.VisibleToRegularObj = Config->Relocatable || Sym->IsUsedInRegularObj ||
+ (R.Prevailing && Sym->includeInDynsym()) ||
+ UsedStartStop.count(ObjSym.getSectionName());
+ const auto *DR = dyn_cast<Defined>(Sym);
+ R.FinalDefinitionInLinkageUnit =
+ (IsExec || Sym->Visibility != STV_DEFAULT) && DR &&
+ // Skip absolute symbols from ELF objects, otherwise PC-rel relocations
+ // will be generated by for them, triggering linker errors.
+ // Symbol section is always null for bitcode symbols, hence the check
+ // for isElf(). Skip linker script defined symbols as well: they have
+ // no File defined.
+ !(DR->Section == nullptr && (!Sym->File || Sym->File->isElf()));
+
+ if (R.Prevailing)
+ undefine(Sym);
+
+ // We tell LTO to not apply interprocedural optimization for wrapped
+ // (with --wrap) symbols because otherwise LTO would inline them while
+ // their values are still not final.
+ R.LinkerRedefined = !Sym->CanInline;
+ }
+ checkError(LTOObj->add(std::move(F.Obj), Resols));
+}
+
+static void createEmptyIndex(StringRef ModulePath) {
+ std::string Path = replaceThinLTOSuffix(getThinLTOOutputFile(ModulePath));
+ std::unique_ptr<raw_fd_ostream> OS = openFile(Path + ".thinlto.bc");
+ if (!OS)
+ return;
+
+ ModuleSummaryIndex M(/*HaveGVs*/ false);
+ M.setSkipModuleByDistributedBackend();
+ WriteIndexToFile(M, *OS);
+
+ if (Config->ThinLTOEmitImportsFiles)
+ openFile(Path + ".imports");
+}
+
+// Merge all the bitcode files we have seen, codegen the result
+// and return the resulting ObjectFile(s).
+std::vector<InputFile *> BitcodeCompiler::compile() {
+ unsigned MaxTasks = LTOObj->getMaxTasks();
+ Buf.resize(MaxTasks);
+ Files.resize(MaxTasks);
+
+ // The --thinlto-cache-dir option specifies the path to a directory in which
+ // to cache native object files for ThinLTO incremental builds. If a path was
+ // specified, configure LTO to use it as the cache directory.
+ lto::NativeObjectCache Cache;
+ if (!Config->ThinLTOCacheDir.empty())
+ Cache = check(
+ lto::localCache(Config->ThinLTOCacheDir,
+ [&](size_t Task, std::unique_ptr<MemoryBuffer> MB) {
+ Files[Task] = std::move(MB);
+ }));
+
+ checkError(LTOObj->run(
+ [&](size_t Task) {
+ return llvm::make_unique<lto::NativeObjectStream>(
+ llvm::make_unique<raw_svector_ostream>(Buf[Task]));
+ },
+ Cache));
+
+ // Emit empty index files for non-indexed files
+ for (StringRef S : ThinIndices) {
+ std::string Path = getThinLTOOutputFile(S);
+ openFile(Path + ".thinlto.bc");
+ if (Config->ThinLTOEmitImportsFiles)
+ openFile(Path + ".imports");
+ }
+
+ // If LazyObjFile has not been added to link, emit empty index files.
+ // This is needed because this is what GNU gold plugin does and we have a
+ // distributed build system that depends on that behavior.
+ if (Config->ThinLTOIndexOnly) {
+ for (LazyObjFile *F : LazyObjFiles)
+ if (!F->AddedToLink && isBitcode(F->MB))
+ createEmptyIndex(F->getName());
+
+ if (!Config->LTOObjPath.empty())
+ saveBuffer(Buf[0], Config->LTOObjPath);
+
+ // ThinLTO with index only option is required to generate only the index
+ // files. After that, we exit from linker and ThinLTO backend runs in a
+ // distributed environment.
+ if (IndexFile)
+ IndexFile->close();
+ return {};
+ }
+
+ if (!Config->ThinLTOCacheDir.empty())
+ pruneCache(Config->ThinLTOCacheDir, Config->ThinLTOCachePolicy);
+
+ std::vector<InputFile *> Ret;
+ for (unsigned I = 0; I != MaxTasks; ++I) {
+ if (Buf[I].empty())
+ continue;
+ if (Config->SaveTemps) {
+ if (I == 0)
+ saveBuffer(Buf[I], Config->OutputFile + ".lto.o");
+ else
+ saveBuffer(Buf[I], Config->OutputFile + Twine(I) + ".lto.o");
+ }
+ InputFile *Obj = createObjectFile(MemoryBufferRef(Buf[I], "lto.tmp"));
+ Ret.push_back(Obj);
+ }
+
+ for (std::unique_ptr<MemoryBuffer> &File : Files)
+ if (File)
+ Ret.push_back(createObjectFile(*File));
+ return Ret;
+}
diff --git a/contrib/llvm/tools/lld/ELF/LTO.h b/contrib/llvm/tools/lld/ELF/LTO.h
new file mode 100644
index 000000000000..a190da3e5996
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/LTO.h
@@ -0,0 +1,63 @@
+//===- LTO.h ----------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides a way to combine bitcode files into one ELF
+// file by compiling them using LLVM.
+//
+// If LTO is in use, your input files are not in regular ELF files
+// but instead LLVM bitcode files. In that case, the linker has to
+// convert bitcode files into the native format so that we can create
+// an ELF file that contains native code. This file provides that
+// functionality.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_LTO_H
+#define LLD_ELF_LTO_H
+
+#include "lld/Common/LLVM.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
+#include <memory>
+#include <vector>
+
+namespace llvm {
+namespace lto {
+class LTO;
+}
+} // namespace llvm
+
+namespace lld {
+namespace elf {
+
+class BitcodeFile;
+class InputFile;
+class LazyObjFile;
+
+class BitcodeCompiler {
+public:
+ BitcodeCompiler();
+ ~BitcodeCompiler();
+
+ void add(BitcodeFile &F);
+ std::vector<InputFile *> compile();
+
+private:
+ std::unique_ptr<llvm::lto::LTO> LTOObj;
+ std::vector<SmallString<0>> Buf;
+ std::vector<std::unique_ptr<MemoryBuffer>> Files;
+ llvm::DenseSet<StringRef> UsedStartStop;
+ std::unique_ptr<llvm::raw_fd_ostream> IndexFile;
+ llvm::DenseSet<StringRef> ThinIndices;
+};
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/ELF/LinkerScript.cpp b/contrib/llvm/tools/lld/ELF/LinkerScript.cpp
new file mode 100644
index 000000000000..fbc025416205
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/LinkerScript.cpp
@@ -0,0 +1,1144 @@
+//===- LinkerScript.cpp ---------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the parser/evaluator of the linker script.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LinkerScript.h"
+#include "Config.h"
+#include "InputSection.h"
+#include "OutputSections.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "Writer.h"
+#include "lld/Common/Memory.h"
+#include "lld/Common/Strings.h"
+#include "lld/Common/Threads.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <iterator>
+#include <limits>
+#include <string>
+#include <vector>
+
+using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+using namespace lld;
+using namespace lld::elf;
+
+LinkerScript *elf::Script;
+
+static uint64_t getOutputSectionVA(SectionBase *InputSec, StringRef Loc) {
+ if (OutputSection *OS = InputSec->getOutputSection())
+ return OS->Addr;
+ error(Loc + ": unable to evaluate expression: input section " +
+ InputSec->Name + " has no output section assigned");
+ return 0;
+}
+
+uint64_t ExprValue::getValue() const {
+ if (Sec)
+ return alignTo(Sec->getOffset(Val) + getOutputSectionVA(Sec, Loc),
+ Alignment);
+ return alignTo(Val, Alignment);
+}
+
+uint64_t ExprValue::getSecAddr() const {
+ if (Sec)
+ return Sec->getOffset(0) + getOutputSectionVA(Sec, Loc);
+ return 0;
+}
+
+uint64_t ExprValue::getSectionOffset() const {
+ // If the alignment is trivial, we don't have to compute the full
+ // value to know the offset. This allows this function to succeed in
+ // cases where the output section is not yet known.
+ if (Alignment == 1 && (!Sec || !Sec->getOutputSection()))
+ return Val;
+ return getValue() - getSecAddr();
+}
+
+OutputSection *LinkerScript::createOutputSection(StringRef Name,
+ StringRef Location) {
+ OutputSection *&SecRef = NameToOutputSection[Name];
+ OutputSection *Sec;
+ if (SecRef && SecRef->Location.empty()) {
+ // There was a forward reference.
+ Sec = SecRef;
+ } else {
+ Sec = make<OutputSection>(Name, SHT_NOBITS, 0);
+ if (!SecRef)
+ SecRef = Sec;
+ }
+ Sec->Location = Location;
+ return Sec;
+}
+
+OutputSection *LinkerScript::getOrCreateOutputSection(StringRef Name) {
+ OutputSection *&CmdRef = NameToOutputSection[Name];
+ if (!CmdRef)
+ CmdRef = make<OutputSection>(Name, SHT_PROGBITS, 0);
+ return CmdRef;
+}
+
+// Expands the memory region by the specified size.
+static void expandMemoryRegion(MemoryRegion *MemRegion, uint64_t Size,
+ StringRef RegionName, StringRef SecName) {
+ MemRegion->CurPos += Size;
+ uint64_t NewSize = MemRegion->CurPos - MemRegion->Origin;
+ if (NewSize > MemRegion->Length)
+ error("section '" + SecName + "' will not fit in region '" + RegionName +
+ "': overflowed by " + Twine(NewSize - MemRegion->Length) + " bytes");
+}
+
+void LinkerScript::expandMemoryRegions(uint64_t Size) {
+ if (Ctx->MemRegion)
+ expandMemoryRegion(Ctx->MemRegion, Size, Ctx->MemRegion->Name,
+ Ctx->OutSec->Name);
+ // Only expand the LMARegion if it is different from MemRegion.
+ if (Ctx->LMARegion && Ctx->MemRegion != Ctx->LMARegion)
+ expandMemoryRegion(Ctx->LMARegion, Size, Ctx->LMARegion->Name,
+ Ctx->OutSec->Name);
+}
+
+void LinkerScript::expandOutputSection(uint64_t Size) {
+ Ctx->OutSec->Size += Size;
+ expandMemoryRegions(Size);
+}
+
+void LinkerScript::setDot(Expr E, const Twine &Loc, bool InSec) {
+ uint64_t Val = E().getValue();
+ if (Val < Dot && InSec)
+ error(Loc + ": unable to move location counter backward for: " +
+ Ctx->OutSec->Name);
+
+ // Update to location counter means update to section size.
+ if (InSec)
+ expandOutputSection(Val - Dot);
+ else
+ expandMemoryRegions(Val - Dot);
+
+ Dot = Val;
+}
+
+// Used for handling linker symbol assignments, for both finalizing
+// their values and doing early declarations. Returns true if symbol
+// should be defined from linker script.
+static bool shouldDefineSym(SymbolAssignment *Cmd) {
+ if (Cmd->Name == ".")
+ return false;
+
+ if (!Cmd->Provide)
+ return true;
+
+ // If a symbol was in PROVIDE(), we need to define it only
+ // when it is a referenced undefined symbol.
+ Symbol *B = Symtab->find(Cmd->Name);
+ if (B && !B->isDefined())
+ return true;
+ return false;
+}
+
+// This function is called from processSectionCommands,
+// while we are fixing the output section layout.
+void LinkerScript::addSymbol(SymbolAssignment *Cmd) {
+ if (!shouldDefineSym(Cmd))
+ return;
+
+ // Define a symbol.
+ Symbol *Sym;
+ uint8_t Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT;
+ std::tie(Sym, std::ignore) = Symtab->insert(Cmd->Name, Visibility,
+ /*CanOmitFromDynSym*/ false,
+ /*File*/ nullptr);
+ ExprValue Value = Cmd->Expression();
+ SectionBase *Sec = Value.isAbsolute() ? nullptr : Value.Sec;
+
+ // When this function is called, section addresses have not been
+ // fixed yet. So, we may or may not know the value of the RHS
+ // expression.
+ //
+ // For example, if an expression is `x = 42`, we know x is always 42.
+ // However, if an expression is `x = .`, there's no way to know its
+ // value at the moment.
+ //
+ // We want to set symbol values early if we can. This allows us to
+ // use symbols as variables in linker scripts. Doing so allows us to
+ // write expressions like this: `alignment = 16; . = ALIGN(., alignment)`.
+ uint64_t SymValue = Value.Sec ? 0 : Value.getValue();
+
+ replaceSymbol<Defined>(Sym, nullptr, Cmd->Name, STB_GLOBAL, Visibility,
+ STT_NOTYPE, SymValue, 0, Sec);
+ Cmd->Sym = cast<Defined>(Sym);
+}
+
+// This function is called from LinkerScript::declareSymbols.
+// It creates a placeholder symbol if needed.
+static void declareSymbol(SymbolAssignment *Cmd) {
+ if (!shouldDefineSym(Cmd))
+ return;
+
+ // We can't calculate final value right now.
+ Symbol *Sym;
+ uint8_t Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT;
+ std::tie(Sym, std::ignore) = Symtab->insert(Cmd->Name, Visibility,
+ /*CanOmitFromDynSym*/ false,
+ /*File*/ nullptr);
+ replaceSymbol<Defined>(Sym, nullptr, Cmd->Name, STB_GLOBAL, Visibility,
+ STT_NOTYPE, 0, 0, nullptr);
+ Cmd->Sym = cast<Defined>(Sym);
+ Cmd->Provide = false;
+ Sym->ScriptDefined = true;
+}
+
+// This method is used to handle INSERT AFTER statement. Here we rebuild
+// the list of script commands to mix sections inserted into.
+void LinkerScript::processInsertCommands() {
+ std::vector<BaseCommand *> V;
+ auto Insert = [&](std::vector<BaseCommand *> &From) {
+ V.insert(V.end(), From.begin(), From.end());
+ From.clear();
+ };
+
+ for (BaseCommand *Base : SectionCommands) {
+ if (auto *OS = dyn_cast<OutputSection>(Base)) {
+ Insert(InsertBeforeCommands[OS->Name]);
+ V.push_back(Base);
+ Insert(InsertAfterCommands[OS->Name]);
+ continue;
+ }
+ V.push_back(Base);
+ }
+
+ for (auto &Cmds : {InsertBeforeCommands, InsertAfterCommands})
+ for (const std::pair<StringRef, std::vector<BaseCommand *>> &P : Cmds)
+ if (!P.second.empty())
+ error("unable to INSERT AFTER/BEFORE " + P.first +
+ ": section not defined");
+
+ SectionCommands = std::move(V);
+}
+
+// Symbols defined in script should not be inlined by LTO. At the same time
+// we don't know their final values until late stages of link. Here we scan
+// over symbol assignment commands and create placeholder symbols if needed.
+void LinkerScript::declareSymbols() {
+ assert(!Ctx);
+ for (BaseCommand *Base : SectionCommands) {
+ if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) {
+ declareSymbol(Cmd);
+ continue;
+ }
+
+ // If the output section directive has constraints,
+ // we can't say for sure if it is going to be included or not.
+ // Skip such sections for now. Improve the checks if we ever
+ // need symbols from that sections to be declared early.
+ auto *Sec = cast<OutputSection>(Base);
+ if (Sec->Constraint != ConstraintKind::NoConstraint)
+ continue;
+ for (BaseCommand *Base2 : Sec->SectionCommands)
+ if (auto *Cmd = dyn_cast<SymbolAssignment>(Base2))
+ declareSymbol(Cmd);
+ }
+}
+
+// This function is called from assignAddresses, while we are
+// fixing the output section addresses. This function is supposed
+// to set the final value for a given symbol assignment.
+void LinkerScript::assignSymbol(SymbolAssignment *Cmd, bool InSec) {
+ if (Cmd->Name == ".") {
+ setDot(Cmd->Expression, Cmd->Location, InSec);
+ return;
+ }
+
+ if (!Cmd->Sym)
+ return;
+
+ ExprValue V = Cmd->Expression();
+ if (V.isAbsolute()) {
+ Cmd->Sym->Section = nullptr;
+ Cmd->Sym->Value = V.getValue();
+ } else {
+ Cmd->Sym->Section = V.Sec;
+ Cmd->Sym->Value = V.getSectionOffset();
+ }
+}
+
+static std::string getFilename(InputFile *File) {
+ if (!File)
+ return "";
+ if (File->ArchiveName.empty())
+ return File->getName();
+ return (File->ArchiveName + "(" + File->getName() + ")").str();
+}
+
+bool LinkerScript::shouldKeep(InputSectionBase *S) {
+ if (KeptSections.empty())
+ return false;
+ std::string Filename = getFilename(S->File);
+ for (InputSectionDescription *ID : KeptSections)
+ if (ID->FilePat.match(Filename))
+ for (SectionPattern &P : ID->SectionPatterns)
+ if (P.SectionPat.match(S->Name))
+ return true;
+ return false;
+}
+
+// A helper function for the SORT() command.
+static std::function<bool(InputSectionBase *, InputSectionBase *)>
+getComparator(SortSectionPolicy K) {
+ switch (K) {
+ case SortSectionPolicy::Alignment:
+ return [](InputSectionBase *A, InputSectionBase *B) {
+ // ">" is not a mistake. Sections with larger alignments are placed
+ // before sections with smaller alignments in order to reduce the
+ // amount of padding necessary. This is compatible with GNU.
+ return A->Alignment > B->Alignment;
+ };
+ case SortSectionPolicy::Name:
+ return [](InputSectionBase *A, InputSectionBase *B) {
+ return A->Name < B->Name;
+ };
+ case SortSectionPolicy::Priority:
+ return [](InputSectionBase *A, InputSectionBase *B) {
+ return getPriority(A->Name) < getPriority(B->Name);
+ };
+ default:
+ llvm_unreachable("unknown sort policy");
+ }
+}
+
+// A helper function for the SORT() command.
+static bool matchConstraints(ArrayRef<InputSection *> Sections,
+ ConstraintKind Kind) {
+ if (Kind == ConstraintKind::NoConstraint)
+ return true;
+
+ bool IsRW = llvm::any_of(
+ Sections, [](InputSection *Sec) { return Sec->Flags & SHF_WRITE; });
+
+ return (IsRW && Kind == ConstraintKind::ReadWrite) ||
+ (!IsRW && Kind == ConstraintKind::ReadOnly);
+}
+
+static void sortSections(MutableArrayRef<InputSection *> Vec,
+ SortSectionPolicy K) {
+ if (K != SortSectionPolicy::Default && K != SortSectionPolicy::None)
+ std::stable_sort(Vec.begin(), Vec.end(), getComparator(K));
+}
+
+// Sort sections as instructed by SORT-family commands and --sort-section
+// option. Because SORT-family commands can be nested at most two depth
+// (e.g. SORT_BY_NAME(SORT_BY_ALIGNMENT(.text.*))) and because the command
+// line option is respected even if a SORT command is given, the exact
+// behavior we have here is a bit complicated. Here are the rules.
+//
+// 1. If two SORT commands are given, --sort-section is ignored.
+// 2. If one SORT command is given, and if it is not SORT_NONE,
+// --sort-section is handled as an inner SORT command.
+// 3. If one SORT command is given, and if it is SORT_NONE, don't sort.
+// 4. If no SORT command is given, sort according to --sort-section.
+static void sortInputSections(MutableArrayRef<InputSection *> Vec,
+ const SectionPattern &Pat) {
+ if (Pat.SortOuter == SortSectionPolicy::None)
+ return;
+
+ if (Pat.SortInner == SortSectionPolicy::Default)
+ sortSections(Vec, Config->SortSection);
+ else
+ sortSections(Vec, Pat.SortInner);
+ sortSections(Vec, Pat.SortOuter);
+}
+
+// Compute and remember which sections the InputSectionDescription matches.
+std::vector<InputSection *>
+LinkerScript::computeInputSections(const InputSectionDescription *Cmd) {
+ std::vector<InputSection *> Ret;
+
+ // Collects all sections that satisfy constraints of Cmd.
+ for (const SectionPattern &Pat : Cmd->SectionPatterns) {
+ size_t SizeBefore = Ret.size();
+
+ for (InputSectionBase *Sec : InputSections) {
+ if (!Sec->Live || Sec->Assigned)
+ continue;
+
+ // For -emit-relocs we have to ignore entries like
+ // .rela.dyn : { *(.rela.data) }
+ // which are common because they are in the default bfd script.
+ // We do not ignore SHT_REL[A] linker-synthesized sections here because
+ // want to support scripts that do custom layout for them.
+ if (auto *IS = dyn_cast<InputSection>(Sec))
+ if (IS->getRelocatedSection())
+ continue;
+
+ std::string Filename = getFilename(Sec->File);
+ if (!Cmd->FilePat.match(Filename) ||
+ Pat.ExcludedFilePat.match(Filename) ||
+ !Pat.SectionPat.match(Sec->Name))
+ continue;
+
+ // It is safe to assume that Sec is an InputSection
+ // because mergeable or EH input sections have already been
+ // handled and eliminated.
+ Ret.push_back(cast<InputSection>(Sec));
+ Sec->Assigned = true;
+ }
+
+ sortInputSections(MutableArrayRef<InputSection *>(Ret).slice(SizeBefore),
+ Pat);
+ }
+ return Ret;
+}
+
+void LinkerScript::discard(ArrayRef<InputSection *> V) {
+ for (InputSection *S : V) {
+ if (S == In.ShStrTab || S == In.RelaDyn || S == In.RelrDyn)
+ error("discarding " + S->Name + " section is not allowed");
+
+ // You can discard .hash and .gnu.hash sections by linker scripts. Since
+ // they are synthesized sections, we need to handle them differently than
+ // other regular sections.
+ if (S == In.GnuHashTab)
+ In.GnuHashTab = nullptr;
+ if (S == In.HashTab)
+ In.HashTab = nullptr;
+
+ S->Assigned = false;
+ S->Live = false;
+ discard(S->DependentSections);
+ }
+}
+
+std::vector<InputSection *>
+LinkerScript::createInputSectionList(OutputSection &OutCmd) {
+ std::vector<InputSection *> Ret;
+
+ for (BaseCommand *Base : OutCmd.SectionCommands) {
+ if (auto *Cmd = dyn_cast<InputSectionDescription>(Base)) {
+ Cmd->Sections = computeInputSections(Cmd);
+ Ret.insert(Ret.end(), Cmd->Sections.begin(), Cmd->Sections.end());
+ }
+ }
+ return Ret;
+}
+
+void LinkerScript::processSectionCommands() {
+ // A symbol can be assigned before any section is mentioned in the linker
+ // script. In an DSO, the symbol values are addresses, so the only important
+ // section values are:
+ // * SHN_UNDEF
+ // * SHN_ABS
+ // * Any value meaning a regular section.
+ // To handle that, create a dummy aether section that fills the void before
+ // the linker scripts switches to another section. It has an index of one
+ // which will map to whatever the first actual section is.
+ Aether = make<OutputSection>("", 0, SHF_ALLOC);
+ Aether->SectionIndex = 1;
+
+ // Ctx captures the local AddressState and makes it accessible deliberately.
+ // This is needed as there are some cases where we cannot just
+ // thread the current state through to a lambda function created by the
+ // script parser.
+ auto Deleter = make_unique<AddressState>();
+ Ctx = Deleter.get();
+ Ctx->OutSec = Aether;
+
+ size_t I = 0;
+ // Add input sections to output sections.
+ for (BaseCommand *Base : SectionCommands) {
+ // Handle symbol assignments outside of any output section.
+ if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) {
+ addSymbol(Cmd);
+ continue;
+ }
+
+ if (auto *Sec = dyn_cast<OutputSection>(Base)) {
+ std::vector<InputSection *> V = createInputSectionList(*Sec);
+
+ // The output section name `/DISCARD/' is special.
+ // Any input section assigned to it is discarded.
+ if (Sec->Name == "/DISCARD/") {
+ discard(V);
+ Sec->SectionCommands.clear();
+ continue;
+ }
+
+ // This is for ONLY_IF_RO and ONLY_IF_RW. An output section directive
+ // ".foo : ONLY_IF_R[OW] { ... }" is handled only if all member input
+ // sections satisfy a given constraint. If not, a directive is handled
+ // as if it wasn't present from the beginning.
+ //
+ // Because we'll iterate over SectionCommands many more times, the easy
+ // way to "make it as if it wasn't present" is to make it empty.
+ if (!matchConstraints(V, Sec->Constraint)) {
+ for (InputSectionBase *S : V)
+ S->Assigned = false;
+ Sec->SectionCommands.clear();
+ continue;
+ }
+
+ // A directive may contain symbol definitions like this:
+ // ".foo : { ...; bar = .; }". Handle them.
+ for (BaseCommand *Base : Sec->SectionCommands)
+ if (auto *OutCmd = dyn_cast<SymbolAssignment>(Base))
+ addSymbol(OutCmd);
+
+ // Handle subalign (e.g. ".foo : SUBALIGN(32) { ... }"). If subalign
+ // is given, input sections are aligned to that value, whether the
+ // given value is larger or smaller than the original section alignment.
+ if (Sec->SubalignExpr) {
+ uint32_t Subalign = Sec->SubalignExpr().getValue();
+ for (InputSectionBase *S : V)
+ S->Alignment = Subalign;
+ }
+
+ // Add input sections to an output section.
+ for (InputSection *S : V)
+ Sec->addSection(S);
+
+ Sec->SectionIndex = I++;
+ if (Sec->Noload)
+ Sec->Type = SHT_NOBITS;
+ if (Sec->NonAlloc)
+ Sec->Flags &= ~(uint64_t)SHF_ALLOC;
+ }
+ }
+ Ctx = nullptr;
+}
+
+static OutputSection *findByName(ArrayRef<BaseCommand *> Vec,
+ StringRef Name) {
+ for (BaseCommand *Base : Vec)
+ if (auto *Sec = dyn_cast<OutputSection>(Base))
+ if (Sec->Name == Name)
+ return Sec;
+ return nullptr;
+}
+
+static OutputSection *createSection(InputSectionBase *IS,
+ StringRef OutsecName) {
+ OutputSection *Sec = Script->createOutputSection(OutsecName, "<internal>");
+ Sec->addSection(cast<InputSection>(IS));
+ return Sec;
+}
+
+static OutputSection *addInputSec(StringMap<OutputSection *> &Map,
+ InputSectionBase *IS, StringRef OutsecName) {
+ // Sections with SHT_GROUP or SHF_GROUP attributes reach here only when the -r
+ // option is given. A section with SHT_GROUP defines a "section group", and
+ // its members have SHF_GROUP attribute. Usually these flags have already been
+ // stripped by InputFiles.cpp as section groups are processed and uniquified.
+ // However, for the -r option, we want to pass through all section groups
+ // as-is because adding/removing members or merging them with other groups
+ // change their semantics.
+ if (IS->Type == SHT_GROUP || (IS->Flags & SHF_GROUP))
+ return createSection(IS, OutsecName);
+
+ // Imagine .zed : { *(.foo) *(.bar) } script. Both foo and bar may have
+ // relocation sections .rela.foo and .rela.bar for example. Most tools do
+ // not allow multiple REL[A] sections for output section. Hence we
+ // should combine these relocation sections into single output.
+ // We skip synthetic sections because it can be .rela.dyn/.rela.plt or any
+ // other REL[A] sections created by linker itself.
+ if (!isa<SyntheticSection>(IS) &&
+ (IS->Type == SHT_REL || IS->Type == SHT_RELA)) {
+ auto *Sec = cast<InputSection>(IS);
+ OutputSection *Out = Sec->getRelocatedSection()->getOutputSection();
+
+ if (Out->RelocationSection) {
+ Out->RelocationSection->addSection(Sec);
+ return nullptr;
+ }
+
+ Out->RelocationSection = createSection(IS, OutsecName);
+ return Out->RelocationSection;
+ }
+
+ // When control reaches here, mergeable sections have already been merged into
+ // synthetic sections. For relocatable case we want to create one output
+ // section per syntetic section so that they have a valid sh_entsize.
+ if (Config->Relocatable && (IS->Flags & SHF_MERGE))
+ return createSection(IS, OutsecName);
+
+ // The ELF spec just says
+ // ----------------------------------------------------------------
+ // In the first phase, input sections that match in name, type and
+ // attribute flags should be concatenated into single sections.
+ // ----------------------------------------------------------------
+ //
+ // However, it is clear that at least some flags have to be ignored for
+ // section merging. At the very least SHF_GROUP and SHF_COMPRESSED have to be
+ // ignored. We should not have two output .text sections just because one was
+ // in a group and another was not for example.
+ //
+ // It also seems that wording was a late addition and didn't get the
+ // necessary scrutiny.
+ //
+ // Merging sections with different flags is expected by some users. One
+ // reason is that if one file has
+ //
+ // int *const bar __attribute__((section(".foo"))) = (int *)0;
+ //
+ // gcc with -fPIC will produce a read only .foo section. But if another
+ // file has
+ //
+ // int zed;
+ // int *const bar __attribute__((section(".foo"))) = (int *)&zed;
+ //
+ // gcc with -fPIC will produce a read write section.
+ //
+ // Last but not least, when using linker script the merge rules are forced by
+ // the script. Unfortunately, linker scripts are name based. This means that
+ // expressions like *(.foo*) can refer to multiple input sections with
+ // different flags. We cannot put them in different output sections or we
+ // would produce wrong results for
+ //
+ // start = .; *(.foo.*) end = .; *(.bar)
+ //
+ // and a mapping of .foo1 and .bar1 to one section and .foo2 and .bar2 to
+ // another. The problem is that there is no way to layout those output
+ // sections such that the .foo sections are the only thing between the start
+ // and end symbols.
+ //
+ // Given the above issues, we instead merge sections by name and error on
+ // incompatible types and flags.
+ OutputSection *&Sec = Map[OutsecName];
+ if (Sec) {
+ Sec->addSection(cast<InputSection>(IS));
+ return nullptr;
+ }
+
+ Sec = createSection(IS, OutsecName);
+ return Sec;
+}
+
+// Add sections that didn't match any sections command.
+void LinkerScript::addOrphanSections() {
+ unsigned End = SectionCommands.size();
+ StringMap<OutputSection *> Map;
+ std::vector<OutputSection *> V;
+
+ auto Add = [&](InputSectionBase *S) {
+ if (!S->Live || S->Parent)
+ return;
+
+ StringRef Name = getOutputSectionName(S);
+
+ if (Config->OrphanHandling == OrphanHandlingPolicy::Error)
+ error(toString(S) + " is being placed in '" + Name + "'");
+ else if (Config->OrphanHandling == OrphanHandlingPolicy::Warn)
+ warn(toString(S) + " is being placed in '" + Name + "'");
+
+ if (OutputSection *Sec =
+ findByName(makeArrayRef(SectionCommands).slice(0, End), Name)) {
+ Sec->addSection(cast<InputSection>(S));
+ return;
+ }
+
+ if (OutputSection *OS = addInputSec(Map, S, Name))
+ V.push_back(OS);
+ assert(S->getOutputSection()->SectionIndex == UINT32_MAX);
+ };
+
+ // For futher --emit-reloc handling code we need target output section
+ // to be created before we create relocation output section, so we want
+ // to create target sections first. We do not want priority handling
+ // for synthetic sections because them are special.
+ for (InputSectionBase *IS : InputSections) {
+ if (auto *Sec = dyn_cast<InputSection>(IS))
+ if (InputSectionBase *Rel = Sec->getRelocatedSection())
+ if (auto *RelIS = dyn_cast_or_null<InputSectionBase>(Rel->Parent))
+ Add(RelIS);
+ Add(IS);
+ }
+
+ // If no SECTIONS command was given, we should insert sections commands
+ // before others, so that we can handle scripts which refers them,
+ // for example: "foo = ABSOLUTE(ADDR(.text)));".
+ // When SECTIONS command is present we just add all orphans to the end.
+ if (HasSectionsCommand)
+ SectionCommands.insert(SectionCommands.end(), V.begin(), V.end());
+ else
+ SectionCommands.insert(SectionCommands.begin(), V.begin(), V.end());
+}
+
+uint64_t LinkerScript::advance(uint64_t Size, unsigned Alignment) {
+ bool IsTbss =
+ (Ctx->OutSec->Flags & SHF_TLS) && Ctx->OutSec->Type == SHT_NOBITS;
+ uint64_t Start = IsTbss ? Dot + Ctx->ThreadBssOffset : Dot;
+ Start = alignTo(Start, Alignment);
+ uint64_t End = Start + Size;
+
+ if (IsTbss)
+ Ctx->ThreadBssOffset = End - Dot;
+ else
+ Dot = End;
+ return End;
+}
+
+void LinkerScript::output(InputSection *S) {
+ assert(Ctx->OutSec == S->getParent());
+ uint64_t Before = advance(0, 1);
+ uint64_t Pos = advance(S->getSize(), S->Alignment);
+ S->OutSecOff = Pos - S->getSize() - Ctx->OutSec->Addr;
+
+ // Update output section size after adding each section. This is so that
+ // SIZEOF works correctly in the case below:
+ // .foo { *(.aaa) a = SIZEOF(.foo); *(.bbb) }
+ expandOutputSection(Pos - Before);
+}
+
+void LinkerScript::switchTo(OutputSection *Sec) {
+ Ctx->OutSec = Sec;
+
+ uint64_t Before = advance(0, 1);
+ Ctx->OutSec->Addr = advance(0, Ctx->OutSec->Alignment);
+ expandMemoryRegions(Ctx->OutSec->Addr - Before);
+}
+
+// This function searches for a memory region to place the given output
+// section in. If found, a pointer to the appropriate memory region is
+// returned. Otherwise, a nullptr is returned.
+MemoryRegion *LinkerScript::findMemoryRegion(OutputSection *Sec) {
+ // If a memory region name was specified in the output section command,
+ // then try to find that region first.
+ if (!Sec->MemoryRegionName.empty()) {
+ if (MemoryRegion *M = MemoryRegions.lookup(Sec->MemoryRegionName))
+ return M;
+ error("memory region '" + Sec->MemoryRegionName + "' not declared");
+ return nullptr;
+ }
+
+ // If at least one memory region is defined, all sections must
+ // belong to some memory region. Otherwise, we don't need to do
+ // anything for memory regions.
+ if (MemoryRegions.empty())
+ return nullptr;
+
+ // See if a region can be found by matching section flags.
+ for (auto &Pair : MemoryRegions) {
+ MemoryRegion *M = Pair.second;
+ if ((M->Flags & Sec->Flags) && (M->NegFlags & Sec->Flags) == 0)
+ return M;
+ }
+
+ // Otherwise, no suitable region was found.
+ if (Sec->Flags & SHF_ALLOC)
+ error("no memory region specified for section '" + Sec->Name + "'");
+ return nullptr;
+}
+
+static OutputSection *findFirstSection(PhdrEntry *Load) {
+ for (OutputSection *Sec : OutputSections)
+ if (Sec->PtLoad == Load)
+ return Sec;
+ return nullptr;
+}
+
+// This function assigns offsets to input sections and an output section
+// for a single sections command (e.g. ".text { *(.text); }").
+void LinkerScript::assignOffsets(OutputSection *Sec) {
+ if (!(Sec->Flags & SHF_ALLOC))
+ Dot = 0;
+ else if (Sec->AddrExpr)
+ setDot(Sec->AddrExpr, Sec->Location, false);
+
+ Ctx->MemRegion = Sec->MemRegion;
+ Ctx->LMARegion = Sec->LMARegion;
+ if (Ctx->MemRegion)
+ Dot = Ctx->MemRegion->CurPos;
+
+ switchTo(Sec);
+
+ if (Sec->LMAExpr)
+ Ctx->LMAOffset = Sec->LMAExpr().getValue() - Dot;
+
+ if (MemoryRegion *MR = Sec->LMARegion)
+ Ctx->LMAOffset = MR->CurPos - Dot;
+
+ // If neither AT nor AT> is specified for an allocatable section, the linker
+ // will set the LMA such that the difference between VMA and LMA for the
+ // section is the same as the preceding output section in the same region
+ // https://sourceware.org/binutils/docs-2.20/ld/Output-Section-LMA.html
+ // This, however, should only be done by the first "non-header" section
+ // in the segment.
+ if (PhdrEntry *L = Ctx->OutSec->PtLoad)
+ if (Sec == findFirstSection(L))
+ L->LMAOffset = Ctx->LMAOffset;
+
+ // We can call this method multiple times during the creation of
+ // thunks and want to start over calculation each time.
+ Sec->Size = 0;
+
+ // We visited SectionsCommands from processSectionCommands to
+ // layout sections. Now, we visit SectionsCommands again to fix
+ // section offsets.
+ for (BaseCommand *Base : Sec->SectionCommands) {
+ // This handles the assignments to symbol or to the dot.
+ if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) {
+ Cmd->Addr = Dot;
+ assignSymbol(Cmd, true);
+ Cmd->Size = Dot - Cmd->Addr;
+ continue;
+ }
+
+ // Handle BYTE(), SHORT(), LONG(), or QUAD().
+ if (auto *Cmd = dyn_cast<ByteCommand>(Base)) {
+ Cmd->Offset = Dot - Ctx->OutSec->Addr;
+ Dot += Cmd->Size;
+ expandOutputSection(Cmd->Size);
+ continue;
+ }
+
+ // Handle a single input section description command.
+ // It calculates and assigns the offsets for each section and also
+ // updates the output section size.
+ for (InputSection *Sec : cast<InputSectionDescription>(Base)->Sections)
+ output(Sec);
+ }
+}
+
+static bool isDiscardable(OutputSection &Sec) {
+ // We do not remove empty sections that are explicitly
+ // assigned to any segment.
+ if (!Sec.Phdrs.empty())
+ return false;
+
+ // We do not want to remove sections that reference symbols in address and
+ // other expressions. We add script symbols as undefined, and want to ensure
+ // all of them are defined in the output, hence have to keep them.
+ if (Sec.ExpressionsUseSymbols)
+ return false;
+
+ for (BaseCommand *Base : Sec.SectionCommands) {
+ if (auto Cmd = dyn_cast<SymbolAssignment>(Base))
+ // Don't create empty output sections just for unreferenced PROVIDE
+ // symbols.
+ if (Cmd->Name != "." && !Cmd->Sym)
+ continue;
+
+ if (!isa<InputSectionDescription>(*Base))
+ return false;
+ }
+ return true;
+}
+
+void LinkerScript::adjustSectionsBeforeSorting() {
+ // If the output section contains only symbol assignments, create a
+ // corresponding output section. The issue is what to do with linker script
+ // like ".foo : { symbol = 42; }". One option would be to convert it to
+ // "symbol = 42;". That is, move the symbol out of the empty section
+ // description. That seems to be what bfd does for this simple case. The
+ // problem is that this is not completely general. bfd will give up and
+ // create a dummy section too if there is a ". = . + 1" inside the section
+ // for example.
+ // Given that we want to create the section, we have to worry what impact
+ // it will have on the link. For example, if we just create a section with
+ // 0 for flags, it would change which PT_LOADs are created.
+ // We could remember that particular section is dummy and ignore it in
+ // other parts of the linker, but unfortunately there are quite a few places
+ // that would need to change:
+ // * The program header creation.
+ // * The orphan section placement.
+ // * The address assignment.
+ // The other option is to pick flags that minimize the impact the section
+ // will have on the rest of the linker. That is why we copy the flags from
+ // the previous sections. Only a few flags are needed to keep the impact low.
+ uint64_t Flags = SHF_ALLOC;
+
+ for (BaseCommand *&Cmd : SectionCommands) {
+ auto *Sec = dyn_cast<OutputSection>(Cmd);
+ if (!Sec)
+ continue;
+
+ // Handle align (e.g. ".foo : ALIGN(16) { ... }").
+ if (Sec->AlignExpr)
+ Sec->Alignment =
+ std::max<uint32_t>(Sec->Alignment, Sec->AlignExpr().getValue());
+
+ // A live output section means that some input section was added to it. It
+ // might have been removed (if it was empty synthetic section), but we at
+ // least know the flags.
+ if (Sec->Live)
+ Flags = Sec->Flags;
+
+ // We do not want to keep any special flags for output section
+ // in case it is empty.
+ bool IsEmpty = getInputSections(Sec).empty();
+ if (IsEmpty)
+ Sec->Flags = Flags & (SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR);
+
+ if (IsEmpty && isDiscardable(*Sec)) {
+ Sec->Live = false;
+ Cmd = nullptr;
+ }
+ }
+
+ // It is common practice to use very generic linker scripts. So for any
+ // given run some of the output sections in the script will be empty.
+ // We could create corresponding empty output sections, but that would
+ // clutter the output.
+ // We instead remove trivially empty sections. The bfd linker seems even
+ // more aggressive at removing them.
+ llvm::erase_if(SectionCommands, [&](BaseCommand *Base) { return !Base; });
+}
+
+void LinkerScript::adjustSectionsAfterSorting() {
+ // Try and find an appropriate memory region to assign offsets in.
+ for (BaseCommand *Base : SectionCommands) {
+ if (auto *Sec = dyn_cast<OutputSection>(Base)) {
+ if (!Sec->LMARegionName.empty()) {
+ if (MemoryRegion *M = MemoryRegions.lookup(Sec->LMARegionName))
+ Sec->LMARegion = M;
+ else
+ error("memory region '" + Sec->LMARegionName + "' not declared");
+ }
+ Sec->MemRegion = findMemoryRegion(Sec);
+ }
+ }
+
+ // If output section command doesn't specify any segments,
+ // and we haven't previously assigned any section to segment,
+ // then we simply assign section to the very first load segment.
+ // Below is an example of such linker script:
+ // PHDRS { seg PT_LOAD; }
+ // SECTIONS { .aaa : { *(.aaa) } }
+ std::vector<StringRef> DefPhdrs;
+ auto FirstPtLoad = llvm::find_if(PhdrsCommands, [](const PhdrsCommand &Cmd) {
+ return Cmd.Type == PT_LOAD;
+ });
+ if (FirstPtLoad != PhdrsCommands.end())
+ DefPhdrs.push_back(FirstPtLoad->Name);
+
+ // Walk the commands and propagate the program headers to commands that don't
+ // explicitly specify them.
+ for (BaseCommand *Base : SectionCommands) {
+ auto *Sec = dyn_cast<OutputSection>(Base);
+ if (!Sec)
+ continue;
+
+ if (Sec->Phdrs.empty()) {
+ // To match the bfd linker script behaviour, only propagate program
+ // headers to sections that are allocated.
+ if (Sec->Flags & SHF_ALLOC)
+ Sec->Phdrs = DefPhdrs;
+ } else {
+ DefPhdrs = Sec->Phdrs;
+ }
+ }
+}
+
+static uint64_t computeBase(uint64_t Min, bool AllocateHeaders) {
+ // If there is no SECTIONS or if the linkerscript is explicit about program
+ // headers, do our best to allocate them.
+ if (!Script->HasSectionsCommand || AllocateHeaders)
+ return 0;
+ // Otherwise only allocate program headers if that would not add a page.
+ return alignDown(Min, Config->MaxPageSize);
+}
+
+// Try to find an address for the file and program headers output sections,
+// which were unconditionally added to the first PT_LOAD segment earlier.
+//
+// When using the default layout, we check if the headers fit below the first
+// allocated section. When using a linker script, we also check if the headers
+// are covered by the output section. This allows omitting the headers by not
+// leaving enough space for them in the linker script; this pattern is common
+// in embedded systems.
+//
+// If there isn't enough space for these sections, we'll remove them from the
+// PT_LOAD segment, and we'll also remove the PT_PHDR segment.
+void LinkerScript::allocateHeaders(std::vector<PhdrEntry *> &Phdrs) {
+ uint64_t Min = std::numeric_limits<uint64_t>::max();
+ for (OutputSection *Sec : OutputSections)
+ if (Sec->Flags & SHF_ALLOC)
+ Min = std::min<uint64_t>(Min, Sec->Addr);
+
+ auto It = llvm::find_if(
+ Phdrs, [](const PhdrEntry *E) { return E->p_type == PT_LOAD; });
+ if (It == Phdrs.end())
+ return;
+ PhdrEntry *FirstPTLoad = *It;
+
+ bool HasExplicitHeaders =
+ llvm::any_of(PhdrsCommands, [](const PhdrsCommand &Cmd) {
+ return Cmd.HasPhdrs || Cmd.HasFilehdr;
+ });
+ uint64_t HeaderSize = getHeaderSize();
+ if (HeaderSize <= Min - computeBase(Min, HasExplicitHeaders)) {
+ Min = alignDown(Min - HeaderSize, Config->MaxPageSize);
+ Out::ElfHeader->Addr = Min;
+ Out::ProgramHeaders->Addr = Min + Out::ElfHeader->Size;
+ return;
+ }
+
+ // Error if we were explicitly asked to allocate headers.
+ if (HasExplicitHeaders)
+ error("could not allocate headers");
+
+ Out::ElfHeader->PtLoad = nullptr;
+ Out::ProgramHeaders->PtLoad = nullptr;
+ FirstPTLoad->FirstSec = findFirstSection(FirstPTLoad);
+
+ llvm::erase_if(Phdrs,
+ [](const PhdrEntry *E) { return E->p_type == PT_PHDR; });
+}
+
+LinkerScript::AddressState::AddressState() {
+ for (auto &MRI : Script->MemoryRegions) {
+ MemoryRegion *MR = MRI.second;
+ MR->CurPos = MR->Origin;
+ }
+}
+
+static uint64_t getInitialDot() {
+ // By default linker scripts use an initial value of 0 for '.',
+ // but prefer -image-base if set.
+ if (Script->HasSectionsCommand)
+ return Config->ImageBase ? *Config->ImageBase : 0;
+
+ uint64_t StartAddr = UINT64_MAX;
+ // The Sections with -T<section> have been sorted in order of ascending
+ // address. We must lower StartAddr if the lowest -T<section address> as
+ // calls to setDot() must be monotonically increasing.
+ for (auto &KV : Config->SectionStartMap)
+ StartAddr = std::min(StartAddr, KV.second);
+ return std::min(StartAddr, Target->getImageBase() + elf::getHeaderSize());
+}
+
+// Here we assign addresses as instructed by linker script SECTIONS
+// sub-commands. Doing that allows us to use final VA values, so here
+// we also handle rest commands like symbol assignments and ASSERTs.
+void LinkerScript::assignAddresses() {
+ Dot = getInitialDot();
+
+ auto Deleter = make_unique<AddressState>();
+ Ctx = Deleter.get();
+ ErrorOnMissingSection = true;
+ switchTo(Aether);
+
+ for (BaseCommand *Base : SectionCommands) {
+ if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) {
+ Cmd->Addr = Dot;
+ assignSymbol(Cmd, false);
+ Cmd->Size = Dot - Cmd->Addr;
+ continue;
+ }
+ assignOffsets(cast<OutputSection>(Base));
+ }
+ Ctx = nullptr;
+}
+
+// Creates program headers as instructed by PHDRS linker script command.
+std::vector<PhdrEntry *> LinkerScript::createPhdrs() {
+ std::vector<PhdrEntry *> Ret;
+
+ // Process PHDRS and FILEHDR keywords because they are not
+ // real output sections and cannot be added in the following loop.
+ for (const PhdrsCommand &Cmd : PhdrsCommands) {
+ PhdrEntry *Phdr = make<PhdrEntry>(Cmd.Type, Cmd.Flags ? *Cmd.Flags : PF_R);
+
+ if (Cmd.HasFilehdr)
+ Phdr->add(Out::ElfHeader);
+ if (Cmd.HasPhdrs)
+ Phdr->add(Out::ProgramHeaders);
+
+ if (Cmd.LMAExpr) {
+ Phdr->p_paddr = Cmd.LMAExpr().getValue();
+ Phdr->HasLMA = true;
+ }
+ Ret.push_back(Phdr);
+ }
+
+ // Add output sections to program headers.
+ for (OutputSection *Sec : OutputSections) {
+ // Assign headers specified by linker script
+ for (size_t Id : getPhdrIndices(Sec)) {
+ Ret[Id]->add(Sec);
+ if (!PhdrsCommands[Id].Flags.hasValue())
+ Ret[Id]->p_flags |= Sec->getPhdrFlags();
+ }
+ }
+ return Ret;
+}
+
+// Returns true if we should emit an .interp section.
+//
+// We usually do. But if PHDRS commands are given, and
+// no PT_INTERP is there, there's no place to emit an
+// .interp, so we don't do that in that case.
+bool LinkerScript::needsInterpSection() {
+ if (PhdrsCommands.empty())
+ return true;
+ for (PhdrsCommand &Cmd : PhdrsCommands)
+ if (Cmd.Type == PT_INTERP)
+ return true;
+ return false;
+}
+
+ExprValue LinkerScript::getSymbolValue(StringRef Name, const Twine &Loc) {
+ if (Name == ".") {
+ if (Ctx)
+ return {Ctx->OutSec, false, Dot - Ctx->OutSec->Addr, Loc};
+ error(Loc + ": unable to get location counter value");
+ return 0;
+ }
+
+ if (Symbol *Sym = Symtab->find(Name)) {
+ if (auto *DS = dyn_cast<Defined>(Sym))
+ return {DS->Section, false, DS->Value, Loc};
+ if (isa<SharedSymbol>(Sym))
+ if (!ErrorOnMissingSection)
+ return {nullptr, false, 0, Loc};
+ }
+
+ error(Loc + ": symbol not found: " + Name);
+ return 0;
+}
+
+// Returns the index of the segment named Name.
+static Optional<size_t> getPhdrIndex(ArrayRef<PhdrsCommand> Vec,
+ StringRef Name) {
+ for (size_t I = 0; I < Vec.size(); ++I)
+ if (Vec[I].Name == Name)
+ return I;
+ return None;
+}
+
+// Returns indices of ELF headers containing specific section. Each index is a
+// zero based number of ELF header listed within PHDRS {} script block.
+std::vector<size_t> LinkerScript::getPhdrIndices(OutputSection *Cmd) {
+ std::vector<size_t> Ret;
+
+ for (StringRef S : Cmd->Phdrs) {
+ if (Optional<size_t> Idx = getPhdrIndex(PhdrsCommands, S))
+ Ret.push_back(*Idx);
+ else if (S != "NONE")
+ error(Cmd->Location + ": section header '" + S +
+ "' is not listed in PHDRS");
+ }
+ return Ret;
+}
diff --git a/contrib/llvm/tools/lld/ELF/LinkerScript.h b/contrib/llvm/tools/lld/ELF/LinkerScript.h
new file mode 100644
index 000000000000..51161981efc8
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/LinkerScript.h
@@ -0,0 +1,314 @@
+//===- LinkerScript.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_LINKER_SCRIPT_H
+#define LLD_ELF_LINKER_SCRIPT_H
+
+#include "Config.h"
+#include "Writer.h"
+#include "lld/Common/LLVM.h"
+#include "lld/Common/Strings.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/MapVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <cstddef>
+#include <cstdint>
+#include <functional>
+#include <memory>
+#include <vector>
+
+namespace lld {
+namespace elf {
+
+class Defined;
+class InputSection;
+class InputSectionBase;
+class InputSectionBase;
+class OutputSection;
+class SectionBase;
+class Symbol;
+class ThunkSection;
+
+// This represents an r-value in the linker script.
+struct ExprValue {
+ ExprValue(SectionBase *Sec, bool ForceAbsolute, uint64_t Val,
+ const Twine &Loc)
+ : Sec(Sec), ForceAbsolute(ForceAbsolute), Val(Val), Loc(Loc.str()) {}
+
+ ExprValue(uint64_t Val) : ExprValue(nullptr, false, Val, "") {}
+
+ bool isAbsolute() const { return ForceAbsolute || Sec == nullptr; }
+ uint64_t getValue() const;
+ uint64_t getSecAddr() const;
+ uint64_t getSectionOffset() const;
+
+ // If a value is relative to a section, it has a non-null Sec.
+ SectionBase *Sec;
+
+ // True if this expression is enclosed in ABSOLUTE().
+ // This flag affects the return value of getValue().
+ bool ForceAbsolute;
+
+ uint64_t Val;
+ uint64_t Alignment = 1;
+
+ // Original source location. Used for error messages.
+ std::string Loc;
+};
+
+// This represents an expression in the linker script.
+// ScriptParser::readExpr reads an expression and returns an Expr.
+// Later, we evaluate the expression by calling the function.
+typedef std::function<ExprValue()> Expr;
+
+// This enum is used to implement linker script SECTIONS command.
+// https://sourceware.org/binutils/docs/ld/SECTIONS.html#SECTIONS
+enum SectionsCommandKind {
+ AssignmentKind, // . = expr or <sym> = expr
+ OutputSectionKind,
+ InputSectionKind,
+ ByteKind // BYTE(expr), SHORT(expr), LONG(expr) or QUAD(expr)
+};
+
+struct BaseCommand {
+ BaseCommand(int K) : Kind(K) {}
+ int Kind;
+};
+
+// This represents ". = <expr>" or "<symbol> = <expr>".
+struct SymbolAssignment : BaseCommand {
+ SymbolAssignment(StringRef Name, Expr E, std::string Loc)
+ : BaseCommand(AssignmentKind), Name(Name), Expression(E), Location(Loc) {}
+
+ static bool classof(const BaseCommand *C) {
+ return C->Kind == AssignmentKind;
+ }
+
+ // The LHS of an expression. Name is either a symbol name or ".".
+ StringRef Name;
+ Defined *Sym = nullptr;
+
+ // The RHS of an expression.
+ Expr Expression;
+
+ // Command attributes for PROVIDE, HIDDEN and PROVIDE_HIDDEN.
+ bool Provide = false;
+ bool Hidden = false;
+
+ // Holds file name and line number for error reporting.
+ std::string Location;
+
+ // A string representation of this command. We use this for -Map.
+ std::string CommandString;
+
+ // Address of this assignment command.
+ unsigned Addr;
+
+ // Size of this assignment command. This is usually 0, but if
+ // you move '.' this may be greater than 0.
+ unsigned Size;
+};
+
+// Linker scripts allow additional constraints to be put on ouput sections.
+// If an output section is marked as ONLY_IF_RO, the section is created
+// only if its input sections are read-only. Likewise, an output section
+// with ONLY_IF_RW is created if all input sections are RW.
+enum class ConstraintKind { NoConstraint, ReadOnly, ReadWrite };
+
+// This struct is used to represent the location and size of regions of
+// target memory. Instances of the struct are created by parsing the
+// MEMORY command.
+struct MemoryRegion {
+ MemoryRegion(StringRef Name, uint64_t Origin, uint64_t Length, uint32_t Flags,
+ uint32_t NegFlags)
+ : Name(Name), Origin(Origin), Length(Length), Flags(Flags),
+ NegFlags(NegFlags) {}
+
+ std::string Name;
+ uint64_t Origin;
+ uint64_t Length;
+ uint32_t Flags;
+ uint32_t NegFlags;
+ uint64_t CurPos = 0;
+};
+
+// This struct represents one section match pattern in SECTIONS() command.
+// It can optionally have negative match pattern for EXCLUDED_FILE command.
+// Also it may be surrounded with SORT() command, so contains sorting rules.
+struct SectionPattern {
+ SectionPattern(StringMatcher &&Pat1, StringMatcher &&Pat2)
+ : ExcludedFilePat(Pat1), SectionPat(Pat2),
+ SortOuter(SortSectionPolicy::Default),
+ SortInner(SortSectionPolicy::Default) {}
+
+ StringMatcher ExcludedFilePat;
+ StringMatcher SectionPat;
+ SortSectionPolicy SortOuter;
+ SortSectionPolicy SortInner;
+};
+
+struct InputSectionDescription : BaseCommand {
+ InputSectionDescription(StringRef FilePattern)
+ : BaseCommand(InputSectionKind), FilePat(FilePattern) {}
+
+ static bool classof(const BaseCommand *C) {
+ return C->Kind == InputSectionKind;
+ }
+
+ StringMatcher FilePat;
+
+ // Input sections that matches at least one of SectionPatterns
+ // will be associated with this InputSectionDescription.
+ std::vector<SectionPattern> SectionPatterns;
+
+ std::vector<InputSection *> Sections;
+
+ // Temporary record of synthetic ThunkSection instances and the pass that
+ // they were created in. This is used to insert newly created ThunkSections
+ // into Sections at the end of a createThunks() pass.
+ std::vector<std::pair<ThunkSection *, uint32_t>> ThunkSections;
+};
+
+// Represents BYTE(), SHORT(), LONG(), or QUAD().
+struct ByteCommand : BaseCommand {
+ ByteCommand(Expr E, unsigned Size, std::string CommandString)
+ : BaseCommand(ByteKind), CommandString(CommandString), Expression(E),
+ Size(Size) {}
+
+ static bool classof(const BaseCommand *C) { return C->Kind == ByteKind; }
+
+ // Keeps string representing the command. Used for -Map" is perhaps better.
+ std::string CommandString;
+
+ Expr Expression;
+
+ // This is just an offset of this assignment command in the output section.
+ unsigned Offset;
+
+ // Size of this data command.
+ unsigned Size;
+};
+
+struct PhdrsCommand {
+ StringRef Name;
+ unsigned Type = llvm::ELF::PT_NULL;
+ bool HasFilehdr = false;
+ bool HasPhdrs = false;
+ llvm::Optional<unsigned> Flags;
+ Expr LMAExpr = nullptr;
+};
+
+class LinkerScript final {
+ // Temporary state used in processSectionCommands() and assignAddresses()
+ // that must be reinitialized for each call to the above functions, and must
+ // not be used outside of the scope of a call to the above functions.
+ struct AddressState {
+ AddressState();
+ uint64_t ThreadBssOffset = 0;
+ OutputSection *OutSec = nullptr;
+ MemoryRegion *MemRegion = nullptr;
+ MemoryRegion *LMARegion = nullptr;
+ uint64_t LMAOffset = 0;
+ };
+
+ llvm::DenseMap<StringRef, OutputSection *> NameToOutputSection;
+
+ void addSymbol(SymbolAssignment *Cmd);
+ void assignSymbol(SymbolAssignment *Cmd, bool InSec);
+ void setDot(Expr E, const Twine &Loc, bool InSec);
+ void expandOutputSection(uint64_t Size);
+ void expandMemoryRegions(uint64_t Size);
+
+ std::vector<InputSection *>
+ computeInputSections(const InputSectionDescription *);
+
+ std::vector<InputSection *> createInputSectionList(OutputSection &Cmd);
+
+ std::vector<size_t> getPhdrIndices(OutputSection *Sec);
+
+ MemoryRegion *findMemoryRegion(OutputSection *Sec);
+
+ void switchTo(OutputSection *Sec);
+ uint64_t advance(uint64_t Size, unsigned Align);
+ void output(InputSection *Sec);
+
+ void assignOffsets(OutputSection *Sec);
+
+ // Ctx captures the local AddressState and makes it accessible
+ // deliberately. This is needed as there are some cases where we cannot just
+ // thread the current state through to a lambda function created by the
+ // script parser.
+ // This should remain a plain pointer as its lifetime is smaller than
+ // LinkerScript.
+ AddressState *Ctx = nullptr;
+
+ OutputSection *Aether;
+
+ uint64_t Dot;
+
+public:
+ OutputSection *createOutputSection(StringRef Name, StringRef Location);
+ OutputSection *getOrCreateOutputSection(StringRef Name);
+
+ bool hasPhdrsCommands() { return !PhdrsCommands.empty(); }
+ uint64_t getDot() { return Dot; }
+ void discard(ArrayRef<InputSection *> V);
+
+ ExprValue getSymbolValue(StringRef Name, const Twine &Loc);
+
+ void addOrphanSections();
+ void adjustSectionsBeforeSorting();
+ void adjustSectionsAfterSorting();
+
+ std::vector<PhdrEntry *> createPhdrs();
+ bool needsInterpSection();
+
+ bool shouldKeep(InputSectionBase *S);
+ void assignAddresses();
+ void allocateHeaders(std::vector<PhdrEntry *> &Phdrs);
+ void processSectionCommands();
+ void declareSymbols();
+
+ // Used to handle INSERT AFTER statements.
+ void processInsertCommands();
+
+ // SECTIONS command list.
+ std::vector<BaseCommand *> SectionCommands;
+
+ // PHDRS command list.
+ std::vector<PhdrsCommand> PhdrsCommands;
+
+ bool HasSectionsCommand = false;
+ bool ErrorOnMissingSection = false;
+
+ // List of section patterns specified with KEEP commands. They will
+ // be kept even if they are unused and --gc-sections is specified.
+ std::vector<InputSectionDescription *> KeptSections;
+
+ // A map from memory region name to a memory region descriptor.
+ llvm::MapVector<llvm::StringRef, MemoryRegion *> MemoryRegions;
+
+ // A list of symbols referenced by the script.
+ std::vector<llvm::StringRef> ReferencedSymbols;
+
+ // Used to implement INSERT [AFTER|BEFORE]. Contains commands that need
+ // to be inserted into SECTIONS commands list.
+ llvm::DenseMap<StringRef, std::vector<BaseCommand *>> InsertAfterCommands;
+ llvm::DenseMap<StringRef, std::vector<BaseCommand *>> InsertBeforeCommands;
+};
+
+extern LinkerScript *Script;
+
+} // end namespace elf
+} // end namespace lld
+
+#endif // LLD_ELF_LINKER_SCRIPT_H
diff --git a/contrib/llvm/tools/lld/ELF/MapFile.cpp b/contrib/llvm/tools/lld/ELF/MapFile.cpp
new file mode 100644
index 000000000000..b0dc6203008d
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/MapFile.cpp
@@ -0,0 +1,263 @@
+//===- MapFile.cpp --------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the -Map option. It shows lists in order and
+// hierarchically the output sections, input sections, input files and
+// symbol:
+//
+// Address Size Align Out In Symbol
+// 00201000 00000015 4 .text
+// 00201000 0000000e 4 test.o:(.text)
+// 0020100e 00000000 0 local
+// 00201005 00000000 0 f(int)
+//
+//===----------------------------------------------------------------------===//
+
+#include "MapFile.h"
+#include "InputFiles.h"
+#include "LinkerScript.h"
+#include "OutputSections.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "lld/Common/Strings.h"
+#include "lld/Common/Threads.h"
+#include "llvm/ADT/MapVector.h"
+#include "llvm/ADT/SetVector.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace llvm::object;
+
+using namespace lld;
+using namespace lld::elf;
+
+typedef DenseMap<const SectionBase *, SmallVector<Defined *, 4>> SymbolMapTy;
+
+static const std::string Indent8 = " "; // 8 spaces
+static const std::string Indent16 = " "; // 16 spaces
+
+// Print out the first three columns of a line.
+static void writeHeader(raw_ostream &OS, uint64_t VMA, uint64_t LMA,
+ uint64_t Size, uint64_t Align) {
+ if (Config->Is64)
+ OS << format("%16llx %16llx %8llx %5lld ", VMA, LMA, Size, Align);
+ else
+ OS << format("%8llx %8llx %8llx %5lld ", VMA, LMA, Size, Align);
+}
+
+// Returns a list of all symbols that we want to print out.
+static std::vector<Defined *> getSymbols() {
+ std::vector<Defined *> V;
+ for (InputFile *File : ObjectFiles)
+ for (Symbol *B : File->getSymbols())
+ if (auto *DR = dyn_cast<Defined>(B))
+ if (!DR->isSection() && DR->Section && DR->Section->Live &&
+ (DR->File == File || DR->NeedsPltAddr || DR->Section->Bss))
+ V.push_back(DR);
+ return V;
+}
+
+// Returns a map from sections to their symbols.
+static SymbolMapTy getSectionSyms(ArrayRef<Defined *> Syms) {
+ SymbolMapTy Ret;
+ for (Defined *DR : Syms)
+ Ret[DR->Section].push_back(DR);
+
+ // Sort symbols by address. We want to print out symbols in the
+ // order in the output file rather than the order they appeared
+ // in the input files.
+ for (auto &It : Ret) {
+ SmallVectorImpl<Defined *> &V = It.second;
+ std::stable_sort(V.begin(), V.end(), [](Defined *A, Defined *B) {
+ return A->getVA() < B->getVA();
+ });
+ }
+ return Ret;
+}
+
+// Construct a map from symbols to their stringified representations.
+// Demangling symbols (which is what toString() does) is slow, so
+// we do that in batch using parallel-for.
+static DenseMap<Symbol *, std::string>
+getSymbolStrings(ArrayRef<Defined *> Syms) {
+ std::vector<std::string> Str(Syms.size());
+ parallelForEachN(0, Syms.size(), [&](size_t I) {
+ raw_string_ostream OS(Str[I]);
+ OutputSection *OSec = Syms[I]->getOutputSection();
+ uint64_t VMA = Syms[I]->getVA();
+ uint64_t LMA = OSec ? OSec->getLMA() + VMA - OSec->getVA(0) : 0;
+ writeHeader(OS, VMA, LMA, Syms[I]->getSize(), 1);
+ OS << Indent16 << toString(*Syms[I]);
+ });
+
+ DenseMap<Symbol *, std::string> Ret;
+ for (size_t I = 0, E = Syms.size(); I < E; ++I)
+ Ret[Syms[I]] = std::move(Str[I]);
+ return Ret;
+}
+
+// Print .eh_frame contents. Since the section consists of EhSectionPieces,
+// we need a specialized printer for that section.
+//
+// .eh_frame tend to contain a lot of section pieces that are contiguous
+// both in input file and output file. Such pieces are squashed before
+// being displayed to make output compact.
+static void printEhFrame(raw_ostream &OS, OutputSection *OSec) {
+ std::vector<EhSectionPiece> Pieces;
+
+ auto Add = [&](const EhSectionPiece &P) {
+ // If P is adjacent to Last, squash the two.
+ if (!Pieces.empty()) {
+ EhSectionPiece &Last = Pieces.back();
+ if (Last.Sec == P.Sec && Last.InputOff + Last.Size == P.InputOff &&
+ Last.OutputOff + Last.Size == P.OutputOff) {
+ Last.Size += P.Size;
+ return;
+ }
+ }
+ Pieces.push_back(P);
+ };
+
+ // Gather section pieces.
+ for (const CieRecord *Rec : In.EhFrame->getCieRecords()) {
+ Add(*Rec->Cie);
+ for (const EhSectionPiece *Fde : Rec->Fdes)
+ Add(*Fde);
+ }
+
+ // Print out section pieces.
+ for (EhSectionPiece &P : Pieces) {
+ writeHeader(OS, OSec->Addr + P.OutputOff, OSec->getLMA() + P.OutputOff,
+ P.Size, 1);
+ OS << Indent8 << toString(P.Sec->File) << ":(" << P.Sec->Name << "+0x"
+ << Twine::utohexstr(P.InputOff) + ")\n";
+ }
+}
+
+void elf::writeMapFile() {
+ if (Config->MapFile.empty())
+ return;
+
+ // Open a map file for writing.
+ std::error_code EC;
+ raw_fd_ostream OS(Config->MapFile, EC, sys::fs::F_None);
+ if (EC) {
+ error("cannot open " + Config->MapFile + ": " + EC.message());
+ return;
+ }
+
+ // Collect symbol info that we want to print out.
+ std::vector<Defined *> Syms = getSymbols();
+ SymbolMapTy SectionSyms = getSectionSyms(Syms);
+ DenseMap<Symbol *, std::string> SymStr = getSymbolStrings(Syms);
+
+ // Print out the header line.
+ int W = Config->Is64 ? 16 : 8;
+ OS << right_justify("VMA", W) << ' ' << right_justify("LMA", W)
+ << " Size Align Out In Symbol\n";
+
+ OutputSection* OSec = nullptr;
+ for (BaseCommand *Base : Script->SectionCommands) {
+ if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) {
+ if (Cmd->Provide && !Cmd->Sym)
+ continue;
+ uint64_t LMA = OSec ? OSec->getLMA() + Cmd->Addr - OSec->getVA(0) : 0;
+ writeHeader(OS, Cmd->Addr, LMA, Cmd->Size, 1);
+ OS << Cmd->CommandString << '\n';
+ continue;
+ }
+
+ OSec = cast<OutputSection>(Base);
+ writeHeader(OS, OSec->Addr, OSec->getLMA(), OSec->Size, OSec->Alignment);
+ OS << OSec->Name << '\n';
+
+ // Dump symbols for each input section.
+ for (BaseCommand *Base : OSec->SectionCommands) {
+ if (auto *ISD = dyn_cast<InputSectionDescription>(Base)) {
+ for (InputSection *IS : ISD->Sections) {
+ if (IS == In.EhFrame) {
+ printEhFrame(OS, OSec);
+ continue;
+ }
+
+ writeHeader(OS, IS->getVA(0), OSec->getLMA() + IS->getOffset(0),
+ IS->getSize(), IS->Alignment);
+ OS << Indent8 << toString(IS) << '\n';
+ for (Symbol *Sym : SectionSyms[IS])
+ OS << SymStr[Sym] << '\n';
+ }
+ continue;
+ }
+
+ if (auto *Cmd = dyn_cast<ByteCommand>(Base)) {
+ writeHeader(OS, OSec->Addr + Cmd->Offset, OSec->getLMA() + Cmd->Offset,
+ Cmd->Size, 1);
+ OS << Indent8 << Cmd->CommandString << '\n';
+ continue;
+ }
+
+ if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) {
+ if (Cmd->Provide && !Cmd->Sym)
+ continue;
+ writeHeader(OS, Cmd->Addr, OSec->getLMA() + Cmd->Addr - OSec->getVA(0),
+ Cmd->Size, 1);
+ OS << Indent8 << Cmd->CommandString << '\n';
+ continue;
+ }
+ }
+ }
+}
+
+static void print(StringRef A, StringRef B) {
+ outs() << left_justify(A, 49) << " " << B << "\n";
+}
+
+// Output a cross reference table to stdout. This is for --cref.
+//
+// For each global symbol, we print out a file that defines the symbol
+// followed by files that uses that symbol. Here is an example.
+//
+// strlen /lib/x86_64-linux-gnu/libc.so.6
+// tools/lld/tools/lld/CMakeFiles/lld.dir/lld.cpp.o
+// lib/libLLVMSupport.a(PrettyStackTrace.cpp.o)
+//
+// In this case, strlen is defined by libc.so.6 and used by other two
+// files.
+void elf::writeCrossReferenceTable() {
+ if (!Config->Cref)
+ return;
+
+ // Collect symbols and files.
+ MapVector<Symbol *, SetVector<InputFile *>> Map;
+ for (InputFile *File : ObjectFiles) {
+ for (Symbol *Sym : File->getSymbols()) {
+ if (isa<SharedSymbol>(Sym))
+ Map[Sym].insert(File);
+ if (auto *D = dyn_cast<Defined>(Sym))
+ if (!D->isLocal() && (!D->Section || D->Section->Live))
+ Map[D].insert(File);
+ }
+ }
+
+ // Print out a header.
+ outs() << "Cross Reference Table\n\n";
+ print("Symbol", "File");
+
+ // Print out a table.
+ for (auto KV : Map) {
+ Symbol *Sym = KV.first;
+ SetVector<InputFile *> &Files = KV.second;
+
+ print(toString(*Sym), toString(Sym->File));
+ for (InputFile *File : Files)
+ if (File != Sym->File)
+ print("", toString(File));
+ }
+}
diff --git a/contrib/llvm/tools/lld/ELF/MapFile.h b/contrib/llvm/tools/lld/ELF/MapFile.h
new file mode 100644
index 000000000000..0282425888b7
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/MapFile.h
@@ -0,0 +1,20 @@
+//===- MapFile.h ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_MAPFILE_H
+#define LLD_ELF_MAPFILE_H
+
+namespace lld {
+namespace elf {
+void writeMapFile();
+void writeCrossReferenceTable();
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/ELF/MarkLive.cpp b/contrib/llvm/tools/lld/ELF/MarkLive.cpp
new file mode 100644
index 000000000000..8d0ec091c327
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/MarkLive.cpp
@@ -0,0 +1,324 @@
+//===- MarkLive.cpp -------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements --gc-sections, which is a feature to remove unused
+// sections from output. Unused sections are sections that are not reachable
+// from known GC-root symbols or sections. Naturally the feature is
+// implemented as a mark-sweep garbage collector.
+//
+// Here's how it works. Each InputSectionBase has a "Live" bit. The bit is off
+// by default. Starting with GC-root symbols or sections, markLive function
+// defined in this file visits all reachable sections to set their Live
+// bits. Writer will then ignore sections whose Live bits are off, so that
+// such sections are not included into output.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MarkLive.h"
+#include "InputSection.h"
+#include "LinkerScript.h"
+#include "OutputSections.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+#include "Target.h"
+#include "lld/Common/Memory.h"
+#include "lld/Common/Strings.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Object/ELF.h"
+#include <functional>
+#include <vector>
+
+using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+
+using namespace lld;
+using namespace lld::elf;
+
+template <class ELFT>
+static typename ELFT::uint getAddend(InputSectionBase &Sec,
+ const typename ELFT::Rel &Rel) {
+ return Target->getImplicitAddend(Sec.data().begin() + Rel.r_offset,
+ Rel.getType(Config->IsMips64EL));
+}
+
+template <class ELFT>
+static typename ELFT::uint getAddend(InputSectionBase &Sec,
+ const typename ELFT::Rela &Rel) {
+ return Rel.r_addend;
+}
+
+// There are normally few input sections whose names are valid C
+// identifiers, so we just store a std::vector instead of a multimap.
+static DenseMap<StringRef, std::vector<InputSectionBase *>> CNamedSections;
+
+template <class ELFT, class RelT>
+static void
+resolveReloc(InputSectionBase &Sec, RelT &Rel,
+ llvm::function_ref<void(InputSectionBase *, uint64_t)> Fn) {
+ Symbol &B = Sec.getFile<ELFT>()->getRelocTargetSym(Rel);
+
+ // If a symbol is referenced in a live section, it is used.
+ B.Used = true;
+ if (auto *SS = dyn_cast<SharedSymbol>(&B))
+ if (!SS->isWeak())
+ SS->getFile<ELFT>().IsNeeded = true;
+
+ if (auto *D = dyn_cast<Defined>(&B)) {
+ auto *RelSec = dyn_cast_or_null<InputSectionBase>(D->Section);
+ if (!RelSec)
+ return;
+ uint64_t Offset = D->Value;
+ if (D->isSection())
+ Offset += getAddend<ELFT>(Sec, Rel);
+ Fn(RelSec, Offset);
+ return;
+ }
+
+ if (!B.isDefined())
+ for (InputSectionBase *Sec : CNamedSections.lookup(B.getName()))
+ Fn(Sec, 0);
+}
+
+// Calls Fn for each section that Sec refers to via relocations.
+template <class ELFT>
+static void
+forEachSuccessor(InputSection &Sec,
+ llvm::function_ref<void(InputSectionBase *, uint64_t)> Fn) {
+ if (Sec.AreRelocsRela) {
+ for (const typename ELFT::Rela &Rel : Sec.template relas<ELFT>())
+ resolveReloc<ELFT>(Sec, Rel, Fn);
+ } else {
+ for (const typename ELFT::Rel &Rel : Sec.template rels<ELFT>())
+ resolveReloc<ELFT>(Sec, Rel, Fn);
+ }
+
+ for (InputSectionBase *IS : Sec.DependentSections)
+ Fn(IS, 0);
+}
+
+// The .eh_frame section is an unfortunate special case.
+// The section is divided in CIEs and FDEs and the relocations it can have are
+// * CIEs can refer to a personality function.
+// * FDEs can refer to a LSDA
+// * FDEs refer to the function they contain information about
+// The last kind of relocation cannot keep the referred section alive, or they
+// would keep everything alive in a common object file. In fact, each FDE is
+// alive if the section it refers to is alive.
+// To keep things simple, in here we just ignore the last relocation kind. The
+// other two keep the referred section alive.
+//
+// A possible improvement would be to fully process .eh_frame in the middle of
+// the gc pass. With that we would be able to also gc some sections holding
+// LSDAs and personality functions if we found that they were unused.
+template <class ELFT, class RelTy>
+static void
+scanEhFrameSection(EhInputSection &EH, ArrayRef<RelTy> Rels,
+ llvm::function_ref<void(InputSectionBase *, uint64_t)> Fn) {
+ const endianness E = ELFT::TargetEndianness;
+
+ for (unsigned I = 0, N = EH.Pieces.size(); I < N; ++I) {
+ EhSectionPiece &Piece = EH.Pieces[I];
+ unsigned FirstRelI = Piece.FirstRelocation;
+ if (FirstRelI == (unsigned)-1)
+ continue;
+ if (read32<E>(Piece.data().data() + 4) == 0) {
+ // This is a CIE, we only need to worry about the first relocation. It is
+ // known to point to the personality function.
+ resolveReloc<ELFT>(EH, Rels[FirstRelI], Fn);
+ continue;
+ }
+ // This is a FDE. The relocations point to the described function or to
+ // a LSDA. We only need to keep the LSDA alive, so ignore anything that
+ // points to executable sections.
+ typename ELFT::uint PieceEnd = Piece.InputOff + Piece.Size;
+ for (unsigned I2 = FirstRelI, N2 = Rels.size(); I2 < N2; ++I2) {
+ const RelTy &Rel = Rels[I2];
+ if (Rel.r_offset >= PieceEnd)
+ break;
+ resolveReloc<ELFT>(EH, Rels[I2],
+ [&](InputSectionBase *Sec, uint64_t Offset) {
+ if (Sec && Sec != &InputSection::Discarded &&
+ !(Sec->Flags & SHF_EXECINSTR))
+ Fn(Sec, 0);
+ });
+ }
+ }
+}
+
+template <class ELFT>
+static void
+scanEhFrameSection(EhInputSection &EH,
+ llvm::function_ref<void(InputSectionBase *, uint64_t)> Fn) {
+ if (!EH.NumRelocations)
+ return;
+
+ if (EH.AreRelocsRela)
+ scanEhFrameSection<ELFT>(EH, EH.template relas<ELFT>(), Fn);
+ else
+ scanEhFrameSection<ELFT>(EH, EH.template rels<ELFT>(), Fn);
+}
+
+// Some sections are used directly by the loader, so they should never be
+// garbage-collected. This function returns true if a given section is such
+// section.
+template <class ELFT> static bool isReserved(InputSectionBase *Sec) {
+ switch (Sec->Type) {
+ case SHT_FINI_ARRAY:
+ case SHT_INIT_ARRAY:
+ case SHT_NOTE:
+ case SHT_PREINIT_ARRAY:
+ return true;
+ default:
+ StringRef S = Sec->Name;
+ return S.startswith(".ctors") || S.startswith(".dtors") ||
+ S.startswith(".init") || S.startswith(".fini") ||
+ S.startswith(".jcr");
+ }
+}
+
+// This is the main function of the garbage collector.
+// Starting from GC-root sections, this function visits all reachable
+// sections to set their "Live" bits.
+template <class ELFT> static void doGcSections() {
+ SmallVector<InputSection *, 256> Q;
+ CNamedSections.clear();
+
+ auto Enqueue = [&](InputSectionBase *Sec, uint64_t Offset) {
+ // Skip over discarded sections. This in theory shouldn't happen, because
+ // the ELF spec doesn't allow a relocation to point to a deduplicated
+ // COMDAT section directly. Unfortunately this happens in practice (e.g.
+ // .eh_frame) so we need to add a check.
+ if (Sec == &InputSection::Discarded)
+ return;
+
+
+ // Usually, a whole section is marked as live or dead, but in mergeable
+ // (splittable) sections, each piece of data has independent liveness bit.
+ // So we explicitly tell it which offset is in use.
+ if (auto *MS = dyn_cast<MergeInputSection>(Sec))
+ MS->getSectionPiece(Offset)->Live = true;
+
+ if (Sec->Live)
+ return;
+ Sec->Live = true;
+
+ // Add input section to the queue.
+ if (InputSection *S = dyn_cast<InputSection>(Sec))
+ Q.push_back(S);
+ };
+
+ auto MarkSymbol = [&](Symbol *Sym) {
+ if (auto *D = dyn_cast_or_null<Defined>(Sym))
+ if (auto *IS = dyn_cast_or_null<InputSectionBase>(D->Section))
+ Enqueue(IS, D->Value);
+ };
+
+ // Add GC root symbols.
+ MarkSymbol(Symtab->find(Config->Entry));
+ MarkSymbol(Symtab->find(Config->Init));
+ MarkSymbol(Symtab->find(Config->Fini));
+ for (StringRef S : Config->Undefined)
+ MarkSymbol(Symtab->find(S));
+ for (StringRef S : Script->ReferencedSymbols)
+ MarkSymbol(Symtab->find(S));
+
+ // Preserve externally-visible symbols if the symbols defined by this
+ // file can interrupt other ELF file's symbols at runtime.
+ for (Symbol *S : Symtab->getSymbols())
+ if (S->includeInDynsym())
+ MarkSymbol(S);
+
+ // Preserve special sections and those which are specified in linker
+ // script KEEP command.
+ for (InputSectionBase *Sec : InputSections) {
+ // Mark .eh_frame sections as live because there are usually no relocations
+ // that point to .eh_frames. Otherwise, the garbage collector would drop
+ // all of them. We also want to preserve personality routines and LSDA
+ // referenced by .eh_frame sections, so we scan them for that here.
+ if (auto *EH = dyn_cast<EhInputSection>(Sec)) {
+ EH->Live = true;
+ scanEhFrameSection<ELFT>(*EH, Enqueue);
+ }
+
+ if (Sec->Flags & SHF_LINK_ORDER)
+ continue;
+
+ if (isReserved<ELFT>(Sec) || Script->shouldKeep(Sec)) {
+ Enqueue(Sec, 0);
+ } else if (isValidCIdentifier(Sec->Name)) {
+ CNamedSections[Saver.save("__start_" + Sec->Name)].push_back(Sec);
+ CNamedSections[Saver.save("__stop_" + Sec->Name)].push_back(Sec);
+ }
+ }
+
+ // Mark all reachable sections.
+ while (!Q.empty())
+ forEachSuccessor<ELFT>(*Q.pop_back_val(), Enqueue);
+}
+
+// Before calling this function, Live bits are off for all
+// input sections. This function make some or all of them on
+// so that they are emitted to the output file.
+template <class ELFT> void elf::markLive() {
+ if (!Config->GcSections) {
+ // If -gc-sections is missing, no sections are removed.
+ for (InputSectionBase *Sec : InputSections)
+ Sec->Live = true;
+
+ // If a DSO defines a symbol referenced in a regular object, it is needed.
+ for (Symbol *Sym : Symtab->getSymbols())
+ if (auto *S = dyn_cast<SharedSymbol>(Sym))
+ if (S->IsUsedInRegularObj && !S->isWeak())
+ S->getFile<ELFT>().IsNeeded = true;
+ return;
+ }
+
+ // The -gc-sections option works only for SHF_ALLOC sections
+ // (sections that are memory-mapped at runtime). So we can
+ // unconditionally make non-SHF_ALLOC sections alive except
+ // SHF_LINK_ORDER and SHT_REL/SHT_RELA sections.
+ //
+ // Usually, SHF_ALLOC sections are not removed even if they are
+ // unreachable through relocations because reachability is not
+ // a good signal whether they are garbage or not (e.g. there is
+ // usually no section referring to a .comment section, but we
+ // want to keep it.).
+ //
+ // Note on SHF_LINK_ORDER: Such sections contain metadata and they
+ // have a reverse dependency on the InputSection they are linked with.
+ // We are able to garbage collect them.
+ //
+ // Note on SHF_REL{,A}: Such sections reach here only when -r
+ // or -emit-reloc were given. And they are subject of garbage
+ // collection because, if we remove a text section, we also
+ // remove its relocation section.
+ for (InputSectionBase *Sec : InputSections) {
+ bool IsAlloc = (Sec->Flags & SHF_ALLOC);
+ bool IsLinkOrder = (Sec->Flags & SHF_LINK_ORDER);
+ bool IsRel = (Sec->Type == SHT_REL || Sec->Type == SHT_RELA);
+ if (!IsAlloc && !IsLinkOrder && !IsRel)
+ Sec->Live = true;
+ }
+
+ // Follow the graph to mark all live sections.
+ doGcSections<ELFT>();
+
+ // Report garbage-collected sections.
+ if (Config->PrintGcSections)
+ for (InputSectionBase *Sec : InputSections)
+ if (!Sec->Live)
+ message("removing unused section " + toString(Sec));
+}
+
+template void elf::markLive<ELF32LE>();
+template void elf::markLive<ELF32BE>();
+template void elf::markLive<ELF64LE>();
+template void elf::markLive<ELF64BE>();
diff --git a/contrib/llvm/tools/lld/ELF/MarkLive.h b/contrib/llvm/tools/lld/ELF/MarkLive.h
new file mode 100644
index 000000000000..c9b99add34de
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/MarkLive.h
@@ -0,0 +1,21 @@
+//===- MarkLive.h -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_MARKLIVE_H
+#define LLD_ELF_MARKLIVE_H
+
+namespace lld {
+namespace elf {
+
+template <class ELFT> void markLive();
+
+} // namespace elf
+} // namespace lld
+
+#endif // LLD_ELF_MARKLIVE_H
diff --git a/contrib/llvm/tools/lld/ELF/Options.td b/contrib/llvm/tools/lld/ELF/Options.td
new file mode 100644
index 000000000000..bc203193661b
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Options.td
@@ -0,0 +1,521 @@
+include "llvm/Option/OptParser.td"
+
+// For options whose names are multiple letters, either one dash or
+// two can precede the option name except those that start with 'o'.
+class F<string name>: Flag<["--", "-"], name>;
+class J<string name>: Joined<["--", "-"], name>;
+
+multiclass Eq<string name, string help> {
+ def NAME: Separate<["--", "-"], name>;
+ def NAME # _eq: Joined<["--", "-"], name # "=">, Alias<!cast<Separate>(NAME)>,
+ HelpText<help>;
+}
+
+multiclass B<string name, string help1, string help2> {
+ def NAME: Flag<["--", "-"], name>, HelpText<help1>;
+ def no_ # NAME: Flag<["--", "-"], "no-" # name>, HelpText<help2>;
+}
+
+defm auxiliary: Eq<"auxiliary", "Set DT_AUXILIARY field to the specified name">;
+
+def Bsymbolic: F<"Bsymbolic">, HelpText<"Bind defined symbols locally">;
+
+def Bsymbolic_functions: F<"Bsymbolic-functions">,
+ HelpText<"Bind defined function symbols locally">;
+
+def Bdynamic: F<"Bdynamic">, HelpText<"Link against shared libraries (default)">;
+
+def Bstatic: F<"Bstatic">, HelpText<"Do not link against shared libraries">;
+
+def build_id: F<"build-id">, HelpText<"Alias for --build-id=fast">;
+
+def build_id_eq: J<"build-id=">, HelpText<"Generate build ID note">,
+ MetaVarName<"[fast,md5,sha,uuid,0x<hexstring>]">;
+
+defm check_sections: B<"check-sections",
+ "Check section addresses for overlaps (default)",
+ "Do not check section addresses for overlaps">;
+
+defm compress_debug_sections:
+ Eq<"compress-debug-sections", "Compress DWARF debug sections">,
+ MetaVarName<"[none,zlib]">;
+
+defm defsym: Eq<"defsym", "Define a symbol alias">, MetaVarName<"<symbol>=<value>">;
+
+defm split_stack_adjust_size
+ : Eq<"split-stack-adjust-size",
+ "Specify adjustment to stack size when a split-stack function calls a "
+ "non-split-stack function">,
+ MetaVarName<"<value>">;
+
+defm library_path:
+ Eq<"library-path", "Add a directory to the library search path">, MetaVarName<"<dir>">;
+
+def O: JoinedOrSeparate<["-"], "O">, HelpText<"Optimize output file size">;
+
+defm Tbss: Eq<"Tbss", "Same as --section-start with .bss as the sectionname">;
+
+defm Tdata: Eq<"Tdata", "Same as --section-start with .data as the sectionname">;
+
+defm Ttext: Eq<"Ttext", "Same as --section-start with .text as the sectionname">;
+
+defm allow_multiple_definition: B<"allow-multiple-definition",
+ "Allow multiple definitions",
+ "Do not allow multiple definitions (default)">;
+
+defm apply_dynamic_relocs: B<"apply-dynamic-relocs",
+ "Apply link-time values for dynamic relocations",
+ "Do not apply link-time values for dynamic relocations (default)">;
+
+defm as_needed: B<"as-needed",
+ "Only set DT_NEEDED for shared libraries if used",
+ "Always set DT_NEEDED for shared libraries (default)">;
+
+defm call_graph_ordering_file:
+ Eq<"call-graph-ordering-file", "Layout sections to optimize the given callgraph">;
+
+defm call_graph_profile_sort: B<"call-graph-profile-sort",
+ "Reorder sections with call graph profile (default)",
+ "Do not reorder sections with call graph profile">;
+
+// -chroot doesn't have a help text because it is an internal option.
+def chroot: Separate<["--", "-"], "chroot">;
+
+def color_diagnostics: F<"color-diagnostics">,
+ HelpText<"Alias for --color-diagnostics=always">;
+
+def color_diagnostics_eq: J<"color-diagnostics=">,
+ HelpText<"Use colors in diagnostics">,
+ MetaVarName<"[auto,always,never]">;
+
+defm cref: B<"cref",
+ "Output cross reference table",
+ "Do not output cross reference table">;
+
+defm define_common: B<"define-common",
+ "Assign space to common symbols",
+ "Do not assign space to common symbols">;
+
+defm demangle: B<"demangle",
+ "Demangle symbol names (default)",
+ "Do not demangle symbol names">;
+
+def disable_new_dtags: F<"disable-new-dtags">,
+ HelpText<"Disable new dynamic tags">;
+
+def discard_all: F<"discard-all">, HelpText<"Delete all local symbols">;
+
+def discard_locals: F<"discard-locals">,
+ HelpText<"Delete temporary local symbols">;
+
+def discard_none: F<"discard-none">,
+ HelpText<"Keep all symbols in the symbol table">;
+
+defm dynamic_linker: Eq<"dynamic-linker", "Which dynamic linker to use">;
+
+defm dynamic_list: Eq<"dynamic-list", "Read a list of dynamic symbols">;
+
+defm eh_frame_hdr: B<"eh-frame-hdr",
+ "Request creation of .eh_frame_hdr section and PT_GNU_EH_FRAME segment header",
+ "Do not create .eh_frame_hdr section">;
+
+def emit_relocs: F<"emit-relocs">, HelpText<"Generate relocations in output">;
+
+def enable_new_dtags: F<"enable-new-dtags">,
+ HelpText<"Enable new dynamic tags (default)">;
+
+def end_group: F<"end-group">,
+ HelpText<"Ignored for compatibility with GNU unless you pass --warn-backrefs">;
+
+def end_lib: F<"end-lib">,
+ HelpText<"End a grouping of objects that should be treated as if they were together in an archive">;
+
+defm entry: Eq<"entry", "Name of entry point symbol">,
+ MetaVarName<"<entry>">;
+
+defm error_limit:
+ Eq<"error-limit", "Maximum number of errors to emit before stopping (0 = no limit)">;
+
+def error_unresolved_symbols: F<"error-unresolved-symbols">,
+ HelpText<"Report unresolved symbols as errors">;
+
+defm exclude_libs: Eq<"exclude-libs", "Exclude static libraries from automatic export">;
+
+defm execute_only: B<"execute-only",
+ "Mark executable sections unreadable",
+ "Mark executable sections readable (default)">;
+
+defm export_dynamic: B<"export-dynamic",
+ "Put symbols in the dynamic symbol table",
+ "Do not put symbols in the dynamic symbol table (default)">;
+
+defm export_dynamic_symbol:
+ Eq<"export-dynamic-symbol", "Put a symbol in the dynamic symbol table">;
+
+defm fatal_warnings: B<"fatal-warnings",
+ "Treat warnings as errors",
+ "Do not treat warnings as errors (default)">;
+
+defm filter: Eq<"filter", "Set DT_FILTER field to the specified name">;
+
+defm fini: Eq<"fini", "Specify a finalizer function">, MetaVarName<"<symbol>">;
+
+def fix_cortex_a53_843419: F<"fix-cortex-a53-843419">,
+ HelpText<"Apply fixes for AArch64 Cortex-A53 erratum 843419">;
+
+defm format: Eq<"format", "Change the input format of the inputs following this option">,
+ MetaVarName<"[default,elf,binary]">;
+
+defm gc_sections: B<"gc-sections",
+ "Enable garbage collection of unused sections",
+ "Disable garbage collection of unused sections (default)">;
+
+defm gdb_index: B<"gdb-index",
+ "Generate .gdb_index section",
+ "Do not generate .gdb_index section (default)">;
+
+defm gnu_unique: B<"gnu-unique",
+ "Enable STB_GNU_UNIQUE symbol binding (default)",
+ "Disable STB_GNU_UNIQUE symbol binding">;
+
+defm hash_style: Eq<"hash-style", "Specify hash style (sysv, gnu or both)">;
+
+def help: F<"help">, HelpText<"Print option help">;
+
+def icf_all: F<"icf=all">, HelpText<"Enable identical code folding">;
+
+def icf_safe: F<"icf=safe">, HelpText<"Enable safe identical code folding">;
+
+def icf_none: F<"icf=none">, HelpText<"Disable identical code folding (default)">;
+
+def ignore_function_address_equality: F<"ignore-function-address-equality">,
+ HelpText<"lld can break the address equality of functions">;
+
+def ignore_data_address_equality: F<"ignore-data-address-equality">,
+ HelpText<"lld can break the address equality of data">;
+
+defm image_base: Eq<"image-base", "Set the base address">;
+
+defm init: Eq<"init", "Specify an initializer function">,
+ MetaVarName<"<symbol>">;
+
+defm just_symbols: Eq<"just-symbols", "Just link symbols">;
+
+defm keep_unique: Eq<"keep-unique", "Do not fold this symbol during ICF">;
+
+defm library: Eq<"library", "Root name of library to use">,
+ MetaVarName<"<libName>">;
+
+def m: JoinedOrSeparate<["-"], "m">, HelpText<"Set target emulation">;
+
+defm Map: Eq<"Map", "Print a link map to the specified file">;
+
+defm merge_exidx_entries: B<"merge-exidx-entries",
+ "Enable merging .ARM.exidx entries (default)",
+ "Disable merging .ARM.exidx entries">;
+
+def nostdlib: F<"nostdlib">,
+ HelpText<"Only search directories specified on the command line">;
+
+def no_color_diagnostics: F<"no-color-diagnostics">,
+ HelpText<"Do not use colors in diagnostics">;
+
+def no_dynamic_linker: F<"no-dynamic-linker">,
+ HelpText<"Inhibit output of .interp section">;
+
+def noinhibit_exec: F<"noinhibit-exec">,
+ HelpText<"Retain the executable output file whenever it is still usable">;
+
+def no_omagic: F<"no-omagic">, MetaVarName<"<magic>">,
+ HelpText<"Do not set the text data sections to be writable">;
+
+def no_rosegment: F<"no-rosegment">,
+ HelpText<"Do not put read-only non-executable sections in their own segment">;
+
+def no_undefined: F<"no-undefined">,
+ HelpText<"Report unresolved symbols even if the linker is creating a shared library">;
+
+def o: JoinedOrSeparate<["-"], "o">, MetaVarName<"<path>">,
+ HelpText<"Path to file to write output">;
+
+def oformat: Separate<["--"], "oformat">, MetaVarName<"<format>">,
+ HelpText<"Specify the binary format for the output object file">;
+
+def omagic: Flag<["--"], "omagic">, MetaVarName<"<magic>">,
+ HelpText<"Set the text and data sections to be readable and writable">;
+
+defm orphan_handling:
+ Eq<"orphan-handling", "Control how orphan sections are handled when linker script used">;
+
+defm pack_dyn_relocs:
+ Eq<"pack-dyn-relocs", "Pack dynamic relocations in the given format">,
+ MetaVarName<"[none,android,relr,android+relr]">;
+
+defm use_android_relr_tags: B<"use-android-relr-tags",
+ "Use SHT_ANDROID_RELR / DT_ANDROID_RELR* tags instead of SHT_RELR / DT_RELR*",
+ "Use SHT_RELR / DT_RELR* tags (default)">;
+
+def pic_veneer: F<"pic-veneer">,
+ HelpText<"Always generate position independent thunks (veneers)">;
+
+defm pie: B<"pie",
+ "Create a position independent executable",
+ "Do not create a position independent executable (default)">;
+
+defm print_gc_sections: B<"print-gc-sections",
+ "List removed unused sections",
+ "Do not list removed unused sections (default)">;
+
+defm print_icf_sections: B<"print-icf-sections",
+ "List identical folded sections",
+ "Do not list identical folded sections (default)">;
+
+def pop_state: F<"pop-state">,
+ HelpText<"Undo the effect of -push-state">;
+
+def push_state: F<"push-state">,
+ HelpText<"Save the current state of -as-needed, -static and -whole-archive">;
+
+def print_map: F<"print-map">,
+ HelpText<"Print a link map to the standard output">;
+
+defm reproduce: Eq<"reproduce", "Dump linker invocation and input files for debugging">;
+
+defm rpath: Eq<"rpath", "Add a DT_RUNPATH to the output">;
+
+def relocatable: F<"relocatable">, HelpText<"Create relocatable object file">;
+
+defm retain_symbols_file:
+ Eq<"retain-symbols-file", "Retain only the symbols listed in the file">,
+ MetaVarName<"<file>">;
+
+defm script: Eq<"script", "Read linker script">;
+
+defm section_start: Eq<"section-start", "Set address of section">,
+ MetaVarName<"<address>">;
+
+def shared: F<"shared">, HelpText<"Build a shared object">;
+
+defm soname: Eq<"soname", "Set DT_SONAME">;
+
+defm sort_section:
+ Eq<"sort-section", "Specifies sections sorting rule when linkerscript is used">;
+
+def start_group: F<"start-group">,
+ HelpText<"Ignored for compatibility with GNU unless you pass --warn-backrefs">;
+
+def start_lib: F<"start-lib">,
+ HelpText<"Start a grouping of objects that should be treated as if they were together in an archive">;
+
+def strip_all: F<"strip-all">, HelpText<"Strip all symbols">;
+
+def strip_debug: F<"strip-debug">, HelpText<"Strip debugging information">;
+
+defm symbol_ordering_file:
+ Eq<"symbol-ordering-file", "Layout sections to place symbols in the order specified by symbol ordering file">;
+
+defm sysroot: Eq<"sysroot", "Set the system root">;
+
+def target1_rel: F<"target1-rel">, HelpText<"Interpret R_ARM_TARGET1 as R_ARM_REL32">;
+
+def target1_abs: F<"target1-abs">, HelpText<"Interpret R_ARM_TARGET1 as R_ARM_ABS32 (default)">;
+
+defm target2:
+ Eq<"target2", "Interpret R_ARM_TARGET2 as <type>, where <type> is one of rel, abs, or got-rel">,
+ MetaVarName<"<type>">;
+
+defm threads: B<"threads",
+ "Run the linker multi-threaded (default)",
+ "Do not run the linker multi-threaded">;
+
+defm toc_optimize : B<"toc-optimize",
+ "(PowerPC64) Enable TOC related optimizations (default)",
+ "(PowerPC64) Disable TOC related optimizations">;
+
+def trace: F<"trace">, HelpText<"Print the names of the input files">;
+
+defm trace_symbol: Eq<"trace-symbol", "Trace references to symbols">;
+
+defm undefined: Eq<"undefined", "Force undefined symbol during linking">,
+ MetaVarName<"<symbol>">;
+
+defm unresolved_symbols:
+ Eq<"unresolved-symbols", "Determine how to handle unresolved symbols">;
+
+defm undefined_version: B<"undefined-version",
+ "Allow unused version in version script (default)",
+ "Report version scripts that refer undefined symbols">;
+
+defm rsp_quoting: Eq<"rsp-quoting", "Quoting style for response files">,
+ MetaVarName<"[posix,windows]">;
+
+def v: Flag<["-"], "v">, HelpText<"Display the version number">;
+
+def verbose: F<"verbose">, HelpText<"Verbose mode">;
+
+def version: F<"version">, HelpText<"Display the version number and exit">;
+
+defm version_script: Eq<"version-script", "Read a version script">;
+
+defm warn_backrefs: B<"warn-backrefs",
+ "Warn about backward symbol references to fetch archive members",
+ "Do not warn about backward symbol references to fetch archive members (default)">;
+
+defm warn_common: B<"warn-common",
+ "Warn about duplicate common symbols",
+ "Do not warn about duplicate common symbols (default)">;
+
+defm warn_ifunc_textrel: B<"warn-ifunc-textrel",
+ "Warn about using ifunc symbols with text relocations",
+ "Do not warn about using ifunc symbols with text relocations (default)">;
+
+defm warn_symbol_ordering: B<"warn-symbol-ordering",
+ "Warn about problems with the symbol ordering file (default)",
+ "Do not warn about problems with the symbol ordering file">;
+
+def warn_unresolved_symbols: F<"warn-unresolved-symbols">,
+ HelpText<"Report unresolved symbols as warnings">;
+
+defm whole_archive: B<"whole-archive",
+ "Force load of all members in a static library",
+ "Do not force load of all members in a static library (default)">;
+
+defm wrap: Eq<"wrap", "Use wrapper functions for symbol">,
+ MetaVarName<"<symbol>=<symbol>">;
+
+def z: JoinedOrSeparate<["-"], "z">, MetaVarName<"<option>">,
+ HelpText<"Linker option extensions">;
+
+// Aliases
+def: Separate<["-"], "f">, Alias<auxiliary>, HelpText<"Alias for --auxiliary">;
+def: F<"call_shared">, Alias<Bdynamic>, HelpText<"Alias for --Bdynamic">;
+def: F<"dy">, Alias<Bdynamic>, HelpText<"Alias for --Bdynamic">;
+def: F<"dn">, Alias<Bstatic>, HelpText<"Alias for --Bstatic">;
+def: F<"non_shared">, Alias<Bstatic>, HelpText<"Alias for --Bstatic">;
+def: F<"static">, Alias<Bstatic>, HelpText<"Alias for --Bstatic">;
+def: Flag<["-"], "d">, Alias<define_common>, HelpText<"Alias for --define-common">;
+def: F<"dc">, Alias<define_common>, HelpText<"Alias for --define-common">;
+def: F<"dp">, Alias<define_common>, HelpText<"Alias for --define-common">;
+def: Flag<["-"], "x">, Alias<discard_all>, HelpText<"Alias for --discard-all">;
+def: Flag<["-"], "X">, Alias<discard_locals>, HelpText<"Alias for --discard-locals">;
+def: Flag<["-"], "q">, Alias<emit_relocs>, HelpText<"Alias for --emit-relocs">;
+def: Flag<["-"], ")">, Alias<end_group>, HelpText<"Alias for --end-group">;
+def: JoinedOrSeparate<["-"], "e">, Alias<entry>, HelpText<"Alias for --entry">;
+def: Flag<["-"], "E">, Alias<export_dynamic>, HelpText<"Alias for --export-dynamic">;
+def: Separate<["-"], "F">, Alias<filter>, HelpText<"Alias for --filter">;
+def: Separate<["-"], "b">, Alias<format>, HelpText<"Alias for --format">;
+def: JoinedOrSeparate<["-"], "l">, Alias<library>, HelpText<"Alias for --library">;
+def: JoinedOrSeparate<["-"], "L">, Alias<library_path>, HelpText<"Alias for --library-path">;
+def: F<"no-pic-executable">, Alias<no_pie>, HelpText<"Alias for --no-pie">;
+def: Flag<["-"], "N">, Alias<omagic>, HelpText<"Alias for --omagic">;
+def: Joined<["--"], "output=">, Alias<o>, HelpText<"Alias for -o">;
+def: Separate<["--"], "output">, Alias<o>, HelpText<"Alias for -o">;
+def: F<"pic-executable">, Alias<pie>, HelpText<"Alias for --pie">;
+def: Flag<["-"], "M">, Alias<print_map>, HelpText<"Alias for --print-map">;
+def: Flag<["-"], "r">, Alias<relocatable>, HelpText<"Alias for --relocatable">;
+def: JoinedOrSeparate<["-"], "R">, Alias<rpath>, HelpText<"Alias for --rpath">;
+def: JoinedOrSeparate<["-"], "T">, Alias<script>, HelpText<"Alias for --script">;
+def: F<"Bshareable">, Alias<shared>, HelpText<"Alias for --shared">;
+def: JoinedOrSeparate<["-"], "h">, Alias<soname>, HelpText<"Alias for --soname">;
+def: Flag<["-"], "(">, Alias<start_group>, HelpText<"Alias for --start-group">;
+def: Flag<["-"], "s">, Alias<strip_all>, HelpText<"Alias for --strip-all">;
+def: Flag<["-"], "S">, Alias<strip_debug>, HelpText<"Alias for --strip-debug">;
+def: Flag<["-"], "t">, Alias<trace>, HelpText<"Alias for --trace">;
+def: JoinedOrSeparate<["-"], "y">, Alias<trace_symbol>, HelpText<"Alias for --trace-symbol">;
+def: Separate<["-", "--"], "Ttext-segment">, Alias<Ttext>, HelpText<"Alias for --Ttext">;
+def: Joined<["-", "--"], "Ttext-segment=">, Alias<Ttext>, HelpText<"Alias for --Ttext">;
+def: JoinedOrSeparate<["-"], "u">, Alias<undefined>, HelpText<"Alias for --undefined">;
+def: Flag<["-"], "V">, Alias<version>, HelpText<"Alias for --version">;
+
+// LTO-related options.
+def lto_aa_pipeline: J<"lto-aa-pipeline=">,
+ HelpText<"AA pipeline to run during LTO. Used in conjunction with -lto-newpm-passes">;
+def lto_debug_pass_manager: F<"lto-debug-pass-manager">,
+ HelpText<"Debug new pass manager">;
+def lto_new_pass_manager: F<"lto-new-pass-manager">,
+ HelpText<"Use new pass manager">;
+def lto_newpm_passes: J<"lto-newpm-passes=">,
+ HelpText<"Passes to run during LTO">;
+def lto_O: J<"lto-O">, MetaVarName<"<opt-level>">,
+ HelpText<"Optimization level for LTO">;
+def lto_partitions: J<"lto-partitions=">,
+ HelpText<"Number of LTO codegen partitions">;
+def lto_sample_profile: J<"lto-sample-profile=">,
+ HelpText<"Sample profile file path">;
+def disable_verify: F<"disable-verify">;
+defm mllvm: Eq<"mllvm", "Additional arguments to forward to LLVM's option processing">;
+def opt_remarks_filename: Separate<["--"], "opt-remarks-filename">,
+ HelpText<"YAML output file for optimization remarks">;
+def opt_remarks_with_hotness: Flag<["--"], "opt-remarks-with-hotness">,
+ HelpText<"Include hotness information in the optimization remarks file">;
+defm plugin_opt: Eq<"plugin-opt", "specifies LTO options for compatibility with GNU linkers">;
+def save_temps: F<"save-temps">;
+def thinlto_cache_dir: J<"thinlto-cache-dir=">,
+ HelpText<"Path to ThinLTO cached object file directory">;
+defm thinlto_cache_policy: Eq<"thinlto-cache-policy", "Pruning policy for the ThinLTO cache">;
+def thinlto_jobs: J<"thinlto-jobs=">, HelpText<"Number of ThinLTO jobs">;
+
+def: J<"plugin-opt=O">, Alias<lto_O>, HelpText<"Alias for -lto-O">;
+def: F<"plugin-opt=debug-pass-manager">,
+ Alias<lto_debug_pass_manager>, HelpText<"Alias for -lto-debug-pass-manager">;
+def: F<"plugin-opt=disable-verify">, Alias<disable_verify>, HelpText<"Alias for -disable-verify">;
+def plugin_opt_dwo_dir_eq: J<"plugin-opt=dwo_dir=">,
+ HelpText<"Directory to store .dwo files when LTO and debug fission are used">;
+def plugin_opt_emit_llvm: F<"plugin-opt=emit-llvm">;
+def: J<"plugin-opt=jobs=">, Alias<thinlto_jobs>, HelpText<"Alias for -thinlto-jobs">;
+def: J<"plugin-opt=lto-partitions=">, Alias<lto_partitions>, HelpText<"Alias for -lto-partitions">;
+def plugin_opt_mcpu_eq: J<"plugin-opt=mcpu=">;
+def: F<"plugin-opt=new-pass-manager">,
+ Alias<lto_new_pass_manager>, HelpText<"Alias for -lto-new-pass-manager">;
+def plugin_opt_obj_path_eq: J<"plugin-opt=obj-path=">;
+def: J<"plugin-opt=sample-profile=">,
+ Alias<lto_sample_profile>, HelpText<"Alias for -lto-sample-profile">;
+def: F<"plugin-opt=save-temps">, Alias<save_temps>, HelpText<"Alias for -save-temps">;
+def plugin_opt_thinlto_emit_imports_files: F<"plugin-opt=thinlto-emit-imports-files">;
+def plugin_opt_thinlto_index_only: F<"plugin-opt=thinlto-index-only">;
+def plugin_opt_thinlto_index_only_eq: J<"plugin-opt=thinlto-index-only=">;
+def plugin_opt_thinlto_object_suffix_replace_eq: J<"plugin-opt=thinlto-object-suffix-replace=">;
+def plugin_opt_thinlto_prefix_replace_eq: J<"plugin-opt=thinlto-prefix-replace=">;
+
+// Ignore LTO plugin-related options.
+// clang -flto passes -plugin and -plugin-opt to the linker. This is required
+// for ld.gold and ld.bfd to get LTO working. But it's not for lld which doesn't
+// rely on a plugin. Instead of detecting which linker is used on clang side we
+// just ignore the option on lld side as it's easier. In fact, the linker could
+// be called 'ld' and understanding which linker is used would require parsing of
+// --version output.
+defm plugin: Eq<"plugin", "Ignored for compatibility with GNU linkers">;
+
+def plugin_opt_fresolution_eq: J<"plugin-opt=-fresolution=">;
+def plugin_opt_pass_through_eq: J<"plugin-opt=-pass-through=">;
+def plugin_opt_thinlto: J<"plugin-opt=thinlto">;
+def plugin_opt_slash: J<"plugin-opt=/">;
+
+// Options listed below are silently ignored for now for compatibility.
+def: F<"allow-shlib-undefined">;
+def: F<"detect-odr-violations">;
+def: Flag<["-"], "g">;
+def: F<"long-plt">;
+def: F<"no-add-needed">;
+def: F<"no-allow-shlib-undefined">;
+def: F<"no-copy-dt-needed-entries">;
+def: F<"no-ctors-in-init-array">;
+def: F<"no-keep-memory">;
+def: F<"no-mmap-output-file">;
+def: F<"no-warn-mismatch">;
+def: Separate<["--", "-"], "rpath-link">;
+def: J<"rpath-link=">;
+def: F<"sort-common">;
+def: F<"stats">;
+def: F<"warn-execstack">;
+def: F<"warn-once">;
+def: F<"warn-shared-textrel">;
+def: F<"EB">;
+def: F<"EL">;
+def: JoinedOrSeparate<["-"], "G">;
+def: F<"Qy">;
+
+// Hidden option used for testing MIPS multi-GOT implementation.
+defm mips_got_size:
+ Eq<"mips-got-size", "Max size of a single MIPS GOT. 0x10000 by default.">,
+ Flags<[HelpHidden]>;
diff --git a/contrib/llvm/tools/lld/ELF/OutputSections.cpp b/contrib/llvm/tools/lld/ELF/OutputSections.cpp
new file mode 100644
index 000000000000..c1442c078736
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/OutputSections.cpp
@@ -0,0 +1,437 @@
+//===- OutputSections.cpp -------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "OutputSections.h"
+#include "Config.h"
+#include "LinkerScript.h"
+#include "SymbolTable.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "lld/Common/Memory.h"
+#include "lld/Common/Strings.h"
+#include "lld/Common/Threads.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/Support/Compression.h"
+#include "llvm/Support/MD5.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/SHA1.h"
+
+using namespace llvm;
+using namespace llvm::dwarf;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+
+using namespace lld;
+using namespace lld::elf;
+
+uint8_t Out::First;
+PhdrEntry *Out::TlsPhdr;
+OutputSection *Out::ElfHeader;
+OutputSection *Out::ProgramHeaders;
+OutputSection *Out::PreinitArray;
+OutputSection *Out::InitArray;
+OutputSection *Out::FiniArray;
+
+std::vector<OutputSection *> elf::OutputSections;
+
+uint32_t OutputSection::getPhdrFlags() const {
+ uint32_t Ret = 0;
+ if (Config->EMachine != EM_ARM || !(Flags & SHF_ARM_PURECODE))
+ Ret |= PF_R;
+ if (Flags & SHF_WRITE)
+ Ret |= PF_W;
+ if (Flags & SHF_EXECINSTR)
+ Ret |= PF_X;
+ return Ret;
+}
+
+template <class ELFT>
+void OutputSection::writeHeaderTo(typename ELFT::Shdr *Shdr) {
+ Shdr->sh_entsize = Entsize;
+ Shdr->sh_addralign = Alignment;
+ Shdr->sh_type = Type;
+ Shdr->sh_offset = Offset;
+ Shdr->sh_flags = Flags;
+ Shdr->sh_info = Info;
+ Shdr->sh_link = Link;
+ Shdr->sh_addr = Addr;
+ Shdr->sh_size = Size;
+ Shdr->sh_name = ShName;
+}
+
+OutputSection::OutputSection(StringRef Name, uint32_t Type, uint64_t Flags)
+ : BaseCommand(OutputSectionKind),
+ SectionBase(Output, Name, Flags, /*Entsize*/ 0, /*Alignment*/ 1, Type,
+ /*Info*/ 0, /*Link*/ 0) {
+ Live = false;
+}
+
+// We allow sections of types listed below to merged into a
+// single progbits section. This is typically done by linker
+// scripts. Merging nobits and progbits will force disk space
+// to be allocated for nobits sections. Other ones don't require
+// any special treatment on top of progbits, so there doesn't
+// seem to be a harm in merging them.
+static bool canMergeToProgbits(unsigned Type) {
+ return Type == SHT_NOBITS || Type == SHT_PROGBITS || Type == SHT_INIT_ARRAY ||
+ Type == SHT_PREINIT_ARRAY || Type == SHT_FINI_ARRAY ||
+ Type == SHT_NOTE;
+}
+
+void OutputSection::addSection(InputSection *IS) {
+ if (!Live) {
+ // If IS is the first section to be added to this section,
+ // initialize Type, Entsize and flags from IS.
+ Live = true;
+ Type = IS->Type;
+ Entsize = IS->Entsize;
+ Flags = IS->Flags;
+ } else {
+ // Otherwise, check if new type or flags are compatible with existing ones.
+ unsigned Mask = SHF_TLS | SHF_LINK_ORDER;
+ if ((Flags & Mask) != (IS->Flags & Mask))
+ error("incompatible section flags for " + Name + "\n>>> " + toString(IS) +
+ ": 0x" + utohexstr(IS->Flags) + "\n>>> output section " + Name +
+ ": 0x" + utohexstr(Flags));
+
+ if (Type != IS->Type) {
+ if (!canMergeToProgbits(Type) || !canMergeToProgbits(IS->Type))
+ error("section type mismatch for " + IS->Name + "\n>>> " +
+ toString(IS) + ": " +
+ getELFSectionTypeName(Config->EMachine, IS->Type) +
+ "\n>>> output section " + Name + ": " +
+ getELFSectionTypeName(Config->EMachine, Type));
+ Type = SHT_PROGBITS;
+ }
+ }
+
+ IS->Parent = this;
+ uint64_t AndMask =
+ Config->EMachine == EM_ARM ? (uint64_t)SHF_ARM_PURECODE : 0;
+ uint64_t OrMask = ~AndMask;
+ uint64_t AndFlags = (Flags & IS->Flags) & AndMask;
+ uint64_t OrFlags = (Flags | IS->Flags) & OrMask;
+ Flags = AndFlags | OrFlags;
+
+ Alignment = std::max(Alignment, IS->Alignment);
+
+ // If this section contains a table of fixed-size entries, sh_entsize
+ // holds the element size. If it contains elements of different size we
+ // set sh_entsize to 0.
+ if (Entsize != IS->Entsize)
+ Entsize = 0;
+
+ if (!IS->Assigned) {
+ IS->Assigned = true;
+ if (SectionCommands.empty() ||
+ !isa<InputSectionDescription>(SectionCommands.back()))
+ SectionCommands.push_back(make<InputSectionDescription>(""));
+ auto *ISD = cast<InputSectionDescription>(SectionCommands.back());
+ ISD->Sections.push_back(IS);
+ }
+}
+
+static void sortByOrder(MutableArrayRef<InputSection *> In,
+ llvm::function_ref<int(InputSectionBase *S)> Order) {
+ typedef std::pair<int, InputSection *> Pair;
+ auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; };
+
+ std::vector<Pair> V;
+ for (InputSection *S : In)
+ V.push_back({Order(S), S});
+ std::stable_sort(V.begin(), V.end(), Comp);
+
+ for (size_t I = 0; I < V.size(); ++I)
+ In[I] = V[I].second;
+}
+
+uint64_t elf::getHeaderSize() {
+ if (Config->OFormatBinary)
+ return 0;
+ return Out::ElfHeader->Size + Out::ProgramHeaders->Size;
+}
+
+bool OutputSection::classof(const BaseCommand *C) {
+ return C->Kind == OutputSectionKind;
+}
+
+void OutputSection::sort(llvm::function_ref<int(InputSectionBase *S)> Order) {
+ assert(Live);
+ for (BaseCommand *B : SectionCommands)
+ if (auto *ISD = dyn_cast<InputSectionDescription>(B))
+ sortByOrder(ISD->Sections, Order);
+}
+
+// Fill [Buf, Buf + Size) with Filler.
+// This is used for linker script "=fillexp" command.
+static void fill(uint8_t *Buf, size_t Size,
+ const std::array<uint8_t, 4> &Filler) {
+ size_t I = 0;
+ for (; I + 4 < Size; I += 4)
+ memcpy(Buf + I, Filler.data(), 4);
+ memcpy(Buf + I, Filler.data(), Size - I);
+}
+
+// Compress section contents if this section contains debug info.
+template <class ELFT> void OutputSection::maybeCompress() {
+ typedef typename ELFT::Chdr Elf_Chdr;
+
+ // Compress only DWARF debug sections.
+ if (!Config->CompressDebugSections || (Flags & SHF_ALLOC) ||
+ !Name.startswith(".debug_"))
+ return;
+
+ // Create a section header.
+ ZDebugHeader.resize(sizeof(Elf_Chdr));
+ auto *Hdr = reinterpret_cast<Elf_Chdr *>(ZDebugHeader.data());
+ Hdr->ch_type = ELFCOMPRESS_ZLIB;
+ Hdr->ch_size = Size;
+ Hdr->ch_addralign = Alignment;
+
+ // Write section contents to a temporary buffer and compress it.
+ std::vector<uint8_t> Buf(Size);
+ writeTo<ELFT>(Buf.data());
+ if (Error E = zlib::compress(toStringRef(Buf), CompressedData))
+ fatal("compress failed: " + llvm::toString(std::move(E)));
+
+ // Update section headers.
+ Size = sizeof(Elf_Chdr) + CompressedData.size();
+ Flags |= SHF_COMPRESSED;
+}
+
+static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) {
+ if (Size == 1)
+ *Buf = Data;
+ else if (Size == 2)
+ write16(Buf, Data);
+ else if (Size == 4)
+ write32(Buf, Data);
+ else if (Size == 8)
+ write64(Buf, Data);
+ else
+ llvm_unreachable("unsupported Size argument");
+}
+
+template <class ELFT> void OutputSection::writeTo(uint8_t *Buf) {
+ if (Type == SHT_NOBITS)
+ return;
+
+ Loc = Buf;
+
+ // If -compress-debug-section is specified and if this is a debug seciton,
+ // we've already compressed section contents. If that's the case,
+ // just write it down.
+ if (!CompressedData.empty()) {
+ memcpy(Buf, ZDebugHeader.data(), ZDebugHeader.size());
+ memcpy(Buf + ZDebugHeader.size(), CompressedData.data(),
+ CompressedData.size());
+ return;
+ }
+
+ // Write leading padding.
+ std::vector<InputSection *> Sections = getInputSections(this);
+ std::array<uint8_t, 4> Filler = getFiller();
+ bool NonZeroFiller = read32(Filler.data()) != 0;
+ if (NonZeroFiller)
+ fill(Buf, Sections.empty() ? Size : Sections[0]->OutSecOff, Filler);
+
+ parallelForEachN(0, Sections.size(), [&](size_t I) {
+ InputSection *IS = Sections[I];
+ IS->writeTo<ELFT>(Buf);
+
+ // Fill gaps between sections.
+ if (NonZeroFiller) {
+ uint8_t *Start = Buf + IS->OutSecOff + IS->getSize();
+ uint8_t *End;
+ if (I + 1 == Sections.size())
+ End = Buf + Size;
+ else
+ End = Buf + Sections[I + 1]->OutSecOff;
+ fill(Start, End - Start, Filler);
+ }
+ });
+
+ // Linker scripts may have BYTE()-family commands with which you
+ // can write arbitrary bytes to the output. Process them if any.
+ for (BaseCommand *Base : SectionCommands)
+ if (auto *Data = dyn_cast<ByteCommand>(Base))
+ writeInt(Buf + Data->Offset, Data->Expression().getValue(), Data->Size);
+}
+
+template <class ELFT>
+static void finalizeShtGroup(OutputSection *OS,
+ InputSection *Section) {
+ assert(Config->Relocatable);
+
+ // sh_link field for SHT_GROUP sections should contain the section index of
+ // the symbol table.
+ OS->Link = In.SymTab->getParent()->SectionIndex;
+
+ // sh_info then contain index of an entry in symbol table section which
+ // provides signature of the section group.
+ ObjFile<ELFT> *Obj = Section->getFile<ELFT>();
+ ArrayRef<Symbol *> Symbols = Obj->getSymbols();
+ OS->Info = In.SymTab->getSymbolIndex(Symbols[Section->Info]);
+}
+
+template <class ELFT> void OutputSection::finalize() {
+ if (Type == SHT_NOBITS)
+ for (BaseCommand *Base : SectionCommands)
+ if (isa<ByteCommand>(Base))
+ Type = SHT_PROGBITS;
+
+ std::vector<InputSection *> V = getInputSections(this);
+ InputSection *First = V.empty() ? nullptr : V[0];
+
+ if (Flags & SHF_LINK_ORDER) {
+ // We must preserve the link order dependency of sections with the
+ // SHF_LINK_ORDER flag. The dependency is indicated by the sh_link field. We
+ // need to translate the InputSection sh_link to the OutputSection sh_link,
+ // all InputSections in the OutputSection have the same dependency.
+ if (auto *D = First->getLinkOrderDep())
+ Link = D->getParent()->SectionIndex;
+ }
+
+ if (Type == SHT_GROUP) {
+ finalizeShtGroup<ELFT>(this, First);
+ return;
+ }
+
+ if (!Config->CopyRelocs || (Type != SHT_RELA && Type != SHT_REL))
+ return;
+
+ if (isa<SyntheticSection>(First))
+ return;
+
+ Link = In.SymTab->getParent()->SectionIndex;
+ // sh_info for SHT_REL[A] sections should contain the section header index of
+ // the section to which the relocation applies.
+ InputSectionBase *S = First->getRelocatedSection();
+ Info = S->getOutputSection()->SectionIndex;
+ Flags |= SHF_INFO_LINK;
+}
+
+// Returns true if S matches /Filename.?\.o$/.
+static bool isCrtBeginEnd(StringRef S, StringRef Filename) {
+ if (!S.endswith(".o"))
+ return false;
+ S = S.drop_back(2);
+ if (S.endswith(Filename))
+ return true;
+ return !S.empty() && S.drop_back().endswith(Filename);
+}
+
+static bool isCrtbegin(StringRef S) { return isCrtBeginEnd(S, "crtbegin"); }
+static bool isCrtend(StringRef S) { return isCrtBeginEnd(S, "crtend"); }
+
+// .ctors and .dtors are sorted by this priority from highest to lowest.
+//
+// 1. The section was contained in crtbegin (crtbegin contains
+// some sentinel value in its .ctors and .dtors so that the runtime
+// can find the beginning of the sections.)
+//
+// 2. The section has an optional priority value in the form of ".ctors.N"
+// or ".dtors.N" where N is a number. Unlike .{init,fini}_array,
+// they are compared as string rather than number.
+//
+// 3. The section is just ".ctors" or ".dtors".
+//
+// 4. The section was contained in crtend, which contains an end marker.
+//
+// In an ideal world, we don't need this function because .init_array and
+// .ctors are duplicate features (and .init_array is newer.) However, there
+// are too many real-world use cases of .ctors, so we had no choice to
+// support that with this rather ad-hoc semantics.
+static bool compCtors(const InputSection *A, const InputSection *B) {
+ bool BeginA = isCrtbegin(A->File->getName());
+ bool BeginB = isCrtbegin(B->File->getName());
+ if (BeginA != BeginB)
+ return BeginA;
+ bool EndA = isCrtend(A->File->getName());
+ bool EndB = isCrtend(B->File->getName());
+ if (EndA != EndB)
+ return EndB;
+ StringRef X = A->Name;
+ StringRef Y = B->Name;
+ assert(X.startswith(".ctors") || X.startswith(".dtors"));
+ assert(Y.startswith(".ctors") || Y.startswith(".dtors"));
+ X = X.substr(6);
+ Y = Y.substr(6);
+ return X < Y;
+}
+
+// Sorts input sections by the special rules for .ctors and .dtors.
+// Unfortunately, the rules are different from the one for .{init,fini}_array.
+// Read the comment above.
+void OutputSection::sortCtorsDtors() {
+ assert(SectionCommands.size() == 1);
+ auto *ISD = cast<InputSectionDescription>(SectionCommands[0]);
+ std::stable_sort(ISD->Sections.begin(), ISD->Sections.end(), compCtors);
+}
+
+// If an input string is in the form of "foo.N" where N is a number,
+// return N. Otherwise, returns 65536, which is one greater than the
+// lowest priority.
+int elf::getPriority(StringRef S) {
+ size_t Pos = S.rfind('.');
+ if (Pos == StringRef::npos)
+ return 65536;
+ int V;
+ if (!to_integer(S.substr(Pos + 1), V, 10))
+ return 65536;
+ return V;
+}
+
+std::vector<InputSection *> elf::getInputSections(OutputSection *OS) {
+ std::vector<InputSection *> Ret;
+ for (BaseCommand *Base : OS->SectionCommands)
+ if (auto *ISD = dyn_cast<InputSectionDescription>(Base))
+ Ret.insert(Ret.end(), ISD->Sections.begin(), ISD->Sections.end());
+ return Ret;
+}
+
+// Sorts input sections by section name suffixes, so that .foo.N comes
+// before .foo.M if N < M. Used to sort .{init,fini}_array.N sections.
+// We want to keep the original order if the priorities are the same
+// because the compiler keeps the original initialization order in a
+// translation unit and we need to respect that.
+// For more detail, read the section of the GCC's manual about init_priority.
+void OutputSection::sortInitFini() {
+ // Sort sections by priority.
+ sort([](InputSectionBase *S) { return getPriority(S->Name); });
+}
+
+std::array<uint8_t, 4> OutputSection::getFiller() {
+ if (Filler)
+ return *Filler;
+ if (Flags & SHF_EXECINSTR)
+ return Target->TrapInstr;
+ return {0, 0, 0, 0};
+}
+
+template void OutputSection::writeHeaderTo<ELF32LE>(ELF32LE::Shdr *Shdr);
+template void OutputSection::writeHeaderTo<ELF32BE>(ELF32BE::Shdr *Shdr);
+template void OutputSection::writeHeaderTo<ELF64LE>(ELF64LE::Shdr *Shdr);
+template void OutputSection::writeHeaderTo<ELF64BE>(ELF64BE::Shdr *Shdr);
+
+template void OutputSection::writeTo<ELF32LE>(uint8_t *Buf);
+template void OutputSection::writeTo<ELF32BE>(uint8_t *Buf);
+template void OutputSection::writeTo<ELF64LE>(uint8_t *Buf);
+template void OutputSection::writeTo<ELF64BE>(uint8_t *Buf);
+
+template void OutputSection::maybeCompress<ELF32LE>();
+template void OutputSection::maybeCompress<ELF32BE>();
+template void OutputSection::maybeCompress<ELF64LE>();
+template void OutputSection::maybeCompress<ELF64BE>();
+
+template void OutputSection::finalize<ELF32LE>();
+template void OutputSection::finalize<ELF32BE>();
+template void OutputSection::finalize<ELF64LE>();
+template void OutputSection::finalize<ELF64BE>();
diff --git a/contrib/llvm/tools/lld/ELF/OutputSections.h b/contrib/llvm/tools/lld/ELF/OutputSections.h
new file mode 100644
index 000000000000..113bf6836926
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/OutputSections.h
@@ -0,0 +1,153 @@
+//===- OutputSections.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_OUTPUT_SECTIONS_H
+#define LLD_ELF_OUTPUT_SECTIONS_H
+
+#include "Config.h"
+#include "InputSection.h"
+#include "LinkerScript.h"
+#include "Relocations.h"
+#include "lld/Common/LLVM.h"
+#include "llvm/MC/StringTableBuilder.h"
+#include "llvm/Object/ELF.h"
+#include <array>
+
+namespace lld {
+namespace elf {
+
+struct PhdrEntry;
+class Symbol;
+struct EhSectionPiece;
+class EhInputSection;
+class InputSection;
+class InputSectionBase;
+class MergeInputSection;
+class OutputSection;
+template <class ELFT> class ObjFile;
+template <class ELFT> class SharedFile;
+class SharedSymbol;
+class Defined;
+
+// This represents a section in an output file.
+// It is composed of multiple InputSections.
+// The writer creates multiple OutputSections and assign them unique,
+// non-overlapping file offsets and VAs.
+class OutputSection final : public BaseCommand, public SectionBase {
+public:
+ OutputSection(StringRef Name, uint32_t Type, uint64_t Flags);
+
+ static bool classof(const SectionBase *S) {
+ return S->kind() == SectionBase::Output;
+ }
+
+ static bool classof(const BaseCommand *C);
+
+ uint64_t getLMA() const { return PtLoad ? Addr + PtLoad->LMAOffset : Addr; }
+ template <typename ELFT> void writeHeaderTo(typename ELFT::Shdr *SHdr);
+
+ uint32_t SectionIndex = UINT32_MAX;
+ unsigned SortRank;
+
+ uint32_t getPhdrFlags() const;
+
+ // Pointer to the PT_LOAD segment, which this section resides in. This field
+ // is used to correctly compute file offset of a section. When two sections
+ // share the same load segment, difference between their file offsets should
+ // be equal to difference between their virtual addresses. To compute some
+ // section offset we use the following formula: Off = Off_first + VA -
+ // VA_first, where Off_first and VA_first is file offset and VA of first
+ // section in PT_LOAD.
+ PhdrEntry *PtLoad = nullptr;
+
+ // Pointer to a relocation section for this section. Usually nullptr because
+ // we consume relocations, but if --emit-relocs is specified (which is rare),
+ // it may have a non-null value.
+ OutputSection *RelocationSection = nullptr;
+
+ // Initially this field is the number of InputSections that have been added to
+ // the OutputSection so far. Later on, after a call to assignAddresses, it
+ // corresponds to the Elf_Shdr member.
+ uint64_t Size = 0;
+
+ // The following fields correspond to Elf_Shdr members.
+ uint64_t Offset = 0;
+ uint64_t Addr = 0;
+ uint32_t ShName = 0;
+
+ void addSection(InputSection *IS);
+
+ // Location in the output buffer.
+ uint8_t *Loc = nullptr;
+
+ // The following members are normally only used in linker scripts.
+ MemoryRegion *MemRegion = nullptr;
+ MemoryRegion *LMARegion = nullptr;
+ Expr AddrExpr;
+ Expr AlignExpr;
+ Expr LMAExpr;
+ Expr SubalignExpr;
+ std::vector<BaseCommand *> SectionCommands;
+ std::vector<StringRef> Phdrs;
+ llvm::Optional<std::array<uint8_t, 4>> Filler;
+ ConstraintKind Constraint = ConstraintKind::NoConstraint;
+ std::string Location;
+ std::string MemoryRegionName;
+ std::string LMARegionName;
+ bool NonAlloc = false;
+ bool Noload = false;
+ bool ExpressionsUseSymbols = false;
+ bool InOverlay = false;
+
+ template <class ELFT> void finalize();
+ template <class ELFT> void writeTo(uint8_t *Buf);
+ template <class ELFT> void maybeCompress();
+
+ void sort(llvm::function_ref<int(InputSectionBase *S)> Order);
+ void sortInitFini();
+ void sortCtorsDtors();
+
+private:
+ // Used for implementation of --compress-debug-sections option.
+ std::vector<uint8_t> ZDebugHeader;
+ llvm::SmallVector<char, 1> CompressedData;
+
+ std::array<uint8_t, 4> getFiller();
+};
+
+int getPriority(StringRef S);
+
+std::vector<InputSection *> getInputSections(OutputSection* OS);
+
+// All output sections that are handled by the linker specially are
+// globally accessible. Writer initializes them, so don't use them
+// until Writer is initialized.
+struct Out {
+ static uint8_t First;
+ static PhdrEntry *TlsPhdr;
+ static OutputSection *ElfHeader;
+ static OutputSection *ProgramHeaders;
+ static OutputSection *PreinitArray;
+ static OutputSection *InitArray;
+ static OutputSection *FiniArray;
+};
+
+} // namespace elf
+} // namespace lld
+
+namespace lld {
+namespace elf {
+
+uint64_t getHeaderSize();
+
+extern std::vector<OutputSection *> OutputSections;
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/ELF/README.md b/contrib/llvm/tools/lld/ELF/README.md
new file mode 100644
index 000000000000..f1bfc9c15263
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/README.md
@@ -0,0 +1 @@
+See docs/NewLLD.rst
diff --git a/contrib/llvm/tools/lld/ELF/Relocations.cpp b/contrib/llvm/tools/lld/ELF/Relocations.cpp
new file mode 100644
index 000000000000..1aa58d4356bf
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Relocations.cpp
@@ -0,0 +1,1520 @@
+//===- Relocations.cpp ----------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains platform-independent functions to process relocations.
+// I'll describe the overview of this file here.
+//
+// Simple relocations are easy to handle for the linker. For example,
+// for R_X86_64_PC64 relocs, the linker just has to fix up locations
+// with the relative offsets to the target symbols. It would just be
+// reading records from relocation sections and applying them to output.
+//
+// But not all relocations are that easy to handle. For example, for
+// R_386_GOTOFF relocs, the linker has to create new GOT entries for
+// symbols if they don't exist, and fix up locations with GOT entry
+// offsets from the beginning of GOT section. So there is more than
+// fixing addresses in relocation processing.
+//
+// ELF defines a large number of complex relocations.
+//
+// The functions in this file analyze relocations and do whatever needs
+// to be done. It includes, but not limited to, the following.
+//
+// - create GOT/PLT entries
+// - create new relocations in .dynsym to let the dynamic linker resolve
+// them at runtime (since ELF supports dynamic linking, not all
+// relocations can be resolved at link-time)
+// - create COPY relocs and reserve space in .bss
+// - replace expensive relocs (in terms of runtime cost) with cheap ones
+// - error out infeasible combinations such as PIC and non-relative relocs
+//
+// Note that the functions in this file don't actually apply relocations
+// because it doesn't know about the output file nor the output file buffer.
+// It instead stores Relocation objects to InputSection's Relocations
+// vector to let it apply later in InputSection::writeTo.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Relocations.h"
+#include "Config.h"
+#include "LinkerScript.h"
+#include "OutputSections.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "Thunks.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Memory.h"
+#include "lld/Common/Strings.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+
+using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+
+using namespace lld;
+using namespace lld::elf;
+
+static Optional<std::string> getLinkerScriptLocation(const Symbol &Sym) {
+ for (BaseCommand *Base : Script->SectionCommands)
+ if (auto *Cmd = dyn_cast<SymbolAssignment>(Base))
+ if (Cmd->Sym == &Sym)
+ return Cmd->Location;
+ return None;
+}
+
+// Construct a message in the following format.
+//
+// >>> defined in /home/alice/src/foo.o
+// >>> referenced by bar.c:12 (/home/alice/src/bar.c:12)
+// >>> /home/alice/src/bar.o:(.text+0x1)
+static std::string getLocation(InputSectionBase &S, const Symbol &Sym,
+ uint64_t Off) {
+ std::string Msg = "\n>>> defined in ";
+ if (Sym.File)
+ Msg += toString(Sym.File);
+ else if (Optional<std::string> Loc = getLinkerScriptLocation(Sym))
+ Msg += *Loc;
+
+ Msg += "\n>>> referenced by ";
+ std::string Src = S.getSrcMsg(Sym, Off);
+ if (!Src.empty())
+ Msg += Src + "\n>>> ";
+ return Msg + S.getObjMsg(Off);
+}
+
+// This function is similar to the `handleTlsRelocation`. MIPS does not
+// support any relaxations for TLS relocations so by factoring out MIPS
+// handling in to the separate function we can simplify the code and do not
+// pollute other `handleTlsRelocation` by MIPS `ifs` statements.
+// Mips has a custom MipsGotSection that handles the writing of GOT entries
+// without dynamic relocations.
+static unsigned handleMipsTlsRelocation(RelType Type, Symbol &Sym,
+ InputSectionBase &C, uint64_t Offset,
+ int64_t Addend, RelExpr Expr) {
+ if (Expr == R_MIPS_TLSLD) {
+ In.MipsGot->addTlsIndex(*C.File);
+ C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
+ return 1;
+ }
+ if (Expr == R_MIPS_TLSGD) {
+ In.MipsGot->addDynTlsEntry(*C.File, Sym);
+ C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
+ return 1;
+ }
+ return 0;
+}
+
+// This function is similar to the `handleMipsTlsRelocation`. ARM also does not
+// support any relaxations for TLS relocations. ARM is logically similar to Mips
+// in how it handles TLS, but Mips uses its own custom GOT which handles some
+// of the cases that ARM uses GOT relocations for.
+//
+// We look for TLS global dynamic and local dynamic relocations, these may
+// require the generation of a pair of GOT entries that have associated
+// dynamic relocations. When the results of the dynamic relocations can be
+// resolved at static link time we do so. This is necessary for static linking
+// as there will be no dynamic loader to resolve them at load-time.
+//
+// The pair of GOT entries created are of the form
+// GOT[e0] Module Index (Used to find pointer to TLS block at run-time)
+// GOT[e1] Offset of symbol in TLS block
+template <class ELFT>
+static unsigned handleARMTlsRelocation(RelType Type, Symbol &Sym,
+ InputSectionBase &C, uint64_t Offset,
+ int64_t Addend, RelExpr Expr) {
+ // The Dynamic TLS Module Index Relocation for a symbol defined in an
+ // executable is always 1. If the target Symbol is not preemptible then
+ // we know the offset into the TLS block at static link time.
+ bool NeedDynId = Sym.IsPreemptible || Config->Shared;
+ bool NeedDynOff = Sym.IsPreemptible;
+
+ auto AddTlsReloc = [&](uint64_t Off, RelType Type, Symbol *Dest, bool Dyn) {
+ if (Dyn)
+ In.RelaDyn->addReloc(Type, In.Got, Off, Dest);
+ else
+ In.Got->Relocations.push_back({R_ABS, Type, Off, 0, Dest});
+ };
+
+ // Local Dynamic is for access to module local TLS variables, while still
+ // being suitable for being dynamically loaded via dlopen.
+ // GOT[e0] is the module index, with a special value of 0 for the current
+ // module. GOT[e1] is unused. There only needs to be one module index entry.
+ if (Expr == R_TLSLD_PC && In.Got->addTlsIndex()) {
+ AddTlsReloc(In.Got->getTlsIndexOff(), Target->TlsModuleIndexRel,
+ NeedDynId ? nullptr : &Sym, NeedDynId);
+ C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
+ return 1;
+ }
+
+ // Global Dynamic is the most general purpose access model. When we know
+ // the module index and offset of symbol in TLS block we can fill these in
+ // using static GOT relocations.
+ if (Expr == R_TLSGD_PC) {
+ if (In.Got->addDynTlsEntry(Sym)) {
+ uint64_t Off = In.Got->getGlobalDynOffset(Sym);
+ AddTlsReloc(Off, Target->TlsModuleIndexRel, &Sym, NeedDynId);
+ AddTlsReloc(Off + Config->Wordsize, Target->TlsOffsetRel, &Sym,
+ NeedDynOff);
+ }
+ C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
+ return 1;
+ }
+ return 0;
+}
+
+// Returns the number of relocations processed.
+template <class ELFT>
+static unsigned
+handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C,
+ typename ELFT::uint Offset, int64_t Addend, RelExpr Expr) {
+ if (!Sym.isTls())
+ return 0;
+
+ if (Config->EMachine == EM_ARM)
+ return handleARMTlsRelocation<ELFT>(Type, Sym, C, Offset, Addend, Expr);
+ if (Config->EMachine == EM_MIPS)
+ return handleMipsTlsRelocation(Type, Sym, C, Offset, Addend, Expr);
+
+ if (isRelExprOneOf<R_TLSDESC, R_AARCH64_TLSDESC_PAGE, R_TLSDESC_CALL>(Expr) &&
+ Config->Shared) {
+ if (In.Got->addDynTlsEntry(Sym)) {
+ uint64_t Off = In.Got->getGlobalDynOffset(Sym);
+ In.RelaDyn->addReloc(
+ {Target->TlsDescRel, In.Got, Off, !Sym.IsPreemptible, &Sym, 0});
+ }
+ if (Expr != R_TLSDESC_CALL)
+ C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
+ return 1;
+ }
+
+ if (isRelExprOneOf<R_TLSLD_GOT, R_TLSLD_GOT_FROM_END, R_TLSLD_PC,
+ R_TLSLD_HINT>(Expr)) {
+ // Local-Dynamic relocs can be relaxed to Local-Exec.
+ if (!Config->Shared) {
+ C.Relocations.push_back(
+ {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_LD_TO_LE), Type,
+ Offset, Addend, &Sym});
+ return Target->TlsGdRelaxSkip;
+ }
+ if (Expr == R_TLSLD_HINT)
+ return 1;
+ if (In.Got->addTlsIndex())
+ In.RelaDyn->addReloc(Target->TlsModuleIndexRel, In.Got,
+ In.Got->getTlsIndexOff(), nullptr);
+ C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
+ return 1;
+ }
+
+ // Local-Dynamic relocs can be relaxed to Local-Exec.
+ if (Expr == R_ABS && !Config->Shared) {
+ C.Relocations.push_back(
+ {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_LD_TO_LE), Type,
+ Offset, Addend, &Sym});
+ return 1;
+ }
+
+ // Local-Dynamic sequence where offset of tls variable relative to dynamic
+ // thread pointer is stored in the got.
+ if (Expr == R_TLSLD_GOT_OFF) {
+ // Local-Dynamic relocs can be relaxed to local-exec
+ if (!Config->Shared) {
+ C.Relocations.push_back({R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Sym});
+ return 1;
+ }
+ if (!Sym.isInGot()) {
+ In.Got->addEntry(Sym);
+ uint64_t Off = Sym.getGotOffset();
+ In.Got->Relocations.push_back(
+ {R_ABS, Target->TlsOffsetRel, Off, 0, &Sym});
+ }
+ C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
+ return 1;
+ }
+
+ if (isRelExprOneOf<R_TLSDESC, R_AARCH64_TLSDESC_PAGE, R_TLSDESC_CALL,
+ R_TLSGD_GOT, R_TLSGD_GOT_FROM_END, R_TLSGD_PC>(Expr)) {
+ if (Config->Shared) {
+ if (In.Got->addDynTlsEntry(Sym)) {
+ uint64_t Off = In.Got->getGlobalDynOffset(Sym);
+ In.RelaDyn->addReloc(Target->TlsModuleIndexRel, In.Got, Off, &Sym);
+
+ // If the symbol is preemptible we need the dynamic linker to write
+ // the offset too.
+ uint64_t OffsetOff = Off + Config->Wordsize;
+ if (Sym.IsPreemptible)
+ In.RelaDyn->addReloc(Target->TlsOffsetRel, In.Got, OffsetOff, &Sym);
+ else
+ In.Got->Relocations.push_back(
+ {R_ABS, Target->TlsOffsetRel, OffsetOff, 0, &Sym});
+ }
+ C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
+ return 1;
+ }
+
+ // Global-Dynamic relocs can be relaxed to Initial-Exec or Local-Exec
+ // depending on the symbol being locally defined or not.
+ if (Sym.IsPreemptible) {
+ C.Relocations.push_back(
+ {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_IE), Type,
+ Offset, Addend, &Sym});
+ if (!Sym.isInGot()) {
+ In.Got->addEntry(Sym);
+ In.RelaDyn->addReloc(Target->TlsGotRel, In.Got, Sym.getGotOffset(),
+ &Sym);
+ }
+ } else {
+ C.Relocations.push_back(
+ {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_LE), Type,
+ Offset, Addend, &Sym});
+ }
+ return Target->TlsGdRelaxSkip;
+ }
+
+ // Initial-Exec relocs can be relaxed to Local-Exec if the symbol is locally
+ // defined.
+ if (isRelExprOneOf<R_GOT, R_GOT_FROM_END, R_GOT_PC, R_AARCH64_GOT_PAGE_PC,
+ R_GOT_OFF, R_TLSIE_HINT>(Expr) &&
+ !Config->Shared && !Sym.IsPreemptible) {
+ C.Relocations.push_back({R_RELAX_TLS_IE_TO_LE, Type, Offset, Addend, &Sym});
+ return 1;
+ }
+
+ if (Expr == R_TLSIE_HINT)
+ return 1;
+ return 0;
+}
+
+static RelType getMipsPairType(RelType Type, bool IsLocal) {
+ switch (Type) {
+ case R_MIPS_HI16:
+ return R_MIPS_LO16;
+ case R_MIPS_GOT16:
+ // In case of global symbol, the R_MIPS_GOT16 relocation does not
+ // have a pair. Each global symbol has a unique entry in the GOT
+ // and a corresponding instruction with help of the R_MIPS_GOT16
+ // relocation loads an address of the symbol. In case of local
+ // symbol, the R_MIPS_GOT16 relocation creates a GOT entry to hold
+ // the high 16 bits of the symbol's value. A paired R_MIPS_LO16
+ // relocations handle low 16 bits of the address. That allows
+ // to allocate only one GOT entry for every 64 KBytes of local data.
+ return IsLocal ? R_MIPS_LO16 : R_MIPS_NONE;
+ case R_MICROMIPS_GOT16:
+ return IsLocal ? R_MICROMIPS_LO16 : R_MIPS_NONE;
+ case R_MIPS_PCHI16:
+ return R_MIPS_PCLO16;
+ case R_MICROMIPS_HI16:
+ return R_MICROMIPS_LO16;
+ default:
+ return R_MIPS_NONE;
+ }
+}
+
+// True if non-preemptable symbol always has the same value regardless of where
+// the DSO is loaded.
+static bool isAbsolute(const Symbol &Sym) {
+ if (Sym.isUndefWeak())
+ return true;
+ if (const auto *DR = dyn_cast<Defined>(&Sym))
+ return DR->Section == nullptr; // Absolute symbol.
+ return false;
+}
+
+static bool isAbsoluteValue(const Symbol &Sym) {
+ return isAbsolute(Sym) || Sym.isTls();
+}
+
+// Returns true if Expr refers a PLT entry.
+static bool needsPlt(RelExpr Expr) {
+ return isRelExprOneOf<R_PLT_PC, R_PPC_CALL_PLT, R_PLT, R_AARCH64_PLT_PAGE_PC,
+ R_GOT_PLT, R_AARCH64_GOT_PAGE_PC_PLT>(Expr);
+}
+
+// Returns true if Expr refers a GOT entry. Note that this function
+// returns false for TLS variables even though they need GOT, because
+// TLS variables uses GOT differently than the regular variables.
+static bool needsGot(RelExpr Expr) {
+ return isRelExprOneOf<R_GOT, R_GOT_OFF, R_HEXAGON_GOT, R_MIPS_GOT_LOCAL_PAGE,
+ R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_AARCH64_GOT_PAGE_PC,
+ R_AARCH64_GOT_PAGE_PC_PLT, R_GOT_PC, R_GOT_FROM_END,
+ R_GOT_PLT>(Expr);
+}
+
+// True if this expression is of the form Sym - X, where X is a position in the
+// file (PC, or GOT for example).
+static bool isRelExpr(RelExpr Expr) {
+ return isRelExprOneOf<R_PC, R_GOTREL, R_GOTREL_FROM_END, R_MIPS_GOTREL,
+ R_PPC_CALL, R_PPC_CALL_PLT, R_AARCH64_PAGE_PC,
+ R_AARCH64_PLT_PAGE_PC, R_RELAX_GOT_PC>(Expr);
+}
+
+// Returns true if a given relocation can be computed at link-time.
+//
+// For instance, we know the offset from a relocation to its target at
+// link-time if the relocation is PC-relative and refers a
+// non-interposable function in the same executable. This function
+// will return true for such relocation.
+//
+// If this function returns false, that means we need to emit a
+// dynamic relocation so that the relocation will be fixed at load-time.
+static bool isStaticLinkTimeConstant(RelExpr E, RelType Type, const Symbol &Sym,
+ InputSectionBase &S, uint64_t RelOff) {
+ // These expressions always compute a constant
+ if (isRelExprOneOf<R_GOT_FROM_END, R_GOT_OFF, R_HEXAGON_GOT, R_TLSLD_GOT_OFF,
+ R_MIPS_GOT_LOCAL_PAGE, R_MIPS_GOTREL, R_MIPS_GOT_OFF,
+ R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC, R_MIPS_TLSGD,
+ R_AARCH64_GOT_PAGE_PC, R_AARCH64_GOT_PAGE_PC_PLT, R_GOT_PC,
+ R_GOTONLY_PC, R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_GOT,
+ R_TLSGD_GOT_FROM_END, R_TLSGD_PC, R_PPC_CALL_PLT,
+ R_TLSDESC_CALL, R_AARCH64_TLSDESC_PAGE, R_HINT,
+ R_TLSLD_HINT, R_TLSIE_HINT>(E))
+ return true;
+
+ // The computation involves output from the ifunc resolver.
+ if (Sym.isGnuIFunc() && Config->ZIfuncnoplt)
+ return false;
+
+ // These never do, except if the entire file is position dependent or if
+ // only the low bits are used.
+ if (E == R_GOT || E == R_GOT_PLT || E == R_PLT || E == R_TLSDESC)
+ return Target->usesOnlyLowPageBits(Type) || !Config->Pic;
+
+ if (Sym.IsPreemptible)
+ return false;
+ if (!Config->Pic)
+ return true;
+
+ // The size of a non preemptible symbol is a constant.
+ if (E == R_SIZE)
+ return true;
+
+ // For the target and the relocation, we want to know if they are
+ // absolute or relative.
+ bool AbsVal = isAbsoluteValue(Sym);
+ bool RelE = isRelExpr(E);
+ if (AbsVal && !RelE)
+ return true;
+ if (!AbsVal && RelE)
+ return true;
+ if (!AbsVal && !RelE)
+ return Target->usesOnlyLowPageBits(Type);
+
+ // Relative relocation to an absolute value. This is normally unrepresentable,
+ // but if the relocation refers to a weak undefined symbol, we allow it to
+ // resolve to the image base. This is a little strange, but it allows us to
+ // link function calls to such symbols. Normally such a call will be guarded
+ // with a comparison, which will load a zero from the GOT.
+ // Another special case is MIPS _gp_disp symbol which represents offset
+ // between start of a function and '_gp' value and defined as absolute just
+ // to simplify the code.
+ assert(AbsVal && RelE);
+ if (Sym.isUndefWeak())
+ return true;
+
+ error("relocation " + toString(Type) + " cannot refer to absolute symbol: " +
+ toString(Sym) + getLocation(S, Sym, RelOff));
+ return true;
+}
+
+static RelExpr toPlt(RelExpr Expr) {
+ switch (Expr) {
+ case R_PPC_CALL:
+ return R_PPC_CALL_PLT;
+ case R_PC:
+ return R_PLT_PC;
+ case R_AARCH64_PAGE_PC:
+ return R_AARCH64_PLT_PAGE_PC;
+ case R_AARCH64_GOT_PAGE_PC:
+ return R_AARCH64_GOT_PAGE_PC_PLT;
+ case R_ABS:
+ return R_PLT;
+ case R_GOT:
+ return R_GOT_PLT;
+ default:
+ return Expr;
+ }
+}
+
+static RelExpr fromPlt(RelExpr Expr) {
+ // We decided not to use a plt. Optimize a reference to the plt to a
+ // reference to the symbol itself.
+ switch (Expr) {
+ case R_PLT_PC:
+ return R_PC;
+ case R_PPC_CALL_PLT:
+ return R_PPC_CALL;
+ case R_PLT:
+ return R_ABS;
+ default:
+ return Expr;
+ }
+}
+
+// Returns true if a given shared symbol is in a read-only segment in a DSO.
+template <class ELFT> static bool isReadOnly(SharedSymbol &SS) {
+ typedef typename ELFT::Phdr Elf_Phdr;
+
+ // Determine if the symbol is read-only by scanning the DSO's program headers.
+ const SharedFile<ELFT> &File = SS.getFile<ELFT>();
+ for (const Elf_Phdr &Phdr : check(File.getObj().program_headers()))
+ if ((Phdr.p_type == ELF::PT_LOAD || Phdr.p_type == ELF::PT_GNU_RELRO) &&
+ !(Phdr.p_flags & ELF::PF_W) && SS.Value >= Phdr.p_vaddr &&
+ SS.Value < Phdr.p_vaddr + Phdr.p_memsz)
+ return true;
+ return false;
+}
+
+// Returns symbols at the same offset as a given symbol, including SS itself.
+//
+// If two or more symbols are at the same offset, and at least one of
+// them are copied by a copy relocation, all of them need to be copied.
+// Otherwise, they would refer to different places at runtime.
+template <class ELFT>
+static SmallSet<SharedSymbol *, 4> getSymbolsAt(SharedSymbol &SS) {
+ typedef typename ELFT::Sym Elf_Sym;
+
+ SharedFile<ELFT> &File = SS.getFile<ELFT>();
+
+ SmallSet<SharedSymbol *, 4> Ret;
+ for (const Elf_Sym &S : File.getGlobalELFSyms()) {
+ if (S.st_shndx == SHN_UNDEF || S.st_shndx == SHN_ABS ||
+ S.getType() == STT_TLS || S.st_value != SS.Value)
+ continue;
+ StringRef Name = check(S.getName(File.getStringTable()));
+ Symbol *Sym = Symtab->find(Name);
+ if (auto *Alias = dyn_cast_or_null<SharedSymbol>(Sym))
+ Ret.insert(Alias);
+ }
+ return Ret;
+}
+
+// When a symbol is copy relocated or we create a canonical plt entry, it is
+// effectively a defined symbol. In the case of copy relocation the symbol is
+// in .bss and in the case of a canonical plt entry it is in .plt. This function
+// replaces the existing symbol with a Defined pointing to the appropriate
+// location.
+static void replaceWithDefined(Symbol &Sym, SectionBase *Sec, uint64_t Value,
+ uint64_t Size) {
+ Symbol Old = Sym;
+ replaceSymbol<Defined>(&Sym, Sym.File, Sym.getName(), Sym.Binding,
+ Sym.StOther, Sym.Type, Value, Size, Sec);
+ Sym.PltIndex = Old.PltIndex;
+ Sym.GotIndex = Old.GotIndex;
+ Sym.VerdefIndex = Old.VerdefIndex;
+ Sym.PPC64BranchltIndex = Old.PPC64BranchltIndex;
+ Sym.IsPreemptible = true;
+ Sym.ExportDynamic = true;
+ Sym.IsUsedInRegularObj = true;
+ Sym.Used = true;
+}
+
+// Reserve space in .bss or .bss.rel.ro for copy relocation.
+//
+// The copy relocation is pretty much a hack. If you use a copy relocation
+// in your program, not only the symbol name but the symbol's size, RW/RO
+// bit and alignment become part of the ABI. In addition to that, if the
+// symbol has aliases, the aliases become part of the ABI. That's subtle,
+// but if you violate that implicit ABI, that can cause very counter-
+// intuitive consequences.
+//
+// So, what is the copy relocation? It's for linking non-position
+// independent code to DSOs. In an ideal world, all references to data
+// exported by DSOs should go indirectly through GOT. But if object files
+// are compiled as non-PIC, all data references are direct. There is no
+// way for the linker to transform the code to use GOT, as machine
+// instructions are already set in stone in object files. This is where
+// the copy relocation takes a role.
+//
+// A copy relocation instructs the dynamic linker to copy data from a DSO
+// to a specified address (which is usually in .bss) at load-time. If the
+// static linker (that's us) finds a direct data reference to a DSO
+// symbol, it creates a copy relocation, so that the symbol can be
+// resolved as if it were in .bss rather than in a DSO.
+//
+// As you can see in this function, we create a copy relocation for the
+// dynamic linker, and the relocation contains not only symbol name but
+// various other informtion about the symbol. So, such attributes become a
+// part of the ABI.
+//
+// Note for application developers: I can give you a piece of advice if
+// you are writing a shared library. You probably should export only
+// functions from your library. You shouldn't export variables.
+//
+// As an example what can happen when you export variables without knowing
+// the semantics of copy relocations, assume that you have an exported
+// variable of type T. It is an ABI-breaking change to add new members at
+// end of T even though doing that doesn't change the layout of the
+// existing members. That's because the space for the new members are not
+// reserved in .bss unless you recompile the main program. That means they
+// are likely to overlap with other data that happens to be laid out next
+// to the variable in .bss. This kind of issue is sometimes very hard to
+// debug. What's a solution? Instead of exporting a varaible V from a DSO,
+// define an accessor getV().
+template <class ELFT> static void addCopyRelSymbol(SharedSymbol &SS) {
+ // Copy relocation against zero-sized symbol doesn't make sense.
+ uint64_t SymSize = SS.getSize();
+ if (SymSize == 0 || SS.Alignment == 0)
+ fatal("cannot create a copy relocation for symbol " + toString(SS));
+
+ // See if this symbol is in a read-only segment. If so, preserve the symbol's
+ // memory protection by reserving space in the .bss.rel.ro section.
+ bool IsReadOnly = isReadOnly<ELFT>(SS);
+ BssSection *Sec = make<BssSection>(IsReadOnly ? ".bss.rel.ro" : ".bss",
+ SymSize, SS.Alignment);
+ if (IsReadOnly)
+ In.BssRelRo->getParent()->addSection(Sec);
+ else
+ In.Bss->getParent()->addSection(Sec);
+
+ // Look through the DSO's dynamic symbol table for aliases and create a
+ // dynamic symbol for each one. This causes the copy relocation to correctly
+ // interpose any aliases.
+ for (SharedSymbol *Sym : getSymbolsAt<ELFT>(SS))
+ replaceWithDefined(*Sym, Sec, 0, Sym->Size);
+
+ In.RelaDyn->addReloc(Target->CopyRel, Sec, 0, &SS);
+}
+
+// MIPS has an odd notion of "paired" relocations to calculate addends.
+// For example, if a relocation is of R_MIPS_HI16, there must be a
+// R_MIPS_LO16 relocation after that, and an addend is calculated using
+// the two relocations.
+template <class ELFT, class RelTy>
+static int64_t computeMipsAddend(const RelTy &Rel, const RelTy *End,
+ InputSectionBase &Sec, RelExpr Expr,
+ bool IsLocal) {
+ if (Expr == R_MIPS_GOTREL && IsLocal)
+ return Sec.getFile<ELFT>()->MipsGp0;
+
+ // The ABI says that the paired relocation is used only for REL.
+ // See p. 4-17 at ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+ if (RelTy::IsRela)
+ return 0;
+
+ RelType Type = Rel.getType(Config->IsMips64EL);
+ uint32_t PairTy = getMipsPairType(Type, IsLocal);
+ if (PairTy == R_MIPS_NONE)
+ return 0;
+
+ const uint8_t *Buf = Sec.data().data();
+ uint32_t SymIndex = Rel.getSymbol(Config->IsMips64EL);
+
+ // To make things worse, paired relocations might not be contiguous in
+ // the relocation table, so we need to do linear search. *sigh*
+ for (const RelTy *RI = &Rel; RI != End; ++RI)
+ if (RI->getType(Config->IsMips64EL) == PairTy &&
+ RI->getSymbol(Config->IsMips64EL) == SymIndex)
+ return Target->getImplicitAddend(Buf + RI->r_offset, PairTy);
+
+ warn("can't find matching " + toString(PairTy) + " relocation for " +
+ toString(Type));
+ return 0;
+}
+
+// Returns an addend of a given relocation. If it is RELA, an addend
+// is in a relocation itself. If it is REL, we need to read it from an
+// input section.
+template <class ELFT, class RelTy>
+static int64_t computeAddend(const RelTy &Rel, const RelTy *End,
+ InputSectionBase &Sec, RelExpr Expr,
+ bool IsLocal) {
+ int64_t Addend;
+ RelType Type = Rel.getType(Config->IsMips64EL);
+
+ if (RelTy::IsRela) {
+ Addend = getAddend<ELFT>(Rel);
+ } else {
+ const uint8_t *Buf = Sec.data().data();
+ Addend = Target->getImplicitAddend(Buf + Rel.r_offset, Type);
+ }
+
+ if (Config->EMachine == EM_PPC64 && Config->Pic && Type == R_PPC64_TOC)
+ Addend += getPPC64TocBase();
+ if (Config->EMachine == EM_MIPS)
+ Addend += computeMipsAddend<ELFT>(Rel, End, Sec, Expr, IsLocal);
+
+ return Addend;
+}
+
+// Report an undefined symbol if necessary.
+// Returns true if this function printed out an error message.
+static bool maybeReportUndefined(Symbol &Sym, InputSectionBase &Sec,
+ uint64_t Offset) {
+ if (Sym.isLocal() || !Sym.isUndefined() || Sym.isWeak())
+ return false;
+
+ bool CanBeExternal =
+ Sym.computeBinding() != STB_LOCAL && Sym.Visibility == STV_DEFAULT;
+ if (Config->UnresolvedSymbols == UnresolvedPolicy::Ignore && CanBeExternal)
+ return false;
+
+ std::string Msg =
+ "undefined symbol: " + toString(Sym) + "\n>>> referenced by ";
+
+ std::string Src = Sec.getSrcMsg(Sym, Offset);
+ if (!Src.empty())
+ Msg += Src + "\n>>> ";
+ Msg += Sec.getObjMsg(Offset);
+
+ if (Sym.getName().startswith("_ZTV"))
+ Msg += "\nthe vtable symbol may be undefined because the class is missing "
+ "its key function (see https://lld.llvm.org/missingkeyfunction)";
+
+ if ((Config->UnresolvedSymbols == UnresolvedPolicy::Warn && CanBeExternal) ||
+ Config->NoinhibitExec) {
+ warn(Msg);
+ return false;
+ }
+
+ error(Msg);
+ return true;
+}
+
+// MIPS N32 ABI treats series of successive relocations with the same offset
+// as a single relocation. The similar approach used by N64 ABI, but this ABI
+// packs all relocations into the single relocation record. Here we emulate
+// this for the N32 ABI. Iterate over relocation with the same offset and put
+// theirs types into the single bit-set.
+template <class RelTy> static RelType getMipsN32RelType(RelTy *&Rel, RelTy *End) {
+ RelType Type = 0;
+ uint64_t Offset = Rel->r_offset;
+
+ int N = 0;
+ while (Rel != End && Rel->r_offset == Offset)
+ Type |= (Rel++)->getType(Config->IsMips64EL) << (8 * N++);
+ return Type;
+}
+
+// .eh_frame sections are mergeable input sections, so their input
+// offsets are not linearly mapped to output section. For each input
+// offset, we need to find a section piece containing the offset and
+// add the piece's base address to the input offset to compute the
+// output offset. That isn't cheap.
+//
+// This class is to speed up the offset computation. When we process
+// relocations, we access offsets in the monotonically increasing
+// order. So we can optimize for that access pattern.
+//
+// For sections other than .eh_frame, this class doesn't do anything.
+namespace {
+class OffsetGetter {
+public:
+ explicit OffsetGetter(InputSectionBase &Sec) {
+ if (auto *Eh = dyn_cast<EhInputSection>(&Sec))
+ Pieces = Eh->Pieces;
+ }
+
+ // Translates offsets in input sections to offsets in output sections.
+ // Given offset must increase monotonically. We assume that Piece is
+ // sorted by InputOff.
+ uint64_t get(uint64_t Off) {
+ if (Pieces.empty())
+ return Off;
+
+ while (I != Pieces.size() && Pieces[I].InputOff + Pieces[I].Size <= Off)
+ ++I;
+ if (I == Pieces.size())
+ fatal(".eh_frame: relocation is not in any piece");
+
+ // Pieces must be contiguous, so there must be no holes in between.
+ assert(Pieces[I].InputOff <= Off && "Relocation not in any piece");
+
+ // Offset -1 means that the piece is dead (i.e. garbage collected).
+ if (Pieces[I].OutputOff == -1)
+ return -1;
+ return Pieces[I].OutputOff + Off - Pieces[I].InputOff;
+ }
+
+private:
+ ArrayRef<EhSectionPiece> Pieces;
+ size_t I = 0;
+};
+} // namespace
+
+static void addRelativeReloc(InputSectionBase *IS, uint64_t OffsetInSec,
+ Symbol *Sym, int64_t Addend, RelExpr Expr,
+ RelType Type) {
+ // Add a relative relocation. If RelrDyn section is enabled, and the
+ // relocation offset is guaranteed to be even, add the relocation to
+ // the RelrDyn section, otherwise add it to the RelaDyn section.
+ // RelrDyn sections don't support odd offsets. Also, RelrDyn sections
+ // don't store the addend values, so we must write it to the relocated
+ // address.
+ if (In.RelrDyn && IS->Alignment >= 2 && OffsetInSec % 2 == 0) {
+ IS->Relocations.push_back({Expr, Type, OffsetInSec, Addend, Sym});
+ In.RelrDyn->Relocs.push_back({IS, OffsetInSec});
+ return;
+ }
+ In.RelaDyn->addReloc(Target->RelativeRel, IS, OffsetInSec, Sym, Addend, Expr,
+ Type);
+}
+
+template <class ELFT, class GotPltSection>
+static void addPltEntry(PltSection *Plt, GotPltSection *GotPlt,
+ RelocationBaseSection *Rel, RelType Type, Symbol &Sym) {
+ Plt->addEntry<ELFT>(Sym);
+ GotPlt->addEntry(Sym);
+ Rel->addReloc(
+ {Type, GotPlt, Sym.getGotPltOffset(), !Sym.IsPreemptible, &Sym, 0});
+}
+
+template <class ELFT> static void addGotEntry(Symbol &Sym) {
+ In.Got->addEntry(Sym);
+
+ RelExpr Expr;
+ if (Sym.isTls())
+ Expr = R_TLS;
+ else if (Sym.isGnuIFunc())
+ Expr = R_PLT;
+ else
+ Expr = R_ABS;
+
+ uint64_t Off = Sym.getGotOffset();
+
+ // If a GOT slot value can be calculated at link-time, which is now,
+ // we can just fill that out.
+ //
+ // (We don't actually write a value to a GOT slot right now, but we
+ // add a static relocation to a Relocations vector so that
+ // InputSection::relocate will do the work for us. We may be able
+ // to just write a value now, but it is a TODO.)
+ bool IsLinkTimeConstant =
+ !Sym.IsPreemptible && (!Config->Pic || isAbsolute(Sym));
+ if (IsLinkTimeConstant) {
+ In.Got->Relocations.push_back({Expr, Target->GotRel, Off, 0, &Sym});
+ return;
+ }
+
+ // Otherwise, we emit a dynamic relocation to .rel[a].dyn so that
+ // the GOT slot will be fixed at load-time.
+ if (!Sym.isTls() && !Sym.IsPreemptible && Config->Pic && !isAbsolute(Sym)) {
+ addRelativeReloc(In.Got, Off, &Sym, 0, R_ABS, Target->GotRel);
+ return;
+ }
+ In.RelaDyn->addReloc(Sym.isTls() ? Target->TlsGotRel : Target->GotRel, In.Got,
+ Off, &Sym, 0, Sym.IsPreemptible ? R_ADDEND : R_ABS,
+ Target->GotRel);
+}
+
+// Return true if we can define a symbol in the executable that
+// contains the value/function of a symbol defined in a shared
+// library.
+static bool canDefineSymbolInExecutable(Symbol &Sym) {
+ // If the symbol has default visibility the symbol defined in the
+ // executable will preempt it.
+ // Note that we want the visibility of the shared symbol itself, not
+ // the visibility of the symbol in the output file we are producing. That is
+ // why we use Sym.StOther.
+ if ((Sym.StOther & 0x3) == STV_DEFAULT)
+ return true;
+
+ // If we are allowed to break address equality of functions, defining
+ // a plt entry will allow the program to call the function in the
+ // .so, but the .so and the executable will no agree on the address
+ // of the function. Similar logic for objects.
+ return ((Sym.isFunc() && Config->IgnoreFunctionAddressEquality) ||
+ (Sym.isObject() && Config->IgnoreDataAddressEquality));
+}
+
+// The reason we have to do this early scan is as follows
+// * To mmap the output file, we need to know the size
+// * For that, we need to know how many dynamic relocs we will have.
+// It might be possible to avoid this by outputting the file with write:
+// * Write the allocated output sections, computing addresses.
+// * Apply relocations, recording which ones require a dynamic reloc.
+// * Write the dynamic relocations.
+// * Write the rest of the file.
+// This would have some drawbacks. For example, we would only know if .rela.dyn
+// is needed after applying relocations. If it is, it will go after rw and rx
+// sections. Given that it is ro, we will need an extra PT_LOAD. This
+// complicates things for the dynamic linker and means we would have to reserve
+// space for the extra PT_LOAD even if we end up not using it.
+template <class ELFT, class RelTy>
+static void processRelocAux(InputSectionBase &Sec, RelExpr Expr, RelType Type,
+ uint64_t Offset, Symbol &Sym, const RelTy &Rel,
+ int64_t Addend) {
+ if (isStaticLinkTimeConstant(Expr, Type, Sym, Sec, Offset)) {
+ Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
+ return;
+ }
+ if (Sym.isGnuIFunc() && Config->ZIfuncnoplt) {
+ In.RelaDyn->addReloc(Type, &Sec, Offset, &Sym, Addend, R_ADDEND, Type);
+ return;
+ }
+ bool CanWrite = (Sec.Flags & SHF_WRITE) || !Config->ZText;
+ if (CanWrite) {
+ // R_GOT refers to a position in the got, even if the symbol is preemptible.
+ bool IsPreemptibleValue = Sym.IsPreemptible && Expr != R_GOT;
+
+ if (!IsPreemptibleValue) {
+ addRelativeReloc(&Sec, Offset, &Sym, Addend, Expr, Type);
+ return;
+ } else if (RelType Rel = Target->getDynRel(Type)) {
+ In.RelaDyn->addReloc(Rel, &Sec, Offset, &Sym, Addend, R_ADDEND, Type);
+
+ // MIPS ABI turns using of GOT and dynamic relocations inside out.
+ // While regular ABI uses dynamic relocations to fill up GOT entries
+ // MIPS ABI requires dynamic linker to fills up GOT entries using
+ // specially sorted dynamic symbol table. This affects even dynamic
+ // relocations against symbols which do not require GOT entries
+ // creation explicitly, i.e. do not have any GOT-relocations. So if
+ // a preemptible symbol has a dynamic relocation we anyway have
+ // to create a GOT entry for it.
+ // If a non-preemptible symbol has a dynamic relocation against it,
+ // dynamic linker takes it st_value, adds offset and writes down
+ // result of the dynamic relocation. In case of preemptible symbol
+ // dynamic linker performs symbol resolution, writes the symbol value
+ // to the GOT entry and reads the GOT entry when it needs to perform
+ // a dynamic relocation.
+ // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf p.4-19
+ if (Config->EMachine == EM_MIPS)
+ In.MipsGot->addEntry(*Sec.File, Sym, Addend, Expr);
+ return;
+ }
+ }
+
+ // If the relocation is to a weak undef, and we are producing
+ // executable, give up on it and produce a non preemptible 0.
+ if (!Config->Shared && Sym.isUndefWeak()) {
+ Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
+ return;
+ }
+
+ if (!CanWrite && (Config->Pic && !isRelExpr(Expr))) {
+ error(
+ "can't create dynamic relocation " + toString(Type) + " against " +
+ (Sym.getName().empty() ? "local symbol" : "symbol: " + toString(Sym)) +
+ " in readonly segment; recompile object files with -fPIC "
+ "or pass '-Wl,-z,notext' to allow text relocations in the output" +
+ getLocation(Sec, Sym, Offset));
+ return;
+ }
+
+ // Copy relocations are only possible if we are creating an executable.
+ if (Config->Shared) {
+ errorOrWarn("relocation " + toString(Type) +
+ " cannot be used against symbol " + toString(Sym) +
+ "; recompile with -fPIC" + getLocation(Sec, Sym, Offset));
+ return;
+ }
+
+ // If the symbol is undefined we already reported any relevant errors.
+ if (Sym.isUndefined())
+ return;
+
+ if (!canDefineSymbolInExecutable(Sym)) {
+ error("cannot preempt symbol: " + toString(Sym) +
+ getLocation(Sec, Sym, Offset));
+ return;
+ }
+
+ if (Sym.isObject()) {
+ // Produce a copy relocation.
+ if (auto *SS = dyn_cast<SharedSymbol>(&Sym)) {
+ if (!Config->ZCopyreloc)
+ error("unresolvable relocation " + toString(Type) +
+ " against symbol '" + toString(*SS) +
+ "'; recompile with -fPIC or remove '-z nocopyreloc'" +
+ getLocation(Sec, Sym, Offset));
+ addCopyRelSymbol<ELFT>(*SS);
+ }
+ Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
+ return;
+ }
+
+ if (Sym.isFunc()) {
+ // This handles a non PIC program call to function in a shared library. In
+ // an ideal world, we could just report an error saying the relocation can
+ // overflow at runtime. In the real world with glibc, crt1.o has a
+ // R_X86_64_PC32 pointing to libc.so.
+ //
+ // The general idea on how to handle such cases is to create a PLT entry and
+ // use that as the function value.
+ //
+ // For the static linking part, we just return a plt expr and everything
+ // else will use the PLT entry as the address.
+ //
+ // The remaining problem is making sure pointer equality still works. We
+ // need the help of the dynamic linker for that. We let it know that we have
+ // a direct reference to a so symbol by creating an undefined symbol with a
+ // non zero st_value. Seeing that, the dynamic linker resolves the symbol to
+ // the value of the symbol we created. This is true even for got entries, so
+ // pointer equality is maintained. To avoid an infinite loop, the only entry
+ // that points to the real function is a dedicated got entry used by the
+ // plt. That is identified by special relocation types (R_X86_64_JUMP_SLOT,
+ // R_386_JMP_SLOT, etc).
+
+ // For position independent executable on i386, the plt entry requires ebx
+ // to be set. This causes two problems:
+ // * If some code has a direct reference to a function, it was probably
+ // compiled without -fPIE/-fPIC and doesn't maintain ebx.
+ // * If a library definition gets preempted to the executable, it will have
+ // the wrong ebx value.
+ if (Config->Pie && Config->EMachine == EM_386)
+ errorOrWarn("symbol '" + toString(Sym) +
+ "' cannot be preempted; recompile with -fPIE" +
+ getLocation(Sec, Sym, Offset));
+ if (!Sym.isInPlt())
+ addPltEntry<ELFT>(In.Plt, In.GotPlt, In.RelaPlt, Target->PltRel, Sym);
+ if (!Sym.isDefined())
+ replaceWithDefined(Sym, In.Plt, getPltEntryOffset(Sym.PltIndex), 0);
+ Sym.NeedsPltAddr = true;
+ Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
+ return;
+ }
+
+ errorOrWarn("symbol '" + toString(Sym) + "' has no type" +
+ getLocation(Sec, Sym, Offset));
+}
+
+template <class ELFT, class RelTy>
+static void scanReloc(InputSectionBase &Sec, OffsetGetter &GetOffset, RelTy *&I,
+ RelTy *End) {
+ const RelTy &Rel = *I;
+ Symbol &Sym = Sec.getFile<ELFT>()->getRelocTargetSym(Rel);
+ RelType Type;
+
+ // Deal with MIPS oddity.
+ if (Config->MipsN32Abi) {
+ Type = getMipsN32RelType(I, End);
+ } else {
+ Type = Rel.getType(Config->IsMips64EL);
+ ++I;
+ }
+
+ // Get an offset in an output section this relocation is applied to.
+ uint64_t Offset = GetOffset.get(Rel.r_offset);
+ if (Offset == uint64_t(-1))
+ return;
+
+ // Skip if the target symbol is an erroneous undefined symbol.
+ if (maybeReportUndefined(Sym, Sec, Rel.r_offset))
+ return;
+
+ const uint8_t *RelocatedAddr = Sec.data().begin() + Rel.r_offset;
+ RelExpr Expr = Target->getRelExpr(Type, Sym, RelocatedAddr);
+
+ // Ignore "hint" relocations because they are only markers for relaxation.
+ if (isRelExprOneOf<R_HINT, R_NONE>(Expr))
+ return;
+
+ // Strenghten or relax relocations.
+ //
+ // GNU ifunc symbols must be accessed via PLT because their addresses
+ // are determined by runtime.
+ //
+ // On the other hand, if we know that a PLT entry will be resolved within
+ // the same ELF module, we can skip PLT access and directly jump to the
+ // destination function. For example, if we are linking a main exectuable,
+ // all dynamic symbols that can be resolved within the executable will
+ // actually be resolved that way at runtime, because the main exectuable
+ // is always at the beginning of a search list. We can leverage that fact.
+ if (Sym.isGnuIFunc() && !Config->ZIfuncnoplt) {
+ if (!Config->ZText && Config->WarnIfuncTextrel) {
+ warn("using ifunc symbols when text relocations are allowed may produce "
+ "a binary that will segfault, if the object file is linked with "
+ "old version of glibc (glibc 2.28 and earlier). If this applies to "
+ "you, consider recompiling the object files without -fPIC and "
+ "without -Wl,-z,notext option. Use -no-warn-ifunc-textrel to "
+ "turn off this warning." +
+ getLocation(Sec, Sym, Offset));
+ }
+ Expr = toPlt(Expr);
+ } else if (!Sym.IsPreemptible && Expr == R_GOT_PC && !isAbsoluteValue(Sym)) {
+ Expr = Target->adjustRelaxExpr(Type, RelocatedAddr, Expr);
+ } else if (!Sym.IsPreemptible) {
+ Expr = fromPlt(Expr);
+ }
+
+ // This relocation does not require got entry, but it is relative to got and
+ // needs it to be created. Here we request for that.
+ if (isRelExprOneOf<R_GOTONLY_PC, R_GOTONLY_PC_FROM_END, R_GOTREL,
+ R_GOTREL_FROM_END, R_PPC_TOC>(Expr))
+ In.Got->HasGotOffRel = true;
+
+ // Read an addend.
+ int64_t Addend = computeAddend<ELFT>(Rel, End, Sec, Expr, Sym.isLocal());
+
+ // Process some TLS relocations, including relaxing TLS relocations.
+ // Note that this function does not handle all TLS relocations.
+ if (unsigned Processed =
+ handleTlsRelocation<ELFT>(Type, Sym, Sec, Offset, Addend, Expr)) {
+ I += (Processed - 1);
+ return;
+ }
+
+ // If a relocation needs PLT, we create PLT and GOTPLT slots for the symbol.
+ if (needsPlt(Expr) && !Sym.isInPlt()) {
+ if (Sym.isGnuIFunc() && !Sym.IsPreemptible)
+ addPltEntry<ELFT>(In.Iplt, In.IgotPlt, In.RelaIplt, Target->IRelativeRel,
+ Sym);
+ else
+ addPltEntry<ELFT>(In.Plt, In.GotPlt, In.RelaPlt, Target->PltRel, Sym);
+ }
+
+ // Create a GOT slot if a relocation needs GOT.
+ if (needsGot(Expr)) {
+ if (Config->EMachine == EM_MIPS) {
+ // MIPS ABI has special rules to process GOT entries and doesn't
+ // require relocation entries for them. A special case is TLS
+ // relocations. In that case dynamic loader applies dynamic
+ // relocations to initialize TLS GOT entries.
+ // See "Global Offset Table" in Chapter 5 in the following document
+ // for detailed description:
+ // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+ In.MipsGot->addEntry(*Sec.File, Sym, Addend, Expr);
+ } else if (!Sym.isInGot()) {
+ addGotEntry<ELFT>(Sym);
+ }
+ }
+
+ processRelocAux<ELFT>(Sec, Expr, Type, Offset, Sym, Rel, Addend);
+}
+
+template <class ELFT, class RelTy>
+static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) {
+ OffsetGetter GetOffset(Sec);
+
+ // Not all relocations end up in Sec.Relocations, but a lot do.
+ Sec.Relocations.reserve(Rels.size());
+
+ for (auto I = Rels.begin(), End = Rels.end(); I != End;)
+ scanReloc<ELFT>(Sec, GetOffset, I, End);
+
+ // Sort relocations by offset to binary search for R_RISCV_PCREL_HI20
+ if (Config->EMachine == EM_RISCV)
+ std::stable_sort(Sec.Relocations.begin(), Sec.Relocations.end(),
+ RelocationOffsetComparator{});
+}
+
+template <class ELFT> void elf::scanRelocations(InputSectionBase &S) {
+ if (S.AreRelocsRela)
+ scanRelocs<ELFT>(S, S.relas<ELFT>());
+ else
+ scanRelocs<ELFT>(S, S.rels<ELFT>());
+}
+
+static bool mergeCmp(const InputSection *A, const InputSection *B) {
+ // std::merge requires a strict weak ordering.
+ if (A->OutSecOff < B->OutSecOff)
+ return true;
+
+ if (A->OutSecOff == B->OutSecOff) {
+ auto *TA = dyn_cast<ThunkSection>(A);
+ auto *TB = dyn_cast<ThunkSection>(B);
+
+ // Check if Thunk is immediately before any specific Target
+ // InputSection for example Mips LA25 Thunks.
+ if (TA && TA->getTargetInputSection() == B)
+ return true;
+
+ // Place Thunk Sections without specific targets before
+ // non-Thunk Sections.
+ if (TA && !TB && !TA->getTargetInputSection())
+ return true;
+ }
+
+ return false;
+}
+
+// Call Fn on every executable InputSection accessed via the linker script
+// InputSectionDescription::Sections.
+static void forEachInputSectionDescription(
+ ArrayRef<OutputSection *> OutputSections,
+ llvm::function_ref<void(OutputSection *, InputSectionDescription *)> Fn) {
+ for (OutputSection *OS : OutputSections) {
+ if (!(OS->Flags & SHF_ALLOC) || !(OS->Flags & SHF_EXECINSTR))
+ continue;
+ for (BaseCommand *BC : OS->SectionCommands)
+ if (auto *ISD = dyn_cast<InputSectionDescription>(BC))
+ Fn(OS, ISD);
+ }
+}
+
+// Thunk Implementation
+//
+// Thunks (sometimes called stubs, veneers or branch islands) are small pieces
+// of code that the linker inserts inbetween a caller and a callee. The thunks
+// are added at link time rather than compile time as the decision on whether
+// a thunk is needed, such as the caller and callee being out of range, can only
+// be made at link time.
+//
+// It is straightforward to tell given the current state of the program when a
+// thunk is needed for a particular call. The more difficult part is that
+// the thunk needs to be placed in the program such that the caller can reach
+// the thunk and the thunk can reach the callee; furthermore, adding thunks to
+// the program alters addresses, which can mean more thunks etc.
+//
+// In lld we have a synthetic ThunkSection that can hold many Thunks.
+// The decision to have a ThunkSection act as a container means that we can
+// more easily handle the most common case of a single block of contiguous
+// Thunks by inserting just a single ThunkSection.
+//
+// The implementation of Thunks in lld is split across these areas
+// Relocations.cpp : Framework for creating and placing thunks
+// Thunks.cpp : The code generated for each supported thunk
+// Target.cpp : Target specific hooks that the framework uses to decide when
+// a thunk is used
+// Synthetic.cpp : Implementation of ThunkSection
+// Writer.cpp : Iteratively call framework until no more Thunks added
+//
+// Thunk placement requirements:
+// Mips LA25 thunks. These must be placed immediately before the callee section
+// We can assume that the caller is in range of the Thunk. These are modelled
+// by Thunks that return the section they must precede with
+// getTargetInputSection().
+//
+// ARM interworking and range extension thunks. These thunks must be placed
+// within range of the caller. All implemented ARM thunks can always reach the
+// callee as they use an indirect jump via a register that has no range
+// restrictions.
+//
+// Thunk placement algorithm:
+// For Mips LA25 ThunkSections; the placement is explicit, it has to be before
+// getTargetInputSection().
+//
+// For thunks that must be placed within range of the caller there are many
+// possible choices given that the maximum range from the caller is usually
+// much larger than the average InputSection size. Desirable properties include:
+// - Maximize reuse of thunks by multiple callers
+// - Minimize number of ThunkSections to simplify insertion
+// - Handle impact of already added Thunks on addresses
+// - Simple to understand and implement
+//
+// In lld for the first pass, we pre-create one or more ThunkSections per
+// InputSectionDescription at Target specific intervals. A ThunkSection is
+// placed so that the estimated end of the ThunkSection is within range of the
+// start of the InputSectionDescription or the previous ThunkSection. For
+// example:
+// InputSectionDescription
+// Section 0
+// ...
+// Section N
+// ThunkSection 0
+// Section N + 1
+// ...
+// Section N + K
+// Thunk Section 1
+//
+// The intention is that we can add a Thunk to a ThunkSection that is well
+// spaced enough to service a number of callers without having to do a lot
+// of work. An important principle is that it is not an error if a Thunk cannot
+// be placed in a pre-created ThunkSection; when this happens we create a new
+// ThunkSection placed next to the caller. This allows us to handle the vast
+// majority of thunks simply, but also handle rare cases where the branch range
+// is smaller than the target specific spacing.
+//
+// The algorithm is expected to create all the thunks that are needed in a
+// single pass, with a small number of programs needing a second pass due to
+// the insertion of thunks in the first pass increasing the offset between
+// callers and callees that were only just in range.
+//
+// A consequence of allowing new ThunkSections to be created outside of the
+// pre-created ThunkSections is that in rare cases calls to Thunks that were in
+// range in pass K, are out of range in some pass > K due to the insertion of
+// more Thunks in between the caller and callee. When this happens we retarget
+// the relocation back to the original target and create another Thunk.
+
+// Remove ThunkSections that are empty, this should only be the initial set
+// precreated on pass 0.
+
+// Insert the Thunks for OutputSection OS into their designated place
+// in the Sections vector, and recalculate the InputSection output section
+// offsets.
+// This may invalidate any output section offsets stored outside of InputSection
+void ThunkCreator::mergeThunks(ArrayRef<OutputSection *> OutputSections) {
+ forEachInputSectionDescription(
+ OutputSections, [&](OutputSection *OS, InputSectionDescription *ISD) {
+ if (ISD->ThunkSections.empty())
+ return;
+
+ // Remove any zero sized precreated Thunks.
+ llvm::erase_if(ISD->ThunkSections,
+ [](const std::pair<ThunkSection *, uint32_t> &TS) {
+ return TS.first->getSize() == 0;
+ });
+
+ // ISD->ThunkSections contains all created ThunkSections, including
+ // those inserted in previous passes. Extract the Thunks created this
+ // pass and order them in ascending OutSecOff.
+ std::vector<ThunkSection *> NewThunks;
+ for (const std::pair<ThunkSection *, uint32_t> TS : ISD->ThunkSections)
+ if (TS.second == Pass)
+ NewThunks.push_back(TS.first);
+ std::stable_sort(NewThunks.begin(), NewThunks.end(),
+ [](const ThunkSection *A, const ThunkSection *B) {
+ return A->OutSecOff < B->OutSecOff;
+ });
+
+ // Merge sorted vectors of Thunks and InputSections by OutSecOff
+ std::vector<InputSection *> Tmp;
+ Tmp.reserve(ISD->Sections.size() + NewThunks.size());
+
+ std::merge(ISD->Sections.begin(), ISD->Sections.end(),
+ NewThunks.begin(), NewThunks.end(), std::back_inserter(Tmp),
+ mergeCmp);
+
+ ISD->Sections = std::move(Tmp);
+ });
+}
+
+// Find or create a ThunkSection within the InputSectionDescription (ISD) that
+// is in range of Src. An ISD maps to a range of InputSections described by a
+// linker script section pattern such as { .text .text.* }.
+ThunkSection *ThunkCreator::getISDThunkSec(OutputSection *OS, InputSection *IS,
+ InputSectionDescription *ISD,
+ uint32_t Type, uint64_t Src) {
+ for (std::pair<ThunkSection *, uint32_t> TP : ISD->ThunkSections) {
+ ThunkSection *TS = TP.first;
+ uint64_t TSBase = OS->Addr + TS->OutSecOff;
+ uint64_t TSLimit = TSBase + TS->getSize();
+ if (Target->inBranchRange(Type, Src, (Src > TSLimit) ? TSBase : TSLimit))
+ return TS;
+ }
+
+ // No suitable ThunkSection exists. This can happen when there is a branch
+ // with lower range than the ThunkSection spacing or when there are too
+ // many Thunks. Create a new ThunkSection as close to the InputSection as
+ // possible. Error if InputSection is so large we cannot place ThunkSection
+ // anywhere in Range.
+ uint64_t ThunkSecOff = IS->OutSecOff;
+ if (!Target->inBranchRange(Type, Src, OS->Addr + ThunkSecOff)) {
+ ThunkSecOff = IS->OutSecOff + IS->getSize();
+ if (!Target->inBranchRange(Type, Src, OS->Addr + ThunkSecOff))
+ fatal("InputSection too large for range extension thunk " +
+ IS->getObjMsg(Src - (OS->Addr + IS->OutSecOff)));
+ }
+ return addThunkSection(OS, ISD, ThunkSecOff);
+}
+
+// Add a Thunk that needs to be placed in a ThunkSection that immediately
+// precedes its Target.
+ThunkSection *ThunkCreator::getISThunkSec(InputSection *IS) {
+ ThunkSection *TS = ThunkedSections.lookup(IS);
+ if (TS)
+ return TS;
+
+ // Find InputSectionRange within Target Output Section (TOS) that the
+ // InputSection (IS) that we need to precede is in.
+ OutputSection *TOS = IS->getParent();
+ for (BaseCommand *BC : TOS->SectionCommands) {
+ auto *ISD = dyn_cast<InputSectionDescription>(BC);
+ if (!ISD || ISD->Sections.empty())
+ continue;
+
+ InputSection *First = ISD->Sections.front();
+ InputSection *Last = ISD->Sections.back();
+
+ if (IS->OutSecOff < First->OutSecOff || Last->OutSecOff < IS->OutSecOff)
+ continue;
+
+ TS = addThunkSection(TOS, ISD, IS->OutSecOff);
+ ThunkedSections[IS] = TS;
+ return TS;
+ }
+
+ return nullptr;
+}
+
+// Create one or more ThunkSections per OS that can be used to place Thunks.
+// We attempt to place the ThunkSections using the following desirable
+// properties:
+// - Within range of the maximum number of callers
+// - Minimise the number of ThunkSections
+//
+// We follow a simple but conservative heuristic to place ThunkSections at
+// offsets that are multiples of a Target specific branch range.
+// For an InputSectionDescription that is smaller than the range, a single
+// ThunkSection at the end of the range will do.
+//
+// For an InputSectionDescription that is more than twice the size of the range,
+// we place the last ThunkSection at range bytes from the end of the
+// InputSectionDescription in order to increase the likelihood that the
+// distance from a thunk to its target will be sufficiently small to
+// allow for the creation of a short thunk.
+void ThunkCreator::createInitialThunkSections(
+ ArrayRef<OutputSection *> OutputSections) {
+ uint32_t ThunkSectionSpacing = Target->getThunkSectionSpacing();
+
+ forEachInputSectionDescription(
+ OutputSections, [&](OutputSection *OS, InputSectionDescription *ISD) {
+ if (ISD->Sections.empty())
+ return;
+
+ uint32_t ISDBegin = ISD->Sections.front()->OutSecOff;
+ uint32_t ISDEnd =
+ ISD->Sections.back()->OutSecOff + ISD->Sections.back()->getSize();
+ uint32_t LastThunkLowerBound = -1;
+ if (ISDEnd - ISDBegin > ThunkSectionSpacing * 2)
+ LastThunkLowerBound = ISDEnd - ThunkSectionSpacing;
+
+ uint32_t ISLimit;
+ uint32_t PrevISLimit = ISDBegin;
+ uint32_t ThunkUpperBound = ISDBegin + ThunkSectionSpacing;
+
+ for (const InputSection *IS : ISD->Sections) {
+ ISLimit = IS->OutSecOff + IS->getSize();
+ if (ISLimit > ThunkUpperBound) {
+ addThunkSection(OS, ISD, PrevISLimit);
+ ThunkUpperBound = PrevISLimit + ThunkSectionSpacing;
+ }
+ if (ISLimit > LastThunkLowerBound)
+ break;
+ PrevISLimit = ISLimit;
+ }
+ addThunkSection(OS, ISD, ISLimit);
+ });
+}
+
+ThunkSection *ThunkCreator::addThunkSection(OutputSection *OS,
+ InputSectionDescription *ISD,
+ uint64_t Off) {
+ auto *TS = make<ThunkSection>(OS, Off);
+ ISD->ThunkSections.push_back({TS, Pass});
+ return TS;
+}
+
+std::pair<Thunk *, bool> ThunkCreator::getThunk(Symbol &Sym, RelType Type,
+ uint64_t Src) {
+ std::vector<Thunk *> *ThunkVec = nullptr;
+
+ // We use (section, offset) pair to find the thunk position if possible so
+ // that we create only one thunk for aliased symbols or ICFed sections.
+ if (auto *D = dyn_cast<Defined>(&Sym))
+ if (!D->isInPlt() && D->Section)
+ ThunkVec = &ThunkedSymbolsBySection[{D->Section->Repl, D->Value}];
+ if (!ThunkVec)
+ ThunkVec = &ThunkedSymbols[&Sym];
+
+ // Check existing Thunks for Sym to see if they can be reused
+ for (Thunk *T : *ThunkVec)
+ if (T->isCompatibleWith(Type) &&
+ Target->inBranchRange(Type, Src, T->getThunkTargetSym()->getVA()))
+ return std::make_pair(T, false);
+
+ // No existing compatible Thunk in range, create a new one
+ Thunk *T = addThunk(Type, Sym);
+ ThunkVec->push_back(T);
+ return std::make_pair(T, true);
+}
+
+// Return true if the relocation target is an in range Thunk.
+// Return false if the relocation is not to a Thunk. If the relocation target
+// was originally to a Thunk, but is no longer in range we revert the
+// relocation back to its original non-Thunk target.
+bool ThunkCreator::normalizeExistingThunk(Relocation &Rel, uint64_t Src) {
+ if (Thunk *T = Thunks.lookup(Rel.Sym)) {
+ if (Target->inBranchRange(Rel.Type, Src, Rel.Sym->getVA()))
+ return true;
+ Rel.Sym = &T->Destination;
+ if (Rel.Sym->isInPlt())
+ Rel.Expr = toPlt(Rel.Expr);
+ }
+ return false;
+}
+
+// Process all relocations from the InputSections that have been assigned
+// to InputSectionDescriptions and redirect through Thunks if needed. The
+// function should be called iteratively until it returns false.
+//
+// PreConditions:
+// All InputSections that may need a Thunk are reachable from
+// OutputSectionCommands.
+//
+// All OutputSections have an address and all InputSections have an offset
+// within the OutputSection.
+//
+// The offsets between caller (relocation place) and callee
+// (relocation target) will not be modified outside of createThunks().
+//
+// PostConditions:
+// If return value is true then ThunkSections have been inserted into
+// OutputSections. All relocations that needed a Thunk based on the information
+// available to createThunks() on entry have been redirected to a Thunk. Note
+// that adding Thunks changes offsets between caller and callee so more Thunks
+// may be required.
+//
+// If return value is false then no more Thunks are needed, and createThunks has
+// made no changes. If the target requires range extension thunks, currently
+// ARM, then any future change in offset between caller and callee risks a
+// relocation out of range error.
+bool ThunkCreator::createThunks(ArrayRef<OutputSection *> OutputSections) {
+ bool AddressesChanged = false;
+
+ if (Pass == 0 && Target->getThunkSectionSpacing())
+ createInitialThunkSections(OutputSections);
+
+ // With Thunk Size much smaller than branch range we expect to
+ // converge quickly; if we get to 10 something has gone wrong.
+ if (Pass == 10)
+ fatal("thunk creation not converged");
+
+ // Create all the Thunks and insert them into synthetic ThunkSections. The
+ // ThunkSections are later inserted back into InputSectionDescriptions.
+ // We separate the creation of ThunkSections from the insertion of the
+ // ThunkSections as ThunkSections are not always inserted into the same
+ // InputSectionDescription as the caller.
+ forEachInputSectionDescription(
+ OutputSections, [&](OutputSection *OS, InputSectionDescription *ISD) {
+ for (InputSection *IS : ISD->Sections)
+ for (Relocation &Rel : IS->Relocations) {
+ uint64_t Src = IS->getVA(Rel.Offset);
+
+ // If we are a relocation to an existing Thunk, check if it is
+ // still in range. If not then Rel will be altered to point to its
+ // original target so another Thunk can be generated.
+ if (Pass > 0 && normalizeExistingThunk(Rel, Src))
+ continue;
+
+ if (!Target->needsThunk(Rel.Expr, Rel.Type, IS->File, Src,
+ *Rel.Sym))
+ continue;
+
+ Thunk *T;
+ bool IsNew;
+ std::tie(T, IsNew) = getThunk(*Rel.Sym, Rel.Type, Src);
+
+ if (IsNew) {
+ // Find or create a ThunkSection for the new Thunk
+ ThunkSection *TS;
+ if (auto *TIS = T->getTargetInputSection())
+ TS = getISThunkSec(TIS);
+ else
+ TS = getISDThunkSec(OS, IS, ISD, Rel.Type, Src);
+ TS->addThunk(T);
+ Thunks[T->getThunkTargetSym()] = T;
+ }
+
+ // Redirect relocation to Thunk, we never go via the PLT to a Thunk
+ Rel.Sym = T->getThunkTargetSym();
+ Rel.Expr = fromPlt(Rel.Expr);
+ }
+
+ for (auto &P : ISD->ThunkSections)
+ AddressesChanged |= P.first->assignOffsets();
+ });
+
+ for (auto &P : ThunkedSections)
+ AddressesChanged |= P.second->assignOffsets();
+
+ // Merge all created synthetic ThunkSections back into OutputSection
+ mergeThunks(OutputSections);
+ ++Pass;
+ return AddressesChanged;
+}
+
+template void elf::scanRelocations<ELF32LE>(InputSectionBase &);
+template void elf::scanRelocations<ELF32BE>(InputSectionBase &);
+template void elf::scanRelocations<ELF64LE>(InputSectionBase &);
+template void elf::scanRelocations<ELF64BE>(InputSectionBase &);
diff --git a/contrib/llvm/tools/lld/ELF/Relocations.h b/contrib/llvm/tools/lld/ELF/Relocations.h
new file mode 100644
index 000000000000..d00e68bd36e6
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Relocations.h
@@ -0,0 +1,219 @@
+//===- Relocations.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_RELOCATIONS_H
+#define LLD_ELF_RELOCATIONS_H
+
+#include "lld/Common/LLVM.h"
+#include "llvm/ADT/DenseMap.h"
+#include <map>
+#include <vector>
+
+namespace lld {
+namespace elf {
+class Symbol;
+class InputSection;
+class InputSectionBase;
+class OutputSection;
+class SectionBase;
+
+// Represents a relocation type, such as R_X86_64_PC32 or R_ARM_THM_CALL.
+typedef uint32_t RelType;
+
+// List of target-independent relocation types. Relocations read
+// from files are converted to these types so that the main code
+// doesn't have to know about architecture-specific details.
+enum RelExpr {
+ R_INVALID,
+ R_ABS,
+ R_ADDEND,
+ R_AARCH64_GOT_PAGE_PC,
+ // The expression is used for IFUNC support. Describes PC-relative
+ // address of the memory page of GOT entry. This entry is used for
+ // a redirection to IPLT.
+ R_AARCH64_GOT_PAGE_PC_PLT,
+ R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC,
+ R_AARCH64_PAGE_PC,
+ R_AARCH64_PLT_PAGE_PC,
+ R_AARCH64_TLSDESC_PAGE,
+ R_ARM_SBREL,
+ R_GOT,
+ // The expression is used for IFUNC support. Evaluates to GOT entry,
+ // containing redirection to the IPLT.
+ R_GOT_PLT,
+ R_GOTONLY_PC,
+ R_GOTONLY_PC_FROM_END,
+ R_GOTREL,
+ R_GOTREL_FROM_END,
+ R_GOT_FROM_END,
+ R_GOT_OFF,
+ R_GOT_PC,
+ R_HEXAGON_GOT,
+ R_HINT,
+ R_MIPS_GOTREL,
+ R_MIPS_GOT_GP,
+ R_MIPS_GOT_GP_PC,
+ R_MIPS_GOT_LOCAL_PAGE,
+ R_MIPS_GOT_OFF,
+ R_MIPS_GOT_OFF32,
+ R_MIPS_TLSGD,
+ R_MIPS_TLSLD,
+ R_NEG_TLS,
+ R_NONE,
+ R_PC,
+ R_PLT,
+ R_PLT_PC,
+ R_PPC_CALL,
+ R_PPC_CALL_PLT,
+ R_PPC_TOC,
+ R_RELAX_GOT_PC,
+ R_RELAX_GOT_PC_NOPIC,
+ R_RELAX_TLS_GD_TO_IE,
+ R_RELAX_TLS_GD_TO_IE_ABS,
+ R_RELAX_TLS_GD_TO_IE_END,
+ R_RELAX_TLS_GD_TO_IE_GOT_OFF,
+ R_RELAX_TLS_GD_TO_LE,
+ R_RELAX_TLS_GD_TO_LE_NEG,
+ R_RELAX_TLS_IE_TO_LE,
+ R_RELAX_TLS_LD_TO_LE,
+ R_RELAX_TLS_LD_TO_LE_ABS,
+ R_RISCV_PC_INDIRECT,
+ R_SIZE,
+ R_TLS,
+ R_TLSDESC,
+ R_TLSDESC_CALL,
+ R_TLSGD_GOT,
+ R_TLSGD_GOT_FROM_END,
+ R_TLSGD_PC,
+ R_TLSIE_HINT,
+ R_TLSLD_GOT,
+ R_TLSLD_GOT_FROM_END,
+ R_TLSLD_GOT_OFF,
+ R_TLSLD_HINT,
+ R_TLSLD_PC,
+};
+
+// Build a bitmask with one bit set for each RelExpr.
+//
+// Constexpr function arguments can't be used in static asserts, so we
+// use template arguments to build the mask.
+// But function template partial specializations don't exist (needed
+// for base case of the recursion), so we need a dummy struct.
+template <RelExpr... Exprs> struct RelExprMaskBuilder {
+ static inline uint64_t build() { return 0; }
+};
+
+// Specialization for recursive case.
+template <RelExpr Head, RelExpr... Tail>
+struct RelExprMaskBuilder<Head, Tail...> {
+ static inline uint64_t build() {
+ static_assert(0 <= Head && Head < 64,
+ "RelExpr is too large for 64-bit mask!");
+ return (uint64_t(1) << Head) | RelExprMaskBuilder<Tail...>::build();
+ }
+};
+
+// Return true if `Expr` is one of `Exprs`.
+// There are fewer than 64 RelExpr's, so we can represent any set of
+// RelExpr's as a constant bit mask and test for membership with a
+// couple cheap bitwise operations.
+template <RelExpr... Exprs> bool isRelExprOneOf(RelExpr Expr) {
+ assert(0 <= Expr && (int)Expr < 64 &&
+ "RelExpr is too large for 64-bit mask!");
+ return (uint64_t(1) << Expr) & RelExprMaskBuilder<Exprs...>::build();
+}
+
+// Architecture-neutral representation of relocation.
+struct Relocation {
+ RelExpr Expr;
+ RelType Type;
+ uint64_t Offset;
+ int64_t Addend;
+ Symbol *Sym;
+};
+
+struct RelocationOffsetComparator {
+ bool operator()(const Relocation &Lhs, const Relocation &Rhs) {
+ return Lhs.Offset < Rhs.Offset;
+ }
+
+ // For std::lower_bound, std::upper_bound, std::equal_range.
+ bool operator()(const Relocation &Rel, uint64_t Val) {
+ return Rel.Offset < Val;
+ }
+
+ bool operator()(uint64_t Val, const Relocation &Rel) {
+ return Val < Rel.Offset;
+ }
+};
+
+template <class ELFT> void scanRelocations(InputSectionBase &);
+
+class ThunkSection;
+class Thunk;
+struct InputSectionDescription;
+
+class ThunkCreator {
+public:
+ // Return true if Thunks have been added to OutputSections
+ bool createThunks(ArrayRef<OutputSection *> OutputSections);
+
+ // The number of completed passes of createThunks this permits us
+ // to do one time initialization on Pass 0 and put a limit on the
+ // number of times it can be called to prevent infinite loops.
+ uint32_t Pass = 0;
+
+private:
+ void mergeThunks(ArrayRef<OutputSection *> OutputSections);
+
+ ThunkSection *getISDThunkSec(OutputSection *OS, InputSection *IS,
+ InputSectionDescription *ISD, uint32_t Type,
+ uint64_t Src);
+
+ ThunkSection *getISThunkSec(InputSection *IS);
+
+ void createInitialThunkSections(ArrayRef<OutputSection *> OutputSections);
+
+ std::pair<Thunk *, bool> getThunk(Symbol &Sym, RelType Type, uint64_t Src);
+
+ ThunkSection *addThunkSection(OutputSection *OS, InputSectionDescription *,
+ uint64_t Off);
+
+ bool normalizeExistingThunk(Relocation &Rel, uint64_t Src);
+
+ // Record all the available Thunks for a Symbol
+ llvm::DenseMap<std::pair<SectionBase *, uint64_t>, std::vector<Thunk *>>
+ ThunkedSymbolsBySection;
+ llvm::DenseMap<Symbol *, std::vector<Thunk *>> ThunkedSymbols;
+
+ // Find a Thunk from the Thunks symbol definition, we can use this to find
+ // the Thunk from a relocation to the Thunks symbol definition.
+ llvm::DenseMap<Symbol *, Thunk *> Thunks;
+
+ // Track InputSections that have an inline ThunkSection placed in front
+ // an inline ThunkSection may have control fall through to the section below
+ // so we need to make sure that there is only one of them.
+ // The Mips LA25 Thunk is an example of an inline ThunkSection.
+ llvm::DenseMap<InputSection *, ThunkSection *> ThunkedSections;
+};
+
+// Return a int64_t to make sure we get the sign extension out of the way as
+// early as possible.
+template <class ELFT>
+static inline int64_t getAddend(const typename ELFT::Rel &Rel) {
+ return 0;
+}
+template <class ELFT>
+static inline int64_t getAddend(const typename ELFT::Rela &Rel) {
+ return Rel.r_addend;
+}
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/ELF/ScriptLexer.cpp b/contrib/llvm/tools/lld/ELF/ScriptLexer.cpp
new file mode 100644
index 000000000000..9a372c6d1c6f
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/ScriptLexer.cpp
@@ -0,0 +1,298 @@
+//===- ScriptLexer.cpp ----------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a lexer for the linker script.
+//
+// The linker script's grammar is not complex but ambiguous due to the
+// lack of the formal specification of the language. What we are trying to
+// do in this and other files in LLD is to make a "reasonable" linker
+// script processor.
+//
+// Among simplicity, compatibility and efficiency, we put the most
+// emphasis on simplicity when we wrote this lexer. Compatibility with the
+// GNU linkers is important, but we did not try to clone every tiny corner
+// case of their lexers, as even ld.bfd and ld.gold are subtly different
+// in various corner cases. We do not care much about efficiency because
+// the time spent in parsing linker scripts is usually negligible.
+//
+// Our grammar of the linker script is LL(2), meaning that it needs at
+// most two-token lookahead to parse. The only place we need two-token
+// lookahead is labels in version scripts, where we need to parse "local :"
+// as if "local:".
+//
+// Overall, this lexer works fine for most linker scripts. There might
+// be room for improving compatibility, but that's probably not at the
+// top of our todo list.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ScriptLexer.h"
+#include "lld/Common/ErrorHandler.h"
+#include "llvm/ADT/Twine.h"
+
+using namespace llvm;
+using namespace lld;
+using namespace lld::elf;
+
+// Returns a whole line containing the current token.
+StringRef ScriptLexer::getLine() {
+ StringRef S = getCurrentMB().getBuffer();
+ StringRef Tok = Tokens[Pos - 1];
+
+ size_t Pos = S.rfind('\n', Tok.data() - S.data());
+ if (Pos != StringRef::npos)
+ S = S.substr(Pos + 1);
+ return S.substr(0, S.find_first_of("\r\n"));
+}
+
+// Returns 1-based line number of the current token.
+size_t ScriptLexer::getLineNumber() {
+ StringRef S = getCurrentMB().getBuffer();
+ StringRef Tok = Tokens[Pos - 1];
+ return S.substr(0, Tok.data() - S.data()).count('\n') + 1;
+}
+
+// Returns 0-based column number of the current token.
+size_t ScriptLexer::getColumnNumber() {
+ StringRef Tok = Tokens[Pos - 1];
+ return Tok.data() - getLine().data();
+}
+
+std::string ScriptLexer::getCurrentLocation() {
+ std::string Filename = getCurrentMB().getBufferIdentifier();
+ return (Filename + ":" + Twine(getLineNumber())).str();
+}
+
+ScriptLexer::ScriptLexer(MemoryBufferRef MB) { tokenize(MB); }
+
+// We don't want to record cascading errors. Keep only the first one.
+void ScriptLexer::setError(const Twine &Msg) {
+ if (errorCount())
+ return;
+
+ std::string S = (getCurrentLocation() + ": " + Msg).str();
+ if (Pos)
+ S += "\n>>> " + getLine().str() + "\n>>> " +
+ std::string(getColumnNumber(), ' ') + "^";
+ error(S);
+}
+
+// Split S into linker script tokens.
+void ScriptLexer::tokenize(MemoryBufferRef MB) {
+ std::vector<StringRef> Vec;
+ MBs.push_back(MB);
+ StringRef S = MB.getBuffer();
+ StringRef Begin = S;
+
+ for (;;) {
+ S = skipSpace(S);
+ if (S.empty())
+ break;
+
+ // Quoted token. Note that double-quote characters are parts of a token
+ // because, in a glob match context, only unquoted tokens are interpreted
+ // as glob patterns. Double-quoted tokens are literal patterns in that
+ // context.
+ if (S.startswith("\"")) {
+ size_t E = S.find("\"", 1);
+ if (E == StringRef::npos) {
+ StringRef Filename = MB.getBufferIdentifier();
+ size_t Lineno = Begin.substr(0, S.data() - Begin.data()).count('\n');
+ error(Filename + ":" + Twine(Lineno + 1) + ": unclosed quote");
+ return;
+ }
+
+ Vec.push_back(S.take_front(E + 1));
+ S = S.substr(E + 1);
+ continue;
+ }
+
+ // ">foo" is parsed to ">" and "foo", but ">>" is parsed to ">>".
+ // "|", "||", "&" and "&&" are different operators.
+ if (S.startswith("<<") || S.startswith("<=") || S.startswith(">>") ||
+ S.startswith(">=") || S.startswith("||") || S.startswith("&&")) {
+ Vec.push_back(S.substr(0, 2));
+ S = S.substr(2);
+ continue;
+ }
+
+ // Unquoted token. This is more relaxed than tokens in C-like language,
+ // so that you can write "file-name.cpp" as one bare token, for example.
+ size_t Pos = S.find_first_not_of(
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+ "0123456789_.$/\\~=+[]*?-!^:");
+
+ // A character that cannot start a word (which is usually a
+ // punctuation) forms a single character token.
+ if (Pos == 0)
+ Pos = 1;
+ Vec.push_back(S.substr(0, Pos));
+ S = S.substr(Pos);
+ }
+
+ Tokens.insert(Tokens.begin() + Pos, Vec.begin(), Vec.end());
+}
+
+// Skip leading whitespace characters or comments.
+StringRef ScriptLexer::skipSpace(StringRef S) {
+ for (;;) {
+ if (S.startswith("/*")) {
+ size_t E = S.find("*/", 2);
+ if (E == StringRef::npos) {
+ error("unclosed comment in a linker script");
+ return "";
+ }
+ S = S.substr(E + 2);
+ continue;
+ }
+ if (S.startswith("#")) {
+ size_t E = S.find('\n', 1);
+ if (E == StringRef::npos)
+ E = S.size() - 1;
+ S = S.substr(E + 1);
+ continue;
+ }
+ size_t Size = S.size();
+ S = S.ltrim();
+ if (S.size() == Size)
+ return S;
+ }
+}
+
+// An erroneous token is handled as if it were the last token before EOF.
+bool ScriptLexer::atEOF() { return errorCount() || Tokens.size() == Pos; }
+
+// Split a given string as an expression.
+// This function returns "3", "*" and "5" for "3*5" for example.
+static std::vector<StringRef> tokenizeExpr(StringRef S) {
+ StringRef Ops = "+-*/:!~"; // List of operators
+
+ // Quoted strings are literal strings, so we don't want to split it.
+ if (S.startswith("\""))
+ return {S};
+
+ // Split S with operators as separators.
+ std::vector<StringRef> Ret;
+ while (!S.empty()) {
+ size_t E = S.find_first_of(Ops);
+
+ // No need to split if there is no operator.
+ if (E == StringRef::npos) {
+ Ret.push_back(S);
+ break;
+ }
+
+ // Get a token before the opreator.
+ if (E != 0)
+ Ret.push_back(S.substr(0, E));
+
+ // Get the operator as a token. Keep != as one token.
+ if (S.substr(E).startswith("!=")) {
+ Ret.push_back(S.substr(E, 2));
+ S = S.substr(E + 2);
+ } else {
+ Ret.push_back(S.substr(E, 1));
+ S = S.substr(E + 1);
+ }
+ }
+ return Ret;
+}
+
+// In contexts where expressions are expected, the lexer should apply
+// different tokenization rules than the default one. By default,
+// arithmetic operator characters are regular characters, but in the
+// expression context, they should be independent tokens.
+//
+// For example, "foo*3" should be tokenized to "foo", "*" and "3" only
+// in the expression context.
+//
+// This function may split the current token into multiple tokens.
+void ScriptLexer::maybeSplitExpr() {
+ if (!InExpr || errorCount() || atEOF())
+ return;
+
+ std::vector<StringRef> V = tokenizeExpr(Tokens[Pos]);
+ if (V.size() == 1)
+ return;
+ Tokens.erase(Tokens.begin() + Pos);
+ Tokens.insert(Tokens.begin() + Pos, V.begin(), V.end());
+}
+
+StringRef ScriptLexer::next() {
+ maybeSplitExpr();
+
+ if (errorCount())
+ return "";
+ if (atEOF()) {
+ setError("unexpected EOF");
+ return "";
+ }
+ return Tokens[Pos++];
+}
+
+StringRef ScriptLexer::peek() {
+ StringRef Tok = next();
+ if (errorCount())
+ return "";
+ Pos = Pos - 1;
+ return Tok;
+}
+
+StringRef ScriptLexer::peek2() {
+ skip();
+ StringRef Tok = next();
+ if (errorCount())
+ return "";
+ Pos = Pos - 2;
+ return Tok;
+}
+
+bool ScriptLexer::consume(StringRef Tok) {
+ if (peek() == Tok) {
+ skip();
+ return true;
+ }
+ return false;
+}
+
+// Consumes Tok followed by ":". Space is allowed between Tok and ":".
+bool ScriptLexer::consumeLabel(StringRef Tok) {
+ if (consume((Tok + ":").str()))
+ return true;
+ if (Tokens.size() >= Pos + 2 && Tokens[Pos] == Tok &&
+ Tokens[Pos + 1] == ":") {
+ Pos += 2;
+ return true;
+ }
+ return false;
+}
+
+void ScriptLexer::skip() { (void)next(); }
+
+void ScriptLexer::expect(StringRef Expect) {
+ if (errorCount())
+ return;
+ StringRef Tok = next();
+ if (Tok != Expect)
+ setError(Expect + " expected, but got " + Tok);
+}
+
+// Returns true if S encloses T.
+static bool encloses(StringRef S, StringRef T) {
+ return S.bytes_begin() <= T.bytes_begin() && T.bytes_end() <= S.bytes_end();
+}
+
+MemoryBufferRef ScriptLexer::getCurrentMB() {
+ // Find input buffer containing the current token.
+ assert(!MBs.empty() && Pos > 0);
+ for (MemoryBufferRef MB : MBs)
+ if (encloses(MB.getBuffer(), Tokens[Pos - 1]))
+ return MB;
+ llvm_unreachable("getCurrentMB: failed to find a token");
+}
diff --git a/contrib/llvm/tools/lld/ELF/ScriptLexer.h b/contrib/llvm/tools/lld/ELF/ScriptLexer.h
new file mode 100644
index 000000000000..fc6b5b1008a7
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/ScriptLexer.h
@@ -0,0 +1,56 @@
+//===- ScriptLexer.h --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_SCRIPT_LEXER_H
+#define LLD_ELF_SCRIPT_LEXER_H
+
+#include "lld/Common/LLVM.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <utility>
+#include <vector>
+
+namespace lld {
+namespace elf {
+
+class ScriptLexer {
+public:
+ explicit ScriptLexer(MemoryBufferRef MB);
+
+ void setError(const Twine &Msg);
+ void tokenize(MemoryBufferRef MB);
+ static StringRef skipSpace(StringRef S);
+ bool atEOF();
+ StringRef next();
+ StringRef peek();
+ StringRef peek2();
+ void skip();
+ bool consume(StringRef Tok);
+ void expect(StringRef Expect);
+ bool consumeLabel(StringRef Tok);
+ std::string getCurrentLocation();
+
+ std::vector<MemoryBufferRef> MBs;
+ std::vector<StringRef> Tokens;
+ bool InExpr = false;
+ size_t Pos = 0;
+
+private:
+ void maybeSplitExpr();
+ StringRef getLine();
+ size_t getLineNumber();
+ size_t getColumnNumber();
+
+ MemoryBufferRef getCurrentMB();
+};
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/ELF/ScriptParser.cpp b/contrib/llvm/tools/lld/ELF/ScriptParser.cpp
new file mode 100644
index 000000000000..7dbe1641622b
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/ScriptParser.cpp
@@ -0,0 +1,1545 @@
+//===- ScriptParser.cpp ---------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains a recursive-descendent parser for linker scripts.
+// Parsed results are stored to Config and Script global objects.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ScriptParser.h"
+#include "Config.h"
+#include "Driver.h"
+#include "InputSection.h"
+#include "LinkerScript.h"
+#include "OutputSections.h"
+#include "ScriptLexer.h"
+#include "Symbols.h"
+#include "Target.h"
+#include "lld/Common/Memory.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include <cassert>
+#include <limits>
+#include <vector>
+
+using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::support::endian;
+using namespace lld;
+using namespace lld::elf;
+
+static bool isUnderSysroot(StringRef Path);
+
+namespace {
+class ScriptParser final : ScriptLexer {
+public:
+ ScriptParser(MemoryBufferRef MB)
+ : ScriptLexer(MB),
+ IsUnderSysroot(isUnderSysroot(MB.getBufferIdentifier())) {}
+
+ void readLinkerScript();
+ void readVersionScript();
+ void readDynamicList();
+ void readDefsym(StringRef Name);
+
+private:
+ void addFile(StringRef Path);
+
+ void readAsNeeded();
+ void readEntry();
+ void readExtern();
+ void readGroup();
+ void readInclude();
+ void readInput();
+ void readMemory();
+ void readOutput();
+ void readOutputArch();
+ void readOutputFormat();
+ void readPhdrs();
+ void readRegionAlias();
+ void readSearchDir();
+ void readSections();
+ void readTarget();
+ void readVersion();
+ void readVersionScriptCommand();
+
+ SymbolAssignment *readSymbolAssignment(StringRef Name);
+ ByteCommand *readByteCommand(StringRef Tok);
+ std::array<uint8_t, 4> readFill();
+ std::array<uint8_t, 4> parseFill(StringRef Tok);
+ bool readSectionDirective(OutputSection *Cmd, StringRef Tok1, StringRef Tok2);
+ void readSectionAddressType(OutputSection *Cmd);
+ OutputSection *readOverlaySectionDescription();
+ OutputSection *readOutputSectionDescription(StringRef OutSec);
+ std::vector<BaseCommand *> readOverlay();
+ std::vector<StringRef> readOutputSectionPhdrs();
+ InputSectionDescription *readInputSectionDescription(StringRef Tok);
+ StringMatcher readFilePatterns();
+ std::vector<SectionPattern> readInputSectionsList();
+ InputSectionDescription *readInputSectionRules(StringRef FilePattern);
+ unsigned readPhdrType();
+ SortSectionPolicy readSortKind();
+ SymbolAssignment *readProvideHidden(bool Provide, bool Hidden);
+ SymbolAssignment *readAssignment(StringRef Tok);
+ void readSort();
+ Expr readAssert();
+ Expr readConstant();
+ Expr getPageSize();
+
+ uint64_t readMemoryAssignment(StringRef, StringRef, StringRef);
+ std::pair<uint32_t, uint32_t> readMemoryAttributes();
+
+ Expr combine(StringRef Op, Expr L, Expr R);
+ Expr readExpr();
+ Expr readExpr1(Expr Lhs, int MinPrec);
+ StringRef readParenLiteral();
+ Expr readPrimary();
+ Expr readTernary(Expr Cond);
+ Expr readParenExpr();
+
+ // For parsing version script.
+ std::vector<SymbolVersion> readVersionExtern();
+ void readAnonymousDeclaration();
+ void readVersionDeclaration(StringRef VerStr);
+
+ std::pair<std::vector<SymbolVersion>, std::vector<SymbolVersion>>
+ readSymbols();
+
+ // True if a script being read is in a subdirectory specified by -sysroot.
+ bool IsUnderSysroot;
+
+ // A set to detect an INCLUDE() cycle.
+ StringSet<> Seen;
+};
+} // namespace
+
+static StringRef unquote(StringRef S) {
+ if (S.startswith("\""))
+ return S.substr(1, S.size() - 2);
+ return S;
+}
+
+static bool isUnderSysroot(StringRef Path) {
+ if (Config->Sysroot == "")
+ return false;
+ for (; !Path.empty(); Path = sys::path::parent_path(Path))
+ if (sys::fs::equivalent(Config->Sysroot, Path))
+ return true;
+ return false;
+}
+
+// Some operations only support one non absolute value. Move the
+// absolute one to the right hand side for convenience.
+static void moveAbsRight(ExprValue &A, ExprValue &B) {
+ if (A.Sec == nullptr || (A.ForceAbsolute && !B.isAbsolute()))
+ std::swap(A, B);
+ if (!B.isAbsolute())
+ error(A.Loc + ": at least one side of the expression must be absolute");
+}
+
+static ExprValue add(ExprValue A, ExprValue B) {
+ moveAbsRight(A, B);
+ return {A.Sec, A.ForceAbsolute, A.getSectionOffset() + B.getValue(), A.Loc};
+}
+
+static ExprValue sub(ExprValue A, ExprValue B) {
+ // The distance between two symbols in sections is absolute.
+ if (!A.isAbsolute() && !B.isAbsolute())
+ return A.getValue() - B.getValue();
+ return {A.Sec, false, A.getSectionOffset() - B.getValue(), A.Loc};
+}
+
+static ExprValue bitAnd(ExprValue A, ExprValue B) {
+ moveAbsRight(A, B);
+ return {A.Sec, A.ForceAbsolute,
+ (A.getValue() & B.getValue()) - A.getSecAddr(), A.Loc};
+}
+
+static ExprValue bitOr(ExprValue A, ExprValue B) {
+ moveAbsRight(A, B);
+ return {A.Sec, A.ForceAbsolute,
+ (A.getValue() | B.getValue()) - A.getSecAddr(), A.Loc};
+}
+
+void ScriptParser::readDynamicList() {
+ Config->HasDynamicList = true;
+ expect("{");
+ std::vector<SymbolVersion> Locals;
+ std::vector<SymbolVersion> Globals;
+ std::tie(Locals, Globals) = readSymbols();
+ expect(";");
+
+ if (!atEOF()) {
+ setError("EOF expected, but got " + next());
+ return;
+ }
+ if (!Locals.empty()) {
+ setError("\"local:\" scope not supported in --dynamic-list");
+ return;
+ }
+
+ for (SymbolVersion V : Globals)
+ Config->DynamicList.push_back(V);
+}
+
+void ScriptParser::readVersionScript() {
+ readVersionScriptCommand();
+ if (!atEOF())
+ setError("EOF expected, but got " + next());
+}
+
+void ScriptParser::readVersionScriptCommand() {
+ if (consume("{")) {
+ readAnonymousDeclaration();
+ return;
+ }
+
+ while (!atEOF() && !errorCount() && peek() != "}") {
+ StringRef VerStr = next();
+ if (VerStr == "{") {
+ setError("anonymous version definition is used in "
+ "combination with other version definitions");
+ return;
+ }
+ expect("{");
+ readVersionDeclaration(VerStr);
+ }
+}
+
+void ScriptParser::readVersion() {
+ expect("{");
+ readVersionScriptCommand();
+ expect("}");
+}
+
+void ScriptParser::readLinkerScript() {
+ while (!atEOF()) {
+ StringRef Tok = next();
+ if (Tok == ";")
+ continue;
+
+ if (Tok == "ENTRY") {
+ readEntry();
+ } else if (Tok == "EXTERN") {
+ readExtern();
+ } else if (Tok == "GROUP") {
+ readGroup();
+ } else if (Tok == "INCLUDE") {
+ readInclude();
+ } else if (Tok == "INPUT") {
+ readInput();
+ } else if (Tok == "MEMORY") {
+ readMemory();
+ } else if (Tok == "OUTPUT") {
+ readOutput();
+ } else if (Tok == "OUTPUT_ARCH") {
+ readOutputArch();
+ } else if (Tok == "OUTPUT_FORMAT") {
+ readOutputFormat();
+ } else if (Tok == "PHDRS") {
+ readPhdrs();
+ } else if (Tok == "REGION_ALIAS") {
+ readRegionAlias();
+ } else if (Tok == "SEARCH_DIR") {
+ readSearchDir();
+ } else if (Tok == "SECTIONS") {
+ readSections();
+ } else if (Tok == "TARGET") {
+ readTarget();
+ } else if (Tok == "VERSION") {
+ readVersion();
+ } else if (SymbolAssignment *Cmd = readAssignment(Tok)) {
+ Script->SectionCommands.push_back(Cmd);
+ } else {
+ setError("unknown directive: " + Tok);
+ }
+ }
+}
+
+void ScriptParser::readDefsym(StringRef Name) {
+ if (errorCount())
+ return;
+ Expr E = readExpr();
+ if (!atEOF())
+ setError("EOF expected, but got " + next());
+ SymbolAssignment *Cmd = make<SymbolAssignment>(Name, E, getCurrentLocation());
+ Script->SectionCommands.push_back(Cmd);
+}
+
+void ScriptParser::addFile(StringRef S) {
+ if (IsUnderSysroot && S.startswith("/")) {
+ SmallString<128> PathData;
+ StringRef Path = (Config->Sysroot + S).toStringRef(PathData);
+ if (sys::fs::exists(Path)) {
+ Driver->addFile(Saver.save(Path), /*WithLOption=*/false);
+ return;
+ }
+ }
+
+ if (S.startswith("/")) {
+ Driver->addFile(S, /*WithLOption=*/false);
+ } else if (S.startswith("=")) {
+ if (Config->Sysroot.empty())
+ Driver->addFile(S.substr(1), /*WithLOption=*/false);
+ else
+ Driver->addFile(Saver.save(Config->Sysroot + "/" + S.substr(1)),
+ /*WithLOption=*/false);
+ } else if (S.startswith("-l")) {
+ Driver->addLibrary(S.substr(2));
+ } else if (sys::fs::exists(S)) {
+ Driver->addFile(S, /*WithLOption=*/false);
+ } else {
+ if (Optional<std::string> Path = findFromSearchPaths(S))
+ Driver->addFile(Saver.save(*Path), /*WithLOption=*/true);
+ else
+ setError("unable to find " + S);
+ }
+}
+
+void ScriptParser::readAsNeeded() {
+ expect("(");
+ bool Orig = Config->AsNeeded;
+ Config->AsNeeded = true;
+ while (!errorCount() && !consume(")"))
+ addFile(unquote(next()));
+ Config->AsNeeded = Orig;
+}
+
+void ScriptParser::readEntry() {
+ // -e <symbol> takes predecence over ENTRY(<symbol>).
+ expect("(");
+ StringRef Tok = next();
+ if (Config->Entry.empty())
+ Config->Entry = Tok;
+ expect(")");
+}
+
+void ScriptParser::readExtern() {
+ expect("(");
+ while (!errorCount() && !consume(")"))
+ Config->Undefined.push_back(next());
+}
+
+void ScriptParser::readGroup() {
+ bool Orig = InputFile::IsInGroup;
+ InputFile::IsInGroup = true;
+ readInput();
+ InputFile::IsInGroup = Orig;
+ if (!Orig)
+ ++InputFile::NextGroupId;
+}
+
+void ScriptParser::readInclude() {
+ StringRef Tok = unquote(next());
+
+ if (!Seen.insert(Tok).second) {
+ setError("there is a cycle in linker script INCLUDEs");
+ return;
+ }
+
+ if (Optional<std::string> Path = searchScript(Tok)) {
+ if (Optional<MemoryBufferRef> MB = readFile(*Path))
+ tokenize(*MB);
+ return;
+ }
+ setError("cannot find linker script " + Tok);
+}
+
+void ScriptParser::readInput() {
+ expect("(");
+ while (!errorCount() && !consume(")")) {
+ if (consume("AS_NEEDED"))
+ readAsNeeded();
+ else
+ addFile(unquote(next()));
+ }
+}
+
+void ScriptParser::readOutput() {
+ // -o <file> takes predecence over OUTPUT(<file>).
+ expect("(");
+ StringRef Tok = next();
+ if (Config->OutputFile.empty())
+ Config->OutputFile = unquote(Tok);
+ expect(")");
+}
+
+void ScriptParser::readOutputArch() {
+ // OUTPUT_ARCH is ignored for now.
+ expect("(");
+ while (!errorCount() && !consume(")"))
+ skip();
+}
+
+static std::pair<ELFKind, uint16_t> parseBfdName(StringRef S) {
+ return StringSwitch<std::pair<ELFKind, uint16_t>>(S)
+ .Case("elf32-i386", {ELF32LEKind, EM_386})
+ .Case("elf32-iamcu", {ELF32LEKind, EM_IAMCU})
+ .Case("elf32-littlearm", {ELF32LEKind, EM_ARM})
+ .Case("elf32-x86-64", {ELF32LEKind, EM_X86_64})
+ .Case("elf64-aarch64", {ELF64LEKind, EM_AARCH64})
+ .Case("elf64-littleaarch64", {ELF64LEKind, EM_AARCH64})
+ .Case("elf32-powerpc", {ELF32BEKind, EM_PPC})
+ .Case("elf64-powerpc", {ELF64BEKind, EM_PPC64})
+ .Case("elf64-powerpcle", {ELF64LEKind, EM_PPC64})
+ .Case("elf64-x86-64", {ELF64LEKind, EM_X86_64})
+ .Cases("elf32-tradbigmips", "elf32-bigmips", {ELF32BEKind, EM_MIPS})
+ .Case("elf32-ntradbigmips", {ELF32BEKind, EM_MIPS})
+ .Case("elf32-tradlittlemips", {ELF32LEKind, EM_MIPS})
+ .Case("elf32-ntradlittlemips", {ELF32LEKind, EM_MIPS})
+ .Case("elf64-tradbigmips", {ELF64BEKind, EM_MIPS})
+ .Case("elf64-tradlittlemips", {ELF64LEKind, EM_MIPS})
+ .Default({ELFNoneKind, EM_NONE});
+}
+
+// Parse OUTPUT_FORMAT(bfdname) or OUTPUT_FORMAT(bfdname, big, little).
+// Currently we ignore big and little parameters.
+void ScriptParser::readOutputFormat() {
+ expect("(");
+
+ StringRef Name = unquote(next());
+ StringRef S = Name;
+ if (S.consume_back("-freebsd"))
+ Config->OSABI = ELFOSABI_FREEBSD;
+
+ std::tie(Config->EKind, Config->EMachine) = parseBfdName(S);
+ if (Config->EMachine == EM_NONE)
+ setError("unknown output format name: " + Name);
+ if (S == "elf32-ntradlittlemips" || S == "elf32-ntradbigmips")
+ Config->MipsN32Abi = true;
+
+ if (consume(")"))
+ return;
+ expect(",");
+ skip();
+ expect(",");
+ skip();
+ expect(")");
+}
+
+void ScriptParser::readPhdrs() {
+ expect("{");
+
+ while (!errorCount() && !consume("}")) {
+ PhdrsCommand Cmd;
+ Cmd.Name = next();
+ Cmd.Type = readPhdrType();
+
+ while (!errorCount() && !consume(";")) {
+ if (consume("FILEHDR"))
+ Cmd.HasFilehdr = true;
+ else if (consume("PHDRS"))
+ Cmd.HasPhdrs = true;
+ else if (consume("AT"))
+ Cmd.LMAExpr = readParenExpr();
+ else if (consume("FLAGS"))
+ Cmd.Flags = readParenExpr()().getValue();
+ else
+ setError("unexpected header attribute: " + next());
+ }
+
+ Script->PhdrsCommands.push_back(Cmd);
+ }
+}
+
+void ScriptParser::readRegionAlias() {
+ expect("(");
+ StringRef Alias = unquote(next());
+ expect(",");
+ StringRef Name = next();
+ expect(")");
+
+ if (Script->MemoryRegions.count(Alias))
+ setError("redefinition of memory region '" + Alias + "'");
+ if (!Script->MemoryRegions.count(Name))
+ setError("memory region '" + Name + "' is not defined");
+ Script->MemoryRegions.insert({Alias, Script->MemoryRegions[Name]});
+}
+
+void ScriptParser::readSearchDir() {
+ expect("(");
+ StringRef Tok = next();
+ if (!Config->Nostdlib)
+ Config->SearchPaths.push_back(unquote(Tok));
+ expect(")");
+}
+
+// This reads an overlay description. Overlays are used to describe output
+// sections that use the same virtual memory range and normally would trigger
+// linker's sections sanity check failures.
+// https://sourceware.org/binutils/docs/ld/Overlay-Description.html#Overlay-Description
+std::vector<BaseCommand *> ScriptParser::readOverlay() {
+ // VA and LMA expressions are optional, though for simplicity of
+ // implementation we assume they are not. That is what OVERLAY was designed
+ // for first of all: to allow sections with overlapping VAs at different LMAs.
+ Expr AddrExpr = readExpr();
+ expect(":");
+ expect("AT");
+ Expr LMAExpr = readParenExpr();
+ expect("{");
+
+ std::vector<BaseCommand *> V;
+ OutputSection *Prev = nullptr;
+ while (!errorCount() && !consume("}")) {
+ // VA is the same for all sections. The LMAs are consecutive in memory
+ // starting from the base load address specified.
+ OutputSection *OS = readOverlaySectionDescription();
+ OS->AddrExpr = AddrExpr;
+ if (Prev)
+ OS->LMAExpr = [=] { return Prev->getLMA() + Prev->Size; };
+ else
+ OS->LMAExpr = LMAExpr;
+ V.push_back(OS);
+ Prev = OS;
+ }
+
+ // According to the specification, at the end of the overlay, the location
+ // counter should be equal to the overlay base address plus size of the
+ // largest section seen in the overlay.
+ // Here we want to create the Dot assignment command to achieve that.
+ Expr MoveDot = [=] {
+ uint64_t Max = 0;
+ for (BaseCommand *Cmd : V)
+ Max = std::max(Max, cast<OutputSection>(Cmd)->Size);
+ return AddrExpr().getValue() + Max;
+ };
+ V.push_back(make<SymbolAssignment>(".", MoveDot, getCurrentLocation()));
+ return V;
+}
+
+void ScriptParser::readSections() {
+ Script->HasSectionsCommand = true;
+
+ // -no-rosegment is used to avoid placing read only non-executable sections in
+ // their own segment. We do the same if SECTIONS command is present in linker
+ // script. See comment for computeFlags().
+ Config->SingleRoRx = true;
+
+ expect("{");
+ std::vector<BaseCommand *> V;
+ while (!errorCount() && !consume("}")) {
+ StringRef Tok = next();
+ if (Tok == "OVERLAY") {
+ for (BaseCommand *Cmd : readOverlay())
+ V.push_back(Cmd);
+ continue;
+ } else if (Tok == "INCLUDE") {
+ readInclude();
+ continue;
+ }
+
+ if (BaseCommand *Cmd = readAssignment(Tok))
+ V.push_back(Cmd);
+ else
+ V.push_back(readOutputSectionDescription(Tok));
+ }
+
+ if (!atEOF() && consume("INSERT")) {
+ std::vector<BaseCommand *> *Dest = nullptr;
+ if (consume("AFTER"))
+ Dest = &Script->InsertAfterCommands[next()];
+ else if (consume("BEFORE"))
+ Dest = &Script->InsertBeforeCommands[next()];
+ else
+ setError("expected AFTER/BEFORE, but got '" + next() + "'");
+ if (Dest)
+ Dest->insert(Dest->end(), V.begin(), V.end());
+ return;
+ }
+
+ Script->SectionCommands.insert(Script->SectionCommands.end(), V.begin(),
+ V.end());
+}
+
+void ScriptParser::readTarget() {
+ // TARGET(foo) is an alias for "--format foo". Unlike GNU linkers,
+ // we accept only a limited set of BFD names (i.e. "elf" or "binary")
+ // for --format. We recognize only /^elf/ and "binary" in the linker
+ // script as well.
+ expect("(");
+ StringRef Tok = next();
+ expect(")");
+
+ if (Tok.startswith("elf"))
+ Config->FormatBinary = false;
+ else if (Tok == "binary")
+ Config->FormatBinary = true;
+ else
+ setError("unknown target: " + Tok);
+}
+
+static int precedence(StringRef Op) {
+ return StringSwitch<int>(Op)
+ .Cases("*", "/", "%", 8)
+ .Cases("+", "-", 7)
+ .Cases("<<", ">>", 6)
+ .Cases("<", "<=", ">", ">=", "==", "!=", 5)
+ .Case("&", 4)
+ .Case("|", 3)
+ .Case("&&", 2)
+ .Case("||", 1)
+ .Default(-1);
+}
+
+StringMatcher ScriptParser::readFilePatterns() {
+ std::vector<StringRef> V;
+ while (!errorCount() && !consume(")"))
+ V.push_back(next());
+ return StringMatcher(V);
+}
+
+SortSectionPolicy ScriptParser::readSortKind() {
+ if (consume("SORT") || consume("SORT_BY_NAME"))
+ return SortSectionPolicy::Name;
+ if (consume("SORT_BY_ALIGNMENT"))
+ return SortSectionPolicy::Alignment;
+ if (consume("SORT_BY_INIT_PRIORITY"))
+ return SortSectionPolicy::Priority;
+ if (consume("SORT_NONE"))
+ return SortSectionPolicy::None;
+ return SortSectionPolicy::Default;
+}
+
+// Reads SECTIONS command contents in the following form:
+//
+// <contents> ::= <elem>*
+// <elem> ::= <exclude>? <glob-pattern>
+// <exclude> ::= "EXCLUDE_FILE" "(" <glob-pattern>+ ")"
+//
+// For example,
+//
+// *(.foo EXCLUDE_FILE (a.o) .bar EXCLUDE_FILE (b.o) .baz)
+//
+// is parsed as ".foo", ".bar" with "a.o", and ".baz" with "b.o".
+// The semantics of that is section .foo in any file, section .bar in
+// any file but a.o, and section .baz in any file but b.o.
+std::vector<SectionPattern> ScriptParser::readInputSectionsList() {
+ std::vector<SectionPattern> Ret;
+ while (!errorCount() && peek() != ")") {
+ StringMatcher ExcludeFilePat;
+ if (consume("EXCLUDE_FILE")) {
+ expect("(");
+ ExcludeFilePat = readFilePatterns();
+ }
+
+ std::vector<StringRef> V;
+ while (!errorCount() && peek() != ")" && peek() != "EXCLUDE_FILE")
+ V.push_back(next());
+
+ if (!V.empty())
+ Ret.push_back({std::move(ExcludeFilePat), StringMatcher(V)});
+ else
+ setError("section pattern is expected");
+ }
+ return Ret;
+}
+
+// Reads contents of "SECTIONS" directive. That directive contains a
+// list of glob patterns for input sections. The grammar is as follows.
+//
+// <patterns> ::= <section-list>
+// | <sort> "(" <section-list> ")"
+// | <sort> "(" <sort> "(" <section-list> ")" ")"
+//
+// <sort> ::= "SORT" | "SORT_BY_NAME" | "SORT_BY_ALIGNMENT"
+// | "SORT_BY_INIT_PRIORITY" | "SORT_NONE"
+//
+// <section-list> is parsed by readInputSectionsList().
+InputSectionDescription *
+ScriptParser::readInputSectionRules(StringRef FilePattern) {
+ auto *Cmd = make<InputSectionDescription>(FilePattern);
+ expect("(");
+
+ while (!errorCount() && !consume(")")) {
+ SortSectionPolicy Outer = readSortKind();
+ SortSectionPolicy Inner = SortSectionPolicy::Default;
+ std::vector<SectionPattern> V;
+ if (Outer != SortSectionPolicy::Default) {
+ expect("(");
+ Inner = readSortKind();
+ if (Inner != SortSectionPolicy::Default) {
+ expect("(");
+ V = readInputSectionsList();
+ expect(")");
+ } else {
+ V = readInputSectionsList();
+ }
+ expect(")");
+ } else {
+ V = readInputSectionsList();
+ }
+
+ for (SectionPattern &Pat : V) {
+ Pat.SortInner = Inner;
+ Pat.SortOuter = Outer;
+ }
+
+ std::move(V.begin(), V.end(), std::back_inserter(Cmd->SectionPatterns));
+ }
+ return Cmd;
+}
+
+InputSectionDescription *
+ScriptParser::readInputSectionDescription(StringRef Tok) {
+ // Input section wildcard can be surrounded by KEEP.
+ // https://sourceware.org/binutils/docs/ld/Input-Section-Keep.html#Input-Section-Keep
+ if (Tok == "KEEP") {
+ expect("(");
+ StringRef FilePattern = next();
+ InputSectionDescription *Cmd = readInputSectionRules(FilePattern);
+ expect(")");
+ Script->KeptSections.push_back(Cmd);
+ return Cmd;
+ }
+ return readInputSectionRules(Tok);
+}
+
+void ScriptParser::readSort() {
+ expect("(");
+ expect("CONSTRUCTORS");
+ expect(")");
+}
+
+Expr ScriptParser::readAssert() {
+ expect("(");
+ Expr E = readExpr();
+ expect(",");
+ StringRef Msg = unquote(next());
+ expect(")");
+
+ return [=] {
+ if (!E().getValue())
+ error(Msg);
+ return Script->getDot();
+ };
+}
+
+// Reads a FILL(expr) command. We handle the FILL command as an
+// alias for =fillexp section attribute, which is different from
+// what GNU linkers do.
+// https://sourceware.org/binutils/docs/ld/Output-Section-Data.html
+std::array<uint8_t, 4> ScriptParser::readFill() {
+ expect("(");
+ std::array<uint8_t, 4> V = parseFill(next());
+ expect(")");
+ return V;
+}
+
+// Tries to read the special directive for an output section definition which
+// can be one of following: "(NOLOAD)", "(COPY)", "(INFO)" or "(OVERLAY)".
+// Tok1 and Tok2 are next 2 tokens peeked. See comment for readSectionAddressType below.
+bool ScriptParser::readSectionDirective(OutputSection *Cmd, StringRef Tok1, StringRef Tok2) {
+ if (Tok1 != "(")
+ return false;
+ if (Tok2 != "NOLOAD" && Tok2 != "COPY" && Tok2 != "INFO" && Tok2 != "OVERLAY")
+ return false;
+
+ expect("(");
+ if (consume("NOLOAD")) {
+ Cmd->Noload = true;
+ } else {
+ skip(); // This is "COPY", "INFO" or "OVERLAY".
+ Cmd->NonAlloc = true;
+ }
+ expect(")");
+ return true;
+}
+
+// Reads an expression and/or the special directive for an output
+// section definition. Directive is one of following: "(NOLOAD)",
+// "(COPY)", "(INFO)" or "(OVERLAY)".
+//
+// An output section name can be followed by an address expression
+// and/or directive. This grammar is not LL(1) because "(" can be
+// interpreted as either the beginning of some expression or beginning
+// of directive.
+//
+// https://sourceware.org/binutils/docs/ld/Output-Section-Address.html
+// https://sourceware.org/binutils/docs/ld/Output-Section-Type.html
+void ScriptParser::readSectionAddressType(OutputSection *Cmd) {
+ if (readSectionDirective(Cmd, peek(), peek2()))
+ return;
+
+ Cmd->AddrExpr = readExpr();
+ if (peek() == "(" && !readSectionDirective(Cmd, "(", peek2()))
+ setError("unknown section directive: " + peek2());
+}
+
+static Expr checkAlignment(Expr E, std::string &Loc) {
+ return [=] {
+ uint64_t Alignment = std::max((uint64_t)1, E().getValue());
+ if (!isPowerOf2_64(Alignment)) {
+ error(Loc + ": alignment must be power of 2");
+ return (uint64_t)1; // Return a dummy value.
+ }
+ return Alignment;
+ };
+}
+
+OutputSection *ScriptParser::readOverlaySectionDescription() {
+ OutputSection *Cmd =
+ Script->createOutputSection(next(), getCurrentLocation());
+ Cmd->InOverlay = true;
+ expect("{");
+ while (!errorCount() && !consume("}"))
+ Cmd->SectionCommands.push_back(readInputSectionRules(next()));
+ Cmd->Phdrs = readOutputSectionPhdrs();
+ return Cmd;
+}
+
+OutputSection *ScriptParser::readOutputSectionDescription(StringRef OutSec) {
+ OutputSection *Cmd =
+ Script->createOutputSection(OutSec, getCurrentLocation());
+
+ size_t SymbolsReferenced = Script->ReferencedSymbols.size();
+
+ if (peek() != ":")
+ readSectionAddressType(Cmd);
+ expect(":");
+
+ std::string Location = getCurrentLocation();
+ if (consume("AT"))
+ Cmd->LMAExpr = readParenExpr();
+ if (consume("ALIGN"))
+ Cmd->AlignExpr = checkAlignment(readParenExpr(), Location);
+ if (consume("SUBALIGN"))
+ Cmd->SubalignExpr = checkAlignment(readParenExpr(), Location);
+
+ // Parse constraints.
+ if (consume("ONLY_IF_RO"))
+ Cmd->Constraint = ConstraintKind::ReadOnly;
+ if (consume("ONLY_IF_RW"))
+ Cmd->Constraint = ConstraintKind::ReadWrite;
+ expect("{");
+
+ while (!errorCount() && !consume("}")) {
+ StringRef Tok = next();
+ if (Tok == ";") {
+ // Empty commands are allowed. Do nothing here.
+ } else if (SymbolAssignment *Assign = readAssignment(Tok)) {
+ Cmd->SectionCommands.push_back(Assign);
+ } else if (ByteCommand *Data = readByteCommand(Tok)) {
+ Cmd->SectionCommands.push_back(Data);
+ } else if (Tok == "CONSTRUCTORS") {
+ // CONSTRUCTORS is a keyword to make the linker recognize C++ ctors/dtors
+ // by name. This is for very old file formats such as ECOFF/XCOFF.
+ // For ELF, we should ignore.
+ } else if (Tok == "FILL") {
+ Cmd->Filler = readFill();
+ } else if (Tok == "SORT") {
+ readSort();
+ } else if (Tok == "INCLUDE") {
+ readInclude();
+ } else if (peek() == "(") {
+ Cmd->SectionCommands.push_back(readInputSectionDescription(Tok));
+ } else {
+ // We have a file name and no input sections description. It is not a
+ // commonly used syntax, but still acceptable. In that case, all sections
+ // from the file will be included.
+ auto *ISD = make<InputSectionDescription>(Tok);
+ ISD->SectionPatterns.push_back({{}, StringMatcher({"*"})});
+ Cmd->SectionCommands.push_back(ISD);
+ }
+ }
+
+ if (consume(">"))
+ Cmd->MemoryRegionName = next();
+
+ if (consume("AT")) {
+ expect(">");
+ Cmd->LMARegionName = next();
+ }
+
+ if (Cmd->LMAExpr && !Cmd->LMARegionName.empty())
+ error("section can't have both LMA and a load region");
+
+ Cmd->Phdrs = readOutputSectionPhdrs();
+
+ if (consume("="))
+ Cmd->Filler = parseFill(next());
+ else if (peek().startswith("="))
+ Cmd->Filler = parseFill(next().drop_front());
+
+ // Consume optional comma following output section command.
+ consume(",");
+
+ if (Script->ReferencedSymbols.size() > SymbolsReferenced)
+ Cmd->ExpressionsUseSymbols = true;
+ return Cmd;
+}
+
+// Parses a given string as a octal/decimal/hexadecimal number and
+// returns it as a big-endian number. Used for `=<fillexp>`.
+// https://sourceware.org/binutils/docs/ld/Output-Section-Fill.html
+//
+// When reading a hexstring, ld.bfd handles it as a blob of arbitrary
+// size, while ld.gold always handles it as a 32-bit big-endian number.
+// We are compatible with ld.gold because it's easier to implement.
+std::array<uint8_t, 4> ScriptParser::parseFill(StringRef Tok) {
+ uint32_t V = 0;
+ if (!to_integer(Tok, V))
+ setError("invalid filler expression: " + Tok);
+
+ std::array<uint8_t, 4> Buf;
+ write32be(Buf.data(), V);
+ return Buf;
+}
+
+SymbolAssignment *ScriptParser::readProvideHidden(bool Provide, bool Hidden) {
+ expect("(");
+ SymbolAssignment *Cmd = readSymbolAssignment(next());
+ Cmd->Provide = Provide;
+ Cmd->Hidden = Hidden;
+ expect(")");
+ return Cmd;
+}
+
+SymbolAssignment *ScriptParser::readAssignment(StringRef Tok) {
+ // Assert expression returns Dot, so this is equal to ".=."
+ if (Tok == "ASSERT")
+ return make<SymbolAssignment>(".", readAssert(), getCurrentLocation());
+
+ size_t OldPos = Pos;
+ SymbolAssignment *Cmd = nullptr;
+ if (peek() == "=" || peek() == "+=")
+ Cmd = readSymbolAssignment(Tok);
+ else if (Tok == "PROVIDE")
+ Cmd = readProvideHidden(true, false);
+ else if (Tok == "HIDDEN")
+ Cmd = readProvideHidden(false, true);
+ else if (Tok == "PROVIDE_HIDDEN")
+ Cmd = readProvideHidden(true, true);
+
+ if (Cmd) {
+ Cmd->CommandString =
+ Tok.str() + " " +
+ llvm::join(Tokens.begin() + OldPos, Tokens.begin() + Pos, " ");
+ expect(";");
+ }
+ return Cmd;
+}
+
+SymbolAssignment *ScriptParser::readSymbolAssignment(StringRef Name) {
+ StringRef Op = next();
+ assert(Op == "=" || Op == "+=");
+ Expr E = readExpr();
+ if (Op == "+=") {
+ std::string Loc = getCurrentLocation();
+ E = [=] { return add(Script->getSymbolValue(Name, Loc), E()); };
+ }
+ return make<SymbolAssignment>(Name, E, getCurrentLocation());
+}
+
+// This is an operator-precedence parser to parse a linker
+// script expression.
+Expr ScriptParser::readExpr() {
+ // Our lexer is context-aware. Set the in-expression bit so that
+ // they apply different tokenization rules.
+ bool Orig = InExpr;
+ InExpr = true;
+ Expr E = readExpr1(readPrimary(), 0);
+ InExpr = Orig;
+ return E;
+}
+
+Expr ScriptParser::combine(StringRef Op, Expr L, Expr R) {
+ if (Op == "+")
+ return [=] { return add(L(), R()); };
+ if (Op == "-")
+ return [=] { return sub(L(), R()); };
+ if (Op == "*")
+ return [=] { return L().getValue() * R().getValue(); };
+ if (Op == "/") {
+ std::string Loc = getCurrentLocation();
+ return [=]() -> uint64_t {
+ if (uint64_t RV = R().getValue())
+ return L().getValue() / RV;
+ error(Loc + ": division by zero");
+ return 0;
+ };
+ }
+ if (Op == "%") {
+ std::string Loc = getCurrentLocation();
+ return [=]() -> uint64_t {
+ if (uint64_t RV = R().getValue())
+ return L().getValue() % RV;
+ error(Loc + ": modulo by zero");
+ return 0;
+ };
+ }
+ if (Op == "<<")
+ return [=] { return L().getValue() << R().getValue(); };
+ if (Op == ">>")
+ return [=] { return L().getValue() >> R().getValue(); };
+ if (Op == "<")
+ return [=] { return L().getValue() < R().getValue(); };
+ if (Op == ">")
+ return [=] { return L().getValue() > R().getValue(); };
+ if (Op == ">=")
+ return [=] { return L().getValue() >= R().getValue(); };
+ if (Op == "<=")
+ return [=] { return L().getValue() <= R().getValue(); };
+ if (Op == "==")
+ return [=] { return L().getValue() == R().getValue(); };
+ if (Op == "!=")
+ return [=] { return L().getValue() != R().getValue(); };
+ if (Op == "||")
+ return [=] { return L().getValue() || R().getValue(); };
+ if (Op == "&&")
+ return [=] { return L().getValue() && R().getValue(); };
+ if (Op == "&")
+ return [=] { return bitAnd(L(), R()); };
+ if (Op == "|")
+ return [=] { return bitOr(L(), R()); };
+ llvm_unreachable("invalid operator");
+}
+
+// This is a part of the operator-precedence parser. This function
+// assumes that the remaining token stream starts with an operator.
+Expr ScriptParser::readExpr1(Expr Lhs, int MinPrec) {
+ while (!atEOF() && !errorCount()) {
+ // Read an operator and an expression.
+ if (consume("?"))
+ return readTernary(Lhs);
+ StringRef Op1 = peek();
+ if (precedence(Op1) < MinPrec)
+ break;
+ skip();
+ Expr Rhs = readPrimary();
+
+ // Evaluate the remaining part of the expression first if the
+ // next operator has greater precedence than the previous one.
+ // For example, if we have read "+" and "3", and if the next
+ // operator is "*", then we'll evaluate 3 * ... part first.
+ while (!atEOF()) {
+ StringRef Op2 = peek();
+ if (precedence(Op2) <= precedence(Op1))
+ break;
+ Rhs = readExpr1(Rhs, precedence(Op2));
+ }
+
+ Lhs = combine(Op1, Lhs, Rhs);
+ }
+ return Lhs;
+}
+
+Expr ScriptParser::getPageSize() {
+ std::string Location = getCurrentLocation();
+ return [=]() -> uint64_t {
+ if (Target)
+ return Target->PageSize;
+ error(Location + ": unable to calculate page size");
+ return 4096; // Return a dummy value.
+ };
+}
+
+Expr ScriptParser::readConstant() {
+ StringRef S = readParenLiteral();
+ if (S == "COMMONPAGESIZE")
+ return getPageSize();
+ if (S == "MAXPAGESIZE")
+ return [] { return Config->MaxPageSize; };
+ setError("unknown constant: " + S);
+ return [] { return 0; };
+}
+
+// Parses Tok as an integer. It recognizes hexadecimal (prefixed with
+// "0x" or suffixed with "H") and decimal numbers. Decimal numbers may
+// have "K" (Ki) or "M" (Mi) suffixes.
+static Optional<uint64_t> parseInt(StringRef Tok) {
+ // Hexadecimal
+ uint64_t Val;
+ if (Tok.startswith_lower("0x")) {
+ if (!to_integer(Tok.substr(2), Val, 16))
+ return None;
+ return Val;
+ }
+ if (Tok.endswith_lower("H")) {
+ if (!to_integer(Tok.drop_back(), Val, 16))
+ return None;
+ return Val;
+ }
+
+ // Decimal
+ if (Tok.endswith_lower("K")) {
+ if (!to_integer(Tok.drop_back(), Val, 10))
+ return None;
+ return Val * 1024;
+ }
+ if (Tok.endswith_lower("M")) {
+ if (!to_integer(Tok.drop_back(), Val, 10))
+ return None;
+ return Val * 1024 * 1024;
+ }
+ if (!to_integer(Tok, Val, 10))
+ return None;
+ return Val;
+}
+
+ByteCommand *ScriptParser::readByteCommand(StringRef Tok) {
+ int Size = StringSwitch<int>(Tok)
+ .Case("BYTE", 1)
+ .Case("SHORT", 2)
+ .Case("LONG", 4)
+ .Case("QUAD", 8)
+ .Default(-1);
+ if (Size == -1)
+ return nullptr;
+
+ size_t OldPos = Pos;
+ Expr E = readParenExpr();
+ std::string CommandString =
+ Tok.str() + " " +
+ llvm::join(Tokens.begin() + OldPos, Tokens.begin() + Pos, " ");
+ return make<ByteCommand>(E, Size, CommandString);
+}
+
+StringRef ScriptParser::readParenLiteral() {
+ expect("(");
+ bool Orig = InExpr;
+ InExpr = false;
+ StringRef Tok = next();
+ InExpr = Orig;
+ expect(")");
+ return Tok;
+}
+
+static void checkIfExists(OutputSection *Cmd, StringRef Location) {
+ if (Cmd->Location.empty() && Script->ErrorOnMissingSection)
+ error(Location + ": undefined section " + Cmd->Name);
+}
+
+Expr ScriptParser::readPrimary() {
+ if (peek() == "(")
+ return readParenExpr();
+
+ if (consume("~")) {
+ Expr E = readPrimary();
+ return [=] { return ~E().getValue(); };
+ }
+ if (consume("!")) {
+ Expr E = readPrimary();
+ return [=] { return !E().getValue(); };
+ }
+ if (consume("-")) {
+ Expr E = readPrimary();
+ return [=] { return -E().getValue(); };
+ }
+
+ StringRef Tok = next();
+ std::string Location = getCurrentLocation();
+
+ // Built-in functions are parsed here.
+ // https://sourceware.org/binutils/docs/ld/Builtin-Functions.html.
+ if (Tok == "ABSOLUTE") {
+ Expr Inner = readParenExpr();
+ return [=] {
+ ExprValue I = Inner();
+ I.ForceAbsolute = true;
+ return I;
+ };
+ }
+ if (Tok == "ADDR") {
+ StringRef Name = readParenLiteral();
+ OutputSection *Sec = Script->getOrCreateOutputSection(Name);
+ return [=]() -> ExprValue {
+ checkIfExists(Sec, Location);
+ return {Sec, false, 0, Location};
+ };
+ }
+ if (Tok == "ALIGN") {
+ expect("(");
+ Expr E = readExpr();
+ if (consume(")")) {
+ E = checkAlignment(E, Location);
+ return [=] { return alignTo(Script->getDot(), E().getValue()); };
+ }
+ expect(",");
+ Expr E2 = checkAlignment(readExpr(), Location);
+ expect(")");
+ return [=] {
+ ExprValue V = E();
+ V.Alignment = E2().getValue();
+ return V;
+ };
+ }
+ if (Tok == "ALIGNOF") {
+ StringRef Name = readParenLiteral();
+ OutputSection *Cmd = Script->getOrCreateOutputSection(Name);
+ return [=] {
+ checkIfExists(Cmd, Location);
+ return Cmd->Alignment;
+ };
+ }
+ if (Tok == "ASSERT")
+ return readAssert();
+ if (Tok == "CONSTANT")
+ return readConstant();
+ if (Tok == "DATA_SEGMENT_ALIGN") {
+ expect("(");
+ Expr E = readExpr();
+ expect(",");
+ readExpr();
+ expect(")");
+ return [=] {
+ return alignTo(Script->getDot(), std::max((uint64_t)1, E().getValue()));
+ };
+ }
+ if (Tok == "DATA_SEGMENT_END") {
+ expect("(");
+ expect(".");
+ expect(")");
+ return [] { return Script->getDot(); };
+ }
+ if (Tok == "DATA_SEGMENT_RELRO_END") {
+ // GNU linkers implements more complicated logic to handle
+ // DATA_SEGMENT_RELRO_END. We instead ignore the arguments and
+ // just align to the next page boundary for simplicity.
+ expect("(");
+ readExpr();
+ expect(",");
+ readExpr();
+ expect(")");
+ Expr E = getPageSize();
+ return [=] { return alignTo(Script->getDot(), E().getValue()); };
+ }
+ if (Tok == "DEFINED") {
+ StringRef Name = readParenLiteral();
+ return [=] { return Symtab->find(Name) ? 1 : 0; };
+ }
+ if (Tok == "LENGTH") {
+ StringRef Name = readParenLiteral();
+ if (Script->MemoryRegions.count(Name) == 0) {
+ setError("memory region not defined: " + Name);
+ return [] { return 0; };
+ }
+ return [=] { return Script->MemoryRegions[Name]->Length; };
+ }
+ if (Tok == "LOADADDR") {
+ StringRef Name = readParenLiteral();
+ OutputSection *Cmd = Script->getOrCreateOutputSection(Name);
+ return [=] {
+ checkIfExists(Cmd, Location);
+ return Cmd->getLMA();
+ };
+ }
+ if (Tok == "MAX" || Tok == "MIN") {
+ expect("(");
+ Expr A = readExpr();
+ expect(",");
+ Expr B = readExpr();
+ expect(")");
+ if (Tok == "MIN")
+ return [=] { return std::min(A().getValue(), B().getValue()); };
+ return [=] { return std::max(A().getValue(), B().getValue()); };
+ }
+ if (Tok == "ORIGIN") {
+ StringRef Name = readParenLiteral();
+ if (Script->MemoryRegions.count(Name) == 0) {
+ setError("memory region not defined: " + Name);
+ return [] { return 0; };
+ }
+ return [=] { return Script->MemoryRegions[Name]->Origin; };
+ }
+ if (Tok == "SEGMENT_START") {
+ expect("(");
+ skip();
+ expect(",");
+ Expr E = readExpr();
+ expect(")");
+ return [=] { return E(); };
+ }
+ if (Tok == "SIZEOF") {
+ StringRef Name = readParenLiteral();
+ OutputSection *Cmd = Script->getOrCreateOutputSection(Name);
+ // Linker script does not create an output section if its content is empty.
+ // We want to allow SIZEOF(.foo) where .foo is a section which happened to
+ // be empty.
+ return [=] { return Cmd->Size; };
+ }
+ if (Tok == "SIZEOF_HEADERS")
+ return [=] { return elf::getHeaderSize(); };
+
+ // Tok is the dot.
+ if (Tok == ".")
+ return [=] { return Script->getSymbolValue(Tok, Location); };
+
+ // Tok is a literal number.
+ if (Optional<uint64_t> Val = parseInt(Tok))
+ return [=] { return *Val; };
+
+ // Tok is a symbol name.
+ if (!isValidCIdentifier(Tok))
+ setError("malformed number: " + Tok);
+ Script->ReferencedSymbols.push_back(Tok);
+ return [=] { return Script->getSymbolValue(Tok, Location); };
+}
+
+Expr ScriptParser::readTernary(Expr Cond) {
+ Expr L = readExpr();
+ expect(":");
+ Expr R = readExpr();
+ return [=] { return Cond().getValue() ? L() : R(); };
+}
+
+Expr ScriptParser::readParenExpr() {
+ expect("(");
+ Expr E = readExpr();
+ expect(")");
+ return E;
+}
+
+std::vector<StringRef> ScriptParser::readOutputSectionPhdrs() {
+ std::vector<StringRef> Phdrs;
+ while (!errorCount() && peek().startswith(":")) {
+ StringRef Tok = next();
+ Phdrs.push_back((Tok.size() == 1) ? next() : Tok.substr(1));
+ }
+ return Phdrs;
+}
+
+// Read a program header type name. The next token must be a
+// name of a program header type or a constant (e.g. "0x3").
+unsigned ScriptParser::readPhdrType() {
+ StringRef Tok = next();
+ if (Optional<uint64_t> Val = parseInt(Tok))
+ return *Val;
+
+ unsigned Ret = StringSwitch<unsigned>(Tok)
+ .Case("PT_NULL", PT_NULL)
+ .Case("PT_LOAD", PT_LOAD)
+ .Case("PT_DYNAMIC", PT_DYNAMIC)
+ .Case("PT_INTERP", PT_INTERP)
+ .Case("PT_NOTE", PT_NOTE)
+ .Case("PT_SHLIB", PT_SHLIB)
+ .Case("PT_PHDR", PT_PHDR)
+ .Case("PT_TLS", PT_TLS)
+ .Case("PT_GNU_EH_FRAME", PT_GNU_EH_FRAME)
+ .Case("PT_GNU_STACK", PT_GNU_STACK)
+ .Case("PT_GNU_RELRO", PT_GNU_RELRO)
+ .Case("PT_OPENBSD_RANDOMIZE", PT_OPENBSD_RANDOMIZE)
+ .Case("PT_OPENBSD_WXNEEDED", PT_OPENBSD_WXNEEDED)
+ .Case("PT_OPENBSD_BOOTDATA", PT_OPENBSD_BOOTDATA)
+ .Default(-1);
+
+ if (Ret == (unsigned)-1) {
+ setError("invalid program header type: " + Tok);
+ return PT_NULL;
+ }
+ return Ret;
+}
+
+// Reads an anonymous version declaration.
+void ScriptParser::readAnonymousDeclaration() {
+ std::vector<SymbolVersion> Locals;
+ std::vector<SymbolVersion> Globals;
+ std::tie(Locals, Globals) = readSymbols();
+
+ for (SymbolVersion V : Locals) {
+ if (V.Name == "*")
+ Config->DefaultSymbolVersion = VER_NDX_LOCAL;
+ else
+ Config->VersionScriptLocals.push_back(V);
+ }
+
+ for (SymbolVersion V : Globals)
+ Config->VersionScriptGlobals.push_back(V);
+
+ expect(";");
+}
+
+// Reads a non-anonymous version definition,
+// e.g. "VerStr { global: foo; bar; local: *; };".
+void ScriptParser::readVersionDeclaration(StringRef VerStr) {
+ // Read a symbol list.
+ std::vector<SymbolVersion> Locals;
+ std::vector<SymbolVersion> Globals;
+ std::tie(Locals, Globals) = readSymbols();
+
+ for (SymbolVersion V : Locals) {
+ if (V.Name == "*")
+ Config->DefaultSymbolVersion = VER_NDX_LOCAL;
+ else
+ Config->VersionScriptLocals.push_back(V);
+ }
+
+ // Create a new version definition and add that to the global symbols.
+ VersionDefinition Ver;
+ Ver.Name = VerStr;
+ Ver.Globals = Globals;
+
+ // User-defined version number starts from 2 because 0 and 1 are
+ // reserved for VER_NDX_LOCAL and VER_NDX_GLOBAL, respectively.
+ Ver.Id = Config->VersionDefinitions.size() + 2;
+ Config->VersionDefinitions.push_back(Ver);
+
+ // Each version may have a parent version. For example, "Ver2"
+ // defined as "Ver2 { global: foo; local: *; } Ver1;" has "Ver1"
+ // as a parent. This version hierarchy is, probably against your
+ // instinct, purely for hint; the runtime doesn't care about it
+ // at all. In LLD, we simply ignore it.
+ if (peek() != ";")
+ skip();
+ expect(";");
+}
+
+static bool hasWildcard(StringRef S) {
+ return S.find_first_of("?*[") != StringRef::npos;
+}
+
+// Reads a list of symbols, e.g. "{ global: foo; bar; local: *; };".
+std::pair<std::vector<SymbolVersion>, std::vector<SymbolVersion>>
+ScriptParser::readSymbols() {
+ std::vector<SymbolVersion> Locals;
+ std::vector<SymbolVersion> Globals;
+ std::vector<SymbolVersion> *V = &Globals;
+
+ while (!errorCount()) {
+ if (consume("}"))
+ break;
+ if (consumeLabel("local")) {
+ V = &Locals;
+ continue;
+ }
+ if (consumeLabel("global")) {
+ V = &Globals;
+ continue;
+ }
+
+ if (consume("extern")) {
+ std::vector<SymbolVersion> Ext = readVersionExtern();
+ V->insert(V->end(), Ext.begin(), Ext.end());
+ } else {
+ StringRef Tok = next();
+ V->push_back({unquote(Tok), false, hasWildcard(Tok)});
+ }
+ expect(";");
+ }
+ return {Locals, Globals};
+}
+
+// Reads an "extern C++" directive, e.g.,
+// "extern "C++" { ns::*; "f(int, double)"; };"
+//
+// The last semicolon is optional. E.g. this is OK:
+// "extern "C++" { ns::*; "f(int, double)" };"
+std::vector<SymbolVersion> ScriptParser::readVersionExtern() {
+ StringRef Tok = next();
+ bool IsCXX = Tok == "\"C++\"";
+ if (!IsCXX && Tok != "\"C\"")
+ setError("Unknown language");
+ expect("{");
+
+ std::vector<SymbolVersion> Ret;
+ while (!errorCount() && peek() != "}") {
+ StringRef Tok = next();
+ bool HasWildcard = !Tok.startswith("\"") && hasWildcard(Tok);
+ Ret.push_back({unquote(Tok), IsCXX, HasWildcard});
+ if (consume("}"))
+ return Ret;
+ expect(";");
+ }
+
+ expect("}");
+ return Ret;
+}
+
+uint64_t ScriptParser::readMemoryAssignment(StringRef S1, StringRef S2,
+ StringRef S3) {
+ if (!consume(S1) && !consume(S2) && !consume(S3)) {
+ setError("expected one of: " + S1 + ", " + S2 + ", or " + S3);
+ return 0;
+ }
+ expect("=");
+ return readExpr()().getValue();
+}
+
+// Parse the MEMORY command as specified in:
+// https://sourceware.org/binutils/docs/ld/MEMORY.html
+//
+// MEMORY { name [(attr)] : ORIGIN = origin, LENGTH = len ... }
+void ScriptParser::readMemory() {
+ expect("{");
+ while (!errorCount() && !consume("}")) {
+ StringRef Tok = next();
+ if (Tok == "INCLUDE") {
+ readInclude();
+ continue;
+ }
+
+ uint32_t Flags = 0;
+ uint32_t NegFlags = 0;
+ if (consume("(")) {
+ std::tie(Flags, NegFlags) = readMemoryAttributes();
+ expect(")");
+ }
+ expect(":");
+
+ uint64_t Origin = readMemoryAssignment("ORIGIN", "org", "o");
+ expect(",");
+ uint64_t Length = readMemoryAssignment("LENGTH", "len", "l");
+
+ // Add the memory region to the region map.
+ MemoryRegion *MR = make<MemoryRegion>(Tok, Origin, Length, Flags, NegFlags);
+ if (!Script->MemoryRegions.insert({Tok, MR}).second)
+ setError("region '" + Tok + "' already defined");
+ }
+}
+
+// This function parses the attributes used to match against section
+// flags when placing output sections in a memory region. These flags
+// are only used when an explicit memory region name is not used.
+std::pair<uint32_t, uint32_t> ScriptParser::readMemoryAttributes() {
+ uint32_t Flags = 0;
+ uint32_t NegFlags = 0;
+ bool Invert = false;
+
+ for (char C : next().lower()) {
+ uint32_t Flag = 0;
+ if (C == '!')
+ Invert = !Invert;
+ else if (C == 'w')
+ Flag = SHF_WRITE;
+ else if (C == 'x')
+ Flag = SHF_EXECINSTR;
+ else if (C == 'a')
+ Flag = SHF_ALLOC;
+ else if (C != 'r')
+ setError("invalid memory region attribute");
+
+ if (Invert)
+ NegFlags |= Flag;
+ else
+ Flags |= Flag;
+ }
+ return {Flags, NegFlags};
+}
+
+void elf::readLinkerScript(MemoryBufferRef MB) {
+ ScriptParser(MB).readLinkerScript();
+}
+
+void elf::readVersionScript(MemoryBufferRef MB) {
+ ScriptParser(MB).readVersionScript();
+}
+
+void elf::readDynamicList(MemoryBufferRef MB) {
+ ScriptParser(MB).readDynamicList();
+}
+
+void elf::readDefsym(StringRef Name, MemoryBufferRef MB) {
+ ScriptParser(MB).readDefsym(Name);
+}
diff --git a/contrib/llvm/tools/lld/ELF/ScriptParser.h b/contrib/llvm/tools/lld/ELF/ScriptParser.h
new file mode 100644
index 000000000000..d48d5aa2115e
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/ScriptParser.h
@@ -0,0 +1,34 @@
+//===- ScriptParser.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_SCRIPT_PARSER_H
+#define LLD_ELF_SCRIPT_PARSER_H
+
+#include "lld/Common/LLVM.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+namespace lld {
+namespace elf {
+
+// Parses a linker script. Calling this function updates
+// Config and ScriptConfig.
+void readLinkerScript(MemoryBufferRef MB);
+
+// Parses a version script.
+void readVersionScript(MemoryBufferRef MB);
+
+void readDynamicList(MemoryBufferRef MB);
+
+// Parses the defsym expression.
+void readDefsym(StringRef Name, MemoryBufferRef MB);
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/ELF/SymbolTable.cpp b/contrib/llvm/tools/lld/ELF/SymbolTable.cpp
new file mode 100644
index 000000000000..7615e12199fa
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/SymbolTable.cpp
@@ -0,0 +1,817 @@
+//===- SymbolTable.cpp ----------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Symbol table is a bag of all known symbols. We put all symbols of
+// all input files to the symbol table. The symbol table is basically
+// a hash table with the logic to resolve symbol name conflicts using
+// the symbol types.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolTable.h"
+#include "Config.h"
+#include "LinkerScript.h"
+#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Memory.h"
+#include "lld/Common/Strings.h"
+#include "llvm/ADT/STLExtras.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::ELF;
+
+using namespace lld;
+using namespace lld::elf;
+
+SymbolTable *elf::Symtab;
+
+static InputFile *getFirstElf() {
+ if (!ObjectFiles.empty())
+ return ObjectFiles[0];
+ if (!SharedFiles.empty())
+ return SharedFiles[0];
+ return BitcodeFiles[0];
+}
+
+// All input object files must be for the same architecture
+// (e.g. it does not make sense to link x86 object files with
+// MIPS object files.) This function checks for that error.
+static bool isCompatible(InputFile *F) {
+ if (!F->isElf() && !isa<BitcodeFile>(F))
+ return true;
+
+ if (F->EKind == Config->EKind && F->EMachine == Config->EMachine) {
+ if (Config->EMachine != EM_MIPS)
+ return true;
+ if (isMipsN32Abi(F) == Config->MipsN32Abi)
+ return true;
+ }
+
+ if (!Config->Emulation.empty())
+ error(toString(F) + " is incompatible with " + Config->Emulation);
+ else
+ error(toString(F) + " is incompatible with " + toString(getFirstElf()));
+ return false;
+}
+
+// Add symbols in File to the symbol table.
+template <class ELFT> void SymbolTable::addFile(InputFile *File) {
+ if (!isCompatible(File))
+ return;
+
+ // Binary file
+ if (auto *F = dyn_cast<BinaryFile>(File)) {
+ BinaryFiles.push_back(F);
+ F->parse();
+ return;
+ }
+
+ // .a file
+ if (auto *F = dyn_cast<ArchiveFile>(File)) {
+ F->parse<ELFT>();
+ return;
+ }
+
+ // Lazy object file
+ if (auto *F = dyn_cast<LazyObjFile>(File)) {
+ LazyObjFiles.push_back(F);
+ F->parse<ELFT>();
+ return;
+ }
+
+ if (Config->Trace)
+ message(toString(File));
+
+ // .so file
+ if (auto *F = dyn_cast<SharedFile<ELFT>>(File)) {
+ // DSOs are uniquified not by filename but by soname.
+ F->parseSoName();
+ if (errorCount())
+ return;
+
+ // If a DSO appears more than once on the command line with and without
+ // --as-needed, --no-as-needed takes precedence over --as-needed because a
+ // user can add an extra DSO with --no-as-needed to force it to be added to
+ // the dependency list.
+ DenseMap<StringRef, InputFile *>::iterator It;
+ bool WasInserted;
+ std::tie(It, WasInserted) = SoNames.try_emplace(F->SoName, F);
+ cast<SharedFile<ELFT>>(It->second)->IsNeeded |= F->IsNeeded;
+ if (!WasInserted)
+ return;
+
+ SharedFiles.push_back(F);
+ F->parseRest();
+ return;
+ }
+
+ // LLVM bitcode file
+ if (auto *F = dyn_cast<BitcodeFile>(File)) {
+ BitcodeFiles.push_back(F);
+ F->parse<ELFT>(ComdatGroups);
+ return;
+ }
+
+ // Regular object file
+ ObjectFiles.push_back(File);
+ cast<ObjFile<ELFT>>(File)->parse(ComdatGroups);
+}
+
+// This function is where all the optimizations of link-time
+// optimization happens. When LTO is in use, some input files are
+// not in native object file format but in the LLVM bitcode format.
+// This function compiles bitcode files into a few big native files
+// using LLVM functions and replaces bitcode symbols with the results.
+// Because all bitcode files that the program consists of are passed
+// to the compiler at once, it can do whole-program optimization.
+template <class ELFT> void SymbolTable::addCombinedLTOObject() {
+ if (BitcodeFiles.empty())
+ return;
+
+ // Compile bitcode files and replace bitcode symbols.
+ LTO.reset(new BitcodeCompiler);
+ for (BitcodeFile *F : BitcodeFiles)
+ LTO->add(*F);
+
+ for (InputFile *File : LTO->compile()) {
+ DenseSet<CachedHashStringRef> DummyGroups;
+ auto *Obj = cast<ObjFile<ELFT>>(File);
+ Obj->parse(DummyGroups);
+ for (Symbol *Sym : Obj->getGlobalSymbols())
+ Sym->parseSymbolVersion();
+ ObjectFiles.push_back(File);
+ }
+}
+
+// Set a flag for --trace-symbol so that we can print out a log message
+// if a new symbol with the same name is inserted into the symbol table.
+void SymbolTable::trace(StringRef Name) {
+ SymMap.insert({CachedHashStringRef(Name), -1});
+}
+
+void SymbolTable::wrap(Symbol *Sym, Symbol *Real, Symbol *Wrap) {
+ // Swap symbols as instructed by -wrap.
+ int &Idx1 = SymMap[CachedHashStringRef(Sym->getName())];
+ int &Idx2 = SymMap[CachedHashStringRef(Real->getName())];
+ int &Idx3 = SymMap[CachedHashStringRef(Wrap->getName())];
+
+ Idx2 = Idx1;
+ Idx1 = Idx3;
+
+ // Now renaming is complete. No one refers Real symbol. We could leave
+ // Real as-is, but if Real is written to the symbol table, that may
+ // contain irrelevant values. So, we copy all values from Sym to Real.
+ StringRef S = Real->getName();
+ memcpy(Real, Sym, sizeof(SymbolUnion));
+ Real->setName(S);
+}
+
+static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) {
+ if (VA == STV_DEFAULT)
+ return VB;
+ if (VB == STV_DEFAULT)
+ return VA;
+ return std::min(VA, VB);
+}
+
+// Find an existing symbol or create and insert a new one.
+std::pair<Symbol *, bool> SymbolTable::insertName(StringRef Name) {
+ // <name>@@<version> means the symbol is the default version. In that
+ // case <name>@@<version> will be used to resolve references to <name>.
+ //
+ // Since this is a hot path, the following string search code is
+ // optimized for speed. StringRef::find(char) is much faster than
+ // StringRef::find(StringRef).
+ size_t Pos = Name.find('@');
+ if (Pos != StringRef::npos && Pos + 1 < Name.size() && Name[Pos + 1] == '@')
+ Name = Name.take_front(Pos);
+
+ auto P = SymMap.insert({CachedHashStringRef(Name), (int)SymVector.size()});
+ int &SymIndex = P.first->second;
+ bool IsNew = P.second;
+ bool Traced = false;
+
+ if (SymIndex == -1) {
+ SymIndex = SymVector.size();
+ IsNew = true;
+ Traced = true;
+ }
+
+ if (!IsNew)
+ return {SymVector[SymIndex], false};
+
+ auto *Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
+ Sym->SymbolKind = Symbol::PlaceholderKind;
+ Sym->Visibility = STV_DEFAULT;
+ Sym->IsUsedInRegularObj = false;
+ Sym->ExportDynamic = false;
+ Sym->CanInline = true;
+ Sym->Traced = Traced;
+ Sym->VersionId = Config->DefaultSymbolVersion;
+ SymVector.push_back(Sym);
+ return {Sym, true};
+}
+
+// Find an existing symbol or create and insert a new one, then apply the given
+// attributes.
+std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name,
+ uint8_t Visibility,
+ bool CanOmitFromDynSym,
+ InputFile *File) {
+ Symbol *S;
+ bool WasInserted;
+ std::tie(S, WasInserted) = insertName(Name);
+
+ // Merge in the new symbol's visibility.
+ S->Visibility = getMinVisibility(S->Visibility, Visibility);
+
+ if (!CanOmitFromDynSym && (Config->Shared || Config->ExportDynamic))
+ S->ExportDynamic = true;
+
+ if (!File || File->kind() == InputFile::ObjKind)
+ S->IsUsedInRegularObj = true;
+
+ return {S, WasInserted};
+}
+
+static uint8_t getVisibility(uint8_t StOther) { return StOther & 3; }
+
+template <class ELFT>
+Symbol *SymbolTable::addUndefined(StringRef Name, uint8_t Binding,
+ uint8_t StOther, uint8_t Type,
+ bool CanOmitFromDynSym, InputFile *File) {
+ Symbol *S;
+ bool WasInserted;
+ uint8_t Visibility = getVisibility(StOther);
+ std::tie(S, WasInserted) = insert(Name, Visibility, CanOmitFromDynSym, File);
+
+ // An undefined symbol with non default visibility must be satisfied
+ // in the same DSO.
+ if (WasInserted || (isa<SharedSymbol>(S) && Visibility != STV_DEFAULT)) {
+ replaceSymbol<Undefined>(S, File, Name, Binding, StOther, Type);
+ return S;
+ }
+
+ if (S->isShared() || S->isLazy() || (S->isUndefined() && Binding != STB_WEAK))
+ S->Binding = Binding;
+
+ if (S->isLazy()) {
+ // An undefined weak will not fetch archive members. See comment on Lazy in
+ // Symbols.h for the details.
+ if (Binding == STB_WEAK) {
+ S->Type = Type;
+ return S;
+ }
+
+ // Do extra check for --warn-backrefs.
+ //
+ // --warn-backrefs is an option to prevent an undefined reference from
+ // fetching an archive member written earlier in the command line. It can be
+ // used to keep compatibility with GNU linkers to some degree.
+ // I'll explain the feature and why you may find it useful in this comment.
+ //
+ // lld's symbol resolution semantics is more relaxed than traditional Unix
+ // linkers. For example,
+ //
+ // ld.lld foo.a bar.o
+ //
+ // succeeds even if bar.o contains an undefined symbol that has to be
+ // resolved by some object file in foo.a. Traditional Unix linkers don't
+ // allow this kind of backward reference, as they visit each file only once
+ // from left to right in the command line while resolving all undefined
+ // symbols at the moment of visiting.
+ //
+ // In the above case, since there's no undefined symbol when a linker visits
+ // foo.a, no files are pulled out from foo.a, and because the linker forgets
+ // about foo.a after visiting, it can't resolve undefined symbols in bar.o
+ // that could have been resolved otherwise.
+ //
+ // That lld accepts more relaxed form means that (besides it'd make more
+ // sense) you can accidentally write a command line or a build file that
+ // works only with lld, even if you have a plan to distribute it to wider
+ // users who may be using GNU linkers. With --warn-backrefs, you can detect
+ // a library order that doesn't work with other Unix linkers.
+ //
+ // The option is also useful to detect cyclic dependencies between static
+ // archives. Again, lld accepts
+ //
+ // ld.lld foo.a bar.a
+ //
+ // even if foo.a and bar.a depend on each other. With --warn-backrefs, it is
+ // handled as an error.
+ //
+ // Here is how the option works. We assign a group ID to each file. A file
+ // with a smaller group ID can pull out object files from an archive file
+ // with an equal or greater group ID. Otherwise, it is a reverse dependency
+ // and an error.
+ //
+ // A file outside --{start,end}-group gets a fresh ID when instantiated. All
+ // files within the same --{start,end}-group get the same group ID. E.g.
+ //
+ // ld.lld A B --start-group C D --end-group E
+ //
+ // A forms group 0. B form group 1. C and D (including their member object
+ // files) form group 2. E forms group 3. I think that you can see how this
+ // group assignment rule simulates the traditional linker's semantics.
+ bool Backref =
+ Config->WarnBackrefs && File && S->File->GroupId < File->GroupId;
+ fetchLazy<ELFT>(S);
+
+ // We don't report backward references to weak symbols as they can be
+ // overridden later.
+ if (Backref && S->Binding != STB_WEAK)
+ warn("backward reference detected: " + Name + " in " + toString(File) +
+ " refers to " + toString(S->File));
+ }
+ return S;
+}
+
+// Using .symver foo,foo@@VER unfortunately creates two symbols: foo and
+// foo@@VER. We want to effectively ignore foo, so give precedence to
+// foo@@VER.
+// FIXME: If users can transition to using
+// .symver foo,foo@@@VER
+// we can delete this hack.
+static int compareVersion(Symbol *S, StringRef Name) {
+ bool A = Name.contains("@@");
+ bool B = S->getName().contains("@@");
+ if (A && !B)
+ return 1;
+ if (!A && B)
+ return -1;
+ return 0;
+}
+
+// We have a new defined symbol with the specified binding. Return 1 if the new
+// symbol should win, -1 if the new symbol should lose, or 0 if both symbols are
+// strong defined symbols.
+static int compareDefined(Symbol *S, bool WasInserted, uint8_t Binding,
+ StringRef Name) {
+ if (WasInserted)
+ return 1;
+ if (!S->isDefined())
+ return 1;
+ if (int R = compareVersion(S, Name))
+ return R;
+ if (Binding == STB_WEAK)
+ return -1;
+ if (S->isWeak())
+ return 1;
+ return 0;
+}
+
+// We have a new non-common defined symbol with the specified binding. Return 1
+// if the new symbol should win, -1 if the new symbol should lose, or 0 if there
+// is a conflict. If the new symbol wins, also update the binding.
+static int compareDefinedNonCommon(Symbol *S, bool WasInserted, uint8_t Binding,
+ bool IsAbsolute, uint64_t Value,
+ StringRef Name) {
+ if (int Cmp = compareDefined(S, WasInserted, Binding, Name))
+ return Cmp;
+ if (auto *R = dyn_cast<Defined>(S)) {
+ if (R->Section && isa<BssSection>(R->Section)) {
+ // Non-common symbols take precedence over common symbols.
+ if (Config->WarnCommon)
+ warn("common " + S->getName() + " is overridden");
+ return 1;
+ }
+ if (R->Section == nullptr && Binding == STB_GLOBAL && IsAbsolute &&
+ R->Value == Value)
+ return -1;
+ }
+ return 0;
+}
+
+Symbol *SymbolTable::addCommon(StringRef N, uint64_t Size, uint32_t Alignment,
+ uint8_t Binding, uint8_t StOther, uint8_t Type,
+ InputFile &File) {
+ Symbol *S;
+ bool WasInserted;
+ std::tie(S, WasInserted) = insert(N, getVisibility(StOther),
+ /*CanOmitFromDynSym*/ false, &File);
+
+ int Cmp = compareDefined(S, WasInserted, Binding, N);
+ if (Cmp < 0)
+ return S;
+
+ if (Cmp > 0) {
+ auto *Bss = make<BssSection>("COMMON", Size, Alignment);
+ Bss->File = &File;
+ Bss->Live = !Config->GcSections;
+ InputSections.push_back(Bss);
+
+ replaceSymbol<Defined>(S, &File, N, Binding, StOther, Type, 0, Size, Bss);
+ return S;
+ }
+
+ auto *D = cast<Defined>(S);
+ auto *Bss = dyn_cast_or_null<BssSection>(D->Section);
+ if (!Bss) {
+ // Non-common symbols take precedence over common symbols.
+ if (Config->WarnCommon)
+ warn("common " + S->getName() + " is overridden");
+ return S;
+ }
+
+ if (Config->WarnCommon)
+ warn("multiple common of " + D->getName());
+
+ Bss->Alignment = std::max(Bss->Alignment, Alignment);
+ if (Size > Bss->Size) {
+ D->File = Bss->File = &File;
+ D->Size = Bss->Size = Size;
+ }
+ return S;
+}
+
+static void reportDuplicate(Symbol *Sym, InputFile *NewFile,
+ InputSectionBase *ErrSec, uint64_t ErrOffset) {
+ if (Config->AllowMultipleDefinition)
+ return;
+
+ Defined *D = cast<Defined>(Sym);
+ if (!D->Section || !ErrSec) {
+ error("duplicate symbol: " + toString(*Sym) + "\n>>> defined in " +
+ toString(Sym->File) + "\n>>> defined in " + toString(NewFile));
+ return;
+ }
+
+ // Construct and print an error message in the form of:
+ //
+ // ld.lld: error: duplicate symbol: foo
+ // >>> defined at bar.c:30
+ // >>> bar.o (/home/alice/src/bar.o)
+ // >>> defined at baz.c:563
+ // >>> baz.o in archive libbaz.a
+ auto *Sec1 = cast<InputSectionBase>(D->Section);
+ std::string Src1 = Sec1->getSrcMsg(*Sym, D->Value);
+ std::string Obj1 = Sec1->getObjMsg(D->Value);
+ std::string Src2 = ErrSec->getSrcMsg(*Sym, ErrOffset);
+ std::string Obj2 = ErrSec->getObjMsg(ErrOffset);
+
+ std::string Msg = "duplicate symbol: " + toString(*Sym) + "\n>>> defined at ";
+ if (!Src1.empty())
+ Msg += Src1 + "\n>>> ";
+ Msg += Obj1 + "\n>>> defined at ";
+ if (!Src2.empty())
+ Msg += Src2 + "\n>>> ";
+ Msg += Obj2;
+ error(Msg);
+}
+
+Defined *SymbolTable::addDefined(StringRef Name, uint8_t StOther, uint8_t Type,
+ uint64_t Value, uint64_t Size, uint8_t Binding,
+ SectionBase *Section, InputFile *File) {
+ Symbol *S;
+ bool WasInserted;
+ std::tie(S, WasInserted) = insert(Name, getVisibility(StOther),
+ /*CanOmitFromDynSym*/ false, File);
+ int Cmp = compareDefinedNonCommon(S, WasInserted, Binding, Section == nullptr,
+ Value, Name);
+ if (Cmp > 0)
+ replaceSymbol<Defined>(S, File, Name, Binding, StOther, Type, Value, Size,
+ Section);
+ else if (Cmp == 0)
+ reportDuplicate(S, File, dyn_cast_or_null<InputSectionBase>(Section),
+ Value);
+ return cast<Defined>(S);
+}
+
+template <typename ELFT>
+void SymbolTable::addShared(StringRef Name, SharedFile<ELFT> &File,
+ const typename ELFT::Sym &Sym, uint32_t Alignment,
+ uint32_t VerdefIndex) {
+ // DSO symbols do not affect visibility in the output, so we pass STV_DEFAULT
+ // as the visibility, which will leave the visibility in the symbol table
+ // unchanged.
+ Symbol *S;
+ bool WasInserted;
+ std::tie(S, WasInserted) = insert(Name, STV_DEFAULT,
+ /*CanOmitFromDynSym*/ true, &File);
+ // Make sure we preempt DSO symbols with default visibility.
+ if (Sym.getVisibility() == STV_DEFAULT)
+ S->ExportDynamic = true;
+
+ // An undefined symbol with non default visibility must be satisfied
+ // in the same DSO.
+ auto Replace = [&](uint8_t Binding) {
+ replaceSymbol<SharedSymbol>(S, File, Name, Binding, Sym.st_other,
+ Sym.getType(), Sym.st_value, Sym.st_size,
+ Alignment, VerdefIndex);
+ };
+
+ if (WasInserted)
+ Replace(Sym.getBinding());
+ else if (S->Visibility == STV_DEFAULT && (S->isUndefined() || S->isLazy()))
+ Replace(S->Binding);
+}
+
+Symbol *SymbolTable::addBitcode(StringRef Name, uint8_t Binding,
+ uint8_t StOther, uint8_t Type,
+ bool CanOmitFromDynSym, BitcodeFile &F) {
+ Symbol *S;
+ bool WasInserted;
+ std::tie(S, WasInserted) =
+ insert(Name, getVisibility(StOther), CanOmitFromDynSym, &F);
+ int Cmp = compareDefinedNonCommon(S, WasInserted, Binding,
+ /*IsAbs*/ false, /*Value*/ 0, Name);
+ if (Cmp > 0)
+ replaceSymbol<Defined>(S, &F, Name, Binding, StOther, Type, 0, 0, nullptr);
+ else if (Cmp == 0)
+ reportDuplicate(S, &F, nullptr, 0);
+ return S;
+}
+
+Symbol *SymbolTable::find(StringRef Name) {
+ auto It = SymMap.find(CachedHashStringRef(Name));
+ if (It == SymMap.end())
+ return nullptr;
+ if (It->second == -1)
+ return nullptr;
+ return SymVector[It->second];
+}
+
+template <class ELFT>
+void SymbolTable::addLazyArchive(StringRef Name, ArchiveFile &File,
+ const object::Archive::Symbol Sym) {
+ Symbol *S;
+ bool WasInserted;
+ std::tie(S, WasInserted) = insertName(Name);
+ if (WasInserted) {
+ replaceSymbol<LazyArchive>(S, File, STT_NOTYPE, Sym);
+ return;
+ }
+ if (!S->isUndefined())
+ return;
+
+ // An undefined weak will not fetch archive members. See comment on Lazy in
+ // Symbols.h for the details.
+ if (S->isWeak()) {
+ replaceSymbol<LazyArchive>(S, File, S->Type, Sym);
+ S->Binding = STB_WEAK;
+ return;
+ }
+
+ if (InputFile *F = File.fetch(Sym))
+ addFile<ELFT>(F);
+}
+
+template <class ELFT>
+void SymbolTable::addLazyObject(StringRef Name, LazyObjFile &File) {
+ Symbol *S;
+ bool WasInserted;
+ std::tie(S, WasInserted) = insertName(Name);
+ if (WasInserted) {
+ replaceSymbol<LazyObject>(S, File, STT_NOTYPE, Name);
+ return;
+ }
+ if (!S->isUndefined())
+ return;
+
+ // An undefined weak will not fetch archive members. See comment on Lazy in
+ // Symbols.h for the details.
+ if (S->isWeak()) {
+ replaceSymbol<LazyObject>(S, File, S->Type, Name);
+ S->Binding = STB_WEAK;
+ return;
+ }
+
+ if (InputFile *F = File.fetch())
+ addFile<ELFT>(F);
+}
+
+template <class ELFT> void SymbolTable::fetchLazy(Symbol *Sym) {
+ if (auto *S = dyn_cast<LazyArchive>(Sym)) {
+ if (InputFile *File = S->fetch())
+ addFile<ELFT>(File);
+ return;
+ }
+
+ auto *S = cast<LazyObject>(Sym);
+ if (InputFile *File = cast<LazyObjFile>(S->File)->fetch())
+ addFile<ELFT>(File);
+}
+
+// Initialize DemangledSyms with a map from demangled symbols to symbol
+// objects. Used to handle "extern C++" directive in version scripts.
+//
+// The map will contain all demangled symbols. That can be very large,
+// and in LLD we generally want to avoid do anything for each symbol.
+// Then, why are we doing this? Here's why.
+//
+// Users can use "extern C++ {}" directive to match against demangled
+// C++ symbols. For example, you can write a pattern such as
+// "llvm::*::foo(int, ?)". Obviously, there's no way to handle this
+// other than trying to match a pattern against all demangled symbols.
+// So, if "extern C++" feature is used, we need to demangle all known
+// symbols.
+StringMap<std::vector<Symbol *>> &SymbolTable::getDemangledSyms() {
+ if (!DemangledSyms) {
+ DemangledSyms.emplace();
+ for (Symbol *Sym : SymVector) {
+ if (!Sym->isDefined())
+ continue;
+ if (Optional<std::string> S = demangleItanium(Sym->getName()))
+ (*DemangledSyms)[*S].push_back(Sym);
+ else
+ (*DemangledSyms)[Sym->getName()].push_back(Sym);
+ }
+ }
+ return *DemangledSyms;
+}
+
+std::vector<Symbol *> SymbolTable::findByVersion(SymbolVersion Ver) {
+ if (Ver.IsExternCpp)
+ return getDemangledSyms().lookup(Ver.Name);
+ if (Symbol *B = find(Ver.Name))
+ if (B->isDefined())
+ return {B};
+ return {};
+}
+
+std::vector<Symbol *> SymbolTable::findAllByVersion(SymbolVersion Ver) {
+ std::vector<Symbol *> Res;
+ StringMatcher M(Ver.Name);
+
+ if (Ver.IsExternCpp) {
+ for (auto &P : getDemangledSyms())
+ if (M.match(P.first()))
+ Res.insert(Res.end(), P.second.begin(), P.second.end());
+ return Res;
+ }
+
+ for (Symbol *Sym : SymVector)
+ if (Sym->isDefined() && M.match(Sym->getName()))
+ Res.push_back(Sym);
+ return Res;
+}
+
+// If there's only one anonymous version definition in a version
+// script file, the script does not actually define any symbol version,
+// but just specifies symbols visibilities.
+void SymbolTable::handleAnonymousVersion() {
+ for (SymbolVersion &Ver : Config->VersionScriptGlobals)
+ assignExactVersion(Ver, VER_NDX_GLOBAL, "global");
+ for (SymbolVersion &Ver : Config->VersionScriptGlobals)
+ assignWildcardVersion(Ver, VER_NDX_GLOBAL);
+ for (SymbolVersion &Ver : Config->VersionScriptLocals)
+ assignExactVersion(Ver, VER_NDX_LOCAL, "local");
+ for (SymbolVersion &Ver : Config->VersionScriptLocals)
+ assignWildcardVersion(Ver, VER_NDX_LOCAL);
+}
+
+// Handles -dynamic-list.
+void SymbolTable::handleDynamicList() {
+ for (SymbolVersion &Ver : Config->DynamicList) {
+ std::vector<Symbol *> Syms;
+ if (Ver.HasWildcard)
+ Syms = findAllByVersion(Ver);
+ else
+ Syms = findByVersion(Ver);
+
+ for (Symbol *B : Syms) {
+ if (!Config->Shared)
+ B->ExportDynamic = true;
+ else if (B->includeInDynsym())
+ B->IsPreemptible = true;
+ }
+ }
+}
+
+// Set symbol versions to symbols. This function handles patterns
+// containing no wildcard characters.
+void SymbolTable::assignExactVersion(SymbolVersion Ver, uint16_t VersionId,
+ StringRef VersionName) {
+ if (Ver.HasWildcard)
+ return;
+
+ // Get a list of symbols which we need to assign the version to.
+ std::vector<Symbol *> Syms = findByVersion(Ver);
+ if (Syms.empty()) {
+ if (!Config->UndefinedVersion)
+ error("version script assignment of '" + VersionName + "' to symbol '" +
+ Ver.Name + "' failed: symbol not defined");
+ return;
+ }
+
+ // Assign the version.
+ for (Symbol *Sym : Syms) {
+ // Skip symbols containing version info because symbol versions
+ // specified by symbol names take precedence over version scripts.
+ // See parseSymbolVersion().
+ if (Sym->getName().contains('@'))
+ continue;
+
+ if (Sym->VersionId != Config->DefaultSymbolVersion &&
+ Sym->VersionId != VersionId)
+ error("duplicate symbol '" + Ver.Name + "' in version script");
+ Sym->VersionId = VersionId;
+ }
+}
+
+void SymbolTable::assignWildcardVersion(SymbolVersion Ver, uint16_t VersionId) {
+ if (!Ver.HasWildcard)
+ return;
+
+ // Exact matching takes precendence over fuzzy matching,
+ // so we set a version to a symbol only if no version has been assigned
+ // to the symbol. This behavior is compatible with GNU.
+ for (Symbol *B : findAllByVersion(Ver))
+ if (B->VersionId == Config->DefaultSymbolVersion)
+ B->VersionId = VersionId;
+}
+
+// This function processes version scripts by updating VersionId
+// member of symbols.
+void SymbolTable::scanVersionScript() {
+ // Handle edge cases first.
+ handleAnonymousVersion();
+ handleDynamicList();
+
+ // Now we have version definitions, so we need to set version ids to symbols.
+ // Each version definition has a glob pattern, and all symbols that match
+ // with the pattern get that version.
+
+ // First, we assign versions to exact matching symbols,
+ // i.e. version definitions not containing any glob meta-characters.
+ for (VersionDefinition &V : Config->VersionDefinitions)
+ for (SymbolVersion &Ver : V.Globals)
+ assignExactVersion(Ver, V.Id, V.Name);
+
+ // Next, we assign versions to fuzzy matching symbols,
+ // i.e. version definitions containing glob meta-characters.
+ // Note that because the last match takes precedence over previous matches,
+ // we iterate over the definitions in the reverse order.
+ for (VersionDefinition &V : llvm::reverse(Config->VersionDefinitions))
+ for (SymbolVersion &Ver : V.Globals)
+ assignWildcardVersion(Ver, V.Id);
+
+ // Symbol themselves might know their versions because symbols
+ // can contain versions in the form of <name>@<version>.
+ // Let them parse and update their names to exclude version suffix.
+ for (Symbol *Sym : SymVector)
+ Sym->parseSymbolVersion();
+}
+
+template void SymbolTable::addFile<ELF32LE>(InputFile *);
+template void SymbolTable::addFile<ELF32BE>(InputFile *);
+template void SymbolTable::addFile<ELF64LE>(InputFile *);
+template void SymbolTable::addFile<ELF64BE>(InputFile *);
+
+template Symbol *SymbolTable::addUndefined<ELF32LE>(StringRef, uint8_t, uint8_t,
+ uint8_t, bool, InputFile *);
+template Symbol *SymbolTable::addUndefined<ELF32BE>(StringRef, uint8_t, uint8_t,
+ uint8_t, bool, InputFile *);
+template Symbol *SymbolTable::addUndefined<ELF64LE>(StringRef, uint8_t, uint8_t,
+ uint8_t, bool, InputFile *);
+template Symbol *SymbolTable::addUndefined<ELF64BE>(StringRef, uint8_t, uint8_t,
+ uint8_t, bool, InputFile *);
+
+template void SymbolTable::addCombinedLTOObject<ELF32LE>();
+template void SymbolTable::addCombinedLTOObject<ELF32BE>();
+template void SymbolTable::addCombinedLTOObject<ELF64LE>();
+template void SymbolTable::addCombinedLTOObject<ELF64BE>();
+
+template void
+SymbolTable::addLazyArchive<ELF32LE>(StringRef, ArchiveFile &,
+ const object::Archive::Symbol);
+template void
+SymbolTable::addLazyArchive<ELF32BE>(StringRef, ArchiveFile &,
+ const object::Archive::Symbol);
+template void
+SymbolTable::addLazyArchive<ELF64LE>(StringRef, ArchiveFile &,
+ const object::Archive::Symbol);
+template void
+SymbolTable::addLazyArchive<ELF64BE>(StringRef, ArchiveFile &,
+ const object::Archive::Symbol);
+
+template void SymbolTable::addLazyObject<ELF32LE>(StringRef, LazyObjFile &);
+template void SymbolTable::addLazyObject<ELF32BE>(StringRef, LazyObjFile &);
+template void SymbolTable::addLazyObject<ELF64LE>(StringRef, LazyObjFile &);
+template void SymbolTable::addLazyObject<ELF64BE>(StringRef, LazyObjFile &);
+
+template void SymbolTable::fetchLazy<ELF32LE>(Symbol *);
+template void SymbolTable::fetchLazy<ELF32BE>(Symbol *);
+template void SymbolTable::fetchLazy<ELF64LE>(Symbol *);
+template void SymbolTable::fetchLazy<ELF64BE>(Symbol *);
+
+template void SymbolTable::addShared<ELF32LE>(StringRef, SharedFile<ELF32LE> &,
+ const typename ELF32LE::Sym &,
+ uint32_t Alignment, uint32_t);
+template void SymbolTable::addShared<ELF32BE>(StringRef, SharedFile<ELF32BE> &,
+ const typename ELF32BE::Sym &,
+ uint32_t Alignment, uint32_t);
+template void SymbolTable::addShared<ELF64LE>(StringRef, SharedFile<ELF64LE> &,
+ const typename ELF64LE::Sym &,
+ uint32_t Alignment, uint32_t);
+template void SymbolTable::addShared<ELF64BE>(StringRef, SharedFile<ELF64BE> &,
+ const typename ELF64BE::Sym &,
+ uint32_t Alignment, uint32_t);
diff --git a/contrib/llvm/tools/lld/ELF/SymbolTable.h b/contrib/llvm/tools/lld/ELF/SymbolTable.h
new file mode 100644
index 000000000000..898185fc9612
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/SymbolTable.h
@@ -0,0 +1,127 @@
+//===- SymbolTable.h --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_SYMBOL_TABLE_H
+#define LLD_ELF_SYMBOL_TABLE_H
+
+#include "InputFiles.h"
+#include "LTO.h"
+#include "lld/Common/Strings.h"
+#include "llvm/ADT/CachedHashString.h"
+#include "llvm/ADT/DenseMap.h"
+
+namespace lld {
+namespace elf {
+class Defined;
+class SectionBase;
+
+// SymbolTable is a bucket of all known symbols, including defined,
+// undefined, or lazy symbols (the last one is symbols in archive
+// files whose archive members are not yet loaded).
+//
+// We put all symbols of all files to a SymbolTable, and the
+// SymbolTable selects the "best" symbols if there are name
+// conflicts. For example, obviously, a defined symbol is better than
+// an undefined symbol. Or, if there's a conflict between a lazy and a
+// undefined, it'll read an archive member to read a real definition
+// to replace the lazy symbol. The logic is implemented in the
+// add*() functions, which are called by input files as they are parsed. There
+// is one add* function per symbol type.
+class SymbolTable {
+public:
+ template <class ELFT> void addFile(InputFile *File);
+ template <class ELFT> void addCombinedLTOObject();
+ void wrap(Symbol *Sym, Symbol *Real, Symbol *Wrap);
+
+ ArrayRef<Symbol *> getSymbols() const { return SymVector; }
+
+ template <class ELFT>
+ Symbol *addUndefined(StringRef Name, uint8_t Binding, uint8_t StOther,
+ uint8_t Type, bool CanOmitFromDynSym, InputFile *File);
+
+ Defined *addDefined(StringRef Name, uint8_t StOther, uint8_t Type,
+ uint64_t Value, uint64_t Size, uint8_t Binding,
+ SectionBase *Section, InputFile *File);
+
+ template <class ELFT>
+ void addShared(StringRef Name, SharedFile<ELFT> &F,
+ const typename ELFT::Sym &Sym, uint32_t Alignment,
+ uint32_t VerdefIndex);
+
+ template <class ELFT>
+ void addLazyArchive(StringRef Name, ArchiveFile &F,
+ const llvm::object::Archive::Symbol S);
+
+ template <class ELFT> void addLazyObject(StringRef Name, LazyObjFile &Obj);
+
+ Symbol *addBitcode(StringRef Name, uint8_t Binding, uint8_t StOther,
+ uint8_t Type, bool CanOmitFromDynSym, BitcodeFile &File);
+
+ Symbol *addCommon(StringRef Name, uint64_t Size, uint32_t Alignment,
+ uint8_t Binding, uint8_t StOther, uint8_t Type,
+ InputFile &File);
+
+ std::pair<Symbol *, bool> insert(StringRef Name, uint8_t Visibility,
+ bool CanOmitFromDynSym, InputFile *File);
+
+ template <class ELFT> void fetchLazy(Symbol *Sym);
+
+ void scanVersionScript();
+
+ Symbol *find(StringRef Name);
+
+ void trace(StringRef Name);
+
+ void handleDynamicList();
+
+private:
+ std::pair<Symbol *, bool> insertName(StringRef Name);
+
+ std::vector<Symbol *> findByVersion(SymbolVersion Ver);
+ std::vector<Symbol *> findAllByVersion(SymbolVersion Ver);
+
+ llvm::StringMap<std::vector<Symbol *>> &getDemangledSyms();
+ void handleAnonymousVersion();
+ void assignExactVersion(SymbolVersion Ver, uint16_t VersionId,
+ StringRef VersionName);
+ void assignWildcardVersion(SymbolVersion Ver, uint16_t VersionId);
+
+ // The order the global symbols are in is not defined. We can use an arbitrary
+ // order, but it has to be reproducible. That is true even when cross linking.
+ // The default hashing of StringRef produces different results on 32 and 64
+ // bit systems so we use a map to a vector. That is arbitrary, deterministic
+ // but a bit inefficient.
+ // FIXME: Experiment with passing in a custom hashing or sorting the symbols
+ // once symbol resolution is finished.
+ llvm::DenseMap<llvm::CachedHashStringRef, int> SymMap;
+ std::vector<Symbol *> SymVector;
+
+ // Comdat groups define "link once" sections. If two comdat groups have the
+ // same name, only one of them is linked, and the other is ignored. This set
+ // is used to uniquify them.
+ llvm::DenseSet<llvm::CachedHashStringRef> ComdatGroups;
+
+ // Set of .so files to not link the same shared object file more than once.
+ llvm::DenseMap<StringRef, InputFile *> SoNames;
+
+ // A map from demangled symbol names to their symbol objects.
+ // This mapping is 1:N because two symbols with different versions
+ // can have the same name. We use this map to handle "extern C++ {}"
+ // directive in version scripts.
+ llvm::Optional<llvm::StringMap<std::vector<Symbol *>>> DemangledSyms;
+
+ // For LTO.
+ std::unique_ptr<BitcodeCompiler> LTO;
+};
+
+extern SymbolTable *Symtab;
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/ELF/Symbols.cpp b/contrib/llvm/tools/lld/ELF/Symbols.cpp
new file mode 100644
index 000000000000..a713ec539d82
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Symbols.cpp
@@ -0,0 +1,305 @@
+//===- Symbols.cpp --------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Symbols.h"
+#include "InputFiles.h"
+#include "InputSection.h"
+#include "OutputSections.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "Writer.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Strings.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Path.h"
+#include <cstring>
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::ELF;
+
+using namespace lld;
+using namespace lld::elf;
+
+Defined *ElfSym::Bss;
+Defined *ElfSym::Etext1;
+Defined *ElfSym::Etext2;
+Defined *ElfSym::Edata1;
+Defined *ElfSym::Edata2;
+Defined *ElfSym::End1;
+Defined *ElfSym::End2;
+Defined *ElfSym::GlobalOffsetTable;
+Defined *ElfSym::MipsGp;
+Defined *ElfSym::MipsGpDisp;
+Defined *ElfSym::MipsLocalGp;
+Defined *ElfSym::RelaIpltStart;
+Defined *ElfSym::RelaIpltEnd;
+
+static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) {
+ switch (Sym.kind()) {
+ case Symbol::DefinedKind: {
+ auto &D = cast<Defined>(Sym);
+ SectionBase *IS = D.Section;
+
+ // According to the ELF spec reference to a local symbol from outside
+ // the group are not allowed. Unfortunately .eh_frame breaks that rule
+ // and must be treated specially. For now we just replace the symbol with
+ // 0.
+ if (IS == &InputSection::Discarded)
+ return 0;
+
+ // This is an absolute symbol.
+ if (!IS)
+ return D.Value;
+
+ IS = IS->Repl;
+
+ uint64_t Offset = D.Value;
+
+ // An object in an SHF_MERGE section might be referenced via a
+ // section symbol (as a hack for reducing the number of local
+ // symbols).
+ // Depending on the addend, the reference via a section symbol
+ // refers to a different object in the merge section.
+ // Since the objects in the merge section are not necessarily
+ // contiguous in the output, the addend can thus affect the final
+ // VA in a non-linear way.
+ // To make this work, we incorporate the addend into the section
+ // offset (and zero out the addend for later processing) so that
+ // we find the right object in the section.
+ if (D.isSection()) {
+ Offset += Addend;
+ Addend = 0;
+ }
+
+ // In the typical case, this is actually very simple and boils
+ // down to adding together 3 numbers:
+ // 1. The address of the output section.
+ // 2. The offset of the input section within the output section.
+ // 3. The offset within the input section (this addition happens
+ // inside InputSection::getOffset).
+ //
+ // If you understand the data structures involved with this next
+ // line (and how they get built), then you have a pretty good
+ // understanding of the linker.
+ uint64_t VA = IS->getVA(Offset);
+
+ if (D.isTls() && !Config->Relocatable) {
+ // Use the address of the TLS segment's first section rather than the
+ // segment's address, because segment addresses aren't initialized until
+ // after sections are finalized. (e.g. Measuring the size of .rela.dyn
+ // for Android relocation packing requires knowing TLS symbol addresses
+ // during section finalization.)
+ if (!Out::TlsPhdr || !Out::TlsPhdr->FirstSec)
+ fatal(toString(D.File) +
+ " has an STT_TLS symbol but doesn't have an SHF_TLS section");
+ return VA - Out::TlsPhdr->FirstSec->Addr;
+ }
+ return VA;
+ }
+ case Symbol::SharedKind:
+ case Symbol::UndefinedKind:
+ return 0;
+ case Symbol::LazyArchiveKind:
+ case Symbol::LazyObjectKind:
+ assert(Sym.IsUsedInRegularObj && "lazy symbol reached writer");
+ return 0;
+ case Symbol::PlaceholderKind:
+ llvm_unreachable("placeholder symbol reached writer");
+ }
+ llvm_unreachable("invalid symbol kind");
+}
+
+uint64_t Symbol::getVA(int64_t Addend) const {
+ uint64_t OutVA = getSymVA(*this, Addend);
+ return OutVA + Addend;
+}
+
+uint64_t Symbol::getGotVA() const { return In.Got->getVA() + getGotOffset(); }
+
+uint64_t Symbol::getGotOffset() const {
+ return GotIndex * Target->GotEntrySize;
+}
+
+uint64_t Symbol::getGotPltVA() const {
+ if (this->IsInIgot)
+ return In.IgotPlt->getVA() + getGotPltOffset();
+ return In.GotPlt->getVA() + getGotPltOffset();
+}
+
+uint64_t Symbol::getGotPltOffset() const {
+ if (IsInIgot)
+ return PltIndex * Target->GotPltEntrySize;
+ return (PltIndex + Target->GotPltHeaderEntriesNum) * Target->GotPltEntrySize;
+}
+
+uint64_t Symbol::getPPC64LongBranchOffset() const {
+ assert(PPC64BranchltIndex != 0xffff);
+ return PPC64BranchltIndex * Target->GotPltEntrySize;
+}
+
+uint64_t Symbol::getPltVA() const {
+ PltSection *Plt = IsInIplt ? In.Iplt : In.Plt;
+ return Plt->getVA() + Plt->HeaderSize + PltIndex * Target->PltEntrySize;
+}
+
+uint64_t Symbol::getPPC64LongBranchTableVA() const {
+ assert(PPC64BranchltIndex != 0xffff);
+ return In.PPC64LongBranchTarget->getVA() +
+ PPC64BranchltIndex * Target->GotPltEntrySize;
+}
+
+uint64_t Symbol::getSize() const {
+ if (const auto *DR = dyn_cast<Defined>(this))
+ return DR->Size;
+ return cast<SharedSymbol>(this)->Size;
+}
+
+OutputSection *Symbol::getOutputSection() const {
+ if (auto *S = dyn_cast<Defined>(this)) {
+ if (auto *Sec = S->Section)
+ return Sec->Repl->getOutputSection();
+ return nullptr;
+ }
+ return nullptr;
+}
+
+// If a symbol name contains '@', the characters after that is
+// a symbol version name. This function parses that.
+void Symbol::parseSymbolVersion() {
+ StringRef S = getName();
+ size_t Pos = S.find('@');
+ if (Pos == 0 || Pos == StringRef::npos)
+ return;
+ StringRef Verstr = S.substr(Pos + 1);
+ if (Verstr.empty())
+ return;
+
+ // Truncate the symbol name so that it doesn't include the version string.
+ NameSize = Pos;
+
+ // If this is not in this DSO, it is not a definition.
+ if (!isDefined())
+ return;
+
+ // '@@' in a symbol name means the default version.
+ // It is usually the most recent one.
+ bool IsDefault = (Verstr[0] == '@');
+ if (IsDefault)
+ Verstr = Verstr.substr(1);
+
+ for (VersionDefinition &Ver : Config->VersionDefinitions) {
+ if (Ver.Name != Verstr)
+ continue;
+
+ if (IsDefault)
+ VersionId = Ver.Id;
+ else
+ VersionId = Ver.Id | VERSYM_HIDDEN;
+ return;
+ }
+
+ // It is an error if the specified version is not defined.
+ // Usually version script is not provided when linking executable,
+ // but we may still want to override a versioned symbol from DSO,
+ // so we do not report error in this case. We also do not error
+ // if the symbol has a local version as it won't be in the dynamic
+ // symbol table.
+ if (Config->Shared && VersionId != VER_NDX_LOCAL)
+ error(toString(File) + ": symbol " + S + " has undefined version " +
+ Verstr);
+}
+
+InputFile *LazyArchive::fetch() { return cast<ArchiveFile>(File)->fetch(Sym); }
+
+MemoryBufferRef LazyArchive::getMemberBuffer() {
+ Archive::Child C = CHECK(
+ Sym.getMember(), "could not get the member for symbol " + Sym.getName());
+
+ return CHECK(C.getMemoryBufferRef(),
+ "could not get the buffer for the member defining symbol " +
+ Sym.getName());
+}
+
+uint8_t Symbol::computeBinding() const {
+ if (Config->Relocatable)
+ return Binding;
+ if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED)
+ return STB_LOCAL;
+ if (VersionId == VER_NDX_LOCAL && isDefined() && !IsPreemptible)
+ return STB_LOCAL;
+ if (!Config->GnuUnique && Binding == STB_GNU_UNIQUE)
+ return STB_GLOBAL;
+ return Binding;
+}
+
+bool Symbol::includeInDynsym() const {
+ if (!Config->HasDynSymTab)
+ return false;
+ if (computeBinding() == STB_LOCAL)
+ return false;
+ if (!isDefined())
+ return true;
+ return ExportDynamic;
+}
+
+// Print out a log message for --trace-symbol.
+void elf::printTraceSymbol(Symbol *Sym) {
+ std::string S;
+ if (Sym->isUndefined())
+ S = ": reference to ";
+ else if (Sym->isLazy())
+ S = ": lazy definition of ";
+ else if (Sym->isShared())
+ S = ": shared definition of ";
+ else if (dyn_cast_or_null<BssSection>(cast<Defined>(Sym)->Section))
+ S = ": common definition of ";
+ else
+ S = ": definition of ";
+
+ message(toString(Sym->File) + S + Sym->getName());
+}
+
+void elf::maybeWarnUnorderableSymbol(const Symbol *Sym) {
+ if (!Config->WarnSymbolOrdering)
+ return;
+
+ // If UnresolvedPolicy::Ignore is used, no "undefined symbol" error/warning
+ // is emitted. It makes sense to not warn on undefined symbols.
+ //
+ // Note, ld.bfd --symbol-ordering-file= does not warn on undefined symbols,
+ // but we don't have to be compatible here.
+ if (Sym->isUndefined() &&
+ Config->UnresolvedSymbols == UnresolvedPolicy::Ignore)
+ return;
+
+ const InputFile *File = Sym->File;
+ auto *D = dyn_cast<Defined>(Sym);
+
+ auto Warn = [&](StringRef S) { warn(toString(File) + S + Sym->getName()); };
+
+ if (Sym->isUndefined())
+ Warn(": unable to order undefined symbol: ");
+ else if (Sym->isShared())
+ Warn(": unable to order shared symbol: ");
+ else if (D && !D->Section)
+ Warn(": unable to order absolute symbol: ");
+ else if (D && isa<OutputSection>(D->Section))
+ Warn(": unable to order synthetic symbol: ");
+ else if (D && !D->Section->Repl->Live)
+ Warn(": unable to order discarded symbol: ");
+}
+
+// Returns a symbol for an error message.
+std::string lld::toString(const Symbol &B) {
+ if (Config->Demangle)
+ if (Optional<std::string> S = demangleItanium(B.getName()))
+ return *S;
+ return B.getName();
+}
diff --git a/contrib/llvm/tools/lld/ELF/Symbols.h b/contrib/llvm/tools/lld/ELF/Symbols.h
new file mode 100644
index 000000000000..4d55405d8936
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Symbols.h
@@ -0,0 +1,419 @@
+//===- Symbols.h ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines various types of Symbols.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_SYMBOLS_H
+#define LLD_ELF_SYMBOLS_H
+
+#include "InputSection.h"
+#include "lld/Common/LLVM.h"
+#include "lld/Common/Strings.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/ELF.h"
+
+namespace lld {
+namespace elf {
+class Symbol;
+class InputFile;
+} // namespace elf
+
+std::string toString(const elf::Symbol &);
+std::string toString(const elf::InputFile *);
+
+namespace elf {
+
+class ArchiveFile;
+class BitcodeFile;
+class BssSection;
+class InputFile;
+class LazyObjFile;
+template <class ELFT> class ObjFile;
+class OutputSection;
+template <class ELFT> class SharedFile;
+
+// This is a StringRef-like container that doesn't run strlen().
+//
+// ELF string tables contain a lot of null-terminated strings. Most of them
+// are not necessary for the linker because they are names of local symbols,
+// and the linker doesn't use local symbol names for name resolution. So, we
+// use this class to represents strings read from string tables.
+struct StringRefZ {
+ StringRefZ(const char *S) : Data(S), Size(-1) {}
+ StringRefZ(StringRef S) : Data(S.data()), Size(S.size()) {}
+
+ const char *Data;
+ const uint32_t Size;
+};
+
+// The base class for real symbol classes.
+class Symbol {
+public:
+ enum Kind {
+ PlaceholderKind,
+ DefinedKind,
+ SharedKind,
+ UndefinedKind,
+ LazyArchiveKind,
+ LazyObjectKind,
+ };
+
+ Kind kind() const { return static_cast<Kind>(SymbolKind); }
+
+ // The file from which this symbol was created.
+ InputFile *File;
+
+protected:
+ const char *NameData;
+ mutable uint32_t NameSize;
+
+public:
+ uint32_t DynsymIndex = 0;
+ uint32_t GotIndex = -1;
+ uint32_t PltIndex = -1;
+
+ uint32_t GlobalDynIndex = -1;
+
+ // This field is a index to the symbol's version definition.
+ uint32_t VerdefIndex = -1;
+
+ // Version definition index.
+ uint16_t VersionId;
+
+ // An index into the .branch_lt section on PPC64.
+ uint16_t PPC64BranchltIndex = -1;
+
+ // Symbol binding. This is not overwritten by replaceSymbol to track
+ // changes during resolution. In particular:
+ // - An undefined weak is still weak when it resolves to a shared library.
+ // - An undefined weak will not fetch archive members, but we have to
+ // remember it is weak.
+ uint8_t Binding;
+
+ // The following fields have the same meaning as the ELF symbol attributes.
+ uint8_t Type; // symbol type
+ uint8_t StOther; // st_other field value
+
+ uint8_t SymbolKind;
+
+ // Symbol visibility. This is the computed minimum visibility of all
+ // observed non-DSO symbols.
+ unsigned Visibility : 2;
+
+ // True if the symbol was used for linking and thus need to be added to the
+ // output file's symbol table. This is true for all symbols except for
+ // unreferenced DSO symbols and bitcode symbols that are unreferenced except
+ // by other bitcode objects.
+ unsigned IsUsedInRegularObj : 1;
+
+ // If this flag is true and the symbol has protected or default visibility, it
+ // will appear in .dynsym. This flag is set by interposable DSO symbols in
+ // executables, by most symbols in DSOs and executables built with
+ // --export-dynamic, and by dynamic lists.
+ unsigned ExportDynamic : 1;
+
+ // False if LTO shouldn't inline whatever this symbol points to. If a symbol
+ // is overwritten after LTO, LTO shouldn't inline the symbol because it
+ // doesn't know the final contents of the symbol.
+ unsigned CanInline : 1;
+
+ // True if this symbol is specified by --trace-symbol option.
+ unsigned Traced : 1;
+
+ bool includeInDynsym() const;
+ uint8_t computeBinding() const;
+ bool isWeak() const { return Binding == llvm::ELF::STB_WEAK; }
+
+ bool isUndefined() const { return SymbolKind == UndefinedKind; }
+ bool isDefined() const { return SymbolKind == DefinedKind; }
+ bool isShared() const { return SymbolKind == SharedKind; }
+ bool isLocal() const { return Binding == llvm::ELF::STB_LOCAL; }
+
+ bool isLazy() const {
+ return SymbolKind == LazyArchiveKind || SymbolKind == LazyObjectKind;
+ }
+
+ // True if this is an undefined weak symbol. This only works once
+ // all input files have been added.
+ bool isUndefWeak() const {
+ // See comment on lazy symbols for details.
+ return isWeak() && (isUndefined() || isLazy());
+ }
+
+ StringRef getName() const {
+ if (NameSize == (uint32_t)-1)
+ NameSize = strlen(NameData);
+ return {NameData, NameSize};
+ }
+
+ void setName(StringRef S) {
+ NameData = S.data();
+ NameSize = S.size();
+ }
+
+ void parseSymbolVersion();
+
+ bool isInGot() const { return GotIndex != -1U; }
+ bool isInPlt() const { return PltIndex != -1U; }
+ bool isInPPC64Branchlt() const { return PPC64BranchltIndex != 0xffff; }
+
+ uint64_t getVA(int64_t Addend = 0) const;
+
+ uint64_t getGotOffset() const;
+ uint64_t getGotVA() const;
+ uint64_t getGotPltOffset() const;
+ uint64_t getGotPltVA() const;
+ uint64_t getPltVA() const;
+ uint64_t getPPC64LongBranchTableVA() const;
+ uint64_t getPPC64LongBranchOffset() const;
+ uint64_t getSize() const;
+ OutputSection *getOutputSection() const;
+
+protected:
+ Symbol(Kind K, InputFile *File, StringRefZ Name, uint8_t Binding,
+ uint8_t StOther, uint8_t Type)
+ : File(File), NameData(Name.Data), NameSize(Name.Size), Binding(Binding),
+ Type(Type), StOther(StOther), SymbolKind(K), NeedsPltAddr(false),
+ IsInIplt(false), IsInIgot(false), IsPreemptible(false),
+ Used(!Config->GcSections), NeedsTocRestore(false),
+ ScriptDefined(false) {}
+
+public:
+ // True the symbol should point to its PLT entry.
+ // For SharedSymbol only.
+ unsigned NeedsPltAddr : 1;
+
+ // True if this symbol is in the Iplt sub-section of the Plt.
+ unsigned IsInIplt : 1;
+
+ // True if this symbol is in the Igot sub-section of the .got.plt or .got.
+ unsigned IsInIgot : 1;
+
+ // True if this symbol is preemptible at load time.
+ unsigned IsPreemptible : 1;
+
+ // True if an undefined or shared symbol is used from a live section.
+ unsigned Used : 1;
+
+ // True if a call to this symbol needs to be followed by a restore of the
+ // PPC64 toc pointer.
+ unsigned NeedsTocRestore : 1;
+
+ // True if this symbol is defined by a linker script.
+ unsigned ScriptDefined : 1;
+
+ bool isSection() const { return Type == llvm::ELF::STT_SECTION; }
+ bool isTls() const { return Type == llvm::ELF::STT_TLS; }
+ bool isFunc() const { return Type == llvm::ELF::STT_FUNC; }
+ bool isGnuIFunc() const { return Type == llvm::ELF::STT_GNU_IFUNC; }
+ bool isObject() const { return Type == llvm::ELF::STT_OBJECT; }
+ bool isFile() const { return Type == llvm::ELF::STT_FILE; }
+};
+
+// Represents a symbol that is defined in the current output file.
+class Defined : public Symbol {
+public:
+ Defined(InputFile *File, StringRefZ Name, uint8_t Binding, uint8_t StOther,
+ uint8_t Type, uint64_t Value, uint64_t Size, SectionBase *Section)
+ : Symbol(DefinedKind, File, Name, Binding, StOther, Type), Value(Value),
+ Size(Size), Section(Section) {}
+
+ static bool classof(const Symbol *S) { return S->isDefined(); }
+
+ uint64_t Value;
+ uint64_t Size;
+ SectionBase *Section;
+};
+
+class Undefined : public Symbol {
+public:
+ Undefined(InputFile *File, StringRefZ Name, uint8_t Binding, uint8_t StOther,
+ uint8_t Type)
+ : Symbol(UndefinedKind, File, Name, Binding, StOther, Type) {}
+
+ static bool classof(const Symbol *S) { return S->kind() == UndefinedKind; }
+};
+
+class SharedSymbol : public Symbol {
+public:
+ static bool classof(const Symbol *S) { return S->kind() == SharedKind; }
+
+ SharedSymbol(InputFile &File, StringRef Name, uint8_t Binding,
+ uint8_t StOther, uint8_t Type, uint64_t Value, uint64_t Size,
+ uint32_t Alignment, uint32_t VerdefIndex)
+ : Symbol(SharedKind, &File, Name, Binding, StOther, Type),
+ Alignment(Alignment), Value(Value), Size(Size) {
+ this->VerdefIndex = VerdefIndex;
+ // GNU ifunc is a mechanism to allow user-supplied functions to
+ // resolve PLT slot values at load-time. This is contrary to the
+ // regular symbol resolution scheme in which symbols are resolved just
+ // by name. Using this hook, you can program how symbols are solved
+ // for you program. For example, you can make "memcpy" to be resolved
+ // to a SSE-enabled version of memcpy only when a machine running the
+ // program supports the SSE instruction set.
+ //
+ // Naturally, such symbols should always be called through their PLT
+ // slots. What GNU ifunc symbols point to are resolver functions, and
+ // calling them directly doesn't make sense (unless you are writing a
+ // loader).
+ //
+ // For DSO symbols, we always call them through PLT slots anyway.
+ // So there's no difference between GNU ifunc and regular function
+ // symbols if they are in DSOs. So we can handle GNU_IFUNC as FUNC.
+ if (this->Type == llvm::ELF::STT_GNU_IFUNC)
+ this->Type = llvm::ELF::STT_FUNC;
+ }
+
+ template <class ELFT> SharedFile<ELFT> &getFile() const {
+ return *cast<SharedFile<ELFT>>(File);
+ }
+
+ uint32_t Alignment;
+
+ uint64_t Value; // st_value
+ uint64_t Size; // st_size
+};
+
+// LazyArchive and LazyObject represent a symbols that is not yet in the link,
+// but we know where to find it if needed. If the resolver finds both Undefined
+// and Lazy for the same name, it will ask the Lazy to load a file.
+//
+// A special complication is the handling of weak undefined symbols. They should
+// not load a file, but we have to remember we have seen both the weak undefined
+// and the lazy. We represent that with a lazy symbol with a weak binding. This
+// means that code looking for undefined symbols normally also has to take lazy
+// symbols into consideration.
+
+// This class represents a symbol defined in an archive file. It is
+// created from an archive file header, and it knows how to load an
+// object file from an archive to replace itself with a defined
+// symbol.
+class LazyArchive : public Symbol {
+public:
+ LazyArchive(InputFile &File, uint8_t Type,
+ const llvm::object::Archive::Symbol S)
+ : Symbol(LazyArchiveKind, &File, S.getName(), llvm::ELF::STB_GLOBAL,
+ llvm::ELF::STV_DEFAULT, Type),
+ Sym(S) {}
+
+ static bool classof(const Symbol *S) { return S->kind() == LazyArchiveKind; }
+
+ InputFile *fetch();
+ MemoryBufferRef getMemberBuffer();
+
+private:
+ const llvm::object::Archive::Symbol Sym;
+};
+
+// LazyObject symbols represents symbols in object files between
+// --start-lib and --end-lib options.
+class LazyObject : public Symbol {
+public:
+ LazyObject(InputFile &File, uint8_t Type, StringRef Name)
+ : Symbol(LazyObjectKind, &File, Name, llvm::ELF::STB_GLOBAL,
+ llvm::ELF::STV_DEFAULT, Type) {}
+
+ static bool classof(const Symbol *S) { return S->kind() == LazyObjectKind; }
+};
+
+// Some linker-generated symbols need to be created as
+// Defined symbols.
+struct ElfSym {
+ // __bss_start
+ static Defined *Bss;
+
+ // etext and _etext
+ static Defined *Etext1;
+ static Defined *Etext2;
+
+ // edata and _edata
+ static Defined *Edata1;
+ static Defined *Edata2;
+
+ // end and _end
+ static Defined *End1;
+ static Defined *End2;
+
+ // The _GLOBAL_OFFSET_TABLE_ symbol is defined by target convention to
+ // be at some offset from the base of the .got section, usually 0 or
+ // the end of the .got.
+ static Defined *GlobalOffsetTable;
+
+ // _gp, _gp_disp and __gnu_local_gp symbols. Only for MIPS.
+ static Defined *MipsGp;
+ static Defined *MipsGpDisp;
+ static Defined *MipsLocalGp;
+
+ // __rel{,a}_iplt_{start,end} symbols.
+ static Defined *RelaIpltStart;
+ static Defined *RelaIpltEnd;
+};
+
+// A buffer class that is large enough to hold any Symbol-derived
+// object. We allocate memory using this class and instantiate a symbol
+// using the placement new.
+union SymbolUnion {
+ alignas(Defined) char A[sizeof(Defined)];
+ alignas(Undefined) char C[sizeof(Undefined)];
+ alignas(SharedSymbol) char D[sizeof(SharedSymbol)];
+ alignas(LazyArchive) char E[sizeof(LazyArchive)];
+ alignas(LazyObject) char F[sizeof(LazyObject)];
+};
+
+void printTraceSymbol(Symbol *Sym);
+
+template <typename T, typename... ArgT>
+void replaceSymbol(Symbol *S, ArgT &&... Arg) {
+ using llvm::ELF::STT_TLS;
+
+ static_assert(std::is_trivially_destructible<T>(),
+ "Symbol types must be trivially destructible");
+ static_assert(sizeof(T) <= sizeof(SymbolUnion), "SymbolUnion too small");
+ static_assert(alignof(T) <= alignof(SymbolUnion),
+ "SymbolUnion not aligned enough");
+ assert(static_cast<Symbol *>(static_cast<T *>(nullptr)) == nullptr &&
+ "Not a Symbol");
+
+ Symbol Sym = *S;
+
+ new (S) T(std::forward<ArgT>(Arg)...);
+
+ S->VersionId = Sym.VersionId;
+ S->Visibility = Sym.Visibility;
+ S->IsUsedInRegularObj = Sym.IsUsedInRegularObj;
+ S->ExportDynamic = Sym.ExportDynamic;
+ S->CanInline = Sym.CanInline;
+ S->Traced = Sym.Traced;
+ S->ScriptDefined = Sym.ScriptDefined;
+
+ // Symbols representing thread-local variables must be referenced by
+ // TLS-aware relocations, and non-TLS symbols must be reference by
+ // non-TLS relocations, so there's a clear distinction between TLS
+ // and non-TLS symbols. It is an error if the same symbol is defined
+ // as a TLS symbol in one file and as a non-TLS symbol in other file.
+ bool TlsMismatch = (Sym.Type == STT_TLS && S->Type != STT_TLS) ||
+ (Sym.Type != STT_TLS && S->Type == STT_TLS);
+
+ if (Sym.SymbolKind != Symbol::PlaceholderKind && TlsMismatch && !Sym.isLazy())
+ error("TLS attribute mismatch: " + toString(Sym) + "\n>>> defined in " +
+ toString(Sym.File) + "\n>>> defined in " + toString(S->File));
+
+ // Print out a log message if --trace-symbol was specified.
+ // This is for debugging.
+ if (S->Traced)
+ printTraceSymbol(S);
+}
+
+void maybeWarnUnorderableSymbol(const Symbol *Sym);
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/ELF/SyntheticSections.cpp b/contrib/llvm/tools/lld/ELF/SyntheticSections.cpp
new file mode 100644
index 000000000000..b1a3f8bc70ae
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/SyntheticSections.cpp
@@ -0,0 +1,3226 @@
+//===- SyntheticSections.cpp ----------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains linker-synthesized sections. Currently,
+// synthetic sections are created either output sections or input sections,
+// but we are rewriting code so that all synthetic sections are created as
+// input sections.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SyntheticSections.h"
+#include "Bits.h"
+#include "Config.h"
+#include "InputFiles.h"
+#include "LinkerScript.h"
+#include "OutputSections.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+#include "Target.h"
+#include "Writer.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Memory.h"
+#include "lld/Common/Strings.h"
+#include "lld/Common/Threads.h"
+#include "lld/Common/Version.h"
+#include "llvm/ADT/SetOperations.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h"
+#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Support/Compression.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/MD5.h"
+#include "llvm/Support/RandomNumberGenerator.h"
+#include "llvm/Support/SHA1.h"
+#include "llvm/Support/xxhash.h"
+#include <cstdlib>
+#include <thread>
+
+using namespace llvm;
+using namespace llvm::dwarf;
+using namespace llvm::ELF;
+using namespace llvm::object;
+using namespace llvm::support;
+
+using namespace lld;
+using namespace lld::elf;
+
+using llvm::support::endian::read32le;
+using llvm::support::endian::write32le;
+using llvm::support::endian::write64le;
+
+constexpr size_t MergeNoTailSection::NumShards;
+
+// Returns an LLD version string.
+static ArrayRef<uint8_t> getVersion() {
+ // Check LLD_VERSION first for ease of testing.
+ // You can get consistent output by using the environment variable.
+ // This is only for testing.
+ StringRef S = getenv("LLD_VERSION");
+ if (S.empty())
+ S = Saver.save(Twine("Linker: ") + getLLDVersion());
+
+ // +1 to include the terminating '\0'.
+ return {(const uint8_t *)S.data(), S.size() + 1};
+}
+
+// Creates a .comment section containing LLD version info.
+// With this feature, you can identify LLD-generated binaries easily
+// by "readelf --string-dump .comment <file>".
+// The returned object is a mergeable string section.
+MergeInputSection *elf::createCommentSection() {
+ return make<MergeInputSection>(SHF_MERGE | SHF_STRINGS, SHT_PROGBITS, 1,
+ getVersion(), ".comment");
+}
+
+// .MIPS.abiflags section.
+template <class ELFT>
+MipsAbiFlagsSection<ELFT>::MipsAbiFlagsSection(Elf_Mips_ABIFlags Flags)
+ : SyntheticSection(SHF_ALLOC, SHT_MIPS_ABIFLAGS, 8, ".MIPS.abiflags"),
+ Flags(Flags) {
+ this->Entsize = sizeof(Elf_Mips_ABIFlags);
+}
+
+template <class ELFT> void MipsAbiFlagsSection<ELFT>::writeTo(uint8_t *Buf) {
+ memcpy(Buf, &Flags, sizeof(Flags));
+}
+
+template <class ELFT>
+MipsAbiFlagsSection<ELFT> *MipsAbiFlagsSection<ELFT>::create() {
+ Elf_Mips_ABIFlags Flags = {};
+ bool Create = false;
+
+ for (InputSectionBase *Sec : InputSections) {
+ if (Sec->Type != SHT_MIPS_ABIFLAGS)
+ continue;
+ Sec->Live = false;
+ Create = true;
+
+ std::string Filename = toString(Sec->File);
+ const size_t Size = Sec->data().size();
+ // Older version of BFD (such as the default FreeBSD linker) concatenate
+ // .MIPS.abiflags instead of merging. To allow for this case (or potential
+ // zero padding) we ignore everything after the first Elf_Mips_ABIFlags
+ if (Size < sizeof(Elf_Mips_ABIFlags)) {
+ error(Filename + ": invalid size of .MIPS.abiflags section: got " +
+ Twine(Size) + " instead of " + Twine(sizeof(Elf_Mips_ABIFlags)));
+ return nullptr;
+ }
+ auto *S = reinterpret_cast<const Elf_Mips_ABIFlags *>(Sec->data().data());
+ if (S->version != 0) {
+ error(Filename + ": unexpected .MIPS.abiflags version " +
+ Twine(S->version));
+ return nullptr;
+ }
+
+ // LLD checks ISA compatibility in calcMipsEFlags(). Here we just
+ // select the highest number of ISA/Rev/Ext.
+ Flags.isa_level = std::max(Flags.isa_level, S->isa_level);
+ Flags.isa_rev = std::max(Flags.isa_rev, S->isa_rev);
+ Flags.isa_ext = std::max(Flags.isa_ext, S->isa_ext);
+ Flags.gpr_size = std::max(Flags.gpr_size, S->gpr_size);
+ Flags.cpr1_size = std::max(Flags.cpr1_size, S->cpr1_size);
+ Flags.cpr2_size = std::max(Flags.cpr2_size, S->cpr2_size);
+ Flags.ases |= S->ases;
+ Flags.flags1 |= S->flags1;
+ Flags.flags2 |= S->flags2;
+ Flags.fp_abi = elf::getMipsFpAbiFlag(Flags.fp_abi, S->fp_abi, Filename);
+ };
+
+ if (Create)
+ return make<MipsAbiFlagsSection<ELFT>>(Flags);
+ return nullptr;
+}
+
+// .MIPS.options section.
+template <class ELFT>
+MipsOptionsSection<ELFT>::MipsOptionsSection(Elf_Mips_RegInfo Reginfo)
+ : SyntheticSection(SHF_ALLOC, SHT_MIPS_OPTIONS, 8, ".MIPS.options"),
+ Reginfo(Reginfo) {
+ this->Entsize = sizeof(Elf_Mips_Options) + sizeof(Elf_Mips_RegInfo);
+}
+
+template <class ELFT> void MipsOptionsSection<ELFT>::writeTo(uint8_t *Buf) {
+ auto *Options = reinterpret_cast<Elf_Mips_Options *>(Buf);
+ Options->kind = ODK_REGINFO;
+ Options->size = getSize();
+
+ if (!Config->Relocatable)
+ Reginfo.ri_gp_value = In.MipsGot->getGp();
+ memcpy(Buf + sizeof(Elf_Mips_Options), &Reginfo, sizeof(Reginfo));
+}
+
+template <class ELFT>
+MipsOptionsSection<ELFT> *MipsOptionsSection<ELFT>::create() {
+ // N64 ABI only.
+ if (!ELFT::Is64Bits)
+ return nullptr;
+
+ std::vector<InputSectionBase *> Sections;
+ for (InputSectionBase *Sec : InputSections)
+ if (Sec->Type == SHT_MIPS_OPTIONS)
+ Sections.push_back(Sec);
+
+ if (Sections.empty())
+ return nullptr;
+
+ Elf_Mips_RegInfo Reginfo = {};
+ for (InputSectionBase *Sec : Sections) {
+ Sec->Live = false;
+
+ std::string Filename = toString(Sec->File);
+ ArrayRef<uint8_t> D = Sec->data();
+
+ while (!D.empty()) {
+ if (D.size() < sizeof(Elf_Mips_Options)) {
+ error(Filename + ": invalid size of .MIPS.options section");
+ break;
+ }
+
+ auto *Opt = reinterpret_cast<const Elf_Mips_Options *>(D.data());
+ if (Opt->kind == ODK_REGINFO) {
+ Reginfo.ri_gprmask |= Opt->getRegInfo().ri_gprmask;
+ Sec->getFile<ELFT>()->MipsGp0 = Opt->getRegInfo().ri_gp_value;
+ break;
+ }
+
+ if (!Opt->size)
+ fatal(Filename + ": zero option descriptor size");
+ D = D.slice(Opt->size);
+ }
+ };
+
+ return make<MipsOptionsSection<ELFT>>(Reginfo);
+}
+
+// MIPS .reginfo section.
+template <class ELFT>
+MipsReginfoSection<ELFT>::MipsReginfoSection(Elf_Mips_RegInfo Reginfo)
+ : SyntheticSection(SHF_ALLOC, SHT_MIPS_REGINFO, 4, ".reginfo"),
+ Reginfo(Reginfo) {
+ this->Entsize = sizeof(Elf_Mips_RegInfo);
+}
+
+template <class ELFT> void MipsReginfoSection<ELFT>::writeTo(uint8_t *Buf) {
+ if (!Config->Relocatable)
+ Reginfo.ri_gp_value = In.MipsGot->getGp();
+ memcpy(Buf, &Reginfo, sizeof(Reginfo));
+}
+
+template <class ELFT>
+MipsReginfoSection<ELFT> *MipsReginfoSection<ELFT>::create() {
+ // Section should be alive for O32 and N32 ABIs only.
+ if (ELFT::Is64Bits)
+ return nullptr;
+
+ std::vector<InputSectionBase *> Sections;
+ for (InputSectionBase *Sec : InputSections)
+ if (Sec->Type == SHT_MIPS_REGINFO)
+ Sections.push_back(Sec);
+
+ if (Sections.empty())
+ return nullptr;
+
+ Elf_Mips_RegInfo Reginfo = {};
+ for (InputSectionBase *Sec : Sections) {
+ Sec->Live = false;
+
+ if (Sec->data().size() != sizeof(Elf_Mips_RegInfo)) {
+ error(toString(Sec->File) + ": invalid size of .reginfo section");
+ return nullptr;
+ }
+
+ auto *R = reinterpret_cast<const Elf_Mips_RegInfo *>(Sec->data().data());
+ Reginfo.ri_gprmask |= R->ri_gprmask;
+ Sec->getFile<ELFT>()->MipsGp0 = R->ri_gp_value;
+ };
+
+ return make<MipsReginfoSection<ELFT>>(Reginfo);
+}
+
+InputSection *elf::createInterpSection() {
+ // StringSaver guarantees that the returned string ends with '\0'.
+ StringRef S = Saver.save(Config->DynamicLinker);
+ ArrayRef<uint8_t> Contents = {(const uint8_t *)S.data(), S.size() + 1};
+
+ auto *Sec = make<InputSection>(nullptr, SHF_ALLOC, SHT_PROGBITS, 1, Contents,
+ ".interp");
+ Sec->Live = true;
+ return Sec;
+}
+
+Defined *elf::addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value,
+ uint64_t Size, InputSectionBase &Section) {
+ auto *S = make<Defined>(Section.File, Name, STB_LOCAL, STV_DEFAULT, Type,
+ Value, Size, &Section);
+ if (In.SymTab)
+ In.SymTab->addSymbol(S);
+ return S;
+}
+
+static size_t getHashSize() {
+ switch (Config->BuildId) {
+ case BuildIdKind::Fast:
+ return 8;
+ case BuildIdKind::Md5:
+ case BuildIdKind::Uuid:
+ return 16;
+ case BuildIdKind::Sha1:
+ return 20;
+ case BuildIdKind::Hexstring:
+ return Config->BuildIdVector.size();
+ default:
+ llvm_unreachable("unknown BuildIdKind");
+ }
+}
+
+BuildIdSection::BuildIdSection()
+ : SyntheticSection(SHF_ALLOC, SHT_NOTE, 4, ".note.gnu.build-id"),
+ HashSize(getHashSize()) {}
+
+void BuildIdSection::writeTo(uint8_t *Buf) {
+ write32(Buf, 4); // Name size
+ write32(Buf + 4, HashSize); // Content size
+ write32(Buf + 8, NT_GNU_BUILD_ID); // Type
+ memcpy(Buf + 12, "GNU", 4); // Name string
+ HashBuf = Buf + 16;
+}
+
+// Split one uint8 array into small pieces of uint8 arrays.
+static std::vector<ArrayRef<uint8_t>> split(ArrayRef<uint8_t> Arr,
+ size_t ChunkSize) {
+ std::vector<ArrayRef<uint8_t>> Ret;
+ while (Arr.size() > ChunkSize) {
+ Ret.push_back(Arr.take_front(ChunkSize));
+ Arr = Arr.drop_front(ChunkSize);
+ }
+ if (!Arr.empty())
+ Ret.push_back(Arr);
+ return Ret;
+}
+
+// Computes a hash value of Data using a given hash function.
+// In order to utilize multiple cores, we first split data into 1MB
+// chunks, compute a hash for each chunk, and then compute a hash value
+// of the hash values.
+void BuildIdSection::computeHash(
+ llvm::ArrayRef<uint8_t> Data,
+ std::function<void(uint8_t *Dest, ArrayRef<uint8_t> Arr)> HashFn) {
+ std::vector<ArrayRef<uint8_t>> Chunks = split(Data, 1024 * 1024);
+ std::vector<uint8_t> Hashes(Chunks.size() * HashSize);
+
+ // Compute hash values.
+ parallelForEachN(0, Chunks.size(), [&](size_t I) {
+ HashFn(Hashes.data() + I * HashSize, Chunks[I]);
+ });
+
+ // Write to the final output buffer.
+ HashFn(HashBuf, Hashes);
+}
+
+BssSection::BssSection(StringRef Name, uint64_t Size, uint32_t Alignment)
+ : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_NOBITS, Alignment, Name) {
+ this->Bss = true;
+ this->Size = Size;
+}
+
+void BuildIdSection::writeBuildId(ArrayRef<uint8_t> Buf) {
+ switch (Config->BuildId) {
+ case BuildIdKind::Fast:
+ computeHash(Buf, [](uint8_t *Dest, ArrayRef<uint8_t> Arr) {
+ write64le(Dest, xxHash64(Arr));
+ });
+ break;
+ case BuildIdKind::Md5:
+ computeHash(Buf, [](uint8_t *Dest, ArrayRef<uint8_t> Arr) {
+ memcpy(Dest, MD5::hash(Arr).data(), 16);
+ });
+ break;
+ case BuildIdKind::Sha1:
+ computeHash(Buf, [](uint8_t *Dest, ArrayRef<uint8_t> Arr) {
+ memcpy(Dest, SHA1::hash(Arr).data(), 20);
+ });
+ break;
+ case BuildIdKind::Uuid:
+ if (auto EC = getRandomBytes(HashBuf, HashSize))
+ error("entropy source failure: " + EC.message());
+ break;
+ case BuildIdKind::Hexstring:
+ memcpy(HashBuf, Config->BuildIdVector.data(), Config->BuildIdVector.size());
+ break;
+ default:
+ llvm_unreachable("unknown BuildIdKind");
+ }
+}
+
+EhFrameSection::EhFrameSection()
+ : SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 1, ".eh_frame") {}
+
+// Search for an existing CIE record or create a new one.
+// CIE records from input object files are uniquified by their contents
+// and where their relocations point to.
+template <class ELFT, class RelTy>
+CieRecord *EhFrameSection::addCie(EhSectionPiece &Cie, ArrayRef<RelTy> Rels) {
+ Symbol *Personality = nullptr;
+ unsigned FirstRelI = Cie.FirstRelocation;
+ if (FirstRelI != (unsigned)-1)
+ Personality =
+ &Cie.Sec->template getFile<ELFT>()->getRelocTargetSym(Rels[FirstRelI]);
+
+ // Search for an existing CIE by CIE contents/relocation target pair.
+ CieRecord *&Rec = CieMap[{Cie.data(), Personality}];
+
+ // If not found, create a new one.
+ if (!Rec) {
+ Rec = make<CieRecord>();
+ Rec->Cie = &Cie;
+ CieRecords.push_back(Rec);
+ }
+ return Rec;
+}
+
+// There is one FDE per function. Returns true if a given FDE
+// points to a live function.
+template <class ELFT, class RelTy>
+bool EhFrameSection::isFdeLive(EhSectionPiece &Fde, ArrayRef<RelTy> Rels) {
+ auto *Sec = cast<EhInputSection>(Fde.Sec);
+ unsigned FirstRelI = Fde.FirstRelocation;
+
+ // An FDE should point to some function because FDEs are to describe
+ // functions. That's however not always the case due to an issue of
+ // ld.gold with -r. ld.gold may discard only functions and leave their
+ // corresponding FDEs, which results in creating bad .eh_frame sections.
+ // To deal with that, we ignore such FDEs.
+ if (FirstRelI == (unsigned)-1)
+ return false;
+
+ const RelTy &Rel = Rels[FirstRelI];
+ Symbol &B = Sec->template getFile<ELFT>()->getRelocTargetSym(Rel);
+
+ // FDEs for garbage-collected or merged-by-ICF sections are dead.
+ if (auto *D = dyn_cast<Defined>(&B))
+ if (SectionBase *Sec = D->Section)
+ return Sec->Live;
+ return false;
+}
+
+// .eh_frame is a sequence of CIE or FDE records. In general, there
+// is one CIE record per input object file which is followed by
+// a list of FDEs. This function searches an existing CIE or create a new
+// one and associates FDEs to the CIE.
+template <class ELFT, class RelTy>
+void EhFrameSection::addSectionAux(EhInputSection *Sec, ArrayRef<RelTy> Rels) {
+ OffsetToCie.clear();
+ for (EhSectionPiece &Piece : Sec->Pieces) {
+ // The empty record is the end marker.
+ if (Piece.Size == 4)
+ return;
+
+ size_t Offset = Piece.InputOff;
+ uint32_t ID = read32(Piece.data().data() + 4);
+ if (ID == 0) {
+ OffsetToCie[Offset] = addCie<ELFT>(Piece, Rels);
+ continue;
+ }
+
+ uint32_t CieOffset = Offset + 4 - ID;
+ CieRecord *Rec = OffsetToCie[CieOffset];
+ if (!Rec)
+ fatal(toString(Sec) + ": invalid CIE reference");
+
+ if (!isFdeLive<ELFT>(Piece, Rels))
+ continue;
+ Rec->Fdes.push_back(&Piece);
+ NumFdes++;
+ }
+}
+
+template <class ELFT> void EhFrameSection::addSection(InputSectionBase *C) {
+ auto *Sec = cast<EhInputSection>(C);
+ Sec->Parent = this;
+
+ Alignment = std::max(Alignment, Sec->Alignment);
+ Sections.push_back(Sec);
+
+ for (auto *DS : Sec->DependentSections)
+ DependentSections.push_back(DS);
+
+ if (Sec->Pieces.empty())
+ return;
+
+ if (Sec->AreRelocsRela)
+ addSectionAux<ELFT>(Sec, Sec->template relas<ELFT>());
+ else
+ addSectionAux<ELFT>(Sec, Sec->template rels<ELFT>());
+}
+
+static void writeCieFde(uint8_t *Buf, ArrayRef<uint8_t> D) {
+ memcpy(Buf, D.data(), D.size());
+
+ size_t Aligned = alignTo(D.size(), Config->Wordsize);
+
+ // Zero-clear trailing padding if it exists.
+ memset(Buf + D.size(), 0, Aligned - D.size());
+
+ // Fix the size field. -4 since size does not include the size field itself.
+ write32(Buf, Aligned - 4);
+}
+
+void EhFrameSection::finalizeContents() {
+ assert(!this->Size); // Not finalized.
+ size_t Off = 0;
+ for (CieRecord *Rec : CieRecords) {
+ Rec->Cie->OutputOff = Off;
+ Off += alignTo(Rec->Cie->Size, Config->Wordsize);
+
+ for (EhSectionPiece *Fde : Rec->Fdes) {
+ Fde->OutputOff = Off;
+ Off += alignTo(Fde->Size, Config->Wordsize);
+ }
+ }
+
+ // The LSB standard does not allow a .eh_frame section with zero
+ // Call Frame Information records. glibc unwind-dw2-fde.c
+ // classify_object_over_fdes expects there is a CIE record length 0 as a
+ // terminator. Thus we add one unconditionally.
+ Off += 4;
+
+ this->Size = Off;
+}
+
+// Returns data for .eh_frame_hdr. .eh_frame_hdr is a binary search table
+// to get an FDE from an address to which FDE is applied. This function
+// returns a list of such pairs.
+std::vector<EhFrameSection::FdeData> EhFrameSection::getFdeData() const {
+ uint8_t *Buf = getParent()->Loc + OutSecOff;
+ std::vector<FdeData> Ret;
+
+ uint64_t VA = In.EhFrameHdr->getVA();
+ for (CieRecord *Rec : CieRecords) {
+ uint8_t Enc = getFdeEncoding(Rec->Cie);
+ for (EhSectionPiece *Fde : Rec->Fdes) {
+ uint64_t Pc = getFdePc(Buf, Fde->OutputOff, Enc);
+ uint64_t FdeVA = getParent()->Addr + Fde->OutputOff;
+ if (!isInt<32>(Pc - VA))
+ fatal(toString(Fde->Sec) + ": PC offset is too large: 0x" +
+ Twine::utohexstr(Pc - VA));
+ Ret.push_back({uint32_t(Pc - VA), uint32_t(FdeVA - VA)});
+ }
+ }
+
+ // Sort the FDE list by their PC and uniqueify. Usually there is only
+ // one FDE for a PC (i.e. function), but if ICF merges two functions
+ // into one, there can be more than one FDEs pointing to the address.
+ auto Less = [](const FdeData &A, const FdeData &B) {
+ return A.PcRel < B.PcRel;
+ };
+ std::stable_sort(Ret.begin(), Ret.end(), Less);
+ auto Eq = [](const FdeData &A, const FdeData &B) {
+ return A.PcRel == B.PcRel;
+ };
+ Ret.erase(std::unique(Ret.begin(), Ret.end(), Eq), Ret.end());
+
+ return Ret;
+}
+
+static uint64_t readFdeAddr(uint8_t *Buf, int Size) {
+ switch (Size) {
+ case DW_EH_PE_udata2:
+ return read16(Buf);
+ case DW_EH_PE_sdata2:
+ return (int16_t)read16(Buf);
+ case DW_EH_PE_udata4:
+ return read32(Buf);
+ case DW_EH_PE_sdata4:
+ return (int32_t)read32(Buf);
+ case DW_EH_PE_udata8:
+ case DW_EH_PE_sdata8:
+ return read64(Buf);
+ case DW_EH_PE_absptr:
+ return readUint(Buf);
+ }
+ fatal("unknown FDE size encoding");
+}
+
+// Returns the VA to which a given FDE (on a mmap'ed buffer) is applied to.
+// We need it to create .eh_frame_hdr section.
+uint64_t EhFrameSection::getFdePc(uint8_t *Buf, size_t FdeOff,
+ uint8_t Enc) const {
+ // The starting address to which this FDE applies is
+ // stored at FDE + 8 byte.
+ size_t Off = FdeOff + 8;
+ uint64_t Addr = readFdeAddr(Buf + Off, Enc & 0xf);
+ if ((Enc & 0x70) == DW_EH_PE_absptr)
+ return Addr;
+ if ((Enc & 0x70) == DW_EH_PE_pcrel)
+ return Addr + getParent()->Addr + Off;
+ fatal("unknown FDE size relative encoding");
+}
+
+void EhFrameSection::writeTo(uint8_t *Buf) {
+ // Write CIE and FDE records.
+ for (CieRecord *Rec : CieRecords) {
+ size_t CieOffset = Rec->Cie->OutputOff;
+ writeCieFde(Buf + CieOffset, Rec->Cie->data());
+
+ for (EhSectionPiece *Fde : Rec->Fdes) {
+ size_t Off = Fde->OutputOff;
+ writeCieFde(Buf + Off, Fde->data());
+
+ // FDE's second word should have the offset to an associated CIE.
+ // Write it.
+ write32(Buf + Off + 4, Off + 4 - CieOffset);
+ }
+ }
+
+ // Apply relocations. .eh_frame section contents are not contiguous
+ // in the output buffer, but relocateAlloc() still works because
+ // getOffset() takes care of discontiguous section pieces.
+ for (EhInputSection *S : Sections)
+ S->relocateAlloc(Buf, nullptr);
+}
+
+GotSection::GotSection()
+ : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
+ Target->GotEntrySize, ".got") {
+ // PPC64 saves the ElfSym::GlobalOffsetTable .TOC. as the first entry in the
+ // .got. If there are no references to .TOC. in the symbol table,
+ // ElfSym::GlobalOffsetTable will not be defined and we won't need to save
+ // .TOC. in the .got. When it is defined, we increase NumEntries by the number
+ // of entries used to emit ElfSym::GlobalOffsetTable.
+ if (ElfSym::GlobalOffsetTable && !Target->GotBaseSymInGotPlt)
+ NumEntries += Target->GotHeaderEntriesNum;
+}
+
+void GotSection::addEntry(Symbol &Sym) {
+ Sym.GotIndex = NumEntries;
+ ++NumEntries;
+}
+
+bool GotSection::addDynTlsEntry(Symbol &Sym) {
+ if (Sym.GlobalDynIndex != -1U)
+ return false;
+ Sym.GlobalDynIndex = NumEntries;
+ // Global Dynamic TLS entries take two GOT slots.
+ NumEntries += 2;
+ return true;
+}
+
+// Reserves TLS entries for a TLS module ID and a TLS block offset.
+// In total it takes two GOT slots.
+bool GotSection::addTlsIndex() {
+ if (TlsIndexOff != uint32_t(-1))
+ return false;
+ TlsIndexOff = NumEntries * Config->Wordsize;
+ NumEntries += 2;
+ return true;
+}
+
+uint64_t GotSection::getGlobalDynAddr(const Symbol &B) const {
+ return this->getVA() + B.GlobalDynIndex * Config->Wordsize;
+}
+
+uint64_t GotSection::getGlobalDynOffset(const Symbol &B) const {
+ return B.GlobalDynIndex * Config->Wordsize;
+}
+
+void GotSection::finalizeContents() {
+ Size = NumEntries * Config->Wordsize;
+}
+
+bool GotSection::empty() const {
+ // We need to emit a GOT even if it's empty if there's a relocation that is
+ // relative to GOT(such as GOTOFFREL) or there's a symbol that points to a GOT
+ // (i.e. _GLOBAL_OFFSET_TABLE_) that the target defines relative to the .got.
+ return NumEntries == 0 && !HasGotOffRel &&
+ !(ElfSym::GlobalOffsetTable && !Target->GotBaseSymInGotPlt);
+}
+
+void GotSection::writeTo(uint8_t *Buf) {
+ // Buf points to the start of this section's buffer,
+ // whereas InputSectionBase::relocateAlloc() expects its argument
+ // to point to the start of the output section.
+ Target->writeGotHeader(Buf);
+ relocateAlloc(Buf - OutSecOff, Buf - OutSecOff + Size);
+}
+
+static uint64_t getMipsPageAddr(uint64_t Addr) {
+ return (Addr + 0x8000) & ~0xffff;
+}
+
+static uint64_t getMipsPageCount(uint64_t Size) {
+ return (Size + 0xfffe) / 0xffff + 1;
+}
+
+MipsGotSection::MipsGotSection()
+ : SyntheticSection(SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL, SHT_PROGBITS, 16,
+ ".got") {}
+
+void MipsGotSection::addEntry(InputFile &File, Symbol &Sym, int64_t Addend,
+ RelExpr Expr) {
+ FileGot &G = getGot(File);
+ if (Expr == R_MIPS_GOT_LOCAL_PAGE) {
+ if (const OutputSection *OS = Sym.getOutputSection())
+ G.PagesMap.insert({OS, {}});
+ else
+ G.Local16.insert({{nullptr, getMipsPageAddr(Sym.getVA(Addend))}, 0});
+ } else if (Sym.isTls())
+ G.Tls.insert({&Sym, 0});
+ else if (Sym.IsPreemptible && Expr == R_ABS)
+ G.Relocs.insert({&Sym, 0});
+ else if (Sym.IsPreemptible)
+ G.Global.insert({&Sym, 0});
+ else if (Expr == R_MIPS_GOT_OFF32)
+ G.Local32.insert({{&Sym, Addend}, 0});
+ else
+ G.Local16.insert({{&Sym, Addend}, 0});
+}
+
+void MipsGotSection::addDynTlsEntry(InputFile &File, Symbol &Sym) {
+ getGot(File).DynTlsSymbols.insert({&Sym, 0});
+}
+
+void MipsGotSection::addTlsIndex(InputFile &File) {
+ getGot(File).DynTlsSymbols.insert({nullptr, 0});
+}
+
+size_t MipsGotSection::FileGot::getEntriesNum() const {
+ return getPageEntriesNum() + Local16.size() + Global.size() + Relocs.size() +
+ Tls.size() + DynTlsSymbols.size() * 2;
+}
+
+size_t MipsGotSection::FileGot::getPageEntriesNum() const {
+ size_t Num = 0;
+ for (const std::pair<const OutputSection *, FileGot::PageBlock> &P : PagesMap)
+ Num += P.second.Count;
+ return Num;
+}
+
+size_t MipsGotSection::FileGot::getIndexedEntriesNum() const {
+ size_t Count = getPageEntriesNum() + Local16.size() + Global.size();
+ // If there are relocation-only entries in the GOT, TLS entries
+ // are allocated after them. TLS entries should be addressable
+ // by 16-bit index so count both reloc-only and TLS entries.
+ if (!Tls.empty() || !DynTlsSymbols.empty())
+ Count += Relocs.size() + Tls.size() + DynTlsSymbols.size() * 2;
+ return Count;
+}
+
+MipsGotSection::FileGot &MipsGotSection::getGot(InputFile &F) {
+ if (!F.MipsGotIndex.hasValue()) {
+ Gots.emplace_back();
+ Gots.back().File = &F;
+ F.MipsGotIndex = Gots.size() - 1;
+ }
+ return Gots[*F.MipsGotIndex];
+}
+
+uint64_t MipsGotSection::getPageEntryOffset(const InputFile *F,
+ const Symbol &Sym,
+ int64_t Addend) const {
+ const FileGot &G = Gots[*F->MipsGotIndex];
+ uint64_t Index = 0;
+ if (const OutputSection *OutSec = Sym.getOutputSection()) {
+ uint64_t SecAddr = getMipsPageAddr(OutSec->Addr);
+ uint64_t SymAddr = getMipsPageAddr(Sym.getVA(Addend));
+ Index = G.PagesMap.lookup(OutSec).FirstIndex + (SymAddr - SecAddr) / 0xffff;
+ } else {
+ Index = G.Local16.lookup({nullptr, getMipsPageAddr(Sym.getVA(Addend))});
+ }
+ return Index * Config->Wordsize;
+}
+
+uint64_t MipsGotSection::getSymEntryOffset(const InputFile *F, const Symbol &S,
+ int64_t Addend) const {
+ const FileGot &G = Gots[*F->MipsGotIndex];
+ Symbol *Sym = const_cast<Symbol *>(&S);
+ if (Sym->isTls())
+ return G.Tls.lookup(Sym) * Config->Wordsize;
+ if (Sym->IsPreemptible)
+ return G.Global.lookup(Sym) * Config->Wordsize;
+ return G.Local16.lookup({Sym, Addend}) * Config->Wordsize;
+}
+
+uint64_t MipsGotSection::getTlsIndexOffset(const InputFile *F) const {
+ const FileGot &G = Gots[*F->MipsGotIndex];
+ return G.DynTlsSymbols.lookup(nullptr) * Config->Wordsize;
+}
+
+uint64_t MipsGotSection::getGlobalDynOffset(const InputFile *F,
+ const Symbol &S) const {
+ const FileGot &G = Gots[*F->MipsGotIndex];
+ Symbol *Sym = const_cast<Symbol *>(&S);
+ return G.DynTlsSymbols.lookup(Sym) * Config->Wordsize;
+}
+
+const Symbol *MipsGotSection::getFirstGlobalEntry() const {
+ if (Gots.empty())
+ return nullptr;
+ const FileGot &PrimGot = Gots.front();
+ if (!PrimGot.Global.empty())
+ return PrimGot.Global.front().first;
+ if (!PrimGot.Relocs.empty())
+ return PrimGot.Relocs.front().first;
+ return nullptr;
+}
+
+unsigned MipsGotSection::getLocalEntriesNum() const {
+ if (Gots.empty())
+ return HeaderEntriesNum;
+ return HeaderEntriesNum + Gots.front().getPageEntriesNum() +
+ Gots.front().Local16.size();
+}
+
+bool MipsGotSection::tryMergeGots(FileGot &Dst, FileGot &Src, bool IsPrimary) {
+ FileGot Tmp = Dst;
+ set_union(Tmp.PagesMap, Src.PagesMap);
+ set_union(Tmp.Local16, Src.Local16);
+ set_union(Tmp.Global, Src.Global);
+ set_union(Tmp.Relocs, Src.Relocs);
+ set_union(Tmp.Tls, Src.Tls);
+ set_union(Tmp.DynTlsSymbols, Src.DynTlsSymbols);
+
+ size_t Count = IsPrimary ? HeaderEntriesNum : 0;
+ Count += Tmp.getIndexedEntriesNum();
+
+ if (Count * Config->Wordsize > Config->MipsGotSize)
+ return false;
+
+ std::swap(Tmp, Dst);
+ return true;
+}
+
+void MipsGotSection::finalizeContents() { updateAllocSize(); }
+
+bool MipsGotSection::updateAllocSize() {
+ Size = HeaderEntriesNum * Config->Wordsize;
+ for (const FileGot &G : Gots)
+ Size += G.getEntriesNum() * Config->Wordsize;
+ return false;
+}
+
+template <class ELFT> void MipsGotSection::build() {
+ if (Gots.empty())
+ return;
+
+ std::vector<FileGot> MergedGots(1);
+
+ // For each GOT move non-preemptible symbols from the `Global`
+ // to `Local16` list. Preemptible symbol might become non-preemptible
+ // one if, for example, it gets a related copy relocation.
+ for (FileGot &Got : Gots) {
+ for (auto &P: Got.Global)
+ if (!P.first->IsPreemptible)
+ Got.Local16.insert({{P.first, 0}, 0});
+ Got.Global.remove_if([&](const std::pair<Symbol *, size_t> &P) {
+ return !P.first->IsPreemptible;
+ });
+ }
+
+ // For each GOT remove "reloc-only" entry if there is "global"
+ // entry for the same symbol. And add local entries which indexed
+ // using 32-bit value at the end of 16-bit entries.
+ for (FileGot &Got : Gots) {
+ Got.Relocs.remove_if([&](const std::pair<Symbol *, size_t> &P) {
+ return Got.Global.count(P.first);
+ });
+ set_union(Got.Local16, Got.Local32);
+ Got.Local32.clear();
+ }
+
+ // Evaluate number of "reloc-only" entries in the resulting GOT.
+ // To do that put all unique "reloc-only" and "global" entries
+ // from all GOTs to the future primary GOT.
+ FileGot *PrimGot = &MergedGots.front();
+ for (FileGot &Got : Gots) {
+ set_union(PrimGot->Relocs, Got.Global);
+ set_union(PrimGot->Relocs, Got.Relocs);
+ Got.Relocs.clear();
+ }
+
+ // Evaluate number of "page" entries in each GOT.
+ for (FileGot &Got : Gots) {
+ for (std::pair<const OutputSection *, FileGot::PageBlock> &P :
+ Got.PagesMap) {
+ const OutputSection *OS = P.first;
+ uint64_t SecSize = 0;
+ for (BaseCommand *Cmd : OS->SectionCommands) {
+ if (auto *ISD = dyn_cast<InputSectionDescription>(Cmd))
+ for (InputSection *IS : ISD->Sections) {
+ uint64_t Off = alignTo(SecSize, IS->Alignment);
+ SecSize = Off + IS->getSize();
+ }
+ }
+ P.second.Count = getMipsPageCount(SecSize);
+ }
+ }
+
+ // Merge GOTs. Try to join as much as possible GOTs but do not exceed
+ // maximum GOT size. At first, try to fill the primary GOT because
+ // the primary GOT can be accessed in the most effective way. If it
+ // is not possible, try to fill the last GOT in the list, and finally
+ // create a new GOT if both attempts failed.
+ for (FileGot &SrcGot : Gots) {
+ InputFile *File = SrcGot.File;
+ if (tryMergeGots(MergedGots.front(), SrcGot, true)) {
+ File->MipsGotIndex = 0;
+ } else {
+ // If this is the first time we failed to merge with the primary GOT,
+ // MergedGots.back() will also be the primary GOT. We must make sure not
+ // to try to merge again with IsPrimary=false, as otherwise, if the
+ // inputs are just right, we could allow the primary GOT to become 1 or 2
+ // words too big due to ignoring the header size.
+ if (MergedGots.size() == 1 ||
+ !tryMergeGots(MergedGots.back(), SrcGot, false)) {
+ MergedGots.emplace_back();
+ std::swap(MergedGots.back(), SrcGot);
+ }
+ File->MipsGotIndex = MergedGots.size() - 1;
+ }
+ }
+ std::swap(Gots, MergedGots);
+
+ // Reduce number of "reloc-only" entries in the primary GOT
+ // by substracting "global" entries exist in the primary GOT.
+ PrimGot = &Gots.front();
+ PrimGot->Relocs.remove_if([&](const std::pair<Symbol *, size_t> &P) {
+ return PrimGot->Global.count(P.first);
+ });
+
+ // Calculate indexes for each GOT entry.
+ size_t Index = HeaderEntriesNum;
+ for (FileGot &Got : Gots) {
+ Got.StartIndex = &Got == PrimGot ? 0 : Index;
+ for (std::pair<const OutputSection *, FileGot::PageBlock> &P :
+ Got.PagesMap) {
+ // For each output section referenced by GOT page relocations calculate
+ // and save into PagesMap an upper bound of MIPS GOT entries required
+ // to store page addresses of local symbols. We assume the worst case -
+ // each 64kb page of the output section has at least one GOT relocation
+ // against it. And take in account the case when the section intersects
+ // page boundaries.
+ P.second.FirstIndex = Index;
+ Index += P.second.Count;
+ }
+ for (auto &P: Got.Local16)
+ P.second = Index++;
+ for (auto &P: Got.Global)
+ P.second = Index++;
+ for (auto &P: Got.Relocs)
+ P.second = Index++;
+ for (auto &P: Got.Tls)
+ P.second = Index++;
+ for (auto &P: Got.DynTlsSymbols) {
+ P.second = Index;
+ Index += 2;
+ }
+ }
+
+ // Update Symbol::GotIndex field to use this
+ // value later in the `sortMipsSymbols` function.
+ for (auto &P : PrimGot->Global)
+ P.first->GotIndex = P.second;
+ for (auto &P : PrimGot->Relocs)
+ P.first->GotIndex = P.second;
+
+ // Create dynamic relocations.
+ for (FileGot &Got : Gots) {
+ // Create dynamic relocations for TLS entries.
+ for (std::pair<Symbol *, size_t> &P : Got.Tls) {
+ Symbol *S = P.first;
+ uint64_t Offset = P.second * Config->Wordsize;
+ if (S->IsPreemptible)
+ In.RelaDyn->addReloc(Target->TlsGotRel, this, Offset, S);
+ }
+ for (std::pair<Symbol *, size_t> &P : Got.DynTlsSymbols) {
+ Symbol *S = P.first;
+ uint64_t Offset = P.second * Config->Wordsize;
+ if (S == nullptr) {
+ if (!Config->Pic)
+ continue;
+ In.RelaDyn->addReloc(Target->TlsModuleIndexRel, this, Offset, S);
+ } else {
+ // When building a shared library we still need a dynamic relocation
+ // for the module index. Therefore only checking for
+ // S->IsPreemptible is not sufficient (this happens e.g. for
+ // thread-locals that have been marked as local through a linker script)
+ if (!S->IsPreemptible && !Config->Pic)
+ continue;
+ In.RelaDyn->addReloc(Target->TlsModuleIndexRel, this, Offset, S);
+ // However, we can skip writing the TLS offset reloc for non-preemptible
+ // symbols since it is known even in shared libraries
+ if (!S->IsPreemptible)
+ continue;
+ Offset += Config->Wordsize;
+ In.RelaDyn->addReloc(Target->TlsOffsetRel, this, Offset, S);
+ }
+ }
+
+ // Do not create dynamic relocations for non-TLS
+ // entries in the primary GOT.
+ if (&Got == PrimGot)
+ continue;
+
+ // Dynamic relocations for "global" entries.
+ for (const std::pair<Symbol *, size_t> &P : Got.Global) {
+ uint64_t Offset = P.second * Config->Wordsize;
+ In.RelaDyn->addReloc(Target->RelativeRel, this, Offset, P.first);
+ }
+ if (!Config->Pic)
+ continue;
+ // Dynamic relocations for "local" entries in case of PIC.
+ for (const std::pair<const OutputSection *, FileGot::PageBlock> &L :
+ Got.PagesMap) {
+ size_t PageCount = L.second.Count;
+ for (size_t PI = 0; PI < PageCount; ++PI) {
+ uint64_t Offset = (L.second.FirstIndex + PI) * Config->Wordsize;
+ In.RelaDyn->addReloc({Target->RelativeRel, this, Offset, L.first,
+ int64_t(PI * 0x10000)});
+ }
+ }
+ for (const std::pair<GotEntry, size_t> &P : Got.Local16) {
+ uint64_t Offset = P.second * Config->Wordsize;
+ In.RelaDyn->addReloc({Target->RelativeRel, this, Offset, true,
+ P.first.first, P.first.second});
+ }
+ }
+}
+
+bool MipsGotSection::empty() const {
+ // We add the .got section to the result for dynamic MIPS target because
+ // its address and properties are mentioned in the .dynamic section.
+ return Config->Relocatable;
+}
+
+uint64_t MipsGotSection::getGp(const InputFile *F) const {
+ // For files without related GOT or files refer a primary GOT
+ // returns "common" _gp value. For secondary GOTs calculate
+ // individual _gp values.
+ if (!F || !F->MipsGotIndex.hasValue() || *F->MipsGotIndex == 0)
+ return ElfSym::MipsGp->getVA(0);
+ return getVA() + Gots[*F->MipsGotIndex].StartIndex * Config->Wordsize +
+ 0x7ff0;
+}
+
+void MipsGotSection::writeTo(uint8_t *Buf) {
+ // Set the MSB of the second GOT slot. This is not required by any
+ // MIPS ABI documentation, though.
+ //
+ // There is a comment in glibc saying that "The MSB of got[1] of a
+ // gnu object is set to identify gnu objects," and in GNU gold it
+ // says "the second entry will be used by some runtime loaders".
+ // But how this field is being used is unclear.
+ //
+ // We are not really willing to mimic other linkers behaviors
+ // without understanding why they do that, but because all files
+ // generated by GNU tools have this special GOT value, and because
+ // we've been doing this for years, it is probably a safe bet to
+ // keep doing this for now. We really need to revisit this to see
+ // if we had to do this.
+ writeUint(Buf + Config->Wordsize, (uint64_t)1 << (Config->Wordsize * 8 - 1));
+ for (const FileGot &G : Gots) {
+ auto Write = [&](size_t I, const Symbol *S, int64_t A) {
+ uint64_t VA = A;
+ if (S) {
+ VA = S->getVA(A);
+ if (S->StOther & STO_MIPS_MICROMIPS)
+ VA |= 1;
+ }
+ writeUint(Buf + I * Config->Wordsize, VA);
+ };
+ // Write 'page address' entries to the local part of the GOT.
+ for (const std::pair<const OutputSection *, FileGot::PageBlock> &L :
+ G.PagesMap) {
+ size_t PageCount = L.second.Count;
+ uint64_t FirstPageAddr = getMipsPageAddr(L.first->Addr);
+ for (size_t PI = 0; PI < PageCount; ++PI)
+ Write(L.second.FirstIndex + PI, nullptr, FirstPageAddr + PI * 0x10000);
+ }
+ // Local, global, TLS, reloc-only entries.
+ // If TLS entry has a corresponding dynamic relocations, leave it
+ // initialized by zero. Write down adjusted TLS symbol's values otherwise.
+ // To calculate the adjustments use offsets for thread-local storage.
+ // https://www.linux-mips.org/wiki/NPTL
+ for (const std::pair<GotEntry, size_t> &P : G.Local16)
+ Write(P.second, P.first.first, P.first.second);
+ // Write VA to the primary GOT only. For secondary GOTs that
+ // will be done by REL32 dynamic relocations.
+ if (&G == &Gots.front())
+ for (const std::pair<const Symbol *, size_t> &P : G.Global)
+ Write(P.second, P.first, 0);
+ for (const std::pair<Symbol *, size_t> &P : G.Relocs)
+ Write(P.second, P.first, 0);
+ for (const std::pair<Symbol *, size_t> &P : G.Tls)
+ Write(P.second, P.first, P.first->IsPreemptible ? 0 : -0x7000);
+ for (const std::pair<Symbol *, size_t> &P : G.DynTlsSymbols) {
+ if (P.first == nullptr && !Config->Pic)
+ Write(P.second, nullptr, 1);
+ else if (P.first && !P.first->IsPreemptible) {
+ // If we are emitting PIC code with relocations we mustn't write
+ // anything to the GOT here. When using Elf_Rel relocations the value
+ // one will be treated as an addend and will cause crashes at runtime
+ if (!Config->Pic)
+ Write(P.second, nullptr, 1);
+ Write(P.second + 1, P.first, -0x8000);
+ }
+ }
+ }
+}
+
+// On PowerPC the .plt section is used to hold the table of function addresses
+// instead of the .got.plt, and the type is SHT_NOBITS similar to a .bss
+// section. I don't know why we have a BSS style type for the section but it is
+// consitent across both 64-bit PowerPC ABIs as well as the 32-bit PowerPC ABI.
+GotPltSection::GotPltSection()
+ : SyntheticSection(SHF_ALLOC | SHF_WRITE,
+ Config->EMachine == EM_PPC64 ? SHT_NOBITS : SHT_PROGBITS,
+ Target->GotPltEntrySize,
+ Config->EMachine == EM_PPC64 ? ".plt" : ".got.plt") {}
+
+void GotPltSection::addEntry(Symbol &Sym) {
+ assert(Sym.PltIndex == Entries.size());
+ Entries.push_back(&Sym);
+}
+
+size_t GotPltSection::getSize() const {
+ return (Target->GotPltHeaderEntriesNum + Entries.size()) *
+ Target->GotPltEntrySize;
+}
+
+void GotPltSection::writeTo(uint8_t *Buf) {
+ Target->writeGotPltHeader(Buf);
+ Buf += Target->GotPltHeaderEntriesNum * Target->GotPltEntrySize;
+ for (const Symbol *B : Entries) {
+ Target->writeGotPlt(Buf, *B);
+ Buf += Config->Wordsize;
+ }
+}
+
+bool GotPltSection::empty() const {
+ // We need to emit a GOT.PLT even if it's empty if there's a symbol that
+ // references the _GLOBAL_OFFSET_TABLE_ and the Target defines the symbol
+ // relative to the .got.plt section.
+ return Entries.empty() &&
+ !(ElfSym::GlobalOffsetTable && Target->GotBaseSymInGotPlt);
+}
+
+static StringRef getIgotPltName() {
+ // On ARM the IgotPltSection is part of the GotSection.
+ if (Config->EMachine == EM_ARM)
+ return ".got";
+
+ // On PowerPC64 the GotPltSection is renamed to '.plt' so the IgotPltSection
+ // needs to be named the same.
+ if (Config->EMachine == EM_PPC64)
+ return ".plt";
+
+ return ".got.plt";
+}
+
+// On PowerPC64 the GotPltSection type is SHT_NOBITS so we have to follow suit
+// with the IgotPltSection.
+IgotPltSection::IgotPltSection()
+ : SyntheticSection(SHF_ALLOC | SHF_WRITE,
+ Config->EMachine == EM_PPC64 ? SHT_NOBITS : SHT_PROGBITS,
+ Target->GotPltEntrySize, getIgotPltName()) {}
+
+void IgotPltSection::addEntry(Symbol &Sym) {
+ Sym.IsInIgot = true;
+ assert(Sym.PltIndex == Entries.size());
+ Entries.push_back(&Sym);
+}
+
+size_t IgotPltSection::getSize() const {
+ return Entries.size() * Target->GotPltEntrySize;
+}
+
+void IgotPltSection::writeTo(uint8_t *Buf) {
+ for (const Symbol *B : Entries) {
+ Target->writeIgotPlt(Buf, *B);
+ Buf += Config->Wordsize;
+ }
+}
+
+StringTableSection::StringTableSection(StringRef Name, bool Dynamic)
+ : SyntheticSection(Dynamic ? (uint64_t)SHF_ALLOC : 0, SHT_STRTAB, 1, Name),
+ Dynamic(Dynamic) {
+ // ELF string tables start with a NUL byte.
+ addString("");
+}
+
+// Adds a string to the string table. If HashIt is true we hash and check for
+// duplicates. It is optional because the name of global symbols are already
+// uniqued and hashing them again has a big cost for a small value: uniquing
+// them with some other string that happens to be the same.
+unsigned StringTableSection::addString(StringRef S, bool HashIt) {
+ if (HashIt) {
+ auto R = StringMap.insert(std::make_pair(S, this->Size));
+ if (!R.second)
+ return R.first->second;
+ }
+ unsigned Ret = this->Size;
+ this->Size = this->Size + S.size() + 1;
+ Strings.push_back(S);
+ return Ret;
+}
+
+void StringTableSection::writeTo(uint8_t *Buf) {
+ for (StringRef S : Strings) {
+ memcpy(Buf, S.data(), S.size());
+ Buf[S.size()] = '\0';
+ Buf += S.size() + 1;
+ }
+}
+
+// Returns the number of version definition entries. Because the first entry
+// is for the version definition itself, it is the number of versioned symbols
+// plus one. Note that we don't support multiple versions yet.
+static unsigned getVerDefNum() { return Config->VersionDefinitions.size() + 1; }
+
+template <class ELFT>
+DynamicSection<ELFT>::DynamicSection()
+ : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_DYNAMIC, Config->Wordsize,
+ ".dynamic") {
+ this->Entsize = ELFT::Is64Bits ? 16 : 8;
+
+ // .dynamic section is not writable on MIPS and on Fuchsia OS
+ // which passes -z rodynamic.
+ // See "Special Section" in Chapter 4 in the following document:
+ // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+ if (Config->EMachine == EM_MIPS || Config->ZRodynamic)
+ this->Flags = SHF_ALLOC;
+
+ // Add strings to .dynstr early so that .dynstr's size will be
+ // fixed early.
+ for (StringRef S : Config->FilterList)
+ addInt(DT_FILTER, In.DynStrTab->addString(S));
+ for (StringRef S : Config->AuxiliaryList)
+ addInt(DT_AUXILIARY, In.DynStrTab->addString(S));
+
+ if (!Config->Rpath.empty())
+ addInt(Config->EnableNewDtags ? DT_RUNPATH : DT_RPATH,
+ In.DynStrTab->addString(Config->Rpath));
+
+ for (InputFile *File : SharedFiles) {
+ SharedFile<ELFT> *F = cast<SharedFile<ELFT>>(File);
+ if (F->IsNeeded)
+ addInt(DT_NEEDED, In.DynStrTab->addString(F->SoName));
+ }
+ if (!Config->SoName.empty())
+ addInt(DT_SONAME, In.DynStrTab->addString(Config->SoName));
+}
+
+template <class ELFT>
+void DynamicSection<ELFT>::add(int32_t Tag, std::function<uint64_t()> Fn) {
+ Entries.push_back({Tag, Fn});
+}
+
+template <class ELFT>
+void DynamicSection<ELFT>::addInt(int32_t Tag, uint64_t Val) {
+ Entries.push_back({Tag, [=] { return Val; }});
+}
+
+template <class ELFT>
+void DynamicSection<ELFT>::addInSec(int32_t Tag, InputSection *Sec) {
+ Entries.push_back({Tag, [=] { return Sec->getVA(0); }});
+}
+
+template <class ELFT>
+void DynamicSection<ELFT>::addInSecRelative(int32_t Tag, InputSection *Sec) {
+ size_t TagOffset = Entries.size() * Entsize;
+ Entries.push_back(
+ {Tag, [=] { return Sec->getVA(0) - (getVA() + TagOffset); }});
+}
+
+template <class ELFT>
+void DynamicSection<ELFT>::addOutSec(int32_t Tag, OutputSection *Sec) {
+ Entries.push_back({Tag, [=] { return Sec->Addr; }});
+}
+
+template <class ELFT>
+void DynamicSection<ELFT>::addSize(int32_t Tag, OutputSection *Sec) {
+ Entries.push_back({Tag, [=] { return Sec->Size; }});
+}
+
+template <class ELFT>
+void DynamicSection<ELFT>::addSym(int32_t Tag, Symbol *Sym) {
+ Entries.push_back({Tag, [=] { return Sym->getVA(); }});
+}
+
+// A Linker script may assign the RELA relocation sections to the same
+// output section. When this occurs we cannot just use the OutputSection
+// Size. Moreover the [DT_JMPREL, DT_JMPREL + DT_PLTRELSZ) is permitted to
+// overlap with the [DT_RELA, DT_RELA + DT_RELASZ).
+static uint64_t addPltRelSz() {
+ size_t Size = In.RelaPlt->getSize();
+ if (In.RelaIplt->getParent() == In.RelaPlt->getParent() &&
+ In.RelaIplt->Name == In.RelaPlt->Name)
+ Size += In.RelaIplt->getSize();
+ return Size;
+}
+
+// Add remaining entries to complete .dynamic contents.
+template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
+ // Set DT_FLAGS and DT_FLAGS_1.
+ uint32_t DtFlags = 0;
+ uint32_t DtFlags1 = 0;
+ if (Config->Bsymbolic)
+ DtFlags |= DF_SYMBOLIC;
+ if (Config->ZGlobal)
+ DtFlags1 |= DF_1_GLOBAL;
+ if (Config->ZInitfirst)
+ DtFlags1 |= DF_1_INITFIRST;
+ if (Config->ZInterpose)
+ DtFlags1 |= DF_1_INTERPOSE;
+ if (Config->ZNodefaultlib)
+ DtFlags1 |= DF_1_NODEFLIB;
+ if (Config->ZNodelete)
+ DtFlags1 |= DF_1_NODELETE;
+ if (Config->ZNodlopen)
+ DtFlags1 |= DF_1_NOOPEN;
+ if (Config->ZNow) {
+ DtFlags |= DF_BIND_NOW;
+ DtFlags1 |= DF_1_NOW;
+ }
+ if (Config->ZOrigin) {
+ DtFlags |= DF_ORIGIN;
+ DtFlags1 |= DF_1_ORIGIN;
+ }
+ if (!Config->ZText)
+ DtFlags |= DF_TEXTREL;
+
+ if (DtFlags)
+ addInt(DT_FLAGS, DtFlags);
+ if (DtFlags1)
+ addInt(DT_FLAGS_1, DtFlags1);
+
+ // DT_DEBUG is a pointer to debug informaion used by debuggers at runtime. We
+ // need it for each process, so we don't write it for DSOs. The loader writes
+ // the pointer into this entry.
+ //
+ // DT_DEBUG is the only .dynamic entry that needs to be written to. Some
+ // systems (currently only Fuchsia OS) provide other means to give the
+ // debugger this information. Such systems may choose make .dynamic read-only.
+ // If the target is such a system (used -z rodynamic) don't write DT_DEBUG.
+ if (!Config->Shared && !Config->Relocatable && !Config->ZRodynamic)
+ addInt(DT_DEBUG, 0);
+
+ if (OutputSection *Sec = In.DynStrTab->getParent())
+ this->Link = Sec->SectionIndex;
+
+ if (!In.RelaDyn->empty()) {
+ addInSec(In.RelaDyn->DynamicTag, In.RelaDyn);
+ addSize(In.RelaDyn->SizeDynamicTag, In.RelaDyn->getParent());
+
+ bool IsRela = Config->IsRela;
+ addInt(IsRela ? DT_RELAENT : DT_RELENT,
+ IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel));
+
+ // MIPS dynamic loader does not support RELCOUNT tag.
+ // The problem is in the tight relation between dynamic
+ // relocations and GOT. So do not emit this tag on MIPS.
+ if (Config->EMachine != EM_MIPS) {
+ size_t NumRelativeRels = In.RelaDyn->getRelativeRelocCount();
+ if (Config->ZCombreloc && NumRelativeRels)
+ addInt(IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels);
+ }
+ }
+ if (In.RelrDyn && !In.RelrDyn->Relocs.empty()) {
+ addInSec(Config->UseAndroidRelrTags ? DT_ANDROID_RELR : DT_RELR,
+ In.RelrDyn);
+ addSize(Config->UseAndroidRelrTags ? DT_ANDROID_RELRSZ : DT_RELRSZ,
+ In.RelrDyn->getParent());
+ addInt(Config->UseAndroidRelrTags ? DT_ANDROID_RELRENT : DT_RELRENT,
+ sizeof(Elf_Relr));
+ }
+ // .rel[a].plt section usually consists of two parts, containing plt and
+ // iplt relocations. It is possible to have only iplt relocations in the
+ // output. In that case RelaPlt is empty and have zero offset, the same offset
+ // as RelaIplt have. And we still want to emit proper dynamic tags for that
+ // case, so here we always use RelaPlt as marker for the begining of
+ // .rel[a].plt section.
+ if (In.RelaPlt->getParent()->Live) {
+ addInSec(DT_JMPREL, In.RelaPlt);
+ Entries.push_back({DT_PLTRELSZ, addPltRelSz});
+ switch (Config->EMachine) {
+ case EM_MIPS:
+ addInSec(DT_MIPS_PLTGOT, In.GotPlt);
+ break;
+ case EM_SPARCV9:
+ addInSec(DT_PLTGOT, In.Plt);
+ break;
+ default:
+ addInSec(DT_PLTGOT, In.GotPlt);
+ break;
+ }
+ addInt(DT_PLTREL, Config->IsRela ? DT_RELA : DT_REL);
+ }
+
+ addInSec(DT_SYMTAB, In.DynSymTab);
+ addInt(DT_SYMENT, sizeof(Elf_Sym));
+ addInSec(DT_STRTAB, In.DynStrTab);
+ addInt(DT_STRSZ, In.DynStrTab->getSize());
+ if (!Config->ZText)
+ addInt(DT_TEXTREL, 0);
+ if (In.GnuHashTab)
+ addInSec(DT_GNU_HASH, In.GnuHashTab);
+ if (In.HashTab)
+ addInSec(DT_HASH, In.HashTab);
+
+ if (Out::PreinitArray) {
+ addOutSec(DT_PREINIT_ARRAY, Out::PreinitArray);
+ addSize(DT_PREINIT_ARRAYSZ, Out::PreinitArray);
+ }
+ if (Out::InitArray) {
+ addOutSec(DT_INIT_ARRAY, Out::InitArray);
+ addSize(DT_INIT_ARRAYSZ, Out::InitArray);
+ }
+ if (Out::FiniArray) {
+ addOutSec(DT_FINI_ARRAY, Out::FiniArray);
+ addSize(DT_FINI_ARRAYSZ, Out::FiniArray);
+ }
+
+ if (Symbol *B = Symtab->find(Config->Init))
+ if (B->isDefined())
+ addSym(DT_INIT, B);
+ if (Symbol *B = Symtab->find(Config->Fini))
+ if (B->isDefined())
+ addSym(DT_FINI, B);
+
+ bool HasVerNeed = InX<ELFT>::VerNeed->getNeedNum() != 0;
+ if (HasVerNeed || In.VerDef)
+ addInSec(DT_VERSYM, InX<ELFT>::VerSym);
+ if (In.VerDef) {
+ addInSec(DT_VERDEF, In.VerDef);
+ addInt(DT_VERDEFNUM, getVerDefNum());
+ }
+ if (HasVerNeed) {
+ addInSec(DT_VERNEED, InX<ELFT>::VerNeed);
+ addInt(DT_VERNEEDNUM, InX<ELFT>::VerNeed->getNeedNum());
+ }
+
+ if (Config->EMachine == EM_MIPS) {
+ addInt(DT_MIPS_RLD_VERSION, 1);
+ addInt(DT_MIPS_FLAGS, RHF_NOTPOT);
+ addInt(DT_MIPS_BASE_ADDRESS, Target->getImageBase());
+ addInt(DT_MIPS_SYMTABNO, In.DynSymTab->getNumSymbols());
+
+ add(DT_MIPS_LOCAL_GOTNO, [] { return In.MipsGot->getLocalEntriesNum(); });
+
+ if (const Symbol *B = In.MipsGot->getFirstGlobalEntry())
+ addInt(DT_MIPS_GOTSYM, B->DynsymIndex);
+ else
+ addInt(DT_MIPS_GOTSYM, In.DynSymTab->getNumSymbols());
+ addInSec(DT_PLTGOT, In.MipsGot);
+ if (In.MipsRldMap) {
+ if (!Config->Pie)
+ addInSec(DT_MIPS_RLD_MAP, In.MipsRldMap);
+ // Store the offset to the .rld_map section
+ // relative to the address of the tag.
+ addInSecRelative(DT_MIPS_RLD_MAP_REL, In.MipsRldMap);
+ }
+ }
+
+ // Glink dynamic tag is required by the V2 abi if the plt section isn't empty.
+ if (Config->EMachine == EM_PPC64 && !In.Plt->empty()) {
+ // The Glink tag points to 32 bytes before the first lazy symbol resolution
+ // stub, which starts directly after the header.
+ Entries.push_back({DT_PPC64_GLINK, [=] {
+ unsigned Offset = Target->PltHeaderSize - 32;
+ return In.Plt->getVA(0) + Offset;
+ }});
+ }
+
+ addInt(DT_NULL, 0);
+
+ getParent()->Link = this->Link;
+ this->Size = Entries.size() * this->Entsize;
+}
+
+template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *Buf) {
+ auto *P = reinterpret_cast<Elf_Dyn *>(Buf);
+
+ for (std::pair<int32_t, std::function<uint64_t()>> &KV : Entries) {
+ P->d_tag = KV.first;
+ P->d_un.d_val = KV.second();
+ ++P;
+ }
+}
+
+uint64_t DynamicReloc::getOffset() const {
+ return InputSec->getVA(OffsetInSec);
+}
+
+int64_t DynamicReloc::computeAddend() const {
+ if (UseSymVA)
+ return Sym->getVA(Addend);
+ if (!OutputSec)
+ return Addend;
+ // See the comment in the DynamicReloc ctor.
+ return getMipsPageAddr(OutputSec->Addr) + Addend;
+}
+
+uint32_t DynamicReloc::getSymIndex() const {
+ if (Sym && !UseSymVA)
+ return Sym->DynsymIndex;
+ return 0;
+}
+
+RelocationBaseSection::RelocationBaseSection(StringRef Name, uint32_t Type,
+ int32_t DynamicTag,
+ int32_t SizeDynamicTag)
+ : SyntheticSection(SHF_ALLOC, Type, Config->Wordsize, Name),
+ DynamicTag(DynamicTag), SizeDynamicTag(SizeDynamicTag) {}
+
+void RelocationBaseSection::addReloc(RelType DynType, InputSectionBase *IS,
+ uint64_t OffsetInSec, Symbol *Sym) {
+ addReloc({DynType, IS, OffsetInSec, false, Sym, 0});
+}
+
+void RelocationBaseSection::addReloc(RelType DynType,
+ InputSectionBase *InputSec,
+ uint64_t OffsetInSec, Symbol *Sym,
+ int64_t Addend, RelExpr Expr,
+ RelType Type) {
+ // Write the addends to the relocated address if required. We skip
+ // it if the written value would be zero.
+ if (Config->WriteAddends && (Expr != R_ADDEND || Addend != 0))
+ InputSec->Relocations.push_back({Expr, Type, OffsetInSec, Addend, Sym});
+ addReloc({DynType, InputSec, OffsetInSec, Expr != R_ADDEND, Sym, Addend});
+}
+
+void RelocationBaseSection::addReloc(const DynamicReloc &Reloc) {
+ if (Reloc.Type == Target->RelativeRel)
+ ++NumRelativeRelocs;
+ Relocs.push_back(Reloc);
+}
+
+void RelocationBaseSection::finalizeContents() {
+ // When linking glibc statically, .rel{,a}.plt contains R_*_IRELATIVE
+ // relocations due to IFUNC (e.g. strcpy). sh_link will be set to 0 in that
+ // case.
+ InputSection *SymTab = Config->Relocatable ? In.SymTab : In.DynSymTab;
+ if (SymTab && SymTab->getParent())
+ getParent()->Link = SymTab->getParent()->SectionIndex;
+ else
+ getParent()->Link = 0;
+
+ if (In.RelaPlt == this)
+ getParent()->Info = In.GotPlt->getParent()->SectionIndex;
+ if (In.RelaIplt == this)
+ getParent()->Info = In.IgotPlt->getParent()->SectionIndex;
+}
+
+RelrBaseSection::RelrBaseSection()
+ : SyntheticSection(SHF_ALLOC,
+ Config->UseAndroidRelrTags ? SHT_ANDROID_RELR : SHT_RELR,
+ Config->Wordsize, ".relr.dyn") {}
+
+template <class ELFT>
+static void encodeDynamicReloc(typename ELFT::Rela *P,
+ const DynamicReloc &Rel) {
+ if (Config->IsRela)
+ P->r_addend = Rel.computeAddend();
+ P->r_offset = Rel.getOffset();
+ P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->IsMips64EL);
+}
+
+template <class ELFT>
+RelocationSection<ELFT>::RelocationSection(StringRef Name, bool Sort)
+ : RelocationBaseSection(Name, Config->IsRela ? SHT_RELA : SHT_REL,
+ Config->IsRela ? DT_RELA : DT_REL,
+ Config->IsRela ? DT_RELASZ : DT_RELSZ),
+ Sort(Sort) {
+ this->Entsize = Config->IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
+}
+
+static bool compRelocations(const DynamicReloc &A, const DynamicReloc &B) {
+ bool AIsRel = A.Type == Target->RelativeRel;
+ bool BIsRel = B.Type == Target->RelativeRel;
+ if (AIsRel != BIsRel)
+ return AIsRel;
+ return A.getSymIndex() < B.getSymIndex();
+}
+
+template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
+ if (Sort)
+ std::stable_sort(Relocs.begin(), Relocs.end(), compRelocations);
+
+ for (const DynamicReloc &Rel : Relocs) {
+ encodeDynamicReloc<ELFT>(reinterpret_cast<Elf_Rela *>(Buf), Rel);
+ Buf += Config->IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
+ }
+}
+
+template <class ELFT> unsigned RelocationSection<ELFT>::getRelocOffset() {
+ return this->Entsize * Relocs.size();
+}
+
+template <class ELFT>
+AndroidPackedRelocationSection<ELFT>::AndroidPackedRelocationSection(
+ StringRef Name)
+ : RelocationBaseSection(
+ Name, Config->IsRela ? SHT_ANDROID_RELA : SHT_ANDROID_REL,
+ Config->IsRela ? DT_ANDROID_RELA : DT_ANDROID_REL,
+ Config->IsRela ? DT_ANDROID_RELASZ : DT_ANDROID_RELSZ) {
+ this->Entsize = 1;
+}
+
+template <class ELFT>
+bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() {
+ // This function computes the contents of an Android-format packed relocation
+ // section.
+ //
+ // This format compresses relocations by using relocation groups to factor out
+ // fields that are common between relocations and storing deltas from previous
+ // relocations in SLEB128 format (which has a short representation for small
+ // numbers). A good example of a relocation type with common fields is
+ // R_*_RELATIVE, which is normally used to represent function pointers in
+ // vtables. In the REL format, each relative relocation has the same r_info
+ // field, and is only different from other relative relocations in terms of
+ // the r_offset field. By sorting relocations by offset, grouping them by
+ // r_info and representing each relocation with only the delta from the
+ // previous offset, each 8-byte relocation can be compressed to as little as 1
+ // byte (or less with run-length encoding). This relocation packer was able to
+ // reduce the size of the relocation section in an Android Chromium DSO from
+ // 2,911,184 bytes to 174,693 bytes, or 6% of the original size.
+ //
+ // A relocation section consists of a header containing the literal bytes
+ // 'APS2' followed by a sequence of SLEB128-encoded integers. The first two
+ // elements are the total number of relocations in the section and an initial
+ // r_offset value. The remaining elements define a sequence of relocation
+ // groups. Each relocation group starts with a header consisting of the
+ // following elements:
+ //
+ // - the number of relocations in the relocation group
+ // - flags for the relocation group
+ // - (if RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG is set) the r_offset delta
+ // for each relocation in the group.
+ // - (if RELOCATION_GROUPED_BY_INFO_FLAG is set) the value of the r_info
+ // field for each relocation in the group.
+ // - (if RELOCATION_GROUP_HAS_ADDEND_FLAG and
+ // RELOCATION_GROUPED_BY_ADDEND_FLAG are set) the r_addend delta for
+ // each relocation in the group.
+ //
+ // Following the relocation group header are descriptions of each of the
+ // relocations in the group. They consist of the following elements:
+ //
+ // - (if RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG is not set) the r_offset
+ // delta for this relocation.
+ // - (if RELOCATION_GROUPED_BY_INFO_FLAG is not set) the value of the r_info
+ // field for this relocation.
+ // - (if RELOCATION_GROUP_HAS_ADDEND_FLAG is set and
+ // RELOCATION_GROUPED_BY_ADDEND_FLAG is not set) the r_addend delta for
+ // this relocation.
+
+ size_t OldSize = RelocData.size();
+
+ RelocData = {'A', 'P', 'S', '2'};
+ raw_svector_ostream OS(RelocData);
+ auto Add = [&](int64_t V) { encodeSLEB128(V, OS); };
+
+ // The format header includes the number of relocations and the initial
+ // offset (we set this to zero because the first relocation group will
+ // perform the initial adjustment).
+ Add(Relocs.size());
+ Add(0);
+
+ std::vector<Elf_Rela> Relatives, NonRelatives;
+
+ for (const DynamicReloc &Rel : Relocs) {
+ Elf_Rela R;
+ encodeDynamicReloc<ELFT>(&R, Rel);
+
+ if (R.getType(Config->IsMips64EL) == Target->RelativeRel)
+ Relatives.push_back(R);
+ else
+ NonRelatives.push_back(R);
+ }
+
+ llvm::sort(Relatives, [](const Elf_Rel &A, const Elf_Rel &B) {
+ return A.r_offset < B.r_offset;
+ });
+
+ // Try to find groups of relative relocations which are spaced one word
+ // apart from one another. These generally correspond to vtable entries. The
+ // format allows these groups to be encoded using a sort of run-length
+ // encoding, but each group will cost 7 bytes in addition to the offset from
+ // the previous group, so it is only profitable to do this for groups of
+ // size 8 or larger.
+ std::vector<Elf_Rela> UngroupedRelatives;
+ std::vector<std::vector<Elf_Rela>> RelativeGroups;
+ for (auto I = Relatives.begin(), E = Relatives.end(); I != E;) {
+ std::vector<Elf_Rela> Group;
+ do {
+ Group.push_back(*I++);
+ } while (I != E && (I - 1)->r_offset + Config->Wordsize == I->r_offset);
+
+ if (Group.size() < 8)
+ UngroupedRelatives.insert(UngroupedRelatives.end(), Group.begin(),
+ Group.end());
+ else
+ RelativeGroups.emplace_back(std::move(Group));
+ }
+
+ unsigned HasAddendIfRela =
+ Config->IsRela ? RELOCATION_GROUP_HAS_ADDEND_FLAG : 0;
+
+ uint64_t Offset = 0;
+ uint64_t Addend = 0;
+
+ // Emit the run-length encoding for the groups of adjacent relative
+ // relocations. Each group is represented using two groups in the packed
+ // format. The first is used to set the current offset to the start of the
+ // group (and also encodes the first relocation), and the second encodes the
+ // remaining relocations.
+ for (std::vector<Elf_Rela> &G : RelativeGroups) {
+ // The first relocation in the group.
+ Add(1);
+ Add(RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG |
+ RELOCATION_GROUPED_BY_INFO_FLAG | HasAddendIfRela);
+ Add(G[0].r_offset - Offset);
+ Add(Target->RelativeRel);
+ if (Config->IsRela) {
+ Add(G[0].r_addend - Addend);
+ Addend = G[0].r_addend;
+ }
+
+ // The remaining relocations.
+ Add(G.size() - 1);
+ Add(RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG |
+ RELOCATION_GROUPED_BY_INFO_FLAG | HasAddendIfRela);
+ Add(Config->Wordsize);
+ Add(Target->RelativeRel);
+ if (Config->IsRela) {
+ for (auto I = G.begin() + 1, E = G.end(); I != E; ++I) {
+ Add(I->r_addend - Addend);
+ Addend = I->r_addend;
+ }
+ }
+
+ Offset = G.back().r_offset;
+ }
+
+ // Now the ungrouped relatives.
+ if (!UngroupedRelatives.empty()) {
+ Add(UngroupedRelatives.size());
+ Add(RELOCATION_GROUPED_BY_INFO_FLAG | HasAddendIfRela);
+ Add(Target->RelativeRel);
+ for (Elf_Rela &R : UngroupedRelatives) {
+ Add(R.r_offset - Offset);
+ Offset = R.r_offset;
+ if (Config->IsRela) {
+ Add(R.r_addend - Addend);
+ Addend = R.r_addend;
+ }
+ }
+ }
+
+ // Finally the non-relative relocations.
+ llvm::sort(NonRelatives, [](const Elf_Rela &A, const Elf_Rela &B) {
+ return A.r_offset < B.r_offset;
+ });
+ if (!NonRelatives.empty()) {
+ Add(NonRelatives.size());
+ Add(HasAddendIfRela);
+ for (Elf_Rela &R : NonRelatives) {
+ Add(R.r_offset - Offset);
+ Offset = R.r_offset;
+ Add(R.r_info);
+ if (Config->IsRela) {
+ Add(R.r_addend - Addend);
+ Addend = R.r_addend;
+ }
+ }
+ }
+
+ // Don't allow the section to shrink; otherwise the size of the section can
+ // oscillate infinitely.
+ if (RelocData.size() < OldSize)
+ RelocData.append(OldSize - RelocData.size(), 0);
+
+ // Returns whether the section size changed. We need to keep recomputing both
+ // section layout and the contents of this section until the size converges
+ // because changing this section's size can affect section layout, which in
+ // turn can affect the sizes of the LEB-encoded integers stored in this
+ // section.
+ return RelocData.size() != OldSize;
+}
+
+template <class ELFT> RelrSection<ELFT>::RelrSection() {
+ this->Entsize = Config->Wordsize;
+}
+
+template <class ELFT> bool RelrSection<ELFT>::updateAllocSize() {
+ // This function computes the contents of an SHT_RELR packed relocation
+ // section.
+ //
+ // Proposal for adding SHT_RELR sections to generic-abi is here:
+ // https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg
+ //
+ // The encoded sequence of Elf64_Relr entries in a SHT_RELR section looks
+ // like [ AAAAAAAA BBBBBBB1 BBBBBBB1 ... AAAAAAAA BBBBBB1 ... ]
+ //
+ // i.e. start with an address, followed by any number of bitmaps. The address
+ // entry encodes 1 relocation. The subsequent bitmap entries encode up to 63
+ // relocations each, at subsequent offsets following the last address entry.
+ //
+ // The bitmap entries must have 1 in the least significant bit. The assumption
+ // here is that an address cannot have 1 in lsb. Odd addresses are not
+ // supported.
+ //
+ // Excluding the least significant bit in the bitmap, each non-zero bit in
+ // the bitmap represents a relocation to be applied to a corresponding machine
+ // word that follows the base address word. The second least significant bit
+ // represents the machine word immediately following the initial address, and
+ // each bit that follows represents the next word, in linear order. As such,
+ // a single bitmap can encode up to 31 relocations in a 32-bit object, and
+ // 63 relocations in a 64-bit object.
+ //
+ // This encoding has a couple of interesting properties:
+ // 1. Looking at any entry, it is clear whether it's an address or a bitmap:
+ // even means address, odd means bitmap.
+ // 2. Just a simple list of addresses is a valid encoding.
+
+ size_t OldSize = RelrRelocs.size();
+ RelrRelocs.clear();
+
+ // Same as Config->Wordsize but faster because this is a compile-time
+ // constant.
+ const size_t Wordsize = sizeof(typename ELFT::uint);
+
+ // Number of bits to use for the relocation offsets bitmap.
+ // Must be either 63 or 31.
+ const size_t NBits = Wordsize * 8 - 1;
+
+ // Get offsets for all relative relocations and sort them.
+ std::vector<uint64_t> Offsets;
+ for (const RelativeReloc &Rel : Relocs)
+ Offsets.push_back(Rel.getOffset());
+ llvm::sort(Offsets.begin(), Offsets.end());
+
+ // For each leading relocation, find following ones that can be folded
+ // as a bitmap and fold them.
+ for (size_t I = 0, E = Offsets.size(); I < E;) {
+ // Add a leading relocation.
+ RelrRelocs.push_back(Elf_Relr(Offsets[I]));
+ uint64_t Base = Offsets[I] + Wordsize;
+ ++I;
+
+ // Find foldable relocations to construct bitmaps.
+ while (I < E) {
+ uint64_t Bitmap = 0;
+
+ while (I < E) {
+ uint64_t Delta = Offsets[I] - Base;
+
+ // If it is too far, it cannot be folded.
+ if (Delta >= NBits * Wordsize)
+ break;
+
+ // If it is not a multiple of wordsize away, it cannot be folded.
+ if (Delta % Wordsize)
+ break;
+
+ // Fold it.
+ Bitmap |= 1ULL << (Delta / Wordsize);
+ ++I;
+ }
+
+ if (!Bitmap)
+ break;
+
+ RelrRelocs.push_back(Elf_Relr((Bitmap << 1) | 1));
+ Base += NBits * Wordsize;
+ }
+ }
+
+ return RelrRelocs.size() != OldSize;
+}
+
+SymbolTableBaseSection::SymbolTableBaseSection(StringTableSection &StrTabSec)
+ : SyntheticSection(StrTabSec.isDynamic() ? (uint64_t)SHF_ALLOC : 0,
+ StrTabSec.isDynamic() ? SHT_DYNSYM : SHT_SYMTAB,
+ Config->Wordsize,
+ StrTabSec.isDynamic() ? ".dynsym" : ".symtab"),
+ StrTabSec(StrTabSec) {}
+
+// Orders symbols according to their positions in the GOT,
+// in compliance with MIPS ABI rules.
+// See "Global Offset Table" in Chapter 5 in the following document
+// for detailed description:
+// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+static bool sortMipsSymbols(const SymbolTableEntry &L,
+ const SymbolTableEntry &R) {
+ // Sort entries related to non-local preemptible symbols by GOT indexes.
+ // All other entries go to the beginning of a dynsym in arbitrary order.
+ if (L.Sym->isInGot() && R.Sym->isInGot())
+ return L.Sym->GotIndex < R.Sym->GotIndex;
+ if (!L.Sym->isInGot() && !R.Sym->isInGot())
+ return false;
+ return !L.Sym->isInGot();
+}
+
+void SymbolTableBaseSection::finalizeContents() {
+ if (OutputSection *Sec = StrTabSec.getParent())
+ getParent()->Link = Sec->SectionIndex;
+
+ if (this->Type != SHT_DYNSYM) {
+ sortSymTabSymbols();
+ return;
+ }
+
+ // If it is a .dynsym, there should be no local symbols, but we need
+ // to do a few things for the dynamic linker.
+
+ // Section's Info field has the index of the first non-local symbol.
+ // Because the first symbol entry is a null entry, 1 is the first.
+ getParent()->Info = 1;
+
+ if (In.GnuHashTab) {
+ // NB: It also sorts Symbols to meet the GNU hash table requirements.
+ In.GnuHashTab->addSymbols(Symbols);
+ } else if (Config->EMachine == EM_MIPS) {
+ std::stable_sort(Symbols.begin(), Symbols.end(), sortMipsSymbols);
+ }
+
+ size_t I = 0;
+ for (const SymbolTableEntry &S : Symbols)
+ S.Sym->DynsymIndex = ++I;
+}
+
+// The ELF spec requires that all local symbols precede global symbols, so we
+// sort symbol entries in this function. (For .dynsym, we don't do that because
+// symbols for dynamic linking are inherently all globals.)
+//
+// Aside from above, we put local symbols in groups starting with the STT_FILE
+// symbol. That is convenient for purpose of identifying where are local symbols
+// coming from.
+void SymbolTableBaseSection::sortSymTabSymbols() {
+ // Move all local symbols before global symbols.
+ auto E = std::stable_partition(
+ Symbols.begin(), Symbols.end(), [](const SymbolTableEntry &S) {
+ return S.Sym->isLocal() || S.Sym->computeBinding() == STB_LOCAL;
+ });
+ size_t NumLocals = E - Symbols.begin();
+ getParent()->Info = NumLocals + 1;
+
+ // We want to group the local symbols by file. For that we rebuild the local
+ // part of the symbols vector. We do not need to care about the STT_FILE
+ // symbols, they are already naturally placed first in each group. That
+ // happens because STT_FILE is always the first symbol in the object and hence
+ // precede all other local symbols we add for a file.
+ MapVector<InputFile *, std::vector<SymbolTableEntry>> Arr;
+ for (const SymbolTableEntry &S : llvm::make_range(Symbols.begin(), E))
+ Arr[S.Sym->File].push_back(S);
+
+ auto I = Symbols.begin();
+ for (std::pair<InputFile *, std::vector<SymbolTableEntry>> &P : Arr)
+ for (SymbolTableEntry &Entry : P.second)
+ *I++ = Entry;
+}
+
+void SymbolTableBaseSection::addSymbol(Symbol *B) {
+ // Adding a local symbol to a .dynsym is a bug.
+ assert(this->Type != SHT_DYNSYM || !B->isLocal());
+
+ bool HashIt = B->isLocal();
+ Symbols.push_back({B, StrTabSec.addString(B->getName(), HashIt)});
+}
+
+size_t SymbolTableBaseSection::getSymbolIndex(Symbol *Sym) {
+ // Initializes symbol lookup tables lazily. This is used only
+ // for -r or -emit-relocs.
+ llvm::call_once(OnceFlag, [&] {
+ SymbolIndexMap.reserve(Symbols.size());
+ size_t I = 0;
+ for (const SymbolTableEntry &E : Symbols) {
+ if (E.Sym->Type == STT_SECTION)
+ SectionIndexMap[E.Sym->getOutputSection()] = ++I;
+ else
+ SymbolIndexMap[E.Sym] = ++I;
+ }
+ });
+
+ // Section symbols are mapped based on their output sections
+ // to maintain their semantics.
+ if (Sym->Type == STT_SECTION)
+ return SectionIndexMap.lookup(Sym->getOutputSection());
+ return SymbolIndexMap.lookup(Sym);
+}
+
+template <class ELFT>
+SymbolTableSection<ELFT>::SymbolTableSection(StringTableSection &StrTabSec)
+ : SymbolTableBaseSection(StrTabSec) {
+ this->Entsize = sizeof(Elf_Sym);
+}
+
+static BssSection *getCommonSec(Symbol *Sym) {
+ if (!Config->DefineCommon)
+ if (auto *D = dyn_cast<Defined>(Sym))
+ return dyn_cast_or_null<BssSection>(D->Section);
+ return nullptr;
+}
+
+static uint32_t getSymSectionIndex(Symbol *Sym) {
+ if (getCommonSec(Sym))
+ return SHN_COMMON;
+ if (!isa<Defined>(Sym) || Sym->NeedsPltAddr)
+ return SHN_UNDEF;
+ if (const OutputSection *OS = Sym->getOutputSection())
+ return OS->SectionIndex >= SHN_LORESERVE ? (uint32_t)SHN_XINDEX
+ : OS->SectionIndex;
+ return SHN_ABS;
+}
+
+// Write the internal symbol table contents to the output symbol table.
+template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) {
+ // The first entry is a null entry as per the ELF spec.
+ memset(Buf, 0, sizeof(Elf_Sym));
+ Buf += sizeof(Elf_Sym);
+
+ auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
+
+ for (SymbolTableEntry &Ent : Symbols) {
+ Symbol *Sym = Ent.Sym;
+
+ // Set st_info and st_other.
+ ESym->st_other = 0;
+ if (Sym->isLocal()) {
+ ESym->setBindingAndType(STB_LOCAL, Sym->Type);
+ } else {
+ ESym->setBindingAndType(Sym->computeBinding(), Sym->Type);
+ ESym->setVisibility(Sym->Visibility);
+ }
+
+ ESym->st_name = Ent.StrTabOffset;
+ ESym->st_shndx = getSymSectionIndex(Ent.Sym);
+
+ // Copy symbol size if it is a defined symbol. st_size is not significant
+ // for undefined symbols, so whether copying it or not is up to us if that's
+ // the case. We'll leave it as zero because by not setting a value, we can
+ // get the exact same outputs for two sets of input files that differ only
+ // in undefined symbol size in DSOs.
+ if (ESym->st_shndx == SHN_UNDEF)
+ ESym->st_size = 0;
+ else
+ ESym->st_size = Sym->getSize();
+
+ // st_value is usually an address of a symbol, but that has a
+ // special meaining for uninstantiated common symbols (this can
+ // occur if -r is given).
+ if (BssSection *CommonSec = getCommonSec(Ent.Sym))
+ ESym->st_value = CommonSec->Alignment;
+ else
+ ESym->st_value = Sym->getVA();
+
+ ++ESym;
+ }
+
+ // On MIPS we need to mark symbol which has a PLT entry and requires
+ // pointer equality by STO_MIPS_PLT flag. That is necessary to help
+ // dynamic linker distinguish such symbols and MIPS lazy-binding stubs.
+ // https://sourceware.org/ml/binutils/2008-07/txt00000.txt
+ if (Config->EMachine == EM_MIPS) {
+ auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
+
+ for (SymbolTableEntry &Ent : Symbols) {
+ Symbol *Sym = Ent.Sym;
+ if (Sym->isInPlt() && Sym->NeedsPltAddr)
+ ESym->st_other |= STO_MIPS_PLT;
+ if (isMicroMips()) {
+ // Set STO_MIPS_MICROMIPS flag and less-significant bit for
+ // a defined microMIPS symbol and symbol should point to its
+ // PLT entry (in case of microMIPS, PLT entries always contain
+ // microMIPS code).
+ if (Sym->isDefined() &&
+ ((Sym->StOther & STO_MIPS_MICROMIPS) || Sym->NeedsPltAddr)) {
+ if (StrTabSec.isDynamic())
+ ESym->st_value |= 1;
+ ESym->st_other |= STO_MIPS_MICROMIPS;
+ }
+ }
+ if (Config->Relocatable)
+ if (auto *D = dyn_cast<Defined>(Sym))
+ if (isMipsPIC<ELFT>(D))
+ ESym->st_other |= STO_MIPS_PIC;
+ ++ESym;
+ }
+ }
+}
+
+SymtabShndxSection::SymtabShndxSection()
+ : SyntheticSection(0, SHT_SYMTAB_SHNDX, 4, ".symtab_shndxr") {
+ this->Entsize = 4;
+}
+
+void SymtabShndxSection::writeTo(uint8_t *Buf) {
+ // We write an array of 32 bit values, where each value has 1:1 association
+ // with an entry in .symtab. If the corresponding entry contains SHN_XINDEX,
+ // we need to write actual index, otherwise, we must write SHN_UNDEF(0).
+ Buf += 4; // Ignore .symtab[0] entry.
+ for (const SymbolTableEntry &Entry : In.SymTab->getSymbols()) {
+ if (getSymSectionIndex(Entry.Sym) == SHN_XINDEX)
+ write32(Buf, Entry.Sym->getOutputSection()->SectionIndex);
+ Buf += 4;
+ }
+}
+
+bool SymtabShndxSection::empty() const {
+ // SHT_SYMTAB can hold symbols with section indices values up to
+ // SHN_LORESERVE. If we need more, we want to use extension SHT_SYMTAB_SHNDX
+ // section. Problem is that we reveal the final section indices a bit too
+ // late, and we do not know them here. For simplicity, we just always create
+ // a .symtab_shndxr section when the amount of output sections is huge.
+ size_t Size = 0;
+ for (BaseCommand *Base : Script->SectionCommands)
+ if (isa<OutputSection>(Base))
+ ++Size;
+ return Size < SHN_LORESERVE;
+}
+
+void SymtabShndxSection::finalizeContents() {
+ getParent()->Link = In.SymTab->getParent()->SectionIndex;
+}
+
+size_t SymtabShndxSection::getSize() const {
+ return In.SymTab->getNumSymbols() * 4;
+}
+
+// .hash and .gnu.hash sections contain on-disk hash tables that map
+// symbol names to their dynamic symbol table indices. Their purpose
+// is to help the dynamic linker resolve symbols quickly. If ELF files
+// don't have them, the dynamic linker has to do linear search on all
+// dynamic symbols, which makes programs slower. Therefore, a .hash
+// section is added to a DSO by default. A .gnu.hash is added if you
+// give the -hash-style=gnu or -hash-style=both option.
+//
+// The Unix semantics of resolving dynamic symbols is somewhat expensive.
+// Each ELF file has a list of DSOs that the ELF file depends on and a
+// list of dynamic symbols that need to be resolved from any of the
+// DSOs. That means resolving all dynamic symbols takes O(m)*O(n)
+// where m is the number of DSOs and n is the number of dynamic
+// symbols. For modern large programs, both m and n are large. So
+// making each step faster by using hash tables substiantially
+// improves time to load programs.
+//
+// (Note that this is not the only way to design the shared library.
+// For instance, the Windows DLL takes a different approach. On
+// Windows, each dynamic symbol has a name of DLL from which the symbol
+// has to be resolved. That makes the cost of symbol resolution O(n).
+// This disables some hacky techniques you can use on Unix such as
+// LD_PRELOAD, but this is arguably better semantics than the Unix ones.)
+//
+// Due to historical reasons, we have two different hash tables, .hash
+// and .gnu.hash. They are for the same purpose, and .gnu.hash is a new
+// and better version of .hash. .hash is just an on-disk hash table, but
+// .gnu.hash has a bloom filter in addition to a hash table to skip
+// DSOs very quickly. If you are sure that your dynamic linker knows
+// about .gnu.hash, you want to specify -hash-style=gnu. Otherwise, a
+// safe bet is to specify -hash-style=both for backward compatibilty.
+GnuHashTableSection::GnuHashTableSection()
+ : SyntheticSection(SHF_ALLOC, SHT_GNU_HASH, Config->Wordsize, ".gnu.hash") {
+}
+
+void GnuHashTableSection::finalizeContents() {
+ if (OutputSection *Sec = In.DynSymTab->getParent())
+ getParent()->Link = Sec->SectionIndex;
+
+ // Computes bloom filter size in word size. We want to allocate 12
+ // bits for each symbol. It must be a power of two.
+ if (Symbols.empty()) {
+ MaskWords = 1;
+ } else {
+ uint64_t NumBits = Symbols.size() * 12;
+ MaskWords = NextPowerOf2(NumBits / (Config->Wordsize * 8));
+ }
+
+ Size = 16; // Header
+ Size += Config->Wordsize * MaskWords; // Bloom filter
+ Size += NBuckets * 4; // Hash buckets
+ Size += Symbols.size() * 4; // Hash values
+}
+
+void GnuHashTableSection::writeTo(uint8_t *Buf) {
+ // The output buffer is not guaranteed to be zero-cleared because we pre-
+ // fill executable sections with trap instructions. This is a precaution
+ // for that case, which happens only when -no-rosegment is given.
+ memset(Buf, 0, Size);
+
+ // Write a header.
+ write32(Buf, NBuckets);
+ write32(Buf + 4, In.DynSymTab->getNumSymbols() - Symbols.size());
+ write32(Buf + 8, MaskWords);
+ write32(Buf + 12, Shift2);
+ Buf += 16;
+
+ // Write a bloom filter and a hash table.
+ writeBloomFilter(Buf);
+ Buf += Config->Wordsize * MaskWords;
+ writeHashTable(Buf);
+}
+
+// This function writes a 2-bit bloom filter. This bloom filter alone
+// usually filters out 80% or more of all symbol lookups [1].
+// The dynamic linker uses the hash table only when a symbol is not
+// filtered out by a bloom filter.
+//
+// [1] Ulrich Drepper (2011), "How To Write Shared Libraries" (Ver. 4.1.2),
+// p.9, https://www.akkadia.org/drepper/dsohowto.pdf
+void GnuHashTableSection::writeBloomFilter(uint8_t *Buf) {
+ unsigned C = Config->Is64 ? 64 : 32;
+ for (const Entry &Sym : Symbols) {
+ // When C = 64, we choose a word with bits [6:...] and set 1 to two bits in
+ // the word using bits [0:5] and [26:31].
+ size_t I = (Sym.Hash / C) & (MaskWords - 1);
+ uint64_t Val = readUint(Buf + I * Config->Wordsize);
+ Val |= uint64_t(1) << (Sym.Hash % C);
+ Val |= uint64_t(1) << ((Sym.Hash >> Shift2) % C);
+ writeUint(Buf + I * Config->Wordsize, Val);
+ }
+}
+
+void GnuHashTableSection::writeHashTable(uint8_t *Buf) {
+ uint32_t *Buckets = reinterpret_cast<uint32_t *>(Buf);
+ uint32_t OldBucket = -1;
+ uint32_t *Values = Buckets + NBuckets;
+ for (auto I = Symbols.begin(), E = Symbols.end(); I != E; ++I) {
+ // Write a hash value. It represents a sequence of chains that share the
+ // same hash modulo value. The last element of each chain is terminated by
+ // LSB 1.
+ uint32_t Hash = I->Hash;
+ bool IsLastInChain = (I + 1) == E || I->BucketIdx != (I + 1)->BucketIdx;
+ Hash = IsLastInChain ? Hash | 1 : Hash & ~1;
+ write32(Values++, Hash);
+
+ if (I->BucketIdx == OldBucket)
+ continue;
+ // Write a hash bucket. Hash buckets contain indices in the following hash
+ // value table.
+ write32(Buckets + I->BucketIdx, I->Sym->DynsymIndex);
+ OldBucket = I->BucketIdx;
+ }
+}
+
+static uint32_t hashGnu(StringRef Name) {
+ uint32_t H = 5381;
+ for (uint8_t C : Name)
+ H = (H << 5) + H + C;
+ return H;
+}
+
+// Add symbols to this symbol hash table. Note that this function
+// destructively sort a given vector -- which is needed because
+// GNU-style hash table places some sorting requirements.
+void GnuHashTableSection::addSymbols(std::vector<SymbolTableEntry> &V) {
+ // We cannot use 'auto' for Mid because GCC 6.1 cannot deduce
+ // its type correctly.
+ std::vector<SymbolTableEntry>::iterator Mid =
+ std::stable_partition(V.begin(), V.end(), [](const SymbolTableEntry &S) {
+ return !S.Sym->isDefined();
+ });
+
+ // We chose load factor 4 for the on-disk hash table. For each hash
+ // collision, the dynamic linker will compare a uint32_t hash value.
+ // Since the integer comparison is quite fast, we believe we can
+ // make the load factor even larger. 4 is just a conservative choice.
+ //
+ // Note that we don't want to create a zero-sized hash table because
+ // Android loader as of 2018 doesn't like a .gnu.hash containing such
+ // table. If that's the case, we create a hash table with one unused
+ // dummy slot.
+ NBuckets = std::max<size_t>((V.end() - Mid) / 4, 1);
+
+ if (Mid == V.end())
+ return;
+
+ for (SymbolTableEntry &Ent : llvm::make_range(Mid, V.end())) {
+ Symbol *B = Ent.Sym;
+ uint32_t Hash = hashGnu(B->getName());
+ uint32_t BucketIdx = Hash % NBuckets;
+ Symbols.push_back({B, Ent.StrTabOffset, Hash, BucketIdx});
+ }
+
+ std::stable_sort(
+ Symbols.begin(), Symbols.end(),
+ [](const Entry &L, const Entry &R) { return L.BucketIdx < R.BucketIdx; });
+
+ V.erase(Mid, V.end());
+ for (const Entry &Ent : Symbols)
+ V.push_back({Ent.Sym, Ent.StrTabOffset});
+}
+
+HashTableSection::HashTableSection()
+ : SyntheticSection(SHF_ALLOC, SHT_HASH, 4, ".hash") {
+ this->Entsize = 4;
+}
+
+void HashTableSection::finalizeContents() {
+ if (OutputSection *Sec = In.DynSymTab->getParent())
+ getParent()->Link = Sec->SectionIndex;
+
+ unsigned NumEntries = 2; // nbucket and nchain.
+ NumEntries += In.DynSymTab->getNumSymbols(); // The chain entries.
+
+ // Create as many buckets as there are symbols.
+ NumEntries += In.DynSymTab->getNumSymbols();
+ this->Size = NumEntries * 4;
+}
+
+void HashTableSection::writeTo(uint8_t *Buf) {
+ // See comment in GnuHashTableSection::writeTo.
+ memset(Buf, 0, Size);
+
+ unsigned NumSymbols = In.DynSymTab->getNumSymbols();
+
+ uint32_t *P = reinterpret_cast<uint32_t *>(Buf);
+ write32(P++, NumSymbols); // nbucket
+ write32(P++, NumSymbols); // nchain
+
+ uint32_t *Buckets = P;
+ uint32_t *Chains = P + NumSymbols;
+
+ for (const SymbolTableEntry &S : In.DynSymTab->getSymbols()) {
+ Symbol *Sym = S.Sym;
+ StringRef Name = Sym->getName();
+ unsigned I = Sym->DynsymIndex;
+ uint32_t Hash = hashSysV(Name) % NumSymbols;
+ Chains[I] = Buckets[Hash];
+ write32(Buckets + Hash, I);
+ }
+}
+
+// On PowerPC64 the lazy symbol resolvers go into the `global linkage table`
+// in the .glink section, rather then the typical .plt section.
+PltSection::PltSection(bool IsIplt)
+ : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16,
+ Config->EMachine == EM_PPC64 ? ".glink" : ".plt"),
+ HeaderSize(!IsIplt || Config->ZRetpolineplt ? Target->PltHeaderSize : 0),
+ IsIplt(IsIplt) {
+ // The PLT needs to be writable on SPARC as the dynamic linker will
+ // modify the instructions in the PLT entries.
+ if (Config->EMachine == EM_SPARCV9)
+ this->Flags |= SHF_WRITE;
+}
+
+void PltSection::writeTo(uint8_t *Buf) {
+ // At beginning of PLT or retpoline IPLT, we have code to call the dynamic
+ // linker to resolve dynsyms at runtime. Write such code.
+ if (HeaderSize > 0)
+ Target->writePltHeader(Buf);
+ size_t Off = HeaderSize;
+ // The IPlt is immediately after the Plt, account for this in RelOff
+ unsigned PltOff = getPltRelocOff();
+
+ for (auto &I : Entries) {
+ const Symbol *B = I.first;
+ unsigned RelOff = I.second + PltOff;
+ uint64_t Got = B->getGotPltVA();
+ uint64_t Plt = this->getVA() + Off;
+ Target->writePlt(Buf + Off, Got, Plt, B->PltIndex, RelOff);
+ Off += Target->PltEntrySize;
+ }
+}
+
+template <class ELFT> void PltSection::addEntry(Symbol &Sym) {
+ Sym.PltIndex = Entries.size();
+ RelocationBaseSection *PltRelocSection = In.RelaPlt;
+ if (IsIplt) {
+ PltRelocSection = In.RelaIplt;
+ Sym.IsInIplt = true;
+ }
+ unsigned RelOff =
+ static_cast<RelocationSection<ELFT> *>(PltRelocSection)->getRelocOffset();
+ Entries.push_back(std::make_pair(&Sym, RelOff));
+}
+
+size_t PltSection::getSize() const {
+ return HeaderSize + Entries.size() * Target->PltEntrySize;
+}
+
+// Some architectures such as additional symbols in the PLT section. For
+// example ARM uses mapping symbols to aid disassembly
+void PltSection::addSymbols() {
+ // The PLT may have symbols defined for the Header, the IPLT has no header
+ if (!IsIplt)
+ Target->addPltHeaderSymbols(*this);
+ size_t Off = HeaderSize;
+ for (size_t I = 0; I < Entries.size(); ++I) {
+ Target->addPltSymbols(*this, Off);
+ Off += Target->PltEntrySize;
+ }
+}
+
+unsigned PltSection::getPltRelocOff() const {
+ return IsIplt ? In.Plt->getSize() : 0;
+}
+
+// The string hash function for .gdb_index.
+static uint32_t computeGdbHash(StringRef S) {
+ uint32_t H = 0;
+ for (uint8_t C : S)
+ H = H * 67 + toLower(C) - 113;
+ return H;
+}
+
+GdbIndexSection::GdbIndexSection()
+ : SyntheticSection(0, SHT_PROGBITS, 1, ".gdb_index") {}
+
+// Returns the desired size of an on-disk hash table for a .gdb_index section.
+// There's a tradeoff between size and collision rate. We aim 75% utilization.
+size_t GdbIndexSection::computeSymtabSize() const {
+ return std::max<size_t>(NextPowerOf2(Symbols.size() * 4 / 3), 1024);
+}
+
+// Compute the output section size.
+void GdbIndexSection::initOutputSize() {
+ Size = sizeof(GdbIndexHeader) + computeSymtabSize() * 8;
+
+ for (GdbChunk &Chunk : Chunks)
+ Size += Chunk.CompilationUnits.size() * 16 + Chunk.AddressAreas.size() * 20;
+
+ // Add the constant pool size if exists.
+ if (!Symbols.empty()) {
+ GdbSymbol &Sym = Symbols.back();
+ Size += Sym.NameOff + Sym.Name.size() + 1;
+ }
+}
+
+static std::vector<InputSection *> getDebugInfoSections() {
+ std::vector<InputSection *> Ret;
+ for (InputSectionBase *S : InputSections)
+ if (InputSection *IS = dyn_cast<InputSection>(S))
+ if (IS->Name == ".debug_info")
+ Ret.push_back(IS);
+ return Ret;
+}
+
+static std::vector<GdbIndexSection::CuEntry> readCuList(DWARFContext &Dwarf) {
+ std::vector<GdbIndexSection::CuEntry> Ret;
+ for (std::unique_ptr<DWARFUnit> &Cu : Dwarf.compile_units())
+ Ret.push_back({Cu->getOffset(), Cu->getLength() + 4});
+ return Ret;
+}
+
+static std::vector<GdbIndexSection::AddressEntry>
+readAddressAreas(DWARFContext &Dwarf, InputSection *Sec) {
+ std::vector<GdbIndexSection::AddressEntry> Ret;
+
+ uint32_t CuIdx = 0;
+ for (std::unique_ptr<DWARFUnit> &Cu : Dwarf.compile_units()) {
+ Expected<DWARFAddressRangesVector> Ranges = Cu->collectAddressRanges();
+ if (!Ranges) {
+ error(toString(Sec) + ": " + toString(Ranges.takeError()));
+ return {};
+ }
+
+ ArrayRef<InputSectionBase *> Sections = Sec->File->getSections();
+ for (DWARFAddressRange &R : *Ranges) {
+ InputSectionBase *S = Sections[R.SectionIndex];
+ if (!S || S == &InputSection::Discarded || !S->Live)
+ continue;
+ // Range list with zero size has no effect.
+ if (R.LowPC == R.HighPC)
+ continue;
+ auto *IS = cast<InputSection>(S);
+ uint64_t Offset = IS->getOffsetInFile();
+ Ret.push_back({IS, R.LowPC - Offset, R.HighPC - Offset, CuIdx});
+ }
+ ++CuIdx;
+ }
+
+ return Ret;
+}
+
+template <class ELFT>
+static std::vector<GdbIndexSection::NameAttrEntry>
+readPubNamesAndTypes(const LLDDwarfObj<ELFT> &Obj,
+ const std::vector<GdbIndexSection::CuEntry> &CUs) {
+ const DWARFSection &PubNames = Obj.getGnuPubNamesSection();
+ const DWARFSection &PubTypes = Obj.getGnuPubTypesSection();
+
+ std::vector<GdbIndexSection::NameAttrEntry> Ret;
+ for (const DWARFSection *Pub : {&PubNames, &PubTypes}) {
+ DWARFDebugPubTable Table(Obj, *Pub, Config->IsLE, true);
+ for (const DWARFDebugPubTable::Set &Set : Table.getData()) {
+ // The value written into the constant pool is Kind << 24 | CuIndex. As we
+ // don't know how many compilation units precede this object to compute
+ // CuIndex, we compute (Kind << 24 | CuIndexInThisObject) instead, and add
+ // the number of preceding compilation units later.
+ uint32_t I =
+ lower_bound(CUs, Set.Offset,
+ [](GdbIndexSection::CuEntry CU, uint32_t Offset) {
+ return CU.CuOffset < Offset;
+ }) -
+ CUs.begin();
+ for (const DWARFDebugPubTable::Entry &Ent : Set.Entries)
+ Ret.push_back({{Ent.Name, computeGdbHash(Ent.Name)},
+ (Ent.Descriptor.toBits() << 24) | I});
+ }
+ }
+ return Ret;
+}
+
+// Create a list of symbols from a given list of symbol names and types
+// by uniquifying them by name.
+static std::vector<GdbIndexSection::GdbSymbol>
+createSymbols(ArrayRef<std::vector<GdbIndexSection::NameAttrEntry>> NameAttrs,
+ const std::vector<GdbIndexSection::GdbChunk> &Chunks) {
+ typedef GdbIndexSection::GdbSymbol GdbSymbol;
+ typedef GdbIndexSection::NameAttrEntry NameAttrEntry;
+
+ // For each chunk, compute the number of compilation units preceding it.
+ uint32_t CuIdx = 0;
+ std::vector<uint32_t> CuIdxs(Chunks.size());
+ for (uint32_t I = 0, E = Chunks.size(); I != E; ++I) {
+ CuIdxs[I] = CuIdx;
+ CuIdx += Chunks[I].CompilationUnits.size();
+ }
+
+ // The number of symbols we will handle in this function is of the order
+ // of millions for very large executables, so we use multi-threading to
+ // speed it up.
+ size_t NumShards = 32;
+ size_t Concurrency = 1;
+ if (ThreadsEnabled)
+ Concurrency =
+ std::min<size_t>(PowerOf2Floor(hardware_concurrency()), NumShards);
+
+ // A sharded map to uniquify symbols by name.
+ std::vector<DenseMap<CachedHashStringRef, size_t>> Map(NumShards);
+ size_t Shift = 32 - countTrailingZeros(NumShards);
+
+ // Instantiate GdbSymbols while uniqufying them by name.
+ std::vector<std::vector<GdbSymbol>> Symbols(NumShards);
+ parallelForEachN(0, Concurrency, [&](size_t ThreadId) {
+ uint32_t I = 0;
+ for (ArrayRef<NameAttrEntry> Entries : NameAttrs) {
+ for (const NameAttrEntry &Ent : Entries) {
+ size_t ShardId = Ent.Name.hash() >> Shift;
+ if ((ShardId & (Concurrency - 1)) != ThreadId)
+ continue;
+
+ uint32_t V = Ent.CuIndexAndAttrs + CuIdxs[I];
+ size_t &Idx = Map[ShardId][Ent.Name];
+ if (Idx) {
+ Symbols[ShardId][Idx - 1].CuVector.push_back(V);
+ continue;
+ }
+
+ Idx = Symbols[ShardId].size() + 1;
+ Symbols[ShardId].push_back({Ent.Name, {V}, 0, 0});
+ }
+ ++I;
+ }
+ });
+
+ size_t NumSymbols = 0;
+ for (ArrayRef<GdbSymbol> V : Symbols)
+ NumSymbols += V.size();
+
+ // The return type is a flattened vector, so we'll copy each vector
+ // contents to Ret.
+ std::vector<GdbSymbol> Ret;
+ Ret.reserve(NumSymbols);
+ for (std::vector<GdbSymbol> &Vec : Symbols)
+ for (GdbSymbol &Sym : Vec)
+ Ret.push_back(std::move(Sym));
+
+ // CU vectors and symbol names are adjacent in the output file.
+ // We can compute their offsets in the output file now.
+ size_t Off = 0;
+ for (GdbSymbol &Sym : Ret) {
+ Sym.CuVectorOff = Off;
+ Off += (Sym.CuVector.size() + 1) * 4;
+ }
+ for (GdbSymbol &Sym : Ret) {
+ Sym.NameOff = Off;
+ Off += Sym.Name.size() + 1;
+ }
+
+ return Ret;
+}
+
+// Returns a newly-created .gdb_index section.
+template <class ELFT> GdbIndexSection *GdbIndexSection::create() {
+ std::vector<InputSection *> Sections = getDebugInfoSections();
+
+ // .debug_gnu_pub{names,types} are useless in executables.
+ // They are present in input object files solely for creating
+ // a .gdb_index. So we can remove them from the output.
+ for (InputSectionBase *S : InputSections)
+ if (S->Name == ".debug_gnu_pubnames" || S->Name == ".debug_gnu_pubtypes")
+ S->Live = false;
+
+ std::vector<GdbChunk> Chunks(Sections.size());
+ std::vector<std::vector<NameAttrEntry>> NameAttrs(Sections.size());
+
+ parallelForEachN(0, Sections.size(), [&](size_t I) {
+ ObjFile<ELFT> *File = Sections[I]->getFile<ELFT>();
+ DWARFContext Dwarf(make_unique<LLDDwarfObj<ELFT>>(File));
+
+ Chunks[I].Sec = Sections[I];
+ Chunks[I].CompilationUnits = readCuList(Dwarf);
+ Chunks[I].AddressAreas = readAddressAreas(Dwarf, Sections[I]);
+ NameAttrs[I] = readPubNamesAndTypes<ELFT>(
+ static_cast<const LLDDwarfObj<ELFT> &>(Dwarf.getDWARFObj()),
+ Chunks[I].CompilationUnits);
+ });
+
+ auto *Ret = make<GdbIndexSection>();
+ Ret->Chunks = std::move(Chunks);
+ Ret->Symbols = createSymbols(NameAttrs, Ret->Chunks);
+ Ret->initOutputSize();
+ return Ret;
+}
+
+void GdbIndexSection::writeTo(uint8_t *Buf) {
+ // Write the header.
+ auto *Hdr = reinterpret_cast<GdbIndexHeader *>(Buf);
+ uint8_t *Start = Buf;
+ Hdr->Version = 7;
+ Buf += sizeof(*Hdr);
+
+ // Write the CU list.
+ Hdr->CuListOff = Buf - Start;
+ for (GdbChunk &Chunk : Chunks) {
+ for (CuEntry &Cu : Chunk.CompilationUnits) {
+ write64le(Buf, Chunk.Sec->OutSecOff + Cu.CuOffset);
+ write64le(Buf + 8, Cu.CuLength);
+ Buf += 16;
+ }
+ }
+
+ // Write the address area.
+ Hdr->CuTypesOff = Buf - Start;
+ Hdr->AddressAreaOff = Buf - Start;
+ uint32_t CuOff = 0;
+ for (GdbChunk &Chunk : Chunks) {
+ for (AddressEntry &E : Chunk.AddressAreas) {
+ uint64_t BaseAddr = E.Section->getVA(0);
+ write64le(Buf, BaseAddr + E.LowAddress);
+ write64le(Buf + 8, BaseAddr + E.HighAddress);
+ write32le(Buf + 16, E.CuIndex + CuOff);
+ Buf += 20;
+ }
+ CuOff += Chunk.CompilationUnits.size();
+ }
+
+ // Write the on-disk open-addressing hash table containing symbols.
+ Hdr->SymtabOff = Buf - Start;
+ size_t SymtabSize = computeSymtabSize();
+ uint32_t Mask = SymtabSize - 1;
+
+ for (GdbSymbol &Sym : Symbols) {
+ uint32_t H = Sym.Name.hash();
+ uint32_t I = H & Mask;
+ uint32_t Step = ((H * 17) & Mask) | 1;
+
+ while (read32le(Buf + I * 8))
+ I = (I + Step) & Mask;
+
+ write32le(Buf + I * 8, Sym.NameOff);
+ write32le(Buf + I * 8 + 4, Sym.CuVectorOff);
+ }
+
+ Buf += SymtabSize * 8;
+
+ // Write the string pool.
+ Hdr->ConstantPoolOff = Buf - Start;
+ parallelForEach(Symbols, [&](GdbSymbol &Sym) {
+ memcpy(Buf + Sym.NameOff, Sym.Name.data(), Sym.Name.size());
+ });
+
+ // Write the CU vectors.
+ for (GdbSymbol &Sym : Symbols) {
+ write32le(Buf, Sym.CuVector.size());
+ Buf += 4;
+ for (uint32_t Val : Sym.CuVector) {
+ write32le(Buf, Val);
+ Buf += 4;
+ }
+ }
+}
+
+bool GdbIndexSection::empty() const { return Chunks.empty(); }
+
+EhFrameHeader::EhFrameHeader()
+ : SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 4, ".eh_frame_hdr") {}
+
+// .eh_frame_hdr contains a binary search table of pointers to FDEs.
+// Each entry of the search table consists of two values,
+// the starting PC from where FDEs covers, and the FDE's address.
+// It is sorted by PC.
+void EhFrameHeader::writeTo(uint8_t *Buf) {
+ typedef EhFrameSection::FdeData FdeData;
+
+ std::vector<FdeData> Fdes = In.EhFrame->getFdeData();
+
+ Buf[0] = 1;
+ Buf[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4;
+ Buf[2] = DW_EH_PE_udata4;
+ Buf[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4;
+ write32(Buf + 4, In.EhFrame->getParent()->Addr - this->getVA() - 4);
+ write32(Buf + 8, Fdes.size());
+ Buf += 12;
+
+ for (FdeData &Fde : Fdes) {
+ write32(Buf, Fde.PcRel);
+ write32(Buf + 4, Fde.FdeVARel);
+ Buf += 8;
+ }
+}
+
+size_t EhFrameHeader::getSize() const {
+ // .eh_frame_hdr has a 12 bytes header followed by an array of FDEs.
+ return 12 + In.EhFrame->NumFdes * 8;
+}
+
+bool EhFrameHeader::empty() const { return In.EhFrame->empty(); }
+
+VersionDefinitionSection::VersionDefinitionSection()
+ : SyntheticSection(SHF_ALLOC, SHT_GNU_verdef, sizeof(uint32_t),
+ ".gnu.version_d") {}
+
+static StringRef getFileDefName() {
+ if (!Config->SoName.empty())
+ return Config->SoName;
+ return Config->OutputFile;
+}
+
+void VersionDefinitionSection::finalizeContents() {
+ FileDefNameOff = In.DynStrTab->addString(getFileDefName());
+ for (VersionDefinition &V : Config->VersionDefinitions)
+ V.NameOff = In.DynStrTab->addString(V.Name);
+
+ if (OutputSection *Sec = In.DynStrTab->getParent())
+ getParent()->Link = Sec->SectionIndex;
+
+ // sh_info should be set to the number of definitions. This fact is missed in
+ // documentation, but confirmed by binutils community:
+ // https://sourceware.org/ml/binutils/2014-11/msg00355.html
+ getParent()->Info = getVerDefNum();
+}
+
+void VersionDefinitionSection::writeOne(uint8_t *Buf, uint32_t Index,
+ StringRef Name, size_t NameOff) {
+ uint16_t Flags = Index == 1 ? VER_FLG_BASE : 0;
+
+ // Write a verdef.
+ write16(Buf, 1); // vd_version
+ write16(Buf + 2, Flags); // vd_flags
+ write16(Buf + 4, Index); // vd_ndx
+ write16(Buf + 6, 1); // vd_cnt
+ write32(Buf + 8, hashSysV(Name)); // vd_hash
+ write32(Buf + 12, 20); // vd_aux
+ write32(Buf + 16, 28); // vd_next
+
+ // Write a veraux.
+ write32(Buf + 20, NameOff); // vda_name
+ write32(Buf + 24, 0); // vda_next
+}
+
+void VersionDefinitionSection::writeTo(uint8_t *Buf) {
+ writeOne(Buf, 1, getFileDefName(), FileDefNameOff);
+
+ for (VersionDefinition &V : Config->VersionDefinitions) {
+ Buf += EntrySize;
+ writeOne(Buf, V.Id, V.Name, V.NameOff);
+ }
+
+ // Need to terminate the last version definition.
+ write32(Buf + 16, 0); // vd_next
+}
+
+size_t VersionDefinitionSection::getSize() const {
+ return EntrySize * getVerDefNum();
+}
+
+// .gnu.version is a table where each entry is 2 byte long.
+template <class ELFT>
+VersionTableSection<ELFT>::VersionTableSection()
+ : SyntheticSection(SHF_ALLOC, SHT_GNU_versym, sizeof(uint16_t),
+ ".gnu.version") {
+ this->Entsize = 2;
+}
+
+template <class ELFT> void VersionTableSection<ELFT>::finalizeContents() {
+ // At the moment of june 2016 GNU docs does not mention that sh_link field
+ // should be set, but Sun docs do. Also readelf relies on this field.
+ getParent()->Link = In.DynSymTab->getParent()->SectionIndex;
+}
+
+template <class ELFT> size_t VersionTableSection<ELFT>::getSize() const {
+ return (In.DynSymTab->getSymbols().size() + 1) * 2;
+}
+
+template <class ELFT> void VersionTableSection<ELFT>::writeTo(uint8_t *Buf) {
+ Buf += 2;
+ for (const SymbolTableEntry &S : In.DynSymTab->getSymbols()) {
+ write16(Buf, S.Sym->VersionId);
+ Buf += 2;
+ }
+}
+
+template <class ELFT> bool VersionTableSection<ELFT>::empty() const {
+ return !In.VerDef && InX<ELFT>::VerNeed->empty();
+}
+
+template <class ELFT>
+VersionNeedSection<ELFT>::VersionNeedSection()
+ : SyntheticSection(SHF_ALLOC, SHT_GNU_verneed, sizeof(uint32_t),
+ ".gnu.version_r") {
+ // Identifiers in verneed section start at 2 because 0 and 1 are reserved
+ // for VER_NDX_LOCAL and VER_NDX_GLOBAL.
+ // First identifiers are reserved by verdef section if it exist.
+ NextIndex = getVerDefNum() + 1;
+}
+
+template <class ELFT> void VersionNeedSection<ELFT>::addSymbol(Symbol *SS) {
+ auto &File = cast<SharedFile<ELFT>>(*SS->File);
+ if (SS->VerdefIndex == VER_NDX_GLOBAL) {
+ SS->VersionId = VER_NDX_GLOBAL;
+ return;
+ }
+
+ // If we don't already know that we need an Elf_Verneed for this DSO, prepare
+ // to create one by adding it to our needed list and creating a dynstr entry
+ // for the soname.
+ if (File.VerdefMap.empty())
+ Needed.push_back({&File, In.DynStrTab->addString(File.SoName)});
+ const typename ELFT::Verdef *Ver = File.Verdefs[SS->VerdefIndex];
+ typename SharedFile<ELFT>::NeededVer &NV = File.VerdefMap[Ver];
+
+ // If we don't already know that we need an Elf_Vernaux for this Elf_Verdef,
+ // prepare to create one by allocating a version identifier and creating a
+ // dynstr entry for the version name.
+ if (NV.Index == 0) {
+ NV.StrTab = In.DynStrTab->addString(File.getStringTable().data() +
+ Ver->getAux()->vda_name);
+ NV.Index = NextIndex++;
+ }
+ SS->VersionId = NV.Index;
+}
+
+template <class ELFT> void VersionNeedSection<ELFT>::writeTo(uint8_t *Buf) {
+ // The Elf_Verneeds need to appear first, followed by the Elf_Vernauxs.
+ auto *Verneed = reinterpret_cast<Elf_Verneed *>(Buf);
+ auto *Vernaux = reinterpret_cast<Elf_Vernaux *>(Verneed + Needed.size());
+
+ for (std::pair<SharedFile<ELFT> *, size_t> &P : Needed) {
+ // Create an Elf_Verneed for this DSO.
+ Verneed->vn_version = 1;
+ Verneed->vn_cnt = P.first->VerdefMap.size();
+ Verneed->vn_file = P.second;
+ Verneed->vn_aux =
+ reinterpret_cast<char *>(Vernaux) - reinterpret_cast<char *>(Verneed);
+ Verneed->vn_next = sizeof(Elf_Verneed);
+ ++Verneed;
+
+ // Create the Elf_Vernauxs for this Elf_Verneed. The loop iterates over
+ // VerdefMap, which will only contain references to needed version
+ // definitions. Each Elf_Vernaux is based on the information contained in
+ // the Elf_Verdef in the source DSO. This loop iterates over a std::map of
+ // pointers, but is deterministic because the pointers refer to Elf_Verdef
+ // data structures within a single input file.
+ for (auto &NV : P.first->VerdefMap) {
+ Vernaux->vna_hash = NV.first->vd_hash;
+ Vernaux->vna_flags = 0;
+ Vernaux->vna_other = NV.second.Index;
+ Vernaux->vna_name = NV.second.StrTab;
+ Vernaux->vna_next = sizeof(Elf_Vernaux);
+ ++Vernaux;
+ }
+
+ Vernaux[-1].vna_next = 0;
+ }
+ Verneed[-1].vn_next = 0;
+}
+
+template <class ELFT> void VersionNeedSection<ELFT>::finalizeContents() {
+ if (OutputSection *Sec = In.DynStrTab->getParent())
+ getParent()->Link = Sec->SectionIndex;
+ getParent()->Info = Needed.size();
+}
+
+template <class ELFT> size_t VersionNeedSection<ELFT>::getSize() const {
+ unsigned Size = Needed.size() * sizeof(Elf_Verneed);
+ for (const std::pair<SharedFile<ELFT> *, size_t> &P : Needed)
+ Size += P.first->VerdefMap.size() * sizeof(Elf_Vernaux);
+ return Size;
+}
+
+template <class ELFT> bool VersionNeedSection<ELFT>::empty() const {
+ return getNeedNum() == 0;
+}
+
+void MergeSyntheticSection::addSection(MergeInputSection *MS) {
+ MS->Parent = this;
+ Sections.push_back(MS);
+}
+
+MergeTailSection::MergeTailSection(StringRef Name, uint32_t Type,
+ uint64_t Flags, uint32_t Alignment)
+ : MergeSyntheticSection(Name, Type, Flags, Alignment),
+ Builder(StringTableBuilder::RAW, Alignment) {}
+
+size_t MergeTailSection::getSize() const { return Builder.getSize(); }
+
+void MergeTailSection::writeTo(uint8_t *Buf) { Builder.write(Buf); }
+
+void MergeTailSection::finalizeContents() {
+ // Add all string pieces to the string table builder to create section
+ // contents.
+ for (MergeInputSection *Sec : Sections)
+ for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
+ if (Sec->Pieces[I].Live)
+ Builder.add(Sec->getData(I));
+
+ // Fix the string table content. After this, the contents will never change.
+ Builder.finalize();
+
+ // finalize() fixed tail-optimized strings, so we can now get
+ // offsets of strings. Get an offset for each string and save it
+ // to a corresponding StringPiece for easy access.
+ for (MergeInputSection *Sec : Sections)
+ for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
+ if (Sec->Pieces[I].Live)
+ Sec->Pieces[I].OutputOff = Builder.getOffset(Sec->getData(I));
+}
+
+void MergeNoTailSection::writeTo(uint8_t *Buf) {
+ for (size_t I = 0; I < NumShards; ++I)
+ Shards[I].write(Buf + ShardOffsets[I]);
+}
+
+// This function is very hot (i.e. it can take several seconds to finish)
+// because sometimes the number of inputs is in an order of magnitude of
+// millions. So, we use multi-threading.
+//
+// For any strings S and T, we know S is not mergeable with T if S's hash
+// value is different from T's. If that's the case, we can safely put S and
+// T into different string builders without worrying about merge misses.
+// We do it in parallel.
+void MergeNoTailSection::finalizeContents() {
+ // Initializes string table builders.
+ for (size_t I = 0; I < NumShards; ++I)
+ Shards.emplace_back(StringTableBuilder::RAW, Alignment);
+
+ // Concurrency level. Must be a power of 2 to avoid expensive modulo
+ // operations in the following tight loop.
+ size_t Concurrency = 1;
+ if (ThreadsEnabled)
+ Concurrency =
+ std::min<size_t>(PowerOf2Floor(hardware_concurrency()), NumShards);
+
+ // Add section pieces to the builders.
+ parallelForEachN(0, Concurrency, [&](size_t ThreadId) {
+ for (MergeInputSection *Sec : Sections) {
+ for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I) {
+ size_t ShardId = getShardId(Sec->Pieces[I].Hash);
+ if ((ShardId & (Concurrency - 1)) == ThreadId && Sec->Pieces[I].Live)
+ Sec->Pieces[I].OutputOff = Shards[ShardId].add(Sec->getData(I));
+ }
+ }
+ });
+
+ // Compute an in-section offset for each shard.
+ size_t Off = 0;
+ for (size_t I = 0; I < NumShards; ++I) {
+ Shards[I].finalizeInOrder();
+ if (Shards[I].getSize() > 0)
+ Off = alignTo(Off, Alignment);
+ ShardOffsets[I] = Off;
+ Off += Shards[I].getSize();
+ }
+ Size = Off;
+
+ // So far, section pieces have offsets from beginning of shards, but
+ // we want offsets from beginning of the whole section. Fix them.
+ parallelForEach(Sections, [&](MergeInputSection *Sec) {
+ for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
+ if (Sec->Pieces[I].Live)
+ Sec->Pieces[I].OutputOff +=
+ ShardOffsets[getShardId(Sec->Pieces[I].Hash)];
+ });
+}
+
+static MergeSyntheticSection *createMergeSynthetic(StringRef Name,
+ uint32_t Type,
+ uint64_t Flags,
+ uint32_t Alignment) {
+ bool ShouldTailMerge = (Flags & SHF_STRINGS) && Config->Optimize >= 2;
+ if (ShouldTailMerge)
+ return make<MergeTailSection>(Name, Type, Flags, Alignment);
+ return make<MergeNoTailSection>(Name, Type, Flags, Alignment);
+}
+
+template <class ELFT> void elf::splitSections() {
+ // splitIntoPieces needs to be called on each MergeInputSection
+ // before calling finalizeContents().
+ parallelForEach(InputSections, [](InputSectionBase *Sec) {
+ if (auto *S = dyn_cast<MergeInputSection>(Sec))
+ S->splitIntoPieces();
+ else if (auto *Eh = dyn_cast<EhInputSection>(Sec))
+ Eh->split<ELFT>();
+ });
+}
+
+// This function scans over the inputsections to create mergeable
+// synthetic sections.
+//
+// It removes MergeInputSections from the input section array and adds
+// new synthetic sections at the location of the first input section
+// that it replaces. It then finalizes each synthetic section in order
+// to compute an output offset for each piece of each input section.
+void elf::mergeSections() {
+ std::vector<MergeSyntheticSection *> MergeSections;
+ for (InputSectionBase *&S : InputSections) {
+ MergeInputSection *MS = dyn_cast<MergeInputSection>(S);
+ if (!MS)
+ continue;
+
+ // We do not want to handle sections that are not alive, so just remove
+ // them instead of trying to merge.
+ if (!MS->Live) {
+ S = nullptr;
+ continue;
+ }
+
+ StringRef OutsecName = getOutputSectionName(MS);
+ uint32_t Alignment = std::max<uint32_t>(MS->Alignment, MS->Entsize);
+
+ auto I = llvm::find_if(MergeSections, [=](MergeSyntheticSection *Sec) {
+ // While we could create a single synthetic section for two different
+ // values of Entsize, it is better to take Entsize into consideration.
+ //
+ // With a single synthetic section no two pieces with different Entsize
+ // could be equal, so we may as well have two sections.
+ //
+ // Using Entsize in here also allows us to propagate it to the synthetic
+ // section.
+ return Sec->Name == OutsecName && Sec->Flags == MS->Flags &&
+ Sec->Entsize == MS->Entsize && Sec->Alignment == Alignment;
+ });
+ if (I == MergeSections.end()) {
+ MergeSyntheticSection *Syn =
+ createMergeSynthetic(OutsecName, MS->Type, MS->Flags, Alignment);
+ MergeSections.push_back(Syn);
+ I = std::prev(MergeSections.end());
+ S = Syn;
+ Syn->Entsize = MS->Entsize;
+ } else {
+ S = nullptr;
+ }
+ (*I)->addSection(MS);
+ }
+ for (auto *MS : MergeSections)
+ MS->finalizeContents();
+
+ std::vector<InputSectionBase *> &V = InputSections;
+ V.erase(std::remove(V.begin(), V.end(), nullptr), V.end());
+}
+
+MipsRldMapSection::MipsRldMapSection()
+ : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Config->Wordsize,
+ ".rld_map") {}
+
+ARMExidxSentinelSection::ARMExidxSentinelSection()
+ : SyntheticSection(SHF_ALLOC | SHF_LINK_ORDER, SHT_ARM_EXIDX,
+ Config->Wordsize, ".ARM.exidx") {}
+
+// Write a terminating sentinel entry to the end of the .ARM.exidx table.
+// This section will have been sorted last in the .ARM.exidx table.
+// This table entry will have the form:
+// | PREL31 upper bound of code that has exception tables | EXIDX_CANTUNWIND |
+// The sentinel must have the PREL31 value of an address higher than any
+// address described by any other table entry.
+void ARMExidxSentinelSection::writeTo(uint8_t *Buf) {
+ assert(Highest);
+ uint64_t S = Highest->getVA(Highest->getSize());
+ uint64_t P = getVA();
+ Target->relocateOne(Buf, R_ARM_PREL31, S - P);
+ write32le(Buf + 4, 1);
+}
+
+// The sentinel has to be removed if there are no other .ARM.exidx entries.
+bool ARMExidxSentinelSection::empty() const {
+ for (InputSection *IS : getInputSections(getParent()))
+ if (!isa<ARMExidxSentinelSection>(IS))
+ return false;
+ return true;
+}
+
+bool ARMExidxSentinelSection::classof(const SectionBase *D) {
+ return D->kind() == InputSectionBase::Synthetic && D->Type == SHT_ARM_EXIDX;
+}
+
+ThunkSection::ThunkSection(OutputSection *OS, uint64_t Off)
+ : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS,
+ Config->Wordsize, ".text.thunk") {
+ this->Parent = OS;
+ this->OutSecOff = Off;
+}
+
+void ThunkSection::addThunk(Thunk *T) {
+ Thunks.push_back(T);
+ T->addSymbols(*this);
+}
+
+void ThunkSection::writeTo(uint8_t *Buf) {
+ for (Thunk *T : Thunks)
+ T->writeTo(Buf + T->Offset);
+}
+
+InputSection *ThunkSection::getTargetInputSection() const {
+ if (Thunks.empty())
+ return nullptr;
+ const Thunk *T = Thunks.front();
+ return T->getTargetInputSection();
+}
+
+bool ThunkSection::assignOffsets() {
+ uint64_t Off = 0;
+ for (Thunk *T : Thunks) {
+ Off = alignTo(Off, T->Alignment);
+ T->setOffset(Off);
+ uint32_t Size = T->size();
+ T->getThunkTargetSym()->Size = Size;
+ Off += Size;
+ }
+ bool Changed = Off != Size;
+ Size = Off;
+ return Changed;
+}
+
+// If linking position-dependent code then the table will store the addresses
+// directly in the binary so the section has type SHT_PROGBITS. If linking
+// position-independent code the section has type SHT_NOBITS since it will be
+// allocated and filled in by the dynamic linker.
+PPC64LongBranchTargetSection::PPC64LongBranchTargetSection()
+ : SyntheticSection(SHF_ALLOC | SHF_WRITE,
+ Config->Pic ? SHT_NOBITS : SHT_PROGBITS, 8,
+ ".branch_lt") {}
+
+void PPC64LongBranchTargetSection::addEntry(Symbol &Sym) {
+ assert(Sym.PPC64BranchltIndex == 0xffff);
+ Sym.PPC64BranchltIndex = Entries.size();
+ Entries.push_back(&Sym);
+}
+
+size_t PPC64LongBranchTargetSection::getSize() const {
+ return Entries.size() * 8;
+}
+
+void PPC64LongBranchTargetSection::writeTo(uint8_t *Buf) {
+ assert(Target->GotPltEntrySize == 8);
+ // If linking non-pic we have the final addresses of the targets and they get
+ // written to the table directly. For pic the dynamic linker will allocate
+ // the section and fill it it.
+ if (Config->Pic)
+ return;
+
+ for (const Symbol *Sym : Entries) {
+ assert(Sym->getVA());
+ // Need calls to branch to the local entry-point since a long-branch
+ // must be a local-call.
+ write64(Buf,
+ Sym->getVA() + getPPC64GlobalEntryToLocalEntryOffset(Sym->StOther));
+ Buf += Target->GotPltEntrySize;
+ }
+}
+
+bool PPC64LongBranchTargetSection::empty() const {
+ // `removeUnusedSyntheticSections()` is called before thunk allocation which
+ // is too early to determine if this section will be empty or not. We need
+ // Finalized to keep the section alive until after thunk creation. Finalized
+ // only gets set to true once `finalizeSections()` is called after thunk
+ // creation. Becuase of this, if we don't create any long-branch thunks we end
+ // up with an empty .branch_lt section in the binary.
+ return Finalized && Entries.empty();
+}
+
+InStruct elf::In;
+
+template GdbIndexSection *GdbIndexSection::create<ELF32LE>();
+template GdbIndexSection *GdbIndexSection::create<ELF32BE>();
+template GdbIndexSection *GdbIndexSection::create<ELF64LE>();
+template GdbIndexSection *GdbIndexSection::create<ELF64BE>();
+
+template void elf::splitSections<ELF32LE>();
+template void elf::splitSections<ELF32BE>();
+template void elf::splitSections<ELF64LE>();
+template void elf::splitSections<ELF64BE>();
+
+template void EhFrameSection::addSection<ELF32LE>(InputSectionBase *);
+template void EhFrameSection::addSection<ELF32BE>(InputSectionBase *);
+template void EhFrameSection::addSection<ELF64LE>(InputSectionBase *);
+template void EhFrameSection::addSection<ELF64BE>(InputSectionBase *);
+
+template void PltSection::addEntry<ELF32LE>(Symbol &Sym);
+template void PltSection::addEntry<ELF32BE>(Symbol &Sym);
+template void PltSection::addEntry<ELF64LE>(Symbol &Sym);
+template void PltSection::addEntry<ELF64BE>(Symbol &Sym);
+
+template void MipsGotSection::build<ELF32LE>();
+template void MipsGotSection::build<ELF32BE>();
+template void MipsGotSection::build<ELF64LE>();
+template void MipsGotSection::build<ELF64BE>();
+
+template class elf::MipsAbiFlagsSection<ELF32LE>;
+template class elf::MipsAbiFlagsSection<ELF32BE>;
+template class elf::MipsAbiFlagsSection<ELF64LE>;
+template class elf::MipsAbiFlagsSection<ELF64BE>;
+
+template class elf::MipsOptionsSection<ELF32LE>;
+template class elf::MipsOptionsSection<ELF32BE>;
+template class elf::MipsOptionsSection<ELF64LE>;
+template class elf::MipsOptionsSection<ELF64BE>;
+
+template class elf::MipsReginfoSection<ELF32LE>;
+template class elf::MipsReginfoSection<ELF32BE>;
+template class elf::MipsReginfoSection<ELF64LE>;
+template class elf::MipsReginfoSection<ELF64BE>;
+
+template class elf::DynamicSection<ELF32LE>;
+template class elf::DynamicSection<ELF32BE>;
+template class elf::DynamicSection<ELF64LE>;
+template class elf::DynamicSection<ELF64BE>;
+
+template class elf::RelocationSection<ELF32LE>;
+template class elf::RelocationSection<ELF32BE>;
+template class elf::RelocationSection<ELF64LE>;
+template class elf::RelocationSection<ELF64BE>;
+
+template class elf::AndroidPackedRelocationSection<ELF32LE>;
+template class elf::AndroidPackedRelocationSection<ELF32BE>;
+template class elf::AndroidPackedRelocationSection<ELF64LE>;
+template class elf::AndroidPackedRelocationSection<ELF64BE>;
+
+template class elf::RelrSection<ELF32LE>;
+template class elf::RelrSection<ELF32BE>;
+template class elf::RelrSection<ELF64LE>;
+template class elf::RelrSection<ELF64BE>;
+
+template class elf::SymbolTableSection<ELF32LE>;
+template class elf::SymbolTableSection<ELF32BE>;
+template class elf::SymbolTableSection<ELF64LE>;
+template class elf::SymbolTableSection<ELF64BE>;
+
+template class elf::VersionTableSection<ELF32LE>;
+template class elf::VersionTableSection<ELF32BE>;
+template class elf::VersionTableSection<ELF64LE>;
+template class elf::VersionTableSection<ELF64BE>;
+
+template class elf::VersionNeedSection<ELF32LE>;
+template class elf::VersionNeedSection<ELF32BE>;
+template class elf::VersionNeedSection<ELF64LE>;
+template class elf::VersionNeedSection<ELF64BE>;
diff --git a/contrib/llvm/tools/lld/ELF/SyntheticSections.h b/contrib/llvm/tools/lld/ELF/SyntheticSections.h
new file mode 100644
index 000000000000..6fc40d355d5e
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/SyntheticSections.h
@@ -0,0 +1,1043 @@
+//===- SyntheticSection.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Synthetic sections represent chunks of linker-created data. If you
+// need to create a chunk of data that to be included in some section
+// in the result, you probably want to create that as a synthetic section.
+//
+// Synthetic sections are designed as input sections as opposed to
+// output sections because we want to allow them to be manipulated
+// using linker scripts just like other input sections from regular
+// files.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_SYNTHETIC_SECTION_H
+#define LLD_ELF_SYNTHETIC_SECTION_H
+
+#include "DWARF.h"
+#include "EhFrame.h"
+#include "InputSection.h"
+#include "llvm/ADT/MapVector.h"
+#include "llvm/MC/StringTableBuilder.h"
+#include "llvm/Support/Endian.h"
+#include <functional>
+
+namespace lld {
+namespace elf {
+class Defined;
+class SharedSymbol;
+
+class SyntheticSection : public InputSection {
+public:
+ SyntheticSection(uint64_t Flags, uint32_t Type, uint32_t Alignment,
+ StringRef Name)
+ : InputSection(nullptr, Flags, Type, Alignment, {}, Name,
+ InputSectionBase::Synthetic) {
+ this->Live = true;
+ }
+
+ virtual ~SyntheticSection() = default;
+ virtual void writeTo(uint8_t *Buf) = 0;
+ virtual size_t getSize() const = 0;
+ virtual void finalizeContents() {}
+ // If the section has the SHF_ALLOC flag and the size may be changed if
+ // thunks are added, update the section size.
+ virtual bool updateAllocSize() { return false; }
+ virtual bool empty() const { return false; }
+
+ static bool classof(const SectionBase *D) {
+ return D->kind() == InputSectionBase::Synthetic;
+ }
+};
+
+struct CieRecord {
+ EhSectionPiece *Cie = nullptr;
+ std::vector<EhSectionPiece *> Fdes;
+};
+
+// Section for .eh_frame.
+class EhFrameSection final : public SyntheticSection {
+public:
+ EhFrameSection();
+ void writeTo(uint8_t *Buf) override;
+ void finalizeContents() override;
+ bool empty() const override { return Sections.empty(); }
+ size_t getSize() const override { return Size; }
+
+ template <class ELFT> void addSection(InputSectionBase *S);
+
+ std::vector<EhInputSection *> Sections;
+ size_t NumFdes = 0;
+
+ struct FdeData {
+ uint32_t PcRel;
+ uint32_t FdeVARel;
+ };
+
+ std::vector<FdeData> getFdeData() const;
+ ArrayRef<CieRecord *> getCieRecords() const { return CieRecords; }
+
+private:
+ // This is used only when parsing EhInputSection. We keep it here to avoid
+ // allocating one for each EhInputSection.
+ llvm::DenseMap<size_t, CieRecord *> OffsetToCie;
+
+ uint64_t Size = 0;
+
+ template <class ELFT, class RelTy>
+ void addSectionAux(EhInputSection *S, llvm::ArrayRef<RelTy> Rels);
+
+ template <class ELFT, class RelTy>
+ CieRecord *addCie(EhSectionPiece &Piece, ArrayRef<RelTy> Rels);
+
+ template <class ELFT, class RelTy>
+ bool isFdeLive(EhSectionPiece &Piece, ArrayRef<RelTy> Rels);
+
+ uint64_t getFdePc(uint8_t *Buf, size_t Off, uint8_t Enc) const;
+
+ std::vector<CieRecord *> CieRecords;
+
+ // CIE records are uniquified by their contents and personality functions.
+ llvm::DenseMap<std::pair<ArrayRef<uint8_t>, Symbol *>, CieRecord *> CieMap;
+};
+
+class GotSection : public SyntheticSection {
+public:
+ GotSection();
+ size_t getSize() const override { return Size; }
+ void finalizeContents() override;
+ bool empty() const override;
+ void writeTo(uint8_t *Buf) override;
+
+ void addEntry(Symbol &Sym);
+ bool addDynTlsEntry(Symbol &Sym);
+ bool addTlsIndex();
+ uint64_t getGlobalDynAddr(const Symbol &B) const;
+ uint64_t getGlobalDynOffset(const Symbol &B) const;
+
+ uint64_t getTlsIndexVA() { return this->getVA() + TlsIndexOff; }
+ uint32_t getTlsIndexOff() const { return TlsIndexOff; }
+
+ // Flag to force GOT to be in output if we have relocations
+ // that relies on its address.
+ bool HasGotOffRel = false;
+
+protected:
+ size_t NumEntries = 0;
+ uint32_t TlsIndexOff = -1;
+ uint64_t Size = 0;
+};
+
+// .note.GNU-stack section.
+class GnuStackSection : public SyntheticSection {
+public:
+ GnuStackSection()
+ : SyntheticSection(0, llvm::ELF::SHT_PROGBITS, 1, ".note.GNU-stack") {}
+ void writeTo(uint8_t *Buf) override {}
+ size_t getSize() const override { return 0; }
+};
+
+// .note.gnu.build-id section.
+class BuildIdSection : public SyntheticSection {
+ // First 16 bytes are a header.
+ static const unsigned HeaderSize = 16;
+
+public:
+ BuildIdSection();
+ void writeTo(uint8_t *Buf) override;
+ size_t getSize() const override { return HeaderSize + HashSize; }
+ void writeBuildId(llvm::ArrayRef<uint8_t> Buf);
+
+private:
+ void computeHash(llvm::ArrayRef<uint8_t> Buf,
+ std::function<void(uint8_t *, ArrayRef<uint8_t>)> Hash);
+
+ size_t HashSize;
+ uint8_t *HashBuf;
+};
+
+// BssSection is used to reserve space for copy relocations and common symbols.
+// We create three instances of this class for .bss, .bss.rel.ro and "COMMON",
+// that are used for writable symbols, read-only symbols and common symbols,
+// respectively.
+class BssSection final : public SyntheticSection {
+public:
+ BssSection(StringRef Name, uint64_t Size, uint32_t Alignment);
+ void writeTo(uint8_t *) override {
+ llvm_unreachable("unexpected writeTo() call for SHT_NOBITS section");
+ }
+ bool empty() const override { return getSize() == 0; }
+ size_t getSize() const override { return Size; }
+
+ static bool classof(const SectionBase *S) { return S->Bss; }
+ uint64_t Size;
+};
+
+class MipsGotSection final : public SyntheticSection {
+public:
+ MipsGotSection();
+ void writeTo(uint8_t *Buf) override;
+ size_t getSize() const override { return Size; }
+ bool updateAllocSize() override;
+ void finalizeContents() override;
+ bool empty() const override;
+
+ // Join separate GOTs built for each input file to generate
+ // primary and optional multiple secondary GOTs.
+ template <class ELFT> void build();
+
+ void addEntry(InputFile &File, Symbol &Sym, int64_t Addend, RelExpr Expr);
+ void addDynTlsEntry(InputFile &File, Symbol &Sym);
+ void addTlsIndex(InputFile &File);
+
+ uint64_t getPageEntryOffset(const InputFile *F, const Symbol &S,
+ int64_t Addend) const;
+ uint64_t getSymEntryOffset(const InputFile *F, const Symbol &S,
+ int64_t Addend) const;
+ uint64_t getGlobalDynOffset(const InputFile *F, const Symbol &S) const;
+ uint64_t getTlsIndexOffset(const InputFile *F) const;
+
+ // Returns the symbol which corresponds to the first entry of the global part
+ // of GOT on MIPS platform. It is required to fill up MIPS-specific dynamic
+ // table properties.
+ // Returns nullptr if the global part is empty.
+ const Symbol *getFirstGlobalEntry() const;
+
+ // Returns the number of entries in the local part of GOT including
+ // the number of reserved entries.
+ unsigned getLocalEntriesNum() const;
+
+ // Return _gp value for primary GOT (nullptr) or particular input file.
+ uint64_t getGp(const InputFile *F = nullptr) const;
+
+private:
+ // MIPS GOT consists of three parts: local, global and tls. Each part
+ // contains different types of entries. Here is a layout of GOT:
+ // - Header entries |
+ // - Page entries | Local part
+ // - Local entries (16-bit access) |
+ // - Local entries (32-bit access) |
+ // - Normal global entries || Global part
+ // - Reloc-only global entries ||
+ // - TLS entries ||| TLS part
+ //
+ // Header:
+ // Two entries hold predefined value 0x0 and 0x80000000.
+ // Page entries:
+ // These entries created by R_MIPS_GOT_PAGE relocation and R_MIPS_GOT16
+ // relocation against local symbols. They are initialized by higher 16-bit
+ // of the corresponding symbol's value. So each 64kb of address space
+ // requires a single GOT entry.
+ // Local entries (16-bit access):
+ // These entries created by GOT relocations against global non-preemptible
+ // symbols so dynamic linker is not necessary to resolve the symbol's
+ // values. "16-bit access" means that corresponding relocations address
+ // GOT using 16-bit index. Each unique Symbol-Addend pair has its own
+ // GOT entry.
+ // Local entries (32-bit access):
+ // These entries are the same as above but created by relocations which
+ // address GOT using 32-bit index (R_MIPS_GOT_HI16/LO16 etc).
+ // Normal global entries:
+ // These entries created by GOT relocations against preemptible global
+ // symbols. They need to be initialized by dynamic linker and they ordered
+ // exactly as the corresponding entries in the dynamic symbols table.
+ // Reloc-only global entries:
+ // These entries created for symbols that are referenced by dynamic
+ // relocations R_MIPS_REL32. These entries are not accessed with gp-relative
+ // addressing, but MIPS ABI requires that these entries be present in GOT.
+ // TLS entries:
+ // Entries created by TLS relocations.
+ //
+ // If the sum of local, global and tls entries is less than 64K only single
+ // got is enough. Otherwise, multi-got is created. Series of primary and
+ // multiple secondary GOTs have the following layout:
+ // - Primary GOT
+ // Header
+ // Local entries
+ // Global entries
+ // Relocation only entries
+ // TLS entries
+ //
+ // - Secondary GOT
+ // Local entries
+ // Global entries
+ // TLS entries
+ // ...
+ //
+ // All GOT entries required by relocations from a single input file entirely
+ // belong to either primary or one of secondary GOTs. To reference GOT entries
+ // each GOT has its own _gp value points to the "middle" of the GOT.
+ // In the code this value loaded to the register which is used for GOT access.
+ //
+ // MIPS 32 function's prologue:
+ // lui v0,0x0
+ // 0: R_MIPS_HI16 _gp_disp
+ // addiu v0,v0,0
+ // 4: R_MIPS_LO16 _gp_disp
+ //
+ // MIPS 64:
+ // lui at,0x0
+ // 14: R_MIPS_GPREL16 main
+ //
+ // Dynamic linker does not know anything about secondary GOTs and cannot
+ // use a regular MIPS mechanism for GOT entries initialization. So we have
+ // to use an approach accepted by other architectures and create dynamic
+ // relocations R_MIPS_REL32 to initialize global entries (and local in case
+ // of PIC code) in secondary GOTs. But ironically MIPS dynamic linker
+ // requires GOT entries and correspondingly ordered dynamic symbol table
+ // entries to deal with dynamic relocations. To handle this problem
+ // relocation-only section in the primary GOT contains entries for all
+ // symbols referenced in global parts of secondary GOTs. Although the sum
+ // of local and normal global entries of the primary got should be less
+ // than 64K, the size of the primary got (including relocation-only entries
+ // can be greater than 64K, because parts of the primary got that overflow
+ // the 64K limit are used only by the dynamic linker at dynamic link-time
+ // and not by 16-bit gp-relative addressing at run-time.
+ //
+ // For complete multi-GOT description see the following link
+ // https://dmz-portal.mips.com/wiki/MIPS_Multi_GOT
+
+ // Number of "Header" entries.
+ static const unsigned HeaderEntriesNum = 2;
+
+ uint64_t Size = 0;
+
+ // Symbol and addend.
+ typedef std::pair<Symbol *, int64_t> GotEntry;
+
+ struct FileGot {
+ InputFile *File = nullptr;
+ size_t StartIndex = 0;
+
+ struct PageBlock {
+ size_t FirstIndex = 0;
+ size_t Count = 0;
+ };
+
+ // Map output sections referenced by MIPS GOT relocations
+ // to the description (index/count) "page" entries allocated
+ // for this section.
+ llvm::SmallMapVector<const OutputSection *, PageBlock, 16> PagesMap;
+ // Maps from Symbol+Addend pair or just Symbol to the GOT entry index.
+ llvm::MapVector<GotEntry, size_t> Local16;
+ llvm::MapVector<GotEntry, size_t> Local32;
+ llvm::MapVector<Symbol *, size_t> Global;
+ llvm::MapVector<Symbol *, size_t> Relocs;
+ llvm::MapVector<Symbol *, size_t> Tls;
+ // Set of symbols referenced by dynamic TLS relocations.
+ llvm::MapVector<Symbol *, size_t> DynTlsSymbols;
+
+ // Total number of all entries.
+ size_t getEntriesNum() const;
+ // Number of "page" entries.
+ size_t getPageEntriesNum() const;
+ // Number of entries require 16-bit index to access.
+ size_t getIndexedEntriesNum() const;
+ };
+
+ // Container of GOT created for each input file.
+ // After building a final series of GOTs this container
+ // holds primary and secondary GOT's.
+ std::vector<FileGot> Gots;
+
+ // Return (and create if necessary) `FileGot`.
+ FileGot &getGot(InputFile &F);
+
+ // Try to merge two GOTs. In case of success the `Dst` contains
+ // result of merging and the function returns true. In case of
+ // ovwerflow the `Dst` is unchanged and the function returns false.
+ bool tryMergeGots(FileGot & Dst, FileGot & Src, bool IsPrimary);
+};
+
+class GotPltSection final : public SyntheticSection {
+public:
+ GotPltSection();
+ void addEntry(Symbol &Sym);
+ size_t getSize() const override;
+ void writeTo(uint8_t *Buf) override;
+ bool empty() const override;
+
+private:
+ std::vector<const Symbol *> Entries;
+};
+
+// The IgotPltSection is a Got associated with the PltSection for GNU Ifunc
+// Symbols that will be relocated by Target->IRelativeRel.
+// On most Targets the IgotPltSection will immediately follow the GotPltSection
+// on ARM the IgotPltSection will immediately follow the GotSection.
+class IgotPltSection final : public SyntheticSection {
+public:
+ IgotPltSection();
+ void addEntry(Symbol &Sym);
+ size_t getSize() const override;
+ void writeTo(uint8_t *Buf) override;
+ bool empty() const override { return Entries.empty(); }
+
+private:
+ std::vector<const Symbol *> Entries;
+};
+
+class StringTableSection final : public SyntheticSection {
+public:
+ StringTableSection(StringRef Name, bool Dynamic);
+ unsigned addString(StringRef S, bool HashIt = true);
+ void writeTo(uint8_t *Buf) override;
+ size_t getSize() const override { return Size; }
+ bool isDynamic() const { return Dynamic; }
+
+private:
+ const bool Dynamic;
+
+ uint64_t Size = 0;
+
+ llvm::DenseMap<StringRef, unsigned> StringMap;
+ std::vector<StringRef> Strings;
+};
+
+class DynamicReloc {
+public:
+ DynamicReloc(RelType Type, const InputSectionBase *InputSec,
+ uint64_t OffsetInSec, bool UseSymVA, Symbol *Sym, int64_t Addend)
+ : Type(Type), Sym(Sym), InputSec(InputSec), OffsetInSec(OffsetInSec),
+ UseSymVA(UseSymVA), Addend(Addend), OutputSec(nullptr) {}
+ // This constructor records dynamic relocation settings used by MIPS
+ // multi-GOT implementation. It's to relocate addresses of 64kb pages
+ // lie inside the output section.
+ DynamicReloc(RelType Type, const InputSectionBase *InputSec,
+ uint64_t OffsetInSec, const OutputSection *OutputSec,
+ int64_t Addend)
+ : Type(Type), Sym(nullptr), InputSec(InputSec), OffsetInSec(OffsetInSec),
+ UseSymVA(false), Addend(Addend), OutputSec(OutputSec) {}
+
+ uint64_t getOffset() const;
+ uint32_t getSymIndex() const;
+ const InputSectionBase *getInputSec() const { return InputSec; }
+
+ // Computes the addend of the dynamic relocation. Note that this is not the
+ // same as the Addend member variable as it also includes the symbol address
+ // if UseSymVA is true.
+ int64_t computeAddend() const;
+
+ RelType Type;
+
+private:
+ Symbol *Sym;
+ const InputSectionBase *InputSec = nullptr;
+ uint64_t OffsetInSec;
+ // If this member is true, the dynamic relocation will not be against the
+ // symbol but will instead be a relative relocation that simply adds the
+ // load address. This means we need to write the symbol virtual address
+ // plus the original addend as the final relocation addend.
+ bool UseSymVA;
+ int64_t Addend;
+ const OutputSection *OutputSec;
+};
+
+template <class ELFT> class DynamicSection final : public SyntheticSection {
+ typedef typename ELFT::Dyn Elf_Dyn;
+ typedef typename ELFT::Rel Elf_Rel;
+ typedef typename ELFT::Rela Elf_Rela;
+ typedef typename ELFT::Relr Elf_Relr;
+ typedef typename ELFT::Shdr Elf_Shdr;
+ typedef typename ELFT::Sym Elf_Sym;
+
+ // finalizeContents() fills this vector with the section contents.
+ std::vector<std::pair<int32_t, std::function<uint64_t()>>> Entries;
+
+public:
+ DynamicSection();
+ void finalizeContents() override;
+ void writeTo(uint8_t *Buf) override;
+ size_t getSize() const override { return Size; }
+
+private:
+ void add(int32_t Tag, std::function<uint64_t()> Fn);
+ void addInt(int32_t Tag, uint64_t Val);
+ void addInSec(int32_t Tag, InputSection *Sec);
+ void addInSecRelative(int32_t Tag, InputSection *Sec);
+ void addOutSec(int32_t Tag, OutputSection *Sec);
+ void addSize(int32_t Tag, OutputSection *Sec);
+ void addSym(int32_t Tag, Symbol *Sym);
+
+ uint64_t Size = 0;
+};
+
+class RelocationBaseSection : public SyntheticSection {
+public:
+ RelocationBaseSection(StringRef Name, uint32_t Type, int32_t DynamicTag,
+ int32_t SizeDynamicTag);
+ void addReloc(RelType DynType, InputSectionBase *IS, uint64_t OffsetInSec,
+ Symbol *Sym);
+ // Add a dynamic relocation that might need an addend. This takes care of
+ // writing the addend to the output section if needed.
+ void addReloc(RelType DynType, InputSectionBase *InputSec,
+ uint64_t OffsetInSec, Symbol *Sym, int64_t Addend, RelExpr Expr,
+ RelType Type);
+ void addReloc(const DynamicReloc &Reloc);
+ bool empty() const override { return Relocs.empty(); }
+ size_t getSize() const override { return Relocs.size() * this->Entsize; }
+ size_t getRelativeRelocCount() const { return NumRelativeRelocs; }
+ void finalizeContents() override;
+ int32_t DynamicTag, SizeDynamicTag;
+
+protected:
+ std::vector<DynamicReloc> Relocs;
+ size_t NumRelativeRelocs = 0;
+};
+
+template <class ELFT>
+class RelocationSection final : public RelocationBaseSection {
+ typedef typename ELFT::Rel Elf_Rel;
+ typedef typename ELFT::Rela Elf_Rela;
+
+public:
+ RelocationSection(StringRef Name, bool Sort);
+ unsigned getRelocOffset();
+ void writeTo(uint8_t *Buf) override;
+
+private:
+ bool Sort;
+};
+
+template <class ELFT>
+class AndroidPackedRelocationSection final : public RelocationBaseSection {
+ typedef typename ELFT::Rel Elf_Rel;
+ typedef typename ELFT::Rela Elf_Rela;
+
+public:
+ AndroidPackedRelocationSection(StringRef Name);
+
+ bool updateAllocSize() override;
+ size_t getSize() const override { return RelocData.size(); }
+ void writeTo(uint8_t *Buf) override {
+ memcpy(Buf, RelocData.data(), RelocData.size());
+ }
+
+private:
+ SmallVector<char, 0> RelocData;
+};
+
+struct RelativeReloc {
+ uint64_t getOffset() const { return InputSec->getVA(OffsetInSec); }
+
+ const InputSectionBase *InputSec;
+ uint64_t OffsetInSec;
+};
+
+class RelrBaseSection : public SyntheticSection {
+public:
+ RelrBaseSection();
+ bool empty() const override { return Relocs.empty(); }
+ std::vector<RelativeReloc> Relocs;
+};
+
+// RelrSection is used to encode offsets for relative relocations.
+// Proposal for adding SHT_RELR sections to generic-abi is here:
+// https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg
+// For more details, see the comment in RelrSection::updateAllocSize().
+template <class ELFT> class RelrSection final : public RelrBaseSection {
+ typedef typename ELFT::Relr Elf_Relr;
+
+public:
+ RelrSection();
+
+ bool updateAllocSize() override;
+ size_t getSize() const override { return RelrRelocs.size() * this->Entsize; }
+ void writeTo(uint8_t *Buf) override {
+ memcpy(Buf, RelrRelocs.data(), getSize());
+ }
+
+private:
+ std::vector<Elf_Relr> RelrRelocs;
+};
+
+struct SymbolTableEntry {
+ Symbol *Sym;
+ size_t StrTabOffset;
+};
+
+class SymbolTableBaseSection : public SyntheticSection {
+public:
+ SymbolTableBaseSection(StringTableSection &StrTabSec);
+ void finalizeContents() override;
+ size_t getSize() const override { return getNumSymbols() * Entsize; }
+ void addSymbol(Symbol *Sym);
+ unsigned getNumSymbols() const { return Symbols.size() + 1; }
+ size_t getSymbolIndex(Symbol *Sym);
+ ArrayRef<SymbolTableEntry> getSymbols() const { return Symbols; }
+
+protected:
+ void sortSymTabSymbols();
+
+ // A vector of symbols and their string table offsets.
+ std::vector<SymbolTableEntry> Symbols;
+
+ StringTableSection &StrTabSec;
+
+ llvm::once_flag OnceFlag;
+ llvm::DenseMap<Symbol *, size_t> SymbolIndexMap;
+ llvm::DenseMap<OutputSection *, size_t> SectionIndexMap;
+};
+
+template <class ELFT>
+class SymbolTableSection final : public SymbolTableBaseSection {
+ typedef typename ELFT::Sym Elf_Sym;
+
+public:
+ SymbolTableSection(StringTableSection &StrTabSec);
+ void writeTo(uint8_t *Buf) override;
+};
+
+class SymtabShndxSection final : public SyntheticSection {
+public:
+ SymtabShndxSection();
+
+ void writeTo(uint8_t *Buf) override;
+ size_t getSize() const override;
+ bool empty() const override;
+ void finalizeContents() override;
+};
+
+// Outputs GNU Hash section. For detailed explanation see:
+// https://blogs.oracle.com/ali/entry/gnu_hash_elf_sections
+class GnuHashTableSection final : public SyntheticSection {
+public:
+ GnuHashTableSection();
+ void finalizeContents() override;
+ void writeTo(uint8_t *Buf) override;
+ size_t getSize() const override { return Size; }
+
+ // Adds symbols to the hash table.
+ // Sorts the input to satisfy GNU hash section requirements.
+ void addSymbols(std::vector<SymbolTableEntry> &Symbols);
+
+private:
+ // See the comment in writeBloomFilter.
+ enum { Shift2 = 26 };
+
+ void writeBloomFilter(uint8_t *Buf);
+ void writeHashTable(uint8_t *Buf);
+
+ struct Entry {
+ Symbol *Sym;
+ size_t StrTabOffset;
+ uint32_t Hash;
+ uint32_t BucketIdx;
+ };
+
+ std::vector<Entry> Symbols;
+ size_t MaskWords;
+ size_t NBuckets = 0;
+ size_t Size = 0;
+};
+
+class HashTableSection final : public SyntheticSection {
+public:
+ HashTableSection();
+ void finalizeContents() override;
+ void writeTo(uint8_t *Buf) override;
+ size_t getSize() const override { return Size; }
+
+private:
+ size_t Size = 0;
+};
+
+// The PltSection is used for both the Plt and Iplt. The former usually has a
+// header as its first entry that is used at run-time to resolve lazy binding.
+// The latter is used for GNU Ifunc symbols, that will be subject to a
+// Target->IRelativeRel.
+class PltSection : public SyntheticSection {
+public:
+ PltSection(bool IsIplt);
+ void writeTo(uint8_t *Buf) override;
+ size_t getSize() const override;
+ bool empty() const override { return Entries.empty(); }
+ void addSymbols();
+ template <class ELFT> void addEntry(Symbol &Sym);
+
+ size_t HeaderSize;
+
+private:
+ unsigned getPltRelocOff() const;
+ std::vector<std::pair<const Symbol *, unsigned>> Entries;
+ bool IsIplt;
+};
+
+class GdbIndexSection final : public SyntheticSection {
+public:
+ struct AddressEntry {
+ InputSection *Section;
+ uint64_t LowAddress;
+ uint64_t HighAddress;
+ uint32_t CuIndex;
+ };
+
+ struct CuEntry {
+ uint64_t CuOffset;
+ uint64_t CuLength;
+ };
+
+ struct NameAttrEntry {
+ llvm::CachedHashStringRef Name;
+ uint32_t CuIndexAndAttrs;
+ };
+
+ struct GdbChunk {
+ InputSection *Sec;
+ std::vector<AddressEntry> AddressAreas;
+ std::vector<CuEntry> CompilationUnits;
+ };
+
+ struct GdbSymbol {
+ llvm::CachedHashStringRef Name;
+ std::vector<uint32_t> CuVector;
+ uint32_t NameOff;
+ uint32_t CuVectorOff;
+ };
+
+ GdbIndexSection();
+ template <typename ELFT> static GdbIndexSection *create();
+ void writeTo(uint8_t *Buf) override;
+ size_t getSize() const override { return Size; }
+ bool empty() const override;
+
+private:
+ struct GdbIndexHeader {
+ llvm::support::ulittle32_t Version;
+ llvm::support::ulittle32_t CuListOff;
+ llvm::support::ulittle32_t CuTypesOff;
+ llvm::support::ulittle32_t AddressAreaOff;
+ llvm::support::ulittle32_t SymtabOff;
+ llvm::support::ulittle32_t ConstantPoolOff;
+ };
+
+ void initOutputSize();
+ size_t computeSymtabSize() const;
+
+ // Each chunk contains information gathered from debug sections of a
+ // single object file.
+ std::vector<GdbChunk> Chunks;
+
+ // A symbol table for this .gdb_index section.
+ std::vector<GdbSymbol> Symbols;
+
+ size_t Size;
+};
+
+// --eh-frame-hdr option tells linker to construct a header for all the
+// .eh_frame sections. This header is placed to a section named .eh_frame_hdr
+// and also to a PT_GNU_EH_FRAME segment.
+// At runtime the unwinder then can find all the PT_GNU_EH_FRAME segments by
+// calling dl_iterate_phdr.
+// This section contains a lookup table for quick binary search of FDEs.
+// Detailed info about internals can be found in Ian Lance Taylor's blog:
+// http://www.airs.com/blog/archives/460 (".eh_frame")
+// http://www.airs.com/blog/archives/462 (".eh_frame_hdr")
+class EhFrameHeader final : public SyntheticSection {
+public:
+ EhFrameHeader();
+ void writeTo(uint8_t *Buf) override;
+ size_t getSize() const override;
+ bool empty() const override;
+};
+
+// For more information about .gnu.version and .gnu.version_r see:
+// https://www.akkadia.org/drepper/symbol-versioning
+
+// The .gnu.version_d section which has a section type of SHT_GNU_verdef shall
+// contain symbol version definitions. The number of entries in this section
+// shall be contained in the DT_VERDEFNUM entry of the .dynamic section.
+// The section shall contain an array of Elf_Verdef structures, optionally
+// followed by an array of Elf_Verdaux structures.
+class VersionDefinitionSection final : public SyntheticSection {
+public:
+ VersionDefinitionSection();
+ void finalizeContents() override;
+ size_t getSize() const override;
+ void writeTo(uint8_t *Buf) override;
+
+private:
+ enum { EntrySize = 28 };
+ void writeOne(uint8_t *Buf, uint32_t Index, StringRef Name, size_t NameOff);
+
+ unsigned FileDefNameOff;
+};
+
+// The .gnu.version section specifies the required version of each symbol in the
+// dynamic symbol table. It contains one Elf_Versym for each dynamic symbol
+// table entry. An Elf_Versym is just a 16-bit integer that refers to a version
+// identifier defined in the either .gnu.version_r or .gnu.version_d section.
+// The values 0 and 1 are reserved. All other values are used for versions in
+// the own object or in any of the dependencies.
+template <class ELFT>
+class VersionTableSection final : public SyntheticSection {
+public:
+ VersionTableSection();
+ void finalizeContents() override;
+ size_t getSize() const override;
+ void writeTo(uint8_t *Buf) override;
+ bool empty() const override;
+};
+
+// The .gnu.version_r section defines the version identifiers used by
+// .gnu.version. It contains a linked list of Elf_Verneed data structures. Each
+// Elf_Verneed specifies the version requirements for a single DSO, and contains
+// a reference to a linked list of Elf_Vernaux data structures which define the
+// mapping from version identifiers to version names.
+template <class ELFT> class VersionNeedSection final : public SyntheticSection {
+ typedef typename ELFT::Verneed Elf_Verneed;
+ typedef typename ELFT::Vernaux Elf_Vernaux;
+
+ // A vector of shared files that need Elf_Verneed data structures and the
+ // string table offsets of their sonames.
+ std::vector<std::pair<SharedFile<ELFT> *, size_t>> Needed;
+
+ // The next available version identifier.
+ unsigned NextIndex;
+
+public:
+ VersionNeedSection();
+ void addSymbol(Symbol *Sym);
+ void finalizeContents() override;
+ void writeTo(uint8_t *Buf) override;
+ size_t getSize() const override;
+ size_t getNeedNum() const { return Needed.size(); }
+ bool empty() const override;
+};
+
+// MergeSyntheticSection is a class that allows us to put mergeable sections
+// with different attributes in a single output sections. To do that
+// we put them into MergeSyntheticSection synthetic input sections which are
+// attached to regular output sections.
+class MergeSyntheticSection : public SyntheticSection {
+public:
+ void addSection(MergeInputSection *MS);
+ std::vector<MergeInputSection *> Sections;
+
+protected:
+ MergeSyntheticSection(StringRef Name, uint32_t Type, uint64_t Flags,
+ uint32_t Alignment)
+ : SyntheticSection(Flags, Type, Alignment, Name) {}
+};
+
+class MergeTailSection final : public MergeSyntheticSection {
+public:
+ MergeTailSection(StringRef Name, uint32_t Type, uint64_t Flags,
+ uint32_t Alignment);
+
+ size_t getSize() const override;
+ void writeTo(uint8_t *Buf) override;
+ void finalizeContents() override;
+
+private:
+ llvm::StringTableBuilder Builder;
+};
+
+class MergeNoTailSection final : public MergeSyntheticSection {
+public:
+ MergeNoTailSection(StringRef Name, uint32_t Type, uint64_t Flags,
+ uint32_t Alignment)
+ : MergeSyntheticSection(Name, Type, Flags, Alignment) {}
+
+ size_t getSize() const override { return Size; }
+ void writeTo(uint8_t *Buf) override;
+ void finalizeContents() override;
+
+private:
+ // We use the most significant bits of a hash as a shard ID.
+ // The reason why we don't want to use the least significant bits is
+ // because DenseMap also uses lower bits to determine a bucket ID.
+ // If we use lower bits, it significantly increases the probability of
+ // hash collisons.
+ size_t getShardId(uint32_t Hash) {
+ return Hash >> (32 - llvm::countTrailingZeros(NumShards));
+ }
+
+ // Section size
+ size_t Size;
+
+ // String table contents
+ constexpr static size_t NumShards = 32;
+ std::vector<llvm::StringTableBuilder> Shards;
+ size_t ShardOffsets[NumShards];
+};
+
+// .MIPS.abiflags section.
+template <class ELFT>
+class MipsAbiFlagsSection final : public SyntheticSection {
+ typedef llvm::object::Elf_Mips_ABIFlags<ELFT> Elf_Mips_ABIFlags;
+
+public:
+ static MipsAbiFlagsSection *create();
+
+ MipsAbiFlagsSection(Elf_Mips_ABIFlags Flags);
+ size_t getSize() const override { return sizeof(Elf_Mips_ABIFlags); }
+ void writeTo(uint8_t *Buf) override;
+
+private:
+ Elf_Mips_ABIFlags Flags;
+};
+
+// .MIPS.options section.
+template <class ELFT> class MipsOptionsSection final : public SyntheticSection {
+ typedef llvm::object::Elf_Mips_Options<ELFT> Elf_Mips_Options;
+ typedef llvm::object::Elf_Mips_RegInfo<ELFT> Elf_Mips_RegInfo;
+
+public:
+ static MipsOptionsSection *create();
+
+ MipsOptionsSection(Elf_Mips_RegInfo Reginfo);
+ void writeTo(uint8_t *Buf) override;
+
+ size_t getSize() const override {
+ return sizeof(Elf_Mips_Options) + sizeof(Elf_Mips_RegInfo);
+ }
+
+private:
+ Elf_Mips_RegInfo Reginfo;
+};
+
+// MIPS .reginfo section.
+template <class ELFT> class MipsReginfoSection final : public SyntheticSection {
+ typedef llvm::object::Elf_Mips_RegInfo<ELFT> Elf_Mips_RegInfo;
+
+public:
+ static MipsReginfoSection *create();
+
+ MipsReginfoSection(Elf_Mips_RegInfo Reginfo);
+ size_t getSize() const override { return sizeof(Elf_Mips_RegInfo); }
+ void writeTo(uint8_t *Buf) override;
+
+private:
+ Elf_Mips_RegInfo Reginfo;
+};
+
+// This is a MIPS specific section to hold a space within the data segment
+// of executable file which is pointed to by the DT_MIPS_RLD_MAP entry.
+// See "Dynamic section" in Chapter 5 in the following document:
+// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+class MipsRldMapSection : public SyntheticSection {
+public:
+ MipsRldMapSection();
+ size_t getSize() const override { return Config->Wordsize; }
+ void writeTo(uint8_t *Buf) override {}
+};
+
+class ARMExidxSentinelSection : public SyntheticSection {
+public:
+ ARMExidxSentinelSection();
+ size_t getSize() const override { return 8; }
+ void writeTo(uint8_t *Buf) override;
+ bool empty() const override;
+
+ static bool classof(const SectionBase *D);
+
+ // The last section referenced by a regular .ARM.exidx section.
+ // It is found and filled in Writer<ELFT>::resolveShfLinkOrder().
+ // The sentinel points at the end of that section.
+ InputSection *Highest = nullptr;
+};
+
+// A container for one or more linker generated thunks. Instances of these
+// thunks including ARM interworking and Mips LA25 PI to non-PI thunks.
+class ThunkSection : public SyntheticSection {
+public:
+ // ThunkSection in OS, with desired OutSecOff of Off
+ ThunkSection(OutputSection *OS, uint64_t Off);
+
+ // Add a newly created Thunk to this container:
+ // Thunk is given offset from start of this InputSection
+ // Thunk defines a symbol in this InputSection that can be used as target
+ // of a relocation
+ void addThunk(Thunk *T);
+ size_t getSize() const override { return Size; }
+ void writeTo(uint8_t *Buf) override;
+ InputSection *getTargetInputSection() const;
+ bool assignOffsets();
+
+private:
+ std::vector<Thunk *> Thunks;
+ size_t Size = 0;
+};
+
+// This section is used to store the addresses of functions that are called
+// in range-extending thunks on PowerPC64. When producing position dependant
+// code the addresses are link-time constants and the table is written out to
+// the binary. When producing position-dependant code the table is allocated and
+// filled in by the dynamic linker.
+class PPC64LongBranchTargetSection final : public SyntheticSection {
+public:
+ PPC64LongBranchTargetSection();
+ void addEntry(Symbol &Sym);
+ size_t getSize() const override;
+ void writeTo(uint8_t *Buf) override;
+ bool empty() const override;
+ void finalizeContents() override { Finalized = true; }
+
+private:
+ std::vector<const Symbol *> Entries;
+ bool Finalized = false;
+};
+
+InputSection *createInterpSection();
+MergeInputSection *createCommentSection();
+template <class ELFT> void splitSections();
+void mergeSections();
+
+Defined *addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value,
+ uint64_t Size, InputSectionBase &Section);
+
+// Linker generated sections which can be used as inputs.
+struct InStruct {
+ InputSection *ARMAttributes;
+ BssSection *Bss;
+ BssSection *BssRelRo;
+ BuildIdSection *BuildId;
+ EhFrameHeader *EhFrameHdr;
+ EhFrameSection *EhFrame;
+ SyntheticSection *Dynamic;
+ StringTableSection *DynStrTab;
+ SymbolTableBaseSection *DynSymTab;
+ GnuHashTableSection *GnuHashTab;
+ HashTableSection *HashTab;
+ InputSection *Interp;
+ GdbIndexSection *GdbIndex;
+ GotSection *Got;
+ GotPltSection *GotPlt;
+ IgotPltSection *IgotPlt;
+ PPC64LongBranchTargetSection *PPC64LongBranchTarget;
+ MipsGotSection *MipsGot;
+ MipsRldMapSection *MipsRldMap;
+ PltSection *Plt;
+ PltSection *Iplt;
+ RelocationBaseSection *RelaDyn;
+ RelrBaseSection *RelrDyn;
+ RelocationBaseSection *RelaPlt;
+ RelocationBaseSection *RelaIplt;
+ StringTableSection *ShStrTab;
+ StringTableSection *StrTab;
+ SymbolTableBaseSection *SymTab;
+ SymtabShndxSection *SymTabShndx;
+ VersionDefinitionSection *VerDef;
+};
+
+extern InStruct In;
+
+template <class ELFT> struct InX {
+ static VersionTableSection<ELFT> *VerSym;
+ static VersionNeedSection<ELFT> *VerNeed;
+};
+
+template <class ELFT> VersionTableSection<ELFT> *InX<ELFT>::VerSym;
+template <class ELFT> VersionNeedSection<ELFT> *InX<ELFT>::VerNeed;
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/ELF/Target.cpp b/contrib/llvm/tools/lld/ELF/Target.cpp
new file mode 100644
index 000000000000..01073a62cfd6
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Target.cpp
@@ -0,0 +1,184 @@
+//===- Target.cpp ---------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Machine-specific things, such as applying relocations, creation of
+// GOT or PLT entries, etc., are handled in this file.
+//
+// Refer the ELF spec for the single letter variables, S, A or P, used
+// in this file.
+//
+// Some functions defined in this file has "relaxTls" as part of their names.
+// They do peephole optimization for TLS variables by rewriting instructions.
+// They are not part of the ABI but optional optimization, so you can skip
+// them if you are not interested in how TLS variables are optimized.
+// See the following paper for the details.
+//
+// Ulrich Drepper, ELF Handling For Thread-Local Storage
+// http://www.akkadia.org/drepper/tls.pdf
+//
+//===----------------------------------------------------------------------===//
+
+#include "Target.h"
+#include "InputFiles.h"
+#include "OutputSections.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+#include "lld/Common/ErrorHandler.h"
+#include "llvm/Object/ELF.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+TargetInfo *elf::Target;
+
+std::string lld::toString(RelType Type) {
+ StringRef S = getELFRelocationTypeName(elf::Config->EMachine, Type);
+ if (S == "Unknown")
+ return ("Unknown (" + Twine(Type) + ")").str();
+ return S;
+}
+
+TargetInfo *elf::getTarget() {
+ switch (Config->EMachine) {
+ case EM_386:
+ case EM_IAMCU:
+ return getX86TargetInfo();
+ case EM_AARCH64:
+ return getAArch64TargetInfo();
+ case EM_AMDGPU:
+ return getAMDGPUTargetInfo();
+ case EM_ARM:
+ return getARMTargetInfo();
+ case EM_AVR:
+ return getAVRTargetInfo();
+ case EM_HEXAGON:
+ return getHexagonTargetInfo();
+ case EM_MIPS:
+ switch (Config->EKind) {
+ case ELF32LEKind:
+ return getMipsTargetInfo<ELF32LE>();
+ case ELF32BEKind:
+ return getMipsTargetInfo<ELF32BE>();
+ case ELF64LEKind:
+ return getMipsTargetInfo<ELF64LE>();
+ case ELF64BEKind:
+ return getMipsTargetInfo<ELF64BE>();
+ default:
+ llvm_unreachable("unsupported MIPS target");
+ }
+ case EM_MSP430:
+ return getMSP430TargetInfo();
+ case EM_PPC:
+ return getPPCTargetInfo();
+ case EM_PPC64:
+ return getPPC64TargetInfo();
+ case EM_RISCV:
+ return getRISCVTargetInfo();
+ case EM_SPARCV9:
+ return getSPARCV9TargetInfo();
+ case EM_X86_64:
+ if (Config->EKind == ELF32LEKind)
+ return getX32TargetInfo();
+ return getX86_64TargetInfo();
+ }
+ llvm_unreachable("unknown target machine");
+}
+
+template <class ELFT> static ErrorPlace getErrPlace(const uint8_t *Loc) {
+ for (InputSectionBase *D : InputSections) {
+ auto *IS = cast<InputSection>(D);
+ if (!IS->getParent())
+ continue;
+
+ uint8_t *ISLoc = IS->getParent()->Loc + IS->OutSecOff;
+ if (ISLoc <= Loc && Loc < ISLoc + IS->getSize())
+ return {IS, IS->template getLocation<ELFT>(Loc - ISLoc) + ": "};
+ }
+ return {};
+}
+
+ErrorPlace elf::getErrorPlace(const uint8_t *Loc) {
+ switch (Config->EKind) {
+ case ELF32LEKind:
+ return getErrPlace<ELF32LE>(Loc);
+ case ELF32BEKind:
+ return getErrPlace<ELF32BE>(Loc);
+ case ELF64LEKind:
+ return getErrPlace<ELF64LE>(Loc);
+ case ELF64BEKind:
+ return getErrPlace<ELF64BE>(Loc);
+ default:
+ llvm_unreachable("unknown ELF type");
+ }
+}
+
+TargetInfo::~TargetInfo() {}
+
+int64_t TargetInfo::getImplicitAddend(const uint8_t *Buf, RelType Type) const {
+ return 0;
+}
+
+bool TargetInfo::usesOnlyLowPageBits(RelType Type) const { return false; }
+
+bool TargetInfo::needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
+ uint64_t BranchAddr, const Symbol &S) const {
+ return false;
+}
+
+bool TargetInfo::adjustPrologueForCrossSplitStack(uint8_t *Loc, uint8_t *End,
+ uint8_t StOther) const {
+ llvm_unreachable("Target doesn't support split stacks.");
+}
+
+bool TargetInfo::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const {
+ return true;
+}
+
+void TargetInfo::writeIgotPlt(uint8_t *Buf, const Symbol &S) const {
+ writeGotPlt(Buf, S);
+}
+
+RelExpr TargetInfo::adjustRelaxExpr(RelType Type, const uint8_t *Data,
+ RelExpr Expr) const {
+ return Expr;
+}
+
+void TargetInfo::relaxGot(uint8_t *Loc, uint64_t Val) const {
+ llvm_unreachable("Should not have claimed to be relaxable");
+}
+
+void TargetInfo::relaxTlsGdToLe(uint8_t *Loc, RelType Type,
+ uint64_t Val) const {
+ llvm_unreachable("Should not have claimed to be relaxable");
+}
+
+void TargetInfo::relaxTlsGdToIe(uint8_t *Loc, RelType Type,
+ uint64_t Val) const {
+ llvm_unreachable("Should not have claimed to be relaxable");
+}
+
+void TargetInfo::relaxTlsIeToLe(uint8_t *Loc, RelType Type,
+ uint64_t Val) const {
+ llvm_unreachable("Should not have claimed to be relaxable");
+}
+
+void TargetInfo::relaxTlsLdToLe(uint8_t *Loc, RelType Type,
+ uint64_t Val) const {
+ llvm_unreachable("Should not have claimed to be relaxable");
+}
+
+uint64_t TargetInfo::getImageBase() {
+ // Use -image-base if set. Fall back to the target default if not.
+ if (Config->ImageBase)
+ return *Config->ImageBase;
+ return Config->Pic ? 0 : DefaultImageBase;
+}
diff --git a/contrib/llvm/tools/lld/ELF/Target.h b/contrib/llvm/tools/lld/ELF/Target.h
new file mode 100644
index 000000000000..685ad05ecd66
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Target.h
@@ -0,0 +1,260 @@
+//===- Target.h -------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_TARGET_H
+#define LLD_ELF_TARGET_H
+
+#include "InputSection.h"
+#include "lld/Common/ErrorHandler.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/MathExtras.h"
+#include <array>
+
+namespace lld {
+std::string toString(elf::RelType Type);
+
+namespace elf {
+class Defined;
+class InputFile;
+class Symbol;
+
+class TargetInfo {
+public:
+ virtual uint32_t calcEFlags() const { return 0; }
+ virtual RelType getDynRel(RelType Type) const { return Type; }
+ virtual void writeGotPltHeader(uint8_t *Buf) const {}
+ virtual void writeGotHeader(uint8_t *Buf) const {}
+ virtual void writeGotPlt(uint8_t *Buf, const Symbol &S) const {};
+ virtual void writeIgotPlt(uint8_t *Buf, const Symbol &S) const;
+ virtual int64_t getImplicitAddend(const uint8_t *Buf, RelType Type) const;
+
+ // If lazy binding is supported, the first entry of the PLT has code
+ // to call the dynamic linker to resolve PLT entries the first time
+ // they are called. This function writes that code.
+ virtual void writePltHeader(uint8_t *Buf) const {}
+
+ virtual void writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const {}
+ virtual void addPltHeaderSymbols(InputSection &IS) const {}
+ virtual void addPltSymbols(InputSection &IS, uint64_t Off) const {}
+
+ // Returns true if a relocation only uses the low bits of a value such that
+ // all those bits are in the same page. For example, if the relocation
+ // only uses the low 12 bits in a system with 4k pages. If this is true, the
+ // bits will always have the same value at runtime and we don't have to emit
+ // a dynamic relocation.
+ virtual bool usesOnlyLowPageBits(RelType Type) const;
+
+ // Decide whether a Thunk is needed for the relocation from File
+ // targeting S.
+ virtual bool needsThunk(RelExpr Expr, RelType RelocType,
+ const InputFile *File, uint64_t BranchAddr,
+ const Symbol &S) const;
+
+ // On systems with range extensions we place collections of Thunks at
+ // regular spacings that enable the majority of branches reach the Thunks.
+ // a value of 0 means range extension thunks are not supported.
+ virtual uint32_t getThunkSectionSpacing() const { return 0; }
+
+ // The function with a prologue starting at Loc was compiled with
+ // -fsplit-stack and it calls a function compiled without. Adjust the prologue
+ // to do the right thing. See https://gcc.gnu.org/wiki/SplitStacks.
+ // The symbols st_other flags are needed on PowerPC64 for determining the
+ // offset to the split-stack prologue.
+ virtual bool adjustPrologueForCrossSplitStack(uint8_t *Loc, uint8_t *End,
+ uint8_t StOther) const;
+
+ // Return true if we can reach Dst from Src with Relocation RelocType
+ virtual bool inBranchRange(RelType Type, uint64_t Src,
+ uint64_t Dst) const;
+ virtual RelExpr getRelExpr(RelType Type, const Symbol &S,
+ const uint8_t *Loc) const = 0;
+
+ virtual void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const = 0;
+
+ virtual ~TargetInfo();
+
+ unsigned TlsGdRelaxSkip = 1;
+ unsigned PageSize = 4096;
+ unsigned DefaultMaxPageSize = 4096;
+
+ uint64_t getImageBase();
+
+ // Offset of _GLOBAL_OFFSET_TABLE_ from base of .got or .got.plt section.
+ uint64_t GotBaseSymOff = 0;
+ // True if _GLOBAL_OFFSET_TABLE_ is relative to .got.plt, false if .got.
+ bool GotBaseSymInGotPlt = true;
+
+ RelType CopyRel;
+ RelType GotRel;
+ RelType NoneRel;
+ RelType PltRel;
+ RelType RelativeRel;
+ RelType IRelativeRel;
+ RelType TlsDescRel;
+ RelType TlsGotRel;
+ RelType TlsModuleIndexRel;
+ RelType TlsOffsetRel;
+ unsigned GotEntrySize = 0;
+ unsigned GotPltEntrySize = 0;
+ unsigned PltEntrySize;
+ unsigned PltHeaderSize;
+
+ // At least on x86_64 positions 1 and 2 are used by the first plt entry
+ // to support lazy loading.
+ unsigned GotPltHeaderEntriesNum = 3;
+
+ // On PPC ELF V2 abi, the first entry in the .got is the .TOC.
+ unsigned GotHeaderEntriesNum = 0;
+
+ bool NeedsThunks = false;
+
+ // A 4-byte field corresponding to one or more trap instructions, used to pad
+ // executable OutputSections.
+ std::array<uint8_t, 4> TrapInstr;
+
+ // If a target needs to rewrite calls to __morestack to instead call
+ // __morestack_non_split when a split-stack enabled caller calls a
+ // non-split-stack callee this will return true. Otherwise returns false.
+ bool NeedsMoreStackNonSplit = true;
+
+ virtual RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data,
+ RelExpr Expr) const;
+ virtual void relaxGot(uint8_t *Loc, uint64_t Val) const;
+ virtual void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const;
+ virtual void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const;
+ virtual void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const;
+ virtual void relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const;
+
+protected:
+ // On FreeBSD x86_64 the first page cannot be mmaped.
+ // On Linux that is controled by vm.mmap_min_addr. At least on some x86_64
+ // installs that is 65536, so the first 15 pages cannot be used.
+ // Given that, the smallest value that can be used in here is 0x10000.
+ uint64_t DefaultImageBase = 0x10000;
+};
+
+TargetInfo *getAArch64TargetInfo();
+TargetInfo *getAMDGPUTargetInfo();
+TargetInfo *getARMTargetInfo();
+TargetInfo *getAVRTargetInfo();
+TargetInfo *getHexagonTargetInfo();
+TargetInfo *getMSP430TargetInfo();
+TargetInfo *getPPC64TargetInfo();
+TargetInfo *getPPCTargetInfo();
+TargetInfo *getRISCVTargetInfo();
+TargetInfo *getSPARCV9TargetInfo();
+TargetInfo *getX32TargetInfo();
+TargetInfo *getX86TargetInfo();
+TargetInfo *getX86_64TargetInfo();
+template <class ELFT> TargetInfo *getMipsTargetInfo();
+
+struct ErrorPlace {
+ InputSectionBase *IS;
+ std::string Loc;
+};
+
+// Returns input section and corresponding source string for the given location.
+ErrorPlace getErrorPlace(const uint8_t *Loc);
+
+static inline std::string getErrorLocation(const uint8_t *Loc) {
+ return getErrorPlace(Loc).Loc;
+}
+
+// In the PowerPC64 Elf V2 abi a function can have 2 entry points. The first is
+// a global entry point (GEP) which typically is used to intiailzie the TOC
+// pointer in general purpose register 2. The second is a local entry
+// point (LEP) which bypasses the TOC pointer initialization code. The
+// offset between GEP and LEP is encoded in a function's st_other flags.
+// This function will return the offset (in bytes) from the global entry-point
+// to the local entry-point.
+unsigned getPPC64GlobalEntryToLocalEntryOffset(uint8_t StOther);
+
+uint64_t getPPC64TocBase();
+uint64_t getAArch64Page(uint64_t Expr);
+
+extern TargetInfo *Target;
+TargetInfo *getTarget();
+
+template <class ELFT> bool isMipsPIC(const Defined *Sym);
+
+static inline void reportRangeError(uint8_t *Loc, RelType Type, const Twine &V,
+ int64_t Min, uint64_t Max) {
+ ErrorPlace ErrPlace = getErrorPlace(Loc);
+ StringRef Hint;
+ if (ErrPlace.IS && ErrPlace.IS->Name.startswith(".debug"))
+ Hint = "; consider recompiling with -fdebug-types-section to reduce size "
+ "of debug sections";
+
+ errorOrWarn(ErrPlace.Loc + "relocation " + lld::toString(Type) +
+ " out of range: " + V.str() + " is not in [" + Twine(Min).str() +
+ ", " + Twine(Max).str() + "]" + Hint);
+}
+
+inline unsigned getPltEntryOffset(unsigned Idx) {
+ return Target->PltHeaderSize + Target->PltEntrySize * Idx;
+}
+
+// Make sure that V can be represented as an N bit signed integer.
+inline void checkInt(uint8_t *Loc, int64_t V, int N, RelType Type) {
+ if (V != llvm::SignExtend64(V, N))
+ reportRangeError(Loc, Type, Twine(V), llvm::minIntN(N), llvm::maxIntN(N));
+}
+
+// Make sure that V can be represented as an N bit unsigned integer.
+inline void checkUInt(uint8_t *Loc, uint64_t V, int N, RelType Type) {
+ if ((V >> N) != 0)
+ reportRangeError(Loc, Type, Twine(V), 0, llvm::maxUIntN(N));
+}
+
+// Make sure that V can be represented as an N bit signed or unsigned integer.
+inline void checkIntUInt(uint8_t *Loc, uint64_t V, int N, RelType Type) {
+ // For the error message we should cast V to a signed integer so that error
+ // messages show a small negative value rather than an extremely large one
+ if (V != (uint64_t)llvm::SignExtend64(V, N) && (V >> N) != 0)
+ reportRangeError(Loc, Type, Twine((int64_t)V), llvm::minIntN(N),
+ llvm::maxIntN(N));
+}
+
+inline void checkAlignment(uint8_t *Loc, uint64_t V, int N, RelType Type) {
+ if ((V & (N - 1)) != 0)
+ error(getErrorLocation(Loc) + "improper alignment for relocation " +
+ lld::toString(Type) + ": 0x" + llvm::utohexstr(V) +
+ " is not aligned to " + Twine(N) + " bytes");
+}
+
+// Endianness-aware read/write.
+inline uint16_t read16(const void *P) {
+ return llvm::support::endian::read16(P, Config->Endianness);
+}
+
+inline uint32_t read32(const void *P) {
+ return llvm::support::endian::read32(P, Config->Endianness);
+}
+
+inline uint64_t read64(const void *P) {
+ return llvm::support::endian::read64(P, Config->Endianness);
+}
+
+inline void write16(void *P, uint16_t V) {
+ llvm::support::endian::write16(P, V, Config->Endianness);
+}
+
+inline void write32(void *P, uint32_t V) {
+ llvm::support::endian::write32(P, V, Config->Endianness);
+}
+
+inline void write64(void *P, uint64_t V) {
+ llvm::support::endian::write64(P, V, Config->Endianness);
+}
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/ELF/Thunks.cpp b/contrib/llvm/tools/lld/ELF/Thunks.cpp
new file mode 100644
index 000000000000..7a31d36b0e90
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Thunks.cpp
@@ -0,0 +1,846 @@
+//===- Thunks.cpp --------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+//
+// This file contains Thunk subclasses.
+//
+// A thunk is a small piece of code written after an input section
+// which is used to jump between "incompatible" functions
+// such as MIPS PIC and non-PIC or ARM non-Thumb and Thumb functions.
+//
+// If a jump target is too far and its address doesn't fit to a
+// short jump instruction, we need to create a thunk too, but we
+// haven't supported it yet.
+//
+// i386 and x86-64 don't need thunks.
+//
+//===---------------------------------------------------------------------===//
+
+#include "Thunks.h"
+#include "Config.h"
+#include "InputSection.h"
+#include "OutputSections.h"
+#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Memory.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MathExtras.h"
+#include <cstdint>
+#include <cstring>
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::ELF;
+
+namespace lld {
+namespace elf {
+
+namespace {
+
+// AArch64 long range Thunks
+class AArch64ABSLongThunk final : public Thunk {
+public:
+ AArch64ABSLongThunk(Symbol &Dest) : Thunk(Dest) {}
+ uint32_t size() override { return 16; }
+ void writeTo(uint8_t *Buf) override;
+ void addSymbols(ThunkSection &IS) override;
+};
+
+class AArch64ADRPThunk final : public Thunk {
+public:
+ AArch64ADRPThunk(Symbol &Dest) : Thunk(Dest) {}
+ uint32_t size() override { return 12; }
+ void writeTo(uint8_t *Buf) override;
+ void addSymbols(ThunkSection &IS) override;
+};
+
+// Base class for ARM thunks.
+//
+// An ARM thunk may be either short or long. A short thunk is simply a branch
+// (B) instruction, and it may be used to call ARM functions when the distance
+// from the thunk to the target is less than 32MB. Long thunks can branch to any
+// virtual address and can switch between ARM and Thumb, and they are
+// implemented in the derived classes. This class tries to create a short thunk
+// if the target is in range, otherwise it creates a long thunk.
+class ARMThunk : public Thunk {
+public:
+ ARMThunk(Symbol &Dest) : Thunk(Dest) {}
+
+ bool mayUseShortThunk();
+ uint32_t size() override { return mayUseShortThunk() ? 4 : sizeLong(); }
+ void writeTo(uint8_t *Buf) override;
+ bool isCompatibleWith(RelType Type) const override;
+
+ // Returns the size of a long thunk.
+ virtual uint32_t sizeLong() = 0;
+
+ // Writes a long thunk to Buf.
+ virtual void writeLong(uint8_t *Buf) = 0;
+
+private:
+ // This field tracks whether all previously considered layouts would allow
+ // this thunk to be short. If we have ever needed a long thunk, we always
+ // create a long thunk, even if the thunk may be short given the current
+ // distance to the target. We do this because transitioning from long to short
+ // can create layout oscillations in certain corner cases which would prevent
+ // the layout from converging.
+ bool MayUseShortThunk = true;
+};
+
+// Base class for Thumb-2 thunks.
+//
+// This class is similar to ARMThunk, but it uses the Thumb-2 B.W instruction
+// which has a range of 16MB.
+class ThumbThunk : public Thunk {
+public:
+ ThumbThunk(Symbol &Dest) : Thunk(Dest) { Alignment = 2; }
+
+ bool mayUseShortThunk();
+ uint32_t size() override { return mayUseShortThunk() ? 4 : sizeLong(); }
+ void writeTo(uint8_t *Buf) override;
+ bool isCompatibleWith(RelType Type) const override;
+
+ // Returns the size of a long thunk.
+ virtual uint32_t sizeLong() = 0;
+
+ // Writes a long thunk to Buf.
+ virtual void writeLong(uint8_t *Buf) = 0;
+
+private:
+ // See comment in ARMThunk above.
+ bool MayUseShortThunk = true;
+};
+
+// Specific ARM Thunk implementations. The naming convention is:
+// Source State, TargetState, Target Requirement, ABS or PI, Range
+class ARMV7ABSLongThunk final : public ARMThunk {
+public:
+ ARMV7ABSLongThunk(Symbol &Dest) : ARMThunk(Dest) {}
+
+ uint32_t sizeLong() override { return 12; }
+ void writeLong(uint8_t *Buf) override;
+ void addSymbols(ThunkSection &IS) override;
+};
+
+class ARMV7PILongThunk final : public ARMThunk {
+public:
+ ARMV7PILongThunk(Symbol &Dest) : ARMThunk(Dest) {}
+
+ uint32_t sizeLong() override { return 16; }
+ void writeLong(uint8_t *Buf) override;
+ void addSymbols(ThunkSection &IS) override;
+};
+
+class ThumbV7ABSLongThunk final : public ThumbThunk {
+public:
+ ThumbV7ABSLongThunk(Symbol &Dest) : ThumbThunk(Dest) {}
+
+ uint32_t sizeLong() override { return 10; }
+ void writeLong(uint8_t *Buf) override;
+ void addSymbols(ThunkSection &IS) override;
+};
+
+class ThumbV7PILongThunk final : public ThumbThunk {
+public:
+ ThumbV7PILongThunk(Symbol &Dest) : ThumbThunk(Dest) {}
+
+ uint32_t sizeLong() override { return 12; }
+ void writeLong(uint8_t *Buf) override;
+ void addSymbols(ThunkSection &IS) override;
+};
+
+// Implementations of Thunks for older Arm architectures that do not support
+// the movt/movw instructions. These thunks require at least Architecture v5
+// as used on processors such as the Arm926ej-s. There are no Thumb entry
+// points as there is no Thumb branch instruction on these architecture that
+// can result in a thunk
+class ARMV5ABSLongThunk final : public ARMThunk {
+public:
+ ARMV5ABSLongThunk(Symbol &Dest) : ARMThunk(Dest) {}
+
+ uint32_t sizeLong() override { return 8; }
+ void writeLong(uint8_t *Buf) override;
+ void addSymbols(ThunkSection &IS) override;
+ bool isCompatibleWith(uint32_t RelocType) const override;
+};
+
+class ARMV5PILongThunk final : public ARMThunk {
+public:
+ ARMV5PILongThunk(Symbol &Dest) : ARMThunk(Dest) {}
+
+ uint32_t sizeLong() override { return 16; }
+ void writeLong(uint8_t *Buf) override;
+ void addSymbols(ThunkSection &IS) override;
+ bool isCompatibleWith(uint32_t RelocType) const override;
+};
+
+// Implementations of Thunks for Arm v6-M. Only Thumb instructions are permitted
+class ThumbV6MABSLongThunk final : public ThumbThunk {
+public:
+ ThumbV6MABSLongThunk(Symbol &Dest) : ThumbThunk(Dest) {}
+
+ uint32_t sizeLong() override { return 12; }
+ void writeLong(uint8_t *Buf) override;
+ void addSymbols(ThunkSection &IS) override;
+};
+
+class ThumbV6MPILongThunk final : public ThumbThunk {
+public:
+ ThumbV6MPILongThunk(Symbol &Dest) : ThumbThunk(Dest) {}
+
+ uint32_t sizeLong() override { return 16; }
+ void writeLong(uint8_t *Buf) override;
+ void addSymbols(ThunkSection &IS) override;
+};
+
+// MIPS LA25 thunk
+class MipsThunk final : public Thunk {
+public:
+ MipsThunk(Symbol &Dest) : Thunk(Dest) {}
+
+ uint32_t size() override { return 16; }
+ void writeTo(uint8_t *Buf) override;
+ void addSymbols(ThunkSection &IS) override;
+ InputSection *getTargetInputSection() const override;
+};
+
+// microMIPS R2-R5 LA25 thunk
+class MicroMipsThunk final : public Thunk {
+public:
+ MicroMipsThunk(Symbol &Dest) : Thunk(Dest) {}
+
+ uint32_t size() override { return 14; }
+ void writeTo(uint8_t *Buf) override;
+ void addSymbols(ThunkSection &IS) override;
+ InputSection *getTargetInputSection() const override;
+};
+
+// microMIPS R6 LA25 thunk
+class MicroMipsR6Thunk final : public Thunk {
+public:
+ MicroMipsR6Thunk(Symbol &Dest) : Thunk(Dest) {}
+
+ uint32_t size() override { return 12; }
+ void writeTo(uint8_t *Buf) override;
+ void addSymbols(ThunkSection &IS) override;
+ InputSection *getTargetInputSection() const override;
+};
+
+
+// PPC64 Plt call stubs.
+// Any call site that needs to call through a plt entry needs a call stub in
+// the .text section. The call stub is responsible for:
+// 1) Saving the toc-pointer to the stack.
+// 2) Loading the target functions address from the procedure linkage table into
+// r12 for use by the target functions global entry point, and into the count
+// register.
+// 3) Transfering control to the target function through an indirect branch.
+class PPC64PltCallStub final : public Thunk {
+public:
+ PPC64PltCallStub(Symbol &Dest) : Thunk(Dest) {}
+ uint32_t size() override { return 20; }
+ void writeTo(uint8_t *Buf) override;
+ void addSymbols(ThunkSection &IS) override;
+};
+
+// A bl instruction uses a signed 24 bit offset, with an implicit 4 byte
+// alignment. This gives a possible 26 bits of 'reach'. If the call offset is
+// larger then that we need to emit a long-branch thunk. The target address
+// of the callee is stored in a table to be accessed TOC-relative. Since the
+// call must be local (a non-local call will have a PltCallStub instead) the
+// table stores the address of the callee's local entry point. For
+// position-independent code a corresponding relative dynamic relocation is
+// used.
+class PPC64LongBranchThunk : public Thunk {
+public:
+ uint32_t size() override { return 16; }
+ void writeTo(uint8_t *Buf) override;
+ void addSymbols(ThunkSection &IS) override;
+
+protected:
+ PPC64LongBranchThunk(Symbol &Dest) : Thunk(Dest) {}
+};
+
+class PPC64PILongBranchThunk final : public PPC64LongBranchThunk {
+public:
+ PPC64PILongBranchThunk(Symbol &Dest) : PPC64LongBranchThunk(Dest) {
+ assert(!Dest.IsPreemptible);
+ if (Dest.isInPPC64Branchlt())
+ return;
+
+ In.PPC64LongBranchTarget->addEntry(Dest);
+ In.RelaDyn->addReloc({Target->RelativeRel, In.PPC64LongBranchTarget,
+ Dest.getPPC64LongBranchOffset(), true, &Dest,
+ getPPC64GlobalEntryToLocalEntryOffset(Dest.StOther)});
+ }
+};
+
+class PPC64PDLongBranchThunk final : public PPC64LongBranchThunk {
+public:
+ PPC64PDLongBranchThunk(Symbol &Dest) : PPC64LongBranchThunk(Dest) {
+ if (!Dest.isInPPC64Branchlt())
+ In.PPC64LongBranchTarget->addEntry(Dest);
+ }
+};
+
+} // end anonymous namespace
+
+Defined *Thunk::addSymbol(StringRef Name, uint8_t Type, uint64_t Value,
+ InputSectionBase &Section) {
+ Defined *D = addSyntheticLocal(Name, Type, Value, /*Size=*/0, Section);
+ Syms.push_back(D);
+ return D;
+}
+
+void Thunk::setOffset(uint64_t NewOffset) {
+ for (Defined *D : Syms)
+ D->Value = D->Value - Offset + NewOffset;
+ Offset = NewOffset;
+}
+
+// AArch64 long range Thunks
+
+static uint64_t getAArch64ThunkDestVA(const Symbol &S) {
+ uint64_t V = S.isInPlt() ? S.getPltVA() : S.getVA();
+ return V;
+}
+
+void AArch64ABSLongThunk::writeTo(uint8_t *Buf) {
+ const uint8_t Data[] = {
+ 0x50, 0x00, 0x00, 0x58, // ldr x16, L0
+ 0x00, 0x02, 0x1f, 0xd6, // br x16
+ 0x00, 0x00, 0x00, 0x00, // L0: .xword S
+ 0x00, 0x00, 0x00, 0x00,
+ };
+ uint64_t S = getAArch64ThunkDestVA(Destination);
+ memcpy(Buf, Data, sizeof(Data));
+ Target->relocateOne(Buf + 8, R_AARCH64_ABS64, S);
+}
+
+void AArch64ABSLongThunk::addSymbols(ThunkSection &IS) {
+ addSymbol(Saver.save("__AArch64AbsLongThunk_" + Destination.getName()),
+ STT_FUNC, 0, IS);
+ addSymbol("$x", STT_NOTYPE, 0, IS);
+ addSymbol("$d", STT_NOTYPE, 8, IS);
+}
+
+// This Thunk has a maximum range of 4Gb, this is sufficient for all programs
+// using the small code model, including pc-relative ones. At time of writing
+// clang and gcc do not support the large code model for position independent
+// code so it is safe to use this for position independent thunks without
+// worrying about the destination being more than 4Gb away.
+void AArch64ADRPThunk::writeTo(uint8_t *Buf) {
+ const uint8_t Data[] = {
+ 0x10, 0x00, 0x00, 0x90, // adrp x16, Dest R_AARCH64_ADR_PREL_PG_HI21(Dest)
+ 0x10, 0x02, 0x00, 0x91, // add x16, x16, R_AARCH64_ADD_ABS_LO12_NC(Dest)
+ 0x00, 0x02, 0x1f, 0xd6, // br x16
+ };
+ uint64_t S = getAArch64ThunkDestVA(Destination);
+ uint64_t P = getThunkTargetSym()->getVA();
+ memcpy(Buf, Data, sizeof(Data));
+ Target->relocateOne(Buf, R_AARCH64_ADR_PREL_PG_HI21,
+ getAArch64Page(S) - getAArch64Page(P));
+ Target->relocateOne(Buf + 4, R_AARCH64_ADD_ABS_LO12_NC, S);
+}
+
+void AArch64ADRPThunk::addSymbols(ThunkSection &IS) {
+ addSymbol(Saver.save("__AArch64ADRPThunk_" + Destination.getName()), STT_FUNC,
+ 0, IS);
+ addSymbol("$x", STT_NOTYPE, 0, IS);
+}
+
+// ARM Target Thunks
+static uint64_t getARMThunkDestVA(const Symbol &S) {
+ uint64_t V = S.isInPlt() ? S.getPltVA() : S.getVA();
+ return SignExtend64<32>(V);
+}
+
+// This function returns true if the target is not Thumb and is within 2^26, and
+// it has not previously returned false (see comment for MayUseShortThunk).
+bool ARMThunk::mayUseShortThunk() {
+ if (!MayUseShortThunk)
+ return false;
+ uint64_t S = getARMThunkDestVA(Destination);
+ if (S & 1) {
+ MayUseShortThunk = false;
+ return false;
+ }
+ uint64_t P = getThunkTargetSym()->getVA();
+ int64_t Offset = S - P - 8;
+ MayUseShortThunk = llvm::isInt<26>(Offset);
+ return MayUseShortThunk;
+}
+
+void ARMThunk::writeTo(uint8_t *Buf) {
+ if (!mayUseShortThunk()) {
+ writeLong(Buf);
+ return;
+ }
+
+ uint64_t S = getARMThunkDestVA(Destination);
+ uint64_t P = getThunkTargetSym()->getVA();
+ int64_t Offset = S - P - 8;
+ const uint8_t Data[] = {
+ 0x00, 0x00, 0x00, 0xea, // b S
+ };
+ memcpy(Buf, Data, sizeof(Data));
+ Target->relocateOne(Buf, R_ARM_JUMP24, Offset);
+}
+
+bool ARMThunk::isCompatibleWith(RelType Type) const {
+ // Thumb branch relocations can't use BLX
+ return Type != R_ARM_THM_JUMP19 && Type != R_ARM_THM_JUMP24;
+}
+
+// This function returns true if the target is Thumb and is within 2^25, and
+// it has not previously returned false (see comment for MayUseShortThunk).
+bool ThumbThunk::mayUseShortThunk() {
+ if (!MayUseShortThunk)
+ return false;
+ uint64_t S = getARMThunkDestVA(Destination);
+ if ((S & 1) == 0) {
+ MayUseShortThunk = false;
+ return false;
+ }
+ uint64_t P = getThunkTargetSym()->getVA() & ~1;
+ int64_t Offset = S - P - 4;
+ MayUseShortThunk = llvm::isInt<25>(Offset);
+ return MayUseShortThunk;
+}
+
+void ThumbThunk::writeTo(uint8_t *Buf) {
+ if (!mayUseShortThunk()) {
+ writeLong(Buf);
+ return;
+ }
+
+ uint64_t S = getARMThunkDestVA(Destination);
+ uint64_t P = getThunkTargetSym()->getVA();
+ int64_t Offset = S - P - 4;
+ const uint8_t Data[] = {
+ 0x00, 0xf0, 0x00, 0xb0, // b.w S
+ };
+ memcpy(Buf, Data, sizeof(Data));
+ Target->relocateOne(Buf, R_ARM_THM_JUMP24, Offset);
+}
+
+bool ThumbThunk::isCompatibleWith(RelType Type) const {
+ // ARM branch relocations can't use BLX
+ return Type != R_ARM_JUMP24 && Type != R_ARM_PC24 && Type != R_ARM_PLT32;
+}
+
+void ARMV7ABSLongThunk::writeLong(uint8_t *Buf) {
+ const uint8_t Data[] = {
+ 0x00, 0xc0, 0x00, 0xe3, // movw ip,:lower16:S
+ 0x00, 0xc0, 0x40, 0xe3, // movt ip,:upper16:S
+ 0x1c, 0xff, 0x2f, 0xe1, // bx ip
+ };
+ uint64_t S = getARMThunkDestVA(Destination);
+ memcpy(Buf, Data, sizeof(Data));
+ Target->relocateOne(Buf, R_ARM_MOVW_ABS_NC, S);
+ Target->relocateOne(Buf + 4, R_ARM_MOVT_ABS, S);
+}
+
+void ARMV7ABSLongThunk::addSymbols(ThunkSection &IS) {
+ addSymbol(Saver.save("__ARMv7ABSLongThunk_" + Destination.getName()),
+ STT_FUNC, 0, IS);
+ addSymbol("$a", STT_NOTYPE, 0, IS);
+}
+
+void ThumbV7ABSLongThunk::writeLong(uint8_t *Buf) {
+ const uint8_t Data[] = {
+ 0x40, 0xf2, 0x00, 0x0c, // movw ip, :lower16:S
+ 0xc0, 0xf2, 0x00, 0x0c, // movt ip, :upper16:S
+ 0x60, 0x47, // bx ip
+ };
+ uint64_t S = getARMThunkDestVA(Destination);
+ memcpy(Buf, Data, sizeof(Data));
+ Target->relocateOne(Buf, R_ARM_THM_MOVW_ABS_NC, S);
+ Target->relocateOne(Buf + 4, R_ARM_THM_MOVT_ABS, S);
+}
+
+void ThumbV7ABSLongThunk::addSymbols(ThunkSection &IS) {
+ addSymbol(Saver.save("__Thumbv7ABSLongThunk_" + Destination.getName()),
+ STT_FUNC, 1, IS);
+ addSymbol("$t", STT_NOTYPE, 0, IS);
+}
+
+void ARMV7PILongThunk::writeLong(uint8_t *Buf) {
+ const uint8_t Data[] = {
+ 0xf0, 0xcf, 0x0f, 0xe3, // P: movw ip,:lower16:S - (P + (L1-P) + 8)
+ 0x00, 0xc0, 0x40, 0xe3, // movt ip,:upper16:S - (P + (L1-P) + 8)
+ 0x0f, 0xc0, 0x8c, 0xe0, // L1: add ip, ip, pc
+ 0x1c, 0xff, 0x2f, 0xe1, // bx ip
+ };
+ uint64_t S = getARMThunkDestVA(Destination);
+ uint64_t P = getThunkTargetSym()->getVA();
+ int64_t Offset = S - P - 16;
+ memcpy(Buf, Data, sizeof(Data));
+ Target->relocateOne(Buf, R_ARM_MOVW_PREL_NC, Offset);
+ Target->relocateOne(Buf + 4, R_ARM_MOVT_PREL, Offset);
+}
+
+void ARMV7PILongThunk::addSymbols(ThunkSection &IS) {
+ addSymbol(Saver.save("__ARMV7PILongThunk_" + Destination.getName()), STT_FUNC,
+ 0, IS);
+ addSymbol("$a", STT_NOTYPE, 0, IS);
+}
+
+void ThumbV7PILongThunk::writeLong(uint8_t *Buf) {
+ const uint8_t Data[] = {
+ 0x4f, 0xf6, 0xf4, 0x7c, // P: movw ip,:lower16:S - (P + (L1-P) + 4)
+ 0xc0, 0xf2, 0x00, 0x0c, // movt ip,:upper16:S - (P + (L1-P) + 4)
+ 0xfc, 0x44, // L1: add ip, pc
+ 0x60, 0x47, // bx ip
+ };
+ uint64_t S = getARMThunkDestVA(Destination);
+ uint64_t P = getThunkTargetSym()->getVA() & ~0x1;
+ int64_t Offset = S - P - 12;
+ memcpy(Buf, Data, sizeof(Data));
+ Target->relocateOne(Buf, R_ARM_THM_MOVW_PREL_NC, Offset);
+ Target->relocateOne(Buf + 4, R_ARM_THM_MOVT_PREL, Offset);
+}
+
+void ThumbV7PILongThunk::addSymbols(ThunkSection &IS) {
+ addSymbol(Saver.save("__ThumbV7PILongThunk_" + Destination.getName()),
+ STT_FUNC, 1, IS);
+ addSymbol("$t", STT_NOTYPE, 0, IS);
+}
+
+void ARMV5ABSLongThunk::writeLong(uint8_t *Buf) {
+ const uint8_t Data[] = {
+ 0x04, 0xf0, 0x1f, 0xe5, // ldr pc, [pc,#-4] ; L1
+ 0x00, 0x00, 0x00, 0x00, // L1: .word S
+ };
+ memcpy(Buf, Data, sizeof(Data));
+ Target->relocateOne(Buf + 4, R_ARM_ABS32, getARMThunkDestVA(Destination));
+}
+
+void ARMV5ABSLongThunk::addSymbols(ThunkSection &IS) {
+ addSymbol(Saver.save("__ARMv5ABSLongThunk_" + Destination.getName()),
+ STT_FUNC, 0, IS);
+ addSymbol("$a", STT_NOTYPE, 0, IS);
+ addSymbol("$d", STT_NOTYPE, 4, IS);
+}
+
+bool ARMV5ABSLongThunk::isCompatibleWith(uint32_t RelocType) const {
+ // Thumb branch relocations can't use BLX
+ return RelocType != R_ARM_THM_JUMP19 && RelocType != R_ARM_THM_JUMP24;
+}
+
+void ARMV5PILongThunk::writeLong(uint8_t *Buf) {
+ const uint8_t Data[] = {
+ 0x04, 0xc0, 0x9f, 0xe5, // P: ldr ip, [pc,#4] ; L2
+ 0x0c, 0xc0, 0x8f, 0xe0, // L1: add ip, pc, ip
+ 0x1c, 0xff, 0x2f, 0xe1, // bx ip
+ 0x00, 0x00, 0x00, 0x00, // L2: .word S - (P + (L1 - P) + 8)
+ };
+ uint64_t S = getARMThunkDestVA(Destination);
+ uint64_t P = getThunkTargetSym()->getVA() & ~0x1;
+ memcpy(Buf, Data, sizeof(Data));
+ Target->relocateOne(Buf + 12, R_ARM_REL32, S - P - 12);
+}
+
+void ARMV5PILongThunk::addSymbols(ThunkSection &IS) {
+ addSymbol(Saver.save("__ARMV5PILongThunk_" + Destination.getName()), STT_FUNC,
+ 0, IS);
+ addSymbol("$a", STT_NOTYPE, 0, IS);
+ addSymbol("$d", STT_NOTYPE, 12, IS);
+}
+
+bool ARMV5PILongThunk::isCompatibleWith(uint32_t RelocType) const {
+ // Thumb branch relocations can't use BLX
+ return RelocType != R_ARM_THM_JUMP19 && RelocType != R_ARM_THM_JUMP24;
+}
+
+void ThumbV6MABSLongThunk::writeLong(uint8_t *Buf) {
+ // Most Thumb instructions cannot access the high registers r8 - r15. As the
+ // only register we can corrupt is r12 we must instead spill a low register
+ // to the stack to use as a scratch register. We push r1 even though we
+ // don't need to get some space to use for the return address.
+ const uint8_t Data[] = {
+ 0x03, 0xb4, // push {r0, r1} ; Obtain scratch registers
+ 0x01, 0x48, // ldr r0, [pc, #4] ; L1
+ 0x01, 0x90, // str r0, [sp, #4] ; SP + 4 = S
+ 0x01, 0xbd, // pop {r0, pc} ; restore r0 and branch to dest
+ 0x00, 0x00, 0x00, 0x00 // L1: .word S
+ };
+ uint64_t S = getARMThunkDestVA(Destination);
+ memcpy(Buf, Data, sizeof(Data));
+ Target->relocateOne(Buf + 8, R_ARM_ABS32, S);
+}
+
+void ThumbV6MABSLongThunk::addSymbols(ThunkSection &IS) {
+ addSymbol(Saver.save("__Thumbv6MABSLongThunk_" + Destination.getName()),
+ STT_FUNC, 1, IS);
+ addSymbol("$t", STT_NOTYPE, 0, IS);
+ addSymbol("$d", STT_NOTYPE, 8, IS);
+}
+
+void ThumbV6MPILongThunk::writeLong(uint8_t *Buf) {
+ // Most Thumb instructions cannot access the high registers r8 - r15. As the
+ // only register we can corrupt is ip (r12) we must instead spill a low
+ // register to the stack to use as a scratch register.
+ const uint8_t Data[] = {
+ 0x01, 0xb4, // P: push {r0} ; Obtain scratch register
+ 0x02, 0x48, // ldr r0, [pc, #8] ; L2
+ 0x84, 0x46, // mov ip, r0 ; high to low register
+ 0x01, 0xbc, // pop {r0} ; restore scratch register
+ 0xe7, 0x44, // L1: add pc, ip ; transfer control
+ 0xc0, 0x46, // nop ; pad to 4-byte boundary
+ 0x00, 0x00, 0x00, 0x00, // L2: .word S - (P + (L1 - P) + 4)
+ };
+ uint64_t S = getARMThunkDestVA(Destination);
+ uint64_t P = getThunkTargetSym()->getVA() & ~0x1;
+ memcpy(Buf, Data, sizeof(Data));
+ Target->relocateOne(Buf + 12, R_ARM_REL32, S - P - 12);
+}
+
+void ThumbV6MPILongThunk::addSymbols(ThunkSection &IS) {
+ addSymbol(Saver.save("__Thumbv6MPILongThunk_" + Destination.getName()),
+ STT_FUNC, 1, IS);
+ addSymbol("$t", STT_NOTYPE, 0, IS);
+ addSymbol("$d", STT_NOTYPE, 12, IS);
+}
+
+// Write MIPS LA25 thunk code to call PIC function from the non-PIC one.
+void MipsThunk::writeTo(uint8_t *Buf) {
+ uint64_t S = Destination.getVA();
+ write32(Buf, 0x3c190000); // lui $25, %hi(func)
+ write32(Buf + 4, 0x08000000 | (S >> 2)); // j func
+ write32(Buf + 8, 0x27390000); // addiu $25, $25, %lo(func)
+ write32(Buf + 12, 0x00000000); // nop
+ Target->relocateOne(Buf, R_MIPS_HI16, S);
+ Target->relocateOne(Buf + 8, R_MIPS_LO16, S);
+}
+
+void MipsThunk::addSymbols(ThunkSection &IS) {
+ addSymbol(Saver.save("__LA25Thunk_" + Destination.getName()), STT_FUNC, 0,
+ IS);
+}
+
+InputSection *MipsThunk::getTargetInputSection() const {
+ auto &DR = cast<Defined>(Destination);
+ return dyn_cast<InputSection>(DR.Section);
+}
+
+// Write microMIPS R2-R5 LA25 thunk code
+// to call PIC function from the non-PIC one.
+void MicroMipsThunk::writeTo(uint8_t *Buf) {
+ uint64_t S = Destination.getVA() | 1;
+ write16(Buf, 0x41b9); // lui $25, %hi(func)
+ write16(Buf + 4, 0xd400); // j func
+ write16(Buf + 8, 0x3339); // addiu $25, $25, %lo(func)
+ write16(Buf + 12, 0x0c00); // nop
+ Target->relocateOne(Buf, R_MICROMIPS_HI16, S);
+ Target->relocateOne(Buf + 4, R_MICROMIPS_26_S1, S);
+ Target->relocateOne(Buf + 8, R_MICROMIPS_LO16, S);
+}
+
+void MicroMipsThunk::addSymbols(ThunkSection &IS) {
+ Defined *D = addSymbol(
+ Saver.save("__microLA25Thunk_" + Destination.getName()), STT_FUNC, 0, IS);
+ D->StOther |= STO_MIPS_MICROMIPS;
+}
+
+InputSection *MicroMipsThunk::getTargetInputSection() const {
+ auto &DR = cast<Defined>(Destination);
+ return dyn_cast<InputSection>(DR.Section);
+}
+
+// Write microMIPS R6 LA25 thunk code
+// to call PIC function from the non-PIC one.
+void MicroMipsR6Thunk::writeTo(uint8_t *Buf) {
+ uint64_t S = Destination.getVA() | 1;
+ uint64_t P = getThunkTargetSym()->getVA();
+ write16(Buf, 0x1320); // lui $25, %hi(func)
+ write16(Buf + 4, 0x3339); // addiu $25, $25, %lo(func)
+ write16(Buf + 8, 0x9400); // bc func
+ Target->relocateOne(Buf, R_MICROMIPS_HI16, S);
+ Target->relocateOne(Buf + 4, R_MICROMIPS_LO16, S);
+ Target->relocateOne(Buf + 8, R_MICROMIPS_PC26_S1, S - P - 12);
+}
+
+void MicroMipsR6Thunk::addSymbols(ThunkSection &IS) {
+ Defined *D = addSymbol(
+ Saver.save("__microLA25Thunk_" + Destination.getName()), STT_FUNC, 0, IS);
+ D->StOther |= STO_MIPS_MICROMIPS;
+}
+
+InputSection *MicroMipsR6Thunk::getTargetInputSection() const {
+ auto &DR = cast<Defined>(Destination);
+ return dyn_cast<InputSection>(DR.Section);
+}
+
+static void writePPCLoadAndBranch(uint8_t *Buf, int64_t Offset) {
+ uint16_t OffHa = (Offset + 0x8000) >> 16;
+ uint16_t OffLo = Offset & 0xffff;
+
+ write32(Buf + 0, 0x3d820000 | OffHa); // addis r12, r2, OffHa
+ write32(Buf + 4, 0xe98c0000 | OffLo); // ld r12, OffLo(r12)
+ write32(Buf + 8, 0x7d8903a6); // mtctr r12
+ write32(Buf + 12, 0x4e800420); // bctr
+}
+
+void PPC64PltCallStub::writeTo(uint8_t *Buf) {
+ int64_t Offset = Destination.getGotPltVA() - getPPC64TocBase();
+ // Save the TOC pointer to the save-slot reserved in the call frame.
+ write32(Buf + 0, 0xf8410018); // std r2,24(r1)
+ writePPCLoadAndBranch(Buf + 4, Offset);
+}
+
+void PPC64PltCallStub::addSymbols(ThunkSection &IS) {
+ Defined *S = addSymbol(Saver.save("__plt_" + Destination.getName()), STT_FUNC,
+ 0, IS);
+ S->NeedsTocRestore = true;
+}
+
+void PPC64LongBranchThunk::writeTo(uint8_t *Buf) {
+ int64_t Offset = Destination.getPPC64LongBranchTableVA() - getPPC64TocBase();
+ writePPCLoadAndBranch(Buf, Offset);
+}
+
+void PPC64LongBranchThunk::addSymbols(ThunkSection &IS) {
+ addSymbol(Saver.save("__long_branch_" + Destination.getName()), STT_FUNC, 0,
+ IS);
+}
+
+Thunk::Thunk(Symbol &D) : Destination(D), Offset(0) {}
+
+Thunk::~Thunk() = default;
+
+static Thunk *addThunkAArch64(RelType Type, Symbol &S) {
+ if (Type != R_AARCH64_CALL26 && Type != R_AARCH64_JUMP26)
+ fatal("unrecognized relocation type");
+ if (Config->PicThunk)
+ return make<AArch64ADRPThunk>(S);
+ return make<AArch64ABSLongThunk>(S);
+}
+
+// Creates a thunk for Thumb-ARM interworking.
+// Arm Architectures v5 and v6 do not support Thumb2 technology. This means
+// - MOVT and MOVW instructions cannot be used
+// - Only Thumb relocation that can generate a Thunk is a BL, this can always
+// be transformed into a BLX
+static Thunk *addThunkPreArmv7(RelType Reloc, Symbol &S) {
+ switch (Reloc) {
+ case R_ARM_PC24:
+ case R_ARM_PLT32:
+ case R_ARM_JUMP24:
+ case R_ARM_CALL:
+ case R_ARM_THM_CALL:
+ if (Config->PicThunk)
+ return make<ARMV5PILongThunk>(S);
+ return make<ARMV5ABSLongThunk>(S);
+ }
+ fatal("relocation " + toString(Reloc) + " to " + toString(S) +
+ " not supported for Armv5 or Armv6 targets");
+}
+
+// Create a thunk for Thumb long branch on V6-M.
+// Arm Architecture v6-M only supports Thumb instructions. This means
+// - MOVT and MOVW instructions cannot be used.
+// - Only a limited number of instructions can access registers r8 and above
+// - No interworking support is needed (all Thumb).
+static Thunk *addThunkV6M(RelType Reloc, Symbol &S) {
+ switch (Reloc) {
+ case R_ARM_THM_JUMP19:
+ case R_ARM_THM_JUMP24:
+ case R_ARM_THM_CALL:
+ if (Config->Pic)
+ return make<ThumbV6MPILongThunk>(S);
+ return make<ThumbV6MABSLongThunk>(S);
+ }
+ fatal("relocation " + toString(Reloc) + " to " + toString(S) +
+ " not supported for Armv6-M targets");
+}
+
+// Creates a thunk for Thumb-ARM interworking or branch range extension.
+static Thunk *addThunkArm(RelType Reloc, Symbol &S) {
+ // Decide which Thunk is needed based on:
+ // Available instruction set
+ // - An Arm Thunk can only be used if Arm state is available.
+ // - A Thumb Thunk can only be used if Thumb state is available.
+ // - Can only use a Thunk if it uses instructions that the Target supports.
+ // Relocation is branch or branch and link
+ // - Branch instructions cannot change state, can only select Thunk that
+ // starts in the same state as the caller.
+ // - Branch and link relocations can change state, can select Thunks from
+ // either Arm or Thumb.
+ // Position independent Thunks if we require position independent code.
+
+ // Handle architectures that have restrictions on the instructions that they
+ // can use in Thunks. The flags below are set by reading the BuildAttributes
+ // of the input objects. InputFiles.cpp contains the mapping from ARM
+ // architecture to flag.
+ if (!Config->ARMHasMovtMovw) {
+ if (!Config->ARMJ1J2BranchEncoding)
+ return addThunkPreArmv7(Reloc, S);
+ return addThunkV6M(Reloc, S);
+ }
+
+ switch (Reloc) {
+ case R_ARM_PC24:
+ case R_ARM_PLT32:
+ case R_ARM_JUMP24:
+ case R_ARM_CALL:
+ if (Config->PicThunk)
+ return make<ARMV7PILongThunk>(S);
+ return make<ARMV7ABSLongThunk>(S);
+ case R_ARM_THM_JUMP19:
+ case R_ARM_THM_JUMP24:
+ case R_ARM_THM_CALL:
+ if (Config->PicThunk)
+ return make<ThumbV7PILongThunk>(S);
+ return make<ThumbV7ABSLongThunk>(S);
+ }
+ fatal("unrecognized relocation type");
+}
+
+static Thunk *addThunkMips(RelType Type, Symbol &S) {
+ if ((S.StOther & STO_MIPS_MICROMIPS) && isMipsR6())
+ return make<MicroMipsR6Thunk>(S);
+ if (S.StOther & STO_MIPS_MICROMIPS)
+ return make<MicroMipsThunk>(S);
+ return make<MipsThunk>(S);
+}
+
+static Thunk *addThunkPPC64(RelType Type, Symbol &S) {
+ assert(Type == R_PPC64_REL24 && "unexpected relocation type for thunk");
+ if (S.isInPlt())
+ return make<PPC64PltCallStub>(S);
+
+ if (Config->PicThunk)
+ return make<PPC64PILongBranchThunk>(S);
+
+ return make<PPC64PDLongBranchThunk>(S);
+}
+
+Thunk *addThunk(RelType Type, Symbol &S) {
+ if (Config->EMachine == EM_AARCH64)
+ return addThunkAArch64(Type, S);
+
+ if (Config->EMachine == EM_ARM)
+ return addThunkArm(Type, S);
+
+ if (Config->EMachine == EM_MIPS)
+ return addThunkMips(Type, S);
+
+ if (Config->EMachine == EM_PPC64)
+ return addThunkPPC64(Type, S);
+
+ llvm_unreachable("add Thunk only supported for ARM, Mips and PowerPC");
+}
+
+} // end namespace elf
+} // end namespace lld
diff --git a/contrib/llvm/tools/lld/ELF/Thunks.h b/contrib/llvm/tools/lld/ELF/Thunks.h
new file mode 100644
index 000000000000..ed82b4d946ac
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Thunks.h
@@ -0,0 +1,71 @@
+//===- Thunks.h --------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_THUNKS_H
+#define LLD_ELF_THUNKS_H
+
+#include "Relocations.h"
+
+namespace lld {
+namespace elf {
+class Defined;
+class Symbol;
+class ThunkSection;
+// Class to describe an instance of a Thunk.
+// A Thunk is a code-sequence inserted by the linker in between a caller and
+// the callee. The relocation to the callee is redirected to the Thunk, which
+// after executing transfers control to the callee. Typical uses of Thunks
+// include transferring control from non-pi to pi and changing state on
+// targets like ARM.
+//
+// Thunks can be created for Defined, Shared and Undefined Symbols.
+// Thunks are assigned to synthetic ThunkSections
+class Thunk {
+public:
+ Thunk(Symbol &Destination);
+ virtual ~Thunk();
+
+ virtual uint32_t size() = 0;
+ virtual void writeTo(uint8_t *Buf) = 0;
+
+ // All Thunks must define at least one symbol, known as the thunk target
+ // symbol, so that we can redirect relocations to it. The thunk may define
+ // additional symbols, but these are never targets for relocations.
+ virtual void addSymbols(ThunkSection &IS) = 0;
+
+ void setOffset(uint64_t Offset);
+ Defined *addSymbol(StringRef Name, uint8_t Type, uint64_t Value,
+ InputSectionBase &Section);
+
+ // Some Thunks must be placed immediately before their Target as they elide
+ // a branch and fall through to the first Symbol in the Target.
+ virtual InputSection *getTargetInputSection() const { return nullptr; }
+
+ // To reuse a Thunk the caller as identified by the Type must be
+ // compatible with it.
+ virtual bool isCompatibleWith(RelType Type) const { return true; }
+
+ Defined *getThunkTargetSym() const { return Syms[0]; }
+
+ // The alignment requirement for this Thunk, defaults to the size of the
+ // typical code section alignment.
+ Symbol &Destination;
+ llvm::SmallVector<Defined *, 3> Syms;
+ uint64_t Offset = 0;
+ uint32_t Alignment = 4;
+};
+
+// For a Relocation to symbol S create a Thunk to be added to a synthetic
+// ThunkSection. At present there are implementations for ARM and Mips Thunks.
+Thunk *addThunk(RelType Type, Symbol &S);
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/ELF/Writer.cpp b/contrib/llvm/tools/lld/ELF/Writer.cpp
new file mode 100644
index 000000000000..5c987ca5a813
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Writer.cpp
@@ -0,0 +1,2530 @@
+//===- Writer.cpp ---------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Writer.h"
+#include "AArch64ErrataFix.h"
+#include "CallGraphSort.h"
+#include "Config.h"
+#include "Filesystem.h"
+#include "LinkerScript.h"
+#include "MapFile.h"
+#include "OutputSections.h"
+#include "Relocations.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "lld/Common/Memory.h"
+#include "lld/Common/Strings.h"
+#include "lld/Common/Threads.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringSwitch.h"
+#include <climits>
+
+using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::object;
+using namespace llvm::support;
+using namespace llvm::support::endian;
+
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+// The writer writes a SymbolTable result to a file.
+template <class ELFT> class Writer {
+public:
+ Writer() : Buffer(errorHandler().OutputBuffer) {}
+ typedef typename ELFT::Shdr Elf_Shdr;
+ typedef typename ELFT::Ehdr Elf_Ehdr;
+ typedef typename ELFT::Phdr Elf_Phdr;
+
+ void run();
+
+private:
+ void copyLocalSymbols();
+ void addSectionSymbols();
+ void forEachRelSec(llvm::function_ref<void(InputSectionBase &)> Fn);
+ void sortSections();
+ void resolveShfLinkOrder();
+ void maybeAddThunks();
+ void sortInputSections();
+ void finalizeSections();
+ void checkExecuteOnly();
+ void setReservedSymbolSections();
+
+ std::vector<PhdrEntry *> createPhdrs();
+ void removeEmptyPTLoad();
+ void addPtArmExid(std::vector<PhdrEntry *> &Phdrs);
+ void assignFileOffsets();
+ void assignFileOffsetsBinary();
+ void setPhdrs();
+ void checkSections();
+ void fixSectionAlignments();
+ void openFile();
+ void writeTrapInstr();
+ void writeHeader();
+ void writeSections();
+ void writeSectionsBinary();
+ void writeBuildId();
+
+ std::unique_ptr<FileOutputBuffer> &Buffer;
+
+ void addRelIpltSymbols();
+ void addStartEndSymbols();
+ void addStartStopSymbols(OutputSection *Sec);
+
+ std::vector<PhdrEntry *> Phdrs;
+
+ uint64_t FileSize;
+ uint64_t SectionHeaderOff;
+};
+} // anonymous namespace
+
+static bool isSectionPrefix(StringRef Prefix, StringRef Name) {
+ return Name.startswith(Prefix) || Name == Prefix.drop_back();
+}
+
+StringRef elf::getOutputSectionName(const InputSectionBase *S) {
+ if (Config->Relocatable)
+ return S->Name;
+
+ // This is for --emit-relocs. If .text.foo is emitted as .text.bar, we want
+ // to emit .rela.text.foo as .rela.text.bar for consistency (this is not
+ // technically required, but not doing it is odd). This code guarantees that.
+ if (auto *IS = dyn_cast<InputSection>(S)) {
+ if (InputSectionBase *Rel = IS->getRelocatedSection()) {
+ OutputSection *Out = Rel->getOutputSection();
+ if (S->Type == SHT_RELA)
+ return Saver.save(".rela" + Out->Name);
+ return Saver.save(".rel" + Out->Name);
+ }
+ }
+
+ // This check is for -z keep-text-section-prefix. This option separates text
+ // sections with prefix ".text.hot", ".text.unlikely", ".text.startup" or
+ // ".text.exit".
+ // When enabled, this allows identifying the hot code region (.text.hot) in
+ // the final binary which can be selectively mapped to huge pages or mlocked,
+ // for instance.
+ if (Config->ZKeepTextSectionPrefix)
+ for (StringRef V :
+ {".text.hot.", ".text.unlikely.", ".text.startup.", ".text.exit."})
+ if (isSectionPrefix(V, S->Name))
+ return V.drop_back();
+
+ for (StringRef V :
+ {".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.rel.ro.",
+ ".bss.", ".init_array.", ".fini_array.", ".ctors.", ".dtors.", ".tbss.",
+ ".gcc_except_table.", ".tdata.", ".ARM.exidx.", ".ARM.extab."})
+ if (isSectionPrefix(V, S->Name))
+ return V.drop_back();
+
+ // CommonSection is identified as "COMMON" in linker scripts.
+ // By default, it should go to .bss section.
+ if (S->Name == "COMMON")
+ return ".bss";
+
+ return S->Name;
+}
+
+static bool needsInterpSection() {
+ return !SharedFiles.empty() && !Config->DynamicLinker.empty() &&
+ Script->needsInterpSection();
+}
+
+template <class ELFT> void elf::writeResult() { Writer<ELFT>().run(); }
+
+template <class ELFT> void Writer<ELFT>::removeEmptyPTLoad() {
+ llvm::erase_if(Phdrs, [&](const PhdrEntry *P) {
+ if (P->p_type != PT_LOAD)
+ return false;
+ if (!P->FirstSec)
+ return true;
+ uint64_t Size = P->LastSec->Addr + P->LastSec->Size - P->FirstSec->Addr;
+ return Size == 0;
+ });
+}
+
+template <class ELFT> static void combineEhFrameSections() {
+ for (InputSectionBase *&S : InputSections) {
+ EhInputSection *ES = dyn_cast<EhInputSection>(S);
+ if (!ES || !ES->Live)
+ continue;
+
+ In.EhFrame->addSection<ELFT>(ES);
+ S = nullptr;
+ }
+
+ std::vector<InputSectionBase *> &V = InputSections;
+ V.erase(std::remove(V.begin(), V.end(), nullptr), V.end());
+}
+
+static Defined *addOptionalRegular(StringRef Name, SectionBase *Sec,
+ uint64_t Val, uint8_t StOther = STV_HIDDEN,
+ uint8_t Binding = STB_GLOBAL) {
+ Symbol *S = Symtab->find(Name);
+ if (!S || S->isDefined())
+ return nullptr;
+ return Symtab->addDefined(Name, StOther, STT_NOTYPE, Val,
+ /*Size=*/0, Binding, Sec,
+ /*File=*/nullptr);
+}
+
+static Defined *addAbsolute(StringRef Name) {
+ return Symtab->addDefined(Name, STV_HIDDEN, STT_NOTYPE, 0, 0, STB_GLOBAL,
+ nullptr, nullptr);
+}
+
+// The linker is expected to define some symbols depending on
+// the linking result. This function defines such symbols.
+void elf::addReservedSymbols() {
+ if (Config->EMachine == EM_MIPS) {
+ // Define _gp for MIPS. st_value of _gp symbol will be updated by Writer
+ // so that it points to an absolute address which by default is relative
+ // to GOT. Default offset is 0x7ff0.
+ // See "Global Data Symbols" in Chapter 6 in the following document:
+ // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+ ElfSym::MipsGp = addAbsolute("_gp");
+
+ // On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between
+ // start of function and 'gp' pointer into GOT.
+ if (Symtab->find("_gp_disp"))
+ ElfSym::MipsGpDisp = addAbsolute("_gp_disp");
+
+ // The __gnu_local_gp is a magic symbol equal to the current value of 'gp'
+ // pointer. This symbol is used in the code generated by .cpload pseudo-op
+ // in case of using -mno-shared option.
+ // https://sourceware.org/ml/binutils/2004-12/msg00094.html
+ if (Symtab->find("__gnu_local_gp"))
+ ElfSym::MipsLocalGp = addAbsolute("__gnu_local_gp");
+ }
+
+ // The Power Architecture 64-bit v2 ABI defines a TableOfContents (TOC) which
+ // combines the typical ELF GOT with the small data sections. It commonly
+ // includes .got .toc .sdata .sbss. The .TOC. symbol replaces both
+ // _GLOBAL_OFFSET_TABLE_ and _SDA_BASE_ from the 32-bit ABI. It is used to
+ // represent the TOC base which is offset by 0x8000 bytes from the start of
+ // the .got section.
+ // We do not allow _GLOBAL_OFFSET_TABLE_ to be defined by input objects as the
+ // correctness of some relocations depends on its value.
+ StringRef GotTableSymName =
+ (Config->EMachine == EM_PPC64) ? ".TOC." : "_GLOBAL_OFFSET_TABLE_";
+ if (Symbol *S = Symtab->find(GotTableSymName)) {
+ if (S->isDefined())
+ error(toString(S->File) + " cannot redefine linker defined symbol '" +
+ GotTableSymName + "'");
+ else
+ ElfSym::GlobalOffsetTable = Symtab->addDefined(
+ GotTableSymName, STV_HIDDEN, STT_NOTYPE, Target->GotBaseSymOff,
+ /*Size=*/0, STB_GLOBAL, Out::ElfHeader,
+ /*File=*/nullptr);
+ }
+
+ // __ehdr_start is the location of ELF file headers. Note that we define
+ // this symbol unconditionally even when using a linker script, which
+ // differs from the behavior implemented by GNU linker which only define
+ // this symbol if ELF headers are in the memory mapped segment.
+ addOptionalRegular("__ehdr_start", Out::ElfHeader, 0, STV_HIDDEN);
+
+ // __executable_start is not documented, but the expectation of at
+ // least the Android libc is that it points to the ELF header.
+ addOptionalRegular("__executable_start", Out::ElfHeader, 0, STV_HIDDEN);
+
+ // __dso_handle symbol is passed to cxa_finalize as a marker to identify
+ // each DSO. The address of the symbol doesn't matter as long as they are
+ // different in different DSOs, so we chose the start address of the DSO.
+ addOptionalRegular("__dso_handle", Out::ElfHeader, 0, STV_HIDDEN);
+
+ // If linker script do layout we do not need to create any standart symbols.
+ if (Script->HasSectionsCommand)
+ return;
+
+ auto Add = [](StringRef S, int64_t Pos) {
+ return addOptionalRegular(S, Out::ElfHeader, Pos, STV_DEFAULT);
+ };
+
+ ElfSym::Bss = Add("__bss_start", 0);
+ ElfSym::End1 = Add("end", -1);
+ ElfSym::End2 = Add("_end", -1);
+ ElfSym::Etext1 = Add("etext", -1);
+ ElfSym::Etext2 = Add("_etext", -1);
+ ElfSym::Edata1 = Add("edata", -1);
+ ElfSym::Edata2 = Add("_edata", -1);
+}
+
+static OutputSection *findSection(StringRef Name) {
+ for (BaseCommand *Base : Script->SectionCommands)
+ if (auto *Sec = dyn_cast<OutputSection>(Base))
+ if (Sec->Name == Name)
+ return Sec;
+ return nullptr;
+}
+
+// Initialize Out members.
+template <class ELFT> static void createSyntheticSections() {
+ // Initialize all pointers with NULL. This is needed because
+ // you can call lld::elf::main more than once as a library.
+ memset(&Out::First, 0, sizeof(Out));
+
+ auto Add = [](InputSectionBase *Sec) { InputSections.push_back(Sec); };
+
+ In.DynStrTab = make<StringTableSection>(".dynstr", true);
+ In.Dynamic = make<DynamicSection<ELFT>>();
+ if (Config->AndroidPackDynRelocs) {
+ In.RelaDyn = make<AndroidPackedRelocationSection<ELFT>>(
+ Config->IsRela ? ".rela.dyn" : ".rel.dyn");
+ } else {
+ In.RelaDyn = make<RelocationSection<ELFT>>(
+ Config->IsRela ? ".rela.dyn" : ".rel.dyn", Config->ZCombreloc);
+ }
+ In.ShStrTab = make<StringTableSection>(".shstrtab", false);
+
+ Out::ProgramHeaders = make<OutputSection>("", 0, SHF_ALLOC);
+ Out::ProgramHeaders->Alignment = Config->Wordsize;
+
+ if (needsInterpSection()) {
+ In.Interp = createInterpSection();
+ Add(In.Interp);
+ }
+
+ if (Config->Strip != StripPolicy::All) {
+ In.StrTab = make<StringTableSection>(".strtab", false);
+ In.SymTab = make<SymbolTableSection<ELFT>>(*In.StrTab);
+ In.SymTabShndx = make<SymtabShndxSection>();
+ }
+
+ if (Config->BuildId != BuildIdKind::None) {
+ In.BuildId = make<BuildIdSection>();
+ Add(In.BuildId);
+ }
+
+ In.Bss = make<BssSection>(".bss", 0, 1);
+ Add(In.Bss);
+
+ // If there is a SECTIONS command and a .data.rel.ro section name use name
+ // .data.rel.ro.bss so that we match in the .data.rel.ro output section.
+ // This makes sure our relro is contiguous.
+ bool HasDataRelRo = Script->HasSectionsCommand && findSection(".data.rel.ro");
+ In.BssRelRo =
+ make<BssSection>(HasDataRelRo ? ".data.rel.ro.bss" : ".bss.rel.ro", 0, 1);
+ Add(In.BssRelRo);
+
+ // Add MIPS-specific sections.
+ if (Config->EMachine == EM_MIPS) {
+ if (!Config->Shared && Config->HasDynSymTab) {
+ In.MipsRldMap = make<MipsRldMapSection>();
+ Add(In.MipsRldMap);
+ }
+ if (auto *Sec = MipsAbiFlagsSection<ELFT>::create())
+ Add(Sec);
+ if (auto *Sec = MipsOptionsSection<ELFT>::create())
+ Add(Sec);
+ if (auto *Sec = MipsReginfoSection<ELFT>::create())
+ Add(Sec);
+ }
+
+ if (Config->HasDynSymTab) {
+ In.DynSymTab = make<SymbolTableSection<ELFT>>(*In.DynStrTab);
+ Add(In.DynSymTab);
+
+ InX<ELFT>::VerSym = make<VersionTableSection<ELFT>>();
+ Add(InX<ELFT>::VerSym);
+
+ if (!Config->VersionDefinitions.empty()) {
+ In.VerDef = make<VersionDefinitionSection>();
+ Add(In.VerDef);
+ }
+
+ InX<ELFT>::VerNeed = make<VersionNeedSection<ELFT>>();
+ Add(InX<ELFT>::VerNeed);
+
+ if (Config->GnuHash) {
+ In.GnuHashTab = make<GnuHashTableSection>();
+ Add(In.GnuHashTab);
+ }
+
+ if (Config->SysvHash) {
+ In.HashTab = make<HashTableSection>();
+ Add(In.HashTab);
+ }
+
+ Add(In.Dynamic);
+ Add(In.DynStrTab);
+ Add(In.RelaDyn);
+ }
+
+ if (Config->RelrPackDynRelocs) {
+ In.RelrDyn = make<RelrSection<ELFT>>();
+ Add(In.RelrDyn);
+ }
+
+ // Add .got. MIPS' .got is so different from the other archs,
+ // it has its own class.
+ if (Config->EMachine == EM_MIPS) {
+ In.MipsGot = make<MipsGotSection>();
+ Add(In.MipsGot);
+ } else {
+ In.Got = make<GotSection>();
+ Add(In.Got);
+ }
+
+ if (Config->EMachine == EM_PPC64) {
+ In.PPC64LongBranchTarget = make<PPC64LongBranchTargetSection>();
+ Add(In.PPC64LongBranchTarget);
+ }
+
+ In.GotPlt = make<GotPltSection>();
+ Add(In.GotPlt);
+ In.IgotPlt = make<IgotPltSection>();
+ Add(In.IgotPlt);
+
+ if (Config->GdbIndex) {
+ In.GdbIndex = GdbIndexSection::create<ELFT>();
+ Add(In.GdbIndex);
+ }
+
+ // We always need to add rel[a].plt to output if it has entries.
+ // Even for static linking it can contain R_[*]_IRELATIVE relocations.
+ In.RelaPlt = make<RelocationSection<ELFT>>(
+ Config->IsRela ? ".rela.plt" : ".rel.plt", false /*Sort*/);
+ Add(In.RelaPlt);
+
+ // The RelaIplt immediately follows .rel.plt (.rel.dyn for ARM) to ensure
+ // that the IRelative relocations are processed last by the dynamic loader.
+ // We cannot place the iplt section in .rel.dyn when Android relocation
+ // packing is enabled because that would cause a section type mismatch.
+ // However, because the Android dynamic loader reads .rel.plt after .rel.dyn,
+ // we can get the desired behaviour by placing the iplt section in .rel.plt.
+ In.RelaIplt = make<RelocationSection<ELFT>>(
+ (Config->EMachine == EM_ARM && !Config->AndroidPackDynRelocs)
+ ? ".rel.dyn"
+ : In.RelaPlt->Name,
+ false /*Sort*/);
+ Add(In.RelaIplt);
+
+ In.Plt = make<PltSection>(false);
+ Add(In.Plt);
+ In.Iplt = make<PltSection>(true);
+ Add(In.Iplt);
+
+ // .note.GNU-stack is always added when we are creating a re-linkable
+ // object file. Other linkers are using the presence of this marker
+ // section to control the executable-ness of the stack area, but that
+ // is irrelevant these days. Stack area should always be non-executable
+ // by default. So we emit this section unconditionally.
+ if (Config->Relocatable)
+ Add(make<GnuStackSection>());
+
+ if (!Config->Relocatable) {
+ if (Config->EhFrameHdr) {
+ In.EhFrameHdr = make<EhFrameHeader>();
+ Add(In.EhFrameHdr);
+ }
+ In.EhFrame = make<EhFrameSection>();
+ Add(In.EhFrame);
+ }
+
+ if (In.SymTab)
+ Add(In.SymTab);
+ if (In.SymTabShndx)
+ Add(In.SymTabShndx);
+ Add(In.ShStrTab);
+ if (In.StrTab)
+ Add(In.StrTab);
+
+ if (Config->EMachine == EM_ARM && !Config->Relocatable)
+ // Add a sentinel to terminate .ARM.exidx. It helps an unwinder
+ // to find the exact address range of the last entry.
+ Add(make<ARMExidxSentinelSection>());
+}
+
+// The main function of the writer.
+template <class ELFT> void Writer<ELFT>::run() {
+ // Create linker-synthesized sections such as .got or .plt.
+ // Such sections are of type input section.
+ createSyntheticSections<ELFT>();
+
+ if (!Config->Relocatable)
+ combineEhFrameSections<ELFT>();
+
+ // We want to process linker script commands. When SECTIONS command
+ // is given we let it create sections.
+ Script->processSectionCommands();
+
+ // Linker scripts controls how input sections are assigned to output sections.
+ // Input sections that were not handled by scripts are called "orphans", and
+ // they are assigned to output sections by the default rule. Process that.
+ Script->addOrphanSections();
+
+ if (Config->Discard != DiscardPolicy::All)
+ copyLocalSymbols();
+
+ if (Config->CopyRelocs)
+ addSectionSymbols();
+
+ // Now that we have a complete set of output sections. This function
+ // completes section contents. For example, we need to add strings
+ // to the string table, and add entries to .got and .plt.
+ // finalizeSections does that.
+ finalizeSections();
+ checkExecuteOnly();
+ if (errorCount())
+ return;
+
+ Script->assignAddresses();
+
+ // If -compressed-debug-sections is specified, we need to compress
+ // .debug_* sections. Do it right now because it changes the size of
+ // output sections.
+ for (OutputSection *Sec : OutputSections)
+ Sec->maybeCompress<ELFT>();
+
+ Script->allocateHeaders(Phdrs);
+
+ // Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a
+ // 0 sized region. This has to be done late since only after assignAddresses
+ // we know the size of the sections.
+ removeEmptyPTLoad();
+
+ if (!Config->OFormatBinary)
+ assignFileOffsets();
+ else
+ assignFileOffsetsBinary();
+
+ setPhdrs();
+
+ if (Config->Relocatable)
+ for (OutputSection *Sec : OutputSections)
+ Sec->Addr = 0;
+
+ if (Config->CheckSections)
+ checkSections();
+
+ // It does not make sense try to open the file if we have error already.
+ if (errorCount())
+ return;
+ // Write the result down to a file.
+ openFile();
+ if (errorCount())
+ return;
+
+ if (!Config->OFormatBinary) {
+ writeTrapInstr();
+ writeHeader();
+ writeSections();
+ } else {
+ writeSectionsBinary();
+ }
+
+ // Backfill .note.gnu.build-id section content. This is done at last
+ // because the content is usually a hash value of the entire output file.
+ writeBuildId();
+ if (errorCount())
+ return;
+
+ // Handle -Map and -cref options.
+ writeMapFile();
+ writeCrossReferenceTable();
+ if (errorCount())
+ return;
+
+ if (auto E = Buffer->commit())
+ error("failed to write to the output file: " + toString(std::move(E)));
+}
+
+static bool shouldKeepInSymtab(SectionBase *Sec, StringRef SymName,
+ const Symbol &B) {
+ if (B.isSection())
+ return false;
+
+ if (Config->Discard == DiscardPolicy::None)
+ return true;
+
+ // In ELF assembly .L symbols are normally discarded by the assembler.
+ // If the assembler fails to do so, the linker discards them if
+ // * --discard-locals is used.
+ // * The symbol is in a SHF_MERGE section, which is normally the reason for
+ // the assembler keeping the .L symbol.
+ if (!SymName.startswith(".L") && !SymName.empty())
+ return true;
+
+ if (Config->Discard == DiscardPolicy::Locals)
+ return false;
+
+ return !Sec || !(Sec->Flags & SHF_MERGE);
+}
+
+static bool includeInSymtab(const Symbol &B) {
+ if (!B.isLocal() && !B.IsUsedInRegularObj)
+ return false;
+
+ if (auto *D = dyn_cast<Defined>(&B)) {
+ // Always include absolute symbols.
+ SectionBase *Sec = D->Section;
+ if (!Sec)
+ return true;
+ Sec = Sec->Repl;
+
+ // Exclude symbols pointing to garbage-collected sections.
+ if (isa<InputSectionBase>(Sec) && !Sec->Live)
+ return false;
+
+ if (auto *S = dyn_cast<MergeInputSection>(Sec))
+ if (!S->getSectionPiece(D->Value)->Live)
+ return false;
+ return true;
+ }
+ return B.Used;
+}
+
+// Local symbols are not in the linker's symbol table. This function scans
+// each object file's symbol table to copy local symbols to the output.
+template <class ELFT> void Writer<ELFT>::copyLocalSymbols() {
+ if (!In.SymTab)
+ return;
+ for (InputFile *File : ObjectFiles) {
+ ObjFile<ELFT> *F = cast<ObjFile<ELFT>>(File);
+ for (Symbol *B : F->getLocalSymbols()) {
+ if (!B->isLocal())
+ fatal(toString(F) +
+ ": broken object: getLocalSymbols returns a non-local symbol");
+ auto *DR = dyn_cast<Defined>(B);
+
+ // No reason to keep local undefined symbol in symtab.
+ if (!DR)
+ continue;
+ if (!includeInSymtab(*B))
+ continue;
+
+ SectionBase *Sec = DR->Section;
+ if (!shouldKeepInSymtab(Sec, B->getName(), *B))
+ continue;
+ In.SymTab->addSymbol(B);
+ }
+ }
+}
+
+// Create a section symbol for each output section so that we can represent
+// relocations that point to the section. If we know that no relocation is
+// referring to a section (that happens if the section is a synthetic one), we
+// don't create a section symbol for that section.
+template <class ELFT> void Writer<ELFT>::addSectionSymbols() {
+ for (BaseCommand *Base : Script->SectionCommands) {
+ auto *Sec = dyn_cast<OutputSection>(Base);
+ if (!Sec)
+ continue;
+ auto I = llvm::find_if(Sec->SectionCommands, [](BaseCommand *Base) {
+ if (auto *ISD = dyn_cast<InputSectionDescription>(Base))
+ return !ISD->Sections.empty();
+ return false;
+ });
+ if (I == Sec->SectionCommands.end())
+ continue;
+ InputSection *IS = cast<InputSectionDescription>(*I)->Sections[0];
+
+ // Relocations are not using REL[A] section symbols.
+ if (IS->Type == SHT_REL || IS->Type == SHT_RELA)
+ continue;
+
+ // Unlike other synthetic sections, mergeable output sections contain data
+ // copied from input sections, and there may be a relocation pointing to its
+ // contents if -r or -emit-reloc are given.
+ if (isa<SyntheticSection>(IS) && !(IS->Flags & SHF_MERGE))
+ continue;
+
+ auto *Sym =
+ make<Defined>(IS->File, "", STB_LOCAL, /*StOther=*/0, STT_SECTION,
+ /*Value=*/0, /*Size=*/0, IS);
+ In.SymTab->addSymbol(Sym);
+ }
+}
+
+// Today's loaders have a feature to make segments read-only after
+// processing dynamic relocations to enhance security. PT_GNU_RELRO
+// is defined for that.
+//
+// This function returns true if a section needs to be put into a
+// PT_GNU_RELRO segment.
+static bool isRelroSection(const OutputSection *Sec) {
+ if (!Config->ZRelro)
+ return false;
+
+ uint64_t Flags = Sec->Flags;
+
+ // Non-allocatable or non-writable sections don't need RELRO because
+ // they are not writable or not even mapped to memory in the first place.
+ // RELRO is for sections that are essentially read-only but need to
+ // be writable only at process startup to allow dynamic linker to
+ // apply relocations.
+ if (!(Flags & SHF_ALLOC) || !(Flags & SHF_WRITE))
+ return false;
+
+ // Once initialized, TLS data segments are used as data templates
+ // for a thread-local storage. For each new thread, runtime
+ // allocates memory for a TLS and copy templates there. No thread
+ // are supposed to use templates directly. Thus, it can be in RELRO.
+ if (Flags & SHF_TLS)
+ return true;
+
+ // .init_array, .preinit_array and .fini_array contain pointers to
+ // functions that are executed on process startup or exit. These
+ // pointers are set by the static linker, and they are not expected
+ // to change at runtime. But if you are an attacker, you could do
+ // interesting things by manipulating pointers in .fini_array, for
+ // example. So they are put into RELRO.
+ uint32_t Type = Sec->Type;
+ if (Type == SHT_INIT_ARRAY || Type == SHT_FINI_ARRAY ||
+ Type == SHT_PREINIT_ARRAY)
+ return true;
+
+ // .got contains pointers to external symbols. They are resolved by
+ // the dynamic linker when a module is loaded into memory, and after
+ // that they are not expected to change. So, it can be in RELRO.
+ if (In.Got && Sec == In.Got->getParent())
+ return true;
+
+ // .toc is a GOT-ish section for PowerPC64. Their contents are accessed
+ // through r2 register, which is reserved for that purpose. Since r2 is used
+ // for accessing .got as well, .got and .toc need to be close enough in the
+ // virtual address space. Usually, .toc comes just after .got. Since we place
+ // .got into RELRO, .toc needs to be placed into RELRO too.
+ if (Sec->Name.equals(".toc"))
+ return true;
+
+ // .got.plt contains pointers to external function symbols. They are
+ // by default resolved lazily, so we usually cannot put it into RELRO.
+ // However, if "-z now" is given, the lazy symbol resolution is
+ // disabled, which enables us to put it into RELRO.
+ if (Sec == In.GotPlt->getParent())
+ return Config->ZNow;
+
+ // .dynamic section contains data for the dynamic linker, and
+ // there's no need to write to it at runtime, so it's better to put
+ // it into RELRO.
+ if (Sec == In.Dynamic->getParent())
+ return true;
+
+ // Sections with some special names are put into RELRO. This is a
+ // bit unfortunate because section names shouldn't be significant in
+ // ELF in spirit. But in reality many linker features depend on
+ // magic section names.
+ StringRef S = Sec->Name;
+ return S == ".data.rel.ro" || S == ".bss.rel.ro" || S == ".ctors" ||
+ S == ".dtors" || S == ".jcr" || S == ".eh_frame" ||
+ S == ".openbsd.randomdata";
+}
+
+// We compute a rank for each section. The rank indicates where the
+// section should be placed in the file. Instead of using simple
+// numbers (0,1,2...), we use a series of flags. One for each decision
+// point when placing the section.
+// Using flags has two key properties:
+// * It is easy to check if a give branch was taken.
+// * It is easy two see how similar two ranks are (see getRankProximity).
+enum RankFlags {
+ RF_NOT_ADDR_SET = 1 << 18,
+ RF_NOT_ALLOC = 1 << 17,
+ RF_NOT_INTERP = 1 << 16,
+ RF_NOT_NOTE = 1 << 15,
+ RF_WRITE = 1 << 14,
+ RF_EXEC_WRITE = 1 << 13,
+ RF_EXEC = 1 << 12,
+ RF_RODATA = 1 << 11,
+ RF_NON_TLS_BSS = 1 << 10,
+ RF_NON_TLS_BSS_RO = 1 << 9,
+ RF_NOT_TLS = 1 << 8,
+ RF_BSS = 1 << 7,
+ RF_PPC_NOT_TOCBSS = 1 << 6,
+ RF_PPC_TOCL = 1 << 5,
+ RF_PPC_TOC = 1 << 4,
+ RF_PPC_GOT = 1 << 3,
+ RF_PPC_BRANCH_LT = 1 << 2,
+ RF_MIPS_GPREL = 1 << 1,
+ RF_MIPS_NOT_GOT = 1 << 0
+};
+
+static unsigned getSectionRank(const OutputSection *Sec) {
+ unsigned Rank = 0;
+
+ // We want to put section specified by -T option first, so we
+ // can start assigning VA starting from them later.
+ if (Config->SectionStartMap.count(Sec->Name))
+ return Rank;
+ Rank |= RF_NOT_ADDR_SET;
+
+ // Allocatable sections go first to reduce the total PT_LOAD size and
+ // so debug info doesn't change addresses in actual code.
+ if (!(Sec->Flags & SHF_ALLOC))
+ return Rank | RF_NOT_ALLOC;
+
+ // Put .interp first because some loaders want to see that section
+ // on the first page of the executable file when loaded into memory.
+ if (Sec->Name == ".interp")
+ return Rank;
+ Rank |= RF_NOT_INTERP;
+
+ // Put .note sections (which make up one PT_NOTE) at the beginning so that
+ // they are likely to be included in a core file even if core file size is
+ // limited. In particular, we want a .note.gnu.build-id and a .note.tag to be
+ // included in a core to match core files with executables.
+ if (Sec->Type == SHT_NOTE)
+ return Rank;
+ Rank |= RF_NOT_NOTE;
+
+ // Sort sections based on their access permission in the following
+ // order: R, RX, RWX, RW. This order is based on the following
+ // considerations:
+ // * Read-only sections come first such that they go in the
+ // PT_LOAD covering the program headers at the start of the file.
+ // * Read-only, executable sections come next.
+ // * Writable, executable sections follow such that .plt on
+ // architectures where it needs to be writable will be placed
+ // between .text and .data.
+ // * Writable sections come last, such that .bss lands at the very
+ // end of the last PT_LOAD.
+ bool IsExec = Sec->Flags & SHF_EXECINSTR;
+ bool IsWrite = Sec->Flags & SHF_WRITE;
+
+ if (IsExec) {
+ if (IsWrite)
+ Rank |= RF_EXEC_WRITE;
+ else
+ Rank |= RF_EXEC;
+ } else if (IsWrite) {
+ Rank |= RF_WRITE;
+ } else if (Sec->Type == SHT_PROGBITS) {
+ // Make non-executable and non-writable PROGBITS sections (e.g .rodata
+ // .eh_frame) closer to .text. They likely contain PC or GOT relative
+ // relocations and there could be relocation overflow if other huge sections
+ // (.dynstr .dynsym) were placed in between.
+ Rank |= RF_RODATA;
+ }
+
+ // If we got here we know that both A and B are in the same PT_LOAD.
+
+ bool IsTls = Sec->Flags & SHF_TLS;
+ bool IsNoBits = Sec->Type == SHT_NOBITS;
+
+ // The first requirement we have is to put (non-TLS) nobits sections last. The
+ // reason is that the only thing the dynamic linker will see about them is a
+ // p_memsz that is larger than p_filesz. Seeing that it zeros the end of the
+ // PT_LOAD, so that has to correspond to the nobits sections.
+ bool IsNonTlsNoBits = IsNoBits && !IsTls;
+ if (IsNonTlsNoBits)
+ Rank |= RF_NON_TLS_BSS;
+
+ // We place nobits RelRo sections before plain r/w ones, and non-nobits RelRo
+ // sections after r/w ones, so that the RelRo sections are contiguous.
+ bool IsRelRo = isRelroSection(Sec);
+ if (IsNonTlsNoBits && !IsRelRo)
+ Rank |= RF_NON_TLS_BSS_RO;
+ if (!IsNonTlsNoBits && IsRelRo)
+ Rank |= RF_NON_TLS_BSS_RO;
+
+ // The TLS initialization block needs to be a single contiguous block in a R/W
+ // PT_LOAD, so stick TLS sections directly before the other RelRo R/W
+ // sections. The TLS NOBITS sections are placed here as they don't take up
+ // virtual address space in the PT_LOAD.
+ if (!IsTls)
+ Rank |= RF_NOT_TLS;
+
+ // Within the TLS initialization block, the non-nobits sections need to appear
+ // first.
+ if (IsNoBits)
+ Rank |= RF_BSS;
+
+ // Some architectures have additional ordering restrictions for sections
+ // within the same PT_LOAD.
+ if (Config->EMachine == EM_PPC64) {
+ // PPC64 has a number of special SHT_PROGBITS+SHF_ALLOC+SHF_WRITE sections
+ // that we would like to make sure appear is a specific order to maximize
+ // their coverage by a single signed 16-bit offset from the TOC base
+ // pointer. Conversely, the special .tocbss section should be first among
+ // all SHT_NOBITS sections. This will put it next to the loaded special
+ // PPC64 sections (and, thus, within reach of the TOC base pointer).
+ StringRef Name = Sec->Name;
+ if (Name != ".tocbss")
+ Rank |= RF_PPC_NOT_TOCBSS;
+
+ if (Name == ".toc1")
+ Rank |= RF_PPC_TOCL;
+
+ if (Name == ".toc")
+ Rank |= RF_PPC_TOC;
+
+ if (Name == ".got")
+ Rank |= RF_PPC_GOT;
+
+ if (Name == ".branch_lt")
+ Rank |= RF_PPC_BRANCH_LT;
+ }
+
+ if (Config->EMachine == EM_MIPS) {
+ // All sections with SHF_MIPS_GPREL flag should be grouped together
+ // because data in these sections is addressable with a gp relative address.
+ if (Sec->Flags & SHF_MIPS_GPREL)
+ Rank |= RF_MIPS_GPREL;
+
+ if (Sec->Name != ".got")
+ Rank |= RF_MIPS_NOT_GOT;
+ }
+
+ return Rank;
+}
+
+static bool compareSections(const BaseCommand *ACmd, const BaseCommand *BCmd) {
+ const OutputSection *A = cast<OutputSection>(ACmd);
+ const OutputSection *B = cast<OutputSection>(BCmd);
+
+ if (A->SortRank != B->SortRank)
+ return A->SortRank < B->SortRank;
+
+ if (!(A->SortRank & RF_NOT_ADDR_SET))
+ return Config->SectionStartMap.lookup(A->Name) <
+ Config->SectionStartMap.lookup(B->Name);
+ return false;
+}
+
+void PhdrEntry::add(OutputSection *Sec) {
+ LastSec = Sec;
+ if (!FirstSec)
+ FirstSec = Sec;
+ p_align = std::max(p_align, Sec->Alignment);
+ if (p_type == PT_LOAD)
+ Sec->PtLoad = this;
+}
+
+// The beginning and the ending of .rel[a].plt section are marked
+// with __rel[a]_iplt_{start,end} symbols if it is a statically linked
+// executable. The runtime needs these symbols in order to resolve
+// all IRELATIVE relocs on startup. For dynamic executables, we don't
+// need these symbols, since IRELATIVE relocs are resolved through GOT
+// and PLT. For details, see http://www.airs.com/blog/archives/403.
+template <class ELFT> void Writer<ELFT>::addRelIpltSymbols() {
+ if (Config->Relocatable || needsInterpSection())
+ return;
+
+ // By default, __rela_iplt_{start,end} belong to a dummy section 0
+ // because .rela.plt might be empty and thus removed from output.
+ // We'll override Out::ElfHeader with In.RelaIplt later when we are
+ // sure that .rela.plt exists in output.
+ ElfSym::RelaIpltStart = addOptionalRegular(
+ Config->IsRela ? "__rela_iplt_start" : "__rel_iplt_start",
+ Out::ElfHeader, 0, STV_HIDDEN, STB_WEAK);
+
+ ElfSym::RelaIpltEnd = addOptionalRegular(
+ Config->IsRela ? "__rela_iplt_end" : "__rel_iplt_end",
+ Out::ElfHeader, 0, STV_HIDDEN, STB_WEAK);
+}
+
+template <class ELFT>
+void Writer<ELFT>::forEachRelSec(
+ llvm::function_ref<void(InputSectionBase &)> Fn) {
+ // Scan all relocations. Each relocation goes through a series
+ // of tests to determine if it needs special treatment, such as
+ // creating GOT, PLT, copy relocations, etc.
+ // Note that relocations for non-alloc sections are directly
+ // processed by InputSection::relocateNonAlloc.
+ for (InputSectionBase *IS : InputSections)
+ if (IS->Live && isa<InputSection>(IS) && (IS->Flags & SHF_ALLOC))
+ Fn(*IS);
+ for (EhInputSection *ES : In.EhFrame->Sections)
+ Fn(*ES);
+}
+
+// This function generates assignments for predefined symbols (e.g. _end or
+// _etext) and inserts them into the commands sequence to be processed at the
+// appropriate time. This ensures that the value is going to be correct by the
+// time any references to these symbols are processed and is equivalent to
+// defining these symbols explicitly in the linker script.
+template <class ELFT> void Writer<ELFT>::setReservedSymbolSections() {
+ if (ElfSym::GlobalOffsetTable) {
+ // The _GLOBAL_OFFSET_TABLE_ symbol is defined by target convention usually
+ // to the start of the .got or .got.plt section.
+ InputSection *GotSection = In.GotPlt;
+ if (!Target->GotBaseSymInGotPlt)
+ GotSection = In.MipsGot ? cast<InputSection>(In.MipsGot)
+ : cast<InputSection>(In.Got);
+ ElfSym::GlobalOffsetTable->Section = GotSection;
+ }
+
+ // .rela_iplt_{start,end} mark the start and the end of .rela.plt section.
+ if (ElfSym::RelaIpltStart && !In.RelaIplt->empty()) {
+ ElfSym::RelaIpltStart->Section = In.RelaIplt;
+ ElfSym::RelaIpltEnd->Section = In.RelaIplt;
+ ElfSym::RelaIpltEnd->Value = In.RelaIplt->getSize();
+ }
+
+ PhdrEntry *Last = nullptr;
+ PhdrEntry *LastRO = nullptr;
+
+ for (PhdrEntry *P : Phdrs) {
+ if (P->p_type != PT_LOAD)
+ continue;
+ Last = P;
+ if (!(P->p_flags & PF_W))
+ LastRO = P;
+ }
+
+ if (LastRO) {
+ // _etext is the first location after the last read-only loadable segment.
+ if (ElfSym::Etext1)
+ ElfSym::Etext1->Section = LastRO->LastSec;
+ if (ElfSym::Etext2)
+ ElfSym::Etext2->Section = LastRO->LastSec;
+ }
+
+ if (Last) {
+ // _edata points to the end of the last mapped initialized section.
+ OutputSection *Edata = nullptr;
+ for (OutputSection *OS : OutputSections) {
+ if (OS->Type != SHT_NOBITS)
+ Edata = OS;
+ if (OS == Last->LastSec)
+ break;
+ }
+
+ if (ElfSym::Edata1)
+ ElfSym::Edata1->Section = Edata;
+ if (ElfSym::Edata2)
+ ElfSym::Edata2->Section = Edata;
+
+ // _end is the first location after the uninitialized data region.
+ if (ElfSym::End1)
+ ElfSym::End1->Section = Last->LastSec;
+ if (ElfSym::End2)
+ ElfSym::End2->Section = Last->LastSec;
+ }
+
+ if (ElfSym::Bss)
+ ElfSym::Bss->Section = findSection(".bss");
+
+ // Setup MIPS _gp_disp/__gnu_local_gp symbols which should
+ // be equal to the _gp symbol's value.
+ if (ElfSym::MipsGp) {
+ // Find GP-relative section with the lowest address
+ // and use this address to calculate default _gp value.
+ for (OutputSection *OS : OutputSections) {
+ if (OS->Flags & SHF_MIPS_GPREL) {
+ ElfSym::MipsGp->Section = OS;
+ ElfSym::MipsGp->Value = 0x7ff0;
+ break;
+ }
+ }
+ }
+}
+
+// We want to find how similar two ranks are.
+// The more branches in getSectionRank that match, the more similar they are.
+// Since each branch corresponds to a bit flag, we can just use
+// countLeadingZeros.
+static int getRankProximityAux(OutputSection *A, OutputSection *B) {
+ return countLeadingZeros(A->SortRank ^ B->SortRank);
+}
+
+static int getRankProximity(OutputSection *A, BaseCommand *B) {
+ if (auto *Sec = dyn_cast<OutputSection>(B))
+ return getRankProximityAux(A, Sec);
+ return -1;
+}
+
+// When placing orphan sections, we want to place them after symbol assignments
+// so that an orphan after
+// begin_foo = .;
+// foo : { *(foo) }
+// end_foo = .;
+// doesn't break the intended meaning of the begin/end symbols.
+// We don't want to go over sections since findOrphanPos is the
+// one in charge of deciding the order of the sections.
+// We don't want to go over changes to '.', since doing so in
+// rx_sec : { *(rx_sec) }
+// . = ALIGN(0x1000);
+// /* The RW PT_LOAD starts here*/
+// rw_sec : { *(rw_sec) }
+// would mean that the RW PT_LOAD would become unaligned.
+static bool shouldSkip(BaseCommand *Cmd) {
+ if (auto *Assign = dyn_cast<SymbolAssignment>(Cmd))
+ return Assign->Name != ".";
+ return false;
+}
+
+// We want to place orphan sections so that they share as much
+// characteristics with their neighbors as possible. For example, if
+// both are rw, or both are tls.
+template <typename ELFT>
+static std::vector<BaseCommand *>::iterator
+findOrphanPos(std::vector<BaseCommand *>::iterator B,
+ std::vector<BaseCommand *>::iterator E) {
+ OutputSection *Sec = cast<OutputSection>(*E);
+
+ // Find the first element that has as close a rank as possible.
+ auto I = std::max_element(B, E, [=](BaseCommand *A, BaseCommand *B) {
+ return getRankProximity(Sec, A) < getRankProximity(Sec, B);
+ });
+ if (I == E)
+ return E;
+
+ // Consider all existing sections with the same proximity.
+ int Proximity = getRankProximity(Sec, *I);
+ for (; I != E; ++I) {
+ auto *CurSec = dyn_cast<OutputSection>(*I);
+ if (!CurSec)
+ continue;
+ if (getRankProximity(Sec, CurSec) != Proximity ||
+ Sec->SortRank < CurSec->SortRank)
+ break;
+ }
+
+ auto IsOutputSec = [](BaseCommand *Cmd) { return isa<OutputSection>(Cmd); };
+ auto J = std::find_if(llvm::make_reverse_iterator(I),
+ llvm::make_reverse_iterator(B), IsOutputSec);
+ I = J.base();
+
+ // As a special case, if the orphan section is the last section, put
+ // it at the very end, past any other commands.
+ // This matches bfd's behavior and is convenient when the linker script fully
+ // specifies the start of the file, but doesn't care about the end (the non
+ // alloc sections for example).
+ auto NextSec = std::find_if(I, E, IsOutputSec);
+ if (NextSec == E)
+ return E;
+
+ while (I != E && shouldSkip(*I))
+ ++I;
+ return I;
+}
+
+// Builds section order for handling --symbol-ordering-file.
+static DenseMap<const InputSectionBase *, int> buildSectionOrder() {
+ DenseMap<const InputSectionBase *, int> SectionOrder;
+ // Use the rarely used option -call-graph-ordering-file to sort sections.
+ if (!Config->CallGraphProfile.empty())
+ return computeCallGraphProfileOrder();
+
+ if (Config->SymbolOrderingFile.empty())
+ return SectionOrder;
+
+ struct SymbolOrderEntry {
+ int Priority;
+ bool Present;
+ };
+
+ // Build a map from symbols to their priorities. Symbols that didn't
+ // appear in the symbol ordering file have the lowest priority 0.
+ // All explicitly mentioned symbols have negative (higher) priorities.
+ DenseMap<StringRef, SymbolOrderEntry> SymbolOrder;
+ int Priority = -Config->SymbolOrderingFile.size();
+ for (StringRef S : Config->SymbolOrderingFile)
+ SymbolOrder.insert({S, {Priority++, false}});
+
+ // Build a map from sections to their priorities.
+ auto AddSym = [&](Symbol &Sym) {
+ auto It = SymbolOrder.find(Sym.getName());
+ if (It == SymbolOrder.end())
+ return;
+ SymbolOrderEntry &Ent = It->second;
+ Ent.Present = true;
+
+ maybeWarnUnorderableSymbol(&Sym);
+
+ if (auto *D = dyn_cast<Defined>(&Sym)) {
+ if (auto *Sec = dyn_cast_or_null<InputSectionBase>(D->Section)) {
+ int &Priority = SectionOrder[cast<InputSectionBase>(Sec->Repl)];
+ Priority = std::min(Priority, Ent.Priority);
+ }
+ }
+ };
+
+ // We want both global and local symbols. We get the global ones from the
+ // symbol table and iterate the object files for the local ones.
+ for (Symbol *Sym : Symtab->getSymbols())
+ if (!Sym->isLazy())
+ AddSym(*Sym);
+ for (InputFile *File : ObjectFiles)
+ for (Symbol *Sym : File->getSymbols())
+ if (Sym->isLocal())
+ AddSym(*Sym);
+
+ if (Config->WarnSymbolOrdering)
+ for (auto OrderEntry : SymbolOrder)
+ if (!OrderEntry.second.Present)
+ warn("symbol ordering file: no such symbol: " + OrderEntry.first);
+
+ return SectionOrder;
+}
+
+// Sorts the sections in ISD according to the provided section order.
+static void
+sortISDBySectionOrder(InputSectionDescription *ISD,
+ const DenseMap<const InputSectionBase *, int> &Order) {
+ std::vector<InputSection *> UnorderedSections;
+ std::vector<std::pair<InputSection *, int>> OrderedSections;
+ uint64_t UnorderedSize = 0;
+
+ for (InputSection *IS : ISD->Sections) {
+ auto I = Order.find(IS);
+ if (I == Order.end()) {
+ UnorderedSections.push_back(IS);
+ UnorderedSize += IS->getSize();
+ continue;
+ }
+ OrderedSections.push_back({IS, I->second});
+ }
+ llvm::sort(OrderedSections, [&](std::pair<InputSection *, int> A,
+ std::pair<InputSection *, int> B) {
+ return A.second < B.second;
+ });
+
+ // Find an insertion point for the ordered section list in the unordered
+ // section list. On targets with limited-range branches, this is the mid-point
+ // of the unordered section list. This decreases the likelihood that a range
+ // extension thunk will be needed to enter or exit the ordered region. If the
+ // ordered section list is a list of hot functions, we can generally expect
+ // the ordered functions to be called more often than the unordered functions,
+ // making it more likely that any particular call will be within range, and
+ // therefore reducing the number of thunks required.
+ //
+ // For example, imagine that you have 8MB of hot code and 32MB of cold code.
+ // If the layout is:
+ //
+ // 8MB hot
+ // 32MB cold
+ //
+ // only the first 8-16MB of the cold code (depending on which hot function it
+ // is actually calling) can call the hot code without a range extension thunk.
+ // However, if we use this layout:
+ //
+ // 16MB cold
+ // 8MB hot
+ // 16MB cold
+ //
+ // both the last 8-16MB of the first block of cold code and the first 8-16MB
+ // of the second block of cold code can call the hot code without a thunk. So
+ // we effectively double the amount of code that could potentially call into
+ // the hot code without a thunk.
+ size_t InsPt = 0;
+ if (Target->getThunkSectionSpacing() && !OrderedSections.empty()) {
+ uint64_t UnorderedPos = 0;
+ for (; InsPt != UnorderedSections.size(); ++InsPt) {
+ UnorderedPos += UnorderedSections[InsPt]->getSize();
+ if (UnorderedPos > UnorderedSize / 2)
+ break;
+ }
+ }
+
+ ISD->Sections.clear();
+ for (InputSection *IS : makeArrayRef(UnorderedSections).slice(0, InsPt))
+ ISD->Sections.push_back(IS);
+ for (std::pair<InputSection *, int> P : OrderedSections)
+ ISD->Sections.push_back(P.first);
+ for (InputSection *IS : makeArrayRef(UnorderedSections).slice(InsPt))
+ ISD->Sections.push_back(IS);
+}
+
+static void sortSection(OutputSection *Sec,
+ const DenseMap<const InputSectionBase *, int> &Order) {
+ StringRef Name = Sec->Name;
+
+ // Sort input sections by section name suffixes for
+ // __attribute__((init_priority(N))).
+ if (Name == ".init_array" || Name == ".fini_array") {
+ if (!Script->HasSectionsCommand)
+ Sec->sortInitFini();
+ return;
+ }
+
+ // Sort input sections by the special rule for .ctors and .dtors.
+ if (Name == ".ctors" || Name == ".dtors") {
+ if (!Script->HasSectionsCommand)
+ Sec->sortCtorsDtors();
+ return;
+ }
+
+ // Never sort these.
+ if (Name == ".init" || Name == ".fini")
+ return;
+
+ // Sort input sections by priority using the list provided
+ // by --symbol-ordering-file.
+ if (!Order.empty())
+ for (BaseCommand *B : Sec->SectionCommands)
+ if (auto *ISD = dyn_cast<InputSectionDescription>(B))
+ sortISDBySectionOrder(ISD, Order);
+}
+
+// If no layout was provided by linker script, we want to apply default
+// sorting for special input sections. This also handles --symbol-ordering-file.
+template <class ELFT> void Writer<ELFT>::sortInputSections() {
+ // Build the order once since it is expensive.
+ DenseMap<const InputSectionBase *, int> Order = buildSectionOrder();
+ for (BaseCommand *Base : Script->SectionCommands)
+ if (auto *Sec = dyn_cast<OutputSection>(Base))
+ sortSection(Sec, Order);
+}
+
+template <class ELFT> void Writer<ELFT>::sortSections() {
+ Script->adjustSectionsBeforeSorting();
+
+ // Don't sort if using -r. It is not necessary and we want to preserve the
+ // relative order for SHF_LINK_ORDER sections.
+ if (Config->Relocatable)
+ return;
+
+ sortInputSections();
+
+ for (BaseCommand *Base : Script->SectionCommands) {
+ auto *OS = dyn_cast<OutputSection>(Base);
+ if (!OS)
+ continue;
+ OS->SortRank = getSectionRank(OS);
+
+ // We want to assign rude approximation values to OutSecOff fields
+ // to know the relative order of the input sections. We use it for
+ // sorting SHF_LINK_ORDER sections. See resolveShfLinkOrder().
+ uint64_t I = 0;
+ for (InputSection *Sec : getInputSections(OS))
+ Sec->OutSecOff = I++;
+ }
+
+ if (!Script->HasSectionsCommand) {
+ // We know that all the OutputSections are contiguous in this case.
+ auto IsSection = [](BaseCommand *Base) { return isa<OutputSection>(Base); };
+ std::stable_sort(
+ llvm::find_if(Script->SectionCommands, IsSection),
+ llvm::find_if(llvm::reverse(Script->SectionCommands), IsSection).base(),
+ compareSections);
+ return;
+ }
+
+ // Orphan sections are sections present in the input files which are
+ // not explicitly placed into the output file by the linker script.
+ //
+ // The sections in the linker script are already in the correct
+ // order. We have to figuere out where to insert the orphan
+ // sections.
+ //
+ // The order of the sections in the script is arbitrary and may not agree with
+ // compareSections. This means that we cannot easily define a strict weak
+ // ordering. To see why, consider a comparison of a section in the script and
+ // one not in the script. We have a two simple options:
+ // * Make them equivalent (a is not less than b, and b is not less than a).
+ // The problem is then that equivalence has to be transitive and we can
+ // have sections a, b and c with only b in a script and a less than c
+ // which breaks this property.
+ // * Use compareSectionsNonScript. Given that the script order doesn't have
+ // to match, we can end up with sections a, b, c, d where b and c are in the
+ // script and c is compareSectionsNonScript less than b. In which case d
+ // can be equivalent to c, a to b and d < a. As a concrete example:
+ // .a (rx) # not in script
+ // .b (rx) # in script
+ // .c (ro) # in script
+ // .d (ro) # not in script
+ //
+ // The way we define an order then is:
+ // * Sort only the orphan sections. They are in the end right now.
+ // * Move each orphan section to its preferred position. We try
+ // to put each section in the last position where it can share
+ // a PT_LOAD.
+ //
+ // There is some ambiguity as to where exactly a new entry should be
+ // inserted, because Commands contains not only output section
+ // commands but also other types of commands such as symbol assignment
+ // expressions. There's no correct answer here due to the lack of the
+ // formal specification of the linker script. We use heuristics to
+ // determine whether a new output command should be added before or
+ // after another commands. For the details, look at shouldSkip
+ // function.
+
+ auto I = Script->SectionCommands.begin();
+ auto E = Script->SectionCommands.end();
+ auto NonScriptI = std::find_if(I, E, [](BaseCommand *Base) {
+ if (auto *Sec = dyn_cast<OutputSection>(Base))
+ return Sec->SectionIndex == UINT32_MAX;
+ return false;
+ });
+
+ // Sort the orphan sections.
+ std::stable_sort(NonScriptI, E, compareSections);
+
+ // As a horrible special case, skip the first . assignment if it is before any
+ // section. We do this because it is common to set a load address by starting
+ // the script with ". = 0xabcd" and the expectation is that every section is
+ // after that.
+ auto FirstSectionOrDotAssignment =
+ std::find_if(I, E, [](BaseCommand *Cmd) { return !shouldSkip(Cmd); });
+ if (FirstSectionOrDotAssignment != E &&
+ isa<SymbolAssignment>(**FirstSectionOrDotAssignment))
+ ++FirstSectionOrDotAssignment;
+ I = FirstSectionOrDotAssignment;
+
+ while (NonScriptI != E) {
+ auto Pos = findOrphanPos<ELFT>(I, NonScriptI);
+ OutputSection *Orphan = cast<OutputSection>(*NonScriptI);
+
+ // As an optimization, find all sections with the same sort rank
+ // and insert them with one rotate.
+ unsigned Rank = Orphan->SortRank;
+ auto End = std::find_if(NonScriptI + 1, E, [=](BaseCommand *Cmd) {
+ return cast<OutputSection>(Cmd)->SortRank != Rank;
+ });
+ std::rotate(Pos, NonScriptI, End);
+ NonScriptI = End;
+ }
+
+ Script->adjustSectionsAfterSorting();
+}
+
+static bool compareByFilePosition(InputSection *A, InputSection *B) {
+ // Synthetic, i. e. a sentinel section, should go last.
+ if (A->kind() == InputSectionBase::Synthetic ||
+ B->kind() == InputSectionBase::Synthetic)
+ return A->kind() != InputSectionBase::Synthetic;
+
+ InputSection *LA = A->getLinkOrderDep();
+ InputSection *LB = B->getLinkOrderDep();
+ OutputSection *AOut = LA->getParent();
+ OutputSection *BOut = LB->getParent();
+
+ if (AOut != BOut)
+ return AOut->SectionIndex < BOut->SectionIndex;
+ return LA->OutSecOff < LB->OutSecOff;
+}
+
+// This function is used by the --merge-exidx-entries to detect duplicate
+// .ARM.exidx sections. It is Arm only.
+//
+// The .ARM.exidx section is of the form:
+// | PREL31 offset to function | Unwind instructions for function |
+// where the unwind instructions are either a small number of unwind
+// instructions inlined into the table entry, the special CANT_UNWIND value of
+// 0x1 or a PREL31 offset into a .ARM.extab Section that contains unwind
+// instructions.
+//
+// We return true if all the unwind instructions in the .ARM.exidx entries of
+// Cur can be merged into the last entry of Prev.
+static bool isDuplicateArmExidxSec(InputSection *Prev, InputSection *Cur) {
+
+ // References to .ARM.Extab Sections have bit 31 clear and are not the
+ // special EXIDX_CANTUNWIND bit-pattern.
+ auto IsExtabRef = [](uint32_t Unwind) {
+ return (Unwind & 0x80000000) == 0 && Unwind != 0x1;
+ };
+
+ struct ExidxEntry {
+ ulittle32_t Fn;
+ ulittle32_t Unwind;
+ };
+
+ // Get the last table Entry from the previous .ARM.exidx section.
+ const ExidxEntry &PrevEntry = Prev->getDataAs<ExidxEntry>().back();
+ if (IsExtabRef(PrevEntry.Unwind))
+ return false;
+
+ // We consider the unwind instructions of an .ARM.exidx table entry
+ // a duplicate if the previous unwind instructions if:
+ // - Both are the special EXIDX_CANTUNWIND.
+ // - Both are the same inline unwind instructions.
+ // We do not attempt to follow and check links into .ARM.extab tables as
+ // consecutive identical entries are rare and the effort to check that they
+ // are identical is high.
+
+ for (const ExidxEntry Entry : Cur->getDataAs<ExidxEntry>())
+ if (IsExtabRef(Entry.Unwind) || Entry.Unwind != PrevEntry.Unwind)
+ return false;
+
+ // All table entries in this .ARM.exidx Section can be merged into the
+ // previous Section.
+ return true;
+}
+
+template <class ELFT> void Writer<ELFT>::resolveShfLinkOrder() {
+ for (OutputSection *Sec : OutputSections) {
+ if (!(Sec->Flags & SHF_LINK_ORDER))
+ continue;
+
+ // Link order may be distributed across several InputSectionDescriptions
+ // but sort must consider them all at once.
+ std::vector<InputSection **> ScriptSections;
+ std::vector<InputSection *> Sections;
+ for (BaseCommand *Base : Sec->SectionCommands) {
+ if (auto *ISD = dyn_cast<InputSectionDescription>(Base)) {
+ for (InputSection *&IS : ISD->Sections) {
+ ScriptSections.push_back(&IS);
+ Sections.push_back(IS);
+ }
+ }
+ }
+ std::stable_sort(Sections.begin(), Sections.end(), compareByFilePosition);
+
+ if (!Config->Relocatable && Config->EMachine == EM_ARM &&
+ Sec->Type == SHT_ARM_EXIDX) {
+
+ if (auto *Sentinel = dyn_cast<ARMExidxSentinelSection>(Sections.back())) {
+ assert(Sections.size() >= 2 &&
+ "We should create a sentinel section only if there are "
+ "alive regular exidx sections.");
+
+ // The last executable section is required to fill the sentinel.
+ // Remember it here so that we don't have to find it again.
+ Sentinel->Highest = Sections[Sections.size() - 2]->getLinkOrderDep();
+ }
+
+ // The EHABI for the Arm Architecture permits consecutive identical
+ // table entries to be merged. We use a simple implementation that
+ // removes a .ARM.exidx Input Section if it can be merged into the
+ // previous one. This does not require any rewriting of InputSection
+ // contents but misses opportunities for fine grained deduplication
+ // where only a subset of the InputSection contents can be merged.
+ if (Config->MergeArmExidx) {
+ size_t Prev = 0;
+ // The last one is a sentinel entry which should not be removed.
+ for (size_t I = 1; I < Sections.size() - 1; ++I) {
+ if (isDuplicateArmExidxSec(Sections[Prev], Sections[I]))
+ Sections[I] = nullptr;
+ else
+ Prev = I;
+ }
+ }
+ }
+
+ for (int I = 0, N = Sections.size(); I < N; ++I)
+ *ScriptSections[I] = Sections[I];
+
+ // Remove the Sections we marked as duplicate earlier.
+ for (BaseCommand *Base : Sec->SectionCommands)
+ if (auto *ISD = dyn_cast<InputSectionDescription>(Base))
+ llvm::erase_if(ISD->Sections, [](InputSection *IS) { return !IS; });
+ }
+}
+
+// For most RISC ISAs, we need to generate content that depends on the address
+// of InputSections. For example some architectures such as AArch64 use small
+// displacements for jump instructions that is the linker's responsibility for
+// creating range extension thunks for. As the generation of the content may
+// also alter InputSection addresses we must converge to a fixed point.
+template <class ELFT> void Writer<ELFT>::maybeAddThunks() {
+ if (!Target->NeedsThunks && !Config->AndroidPackDynRelocs &&
+ !Config->RelrPackDynRelocs)
+ return;
+
+ ThunkCreator TC;
+ AArch64Err843419Patcher A64P;
+
+ for (;;) {
+ bool Changed = false;
+
+ Script->assignAddresses();
+
+ if (Target->NeedsThunks)
+ Changed |= TC.createThunks(OutputSections);
+
+ if (Config->FixCortexA53Errata843419) {
+ if (Changed)
+ Script->assignAddresses();
+ Changed |= A64P.createFixes();
+ }
+
+ if (In.MipsGot)
+ In.MipsGot->updateAllocSize();
+
+ Changed |= In.RelaDyn->updateAllocSize();
+
+ if (In.RelrDyn)
+ Changed |= In.RelrDyn->updateAllocSize();
+
+ if (!Changed)
+ return;
+ }
+}
+
+static void finalizeSynthetic(SyntheticSection *Sec) {
+ if (Sec && !Sec->empty() && Sec->getParent())
+ Sec->finalizeContents();
+}
+
+// In order to allow users to manipulate linker-synthesized sections,
+// we had to add synthetic sections to the input section list early,
+// even before we make decisions whether they are needed. This allows
+// users to write scripts like this: ".mygot : { .got }".
+//
+// Doing it has an unintended side effects. If it turns out that we
+// don't need a .got (for example) at all because there's no
+// relocation that needs a .got, we don't want to emit .got.
+//
+// To deal with the above problem, this function is called after
+// scanRelocations is called to remove synthetic sections that turn
+// out to be empty.
+static void removeUnusedSyntheticSections() {
+ // All input synthetic sections that can be empty are placed after
+ // all regular ones. We iterate over them all and exit at first
+ // non-synthetic.
+ for (InputSectionBase *S : llvm::reverse(InputSections)) {
+ SyntheticSection *SS = dyn_cast<SyntheticSection>(S);
+ if (!SS)
+ return;
+ OutputSection *OS = SS->getParent();
+ if (!OS || !SS->empty())
+ continue;
+
+ // If we reach here, then SS is an unused synthetic section and we want to
+ // remove it from corresponding input section description of output section.
+ for (BaseCommand *B : OS->SectionCommands)
+ if (auto *ISD = dyn_cast<InputSectionDescription>(B))
+ llvm::erase_if(ISD->Sections,
+ [=](InputSection *IS) { return IS == SS; });
+ }
+}
+
+// Returns true if a symbol can be replaced at load-time by a symbol
+// with the same name defined in other ELF executable or DSO.
+static bool computeIsPreemptible(const Symbol &B) {
+ assert(!B.isLocal());
+
+ // Only symbols that appear in dynsym can be preempted.
+ if (!B.includeInDynsym())
+ return false;
+
+ // Only default visibility symbols can be preempted.
+ if (B.Visibility != STV_DEFAULT)
+ return false;
+
+ // At this point copy relocations have not been created yet, so any
+ // symbol that is not defined locally is preemptible.
+ if (!B.isDefined())
+ return true;
+
+ // If we have a dynamic list it specifies which local symbols are preemptible.
+ if (Config->HasDynamicList)
+ return false;
+
+ if (!Config->Shared)
+ return false;
+
+ // -Bsymbolic means that definitions are not preempted.
+ if (Config->Bsymbolic || (Config->BsymbolicFunctions && B.isFunc()))
+ return false;
+ return true;
+}
+
+// Create output section objects and add them to OutputSections.
+template <class ELFT> void Writer<ELFT>::finalizeSections() {
+ Out::PreinitArray = findSection(".preinit_array");
+ Out::InitArray = findSection(".init_array");
+ Out::FiniArray = findSection(".fini_array");
+
+ // The linker needs to define SECNAME_start, SECNAME_end and SECNAME_stop
+ // symbols for sections, so that the runtime can get the start and end
+ // addresses of each section by section name. Add such symbols.
+ if (!Config->Relocatable) {
+ addStartEndSymbols();
+ for (BaseCommand *Base : Script->SectionCommands)
+ if (auto *Sec = dyn_cast<OutputSection>(Base))
+ addStartStopSymbols(Sec);
+ }
+
+ // Add _DYNAMIC symbol. Unlike GNU gold, our _DYNAMIC symbol has no type.
+ // It should be okay as no one seems to care about the type.
+ // Even the author of gold doesn't remember why gold behaves that way.
+ // https://sourceware.org/ml/binutils/2002-03/msg00360.html
+ if (In.Dynamic->Parent)
+ Symtab->addDefined("_DYNAMIC", STV_HIDDEN, STT_NOTYPE, 0 /*Value*/,
+ /*Size=*/0, STB_WEAK, In.Dynamic,
+ /*File=*/nullptr);
+
+ // Define __rel[a]_iplt_{start,end} symbols if needed.
+ addRelIpltSymbols();
+
+ // RISC-V's gp can address +/- 2 KiB, set it to .sdata + 0x800 if not defined.
+ if (Config->EMachine == EM_RISCV)
+ if (!dyn_cast_or_null<Defined>(Symtab->find("__global_pointer$")))
+ addOptionalRegular("__global_pointer$", findSection(".sdata"), 0x800);
+
+ // This responsible for splitting up .eh_frame section into
+ // pieces. The relocation scan uses those pieces, so this has to be
+ // earlier.
+ finalizeSynthetic(In.EhFrame);
+
+ for (Symbol *S : Symtab->getSymbols()) {
+ if (!S->IsPreemptible)
+ S->IsPreemptible = computeIsPreemptible(*S);
+ if (S->isGnuIFunc() && Config->ZIfuncnoplt)
+ S->ExportDynamic = true;
+ }
+
+ // Scan relocations. This must be done after every symbol is declared so that
+ // we can correctly decide if a dynamic relocation is needed.
+ if (!Config->Relocatable)
+ forEachRelSec(scanRelocations<ELFT>);
+
+ if (In.Plt && !In.Plt->empty())
+ In.Plt->addSymbols();
+ if (In.Iplt && !In.Iplt->empty())
+ In.Iplt->addSymbols();
+
+ // Now that we have defined all possible global symbols including linker-
+ // synthesized ones. Visit all symbols to give the finishing touches.
+ for (Symbol *Sym : Symtab->getSymbols()) {
+ if (!includeInSymtab(*Sym))
+ continue;
+ if (In.SymTab)
+ In.SymTab->addSymbol(Sym);
+
+ if (Sym->includeInDynsym()) {
+ In.DynSymTab->addSymbol(Sym);
+ if (auto *File = dyn_cast_or_null<SharedFile<ELFT>>(Sym->File))
+ if (File->IsNeeded && !Sym->isUndefined())
+ InX<ELFT>::VerNeed->addSymbol(Sym);
+ }
+ }
+
+ // Do not proceed if there was an undefined symbol.
+ if (errorCount())
+ return;
+
+ if (In.MipsGot)
+ In.MipsGot->build<ELFT>();
+
+ removeUnusedSyntheticSections();
+
+ sortSections();
+
+ // Now that we have the final list, create a list of all the
+ // OutputSections for convenience.
+ for (BaseCommand *Base : Script->SectionCommands)
+ if (auto *Sec = dyn_cast<OutputSection>(Base))
+ OutputSections.push_back(Sec);
+
+ // Prefer command line supplied address over other constraints.
+ for (OutputSection *Sec : OutputSections) {
+ auto I = Config->SectionStartMap.find(Sec->Name);
+ if (I != Config->SectionStartMap.end())
+ Sec->AddrExpr = [=] { return I->second; };
+ }
+
+ // This is a bit of a hack. A value of 0 means undef, so we set it
+ // to 1 to make __ehdr_start defined. The section number is not
+ // particularly relevant.
+ Out::ElfHeader->SectionIndex = 1;
+
+ for (size_t I = 0, E = OutputSections.size(); I != E; ++I) {
+ OutputSection *Sec = OutputSections[I];
+ Sec->SectionIndex = I + 1;
+ Sec->ShName = In.ShStrTab->addString(Sec->Name);
+ }
+
+ // Binary and relocatable output does not have PHDRS.
+ // The headers have to be created before finalize as that can influence the
+ // image base and the dynamic section on mips includes the image base.
+ if (!Config->Relocatable && !Config->OFormatBinary) {
+ Phdrs = Script->hasPhdrsCommands() ? Script->createPhdrs() : createPhdrs();
+ addPtArmExid(Phdrs);
+ Out::ProgramHeaders->Size = sizeof(Elf_Phdr) * Phdrs.size();
+
+ // Find the TLS segment. This happens before the section layout loop so that
+ // Android relocation packing can look up TLS symbol addresses.
+ for (PhdrEntry *P : Phdrs)
+ if (P->p_type == PT_TLS)
+ Out::TlsPhdr = P;
+ }
+
+ // Some symbols are defined in term of program headers. Now that we
+ // have the headers, we can find out which sections they point to.
+ setReservedSymbolSections();
+
+ // Dynamic section must be the last one in this list and dynamic
+ // symbol table section (DynSymTab) must be the first one.
+ finalizeSynthetic(In.DynSymTab);
+ finalizeSynthetic(In.Bss);
+ finalizeSynthetic(In.BssRelRo);
+ finalizeSynthetic(In.GnuHashTab);
+ finalizeSynthetic(In.HashTab);
+ finalizeSynthetic(In.SymTabShndx);
+ finalizeSynthetic(In.ShStrTab);
+ finalizeSynthetic(In.StrTab);
+ finalizeSynthetic(In.VerDef);
+ finalizeSynthetic(In.DynStrTab);
+ finalizeSynthetic(In.Got);
+ finalizeSynthetic(In.MipsGot);
+ finalizeSynthetic(In.IgotPlt);
+ finalizeSynthetic(In.GotPlt);
+ finalizeSynthetic(In.RelaDyn);
+ finalizeSynthetic(In.RelrDyn);
+ finalizeSynthetic(In.RelaIplt);
+ finalizeSynthetic(In.RelaPlt);
+ finalizeSynthetic(In.Plt);
+ finalizeSynthetic(In.Iplt);
+ finalizeSynthetic(In.EhFrameHdr);
+ finalizeSynthetic(InX<ELFT>::VerSym);
+ finalizeSynthetic(InX<ELFT>::VerNeed);
+ finalizeSynthetic(In.Dynamic);
+
+ if (!Script->HasSectionsCommand && !Config->Relocatable)
+ fixSectionAlignments();
+
+ // After link order processing .ARM.exidx sections can be deduplicated, which
+ // needs to be resolved before any other address dependent operation.
+ resolveShfLinkOrder();
+
+ // Jump instructions in many ISAs have small displacements, and therefore they
+ // cannot jump to arbitrary addresses in memory. For example, RISC-V JAL
+ // instruction can target only +-1 MiB from PC. It is a linker's
+ // responsibility to create and insert small pieces of code between sections
+ // to extend the ranges if jump targets are out of range. Such code pieces are
+ // called "thunks".
+ //
+ // We add thunks at this stage. We couldn't do this before this point because
+ // this is the earliest point where we know sizes of sections and their
+ // layouts (that are needed to determine if jump targets are in range).
+ maybeAddThunks();
+
+ // maybeAddThunks may have added local symbols to the static symbol table.
+ finalizeSynthetic(In.SymTab);
+ finalizeSynthetic(In.PPC64LongBranchTarget);
+
+ // Fill other section headers. The dynamic table is finalized
+ // at the end because some tags like RELSZ depend on result
+ // of finalizing other sections.
+ for (OutputSection *Sec : OutputSections)
+ Sec->finalize<ELFT>();
+}
+
+// Ensure data sections are not mixed with executable sections when
+// -execute-only is used. -execute-only is a feature to make pages executable
+// but not readable, and the feature is currently supported only on AArch64.
+template <class ELFT> void Writer<ELFT>::checkExecuteOnly() {
+ if (!Config->ExecuteOnly)
+ return;
+
+ for (OutputSection *OS : OutputSections)
+ if (OS->Flags & SHF_EXECINSTR)
+ for (InputSection *IS : getInputSections(OS))
+ if (!(IS->Flags & SHF_EXECINSTR))
+ error("cannot place " + toString(IS) + " into " + toString(OS->Name) +
+ ": -execute-only does not support intermingling data and code");
+}
+
+// The linker is expected to define SECNAME_start and SECNAME_end
+// symbols for a few sections. This function defines them.
+template <class ELFT> void Writer<ELFT>::addStartEndSymbols() {
+ // If a section does not exist, there's ambiguity as to how we
+ // define _start and _end symbols for an init/fini section. Since
+ // the loader assume that the symbols are always defined, we need to
+ // always define them. But what value? The loader iterates over all
+ // pointers between _start and _end to run global ctors/dtors, so if
+ // the section is empty, their symbol values don't actually matter
+ // as long as _start and _end point to the same location.
+ //
+ // That said, we don't want to set the symbols to 0 (which is
+ // probably the simplest value) because that could cause some
+ // program to fail to link due to relocation overflow, if their
+ // program text is above 2 GiB. We use the address of the .text
+ // section instead to prevent that failure.
+ //
+ // In a rare sitaution, .text section may not exist. If that's the
+ // case, use the image base address as a last resort.
+ OutputSection *Default = findSection(".text");
+ if (!Default)
+ Default = Out::ElfHeader;
+
+ auto Define = [=](StringRef Start, StringRef End, OutputSection *OS) {
+ if (OS) {
+ addOptionalRegular(Start, OS, 0);
+ addOptionalRegular(End, OS, -1);
+ } else {
+ addOptionalRegular(Start, Default, 0);
+ addOptionalRegular(End, Default, 0);
+ }
+ };
+
+ Define("__preinit_array_start", "__preinit_array_end", Out::PreinitArray);
+ Define("__init_array_start", "__init_array_end", Out::InitArray);
+ Define("__fini_array_start", "__fini_array_end", Out::FiniArray);
+
+ if (OutputSection *Sec = findSection(".ARM.exidx"))
+ Define("__exidx_start", "__exidx_end", Sec);
+}
+
+// If a section name is valid as a C identifier (which is rare because of
+// the leading '.'), linkers are expected to define __start_<secname> and
+// __stop_<secname> symbols. They are at beginning and end of the section,
+// respectively. This is not requested by the ELF standard, but GNU ld and
+// gold provide the feature, and used by many programs.
+template <class ELFT>
+void Writer<ELFT>::addStartStopSymbols(OutputSection *Sec) {
+ StringRef S = Sec->Name;
+ if (!isValidCIdentifier(S))
+ return;
+ addOptionalRegular(Saver.save("__start_" + S), Sec, 0, STV_PROTECTED);
+ addOptionalRegular(Saver.save("__stop_" + S), Sec, -1, STV_PROTECTED);
+}
+
+static bool needsPtLoad(OutputSection *Sec) {
+ if (!(Sec->Flags & SHF_ALLOC) || Sec->Noload)
+ return false;
+
+ // Don't allocate VA space for TLS NOBITS sections. The PT_TLS PHDR is
+ // responsible for allocating space for them, not the PT_LOAD that
+ // contains the TLS initialization image.
+ if ((Sec->Flags & SHF_TLS) && Sec->Type == SHT_NOBITS)
+ return false;
+ return true;
+}
+
+// Linker scripts are responsible for aligning addresses. Unfortunately, most
+// linker scripts are designed for creating two PT_LOADs only, one RX and one
+// RW. This means that there is no alignment in the RO to RX transition and we
+// cannot create a PT_LOAD there.
+static uint64_t computeFlags(uint64_t Flags) {
+ if (Config->Omagic)
+ return PF_R | PF_W | PF_X;
+ if (Config->ExecuteOnly && (Flags & PF_X))
+ return Flags & ~PF_R;
+ if (Config->SingleRoRx && !(Flags & PF_W))
+ return Flags | PF_X;
+ return Flags;
+}
+
+// Decide which program headers to create and which sections to include in each
+// one.
+template <class ELFT> std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs() {
+ std::vector<PhdrEntry *> Ret;
+ auto AddHdr = [&](unsigned Type, unsigned Flags) -> PhdrEntry * {
+ Ret.push_back(make<PhdrEntry>(Type, Flags));
+ return Ret.back();
+ };
+
+ // The first phdr entry is PT_PHDR which describes the program header itself.
+ AddHdr(PT_PHDR, PF_R)->add(Out::ProgramHeaders);
+
+ // PT_INTERP must be the second entry if exists.
+ if (OutputSection *Cmd = findSection(".interp"))
+ AddHdr(PT_INTERP, Cmd->getPhdrFlags())->add(Cmd);
+
+ // Add the first PT_LOAD segment for regular output sections.
+ uint64_t Flags = computeFlags(PF_R);
+ PhdrEntry *Load = AddHdr(PT_LOAD, Flags);
+
+ // Add the headers. We will remove them if they don't fit.
+ Load->add(Out::ElfHeader);
+ Load->add(Out::ProgramHeaders);
+
+ for (OutputSection *Sec : OutputSections) {
+ if (!(Sec->Flags & SHF_ALLOC))
+ break;
+ if (!needsPtLoad(Sec))
+ continue;
+
+ // Segments are contiguous memory regions that has the same attributes
+ // (e.g. executable or writable). There is one phdr for each segment.
+ // Therefore, we need to create a new phdr when the next section has
+ // different flags or is loaded at a discontiguous address or memory
+ // region using AT or AT> linker script command, respectively. At the same
+ // time, we don't want to create a separate load segment for the headers,
+ // even if the first output section has an AT or AT> attribute.
+ uint64_t NewFlags = computeFlags(Sec->getPhdrFlags());
+ if (((Sec->LMAExpr ||
+ (Sec->LMARegion && (Sec->LMARegion != Load->FirstSec->LMARegion))) &&
+ Load->LastSec != Out::ProgramHeaders) ||
+ Sec->MemRegion != Load->FirstSec->MemRegion || Flags != NewFlags) {
+
+ Load = AddHdr(PT_LOAD, NewFlags);
+ Flags = NewFlags;
+ }
+
+ Load->add(Sec);
+ }
+
+ // Add a TLS segment if any.
+ PhdrEntry *TlsHdr = make<PhdrEntry>(PT_TLS, PF_R);
+ for (OutputSection *Sec : OutputSections)
+ if (Sec->Flags & SHF_TLS)
+ TlsHdr->add(Sec);
+ if (TlsHdr->FirstSec)
+ Ret.push_back(TlsHdr);
+
+ // Add an entry for .dynamic.
+ if (OutputSection *Sec = In.Dynamic->getParent())
+ AddHdr(PT_DYNAMIC, Sec->getPhdrFlags())->add(Sec);
+
+ // PT_GNU_RELRO includes all sections that should be marked as
+ // read-only by dynamic linker after proccessing relocations.
+ // Current dynamic loaders only support one PT_GNU_RELRO PHDR, give
+ // an error message if more than one PT_GNU_RELRO PHDR is required.
+ PhdrEntry *RelRo = make<PhdrEntry>(PT_GNU_RELRO, PF_R);
+ bool InRelroPhdr = false;
+ bool IsRelroFinished = false;
+ for (OutputSection *Sec : OutputSections) {
+ if (!needsPtLoad(Sec))
+ continue;
+ if (isRelroSection(Sec)) {
+ InRelroPhdr = true;
+ if (!IsRelroFinished)
+ RelRo->add(Sec);
+ else
+ error("section: " + Sec->Name + " is not contiguous with other relro" +
+ " sections");
+ } else if (InRelroPhdr) {
+ InRelroPhdr = false;
+ IsRelroFinished = true;
+ }
+ }
+ if (RelRo->FirstSec)
+ Ret.push_back(RelRo);
+
+ // PT_GNU_EH_FRAME is a special section pointing on .eh_frame_hdr.
+ if (!In.EhFrame->empty() && In.EhFrameHdr && In.EhFrame->getParent() &&
+ In.EhFrameHdr->getParent())
+ AddHdr(PT_GNU_EH_FRAME, In.EhFrameHdr->getParent()->getPhdrFlags())
+ ->add(In.EhFrameHdr->getParent());
+
+ // PT_OPENBSD_RANDOMIZE is an OpenBSD-specific feature. That makes
+ // the dynamic linker fill the segment with random data.
+ if (OutputSection *Cmd = findSection(".openbsd.randomdata"))
+ AddHdr(PT_OPENBSD_RANDOMIZE, Cmd->getPhdrFlags())->add(Cmd);
+
+ // PT_GNU_STACK is a special section to tell the loader to make the
+ // pages for the stack non-executable. If you really want an executable
+ // stack, you can pass -z execstack, but that's not recommended for
+ // security reasons.
+ unsigned Perm = PF_R | PF_W;
+ if (Config->ZExecstack)
+ Perm |= PF_X;
+ AddHdr(PT_GNU_STACK, Perm)->p_memsz = Config->ZStackSize;
+
+ // PT_OPENBSD_WXNEEDED is a OpenBSD-specific header to mark the executable
+ // is expected to perform W^X violations, such as calling mprotect(2) or
+ // mmap(2) with PROT_WRITE | PROT_EXEC, which is prohibited by default on
+ // OpenBSD.
+ if (Config->ZWxneeded)
+ AddHdr(PT_OPENBSD_WXNEEDED, PF_X);
+
+ // Create one PT_NOTE per a group of contiguous .note sections.
+ PhdrEntry *Note = nullptr;
+ for (OutputSection *Sec : OutputSections) {
+ if (Sec->Type == SHT_NOTE && (Sec->Flags & SHF_ALLOC)) {
+ if (!Note || Sec->LMAExpr)
+ Note = AddHdr(PT_NOTE, PF_R);
+ Note->add(Sec);
+ } else {
+ Note = nullptr;
+ }
+ }
+ return Ret;
+}
+
+template <class ELFT>
+void Writer<ELFT>::addPtArmExid(std::vector<PhdrEntry *> &Phdrs) {
+ if (Config->EMachine != EM_ARM)
+ return;
+ auto I = llvm::find_if(OutputSections, [](OutputSection *Cmd) {
+ return Cmd->Type == SHT_ARM_EXIDX;
+ });
+ if (I == OutputSections.end())
+ return;
+
+ // PT_ARM_EXIDX is the ARM EHABI equivalent of PT_GNU_EH_FRAME
+ PhdrEntry *ARMExidx = make<PhdrEntry>(PT_ARM_EXIDX, PF_R);
+ ARMExidx->add(*I);
+ Phdrs.push_back(ARMExidx);
+}
+
+// The first section of each PT_LOAD, the first section in PT_GNU_RELRO and the
+// first section after PT_GNU_RELRO have to be page aligned so that the dynamic
+// linker can set the permissions.
+template <class ELFT> void Writer<ELFT>::fixSectionAlignments() {
+ auto PageAlign = [](OutputSection *Cmd) {
+ if (Cmd && !Cmd->AddrExpr)
+ Cmd->AddrExpr = [=] {
+ return alignTo(Script->getDot(), Config->MaxPageSize);
+ };
+ };
+
+ for (const PhdrEntry *P : Phdrs)
+ if (P->p_type == PT_LOAD && P->FirstSec)
+ PageAlign(P->FirstSec);
+
+ for (const PhdrEntry *P : Phdrs) {
+ if (P->p_type != PT_GNU_RELRO)
+ continue;
+
+ if (P->FirstSec)
+ PageAlign(P->FirstSec);
+
+ // Find the first section after PT_GNU_RELRO. If it is in a PT_LOAD we
+ // have to align it to a page.
+ auto End = OutputSections.end();
+ auto I = std::find(OutputSections.begin(), End, P->LastSec);
+ if (I == End || (I + 1) == End)
+ continue;
+
+ OutputSection *Cmd = (*(I + 1));
+ if (needsPtLoad(Cmd))
+ PageAlign(Cmd);
+ }
+}
+
+// Compute an in-file position for a given section. The file offset must be the
+// same with its virtual address modulo the page size, so that the loader can
+// load executables without any address adjustment.
+static uint64_t computeFileOffset(OutputSection *OS, uint64_t Off) {
+ // File offsets are not significant for .bss sections. By convention, we keep
+ // section offsets monotonically increasing rather than setting to zero.
+ if (OS->Type == SHT_NOBITS)
+ return Off;
+
+ // If the section is not in a PT_LOAD, we just have to align it.
+ if (!OS->PtLoad)
+ return alignTo(Off, OS->Alignment);
+
+ // The first section in a PT_LOAD has to have congruent offset and address
+ // module the page size.
+ OutputSection *First = OS->PtLoad->FirstSec;
+ if (OS == First) {
+ uint64_t Alignment = std::max<uint64_t>(OS->Alignment, Config->MaxPageSize);
+ return alignTo(Off, Alignment, OS->Addr);
+ }
+
+ // If two sections share the same PT_LOAD the file offset is calculated
+ // using this formula: Off2 = Off1 + (VA2 - VA1).
+ return First->Offset + OS->Addr - First->Addr;
+}
+
+// Set an in-file position to a given section and returns the end position of
+// the section.
+static uint64_t setFileOffset(OutputSection *OS, uint64_t Off) {
+ Off = computeFileOffset(OS, Off);
+ OS->Offset = Off;
+
+ if (OS->Type == SHT_NOBITS)
+ return Off;
+ return Off + OS->Size;
+}
+
+template <class ELFT> void Writer<ELFT>::assignFileOffsetsBinary() {
+ uint64_t Off = 0;
+ for (OutputSection *Sec : OutputSections)
+ if (Sec->Flags & SHF_ALLOC)
+ Off = setFileOffset(Sec, Off);
+ FileSize = alignTo(Off, Config->Wordsize);
+}
+
+static std::string rangeToString(uint64_t Addr, uint64_t Len) {
+ return "[0x" + utohexstr(Addr) + ", 0x" + utohexstr(Addr + Len - 1) + "]";
+}
+
+// Assign file offsets to output sections.
+template <class ELFT> void Writer<ELFT>::assignFileOffsets() {
+ uint64_t Off = 0;
+ Off = setFileOffset(Out::ElfHeader, Off);
+ Off = setFileOffset(Out::ProgramHeaders, Off);
+
+ PhdrEntry *LastRX = nullptr;
+ for (PhdrEntry *P : Phdrs)
+ if (P->p_type == PT_LOAD && (P->p_flags & PF_X))
+ LastRX = P;
+
+ for (OutputSection *Sec : OutputSections) {
+ Off = setFileOffset(Sec, Off);
+ if (Script->HasSectionsCommand)
+ continue;
+
+ // If this is a last section of the last executable segment and that
+ // segment is the last loadable segment, align the offset of the
+ // following section to avoid loading non-segments parts of the file.
+ if (LastRX && LastRX->LastSec == Sec)
+ Off = alignTo(Off, Target->PageSize);
+ }
+
+ SectionHeaderOff = alignTo(Off, Config->Wordsize);
+ FileSize = SectionHeaderOff + (OutputSections.size() + 1) * sizeof(Elf_Shdr);
+
+ // Our logic assumes that sections have rising VA within the same segment.
+ // With use of linker scripts it is possible to violate this rule and get file
+ // offset overlaps or overflows. That should never happen with a valid script
+ // which does not move the location counter backwards and usually scripts do
+ // not do that. Unfortunately, there are apps in the wild, for example, Linux
+ // kernel, which control segment distribution explicitly and move the counter
+ // backwards, so we have to allow doing that to support linking them. We
+ // perform non-critical checks for overlaps in checkSectionOverlap(), but here
+ // we want to prevent file size overflows because it would crash the linker.
+ for (OutputSection *Sec : OutputSections) {
+ if (Sec->Type == SHT_NOBITS)
+ continue;
+ if ((Sec->Offset > FileSize) || (Sec->Offset + Sec->Size > FileSize))
+ error("unable to place section " + Sec->Name + " at file offset " +
+ rangeToString(Sec->Offset, Sec->Size) +
+ "; check your linker script for overflows");
+ }
+}
+
+// Finalize the program headers. We call this function after we assign
+// file offsets and VAs to all sections.
+template <class ELFT> void Writer<ELFT>::setPhdrs() {
+ for (PhdrEntry *P : Phdrs) {
+ OutputSection *First = P->FirstSec;
+ OutputSection *Last = P->LastSec;
+
+ if (First) {
+ P->p_filesz = Last->Offset - First->Offset;
+ if (Last->Type != SHT_NOBITS)
+ P->p_filesz += Last->Size;
+
+ P->p_memsz = Last->Addr + Last->Size - First->Addr;
+ P->p_offset = First->Offset;
+ P->p_vaddr = First->Addr;
+
+ if (!P->HasLMA)
+ P->p_paddr = First->getLMA();
+ }
+
+ if (P->p_type == PT_LOAD) {
+ P->p_align = std::max<uint64_t>(P->p_align, Config->MaxPageSize);
+ } else if (P->p_type == PT_GNU_RELRO) {
+ P->p_align = 1;
+ // The glibc dynamic loader rounds the size down, so we need to round up
+ // to protect the last page. This is a no-op on FreeBSD which always
+ // rounds up.
+ P->p_memsz = alignTo(P->p_memsz, Target->PageSize);
+ }
+
+ if (P->p_type == PT_TLS && P->p_memsz) {
+ if (!Config->Shared &&
+ (Config->EMachine == EM_ARM || Config->EMachine == EM_AARCH64)) {
+ // On ARM/AArch64, reserve extra space (8 words) between the thread
+ // pointer and an executable's TLS segment by overaligning the segment.
+ // This reservation is needed for backwards compatibility with Android's
+ // TCB, which allocates several slots after the thread pointer (e.g.
+ // TLS_SLOT_STACK_GUARD==5). For simplicity, this overalignment is also
+ // done on other operating systems.
+ P->p_align = std::max<uint64_t>(P->p_align, Config->Wordsize * 8);
+ }
+
+ // The TLS pointer goes after PT_TLS for variant 2 targets. At least glibc
+ // will align it, so round up the size to make sure the offsets are
+ // correct.
+ P->p_memsz = alignTo(P->p_memsz, P->p_align);
+ }
+ }
+}
+
+// A helper struct for checkSectionOverlap.
+namespace {
+struct SectionOffset {
+ OutputSection *Sec;
+ uint64_t Offset;
+};
+} // namespace
+
+// Check whether sections overlap for a specific address range (file offsets,
+// load and virtual adresses).
+static void checkOverlap(StringRef Name, std::vector<SectionOffset> &Sections,
+ bool IsVirtualAddr) {
+ llvm::sort(Sections, [=](const SectionOffset &A, const SectionOffset &B) {
+ return A.Offset < B.Offset;
+ });
+
+ // Finding overlap is easy given a vector is sorted by start position.
+ // If an element starts before the end of the previous element, they overlap.
+ for (size_t I = 1, End = Sections.size(); I < End; ++I) {
+ SectionOffset A = Sections[I - 1];
+ SectionOffset B = Sections[I];
+ if (B.Offset >= A.Offset + A.Sec->Size)
+ continue;
+
+ // If both sections are in OVERLAY we allow the overlapping of virtual
+ // addresses, because it is what OVERLAY was designed for.
+ if (IsVirtualAddr && A.Sec->InOverlay && B.Sec->InOverlay)
+ continue;
+
+ errorOrWarn("section " + A.Sec->Name + " " + Name +
+ " range overlaps with " + B.Sec->Name + "\n>>> " + A.Sec->Name +
+ " range is " + rangeToString(A.Offset, A.Sec->Size) + "\n>>> " +
+ B.Sec->Name + " range is " +
+ rangeToString(B.Offset, B.Sec->Size));
+ }
+}
+
+// Check for overlapping sections and address overflows.
+//
+// In this function we check that none of the output sections have overlapping
+// file offsets. For SHF_ALLOC sections we also check that the load address
+// ranges and the virtual address ranges don't overlap
+template <class ELFT> void Writer<ELFT>::checkSections() {
+ // First, check that section's VAs fit in available address space for target.
+ for (OutputSection *OS : OutputSections)
+ if ((OS->Addr + OS->Size < OS->Addr) ||
+ (!ELFT::Is64Bits && OS->Addr + OS->Size > UINT32_MAX))
+ errorOrWarn("section " + OS->Name + " at 0x" + utohexstr(OS->Addr) +
+ " of size 0x" + utohexstr(OS->Size) +
+ " exceeds available address space");
+
+ // Check for overlapping file offsets. In this case we need to skip any
+ // section marked as SHT_NOBITS. These sections don't actually occupy space in
+ // the file so Sec->Offset + Sec->Size can overlap with others. If --oformat
+ // binary is specified only add SHF_ALLOC sections are added to the output
+ // file so we skip any non-allocated sections in that case.
+ std::vector<SectionOffset> FileOffs;
+ for (OutputSection *Sec : OutputSections)
+ if (Sec->Size > 0 && Sec->Type != SHT_NOBITS &&
+ (!Config->OFormatBinary || (Sec->Flags & SHF_ALLOC)))
+ FileOffs.push_back({Sec, Sec->Offset});
+ checkOverlap("file", FileOffs, false);
+
+ // When linking with -r there is no need to check for overlapping virtual/load
+ // addresses since those addresses will only be assigned when the final
+ // executable/shared object is created.
+ if (Config->Relocatable)
+ return;
+
+ // Checking for overlapping virtual and load addresses only needs to take
+ // into account SHF_ALLOC sections since others will not be loaded.
+ // Furthermore, we also need to skip SHF_TLS sections since these will be
+ // mapped to other addresses at runtime and can therefore have overlapping
+ // ranges in the file.
+ std::vector<SectionOffset> VMAs;
+ for (OutputSection *Sec : OutputSections)
+ if (Sec->Size > 0 && (Sec->Flags & SHF_ALLOC) && !(Sec->Flags & SHF_TLS))
+ VMAs.push_back({Sec, Sec->Addr});
+ checkOverlap("virtual address", VMAs, true);
+
+ // Finally, check that the load addresses don't overlap. This will usually be
+ // the same as the virtual addresses but can be different when using a linker
+ // script with AT().
+ std::vector<SectionOffset> LMAs;
+ for (OutputSection *Sec : OutputSections)
+ if (Sec->Size > 0 && (Sec->Flags & SHF_ALLOC) && !(Sec->Flags & SHF_TLS))
+ LMAs.push_back({Sec, Sec->getLMA()});
+ checkOverlap("load address", LMAs, false);
+}
+
+// The entry point address is chosen in the following ways.
+//
+// 1. the '-e' entry command-line option;
+// 2. the ENTRY(symbol) command in a linker control script;
+// 3. the value of the symbol _start, if present;
+// 4. the number represented by the entry symbol, if it is a number;
+// 5. the address of the first byte of the .text section, if present;
+// 6. the address 0.
+static uint64_t getEntryAddr() {
+ // Case 1, 2 or 3
+ if (Symbol *B = Symtab->find(Config->Entry))
+ return B->getVA();
+
+ // Case 4
+ uint64_t Addr;
+ if (to_integer(Config->Entry, Addr))
+ return Addr;
+
+ // Case 5
+ if (OutputSection *Sec = findSection(".text")) {
+ if (Config->WarnMissingEntry)
+ warn("cannot find entry symbol " + Config->Entry + "; defaulting to 0x" +
+ utohexstr(Sec->Addr));
+ return Sec->Addr;
+ }
+
+ // Case 6
+ if (Config->WarnMissingEntry)
+ warn("cannot find entry symbol " + Config->Entry +
+ "; not setting start address");
+ return 0;
+}
+
+static uint16_t getELFType() {
+ if (Config->Pic)
+ return ET_DYN;
+ if (Config->Relocatable)
+ return ET_REL;
+ return ET_EXEC;
+}
+
+static uint8_t getAbiVersion() {
+ // MIPS non-PIC executable gets ABI version 1.
+ if (Config->EMachine == EM_MIPS && getELFType() == ET_EXEC &&
+ (Config->EFlags & (EF_MIPS_PIC | EF_MIPS_CPIC)) == EF_MIPS_CPIC)
+ return 1;
+ return 0;
+}
+
+template <class ELFT> void Writer<ELFT>::writeHeader() {
+ uint8_t *Buf = Buffer->getBufferStart();
+
+ // For executable segments, the trap instructions are written before writing
+ // the header. Setting Elf header bytes to zero ensures that any unused bytes
+ // in header are zero-cleared, instead of having trap instructions.
+ memset(Buf, 0, sizeof(Elf_Ehdr));
+ memcpy(Buf, "\177ELF", 4);
+
+ // Write the ELF header.
+ auto *EHdr = reinterpret_cast<Elf_Ehdr *>(Buf);
+ EHdr->e_ident[EI_CLASS] = Config->Is64 ? ELFCLASS64 : ELFCLASS32;
+ EHdr->e_ident[EI_DATA] = Config->IsLE ? ELFDATA2LSB : ELFDATA2MSB;
+ EHdr->e_ident[EI_VERSION] = EV_CURRENT;
+ EHdr->e_ident[EI_OSABI] = Config->OSABI;
+ EHdr->e_ident[EI_ABIVERSION] = getAbiVersion();
+ EHdr->e_type = getELFType();
+ EHdr->e_machine = Config->EMachine;
+ EHdr->e_version = EV_CURRENT;
+ EHdr->e_entry = getEntryAddr();
+ EHdr->e_shoff = SectionHeaderOff;
+ EHdr->e_flags = Config->EFlags;
+ EHdr->e_ehsize = sizeof(Elf_Ehdr);
+ EHdr->e_phnum = Phdrs.size();
+ EHdr->e_shentsize = sizeof(Elf_Shdr);
+
+ if (!Config->Relocatable) {
+ EHdr->e_phoff = sizeof(Elf_Ehdr);
+ EHdr->e_phentsize = sizeof(Elf_Phdr);
+ }
+
+ // Write the program header table.
+ auto *HBuf = reinterpret_cast<Elf_Phdr *>(Buf + EHdr->e_phoff);
+ for (PhdrEntry *P : Phdrs) {
+ HBuf->p_type = P->p_type;
+ HBuf->p_flags = P->p_flags;
+ HBuf->p_offset = P->p_offset;
+ HBuf->p_vaddr = P->p_vaddr;
+ HBuf->p_paddr = P->p_paddr;
+ HBuf->p_filesz = P->p_filesz;
+ HBuf->p_memsz = P->p_memsz;
+ HBuf->p_align = P->p_align;
+ ++HBuf;
+ }
+
+ // Write the section header table.
+ //
+ // The ELF header can only store numbers up to SHN_LORESERVE in the e_shnum
+ // and e_shstrndx fields. When the value of one of these fields exceeds
+ // SHN_LORESERVE ELF requires us to put sentinel values in the ELF header and
+ // use fields in the section header at index 0 to store
+ // the value. The sentinel values and fields are:
+ // e_shnum = 0, SHdrs[0].sh_size = number of sections.
+ // e_shstrndx = SHN_XINDEX, SHdrs[0].sh_link = .shstrtab section index.
+ auto *SHdrs = reinterpret_cast<Elf_Shdr *>(Buf + EHdr->e_shoff);
+ size_t Num = OutputSections.size() + 1;
+ if (Num >= SHN_LORESERVE)
+ SHdrs->sh_size = Num;
+ else
+ EHdr->e_shnum = Num;
+
+ uint32_t StrTabIndex = In.ShStrTab->getParent()->SectionIndex;
+ if (StrTabIndex >= SHN_LORESERVE) {
+ SHdrs->sh_link = StrTabIndex;
+ EHdr->e_shstrndx = SHN_XINDEX;
+ } else {
+ EHdr->e_shstrndx = StrTabIndex;
+ }
+
+ for (OutputSection *Sec : OutputSections)
+ Sec->writeHeaderTo<ELFT>(++SHdrs);
+}
+
+// Open a result file.
+template <class ELFT> void Writer<ELFT>::openFile() {
+ uint64_t MaxSize = Config->Is64 ? INT64_MAX : UINT32_MAX;
+ if (MaxSize < FileSize) {
+ error("output file too large: " + Twine(FileSize) + " bytes");
+ return;
+ }
+
+ unlinkAsync(Config->OutputFile);
+ unsigned Flags = 0;
+ if (!Config->Relocatable)
+ Flags = FileOutputBuffer::F_executable;
+ Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
+ FileOutputBuffer::create(Config->OutputFile, FileSize, Flags);
+
+ if (!BufferOrErr)
+ error("failed to open " + Config->OutputFile + ": " +
+ llvm::toString(BufferOrErr.takeError()));
+ else
+ Buffer = std::move(*BufferOrErr);
+}
+
+template <class ELFT> void Writer<ELFT>::writeSectionsBinary() {
+ uint8_t *Buf = Buffer->getBufferStart();
+ for (OutputSection *Sec : OutputSections)
+ if (Sec->Flags & SHF_ALLOC)
+ Sec->writeTo<ELFT>(Buf + Sec->Offset);
+}
+
+static void fillTrap(uint8_t *I, uint8_t *End) {
+ for (; I + 4 <= End; I += 4)
+ memcpy(I, &Target->TrapInstr, 4);
+}
+
+// Fill the last page of executable segments with trap instructions
+// instead of leaving them as zero. Even though it is not required by any
+// standard, it is in general a good thing to do for security reasons.
+//
+// We'll leave other pages in segments as-is because the rest will be
+// overwritten by output sections.
+template <class ELFT> void Writer<ELFT>::writeTrapInstr() {
+ if (Script->HasSectionsCommand)
+ return;
+
+ // Fill the last page.
+ uint8_t *Buf = Buffer->getBufferStart();
+ for (PhdrEntry *P : Phdrs)
+ if (P->p_type == PT_LOAD && (P->p_flags & PF_X))
+ fillTrap(Buf + alignDown(P->p_offset + P->p_filesz, Target->PageSize),
+ Buf + alignTo(P->p_offset + P->p_filesz, Target->PageSize));
+
+ // Round up the file size of the last segment to the page boundary iff it is
+ // an executable segment to ensure that other tools don't accidentally
+ // trim the instruction padding (e.g. when stripping the file).
+ PhdrEntry *Last = nullptr;
+ for (PhdrEntry *P : Phdrs)
+ if (P->p_type == PT_LOAD)
+ Last = P;
+
+ if (Last && (Last->p_flags & PF_X))
+ Last->p_memsz = Last->p_filesz = alignTo(Last->p_filesz, Target->PageSize);
+}
+
+// Write section contents to a mmap'ed file.
+template <class ELFT> void Writer<ELFT>::writeSections() {
+ uint8_t *Buf = Buffer->getBufferStart();
+
+ OutputSection *EhFrameHdr = nullptr;
+ if (In.EhFrameHdr && !In.EhFrameHdr->empty())
+ EhFrameHdr = In.EhFrameHdr->getParent();
+
+ // In -r or -emit-relocs mode, write the relocation sections first as in
+ // ELf_Rel targets we might find out that we need to modify the relocated
+ // section while doing it.
+ for (OutputSection *Sec : OutputSections)
+ if (Sec->Type == SHT_REL || Sec->Type == SHT_RELA)
+ Sec->writeTo<ELFT>(Buf + Sec->Offset);
+
+ for (OutputSection *Sec : OutputSections)
+ if (Sec != EhFrameHdr && Sec->Type != SHT_REL && Sec->Type != SHT_RELA)
+ Sec->writeTo<ELFT>(Buf + Sec->Offset);
+
+ // The .eh_frame_hdr depends on .eh_frame section contents, therefore
+ // it should be written after .eh_frame is written.
+ if (EhFrameHdr)
+ EhFrameHdr->writeTo<ELFT>(Buf + EhFrameHdr->Offset);
+}
+
+template <class ELFT> void Writer<ELFT>::writeBuildId() {
+ if (!In.BuildId || !In.BuildId->getParent())
+ return;
+
+ // Compute a hash of all sections of the output file.
+ uint8_t *Start = Buffer->getBufferStart();
+ uint8_t *End = Start + FileSize;
+ In.BuildId->writeBuildId({Start, End});
+}
+
+template void elf::writeResult<ELF32LE>();
+template void elf::writeResult<ELF32BE>();
+template void elf::writeResult<ELF64LE>();
+template void elf::writeResult<ELF64BE>();
diff --git a/contrib/llvm/tools/lld/ELF/Writer.h b/contrib/llvm/tools/lld/ELF/Writer.h
new file mode 100644
index 000000000000..7806f824c58f
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Writer.h
@@ -0,0 +1,64 @@
+//===- Writer.h -------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_WRITER_H
+#define LLD_ELF_WRITER_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include <cstdint>
+#include <memory>
+
+namespace lld {
+namespace elf {
+class InputFile;
+class OutputSection;
+class InputSectionBase;
+template <class ELFT> class ObjFile;
+class SymbolTable;
+template <class ELFT> void writeResult();
+
+// This describes a program header entry.
+// Each contains type, access flags and range of output sections that will be
+// placed in it.
+struct PhdrEntry {
+ PhdrEntry(unsigned Type, unsigned Flags) : p_type(Type), p_flags(Flags) {}
+ void add(OutputSection *Sec);
+
+ uint64_t p_paddr = 0;
+ uint64_t p_vaddr = 0;
+ uint64_t p_memsz = 0;
+ uint64_t p_filesz = 0;
+ uint64_t p_offset = 0;
+ uint32_t p_align = 0;
+ uint32_t p_type = 0;
+ uint32_t p_flags = 0;
+
+ OutputSection *FirstSec = nullptr;
+ OutputSection *LastSec = nullptr;
+ bool HasLMA = false;
+
+ uint64_t LMAOffset = 0;
+};
+
+void addReservedSymbols();
+llvm::StringRef getOutputSectionName(const InputSectionBase *S);
+
+template <class ELFT> uint32_t calcMipsEFlags();
+
+uint8_t getMipsFpAbiFlag(uint8_t OldFlag, uint8_t NewFlag,
+ llvm::StringRef FileName);
+
+bool isMipsN32Abi(const InputFile *F);
+bool isMicroMips();
+bool isMipsR6();
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/FREEBSD-Xlist b/contrib/llvm/tools/lld/FREEBSD-Xlist
new file mode 100644
index 000000000000..4330bf30bcc4
--- /dev/null
+++ b/contrib/llvm/tools/lld/FREEBSD-Xlist
@@ -0,0 +1,7 @@
+# $FreeBSD$
+MinGW/
+cmake/
+test/
+unittests/
+utils/
+wasm/
diff --git a/contrib/llvm/tools/lld/LICENSE.TXT b/contrib/llvm/tools/lld/LICENSE.TXT
new file mode 100644
index 000000000000..09b8b616c227
--- /dev/null
+++ b/contrib/llvm/tools/lld/LICENSE.TXT
@@ -0,0 +1,62 @@
+==============================================================================
+lld License
+==============================================================================
+University of Illinois/NCSA
+Open Source License
+
+Copyright (c) 2011-2019 by the contributors listed in CREDITS.TXT
+All rights reserved.
+
+Developed by:
+
+ LLVM Team
+
+ University of Illinois at Urbana-Champaign
+
+ http://llvm.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal with
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimers.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimers in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the names of the LLVM Team, University of Illinois at
+ Urbana-Champaign, nor the names of its contributors may be used to
+ endorse or promote products derived from this Software without specific
+ prior written permission.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
+SOFTWARE.
+
+==============================================================================
+The lld software contains code written by third parties. Such software will
+have its own individual LICENSE.TXT file in the directory in which it appears.
+This file will describe the copyrights, license, and restrictions which apply
+to that code.
+
+The disclaimer of warranty in the University of Illinois Open Source License
+applies to all code in the lld Distribution, and nothing in any of the
+other licenses gives permission to use the names of the LLVM Team or the
+University of Illinois to endorse or promote products derived from this
+Software.
+
+The following pieces of software have additional or alternate copyrights,
+licenses, and/or restrictions:
+
+Program Directory
+------- ---------
+<none yet>
diff --git a/contrib/llvm/tools/lld/README.md b/contrib/llvm/tools/lld/README.md
new file mode 100644
index 000000000000..3b8cd7a14948
--- /dev/null
+++ b/contrib/llvm/tools/lld/README.md
@@ -0,0 +1,19 @@
+LLVM Linker (lld)
+=================
+
+This directory and its subdirectories contain source code for the LLVM Linker, a
+modular cross platform linker which is built as part of the LLVM compiler
+infrastructure project.
+
+lld is open source software. You may freely distribute it under the terms of
+the license agreement found in LICENSE.txt.
+
+Benchmarking
+============
+
+In order to make sure various developers can evaluate patches over the
+same tests, we create a collection of self contained programs.
+
+It is hosted at https://s3-us-west-2.amazonaws.com/linker-tests/lld-speed-test.tar.xz
+
+The current sha256 is 10eec685463d5a8bbf08d77f4ca96282161d396c65bd97dc99dbde644a31610f.
diff --git a/contrib/llvm/tools/lld/docs/AtomLLD.rst b/contrib/llvm/tools/lld/docs/AtomLLD.rst
new file mode 100644
index 000000000000..614e568d1997
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/AtomLLD.rst
@@ -0,0 +1,62 @@
+ATOM-based lld
+==============
+
+Note: this document discuss Mach-O port of LLD. For ELF and COFF,
+see :doc:`index`.
+
+ATOM-based lld is a new set of modular code for creating linker tools.
+Currently it supports Mach-O.
+
+* End-User Features:
+
+ * Compatible with existing linker options
+ * Reads standard Object Files
+ * Writes standard Executable Files
+ * Remove clang's reliance on "the system linker"
+ * Uses the LLVM `"UIUC" BSD-Style license`__.
+
+* Applications:
+
+ * Modular design
+ * Support cross linking
+ * Easy to add new CPU support
+ * Can be built as static tool or library
+
+* Design and Implementation:
+
+ * Extensive unit tests
+ * Internal linker model can be dumped/read to textual format
+ * Additional linking features can be plugged in as "passes"
+ * OS specific and CPU specific code factored out
+
+Why a new linker?
+-----------------
+
+The fact that clang relies on whatever linker tool you happen to have installed
+means that clang has been very conservative adopting features which require a
+recent linker.
+
+In the same way that the MC layer of LLVM has removed clang's reliance on the
+system assembler tool, the lld project will remove clang's reliance on the
+system linker tool.
+
+
+Contents
+--------
+
+.. toctree::
+ :maxdepth: 2
+
+ design
+ getting_started
+ development
+ open_projects
+ sphinx_intro
+
+Indices and tables
+------------------
+
+* :ref:`genindex`
+* :ref:`search`
+
+__ http://llvm.org/docs/DeveloperPolicy.html#license
diff --git a/contrib/llvm/tools/lld/docs/CMakeLists.txt b/contrib/llvm/tools/lld/docs/CMakeLists.txt
new file mode 100644
index 000000000000..112ce35e8cf4
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/CMakeLists.txt
@@ -0,0 +1,8 @@
+if (LLVM_ENABLE_SPHINX)
+ include(AddSphinxTarget)
+ if (SPHINX_FOUND)
+ if (${SPHINX_OUTPUT_HTML})
+ add_sphinx_target(html lld)
+ endif()
+ endif()
+endif()
diff --git a/contrib/llvm/tools/lld/docs/Driver.rst b/contrib/llvm/tools/lld/docs/Driver.rst
new file mode 100644
index 000000000000..4ee6ce0c985f
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/Driver.rst
@@ -0,0 +1,82 @@
+======
+Driver
+======
+
+Note: this document discuss Mach-O port of LLD. For ELF and COFF,
+see :doc:`index`.
+
+.. contents::
+ :local:
+
+Introduction
+============
+
+This document describes the lld driver. The purpose of this document is to
+describe both the motivation and design goals for the driver, as well as details
+of the internal implementation.
+
+Overview
+========
+
+The lld driver is designed to support a number of different command line
+interfaces. The main interfaces we plan to support are binutils' ld, Apple's
+ld, and Microsoft's link.exe.
+
+Flavors
+-------
+
+Each of these different interfaces is referred to as a flavor. There is also an
+extra flavor "core" which is used to exercise the core functionality of the
+linker it the test suite.
+
+* gnu
+* darwin
+* link
+* core
+
+Selecting a Flavor
+^^^^^^^^^^^^^^^^^^
+
+There are two different ways to tell lld which flavor to be. They are checked in
+order, so the second overrides the first. The first is to symlink :program:`lld`
+as :program:`lld-{flavor}` or just :program:`{flavor}`. You can also specify
+it as the first command line argument using ``-flavor``::
+
+ $ lld -flavor gnu
+
+There is a shortcut for ``-flavor core`` as ``-core``.
+
+
+Adding an Option to an existing Flavor
+======================================
+
+#. Add the option to the desired :file:`lib/Driver/{flavor}Options.td`.
+
+#. Add to :cpp:class:`lld::FlavorLinkingContext` a getter and setter method
+ for the option.
+
+#. Modify :cpp:func:`lld::FlavorDriver::parse` in :file:
+ `lib/Driver/{Flavor}Driver.cpp` to call the targetInfo setter
+ for corresponding to the option.
+
+#. Modify {Flavor}Reader and {Flavor}Writer to use the new targtInfo option.
+
+
+Adding a Flavor
+===============
+
+#. Add an entry for the flavor in :file:`include/lld/Common/Driver.h` to
+ :cpp:class:`lld::UniversalDriver::Flavor`.
+
+#. Add an entry in :file:`lib/Driver/UniversalDriver.cpp` to
+ :cpp:func:`lld::Driver::strToFlavor` and
+ :cpp:func:`lld::UniversalDriver::link`.
+ This allows the flavor to be selected via symlink and `-flavor`.
+
+#. Add a tablegen file called :file:`lib/Driver/{flavor}Options.td` that
+ describes the options. If the options are a superset of another driver, that
+ driver's td file can simply be included. The :file:`{flavor}Options.td` file
+ must also be added to :file:`lib/Driver/CMakeLists.txt`.
+
+#. Add a ``{flavor}Driver`` as a subclass of :cpp:class:`lld::Driver`
+ in :file:`lib/Driver/{flavor}Driver.cpp`.
diff --git a/contrib/llvm/tools/lld/docs/NewLLD.rst b/contrib/llvm/tools/lld/docs/NewLLD.rst
new file mode 100644
index 000000000000..79bdf90c6ccd
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/NewLLD.rst
@@ -0,0 +1,309 @@
+The ELF, COFF and Wasm Linkers
+==============================
+
+The ELF Linker as a Library
+---------------------------
+
+You can embed LLD to your program by linking against it and calling the linker's
+entry point function lld::elf::link.
+
+The current policy is that it is your reponsibility to give trustworthy object
+files. The function is guaranteed to return as long as you do not pass corrupted
+or malicious object files. A corrupted file could cause a fatal error or SEGV.
+That being said, you don't need to worry too much about it if you create object
+files in the usual way and give them to the linker. It is naturally expected to
+work, or otherwise it's a linker's bug.
+
+Design
+======
+
+We will describe the design of the linkers in the rest of the document.
+
+Key Concepts
+------------
+
+Linkers are fairly large pieces of software.
+There are many design choices you have to make to create a complete linker.
+
+This is a list of design choices we've made for ELF and COFF LLD.
+We believe that these high-level design choices achieved a right balance
+between speed, simplicity and extensibility.
+
+* Implement as native linkers
+
+ We implemented the linkers as native linkers for each file format.
+
+ The linkers share the same design but share very little code.
+ Sharing code makes sense if the benefit is worth its cost.
+ In our case, the object formats are different enough that we thought the layer
+ to abstract the differences wouldn't be worth its complexity and run-time
+ cost. Elimination of the abstract layer has greatly simplified the
+ implementation.
+
+* Speed by design
+
+ One of the most important things in archiving high performance is to
+ do less rather than do it efficiently.
+ Therefore, the high-level design matters more than local optimizations.
+ Since we are trying to create a high-performance linker,
+ it is very important to keep the design as efficient as possible.
+
+ Broadly speaking, we do not do anything until we have to do it.
+ For example, we do not read section contents or relocations
+ until we need them to continue linking.
+ When we need to do some costly operation (such as looking up
+ a hash table for each symbol), we do it only once.
+ We obtain a handle (which is typically just a pointer to actual data)
+ on the first operation and use it throughout the process.
+
+* Efficient archive file handling
+
+ LLD's handling of archive files (the files with ".a" file extension) is
+ different from the traditional Unix linkers and similar to Windows linkers.
+ We'll describe how the traditional Unix linker handles archive files, what the
+ problem is, and how LLD approached the problem.
+
+ The traditional Unix linker maintains a set of undefined symbols during
+ linking. The linker visits each file in the order as they appeared in the
+ command line until the set becomes empty. What the linker would do depends on
+ file type.
+
+ - If the linker visits an object file, the linker links object files to the
+ result, and undefined symbols in the object file are added to the set.
+
+ - If the linker visits an archive file, it checks for the archive file's
+ symbol table and extracts all object files that have definitions for any
+ symbols in the set.
+
+ This algorithm sometimes leads to a counter-intuitive behavior. If you give
+ archive files before object files, nothing will happen because when the linker
+ visits archives, there is no undefined symbols in the set. As a result, no
+ files are extracted from the first archive file, and the link is done at that
+ point because the set is empty after it visits one file.
+
+ You can fix the problem by reordering the files,
+ but that cannot fix the issue of mutually-dependent archive files.
+
+ Linking mutually-dependent archive files is tricky. You may specify the same
+ archive file multiple times to let the linker visit it more than once. Or,
+ you may use the special command line options, `--start-group` and
+ `--end-group`, to let the linker loop over the files between the options until
+ no new symbols are added to the set.
+
+ Visiting the same archive files multiple times makes the linker slower.
+
+ Here is how LLD approaches the problem. Instead of memorizing only undefined
+ symbols, we program LLD so that it memorizes all symbols. When it sees an
+ undefined symbol that can be resolved by extracting an object file from an
+ archive file it previously visited, it immediately extracts the file and links
+ it. It is doable because LLD does not forget symbols it has seen in archive
+ files.
+
+ We believe that LLD's way is efficient and easy to justify.
+
+ The semantics of LLD's archive handling are different from the traditional
+ Unix's. You can observe it if you carefully craft archive files to exploit
+ it. However, in reality, we don't know any program that cannot link with our
+ algorithm so far, so it's not going to cause trouble.
+
+Numbers You Want to Know
+------------------------
+
+To give you intuition about what kinds of data the linker is mainly working on,
+I'll give you the list of objects and their numbers LLD has to read and process
+in order to link a very large executable. In order to link Chrome with debug
+info, which is roughly 2 GB in output size, LLD reads
+
+- 17,000 files,
+- 1,800,000 sections,
+- 6,300,000 symbols, and
+- 13,000,000 relocations.
+
+LLD produces the 2 GB executable in 15 seconds.
+
+These numbers vary depending on your program, but in general,
+you have a lot of relocations and symbols for each file.
+If your program is written in C++, symbol names are likely to be
+pretty long because of name mangling.
+
+It is important to not waste time on relocations and symbols.
+
+In the above case, the total amount of symbol strings is 450 MB,
+and inserting all of them to a hash table takes 1.5 seconds.
+Therefore, if you causally add a hash table lookup for each symbol,
+it would slow down the linker by 10%. So, don't do that.
+
+On the other hand, you don't have to pursue efficiency
+when handling files.
+
+Important Data Structures
+-------------------------
+
+We will describe the key data structures in LLD in this section. The linker can
+be understood as the interactions between them. Once you understand their
+functions, the code of the linker should look obvious to you.
+
+* Symbol
+
+ This class represents a symbol.
+ They are created for symbols in object files or archive files.
+ The linker creates linker-defined symbols as well.
+
+ There are basically three types of Symbols: Defined, Undefined, or Lazy.
+
+ - Defined symbols are for all symbols that are considered as "resolved",
+ including real defined symbols, COMDAT symbols, common symbols,
+ absolute symbols, linker-created symbols, etc.
+ - Undefined symbols represent undefined symbols, which need to be replaced by
+ Defined symbols by the resolver until the link is complete.
+ - Lazy symbols represent symbols we found in archive file headers
+ which can turn into Defined if we read archive members.
+
+ There's only one Symbol instance for each unique symbol name. This uniqueness
+ is guaranteed by the symbol table. As the resolver reads symbols from input
+ files, it replaces an existing Symbol with the "best" Symbol for its symbol
+ name using the placement new.
+
+ The above mechanism allows you to use pointers to Symbols as a very cheap way
+ to access name resolution results. Assume for example that you have a pointer
+ to an undefined symbol before name resolution. If the symbol is resolved to a
+ defined symbol by the resolver, the pointer will "automatically" point to the
+ defined symbol, because the undefined symbol the pointer pointed to will have
+ been replaced by the defined symbol in-place.
+
+* SymbolTable
+
+ SymbolTable is basically a hash table from strings to Symbols
+ with logic to resolve symbol conflicts. It resolves conflicts by symbol type.
+
+ - If we add Defined and Undefined symbols, the symbol table will keep the
+ former.
+ - If we add Defined and Lazy symbols, it will keep the former.
+ - If we add Lazy and Undefined, it will keep the former,
+ but it will also trigger the Lazy symbol to load the archive member
+ to actually resolve the symbol.
+
+* Chunk (COFF specific)
+
+ Chunk represents a chunk of data that will occupy space in an output.
+ Each regular section becomes a chunk.
+ Chunks created for common or BSS symbols are not backed by sections.
+ The linker may create chunks to append additional data to an output as well.
+
+ Chunks know about their size, how to copy their data to mmap'ed outputs,
+ and how to apply relocations to them.
+ Specifically, section-based chunks know how to read relocation tables
+ and how to apply them.
+
+* InputSection (ELF specific)
+
+ Since we have less synthesized data for ELF, we don't abstract slices of
+ input files as Chunks for ELF. Instead, we directly use the input section
+ as an internal data type.
+
+ InputSection knows about their size and how to copy themselves to
+ mmap'ed outputs, just like COFF Chunks.
+
+* OutputSection
+
+ OutputSection is a container of InputSections (ELF) or Chunks (COFF).
+ An InputSection or Chunk belongs to at most one OutputSection.
+
+There are mainly three actors in this linker.
+
+* InputFile
+
+ InputFile is a superclass of file readers.
+ We have a different subclass for each input file type,
+ such as regular object file, archive file, etc.
+ They are responsible for creating and owning Symbols and InputSections/Chunks.
+
+* Writer
+
+ The writer is responsible for writing file headers and InputSections/Chunks to
+ a file. It creates OutputSections, put all InputSections/Chunks into them,
+ assign unique, non-overlapping addresses and file offsets to them, and then
+ write them down to a file.
+
+* Driver
+
+ The linking process is driven by the driver. The driver:
+
+ - processes command line options,
+ - creates a symbol table,
+ - creates an InputFile for each input file and puts all symbols within into
+ the symbol table,
+ - checks if there's no remaining undefined symbols,
+ - creates a writer,
+ - and passes the symbol table to the writer to write the result to a file.
+
+Link-Time Optimization
+----------------------
+
+LTO is implemented by handling LLVM bitcode files as object files.
+The linker resolves symbols in bitcode files normally. If all symbols
+are successfully resolved, it then runs LLVM passes
+with all bitcode files to convert them to one big regular ELF/COFF file.
+Finally, the linker replaces bitcode symbols with ELF/COFF symbols,
+so that they are linked as if they were in the native format from the beginning.
+
+The details are described in this document.
+http://llvm.org/docs/LinkTimeOptimization.html
+
+Glossary
+--------
+
+* RVA (COFF)
+
+ Short for Relative Virtual Address.
+
+ Windows executables or DLLs are not position-independent; they are
+ linked against a fixed address called an image base. RVAs are
+ offsets from an image base.
+
+ Default image bases are 0x140000000 for executables and 0x18000000
+ for DLLs. For example, when we are creating an executable, we assume
+ that the executable will be loaded at address 0x140000000 by the
+ loader, so we apply relocations accordingly. Result texts and data
+ will contain raw absolute addresses.
+
+* VA
+
+ Short for Virtual Address. For COFF, it is equivalent to RVA + image base.
+
+* Base relocations (COFF)
+
+ Relocation information for the loader. If the loader decides to map
+ an executable or a DLL to a different address than their image
+ bases, it fixes up binaries using information contained in the base
+ relocation table. A base relocation table consists of a list of
+ locations containing addresses. The loader adds a difference between
+ RVA and actual load address to all locations listed there.
+
+ Note that this run-time relocation mechanism is much simpler than ELF.
+ There's no PLT or GOT. Images are relocated as a whole just
+ by shifting entire images in memory by some offsets. Although doing
+ this breaks text sharing, I think this mechanism is not actually bad
+ on today's computers.
+
+* ICF
+
+ Short for Identical COMDAT Folding (COFF) or Identical Code Folding (ELF).
+
+ ICF is an optimization to reduce output size by merging read-only sections
+ by not only their names but by their contents. If two read-only sections
+ happen to have the same metadata, actual contents and relocations,
+ they are merged by ICF. It is known as an effective technique,
+ and it usually reduces C++ program's size by a few percent or more.
+
+ Note that this is not an entirely sound optimization. C/C++ require
+ different functions have different addresses. If a program depends on
+ that property, it would fail at runtime.
+
+ On Windows, that's not really an issue because MSVC link.exe enabled
+ the optimization by default. As long as your program works
+ with the linker's default settings, your program should be safe with ICF.
+
+ On Unix, your program is generally not guaranteed to be safe with ICF,
+ although large programs happen to work correctly.
+ LLD works fine with ICF for example.
diff --git a/contrib/llvm/tools/lld/docs/README.txt b/contrib/llvm/tools/lld/docs/README.txt
new file mode 100644
index 000000000000..2ed016639de7
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/README.txt
@@ -0,0 +1,9 @@
+lld Documentation
+=================
+
+The lld documentation is written using the Sphinx documentation generator. It is
+currently tested with Sphinx 1.1.3.
+
+We currently use the 'nature' theme and a Beaker inspired structure.
+
+See sphinx_intro.rst for more details.
diff --git a/contrib/llvm/tools/lld/docs/Readers.rst b/contrib/llvm/tools/lld/docs/Readers.rst
new file mode 100644
index 000000000000..eae1717f6e5b
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/Readers.rst
@@ -0,0 +1,174 @@
+.. _Readers:
+
+Developing lld Readers
+======================
+
+Note: this document discuss Mach-O port of LLD. For ELF and COFF,
+see :doc:`index`.
+
+Introduction
+------------
+
+The purpose of a "Reader" is to take an object file in a particular format
+and create an `lld::File`:cpp:class: (which is a graph of Atoms)
+representing the object file. A Reader inherits from
+`lld::Reader`:cpp:class: which lives in
+:file:`include/lld/Core/Reader.h` and
+:file:`lib/Core/Reader.cpp`.
+
+The Reader infrastructure for an object format ``Foo`` requires the
+following pieces in order to fit into lld:
+
+:file:`include/lld/ReaderWriter/ReaderFoo.h`
+
+ .. cpp:class:: ReaderOptionsFoo : public ReaderOptions
+
+ This Options class is the only way to configure how the Reader will
+ parse any file into an `lld::Reader`:cpp:class: object. This class
+ should be declared in the `lld`:cpp:class: namespace.
+
+ .. cpp:function:: Reader *createReaderFoo(ReaderOptionsFoo &reader)
+
+ This factory function configures and create the Reader. This function
+ should be declared in the `lld`:cpp:class: namespace.
+
+:file:`lib/ReaderWriter/Foo/ReaderFoo.cpp`
+
+ .. cpp:class:: ReaderFoo : public Reader
+
+ This is the concrete Reader class which can be called to parse
+ object files. It should be declared in an anonymous namespace or
+ if there is shared code with the `lld::WriterFoo`:cpp:class: you
+ can make a nested namespace (e.g. `lld::foo`:cpp:class:).
+
+You may have noticed that :cpp:class:`ReaderFoo` is not declared in the
+``.h`` file. An important design aspect of lld is that all Readers are
+created *only* through an object-format-specific
+:cpp:func:`createReaderFoo` factory function. The creation of the Reader is
+parametrized through a :cpp:class:`ReaderOptionsFoo` class. This options
+class is the one-and-only way to control how the Reader operates when
+parsing an input file into an Atom graph. For instance, you may want the
+Reader to only accept certain architectures. The options class can be
+instantiated from command line options or be programmatically configured.
+
+Where to start
+--------------
+
+The lld project already has a skeleton of source code for Readers for
+``ELF``, ``PECOFF``, ``MachO``, and lld's native ``YAML`` graph format.
+If your file format is a variant of one of those, you should modify the
+existing Reader to support your variant. This is done by customizing the Options
+class for the Reader and making appropriate changes to the ``.cpp`` file to
+interpret those options and act accordingly.
+
+If your object file format is not a variant of any existing Reader, you'll need
+to create a new Reader subclass with the organization described above.
+
+Readers are factories
+---------------------
+
+The linker will usually only instantiate your Reader once. That one Reader will
+have its loadFile() method called many times with different input files.
+To support multithreaded linking, the Reader may be parsing multiple input
+files in parallel. Therefore, there should be no parsing state in you Reader
+object. Any parsing state should be in ivars of your File subclass or in
+some temporary object.
+
+The key function to implement in a reader is::
+
+ virtual error_code loadFile(LinkerInput &input,
+ std::vector<std::unique_ptr<File>> &result);
+
+It takes a memory buffer (which contains the contents of the object file
+being read) and returns an instantiated lld::File object which is
+a collection of Atoms. The result is a vector of File pointers (instead of
+simple a File pointer) because some file formats allow multiple object
+"files" to be encoded in one file system file.
+
+
+Memory Ownership
+----------------
+
+Atoms are always owned by their File object. During core linking when Atoms
+are coalesced or stripped away, core linking does not delete them.
+Core linking just removes those unused Atoms from its internal list.
+The destructor of a File object is responsible for deleting all Atoms it
+owns, and if ownership of the MemoryBuffer was passed to it, the File
+destructor needs to delete that too.
+
+Making Atoms
+------------
+
+The internal model of lld is purely Atom based. But most object files do not
+have an explicit concept of Atoms, instead most have "sections". The way
+to think of this is that a section is just a list of Atoms with common
+attributes.
+
+The first step in parsing section-based object files is to cleave each
+section into a list of Atoms. The technique may vary by section type. For
+code sections (e.g. .text), there are usually symbols at the start of each
+function. Those symbol addresses are the points at which the section is
+cleaved into discrete Atoms. Some file formats (like ELF) also include the
+length of each symbol in the symbol table. Otherwise, the length of each
+Atom is calculated to run to the start of the next symbol or the end of the
+section.
+
+Other sections types can be implicitly cleaved. For instance c-string literals
+or unwind info (e.g. .eh_frame) can be cleaved by having the Reader look at
+the content of the section. It is important to cleave sections into Atoms
+to remove false dependencies. For instance the .eh_frame section often
+has no symbols, but contains "pointers" to the functions for which it
+has unwind info. If the .eh_frame section was not cleaved (but left as one
+big Atom), there would always be a reference (from the eh_frame Atom) to
+each function. So the linker would be unable to coalesce or dead stripped
+away the function atoms.
+
+The lld Atom model also requires that a reference to an undefined symbol be
+modeled as a Reference to an UndefinedAtom. So the Reader also needs to
+create an UndefinedAtom for each undefined symbol in the object file.
+
+Once all Atoms have been created, the second step is to create References
+(recall that Atoms are "nodes" and References are "edges"). Most References
+are created by looking at the "relocation records" in the object file. If
+a function contains a call to "malloc", there is usually a relocation record
+specifying the address in the section and the symbol table index. Your
+Reader will need to convert the address to an Atom and offset and the symbol
+table index into a target Atom. If "malloc" is not defined in the object file,
+the target Atom of the Reference will be an UndefinedAtom.
+
+
+Performance
+-----------
+Once you have the above working to parse an object file into Atoms and
+References, you'll want to look at performance. Some techniques that can
+help performance are:
+
+* Use llvm::BumpPtrAllocator or pre-allocate one big vector<Reference> and then
+ just have each atom point to its subrange of References in that vector.
+ This can be faster that allocating each Reference as separate object.
+* Pre-scan the symbol table and determine how many atoms are in each section
+ then allocate space for all the Atom objects at once.
+* Don't copy symbol names or section content to each Atom, instead use
+ StringRef and ArrayRef in each Atom to point to its name and content in the
+ MemoryBuffer.
+
+
+Testing
+-------
+
+We are still working on infrastructure to test Readers. The issue is that
+you don't want to check in binary files to the test suite. And the tools
+for creating your object file from assembly source may not be available on
+every OS.
+
+We are investigating a way to use YAML to describe the section, symbols,
+and content of a file. Then have some code which will write out an object
+file from that YAML description.
+
+Once that is in place, you can write test cases that contain section/symbols
+YAML and is run through the linker to produce Atom/References based YAML which
+is then run through FileCheck to verify the Atoms and References are as
+expected.
+
+
+
diff --git a/contrib/llvm/tools/lld/docs/ReleaseNotes.rst b/contrib/llvm/tools/lld/docs/ReleaseNotes.rst
new file mode 100644
index 000000000000..0bebfb3fb1ce
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/ReleaseNotes.rst
@@ -0,0 +1,126 @@
+=======================
+lld 8.0.0 Release Notes
+=======================
+
+.. contents::
+ :local:
+
+.. warning::
+ These are in-progress notes for the upcoming LLVM 8.0.0 release.
+ Release notes for previous releases can be found on
+ `the Download Page <https://releases.llvm.org/download.html>`_.
+
+Introduction
+============
+
+lld is a high-performance linker that supports ELF (Unix), COFF (Windows),
+Mach-O (macOS), MinGW and WebAssembly. lld is command-line-compatible with
+GNU linkers and Microsoft link.exe and is significantly faster than the
+system default linkers.
+
+nlld 8.0.0 has lots of feature improvements and bug fixes.
+
+Non-comprehensive list of changes in this release
+=================================================
+
+ELF Improvements
+----------------
+
+* lld now supports RISC-V. (`r339364
+ <https://reviews.llvm.org/rL339364>`_)
+
+* Default image base address has changed from 65536 to 2 MiB for i386
+ and 4 MiB for AArch64 to make lld-generated executables work better
+ with automatic superpage promotion. FreeBSD can promote contiguous
+ non-superpages to a superpage if they are aligned to the superpage
+ size. (`r342746 <https://reviews.llvm.org/rL342746>`_)
+
+* lld now attempts to place a ``.note`` segment in the first page of a
+ generated file, so that you can find some important information
+ (``.note.gnu.build-id`` in particular) in a core file even if a core
+ file is truncated by ulimit.
+ (`r349524 <https://reviews.llvm.org/rL349524>`_)
+
+* lld now reports an error if ``_GLOBAL_OFFSET_TABLE_`` symbol is
+ defined by an input object file, as the symbol is supposed to be
+ synthesized by the linker.
+ (`r347854 <https://reviews.llvm.org/rL347854>`_)
+
+* lld/Hexagon can now link Linux kernel and musl libc for Qualcomm
+ Hexagon ISA.
+
+* Initial MSP430 ISA support has landed.
+
+* lld now uses the ``sigrie`` instruction as a trap instruction for
+ MIPS targets.
+
+* lld now creates a TLS segment for AArch64 with a slightly larger
+ alignment requirement, so that the loader makes a few bytes room
+ before each TLS segment at runtime. The aim of this change is to
+ make room to accomodate nonstandard Android TLS slots while keeping
+ the compatibility with the standard AArch64 ABI.
+ (`r350681 <https://reviews.llvm.org/rL350681>`_)
+
+* The following flags have been added: ``--call-graph-profile``,
+ ``--no-call-graph-profile``, ``--warn-ifunc-textrel``,
+ ``-z interpose``, ``-z global``, ``-z nodefaultlib``
+
+COFF Improvements
+-----------------
+
+* PDB GUID is set to hash of PDB contents instead to a random byte
+ sequence for build reproducibility.
+
+* ``/pdbsourcepath:`` is now also used to make ``"cwd"``, ``"exe"``, ``"pdb"``
+ in the env block of PDB outputs absolute if they are relative, and to make
+ paths to obj files referenced in PDB outputs absolute if they are relative.
+ Together with the previous item, this makes it possible to generate
+ executables and PDBs that are fully deterministic and independent of the
+ absolute path to the build directory, so that different machines building
+ the same code in different directories can produce exactly the same output.
+
+* The following flags have been added: ``/force:multiple``
+
+* lld now can link against import libraries produced by GNU tools.
+
+* lld can create thunks for ARM and ARM64, to allow linking larger images
+ (over 16 MB for ARM and over 128 MB for ARM64)
+
+* Several speed and memory usage improvements.
+
+* lld now creates debug info for typedefs.
+
+* lld can now link obj files produced by ``cl.exe /Z7 /Yc``.
+
+* lld now understands ``%_PDB%`` and ``%_EXT%`` in ``/pdbaltpath:``.
+
+* Undefined symbols are now printed in demangled form in addition to raw form.
+
+MinGW Improvements
+------------------
+
+* lld can now automatically import data variables from DLLs without the
+ use of the dllimport attribute.
+
+* lld can now use existing normal MinGW sysroots with import libraries and
+ CRT startup object files for GNU binutils. lld can handle most object
+ files produced by GCC, and thus works as a drop-in replacement for
+ ld.bfd in such environments. (There are known issues with linking crtend.o
+ from GCC in setups with DWARF exceptions though, where object files are
+ linked in a different order than with GNU ld, inserting a DWARF exception
+ table terminator too early.)
+
+* lld now supports COFF embedded directives for linking to nondefault
+ libraries, just like for the normal COFF target.
+
+* Actually generate a codeview build id signature, even if not creating a PDB.
+ Previously, the ``--build-id`` option did not actually generate a build id
+ unless ``--pdb`` was specified.
+
+WebAssembly Improvements
+------------------------
+
+* Add initial support for creating shared libraries (-shared).
+ Note: The shared library format is still under active development and may
+ undergo significant changes in future versions.
+ See: https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md
diff --git a/contrib/llvm/tools/lld/docs/WebAssembly.rst b/contrib/llvm/tools/lld/docs/WebAssembly.rst
new file mode 100644
index 000000000000..424c1a10c7e7
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/WebAssembly.rst
@@ -0,0 +1,114 @@
+WebAssembly lld port
+====================
+
+The WebAssembly version of lld takes WebAssembly binaries as inputs and produces
+a WebAssembly binary as its output. For the most part it tries to mimic the
+behaviour of traditional ELF linkers and specifically the ELF lld port. Where
+possible that command line flags and the semantics should be the same.
+
+
+Object file format
+------------------
+
+The format the input object files that lld expects is specified as part of the
+the WebAssembly tool conventions
+https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md.
+
+This is object format that the llvm will produce when run with the
+``wasm32-unknown-unknown`` target. To build llvm with WebAssembly support
+currently requires enabling the experimental backed using
+``-DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly``.
+
+
+Usage
+-----
+
+The WebAssembly version of lld is installed as **wasm-ld**. It shared many
+common linker flags with **ld.lld** but also includes several
+WebAssembly-specific options:
+
+.. option:: --no-entry
+
+ Don't search for the entry point symbol (by default ``_start``).
+
+.. option:: --export-table
+
+ Export the function table to the environment.
+
+.. option:: --import-table
+
+ Import the function table from the environment.
+
+.. option:: --export-all
+
+ Export all symbols (normally combined with --no-gc-sections)
+
+.. option:: --export-dynamic
+
+ When building an executable, export any non-hidden symbols. By default only
+ the entry point and any symbols marked with --export/--export-all are
+ exported.
+
+.. option:: --global-base=<value>
+
+ Address at which to place global data.
+
+.. option:: --no-merge-data-segments
+
+ Disable merging of data segments.
+
+.. option:: --stack-first
+
+ Place stack at start of linear memory rather than after data.
+
+.. option:: --compress-relocations
+
+ Relocation targets in the code section 5-bytes wide in order to potentially
+ occomate the largest LEB128 value. This option will cause the linker to
+ shirnk the code section to remove any padding from the final output. However
+ because it effects code offset, this option is not comatible with outputing
+ debug information.
+
+.. option:: --allow-undefined
+
+ Allow undefined symbols in linked binary.
+
+.. option:: --import-memory
+
+ Import memory from the environment.
+
+.. option:: --initial-memory=<value>
+
+ Initial size of the linear memory. Default: static data size.
+
+.. option:: --max-memory=<value>
+
+ Maximum size of the linear memory. Default: unlimited.
+
+By default the function table is neither imported nor exported, but defined
+for internal use only.
+
+When building shared libraries symbols are exported if they are marked
+as ``visibility=default``. When building executables only the entry point is
+exported by default. In addition any symbol included on the command line via
+``--export`` is also exported.
+
+Since WebAssembly is designed with size in mind the linker defaults to
+``--gc-sections`` which means that all unused functions and data segments will
+be stripped from the binary.
+
+The symbols which are preserved by default are:
+
+- The entry point (by default ``_start``).
+- Any symbol which is to be exported.
+- Any symbol transitively referenced by the above.
+
+
+Missing features
+----------------
+
+- Merging of data section similar to ``SHF_MERGE`` in the ELF world is not
+ supported.
+- No support for creating shared libraries. The spec for shared libraries in
+ WebAssembly is still in flux:
+ https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md
diff --git a/contrib/llvm/tools/lld/docs/_static/favicon.ico b/contrib/llvm/tools/lld/docs/_static/favicon.ico
new file mode 100644
index 000000000000..724ad6e12dd4
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/_static/favicon.ico
Binary files differ
diff --git a/contrib/llvm/tools/lld/docs/_templates/indexsidebar.html b/contrib/llvm/tools/lld/docs/_templates/indexsidebar.html
new file mode 100644
index 000000000000..588be9309bde
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/_templates/indexsidebar.html
@@ -0,0 +1,4 @@
+<h3>Bugs</h3>
+
+<p>lld bugs should be reported at the
+ LLVM <a href="https://bugs.llvm.org/">Bugzilla</a>.</p>
diff --git a/contrib/llvm/tools/lld/docs/_templates/layout.html b/contrib/llvm/tools/lld/docs/_templates/layout.html
new file mode 100644
index 000000000000..519a24bce63a
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/_templates/layout.html
@@ -0,0 +1,12 @@
+{% extends "!layout.html" %}
+
+{% block extrahead %}
+<style type="text/css">
+ table.right { float: right; margin-left: 20px; }
+ table.right td { border: 1px solid #ccc; }
+</style>
+{% endblock %}
+
+{% block rootrellink %}
+ <li><a href="{{ pathto('index') }}">lld Home</a>&nbsp;|&nbsp;</li>
+{% endblock %}
diff --git a/contrib/llvm/tools/lld/docs/conf.py b/contrib/llvm/tools/lld/docs/conf.py
new file mode 100644
index 000000000000..62404b275450
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/conf.py
@@ -0,0 +1,255 @@
+# -*- coding: utf-8 -*-
+#
+# lld documentation build configuration file.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+from datetime import date
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.insert(0, os.path.abspath('.'))
+
+# -- General configuration -----------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['sphinx.ext.intersphinx', 'sphinx.ext.todo']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'lld'
+copyright = u'2011-%d, LLVM Project' % date.today().year
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short version.
+version = '8'
+# The full version, including alpha/beta/rc tags.
+release = '8'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+today_fmt = '%Y-%m-%d'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['_build']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+show_authors = True
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'friendly'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+html_theme = 'llvm-theme'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+html_theme_path = ["."]
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# If given, this must be the name of an image file (path relative to the
+# configuration directory) that is the favicon of the docs. Modern browsers use
+# this as icon for tabs, windows and bookmarks. It should be a Windows-style
+# icon file (.ico), which is 16x16 or 32x32 pixels large. Default: None. The
+# image file will be copied to the _static directory of the output HTML, but
+# only if the file does not already exist there.
+html_favicon = '_static/favicon.ico'
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+html_last_updated_fmt = '%Y-%m-%d'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+html_sidebars = {'index': 'indexsidebar.html'}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+# html_additional_pages = {'index': 'index.html'}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'llddoc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+latex_elements = {
+# The paper size ('letterpaper' or 'a4paper').
+#'papersize': 'letterpaper',
+
+# The font size ('10pt', '11pt' or '12pt').
+#'pointsize': '10pt',
+
+# Additional stuff for the LaTeX preamble.
+#'preamble': '',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+ ('contents', 'lld.tex', u'lld Documentation',
+ u'LLVM project', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output --------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ ('contents', 'lld', u'lld Documentation',
+ [u'LLVM project'], 1)
+]
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+
+# -- Options for Texinfo output ------------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+# dir menu entry, description, category)
+texinfo_documents = [
+ ('contents', 'lld', u'lld Documentation',
+ u'LLVM project', 'lld', 'One line description of project.',
+ 'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#texinfo_appendices = []
+
+# If false, no module index is generated.
+#texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#texinfo_show_urls = 'footnote'
+
+
+# FIXME: Define intersphinx configration.
+intersphinx_mapping = {}
+
+
+# -- Options for extensions ----------------------------------------------------
+
+# Enable this if you want TODOs to show up in the generated documentation.
+todo_include_todos = True
diff --git a/contrib/llvm/tools/lld/docs/design.rst b/contrib/llvm/tools/lld/docs/design.rst
new file mode 100644
index 000000000000..1e111f979bb5
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/design.rst
@@ -0,0 +1,421 @@
+.. _design:
+
+Linker Design
+=============
+
+Note: this document discuss Mach-O port of LLD. For ELF and COFF,
+see :doc:`index`.
+
+Introduction
+------------
+
+lld is a new generation of linker. It is not "section" based like traditional
+linkers which mostly just interlace sections from multiple object files into the
+output file. Instead, lld is based on "Atoms". Traditional section based
+linking work well for simple linking, but their model makes advanced linking
+features difficult to implement. Features like dead code stripping, reordering
+functions for locality, and C++ coalescing require the linker to work at a finer
+grain.
+
+An atom is an indivisible chunk of code or data. An atom has a set of
+attributes, such as: name, scope, content-type, alignment, etc. An atom also
+has a list of References. A Reference contains: a kind, an optional offset, an
+optional addend, and an optional target atom.
+
+The Atom model allows the linker to use standard graph theory models for linking
+data structures. Each atom is a node, and each Reference is an edge. The
+feature of dead code stripping is implemented by following edges to mark all
+live atoms, and then delete the non-live atoms.
+
+
+Atom Model
+----------
+
+An atom is an indivisible chunk of code or data. Typically each user written
+function or global variable is an atom. In addition, the compiler may emit
+other atoms, such as for literal c-strings or floating point constants, or for
+runtime data structures like dwarf unwind info or pointers to initializers.
+
+A simple "hello world" object file would be modeled like this:
+
+.. image:: hello.png
+
+There are three atoms: main, a proxy for printf, and an anonymous atom
+containing the c-string literal "hello world". The Atom "main" has two
+references. One is the call site for the call to printf, and the other is a
+reference for the instruction that loads the address of the c-string literal.
+
+There are only four different types of atoms:
+
+ * DefinedAtom
+ 95% of all atoms. This is a chunk of code or data
+
+ * UndefinedAtom
+ This is a place holder in object files for a reference to some atom
+ outside the translation unit.During core linking it is usually replaced
+ by (coalesced into) another Atom.
+
+ * SharedLibraryAtom
+ If a required symbol name turns out to be defined in a dynamic shared
+ library (and not some object file). A SharedLibraryAtom is the
+ placeholder Atom used to represent that fact.
+
+ It is similar to an UndefinedAtom, but it also tracks information
+ about the associated shared library.
+
+ * AbsoluteAtom
+ This is for embedded support where some stuff is implemented in ROM at
+ some fixed address. This atom has no content. It is just an address
+ that the Writer needs to fix up any references to point to.
+
+
+File Model
+----------
+
+The linker views the input files as basically containers of Atoms and
+References, and just a few attributes of their own. The linker works with three
+kinds of files: object files, static libraries, and dynamic shared libraries.
+Each kind of file has reader object which presents the file in the model
+expected by the linker.
+
+Object File
+~~~~~~~~~~~
+
+An object file is just a container of atoms. When linking an object file, a
+reader is instantiated which parses the object file and instantiates a set of
+atoms representing all content in the .o file. The linker adds all those atoms
+to a master graph.
+
+Static Library (Archive)
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+This is the traditional unix static archive which is just a collection of object
+files with a "table of contents". When linking with a static library, by default
+nothing is added to the master graph of atoms. Instead, if after merging all
+atoms from object files into a master graph, if any "undefined" atoms are left
+remaining in the master graph, the linker reads the table of contents for each
+static library to see if any have the needed definitions. If so, the set of
+atoms from the specified object file in the static library is added to the
+master graph of atoms.
+
+Dynamic Library (Shared Object)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Dynamic libraries are different than object files and static libraries in that
+they don't directly add any content. Their purpose is to check at build time
+that the remaining undefined references can be resolved at runtime, and provide
+a list of dynamic libraries (SO_NEEDED) that will be needed at runtime. The way
+this is modeled in the linker is that a dynamic library contributes no atoms to
+the initial graph of atoms. Instead, (like static libraries) if there are
+"undefined" atoms in the master graph of all atoms, then each dynamic library is
+checked to see if exports the required symbol. If so, a "shared library" atom is
+instantiated by the by the reader which the linker uses to replace the
+"undefined" atom.
+
+Linking Steps
+-------------
+
+Through the use of abstract Atoms, the core of linking is architecture
+independent and file format independent. All command line parsing is factored
+out into a separate "options" abstraction which enables the linker to be driven
+with different command line sets.
+
+The overall steps in linking are:
+
+ #. Command line processing
+
+ #. Parsing input files
+
+ #. Resolving
+
+ #. Passes/Optimizations
+
+ #. Generate output file
+
+The Resolving and Passes steps are done purely on the master graph of atoms, so
+they have no notion of file formats such as mach-o or ELF.
+
+
+Input Files
+~~~~~~~~~~~
+
+Existing developer tools using different file formats for object files.
+A goal of lld is to be file format independent. This is done
+through a plug-in model for reading object files. The lld::Reader is the base
+class for all object file readers. A Reader follows the factory method pattern.
+A Reader instantiates an lld::File object (which is a graph of Atoms) from a
+given object file (on disk or in-memory).
+
+Every Reader subclass defines its own "options" class (for instance the mach-o
+Reader defines the class ReaderOptionsMachO). This options class is the
+one-and-only way to control how the Reader operates when parsing an input file
+into an Atom graph. For instance, you may want the Reader to only accept
+certain architectures. The options class can be instantiated from command
+line options, or it can be subclassed and the ivars programmatically set.
+
+Resolving
+~~~~~~~~~
+
+The resolving step takes all the atoms' graphs from each object file and
+combines them into one master object graph. Unfortunately, it is not as simple
+as appending the atom list from each file into one big list. There are many
+cases where atoms need to be coalesced. That is, two or more atoms need to be
+coalesced into one atom. This is necessary to support: C language "tentative
+definitions", C++ weak symbols for templates and inlines defined in headers,
+replacing undefined atoms with actual definition atoms, and for merging copies
+of constants like c-strings and floating point constants.
+
+The linker support coalescing by-name and by-content. By-name is used for
+tentative definitions and weak symbols. By-content is used for constant data
+that can be merged.
+
+The resolving process maintains some global linking "state", including a "symbol
+table" which is a map from llvm::StringRef to lld::Atom*. With these data
+structures, the linker iterates all atoms in all input files. For each atom, it
+checks if the atom is named and has a global or hidden scope. If so, the atom
+is added to the symbol table map. If there already is a matching atom in that
+table, that means the current atom needs to be coalesced with the found atom, or
+it is a multiple definition error.
+
+When all initial input file atoms have been processed by the resolver, a scan is
+made to see if there are any undefined atoms in the graph. If there are, the
+linker scans all libraries (both static and dynamic) looking for definitions to
+replace the undefined atoms. It is an error if any undefined atoms are left
+remaining.
+
+Dead code stripping (if requested) is done at the end of resolving. The linker
+does a simple mark-and-sweep. It starts with "root" atoms (like "main" in a main
+executable) and follows each references and marks each Atom that it visits as
+"live". When done, all atoms not marked "live" are removed.
+
+The result of the Resolving phase is the creation of an lld::File object. The
+goal is that the lld::File model is **the** internal representation
+throughout the linker. The file readers parse (mach-o, ELF, COFF) into an
+lld::File. The file writers (mach-o, ELF, COFF) taken an lld::File and produce
+their file kind, and every Pass only operates on an lld::File. This is not only
+a simpler, consistent model, but it enables the state of the linker to be dumped
+at any point in the link for testing purposes.
+
+
+Passes
+~~~~~~
+
+The Passes step is an open ended set of routines that each get a change to
+modify or enhance the current lld::File object. Some example Passes are:
+
+ * stub (PLT) generation
+
+ * GOT instantiation
+
+ * order_file optimization
+
+ * branch island generation
+
+ * branch shim generation
+
+ * Objective-C optimizations (Darwin specific)
+
+ * TLV instantiation (Darwin specific)
+
+ * DTrace probe processing (Darwin specific)
+
+ * compact unwind encoding (Darwin specific)
+
+
+Some of these passes are specific to Darwin's runtime environments. But many of
+the passes are applicable to any OS (such as generating branch island for out of
+range branch instructions).
+
+The general structure of a pass is to iterate through the atoms in the current
+lld::File object, inspecting each atom and doing something. For instance, the
+stub pass, looks for call sites to shared library atoms (e.g. call to printf).
+It then instantiates a "stub" atom (PLT entry) and a "lazy pointer" atom for
+each proxy atom needed, and these new atoms are added to the current lld::File
+object. Next, all the noted call sites to shared library atoms have their
+References altered to point to the stub atom instead of the shared library atom.
+
+
+Generate Output File
+~~~~~~~~~~~~~~~~~~~~
+
+Once the passes are done, the output file writer is given current lld::File
+object. The writer's job is to create the executable content file wrapper and
+place the content of the atoms into it.
+
+lld uses a plug-in model for writing output files. All concrete writers (e.g.
+ELF, mach-o, etc) are subclasses of the lld::Writer class.
+
+Unlike the Reader class which has just one method to instantiate an lld::File,
+the Writer class has multiple methods. The crucial method is to generate the
+output file, but there are also methods which allow the Writer to contribute
+Atoms to the resolver and specify passes to run.
+
+An example of contributing
+atoms is that if the Writer knows a main executable is being linked and such
+an executable requires a specially named entry point (e.g. "_main"), the Writer
+can add an UndefinedAtom with that special name to the resolver. This will
+cause the resolver to issue an error if that symbol is not defined.
+
+Sometimes a Writer supports lazily created symbols, such as names for the start
+of sections. To support this, the Writer can create a File object which vends
+no initial atoms, but does lazily supply atoms by name as needed.
+
+Every Writer subclass defines its own "options" class (for instance the mach-o
+Writer defines the class WriterOptionsMachO). This options class is the
+one-and-only way to control how the Writer operates when producing an output
+file from an Atom graph. For instance, you may want the Writer to optimize
+the output for certain OS versions, or strip local symbols, etc. The options
+class can be instantiated from command line options, or it can be subclassed
+and the ivars programmatically set.
+
+
+lld::File representations
+-------------------------
+
+Just as LLVM has three representations of its IR model, lld has two
+representations of its File/Atom/Reference model:
+
+ * In memory, abstract C++ classes (lld::Atom, lld::Reference, and lld::File).
+
+ * textual (in YAML)
+
+
+Textual representations in YAML
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In designing a textual format we want something easy for humans to read and easy
+for the linker to parse. Since an atom has lots of attributes most of which are
+usually just the default, we should define default values for every attribute so
+that those can be omitted from the text representation. Here is the atoms for a
+simple hello world program expressed in YAML::
+
+ target-triple: x86_64-apple-darwin11
+
+ atoms:
+ - name: _main
+ scope: global
+ type: code
+ content: [ 55, 48, 89, e5, 48, 8d, 3d, 00, 00, 00, 00, 30, c0, e8, 00, 00,
+ 00, 00, 31, c0, 5d, c3 ]
+ fixups:
+ - offset: 07
+ kind: pcrel32
+ target: 2
+ - offset: 0E
+ kind: call32
+ target: _fprintf
+
+ - type: c-string
+ content: [ 73, 5A, 00 ]
+
+ ...
+
+The biggest use for the textual format will be writing test cases. Writing test
+cases in C is problematic because the compiler may vary its output over time for
+its own optimization reasons which my inadvertently disable or break the linker
+feature trying to be tested. By writing test cases in the linkers own textual
+format, we can exactly specify every attribute of every atom and thus target
+specific linker logic.
+
+The textual/YAML format follows the ReaderWriter patterns used in lld. The lld
+library comes with the classes: ReaderYAML and WriterYAML.
+
+
+Testing
+-------
+
+The lld project contains a test suite which is being built up as new code is
+added to lld. All new lld functionality should have a tests added to the test
+suite. The test suite is `lit <http://llvm.org/cmds/lit.html/>`_ driven. Each
+test is a text file with comments telling lit how to run the test and check the
+result To facilitate testing, the lld project builds a tool called lld-core.
+This tool reads a YAML file (default from stdin), parses it into one or more
+lld::File objects in memory and then feeds those lld::File objects to the
+resolver phase.
+
+
+Resolver testing
+~~~~~~~~~~~~~~~~
+
+Basic testing is the "core linking" or resolving phase. That is where the
+linker merges object files. All test cases are written in YAML. One feature of
+YAML is that it allows multiple "documents" to be encoding in one YAML stream.
+That means one text file can appear to the linker as multiple .o files - the
+normal case for the linker.
+
+Here is a simple example of a core linking test case. It checks that an
+undefined atom from one file will be replaced by a definition from another
+file::
+
+ # RUN: lld-core %s | FileCheck %s
+
+ #
+ # Test that undefined atoms are replaced with defined atoms.
+ #
+
+ ---
+ atoms:
+ - name: foo
+ definition: undefined
+ ---
+ atoms:
+ - name: foo
+ scope: global
+ type: code
+ ...
+
+ # CHECK: name: foo
+ # CHECK: scope: global
+ # CHECK: type: code
+ # CHECK-NOT: name: foo
+ # CHECK: ...
+
+
+Passes testing
+~~~~~~~~~~~~~~
+
+Since Passes just operate on an lld::File object, the lld-core tool has the
+option to run a particular pass (after resolving). Thus, you can write a YAML
+test case with carefully crafted input to exercise areas of a Pass and the check
+the resulting lld::File object as represented in YAML.
+
+
+Design Issues
+-------------
+
+There are a number of open issues in the design of lld. The plan is to wait and
+make these design decisions when we need to.
+
+
+Debug Info
+~~~~~~~~~~
+
+Currently, the lld model says nothing about debug info. But the most popular
+debug format is DWARF and there is some impedance mismatch with the lld model
+and DWARF. In lld there are just Atoms and only Atoms that need to be in a
+special section at runtime have an associated section. Also, Atoms do not have
+addresses. The way DWARF is spec'ed different parts of DWARF are supposed to go
+into specially named sections and the DWARF references function code by address.
+
+CPU and OS specific functionality
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Currently, lld has an abstract "Platform" that deals with any CPU or OS specific
+differences in linking. We just keep adding virtual methods to the base
+Platform class as we find linking areas that might need customization. At some
+point we'll need to structure this better.
+
+
+File Attributes
+~~~~~~~~~~~~~~~
+
+Currently, lld::File just has a path and a way to iterate its atoms. We will
+need to add more attributes on a File. For example, some equivalent to the
+target triple. There is also a number of cached or computed attributes that
+could make various Passes more efficient. For instance, on Darwin there are a
+number of Objective-C optimizations that can be done by a Pass. But it would
+improve the plain C case if the Objective-C optimization Pass did not have to
+scan all atoms looking for any Objective-C data structures. This could be done
+if the lld::File object had an attribute that said if the file had any
+Objective-C data in it. The Resolving phase would then be required to "merge"
+that attribute as object files are added.
diff --git a/contrib/llvm/tools/lld/docs/development.rst b/contrib/llvm/tools/lld/docs/development.rst
new file mode 100644
index 000000000000..ce91341d665f
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/development.rst
@@ -0,0 +1,45 @@
+.. _development:
+
+Development
+===========
+
+Note: this document discuss Mach-O port of LLD. For ELF and COFF,
+see :doc:`index`.
+
+lld is developed as part of the `LLVM <http://llvm.org>`_ project.
+
+Creating a Reader
+-----------------
+
+See the :ref:`Creating a Reader <Readers>` guide.
+
+
+Modifying the Driver
+--------------------
+
+See :doc:`Driver`.
+
+
+Debugging
+---------
+
+You can run lld with ``-mllvm -debug`` command line options to enable debugging
+printouts. If you want to enable debug information for some specific pass, you
+can run it with ``-mllvm '-debug-only=<pass>'``, where pass is a name used in
+the ``DEBUG_WITH_TYPE()`` macro.
+
+
+
+Documentation
+-------------
+
+The project documentation is written in reStructuredText and generated using the
+`Sphinx <http://sphinx.pocoo.org/>`_ documentation generator. For more
+information on writing documentation for the project, see the
+:ref:`sphinx_intro`.
+
+.. toctree::
+ :hidden:
+
+ Readers
+ Driver
diff --git a/contrib/llvm/tools/lld/docs/getting_started.rst b/contrib/llvm/tools/lld/docs/getting_started.rst
new file mode 100644
index 000000000000..97c3d1bccbda
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/getting_started.rst
@@ -0,0 +1,106 @@
+.. _getting_started:
+
+Getting Started: Building and Running lld
+=========================================
+
+This page gives you the shortest path to checking out and building lld. If you
+run into problems, please file bugs in the `LLVM Bugzilla`__
+
+__ http://llvm.org/bugs/
+
+Building lld
+------------
+
+On Unix-like Systems
+~~~~~~~~~~~~~~~~~~~~
+
+1. Get the required tools.
+
+ * `CMake 2.8`_\+.
+ * make (or any build system CMake supports).
+ * `Clang 3.1`_\+ or GCC 4.7+ (C++11 support is required).
+
+ * If using Clang, you will also need `libc++`_.
+ * `Python 2.4`_\+ (not 3.x) for running tests.
+
+.. _CMake 2.8: http://www.cmake.org/cmake/resources/software.html
+.. _Clang 3.1: http://clang.llvm.org/
+.. _libc++: http://libcxx.llvm.org/
+.. _Python 2.4: http://python.org/download/
+
+2. Check out LLVM::
+
+ $ cd path/to/llvm-project
+ $ svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm
+
+3. Check out lld::
+
+ $ cd llvm/tools
+ $ svn co http://llvm.org/svn/llvm-project/lld/trunk lld
+
+ * lld can also be checked out to ``path/to/llvm-project`` and built as an external
+ project.
+
+4. Build LLVM and lld::
+
+ $ cd path/to/llvm-build/llvm (out of source build required)
+ $ cmake -G "Unix Makefiles" path/to/llvm-project/llvm
+ $ make
+
+ * If you want to build with clang and it is not the default compiler or
+ it is installed in an alternate location, you'll need to tell the cmake tool
+ the location of the C and C++ compiler via CMAKE_C_COMPILER and
+ CMAKE_CXX_COMPILER. For example::
+
+ $ cmake -DCMAKE_CXX_COMPILER=/path/to/clang++ -DCMAKE_C_COMPILER=/path/to/clang ...
+
+5. Test::
+
+ $ make check-lld
+
+Using Visual Studio
+~~~~~~~~~~~~~~~~~~~
+
+#. Get the required tools.
+
+ * `CMake 2.8`_\+.
+ * `Visual Studio 12 (2013) or later`_ (required for C++11 support)
+ * `Python 2.4`_\+ (not 3.x) for running tests.
+
+.. _CMake 2.8: http://www.cmake.org/cmake/resources/software.html
+.. _Visual Studio 12 (2013) or later: http://www.microsoft.com/visualstudio/11/en-us
+.. _Python 2.4: http://python.org/download/
+
+#. Check out LLVM::
+
+ $ cd path/to/llvm-project
+ $ svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm
+
+#. Check out lld::
+
+ $ cd llvm/tools
+ $ svn co http://llvm.org/svn/llvm-project/lld/trunk lld
+
+ * lld can also be checked out to ``path/to/llvm-project`` and built as an external
+ project.
+
+#. Generate Visual Studio project files::
+
+ $ cd path/to/llvm-build/llvm (out of source build required)
+ $ cmake -G "Visual Studio 11" path/to/llvm-project/llvm
+
+#. Build
+
+ * Open LLVM.sln in Visual Studio.
+ * Build the ``ALL_BUILD`` target.
+
+#. Test
+
+ * Build the ``lld-test`` target.
+
+More Information
+~~~~~~~~~~~~~~~~
+
+For more information on using CMake see the `LLVM CMake guide`_.
+
+.. _LLVM CMake guide: http://llvm.org/docs/CMake.html
diff --git a/contrib/llvm/tools/lld/docs/hello.png b/contrib/llvm/tools/lld/docs/hello.png
new file mode 100644
index 000000000000..70df111f1abd
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/hello.png
Binary files differ
diff --git a/contrib/llvm/tools/lld/docs/index.rst b/contrib/llvm/tools/lld/docs/index.rst
new file mode 100644
index 000000000000..2564e9b6310f
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/index.rst
@@ -0,0 +1,177 @@
+LLD - The LLVM Linker
+=====================
+
+LLD is a linker from the LLVM project that is a drop-in replacement
+for system linkers and runs much faster than them. It also provides
+features that are useful for toolchain developers.
+
+The linker supports ELF (Unix), PE/COFF (Windows), Mach-O (macOS) and
+WebAssembly in descending order of completeness. Internally, LLD consists of
+several different linkers. The ELF port is the one that will be described in
+this document. The PE/COFF port is complete, including
+Windows debug info (PDB) support. The WebAssembly port is still a work in
+progress (See :doc:`WebAssembly`). The Mach-O port is built based on a
+different architecture than the others. For the details about Mach-O, please
+read :doc:`AtomLLD`.
+
+Features
+--------
+
+- LLD is a drop-in replacement for the GNU linkers that accepts the
+ same command line arguments and linker scripts as GNU.
+
+ We are currently working closely with the FreeBSD project to make
+ LLD default system linker in future versions of the operating
+ system, so we are serious about addressing compatibility issues. As
+ of February 2017, LLD is able to link the entire FreeBSD/amd64 base
+ system including the kernel. With a few work-in-progress patches it
+ can link approximately 95% of the ports collection on AMD64. For the
+ details, see `FreeBSD quarterly status report
+ <https://www.freebsd.org/news/status/report-2016-10-2016-12.html#Using-LLVM%27s-LLD-Linker-as-FreeBSD%27s-System-Linker>`_.
+
+- LLD is very fast. When you link a large program on a multicore
+ machine, you can expect that LLD runs more than twice as fast as the GNU
+ gold linker. Your milage may vary, though.
+
+- It supports various CPUs/ABIs including x86-64, x86, x32, AArch64,
+ ARM, MIPS 32/64 big/little-endian, PowerPC, PowerPC 64 and AMDGPU.
+ Among these, x86-64, AArch64, and ARM (>= v6) are production quality.
+ MIPS seems decent too. x86 should be OK but is not well tested yet.
+
+- It is always a cross-linker, meaning that it always supports all the
+ above targets however it was built. In fact, we don't provide a
+ build-time option to enable/disable each target. This should make it
+ easy to use our linker as part of a cross-compile toolchain.
+
+- You can embed LLD in your program to eliminate dependencies on
+ external linkers. All you have to do is to construct object files
+ and command line arguments just like you would do to invoke an
+ external linker and then call the linker's main function,
+ ``lld::elf::link``, from your code.
+
+- It is small. We are using LLVM libObject library to read from object
+ files, so it is not a completely fair comparison, but as of February
+ 2017, LLD/ELF consists only of 21k lines of C++ code while GNU gold
+ consists of 198k lines of C++ code.
+
+- Link-time optimization (LTO) is supported by default. Essentially,
+ all you have to do to do LTO is to pass the ``-flto`` option to clang.
+ Then clang creates object files not in the native object file format
+ but in LLVM bitcode format. LLD reads bitcode object files, compile
+ them using LLVM and emit an output file. Because in this way LLD can
+ see the entire program, it can do the whole program optimization.
+
+- Some very old features for ancient Unix systems (pre-90s or even
+ before that) have been removed. Some default settings have been
+ tuned for the 21st century. For example, the stack is marked as
+ non-executable by default to tighten security.
+
+Performance
+-----------
+
+This is a link time comparison on a 2-socket 20-core 40-thread Xeon
+E5-2680 2.80 GHz machine with an SSD drive. We ran gold and lld with
+or without multi-threading support. To disable multi-threading, we
+added ``-no-threads`` to the command lines.
+
+============ =========== ============ ==================== ================== =============== =============
+Program Output size GNU ld GNU gold w/o threads GNU gold w/threads lld w/o threads lld w/threads
+ffmpeg dbg 92 MiB 1.72s 1.16s 1.01s 0.60s 0.35s
+mysqld dbg 154 MiB 8.50s 2.96s 2.68s 1.06s 0.68s
+clang dbg 1.67 GiB 104.03s 34.18s 23.49s 14.82s 5.28s
+chromium dbg 1.14 GiB 209.05s [1]_ 64.70s 60.82s 27.60s 16.70s
+============ =========== ============ ==================== ================== =============== =============
+
+As you can see, lld is significantly faster than GNU linkers.
+Note that this is just a benchmark result of our environment.
+Depending on number of available cores, available amount of memory or
+disk latency/throughput, your results may vary.
+
+.. [1] Since GNU ld doesn't support the ``-icf=all`` and
+ ``-gdb-index`` options, we removed them from the command line
+ for GNU ld. GNU ld would have been slower than this if it had
+ these options.
+
+Build
+-----
+
+If you have already checked out LLVM using SVN, you can check out LLD
+under ``tools`` directory just like you probably did for clang. For the
+details, see `Getting Started with the LLVM System
+<http://llvm.org/docs/GettingStarted.html>`_.
+
+If you haven't checked out LLVM, the easiest way to build LLD is to
+check out the entire LLVM projects/sub-projects from a git mirror and
+build that tree. You need `cmake` and of course a C++ compiler.
+
+.. code-block:: console
+
+ $ git clone https://github.com/llvm-project/llvm-project-20170507 llvm-project
+ $ mkdir build
+ $ cd build
+ $ cmake -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS=lld -DCMAKE_INSTALL_PREFIX=/usr/local ../llvm-project/llvm
+ $ make install
+
+Using LLD
+---------
+
+LLD is installed as ``ld.lld``. On Unix, linkers are invoked by
+compiler drivers, so you are not expected to use that command
+directly. There are a few ways to tell compiler drivers to use ld.lld
+instead of the default linker.
+
+The easiest way to do that is to overwrite the default linker. After
+installing LLD to somewhere on your disk, you can create a symbolic
+link by doing ``ln -s /path/to/ld.lld /usr/bin/ld`` so that
+``/usr/bin/ld`` is resolved to LLD.
+
+If you don't want to change the system setting, you can use clang's
+``-fuse-ld`` option. In this way, you want to set ``-fuse-ld=lld`` to
+LDFLAGS when building your programs.
+
+LLD leaves its name and version number to a ``.comment`` section in an
+output. If you are in doubt whether you are successfully using LLD or
+not, run ``readelf --string-dump .comment <output-file>`` and examine the
+output. If the string "Linker: LLD" is included in the output, you are
+using LLD.
+
+History
+-------
+
+Here is a brief project history of the ELF and COFF ports.
+
+- May 2015: We decided to rewrite the COFF linker and did that.
+ Noticed that the new linker is much faster than the MSVC linker.
+
+- July 2015: The new ELF port was developed based on the COFF linker
+ architecture.
+
+- September 2015: The first patches to support MIPS and AArch64 landed.
+
+- October 2015: Succeeded to self-host the ELF port. We have noticed
+ that the linker was faster than the GNU linkers, but we weren't sure
+ at the time if we would be able to keep the gap as we would add more
+ features to the linker.
+
+- July 2016: Started working on improving the linker script support.
+
+- December 2016: Succeeded to build the entire FreeBSD base system
+ including the kernel. We had widen the performance gap against the
+ GNU linkers.
+
+Internals
+---------
+
+For the internals of the linker, please read :doc:`NewLLD`. It is a bit
+outdated but the fundamental concepts remain valid. We'll update the
+document soon.
+
+.. toctree::
+ :maxdepth: 1
+
+ NewLLD
+ AtomLLD
+ WebAssembly
+ windows_support
+ missingkeyfunction
+ ReleaseNotes
diff --git a/contrib/llvm/tools/lld/docs/ld.lld.1 b/contrib/llvm/tools/lld/docs/ld.lld.1
new file mode 100644
index 000000000000..04bf19d6b23c
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/ld.lld.1
@@ -0,0 +1,626 @@
+.\" This file is distributed under the University of Illinois Open Source
+.\" License. See LICENSE.TXT for details.
+.\"
+.\" This man page documents only lld's ELF linking support, obtained originally
+.\" from FreeBSD.
+.Dd September 26, 2018
+.Dt LD.LLD 1
+.Os
+.Sh NAME
+.Nm ld.lld
+.Nd ELF linker from the LLVM project
+.Sh SYNOPSIS
+.Nm ld.lld
+.Op Ar options
+.Ar objfile ...
+
+.Sh DESCRIPTION
+A linker takes one or more object, archive, and library files, and combines
+them into an output file (an executable, a shared library, or another object
+file).
+It relocates code and data from the input files and resolves symbol
+references between them.
+.Pp
+.Nm
+is a drop-in replacement for the GNU BFD and gold linkers.
+It accepts most of the same command line arguments and linker scripts
+as GNU linkers.
+.Pp
+.Nm
+currently supports i386, x86-64, ARM, AArch64, PowerPC32, PowerPC64,
+MIPS32, MIPS64, RISC-V, AMDGPU, Hexagon and SPARC V9 targets.
+.Nm
+acts as a Microsoft link.exe-compatible linker if invoked as
+.Nm lld-link
+and as macOS's ld if invoked as
+.Nm ld.ld64.
+All these targets are always supported however
+.Nm
+was built, so you can always use
+.Nm
+as a native linker as well as a cross linker.
+
+.Sh OPTIONS
+Many options have both a single-letter and long form.
+When using the long form options other than those beginning with the
+letter
+.Cm o
+may be specified using either one or two dashes preceding the option name.
+Long options beginning with
+.Cm o
+require two dashes to avoid confusion with the
+.Fl o Ar path
+option.
+.Pp
+.Bl -tag -width indent
+.It Fl -allow-multiple-definition
+Do not error if a symbol is defined multiple times.
+The first definition will be used.
+.It Fl -apply-dynamic-relocs
+Apply link-time values for dynamic relocations.
+.It Fl -as-needed
+Only set
+.Dv DT_NEEDED
+for shared libraries if used.
+.It Fl -auxiliary Ns = Ns Ar value
+Set the
+.Dv DT_AUXILIARY
+field to the specified name.
+.It Fl -Bdynamic , Fl -dy
+Link against shared libraries.
+.It Fl -Bstatic , Fl -static , Fl -dn
+Do not link against shared libraries.
+.It Fl -Bsymbolic
+Bind defined symbols locally.
+.It Fl -Bsymbolic-functions
+Bind defined function symbols locally.
+.It Fl -build-id Ns = Ns Ar value
+Generate a build ID note.
+.Ar value
+may be one of
+.Cm fast ,
+.Cm md5 ,
+.Cm sha1 ,
+.Cm tree ,
+.Cm uuid ,
+.Cm 0x Ns Ar hex-string ,
+and
+.Cm none .
+.Cm tree
+is an alias for
+.Cm sha1 .
+Build-IDs of type
+.Cm fast ,
+.Cm md5 ,
+.Cm sha1 ,
+and
+.Cm tree
+are calculated from the object contents.
+.Cm fast
+is not intended to be cryptographically secure.
+.It Fl -build-id
+Synonym for
+.Fl -build-id Ns = Ns Cm fast .
+.It Fl -color-diagnostics Ns = Ns Ar value
+Use colors in diagnostics.
+.Ar value
+may be one of
+.Cm always ,
+.Cm auto ,
+and
+.Cm never .
+.Cm auto
+enables color if and only if output is to a terminal.
+.It Fl -color-diagnostics
+Alias for
+.Fl -color-diagnostics Ns = Ns Cm auto .
+.It Fl -compress-debug-sections Ns = Ns Ar value
+Compress DWARF debug sections.
+.Ar value
+may be
+.Cm none
+or
+.Cm zlib .
+.It Fl -cref
+Output cross reference table.
+.It Fl -define-common , Fl d
+Assign space to common symbols.
+.It Fl -defsym Ns = Ns Ar symbol Ns = Ns Ar expression
+Define a symbol alias.
+.Ar expression
+may be another symbol or a linker script expression.
+For example,
+.Ql --defsym=foo=bar
+or
+.Ql --defsym=foo=bar+0x100 .
+.It Fl -demangle
+Demangle symbol names.
+.It Fl -disable-new-dtags
+Disable new dynamic tags.
+.It Fl -discard-all , Fl x
+Delete all local symbols.
+.It Fl -discard-locals , Fl X
+Delete temporary local symbols.
+.It Fl -discard-none
+Keep all symbols in the symbol table.
+.It Fl -dynamic-linker Ns = Ns Ar value
+Specify the dynamic linker to be used for a dynamically linked executable.
+This is recorded in an ELF segment of type
+.Dv PT_INTERP .
+.It Fl -dynamic-list Ns = Ns Ar file
+Read a list of dynamic symbols from
+.Ar file .
+.It Fl -eh-frame-hdr
+Request creation of
+.Li .eh_frame_hdr
+section and
+.Dv PT_GNU_EH_FRAME
+segment header.
+.It Fl -emit-relocs , Fl q
+Generate relocations in the output.
+.It Fl -enable-new-dtags
+Enable new dynamic tags.
+.It Fl -end-lib
+End a grouping of objects that should be treated as if they were together
+in an archive.
+.It Fl -entry Ns = Ns Ar entry
+Name of entry point symbol.
+.It Fl -error-limit Ns = Ns Ar value
+Maximum number of errors to emit before stopping.
+A value of zero indicates that there is no limit.
+.It Fl -error-unresolved-symbols
+Report unresolved symbols as errors.
+.It Fl -execute-only
+Mark executable sections unreadable. This option is currently only
+supported on AArch64.
+.It Fl -exclude-libs Ns = Ns Ar value
+Exclude static libraries from automatic export.
+.It Fl -export-dynamic , Fl E
+Put symbols in the dynamic symbol table.
+.It Fl -export-dynamic-symbol Ns = Ns Ar symbol
+Include
+.Ar symbol
+in the dynamic symbol table.
+.It Fl -fatal-warnings
+Treat warnings as errors.
+.It Fl -filter Ns = Ns Ar value , Fl F Ar value
+Set the
+.Dv DT_FILTER
+field to the specified value.
+.It Fl -fini Ns = Ns Ar symbol
+Specify a finalizer function.
+.It Fl -format Ns = Ns Ar input-format , Fl b Ar input-format
+Specify the format of the inputs following this option.
+.Ar input-format
+may be one of
+.Cm binary ,
+.Cm elf ,
+and
+.Cm default .
+.Cm default
+is a synonym for
+.Cm elf .
+.It Fl -gc-sections
+Enable garbage collection of unused sections.
+.It Fl -gdb-index
+Generate
+.Li .gdb_index
+section.
+.It Fl -hash-style Ns = Ns Ar value
+Specify hash style.
+.Ar value
+may be
+.Cm sysv ,
+.Cm gnu ,
+or
+.Cm both .
+.Cm both
+is the default.
+.It Fl -help
+Print a help message.
+.It Fl -icf Ns = Ns Cm all
+Enable identical code folding.
+.It Fl -icf Ns = Ns Cm safe
+Enable safe identical code folding.
+.It Fl -icf Ns = Ns Cm none
+Disable identical code folding.
+.It Fl -image-base Ns = Ns Ar value
+Set the base address to
+.Ar value .
+.It Fl -init Ns = Ns Ar symbol
+Specify an initializer function.
+.It Fl -keep-unique Ns = Ns Ar symbol
+Do not fold
+.Ar symbol
+during ICF.
+.It Fl l Ar libName, Fl -library Ns = Ns Ar libName
+Root name of library to use.
+.It Fl L Ar dir , Fl -library-path Ns = Ns Ar dir
+Add a directory to the library search path.
+.It Fl -lto-aa-pipeline Ns = Ns Ar value
+AA pipeline to run during LTO.
+Used in conjunction with
+.Fl -lto-newpm-passes .
+.It Fl -lto-newpm-passes Ns = Ns Ar value
+Passes to run during LTO.
+.It Fl -lto-O Ns Ar opt-level
+Optimization level for LTO.
+.It Fl -lto-partitions Ns = Ns Ar value
+Number of LTO codegen partitions.
+.It Fl m Ar value
+Set target emulation.
+.It Fl -Map Ns = Ns Ar file , Fl M Ar file
+Print a link map to
+.Ar file .
+.It Fl -no-as-needed
+Always set
+.Dv DT_NEEDED
+for shared libraries.
+.It Fl -no-color-diagnostics
+Do not use colors in diagnostics.
+.It Fl -no-define-common
+Do not assign space to common symbols.
+.It Fl -no-demangle
+Do not demangle symbol names.
+.It Fl -no-dynamic-linker
+Inhibit output of an
+.Li .interp
+section.
+.It Fl -no-gc-sections
+Disable garbage collection of unused sections.
+.It Fl -no-gnu-unique
+Disable STB_GNU_UNIQUE symbol binding.
+.It Fl -no-rosegment
+Do not put read-only non-executable sections in their own segment.
+.It Fl -no-threads
+Do not run the linker multi-threaded.
+.It Fl -no-undefined-version
+Report version scripts that refer undefined symbols.
+.It Fl -no-undefined
+Report unresolved symbols even if the linker is creating a shared library.
+.It Fl -no-whole-archive
+Restores the default behavior of loading archive members.
+.It Fl -no-pie
+Do not create a position independent executable.
+.It Fl -noinhibit-exec
+Retain the executable output file whenever it is still usable.
+.It Fl -nostdlib
+Only search directories specified on the command line.
+.It Fl o Ar path
+Write the output executable, library, or object to
+.Ar path .
+If not specified,
+.Dv a.out
+is used as a default.
+.It Fl O Ns Ar value
+Optimize output file size.
+.Ar value
+may be:
+.Pp
+.Bl -tag -width 2n -compact
+.It Cm 0
+Disable string merging.
+.It Cm 1
+Enable string merging.
+.It Cm 2
+Enable string tail merging.
+.El
+.Pp
+.Fl O Ns Cm 1
+is the default.
+.It Fl -oformat Ns = Ns Ar format
+Specify the format for the output object file.
+The only supported
+.Ar format
+is
+.Cm binary ,
+which produces output with no ELF header.
+.It Fl -omagic , Fl N
+Set the text and data sections to be readable and writable.
+.It Fl -opt-remarks-filename Ar file
+Write optimization remarks in YAML format to
+.Ar file .
+.It Fl -opt-remarks-with-hotness
+Include hotness information in the optimization remarks file.
+.It Fl -pic-veneer
+Always generate position independent thunks.
+.It Fl -pie
+Create a position independent executable.
+.It Fl -print-gc-sections
+List removed unused sections.
+.It Fl -print-icf-sections
+List identical folded sections.
+.It Fl -print-map
+Print a link map to the standard output.
+.It Fl -push-state
+Save the current state of
+.Fl -as-needed ,
+.Fl -static ,
+and
+.Fl -whole-archive.
+.It Fl -pop-state
+Undo the effect of
+.Fl -push-state.
+.It Fl -relocatable , Fl r
+Create relocatable object file.
+.It Fl -reproduce Ns = Ns Ar value
+Dump linker invocation and input files for debugging.
+.It Fl -retain-symbols-file Ns = Ns Ar file
+Retain only the symbols listed in the file.
+.It Fl -rpath Ns = Ns Ar value , Fl R Ar value
+Add a
+.Dv DT_RUNPATH
+to the output.
+.It Fl -rsp-quoting Ns = Ns Ar value
+Quoting style for response files.
+The supported values are
+.Cm windows
+and
+.Cm posix .
+.It Fl -script Ns = Ns Ar file , Fl T Ar file
+Read linker script from
+.Ar file .
+.It Fl -section-start Ns = Ns Ar section Ns = Ns Ar address
+Set address of section.
+.It Fl -shared , Fl -Bsharable
+Build a shared object.
+.It Fl -soname Ns = Ns Ar value , Fl h Ar value
+Set
+.Dv DT_SONAME
+to
+.Ar value .
+.It Fl -sort-section Ns = Ns Ar value
+Specifies sections sorting rule when linkerscript is used.
+.It Fl -start-lib
+Start a grouping of objects that should be treated as if they were together
+in an archive.
+.It Fl -strip-all , Fl s
+Strip all symbols.
+.It Fl -strip-debug , Fl S
+Strip debugging information.
+.It Fl -symbol-ordering-file Ns = Ns Ar file
+Lay out sections in the order specified by
+.Ar file .
+.It Fl -sysroot Ns = Ns Ar value
+Set the system root.
+.It Fl -target1-abs
+Interpret
+.Dv R_ARM_TARGET1
+as
+.Dv R_ARM_ABS32 .
+.It Fl -target1-rel
+Interpret
+.Dv R_ARM_TARGET1
+as
+.Dv R_ARM_REL32 .
+.It Fl -target2 Ns = Ns Ar type
+Interpret
+.Dv R_ARM_TARGET2
+as
+.Ar type ,
+where
+.Ar type
+is one of
+.Cm rel ,
+.Cm abs ,
+or
+.Cm got-rel .
+.It Fl -Tbss Ns = Ns Ar value
+Same as
+.Fl -section-start
+with
+.Li .bss
+as the sectionname.
+.It Fl -Tdata Ns = Ns Ar value
+Same as
+.Fl -section-start
+with
+.Li .data
+as the sectionname.
+.It Fl -Ttext Ns = Ns Ar value
+Same as
+.Fl -section-start
+with
+.Li .text
+as the sectionname.
+.It Fl -thinlto-cache-dir Ns = Ns Ar value
+Path to ThinLTO cached object file directory.
+.It Fl -thinlto-cache-policy Ns = Ns Ar value
+Pruning policy for the ThinLTO cache.
+.It Fl -thinlto-jobs Ns = Ns Ar value
+Number of ThinLTO jobs.
+.It Fl -threads
+Run the linker multi-threaded.
+This option is enabled by default.
+.It Fl -trace
+Print the names of the input files.
+.It Fl -trace-symbol Ns = Ns Ar symbol , Fl y Ar symbol
+Trace references to
+.Ar symbol .
+.It Fl -undefined Ns = Ns Ar symbol , Fl u Ar symbol
+Force
+.Ar symbol
+to be an undefined symbol during linking.
+.It Fl -unresolved-symbols Ns = Ns Ar value
+Determine how to handle unresolved symbols.
+.It Fl v
+Display the version number and proceed with linking if object files are
+specified.
+.It Fl V , Fl -version
+Display the version number and exit.
+.It Fl -verbose
+Verbose mode.
+.It Fl -version-script Ns = Ns Ar file
+Read version script from
+.Ar file .
+.It Fl -warn-backrefs
+Warn about reverse or cyclic dependencies to or between static archives.
+This can be used to ensure linker invocation remains compatible with
+traditional Unix-like linkers.
+.It Fl -warn-common
+Warn about duplicate common symbols.
+.It Fl -warn-ifunc-textrel
+Warn about using ifunc symbols in conjunction with text relocations.
+Older versions of glibc library (2.28 and earlier) has a bug that causes
+the segment that includes ifunc symbols to be marked as not executable when
+they are relocated. As a result, although the program compiles and links
+successfully, it gives segmentation fault when the instruction pointer reaches
+an ifunc symbol. Use -warn-ifunc-textrel to let lld give a warning, if the
+code may include ifunc symbols, may do text relocations and be linked with
+an older glibc version. Otherwise, there is no need to use it, as the default
+value does not give a warning. This flag has been introduced in late 2018,
+has no counter part in ld and gold linkers, and may be removed in the future.
+.It Fl -warn-unresolved-symbols
+Report unresolved symbols as warnings.
+.It Fl -whole-archive
+Force load of all members in a static library.
+.It Fl -wrap Ns = Ns Ar symbol
+Use wrapper functions for symbol.
+.It Fl z Ar option
+Linker option extensions.
+.Bl -tag -width indent
+.It Cm execstack
+Make the main stack executable.
+Stack permissions are recorded in the
+.Dv PT_GNU_STACK
+segment.
+.It Cm global
+Sets the
+.Dv DF_1_GLOBAL flag in the
+.Dv DYNAMIC
+section.
+Different loaders can decide how to handle this flag on their own.
+.It Cm ifunc-noplt
+Do not emit PLT entries for GNU ifuncs.
+Instead, preserve relocations for ifunc call sites so that they may
+be applied by a run-time loader.
+Note that this feature requires special loader support and will
+generally result in application crashes when used outside of freestanding
+environments.
+.It Cm initfirst
+Sets the
+.Dv DF_1_INITFIRST
+flag to indicate the module should be initialized first.
+.It Cm interpose
+Set the
+.Dv DF_1_INTERPOSE
+flag to indicate to the runtime linker that the object is an interposer.
+During symbol resolution interposers are searched after the application
+but before other dependencies.
+.It Cm muldefs
+Do not error if a symbol is defined multiple times.
+The first definition will be used.
+This is a synonym for
+.Fl -allow-multiple-definition.
+.It Cm nocombreloc
+Disable combining and sorting multiple relocation sections.
+.It Cm nocopyreloc
+Disable the creation of copy relocations.
+.It Cm nodefaultlib
+Set the
+.Dv DF_1_NODEFLIB
+flag to indicate that default library search paths should be ignored.
+.It Cm nodelete
+Set the
+.Dv DF_1_NODELETE
+flag to indicate that the object cannot be unloaded from a process.
+.It Cm nodlopen
+Set the
+.Dv DF_1_NOOPEN
+flag to indicate that the object may not be opened by
+.Xr dlopen 3 .
+.It Cm norelro
+Do not indicate that portions of the object shold be mapped read-only
+after initial relocation processing.
+The object will omit the
+.Dv PT_GNU_RELRO
+segment.
+.It Cm notext
+Allow relocations against read-only segments.
+Sets the
+.Dv DT_TEXTREL flag in the
+.Dv DYNAMIC
+section.
+.It Cm now
+Set the
+.Dv DF_BIND_NOW
+flag to indicate that the run-time loader should perform all relocation
+processing as part of object initialization.
+By default relocations may be performed on demand.
+.It Cm origin
+Set the
+.Dv DF_ORIGIN
+flag to indicate that the object requires
+$ORIGIN
+processing.
+.It Cm retpolineplt
+Emit retpoline format PLT entries as a mitigation for CVE-2017-5715.
+.It Cm rodynamic
+Make the
+.Li .dynamic
+section read-only.
+The
+.Dv DT_DEBUG
+tag will not be emitted.
+.It Cm stack-size Ns = Ns Ar size
+Set the main thread's stack size to
+.Ar size .
+The stack size is recorded as the size of the
+.Ar size .
+.Dv PT_GNU_STACK
+program segment.
+.It Cm text
+Do not allow relocations against read-only segments.
+This is the default.
+.It Cm wxneeded
+Create a
+.Dv PT_OPENBSD_WXNEEDED
+segment.
+.El
+.El
+.Sh IMPLEMENTATION NOTES
+.Nm Ap s
+handing of archive files (those with a
+.Pa .a
+file extension) is different from traditional linkers used on Unix-like
+systems.
+.Pp
+Traditional linkers maintain a set of undefined symbols during linking.
+The linker processes each file in the order in which it appears on the
+command line, until the set of undefined symbols becomes empty.
+An object file is linked into the output object when it is encountered,
+with its undefined symbols added to the set.
+Upon encountering an archive file a traditional linker searches the objects
+contained therein, and processes those that satisfy symbols in the unresolved
+set.
+.Pp
+Handling mutually dependent archives may be awkward when using a traditional
+linker.
+Archive files may have to be specified multiple times, or the special command
+line options
+.Fl -start-group
+and
+.Fl -end-group
+may be used to have the linker loop over the files in the group until no new
+symbols are added to the set.
+.Pp
+.Nm
+records all symbols found in objects and archives as it iterates over
+command line arguments.
+When
+.Nm
+encounters an undefined symbol that can be resolved by an object file
+contained in a previously processed archive file, it immediately extracts
+and links it into the output object.
+.Pp
+With certain archive inputs
+.Nm
+may produce different results compared to traditional linkers.
+In practice, large bodies of third party software have been linked with
+.Nm
+without material issues.
+.Pp
+The
+.Fl -warn-backrefs
+option may be used to identify a linker invocation that may be incompatible
+with traditional Unix-like linker behavior.
diff --git a/contrib/llvm/tools/lld/docs/llvm-theme/layout.html b/contrib/llvm/tools/lld/docs/llvm-theme/layout.html
new file mode 100644
index 000000000000..0cd0918eac2a
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/llvm-theme/layout.html
@@ -0,0 +1,22 @@
+{#
+ sphinxdoc/layout.html
+ ~~~~~~~~~~~~~~~~~~~~~
+
+ Sphinx layout template for the sphinxdoc theme.
+
+ :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+#}
+{% extends "basic/layout.html" %}
+
+{% block relbar1 %}
+<div class="logo">
+<a href="{{ pathto('index') }}"><img src="{{
+pathto("_static/logo.png", 1) }}" alt="LLVM Documentation"/></a>
+</div>
+{{ super() }}
+{% endblock %}
+
+{# put the sidebar before the body #}
+{% block sidebar1 %}{{ sidebar() }}{% endblock %}
+{% block sidebar2 %}{% endblock %}
diff --git a/contrib/llvm/tools/lld/docs/llvm-theme/static/contents.png b/contrib/llvm/tools/lld/docs/llvm-theme/static/contents.png
new file mode 100644
index 000000000000..7fb82154a174
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/llvm-theme/static/contents.png
Binary files differ
diff --git a/contrib/llvm/tools/lld/docs/llvm-theme/static/llvm.css b/contrib/llvm/tools/lld/docs/llvm-theme/static/llvm.css
new file mode 100644
index 000000000000..32802bb6a2d0
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/llvm-theme/static/llvm.css
@@ -0,0 +1,345 @@
+/*
+ * sphinxdoc.css_t
+ * ~~~~~~~~~~~~~~~
+ *
+ * Sphinx stylesheet -- sphinxdoc theme. Originally created by
+ * Armin Ronacher for Werkzeug.
+ *
+ * :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+@import url("basic.css");
+
+/* -- page layout ----------------------------------------------------------- */
+
+body {
+ font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva',
+ 'Verdana', sans-serif;
+ font-size: 14px;
+ letter-spacing: -0.01em;
+ line-height: 150%;
+ text-align: center;
+ background-color: #BFD1D4;
+ color: black;
+ padding: 0;
+ border: 1px solid #aaa;
+
+ margin: 0px 80px 0px 80px;
+ min-width: 740px;
+}
+
+div.logo {
+ background-color: white;
+ text-align: left;
+ padding: 10px 10px 15px 15px;
+}
+
+div.document {
+ background-color: white;
+ text-align: left;
+ background-image: url(contents.png);
+ background-repeat: repeat-x;
+}
+
+div.bodywrapper {
+ margin: 0 240px 0 0;
+ border-right: 1px solid #ccc;
+}
+
+div.body {
+ margin: 0;
+ padding: 0.5em 20px 20px 20px;
+}
+
+div.related {
+ font-size: 1em;
+}
+
+div.related ul {
+ background-image: url(navigation.png);
+ height: 2em;
+ border-top: 1px solid #ddd;
+ border-bottom: 1px solid #ddd;
+}
+
+div.related ul li {
+ margin: 0;
+ padding: 0;
+ height: 2em;
+ float: left;
+}
+
+div.related ul li.right {
+ float: right;
+ margin-right: 5px;
+}
+
+div.related ul li a {
+ margin: 0;
+ padding: 0 5px 0 5px;
+ line-height: 1.75em;
+ color: #EE9816;
+}
+
+div.related ul li a:hover {
+ color: #3CA8E7;
+}
+
+div.sphinxsidebarwrapper {
+ padding: 0;
+}
+
+div.sphinxsidebar {
+ margin: 0;
+ padding: 0.5em 15px 15px 0;
+ width: 210px;
+ float: right;
+ font-size: 1em;
+ text-align: left;
+}
+
+div.sphinxsidebar h3, div.sphinxsidebar h4 {
+ margin: 1em 0 0.5em 0;
+ font-size: 1em;
+ padding: 0.1em 0 0.1em 0.5em;
+ color: white;
+ border: 1px solid #86989B;
+ background-color: #AFC1C4;
+}
+
+div.sphinxsidebar h3 a {
+ color: white;
+}
+
+div.sphinxsidebar ul {
+ padding-left: 1.5em;
+ margin-top: 7px;
+ padding: 0;
+ line-height: 130%;
+}
+
+div.sphinxsidebar ul ul {
+ margin-left: 20px;
+}
+
+div.footer {
+ background-color: #E3EFF1;
+ color: #86989B;
+ padding: 3px 8px 3px 0;
+ clear: both;
+ font-size: 0.8em;
+ text-align: right;
+}
+
+div.footer a {
+ color: #86989B;
+ text-decoration: underline;
+}
+
+/* -- body styles ----------------------------------------------------------- */
+
+p {
+ margin: 0.8em 0 0.5em 0;
+}
+
+a {
+ color: #CA7900;
+ text-decoration: none;
+}
+
+a:hover {
+ color: #2491CF;
+}
+
+div.body a {
+ text-decoration: underline;
+}
+
+h1 {
+ margin: 0;
+ padding: 0.7em 0 0.3em 0;
+ font-size: 1.5em;
+ color: #11557C;
+}
+
+h2 {
+ margin: 1.3em 0 0.2em 0;
+ font-size: 1.35em;
+ padding: 0;
+}
+
+h3 {
+ margin: 1em 0 -0.3em 0;
+ font-size: 1.2em;
+}
+
+div.body h1 a, div.body h2 a, div.body h3 a, div.body h4 a, div.body h5 a, div.body h6 a {
+ color: black!important;
+}
+
+h1 a.anchor, h2 a.anchor, h3 a.anchor, h4 a.anchor, h5 a.anchor, h6 a.anchor {
+ display: none;
+ margin: 0 0 0 0.3em;
+ padding: 0 0.2em 0 0.2em;
+ color: #aaa!important;
+}
+
+h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor,
+h5:hover a.anchor, h6:hover a.anchor {
+ display: inline;
+}
+
+h1 a.anchor:hover, h2 a.anchor:hover, h3 a.anchor:hover, h4 a.anchor:hover,
+h5 a.anchor:hover, h6 a.anchor:hover {
+ color: #777;
+ background-color: #eee;
+}
+
+a.headerlink {
+ color: #c60f0f!important;
+ font-size: 1em;
+ margin-left: 6px;
+ padding: 0 4px 0 4px;
+ text-decoration: none!important;
+}
+
+a.headerlink:hover {
+ background-color: #ccc;
+ color: white!important;
+}
+
+cite, code, tt {
+ font-family: 'Consolas', 'Deja Vu Sans Mono',
+ 'Bitstream Vera Sans Mono', monospace;
+ font-size: 0.95em;
+ letter-spacing: 0.01em;
+}
+
+tt {
+ background-color: #f2f2f2;
+ border-bottom: 1px solid #ddd;
+ color: #333;
+}
+
+tt.descname, tt.descclassname, tt.xref {
+ border: 0;
+}
+
+hr {
+ border: 1px solid #abc;
+ margin: 2em;
+}
+
+a tt {
+ border: 0;
+ color: #CA7900;
+}
+
+a tt:hover {
+ color: #2491CF;
+}
+
+pre {
+ font-family: 'Consolas', 'Deja Vu Sans Mono',
+ 'Bitstream Vera Sans Mono', monospace;
+ font-size: 0.95em;
+ letter-spacing: 0.015em;
+ line-height: 120%;
+ padding: 0.5em;
+ border: 1px solid #ccc;
+ background-color: #f8f8f8;
+}
+
+pre a {
+ color: inherit;
+ text-decoration: underline;
+}
+
+td.linenos pre {
+ padding: 0.5em 0;
+}
+
+div.quotebar {
+ background-color: #f8f8f8;
+ max-width: 250px;
+ float: right;
+ padding: 2px 7px;
+ border: 1px solid #ccc;
+}
+
+div.topic {
+ background-color: #f8f8f8;
+}
+
+table {
+ border-collapse: collapse;
+ margin: 0 -0.5em 0 -0.5em;
+}
+
+table td, table th {
+ padding: 0.2em 0.5em 0.2em 0.5em;
+}
+
+div.admonition, div.warning {
+ font-size: 0.9em;
+ margin: 1em 0 1em 0;
+ border: 1px solid #86989B;
+ background-color: #f7f7f7;
+ padding: 0;
+}
+
+div.admonition p, div.warning p {
+ margin: 0.5em 1em 0.5em 1em;
+ padding: 0;
+}
+
+div.admonition pre, div.warning pre {
+ margin: 0.4em 1em 0.4em 1em;
+}
+
+div.admonition p.admonition-title,
+div.warning p.admonition-title {
+ margin: 0;
+ padding: 0.1em 0 0.1em 0.5em;
+ color: white;
+ border-bottom: 1px solid #86989B;
+ font-weight: bold;
+ background-color: #AFC1C4;
+}
+
+div.warning {
+ border: 1px solid #940000;
+}
+
+div.warning p.admonition-title {
+ background-color: #CF0000;
+ border-bottom-color: #940000;
+}
+
+div.admonition ul, div.admonition ol,
+div.warning ul, div.warning ol {
+ margin: 0.1em 0.5em 0.5em 3em;
+ padding: 0;
+}
+
+div.versioninfo {
+ margin: 1em 0 0 0;
+ border: 1px solid #ccc;
+ background-color: #DDEAF0;
+ padding: 8px;
+ line-height: 1.3em;
+ font-size: 0.9em;
+}
+
+.viewcode-back {
+ font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva',
+ 'Verdana', sans-serif;
+}
+
+div.viewcode-block:target {
+ background-color: #f4debf;
+ border-top: 1px solid #ac9;
+ border-bottom: 1px solid #ac9;
+}
diff --git a/contrib/llvm/tools/lld/docs/llvm-theme/static/logo.png b/contrib/llvm/tools/lld/docs/llvm-theme/static/logo.png
new file mode 100644
index 000000000000..4fc899028dc6
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/llvm-theme/static/logo.png
Binary files differ
diff --git a/contrib/llvm/tools/lld/docs/llvm-theme/static/navigation.png b/contrib/llvm/tools/lld/docs/llvm-theme/static/navigation.png
new file mode 100644
index 000000000000..1081dc1439fb
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/llvm-theme/static/navigation.png
Binary files differ
diff --git a/contrib/llvm/tools/lld/docs/llvm-theme/theme.conf b/contrib/llvm/tools/lld/docs/llvm-theme/theme.conf
new file mode 100644
index 000000000000..330fc92ffa18
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/llvm-theme/theme.conf
@@ -0,0 +1,4 @@
+[theme]
+inherit = basic
+stylesheet = llvm.css
+pygments_style = friendly
diff --git a/contrib/llvm/tools/lld/docs/make.bat b/contrib/llvm/tools/lld/docs/make.bat
new file mode 100644
index 000000000000..8471252d709f
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/make.bat
@@ -0,0 +1,190 @@
+@ECHO OFF
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set BUILDDIR=_build
+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
+set I18NSPHINXOPTS=%SPHINXOPTS% .
+if NOT "%PAPER%" == "" (
+ set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
+ set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
+)
+
+if "%1" == "" goto help
+
+if "%1" == "help" (
+ :help
+ echo.Please use `make ^<target^>` where ^<target^> is one of
+ echo. html to make standalone HTML files
+ echo. dirhtml to make HTML files named index.html in directories
+ echo. singlehtml to make a single large HTML file
+ echo. pickle to make pickle files
+ echo. json to make JSON files
+ echo. htmlhelp to make HTML files and a HTML help project
+ echo. qthelp to make HTML files and a qthelp project
+ echo. devhelp to make HTML files and a Devhelp project
+ echo. epub to make an epub
+ echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
+ echo. text to make text files
+ echo. man to make manual pages
+ echo. texinfo to make Texinfo files
+ echo. gettext to make PO message catalogs
+ echo. changes to make an overview over all changed/added/deprecated items
+ echo. linkcheck to check all external links for integrity
+ echo. doctest to run all doctests embedded in the documentation if enabled
+ goto end
+)
+
+if "%1" == "clean" (
+ for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
+ del /q /s %BUILDDIR%\*
+ goto end
+)
+
+if "%1" == "html" (
+ %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/html.
+ goto end
+)
+
+if "%1" == "dirhtml" (
+ %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
+ goto end
+)
+
+if "%1" == "singlehtml" (
+ %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
+ goto end
+)
+
+if "%1" == "pickle" (
+ %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can process the pickle files.
+ goto end
+)
+
+if "%1" == "json" (
+ %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can process the JSON files.
+ goto end
+)
+
+if "%1" == "htmlhelp" (
+ %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can run HTML Help Workshop with the ^
+.hhp project file in %BUILDDIR%/htmlhelp.
+ goto end
+)
+
+if "%1" == "qthelp" (
+ %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can run "qcollectiongenerator" with the ^
+.qhcp project file in %BUILDDIR%/qthelp, like this:
+ echo.^> qcollectiongenerator %BUILDDIR%\qthelp\lld.qhcp
+ echo.To view the help file:
+ echo.^> assistant -collectionFile %BUILDDIR%\qthelp\lld.ghc
+ goto end
+)
+
+if "%1" == "devhelp" (
+ %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished.
+ goto end
+)
+
+if "%1" == "epub" (
+ %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The epub file is in %BUILDDIR%/epub.
+ goto end
+)
+
+if "%1" == "latex" (
+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
+ goto end
+)
+
+if "%1" == "text" (
+ %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The text files are in %BUILDDIR%/text.
+ goto end
+)
+
+if "%1" == "man" (
+ %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The manual pages are in %BUILDDIR%/man.
+ goto end
+)
+
+if "%1" == "texinfo" (
+ %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
+ goto end
+)
+
+if "%1" == "gettext" (
+ %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
+ goto end
+)
+
+if "%1" == "changes" (
+ %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.The overview file is in %BUILDDIR%/changes.
+ goto end
+)
+
+if "%1" == "linkcheck" (
+ %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Link check complete; look for any errors in the above output ^
+or in %BUILDDIR%/linkcheck/output.txt.
+ goto end
+)
+
+if "%1" == "doctest" (
+ %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Testing of doctests in the sources finished, look at the ^
+results in %BUILDDIR%/doctest/output.txt.
+ goto end
+)
+
+:end
diff --git a/contrib/llvm/tools/lld/docs/missingkeyfunction.rst b/contrib/llvm/tools/lld/docs/missingkeyfunction.rst
new file mode 100644
index 000000000000..54ad3251f794
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/missingkeyfunction.rst
@@ -0,0 +1,84 @@
+Missing Key Function
+====================
+
+If your build failed with a linker error something like this::
+
+ foo.cc:28: error: undefined reference to 'vtable for C'
+ the vtable symbol may be undefined because the class is missing its key function (see https://lld.llvm.org/missingkeyfunction)
+
+it's likely that your class C has a key function (defined by the ABI as the first
+non-pure, non-inline, virtual method), but you haven't actually defined it.
+
+When a class has a key function, the compiler emits the vtable (and some other
+things as well) only in the translation unit that defines that key function. Thus,
+if you're missing the key function, you'll also be missing the vtable. If no other
+function calls your missing method, you won't see any undefined reference errors
+for it, but you will see undefined references to the vtable symbol.
+
+When a class has no non-pure, non-inline, virtual methods, there is no key
+method, and the compiler is forced to emit the vtable in every translation unit
+that references the class. In this case, it is emitted in a COMDAT section,
+which allows the linker to eliminate all duplicate copies. This is still
+wasteful in terms of object file size and link time, so it's always advisable to
+ensure there is at least one eligible method that can serve as the key function.
+
+Here are the most common mistakes that lead to this error:
+
+Failing to define a virtual destructor
+--------------------------------------
+
+Say you have a base class declared in a header file::
+
+ class B {
+ public:
+ B();
+ virtual ~B();
+ ...
+ };
+
+Here, ``~B`` is the first non-pure, non-inline, virtual method, so it is the key
+method. If you forget to define ``B::~B`` in your source file, the compiler will
+not emit the vtable for ``B``, and you'll get an undefined reference to "vtable
+for B".
+
+This is just an example of the more general mistake of forgetting to define the
+key function, but it's quite common because virtual destructors are likely to be
+the first eligible key function and it's easy to forget to implement them. It's
+also more likely that you won't have any direct references to the destructor, so
+you won't see any undefined reference errors that point directly to the problem.
+
+The solution in this case is to implement the missing method.
+
+Forgetting to declare a virtual method in an abstract class as pure
+-------------------------------------------------------------------
+
+Say you have an abstract base class declared in a header file::
+
+ class A {
+ public:
+ A();
+ virtual ~A() {}
+ virtual int foo() = 0;
+ ...
+ virtual int bar();
+ ...
+ };
+
+This base class is intended to be abstract, but you forgot to mark one of the
+methods pure. Here, ``A::bar``, being non-pure, is nominated as the key function,
+and as a result, the vtable for ``A`` is not emitted, because the compiler is
+waiting for a translation unit that defines ``A::bar``.
+
+The solution in this case is to add the missing ``= 0`` to the declaration of
+``A::bar``.
+
+Key method is defined, but the linker doesn't see it
+----------------------------------------------------
+
+It's also possible that you have defined the key function somewhere, but the
+object file containing the definition of that method isn't being linked into
+your application.
+
+The solution in this case is to check your dependencies to make sure that
+the object file or the library file containing the key function is given to
+the linker.
diff --git a/contrib/llvm/tools/lld/docs/open_projects.rst b/contrib/llvm/tools/lld/docs/open_projects.rst
new file mode 100644
index 000000000000..36edca4e96dc
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/open_projects.rst
@@ -0,0 +1,9 @@
+.. _open_projects:
+
+Open Projects
+=============
+
+Documentation TODOs
+~~~~~~~~~~~~~~~~~~~
+
+.. todolist::
diff --git a/contrib/llvm/tools/lld/docs/sphinx_intro.rst b/contrib/llvm/tools/lld/docs/sphinx_intro.rst
new file mode 100644
index 000000000000..6bb9816b5ab4
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/sphinx_intro.rst
@@ -0,0 +1,127 @@
+.. _sphinx_intro:
+
+Sphinx Introduction for LLVM Developers
+=======================================
+
+This document is intended as a short and simple introduction to the Sphinx
+documentation generation system for LLVM developers.
+
+Quickstart
+----------
+
+To get started writing documentation, you will need to:
+
+ 1. Have the Sphinx tools :ref:`installed <installing_sphinx>`.
+
+ 2. Understand how to :ref:`build the documentation
+ <building_the_documentation>`.
+
+ 3. Start :ref:`writing documentation <writing_documentation>`!
+
+.. _installing_sphinx:
+
+Installing Sphinx
+~~~~~~~~~~~~~~~~~
+
+You should be able to install Sphinx using the standard Python package
+installation tool ``easy_install``, as follows::
+
+ $ sudo easy_install sphinx
+ Searching for sphinx
+ Reading http://pypi.python.org/simple/sphinx/
+ Reading http://sphinx.pocoo.org/
+ Best match: Sphinx 1.1.3
+ ... more lines here ..
+
+If you do not have root access (or otherwise want to avoid installing Sphinx in
+system directories) see the section on :ref:`installing_sphinx_in_a_venv` .
+
+If you do not have the ``easy_install`` tool on your system, you should be able
+to install it using:
+
+ Linux
+ Use your distribution's standard package management tool to install it,
+ i.e., ``apt-get install easy_install`` or ``yum install easy_install``.
+
+ Mac OS X
+ All modern Mac OS X systems come with ``easy_install`` as part of the base
+ system.
+
+ Windows
+ See the `setuptools <http://pypi.python.org/pypi/setuptools>`_ package web
+ page for instructions.
+
+
+.. _building_the_documentation:
+
+Building the documentation
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In order to build the documentation need to add ``-DLLVM_ENABLE_SPHINX=ON`` to
+your ``cmake`` command. Once you do this you can build the docs using
+``docs-lld-html`` build (``ninja`` or ``make``) target.
+
+That build target will invoke ``sphinx-build`` with the appropriate options for
+the project, and generate the HTML documentation in a ``tools/lld/docs/html``
+subdirectory.
+
+.. _writing_documentation:
+
+Writing documentation
+~~~~~~~~~~~~~~~~~~~~~
+
+The documentation itself is written in the reStructuredText (ReST) format, and
+Sphinx defines additional tags to support features like cross-referencing.
+
+The ReST format itself is organized around documents mostly being readable
+plaintext documents. You should generally be able to write new documentation
+easily just by following the style of the existing documentation.
+
+If you want to understand the formatting of the documents more, the best place
+to start is Sphinx's own `ReST Primer <http://sphinx.pocoo.org/rest.html>`_.
+
+
+Learning More
+-------------
+
+If you want to learn more about the Sphinx system, the best place to start is
+the Sphinx documentation itself, available `here
+<http://sphinx.pocoo.org/contents.html>`_.
+
+
+.. _installing_sphinx_in_a_venv:
+
+Installing Sphinx in a Virtual Environment
+------------------------------------------
+
+Most Python developers prefer to work with tools inside a *virtualenv* (virtual
+environment) instance, which functions as an application sandbox. This avoids
+polluting your system installation with different packages used by various
+projects (and ensures that dependencies for different packages don't conflict
+with one another). Of course, you need to first have the virtualenv software
+itself which generally would be installed at the system level::
+
+ $ sudo easy_install virtualenv
+
+but after that you no longer need to install additional packages in the system
+directories.
+
+Once you have the *virtualenv* tool itself installed, you can create a
+virtualenv for Sphinx using::
+
+ $ virtualenv ~/my-sphinx-install
+ New python executable in /Users/dummy/my-sphinx-install/bin/python
+ Installing setuptools............done.
+ Installing pip...............done.
+
+ $ ~/my-sphinx-install/bin/easy_install sphinx
+ ... install messages here ...
+
+and from now on you can "activate" the *virtualenv* using::
+
+ $ source ~/my-sphinx-install/bin/activate
+
+which will change your PATH to ensure the sphinx-build tool from inside the
+virtual environment will be used. See the `virtualenv website
+<http://www.virtualenv.org/en/latest/index.html>`_ for more information on using
+virtual environments.
diff --git a/contrib/llvm/tools/lld/docs/windows_support.rst b/contrib/llvm/tools/lld/docs/windows_support.rst
new file mode 100644
index 000000000000..c9723c42fcc8
--- /dev/null
+++ b/contrib/llvm/tools/lld/docs/windows_support.rst
@@ -0,0 +1,97 @@
+.. raw:: html
+
+ <style type="text/css">
+ .none { background-color: #FFCCCC }
+ .partial { background-color: #FFFF99 }
+ .good { background-color: #CCFF99 }
+ </style>
+
+.. role:: none
+.. role:: partial
+.. role:: good
+
+===============
+Windows support
+===============
+
+LLD supports Windows operating system. When invoked as ``lld-link.exe`` or with
+``-flavor link``, the driver for Windows operating system is used to parse
+command line options, and it drives further linking processes. LLD accepts
+almost all command line options that the linker shipped with Microsoft Visual
+C++ (link.exe) supports.
+
+The current status is that LLD is used to link production builds of large
+real-world binaries such as Firefox and Chromium.
+
+Development status
+==================
+
+Driver
+ :good:`Mostly done`. Some exotic command line options that are not usually
+ used for application develompent, such as ``/DRIVER``, are not supported.
+
+Linking against DLL
+ :good:`Done`. LLD can read import libraries needed to link against DLL. Both
+ export-by-name and export-by-ordinal are supported.
+
+Linking against static library
+ :good:`Done`. The format of static library (.lib) on Windows is actually the
+ same as on Unix (.a). LLD can read it.
+
+Creating DLL
+ :good:`Done`. LLD creates a DLL if ``/DLL`` option is given. Exported
+ functions can be specified either via command line (``/EXPORT``) or via
+ module-definition file (.def). Both export-by-name and export-by-ordinal are
+ supported.
+
+Windows resource files support
+ :good:`Done`. If an ``.res`` file is given, LLD converts the file to a COFF
+ file using LLVM's Object library.
+
+Safe Structured Exception Handler (SEH)
+ :good:`Done` for both x86 and x64.
+
+Module-definition file
+ :partial:`Partially done`. LLD currently recognizes these directives:
+ ``EXPORTS``, ``HEAPSIZE``, ``STACKSIZE``, ``NAME``, and ``VERSION``.
+
+Debug info
+ :good:`Done`. LLD can emit PDBs that are at parity with those generated by
+ link.exe. However, LLD does not support /DEBUG:FASTLINK.
+
+
+Downloading LLD
+===============
+
+The Windows version of LLD is included in the `pre-built binaries of LLVM's
+releases <https://releases.llvm.org/download.html>`_ and in the `LLVM Snapshot
+Builds <https://llvm.org/builds/>`_.
+
+Building LLD
+============
+
+Using Visual Studio IDE/MSBuild
+-------------------------------
+
+1. Check out LLVM and LLD from the LLVM SVN repository (or Git mirror),
+#. run ``cmake -G "Visual Studio 12" <llvm-source-dir>`` from VS command prompt,
+#. open LLVM.sln with Visual Studio, and
+#. build ``lld`` target in ``lld executables`` folder
+
+Alternatively, you can use msbuild if you don't like to work in an IDE::
+
+ msbuild LLVM.sln /m /target:"lld executables\lld"
+
+MSBuild.exe had been shipped as a component of the .NET framework, but since
+2013 it's part of Visual Studio. You can find it at "C:\\Program Files
+(x86)\\msbuild".
+
+You can build LLD as a 64 bit application. To do that, open VS2013 x64 command
+prompt and run cmake for "Visual Studio 12 Win64" target.
+
+Using Ninja
+-----------
+
+1. Check out LLVM and LLD from the LLVM SVN repository (or Git mirror),
+#. run ``cmake -G ninja <llvm-source-dir>`` from VS command prompt,
+#. run ``ninja lld``
diff --git a/contrib/llvm/tools/lld/include/lld/Common/Args.h b/contrib/llvm/tools/lld/include/lld/Common/Args.h
new file mode 100644
index 000000000000..769d4840cf06
--- /dev/null
+++ b/contrib/llvm/tools/lld/include/lld/Common/Args.h
@@ -0,0 +1,38 @@
+//===- Args.h ---------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ARGS_H
+#define LLD_ARGS_H
+
+#include "lld/Common/LLVM.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <vector>
+
+namespace llvm {
+namespace opt {
+class InputArgList;
+}
+} // namespace llvm
+
+namespace lld {
+namespace args {
+int getInteger(llvm::opt::InputArgList &Args, unsigned Key, int Default);
+std::vector<StringRef> getStrings(llvm::opt::InputArgList &Args, int Id);
+
+uint64_t getZOptionValue(llvm::opt::InputArgList &Args, int Id, StringRef Key,
+ uint64_t Default);
+
+std::vector<StringRef> getLines(MemoryBufferRef MB);
+
+StringRef getFilenameWithoutExe(StringRef Path);
+
+} // namespace args
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/include/lld/Common/Driver.h b/contrib/llvm/tools/lld/include/lld/Common/Driver.h
new file mode 100644
index 000000000000..f6d92933af62
--- /dev/null
+++ b/contrib/llvm/tools/lld/include/lld/Common/Driver.h
@@ -0,0 +1,43 @@
+//===- lld/Common/Driver.h - Linker Driver Emulator -----------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COMMON_DRIVER_H
+#define LLD_COMMON_DRIVER_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace lld {
+namespace coff {
+bool link(llvm::ArrayRef<const char *> Args, bool CanExitEarly,
+ llvm::raw_ostream &Diag = llvm::errs());
+}
+
+namespace mingw {
+bool link(llvm::ArrayRef<const char *> Args,
+ llvm::raw_ostream &Diag = llvm::errs());
+}
+
+namespace elf {
+bool link(llvm::ArrayRef<const char *> Args, bool CanExitEarly,
+ llvm::raw_ostream &Diag = llvm::errs());
+}
+
+namespace mach_o {
+bool link(llvm::ArrayRef<const char *> Args, bool CanExitEarly,
+ llvm::raw_ostream &Diag = llvm::errs());
+}
+
+namespace wasm {
+bool link(llvm::ArrayRef<const char *> Args, bool CanExitEarly,
+ llvm::raw_ostream &Diag = llvm::errs());
+}
+}
+
+#endif
diff --git a/contrib/llvm/tools/lld/include/lld/Common/ErrorHandler.h b/contrib/llvm/tools/lld/include/lld/Common/ErrorHandler.h
new file mode 100644
index 000000000000..c169f7b50de8
--- /dev/null
+++ b/contrib/llvm/tools/lld/include/lld/Common/ErrorHandler.h
@@ -0,0 +1,160 @@
+//===- ErrorHandler.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// We designed lld's error handlers with the following goals in mind:
+//
+// - Errors can occur at any place where we handle user input, but we don't
+// want them to affect the normal execution path too much. Ideally,
+// handling errors should be as simple as reporting them and exit (but
+// without actually doing exit).
+//
+// In particular, the design to wrap all functions that could fail with
+// ErrorOr<T> is rejected because otherwise we would have to wrap a large
+// number of functions in lld with ErrorOr. With that approach, if some
+// function F can fail, not only F but all functions that transitively call
+// F have to be wrapped with ErrorOr. That seemed too much.
+//
+// - Finding only one error at a time is not sufficient. We want to find as
+// many errors as possible with one execution of the linker. That means the
+// linker needs to keep running after a first error and give up at some
+// checkpoint (beyond which it would find cascading, false errors caused by
+// the previous errors).
+//
+// - We want a simple interface to report errors. Unlike Clang, the data we
+// handle is compiled binary, so we don't need an error reporting mechanism
+// that's as sophisticated as the one that Clang has.
+//
+// The current lld's error handling mechanism is simple:
+//
+// - When you find an error, report it using error() and continue as far as
+// you can. An internal error counter is incremented by one every time you
+// call error().
+//
+// A common idiom to handle an error is calling error() and then returning
+// a reasonable default value. For example, if your function handles a
+// user-supplied alignment value, and if you find an invalid alignment
+// (e.g. 17 which is not 2^n), you may report it using error() and continue
+// as if it were alignment 1 (which is the simplest reasonable value).
+//
+// Note that you should not continue with an invalid value; that breaks the
+// internal consistency. You need to maintain all variables have some sane
+// value even after an error occurred. So, when you have to continue with
+// some value, always use a dummy value.
+//
+// - Find a reasonable checkpoint at where you want to stop the linker, and
+// add code to return from the function if errorCount() > 0. In most cases,
+// a checkpoint already exists, so you don't need to do anything for this.
+//
+// This interface satisfies all the goals that we mentioned above.
+//
+// You should never call fatal() except for reporting a corrupted input file.
+// fatal() immediately terminates the linker, so the function is not desirable
+// if you are using lld as a subroutine in other program, and with that you
+// can find only one error at a time.
+//
+// warn() doesn't do anything but printing out a given message.
+//
+// It is not recommended to use llvm::outs() or llvm::errs() directly in lld
+// because they are not thread-safe. The functions declared in this file are
+// thread-safe.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COMMON_ERRORHANDLER_H
+#define LLD_COMMON_ERRORHANDLER_H
+
+#include "lld/Common/LLVM.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileOutputBuffer.h"
+
+namespace llvm {
+class DiagnosticInfo;
+}
+
+namespace lld {
+
+class ErrorHandler {
+public:
+ uint64_t ErrorCount = 0;
+ uint64_t ErrorLimit = 20;
+ StringRef ErrorLimitExceededMsg = "too many errors emitted, stopping now";
+ StringRef LogName = "lld";
+ llvm::raw_ostream *ErrorOS = &llvm::errs();
+ bool ColorDiagnostics = llvm::errs().has_colors();
+ bool ExitEarly = true;
+ bool FatalWarnings = false;
+ bool Verbose = false;
+
+ void error(const Twine &Msg);
+ LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg);
+ void log(const Twine &Msg);
+ void message(const Twine &Msg);
+ void warn(const Twine &Msg);
+
+ std::unique_ptr<llvm::FileOutputBuffer> OutputBuffer;
+
+private:
+ void print(StringRef S, raw_ostream::Colors C);
+};
+
+/// Returns the default error handler.
+ErrorHandler &errorHandler();
+
+inline void error(const Twine &Msg) { errorHandler().error(Msg); }
+inline LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg) {
+ errorHandler().fatal(Msg);
+}
+inline void log(const Twine &Msg) { errorHandler().log(Msg); }
+inline void message(const Twine &Msg) { errorHandler().message(Msg); }
+inline void warn(const Twine &Msg) { errorHandler().warn(Msg); }
+inline uint64_t errorCount() { return errorHandler().ErrorCount; }
+
+LLVM_ATTRIBUTE_NORETURN void exitLld(int Val);
+
+void diagnosticHandler(const llvm::DiagnosticInfo &DI);
+void checkError(Error E);
+
+// check functions are convenient functions to strip errors
+// from error-or-value objects.
+template <class T> T check(ErrorOr<T> E) {
+ if (auto EC = E.getError())
+ fatal(EC.message());
+ return std::move(*E);
+}
+
+template <class T> T check(Expected<T> E) {
+ if (!E)
+ fatal(llvm::toString(E.takeError()));
+ return std::move(*E);
+}
+
+template <class T>
+T check2(ErrorOr<T> E, llvm::function_ref<std::string()> Prefix) {
+ if (auto EC = E.getError())
+ fatal(Prefix() + ": " + EC.message());
+ return std::move(*E);
+}
+
+template <class T>
+T check2(Expected<T> E, llvm::function_ref<std::string()> Prefix) {
+ if (!E)
+ fatal(Prefix() + ": " + toString(E.takeError()));
+ return std::move(*E);
+}
+
+inline std::string toString(const Twine &S) { return S.str(); }
+
+// To evaluate the second argument lazily, we use C macro.
+#define CHECK(E, S) check2((E), [&] { return toString(S); })
+
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/include/lld/Common/LLVM.h b/contrib/llvm/tools/lld/include/lld/Common/LLVM.h
new file mode 100644
index 000000000000..95a2aa903957
--- /dev/null
+++ b/contrib/llvm/tools/lld/include/lld/Common/LLVM.h
@@ -0,0 +1,99 @@
+//===--- LLVM.h - Import various common LLVM datatypes ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file forward declares and imports various common LLVM datatypes that
+// lld wants to use unqualified.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COMMON_LLVM_H
+#define LLD_COMMON_LLVM_H
+
+// This should be the only #include, force #includes of all the others on
+// clients.
+#include "llvm/ADT/Hashing.h"
+#include "llvm/Support/Casting.h"
+#include <utility>
+
+namespace llvm {
+// ADT's.
+class raw_ostream;
+class Error;
+class StringRef;
+class Twine;
+class MemoryBuffer;
+class MemoryBufferRef;
+template <typename T> class ArrayRef;
+template <unsigned InternalLen> class SmallString;
+template <typename T, unsigned N> class SmallVector;
+template <typename T> class ErrorOr;
+template <typename T> class Expected;
+
+namespace object {
+class WasmObjectFile;
+struct WasmSection;
+struct WasmSegment;
+class WasmSymbol;
+} // namespace object
+
+namespace wasm {
+struct WasmEvent;
+struct WasmEventType;
+struct WasmFunction;
+struct WasmGlobal;
+struct WasmGlobalType;
+struct WasmRelocation;
+struct WasmSignature;
+} // namespace wasm
+} // namespace llvm
+
+namespace lld {
+// Casting operators.
+using llvm::cast;
+using llvm::cast_or_null;
+using llvm::dyn_cast;
+using llvm::dyn_cast_or_null;
+using llvm::isa;
+
+// ADT's.
+using llvm::ArrayRef;
+using llvm::Error;
+using llvm::ErrorOr;
+using llvm::Expected;
+using llvm::MemoryBuffer;
+using llvm::MemoryBufferRef;
+using llvm::raw_ostream;
+using llvm::SmallString;
+using llvm::SmallVector;
+using llvm::StringRef;
+using llvm::Twine;
+
+using llvm::object::WasmObjectFile;
+using llvm::object::WasmSection;
+using llvm::object::WasmSegment;
+using llvm::object::WasmSymbol;
+using llvm::wasm::WasmEvent;
+using llvm::wasm::WasmEventType;
+using llvm::wasm::WasmFunction;
+using llvm::wasm::WasmGlobal;
+using llvm::wasm::WasmGlobalType;
+using llvm::wasm::WasmRelocation;
+using llvm::wasm::WasmSignature;
+} // end namespace lld.
+
+namespace std {
+template <> struct hash<llvm::StringRef> {
+public:
+ size_t operator()(const llvm::StringRef &s) const {
+ return llvm::hash_value(s);
+ }
+};
+} // namespace std
+
+#endif
diff --git a/contrib/llvm/tools/lld/include/lld/Common/Memory.h b/contrib/llvm/tools/lld/include/lld/Common/Memory.h
new file mode 100644
index 000000000000..699f7c1654cd
--- /dev/null
+++ b/contrib/llvm/tools/lld/include/lld/Common/Memory.h
@@ -0,0 +1,60 @@
+//===- Memory.h -------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines arena allocators.
+//
+// Almost all large objects, such as files, sections or symbols, are
+// used for the entire lifetime of the linker once they are created.
+// This usage characteristic makes arena allocator an attractive choice
+// where the entire linker is one arena. With an arena, newly created
+// objects belong to the arena and freed all at once when everything is done.
+// Arena allocators are efficient and easy to understand.
+// Most objects are allocated using the arena allocators defined by this file.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COMMON_MEMORY_H
+#define LLD_COMMON_MEMORY_H
+
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/StringSaver.h"
+#include <vector>
+
+namespace lld {
+
+// Use this arena if your object doesn't have a destructor.
+extern llvm::BumpPtrAllocator BAlloc;
+extern llvm::StringSaver Saver;
+
+void freeArena();
+
+// These two classes are hack to keep track of all
+// SpecificBumpPtrAllocator instances.
+struct SpecificAllocBase {
+ SpecificAllocBase() { Instances.push_back(this); }
+ virtual ~SpecificAllocBase() = default;
+ virtual void reset() = 0;
+ static std::vector<SpecificAllocBase *> Instances;
+};
+
+template <class T> struct SpecificAlloc : public SpecificAllocBase {
+ void reset() override { Alloc.DestroyAll(); }
+ llvm::SpecificBumpPtrAllocator<T> Alloc;
+};
+
+// Use this arena if your object has a destructor.
+// Your destructor will be invoked from freeArena().
+template <typename T, typename... U> T *make(U &&... Args) {
+ static SpecificAlloc<T> Alloc;
+ return new (Alloc.Alloc.Allocate()) T(std::forward<U>(Args)...);
+}
+
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/include/lld/Common/Reproduce.h b/contrib/llvm/tools/lld/include/lld/Common/Reproduce.h
new file mode 100644
index 000000000000..0f425de269c7
--- /dev/null
+++ b/contrib/llvm/tools/lld/include/lld/Common/Reproduce.h
@@ -0,0 +1,39 @@
+//===- Reproduce.h - Utilities for creating reproducers ---------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COMMON_REPRODUCE_H
+#define LLD_COMMON_REPRODUCE_H
+
+#include "lld/Common/LLVM.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+namespace opt { class Arg; }
+}
+
+namespace lld {
+
+// Makes a given pathname an absolute path first, and then remove
+// beginning /. For example, "../foo.o" is converted to "home/john/foo.o",
+// assuming that the current directory is "/home/john/bar".
+std::string relativeToRoot(StringRef Path);
+
+// Quote a given string if it contains a space character.
+std::string quote(StringRef S);
+
+// Rewrite the given path if a file exists with that pathname, otherwise
+// returns the original path.
+std::string rewritePath(StringRef S);
+
+// Returns the string form of the given argument.
+std::string toString(const llvm::opt::Arg &Arg);
+}
+
+#endif
diff --git a/contrib/llvm/tools/lld/include/lld/Common/Strings.h b/contrib/llvm/tools/lld/include/lld/Common/Strings.h
new file mode 100644
index 000000000000..566030e43aa6
--- /dev/null
+++ b/contrib/llvm/tools/lld/include/lld/Common/Strings.h
@@ -0,0 +1,46 @@
+//===- Strings.h ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_STRINGS_H
+#define LLD_STRINGS_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/GlobPattern.h"
+#include <string>
+#include <vector>
+
+namespace lld {
+// Returns a demangled C++ symbol name. If Name is not a mangled
+// name, it returns Optional::None.
+llvm::Optional<std::string> demangleItanium(llvm::StringRef Name);
+llvm::Optional<std::string> demangleMSVC(llvm::StringRef S);
+
+std::vector<uint8_t> parseHex(llvm::StringRef S);
+bool isValidCIdentifier(llvm::StringRef S);
+
+// Write the contents of the a buffer to a file
+void saveBuffer(llvm::StringRef Buffer, const llvm::Twine &Path);
+
+// This class represents multiple glob patterns.
+class StringMatcher {
+public:
+ StringMatcher() = default;
+ explicit StringMatcher(llvm::ArrayRef<llvm::StringRef> Pat);
+
+ bool match(llvm::StringRef S) const;
+
+private:
+ std::vector<llvm::GlobPattern> Patterns;
+};
+
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/include/lld/Common/TargetOptionsCommandFlags.h b/contrib/llvm/tools/lld/include/lld/Common/TargetOptionsCommandFlags.h
new file mode 100644
index 000000000000..2eaecb72759e
--- /dev/null
+++ b/contrib/llvm/tools/lld/include/lld/Common/TargetOptionsCommandFlags.h
@@ -0,0 +1,23 @@
+//===-- TargetOptionsCommandFlags.h ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Helper to create TargetOptions from command line flags.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/Support/CodeGen.h"
+#include "llvm/Target/TargetOptions.h"
+
+namespace lld {
+llvm::TargetOptions InitTargetOptionsFromCodeGenFlags();
+llvm::Optional<llvm::CodeModel::Model> GetCodeModelFromCMModel();
+std::string GetCPUStr();
+std::vector<std::string> GetMAttrs();
+}
diff --git a/contrib/llvm/tools/lld/include/lld/Common/Threads.h b/contrib/llvm/tools/lld/include/lld/Common/Threads.h
new file mode 100644
index 000000000000..1425abd12922
--- /dev/null
+++ b/contrib/llvm/tools/lld/include/lld/Common/Threads.h
@@ -0,0 +1,86 @@
+//===- Threads.h ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// LLD supports threads to distribute workloads to multiple cores. Using
+// multicore is most effective when more than one core are idle. At the
+// last step of a build, it is often the case that a linker is the only
+// active process on a computer. So, we are naturally interested in using
+// threads wisely to reduce latency to deliver results to users.
+//
+// That said, we don't want to do "too clever" things using threads.
+// Complex multi-threaded algorithms are sometimes extremely hard to
+// reason about and can easily mess up the entire design.
+//
+// Fortunately, when a linker links large programs (when the link time is
+// most critical), it spends most of the time to work on massive number of
+// small pieces of data of the same kind, and there are opportunities for
+// large parallelism there. Here are examples:
+//
+// - We have hundreds of thousands of input sections that need to be
+// copied to a result file at the last step of link. Once we fix a file
+// layout, each section can be copied to its destination and its
+// relocations can be applied independently.
+//
+// - We have tens of millions of small strings when constructing a
+// mergeable string section.
+//
+// For the cases such as the former, we can just use parallelForEach
+// instead of std::for_each (or a plain for loop). Because tasks are
+// completely independent from each other, we can run them in parallel
+// without any coordination between them. That's very easy to understand
+// and reason about.
+//
+// For the cases such as the latter, we can use parallel algorithms to
+// deal with massive data. We have to write code for a tailored algorithm
+// for each problem, but the complexity of multi-threading is isolated in
+// a single pass and doesn't affect the linker's overall design.
+//
+// The above approach seems to be working fairly well. As an example, when
+// linking Chromium (output size 1.6 GB), using 4 cores reduces latency to
+// 75% compared to single core (from 12.66 seconds to 9.55 seconds) on my
+// Ivy Bridge Xeon 2.8 GHz machine. Using 40 cores reduces it to 63% (from
+// 12.66 seconds to 7.95 seconds). Because of the Amdahl's law, the
+// speedup is not linear, but as you add more cores, it gets faster.
+//
+// On a final note, if you are trying to optimize, keep the axiom "don't
+// guess, measure!" in mind. Some important passes of the linker are not
+// that slow. For example, resolving all symbols is not a very heavy pass,
+// although it would be very hard to parallelize it. You want to first
+// identify a slow pass and then optimize it.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COMMON_THREADS_H
+#define LLD_COMMON_THREADS_H
+
+#include "llvm/Support/Parallel.h"
+#include <functional>
+
+namespace lld {
+
+extern bool ThreadsEnabled;
+
+template <typename R, class FuncTy> void parallelForEach(R &&Range, FuncTy Fn) {
+ if (ThreadsEnabled)
+ for_each(llvm::parallel::par, std::begin(Range), std::end(Range), Fn);
+ else
+ for_each(llvm::parallel::seq, std::begin(Range), std::end(Range), Fn);
+}
+
+inline void parallelForEachN(size_t Begin, size_t End,
+ llvm::function_ref<void(size_t)> Fn) {
+ if (ThreadsEnabled)
+ for_each_n(llvm::parallel::par, Begin, End, Fn);
+ else
+ for_each_n(llvm::parallel::seq, Begin, End, Fn);
+}
+
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/include/lld/Common/Timer.h b/contrib/llvm/tools/lld/include/lld/Common/Timer.h
new file mode 100644
index 000000000000..6654af626919
--- /dev/null
+++ b/contrib/llvm/tools/lld/include/lld/Common/Timer.h
@@ -0,0 +1,59 @@
+//===- Timer.h ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COMMON_TIMER_H
+#define LLD_COMMON_TIMER_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringRef.h"
+#include <assert.h>
+#include <chrono>
+#include <map>
+#include <memory>
+
+namespace lld {
+
+class Timer;
+
+struct ScopedTimer {
+ explicit ScopedTimer(Timer &T);
+
+ ~ScopedTimer();
+
+ void stop();
+
+ Timer *T = nullptr;
+};
+
+class Timer {
+public:
+ Timer(llvm::StringRef Name, Timer &Parent);
+
+ static Timer &root();
+
+ void start();
+ void stop();
+ void print();
+
+ double millis() const;
+
+private:
+ explicit Timer(llvm::StringRef Name);
+ void print(int Depth, double TotalDuration, bool Recurse = true) const;
+
+ std::chrono::time_point<std::chrono::high_resolution_clock> StartTime;
+ std::chrono::nanoseconds Total;
+ std::vector<Timer *> Children;
+ std::string Name;
+ Timer *Parent;
+};
+
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/include/lld/Common/Version.h b/contrib/llvm/tools/lld/include/lld/Common/Version.h
new file mode 100644
index 000000000000..23a10ed6dbf3
--- /dev/null
+++ b/contrib/llvm/tools/lld/include/lld/Common/Version.h
@@ -0,0 +1,25 @@
+//===- lld/Common/Version.h - LLD Version Number ----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines a version-related utility function.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_VERSION_H
+#define LLD_VERSION_H
+
+#include "lld/Common/Version.inc"
+#include "llvm/ADT/StringRef.h"
+
+namespace lld {
+/// Retrieves a string representing the complete lld version.
+std::string getLLDVersion();
+}
+
+#endif // LLD_VERSION_H
diff --git a/contrib/llvm/tools/lld/include/lld/Common/Version.inc.in b/contrib/llvm/tools/lld/include/lld/Common/Version.inc.in
new file mode 100644
index 000000000000..2789a5c46089
--- /dev/null
+++ b/contrib/llvm/tools/lld/include/lld/Common/Version.inc.in
@@ -0,0 +1,6 @@
+#define LLD_VERSION @LLD_VERSION@
+#define LLD_VERSION_STRING "@LLD_VERSION@"
+#define LLD_VERSION_MAJOR @LLD_VERSION_MAJOR@
+#define LLD_VERSION_MINOR @LLD_VERSION_MINOR@
+#define LLD_REVISION_STRING "@LLD_REVISION@"
+#define LLD_REPOSITORY_STRING "@LLD_REPOSITORY@"
diff --git a/contrib/llvm/tools/lld/include/lld/Core/AbsoluteAtom.h b/contrib/llvm/tools/lld/include/lld/Core/AbsoluteAtom.h
new file mode 100644
index 000000000000..ed25297cea81
--- /dev/null
+++ b/contrib/llvm/tools/lld/include/lld/Core/AbsoluteAtom.h
@@ -0,0 +1,43 @@
+//===- Core/AbsoluteAtom.h - An absolute Atom -----------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_ABSOLUTE_ATOM_H
+#define LLD_CORE_ABSOLUTE_ATOM_H
+
+#include "lld/Core/Atom.h"
+
+namespace lld {
+
+/// An AbsoluteAtom has no content.
+/// It exists to represent content at fixed addresses in memory.
+class AbsoluteAtom : public Atom {
+public:
+
+ virtual uint64_t value() const = 0;
+
+ /// scope - The visibility of this atom to other atoms. C static functions
+ /// have scope scopeTranslationUnit. Regular C functions have scope
+ /// scopeGlobal. Functions compiled with visibility=hidden have scope
+ /// scopeLinkageUnit so they can be see by other atoms being linked but not
+ /// by the OS loader.
+ virtual Scope scope() const = 0;
+
+ static bool classof(const Atom *a) {
+ return a->definition() == definitionAbsolute;
+ }
+
+ static bool classof(const AbsoluteAtom *) { return true; }
+
+protected:
+ AbsoluteAtom() : Atom(definitionAbsolute) {}
+};
+
+} // namespace lld
+
+#endif // LLD_CORE_ABSOLUTE_ATOM_H
diff --git a/contrib/llvm/tools/lld/include/lld/Core/ArchiveLibraryFile.h b/contrib/llvm/tools/lld/include/lld/Core/ArchiveLibraryFile.h
new file mode 100644
index 000000000000..2c736e7d6c61
--- /dev/null
+++ b/contrib/llvm/tools/lld/include/lld/Core/ArchiveLibraryFile.h
@@ -0,0 +1,47 @@
+//===- Core/ArchiveLibraryFile.h - Models static library ------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_ARCHIVE_LIBRARY_FILE_H
+#define LLD_CORE_ARCHIVE_LIBRARY_FILE_H
+
+#include "lld/Core/File.h"
+#include <set>
+
+namespace lld {
+
+///
+/// The ArchiveLibraryFile subclass of File is used to represent unix
+/// static library archives. These libraries provide no atoms to the
+/// initial set of atoms linked. Instead, when the Resolver will query
+/// ArchiveLibraryFile instances for specific symbols names using the
+/// find() method. If the archive contains an object file which has a
+/// DefinedAtom whose scope is not translationUnit, then that entire
+/// object file File is returned.
+///
+class ArchiveLibraryFile : public File {
+public:
+ static bool classof(const File *f) {
+ return f->kind() == kindArchiveLibrary;
+ }
+
+ /// Check if any member of the archive contains an Atom with the
+ /// specified name and return the File object for that member, or nullptr.
+ virtual File *find(StringRef name) = 0;
+
+ virtual std::error_code
+ parseAllMembers(std::vector<std::unique_ptr<File>> &result) = 0;
+
+protected:
+ /// only subclasses of ArchiveLibraryFile can be instantiated
+ ArchiveLibraryFile(StringRef path) : File(path, kindArchiveLibrary) {}
+};
+
+} // namespace lld
+
+#endif // LLD_CORE_ARCHIVE_LIBRARY_FILE_H
diff --git a/contrib/llvm/tools/lld/include/lld/Core/Atom.h b/contrib/llvm/tools/lld/include/lld/Core/Atom.h
new file mode 100644
index 000000000000..149c3d5ee2c5
--- /dev/null
+++ b/contrib/llvm/tools/lld/include/lld/Core/Atom.h
@@ -0,0 +1,131 @@
+//===- Core/Atom.h - A node in linking graph --------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_ATOM_H
+#define LLD_CORE_ATOM_H
+
+#include "lld/Common/LLVM.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace lld {
+
+class File;
+
+template<typename T>
+class OwningAtomPtr;
+
+///
+/// The linker has a Graph Theory model of linking. An object file is seen
+/// as a set of Atoms with References to other Atoms. Each Atom is a node
+/// and each Reference is an edge. An Atom can be a DefinedAtom which has
+/// content or a UndefinedAtom which is a placeholder and represents an
+/// undefined symbol (extern declaration).
+///
+class Atom {
+ template<typename T> friend class OwningAtomPtr;
+
+public:
+ /// Whether this atom is defined or a proxy for an undefined symbol
+ enum Definition {
+ definitionRegular, ///< Normal C/C++ function or global variable.
+ definitionAbsolute, ///< Asm-only (foo = 10). Not tied to any content.
+ definitionUndefined, ///< Only in .o files to model reference to undef.
+ definitionSharedLibrary ///< Only in shared libraries to model export.
+ };
+
+ /// The scope in which this atom is acessible to other atoms.
+ enum Scope {
+ scopeTranslationUnit, ///< Accessible only to atoms in the same translation
+ /// unit (e.g. a C static).
+ scopeLinkageUnit, ///< Accessible to atoms being linked but not visible
+ /// to runtime loader (e.g. visibility=hidden).
+ scopeGlobal ///< Accessible to all atoms and visible to runtime
+ /// loader (e.g. visibility=default).
+ };
+
+ /// file - returns the File that produced/owns this Atom
+ virtual const File& file() const = 0;
+
+ /// name - The name of the atom. For a function atom, it is the (mangled)
+ /// name of the function.
+ virtual StringRef name() const = 0;
+
+ /// definition - Whether this atom is a definition or represents an undefined
+ /// symbol.
+ Definition definition() const { return _definition; }
+
+ static bool classof(const Atom *a) { return true; }
+
+protected:
+ /// Atom is an abstract base class. Only subclasses can access constructor.
+ explicit Atom(Definition def) : _definition(def) {}
+
+ /// The memory for Atom objects is always managed by the owning File
+ /// object. Therefore, no one but the owning File object should call
+ /// delete on an Atom. In fact, some File objects may bulk allocate
+ /// an array of Atoms, so they cannot be individually deleted by anyone.
+ virtual ~Atom() = default;
+
+private:
+ Definition _definition;
+};
+
+/// Class which owns an atom pointer and runs the atom destructor when the
+/// owning pointer goes out of scope.
+template<typename T>
+class OwningAtomPtr {
+private:
+ OwningAtomPtr(const OwningAtomPtr &) = delete;
+ void operator=(const OwningAtomPtr &) = delete;
+
+public:
+ OwningAtomPtr() = default;
+ OwningAtomPtr(T *atom) : atom(atom) { }
+
+ ~OwningAtomPtr() {
+ if (atom)
+ runDestructor(atom);
+ }
+
+ void runDestructor(Atom *atom) {
+ atom->~Atom();
+ }
+
+ OwningAtomPtr(OwningAtomPtr &&ptr) : atom(ptr.atom) {
+ ptr.atom = nullptr;
+ }
+
+ void operator=(OwningAtomPtr&& ptr) {
+ if (atom)
+ runDestructor(atom);
+ atom = ptr.atom;
+ ptr.atom = nullptr;
+ }
+
+ T *const &get() const {
+ return atom;
+ }
+
+ T *&get() {
+ return atom;
+ }
+
+ T *release() {
+ auto *v = atom;
+ atom = nullptr;
+ return v;
+ }
+
+private:
+ T *atom = nullptr;
+};
+
+} // end namespace lld
+
+#endif // LLD_CORE_ATOM_H
diff --git a/contrib/llvm/tools/lld/include/lld/Core/DefinedAtom.h b/contrib/llvm/tools/lld/include/lld/Core/DefinedAtom.h
new file mode 100644
index 000000000000..ba10b45411f1
--- /dev/null
+++ b/contrib/llvm/tools/lld/include/lld/Core/DefinedAtom.h
@@ -0,0 +1,374 @@
+//===- Core/DefinedAtom.h - An Atom with content --------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_DEFINED_ATOM_H
+#define LLD_CORE_DEFINED_ATOM_H
+
+#include "lld/Common/LLVM.h"
+#include "lld/Core/Atom.h"
+#include "lld/Core/Reference.h"
+#include "llvm/Support/ErrorHandling.h"
+
+namespace lld {
+class File;
+
+/// The fundamental unit of linking.
+///
+/// A C function or global variable is an atom. An atom has content and
+/// attributes. The content of a function atom is the instructions that
+/// implement the function. The content of a global variable atom is its
+/// initial bytes.
+///
+/// Here are some example attribute sets for common atoms. If a particular
+/// attribute is not listed, the default values are: definition=regular,
+/// sectionChoice=basedOnContent, scope=translationUnit, merge=no,
+/// deadStrip=normal, interposable=no
+///
+/// C function: void foo() {} <br>
+/// name=foo, type=code, perm=r_x, scope=global
+///
+/// C static function: staic void func() {} <br>
+/// name=func, type=code, perm=r_x
+///
+/// C global variable: int count = 1; <br>
+/// name=count, type=data, perm=rw_, scope=global
+///
+/// C tentative definition: int bar; <br>
+/// name=bar, type=zerofill, perm=rw_, scope=global,
+/// merge=asTentative, interposable=yesAndRuntimeWeak
+///
+/// Uninitialized C static variable: static int stuff; <br>
+/// name=stuff, type=zerofill, perm=rw_
+///
+/// Weak C function: __attribute__((weak)) void foo() {} <br>
+/// name=foo, type=code, perm=r_x, scope=global, merge=asWeak
+///
+/// Hidden C function: __attribute__((visibility("hidden"))) void foo() {}<br>
+/// name=foo, type=code, perm=r_x, scope=linkageUnit
+///
+/// No-dead-strip function: __attribute__((used)) void foo() {} <br>
+/// name=foo, type=code, perm=r_x, scope=global, deadStrip=never
+///
+/// Non-inlined C++ inline method: inline void Foo::doit() {} <br>
+/// name=_ZN3Foo4doitEv, type=code, perm=r_x, scope=global,
+/// mergeDupes=asWeak
+///
+/// Non-inlined C++ inline method whose address is taken:
+/// inline void Foo::doit() {} <br>
+/// name=_ZN3Foo4doitEv, type=code, perm=r_x, scope=global,
+/// mergeDupes=asAddressedWeak
+///
+/// literal c-string: "hello" <br>
+/// name="" type=cstring, perm=r__, scope=linkageUnit
+///
+/// literal double: 1.234 <br>
+/// name="" type=literal8, perm=r__, scope=linkageUnit
+///
+/// constant: { 1,2,3 } <br>
+/// name="" type=constant, perm=r__, scope=linkageUnit
+///
+/// Pointer to initializer function: <br>
+/// name="" type=initializer, perm=rw_l,
+/// sectionChoice=customRequired
+///
+/// C function place in custom section: __attribute__((section("__foo")))
+/// void foo() {} <br>
+/// name=foo, type=code, perm=r_x, scope=global,
+/// sectionChoice=customRequired, customSectionName=__foo
+///
+class DefinedAtom : public Atom {
+public:
+ enum Interposable {
+ interposeNo, // linker can directly bind uses of this atom
+ interposeYes, // linker must indirect (through GOT) uses
+ interposeYesAndRuntimeWeak // must indirect and mark symbol weak in final
+ // linked image
+ };
+
+ enum Merge {
+ mergeNo, // Another atom with same name is error
+ mergeAsTentative, // Is ANSI C tentative definition, can be coalesced
+ mergeAsWeak, // Is C++ inline definition that was not inlined,
+ // but address was not taken, so atom can be hidden
+ // by linker
+ mergeAsWeakAndAddressUsed, // Is C++ definition inline definition whose
+ // address was taken.
+ mergeSameNameAndSize, // Another atom with different size is error
+ mergeByLargestSection, // Choose an atom whose section is the largest.
+ mergeByContent, // Merge with other constants with same content.
+ };
+
+ enum ContentType {
+ typeUnknown, // for use with definitionUndefined
+ typeMachHeader, // atom representing mach_header [Darwin]
+ typeCode, // executable code
+ typeResolver, // function which returns address of target
+ typeBranchIsland, // linker created for large binaries
+ typeBranchShim, // linker created to switch thumb mode
+ typeStub, // linker created for calling external function
+ typeStubHelper, // linker created for initial stub binding
+ typeConstant, // a read-only constant
+ typeCString, // a zero terminated UTF8 C string
+ typeUTF16String, // a zero terminated UTF16 string
+ typeCFI, // a FDE or CIE from dwarf unwind info
+ typeLSDA, // extra unwinding info
+ typeLiteral4, // a four-btye read-only constant
+ typeLiteral8, // an eight-btye read-only constant
+ typeLiteral16, // a sixteen-btye read-only constant
+ typeData, // read-write data
+ typeDataFast, // allow data to be quickly accessed
+ typeZeroFill, // zero-fill data
+ typeZeroFillFast, // allow zero-fill data to be quicky accessed
+ typeConstData, // read-only data after dynamic linker is done
+ typeObjC1Class, // ObjC1 class [Darwin]
+ typeLazyPointer, // pointer through which a stub jumps
+ typeLazyDylibPointer, // pointer through which a stub jumps [Darwin]
+ typeNonLazyPointer, // pointer to external symbol
+ typeCFString, // NS/CFString object [Darwin]
+ typeGOT, // pointer to external symbol
+ typeInitializerPtr, // pointer to initializer function
+ typeTerminatorPtr, // pointer to terminator function
+ typeCStringPtr, // pointer to UTF8 C string [Darwin]
+ typeObjCClassPtr, // pointer to ObjC class [Darwin]
+ typeObjC2CategoryList, // pointers to ObjC category [Darwin]
+ typeObjCImageInfo, // pointer to ObjC class [Darwin]
+ typeObjCMethodList, // pointer to ObjC method list [Darwin]
+ typeDTraceDOF, // runtime data for Dtrace [Darwin]
+ typeInterposingTuples, // tuples of interposing info for dyld [Darwin]
+ typeTempLTO, // temporary atom for bitcode reader
+ typeCompactUnwindInfo, // runtime data for unwinder [Darwin]
+ typeProcessedUnwindInfo,// compressed compact unwind info [Darwin]
+ typeThunkTLV, // thunk used to access a TLV [Darwin]
+ typeTLVInitialData, // initial data for a TLV [Darwin]
+ typeTLVInitialZeroFill, // TLV initial zero fill data [Darwin]
+ typeTLVInitializerPtr, // pointer to thread local initializer [Darwin]
+ typeDSOHandle, // atom representing DSO handle [Darwin]
+ typeSectCreate, // Created via the -sectcreate option [Darwin]
+ };
+
+ // Permission bits for atoms and segments. The order of these values are
+ // important, because the layout pass may sort atoms by permission if other
+ // attributes are the same.
+ enum ContentPermissions {
+ perm___ = 0, // mapped as unaccessible
+ permR__ = 8, // mapped read-only
+ permRW_ = 8 + 2, // mapped readable and writable
+ permRW_L = 8 + 2 + 1, // initially mapped r/w, then made read-only
+ // loader writable
+ permR_X = 8 + 4, // mapped readable and executable
+ permRWX = 8 + 2 + 4, // mapped readable and writable and executable
+ permUnknown = 16 // unknown or invalid permissions
+ };
+
+ enum SectionChoice {
+ sectionBasedOnContent, // linker infers final section based on content
+ sectionCustomPreferred, // linker may place in specific section
+ sectionCustomRequired // linker must place in specific section
+ };
+
+ enum DeadStripKind {
+ deadStripNormal, // linker may dead strip this atom
+ deadStripNever, // linker must never dead strip this atom
+ deadStripAlways // linker must remove this atom if unused
+ };
+
+ enum DynamicExport {
+ /// The linker may or may not export this atom dynamically depending
+ /// on the output type and other context of the link.
+ dynamicExportNormal,
+ /// The linker will always export this atom dynamically.
+ dynamicExportAlways,
+ };
+
+ // Attributes describe a code model used by the atom.
+ enum CodeModel {
+ codeNA, // no specific code model
+ // MIPS code models
+ codeMipsPIC, // PIC function in a PIC / non-PIC mixed file
+ codeMipsMicro, // microMIPS instruction encoding
+ codeMipsMicroPIC, // microMIPS instruction encoding + PIC
+ codeMips16, // MIPS-16 instruction encoding
+ // ARM code models
+ codeARMThumb, // ARM Thumb instruction set
+ codeARM_a, // $a-like mapping symbol (for ARM code)
+ codeARM_d, // $d-like mapping symbol (for data)
+ codeARM_t, // $t-like mapping symbol (for Thumb code)
+ };
+
+ struct Alignment {
+ Alignment(int v, int m = 0) : value(v), modulus(m) {}
+
+ uint16_t value;
+ uint16_t modulus;
+
+ bool operator==(const Alignment &rhs) const {
+ return (value == rhs.value) && (modulus == rhs.modulus);
+ }
+ };
+
+ /// returns a value for the order of this Atom within its file.
+ ///
+ /// This is used by the linker to order the layout of Atoms so that the
+ /// resulting image is stable and reproducible.
+ virtual uint64_t ordinal() const = 0;
+
+ /// the number of bytes of space this atom's content will occupy in the
+ /// final linked image.
+ ///
+ /// For a function atom, it is the number of bytes of code in the function.
+ virtual uint64_t size() const = 0;
+
+ /// The size of the section from which the atom is instantiated.
+ ///
+ /// Merge::mergeByLargestSection is defined in terms of section size
+ /// and not in terms of atom size, so we need this function separate
+ /// from size().
+ virtual uint64_t sectionSize() const { return 0; }
+
+ /// The visibility of this atom to other atoms.
+ ///
+ /// C static functions have scope scopeTranslationUnit. Regular C functions
+ /// have scope scopeGlobal. Functions compiled with visibility=hidden have
+ /// scope scopeLinkageUnit so they can be see by other atoms being linked but
+ /// not by the OS loader.
+ virtual Scope scope() const = 0;
+
+ /// Whether the linker should use direct or indirect access to this
+ /// atom.
+ virtual Interposable interposable() const = 0;
+
+ /// how the linker should handle if multiple atoms have the same name.
+ virtual Merge merge() const = 0;
+
+ /// The type of this atom, such as code or data.
+ virtual ContentType contentType() const = 0;
+
+ /// The alignment constraints on how this atom must be laid out in the
+ /// final linked image (e.g. 16-byte aligned).
+ virtual Alignment alignment() const = 0;
+
+ /// Whether this atom must be in a specially named section in the final
+ /// linked image, or if the linker can infer the section based on the
+ /// contentType().
+ virtual SectionChoice sectionChoice() const = 0;
+
+ /// If sectionChoice() != sectionBasedOnContent, then this return the
+ /// name of the section the atom should be placed into.
+ virtual StringRef customSectionName() const = 0;
+
+ /// constraints on whether the linker may dead strip away this atom.
+ virtual DeadStripKind deadStrip() const = 0;
+
+ /// Under which conditions should this atom be dynamically exported.
+ virtual DynamicExport dynamicExport() const {
+ return dynamicExportNormal;
+ }
+
+ /// Code model used by the atom.
+ virtual CodeModel codeModel() const { return codeNA; }
+
+ /// Returns the OS memory protections required for this atom's content
+ /// at runtime.
+ ///
+ /// A function atom is R_X, a global variable is RW_, and a read-only constant
+ /// is R__.
+ virtual ContentPermissions permissions() const;
+
+ /// returns a reference to the raw (unrelocated) bytes of this Atom's
+ /// content.
+ virtual ArrayRef<uint8_t> rawContent() const = 0;
+
+ /// This class abstracts iterating over the sequence of References
+ /// in an Atom. Concrete instances of DefinedAtom must implement
+ /// the derefIterator() and incrementIterator() methods.
+ class reference_iterator {
+ public:
+ reference_iterator(const DefinedAtom &a, const void *it)
+ : _atom(a), _it(it) { }
+
+ const Reference *operator*() const {
+ return _atom.derefIterator(_it);
+ }
+
+ const Reference *operator->() const {
+ return _atom.derefIterator(_it);
+ }
+
+ bool operator==(const reference_iterator &other) const {
+ return _it == other._it;
+ }
+
+ bool operator!=(const reference_iterator &other) const {
+ return !(*this == other);
+ }
+
+ reference_iterator &operator++() {
+ _atom.incrementIterator(_it);
+ return *this;
+ }
+ private:
+ const DefinedAtom &_atom;
+ const void *_it;
+ };
+
+ /// Returns an iterator to the beginning of this Atom's References.
+ virtual reference_iterator begin() const = 0;
+
+ /// Returns an iterator to the end of this Atom's References.
+ virtual reference_iterator end() const = 0;
+
+ /// Adds a reference to this atom.
+ virtual void addReference(Reference::KindNamespace ns,
+ Reference::KindArch arch,
+ Reference::KindValue kindValue, uint64_t off,
+ const Atom *target, Reference::Addend a) {
+ llvm_unreachable("Subclass does not permit adding references");
+ }
+
+ static bool classof(const Atom *a) {
+ return a->definition() == definitionRegular;
+ }
+
+ /// Utility for deriving permissions from content type
+ static ContentPermissions permissions(ContentType type);
+
+ /// Utility function to check if the atom occupies file space
+ bool occupiesDiskSpace() const {
+ ContentType atomContentType = contentType();
+ return !(atomContentType == DefinedAtom::typeZeroFill ||
+ atomContentType == DefinedAtom::typeZeroFillFast ||
+ atomContentType == DefinedAtom::typeTLVInitialZeroFill);
+ }
+
+ /// Utility function to check if relocations in this atom to other defined
+ /// atoms can be implicitly generated, and so we don't need to explicitly
+ /// emit those relocations.
+ bool relocsToDefinedCanBeImplicit() const {
+ ContentType atomContentType = contentType();
+ return atomContentType == typeCFI;
+ }
+
+protected:
+ // DefinedAtom is an abstract base class. Only subclasses can access
+ // constructor.
+ DefinedAtom() : Atom(definitionRegular) { }
+
+ ~DefinedAtom() override = default;
+
+ /// Returns a pointer to the Reference object that the abstract
+ /// iterator "points" to.
+ virtual const Reference *derefIterator(const void *iter) const = 0;
+
+ /// Adjusts the abstract iterator to "point" to the next Reference
+ /// object for this Atom.
+ virtual void incrementIterator(const void *&iter) const = 0;
+};
+} // end namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/include/lld/Core/Error.h b/contrib/llvm/tools/lld/include/lld/Core/Error.h
new file mode 100644
index 000000000000..36a36724987a
--- /dev/null
+++ b/contrib/llvm/tools/lld/include/lld/Core/Error.h
@@ -0,0 +1,68 @@
+//===- Error.h - system_error extensions for lld ----------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This declares a new error_category for the lld library.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_ERROR_H
+#define LLD_CORE_ERROR_H
+
+#include "lld/Common/LLVM.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/Error.h"
+#include <system_error>
+
+namespace lld {
+
+const std::error_category &YamlReaderCategory();
+
+enum class YamlReaderError {
+ unknown_keyword,
+ illegal_value
+};
+
+inline std::error_code make_error_code(YamlReaderError e) {
+ return std::error_code(static_cast<int>(e), YamlReaderCategory());
+}
+
+/// Creates an error_code object that has associated with it an arbitrary
+/// error messsage. The value() of the error_code will always be non-zero
+/// but its value is meaningless. The messsage() will be (a copy of) the
+/// supplied error string.
+/// Note: Once ErrorOr<> is updated to work with errors other than error_code,
+/// this can be updated to return some other kind of error.
+std::error_code make_dynamic_error_code(StringRef msg);
+
+/// Generic error.
+///
+/// For errors that don't require their own specific sub-error (most errors)
+/// this class can be used to describe the error via a string message.
+class GenericError : public llvm::ErrorInfo<GenericError> {
+public:
+ static char ID;
+ GenericError(Twine Msg);
+ const std::string &getMessage() const { return Msg; }
+ void log(llvm::raw_ostream &OS) const override;
+
+ std::error_code convertToErrorCode() const override {
+ return make_dynamic_error_code(getMessage());
+ }
+
+private:
+ std::string Msg;
+};
+
+} // end namespace lld
+
+namespace std {
+template <> struct is_error_code_enum<lld::YamlReaderError> : std::true_type {};
+}
+
+#endif
diff --git a/contrib/llvm/tools/lld/include/lld/Core/File.h b/contrib/llvm/tools/lld/include/lld/Core/File.h
new file mode 100644
index 000000000000..54f533576a4b
--- /dev/null
+++ b/contrib/llvm/tools/lld/include/lld/Core/File.h
@@ -0,0 +1,276 @@
+//===- Core/File.h - A Container of Atoms ---------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_FILE_H
+#define LLD_CORE_FILE_H
+
+#include "lld/Core/AbsoluteAtom.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/SharedLibraryAtom.h"
+#include "lld/Core/UndefinedAtom.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <functional>
+#include <memory>
+#include <mutex>
+#include <vector>
+
+namespace lld {
+
+class LinkingContext;
+
+/// Every Atom is owned by some File. A common scenario is for a single
+/// object file (.o) to be parsed by some reader and produce a single
+/// File object that represents the content of that object file.
+///
+/// To iterate through the Atoms in a File there are four methods that
+/// return collections. For instance to iterate through all the DefinedAtoms
+/// in a File object use:
+/// for (const DefinedAtoms *atom : file->defined()) {
+/// }
+///
+/// The Atom objects in a File are owned by the File object. The Atom objects
+/// are destroyed when the File object is destroyed.
+class File {
+public:
+ virtual ~File();
+
+ /// Kinds of files that are supported.
+ enum Kind {
+ kindErrorObject, ///< a error object file (.o)
+ kindNormalizedObject, ///< a normalized file (.o)
+ kindMachObject, ///< a MachO object file (.o)
+ kindCEntryObject, ///< a file for CEntries
+ kindHeaderObject, ///< a file for file headers
+ kindEntryObject, ///< a file for the entry
+ kindUndefinedSymsObject, ///< a file for undefined symbols
+ kindStubHelperObject, ///< a file for stub helpers
+ kindResolverMergedObject, ///< the resolver merged file.
+ kindSectCreateObject, ///< a sect create object file (.o)
+ kindSharedLibrary, ///< shared library (.so)
+ kindArchiveLibrary ///< archive (.a)
+ };
+
+ /// Returns file kind. Need for dyn_cast<> on File objects.
+ Kind kind() const {
+ return _kind;
+ }
+
+ /// This returns the path to the file which was used to create this object
+ /// (e.g. "/tmp/foo.o"). If the file is a member of an archive file, the
+ /// returned string includes the archive file name.
+ StringRef path() const {
+ if (_archivePath.empty())
+ return _path;
+ if (_archiveMemberPath.empty())
+ _archiveMemberPath = (_archivePath + "(" + _path + ")").str();
+ return _archiveMemberPath;
+ }
+
+ /// Returns the path of the archive file name if this file is instantiated
+ /// from an archive file. Otherwise returns the empty string.
+ StringRef archivePath() const { return _archivePath; }
+ void setArchivePath(StringRef path) { _archivePath = path; }
+
+ /// Returns the path name of this file. It doesn't include archive file name.
+ StringRef memberPath() const { return _path; }
+
+ /// Returns the command line order of the file.
+ uint64_t ordinal() const {
+ assert(_ordinal != UINT64_MAX);
+ return _ordinal;
+ }
+
+ /// Returns true/false depending on whether an ordinal has been set.
+ bool hasOrdinal() const { return (_ordinal != UINT64_MAX); }
+
+ /// Sets the command line order of the file.
+ void setOrdinal(uint64_t ordinal) const { _ordinal = ordinal; }
+
+ /// Returns the ordinal for the next atom to be defined in this file.
+ uint64_t getNextAtomOrdinalAndIncrement() const {
+ return _nextAtomOrdinal++;
+ }
+
+ /// For allocating any objects owned by this File.
+ llvm::BumpPtrAllocator &allocator() const {
+ return _allocator;
+ }
+
+ /// The type of atom mutable container.
+ template <typename T> using AtomVector = std::vector<OwningAtomPtr<T>>;
+
+ /// The range type for the atoms.
+ template <typename T> class AtomRange {
+ public:
+ AtomRange(AtomVector<T> &v) : _v(v) {}
+ AtomRange(const AtomVector<T> &v) : _v(const_cast<AtomVector<T> &>(v)) {}
+
+ using ConstDerefFn = const T* (*)(const OwningAtomPtr<T>&);
+ using DerefFn = T* (*)(OwningAtomPtr<T>&);
+
+ typedef llvm::mapped_iterator<typename AtomVector<T>::const_iterator,
+ ConstDerefFn> ConstItTy;
+ typedef llvm::mapped_iterator<typename AtomVector<T>::iterator,
+ DerefFn> ItTy;
+
+ static const T* DerefConst(const OwningAtomPtr<T> &p) {
+ return p.get();
+ }
+
+ static T* Deref(OwningAtomPtr<T> &p) {
+ return p.get();
+ }
+
+ ConstItTy begin() const {
+ return ConstItTy(_v.begin(), ConstDerefFn(DerefConst));
+ }
+ ConstItTy end() const {
+ return ConstItTy(_v.end(), ConstDerefFn(DerefConst));
+ }
+
+ ItTy begin() {
+ return ItTy(_v.begin(), DerefFn(Deref));
+ }
+ ItTy end() {
+ return ItTy(_v.end(), DerefFn(Deref));
+ }
+
+ llvm::iterator_range<typename AtomVector<T>::iterator> owning_ptrs() {
+ return llvm::make_range(_v.begin(), _v.end());
+ }
+
+ llvm::iterator_range<typename AtomVector<T>::iterator> owning_ptrs() const {
+ return llvm::make_range(_v.begin(), _v.end());
+ }
+
+ bool empty() const {
+ return _v.empty();
+ }
+
+ size_t size() const {
+ return _v.size();
+ }
+
+ const OwningAtomPtr<T> &operator[](size_t idx) const {
+ return _v[idx];
+ }
+
+ OwningAtomPtr<T> &operator[](size_t idx) {
+ return _v[idx];
+ }
+
+ private:
+ AtomVector<T> &_v;
+ };
+
+ /// Must be implemented to return the AtomVector object for
+ /// all DefinedAtoms in this File.
+ virtual const AtomRange<DefinedAtom> defined() const = 0;
+
+ /// Must be implemented to return the AtomVector object for
+ /// all UndefinedAtomw in this File.
+ virtual const AtomRange<UndefinedAtom> undefined() const = 0;
+
+ /// Must be implemented to return the AtomVector object for
+ /// all SharedLibraryAtoms in this File.
+ virtual const AtomRange<SharedLibraryAtom> sharedLibrary() const = 0;
+
+ /// Must be implemented to return the AtomVector object for
+ /// all AbsoluteAtoms in this File.
+ virtual const AtomRange<AbsoluteAtom> absolute() const = 0;
+
+ /// Drop all of the atoms owned by this file. This will result in all of
+ /// the atoms running their destructors.
+ /// This is required because atoms may be allocated on a BumpPtrAllocator
+ /// of a different file. We need to destruct all atoms before any files.
+ virtual void clearAtoms() = 0;
+
+ /// If a file is parsed using a different method than doParse(),
+ /// one must use this method to set the last error status, so that
+ /// doParse will not be called twice. Only YAML reader uses this
+ /// (because YAML reader does not read blobs but structured data).
+ void setLastError(std::error_code err) { _lastError = err; }
+
+ std::error_code parse();
+
+ // Usually each file owns a std::unique_ptr<MemoryBuffer>.
+ // However, there's one special case. If a file is an archive file,
+ // the archive file and its children all shares the same memory buffer.
+ // This method is used by the ArchiveFile to give its children
+ // co-ownership of the buffer.
+ void setSharedMemoryBuffer(std::shared_ptr<MemoryBuffer> mb) {
+ _sharedMemoryBuffer = mb;
+ }
+
+protected:
+ /// only subclasses of File can be instantiated
+ File(StringRef p, Kind kind)
+ : _path(p), _kind(kind), _ordinal(UINT64_MAX),
+ _nextAtomOrdinal(0) {}
+
+ /// Subclasses should override this method to parse the
+ /// memory buffer passed to this file's constructor.
+ virtual std::error_code doParse() { return std::error_code(); }
+
+ static AtomVector<DefinedAtom> _noDefinedAtoms;
+ static AtomVector<UndefinedAtom> _noUndefinedAtoms;
+ static AtomVector<SharedLibraryAtom> _noSharedLibraryAtoms;
+ static AtomVector<AbsoluteAtom> _noAbsoluteAtoms;
+ mutable llvm::BumpPtrAllocator _allocator;
+
+private:
+ StringRef _path;
+ std::string _archivePath;
+ mutable std::string _archiveMemberPath;
+ Kind _kind;
+ mutable uint64_t _ordinal;
+ mutable uint64_t _nextAtomOrdinal;
+ std::shared_ptr<MemoryBuffer> _sharedMemoryBuffer;
+ llvm::Optional<std::error_code> _lastError;
+ std::mutex _parseMutex;
+};
+
+/// An ErrorFile represents a file that doesn't exist.
+/// If you try to parse a file which doesn't exist, an instance of this
+/// class will be returned. That's parse method always returns an error.
+/// This is useful to delay erroring on non-existent files, so that we
+/// can do unit testing a driver using non-existing file paths.
+class ErrorFile : public File {
+public:
+ ErrorFile(StringRef path, std::error_code ec)
+ : File(path, kindErrorObject), _ec(ec) {}
+
+ std::error_code doParse() override { return _ec; }
+
+ const AtomRange<DefinedAtom> defined() const override {
+ llvm_unreachable("internal error");
+ }
+ const AtomRange<UndefinedAtom> undefined() const override {
+ llvm_unreachable("internal error");
+ }
+ const AtomRange<SharedLibraryAtom> sharedLibrary() const override {
+ llvm_unreachable("internal error");
+ }
+ const AtomRange<AbsoluteAtom> absolute() const override {
+ llvm_unreachable("internal error");
+ }
+
+ void clearAtoms() override {
+ }
+
+private:
+ std::error_code _ec;
+};
+
+} // end namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/include/lld/Core/Instrumentation.h b/contrib/llvm/tools/lld/include/lld/Core/Instrumentation.h
new file mode 100644
index 000000000000..939d64557587
--- /dev/null
+++ b/contrib/llvm/tools/lld/include/lld/Core/Instrumentation.h
@@ -0,0 +1,132 @@
+//===- include/Core/Instrumentation.h - Instrumentation API ---------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Provide an Instrumentation API that optionally uses VTune interfaces.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_INSTRUMENTATION_H
+#define LLD_CORE_INSTRUMENTATION_H
+
+#include "llvm/Support/Compiler.h"
+#include <utility>
+
+#ifdef LLD_HAS_VTUNE
+# include <ittnotify.h>
+#endif
+
+namespace lld {
+#ifdef LLD_HAS_VTUNE
+/// A unique global scope for instrumentation data.
+///
+/// Domains last for the lifetime of the application and cannot be destroyed.
+/// Multiple Domains created with the same name represent the same domain.
+class Domain {
+ __itt_domain *_domain;
+
+public:
+ explicit Domain(const char *name) : _domain(__itt_domain_createA(name)) {}
+
+ operator __itt_domain *() const { return _domain; }
+ __itt_domain *operator->() const { return _domain; }
+};
+
+/// A global reference to a string constant.
+///
+/// These are uniqued by the ITT runtime and cannot be deleted. They are not
+/// specific to a domain.
+///
+/// Prefer reusing a single StringHandle over passing a ntbs when the same
+/// string will be used often.
+class StringHandle {
+ __itt_string_handle *_handle;
+
+public:
+ StringHandle(const char *name) : _handle(__itt_string_handle_createA(name)) {}
+
+ operator __itt_string_handle *() const { return _handle; }
+};
+
+/// A task on a single thread. Nests within other tasks.
+///
+/// Each thread has its own task stack and tasks nest recursively on that stack.
+/// A task cannot transfer threads.
+///
+/// SBRM is used to ensure task starts and ends are ballanced. The lifetime of
+/// a task is either the lifetime of this object, or until end is called.
+class ScopedTask {
+ __itt_domain *_domain;
+
+ ScopedTask(const ScopedTask &) = delete;
+ ScopedTask &operator=(const ScopedTask &) = delete;
+
+public:
+ /// Create a task in Domain \p d named \p s.
+ ScopedTask(const Domain &d, const StringHandle &s) : _domain(d) {
+ __itt_task_begin(d, __itt_null, __itt_null, s);
+ }
+
+ ScopedTask(ScopedTask &&other) {
+ *this = std::move(other);
+ }
+
+ ScopedTask &operator=(ScopedTask &&other) {
+ _domain = other._domain;
+ other._domain = nullptr;
+ return *this;
+ }
+
+ /// Prematurely end this task.
+ void end() {
+ if (_domain)
+ __itt_task_end(_domain);
+ _domain = nullptr;
+ }
+
+ ~ScopedTask() { end(); }
+};
+
+/// A specific point in time. Allows metadata to be associated.
+class Marker {
+public:
+ Marker(const Domain &d, const StringHandle &s) {
+ __itt_marker(d, __itt_null, s, __itt_scope_global);
+ }
+};
+#else
+class Domain {
+public:
+ Domain(const char *name) {}
+};
+
+class StringHandle {
+public:
+ StringHandle(const char *name) {}
+};
+
+class ScopedTask {
+public:
+ ScopedTask(const Domain &d, const StringHandle &s) {}
+ void end() {}
+};
+
+class Marker {
+public:
+ Marker(const Domain &d, const StringHandle &s) {}
+};
+#endif
+
+inline const Domain &getDefaultDomain() {
+ static Domain domain("org.llvm.lld");
+ return domain;
+}
+} // end namespace lld.
+
+#endif
diff --git a/contrib/llvm/tools/lld/include/lld/Core/LinkingContext.h b/contrib/llvm/tools/lld/include/lld/Core/LinkingContext.h
new file mode 100644
index 000000000000..52ab1a2480e8
--- /dev/null
+++ b/contrib/llvm/tools/lld/include/lld/Core/LinkingContext.h
@@ -0,0 +1,257 @@
+//===- lld/Core/LinkingContext.h - Linker Target Info Interface -*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_LINKING_CONTEXT_H
+#define LLD_CORE_LINKING_CONTEXT_H
+
+#include "lld/Core/Node.h"
+#include "lld/Core/Reader.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Error.h"
+#include <cassert>
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace lld {
+
+class PassManager;
+class File;
+class Writer;
+class Node;
+class SharedLibraryFile;
+
+/// The LinkingContext class encapsulates "what and how" to link.
+///
+/// The base class LinkingContext contains the options needed by core linking.
+/// Subclasses of LinkingContext have additional options needed by specific
+/// Writers.
+class LinkingContext {
+public:
+ virtual ~LinkingContext();
+
+ /// \name Methods needed by core linking
+ /// @{
+
+ /// Name of symbol linker should use as "entry point" to program,
+ /// usually "main" or "start".
+ virtual StringRef entrySymbolName() const { return _entrySymbolName; }
+
+ /// Whether core linking should remove Atoms not reachable by following
+ /// References from the entry point Atom or from all global scope Atoms
+ /// if globalsAreDeadStripRoots() is true.
+ bool deadStrip() const { return _deadStrip; }
+
+ /// Only used if deadStrip() returns true. Means all global scope Atoms
+ /// should be marked live (along with all Atoms they reference). Usually
+ /// this method returns false for main executables, but true for dynamic
+ /// shared libraries.
+ bool globalsAreDeadStripRoots() const { return _globalsAreDeadStripRoots; }
+
+ /// Only used if deadStrip() returns true. This method returns the names
+ /// of DefinedAtoms that should be marked live (along with all Atoms they
+ /// reference). Only Atoms with scope scopeLinkageUnit or scopeGlobal can
+ /// be kept live using this method.
+ ArrayRef<StringRef> deadStripRoots() const {
+ return _deadStripRoots;
+ }
+
+ /// Add the given symbol name to the dead strip root set. Only used if
+ /// deadStrip() returns true.
+ void addDeadStripRoot(StringRef symbolName) {
+ assert(!symbolName.empty() && "Empty symbol cannot be a dead strip root");
+ _deadStripRoots.push_back(symbolName);
+ }
+
+ /// Normally, every UndefinedAtom must be replaced by a DefinedAtom or a
+ /// SharedLibraryAtom for the link to be successful. This method controls
+ /// whether core linking prints out a list of remaining UndefinedAtoms.
+ ///
+ /// \todo This should be a method core linking calls with a list of the
+ /// UndefinedAtoms so that different drivers can format the error message
+ /// as needed.
+ bool printRemainingUndefines() const { return _printRemainingUndefines; }
+
+ /// Normally, every UndefinedAtom must be replaced by a DefinedAtom or a
+ /// SharedLibraryAtom for the link to be successful. This method controls
+ /// whether core linking considers remaining undefines to be an error.
+ bool allowRemainingUndefines() const { return _allowRemainingUndefines; }
+
+ /// Normally, every UndefinedAtom must be replaced by a DefinedAtom or a
+ /// SharedLibraryAtom for the link to be successful. This method controls
+ /// whether core linking considers remaining undefines from the shared library
+ /// to be an error.
+ bool allowShlibUndefines() const { return _allowShlibUndefines; }
+
+ /// If true, core linking will write the path to each input file to stdout
+ /// (i.e. llvm::outs()) as it is used. This is used to implement the -t
+ /// linker option.
+ ///
+ /// \todo This should be a method core linking calls so that drivers can
+ /// format the line as needed.
+ bool logInputFiles() const { return _logInputFiles; }
+
+ /// Parts of LLVM use global variables which are bound to command line
+ /// options (see llvm::cl::Options). This method returns "command line"
+ /// options which are used to configure LLVM's command line settings.
+ /// For instance the -debug-only XXX option can be used to dynamically
+ /// trace different parts of LLVM and lld.
+ ArrayRef<const char *> llvmOptions() const { return _llvmOptions; }
+
+ /// \name Methods used by Drivers to configure TargetInfo
+ /// @{
+ void setOutputPath(StringRef str) { _outputPath = str; }
+
+ // Set the entry symbol name. You may also need to call addDeadStripRoot() for
+ // the symbol if your platform supports dead-stripping, so that the symbol
+ // will not be removed from the output.
+ void setEntrySymbolName(StringRef name) {
+ _entrySymbolName = name;
+ }
+
+ void setDeadStripping(bool enable) { _deadStrip = enable; }
+ void setGlobalsAreDeadStripRoots(bool v) { _globalsAreDeadStripRoots = v; }
+
+ void setPrintRemainingUndefines(bool print) {
+ _printRemainingUndefines = print;
+ }
+
+ void setAllowRemainingUndefines(bool allow) {
+ _allowRemainingUndefines = allow;
+ }
+
+ void setAllowShlibUndefines(bool allow) { _allowShlibUndefines = allow; }
+ void setLogInputFiles(bool log) { _logInputFiles = log; }
+
+ void appendLLVMOption(const char *opt) { _llvmOptions.push_back(opt); }
+
+ std::vector<std::unique_ptr<Node>> &getNodes() { return _nodes; }
+ const std::vector<std::unique_ptr<Node>> &getNodes() const { return _nodes; }
+
+ /// This method adds undefined symbols specified by the -u option to the to
+ /// the list of undefined symbols known to the linker. This option essentially
+ /// forces an undefined symbol to be created. You may also need to call
+ /// addDeadStripRoot() for the symbol if your platform supports dead
+ /// stripping, so that the symbol will not be removed from the output.
+ void addInitialUndefinedSymbol(StringRef symbolName) {
+ _initialUndefinedSymbols.push_back(symbolName);
+ }
+
+ /// Iterators for symbols that appear on the command line.
+ typedef std::vector<StringRef> StringRefVector;
+ typedef StringRefVector::iterator StringRefVectorIter;
+ typedef StringRefVector::const_iterator StringRefVectorConstIter;
+
+ /// Create linker internal files containing atoms for the linker to include
+ /// during link. Flavors can override this function in their LinkingContext
+ /// to add more internal files. These internal files are positioned before
+ /// the actual input files.
+ virtual void createInternalFiles(std::vector<std::unique_ptr<File>> &) const;
+
+ /// Return the list of undefined symbols that are specified in the
+ /// linker command line, using the -u option.
+ ArrayRef<StringRef> initialUndefinedSymbols() const {
+ return _initialUndefinedSymbols;
+ }
+
+ /// After all set* methods are called, the Driver calls this method
+ /// to validate that there are no missing options or invalid combinations
+ /// of options. If there is a problem, a description of the problem
+ /// is written to the global error handler.
+ ///
+ /// \returns true if there is an error with the current settings.
+ bool validate();
+
+ /// Formats symbol name for use in error messages.
+ virtual std::string demangle(StringRef symbolName) const = 0;
+
+ /// @}
+ /// \name Methods used by Driver::link()
+ /// @{
+
+ /// Returns the file system path to which the linked output should be written.
+ ///
+ /// \todo To support in-memory linking, we need an abstraction that allows
+ /// the linker to write to an in-memory buffer.
+ StringRef outputPath() const { return _outputPath; }
+
+ /// Accessor for Register object embedded in LinkingContext.
+ const Registry &registry() const { return _registry; }
+ Registry &registry() { return _registry; }
+
+ /// This method is called by core linking to give the Writer a chance
+ /// to add file format specific "files" to set of files to be linked. This is
+ /// how file format specific atoms can be added to the link.
+ virtual void createImplicitFiles(std::vector<std::unique_ptr<File>> &) = 0;
+
+ /// This method is called by core linking to build the list of Passes to be
+ /// run on the merged/linked graph of all input files.
+ virtual void addPasses(PassManager &pm) = 0;
+
+ /// Calls through to the writeFile() method on the specified Writer.
+ ///
+ /// \param linkedFile This is the merged/linked graph of all input file Atoms.
+ virtual llvm::Error writeFile(const File &linkedFile) const;
+
+ /// Return the next ordinal and Increment it.
+ virtual uint64_t getNextOrdinalAndIncrement() const { return _nextOrdinal++; }
+
+ // This function is called just before the Resolver kicks in.
+ // Derived classes may use it to change the list of input files.
+ virtual void finalizeInputFiles() = 0;
+
+ /// Callback invoked for each file the Resolver decides we are going to load.
+ /// This can be used to update context state based on the file, and emit
+ /// errors for any differences between the context state and a loaded file.
+ /// For example, we can error if we try to load a file which is a different
+ /// arch from that being linked.
+ virtual llvm::Error handleLoadedFile(File &file) = 0;
+
+ /// @}
+protected:
+ LinkingContext(); // Must be subclassed
+
+ /// Abstract method to lazily instantiate the Writer.
+ virtual Writer &writer() const = 0;
+
+ /// Method to create an internal file for the entry symbol
+ virtual std::unique_ptr<File> createEntrySymbolFile() const;
+ std::unique_ptr<File> createEntrySymbolFile(StringRef filename) const;
+
+ /// Method to create an internal file for an undefined symbol
+ virtual std::unique_ptr<File> createUndefinedSymbolFile() const;
+ std::unique_ptr<File> createUndefinedSymbolFile(StringRef filename) const;
+
+ StringRef _outputPath;
+ StringRef _entrySymbolName;
+ bool _deadStrip = false;
+ bool _globalsAreDeadStripRoots = false;
+ bool _printRemainingUndefines = true;
+ bool _allowRemainingUndefines = false;
+ bool _logInputFiles = false;
+ bool _allowShlibUndefines = false;
+ std::vector<StringRef> _deadStripRoots;
+ std::vector<const char *> _llvmOptions;
+ StringRefVector _initialUndefinedSymbols;
+ std::vector<std::unique_ptr<Node>> _nodes;
+ mutable llvm::BumpPtrAllocator _allocator;
+ mutable uint64_t _nextOrdinal = 0;
+ Registry _registry;
+
+private:
+ /// Validate the subclass bits. Only called by validate.
+ virtual bool validateImpl() = 0;
+};
+
+} // end namespace lld
+
+#endif // LLD_CORE_LINKING_CONTEXT_H
diff --git a/contrib/llvm/tools/lld/include/lld/Core/Node.h b/contrib/llvm/tools/lld/include/lld/Core/Node.h
new file mode 100644
index 000000000000..c30482409e7a
--- /dev/null
+++ b/contrib/llvm/tools/lld/include/lld/Core/Node.h
@@ -0,0 +1,75 @@
+//===- lld/Core/Node.h - Input file class -----------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+///
+/// The classes in this file represents inputs to the linker.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_NODE_H
+#define LLD_CORE_NODE_H
+
+#include "lld/Core/File.h"
+#include <algorithm>
+#include <memory>
+
+namespace lld {
+
+// A Node represents a FileNode or other type of Node. In the latter case,
+// the node contains meta information about the input file list.
+// Currently only GroupEnd node is defined as a meta node.
+class Node {
+public:
+ enum class Kind { File, GroupEnd };
+
+ explicit Node(Kind type) : _kind(type) {}
+ virtual ~Node() = default;
+
+ virtual Kind kind() const { return _kind; }
+
+private:
+ Kind _kind;
+};
+
+// This is a marker for --end-group. getSize() returns the number of
+// files between the corresponding --start-group and this marker.
+class GroupEnd : public Node {
+public:
+ explicit GroupEnd(int size) : Node(Kind::GroupEnd), _size(size) {}
+
+ int getSize() const { return _size; }
+
+ static bool classof(const Node *a) {
+ return a->kind() == Kind::GroupEnd;
+ }
+
+private:
+ int _size;
+};
+
+// A container of File.
+class FileNode : public Node {
+public:
+ explicit FileNode(std::unique_ptr<File> f)
+ : Node(Node::Kind::File), _file(std::move(f)) {}
+
+ static bool classof(const Node *a) {
+ return a->kind() == Node::Kind::File;
+ }
+
+ File *getFile() { return _file.get(); }
+
+protected:
+ std::unique_ptr<File> _file;
+};
+
+} // end namespace lld
+
+#endif // LLD_CORE_NODE_H
diff --git a/contrib/llvm/tools/lld/include/lld/Core/Pass.h b/contrib/llvm/tools/lld/include/lld/Core/Pass.h
new file mode 100644
index 000000000000..bfe3f9b10e0c
--- /dev/null
+++ b/contrib/llvm/tools/lld/include/lld/Core/Pass.h
@@ -0,0 +1,43 @@
+//===------ Core/Pass.h - Base class for linker passes ----------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_PASS_H
+#define LLD_CORE_PASS_H
+
+#include "llvm/Support/Error.h"
+
+namespace lld {
+
+class SimpleFile;
+
+/// Once the core linking is done (which resolves references, coalesces atoms
+/// and produces a complete Atom graph), the linker runs a series of passes
+/// on the Atom graph. The graph is modeled as a File, which means the pass
+/// has access to all the atoms and to File level attributes. Each pass does
+/// a particular transformation to the Atom graph or to the File attributes.
+///
+/// This is the abstract base class for all passes. A Pass does its
+/// actual work in it perform() method. It can iterator over Atoms in the
+/// graph using the *begin()/*end() atom iterator of the File. It can add
+/// new Atoms to the graph using the File's addAtom() method.
+class Pass {
+public:
+ virtual ~Pass() = default;
+
+ /// Do the actual work of the Pass.
+ virtual llvm::Error perform(SimpleFile &mergedFile) = 0;
+
+protected:
+ // Only subclassess can be instantiated.
+ Pass() = default;
+};
+
+} // end namespace lld
+
+#endif // LLD_CORE_PASS_H
diff --git a/contrib/llvm/tools/lld/include/lld/Core/PassManager.h b/contrib/llvm/tools/lld/include/lld/Core/PassManager.h
new file mode 100644
index 000000000000..f2ef10f406f2
--- /dev/null
+++ b/contrib/llvm/tools/lld/include/lld/Core/PassManager.h
@@ -0,0 +1,48 @@
+//===- lld/Core/PassManager.h - Manage linker passes ----------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_PASS_MANAGER_H
+#define LLD_CORE_PASS_MANAGER_H
+
+#include "lld/Common/LLVM.h"
+#include "lld/Core/Pass.h"
+#include "llvm/Support/Error.h"
+#include <memory>
+#include <vector>
+
+namespace lld {
+class SimpleFile;
+class Pass;
+
+/// Owns and runs a collection of passes.
+///
+/// This class is currently just a container for passes and a way to run them.
+///
+/// In the future this should handle timing pass runs, running parallel passes,
+/// and validate/satisfy pass dependencies.
+class PassManager {
+public:
+ void add(std::unique_ptr<Pass> pass) {
+ _passes.push_back(std::move(pass));
+ }
+
+ llvm::Error runOnFile(SimpleFile &file) {
+ for (std::unique_ptr<Pass> &pass : _passes)
+ if (llvm::Error EC = pass->perform(file))
+ return EC;
+ return llvm::Error::success();
+ }
+
+private:
+ /// Passes in the order they should run.
+ std::vector<std::unique_ptr<Pass>> _passes;
+};
+} // end namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/include/lld/Core/Reader.h b/contrib/llvm/tools/lld/include/lld/Core/Reader.h
new file mode 100644
index 000000000000..6cf6282ff39c
--- /dev/null
+++ b/contrib/llvm/tools/lld/include/lld/Core/Reader.h
@@ -0,0 +1,155 @@
+//===- lld/Core/Reader.h - Abstract File Format Reading Interface ---------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_READER_H
+#define LLD_CORE_READER_H
+
+#include "lld/Common/LLVM.h"
+#include "lld/Core/Reference.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <memory>
+#include <vector>
+
+namespace llvm {
+namespace yaml {
+class IO;
+} // end namespace yaml
+} // end namespace llvm
+
+namespace lld {
+
+class File;
+class LinkingContext;
+class MachOLinkingContext;
+
+/// An abstract class for reading object files, library files, and
+/// executable files.
+///
+/// Each file format (e.g. mach-o, etc) has a concrete subclass of Reader.
+class Reader {
+public:
+ virtual ~Reader() = default;
+
+ /// Sniffs the file to determine if this Reader can parse it.
+ /// The method is called with:
+ /// 1) the file_magic enumeration returned by identify_magic()
+ /// 2) the whole file content buffer if the above is not enough.
+ virtual bool canParse(llvm::file_magic magic, MemoryBufferRef mb) const = 0;
+
+ /// Parse a supplied buffer (already filled with the contents of a
+ /// file) and create a File object.
+ /// The resulting File object takes ownership of the MemoryBuffer.
+ virtual ErrorOr<std::unique_ptr<File>>
+ loadFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &) const = 0;
+};
+
+/// An abstract class for handling alternate yaml representations
+/// of object files.
+///
+/// The YAML syntax allows "tags" which are used to specify the type of
+/// the YAML node. In lld, top level YAML documents can be in many YAML
+/// representations (e.g mach-o encoded as yaml, etc). A tag is used to
+/// specify which representation is used in the following YAML document.
+/// To work, there must be a YamlIOTaggedDocumentHandler registered that
+/// handles each tag type.
+class YamlIOTaggedDocumentHandler {
+public:
+ virtual ~YamlIOTaggedDocumentHandler();
+
+ /// This method is called on each registered YamlIOTaggedDocumentHandler
+ /// until one returns true. If the subclass handles tag type !xyz, then
+ /// this method should call io.mapTag("!xzy") to see if that is the current
+ /// document type, and if so, process the rest of the document using
+ /// YAML I/O, then convert the result into an lld::File* and return it.
+ virtual bool handledDocTag(llvm::yaml::IO &io, const lld::File *&f) const = 0;
+};
+
+/// A registry to hold the list of currently registered Readers and
+/// tables which map Reference kind values to strings.
+/// The linker does not directly invoke Readers. Instead, it registers
+/// Readers based on it configuration and command line options, then calls
+/// the Registry object to parse files.
+class Registry {
+public:
+ Registry();
+
+ /// Walk the list of registered Readers and find one that can parse the
+ /// supplied file and parse it.
+ ErrorOr<std::unique_ptr<File>>
+ loadFile(std::unique_ptr<MemoryBuffer> mb) const;
+
+ /// Walk the list of registered kind tables to convert a Reference Kind
+ /// name to a value.
+ bool referenceKindFromString(StringRef inputStr, Reference::KindNamespace &ns,
+ Reference::KindArch &a,
+ Reference::KindValue &value) const;
+
+ /// Walk the list of registered kind tables to convert a Reference Kind
+ /// value to a string.
+ bool referenceKindToString(Reference::KindNamespace ns, Reference::KindArch a,
+ Reference::KindValue value, StringRef &) const;
+
+ /// Walk the list of registered tag handlers and have the one that handles
+ /// the current document type process the yaml into an lld::File*.
+ bool handleTaggedDoc(llvm::yaml::IO &io, const lld::File *&file) const;
+
+ // These methods are called to dynamically add support for various file
+ // formats. The methods are also implemented in the appropriate lib*.a
+ // library, so that the code for handling a format is only linked in, if this
+ // method is used. Any options that a Reader might need must be passed
+ // as parameters to the addSupport*() method.
+ void addSupportArchives(bool logLoading);
+ void addSupportYamlFiles();
+ void addSupportMachOObjects(MachOLinkingContext &);
+
+ /// To convert between kind values and names, the registry walks the list
+ /// of registered kind tables. Each table is a zero terminated array of
+ /// KindStrings elements.
+ struct KindStrings {
+ Reference::KindValue value;
+ StringRef name;
+ };
+
+ /// A Reference Kind value is a tuple of <namespace, arch, value>. All
+ /// entries in a conversion table have the same <namespace, arch>. The
+ /// array then contains the value/name pairs.
+ void addKindTable(Reference::KindNamespace ns, Reference::KindArch arch,
+ const KindStrings array[]);
+
+private:
+ struct KindEntry {
+ Reference::KindNamespace ns;
+ Reference::KindArch arch;
+ const KindStrings *array;
+ };
+
+ void add(std::unique_ptr<Reader>);
+ void add(std::unique_ptr<YamlIOTaggedDocumentHandler>);
+
+ std::vector<std::unique_ptr<Reader>> _readers;
+ std::vector<std::unique_ptr<YamlIOTaggedDocumentHandler>> _yamlHandlers;
+ std::vector<KindEntry> _kindEntries;
+};
+
+// Utilities for building a KindString table. For instance:
+// static const Registry::KindStrings table[] = {
+// LLD_KIND_STRING_ENTRY(R_VAX_ADDR16),
+// LLD_KIND_STRING_ENTRY(R_VAX_DATA16),
+// LLD_KIND_STRING_END
+// };
+#define LLD_KIND_STRING_ENTRY(name) { name, #name }
+#define LLD_KIND_STRING_END { 0, "" }
+
+} // end namespace lld
+
+#endif // LLD_CORE_READER_H
diff --git a/contrib/llvm/tools/lld/include/lld/Core/Reference.h b/contrib/llvm/tools/lld/include/lld/Core/Reference.h
new file mode 100644
index 000000000000..1d3003c84616
--- /dev/null
+++ b/contrib/llvm/tools/lld/include/lld/Core/Reference.h
@@ -0,0 +1,119 @@
+//===- Core/References.h - A Reference to Another Atom ----------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_REFERENCES_H
+#define LLD_CORE_REFERENCES_H
+
+#include <cstdint>
+
+namespace lld {
+
+class Atom;
+
+///
+/// The linker has a Graph Theory model of linking. An object file is seen
+/// as a set of Atoms with References to other Atoms. Each Atom is a node
+/// and each Reference is an edge.
+///
+/// For example if a function contains a call site to "malloc" 40 bytes into
+/// the Atom, then the function Atom will have a Reference of: offsetInAtom=40,
+/// kind=callsite, target=malloc, addend=0.
+///
+/// Besides supporting traditional "relocations", references are also used
+/// forcing layout (one atom must follow another), marking data-in-code
+/// (jump tables or ARM constants), etc.
+///
+/// The "kind" of a reference is a tuple of <namespace, arch, value>. This
+/// enable us to re-use existing relocation types definded for various
+/// file formats and architectures.
+///
+/// References and atoms form a directed graph. The dead-stripping pass
+/// traverses them starting from dead-strip root atoms to garbage collect
+/// unreachable ones.
+///
+/// References of any kind are considered as directed edges. In addition to
+/// that, references of some kind is considered as bidirected edges.
+class Reference {
+public:
+ /// Which universe defines the kindValue().
+ enum class KindNamespace {
+ all = 0,
+ testing = 1,
+ mach_o = 2,
+ };
+
+ KindNamespace kindNamespace() const { return (KindNamespace)_kindNamespace; }
+ void setKindNamespace(KindNamespace ns) { _kindNamespace = (uint8_t)ns; }
+
+ // Which architecture the kind value is for.
+ enum class KindArch { all, AArch64, ARM, x86, x86_64};
+
+ KindArch kindArch() const { return (KindArch)_kindArch; }
+ void setKindArch(KindArch a) { _kindArch = (uint8_t)a; }
+
+ typedef uint16_t KindValue;
+
+ KindValue kindValue() const { return _kindValue; }
+
+ /// setKindValue() is needed because during linking, some optimizations may
+ /// change the codegen and hence the reference kind.
+ void setKindValue(KindValue value) {
+ _kindValue = value;
+ }
+
+ /// KindValues used with KindNamespace::all and KindArch::all.
+ enum {
+ // kindLayoutAfter is treated as a bidirected edge by the dead-stripping
+ // pass.
+ kindLayoutAfter = 1,
+ kindAssociate,
+ };
+
+ // A value to be added to the value of a target
+ typedef int64_t Addend;
+
+ /// If the reference is a fixup in the Atom, then this returns the
+ /// byte offset into the Atom's content to do the fix up.
+ virtual uint64_t offsetInAtom() const = 0;
+
+ /// Returns the atom this reference refers to.
+ virtual const Atom *target() const = 0;
+
+ /// During linking, the linker may merge graphs which coalesces some nodes
+ /// (i.e. Atoms). To switch the target of a reference, this method is called.
+ virtual void setTarget(const Atom *) = 0;
+
+ /// Some relocations require a symbol and a value (e.g. foo + 4).
+ virtual Addend addend() const = 0;
+
+ /// During linking, some optimzations may change addend value.
+ virtual void setAddend(Addend) = 0;
+
+ /// Returns target specific attributes of the reference.
+ virtual uint32_t tag() const { return 0; }
+
+protected:
+ /// Reference is an abstract base class. Only subclasses can use constructor.
+ Reference(KindNamespace ns, KindArch a, KindValue value)
+ : _kindValue(value), _kindNamespace((uint8_t)ns), _kindArch((uint8_t)a) {}
+
+ /// The memory for Reference objects is always managed by the owning File
+ /// object. Therefore, no one but the owning File object should call
+ /// delete on an Reference. In fact, some File objects may bulk allocate
+ /// an array of References, so they cannot be individually deleted by anyone.
+ virtual ~Reference() = default;
+
+ KindValue _kindValue;
+ uint8_t _kindNamespace;
+ uint8_t _kindArch;
+};
+
+} // end namespace lld
+
+#endif // LLD_CORE_REFERENCES_H
diff --git a/contrib/llvm/tools/lld/include/lld/Core/Resolver.h b/contrib/llvm/tools/lld/include/lld/Core/Resolver.h
new file mode 100644
index 000000000000..5157c9fddc1a
--- /dev/null
+++ b/contrib/llvm/tools/lld/include/lld/Core/Resolver.h
@@ -0,0 +1,106 @@
+//===- Core/Resolver.h - Resolves Atom References -------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_RESOLVER_H
+#define LLD_CORE_RESOLVER_H
+
+#include "lld/Core/ArchiveLibraryFile.h"
+#include "lld/Core/File.h"
+#include "lld/Core/SharedLibraryFile.h"
+#include "lld/Core/Simple.h"
+#include "lld/Core/SymbolTable.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/Support/ErrorOr.h"
+#include <set>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+namespace lld {
+
+class Atom;
+class LinkingContext;
+
+/// The Resolver is responsible for merging all input object files
+/// and producing a merged graph.
+class Resolver {
+public:
+ Resolver(LinkingContext &ctx) : _ctx(ctx), _result(new MergedFile()) {}
+
+ // InputFiles::Handler methods
+ void doDefinedAtom(OwningAtomPtr<DefinedAtom> atom);
+ bool doUndefinedAtom(OwningAtomPtr<UndefinedAtom> atom);
+ void doSharedLibraryAtom(OwningAtomPtr<SharedLibraryAtom> atom);
+ void doAbsoluteAtom(OwningAtomPtr<AbsoluteAtom> atom);
+
+ // Handle files, this adds atoms from the current file thats
+ // being processed by the resolver
+ llvm::Expected<bool> handleFile(File &);
+
+ // Handle an archive library file.
+ llvm::Expected<bool> handleArchiveFile(File &);
+
+ // Handle a shared library file.
+ llvm::Error handleSharedLibrary(File &);
+
+ /// do work of merging and resolving and return list
+ bool resolve();
+
+ std::unique_ptr<SimpleFile> resultFile() { return std::move(_result); }
+
+private:
+ typedef std::function<llvm::Expected<bool>(StringRef)> UndefCallback;
+
+ bool undefinesAdded(int begin, int end);
+ File *getFile(int &index);
+
+ /// The main function that iterates over the files to resolve
+ bool resolveUndefines();
+ void updateReferences();
+ void deadStripOptimize();
+ bool checkUndefines();
+ void removeCoalescedAwayAtoms();
+ llvm::Expected<bool> forEachUndefines(File &file, UndefCallback callback);
+
+ void markLive(const Atom *atom);
+
+ class MergedFile : public SimpleFile {
+ public:
+ MergedFile() : SimpleFile("<linker-internal>", kindResolverMergedObject) {}
+ void addAtoms(llvm::MutableArrayRef<OwningAtomPtr<Atom>> atoms);
+ };
+
+ LinkingContext &_ctx;
+ SymbolTable _symbolTable;
+ std::vector<OwningAtomPtr<Atom>> _atoms;
+ std::set<const Atom *> _deadStripRoots;
+ llvm::DenseSet<const Atom *> _liveAtoms;
+ llvm::DenseSet<const Atom *> _deadAtoms;
+ std::unique_ptr<MergedFile> _result;
+ std::unordered_multimap<const Atom *, const Atom *> _reverseRef;
+
+ // --start-group and --end-group
+ std::vector<File *> _files;
+ std::map<File *, bool> _newUndefinesAdded;
+
+ // List of undefined symbols.
+ std::vector<StringRef> _undefines;
+
+ // Start position in _undefines for each archive/shared library file.
+ // Symbols from index 0 to the start position are already searched before.
+ // Searching them again would never succeed. When we look for undefined
+ // symbols from an archive/shared library file, start from its start
+ // position to save time.
+ std::map<File *, size_t> _undefineIndex;
+};
+
+} // namespace lld
+
+#endif // LLD_CORE_RESOLVER_H
diff --git a/contrib/llvm/tools/lld/include/lld/Core/SharedLibraryAtom.h b/contrib/llvm/tools/lld/include/lld/Core/SharedLibraryAtom.h
new file mode 100644
index 000000000000..7fec7a3e3d29
--- /dev/null
+++ b/contrib/llvm/tools/lld/include/lld/Core/SharedLibraryAtom.h
@@ -0,0 +1,53 @@
+//===- Core/SharedLibraryAtom.h - A Shared Library Atom -------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_SHARED_LIBRARY_ATOM_H
+#define LLD_CORE_SHARED_LIBRARY_ATOM_H
+
+#include "lld/Core/Atom.h"
+
+namespace lld {
+
+/// A SharedLibraryAtom has no content.
+/// It exists to represent a symbol which will be bound at runtime.
+class SharedLibraryAtom : public Atom {
+public:
+ enum class Type : uint32_t {
+ Unknown,
+ Code,
+ Data,
+ };
+
+ /// Returns shared library name used to load it at runtime.
+ /// On Darwin it is the LC_DYLIB_LOAD dylib name.
+ virtual StringRef loadName() const = 0;
+
+ /// Returns if shared library symbol can be missing at runtime and if
+ /// so the loader should silently resolve address of symbol to be nullptr.
+ virtual bool canBeNullAtRuntime() const = 0;
+
+ virtual Type type() const = 0;
+
+ virtual uint64_t size() const = 0;
+
+ static bool classof(const Atom *a) {
+ return a->definition() == definitionSharedLibrary;
+ }
+
+ static inline bool classof(const SharedLibraryAtom *) { return true; }
+
+protected:
+ SharedLibraryAtom() : Atom(definitionSharedLibrary) {}
+
+ ~SharedLibraryAtom() override = default;
+};
+
+} // namespace lld
+
+#endif // LLD_CORE_SHARED_LIBRARY_ATOM_H
diff --git a/contrib/llvm/tools/lld/include/lld/Core/SharedLibraryFile.h b/contrib/llvm/tools/lld/include/lld/Core/SharedLibraryFile.h
new file mode 100644
index 000000000000..53bf967b0236
--- /dev/null
+++ b/contrib/llvm/tools/lld/include/lld/Core/SharedLibraryFile.h
@@ -0,0 +1,70 @@
+//===- Core/SharedLibraryFile.h - Models shared libraries as Atoms --------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_SHARED_LIBRARY_FILE_H
+#define LLD_CORE_SHARED_LIBRARY_FILE_H
+
+#include "lld/Core/File.h"
+
+namespace lld {
+
+///
+/// The SharedLibraryFile subclass of File is used to represent dynamic
+/// shared libraries being linked against.
+///
+class SharedLibraryFile : public File {
+public:
+ static bool classof(const File *f) {
+ return f->kind() == kindSharedLibrary;
+ }
+
+ /// Check if the shared library exports a symbol with the specified name.
+ /// If so, return a SharedLibraryAtom which represents that exported
+ /// symbol. Otherwise return nullptr.
+ virtual OwningAtomPtr<SharedLibraryAtom> exports(StringRef name) const = 0;
+
+ // Returns the install name.
+ virtual StringRef getDSOName() const = 0;
+
+ const AtomRange<DefinedAtom> defined() const override {
+ return _definedAtoms;
+ }
+
+ const AtomRange<UndefinedAtom> undefined() const override {
+ return _undefinedAtoms;
+ }
+
+ const AtomRange<SharedLibraryAtom> sharedLibrary() const override {
+ return _sharedLibraryAtoms;
+ }
+
+ const AtomRange<AbsoluteAtom> absolute() const override {
+ return _absoluteAtoms;
+ }
+
+ void clearAtoms() override {
+ _definedAtoms.clear();
+ _undefinedAtoms.clear();
+ _sharedLibraryAtoms.clear();
+ _absoluteAtoms.clear();
+ }
+
+protected:
+ /// only subclasses of SharedLibraryFile can be instantiated
+ explicit SharedLibraryFile(StringRef path) : File(path, kindSharedLibrary) {}
+
+ AtomVector<DefinedAtom> _definedAtoms;
+ AtomVector<UndefinedAtom> _undefinedAtoms;
+ AtomVector<SharedLibraryAtom> _sharedLibraryAtoms;
+ AtomVector<AbsoluteAtom> _absoluteAtoms;
+};
+
+} // namespace lld
+
+#endif // LLD_CORE_SHARED_LIBRARY_FILE_H
diff --git a/contrib/llvm/tools/lld/include/lld/Core/Simple.h b/contrib/llvm/tools/lld/include/lld/Core/Simple.h
new file mode 100644
index 000000000000..feeed6ae473b
--- /dev/null
+++ b/contrib/llvm/tools/lld/include/lld/Core/Simple.h
@@ -0,0 +1,271 @@
+//===- lld/Core/Simple.h - Simple implementations of Atom and File --------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Provide simple implementations for Atoms and File.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_SIMPLE_H
+#define LLD_CORE_SIMPLE_H
+
+#include "lld/Core/AbsoluteAtom.h"
+#include "lld/Core/Atom.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/SharedLibraryAtom.h"
+#include "lld/Core/UndefinedAtom.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/ilist.h"
+#include "llvm/ADT/ilist_node.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <functional>
+
+namespace lld {
+
+class SimpleFile : public File {
+public:
+ SimpleFile(StringRef path, File::Kind kind)
+ : File(path, kind) {}
+
+ ~SimpleFile() override {
+ _defined.clear();
+ _undefined.clear();
+ _shared.clear();
+ _absolute.clear();
+ }
+
+ void addAtom(DefinedAtom &a) {
+ _defined.push_back(OwningAtomPtr<DefinedAtom>(&a));
+ }
+ void addAtom(UndefinedAtom &a) {
+ _undefined.push_back(OwningAtomPtr<UndefinedAtom>(&a));
+ }
+ void addAtom(SharedLibraryAtom &a) {
+ _shared.push_back(OwningAtomPtr<SharedLibraryAtom>(&a));
+ }
+ void addAtom(AbsoluteAtom &a) {
+ _absolute.push_back(OwningAtomPtr<AbsoluteAtom>(&a));
+ }
+
+ void addAtom(const Atom &atom) {
+ if (auto *p = dyn_cast<DefinedAtom>(&atom)) {
+ addAtom(const_cast<DefinedAtom &>(*p));
+ } else if (auto *p = dyn_cast<UndefinedAtom>(&atom)) {
+ addAtom(const_cast<UndefinedAtom &>(*p));
+ } else if (auto *p = dyn_cast<SharedLibraryAtom>(&atom)) {
+ addAtom(const_cast<SharedLibraryAtom &>(*p));
+ } else if (auto *p = dyn_cast<AbsoluteAtom>(&atom)) {
+ addAtom(const_cast<AbsoluteAtom &>(*p));
+ } else {
+ llvm_unreachable("atom has unknown definition kind");
+ }
+ }
+
+ void removeDefinedAtomsIf(std::function<bool(const DefinedAtom *)> pred) {
+ auto &atoms = _defined;
+ auto newEnd = std::remove_if(atoms.begin(), atoms.end(),
+ [&pred](OwningAtomPtr<DefinedAtom> &p) {
+ return pred(p.get());
+ });
+ atoms.erase(newEnd, atoms.end());
+ }
+
+ const AtomRange<DefinedAtom> defined() const override { return _defined; }
+
+ const AtomRange<UndefinedAtom> undefined() const override {
+ return _undefined;
+ }
+
+ const AtomRange<SharedLibraryAtom> sharedLibrary() const override {
+ return _shared;
+ }
+
+ const AtomRange<AbsoluteAtom> absolute() const override {
+ return _absolute;
+ }
+
+ void clearAtoms() override {
+ _defined.clear();
+ _undefined.clear();
+ _shared.clear();
+ _absolute.clear();
+ }
+
+private:
+ AtomVector<DefinedAtom> _defined;
+ AtomVector<UndefinedAtom> _undefined;
+ AtomVector<SharedLibraryAtom> _shared;
+ AtomVector<AbsoluteAtom> _absolute;
+};
+
+class SimpleReference : public Reference,
+ public llvm::ilist_node<SimpleReference> {
+public:
+ SimpleReference(Reference::KindNamespace ns, Reference::KindArch arch,
+ Reference::KindValue value, uint64_t off, const Atom *t,
+ Reference::Addend a)
+ : Reference(ns, arch, value), _target(t), _offsetInAtom(off), _addend(a) {
+ }
+ SimpleReference()
+ : Reference(Reference::KindNamespace::all, Reference::KindArch::all, 0),
+ _target(nullptr), _offsetInAtom(0), _addend(0) {}
+
+ uint64_t offsetInAtom() const override { return _offsetInAtom; }
+
+ const Atom *target() const override {
+ assert(_target);
+ return _target;
+ }
+
+ Addend addend() const override { return _addend; }
+ void setAddend(Addend a) override { _addend = a; }
+ void setTarget(const Atom *newAtom) override { _target = newAtom; }
+
+private:
+ const Atom *_target;
+ uint64_t _offsetInAtom;
+ Addend _addend;
+};
+
+class SimpleDefinedAtom : public DefinedAtom {
+public:
+ explicit SimpleDefinedAtom(const File &f)
+ : _file(f), _ordinal(f.getNextAtomOrdinalAndIncrement()) {}
+
+ ~SimpleDefinedAtom() override {
+ _references.clearAndLeakNodesUnsafely();
+ }
+
+ const File &file() const override { return _file; }
+
+ StringRef name() const override { return StringRef(); }
+
+ uint64_t ordinal() const override { return _ordinal; }
+
+ Scope scope() const override { return DefinedAtom::scopeLinkageUnit; }
+
+ Interposable interposable() const override {
+ return DefinedAtom::interposeNo;
+ }
+
+ Merge merge() const override { return DefinedAtom::mergeNo; }
+
+ Alignment alignment() const override { return 1; }
+
+ SectionChoice sectionChoice() const override {
+ return DefinedAtom::sectionBasedOnContent;
+ }
+
+ StringRef customSectionName() const override { return StringRef(); }
+ DeadStripKind deadStrip() const override {
+ return DefinedAtom::deadStripNormal;
+ }
+
+ DefinedAtom::reference_iterator begin() const override {
+ const void *it =
+ reinterpret_cast<const void *>(_references.begin().getNodePtr());
+ return reference_iterator(*this, it);
+ }
+
+ DefinedAtom::reference_iterator end() const override {
+ const void *it =
+ reinterpret_cast<const void *>(_references.end().getNodePtr());
+ return reference_iterator(*this, it);
+ }
+
+ const Reference *derefIterator(const void *it) const override {
+ return &*RefList::const_iterator(
+ *reinterpret_cast<const llvm::ilist_node<SimpleReference> *>(it));
+ }
+
+ void incrementIterator(const void *&it) const override {
+ RefList::const_iterator ref(
+ *reinterpret_cast<const llvm::ilist_node<SimpleReference> *>(it));
+ it = reinterpret_cast<const void *>(std::next(ref).getNodePtr());
+ }
+
+ void addReference(Reference::KindNamespace ns,
+ Reference::KindArch arch,
+ Reference::KindValue kindValue, uint64_t off,
+ const Atom *target, Reference::Addend a) override {
+ assert(target && "trying to create reference to nothing");
+ auto node = new (_file.allocator())
+ SimpleReference(ns, arch, kindValue, off, target, a);
+ _references.push_back(node);
+ }
+
+ /// Sort references in a canonical order (by offset, then by kind).
+ void sortReferences() const {
+ // Cannot sort a linked list, so move elements into a temporary vector,
+ // sort the vector, then reconstruct the list.
+ llvm::SmallVector<SimpleReference *, 16> elements;
+ for (SimpleReference &node : _references) {
+ elements.push_back(&node);
+ }
+ std::sort(elements.begin(), elements.end(),
+ [] (const SimpleReference *lhs, const SimpleReference *rhs) -> bool {
+ uint64_t lhsOffset = lhs->offsetInAtom();
+ uint64_t rhsOffset = rhs->offsetInAtom();
+ if (rhsOffset != lhsOffset)
+ return (lhsOffset < rhsOffset);
+ if (rhs->kindNamespace() != lhs->kindNamespace())
+ return (lhs->kindNamespace() < rhs->kindNamespace());
+ if (rhs->kindArch() != lhs->kindArch())
+ return (lhs->kindArch() < rhs->kindArch());
+ return (lhs->kindValue() < rhs->kindValue());
+ });
+ _references.clearAndLeakNodesUnsafely();
+ for (SimpleReference *node : elements) {
+ _references.push_back(node);
+ }
+ }
+
+ void setOrdinal(uint64_t ord) { _ordinal = ord; }
+
+private:
+ typedef llvm::ilist<SimpleReference> RefList;
+
+ const File &_file;
+ uint64_t _ordinal;
+ mutable RefList _references;
+};
+
+class SimpleUndefinedAtom : public UndefinedAtom {
+public:
+ SimpleUndefinedAtom(const File &f, StringRef name) : _file(f), _name(name) {
+ assert(!name.empty() && "UndefinedAtoms must have a name");
+ }
+
+ ~SimpleUndefinedAtom() override = default;
+
+ /// file - returns the File that produced/owns this Atom
+ const File &file() const override { return _file; }
+
+ /// name - The name of the atom. For a function atom, it is the (mangled)
+ /// name of the function.
+ StringRef name() const override { return _name; }
+
+ CanBeNull canBeNull() const override { return UndefinedAtom::canBeNullNever; }
+
+private:
+ const File &_file;
+ StringRef _name;
+};
+
+} // end namespace lld
+
+#endif // LLD_CORE_SIMPLE_H
diff --git a/contrib/llvm/tools/lld/include/lld/Core/SymbolTable.h b/contrib/llvm/tools/lld/include/lld/Core/SymbolTable.h
new file mode 100644
index 000000000000..156c56eafbf7
--- /dev/null
+++ b/contrib/llvm/tools/lld/include/lld/Core/SymbolTable.h
@@ -0,0 +1,96 @@
+//===- Core/SymbolTable.h - Main Symbol Table -----------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_SYMBOL_TABLE_H
+#define LLD_CORE_SYMBOL_TABLE_H
+
+#include "lld/Common/LLVM.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/Support/DJB.h"
+#include <cstring>
+#include <map>
+#include <vector>
+
+namespace lld {
+
+class AbsoluteAtom;
+class Atom;
+class DefinedAtom;
+class LinkingContext;
+class ResolverOptions;
+class SharedLibraryAtom;
+class UndefinedAtom;
+
+/// The SymbolTable class is responsible for coalescing atoms.
+///
+/// All atoms coalescable by-name or by-content should be added.
+/// The method replacement() can be used to find the replacement atom
+/// if an atom has been coalesced away.
+class SymbolTable {
+public:
+ /// add atom to symbol table
+ bool add(const DefinedAtom &);
+
+ /// add atom to symbol table
+ bool add(const UndefinedAtom &);
+
+ /// add atom to symbol table
+ bool add(const SharedLibraryAtom &);
+
+ /// add atom to symbol table
+ bool add(const AbsoluteAtom &);
+
+ /// returns atom in symbol table for specified name (or nullptr)
+ const Atom *findByName(StringRef sym);
+
+ /// returns vector of remaining UndefinedAtoms
+ std::vector<const UndefinedAtom *> undefines();
+
+ /// if atom has been coalesced away, return replacement, else return atom
+ const Atom *replacement(const Atom *);
+
+ /// if atom has been coalesced away, return true
+ bool isCoalescedAway(const Atom *);
+
+private:
+ typedef llvm::DenseMap<const Atom *, const Atom *> AtomToAtom;
+
+ struct StringRefMappingInfo {
+ static StringRef getEmptyKey() { return StringRef(); }
+ static StringRef getTombstoneKey() { return StringRef(" ", 1); }
+ static unsigned getHashValue(StringRef const val) {
+ return llvm::djbHash(val, 0);
+ }
+ static bool isEqual(StringRef const lhs, StringRef const rhs) {
+ return lhs.equals(rhs);
+ }
+ };
+ typedef llvm::DenseMap<StringRef, const Atom *,
+ StringRefMappingInfo> NameToAtom;
+
+ struct AtomMappingInfo {
+ static const DefinedAtom * getEmptyKey() { return nullptr; }
+ static const DefinedAtom * getTombstoneKey() { return (DefinedAtom*)(-1); }
+ static unsigned getHashValue(const DefinedAtom * const Val);
+ static bool isEqual(const DefinedAtom * const LHS,
+ const DefinedAtom * const RHS);
+ };
+ typedef llvm::DenseSet<const DefinedAtom*, AtomMappingInfo> AtomContentSet;
+
+ bool addByName(const Atom &);
+ bool addByContent(const DefinedAtom &);
+
+ AtomToAtom _replacedAtoms;
+ NameToAtom _nameTable;
+ AtomContentSet _contentTable;
+};
+
+} // namespace lld
+
+#endif // LLD_CORE_SYMBOL_TABLE_H
diff --git a/contrib/llvm/tools/lld/include/lld/Core/UndefinedAtom.h b/contrib/llvm/tools/lld/include/lld/Core/UndefinedAtom.h
new file mode 100644
index 000000000000..f45d6ecda6b0
--- /dev/null
+++ b/contrib/llvm/tools/lld/include/lld/Core/UndefinedAtom.h
@@ -0,0 +1,68 @@
+//===- Core/UndefinedAtom.h - An Undefined Atom ---------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_UNDEFINED_ATOM_H
+#define LLD_CORE_UNDEFINED_ATOM_H
+
+#include "lld/Core/Atom.h"
+
+namespace lld {
+
+/// An UndefinedAtom has no content.
+/// It exists as a placeholder for a future atom.
+class UndefinedAtom : public Atom {
+public:
+ /// Whether this undefined symbol needs to be resolved,
+ /// or whether it can just evaluate to nullptr.
+ /// This concept is often called "weak", but that term
+ /// is overloaded to mean other things too.
+ enum CanBeNull {
+ /// Normal symbols must be resolved at build time
+ canBeNullNever,
+
+ /// This symbol can be missing at runtime and will evalute to nullptr.
+ /// That is, the static linker still must find a definition (usually
+ /// is some shared library), but at runtime, the dynamic loader
+ /// will allow the symbol to be missing and resolved to nullptr.
+ ///
+ /// On Darwin this is generated using a function prototype with
+ /// __attribute__((weak_import)).
+ /// On linux this is generated using a function prototype with
+ /// __attribute__((weak)).
+ /// On Windows this feature is not supported.
+ canBeNullAtRuntime,
+
+ /// This symbol can be missing at build time.
+ /// That is, the static linker will not error if a definition for
+ /// this symbol is not found at build time. Instead, the linker
+ /// will build an executable that lets the dynamic loader find the
+ /// symbol at runtime.
+ /// This feature is not supported on Darwin nor Windows.
+ /// On linux this is generated using a function prototype with
+ /// __attribute__((weak)).
+ canBeNullAtBuildtime
+ };
+
+ virtual CanBeNull canBeNull() const = 0;
+
+ static bool classof(const Atom *a) {
+ return a->definition() == definitionUndefined;
+ }
+
+ static bool classof(const UndefinedAtom *) { return true; }
+
+protected:
+ UndefinedAtom() : Atom(definitionUndefined) {}
+
+ ~UndefinedAtom() override = default;
+};
+
+} // namespace lld
+
+#endif // LLD_CORE_UNDEFINED_ATOM_H
diff --git a/contrib/llvm/tools/lld/include/lld/Core/Writer.h b/contrib/llvm/tools/lld/include/lld/Core/Writer.h
new file mode 100644
index 000000000000..1cdfabefebd7
--- /dev/null
+++ b/contrib/llvm/tools/lld/include/lld/Core/Writer.h
@@ -0,0 +1,47 @@
+//===- lld/Core/Writer.h - Abstract File Format Interface -----------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_WRITER_H
+#define LLD_CORE_WRITER_H
+
+#include "lld/Common/LLVM.h"
+#include "llvm/Support/Error.h"
+#include <memory>
+#include <vector>
+
+namespace lld {
+class File;
+class LinkingContext;
+class MachOLinkingContext;
+
+/// The Writer is an abstract class for writing object files, shared
+/// library files, and executable files. Each file format (e.g. mach-o, etc)
+/// has a concrete subclass of Writer.
+class Writer {
+public:
+ virtual ~Writer();
+
+ /// Write a file from the supplied File object
+ virtual llvm::Error writeFile(const File &linkedFile, StringRef path) = 0;
+
+ /// This method is called by Core Linking to give the Writer a chance
+ /// to add file format specific "files" to set of files to be linked. This is
+ /// how file format specific atoms can be added to the link.
+ virtual void createImplicitFiles(std::vector<std::unique_ptr<File>> &) {}
+
+protected:
+ // only concrete subclasses can be instantiated
+ Writer();
+};
+
+std::unique_ptr<Writer> createWriterMachO(const MachOLinkingContext &);
+std::unique_ptr<Writer> createWriterYAML(const LinkingContext &);
+} // end namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/include/lld/ReaderWriter/MachOLinkingContext.h b/contrib/llvm/tools/lld/include/lld/ReaderWriter/MachOLinkingContext.h
new file mode 100644
index 000000000000..fde65880c3e3
--- /dev/null
+++ b/contrib/llvm/tools/lld/include/lld/ReaderWriter/MachOLinkingContext.h
@@ -0,0 +1,508 @@
+//===- lld/ReaderWriter/MachOLinkingContext.h -----------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_MACHO_LINKING_CONTEXT_H
+#define LLD_READER_WRITER_MACHO_LINKING_CONTEXT_H
+
+#include "lld/Core/LinkingContext.h"
+#include "lld/Core/Reader.h"
+#include "lld/Core/Writer.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <set>
+
+using llvm::MachO::HeaderFileType;
+
+namespace lld {
+
+namespace mach_o {
+class ArchHandler;
+class MachODylibFile;
+class MachOFile;
+class SectCreateFile;
+}
+
+class MachOLinkingContext : public LinkingContext {
+public:
+ MachOLinkingContext();
+ ~MachOLinkingContext() override;
+
+ enum Arch {
+ arch_unknown,
+ arch_ppc,
+ arch_x86,
+ arch_x86_64,
+ arch_armv6,
+ arch_armv7,
+ arch_armv7s,
+ arch_arm64,
+ };
+
+ enum class OS {
+ unknown,
+ macOSX,
+ iOS,
+ iOS_simulator
+ };
+
+ enum class ExportMode {
+ globals, // Default, all global symbols exported.
+ whiteList, // -exported_symbol[s_list], only listed symbols exported.
+ blackList // -unexported_symbol[s_list], no listed symbol exported.
+ };
+
+ enum class DebugInfoMode {
+ addDebugMap, // Default
+ noDebugMap // -S option
+ };
+
+ enum class UndefinedMode {
+ error,
+ warning,
+ suppress,
+ dynamicLookup
+ };
+
+ enum ObjCConstraint {
+ objc_unknown = 0,
+ objc_supports_gc = 2,
+ objc_gc_only = 4,
+ // Image optimized by dyld = 8
+ // GC compaction = 16
+ objc_retainReleaseForSimulator = 32,
+ objc_retainRelease
+ };
+
+ /// Initializes the context to sane default values given the specified output
+ /// file type, arch, os, and minimum os version. This should be called before
+ /// other setXXX() methods.
+ void configure(HeaderFileType type, Arch arch, OS os, uint32_t minOSVersion,
+ bool exportDynamicSymbols);
+
+ void addPasses(PassManager &pm) override;
+ bool validateImpl() override;
+ std::string demangle(StringRef symbolName) const override;
+
+ void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
+
+ /// Creates a new file which is owned by the context. Returns a pointer to
+ /// the new file.
+ template <class T, class... Args>
+ typename std::enable_if<!std::is_array<T>::value, T *>::type
+ make_file(Args &&... args) const {
+ auto file = std::unique_ptr<T>(new T(std::forward<Args>(args)...));
+ auto *filePtr = file.get();
+ auto *ctx = const_cast<MachOLinkingContext *>(this);
+ ctx->getNodes().push_back(llvm::make_unique<FileNode>(std::move(file)));
+ return filePtr;
+ }
+
+ uint32_t getCPUType() const;
+ uint32_t getCPUSubType() const;
+
+ bool addEntryPointLoadCommand() const;
+ bool addUnixThreadLoadCommand() const;
+ bool outputTypeHasEntry() const;
+ bool is64Bit() const;
+
+ virtual uint64_t pageZeroSize() const { return _pageZeroSize; }
+ virtual uint64_t pageSize() const { return _pageSize; }
+
+ mach_o::ArchHandler &archHandler() const;
+
+ HeaderFileType outputMachOType() const { return _outputMachOType; }
+
+ Arch arch() const { return _arch; }
+ StringRef archName() const { return nameFromArch(_arch); }
+ OS os() const { return _os; }
+
+ ExportMode exportMode() const { return _exportMode; }
+ void setExportMode(ExportMode mode) { _exportMode = mode; }
+ void addExportSymbol(StringRef sym);
+ bool exportRestrictMode() const { return _exportMode != ExportMode::globals; }
+ bool exportSymbolNamed(StringRef sym) const;
+
+ DebugInfoMode debugInfoMode() const { return _debugInfoMode; }
+ void setDebugInfoMode(DebugInfoMode mode) {
+ _debugInfoMode = mode;
+ }
+
+ void appendOrderedSymbol(StringRef symbol, StringRef filename);
+
+ bool keepPrivateExterns() const { return _keepPrivateExterns; }
+ void setKeepPrivateExterns(bool v) { _keepPrivateExterns = v; }
+ bool demangleSymbols() const { return _demangle; }
+ void setDemangleSymbols(bool d) { _demangle = d; }
+ bool mergeObjCCategories() const { return _mergeObjCCategories; }
+ void setMergeObjCCategories(bool v) { _mergeObjCCategories = v; }
+ /// Create file at specified path which will contain a binary encoding
+ /// of all input and output file paths.
+ std::error_code createDependencyFile(StringRef path);
+ void addInputFileDependency(StringRef path) const;
+ void addInputFileNotFound(StringRef path) const;
+ void addOutputFileDependency(StringRef path) const;
+
+ bool minOS(StringRef mac, StringRef iOS) const;
+ void setDoNothing(bool value) { _doNothing = value; }
+ bool doNothing() const { return _doNothing; }
+ bool printAtoms() const { return _printAtoms; }
+ bool testingFileUsage() const { return _testingFileUsage; }
+ const StringRefVector &searchDirs() const { return _searchDirs; }
+ const StringRefVector &frameworkDirs() const { return _frameworkDirs; }
+ void setSysLibRoots(const StringRefVector &paths);
+ const StringRefVector &sysLibRoots() const { return _syslibRoots; }
+ bool PIE() const { return _pie; }
+ void setPIE(bool pie) { _pie = pie; }
+ bool generateVersionLoadCommand() const {
+ return _generateVersionLoadCommand;
+ }
+ void setGenerateVersionLoadCommand(bool v) {
+ _generateVersionLoadCommand = v;
+ }
+
+ bool generateFunctionStartsLoadCommand() const {
+ return _generateFunctionStartsLoadCommand;
+ }
+ void setGenerateFunctionStartsLoadCommand(bool v) {
+ _generateFunctionStartsLoadCommand = v;
+ }
+
+ bool generateDataInCodeLoadCommand() const {
+ return _generateDataInCodeLoadCommand;
+ }
+ void setGenerateDataInCodeLoadCommand(bool v) {
+ _generateDataInCodeLoadCommand = v;
+ }
+
+ uint64_t stackSize() const { return _stackSize; }
+ void setStackSize(uint64_t stackSize) { _stackSize = stackSize; }
+
+ uint64_t baseAddress() const { return _baseAddress; }
+ void setBaseAddress(uint64_t baseAddress) { _baseAddress = baseAddress; }
+
+ ObjCConstraint objcConstraint() const { return _objcConstraint; }
+
+ uint32_t osMinVersion() const { return _osMinVersion; }
+
+ uint32_t sdkVersion() const { return _sdkVersion; }
+ void setSdkVersion(uint64_t v) { _sdkVersion = v; }
+
+ uint64_t sourceVersion() const { return _sourceVersion; }
+ void setSourceVersion(uint64_t v) { _sourceVersion = v; }
+
+ uint32_t swiftVersion() const { return _swiftVersion; }
+
+ /// Checks whether a given path on the filesystem exists.
+ ///
+ /// When running in -test_file_usage mode, this method consults an
+ /// internally maintained list of files that exist (provided by -path_exists)
+ /// instead of the actual filesystem.
+ bool pathExists(StringRef path) const;
+
+ /// Like pathExists() but only used on files - not directories.
+ bool fileExists(StringRef path) const;
+
+ /// Adds any library search paths derived from the given base, possibly
+ /// modified by -syslibroots.
+ ///
+ /// The set of paths added consists of approximately all syslibroot-prepended
+ /// versions of libPath that exist, or the original libPath if there are none
+ /// for whatever reason. With various edge-cases for compatibility.
+ void addModifiedSearchDir(StringRef libPath, bool isSystemPath = false);
+
+ /// Determine whether -lFoo can be resolve within the given path, and
+ /// return the filename if so.
+ ///
+ /// The -lFoo option is documented to search for libFoo.dylib and libFoo.a in
+ /// that order, unless Foo ends in ".o", in which case only the exact file
+ /// matches (e.g. -lfoo.o would only find foo.o).
+ llvm::Optional<StringRef> searchDirForLibrary(StringRef path,
+ StringRef libName) const;
+
+ /// Iterates through all search path entries looking for libName (as
+ /// specified by -lFoo).
+ llvm::Optional<StringRef> searchLibrary(StringRef libName) const;
+
+ /// Add a framework search path. Internally, this method may be prepended
+ /// the path with syslibroot.
+ void addFrameworkSearchDir(StringRef fwPath, bool isSystemPath = false);
+
+ /// Iterates through all framework directories looking for
+ /// Foo.framework/Foo (when fwName = "Foo").
+ llvm::Optional<StringRef> findPathForFramework(StringRef fwName) const;
+
+ /// The dylib's binary compatibility version, in the raw uint32 format.
+ ///
+ /// When building a dynamic library, this is the compatibility version that
+ /// gets embedded into the result. Other Mach-O binaries that link against
+ /// this library will store the compatibility version in its load command. At
+ /// runtime, the loader will verify that the binary is compatible with the
+ /// installed dynamic library.
+ uint32_t compatibilityVersion() const { return _compatibilityVersion; }
+
+ /// The dylib's current version, in the the raw uint32 format.
+ ///
+ /// When building a dynamic library, this is the current version that gets
+ /// embedded into the result. Other Mach-O binaries that link against
+ /// this library will store the compatibility version in its load command.
+ uint32_t currentVersion() const { return _currentVersion; }
+
+ /// The dylib's install name.
+ ///
+ /// Binaries that link against the dylib will embed this path into the dylib
+ /// load command. When loading the binaries at runtime, this is the location
+ /// on disk that the loader will look for the dylib.
+ StringRef installName() const { return _installName; }
+
+ /// Whether or not the dylib has side effects during initialization.
+ ///
+ /// Dylibs marked as being dead strippable provide the guarantee that loading
+ /// the dylib has no side effects, allowing the linker to strip out the dylib
+ /// when linking a binary that does not use any of its symbols.
+ bool deadStrippableDylib() const { return _deadStrippableDylib; }
+
+ /// Whether or not to use flat namespace.
+ ///
+ /// MachO usually uses a two-level namespace, where each external symbol
+ /// referenced by the target is associated with the dylib that will provide
+ /// the symbol's definition at runtime. Using flat namespace overrides this
+ /// behavior: the linker searches all dylibs on the command line and all
+ /// dylibs those original dylibs depend on, but does not record which dylib
+ /// an external symbol came from. At runtime dyld again searches all images
+ /// and uses the first definition it finds. In addition, any undefines in
+ /// loaded flat_namespace dylibs must be resolvable at build time.
+ bool useFlatNamespace() const { return _flatNamespace; }
+
+ /// How to handle undefined symbols.
+ ///
+ /// Options are:
+ /// * error: Report an error and terminate linking.
+ /// * warning: Report a warning, but continue linking.
+ /// * suppress: Ignore and continue linking.
+ /// * dynamic_lookup: For use with -twolevel namespace: Records source dylibs
+ /// for symbols that are defined in a linked dylib at static link time.
+ /// Undefined symbols are handled by searching all loaded images at
+ /// runtime.
+ UndefinedMode undefinedMode() const { return _undefinedMode; }
+
+ /// The path to the executable that will load the bundle at runtime.
+ ///
+ /// When building a Mach-O bundle, this executable will be examined if there
+ /// are undefined symbols after the main link phase. It is expected that this
+ /// binary will be loading the bundle at runtime and will provide the symbols
+ /// at that point.
+ StringRef bundleLoader() const { return _bundleLoader; }
+
+ void setCompatibilityVersion(uint32_t vers) { _compatibilityVersion = vers; }
+ void setCurrentVersion(uint32_t vers) { _currentVersion = vers; }
+ void setInstallName(StringRef name) { _installName = name; }
+ void setDeadStrippableDylib(bool deadStrippable) {
+ _deadStrippableDylib = deadStrippable;
+ }
+ void setUseFlatNamespace(bool flatNamespace) {
+ _flatNamespace = flatNamespace;
+ }
+
+ void setUndefinedMode(UndefinedMode undefinedMode) {
+ _undefinedMode = undefinedMode;
+ }
+
+ void setBundleLoader(StringRef loader) { _bundleLoader = loader; }
+ void setPrintAtoms(bool value=true) { _printAtoms = value; }
+ void setTestingFileUsage(bool value = true) {
+ _testingFileUsage = value;
+ }
+ void addExistingPathForDebug(StringRef path) {
+ _existingPaths.insert(path);
+ }
+
+ void addRpath(StringRef rpath);
+ const StringRefVector &rpaths() const { return _rpaths; }
+
+ /// Add section alignment constraint on final layout.
+ void addSectionAlignment(StringRef seg, StringRef sect, uint16_t align);
+
+ /// Add a section based on a command-line sectcreate option.
+ void addSectCreateSection(StringRef seg, StringRef sect,
+ std::unique_ptr<MemoryBuffer> content);
+
+ /// Returns true if specified section had alignment constraints.
+ bool sectionAligned(StringRef seg, StringRef sect, uint16_t &align) const;
+
+ StringRef dyldPath() const { return "/usr/lib/dyld"; }
+
+ /// Stub creation Pass should be run.
+ bool needsStubsPass() const;
+
+ // GOT creation Pass should be run.
+ bool needsGOTPass() const;
+
+ /// Pass to add TLV sections.
+ bool needsTLVPass() const;
+
+ /// Pass to transform __compact_unwind into __unwind_info should be run.
+ bool needsCompactUnwindPass() const;
+
+ /// Pass to add shims switching between thumb and arm mode.
+ bool needsShimPass() const;
+
+ /// Pass to add objc image info and optimized objc data.
+ bool needsObjCPass() const;
+
+ /// Magic symbol name stubs will need to help lazy bind.
+ StringRef binderSymbolName() const;
+
+ /// Used to keep track of direct and indirect dylibs.
+ void registerDylib(mach_o::MachODylibFile *dylib, bool upward) const;
+
+ // Reads a file from disk to memory. Returns only a needed chunk
+ // if a fat binary.
+ ErrorOr<std::unique_ptr<MemoryBuffer>> getMemoryBuffer(StringRef path);
+
+ /// Used to find indirect dylibs. Instantiates a MachODylibFile if one
+ /// has not already been made for the requested dylib. Uses -L and -F
+ /// search paths to allow indirect dylibs to be overridden.
+ mach_o::MachODylibFile* findIndirectDylib(StringRef path);
+
+ uint32_t dylibCurrentVersion(StringRef installName) const;
+
+ uint32_t dylibCompatVersion(StringRef installName) const;
+
+ ArrayRef<mach_o::MachODylibFile*> allDylibs() const {
+ return _allDylibs;
+ }
+
+ /// Creates a copy (owned by this MachOLinkingContext) of a string.
+ StringRef copy(StringRef str) { return str.copy(_allocator); }
+
+ /// If the memoryBuffer is a fat file with a slice for the current arch,
+ /// this method will return the offset and size of that slice.
+ bool sliceFromFatFile(MemoryBufferRef mb, uint32_t &offset, uint32_t &size);
+
+ /// Returns if a command line option specified dylib is an upward link.
+ bool isUpwardDylib(StringRef installName) const;
+
+ static bool isThinObjectFile(StringRef path, Arch &arch);
+ static Arch archFromCpuType(uint32_t cputype, uint32_t cpusubtype);
+ static Arch archFromName(StringRef archName);
+ static StringRef nameFromArch(Arch arch);
+ static uint32_t cpuTypeFromArch(Arch arch);
+ static uint32_t cpuSubtypeFromArch(Arch arch);
+ static bool is64Bit(Arch arch);
+ static bool isHostEndian(Arch arch);
+ static bool isBigEndian(Arch arch);
+
+ /// Construct 32-bit value from string "X.Y.Z" where
+ /// bits are xxxx.yy.zz. Largest number is 65535.255.255
+ static bool parsePackedVersion(StringRef str, uint32_t &result);
+
+ /// Construct 64-bit value from string "A.B.C.D.E" where
+ /// bits are aaaa.bb.cc.dd.ee. Largest number is 16777215.1023.1023.1023.1023
+ static bool parsePackedVersion(StringRef str, uint64_t &result);
+
+ void finalizeInputFiles() override;
+
+ llvm::Error handleLoadedFile(File &file) override;
+
+ bool customAtomOrderer(const DefinedAtom *left, const DefinedAtom *right,
+ bool &leftBeforeRight) const;
+
+ /// Return the 'flat namespace' file. This is the file that supplies
+ /// atoms for otherwise undefined symbols when the -flat_namespace or
+ /// -undefined dynamic_lookup options are used.
+ File* flatNamespaceFile() const { return _flatNamespaceFile; }
+
+private:
+ Writer &writer() const override;
+ mach_o::MachODylibFile* loadIndirectDylib(StringRef path);
+ void checkExportWhiteList(const DefinedAtom *atom) const;
+ void checkExportBlackList(const DefinedAtom *atom) const;
+ struct ArchInfo {
+ StringRef archName;
+ MachOLinkingContext::Arch arch;
+ bool littleEndian;
+ uint32_t cputype;
+ uint32_t cpusubtype;
+ };
+
+ struct SectionAlign {
+ StringRef segmentName;
+ StringRef sectionName;
+ uint16_t align;
+ };
+
+ struct OrderFileNode {
+ StringRef fileFilter;
+ unsigned order;
+ };
+
+ static bool findOrderOrdinal(const std::vector<OrderFileNode> &nodes,
+ const DefinedAtom *atom, unsigned &ordinal);
+
+ static ArchInfo _s_archInfos[];
+
+ std::set<StringRef> _existingPaths; // For testing only.
+ StringRefVector _searchDirs;
+ StringRefVector _syslibRoots;
+ StringRefVector _frameworkDirs;
+ HeaderFileType _outputMachOType = llvm::MachO::MH_EXECUTE;
+ bool _outputMachOTypeStatic = false; // Disambiguate static vs dynamic prog
+ bool _doNothing = false; // for -help and -v which just print info
+ bool _pie = false;
+ Arch _arch = arch_unknown;
+ OS _os = OS::macOSX;
+ uint32_t _osMinVersion = 0;
+ uint32_t _sdkVersion = 0;
+ uint64_t _sourceVersion = 0;
+ uint64_t _pageZeroSize = 0;
+ uint64_t _pageSize = 4096;
+ uint64_t _baseAddress = 0;
+ uint64_t _stackSize = 0;
+ uint32_t _compatibilityVersion = 0;
+ uint32_t _currentVersion = 0;
+ ObjCConstraint _objcConstraint = objc_unknown;
+ uint32_t _swiftVersion = 0;
+ StringRef _installName;
+ StringRefVector _rpaths;
+ bool _flatNamespace = false;
+ UndefinedMode _undefinedMode = UndefinedMode::error;
+ bool _deadStrippableDylib = false;
+ bool _printAtoms = false;
+ bool _testingFileUsage = false;
+ bool _keepPrivateExterns = false;
+ bool _demangle = false;
+ bool _mergeObjCCategories = true;
+ bool _generateVersionLoadCommand = false;
+ bool _generateFunctionStartsLoadCommand = false;
+ bool _generateDataInCodeLoadCommand = false;
+ StringRef _bundleLoader;
+ mutable std::unique_ptr<mach_o::ArchHandler> _archHandler;
+ mutable std::unique_ptr<Writer> _writer;
+ std::vector<SectionAlign> _sectAligns;
+ mutable llvm::StringMap<mach_o::MachODylibFile*> _pathToDylibMap;
+ mutable std::vector<mach_o::MachODylibFile*> _allDylibs;
+ mutable std::set<mach_o::MachODylibFile*> _upwardDylibs;
+ mutable std::vector<std::unique_ptr<File>> _indirectDylibs;
+ mutable std::mutex _dylibsMutex;
+ ExportMode _exportMode = ExportMode::globals;
+ llvm::StringSet<> _exportedSymbols;
+ DebugInfoMode _debugInfoMode = DebugInfoMode::addDebugMap;
+ std::unique_ptr<llvm::raw_fd_ostream> _dependencyInfo;
+ llvm::StringMap<std::vector<OrderFileNode>> _orderFiles;
+ unsigned _orderFileEntries = 0;
+ File *_flatNamespaceFile = nullptr;
+ mach_o::SectCreateFile *_sectCreateFile = nullptr;
+};
+
+} // end namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_LINKING_CONTEXT_H
diff --git a/contrib/llvm/tools/lld/include/lld/ReaderWriter/YamlContext.h b/contrib/llvm/tools/lld/include/lld/ReaderWriter/YamlContext.h
new file mode 100644
index 000000000000..b97d21f68e55
--- /dev/null
+++ b/contrib/llvm/tools/lld/include/lld/ReaderWriter/YamlContext.h
@@ -0,0 +1,43 @@
+//===- lld/ReaderWriter/YamlContext.h - object used in YAML I/O context ---===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_YAML_CONTEXT_H
+#define LLD_READER_WRITER_YAML_CONTEXT_H
+
+#include "lld/Common/LLVM.h"
+#include <functional>
+#include <memory>
+#include <vector>
+
+namespace lld {
+class File;
+class LinkingContext;
+class Registry;
+namespace mach_o {
+namespace normalized {
+struct NormalizedFile;
+}
+}
+
+using lld::mach_o::normalized::NormalizedFile;
+
+/// When YAML I/O is used in lld, the yaml context always holds a YamlContext
+/// object. We need to support hetergenous yaml documents which each require
+/// different context info. This struct supports all clients.
+struct YamlContext {
+ const LinkingContext *_ctx = nullptr;
+ const Registry *_registry = nullptr;
+ File *_file = nullptr;
+ NormalizedFile *_normalizeMachOFile = nullptr;
+ StringRef _path;
+};
+
+} // end namespace lld
+
+#endif // LLD_READER_WRITER_YAML_CONTEXT_H
diff --git a/contrib/llvm/tools/lld/lib/CMakeLists.txt b/contrib/llvm/tools/lld/lib/CMakeLists.txt
new file mode 100644
index 000000000000..8884efcfe9ba
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_subdirectory(Core)
+add_subdirectory(Driver)
+add_subdirectory(ReaderWriter)
diff --git a/contrib/llvm/tools/lld/lib/Core/CMakeLists.txt b/contrib/llvm/tools/lld/lib/Core/CMakeLists.txt
new file mode 100644
index 000000000000..2d4d9ded0886
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/Core/CMakeLists.txt
@@ -0,0 +1,28 @@
+if(NOT LLD_BUILT_STANDALONE)
+ set(tablegen_deps intrinsics_gen)
+endif()
+
+add_lld_library(lldCore
+ DefinedAtom.cpp
+ Error.cpp
+ File.cpp
+ LinkingContext.cpp
+ Reader.cpp
+ Resolver.cpp
+ SymbolTable.cpp
+ Writer.cpp
+
+ ADDITIONAL_HEADER_DIRS
+ ${LLD_INCLUDE_DIR}/lld/Core
+
+ LINK_COMPONENTS
+ BinaryFormat
+ MC
+ Support
+
+ LINK_LIBS
+ ${LLVM_PTHREAD_LIB}
+
+ DEPENDS
+ ${tablegen_deps}
+ )
diff --git a/contrib/llvm/tools/lld/lib/Core/DefinedAtom.cpp b/contrib/llvm/tools/lld/lib/Core/DefinedAtom.cpp
new file mode 100644
index 000000000000..177cae7fcbf0
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/Core/DefinedAtom.cpp
@@ -0,0 +1,82 @@
+//===- DefinedAtom.cpp ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/ErrorHandling.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+
+namespace lld {
+
+DefinedAtom::ContentPermissions DefinedAtom::permissions() const {
+ // By default base permissions on content type.
+ return permissions(this->contentType());
+}
+
+// Utility function for deriving permissions from content type
+DefinedAtom::ContentPermissions DefinedAtom::permissions(ContentType type) {
+ switch (type) {
+ case typeCode:
+ case typeResolver:
+ case typeBranchIsland:
+ case typeBranchShim:
+ case typeStub:
+ case typeStubHelper:
+ case typeMachHeader:
+ return permR_X;
+
+ case typeConstant:
+ case typeCString:
+ case typeUTF16String:
+ case typeCFI:
+ case typeLSDA:
+ case typeLiteral4:
+ case typeLiteral8:
+ case typeLiteral16:
+ case typeDTraceDOF:
+ case typeCompactUnwindInfo:
+ case typeProcessedUnwindInfo:
+ case typeObjCImageInfo:
+ case typeObjCMethodList:
+ return permR__;
+
+ case typeData:
+ case typeDataFast:
+ case typeZeroFill:
+ case typeZeroFillFast:
+ case typeObjC1Class:
+ case typeLazyPointer:
+ case typeLazyDylibPointer:
+ case typeNonLazyPointer:
+ case typeThunkTLV:
+ return permRW_;
+
+ case typeGOT:
+ case typeConstData:
+ case typeCFString:
+ case typeInitializerPtr:
+ case typeTerminatorPtr:
+ case typeCStringPtr:
+ case typeObjCClassPtr:
+ case typeObjC2CategoryList:
+ case typeInterposingTuples:
+ case typeTLVInitialData:
+ case typeTLVInitialZeroFill:
+ case typeTLVInitializerPtr:
+ return permRW_L;
+
+ case typeUnknown:
+ case typeTempLTO:
+ case typeSectCreate:
+ case typeDSOHandle:
+ return permUnknown;
+ }
+ llvm_unreachable("unknown content type");
+}
+
+} // namespace
diff --git a/contrib/llvm/tools/lld/lib/Core/Error.cpp b/contrib/llvm/tools/lld/lib/Core/Error.cpp
new file mode 100644
index 000000000000..6fc76f7ca3d0
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/Core/Error.cpp
@@ -0,0 +1,93 @@
+//===- Error.cpp - system_error extensions for lld --------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/Error.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <mutex>
+#include <string>
+#include <vector>
+
+using namespace lld;
+
+namespace {
+class _YamlReaderErrorCategory : public std::error_category {
+public:
+ const char* name() const noexcept override {
+ return "lld.yaml.reader";
+ }
+
+ std::string message(int ev) const override {
+ switch (static_cast<YamlReaderError>(ev)) {
+ case YamlReaderError::unknown_keyword:
+ return "Unknown keyword found in yaml file";
+ case YamlReaderError::illegal_value:
+ return "Bad value found in yaml file";
+ }
+ llvm_unreachable("An enumerator of YamlReaderError does not have a "
+ "message defined.");
+ }
+};
+} // end anonymous namespace
+
+const std::error_category &lld::YamlReaderCategory() {
+ static _YamlReaderErrorCategory o;
+ return o;
+}
+
+namespace lld {
+
+/// Temporary class to enable make_dynamic_error_code() until
+/// llvm::ErrorOr<> is updated to work with error encapsulations
+/// other than error_code.
+class dynamic_error_category : public std::error_category {
+public:
+ ~dynamic_error_category() override = default;
+
+ const char *name() const noexcept override {
+ return "lld.dynamic_error";
+ }
+
+ std::string message(int ev) const override {
+ assert(ev >= 0);
+ assert(ev < (int)_messages.size());
+ // The value is an index into the string vector.
+ return _messages[ev];
+ }
+
+ int add(std::string msg) {
+ std::lock_guard<std::recursive_mutex> lock(_mutex);
+ // Value zero is always the successs value.
+ if (_messages.empty())
+ _messages.push_back("Success");
+ _messages.push_back(msg);
+ // Return the index of the string just appended.
+ return _messages.size() - 1;
+ }
+
+private:
+ std::vector<std::string> _messages;
+ std::recursive_mutex _mutex;
+};
+
+static dynamic_error_category categorySingleton;
+
+std::error_code make_dynamic_error_code(StringRef msg) {
+ return std::error_code(categorySingleton.add(msg), categorySingleton);
+}
+
+char GenericError::ID = 0;
+
+GenericError::GenericError(Twine Msg) : Msg(Msg.str()) { }
+
+void GenericError::log(raw_ostream &OS) const {
+ OS << Msg;
+}
+
+} // namespace lld
diff --git a/contrib/llvm/tools/lld/lib/Core/File.cpp b/contrib/llvm/tools/lld/lib/Core/File.cpp
new file mode 100644
index 000000000000..30ded091a92a
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/Core/File.cpp
@@ -0,0 +1,29 @@
+//===- Core/File.cpp - A Container of Atoms -------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/File.h"
+#include <mutex>
+
+namespace lld {
+
+File::~File() = default;
+
+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);
+ if (!_lastError.hasValue())
+ _lastError = doParse();
+ return _lastError.getValue();
+}
+
+} // end namespace lld
diff --git a/contrib/llvm/tools/lld/lib/Core/LinkingContext.cpp b/contrib/llvm/tools/lld/lib/Core/LinkingContext.cpp
new file mode 100644
index 000000000000..0f225c322122
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/Core/LinkingContext.cpp
@@ -0,0 +1,70 @@
+//===- lib/Core/LinkingContext.cpp - Linker Context Object Interface ------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/LinkingContext.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Node.h"
+#include "lld/Core/Simple.h"
+#include "lld/Core/Writer.h"
+#include <algorithm>
+
+namespace lld {
+
+LinkingContext::LinkingContext() = default;
+
+LinkingContext::~LinkingContext() = default;
+
+bool LinkingContext::validate() {
+ return validateImpl();
+}
+
+llvm::Error LinkingContext::writeFile(const File &linkedFile) const {
+ return this->writer().writeFile(linkedFile, _outputPath);
+}
+
+std::unique_ptr<File> LinkingContext::createEntrySymbolFile() const {
+ return createEntrySymbolFile("<command line option -e>");
+}
+
+std::unique_ptr<File>
+LinkingContext::createEntrySymbolFile(StringRef filename) const {
+ if (entrySymbolName().empty())
+ return nullptr;
+ std::unique_ptr<SimpleFile> entryFile(new SimpleFile(filename,
+ File::kindEntryObject));
+ entryFile->addAtom(
+ *(new (_allocator) SimpleUndefinedAtom(*entryFile, entrySymbolName())));
+ return std::move(entryFile);
+}
+
+std::unique_ptr<File> LinkingContext::createUndefinedSymbolFile() const {
+ return createUndefinedSymbolFile("<command line option -u or --defsym>");
+}
+
+std::unique_ptr<File>
+LinkingContext::createUndefinedSymbolFile(StringRef filename) const {
+ if (_initialUndefinedSymbols.empty())
+ return nullptr;
+ std::unique_ptr<SimpleFile> undefinedSymFile(
+ new SimpleFile(filename, File::kindUndefinedSymsObject));
+ for (StringRef undefSym : _initialUndefinedSymbols)
+ undefinedSymFile->addAtom(*(new (_allocator) SimpleUndefinedAtom(
+ *undefinedSymFile, undefSym)));
+ return std::move(undefinedSymFile);
+}
+
+void LinkingContext::createInternalFiles(
+ std::vector<std::unique_ptr<File>> &result) const {
+ if (std::unique_ptr<File> file = createEntrySymbolFile())
+ result.push_back(std::move(file));
+ if (std::unique_ptr<File> file = createUndefinedSymbolFile())
+ result.push_back(std::move(file));
+}
+
+} // end namespace lld
diff --git a/contrib/llvm/tools/lld/lib/Core/Reader.cpp b/contrib/llvm/tools/lld/lib/Core/Reader.cpp
new file mode 100644
index 000000000000..5d8bbbbfe4d7
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/Core/Reader.cpp
@@ -0,0 +1,114 @@
+//===- lib/Core/Reader.cpp ------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/Reader.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Reference.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <algorithm>
+#include <memory>
+
+using llvm::file_magic;
+using llvm::identify_magic;
+
+namespace lld {
+
+YamlIOTaggedDocumentHandler::~YamlIOTaggedDocumentHandler() = default;
+
+void Registry::add(std::unique_ptr<Reader> reader) {
+ _readers.push_back(std::move(reader));
+}
+
+void Registry::add(std::unique_ptr<YamlIOTaggedDocumentHandler> handler) {
+ _yamlHandlers.push_back(std::move(handler));
+}
+
+ErrorOr<std::unique_ptr<File>>
+Registry::loadFile(std::unique_ptr<MemoryBuffer> mb) const {
+ // Get file magic.
+ StringRef content(mb->getBufferStart(), mb->getBufferSize());
+ file_magic fileType = identify_magic(content);
+
+ // 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, mb->getMemBufferRef()))
+ continue;
+ return reader->loadFile(std::move(mb), *this);
+ }
+
+ // No Reader could parse this file.
+ return make_error_code(llvm::errc::executable_format_error);
+}
+
+static const Registry::KindStrings kindStrings[] = {
+ {Reference::kindLayoutAfter, "layout-after"},
+ {Reference::kindAssociate, "associate"},
+ LLD_KIND_STRING_END};
+
+Registry::Registry() {
+ addKindTable(Reference::KindNamespace::all, Reference::KindArch::all,
+ kindStrings);
+}
+
+bool Registry::handleTaggedDoc(llvm::yaml::IO &io,
+ const lld::File *&file) const {
+ for (const std::unique_ptr<YamlIOTaggedDocumentHandler> &h : _yamlHandlers)
+ if (h->handledDocTag(io, file))
+ return true;
+ return false;
+}
+
+void Registry::addKindTable(Reference::KindNamespace ns,
+ Reference::KindArch arch,
+ const KindStrings array[]) {
+ KindEntry entry = { ns, arch, array };
+ _kindEntries.push_back(entry);
+}
+
+bool Registry::referenceKindFromString(StringRef inputStr,
+ Reference::KindNamespace &ns,
+ Reference::KindArch &arch,
+ Reference::KindValue &value) const {
+ for (const KindEntry &entry : _kindEntries) {
+ for (const KindStrings *pair = entry.array; !pair->name.empty(); ++pair) {
+ if (!inputStr.equals(pair->name))
+ continue;
+ ns = entry.ns;
+ arch = entry.arch;
+ value = pair->value;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Registry::referenceKindToString(Reference::KindNamespace ns,
+ Reference::KindArch arch,
+ Reference::KindValue value,
+ StringRef &str) const {
+ for (const KindEntry &entry : _kindEntries) {
+ if (entry.ns != ns)
+ continue;
+ if (entry.arch != arch)
+ continue;
+ for (const KindStrings *pair = entry.array; !pair->name.empty(); ++pair) {
+ if (pair->value != value)
+ continue;
+ str = pair->name;
+ return true;
+ }
+ }
+ return false;
+}
+
+} // end namespace lld
diff --git a/contrib/llvm/tools/lld/lib/Core/Resolver.cpp b/contrib/llvm/tools/lld/lib/Core/Resolver.cpp
new file mode 100644
index 000000000000..9c51c6cdb19c
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/Core/Resolver.cpp
@@ -0,0 +1,505 @@
+//===- Core/Resolver.cpp - Resolves Atom References -----------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/Resolver.h"
+#include "lld/Common/LLVM.h"
+#include "lld/Core/ArchiveLibraryFile.h"
+#include "lld/Core/Atom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Instrumentation.h"
+#include "lld/Core/LinkingContext.h"
+#include "lld/Core/SharedLibraryFile.h"
+#include "lld/Core/SymbolTable.h"
+#include "lld/Core/UndefinedAtom.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <utility>
+#include <vector>
+
+namespace lld {
+
+llvm::Expected<bool> Resolver::handleFile(File &file) {
+ if (auto ec = _ctx.handleLoadedFile(file))
+ return std::move(ec);
+ bool undefAdded = false;
+ for (auto &atom : file.defined().owning_ptrs())
+ doDefinedAtom(std::move(atom));
+ for (auto &atom : file.undefined().owning_ptrs()) {
+ if (doUndefinedAtom(std::move(atom)))
+ undefAdded = true;
+ }
+ for (auto &atom : file.sharedLibrary().owning_ptrs())
+ doSharedLibraryAtom(std::move(atom));
+ for (auto &atom : file.absolute().owning_ptrs())
+ doAbsoluteAtom(std::move(atom));
+ return undefAdded;
+}
+
+llvm::Expected<bool> Resolver::forEachUndefines(File &file,
+ UndefCallback callback) {
+ size_t i = _undefineIndex[&file];
+ bool undefAdded = false;
+ do {
+ for (; i < _undefines.size(); ++i) {
+ StringRef undefName = _undefines[i];
+ if (undefName.empty())
+ continue;
+ const Atom *atom = _symbolTable.findByName(undefName);
+ if (!isa<UndefinedAtom>(atom) || _symbolTable.isCoalescedAway(atom)) {
+ // The symbol was resolved by some other file. Cache the result.
+ _undefines[i] = "";
+ continue;
+ }
+ auto undefAddedOrError = callback(undefName);
+ if (auto ec = undefAddedOrError.takeError())
+ return std::move(ec);
+ undefAdded |= undefAddedOrError.get();
+ }
+ } while (i < _undefines.size());
+ _undefineIndex[&file] = i;
+ return undefAdded;
+}
+
+llvm::Expected<bool> Resolver::handleArchiveFile(File &file) {
+ ArchiveLibraryFile *archiveFile = cast<ArchiveLibraryFile>(&file);
+ return forEachUndefines(file,
+ [&](StringRef undefName) -> llvm::Expected<bool> {
+ if (File *member = archiveFile->find(undefName)) {
+ member->setOrdinal(_ctx.getNextOrdinalAndIncrement());
+ return handleFile(*member);
+ }
+ return false;
+ });
+}
+
+llvm::Error Resolver::handleSharedLibrary(File &file) {
+ // Add all the atoms from the shared library
+ SharedLibraryFile *sharedLibrary = cast<SharedLibraryFile>(&file);
+ auto undefAddedOrError = handleFile(*sharedLibrary);
+ if (auto ec = undefAddedOrError.takeError())
+ return ec;
+ undefAddedOrError =
+ forEachUndefines(file, [&](StringRef undefName) -> llvm::Expected<bool> {
+ auto atom = sharedLibrary->exports(undefName);
+ if (atom.get())
+ doSharedLibraryAtom(std::move(atom));
+ return false;
+ });
+
+ if (auto ec = undefAddedOrError.takeError())
+ return ec;
+ return llvm::Error::success();
+}
+
+bool Resolver::doUndefinedAtom(OwningAtomPtr<UndefinedAtom> atom) {
+ DEBUG_WITH_TYPE("resolver", llvm::dbgs()
+ << " UndefinedAtom: "
+ << llvm::format("0x%09lX", atom.get())
+ << ", name=" << atom.get()->name() << "\n");
+
+ // tell symbol table
+ bool newUndefAdded = _symbolTable.add(*atom.get());
+ if (newUndefAdded)
+ _undefines.push_back(atom.get()->name());
+
+ // add to list of known atoms
+ _atoms.push_back(OwningAtomPtr<Atom>(atom.release()));
+
+ return newUndefAdded;
+}
+
+// Called on each atom when a file is added. Returns true if a given
+// atom is added to the symbol table.
+void Resolver::doDefinedAtom(OwningAtomPtr<DefinedAtom> atom) {
+ DEBUG_WITH_TYPE("resolver", llvm::dbgs()
+ << " DefinedAtom: "
+ << llvm::format("0x%09lX", atom.get())
+ << ", file=#"
+ << atom.get()->file().ordinal()
+ << ", atom=#"
+ << atom.get()->ordinal()
+ << ", name="
+ << atom.get()->name()
+ << ", type="
+ << atom.get()->contentType()
+ << "\n");
+
+ // An atom that should never be dead-stripped is a dead-strip root.
+ if (_ctx.deadStrip() &&
+ atom.get()->deadStrip() == DefinedAtom::deadStripNever) {
+ _deadStripRoots.insert(atom.get());
+ }
+
+ // add to list of known atoms
+ _symbolTable.add(*atom.get());
+ _atoms.push_back(OwningAtomPtr<Atom>(atom.release()));
+}
+
+void Resolver::doSharedLibraryAtom(OwningAtomPtr<SharedLibraryAtom> atom) {
+ DEBUG_WITH_TYPE("resolver", llvm::dbgs()
+ << " SharedLibraryAtom: "
+ << llvm::format("0x%09lX", atom.get())
+ << ", name="
+ << atom.get()->name()
+ << "\n");
+
+ // tell symbol table
+ _symbolTable.add(*atom.get());
+
+ // add to list of known atoms
+ _atoms.push_back(OwningAtomPtr<Atom>(atom.release()));
+}
+
+void Resolver::doAbsoluteAtom(OwningAtomPtr<AbsoluteAtom> atom) {
+ DEBUG_WITH_TYPE("resolver", llvm::dbgs()
+ << " AbsoluteAtom: "
+ << llvm::format("0x%09lX", atom.get())
+ << ", name="
+ << atom.get()->name()
+ << "\n");
+
+ // tell symbol table
+ if (atom.get()->scope() != Atom::scopeTranslationUnit)
+ _symbolTable.add(*atom.get());
+
+ // add to list of known atoms
+ _atoms.push_back(OwningAtomPtr<Atom>(atom.release()));
+}
+
+// Returns true if at least one of N previous files has created an
+// undefined symbol.
+bool Resolver::undefinesAdded(int begin, int end) {
+ std::vector<std::unique_ptr<Node>> &inputs = _ctx.getNodes();
+ for (int i = begin; i < end; ++i)
+ if (FileNode *node = dyn_cast<FileNode>(inputs[i].get()))
+ if (_newUndefinesAdded[node->getFile()])
+ return true;
+ return false;
+}
+
+File *Resolver::getFile(int &index) {
+ std::vector<std::unique_ptr<Node>> &inputs = _ctx.getNodes();
+ if ((size_t)index >= inputs.size())
+ return nullptr;
+ if (GroupEnd *group = dyn_cast<GroupEnd>(inputs[index].get())) {
+ // We are at the end of the current group. If one or more new
+ // undefined atom has been added in the last groupSize files, we
+ // reiterate over the files.
+ int size = group->getSize();
+ if (undefinesAdded(index - size, index)) {
+ index -= size;
+ return getFile(index);
+ }
+ ++index;
+ return getFile(index);
+ }
+ return cast<FileNode>(inputs[index++].get())->getFile();
+}
+
+// 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;
+ if (std::error_code ec = file->parse()) {
+ llvm::errs() << "Cannot open " + file->path()
+ << ": " << ec.message() << "\n";
+ return false;
+ }
+ DEBUG_WITH_TYPE("resolver",
+ llvm::dbgs() << "Loaded file: " << file->path() << "\n");
+ switch (file->kind()) {
+ case File::kindErrorObject:
+ case File::kindNormalizedObject:
+ case File::kindMachObject:
+ case File::kindCEntryObject:
+ case File::kindHeaderObject:
+ case File::kindEntryObject:
+ case File::kindUndefinedSymsObject:
+ case File::kindStubHelperObject:
+ case File::kindResolverMergedObject:
+ case File::kindSectCreateObject: {
+ // The same file may be visited more than once if the file is
+ // in --start-group and --end-group. Only library files should
+ // be processed more than once.
+ if (seen.count(file))
+ break;
+ seen.insert(file);
+ assert(!file->hasOrdinal());
+ file->setOrdinal(_ctx.getNextOrdinalAndIncrement());
+ auto undefAddedOrError = handleFile(*file);
+ if (auto EC = undefAddedOrError.takeError()) {
+ // FIXME: This should be passed to logAllUnhandledErrors but it needs
+ // to be passed a Twine instead of a string.
+ llvm::errs() << "Error in " + file->path() << ": ";
+ logAllUnhandledErrors(std::move(EC), llvm::errs(), std::string());
+ return false;
+ }
+ undefAdded = undefAddedOrError.get();
+ break;
+ }
+ case File::kindArchiveLibrary: {
+ if (!file->hasOrdinal())
+ file->setOrdinal(_ctx.getNextOrdinalAndIncrement());
+ auto undefAddedOrError = handleArchiveFile(*file);
+ if (auto EC = undefAddedOrError.takeError()) {
+ // FIXME: This should be passed to logAllUnhandledErrors but it needs
+ // to be passed a Twine instead of a string.
+ llvm::errs() << "Error in " + file->path() << ": ";
+ logAllUnhandledErrors(std::move(EC), llvm::errs(), std::string());
+ return false;
+ }
+ undefAdded = undefAddedOrError.get();
+ break;
+ }
+ case File::kindSharedLibrary:
+ if (!file->hasOrdinal())
+ file->setOrdinal(_ctx.getNextOrdinalAndIncrement());
+ if (auto EC = handleSharedLibrary(*file)) {
+ // FIXME: This should be passed to logAllUnhandledErrors but it needs
+ // to be passed a Twine instead of a string.
+ llvm::errs() << "Error in " + file->path() << ": ";
+ logAllUnhandledErrors(std::move(EC), llvm::errs(), std::string());
+ return false;
+ }
+ break;
+ }
+ _newUndefinesAdded[file] = undefAdded;
+ }
+}
+
+// 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 OwningAtomPtr<Atom> &atom : _atoms) {
+ if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom.get())) {
+ for (const Reference *ref : *defAtom) {
+ // A reference of type kindAssociate should't be updated.
+ // Instead, an atom having such reference will be removed
+ // if the target atom is coalesced away, so that they will
+ // go away as a group.
+ if (ref->kindNamespace() == lld::Reference::KindNamespace::all &&
+ ref->kindValue() == lld::Reference::kindAssociate) {
+ if (_symbolTable.isCoalescedAway(atom.get()))
+ _deadAtoms.insert(ref->target());
+ continue;
+ }
+ const Atom *newTarget = _symbolTable.replacement(ref->target());
+ const_cast<Reference *>(ref)->setTarget(newTarget);
+ }
+ }
+ }
+}
+
+// For dead code stripping, recursively mark atoms "live"
+void Resolver::markLive(const Atom *atom) {
+ // Mark the atom is live. If it's already marked live, then stop recursion.
+ auto exists = _liveAtoms.insert(atom);
+ if (!exists.second)
+ return;
+
+ // Mark all atoms it references as live
+ if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom)) {
+ for (const Reference *ref : *defAtom)
+ markLive(ref->target());
+ for (auto &p : llvm::make_range(_reverseRef.equal_range(defAtom))) {
+ const Atom *target = p.second;
+ markLive(target);
+ }
+ }
+}
+
+static bool isBackref(const Reference *ref) {
+ if (ref->kindNamespace() != lld::Reference::KindNamespace::all)
+ return false;
+ return (ref->kindValue() == lld::Reference::kindLayoutAfter);
+}
+
+// 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())
+ return;
+
+ // Some type of references prevent referring atoms to be dead-striped.
+ // Make a reverse map of such references before traversing the graph.
+ // While traversing the list of atoms, mark AbsoluteAtoms as live
+ // in order to avoid reclaim.
+ for (const OwningAtomPtr<Atom> &atom : _atoms) {
+ if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom.get()))
+ for (const Reference *ref : *defAtom)
+ if (isBackref(ref))
+ _reverseRef.insert(std::make_pair(ref->target(), atom.get()));
+ if (const AbsoluteAtom *absAtom = dyn_cast<AbsoluteAtom>(atom.get()))
+ markLive(absAtom);
+ }
+
+ // By default, shared libraries are built with all globals as dead strip roots
+ if (_ctx.globalsAreDeadStripRoots())
+ for (const OwningAtomPtr<Atom> &atom : _atoms)
+ if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom.get()))
+ if (defAtom->scope() == DefinedAtom::scopeGlobal)
+ _deadStripRoots.insert(defAtom);
+
+ // Or, use list of names that are dead strip roots.
+ for (const StringRef &name : _ctx.deadStripRoots()) {
+ const Atom *symAtom = _symbolTable.findByName(name);
+ assert(symAtom);
+ _deadStripRoots.insert(symAtom);
+ }
+
+ // mark all roots as live, and recursively all atoms they reference
+ for (const Atom *dsrAtom : _deadStripRoots)
+ markLive(dsrAtom);
+
+ // now remove all non-live atoms from _atoms
+ _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(),
+ [&](OwningAtomPtr<Atom> &a) {
+ return _liveAtoms.count(a.get()) == 0;
+ }),
+ _atoms.end());
+}
+
+// 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()) {
+ // When dead code stripping, we don't care if dead atoms are undefined.
+ undefinedAtoms.erase(
+ std::remove_if(undefinedAtoms.begin(), undefinedAtoms.end(),
+ [&](const Atom *a) { return _liveAtoms.count(a) == 0; }),
+ undefinedAtoms.end());
+ }
+
+ if (undefinedAtoms.empty())
+ return false;
+
+ // Warn about unresolved symbols.
+ bool foundUndefines = false;
+ for (const UndefinedAtom *undef : undefinedAtoms) {
+ // Skip over a weak symbol.
+ if (undef->canBeNull() != UndefinedAtom::canBeNullNever)
+ continue;
+
+ // If this is a library and undefined symbols are allowed on the
+ // target platform, skip over it.
+ if (isa<SharedLibraryFile>(undef->file()) && _ctx.allowShlibUndefines())
+ continue;
+
+ // If the undefine is coalesced away, skip over it.
+ if (_symbolTable.isCoalescedAway(undef))
+ continue;
+
+ // Seems like this symbol is undefined. Warn that.
+ foundUndefines = true;
+ if (_ctx.printRemainingUndefines()) {
+ llvm::errs() << "Undefined symbol: " << undef->file().path()
+ << ": " << _ctx.demangle(undef->name())
+ << "\n";
+ }
+ }
+ if (!foundUndefines)
+ return false;
+ if (_ctx.printRemainingUndefines())
+ llvm::errs() << "symbol(s) not found\n";
+ return true;
+}
+
+// remove from _atoms all coaleseced away atoms
+void Resolver::removeCoalescedAwayAtoms() {
+ DEBUG_WITH_TYPE("resolver",
+ llvm::dbgs() << "******** Removing coalesced away atoms:\n");
+ ScopedTask task(getDefaultDomain(), "removeCoalescedAwayAtoms");
+ _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(),
+ [&](OwningAtomPtr<Atom> &a) {
+ return _symbolTable.isCoalescedAway(a.get()) ||
+ _deadAtoms.count(a.get());
+ }),
+ _atoms.end());
+}
+
+bool Resolver::resolve() {
+ DEBUG_WITH_TYPE("resolver",
+ llvm::dbgs() << "******** Resolving atom references:\n");
+ if (!resolveUndefines())
+ return false;
+ updateReferences();
+ deadStripOptimize();
+ 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(
+ llvm::MutableArrayRef<OwningAtomPtr<Atom>> all) {
+ ScopedTask task(getDefaultDomain(), "addAtoms");
+ DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "Resolver final atom list:\n");
+
+ for (OwningAtomPtr<Atom> &atom : all) {
+#ifndef NDEBUG
+ if (auto *definedAtom = dyn_cast<DefinedAtom>(atom.get())) {
+ DEBUG_WITH_TYPE("resolver", llvm::dbgs()
+ << llvm::format(" 0x%09lX", definedAtom)
+ << ", 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.get())
+ << ", name="
+ << atom.get()->name()
+ << "\n");
+ }
+#endif
+ addAtom(*atom.release());
+ }
+}
+
+} // namespace lld
diff --git a/contrib/llvm/tools/lld/lib/Core/SymbolTable.cpp b/contrib/llvm/tools/lld/lib/Core/SymbolTable.cpp
new file mode 100644
index 000000000000..51ae8d17181d
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/Core/SymbolTable.cpp
@@ -0,0 +1,291 @@
+//===- Core/SymbolTable.cpp - Main Symbol Table ---------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/SymbolTable.h"
+#include "lld/Common/LLVM.h"
+#include "lld/Core/AbsoluteAtom.h"
+#include "lld/Core/Atom.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/LinkingContext.h"
+#include "lld/Core/Resolver.h"
+#include "lld/Core/SharedLibraryAtom.h"
+#include "lld/Core/UndefinedAtom.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdlib>
+#include <vector>
+
+namespace lld {
+bool SymbolTable::add(const UndefinedAtom &atom) { return addByName(atom); }
+
+bool SymbolTable::add(const SharedLibraryAtom &atom) { return addByName(atom); }
+
+bool SymbolTable::add(const AbsoluteAtom &atom) { return addByName(atom); }
+
+bool SymbolTable::add(const DefinedAtom &atom) {
+ if (!atom.name().empty() &&
+ atom.scope() != DefinedAtom::scopeTranslationUnit) {
+ // Named atoms cannot be merged by content.
+ assert(atom.merge() != DefinedAtom::mergeByContent);
+ // Track named atoms that are not scoped to file (static).
+ return addByName(atom);
+ }
+ if (atom.merge() == DefinedAtom::mergeByContent) {
+ // Named atoms cannot be merged by content.
+ assert(atom.name().empty());
+ // Currently only read-only constants can be merged.
+ if (atom.permissions() == DefinedAtom::permR__)
+ return addByContent(atom);
+ // TODO: support mergeByContent of data atoms by comparing content & fixups.
+ }
+ return false;
+}
+
+enum NameCollisionResolution {
+ NCR_First,
+ NCR_Second,
+ NCR_DupDef,
+ NCR_DupUndef,
+ NCR_DupShLib,
+ NCR_Error
+};
+
+static NameCollisionResolution cases[4][4] = {
+ //regular absolute undef sharedLib
+ {
+ // first is regular
+ NCR_DupDef, NCR_Error, NCR_First, NCR_First
+ },
+ {
+ // first is absolute
+ NCR_Error, NCR_Error, NCR_First, NCR_First
+ },
+ {
+ // first is undef
+ NCR_Second, NCR_Second, NCR_DupUndef, NCR_Second
+ },
+ {
+ // first is sharedLib
+ NCR_Second, NCR_Second, NCR_First, NCR_DupShLib
+ }
+};
+
+static NameCollisionResolution collide(Atom::Definition first,
+ Atom::Definition second) {
+ return cases[first][second];
+}
+
+enum MergeResolution {
+ MCR_First,
+ MCR_Second,
+ MCR_Largest,
+ MCR_SameSize,
+ MCR_Error
+};
+
+static MergeResolution mergeCases[][6] = {
+ // no tentative weak weakAddress sameNameAndSize largest
+ {MCR_Error, MCR_First, MCR_First, MCR_First, MCR_SameSize, MCR_Largest}, // no
+ {MCR_Second, MCR_Largest, MCR_Second, MCR_Second, MCR_SameSize, MCR_Largest}, // tentative
+ {MCR_Second, MCR_First, MCR_First, MCR_Second, MCR_SameSize, MCR_Largest}, // weak
+ {MCR_Second, MCR_First, MCR_First, MCR_First, MCR_SameSize, MCR_Largest}, // weakAddress
+ {MCR_SameSize, MCR_SameSize, MCR_SameSize, MCR_SameSize, MCR_SameSize, MCR_SameSize}, // sameSize
+ {MCR_Largest, MCR_Largest, MCR_Largest, MCR_Largest, MCR_SameSize, MCR_Largest}, // largest
+};
+
+static MergeResolution mergeSelect(DefinedAtom::Merge first,
+ DefinedAtom::Merge second) {
+ assert(first != DefinedAtom::mergeByContent);
+ assert(second != DefinedAtom::mergeByContent);
+ return mergeCases[first][second];
+}
+
+bool SymbolTable::addByName(const Atom &newAtom) {
+ StringRef name = newAtom.name();
+ assert(!name.empty());
+ const Atom *existing = findByName(name);
+ if (existing == nullptr) {
+ // Name is not in symbol table yet, add it associate with this atom.
+ _nameTable[name] = &newAtom;
+ return true;
+ }
+
+ // Do nothing if the same object is added more than once.
+ if (existing == &newAtom)
+ return false;
+
+ // Name is already in symbol table and associated with another atom.
+ bool useNew = true;
+ switch (collide(existing->definition(), newAtom.definition())) {
+ case NCR_First:
+ useNew = false;
+ break;
+ case NCR_Second:
+ useNew = true;
+ break;
+ case NCR_DupDef: {
+ const auto *existingDef = cast<DefinedAtom>(existing);
+ const auto *newDef = cast<DefinedAtom>(&newAtom);
+ switch (mergeSelect(existingDef->merge(), newDef->merge())) {
+ case MCR_First:
+ useNew = false;
+ break;
+ case MCR_Second:
+ useNew = true;
+ break;
+ case MCR_Largest: {
+ uint64_t existingSize = existingDef->sectionSize();
+ uint64_t newSize = newDef->sectionSize();
+ useNew = (newSize >= existingSize);
+ break;
+ }
+ case MCR_SameSize: {
+ uint64_t existingSize = existingDef->sectionSize();
+ uint64_t newSize = newDef->sectionSize();
+ if (existingSize == newSize) {
+ useNew = true;
+ break;
+ }
+ llvm::errs() << "Size mismatch: "
+ << existing->name() << " (" << existingSize << ") "
+ << newAtom.name() << " (" << newSize << ")\n";
+ LLVM_FALLTHROUGH;
+ }
+ case MCR_Error:
+ llvm::errs() << "Duplicate symbols: "
+ << existing->name()
+ << ":"
+ << existing->file().path()
+ << " and "
+ << newAtom.name()
+ << ":"
+ << newAtom.file().path()
+ << "\n";
+ llvm::report_fatal_error("duplicate symbol error");
+ break;
+ }
+ break;
+ }
+ case NCR_DupUndef: {
+ const UndefinedAtom* existingUndef = cast<UndefinedAtom>(existing);
+ const UndefinedAtom* newUndef = cast<UndefinedAtom>(&newAtom);
+
+ bool sameCanBeNull = (existingUndef->canBeNull() == newUndef->canBeNull());
+ if (sameCanBeNull)
+ useNew = false;
+ else
+ useNew = (newUndef->canBeNull() < existingUndef->canBeNull());
+ break;
+ }
+ case NCR_DupShLib: {
+ useNew = false;
+ break;
+ }
+ case NCR_Error:
+ llvm::errs() << "SymbolTable: error while merging " << name << "\n";
+ llvm::report_fatal_error("duplicate symbol error");
+ break;
+ }
+
+ if (useNew) {
+ // Update name table to use new atom.
+ _nameTable[name] = &newAtom;
+ // Add existing atom to replacement table.
+ _replacedAtoms[existing] = &newAtom;
+ } else {
+ // New atom is not being used. Add it to replacement table.
+ _replacedAtoms[&newAtom] = existing;
+ }
+ return false;
+}
+
+unsigned SymbolTable::AtomMappingInfo::getHashValue(const DefinedAtom *atom) {
+ auto content = atom->rawContent();
+ return llvm::hash_combine(atom->size(),
+ atom->contentType(),
+ llvm::hash_combine_range(content.begin(),
+ content.end()));
+}
+
+bool SymbolTable::AtomMappingInfo::isEqual(const DefinedAtom * const l,
+ const DefinedAtom * const r) {
+ if (l == r)
+ return true;
+ if (l == getEmptyKey() || r == getEmptyKey())
+ return false;
+ if (l == getTombstoneKey() || r == getTombstoneKey())
+ return false;
+ if (l->contentType() != r->contentType())
+ return false;
+ if (l->size() != r->size())
+ return false;
+ if (l->sectionChoice() != r->sectionChoice())
+ return false;
+ if (l->sectionChoice() == DefinedAtom::sectionCustomRequired) {
+ if (!l->customSectionName().equals(r->customSectionName()))
+ return false;
+ }
+ ArrayRef<uint8_t> lc = l->rawContent();
+ ArrayRef<uint8_t> rc = r->rawContent();
+ return memcmp(lc.data(), rc.data(), lc.size()) == 0;
+}
+
+bool SymbolTable::addByContent(const DefinedAtom &newAtom) {
+ AtomContentSet::iterator pos = _contentTable.find(&newAtom);
+ if (pos == _contentTable.end()) {
+ _contentTable.insert(&newAtom);
+ return true;
+ }
+ const Atom* existing = *pos;
+ // New atom is not being used. Add it to replacement table.
+ _replacedAtoms[&newAtom] = existing;
+ return false;
+}
+
+const Atom *SymbolTable::findByName(StringRef sym) {
+ NameToAtom::iterator pos = _nameTable.find(sym);
+ if (pos == _nameTable.end())
+ return nullptr;
+ return pos->second;
+}
+
+const Atom *SymbolTable::replacement(const Atom *atom) {
+ // Find the replacement for a given atom. Atoms in _replacedAtoms
+ // may be chained, so find the last one.
+ for (;;) {
+ AtomToAtom::iterator pos = _replacedAtoms.find(atom);
+ if (pos == _replacedAtoms.end())
+ return atom;
+ atom = pos->second;
+ }
+}
+
+bool SymbolTable::isCoalescedAway(const Atom *atom) {
+ return _replacedAtoms.count(atom) > 0;
+}
+
+std::vector<const UndefinedAtom *> SymbolTable::undefines() {
+ std::vector<const UndefinedAtom *> ret;
+ for (auto it : _nameTable) {
+ const Atom *atom = it.second;
+ assert(atom != nullptr);
+ if (const auto *undef = dyn_cast<const UndefinedAtom>(atom))
+ if (_replacedAtoms.count(undef) == 0)
+ ret.push_back(undef);
+ }
+ return ret;
+}
+
+} // namespace lld
diff --git a/contrib/llvm/tools/lld/lib/Core/Writer.cpp b/contrib/llvm/tools/lld/lib/Core/Writer.cpp
new file mode 100644
index 000000000000..51f95bc5053a
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/Core/Writer.cpp
@@ -0,0 +1,18 @@
+//===- lib/Core/Writer.cpp ------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/Writer.h"
+
+namespace lld {
+
+Writer::Writer() = default;
+
+Writer::~Writer() = default;
+
+} // end namespace lld
diff --git a/contrib/llvm/tools/lld/lib/Driver/CMakeLists.txt b/contrib/llvm/tools/lld/lib/Driver/CMakeLists.txt
new file mode 100644
index 000000000000..ff67c282f47e
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/Driver/CMakeLists.txt
@@ -0,0 +1,23 @@
+set(LLVM_TARGET_DEFINITIONS DarwinLdOptions.td)
+tablegen(LLVM DarwinLdOptions.inc -gen-opt-parser-defs)
+add_public_tablegen_target(DriverOptionsTableGen)
+
+add_lld_library(lldDriver
+ DarwinLdDriver.cpp
+
+ ADDITIONAL_HEADER_DIRS
+ ${LLD_INCLUDE_DIR}/lld/Driver
+
+ LINK_COMPONENTS
+ Option
+ Support
+
+ LINK_LIBS
+ lldCommon
+ lldCore
+ lldMachO
+ lldReaderWriter
+ lldYAML
+ )
+
+add_dependencies(lldDriver DriverOptionsTableGen)
diff --git a/contrib/llvm/tools/lld/lib/Driver/DarwinLdDriver.cpp b/contrib/llvm/tools/lld/lib/Driver/DarwinLdDriver.cpp
new file mode 100644
index 000000000000..bbac230df453
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/Driver/DarwinLdDriver.cpp
@@ -0,0 +1,1230 @@
+//===- lib/Driver/DarwinLdDriver.cpp --------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+///
+/// Concrete instance of the Driver for darwin's ld.
+///
+//===----------------------------------------------------------------------===//
+
+#include "lld/Common/Args.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/LLVM.h"
+#include "lld/Core/ArchiveLibraryFile.h"
+#include "lld/Core/Error.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Instrumentation.h"
+#include "lld/Core/LinkingContext.h"
+#include "lld/Core/Node.h"
+#include "lld/Core/PassManager.h"
+#include "lld/Core/Resolver.h"
+#include "lld/Core/SharedLibraryFile.h"
+#include "lld/Core/Simple.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/OptTable.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <system_error>
+#include <utility>
+#include <vector>
+
+using namespace lld;
+
+namespace {
+
+// Create enum with OPT_xxx values for each option in DarwinLdOptions.td
+enum {
+ OPT_INVALID = 0,
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELP, META, VALUES) \
+ OPT_##ID,
+#include "DarwinLdOptions.inc"
+#undef OPTION
+};
+
+// Create prefix string literals used in DarwinLdOptions.td
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#include "DarwinLdOptions.inc"
+#undef PREFIX
+
+// Create table mapping all options defined in DarwinLdOptions.td
+static const llvm::opt::OptTable::Info InfoTable[] = {
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES) \
+ {PREFIX, NAME, HELPTEXT, \
+ METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \
+ PARAM, FLAGS, OPT_##GROUP, \
+ OPT_##ALIAS, ALIASARGS, VALUES},
+#include "DarwinLdOptions.inc"
+#undef OPTION
+};
+
+// Create OptTable class for parsing actual command line arguments
+class DarwinLdOptTable : public llvm::opt::OptTable {
+public:
+ DarwinLdOptTable() : OptTable(InfoTable) {}
+};
+
+static std::vector<std::unique_ptr<File>>
+makeErrorFile(StringRef path, std::error_code ec) {
+ std::vector<std::unique_ptr<File>> result;
+ result.push_back(llvm::make_unique<ErrorFile>(path, ec));
+ return result;
+}
+
+static std::vector<std::unique_ptr<File>>
+parseMemberFiles(std::unique_ptr<File> file) {
+ std::vector<std::unique_ptr<File>> members;
+ if (auto *archive = dyn_cast<ArchiveLibraryFile>(file.get())) {
+ if (std::error_code ec = archive->parseAllMembers(members))
+ return makeErrorFile(file->path(), ec);
+ } else {
+ members.push_back(std::move(file));
+ }
+ return members;
+}
+
+std::vector<std::unique_ptr<File>> loadFile(MachOLinkingContext &ctx,
+ StringRef path, bool wholeArchive,
+ bool upwardDylib) {
+ if (ctx.logInputFiles())
+ message(path);
+
+ ErrorOr<std::unique_ptr<MemoryBuffer>> mbOrErr = ctx.getMemoryBuffer(path);
+ if (std::error_code ec = mbOrErr.getError())
+ return makeErrorFile(path, ec);
+ ErrorOr<std::unique_ptr<File>> fileOrErr =
+ ctx.registry().loadFile(std::move(mbOrErr.get()));
+ if (std::error_code ec = fileOrErr.getError())
+ return makeErrorFile(path, ec);
+ 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(std::move(file));
+ std::vector<std::unique_ptr<File>> files;
+ files.push_back(std::move(file));
+ return files;
+}
+
+} // end anonymous namespace
+
+// Test may be running on Windows. Canonicalize the path
+// separator to '/' to get consistent outputs for tests.
+static std::string canonicalizePath(StringRef path) {
+ char sep = llvm::sys::path::get_separator().front();
+ if (sep != '/') {
+ std::string fixedPath = path;
+ std::replace(fixedPath.begin(), fixedPath.end(), sep, '/');
+ return fixedPath;
+ } else {
+ return path;
+ }
+}
+
+static void addFile(StringRef path, MachOLinkingContext &ctx,
+ bool loadWholeArchive, bool upwardDylib) {
+ std::vector<std::unique_ptr<File>> files =
+ loadFile(ctx, path, loadWholeArchive, upwardDylib);
+ for (std::unique_ptr<File> &file : files)
+ ctx.getNodes().push_back(llvm::make_unique<FileNode>(std::move(file)));
+}
+
+// Export lists are one symbol per line. Blank lines are ignored.
+// Trailing comments start with #.
+static std::error_code parseExportsList(StringRef exportFilePath,
+ MachOLinkingContext &ctx) {
+ // Map in export list file.
+ ErrorOr<std::unique_ptr<MemoryBuffer>> mb =
+ MemoryBuffer::getFileOrSTDIN(exportFilePath);
+ if (std::error_code ec = mb.getError())
+ return ec;
+ ctx.addInputFileDependency(exportFilePath);
+ StringRef buffer = mb->get()->getBuffer();
+ while (!buffer.empty()) {
+ // Split off each line in the file.
+ std::pair<StringRef, StringRef> lineAndRest = buffer.split('\n');
+ StringRef line = lineAndRest.first;
+ // Ignore trailing # comments.
+ std::pair<StringRef, StringRef> symAndComment = line.split('#');
+ StringRef sym = symAndComment.first.trim();
+ if (!sym.empty())
+ ctx.addExportSymbol(sym);
+ buffer = lineAndRest.second;
+ }
+ return std::error_code();
+}
+
+/// Order files are one symbol per line. Blank lines are ignored.
+/// Trailing comments start with #. Symbol names can be prefixed with an
+/// architecture name and/or .o leaf name. Examples:
+/// _foo
+/// bar.o:_bar
+/// libfrob.a(bar.o):_bar
+/// x86_64:_foo64
+static std::error_code parseOrderFile(StringRef orderFilePath,
+ MachOLinkingContext &ctx) {
+ // Map in order file.
+ ErrorOr<std::unique_ptr<MemoryBuffer>> mb =
+ MemoryBuffer::getFileOrSTDIN(orderFilePath);
+ if (std::error_code ec = mb.getError())
+ return ec;
+ ctx.addInputFileDependency(orderFilePath);
+ StringRef buffer = mb->get()->getBuffer();
+ while (!buffer.empty()) {
+ // Split off each line in the file.
+ std::pair<StringRef, StringRef> lineAndRest = buffer.split('\n');
+ StringRef line = lineAndRest.first;
+ buffer = lineAndRest.second;
+ // Ignore trailing # comments.
+ std::pair<StringRef, StringRef> symAndComment = line.split('#');
+ if (symAndComment.first.empty())
+ continue;
+ StringRef sym = symAndComment.first.trim();
+ if (sym.empty())
+ continue;
+ // Check for prefix.
+ StringRef prefix;
+ std::pair<StringRef, StringRef> prefixAndSym = sym.split(':');
+ if (!prefixAndSym.second.empty()) {
+ sym = prefixAndSym.second;
+ prefix = prefixAndSym.first;
+ if (!prefix.endswith(".o") && !prefix.endswith(".o)")) {
+ // If arch name prefix does not match arch being linked, ignore symbol.
+ if (!ctx.archName().equals(prefix))
+ continue;
+ prefix = "";
+ }
+ } else
+ sym = prefixAndSym.first;
+ if (!sym.empty()) {
+ ctx.appendOrderedSymbol(sym, prefix);
+ //llvm::errs() << sym << ", prefix=" << prefix << "\n";
+ }
+ }
+ return std::error_code();
+}
+
+//
+// There are two variants of the -filelist option:
+//
+// -filelist <path>
+// In this variant, the path is to a text file which contains one file path
+// per line. There are no comments or trimming of whitespace.
+//
+// -fileList <path>,<dir>
+// In this variant, the path is to a text file which contains a partial path
+// per line. The <dir> prefix is prepended to each partial path.
+//
+static llvm::Error loadFileList(StringRef fileListPath,
+ MachOLinkingContext &ctx, bool forceLoad) {
+ // If there is a comma, split off <dir>.
+ std::pair<StringRef, StringRef> opt = fileListPath.split(',');
+ StringRef filePath = opt.first;
+ StringRef dirName = opt.second;
+ ctx.addInputFileDependency(filePath);
+ // Map in file list file.
+ ErrorOr<std::unique_ptr<MemoryBuffer>> mb =
+ MemoryBuffer::getFileOrSTDIN(filePath);
+ if (std::error_code ec = mb.getError())
+ return llvm::errorCodeToError(ec);
+ StringRef buffer = mb->get()->getBuffer();
+ while (!buffer.empty()) {
+ // Split off each line in the file.
+ std::pair<StringRef, StringRef> lineAndRest = buffer.split('\n');
+ StringRef line = lineAndRest.first;
+ StringRef path;
+ if (!dirName.empty()) {
+ // If there is a <dir> then prepend dir to each line.
+ SmallString<256> fullPath;
+ fullPath.assign(dirName);
+ llvm::sys::path::append(fullPath, Twine(line));
+ path = ctx.copy(fullPath.str());
+ } else {
+ // No <dir> use whole line as input file path.
+ path = ctx.copy(line);
+ }
+ if (!ctx.pathExists(path)) {
+ return llvm::make_error<GenericError>(Twine("File not found '")
+ + path
+ + "'");
+ }
+ if (ctx.testingFileUsage()) {
+ message("Found filelist entry " + canonicalizePath(path));
+ }
+ addFile(path, ctx, forceLoad, false);
+ buffer = lineAndRest.second;
+ }
+ return llvm::Error::success();
+}
+
+/// Parse number assuming it is base 16, but allow 0x prefix.
+static bool parseNumberBase16(StringRef numStr, uint64_t &baseAddress) {
+ if (numStr.startswith_lower("0x"))
+ numStr = numStr.drop_front(2);
+ return numStr.getAsInteger(16, baseAddress);
+}
+
+static void parseLLVMOptions(const LinkingContext &ctx) {
+ // Honor -mllvm
+ if (!ctx.llvmOptions().empty()) {
+ unsigned numArgs = ctx.llvmOptions().size();
+ auto **args = new const char *[numArgs + 2];
+ args[0] = "lld (LLVM option parsing)";
+ for (unsigned i = 0; i != numArgs; ++i)
+ args[i + 1] = ctx.llvmOptions()[i];
+ args[numArgs + 1] = nullptr;
+ llvm::cl::ParseCommandLineOptions(numArgs + 1, args);
+ }
+}
+
+namespace lld {
+namespace mach_o {
+
+bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx) {
+ // Parse command line options using DarwinLdOptions.td
+ DarwinLdOptTable table;
+ unsigned missingIndex;
+ unsigned missingCount;
+ llvm::opt::InputArgList parsedArgs =
+ table.ParseArgs(args.slice(1), missingIndex, missingCount);
+ if (missingCount) {
+ error("missing arg value for '" +
+ Twine(parsedArgs.getArgString(missingIndex)) + "' expected " +
+ Twine(missingCount) + " argument(s).");
+ return false;
+ }
+
+ for (auto unknownArg : parsedArgs.filtered(OPT_UNKNOWN)) {
+ warn("ignoring unknown argument: " +
+ Twine(unknownArg->getAsString(parsedArgs)));
+ }
+
+ errorHandler().Verbose = parsedArgs.hasArg(OPT_v);
+ errorHandler().ErrorLimit = args::getInteger(parsedArgs, OPT_error_limit, 20);
+
+ // Figure out output kind ( -dylib, -r, -bundle, -preload, or -static )
+ llvm::MachO::HeaderFileType fileType = llvm::MachO::MH_EXECUTE;
+ bool isStaticExecutable = false;
+ if (llvm::opt::Arg *kind = parsedArgs.getLastArg(
+ OPT_dylib, OPT_relocatable, OPT_bundle, OPT_static, OPT_preload)) {
+ switch (kind->getOption().getID()) {
+ case OPT_dylib:
+ fileType = llvm::MachO::MH_DYLIB;
+ break;
+ case OPT_relocatable:
+ fileType = llvm::MachO::MH_OBJECT;
+ break;
+ case OPT_bundle:
+ fileType = llvm::MachO::MH_BUNDLE;
+ break;
+ case OPT_static:
+ fileType = llvm::MachO::MH_EXECUTE;
+ isStaticExecutable = true;
+ break;
+ case OPT_preload:
+ fileType = llvm::MachO::MH_PRELOAD;
+ break;
+ }
+ }
+
+ // Handle -arch xxx
+ MachOLinkingContext::Arch arch = MachOLinkingContext::arch_unknown;
+ if (llvm::opt::Arg *archStr = parsedArgs.getLastArg(OPT_arch)) {
+ arch = MachOLinkingContext::archFromName(archStr->getValue());
+ if (arch == MachOLinkingContext::arch_unknown) {
+ error("unknown arch named '" + Twine(archStr->getValue()) + "'");
+ return false;
+ }
+ }
+ // If no -arch specified, scan input files to find first non-fat .o file.
+ if (arch == MachOLinkingContext::arch_unknown) {
+ for (auto &inFile : parsedArgs.filtered(OPT_INPUT)) {
+ // This is expensive because it opens and maps the file. But that is
+ // ok because no -arch is rare.
+ if (MachOLinkingContext::isThinObjectFile(inFile->getValue(), arch))
+ break;
+ }
+ if (arch == MachOLinkingContext::arch_unknown &&
+ !parsedArgs.getLastArg(OPT_test_file_usage)) {
+ // If no -arch and no options at all, print usage message.
+ if (parsedArgs.size() == 0) {
+ table.PrintHelp(llvm::outs(),
+ (std::string(args[0]) + " [options] file...").c_str(),
+ "LLVM Linker", false);
+ } else {
+ error("-arch not specified and could not be inferred");
+ }
+ return false;
+ }
+ }
+
+ // Handle -macosx_version_min or -ios_version_min
+ MachOLinkingContext::OS os = MachOLinkingContext::OS::unknown;
+ uint32_t minOSVersion = 0;
+ if (llvm::opt::Arg *minOS =
+ parsedArgs.getLastArg(OPT_macosx_version_min, OPT_ios_version_min,
+ OPT_ios_simulator_version_min)) {
+ switch (minOS->getOption().getID()) {
+ case OPT_macosx_version_min:
+ os = MachOLinkingContext::OS::macOSX;
+ if (MachOLinkingContext::parsePackedVersion(minOS->getValue(),
+ minOSVersion)) {
+ error("malformed macosx_version_min value");
+ return false;
+ }
+ break;
+ case OPT_ios_version_min:
+ os = MachOLinkingContext::OS::iOS;
+ if (MachOLinkingContext::parsePackedVersion(minOS->getValue(),
+ minOSVersion)) {
+ error("malformed ios_version_min value");
+ return false;
+ }
+ break;
+ case OPT_ios_simulator_version_min:
+ os = MachOLinkingContext::OS::iOS_simulator;
+ if (MachOLinkingContext::parsePackedVersion(minOS->getValue(),
+ minOSVersion)) {
+ error("malformed ios_simulator_version_min value");
+ return false;
+ }
+ break;
+ }
+ } else {
+ // No min-os version on command line, check environment variables
+ }
+
+ // Handle export_dynamic
+ // FIXME: Should we warn when this applies to something other than a static
+ // executable or dylib? Those are the only cases where this has an effect.
+ // Note, this has to come before ctx.configure() so that we get the correct
+ // value for _globalsAreDeadStripRoots.
+ bool exportDynamicSymbols = parsedArgs.hasArg(OPT_export_dynamic);
+
+ // Now that there's enough information parsed in, let the linking context
+ // set up default values.
+ ctx.configure(fileType, arch, os, minOSVersion, exportDynamicSymbols);
+
+ // Handle -e xxx
+ if (llvm::opt::Arg *entry = parsedArgs.getLastArg(OPT_entry))
+ ctx.setEntrySymbolName(entry->getValue());
+
+ // Handle -o xxx
+ if (llvm::opt::Arg *outpath = parsedArgs.getLastArg(OPT_output))
+ ctx.setOutputPath(outpath->getValue());
+ else
+ ctx.setOutputPath("a.out");
+
+ // Handle -image_base XXX and -seg1addr XXXX
+ if (llvm::opt::Arg *imageBase = parsedArgs.getLastArg(OPT_image_base)) {
+ uint64_t baseAddress;
+ if (parseNumberBase16(imageBase->getValue(), baseAddress)) {
+ error("image_base expects a hex number");
+ return false;
+ } else if (baseAddress < ctx.pageZeroSize()) {
+ error("image_base overlaps with __PAGEZERO");
+ return false;
+ } else if (baseAddress % ctx.pageSize()) {
+ error("image_base must be a multiple of page size (0x" +
+ llvm::utohexstr(ctx.pageSize()) + ")");
+ return false;
+ }
+
+ ctx.setBaseAddress(baseAddress);
+ }
+
+ // Handle -dead_strip
+ if (parsedArgs.getLastArg(OPT_dead_strip))
+ ctx.setDeadStripping(true);
+
+ bool globalWholeArchive = false;
+ // Handle -all_load
+ if (parsedArgs.getLastArg(OPT_all_load))
+ globalWholeArchive = true;
+
+ // Handle -install_name
+ if (llvm::opt::Arg *installName = parsedArgs.getLastArg(OPT_install_name))
+ ctx.setInstallName(installName->getValue());
+ else
+ ctx.setInstallName(ctx.outputPath());
+
+ // Handle -mark_dead_strippable_dylib
+ if (parsedArgs.getLastArg(OPT_mark_dead_strippable_dylib))
+ ctx.setDeadStrippableDylib(true);
+
+ // Handle -compatibility_version and -current_version
+ if (llvm::opt::Arg *vers = parsedArgs.getLastArg(OPT_compatibility_version)) {
+ if (ctx.outputMachOType() != llvm::MachO::MH_DYLIB) {
+ error("-compatibility_version can only be used with -dylib");
+ return false;
+ }
+ uint32_t parsedVers;
+ if (MachOLinkingContext::parsePackedVersion(vers->getValue(), parsedVers)) {
+ error("-compatibility_version value is malformed");
+ return false;
+ }
+ ctx.setCompatibilityVersion(parsedVers);
+ }
+
+ if (llvm::opt::Arg *vers = parsedArgs.getLastArg(OPT_current_version)) {
+ if (ctx.outputMachOType() != llvm::MachO::MH_DYLIB) {
+ error("-current_version can only be used with -dylib");
+ return false;
+ }
+ uint32_t parsedVers;
+ if (MachOLinkingContext::parsePackedVersion(vers->getValue(), parsedVers)) {
+ error("-current_version value is malformed");
+ return false;
+ }
+ ctx.setCurrentVersion(parsedVers);
+ }
+
+ // Handle -bundle_loader
+ if (llvm::opt::Arg *loader = parsedArgs.getLastArg(OPT_bundle_loader))
+ ctx.setBundleLoader(loader->getValue());
+
+ // Handle -sectalign segname sectname align
+ for (auto &alignArg : parsedArgs.filtered(OPT_sectalign)) {
+ const char* segName = alignArg->getValue(0);
+ const char* sectName = alignArg->getValue(1);
+ const char* alignStr = alignArg->getValue(2);
+ if ((alignStr[0] == '0') && (alignStr[1] == 'x'))
+ alignStr += 2;
+ unsigned long long alignValue;
+ if (llvm::getAsUnsignedInteger(alignStr, 16, alignValue)) {
+ error("-sectalign alignment value '" + Twine(alignStr) +
+ "' not a valid number");
+ return false;
+ }
+ uint16_t align = 1 << llvm::countTrailingZeros(alignValue);
+ if (!llvm::isPowerOf2_64(alignValue)) {
+ std::string Msg;
+ llvm::raw_string_ostream OS(Msg);
+ OS << "alignment for '-sectalign " << segName << " " << sectName
+ << llvm::format(" 0x%llX", alignValue)
+ << "' is not a power of two, using " << llvm::format("0x%08X", align);
+ OS.flush();
+ warn(Msg);
+ }
+ ctx.addSectionAlignment(segName, sectName, align);
+ }
+
+ // Handle -mllvm
+ for (auto &llvmArg : parsedArgs.filtered(OPT_mllvm)) {
+ ctx.appendLLVMOption(llvmArg->getValue());
+ }
+
+ // Handle -print_atoms
+ if (parsedArgs.getLastArg(OPT_print_atoms))
+ ctx.setPrintAtoms();
+
+ // Handle -t (trace) option.
+ if (parsedArgs.getLastArg(OPT_t))
+ ctx.setLogInputFiles(true);
+
+ // Handle -demangle option.
+ if (parsedArgs.getLastArg(OPT_demangle))
+ ctx.setDemangleSymbols(true);
+
+ // Handle -keep_private_externs
+ if (parsedArgs.getLastArg(OPT_keep_private_externs)) {
+ ctx.setKeepPrivateExterns(true);
+ if (ctx.outputMachOType() != llvm::MachO::MH_OBJECT)
+ warn("-keep_private_externs only used in -r mode");
+ }
+
+ // Handle -dependency_info <path> used by Xcode.
+ if (llvm::opt::Arg *depInfo = parsedArgs.getLastArg(OPT_dependency_info))
+ if (std::error_code ec = ctx.createDependencyFile(depInfo->getValue()))
+ warn(ec.message() + ", processing '-dependency_info " +
+ depInfo->getValue());
+
+ // In -test_file_usage mode, we'll be given an explicit list of paths that
+ // exist. We'll also be expected to print out information about how we located
+ // libraries and so on that the user specified, but not to actually do any
+ // linking.
+ if (parsedArgs.getLastArg(OPT_test_file_usage)) {
+ ctx.setTestingFileUsage();
+
+ // With paths existing by fiat, linking is not going to end well.
+ ctx.setDoNothing(true);
+
+ // Only bother looking for an existence override if we're going to use it.
+ for (auto existingPath : parsedArgs.filtered(OPT_path_exists)) {
+ ctx.addExistingPathForDebug(existingPath->getValue());
+ }
+ }
+
+ // Register possible input file parsers.
+ if (!ctx.doNothing()) {
+ ctx.registry().addSupportMachOObjects(ctx);
+ ctx.registry().addSupportArchives(ctx.logInputFiles());
+ ctx.registry().addSupportYamlFiles();
+ }
+
+ // Now construct the set of library search directories, following ld64's
+ // baroque set of accumulated hacks. Mostly, the algorithm constructs
+ // { syslibroots } x { libpaths }
+ //
+ // Unfortunately, there are numerous exceptions:
+ // 1. Only absolute paths get modified by syslibroot options.
+ // 2. If there is just 1 -syslibroot, system paths not found in it are
+ // skipped.
+ // 3. If the last -syslibroot is "/", all of them are ignored entirely.
+ // 4. If { syslibroots } x path == {}, the original path is kept.
+ std::vector<StringRef> sysLibRoots;
+ for (auto syslibRoot : parsedArgs.filtered(OPT_syslibroot)) {
+ sysLibRoots.push_back(syslibRoot->getValue());
+ }
+ if (!sysLibRoots.empty()) {
+ // Ignore all if last -syslibroot is "/".
+ if (sysLibRoots.back() != "/")
+ ctx.setSysLibRoots(sysLibRoots);
+ }
+
+ // Paths specified with -L come first, and are not considered system paths for
+ // the case where there is precisely 1 -syslibroot.
+ for (auto libPath : parsedArgs.filtered(OPT_L)) {
+ ctx.addModifiedSearchDir(libPath->getValue());
+ }
+
+ // Process -F directories (where to look for frameworks).
+ for (auto fwPath : parsedArgs.filtered(OPT_F)) {
+ ctx.addFrameworkSearchDir(fwPath->getValue());
+ }
+
+ // -Z suppresses the standard search paths.
+ if (!parsedArgs.hasArg(OPT_Z)) {
+ ctx.addModifiedSearchDir("/usr/lib", true);
+ ctx.addModifiedSearchDir("/usr/local/lib", true);
+ ctx.addFrameworkSearchDir("/Library/Frameworks", true);
+ ctx.addFrameworkSearchDir("/System/Library/Frameworks", true);
+ }
+
+ // Now that we've constructed the final set of search paths, print out those
+ // search paths in verbose mode.
+ if (errorHandler().Verbose) {
+ message("Library search paths:");
+ for (auto path : ctx.searchDirs()) {
+ message(" " + path);
+ }
+ message("Framework search paths:");
+ for (auto path : ctx.frameworkDirs()) {
+ message(" " + path);
+ }
+ }
+
+ // Handle -exported_symbols_list <file>
+ for (auto expFile : parsedArgs.filtered(OPT_exported_symbols_list)) {
+ if (ctx.exportMode() == MachOLinkingContext::ExportMode::blackList) {
+ error("-exported_symbols_list cannot be combined with "
+ "-unexported_symbol[s_list]");
+ return false;
+ }
+ ctx.setExportMode(MachOLinkingContext::ExportMode::whiteList);
+ if (std::error_code ec = parseExportsList(expFile->getValue(), ctx)) {
+ error(ec.message() + ", processing '-exported_symbols_list " +
+ expFile->getValue());
+ return false;
+ }
+ }
+
+ // Handle -exported_symbol <symbol>
+ for (auto symbol : parsedArgs.filtered(OPT_exported_symbol)) {
+ if (ctx.exportMode() == MachOLinkingContext::ExportMode::blackList) {
+ error("-exported_symbol cannot be combined with "
+ "-unexported_symbol[s_list]");
+ return false;
+ }
+ ctx.setExportMode(MachOLinkingContext::ExportMode::whiteList);
+ ctx.addExportSymbol(symbol->getValue());
+ }
+
+ // Handle -unexported_symbols_list <file>
+ for (auto expFile : parsedArgs.filtered(OPT_unexported_symbols_list)) {
+ if (ctx.exportMode() == MachOLinkingContext::ExportMode::whiteList) {
+ error("-unexported_symbols_list cannot be combined with "
+ "-exported_symbol[s_list]");
+ return false;
+ }
+ ctx.setExportMode(MachOLinkingContext::ExportMode::blackList);
+ if (std::error_code ec = parseExportsList(expFile->getValue(), ctx)) {
+ error(ec.message() + ", processing '-unexported_symbols_list " +
+ expFile->getValue());
+ return false;
+ }
+ }
+
+ // Handle -unexported_symbol <symbol>
+ for (auto symbol : parsedArgs.filtered(OPT_unexported_symbol)) {
+ if (ctx.exportMode() == MachOLinkingContext::ExportMode::whiteList) {
+ error("-unexported_symbol cannot be combined with "
+ "-exported_symbol[s_list]");
+ return false;
+ }
+ ctx.setExportMode(MachOLinkingContext::ExportMode::blackList);
+ ctx.addExportSymbol(symbol->getValue());
+ }
+
+ // Handle obosolete -multi_module and -single_module
+ if (llvm::opt::Arg *mod =
+ parsedArgs.getLastArg(OPT_multi_module, OPT_single_module)) {
+ if (mod->getOption().getID() == OPT_multi_module)
+ warn("-multi_module is obsolete and being ignored");
+ else if (ctx.outputMachOType() != llvm::MachO::MH_DYLIB)
+ warn("-single_module being ignored. It is only for use when producing a "
+ "dylib");
+ }
+
+ // Handle obsolete ObjC options: -objc_gc_compaction, -objc_gc, -objc_gc_only
+ if (parsedArgs.getLastArg(OPT_objc_gc_compaction)) {
+ error("-objc_gc_compaction is not supported");
+ return false;
+ }
+
+ if (parsedArgs.getLastArg(OPT_objc_gc)) {
+ error("-objc_gc is not supported");
+ return false;
+ }
+
+ if (parsedArgs.getLastArg(OPT_objc_gc_only)) {
+ error("-objc_gc_only is not supported");
+ return false;
+ }
+
+ // Handle -pie or -no_pie
+ if (llvm::opt::Arg *pie = parsedArgs.getLastArg(OPT_pie, OPT_no_pie)) {
+ switch (ctx.outputMachOType()) {
+ case llvm::MachO::MH_EXECUTE:
+ switch (ctx.os()) {
+ case MachOLinkingContext::OS::macOSX:
+ if ((minOSVersion < 0x000A0500) &&
+ (pie->getOption().getID() == OPT_pie)) {
+ error("-pie can only be used when targeting Mac OS X 10.5 or later");
+ return false;
+ }
+ break;
+ case MachOLinkingContext::OS::iOS:
+ if ((minOSVersion < 0x00040200) &&
+ (pie->getOption().getID() == OPT_pie)) {
+ error("-pie can only be used when targeting iOS 4.2 or later");
+ return false;
+ }
+ break;
+ case MachOLinkingContext::OS::iOS_simulator:
+ if (pie->getOption().getID() == OPT_no_pie) {
+ error("iOS simulator programs must be built PIE");
+ return false;
+ }
+ break;
+ case MachOLinkingContext::OS::unknown:
+ break;
+ }
+ ctx.setPIE(pie->getOption().getID() == OPT_pie);
+ break;
+ case llvm::MachO::MH_PRELOAD:
+ break;
+ case llvm::MachO::MH_DYLIB:
+ case llvm::MachO::MH_BUNDLE:
+ warn(pie->getSpelling() +
+ " being ignored. It is only used when linking main executables");
+ break;
+ default:
+ error(pie->getSpelling() +
+ " can only used when linking main executables");
+ return false;
+ }
+ }
+
+ // Handle -version_load_command or -no_version_load_command
+ {
+ bool flagOn = false;
+ bool flagOff = false;
+ if (auto *arg = parsedArgs.getLastArg(OPT_version_load_command,
+ OPT_no_version_load_command)) {
+ flagOn = arg->getOption().getID() == OPT_version_load_command;
+ flagOff = arg->getOption().getID() == OPT_no_version_load_command;
+ }
+
+ // default to adding version load command for dynamic code,
+ // static code must opt-in
+ switch (ctx.outputMachOType()) {
+ case llvm::MachO::MH_OBJECT:
+ ctx.setGenerateVersionLoadCommand(false);
+ break;
+ case llvm::MachO::MH_EXECUTE:
+ // dynamic executables default to generating a version load command,
+ // while static exectuables only generate it if required.
+ if (isStaticExecutable) {
+ if (flagOn)
+ ctx.setGenerateVersionLoadCommand(true);
+ } else {
+ if (!flagOff)
+ ctx.setGenerateVersionLoadCommand(true);
+ }
+ break;
+ case llvm::MachO::MH_PRELOAD:
+ case llvm::MachO::MH_KEXT_BUNDLE:
+ if (flagOn)
+ ctx.setGenerateVersionLoadCommand(true);
+ break;
+ case llvm::MachO::MH_DYLINKER:
+ case llvm::MachO::MH_DYLIB:
+ case llvm::MachO::MH_BUNDLE:
+ if (!flagOff)
+ ctx.setGenerateVersionLoadCommand(true);
+ break;
+ case llvm::MachO::MH_FVMLIB:
+ case llvm::MachO::MH_DYLDLINK:
+ case llvm::MachO::MH_DYLIB_STUB:
+ case llvm::MachO::MH_DSYM:
+ // We don't generate load commands for these file types, even if
+ // forced on.
+ break;
+ }
+ }
+
+ // Handle -function_starts or -no_function_starts
+ {
+ bool flagOn = false;
+ bool flagOff = false;
+ if (auto *arg = parsedArgs.getLastArg(OPT_function_starts,
+ OPT_no_function_starts)) {
+ flagOn = arg->getOption().getID() == OPT_function_starts;
+ flagOff = arg->getOption().getID() == OPT_no_function_starts;
+ }
+
+ // default to adding functions start for dynamic code, static code must
+ // opt-in
+ switch (ctx.outputMachOType()) {
+ case llvm::MachO::MH_OBJECT:
+ ctx.setGenerateFunctionStartsLoadCommand(false);
+ break;
+ case llvm::MachO::MH_EXECUTE:
+ // dynamic executables default to generating a version load command,
+ // while static exectuables only generate it if required.
+ if (isStaticExecutable) {
+ if (flagOn)
+ ctx.setGenerateFunctionStartsLoadCommand(true);
+ } else {
+ if (!flagOff)
+ ctx.setGenerateFunctionStartsLoadCommand(true);
+ }
+ break;
+ case llvm::MachO::MH_PRELOAD:
+ case llvm::MachO::MH_KEXT_BUNDLE:
+ if (flagOn)
+ ctx.setGenerateFunctionStartsLoadCommand(true);
+ break;
+ case llvm::MachO::MH_DYLINKER:
+ case llvm::MachO::MH_DYLIB:
+ case llvm::MachO::MH_BUNDLE:
+ if (!flagOff)
+ ctx.setGenerateFunctionStartsLoadCommand(true);
+ break;
+ case llvm::MachO::MH_FVMLIB:
+ case llvm::MachO::MH_DYLDLINK:
+ case llvm::MachO::MH_DYLIB_STUB:
+ case llvm::MachO::MH_DSYM:
+ // We don't generate load commands for these file types, even if
+ // forced on.
+ break;
+ }
+ }
+
+ // Handle -data_in_code_info or -no_data_in_code_info
+ {
+ bool flagOn = false;
+ bool flagOff = false;
+ if (auto *arg = parsedArgs.getLastArg(OPT_data_in_code_info,
+ OPT_no_data_in_code_info)) {
+ flagOn = arg->getOption().getID() == OPT_data_in_code_info;
+ flagOff = arg->getOption().getID() == OPT_no_data_in_code_info;
+ }
+
+ // default to adding data in code for dynamic code, static code must
+ // opt-in
+ switch (ctx.outputMachOType()) {
+ case llvm::MachO::MH_OBJECT:
+ if (!flagOff)
+ ctx.setGenerateDataInCodeLoadCommand(true);
+ break;
+ case llvm::MachO::MH_EXECUTE:
+ // dynamic executables default to generating a version load command,
+ // while static exectuables only generate it if required.
+ if (isStaticExecutable) {
+ if (flagOn)
+ ctx.setGenerateDataInCodeLoadCommand(true);
+ } else {
+ if (!flagOff)
+ ctx.setGenerateDataInCodeLoadCommand(true);
+ }
+ break;
+ case llvm::MachO::MH_PRELOAD:
+ case llvm::MachO::MH_KEXT_BUNDLE:
+ if (flagOn)
+ ctx.setGenerateDataInCodeLoadCommand(true);
+ break;
+ case llvm::MachO::MH_DYLINKER:
+ case llvm::MachO::MH_DYLIB:
+ case llvm::MachO::MH_BUNDLE:
+ if (!flagOff)
+ ctx.setGenerateDataInCodeLoadCommand(true);
+ break;
+ case llvm::MachO::MH_FVMLIB:
+ case llvm::MachO::MH_DYLDLINK:
+ case llvm::MachO::MH_DYLIB_STUB:
+ case llvm::MachO::MH_DSYM:
+ // We don't generate load commands for these file types, even if
+ // forced on.
+ break;
+ }
+ }
+
+ // Handle sdk_version
+ if (llvm::opt::Arg *arg = parsedArgs.getLastArg(OPT_sdk_version)) {
+ uint32_t sdkVersion = 0;
+ if (MachOLinkingContext::parsePackedVersion(arg->getValue(),
+ sdkVersion)) {
+ error("malformed sdkVersion value");
+ return false;
+ }
+ ctx.setSdkVersion(sdkVersion);
+ } else if (ctx.generateVersionLoadCommand()) {
+ // If we don't have an sdk version, but were going to emit a load command
+ // with min_version, then we need to give an warning as we have no sdk
+ // version to put in that command.
+ // FIXME: We need to decide whether to make this an error.
+ warn("-sdk_version is required when emitting min version load command. "
+ "Setting sdk version to match provided min version");
+ ctx.setSdkVersion(ctx.osMinVersion());
+ }
+
+ // Handle source_version
+ if (llvm::opt::Arg *arg = parsedArgs.getLastArg(OPT_source_version)) {
+ uint64_t version = 0;
+ if (MachOLinkingContext::parsePackedVersion(arg->getValue(),
+ version)) {
+ error("malformed source_version value");
+ return false;
+ }
+ ctx.setSourceVersion(version);
+ }
+
+ // Handle stack_size
+ if (llvm::opt::Arg *stackSize = parsedArgs.getLastArg(OPT_stack_size)) {
+ uint64_t stackSizeVal;
+ if (parseNumberBase16(stackSize->getValue(), stackSizeVal)) {
+ error("stack_size expects a hex number");
+ return false;
+ }
+ if ((stackSizeVal % ctx.pageSize()) != 0) {
+ error("stack_size must be a multiple of page size (0x" +
+ llvm::utohexstr(ctx.pageSize()) + ")");
+ return false;
+ }
+
+ ctx.setStackSize(stackSizeVal);
+ }
+
+ // Handle debug info handling options: -S
+ if (parsedArgs.hasArg(OPT_S))
+ ctx.setDebugInfoMode(MachOLinkingContext::DebugInfoMode::noDebugMap);
+
+ // Handle -order_file <file>
+ for (auto orderFile : parsedArgs.filtered(OPT_order_file)) {
+ if (std::error_code ec = parseOrderFile(orderFile->getValue(), ctx)) {
+ error(ec.message() + ", processing '-order_file " + orderFile->getValue()
+ + "'");
+ return false;
+ }
+ }
+
+ // 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 {
+ error("invalid option to -undefined [ warning | error | suppress | "
+ "dynamic_lookup ]");
+ 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) {
+ error("can't use -undefined warning or suppress with "
+ "-twolevel_namespace");
+ return false;
+ }
+ }
+
+ ctx.setUndefinedMode(UndefMode);
+ }
+
+ // Handle -no_objc_category_merging.
+ if (parsedArgs.getLastArg(OPT_no_objc_category_merging))
+ ctx.setMergeObjCCategories(false);
+
+ // Handle -rpath <path>
+ if (parsedArgs.hasArg(OPT_rpath)) {
+ switch (ctx.outputMachOType()) {
+ case llvm::MachO::MH_EXECUTE:
+ case llvm::MachO::MH_DYLIB:
+ case llvm::MachO::MH_BUNDLE:
+ if (!ctx.minOS("10.5", "2.0")) {
+ if (ctx.os() == MachOLinkingContext::OS::macOSX)
+ error("-rpath can only be used when targeting OS X 10.5 or later");
+ else
+ error("-rpath can only be used when targeting iOS 2.0 or later");
+ return false;
+ }
+ break;
+ default:
+ error("-rpath can only be used when creating a dynamic final linked "
+ "image");
+ return false;
+ }
+
+ for (auto rPath : parsedArgs.filtered(OPT_rpath)) {
+ ctx.addRpath(rPath->getValue());
+ }
+ }
+
+ // Parse the LLVM options before we process files in case the file handling
+ // makes use of things like LLVM_DEBUG().
+ parseLLVMOptions(ctx);
+
+ // Handle input files and sectcreate.
+ for (auto &arg : parsedArgs) {
+ bool upward;
+ llvm::Optional<StringRef> resolvedPath;
+ switch (arg->getOption().getID()) {
+ default:
+ continue;
+ case OPT_INPUT:
+ addFile(arg->getValue(), ctx, globalWholeArchive, false);
+ break;
+ case OPT_upward_library:
+ addFile(arg->getValue(), ctx, false, true);
+ break;
+ case OPT_force_load:
+ addFile(arg->getValue(), ctx, true, false);
+ break;
+ case OPT_l:
+ case OPT_upward_l:
+ upward = (arg->getOption().getID() == OPT_upward_l);
+ resolvedPath = ctx.searchLibrary(arg->getValue());
+ if (!resolvedPath) {
+ error("Unable to find library for " + arg->getSpelling() +
+ arg->getValue());
+ return false;
+ } else if (ctx.testingFileUsage()) {
+ message(Twine("Found ") + (upward ? "upward " : " ") + "library " +
+ canonicalizePath(resolvedPath.getValue()));
+ }
+ addFile(resolvedPath.getValue(), ctx, globalWholeArchive, upward);
+ break;
+ case OPT_framework:
+ case OPT_upward_framework:
+ upward = (arg->getOption().getID() == OPT_upward_framework);
+ resolvedPath = ctx.findPathForFramework(arg->getValue());
+ if (!resolvedPath) {
+ error("Unable to find framework for " + arg->getSpelling() + " " +
+ arg->getValue());
+ return false;
+ } else if (ctx.testingFileUsage()) {
+ message(Twine("Found ") + (upward ? "upward " : " ") + "framework " +
+ canonicalizePath(resolvedPath.getValue()));
+ }
+ addFile(resolvedPath.getValue(), ctx, globalWholeArchive, upward);
+ break;
+ case OPT_filelist:
+ if (auto ec = loadFileList(arg->getValue(), ctx, globalWholeArchive)) {
+ handleAllErrors(std::move(ec), [&](const llvm::ErrorInfoBase &EI) {
+ error(EI.message() + ", processing '-filelist " + arg->getValue());
+ });
+ 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) {
+ error("can't open -sectcreate file " + Twine(fileName));
+ return false;
+ }
+
+ ctx.addSectCreateSection(seg, sect, std::move(*contentOrErr));
+ }
+ break;
+ }
+ }
+
+ if (ctx.getNodes().empty()) {
+ error("No input files");
+ return false;
+ }
+
+ // Validate the combination of options used.
+ return ctx.validate();
+}
+
+static void createFiles(MachOLinkingContext &ctx, bool Implicit) {
+ std::vector<std::unique_ptr<File>> Files;
+ if (Implicit)
+ ctx.createImplicitFiles(Files);
+ else
+ ctx.createInternalFiles(Files);
+ for (auto i = Files.rbegin(), e = Files.rend(); i != e; ++i) {
+ auto &members = ctx.getNodes();
+ members.insert(members.begin(), llvm::make_unique<FileNode>(std::move(*i)));
+ }
+}
+
+/// This is where the link is actually performed.
+bool link(llvm::ArrayRef<const char *> args, bool CanExitEarly,
+ raw_ostream &Error) {
+ errorHandler().LogName = args::getFilenameWithoutExe(args[0]);
+ errorHandler().ErrorLimitExceededMsg =
+ "too many errors emitted, stopping now (use "
+ "'-error-limit 0' to see all errors)";
+ errorHandler().ErrorOS = &Error;
+ errorHandler().ExitEarly = CanExitEarly;
+ errorHandler().ColorDiagnostics = Error.has_colors();
+
+ MachOLinkingContext ctx;
+ if (!parse(args, ctx))
+ return false;
+ if (ctx.doNothing())
+ return true;
+ if (ctx.getNodes().empty())
+ return false;
+
+ for (std::unique_ptr<Node> &ie : ctx.getNodes())
+ if (FileNode *node = dyn_cast<FileNode>(ie.get()))
+ node->getFile()->parse();
+
+ createFiles(ctx, false /* Implicit */);
+
+ // Give target a chance to add files
+ createFiles(ctx, true /* Implicit */);
+
+ // Give target a chance to postprocess input files.
+ // Mach-O uses this chance to move all object files before library files.
+ ctx.finalizeInputFiles();
+
+ // Do core linking.
+ ScopedTask resolveTask(getDefaultDomain(), "Resolve");
+ Resolver resolver(ctx);
+ if (!resolver.resolve())
+ return false;
+ SimpleFile *merged = nullptr;
+ {
+ std::unique_ptr<SimpleFile> mergedFile = resolver.resultFile();
+ merged = mergedFile.get();
+ auto &members = ctx.getNodes();
+ members.insert(members.begin(),
+ llvm::make_unique<FileNode>(std::move(mergedFile)));
+ }
+ resolveTask.end();
+
+ // Run passes on linked atoms.
+ ScopedTask passTask(getDefaultDomain(), "Passes");
+ PassManager pm;
+ ctx.addPasses(pm);
+ if (auto ec = pm.runOnFile(*merged)) {
+ // FIXME: This should be passed to logAllUnhandledErrors but it needs
+ // to be passed a Twine instead of a string.
+ *errorHandler().ErrorOS << "Failed to run passes on file '"
+ << ctx.outputPath() << "': ";
+ logAllUnhandledErrors(std::move(ec), *errorHandler().ErrorOS,
+ std::string());
+ return false;
+ }
+
+ passTask.end();
+
+ // Give linked atoms to Writer to generate output file.
+ ScopedTask writeTask(getDefaultDomain(), "Write");
+ if (auto ec = ctx.writeFile(*merged)) {
+ // FIXME: This should be passed to logAllUnhandledErrors but it needs
+ // to be passed a Twine instead of a string.
+ *errorHandler().ErrorOS << "Failed to write file '" << ctx.outputPath()
+ << "': ";
+ logAllUnhandledErrors(std::move(ec), *errorHandler().ErrorOS,
+ std::string());
+ return false;
+ }
+
+ // Call exit() if we can to avoid calling destructors.
+ if (CanExitEarly)
+ exitLld(errorCount() ? 1 : 0);
+
+
+ return true;
+}
+
+} // end namespace mach_o
+} // end namespace lld
diff --git a/contrib/llvm/tools/lld/lib/Driver/DarwinLdOptions.td b/contrib/llvm/tools/lld/lib/Driver/DarwinLdOptions.td
new file mode 100644
index 000000000000..3bbde8bf1c1c
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/Driver/DarwinLdOptions.td
@@ -0,0 +1,250 @@
+include "llvm/Option/OptParser.td"
+
+
+// output kinds
+def grp_kind : OptionGroup<"outs">, HelpText<"OUTPUT KIND">;
+def relocatable : Flag<["-"], "r">,
+ HelpText<"Create relocatable object file">, Group<grp_kind>;
+def static : Flag<["-"], "static">,
+ HelpText<"Create static executable">, Group<grp_kind>;
+def dynamic : Flag<["-"], "dynamic">,
+ HelpText<"Create dynamic executable (default)">,Group<grp_kind>;
+def dylib : Flag<["-"], "dylib">,
+ HelpText<"Create dynamic library">, Group<grp_kind>;
+def bundle : Flag<["-"], "bundle">,
+ HelpText<"Create dynamic bundle">, Group<grp_kind>;
+def execute : Flag<["-"], "execute">,
+ HelpText<"Create main executable (default)">, Group<grp_kind>;
+def preload : Flag<["-"], "preload">,
+ HelpText<"Create binary for use with embedded systems">, Group<grp_kind>;
+
+// optimizations
+def grp_opts : OptionGroup<"opts">, HelpText<"OPTIMIZATIONS">;
+def dead_strip : Flag<["-"], "dead_strip">,
+ HelpText<"Remove unreference code and data">, Group<grp_opts>;
+def macosx_version_min : Separate<["-"], "macosx_version_min">,
+ MetaVarName<"<version>">,
+ HelpText<"Minimum Mac OS X version">, Group<grp_opts>;
+def ios_version_min : Separate<["-"], "ios_version_min">,
+ MetaVarName<"<version>">,
+ HelpText<"Minimum iOS version">, Group<grp_opts>;
+def iphoneos_version_min : Separate<["-"], "iphoneos_version_min">,
+ Alias<ios_version_min>;
+def ios_simulator_version_min : Separate<["-"], "ios_simulator_version_min">,
+ MetaVarName<"<version>">,
+ HelpText<"Minimum iOS simulator version">, Group<grp_opts>;
+def sdk_version : Separate<["-"], "sdk_version">,
+ MetaVarName<"<version>">,
+ HelpText<"SDK version">, Group<grp_opts>;
+def source_version : Separate<["-"], "source_version">,
+ MetaVarName<"<version>">,
+ HelpText<"Source version">, Group<grp_opts>;
+def version_load_command : Flag<["-"], "version_load_command">,
+ HelpText<"Force generation of a version load command">, Group<grp_opts>;
+def no_version_load_command : Flag<["-"], "no_version_load_command">,
+ HelpText<"Disable generation of a version load command">, Group<grp_opts>;
+def function_starts : Flag<["-"], "function_starts">,
+ HelpText<"Force generation of a function starts load command">,
+ Group<grp_opts>;
+def no_function_starts : Flag<["-"], "no_function_starts">,
+ HelpText<"Disable generation of a function starts load command">,
+ Group<grp_opts>;
+def data_in_code_info : Flag<["-"], "data_in_code_info">,
+ HelpText<"Force generation of a data in code load command">,
+ Group<grp_opts>;
+def no_data_in_code_info : Flag<["-"], "no_data_in_code_info">,
+ HelpText<"Disable generation of a data in code load command">,
+ Group<grp_opts>;
+def mllvm : Separate<["-"], "mllvm">,
+ MetaVarName<"<option>">,
+ HelpText<"Options to pass to LLVM during LTO">, Group<grp_opts>;
+def exported_symbols_list : Separate<["-"], "exported_symbols_list">,
+ MetaVarName<"<file-path>">,
+ HelpText<"Restricts which symbols will be exported">, Group<grp_opts>;
+def exported_symbol : Separate<["-"], "exported_symbol">,
+ MetaVarName<"<symbol>">,
+ HelpText<"Restricts which symbols will be exported">, Group<grp_opts>;
+def unexported_symbols_list : Separate<["-"], "unexported_symbols_list">,
+ MetaVarName<"<file-path>">,
+ HelpText<"Lists symbols that should not be exported">, Group<grp_opts>;
+def unexported_symbol : Separate<["-"], "unexported_symbol">,
+ MetaVarName<"<symbol>">,
+ HelpText<"A symbol which should not be exported">, Group<grp_opts>;
+def keep_private_externs : Flag<["-"], "keep_private_externs">,
+ HelpText<"Private extern (hidden) symbols should not be transformed "
+ "into local symbols">, Group<grp_opts>;
+def order_file : Separate<["-"], "order_file">,
+ MetaVarName<"<file-path>">,
+ HelpText<"re-order and move specified symbols to start of their section">,
+ Group<grp_opts>;
+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>;
+def no_objc_category_merging : Flag<["-"], "no_objc_category_merging">,
+ HelpText<"Disables the optimisation which merges Objective-C categories "
+ "on a class in to the class itself.">,
+ Group<grp_opts>;
+
+// main executable options
+def grp_main : OptionGroup<"opts">, HelpText<"MAIN EXECUTABLE OPTIONS">;
+def entry : Separate<["-"], "e">,
+ MetaVarName<"<entry-name>">,
+ HelpText<"entry symbol name">,Group<grp_main>;
+def pie : Flag<["-"], "pie">,
+ HelpText<"Create Position Independent Executable (for ASLR)">,
+ Group<grp_main>;
+def no_pie : Flag<["-"], "no_pie">,
+ HelpText<"Do not create Position Independent Executable">,
+ Group<grp_main>;
+def stack_size : Separate<["-"], "stack_size">,
+ HelpText<"Specifies the maximum stack size for the main thread in a program. "
+ "Must be a page-size multiple. (default=8Mb)">,
+ Group<grp_main>;
+def export_dynamic : Flag<["-"], "export_dynamic">,
+ HelpText<"Preserves all global symbols in main executables during LTO">,
+ Group<grp_main>;
+
+// dylib executable options
+def grp_dylib : OptionGroup<"opts">, HelpText<"DYLIB EXECUTABLE OPTIONS">;
+def install_name : Separate<["-"], "install_name">,
+ MetaVarName<"<path>">,
+ HelpText<"The dylib's install name">, Group<grp_dylib>;
+def mark_dead_strippable_dylib : Flag<["-"], "mark_dead_strippable_dylib">,
+ HelpText<"Marks the dylib as having no side effects during initialization">,
+ Group<grp_dylib>;
+def compatibility_version : Separate<["-"], "compatibility_version">,
+ MetaVarName<"<version>">,
+ HelpText<"The dylib's compatibility version">, Group<grp_dylib>;
+def current_version : Separate<["-"], "current_version">,
+ MetaVarName<"<version>">,
+ HelpText<"The dylib's current version">, Group<grp_dylib>;
+
+// dylib executable options - compatibility aliases
+def dylib_install_name : Separate<["-"], "dylib_install_name">,
+ Alias<install_name>;
+def dylib_compatibility_version : Separate<["-"], "dylib_compatibility_version">,
+ MetaVarName<"<version>">, Alias<compatibility_version>;
+def dylib_current_version : Separate<["-"], "dylib_current_version">,
+ MetaVarName<"<version>">, Alias<current_version>;
+
+// bundle executable options
+def grp_bundle : OptionGroup<"opts">, HelpText<"BUNDLE EXECUTABLE OPTIONS">;
+def bundle_loader : Separate<["-"], "bundle_loader">,
+ MetaVarName<"<path>">,
+ HelpText<"The executable that will be loading this Mach-O bundle">,
+ Group<grp_bundle>;
+
+// library options
+def grp_libs : OptionGroup<"libs">, HelpText<"LIBRARY OPTIONS">;
+def L : JoinedOrSeparate<["-"], "L">,
+ MetaVarName<"<dir>">,
+ HelpText<"Add directory to library search path">, Group<grp_libs>;
+def F : JoinedOrSeparate<["-"], "F">,
+ MetaVarName<"<dir>">,
+ HelpText<"Add directory to framework search path">, Group<grp_libs>;
+def Z : Flag<["-"], "Z">,
+ HelpText<"Do not search standard directories for libraries or frameworks">;
+def all_load : Flag<["-"], "all_load">,
+ HelpText<"Forces all members of all static libraries to be loaded">,
+ Group<grp_libs>;
+def force_load : Separate<["-"], "force_load">,
+ MetaVarName<"<library-path>">,
+ HelpText<"Forces all members of specified static libraries to be loaded">,
+ Group<grp_libs>;
+def syslibroot : Separate<["-"], "syslibroot">, MetaVarName<"<dir>">,
+ HelpText<"Add path to SDK to all absolute library search paths">,
+ Group<grp_libs>;
+
+// Input options
+def l : Joined<["-"], "l">,
+ MetaVarName<"<libname>">,
+ HelpText<"Base name of library searched for in -L directories">;
+def upward_l : Joined<["-"], "upward-l">,
+ MetaVarName<"<libname>">,
+ HelpText<"Base name of upward library searched for in -L directories">;
+def framework : Separate<["-"], "framework">,
+ MetaVarName<"<name>">,
+ HelpText<"Base name of framework searched for in -F directories">;
+def upward_framework : Separate<["-"], "upward_framework">,
+ MetaVarName<"<name>">,
+ HelpText<"Base name of upward framework searched for in -F directories">;
+def upward_library : Separate<["-"], "upward_library">,
+ MetaVarName<"<path>">,
+ HelpText<"path to upward dylib to link with">;
+def filelist : Separate<["-"], "filelist">,
+ MetaVarName<"<path>">,
+ HelpText<"file containing paths to input files">;
+
+
+// test case options
+def print_atoms : Flag<["-"], "print_atoms">,
+ HelpText<"Emit output as yaml atoms">;
+def test_file_usage : Flag<["-"], "test_file_usage">,
+ HelpText<"Only files specified by -file_exists are considered to exist. "
+ "Print which files would be used">;
+def path_exists : Separate<["-"], "path_exists">,
+ MetaVarName<"<path>">,
+ HelpText<"Used with -test_file_usage to declare a path">;
+
+
+// general options
+def output : Separate<["-"], "o">,
+ MetaVarName<"<path>">,
+ HelpText<"Output file path">;
+def arch : Separate<["-"], "arch">,
+ MetaVarName<"<arch-name>">,
+ HelpText<"Architecture to link">;
+def sectalign : MultiArg<["-"], "sectalign", 3>,
+ MetaVarName<"<segname> <sectname> <alignment>">,
+ HelpText<"Alignment for segment/section">;
+def 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">,
+ HelpText<"Demangles symbol names in errors and warnings">;
+def dependency_info : Separate<["-"], "dependency_info">,
+ MetaVarName<"<file>">,
+ HelpText<"Write binary list of files used during link">;
+def S : Flag<["-"], "S">,
+ HelpText<"Remove debug information (STABS or DWARF) from the output file">;
+def rpath : Separate<["-"], "rpath">,
+ MetaVarName<"<path>">,
+ HelpText<"Add path to the runpath search path list for image being created">;
+
+def t : Flag<["-"], "t">,
+ HelpText<"Print the names of the input files as ld processes them">;
+def v : Flag<["-"], "v">,
+ HelpText<"Print linker information">;
+def error_limit : Separate<["-", "--"], "error-limit">,
+ MetaVarName<"<number>">,
+ HelpText<"Maximum number of errors to emit before stopping (0 = no limit)">;
+
+// Ignored options
+def lto_library : Separate<["-"], "lto_library">,
+ MetaVarName<"<path>">,
+ HelpText<"Ignored for compatibility with other linkers">;
+
+// Obsolete options
+def grp_obsolete : OptionGroup<"obsolete">, HelpText<"OBSOLETE OPTIONS">;
+def single_module : Flag<["-"], "single_module">,
+ HelpText<"Default for dylibs">, Group<grp_obsolete>;
+def multi_module : Flag<["-"], "multi_module">,
+ HelpText<"Unsupported way to build dylibs">, Group<grp_obsolete>;
+def objc_gc_compaction : Flag<["-"], "objc_gc_compaction">,
+ HelpText<"Unsupported ObjC GC option">, Group<grp_obsolete>;
+def objc_gc : Flag<["-"], "objc_gc">,
+ HelpText<"Unsupported ObjC GC option">, Group<grp_obsolete>;
+def objc_gc_only : Flag<["-"], "objc_gc_only">,
+ HelpText<"Unsupported ObjC GC option">, Group<grp_obsolete>;
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/CMakeLists.txt b/contrib/llvm/tools/lld/lib/ReaderWriter/CMakeLists.txt
new file mode 100644
index 000000000000..bedb836d2c1e
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/CMakeLists.txt
@@ -0,0 +1,20 @@
+add_subdirectory(MachO)
+add_subdirectory(YAML)
+
+if (MSVC)
+ add_definitions(-wd4062) # Suppress 'warning C4062: Enumerator has no associated handler in a switch statement.'
+endif()
+
+add_lld_library(lldReaderWriter
+ FileArchive.cpp
+
+ ADDITIONAL_HEADER_DIRS
+ ${LLD_INCLUDE_DIR}/lld/ReaderWriter
+
+ LINK_COMPONENTS
+ Object
+ Support
+
+ LINK_LIBS
+ lldCore
+ )
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/FileArchive.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/FileArchive.cpp
new file mode 100644
index 000000000000..2f52d9d34312
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/FileArchive.cpp
@@ -0,0 +1,228 @@
+//===- lib/ReaderWriter/FileArchive.cpp -----------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Common/LLVM.h"
+#include "lld/Core/ArchiveLibraryFile.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Reader.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/Error.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <memory>
+#include <set>
+#include <string>
+#include <system_error>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+using llvm::object::Archive;
+using llvm::file_magic;
+using llvm::identify_magic;
+
+namespace lld {
+
+namespace {
+
+/// The FileArchive class represents an Archive Library file
+class FileArchive : public lld::ArchiveLibraryFile {
+public:
+ FileArchive(std::unique_ptr<MemoryBuffer> mb, const Registry &reg,
+ StringRef path, bool logLoading)
+ : ArchiveLibraryFile(path), _mb(std::shared_ptr<MemoryBuffer>(mb.release())),
+ _registry(reg), _logLoading(logLoading) {}
+
+ /// Check if any member of the archive contains an Atom with the
+ /// specified name and return the File object for that member, or nullptr.
+ File *find(StringRef name) override {
+ auto member = _symbolMemberMap.find(name);
+ if (member == _symbolMemberMap.end())
+ return nullptr;
+ Archive::Child c = member->second;
+
+ // Don't return a member already returned
+ Expected<StringRef> buf = c.getBuffer();
+ if (!buf) {
+ // TODO: Actually report errors helpfully.
+ consumeError(buf.takeError());
+ return nullptr;
+ }
+ const char *memberStart = buf->data();
+ if (_membersInstantiated.count(memberStart))
+ return nullptr;
+ _membersInstantiated.insert(memberStart);
+
+ std::unique_ptr<File> result;
+ if (instantiateMember(c, result))
+ return nullptr;
+
+ File *file = result.get();
+ _filesReturned.push_back(std::move(result));
+
+ // Give up the file pointer. It was stored and will be destroyed with destruction of FileArchive
+ return file;
+ }
+
+ /// parse each member
+ std::error_code
+ parseAllMembers(std::vector<std::unique_ptr<File>> &result) override {
+ if (std::error_code ec = parse())
+ return ec;
+ llvm::Error err = llvm::Error::success();
+ for (auto mf = _archive->child_begin(err), me = _archive->child_end();
+ mf != me; ++mf) {
+ std::unique_ptr<File> file;
+ if (std::error_code ec = instantiateMember(*mf, file)) {
+ // err is Success (or we wouldn't be in the loop body) but we can't
+ // return without testing or consuming it.
+ consumeError(std::move(err));
+ return ec;
+ }
+ result.push_back(std::move(file));
+ }
+ if (err)
+ return errorToErrorCode(std::move(err));
+ return std::error_code();
+ }
+
+ const AtomRange<DefinedAtom> defined() const override {
+ return _noDefinedAtoms;
+ }
+
+ const AtomRange<UndefinedAtom> undefined() const override {
+ return _noUndefinedAtoms;
+ }
+
+ const AtomRange<SharedLibraryAtom> sharedLibrary() const override {
+ return _noSharedLibraryAtoms;
+ }
+
+ const AtomRange<AbsoluteAtom> absolute() const override {
+ return _noAbsoluteAtoms;
+ }
+
+ void clearAtoms() override {
+ _noDefinedAtoms.clear();
+ _noUndefinedAtoms.clear();
+ _noSharedLibraryAtoms.clear();
+ _noAbsoluteAtoms.clear();
+ }
+
+protected:
+ std::error_code doParse() override {
+ // Make Archive object which will be owned by FileArchive object.
+ llvm::Error Err = llvm::Error::success();
+ _archive.reset(new Archive(_mb->getMemBufferRef(), Err));
+ if (Err)
+ return errorToErrorCode(std::move(Err));
+ std::error_code ec;
+ if ((ec = buildTableOfContents()))
+ return ec;
+ return std::error_code();
+ }
+
+private:
+ std::error_code instantiateMember(Archive::Child member,
+ std::unique_ptr<File> &result) const {
+ Expected<llvm::MemoryBufferRef> mbOrErr = member.getMemoryBufferRef();
+ if (!mbOrErr)
+ return errorToErrorCode(mbOrErr.takeError());
+ llvm::MemoryBufferRef mb = mbOrErr.get();
+ std::string memberPath = (_archive->getFileName() + "("
+ + mb.getBufferIdentifier() + ")").str();
+
+ if (_logLoading)
+ llvm::errs() << memberPath << "\n";
+
+ std::unique_ptr<MemoryBuffer> memberMB(MemoryBuffer::getMemBuffer(
+ mb.getBuffer(), mb.getBufferIdentifier(), false));
+
+ ErrorOr<std::unique_ptr<File>> fileOrErr =
+ _registry.loadFile(std::move(memberMB));
+ if (std::error_code ec = fileOrErr.getError())
+ return ec;
+ result = std::move(fileOrErr.get());
+ if (std::error_code ec = result->parse())
+ return ec;
+ result->setArchivePath(_archive->getFileName());
+
+ // The memory buffer is co-owned by the archive file and the children,
+ // so that the bufffer is deallocated when all the members are destructed.
+ result->setSharedMemoryBuffer(_mb);
+ return std::error_code();
+ }
+
+ std::error_code buildTableOfContents() {
+ DEBUG_WITH_TYPE("FileArchive", llvm::dbgs()
+ << "Table of contents for archive '"
+ << _archive->getFileName() << "':\n");
+ for (const Archive::Symbol &sym : _archive->symbols()) {
+ StringRef name = sym.getName();
+ Expected<Archive::Child> memberOrErr = sym.getMember();
+ if (!memberOrErr)
+ return errorToErrorCode(memberOrErr.takeError());
+ Archive::Child member = memberOrErr.get();
+ DEBUG_WITH_TYPE("FileArchive",
+ llvm::dbgs()
+ << llvm::format("0x%08llX ",
+ member.getBuffer()->data())
+ << "'" << name << "'\n");
+ _symbolMemberMap.insert(std::make_pair(name, member));
+ }
+ return std::error_code();
+ }
+
+ typedef std::unordered_map<StringRef, Archive::Child> MemberMap;
+ typedef std::set<const char *> InstantiatedSet;
+
+ std::shared_ptr<MemoryBuffer> _mb;
+ const Registry &_registry;
+ std::unique_ptr<Archive> _archive;
+ MemberMap _symbolMemberMap;
+ InstantiatedSet _membersInstantiated;
+ bool _logLoading;
+ std::vector<std::unique_ptr<MemoryBuffer>> _memberBuffers;
+ std::vector<std::unique_ptr<File>> _filesReturned;
+};
+
+class ArchiveReader : public Reader {
+public:
+ ArchiveReader(bool logLoading) : _logLoading(logLoading) {}
+
+ bool canParse(file_magic magic, MemoryBufferRef) const override {
+ return magic == file_magic::archive;
+ }
+
+ ErrorOr<std::unique_ptr<File>> loadFile(std::unique_ptr<MemoryBuffer> mb,
+ const Registry &reg) const override {
+ StringRef path = mb->getBufferIdentifier();
+ std::unique_ptr<File> ret =
+ llvm::make_unique<FileArchive>(std::move(mb), reg, path, _logLoading);
+ return std::move(ret);
+ }
+
+private:
+ bool _logLoading;
+};
+
+} // anonymous namespace
+
+void Registry::addSupportArchives(bool logLoading) {
+ add(std::unique_ptr<Reader>(new ArchiveReader(logLoading)));
+}
+
+} // namespace lld
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler.cpp
new file mode 100644
index 000000000000..cb20907b3e30
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler.cpp
@@ -0,0 +1,172 @@
+//===- lib/FileFormat/MachO/ArchHandler.cpp -------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "ArchHandler.h"
+#include "Atoms.h"
+#include "MachONormalizedFileBinaryUtils.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
+
+namespace lld {
+namespace mach_o {
+
+
+ArchHandler::ArchHandler() {
+}
+
+ArchHandler::~ArchHandler() {
+}
+
+std::unique_ptr<mach_o::ArchHandler> ArchHandler::create(
+ MachOLinkingContext::Arch arch) {
+ switch (arch) {
+ case MachOLinkingContext::arch_x86_64:
+ return create_x86_64();
+ case MachOLinkingContext::arch_x86:
+ return create_x86();
+ case MachOLinkingContext::arch_armv6:
+ case MachOLinkingContext::arch_armv7:
+ case MachOLinkingContext::arch_armv7s:
+ return create_arm();
+ case MachOLinkingContext::arch_arm64:
+ return create_arm64();
+ default:
+ llvm_unreachable("Unknown arch");
+ }
+}
+
+
+bool ArchHandler::isLazyPointer(const Reference &ref) {
+ // A lazy bind entry is needed for a lazy pointer.
+ const StubInfo &info = stubInfo();
+ if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+ return false;
+ if (ref.kindArch() != info.lazyPointerReferenceToFinal.arch)
+ return false;
+ return (ref.kindValue() == info.lazyPointerReferenceToFinal.kind);
+}
+
+
+ArchHandler::RelocPattern ArchHandler::relocPattern(const Relocation &reloc) {
+ assert((reloc.type & 0xFFF0) == 0);
+ uint16_t result = reloc.type;
+ if (reloc.scattered)
+ result |= rScattered;
+ if (reloc.pcRel)
+ result |= rPcRel;
+ if (reloc.isExtern)
+ result |= rExtern;
+ switch(reloc.length) {
+ case 0:
+ break;
+ case 1:
+ result |= rLength2;
+ break;
+ case 2:
+ result |= rLength4;
+ break;
+ case 3:
+ result |= rLength8;
+ break;
+ default:
+ llvm_unreachable("bad r_length");
+ }
+ return result;
+}
+
+normalized::Relocation
+ArchHandler::relocFromPattern(ArchHandler::RelocPattern pattern) {
+ normalized::Relocation result;
+ result.offset = 0;
+ result.scattered = (pattern & rScattered);
+ result.type = (RelocationInfoType)(pattern & 0xF);
+ result.pcRel = (pattern & rPcRel);
+ result.isExtern = (pattern & rExtern);
+ result.value = 0;
+ result.symbol = 0;
+ switch (pattern & 0x300) {
+ case rLength1:
+ result.length = 0;
+ break;
+ case rLength2:
+ result.length = 1;
+ break;
+ case rLength4:
+ result.length = 2;
+ break;
+ case rLength8:
+ result.length = 3;
+ break;
+ }
+ return result;
+}
+
+void ArchHandler::appendReloc(normalized::Relocations &relocs, uint32_t offset,
+ uint32_t symbol, uint32_t value,
+ RelocPattern pattern) {
+ normalized::Relocation reloc = relocFromPattern(pattern);
+ reloc.offset = offset;
+ reloc.symbol = symbol;
+ reloc.value = value;
+ relocs.push_back(reloc);
+}
+
+
+int16_t ArchHandler::readS16(const uint8_t *addr, bool isBig) {
+ return read16(addr, isBig);
+}
+
+int32_t ArchHandler::readS32(const uint8_t *addr, bool isBig) {
+ return read32(addr, isBig);
+}
+
+uint32_t ArchHandler::readU32(const uint8_t *addr, bool isBig) {
+ return read32(addr, isBig);
+}
+
+ int64_t ArchHandler::readS64(const uint8_t *addr, bool isBig) {
+ return read64(addr, isBig);
+}
+
+bool ArchHandler::isDwarfCIE(bool isBig, const DefinedAtom *atom) {
+ assert(atom->contentType() == DefinedAtom::typeCFI);
+ if (atom->rawContent().size() < sizeof(uint32_t))
+ return false;
+ uint32_t size = read32(atom->rawContent().data(), isBig);
+
+ uint32_t idOffset = sizeof(uint32_t);
+ if (size == 0xffffffffU)
+ idOffset += sizeof(uint64_t);
+
+ return read32(atom->rawContent().data() + idOffset, isBig) == 0;
+}
+
+const Atom *ArchHandler::fdeTargetFunction(const DefinedAtom *fde) {
+ for (auto ref : *fde) {
+ if (ref->kindNamespace() == Reference::KindNamespace::mach_o &&
+ ref->kindValue() == unwindRefToFunctionKind()) {
+ assert(ref->kindArch() == kindArch() && "unexpected Reference arch");
+ return ref->target();
+ }
+ }
+
+ return nullptr;
+}
+
+} // namespace mach_o
+} // namespace lld
+
+
+
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler.h b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler.h
new file mode 100644
index 000000000000..80840b561701
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler.h
@@ -0,0 +1,323 @@
+//===- lib/FileFormat/MachO/ArchHandler.h ---------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_MACHO_ARCH_HANDLER_H
+#define LLD_READER_WRITER_MACHO_ARCH_HANDLER_H
+
+#include "Atoms.h"
+#include "File.h"
+#include "MachONormalizedFile.h"
+#include "lld/Common/LLVM.h"
+#include "lld/Core/Error.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/Simple.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/ADT/Triple.h"
+
+namespace lld {
+namespace mach_o {
+
+///
+/// The ArchHandler class handles all architecture specific aspects of
+/// mach-o linking.
+///
+class ArchHandler {
+public:
+ virtual ~ArchHandler();
+
+ /// There is no public interface to subclasses of ArchHandler, so this
+ /// is the only way to instantiate an ArchHandler.
+ static std::unique_ptr<ArchHandler> create(MachOLinkingContext::Arch arch);
+
+ /// Get (arch specific) kind strings used by Registry.
+ virtual const Registry::KindStrings *kindStrings() = 0;
+
+ /// Convert mach-o Arch to Reference::KindArch.
+ virtual Reference::KindArch kindArch() = 0;
+
+ /// Used by StubPass to update References to shared library functions
+ /// to be references to a stub.
+ virtual bool isCallSite(const Reference &) = 0;
+
+ /// Used by GOTPass to locate GOT References
+ virtual bool isGOTAccess(const Reference &, bool &canBypassGOT) {
+ return false;
+ }
+
+ /// Used by TLVPass to locate TLV References.
+ virtual bool isTLVAccess(const Reference &) const { return false; }
+
+ /// Used by the TLVPass to update TLV References.
+ virtual void updateReferenceToTLV(const Reference *) {}
+
+ /// Used by ShimPass to insert shims in branches that switch mode.
+ virtual bool isNonCallBranch(const Reference &) = 0;
+
+ /// Used by GOTPass to update GOT References
+ virtual void updateReferenceToGOT(const Reference *, bool targetIsNowGOT) {}
+
+ /// Does this architecture make use of __unwind_info sections for exception
+ /// handling? If so, it will need a separate pass to create them.
+ virtual bool needsCompactUnwind() = 0;
+
+ /// Returns the kind of reference to use to synthesize a 32-bit image-offset
+ /// value, used in the __unwind_info section.
+ virtual Reference::KindValue imageOffsetKind() = 0;
+
+ /// Returns the kind of reference to use to synthesize a 32-bit image-offset
+ /// indirect value. Used for personality functions in the __unwind_info
+ /// section.
+ virtual Reference::KindValue imageOffsetKindIndirect() = 0;
+
+ /// Architecture specific compact unwind type that signals __eh_frame should
+ /// actually be used.
+ virtual uint32_t dwarfCompactUnwindType() = 0;
+
+ /// Reference from an __eh_frame CIE atom to its personality function it's
+ /// describing. Usually pointer-sized and PC-relative, but differs in whether
+ /// it needs to be in relocatable objects.
+ virtual Reference::KindValue unwindRefToPersonalityFunctionKind() = 0;
+
+ /// Reference from an __eh_frame FDE to the CIE it's based on.
+ virtual Reference::KindValue unwindRefToCIEKind() = 0;
+
+ /// Reference from an __eh_frame FDE atom to the function it's
+ /// describing. Usually pointer-sized and PC-relative, but differs in whether
+ /// it needs to be in relocatable objects.
+ virtual Reference::KindValue unwindRefToFunctionKind() = 0;
+
+ /// Reference from an __unwind_info entry of dwarfCompactUnwindType to the
+ /// required __eh_frame entry. On current architectures, the low 24 bits
+ /// represent the offset of the function's FDE entry from the start of
+ /// __eh_frame.
+ virtual Reference::KindValue unwindRefToEhFrameKind() = 0;
+
+ /// Returns a pointer sized reference kind. On 64-bit targets this will
+ /// likely be something like pointer64, and pointer32 on 32-bit targets.
+ virtual Reference::KindValue pointerKind() = 0;
+
+ virtual const Atom *fdeTargetFunction(const DefinedAtom *fde);
+
+ /// Used by normalizedFromAtoms() to know where to generated rebasing and
+ /// binding info in final executables.
+ virtual bool isPointer(const Reference &) = 0;
+
+ /// Used by normalizedFromAtoms() to know where to generated lazy binding
+ /// info in final executables.
+ virtual bool isLazyPointer(const Reference &);
+
+ /// Reference from an __stub_helper entry to the required offset of the
+ /// lazy bind commands.
+ virtual Reference::KindValue lazyImmediateLocationKind() = 0;
+
+ /// Returns true if the specified relocation is paired to the next relocation.
+ virtual bool isPairedReloc(const normalized::Relocation &) = 0;
+
+ /// Prototype for a helper function. Given a sectionIndex and address,
+ /// finds the atom and offset with that atom of that address.
+ typedef std::function<llvm::Error (uint32_t sectionIndex, uint64_t addr,
+ const lld::Atom **, Reference::Addend *)>
+ FindAtomBySectionAndAddress;
+
+ /// Prototype for a helper function. Given a symbolIndex, finds the atom
+ /// representing that symbol.
+ typedef std::function<llvm::Error (uint32_t symbolIndex,
+ const lld::Atom **)> FindAtomBySymbolIndex;
+
+ /// Analyzes a relocation from a .o file and returns the info
+ /// (kind, target, addend) needed to instantiate a Reference.
+ /// Two helper functions are passed as parameters to find the target atom
+ /// given a symbol index or address.
+ virtual llvm::Error
+ getReferenceInfo(const normalized::Relocation &reloc,
+ const DefinedAtom *inAtom,
+ uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool isBigEndian,
+ FindAtomBySectionAndAddress atomFromAddress,
+ FindAtomBySymbolIndex atomFromSymbolIndex,
+ Reference::KindValue *kind,
+ const lld::Atom **target,
+ Reference::Addend *addend) = 0;
+
+ /// Analyzes a pair of relocations from a .o file and returns the info
+ /// (kind, target, addend) needed to instantiate a Reference.
+ /// Two helper functions are passed as parameters to find the target atom
+ /// given a symbol index or address.
+ virtual llvm::Error
+ getPairReferenceInfo(const normalized::Relocation &reloc1,
+ const normalized::Relocation &reloc2,
+ const DefinedAtom *inAtom,
+ uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool isBig, bool scatterable,
+ FindAtomBySectionAndAddress atomFromAddress,
+ FindAtomBySymbolIndex atomFromSymbolIndex,
+ Reference::KindValue *kind,
+ const lld::Atom **target,
+ Reference::Addend *addend) = 0;
+
+ /// Prototype for a helper function. Given an atom, finds the symbol table
+ /// index for it in the output file.
+ typedef std::function<uint32_t (const Atom &atom)> FindSymbolIndexForAtom;
+
+ /// Prototype for a helper function. Given an atom, finds the index
+ /// of the section that will contain the atom.
+ typedef std::function<uint32_t (const Atom &atom)> FindSectionIndexForAtom;
+
+ /// Prototype for a helper function. Given an atom, finds the address
+ /// assigned to it in the output file.
+ typedef std::function<uint64_t (const Atom &atom)> FindAddressForAtom;
+
+ /// Some architectures require local symbols on anonymous atoms.
+ virtual bool needsLocalSymbolInRelocatableFile(const DefinedAtom *atom) {
+ return false;
+ }
+
+ /// Copy raw content then apply all fixup References on an Atom.
+ virtual void generateAtomContent(const DefinedAtom &atom, bool relocatable,
+ FindAddressForAtom findAddress,
+ FindAddressForAtom findSectionAddress,
+ uint64_t imageBaseAddress,
+ llvm::MutableArrayRef<uint8_t> atomContentBuffer) = 0;
+
+ /// Used in -r mode to convert a Reference to a mach-o relocation.
+ virtual void appendSectionRelocations(const DefinedAtom &atom,
+ uint64_t atomSectionOffset,
+ const Reference &ref,
+ FindSymbolIndexForAtom,
+ FindSectionIndexForAtom,
+ FindAddressForAtom,
+ normalized::Relocations&) = 0;
+
+ /// Add arch-specific References.
+ virtual void addAdditionalReferences(MachODefinedAtom &atom) { }
+
+ // Add Reference for data-in-code marker.
+ virtual void addDataInCodeReference(MachODefinedAtom &atom, uint32_t atomOff,
+ uint16_t length, uint16_t kind) { }
+
+ /// Returns true if the specificed Reference value marks the start or end
+ /// of a data-in-code range in an atom.
+ virtual bool isDataInCodeTransition(Reference::KindValue refKind) {
+ return false;
+ }
+
+ /// Returns the Reference value for a Reference that marks that start of
+ /// a data-in-code range.
+ virtual Reference::KindValue dataInCodeTransitionStart(
+ const MachODefinedAtom &atom) {
+ return 0;
+ }
+
+ /// Returns the Reference value for a Reference that marks that end of
+ /// a data-in-code range.
+ virtual Reference::KindValue dataInCodeTransitionEnd(
+ const MachODefinedAtom &atom) {
+ return 0;
+ }
+
+ /// Only relevant for 32-bit arm archs.
+ virtual bool isThumbFunction(const DefinedAtom &atom) { return false; }
+
+ /// Only relevant for 32-bit arm archs.
+ virtual const DefinedAtom *createShim(MachOFile &file, bool thumbToArm,
+ const DefinedAtom &) {
+ llvm_unreachable("shims only support on arm");
+ }
+
+ /// Does a given unwind-cfi atom represent a CIE (as opposed to an FDE).
+ static bool isDwarfCIE(bool isBig, const DefinedAtom *atom);
+
+ struct ReferenceInfo {
+ Reference::KindArch arch;
+ uint16_t kind;
+ uint32_t offset;
+ int32_t addend;
+ };
+
+ struct OptionalRefInfo {
+ bool used;
+ uint16_t kind;
+ uint32_t offset;
+ int32_t addend;
+ };
+
+ /// Table of architecture specific information for creating stubs.
+ struct StubInfo {
+ const char* binderSymbolName;
+ ReferenceInfo lazyPointerReferenceToHelper;
+ ReferenceInfo lazyPointerReferenceToFinal;
+ ReferenceInfo nonLazyPointerReferenceToBinder;
+ uint8_t codeAlignment;
+
+ uint32_t stubSize;
+ uint8_t stubBytes[16];
+ ReferenceInfo stubReferenceToLP;
+ OptionalRefInfo optStubReferenceToLP;
+
+ uint32_t stubHelperSize;
+ uint8_t stubHelperBytes[16];
+ ReferenceInfo stubHelperReferenceToImm;
+ ReferenceInfo stubHelperReferenceToHelperCommon;
+
+ DefinedAtom::ContentType stubHelperImageCacheContentType;
+
+ uint32_t stubHelperCommonSize;
+ uint8_t stubHelperCommonAlignment;
+ uint8_t stubHelperCommonBytes[36];
+ ReferenceInfo stubHelperCommonReferenceToCache;
+ OptionalRefInfo optStubHelperCommonReferenceToCache;
+ ReferenceInfo stubHelperCommonReferenceToBinder;
+ OptionalRefInfo optStubHelperCommonReferenceToBinder;
+ };
+
+ virtual const StubInfo &stubInfo() = 0;
+
+protected:
+ ArchHandler();
+
+ static std::unique_ptr<mach_o::ArchHandler> create_x86_64();
+ static std::unique_ptr<mach_o::ArchHandler> create_x86();
+ static std::unique_ptr<mach_o::ArchHandler> create_arm();
+ static std::unique_ptr<mach_o::ArchHandler> create_arm64();
+
+ // Handy way to pack mach-o r_type and other bit fields into one 16-bit value.
+ typedef uint16_t RelocPattern;
+ enum {
+ rScattered = 0x8000,
+ rPcRel = 0x4000,
+ rExtern = 0x2000,
+ rLength1 = 0x0000,
+ rLength2 = 0x0100,
+ rLength4 = 0x0200,
+ rLength8 = 0x0300,
+ rLenArmLo = rLength1,
+ rLenArmHi = rLength2,
+ rLenThmbLo = rLength4,
+ rLenThmbHi = rLength8
+ };
+ /// Extract RelocPattern from normalized mach-o relocation.
+ static RelocPattern relocPattern(const normalized::Relocation &reloc);
+ /// Create normalized Relocation initialized from pattern.
+ static normalized::Relocation relocFromPattern(RelocPattern pattern);
+ /// One liner to add a relocation.
+ static void appendReloc(normalized::Relocations &relocs, uint32_t offset,
+ uint32_t symbol, uint32_t value,
+ RelocPattern pattern);
+
+
+ static int16_t readS16(const uint8_t *addr, bool isBig);
+ static int32_t readS32(const uint8_t *addr, bool isBig);
+ static uint32_t readU32(const uint8_t *addr, bool isBig);
+ static int64_t readS64(const uint8_t *addr, bool isBig);
+};
+
+} // namespace mach_o
+} // namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_ARCH_HANDLER_H
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp
new file mode 100644
index 000000000000..2f663c660f5c
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp
@@ -0,0 +1,1523 @@
+//===- lib/FileFormat/MachO/ArchHandler_arm.cpp ---------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ArchHandler.h"
+#include "Atoms.h"
+#include "MachONormalizedFileBinaryUtils.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
+
+namespace lld {
+namespace mach_o {
+
+using llvm::support::ulittle32_t;
+using llvm::support::little32_t;
+
+
+class ArchHandler_arm : public ArchHandler {
+public:
+ ArchHandler_arm() = default;
+ ~ArchHandler_arm() override = default;
+
+ const Registry::KindStrings *kindStrings() override { return _sKindStrings; }
+
+ Reference::KindArch kindArch() override { return Reference::KindArch::ARM; }
+
+ const ArchHandler::StubInfo &stubInfo() override;
+ bool isCallSite(const Reference &) override;
+ bool isPointer(const Reference &) override;
+ bool isPairedReloc(const normalized::Relocation &) override;
+ bool isNonCallBranch(const Reference &) override;
+
+ bool needsCompactUnwind() override {
+ return false;
+ }
+ Reference::KindValue imageOffsetKind() override {
+ return invalid;
+ }
+ Reference::KindValue imageOffsetKindIndirect() override {
+ return invalid;
+ }
+
+ Reference::KindValue unwindRefToPersonalityFunctionKind() override {
+ return invalid;
+ }
+
+ Reference::KindValue unwindRefToCIEKind() override {
+ return invalid;
+ }
+
+ Reference::KindValue unwindRefToFunctionKind() override {
+ return invalid;
+ }
+
+ Reference::KindValue unwindRefToEhFrameKind() override {
+ return invalid;
+ }
+
+ Reference::KindValue lazyImmediateLocationKind() override {
+ return lazyImmediateLocation;
+ }
+
+ Reference::KindValue pointerKind() override {
+ return invalid;
+ }
+
+ uint32_t dwarfCompactUnwindType() override {
+ // FIXME
+ return -1;
+ }
+
+ llvm::Error getReferenceInfo(const normalized::Relocation &reloc,
+ const DefinedAtom *inAtom,
+ uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool swap,
+ FindAtomBySectionAndAddress atomFromAddress,
+ FindAtomBySymbolIndex atomFromSymbolIndex,
+ Reference::KindValue *kind,
+ const lld::Atom **target,
+ Reference::Addend *addend) override;
+ llvm::Error
+ getPairReferenceInfo(const normalized::Relocation &reloc1,
+ const normalized::Relocation &reloc2,
+ const DefinedAtom *inAtom,
+ uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool swap, bool scatterable,
+ FindAtomBySectionAndAddress atomFromAddress,
+ FindAtomBySymbolIndex atomFromSymbolIndex,
+ Reference::KindValue *kind,
+ const lld::Atom **target,
+ Reference::Addend *addend) override;
+
+ void generateAtomContent(const DefinedAtom &atom, bool relocatable,
+ FindAddressForAtom findAddress,
+ FindAddressForAtom findSectionAddress,
+ uint64_t imageBaseAddress,
+ llvm::MutableArrayRef<uint8_t> atomContentBuffer) override;
+
+ void appendSectionRelocations(const DefinedAtom &atom,
+ uint64_t atomSectionOffset,
+ const Reference &ref,
+ FindSymbolIndexForAtom,
+ FindSectionIndexForAtom,
+ FindAddressForAtom,
+ normalized::Relocations &) override;
+
+ void addAdditionalReferences(MachODefinedAtom &atom) override;
+
+ bool isDataInCodeTransition(Reference::KindValue refKind) override {
+ switch (refKind) {
+ case modeThumbCode:
+ case modeArmCode:
+ case modeData:
+ return true;
+ default:
+ return false;
+ break;
+ }
+ }
+
+ Reference::KindValue dataInCodeTransitionStart(
+ const MachODefinedAtom &atom) override {
+ return modeData;
+ }
+
+ Reference::KindValue dataInCodeTransitionEnd(
+ const MachODefinedAtom &atom) override {
+ return atom.isThumb() ? modeThumbCode : modeArmCode;
+ }
+
+ bool isThumbFunction(const DefinedAtom &atom) override;
+ const DefinedAtom *createShim(MachOFile &file, bool thumbToArm,
+ const DefinedAtom &) override;
+
+private:
+ friend class Thumb2ToArmShimAtom;
+ friend class ArmToThumbShimAtom;
+
+ static const Registry::KindStrings _sKindStrings[];
+ static const StubInfo _sStubInfoArmPIC;
+
+ enum ArmKind : Reference::KindValue {
+ invalid, /// for error condition
+
+ modeThumbCode, /// Content starting at this offset is thumb.
+ modeArmCode, /// Content starting at this offset is arm.
+ modeData, /// Content starting at this offset is data.
+
+ // Kinds found in mach-o .o files:
+ thumb_bl22, /// ex: bl _foo
+ thumb_b22, /// ex: b _foo
+ thumb_movw, /// ex: movw r1, :lower16:_foo
+ thumb_movt, /// ex: movt r1, :lower16:_foo
+ thumb_movw_funcRel, /// ex: movw r1, :lower16:(_foo-(L1+4))
+ thumb_movt_funcRel, /// ex: movt r1, :upper16:(_foo-(L1+4))
+ arm_bl24, /// ex: bl _foo
+ arm_b24, /// ex: b _foo
+ arm_movw, /// ex: movw r1, :lower16:_foo
+ arm_movt, /// ex: movt r1, :lower16:_foo
+ arm_movw_funcRel, /// ex: movw r1, :lower16:(_foo-(L1+4))
+ arm_movt_funcRel, /// ex: movt r1, :upper16:(_foo-(L1+4))
+ pointer32, /// ex: .long _foo
+ delta32, /// ex: .long _foo - .
+
+ // Kinds introduced by Passes:
+ lazyPointer, /// Location contains a lazy pointer.
+ lazyImmediateLocation, /// Location contains immediate value used in stub.
+ };
+
+ // Utility functions for inspecting/updating instructions.
+ static bool isThumbMovw(uint32_t instruction);
+ static bool isThumbMovt(uint32_t instruction);
+ static bool isArmMovw(uint32_t instruction);
+ static bool isArmMovt(uint32_t instruction);
+ static int32_t getDisplacementFromThumbBranch(uint32_t instruction, uint32_t);
+ static int32_t getDisplacementFromArmBranch(uint32_t instruction);
+ static uint16_t getWordFromThumbMov(uint32_t instruction);
+ static uint16_t getWordFromArmMov(uint32_t instruction);
+ static uint32_t clearThumbBit(uint32_t value, const Atom *target);
+ static uint32_t setDisplacementInArmBranch(uint32_t instr, int32_t disp,
+ bool targetIsThumb);
+ static uint32_t setDisplacementInThumbBranch(uint32_t instr, uint32_t ia,
+ int32_t disp, bool targetThumb);
+ static uint32_t setWordFromThumbMov(uint32_t instruction, uint16_t word);
+ static uint32_t setWordFromArmMov(uint32_t instruction, uint16_t word);
+
+ StringRef stubName(const DefinedAtom &);
+ bool useExternalRelocationTo(const Atom &target);
+
+ void applyFixupFinal(const Reference &ref, uint8_t *location,
+ uint64_t fixupAddress, uint64_t targetAddress,
+ uint64_t inAtomAddress, bool &thumbMode,
+ bool targetIsThumb);
+
+ void applyFixupRelocatable(const Reference &ref, uint8_t *location,
+ uint64_t fixupAddress,
+ uint64_t targetAddress,
+ uint64_t inAtomAddress, bool &thumbMode,
+ bool targetIsThumb);
+};
+
+//===----------------------------------------------------------------------===//
+// ArchHandler_arm
+//===----------------------------------------------------------------------===//
+
+const Registry::KindStrings ArchHandler_arm::_sKindStrings[] = {
+ LLD_KIND_STRING_ENTRY(invalid),
+ LLD_KIND_STRING_ENTRY(modeThumbCode),
+ LLD_KIND_STRING_ENTRY(modeArmCode),
+ LLD_KIND_STRING_ENTRY(modeData),
+ LLD_KIND_STRING_ENTRY(thumb_bl22),
+ LLD_KIND_STRING_ENTRY(thumb_b22),
+ LLD_KIND_STRING_ENTRY(thumb_movw),
+ LLD_KIND_STRING_ENTRY(thumb_movt),
+ LLD_KIND_STRING_ENTRY(thumb_movw_funcRel),
+ LLD_KIND_STRING_ENTRY(thumb_movt_funcRel),
+ LLD_KIND_STRING_ENTRY(arm_bl24),
+ LLD_KIND_STRING_ENTRY(arm_b24),
+ LLD_KIND_STRING_ENTRY(arm_movw),
+ LLD_KIND_STRING_ENTRY(arm_movt),
+ LLD_KIND_STRING_ENTRY(arm_movw_funcRel),
+ LLD_KIND_STRING_ENTRY(arm_movt_funcRel),
+ LLD_KIND_STRING_ENTRY(pointer32),
+ LLD_KIND_STRING_ENTRY(delta32),
+ LLD_KIND_STRING_ENTRY(lazyPointer),
+ LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
+ LLD_KIND_STRING_END
+};
+
+const ArchHandler::StubInfo ArchHandler_arm::_sStubInfoArmPIC = {
+ "dyld_stub_binder",
+
+ // References in lazy pointer
+ { Reference::KindArch::ARM, pointer32, 0, 0 },
+ { Reference::KindArch::ARM, lazyPointer, 0, 0 },
+
+ // GOT pointer to dyld_stub_binder
+ { Reference::KindArch::ARM, pointer32, 0, 0 },
+
+ // arm code alignment 2^2
+ 2,
+
+ // Stub size and code
+ 16,
+ { 0x04, 0xC0, 0x9F, 0xE5, // ldr ip, pc + 12
+ 0x0C, 0xC0, 0x8F, 0xE0, // add ip, pc, ip
+ 0x00, 0xF0, 0x9C, 0xE5, // ldr pc, [ip]
+ 0x00, 0x00, 0x00, 0x00 }, // .long L_foo$lazy_ptr - (L1$scv + 8)
+ { Reference::KindArch::ARM, delta32, 12, 0 },
+ { false, 0, 0, 0 },
+
+ // Stub Helper size and code
+ 12,
+ { 0x00, 0xC0, 0x9F, 0xE5, // ldr ip, [pc, #0]
+ 0x00, 0x00, 0x00, 0xEA, // b _helperhelper
+ 0x00, 0x00, 0x00, 0x00 }, // .long lazy-info-offset
+ { Reference::KindArch::ARM, lazyImmediateLocation, 8, 0 },
+ { Reference::KindArch::ARM, arm_b24, 4, 0 },
+
+ // Stub helper image cache content type
+ DefinedAtom::typeGOT,
+
+ // Stub Helper-Common size and code
+ 36,
+ // Stub helper alignment
+ 2,
+ { // push lazy-info-offset
+ 0x04, 0xC0, 0x2D, 0xE5, // str ip, [sp, #-4]!
+ // push address of dyld_mageLoaderCache
+ 0x10, 0xC0, 0x9F, 0xE5, // ldr ip, L1
+ 0x0C, 0xC0, 0x8F, 0xE0, // add ip, pc, ip
+ 0x04, 0xC0, 0x2D, 0xE5, // str ip, [sp, #-4]!
+ // jump through dyld_stub_binder
+ 0x08, 0xC0, 0x9F, 0xE5, // ldr ip, L2
+ 0x0C, 0xC0, 0x8F, 0xE0, // add ip, pc, ip
+ 0x00, 0xF0, 0x9C, 0xE5, // ldr pc, [ip]
+ 0x00, 0x00, 0x00, 0x00, // L1: .long fFastStubGOTAtom - (helper+16)
+ 0x00, 0x00, 0x00, 0x00 }, // L2: .long dyld_stub_binder - (helper+28)
+ { Reference::KindArch::ARM, delta32, 28, 0xC },
+ { false, 0, 0, 0 },
+ { Reference::KindArch::ARM, delta32, 32, 0x04 },
+ { false, 0, 0, 0 }
+};
+
+const ArchHandler::StubInfo &ArchHandler_arm::stubInfo() {
+ // If multiple kinds of stubs are supported, select which StubInfo here.
+ return _sStubInfoArmPIC;
+}
+
+bool ArchHandler_arm::isCallSite(const Reference &ref) {
+ switch (ref.kindValue()) {
+ case thumb_b22:
+ case thumb_bl22:
+ case arm_b24:
+ case arm_bl24:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool ArchHandler_arm::isPointer(const Reference &ref) {
+ return (ref.kindValue() == pointer32);
+}
+
+bool ArchHandler_arm::isNonCallBranch(const Reference &ref) {
+ switch (ref.kindValue()) {
+ case thumb_b22:
+ case arm_b24:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool ArchHandler_arm::isPairedReloc(const Relocation &reloc) {
+ switch (reloc.type) {
+ case ARM_RELOC_SECTDIFF:
+ case ARM_RELOC_LOCAL_SECTDIFF:
+ case ARM_RELOC_HALF_SECTDIFF:
+ case ARM_RELOC_HALF:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/// Trace references from stub atom to lazy pointer to target and get its name.
+StringRef ArchHandler_arm::stubName(const DefinedAtom &stubAtom) {
+ assert(stubAtom.contentType() == DefinedAtom::typeStub);
+ for (const Reference *ref : stubAtom) {
+ if (const DefinedAtom* lp = dyn_cast<DefinedAtom>(ref->target())) {
+ if (lp->contentType() != DefinedAtom::typeLazyPointer)
+ continue;
+ for (const Reference *ref2 : *lp) {
+ if (ref2->kindValue() != lazyPointer)
+ continue;
+ return ref2->target()->name();
+ }
+ }
+ }
+ return "stub";
+}
+
+/// Extract displacement from an ARM b/bl/blx instruction.
+int32_t ArchHandler_arm::getDisplacementFromArmBranch(uint32_t instruction) {
+ // Sign-extend imm24
+ int32_t displacement = (instruction & 0x00FFFFFF) << 2;
+ if ((displacement & 0x02000000) != 0)
+ displacement |= 0xFC000000;
+ // If this is BLX and H bit set, add 2.
+ if ((instruction & 0xFF000000) == 0xFB000000)
+ displacement += 2;
+ return displacement;
+}
+
+/// Update an ARM b/bl/blx instruction, switching bl <-> blx as needed.
+uint32_t ArchHandler_arm::setDisplacementInArmBranch(uint32_t instruction,
+ int32_t displacement,
+ bool targetIsThumb) {
+ assert((displacement <= 33554428) && (displacement > (-33554432))
+ && "arm branch out of range");
+ bool is_blx = ((instruction & 0xF0000000) == 0xF0000000);
+ uint32_t newInstruction = (instruction & 0xFF000000);
+ uint32_t h = 0;
+ if (targetIsThumb) {
+ // Force use of BLX.
+ newInstruction = 0xFA000000;
+ if (!is_blx) {
+ assert(((instruction & 0xF0000000) == 0xE0000000)
+ && "no conditional arm blx");
+ assert(((instruction & 0xFF000000) == 0xEB000000)
+ && "no arm pc-rel BX instruction");
+ }
+ if (displacement & 2)
+ h = 1;
+ }
+ else {
+ // Force use of B/BL.
+ if (is_blx)
+ newInstruction = 0xEB000000;
+ }
+ newInstruction |= (h << 24) | ((displacement >> 2) & 0x00FFFFFF);
+ return newInstruction;
+}
+
+/// Extract displacement from a thumb b/bl/blx instruction.
+int32_t ArchHandler_arm::getDisplacementFromThumbBranch(uint32_t instruction,
+ uint32_t instrAddr) {
+ bool is_blx = ((instruction & 0xD000F800) == 0xC000F000);
+ uint32_t s = (instruction >> 10) & 0x1;
+ uint32_t j1 = (instruction >> 29) & 0x1;
+ uint32_t j2 = (instruction >> 27) & 0x1;
+ uint32_t imm10 = instruction & 0x3FF;
+ uint32_t imm11 = (instruction >> 16) & 0x7FF;
+ uint32_t i1 = (j1 == s);
+ uint32_t i2 = (j2 == s);
+ uint32_t dis =
+ (s << 24) | (i1 << 23) | (i2 << 22) | (imm10 << 12) | (imm11 << 1);
+ int32_t sdis = dis;
+ int32_t result = s ? (sdis | 0xFE000000) : sdis;
+ if (is_blx && (instrAddr & 0x2)) {
+ // The thumb blx instruction always has low bit of imm11 as zero. The way
+ // a 2-byte aligned blx can branch to a 4-byte aligned ARM target is that
+ // the blx instruction always 4-byte aligns the pc before adding the
+ // displacement from the blx. We must emulate that when decoding this.
+ result -= 2;
+ }
+ return result;
+}
+
+/// Update a thumb b/bl/blx instruction, switching bl <-> blx as needed.
+uint32_t ArchHandler_arm::setDisplacementInThumbBranch(uint32_t instruction,
+ uint32_t instrAddr,
+ int32_t displacement,
+ bool targetIsThumb) {
+ assert((displacement <= 16777214) && (displacement > (-16777216))
+ && "thumb branch out of range");
+ bool is_bl = ((instruction & 0xD000F800) == 0xD000F000);
+ bool is_blx = ((instruction & 0xD000F800) == 0xC000F000);
+ bool is_b = ((instruction & 0xD000F800) == 0x9000F000);
+ uint32_t newInstruction = (instruction & 0xD000F800);
+ if (is_bl || is_blx) {
+ if (targetIsThumb) {
+ newInstruction = 0xD000F000; // Use bl
+ } else {
+ newInstruction = 0xC000F000; // Use blx
+ // See note in getDisplacementFromThumbBranch() about blx.
+ if (instrAddr & 0x2)
+ displacement += 2;
+ }
+ } else if (is_b) {
+ assert(targetIsThumb && "no pc-rel thumb branch instruction that "
+ "switches to arm mode");
+ }
+ else {
+ llvm_unreachable("thumb branch22 reloc on a non-branch instruction");
+ }
+ uint32_t s = (uint32_t)(displacement >> 24) & 0x1;
+ uint32_t i1 = (uint32_t)(displacement >> 23) & 0x1;
+ uint32_t i2 = (uint32_t)(displacement >> 22) & 0x1;
+ uint32_t imm10 = (uint32_t)(displacement >> 12) & 0x3FF;
+ uint32_t imm11 = (uint32_t)(displacement >> 1) & 0x7FF;
+ uint32_t j1 = (i1 == s);
+ uint32_t j2 = (i2 == s);
+ uint32_t nextDisp = (j1 << 13) | (j2 << 11) | imm11;
+ uint32_t firstDisp = (s << 10) | imm10;
+ newInstruction |= (nextDisp << 16) | firstDisp;
+ return newInstruction;
+}
+
+bool ArchHandler_arm::isThumbMovw(uint32_t instruction) {
+ return (instruction & 0x8000FBF0) == 0x0000F240;
+}
+
+bool ArchHandler_arm::isThumbMovt(uint32_t instruction) {
+ return (instruction & 0x8000FBF0) == 0x0000F2C0;
+}
+
+bool ArchHandler_arm::isArmMovw(uint32_t instruction) {
+ return (instruction & 0x0FF00000) == 0x03000000;
+}
+
+bool ArchHandler_arm::isArmMovt(uint32_t instruction) {
+ return (instruction & 0x0FF00000) == 0x03400000;
+}
+
+uint16_t ArchHandler_arm::getWordFromThumbMov(uint32_t instruction) {
+ assert(isThumbMovw(instruction) || isThumbMovt(instruction));
+ uint32_t i = ((instruction & 0x00000400) >> 10);
+ uint32_t imm4 = (instruction & 0x0000000F);
+ uint32_t imm3 = ((instruction & 0x70000000) >> 28);
+ uint32_t imm8 = ((instruction & 0x00FF0000) >> 16);
+ return (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8;
+}
+
+uint16_t ArchHandler_arm::getWordFromArmMov(uint32_t instruction) {
+ assert(isArmMovw(instruction) || isArmMovt(instruction));
+ uint32_t imm4 = ((instruction & 0x000F0000) >> 16);
+ uint32_t imm12 = (instruction & 0x00000FFF);
+ return (imm4 << 12) | imm12;
+}
+
+uint32_t ArchHandler_arm::setWordFromThumbMov(uint32_t instr, uint16_t word) {
+ assert(isThumbMovw(instr) || isThumbMovt(instr));
+ uint32_t imm4 = (word & 0xF000) >> 12;
+ uint32_t i = (word & 0x0800) >> 11;
+ uint32_t imm3 = (word & 0x0700) >> 8;
+ uint32_t imm8 = word & 0x00FF;
+ return (instr & 0x8F00FBF0) | imm4 | (i << 10) | (imm3 << 28) | (imm8 << 16);
+}
+
+uint32_t ArchHandler_arm::setWordFromArmMov(uint32_t instr, uint16_t word) {
+ assert(isArmMovw(instr) || isArmMovt(instr));
+ uint32_t imm4 = (word & 0xF000) >> 12;
+ uint32_t imm12 = word & 0x0FFF;
+ return (instr & 0xFFF0F000) | (imm4 << 16) | imm12;
+}
+
+uint32_t ArchHandler_arm::clearThumbBit(uint32_t value, const Atom *target) {
+ // The assembler often adds one to the address of a thumb function.
+ // We need to undo that so it does not look like an addend.
+ if (value & 1) {
+ if (isa<DefinedAtom>(target)) {
+ const MachODefinedAtom *machoTarget =
+ reinterpret_cast<const MachODefinedAtom *>(target);
+ if (machoTarget->isThumb())
+ value &= -2; // mask off thumb-bit
+ }
+ }
+ return value;
+}
+
+llvm::Error ArchHandler_arm::getReferenceInfo(
+ const Relocation &reloc, const DefinedAtom *inAtom, uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool isBig,
+ FindAtomBySectionAndAddress atomFromAddress,
+ FindAtomBySymbolIndex atomFromSymbolIndex, Reference::KindValue *kind,
+ const lld::Atom **target, Reference::Addend *addend) {
+ const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+ uint64_t targetAddress;
+ uint32_t instruction = *(const ulittle32_t *)fixupContent;
+ int32_t displacement;
+ switch (relocPattern(reloc)) {
+ case ARM_THUMB_RELOC_BR22 | rPcRel | rExtern | rLength4:
+ // ex: bl _foo (and _foo is undefined)
+ if ((instruction & 0xD000F800) == 0x9000F000)
+ *kind = thumb_b22;
+ else
+ *kind = thumb_bl22;
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ // Instruction contains branch to addend.
+ displacement = getDisplacementFromThumbBranch(instruction, fixupAddress);
+ *addend = fixupAddress + 4 + displacement;
+ return llvm::Error::success();
+ case ARM_THUMB_RELOC_BR22 | rPcRel | rLength4:
+ // ex: bl _foo (and _foo is defined)
+ if ((instruction & 0xD000F800) == 0x9000F000)
+ *kind = thumb_b22;
+ else
+ *kind = thumb_bl22;
+ displacement = getDisplacementFromThumbBranch(instruction, fixupAddress);
+ targetAddress = fixupAddress + 4 + displacement;
+ return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+ case ARM_THUMB_RELOC_BR22 | rScattered | rPcRel | rLength4:
+ // ex: bl _foo+4 (and _foo is defined)
+ if ((instruction & 0xD000F800) == 0x9000F000)
+ *kind = thumb_b22;
+ else
+ *kind = thumb_bl22;
+ displacement = getDisplacementFromThumbBranch(instruction, fixupAddress);
+ targetAddress = fixupAddress + 4 + displacement;
+ if (auto ec = atomFromAddress(0, reloc.value, target, addend))
+ return ec;
+ // reloc.value is target atom's address. Instruction contains branch
+ // to atom+addend.
+ *addend += (targetAddress - reloc.value);
+ return llvm::Error::success();
+ case ARM_RELOC_BR24 | rPcRel | rExtern | rLength4:
+ // ex: bl _foo (and _foo is undefined)
+ if (((instruction & 0x0F000000) == 0x0A000000)
+ && ((instruction & 0xF0000000) != 0xF0000000))
+ *kind = arm_b24;
+ else
+ *kind = arm_bl24;
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ // Instruction contains branch to addend.
+ displacement = getDisplacementFromArmBranch(instruction);
+ *addend = fixupAddress + 8 + displacement;
+ return llvm::Error::success();
+ case ARM_RELOC_BR24 | rPcRel | rLength4:
+ // ex: bl _foo (and _foo is defined)
+ if (((instruction & 0x0F000000) == 0x0A000000)
+ && ((instruction & 0xF0000000) != 0xF0000000))
+ *kind = arm_b24;
+ else
+ *kind = arm_bl24;
+ displacement = getDisplacementFromArmBranch(instruction);
+ targetAddress = fixupAddress + 8 + displacement;
+ return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+ case ARM_RELOC_BR24 | rScattered | rPcRel | rLength4:
+ // ex: bl _foo+4 (and _foo is defined)
+ if (((instruction & 0x0F000000) == 0x0A000000)
+ && ((instruction & 0xF0000000) != 0xF0000000))
+ *kind = arm_b24;
+ else
+ *kind = arm_bl24;
+ displacement = getDisplacementFromArmBranch(instruction);
+ targetAddress = fixupAddress + 8 + displacement;
+ if (auto ec = atomFromAddress(0, reloc.value, target, addend))
+ return ec;
+ // reloc.value is target atom's address. Instruction contains branch
+ // to atom+addend.
+ *addend += (targetAddress - reloc.value);
+ return llvm::Error::success();
+ case ARM_RELOC_VANILLA | rExtern | rLength4:
+ // ex: .long _foo (and _foo is undefined)
+ *kind = pointer32;
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = instruction;
+ return llvm::Error::success();
+ case ARM_RELOC_VANILLA | rLength4:
+ // ex: .long _foo (and _foo is defined)
+ *kind = pointer32;
+ if (auto ec = atomFromAddress(reloc.symbol, instruction, target, addend))
+ return ec;
+ *addend = clearThumbBit((uint32_t) * addend, *target);
+ return llvm::Error::success();
+ case ARM_RELOC_VANILLA | rScattered | rLength4:
+ // ex: .long _foo+a (and _foo is defined)
+ *kind = pointer32;
+ if (auto ec = atomFromAddress(0, reloc.value, target, addend))
+ return ec;
+ *addend += (clearThumbBit(instruction, *target) - reloc.value);
+ return llvm::Error::success();
+ default:
+ return llvm::make_error<GenericError>("unsupported arm relocation type");
+ }
+ return llvm::Error::success();
+}
+
+llvm::Error
+ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1,
+ const normalized::Relocation &reloc2,
+ const DefinedAtom *inAtom,
+ uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool isBig,
+ bool scatterable,
+ FindAtomBySectionAndAddress atomFromAddr,
+ FindAtomBySymbolIndex atomFromSymbolIndex,
+ Reference::KindValue *kind,
+ const lld::Atom **target,
+ Reference::Addend *addend) {
+ bool pointerDiff = false;
+ bool funcRel;
+ bool top;
+ bool thumbReloc;
+ switch(relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
+ case ((ARM_RELOC_HALF_SECTDIFF | rScattered | rLenThmbLo) << 16 |
+ ARM_RELOC_PAIR | rScattered | rLenThmbLo):
+ // ex: movw r1, :lower16:(_x-L1) [thumb mode]
+ *kind = thumb_movw_funcRel;
+ funcRel = true;
+ top = false;
+ thumbReloc = true;
+ break;
+ case ((ARM_RELOC_HALF_SECTDIFF | rScattered | rLenThmbHi) << 16 |
+ ARM_RELOC_PAIR | rScattered | rLenThmbHi):
+ // ex: movt r1, :upper16:(_x-L1) [thumb mode]
+ *kind = thumb_movt_funcRel;
+ funcRel = true;
+ top = true;
+ thumbReloc = true;
+ break;
+ case ((ARM_RELOC_HALF_SECTDIFF | rScattered | rLenArmLo) << 16 |
+ ARM_RELOC_PAIR | rScattered | rLenArmLo):
+ // ex: movw r1, :lower16:(_x-L1) [arm mode]
+ *kind = arm_movw_funcRel;
+ funcRel = true;
+ top = false;
+ thumbReloc = false;
+ break;
+ case ((ARM_RELOC_HALF_SECTDIFF | rScattered | rLenArmHi) << 16 |
+ ARM_RELOC_PAIR | rScattered | rLenArmHi):
+ // ex: movt r1, :upper16:(_x-L1) [arm mode]
+ *kind = arm_movt_funcRel;
+ funcRel = true;
+ top = true;
+ thumbReloc = false;
+ break;
+ case ((ARM_RELOC_HALF | rLenThmbLo) << 16 |
+ ARM_RELOC_PAIR | rLenThmbLo):
+ // ex: movw r1, :lower16:_x [thumb mode]
+ *kind = thumb_movw;
+ funcRel = false;
+ top = false;
+ thumbReloc = true;
+ break;
+ case ((ARM_RELOC_HALF | rLenThmbHi) << 16 |
+ ARM_RELOC_PAIR | rLenThmbHi):
+ // ex: movt r1, :upper16:_x [thumb mode]
+ *kind = thumb_movt;
+ funcRel = false;
+ top = true;
+ thumbReloc = true;
+ break;
+ case ((ARM_RELOC_HALF | rLenArmLo) << 16 |
+ ARM_RELOC_PAIR | rLenArmLo):
+ // ex: movw r1, :lower16:_x [arm mode]
+ *kind = arm_movw;
+ funcRel = false;
+ top = false;
+ thumbReloc = false;
+ break;
+ case ((ARM_RELOC_HALF | rLenArmHi) << 16 |
+ ARM_RELOC_PAIR | rLenArmHi):
+ // ex: movt r1, :upper16:_x [arm mode]
+ *kind = arm_movt;
+ funcRel = false;
+ top = true;
+ thumbReloc = false;
+ break;
+ case ((ARM_RELOC_HALF | rScattered | rLenThmbLo) << 16 |
+ ARM_RELOC_PAIR | rLenThmbLo):
+ // ex: movw r1, :lower16:_x+a [thumb mode]
+ *kind = thumb_movw;
+ funcRel = false;
+ top = false;
+ thumbReloc = true;
+ break;
+ case ((ARM_RELOC_HALF | rScattered | rLenThmbHi) << 16 |
+ ARM_RELOC_PAIR | rLenThmbHi):
+ // ex: movt r1, :upper16:_x+a [thumb mode]
+ *kind = thumb_movt;
+ funcRel = false;
+ top = true;
+ thumbReloc = true;
+ break;
+ case ((ARM_RELOC_HALF | rScattered | rLenArmLo) << 16 |
+ ARM_RELOC_PAIR | rLenArmLo):
+ // ex: movw r1, :lower16:_x+a [arm mode]
+ *kind = arm_movw;
+ funcRel = false;
+ top = false;
+ thumbReloc = false;
+ break;
+ case ((ARM_RELOC_HALF | rScattered | rLenArmHi) << 16 |
+ ARM_RELOC_PAIR | rLenArmHi):
+ // ex: movt r1, :upper16:_x+a [arm mode]
+ *kind = arm_movt;
+ funcRel = false;
+ top = true;
+ thumbReloc = false;
+ break;
+ case ((ARM_RELOC_HALF | rExtern | rLenThmbLo) << 16 |
+ ARM_RELOC_PAIR | rLenThmbLo):
+ // ex: movw r1, :lower16:_undef [thumb mode]
+ *kind = thumb_movw;
+ funcRel = false;
+ top = false;
+ thumbReloc = true;
+ break;
+ case ((ARM_RELOC_HALF | rExtern | rLenThmbHi) << 16 |
+ ARM_RELOC_PAIR | rLenThmbHi):
+ // ex: movt r1, :upper16:_undef [thumb mode]
+ *kind = thumb_movt;
+ funcRel = false;
+ top = true;
+ thumbReloc = true;
+ break;
+ case ((ARM_RELOC_HALF | rExtern | rLenArmLo) << 16 |
+ ARM_RELOC_PAIR | rLenArmLo):
+ // ex: movw r1, :lower16:_undef [arm mode]
+ *kind = arm_movw;
+ funcRel = false;
+ top = false;
+ thumbReloc = false;
+ break;
+ case ((ARM_RELOC_HALF | rExtern | rLenArmHi) << 16 |
+ ARM_RELOC_PAIR | rLenArmHi):
+ // ex: movt r1, :upper16:_undef [arm mode]
+ *kind = arm_movt;
+ funcRel = false;
+ top = true;
+ thumbReloc = false;
+ break;
+ case ((ARM_RELOC_SECTDIFF | rScattered | rLength4) << 16 |
+ ARM_RELOC_PAIR | rScattered | rLength4):
+ case ((ARM_RELOC_LOCAL_SECTDIFF | rScattered | rLength4) << 16 |
+ ARM_RELOC_PAIR | rScattered | rLength4):
+ // ex: .long _foo - .
+ pointerDiff = true;
+ break;
+ default:
+ return llvm::make_error<GenericError>("unsupported arm relocation pair");
+ }
+ const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+ uint32_t instruction = *(const ulittle32_t *)fixupContent;
+ uint32_t value;
+ uint32_t fromAddress;
+ uint32_t toAddress;
+ uint16_t instruction16;
+ uint16_t other16;
+ const lld::Atom *fromTarget;
+ Reference::Addend offsetInTo;
+ Reference::Addend offsetInFrom;
+ if (pointerDiff) {
+ toAddress = reloc1.value;
+ fromAddress = reloc2.value;
+ if (auto ec = atomFromAddr(0, toAddress, target, &offsetInTo))
+ return ec;
+ if (auto ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom))
+ return ec;
+ if (scatterable && (fromTarget != inAtom))
+ return llvm::make_error<GenericError>(
+ "SECTDIFF relocation where subtrahend label is not in atom");
+ *kind = delta32;
+ value = clearThumbBit(instruction, *target);
+ *addend = (int32_t)(value - (toAddress - fixupAddress));
+ } else if (funcRel) {
+ toAddress = reloc1.value;
+ fromAddress = reloc2.value;
+ if (auto ec = atomFromAddr(0, toAddress, target, &offsetInTo))
+ return ec;
+ if (auto ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom))
+ return ec;
+ if (fromTarget != inAtom)
+ return llvm::make_error<GenericError>("ARM_RELOC_HALF_SECTDIFF relocation"
+ " where subtrahend label is not in atom");
+ other16 = (reloc2.offset & 0xFFFF);
+ if (thumbReloc) {
+ if (top) {
+ if (!isThumbMovt(instruction))
+ return llvm::make_error<GenericError>("expected movt instruction");
+ }
+ else {
+ if (!isThumbMovw(instruction))
+ return llvm::make_error<GenericError>("expected movw instruction");
+ }
+ instruction16 = getWordFromThumbMov(instruction);
+ }
+ else {
+ if (top) {
+ if (!isArmMovt(instruction))
+ return llvm::make_error<GenericError>("expected movt instruction");
+ }
+ else {
+ if (!isArmMovw(instruction))
+ return llvm::make_error<GenericError>("expected movw instruction");
+ }
+ instruction16 = getWordFromArmMov(instruction);
+ }
+ if (top)
+ value = (instruction16 << 16) | other16;
+ else
+ value = (other16 << 16) | instruction16;
+ value = clearThumbBit(value, *target);
+ int64_t ta = (int64_t) value - (toAddress - fromAddress);
+ *addend = ta - offsetInFrom;
+ return llvm::Error::success();
+ } else {
+ uint32_t sectIndex;
+ if (thumbReloc) {
+ if (top) {
+ if (!isThumbMovt(instruction))
+ return llvm::make_error<GenericError>("expected movt instruction");
+ }
+ else {
+ if (!isThumbMovw(instruction))
+ return llvm::make_error<GenericError>("expected movw instruction");
+ }
+ instruction16 = getWordFromThumbMov(instruction);
+ }
+ else {
+ if (top) {
+ if (!isArmMovt(instruction))
+ return llvm::make_error<GenericError>("expected movt instruction");
+ }
+ else {
+ if (!isArmMovw(instruction))
+ return llvm::make_error<GenericError>("expected movw instruction");
+ }
+ instruction16 = getWordFromArmMov(instruction);
+ }
+ other16 = (reloc2.offset & 0xFFFF);
+ if (top)
+ value = (instruction16 << 16) | other16;
+ else
+ value = (other16 << 16) | instruction16;
+ if (reloc1.isExtern) {
+ if (auto ec = atomFromSymbolIndex(reloc1.symbol, target))
+ return ec;
+ *addend = value;
+ } else {
+ if (reloc1.scattered) {
+ toAddress = reloc1.value;
+ sectIndex = 0;
+ } else {
+ toAddress = value;
+ sectIndex = reloc1.symbol;
+ }
+ if (auto ec = atomFromAddr(sectIndex, toAddress, target, &offsetInTo))
+ return ec;
+ *addend = value - toAddress;
+ }
+ }
+
+ return llvm::Error::success();
+}
+
+void ArchHandler_arm::applyFixupFinal(const Reference &ref, uint8_t *loc,
+ uint64_t fixupAddress,
+ uint64_t targetAddress,
+ uint64_t inAtomAddress,
+ bool &thumbMode, bool targetIsThumb) {
+ if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+ return;
+ assert(ref.kindArch() == Reference::KindArch::ARM);
+ ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
+ int32_t displacement;
+ uint16_t value16;
+ uint32_t value32;
+ switch (static_cast<ArmKind>(ref.kindValue())) {
+ case modeThumbCode:
+ thumbMode = true;
+ break;
+ case modeArmCode:
+ thumbMode = false;
+ break;
+ case modeData:
+ break;
+ case thumb_b22:
+ case thumb_bl22:
+ assert(thumbMode);
+ displacement = (targetAddress - (fixupAddress + 4)) + ref.addend();
+ value32 = setDisplacementInThumbBranch(*loc32, fixupAddress,
+ displacement, targetIsThumb);
+ *loc32 = value32;
+ break;
+ case thumb_movw:
+ assert(thumbMode);
+ value16 = (targetAddress + ref.addend()) & 0xFFFF;
+ if (targetIsThumb)
+ value16 |= 1;
+ *loc32 = setWordFromThumbMov(*loc32, value16);
+ break;
+ case thumb_movt:
+ assert(thumbMode);
+ value16 = (targetAddress + ref.addend()) >> 16;
+ *loc32 = setWordFromThumbMov(*loc32, value16);
+ break;
+ case thumb_movw_funcRel:
+ assert(thumbMode);
+ value16 = (targetAddress - inAtomAddress + ref.addend()) & 0xFFFF;
+ if (targetIsThumb)
+ value16 |= 1;
+ *loc32 = setWordFromThumbMov(*loc32, value16);
+ break;
+ case thumb_movt_funcRel:
+ assert(thumbMode);
+ value16 = (targetAddress - inAtomAddress + ref.addend()) >> 16;
+ *loc32 = setWordFromThumbMov(*loc32, value16);
+ break;
+ case arm_b24:
+ case arm_bl24:
+ assert(!thumbMode);
+ displacement = (targetAddress - (fixupAddress + 8)) + ref.addend();
+ value32 = setDisplacementInArmBranch(*loc32, displacement, targetIsThumb);
+ *loc32 = value32;
+ break;
+ case arm_movw:
+ assert(!thumbMode);
+ value16 = (targetAddress + ref.addend()) & 0xFFFF;
+ if (targetIsThumb)
+ value16 |= 1;
+ *loc32 = setWordFromArmMov(*loc32, value16);
+ break;
+ case arm_movt:
+ assert(!thumbMode);
+ value16 = (targetAddress + ref.addend()) >> 16;
+ *loc32 = setWordFromArmMov(*loc32, value16);
+ break;
+ case arm_movw_funcRel:
+ assert(!thumbMode);
+ value16 = (targetAddress - inAtomAddress + ref.addend()) & 0xFFFF;
+ if (targetIsThumb)
+ value16 |= 1;
+ *loc32 = setWordFromArmMov(*loc32, value16);
+ break;
+ case arm_movt_funcRel:
+ assert(!thumbMode);
+ value16 = (targetAddress - inAtomAddress + ref.addend()) >> 16;
+ *loc32 = setWordFromArmMov(*loc32, value16);
+ break;
+ case pointer32:
+ if (targetIsThumb)
+ *loc32 = targetAddress + ref.addend() + 1;
+ else
+ *loc32 = targetAddress + ref.addend();
+ break;
+ case delta32:
+ if (targetIsThumb)
+ *loc32 = targetAddress - fixupAddress + ref.addend() + 1;
+ else
+ *loc32 = targetAddress - fixupAddress + ref.addend();
+ break;
+ case lazyPointer:
+ // do nothing
+ break;
+ case lazyImmediateLocation:
+ *loc32 = ref.addend();
+ break;
+ case invalid:
+ llvm_unreachable("invalid ARM Reference Kind");
+ break;
+ }
+}
+
+void ArchHandler_arm::generateAtomContent(const DefinedAtom &atom,
+ bool relocatable,
+ FindAddressForAtom findAddress,
+ FindAddressForAtom findSectionAddress,
+ uint64_t imageBaseAddress,
+ llvm::MutableArrayRef<uint8_t> atomContentBuffer) {
+ // Copy raw bytes.
+ std::copy(atom.rawContent().begin(), atom.rawContent().end(),
+ atomContentBuffer.begin());
+ // Apply fix-ups.
+ bool thumbMode = false;
+ for (const Reference *ref : atom) {
+ uint32_t offset = ref->offsetInAtom();
+ const Atom *target = ref->target();
+ uint64_t targetAddress = 0;
+ bool targetIsThumb = false;
+ if (const DefinedAtom *defTarg = dyn_cast<DefinedAtom>(target)) {
+ targetAddress = findAddress(*target);
+ targetIsThumb = isThumbFunction(*defTarg);
+ }
+ uint64_t atomAddress = findAddress(atom);
+ uint64_t fixupAddress = atomAddress + offset;
+ if (relocatable) {
+ applyFixupRelocatable(*ref, &atomContentBuffer[offset], fixupAddress,
+ targetAddress, atomAddress, thumbMode,
+ targetIsThumb);
+ } else {
+ applyFixupFinal(*ref, &atomContentBuffer[offset], fixupAddress,
+ targetAddress, atomAddress, thumbMode, targetIsThumb);
+ }
+ }
+}
+
+bool ArchHandler_arm::useExternalRelocationTo(const Atom &target) {
+ // Undefined symbols are referenced via external relocations.
+ if (isa<UndefinedAtom>(&target))
+ return true;
+ if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(&target)) {
+ switch (defAtom->merge()) {
+ case DefinedAtom::mergeAsTentative:
+ // Tentative definitions are referenced via external relocations.
+ return true;
+ case DefinedAtom::mergeAsWeak:
+ case DefinedAtom::mergeAsWeakAndAddressUsed:
+ // Global weak-defs are referenced via external relocations.
+ return (defAtom->scope() == DefinedAtom::scopeGlobal);
+ default:
+ break;
+ }
+ }
+ // Everything else is reference via an internal relocation.
+ return false;
+}
+
+void ArchHandler_arm::applyFixupRelocatable(const Reference &ref, uint8_t *loc,
+ uint64_t fixupAddress,
+ uint64_t targetAddress,
+ uint64_t inAtomAddress,
+ bool &thumbMode,
+ bool targetIsThumb) {
+ if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+ return;
+ assert(ref.kindArch() == Reference::KindArch::ARM);
+ bool useExternalReloc = useExternalRelocationTo(*ref.target());
+ ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
+ int32_t displacement;
+ uint16_t value16;
+ uint32_t value32;
+ bool targetIsUndef = isa<UndefinedAtom>(ref.target());
+ switch (static_cast<ArmKind>(ref.kindValue())) {
+ case modeThumbCode:
+ thumbMode = true;
+ break;
+ case modeArmCode:
+ thumbMode = false;
+ break;
+ case modeData:
+ break;
+ case thumb_b22:
+ case thumb_bl22:
+ assert(thumbMode);
+ if (useExternalReloc)
+ displacement = (ref.addend() - (fixupAddress + 4));
+ else
+ displacement = (targetAddress - (fixupAddress + 4)) + ref.addend();
+ value32 = setDisplacementInThumbBranch(*loc32, fixupAddress,
+ displacement,
+ targetIsUndef || targetIsThumb);
+ *loc32 = value32;
+ break;
+ case thumb_movw:
+ assert(thumbMode);
+ if (useExternalReloc)
+ value16 = ref.addend() & 0xFFFF;
+ else
+ value16 = (targetAddress + ref.addend()) & 0xFFFF;
+ *loc32 = setWordFromThumbMov(*loc32, value16);
+ break;
+ case thumb_movt:
+ assert(thumbMode);
+ if (useExternalReloc)
+ value16 = ref.addend() >> 16;
+ else
+ value16 = (targetAddress + ref.addend()) >> 16;
+ *loc32 = setWordFromThumbMov(*loc32, value16);
+ break;
+ case thumb_movw_funcRel:
+ assert(thumbMode);
+ value16 = (targetAddress - inAtomAddress + ref.addend()) & 0xFFFF;
+ *loc32 = setWordFromThumbMov(*loc32, value16);
+ break;
+ case thumb_movt_funcRel:
+ assert(thumbMode);
+ value16 = (targetAddress - inAtomAddress + ref.addend()) >> 16;
+ *loc32 = setWordFromThumbMov(*loc32, value16);
+ break;
+ case arm_b24:
+ case arm_bl24:
+ assert(!thumbMode);
+ if (useExternalReloc)
+ displacement = (ref.addend() - (fixupAddress + 8));
+ else
+ displacement = (targetAddress - (fixupAddress + 8)) + ref.addend();
+ value32 = setDisplacementInArmBranch(*loc32, displacement,
+ targetIsThumb);
+ *loc32 = value32;
+ break;
+ case arm_movw:
+ assert(!thumbMode);
+ if (useExternalReloc)
+ value16 = ref.addend() & 0xFFFF;
+ else
+ value16 = (targetAddress + ref.addend()) & 0xFFFF;
+ *loc32 = setWordFromArmMov(*loc32, value16);
+ break;
+ case arm_movt:
+ assert(!thumbMode);
+ if (useExternalReloc)
+ value16 = ref.addend() >> 16;
+ else
+ value16 = (targetAddress + ref.addend()) >> 16;
+ *loc32 = setWordFromArmMov(*loc32, value16);
+ break;
+ case arm_movw_funcRel:
+ assert(!thumbMode);
+ value16 = (targetAddress - inAtomAddress + ref.addend()) & 0xFFFF;
+ *loc32 = setWordFromArmMov(*loc32, value16);
+ break;
+ case arm_movt_funcRel:
+ assert(!thumbMode);
+ value16 = (targetAddress - inAtomAddress + ref.addend()) >> 16;
+ *loc32 = setWordFromArmMov(*loc32, value16);
+ break;
+ case pointer32:
+ *loc32 = targetAddress + ref.addend();
+ break;
+ case delta32:
+ *loc32 = targetAddress - fixupAddress + ref.addend();
+ break;
+ case lazyPointer:
+ case lazyImmediateLocation:
+ // do nothing
+ break;
+ case invalid:
+ llvm_unreachable("invalid ARM Reference Kind");
+ break;
+ }
+}
+
+void ArchHandler_arm::appendSectionRelocations(
+ const DefinedAtom &atom,
+ uint64_t atomSectionOffset,
+ const Reference &ref,
+ FindSymbolIndexForAtom symbolIndexForAtom,
+ FindSectionIndexForAtom sectionIndexForAtom,
+ FindAddressForAtom addressForAtom,
+ normalized::Relocations &relocs) {
+ if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+ return;
+ assert(ref.kindArch() == Reference::KindArch::ARM);
+ uint32_t sectionOffset = atomSectionOffset + ref.offsetInAtom();
+ bool useExternalReloc = useExternalRelocationTo(*ref.target());
+ uint32_t targetAtomAddress;
+ uint32_t fromAtomAddress;
+ uint16_t other16;
+ switch (static_cast<ArmKind>(ref.kindValue())) {
+ case modeThumbCode:
+ case modeArmCode:
+ case modeData:
+ // Do nothing.
+ break;
+ case thumb_b22:
+ case thumb_bl22:
+ if (useExternalReloc) {
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ ARM_THUMB_RELOC_BR22 | rExtern | rPcRel | rLength4);
+ } else {
+ if (ref.addend() != 0)
+ appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
+ ARM_THUMB_RELOC_BR22 | rScattered | rPcRel | rLength4);
+ else
+ appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
+ ARM_THUMB_RELOC_BR22 | rPcRel | rLength4);
+ }
+ break;
+ case thumb_movw:
+ if (useExternalReloc) {
+ other16 = ref.addend() >> 16;
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ ARM_RELOC_HALF | rExtern | rLenThmbLo);
+ appendReloc(relocs, other16, 0, 0,
+ ARM_RELOC_PAIR | rLenThmbLo);
+ } else {
+ targetAtomAddress = addressForAtom(*ref.target());
+ if (ref.addend() != 0) {
+ other16 = (targetAtomAddress + ref.addend()) >> 16;
+ appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
+ ARM_RELOC_HALF | rScattered | rLenThmbLo);
+ appendReloc(relocs, other16, 0, 0,
+ ARM_RELOC_PAIR | rLenThmbLo);
+ } else {
+ other16 = (targetAtomAddress + ref.addend()) >> 16;
+ appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
+ ARM_RELOC_HALF | rLenThmbLo);
+ appendReloc(relocs, other16, 0, 0,
+ ARM_RELOC_PAIR | rLenThmbLo);
+ }
+ }
+ break;
+ case thumb_movt:
+ if (useExternalReloc) {
+ other16 = ref.addend() & 0xFFFF;
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ ARM_RELOC_HALF | rExtern | rLenThmbHi);
+ appendReloc(relocs, other16, 0, 0,
+ ARM_RELOC_PAIR | rLenThmbHi);
+ } else {
+ targetAtomAddress = addressForAtom(*ref.target());
+ if (ref.addend() != 0) {
+ other16 = (targetAtomAddress + ref.addend()) & 0xFFFF;
+ appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
+ ARM_RELOC_HALF | rScattered | rLenThmbHi);
+ appendReloc(relocs, other16, 0, 0,
+ ARM_RELOC_PAIR | rLenThmbHi);
+ } else {
+ other16 = (targetAtomAddress + ref.addend()) & 0xFFFF;
+ appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
+ ARM_RELOC_HALF | rLenThmbHi);
+ appendReloc(relocs, other16, 0, 0,
+ ARM_RELOC_PAIR | rLenThmbHi);
+ }
+ }
+ break;
+ case thumb_movw_funcRel:
+ fromAtomAddress = addressForAtom(atom);
+ targetAtomAddress = addressForAtom(*ref.target());
+ other16 = (targetAtomAddress - fromAtomAddress + ref.addend()) >> 16;
+ appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
+ ARM_RELOC_HALF_SECTDIFF | rScattered | rLenThmbLo);
+ appendReloc(relocs, other16, 0, fromAtomAddress,
+ ARM_RELOC_PAIR | rScattered | rLenThmbLo);
+ break;
+ case thumb_movt_funcRel:
+ fromAtomAddress = addressForAtom(atom);
+ targetAtomAddress = addressForAtom(*ref.target());
+ other16 = (targetAtomAddress - fromAtomAddress + ref.addend()) & 0xFFFF;
+ appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
+ ARM_RELOC_HALF_SECTDIFF | rScattered | rLenThmbHi);
+ appendReloc(relocs, other16, 0, fromAtomAddress,
+ ARM_RELOC_PAIR | rScattered | rLenThmbHi);
+ break;
+ case arm_b24:
+ case arm_bl24:
+ if (useExternalReloc) {
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ ARM_RELOC_BR24 | rExtern | rPcRel | rLength4);
+ } else {
+ if (ref.addend() != 0)
+ appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
+ ARM_RELOC_BR24 | rScattered | rPcRel | rLength4);
+ else
+ appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
+ ARM_RELOC_BR24 | rPcRel | rLength4);
+ }
+ break;
+ case arm_movw:
+ if (useExternalReloc) {
+ other16 = ref.addend() >> 16;
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ ARM_RELOC_HALF | rExtern | rLenArmLo);
+ appendReloc(relocs, other16, 0, 0,
+ ARM_RELOC_PAIR | rLenArmLo);
+ } else {
+ targetAtomAddress = addressForAtom(*ref.target());
+ if (ref.addend() != 0) {
+ other16 = (targetAtomAddress + ref.addend()) >> 16;
+ appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
+ ARM_RELOC_HALF | rScattered | rLenArmLo);
+ appendReloc(relocs, other16, 0, 0,
+ ARM_RELOC_PAIR | rLenArmLo);
+ } else {
+ other16 = (targetAtomAddress + ref.addend()) >> 16;
+ appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
+ ARM_RELOC_HALF | rLenArmLo);
+ appendReloc(relocs, other16, 0, 0,
+ ARM_RELOC_PAIR | rLenArmLo);
+ }
+ }
+ break;
+ case arm_movt:
+ if (useExternalReloc) {
+ other16 = ref.addend() & 0xFFFF;
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ ARM_RELOC_HALF | rExtern | rLenArmHi);
+ appendReloc(relocs, other16, 0, 0,
+ ARM_RELOC_PAIR | rLenArmHi);
+ } else {
+ targetAtomAddress = addressForAtom(*ref.target());
+ if (ref.addend() != 0) {
+ other16 = (targetAtomAddress + ref.addend()) & 0xFFFF;
+ appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
+ ARM_RELOC_HALF | rScattered | rLenArmHi);
+ appendReloc(relocs, other16, 0, 0,
+ ARM_RELOC_PAIR | rLenArmHi);
+ } else {
+ other16 = (targetAtomAddress + ref.addend()) & 0xFFFF;
+ appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
+ ARM_RELOC_HALF | rLenArmHi);
+ appendReloc(relocs, other16, 0, 0,
+ ARM_RELOC_PAIR | rLenArmHi);
+ }
+ }
+ break;
+ case arm_movw_funcRel:
+ fromAtomAddress = addressForAtom(atom);
+ targetAtomAddress = addressForAtom(*ref.target());
+ other16 = (targetAtomAddress - fromAtomAddress + ref.addend()) >> 16;
+ appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
+ ARM_RELOC_HALF_SECTDIFF | rScattered | rLenArmLo);
+ appendReloc(relocs, other16, 0, fromAtomAddress,
+ ARM_RELOC_PAIR | rScattered | rLenArmLo);
+ break;
+ case arm_movt_funcRel:
+ fromAtomAddress = addressForAtom(atom);
+ targetAtomAddress = addressForAtom(*ref.target());
+ other16 = (targetAtomAddress - fromAtomAddress + ref.addend()) & 0xFFFF;
+ appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
+ ARM_RELOC_HALF_SECTDIFF | rScattered | rLenArmHi);
+ appendReloc(relocs, other16, 0, fromAtomAddress,
+ ARM_RELOC_PAIR | rScattered | rLenArmHi);
+ break;
+ case pointer32:
+ if (useExternalReloc) {
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ ARM_RELOC_VANILLA | rExtern | rLength4);
+ }
+ else {
+ if (ref.addend() != 0)
+ appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
+ ARM_RELOC_VANILLA | rScattered | rLength4);
+ else
+ appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
+ ARM_RELOC_VANILLA | rLength4);
+ }
+ break;
+ case delta32:
+ appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
+ ARM_RELOC_SECTDIFF | rScattered | rLength4);
+ appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) +
+ ref.offsetInAtom(),
+ ARM_RELOC_PAIR | rScattered | rLength4);
+ break;
+ case lazyPointer:
+ case lazyImmediateLocation:
+ // do nothing
+ break;
+ case invalid:
+ llvm_unreachable("invalid ARM Reference Kind");
+ break;
+ }
+}
+
+void ArchHandler_arm::addAdditionalReferences(MachODefinedAtom &atom) {
+ if (atom.isThumb()) {
+ atom.addReference(Reference::KindNamespace::mach_o,
+ Reference::KindArch::ARM, modeThumbCode, 0, &atom, 0);
+ }
+}
+
+bool ArchHandler_arm::isThumbFunction(const DefinedAtom &atom) {
+ for (const Reference *ref : atom) {
+ if (ref->offsetInAtom() != 0)
+ return false;
+ if (ref->kindNamespace() != Reference::KindNamespace::mach_o)
+ continue;
+ assert(ref->kindArch() == Reference::KindArch::ARM);
+ if (ref->kindValue() == modeThumbCode)
+ return true;
+ }
+ return false;
+}
+
+class Thumb2ToArmShimAtom : public SimpleDefinedAtom {
+public:
+ Thumb2ToArmShimAtom(MachOFile &file, StringRef targetName,
+ const DefinedAtom &target)
+ : SimpleDefinedAtom(file) {
+ addReference(Reference::KindNamespace::mach_o, Reference::KindArch::ARM,
+ ArchHandler_arm::modeThumbCode, 0, this, 0);
+ addReference(Reference::KindNamespace::mach_o, Reference::KindArch::ARM,
+ ArchHandler_arm::delta32, 8, &target, 0);
+ std::string name = std::string(targetName) + "$shim";
+ StringRef tmp(name);
+ _name = tmp.copy(file.allocator());
+ }
+
+ ~Thumb2ToArmShimAtom() override = default;
+
+ StringRef name() const override {
+ return _name;
+ }
+
+ ContentType contentType() const override {
+ return DefinedAtom::typeCode;
+ }
+
+ Alignment alignment() const override { return 4; }
+
+ uint64_t size() const override {
+ return 12;
+ }
+
+ ContentPermissions permissions() const override {
+ return DefinedAtom::permR_X;
+ }
+
+ ArrayRef<uint8_t> rawContent() const override {
+ static const uint8_t bytes[] =
+ { 0xDF, 0xF8, 0x04, 0xC0, // ldr ip, pc + 4
+ 0xFF, 0x44, // add ip, pc, ip
+ 0x60, 0x47, // ldr pc, [ip]
+ 0x00, 0x00, 0x00, 0x00 }; // .long target - this
+ assert(sizeof(bytes) == size());
+ return llvm::makeArrayRef(bytes, sizeof(bytes));
+ }
+private:
+ StringRef _name;
+};
+
+class ArmToThumbShimAtom : public SimpleDefinedAtom {
+public:
+ ArmToThumbShimAtom(MachOFile &file, StringRef targetName,
+ const DefinedAtom &target)
+ : SimpleDefinedAtom(file) {
+ addReference(Reference::KindNamespace::mach_o, Reference::KindArch::ARM,
+ ArchHandler_arm::delta32, 12, &target, 0);
+ std::string name = std::string(targetName) + "$shim";
+ StringRef tmp(name);
+ _name = tmp.copy(file.allocator());
+ }
+
+ ~ArmToThumbShimAtom() override = default;
+
+ StringRef name() const override {
+ return _name;
+ }
+
+ ContentType contentType() const override {
+ return DefinedAtom::typeCode;
+ }
+
+ Alignment alignment() const override { return 4; }
+
+ uint64_t size() const override {
+ return 16;
+ }
+
+ ContentPermissions permissions() const override {
+ return DefinedAtom::permR_X;
+ }
+
+ ArrayRef<uint8_t> rawContent() const override {
+ static const uint8_t bytes[] =
+ { 0x04, 0xC0, 0x9F, 0xE5, // ldr ip, pc + 4
+ 0x0C, 0xC0, 0x8F, 0xE0, // add ip, pc, ip
+ 0x1C, 0xFF, 0x2F, 0xE1, // ldr pc, [ip]
+ 0x00, 0x00, 0x00, 0x00 }; // .long target - this
+ assert(sizeof(bytes) == size());
+ return llvm::makeArrayRef(bytes, sizeof(bytes));
+ }
+private:
+ StringRef _name;
+};
+
+const DefinedAtom *ArchHandler_arm::createShim(MachOFile &file,
+ bool thumbToArm,
+ const DefinedAtom &target) {
+ bool isStub = (target.contentType() == DefinedAtom::typeStub);
+ StringRef targetName = isStub ? stubName(target) : target.name();
+ if (thumbToArm)
+ return new (file.allocator()) Thumb2ToArmShimAtom(file, targetName, target);
+ else
+ return new (file.allocator()) ArmToThumbShimAtom(file, targetName, target);
+}
+
+std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_arm() {
+ return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_arm());
+}
+
+} // namespace mach_o
+} // namespace lld
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp
new file mode 100644
index 000000000000..b9c815c5a320
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp
@@ -0,0 +1,898 @@
+//===- lib/FileFormat/MachO/ArchHandler_arm64.cpp -------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ArchHandler.h"
+#include "Atoms.h"
+#include "MachONormalizedFileBinaryUtils.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+
+using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
+
+namespace lld {
+namespace mach_o {
+
+using llvm::support::ulittle32_t;
+using llvm::support::ulittle64_t;
+
+using llvm::support::little32_t;
+using llvm::support::little64_t;
+
+class ArchHandler_arm64 : public ArchHandler {
+public:
+ ArchHandler_arm64() = default;
+ ~ArchHandler_arm64() override = default;
+
+ const Registry::KindStrings *kindStrings() override { return _sKindStrings; }
+
+ Reference::KindArch kindArch() override {
+ return Reference::KindArch::AArch64;
+ }
+
+ /// Used by GOTPass to locate GOT References
+ bool isGOTAccess(const Reference &ref, bool &canBypassGOT) override {
+ if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+ return false;
+ assert(ref.kindArch() == Reference::KindArch::AArch64);
+ switch (ref.kindValue()) {
+ case gotPage21:
+ case gotOffset12:
+ canBypassGOT = true;
+ return true;
+ case delta32ToGOT:
+ case unwindCIEToPersonalityFunction:
+ case imageOffsetGot:
+ canBypassGOT = false;
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /// Used by GOTPass to update GOT References.
+ void updateReferenceToGOT(const Reference *ref, bool targetNowGOT) override {
+ // If GOT slot was instanciated, transform:
+ // gotPage21/gotOffset12 -> page21/offset12scale8
+ // If GOT slot optimized away, transform:
+ // gotPage21/gotOffset12 -> page21/addOffset12
+ assert(ref->kindNamespace() == Reference::KindNamespace::mach_o);
+ assert(ref->kindArch() == Reference::KindArch::AArch64);
+ switch (ref->kindValue()) {
+ case gotPage21:
+ const_cast<Reference *>(ref)->setKindValue(page21);
+ break;
+ case gotOffset12:
+ const_cast<Reference *>(ref)->setKindValue(targetNowGOT ?
+ offset12scale8 : addOffset12);
+ break;
+ case delta32ToGOT:
+ const_cast<Reference *>(ref)->setKindValue(delta32);
+ break;
+ case imageOffsetGot:
+ const_cast<Reference *>(ref)->setKindValue(imageOffset);
+ break;
+ default:
+ llvm_unreachable("Not a GOT reference");
+ }
+ }
+
+ const StubInfo &stubInfo() override { return _sStubInfo; }
+
+ bool isCallSite(const Reference &) override;
+ bool isNonCallBranch(const Reference &) override {
+ return false;
+ }
+
+ bool isPointer(const Reference &) override;
+ bool isPairedReloc(const normalized::Relocation &) override;
+
+ bool needsCompactUnwind() override {
+ return true;
+ }
+ Reference::KindValue imageOffsetKind() override {
+ return imageOffset;
+ }
+ Reference::KindValue imageOffsetKindIndirect() override {
+ return imageOffsetGot;
+ }
+
+ Reference::KindValue unwindRefToPersonalityFunctionKind() override {
+ return unwindCIEToPersonalityFunction;
+ }
+
+ Reference::KindValue unwindRefToCIEKind() override {
+ return negDelta32;
+ }
+
+ Reference::KindValue unwindRefToFunctionKind() override {
+ return unwindFDEToFunction;
+ }
+
+ Reference::KindValue unwindRefToEhFrameKind() override {
+ return unwindInfoToEhFrame;
+ }
+
+ Reference::KindValue pointerKind() override {
+ return pointer64;
+ }
+
+ Reference::KindValue lazyImmediateLocationKind() override {
+ return lazyImmediateLocation;
+ }
+
+ uint32_t dwarfCompactUnwindType() override {
+ return 0x03000000;
+ }
+
+ llvm::Error getReferenceInfo(const normalized::Relocation &reloc,
+ const DefinedAtom *inAtom,
+ uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool isBig,
+ FindAtomBySectionAndAddress atomFromAddress,
+ FindAtomBySymbolIndex atomFromSymbolIndex,
+ Reference::KindValue *kind,
+ const lld::Atom **target,
+ Reference::Addend *addend) override;
+ llvm::Error
+ getPairReferenceInfo(const normalized::Relocation &reloc1,
+ const normalized::Relocation &reloc2,
+ const DefinedAtom *inAtom,
+ uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool isBig, bool scatterable,
+ FindAtomBySectionAndAddress atomFromAddress,
+ FindAtomBySymbolIndex atomFromSymbolIndex,
+ Reference::KindValue *kind,
+ const lld::Atom **target,
+ Reference::Addend *addend) override;
+
+ bool needsLocalSymbolInRelocatableFile(const DefinedAtom *atom) override {
+ return (atom->contentType() == DefinedAtom::typeCString);
+ }
+
+ void generateAtomContent(const DefinedAtom &atom, bool relocatable,
+ FindAddressForAtom findAddress,
+ FindAddressForAtom findSectionAddress,
+ uint64_t imageBaseAddress,
+ llvm::MutableArrayRef<uint8_t> atomContentBuffer) override;
+
+ void appendSectionRelocations(const DefinedAtom &atom,
+ uint64_t atomSectionOffset,
+ const Reference &ref,
+ FindSymbolIndexForAtom symbolIndexForAtom,
+ FindSectionIndexForAtom sectionIndexForAtom,
+ FindAddressForAtom addressForAtom,
+ normalized::Relocations &relocs) override;
+
+private:
+ static const Registry::KindStrings _sKindStrings[];
+ static const StubInfo _sStubInfo;
+
+ enum Arm64Kind : Reference::KindValue {
+ invalid, /// for error condition
+
+ // Kinds found in mach-o .o files:
+ branch26, /// ex: bl _foo
+ page21, /// ex: adrp x1, _foo@PAGE
+ offset12, /// ex: ldrb w0, [x1, _foo@PAGEOFF]
+ offset12scale2, /// ex: ldrs w0, [x1, _foo@PAGEOFF]
+ offset12scale4, /// ex: ldr w0, [x1, _foo@PAGEOFF]
+ offset12scale8, /// ex: ldr x0, [x1, _foo@PAGEOFF]
+ offset12scale16, /// ex: ldr q0, [x1, _foo@PAGEOFF]
+ gotPage21, /// ex: adrp x1, _foo@GOTPAGE
+ gotOffset12, /// ex: ldr w0, [x1, _foo@GOTPAGEOFF]
+ tlvPage21, /// ex: adrp x1, _foo@TLVPAGE
+ tlvOffset12, /// ex: ldr w0, [x1, _foo@TLVPAGEOFF]
+
+ pointer64, /// ex: .quad _foo
+ delta64, /// ex: .quad _foo - .
+ delta32, /// ex: .long _foo - .
+ negDelta32, /// ex: .long . - _foo
+ pointer64ToGOT, /// ex: .quad _foo@GOT
+ delta32ToGOT, /// ex: .long _foo@GOT - .
+
+ // Kinds introduced by Passes:
+ addOffset12, /// Location contains LDR to change into ADD.
+ lazyPointer, /// Location contains a lazy pointer.
+ lazyImmediateLocation, /// Location contains immediate value used in stub.
+ imageOffset, /// Location contains offset of atom in final image
+ imageOffsetGot, /// Location contains offset of GOT entry for atom in
+ /// final image (typically personality function).
+ unwindCIEToPersonalityFunction, /// Nearly delta32ToGOT, but cannot be
+ /// rematerialized in relocatable object
+ /// (yay for implicit contracts!).
+ unwindFDEToFunction, /// Nearly delta64, but cannot be rematerialized in
+ /// relocatable object (yay for implicit contracts!).
+ unwindInfoToEhFrame, /// Fix low 24 bits of compact unwind encoding to
+ /// refer to __eh_frame entry.
+ };
+
+ void applyFixupFinal(const Reference &ref, uint8_t *location,
+ uint64_t fixupAddress, uint64_t targetAddress,
+ uint64_t inAtomAddress, uint64_t imageBaseAddress,
+ FindAddressForAtom findSectionAddress);
+
+ void applyFixupRelocatable(const Reference &ref, uint8_t *location,
+ uint64_t fixupAddress, uint64_t targetAddress,
+ uint64_t inAtomAddress, bool targetUnnamed);
+
+ // Utility functions for inspecting/updating instructions.
+ static uint32_t setDisplacementInBranch26(uint32_t instr, int32_t disp);
+ static uint32_t setDisplacementInADRP(uint32_t instr, int64_t disp);
+ static Arm64Kind offset12KindFromInstruction(uint32_t instr);
+ static uint32_t setImm12(uint32_t instr, uint32_t offset);
+};
+
+const Registry::KindStrings ArchHandler_arm64::_sKindStrings[] = {
+ LLD_KIND_STRING_ENTRY(invalid),
+ LLD_KIND_STRING_ENTRY(branch26),
+ LLD_KIND_STRING_ENTRY(page21),
+ LLD_KIND_STRING_ENTRY(offset12),
+ LLD_KIND_STRING_ENTRY(offset12scale2),
+ LLD_KIND_STRING_ENTRY(offset12scale4),
+ LLD_KIND_STRING_ENTRY(offset12scale8),
+ LLD_KIND_STRING_ENTRY(offset12scale16),
+ LLD_KIND_STRING_ENTRY(gotPage21),
+ LLD_KIND_STRING_ENTRY(gotOffset12),
+ LLD_KIND_STRING_ENTRY(tlvPage21),
+ LLD_KIND_STRING_ENTRY(tlvOffset12),
+ LLD_KIND_STRING_ENTRY(pointer64),
+ LLD_KIND_STRING_ENTRY(delta64),
+ LLD_KIND_STRING_ENTRY(delta32),
+ LLD_KIND_STRING_ENTRY(negDelta32),
+ LLD_KIND_STRING_ENTRY(pointer64ToGOT),
+ LLD_KIND_STRING_ENTRY(delta32ToGOT),
+
+ LLD_KIND_STRING_ENTRY(addOffset12),
+ LLD_KIND_STRING_ENTRY(lazyPointer),
+ LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
+ LLD_KIND_STRING_ENTRY(imageOffset),
+ LLD_KIND_STRING_ENTRY(imageOffsetGot),
+ LLD_KIND_STRING_ENTRY(unwindCIEToPersonalityFunction),
+ LLD_KIND_STRING_ENTRY(unwindFDEToFunction),
+ LLD_KIND_STRING_ENTRY(unwindInfoToEhFrame),
+
+ LLD_KIND_STRING_END
+};
+
+const ArchHandler::StubInfo ArchHandler_arm64::_sStubInfo = {
+ "dyld_stub_binder",
+
+ // Lazy pointer references
+ { Reference::KindArch::AArch64, pointer64, 0, 0 },
+ { Reference::KindArch::AArch64, lazyPointer, 0, 0 },
+
+ // GOT pointer to dyld_stub_binder
+ { Reference::KindArch::AArch64, pointer64, 0, 0 },
+
+ // arm64 code alignment 2^1
+ 1,
+
+ // Stub size and code
+ 12,
+ { 0x10, 0x00, 0x00, 0x90, // ADRP X16, lazy_pointer@page
+ 0x10, 0x02, 0x40, 0xF9, // LDR X16, [X16, lazy_pointer@pageoff]
+ 0x00, 0x02, 0x1F, 0xD6 }, // BR X16
+ { Reference::KindArch::AArch64, page21, 0, 0 },
+ { true, offset12scale8, 4, 0 },
+
+ // Stub Helper size and code
+ 12,
+ { 0x50, 0x00, 0x00, 0x18, // LDR W16, L0
+ 0x00, 0x00, 0x00, 0x14, // LDR B helperhelper
+ 0x00, 0x00, 0x00, 0x00 }, // L0: .long 0
+ { Reference::KindArch::AArch64, lazyImmediateLocation, 8, 0 },
+ { Reference::KindArch::AArch64, branch26, 4, 0 },
+
+ // Stub helper image cache content type
+ DefinedAtom::typeGOT,
+
+ // Stub Helper-Common size and code
+ 24,
+ // Stub helper alignment
+ 2,
+ { 0x11, 0x00, 0x00, 0x90, // ADRP X17, dyld_ImageLoaderCache@page
+ 0x31, 0x02, 0x00, 0x91, // ADD X17, X17, dyld_ImageLoaderCache@pageoff
+ 0xF0, 0x47, 0xBF, 0xA9, // STP X16/X17, [SP, #-16]!
+ 0x10, 0x00, 0x00, 0x90, // ADRP X16, _fast_lazy_bind@page
+ 0x10, 0x02, 0x40, 0xF9, // LDR X16, [X16,_fast_lazy_bind@pageoff]
+ 0x00, 0x02, 0x1F, 0xD6 }, // BR X16
+ { Reference::KindArch::AArch64, page21, 0, 0 },
+ { true, offset12, 4, 0 },
+ { Reference::KindArch::AArch64, page21, 12, 0 },
+ { true, offset12scale8, 16, 0 }
+};
+
+bool ArchHandler_arm64::isCallSite(const Reference &ref) {
+ if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+ return false;
+ assert(ref.kindArch() == Reference::KindArch::AArch64);
+ return (ref.kindValue() == branch26);
+}
+
+bool ArchHandler_arm64::isPointer(const Reference &ref) {
+ if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+ return false;
+ assert(ref.kindArch() == Reference::KindArch::AArch64);
+ Reference::KindValue kind = ref.kindValue();
+ return (kind == pointer64);
+}
+
+bool ArchHandler_arm64::isPairedReloc(const Relocation &r) {
+ return ((r.type == ARM64_RELOC_ADDEND) || (r.type == ARM64_RELOC_SUBTRACTOR));
+}
+
+uint32_t ArchHandler_arm64::setDisplacementInBranch26(uint32_t instr,
+ int32_t displacement) {
+ assert((displacement <= 134217727) && (displacement > (-134217728)) &&
+ "arm64 branch out of range");
+ return (instr & 0xFC000000) | ((uint32_t)(displacement >> 2) & 0x03FFFFFF);
+}
+
+uint32_t ArchHandler_arm64::setDisplacementInADRP(uint32_t instruction,
+ int64_t displacement) {
+ assert((displacement <= 0x100000000LL) && (displacement > (-0x100000000LL)) &&
+ "arm64 ADRP out of range");
+ assert(((instruction & 0x9F000000) == 0x90000000) &&
+ "reloc not on ADRP instruction");
+ uint32_t immhi = (displacement >> 9) & (0x00FFFFE0);
+ uint32_t immlo = (displacement << 17) & (0x60000000);
+ return (instruction & 0x9F00001F) | immlo | immhi;
+}
+
+ArchHandler_arm64::Arm64Kind
+ArchHandler_arm64::offset12KindFromInstruction(uint32_t instruction) {
+ if (instruction & 0x08000000) {
+ switch ((instruction >> 30) & 0x3) {
+ case 0:
+ if ((instruction & 0x04800000) == 0x04800000)
+ return offset12scale16;
+ return offset12;
+ case 1:
+ return offset12scale2;
+ case 2:
+ return offset12scale4;
+ case 3:
+ return offset12scale8;
+ }
+ }
+ return offset12;
+}
+
+uint32_t ArchHandler_arm64::setImm12(uint32_t instruction, uint32_t offset) {
+ assert(((offset & 0xFFFFF000) == 0) && "imm12 offset out of range");
+ uint32_t imm12 = offset << 10;
+ return (instruction & 0xFFC003FF) | imm12;
+}
+
+llvm::Error ArchHandler_arm64::getReferenceInfo(
+ const Relocation &reloc, const DefinedAtom *inAtom, uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool isBig,
+ FindAtomBySectionAndAddress atomFromAddress,
+ FindAtomBySymbolIndex atomFromSymbolIndex, Reference::KindValue *kind,
+ const lld::Atom **target, Reference::Addend *addend) {
+ const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+ switch (relocPattern(reloc)) {
+ case ARM64_RELOC_BRANCH26 | rPcRel | rExtern | rLength4:
+ // ex: bl _foo
+ *kind = branch26;
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = 0;
+ return llvm::Error::success();
+ case ARM64_RELOC_PAGE21 | rPcRel | rExtern | rLength4:
+ // ex: adrp x1, _foo@PAGE
+ *kind = page21;
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = 0;
+ return llvm::Error::success();
+ case ARM64_RELOC_PAGEOFF12 | rExtern | rLength4:
+ // ex: ldr x0, [x1, _foo@PAGEOFF]
+ *kind = offset12KindFromInstruction(*(const little32_t *)fixupContent);
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = 0;
+ return llvm::Error::success();
+ case ARM64_RELOC_GOT_LOAD_PAGE21 | rPcRel | rExtern | rLength4:
+ // ex: adrp x1, _foo@GOTPAGE
+ *kind = gotPage21;
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = 0;
+ return llvm::Error::success();
+ case ARM64_RELOC_GOT_LOAD_PAGEOFF12 | rExtern | rLength4:
+ // ex: ldr x0, [x1, _foo@GOTPAGEOFF]
+ *kind = gotOffset12;
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = 0;
+ return llvm::Error::success();
+ case ARM64_RELOC_TLVP_LOAD_PAGE21 | rPcRel | rExtern | rLength4:
+ // ex: adrp x1, _foo@TLVPAGE
+ *kind = tlvPage21;
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = 0;
+ return llvm::Error::success();
+ case ARM64_RELOC_TLVP_LOAD_PAGEOFF12 | rExtern | rLength4:
+ // ex: ldr x0, [x1, _foo@TLVPAGEOFF]
+ *kind = tlvOffset12;
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = 0;
+ return llvm::Error::success();
+ case ARM64_RELOC_UNSIGNED | rExtern | rLength8:
+ // ex: .quad _foo + N
+ *kind = pointer64;
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = *(const little64_t *)fixupContent;
+ return llvm::Error::success();
+ case ARM64_RELOC_UNSIGNED | rLength8:
+ // ex: .quad Lfoo + N
+ *kind = pointer64;
+ return atomFromAddress(reloc.symbol, *(const little64_t *)fixupContent,
+ target, addend);
+ case ARM64_RELOC_POINTER_TO_GOT | rExtern | rLength8:
+ // ex: .quad _foo@GOT
+ *kind = pointer64ToGOT;
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = 0;
+ return llvm::Error::success();
+ case ARM64_RELOC_POINTER_TO_GOT | rPcRel | rExtern | rLength4:
+ // ex: .long _foo@GOT - .
+
+ // If we are in an .eh_frame section, then the kind of the relocation should
+ // not be delta32ToGOT. It may instead be unwindCIEToPersonalityFunction.
+ if (inAtom->contentType() == DefinedAtom::typeCFI)
+ *kind = unwindCIEToPersonalityFunction;
+ else
+ *kind = delta32ToGOT;
+
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = 0;
+ return llvm::Error::success();
+ default:
+ return llvm::make_error<GenericError>("unsupported arm64 relocation type");
+ }
+}
+
+llvm::Error ArchHandler_arm64::getPairReferenceInfo(
+ const normalized::Relocation &reloc1, const normalized::Relocation &reloc2,
+ const DefinedAtom *inAtom, uint32_t offsetInAtom, uint64_t fixupAddress,
+ bool swap, bool scatterable, FindAtomBySectionAndAddress atomFromAddress,
+ FindAtomBySymbolIndex atomFromSymbolIndex, Reference::KindValue *kind,
+ const lld::Atom **target, Reference::Addend *addend) {
+ const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+ switch (relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
+ case ((ARM64_RELOC_ADDEND | rLength4) << 16 |
+ ARM64_RELOC_BRANCH26 | rPcRel | rExtern | rLength4):
+ // ex: bl _foo+8
+ *kind = branch26;
+ if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
+ return ec;
+ *addend = reloc1.symbol;
+ return llvm::Error::success();
+ case ((ARM64_RELOC_ADDEND | rLength4) << 16 |
+ ARM64_RELOC_PAGE21 | rPcRel | rExtern | rLength4):
+ // ex: adrp x1, _foo@PAGE
+ *kind = page21;
+ if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
+ return ec;
+ *addend = reloc1.symbol;
+ return llvm::Error::success();
+ case ((ARM64_RELOC_ADDEND | rLength4) << 16 |
+ ARM64_RELOC_PAGEOFF12 | rExtern | rLength4): {
+ // ex: ldr w0, [x1, _foo@PAGEOFF]
+ uint32_t cont32 = (int32_t)*(const little32_t *)fixupContent;
+ *kind = offset12KindFromInstruction(cont32);
+ if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
+ return ec;
+ *addend = reloc1.symbol;
+ return llvm::Error::success();
+ }
+ case ((ARM64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 |
+ ARM64_RELOC_UNSIGNED | rExtern | rLength8):
+ // ex: .quad _foo - .
+ if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
+ return ec;
+
+ // If we are in an .eh_frame section, then the kind of the relocation should
+ // not be delta64. It may instead be unwindFDEToFunction.
+ if (inAtom->contentType() == DefinedAtom::typeCFI)
+ *kind = unwindFDEToFunction;
+ else
+ *kind = delta64;
+
+ // The offsets of the 2 relocations must match
+ if (reloc1.offset != reloc2.offset)
+ return llvm::make_error<GenericError>(
+ "paired relocs must have the same offset");
+ *addend = (int64_t)*(const little64_t *)fixupContent + offsetInAtom;
+ return llvm::Error::success();
+ case ((ARM64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 |
+ ARM64_RELOC_UNSIGNED | rExtern | rLength4):
+ // ex: .quad _foo - .
+ *kind = delta32;
+ if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
+ return ec;
+ *addend = (int32_t)*(const little32_t *)fixupContent + offsetInAtom;
+ return llvm::Error::success();
+ default:
+ return llvm::make_error<GenericError>("unsupported arm64 relocation pair");
+ }
+}
+
+void ArchHandler_arm64::generateAtomContent(
+ const DefinedAtom &atom, bool relocatable, FindAddressForAtom findAddress,
+ FindAddressForAtom findSectionAddress, uint64_t imageBaseAddress,
+ llvm::MutableArrayRef<uint8_t> atomContentBuffer) {
+ // Copy raw bytes.
+ std::copy(atom.rawContent().begin(), atom.rawContent().end(),
+ atomContentBuffer.begin());
+ // Apply fix-ups.
+#ifndef NDEBUG
+ if (atom.begin() != atom.end()) {
+ DEBUG_WITH_TYPE("atom-content", llvm::dbgs()
+ << "Applying fixups to atom:\n"
+ << " address="
+ << llvm::format(" 0x%09lX", &atom)
+ << ", file=#"
+ << atom.file().ordinal()
+ << ", atom=#"
+ << atom.ordinal()
+ << ", name="
+ << atom.name()
+ << ", type="
+ << atom.contentType()
+ << "\n");
+ }
+#endif
+ for (const Reference *ref : atom) {
+ uint32_t offset = ref->offsetInAtom();
+ const Atom *target = ref->target();
+ bool targetUnnamed = target->name().empty();
+ uint64_t targetAddress = 0;
+ if (isa<DefinedAtom>(target))
+ targetAddress = findAddress(*target);
+ uint64_t atomAddress = findAddress(atom);
+ uint64_t fixupAddress = atomAddress + offset;
+ if (relocatable) {
+ applyFixupRelocatable(*ref, &atomContentBuffer[offset], fixupAddress,
+ targetAddress, atomAddress, targetUnnamed);
+ } else {
+ applyFixupFinal(*ref, &atomContentBuffer[offset], fixupAddress,
+ targetAddress, atomAddress, imageBaseAddress,
+ findSectionAddress);
+ }
+ }
+}
+
+void ArchHandler_arm64::applyFixupFinal(const Reference &ref, uint8_t *loc,
+ uint64_t fixupAddress,
+ uint64_t targetAddress,
+ uint64_t inAtomAddress,
+ uint64_t imageBaseAddress,
+ FindAddressForAtom findSectionAddress) {
+ if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+ return;
+ assert(ref.kindArch() == Reference::KindArch::AArch64);
+ ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
+ ulittle64_t *loc64 = reinterpret_cast<ulittle64_t *>(loc);
+ int32_t displacement;
+ uint32_t instruction;
+ uint32_t value32;
+ uint32_t value64;
+ switch (static_cast<Arm64Kind>(ref.kindValue())) {
+ case branch26:
+ displacement = (targetAddress - fixupAddress) + ref.addend();
+ *loc32 = setDisplacementInBranch26(*loc32, displacement);
+ return;
+ case page21:
+ case gotPage21:
+ case tlvPage21:
+ displacement =
+ ((targetAddress + ref.addend()) & (-4096)) - (fixupAddress & (-4096));
+ *loc32 = setDisplacementInADRP(*loc32, displacement);
+ return;
+ case offset12:
+ case gotOffset12:
+ case tlvOffset12:
+ displacement = (targetAddress + ref.addend()) & 0x00000FFF;
+ *loc32 = setImm12(*loc32, displacement);
+ return;
+ case offset12scale2:
+ displacement = (targetAddress + ref.addend()) & 0x00000FFF;
+ assert(((displacement & 0x1) == 0) &&
+ "scaled imm12 not accessing 2-byte aligneds");
+ *loc32 = setImm12(*loc32, displacement >> 1);
+ return;
+ case offset12scale4:
+ displacement = (targetAddress + ref.addend()) & 0x00000FFF;
+ assert(((displacement & 0x3) == 0) &&
+ "scaled imm12 not accessing 4-byte aligned");
+ *loc32 = setImm12(*loc32, displacement >> 2);
+ return;
+ case offset12scale8:
+ displacement = (targetAddress + ref.addend()) & 0x00000FFF;
+ assert(((displacement & 0x7) == 0) &&
+ "scaled imm12 not accessing 8-byte aligned");
+ *loc32 = setImm12(*loc32, displacement >> 3);
+ return;
+ case offset12scale16:
+ displacement = (targetAddress + ref.addend()) & 0x00000FFF;
+ assert(((displacement & 0xF) == 0) &&
+ "scaled imm12 not accessing 16-byte aligned");
+ *loc32 = setImm12(*loc32, displacement >> 4);
+ return;
+ case addOffset12:
+ instruction = *loc32;
+ assert(((instruction & 0xFFC00000) == 0xF9400000) &&
+ "GOT reloc is not an LDR instruction");
+ displacement = (targetAddress + ref.addend()) & 0x00000FFF;
+ value32 = 0x91000000 | (instruction & 0x000003FF);
+ instruction = setImm12(value32, displacement);
+ *loc32 = instruction;
+ return;
+ case pointer64:
+ case pointer64ToGOT:
+ *loc64 = targetAddress + ref.addend();
+ return;
+ case delta64:
+ case unwindFDEToFunction:
+ *loc64 = (targetAddress - fixupAddress) + ref.addend();
+ return;
+ case delta32:
+ case delta32ToGOT:
+ case unwindCIEToPersonalityFunction:
+ *loc32 = (targetAddress - fixupAddress) + ref.addend();
+ return;
+ case negDelta32:
+ *loc32 = fixupAddress - targetAddress + ref.addend();
+ return;
+ case lazyPointer:
+ // Do nothing
+ return;
+ case lazyImmediateLocation:
+ *loc32 = ref.addend();
+ return;
+ case imageOffset:
+ *loc32 = (targetAddress - imageBaseAddress) + ref.addend();
+ return;
+ case imageOffsetGot:
+ llvm_unreachable("imageOffsetGot should have been changed to imageOffset");
+ break;
+ case unwindInfoToEhFrame:
+ value64 = targetAddress - findSectionAddress(*ref.target()) + ref.addend();
+ assert(value64 < 0xffffffU && "offset in __eh_frame too large");
+ *loc32 = (*loc32 & 0xff000000U) | value64;
+ return;
+ case invalid:
+ // Fall into llvm_unreachable().
+ break;
+ }
+ llvm_unreachable("invalid arm64 Reference Kind");
+}
+
+void ArchHandler_arm64::applyFixupRelocatable(const Reference &ref,
+ uint8_t *loc,
+ uint64_t fixupAddress,
+ uint64_t targetAddress,
+ uint64_t inAtomAddress,
+ bool targetUnnamed) {
+ if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+ return;
+ assert(ref.kindArch() == Reference::KindArch::AArch64);
+ ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
+ ulittle64_t *loc64 = reinterpret_cast<ulittle64_t *>(loc);
+ switch (static_cast<Arm64Kind>(ref.kindValue())) {
+ case branch26:
+ *loc32 = setDisplacementInBranch26(*loc32, 0);
+ return;
+ case page21:
+ case gotPage21:
+ case tlvPage21:
+ *loc32 = setDisplacementInADRP(*loc32, 0);
+ return;
+ case offset12:
+ case offset12scale2:
+ case offset12scale4:
+ case offset12scale8:
+ case offset12scale16:
+ case gotOffset12:
+ case tlvOffset12:
+ *loc32 = setImm12(*loc32, 0);
+ return;
+ case pointer64:
+ if (targetUnnamed)
+ *loc64 = targetAddress + ref.addend();
+ else
+ *loc64 = ref.addend();
+ return;
+ case delta64:
+ *loc64 = ref.addend() + inAtomAddress - fixupAddress;
+ return;
+ case unwindFDEToFunction:
+ // We don't emit unwindFDEToFunction in -r mode as they are implicitly
+ // generated from the data in the __eh_frame section. So here we need
+ // to use the targetAddress so that we can generate the full relocation
+ // when we parse again later.
+ *loc64 = targetAddress - fixupAddress;
+ return;
+ case delta32:
+ *loc32 = ref.addend() + inAtomAddress - fixupAddress;
+ return;
+ case negDelta32:
+ // We don't emit negDelta32 in -r mode as they are implicitly
+ // generated from the data in the __eh_frame section. So here we need
+ // to use the targetAddress so that we can generate the full relocation
+ // when we parse again later.
+ *loc32 = fixupAddress - targetAddress + ref.addend();
+ return;
+ case pointer64ToGOT:
+ *loc64 = 0;
+ return;
+ case delta32ToGOT:
+ *loc32 = inAtomAddress - fixupAddress;
+ return;
+ case unwindCIEToPersonalityFunction:
+ // We don't emit unwindCIEToPersonalityFunction in -r mode as they are
+ // implicitly generated from the data in the __eh_frame section. So here we
+ // need to use the targetAddress so that we can generate the full relocation
+ // when we parse again later.
+ *loc32 = targetAddress - fixupAddress;
+ return;
+ case addOffset12:
+ llvm_unreachable("lazy reference kind implies GOT pass was run");
+ case lazyPointer:
+ case lazyImmediateLocation:
+ llvm_unreachable("lazy reference kind implies Stubs pass was run");
+ case imageOffset:
+ case imageOffsetGot:
+ case unwindInfoToEhFrame:
+ llvm_unreachable("fixup implies __unwind_info");
+ return;
+ case invalid:
+ // Fall into llvm_unreachable().
+ break;
+ }
+ llvm_unreachable("unknown arm64 Reference Kind");
+}
+
+void ArchHandler_arm64::appendSectionRelocations(
+ const DefinedAtom &atom, uint64_t atomSectionOffset, const Reference &ref,
+ FindSymbolIndexForAtom symbolIndexForAtom,
+ FindSectionIndexForAtom sectionIndexForAtom,
+ FindAddressForAtom addressForAtom, normalized::Relocations &relocs) {
+ if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+ return;
+ assert(ref.kindArch() == Reference::KindArch::AArch64);
+ uint32_t sectionOffset = atomSectionOffset + ref.offsetInAtom();
+ switch (static_cast<Arm64Kind>(ref.kindValue())) {
+ case branch26:
+ if (ref.addend()) {
+ appendReloc(relocs, sectionOffset, ref.addend(), 0,
+ ARM64_RELOC_ADDEND | rLength4);
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ ARM64_RELOC_BRANCH26 | rPcRel | rExtern | rLength4);
+ } else {
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ ARM64_RELOC_BRANCH26 | rPcRel | rExtern | rLength4);
+ }
+ return;
+ case page21:
+ if (ref.addend()) {
+ appendReloc(relocs, sectionOffset, ref.addend(), 0,
+ ARM64_RELOC_ADDEND | rLength4);
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ ARM64_RELOC_PAGE21 | rPcRel | rExtern | rLength4);
+ } else {
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ ARM64_RELOC_PAGE21 | rPcRel | rExtern | rLength4);
+ }
+ return;
+ case offset12:
+ case offset12scale2:
+ case offset12scale4:
+ case offset12scale8:
+ case offset12scale16:
+ if (ref.addend()) {
+ appendReloc(relocs, sectionOffset, ref.addend(), 0,
+ ARM64_RELOC_ADDEND | rLength4);
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ ARM64_RELOC_PAGEOFF12 | rExtern | rLength4);
+ } else {
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ ARM64_RELOC_PAGEOFF12 | rExtern | rLength4);
+ }
+ return;
+ case gotPage21:
+ assert(ref.addend() == 0);
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ ARM64_RELOC_GOT_LOAD_PAGE21 | rPcRel | rExtern | rLength4);
+ return;
+ case gotOffset12:
+ assert(ref.addend() == 0);
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ ARM64_RELOC_GOT_LOAD_PAGEOFF12 | rExtern | rLength4);
+ return;
+ case tlvPage21:
+ assert(ref.addend() == 0);
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ ARM64_RELOC_TLVP_LOAD_PAGE21 | rPcRel | rExtern | rLength4);
+ return;
+ case tlvOffset12:
+ assert(ref.addend() == 0);
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ ARM64_RELOC_TLVP_LOAD_PAGEOFF12 | rExtern | rLength4);
+ return;
+ case pointer64:
+ if (ref.target()->name().empty())
+ appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
+ ARM64_RELOC_UNSIGNED | rLength8);
+ else
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ ARM64_RELOC_UNSIGNED | rExtern | rLength8);
+ return;
+ case delta64:
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
+ ARM64_RELOC_SUBTRACTOR | rExtern | rLength8);
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ ARM64_RELOC_UNSIGNED | rExtern | rLength8);
+ return;
+ case delta32:
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
+ ARM64_RELOC_SUBTRACTOR | rExtern | rLength4 );
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ ARM64_RELOC_UNSIGNED | rExtern | rLength4 );
+ return;
+ case pointer64ToGOT:
+ assert(ref.addend() == 0);
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ ARM64_RELOC_POINTER_TO_GOT | rExtern | rLength8);
+ return;
+ case delta32ToGOT:
+ assert(ref.addend() == 0);
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ ARM64_RELOC_POINTER_TO_GOT | rPcRel | rExtern | rLength4);
+ return;
+ case addOffset12:
+ llvm_unreachable("lazy reference kind implies GOT pass was run");
+ case lazyPointer:
+ case lazyImmediateLocation:
+ llvm_unreachable("lazy reference kind implies Stubs pass was run");
+ case imageOffset:
+ case imageOffsetGot:
+ llvm_unreachable("deltas from mach_header can only be in final images");
+ case unwindCIEToPersonalityFunction:
+ case unwindFDEToFunction:
+ case unwindInfoToEhFrame:
+ case negDelta32:
+ // Do nothing.
+ return;
+ case invalid:
+ // Fall into llvm_unreachable().
+ break;
+ }
+ llvm_unreachable("unknown arm64 Reference Kind");
+}
+
+std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_arm64() {
+ return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_arm64());
+}
+
+} // namespace mach_o
+} // namespace lld
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp
new file mode 100644
index 000000000000..a2c68092724d
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp
@@ -0,0 +1,644 @@
+//===- lib/FileFormat/MachO/ArchHandler_x86.cpp ---------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ArchHandler.h"
+#include "Atoms.h"
+#include "MachONormalizedFileBinaryUtils.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
+
+namespace lld {
+namespace mach_o {
+
+using llvm::support::ulittle16_t;
+using llvm::support::ulittle32_t;
+
+using llvm::support::little16_t;
+using llvm::support::little32_t;
+
+class ArchHandler_x86 : public ArchHandler {
+public:
+ ArchHandler_x86() = default;
+ ~ArchHandler_x86() override = default;
+
+ const Registry::KindStrings *kindStrings() override { return _sKindStrings; }
+
+ Reference::KindArch kindArch() override { return Reference::KindArch::x86; }
+
+ const StubInfo &stubInfo() override { return _sStubInfo; }
+ bool isCallSite(const Reference &) override;
+ bool isNonCallBranch(const Reference &) override {
+ return false;
+ }
+
+ bool isPointer(const Reference &) override;
+ bool isPairedReloc(const normalized::Relocation &) override;
+
+ bool needsCompactUnwind() override {
+ return false;
+ }
+
+ Reference::KindValue imageOffsetKind() override {
+ return invalid;
+ }
+
+ Reference::KindValue imageOffsetKindIndirect() override {
+ return invalid;
+ }
+
+ Reference::KindValue unwindRefToPersonalityFunctionKind() override {
+ return invalid;
+ }
+
+ Reference::KindValue unwindRefToCIEKind() override {
+ return negDelta32;
+ }
+
+ Reference::KindValue unwindRefToFunctionKind() override{
+ return delta32;
+ }
+
+ Reference::KindValue lazyImmediateLocationKind() override {
+ return lazyImmediateLocation;
+ }
+
+ Reference::KindValue unwindRefToEhFrameKind() override {
+ return invalid;
+ }
+
+ Reference::KindValue pointerKind() override {
+ return invalid;
+ }
+
+ uint32_t dwarfCompactUnwindType() override {
+ return 0x04000000U;
+ }
+
+ llvm::Error getReferenceInfo(const normalized::Relocation &reloc,
+ const DefinedAtom *inAtom,
+ uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool swap,
+ FindAtomBySectionAndAddress atomFromAddress,
+ FindAtomBySymbolIndex atomFromSymbolIndex,
+ Reference::KindValue *kind,
+ const lld::Atom **target,
+ Reference::Addend *addend) override;
+ llvm::Error
+ getPairReferenceInfo(const normalized::Relocation &reloc1,
+ const normalized::Relocation &reloc2,
+ const DefinedAtom *inAtom,
+ uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool swap, bool scatterable,
+ FindAtomBySectionAndAddress atomFromAddress,
+ FindAtomBySymbolIndex atomFromSymbolIndex,
+ Reference::KindValue *kind,
+ const lld::Atom **target,
+ Reference::Addend *addend) override;
+
+ void generateAtomContent(const DefinedAtom &atom, bool relocatable,
+ FindAddressForAtom findAddress,
+ FindAddressForAtom findSectionAddress,
+ uint64_t imageBaseAddress,
+ llvm::MutableArrayRef<uint8_t> atomContentBuffer) override;
+
+ void appendSectionRelocations(const DefinedAtom &atom,
+ uint64_t atomSectionOffset,
+ const Reference &ref,
+ FindSymbolIndexForAtom symbolIndexForAtom,
+ FindSectionIndexForAtom sectionIndexForAtom,
+ FindAddressForAtom addressForAtom,
+ normalized::Relocations &relocs) override;
+
+ bool isDataInCodeTransition(Reference::KindValue refKind) override {
+ return refKind == modeCode || refKind == modeData;
+ }
+
+ Reference::KindValue dataInCodeTransitionStart(
+ const MachODefinedAtom &atom) override {
+ return modeData;
+ }
+
+ Reference::KindValue dataInCodeTransitionEnd(
+ const MachODefinedAtom &atom) override {
+ return modeCode;
+ }
+
+private:
+ static const Registry::KindStrings _sKindStrings[];
+ static const StubInfo _sStubInfo;
+
+ enum X86Kind : Reference::KindValue {
+ invalid, /// for error condition
+
+ modeCode, /// Content starting at this offset is code.
+ modeData, /// Content starting at this offset is data.
+
+ // Kinds found in mach-o .o files:
+ branch32, /// ex: call _foo
+ branch16, /// ex: callw _foo
+ abs32, /// ex: movl _foo, %eax
+ funcRel32, /// ex: movl _foo-L1(%eax), %eax
+ pointer32, /// ex: .long _foo
+ delta32, /// ex: .long _foo - .
+ negDelta32, /// ex: .long . - _foo
+
+ // Kinds introduced by Passes:
+ lazyPointer, /// Location contains a lazy pointer.
+ lazyImmediateLocation, /// Location contains immediate value used in stub.
+ };
+
+ static bool useExternalRelocationTo(const Atom &target);
+
+ void applyFixupFinal(const Reference &ref, uint8_t *location,
+ uint64_t fixupAddress, uint64_t targetAddress,
+ uint64_t inAtomAddress);
+
+ void applyFixupRelocatable(const Reference &ref, uint8_t *location,
+ uint64_t fixupAddress,
+ uint64_t targetAddress,
+ uint64_t inAtomAddress);
+};
+
+//===----------------------------------------------------------------------===//
+// ArchHandler_x86
+//===----------------------------------------------------------------------===//
+
+const Registry::KindStrings ArchHandler_x86::_sKindStrings[] = {
+ LLD_KIND_STRING_ENTRY(invalid),
+ LLD_KIND_STRING_ENTRY(modeCode),
+ LLD_KIND_STRING_ENTRY(modeData),
+ LLD_KIND_STRING_ENTRY(branch32),
+ LLD_KIND_STRING_ENTRY(branch16),
+ LLD_KIND_STRING_ENTRY(abs32),
+ LLD_KIND_STRING_ENTRY(funcRel32),
+ LLD_KIND_STRING_ENTRY(pointer32),
+ LLD_KIND_STRING_ENTRY(delta32),
+ LLD_KIND_STRING_ENTRY(negDelta32),
+ LLD_KIND_STRING_ENTRY(lazyPointer),
+ LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
+ LLD_KIND_STRING_END
+};
+
+const ArchHandler::StubInfo ArchHandler_x86::_sStubInfo = {
+ "dyld_stub_binder",
+
+ // Lazy pointer references
+ { Reference::KindArch::x86, pointer32, 0, 0 },
+ { Reference::KindArch::x86, lazyPointer, 0, 0 },
+
+ // GOT pointer to dyld_stub_binder
+ { Reference::KindArch::x86, pointer32, 0, 0 },
+
+ // x86 code alignment
+ 1,
+
+ // Stub size and code
+ 6,
+ { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 }, // jmp *lazyPointer
+ { Reference::KindArch::x86, abs32, 2, 0 },
+ { false, 0, 0, 0 },
+
+ // Stub Helper size and code
+ 10,
+ { 0x68, 0x00, 0x00, 0x00, 0x00, // pushl $lazy-info-offset
+ 0xE9, 0x00, 0x00, 0x00, 0x00 }, // jmp helperhelper
+ { Reference::KindArch::x86, lazyImmediateLocation, 1, 0 },
+ { Reference::KindArch::x86, branch32, 6, 0 },
+
+ // Stub helper image cache content type
+ DefinedAtom::typeNonLazyPointer,
+
+ // Stub Helper-Common size and code
+ 12,
+ // Stub helper alignment
+ 2,
+ { 0x68, 0x00, 0x00, 0x00, 0x00, // pushl $dyld_ImageLoaderCache
+ 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *_fast_lazy_bind
+ 0x90 }, // nop
+ { Reference::KindArch::x86, abs32, 1, 0 },
+ { false, 0, 0, 0 },
+ { Reference::KindArch::x86, abs32, 7, 0 },
+ { false, 0, 0, 0 }
+};
+
+bool ArchHandler_x86::isCallSite(const Reference &ref) {
+ return (ref.kindValue() == branch32);
+}
+
+bool ArchHandler_x86::isPointer(const Reference &ref) {
+ return (ref.kindValue() == pointer32);
+}
+
+bool ArchHandler_x86::isPairedReloc(const Relocation &reloc) {
+ if (!reloc.scattered)
+ return false;
+ return (reloc.type == GENERIC_RELOC_LOCAL_SECTDIFF) ||
+ (reloc.type == GENERIC_RELOC_SECTDIFF);
+}
+
+llvm::Error
+ArchHandler_x86::getReferenceInfo(const Relocation &reloc,
+ const DefinedAtom *inAtom,
+ uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool swap,
+ FindAtomBySectionAndAddress atomFromAddress,
+ FindAtomBySymbolIndex atomFromSymbolIndex,
+ Reference::KindValue *kind,
+ const lld::Atom **target,
+ Reference::Addend *addend) {
+ DefinedAtom::ContentPermissions perms;
+ const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+ uint64_t targetAddress;
+ switch (relocPattern(reloc)) {
+ case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength4:
+ // ex: call _foo (and _foo undefined)
+ *kind = branch32;
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = fixupAddress + 4 + (int32_t)*(const little32_t *)fixupContent;
+ break;
+ case GENERIC_RELOC_VANILLA | rPcRel | rLength4:
+ // ex: call _foo (and _foo defined)
+ *kind = branch32;
+ targetAddress =
+ fixupAddress + 4 + (int32_t) * (const little32_t *)fixupContent;
+ return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+ break;
+ case GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength4:
+ // ex: call _foo+n (and _foo defined)
+ *kind = branch32;
+ targetAddress =
+ fixupAddress + 4 + (int32_t) * (const little32_t *)fixupContent;
+ if (auto ec = atomFromAddress(0, reloc.value, target, addend))
+ return ec;
+ *addend = targetAddress - reloc.value;
+ break;
+ case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength2:
+ // ex: callw _foo (and _foo undefined)
+ *kind = branch16;
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = fixupAddress + 2 + (int16_t)*(const little16_t *)fixupContent;
+ break;
+ case GENERIC_RELOC_VANILLA | rPcRel | rLength2:
+ // ex: callw _foo (and _foo defined)
+ *kind = branch16;
+ targetAddress =
+ fixupAddress + 2 + (int16_t) * (const little16_t *)fixupContent;
+ return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+ break;
+ case GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength2:
+ // ex: callw _foo+n (and _foo defined)
+ *kind = branch16;
+ targetAddress =
+ fixupAddress + 2 + (int16_t) * (const little16_t *)fixupContent;
+ if (auto ec = atomFromAddress(0, reloc.value, target, addend))
+ return ec;
+ *addend = targetAddress - reloc.value;
+ break;
+ case GENERIC_RELOC_VANILLA | rExtern | rLength4:
+ // ex: movl _foo, %eax (and _foo undefined)
+ // ex: .long _foo (and _foo undefined)
+ perms = inAtom->permissions();
+ *kind =
+ ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
+ : pointer32;
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = *(const ulittle32_t *)fixupContent;
+ break;
+ case GENERIC_RELOC_VANILLA | rLength4:
+ // ex: movl _foo, %eax (and _foo defined)
+ // ex: .long _foo (and _foo defined)
+ perms = inAtom->permissions();
+ *kind =
+ ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
+ : pointer32;
+ targetAddress = *(const ulittle32_t *)fixupContent;
+ return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+ break;
+ case GENERIC_RELOC_VANILLA | rScattered | rLength4:
+ // ex: .long _foo+n (and _foo defined)
+ perms = inAtom->permissions();
+ *kind =
+ ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
+ : pointer32;
+ if (auto ec = atomFromAddress(0, reloc.value, target, addend))
+ return ec;
+ *addend = *(const ulittle32_t *)fixupContent - reloc.value;
+ break;
+ default:
+ return llvm::make_error<GenericError>("unsupported i386 relocation type");
+ }
+ return llvm::Error::success();
+}
+
+llvm::Error
+ArchHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1,
+ const normalized::Relocation &reloc2,
+ const DefinedAtom *inAtom,
+ uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool swap,
+ bool scatterable,
+ FindAtomBySectionAndAddress atomFromAddr,
+ FindAtomBySymbolIndex atomFromSymbolIndex,
+ Reference::KindValue *kind,
+ const lld::Atom **target,
+ Reference::Addend *addend) {
+ const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+ DefinedAtom::ContentPermissions perms = inAtom->permissions();
+ uint32_t fromAddress;
+ uint32_t toAddress;
+ uint32_t value;
+ const lld::Atom *fromTarget;
+ Reference::Addend offsetInTo;
+ Reference::Addend offsetInFrom;
+ switch (relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
+ case ((GENERIC_RELOC_SECTDIFF | rScattered | rLength4) << 16 |
+ GENERIC_RELOC_PAIR | rScattered | rLength4):
+ case ((GENERIC_RELOC_LOCAL_SECTDIFF | rScattered | rLength4) << 16 |
+ GENERIC_RELOC_PAIR | rScattered | rLength4):
+ toAddress = reloc1.value;
+ fromAddress = reloc2.value;
+ value = *(const little32_t *)fixupContent;
+ if (auto ec = atomFromAddr(0, toAddress, target, &offsetInTo))
+ return ec;
+ if (auto ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom))
+ return ec;
+ if (fromTarget != inAtom) {
+ if (*target != inAtom)
+ return llvm::make_error<GenericError>(
+ "SECTDIFF relocation where neither target is in atom");
+ *kind = negDelta32;
+ *addend = toAddress - value - fromAddress;
+ *target = fromTarget;
+ } else {
+ if ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) {
+ // SECTDIFF relocations are used in i386 codegen where the function
+ // prolog does a CALL to the next instruction which POPs the return
+ // address into EBX which becomes the pic-base register. The POP
+ // instruction is label the used for the subtrahend in expressions.
+ // The funcRel32 kind represents the 32-bit delta to some symbol from
+ // the start of the function (atom) containing the funcRel32.
+ *kind = funcRel32;
+ uint32_t ta = fromAddress + value - toAddress;
+ *addend = ta - offsetInFrom;
+ } else {
+ *kind = delta32;
+ *addend = fromAddress + value - toAddress;
+ }
+ }
+ return llvm::Error::success();
+ break;
+ default:
+ return llvm::make_error<GenericError>("unsupported i386 relocation type");
+ }
+}
+
+void ArchHandler_x86::generateAtomContent(const DefinedAtom &atom,
+ bool relocatable,
+ FindAddressForAtom findAddress,
+ FindAddressForAtom findSectionAddress,
+ uint64_t imageBaseAddress,
+ llvm::MutableArrayRef<uint8_t> atomContentBuffer) {
+ // Copy raw bytes.
+ std::copy(atom.rawContent().begin(), atom.rawContent().end(),
+ atomContentBuffer.begin());
+ // Apply fix-ups.
+ for (const Reference *ref : atom) {
+ uint32_t offset = ref->offsetInAtom();
+ const Atom *target = ref->target();
+ uint64_t targetAddress = 0;
+ if (isa<DefinedAtom>(target))
+ targetAddress = findAddress(*target);
+ uint64_t atomAddress = findAddress(atom);
+ uint64_t fixupAddress = atomAddress + offset;
+ if (relocatable) {
+ applyFixupRelocatable(*ref, &atomContentBuffer[offset],
+ fixupAddress, targetAddress,
+ atomAddress);
+ } else {
+ applyFixupFinal(*ref, &atomContentBuffer[offset],
+ fixupAddress, targetAddress,
+ atomAddress);
+ }
+ }
+}
+
+void ArchHandler_x86::applyFixupFinal(const Reference &ref, uint8_t *loc,
+ uint64_t fixupAddress,
+ uint64_t targetAddress,
+ uint64_t inAtomAddress) {
+ if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+ return;
+ assert(ref.kindArch() == Reference::KindArch::x86);
+ ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
+ switch (static_cast<X86Kind>(ref.kindValue())) {
+ case branch32:
+ *loc32 = (targetAddress - (fixupAddress + 4)) + ref.addend();
+ break;
+ case branch16:
+ *loc32 = (targetAddress - (fixupAddress + 2)) + ref.addend();
+ break;
+ case pointer32:
+ case abs32:
+ *loc32 = targetAddress + ref.addend();
+ break;
+ case funcRel32:
+ *loc32 = targetAddress - inAtomAddress + ref.addend();
+ break;
+ case delta32:
+ *loc32 = targetAddress - fixupAddress + ref.addend();
+ break;
+ case negDelta32:
+ *loc32 = fixupAddress - targetAddress + ref.addend();
+ break;
+ case modeCode:
+ case modeData:
+ case lazyPointer:
+ // do nothing
+ break;
+ case lazyImmediateLocation:
+ *loc32 = ref.addend();
+ break;
+ case invalid:
+ llvm_unreachable("invalid x86 Reference Kind");
+ break;
+ }
+}
+
+void ArchHandler_x86::applyFixupRelocatable(const Reference &ref,
+ uint8_t *loc,
+ uint64_t fixupAddress,
+ uint64_t targetAddress,
+ uint64_t inAtomAddress) {
+ if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+ return;
+ assert(ref.kindArch() == Reference::KindArch::x86);
+ bool useExternalReloc = useExternalRelocationTo(*ref.target());
+ ulittle16_t *loc16 = reinterpret_cast<ulittle16_t *>(loc);
+ ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
+ switch (static_cast<X86Kind>(ref.kindValue())) {
+ case branch32:
+ if (useExternalReloc)
+ *loc32 = ref.addend() - (fixupAddress + 4);
+ else
+ *loc32 =(targetAddress - (fixupAddress+4)) + ref.addend();
+ break;
+ case branch16:
+ if (useExternalReloc)
+ *loc16 = ref.addend() - (fixupAddress + 2);
+ else
+ *loc16 = (targetAddress - (fixupAddress+2)) + ref.addend();
+ break;
+ case pointer32:
+ case abs32:
+ *loc32 = targetAddress + ref.addend();
+ break;
+ case funcRel32:
+ *loc32 = targetAddress - inAtomAddress + ref.addend(); // FIXME
+ break;
+ case delta32:
+ *loc32 = targetAddress - fixupAddress + ref.addend();
+ break;
+ case negDelta32:
+ *loc32 = fixupAddress - targetAddress + ref.addend();
+ break;
+ case modeCode:
+ case modeData:
+ case lazyPointer:
+ case lazyImmediateLocation:
+ // do nothing
+ break;
+ case invalid:
+ llvm_unreachable("invalid x86 Reference Kind");
+ break;
+ }
+}
+
+bool ArchHandler_x86::useExternalRelocationTo(const Atom &target) {
+ // Undefined symbols are referenced via external relocations.
+ if (isa<UndefinedAtom>(&target))
+ return true;
+ if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(&target)) {
+ switch (defAtom->merge()) {
+ case DefinedAtom::mergeAsTentative:
+ // Tentative definitions are referenced via external relocations.
+ return true;
+ case DefinedAtom::mergeAsWeak:
+ case DefinedAtom::mergeAsWeakAndAddressUsed:
+ // Global weak-defs are referenced via external relocations.
+ return (defAtom->scope() == DefinedAtom::scopeGlobal);
+ default:
+ break;
+ }
+ }
+ // Everything else is reference via an internal relocation.
+ return false;
+}
+
+void ArchHandler_x86::appendSectionRelocations(
+ const DefinedAtom &atom,
+ uint64_t atomSectionOffset,
+ const Reference &ref,
+ FindSymbolIndexForAtom symbolIndexForAtom,
+ FindSectionIndexForAtom sectionIndexForAtom,
+ FindAddressForAtom addressForAtom,
+ normalized::Relocations &relocs) {
+ if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+ return;
+ assert(ref.kindArch() == Reference::KindArch::x86);
+ uint32_t sectionOffset = atomSectionOffset + ref.offsetInAtom();
+ bool useExternalReloc = useExternalRelocationTo(*ref.target());
+ switch (static_cast<X86Kind>(ref.kindValue())) {
+ case modeCode:
+ case modeData:
+ break;
+ case branch32:
+ if (useExternalReloc) {
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ GENERIC_RELOC_VANILLA | rExtern | rPcRel | rLength4);
+ } else {
+ if (ref.addend() != 0)
+ appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
+ GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength4);
+ else
+ appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
+ GENERIC_RELOC_VANILLA | rPcRel | rLength4);
+ }
+ break;
+ case branch16:
+ if (useExternalReloc) {
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ GENERIC_RELOC_VANILLA | rExtern | rPcRel | rLength2);
+ } else {
+ if (ref.addend() != 0)
+ appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
+ GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength2);
+ else
+ appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
+ GENERIC_RELOC_VANILLA | rPcRel | rLength2);
+ }
+ break;
+ case pointer32:
+ case abs32:
+ if (useExternalReloc)
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ GENERIC_RELOC_VANILLA | rExtern | rLength4);
+ else {
+ if (ref.addend() != 0)
+ appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
+ GENERIC_RELOC_VANILLA | rScattered | rLength4);
+ else
+ appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
+ GENERIC_RELOC_VANILLA | rLength4);
+ }
+ break;
+ case funcRel32:
+ appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
+ GENERIC_RELOC_SECTDIFF | rScattered | rLength4);
+ appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) - ref.addend(),
+ GENERIC_RELOC_PAIR | rScattered | rLength4);
+ break;
+ case delta32:
+ appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
+ GENERIC_RELOC_SECTDIFF | rScattered | rLength4);
+ appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) +
+ ref.offsetInAtom(),
+ GENERIC_RELOC_PAIR | rScattered | rLength4);
+ break;
+ case negDelta32:
+ appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) +
+ ref.offsetInAtom(),
+ GENERIC_RELOC_SECTDIFF | rScattered | rLength4);
+ appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
+ GENERIC_RELOC_PAIR | rScattered | rLength4);
+ break;
+ case lazyPointer:
+ case lazyImmediateLocation:
+ llvm_unreachable("lazy reference kind implies Stubs pass was run");
+ break;
+ case invalid:
+ llvm_unreachable("unknown x86 Reference Kind");
+ break;
+ }
+}
+
+std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_x86() {
+ return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_x86());
+}
+
+} // namespace mach_o
+} // namespace lld
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
new file mode 100644
index 000000000000..fba3d530e484
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
@@ -0,0 +1,866 @@
+//===- lib/FileFormat/MachO/ArchHandler_x86_64.cpp ------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ArchHandler.h"
+#include "Atoms.h"
+#include "MachONormalizedFileBinaryUtils.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
+
+namespace lld {
+namespace mach_o {
+
+using llvm::support::ulittle32_t;
+using llvm::support::ulittle64_t;
+
+using llvm::support::little32_t;
+using llvm::support::little64_t;
+
+class ArchHandler_x86_64 : public ArchHandler {
+public:
+ ArchHandler_x86_64() = default;
+ ~ArchHandler_x86_64() override = default;
+
+ const Registry::KindStrings *kindStrings() override { return _sKindStrings; }
+
+ Reference::KindArch kindArch() override {
+ return Reference::KindArch::x86_64;
+ }
+
+ /// Used by GOTPass to locate GOT References
+ bool isGOTAccess(const Reference &ref, bool &canBypassGOT) override {
+ if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+ return false;
+ assert(ref.kindArch() == Reference::KindArch::x86_64);
+ switch (ref.kindValue()) {
+ case ripRel32GotLoad:
+ canBypassGOT = true;
+ return true;
+ case ripRel32Got:
+ canBypassGOT = false;
+ return true;
+ case imageOffsetGot:
+ canBypassGOT = false;
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ bool isTLVAccess(const Reference &ref) const override {
+ assert(ref.kindNamespace() == Reference::KindNamespace::mach_o);
+ assert(ref.kindArch() == Reference::KindArch::x86_64);
+ return ref.kindValue() == ripRel32Tlv;
+ }
+
+ void updateReferenceToTLV(const Reference *ref) override {
+ assert(ref->kindNamespace() == Reference::KindNamespace::mach_o);
+ assert(ref->kindArch() == Reference::KindArch::x86_64);
+ assert(ref->kindValue() == ripRel32Tlv);
+ const_cast<Reference*>(ref)->setKindValue(ripRel32);
+ }
+
+ /// Used by GOTPass to update GOT References
+ void updateReferenceToGOT(const Reference *ref, bool targetNowGOT) override {
+ assert(ref->kindNamespace() == Reference::KindNamespace::mach_o);
+ assert(ref->kindArch() == Reference::KindArch::x86_64);
+
+ switch (ref->kindValue()) {
+ case ripRel32Got:
+ assert(targetNowGOT && "target must be GOT");
+ LLVM_FALLTHROUGH;
+ case ripRel32GotLoad:
+ const_cast<Reference *>(ref)
+ ->setKindValue(targetNowGOT ? ripRel32 : ripRel32GotLoadNowLea);
+ break;
+ case imageOffsetGot:
+ const_cast<Reference *>(ref)->setKindValue(imageOffset);
+ break;
+ default:
+ llvm_unreachable("unknown GOT reference kind");
+ }
+ }
+
+ bool needsCompactUnwind() override {
+ return true;
+ }
+
+ Reference::KindValue imageOffsetKind() override {
+ return imageOffset;
+ }
+
+ Reference::KindValue imageOffsetKindIndirect() override {
+ return imageOffsetGot;
+ }
+
+ Reference::KindValue unwindRefToPersonalityFunctionKind() override {
+ return ripRel32Got;
+ }
+
+ Reference::KindValue unwindRefToCIEKind() override {
+ return negDelta32;
+ }
+
+ Reference::KindValue unwindRefToFunctionKind() override{
+ return unwindFDEToFunction;
+ }
+
+ Reference::KindValue lazyImmediateLocationKind() override {
+ return lazyImmediateLocation;
+ }
+
+ Reference::KindValue unwindRefToEhFrameKind() override {
+ return unwindInfoToEhFrame;
+ }
+
+ Reference::KindValue pointerKind() override {
+ return pointer64;
+ }
+
+ uint32_t dwarfCompactUnwindType() override {
+ return 0x04000000U;
+ }
+
+ const StubInfo &stubInfo() override { return _sStubInfo; }
+
+ bool isNonCallBranch(const Reference &) override {
+ return false;
+ }
+
+ bool isCallSite(const Reference &) override;
+ bool isPointer(const Reference &) override;
+ bool isPairedReloc(const normalized::Relocation &) override;
+
+ llvm::Error getReferenceInfo(const normalized::Relocation &reloc,
+ const DefinedAtom *inAtom,
+ uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool swap,
+ FindAtomBySectionAndAddress atomFromAddress,
+ FindAtomBySymbolIndex atomFromSymbolIndex,
+ Reference::KindValue *kind,
+ const lld::Atom **target,
+ Reference::Addend *addend) override;
+ llvm::Error
+ getPairReferenceInfo(const normalized::Relocation &reloc1,
+ const normalized::Relocation &reloc2,
+ const DefinedAtom *inAtom,
+ uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool swap, bool scatterable,
+ FindAtomBySectionAndAddress atomFromAddress,
+ FindAtomBySymbolIndex atomFromSymbolIndex,
+ Reference::KindValue *kind,
+ const lld::Atom **target,
+ Reference::Addend *addend) override;
+
+ bool needsLocalSymbolInRelocatableFile(const DefinedAtom *atom) override {
+ return (atom->contentType() == DefinedAtom::typeCString);
+ }
+
+ void generateAtomContent(const DefinedAtom &atom, bool relocatable,
+ FindAddressForAtom findAddress,
+ FindAddressForAtom findSectionAddress,
+ uint64_t imageBase,
+ llvm::MutableArrayRef<uint8_t> atomContentBuffer) override;
+
+ void appendSectionRelocations(const DefinedAtom &atom,
+ uint64_t atomSectionOffset,
+ const Reference &ref,
+ FindSymbolIndexForAtom symbolIndexForAtom,
+ FindSectionIndexForAtom sectionIndexForAtom,
+ FindAddressForAtom addressForAtom,
+ normalized::Relocations &relocs) override;
+
+private:
+ static const Registry::KindStrings _sKindStrings[];
+ static const StubInfo _sStubInfo;
+
+ enum X86_64Kind: Reference::KindValue {
+ invalid, /// for error condition
+
+ // Kinds found in mach-o .o files:
+ branch32, /// ex: call _foo
+ ripRel32, /// ex: movq _foo(%rip), %rax
+ ripRel32Minus1, /// ex: movb $0x12, _foo(%rip)
+ ripRel32Minus2, /// ex: movw $0x1234, _foo(%rip)
+ ripRel32Minus4, /// ex: movl $0x12345678, _foo(%rip)
+ ripRel32Anon, /// ex: movq L1(%rip), %rax
+ ripRel32Minus1Anon, /// ex: movb $0x12, L1(%rip)
+ ripRel32Minus2Anon, /// ex: movw $0x1234, L1(%rip)
+ ripRel32Minus4Anon, /// ex: movw $0x12345678, L1(%rip)
+ ripRel32GotLoad, /// ex: movq _foo@GOTPCREL(%rip), %rax
+ ripRel32Got, /// ex: pushq _foo@GOTPCREL(%rip)
+ ripRel32Tlv, /// ex: movq _foo@TLVP(%rip), %rdi
+ pointer64, /// ex: .quad _foo
+ pointer64Anon, /// ex: .quad L1
+ delta64, /// ex: .quad _foo - .
+ delta32, /// ex: .long _foo - .
+ delta64Anon, /// ex: .quad L1 - .
+ delta32Anon, /// ex: .long L1 - .
+ negDelta64, /// ex: .quad . - _foo
+ negDelta32, /// ex: .long . - _foo
+
+ // Kinds introduced by Passes:
+ ripRel32GotLoadNowLea, /// Target of GOT load is in linkage unit so
+ /// "movq _foo@GOTPCREL(%rip), %rax" can be changed
+ /// to "leaq _foo(%rip), %rax
+ lazyPointer, /// Location contains a lazy pointer.
+ lazyImmediateLocation, /// Location contains immediate value used in stub.
+
+ imageOffset, /// Location contains offset of atom in final image
+ imageOffsetGot, /// Location contains offset of GOT entry for atom in
+ /// final image (typically personality function).
+ unwindFDEToFunction, /// Nearly delta64, but cannot be rematerialized in
+ /// relocatable object (yay for implicit contracts!).
+ unwindInfoToEhFrame, /// Fix low 24 bits of compact unwind encoding to
+ /// refer to __eh_frame entry.
+ tlvInitSectionOffset /// Location contains offset tlv init-value atom
+ /// within the __thread_data section.
+ };
+
+ Reference::KindValue kindFromReloc(const normalized::Relocation &reloc);
+
+ void applyFixupFinal(const Reference &ref, uint8_t *location,
+ uint64_t fixupAddress, uint64_t targetAddress,
+ uint64_t inAtomAddress, uint64_t imageBaseAddress,
+ FindAddressForAtom findSectionAddress);
+
+ void applyFixupRelocatable(const Reference &ref, uint8_t *location,
+ uint64_t fixupAddress,
+ uint64_t targetAddress,
+ uint64_t inAtomAddress);
+};
+
+const Registry::KindStrings ArchHandler_x86_64::_sKindStrings[] = {
+ LLD_KIND_STRING_ENTRY(invalid), LLD_KIND_STRING_ENTRY(branch32),
+ LLD_KIND_STRING_ENTRY(ripRel32), LLD_KIND_STRING_ENTRY(ripRel32Minus1),
+ LLD_KIND_STRING_ENTRY(ripRel32Minus2), LLD_KIND_STRING_ENTRY(ripRel32Minus4),
+ LLD_KIND_STRING_ENTRY(ripRel32Anon),
+ LLD_KIND_STRING_ENTRY(ripRel32Minus1Anon),
+ LLD_KIND_STRING_ENTRY(ripRel32Minus2Anon),
+ LLD_KIND_STRING_ENTRY(ripRel32Minus4Anon),
+ LLD_KIND_STRING_ENTRY(ripRel32GotLoad),
+ LLD_KIND_STRING_ENTRY(ripRel32GotLoadNowLea),
+ LLD_KIND_STRING_ENTRY(ripRel32Got), LLD_KIND_STRING_ENTRY(ripRel32Tlv),
+ LLD_KIND_STRING_ENTRY(lazyPointer),
+ LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
+ LLD_KIND_STRING_ENTRY(pointer64), LLD_KIND_STRING_ENTRY(pointer64Anon),
+ LLD_KIND_STRING_ENTRY(delta32), LLD_KIND_STRING_ENTRY(delta64),
+ LLD_KIND_STRING_ENTRY(delta32Anon), LLD_KIND_STRING_ENTRY(delta64Anon),
+ LLD_KIND_STRING_ENTRY(negDelta64),
+ LLD_KIND_STRING_ENTRY(negDelta32),
+ LLD_KIND_STRING_ENTRY(imageOffset), LLD_KIND_STRING_ENTRY(imageOffsetGot),
+ LLD_KIND_STRING_ENTRY(unwindFDEToFunction),
+ LLD_KIND_STRING_ENTRY(unwindInfoToEhFrame),
+ LLD_KIND_STRING_ENTRY(tlvInitSectionOffset),
+ LLD_KIND_STRING_END
+};
+
+const ArchHandler::StubInfo ArchHandler_x86_64::_sStubInfo = {
+ "dyld_stub_binder",
+
+ // Lazy pointer references
+ { Reference::KindArch::x86_64, pointer64, 0, 0 },
+ { Reference::KindArch::x86_64, lazyPointer, 0, 0 },
+
+ // GOT pointer to dyld_stub_binder
+ { Reference::KindArch::x86_64, pointer64, 0, 0 },
+
+ // x86_64 code alignment 2^1
+ 1,
+
+ // Stub size and code
+ 6,
+ { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 }, // jmp *lazyPointer
+ { Reference::KindArch::x86_64, ripRel32, 2, 0 },
+ { false, 0, 0, 0 },
+
+ // Stub Helper size and code
+ 10,
+ { 0x68, 0x00, 0x00, 0x00, 0x00, // pushq $lazy-info-offset
+ 0xE9, 0x00, 0x00, 0x00, 0x00 }, // jmp helperhelper
+ { Reference::KindArch::x86_64, lazyImmediateLocation, 1, 0 },
+ { Reference::KindArch::x86_64, branch32, 6, 0 },
+
+ // Stub helper image cache content type
+ DefinedAtom::typeNonLazyPointer,
+
+ // Stub Helper-Common size and code
+ 16,
+ // Stub helper alignment
+ 2,
+ { 0x4C, 0x8D, 0x1D, 0x00, 0x00, 0x00, 0x00, // leaq cache(%rip),%r11
+ 0x41, 0x53, // push %r11
+ 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *binder(%rip)
+ 0x90 }, // nop
+ { Reference::KindArch::x86_64, ripRel32, 3, 0 },
+ { false, 0, 0, 0 },
+ { Reference::KindArch::x86_64, ripRel32, 11, 0 },
+ { false, 0, 0, 0 }
+
+};
+
+bool ArchHandler_x86_64::isCallSite(const Reference &ref) {
+ if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+ return false;
+ assert(ref.kindArch() == Reference::KindArch::x86_64);
+ return (ref.kindValue() == branch32);
+}
+
+bool ArchHandler_x86_64::isPointer(const Reference &ref) {
+ if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+ return false;
+ assert(ref.kindArch() == Reference::KindArch::x86_64);
+ Reference::KindValue kind = ref.kindValue();
+ return (kind == pointer64 || kind == pointer64Anon);
+}
+
+bool ArchHandler_x86_64::isPairedReloc(const Relocation &reloc) {
+ return (reloc.type == X86_64_RELOC_SUBTRACTOR);
+}
+
+Reference::KindValue
+ArchHandler_x86_64::kindFromReloc(const Relocation &reloc) {
+ switch(relocPattern(reloc)) {
+ case X86_64_RELOC_BRANCH | rPcRel | rExtern | rLength4:
+ return branch32;
+ case X86_64_RELOC_SIGNED | rPcRel | rExtern | rLength4:
+ return ripRel32;
+ case X86_64_RELOC_SIGNED | rPcRel | rLength4:
+ return ripRel32Anon;
+ case X86_64_RELOC_SIGNED_1 | rPcRel | rExtern | rLength4:
+ return ripRel32Minus1;
+ case X86_64_RELOC_SIGNED_1 | rPcRel | rLength4:
+ return ripRel32Minus1Anon;
+ case X86_64_RELOC_SIGNED_2 | rPcRel | rExtern | rLength4:
+ return ripRel32Minus2;
+ case X86_64_RELOC_SIGNED_2 | rPcRel | rLength4:
+ return ripRel32Minus2Anon;
+ case X86_64_RELOC_SIGNED_4 | rPcRel | rExtern | rLength4:
+ return ripRel32Minus4;
+ case X86_64_RELOC_SIGNED_4 | rPcRel | rLength4:
+ return ripRel32Minus4Anon;
+ case X86_64_RELOC_GOT_LOAD | rPcRel | rExtern | rLength4:
+ return ripRel32GotLoad;
+ case X86_64_RELOC_GOT | rPcRel | rExtern | rLength4:
+ return ripRel32Got;
+ case X86_64_RELOC_TLV | rPcRel | rExtern | rLength4:
+ return ripRel32Tlv;
+ case X86_64_RELOC_UNSIGNED | rExtern | rLength8:
+ return pointer64;
+ case X86_64_RELOC_UNSIGNED | rLength8:
+ return pointer64Anon;
+ default:
+ return invalid;
+ }
+}
+
+llvm::Error
+ArchHandler_x86_64::getReferenceInfo(const Relocation &reloc,
+ const DefinedAtom *inAtom,
+ uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool swap,
+ FindAtomBySectionAndAddress atomFromAddress,
+ FindAtomBySymbolIndex atomFromSymbolIndex,
+ Reference::KindValue *kind,
+ const lld::Atom **target,
+ Reference::Addend *addend) {
+ *kind = kindFromReloc(reloc);
+ if (*kind == invalid)
+ return llvm::make_error<GenericError>("unknown type");
+ const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+ uint64_t targetAddress;
+ switch (*kind) {
+ case branch32:
+ case ripRel32:
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = *(const little32_t *)fixupContent;
+ return llvm::Error::success();
+ case ripRel32Minus1:
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = (int32_t)*(const little32_t *)fixupContent + 1;
+ return llvm::Error::success();
+ case ripRel32Minus2:
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = (int32_t)*(const little32_t *)fixupContent + 2;
+ return llvm::Error::success();
+ case ripRel32Minus4:
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = (int32_t)*(const little32_t *)fixupContent + 4;
+ return llvm::Error::success();
+ case ripRel32Anon:
+ targetAddress = fixupAddress + 4 + *(const little32_t *)fixupContent;
+ return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+ case ripRel32Minus1Anon:
+ targetAddress = fixupAddress + 5 + *(const little32_t *)fixupContent;
+ return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+ case ripRel32Minus2Anon:
+ targetAddress = fixupAddress + 6 + *(const little32_t *)fixupContent;
+ return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+ case ripRel32Minus4Anon:
+ targetAddress = fixupAddress + 8 + *(const little32_t *)fixupContent;
+ return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+ case ripRel32GotLoad:
+ case ripRel32Got:
+ case ripRel32Tlv:
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = *(const little32_t *)fixupContent;
+ return llvm::Error::success();
+ case tlvInitSectionOffset:
+ case pointer64:
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ // If this is the 3rd pointer of a tlv-thunk (i.e. the pointer to the TLV's
+ // initial value) we need to handle it specially.
+ if (inAtom->contentType() == DefinedAtom::typeThunkTLV &&
+ offsetInAtom == 16) {
+ *kind = tlvInitSectionOffset;
+ assert(*addend == 0 && "TLV-init has non-zero addend?");
+ } else
+ *addend = *(const little64_t *)fixupContent;
+ return llvm::Error::success();
+ case pointer64Anon:
+ targetAddress = *(const little64_t *)fixupContent;
+ return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+ default:
+ llvm_unreachable("bad reloc kind");
+ }
+}
+
+llvm::Error
+ArchHandler_x86_64::getPairReferenceInfo(const normalized::Relocation &reloc1,
+ const normalized::Relocation &reloc2,
+ const DefinedAtom *inAtom,
+ uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool swap,
+ bool scatterable,
+ FindAtomBySectionAndAddress atomFromAddress,
+ FindAtomBySymbolIndex atomFromSymbolIndex,
+ Reference::KindValue *kind,
+ const lld::Atom **target,
+ Reference::Addend *addend) {
+ const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+ uint64_t targetAddress;
+ const lld::Atom *fromTarget;
+ if (auto ec = atomFromSymbolIndex(reloc1.symbol, &fromTarget))
+ return ec;
+
+ switch(relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
+ case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 |
+ X86_64_RELOC_UNSIGNED | rExtern | rLength8): {
+ if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
+ return ec;
+ uint64_t encodedAddend = (int64_t)*(const little64_t *)fixupContent;
+ if (inAtom == fromTarget) {
+ if (inAtom->contentType() == DefinedAtom::typeCFI)
+ *kind = unwindFDEToFunction;
+ else
+ *kind = delta64;
+ *addend = encodedAddend + offsetInAtom;
+ } else if (inAtom == *target) {
+ *kind = negDelta64;
+ *addend = encodedAddend - offsetInAtom;
+ *target = fromTarget;
+ } else
+ return llvm::make_error<GenericError>("Invalid pointer diff");
+ return llvm::Error::success();
+ }
+ case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 |
+ X86_64_RELOC_UNSIGNED | rExtern | rLength4): {
+ if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
+ return ec;
+ uint32_t encodedAddend = (int32_t)*(const little32_t *)fixupContent;
+ if (inAtom == fromTarget) {
+ *kind = delta32;
+ *addend = encodedAddend + offsetInAtom;
+ } else if (inAtom == *target) {
+ *kind = negDelta32;
+ *addend = encodedAddend - offsetInAtom;
+ *target = fromTarget;
+ } else
+ return llvm::make_error<GenericError>("Invalid pointer diff");
+ return llvm::Error::success();
+ }
+ case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 |
+ X86_64_RELOC_UNSIGNED | rLength8):
+ if (fromTarget != inAtom)
+ return llvm::make_error<GenericError>("pointer diff not in base atom");
+ *kind = delta64Anon;
+ targetAddress = offsetInAtom + (int64_t)*(const little64_t *)fixupContent;
+ return atomFromAddress(reloc2.symbol, targetAddress, target, addend);
+ case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 |
+ X86_64_RELOC_UNSIGNED | rLength4):
+ if (fromTarget != inAtom)
+ return llvm::make_error<GenericError>("pointer diff not in base atom");
+ *kind = delta32Anon;
+ targetAddress = offsetInAtom + (int32_t)*(const little32_t *)fixupContent;
+ return atomFromAddress(reloc2.symbol, targetAddress, target, addend);
+ default:
+ return llvm::make_error<GenericError>("unknown pair");
+ }
+}
+
+void ArchHandler_x86_64::generateAtomContent(
+ const DefinedAtom &atom, bool relocatable, FindAddressForAtom findAddress,
+ FindAddressForAtom findSectionAddress, uint64_t imageBaseAddress,
+ llvm::MutableArrayRef<uint8_t> atomContentBuffer) {
+ // Copy raw bytes.
+ std::copy(atom.rawContent().begin(), atom.rawContent().end(),
+ atomContentBuffer.begin());
+ // Apply fix-ups.
+ for (const Reference *ref : atom) {
+ uint32_t offset = ref->offsetInAtom();
+ const Atom *target = ref->target();
+ uint64_t targetAddress = 0;
+ if (isa<DefinedAtom>(target))
+ targetAddress = findAddress(*target);
+ uint64_t atomAddress = findAddress(atom);
+ uint64_t fixupAddress = atomAddress + offset;
+ if (relocatable) {
+ applyFixupRelocatable(*ref, &atomContentBuffer[offset],
+ fixupAddress, targetAddress,
+ atomAddress);
+ } else {
+ applyFixupFinal(*ref, &atomContentBuffer[offset],
+ fixupAddress, targetAddress,
+ atomAddress, imageBaseAddress, findSectionAddress);
+ }
+ }
+}
+
+void ArchHandler_x86_64::applyFixupFinal(
+ const Reference &ref, uint8_t *loc, uint64_t fixupAddress,
+ uint64_t targetAddress, uint64_t inAtomAddress, uint64_t imageBaseAddress,
+ FindAddressForAtom findSectionAddress) {
+ if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+ return;
+ assert(ref.kindArch() == Reference::KindArch::x86_64);
+ ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
+ ulittle64_t *loc64 = reinterpret_cast<ulittle64_t *>(loc);
+ switch (static_cast<X86_64Kind>(ref.kindValue())) {
+ case branch32:
+ case ripRel32:
+ case ripRel32Anon:
+ case ripRel32Got:
+ case ripRel32GotLoad:
+ case ripRel32Tlv:
+ *loc32 = targetAddress - (fixupAddress + 4) + ref.addend();
+ return;
+ case pointer64:
+ case pointer64Anon:
+ *loc64 = targetAddress + ref.addend();
+ return;
+ case tlvInitSectionOffset:
+ *loc64 = targetAddress - findSectionAddress(*ref.target()) + ref.addend();
+ return;
+ case ripRel32Minus1:
+ case ripRel32Minus1Anon:
+ *loc32 = targetAddress - (fixupAddress + 5) + ref.addend();
+ return;
+ case ripRel32Minus2:
+ case ripRel32Minus2Anon:
+ *loc32 = targetAddress - (fixupAddress + 6) + ref.addend();
+ return;
+ case ripRel32Minus4:
+ case ripRel32Minus4Anon:
+ *loc32 = targetAddress - (fixupAddress + 8) + ref.addend();
+ return;
+ case delta32:
+ case delta32Anon:
+ *loc32 = targetAddress - fixupAddress + ref.addend();
+ return;
+ case delta64:
+ case delta64Anon:
+ case unwindFDEToFunction:
+ *loc64 = targetAddress - fixupAddress + ref.addend();
+ return;
+ case ripRel32GotLoadNowLea:
+ // Change MOVQ to LEA
+ assert(loc[-2] == 0x8B);
+ loc[-2] = 0x8D;
+ *loc32 = targetAddress - (fixupAddress + 4) + ref.addend();
+ return;
+ case negDelta64:
+ *loc64 = fixupAddress - targetAddress + ref.addend();
+ return;
+ case negDelta32:
+ *loc32 = fixupAddress - targetAddress + ref.addend();
+ return;
+ case lazyPointer:
+ // Do nothing
+ return;
+ case lazyImmediateLocation:
+ *loc32 = ref.addend();
+ return;
+ case imageOffset:
+ case imageOffsetGot:
+ *loc32 = (targetAddress - imageBaseAddress) + ref.addend();
+ return;
+ case unwindInfoToEhFrame: {
+ uint64_t val = targetAddress - findSectionAddress(*ref.target()) + ref.addend();
+ assert(val < 0xffffffU && "offset in __eh_frame too large");
+ *loc32 = (*loc32 & 0xff000000U) | val;
+ return;
+ }
+ case invalid:
+ // Fall into llvm_unreachable().
+ break;
+ }
+ llvm_unreachable("invalid x86_64 Reference Kind");
+}
+
+void ArchHandler_x86_64::applyFixupRelocatable(const Reference &ref,
+ uint8_t *loc,
+ uint64_t fixupAddress,
+ uint64_t targetAddress,
+ uint64_t inAtomAddress) {
+ if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+ return;
+ assert(ref.kindArch() == Reference::KindArch::x86_64);
+ ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
+ ulittle64_t *loc64 = reinterpret_cast<ulittle64_t *>(loc);
+ switch (static_cast<X86_64Kind>(ref.kindValue())) {
+ case branch32:
+ case ripRel32:
+ case ripRel32Got:
+ case ripRel32GotLoad:
+ case ripRel32Tlv:
+ *loc32 = ref.addend();
+ return;
+ case ripRel32Anon:
+ *loc32 = (targetAddress - (fixupAddress + 4)) + ref.addend();
+ return;
+ case tlvInitSectionOffset:
+ case pointer64:
+ *loc64 = ref.addend();
+ return;
+ case pointer64Anon:
+ *loc64 = targetAddress + ref.addend();
+ return;
+ case ripRel32Minus1:
+ *loc32 = ref.addend() - 1;
+ return;
+ case ripRel32Minus1Anon:
+ *loc32 = (targetAddress - (fixupAddress + 5)) + ref.addend();
+ return;
+ case ripRel32Minus2:
+ *loc32 = ref.addend() - 2;
+ return;
+ case ripRel32Minus2Anon:
+ *loc32 = (targetAddress - (fixupAddress + 6)) + ref.addend();
+ return;
+ case ripRel32Minus4:
+ *loc32 = ref.addend() - 4;
+ return;
+ case ripRel32Minus4Anon:
+ *loc32 = (targetAddress - (fixupAddress + 8)) + ref.addend();
+ return;
+ case delta32:
+ *loc32 = ref.addend() + inAtomAddress - fixupAddress;
+ return;
+ case delta32Anon:
+ // The value we write here should be the delta to the target
+ // after taking in to account the difference from the fixup back to the
+ // last defined label
+ // ie, if we have:
+ // _base: ...
+ // Lfixup: .quad Ltarget - .
+ // ...
+ // Ltarget:
+ //
+ // Then we want to encode the value (Ltarget + addend) - (LFixup - _base)
+ *loc32 = (targetAddress + ref.addend()) - (fixupAddress - inAtomAddress);
+ return;
+ case delta64:
+ *loc64 = ref.addend() + inAtomAddress - fixupAddress;
+ return;
+ case delta64Anon:
+ // The value we write here should be the delta to the target
+ // after taking in to account the difference from the fixup back to the
+ // last defined label
+ // ie, if we have:
+ // _base: ...
+ // Lfixup: .quad Ltarget - .
+ // ...
+ // Ltarget:
+ //
+ // Then we want to encode the value (Ltarget + addend) - (LFixup - _base)
+ *loc64 = (targetAddress + ref.addend()) - (fixupAddress - inAtomAddress);
+ return;
+ case negDelta64:
+ *loc64 = ref.addend() + fixupAddress - inAtomAddress;
+ return;
+ case negDelta32:
+ *loc32 = ref.addend() + fixupAddress - inAtomAddress;
+ return;
+ case ripRel32GotLoadNowLea:
+ llvm_unreachable("ripRel32GotLoadNowLea implies GOT pass was run");
+ return;
+ case lazyPointer:
+ case lazyImmediateLocation:
+ llvm_unreachable("lazy reference kind implies Stubs pass was run");
+ return;
+ case imageOffset:
+ case imageOffsetGot:
+ case unwindInfoToEhFrame:
+ llvm_unreachable("fixup implies __unwind_info");
+ return;
+ case unwindFDEToFunction:
+ // Do nothing for now
+ return;
+ case invalid:
+ // Fall into llvm_unreachable().
+ break;
+ }
+ llvm_unreachable("unknown x86_64 Reference Kind");
+}
+
+void ArchHandler_x86_64::appendSectionRelocations(
+ const DefinedAtom &atom,
+ uint64_t atomSectionOffset,
+ const Reference &ref,
+ FindSymbolIndexForAtom symbolIndexForAtom,
+ FindSectionIndexForAtom sectionIndexForAtom,
+ FindAddressForAtom addressForAtom,
+ normalized::Relocations &relocs) {
+ if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+ return;
+ assert(ref.kindArch() == Reference::KindArch::x86_64);
+ uint32_t sectionOffset = atomSectionOffset + ref.offsetInAtom();
+ switch (static_cast<X86_64Kind>(ref.kindValue())) {
+ case branch32:
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_BRANCH | rPcRel | rExtern | rLength4);
+ return;
+ case ripRel32:
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_SIGNED | rPcRel | rExtern | rLength4 );
+ return;
+ case ripRel32Anon:
+ appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_SIGNED | rPcRel | rLength4 );
+ return;
+ case ripRel32Got:
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_GOT | rPcRel | rExtern | rLength4 );
+ return;
+ case ripRel32GotLoad:
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_GOT_LOAD | rPcRel | rExtern | rLength4 );
+ return;
+ case ripRel32Tlv:
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_TLV | rPcRel | rExtern | rLength4 );
+ return;
+ case tlvInitSectionOffset:
+ case pointer64:
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_UNSIGNED | rExtern | rLength8);
+ return;
+ case pointer64Anon:
+ appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_UNSIGNED | rLength8);
+ return;
+ case ripRel32Minus1:
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_SIGNED_1 | rPcRel | rExtern | rLength4 );
+ return;
+ case ripRel32Minus1Anon:
+ appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_SIGNED_1 | rPcRel | rLength4 );
+ return;
+ case ripRel32Minus2:
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_SIGNED_2 | rPcRel | rExtern | rLength4 );
+ return;
+ case ripRel32Minus2Anon:
+ appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_SIGNED_2 | rPcRel | rLength4 );
+ return;
+ case ripRel32Minus4:
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_SIGNED_4 | rPcRel | rExtern | rLength4 );
+ return;
+ case ripRel32Minus4Anon:
+ appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_SIGNED_4 | rPcRel | rLength4 );
+ return;
+ case delta32:
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
+ X86_64_RELOC_SUBTRACTOR | rExtern | rLength4 );
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_UNSIGNED | rExtern | rLength4 );
+ return;
+ case delta32Anon:
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
+ X86_64_RELOC_SUBTRACTOR | rExtern | rLength4 );
+ appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_UNSIGNED | rLength4 );
+ return;
+ case delta64:
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
+ X86_64_RELOC_SUBTRACTOR | rExtern | rLength8 );
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_UNSIGNED | rExtern | rLength8 );
+ return;
+ case delta64Anon:
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
+ X86_64_RELOC_SUBTRACTOR | rExtern | rLength8 );
+ appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_UNSIGNED | rLength8 );
+ return;
+ case unwindFDEToFunction:
+ case unwindInfoToEhFrame:
+ return;
+ case negDelta32:
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_SUBTRACTOR | rExtern | rLength4 );
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
+ X86_64_RELOC_UNSIGNED | rExtern | rLength4 );
+ return;
+ case negDelta64:
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_SUBTRACTOR | rExtern | rLength8 );
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
+ X86_64_RELOC_UNSIGNED | rExtern | rLength8 );
+ return;
+ case ripRel32GotLoadNowLea:
+ llvm_unreachable("ripRel32GotLoadNowLea implies GOT pass was run");
+ return;
+ case lazyPointer:
+ case lazyImmediateLocation:
+ llvm_unreachable("lazy reference kind implies Stubs pass was run");
+ return;
+ case imageOffset:
+ case imageOffsetGot:
+ llvm_unreachable("__unwind_info references should have been resolved");
+ return;
+ case invalid:
+ // Fall into llvm_unreachable().
+ break;
+ }
+ llvm_unreachable("unknown x86_64 Reference Kind");
+}
+
+std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_x86_64() {
+ return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_x86_64());
+}
+
+} // namespace mach_o
+} // namespace lld
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/Atoms.h b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/Atoms.h
new file mode 100644
index 000000000000..573efca9f6f9
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/Atoms.h
@@ -0,0 +1,181 @@
+//===- lib/ReaderWriter/MachO/Atoms.h ---------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_MACHO_ATOMS_H
+#define LLD_READER_WRITER_MACHO_ATOMS_H
+
+#include "lld/Core/Atom.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/SharedLibraryAtom.h"
+#include "lld/Core/Simple.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include <cstdint>
+#include <string>
+
+namespace lld {
+
+class File;
+
+namespace mach_o {
+
+class MachODefinedAtom : public SimpleDefinedAtom {
+public:
+ MachODefinedAtom(const File &f, const StringRef name, Scope scope,
+ ContentType type, Merge merge, bool thumb, bool noDeadStrip,
+ const ArrayRef<uint8_t> content, Alignment align)
+ : SimpleDefinedAtom(f), _name(name), _content(content),
+ _align(align), _contentType(type), _scope(scope), _merge(merge),
+ _thumb(thumb), _noDeadStrip(noDeadStrip) {}
+
+ // Constructor for zero-fill content
+ MachODefinedAtom(const File &f, const StringRef name, Scope scope,
+ ContentType type, uint64_t size, bool noDeadStrip,
+ Alignment align)
+ : SimpleDefinedAtom(f), _name(name),
+ _content(ArrayRef<uint8_t>(nullptr, size)), _align(align),
+ _contentType(type), _scope(scope), _merge(mergeNo), _thumb(false),
+ _noDeadStrip(noDeadStrip) {}
+
+ ~MachODefinedAtom() override = default;
+
+ uint64_t size() const override { return _content.size(); }
+
+ ContentType contentType() const override { return _contentType; }
+
+ Alignment alignment() const override { return _align; }
+
+ StringRef name() const override { return _name; }
+
+ Scope scope() const override { return _scope; }
+
+ Merge merge() const override { return _merge; }
+
+ DeadStripKind deadStrip() const override {
+ if (_contentType == DefinedAtom::typeInitializerPtr)
+ return deadStripNever;
+ if (_contentType == DefinedAtom::typeTerminatorPtr)
+ return deadStripNever;
+ if (_noDeadStrip)
+ return deadStripNever;
+ return deadStripNormal;
+ }
+
+ ArrayRef<uint8_t> rawContent() const override {
+ // Note: Zerofill atoms have a content pointer which is null.
+ return _content;
+ }
+
+ bool isThumb() const { return _thumb; }
+
+private:
+ const StringRef _name;
+ const ArrayRef<uint8_t> _content;
+ const DefinedAtom::Alignment _align;
+ const ContentType _contentType;
+ const Scope _scope;
+ const Merge _merge;
+ const bool _thumb;
+ const bool _noDeadStrip;
+};
+
+class MachODefinedCustomSectionAtom : public MachODefinedAtom {
+public:
+ MachODefinedCustomSectionAtom(const File &f, const StringRef name,
+ Scope scope, ContentType type, Merge merge,
+ bool thumb, bool noDeadStrip,
+ const ArrayRef<uint8_t> content,
+ StringRef sectionName, Alignment align)
+ : MachODefinedAtom(f, name, scope, type, merge, thumb, noDeadStrip,
+ content, align),
+ _sectionName(sectionName) {}
+
+ ~MachODefinedCustomSectionAtom() override = default;
+
+ SectionChoice sectionChoice() const override {
+ return DefinedAtom::sectionCustomRequired;
+ }
+
+ StringRef customSectionName() const override {
+ return _sectionName;
+ }
+private:
+ StringRef _sectionName;
+};
+
+class MachOTentativeDefAtom : public SimpleDefinedAtom {
+public:
+ MachOTentativeDefAtom(const File &f, const StringRef name, Scope scope,
+ uint64_t size, DefinedAtom::Alignment align)
+ : SimpleDefinedAtom(f), _name(name), _scope(scope), _size(size),
+ _align(align) {}
+
+ ~MachOTentativeDefAtom() override = default;
+
+ uint64_t size() const override { return _size; }
+
+ Merge merge() const override { return DefinedAtom::mergeAsTentative; }
+
+ ContentType contentType() const override { return DefinedAtom::typeZeroFill; }
+
+ Alignment alignment() const override { return _align; }
+
+ StringRef name() const override { return _name; }
+
+ Scope scope() const override { return _scope; }
+
+ ArrayRef<uint8_t> rawContent() const override { return ArrayRef<uint8_t>(); }
+
+private:
+ const std::string _name;
+ const Scope _scope;
+ const uint64_t _size;
+ const DefinedAtom::Alignment _align;
+};
+
+class MachOSharedLibraryAtom : public SharedLibraryAtom {
+public:
+ MachOSharedLibraryAtom(const File &file, StringRef name,
+ StringRef dylibInstallName, bool weakDef)
+ : SharedLibraryAtom(), _file(file), _name(name),
+ _dylibInstallName(dylibInstallName) {}
+ ~MachOSharedLibraryAtom() override = default;
+
+ StringRef loadName() const override { return _dylibInstallName; }
+
+ bool canBeNullAtRuntime() const override {
+ // FIXME: this may actually be changeable. For now, all symbols are strongly
+ // defined though.
+ return false;
+ }
+
+ const File &file() const override { return _file; }
+
+ StringRef name() const override { return _name; }
+
+ Type type() const override {
+ // Unused in MachO (I think).
+ return Type::Unknown;
+ }
+
+ uint64_t size() const override {
+ // Unused in MachO (I think)
+ return 0;
+ }
+
+private:
+ const File &_file;
+ StringRef _name;
+ StringRef _dylibInstallName;
+};
+
+} // end namespace mach_o
+} // end namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_ATOMS_H
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/CMakeLists.txt b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/CMakeLists.txt
new file mode 100644
index 000000000000..37d1de432c0f
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/CMakeLists.txt
@@ -0,0 +1,35 @@
+add_lld_library(lldMachO
+ ArchHandler.cpp
+ ArchHandler_arm.cpp
+ ArchHandler_arm64.cpp
+ ArchHandler_x86.cpp
+ ArchHandler_x86_64.cpp
+ CompactUnwindPass.cpp
+ GOTPass.cpp
+ LayoutPass.cpp
+ MachOLinkingContext.cpp
+ MachONormalizedFileBinaryReader.cpp
+ MachONormalizedFileBinaryWriter.cpp
+ MachONormalizedFileFromAtoms.cpp
+ MachONormalizedFileToAtoms.cpp
+ MachONormalizedFileYAML.cpp
+ ObjCPass.cpp
+ ShimPass.cpp
+ StubsPass.cpp
+ TLVPass.cpp
+ WriterMachO.cpp
+
+ LINK_COMPONENTS
+ DebugInfoDWARF
+ Demangle
+ Object
+ Support
+
+ LINK_LIBS
+ lldCommon
+ lldCore
+ lldYAML
+ ${LLVM_PTHREAD_LIB}
+ )
+
+include_directories(.)
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/CompactUnwindPass.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/CompactUnwindPass.cpp
new file mode 100644
index 000000000000..fa0aaa103eeb
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/CompactUnwindPass.cpp
@@ -0,0 +1,585 @@
+//===- lib/ReaderWriter/MachO/CompactUnwindPass.cpp -------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file A pass to convert MachO's __compact_unwind sections into the final
+/// __unwind_info format used during runtime. See
+/// mach-o/compact_unwind_encoding.h for more details on the formats involved.
+///
+//===----------------------------------------------------------------------===//
+
+#include "ArchHandler.h"
+#include "File.h"
+#include "MachONormalizedFileBinaryUtils.h"
+#include "MachOPasses.h"
+#include "lld/Common/LLVM.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/Simple.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Format.h"
+
+#define DEBUG_TYPE "macho-compact-unwind"
+
+namespace lld {
+namespace mach_o {
+
+namespace {
+struct CompactUnwindEntry {
+ const Atom *rangeStart;
+ const Atom *personalityFunction;
+ const Atom *lsdaLocation;
+ const Atom *ehFrame;
+
+ uint32_t rangeLength;
+
+ // There are 3 types of compact unwind entry, distinguished by the encoding
+ // value: 0 indicates a function with no unwind info;
+ // _archHandler.dwarfCompactUnwindType() indicates that the entry defers to
+ // __eh_frame, and that the ehFrame entry will be valid; any other value is a
+ // real compact unwind entry -- personalityFunction will be set and
+ // lsdaLocation may be.
+ uint32_t encoding;
+
+ CompactUnwindEntry(const DefinedAtom *function)
+ : rangeStart(function), personalityFunction(nullptr),
+ lsdaLocation(nullptr), ehFrame(nullptr), rangeLength(function->size()),
+ encoding(0) {}
+
+ CompactUnwindEntry()
+ : rangeStart(nullptr), personalityFunction(nullptr),
+ lsdaLocation(nullptr), ehFrame(nullptr), rangeLength(0), encoding(0) {}
+};
+
+struct UnwindInfoPage {
+ ArrayRef<CompactUnwindEntry> entries;
+};
+}
+
+class UnwindInfoAtom : public SimpleDefinedAtom {
+public:
+ UnwindInfoAtom(ArchHandler &archHandler, const File &file, bool isBig,
+ std::vector<const Atom *> &personalities,
+ std::vector<uint32_t> &commonEncodings,
+ std::vector<UnwindInfoPage> &pages, uint32_t numLSDAs)
+ : SimpleDefinedAtom(file), _archHandler(archHandler),
+ _commonEncodingsOffset(7 * sizeof(uint32_t)),
+ _personalityArrayOffset(_commonEncodingsOffset +
+ commonEncodings.size() * sizeof(uint32_t)),
+ _topLevelIndexOffset(_personalityArrayOffset +
+ personalities.size() * sizeof(uint32_t)),
+ _lsdaIndexOffset(_topLevelIndexOffset +
+ 3 * (pages.size() + 1) * sizeof(uint32_t)),
+ _firstPageOffset(_lsdaIndexOffset + 2 * numLSDAs * sizeof(uint32_t)),
+ _isBig(isBig) {
+
+ addHeader(commonEncodings.size(), personalities.size(), pages.size());
+ addCommonEncodings(commonEncodings);
+ addPersonalityFunctions(personalities);
+ addTopLevelIndexes(pages);
+ addLSDAIndexes(pages, numLSDAs);
+ addSecondLevelPages(pages);
+ }
+
+ ~UnwindInfoAtom() override = default;
+
+ ContentType contentType() const override {
+ return DefinedAtom::typeProcessedUnwindInfo;
+ }
+
+ Alignment alignment() const override { return 4; }
+
+ uint64_t size() const override { return _contents.size(); }
+
+ ContentPermissions permissions() const override {
+ return DefinedAtom::permR__;
+ }
+
+ ArrayRef<uint8_t> rawContent() const override { return _contents; }
+
+ void addHeader(uint32_t numCommon, uint32_t numPersonalities,
+ uint32_t numPages) {
+ using normalized::write32;
+
+ uint32_t headerSize = 7 * sizeof(uint32_t);
+ _contents.resize(headerSize);
+
+ uint8_t *headerEntries = _contents.data();
+ // version
+ write32(headerEntries, 1, _isBig);
+ // commonEncodingsArraySectionOffset
+ write32(headerEntries + sizeof(uint32_t), _commonEncodingsOffset, _isBig);
+ // commonEncodingsArrayCount
+ write32(headerEntries + 2 * sizeof(uint32_t), numCommon, _isBig);
+ // personalityArraySectionOffset
+ write32(headerEntries + 3 * sizeof(uint32_t), _personalityArrayOffset,
+ _isBig);
+ // personalityArrayCount
+ write32(headerEntries + 4 * sizeof(uint32_t), numPersonalities, _isBig);
+ // indexSectionOffset
+ write32(headerEntries + 5 * sizeof(uint32_t), _topLevelIndexOffset, _isBig);
+ // indexCount
+ write32(headerEntries + 6 * sizeof(uint32_t), numPages + 1, _isBig);
+ }
+
+ /// Add the list of common encodings to the section; this is simply an array
+ /// of uint32_t compact values. Size has already been specified in the header.
+ void addCommonEncodings(std::vector<uint32_t> &commonEncodings) {
+ using normalized::write32;
+
+ _contents.resize(_commonEncodingsOffset +
+ commonEncodings.size() * sizeof(uint32_t));
+ uint8_t *commonEncodingsArea =
+ reinterpret_cast<uint8_t *>(_contents.data() + _commonEncodingsOffset);
+
+ for (uint32_t encoding : commonEncodings) {
+ write32(commonEncodingsArea, encoding, _isBig);
+ commonEncodingsArea += sizeof(uint32_t);
+ }
+ }
+
+ void addPersonalityFunctions(std::vector<const Atom *> personalities) {
+ _contents.resize(_personalityArrayOffset +
+ personalities.size() * sizeof(uint32_t));
+
+ for (unsigned i = 0; i < personalities.size(); ++i)
+ addImageReferenceIndirect(_personalityArrayOffset + i * sizeof(uint32_t),
+ personalities[i]);
+ }
+
+ void addTopLevelIndexes(std::vector<UnwindInfoPage> &pages) {
+ using normalized::write32;
+
+ uint32_t numIndexes = pages.size() + 1;
+ _contents.resize(_topLevelIndexOffset + numIndexes * 3 * sizeof(uint32_t));
+
+ uint32_t pageLoc = _firstPageOffset;
+
+ // The most difficult job here is calculating the LSDAs; everything else
+ // follows fairly naturally, but we can't state where the first
+ uint8_t *indexData = &_contents[_topLevelIndexOffset];
+ uint32_t numLSDAs = 0;
+ for (unsigned i = 0; i < pages.size(); ++i) {
+ // functionOffset
+ addImageReference(_topLevelIndexOffset + 3 * i * sizeof(uint32_t),
+ pages[i].entries[0].rangeStart);
+ // secondLevelPagesSectionOffset
+ write32(indexData + (3 * i + 1) * sizeof(uint32_t), pageLoc, _isBig);
+ write32(indexData + (3 * i + 2) * sizeof(uint32_t),
+ _lsdaIndexOffset + numLSDAs * 2 * sizeof(uint32_t), _isBig);
+
+ for (auto &entry : pages[i].entries)
+ if (entry.lsdaLocation)
+ ++numLSDAs;
+ }
+
+ // Finally, write out the final sentinel index
+ auto &finalEntry = pages[pages.size() - 1].entries.back();
+ addImageReference(_topLevelIndexOffset +
+ 3 * pages.size() * sizeof(uint32_t),
+ finalEntry.rangeStart, finalEntry.rangeLength);
+ // secondLevelPagesSectionOffset => 0
+ write32(indexData + (3 * pages.size() + 2) * sizeof(uint32_t),
+ _lsdaIndexOffset + numLSDAs * 2 * sizeof(uint32_t), _isBig);
+ }
+
+ void addLSDAIndexes(std::vector<UnwindInfoPage> &pages, uint32_t numLSDAs) {
+ _contents.resize(_lsdaIndexOffset + numLSDAs * 2 * sizeof(uint32_t));
+
+ uint32_t curOffset = _lsdaIndexOffset;
+ for (auto &page : pages) {
+ for (auto &entry : page.entries) {
+ if (!entry.lsdaLocation)
+ continue;
+
+ addImageReference(curOffset, entry.rangeStart);
+ addImageReference(curOffset + sizeof(uint32_t), entry.lsdaLocation);
+ curOffset += 2 * sizeof(uint32_t);
+ }
+ }
+ }
+
+ void addSecondLevelPages(std::vector<UnwindInfoPage> &pages) {
+ for (auto &page : pages) {
+ addRegularSecondLevelPage(page);
+ }
+ }
+
+ void addRegularSecondLevelPage(const UnwindInfoPage &page) {
+ uint32_t curPageOffset = _contents.size();
+ const int16_t headerSize = sizeof(uint32_t) + 2 * sizeof(uint16_t);
+ uint32_t curPageSize =
+ headerSize + 2 * page.entries.size() * sizeof(uint32_t);
+ _contents.resize(curPageOffset + curPageSize);
+
+ using normalized::write32;
+ using normalized::write16;
+ // 2 => regular page
+ write32(&_contents[curPageOffset], 2, _isBig);
+ // offset of 1st entry
+ write16(&_contents[curPageOffset + 4], headerSize, _isBig);
+ write16(&_contents[curPageOffset + 6], page.entries.size(), _isBig);
+
+ uint32_t pagePos = curPageOffset + headerSize;
+ for (auto &entry : page.entries) {
+ addImageReference(pagePos, entry.rangeStart);
+
+ write32(_contents.data() + pagePos + sizeof(uint32_t), entry.encoding,
+ _isBig);
+ if ((entry.encoding & 0x0f000000U) ==
+ _archHandler.dwarfCompactUnwindType())
+ addEhFrameReference(pagePos + sizeof(uint32_t), entry.ehFrame);
+
+ pagePos += 2 * sizeof(uint32_t);
+ }
+ }
+
+ void addEhFrameReference(uint32_t offset, const Atom *dest,
+ Reference::Addend addend = 0) {
+ addReference(Reference::KindNamespace::mach_o, _archHandler.kindArch(),
+ _archHandler.unwindRefToEhFrameKind(), offset, dest, addend);
+ }
+
+ void addImageReference(uint32_t offset, const Atom *dest,
+ Reference::Addend addend = 0) {
+ addReference(Reference::KindNamespace::mach_o, _archHandler.kindArch(),
+ _archHandler.imageOffsetKind(), offset, dest, addend);
+ }
+
+ void addImageReferenceIndirect(uint32_t offset, const Atom *dest) {
+ addReference(Reference::KindNamespace::mach_o, _archHandler.kindArch(),
+ _archHandler.imageOffsetKindIndirect(), offset, dest, 0);
+ }
+
+private:
+ mach_o::ArchHandler &_archHandler;
+ std::vector<uint8_t> _contents;
+ uint32_t _commonEncodingsOffset;
+ uint32_t _personalityArrayOffset;
+ uint32_t _topLevelIndexOffset;
+ uint32_t _lsdaIndexOffset;
+ uint32_t _firstPageOffset;
+ bool _isBig;
+};
+
+/// Pass for instantiating and optimizing GOT slots.
+///
+class CompactUnwindPass : public Pass {
+public:
+ CompactUnwindPass(const MachOLinkingContext &context)
+ : _ctx(context), _archHandler(_ctx.archHandler()),
+ _file(*_ctx.make_file<MachOFile>("<mach-o Compact Unwind Pass>")),
+ _isBig(MachOLinkingContext::isBigEndian(_ctx.arch())) {
+ _file.setOrdinal(_ctx.getNextOrdinalAndIncrement());
+ }
+
+private:
+ llvm::Error perform(SimpleFile &mergedFile) override {
+ LLVM_DEBUG(llvm::dbgs() << "MachO Compact Unwind pass\n");
+
+ std::map<const Atom *, CompactUnwindEntry> unwindLocs;
+ std::map<const Atom *, const Atom *> dwarfFrames;
+ std::vector<const Atom *> personalities;
+ uint32_t numLSDAs = 0;
+
+ // First collect all __compact_unwind and __eh_frame entries, addressable by
+ // the function referred to.
+ collectCompactUnwindEntries(mergedFile, unwindLocs, personalities,
+ numLSDAs);
+
+ collectDwarfFrameEntries(mergedFile, dwarfFrames);
+
+ // Skip rest of pass if no unwind info.
+ if (unwindLocs.empty() && dwarfFrames.empty())
+ return llvm::Error::success();
+
+ // FIXME: if there are more than 4 personality functions then we need to
+ // defer to DWARF info for the ones we don't put in the list. They should
+ // also probably be sorted by frequency.
+ assert(personalities.size() <= 4);
+
+ // TODO: Find commmon encodings for use by compressed pages.
+ std::vector<uint32_t> commonEncodings;
+
+ // Now sort the entries by final address and fixup the compact encoding to
+ // its final form (i.e. set personality function bits & create DWARF
+ // references where needed).
+ std::vector<CompactUnwindEntry> unwindInfos = createUnwindInfoEntries(
+ mergedFile, unwindLocs, personalities, dwarfFrames);
+
+ // Remove any unused eh-frame atoms.
+ pruneUnusedEHFrames(mergedFile, unwindInfos, unwindLocs, dwarfFrames);
+
+ // Finally, we can start creating pages based on these entries.
+
+ LLVM_DEBUG(llvm::dbgs() << " Splitting entries into pages\n");
+ // FIXME: we split the entries into pages naively: lots of 4k pages followed
+ // by a small one. ld64 tried to minimize space and align them to real 4k
+ // boundaries. That might be worth doing, or perhaps we could perform some
+ // minor balancing for expected number of lookups.
+ std::vector<UnwindInfoPage> pages;
+ auto remainingInfos = llvm::makeArrayRef(unwindInfos);
+ do {
+ pages.push_back(UnwindInfoPage());
+
+ // FIXME: we only create regular pages at the moment. These can hold up to
+ // 1021 entries according to the documentation.
+ unsigned entriesInPage = std::min(1021U, (unsigned)remainingInfos.size());
+
+ pages.back().entries = remainingInfos.slice(0, entriesInPage);
+ remainingInfos = remainingInfos.slice(entriesInPage);
+
+ LLVM_DEBUG(llvm::dbgs()
+ << " Page from "
+ << pages.back().entries[0].rangeStart->name() << " to "
+ << pages.back().entries.back().rangeStart->name() << " + "
+ << llvm::format("0x%x",
+ pages.back().entries.back().rangeLength)
+ << " has " << entriesInPage << " entries\n");
+ } while (!remainingInfos.empty());
+
+ auto *unwind = new (_file.allocator())
+ UnwindInfoAtom(_archHandler, _file, _isBig, personalities,
+ commonEncodings, pages, numLSDAs);
+ mergedFile.addAtom(*unwind);
+
+ // Finally, remove all __compact_unwind atoms now that we've processed them.
+ mergedFile.removeDefinedAtomsIf([](const DefinedAtom *atom) {
+ return atom->contentType() == DefinedAtom::typeCompactUnwindInfo;
+ });
+
+ return llvm::Error::success();
+ }
+
+ void collectCompactUnwindEntries(
+ const SimpleFile &mergedFile,
+ std::map<const Atom *, CompactUnwindEntry> &unwindLocs,
+ std::vector<const Atom *> &personalities, uint32_t &numLSDAs) {
+ LLVM_DEBUG(llvm::dbgs() << " Collecting __compact_unwind entries\n");
+
+ for (const DefinedAtom *atom : mergedFile.defined()) {
+ if (atom->contentType() != DefinedAtom::typeCompactUnwindInfo)
+ continue;
+
+ auto unwindEntry = extractCompactUnwindEntry(atom);
+ unwindLocs.insert(std::make_pair(unwindEntry.rangeStart, unwindEntry));
+
+ LLVM_DEBUG(llvm::dbgs() << " Entry for "
+ << unwindEntry.rangeStart->name() << ", encoding="
+ << llvm::format("0x%08x", unwindEntry.encoding));
+ if (unwindEntry.personalityFunction)
+ LLVM_DEBUG(llvm::dbgs()
+ << ", personality="
+ << unwindEntry.personalityFunction->name()
+ << ", lsdaLoc=" << unwindEntry.lsdaLocation->name());
+ LLVM_DEBUG(llvm::dbgs() << '\n');
+
+ // Count number of LSDAs we see, since we need to know how big the index
+ // will be while laying out the section.
+ if (unwindEntry.lsdaLocation)
+ ++numLSDAs;
+
+ // Gather the personality functions now, so that they're in deterministic
+ // order (derived from the DefinedAtom order).
+ if (unwindEntry.personalityFunction) {
+ auto pFunc = std::find(personalities.begin(), personalities.end(),
+ unwindEntry.personalityFunction);
+ if (pFunc == personalities.end())
+ personalities.push_back(unwindEntry.personalityFunction);
+ }
+ }
+ }
+
+ CompactUnwindEntry extractCompactUnwindEntry(const DefinedAtom *atom) {
+ CompactUnwindEntry entry;
+
+ for (const Reference *ref : *atom) {
+ switch (ref->offsetInAtom()) {
+ case 0:
+ // FIXME: there could legitimately be functions with multiple encoding
+ // entries. However, nothing produces them at the moment.
+ assert(ref->addend() == 0 && "unexpected offset into function");
+ entry.rangeStart = ref->target();
+ break;
+ case 0x10:
+ assert(ref->addend() == 0 && "unexpected offset into personality fn");
+ entry.personalityFunction = ref->target();
+ break;
+ case 0x18:
+ assert(ref->addend() == 0 && "unexpected offset into LSDA atom");
+ entry.lsdaLocation = ref->target();
+ break;
+ }
+ }
+
+ if (atom->rawContent().size() < 4 * sizeof(uint32_t))
+ return entry;
+
+ using normalized::read32;
+ entry.rangeLength =
+ read32(atom->rawContent().data() + 2 * sizeof(uint32_t), _isBig);
+ entry.encoding =
+ read32(atom->rawContent().data() + 3 * sizeof(uint32_t), _isBig);
+ return entry;
+ }
+
+ void
+ collectDwarfFrameEntries(const SimpleFile &mergedFile,
+ std::map<const Atom *, const Atom *> &dwarfFrames) {
+ for (const DefinedAtom *ehFrameAtom : mergedFile.defined()) {
+ if (ehFrameAtom->contentType() != DefinedAtom::typeCFI)
+ continue;
+ if (ArchHandler::isDwarfCIE(_isBig, ehFrameAtom))
+ continue;
+
+ if (const Atom *function = _archHandler.fdeTargetFunction(ehFrameAtom))
+ dwarfFrames[function] = ehFrameAtom;
+ }
+ }
+
+ /// Every atom defined in __TEXT,__text needs an entry in the final
+ /// __unwind_info section (in order). These comes from two sources:
+ /// + Input __compact_unwind sections where possible (after adding the
+ /// personality function offset which is only known now).
+ /// + A synthesised reference to __eh_frame if there's no __compact_unwind
+ /// or too many personality functions to be accommodated.
+ std::vector<CompactUnwindEntry> createUnwindInfoEntries(
+ const SimpleFile &mergedFile,
+ const std::map<const Atom *, CompactUnwindEntry> &unwindLocs,
+ const std::vector<const Atom *> &personalities,
+ const std::map<const Atom *, const Atom *> &dwarfFrames) {
+ std::vector<CompactUnwindEntry> unwindInfos;
+
+ LLVM_DEBUG(llvm::dbgs() << " Creating __unwind_info entries\n");
+ // The final order in the __unwind_info section must be derived from the
+ // order of typeCode atoms, since that's how they'll be put into the object
+ // file eventually (yuck!).
+ for (const DefinedAtom *atom : mergedFile.defined()) {
+ if (atom->contentType() != DefinedAtom::typeCode)
+ continue;
+
+ unwindInfos.push_back(finalizeUnwindInfoEntryForAtom(
+ atom, unwindLocs, personalities, dwarfFrames));
+
+ LLVM_DEBUG(llvm::dbgs()
+ << " Entry for " << atom->name() << ", final encoding="
+ << llvm::format("0x%08x", unwindInfos.back().encoding)
+ << '\n');
+ }
+
+ return unwindInfos;
+ }
+
+ /// Remove unused EH frames.
+ ///
+ /// An EH frame is considered unused if there is a corresponding compact
+ /// unwind atom that doesn't require the EH frame.
+ void pruneUnusedEHFrames(
+ SimpleFile &mergedFile,
+ const std::vector<CompactUnwindEntry> &unwindInfos,
+ const std::map<const Atom *, CompactUnwindEntry> &unwindLocs,
+ const std::map<const Atom *, const Atom *> &dwarfFrames) {
+
+ // Worklist of all 'used' FDEs.
+ std::vector<const DefinedAtom *> usedDwarfWorklist;
+
+ // We have to check two conditions when building the worklist:
+ // (1) EH frames used by compact unwind entries.
+ for (auto &entry : unwindInfos)
+ if (entry.ehFrame)
+ usedDwarfWorklist.push_back(cast<DefinedAtom>(entry.ehFrame));
+
+ // (2) EH frames that reference functions with no corresponding compact
+ // unwind info.
+ for (auto &entry : dwarfFrames)
+ if (!unwindLocs.count(entry.first))
+ usedDwarfWorklist.push_back(cast<DefinedAtom>(entry.second));
+
+ // Add all transitively referenced CFI atoms by processing the worklist.
+ std::set<const Atom *> usedDwarfFrames;
+ while (!usedDwarfWorklist.empty()) {
+ const DefinedAtom *cfiAtom = usedDwarfWorklist.back();
+ usedDwarfWorklist.pop_back();
+ usedDwarfFrames.insert(cfiAtom);
+ for (const auto *ref : *cfiAtom) {
+ const DefinedAtom *cfiTarget = dyn_cast<DefinedAtom>(ref->target());
+ if (cfiTarget->contentType() == DefinedAtom::typeCFI)
+ usedDwarfWorklist.push_back(cfiTarget);
+ }
+ }
+
+ // Finally, delete all unreferenced CFI atoms.
+ mergedFile.removeDefinedAtomsIf([&](const DefinedAtom *atom) {
+ if ((atom->contentType() == DefinedAtom::typeCFI) &&
+ !usedDwarfFrames.count(atom))
+ return true;
+ return false;
+ });
+ }
+
+ CompactUnwindEntry finalizeUnwindInfoEntryForAtom(
+ const DefinedAtom *function,
+ const std::map<const Atom *, CompactUnwindEntry> &unwindLocs,
+ const std::vector<const Atom *> &personalities,
+ const std::map<const Atom *, const Atom *> &dwarfFrames) {
+ auto unwindLoc = unwindLocs.find(function);
+
+ CompactUnwindEntry entry;
+ if (unwindLoc == unwindLocs.end()) {
+ // Default entry has correct encoding (0 => no unwind), but we need to
+ // synthesise the function.
+ entry.rangeStart = function;
+ entry.rangeLength = function->size();
+ } else
+ entry = unwindLoc->second;
+
+
+ // If there's no __compact_unwind entry, or it explicitly says to use
+ // __eh_frame, we need to try and fill in the correct DWARF atom.
+ if (entry.encoding == _archHandler.dwarfCompactUnwindType() ||
+ entry.encoding == 0) {
+ auto dwarfFrame = dwarfFrames.find(function);
+ if (dwarfFrame != dwarfFrames.end()) {
+ entry.encoding = _archHandler.dwarfCompactUnwindType();
+ entry.ehFrame = dwarfFrame->second;
+ }
+ }
+
+ auto personality = std::find(personalities.begin(), personalities.end(),
+ entry.personalityFunction);
+ uint32_t personalityIdx = personality == personalities.end()
+ ? 0
+ : personality - personalities.begin() + 1;
+
+ // FIXME: We should also use DWARF when there isn't enough room for the
+ // personality function in the compact encoding.
+ assert(personalityIdx < 4 && "too many personality functions");
+
+ entry.encoding |= personalityIdx << 28;
+
+ if (entry.lsdaLocation)
+ entry.encoding |= 1U << 30;
+
+ return entry;
+ }
+
+ const MachOLinkingContext &_ctx;
+ mach_o::ArchHandler &_archHandler;
+ MachOFile &_file;
+ bool _isBig;
+};
+
+void addCompactUnwindPass(PassManager &pm, const MachOLinkingContext &ctx) {
+ assert(ctx.needsCompactUnwindPass());
+ pm.add(llvm::make_unique<CompactUnwindPass>(ctx));
+}
+
+} // end namesapce mach_o
+} // end namesapce lld
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/DebugInfo.h b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/DebugInfo.h
new file mode 100644
index 000000000000..28e41bf4263c
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/DebugInfo.h
@@ -0,0 +1,106 @@
+//===- lib/ReaderWriter/MachO/File.h ----------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_MACHO_DEBUGINFO_H
+#define LLD_READER_WRITER_MACHO_DEBUGINFO_H
+
+#include "lld/Core/Atom.h"
+#include <vector>
+
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+
+
+namespace lld {
+namespace mach_o {
+
+class DebugInfo {
+public:
+ enum class Kind {
+ Dwarf,
+ Stabs
+ };
+
+ Kind kind() const { return _kind; }
+
+ void setAllocator(std::unique_ptr<llvm::BumpPtrAllocator> allocator) {
+ _allocator = std::move(allocator);
+ }
+
+protected:
+ DebugInfo(Kind kind) : _kind(kind) {}
+
+private:
+ std::unique_ptr<llvm::BumpPtrAllocator> _allocator;
+ Kind _kind;
+};
+
+struct TranslationUnitSource {
+ StringRef name;
+ StringRef path;
+};
+
+class DwarfDebugInfo : public DebugInfo {
+public:
+ DwarfDebugInfo(TranslationUnitSource tu)
+ : DebugInfo(Kind::Dwarf), _tu(std::move(tu)) {}
+
+ static inline bool classof(const DebugInfo *di) {
+ return di->kind() == Kind::Dwarf;
+ }
+
+ const TranslationUnitSource &translationUnitSource() const { return _tu; }
+
+private:
+ TranslationUnitSource _tu;
+};
+
+struct Stab {
+ Stab(const Atom* atom, uint8_t type, uint8_t other, uint16_t desc,
+ uint32_t value, StringRef str)
+ : atom(atom), type(type), other(other), desc(desc), value(value),
+ str(str) {}
+
+ const class Atom* atom;
+ uint8_t type;
+ uint8_t other;
+ uint16_t desc;
+ uint32_t value;
+ StringRef str;
+};
+
+inline raw_ostream& operator<<(raw_ostream &os, Stab &s) {
+ os << "Stab -- atom: " << llvm::format("%p", s.atom) << ", type: " << (uint32_t)s.type
+ << ", other: " << (uint32_t)s.other << ", desc: " << s.desc << ", value: " << s.value
+ << ", str: '" << s.str << "'";
+ return os;
+}
+
+class StabsDebugInfo : public DebugInfo {
+public:
+
+ typedef std::vector<Stab> StabsList;
+
+ StabsDebugInfo(StabsList stabs)
+ : DebugInfo(Kind::Stabs), _stabs(std::move(stabs)) {}
+
+ static inline bool classof(const DebugInfo *di) {
+ return di->kind() == Kind::Stabs;
+ }
+
+ const StabsList& stabs() const { return _stabs; }
+
+public:
+ StabsList _stabs;
+};
+
+} // end namespace mach_o
+} // end namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_DEBUGINFO_H
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ExecutableAtoms.h b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ExecutableAtoms.h
new file mode 100644
index 000000000000..ab14e6d8c3e7
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ExecutableAtoms.h
@@ -0,0 +1,155 @@
+//===- lib/ReaderWriter/MachO/ExecutableAtoms.h ---------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_MACHO_EXECUTABLE_ATOMS_H
+#define LLD_READER_WRITER_MACHO_EXECUTABLE_ATOMS_H
+
+#include "Atoms.h"
+#include "File.h"
+
+#include "llvm/BinaryFormat/MachO.h"
+
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/LinkingContext.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/Simple.h"
+#include "lld/Core/UndefinedAtom.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+
+namespace lld {
+namespace mach_o {
+
+
+//
+// CEntryFile adds an UndefinedAtom for "_main" so that the Resolving
+// phase will fail if "_main" is undefined.
+//
+class CEntryFile : public SimpleFile {
+public:
+ CEntryFile(const MachOLinkingContext &context)
+ : SimpleFile("C entry", kindCEntryObject),
+ _undefMain(*this, context.entrySymbolName()) {
+ this->addAtom(_undefMain);
+ }
+
+private:
+ SimpleUndefinedAtom _undefMain;
+};
+
+
+//
+// StubHelperFile adds an UndefinedAtom for "dyld_stub_binder" so that
+// the Resolveing phase will fail if "dyld_stub_binder" is undefined.
+//
+class StubHelperFile : public SimpleFile {
+public:
+ StubHelperFile(const MachOLinkingContext &context)
+ : SimpleFile("stub runtime", kindStubHelperObject),
+ _undefBinder(*this, context.binderSymbolName()) {
+ this->addAtom(_undefBinder);
+ }
+
+private:
+ SimpleUndefinedAtom _undefBinder;
+};
+
+
+//
+// MachHeaderAliasFile lazily instantiates the magic symbols that mark the start
+// of the mach_header for final linked images.
+//
+class MachHeaderAliasFile : public SimpleFile {
+public:
+ MachHeaderAliasFile(const MachOLinkingContext &context)
+ : SimpleFile("mach_header symbols", kindHeaderObject) {
+ StringRef machHeaderSymbolName;
+ DefinedAtom::Scope symbolScope = DefinedAtom::scopeLinkageUnit;
+ StringRef dsoHandleName;
+ switch (context.outputMachOType()) {
+ case llvm::MachO::MH_OBJECT:
+ machHeaderSymbolName = "__mh_object_header";
+ break;
+ case llvm::MachO::MH_EXECUTE:
+ machHeaderSymbolName = "__mh_execute_header";
+ symbolScope = DefinedAtom::scopeGlobal;
+ dsoHandleName = "___dso_handle";
+ break;
+ case llvm::MachO::MH_FVMLIB:
+ llvm_unreachable("no mach_header symbol for file type");
+ case llvm::MachO::MH_CORE:
+ llvm_unreachable("no mach_header symbol for file type");
+ case llvm::MachO::MH_PRELOAD:
+ llvm_unreachable("no mach_header symbol for file type");
+ case llvm::MachO::MH_DYLIB:
+ machHeaderSymbolName = "__mh_dylib_header";
+ dsoHandleName = "___dso_handle";
+ break;
+ case llvm::MachO::MH_DYLINKER:
+ machHeaderSymbolName = "__mh_dylinker_header";
+ dsoHandleName = "___dso_handle";
+ break;
+ case llvm::MachO::MH_BUNDLE:
+ machHeaderSymbolName = "__mh_bundle_header";
+ dsoHandleName = "___dso_handle";
+ break;
+ case llvm::MachO::MH_DYLIB_STUB:
+ llvm_unreachable("no mach_header symbol for file type");
+ case llvm::MachO::MH_DSYM:
+ llvm_unreachable("no mach_header symbol for file type");
+ case llvm::MachO::MH_KEXT_BUNDLE:
+ dsoHandleName = "___dso_handle";
+ break;
+ }
+ if (!machHeaderSymbolName.empty())
+ _definedAtoms.push_back(new (allocator()) MachODefinedAtom(
+ *this, machHeaderSymbolName, symbolScope,
+ DefinedAtom::typeMachHeader, DefinedAtom::mergeNo, false,
+ true /* noDeadStrip */,
+ ArrayRef<uint8_t>(), DefinedAtom::Alignment(4096)));
+
+ if (!dsoHandleName.empty())
+ _definedAtoms.push_back(new (allocator()) MachODefinedAtom(
+ *this, dsoHandleName, DefinedAtom::scopeLinkageUnit,
+ DefinedAtom::typeDSOHandle, DefinedAtom::mergeNo, false,
+ true /* noDeadStrip */,
+ ArrayRef<uint8_t>(), DefinedAtom::Alignment(1)));
+ }
+
+ const AtomRange<DefinedAtom> defined() const override {
+ return _definedAtoms;
+ }
+ const AtomRange<UndefinedAtom> undefined() const override {
+ return _noUndefinedAtoms;
+ }
+
+ const AtomRange<SharedLibraryAtom> sharedLibrary() const override {
+ return _noSharedLibraryAtoms;
+ }
+
+ const AtomRange<AbsoluteAtom> absolute() const override {
+ return _noAbsoluteAtoms;
+ }
+
+ void clearAtoms() override {
+ _definedAtoms.clear();
+ _noUndefinedAtoms.clear();
+ _noSharedLibraryAtoms.clear();
+ _noAbsoluteAtoms.clear();
+ }
+
+
+private:
+ mutable AtomVector<DefinedAtom> _definedAtoms;
+};
+
+} // namespace mach_o
+} // namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_EXECUTABLE_ATOMS_H
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/File.h b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/File.h
new file mode 100644
index 000000000000..2bdd6342b477
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/File.h
@@ -0,0 +1,400 @@
+//===- lib/ReaderWriter/MachO/File.h ----------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_MACHO_FILE_H
+#define LLD_READER_WRITER_MACHO_FILE_H
+
+#include "Atoms.h"
+#include "DebugInfo.h"
+#include "MachONormalizedFile.h"
+#include "lld/Core/SharedLibraryFile.h"
+#include "lld/Core/Simple.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/Format.h"
+#include <unordered_map>
+
+namespace lld {
+namespace mach_o {
+
+using lld::mach_o::normalized::Section;
+
+class MachOFile : public SimpleFile {
+public:
+
+ /// Real file constructor - for on-disk files.
+ MachOFile(std::unique_ptr<MemoryBuffer> mb, MachOLinkingContext *ctx)
+ : SimpleFile(mb->getBufferIdentifier(), File::kindMachObject),
+ _mb(std::move(mb)), _ctx(ctx) {}
+
+ /// Dummy file constructor - for virtual files.
+ MachOFile(StringRef path)
+ : SimpleFile(path, File::kindMachObject) {}
+
+ void addDefinedAtom(StringRef name, Atom::Scope scope,
+ DefinedAtom::ContentType type, DefinedAtom::Merge merge,
+ uint64_t sectionOffset, uint64_t contentSize, bool thumb,
+ bool noDeadStrip, bool copyRefs,
+ const Section *inSection) {
+ assert(sectionOffset+contentSize <= inSection->content.size());
+ ArrayRef<uint8_t> content = inSection->content.slice(sectionOffset,
+ contentSize);
+ if (copyRefs) {
+ // Make a copy of the atom's name and content that is owned by this file.
+ name = name.copy(allocator());
+ content = content.copy(allocator());
+ }
+ DefinedAtom::Alignment align(
+ inSection->alignment,
+ sectionOffset % inSection->alignment);
+ auto *atom =
+ new (allocator()) MachODefinedAtom(*this, name, scope, type, merge,
+ thumb, noDeadStrip, content, align);
+ addAtomForSection(inSection, atom, sectionOffset);
+ }
+
+ void addDefinedAtomInCustomSection(StringRef name, Atom::Scope scope,
+ DefinedAtom::ContentType type, DefinedAtom::Merge merge,
+ bool thumb, bool noDeadStrip, uint64_t sectionOffset,
+ uint64_t contentSize, StringRef sectionName,
+ bool copyRefs, const Section *inSection) {
+ assert(sectionOffset+contentSize <= inSection->content.size());
+ ArrayRef<uint8_t> content = inSection->content.slice(sectionOffset,
+ contentSize);
+ if (copyRefs) {
+ // Make a copy of the atom's name and content that is owned by this file.
+ name = name.copy(allocator());
+ content = content.copy(allocator());
+ sectionName = sectionName.copy(allocator());
+ }
+ DefinedAtom::Alignment align(
+ inSection->alignment,
+ sectionOffset % inSection->alignment);
+ auto *atom =
+ new (allocator()) MachODefinedCustomSectionAtom(*this, name, scope, type,
+ merge, thumb,
+ noDeadStrip, content,
+ sectionName, align);
+ addAtomForSection(inSection, atom, sectionOffset);
+ }
+
+ void addZeroFillDefinedAtom(StringRef name, Atom::Scope scope,
+ uint64_t sectionOffset, uint64_t size,
+ bool noDeadStrip, bool copyRefs,
+ const Section *inSection) {
+ if (copyRefs) {
+ // Make a copy of the atom's name and content that is owned by this file.
+ name = name.copy(allocator());
+ }
+ DefinedAtom::Alignment align(
+ inSection->alignment,
+ sectionOffset % inSection->alignment);
+
+ DefinedAtom::ContentType type = DefinedAtom::typeUnknown;
+ switch (inSection->type) {
+ case llvm::MachO::S_ZEROFILL:
+ type = DefinedAtom::typeZeroFill;
+ break;
+ case llvm::MachO::S_THREAD_LOCAL_ZEROFILL:
+ type = DefinedAtom::typeTLVInitialZeroFill;
+ break;
+ default:
+ llvm_unreachable("Unrecognized zero-fill section");
+ }
+
+ auto *atom =
+ new (allocator()) MachODefinedAtom(*this, name, scope, type, size,
+ noDeadStrip, align);
+ addAtomForSection(inSection, atom, sectionOffset);
+ }
+
+ void addUndefinedAtom(StringRef name, bool copyRefs) {
+ if (copyRefs) {
+ // Make a copy of the atom's name that is owned by this file.
+ name = name.copy(allocator());
+ }
+ auto *atom = new (allocator()) SimpleUndefinedAtom(*this, name);
+ addAtom(*atom);
+ _undefAtoms[name] = atom;
+ }
+
+ void addTentativeDefAtom(StringRef name, Atom::Scope scope, uint64_t size,
+ DefinedAtom::Alignment align, bool copyRefs) {
+ if (copyRefs) {
+ // Make a copy of the atom's name that is owned by this file.
+ name = name.copy(allocator());
+ }
+ auto *atom =
+ new (allocator()) MachOTentativeDefAtom(*this, name, scope, size, align);
+ addAtom(*atom);
+ _undefAtoms[name] = atom;
+ }
+
+ /// Search this file for an the atom from 'section' that covers
+ /// 'offsetInSect'. Returns nullptr is no atom found.
+ MachODefinedAtom *findAtomCoveringAddress(const Section &section,
+ uint64_t offsetInSect,
+ uint32_t *foundOffsetAtom=nullptr) {
+ const auto &pos = _sectionAtoms.find(&section);
+ if (pos == _sectionAtoms.end())
+ return nullptr;
+ const auto &vec = pos->second;
+ assert(offsetInSect < section.content.size());
+ // Vector of atoms for section are already sorted, so do binary search.
+ const auto &atomPos = std::lower_bound(vec.begin(), vec.end(), offsetInSect,
+ [offsetInSect](const SectionOffsetAndAtom &ao,
+ uint64_t targetAddr) -> bool {
+ // Each atom has a start offset of its slice of the
+ // section's content. This compare function must return true
+ // iff the atom's range is before the offset being searched for.
+ uint64_t atomsEndOffset = ao.offset+ao.atom->rawContent().size();
+ return (atomsEndOffset <= offsetInSect);
+ });
+ if (atomPos == vec.end())
+ return nullptr;
+ if (foundOffsetAtom)
+ *foundOffsetAtom = offsetInSect - atomPos->offset;
+ return atomPos->atom;
+ }
+
+ /// Searches this file for an UndefinedAtom named 'name'. Returns
+ /// nullptr is no such atom found.
+ const lld::Atom *findUndefAtom(StringRef name) {
+ auto pos = _undefAtoms.find(name);
+ if (pos == _undefAtoms.end())
+ return nullptr;
+ return pos->second;
+ }
+
+ typedef std::function<void (MachODefinedAtom* atom)> DefinedAtomVisitor;
+
+ void eachDefinedAtom(DefinedAtomVisitor vistor) {
+ for (auto &sectAndAtoms : _sectionAtoms) {
+ for (auto &offAndAtom : sectAndAtoms.second) {
+ vistor(offAndAtom.atom);
+ }
+ }
+ }
+
+ typedef std::function<void(MachODefinedAtom *atom, uint64_t offset)>
+ SectionAtomVisitor;
+
+ void eachAtomInSection(const Section &section, SectionAtomVisitor visitor) {
+ auto pos = _sectionAtoms.find(&section);
+ if (pos == _sectionAtoms.end())
+ return;
+ auto vec = pos->second;
+
+ for (auto &offAndAtom : vec)
+ visitor(offAndAtom.atom, offAndAtom.offset);
+ }
+
+ MachOLinkingContext::Arch arch() const { return _arch; }
+ void setArch(MachOLinkingContext::Arch arch) { _arch = arch; }
+
+ MachOLinkingContext::OS OS() const { return _os; }
+ void setOS(MachOLinkingContext::OS os) { _os = os; }
+
+ MachOLinkingContext::ObjCConstraint objcConstraint() const {
+ return _objcConstraint;
+ }
+ void setObjcConstraint(MachOLinkingContext::ObjCConstraint v) {
+ _objcConstraint = v;
+ }
+
+ uint32_t minVersion() const { return _minVersion; }
+ void setMinVersion(uint32_t v) { _minVersion = v; }
+
+ LoadCommandType minVersionLoadCommandKind() const {
+ return _minVersionLoadCommandKind;
+ }
+ void setMinVersionLoadCommandKind(LoadCommandType v) {
+ _minVersionLoadCommandKind = v;
+ }
+
+ uint32_t swiftVersion() const { return _swiftVersion; }
+ void setSwiftVersion(uint32_t v) { _swiftVersion = v; }
+
+ bool subsectionsViaSymbols() const {
+ return _flags & llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS;
+ }
+ void setFlags(normalized::FileFlags v) { _flags = v; }
+
+ /// Methods for support type inquiry through isa, cast, and dyn_cast:
+ static inline bool classof(const File *F) {
+ return F->kind() == File::kindMachObject;
+ }
+
+ void setDebugInfo(std::unique_ptr<DebugInfo> debugInfo) {
+ _debugInfo = std::move(debugInfo);
+ }
+
+ DebugInfo* debugInfo() const { return _debugInfo.get(); }
+ std::unique_ptr<DebugInfo> takeDebugInfo() { return std::move(_debugInfo); }
+
+protected:
+ std::error_code doParse() override {
+ // Convert binary file to normalized mach-o.
+ auto normFile = normalized::readBinary(_mb, _ctx->arch());
+ if (auto ec = normFile.takeError())
+ return llvm::errorToErrorCode(std::move(ec));
+ // Convert normalized mach-o to atoms.
+ if (auto ec = normalized::normalizedObjectToAtoms(this, **normFile, false))
+ return llvm::errorToErrorCode(std::move(ec));
+ return std::error_code();
+ }
+
+private:
+ struct SectionOffsetAndAtom { uint64_t offset; MachODefinedAtom *atom; };
+
+ void addAtomForSection(const Section *inSection, MachODefinedAtom* atom,
+ uint64_t sectionOffset) {
+ SectionOffsetAndAtom offAndAtom;
+ offAndAtom.offset = sectionOffset;
+ offAndAtom.atom = atom;
+ _sectionAtoms[inSection].push_back(offAndAtom);
+ addAtom(*atom);
+ }
+
+ typedef llvm::DenseMap<const normalized::Section *,
+ std::vector<SectionOffsetAndAtom>> SectionToAtoms;
+ typedef llvm::StringMap<const lld::Atom *> NameToAtom;
+
+ std::unique_ptr<MemoryBuffer> _mb;
+ MachOLinkingContext *_ctx;
+ SectionToAtoms _sectionAtoms;
+ NameToAtom _undefAtoms;
+ MachOLinkingContext::Arch _arch = MachOLinkingContext::arch_unknown;
+ MachOLinkingContext::OS _os = MachOLinkingContext::OS::unknown;
+ uint32_t _minVersion = 0;
+ LoadCommandType _minVersionLoadCommandKind = (LoadCommandType)0;
+ MachOLinkingContext::ObjCConstraint _objcConstraint =
+ MachOLinkingContext::objc_unknown;
+ uint32_t _swiftVersion = 0;
+ normalized::FileFlags _flags = llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS;
+ std::unique_ptr<DebugInfo> _debugInfo;
+};
+
+class MachODylibFile : public SharedLibraryFile {
+public:
+ MachODylibFile(std::unique_ptr<MemoryBuffer> mb, MachOLinkingContext *ctx)
+ : SharedLibraryFile(mb->getBufferIdentifier()),
+ _mb(std::move(mb)), _ctx(ctx) {}
+
+ MachODylibFile(StringRef path) : SharedLibraryFile(path) {}
+
+ OwningAtomPtr<SharedLibraryAtom> exports(StringRef name) const override {
+ // Pass down _installName so that if this requested symbol
+ // is re-exported through this dylib, the SharedLibraryAtom's loadName()
+ // is this dylib installName and not the implementation dylib's.
+ // NOTE: isData is not needed for dylibs (it matters for static libs).
+ return exports(name, _installName);
+ }
+
+ /// Adds symbol name that this dylib exports. The corresponding
+ /// SharedLibraryAtom is created lazily (since most symbols are not used).
+ void addExportedSymbol(StringRef name, bool weakDef, bool copyRefs) {
+ if (copyRefs) {
+ name = name.copy(allocator());
+ }
+ AtomAndFlags info(weakDef);
+ _nameToAtom[name] = info;
+ }
+
+ void addReExportedDylib(StringRef dylibPath) {
+ _reExportedDylibs.emplace_back(dylibPath);
+ }
+
+ StringRef installName() const { return _installName; }
+ uint32_t currentVersion() { return _currentVersion; }
+ uint32_t compatVersion() { return _compatVersion; }
+
+ void setInstallName(StringRef name) { _installName = name; }
+ void setCompatVersion(uint32_t version) { _compatVersion = version; }
+ void setCurrentVersion(uint32_t version) { _currentVersion = version; }
+
+ typedef std::function<MachODylibFile *(StringRef)> FindDylib;
+
+ void loadReExportedDylibs(FindDylib find) {
+ for (ReExportedDylib &entry : _reExportedDylibs) {
+ entry.file = find(entry.path);
+ }
+ }
+
+ StringRef getDSOName() const override { return _installName; }
+
+ std::error_code doParse() override {
+ // Convert binary file to normalized mach-o.
+ auto normFile = normalized::readBinary(_mb, _ctx->arch());
+ if (auto ec = normFile.takeError())
+ return llvm::errorToErrorCode(std::move(ec));
+ // Convert normalized mach-o to atoms.
+ if (auto ec = normalized::normalizedDylibToAtoms(this, **normFile, false))
+ return llvm::errorToErrorCode(std::move(ec));
+ return std::error_code();
+ }
+
+private:
+ OwningAtomPtr<SharedLibraryAtom> exports(StringRef name,
+ StringRef installName) const {
+ // First, check if requested symbol is directly implemented by this dylib.
+ auto entry = _nameToAtom.find(name);
+ if (entry != _nameToAtom.end()) {
+ // FIXME: Make this map a set and only used in assert builds.
+ // Note, its safe to assert here as the resolver is the only client of
+ // this API and it only requests exports for undefined symbols.
+ // If we return from here we are no longer undefined so we should never
+ // get here again.
+ assert(!entry->second.atom && "Duplicate shared library export");
+ bool weakDef = entry->second.weakDef;
+ auto *atom = new (allocator()) MachOSharedLibraryAtom(*this, name,
+ installName,
+ weakDef);
+ entry->second.atom = atom;
+ return atom;
+ }
+
+ // Next, check if symbol is implemented in some re-exported dylib.
+ for (const ReExportedDylib &dylib : _reExportedDylibs) {
+ assert(dylib.file);
+ auto atom = dylib.file->exports(name, installName);
+ if (atom.get())
+ return atom;
+ }
+
+ // Symbol not exported or re-exported by this dylib.
+ return nullptr;
+ }
+
+ struct ReExportedDylib {
+ ReExportedDylib(StringRef p) : path(p), file(nullptr) { }
+ StringRef path;
+ MachODylibFile *file;
+ };
+
+ struct AtomAndFlags {
+ AtomAndFlags() : atom(nullptr), weakDef(false) { }
+ AtomAndFlags(bool weak) : atom(nullptr), weakDef(weak) { }
+ const SharedLibraryAtom *atom;
+ bool weakDef;
+ };
+
+ std::unique_ptr<MemoryBuffer> _mb;
+ MachOLinkingContext *_ctx;
+ StringRef _installName;
+ uint32_t _currentVersion;
+ uint32_t _compatVersion;
+ std::vector<ReExportedDylib> _reExportedDylibs;
+ mutable std::unordered_map<StringRef, AtomAndFlags> _nameToAtom;
+};
+
+} // end namespace mach_o
+} // end namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_FILE_H
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/FlatNamespaceFile.h b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/FlatNamespaceFile.h
new file mode 100644
index 000000000000..7ccd4f19f834
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/FlatNamespaceFile.h
@@ -0,0 +1,63 @@
+//===- lib/ReaderWriter/MachO/FlatNamespaceFile.h -------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_MACHO_FLAT_NAMESPACE_FILE_H
+#define LLD_READER_WRITER_MACHO_FLAT_NAMESPACE_FILE_H
+
+#include "Atoms.h"
+#include "lld/Core/SharedLibraryFile.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/Support/Debug.h"
+
+namespace lld {
+namespace mach_o {
+
+//
+// A FlateNamespaceFile instance may be added as a resolution source of last
+// resort, depending on how -flat_namespace and -undefined are set.
+//
+class FlatNamespaceFile : public SharedLibraryFile {
+public:
+ FlatNamespaceFile(const MachOLinkingContext &context)
+ : SharedLibraryFile("flat namespace") { }
+
+ OwningAtomPtr<SharedLibraryAtom> exports(StringRef name) const override {
+ return new (allocator()) MachOSharedLibraryAtom(*this, name, getDSOName(),
+ false);
+ }
+
+ StringRef getDSOName() const override { return "flat-namespace"; }
+
+ const AtomRange<DefinedAtom> defined() const override {
+ return _noDefinedAtoms;
+ }
+ const AtomRange<UndefinedAtom> undefined() const override {
+ return _noUndefinedAtoms;
+ }
+
+ const AtomRange<SharedLibraryAtom> sharedLibrary() const override {
+ return _noSharedLibraryAtoms;
+ }
+
+ const AtomRange<AbsoluteAtom> absolute() const override {
+ return _noAbsoluteAtoms;
+ }
+
+ void clearAtoms() override {
+ _noDefinedAtoms.clear();
+ _noUndefinedAtoms.clear();
+ _noSharedLibraryAtoms.clear();
+ _noAbsoluteAtoms.clear();
+ }
+};
+
+} // namespace mach_o
+} // namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_FLAT_NAMESPACE_FILE_H
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/GOTPass.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/GOTPass.cpp
new file mode 100644
index 000000000000..49e6f88d4aa4
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/GOTPass.cpp
@@ -0,0 +1,184 @@
+//===- lib/ReaderWriter/MachO/GOTPass.cpp -----------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This linker pass transforms all GOT kind references to real references.
+/// That is, in assembly you can write something like:
+/// movq foo@GOTPCREL(%rip), %rax
+/// which means you want to load a pointer to "foo" out of the GOT (global
+/// Offsets Table). In the object file, the Atom containing this instruction
+/// has a Reference whose target is an Atom named "foo" and the Reference
+/// kind is a GOT load. The linker needs to instantiate a pointer sized
+/// GOT entry. This is done be creating a GOT Atom to represent that pointer
+/// sized data in this pass, and altering the Atom graph so the Reference now
+/// points to the GOT Atom entry (corresponding to "foo") and changing the
+/// Reference Kind to reflect it is now pointing to a GOT entry (rather
+/// then needing a GOT entry).
+///
+/// There is one optimization the linker can do here. If the target of the GOT
+/// is in the same linkage unit and does not need to be interposable, and
+/// the GOT use is just a load (not some other operation), this pass can
+/// transform that load into an LEA (add). This optimizes away one memory load
+/// which at runtime that could stall the pipeline. This optimization only
+/// works for architectures in which a (GOT) load instruction can be change to
+/// an LEA instruction that is the same size. The method isGOTAccess() should
+/// only return true for "canBypassGOT" if this optimization is supported.
+///
+//===----------------------------------------------------------------------===//
+
+#include "ArchHandler.h"
+#include "File.h"
+#include "MachOPasses.h"
+#include "lld/Common/LLVM.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/Simple.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
+
+namespace lld {
+namespace mach_o {
+
+//
+// GOT Entry Atom created by the GOT pass.
+//
+class GOTEntryAtom : public SimpleDefinedAtom {
+public:
+ GOTEntryAtom(const File &file, bool is64, StringRef name)
+ : SimpleDefinedAtom(file), _is64(is64), _name(name) { }
+
+ ~GOTEntryAtom() override = default;
+
+ ContentType contentType() const override {
+ return DefinedAtom::typeGOT;
+ }
+
+ Alignment alignment() const override {
+ return _is64 ? 8 : 4;
+ }
+
+ uint64_t size() const override {
+ return _is64 ? 8 : 4;
+ }
+
+ ContentPermissions permissions() const override {
+ return DefinedAtom::permRW_;
+ }
+
+ ArrayRef<uint8_t> rawContent() const override {
+ static const uint8_t zeros[] =
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ return llvm::makeArrayRef(zeros, size());
+ }
+
+ StringRef slotName() const {
+ return _name;
+ }
+
+private:
+ const bool _is64;
+ StringRef _name;
+};
+
+/// Pass for instantiating and optimizing GOT slots.
+///
+class GOTPass : public Pass {
+public:
+ GOTPass(const MachOLinkingContext &context)
+ : _ctx(context), _archHandler(_ctx.archHandler()),
+ _file(*_ctx.make_file<MachOFile>("<mach-o GOT Pass>")) {
+ _file.setOrdinal(_ctx.getNextOrdinalAndIncrement());
+ }
+
+private:
+ llvm::Error perform(SimpleFile &mergedFile) override {
+ // Scan all references in all atoms.
+ for (const DefinedAtom *atom : mergedFile.defined()) {
+ for (const Reference *ref : *atom) {
+ // Look at instructions accessing the GOT.
+ bool canBypassGOT;
+ if (!_archHandler.isGOTAccess(*ref, canBypassGOT))
+ continue;
+ const Atom *target = ref->target();
+ assert(target != nullptr);
+
+ if (!shouldReplaceTargetWithGOTAtom(target, canBypassGOT)) {
+ // Update reference kind to reflect that target is a direct accesss.
+ _archHandler.updateReferenceToGOT(ref, false);
+ } else {
+ // Replace the target with a reference to a GOT entry.
+ const DefinedAtom *gotEntry = makeGOTEntry(target);
+ const_cast<Reference *>(ref)->setTarget(gotEntry);
+ // Update reference kind to reflect that target is now a GOT entry.
+ _archHandler.updateReferenceToGOT(ref, true);
+ }
+ }
+ }
+
+ // Sort and add all created GOT Atoms to master file
+ std::vector<const GOTEntryAtom *> entries;
+ entries.reserve(_targetToGOT.size());
+ for (auto &it : _targetToGOT)
+ entries.push_back(it.second);
+ std::sort(entries.begin(), entries.end(),
+ [](const GOTEntryAtom *left, const GOTEntryAtom *right) {
+ return (left->slotName().compare(right->slotName()) < 0);
+ });
+ for (const GOTEntryAtom *slot : entries)
+ mergedFile.addAtom(*slot);
+
+ return llvm::Error::success();
+ }
+
+ bool shouldReplaceTargetWithGOTAtom(const Atom *target, bool canBypassGOT) {
+ // Accesses to shared library symbols must go through GOT.
+ if (isa<SharedLibraryAtom>(target))
+ return true;
+ // Accesses to interposable symbols in same linkage unit must also go
+ // through GOT.
+ const DefinedAtom *defTarget = dyn_cast<DefinedAtom>(target);
+ if (defTarget != nullptr &&
+ defTarget->interposable() != DefinedAtom::interposeNo) {
+ assert(defTarget->scope() != DefinedAtom::scopeTranslationUnit);
+ return true;
+ }
+ // Target does not require indirection. So, if instruction allows GOT to be
+ // by-passed, do that optimization and don't create GOT entry.
+ return !canBypassGOT;
+ }
+
+ const DefinedAtom *makeGOTEntry(const Atom *target) {
+ auto pos = _targetToGOT.find(target);
+ if (pos == _targetToGOT.end()) {
+ auto *gotEntry = new (_file.allocator())
+ GOTEntryAtom(_file, _ctx.is64Bit(), target->name());
+ _targetToGOT[target] = gotEntry;
+ const ArchHandler::ReferenceInfo &nlInfo = _archHandler.stubInfo().
+ nonLazyPointerReferenceToBinder;
+ gotEntry->addReference(Reference::KindNamespace::mach_o, nlInfo.arch,
+ nlInfo.kind, 0, target, 0);
+ return gotEntry;
+ }
+ return pos->second;
+ }
+
+ const MachOLinkingContext &_ctx;
+ mach_o::ArchHandler &_archHandler;
+ MachOFile &_file;
+ llvm::DenseMap<const Atom*, const GOTEntryAtom*> _targetToGOT;
+};
+
+void addGOTPass(PassManager &pm, const MachOLinkingContext &ctx) {
+ assert(ctx.needsGOTPass());
+ pm.add(llvm::make_unique<GOTPass>(ctx));
+}
+
+} // end namesapce mach_o
+} // end namesapce lld
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/LayoutPass.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/LayoutPass.cpp
new file mode 100644
index 000000000000..9058e4f562e2
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/LayoutPass.cpp
@@ -0,0 +1,490 @@
+//===-- ReaderWriter/MachO/LayoutPass.cpp - Layout atoms ------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LayoutPass.h"
+#include "lld/Core/Instrumentation.h"
+#include "lld/Core/PassManager.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Parallel.h"
+#include <algorithm>
+#include <set>
+#include <utility>
+
+using namespace lld;
+
+#define DEBUG_TYPE "LayoutPass"
+
+namespace lld {
+namespace mach_o {
+
+static bool compareAtoms(const LayoutPass::SortKey &,
+ const LayoutPass::SortKey &,
+ LayoutPass::SortOverride customSorter);
+
+#ifndef NDEBUG
+// Return "reason (leftval, rightval)"
+static std::string formatReason(StringRef reason, int leftVal, int rightVal) {
+ return (Twine(reason) + " (" + Twine(leftVal) + ", " + Twine(rightVal) + ")")
+ .str();
+}
+
+// Less-than relationship of two atoms must be transitive, which is, if a < b
+// and b < c, a < c must be true. This function checks the transitivity by
+// checking the sort results.
+static void checkTransitivity(std::vector<LayoutPass::SortKey> &vec,
+ LayoutPass::SortOverride customSorter) {
+ for (auto i = vec.begin(), e = vec.end(); (i + 1) != e; ++i) {
+ for (auto j = i + 1; j != e; ++j) {
+ assert(compareAtoms(*i, *j, customSorter));
+ assert(!compareAtoms(*j, *i, customSorter));
+ }
+ }
+}
+
+// Helper functions to check follow-on graph.
+typedef llvm::DenseMap<const DefinedAtom *, const DefinedAtom *> AtomToAtomT;
+
+static std::string atomToDebugString(const Atom *atom) {
+ const DefinedAtom *definedAtom = dyn_cast<DefinedAtom>(atom);
+ std::string str;
+ llvm::raw_string_ostream s(str);
+ if (definedAtom->name().empty())
+ s << "<anonymous " << definedAtom << ">";
+ else
+ s << definedAtom->name();
+ s << " in ";
+ if (definedAtom->customSectionName().empty())
+ s << "<anonymous>";
+ else
+ s << definedAtom->customSectionName();
+ s.flush();
+ return str;
+}
+
+static void showCycleDetectedError(const Registry &registry,
+ AtomToAtomT &followOnNexts,
+ const DefinedAtom *atom) {
+ const DefinedAtom *start = atom;
+ llvm::dbgs() << "There's a cycle in a follow-on chain!\n";
+ do {
+ llvm::dbgs() << " " << atomToDebugString(atom) << "\n";
+ for (const Reference *ref : *atom) {
+ StringRef kindValStr;
+ if (!registry.referenceKindToString(ref->kindNamespace(), ref->kindArch(),
+ ref->kindValue(), kindValStr)) {
+ kindValStr = "<unknown>";
+ }
+ llvm::dbgs() << " " << kindValStr
+ << ": " << atomToDebugString(ref->target()) << "\n";
+ }
+ atom = followOnNexts[atom];
+ } while (atom != start);
+ llvm::report_fatal_error("Cycle detected");
+}
+
+/// Exit if there's a cycle in a followon chain reachable from the
+/// given root atom. Uses the tortoise and hare algorithm to detect a
+/// cycle.
+static void checkNoCycleInFollowonChain(const Registry &registry,
+ AtomToAtomT &followOnNexts,
+ const DefinedAtom *root) {
+ const DefinedAtom *tortoise = root;
+ const DefinedAtom *hare = followOnNexts[root];
+ while (true) {
+ if (!tortoise || !hare)
+ return;
+ if (tortoise == hare)
+ showCycleDetectedError(registry, followOnNexts, tortoise);
+ tortoise = followOnNexts[tortoise];
+ hare = followOnNexts[followOnNexts[hare]];
+ }
+}
+
+static void checkReachabilityFromRoot(AtomToAtomT &followOnRoots,
+ const DefinedAtom *atom) {
+ if (!atom) return;
+ auto i = followOnRoots.find(atom);
+ if (i == followOnRoots.end()) {
+ llvm_unreachable(((Twine("Atom <") + atomToDebugString(atom) +
+ "> has no follow-on root!"))
+ .str()
+ .c_str());
+ }
+ const DefinedAtom *ap = i->second;
+ while (true) {
+ const DefinedAtom *next = followOnRoots[ap];
+ if (!next) {
+ llvm_unreachable((Twine("Atom <" + atomToDebugString(atom) +
+ "> is not reachable from its root!"))
+ .str()
+ .c_str());
+ }
+ if (next == ap)
+ return;
+ ap = next;
+ }
+}
+
+static void printDefinedAtoms(const File::AtomRange<DefinedAtom> &atomRange) {
+ for (const DefinedAtom *atom : atomRange) {
+ llvm::dbgs() << " file=" << atom->file().path()
+ << ", name=" << atom->name()
+ << ", size=" << atom->size()
+ << ", type=" << atom->contentType()
+ << ", ordinal=" << atom->ordinal()
+ << "\n";
+ }
+}
+
+/// Verify that the followon chain is sane. Should not be called in
+/// release binary.
+void LayoutPass::checkFollowonChain(const File::AtomRange<DefinedAtom> &range) {
+ ScopedTask task(getDefaultDomain(), "LayoutPass::checkFollowonChain");
+
+ // Verify that there's no cycle in follow-on chain.
+ std::set<const DefinedAtom *> roots;
+ for (const auto &ai : _followOnRoots)
+ roots.insert(ai.second);
+ for (const DefinedAtom *root : roots)
+ checkNoCycleInFollowonChain(_registry, _followOnNexts, root);
+
+ // Verify that all the atoms in followOnNexts have references to
+ // their roots.
+ for (const auto &ai : _followOnNexts) {
+ checkReachabilityFromRoot(_followOnRoots, ai.first);
+ checkReachabilityFromRoot(_followOnRoots, ai.second);
+ }
+}
+#endif // #ifndef NDEBUG
+
+/// The function compares atoms by sorting atoms in the following order
+/// a) Sorts atoms by their ordinal overrides (layout-after/ingroup)
+/// b) Sorts atoms by their permissions
+/// c) Sorts atoms by their content
+/// d) Sorts atoms by custom sorter
+/// e) Sorts atoms on how they appear using File Ordinality
+/// f) Sorts atoms on how they appear within the File
+static bool compareAtomsSub(const LayoutPass::SortKey &lc,
+ const LayoutPass::SortKey &rc,
+ LayoutPass::SortOverride customSorter,
+ std::string &reason) {
+ const DefinedAtom *left = lc._atom.get();
+ const DefinedAtom *right = rc._atom.get();
+ if (left == right) {
+ reason = "same";
+ return false;
+ }
+
+ // Find the root of the chain if it is a part of a follow-on chain.
+ const DefinedAtom *leftRoot = lc._root;
+ const DefinedAtom *rightRoot = rc._root;
+
+ // Sort atoms by their ordinal overrides only if they fall in the same
+ // chain.
+ if (leftRoot == rightRoot) {
+ LLVM_DEBUG(reason = formatReason("override", lc._override, rc._override));
+ return lc._override < rc._override;
+ }
+
+ // Sort same permissions together.
+ DefinedAtom::ContentPermissions leftPerms = leftRoot->permissions();
+ DefinedAtom::ContentPermissions rightPerms = rightRoot->permissions();
+
+ if (leftPerms != rightPerms) {
+ LLVM_DEBUG(
+ reason = formatReason("contentPerms", (int)leftPerms, (int)rightPerms));
+ return leftPerms < rightPerms;
+ }
+
+ // Sort same content types together.
+ DefinedAtom::ContentType leftType = leftRoot->contentType();
+ DefinedAtom::ContentType rightType = rightRoot->contentType();
+
+ if (leftType != rightType) {
+ LLVM_DEBUG(reason =
+ formatReason("contentType", (int)leftType, (int)rightType));
+ return leftType < rightType;
+ }
+
+ // Use custom sorter if supplied.
+ if (customSorter) {
+ bool leftBeforeRight;
+ if (customSorter(leftRoot, rightRoot, leftBeforeRight))
+ return leftBeforeRight;
+ }
+
+ // Sort by .o order.
+ const File *leftFile = &leftRoot->file();
+ const File *rightFile = &rightRoot->file();
+
+ if (leftFile != rightFile) {
+ LLVM_DEBUG(reason = formatReason(".o order", (int)leftFile->ordinal(),
+ (int)rightFile->ordinal()));
+ return leftFile->ordinal() < rightFile->ordinal();
+ }
+
+ // Sort by atom order with .o file.
+ uint64_t leftOrdinal = leftRoot->ordinal();
+ uint64_t rightOrdinal = rightRoot->ordinal();
+
+ if (leftOrdinal != rightOrdinal) {
+ LLVM_DEBUG(reason = formatReason("ordinal", (int)leftRoot->ordinal(),
+ (int)rightRoot->ordinal()));
+ return leftOrdinal < rightOrdinal;
+ }
+
+ llvm::errs() << "Unordered: <" << left->name() << "> <"
+ << right->name() << ">\n";
+ llvm_unreachable("Atoms with Same Ordinal!");
+}
+
+static bool compareAtoms(const LayoutPass::SortKey &lc,
+ const LayoutPass::SortKey &rc,
+ LayoutPass::SortOverride customSorter) {
+ std::string reason;
+ bool result = compareAtomsSub(lc, rc, customSorter, reason);
+ LLVM_DEBUG({
+ StringRef comp = result ? "<" : ">=";
+ llvm::dbgs() << "Layout: '" << lc._atom.get()->name()
+ << "' " << comp << " '"
+ << rc._atom.get()->name() << "' (" << reason << ")\n";
+ });
+ return result;
+}
+
+LayoutPass::LayoutPass(const Registry &registry, SortOverride sorter)
+ : _registry(registry), _customSorter(std::move(sorter)) {}
+
+// Returns the atom immediately followed by the given atom in the followon
+// chain.
+const DefinedAtom *LayoutPass::findAtomFollowedBy(
+ const DefinedAtom *targetAtom) {
+ // Start from the beginning of the chain and follow the chain until
+ // we find the targetChain.
+ const DefinedAtom *atom = _followOnRoots[targetAtom];
+ while (true) {
+ const DefinedAtom *prevAtom = atom;
+ AtomToAtomT::iterator targetFollowOnAtomsIter = _followOnNexts.find(atom);
+ // The target atom must be in the chain of its root.
+ assert(targetFollowOnAtomsIter != _followOnNexts.end());
+ atom = targetFollowOnAtomsIter->second;
+ if (atom == targetAtom)
+ return prevAtom;
+ }
+}
+
+// Check if all the atoms followed by the given target atom are of size zero.
+// When this method is called, an atom being added is not of size zero and
+// will be added to the head of the followon chain. All the atoms between the
+// atom and the targetAtom (specified by layout-after) need to be of size zero
+// in this case. Otherwise the desired layout is impossible.
+bool LayoutPass::checkAllPrevAtomsZeroSize(const DefinedAtom *targetAtom) {
+ const DefinedAtom *atom = _followOnRoots[targetAtom];
+ while (true) {
+ if (atom == targetAtom)
+ return true;
+ if (atom->size() != 0)
+ // TODO: print warning that an impossible layout is being desired by the
+ // user.
+ return false;
+ AtomToAtomT::iterator targetFollowOnAtomsIter = _followOnNexts.find(atom);
+ // The target atom must be in the chain of its root.
+ assert(targetFollowOnAtomsIter != _followOnNexts.end());
+ atom = targetFollowOnAtomsIter->second;
+ }
+}
+
+// Set the root of all atoms in targetAtom's chain to the given root.
+void LayoutPass::setChainRoot(const DefinedAtom *targetAtom,
+ const DefinedAtom *root) {
+ // Walk through the followon chain and override each node's root.
+ while (true) {
+ _followOnRoots[targetAtom] = root;
+ AtomToAtomT::iterator targetFollowOnAtomsIter =
+ _followOnNexts.find(targetAtom);
+ if (targetFollowOnAtomsIter == _followOnNexts.end())
+ return;
+ targetAtom = targetFollowOnAtomsIter->second;
+ }
+}
+
+/// This pass builds the followon tables described by two DenseMaps
+/// followOnRoots and followonNexts.
+/// The followOnRoots map contains a mapping of a DefinedAtom to its root
+/// The followOnNexts map contains a mapping of what DefinedAtom follows the
+/// current Atom
+/// The algorithm follows a very simple approach
+/// a) If the atom is first seen, then make that as the root atom
+/// b) The targetAtom which this Atom contains, has the root thats set to the
+/// root of the current atom
+/// c) If the targetAtom is part of a different tree and the root of the
+/// targetAtom is itself, Chain all the atoms that are contained in the tree
+/// to the current Tree
+/// d) If the targetAtom is part of a different chain and the root of the
+/// targetAtom until the targetAtom has all atoms of size 0, then chain the
+/// targetAtoms and its tree to the current chain
+void LayoutPass::buildFollowOnTable(const File::AtomRange<DefinedAtom> &range) {
+ ScopedTask task(getDefaultDomain(), "LayoutPass::buildFollowOnTable");
+ // Set the initial size of the followon and the followonNext hash to the
+ // number of atoms that we have.
+ _followOnRoots.reserve(range.size());
+ _followOnNexts.reserve(range.size());
+ for (const DefinedAtom *ai : range) {
+ for (const Reference *r : *ai) {
+ if (r->kindNamespace() != lld::Reference::KindNamespace::all ||
+ r->kindValue() != lld::Reference::kindLayoutAfter)
+ continue;
+ const DefinedAtom *targetAtom = dyn_cast<DefinedAtom>(r->target());
+ _followOnNexts[ai] = targetAtom;
+
+ // If we find a followon for the first time, let's make that atom as the
+ // root atom.
+ if (_followOnRoots.count(ai) == 0)
+ _followOnRoots[ai] = ai;
+
+ auto iter = _followOnRoots.find(targetAtom);
+ if (iter == _followOnRoots.end()) {
+ // If the targetAtom is not a root of any chain, let's make the root of
+ // the targetAtom to the root of the current chain.
+
+ // The expression m[i] = m[j] where m is a DenseMap and i != j is not
+ // safe. m[j] returns a reference, which would be invalidated when a
+ // rehashing occurs. If rehashing occurs to make room for m[i], m[j]
+ // becomes invalid, and that invalid reference would be used as the RHS
+ // value of the expression.
+ // Copy the value to workaround.
+ const DefinedAtom *tmp = _followOnRoots[ai];
+ _followOnRoots[targetAtom] = tmp;
+ continue;
+ }
+ if (iter->second == targetAtom) {
+ // If the targetAtom is the root of a chain, the chain becomes part of
+ // the current chain. Rewrite the subchain's root to the current
+ // chain's root.
+ setChainRoot(targetAtom, _followOnRoots[ai]);
+ continue;
+ }
+ // The targetAtom is already a part of a chain. If the current atom is
+ // of size zero, we can insert it in the middle of the chain just
+ // before the target atom, while not breaking other atom's followon
+ // relationships. If it's not, we can only insert the current atom at
+ // the beginning of the chain. All the atoms followed by the target
+ // atom must be of size zero in that case to satisfy the followon
+ // relationships.
+ size_t currentAtomSize = ai->size();
+ if (currentAtomSize == 0) {
+ const DefinedAtom *targetPrevAtom = findAtomFollowedBy(targetAtom);
+ _followOnNexts[targetPrevAtom] = ai;
+ const DefinedAtom *tmp = _followOnRoots[targetPrevAtom];
+ _followOnRoots[ai] = tmp;
+ continue;
+ }
+ if (!checkAllPrevAtomsZeroSize(targetAtom))
+ break;
+ _followOnNexts[ai] = _followOnRoots[targetAtom];
+ setChainRoot(_followOnRoots[targetAtom], _followOnRoots[ai]);
+ }
+ }
+}
+
+/// Build an ordinal override map by traversing the followon chain, and
+/// assigning ordinals to each atom, if the atoms have their ordinals
+/// already assigned skip the atom and move to the next. This is the
+/// main map thats used to sort the atoms while comparing two atoms together
+void
+LayoutPass::buildOrdinalOverrideMap(const File::AtomRange<DefinedAtom> &range) {
+ ScopedTask task(getDefaultDomain(), "LayoutPass::buildOrdinalOverrideMap");
+ uint64_t index = 0;
+ for (const DefinedAtom *ai : range) {
+ const DefinedAtom *atom = ai;
+ if (_ordinalOverrideMap.find(atom) != _ordinalOverrideMap.end())
+ continue;
+ AtomToAtomT::iterator start = _followOnRoots.find(atom);
+ if (start == _followOnRoots.end())
+ continue;
+ for (const DefinedAtom *nextAtom = start->second; nextAtom;
+ nextAtom = _followOnNexts[nextAtom]) {
+ AtomToOrdinalT::iterator pos = _ordinalOverrideMap.find(nextAtom);
+ if (pos == _ordinalOverrideMap.end())
+ _ordinalOverrideMap[nextAtom] = index++;
+ }
+ }
+}
+
+std::vector<LayoutPass::SortKey>
+LayoutPass::decorate(File::AtomRange<DefinedAtom> &atomRange) const {
+ std::vector<SortKey> ret;
+ for (OwningAtomPtr<DefinedAtom> &atom : atomRange.owning_ptrs()) {
+ auto ri = _followOnRoots.find(atom.get());
+ auto oi = _ordinalOverrideMap.find(atom.get());
+ const auto *root = (ri == _followOnRoots.end()) ? atom.get() : ri->second;
+ uint64_t override = (oi == _ordinalOverrideMap.end()) ? 0 : oi->second;
+ ret.push_back(SortKey(std::move(atom), root, override));
+ }
+ return ret;
+}
+
+void LayoutPass::undecorate(File::AtomRange<DefinedAtom> &atomRange,
+ std::vector<SortKey> &keys) const {
+ size_t i = 0;
+ for (SortKey &k : keys)
+ atomRange[i++] = std::move(k._atom);
+}
+
+/// Perform the actual pass
+llvm::Error LayoutPass::perform(SimpleFile &mergedFile) {
+ LLVM_DEBUG(llvm::dbgs() << "******** Laying out atoms:\n");
+ // sort the atoms
+ ScopedTask task(getDefaultDomain(), "LayoutPass");
+ File::AtomRange<DefinedAtom> atomRange = mergedFile.defined();
+
+ // Build follow on tables
+ buildFollowOnTable(atomRange);
+
+ // Check the structure of followon graph if running in debug mode.
+ LLVM_DEBUG(checkFollowonChain(atomRange));
+
+ // Build override maps
+ buildOrdinalOverrideMap(atomRange);
+
+ LLVM_DEBUG({
+ llvm::dbgs() << "unsorted atoms:\n";
+ printDefinedAtoms(atomRange);
+ });
+
+ std::vector<LayoutPass::SortKey> vec = decorate(atomRange);
+ sort(llvm::parallel::par, vec.begin(), vec.end(),
+ [&](const LayoutPass::SortKey &l, const LayoutPass::SortKey &r) -> bool {
+ return compareAtoms(l, r, _customSorter);
+ });
+ LLVM_DEBUG(checkTransitivity(vec, _customSorter));
+ undecorate(atomRange, vec);
+
+ LLVM_DEBUG({
+ llvm::dbgs() << "sorted atoms:\n";
+ printDefinedAtoms(atomRange);
+ });
+
+ LLVM_DEBUG(llvm::dbgs() << "******** Finished laying out atoms\n");
+ return llvm::Error::success();
+}
+
+void addLayoutPass(PassManager &pm, const MachOLinkingContext &ctx) {
+ pm.add(llvm::make_unique<LayoutPass>(
+ ctx.registry(), [&](const DefinedAtom * left, const DefinedAtom * right,
+ bool & leftBeforeRight) ->bool {
+ return ctx.customAtomOrderer(left, right, leftBeforeRight);
+ }));
+}
+
+} // namespace mach_o
+} // namespace lld
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/LayoutPass.h b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/LayoutPass.h
new file mode 100644
index 000000000000..c18777eded0a
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/LayoutPass.h
@@ -0,0 +1,119 @@
+//===------ lib/ReaderWriter/MachO/LayoutPass.h - Handles Layout of atoms -===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_MACHO_LAYOUT_PASS_H
+#define LLD_READER_WRITER_MACHO_LAYOUT_PASS_H
+
+#include "lld/Core/File.h"
+#include "lld/Core/Pass.h"
+#include "lld/Core/Reader.h"
+#include "lld/Core/Simple.h"
+#include "llvm/ADT/DenseMap.h"
+#include <map>
+#include <string>
+#include <vector>
+
+namespace lld {
+class DefinedAtom;
+class SimpleFile;
+
+namespace mach_o {
+
+/// This linker pass does the layout of the atoms. The pass is done after the
+/// order their .o files were found on the command line, then by order of the
+/// atoms (address) in the .o file. But some atoms have a preferred location
+/// in their section (such as pinned to the start or end of the section), so
+/// the sort must take that into account too.
+class LayoutPass : public Pass {
+public:
+ struct SortKey {
+ SortKey(OwningAtomPtr<DefinedAtom> &&atom,
+ const DefinedAtom *root, uint64_t override)
+ : _atom(std::move(atom)), _root(root), _override(override) {}
+ OwningAtomPtr<DefinedAtom> _atom;
+ const DefinedAtom *_root;
+ uint64_t _override;
+
+ // Note, these are only here to appease MSVC bots which didn't like
+ // the same methods being implemented/deleted in OwningAtomPtr.
+ SortKey(SortKey &&key) : _atom(std::move(key._atom)), _root(key._root),
+ _override(key._override) {
+ key._root = nullptr;
+ }
+
+ SortKey &operator=(SortKey &&key) {
+ _atom = std::move(key._atom);
+ _root = key._root;
+ key._root = nullptr;
+ _override = key._override;
+ return *this;
+ }
+
+ private:
+ SortKey(const SortKey &) = delete;
+ void operator=(const SortKey&) = delete;
+ };
+
+ typedef std::function<bool (const DefinedAtom *left, const DefinedAtom *right,
+ bool &leftBeforeRight)> SortOverride;
+
+ LayoutPass(const Registry &registry, SortOverride sorter);
+
+ /// Sorts atoms in mergedFile by content type then by command line order.
+ llvm::Error perform(SimpleFile &mergedFile) override;
+
+ ~LayoutPass() override = default;
+
+private:
+ // Build the followOn atoms chain as specified by the kindLayoutAfter
+ // reference type
+ void buildFollowOnTable(const File::AtomRange<DefinedAtom> &range);
+
+ // Build a map of Atoms to ordinals for sorting the atoms
+ void buildOrdinalOverrideMap(const File::AtomRange<DefinedAtom> &range);
+
+ const Registry &_registry;
+ SortOverride _customSorter;
+
+ typedef llvm::DenseMap<const DefinedAtom *, const DefinedAtom *> AtomToAtomT;
+ typedef llvm::DenseMap<const DefinedAtom *, uint64_t> AtomToOrdinalT;
+
+ // A map to be used to sort atoms. It represents the order of atoms in the
+ // result; if Atom X is mapped to atom Y in this map, X will be located
+ // immediately before Y in the output file. Y might be mapped to another
+ // atom, constructing a follow-on chain. An atom cannot be mapped to more
+ // than one atom unless all but one atom are of size zero.
+ AtomToAtomT _followOnNexts;
+
+ // A map to be used to sort atoms. It's a map from an atom to its root of
+ // follow-on chain. A root atom is mapped to itself. If an atom is not in
+ // _followOnNexts, the atom is not in this map, and vice versa.
+ AtomToAtomT _followOnRoots;
+
+ AtomToOrdinalT _ordinalOverrideMap;
+
+ // Helper methods for buildFollowOnTable().
+ const DefinedAtom *findAtomFollowedBy(const DefinedAtom *targetAtom);
+ bool checkAllPrevAtomsZeroSize(const DefinedAtom *targetAtom);
+
+ void setChainRoot(const DefinedAtom *targetAtom, const DefinedAtom *root);
+
+ std::vector<SortKey> decorate(File::AtomRange<DefinedAtom> &atomRange) const;
+
+ void undecorate(File::AtomRange<DefinedAtom> &atomRange,
+ std::vector<SortKey> &keys) const;
+
+ // Check if the follow-on graph is a correct structure. For debugging only.
+ void checkFollowonChain(const File::AtomRange<DefinedAtom> &range);
+};
+
+} // namespace mach_o
+} // namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_LAYOUT_PASS_H
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
new file mode 100644
index 000000000000..61583963ddd7
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
@@ -0,0 +1,1101 @@
+//===- lib/ReaderWriter/MachO/MachOLinkingContext.cpp ---------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Common/ErrorHandler.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "ArchHandler.h"
+#include "File.h"
+#include "FlatNamespaceFile.h"
+#include "MachONormalizedFile.h"
+#include "MachOPasses.h"
+#include "SectCreateFile.h"
+#include "lld/Common/Driver.h"
+#include "lld/Core/ArchiveLibraryFile.h"
+#include "lld/Core/PassManager.h"
+#include "lld/Core/Reader.h"
+#include "lld/Core/Writer.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/Demangle/Demangle.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/Path.h"
+#include <algorithm>
+
+using lld::mach_o::ArchHandler;
+using lld::mach_o::MachOFile;
+using lld::mach_o::MachODylibFile;
+using namespace llvm::MachO;
+
+namespace lld {
+
+bool MachOLinkingContext::parsePackedVersion(StringRef str, uint32_t &result) {
+ result = 0;
+
+ if (str.empty())
+ return false;
+
+ SmallVector<StringRef, 3> parts;
+ llvm::SplitString(str, parts, ".");
+
+ unsigned long long num;
+ if (llvm::getAsUnsignedInteger(parts[0], 10, num))
+ return true;
+ if (num > 65535)
+ return true;
+ result = num << 16;
+
+ if (parts.size() > 1) {
+ if (llvm::getAsUnsignedInteger(parts[1], 10, num))
+ return true;
+ if (num > 255)
+ return true;
+ result |= (num << 8);
+ }
+
+ if (parts.size() > 2) {
+ if (llvm::getAsUnsignedInteger(parts[2], 10, num))
+ return true;
+ if (num > 255)
+ return true;
+ result |= num;
+ }
+
+ return false;
+}
+
+bool MachOLinkingContext::parsePackedVersion(StringRef str, uint64_t &result) {
+ result = 0;
+
+ if (str.empty())
+ return false;
+
+ SmallVector<StringRef, 5> parts;
+ llvm::SplitString(str, parts, ".");
+
+ unsigned long long num;
+ if (llvm::getAsUnsignedInteger(parts[0], 10, num))
+ return true;
+ if (num > 0xFFFFFF)
+ return true;
+ result = num << 40;
+
+ unsigned Shift = 30;
+ for (StringRef str : llvm::makeArrayRef(parts).slice(1)) {
+ if (llvm::getAsUnsignedInteger(str, 10, num))
+ return true;
+ if (num > 0x3FF)
+ return true;
+ result |= (num << Shift);
+ Shift -= 10;
+ }
+
+ return false;
+}
+
+MachOLinkingContext::ArchInfo MachOLinkingContext::_s_archInfos[] = {
+ { "x86_64", arch_x86_64, true, CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL },
+ { "i386", arch_x86, true, CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL },
+ { "ppc", arch_ppc, false, CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL },
+ { "armv6", arch_armv6, true, CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6 },
+ { "armv7", arch_armv7, true, CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7 },
+ { "armv7s", arch_armv7s, true, CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7S },
+ { "arm64", arch_arm64, true, CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64_ALL },
+ { "", arch_unknown,false, 0, 0 }
+};
+
+MachOLinkingContext::Arch
+MachOLinkingContext::archFromCpuType(uint32_t cputype, uint32_t cpusubtype) {
+ for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
+ if ((info->cputype == cputype) && (info->cpusubtype == cpusubtype))
+ return info->arch;
+ }
+ return arch_unknown;
+}
+
+MachOLinkingContext::Arch
+MachOLinkingContext::archFromName(StringRef archName) {
+ for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
+ if (info->archName.equals(archName))
+ return info->arch;
+ }
+ return arch_unknown;
+}
+
+StringRef MachOLinkingContext::nameFromArch(Arch arch) {
+ for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
+ if (info->arch == arch)
+ return info->archName;
+ }
+ return "<unknown>";
+}
+
+uint32_t MachOLinkingContext::cpuTypeFromArch(Arch arch) {
+ assert(arch != arch_unknown);
+ for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
+ if (info->arch == arch)
+ return info->cputype;
+ }
+ llvm_unreachable("Unknown arch type");
+}
+
+uint32_t MachOLinkingContext::cpuSubtypeFromArch(Arch arch) {
+ assert(arch != arch_unknown);
+ for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
+ if (info->arch == arch)
+ return info->cpusubtype;
+ }
+ llvm_unreachable("Unknown arch type");
+}
+
+bool MachOLinkingContext::isThinObjectFile(StringRef path, Arch &arch) {
+ return mach_o::normalized::isThinObjectFile(path, arch);
+}
+
+bool MachOLinkingContext::sliceFromFatFile(MemoryBufferRef mb, uint32_t &offset,
+ uint32_t &size) {
+ return mach_o::normalized::sliceFromFatFile(mb, _arch, offset, size);
+}
+
+MachOLinkingContext::MachOLinkingContext() {}
+
+MachOLinkingContext::~MachOLinkingContext() {
+ // Atoms are allocated on BumpPtrAllocator's on File's.
+ // As we transfer atoms from one file to another, we need to clear all of the
+ // atoms before we remove any of the BumpPtrAllocator's.
+ auto &nodes = getNodes();
+ for (unsigned i = 0, e = nodes.size(); i != e; ++i) {
+ FileNode *node = dyn_cast<FileNode>(nodes[i].get());
+ if (!node)
+ continue;
+ File *file = node->getFile();
+ file->clearAtoms();
+ }
+}
+
+void MachOLinkingContext::configure(HeaderFileType type, Arch arch, OS os,
+ uint32_t minOSVersion,
+ bool exportDynamicSymbols) {
+ _outputMachOType = type;
+ _arch = arch;
+ _os = os;
+ _osMinVersion = minOSVersion;
+
+ // If min OS not specified on command line, use reasonable defaults.
+ // Note that we only do sensible defaults when emitting something other than
+ // object and preload.
+ if (_outputMachOType != llvm::MachO::MH_OBJECT &&
+ _outputMachOType != llvm::MachO::MH_PRELOAD) {
+ if (minOSVersion == 0) {
+ switch (_arch) {
+ case arch_x86_64:
+ case arch_x86:
+ parsePackedVersion("10.8", _osMinVersion);
+ _os = MachOLinkingContext::OS::macOSX;
+ break;
+ case arch_armv6:
+ case arch_armv7:
+ case arch_armv7s:
+ case arch_arm64:
+ parsePackedVersion("7.0", _osMinVersion);
+ _os = MachOLinkingContext::OS::iOS;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ switch (_outputMachOType) {
+ case llvm::MachO::MH_EXECUTE:
+ // If targeting newer OS, use _main
+ if (minOS("10.8", "6.0")) {
+ _entrySymbolName = "_main";
+ } else {
+ // If targeting older OS, use start (in crt1.o)
+ _entrySymbolName = "start";
+ }
+
+ // __PAGEZERO defaults to 4GB on 64-bit (except for PP64 which lld does not
+ // support) and 4KB on 32-bit.
+ if (is64Bit(_arch)) {
+ _pageZeroSize = 0x100000000;
+ } else {
+ _pageZeroSize = 0x1000;
+ }
+
+ // Initial base address is __PAGEZERO size.
+ _baseAddress = _pageZeroSize;
+
+ // Make PIE by default when targetting newer OSs.
+ switch (os) {
+ case OS::macOSX:
+ if (minOSVersion >= 0x000A0700) // MacOSX 10.7
+ _pie = true;
+ break;
+ case OS::iOS:
+ if (minOSVersion >= 0x00040300) // iOS 4.3
+ _pie = true;
+ break;
+ case OS::iOS_simulator:
+ _pie = true;
+ break;
+ case OS::unknown:
+ break;
+ }
+ setGlobalsAreDeadStripRoots(exportDynamicSymbols);
+ break;
+ case llvm::MachO::MH_DYLIB:
+ setGlobalsAreDeadStripRoots(exportDynamicSymbols);
+ break;
+ case llvm::MachO::MH_BUNDLE:
+ break;
+ case llvm::MachO::MH_OBJECT:
+ _printRemainingUndefines = false;
+ _allowRemainingUndefines = true;
+ break;
+ default:
+ break;
+ }
+
+ // Set default segment page sizes based on arch.
+ if (arch == arch_arm64)
+ _pageSize = 4*4096;
+}
+
+uint32_t MachOLinkingContext::getCPUType() const {
+ return cpuTypeFromArch(_arch);
+}
+
+uint32_t MachOLinkingContext::getCPUSubType() const {
+ return cpuSubtypeFromArch(_arch);
+}
+
+bool MachOLinkingContext::is64Bit(Arch arch) {
+ for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
+ if (info->arch == arch) {
+ return (info->cputype & CPU_ARCH_ABI64);
+ }
+ }
+ // unknown archs are not 64-bit.
+ return false;
+}
+
+bool MachOLinkingContext::isHostEndian(Arch arch) {
+ assert(arch != arch_unknown);
+ for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
+ if (info->arch == arch) {
+ return (info->littleEndian == llvm::sys::IsLittleEndianHost);
+ }
+ }
+ llvm_unreachable("Unknown arch type");
+}
+
+bool MachOLinkingContext::isBigEndian(Arch arch) {
+ assert(arch != arch_unknown);
+ for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
+ if (info->arch == arch) {
+ return ! info->littleEndian;
+ }
+ }
+ llvm_unreachable("Unknown arch type");
+}
+
+bool MachOLinkingContext::is64Bit() const {
+ return is64Bit(_arch);
+}
+
+bool MachOLinkingContext::outputTypeHasEntry() const {
+ switch (_outputMachOType) {
+ case MH_EXECUTE:
+ case MH_DYLINKER:
+ case MH_PRELOAD:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool MachOLinkingContext::needsStubsPass() const {
+ switch (_outputMachOType) {
+ case MH_EXECUTE:
+ return !_outputMachOTypeStatic;
+ case MH_DYLIB:
+ case MH_BUNDLE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool MachOLinkingContext::needsGOTPass() const {
+ // GOT pass not used in -r mode.
+ if (_outputMachOType == MH_OBJECT)
+ return false;
+ // Only some arches use GOT pass.
+ switch (_arch) {
+ case arch_x86_64:
+ case arch_arm64:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool MachOLinkingContext::needsCompactUnwindPass() const {
+ switch (_outputMachOType) {
+ case MH_EXECUTE:
+ case MH_DYLIB:
+ case MH_BUNDLE:
+ return archHandler().needsCompactUnwind();
+ default:
+ return false;
+ }
+}
+
+bool MachOLinkingContext::needsObjCPass() const {
+ // ObjC pass is only needed if any of the inputs were ObjC.
+ return _objcConstraint != objc_unknown;
+}
+
+bool MachOLinkingContext::needsShimPass() const {
+ // Shim pass only used in final executables.
+ if (_outputMachOType == MH_OBJECT)
+ return false;
+ // Only 32-bit arm arches use Shim pass.
+ switch (_arch) {
+ case arch_armv6:
+ case arch_armv7:
+ case arch_armv7s:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool MachOLinkingContext::needsTLVPass() const {
+ switch (_outputMachOType) {
+ case MH_BUNDLE:
+ case MH_EXECUTE:
+ case MH_DYLIB:
+ return true;
+ default:
+ return false;
+ }
+}
+
+StringRef MachOLinkingContext::binderSymbolName() const {
+ return archHandler().stubInfo().binderSymbolName;
+}
+
+bool MachOLinkingContext::minOS(StringRef mac, StringRef iOS) const {
+ uint32_t parsedVersion;
+ switch (_os) {
+ case OS::macOSX:
+ if (parsePackedVersion(mac, parsedVersion))
+ return false;
+ return _osMinVersion >= parsedVersion;
+ case OS::iOS:
+ case OS::iOS_simulator:
+ if (parsePackedVersion(iOS, parsedVersion))
+ return false;
+ return _osMinVersion >= parsedVersion;
+ case OS::unknown:
+ // If we don't know the target, then assume that we don't meet the min OS.
+ // This matches the ld64 behaviour
+ return false;
+ }
+ llvm_unreachable("invalid OS enum");
+}
+
+bool MachOLinkingContext::addEntryPointLoadCommand() const {
+ if ((_outputMachOType == MH_EXECUTE) && !_outputMachOTypeStatic) {
+ return minOS("10.8", "6.0");
+ }
+ return false;
+}
+
+bool MachOLinkingContext::addUnixThreadLoadCommand() const {
+ switch (_outputMachOType) {
+ case MH_EXECUTE:
+ if (_outputMachOTypeStatic)
+ return true;
+ else
+ return !minOS("10.8", "6.0");
+ break;
+ case MH_DYLINKER:
+ case MH_PRELOAD:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool MachOLinkingContext::pathExists(StringRef path) const {
+ if (!_testingFileUsage)
+ return llvm::sys::fs::exists(path.str());
+
+ // Otherwise, we're in test mode: only files explicitly provided on the
+ // command-line exist.
+ std::string key = path.str();
+ std::replace(key.begin(), key.end(), '\\', '/');
+ return _existingPaths.find(key) != _existingPaths.end();
+}
+
+bool MachOLinkingContext::fileExists(StringRef path) const {
+ bool found = pathExists(path);
+ // Log search misses.
+ if (!found)
+ addInputFileNotFound(path);
+
+ // When testing, file is never opened, so logging is done here.
+ if (_testingFileUsage && found)
+ addInputFileDependency(path);
+
+ return found;
+}
+
+void MachOLinkingContext::setSysLibRoots(const StringRefVector &paths) {
+ _syslibRoots = paths;
+}
+
+void MachOLinkingContext::addRpath(StringRef rpath) {
+ _rpaths.push_back(rpath);
+}
+
+void MachOLinkingContext::addModifiedSearchDir(StringRef libPath,
+ bool isSystemPath) {
+ bool addedModifiedPath = false;
+
+ // -syslibroot only applies to absolute paths.
+ if (libPath.startswith("/")) {
+ for (auto syslibRoot : _syslibRoots) {
+ SmallString<256> path(syslibRoot);
+ llvm::sys::path::append(path, libPath);
+ if (pathExists(path)) {
+ _searchDirs.push_back(path.str().copy(_allocator));
+ addedModifiedPath = true;
+ }
+ }
+ }
+
+ if (addedModifiedPath)
+ return;
+
+ // Finally, if only one -syslibroot is given, system paths which aren't in it
+ // get suppressed.
+ if (_syslibRoots.size() != 1 || !isSystemPath) {
+ if (pathExists(libPath)) {
+ _searchDirs.push_back(libPath);
+ }
+ }
+}
+
+void MachOLinkingContext::addFrameworkSearchDir(StringRef fwPath,
+ bool isSystemPath) {
+ bool pathAdded = false;
+
+ // -syslibroot only used with to absolute framework search paths.
+ if (fwPath.startswith("/")) {
+ for (auto syslibRoot : _syslibRoots) {
+ SmallString<256> path(syslibRoot);
+ llvm::sys::path::append(path, fwPath);
+ if (pathExists(path)) {
+ _frameworkDirs.push_back(path.str().copy(_allocator));
+ pathAdded = true;
+ }
+ }
+ }
+ // If fwPath found in any -syslibroot, then done.
+ if (pathAdded)
+ return;
+
+ // If only one -syslibroot, system paths not in that SDK are suppressed.
+ if (isSystemPath && (_syslibRoots.size() == 1))
+ return;
+
+ // Only use raw fwPath if that directory exists.
+ if (pathExists(fwPath))
+ _frameworkDirs.push_back(fwPath);
+}
+
+llvm::Optional<StringRef>
+MachOLinkingContext::searchDirForLibrary(StringRef path,
+ StringRef libName) const {
+ SmallString<256> fullPath;
+ if (libName.endswith(".o")) {
+ // A request ending in .o is special: just search for the file directly.
+ fullPath.assign(path);
+ llvm::sys::path::append(fullPath, libName);
+ if (fileExists(fullPath))
+ return fullPath.str().copy(_allocator);
+ return llvm::None;
+ }
+
+ // Search for dynamic library
+ fullPath.assign(path);
+ llvm::sys::path::append(fullPath, Twine("lib") + libName + ".dylib");
+ if (fileExists(fullPath))
+ return fullPath.str().copy(_allocator);
+
+ // If not, try for a static library
+ fullPath.assign(path);
+ llvm::sys::path::append(fullPath, Twine("lib") + libName + ".a");
+ if (fileExists(fullPath))
+ return fullPath.str().copy(_allocator);
+
+ return llvm::None;
+}
+
+llvm::Optional<StringRef>
+MachOLinkingContext::searchLibrary(StringRef libName) const {
+ SmallString<256> path;
+ for (StringRef dir : searchDirs()) {
+ llvm::Optional<StringRef> searchDir = searchDirForLibrary(dir, libName);
+ if (searchDir)
+ return searchDir;
+ }
+
+ return llvm::None;
+}
+
+llvm::Optional<StringRef>
+MachOLinkingContext::findPathForFramework(StringRef fwName) const{
+ SmallString<256> fullPath;
+ for (StringRef dir : frameworkDirs()) {
+ fullPath.assign(dir);
+ llvm::sys::path::append(fullPath, Twine(fwName) + ".framework", fwName);
+ if (fileExists(fullPath))
+ return fullPath.str().copy(_allocator);
+ }
+
+ return llvm::None;
+}
+
+bool MachOLinkingContext::validateImpl() {
+ // TODO: if -arch not specified, look at arch of first .o file.
+
+ if (_currentVersion && _outputMachOType != MH_DYLIB) {
+ error("-current_version can only be used with dylibs");
+ return false;
+ }
+
+ if (_compatibilityVersion && _outputMachOType != MH_DYLIB) {
+ error("-compatibility_version can only be used with dylibs");
+ return false;
+ }
+
+ if (_deadStrippableDylib && _outputMachOType != MH_DYLIB) {
+ error("-mark_dead_strippable_dylib can only be used with dylibs");
+ return false;
+ }
+
+ if (!_bundleLoader.empty() && outputMachOType() != MH_BUNDLE) {
+ error("-bundle_loader can only be used with Mach-O bundles");
+ return false;
+ }
+
+ // If -exported_symbols_list used, all exported symbols must be defined.
+ if (_exportMode == ExportMode::whiteList) {
+ for (const auto &symbol : _exportedSymbols)
+ addInitialUndefinedSymbol(symbol.getKey());
+ }
+
+ // If -dead_strip, set up initial live symbols.
+ if (deadStrip()) {
+ // Entry point is live.
+ if (outputTypeHasEntry())
+ addDeadStripRoot(entrySymbolName());
+ // Lazy binding helper is live.
+ if (needsStubsPass())
+ addDeadStripRoot(binderSymbolName());
+ // If using -exported_symbols_list, make all exported symbols live.
+ if (_exportMode == ExportMode::whiteList) {
+ setGlobalsAreDeadStripRoots(false);
+ for (const auto &symbol : _exportedSymbols)
+ addDeadStripRoot(symbol.getKey());
+ }
+ }
+
+ addOutputFileDependency(outputPath());
+
+ return true;
+}
+
+void MachOLinkingContext::addPasses(PassManager &pm) {
+ // objc pass should be before layout pass. Otherwise test cases may contain
+ // no atoms which confuses the layout pass.
+ if (needsObjCPass())
+ mach_o::addObjCPass(pm, *this);
+ mach_o::addLayoutPass(pm, *this);
+ if (needsStubsPass())
+ mach_o::addStubsPass(pm, *this);
+ if (needsCompactUnwindPass())
+ mach_o::addCompactUnwindPass(pm, *this);
+ if (needsGOTPass())
+ mach_o::addGOTPass(pm, *this);
+ if (needsTLVPass())
+ mach_o::addTLVPass(pm, *this);
+ if (needsShimPass())
+ mach_o::addShimPass(pm, *this); // Shim pass must run after stubs pass.
+}
+
+Writer &MachOLinkingContext::writer() const {
+ if (!_writer)
+ _writer = createWriterMachO(*this);
+ return *_writer;
+}
+
+ErrorOr<std::unique_ptr<MemoryBuffer>>
+MachOLinkingContext::getMemoryBuffer(StringRef path) {
+ addInputFileDependency(path);
+
+ ErrorOr<std::unique_ptr<MemoryBuffer>> mbOrErr =
+ MemoryBuffer::getFileOrSTDIN(path);
+ if (std::error_code ec = mbOrErr.getError())
+ return ec;
+ std::unique_ptr<MemoryBuffer> mb = std::move(mbOrErr.get());
+
+ // If buffer contains a fat file, find required arch in fat buffer
+ // and switch buffer to point to just that required slice.
+ uint32_t offset;
+ uint32_t size;
+ if (sliceFromFatFile(mb->getMemBufferRef(), offset, size))
+ return MemoryBuffer::getFileSlice(path, size, offset);
+ return std::move(mb);
+}
+
+MachODylibFile* MachOLinkingContext::loadIndirectDylib(StringRef path) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> mbOrErr = getMemoryBuffer(path);
+ if (mbOrErr.getError())
+ return nullptr;
+
+ ErrorOr<std::unique_ptr<File>> fileOrErr =
+ registry().loadFile(std::move(mbOrErr.get()));
+ if (!fileOrErr)
+ return nullptr;
+ std::unique_ptr<File> &file = fileOrErr.get();
+ file->parse();
+ MachODylibFile *result = reinterpret_cast<MachODylibFile *>(file.get());
+ // Node object now owned by _indirectDylibs vector.
+ _indirectDylibs.push_back(std::move(file));
+ return result;
+}
+
+MachODylibFile* MachOLinkingContext::findIndirectDylib(StringRef path) {
+ // See if already loaded.
+ auto pos = _pathToDylibMap.find(path);
+ if (pos != _pathToDylibMap.end())
+ return pos->second;
+
+ // Search -L paths if of the form "libXXX.dylib"
+ std::pair<StringRef, StringRef> split = path.rsplit('/');
+ StringRef leafName = split.second;
+ if (leafName.startswith("lib") && leafName.endswith(".dylib")) {
+ // FIXME: Need to enhance searchLibrary() to only look for .dylib
+ auto libPath = searchLibrary(leafName);
+ if (libPath)
+ return loadIndirectDylib(libPath.getValue());
+ }
+
+ // Try full path with sysroot.
+ for (StringRef sysPath : _syslibRoots) {
+ SmallString<256> fullPath;
+ fullPath.assign(sysPath);
+ llvm::sys::path::append(fullPath, path);
+ if (pathExists(fullPath))
+ return loadIndirectDylib(fullPath);
+ }
+
+ // Try full path.
+ if (pathExists(path)) {
+ return loadIndirectDylib(path);
+ }
+
+ return nullptr;
+}
+
+uint32_t MachOLinkingContext::dylibCurrentVersion(StringRef installName) const {
+ auto pos = _pathToDylibMap.find(installName);
+ if (pos != _pathToDylibMap.end())
+ return pos->second->currentVersion();
+ else
+ return 0x10000; // 1.0
+}
+
+uint32_t MachOLinkingContext::dylibCompatVersion(StringRef installName) const {
+ auto pos = _pathToDylibMap.find(installName);
+ if (pos != _pathToDylibMap.end())
+ return pos->second->compatVersion();
+ else
+ return 0x10000; // 1.0
+}
+
+void MachOLinkingContext::createImplicitFiles(
+ std::vector<std::unique_ptr<File> > &result) {
+ // Add indirect dylibs by asking each linked dylib to add its indirects.
+ // Iterate until no more dylibs get loaded.
+ size_t dylibCount = 0;
+ while (dylibCount != _allDylibs.size()) {
+ dylibCount = _allDylibs.size();
+ for (MachODylibFile *dylib : _allDylibs) {
+ dylib->loadReExportedDylibs([this] (StringRef path) -> MachODylibFile* {
+ return findIndirectDylib(path); });
+ }
+ }
+
+ // Let writer add output type specific extras.
+ writer().createImplicitFiles(result);
+
+ // If undefinedMode is != error, add a FlatNamespaceFile instance. This will
+ // provide a SharedLibraryAtom for symbols that aren't defined elsewhere.
+ if (undefinedMode() != UndefinedMode::error) {
+ result.emplace_back(new mach_o::FlatNamespaceFile(*this));
+ _flatNamespaceFile = result.back().get();
+ }
+}
+
+void MachOLinkingContext::registerDylib(MachODylibFile *dylib,
+ bool upward) const {
+ std::lock_guard<std::mutex> lock(_dylibsMutex);
+
+ if (std::find(_allDylibs.begin(),
+ _allDylibs.end(), dylib) == _allDylibs.end())
+ _allDylibs.push_back(dylib);
+ _pathToDylibMap[dylib->installName()] = dylib;
+ // If path is different than install name, register path too.
+ if (!dylib->path().equals(dylib->installName()))
+ _pathToDylibMap[dylib->path()] = dylib;
+ if (upward)
+ _upwardDylibs.insert(dylib);
+}
+
+bool MachOLinkingContext::isUpwardDylib(StringRef installName) const {
+ for (MachODylibFile *dylib : _upwardDylibs) {
+ if (dylib->installName().equals(installName))
+ return true;
+ }
+ return false;
+}
+
+ArchHandler &MachOLinkingContext::archHandler() const {
+ if (!_archHandler)
+ _archHandler = ArchHandler::create(_arch);
+ return *_archHandler;
+}
+
+void MachOLinkingContext::addSectionAlignment(StringRef seg, StringRef sect,
+ uint16_t align) {
+ SectionAlign entry = { seg, sect, align };
+ _sectAligns.push_back(entry);
+}
+
+void MachOLinkingContext::addSectCreateSection(
+ StringRef seg, StringRef sect,
+ std::unique_ptr<MemoryBuffer> content) {
+
+ if (!_sectCreateFile) {
+ auto sectCreateFile = llvm::make_unique<mach_o::SectCreateFile>();
+ _sectCreateFile = sectCreateFile.get();
+ getNodes().push_back(llvm::make_unique<FileNode>(std::move(sectCreateFile)));
+ }
+
+ assert(_sectCreateFile && "sectcreate file does not exist.");
+ _sectCreateFile->addSection(seg, sect, std::move(content));
+}
+
+bool MachOLinkingContext::sectionAligned(StringRef seg, StringRef sect,
+ uint16_t &align) const {
+ for (const SectionAlign &entry : _sectAligns) {
+ if (seg.equals(entry.segmentName) && sect.equals(entry.sectionName)) {
+ align = entry.align;
+ return true;
+ }
+ }
+ return false;
+}
+
+void MachOLinkingContext::addExportSymbol(StringRef sym) {
+ // Support old crufty export lists with bogus entries.
+ if (sym.endswith(".eh") || sym.startswith(".objc_category_name_")) {
+ llvm::errs() << "warning: ignoring " << sym << " in export list\n";
+ return;
+ }
+ // Only i386 MacOSX uses old ABI, so don't change those.
+ if ((_os != OS::macOSX) || (_arch != arch_x86)) {
+ // ObjC has two differnent ABIs. Be nice and allow one export list work for
+ // both ABIs by renaming symbols.
+ if (sym.startswith(".objc_class_name_")) {
+ std::string abi2className("_OBJC_CLASS_$_");
+ abi2className += sym.substr(17);
+ _exportedSymbols.insert(copy(abi2className));
+ std::string abi2metaclassName("_OBJC_METACLASS_$_");
+ abi2metaclassName += sym.substr(17);
+ _exportedSymbols.insert(copy(abi2metaclassName));
+ return;
+ }
+ }
+
+ // FIXME: Support wildcards.
+ _exportedSymbols.insert(sym);
+}
+
+bool MachOLinkingContext::exportSymbolNamed(StringRef sym) const {
+ switch (_exportMode) {
+ case ExportMode::globals:
+ llvm_unreachable("exportSymbolNamed() should not be called in this mode");
+ break;
+ case ExportMode::whiteList:
+ return _exportedSymbols.count(sym);
+ case ExportMode::blackList:
+ return !_exportedSymbols.count(sym);
+ }
+ llvm_unreachable("_exportMode unknown enum value");
+}
+
+std::string MachOLinkingContext::demangle(StringRef symbolName) const {
+ // Only try to demangle symbols if -demangle on command line
+ if (!demangleSymbols())
+ return symbolName;
+
+ // Only try to demangle symbols that look like C++ symbols
+ if (!symbolName.startswith("__Z"))
+ return symbolName;
+
+ SmallString<256> symBuff;
+ StringRef nullTermSym = Twine(symbolName).toNullTerminatedStringRef(symBuff);
+ // Mach-O has extra leading underscore that needs to be removed.
+ const char *cstr = nullTermSym.data() + 1;
+ int status;
+ char *demangled = llvm::itaniumDemangle(cstr, nullptr, nullptr, &status);
+ if (demangled) {
+ std::string result(demangled);
+ // __cxa_demangle() always uses a malloc'ed buffer to return the result.
+ free(demangled);
+ return result;
+ }
+
+ return symbolName;
+}
+
+static void addDependencyInfoHelper(llvm::raw_fd_ostream *DepInfo,
+ char Opcode, StringRef Path) {
+ if (!DepInfo)
+ return;
+
+ *DepInfo << Opcode;
+ *DepInfo << Path;
+ *DepInfo << '\0';
+}
+
+std::error_code MachOLinkingContext::createDependencyFile(StringRef path) {
+ std::error_code ec;
+ _dependencyInfo = std::unique_ptr<llvm::raw_fd_ostream>(new
+ llvm::raw_fd_ostream(path, ec, llvm::sys::fs::F_None));
+ if (ec) {
+ _dependencyInfo.reset();
+ return ec;
+ }
+
+ addDependencyInfoHelper(_dependencyInfo.get(), 0x00, "lld" /*FIXME*/);
+ return std::error_code();
+}
+
+void MachOLinkingContext::addInputFileDependency(StringRef path) const {
+ addDependencyInfoHelper(_dependencyInfo.get(), 0x10, path);
+}
+
+void MachOLinkingContext::addInputFileNotFound(StringRef path) const {
+ addDependencyInfoHelper(_dependencyInfo.get(), 0x11, path);
+}
+
+void MachOLinkingContext::addOutputFileDependency(StringRef path) const {
+ addDependencyInfoHelper(_dependencyInfo.get(), 0x40, path);
+}
+
+void MachOLinkingContext::appendOrderedSymbol(StringRef symbol,
+ StringRef filename) {
+ // To support sorting static functions which may have the same name in
+ // multiple .o files, _orderFiles maps the symbol name to a vector
+ // of OrderFileNode each of which can specify a file prefix.
+ OrderFileNode info;
+ if (!filename.empty())
+ info.fileFilter = copy(filename);
+ info.order = _orderFileEntries++;
+ _orderFiles[symbol].push_back(info);
+}
+
+bool
+MachOLinkingContext::findOrderOrdinal(const std::vector<OrderFileNode> &nodes,
+ const DefinedAtom *atom,
+ unsigned &ordinal) {
+ const File *objFile = &atom->file();
+ assert(objFile);
+ StringRef objName = objFile->path();
+ std::pair<StringRef, StringRef> dirAndLeaf = objName.rsplit('/');
+ if (!dirAndLeaf.second.empty())
+ objName = dirAndLeaf.second;
+ for (const OrderFileNode &info : nodes) {
+ if (info.fileFilter.empty()) {
+ // Have unprefixed symbol name in order file that matches this atom.
+ ordinal = info.order;
+ return true;
+ }
+ if (info.fileFilter.equals(objName)) {
+ // Have prefixed symbol name in order file that matches atom's path.
+ ordinal = info.order;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool MachOLinkingContext::customAtomOrderer(const DefinedAtom *left,
+ const DefinedAtom *right,
+ bool &leftBeforeRight) const {
+ // No custom sorting if no order file entries.
+ if (!_orderFileEntries)
+ return false;
+
+ // Order files can only order named atoms.
+ StringRef leftName = left->name();
+ StringRef rightName = right->name();
+ if (leftName.empty() || rightName.empty())
+ return false;
+
+ // If neither is in order file list, no custom sorter.
+ auto leftPos = _orderFiles.find(leftName);
+ auto rightPos = _orderFiles.find(rightName);
+ bool leftIsOrdered = (leftPos != _orderFiles.end());
+ bool rightIsOrdered = (rightPos != _orderFiles.end());
+ if (!leftIsOrdered && !rightIsOrdered)
+ return false;
+
+ // There could be multiple symbols with same name but different file prefixes.
+ unsigned leftOrder;
+ unsigned rightOrder;
+ bool foundLeft =
+ leftIsOrdered && findOrderOrdinal(leftPos->getValue(), left, leftOrder);
+ bool foundRight = rightIsOrdered &&
+ findOrderOrdinal(rightPos->getValue(), right, rightOrder);
+ if (!foundLeft && !foundRight)
+ return false;
+
+ // If only one is in order file list, ordered one goes first.
+ if (foundLeft != foundRight)
+ leftBeforeRight = foundLeft;
+ else
+ leftBeforeRight = (leftOrder < rightOrder);
+
+ return true;
+}
+
+static bool isLibrary(const std::unique_ptr<Node> &elem) {
+ if (FileNode *node = dyn_cast<FileNode>(const_cast<Node *>(elem.get()))) {
+ File *file = node->getFile();
+ return isa<SharedLibraryFile>(file) || isa<ArchiveLibraryFile>(file);
+ }
+ return false;
+}
+
+// The darwin linker processes input files in two phases. The first phase
+// links in all object (.o) files in command line order. The second phase
+// links in libraries in command line order.
+// In this function we reorder the input files so that all the object files
+// comes before any library file. We also make a group for the library files
+// so that the Resolver will reiterate over the libraries as long as we find
+// new undefines from libraries.
+void MachOLinkingContext::finalizeInputFiles() {
+ std::vector<std::unique_ptr<Node>> &elements = getNodes();
+ std::stable_sort(elements.begin(), elements.end(),
+ [](const std::unique_ptr<Node> &a,
+ const std::unique_ptr<Node> &b) {
+ return !isLibrary(a) && isLibrary(b);
+ });
+ size_t numLibs = std::count_if(elements.begin(), elements.end(), isLibrary);
+ elements.push_back(llvm::make_unique<GroupEnd>(numLibs));
+}
+
+llvm::Error MachOLinkingContext::handleLoadedFile(File &file) {
+ auto *machoFile = dyn_cast<MachOFile>(&file);
+ if (!machoFile)
+ return llvm::Error::success();
+
+ // Check that the arch of the context matches that of the file.
+ // Also set the arch of the context if it didn't have one.
+ if (_arch == arch_unknown) {
+ _arch = machoFile->arch();
+ } else if (machoFile->arch() != arch_unknown && machoFile->arch() != _arch) {
+ // Archs are different.
+ return llvm::make_error<GenericError>(file.path() +
+ Twine(" cannot be linked due to incompatible architecture"));
+ }
+
+ // Check that the OS of the context matches that of the file.
+ // Also set the OS of the context if it didn't have one.
+ if (_os == OS::unknown) {
+ _os = machoFile->OS();
+ } else if (machoFile->OS() != OS::unknown && machoFile->OS() != _os) {
+ // OSes are different.
+ return llvm::make_error<GenericError>(file.path() +
+ Twine(" cannot be linked due to incompatible operating systems"));
+ }
+
+ // Check that if the objc info exists, that it is compatible with the target
+ // OS.
+ switch (machoFile->objcConstraint()) {
+ case objc_unknown:
+ // The file is not compiled with objc, so skip the checks.
+ break;
+ case objc_gc_only:
+ case objc_supports_gc:
+ llvm_unreachable("GC support should already have thrown an error");
+ case objc_retainReleaseForSimulator:
+ // The file is built with simulator objc, so make sure that the context
+ // is also building with simulator support.
+ if (_os != OS::iOS_simulator)
+ return llvm::make_error<GenericError>(file.path() +
+ Twine(" cannot be linked. It contains ObjC built for the simulator"
+ " while we are linking a non-simulator target"));
+ assert((_objcConstraint == objc_unknown ||
+ _objcConstraint == objc_retainReleaseForSimulator) &&
+ "Must be linking with retain/release for the simulator");
+ _objcConstraint = objc_retainReleaseForSimulator;
+ break;
+ case objc_retainRelease:
+ // The file is built without simulator objc, so make sure that the
+ // context is also building without simulator support.
+ if (_os == OS::iOS_simulator)
+ return llvm::make_error<GenericError>(file.path() +
+ Twine(" cannot be linked. It contains ObjC built for a non-simulator"
+ " target while we are linking a simulator target"));
+ assert((_objcConstraint == objc_unknown ||
+ _objcConstraint == objc_retainRelease) &&
+ "Must be linking with retain/release for a non-simulator target");
+ _objcConstraint = objc_retainRelease;
+ break;
+ }
+
+ // Check that the swift version of the context matches that of the file.
+ // Also set the swift version of the context if it didn't have one.
+ if (!_swiftVersion) {
+ _swiftVersion = machoFile->swiftVersion();
+ } else if (machoFile->swiftVersion() &&
+ machoFile->swiftVersion() != _swiftVersion) {
+ // Swift versions are different.
+ return llvm::make_error<GenericError>("different swift versions");
+ }
+
+ return llvm::Error::success();
+}
+
+} // end namespace lld
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFile.h b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFile.h
new file mode 100644
index 000000000000..7eeb8adbd84f
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFile.h
@@ -0,0 +1,336 @@
+//===- lib/ReaderWriter/MachO/MachONormalizedFile.h -----------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+///
+/// \file These data structures comprise the "normalized" view of
+/// mach-o object files. The normalized view is an in-memory only data structure
+/// which is always in native endianness and pointer size.
+///
+/// The normalized view easily converts to and from YAML using YAML I/O.
+///
+/// The normalized view converts to and from binary mach-o object files using
+/// the writeBinary() and readBinary() functions.
+///
+/// The normalized view converts to and from lld::Atoms using the
+/// normalizedToAtoms() and normalizedFromAtoms().
+///
+/// Overall, the conversion paths available look like:
+///
+/// +---------------+
+/// | binary mach-o |
+/// +---------------+
+/// ^
+/// |
+/// v
+/// +------------+ +------+
+/// | normalized | <-> | yaml |
+/// +------------+ +------+
+/// ^
+/// |
+/// v
+/// +-------+
+/// | Atoms |
+/// +-------+
+///
+
+#ifndef LLD_READER_WRITER_MACHO_NORMALIZE_FILE_H
+#define LLD_READER_WRITER_MACHO_NORMALIZE_FILE_H
+
+#include "DebugInfo.h"
+#include "lld/Common/LLVM.h"
+#include "lld/Core/Error.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/YAMLTraits.h"
+
+using llvm::BumpPtrAllocator;
+using llvm::yaml::Hex64;
+using llvm::yaml::Hex32;
+using llvm::yaml::Hex16;
+using llvm::yaml::Hex8;
+using llvm::yaml::SequenceTraits;
+using llvm::MachO::HeaderFileType;
+using llvm::MachO::BindType;
+using llvm::MachO::RebaseType;
+using llvm::MachO::NListType;
+using llvm::MachO::RelocationInfoType;
+using llvm::MachO::SectionType;
+using llvm::MachO::LoadCommandType;
+using llvm::MachO::ExportSymbolKind;
+using llvm::MachO::DataRegionType;
+
+namespace lld {
+namespace mach_o {
+namespace normalized {
+
+
+/// The real mach-o relocation record is 8-bytes on disk and is
+/// encoded in one of two different bit-field patterns. This
+/// normalized form has the union of all possible fields.
+struct Relocation {
+ Relocation() : offset(0), scattered(false),
+ type(llvm::MachO::GENERIC_RELOC_VANILLA),
+ length(0), pcRel(false), isExtern(false), value(0),
+ symbol(0) { }
+
+ Hex32 offset;
+ bool scattered;
+ RelocationInfoType type;
+ uint8_t length;
+ bool pcRel;
+ bool isExtern;
+ Hex32 value;
+ uint32_t symbol;
+};
+
+/// A typedef so that YAML I/O can treat this vector as a sequence.
+typedef std::vector<Relocation> Relocations;
+
+/// A typedef so that YAML I/O can process the raw bytes in a section.
+typedef std::vector<Hex8> ContentBytes;
+
+/// A typedef so that YAML I/O can treat indirect symbols as a flow sequence.
+typedef std::vector<uint32_t> IndirectSymbols;
+
+/// A typedef so that YAML I/O can encode/decode section attributes.
+LLVM_YAML_STRONG_TYPEDEF(uint32_t, SectionAttr)
+
+/// A typedef so that YAML I/O can encode/decode section alignment.
+LLVM_YAML_STRONG_TYPEDEF(uint16_t, SectionAlignment)
+
+/// Mach-O has a 32-bit and 64-bit section record. This normalized form
+/// can support either kind.
+struct Section {
+ Section() : type(llvm::MachO::S_REGULAR),
+ attributes(0), alignment(1), address(0) { }
+
+ StringRef segmentName;
+ StringRef sectionName;
+ SectionType type;
+ SectionAttr attributes;
+ SectionAlignment alignment;
+ Hex64 address;
+ ArrayRef<uint8_t> content;
+ Relocations relocations;
+ IndirectSymbols indirectSymbols;
+};
+
+
+/// A typedef so that YAML I/O can encode/decode the scope bits of an nlist.
+LLVM_YAML_STRONG_TYPEDEF(uint8_t, SymbolScope)
+
+/// A typedef so that YAML I/O can encode/decode the desc bits of an nlist.
+LLVM_YAML_STRONG_TYPEDEF(uint16_t, SymbolDesc)
+
+/// Mach-O has a 32-bit and 64-bit symbol table entry (nlist), and the symbol
+/// type and scope and mixed in the same n_type field. This normalized form
+/// works for any pointer size and separates out the type and scope.
+struct Symbol {
+ Symbol() : type(llvm::MachO::N_UNDF), scope(0), sect(0), desc(0), value(0) { }
+
+ StringRef name;
+ NListType type;
+ SymbolScope scope;
+ uint8_t sect;
+ SymbolDesc desc;
+ Hex64 value;
+};
+
+/// Check whether the given section type indicates a zero-filled section.
+// FIXME: Utility functions of this kind should probably be moved into
+// llvm/Support.
+inline bool isZeroFillSection(SectionType T) {
+ return (T == llvm::MachO::S_ZEROFILL ||
+ T == llvm::MachO::S_THREAD_LOCAL_ZEROFILL);
+}
+
+/// A typedef so that YAML I/O can (de/en)code the protection bits of a segment.
+LLVM_YAML_STRONG_TYPEDEF(uint32_t, VMProtect)
+
+/// A typedef to hold verions X.Y.X packed into 32-bit xxxx.yy.zz
+LLVM_YAML_STRONG_TYPEDEF(uint32_t, PackedVersion)
+
+/// Segments are only used in normalized final linked images (not in relocatable
+/// object files). They specify how a range of the file is loaded.
+struct Segment {
+ StringRef name;
+ Hex64 address;
+ Hex64 size;
+ VMProtect init_access;
+ VMProtect max_access;
+};
+
+/// Only used in normalized final linked images to specify on which dylibs
+/// it depends.
+struct DependentDylib {
+ StringRef path;
+ LoadCommandType kind;
+ PackedVersion compatVersion;
+ PackedVersion currentVersion;
+};
+
+/// A normalized rebasing entry. Only used in normalized final linked images.
+struct RebaseLocation {
+ Hex32 segOffset;
+ uint8_t segIndex;
+ RebaseType kind;
+};
+
+/// A normalized binding entry. Only used in normalized final linked images.
+struct BindLocation {
+ Hex32 segOffset;
+ uint8_t segIndex;
+ BindType kind;
+ bool canBeNull;
+ int ordinal;
+ StringRef symbolName;
+ Hex64 addend;
+};
+
+/// A typedef so that YAML I/O can encode/decode export flags.
+LLVM_YAML_STRONG_TYPEDEF(uint32_t, ExportFlags)
+
+/// A normalized export entry. Only used in normalized final linked images.
+struct Export {
+ StringRef name;
+ Hex64 offset;
+ ExportSymbolKind kind;
+ ExportFlags flags;
+ Hex32 otherOffset;
+ StringRef otherName;
+};
+
+/// A normalized data-in-code entry.
+struct DataInCode {
+ Hex32 offset;
+ Hex16 length;
+ DataRegionType kind;
+};
+
+/// A typedef so that YAML I/O can encode/decode mach_header.flags.
+LLVM_YAML_STRONG_TYPEDEF(uint32_t, FileFlags)
+
+///
+struct NormalizedFile {
+ MachOLinkingContext::Arch arch = MachOLinkingContext::arch_unknown;
+ HeaderFileType fileType = llvm::MachO::MH_OBJECT;
+ FileFlags flags = 0;
+ std::vector<Segment> segments; // Not used in object files.
+ std::vector<Section> sections;
+
+ // Symbols sorted by kind.
+ std::vector<Symbol> localSymbols;
+ std::vector<Symbol> globalSymbols;
+ std::vector<Symbol> undefinedSymbols;
+ std::vector<Symbol> stabsSymbols;
+
+ // Maps to load commands with no LINKEDIT content (final linked images only).
+ std::vector<DependentDylib> dependentDylibs;
+ StringRef installName; // dylibs only
+ PackedVersion compatVersion = 0; // dylibs only
+ PackedVersion currentVersion = 0; // dylibs only
+ bool hasUUID = false;
+ bool hasMinVersionLoadCommand = false;
+ bool generateDataInCodeLoadCommand = false;
+ std::vector<StringRef> rpaths;
+ Hex64 entryAddress = 0;
+ Hex64 stackSize = 0;
+ MachOLinkingContext::OS os = MachOLinkingContext::OS::unknown;
+ Hex64 sourceVersion = 0;
+ PackedVersion minOSverson = 0;
+ PackedVersion sdkVersion = 0;
+ LoadCommandType minOSVersionKind = (LoadCommandType)0;
+
+ // Maps to load commands with LINKEDIT content (final linked images only).
+ Hex32 pageSize = 0;
+ std::vector<RebaseLocation> rebasingInfo;
+ std::vector<BindLocation> bindingInfo;
+ std::vector<BindLocation> weakBindingInfo;
+ std::vector<BindLocation> lazyBindingInfo;
+ std::vector<Export> exportInfo;
+ std::vector<uint8_t> functionStarts;
+ std::vector<DataInCode> dataInCode;
+
+ // TODO:
+ // code-signature
+ // split-seg-info
+ // function-starts
+
+ // For any allocations in this struct which need to be owned by this struct.
+ BumpPtrAllocator ownedAllocations;
+};
+
+/// Tests if a file is a non-fat mach-o object file.
+bool isThinObjectFile(StringRef path, MachOLinkingContext::Arch &arch);
+
+/// If the buffer is a fat file with the request arch, then this function
+/// returns true with 'offset' and 'size' set to location of the arch slice
+/// within the buffer. Otherwise returns false;
+bool sliceFromFatFile(MemoryBufferRef mb, MachOLinkingContext::Arch arch,
+ uint32_t &offset, uint32_t &size);
+
+/// Reads a mach-o file and produces an in-memory normalized view.
+llvm::Expected<std::unique_ptr<NormalizedFile>>
+readBinary(std::unique_ptr<MemoryBuffer> &mb,
+ const MachOLinkingContext::Arch arch);
+
+/// Takes in-memory normalized view and writes a mach-o object file.
+llvm::Error writeBinary(const NormalizedFile &file, StringRef path);
+
+size_t headerAndLoadCommandsSize(const NormalizedFile &file);
+
+
+/// Parses a yaml encoded mach-o file to produce an in-memory normalized view.
+llvm::Expected<std::unique_ptr<NormalizedFile>>
+readYaml(std::unique_ptr<MemoryBuffer> &mb);
+
+/// Writes a yaml encoded mach-o files given an in-memory normalized view.
+std::error_code writeYaml(const NormalizedFile &file, raw_ostream &out);
+
+llvm::Error
+normalizedObjectToAtoms(MachOFile *file,
+ const NormalizedFile &normalizedFile,
+ bool copyRefs);
+
+llvm::Error
+normalizedDylibToAtoms(MachODylibFile *file,
+ const NormalizedFile &normalizedFile,
+ bool copyRefs);
+
+/// Takes in-memory normalized dylib or object and parses it into lld::File
+llvm::Expected<std::unique_ptr<lld::File>>
+normalizedToAtoms(const NormalizedFile &normalizedFile, StringRef path,
+ bool copyRefs);
+
+/// Takes atoms and generates a normalized macho-o view.
+llvm::Expected<std::unique_ptr<NormalizedFile>>
+normalizedFromAtoms(const lld::File &atomFile, const MachOLinkingContext &ctxt);
+
+
+} // namespace normalized
+
+/// Class for interfacing mach-o yaml files into generic yaml parsing
+class MachOYamlIOTaggedDocumentHandler : public YamlIOTaggedDocumentHandler {
+public:
+ MachOYamlIOTaggedDocumentHandler(MachOLinkingContext::Arch arch)
+ : _arch(arch) { }
+ bool handledDocTag(llvm::yaml::IO &io, const lld::File *&file) const override;
+private:
+ const MachOLinkingContext::Arch _arch;
+};
+
+} // namespace mach_o
+} // namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_NORMALIZE_FILE_H
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
new file mode 100644
index 000000000000..7c2e833c090f
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
@@ -0,0 +1,594 @@
+//===- lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp ---------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+///
+/// \file For mach-o object files, this implementation converts from
+/// mach-o on-disk binary format to in-memory normalized mach-o.
+///
+/// +---------------+
+/// | binary mach-o |
+/// +---------------+
+/// |
+/// |
+/// v
+/// +------------+
+/// | normalized |
+/// +------------+
+
+#include "ArchHandler.h"
+#include "MachONormalizedFile.h"
+#include "MachONormalizedFileBinaryUtils.h"
+#include "lld/Common/LLVM.h"
+#include "lld/Core/Error.h"
+#include "lld/Core/SharedLibraryFile.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/Object/MachO.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <functional>
+#include <system_error>
+
+using namespace llvm::MachO;
+using llvm::object::ExportEntry;
+using llvm::file_magic;
+using llvm::object::MachOObjectFile;
+
+namespace lld {
+namespace mach_o {
+namespace normalized {
+
+// Utility to call a lambda expression on each load command.
+static llvm::Error forEachLoadCommand(
+ StringRef lcRange, unsigned lcCount, bool isBig, bool is64,
+ std::function<bool(uint32_t cmd, uint32_t size, const char *lc)> func) {
+ const char* p = lcRange.begin();
+ for (unsigned i=0; i < lcCount; ++i) {
+ const load_command *lc = reinterpret_cast<const load_command*>(p);
+ load_command lcCopy;
+ const load_command *slc = lc;
+ if (isBig != llvm::sys::IsBigEndianHost) {
+ memcpy(&lcCopy, lc, sizeof(load_command));
+ swapStruct(lcCopy);
+ slc = &lcCopy;
+ }
+ if ( (p + slc->cmdsize) > lcRange.end() )
+ return llvm::make_error<GenericError>("Load command exceeds range");
+
+ if (func(slc->cmd, slc->cmdsize, p))
+ return llvm::Error::success();
+
+ p += slc->cmdsize;
+ }
+
+ return llvm::Error::success();
+}
+
+static std::error_code appendRelocations(Relocations &relocs, StringRef buffer,
+ bool bigEndian,
+ uint32_t reloff, uint32_t nreloc) {
+ if ((reloff + nreloc*8) > buffer.size())
+ return make_error_code(llvm::errc::executable_format_error);
+ const any_relocation_info* relocsArray =
+ reinterpret_cast<const any_relocation_info*>(buffer.begin()+reloff);
+
+ for(uint32_t i=0; i < nreloc; ++i) {
+ relocs.push_back(unpackRelocation(relocsArray[i], bigEndian));
+ }
+ return std::error_code();
+}
+
+static std::error_code
+appendIndirectSymbols(IndirectSymbols &isyms, StringRef buffer, bool isBig,
+ uint32_t istOffset, uint32_t istCount,
+ uint32_t startIndex, uint32_t count) {
+ if ((istOffset + istCount*4) > buffer.size())
+ return make_error_code(llvm::errc::executable_format_error);
+ if (startIndex+count > istCount)
+ return make_error_code(llvm::errc::executable_format_error);
+ const uint8_t *indirectSymbolArray = (const uint8_t *)buffer.data();
+
+ for(uint32_t i=0; i < count; ++i) {
+ isyms.push_back(read32(
+ indirectSymbolArray + (startIndex + i) * sizeof(uint32_t), isBig));
+ }
+ return std::error_code();
+}
+
+
+template <typename T> static T readBigEndian(T t) {
+ if (llvm::sys::IsLittleEndianHost)
+ llvm::sys::swapByteOrder(t);
+ return t;
+}
+
+
+static bool isMachOHeader(const mach_header *mh, bool &is64, bool &isBig) {
+ switch (read32(&mh->magic, false)) {
+ case llvm::MachO::MH_MAGIC:
+ is64 = false;
+ isBig = false;
+ return true;
+ case llvm::MachO::MH_MAGIC_64:
+ is64 = true;
+ isBig = false;
+ return true;
+ case llvm::MachO::MH_CIGAM:
+ is64 = false;
+ isBig = true;
+ return true;
+ case llvm::MachO::MH_CIGAM_64:
+ is64 = true;
+ isBig = true;
+ return true;
+ default:
+ return false;
+ }
+}
+
+
+bool isThinObjectFile(StringRef path, MachOLinkingContext::Arch &arch) {
+ // Try opening and mapping file at path.
+ ErrorOr<std::unique_ptr<MemoryBuffer>> b = MemoryBuffer::getFileOrSTDIN(path);
+ if (b.getError())
+ return false;
+
+ // If file length < 32 it is too small to be mach-o object file.
+ StringRef fileBuffer = b->get()->getBuffer();
+ if (fileBuffer.size() < 32)
+ return false;
+
+ // If file buffer does not start with MH_MAGIC (and variants), not obj file.
+ const mach_header *mh = reinterpret_cast<const mach_header *>(
+ fileBuffer.begin());
+ bool is64, isBig;
+ if (!isMachOHeader(mh, is64, isBig))
+ return false;
+
+ // If not MH_OBJECT, not object file.
+ if (read32(&mh->filetype, isBig) != MH_OBJECT)
+ return false;
+
+ // Lookup up arch from cpu/subtype pair.
+ arch = MachOLinkingContext::archFromCpuType(
+ read32(&mh->cputype, isBig),
+ read32(&mh->cpusubtype, isBig));
+ return true;
+}
+
+bool sliceFromFatFile(MemoryBufferRef mb, MachOLinkingContext::Arch arch,
+ uint32_t &offset, uint32_t &size) {
+ const char *start = mb.getBufferStart();
+ const llvm::MachO::fat_header *fh =
+ reinterpret_cast<const llvm::MachO::fat_header *>(start);
+ if (readBigEndian(fh->magic) != llvm::MachO::FAT_MAGIC)
+ return false;
+ uint32_t nfat_arch = readBigEndian(fh->nfat_arch);
+ const fat_arch *fstart =
+ reinterpret_cast<const fat_arch *>(start + sizeof(fat_header));
+ const fat_arch *fend =
+ reinterpret_cast<const fat_arch *>(start + sizeof(fat_header) +
+ sizeof(fat_arch) * nfat_arch);
+ const uint32_t reqCpuType = MachOLinkingContext::cpuTypeFromArch(arch);
+ const uint32_t reqCpuSubtype = MachOLinkingContext::cpuSubtypeFromArch(arch);
+ for (const fat_arch *fa = fstart; fa < fend; ++fa) {
+ if ((readBigEndian(fa->cputype) == reqCpuType) &&
+ (readBigEndian(fa->cpusubtype) == reqCpuSubtype)) {
+ offset = readBigEndian(fa->offset);
+ size = readBigEndian(fa->size);
+ if ((offset + size) > mb.getBufferSize())
+ return false;
+ return true;
+ }
+ }
+ return false;
+}
+
+/// Reads a mach-o file and produces an in-memory normalized view.
+llvm::Expected<std::unique_ptr<NormalizedFile>>
+readBinary(std::unique_ptr<MemoryBuffer> &mb,
+ const MachOLinkingContext::Arch arch) {
+ // Make empty NormalizedFile.
+ std::unique_ptr<NormalizedFile> f(new NormalizedFile());
+
+ const char *start = mb->getBufferStart();
+ size_t objSize = mb->getBufferSize();
+ const mach_header *mh = reinterpret_cast<const mach_header *>(start);
+
+ uint32_t sliceOffset;
+ uint32_t sliceSize;
+ if (sliceFromFatFile(mb->getMemBufferRef(), arch, sliceOffset, sliceSize)) {
+ start = &start[sliceOffset];
+ objSize = sliceSize;
+ mh = reinterpret_cast<const mach_header *>(start);
+ }
+
+ // Determine endianness and pointer size for mach-o file.
+ bool is64, isBig;
+ if (!isMachOHeader(mh, is64, isBig))
+ return llvm::make_error<GenericError>("File is not a mach-o");
+
+ // Endian swap header, if needed.
+ mach_header headerCopy;
+ const mach_header *smh = mh;
+ if (isBig != llvm::sys::IsBigEndianHost) {
+ memcpy(&headerCopy, mh, sizeof(mach_header));
+ swapStruct(headerCopy);
+ smh = &headerCopy;
+ }
+
+ // Validate head and load commands fit in buffer.
+ const uint32_t lcCount = smh->ncmds;
+ const char *lcStart =
+ start + (is64 ? sizeof(mach_header_64) : sizeof(mach_header));
+ StringRef lcRange(lcStart, smh->sizeofcmds);
+ if (lcRange.end() > (start + objSize))
+ return llvm::make_error<GenericError>("Load commands exceed file size");
+
+ // Get architecture from mach_header.
+ f->arch = MachOLinkingContext::archFromCpuType(smh->cputype, smh->cpusubtype);
+ if (f->arch != arch) {
+ return llvm::make_error<GenericError>(
+ Twine("file is wrong architecture. Expected "
+ "(" + MachOLinkingContext::nameFromArch(arch)
+ + ") found ("
+ + MachOLinkingContext::nameFromArch(f->arch)
+ + ")" ));
+ }
+ // Copy file type and flags
+ f->fileType = HeaderFileType(smh->filetype);
+ f->flags = smh->flags;
+
+
+ // Pre-scan load commands looking for indirect symbol table.
+ uint32_t indirectSymbolTableOffset = 0;
+ uint32_t indirectSymbolTableCount = 0;
+ auto ec = forEachLoadCommand(lcRange, lcCount, isBig, is64,
+ [&](uint32_t cmd, uint32_t size,
+ const char *lc) -> bool {
+ if (cmd == LC_DYSYMTAB) {
+ const dysymtab_command *d = reinterpret_cast<const dysymtab_command*>(lc);
+ indirectSymbolTableOffset = read32(&d->indirectsymoff, isBig);
+ indirectSymbolTableCount = read32(&d->nindirectsyms, isBig);
+ return true;
+ }
+ return false;
+ });
+ if (ec)
+ return std::move(ec);
+
+ // Walk load commands looking for segments/sections and the symbol table.
+ const data_in_code_entry *dataInCode = nullptr;
+ const dyld_info_command *dyldInfo = nullptr;
+ uint32_t dataInCodeSize = 0;
+ ec = forEachLoadCommand(lcRange, lcCount, isBig, is64,
+ [&] (uint32_t cmd, uint32_t size, const char* lc) -> bool {
+ switch(cmd) {
+ case LC_SEGMENT_64:
+ if (is64) {
+ const segment_command_64 *seg =
+ reinterpret_cast<const segment_command_64*>(lc);
+ const unsigned sectionCount = read32(&seg->nsects, isBig);
+ const section_64 *sects = reinterpret_cast<const section_64*>
+ (lc + sizeof(segment_command_64));
+ const unsigned lcSize = sizeof(segment_command_64)
+ + sectionCount*sizeof(section_64);
+ // Verify sections don't extend beyond end of segment load command.
+ if (lcSize > size)
+ return true;
+ for (unsigned i=0; i < sectionCount; ++i) {
+ const section_64 *sect = &sects[i];
+ Section section;
+ section.segmentName = getString16(sect->segname);
+ section.sectionName = getString16(sect->sectname);
+ section.type = (SectionType)(read32(&sect->flags, isBig) &
+ SECTION_TYPE);
+ section.attributes = read32(&sect->flags, isBig) & SECTION_ATTRIBUTES;
+ section.alignment = 1 << read32(&sect->align, isBig);
+ section.address = read64(&sect->addr, isBig);
+ const uint8_t *content =
+ (const uint8_t *)start + read32(&sect->offset, isBig);
+ size_t contentSize = read64(&sect->size, isBig);
+ // Note: this assign() is copying the content bytes. Ideally,
+ // we can use a custom allocator for vector to avoid the copy.
+ section.content = llvm::makeArrayRef(content, contentSize);
+ appendRelocations(section.relocations, mb->getBuffer(), isBig,
+ read32(&sect->reloff, isBig),
+ read32(&sect->nreloc, isBig));
+ if (section.type == S_NON_LAZY_SYMBOL_POINTERS) {
+ appendIndirectSymbols(section.indirectSymbols, mb->getBuffer(),
+ isBig,
+ indirectSymbolTableOffset,
+ indirectSymbolTableCount,
+ read32(&sect->reserved1, isBig),
+ contentSize/4);
+ }
+ f->sections.push_back(section);
+ }
+ }
+ break;
+ case LC_SEGMENT:
+ if (!is64) {
+ const segment_command *seg =
+ reinterpret_cast<const segment_command*>(lc);
+ const unsigned sectionCount = read32(&seg->nsects, isBig);
+ const section *sects = reinterpret_cast<const section*>
+ (lc + sizeof(segment_command));
+ const unsigned lcSize = sizeof(segment_command)
+ + sectionCount*sizeof(section);
+ // Verify sections don't extend beyond end of segment load command.
+ if (lcSize > size)
+ return true;
+ for (unsigned i=0; i < sectionCount; ++i) {
+ const section *sect = &sects[i];
+ Section section;
+ section.segmentName = getString16(sect->segname);
+ section.sectionName = getString16(sect->sectname);
+ section.type = (SectionType)(read32(&sect->flags, isBig) &
+ SECTION_TYPE);
+ section.attributes =
+ read32((const uint8_t *)&sect->flags, isBig) & SECTION_ATTRIBUTES;
+ section.alignment = 1 << read32(&sect->align, isBig);
+ section.address = read32(&sect->addr, isBig);
+ const uint8_t *content =
+ (const uint8_t *)start + read32(&sect->offset, isBig);
+ size_t contentSize = read32(&sect->size, isBig);
+ // Note: this assign() is copying the content bytes. Ideally,
+ // we can use a custom allocator for vector to avoid the copy.
+ section.content = llvm::makeArrayRef(content, contentSize);
+ appendRelocations(section.relocations, mb->getBuffer(), isBig,
+ read32(&sect->reloff, isBig),
+ read32(&sect->nreloc, isBig));
+ if (section.type == S_NON_LAZY_SYMBOL_POINTERS) {
+ appendIndirectSymbols(
+ section.indirectSymbols, mb->getBuffer(), isBig,
+ indirectSymbolTableOffset, indirectSymbolTableCount,
+ read32(&sect->reserved1, isBig), contentSize / 4);
+ }
+ f->sections.push_back(section);
+ }
+ }
+ break;
+ case LC_SYMTAB: {
+ const symtab_command *st = reinterpret_cast<const symtab_command*>(lc);
+ const char *strings = start + read32(&st->stroff, isBig);
+ const uint32_t strSize = read32(&st->strsize, isBig);
+ // Validate string pool and symbol table all in buffer.
+ if (read32((const uint8_t *)&st->stroff, isBig) +
+ read32((const uint8_t *)&st->strsize, isBig) >
+ objSize)
+ return true;
+ if (is64) {
+ const uint32_t symOffset = read32(&st->symoff, isBig);
+ const uint32_t symCount = read32(&st->nsyms, isBig);
+ if ( symOffset+(symCount*sizeof(nlist_64)) > objSize)
+ return true;
+ const nlist_64 *symbols =
+ reinterpret_cast<const nlist_64 *>(start + symOffset);
+ // Convert each nlist_64 to a lld::mach_o::normalized::Symbol.
+ for(uint32_t i=0; i < symCount; ++i) {
+ nlist_64 tempSym;
+ memcpy(&tempSym, &symbols[i], sizeof(nlist_64));
+ const nlist_64 *sin = &tempSym;
+ if (isBig != llvm::sys::IsBigEndianHost)
+ swapStruct(tempSym);
+ Symbol sout;
+ if (sin->n_strx > strSize)
+ return true;
+ sout.name = &strings[sin->n_strx];
+ sout.type = static_cast<NListType>(sin->n_type & (N_STAB|N_TYPE));
+ sout.scope = (sin->n_type & (N_PEXT|N_EXT));
+ sout.sect = sin->n_sect;
+ sout.desc = sin->n_desc;
+ sout.value = sin->n_value;
+ if (sin->n_type & N_STAB)
+ f->stabsSymbols.push_back(sout);
+ else if (sout.type == N_UNDF)
+ f->undefinedSymbols.push_back(sout);
+ else if (sin->n_type & N_EXT)
+ f->globalSymbols.push_back(sout);
+ else
+ f->localSymbols.push_back(sout);
+ }
+ } else {
+ const uint32_t symOffset = read32(&st->symoff, isBig);
+ const uint32_t symCount = read32(&st->nsyms, isBig);
+ if ( symOffset+(symCount*sizeof(nlist)) > objSize)
+ return true;
+ const nlist *symbols =
+ reinterpret_cast<const nlist *>(start + symOffset);
+ // Convert each nlist to a lld::mach_o::normalized::Symbol.
+ for(uint32_t i=0; i < symCount; ++i) {
+ const nlist *sin = &symbols[i];
+ nlist tempSym;
+ if (isBig != llvm::sys::IsBigEndianHost) {
+ tempSym = *sin; swapStruct(tempSym); sin = &tempSym;
+ }
+ Symbol sout;
+ if (sin->n_strx > strSize)
+ return true;
+ sout.name = &strings[sin->n_strx];
+ sout.type = (NListType)(sin->n_type & N_TYPE);
+ sout.scope = (sin->n_type & (N_PEXT|N_EXT));
+ sout.sect = sin->n_sect;
+ sout.desc = sin->n_desc;
+ sout.value = sin->n_value;
+ if (sout.type == N_UNDF)
+ f->undefinedSymbols.push_back(sout);
+ else if (sout.scope == (SymbolScope)N_EXT)
+ f->globalSymbols.push_back(sout);
+ else if (sin->n_type & N_STAB)
+ f->stabsSymbols.push_back(sout);
+ else
+ f->localSymbols.push_back(sout);
+ }
+ }
+ }
+ break;
+ case LC_ID_DYLIB: {
+ const dylib_command *dl = reinterpret_cast<const dylib_command*>(lc);
+ f->installName = lc + read32(&dl->dylib.name, isBig);
+ f->currentVersion = read32(&dl->dylib.current_version, isBig);
+ f->compatVersion = read32(&dl->dylib.compatibility_version, isBig);
+ }
+ break;
+ case LC_DATA_IN_CODE: {
+ const linkedit_data_command *ldc =
+ reinterpret_cast<const linkedit_data_command*>(lc);
+ dataInCode = reinterpret_cast<const data_in_code_entry *>(
+ start + read32(&ldc->dataoff, isBig));
+ dataInCodeSize = read32(&ldc->datasize, isBig);
+ }
+ break;
+ case LC_LOAD_DYLIB:
+ case LC_LOAD_WEAK_DYLIB:
+ case LC_REEXPORT_DYLIB:
+ case LC_LOAD_UPWARD_DYLIB: {
+ const dylib_command *dl = reinterpret_cast<const dylib_command*>(lc);
+ DependentDylib entry;
+ entry.path = lc + read32(&dl->dylib.name, isBig);
+ entry.kind = LoadCommandType(cmd);
+ entry.compatVersion = read32(&dl->dylib.compatibility_version, isBig);
+ entry.currentVersion = read32(&dl->dylib.current_version, isBig);
+ f->dependentDylibs.push_back(entry);
+ }
+ break;
+ case LC_RPATH: {
+ const rpath_command *rpc = reinterpret_cast<const rpath_command *>(lc);
+ f->rpaths.push_back(lc + read32(&rpc->path, isBig));
+ }
+ break;
+ case LC_DYLD_INFO:
+ case LC_DYLD_INFO_ONLY:
+ dyldInfo = reinterpret_cast<const dyld_info_command*>(lc);
+ break;
+ case LC_VERSION_MIN_MACOSX:
+ case LC_VERSION_MIN_IPHONEOS:
+ case LC_VERSION_MIN_WATCHOS:
+ case LC_VERSION_MIN_TVOS:
+ // If we are emitting an object file, then we may take the load command
+ // kind from these commands and pass it on to the output
+ // file.
+ f->minOSVersionKind = (LoadCommandType)cmd;
+ break;
+ }
+ return false;
+ });
+ if (ec)
+ return std::move(ec);
+
+ if (dataInCode) {
+ // Convert on-disk data_in_code_entry array to DataInCode vector.
+ for (unsigned i=0; i < dataInCodeSize/sizeof(data_in_code_entry); ++i) {
+ DataInCode entry;
+ entry.offset = read32(&dataInCode[i].offset, isBig);
+ entry.length = read16(&dataInCode[i].length, isBig);
+ entry.kind =
+ (DataRegionType)read16((const uint8_t *)&dataInCode[i].kind, isBig);
+ f->dataInCode.push_back(entry);
+ }
+ }
+
+ if (dyldInfo) {
+ // If any exports, extract and add to normalized exportInfo vector.
+ if (dyldInfo->export_size) {
+ const uint8_t *trieStart = reinterpret_cast<const uint8_t *>(
+ start + read32(&dyldInfo->export_off, isBig));
+ ArrayRef<uint8_t> trie(trieStart, read32(&dyldInfo->export_size, isBig));
+ Error Err = Error::success();
+ for (const ExportEntry &trieExport : MachOObjectFile::exports(Err, trie)) {
+ Export normExport;
+ normExport.name = trieExport.name().copy(f->ownedAllocations);
+ normExport.offset = trieExport.address();
+ normExport.kind = ExportSymbolKind(trieExport.flags() & EXPORT_SYMBOL_FLAGS_KIND_MASK);
+ normExport.flags = trieExport.flags() & ~EXPORT_SYMBOL_FLAGS_KIND_MASK;
+ normExport.otherOffset = trieExport.other();
+ if (!trieExport.otherName().empty())
+ normExport.otherName = trieExport.otherName().copy(f->ownedAllocations);
+ f->exportInfo.push_back(normExport);
+ }
+ if (Err)
+ return std::move(Err);
+ }
+ }
+
+ return std::move(f);
+}
+
+class MachOObjectReader : public Reader {
+public:
+ MachOObjectReader(MachOLinkingContext &ctx) : _ctx(ctx) {}
+
+ bool canParse(file_magic magic, MemoryBufferRef mb) const override {
+ return (magic == file_magic::macho_object && mb.getBufferSize() > 32);
+ }
+
+ ErrorOr<std::unique_ptr<File>>
+ loadFile(std::unique_ptr<MemoryBuffer> mb,
+ const Registry &registry) const override {
+ std::unique_ptr<File> ret =
+ llvm::make_unique<MachOFile>(std::move(mb), &_ctx);
+ return std::move(ret);
+ }
+
+private:
+ MachOLinkingContext &_ctx;
+};
+
+class MachODylibReader : public Reader {
+public:
+ MachODylibReader(MachOLinkingContext &ctx) : _ctx(ctx) {}
+
+ bool canParse(file_magic magic, MemoryBufferRef mb) const override {
+ switch (magic) {
+ case file_magic::macho_dynamically_linked_shared_lib:
+ case file_magic::macho_dynamically_linked_shared_lib_stub:
+ return mb.getBufferSize() > 32;
+ default:
+ return false;
+ }
+ }
+
+ ErrorOr<std::unique_ptr<File>>
+ loadFile(std::unique_ptr<MemoryBuffer> mb,
+ const Registry &registry) const override {
+ std::unique_ptr<File> ret =
+ llvm::make_unique<MachODylibFile>(std::move(mb), &_ctx);
+ return std::move(ret);
+ }
+
+private:
+ MachOLinkingContext &_ctx;
+};
+
+} // namespace normalized
+} // namespace mach_o
+
+void Registry::addSupportMachOObjects(MachOLinkingContext &ctx) {
+ MachOLinkingContext::Arch arch = ctx.arch();
+ add(std::unique_ptr<Reader>(new mach_o::normalized::MachOObjectReader(ctx)));
+ add(std::unique_ptr<Reader>(new mach_o::normalized::MachODylibReader(ctx)));
+ addKindTable(Reference::KindNamespace::mach_o, ctx.archHandler().kindArch(),
+ ctx.archHandler().kindStrings());
+ add(std::unique_ptr<YamlIOTaggedDocumentHandler>(
+ new mach_o::MachOYamlIOTaggedDocumentHandler(arch)));
+}
+
+
+} // namespace lld
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h
new file mode 100644
index 000000000000..ee9e174b82e0
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h
@@ -0,0 +1,214 @@
+//===- lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h ------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H
+#define LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H
+
+#include "MachONormalizedFile.h"
+#include "lld/Common/LLVM.h"
+#include "lld/Core/Error.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/LEB128.h"
+#include <system_error>
+
+namespace lld {
+namespace mach_o {
+namespace normalized {
+
+class ByteBuffer {
+public:
+ ByteBuffer() : _ostream(_bytes) { }
+
+ void append_byte(uint8_t b) {
+ _ostream << b;
+ }
+ void append_uleb128(uint64_t value) {
+ llvm::encodeULEB128(value, _ostream);
+ }
+ void append_uleb128Fixed(uint64_t value, unsigned byteCount) {
+ unsigned min = llvm::getULEB128Size(value);
+ assert(min <= byteCount);
+ unsigned pad = byteCount - min;
+ llvm::encodeULEB128(value, _ostream, pad);
+ }
+ void append_sleb128(int64_t value) {
+ llvm::encodeSLEB128(value, _ostream);
+ }
+ void append_string(StringRef str) {
+ _ostream << str;
+ append_byte(0);
+ }
+ void align(unsigned alignment) {
+ while ( (_ostream.tell() % alignment) != 0 )
+ append_byte(0);
+ }
+ size_t size() {
+ return _ostream.tell();
+ }
+ const uint8_t *bytes() {
+ return reinterpret_cast<const uint8_t*>(_ostream.str().data());
+ }
+
+private:
+ SmallVector<char, 128> _bytes;
+ // Stream ivar must be after SmallVector ivar to construct properly.
+ llvm::raw_svector_ostream _ostream;
+};
+
+using namespace llvm::support::endian;
+using llvm::sys::getSwappedBytes;
+
+template<typename T>
+static inline uint16_t read16(const T *loc, bool isBig) {
+ assert((uint64_t)loc % alignof(T) == 0 && "invalid pointer alignment");
+ return isBig ? read16be(loc) : read16le(loc);
+}
+
+template<typename T>
+static inline uint32_t read32(const T *loc, bool isBig) {
+ assert((uint64_t)loc % alignof(T) == 0 && "invalid pointer alignment");
+ return isBig ? read32be(loc) : read32le(loc);
+}
+
+template<typename T>
+static inline uint64_t read64(const T *loc, bool isBig) {
+ assert((uint64_t)loc % alignof(T) == 0 && "invalid pointer alignment");
+ return isBig ? read64be(loc) : read64le(loc);
+}
+
+inline void write16(uint8_t *loc, uint16_t value, bool isBig) {
+ if (isBig)
+ write16be(loc, value);
+ else
+ write16le(loc, value);
+}
+
+inline void write32(uint8_t *loc, uint32_t value, bool isBig) {
+ if (isBig)
+ write32be(loc, value);
+ else
+ write32le(loc, value);
+}
+
+inline void write64(uint8_t *loc, uint64_t value, bool isBig) {
+ if (isBig)
+ write64be(loc, value);
+ else
+ write64le(loc, value);
+}
+
+inline uint32_t
+bitFieldExtract(uint32_t value, bool isBigEndianBigField, uint8_t firstBit,
+ uint8_t bitCount) {
+ const uint32_t mask = ((1<<bitCount)-1);
+ const uint8_t shift = isBigEndianBigField ? (32-firstBit-bitCount) : firstBit;
+ return (value >> shift) & mask;
+}
+
+inline void
+bitFieldSet(uint32_t &bits, bool isBigEndianBigField, uint32_t newBits,
+ uint8_t firstBit, uint8_t bitCount) {
+ const uint32_t mask = ((1<<bitCount)-1);
+ assert((newBits & mask) == newBits);
+ const uint8_t shift = isBigEndianBigField ? (32-firstBit-bitCount) : firstBit;
+ bits &= ~(mask << shift);
+ bits |= (newBits << shift);
+}
+
+inline Relocation unpackRelocation(const llvm::MachO::any_relocation_info &r,
+ bool isBigEndian) {
+ uint32_t r0 = read32(&r.r_word0, isBigEndian);
+ uint32_t r1 = read32(&r.r_word1, isBigEndian);
+
+ Relocation result;
+ if (r0 & llvm::MachO::R_SCATTERED) {
+ // scattered relocation record always laid out like big endian bit field
+ result.offset = bitFieldExtract(r0, true, 8, 24);
+ result.scattered = true;
+ result.type = (RelocationInfoType)
+ bitFieldExtract(r0, true, 4, 4);
+ result.length = bitFieldExtract(r0, true, 2, 2);
+ result.pcRel = bitFieldExtract(r0, true, 1, 1);
+ result.isExtern = false;
+ result.value = r1;
+ result.symbol = 0;
+ } else {
+ result.offset = r0;
+ result.scattered = false;
+ result.type = (RelocationInfoType)
+ bitFieldExtract(r1, isBigEndian, 28, 4);
+ result.length = bitFieldExtract(r1, isBigEndian, 25, 2);
+ result.pcRel = bitFieldExtract(r1, isBigEndian, 24, 1);
+ result.isExtern = bitFieldExtract(r1, isBigEndian, 27, 1);
+ result.value = 0;
+ result.symbol = bitFieldExtract(r1, isBigEndian, 0, 24);
+ }
+ return result;
+}
+
+
+inline llvm::MachO::any_relocation_info
+packRelocation(const Relocation &r, bool swap, bool isBigEndian) {
+ uint32_t r0 = 0;
+ uint32_t r1 = 0;
+
+ if (r.scattered) {
+ r1 = r.value;
+ bitFieldSet(r0, true, r.offset, 8, 24);
+ bitFieldSet(r0, true, r.type, 4, 4);
+ bitFieldSet(r0, true, r.length, 2, 2);
+ bitFieldSet(r0, true, r.pcRel, 1, 1);
+ bitFieldSet(r0, true, r.scattered, 0, 1); // R_SCATTERED
+ } else {
+ r0 = r.offset;
+ bitFieldSet(r1, isBigEndian, r.type, 28, 4);
+ bitFieldSet(r1, isBigEndian, r.isExtern, 27, 1);
+ bitFieldSet(r1, isBigEndian, r.length, 25, 2);
+ bitFieldSet(r1, isBigEndian, r.pcRel, 24, 1);
+ bitFieldSet(r1, isBigEndian, r.symbol, 0, 24);
+ }
+
+ llvm::MachO::any_relocation_info result;
+ result.r_word0 = swap ? getSwappedBytes(r0) : r0;
+ result.r_word1 = swap ? getSwappedBytes(r1) : r1;
+ return result;
+}
+
+inline StringRef getString16(const char s[16]) {
+ // The StringRef(const char *) constructor passes the const char * to
+ // strlen(), so we can't use this constructor here, because if there is no
+ // null terminator in s, then strlen() will read past the end of the array.
+ return StringRef(s, strnlen(s, 16));
+}
+
+inline void setString16(StringRef str, char s[16]) {
+ memset(s, 0, 16);
+ memcpy(s, str.begin(), (str.size() > 16) ? 16: str.size());
+}
+
+// Implemented in normalizedToAtoms() and used by normalizedFromAtoms() so
+// that the same table can be used to map mach-o sections to and from
+// DefinedAtom::ContentType.
+void relocatableSectionInfoForContentType(DefinedAtom::ContentType atomType,
+ StringRef &segmentName,
+ StringRef &sectionName,
+ SectionType &sectionType,
+ SectionAttr &sectionAttrs,
+ bool &relocsToDefinedCanBeImplicit);
+
+} // namespace normalized
+} // namespace mach_o
+} // namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
new file mode 100644
index 000000000000..7ef0237e8c36
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
@@ -0,0 +1,1552 @@
+//===- lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp ---------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+///
+/// \file For mach-o object files, this implementation converts normalized
+/// mach-o in memory to mach-o binary on disk.
+///
+/// +---------------+
+/// | binary mach-o |
+/// +---------------+
+/// ^
+/// |
+/// |
+/// +------------+
+/// | normalized |
+/// +------------+
+
+#include "MachONormalizedFile.h"
+#include "MachONormalizedFileBinaryUtils.h"
+#include "lld/Common/LLVM.h"
+#include "lld/Core/Error.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/ilist.h"
+#include "llvm/ADT/ilist_node.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <functional>
+#include <list>
+#include <map>
+#include <system_error>
+
+using namespace llvm::MachO;
+
+namespace lld {
+namespace mach_o {
+namespace normalized {
+
+struct TrieNode; // Forward declaration.
+
+struct TrieEdge : public llvm::ilist_node<TrieEdge> {
+ TrieEdge(StringRef s, TrieNode *node) : _subString(s), _child(node) {}
+
+ StringRef _subString;
+ struct TrieNode *_child;
+};
+
+} // namespace normalized
+} // namespace mach_o
+} // namespace lld
+
+
+namespace llvm {
+using lld::mach_o::normalized::TrieEdge;
+template <>
+struct ilist_alloc_traits<TrieEdge> : ilist_noalloc_traits<TrieEdge> {};
+} // namespace llvm
+
+
+namespace lld {
+namespace mach_o {
+namespace normalized {
+
+struct TrieNode {
+ typedef llvm::ilist<TrieEdge> TrieEdgeList;
+
+ TrieNode(StringRef s)
+ : _cummulativeString(s), _address(0), _flags(0), _other(0),
+ _trieOffset(0), _hasExportInfo(false) {}
+ ~TrieNode() = default;
+
+ void addSymbol(const Export &entry, BumpPtrAllocator &allocator,
+ std::vector<TrieNode *> &allNodes);
+
+ void addOrderedNodes(const Export &entry,
+ std::vector<TrieNode *> &allNodes);
+ bool updateOffset(uint32_t &offset);
+ void appendToByteBuffer(ByteBuffer &out);
+
+private:
+ StringRef _cummulativeString;
+ TrieEdgeList _children;
+ uint64_t _address;
+ uint64_t _flags;
+ uint64_t _other;
+ StringRef _importedName;
+ uint32_t _trieOffset;
+ bool _hasExportInfo;
+ bool _ordered = false;
+};
+
+/// Utility class for writing a mach-o binary file given an in-memory
+/// normalized file.
+class MachOFileLayout {
+public:
+ /// All layout computation is done in the constructor.
+ MachOFileLayout(const NormalizedFile &file);
+
+ /// Returns the final file size as computed in the constructor.
+ size_t size() const;
+
+ // Returns size of the mach_header and load commands.
+ size_t headerAndLoadCommandsSize() const;
+
+ /// Writes the normalized file as a binary mach-o file to the specified
+ /// path. This does not have a stream interface because the generated
+ /// file may need the 'x' bit set.
+ llvm::Error writeBinary(StringRef path);
+
+private:
+ uint32_t loadCommandsSize(uint32_t &count);
+ void buildFileOffsets();
+ void writeMachHeader();
+ llvm::Error writeLoadCommands();
+ void writeSectionContent();
+ void writeRelocations();
+ void writeSymbolTable();
+ void writeRebaseInfo();
+ void writeBindingInfo();
+ void writeLazyBindingInfo();
+ void writeExportInfo();
+ void writeFunctionStartsInfo();
+ void writeDataInCodeInfo();
+ void writeLinkEditContent();
+ void buildLinkEditInfo();
+ void buildRebaseInfo();
+ void buildBindInfo();
+ void buildLazyBindInfo();
+ void buildExportTrie();
+ void computeFunctionStartsSize();
+ void computeDataInCodeSize();
+ void computeSymbolTableSizes();
+ void buildSectionRelocations();
+ void appendSymbols(const std::vector<Symbol> &symbols,
+ uint32_t &symOffset, uint32_t &strOffset);
+ uint32_t indirectSymbolIndex(const Section &sect, uint32_t &index);
+ uint32_t indirectSymbolElementSize(const Section &sect);
+
+ // For use as template parameter to load command methods.
+ struct MachO64Trait {
+ typedef llvm::MachO::segment_command_64 command;
+ typedef llvm::MachO::section_64 section;
+ enum { LC = llvm::MachO::LC_SEGMENT_64 };
+ };
+
+ // For use as template parameter to load command methods.
+ struct MachO32Trait {
+ typedef llvm::MachO::segment_command command;
+ typedef llvm::MachO::section section;
+ enum { LC = llvm::MachO::LC_SEGMENT };
+ };
+
+ template <typename T>
+ llvm::Error writeSingleSegmentLoadCommand(uint8_t *&lc);
+ template <typename T> llvm::Error writeSegmentLoadCommands(uint8_t *&lc);
+
+ uint32_t pointerAlign(uint32_t value);
+ static StringRef dyldPath();
+
+ struct SegExtraInfo {
+ uint32_t fileOffset;
+ uint32_t fileSize;
+ std::vector<const Section*> sections;
+ };
+ typedef std::map<const Segment*, SegExtraInfo> SegMap;
+ struct SectionExtraInfo {
+ uint32_t fileOffset;
+ };
+ typedef std::map<const Section*, SectionExtraInfo> SectionMap;
+
+ const NormalizedFile &_file;
+ std::error_code _ec;
+ uint8_t *_buffer;
+ const bool _is64;
+ const bool _swap;
+ const bool _bigEndianArch;
+ uint64_t _seg1addr;
+ uint32_t _startOfLoadCommands;
+ uint32_t _countOfLoadCommands;
+ uint32_t _endOfLoadCommands;
+ uint32_t _startOfRelocations;
+ uint32_t _startOfFunctionStarts;
+ uint32_t _startOfDataInCode;
+ uint32_t _startOfSymbols;
+ uint32_t _startOfIndirectSymbols;
+ uint32_t _startOfSymbolStrings;
+ uint32_t _endOfSymbolStrings;
+ uint32_t _symbolTableLocalsStartIndex;
+ uint32_t _symbolTableGlobalsStartIndex;
+ uint32_t _symbolTableUndefinesStartIndex;
+ uint32_t _symbolStringPoolSize;
+ uint32_t _symbolTableSize;
+ uint32_t _functionStartsSize;
+ uint32_t _dataInCodeSize;
+ uint32_t _indirectSymbolTableCount;
+ // Used in object file creation only
+ uint32_t _startOfSectionsContent;
+ uint32_t _endOfSectionsContent;
+ // Used in final linked image only
+ uint32_t _startOfLinkEdit;
+ uint32_t _startOfRebaseInfo;
+ uint32_t _endOfRebaseInfo;
+ uint32_t _startOfBindingInfo;
+ uint32_t _endOfBindingInfo;
+ uint32_t _startOfLazyBindingInfo;
+ uint32_t _endOfLazyBindingInfo;
+ uint32_t _startOfExportTrie;
+ uint32_t _endOfExportTrie;
+ uint32_t _endOfLinkEdit;
+ uint64_t _addressOfLinkEdit;
+ SegMap _segInfo;
+ SectionMap _sectInfo;
+ ByteBuffer _rebaseInfo;
+ ByteBuffer _bindingInfo;
+ ByteBuffer _lazyBindingInfo;
+ ByteBuffer _weakBindingInfo;
+ ByteBuffer _exportTrie;
+};
+
+size_t headerAndLoadCommandsSize(const NormalizedFile &file) {
+ MachOFileLayout layout(file);
+ return layout.headerAndLoadCommandsSize();
+}
+
+StringRef MachOFileLayout::dyldPath() {
+ return "/usr/lib/dyld";
+}
+
+uint32_t MachOFileLayout::pointerAlign(uint32_t value) {
+ return llvm::alignTo(value, _is64 ? 8 : 4);
+}
+
+
+size_t MachOFileLayout::headerAndLoadCommandsSize() const {
+ return _endOfLoadCommands;
+}
+
+MachOFileLayout::MachOFileLayout(const NormalizedFile &file)
+ : _file(file),
+ _is64(MachOLinkingContext::is64Bit(file.arch)),
+ _swap(!MachOLinkingContext::isHostEndian(file.arch)),
+ _bigEndianArch(MachOLinkingContext::isBigEndian(file.arch)),
+ _seg1addr(INT64_MAX) {
+ _startOfLoadCommands = _is64 ? sizeof(mach_header_64) : sizeof(mach_header);
+ const size_t segCommandBaseSize =
+ (_is64 ? sizeof(segment_command_64) : sizeof(segment_command));
+ const size_t sectsSize = (_is64 ? sizeof(section_64) : sizeof(section));
+ if (file.fileType == llvm::MachO::MH_OBJECT) {
+ // object files have just one segment load command containing all sections
+ _endOfLoadCommands = _startOfLoadCommands
+ + segCommandBaseSize
+ + file.sections.size() * sectsSize
+ + sizeof(symtab_command);
+ _countOfLoadCommands = 2;
+ if (file.hasMinVersionLoadCommand) {
+ _endOfLoadCommands += sizeof(version_min_command);
+ _countOfLoadCommands++;
+ }
+ if (!_file.functionStarts.empty()) {
+ _endOfLoadCommands += sizeof(linkedit_data_command);
+ _countOfLoadCommands++;
+ }
+ if (_file.generateDataInCodeLoadCommand) {
+ _endOfLoadCommands += sizeof(linkedit_data_command);
+ _countOfLoadCommands++;
+ }
+ // Assign file offsets to each section.
+ _startOfSectionsContent = _endOfLoadCommands;
+ unsigned relocCount = 0;
+ uint64_t offset = _startOfSectionsContent;
+ for (const Section &sect : file.sections) {
+ if (isZeroFillSection(sect.type))
+ _sectInfo[&sect].fileOffset = 0;
+ else {
+ offset = llvm::alignTo(offset, sect.alignment);
+ _sectInfo[&sect].fileOffset = offset;
+ offset += sect.content.size();
+ }
+ relocCount += sect.relocations.size();
+ }
+ _endOfSectionsContent = offset;
+
+ computeSymbolTableSizes();
+ computeFunctionStartsSize();
+ computeDataInCodeSize();
+
+ // Align start of relocations.
+ _startOfRelocations = pointerAlign(_endOfSectionsContent);
+ _startOfFunctionStarts = _startOfRelocations + relocCount * 8;
+ _startOfDataInCode = _startOfFunctionStarts + _functionStartsSize;
+ _startOfSymbols = _startOfDataInCode + _dataInCodeSize;
+ // Add Indirect symbol table.
+ _startOfIndirectSymbols = _startOfSymbols + _symbolTableSize;
+ // Align start of symbol table and symbol strings.
+ _startOfSymbolStrings = _startOfIndirectSymbols
+ + pointerAlign(_indirectSymbolTableCount * sizeof(uint32_t));
+ _endOfSymbolStrings = _startOfSymbolStrings
+ + pointerAlign(_symbolStringPoolSize);
+ _endOfLinkEdit = _endOfSymbolStrings;
+ DEBUG_WITH_TYPE("MachOFileLayout",
+ llvm::dbgs() << "MachOFileLayout()\n"
+ << " startOfLoadCommands=" << _startOfLoadCommands << "\n"
+ << " countOfLoadCommands=" << _countOfLoadCommands << "\n"
+ << " endOfLoadCommands=" << _endOfLoadCommands << "\n"
+ << " startOfRelocations=" << _startOfRelocations << "\n"
+ << " startOfSymbols=" << _startOfSymbols << "\n"
+ << " startOfSymbolStrings=" << _startOfSymbolStrings << "\n"
+ << " endOfSymbolStrings=" << _endOfSymbolStrings << "\n"
+ << " startOfSectionsContent=" << _startOfSectionsContent << "\n"
+ << " endOfSectionsContent=" << _endOfSectionsContent << "\n");
+ } else {
+ // Final linked images have one load command per segment.
+ _endOfLoadCommands = _startOfLoadCommands
+ + loadCommandsSize(_countOfLoadCommands);
+
+ // Assign section file offsets.
+ buildFileOffsets();
+ buildLinkEditInfo();
+
+ // LINKEDIT of final linked images has in order:
+ // rebase info, binding info, lazy binding info, weak binding info,
+ // data-in-code, symbol table, indirect symbol table, symbol table strings.
+ _startOfRebaseInfo = _startOfLinkEdit;
+ _endOfRebaseInfo = _startOfRebaseInfo + _rebaseInfo.size();
+ _startOfBindingInfo = _endOfRebaseInfo;
+ _endOfBindingInfo = _startOfBindingInfo + _bindingInfo.size();
+ _startOfLazyBindingInfo = _endOfBindingInfo;
+ _endOfLazyBindingInfo = _startOfLazyBindingInfo + _lazyBindingInfo.size();
+ _startOfExportTrie = _endOfLazyBindingInfo;
+ _endOfExportTrie = _startOfExportTrie + _exportTrie.size();
+ _startOfFunctionStarts = _endOfExportTrie;
+ _startOfDataInCode = _startOfFunctionStarts + _functionStartsSize;
+ _startOfSymbols = _startOfDataInCode + _dataInCodeSize;
+ _startOfIndirectSymbols = _startOfSymbols + _symbolTableSize;
+ _startOfSymbolStrings = _startOfIndirectSymbols
+ + pointerAlign(_indirectSymbolTableCount * sizeof(uint32_t));
+ _endOfSymbolStrings = _startOfSymbolStrings
+ + pointerAlign(_symbolStringPoolSize);
+ _endOfLinkEdit = _endOfSymbolStrings;
+ DEBUG_WITH_TYPE("MachOFileLayout",
+ llvm::dbgs() << "MachOFileLayout()\n"
+ << " startOfLoadCommands=" << _startOfLoadCommands << "\n"
+ << " countOfLoadCommands=" << _countOfLoadCommands << "\n"
+ << " endOfLoadCommands=" << _endOfLoadCommands << "\n"
+ << " startOfLinkEdit=" << _startOfLinkEdit << "\n"
+ << " startOfRebaseInfo=" << _startOfRebaseInfo << "\n"
+ << " endOfRebaseInfo=" << _endOfRebaseInfo << "\n"
+ << " startOfBindingInfo=" << _startOfBindingInfo << "\n"
+ << " endOfBindingInfo=" << _endOfBindingInfo << "\n"
+ << " startOfLazyBindingInfo=" << _startOfLazyBindingInfo << "\n"
+ << " endOfLazyBindingInfo=" << _endOfLazyBindingInfo << "\n"
+ << " startOfExportTrie=" << _startOfExportTrie << "\n"
+ << " endOfExportTrie=" << _endOfExportTrie << "\n"
+ << " startOfFunctionStarts=" << _startOfFunctionStarts << "\n"
+ << " startOfDataInCode=" << _startOfDataInCode << "\n"
+ << " startOfSymbols=" << _startOfSymbols << "\n"
+ << " startOfSymbolStrings=" << _startOfSymbolStrings << "\n"
+ << " endOfSymbolStrings=" << _endOfSymbolStrings << "\n"
+ << " addressOfLinkEdit=" << _addressOfLinkEdit << "\n");
+ }
+}
+
+uint32_t MachOFileLayout::loadCommandsSize(uint32_t &count) {
+ uint32_t size = 0;
+ count = 0;
+
+ const size_t segCommandSize =
+ (_is64 ? sizeof(segment_command_64) : sizeof(segment_command));
+ const size_t sectionSize = (_is64 ? sizeof(section_64) : sizeof(section));
+
+ // Add LC_SEGMENT for each segment.
+ size += _file.segments.size() * segCommandSize;
+ count += _file.segments.size();
+ // Add section record for each section.
+ size += _file.sections.size() * sectionSize;
+
+ // If creating a dylib, add LC_ID_DYLIB.
+ if (_file.fileType == llvm::MachO::MH_DYLIB) {
+ size += sizeof(dylib_command) + pointerAlign(_file.installName.size() + 1);
+ ++count;
+ }
+
+ // Add LC_DYLD_INFO
+ size += sizeof(dyld_info_command);
+ ++count;
+
+ // Add LC_SYMTAB
+ size += sizeof(symtab_command);
+ ++count;
+
+ // Add LC_DYSYMTAB
+ if (_file.fileType != llvm::MachO::MH_PRELOAD) {
+ size += sizeof(dysymtab_command);
+ ++count;
+ }
+
+ // If main executable add LC_LOAD_DYLINKER
+ if (_file.fileType == llvm::MachO::MH_EXECUTE) {
+ size += pointerAlign(sizeof(dylinker_command) + dyldPath().size()+1);
+ ++count;
+ }
+
+ // Add LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS, LC_VERSION_MIN_WATCHOS,
+ // LC_VERSION_MIN_TVOS
+ if (_file.hasMinVersionLoadCommand) {
+ size += sizeof(version_min_command);
+ ++count;
+ }
+
+ // Add LC_SOURCE_VERSION
+ size += sizeof(source_version_command);
+ ++count;
+
+ // If main executable add LC_MAIN
+ if (_file.fileType == llvm::MachO::MH_EXECUTE) {
+ size += sizeof(entry_point_command);
+ ++count;
+ }
+
+ // Add LC_LOAD_DYLIB for each dependent dylib.
+ for (const DependentDylib &dep : _file.dependentDylibs) {
+ size += sizeof(dylib_command) + pointerAlign(dep.path.size()+1);
+ ++count;
+ }
+
+ // Add LC_RPATH
+ for (const StringRef &path : _file.rpaths) {
+ size += pointerAlign(sizeof(rpath_command) + path.size() + 1);
+ ++count;
+ }
+
+ // Add LC_FUNCTION_STARTS if needed
+ if (!_file.functionStarts.empty()) {
+ size += sizeof(linkedit_data_command);
+ ++count;
+ }
+
+ // Add LC_DATA_IN_CODE if requested. Note, we do encode zero length entries.
+ // FIXME: Zero length entries is only to match ld64. Should we change this?
+ if (_file.generateDataInCodeLoadCommand) {
+ size += sizeof(linkedit_data_command);
+ ++count;
+ }
+
+ return size;
+}
+
+static bool overlaps(const Segment &s1, const Segment &s2) {
+ if (s2.address >= s1.address+s1.size)
+ return false;
+ if (s1.address >= s2.address+s2.size)
+ return false;
+ return true;
+}
+
+static bool overlaps(const Section &s1, const Section &s2) {
+ if (s2.address >= s1.address+s1.content.size())
+ return false;
+ if (s1.address >= s2.address+s2.content.size())
+ return false;
+ return true;
+}
+
+void MachOFileLayout::buildFileOffsets() {
+ // Verify no segments overlap
+ for (const Segment &sg1 : _file.segments) {
+ for (const Segment &sg2 : _file.segments) {
+ if (&sg1 == &sg2)
+ continue;
+ if (overlaps(sg1,sg2)) {
+ _ec = make_error_code(llvm::errc::executable_format_error);
+ return;
+ }
+ }
+ }
+
+ // Verify no sections overlap
+ for (const Section &s1 : _file.sections) {
+ for (const Section &s2 : _file.sections) {
+ if (&s1 == &s2)
+ continue;
+ if (overlaps(s1,s2)) {
+ _ec = make_error_code(llvm::errc::executable_format_error);
+ return;
+ }
+ }
+ }
+
+ // Build side table of extra info about segments and sections.
+ SegExtraInfo t;
+ t.fileOffset = 0;
+ for (const Segment &sg : _file.segments) {
+ _segInfo[&sg] = t;
+ }
+ SectionExtraInfo t2;
+ t2.fileOffset = 0;
+ // Assign sections to segments.
+ for (const Section &s : _file.sections) {
+ _sectInfo[&s] = t2;
+ bool foundSegment = false;
+ for (const Segment &sg : _file.segments) {
+ if (sg.name.equals(s.segmentName)) {
+ if ((s.address >= sg.address)
+ && (s.address+s.content.size() <= sg.address+sg.size)) {
+ _segInfo[&sg].sections.push_back(&s);
+ foundSegment = true;
+ break;
+ }
+ }
+ }
+ if (!foundSegment) {
+ _ec = make_error_code(llvm::errc::executable_format_error);
+ return;
+ }
+ }
+
+ // Assign file offsets.
+ uint32_t fileOffset = 0;
+ DEBUG_WITH_TYPE("MachOFileLayout",
+ llvm::dbgs() << "buildFileOffsets()\n");
+ for (const Segment &sg : _file.segments) {
+ _segInfo[&sg].fileOffset = fileOffset;
+ if ((_seg1addr == INT64_MAX) && sg.init_access)
+ _seg1addr = sg.address;
+ DEBUG_WITH_TYPE("MachOFileLayout",
+ llvm::dbgs() << " segment=" << sg.name
+ << ", fileOffset=" << _segInfo[&sg].fileOffset << "\n");
+
+ uint32_t segFileSize = 0;
+ // A segment that is not zero-fill must use a least one page of disk space.
+ if (sg.init_access)
+ segFileSize = _file.pageSize;
+ for (const Section *s : _segInfo[&sg].sections) {
+ uint32_t sectOffset = s->address - sg.address;
+ uint32_t sectFileSize =
+ isZeroFillSection(s->type) ? 0 : s->content.size();
+ segFileSize = std::max(segFileSize, sectOffset + sectFileSize);
+
+ _sectInfo[s].fileOffset = _segInfo[&sg].fileOffset + sectOffset;
+ DEBUG_WITH_TYPE("MachOFileLayout",
+ llvm::dbgs() << " section=" << s->sectionName
+ << ", fileOffset=" << fileOffset << "\n");
+ }
+
+ // round up all segments to page aligned, except __LINKEDIT
+ if (!sg.name.equals("__LINKEDIT")) {
+ _segInfo[&sg].fileSize = llvm::alignTo(segFileSize, _file.pageSize);
+ fileOffset = llvm::alignTo(fileOffset + segFileSize, _file.pageSize);
+ }
+ _addressOfLinkEdit = sg.address + sg.size;
+ }
+ _startOfLinkEdit = fileOffset;
+}
+
+size_t MachOFileLayout::size() const {
+ return _endOfSymbolStrings;
+}
+
+void MachOFileLayout::writeMachHeader() {
+ auto cpusubtype = MachOLinkingContext::cpuSubtypeFromArch(_file.arch);
+ // dynamic x86 executables on newer OS version should also set the
+ // CPU_SUBTYPE_LIB64 mask in the CPU subtype.
+ // FIXME: Check that this is a dynamic executable, not a static one.
+ if (_file.fileType == llvm::MachO::MH_EXECUTE &&
+ cpusubtype == CPU_SUBTYPE_X86_64_ALL &&
+ _file.os == MachOLinkingContext::OS::macOSX) {
+ uint32_t version;
+ bool failed = MachOLinkingContext::parsePackedVersion("10.5", version);
+ if (!failed && _file.minOSverson >= version)
+ cpusubtype |= CPU_SUBTYPE_LIB64;
+ }
+
+ mach_header *mh = reinterpret_cast<mach_header*>(_buffer);
+ mh->magic = _is64 ? llvm::MachO::MH_MAGIC_64 : llvm::MachO::MH_MAGIC;
+ mh->cputype = MachOLinkingContext::cpuTypeFromArch(_file.arch);
+ mh->cpusubtype = cpusubtype;
+ mh->filetype = _file.fileType;
+ mh->ncmds = _countOfLoadCommands;
+ mh->sizeofcmds = _endOfLoadCommands - _startOfLoadCommands;
+ mh->flags = _file.flags;
+ if (_swap)
+ swapStruct(*mh);
+}
+
+uint32_t MachOFileLayout::indirectSymbolIndex(const Section &sect,
+ uint32_t &index) {
+ if (sect.indirectSymbols.empty())
+ return 0;
+ uint32_t result = index;
+ index += sect.indirectSymbols.size();
+ return result;
+}
+
+uint32_t MachOFileLayout::indirectSymbolElementSize(const Section &sect) {
+ if (sect.indirectSymbols.empty())
+ return 0;
+ if (sect.type != S_SYMBOL_STUBS)
+ return 0;
+ return sect.content.size() / sect.indirectSymbols.size();
+}
+
+template <typename T>
+llvm::Error MachOFileLayout::writeSingleSegmentLoadCommand(uint8_t *&lc) {
+ typename T::command* seg = reinterpret_cast<typename T::command*>(lc);
+ seg->cmd = T::LC;
+ seg->cmdsize = sizeof(typename T::command)
+ + _file.sections.size() * sizeof(typename T::section);
+ uint8_t *next = lc + seg->cmdsize;
+ memset(seg->segname, 0, 16);
+ seg->vmaddr = 0;
+ seg->vmsize = _file.sections.back().address
+ + _file.sections.back().content.size();
+ seg->fileoff = _endOfLoadCommands;
+ seg->filesize = _sectInfo[&_file.sections.back()].fileOffset +
+ _file.sections.back().content.size() -
+ _sectInfo[&_file.sections.front()].fileOffset;
+ seg->maxprot = VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE;
+ seg->initprot = VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE;
+ seg->nsects = _file.sections.size();
+ seg->flags = 0;
+ if (_swap)
+ swapStruct(*seg);
+ typename T::section *sout = reinterpret_cast<typename T::section*>
+ (lc+sizeof(typename T::command));
+ uint32_t relOffset = _startOfRelocations;
+ uint32_t indirectSymRunningIndex = 0;
+ for (const Section &sin : _file.sections) {
+ setString16(sin.sectionName, sout->sectname);
+ setString16(sin.segmentName, sout->segname);
+ sout->addr = sin.address;
+ sout->size = sin.content.size();
+ sout->offset = _sectInfo[&sin].fileOffset;
+ sout->align = llvm::Log2_32(sin.alignment);
+ sout->reloff = sin.relocations.empty() ? 0 : relOffset;
+ sout->nreloc = sin.relocations.size();
+ sout->flags = sin.type | sin.attributes;
+ sout->reserved1 = indirectSymbolIndex(sin, indirectSymRunningIndex);
+ sout->reserved2 = indirectSymbolElementSize(sin);
+ relOffset += sin.relocations.size() * sizeof(any_relocation_info);
+ if (_swap)
+ swapStruct(*sout);
+ ++sout;
+ }
+ lc = next;
+ return llvm::Error::success();
+}
+
+template <typename T>
+llvm::Error MachOFileLayout::writeSegmentLoadCommands(uint8_t *&lc) {
+ uint32_t indirectSymRunningIndex = 0;
+ for (const Segment &seg : _file.segments) {
+ // Link edit has no sections and a custom range of address, so handle it
+ // specially.
+ SegExtraInfo &segInfo = _segInfo[&seg];
+ if (seg.name.equals("__LINKEDIT")) {
+ size_t linkeditSize = _endOfLinkEdit - _startOfLinkEdit;
+ typename T::command* cmd = reinterpret_cast<typename T::command*>(lc);
+ cmd->cmd = T::LC;
+ cmd->cmdsize = sizeof(typename T::command);
+ uint8_t *next = lc + cmd->cmdsize;
+ setString16("__LINKEDIT", cmd->segname);
+ cmd->vmaddr = _addressOfLinkEdit;
+ cmd->vmsize = llvm::alignTo(linkeditSize, _file.pageSize);
+ cmd->fileoff = _startOfLinkEdit;
+ cmd->filesize = linkeditSize;
+ cmd->initprot = seg.init_access;
+ cmd->maxprot = seg.max_access;
+ cmd->nsects = 0;
+ cmd->flags = 0;
+ if (_swap)
+ swapStruct(*cmd);
+ lc = next;
+ continue;
+ }
+ // Write segment command with trailing sections.
+ typename T::command* cmd = reinterpret_cast<typename T::command*>(lc);
+ cmd->cmd = T::LC;
+ cmd->cmdsize = sizeof(typename T::command)
+ + segInfo.sections.size() * sizeof(typename T::section);
+ uint8_t *next = lc + cmd->cmdsize;
+ setString16(seg.name, cmd->segname);
+ cmd->vmaddr = seg.address;
+ cmd->vmsize = seg.size;
+ cmd->fileoff = segInfo.fileOffset;
+ cmd->filesize = segInfo.fileSize;
+ cmd->initprot = seg.init_access;
+ cmd->maxprot = seg.max_access;
+ cmd->nsects = segInfo.sections.size();
+ cmd->flags = 0;
+ if (_swap)
+ swapStruct(*cmd);
+ typename T::section *sect = reinterpret_cast<typename T::section*>
+ (lc+sizeof(typename T::command));
+ for (const Section *section : segInfo.sections) {
+ setString16(section->sectionName, sect->sectname);
+ setString16(section->segmentName, sect->segname);
+ sect->addr = section->address;
+ sect->size = section->content.size();
+ if (isZeroFillSection(section->type))
+ sect->offset = 0;
+ else
+ sect->offset = section->address - seg.address + segInfo.fileOffset;
+ sect->align = llvm::Log2_32(section->alignment);
+ sect->reloff = 0;
+ sect->nreloc = 0;
+ sect->flags = section->type | section->attributes;
+ sect->reserved1 = indirectSymbolIndex(*section, indirectSymRunningIndex);
+ sect->reserved2 = indirectSymbolElementSize(*section);
+ if (_swap)
+ swapStruct(*sect);
+ ++sect;
+ }
+ lc = reinterpret_cast<uint8_t*>(next);
+ }
+ return llvm::Error::success();
+}
+
+static void writeVersionMinLoadCommand(const NormalizedFile &_file,
+ bool _swap,
+ uint8_t *&lc) {
+ if (!_file.hasMinVersionLoadCommand)
+ return;
+ version_min_command *vm = reinterpret_cast<version_min_command*>(lc);
+ switch (_file.os) {
+ case MachOLinkingContext::OS::unknown:
+ vm->cmd = _file.minOSVersionKind;
+ vm->cmdsize = sizeof(version_min_command);
+ vm->version = _file.minOSverson;
+ vm->sdk = 0;
+ break;
+ case MachOLinkingContext::OS::macOSX:
+ vm->cmd = LC_VERSION_MIN_MACOSX;
+ vm->cmdsize = sizeof(version_min_command);
+ vm->version = _file.minOSverson;
+ vm->sdk = _file.sdkVersion;
+ break;
+ case MachOLinkingContext::OS::iOS:
+ case MachOLinkingContext::OS::iOS_simulator:
+ vm->cmd = LC_VERSION_MIN_IPHONEOS;
+ vm->cmdsize = sizeof(version_min_command);
+ vm->version = _file.minOSverson;
+ vm->sdk = _file.sdkVersion;
+ break;
+ }
+ if (_swap)
+ swapStruct(*vm);
+ lc += sizeof(version_min_command);
+}
+
+llvm::Error MachOFileLayout::writeLoadCommands() {
+ uint8_t *lc = &_buffer[_startOfLoadCommands];
+ if (_file.fileType == llvm::MachO::MH_OBJECT) {
+ // Object files have one unnamed segment which holds all sections.
+ if (_is64) {
+ if (auto ec = writeSingleSegmentLoadCommand<MachO64Trait>(lc))
+ return ec;
+ } else {
+ if (auto ec = writeSingleSegmentLoadCommand<MachO32Trait>(lc))
+ return ec;
+ }
+ // Add LC_SYMTAB with symbol table info
+ symtab_command* st = reinterpret_cast<symtab_command*>(lc);
+ st->cmd = LC_SYMTAB;
+ st->cmdsize = sizeof(symtab_command);
+ st->symoff = _startOfSymbols;
+ st->nsyms = _file.stabsSymbols.size() + _file.localSymbols.size() +
+ _file.globalSymbols.size() + _file.undefinedSymbols.size();
+ st->stroff = _startOfSymbolStrings;
+ st->strsize = _endOfSymbolStrings - _startOfSymbolStrings;
+ if (_swap)
+ swapStruct(*st);
+ lc += sizeof(symtab_command);
+
+ // Add LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS,
+ // LC_VERSION_MIN_WATCHOS, LC_VERSION_MIN_TVOS
+ writeVersionMinLoadCommand(_file, _swap, lc);
+
+ // Add LC_FUNCTION_STARTS if needed.
+ if (_functionStartsSize != 0) {
+ linkedit_data_command* dl = reinterpret_cast<linkedit_data_command*>(lc);
+ dl->cmd = LC_FUNCTION_STARTS;
+ dl->cmdsize = sizeof(linkedit_data_command);
+ dl->dataoff = _startOfFunctionStarts;
+ dl->datasize = _functionStartsSize;
+ if (_swap)
+ swapStruct(*dl);
+ lc += sizeof(linkedit_data_command);
+ }
+
+ // Add LC_DATA_IN_CODE if requested.
+ if (_file.generateDataInCodeLoadCommand) {
+ linkedit_data_command* dl = reinterpret_cast<linkedit_data_command*>(lc);
+ dl->cmd = LC_DATA_IN_CODE;
+ dl->cmdsize = sizeof(linkedit_data_command);
+ dl->dataoff = _startOfDataInCode;
+ dl->datasize = _dataInCodeSize;
+ if (_swap)
+ swapStruct(*dl);
+ lc += sizeof(linkedit_data_command);
+ }
+ } else {
+ // Final linked images have sections under segments.
+ if (_is64) {
+ if (auto ec = writeSegmentLoadCommands<MachO64Trait>(lc))
+ return ec;
+ } else {
+ if (auto ec = writeSegmentLoadCommands<MachO32Trait>(lc))
+ return ec;
+ }
+
+ // Add LC_ID_DYLIB command for dynamic libraries.
+ if (_file.fileType == llvm::MachO::MH_DYLIB) {
+ dylib_command *dc = reinterpret_cast<dylib_command*>(lc);
+ StringRef path = _file.installName;
+ uint32_t size = sizeof(dylib_command) + pointerAlign(path.size() + 1);
+ dc->cmd = LC_ID_DYLIB;
+ dc->cmdsize = size;
+ dc->dylib.name = sizeof(dylib_command); // offset
+ // needs to be some constant value different than the one in LC_LOAD_DYLIB
+ dc->dylib.timestamp = 1;
+ dc->dylib.current_version = _file.currentVersion;
+ dc->dylib.compatibility_version = _file.compatVersion;
+ if (_swap)
+ swapStruct(*dc);
+ memcpy(lc + sizeof(dylib_command), path.begin(), path.size());
+ lc[sizeof(dylib_command) + path.size()] = '\0';
+ lc += size;
+ }
+
+ // Add LC_DYLD_INFO_ONLY.
+ dyld_info_command* di = reinterpret_cast<dyld_info_command*>(lc);
+ di->cmd = LC_DYLD_INFO_ONLY;
+ di->cmdsize = sizeof(dyld_info_command);
+ di->rebase_off = _rebaseInfo.size() ? _startOfRebaseInfo : 0;
+ di->rebase_size = _rebaseInfo.size();
+ di->bind_off = _bindingInfo.size() ? _startOfBindingInfo : 0;
+ di->bind_size = _bindingInfo.size();
+ di->weak_bind_off = 0;
+ di->weak_bind_size = 0;
+ di->lazy_bind_off = _lazyBindingInfo.size() ? _startOfLazyBindingInfo : 0;
+ di->lazy_bind_size = _lazyBindingInfo.size();
+ di->export_off = _exportTrie.size() ? _startOfExportTrie : 0;
+ di->export_size = _exportTrie.size();
+ if (_swap)
+ swapStruct(*di);
+ lc += sizeof(dyld_info_command);
+
+ // Add LC_SYMTAB with symbol table info.
+ symtab_command* st = reinterpret_cast<symtab_command*>(lc);
+ st->cmd = LC_SYMTAB;
+ st->cmdsize = sizeof(symtab_command);
+ st->symoff = _startOfSymbols;
+ st->nsyms = _file.stabsSymbols.size() + _file.localSymbols.size() +
+ _file.globalSymbols.size() + _file.undefinedSymbols.size();
+ st->stroff = _startOfSymbolStrings;
+ st->strsize = _endOfSymbolStrings - _startOfSymbolStrings;
+ if (_swap)
+ swapStruct(*st);
+ lc += sizeof(symtab_command);
+
+ // Add LC_DYSYMTAB
+ if (_file.fileType != llvm::MachO::MH_PRELOAD) {
+ dysymtab_command* dst = reinterpret_cast<dysymtab_command*>(lc);
+ dst->cmd = LC_DYSYMTAB;
+ dst->cmdsize = sizeof(dysymtab_command);
+ dst->ilocalsym = _symbolTableLocalsStartIndex;
+ dst->nlocalsym = _file.stabsSymbols.size() +
+ _file.localSymbols.size();
+ dst->iextdefsym = _symbolTableGlobalsStartIndex;
+ dst->nextdefsym = _file.globalSymbols.size();
+ dst->iundefsym = _symbolTableUndefinesStartIndex;
+ dst->nundefsym = _file.undefinedSymbols.size();
+ dst->tocoff = 0;
+ dst->ntoc = 0;
+ dst->modtaboff = 0;
+ dst->nmodtab = 0;
+ dst->extrefsymoff = 0;
+ dst->nextrefsyms = 0;
+ dst->indirectsymoff = _startOfIndirectSymbols;
+ dst->nindirectsyms = _indirectSymbolTableCount;
+ dst->extreloff = 0;
+ dst->nextrel = 0;
+ dst->locreloff = 0;
+ dst->nlocrel = 0;
+ if (_swap)
+ swapStruct(*dst);
+ lc += sizeof(dysymtab_command);
+ }
+
+ // If main executable, add LC_LOAD_DYLINKER
+ if (_file.fileType == llvm::MachO::MH_EXECUTE) {
+ // Build LC_LOAD_DYLINKER load command.
+ uint32_t size=pointerAlign(sizeof(dylinker_command)+dyldPath().size()+1);
+ dylinker_command* dl = reinterpret_cast<dylinker_command*>(lc);
+ dl->cmd = LC_LOAD_DYLINKER;
+ dl->cmdsize = size;
+ dl->name = sizeof(dylinker_command); // offset
+ if (_swap)
+ swapStruct(*dl);
+ memcpy(lc+sizeof(dylinker_command), dyldPath().data(), dyldPath().size());
+ lc[sizeof(dylinker_command)+dyldPath().size()] = '\0';
+ lc += size;
+ }
+
+ // Add LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS, LC_VERSION_MIN_WATCHOS,
+ // LC_VERSION_MIN_TVOS
+ writeVersionMinLoadCommand(_file, _swap, lc);
+
+ // Add LC_SOURCE_VERSION
+ {
+ // Note, using a temporary here to appease UB as we may not be aligned
+ // enough for a struct containing a uint64_t when emitting a 32-bit binary
+ source_version_command sv;
+ sv.cmd = LC_SOURCE_VERSION;
+ sv.cmdsize = sizeof(source_version_command);
+ sv.version = _file.sourceVersion;
+ if (_swap)
+ swapStruct(sv);
+ memcpy(lc, &sv, sizeof(source_version_command));
+ lc += sizeof(source_version_command);
+ }
+
+ // If main executable, add LC_MAIN.
+ if (_file.fileType == llvm::MachO::MH_EXECUTE) {
+ // Build LC_MAIN load command.
+ // Note, using a temporary here to appease UB as we may not be aligned
+ // enough for a struct containing a uint64_t when emitting a 32-bit binary
+ entry_point_command ep;
+ ep.cmd = LC_MAIN;
+ ep.cmdsize = sizeof(entry_point_command);
+ ep.entryoff = _file.entryAddress - _seg1addr;
+ ep.stacksize = _file.stackSize;
+ if (_swap)
+ swapStruct(ep);
+ memcpy(lc, &ep, sizeof(entry_point_command));
+ lc += sizeof(entry_point_command);
+ }
+
+ // Add LC_LOAD_DYLIB commands
+ for (const DependentDylib &dep : _file.dependentDylibs) {
+ dylib_command* dc = reinterpret_cast<dylib_command*>(lc);
+ uint32_t size = sizeof(dylib_command) + pointerAlign(dep.path.size()+1);
+ dc->cmd = dep.kind;
+ dc->cmdsize = size;
+ dc->dylib.name = sizeof(dylib_command); // offset
+ // needs to be some constant value different than the one in LC_ID_DYLIB
+ dc->dylib.timestamp = 2;
+ dc->dylib.current_version = dep.currentVersion;
+ dc->dylib.compatibility_version = dep.compatVersion;
+ if (_swap)
+ swapStruct(*dc);
+ memcpy(lc+sizeof(dylib_command), dep.path.begin(), dep.path.size());
+ lc[sizeof(dylib_command)+dep.path.size()] = '\0';
+ lc += size;
+ }
+
+ // Add LC_RPATH
+ for (const StringRef &path : _file.rpaths) {
+ rpath_command *rpc = reinterpret_cast<rpath_command *>(lc);
+ uint32_t size = pointerAlign(sizeof(rpath_command) + path.size() + 1);
+ rpc->cmd = LC_RPATH;
+ rpc->cmdsize = size;
+ rpc->path = sizeof(rpath_command); // offset
+ if (_swap)
+ swapStruct(*rpc);
+ memcpy(lc+sizeof(rpath_command), path.begin(), path.size());
+ lc[sizeof(rpath_command)+path.size()] = '\0';
+ lc += size;
+ }
+
+ // Add LC_FUNCTION_STARTS if needed.
+ if (_functionStartsSize != 0) {
+ linkedit_data_command* dl = reinterpret_cast<linkedit_data_command*>(lc);
+ dl->cmd = LC_FUNCTION_STARTS;
+ dl->cmdsize = sizeof(linkedit_data_command);
+ dl->dataoff = _startOfFunctionStarts;
+ dl->datasize = _functionStartsSize;
+ if (_swap)
+ swapStruct(*dl);
+ lc += sizeof(linkedit_data_command);
+ }
+
+ // Add LC_DATA_IN_CODE if requested.
+ if (_file.generateDataInCodeLoadCommand) {
+ linkedit_data_command* dl = reinterpret_cast<linkedit_data_command*>(lc);
+ dl->cmd = LC_DATA_IN_CODE;
+ dl->cmdsize = sizeof(linkedit_data_command);
+ dl->dataoff = _startOfDataInCode;
+ dl->datasize = _dataInCodeSize;
+ if (_swap)
+ swapStruct(*dl);
+ lc += sizeof(linkedit_data_command);
+ }
+ }
+ return llvm::Error::success();
+}
+
+void MachOFileLayout::writeSectionContent() {
+ for (const Section &s : _file.sections) {
+ // Copy all section content to output buffer.
+ if (isZeroFillSection(s.type))
+ continue;
+ if (s.content.empty())
+ continue;
+ uint32_t offset = _sectInfo[&s].fileOffset;
+ uint8_t *p = &_buffer[offset];
+ memcpy(p, &s.content[0], s.content.size());
+ p += s.content.size();
+ }
+}
+
+void MachOFileLayout::writeRelocations() {
+ uint32_t relOffset = _startOfRelocations;
+ for (Section sect : _file.sections) {
+ for (Relocation r : sect.relocations) {
+ any_relocation_info* rb = reinterpret_cast<any_relocation_info*>(
+ &_buffer[relOffset]);
+ *rb = packRelocation(r, _swap, _bigEndianArch);
+ relOffset += sizeof(any_relocation_info);
+ }
+ }
+}
+
+void MachOFileLayout::appendSymbols(const std::vector<Symbol> &symbols,
+ uint32_t &symOffset, uint32_t &strOffset) {
+ for (const Symbol &sym : symbols) {
+ if (_is64) {
+ nlist_64* nb = reinterpret_cast<nlist_64*>(&_buffer[symOffset]);
+ nb->n_strx = strOffset - _startOfSymbolStrings;
+ nb->n_type = sym.type | sym.scope;
+ nb->n_sect = sym.sect;
+ nb->n_desc = sym.desc;
+ nb->n_value = sym.value;
+ if (_swap)
+ swapStruct(*nb);
+ symOffset += sizeof(nlist_64);
+ } else {
+ nlist* nb = reinterpret_cast<nlist*>(&_buffer[symOffset]);
+ nb->n_strx = strOffset - _startOfSymbolStrings;
+ nb->n_type = sym.type | sym.scope;
+ nb->n_sect = sym.sect;
+ nb->n_desc = sym.desc;
+ nb->n_value = sym.value;
+ if (_swap)
+ swapStruct(*nb);
+ symOffset += sizeof(nlist);
+ }
+ memcpy(&_buffer[strOffset], sym.name.begin(), sym.name.size());
+ strOffset += sym.name.size();
+ _buffer[strOffset++] ='\0'; // Strings in table have nul terminator.
+ }
+}
+
+void MachOFileLayout::writeFunctionStartsInfo() {
+ if (!_functionStartsSize)
+ return;
+ memcpy(&_buffer[_startOfFunctionStarts], _file.functionStarts.data(),
+ _functionStartsSize);
+}
+
+void MachOFileLayout::writeDataInCodeInfo() {
+ uint32_t offset = _startOfDataInCode;
+ for (const DataInCode &entry : _file.dataInCode) {
+ data_in_code_entry *dst = reinterpret_cast<data_in_code_entry*>(
+ &_buffer[offset]);
+ dst->offset = entry.offset;
+ dst->length = entry.length;
+ dst->kind = entry.kind;
+ if (_swap)
+ swapStruct(*dst);
+ offset += sizeof(data_in_code_entry);
+ }
+}
+
+void MachOFileLayout::writeSymbolTable() {
+ // Write symbol table and symbol strings in parallel.
+ uint32_t symOffset = _startOfSymbols;
+ uint32_t strOffset = _startOfSymbolStrings;
+ // Reserve n_strx offset of zero to mean no name.
+ _buffer[strOffset++] = ' ';
+ _buffer[strOffset++] = '\0';
+ appendSymbols(_file.stabsSymbols, symOffset, strOffset);
+ appendSymbols(_file.localSymbols, symOffset, strOffset);
+ appendSymbols(_file.globalSymbols, symOffset, strOffset);
+ appendSymbols(_file.undefinedSymbols, symOffset, strOffset);
+ // Write indirect symbol table array.
+ uint32_t *indirects = reinterpret_cast<uint32_t*>
+ (&_buffer[_startOfIndirectSymbols]);
+ if (_file.fileType == llvm::MachO::MH_OBJECT) {
+ // Object files have sections in same order as input normalized file.
+ for (const Section &section : _file.sections) {
+ for (uint32_t index : section.indirectSymbols) {
+ if (_swap)
+ *indirects++ = llvm::sys::getSwappedBytes(index);
+ else
+ *indirects++ = index;
+ }
+ }
+ } else {
+ // Final linked images must sort sections from normalized file.
+ for (const Segment &seg : _file.segments) {
+ SegExtraInfo &segInfo = _segInfo[&seg];
+ for (const Section *section : segInfo.sections) {
+ for (uint32_t index : section->indirectSymbols) {
+ if (_swap)
+ *indirects++ = llvm::sys::getSwappedBytes(index);
+ else
+ *indirects++ = index;
+ }
+ }
+ }
+ }
+}
+
+void MachOFileLayout::writeRebaseInfo() {
+ memcpy(&_buffer[_startOfRebaseInfo], _rebaseInfo.bytes(), _rebaseInfo.size());
+}
+
+void MachOFileLayout::writeBindingInfo() {
+ memcpy(&_buffer[_startOfBindingInfo],
+ _bindingInfo.bytes(), _bindingInfo.size());
+}
+
+void MachOFileLayout::writeLazyBindingInfo() {
+ memcpy(&_buffer[_startOfLazyBindingInfo],
+ _lazyBindingInfo.bytes(), _lazyBindingInfo.size());
+}
+
+void MachOFileLayout::writeExportInfo() {
+ memcpy(&_buffer[_startOfExportTrie], _exportTrie.bytes(), _exportTrie.size());
+}
+
+void MachOFileLayout::buildLinkEditInfo() {
+ buildRebaseInfo();
+ buildBindInfo();
+ buildLazyBindInfo();
+ buildExportTrie();
+ computeSymbolTableSizes();
+ computeFunctionStartsSize();
+ computeDataInCodeSize();
+}
+
+void MachOFileLayout::buildSectionRelocations() {
+
+}
+
+void MachOFileLayout::buildRebaseInfo() {
+ // TODO: compress rebasing info.
+ for (const RebaseLocation& entry : _file.rebasingInfo) {
+ _rebaseInfo.append_byte(REBASE_OPCODE_SET_TYPE_IMM | entry.kind);
+ _rebaseInfo.append_byte(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
+ | entry.segIndex);
+ _rebaseInfo.append_uleb128(entry.segOffset);
+ _rebaseInfo.append_uleb128(REBASE_OPCODE_DO_REBASE_IMM_TIMES | 1);
+ }
+ _rebaseInfo.append_byte(REBASE_OPCODE_DONE);
+ _rebaseInfo.align(_is64 ? 8 : 4);
+}
+
+void MachOFileLayout::buildBindInfo() {
+ // TODO: compress bind info.
+ uint64_t lastAddend = 0;
+ int lastOrdinal = 0x80000000;
+ StringRef lastSymbolName;
+ BindType lastType = (BindType)0;
+ Hex32 lastSegOffset = ~0U;
+ uint8_t lastSegIndex = (uint8_t)~0U;
+ for (const BindLocation& entry : _file.bindingInfo) {
+ if (entry.ordinal != lastOrdinal) {
+ if (entry.ordinal <= 0)
+ _bindingInfo.append_byte(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM |
+ (entry.ordinal & BIND_IMMEDIATE_MASK));
+ else if (entry.ordinal <= BIND_IMMEDIATE_MASK)
+ _bindingInfo.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM |
+ entry.ordinal);
+ else {
+ _bindingInfo.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
+ _bindingInfo.append_uleb128(entry.ordinal);
+ }
+ lastOrdinal = entry.ordinal;
+ }
+
+ if (lastSymbolName != entry.symbolName) {
+ _bindingInfo.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM);
+ _bindingInfo.append_string(entry.symbolName);
+ lastSymbolName = entry.symbolName;
+ }
+
+ if (lastType != entry.kind) {
+ _bindingInfo.append_byte(BIND_OPCODE_SET_TYPE_IMM | entry.kind);
+ lastType = entry.kind;
+ }
+
+ if (lastSegIndex != entry.segIndex || lastSegOffset != entry.segOffset) {
+ _bindingInfo.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
+ | entry.segIndex);
+ _bindingInfo.append_uleb128(entry.segOffset);
+ lastSegIndex = entry.segIndex;
+ lastSegOffset = entry.segOffset;
+ }
+ if (entry.addend != lastAddend) {
+ _bindingInfo.append_byte(BIND_OPCODE_SET_ADDEND_SLEB);
+ _bindingInfo.append_sleb128(entry.addend);
+ lastAddend = entry.addend;
+ }
+ _bindingInfo.append_byte(BIND_OPCODE_DO_BIND);
+ }
+ _bindingInfo.append_byte(BIND_OPCODE_DONE);
+ _bindingInfo.align(_is64 ? 8 : 4);
+}
+
+void MachOFileLayout::buildLazyBindInfo() {
+ for (const BindLocation& entry : _file.lazyBindingInfo) {
+ _lazyBindingInfo.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
+ | entry.segIndex);
+ _lazyBindingInfo.append_uleb128(entry.segOffset);
+ if (entry.ordinal <= 0)
+ _lazyBindingInfo.append_byte(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM |
+ (entry.ordinal & BIND_IMMEDIATE_MASK));
+ else if (entry.ordinal <= BIND_IMMEDIATE_MASK)
+ _lazyBindingInfo.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM |
+ entry.ordinal);
+ else {
+ _lazyBindingInfo.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
+ _lazyBindingInfo.append_uleb128(entry.ordinal);
+ }
+ // FIXME: We need to | the opcode here with flags.
+ _lazyBindingInfo.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM);
+ _lazyBindingInfo.append_string(entry.symbolName);
+ _lazyBindingInfo.append_byte(BIND_OPCODE_DO_BIND);
+ _lazyBindingInfo.append_byte(BIND_OPCODE_DONE);
+ }
+ _lazyBindingInfo.align(_is64 ? 8 : 4);
+}
+
+void TrieNode::addSymbol(const Export& entry,
+ BumpPtrAllocator &allocator,
+ std::vector<TrieNode*> &allNodes) {
+ StringRef partialStr = entry.name.drop_front(_cummulativeString.size());
+ for (TrieEdge &edge : _children) {
+ StringRef edgeStr = edge._subString;
+ if (partialStr.startswith(edgeStr)) {
+ // Already have matching edge, go down that path.
+ edge._child->addSymbol(entry, allocator, allNodes);
+ return;
+ }
+ // See if string has commmon prefix with existing edge.
+ for (int n=edgeStr.size()-1; n > 0; --n) {
+ if (partialStr.substr(0, n).equals(edgeStr.substr(0, n))) {
+ // Splice in new node: was A -> C, now A -> B -> C
+ StringRef bNodeStr = edge._child->_cummulativeString;
+ bNodeStr = bNodeStr.drop_back(edgeStr.size()-n).copy(allocator);
+ auto *bNode = new (allocator) TrieNode(bNodeStr);
+ allNodes.push_back(bNode);
+ TrieNode* cNode = edge._child;
+ StringRef abEdgeStr = edgeStr.substr(0,n).copy(allocator);
+ StringRef bcEdgeStr = edgeStr.substr(n).copy(allocator);
+ DEBUG_WITH_TYPE("trie-builder", llvm::dbgs()
+ << "splice in TrieNode('" << bNodeStr
+ << "') between edge '"
+ << abEdgeStr << "' and edge='"
+ << bcEdgeStr<< "'\n");
+ TrieEdge& abEdge = edge;
+ abEdge._subString = abEdgeStr;
+ abEdge._child = bNode;
+ auto *bcEdge = new (allocator) TrieEdge(bcEdgeStr, cNode);
+ bNode->_children.insert(bNode->_children.end(), bcEdge);
+ bNode->addSymbol(entry, allocator, allNodes);
+ return;
+ }
+ }
+ }
+ if (entry.flags & EXPORT_SYMBOL_FLAGS_REEXPORT) {
+ assert(entry.otherOffset != 0);
+ }
+ if (entry.flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER) {
+ assert(entry.otherOffset != 0);
+ }
+ // No commonality with any existing child, make a new edge.
+ auto *newNode = new (allocator) TrieNode(entry.name.copy(allocator));
+ auto *newEdge = new (allocator) TrieEdge(partialStr, newNode);
+ _children.insert(_children.end(), newEdge);
+ DEBUG_WITH_TYPE("trie-builder", llvm::dbgs()
+ << "new TrieNode('" << entry.name << "') with edge '"
+ << partialStr << "' from node='"
+ << _cummulativeString << "'\n");
+ newNode->_address = entry.offset;
+ newNode->_flags = entry.flags | entry.kind;
+ newNode->_other = entry.otherOffset;
+ if ((entry.flags & EXPORT_SYMBOL_FLAGS_REEXPORT) && !entry.otherName.empty())
+ newNode->_importedName = entry.otherName.copy(allocator);
+ newNode->_hasExportInfo = true;
+ allNodes.push_back(newNode);
+}
+
+void TrieNode::addOrderedNodes(const Export& entry,
+ std::vector<TrieNode*> &orderedNodes) {
+ if (!_ordered) {
+ orderedNodes.push_back(this);
+ _ordered = true;
+ }
+
+ StringRef partialStr = entry.name.drop_front(_cummulativeString.size());
+ for (TrieEdge &edge : _children) {
+ StringRef edgeStr = edge._subString;
+ if (partialStr.startswith(edgeStr)) {
+ // Already have matching edge, go down that path.
+ edge._child->addOrderedNodes(entry, orderedNodes);
+ return;
+ }
+ }
+}
+
+bool TrieNode::updateOffset(uint32_t& offset) {
+ uint32_t nodeSize = 1; // Length when no export info
+ if (_hasExportInfo) {
+ if (_flags & EXPORT_SYMBOL_FLAGS_REEXPORT) {
+ nodeSize = llvm::getULEB128Size(_flags);
+ nodeSize += llvm::getULEB128Size(_other); // Other contains ordinal.
+ nodeSize += _importedName.size();
+ ++nodeSize; // Trailing zero in imported name.
+ } else {
+ nodeSize = llvm::getULEB128Size(_flags) + llvm::getULEB128Size(_address);
+ if (_flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER)
+ nodeSize += llvm::getULEB128Size(_other);
+ }
+ // Overall node size so far is uleb128 of export info + actual export info.
+ nodeSize += llvm::getULEB128Size(nodeSize);
+ }
+ // Compute size of all child edges.
+ ++nodeSize; // Byte for number of chidren.
+ for (TrieEdge &edge : _children) {
+ nodeSize += edge._subString.size() + 1 // String length.
+ + llvm::getULEB128Size(edge._child->_trieOffset); // Offset len.
+ }
+ // On input, 'offset' is new prefered location for this node.
+ bool result = (_trieOffset != offset);
+ // Store new location in node object for use by parents.
+ _trieOffset = offset;
+ // Update offset for next iteration.
+ offset += nodeSize;
+ // Return true if _trieOffset was changed.
+ return result;
+}
+
+void TrieNode::appendToByteBuffer(ByteBuffer &out) {
+ if (_hasExportInfo) {
+ if (_flags & EXPORT_SYMBOL_FLAGS_REEXPORT) {
+ if (!_importedName.empty()) {
+ // nodes with re-export info: size, flags, ordinal, import-name
+ uint32_t nodeSize = llvm::getULEB128Size(_flags)
+ + llvm::getULEB128Size(_other)
+ + _importedName.size() + 1;
+ assert(nodeSize < 256);
+ out.append_byte(nodeSize);
+ out.append_uleb128(_flags);
+ out.append_uleb128(_other);
+ out.append_string(_importedName);
+ } else {
+ // nodes without re-export info: size, flags, ordinal, empty-string
+ uint32_t nodeSize = llvm::getULEB128Size(_flags)
+ + llvm::getULEB128Size(_other) + 1;
+ assert(nodeSize < 256);
+ out.append_byte(nodeSize);
+ out.append_uleb128(_flags);
+ out.append_uleb128(_other);
+ out.append_byte(0);
+ }
+ } else if ( _flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER ) {
+ // Nodes with export info: size, flags, address, other
+ uint32_t nodeSize = llvm::getULEB128Size(_flags)
+ + llvm::getULEB128Size(_address)
+ + llvm::getULEB128Size(_other);
+ assert(nodeSize < 256);
+ out.append_byte(nodeSize);
+ out.append_uleb128(_flags);
+ out.append_uleb128(_address);
+ out.append_uleb128(_other);
+ } else {
+ // Nodes with export info: size, flags, address
+ uint32_t nodeSize = llvm::getULEB128Size(_flags)
+ + llvm::getULEB128Size(_address);
+ assert(nodeSize < 256);
+ out.append_byte(nodeSize);
+ out.append_uleb128(_flags);
+ out.append_uleb128(_address);
+ }
+ } else {
+ // Node with no export info.
+ uint32_t nodeSize = 0;
+ out.append_byte(nodeSize);
+ }
+ // Add number of children.
+ assert(_children.size() < 256);
+ out.append_byte(_children.size());
+ // Append each child edge substring and node offset.
+ for (TrieEdge &edge : _children) {
+ out.append_string(edge._subString);
+ out.append_uleb128(edge._child->_trieOffset);
+ }
+}
+
+void MachOFileLayout::buildExportTrie() {
+ if (_file.exportInfo.empty())
+ return;
+
+ // For all temporary strings and objects used building trie.
+ BumpPtrAllocator allocator;
+
+ // Build trie of all exported symbols.
+ auto *rootNode = new (allocator) TrieNode(StringRef());
+ std::vector<TrieNode*> allNodes;
+ allNodes.reserve(_file.exportInfo.size()*2);
+ allNodes.push_back(rootNode);
+ for (const Export& entry : _file.exportInfo) {
+ rootNode->addSymbol(entry, allocator, allNodes);
+ }
+
+ std::vector<TrieNode*> orderedNodes;
+ orderedNodes.reserve(allNodes.size());
+
+ for (const Export& entry : _file.exportInfo)
+ rootNode->addOrderedNodes(entry, orderedNodes);
+
+ // Assign each node in the vector an offset in the trie stream, iterating
+ // until all uleb128 sizes have stabilized.
+ bool more;
+ do {
+ uint32_t offset = 0;
+ more = false;
+ for (TrieNode* node : orderedNodes) {
+ if (node->updateOffset(offset))
+ more = true;
+ }
+ } while (more);
+
+ // Serialize trie to ByteBuffer.
+ for (TrieNode* node : orderedNodes) {
+ node->appendToByteBuffer(_exportTrie);
+ }
+ _exportTrie.align(_is64 ? 8 : 4);
+}
+
+void MachOFileLayout::computeSymbolTableSizes() {
+ // MachO symbol tables have three ranges: locals, globals, and undefines
+ const size_t nlistSize = (_is64 ? sizeof(nlist_64) : sizeof(nlist));
+ _symbolTableSize = nlistSize * (_file.stabsSymbols.size()
+ + _file.localSymbols.size()
+ + _file.globalSymbols.size()
+ + _file.undefinedSymbols.size());
+ // Always reserve 1-byte for the empty string and 1-byte for its terminator.
+ _symbolStringPoolSize = 2;
+ for (const Symbol &sym : _file.stabsSymbols) {
+ _symbolStringPoolSize += (sym.name.size()+1);
+ }
+ for (const Symbol &sym : _file.localSymbols) {
+ _symbolStringPoolSize += (sym.name.size()+1);
+ }
+ for (const Symbol &sym : _file.globalSymbols) {
+ _symbolStringPoolSize += (sym.name.size()+1);
+ }
+ for (const Symbol &sym : _file.undefinedSymbols) {
+ _symbolStringPoolSize += (sym.name.size()+1);
+ }
+ _symbolTableLocalsStartIndex = 0;
+ _symbolTableGlobalsStartIndex = _file.stabsSymbols.size() +
+ _file.localSymbols.size();
+ _symbolTableUndefinesStartIndex = _symbolTableGlobalsStartIndex
+ + _file.globalSymbols.size();
+
+ _indirectSymbolTableCount = 0;
+ for (const Section &sect : _file.sections) {
+ _indirectSymbolTableCount += sect.indirectSymbols.size();
+ }
+}
+
+void MachOFileLayout::computeFunctionStartsSize() {
+ _functionStartsSize = _file.functionStarts.size();
+}
+
+void MachOFileLayout::computeDataInCodeSize() {
+ _dataInCodeSize = _file.dataInCode.size() * sizeof(data_in_code_entry);
+}
+
+void MachOFileLayout::writeLinkEditContent() {
+ if (_file.fileType == llvm::MachO::MH_OBJECT) {
+ writeRelocations();
+ writeFunctionStartsInfo();
+ writeDataInCodeInfo();
+ writeSymbolTable();
+ } else {
+ writeRebaseInfo();
+ writeBindingInfo();
+ writeLazyBindingInfo();
+ // TODO: add weak binding info
+ writeExportInfo();
+ writeFunctionStartsInfo();
+ writeDataInCodeInfo();
+ writeSymbolTable();
+ }
+}
+
+llvm::Error MachOFileLayout::writeBinary(StringRef path) {
+ // Check for pending error from constructor.
+ if (_ec)
+ return llvm::errorCodeToError(_ec);
+ // Create FileOutputBuffer with calculated size.
+ unsigned flags = 0;
+ if (_file.fileType != llvm::MachO::MH_OBJECT)
+ flags = llvm::FileOutputBuffer::F_executable;
+ Expected<std::unique_ptr<llvm::FileOutputBuffer>> fobOrErr =
+ llvm::FileOutputBuffer::create(path, size(), flags);
+ if (Error E = fobOrErr.takeError())
+ return E;
+ std::unique_ptr<llvm::FileOutputBuffer> &fob = *fobOrErr;
+ // Write content.
+ _buffer = fob->getBufferStart();
+ writeMachHeader();
+ if (auto ec = writeLoadCommands())
+ return ec;
+ writeSectionContent();
+ writeLinkEditContent();
+ if (Error E = fob->commit())
+ return E;
+
+ return llvm::Error::success();
+}
+
+/// Takes in-memory normalized view and writes a mach-o object file.
+llvm::Error writeBinary(const NormalizedFile &file, StringRef path) {
+ MachOFileLayout layout(file);
+ return layout.writeBinary(path);
+}
+
+} // namespace normalized
+} // namespace mach_o
+} // namespace lld
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
new file mode 100644
index 000000000000..e93ca86c3164
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
@@ -0,0 +1,1657 @@
+//===- lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp ------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+///
+/// \file Converts from in-memory Atoms to in-memory normalized mach-o.
+///
+/// +------------+
+/// | normalized |
+/// +------------+
+/// ^
+/// |
+/// |
+/// +-------+
+/// | Atoms |
+/// +-------+
+
+#include "ArchHandler.h"
+#include "DebugInfo.h"
+#include "MachONormalizedFile.h"
+#include "MachONormalizedFileBinaryUtils.h"
+#include "lld/Common/LLVM.h"
+#include "lld/Core/Error.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+#include <map>
+#include <system_error>
+#include <unordered_set>
+
+using llvm::StringRef;
+using llvm::isa;
+using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
+using namespace lld;
+
+namespace {
+
+struct AtomInfo {
+ const DefinedAtom *atom;
+ uint64_t offsetInSection;
+};
+
+struct SectionInfo {
+ SectionInfo(StringRef seg, StringRef sect, SectionType type,
+ const MachOLinkingContext &ctxt, uint32_t attr,
+ bool relocsToDefinedCanBeImplicit);
+
+ StringRef segmentName;
+ StringRef sectionName;
+ SectionType type;
+ uint32_t attributes;
+ uint64_t address;
+ uint64_t size;
+ uint16_t alignment;
+
+ /// If this is set, the any relocs in this section which point to defined
+ /// addresses can be implicitly generated. This is the case for the
+ /// __eh_frame section where references to the function can be implicit if the
+ /// function is defined.
+ bool relocsToDefinedCanBeImplicit;
+
+
+ std::vector<AtomInfo> atomsAndOffsets;
+ uint32_t normalizedSectionIndex;
+ uint32_t finalSectionIndex;
+};
+
+SectionInfo::SectionInfo(StringRef sg, StringRef sct, SectionType t,
+ const MachOLinkingContext &ctxt, uint32_t attrs,
+ bool relocsToDefinedCanBeImplicit)
+ : segmentName(sg), sectionName(sct), type(t), attributes(attrs),
+ address(0), size(0), alignment(1),
+ relocsToDefinedCanBeImplicit(relocsToDefinedCanBeImplicit),
+ normalizedSectionIndex(0), finalSectionIndex(0) {
+ uint16_t align = 1;
+ if (ctxt.sectionAligned(segmentName, sectionName, align)) {
+ alignment = align;
+ }
+}
+
+struct SegmentInfo {
+ SegmentInfo(StringRef name);
+
+ StringRef name;
+ uint64_t address;
+ uint64_t size;
+ uint32_t init_access;
+ uint32_t max_access;
+ std::vector<SectionInfo*> sections;
+ uint32_t normalizedSegmentIndex;
+};
+
+SegmentInfo::SegmentInfo(StringRef n)
+ : name(n), address(0), size(0), init_access(0), max_access(0),
+ normalizedSegmentIndex(0) {
+}
+
+class Util {
+public:
+ Util(const MachOLinkingContext &ctxt)
+ : _ctx(ctxt), _archHandler(ctxt.archHandler()), _entryAtom(nullptr),
+ _hasTLVDescriptors(false), _subsectionsViaSymbols(true) {}
+ ~Util();
+
+ void processDefinedAtoms(const lld::File &atomFile);
+ void processAtomAttributes(const DefinedAtom *atom);
+ void assignAtomToSection(const DefinedAtom *atom);
+ void organizeSections();
+ void assignAddressesToSections(const NormalizedFile &file);
+ uint32_t fileFlags();
+ void copySegmentInfo(NormalizedFile &file);
+ void copySectionInfo(NormalizedFile &file);
+ void updateSectionInfo(NormalizedFile &file);
+ void buildAtomToAddressMap();
+ llvm::Error synthesizeDebugNotes(NormalizedFile &file);
+ llvm::Error addSymbols(const lld::File &atomFile, NormalizedFile &file);
+ void addIndirectSymbols(const lld::File &atomFile, NormalizedFile &file);
+ void addRebaseAndBindingInfo(const lld::File &, NormalizedFile &file);
+ void addExportInfo(const lld::File &, NormalizedFile &file);
+ void addSectionRelocs(const lld::File &, NormalizedFile &file);
+ void addFunctionStarts(const lld::File &, NormalizedFile &file);
+ void buildDataInCodeArray(const lld::File &, NormalizedFile &file);
+ void addDependentDylibs(const lld::File &, NormalizedFile &file);
+ void copyEntryPointAddress(NormalizedFile &file);
+ void copySectionContent(NormalizedFile &file);
+
+ bool allSourceFilesHaveMinVersions() const {
+ return _allSourceFilesHaveMinVersions;
+ }
+
+ uint32_t minVersion() const {
+ return _minVersion;
+ }
+
+ LoadCommandType minVersionCommandType() const {
+ return _minVersionCommandType;
+ }
+
+private:
+ typedef std::map<DefinedAtom::ContentType, SectionInfo*> TypeToSection;
+ typedef llvm::DenseMap<const Atom*, uint64_t> AtomToAddress;
+
+ struct DylibInfo { int ordinal; bool hasWeak; bool hasNonWeak; };
+ typedef llvm::StringMap<DylibInfo> DylibPathToInfo;
+
+ SectionInfo *sectionForAtom(const DefinedAtom*);
+ SectionInfo *getRelocatableSection(DefinedAtom::ContentType type);
+ SectionInfo *getFinalSection(DefinedAtom::ContentType type);
+ void appendAtom(SectionInfo *sect, const DefinedAtom *atom);
+ SegmentInfo *segmentForName(StringRef segName);
+ void layoutSectionsInSegment(SegmentInfo *seg, uint64_t &addr);
+ void layoutSectionsInTextSegment(size_t, SegmentInfo *, uint64_t &);
+ void copySectionContent(SectionInfo *si, ContentBytes &content);
+ uint16_t descBits(const DefinedAtom* atom);
+ int dylibOrdinal(const SharedLibraryAtom *sa);
+ void segIndexForSection(const SectionInfo *sect,
+ uint8_t &segmentIndex, uint64_t &segmentStartAddr);
+ const Atom *targetOfLazyPointer(const DefinedAtom *lpAtom);
+ const Atom *targetOfStub(const DefinedAtom *stubAtom);
+ llvm::Error getSymbolTableRegion(const DefinedAtom* atom,
+ bool &inGlobalsRegion,
+ SymbolScope &symbolScope);
+ void appendSection(SectionInfo *si, NormalizedFile &file);
+ uint32_t sectionIndexForAtom(const Atom *atom);
+ void fixLazyReferenceImm(const DefinedAtom *atom, uint32_t offset,
+ NormalizedFile &file);
+
+ typedef llvm::DenseMap<const Atom*, uint32_t> AtomToIndex;
+ struct AtomAndIndex { const Atom *atom; uint32_t index; SymbolScope scope; };
+ struct AtomSorter {
+ bool operator()(const AtomAndIndex &left, const AtomAndIndex &right);
+ };
+ struct SegmentSorter {
+ bool operator()(const SegmentInfo *left, const SegmentInfo *right);
+ static unsigned weight(const SegmentInfo *);
+ };
+ struct TextSectionSorter {
+ bool operator()(const SectionInfo *left, const SectionInfo *right);
+ static unsigned weight(const SectionInfo *);
+ };
+
+ const MachOLinkingContext &_ctx;
+ mach_o::ArchHandler &_archHandler;
+ llvm::BumpPtrAllocator _allocator;
+ std::vector<SectionInfo*> _sectionInfos;
+ std::vector<SegmentInfo*> _segmentInfos;
+ TypeToSection _sectionMap;
+ std::vector<SectionInfo*> _customSections;
+ AtomToAddress _atomToAddress;
+ DylibPathToInfo _dylibInfo;
+ const DefinedAtom *_entryAtom;
+ AtomToIndex _atomToSymbolIndex;
+ std::vector<const Atom *> _machHeaderAliasAtoms;
+ bool _hasTLVDescriptors;
+ bool _subsectionsViaSymbols;
+ bool _allSourceFilesHaveMinVersions = true;
+ LoadCommandType _minVersionCommandType = (LoadCommandType)0;
+ uint32_t _minVersion = 0;
+ std::vector<lld::mach_o::Stab> _stabs;
+};
+
+Util::~Util() {
+ // The SectionInfo structs are BumpPtr allocated, but atomsAndOffsets needs
+ // to be deleted.
+ for (SectionInfo *si : _sectionInfos) {
+ // clear() destroys vector elements, but does not deallocate.
+ // Instead use swap() to deallocate vector buffer.
+ std::vector<AtomInfo> empty;
+ si->atomsAndOffsets.swap(empty);
+ }
+ // The SegmentInfo structs are BumpPtr allocated, but sections needs
+ // to be deleted.
+ for (SegmentInfo *sgi : _segmentInfos) {
+ std::vector<SectionInfo*> empty2;
+ sgi->sections.swap(empty2);
+ }
+}
+
+SectionInfo *Util::getRelocatableSection(DefinedAtom::ContentType type) {
+ StringRef segmentName;
+ StringRef sectionName;
+ SectionType sectionType;
+ SectionAttr sectionAttrs;
+ bool relocsToDefinedCanBeImplicit;
+
+ // Use same table used by when parsing .o files.
+ relocatableSectionInfoForContentType(type, segmentName, sectionName,
+ sectionType, sectionAttrs,
+ relocsToDefinedCanBeImplicit);
+ // If we already have a SectionInfo with this name, re-use it.
+ // This can happen if two ContentType map to the same mach-o section.
+ for (auto sect : _sectionMap) {
+ if (sect.second->sectionName.equals(sectionName) &&
+ sect.second->segmentName.equals(segmentName)) {
+ return sect.second;
+ }
+ }
+ // Otherwise allocate new SectionInfo object.
+ auto *sect = new (_allocator)
+ SectionInfo(segmentName, sectionName, sectionType, _ctx, sectionAttrs,
+ relocsToDefinedCanBeImplicit);
+ _sectionInfos.push_back(sect);
+ _sectionMap[type] = sect;
+ return sect;
+}
+
+#define ENTRY(seg, sect, type, atomType) \
+ {seg, sect, type, DefinedAtom::atomType }
+
+struct MachOFinalSectionFromAtomType {
+ StringRef segmentName;
+ StringRef sectionName;
+ SectionType sectionType;
+ DefinedAtom::ContentType atomType;
+};
+
+const MachOFinalSectionFromAtomType sectsToAtomType[] = {
+ ENTRY("__TEXT", "__text", S_REGULAR, typeCode),
+ ENTRY("__TEXT", "__text", S_REGULAR, typeMachHeader),
+ ENTRY("__TEXT", "__cstring", S_CSTRING_LITERALS, typeCString),
+ ENTRY("__TEXT", "__ustring", S_REGULAR, typeUTF16String),
+ ENTRY("__TEXT", "__const", S_REGULAR, typeConstant),
+ ENTRY("__TEXT", "__const", S_4BYTE_LITERALS, typeLiteral4),
+ ENTRY("__TEXT", "__const", S_8BYTE_LITERALS, typeLiteral8),
+ ENTRY("__TEXT", "__const", S_16BYTE_LITERALS, typeLiteral16),
+ ENTRY("__TEXT", "__stubs", S_SYMBOL_STUBS, typeStub),
+ ENTRY("__TEXT", "__stub_helper", S_REGULAR, typeStubHelper),
+ ENTRY("__TEXT", "__gcc_except_tab", S_REGULAR, typeLSDA),
+ ENTRY("__TEXT", "__eh_frame", S_COALESCED, typeCFI),
+ ENTRY("__TEXT", "__unwind_info", S_REGULAR, typeProcessedUnwindInfo),
+ ENTRY("__DATA", "__data", S_REGULAR, typeData),
+ ENTRY("__DATA", "__const", S_REGULAR, typeConstData),
+ ENTRY("__DATA", "__cfstring", S_REGULAR, typeCFString),
+ ENTRY("__DATA", "__la_symbol_ptr", S_LAZY_SYMBOL_POINTERS,
+ typeLazyPointer),
+ ENTRY("__DATA", "__mod_init_func", S_MOD_INIT_FUNC_POINTERS,
+ typeInitializerPtr),
+ ENTRY("__DATA", "__mod_term_func", S_MOD_TERM_FUNC_POINTERS,
+ typeTerminatorPtr),
+ ENTRY("__DATA", "__got", S_NON_LAZY_SYMBOL_POINTERS,
+ typeGOT),
+ ENTRY("__DATA", "__nl_symbol_ptr", S_NON_LAZY_SYMBOL_POINTERS,
+ typeNonLazyPointer),
+ ENTRY("__DATA", "__thread_vars", S_THREAD_LOCAL_VARIABLES,
+ typeThunkTLV),
+ ENTRY("__DATA", "__thread_data", S_THREAD_LOCAL_REGULAR,
+ typeTLVInitialData),
+ ENTRY("__DATA", "__thread_ptrs", S_THREAD_LOCAL_VARIABLE_POINTERS,
+ typeTLVInitializerPtr),
+ ENTRY("__DATA", "__thread_bss", S_THREAD_LOCAL_ZEROFILL,
+ typeTLVInitialZeroFill),
+ ENTRY("__DATA", "__bss", S_ZEROFILL, typeZeroFill),
+ ENTRY("__DATA", "__interposing", S_INTERPOSING, typeInterposingTuples),
+};
+#undef ENTRY
+
+SectionInfo *Util::getFinalSection(DefinedAtom::ContentType atomType) {
+ for (auto &p : sectsToAtomType) {
+ if (p.atomType != atomType)
+ continue;
+ SectionAttr sectionAttrs = 0;
+ switch (atomType) {
+ case DefinedAtom::typeMachHeader:
+ case DefinedAtom::typeCode:
+ case DefinedAtom::typeStub:
+ case DefinedAtom::typeStubHelper:
+ sectionAttrs = S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS;
+ break;
+ case DefinedAtom::typeThunkTLV:
+ _hasTLVDescriptors = true;
+ break;
+ default:
+ break;
+ }
+ // If we already have a SectionInfo with this name, re-use it.
+ // This can happen if two ContentType map to the same mach-o section.
+ for (auto sect : _sectionMap) {
+ if (sect.second->sectionName.equals(p.sectionName) &&
+ sect.second->segmentName.equals(p.segmentName)) {
+ return sect.second;
+ }
+ }
+ // Otherwise allocate new SectionInfo object.
+ auto *sect = new (_allocator) SectionInfo(
+ p.segmentName, p.sectionName, p.sectionType, _ctx, sectionAttrs,
+ /* relocsToDefinedCanBeImplicit */ false);
+ _sectionInfos.push_back(sect);
+ _sectionMap[atomType] = sect;
+ return sect;
+ }
+ llvm_unreachable("content type not yet supported");
+}
+
+SectionInfo *Util::sectionForAtom(const DefinedAtom *atom) {
+ if (atom->sectionChoice() == DefinedAtom::sectionBasedOnContent) {
+ // Section for this atom is derived from content type.
+ DefinedAtom::ContentType type = atom->contentType();
+ auto pos = _sectionMap.find(type);
+ if ( pos != _sectionMap.end() )
+ return pos->second;
+ bool rMode = (_ctx.outputMachOType() == llvm::MachO::MH_OBJECT);
+ return rMode ? getRelocatableSection(type) : getFinalSection(type);
+ } else {
+ // This atom needs to be in a custom section.
+ StringRef customName = atom->customSectionName();
+ // Look to see if we have already allocated the needed custom section.
+ for(SectionInfo *sect : _customSections) {
+ const DefinedAtom *firstAtom = sect->atomsAndOffsets.front().atom;
+ if (firstAtom->customSectionName().equals(customName)) {
+ return sect;
+ }
+ }
+ // Not found, so need to create a new custom section.
+ size_t seperatorIndex = customName.find('/');
+ assert(seperatorIndex != StringRef::npos);
+ StringRef segName = customName.slice(0, seperatorIndex);
+ StringRef sectName = customName.drop_front(seperatorIndex + 1);
+ auto *sect =
+ new (_allocator) SectionInfo(segName, sectName, S_REGULAR, _ctx,
+ 0, /* relocsToDefinedCanBeImplicit */ false);
+ _customSections.push_back(sect);
+ _sectionInfos.push_back(sect);
+ return sect;
+ }
+}
+
+void Util::appendAtom(SectionInfo *sect, const DefinedAtom *atom) {
+ // Figure out offset for atom in this section given alignment constraints.
+ uint64_t offset = sect->size;
+ DefinedAtom::Alignment atomAlign = atom->alignment();
+ uint64_t align = atomAlign.value;
+ uint64_t requiredModulus = atomAlign.modulus;
+ uint64_t currentModulus = (offset % align);
+ if ( currentModulus != requiredModulus ) {
+ if ( requiredModulus > currentModulus )
+ offset += requiredModulus-currentModulus;
+ else
+ offset += align+requiredModulus-currentModulus;
+ }
+ // Record max alignment of any atom in this section.
+ if (align > sect->alignment)
+ sect->alignment = atomAlign.value;
+ // Assign atom to this section with this offset.
+ AtomInfo ai = {atom, offset};
+ sect->atomsAndOffsets.push_back(ai);
+ // Update section size to include this atom.
+ sect->size = offset + atom->size();
+}
+
+void Util::processDefinedAtoms(const lld::File &atomFile) {
+ for (const DefinedAtom *atom : atomFile.defined()) {
+ processAtomAttributes(atom);
+ assignAtomToSection(atom);
+ }
+}
+
+void Util::processAtomAttributes(const DefinedAtom *atom) {
+ if (auto *machoFile = dyn_cast<mach_o::MachOFile>(&atom->file())) {
+ // If the file doesn't use subsections via symbols, then make sure we don't
+ // add that flag to the final output file if we have a relocatable file.
+ if (!machoFile->subsectionsViaSymbols())
+ _subsectionsViaSymbols = false;
+
+ // All the source files must have min versions for us to output an object
+ // file with a min version.
+ if (auto v = machoFile->minVersion())
+ _minVersion = std::max(_minVersion, v);
+ else
+ _allSourceFilesHaveMinVersions = false;
+
+ // If we don't have a platform load command, but one of the source files
+ // does, then take the one from the file.
+ if (!_minVersionCommandType)
+ if (auto v = machoFile->minVersionLoadCommandKind())
+ _minVersionCommandType = v;
+ }
+}
+
+void Util::assignAtomToSection(const DefinedAtom *atom) {
+ if (atom->contentType() == DefinedAtom::typeMachHeader) {
+ _machHeaderAliasAtoms.push_back(atom);
+ // Assign atom to this section with this offset.
+ AtomInfo ai = {atom, 0};
+ sectionForAtom(atom)->atomsAndOffsets.push_back(ai);
+ } else if (atom->contentType() == DefinedAtom::typeDSOHandle)
+ _machHeaderAliasAtoms.push_back(atom);
+ else
+ appendAtom(sectionForAtom(atom), atom);
+}
+
+SegmentInfo *Util::segmentForName(StringRef segName) {
+ for (SegmentInfo *si : _segmentInfos) {
+ if ( si->name.equals(segName) )
+ return si;
+ }
+ auto *info = new (_allocator) SegmentInfo(segName);
+
+ // Set the initial segment protection.
+ if (segName.equals("__TEXT"))
+ info->init_access = VM_PROT_READ | VM_PROT_EXECUTE;
+ else if (segName.equals("__PAGEZERO"))
+ info->init_access = 0;
+ else if (segName.equals("__LINKEDIT"))
+ info->init_access = VM_PROT_READ;
+ else {
+ // All others default to read-write
+ info->init_access = VM_PROT_READ | VM_PROT_WRITE;
+ }
+
+ // Set max segment protection
+ // Note, its overkill to use a switch statement here, but makes it so much
+ // easier to use switch coverage to catch new cases.
+ switch (_ctx.os()) {
+ case lld::MachOLinkingContext::OS::unknown:
+ case lld::MachOLinkingContext::OS::macOSX:
+ case lld::MachOLinkingContext::OS::iOS_simulator:
+ if (segName.equals("__PAGEZERO")) {
+ info->max_access = 0;
+ break;
+ }
+ // All others default to all
+ info->max_access = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
+ break;
+ case lld::MachOLinkingContext::OS::iOS:
+ // iPhoneOS always uses same protection for max and initial
+ info->max_access = info->init_access;
+ break;
+ }
+ _segmentInfos.push_back(info);
+ return info;
+}
+
+unsigned Util::SegmentSorter::weight(const SegmentInfo *seg) {
+ return llvm::StringSwitch<unsigned>(seg->name)
+ .Case("__PAGEZERO", 1)
+ .Case("__TEXT", 2)
+ .Case("__DATA", 3)
+ .Default(100);
+}
+
+bool Util::SegmentSorter::operator()(const SegmentInfo *left,
+ const SegmentInfo *right) {
+ return (weight(left) < weight(right));
+}
+
+unsigned Util::TextSectionSorter::weight(const SectionInfo *sect) {
+ return llvm::StringSwitch<unsigned>(sect->sectionName)
+ .Case("__text", 1)
+ .Case("__stubs", 2)
+ .Case("__stub_helper", 3)
+ .Case("__const", 4)
+ .Case("__cstring", 5)
+ .Case("__unwind_info", 98)
+ .Case("__eh_frame", 99)
+ .Default(10);
+}
+
+bool Util::TextSectionSorter::operator()(const SectionInfo *left,
+ const SectionInfo *right) {
+ return (weight(left) < weight(right));
+}
+
+void Util::organizeSections() {
+ // NOTE!: Keep this in sync with assignAddressesToSections.
+ switch (_ctx.outputMachOType()) {
+ case llvm::MachO::MH_EXECUTE:
+ // Main executables, need a zero-page segment
+ segmentForName("__PAGEZERO");
+ // Fall into next case.
+ LLVM_FALLTHROUGH;
+ case llvm::MachO::MH_DYLIB:
+ case llvm::MachO::MH_BUNDLE:
+ // All dynamic code needs TEXT segment to hold the load commands.
+ segmentForName("__TEXT");
+ break;
+ default:
+ break;
+ }
+ segmentForName("__LINKEDIT");
+
+ // Group sections into segments.
+ for (SectionInfo *si : _sectionInfos) {
+ SegmentInfo *seg = segmentForName(si->segmentName);
+ seg->sections.push_back(si);
+ }
+ // Sort segments.
+ std::sort(_segmentInfos.begin(), _segmentInfos.end(), SegmentSorter());
+
+ // Sort sections within segments.
+ for (SegmentInfo *seg : _segmentInfos) {
+ if (seg->name.equals("__TEXT")) {
+ std::sort(seg->sections.begin(), seg->sections.end(),
+ TextSectionSorter());
+ }
+ }
+
+ // Record final section indexes.
+ uint32_t segmentIndex = 0;
+ uint32_t sectionIndex = 1;
+ for (SegmentInfo *seg : _segmentInfos) {
+ seg->normalizedSegmentIndex = segmentIndex++;
+ for (SectionInfo *sect : seg->sections)
+ sect->finalSectionIndex = sectionIndex++;
+ }
+}
+
+void Util::layoutSectionsInSegment(SegmentInfo *seg, uint64_t &addr) {
+ seg->address = addr;
+ for (SectionInfo *sect : seg->sections) {
+ sect->address = llvm::alignTo(addr, sect->alignment);
+ addr = sect->address + sect->size;
+ }
+ seg->size = llvm::alignTo(addr - seg->address, _ctx.pageSize());
+}
+
+// __TEXT segment lays out backwards so padding is at front after load commands.
+void Util::layoutSectionsInTextSegment(size_t hlcSize, SegmentInfo *seg,
+ uint64_t &addr) {
+ seg->address = addr;
+ // Walks sections starting at end to calculate padding for start.
+ int64_t taddr = 0;
+ for (auto it = seg->sections.rbegin(); it != seg->sections.rend(); ++it) {
+ SectionInfo *sect = *it;
+ taddr -= sect->size;
+ taddr = taddr & (0 - sect->alignment);
+ }
+ int64_t padding = taddr - hlcSize;
+ while (padding < 0)
+ padding += _ctx.pageSize();
+ // Start assigning section address starting at padded offset.
+ addr += (padding + hlcSize);
+ for (SectionInfo *sect : seg->sections) {
+ sect->address = llvm::alignTo(addr, sect->alignment);
+ addr = sect->address + sect->size;
+ }
+ seg->size = llvm::alignTo(addr - seg->address, _ctx.pageSize());
+}
+
+void Util::assignAddressesToSections(const NormalizedFile &file) {
+ // NOTE!: Keep this in sync with organizeSections.
+ size_t hlcSize = headerAndLoadCommandsSize(file);
+ uint64_t address = 0;
+ for (SegmentInfo *seg : _segmentInfos) {
+ if (seg->name.equals("__PAGEZERO")) {
+ seg->size = _ctx.pageZeroSize();
+ address += seg->size;
+ }
+ else if (seg->name.equals("__TEXT")) {
+ // _ctx.baseAddress() == 0 implies it was either unspecified or
+ // pageZeroSize is also 0. In either case resetting address is safe.
+ address = _ctx.baseAddress() ? _ctx.baseAddress() : address;
+ layoutSectionsInTextSegment(hlcSize, seg, address);
+ } else
+ layoutSectionsInSegment(seg, address);
+
+ address = llvm::alignTo(address, _ctx.pageSize());
+ }
+ DEBUG_WITH_TYPE("WriterMachO-norm",
+ llvm::dbgs() << "assignAddressesToSections()\n";
+ for (SegmentInfo *sgi : _segmentInfos) {
+ llvm::dbgs() << " address=" << llvm::format("0x%08llX", sgi->address)
+ << ", size=" << llvm::format("0x%08llX", sgi->size)
+ << ", segment-name='" << sgi->name
+ << "'\n";
+ for (SectionInfo *si : sgi->sections) {
+ llvm::dbgs()<< " addr=" << llvm::format("0x%08llX", si->address)
+ << ", size=" << llvm::format("0x%08llX", si->size)
+ << ", section-name='" << si->sectionName
+ << "\n";
+ }
+ }
+ );
+}
+
+void Util::copySegmentInfo(NormalizedFile &file) {
+ for (SegmentInfo *sgi : _segmentInfos) {
+ Segment seg;
+ seg.name = sgi->name;
+ seg.address = sgi->address;
+ seg.size = sgi->size;
+ seg.init_access = sgi->init_access;
+ seg.max_access = sgi->max_access;
+ file.segments.push_back(seg);
+ }
+}
+
+void Util::appendSection(SectionInfo *si, NormalizedFile &file) {
+ // Add new empty section to end of file.sections.
+ Section temp;
+ file.sections.push_back(std::move(temp));
+ Section* normSect = &file.sections.back();
+ // Copy fields to normalized section.
+ normSect->segmentName = si->segmentName;
+ normSect->sectionName = si->sectionName;
+ normSect->type = si->type;
+ normSect->attributes = si->attributes;
+ normSect->address = si->address;
+ normSect->alignment = si->alignment;
+ // Record where normalized section is.
+ si->normalizedSectionIndex = file.sections.size()-1;
+}
+
+void Util::copySectionContent(NormalizedFile &file) {
+ const bool r = (_ctx.outputMachOType() == llvm::MachO::MH_OBJECT);
+
+ // Utility function for ArchHandler to find address of atom in output file.
+ auto addrForAtom = [&] (const Atom &atom) -> uint64_t {
+ auto pos = _atomToAddress.find(&atom);
+ assert(pos != _atomToAddress.end());
+ return pos->second;
+ };
+
+ auto sectionAddrForAtom = [&] (const Atom &atom) -> uint64_t {
+ for (const SectionInfo *sectInfo : _sectionInfos)
+ for (const AtomInfo &atomInfo : sectInfo->atomsAndOffsets)
+ if (atomInfo.atom == &atom)
+ return sectInfo->address;
+ llvm_unreachable("atom not assigned to section");
+ };
+
+ for (SectionInfo *si : _sectionInfos) {
+ Section *normSect = &file.sections[si->normalizedSectionIndex];
+ if (isZeroFillSection(si->type)) {
+ const uint8_t *empty = nullptr;
+ normSect->content = llvm::makeArrayRef(empty, si->size);
+ continue;
+ }
+ // Copy content from atoms to content buffer for section.
+ llvm::MutableArrayRef<uint8_t> sectionContent;
+ if (si->size) {
+ uint8_t *sectContent = file.ownedAllocations.Allocate<uint8_t>(si->size);
+ sectionContent = llvm::MutableArrayRef<uint8_t>(sectContent, si->size);
+ normSect->content = sectionContent;
+ }
+ for (AtomInfo &ai : si->atomsAndOffsets) {
+ if (!ai.atom->size()) {
+ assert(ai.atom->begin() == ai.atom->end() &&
+ "Cannot have references without content");
+ continue;
+ }
+ auto atomContent = sectionContent.slice(ai.offsetInSection,
+ ai.atom->size());
+ _archHandler.generateAtomContent(*ai.atom, r, addrForAtom,
+ sectionAddrForAtom, _ctx.baseAddress(),
+ atomContent);
+ }
+ }
+}
+
+void Util::copySectionInfo(NormalizedFile &file) {
+ file.sections.reserve(_sectionInfos.size());
+ // Write sections grouped by segment.
+ for (SegmentInfo *sgi : _segmentInfos) {
+ for (SectionInfo *si : sgi->sections) {
+ appendSection(si, file);
+ }
+ }
+}
+
+void Util::updateSectionInfo(NormalizedFile &file) {
+ file.sections.reserve(_sectionInfos.size());
+ // sections grouped by segment.
+ for (SegmentInfo *sgi : _segmentInfos) {
+ Segment *normSeg = &file.segments[sgi->normalizedSegmentIndex];
+ normSeg->address = sgi->address;
+ normSeg->size = sgi->size;
+ for (SectionInfo *si : sgi->sections) {
+ Section *normSect = &file.sections[si->normalizedSectionIndex];
+ normSect->address = si->address;
+ }
+ }
+}
+
+void Util::copyEntryPointAddress(NormalizedFile &nFile) {
+ if (!_entryAtom) {
+ nFile.entryAddress = 0;
+ return;
+ }
+
+ if (_ctx.outputTypeHasEntry()) {
+ if (_archHandler.isThumbFunction(*_entryAtom))
+ nFile.entryAddress = (_atomToAddress[_entryAtom] | 1);
+ else
+ nFile.entryAddress = _atomToAddress[_entryAtom];
+ }
+}
+
+void Util::buildAtomToAddressMap() {
+ DEBUG_WITH_TYPE("WriterMachO-address", llvm::dbgs()
+ << "assign atom addresses:\n");
+ const bool lookForEntry = _ctx.outputTypeHasEntry();
+ for (SectionInfo *sect : _sectionInfos) {
+ for (const AtomInfo &info : sect->atomsAndOffsets) {
+ _atomToAddress[info.atom] = sect->address + info.offsetInSection;
+ if (lookForEntry && (info.atom->contentType() == DefinedAtom::typeCode) &&
+ (info.atom->size() != 0) &&
+ info.atom->name() == _ctx.entrySymbolName()) {
+ _entryAtom = info.atom;
+ }
+ DEBUG_WITH_TYPE("WriterMachO-address", llvm::dbgs()
+ << " address="
+ << llvm::format("0x%016X", _atomToAddress[info.atom])
+ << llvm::format(" 0x%09lX", info.atom)
+ << ", file=#"
+ << info.atom->file().ordinal()
+ << ", atom=#"
+ << info.atom->ordinal()
+ << ", name="
+ << info.atom->name()
+ << ", type="
+ << info.atom->contentType()
+ << "\n");
+ }
+ }
+ DEBUG_WITH_TYPE("WriterMachO-address", llvm::dbgs()
+ << "assign header alias atom addresses:\n");
+ for (const Atom *atom : _machHeaderAliasAtoms) {
+ _atomToAddress[atom] = _ctx.baseAddress();
+#ifndef NDEBUG
+ if (auto *definedAtom = dyn_cast<DefinedAtom>(atom)) {
+ DEBUG_WITH_TYPE("WriterMachO-address", llvm::dbgs()
+ << " address="
+ << llvm::format("0x%016X", _atomToAddress[atom])
+ << llvm::format(" 0x%09lX", atom)
+ << ", file=#"
+ << definedAtom->file().ordinal()
+ << ", atom=#"
+ << definedAtom->ordinal()
+ << ", name="
+ << definedAtom->name()
+ << ", type="
+ << definedAtom->contentType()
+ << "\n");
+ } else {
+ DEBUG_WITH_TYPE("WriterMachO-address", llvm::dbgs()
+ << " address="
+ << llvm::format("0x%016X", _atomToAddress[atom])
+ << " atom=" << atom
+ << " name=" << atom->name() << "\n");
+ }
+#endif
+ }
+}
+
+llvm::Error Util::synthesizeDebugNotes(NormalizedFile &file) {
+
+ // Bail out early if we don't need to generate a debug map.
+ if (_ctx.debugInfoMode() == MachOLinkingContext::DebugInfoMode::noDebugMap)
+ return llvm::Error::success();
+
+ std::vector<const DefinedAtom*> atomsNeedingDebugNotes;
+ std::set<const mach_o::MachOFile*> filesWithStabs;
+ bool objFileHasDwarf = false;
+ const File *objFile = nullptr;
+
+ for (SectionInfo *sect : _sectionInfos) {
+ for (const AtomInfo &info : sect->atomsAndOffsets) {
+ if (const DefinedAtom *atom = dyn_cast<DefinedAtom>(info.atom)) {
+
+ // FIXME: No stabs/debug-notes for symbols that wouldn't be in the
+ // symbol table.
+ // FIXME: No stabs/debug-notes for kernel dtrace probes.
+
+ if (atom->contentType() == DefinedAtom::typeCFI ||
+ atom->contentType() == DefinedAtom::typeCString)
+ continue;
+
+ // Whenever we encounter a new file, update the 'objfileHasDwarf' flag.
+ if (&info.atom->file() != objFile) {
+ objFileHasDwarf = false;
+ if (const mach_o::MachOFile *atomFile =
+ dyn_cast<mach_o::MachOFile>(&info.atom->file())) {
+ if (atomFile->debugInfo()) {
+ if (isa<mach_o::DwarfDebugInfo>(atomFile->debugInfo()))
+ objFileHasDwarf = true;
+ else if (isa<mach_o::StabsDebugInfo>(atomFile->debugInfo()))
+ filesWithStabs.insert(atomFile);
+ }
+ }
+ }
+
+ // If this atom is from a file that needs dwarf, add it to the list.
+ if (objFileHasDwarf)
+ atomsNeedingDebugNotes.push_back(info.atom);
+ }
+ }
+ }
+
+ // Sort atoms needing debug notes by file ordinal, then atom ordinal.
+ std::sort(atomsNeedingDebugNotes.begin(), atomsNeedingDebugNotes.end(),
+ [](const DefinedAtom *lhs, const DefinedAtom *rhs) {
+ if (lhs->file().ordinal() != rhs->file().ordinal())
+ return (lhs->file().ordinal() < rhs->file().ordinal());
+ return (lhs->ordinal() < rhs->ordinal());
+ });
+
+ // FIXME: Handle <rdar://problem/17689030>: Add -add_ast_path option to \
+ // linker which add N_AST stab entry to output
+ // See OutputFile::synthesizeDebugNotes in ObjectFile.cpp in ld64.
+
+ StringRef oldFileName = "";
+ StringRef oldDirPath = "";
+ bool wroteStartSO = false;
+ std::unordered_set<std::string> seenFiles;
+ for (const DefinedAtom *atom : atomsNeedingDebugNotes) {
+ const auto &atomFile = cast<mach_o::MachOFile>(atom->file());
+ assert(dyn_cast_or_null<lld::mach_o::DwarfDebugInfo>(atomFile.debugInfo())
+ && "file for atom needing debug notes does not contain dwarf");
+ auto &dwarf = cast<lld::mach_o::DwarfDebugInfo>(*atomFile.debugInfo());
+
+ auto &tu = dwarf.translationUnitSource();
+ StringRef newFileName = tu.name;
+ StringRef newDirPath = tu.path;
+
+ // Add an SO whenever the TU source file changes.
+ if (newFileName != oldFileName || newDirPath != oldDirPath) {
+ // Translation unit change, emit ending SO
+ if (oldFileName != "")
+ _stabs.push_back(mach_o::Stab(nullptr, N_SO, 1, 0, 0, ""));
+
+ oldFileName = newFileName;
+ oldDirPath = newDirPath;
+
+ // If newDirPath doesn't end with a '/' we need to add one:
+ if (newDirPath.back() != '/') {
+ char *p =
+ file.ownedAllocations.Allocate<char>(newDirPath.size() + 2);
+ memcpy(p, newDirPath.data(), newDirPath.size());
+ p[newDirPath.size()] = '/';
+ p[newDirPath.size() + 1] = '\0';
+ newDirPath = p;
+ }
+
+ // New translation unit, emit start SOs:
+ _stabs.push_back(mach_o::Stab(nullptr, N_SO, 0, 0, 0, newDirPath));
+ _stabs.push_back(mach_o::Stab(nullptr, N_SO, 0, 0, 0, newFileName));
+
+ // Synthesize OSO for start of file.
+ char *fullPath = nullptr;
+ {
+ SmallString<1024> pathBuf(atomFile.path());
+ if (auto EC = llvm::sys::fs::make_absolute(pathBuf))
+ return llvm::errorCodeToError(EC);
+ fullPath = file.ownedAllocations.Allocate<char>(pathBuf.size() + 1);
+ memcpy(fullPath, pathBuf.c_str(), pathBuf.size() + 1);
+ }
+
+ // Get mod time.
+ uint32_t modTime = 0;
+ llvm::sys::fs::file_status stat;
+ if (!llvm::sys::fs::status(fullPath, stat))
+ if (llvm::sys::fs::exists(stat))
+ modTime = llvm::sys::toTimeT(stat.getLastModificationTime());
+
+ _stabs.push_back(mach_o::Stab(nullptr, N_OSO, _ctx.getCPUSubType(), 1,
+ modTime, fullPath));
+ // <rdar://problem/6337329> linker should put cpusubtype in n_sect field
+ // of nlist entry for N_OSO debug note entries.
+ wroteStartSO = true;
+ }
+
+ if (atom->contentType() == DefinedAtom::typeCode) {
+ // Synthesize BNSYM and start FUN stabs.
+ _stabs.push_back(mach_o::Stab(atom, N_BNSYM, 1, 0, 0, ""));
+ _stabs.push_back(mach_o::Stab(atom, N_FUN, 1, 0, 0, atom->name()));
+ // Synthesize any SOL stabs needed
+ // FIXME: add SOL stabs.
+ _stabs.push_back(mach_o::Stab(nullptr, N_FUN, 0, 0,
+ atom->rawContent().size(), ""));
+ _stabs.push_back(mach_o::Stab(nullptr, N_ENSYM, 1, 0,
+ atom->rawContent().size(), ""));
+ } else {
+ if (atom->scope() == Atom::scopeTranslationUnit)
+ _stabs.push_back(mach_o::Stab(atom, N_STSYM, 1, 0, 0, atom->name()));
+ else
+ _stabs.push_back(mach_o::Stab(nullptr, N_GSYM, 1, 0, 0, atom->name()));
+ }
+ }
+
+ // Emit ending SO if necessary.
+ if (wroteStartSO)
+ _stabs.push_back(mach_o::Stab(nullptr, N_SO, 1, 0, 0, ""));
+
+ // Copy any stabs from .o file.
+ for (const auto *objFile : filesWithStabs) {
+ const auto &stabsList =
+ cast<mach_o::StabsDebugInfo>(objFile->debugInfo())->stabs();
+ for (auto &stab : stabsList) {
+ // FIXME: Drop stabs whose atoms have been dead-stripped.
+ _stabs.push_back(stab);
+ }
+ }
+
+ return llvm::Error::success();
+}
+
+uint16_t Util::descBits(const DefinedAtom* atom) {
+ uint16_t desc = 0;
+ switch (atom->merge()) {
+ case lld::DefinedAtom::mergeNo:
+ case lld::DefinedAtom::mergeAsTentative:
+ break;
+ case lld::DefinedAtom::mergeAsWeak:
+ case lld::DefinedAtom::mergeAsWeakAndAddressUsed:
+ desc |= N_WEAK_DEF;
+ break;
+ case lld::DefinedAtom::mergeSameNameAndSize:
+ case lld::DefinedAtom::mergeByLargestSection:
+ case lld::DefinedAtom::mergeByContent:
+ llvm_unreachable("Unsupported DefinedAtom::merge()");
+ break;
+ }
+ if (atom->contentType() == lld::DefinedAtom::typeResolver)
+ desc |= N_SYMBOL_RESOLVER;
+ if (atom->contentType() == lld::DefinedAtom::typeMachHeader)
+ desc |= REFERENCED_DYNAMICALLY;
+ if (_archHandler.isThumbFunction(*atom))
+ desc |= N_ARM_THUMB_DEF;
+ if (atom->deadStrip() == DefinedAtom::deadStripNever &&
+ _ctx.outputMachOType() == llvm::MachO::MH_OBJECT) {
+ if ((atom->contentType() != DefinedAtom::typeInitializerPtr)
+ && (atom->contentType() != DefinedAtom::typeTerminatorPtr))
+ desc |= N_NO_DEAD_STRIP;
+ }
+ return desc;
+}
+
+bool Util::AtomSorter::operator()(const AtomAndIndex &left,
+ const AtomAndIndex &right) {
+ return (left.atom->name().compare(right.atom->name()) < 0);
+}
+
+llvm::Error Util::getSymbolTableRegion(const DefinedAtom* atom,
+ bool &inGlobalsRegion,
+ SymbolScope &scope) {
+ bool rMode = (_ctx.outputMachOType() == llvm::MachO::MH_OBJECT);
+ switch (atom->scope()) {
+ case Atom::scopeTranslationUnit:
+ scope = 0;
+ inGlobalsRegion = false;
+ return llvm::Error::success();
+ case Atom::scopeLinkageUnit:
+ if ((_ctx.exportMode() == MachOLinkingContext::ExportMode::whiteList) &&
+ _ctx.exportSymbolNamed(atom->name())) {
+ return llvm::make_error<GenericError>(
+ Twine("cannot export hidden symbol ") + atom->name());
+ }
+ if (rMode) {
+ if (_ctx.keepPrivateExterns()) {
+ // -keep_private_externs means keep in globals region as N_PEXT.
+ scope = N_PEXT | N_EXT;
+ inGlobalsRegion = true;
+ return llvm::Error::success();
+ }
+ }
+ // scopeLinkageUnit symbols are no longer global once linked.
+ scope = N_PEXT;
+ inGlobalsRegion = false;
+ return llvm::Error::success();
+ case Atom::scopeGlobal:
+ if (_ctx.exportRestrictMode()) {
+ if (_ctx.exportSymbolNamed(atom->name())) {
+ scope = N_EXT;
+ inGlobalsRegion = true;
+ return llvm::Error::success();
+ } else {
+ scope = N_PEXT;
+ inGlobalsRegion = false;
+ return llvm::Error::success();
+ }
+ } else {
+ scope = N_EXT;
+ inGlobalsRegion = true;
+ return llvm::Error::success();
+ }
+ break;
+ }
+ llvm_unreachable("atom->scope() unknown enum value");
+}
+
+
+
+llvm::Error Util::addSymbols(const lld::File &atomFile,
+ NormalizedFile &file) {
+ bool rMode = (_ctx.outputMachOType() == llvm::MachO::MH_OBJECT);
+ // Mach-O symbol table has four regions: stabs, locals, globals, undefs.
+
+ // Add all stabs.
+ for (auto &stab : _stabs) {
+ Symbol sym;
+ sym.type = static_cast<NListType>(stab.type);
+ sym.scope = 0;
+ sym.sect = stab.other;
+ sym.desc = stab.desc;
+ if (stab.atom)
+ sym.value = _atomToAddress[stab.atom];
+ else
+ sym.value = stab.value;
+ sym.name = stab.str;
+ file.stabsSymbols.push_back(sym);
+ }
+
+ // Add all local (non-global) symbols in address order
+ std::vector<AtomAndIndex> globals;
+ globals.reserve(512);
+ for (SectionInfo *sect : _sectionInfos) {
+ for (const AtomInfo &info : sect->atomsAndOffsets) {
+ const DefinedAtom *atom = info.atom;
+ if (!atom->name().empty()) {
+ SymbolScope symbolScope;
+ bool inGlobalsRegion;
+ if (auto ec = getSymbolTableRegion(atom, inGlobalsRegion, symbolScope)){
+ return ec;
+ }
+ if (inGlobalsRegion) {
+ AtomAndIndex ai = { atom, sect->finalSectionIndex, symbolScope };
+ globals.push_back(ai);
+ } else {
+ Symbol sym;
+ sym.name = atom->name();
+ sym.type = N_SECT;
+ sym.scope = symbolScope;
+ sym.sect = sect->finalSectionIndex;
+ sym.desc = descBits(atom);
+ sym.value = _atomToAddress[atom];
+ _atomToSymbolIndex[atom] = file.localSymbols.size();
+ file.localSymbols.push_back(sym);
+ }
+ } else if (rMode && _archHandler.needsLocalSymbolInRelocatableFile(atom)){
+ // Create 'Lxxx' labels for anonymous atoms if archHandler says so.
+ static unsigned tempNum = 1;
+ char tmpName[16];
+ sprintf(tmpName, "L%04u", tempNum++);
+ StringRef tempRef(tmpName);
+ Symbol sym;
+ sym.name = tempRef.copy(file.ownedAllocations);
+ sym.type = N_SECT;
+ sym.scope = 0;
+ sym.sect = sect->finalSectionIndex;
+ sym.desc = 0;
+ sym.value = _atomToAddress[atom];
+ _atomToSymbolIndex[atom] = file.localSymbols.size();
+ file.localSymbols.push_back(sym);
+ }
+ }
+ }
+
+ // Sort global symbol alphabetically, then add to symbol table.
+ std::sort(globals.begin(), globals.end(), AtomSorter());
+ const uint32_t globalStartIndex = file.localSymbols.size();
+ for (AtomAndIndex &ai : globals) {
+ Symbol sym;
+ sym.name = ai.atom->name();
+ sym.type = N_SECT;
+ sym.scope = ai.scope;
+ sym.sect = ai.index;
+ sym.desc = descBits(static_cast<const DefinedAtom*>(ai.atom));
+ sym.value = _atomToAddress[ai.atom];
+ _atomToSymbolIndex[ai.atom] = globalStartIndex + file.globalSymbols.size();
+ file.globalSymbols.push_back(sym);
+ }
+
+ // Sort undefined symbol alphabetically, then add to symbol table.
+ std::vector<AtomAndIndex> undefs;
+ undefs.reserve(128);
+ for (const UndefinedAtom *atom : atomFile.undefined()) {
+ AtomAndIndex ai = { atom, 0, N_EXT };
+ undefs.push_back(ai);
+ }
+ for (const SharedLibraryAtom *atom : atomFile.sharedLibrary()) {
+ AtomAndIndex ai = { atom, 0, N_EXT };
+ undefs.push_back(ai);
+ }
+ std::sort(undefs.begin(), undefs.end(), AtomSorter());
+ const uint32_t start = file.globalSymbols.size() + file.localSymbols.size();
+ for (AtomAndIndex &ai : undefs) {
+ Symbol sym;
+ uint16_t desc = 0;
+ if (!rMode) {
+ uint8_t ordinal = 0;
+ if (!_ctx.useFlatNamespace())
+ ordinal = dylibOrdinal(dyn_cast<SharedLibraryAtom>(ai.atom));
+ llvm::MachO::SET_LIBRARY_ORDINAL(desc, ordinal);
+ }
+ sym.name = ai.atom->name();
+ sym.type = N_UNDF;
+ sym.scope = ai.scope;
+ sym.sect = 0;
+ sym.desc = desc;
+ sym.value = 0;
+ _atomToSymbolIndex[ai.atom] = file.undefinedSymbols.size() + start;
+ file.undefinedSymbols.push_back(sym);
+ }
+
+ return llvm::Error::success();
+}
+
+const Atom *Util::targetOfLazyPointer(const DefinedAtom *lpAtom) {
+ for (const Reference *ref : *lpAtom) {
+ if (_archHandler.isLazyPointer(*ref)) {
+ return ref->target();
+ }
+ }
+ return nullptr;
+}
+
+const Atom *Util::targetOfStub(const DefinedAtom *stubAtom) {
+ for (const Reference *ref : *stubAtom) {
+ if (const Atom *ta = ref->target()) {
+ if (const DefinedAtom *lpAtom = dyn_cast<DefinedAtom>(ta)) {
+ const Atom *target = targetOfLazyPointer(lpAtom);
+ if (target)
+ return target;
+ }
+ }
+ }
+ return nullptr;
+}
+
+void Util::addIndirectSymbols(const lld::File &atomFile, NormalizedFile &file) {
+ for (SectionInfo *si : _sectionInfos) {
+ Section &normSect = file.sections[si->normalizedSectionIndex];
+ switch (si->type) {
+ case llvm::MachO::S_NON_LAZY_SYMBOL_POINTERS:
+ for (const AtomInfo &info : si->atomsAndOffsets) {
+ bool foundTarget = false;
+ for (const Reference *ref : *info.atom) {
+ const Atom *target = ref->target();
+ if (target) {
+ if (isa<const SharedLibraryAtom>(target)) {
+ uint32_t index = _atomToSymbolIndex[target];
+ normSect.indirectSymbols.push_back(index);
+ foundTarget = true;
+ } else {
+ normSect.indirectSymbols.push_back(
+ llvm::MachO::INDIRECT_SYMBOL_LOCAL);
+ }
+ }
+ }
+ if (!foundTarget) {
+ normSect.indirectSymbols.push_back(
+ llvm::MachO::INDIRECT_SYMBOL_ABS);
+ }
+ }
+ break;
+ case llvm::MachO::S_LAZY_SYMBOL_POINTERS:
+ for (const AtomInfo &info : si->atomsAndOffsets) {
+ const Atom *target = targetOfLazyPointer(info.atom);
+ if (target) {
+ uint32_t index = _atomToSymbolIndex[target];
+ normSect.indirectSymbols.push_back(index);
+ }
+ }
+ break;
+ case llvm::MachO::S_SYMBOL_STUBS:
+ for (const AtomInfo &info : si->atomsAndOffsets) {
+ const Atom *target = targetOfStub(info.atom);
+ if (target) {
+ uint32_t index = _atomToSymbolIndex[target];
+ normSect.indirectSymbols.push_back(index);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void Util::addDependentDylibs(const lld::File &atomFile,
+ NormalizedFile &nFile) {
+ // Scan all imported symbols and build up list of dylibs they are from.
+ int ordinal = 1;
+ for (const auto *dylib : _ctx.allDylibs()) {
+ DylibPathToInfo::iterator pos = _dylibInfo.find(dylib->installName());
+ if (pos == _dylibInfo.end()) {
+ DylibInfo info;
+ bool flatNamespaceAtom = dylib == _ctx.flatNamespaceFile();
+
+ // If we're in -flat_namespace mode (or this atom came from the flat
+ // namespace file under -undefined dynamic_lookup) then use the flat
+ // lookup ordinal.
+ if (flatNamespaceAtom || _ctx.useFlatNamespace())
+ info.ordinal = BIND_SPECIAL_DYLIB_FLAT_LOOKUP;
+ else
+ info.ordinal = ordinal++;
+ info.hasWeak = false;
+ info.hasNonWeak = !info.hasWeak;
+ _dylibInfo[dylib->installName()] = info;
+
+ // Unless this was a flat_namespace atom, record the source dylib.
+ if (!flatNamespaceAtom) {
+ DependentDylib depInfo;
+ depInfo.path = dylib->installName();
+ depInfo.kind = llvm::MachO::LC_LOAD_DYLIB;
+ depInfo.currentVersion = _ctx.dylibCurrentVersion(dylib->path());
+ depInfo.compatVersion = _ctx.dylibCompatVersion(dylib->path());
+ nFile.dependentDylibs.push_back(depInfo);
+ }
+ } else {
+ pos->second.hasWeak = false;
+ pos->second.hasNonWeak = !pos->second.hasWeak;
+ }
+ }
+ // Automatically weak link dylib in which all symbols are weak (canBeNull).
+ for (DependentDylib &dep : nFile.dependentDylibs) {
+ DylibInfo &info = _dylibInfo[dep.path];
+ if (info.hasWeak && !info.hasNonWeak)
+ dep.kind = llvm::MachO::LC_LOAD_WEAK_DYLIB;
+ else if (_ctx.isUpwardDylib(dep.path))
+ dep.kind = llvm::MachO::LC_LOAD_UPWARD_DYLIB;
+ }
+}
+
+int Util::dylibOrdinal(const SharedLibraryAtom *sa) {
+ return _dylibInfo[sa->loadName()].ordinal;
+}
+
+void Util::segIndexForSection(const SectionInfo *sect, uint8_t &segmentIndex,
+ uint64_t &segmentStartAddr) {
+ segmentIndex = 0;
+ for (const SegmentInfo *seg : _segmentInfos) {
+ if ((seg->address <= sect->address)
+ && (seg->address+seg->size >= sect->address+sect->size)) {
+ segmentStartAddr = seg->address;
+ return;
+ }
+ ++segmentIndex;
+ }
+ llvm_unreachable("section not in any segment");
+}
+
+uint32_t Util::sectionIndexForAtom(const Atom *atom) {
+ uint64_t address = _atomToAddress[atom];
+ for (const SectionInfo *si : _sectionInfos) {
+ if ((si->address <= address) && (address < si->address+si->size))
+ return si->finalSectionIndex;
+ }
+ llvm_unreachable("atom not in any section");
+}
+
+void Util::addSectionRelocs(const lld::File &, NormalizedFile &file) {
+ if (_ctx.outputMachOType() != llvm::MachO::MH_OBJECT)
+ return;
+
+ // Utility function for ArchHandler to find symbol index for an atom.
+ auto symIndexForAtom = [&] (const Atom &atom) -> uint32_t {
+ auto pos = _atomToSymbolIndex.find(&atom);
+ assert(pos != _atomToSymbolIndex.end());
+ return pos->second;
+ };
+
+ // Utility function for ArchHandler to find section index for an atom.
+ auto sectIndexForAtom = [&] (const Atom &atom) -> uint32_t {
+ return sectionIndexForAtom(&atom);
+ };
+
+ // Utility function for ArchHandler to find address of atom in output file.
+ auto addressForAtom = [&] (const Atom &atom) -> uint64_t {
+ auto pos = _atomToAddress.find(&atom);
+ assert(pos != _atomToAddress.end());
+ return pos->second;
+ };
+
+ for (SectionInfo *si : _sectionInfos) {
+ Section &normSect = file.sections[si->normalizedSectionIndex];
+ for (const AtomInfo &info : si->atomsAndOffsets) {
+ const DefinedAtom *atom = info.atom;
+ for (const Reference *ref : *atom) {
+ // Skip emitting relocs for sections which are always able to be
+ // implicitly regenerated and where the relocation targets an address
+ // which is defined.
+ if (si->relocsToDefinedCanBeImplicit && isa<DefinedAtom>(ref->target()))
+ continue;
+ _archHandler.appendSectionRelocations(*atom, info.offsetInSection, *ref,
+ symIndexForAtom,
+ sectIndexForAtom,
+ addressForAtom,
+ normSect.relocations);
+ }
+ }
+ }
+}
+
+void Util::addFunctionStarts(const lld::File &, NormalizedFile &file) {
+ if (!_ctx.generateFunctionStartsLoadCommand())
+ return;
+ file.functionStarts.reserve(8192);
+ // Delta compress function starts, starting with the mach header symbol.
+ const uint64_t badAddress = ~0ULL;
+ uint64_t addr = badAddress;
+ for (SectionInfo *si : _sectionInfos) {
+ for (const AtomInfo &info : si->atomsAndOffsets) {
+ auto type = info.atom->contentType();
+ if (type == DefinedAtom::typeMachHeader) {
+ addr = _atomToAddress[info.atom];
+ continue;
+ }
+ if (type != DefinedAtom::typeCode)
+ continue;
+ assert(addr != badAddress && "Missing mach header symbol");
+ // Skip atoms which have 0 size. This is so that LC_FUNCTION_STARTS
+ // can't spill in to the next section.
+ if (!info.atom->size())
+ continue;
+ uint64_t nextAddr = _atomToAddress[info.atom];
+ if (_archHandler.isThumbFunction(*info.atom))
+ nextAddr |= 1;
+ uint64_t delta = nextAddr - addr;
+ if (delta) {
+ ByteBuffer buffer;
+ buffer.append_uleb128(delta);
+ file.functionStarts.insert(file.functionStarts.end(), buffer.bytes(),
+ buffer.bytes() + buffer.size());
+ }
+ addr = nextAddr;
+ }
+ }
+
+ // Null terminate, and pad to pointer size for this arch.
+ file.functionStarts.push_back(0);
+
+ auto size = file.functionStarts.size();
+ for (unsigned i = size, e = llvm::alignTo(size, _ctx.is64Bit() ? 8 : 4);
+ i != e; ++i)
+ file.functionStarts.push_back(0);
+}
+
+void Util::buildDataInCodeArray(const lld::File &, NormalizedFile &file) {
+ if (!_ctx.generateDataInCodeLoadCommand())
+ return;
+ for (SectionInfo *si : _sectionInfos) {
+ for (const AtomInfo &info : si->atomsAndOffsets) {
+ // Atoms that contain data-in-code have "transition" references
+ // which mark a point where the embedded data starts of ends.
+ // This needs to be converted to the mach-o format which is an array
+ // of data-in-code ranges.
+ uint32_t startOffset = 0;
+ DataRegionType mode = DataRegionType(0);
+ for (const Reference *ref : *info.atom) {
+ if (ref->kindNamespace() != Reference::KindNamespace::mach_o)
+ continue;
+ if (_archHandler.isDataInCodeTransition(ref->kindValue())) {
+ DataRegionType nextMode = (DataRegionType)ref->addend();
+ if (mode != nextMode) {
+ if (mode != 0) {
+ // Found end data range, so make range entry.
+ DataInCode entry;
+ entry.offset = si->address + info.offsetInSection + startOffset;
+ entry.length = ref->offsetInAtom() - startOffset;
+ entry.kind = mode;
+ file.dataInCode.push_back(entry);
+ }
+ }
+ mode = nextMode;
+ startOffset = ref->offsetInAtom();
+ }
+ }
+ if (mode != 0) {
+ // Function ends with data (no end transition).
+ DataInCode entry;
+ entry.offset = si->address + info.offsetInSection + startOffset;
+ entry.length = info.atom->size() - startOffset;
+ entry.kind = mode;
+ file.dataInCode.push_back(entry);
+ }
+ }
+ }
+}
+
+void Util::addRebaseAndBindingInfo(const lld::File &atomFile,
+ NormalizedFile &nFile) {
+ if (_ctx.outputMachOType() == llvm::MachO::MH_OBJECT)
+ return;
+
+ uint8_t segmentIndex;
+ uint64_t segmentStartAddr;
+ uint32_t offsetInBindInfo = 0;
+
+ for (SectionInfo *sect : _sectionInfos) {
+ segIndexForSection(sect, segmentIndex, segmentStartAddr);
+ for (const AtomInfo &info : sect->atomsAndOffsets) {
+ const DefinedAtom *atom = info.atom;
+ for (const Reference *ref : *atom) {
+ uint64_t segmentOffset = _atomToAddress[atom] + ref->offsetInAtom()
+ - segmentStartAddr;
+ const Atom* targ = ref->target();
+ if (_archHandler.isPointer(*ref)) {
+ // A pointer to a DefinedAtom requires rebasing.
+ if (isa<DefinedAtom>(targ)) {
+ RebaseLocation rebase;
+ rebase.segIndex = segmentIndex;
+ rebase.segOffset = segmentOffset;
+ rebase.kind = llvm::MachO::REBASE_TYPE_POINTER;
+ nFile.rebasingInfo.push_back(rebase);
+ }
+ // A pointer to an SharedLibraryAtom requires binding.
+ if (const SharedLibraryAtom *sa = dyn_cast<SharedLibraryAtom>(targ)) {
+ BindLocation bind;
+ bind.segIndex = segmentIndex;
+ bind.segOffset = segmentOffset;
+ bind.kind = llvm::MachO::BIND_TYPE_POINTER;
+ bind.canBeNull = sa->canBeNullAtRuntime();
+ bind.ordinal = dylibOrdinal(sa);
+ bind.symbolName = targ->name();
+ bind.addend = ref->addend();
+ nFile.bindingInfo.push_back(bind);
+ }
+ }
+ else if (_archHandler.isLazyPointer(*ref)) {
+ BindLocation bind;
+ if (const SharedLibraryAtom *sa = dyn_cast<SharedLibraryAtom>(targ)) {
+ bind.ordinal = dylibOrdinal(sa);
+ } else {
+ bind.ordinal = llvm::MachO::BIND_SPECIAL_DYLIB_SELF;
+ }
+ bind.segIndex = segmentIndex;
+ bind.segOffset = segmentOffset;
+ bind.kind = llvm::MachO::BIND_TYPE_POINTER;
+ bind.canBeNull = false; //sa->canBeNullAtRuntime();
+ bind.symbolName = targ->name();
+ bind.addend = ref->addend();
+ nFile.lazyBindingInfo.push_back(bind);
+
+ // Now that we know the segmentOffset and the ordinal attribute,
+ // we can fix the helper's code
+
+ fixLazyReferenceImm(atom, offsetInBindInfo, nFile);
+
+ // 5 bytes for opcodes + variable sizes (target name + \0 and offset
+ // encode's size)
+ offsetInBindInfo +=
+ 6 + targ->name().size() + llvm::getULEB128Size(bind.segOffset);
+ if (bind.ordinal > BIND_IMMEDIATE_MASK)
+ offsetInBindInfo += llvm::getULEB128Size(bind.ordinal);
+ }
+ }
+ }
+ }
+}
+
+void Util::fixLazyReferenceImm(const DefinedAtom *atom, uint32_t offset,
+ NormalizedFile &file) {
+ for (const auto &ref : *atom) {
+ const DefinedAtom *da = dyn_cast<DefinedAtom>(ref->target());
+ if (da == nullptr)
+ return;
+
+ const Reference *helperRef = nullptr;
+ for (const Reference *hr : *da) {
+ if (hr->kindValue() == _archHandler.lazyImmediateLocationKind()) {
+ helperRef = hr;
+ break;
+ }
+ }
+ if (helperRef == nullptr)
+ continue;
+
+ // TODO: maybe get the fixed atom content from _archHandler ?
+ for (SectionInfo *sectInfo : _sectionInfos) {
+ for (const AtomInfo &atomInfo : sectInfo->atomsAndOffsets) {
+ if (atomInfo.atom == helperRef->target()) {
+ auto sectionContent =
+ file.sections[sectInfo->normalizedSectionIndex].content;
+ uint8_t *rawb =
+ file.ownedAllocations.Allocate<uint8_t>(sectionContent.size());
+ llvm::MutableArrayRef<uint8_t> newContent{rawb,
+ sectionContent.size()};
+ std::copy(sectionContent.begin(), sectionContent.end(),
+ newContent.begin());
+ llvm::support::ulittle32_t *loc =
+ reinterpret_cast<llvm::support::ulittle32_t *>(
+ &newContent[atomInfo.offsetInSection +
+ helperRef->offsetInAtom()]);
+ *loc = offset;
+ file.sections[sectInfo->normalizedSectionIndex].content = newContent;
+ }
+ }
+ }
+ }
+}
+
+void Util::addExportInfo(const lld::File &atomFile, NormalizedFile &nFile) {
+ if (_ctx.outputMachOType() == llvm::MachO::MH_OBJECT)
+ return;
+
+ for (SectionInfo *sect : _sectionInfos) {
+ for (const AtomInfo &info : sect->atomsAndOffsets) {
+ const DefinedAtom *atom = info.atom;
+ if (atom->scope() != Atom::scopeGlobal)
+ continue;
+ if (_ctx.exportRestrictMode()) {
+ if (!_ctx.exportSymbolNamed(atom->name()))
+ continue;
+ }
+ Export exprt;
+ exprt.name = atom->name();
+ exprt.offset = _atomToAddress[atom] - _ctx.baseAddress();
+ exprt.kind = EXPORT_SYMBOL_FLAGS_KIND_REGULAR;
+ if (atom->merge() == DefinedAtom::mergeAsWeak)
+ exprt.flags = EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION;
+ else
+ exprt.flags = 0;
+ exprt.otherOffset = 0;
+ exprt.otherName = StringRef();
+ nFile.exportInfo.push_back(exprt);
+ }
+ }
+}
+
+uint32_t Util::fileFlags() {
+ // FIXME: these need to determined at runtime.
+ if (_ctx.outputMachOType() == MH_OBJECT) {
+ return _subsectionsViaSymbols ? MH_SUBSECTIONS_VIA_SYMBOLS : 0;
+ } else {
+ uint32_t flags = MH_DYLDLINK;
+ if (!_ctx.useFlatNamespace())
+ flags |= MH_TWOLEVEL | MH_NOUNDEFS;
+ if ((_ctx.outputMachOType() == MH_EXECUTE) && _ctx.PIE())
+ flags |= MH_PIE;
+ if (_hasTLVDescriptors)
+ flags |= (MH_PIE | MH_HAS_TLV_DESCRIPTORS);
+ return flags;
+ }
+}
+
+} // end anonymous namespace
+
+namespace lld {
+namespace mach_o {
+namespace normalized {
+
+/// Convert a set of Atoms into a normalized mach-o file.
+llvm::Expected<std::unique_ptr<NormalizedFile>>
+normalizedFromAtoms(const lld::File &atomFile,
+ const MachOLinkingContext &context) {
+ // The util object buffers info until the normalized file can be made.
+ Util util(context);
+ util.processDefinedAtoms(atomFile);
+ util.organizeSections();
+
+ std::unique_ptr<NormalizedFile> f(new NormalizedFile());
+ NormalizedFile &normFile = *f.get();
+ normFile.arch = context.arch();
+ normFile.fileType = context.outputMachOType();
+ normFile.flags = util.fileFlags();
+ normFile.stackSize = context.stackSize();
+ normFile.installName = context.installName();
+ normFile.currentVersion = context.currentVersion();
+ normFile.compatVersion = context.compatibilityVersion();
+ normFile.os = context.os();
+
+ // If we are emitting an object file, then the min version is the maximum
+ // of the min's of all the source files and the cmdline.
+ if (normFile.fileType == llvm::MachO::MH_OBJECT)
+ normFile.minOSverson = std::max(context.osMinVersion(), util.minVersion());
+ else
+ normFile.minOSverson = context.osMinVersion();
+
+ normFile.minOSVersionKind = util.minVersionCommandType();
+
+ normFile.sdkVersion = context.sdkVersion();
+ normFile.sourceVersion = context.sourceVersion();
+
+ if (context.generateVersionLoadCommand() &&
+ context.os() != MachOLinkingContext::OS::unknown)
+ normFile.hasMinVersionLoadCommand = true;
+ else if (normFile.fileType == llvm::MachO::MH_OBJECT &&
+ util.allSourceFilesHaveMinVersions() &&
+ ((normFile.os != MachOLinkingContext::OS::unknown) ||
+ util.minVersionCommandType())) {
+ // If we emit an object file, then it should contain a min version load
+ // command if all of the source files also contained min version commands.
+ // Also, we either need to have a platform, or found a platform from the
+ // source object files.
+ normFile.hasMinVersionLoadCommand = true;
+ }
+ normFile.generateDataInCodeLoadCommand =
+ context.generateDataInCodeLoadCommand();
+ normFile.pageSize = context.pageSize();
+ normFile.rpaths = context.rpaths();
+ util.addDependentDylibs(atomFile, normFile);
+ util.copySegmentInfo(normFile);
+ util.copySectionInfo(normFile);
+ util.assignAddressesToSections(normFile);
+ util.buildAtomToAddressMap();
+ if (auto err = util.synthesizeDebugNotes(normFile))
+ return std::move(err);
+ util.updateSectionInfo(normFile);
+ util.copySectionContent(normFile);
+ if (auto ec = util.addSymbols(atomFile, normFile)) {
+ return std::move(ec);
+ }
+ util.addIndirectSymbols(atomFile, normFile);
+ util.addRebaseAndBindingInfo(atomFile, normFile);
+ util.addExportInfo(atomFile, normFile);
+ util.addSectionRelocs(atomFile, normFile);
+ util.addFunctionStarts(atomFile, normFile);
+ util.buildDataInCodeArray(atomFile, normFile);
+ util.copyEntryPointAddress(normFile);
+
+ return std::move(f);
+}
+
+} // namespace normalized
+} // namespace mach_o
+} // namespace lld
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
new file mode 100644
index 000000000000..473de894894e
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
@@ -0,0 +1,1635 @@
+//===- lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp --------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+///
+/// \file Converts from in-memory normalized mach-o to in-memory Atoms.
+///
+/// +------------+
+/// | normalized |
+/// +------------+
+/// |
+/// |
+/// v
+/// +-------+
+/// | Atoms |
+/// +-------+
+
+#include "ArchHandler.h"
+#include "Atoms.h"
+#include "File.h"
+#include "MachONormalizedFile.h"
+#include "MachONormalizedFileBinaryUtils.h"
+#include "lld/Common/LLVM.h"
+#include "lld/Core/Error.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
+
+#define DEBUG_TYPE "normalized-file-to-atoms"
+
+namespace lld {
+namespace mach_o {
+
+
+namespace { // anonymous
+
+
+#define ENTRY(seg, sect, type, atomType) \
+ {seg, sect, type, DefinedAtom::atomType }
+
+struct MachORelocatableSectionToAtomType {
+ StringRef segmentName;
+ StringRef sectionName;
+ SectionType sectionType;
+ DefinedAtom::ContentType atomType;
+};
+
+const MachORelocatableSectionToAtomType sectsToAtomType[] = {
+ ENTRY("__TEXT", "__text", S_REGULAR, typeCode),
+ ENTRY("__TEXT", "__text", S_REGULAR, typeResolver),
+ ENTRY("__TEXT", "__cstring", S_CSTRING_LITERALS, typeCString),
+ ENTRY("", "", S_CSTRING_LITERALS, typeCString),
+ ENTRY("__TEXT", "__ustring", S_REGULAR, typeUTF16String),
+ ENTRY("__TEXT", "__const", S_REGULAR, typeConstant),
+ ENTRY("__TEXT", "__const_coal", S_COALESCED, typeConstant),
+ ENTRY("__TEXT", "__eh_frame", S_COALESCED, typeCFI),
+ ENTRY("__TEXT", "__eh_frame", S_REGULAR, typeCFI),
+ ENTRY("__TEXT", "__literal4", S_4BYTE_LITERALS, typeLiteral4),
+ ENTRY("__TEXT", "__literal8", S_8BYTE_LITERALS, typeLiteral8),
+ ENTRY("__TEXT", "__literal16", S_16BYTE_LITERALS, typeLiteral16),
+ ENTRY("__TEXT", "__gcc_except_tab", S_REGULAR, typeLSDA),
+ ENTRY("__DATA", "__data", S_REGULAR, typeData),
+ ENTRY("__DATA", "__datacoal_nt", S_COALESCED, typeData),
+ ENTRY("__DATA", "__const", S_REGULAR, typeConstData),
+ ENTRY("__DATA", "__cfstring", S_REGULAR, typeCFString),
+ ENTRY("__DATA", "__mod_init_func", S_MOD_INIT_FUNC_POINTERS,
+ typeInitializerPtr),
+ ENTRY("__DATA", "__mod_term_func", S_MOD_TERM_FUNC_POINTERS,
+ typeTerminatorPtr),
+ ENTRY("__DATA", "__got", S_NON_LAZY_SYMBOL_POINTERS,
+ typeGOT),
+ ENTRY("__DATA", "__bss", S_ZEROFILL, typeZeroFill),
+ ENTRY("", "", S_NON_LAZY_SYMBOL_POINTERS,
+ typeGOT),
+ ENTRY("__DATA", "__interposing", S_INTERPOSING, typeInterposingTuples),
+ ENTRY("__DATA", "__thread_vars", S_THREAD_LOCAL_VARIABLES,
+ typeThunkTLV),
+ ENTRY("__DATA", "__thread_data", S_THREAD_LOCAL_REGULAR, typeTLVInitialData),
+ ENTRY("__DATA", "__thread_bss", S_THREAD_LOCAL_ZEROFILL,
+ typeTLVInitialZeroFill),
+ ENTRY("__DATA", "__objc_imageinfo", S_REGULAR, typeObjCImageInfo),
+ ENTRY("__DATA", "__objc_catlist", S_REGULAR, typeObjC2CategoryList),
+ ENTRY("", "", S_INTERPOSING, typeInterposingTuples),
+ ENTRY("__LD", "__compact_unwind", S_REGULAR,
+ typeCompactUnwindInfo),
+ ENTRY("", "", S_REGULAR, typeUnknown)
+};
+#undef ENTRY
+
+
+/// Figures out ContentType of a mach-o section.
+DefinedAtom::ContentType atomTypeFromSection(const Section &section,
+ bool &customSectionName) {
+ // First look for match of name and type. Empty names in table are wildcards.
+ customSectionName = false;
+ for (const MachORelocatableSectionToAtomType *p = sectsToAtomType ;
+ p->atomType != DefinedAtom::typeUnknown; ++p) {
+ if (p->sectionType != section.type)
+ continue;
+ if (!p->segmentName.equals(section.segmentName) && !p->segmentName.empty())
+ continue;
+ if (!p->sectionName.equals(section.sectionName) && !p->sectionName.empty())
+ continue;
+ customSectionName = p->segmentName.empty() && p->sectionName.empty();
+ return p->atomType;
+ }
+ // Look for code denoted by section attributes
+ if (section.attributes & S_ATTR_PURE_INSTRUCTIONS)
+ return DefinedAtom::typeCode;
+
+ return DefinedAtom::typeUnknown;
+}
+
+enum AtomizeModel {
+ atomizeAtSymbols,
+ atomizeFixedSize,
+ atomizePointerSize,
+ atomizeUTF8,
+ atomizeUTF16,
+ atomizeCFI,
+ atomizeCU,
+ atomizeCFString
+};
+
+/// Returns info on how to atomize a section of the specified ContentType.
+void sectionParseInfo(DefinedAtom::ContentType atomType,
+ unsigned int &sizeMultiple,
+ DefinedAtom::Scope &scope,
+ DefinedAtom::Merge &merge,
+ AtomizeModel &atomizeModel) {
+ struct ParseInfo {
+ DefinedAtom::ContentType atomType;
+ unsigned int sizeMultiple;
+ DefinedAtom::Scope scope;
+ DefinedAtom::Merge merge;
+ AtomizeModel atomizeModel;
+ };
+
+ #define ENTRY(type, size, scope, merge, model) \
+ {DefinedAtom::type, size, DefinedAtom::scope, DefinedAtom::merge, model }
+
+ static const ParseInfo parseInfo[] = {
+ ENTRY(typeCode, 1, scopeGlobal, mergeNo,
+ atomizeAtSymbols),
+ ENTRY(typeData, 1, scopeGlobal, mergeNo,
+ atomizeAtSymbols),
+ ENTRY(typeConstData, 1, scopeGlobal, mergeNo,
+ atomizeAtSymbols),
+ ENTRY(typeZeroFill, 1, scopeGlobal, mergeNo,
+ atomizeAtSymbols),
+ ENTRY(typeConstant, 1, scopeGlobal, mergeNo,
+ atomizeAtSymbols),
+ ENTRY(typeCString, 1, scopeLinkageUnit, mergeByContent,
+ atomizeUTF8),
+ ENTRY(typeUTF16String, 1, scopeLinkageUnit, mergeByContent,
+ atomizeUTF16),
+ ENTRY(typeCFI, 4, scopeTranslationUnit, mergeNo,
+ atomizeCFI),
+ ENTRY(typeLiteral4, 4, scopeLinkageUnit, mergeByContent,
+ atomizeFixedSize),
+ ENTRY(typeLiteral8, 8, scopeLinkageUnit, mergeByContent,
+ atomizeFixedSize),
+ ENTRY(typeLiteral16, 16, scopeLinkageUnit, mergeByContent,
+ atomizeFixedSize),
+ ENTRY(typeCFString, 4, scopeLinkageUnit, mergeByContent,
+ atomizeCFString),
+ ENTRY(typeInitializerPtr, 4, scopeTranslationUnit, mergeNo,
+ atomizePointerSize),
+ ENTRY(typeTerminatorPtr, 4, scopeTranslationUnit, mergeNo,
+ atomizePointerSize),
+ ENTRY(typeCompactUnwindInfo, 4, scopeTranslationUnit, mergeNo,
+ atomizeCU),
+ ENTRY(typeGOT, 4, scopeLinkageUnit, mergeByContent,
+ atomizePointerSize),
+ ENTRY(typeObjC2CategoryList, 4, scopeTranslationUnit, mergeByContent,
+ atomizePointerSize),
+ ENTRY(typeUnknown, 1, scopeGlobal, mergeNo,
+ atomizeAtSymbols)
+ };
+ #undef ENTRY
+ const int tableLen = sizeof(parseInfo) / sizeof(ParseInfo);
+ for (int i=0; i < tableLen; ++i) {
+ if (parseInfo[i].atomType == atomType) {
+ sizeMultiple = parseInfo[i].sizeMultiple;
+ scope = parseInfo[i].scope;
+ merge = parseInfo[i].merge;
+ atomizeModel = parseInfo[i].atomizeModel;
+ return;
+ }
+ }
+
+ // Unknown type is atomized by symbols.
+ sizeMultiple = 1;
+ scope = DefinedAtom::scopeGlobal;
+ merge = DefinedAtom::mergeNo;
+ atomizeModel = atomizeAtSymbols;
+}
+
+
+Atom::Scope atomScope(uint8_t scope) {
+ switch (scope) {
+ case N_EXT:
+ return Atom::scopeGlobal;
+ case N_PEXT:
+ case N_PEXT | N_EXT:
+ return Atom::scopeLinkageUnit;
+ case 0:
+ return Atom::scopeTranslationUnit;
+ }
+ llvm_unreachable("unknown scope value!");
+}
+
+void appendSymbolsInSection(const std::vector<Symbol> &inSymbols,
+ uint32_t sectionIndex,
+ SmallVector<const Symbol *, 64> &outSyms) {
+ for (const Symbol &sym : inSymbols) {
+ // Only look at definition symbols.
+ if ((sym.type & N_TYPE) != N_SECT)
+ continue;
+ if (sym.sect != sectionIndex)
+ continue;
+ outSyms.push_back(&sym);
+ }
+}
+
+void atomFromSymbol(DefinedAtom::ContentType atomType, const Section &section,
+ MachOFile &file, uint64_t symbolAddr, StringRef symbolName,
+ uint16_t symbolDescFlags, Atom::Scope symbolScope,
+ uint64_t nextSymbolAddr, bool scatterable, bool copyRefs) {
+ // Mach-O symbol table does have size in it. Instead the size is the
+ // difference between this and the next symbol.
+ uint64_t size = nextSymbolAddr - symbolAddr;
+ uint64_t offset = symbolAddr - section.address;
+ bool noDeadStrip = (symbolDescFlags & N_NO_DEAD_STRIP) || !scatterable;
+ if (isZeroFillSection(section.type)) {
+ file.addZeroFillDefinedAtom(symbolName, symbolScope, offset, size,
+ noDeadStrip, copyRefs, &section);
+ } else {
+ DefinedAtom::Merge merge = (symbolDescFlags & N_WEAK_DEF)
+ ? DefinedAtom::mergeAsWeak : DefinedAtom::mergeNo;
+ bool thumb = (symbolDescFlags & N_ARM_THUMB_DEF);
+ if (atomType == DefinedAtom::typeUnknown) {
+ // Mach-O needs a segment and section name. Concatentate those two
+ // with a / separator (e.g. "seg/sect") to fit into the lld model
+ // of just a section name.
+ std::string segSectName = section.segmentName.str()
+ + "/" + section.sectionName.str();
+ file.addDefinedAtomInCustomSection(symbolName, symbolScope, atomType,
+ merge, thumb, noDeadStrip, offset,
+ size, segSectName, true, &section);
+ } else {
+ if ((atomType == lld::DefinedAtom::typeCode) &&
+ (symbolDescFlags & N_SYMBOL_RESOLVER)) {
+ atomType = lld::DefinedAtom::typeResolver;
+ }
+ file.addDefinedAtom(symbolName, symbolScope, atomType, merge,
+ offset, size, thumb, noDeadStrip, copyRefs, &section);
+ }
+ }
+}
+
+llvm::Error processSymboledSection(DefinedAtom::ContentType atomType,
+ const Section &section,
+ const NormalizedFile &normalizedFile,
+ MachOFile &file, bool scatterable,
+ bool copyRefs) {
+ // Find section's index.
+ uint32_t sectIndex = 1;
+ for (auto &sect : normalizedFile.sections) {
+ if (&sect == &section)
+ break;
+ ++sectIndex;
+ }
+
+ // Find all symbols in this section.
+ SmallVector<const Symbol *, 64> symbols;
+ appendSymbolsInSection(normalizedFile.globalSymbols, sectIndex, symbols);
+ appendSymbolsInSection(normalizedFile.localSymbols, sectIndex, symbols);
+
+ // Sort symbols.
+ std::sort(symbols.begin(), symbols.end(),
+ [](const Symbol *lhs, const Symbol *rhs) -> bool {
+ if (lhs == rhs)
+ return false;
+ // First by address.
+ uint64_t lhsAddr = lhs->value;
+ uint64_t rhsAddr = rhs->value;
+ if (lhsAddr != rhsAddr)
+ return lhsAddr < rhsAddr;
+ // If same address, one is an alias so sort by scope.
+ Atom::Scope lScope = atomScope(lhs->scope);
+ Atom::Scope rScope = atomScope(rhs->scope);
+ if (lScope != rScope)
+ return lScope < rScope;
+ // If same address and scope, see if one might be better as
+ // the alias.
+ bool lPrivate = (lhs->name.front() == 'l');
+ bool rPrivate = (rhs->name.front() == 'l');
+ if (lPrivate != rPrivate)
+ return lPrivate;
+ // If same address and scope, sort by name.
+ return lhs->name < rhs->name;
+ });
+
+ // Debug logging of symbols.
+ //for (const Symbol *sym : symbols)
+ // llvm::errs() << " sym: "
+ // << llvm::format("0x%08llx ", (uint64_t)sym->value)
+ // << ", " << sym->name << "\n";
+
+ // If section has no symbols and no content, there are no atoms.
+ if (symbols.empty() && section.content.empty())
+ return llvm::Error::success();
+
+ if (symbols.empty()) {
+ // Section has no symbols, put all content in one anoymous atom.
+ atomFromSymbol(atomType, section, file, section.address, StringRef(),
+ 0, Atom::scopeTranslationUnit,
+ section.address + section.content.size(),
+ scatterable, copyRefs);
+ }
+ else if (symbols.front()->value != section.address) {
+ // Section has anonymous content before first symbol.
+ atomFromSymbol(atomType, section, file, section.address, StringRef(),
+ 0, Atom::scopeTranslationUnit, symbols.front()->value,
+ scatterable, copyRefs);
+ }
+
+ const Symbol *lastSym = nullptr;
+ for (const Symbol *sym : symbols) {
+ if (lastSym != nullptr) {
+ // Ignore any assembler added "ltmpNNN" symbol at start of section
+ // if there is another symbol at the start.
+ if ((lastSym->value != sym->value)
+ || lastSym->value != section.address
+ || !lastSym->name.startswith("ltmp")) {
+ atomFromSymbol(atomType, section, file, lastSym->value, lastSym->name,
+ lastSym->desc, atomScope(lastSym->scope), sym->value,
+ scatterable, copyRefs);
+ }
+ }
+ lastSym = sym;
+ }
+ if (lastSym != nullptr) {
+ atomFromSymbol(atomType, section, file, lastSym->value, lastSym->name,
+ lastSym->desc, atomScope(lastSym->scope),
+ section.address + section.content.size(),
+ scatterable, copyRefs);
+ }
+
+ // If object built without .subsections_via_symbols, add reference chain.
+ if (!scatterable) {
+ MachODefinedAtom *prevAtom = nullptr;
+ file.eachAtomInSection(section,
+ [&](MachODefinedAtom *atom, uint64_t offset)->void {
+ if (prevAtom)
+ prevAtom->addReference(Reference::KindNamespace::all,
+ Reference::KindArch::all,
+ Reference::kindLayoutAfter, 0, atom, 0);
+ prevAtom = atom;
+ });
+ }
+
+ return llvm::Error::success();
+}
+
+llvm::Error processSection(DefinedAtom::ContentType atomType,
+ const Section &section,
+ bool customSectionName,
+ const NormalizedFile &normalizedFile,
+ MachOFile &file, bool scatterable,
+ bool copyRefs) {
+ const bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch);
+ const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
+
+ // Get info on how to atomize section.
+ unsigned int sizeMultiple;
+ DefinedAtom::Scope scope;
+ DefinedAtom::Merge merge;
+ AtomizeModel atomizeModel;
+ sectionParseInfo(atomType, sizeMultiple, scope, merge, atomizeModel);
+
+ // Validate section size.
+ if ((section.content.size() % sizeMultiple) != 0)
+ return llvm::make_error<GenericError>(Twine("Section ")
+ + section.segmentName
+ + "/" + section.sectionName
+ + " has size ("
+ + Twine(section.content.size())
+ + ") which is not a multiple of "
+ + Twine(sizeMultiple));
+
+ if (atomizeModel == atomizeAtSymbols) {
+ // Break section up into atoms each with a fixed size.
+ return processSymboledSection(atomType, section, normalizedFile, file,
+ scatterable, copyRefs);
+ } else {
+ unsigned int size;
+ for (unsigned int offset = 0, e = section.content.size(); offset != e;) {
+ switch (atomizeModel) {
+ case atomizeFixedSize:
+ // Break section up into atoms each with a fixed size.
+ size = sizeMultiple;
+ break;
+ case atomizePointerSize:
+ // Break section up into atoms each the size of a pointer.
+ size = is64 ? 8 : 4;
+ break;
+ case atomizeUTF8:
+ // Break section up into zero terminated c-strings.
+ size = 0;
+ for (unsigned int i = offset; i < e; ++i) {
+ if (section.content[i] == 0) {
+ size = i + 1 - offset;
+ break;
+ }
+ }
+ break;
+ case atomizeUTF16:
+ // Break section up into zero terminated UTF16 strings.
+ size = 0;
+ for (unsigned int i = offset; i < e; i += 2) {
+ if ((section.content[i] == 0) && (section.content[i + 1] == 0)) {
+ size = i + 2 - offset;
+ break;
+ }
+ }
+ break;
+ case atomizeCFI:
+ // Break section up into dwarf unwind CFIs (FDE or CIE).
+ size = read32(&section.content[offset], isBig) + 4;
+ if (offset+size > section.content.size()) {
+ return llvm::make_error<GenericError>(Twine("Section ")
+ + section.segmentName
+ + "/" + section.sectionName
+ + " is malformed. Size of CFI "
+ "starting at offset ("
+ + Twine(offset)
+ + ") is past end of section.");
+ }
+ break;
+ case atomizeCU:
+ // Break section up into compact unwind entries.
+ size = is64 ? 32 : 20;
+ break;
+ case atomizeCFString:
+ // Break section up into NS/CFString objects.
+ size = is64 ? 32 : 16;
+ break;
+ case atomizeAtSymbols:
+ break;
+ }
+ if (size == 0) {
+ return llvm::make_error<GenericError>(Twine("Section ")
+ + section.segmentName
+ + "/" + section.sectionName
+ + " is malformed. The last atom "
+ "is not zero terminated.");
+ }
+ if (customSectionName) {
+ // Mach-O needs a segment and section name. Concatentate those two
+ // with a / separator (e.g. "seg/sect") to fit into the lld model
+ // of just a section name.
+ std::string segSectName = section.segmentName.str()
+ + "/" + section.sectionName.str();
+ file.addDefinedAtomInCustomSection(StringRef(), scope, atomType,
+ merge, false, false, offset,
+ size, segSectName, true, &section);
+ } else {
+ file.addDefinedAtom(StringRef(), scope, atomType, merge, offset, size,
+ false, false, copyRefs, &section);
+ }
+ offset += size;
+ }
+ }
+ return llvm::Error::success();
+}
+
+const Section* findSectionCoveringAddress(const NormalizedFile &normalizedFile,
+ uint64_t address) {
+ for (const Section &s : normalizedFile.sections) {
+ uint64_t sAddr = s.address;
+ if ((sAddr <= address) && (address < sAddr+s.content.size())) {
+ return &s;
+ }
+ }
+ return nullptr;
+}
+
+const MachODefinedAtom *
+findAtomCoveringAddress(const NormalizedFile &normalizedFile, MachOFile &file,
+ uint64_t addr, Reference::Addend &addend) {
+ const Section *sect = nullptr;
+ sect = findSectionCoveringAddress(normalizedFile, addr);
+ if (!sect)
+ return nullptr;
+
+ uint32_t offsetInTarget;
+ uint64_t offsetInSect = addr - sect->address;
+ auto atom =
+ file.findAtomCoveringAddress(*sect, offsetInSect, &offsetInTarget);
+ addend = offsetInTarget;
+ return atom;
+}
+
+// Walks all relocations for a section in a normalized .o file and
+// creates corresponding lld::Reference objects.
+llvm::Error convertRelocs(const Section &section,
+ const NormalizedFile &normalizedFile,
+ bool scatterable,
+ MachOFile &file,
+ ArchHandler &handler) {
+ // Utility function for ArchHandler to find atom by its address.
+ auto atomByAddr = [&] (uint32_t sectIndex, uint64_t addr,
+ const lld::Atom **atom, Reference::Addend *addend)
+ -> llvm::Error {
+ if (sectIndex > normalizedFile.sections.size())
+ return llvm::make_error<GenericError>(Twine("out of range section "
+ "index (") + Twine(sectIndex) + ")");
+ const Section *sect = nullptr;
+ if (sectIndex == 0) {
+ sect = findSectionCoveringAddress(normalizedFile, addr);
+ if (!sect)
+ return llvm::make_error<GenericError>(Twine("address (" + Twine(addr)
+ + ") is not in any section"));
+ } else {
+ sect = &normalizedFile.sections[sectIndex-1];
+ }
+ uint32_t offsetInTarget;
+ uint64_t offsetInSect = addr - sect->address;
+ *atom = file.findAtomCoveringAddress(*sect, offsetInSect, &offsetInTarget);
+ *addend = offsetInTarget;
+ return llvm::Error::success();
+ };
+
+ // Utility function for ArchHandler to find atom by its symbol index.
+ auto atomBySymbol = [&] (uint32_t symbolIndex, const lld::Atom **result)
+ -> llvm::Error {
+ // Find symbol from index.
+ const Symbol *sym = nullptr;
+ uint32_t numStabs = normalizedFile.stabsSymbols.size();
+ uint32_t numLocal = normalizedFile.localSymbols.size();
+ uint32_t numGlobal = normalizedFile.globalSymbols.size();
+ uint32_t numUndef = normalizedFile.undefinedSymbols.size();
+ assert(symbolIndex >= numStabs && "Searched for stab via atomBySymbol?");
+ if (symbolIndex < numStabs+numLocal) {
+ sym = &normalizedFile.localSymbols[symbolIndex-numStabs];
+ } else if (symbolIndex < numStabs+numLocal+numGlobal) {
+ sym = &normalizedFile.globalSymbols[symbolIndex-numStabs-numLocal];
+ } else if (symbolIndex < numStabs+numLocal+numGlobal+numUndef) {
+ sym = &normalizedFile.undefinedSymbols[symbolIndex-numStabs-numLocal-
+ numGlobal];
+ } else {
+ return llvm::make_error<GenericError>(Twine("symbol index (")
+ + Twine(symbolIndex) + ") out of range");
+ }
+
+ // Find atom from symbol.
+ if ((sym->type & N_TYPE) == N_SECT) {
+ if (sym->sect > normalizedFile.sections.size())
+ return llvm::make_error<GenericError>(Twine("symbol section index (")
+ + Twine(sym->sect) + ") out of range ");
+ const Section &symSection = normalizedFile.sections[sym->sect-1];
+ uint64_t targetOffsetInSect = sym->value - symSection.address;
+ MachODefinedAtom *target = file.findAtomCoveringAddress(symSection,
+ targetOffsetInSect);
+ if (target) {
+ *result = target;
+ return llvm::Error::success();
+ }
+ return llvm::make_error<GenericError>("no atom found for defined symbol");
+ } else if ((sym->type & N_TYPE) == N_UNDF) {
+ const lld::Atom *target = file.findUndefAtom(sym->name);
+ if (target) {
+ *result = target;
+ return llvm::Error::success();
+ }
+ return llvm::make_error<GenericError>("no undefined atom found for sym");
+ } else {
+ // Search undefs
+ return llvm::make_error<GenericError>("no atom found for symbol");
+ }
+ };
+
+ const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
+ // Use old-school iterator so that paired relocations can be grouped.
+ for (auto it=section.relocations.begin(), e=section.relocations.end();
+ it != e; ++it) {
+ const Relocation &reloc = *it;
+ // Find atom this relocation is in.
+ if (reloc.offset > section.content.size())
+ return llvm::make_error<GenericError>(
+ Twine("r_address (") + Twine(reloc.offset)
+ + ") is larger than section size ("
+ + Twine(section.content.size()) + ")");
+ uint32_t offsetInAtom;
+ MachODefinedAtom *inAtom = file.findAtomCoveringAddress(section,
+ reloc.offset,
+ &offsetInAtom);
+ assert(inAtom && "r_address in range, should have found atom");
+ uint64_t fixupAddress = section.address + reloc.offset;
+
+ const lld::Atom *target = nullptr;
+ Reference::Addend addend = 0;
+ Reference::KindValue kind;
+ if (handler.isPairedReloc(reloc)) {
+ // Handle paired relocations together.
+ const Relocation &reloc2 = *++it;
+ auto relocErr = handler.getPairReferenceInfo(
+ reloc, reloc2, inAtom, offsetInAtom, fixupAddress, isBig, scatterable,
+ atomByAddr, atomBySymbol, &kind, &target, &addend);
+ if (relocErr) {
+ return handleErrors(std::move(relocErr),
+ [&](std::unique_ptr<GenericError> GE) {
+ return llvm::make_error<GenericError>(
+ Twine("bad relocation (") + GE->getMessage()
+ + ") in section "
+ + section.segmentName + "/" + section.sectionName
+ + " (r1_address=" + Twine::utohexstr(reloc.offset)
+ + ", r1_type=" + Twine(reloc.type)
+ + ", r1_extern=" + Twine(reloc.isExtern)
+ + ", r1_length=" + Twine((int)reloc.length)
+ + ", r1_pcrel=" + Twine(reloc.pcRel)
+ + (!reloc.scattered ? (Twine(", r1_symbolnum=")
+ + Twine(reloc.symbol))
+ : (Twine(", r1_scattered=1, r1_value=")
+ + Twine(reloc.value)))
+ + ")"
+ + ", (r2_address=" + Twine::utohexstr(reloc2.offset)
+ + ", r2_type=" + Twine(reloc2.type)
+ + ", r2_extern=" + Twine(reloc2.isExtern)
+ + ", r2_length=" + Twine((int)reloc2.length)
+ + ", r2_pcrel=" + Twine(reloc2.pcRel)
+ + (!reloc2.scattered ? (Twine(", r2_symbolnum=")
+ + Twine(reloc2.symbol))
+ : (Twine(", r2_scattered=1, r2_value=")
+ + Twine(reloc2.value)))
+ + ")" );
+ });
+ }
+ }
+ else {
+ // Use ArchHandler to convert relocation record into information
+ // needed to instantiate an lld::Reference object.
+ auto relocErr = handler.getReferenceInfo(
+ reloc, inAtom, offsetInAtom, fixupAddress, isBig, atomByAddr,
+ atomBySymbol, &kind, &target, &addend);
+ if (relocErr) {
+ return handleErrors(std::move(relocErr),
+ [&](std::unique_ptr<GenericError> GE) {
+ return llvm::make_error<GenericError>(
+ Twine("bad relocation (") + GE->getMessage()
+ + ") in section "
+ + section.segmentName + "/" + section.sectionName
+ + " (r_address=" + Twine::utohexstr(reloc.offset)
+ + ", r_type=" + Twine(reloc.type)
+ + ", r_extern=" + Twine(reloc.isExtern)
+ + ", r_length=" + Twine((int)reloc.length)
+ + ", r_pcrel=" + Twine(reloc.pcRel)
+ + (!reloc.scattered ? (Twine(", r_symbolnum=") + Twine(reloc.symbol))
+ : (Twine(", r_scattered=1, r_value=")
+ + Twine(reloc.value)))
+ + ")" );
+ });
+ }
+ }
+ // Instantiate an lld::Reference object and add to its atom.
+ inAtom->addReference(Reference::KindNamespace::mach_o,
+ handler.kindArch(),
+ kind, offsetInAtom, target, addend);
+ }
+
+ return llvm::Error::success();
+}
+
+bool isDebugInfoSection(const Section &section) {
+ if ((section.attributes & S_ATTR_DEBUG) == 0)
+ return false;
+ return section.segmentName.equals("__DWARF");
+}
+
+static const Atom* findDefinedAtomByName(MachOFile &file, Twine name) {
+ std::string strName = name.str();
+ for (auto *atom : file.defined())
+ if (atom->name() == strName)
+ return atom;
+ return nullptr;
+}
+
+static StringRef copyDebugString(StringRef str, BumpPtrAllocator &alloc) {
+ char *strCopy = alloc.Allocate<char>(str.size() + 1);
+ memcpy(strCopy, str.data(), str.size());
+ strCopy[str.size()] = '\0';
+ return strCopy;
+}
+
+llvm::Error parseStabs(MachOFile &file,
+ const NormalizedFile &normalizedFile,
+ bool copyRefs) {
+
+ if (normalizedFile.stabsSymbols.empty())
+ return llvm::Error::success();
+
+ // FIXME: Kill this off when we can move to sane yaml parsing.
+ std::unique_ptr<BumpPtrAllocator> allocator;
+ if (copyRefs)
+ allocator = llvm::make_unique<BumpPtrAllocator>();
+
+ enum { start, inBeginEnd } state = start;
+
+ const Atom *currentAtom = nullptr;
+ uint64_t currentAtomAddress = 0;
+ StabsDebugInfo::StabsList stabsList;
+ for (const auto &stabSym : normalizedFile.stabsSymbols) {
+ Stab stab(nullptr, stabSym.type, stabSym.sect, stabSym.desc,
+ stabSym.value, stabSym.name);
+ switch (state) {
+ case start:
+ switch (static_cast<StabType>(stabSym.type)) {
+ case N_BNSYM:
+ state = inBeginEnd;
+ currentAtomAddress = stabSym.value;
+ Reference::Addend addend;
+ currentAtom = findAtomCoveringAddress(normalizedFile, file,
+ currentAtomAddress, addend);
+ if (addend != 0)
+ return llvm::make_error<GenericError>(
+ "Non-zero addend for BNSYM '" + stabSym.name + "' in " +
+ file.path());
+ if (currentAtom)
+ stab.atom = currentAtom;
+ else {
+ // FIXME: ld64 just issues a warning here - should we match that?
+ return llvm::make_error<GenericError>(
+ "can't find atom for stabs BNSYM at " +
+ Twine::utohexstr(stabSym.value) + " in " + file.path());
+ }
+ break;
+ case N_SO:
+ case N_OSO:
+ // Not associated with an atom, just copy.
+ if (copyRefs)
+ stab.str = copyDebugString(stabSym.name, *allocator);
+ else
+ stab.str = stabSym.name;
+ break;
+ case N_GSYM: {
+ auto colonIdx = stabSym.name.find(':');
+ if (colonIdx != StringRef::npos) {
+ StringRef name = stabSym.name.substr(0, colonIdx);
+ currentAtom = findDefinedAtomByName(file, "_" + name);
+ stab.atom = currentAtom;
+ if (copyRefs)
+ stab.str = copyDebugString(stabSym.name, *allocator);
+ else
+ stab.str = stabSym.name;
+ } else {
+ currentAtom = findDefinedAtomByName(file, stabSym.name);
+ stab.atom = currentAtom;
+ if (copyRefs)
+ stab.str = copyDebugString(stabSym.name, *allocator);
+ else
+ stab.str = stabSym.name;
+ }
+ if (stab.atom == nullptr)
+ return llvm::make_error<GenericError>(
+ "can't find atom for N_GSYM stabs" + stabSym.name +
+ " in " + file.path());
+ break;
+ }
+ case N_FUN:
+ return llvm::make_error<GenericError>(
+ "old-style N_FUN stab '" + stabSym.name + "' unsupported");
+ default:
+ return llvm::make_error<GenericError>(
+ "unrecognized stab symbol '" + stabSym.name + "'");
+ }
+ break;
+ case inBeginEnd:
+ stab.atom = currentAtom;
+ switch (static_cast<StabType>(stabSym.type)) {
+ case N_ENSYM:
+ state = start;
+ currentAtom = nullptr;
+ break;
+ case N_FUN:
+ // Just copy the string.
+ if (copyRefs)
+ stab.str = copyDebugString(stabSym.name, *allocator);
+ else
+ stab.str = stabSym.name;
+ break;
+ default:
+ return llvm::make_error<GenericError>(
+ "unrecognized stab symbol '" + stabSym.name + "'");
+ }
+ }
+ llvm::dbgs() << "Adding to stabsList: " << stab << "\n";
+ stabsList.push_back(stab);
+ }
+
+ file.setDebugInfo(llvm::make_unique<StabsDebugInfo>(std::move(stabsList)));
+
+ // FIXME: Kill this off when we fix YAML memory ownership.
+ file.debugInfo()->setAllocator(std::move(allocator));
+
+ return llvm::Error::success();
+}
+
+static llvm::DataExtractor
+dataExtractorFromSection(const NormalizedFile &normalizedFile,
+ const Section &S) {
+ const bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch);
+ const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
+ StringRef SecData(reinterpret_cast<const char*>(S.content.data()),
+ S.content.size());
+ return llvm::DataExtractor(SecData, !isBig, is64 ? 8 : 4);
+}
+
+// FIXME: Cribbed from llvm-dwp -- should share "lightweight CU DIE
+// inspection" code if possible.
+static uint32_t getCUAbbrevOffset(llvm::DataExtractor abbrevData,
+ uint64_t abbrCode) {
+ uint64_t curCode;
+ uint32_t offset = 0;
+ while ((curCode = abbrevData.getULEB128(&offset)) != abbrCode) {
+ // Tag
+ abbrevData.getULEB128(&offset);
+ // DW_CHILDREN
+ abbrevData.getU8(&offset);
+ // Attributes
+ while (abbrevData.getULEB128(&offset) | abbrevData.getULEB128(&offset))
+ ;
+ }
+ return offset;
+}
+
+// FIXME: Cribbed from llvm-dwp -- should share "lightweight CU DIE
+// inspection" code if possible.
+static Expected<const char *>
+getIndexedString(const NormalizedFile &normalizedFile,
+ llvm::dwarf::Form form, llvm::DataExtractor infoData,
+ uint32_t &infoOffset, const Section &stringsSection) {
+ if (form == llvm::dwarf::DW_FORM_string)
+ return infoData.getCStr(&infoOffset);
+ if (form != llvm::dwarf::DW_FORM_strp)
+ return llvm::make_error<GenericError>(
+ "string field encoded without DW_FORM_strp");
+ uint32_t stringOffset = infoData.getU32(&infoOffset);
+ llvm::DataExtractor stringsData =
+ dataExtractorFromSection(normalizedFile, stringsSection);
+ return stringsData.getCStr(&stringOffset);
+}
+
+// FIXME: Cribbed from llvm-dwp -- should share "lightweight CU DIE
+// inspection" code if possible.
+static llvm::Expected<TranslationUnitSource>
+readCompUnit(const NormalizedFile &normalizedFile,
+ const Section &info,
+ const Section &abbrev,
+ const Section &strings,
+ StringRef path) {
+ // FIXME: Cribbed from llvm-dwp -- should share "lightweight CU DIE
+ // inspection" code if possible.
+ uint32_t offset = 0;
+ llvm::dwarf::DwarfFormat Format = llvm::dwarf::DwarfFormat::DWARF32;
+ auto infoData = dataExtractorFromSection(normalizedFile, info);
+ uint32_t length = infoData.getU32(&offset);
+ if (length == 0xffffffff) {
+ Format = llvm::dwarf::DwarfFormat::DWARF64;
+ infoData.getU64(&offset);
+ }
+ else if (length > 0xffffff00)
+ return llvm::make_error<GenericError>("Malformed DWARF in " + path);
+
+ uint16_t version = infoData.getU16(&offset);
+
+ if (version < 2 || version > 4)
+ return llvm::make_error<GenericError>("Unsupported DWARF version in " +
+ path);
+
+ infoData.getU32(&offset); // Abbrev offset (should be zero)
+ uint8_t addrSize = infoData.getU8(&offset);
+
+ uint32_t abbrCode = infoData.getULEB128(&offset);
+ auto abbrevData = dataExtractorFromSection(normalizedFile, abbrev);
+ uint32_t abbrevOffset = getCUAbbrevOffset(abbrevData, abbrCode);
+ uint64_t tag = abbrevData.getULEB128(&abbrevOffset);
+ if (tag != llvm::dwarf::DW_TAG_compile_unit)
+ return llvm::make_error<GenericError>("top level DIE is not a compile unit");
+ // DW_CHILDREN
+ abbrevData.getU8(&abbrevOffset);
+ uint32_t name;
+ llvm::dwarf::Form form;
+ llvm::dwarf::FormParams formParams = {version, addrSize, Format};
+ TranslationUnitSource tu;
+ while ((name = abbrevData.getULEB128(&abbrevOffset)) |
+ (form = static_cast<llvm::dwarf::Form>(
+ abbrevData.getULEB128(&abbrevOffset))) &&
+ (name != 0 || form != 0)) {
+ switch (name) {
+ case llvm::dwarf::DW_AT_name: {
+ if (auto eName = getIndexedString(normalizedFile, form, infoData, offset,
+ strings))
+ tu.name = *eName;
+ else
+ return eName.takeError();
+ break;
+ }
+ case llvm::dwarf::DW_AT_comp_dir: {
+ if (auto eName = getIndexedString(normalizedFile, form, infoData, offset,
+ strings))
+ tu.path = *eName;
+ else
+ return eName.takeError();
+ break;
+ }
+ default:
+ llvm::DWARFFormValue::skipValue(form, infoData, &offset, formParams);
+ }
+ }
+ return tu;
+}
+
+llvm::Error parseDebugInfo(MachOFile &file,
+ const NormalizedFile &normalizedFile, bool copyRefs) {
+
+ // Find the interesting debug info sections.
+ const Section *debugInfo = nullptr;
+ const Section *debugAbbrev = nullptr;
+ const Section *debugStrings = nullptr;
+
+ for (auto &s : normalizedFile.sections) {
+ if (s.segmentName == "__DWARF") {
+ if (s.sectionName == "__debug_info")
+ debugInfo = &s;
+ else if (s.sectionName == "__debug_abbrev")
+ debugAbbrev = &s;
+ else if (s.sectionName == "__debug_str")
+ debugStrings = &s;
+ }
+ }
+
+ if (!debugInfo)
+ return parseStabs(file, normalizedFile, copyRefs);
+
+ if (debugInfo->content.size() == 0)
+ return llvm::Error::success();
+
+ if (debugInfo->content.size() < 12)
+ return llvm::make_error<GenericError>("Malformed __debug_info section in " +
+ file.path() + ": too small");
+
+ if (!debugAbbrev)
+ return llvm::make_error<GenericError>("Missing __dwarf_abbrev section in " +
+ file.path());
+
+ if (auto tuOrErr = readCompUnit(normalizedFile, *debugInfo, *debugAbbrev,
+ *debugStrings, file.path())) {
+ // FIXME: Kill of allocator and code under 'copyRefs' when we fix YAML
+ // memory ownership.
+ std::unique_ptr<BumpPtrAllocator> allocator;
+ if (copyRefs) {
+ allocator = llvm::make_unique<BumpPtrAllocator>();
+ tuOrErr->name = copyDebugString(tuOrErr->name, *allocator);
+ tuOrErr->path = copyDebugString(tuOrErr->path, *allocator);
+ }
+ file.setDebugInfo(llvm::make_unique<DwarfDebugInfo>(std::move(*tuOrErr)));
+ if (copyRefs)
+ file.debugInfo()->setAllocator(std::move(allocator));
+ } else
+ return tuOrErr.takeError();
+
+ return llvm::Error::success();
+}
+
+static int64_t readSPtr(bool is64, bool isBig, const uint8_t *addr) {
+ if (is64)
+ return read64(addr, isBig);
+
+ int32_t res = read32(addr, isBig);
+ return res;
+}
+
+/// --- Augmentation String Processing ---
+
+struct CIEInfo {
+ bool _augmentationDataPresent = false;
+ bool _mayHaveEH = false;
+ uint32_t _offsetOfLSDA = ~0U;
+ uint32_t _offsetOfPersonality = ~0U;
+ uint32_t _offsetOfFDEPointerEncoding = ~0U;
+ uint32_t _augmentationDataLength = ~0U;
+};
+
+typedef llvm::DenseMap<const MachODefinedAtom*, CIEInfo> CIEInfoMap;
+
+static llvm::Error processAugmentationString(const uint8_t *augStr,
+ CIEInfo &cieInfo,
+ unsigned &len) {
+
+ if (augStr[0] == '\0') {
+ len = 1;
+ return llvm::Error::success();
+ }
+
+ if (augStr[0] != 'z')
+ return llvm::make_error<GenericError>("expected 'z' at start of "
+ "augmentation string");
+
+ cieInfo._augmentationDataPresent = true;
+ uint64_t idx = 1;
+
+ uint32_t offsetInAugmentationData = 0;
+ while (augStr[idx] != '\0') {
+ if (augStr[idx] == 'L') {
+ cieInfo._offsetOfLSDA = offsetInAugmentationData;
+ // This adds a single byte to the augmentation data.
+ ++offsetInAugmentationData;
+ ++idx;
+ continue;
+ }
+ if (augStr[idx] == 'P') {
+ cieInfo._offsetOfPersonality = offsetInAugmentationData;
+ // This adds a single byte to the augmentation data for the encoding,
+ // then a number of bytes for the pointer data.
+ // FIXME: We are assuming 4 is correct here for the pointer size as we
+ // always currently use delta32ToGOT.
+ offsetInAugmentationData += 5;
+ ++idx;
+ continue;
+ }
+ if (augStr[idx] == 'R') {
+ cieInfo._offsetOfFDEPointerEncoding = offsetInAugmentationData;
+ // This adds a single byte to the augmentation data.
+ ++offsetInAugmentationData;
+ ++idx;
+ continue;
+ }
+ if (augStr[idx] == 'e') {
+ if (augStr[idx + 1] != 'h')
+ return llvm::make_error<GenericError>("expected 'eh' in "
+ "augmentation string");
+ cieInfo._mayHaveEH = true;
+ idx += 2;
+ continue;
+ }
+ ++idx;
+ }
+
+ cieInfo._augmentationDataLength = offsetInAugmentationData;
+
+ len = idx + 1;
+ return llvm::Error::success();
+}
+
+static llvm::Error processCIE(const NormalizedFile &normalizedFile,
+ MachOFile &file,
+ mach_o::ArchHandler &handler,
+ const Section *ehFrameSection,
+ MachODefinedAtom *atom,
+ uint64_t offset,
+ CIEInfoMap &cieInfos) {
+ const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
+ const uint8_t *frameData = atom->rawContent().data();
+
+ CIEInfo cieInfo;
+
+ uint32_t size = read32(frameData, isBig);
+ uint64_t cieIDField = size == 0xffffffffU
+ ? sizeof(uint32_t) + sizeof(uint64_t)
+ : sizeof(uint32_t);
+ uint64_t versionField = cieIDField + sizeof(uint32_t);
+ uint64_t augmentationStringField = versionField + sizeof(uint8_t);
+
+ unsigned augmentationStringLength = 0;
+ if (auto err = processAugmentationString(frameData + augmentationStringField,
+ cieInfo, augmentationStringLength))
+ return err;
+
+ if (cieInfo._offsetOfPersonality != ~0U) {
+ // If we have augmentation data for the personality function, then we may
+ // need to implicitly generate its relocation.
+
+ // Parse the EH Data field which is pointer sized.
+ uint64_t EHDataField = augmentationStringField + augmentationStringLength;
+ const bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch);
+ unsigned EHDataFieldSize = (cieInfo._mayHaveEH ? (is64 ? 8 : 4) : 0);
+
+ // Parse Code Align Factor which is a ULEB128.
+ uint64_t CodeAlignField = EHDataField + EHDataFieldSize;
+ unsigned lengthFieldSize = 0;
+ llvm::decodeULEB128(frameData + CodeAlignField, &lengthFieldSize);
+
+ // Parse Data Align Factor which is a SLEB128.
+ uint64_t DataAlignField = CodeAlignField + lengthFieldSize;
+ llvm::decodeSLEB128(frameData + DataAlignField, &lengthFieldSize);
+
+ // Parse Return Address Register which is a byte.
+ uint64_t ReturnAddressField = DataAlignField + lengthFieldSize;
+
+ // Parse the augmentation length which is a ULEB128.
+ uint64_t AugmentationLengthField = ReturnAddressField + 1;
+ uint64_t AugmentationLength =
+ llvm::decodeULEB128(frameData + AugmentationLengthField,
+ &lengthFieldSize);
+
+ if (AugmentationLength != cieInfo._augmentationDataLength)
+ return llvm::make_error<GenericError>("CIE augmentation data length "
+ "mismatch");
+
+ // Get the start address of the augmentation data.
+ uint64_t AugmentationDataField = AugmentationLengthField + lengthFieldSize;
+
+ // Parse the personality function from the augmentation data.
+ uint64_t PersonalityField =
+ AugmentationDataField + cieInfo._offsetOfPersonality;
+
+ // Parse the personality encoding.
+ // FIXME: Verify that this is a 32-bit pcrel offset.
+ uint64_t PersonalityFunctionField = PersonalityField + 1;
+
+ if (atom->begin() != atom->end()) {
+ // If we have an explicit relocation, then make sure it matches this
+ // offset as this is where we'd expect it to be applied to.
+ DefinedAtom::reference_iterator CurrentRef = atom->begin();
+ if (CurrentRef->offsetInAtom() != PersonalityFunctionField)
+ return llvm::make_error<GenericError>("CIE personality reloc at "
+ "wrong offset");
+
+ if (++CurrentRef != atom->end())
+ return llvm::make_error<GenericError>("CIE contains too many relocs");
+ } else {
+ // Implicitly generate the personality function reloc. It's assumed to
+ // be a delta32 offset to a GOT entry.
+ // FIXME: Parse the encoding and check this.
+ int32_t funcDelta = read32(frameData + PersonalityFunctionField, isBig);
+ uint64_t funcAddress = ehFrameSection->address + offset +
+ PersonalityFunctionField;
+ funcAddress += funcDelta;
+
+ const MachODefinedAtom *func = nullptr;
+ Reference::Addend addend;
+ func = findAtomCoveringAddress(normalizedFile, file, funcAddress,
+ addend);
+ atom->addReference(Reference::KindNamespace::mach_o, handler.kindArch(),
+ handler.unwindRefToPersonalityFunctionKind(),
+ PersonalityFunctionField, func, addend);
+ }
+ } else if (atom->begin() != atom->end()) {
+ // Otherwise, we expect there to be no relocations in this atom as the only
+ // relocation would have been to the personality function.
+ return llvm::make_error<GenericError>("unexpected relocation in CIE");
+ }
+
+
+ cieInfos[atom] = std::move(cieInfo);
+
+ return llvm::Error::success();
+}
+
+static llvm::Error processFDE(const NormalizedFile &normalizedFile,
+ MachOFile &file,
+ mach_o::ArchHandler &handler,
+ const Section *ehFrameSection,
+ MachODefinedAtom *atom,
+ uint64_t offset,
+ const CIEInfoMap &cieInfos) {
+
+ const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
+ const bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch);
+
+ // Compiler wasn't lazy and actually told us what it meant.
+ // Unfortunately, the compiler may not have generated references for all of
+ // [cie, func, lsda] and so we still need to parse the FDE and add references
+ // for any the compiler didn't generate.
+ if (atom->begin() != atom->end())
+ atom->sortReferences();
+
+ DefinedAtom::reference_iterator CurrentRef = atom->begin();
+
+ // This helper returns the reference (if one exists) at the offset we are
+ // currently processing. It automatically increments the ref iterator if we
+ // do return a ref, and throws an error if we pass over a ref without
+ // comsuming it.
+ auto currentRefGetter = [&CurrentRef,
+ &atom](uint64_t Offset)->const Reference* {
+ // If there are no more refs found, then we are done.
+ if (CurrentRef == atom->end())
+ return nullptr;
+
+ const Reference *Ref = *CurrentRef;
+
+ // If we haven't reached the offset for this reference, then return that
+ // we don't yet have a reference to process.
+ if (Offset < Ref->offsetInAtom())
+ return nullptr;
+
+ // If the offset is equal, then we want to process this ref.
+ if (Offset == Ref->offsetInAtom()) {
+ ++CurrentRef;
+ return Ref;
+ }
+
+ // The current ref is at an offset which is earlier than the current
+ // offset, then we failed to consume it when we should have. In this case
+ // throw an error.
+ llvm::report_fatal_error("Skipped reference when processing FDE");
+ };
+
+ // Helper to either get the reference at this current location, and verify
+ // that it is of the expected type, or add a reference of that type.
+ // Returns the reference target.
+ auto verifyOrAddReference = [&](uint64_t targetAddress,
+ Reference::KindValue refKind,
+ uint64_t refAddress,
+ bool allowsAddend)->const Atom* {
+ if (auto *ref = currentRefGetter(refAddress)) {
+ // The compiler already emitted a relocation for the CIE ref. This should
+ // have been converted to the correct type of reference in
+ // get[Pair]ReferenceInfo().
+ assert(ref->kindValue() == refKind &&
+ "Incorrect EHFrame reference kind");
+ return ref->target();
+ }
+ Reference::Addend addend;
+ auto *target = findAtomCoveringAddress(normalizedFile, file,
+ targetAddress, addend);
+ atom->addReference(Reference::KindNamespace::mach_o, handler.kindArch(),
+ refKind, refAddress, target, addend);
+
+ if (!allowsAddend)
+ assert(!addend && "EHFrame reference cannot have addend");
+ return target;
+ };
+
+ const uint8_t *startFrameData = atom->rawContent().data();
+ const uint8_t *frameData = startFrameData;
+
+ uint32_t size = read32(frameData, isBig);
+ uint64_t cieFieldInFDE = size == 0xffffffffU
+ ? sizeof(uint32_t) + sizeof(uint64_t)
+ : sizeof(uint32_t);
+
+ // Linker needs to fixup a reference from the FDE to its parent CIE (a
+ // 32-bit byte offset backwards in the __eh_frame section).
+ uint32_t cieDelta = read32(frameData + cieFieldInFDE, isBig);
+ uint64_t cieAddress = ehFrameSection->address + offset + cieFieldInFDE;
+ cieAddress -= cieDelta;
+
+ auto *cieRefTarget = verifyOrAddReference(cieAddress,
+ handler.unwindRefToCIEKind(),
+ cieFieldInFDE, false);
+ const MachODefinedAtom *cie = dyn_cast<MachODefinedAtom>(cieRefTarget);
+ assert(cie && cie->contentType() == DefinedAtom::typeCFI &&
+ "FDE's CIE field does not point at the start of a CIE.");
+
+ const CIEInfo &cieInfo = cieInfos.find(cie)->second;
+
+ // Linker needs to fixup reference from the FDE to the function it's
+ // describing. FIXME: there are actually different ways to do this, and the
+ // particular method used is specified in the CIE's augmentation fields
+ // (hopefully)
+ uint64_t rangeFieldInFDE = cieFieldInFDE + sizeof(uint32_t);
+
+ int64_t functionFromFDE = readSPtr(is64, isBig,
+ frameData + rangeFieldInFDE);
+ uint64_t rangeStart = ehFrameSection->address + offset + rangeFieldInFDE;
+ rangeStart += functionFromFDE;
+
+ verifyOrAddReference(rangeStart,
+ handler.unwindRefToFunctionKind(),
+ rangeFieldInFDE, true);
+
+ // Handle the augmentation data if there is any.
+ if (cieInfo._augmentationDataPresent) {
+ // First process the augmentation data length field.
+ uint64_t augmentationDataLengthFieldInFDE =
+ rangeFieldInFDE + 2 * (is64 ? sizeof(uint64_t) : sizeof(uint32_t));
+ unsigned lengthFieldSize = 0;
+ uint64_t augmentationDataLength =
+ llvm::decodeULEB128(frameData + augmentationDataLengthFieldInFDE,
+ &lengthFieldSize);
+
+ if (cieInfo._offsetOfLSDA != ~0U && augmentationDataLength > 0) {
+
+ // Look at the augmentation data field.
+ uint64_t augmentationDataFieldInFDE =
+ augmentationDataLengthFieldInFDE + lengthFieldSize;
+
+ int64_t lsdaFromFDE = readSPtr(is64, isBig,
+ frameData + augmentationDataFieldInFDE);
+ uint64_t lsdaStart =
+ ehFrameSection->address + offset + augmentationDataFieldInFDE +
+ lsdaFromFDE;
+
+ verifyOrAddReference(lsdaStart,
+ handler.unwindRefToFunctionKind(),
+ augmentationDataFieldInFDE, true);
+ }
+ }
+
+ return llvm::Error::success();
+}
+
+llvm::Error addEHFrameReferences(const NormalizedFile &normalizedFile,
+ MachOFile &file,
+ mach_o::ArchHandler &handler) {
+
+ const Section *ehFrameSection = nullptr;
+ for (auto &section : normalizedFile.sections)
+ if (section.segmentName == "__TEXT" &&
+ section.sectionName == "__eh_frame") {
+ ehFrameSection = &section;
+ break;
+ }
+
+ // No __eh_frame so nothing to do.
+ if (!ehFrameSection)
+ return llvm::Error::success();
+
+ llvm::Error ehFrameErr = llvm::Error::success();
+ CIEInfoMap cieInfos;
+
+ file.eachAtomInSection(*ehFrameSection,
+ [&](MachODefinedAtom *atom, uint64_t offset) -> void {
+ assert(atom->contentType() == DefinedAtom::typeCFI);
+
+ // Bail out if we've encountered an error.
+ if (ehFrameErr)
+ return;
+
+ const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
+ if (ArchHandler::isDwarfCIE(isBig, atom))
+ ehFrameErr = processCIE(normalizedFile, file, handler, ehFrameSection,
+ atom, offset, cieInfos);
+ else
+ ehFrameErr = processFDE(normalizedFile, file, handler, ehFrameSection,
+ atom, offset, cieInfos);
+ });
+
+ return ehFrameErr;
+}
+
+llvm::Error parseObjCImageInfo(const Section &sect,
+ const NormalizedFile &normalizedFile,
+ MachOFile &file) {
+
+ // struct objc_image_info {
+ // uint32_t version; // initially 0
+ // uint32_t flags;
+ // };
+
+ ArrayRef<uint8_t> content = sect.content;
+ if (content.size() != 8)
+ return llvm::make_error<GenericError>(sect.segmentName + "/" +
+ sect.sectionName +
+ " in file " + file.path() +
+ " should be 8 bytes in size");
+
+ const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
+ uint32_t version = read32(content.data(), isBig);
+ if (version)
+ return llvm::make_error<GenericError>(sect.segmentName + "/" +
+ sect.sectionName +
+ " in file " + file.path() +
+ " should have version=0");
+
+ uint32_t flags = read32(content.data() + 4, isBig);
+ if (flags & (MachOLinkingContext::objc_supports_gc |
+ MachOLinkingContext::objc_gc_only))
+ return llvm::make_error<GenericError>(sect.segmentName + "/" +
+ sect.sectionName +
+ " in file " + file.path() +
+ " uses GC. This is not supported");
+
+ if (flags & MachOLinkingContext::objc_retainReleaseForSimulator)
+ file.setObjcConstraint(MachOLinkingContext::objc_retainReleaseForSimulator);
+ else
+ file.setObjcConstraint(MachOLinkingContext::objc_retainRelease);
+
+ file.setSwiftVersion((flags >> 8) & 0xFF);
+
+ return llvm::Error::success();
+}
+
+/// Converts normalized mach-o file into an lld::File and lld::Atoms.
+llvm::Expected<std::unique_ptr<lld::File>>
+objectToAtoms(const NormalizedFile &normalizedFile, StringRef path,
+ bool copyRefs) {
+ std::unique_ptr<MachOFile> file(new MachOFile(path));
+ if (auto ec = normalizedObjectToAtoms(file.get(), normalizedFile, copyRefs))
+ return std::move(ec);
+ return std::unique_ptr<File>(std::move(file));
+}
+
+llvm::Expected<std::unique_ptr<lld::File>>
+dylibToAtoms(const NormalizedFile &normalizedFile, StringRef path,
+ bool copyRefs) {
+ // Instantiate SharedLibraryFile object.
+ std::unique_ptr<MachODylibFile> file(new MachODylibFile(path));
+ if (auto ec = normalizedDylibToAtoms(file.get(), normalizedFile, copyRefs))
+ return std::move(ec);
+ return std::unique_ptr<File>(std::move(file));
+}
+
+} // anonymous namespace
+
+namespace normalized {
+
+static bool isObjCImageInfo(const Section &sect) {
+ return (sect.segmentName == "__OBJC" && sect.sectionName == "__image_info") ||
+ (sect.segmentName == "__DATA" && sect.sectionName == "__objc_imageinfo");
+}
+
+llvm::Error
+normalizedObjectToAtoms(MachOFile *file,
+ const NormalizedFile &normalizedFile,
+ bool copyRefs) {
+ LLVM_DEBUG(llvm::dbgs() << "******** Normalizing file to atoms: "
+ << file->path() << "\n");
+ bool scatterable = ((normalizedFile.flags & MH_SUBSECTIONS_VIA_SYMBOLS) != 0);
+
+ // Create atoms from each section.
+ for (auto &sect : normalizedFile.sections) {
+
+ // If this is a debug-info section parse it specially.
+ if (isDebugInfoSection(sect))
+ continue;
+
+ // If the file contains an objc_image_info struct, then we should parse the
+ // ObjC flags and Swift version.
+ if (isObjCImageInfo(sect)) {
+ if (auto ec = parseObjCImageInfo(sect, normalizedFile, *file))
+ return ec;
+ // We then skip adding atoms for this section as we use the ObjCPass to
+ // re-emit this data after it has been aggregated for all files.
+ continue;
+ }
+
+ bool customSectionName;
+ DefinedAtom::ContentType atomType = atomTypeFromSection(sect,
+ customSectionName);
+ if (auto ec = processSection(atomType, sect, customSectionName,
+ normalizedFile, *file, scatterable, copyRefs))
+ return ec;
+ }
+ // Create atoms from undefined symbols.
+ for (auto &sym : normalizedFile.undefinedSymbols) {
+ // Undefinded symbols with n_value != 0 are actually tentative definitions.
+ if (sym.value == Hex64(0)) {
+ file->addUndefinedAtom(sym.name, copyRefs);
+ } else {
+ file->addTentativeDefAtom(sym.name, atomScope(sym.scope), sym.value,
+ DefinedAtom::Alignment(1 << (sym.desc >> 8)),
+ copyRefs);
+ }
+ }
+
+ // Convert mach-o relocations to References
+ std::unique_ptr<mach_o::ArchHandler> handler
+ = ArchHandler::create(normalizedFile.arch);
+ for (auto &sect : normalizedFile.sections) {
+ if (isDebugInfoSection(sect))
+ continue;
+ if (llvm::Error ec = convertRelocs(sect, normalizedFile, scatterable,
+ *file, *handler))
+ return ec;
+ }
+
+ // Add additional arch-specific References
+ file->eachDefinedAtom([&](MachODefinedAtom* atom) -> void {
+ handler->addAdditionalReferences(*atom);
+ });
+
+ // Each __eh_frame section needs references to both __text (the function we're
+ // providing unwind info for) and itself (FDE -> CIE). These aren't
+ // represented in the relocations on some architectures, so we have to add
+ // them back in manually there.
+ if (auto ec = addEHFrameReferences(normalizedFile, *file, *handler))
+ return ec;
+
+ // Process mach-o data-in-code regions array. That information is encoded in
+ // atoms as References at each transition point.
+ unsigned nextIndex = 0;
+ for (const DataInCode &entry : normalizedFile.dataInCode) {
+ ++nextIndex;
+ const Section* s = findSectionCoveringAddress(normalizedFile, entry.offset);
+ if (!s) {
+ return llvm::make_error<GenericError>(Twine("LC_DATA_IN_CODE address ("
+ + Twine(entry.offset)
+ + ") is not in any section"));
+ }
+ uint64_t offsetInSect = entry.offset - s->address;
+ uint32_t offsetInAtom;
+ MachODefinedAtom *atom = file->findAtomCoveringAddress(*s, offsetInSect,
+ &offsetInAtom);
+ if (offsetInAtom + entry.length > atom->size()) {
+ return llvm::make_error<GenericError>(Twine("LC_DATA_IN_CODE entry "
+ "(offset="
+ + Twine(entry.offset)
+ + ", length="
+ + Twine(entry.length)
+ + ") crosses atom boundary."));
+ }
+ // Add reference that marks start of data-in-code.
+ atom->addReference(Reference::KindNamespace::mach_o, handler->kindArch(),
+ handler->dataInCodeTransitionStart(*atom),
+ offsetInAtom, atom, entry.kind);
+
+ // Peek at next entry, if it starts where this one ends, skip ending ref.
+ if (nextIndex < normalizedFile.dataInCode.size()) {
+ const DataInCode &nextEntry = normalizedFile.dataInCode[nextIndex];
+ if (nextEntry.offset == (entry.offset + entry.length))
+ continue;
+ }
+
+ // If data goes to end of function, skip ending ref.
+ if ((offsetInAtom + entry.length) == atom->size())
+ continue;
+
+ // Add reference that marks end of data-in-code.
+ atom->addReference(Reference::KindNamespace::mach_o, handler->kindArch(),
+ handler->dataInCodeTransitionEnd(*atom),
+ offsetInAtom+entry.length, atom, 0);
+ }
+
+ // Cache some attributes on the file for use later.
+ file->setFlags(normalizedFile.flags);
+ file->setArch(normalizedFile.arch);
+ file->setOS(normalizedFile.os);
+ file->setMinVersion(normalizedFile.minOSverson);
+ file->setMinVersionLoadCommandKind(normalizedFile.minOSVersionKind);
+
+ // Sort references in each atom to their canonical order.
+ for (const DefinedAtom* defAtom : file->defined()) {
+ reinterpret_cast<const SimpleDefinedAtom*>(defAtom)->sortReferences();
+ }
+
+ if (auto err = parseDebugInfo(*file, normalizedFile, copyRefs))
+ return err;
+
+ return llvm::Error::success();
+}
+
+llvm::Error
+normalizedDylibToAtoms(MachODylibFile *file,
+ const NormalizedFile &normalizedFile,
+ bool copyRefs) {
+ file->setInstallName(normalizedFile.installName);
+ file->setCompatVersion(normalizedFile.compatVersion);
+ file->setCurrentVersion(normalizedFile.currentVersion);
+
+ // Tell MachODylibFile object about all symbols it exports.
+ if (!normalizedFile.exportInfo.empty()) {
+ // If exports trie exists, use it instead of traditional symbol table.
+ for (const Export &exp : normalizedFile.exportInfo) {
+ bool weakDef = (exp.flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);
+ // StringRefs from export iterator are ephemeral, so force copy.
+ file->addExportedSymbol(exp.name, weakDef, true);
+ }
+ } else {
+ for (auto &sym : normalizedFile.globalSymbols) {
+ assert((sym.scope & N_EXT) && "only expect external symbols here");
+ bool weakDef = (sym.desc & N_WEAK_DEF);
+ file->addExportedSymbol(sym.name, weakDef, copyRefs);
+ }
+ }
+ // Tell MachODylibFile object about all dylibs it re-exports.
+ for (const DependentDylib &dep : normalizedFile.dependentDylibs) {
+ if (dep.kind == llvm::MachO::LC_REEXPORT_DYLIB)
+ file->addReExportedDylib(dep.path);
+ }
+ return llvm::Error::success();
+}
+
+void relocatableSectionInfoForContentType(DefinedAtom::ContentType atomType,
+ StringRef &segmentName,
+ StringRef &sectionName,
+ SectionType &sectionType,
+ SectionAttr &sectionAttrs,
+ bool &relocsToDefinedCanBeImplicit) {
+
+ for (const MachORelocatableSectionToAtomType *p = sectsToAtomType ;
+ p->atomType != DefinedAtom::typeUnknown; ++p) {
+ if (p->atomType != atomType)
+ continue;
+ // Wild carded entries are ignored for reverse lookups.
+ if (p->segmentName.empty() || p->sectionName.empty())
+ continue;
+ segmentName = p->segmentName;
+ sectionName = p->sectionName;
+ sectionType = p->sectionType;
+ sectionAttrs = 0;
+ relocsToDefinedCanBeImplicit = false;
+ if (atomType == DefinedAtom::typeCode)
+ sectionAttrs = S_ATTR_PURE_INSTRUCTIONS;
+ if (atomType == DefinedAtom::typeCFI)
+ relocsToDefinedCanBeImplicit = true;
+ return;
+ }
+ llvm_unreachable("content type not yet supported");
+}
+
+llvm::Expected<std::unique_ptr<lld::File>>
+normalizedToAtoms(const NormalizedFile &normalizedFile, StringRef path,
+ bool copyRefs) {
+ switch (normalizedFile.fileType) {
+ case MH_DYLIB:
+ case MH_DYLIB_STUB:
+ return dylibToAtoms(normalizedFile, path, copyRefs);
+ case MH_OBJECT:
+ return objectToAtoms(normalizedFile, path, copyRefs);
+ default:
+ llvm_unreachable("unhandled MachO file type!");
+ }
+}
+
+} // namespace normalized
+} // namespace mach_o
+} // namespace lld
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp
new file mode 100644
index 000000000000..92a646dab5e0
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp
@@ -0,0 +1,843 @@
+//===- lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp -----------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+///
+/// \file For mach-o object files, this implementation uses YAML I/O to
+/// provide the convert between YAML and the normalized mach-o (NM).
+///
+/// +------------+ +------+
+/// | normalized | <-> | yaml |
+/// +------------+ +------+
+
+#include "MachONormalizedFile.h"
+#include "lld/Common/LLVM.h"
+#include "lld/Core/Error.h"
+#include "lld/ReaderWriter/YamlContext.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/YAMLTraits.h"
+#include "llvm/Support/raw_ostream.h"
+#include <system_error>
+
+using llvm::StringRef;
+using namespace llvm::yaml;
+using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
+using lld::YamlContext;
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(Segment)
+LLVM_YAML_IS_SEQUENCE_VECTOR(DependentDylib)
+LLVM_YAML_IS_SEQUENCE_VECTOR(RebaseLocation)
+LLVM_YAML_IS_SEQUENCE_VECTOR(BindLocation)
+LLVM_YAML_IS_SEQUENCE_VECTOR(Export)
+LLVM_YAML_IS_SEQUENCE_VECTOR(DataInCode)
+
+
+// for compatibility with gcc-4.7 in C++11 mode, add extra namespace
+namespace llvm {
+namespace yaml {
+
+// A vector of Sections is a sequence.
+template<>
+struct SequenceTraits< std::vector<Section> > {
+ static size_t size(IO &io, std::vector<Section> &seq) {
+ return seq.size();
+ }
+ static Section& element(IO &io, std::vector<Section> &seq, size_t index) {
+ if ( index >= seq.size() )
+ seq.resize(index+1);
+ return seq[index];
+ }
+};
+
+template<>
+struct SequenceTraits< std::vector<Symbol> > {
+ static size_t size(IO &io, std::vector<Symbol> &seq) {
+ return seq.size();
+ }
+ static Symbol& element(IO &io, std::vector<Symbol> &seq, size_t index) {
+ if ( index >= seq.size() )
+ seq.resize(index+1);
+ return seq[index];
+ }
+};
+
+// A vector of Relocations is a sequence.
+template<>
+struct SequenceTraits< Relocations > {
+ static size_t size(IO &io, Relocations &seq) {
+ return seq.size();
+ }
+ static Relocation& element(IO &io, Relocations &seq, size_t index) {
+ if ( index >= seq.size() )
+ seq.resize(index+1);
+ return seq[index];
+ }
+};
+
+// The content for a section is represented as a flow sequence of hex bytes.
+template<>
+struct SequenceTraits< ContentBytes > {
+ static size_t size(IO &io, ContentBytes &seq) {
+ return seq.size();
+ }
+ static Hex8& element(IO &io, ContentBytes &seq, size_t index) {
+ if ( index >= seq.size() )
+ seq.resize(index+1);
+ return seq[index];
+ }
+ static const bool flow = true;
+};
+
+// The indirect symbols for a section is represented as a flow sequence
+// of numbers (symbol table indexes).
+template<>
+struct SequenceTraits< IndirectSymbols > {
+ static size_t size(IO &io, IndirectSymbols &seq) {
+ return seq.size();
+ }
+ static uint32_t& element(IO &io, IndirectSymbols &seq, size_t index) {
+ if ( index >= seq.size() )
+ seq.resize(index+1);
+ return seq[index];
+ }
+ static const bool flow = true;
+};
+
+template <>
+struct ScalarEnumerationTraits<lld::MachOLinkingContext::Arch> {
+ static void enumeration(IO &io, lld::MachOLinkingContext::Arch &value) {
+ io.enumCase(value, "unknown",lld::MachOLinkingContext::arch_unknown);
+ io.enumCase(value, "ppc", lld::MachOLinkingContext::arch_ppc);
+ io.enumCase(value, "x86", lld::MachOLinkingContext::arch_x86);
+ io.enumCase(value, "x86_64", lld::MachOLinkingContext::arch_x86_64);
+ io.enumCase(value, "armv6", lld::MachOLinkingContext::arch_armv6);
+ io.enumCase(value, "armv7", lld::MachOLinkingContext::arch_armv7);
+ io.enumCase(value, "armv7s", lld::MachOLinkingContext::arch_armv7s);
+ io.enumCase(value, "arm64", lld::MachOLinkingContext::arch_arm64);
+ }
+};
+
+template <>
+struct ScalarEnumerationTraits<lld::MachOLinkingContext::OS> {
+ static void enumeration(IO &io, lld::MachOLinkingContext::OS &value) {
+ io.enumCase(value, "unknown",
+ lld::MachOLinkingContext::OS::unknown);
+ io.enumCase(value, "Mac OS X",
+ lld::MachOLinkingContext::OS::macOSX);
+ io.enumCase(value, "iOS",
+ lld::MachOLinkingContext::OS::iOS);
+ io.enumCase(value, "iOS Simulator",
+ lld::MachOLinkingContext::OS::iOS_simulator);
+ }
+};
+
+
+template <>
+struct ScalarEnumerationTraits<HeaderFileType> {
+ static void enumeration(IO &io, HeaderFileType &value) {
+ io.enumCase(value, "MH_OBJECT", llvm::MachO::MH_OBJECT);
+ io.enumCase(value, "MH_DYLIB", llvm::MachO::MH_DYLIB);
+ io.enumCase(value, "MH_EXECUTE", llvm::MachO::MH_EXECUTE);
+ io.enumCase(value, "MH_BUNDLE", llvm::MachO::MH_BUNDLE);
+ }
+};
+
+
+template <>
+struct ScalarBitSetTraits<FileFlags> {
+ static void bitset(IO &io, FileFlags &value) {
+ io.bitSetCase(value, "MH_TWOLEVEL",
+ llvm::MachO::MH_TWOLEVEL);
+ io.bitSetCase(value, "MH_SUBSECTIONS_VIA_SYMBOLS",
+ llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+ }
+};
+
+
+template <>
+struct ScalarEnumerationTraits<SectionType> {
+ static void enumeration(IO &io, SectionType &value) {
+ io.enumCase(value, "S_REGULAR",
+ llvm::MachO::S_REGULAR);
+ io.enumCase(value, "S_ZEROFILL",
+ llvm::MachO::S_ZEROFILL);
+ io.enumCase(value, "S_CSTRING_LITERALS",
+ llvm::MachO::S_CSTRING_LITERALS);
+ io.enumCase(value, "S_4BYTE_LITERALS",
+ llvm::MachO::S_4BYTE_LITERALS);
+ io.enumCase(value, "S_8BYTE_LITERALS",
+ llvm::MachO::S_8BYTE_LITERALS);
+ io.enumCase(value, "S_LITERAL_POINTERS",
+ llvm::MachO::S_LITERAL_POINTERS);
+ io.enumCase(value, "S_NON_LAZY_SYMBOL_POINTERS",
+ llvm::MachO::S_NON_LAZY_SYMBOL_POINTERS);
+ io.enumCase(value, "S_LAZY_SYMBOL_POINTERS",
+ llvm::MachO::S_LAZY_SYMBOL_POINTERS);
+ io.enumCase(value, "S_SYMBOL_STUBS",
+ llvm::MachO::S_SYMBOL_STUBS);
+ io.enumCase(value, "S_MOD_INIT_FUNC_POINTERS",
+ llvm::MachO::S_MOD_INIT_FUNC_POINTERS);
+ io.enumCase(value, "S_MOD_TERM_FUNC_POINTERS",
+ llvm::MachO::S_MOD_TERM_FUNC_POINTERS);
+ io.enumCase(value, "S_COALESCED",
+ llvm::MachO::S_COALESCED);
+ io.enumCase(value, "S_GB_ZEROFILL",
+ llvm::MachO::S_GB_ZEROFILL);
+ io.enumCase(value, "S_INTERPOSING",
+ llvm::MachO::S_INTERPOSING);
+ io.enumCase(value, "S_16BYTE_LITERALS",
+ llvm::MachO::S_16BYTE_LITERALS);
+ io.enumCase(value, "S_DTRACE_DOF",
+ llvm::MachO::S_DTRACE_DOF);
+ io.enumCase(value, "S_LAZY_DYLIB_SYMBOL_POINTERS",
+ llvm::MachO::S_LAZY_DYLIB_SYMBOL_POINTERS);
+ io.enumCase(value, "S_THREAD_LOCAL_REGULAR",
+ llvm::MachO::S_THREAD_LOCAL_REGULAR);
+ io.enumCase(value, "S_THREAD_LOCAL_ZEROFILL",
+ llvm::MachO::S_THREAD_LOCAL_ZEROFILL);
+ io.enumCase(value, "S_THREAD_LOCAL_VARIABLES",
+ llvm::MachO::S_THREAD_LOCAL_VARIABLES);
+ io.enumCase(value, "S_THREAD_LOCAL_VARIABLE_POINTERS",
+ llvm::MachO::S_THREAD_LOCAL_VARIABLE_POINTERS);
+ io.enumCase(value, "S_THREAD_LOCAL_INIT_FUNCTION_POINTERS",
+ llvm::MachO::S_THREAD_LOCAL_INIT_FUNCTION_POINTERS);
+ }
+};
+
+template <>
+struct ScalarBitSetTraits<SectionAttr> {
+ static void bitset(IO &io, SectionAttr &value) {
+ io.bitSetCase(value, "S_ATTR_PURE_INSTRUCTIONS",
+ llvm::MachO::S_ATTR_PURE_INSTRUCTIONS);
+ io.bitSetCase(value, "S_ATTR_SOME_INSTRUCTIONS",
+ llvm::MachO::S_ATTR_SOME_INSTRUCTIONS);
+ io.bitSetCase(value, "S_ATTR_NO_DEAD_STRIP",
+ llvm::MachO::S_ATTR_NO_DEAD_STRIP);
+ io.bitSetCase(value, "S_ATTR_EXT_RELOC",
+ llvm::MachO::S_ATTR_EXT_RELOC);
+ io.bitSetCase(value, "S_ATTR_LOC_RELOC",
+ llvm::MachO::S_ATTR_LOC_RELOC);
+ io.bitSetCase(value, "S_ATTR_DEBUG",
+ llvm::MachO::S_ATTR_DEBUG);
+ }
+};
+
+/// This is a custom formatter for SectionAlignment. Values are
+/// the power to raise by, ie, the n in 2^n.
+template <> struct ScalarTraits<SectionAlignment> {
+ static void output(const SectionAlignment &value, void *ctxt,
+ raw_ostream &out) {
+ out << llvm::format("%d", (uint32_t)value);
+ }
+
+ static StringRef input(StringRef scalar, void *ctxt,
+ SectionAlignment &value) {
+ uint32_t alignment;
+ if (scalar.getAsInteger(0, alignment)) {
+ return "malformed alignment value";
+ }
+ if (!llvm::isPowerOf2_32(alignment))
+ return "alignment must be a power of 2";
+ value = alignment;
+ return StringRef(); // returning empty string means success
+ }
+
+ static QuotingType mustQuote(StringRef) { return QuotingType::None; }
+};
+
+template <>
+struct ScalarEnumerationTraits<NListType> {
+ static void enumeration(IO &io, NListType &value) {
+ io.enumCase(value, "N_UNDF", llvm::MachO::N_UNDF);
+ io.enumCase(value, "N_ABS", llvm::MachO::N_ABS);
+ io.enumCase(value, "N_SECT", llvm::MachO::N_SECT);
+ io.enumCase(value, "N_PBUD", llvm::MachO::N_PBUD);
+ io.enumCase(value, "N_INDR", llvm::MachO::N_INDR);
+ }
+};
+
+template <>
+struct ScalarBitSetTraits<SymbolScope> {
+ static void bitset(IO &io, SymbolScope &value) {
+ io.bitSetCase(value, "N_EXT", llvm::MachO::N_EXT);
+ io.bitSetCase(value, "N_PEXT", llvm::MachO::N_PEXT);
+ }
+};
+
+template <>
+struct ScalarBitSetTraits<SymbolDesc> {
+ static void bitset(IO &io, SymbolDesc &value) {
+ io.bitSetCase(value, "N_NO_DEAD_STRIP", llvm::MachO::N_NO_DEAD_STRIP);
+ io.bitSetCase(value, "N_WEAK_REF", llvm::MachO::N_WEAK_REF);
+ io.bitSetCase(value, "N_WEAK_DEF", llvm::MachO::N_WEAK_DEF);
+ io.bitSetCase(value, "N_ARM_THUMB_DEF", llvm::MachO::N_ARM_THUMB_DEF);
+ io.bitSetCase(value, "N_SYMBOL_RESOLVER", llvm::MachO::N_SYMBOL_RESOLVER);
+ }
+};
+
+
+template <>
+struct MappingTraits<Section> {
+ struct NormalizedContentBytes;
+ static void mapping(IO &io, Section &sect) {
+ io.mapRequired("segment", sect.segmentName);
+ io.mapRequired("section", sect.sectionName);
+ io.mapRequired("type", sect.type);
+ io.mapOptional("attributes", sect.attributes);
+ io.mapOptional("alignment", sect.alignment, (SectionAlignment)1);
+ io.mapRequired("address", sect.address);
+ if (isZeroFillSection(sect.type)) {
+ // S_ZEROFILL sections use "size:" instead of "content:"
+ uint64_t size = sect.content.size();
+ io.mapOptional("size", size);
+ if (!io.outputting()) {
+ uint8_t *bytes = nullptr;
+ sect.content = makeArrayRef(bytes, size);
+ }
+ } else {
+ MappingNormalization<NormalizedContent, ArrayRef<uint8_t>> content(
+ io, sect.content);
+ io.mapOptional("content", content->_normalizedContent);
+ }
+ io.mapOptional("relocations", sect.relocations);
+ io.mapOptional("indirect-syms", sect.indirectSymbols);
+ }
+
+ struct NormalizedContent {
+ NormalizedContent(IO &io) : _io(io) {}
+ NormalizedContent(IO &io, ArrayRef<uint8_t> content) : _io(io) {
+ // When writing yaml, copy content byte array to Hex8 vector.
+ for (auto &c : content) {
+ _normalizedContent.push_back(c);
+ }
+ }
+ ArrayRef<uint8_t> denormalize(IO &io) {
+ // When reading yaml, allocate byte array owned by NormalizedFile and
+ // copy Hex8 vector to byte array.
+ YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+ assert(info != nullptr);
+ NormalizedFile *file = info->_normalizeMachOFile;
+ assert(file != nullptr);
+ size_t size = _normalizedContent.size();
+ if (!size)
+ return None;
+ uint8_t *bytes = file->ownedAllocations.Allocate<uint8_t>(size);
+ std::copy(_normalizedContent.begin(), _normalizedContent.end(), bytes);
+ return makeArrayRef(bytes, size);
+ }
+
+ IO &_io;
+ ContentBytes _normalizedContent;
+ };
+};
+
+
+template <>
+struct MappingTraits<Relocation> {
+ static void mapping(IO &io, Relocation &reloc) {
+ io.mapRequired("offset", reloc.offset);
+ io.mapOptional("scattered", reloc.scattered, false);
+ io.mapRequired("type", reloc.type);
+ io.mapRequired("length", reloc.length);
+ io.mapRequired("pc-rel", reloc.pcRel);
+ if ( !reloc.scattered )
+ io.mapRequired("extern", reloc.isExtern);
+ if ( reloc.scattered )
+ io.mapRequired("value", reloc.value);
+ if ( !reloc.scattered )
+ io.mapRequired("symbol", reloc.symbol);
+ }
+};
+
+
+template <>
+struct ScalarEnumerationTraits<RelocationInfoType> {
+ static void enumeration(IO &io, RelocationInfoType &value) {
+ YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+ assert(info != nullptr);
+ NormalizedFile *file = info->_normalizeMachOFile;
+ assert(file != nullptr);
+ switch (file->arch) {
+ case lld::MachOLinkingContext::arch_x86_64:
+ io.enumCase(value, "X86_64_RELOC_UNSIGNED",
+ llvm::MachO::X86_64_RELOC_UNSIGNED);
+ io.enumCase(value, "X86_64_RELOC_SIGNED",
+ llvm::MachO::X86_64_RELOC_SIGNED);
+ io.enumCase(value, "X86_64_RELOC_BRANCH",
+ llvm::MachO::X86_64_RELOC_BRANCH);
+ io.enumCase(value, "X86_64_RELOC_GOT_LOAD",
+ llvm::MachO::X86_64_RELOC_GOT_LOAD);
+ io.enumCase(value, "X86_64_RELOC_GOT",
+ llvm::MachO::X86_64_RELOC_GOT);
+ io.enumCase(value, "X86_64_RELOC_SUBTRACTOR",
+ llvm::MachO::X86_64_RELOC_SUBTRACTOR);
+ io.enumCase(value, "X86_64_RELOC_SIGNED_1",
+ llvm::MachO::X86_64_RELOC_SIGNED_1);
+ io.enumCase(value, "X86_64_RELOC_SIGNED_2",
+ llvm::MachO::X86_64_RELOC_SIGNED_2);
+ io.enumCase(value, "X86_64_RELOC_SIGNED_4",
+ llvm::MachO::X86_64_RELOC_SIGNED_4);
+ io.enumCase(value, "X86_64_RELOC_TLV",
+ llvm::MachO::X86_64_RELOC_TLV);
+ break;
+ case lld::MachOLinkingContext::arch_x86:
+ io.enumCase(value, "GENERIC_RELOC_VANILLA",
+ llvm::MachO::GENERIC_RELOC_VANILLA);
+ io.enumCase(value, "GENERIC_RELOC_PAIR",
+ llvm::MachO::GENERIC_RELOC_PAIR);
+ io.enumCase(value, "GENERIC_RELOC_SECTDIFF",
+ llvm::MachO::GENERIC_RELOC_SECTDIFF);
+ io.enumCase(value, "GENERIC_RELOC_LOCAL_SECTDIFF",
+ llvm::MachO::GENERIC_RELOC_LOCAL_SECTDIFF);
+ io.enumCase(value, "GENERIC_RELOC_TLV",
+ llvm::MachO::GENERIC_RELOC_TLV);
+ break;
+ case lld::MachOLinkingContext::arch_armv6:
+ case lld::MachOLinkingContext::arch_armv7:
+ case lld::MachOLinkingContext::arch_armv7s:
+ io.enumCase(value, "ARM_RELOC_VANILLA",
+ llvm::MachO::ARM_RELOC_VANILLA);
+ io.enumCase(value, "ARM_RELOC_PAIR",
+ llvm::MachO::ARM_RELOC_PAIR);
+ io.enumCase(value, "ARM_RELOC_SECTDIFF",
+ llvm::MachO::ARM_RELOC_SECTDIFF);
+ io.enumCase(value, "ARM_RELOC_LOCAL_SECTDIFF",
+ llvm::MachO::ARM_RELOC_LOCAL_SECTDIFF);
+ io.enumCase(value, "ARM_RELOC_BR24",
+ llvm::MachO::ARM_RELOC_BR24);
+ io.enumCase(value, "ARM_THUMB_RELOC_BR22",
+ llvm::MachO::ARM_THUMB_RELOC_BR22);
+ io.enumCase(value, "ARM_RELOC_HALF",
+ llvm::MachO::ARM_RELOC_HALF);
+ io.enumCase(value, "ARM_RELOC_HALF_SECTDIFF",
+ llvm::MachO::ARM_RELOC_HALF_SECTDIFF);
+ break;
+ case lld::MachOLinkingContext::arch_arm64:
+ io.enumCase(value, "ARM64_RELOC_UNSIGNED",
+ llvm::MachO::ARM64_RELOC_UNSIGNED);
+ io.enumCase(value, "ARM64_RELOC_SUBTRACTOR",
+ llvm::MachO::ARM64_RELOC_SUBTRACTOR);
+ io.enumCase(value, "ARM64_RELOC_BRANCH26",
+ llvm::MachO::ARM64_RELOC_BRANCH26);
+ io.enumCase(value, "ARM64_RELOC_PAGE21",
+ llvm::MachO::ARM64_RELOC_PAGE21);
+ io.enumCase(value, "ARM64_RELOC_PAGEOFF12",
+ llvm::MachO::ARM64_RELOC_PAGEOFF12);
+ io.enumCase(value, "ARM64_RELOC_GOT_LOAD_PAGE21",
+ llvm::MachO::ARM64_RELOC_GOT_LOAD_PAGE21);
+ io.enumCase(value, "ARM64_RELOC_GOT_LOAD_PAGEOFF12",
+ llvm::MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12);
+ io.enumCase(value, "ARM64_RELOC_POINTER_TO_GOT",
+ llvm::MachO::ARM64_RELOC_POINTER_TO_GOT);
+ io.enumCase(value, "ARM64_RELOC_TLVP_LOAD_PAGE21",
+ llvm::MachO::ARM64_RELOC_TLVP_LOAD_PAGE21);
+ io.enumCase(value, "ARM64_RELOC_TLVP_LOAD_PAGEOFF12",
+ llvm::MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12);
+ io.enumCase(value, "ARM64_RELOC_ADDEND",
+ llvm::MachO::ARM64_RELOC_ADDEND);
+ break;
+ default:
+ llvm_unreachable("unknown architecture");
+ }
+ }
+};
+
+
+template <>
+struct MappingTraits<Symbol> {
+ static void mapping(IO &io, Symbol& sym) {
+ io.mapRequired("name", sym.name);
+ io.mapRequired("type", sym.type);
+ io.mapOptional("scope", sym.scope, SymbolScope(0));
+ io.mapOptional("sect", sym.sect, (uint8_t)0);
+ if (sym.type == llvm::MachO::N_UNDF) {
+ // In undef symbols, desc field contains alignment/ordinal info
+ // which is better represented as a hex vaule.
+ uint16_t t1 = sym.desc;
+ Hex16 t2 = t1;
+ io.mapOptional("desc", t2, Hex16(0));
+ sym.desc = t2;
+ } else {
+ // In defined symbols, desc fit is a set of option bits.
+ io.mapOptional("desc", sym.desc, SymbolDesc(0));
+ }
+ io.mapRequired("value", sym.value);
+ }
+};
+
+// Custom mapping for VMProtect (e.g. "r-x").
+template <>
+struct ScalarTraits<VMProtect> {
+ static void output(const VMProtect &value, void*, raw_ostream &out) {
+ out << ( (value & llvm::MachO::VM_PROT_READ) ? 'r' : '-');
+ out << ( (value & llvm::MachO::VM_PROT_WRITE) ? 'w' : '-');
+ out << ( (value & llvm::MachO::VM_PROT_EXECUTE) ? 'x' : '-');
+ }
+ static StringRef input(StringRef scalar, void*, VMProtect &value) {
+ value = 0;
+ if (scalar.size() != 3)
+ return "segment access protection must be three chars (e.g. \"r-x\")";
+ switch (scalar[0]) {
+ case 'r':
+ value = llvm::MachO::VM_PROT_READ;
+ break;
+ case '-':
+ break;
+ default:
+ return "segment access protection first char must be 'r' or '-'";
+ }
+ switch (scalar[1]) {
+ case 'w':
+ value = value | llvm::MachO::VM_PROT_WRITE;
+ break;
+ case '-':
+ break;
+ default:
+ return "segment access protection second char must be 'w' or '-'";
+ }
+ switch (scalar[2]) {
+ case 'x':
+ value = value | llvm::MachO::VM_PROT_EXECUTE;
+ break;
+ case '-':
+ break;
+ default:
+ return "segment access protection third char must be 'x' or '-'";
+ }
+ // Return the empty string on success,
+ return StringRef();
+ }
+ static QuotingType mustQuote(StringRef) { return QuotingType::None; }
+};
+
+
+template <>
+struct MappingTraits<Segment> {
+ static void mapping(IO &io, Segment& seg) {
+ io.mapRequired("name", seg.name);
+ io.mapRequired("address", seg.address);
+ io.mapRequired("size", seg.size);
+ io.mapRequired("init-access", seg.init_access);
+ io.mapRequired("max-access", seg.max_access);
+ }
+};
+
+template <>
+struct ScalarEnumerationTraits<LoadCommandType> {
+ static void enumeration(IO &io, LoadCommandType &value) {
+ io.enumCase(value, "LC_LOAD_DYLIB",
+ llvm::MachO::LC_LOAD_DYLIB);
+ io.enumCase(value, "LC_LOAD_WEAK_DYLIB",
+ llvm::MachO::LC_LOAD_WEAK_DYLIB);
+ io.enumCase(value, "LC_REEXPORT_DYLIB",
+ llvm::MachO::LC_REEXPORT_DYLIB);
+ io.enumCase(value, "LC_LOAD_UPWARD_DYLIB",
+ llvm::MachO::LC_LOAD_UPWARD_DYLIB);
+ io.enumCase(value, "LC_LAZY_LOAD_DYLIB",
+ llvm::MachO::LC_LAZY_LOAD_DYLIB);
+ io.enumCase(value, "LC_VERSION_MIN_MACOSX",
+ llvm::MachO::LC_VERSION_MIN_MACOSX);
+ io.enumCase(value, "LC_VERSION_MIN_IPHONEOS",
+ llvm::MachO::LC_VERSION_MIN_IPHONEOS);
+ io.enumCase(value, "LC_VERSION_MIN_TVOS",
+ llvm::MachO::LC_VERSION_MIN_TVOS);
+ io.enumCase(value, "LC_VERSION_MIN_WATCHOS",
+ llvm::MachO::LC_VERSION_MIN_WATCHOS);
+ }
+};
+
+template <>
+struct MappingTraits<DependentDylib> {
+ static void mapping(IO &io, DependentDylib& dylib) {
+ io.mapRequired("path", dylib.path);
+ io.mapOptional("kind", dylib.kind,
+ llvm::MachO::LC_LOAD_DYLIB);
+ io.mapOptional("compat-version", dylib.compatVersion,
+ PackedVersion(0x10000));
+ io.mapOptional("current-version", dylib.currentVersion,
+ PackedVersion(0x10000));
+ }
+};
+
+template <>
+struct ScalarEnumerationTraits<RebaseType> {
+ static void enumeration(IO &io, RebaseType &value) {
+ io.enumCase(value, "REBASE_TYPE_POINTER",
+ llvm::MachO::REBASE_TYPE_POINTER);
+ io.enumCase(value, "REBASE_TYPE_TEXT_PCREL32",
+ llvm::MachO::REBASE_TYPE_TEXT_PCREL32);
+ io.enumCase(value, "REBASE_TYPE_TEXT_ABSOLUTE32",
+ llvm::MachO::REBASE_TYPE_TEXT_ABSOLUTE32);
+ }
+};
+
+
+template <>
+struct MappingTraits<RebaseLocation> {
+ static void mapping(IO &io, RebaseLocation& rebase) {
+ io.mapRequired("segment-index", rebase.segIndex);
+ io.mapRequired("segment-offset", rebase.segOffset);
+ io.mapOptional("kind", rebase.kind,
+ llvm::MachO::REBASE_TYPE_POINTER);
+ }
+};
+
+
+
+template <>
+struct ScalarEnumerationTraits<BindType> {
+ static void enumeration(IO &io, BindType &value) {
+ io.enumCase(value, "BIND_TYPE_POINTER",
+ llvm::MachO::BIND_TYPE_POINTER);
+ io.enumCase(value, "BIND_TYPE_TEXT_ABSOLUTE32",
+ llvm::MachO::BIND_TYPE_TEXT_ABSOLUTE32);
+ io.enumCase(value, "BIND_TYPE_TEXT_PCREL32",
+ llvm::MachO::BIND_TYPE_TEXT_PCREL32);
+ }
+};
+
+template <>
+struct MappingTraits<BindLocation> {
+ static void mapping(IO &io, BindLocation &bind) {
+ io.mapRequired("segment-index", bind.segIndex);
+ io.mapRequired("segment-offset", bind.segOffset);
+ io.mapOptional("kind", bind.kind,
+ llvm::MachO::BIND_TYPE_POINTER);
+ io.mapOptional("can-be-null", bind.canBeNull, false);
+ io.mapRequired("ordinal", bind.ordinal);
+ io.mapRequired("symbol-name", bind.symbolName);
+ io.mapOptional("addend", bind.addend, Hex64(0));
+ }
+};
+
+
+template <>
+struct ScalarEnumerationTraits<ExportSymbolKind> {
+ static void enumeration(IO &io, ExportSymbolKind &value) {
+ io.enumCase(value, "EXPORT_SYMBOL_FLAGS_KIND_REGULAR",
+ llvm::MachO::EXPORT_SYMBOL_FLAGS_KIND_REGULAR);
+ io.enumCase(value, "EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL",
+ llvm::MachO::EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL);
+ io.enumCase(value, "EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE",
+ llvm::MachO::EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE);
+ }
+};
+
+template <>
+struct ScalarBitSetTraits<ExportFlags> {
+ static void bitset(IO &io, ExportFlags &value) {
+ io.bitSetCase(value, "EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION",
+ llvm::MachO::EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);
+ io.bitSetCase(value, "EXPORT_SYMBOL_FLAGS_REEXPORT",
+ llvm::MachO::EXPORT_SYMBOL_FLAGS_REEXPORT);
+ io.bitSetCase(value, "EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER",
+ llvm::MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER);
+ }
+};
+
+
+template <>
+struct MappingTraits<Export> {
+ static void mapping(IO &io, Export &exp) {
+ io.mapRequired("name", exp.name);
+ io.mapOptional("offset", exp.offset);
+ io.mapOptional("kind", exp.kind,
+ llvm::MachO::EXPORT_SYMBOL_FLAGS_KIND_REGULAR);
+ if (!io.outputting() || exp.flags)
+ io.mapOptional("flags", exp.flags);
+ io.mapOptional("other", exp.otherOffset, Hex32(0));
+ io.mapOptional("other-name", exp.otherName, StringRef());
+ }
+};
+
+template <>
+struct ScalarEnumerationTraits<DataRegionType> {
+ static void enumeration(IO &io, DataRegionType &value) {
+ io.enumCase(value, "DICE_KIND_DATA",
+ llvm::MachO::DICE_KIND_DATA);
+ io.enumCase(value, "DICE_KIND_JUMP_TABLE8",
+ llvm::MachO::DICE_KIND_JUMP_TABLE8);
+ io.enumCase(value, "DICE_KIND_JUMP_TABLE16",
+ llvm::MachO::DICE_KIND_JUMP_TABLE16);
+ io.enumCase(value, "DICE_KIND_JUMP_TABLE32",
+ llvm::MachO::DICE_KIND_JUMP_TABLE32);
+ io.enumCase(value, "DICE_KIND_ABS_JUMP_TABLE32",
+ llvm::MachO::DICE_KIND_ABS_JUMP_TABLE32);
+ }
+};
+
+template <>
+struct MappingTraits<DataInCode> {
+ static void mapping(IO &io, DataInCode &entry) {
+ io.mapRequired("offset", entry.offset);
+ io.mapRequired("length", entry.length);
+ io.mapRequired("kind", entry.kind);
+ }
+};
+
+template <>
+struct ScalarTraits<PackedVersion> {
+ static void output(const PackedVersion &value, void*, raw_ostream &out) {
+ out << llvm::format("%d.%d", (value >> 16), (value >> 8) & 0xFF);
+ if (value & 0xFF) {
+ out << llvm::format(".%d", (value & 0xFF));
+ }
+ }
+ static StringRef input(StringRef scalar, void*, PackedVersion &result) {
+ uint32_t value;
+ if (lld::MachOLinkingContext::parsePackedVersion(scalar, value))
+ return "malformed version number";
+ result = value;
+ // Return the empty string on success,
+ return StringRef();
+ }
+ static QuotingType mustQuote(StringRef) { return QuotingType::None; }
+};
+
+template <>
+struct MappingTraits<NormalizedFile> {
+ static void mapping(IO &io, NormalizedFile &file) {
+ io.mapRequired("arch", file.arch);
+ io.mapRequired("file-type", file.fileType);
+ io.mapOptional("flags", file.flags);
+ io.mapOptional("dependents", file.dependentDylibs);
+ io.mapOptional("install-name", file.installName, StringRef());
+ io.mapOptional("compat-version", file.compatVersion, PackedVersion(0x10000));
+ io.mapOptional("current-version", file.currentVersion, PackedVersion(0x10000));
+ io.mapOptional("has-UUID", file.hasUUID, true);
+ io.mapOptional("rpaths", file.rpaths);
+ io.mapOptional("entry-point", file.entryAddress, Hex64(0));
+ io.mapOptional("stack-size", file.stackSize, Hex64(0));
+ io.mapOptional("source-version", file.sourceVersion, Hex64(0));
+ io.mapOptional("OS", file.os);
+ io.mapOptional("min-os-version", file.minOSverson, PackedVersion(0));
+ io.mapOptional("min-os-version-kind", file.minOSVersionKind, (LoadCommandType)0);
+ io.mapOptional("sdk-version", file.sdkVersion, PackedVersion(0));
+ io.mapOptional("segments", file.segments);
+ io.mapOptional("sections", file.sections);
+ io.mapOptional("local-symbols", file.localSymbols);
+ io.mapOptional("global-symbols", file.globalSymbols);
+ io.mapOptional("undefined-symbols",file.undefinedSymbols);
+ io.mapOptional("page-size", file.pageSize, Hex32(4096));
+ io.mapOptional("rebasings", file.rebasingInfo);
+ io.mapOptional("bindings", file.bindingInfo);
+ io.mapOptional("weak-bindings", file.weakBindingInfo);
+ io.mapOptional("lazy-bindings", file.lazyBindingInfo);
+ io.mapOptional("exports", file.exportInfo);
+ io.mapOptional("dataInCode", file.dataInCode);
+ }
+ static StringRef validate(IO &io, NormalizedFile &file) {
+ return StringRef();
+ }
+};
+
+} // namespace llvm
+} // namespace yaml
+
+
+namespace lld {
+namespace mach_o {
+
+/// Handles !mach-o tagged yaml documents.
+bool MachOYamlIOTaggedDocumentHandler::handledDocTag(llvm::yaml::IO &io,
+ const lld::File *&file) const {
+ if (!io.mapTag("!mach-o"))
+ return false;
+ // Step 1: parse yaml into normalized mach-o struct.
+ NormalizedFile nf;
+ YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+ assert(info != nullptr);
+ assert(info->_normalizeMachOFile == nullptr);
+ info->_normalizeMachOFile = &nf;
+ MappingTraits<NormalizedFile>::mapping(io, nf);
+ // Step 2: parse normalized mach-o struct into atoms.
+ auto fileOrError = normalizedToAtoms(nf, info->_path, true);
+
+ // Check that we parsed successfully.
+ if (!fileOrError) {
+ std::string buffer;
+ llvm::raw_string_ostream stream(buffer);
+ handleAllErrors(fileOrError.takeError(),
+ [&](const llvm::ErrorInfoBase &EI) {
+ EI.log(stream);
+ stream << "\n";
+ });
+ io.setError(stream.str());
+ return false;
+ }
+
+ if (nf.arch != _arch) {
+ io.setError(Twine("file is wrong architecture. Expected ("
+ + MachOLinkingContext::nameFromArch(_arch)
+ + ") found ("
+ + MachOLinkingContext::nameFromArch(nf.arch)
+ + ")"));
+ return false;
+ }
+ info->_normalizeMachOFile = nullptr;
+ file = fileOrError->release();
+ return true;
+}
+
+
+
+namespace normalized {
+
+/// Parses a yaml encoded mach-o file to produce an in-memory normalized view.
+llvm::Expected<std::unique_ptr<NormalizedFile>>
+readYaml(std::unique_ptr<MemoryBuffer> &mb) {
+ // Make empty NormalizedFile.
+ std::unique_ptr<NormalizedFile> f(new NormalizedFile());
+
+ // Create YAML Input parser.
+ YamlContext yamlContext;
+ yamlContext._normalizeMachOFile = f.get();
+ llvm::yaml::Input yin(mb->getBuffer(), &yamlContext);
+
+ // Fill NormalizedFile by parsing yaml.
+ yin >> *f;
+
+ // Return error if there were parsing problems.
+ if (auto ec = yin.error())
+ return llvm::make_error<GenericError>(Twine("YAML parsing error: ")
+ + ec.message());
+
+ // Hand ownership of instantiated NormalizedFile to caller.
+ return std::move(f);
+}
+
+
+/// Writes a yaml encoded mach-o files from an in-memory normalized view.
+std::error_code writeYaml(const NormalizedFile &file, raw_ostream &out) {
+ // YAML I/O is not const aware, so need to cast away ;-(
+ NormalizedFile *f = const_cast<NormalizedFile*>(&file);
+
+ // Create yaml Output writer, using yaml options for context.
+ YamlContext yamlContext;
+ yamlContext._normalizeMachOFile = f;
+ llvm::yaml::Output yout(out, &yamlContext);
+
+ // Stream out yaml.
+ yout << *f;
+
+ return std::error_code();
+}
+
+} // namespace normalized
+} // namespace mach_o
+} // namespace lld
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachOPasses.h b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachOPasses.h
new file mode 100644
index 000000000000..cd01d4aa2c93
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachOPasses.h
@@ -0,0 +1,30 @@
+//===- lib/ReaderWriter/MachO/MachOPasses.h -------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_MACHO_PASSES_H
+#define LLD_READER_WRITER_MACHO_PASSES_H
+
+#include "lld/Core/PassManager.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+
+namespace lld {
+namespace mach_o {
+
+void addLayoutPass(PassManager &pm, const MachOLinkingContext &ctx);
+void addStubsPass(PassManager &pm, const MachOLinkingContext &ctx);
+void addGOTPass(PassManager &pm, const MachOLinkingContext &ctx);
+void addTLVPass(PassManager &pm, const MachOLinkingContext &ctx);
+void addCompactUnwindPass(PassManager &pm, const MachOLinkingContext &ctx);
+void addObjCPass(PassManager &pm, const MachOLinkingContext &ctx);
+void addShimPass(PassManager &pm, const MachOLinkingContext &ctx);
+
+} // namespace mach_o
+} // namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_PASSES_H
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ObjCPass.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ObjCPass.cpp
new file mode 100644
index 000000000000..23c71e0f5ecd
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ObjCPass.cpp
@@ -0,0 +1,132 @@
+//===- lib/ReaderWriter/MachO/ObjCPass.cpp -------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+
+#include "ArchHandler.h"
+#include "File.h"
+#include "MachONormalizedFileBinaryUtils.h"
+#include "MachOPasses.h"
+#include "lld/Common/LLVM.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/Simple.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
+
+namespace lld {
+namespace mach_o {
+
+///
+/// ObjC Image Info Atom created by the ObjC pass.
+///
+class ObjCImageInfoAtom : public SimpleDefinedAtom {
+public:
+ ObjCImageInfoAtom(const File &file, bool isBig,
+ MachOLinkingContext::ObjCConstraint objCConstraint,
+ uint32_t swiftVersion)
+ : SimpleDefinedAtom(file) {
+
+ Data.info.version = 0;
+
+ switch (objCConstraint) {
+ case MachOLinkingContext::objc_unknown:
+ llvm_unreachable("Shouldn't run the objc pass without a constraint");
+ case MachOLinkingContext::objc_supports_gc:
+ case MachOLinkingContext::objc_gc_only:
+ llvm_unreachable("GC is not supported");
+ case MachOLinkingContext::objc_retainReleaseForSimulator:
+ // The retain/release for simulator flag is already the correct
+ // encoded value for the data so just set it here.
+ Data.info.flags = (uint32_t)objCConstraint;
+ break;
+ case MachOLinkingContext::objc_retainRelease:
+ // We don't need to encode this flag, so just leave the flags as 0.
+ Data.info.flags = 0;
+ break;
+ }
+
+ Data.info.flags |= (swiftVersion << 8);
+
+ normalized::write32(Data.bytes + 4, Data.info.flags, isBig);
+ }
+
+ ~ObjCImageInfoAtom() override = default;
+
+ ContentType contentType() const override {
+ return DefinedAtom::typeObjCImageInfo;
+ }
+
+ Alignment alignment() const override {
+ return 4;
+ }
+
+ uint64_t size() const override {
+ return 8;
+ }
+
+ ContentPermissions permissions() const override {
+ return DefinedAtom::permR__;
+ }
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return llvm::makeArrayRef(Data.bytes, size());
+ }
+
+private:
+
+ struct objc_image_info {
+ uint32_t version;
+ uint32_t flags;
+ };
+
+ union {
+ objc_image_info info;
+ uint8_t bytes[8];
+ } Data;
+};
+
+class ObjCPass : public Pass {
+public:
+ ObjCPass(const MachOLinkingContext &context)
+ : _ctx(context),
+ _file(*_ctx.make_file<MachOFile>("<mach-o objc pass>")) {
+ _file.setOrdinal(_ctx.getNextOrdinalAndIncrement());
+ }
+
+ llvm::Error perform(SimpleFile &mergedFile) override {
+ // Add the image info.
+ mergedFile.addAtom(*getImageInfo());
+
+ return llvm::Error::success();
+ }
+
+private:
+
+ const DefinedAtom* getImageInfo() {
+ bool IsBig = MachOLinkingContext::isBigEndian(_ctx.arch());
+ return new (_file.allocator()) ObjCImageInfoAtom(_file, IsBig,
+ _ctx.objcConstraint(),
+ _ctx.swiftVersion());
+ }
+
+ const MachOLinkingContext &_ctx;
+ MachOFile &_file;
+};
+
+
+
+void addObjCPass(PassManager &pm, const MachOLinkingContext &ctx) {
+ pm.add(llvm::make_unique<ObjCPass>(ctx));
+}
+
+} // end namespace mach_o
+} // end namespace lld
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/SectCreateFile.h b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/SectCreateFile.h
new file mode 100644
index 000000000000..49e65f63151d
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/SectCreateFile.h
@@ -0,0 +1,102 @@
+//===---- lib/ReaderWriter/MachO/SectCreateFile.h ---------------*- c++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_MACHO_SECTCREATE_FILE_H
+#define LLD_READER_WRITER_MACHO_SECTCREATE_FILE_H
+
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/Simple.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+
+namespace lld {
+namespace mach_o {
+
+//
+// A FlateNamespaceFile instance may be added as a resolution source of last
+// resort, depending on how -flat_namespace and -undefined are set.
+//
+class SectCreateFile : public File {
+public:
+ class SectCreateAtom : public SimpleDefinedAtom {
+ public:
+ SectCreateAtom(const File &file, StringRef segName, StringRef sectName,
+ std::unique_ptr<MemoryBuffer> content)
+ : SimpleDefinedAtom(file),
+ _combinedName((segName + "/" + sectName).str()),
+ _content(std::move(content)) {}
+
+ ~SectCreateAtom() override = default;
+
+ uint64_t size() const override { return _content->getBufferSize(); }
+
+ Scope scope() const override { return scopeGlobal; }
+
+ ContentType contentType() const override { return typeSectCreate; }
+
+ SectionChoice sectionChoice() const override { return sectionCustomRequired; }
+
+ StringRef customSectionName() const override { return _combinedName; }
+
+ DeadStripKind deadStrip() const override { return deadStripNever; }
+
+ ArrayRef<uint8_t> rawContent() const override {
+ const uint8_t *data =
+ reinterpret_cast<const uint8_t*>(_content->getBufferStart());
+ return ArrayRef<uint8_t>(data, _content->getBufferSize());
+ }
+
+ StringRef segmentName() const { return _segName; }
+ StringRef sectionName() const { return _sectName; }
+
+ private:
+ std::string _combinedName;
+ StringRef _segName;
+ StringRef _sectName;
+ std::unique_ptr<MemoryBuffer> _content;
+ };
+
+ SectCreateFile() : File("sectcreate", kindSectCreateObject) {}
+
+ void addSection(StringRef seg, StringRef sect,
+ std::unique_ptr<MemoryBuffer> content) {
+ _definedAtoms.push_back(
+ new (allocator()) SectCreateAtom(*this, seg, sect, std::move(content)));
+ }
+
+ const AtomRange<DefinedAtom> defined() const override {
+ return _definedAtoms;
+ }
+
+ const AtomRange<UndefinedAtom> undefined() const override {
+ return _noUndefinedAtoms;
+ }
+
+ const AtomRange<SharedLibraryAtom> sharedLibrary() const override {
+ return _noSharedLibraryAtoms;
+ }
+
+ const AtomRange<AbsoluteAtom> absolute() const override {
+ return _noAbsoluteAtoms;
+ }
+
+ void clearAtoms() override {
+ _definedAtoms.clear();
+ _noUndefinedAtoms.clear();
+ _noSharedLibraryAtoms.clear();
+ _noAbsoluteAtoms.clear();
+ }
+
+private:
+ AtomVector<DefinedAtom> _definedAtoms;
+};
+
+} // namespace mach_o
+} // namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_SECTCREATE_FILE_H
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ShimPass.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ShimPass.cpp
new file mode 100644
index 000000000000..8a2d2e910cad
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ShimPass.cpp
@@ -0,0 +1,129 @@
+//===- lib/ReaderWriter/MachO/ShimPass.cpp -------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This linker pass updates branch-sites whose target is a different mode
+// (thumb vs arm).
+//
+// Arm code has two instruction encodings thumb and arm. When branching from
+// one code encoding to another, you need to use an instruction that switches
+// the instruction mode. Usually the transition only happens at call sites, and
+// the linker can transform a BL instruction in BLX (or vice versa). But if the
+// compiler did a tail call optimization and a function ends with a branch (not
+// branch and link), there is no pc-rel BX instruction.
+//
+// The ShimPass looks for pc-rel B instructions that will need to switch mode.
+// For those cases it synthesizes a shim which does the transition, then
+// modifies the original atom with the B instruction to target to the shim atom.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ArchHandler.h"
+#include "File.h"
+#include "MachOPasses.h"
+#include "lld/Common/LLVM.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/Simple.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
+
+namespace lld {
+namespace mach_o {
+
+class ShimPass : public Pass {
+public:
+ ShimPass(const MachOLinkingContext &context)
+ : _ctx(context), _archHandler(_ctx.archHandler()),
+ _stubInfo(_archHandler.stubInfo()),
+ _file(*_ctx.make_file<MachOFile>("<mach-o shim pass>")) {
+ _file.setOrdinal(_ctx.getNextOrdinalAndIncrement());
+ }
+
+ llvm::Error perform(SimpleFile &mergedFile) override {
+ // Scan all references in all atoms.
+ for (const DefinedAtom *atom : mergedFile.defined()) {
+ for (const Reference *ref : *atom) {
+ // Look at non-call branches.
+ if (!_archHandler.isNonCallBranch(*ref))
+ continue;
+ const Atom *target = ref->target();
+ assert(target != nullptr);
+ if (const lld::DefinedAtom *daTarget = dyn_cast<DefinedAtom>(target)) {
+ bool atomIsThumb = _archHandler.isThumbFunction(*atom);
+ bool targetIsThumb = _archHandler.isThumbFunction(*daTarget);
+ if (atomIsThumb != targetIsThumb)
+ updateBranchToUseShim(atomIsThumb, *daTarget, ref);
+ }
+ }
+ }
+ // Exit early if no shims needed.
+ if (_targetToShim.empty())
+ return llvm::Error::success();
+
+ // Sort shim atoms so the layout order is stable.
+ std::vector<const DefinedAtom *> shims;
+ shims.reserve(_targetToShim.size());
+ for (auto element : _targetToShim) {
+ shims.push_back(element.second);
+ }
+ std::sort(shims.begin(), shims.end(),
+ [](const DefinedAtom *l, const DefinedAtom *r) {
+ return (l->name() < r->name());
+ });
+
+ // Add all shims to master file.
+ for (const DefinedAtom *shim : shims)
+ mergedFile.addAtom(*shim);
+
+ return llvm::Error::success();
+ }
+
+private:
+
+ void updateBranchToUseShim(bool thumbToArm, const DefinedAtom& target,
+ const Reference *ref) {
+ // Make file-format specific stub and other support atoms.
+ const DefinedAtom *shim = this->getShim(thumbToArm, target);
+ assert(shim != nullptr);
+ // Switch branch site to target shim atom.
+ const_cast<Reference *>(ref)->setTarget(shim);
+ }
+
+ const DefinedAtom* getShim(bool thumbToArm, const DefinedAtom& target) {
+ auto pos = _targetToShim.find(&target);
+ if ( pos != _targetToShim.end() ) {
+ // Reuse an existing shim.
+ assert(pos->second != nullptr);
+ return pos->second;
+ } else {
+ // There is no existing shim, so create a new one.
+ const DefinedAtom *shim = _archHandler.createShim(_file, thumbToArm,
+ target);
+ _targetToShim[&target] = shim;
+ return shim;
+ }
+ }
+
+ const MachOLinkingContext &_ctx;
+ mach_o::ArchHandler &_archHandler;
+ const ArchHandler::StubInfo &_stubInfo;
+ MachOFile &_file;
+ llvm::DenseMap<const Atom*, const DefinedAtom*> _targetToShim;
+};
+
+
+
+void addShimPass(PassManager &pm, const MachOLinkingContext &ctx) {
+ pm.add(llvm::make_unique<ShimPass>(ctx));
+}
+
+} // end namespace mach_o
+} // end namespace lld
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/StubsPass.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/StubsPass.cpp
new file mode 100644
index 000000000000..04c586df336c
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/StubsPass.cpp
@@ -0,0 +1,379 @@
+//===- lib/ReaderWriter/MachO/StubsPass.cpp ---------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This linker pass updates call-sites which have references to shared library
+// atoms to instead have a reference to a stub (PLT entry) for the specified
+// symbol. Each file format defines a subclass of StubsPass which implements
+// the abstract methods for creating the file format specific StubAtoms.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ArchHandler.h"
+#include "File.h"
+#include "MachOPasses.h"
+#include "lld/Common/LLVM.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/Simple.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+
+namespace lld {
+namespace mach_o {
+
+//
+// Lazy Pointer Atom created by the stubs pass.
+//
+class LazyPointerAtom : public SimpleDefinedAtom {
+public:
+ LazyPointerAtom(const File &file, bool is64)
+ : SimpleDefinedAtom(file), _is64(is64) { }
+
+ ~LazyPointerAtom() override = default;
+
+ ContentType contentType() const override {
+ return DefinedAtom::typeLazyPointer;
+ }
+
+ Alignment alignment() const override {
+ return _is64 ? 8 : 4;
+ }
+
+ uint64_t size() const override {
+ return _is64 ? 8 : 4;
+ }
+
+ ContentPermissions permissions() const override {
+ return DefinedAtom::permRW_;
+ }
+
+ ArrayRef<uint8_t> rawContent() const override {
+ static const uint8_t zeros[] =
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ return llvm::makeArrayRef(zeros, size());
+ }
+
+private:
+ const bool _is64;
+};
+
+//
+// NonLazyPointer (GOT) Atom created by the stubs pass.
+//
+class NonLazyPointerAtom : public SimpleDefinedAtom {
+public:
+ NonLazyPointerAtom(const File &file, bool is64, ContentType contentType)
+ : SimpleDefinedAtom(file), _is64(is64), _contentType(contentType) { }
+
+ ~NonLazyPointerAtom() override = default;
+
+ ContentType contentType() const override {
+ return _contentType;
+ }
+
+ Alignment alignment() const override {
+ return _is64 ? 8 : 4;
+ }
+
+ uint64_t size() const override {
+ return _is64 ? 8 : 4;
+ }
+
+ ContentPermissions permissions() const override {
+ return DefinedAtom::permRW_;
+ }
+
+ ArrayRef<uint8_t> rawContent() const override {
+ static const uint8_t zeros[] =
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ return llvm::makeArrayRef(zeros, size());
+ }
+
+private:
+ const bool _is64;
+ const ContentType _contentType;
+};
+
+//
+// Stub Atom created by the stubs pass.
+//
+class StubAtom : public SimpleDefinedAtom {
+public:
+ StubAtom(const File &file, const ArchHandler::StubInfo &stubInfo)
+ : SimpleDefinedAtom(file), _stubInfo(stubInfo){ }
+
+ ~StubAtom() override = default;
+
+ ContentType contentType() const override {
+ return DefinedAtom::typeStub;
+ }
+
+ Alignment alignment() const override {
+ return 1 << _stubInfo.codeAlignment;
+ }
+
+ uint64_t size() const override {
+ return _stubInfo.stubSize;
+ }
+
+ ContentPermissions permissions() const override {
+ return DefinedAtom::permR_X;
+ }
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return llvm::makeArrayRef(_stubInfo.stubBytes, _stubInfo.stubSize);
+ }
+
+private:
+ const ArchHandler::StubInfo &_stubInfo;
+};
+
+//
+// Stub Helper Atom created by the stubs pass.
+//
+class StubHelperAtom : public SimpleDefinedAtom {
+public:
+ StubHelperAtom(const File &file, const ArchHandler::StubInfo &stubInfo)
+ : SimpleDefinedAtom(file), _stubInfo(stubInfo) { }
+
+ ~StubHelperAtom() override = default;
+
+ ContentType contentType() const override {
+ return DefinedAtom::typeStubHelper;
+ }
+
+ Alignment alignment() const override {
+ return 1 << _stubInfo.codeAlignment;
+ }
+
+ uint64_t size() const override {
+ return _stubInfo.stubHelperSize;
+ }
+
+ ContentPermissions permissions() const override {
+ return DefinedAtom::permR_X;
+ }
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return llvm::makeArrayRef(_stubInfo.stubHelperBytes,
+ _stubInfo.stubHelperSize);
+ }
+
+private:
+ const ArchHandler::StubInfo &_stubInfo;
+};
+
+//
+// Stub Helper Common Atom created by the stubs pass.
+//
+class StubHelperCommonAtom : public SimpleDefinedAtom {
+public:
+ StubHelperCommonAtom(const File &file, const ArchHandler::StubInfo &stubInfo)
+ : SimpleDefinedAtom(file), _stubInfo(stubInfo) { }
+
+ ~StubHelperCommonAtom() override = default;
+
+ ContentType contentType() const override {
+ return DefinedAtom::typeStubHelper;
+ }
+
+ Alignment alignment() const override {
+ return 1 << _stubInfo.stubHelperCommonAlignment;
+ }
+
+ uint64_t size() const override {
+ return _stubInfo.stubHelperCommonSize;
+ }
+
+ ContentPermissions permissions() const override {
+ return DefinedAtom::permR_X;
+ }
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return llvm::makeArrayRef(_stubInfo.stubHelperCommonBytes,
+ _stubInfo.stubHelperCommonSize);
+ }
+
+private:
+ const ArchHandler::StubInfo &_stubInfo;
+};
+
+class StubsPass : public Pass {
+public:
+ StubsPass(const MachOLinkingContext &context)
+ : _ctx(context), _archHandler(_ctx.archHandler()),
+ _stubInfo(_archHandler.stubInfo()),
+ _file(*_ctx.make_file<MachOFile>("<mach-o Stubs pass>")) {
+ _file.setOrdinal(_ctx.getNextOrdinalAndIncrement());
+ }
+
+ llvm::Error perform(SimpleFile &mergedFile) override {
+ // Skip this pass if output format uses text relocations instead of stubs.
+ if (!this->noTextRelocs())
+ return llvm::Error::success();
+
+ // Scan all references in all atoms.
+ for (const DefinedAtom *atom : mergedFile.defined()) {
+ for (const Reference *ref : *atom) {
+ // Look at call-sites.
+ if (!this->isCallSite(*ref))
+ continue;
+ const Atom *target = ref->target();
+ assert(target != nullptr);
+ if (isa<SharedLibraryAtom>(target)) {
+ // Calls to shared libraries go through stubs.
+ _targetToUses[target].push_back(ref);
+ continue;
+ }
+ const DefinedAtom *defTarget = dyn_cast<DefinedAtom>(target);
+ if (defTarget && defTarget->interposable() != DefinedAtom::interposeNo){
+ // Calls to interposable functions in same linkage unit must also go
+ // through a stub.
+ assert(defTarget->scope() != DefinedAtom::scopeTranslationUnit);
+ _targetToUses[target].push_back(ref);
+ }
+ }
+ }
+
+ // Exit early if no stubs needed.
+ if (_targetToUses.empty())
+ return llvm::Error::success();
+
+ // First add help-common and GOT slots used by lazy binding.
+ SimpleDefinedAtom *helperCommonAtom =
+ new (_file.allocator()) StubHelperCommonAtom(_file, _stubInfo);
+ SimpleDefinedAtom *helperCacheNLPAtom =
+ new (_file.allocator()) NonLazyPointerAtom(_file, _ctx.is64Bit(),
+ _stubInfo.stubHelperImageCacheContentType);
+ SimpleDefinedAtom *helperBinderNLPAtom =
+ new (_file.allocator()) NonLazyPointerAtom(_file, _ctx.is64Bit(),
+ _stubInfo.stubHelperImageCacheContentType);
+ addReference(helperCommonAtom, _stubInfo.stubHelperCommonReferenceToCache,
+ helperCacheNLPAtom);
+ addOptReference(
+ helperCommonAtom, _stubInfo.stubHelperCommonReferenceToCache,
+ _stubInfo.optStubHelperCommonReferenceToCache, helperCacheNLPAtom);
+ addReference(helperCommonAtom, _stubInfo.stubHelperCommonReferenceToBinder,
+ helperBinderNLPAtom);
+ addOptReference(
+ helperCommonAtom, _stubInfo.stubHelperCommonReferenceToBinder,
+ _stubInfo.optStubHelperCommonReferenceToBinder, helperBinderNLPAtom);
+ mergedFile.addAtom(*helperCommonAtom);
+ mergedFile.addAtom(*helperBinderNLPAtom);
+ mergedFile.addAtom(*helperCacheNLPAtom);
+
+ // Add reference to dyld_stub_binder in libSystem.dylib
+ auto I = std::find_if(
+ mergedFile.sharedLibrary().begin(), mergedFile.sharedLibrary().end(),
+ [&](const SharedLibraryAtom *atom) {
+ return atom->name().equals(_stubInfo.binderSymbolName);
+ });
+ assert(I != mergedFile.sharedLibrary().end() &&
+ "dyld_stub_binder not found");
+ addReference(helperBinderNLPAtom, _stubInfo.nonLazyPointerReferenceToBinder, *I);
+
+ // Sort targets by name, so stubs and lazy pointers are consistent
+ std::vector<const Atom *> targetsNeedingStubs;
+ for (auto it : _targetToUses)
+ targetsNeedingStubs.push_back(it.first);
+ std::sort(targetsNeedingStubs.begin(), targetsNeedingStubs.end(),
+ [](const Atom * left, const Atom * right) {
+ return (left->name().compare(right->name()) < 0);
+ });
+
+ // Make and append stubs, lazy pointers, and helpers in alphabetical order.
+ unsigned lazyOffset = 0;
+ for (const Atom *target : targetsNeedingStubs) {
+ auto *stub = new (_file.allocator()) StubAtom(_file, _stubInfo);
+ auto *lp =
+ new (_file.allocator()) LazyPointerAtom(_file, _ctx.is64Bit());
+ auto *helper = new (_file.allocator()) StubHelperAtom(_file, _stubInfo);
+
+ addReference(stub, _stubInfo.stubReferenceToLP, lp);
+ addOptReference(stub, _stubInfo.stubReferenceToLP,
+ _stubInfo.optStubReferenceToLP, lp);
+ addReference(lp, _stubInfo.lazyPointerReferenceToHelper, helper);
+ addReference(lp, _stubInfo.lazyPointerReferenceToFinal, target);
+ addReference(helper, _stubInfo.stubHelperReferenceToImm, helper);
+ addReferenceAddend(helper, _stubInfo.stubHelperReferenceToImm, helper,
+ lazyOffset);
+ addReference(helper, _stubInfo.stubHelperReferenceToHelperCommon,
+ helperCommonAtom);
+
+ mergedFile.addAtom(*stub);
+ mergedFile.addAtom(*lp);
+ mergedFile.addAtom(*helper);
+
+ // Update each reference to use stub.
+ for (const Reference *ref : _targetToUses[target]) {
+ assert(ref->target() == target);
+ // Switch call site to reference stub atom instead.
+ const_cast<Reference *>(ref)->setTarget(stub);
+ }
+
+ // Calculate new offset
+ lazyOffset += target->name().size() + 12;
+ }
+
+ return llvm::Error::success();
+ }
+
+private:
+ bool noTextRelocs() {
+ return true;
+ }
+
+ bool isCallSite(const Reference &ref) {
+ return _archHandler.isCallSite(ref);
+ }
+
+ void addReference(SimpleDefinedAtom* atom,
+ const ArchHandler::ReferenceInfo &refInfo,
+ const lld::Atom* target) {
+ atom->addReference(Reference::KindNamespace::mach_o,
+ refInfo.arch, refInfo.kind, refInfo.offset,
+ target, refInfo.addend);
+ }
+
+ void addReferenceAddend(SimpleDefinedAtom *atom,
+ const ArchHandler::ReferenceInfo &refInfo,
+ const lld::Atom *target, uint64_t addend) {
+ atom->addReference(Reference::KindNamespace::mach_o, refInfo.arch,
+ refInfo.kind, refInfo.offset, target, addend);
+ }
+
+ void addOptReference(SimpleDefinedAtom* atom,
+ const ArchHandler::ReferenceInfo &refInfo,
+ const ArchHandler::OptionalRefInfo &optRef,
+ const lld::Atom* target) {
+ if (!optRef.used)
+ return;
+ atom->addReference(Reference::KindNamespace::mach_o,
+ refInfo.arch, optRef.kind, optRef.offset,
+ target, optRef.addend);
+ }
+
+ typedef llvm::DenseMap<const Atom*,
+ llvm::SmallVector<const Reference *, 8>> TargetToUses;
+
+ const MachOLinkingContext &_ctx;
+ mach_o::ArchHandler &_archHandler;
+ const ArchHandler::StubInfo &_stubInfo;
+ MachOFile &_file;
+ TargetToUses _targetToUses;
+};
+
+void addStubsPass(PassManager &pm, const MachOLinkingContext &ctx) {
+ pm.add(std::unique_ptr<Pass>(new StubsPass(ctx)));
+}
+
+} // end namespace mach_o
+} // end namespace lld
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/TLVPass.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/TLVPass.cpp
new file mode 100644
index 000000000000..e362e507ebf2
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/TLVPass.cpp
@@ -0,0 +1,141 @@
+//===- lib/ReaderWriter/MachO/TLVPass.cpp -----------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This linker pass transforms all TLV references to real references.
+///
+//===----------------------------------------------------------------------===//
+
+#include "ArchHandler.h"
+#include "File.h"
+#include "MachOPasses.h"
+#include "lld/Core/Simple.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Debug.h"
+
+namespace lld {
+namespace mach_o {
+
+//
+// TLVP Entry Atom created by the TLV pass.
+//
+class TLVPEntryAtom : public SimpleDefinedAtom {
+public:
+ TLVPEntryAtom(const File &file, bool is64, StringRef name)
+ : SimpleDefinedAtom(file), _is64(is64), _name(name) {}
+
+ ~TLVPEntryAtom() override = default;
+
+ ContentType contentType() const override {
+ return DefinedAtom::typeTLVInitializerPtr;
+ }
+
+ Alignment alignment() const override {
+ return _is64 ? 8 : 4;
+ }
+
+ uint64_t size() const override {
+ return _is64 ? 8 : 4;
+ }
+
+ ContentPermissions permissions() const override {
+ return DefinedAtom::permRW_;
+ }
+
+ ArrayRef<uint8_t> rawContent() const override {
+ static const uint8_t zeros[] =
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ return llvm::makeArrayRef(zeros, size());
+ }
+
+ StringRef slotName() const {
+ return _name;
+ }
+
+private:
+ const bool _is64;
+ StringRef _name;
+};
+
+class TLVPass : public Pass {
+public:
+ TLVPass(const MachOLinkingContext &context)
+ : _ctx(context), _archHandler(_ctx.archHandler()),
+ _file(*_ctx.make_file<MachOFile>("<mach-o TLV pass>")) {
+ _file.setOrdinal(_ctx.getNextOrdinalAndIncrement());
+ }
+
+private:
+ llvm::Error perform(SimpleFile &mergedFile) override {
+ bool allowTLV = _ctx.minOS("10.7", "1.0");
+
+ for (const DefinedAtom *atom : mergedFile.defined()) {
+ for (const Reference *ref : *atom) {
+ if (!_archHandler.isTLVAccess(*ref))
+ continue;
+
+ if (!allowTLV)
+ return llvm::make_error<GenericError>(
+ "targeted OS version does not support use of thread local "
+ "variables in " + atom->name() + " for architecture " +
+ _ctx.archName());
+
+ const Atom *target = ref->target();
+ assert(target != nullptr);
+
+ const DefinedAtom *tlvpEntry = makeTLVPEntry(target);
+ const_cast<Reference*>(ref)->setTarget(tlvpEntry);
+ _archHandler.updateReferenceToTLV(ref);
+ }
+ }
+
+ std::vector<const TLVPEntryAtom*> entries;
+ entries.reserve(_targetToTLVP.size());
+ for (auto &it : _targetToTLVP)
+ entries.push_back(it.second);
+ std::sort(entries.begin(), entries.end(),
+ [](const TLVPEntryAtom *lhs, const TLVPEntryAtom *rhs) {
+ return (lhs->slotName().compare(rhs->slotName()) < 0);
+ });
+
+ for (const TLVPEntryAtom *slot : entries)
+ mergedFile.addAtom(*slot);
+
+ return llvm::Error::success();
+ }
+
+ const DefinedAtom *makeTLVPEntry(const Atom *target) {
+ auto pos = _targetToTLVP.find(target);
+
+ if (pos != _targetToTLVP.end())
+ return pos->second;
+
+ auto *tlvpEntry = new (_file.allocator())
+ TLVPEntryAtom(_file, _ctx.is64Bit(), target->name());
+ _targetToTLVP[target] = tlvpEntry;
+ const ArchHandler::ReferenceInfo &nlInfo =
+ _archHandler.stubInfo().nonLazyPointerReferenceToBinder;
+ tlvpEntry->addReference(Reference::KindNamespace::mach_o, nlInfo.arch,
+ nlInfo.kind, 0, target, 0);
+ return tlvpEntry;
+ }
+
+ const MachOLinkingContext &_ctx;
+ mach_o::ArchHandler &_archHandler;
+ MachOFile &_file;
+ llvm::DenseMap<const Atom*, const TLVPEntryAtom*> _targetToTLVP;
+};
+
+void addTLVPass(PassManager &pm, const MachOLinkingContext &ctx) {
+ assert(ctx.needsTLVPass());
+ pm.add(llvm::make_unique<TLVPass>(ctx));
+}
+
+} // end namesapce mach_o
+} // end namesapce lld
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/WriterMachO.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/WriterMachO.cpp
new file mode 100644
index 000000000000..c457e7b55a43
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/WriterMachO.cpp
@@ -0,0 +1,71 @@
+//===- lib/ReaderWriter/MachO/WriterMachO.cpp -----------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExecutableAtoms.h"
+#include "MachONormalizedFile.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Writer.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <system_error>
+
+using lld::mach_o::normalized::NormalizedFile;
+
+namespace lld {
+namespace mach_o {
+
+class MachOWriter : public Writer {
+public:
+ MachOWriter(const MachOLinkingContext &ctxt) : _ctx(ctxt) {}
+
+ llvm::Error writeFile(const lld::File &file, StringRef path) override {
+ // Construct empty normalized file from atoms.
+ llvm::Expected<std::unique_ptr<NormalizedFile>> nFile =
+ normalized::normalizedFromAtoms(file, _ctx);
+ if (auto ec = nFile.takeError())
+ return ec;
+
+ // For testing, write out yaml form of normalized file.
+ if (_ctx.printAtoms()) {
+ std::unique_ptr<Writer> yamlWriter = createWriterYAML(_ctx);
+ if (auto ec = yamlWriter->writeFile(file, "-"))
+ return ec;
+ }
+
+ // Write normalized file as mach-o binary.
+ return writeBinary(*nFile->get(), path);
+ }
+
+ void createImplicitFiles(std::vector<std::unique_ptr<File>> &r) override {
+ // When building main executables, add _main as required entry point.
+ if (_ctx.outputTypeHasEntry())
+ r.emplace_back(new CEntryFile(_ctx));
+ // If this can link with dylibs, need helper function (dyld_stub_binder).
+ if (_ctx.needsStubsPass())
+ r.emplace_back(new StubHelperFile(_ctx));
+ // Final linked images can access a symbol for their mach_header.
+ if (_ctx.outputMachOType() != llvm::MachO::MH_OBJECT)
+ r.emplace_back(new MachHeaderAliasFile(_ctx));
+ }
+private:
+ const MachOLinkingContext &_ctx;
+ };
+
+
+} // namespace mach_o
+
+std::unique_ptr<Writer> createWriterMachO(const MachOLinkingContext &context) {
+ return std::unique_ptr<Writer>(new lld::mach_o::MachOWriter(context));
+}
+
+} // namespace lld
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/YAML/CMakeLists.txt b/contrib/llvm/tools/lld/lib/ReaderWriter/YAML/CMakeLists.txt
new file mode 100644
index 000000000000..0e63574a63d2
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/YAML/CMakeLists.txt
@@ -0,0 +1,9 @@
+add_lld_library(lldYAML
+ ReaderWriterYAML.cpp
+
+ LINK_COMPONENTS
+ Support
+
+ LINK_LIBS
+ lldCore
+ )
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp
new file mode 100644
index 000000000000..59548684e677
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp
@@ -0,0 +1,1404 @@
+//===- lib/ReaderWriter/YAML/ReaderWriterYAML.cpp -------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/AbsoluteAtom.h"
+#include "lld/Core/ArchiveLibraryFile.h"
+#include "lld/Core/Atom.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/Error.h"
+#include "lld/Core/File.h"
+#include "lld/Core/LinkingContext.h"
+#include "lld/Core/Reader.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/SharedLibraryAtom.h"
+#include "lld/Core/Simple.h"
+#include "lld/Core/UndefinedAtom.h"
+#include "lld/Core/Writer.h"
+#include "lld/ReaderWriter/YamlContext.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/YAMLTraits.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <cstdint>
+#include <cstring>
+#include <memory>
+#include <string>
+#include <system_error>
+#include <vector>
+
+using llvm::file_magic;
+using llvm::yaml::MappingTraits;
+using llvm::yaml::ScalarEnumerationTraits;
+using llvm::yaml::ScalarTraits;
+using llvm::yaml::IO;
+using llvm::yaml::SequenceTraits;
+using llvm::yaml::DocumentListTraits;
+
+using namespace lld;
+
+/// The conversion of Atoms to and from YAML uses LLVM's YAML I/O. This
+/// file just defines template specializations on the lld types which control
+/// how the mapping is done to and from YAML.
+
+namespace {
+
+/// Used when writing yaml files.
+/// In most cases, atoms names are unambiguous, so references can just
+/// use the atom name as the target (e.g. target: foo). But in a few
+/// cases that does not work, so ref-names are added. These are labels
+/// used only in yaml. The labels do not exist in the Atom model.
+///
+/// One need for ref-names are when atoms have no user supplied name
+/// (e.g. c-string literal). Another case is when two object files with
+/// identically named static functions are merged (ld -r) into one object file.
+/// In that case referencing the function by name is ambiguous, so a unique
+/// ref-name is added.
+class RefNameBuilder {
+public:
+ RefNameBuilder(const lld::File &file)
+ : _collisionCount(0), _unnamedCounter(0) {
+ // visit all atoms
+ for (const lld::DefinedAtom *atom : file.defined()) {
+ // Build map of atoms names to detect duplicates
+ if (!atom->name().empty())
+ buildDuplicateNameMap(*atom);
+
+ // Find references to unnamed atoms and create ref-names for them.
+ for (const lld::Reference *ref : *atom) {
+ // create refname for any unnamed reference target
+ const lld::Atom *target = ref->target();
+ if ((target != nullptr) && target->name().empty()) {
+ std::string storage;
+ llvm::raw_string_ostream buffer(storage);
+ buffer << llvm::format("L%03d", _unnamedCounter++);
+ StringRef newName = copyString(buffer.str());
+ _refNames[target] = newName;
+ DEBUG_WITH_TYPE("WriterYAML",
+ llvm::dbgs() << "unnamed atom: creating ref-name: '"
+ << newName << "' ("
+ << (const void *)newName.data() << ", "
+ << newName.size() << ")\n");
+ }
+ }
+ }
+ for (const lld::UndefinedAtom *undefAtom : file.undefined()) {
+ buildDuplicateNameMap(*undefAtom);
+ }
+ for (const lld::SharedLibraryAtom *shlibAtom : file.sharedLibrary()) {
+ buildDuplicateNameMap(*shlibAtom);
+ }
+ for (const lld::AbsoluteAtom *absAtom : file.absolute()) {
+ if (!absAtom->name().empty())
+ buildDuplicateNameMap(*absAtom);
+ }
+ }
+
+ void buildDuplicateNameMap(const lld::Atom &atom) {
+ assert(!atom.name().empty());
+ NameToAtom::iterator pos = _nameMap.find(atom.name());
+ if (pos != _nameMap.end()) {
+ // Found name collision, give each a unique ref-name.
+ std::string Storage;
+ llvm::raw_string_ostream buffer(Storage);
+ buffer << atom.name() << llvm::format(".%03d", ++_collisionCount);
+ StringRef newName = copyString(buffer.str());
+ _refNames[&atom] = newName;
+ DEBUG_WITH_TYPE("WriterYAML",
+ llvm::dbgs() << "name collsion: creating ref-name: '"
+ << newName << "' ("
+ << (const void *)newName.data()
+ << ", " << newName.size() << ")\n");
+ const lld::Atom *prevAtom = pos->second;
+ AtomToRefName::iterator pos2 = _refNames.find(prevAtom);
+ if (pos2 == _refNames.end()) {
+ // Only create ref-name for previous if none already created.
+ std::string Storage2;
+ llvm::raw_string_ostream buffer2(Storage2);
+ buffer2 << prevAtom->name() << llvm::format(".%03d", ++_collisionCount);
+ StringRef newName2 = copyString(buffer2.str());
+ _refNames[prevAtom] = newName2;
+ DEBUG_WITH_TYPE("WriterYAML",
+ llvm::dbgs() << "name collsion: creating ref-name: '"
+ << newName2 << "' ("
+ << (const void *)newName2.data() << ", "
+ << newName2.size() << ")\n");
+ }
+ } else {
+ // First time we've seen this name, just add it to map.
+ _nameMap[atom.name()] = &atom;
+ DEBUG_WITH_TYPE("WriterYAML", llvm::dbgs()
+ << "atom name seen for first time: '"
+ << atom.name() << "' ("
+ << (const void *)atom.name().data()
+ << ", " << atom.name().size() << ")\n");
+ }
+ }
+
+ bool hasRefName(const lld::Atom *atom) { return _refNames.count(atom); }
+
+ StringRef refName(const lld::Atom *atom) {
+ return _refNames.find(atom)->second;
+ }
+
+private:
+ typedef llvm::StringMap<const lld::Atom *> NameToAtom;
+ typedef llvm::DenseMap<const lld::Atom *, std::string> AtomToRefName;
+
+ // Allocate a new copy of this string in _storage, so the strings
+ // can be freed when RefNameBuilder is destroyed.
+ StringRef copyString(StringRef str) {
+ char *s = _storage.Allocate<char>(str.size());
+ memcpy(s, str.data(), str.size());
+ return StringRef(s, str.size());
+ }
+
+ unsigned int _collisionCount;
+ unsigned int _unnamedCounter;
+ NameToAtom _nameMap;
+ AtomToRefName _refNames;
+ llvm::BumpPtrAllocator _storage;
+};
+
+/// Used when reading yaml files to find the target of a reference
+/// that could be a name or ref-name.
+class RefNameResolver {
+public:
+ RefNameResolver(const lld::File *file, IO &io);
+
+ const lld::Atom *lookup(StringRef name) const {
+ NameToAtom::const_iterator pos = _nameMap.find(name);
+ if (pos != _nameMap.end())
+ return pos->second;
+ _io.setError(Twine("no such atom name: ") + name);
+ return nullptr;
+ }
+
+private:
+ typedef llvm::StringMap<const lld::Atom *> NameToAtom;
+
+ void add(StringRef name, const lld::Atom *atom) {
+ if (_nameMap.count(name)) {
+ _io.setError(Twine("duplicate atom name: ") + name);
+ } else {
+ _nameMap[name] = atom;
+ }
+ }
+
+ IO &_io;
+ NameToAtom _nameMap;
+};
+
+/// Mapping of Atoms.
+template <typename T> class AtomList {
+ using Ty = std::vector<OwningAtomPtr<T>>;
+
+public:
+ typename Ty::iterator begin() { return _atoms.begin(); }
+ typename Ty::iterator end() { return _atoms.end(); }
+ Ty _atoms;
+};
+
+/// Mapping of kind: field in yaml files.
+enum FileKinds {
+ fileKindObjectAtoms, // atom based object file encoded in yaml
+ fileKindArchive, // static archive library encoded in yaml
+ fileKindObjectMachO // mach-o object files encoded in yaml
+};
+
+struct ArchMember {
+ FileKinds _kind;
+ StringRef _name;
+ const lld::File *_content;
+};
+
+// The content bytes in a DefinedAtom are just uint8_t but we want
+// special formatting, so define a strong type.
+LLVM_YAML_STRONG_TYPEDEF(uint8_t, ImplicitHex8)
+
+// SharedLibraryAtoms have a bool canBeNull() method which we'd like to be
+// more readable than just true/false.
+LLVM_YAML_STRONG_TYPEDEF(bool, ShlibCanBeNull)
+
+// lld::Reference::Kind is a tuple of <namespace, arch, value>.
+// For yaml, we just want one string that encapsulates the tuple.
+struct RefKind {
+ Reference::KindNamespace ns;
+ Reference::KindArch arch;
+ Reference::KindValue value;
+};
+
+} // end anonymous namespace
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(ArchMember)
+LLVM_YAML_IS_SEQUENCE_VECTOR(const lld::Reference *)
+// Always write DefinedAtoms content bytes as a flow sequence.
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(ImplicitHex8)
+
+// for compatibility with gcc-4.7 in C++11 mode, add extra namespace
+namespace llvm {
+namespace yaml {
+
+// This is a custom formatter for RefKind
+template <> struct ScalarTraits<RefKind> {
+ static void output(const RefKind &kind, void *ctxt, raw_ostream &out) {
+ assert(ctxt != nullptr);
+ YamlContext *info = reinterpret_cast<YamlContext *>(ctxt);
+ assert(info->_registry);
+ StringRef str;
+ if (info->_registry->referenceKindToString(kind.ns, kind.arch, kind.value,
+ str))
+ out << str;
+ else
+ out << (int)(kind.ns) << "-" << (int)(kind.arch) << "-" << kind.value;
+ }
+
+ static StringRef input(StringRef scalar, void *ctxt, RefKind &kind) {
+ assert(ctxt != nullptr);
+ YamlContext *info = reinterpret_cast<YamlContext *>(ctxt);
+ assert(info->_registry);
+ if (info->_registry->referenceKindFromString(scalar, kind.ns, kind.arch,
+ kind.value))
+ return StringRef();
+ return StringRef("unknown reference kind");
+ }
+
+ static QuotingType mustQuote(StringRef) { return QuotingType::None; }
+};
+
+template <> struct ScalarEnumerationTraits<lld::File::Kind> {
+ static void enumeration(IO &io, lld::File::Kind &value) {
+ io.enumCase(value, "error-object", lld::File::kindErrorObject);
+ io.enumCase(value, "object", lld::File::kindMachObject);
+ io.enumCase(value, "shared-library", lld::File::kindSharedLibrary);
+ io.enumCase(value, "static-library", lld::File::kindArchiveLibrary);
+ }
+};
+
+template <> struct ScalarEnumerationTraits<lld::Atom::Scope> {
+ static void enumeration(IO &io, lld::Atom::Scope &value) {
+ io.enumCase(value, "global", lld::Atom::scopeGlobal);
+ io.enumCase(value, "hidden", lld::Atom::scopeLinkageUnit);
+ io.enumCase(value, "static", lld::Atom::scopeTranslationUnit);
+ }
+};
+
+template <> struct ScalarEnumerationTraits<lld::DefinedAtom::SectionChoice> {
+ static void enumeration(IO &io, lld::DefinedAtom::SectionChoice &value) {
+ io.enumCase(value, "content", lld::DefinedAtom::sectionBasedOnContent);
+ io.enumCase(value, "custom", lld::DefinedAtom::sectionCustomPreferred);
+ io.enumCase(value, "custom-required",
+ lld::DefinedAtom::sectionCustomRequired);
+ }
+};
+
+template <> struct ScalarEnumerationTraits<lld::DefinedAtom::Interposable> {
+ static void enumeration(IO &io, lld::DefinedAtom::Interposable &value) {
+ io.enumCase(value, "no", DefinedAtom::interposeNo);
+ io.enumCase(value, "yes", DefinedAtom::interposeYes);
+ io.enumCase(value, "yes-and-weak", DefinedAtom::interposeYesAndRuntimeWeak);
+ }
+};
+
+template <> struct ScalarEnumerationTraits<lld::DefinedAtom::Merge> {
+ static void enumeration(IO &io, lld::DefinedAtom::Merge &value) {
+ io.enumCase(value, "no", lld::DefinedAtom::mergeNo);
+ io.enumCase(value, "as-tentative", lld::DefinedAtom::mergeAsTentative);
+ io.enumCase(value, "as-weak", lld::DefinedAtom::mergeAsWeak);
+ io.enumCase(value, "as-addressed-weak",
+ lld::DefinedAtom::mergeAsWeakAndAddressUsed);
+ io.enumCase(value, "by-content", lld::DefinedAtom::mergeByContent);
+ io.enumCase(value, "same-name-and-size",
+ lld::DefinedAtom::mergeSameNameAndSize);
+ io.enumCase(value, "largest", lld::DefinedAtom::mergeByLargestSection);
+ }
+};
+
+template <> struct ScalarEnumerationTraits<lld::DefinedAtom::DeadStripKind> {
+ static void enumeration(IO &io, lld::DefinedAtom::DeadStripKind &value) {
+ io.enumCase(value, "normal", lld::DefinedAtom::deadStripNormal);
+ io.enumCase(value, "never", lld::DefinedAtom::deadStripNever);
+ io.enumCase(value, "always", lld::DefinedAtom::deadStripAlways);
+ }
+};
+
+template <> struct ScalarEnumerationTraits<lld::DefinedAtom::DynamicExport> {
+ static void enumeration(IO &io, lld::DefinedAtom::DynamicExport &value) {
+ io.enumCase(value, "normal", lld::DefinedAtom::dynamicExportNormal);
+ io.enumCase(value, "always", lld::DefinedAtom::dynamicExportAlways);
+ }
+};
+
+template <> struct ScalarEnumerationTraits<lld::DefinedAtom::CodeModel> {
+ static void enumeration(IO &io, lld::DefinedAtom::CodeModel &value) {
+ io.enumCase(value, "none", lld::DefinedAtom::codeNA);
+ io.enumCase(value, "mips-pic", lld::DefinedAtom::codeMipsPIC);
+ io.enumCase(value, "mips-micro", lld::DefinedAtom::codeMipsMicro);
+ io.enumCase(value, "mips-micro-pic", lld::DefinedAtom::codeMipsMicroPIC);
+ io.enumCase(value, "mips-16", lld::DefinedAtom::codeMips16);
+ io.enumCase(value, "arm-thumb", lld::DefinedAtom::codeARMThumb);
+ io.enumCase(value, "arm-a", lld::DefinedAtom::codeARM_a);
+ io.enumCase(value, "arm-d", lld::DefinedAtom::codeARM_d);
+ io.enumCase(value, "arm-t", lld::DefinedAtom::codeARM_t);
+ }
+};
+
+template <>
+struct ScalarEnumerationTraits<lld::DefinedAtom::ContentPermissions> {
+ static void enumeration(IO &io, lld::DefinedAtom::ContentPermissions &value) {
+ io.enumCase(value, "---", lld::DefinedAtom::perm___);
+ io.enumCase(value, "r--", lld::DefinedAtom::permR__);
+ io.enumCase(value, "r-x", lld::DefinedAtom::permR_X);
+ io.enumCase(value, "rw-", lld::DefinedAtom::permRW_);
+ io.enumCase(value, "rwx", lld::DefinedAtom::permRWX);
+ io.enumCase(value, "rw-l", lld::DefinedAtom::permRW_L);
+ io.enumCase(value, "unknown", lld::DefinedAtom::permUnknown);
+ }
+};
+
+template <> struct ScalarEnumerationTraits<lld::DefinedAtom::ContentType> {
+ static void enumeration(IO &io, lld::DefinedAtom::ContentType &value) {
+ io.enumCase(value, "unknown", DefinedAtom::typeUnknown);
+ io.enumCase(value, "code", DefinedAtom::typeCode);
+ io.enumCase(value, "stub", DefinedAtom::typeStub);
+ io.enumCase(value, "constant", DefinedAtom::typeConstant);
+ io.enumCase(value, "data", DefinedAtom::typeData);
+ io.enumCase(value, "quick-data", DefinedAtom::typeDataFast);
+ io.enumCase(value, "zero-fill", DefinedAtom::typeZeroFill);
+ io.enumCase(value, "zero-fill-quick", DefinedAtom::typeZeroFillFast);
+ io.enumCase(value, "const-data", DefinedAtom::typeConstData);
+ io.enumCase(value, "got", DefinedAtom::typeGOT);
+ io.enumCase(value, "resolver", DefinedAtom::typeResolver);
+ io.enumCase(value, "branch-island", DefinedAtom::typeBranchIsland);
+ io.enumCase(value, "branch-shim", DefinedAtom::typeBranchShim);
+ io.enumCase(value, "stub-helper", DefinedAtom::typeStubHelper);
+ io.enumCase(value, "c-string", DefinedAtom::typeCString);
+ io.enumCase(value, "utf16-string", DefinedAtom::typeUTF16String);
+ io.enumCase(value, "unwind-cfi", DefinedAtom::typeCFI);
+ io.enumCase(value, "unwind-lsda", DefinedAtom::typeLSDA);
+ io.enumCase(value, "const-4-byte", DefinedAtom::typeLiteral4);
+ io.enumCase(value, "const-8-byte", DefinedAtom::typeLiteral8);
+ io.enumCase(value, "const-16-byte", DefinedAtom::typeLiteral16);
+ io.enumCase(value, "lazy-pointer", DefinedAtom::typeLazyPointer);
+ io.enumCase(value, "lazy-dylib-pointer",
+ DefinedAtom::typeLazyDylibPointer);
+ io.enumCase(value, "cfstring", DefinedAtom::typeCFString);
+ io.enumCase(value, "initializer-pointer",
+ DefinedAtom::typeInitializerPtr);
+ io.enumCase(value, "terminator-pointer",
+ DefinedAtom::typeTerminatorPtr);
+ io.enumCase(value, "c-string-pointer",DefinedAtom::typeCStringPtr);
+ io.enumCase(value, "objc-class-pointer",
+ DefinedAtom::typeObjCClassPtr);
+ io.enumCase(value, "objc-category-list",
+ DefinedAtom::typeObjC2CategoryList);
+ io.enumCase(value, "objc-image-info",
+ DefinedAtom::typeObjCImageInfo);
+ io.enumCase(value, "objc-method-list",
+ DefinedAtom::typeObjCMethodList);
+ io.enumCase(value, "objc-class1", DefinedAtom::typeObjC1Class);
+ io.enumCase(value, "dtraceDOF", DefinedAtom::typeDTraceDOF);
+ io.enumCase(value, "interposing-tuples",
+ DefinedAtom::typeInterposingTuples);
+ io.enumCase(value, "lto-temp", DefinedAtom::typeTempLTO);
+ io.enumCase(value, "compact-unwind", DefinedAtom::typeCompactUnwindInfo);
+ io.enumCase(value, "unwind-info", DefinedAtom::typeProcessedUnwindInfo);
+ io.enumCase(value, "tlv-thunk", DefinedAtom::typeThunkTLV);
+ io.enumCase(value, "tlv-data", DefinedAtom::typeTLVInitialData);
+ io.enumCase(value, "tlv-zero-fill", DefinedAtom::typeTLVInitialZeroFill);
+ io.enumCase(value, "tlv-initializer-ptr",
+ DefinedAtom::typeTLVInitializerPtr);
+ io.enumCase(value, "mach_header", DefinedAtom::typeMachHeader);
+ io.enumCase(value, "dso_handle", DefinedAtom::typeDSOHandle);
+ io.enumCase(value, "sectcreate", DefinedAtom::typeSectCreate);
+ }
+};
+
+template <> struct ScalarEnumerationTraits<lld::UndefinedAtom::CanBeNull> {
+ static void enumeration(IO &io, lld::UndefinedAtom::CanBeNull &value) {
+ io.enumCase(value, "never", lld::UndefinedAtom::canBeNullNever);
+ io.enumCase(value, "at-runtime", lld::UndefinedAtom::canBeNullAtRuntime);
+ io.enumCase(value, "at-buildtime",lld::UndefinedAtom::canBeNullAtBuildtime);
+ }
+};
+
+template <> struct ScalarEnumerationTraits<ShlibCanBeNull> {
+ static void enumeration(IO &io, ShlibCanBeNull &value) {
+ io.enumCase(value, "never", false);
+ io.enumCase(value, "at-runtime", true);
+ }
+};
+
+template <>
+struct ScalarEnumerationTraits<lld::SharedLibraryAtom::Type> {
+ static void enumeration(IO &io, lld::SharedLibraryAtom::Type &value) {
+ io.enumCase(value, "code", lld::SharedLibraryAtom::Type::Code);
+ io.enumCase(value, "data", lld::SharedLibraryAtom::Type::Data);
+ io.enumCase(value, "unknown", lld::SharedLibraryAtom::Type::Unknown);
+ }
+};
+
+/// This is a custom formatter for lld::DefinedAtom::Alignment. Values look
+/// like:
+/// 8 # 8-byte aligned
+/// 7 mod 16 # 16-byte aligned plus 7 bytes
+template <> struct ScalarTraits<lld::DefinedAtom::Alignment> {
+ static void output(const lld::DefinedAtom::Alignment &value, void *ctxt,
+ raw_ostream &out) {
+ if (value.modulus == 0) {
+ out << llvm::format("%d", value.value);
+ } else {
+ out << llvm::format("%d mod %d", value.modulus, value.value);
+ }
+ }
+
+ static StringRef input(StringRef scalar, void *ctxt,
+ lld::DefinedAtom::Alignment &value) {
+ value.modulus = 0;
+ size_t modStart = scalar.find("mod");
+ if (modStart != StringRef::npos) {
+ StringRef modStr = scalar.slice(0, modStart);
+ modStr = modStr.rtrim();
+ unsigned int modulus;
+ if (modStr.getAsInteger(0, modulus)) {
+ return "malformed alignment modulus";
+ }
+ value.modulus = modulus;
+ scalar = scalar.drop_front(modStart + 3);
+ scalar = scalar.ltrim();
+ }
+ unsigned int power;
+ if (scalar.getAsInteger(0, power)) {
+ return "malformed alignment power";
+ }
+ value.value = power;
+ if (value.modulus >= power) {
+ return "malformed alignment, modulus too large for power";
+ }
+ return StringRef(); // returning empty string means success
+ }
+
+ static QuotingType mustQuote(StringRef) { return QuotingType::None; }
+};
+
+template <> struct ScalarEnumerationTraits<FileKinds> {
+ static void enumeration(IO &io, FileKinds &value) {
+ io.enumCase(value, "object", fileKindObjectAtoms);
+ io.enumCase(value, "archive", fileKindArchive);
+ io.enumCase(value, "object-mach-o", fileKindObjectMachO);
+ }
+};
+
+template <> struct MappingTraits<ArchMember> {
+ static void mapping(IO &io, ArchMember &member) {
+ io.mapOptional("kind", member._kind, fileKindObjectAtoms);
+ io.mapOptional("name", member._name);
+ io.mapRequired("content", member._content);
+ }
+};
+
+// Declare that an AtomList is a yaml sequence.
+template <typename T> struct SequenceTraits<AtomList<T> > {
+ static size_t size(IO &io, AtomList<T> &seq) { return seq._atoms.size(); }
+ static T *&element(IO &io, AtomList<T> &seq, size_t index) {
+ if (index >= seq._atoms.size())
+ seq._atoms.resize(index + 1);
+ return seq._atoms[index].get();
+ }
+};
+
+// Declare that an AtomRange is a yaml sequence.
+template <typename T> struct SequenceTraits<File::AtomRange<T> > {
+ static size_t size(IO &io, File::AtomRange<T> &seq) { return seq.size(); }
+ static T *&element(IO &io, File::AtomRange<T> &seq, size_t index) {
+ assert(io.outputting() && "AtomRange only used when outputting");
+ assert(index < seq.size() && "Out of range access");
+ return seq[index].get();
+ }
+};
+
+// Used to allow DefinedAtom content bytes to be a flow sequence of
+// two-digit hex numbers without the leading 0x (e.g. FF, 04, 0A)
+template <> struct ScalarTraits<ImplicitHex8> {
+ static void output(const ImplicitHex8 &val, void *, raw_ostream &out) {
+ uint8_t num = val;
+ out << llvm::format("%02X", num);
+ }
+
+ static StringRef input(StringRef str, void *, ImplicitHex8 &val) {
+ unsigned long long n;
+ if (getAsUnsignedInteger(str, 16, n))
+ return "invalid two-digit-hex number";
+ if (n > 0xFF)
+ return "out of range two-digit-hex number";
+ val = n;
+ return StringRef(); // returning empty string means success
+ }
+
+ static QuotingType mustQuote(StringRef) { return QuotingType::None; }
+};
+
+// YAML conversion for std::vector<const lld::File*>
+template <> struct DocumentListTraits<std::vector<const lld::File *> > {
+ static size_t size(IO &io, std::vector<const lld::File *> &seq) {
+ return seq.size();
+ }
+ static const lld::File *&element(IO &io, std::vector<const lld::File *> &seq,
+ size_t index) {
+ if (index >= seq.size())
+ seq.resize(index + 1);
+ return seq[index];
+ }
+};
+
+// YAML conversion for const lld::File*
+template <> struct MappingTraits<const lld::File *> {
+ class NormArchiveFile : public lld::ArchiveLibraryFile {
+ public:
+ NormArchiveFile(IO &io) : ArchiveLibraryFile("") {}
+
+ NormArchiveFile(IO &io, const lld::File *file)
+ : ArchiveLibraryFile(file->path()), _path(file->path()) {
+ // If we want to support writing archives, this constructor would
+ // need to populate _members.
+ }
+
+ const lld::File *denormalize(IO &io) { return this; }
+
+ const AtomRange<lld::DefinedAtom> defined() const override {
+ return _noDefinedAtoms;
+ }
+
+ const AtomRange<lld::UndefinedAtom> undefined() const override {
+ return _noUndefinedAtoms;
+ }
+
+ const AtomRange<lld::SharedLibraryAtom> sharedLibrary() const override {
+ return _noSharedLibraryAtoms;
+ }
+
+ const AtomRange<lld::AbsoluteAtom> absolute() const override {
+ return _noAbsoluteAtoms;
+ }
+
+ void clearAtoms() override {
+ _noDefinedAtoms.clear();
+ _noUndefinedAtoms.clear();
+ _noSharedLibraryAtoms.clear();
+ _noAbsoluteAtoms.clear();
+ }
+
+ File *find(StringRef name) override {
+ for (const ArchMember &member : _members)
+ for (const lld::DefinedAtom *atom : member._content->defined())
+ if (name == atom->name())
+ return const_cast<File *>(member._content);
+ return nullptr;
+ }
+
+ std::error_code
+ parseAllMembers(std::vector<std::unique_ptr<File>> &result) override {
+ return std::error_code();
+ }
+
+ StringRef _path;
+ std::vector<ArchMember> _members;
+ };
+
+ class NormalizedFile : public lld::File {
+ public:
+ NormalizedFile(IO &io)
+ : File("", kindNormalizedObject), _io(io), _rnb(nullptr),
+ _definedAtomsRef(_definedAtoms._atoms),
+ _undefinedAtomsRef(_undefinedAtoms._atoms),
+ _sharedLibraryAtomsRef(_sharedLibraryAtoms._atoms),
+ _absoluteAtomsRef(_absoluteAtoms._atoms) {}
+
+ NormalizedFile(IO &io, const lld::File *file)
+ : File(file->path(), kindNormalizedObject), _io(io),
+ _rnb(new RefNameBuilder(*file)), _path(file->path()),
+ _definedAtomsRef(file->defined()),
+ _undefinedAtomsRef(file->undefined()),
+ _sharedLibraryAtomsRef(file->sharedLibrary()),
+ _absoluteAtomsRef(file->absolute()) {
+ }
+
+ ~NormalizedFile() override {
+ }
+
+ const lld::File *denormalize(IO &io);
+
+ const AtomRange<lld::DefinedAtom> defined() const override {
+ return _definedAtomsRef;
+ }
+
+ const AtomRange<lld::UndefinedAtom> undefined() const override {
+ return _undefinedAtomsRef;
+ }
+
+ const AtomRange<lld::SharedLibraryAtom> sharedLibrary() const override {
+ return _sharedLibraryAtomsRef;
+ }
+
+ const AtomRange<lld::AbsoluteAtom> absolute() const override {
+ return _absoluteAtomsRef;
+ }
+
+ void clearAtoms() override {
+ _definedAtoms._atoms.clear();
+ _undefinedAtoms._atoms.clear();
+ _sharedLibraryAtoms._atoms.clear();
+ _absoluteAtoms._atoms.clear();
+ }
+
+ // Allocate a new copy of this string in _storage, so the strings
+ // can be freed when File is destroyed.
+ StringRef copyString(StringRef str) {
+ char *s = _storage.Allocate<char>(str.size());
+ memcpy(s, str.data(), str.size());
+ return StringRef(s, str.size());
+ }
+
+ IO &_io;
+ std::unique_ptr<RefNameBuilder> _rnb;
+ StringRef _path;
+ AtomList<lld::DefinedAtom> _definedAtoms;
+ AtomList<lld::UndefinedAtom> _undefinedAtoms;
+ AtomList<lld::SharedLibraryAtom> _sharedLibraryAtoms;
+ AtomList<lld::AbsoluteAtom> _absoluteAtoms;
+ AtomRange<lld::DefinedAtom> _definedAtomsRef;
+ AtomRange<lld::UndefinedAtom> _undefinedAtomsRef;
+ AtomRange<lld::SharedLibraryAtom> _sharedLibraryAtomsRef;
+ AtomRange<lld::AbsoluteAtom> _absoluteAtomsRef;
+ llvm::BumpPtrAllocator _storage;
+ };
+
+ static void mapping(IO &io, const lld::File *&file) {
+ YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+ assert(info != nullptr);
+ // Let any register tag handler process this.
+ if (info->_registry && info->_registry->handleTaggedDoc(io, file))
+ return;
+ // If no registered handler claims this tag and there is no tag,
+ // grandfather in as "!native".
+ if (io.mapTag("!native", true) || io.mapTag("tag:yaml.org,2002:map"))
+ mappingAtoms(io, file);
+ }
+
+ static void mappingAtoms(IO &io, const lld::File *&file) {
+ YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+ MappingNormalizationHeap<NormalizedFile, const lld::File *>
+ keys(io, file, nullptr);
+ assert(info != nullptr);
+ info->_file = keys.operator->();
+
+ io.mapOptional("path", keys->_path);
+
+ if (io.outputting()) {
+ io.mapOptional("defined-atoms", keys->_definedAtomsRef);
+ io.mapOptional("undefined-atoms", keys->_undefinedAtomsRef);
+ io.mapOptional("shared-library-atoms", keys->_sharedLibraryAtomsRef);
+ io.mapOptional("absolute-atoms", keys->_absoluteAtomsRef);
+ } else {
+ io.mapOptional("defined-atoms", keys->_definedAtoms);
+ io.mapOptional("undefined-atoms", keys->_undefinedAtoms);
+ io.mapOptional("shared-library-atoms", keys->_sharedLibraryAtoms);
+ io.mapOptional("absolute-atoms", keys->_absoluteAtoms);
+ }
+ }
+
+ static void mappingArchive(IO &io, const lld::File *&file) {
+ YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+ MappingNormalizationHeap<NormArchiveFile, const lld::File *>
+ keys(io, file, &info->_file->allocator());
+
+ io.mapOptional("path", keys->_path);
+ io.mapOptional("members", keys->_members);
+ }
+};
+
+// YAML conversion for const lld::Reference*
+template <> struct MappingTraits<const lld::Reference *> {
+ class NormalizedReference : public lld::Reference {
+ public:
+ NormalizedReference(IO &io)
+ : lld::Reference(lld::Reference::KindNamespace::all,
+ lld::Reference::KindArch::all, 0),
+ _target(nullptr), _offset(0), _addend(0), _tag(0) {}
+
+ NormalizedReference(IO &io, const lld::Reference *ref)
+ : lld::Reference(ref->kindNamespace(), ref->kindArch(),
+ ref->kindValue()),
+ _target(nullptr), _targetName(targetName(io, ref)),
+ _offset(ref->offsetInAtom()), _addend(ref->addend()),
+ _tag(ref->tag()) {
+ _mappedKind.ns = ref->kindNamespace();
+ _mappedKind.arch = ref->kindArch();
+ _mappedKind.value = ref->kindValue();
+ }
+
+ const lld::Reference *denormalize(IO &io) {
+ YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+ assert(info != nullptr);
+ typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
+ NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
+ if (!_targetName.empty())
+ _targetName = f->copyString(_targetName);
+ DEBUG_WITH_TYPE("WriterYAML", llvm::dbgs()
+ << "created Reference to name: '"
+ << _targetName << "' ("
+ << (const void *)_targetName.data()
+ << ", " << _targetName.size() << ")\n");
+ setKindNamespace(_mappedKind.ns);
+ setKindArch(_mappedKind.arch);
+ setKindValue(_mappedKind.value);
+ return this;
+ }
+
+ void bind(const RefNameResolver &);
+ static StringRef targetName(IO &io, const lld::Reference *ref);
+
+ uint64_t offsetInAtom() const override { return _offset; }
+ const lld::Atom *target() const override { return _target; }
+ Addend addend() const override { return _addend; }
+ void setAddend(Addend a) override { _addend = a; }
+ void setTarget(const lld::Atom *a) override { _target = a; }
+
+ const lld::Atom *_target;
+ StringRef _targetName;
+ uint32_t _offset;
+ Addend _addend;
+ RefKind _mappedKind;
+ uint32_t _tag;
+ };
+
+ static void mapping(IO &io, const lld::Reference *&ref) {
+ YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+ MappingNormalizationHeap<NormalizedReference, const lld::Reference *> keys(
+ io, ref, &info->_file->allocator());
+
+ io.mapRequired("kind", keys->_mappedKind);
+ io.mapOptional("offset", keys->_offset);
+ io.mapOptional("target", keys->_targetName);
+ io.mapOptional("addend", keys->_addend, (lld::Reference::Addend)0);
+ io.mapOptional("tag", keys->_tag, 0u);
+ }
+};
+
+// YAML conversion for const lld::DefinedAtom*
+template <> struct MappingTraits<const lld::DefinedAtom *> {
+
+ class NormalizedAtom : public lld::DefinedAtom {
+ public:
+ NormalizedAtom(IO &io)
+ : _file(fileFromContext(io)), _contentType(), _alignment(1) {
+ static uint32_t ordinalCounter = 1;
+ _ordinal = ordinalCounter++;
+ }
+
+ NormalizedAtom(IO &io, const lld::DefinedAtom *atom)
+ : _file(fileFromContext(io)), _name(atom->name()),
+ _scope(atom->scope()), _interpose(atom->interposable()),
+ _merge(atom->merge()), _contentType(atom->contentType()),
+ _alignment(atom->alignment()), _sectionChoice(atom->sectionChoice()),
+ _deadStrip(atom->deadStrip()), _dynamicExport(atom->dynamicExport()),
+ _codeModel(atom->codeModel()),
+ _permissions(atom->permissions()), _size(atom->size()),
+ _sectionName(atom->customSectionName()),
+ _sectionSize(atom->sectionSize()) {
+ for (const lld::Reference *r : *atom)
+ _references.push_back(r);
+ if (!atom->occupiesDiskSpace())
+ return;
+ ArrayRef<uint8_t> cont = atom->rawContent();
+ _content.reserve(cont.size());
+ for (uint8_t x : cont)
+ _content.push_back(x);
+ }
+
+ ~NormalizedAtom() override = default;
+
+ const lld::DefinedAtom *denormalize(IO &io) {
+ YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+ assert(info != nullptr);
+ typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
+ NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
+ if (!_name.empty())
+ _name = f->copyString(_name);
+ if (!_refName.empty())
+ _refName = f->copyString(_refName);
+ if (!_sectionName.empty())
+ _sectionName = f->copyString(_sectionName);
+ DEBUG_WITH_TYPE("WriterYAML",
+ llvm::dbgs() << "created DefinedAtom named: '" << _name
+ << "' (" << (const void *)_name.data()
+ << ", " << _name.size() << ")\n");
+ return this;
+ }
+
+ void bind(const RefNameResolver &);
+
+ // Extract current File object from YAML I/O parsing context
+ const lld::File &fileFromContext(IO &io) {
+ YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+ assert(info != nullptr);
+ assert(info->_file != nullptr);
+ return *info->_file;
+ }
+
+ const lld::File &file() const override { return _file; }
+ StringRef name() const override { return _name; }
+ uint64_t size() const override { return _size; }
+ Scope scope() const override { return _scope; }
+ Interposable interposable() const override { return _interpose; }
+ Merge merge() const override { return _merge; }
+ ContentType contentType() const override { return _contentType; }
+ Alignment alignment() const override { return _alignment; }
+ SectionChoice sectionChoice() const override { return _sectionChoice; }
+ StringRef customSectionName() const override { return _sectionName; }
+ uint64_t sectionSize() const override { return _sectionSize; }
+ DeadStripKind deadStrip() const override { return _deadStrip; }
+ DynamicExport dynamicExport() const override { return _dynamicExport; }
+ CodeModel codeModel() const override { return _codeModel; }
+ ContentPermissions permissions() const override { return _permissions; }
+ ArrayRef<uint8_t> rawContent() const override {
+ if (!occupiesDiskSpace())
+ return ArrayRef<uint8_t>();
+ return ArrayRef<uint8_t>(
+ reinterpret_cast<const uint8_t *>(_content.data()), _content.size());
+ }
+
+ uint64_t ordinal() const override { return _ordinal; }
+
+ reference_iterator begin() const override {
+ uintptr_t index = 0;
+ const void *it = reinterpret_cast<const void *>(index);
+ return reference_iterator(*this, it);
+ }
+ reference_iterator end() const override {
+ uintptr_t index = _references.size();
+ const void *it = reinterpret_cast<const void *>(index);
+ return reference_iterator(*this, it);
+ }
+ const lld::Reference *derefIterator(const void *it) const override {
+ uintptr_t index = reinterpret_cast<uintptr_t>(it);
+ assert(index < _references.size());
+ return _references[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(Reference::KindNamespace ns,
+ Reference::KindArch arch,
+ Reference::KindValue kindValue, uint64_t off,
+ const Atom *target, Reference::Addend a) override {
+ assert(target && "trying to create reference to nothing");
+ auto node = new (file().allocator()) SimpleReference(ns, arch, kindValue,
+ off, target, a);
+ _references.push_back(node);
+ }
+
+ const lld::File &_file;
+ StringRef _name;
+ StringRef _refName;
+ Scope _scope;
+ Interposable _interpose;
+ Merge _merge;
+ ContentType _contentType;
+ Alignment _alignment;
+ SectionChoice _sectionChoice;
+ DeadStripKind _deadStrip;
+ DynamicExport _dynamicExport;
+ CodeModel _codeModel;
+ ContentPermissions _permissions;
+ uint32_t _ordinal;
+ std::vector<ImplicitHex8> _content;
+ uint64_t _size;
+ StringRef _sectionName;
+ uint64_t _sectionSize;
+ std::vector<const lld::Reference *> _references;
+ };
+
+ static void mapping(IO &io, const lld::DefinedAtom *&atom) {
+ YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+ MappingNormalizationHeap<NormalizedAtom, const lld::DefinedAtom *> keys(
+ io, atom, &info->_file->allocator());
+ if (io.outputting()) {
+ // If writing YAML, check if atom needs a ref-name.
+ typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
+ assert(info != nullptr);
+ NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
+ assert(f);
+ assert(f->_rnb);
+ if (f->_rnb->hasRefName(atom)) {
+ keys->_refName = f->_rnb->refName(atom);
+ }
+ }
+
+ io.mapOptional("name", keys->_name, StringRef());
+ io.mapOptional("ref-name", keys->_refName, StringRef());
+ io.mapOptional("scope", keys->_scope,
+ DefinedAtom::scopeTranslationUnit);
+ io.mapOptional("type", keys->_contentType,
+ DefinedAtom::typeCode);
+ io.mapOptional("content", keys->_content);
+ io.mapOptional("size", keys->_size, (uint64_t)keys->_content.size());
+ io.mapOptional("interposable", keys->_interpose,
+ DefinedAtom::interposeNo);
+ io.mapOptional("merge", keys->_merge, DefinedAtom::mergeNo);
+ io.mapOptional("alignment", keys->_alignment,
+ DefinedAtom::Alignment(1));
+ io.mapOptional("section-choice", keys->_sectionChoice,
+ DefinedAtom::sectionBasedOnContent);
+ io.mapOptional("section-name", keys->_sectionName, StringRef());
+ io.mapOptional("section-size", keys->_sectionSize, (uint64_t)0);
+ io.mapOptional("dead-strip", keys->_deadStrip,
+ DefinedAtom::deadStripNormal);
+ io.mapOptional("dynamic-export", keys->_dynamicExport,
+ DefinedAtom::dynamicExportNormal);
+ io.mapOptional("code-model", keys->_codeModel, DefinedAtom::codeNA);
+ // default permissions based on content type
+ io.mapOptional("permissions", keys->_permissions,
+ DefinedAtom::permissions(
+ keys->_contentType));
+ io.mapOptional("references", keys->_references);
+ }
+};
+
+template <> struct MappingTraits<lld::DefinedAtom *> {
+ static void mapping(IO &io, lld::DefinedAtom *&atom) {
+ const lld::DefinedAtom *atomPtr = atom;
+ MappingTraits<const lld::DefinedAtom *>::mapping(io, atomPtr);
+ atom = const_cast<lld::DefinedAtom *>(atomPtr);
+ }
+};
+
+// YAML conversion for const lld::UndefinedAtom*
+template <> struct MappingTraits<const lld::UndefinedAtom *> {
+ class NormalizedAtom : public lld::UndefinedAtom {
+ public:
+ NormalizedAtom(IO &io)
+ : _file(fileFromContext(io)), _canBeNull(canBeNullNever) {}
+
+ NormalizedAtom(IO &io, const lld::UndefinedAtom *atom)
+ : _file(fileFromContext(io)), _name(atom->name()),
+ _canBeNull(atom->canBeNull()) {}
+
+ ~NormalizedAtom() override = default;
+
+ const lld::UndefinedAtom *denormalize(IO &io) {
+ YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+ assert(info != nullptr);
+ typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
+ NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
+ if (!_name.empty())
+ _name = f->copyString(_name);
+
+ DEBUG_WITH_TYPE("WriterYAML",
+ llvm::dbgs() << "created UndefinedAtom named: '" << _name
+ << "' (" << (const void *)_name.data() << ", "
+ << _name.size() << ")\n");
+ return this;
+ }
+
+ // Extract current File object from YAML I/O parsing context
+ const lld::File &fileFromContext(IO &io) {
+ YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+ assert(info != nullptr);
+ assert(info->_file != nullptr);
+ return *info->_file;
+ }
+
+ const lld::File &file() const override { return _file; }
+ StringRef name() const override { return _name; }
+ CanBeNull canBeNull() const override { return _canBeNull; }
+
+ const lld::File &_file;
+ StringRef _name;
+ CanBeNull _canBeNull;
+ };
+
+ static void mapping(IO &io, const lld::UndefinedAtom *&atom) {
+ YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+ MappingNormalizationHeap<NormalizedAtom, const lld::UndefinedAtom *> keys(
+ io, atom, &info->_file->allocator());
+
+ io.mapRequired("name", keys->_name);
+ io.mapOptional("can-be-null", keys->_canBeNull,
+ lld::UndefinedAtom::canBeNullNever);
+ }
+};
+
+template <> struct MappingTraits<lld::UndefinedAtom *> {
+ static void mapping(IO &io, lld::UndefinedAtom *&atom) {
+ const lld::UndefinedAtom *atomPtr = atom;
+ MappingTraits<const lld::UndefinedAtom *>::mapping(io, atomPtr);
+ atom = const_cast<lld::UndefinedAtom *>(atomPtr);
+ }
+};
+
+// YAML conversion for const lld::SharedLibraryAtom*
+template <> struct MappingTraits<const lld::SharedLibraryAtom *> {
+ class NormalizedAtom : public lld::SharedLibraryAtom {
+ public:
+ NormalizedAtom(IO &io)
+ : _file(fileFromContext(io)), _canBeNull(false),
+ _type(Type::Unknown), _size(0) {}
+
+ NormalizedAtom(IO &io, const lld::SharedLibraryAtom *atom)
+ : _file(fileFromContext(io)), _name(atom->name()),
+ _loadName(atom->loadName()), _canBeNull(atom->canBeNullAtRuntime()),
+ _type(atom->type()), _size(atom->size()) {}
+
+ ~NormalizedAtom() override = default;
+
+ const lld::SharedLibraryAtom *denormalize(IO &io) {
+ YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+ assert(info != nullptr);
+ typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
+ NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
+ if (!_name.empty())
+ _name = f->copyString(_name);
+ if (!_loadName.empty())
+ _loadName = f->copyString(_loadName);
+
+ DEBUG_WITH_TYPE("WriterYAML",
+ llvm::dbgs() << "created SharedLibraryAtom named: '"
+ << _name << "' ("
+ << (const void *)_name.data()
+ << ", " << _name.size() << ")\n");
+ return this;
+ }
+
+ // Extract current File object from YAML I/O parsing context
+ const lld::File &fileFromContext(IO &io) {
+ YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+ assert(info != nullptr);
+ assert(info->_file != nullptr);
+ return *info->_file;
+ }
+
+ const lld::File &file() const override { return _file; }
+ StringRef name() const override { return _name; }
+ StringRef loadName() const override { return _loadName; }
+ bool canBeNullAtRuntime() const override { return _canBeNull; }
+ Type type() const override { return _type; }
+ uint64_t size() const override { return _size; }
+
+ const lld::File &_file;
+ StringRef _name;
+ StringRef _loadName;
+ ShlibCanBeNull _canBeNull;
+ Type _type;
+ uint64_t _size;
+ };
+
+ static void mapping(IO &io, const lld::SharedLibraryAtom *&atom) {
+
+ YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+ MappingNormalizationHeap<NormalizedAtom, const lld::SharedLibraryAtom *>
+ keys(io, atom, &info->_file->allocator());
+
+ io.mapRequired("name", keys->_name);
+ io.mapOptional("load-name", keys->_loadName);
+ io.mapOptional("can-be-null", keys->_canBeNull, (ShlibCanBeNull) false);
+ io.mapOptional("type", keys->_type, SharedLibraryAtom::Type::Code);
+ io.mapOptional("size", keys->_size, uint64_t(0));
+ }
+};
+
+template <> struct MappingTraits<lld::SharedLibraryAtom *> {
+ static void mapping(IO &io, lld::SharedLibraryAtom *&atom) {
+ const lld::SharedLibraryAtom *atomPtr = atom;
+ MappingTraits<const lld::SharedLibraryAtom *>::mapping(io, atomPtr);
+ atom = const_cast<lld::SharedLibraryAtom *>(atomPtr);
+ }
+};
+
+// YAML conversion for const lld::AbsoluteAtom*
+template <> struct MappingTraits<const lld::AbsoluteAtom *> {
+ class NormalizedAtom : public lld::AbsoluteAtom {
+ public:
+ NormalizedAtom(IO &io)
+ : _file(fileFromContext(io)), _scope(), _value(0) {}
+
+ NormalizedAtom(IO &io, const lld::AbsoluteAtom *atom)
+ : _file(fileFromContext(io)), _name(atom->name()),
+ _scope(atom->scope()), _value(atom->value()) {}
+
+ ~NormalizedAtom() override = default;
+
+ const lld::AbsoluteAtom *denormalize(IO &io) {
+ YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+ assert(info != nullptr);
+ typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
+ NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
+ if (!_name.empty())
+ _name = f->copyString(_name);
+
+ DEBUG_WITH_TYPE("WriterYAML",
+ llvm::dbgs() << "created AbsoluteAtom named: '" << _name
+ << "' (" << (const void *)_name.data()
+ << ", " << _name.size() << ")\n");
+ return this;
+ }
+
+ // Extract current File object from YAML I/O parsing context
+ const lld::File &fileFromContext(IO &io) {
+ YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+ assert(info != nullptr);
+ assert(info->_file != nullptr);
+ return *info->_file;
+ }
+
+ const lld::File &file() const override { return _file; }
+ StringRef name() const override { return _name; }
+ uint64_t value() const override { return _value; }
+ Scope scope() const override { return _scope; }
+
+ const lld::File &_file;
+ StringRef _name;
+ StringRef _refName;
+ Scope _scope;
+ Hex64 _value;
+ };
+
+ static void mapping(IO &io, const lld::AbsoluteAtom *&atom) {
+ YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+ MappingNormalizationHeap<NormalizedAtom, const lld::AbsoluteAtom *> keys(
+ io, atom, &info->_file->allocator());
+
+ if (io.outputting()) {
+ typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
+ YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+ assert(info != nullptr);
+ NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
+ assert(f);
+ assert(f->_rnb);
+ if (f->_rnb->hasRefName(atom)) {
+ keys->_refName = f->_rnb->refName(atom);
+ }
+ }
+
+ io.mapRequired("name", keys->_name);
+ io.mapOptional("ref-name", keys->_refName, StringRef());
+ io.mapOptional("scope", keys->_scope);
+ io.mapRequired("value", keys->_value);
+ }
+};
+
+template <> struct MappingTraits<lld::AbsoluteAtom *> {
+ static void mapping(IO &io, lld::AbsoluteAtom *&atom) {
+ const lld::AbsoluteAtom *atomPtr = atom;
+ MappingTraits<const lld::AbsoluteAtom *>::mapping(io, atomPtr);
+ atom = const_cast<lld::AbsoluteAtom *>(atomPtr);
+ }
+};
+
+} // end namespace llvm
+} // end namespace yaml
+
+RefNameResolver::RefNameResolver(const lld::File *file, IO &io) : _io(io) {
+ typedef MappingTraits<const lld::DefinedAtom *>::NormalizedAtom
+ NormalizedAtom;
+ for (const lld::DefinedAtom *a : file->defined()) {
+ const auto *na = (const NormalizedAtom *)a;
+ if (!na->_refName.empty())
+ add(na->_refName, a);
+ else if (!na->_name.empty())
+ add(na->_name, a);
+ }
+
+ for (const lld::UndefinedAtom *a : file->undefined())
+ add(a->name(), a);
+
+ for (const lld::SharedLibraryAtom *a : file->sharedLibrary())
+ add(a->name(), a);
+
+ typedef MappingTraits<const lld::AbsoluteAtom *>::NormalizedAtom NormAbsAtom;
+ for (const lld::AbsoluteAtom *a : file->absolute()) {
+ const auto *na = (const NormAbsAtom *)a;
+ if (na->_refName.empty())
+ add(na->_name, a);
+ else
+ add(na->_refName, a);
+ }
+}
+
+inline const lld::File *
+MappingTraits<const lld::File *>::NormalizedFile::denormalize(IO &io) {
+ typedef MappingTraits<const lld::DefinedAtom *>::NormalizedAtom
+ NormalizedAtom;
+
+ RefNameResolver nameResolver(this, io);
+ // Now that all atoms are parsed, references can be bound.
+ for (const lld::DefinedAtom *a : this->defined()) {
+ auto *normAtom = (NormalizedAtom *)const_cast<DefinedAtom *>(a);
+ normAtom->bind(nameResolver);
+ }
+
+ return this;
+}
+
+inline void MappingTraits<const lld::DefinedAtom *>::NormalizedAtom::bind(
+ const RefNameResolver &resolver) {
+ typedef MappingTraits<const lld::Reference *>::NormalizedReference
+ NormalizedReference;
+ for (const lld::Reference *ref : _references) {
+ auto *normRef = (NormalizedReference *)const_cast<Reference *>(ref);
+ normRef->bind(resolver);
+ }
+}
+
+inline void MappingTraits<const lld::Reference *>::NormalizedReference::bind(
+ const RefNameResolver &resolver) {
+ _target = resolver.lookup(_targetName);
+}
+
+inline StringRef
+MappingTraits<const lld::Reference *>::NormalizedReference::targetName(
+ IO &io, const lld::Reference *ref) {
+ if (ref->target() == nullptr)
+ return StringRef();
+ YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+ assert(info != nullptr);
+ typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
+ NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
+ RefNameBuilder &rnb = *f->_rnb;
+ if (rnb.hasRefName(ref->target()))
+ return rnb.refName(ref->target());
+ return ref->target()->name();
+}
+
+namespace lld {
+namespace yaml {
+
+class Writer : public lld::Writer {
+public:
+ Writer(const LinkingContext &context) : _ctx(context) {}
+
+ llvm::Error writeFile(const lld::File &file, StringRef outPath) override {
+ // Create stream to path.
+ std::error_code ec;
+ llvm::raw_fd_ostream out(outPath, ec, llvm::sys::fs::F_Text);
+ if (ec)
+ return llvm::errorCodeToError(ec);
+
+ // Create yaml Output writer, using yaml options for context.
+ YamlContext yamlContext;
+ yamlContext._ctx = &_ctx;
+ yamlContext._registry = &_ctx.registry();
+ llvm::yaml::Output yout(out, &yamlContext);
+
+ // Write yaml output.
+ const lld::File *fileRef = &file;
+ yout << fileRef;
+
+ return llvm::Error::success();
+ }
+
+private:
+ const LinkingContext &_ctx;
+};
+
+} // end namespace yaml
+
+namespace {
+
+/// Handles !native tagged yaml documents.
+class NativeYamlIOTaggedDocumentHandler : public YamlIOTaggedDocumentHandler {
+ bool handledDocTag(llvm::yaml::IO &io, const lld::File *&file) const override {
+ if (io.mapTag("!native")) {
+ MappingTraits<const lld::File *>::mappingAtoms(io, file);
+ return true;
+ }
+ return false;
+ }
+};
+
+/// Handles !archive tagged yaml documents.
+class ArchiveYamlIOTaggedDocumentHandler : public YamlIOTaggedDocumentHandler {
+ bool handledDocTag(llvm::yaml::IO &io, const lld::File *&file) const override {
+ if (io.mapTag("!archive")) {
+ MappingTraits<const lld::File *>::mappingArchive(io, file);
+ return true;
+ }
+ return false;
+ }
+};
+
+class YAMLReader : public Reader {
+public:
+ YAMLReader(const Registry &registry) : _registry(registry) {}
+
+ bool canParse(file_magic magic, MemoryBufferRef mb) const override {
+ StringRef name = mb.getBufferIdentifier();
+ return name.endswith(".objtxt") || name.endswith(".yaml");
+ }
+
+ ErrorOr<std::unique_ptr<File>>
+ loadFile(std::unique_ptr<MemoryBuffer> mb,
+ const class Registry &) const override {
+ // Create YAML Input Reader.
+ YamlContext yamlContext;
+ yamlContext._registry = &_registry;
+ yamlContext._path = mb->getBufferIdentifier();
+ llvm::yaml::Input yin(mb->getBuffer(), &yamlContext);
+
+ // Fill vector with File objects created by parsing yaml.
+ std::vector<const lld::File *> createdFiles;
+ yin >> createdFiles;
+ assert(createdFiles.size() == 1);
+
+ // Error out now if there were parsing errors.
+ if (yin.error())
+ return make_error_code(lld::YamlReaderError::illegal_value);
+
+ std::shared_ptr<MemoryBuffer> smb(mb.release());
+ const File *file = createdFiles[0];
+ // Note: loadFile() should return vector of *const* File
+ File *f = const_cast<File *>(file);
+ f->setLastError(std::error_code());
+ f->setSharedMemoryBuffer(smb);
+ return std::unique_ptr<File>(f);
+ }
+
+private:
+ const Registry &_registry;
+};
+
+} // end anonymous namespace
+
+void Registry::addSupportYamlFiles() {
+ add(std::unique_ptr<Reader>(new YAMLReader(*this)));
+ add(std::unique_ptr<YamlIOTaggedDocumentHandler>(
+ new NativeYamlIOTaggedDocumentHandler()));
+ add(std::unique_ptr<YamlIOTaggedDocumentHandler>(
+ new ArchiveYamlIOTaggedDocumentHandler()));
+}
+
+std::unique_ptr<Writer> createWriterYAML(const LinkingContext &context) {
+ return std::unique_ptr<Writer>(new lld::yaml::Writer(context));
+}
+
+} // end namespace lld
diff --git a/contrib/llvm/tools/lld/tools/lld/CMakeLists.txt b/contrib/llvm/tools/lld/tools/lld/CMakeLists.txt
new file mode 100644
index 000000000000..d8829493fc22
--- /dev/null
+++ b/contrib/llvm/tools/lld/tools/lld/CMakeLists.txt
@@ -0,0 +1,27 @@
+set(LLVM_LINK_COMPONENTS
+ Support
+ )
+
+add_lld_tool(lld
+ lld.cpp
+ )
+
+target_link_libraries(lld
+ PRIVATE
+ lldCOFF
+ lldDriver
+ lldELF
+ lldMinGW
+ lldWasm
+ )
+
+install(TARGETS lld
+ RUNTIME DESTINATION bin)
+
+if(NOT LLD_SYMLINKS_TO_CREATE)
+ set(LLD_SYMLINKS_TO_CREATE lld-link ld.lld ld64.lld wasm-ld)
+endif()
+
+foreach(link ${LLD_SYMLINKS_TO_CREATE})
+ add_lld_symlink(${link} lld)
+endforeach()
diff --git a/contrib/llvm/tools/lld/tools/lld/lld.cpp b/contrib/llvm/tools/lld/tools/lld/lld.cpp
new file mode 100644
index 000000000000..4ba0b258e8d3
--- /dev/null
+++ b/contrib/llvm/tools/lld/tools/lld/lld.cpp
@@ -0,0 +1,148 @@
+//===- tools/lld/lld.cpp - Linker Driver Dispatcher -----------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the main function of the lld executable. The main
+// function is a thin wrapper which dispatches to the platform specific
+// driver.
+//
+// lld is a single executable that contains four different linkers for ELF,
+// COFF, WebAssembly and Mach-O. The main function dispatches according to
+// argv[0] (i.e. command name). The most common name for each target is shown
+// below:
+//
+// - ld.lld: ELF (Unix)
+// - ld64: Mach-O (macOS)
+// - lld-link: COFF (Windows)
+// - ld-wasm: WebAssembly
+//
+// lld can be invoked as "lld" along with "-flavor" option. This is for
+// backward compatibility and not recommended.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Common/Driver.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/Path.h"
+#include <cstdlib>
+
+using namespace lld;
+using namespace llvm;
+using namespace llvm::sys;
+
+enum Flavor {
+ Invalid,
+ Gnu, // -flavor gnu
+ WinLink, // -flavor link
+ Darwin, // -flavor darwin
+ Wasm, // -flavor wasm
+};
+
+LLVM_ATTRIBUTE_NORETURN static void die(const Twine &S) {
+ errs() << S << "\n";
+ exit(1);
+}
+
+static Flavor getFlavor(StringRef S) {
+ return StringSwitch<Flavor>(S)
+ .CasesLower("ld", "ld.lld", "gnu", Gnu)
+ .CasesLower("wasm", "ld-wasm", Wasm)
+ .CaseLower("link", WinLink)
+ .CasesLower("ld64", "ld64.lld", "darwin", Darwin)
+ .Default(Invalid);
+}
+
+static bool isPETarget(const std::vector<const char *> &V) {
+ for (auto It = V.begin(); It + 1 != V.end(); ++It) {
+ if (StringRef(*It) != "-m")
+ continue;
+ StringRef S = *(It + 1);
+ return S == "i386pe" || S == "i386pep" || S == "thumb2pe" || S == "arm64pe";
+ }
+ return false;
+}
+
+static Flavor parseProgname(StringRef Progname) {
+#if __APPLE__
+ // Use Darwin driver for "ld" on Darwin.
+ if (Progname == "ld")
+ return Darwin;
+#endif
+
+#if LLVM_ON_UNIX
+ // Use GNU driver for "ld" on other Unix-like system.
+ if (Progname == "ld")
+ return Gnu;
+#endif
+
+ // Progname may be something like "lld-gnu". Parse it.
+ SmallVector<StringRef, 3> V;
+ Progname.split(V, "-");
+ for (StringRef S : V)
+ if (Flavor F = getFlavor(S))
+ return F;
+ return Invalid;
+}
+
+static Flavor parseFlavor(std::vector<const char *> &V) {
+ // Parse -flavor option.
+ if (V.size() > 1 && V[1] == StringRef("-flavor")) {
+ if (V.size() <= 2)
+ die("missing arg value for '-flavor'");
+ Flavor F = getFlavor(V[2]);
+ if (F == Invalid)
+ die("Unknown flavor: " + StringRef(V[2]));
+ V.erase(V.begin() + 1, V.begin() + 3);
+ return F;
+ }
+
+ // Deduct the flavor from argv[0].
+ StringRef Arg0 = path::filename(V[0]);
+ if (Arg0.endswith_lower(".exe"))
+ Arg0 = Arg0.drop_back(4);
+ return parseProgname(Arg0);
+}
+
+// If this function returns true, lld calls _exit() so that it quickly
+// exits without invoking destructors of globally allocated objects.
+//
+// We don't want to do that if we are running tests though, because
+// doing that breaks leak sanitizer. So, lit sets this environment variable,
+// and we use it to detect whether we are running tests or not.
+static bool canExitEarly() { return StringRef(getenv("LLD_IN_TEST")) != "1"; }
+
+/// Universal linker main(). This linker emulates the gnu, darwin, or
+/// windows linker based on the argv[0] or -flavor option.
+int main(int Argc, const char **Argv) {
+ InitLLVM X(Argc, Argv);
+
+ std::vector<const char *> Args(Argv, Argv + Argc);
+#ifdef __FreeBSD__
+ return !elf::link(Args, true);
+#else
+ switch (parseFlavor(Args)) {
+ case Gnu:
+ if (isPETarget(Args))
+ return !mingw::link(Args);
+ return !elf::link(Args, canExitEarly());
+ case WinLink:
+ return !coff::link(Args, canExitEarly());
+ case Darwin:
+ return !mach_o::link(Args, canExitEarly());
+ case Wasm:
+ return !wasm::link(Args, canExitEarly());
+ default:
+ die("lld is a generic driver.\n"
+ "Invoke ld.lld (Unix), ld64.lld (macOS), lld-link (Windows), wasm-ld"
+ " (WebAssembly) instead");
+ }
+#endif
+}