aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.arcconfig4
-rw-r--r--.clang-format1
-rw-r--r--.gitignore24
-rw-r--r--CMakeLists.txt98
-rw-r--r--LICENSE.TXT62
-rw-r--r--Makefile86
-rw-r--r--README.md10
-rw-r--r--cmake/modules/FindVTune.cmake31
-rw-r--r--docs/C++11.rst9
-rw-r--r--docs/CMakeLists.txt8
-rw-r--r--docs/Driver.rst79
-rw-r--r--docs/Makefile155
-rw-r--r--docs/README.txt12
-rw-r--r--docs/Readers.rst172
-rw-r--r--docs/_static/favicon.icobin0 -> 1150 bytes
-rw-r--r--docs/_templates/indexsidebar.html4
-rw-r--r--docs/_templates/layout.html12
-rw-r--r--docs/conf.py254
-rw-r--r--docs/design.rst500
-rw-r--r--docs/development.rst48
-rw-r--r--docs/getting_started.rst106
-rw-r--r--docs/hello.pngbin0 -> 27616 bytes
-rw-r--r--docs/index.rst88
-rw-r--r--docs/llvm-theme/layout.html22
-rw-r--r--docs/llvm-theme/static/contents.pngbin0 -> 202 bytes
-rw-r--r--docs/llvm-theme/static/llvm.css345
-rw-r--r--docs/llvm-theme/static/logo.pngbin0 -> 9865 bytes
-rw-r--r--docs/llvm-theme/static/navigation.pngbin0 -> 218 bytes
-rw-r--r--docs/llvm-theme/theme.conf4
-rw-r--r--docs/make.bat190
-rw-r--r--docs/open_projects.rst17
-rw-r--r--docs/sphinx_intro.rst147
-rw-r--r--docs/windows_support.rst118
-rw-r--r--include/Makefile4
-rw-r--r--include/lld/Config/Makefile32
-rw-r--r--include/lld/Config/Version.h51
-rw-r--r--include/lld/Config/Version.inc.in5
-rw-r--r--include/lld/Core/AbsoluteAtom.h43
-rw-r--r--include/lld/Core/Alias.h102
-rw-r--r--include/lld/Core/ArchiveLibraryFile.h60
-rw-r--r--include/lld/Core/Atom.h76
-rw-r--r--include/lld/Core/DefinedAtom.h368
-rw-r--r--include/lld/Core/Error.h82
-rw-r--r--include/lld/Core/File.h324
-rw-r--r--include/lld/Core/Instrumentation.h132
-rw-r--r--include/lld/Core/LLVM.h75
-rw-r--r--include/lld/Core/LinkingContext.h364
-rw-r--r--include/lld/Core/Node.h78
-rw-r--r--include/lld/Core/Parallel.h309
-rw-r--r--include/lld/Core/Pass.h46
-rw-r--r--include/lld/Core/PassManager.h46
-rw-r--r--include/lld/Core/Reader.h169
-rw-r--r--include/lld/Core/Reference.h125
-rw-r--r--include/lld/Core/Resolver.h119
-rw-r--r--include/lld/Core/STDExtras.h29
-rw-r--r--include/lld/Core/SharedLibraryAtom.h53
-rw-r--r--include/lld/Core/SharedLibraryFile.h65
-rw-r--r--include/lld/Core/Simple.h341
-rw-r--r--include/lld/Core/SymbolTable.h117
-rw-r--r--include/lld/Core/TODO.txt17
-rw-r--r--include/lld/Core/UndefinedAtom.h74
-rw-r--r--include/lld/Core/Writer.h52
-rw-r--r--include/lld/Core/range.h738
-rw-r--r--include/lld/Driver/Driver.h162
-rw-r--r--include/lld/Driver/WinLinkModuleDef.h200
-rw-r--r--include/lld/Makefile44
-rw-r--r--include/lld/ReaderWriter/AtomLayout.h39
-rw-r--r--include/lld/ReaderWriter/CoreLinkingContext.h47
-rw-r--r--include/lld/ReaderWriter/ELFLinkingContext.h362
-rw-r--r--include/lld/ReaderWriter/ELFTargets.h38
-rw-r--r--include/lld/ReaderWriter/LinkerScript.h1396
-rw-r--r--include/lld/ReaderWriter/MachOLinkingContext.h369
-rw-r--r--include/lld/ReaderWriter/PECOFFLinkingContext.h463
-rw-r--r--include/lld/ReaderWriter/RelocationHelperFunctions.h57
-rw-r--r--include/lld/ReaderWriter/YamlContext.h46
-rw-r--r--lib/CMakeLists.txt4
-rw-r--r--lib/Config/CMakeLists.txt5
-rw-r--r--lib/Config/Makefile13
-rw-r--r--lib/Config/Version.cpp66
-rw-r--r--lib/Core/CMakeLists.txt12
-rw-r--r--lib/Core/DefinedAtom.cpp96
-rw-r--r--lib/Core/Error.cpp151
-rw-r--r--lib/Core/File.cpp30
-rw-r--r--lib/Core/LinkingContext.cpp104
-rw-r--r--lib/Core/Makefile13
-rw-r--r--lib/Core/Reader.cpp117
-rw-r--r--lib/Core/Resolver.cpp516
-rw-r--r--lib/Core/SymbolTable.cpp390
-rw-r--r--lib/Core/TODO.txt18
-rw-r--r--lib/Core/Writer.cpp23
-rw-r--r--lib/Driver/CMakeLists.txt43
-rw-r--r--lib/Driver/CoreDriver.cpp172
-rw-r--r--lib/Driver/CoreOptions.td15
-rw-r--r--lib/Driver/DarwinLdDriver.cpp832
-rw-r--r--lib/Driver/DarwinLdOptions.td187
-rw-r--r--lib/Driver/Driver.cpp130
-rw-r--r--lib/Driver/GnuLdDriver.cpp760
-rw-r--r--lib/Driver/GnuLdOptions.td323
-rw-r--r--lib/Driver/Makefile38
-rw-r--r--lib/Driver/TODO.rst101
-rw-r--r--lib/Driver/UniversalDriver.cpp218
-rw-r--r--lib/Driver/UniversalDriverOptions.td19
-rw-r--r--lib/Driver/WinLinkDriver.cpp1371
-rw-r--r--lib/Driver/WinLinkModuleDef.cpp295
-rw-r--r--lib/Driver/WinLinkOptions.td120
-rw-r--r--lib/Makefile16
-rw-r--r--lib/ReaderWriter/CMakeLists.txt20
-rw-r--r--lib/ReaderWriter/CoreLinkingContext.cpp171
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64DynamicLibraryWriter.h69
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64ELFFile.h41
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64ELFReader.h62
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.h68
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.cpp33
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.h95
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.cpp440
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.h33
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.cpp527
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.h32
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.cpp52
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.h64
-rw-r--r--lib/ReaderWriter/ELF/AArch64/CMakeLists.txt12
-rw-r--r--lib/ReaderWriter/ELF/AArch64/Makefile15
-rw-r--r--lib/ReaderWriter/ELF/AArch64/TODO.rst15
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMELFFile.h97
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMELFReader.h62
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h121
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp34
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h36
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp500
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h38
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp373
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMRelocationPass.h31
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h46
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp44
-rw-r--r--lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h88
-rw-r--r--lib/ReaderWriter/ELF/ARM/CMakeLists.txt12
-rw-r--r--lib/ReaderWriter/ELF/ARM/Makefile15
-rw-r--r--lib/ReaderWriter/ELF/ARM/TODO.rst20
-rw-r--r--lib/ReaderWriter/ELF/Atoms.h849
-rw-r--r--lib/ReaderWriter/ELF/CMakeLists.txt19
-rw-r--r--lib/ReaderWriter/ELF/Chunk.h102
-rw-r--r--lib/ReaderWriter/ELF/CreateELF.h118
-rw-r--r--lib/ReaderWriter/ELF/DefaultLayout.h1050
-rw-r--r--lib/ReaderWriter/ELF/DefaultTargetHandler.h38
-rw-r--r--lib/ReaderWriter/ELF/DynamicFile.h123
-rw-r--r--lib/ReaderWriter/ELF/DynamicLibraryWriter.h96
-rw-r--r--lib/ReaderWriter/ELF/ELFFile.h1179
-rw-r--r--lib/ReaderWriter/ELF/ELFLinkingContext.cpp259
-rw-r--r--lib/ReaderWriter/ELF/ELFReader.h102
-rw-r--r--lib/ReaderWriter/ELF/ExecutableWriter.h182
-rw-r--r--lib/ReaderWriter/ELF/HeaderChunks.h364
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/CMakeLists.txt11
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonDynamicLibraryWriter.h79
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonELFFile.h170
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonELFReader.h62
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonELFWriters.h61
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonEncodings.h601
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonExecutableAtoms.h29
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonExecutableWriter.h86
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.cpp25
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.h69
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonRelocationFunctions.h49
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.cpp350
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.h35
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonSectionChunks.h86
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.cpp334
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.h143
-rw-r--r--lib/ReaderWriter/ELF/Hexagon/Makefile16
-rw-r--r--lib/ReaderWriter/ELF/Layout.h59
-rw-r--r--lib/ReaderWriter/ELF/Makefile18
-rw-r--r--lib/ReaderWriter/ELF/Mips/CMakeLists.txt14
-rw-r--r--lib/ReaderWriter/ELF/Mips/Makefile15
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.cpp73
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.h25
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsDynamicLibraryWriter.h101
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsDynamicTable.h115
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsELFFile.h331
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsELFFlagsMerger.cpp149
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsELFFlagsMerger.h36
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsELFReader.h93
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsELFWriters.h82
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsExecutableWriter.h154
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp115
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h68
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp606
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.h31
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp1070
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsRelocationPass.h25
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h170
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp35
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h257
-rw-r--r--lib/ReaderWriter/ELF/OrderPass.h30
-rw-r--r--lib/ReaderWriter/ELF/OutputELFWriter.h615
-rw-r--r--lib/ReaderWriter/ELF/Reader.cpp43
-rw-r--r--lib/ReaderWriter/ELF/SectionChunks.h1498
-rw-r--r--lib/ReaderWriter/ELF/SegmentChunks.h686
-rw-r--r--lib/ReaderWriter/ELF/TODO.txt18
-rw-r--r--lib/ReaderWriter/ELF/TargetHandler.h86
-rw-r--r--lib/ReaderWriter/ELF/TargetLayout.h28
-rw-r--r--lib/ReaderWriter/ELF/Writer.cpp23
-rw-r--r--lib/ReaderWriter/ELF/Writer.h38
-rw-r--r--lib/ReaderWriter/ELF/X86/CMakeLists.txt11
-rw-r--r--lib/ReaderWriter/ELF/X86/Makefile15
-rw-r--r--lib/ReaderWriter/ELF/X86/X86DynamicLibraryWriter.h67
-rw-r--r--lib/ReaderWriter/ELF/X86/X86ELFFile.h41
-rw-r--r--lib/ReaderWriter/ELF/X86/X86ELFReader.h62
-rw-r--r--lib/ReaderWriter/ELF/X86/X86ExecutableWriter.h57
-rw-r--r--lib/ReaderWriter/ELF/X86/X86LinkingContext.cpp28
-rw-r--r--lib/ReaderWriter/ELF/X86/X86LinkingContext.h42
-rw-r--r--lib/ReaderWriter/ELF/X86/X86RelocationHandler.cpp57
-rw-r--r--lib/ReaderWriter/ELF/X86/X86RelocationHandler.h29
-rw-r--r--lib/ReaderWriter/ELF/X86/X86TargetHandler.cpp53
-rw-r--r--lib/ReaderWriter/ELF/X86/X86TargetHandler.h63
-rw-r--r--lib/ReaderWriter/ELF/X86_64/CMakeLists.txt16
-rw-r--r--lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/CMakeLists.txt11
-rw-r--r--lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleLinkingContext.cpp35
-rw-r--r--lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleLinkingContext.h31
-rw-r--r--lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleTargetHandler.cpp23
-rw-r--r--lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleTargetHandler.h31
-rw-r--r--lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/Makefile15
-rw-r--r--lib/ReaderWriter/ELF/X86_64/Makefile19
-rw-r--r--lib/ReaderWriter/ELF/X86_64/TODO.rst46
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64DynamicLibraryWriter.h63
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64ELFFile.h41
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64ELFReader.h62
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64ElfType.h21
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64ExecutableWriter.h61
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp38
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h100
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp151
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.h39
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp513
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.h32
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.cpp52
-rw-r--r--lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h69
-rw-r--r--lib/ReaderWriter/FileArchive.cpp293
-rw-r--r--lib/ReaderWriter/LinkerScript.cpp2564
-rw-r--r--lib/ReaderWriter/MachO/ArchHandler.cpp172
-rw-r--r--lib/ReaderWriter/MachO/ArchHandler.h300
-rw-r--r--lib/ReaderWriter/MachO/ArchHandler_arm.cpp1524
-rw-r--r--lib/ReaderWriter/MachO/ArchHandler_arm64.cpp822
-rw-r--r--lib/ReaderWriter/MachO/ArchHandler_x86.cpp642
-rw-r--r--lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp723
-rw-r--r--lib/ReaderWriter/MachO/Atoms.h181
-rw-r--r--lib/ReaderWriter/MachO/CMakeLists.txt26
-rw-r--r--lib/ReaderWriter/MachO/CompactUnwindPass.cpp530
-rw-r--r--lib/ReaderWriter/MachO/ExecutableAtoms.hpp136
-rw-r--r--lib/ReaderWriter/MachO/File.h327
-rw-r--r--lib/ReaderWriter/MachO/GOTPass.cpp185
-rw-r--r--lib/ReaderWriter/MachO/LayoutPass.cpp482
-rw-r--r--lib/ReaderWriter/MachO/LayoutPass.h97
-rw-r--r--lib/ReaderWriter/MachO/MachOLinkingContext.cpp969
-rw-r--r--lib/ReaderWriter/MachO/MachONormalizedFile.h323
-rw-r--r--lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp582
-rw-r--r--lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h177
-rw-r--r--lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp1346
-rw-r--r--lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp1238
-rw-r--r--lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp911
-rw-r--r--lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp802
-rw-r--r--lib/ReaderWriter/MachO/MachOPasses.h28
-rw-r--r--lib/ReaderWriter/MachO/Makefile14
-rw-r--r--lib/ReaderWriter/MachO/ShimPass.cpp129
-rw-r--r--lib/ReaderWriter/MachO/StubsPass.cpp373
-rw-r--r--lib/ReaderWriter/MachO/WriterMachO.cpp72
-rw-r--r--lib/ReaderWriter/Makefile16
-rw-r--r--lib/ReaderWriter/Native/CMakeLists.txt7
-rw-r--r--lib/ReaderWriter/Native/Makefile14
-rw-r--r--lib/ReaderWriter/Native/NativeFileFormat.h258
-rw-r--r--lib/ReaderWriter/Native/ReaderNative.cpp1013
-rw-r--r--lib/ReaderWriter/Native/WriterNative.cpp566
-rw-r--r--lib/ReaderWriter/PECOFF/Atoms.h312
-rw-r--r--lib/ReaderWriter/PECOFF/CMakeLists.txt16
-rw-r--r--lib/ReaderWriter/PECOFF/EdataPass.cpp227
-rw-r--r--lib/ReaderWriter/PECOFF/EdataPass.h99
-rw-r--r--lib/ReaderWriter/PECOFF/IdataPass.cpp345
-rw-r--r--lib/ReaderWriter/PECOFF/IdataPass.h218
-rw-r--r--lib/ReaderWriter/PECOFF/InferSubsystemPass.h66
-rw-r--r--lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.cpp48
-rw-r--r--lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h309
-rw-r--r--lib/ReaderWriter/PECOFF/LoadConfigPass.cpp75
-rw-r--r--lib/ReaderWriter/PECOFF/LoadConfigPass.h63
-rw-r--r--lib/ReaderWriter/PECOFF/Makefile14
-rw-r--r--lib/ReaderWriter/PECOFF/OrderPass.h67
-rw-r--r--lib/ReaderWriter/PECOFF/PDBPass.h43
-rw-r--r--lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp352
-rw-r--r--lib/ReaderWriter/PECOFF/Pass.cpp95
-rw-r--r--lib/ReaderWriter/PECOFF/Pass.h34
-rw-r--r--lib/ReaderWriter/PECOFF/ReaderCOFF.cpp1140
-rw-r--r--lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp389
-rw-r--r--lib/ReaderWriter/PECOFF/WriterImportLibrary.cpp118
-rw-r--r--lib/ReaderWriter/PECOFF/WriterImportLibrary.h23
-rw-r--r--lib/ReaderWriter/PECOFF/WriterPECOFF.cpp1417
-rw-r--r--lib/ReaderWriter/YAML/CMakeLists.txt6
-rw-r--r--lib/ReaderWriter/YAML/Makefile14
-rw-r--r--lib/ReaderWriter/YAML/ReaderWriterYAML.cpp1358
-rw-r--r--test/CMakeLists.txt47
-rw-r--r--test/Driver/Inputs/libtest.a1
-rw-r--r--test/Driver/Inputs/usr/lib/i386/libtest.a1
-rw-r--r--test/Driver/Inputs/usr/lib/libtest.a1
-rw-r--r--test/Driver/def-lib-search.test8
-rw-r--r--test/Driver/flavor-option.test8
-rw-r--r--test/Driver/lib-search.test24
-rw-r--r--test/Driver/so-whole-archive.test63
-rw-r--r--test/Driver/trivial-driver.test5
-rw-r--r--test/Driver/undef-basic.objtxt22
-rw-r--r--test/LinkerScript/expr-precedence.test34
-rw-r--r--test/LinkerScript/extern-bad-symbol.test22
-rw-r--r--test/LinkerScript/extern-empty.test19
-rw-r--r--test/LinkerScript/extern-valid.test29
-rw-r--r--test/LinkerScript/incomplete-ternary.test25
-rw-r--r--test/LinkerScript/libname-err-1.test11
-rw-r--r--test/LinkerScript/libname-err-2.test11
-rw-r--r--test/LinkerScript/linker-script-outputformat.test12
-rw-r--r--test/LinkerScript/linker-script.test46
-rw-r--r--test/LinkerScript/memory-empty.test17
-rw-r--r--test/LinkerScript/memory-missing-attrs.test32
-rw-r--r--test/LinkerScript/memory-missing-length.test29
-rw-r--r--test/LinkerScript/memory-missing-name.test31
-rw-r--r--test/LinkerScript/memory-missing-origin.test30
-rw-r--r--test/LinkerScript/memory-valid.test56
-rw-r--r--test/LinkerScript/missing-entry-symbol.test21
-rw-r--r--test/LinkerScript/missing-input-file-name.test25
-rw-r--r--test/LinkerScript/missing-input-sections.test27
-rw-r--r--test/LinkerScript/missing-operand.test24
-rw-r--r--test/LinkerScript/missing-output-section-name.test25
-rw-r--r--test/LinkerScript/missing-symbol.test24
-rw-r--r--test/LinkerScript/sections.test618
-rw-r--r--test/Makefile71
-rw-r--r--test/Unit/lit.cfg23
-rw-r--r--test/Unit/lit.site.cfg.in25
-rw-r--r--test/core/absolute-basic.objtxt23
-rw-r--r--test/core/absolute-local.objtxt25
-rw-r--r--test/core/archive-basic.objtxt44
-rw-r--r--test/core/archive-chain.objtxt70
-rw-r--r--test/core/archive-tentdef-search.objtxt42
-rw-r--r--test/core/associates.objtxt30
-rw-r--r--test/core/auto-hide-coalesce.objtxt60
-rw-r--r--test/core/code-model-attributes.objtxt50
-rw-r--r--test/core/constants-coalesce.objtxt60
-rw-r--r--test/core/cstring-coalesce.objtxt41
-rw-r--r--test/core/custom-section-coalesce.objtxt78
-rw-r--r--test/core/custom-section.objtxt34
-rw-r--r--test/core/dead-strip-attributes.objtxt29
-rw-r--r--test/core/dead-strip-basic.objtxt62
-rw-r--r--test/core/dead-strip-globals.objtxt60
-rw-r--r--test/core/dead-strip-reverse.objtxt25
-rw-r--r--test/core/error-atom-attribute.objtxt19
-rw-r--r--test/core/error-atom-content-byte-value.objtxt18
-rw-r--r--test/core/error-atom-content-bytes.objtxt19
-rw-r--r--test/core/error-atom-type.objtxt19
-rw-r--r--test/core/error-atom-undefined-wrong-attribue.objtxt17
-rw-r--r--test/core/error-duplicate-absolutes.objtxt24
-rw-r--r--test/core/error-file-attribute.objtxt17
-rw-r--r--test/core/error-fixup-attribute.objtxt21
-rw-r--r--test/core/error-fixup-target.objtxt26
-rw-r--r--test/core/fixups-addend.objtxt50
-rw-r--r--test/core/fixups-dup-named.objtxt31
-rw-r--r--test/core/fixups-named.objtxt36
-rw-r--r--test/core/fixups-unnamed.objtxt40
-rw-r--r--test/core/gnulinkonce-rearrange-resolve.objtxt79
-rw-r--r--test/core/gnulinkonce-remaining-undef.objtxt80
-rw-r--r--test/core/gnulinkonce-resolve.objtxt89
-rw-r--r--test/core/gnulinkonce-simple.objtxt80
-rw-r--r--test/core/inline-coalesce.objtxt31
-rw-r--r--test/core/multiple-def-error.objtxt19
-rw-r--r--test/core/permissions.objtxt57
-rw-r--r--test/core/sectiongroup-deadstrip.objtxt88
-rw-r--r--test/core/sectiongroup-gnulinkonce-error.objtxt64
-rw-r--r--test/core/sectiongroup-rearrange-resolve.objtxt79
-rw-r--r--test/core/sectiongroup-remaining-undef.objtxt80
-rw-r--r--test/core/sectiongroup-resolve.objtxt90
-rw-r--r--test/core/sectiongroup-simple.objtxt80
-rw-r--r--test/core/shared-library-basic.objtxt40
-rw-r--r--test/core/shared-library-coalesce.objtxt84
-rw-r--r--test/core/tent-merge.objtxt25
-rw-r--r--test/core/undef-coalesce-error.objtxt47
-rw-r--r--test/core/undef-coalesce.objtxt42
-rw-r--r--test/core/undef-fallback.objtxt37
-rw-r--r--test/core/undef-weak-coalesce.objtxt72
-rw-r--r--test/core/weak-coalesce.objtxt30
-rw-r--r--test/darwin/native-and-mach-o.objtxt65
-rw-r--r--test/elf/AArch64/Inputs/fn.c4
-rw-r--r--test/elf/AArch64/Inputs/fn.obin0 -> 899 bytes
-rw-r--r--test/elf/AArch64/Inputs/initfini-option.c12
-rw-r--r--test/elf/AArch64/Inputs/initfini-option.obin0 -> 1552 bytes
-rw-r--r--test/elf/AArch64/Inputs/initfini.c13
-rw-r--r--test/elf/AArch64/Inputs/initfini.obin0 -> 2056 bytes
-rw-r--r--test/elf/AArch64/Inputs/main.c4
-rw-r--r--test/elf/AArch64/Inputs/main.obin0 -> 1064 bytes
-rw-r--r--test/elf/AArch64/Inputs/no-interp-section.c1
-rw-r--r--test/elf/AArch64/Inputs/no-interp-section.obin0 -> 903 bytes
-rw-r--r--test/elf/AArch64/Inputs/zerosizedsection.obin0 -> 816 bytes
-rw-r--r--test/elf/AArch64/Inputs/zerosizedsection.s3
-rw-r--r--test/elf/AArch64/defsym.test22
-rw-r--r--test/elf/AArch64/dontignorezerosize-sections.test9
-rw-r--r--test/elf/AArch64/dynlib-nointerp-section.test5
-rw-r--r--test/elf/AArch64/initfini.test23
-rw-r--r--test/elf/AArch64/rel-abs32-overflow.test53
-rw-r--r--test/elf/AArch64/rel-abs32.test59
-rw-r--r--test/elf/AArch64/rel-abs64.test59
-rw-r--r--test/elf/AArch64/rel-bad.test44
-rw-r--r--test/elf/ARM/arm-symbols.test52
-rw-r--r--test/elf/ARM/defsym.test51
-rw-r--r--test/elf/ARM/entry-point.test77
-rw-r--r--test/elf/ARM/missing-symbol.test39
-rw-r--r--test/elf/ARM/rel-abs32.test59
-rw-r--r--test/elf/ARM/rel-arm-call.test60
-rw-r--r--test/elf/ARM/rel-arm-jump24-veneer-b.test101
-rw-r--r--test/elf/ARM/rel-arm-jump24-veneer-bl.test100
-rw-r--r--test/elf/ARM/rel-arm-jump24.test58
-rw-r--r--test/elf/ARM/rel-arm-mov.test64
-rw-r--r--test/elf/ARM/rel-arm-prel31.test47
-rw-r--r--test/elf/ARM/rel-arm-thm-interwork.test123
-rw-r--r--test/elf/ARM/rel-rel32.test57
-rw-r--r--test/elf/ARM/rel-thm-call.test61
-rw-r--r--test/elf/ARM/rel-thm-jump11.test141
-rw-r--r--test/elf/ARM/rel-thm-jump24-veneer.test100
-rw-r--r--test/elf/ARM/rel-thm-jump24.test59
-rw-r--r--test/elf/ARM/rel-thm-mov.test70
-rw-r--r--test/elf/ARM/rel-tls-ie32.test109
-rw-r--r--test/elf/ARM/rel-tls-le32.test61
-rw-r--r--test/elf/ARM/thm-symbols.test52
-rw-r--r--test/elf/ARM/undef-lazy-symbol.test135
-rw-r--r--test/elf/Hexagon/Inputs/dynobj-data.c3
-rw-r--r--test/elf/Hexagon/Inputs/dynobj-data.obin0 -> 916 bytes
-rw-r--r--test/elf/Hexagon/Inputs/dynobj.c26
-rw-r--r--test/elf/Hexagon/Inputs/dynobj.obin0 -> 1288 bytes
-rw-r--r--test/elf/Hexagon/Inputs/got-plt-order.c6
-rw-r--r--test/elf/Hexagon/Inputs/got-plt-order.obin0 -> 964 bytes
-rw-r--r--test/elf/Hexagon/Inputs/libMaxAlignment.abin0 -> 1010 bytes
-rw-r--r--test/elf/Hexagon/Inputs/sda-base.obin0 -> 1469 bytes
-rw-r--r--test/elf/Hexagon/Inputs/sdata1.c3
-rw-r--r--test/elf/Hexagon/Inputs/sdata1.obin0 -> 684 bytes
-rw-r--r--test/elf/Hexagon/Inputs/sdata2.c6
-rw-r--r--test/elf/Hexagon/Inputs/sdata2.obin0 -> 829 bytes
-rw-r--r--test/elf/Hexagon/Inputs/use-shared.hexagonbin0 -> 872 bytes
-rw-r--r--test/elf/Hexagon/dynlib-data.test9
-rw-r--r--test/elf/Hexagon/dynlib-gotoff.test128
-rw-r--r--test/elf/Hexagon/dynlib-hash.test9
-rw-r--r--test/elf/Hexagon/dynlib-rela.test9
-rw-r--r--test/elf/Hexagon/dynlib-syms.test7
-rw-r--r--test/elf/Hexagon/dynlib.test36
-rw-r--r--test/elf/Hexagon/hexagon-got-plt-order.test5
-rw-r--r--test/elf/Hexagon/hexagon-plt-setup.test12
-rw-r--r--test/elf/Hexagon/maxalignment.test8
-rw-r--r--test/elf/Hexagon/rela-order.test9
-rw-r--r--test/elf/Hexagon/sda-base.test4
-rw-r--r--test/elf/Hexagon/zerofillquick-sdata.test18
-rw-r--r--test/elf/Inputs/abs-test.i386bin0 -> 504 bytes
-rw-r--r--test/elf/Inputs/bar.o.x86-64bin0 -> 1240 bytes
-rw-r--r--test/elf/Inputs/branch-test.hexagonbin0 -> 700 bytes
-rw-r--r--test/elf/Inputs/branch-test.ppcbin0 -> 852 bytes
-rw-r--r--test/elf/Inputs/consecutive-weak-defs.o.yaml66
-rw-r--r--test/elf/Inputs/constants-merge.x86-64bin0 -> 1232 bytes
-rw-r--r--test/elf/Inputs/constdata.x86-64bin0 -> 1688 bytes
-rw-r--r--test/elf/Inputs/foo.o.x86-64bin0 -> 1240 bytes
-rw-r--r--test/elf/Inputs/globalconst.c2
-rw-r--r--test/elf/Inputs/globalconst.o.x86-64bin0 -> 1072 bytes
-rw-r--r--test/elf/Inputs/gotpcrel.S11
-rw-r--r--test/elf/Inputs/gotpcrel.x86-64bin0 -> 904 bytes
-rw-r--r--test/elf/Inputs/group-cmd-search-1.ls1
-rw-r--r--test/elf/Inputs/group-cmd-search-2.ls1
-rw-r--r--test/elf/Inputs/group-cmd-search-3.ls1
-rw-r--r--test/elf/Inputs/ifunc.S21
-rw-r--r--test/elf/Inputs/ifunc.cpp3
-rw-r--r--test/elf/Inputs/ifunc.cpp.x86-64bin0 -> 1224 bytes
-rw-r--r--test/elf/Inputs/ifunc.x86-64bin0 -> 912 bytes
-rw-r--r--test/elf/Inputs/init_array.x86-64bin0 -> 3440 bytes
-rw-r--r--test/elf/Inputs/libfnarchive.abin0 -> 2656 bytes
-rw-r--r--test/elf/Inputs/libifunc.x86-64.sobin0 -> 2512 bytes
-rw-r--r--test/elf/Inputs/libundef.sobin0 -> 11128 bytes
-rwxr-xr-xtest/elf/Inputs/libweaksym.sobin0 -> 2160 bytes
-rw-r--r--test/elf/Inputs/main-with-global-def.o.yaml56
-rw-r--r--test/elf/Inputs/mainobj.x86_64bin0 -> 1360 bytes
-rw-r--r--test/elf/Inputs/object-test.elf-hexagonbin0 -> 1532 bytes
-rw-r--r--test/elf/Inputs/object-test.elf-i386bin0 -> 1784 bytes
-rw-r--r--test/elf/Inputs/phdr.i386bin0 -> 17536 bytes
-rw-r--r--test/elf/Inputs/quickdata-sort-test.o.elf-hexagonbin0 -> 1385 bytes
-rw-r--r--test/elf/Inputs/quickdata-sortcommon-test.o.elf-hexagonbin0 -> 1469 bytes
-rw-r--r--test/elf/Inputs/quickdata-test.elf-hexagonbin0 -> 891 bytes
-rw-r--r--test/elf/Inputs/reloc-test.elf-i386bin0 -> 1076 bytes
-rw-r--r--test/elf/Inputs/reloc-xb.x86bin0 -> 568 bytes
-rw-r--r--test/elf/Inputs/reloc-xt.x86bin0 -> 548 bytes
-rw-r--r--test/elf/Inputs/relocs-dynamic.x86-64bin0 -> 864 bytes
-rw-r--r--test/elf/Inputs/relocs.x86-64bin0 -> 1536 bytes
-rw-r--r--test/elf/Inputs/responsefile1
-rw-r--r--test/elf/Inputs/rodata-test.hexagonbin0 -> 669 bytes
-rw-r--r--test/elf/Inputs/rodata-test.i386bin0 -> 537 bytes
-rw-r--r--test/elf/Inputs/rodata.c4
-rw-r--r--test/elf/Inputs/rodata.obin0 -> 1568 bytes
-rw-r--r--test/elf/Inputs/section-test.i386bin0 -> 717 bytes
-rw-r--r--test/elf/Inputs/shared.c16
-rw-r--r--test/elf/Inputs/shared.so-x86-64bin0 -> 7536 bytes
-rw-r--r--test/elf/Inputs/stripped-empty.x86_64bin0 -> 416 bytes
-rw-r--r--test/elf/Inputs/target-test.hexagonbin0 -> 676 bytes
-rw-r--r--test/elf/Inputs/target-test.ppcbin0 -> 552 bytes
-rw-r--r--test/elf/Inputs/tls.S50
-rw-r--r--test/elf/Inputs/tls.c11
-rw-r--r--test/elf/Inputs/tls.x86-64bin0 -> 1424 bytes
-rw-r--r--test/elf/Inputs/tlsAddr.x86-64bin0 -> 1752 bytes
-rw-r--r--test/elf/Inputs/tlsaddr.c8
-rw-r--r--test/elf/Inputs/undef-from-main-so.c1
-rw-r--r--test/elf/Inputs/undef-from-main.c5
-rw-r--r--test/elf/Inputs/undef-pc32.obin0 -> 1248 bytes
-rw-r--r--test/elf/Inputs/undef.obin0 -> 1264 bytes
-rw-r--r--test/elf/Inputs/undef2-so.o.yaml50
-rw-r--r--test/elf/Inputs/use-shared-32s.c8
-rw-r--r--test/elf/Inputs/use-shared-32s.x86-64bin0 -> 1336 bytes
-rw-r--r--test/elf/Inputs/use-shared.c7
-rw-r--r--test/elf/Inputs/use-shared.x86-64bin0 -> 1376 bytes
-rw-r--r--test/elf/Inputs/weaksym.obin0 -> 840 bytes
-rw-r--r--test/elf/Inputs/writersyms.obin0 -> 868 bytes
-rw-r--r--test/elf/Inputs/x86-64-relocs.S12
-rw-r--r--test/elf/Mips/base-address-64.test78
-rw-r--r--test/elf/Mips/base-address.test109
-rw-r--r--test/elf/Mips/ctors-order.test163
-rw-r--r--test/elf/Mips/dt-textrel-64.test74
-rw-r--r--test/elf/Mips/dt-textrel.test74
-rw-r--r--test/elf/Mips/dynlib-dynamic.test110
-rw-r--r--test/elf/Mips/dynlib-dynsym-micro.test208
-rw-r--r--test/elf/Mips/dynlib-dynsym.test202
-rw-r--r--test/elf/Mips/dynlib-fileheader-64.test72
-rw-r--r--test/elf/Mips/dynlib-fileheader-micro-64.test75
-rw-r--r--test/elf/Mips/dynlib-fileheader-micro.test82
-rw-r--r--test/elf/Mips/dynlib-fileheader.test80
-rw-r--r--test/elf/Mips/dynsym-table-1.test127
-rw-r--r--test/elf/Mips/dynsym-table-2.test105
-rw-r--r--test/elf/Mips/e-flags-merge-1-64.test30
-rw-r--r--test/elf/Mips/e-flags-merge-1.test56
-rw-r--r--test/elf/Mips/e-flags-merge-10.test43
-rw-r--r--test/elf/Mips/e-flags-merge-11.test43
-rw-r--r--test/elf/Mips/e-flags-merge-2-64.test33
-rw-r--r--test/elf/Mips/e-flags-merge-2.test35
-rw-r--r--test/elf/Mips/e-flags-merge-3-64.test130
-rw-r--r--test/elf/Mips/e-flags-merge-3.test134
-rw-r--r--test/elf/Mips/e-flags-merge-4-64.test64
-rw-r--r--test/elf/Mips/e-flags-merge-4.test65
-rw-r--r--test/elf/Mips/e-flags-merge-5-64.test42
-rw-r--r--test/elf/Mips/e-flags-merge-5.test42
-rw-r--r--test/elf/Mips/e-flags-merge-6-64.test79
-rw-r--r--test/elf/Mips/e-flags-merge-6.test80
-rw-r--r--test/elf/Mips/e-flags-merge-7-64.test42
-rw-r--r--test/elf/Mips/e-flags-merge-7.test42
-rw-r--r--test/elf/Mips/e-flags-merge-8.test65
-rw-r--r--test/elf/Mips/e-flags-merge-9.test43
-rw-r--r--test/elf/Mips/entry-name.test26
-rw-r--r--test/elf/Mips/exe-dynamic.test108
-rw-r--r--test/elf/Mips/exe-dynsym-micro.test94
-rw-r--r--test/elf/Mips/exe-dynsym.test91
-rw-r--r--test/elf/Mips/exe-fileheader-64.test66
-rw-r--r--test/elf/Mips/exe-fileheader-micro-64.test68
-rw-r--r--test/elf/Mips/exe-fileheader-micro.test69
-rw-r--r--test/elf/Mips/exe-fileheader.test105
-rw-r--r--test/elf/Mips/exe-got-micro.test115
-rw-r--r--test/elf/Mips/exe-got.test116
-rw-r--r--test/elf/Mips/got-page-32.test203
-rw-r--r--test/elf/Mips/got-page-64.test203
-rw-r--r--test/elf/Mips/got16-2.test73
-rw-r--r--test/elf/Mips/got16-micro.test165
-rw-r--r--test/elf/Mips/got16.test196
-rw-r--r--test/elf/Mips/gotsym.test43
-rw-r--r--test/elf/Mips/gp-sym-1-micro.test88
-rw-r--r--test/elf/Mips/gp-sym-1.test86
-rw-r--r--test/elf/Mips/gp-sym-2.test103
-rw-r--r--test/elf/Mips/hilo16-1.test44
-rw-r--r--test/elf/Mips/hilo16-2.test68
-rw-r--r--test/elf/Mips/hilo16-3.test45
-rw-r--r--test/elf/Mips/hilo16-4.test93
-rw-r--r--test/elf/Mips/hilo16-5.test103
-rw-r--r--test/elf/Mips/hilo16-8-micro.test81
-rw-r--r--test/elf/Mips/hilo16-9-micro.test68
-rw-r--r--test/elf/Mips/initfini-micro.test45
-rw-r--r--test/elf/Mips/interpreter-64.test26
-rw-r--r--test/elf/Mips/interpreter.test26
-rw-r--r--test/elf/Mips/invalid-reginfo.test28
-rw-r--r--test/elf/Mips/jalx-align-err.test46
-rw-r--r--test/elf/Mips/jump-fix-err.test45
-rw-r--r--test/elf/Mips/la25-stub-micro.test140
-rw-r--r--test/elf/Mips/la25-stub.test133
-rw-r--r--test/elf/Mips/mips-options-gp0.test78
-rw-r--r--test/elf/Mips/n64-rel-chain.test134
-rw-r--r--test/elf/Mips/opt-emulation.test41
-rw-r--r--test/elf/Mips/pc23-range.test56
-rw-r--r--test/elf/Mips/plt-entry-mixed-1.test114
-rw-r--r--test/elf/Mips/plt-entry-mixed-2.test93
-rw-r--r--test/elf/Mips/plt-entry-mixed-3.test98
-rw-r--r--test/elf/Mips/plt-entry-mixed-4.test85
-rw-r--r--test/elf/Mips/plt-entry-r6.test109
-rw-r--r--test/elf/Mips/plt-header-micro.test108
-rw-r--r--test/elf/Mips/plt-header-mixed.test105
-rw-r--r--test/elf/Mips/plt-header.test99
-rw-r--r--test/elf/Mips/r26-1-micro.test131
-rw-r--r--test/elf/Mips/r26-1.test132
-rw-r--r--test/elf/Mips/r26-2-micro.test88
-rw-r--r--test/elf/Mips/r26-2.test82
-rw-r--r--test/elf/Mips/rel-32.test59
-rw-r--r--test/elf/Mips/rel-64.test61
-rw-r--r--test/elf/Mips/rel-copy-micro.test159
-rw-r--r--test/elf/Mips/rel-copy-pc.test113
-rw-r--r--test/elf/Mips/rel-copy.test177
-rw-r--r--test/elf/Mips/rel-dynamic-01-micro.test201
-rw-r--r--test/elf/Mips/rel-dynamic-01.test237
-rw-r--r--test/elf/Mips/rel-dynamic-02.test82
-rw-r--r--test/elf/Mips/rel-dynamic-03-micro.test133
-rw-r--r--test/elf/Mips/rel-dynamic-03.test129
-rw-r--r--test/elf/Mips/rel-dynamic-04-micro.test211
-rw-r--r--test/elf/Mips/rel-dynamic-04.test206
-rw-r--r--test/elf/Mips/rel-dynamic-05-micro.test192
-rw-r--r--test/elf/Mips/rel-dynamic-05.test188
-rw-r--r--test/elf/Mips/rel-dynamic-06-64.test101
-rw-r--r--test/elf/Mips/rel-dynamic-06.test103
-rw-r--r--test/elf/Mips/rel-dynamic-07-64.test261
-rw-r--r--test/elf/Mips/rel-dynamic-07.test276
-rw-r--r--test/elf/Mips/rel-dynamic-08-64.test233
-rw-r--r--test/elf/Mips/rel-dynamic-08-micro.test236
-rw-r--r--test/elf/Mips/rel-dynamic-08.test233
-rw-r--r--test/elf/Mips/rel-dynamic-09-micro.test109
-rw-r--r--test/elf/Mips/rel-dynamic-09.test107
-rw-r--r--test/elf/Mips/rel-dynamic-10-micro.test166
-rw-r--r--test/elf/Mips/rel-dynamic-10.test160
-rw-r--r--test/elf/Mips/rel-dynamic-11.test110
-rw-r--r--test/elf/Mips/rel-dynamic-12.test213
-rw-r--r--test/elf/Mips/rel-gprel16.test104
-rw-r--r--test/elf/Mips/rel-gprel32-64.test70
-rw-r--r--test/elf/Mips/rel-gprel32.test84
-rw-r--r--test/elf/Mips/rel-pc-hilo.test70
-rw-r--r--test/elf/Mips/rel-pc18-s3.test54
-rw-r--r--test/elf/Mips/rel-pc19-s2.test54
-rw-r--r--test/elf/Mips/rel-pc21-s2.test54
-rw-r--r--test/elf/Mips/rel-pc26-s2.test54
-rw-r--r--test/elf/Mips/rel-pc32.test59
-rw-r--r--test/elf/Mips/rel-pc7-10-16-23.test86
-rw-r--r--test/elf/Mips/rel-sub.test61
-rw-r--r--test/elf/Mips/st-other.test90
-rw-r--r--test/elf/Mips/tls-1-micro.test65
-rw-r--r--test/elf/Mips/tls-1.test63
-rw-r--r--test/elf/Mips/tls-2-64.test69
-rw-r--r--test/elf/Mips/tls-2-micro.test70
-rw-r--r--test/elf/Mips/tls-2.test69
-rw-r--r--test/elf/Mips/tls-3-micro.test183
-rw-r--r--test/elf/Mips/tls-3.test180
-rw-r--r--test/elf/Mips/tls-4-micro.test126
-rw-r--r--test/elf/Mips/tls-4.test123
-rw-r--r--test/elf/Mips/tls-5-64.test71
-rw-r--r--test/elf/Mips/tls-5-micro.test70
-rw-r--r--test/elf/Mips/tls-5.test69
-rw-r--r--test/elf/X86_64/ExampleTarget/triple.test32
-rw-r--r--test/elf/X86_64/Inputs/constint.c1
-rw-r--r--test/elf/X86_64/Inputs/constint.obin0 -> 1062 bytes
-rw-r--r--test/elf/X86_64/Inputs/debug0.c5
-rw-r--r--test/elf/X86_64/Inputs/debug0.x86-64bin0 -> 2704 bytes
-rw-r--r--test/elf/X86_64/Inputs/debug1.c3
-rw-r--r--test/elf/X86_64/Inputs/debug1.x86-64bin0 -> 2584 bytes
-rw-r--r--test/elf/X86_64/Inputs/externtls.c6
-rw-r--r--test/elf/X86_64/Inputs/externtls.x86-64bin0 -> 1424 bytes
-rw-r--r--test/elf/X86_64/Inputs/fn.c4
-rw-r--r--test/elf/X86_64/Inputs/fn.obin0 -> 1072 bytes
-rw-r--r--test/elf/X86_64/Inputs/generaltls-so.o.yaml68
-rw-r--r--test/elf/X86_64/Inputs/group/1.c8
-rw-r--r--test/elf/X86_64/Inputs/group/1.obin0 -> 1456 bytes
-rw-r--r--test/elf/X86_64/Inputs/group/fn.c4
-rw-r--r--test/elf/X86_64/Inputs/group/fn.obin0 -> 1360 bytes
-rw-r--r--test/elf/X86_64/Inputs/group/fn1.c3
-rw-r--r--test/elf/X86_64/Inputs/group/fn1.obin0 -> 1352 bytes
-rw-r--r--test/elf/X86_64/Inputs/group/fn2.c3
-rw-r--r--test/elf/X86_64/Inputs/group/fn2.obin0 -> 1224 bytes
-rwxr-xr-xtest/elf/X86_64/Inputs/group/group.sh38
-rw-r--r--test/elf/X86_64/Inputs/group/libfn.abin0 -> 2792 bytes
-rwxr-xr-xtest/elf/X86_64/Inputs/group/libfn.sobin0 -> 2516 bytes
-rw-r--r--test/elf/X86_64/Inputs/group/libfn1.abin0 -> 1492 bytes
-rwxr-xr-xtest/elf/X86_64/Inputs/group/libfn2.sobin0 -> 9624 bytes
-rw-r--r--test/elf/X86_64/Inputs/initfini-option.c13
-rw-r--r--test/elf/X86_64/Inputs/initfini-option.obin0 -> 1824 bytes
-rw-r--r--test/elf/X86_64/Inputs/initfini.c14
-rw-r--r--test/elf/X86_64/Inputs/initfini.obin0 -> 2256 bytes
-rw-r--r--test/elf/X86_64/Inputs/largebss.c3
-rw-r--r--test/elf/X86_64/Inputs/largebss.obin0 -> 1131 bytes
-rw-r--r--test/elf/X86_64/Inputs/layoutpass/1.c8
-rw-r--r--test/elf/X86_64/Inputs/layoutpass/1.obin0 -> 1448 bytes
-rw-r--r--test/elf/X86_64/Inputs/layoutpass/2.c7
-rw-r--r--test/elf/X86_64/Inputs/layoutpass/2.obin0 -> 1320 bytes
-rw-r--r--test/elf/X86_64/Inputs/layoutpass/3.c3
-rw-r--r--test/elf/X86_64/Inputs/layoutpass/3.obin0 -> 1216 bytes
-rw-r--r--test/elf/X86_64/Inputs/layoutpass/lib2.abin0 -> 1464 bytes
-rw-r--r--test/elf/X86_64/Inputs/libfn.abin0 -> 1364 bytes
-rwxr-xr-xtest/elf/X86_64/Inputs/libfn.sobin0 -> 2008 bytes
-rw-r--r--test/elf/X86_64/Inputs/main.c4
-rw-r--r--test/elf/X86_64/Inputs/main.obin0 -> 1360 bytes
-rw-r--r--test/elf/X86_64/Inputs/multi-ovrd.c10
-rw-r--r--test/elf/X86_64/Inputs/multi-ovrd.obin0 -> 1648 bytes
-rw-r--r--test/elf/X86_64/Inputs/multi-weak.c20
-rw-r--r--test/elf/X86_64/Inputs/multi-weak.obin0 -> 1856 bytes
-rw-r--r--test/elf/X86_64/Inputs/multiweaksyms.obin0 -> 928 bytes
-rw-r--r--test/elf/X86_64/Inputs/nmagic.c8
-rw-r--r--test/elf/X86_64/Inputs/nmagic.obin0 -> 1528 bytes
-rw-r--r--test/elf/X86_64/Inputs/no-interp-section.c1
-rw-r--r--test/elf/X86_64/Inputs/no-interp-section.obin0 -> 975 bytes
-rw-r--r--test/elf/X86_64/Inputs/note.obin0 -> 785 bytes
-rw-r--r--test/elf/X86_64/Inputs/note.s11
-rw-r--r--test/elf/X86_64/Inputs/note_ro_rw.obin0 -> 905 bytes
-rw-r--r--test/elf/X86_64/Inputs/note_ro_rw.s21
-rw-r--r--test/elf/X86_64/Inputs/ovrd.c6
-rw-r--r--test/elf/X86_64/Inputs/ovrd.obin0 -> 1488 bytes
-rw-r--r--test/elf/X86_64/Inputs/rodata.c3
-rw-r--r--test/elf/X86_64/Inputs/rodata.obin0 -> 1584 bytes
-rw-r--r--test/elf/X86_64/Inputs/rodata.s24
-rw-r--r--test/elf/X86_64/Inputs/rwint.c1
-rw-r--r--test/elf/X86_64/Inputs/rwint.obin0 -> 963 bytes
-rw-r--r--test/elf/X86_64/Inputs/sectionmap.c4
-rw-r--r--test/elf/X86_64/Inputs/sectionmap.obin0 -> 1478 bytes
-rw-r--r--test/elf/X86_64/Inputs/undefcpp.c1
-rw-r--r--test/elf/X86_64/Inputs/undefcpp.obin0 -> 1344 bytes
-rw-r--r--test/elf/X86_64/Inputs/weak-zero-sized.obin0 -> 688 bytes
-rw-r--r--test/elf/X86_64/Inputs/weak.c14
-rw-r--r--test/elf/X86_64/Inputs/weak.obin0 -> 1712 bytes
-rw-r--r--test/elf/X86_64/Inputs/weak.s21
-rw-r--r--test/elf/X86_64/Inputs/zerosizedsection.obin0 -> 760 bytes
-rw-r--r--test/elf/X86_64/Inputs/zerosizedsection.s3
-rw-r--r--test/elf/X86_64/alignoffset.test119
-rw-r--r--test/elf/X86_64/debug.test57
-rw-r--r--test/elf/X86_64/defsym.test22
-rw-r--r--test/elf/X86_64/demangle.test12
-rw-r--r--test/elf/X86_64/dontignorezerosize-sections.test9
-rw-r--r--test/elf/X86_64/dynamicvars.test124
-rw-r--r--test/elf/X86_64/dynlib-nointerp-section.test4
-rw-r--r--test/elf/X86_64/dynlib-search.test6
-rw-r--r--test/elf/X86_64/dynsym-weak.test118
-rw-r--r--test/elf/X86_64/extern-tls.test16
-rw-r--r--test/elf/X86_64/general-dynamic-tls.test129
-rw-r--r--test/elf/X86_64/imagebase.test94
-rw-r--r--test/elf/X86_64/initfini-order.test10
-rw-r--r--test/elf/X86_64/initfini.test23
-rw-r--r--test/elf/X86_64/largebss.test20
-rw-r--r--test/elf/X86_64/layoutpass-order.test14
-rw-r--r--test/elf/X86_64/maxpagesize.test113
-rw-r--r--test/elf/X86_64/mergesimilarstrings.test47
-rw-r--r--test/elf/X86_64/multi-weak-layout.test52
-rw-r--r--test/elf/X86_64/multi-weak-override.test16
-rw-r--r--test/elf/X86_64/multi-weak-syms-order.test13
-rw-r--r--test/elf/X86_64/nmagic.test91
-rw-r--r--test/elf/X86_64/noalignsegments.test95
-rw-r--r--test/elf/X86_64/note-sections-ro_plus_rw.test42
-rw-r--r--test/elf/X86_64/note-sections.test23
-rw-r--r--test/elf/X86_64/omagic.test237
-rw-r--r--test/elf/X86_64/outputsegments.test189
-rw-r--r--test/elf/X86_64/reloc_r_x86_64_16.test60
-rw-r--r--test/elf/X86_64/reloc_r_x86_64_pc16.test61
-rw-r--r--test/elf/X86_64/reloc_r_x86_64_pc64.test61
-rw-r--r--test/elf/X86_64/rodata.test9
-rw-r--r--test/elf/X86_64/sectionchoice.test7
-rw-r--r--test/elf/X86_64/sectionmap.test22
-rw-r--r--test/elf/X86_64/startGroupEndGroup.test48
-rw-r--r--test/elf/X86_64/startGroupEndGroupWithDynlib.test10
-rw-r--r--test/elf/X86_64/staticlib-search.test6
-rw-r--r--test/elf/X86_64/undef.test18
-rw-r--r--test/elf/X86_64/underscore-end.test81
-rw-r--r--test/elf/X86_64/weak-override.test45
-rw-r--r--test/elf/X86_64/weak-zero-sized.test26
-rw-r--r--test/elf/X86_64/weaksym.test78
-rw-r--r--test/elf/X86_64/yamlinput.test166
-rw-r--r--test/elf/abs-dup.objtxt19
-rw-r--r--test/elf/abs.test19
-rw-r--r--test/elf/allowduplicates.objtxt51
-rw-r--r--test/elf/archive-elf-forceload.test43
-rw-r--r--test/elf/archive-elf.test38
-rw-r--r--test/elf/as-needed.test15
-rw-r--r--test/elf/branch.test34
-rw-r--r--test/elf/check.test39
-rw-r--r--test/elf/checkrodata.test9
-rw-r--r--test/elf/common.test10
-rw-r--r--test/elf/consecutive-weak-sym-defs.test81
-rw-r--r--test/elf/defsym.objtxt28
-rw-r--r--test/elf/dynamic-segorder.test17
-rw-r--r--test/elf/dynamic-undef.test34
-rw-r--r--test/elf/dynamic.test80
-rw-r--r--test/elf/eh_frame_hdr.test30
-rw-r--r--test/elf/entry.objtxt58
-rw-r--r--test/elf/export-dynamic.test99
-rw-r--r--test/elf/filenotfound.test3
-rw-r--r--test/elf/gnulinkonce/gnulinkonce-report-discarded-reference.test147
-rw-r--r--test/elf/gnulinkonce/gnulinkonce-report-undef.test129
-rw-r--r--test/elf/gnulinkonce/gnulinkonce.test151
-rw-r--r--test/elf/gotpcrel.test21
-rw-r--r--test/elf/gottpoff.test120
-rw-r--r--test/elf/group-cmd-search.test134
-rw-r--r--test/elf/hexagon-quickdata-sort.test12
-rw-r--r--test/elf/hexagon-quickdata-sortcommon.test16
-rw-r--r--test/elf/ifunc.test69
-rw-r--r--test/elf/ignore-unknownoption.test5
-rw-r--r--test/elf/init_array-order.test67
-rw-r--r--test/elf/init_array.test6
-rw-r--r--test/elf/initfini-options.test-1.test33
-rw-r--r--test/elf/initfini-options.test-2.test47
-rw-r--r--test/elf/initfini-options.test-3.test53
-rw-r--r--test/elf/librarynotfound.test5
-rw-r--r--test/elf/linker-as-ld.test16
-rw-r--r--test/elf/linkerscript/Inputs/externs.ls3
-rw-r--r--test/elf/linkerscript/Inputs/invalid.ls1
-rw-r--r--test/elf/linkerscript/Inputs/prog1.o.yaml88
-rw-r--r--test/elf/linkerscript/Inputs/prog2.o.yaml89
-rw-r--r--test/elf/linkerscript/Inputs/prog3.o.yaml52
-rw-r--r--test/elf/linkerscript/Inputs/simple.o.yaml52
-rw-r--r--test/elf/linkerscript/Inputs/valid.ls6
-rw-r--r--test/elf/linkerscript/externs.objtxt21
-rw-r--r--test/elf/linkerscript/invalid-script-cli-1.test10
-rw-r--r--test/elf/linkerscript/invalid-script-cli-2.test6
-rw-r--r--test/elf/linkerscript/invalid.test5
-rw-r--r--test/elf/linkerscript/sections-order.test97
-rw-r--r--test/elf/linkerscript/sections-with-wildcards.test88
-rw-r--r--test/elf/linkerscript/symbol-definition.test54
-rw-r--r--test/elf/linkerscript/valid-script-cli.objtxt23
-rw-r--r--test/elf/loginputfiles.test28
-rw-r--r--test/elf/mergeatoms.test6
-rw-r--r--test/elf/mergeconstants.test20
-rw-r--r--test/elf/mergeglobalatoms.test11
-rw-r--r--test/elf/note.test49
-rw-r--r--test/elf/options/dynamic-linker.test17
-rw-r--r--test/elf/phdr.test99
-rw-r--r--test/elf/quickdata.test15
-rw-r--r--test/elf/reloc.test38
-rw-r--r--test/elf/responsefile.test6
-rw-r--r--test/elf/rodata.test5
-rw-r--r--test/elf/rosegment.test26
-rw-r--r--test/elf/sectionGroups/sectiongroup-new-members.test153
-rw-r--r--test/elf/sectionGroups/sectiongroup-simple.test146
-rw-r--r--test/elf/sectionGroups/sectiongroup-undef-member-other.test158
-rw-r--r--test/elf/sectionGroups/sectiongroup-undef-member.test144
-rw-r--r--test/elf/sectionGroups/sectiongroup-with-globalsymbols.test253
-rw-r--r--test/elf/sectionGroups/sectiongroup-with-undef-external-reference.test239
-rw-r--r--test/elf/sectionGroups/sectiongroup-with-undef-signature.test222
-rw-r--r--test/elf/sections.test142
-rw-r--r--test/elf/sh_addralign.test38
-rw-r--r--test/elf/soname.test6
-rw-r--r--test/elf/strip-all.test107
-rw-r--r--test/elf/stripped-empty.test4
-rw-r--r--test/elf/symbols.test33
-rw-r--r--test/elf/tls.test43
-rw-r--r--test/elf/tlsAddr.test7
-rw-r--r--test/elf/undef-from-dso-to-main.test52
-rw-r--r--test/elf/undef-from-main-dso.test43
-rw-r--r--test/elf/weaksym.test7
-rw-r--r--test/elf/wrap.test279
-rw-r--r--test/elf/x86-64-dynamic-relocs.test26
-rw-r--r--test/elf/x86-64-dynamic.test79
-rw-r--r--test/elf/x86.test38
-rw-r--r--test/elf/x86_64-kinds.test23
-rw-r--r--test/lit.cfg167
-rw-r--r--test/lit.site.cfg.in22
-rwxr-xr-xtest/mach-o/Inputs/DependencyDump.py30
-rw-r--r--test/mach-o/Inputs/bar.yaml18
-rw-r--r--test/mach-o/Inputs/exported_symbols_list.exp6
-rw-r--r--test/mach-o/Inputs/full.filelist3
-rwxr-xr-xtest/mach-o/Inputs/lib-search-paths/usr/lib/libmyshared.dylibbin0 -> 20628 bytes
-rw-r--r--test/mach-o/Inputs/lib-search-paths/usr/lib/libmystatic.abin0 -> 556 bytes
-rw-r--r--test/mach-o/Inputs/lib-search-paths/usr/local/lib/file.obin0 -> 404 bytes
-rw-r--r--test/mach-o/Inputs/libSystem.yaml13
-rw-r--r--test/mach-o/Inputs/libbar.abin0 -> 824 bytes
-rw-r--r--test/mach-o/Inputs/libfoo.abin0 -> 1320 bytes
-rw-r--r--test/mach-o/Inputs/order_file-basic.order11
-rw-r--r--test/mach-o/Inputs/partial.filelist3
-rw-r--r--test/mach-o/Inputs/use-dylib-install-names.yaml28
-rw-r--r--test/mach-o/PIE.yaml44
-rw-r--r--test/mach-o/align_text.yaml45
-rw-r--r--test/mach-o/arm-interworking-movw.yaml393
-rw-r--r--test/mach-o/arm-interworking.yaml362
-rw-r--r--test/mach-o/arm-shims.yaml179
-rw-r--r--test/mach-o/arm-subsections-via-symbols.yaml60
-rw-r--r--test/mach-o/cstring-sections.yaml91
-rw-r--r--test/mach-o/data-only-dylib.yaml27
-rw-r--r--test/mach-o/demangle.yaml74
-rw-r--r--test/mach-o/dependency_info.yaml24
-rw-r--r--test/mach-o/dso_handle.yaml62
-rw-r--r--test/mach-o/dylib-exports.yaml41
-rw-r--r--test/mach-o/dylib-install-names.yaml74
-rw-r--r--test/mach-o/exe-offsets.yaml45
-rw-r--r--test/mach-o/exe-segment-overlap.yaml44
-rw-r--r--test/mach-o/exported_symbols_list-dylib.yaml77
-rw-r--r--test/mach-o/exported_symbols_list-obj.yaml67
-rw-r--r--test/mach-o/exported_symbols_list-undef.yaml55
-rw-r--r--test/mach-o/fat-archive.yaml45
-rw-r--r--test/mach-o/filelist.yaml18
-rw-r--r--test/mach-o/force_load-dylib.yaml45
-rw-r--r--test/mach-o/force_load-x86_64.yaml38
-rw-r--r--test/mach-o/framework-user-paths.yaml41
-rw-r--r--test/mach-o/got-order.yaml134
-rw-r--r--test/mach-o/hello-world-arm64.yaml104
-rw-r--r--test/mach-o/hello-world-armv6.yaml72
-rw-r--r--test/mach-o/hello-world-armv7.yaml85
-rw-r--r--test/mach-o/hello-world-x86.yaml71
-rw-r--r--test/mach-o/hello-world-x86_64.yaml126
-rw-r--r--test/mach-o/image-base.yaml27
-rw-r--r--test/mach-o/infer-arch.yaml29
-rw-r--r--test/mach-o/interposing-section.yaml79
-rw-r--r--test/mach-o/keep_private_externs.yaml63
-rw-r--r--test/mach-o/lazy-bind-x86_64.yaml125
-rw-r--r--test/mach-o/lib-search-paths.yaml16
-rw-r--r--test/mach-o/library-order.yaml45
-rw-r--r--test/mach-o/library-rescan.yaml46
-rw-r--r--test/mach-o/libresolve-bizarre-root-override.yaml17
-rw-r--r--test/mach-o/libresolve-multiple-syslibroots.yaml17
-rw-r--r--test/mach-o/libresolve-one-syslibroot.yaml25
-rw-r--r--test/mach-o/libresolve-simple.yaml21
-rw-r--r--test/mach-o/libresolve-user-paths.yaml20
-rw-r--r--test/mach-o/libresolve-z.yaml21
-rw-r--r--test/mach-o/linker-as-ld.yaml39
-rw-r--r--test/mach-o/lit.local.cfg4
-rw-r--r--test/mach-o/mh_bundle_header.yaml53
-rw-r--r--test/mach-o/mh_dylib_header.yaml53
-rw-r--r--test/mach-o/objc_export_list.yaml63
-rw-r--r--test/mach-o/order_file-basic.yaml75
-rw-r--r--test/mach-o/parse-aliases.yaml90
-rw-r--r--test/mach-o/parse-arm-relocs.yaml818
-rw-r--r--test/mach-o/parse-cfstring32.yaml94
-rw-r--r--test/mach-o/parse-cfstring64.yaml108
-rw-r--r--test/mach-o/parse-compact-unwind32.yaml72
-rw-r--r--test/mach-o/parse-compact-unwind64.yaml76
-rw-r--r--test/mach-o/parse-data-in-code-armv7.yaml157
-rw-r--r--test/mach-o/parse-data-in-code-x86.yaml77
-rw-r--r--test/mach-o/parse-data-relocs-arm64.yaml222
-rw-r--r--test/mach-o/parse-data-relocs-x86_64.yaml230
-rw-r--r--test/mach-o/parse-data.yaml119
-rw-r--r--test/mach-o/parse-eh-frame-x86-anon.yaml129
-rw-r--r--test/mach-o/parse-eh-frame-x86-labeled.yaml193
-rw-r--r--test/mach-o/parse-eh-frame.yaml88
-rw-r--r--test/mach-o/parse-function.yaml100
-rw-r--r--test/mach-o/parse-initializers32.yaml84
-rw-r--r--test/mach-o/parse-initializers64.yaml105
-rw-r--r--test/mach-o/parse-literals-error.yaml25
-rw-r--r--test/mach-o/parse-literals.yaml93
-rw-r--r--test/mach-o/parse-non-lazy-pointers.yaml98
-rw-r--r--test/mach-o/parse-relocs-x86.yaml296
-rw-r--r--test/mach-o/parse-section-no-symbol.yaml23
-rw-r--r--test/mach-o/parse-tentative-defs.yaml88
-rw-r--r--test/mach-o/parse-text-relocs-arm64.yaml237
-rw-r--r--test/mach-o/parse-text-relocs-x86_64.yaml168
-rw-r--r--test/mach-o/re-exported-dylib-ordinal.yaml105
-rw-r--r--test/mach-o/rpath.yaml38
-rw-r--r--test/mach-o/sectalign.yaml80
-rw-r--r--test/mach-o/unwind-info-simple-arm64.yaml280
-rw-r--r--test/mach-o/unwind-info-simple-x86_64.yaml118
-rw-r--r--test/mach-o/upward-dylib-load-command.yaml48
-rw-r--r--test/mach-o/upward-dylib-paths.yaml18
-rw-r--r--test/mach-o/usage.yaml8
-rw-r--r--test/mach-o/use-simple-dylib.yaml131
-rw-r--r--test/mach-o/write-final-sections.yaml167
-rw-r--r--test/mach-o/wrong-arch-error.yaml49
-rw-r--r--test/pecoff/Inputs/abs.obj.yaml11
-rw-r--r--test/pecoff/Inputs/alignment.obj.yaml103
-rw-r--r--test/pecoff/Inputs/alternatename1.obj.yaml23
-rw-r--r--test/pecoff/Inputs/alternatename2.obj.yaml23
-rw-r--r--test/pecoff/Inputs/alternatename3.obj.yaml39
-rw-r--r--test/pecoff/Inputs/armnt-ImageBase.obj.yaml39
-rw-r--r--test/pecoff/Inputs/armnt-ImageBase.s16
-rw-r--r--test/pecoff/Inputs/armnt-addr32-exec.obj.yaml55
-rw-r--r--test/pecoff/Inputs/armnt-addr32-exec.s24
-rw-r--r--test/pecoff/Inputs/armnt-addr32.obj.yaml39
-rw-r--r--test/pecoff/Inputs/armnt-addr32.s18
-rw-r--r--test/pecoff/Inputs/armnt-blx23t.obj.yaml39
-rw-r--r--test/pecoff/Inputs/armnt-blx23t.s33
-rw-r--r--test/pecoff/Inputs/armnt-branch24t.obj.yaml39
-rw-r--r--test/pecoff/Inputs/armnt-branch24t.s26
-rw-r--r--test/pecoff/Inputs/armnt-exports.def4
-rw-r--r--test/pecoff/Inputs/armnt-exports.obj.yaml35
-rw-r--r--test/pecoff/Inputs/armnt-import.obj.yaml39
-rw-r--r--test/pecoff/Inputs/armnt-import.s21
-rw-r--r--test/pecoff/Inputs/armnt-mov32t-exec.obj.yaml39
-rw-r--r--test/pecoff/Inputs/armnt-mov32t-exec.s30
-rw-r--r--test/pecoff/Inputs/armnt-mov32t.obj.yaml55
-rw-r--r--test/pecoff/Inputs/armnt-mov32t.s24
-rw-r--r--test/pecoff/Inputs/armnt-obj.s12
-rw-r--r--test/pecoff/Inputs/armnt-obj.yaml29
-rw-r--r--test/pecoff/Inputs/associative1.obj.yaml53
-rw-r--r--test/pecoff/Inputs/associative3.obj.yaml33
-rw-r--r--test/pecoff/Inputs/basereloc.obj.yaml164
-rw-r--r--test/pecoff/Inputs/bss.asm20
-rw-r--r--test/pecoff/Inputs/bss.objbin0 -> 683 bytes
-rw-r--r--test/pecoff/Inputs/comdat.obj.yaml53
-rw-r--r--test/pecoff/Inputs/common-symbol.obj.yaml85
-rw-r--r--test/pecoff/Inputs/drectve.obj.yaml79
-rw-r--r--test/pecoff/Inputs/drectve2.obj.yaml45
-rw-r--r--test/pecoff/Inputs/drectve3.libbin0 -> 462 bytes
-rw-r--r--test/pecoff/Inputs/entry.obj.yaml40
-rw-r--r--test/pecoff/Inputs/executable.obj.yaml29
-rw-r--r--test/pecoff/Inputs/executable.s17
-rw-r--r--test/pecoff/Inputs/export.obj.yaml69
-rw-r--r--test/pecoff/Inputs/exports.def6
-rw-r--r--test/pecoff/Inputs/exports2.def6
-rw-r--r--test/pecoff/Inputs/grouped-sections.asm18
-rw-r--r--test/pecoff/Inputs/grouped-sections.obj.yaml83
-rw-r--r--test/pecoff/Inputs/hello.asm24
-rw-r--r--test/pecoff/Inputs/hello.obj.yaml111
-rw-r--r--test/pecoff/Inputs/hello64.asm22
-rw-r--r--test/pecoff/Inputs/hello64.obj.yaml110
-rw-r--r--test/pecoff/Inputs/hello64lib.asm14
-rw-r--r--test/pecoff/Inputs/hello64lib.libbin0 -> 1938 bytes
-rw-r--r--test/pecoff/Inputs/imagebase.obj.yaml55
-rwxr-xr-xtest/pecoff/Inputs/library.libbin0 -> 1694 bytes
-rw-r--r--test/pecoff/Inputs/machine-type-unknown.obj.yaml38
-rw-r--r--test/pecoff/Inputs/main.obj.yaml70
-rw-r--r--test/pecoff/Inputs/merge-largest1.obj.yaml30
-rw-r--r--test/pecoff/Inputs/merge-largest2.obj.yaml30
-rw-r--r--test/pecoff/Inputs/merge-same-size1.obj.yaml30
-rw-r--r--test/pecoff/Inputs/merge-same-size2.obj.yaml30
-rw-r--r--test/pecoff/Inputs/merge-same-size3.obj.yaml30
-rw-r--r--test/pecoff/Inputs/nonstandard-sections.obj.yaml53
-rw-r--r--test/pecoff/Inputs/nop.asm9
-rw-r--r--test/pecoff/Inputs/nop.obj.yaml51
-rw-r--r--test/pecoff/Inputs/nop64.obj.yaml67
-rw-r--r--test/pecoff/Inputs/reloc.obj.yaml82
-rw-r--r--test/pecoff/Inputs/reloc64.obj.yaml63
-rw-r--r--test/pecoff/Inputs/resource.rc4
-rwxr-xr-xtest/pecoff/Inputs/resource.resbin0 -> 108 bytes
-rw-r--r--test/pecoff/Inputs/responsefile.txt1
-rw-r--r--test/pecoff/Inputs/secrel1.obj.yaml69
-rw-r--r--test/pecoff/Inputs/secrel2.obj.yaml47
-rw-r--r--test/pecoff/Inputs/seh.c13
-rw-r--r--test/pecoff/Inputs/seh.obj.yaml387
-rw-r--r--test/pecoff/Inputs/static-data1.obj.yaml67
-rw-r--r--test/pecoff/Inputs/static-data2.obj.yaml67
-rw-r--r--test/pecoff/Inputs/static.libbin0 -> 1120 bytes
-rw-r--r--test/pecoff/Inputs/subsystem.main.yaml35
-rw-r--r--test/pecoff/Inputs/subsystem.winmain.yaml35
-rw-r--r--test/pecoff/Inputs/tlsused.obj.yaml29
-rw-r--r--test/pecoff/Inputs/unknown-drectve.obj.yaml42
-rw-r--r--test/pecoff/Inputs/unwind.obj.yaml129
-rw-r--r--test/pecoff/Inputs/vars-main-x64.obj.yaml63
-rw-r--r--test/pecoff/Inputs/vars-main-x86.obj.yaml69
-rw-r--r--test/pecoff/Inputs/vars-main.c7
-rw-r--r--test/pecoff/Inputs/vars.c20
-rw-r--r--test/pecoff/Inputs/vars.dll.yaml19
-rw-r--r--test/pecoff/Inputs/vars.libbin0 -> 1994 bytes
-rw-r--r--test/pecoff/Inputs/vars64.libbin0 -> 2016 bytes
-rw-r--r--test/pecoff/Inputs/weak-externals.asm25
-rw-r--r--test/pecoff/Inputs/weak-externals.obj.yaml91
-rw-r--r--test/pecoff/alignment.test22
-rw-r--r--test/pecoff/alternatename.test44
-rw-r--r--test/pecoff/armnt-ImageBase.test14
-rw-r--r--test/pecoff/armnt-addr32-exec.test11
-rw-r--r--test/pecoff/armnt-addr32.test11
-rw-r--r--test/pecoff/armnt-address-of-entry-point.test6
-rw-r--r--test/pecoff/armnt-blx23t.test27
-rw-r--r--test/pecoff/armnt-branch24t.test20
-rw-r--r--test/pecoff/armnt-exports.s28
-rw-r--r--test/pecoff/armnt-exports.test10
-rw-r--r--test/pecoff/armnt-imports.test11
-rw-r--r--test/pecoff/armnt-mov32t-exec.test21
-rw-r--r--test/pecoff/armnt-movt32t.test17
-rw-r--r--test/pecoff/armnt.test6
-rw-r--r--test/pecoff/associative.test10
-rw-r--r--test/pecoff/base-reloc.test78
-rw-r--r--test/pecoff/baseaddr.test18
-rw-r--r--test/pecoff/bss-section.test21
-rw-r--r--test/pecoff/comdat.test12
-rw-r--r--test/pecoff/common-symbol.test14
-rw-r--r--test/pecoff/conflicting-machine.test6
-rw-r--r--test/pecoff/delayimport.test54
-rw-r--r--test/pecoff/dll.test7
-rw-r--r--test/pecoff/dosstub.test11
-rw-r--r--test/pecoff/drectve.test39
-rw-r--r--test/pecoff/dynamic.test11
-rw-r--r--test/pecoff/dynamicbase.test24
-rw-r--r--test/pecoff/entry.test41
-rw-r--r--test/pecoff/export-warning.test19
-rw-r--r--test/pecoff/export.test90
-rw-r--r--test/pecoff/exportlib.test32
-rw-r--r--test/pecoff/exportlib2.test21
-rw-r--r--test/pecoff/grouped-sections.test17
-rw-r--r--test/pecoff/hello.test51
-rw-r--r--test/pecoff/hello64.test22
-rw-r--r--test/pecoff/help.test4
-rw-r--r--test/pecoff/imagebase.test15
-rw-r--r--test/pecoff/importlib.test55
-rw-r--r--test/pecoff/include.test8
-rw-r--r--test/pecoff/lib.test15
-rw-r--r--test/pecoff/libarg.test9
-rw-r--r--test/pecoff/localyimported.test15
-rw-r--r--test/pecoff/long-section-name.test7
-rw-r--r--test/pecoff/machinetype.test13
-rw-r--r--test/pecoff/manifest.test63
-rw-r--r--test/pecoff/merge-largest.test24
-rw-r--r--test/pecoff/merge-same-size.test32
-rw-r--r--test/pecoff/multi.test17
-rw-r--r--test/pecoff/noentry.test10
-rw-r--r--test/pecoff/nonstandard-sections.test75
-rw-r--r--test/pecoff/options.test40
-rw-r--r--test/pecoff/pe32plus.test87
-rw-r--r--test/pecoff/reloc.test16
-rw-r--r--test/pecoff/reloc64.test20
-rw-r--r--test/pecoff/resource.test16
-rw-r--r--test/pecoff/responsefile.test7
-rw-r--r--test/pecoff/safeseh.test9
-rw-r--r--test/pecoff/secrel.test16
-rw-r--r--test/pecoff/section-attribute.test45
-rw-r--r--test/pecoff/section-renaming.test61
-rw-r--r--test/pecoff/seh.test31
-rw-r--r--test/pecoff/seh64.test57
-rw-r--r--test/pecoff/subsystem.test12
-rw-r--r--test/pecoff/tls.test14
-rw-r--r--test/pecoff/trivial.test103
-rw-r--r--test/pecoff/unknown-drectve.test6
-rw-r--r--test/pecoff/weak-external.test9
-rw-r--r--tools/CMakeLists.txt2
-rw-r--r--tools/Makefile17
-rw-r--r--tools/linker-script-test/CMakeLists.txt8
-rw-r--r--tools/linker-script-test/Makefile24
-rw-r--r--tools/linker-script-test/linker-script-test.cpp57
-rw-r--r--tools/lld/CMakeLists.txt25
-rw-r--r--tools/lld/Makefile30
-rw-r--r--tools/lld/TODO.txt2
-rw-r--r--tools/lld/lld.cpp36
-rw-r--r--unittests/CMakeLists.txt15
-rw-r--r--unittests/CoreTests/CMakeLists.txt4
-rw-r--r--unittests/CoreTests/Makefile14
-rw-r--r--unittests/CoreTests/ParallelTest.cpp31
-rw-r--r--unittests/CoreTests/RangeTest.cpp240
-rw-r--r--unittests/DriverTests/CMakeLists.txt14
-rw-r--r--unittests/DriverTests/DarwinLdDriverTest.cpp240
-rw-r--r--unittests/DriverTests/DriverTest.h61
-rw-r--r--unittests/DriverTests/GnuLdDriverTest.cpp284
-rw-r--r--unittests/DriverTests/Makefile20
-rw-r--r--unittests/DriverTests/UniversalDriverTest.cpp33
-rw-r--r--unittests/DriverTests/WinLinkDriverTest.cpp728
-rw-r--r--unittests/DriverTests/WinLinkModuleDefTest.cpp155
-rw-r--r--unittests/MachOTests/CMakeLists.txt13
-rw-r--r--unittests/MachOTests/MachONormalizedFileBinaryReaderTests.cpp748
-rw-r--r--unittests/MachOTests/MachONormalizedFileBinaryWriterTests.cpp693
-rw-r--r--unittests/MachOTests/MachONormalizedFileToAtomsTests.cpp94
-rw-r--r--unittests/MachOTests/MachONormalizedFileYAMLTests.cpp766
-rw-r--r--unittests/MachOTests/empty_obj_x86_armv7.txt1272
-rw-r--r--unittests/Makefile31
-rw-r--r--utils/astyle-options7
1131 files changed, 106976 insertions, 0 deletions
diff --git a/.arcconfig b/.arcconfig
new file mode 100644
index 000000000000..787b339a9f20
--- /dev/null
+++ b/.arcconfig
@@ -0,0 +1,4 @@
+{
+ "project_id" : "lld",
+ "conduit_uri" : "http://reviews.llvm.org/"
+}
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 000000000000..9b3aa8b7213b
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1 @@
+BasedOnStyle: LLVM
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 000000000000..0a288ee8ce96
--- /dev/null
+++ b/.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/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 000000000000..30ef47a692d2
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,98 @@
+set(LLD_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
+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/Config/Version.inc.in
+ ${CMAKE_CURRENT_BINARY_DIR}/include/lld/Config/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")
+
+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()
+
+
+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(lib)
+add_subdirectory(tools)
+
+add_subdirectory(test)
+
+if (LLVM_INCLUDE_TESTS)
+ add_subdirectory(unittests)
+endif()
+
+add_subdirectory(docs)
diff --git a/LICENSE.TXT b/LICENSE.TXT
new file mode 100644
index 000000000000..bcb83b211422
--- /dev/null
+++ b/LICENSE.TXT
@@ -0,0 +1,62 @@
+==============================================================================
+lld License
+==============================================================================
+University of Illinois/NCSA
+Open Source License
+
+Copyright (c) 2011-2015 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/Makefile b/Makefile
new file mode 100644
index 000000000000..e1b6a678fc23
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,86 @@
+##===- Makefile --------------------------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+# If LLD_LEVEL is not set, then we are the top-level Makefile. Otherwise, we
+# are being included from a subdirectory makefile.
+
+ifndef LLD_LEVEL
+
+IS_TOP_LEVEL := 1
+LLD_LEVEL := .
+DIRS := include lib tools unittests
+
+PARALLEL_DIRS :=
+
+endif
+
+ifeq ($(MAKECMDGOALS),libs-only)
+ DIRS := $(filter-out tools docs, $(DIRS))
+ OPTIONAL_DIRS :=
+endif
+ifeq ($(BUILD_LLD_ONLY),YES)
+ DIRS := $(filter-out docs unittests, $(DIRS))
+ OPTIONAL_DIRS :=
+endif
+
+###
+# Common Makefile code, shared by all lld Makefiles.
+
+# Set LLVM source root level.
+LEVEL := $(LLD_LEVEL)/../..
+
+# Include LLVM common makefile.
+include $(LEVEL)/Makefile.common
+
+ifneq ($(ENABLE_DOCS),1)
+ DIRS := $(filter-out docs, $(DIRS))
+endif
+
+CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/include
+CPP.Flags += -I$(PROJ_OBJ_DIR)/$(LLD_LEVEL)/include
+
+###
+# lld Top Level specific stuff.
+
+ifeq ($(IS_TOP_LEVEL),1)
+
+ifneq ($(PROJ_SRC_ROOT),$(PROJ_OBJ_ROOT))
+$(RecursiveTargets)::
+ $(Verb) for dir in test unittests; do \
+ if [ -f $(PROJ_SRC_DIR)/$${dir}/Makefile ] && [ ! -f $${dir}/Makefile ]; then \
+ $(MKDIR) $${dir}; \
+ $(CP) $(PROJ_SRC_DIR)/$${dir}/Makefile $${dir}/Makefile; \
+ fi \
+ done
+endif
+
+test::
+ @ $(MAKE) -C test
+
+report::
+ @ $(MAKE) -C test report
+
+clean::
+ @ $(MAKE) -C test clean
+
+libs-only: all
+
+tags::
+ $(Verb) etags `find . -type f -name '*.h' -or -name '*.cpp' | \
+ grep -v /lib/Headers | grep -v /test/`
+
+cscope.files:
+ find tools lib include -name '*.cpp' \
+ -or -name '*.def' \
+ -or -name '*.td' \
+ -or -name '*.h' > cscope.files
+
+.PHONY: test report clean cscope.files
+
+endif
diff --git a/README.md b/README.md
new file mode 100644
index 000000000000..dc05cdea0a12
--- /dev/null
+++ b/README.md
@@ -0,0 +1,10 @@
+
+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.
diff --git a/cmake/modules/FindVTune.cmake b/cmake/modules/FindVTune.cmake
new file mode 100644
index 000000000000..bd0cbe9a38cb
--- /dev/null
+++ b/cmake/modules/FindVTune.cmake
@@ -0,0 +1,31 @@
+# - Find VTune ittnotify.
+# Defines:
+# VTune_FOUND
+# VTune_INCLUDE_DIRS
+# VTune_LIBRARIES
+
+set(dirs
+ "$ENV{VTUNE_AMPLIFIER_XE_2013_DIR}/"
+ "C:/Program Files (x86)/Intel/VTune Amplifier XE 2013/"
+ "$ENV{VTUNE_AMPLIFIER_XE_2011_DIR}/"
+ "C:/Program Files (x86)/Intel/VTune Amplifier XE 2011/"
+ )
+
+find_path(VTune_INCLUDE_DIRS ittnotify.h
+ PATHS ${dirs}
+ PATH_SUFFIXES include)
+
+if (CMAKE_SIZEOF_VOID_P MATCHES "8")
+ set(vtune_lib_dir lib64)
+else()
+ set(vtune_lib_dir lib32)
+endif()
+
+find_library(VTune_LIBRARIES libittnotify
+ HINTS "${VTune_INCLUDE_DIRS}/.."
+ PATHS ${dirs}
+ PATH_SUFFIXES ${vtune_lib_dir})
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(
+ VTune DEFAULT_MSG VTune_LIBRARIES VTune_INCLUDE_DIRS)
diff --git a/docs/C++11.rst b/docs/C++11.rst
new file mode 100644
index 000000000000..0c4391e7b037
--- /dev/null
+++ b/docs/C++11.rst
@@ -0,0 +1,9 @@
+C++11
+=====
+
+Originally, LLD was developed in C++11 unlike the rest of LLVM. Now, all of
+LLVM, LLD, and Clang are developed using C++11. See the `LLVM Coding
+Standards`_ for details on the precise subset of C++11 supported by the various
+host compilers.
+
+.. _LLVM Coding Standards: http://llvm.org/docs/CodingStandards.html
diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt
new file mode 100644
index 000000000000..d4f3b058efb7
--- /dev/null
+++ b/docs/CMakeLists.txt
@@ -0,0 +1,8 @@
+if (LLVM_ENABLE_SPHINX)
+ if (SPHINX_FOUND)
+ include(AddSphinxTarget)
+ if (${SPHINX_OUTPUT_HTML})
+ add_sphinx_target(html lld)
+ endif()
+ endif()
+endif()
diff --git a/docs/Driver.rst b/docs/Driver.rst
new file mode 100644
index 000000000000..5f2d946d36bd
--- /dev/null
+++ b/docs/Driver.rst
@@ -0,0 +1,79 @@
+======
+Driver
+======
+
+.. 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/Driver/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 :option:`-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/docs/Makefile b/docs/Makefile
new file mode 100644
index 000000000000..4c147eb11137
--- /dev/null
+++ b/docs/Makefile
@@ -0,0 +1,155 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+SPHINXBUILD = sphinx-build
+PAPER =
+BUILDDIR = _build
+
+# Internal variables.
+PAPEROPT_a4 = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+# the i18n builder cannot share the environment and doctrees with the others
+I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
+
+all: html
+
+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 " latexpdf to make LaTeX files and run them through pdflatex"
+ @echo " text to make text files"
+ @echo " man to make manual pages"
+ @echo " texinfo to make Texinfo files"
+ @echo " info to make Texinfo files and run them through makeinfo"
+ @echo " gettext to make PO message catalogs"
+ @echo " changes to make an overview of 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)"
+
+clean:
+ -rm -rf $(BUILDDIR)/*
+
+html:
+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+ $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+ $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+ @echo
+ @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+ @echo
+ @echo "Build finished; now you can process the pickle files."
+
+json:
+ $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+ @echo
+ @echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+ @echo
+ @echo "Build finished; now you can run HTML Help Workshop with the" \
+ ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+ $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+ @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.qhc"
+
+devhelp:
+ $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+ @echo
+ @echo "Build finished."
+ @echo "To view the help file:"
+ @echo "# mkdir -p $$HOME/.local/share/devhelp/lld"
+ @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/lld"
+ @echo "# devhelp"
+
+epub:
+ $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+ @echo
+ @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo
+ @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+ @echo "Run \`make' in that directory to run these through (pdf)latex" \
+ "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo "Running LaTeX files through pdflatex..."
+ $(MAKE) -C $(BUILDDIR)/latex all-pdf
+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+ $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+ @echo
+ @echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+ $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+ @echo
+ @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+texinfo:
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+ @echo
+ @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
+ @echo "Run \`make' in that directory to run these through makeinfo" \
+ "(use \`make info' here to do that automatically)."
+
+info:
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+ @echo "Running Texinfo files through makeinfo..."
+ make -C $(BUILDDIR)/texinfo info
+ @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
+
+gettext:
+ $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
+ @echo
+ @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
+
+changes:
+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+ @echo
+ @echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+ @echo
+ @echo "Link check complete; look for any errors in the above output " \
+ "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+ $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+ @echo "Testing of doctests in the sources finished, look at the " \
+ "results in $(BUILDDIR)/doctest/output.txt."
diff --git a/docs/README.txt b/docs/README.txt
new file mode 100644
index 000000000000..eb09a2d2b7ea
--- /dev/null
+++ b/docs/README.txt
@@ -0,0 +1,12 @@
+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.
+
+To rebuild documents into html:
+
+ [/lld/docs]> make html
+
diff --git a/docs/Readers.rst b/docs/Readers.rst
new file mode 100644
index 000000000000..e00406b8c4ce
--- /dev/null
+++ b/docs/Readers.rst
@@ -0,0 +1,172 @@
+.. _Readers:
+
+Developing lld Readers
+======================
+
+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 Atom graph format
+(both binary ``Native`` and ``YAML`` representations). 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 method 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/docs/_static/favicon.ico b/docs/_static/favicon.ico
new file mode 100644
index 000000000000..724ad6e12dd4
--- /dev/null
+++ b/docs/_static/favicon.ico
Binary files differ
diff --git a/docs/_templates/indexsidebar.html b/docs/_templates/indexsidebar.html
new file mode 100644
index 000000000000..61968f22d5c5
--- /dev/null
+++ b/docs/_templates/indexsidebar.html
@@ -0,0 +1,4 @@
+<h3>Bugs</h3>
+
+<p>lld bugs should be reported at the
+ LLVM <a href="http://llvm.org/bugs">Bugzilla</a>.</p>
diff --git a/docs/_templates/layout.html b/docs/_templates/layout.html
new file mode 100644
index 000000000000..519a24bce63a
--- /dev/null
+++ b/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/docs/conf.py b/docs/conf.py
new file mode 100644
index 000000000000..99866e1bd1e1
--- /dev/null
+++ b/docs/conf.py
@@ -0,0 +1,254 @@
+# -*- 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
+
+# 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-2014, LLVM Project'
+
+# 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 X.Y version.
+version = '3.2'
+# The full version, including alpha/beta/rc tags.
+release = '3.2'
+
+# 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/docs/design.rst b/docs/design.rst
new file mode 100644
index 000000000000..06d356527f58
--- /dev/null
+++ b/docs/design.rst
@@ -0,0 +1,500 @@
+.. _design:
+
+Linker Design
+=============
+
+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.
+
+ELF Section Groups
+~~~~~~~~~~~~~~~~~~
+Reference : `ELF Section Groups <http://mentorembedded.github.io/cxx-abi/abi/prop-72-comdat.html>`_
+
+C++ has many situations where the compiler may need to emit code or data,
+but may not be able to identify a unique compilation unit where it should be
+emitted. The approach chosen by the C++ ABI group to deal with this problem, is
+to allow the compiler to emit the required information in multiple compilation
+units, in a form which allows the linker to remove all but one copy. This is
+essentially the feature called COMDAT in several existing implementations.
+
+The COMDAT sections in ELF are modeled by using '.group' sections in the input
+files. Each '.group' section is associated with a signature. The '.group'
+section has a list of members that are part of the the '.group' which the linker
+selects to appear in the input file(Whichever .group section appeared first
+in the link). References to any of the '.group' members can also appear from
+outside the '.group'.
+
+In lld the the '.group' sections with COMDAT are identified by contentType(
+typeGroupComdat). The '.group' members are identified by using
+**kindGroupChild** references.
+
+The point to be noted here is the 'group child' members would need to be emitted
+in the output file **iff** the group was selected by the resolver.
+
+This is modeled in lld by removing the 'group child' members from the
+definedAtom List.
+
+Any reference to the group-child from **outside the group** is referenced using
+a 'undefined' atom.
+
+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 three
+representations of its File/Atom/Reference model:
+
+ * In memory, abstract C++ classes (lld::Atom, lld::Reference, and lld::File).
+
+ * textual (in YAML)
+
+ * binary format ("native")
+
+Binary File Format
+~~~~~~~~~~~~~~~~~~
+
+In theory, lld::File objects could be written to disk in an existing Object File
+format standard (e.g. ELF). Instead we choose to define a new binary file
+format. There are two main reasons for this: fidelity and performance. In order
+for lld to work as a linker on all platforms, its internal model must be rich
+enough to model all CPU and OS linking features. But if we choose an existing
+Object File format as the lld binary format, that means an on going need to
+retrofit each platform specific feature needed from alternate platforms into the
+existing Object File format. Having our own "native" binary format side steps
+that issue. We still need to be able to binary encode all the features, but
+once the in-memory model can represent the feature, it is straight forward to
+binary encode it.
+
+The reason to use a binary file format at all, instead of a textual file format,
+is speed. You want the binary format to be as fast as possible to read into the
+in-memory model. Given that we control the in-memory model and the binary
+format, the obvious way to make reading super fast it to make the file format be
+basically just an array of atoms. The reader just mmaps in the file and looks
+at the header to see how many atoms there are and instantiate that many atom
+objects with the atom attribute information coming from that array. The trick
+is designing this in a way that can be extended as the Atom mode evolves and new
+attributes are added.
+
+The native object file format starts with a header that lists how many "chunks"
+are in the file. A chunk is an array of "ivar data". The native file reader
+instantiates an array of Atom objects (with one large malloc call). Each atom
+contains just a pointer to its vtable and a pointer to its ivar data. All
+methods on lld::Atom are virtual, so all the method implementations return
+values based on the ivar data to which it has a pointer. If a new linking
+features is added which requires a change to the lld::Atom model, a new native
+reader class (e.g. version 2) is defined which knows how to read the new feature
+information from the new ivar data. The old reader class (e.g. version 1) is
+updated to do its best to model (the lack of the new feature) given the old ivar
+data in existing native object files.
+
+With this model for the native file format, files can be read and turned
+into the in-memory graph of lld::Atoms with just a few memory allocations.
+And the format can easily adapt over time to new features.
+
+The binary file format follows the ReaderWriter patterns used in lld. The lld
+library comes with the classes: ReaderNative and WriterNative. So, switching
+between file formats is as easy as switching which Reader subclass is used.
+
+
+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. The output of the resolver is written as a native object file.
+It is then read back in using the native object file reader and then pass to the
+YAML writer. This round-about path means that all three representations
+(in-memory, binary, and text) are exercised, and any new feature has to work in
+all the representations to pass the test.
+
+
+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/docs/development.rst b/docs/development.rst
new file mode 100644
index 000000000000..918e1778b801
--- /dev/null
+++ b/docs/development.rst
@@ -0,0 +1,48 @@
+.. _development:
+
+Development
+===========
+
+lld is developed as part of the `LLVM <http://llvm.org>`_ project.
+
+Using C++11 in lld
+------------------
+
+:doc:`C++11`.
+
+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:
+
+ C++11
+ Readers
+ Driver
diff --git a/docs/getting_started.rst b/docs/getting_started.rst
new file mode 100644
index 000000000000..986a406c1cb7
--- /dev/null
+++ b/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 lld-test
+
+Using Visual Studio
+~~~~~~~~~~~~~~~~~~~
+
+#. Get the required tools.
+
+ * `CMake 2.8`_\+.
+ * `Visual Studio 11 (2012) 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 11 (2012) 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/docs/hello.png b/docs/hello.png
new file mode 100644
index 000000000000..70df111f1abd
--- /dev/null
+++ b/docs/hello.png
Binary files differ
diff --git a/docs/index.rst b/docs/index.rst
new file mode 100644
index 000000000000..7a87ad8d0583
--- /dev/null
+++ b/docs/index.rst
@@ -0,0 +1,88 @@
+.. _index:
+
+lld - The LLVM Linker
+=====================
+
+lld is a new set of modular code for creating linker tools.
+
+* End-User Features:
+
+ * Compatible with existing linker options
+ * Reads standard Object Files (e.g. ELF, Mach-O, PE/COFF)
+ * Writes standard Executable Files (e.g. ELF, Mach-O, PE)
+ * Fast link times
+ * Minimal memory use
+ * 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
+ * Internal linker model can be dumped/read to a new native format
+ * Native format designed to be fast to read and write
+ * 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.
+
+
+Current Status
+--------------
+
+lld can self host on x86-64 FreeBSD and Linux and x86 Windows.
+
+All SingleSource tests in test-suite pass on x86-64 Linux.
+
+All SingleSource and MultiSource tests in the LLVM test-suite
+pass on MIPS 32-bit little-endian Linux.
+
+Source
+------
+
+lld is available in the LLVM SVN repository::
+
+ svn co http://llvm.org/svn/llvm-project/lld/trunk lld
+
+lld is also available via the read-only git mirror::
+
+ git clone http://llvm.org/git/lld.git
+
+Put it in llvm's tools/ directory, rerun cmake, then build target lld.
+
+Contents
+--------
+
+.. toctree::
+ :maxdepth: 2
+
+ design
+ getting_started
+ development
+ windows_support
+ open_projects
+ sphinx_intro
+
+Indices and tables
+------------------
+
+* :ref:`genindex`
+* :ref:`search`
+
+__ http://llvm.org/docs/DeveloperPolicy.html#license
diff --git a/docs/llvm-theme/layout.html b/docs/llvm-theme/layout.html
new file mode 100644
index 000000000000..0cd0918eac2a
--- /dev/null
+++ b/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/docs/llvm-theme/static/contents.png b/docs/llvm-theme/static/contents.png
new file mode 100644
index 000000000000..7fb82154a174
--- /dev/null
+++ b/docs/llvm-theme/static/contents.png
Binary files differ
diff --git a/docs/llvm-theme/static/llvm.css b/docs/llvm-theme/static/llvm.css
new file mode 100644
index 000000000000..32802bb6a2d0
--- /dev/null
+++ b/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/docs/llvm-theme/static/logo.png b/docs/llvm-theme/static/logo.png
new file mode 100644
index 000000000000..4fc899028dc6
--- /dev/null
+++ b/docs/llvm-theme/static/logo.png
Binary files differ
diff --git a/docs/llvm-theme/static/navigation.png b/docs/llvm-theme/static/navigation.png
new file mode 100644
index 000000000000..1081dc1439fb
--- /dev/null
+++ b/docs/llvm-theme/static/navigation.png
Binary files differ
diff --git a/docs/llvm-theme/theme.conf b/docs/llvm-theme/theme.conf
new file mode 100644
index 000000000000..330fc92ffa18
--- /dev/null
+++ b/docs/llvm-theme/theme.conf
@@ -0,0 +1,4 @@
+[theme]
+inherit = basic
+stylesheet = llvm.css
+pygments_style = friendly
diff --git a/docs/make.bat b/docs/make.bat
new file mode 100644
index 000000000000..8471252d709f
--- /dev/null
+++ b/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/docs/open_projects.rst b/docs/open_projects.rst
new file mode 100644
index 000000000000..eb146c8b7542
--- /dev/null
+++ b/docs/open_projects.rst
@@ -0,0 +1,17 @@
+.. _open_projects:
+
+Open Projects
+=============
+
+.. include:: ../include/lld/Core/TODO.txt
+.. include:: ../lib/Core/TODO.txt
+.. include:: ../lib/Driver/TODO.rst
+.. include:: ../lib/ReaderWriter/ELF/X86_64/TODO.rst
+.. include:: ../lib/ReaderWriter/ELF/AArch64/TODO.rst
+.. include:: ../lib/ReaderWriter/ELF/ARM/TODO.rst
+.. include:: ../tools/lld/TODO.txt
+
+Documentation TODOs
+~~~~~~~~~~~~~~~~~~~
+
+.. todolist::
diff --git a/docs/sphinx_intro.rst b/docs/sphinx_intro.rst
new file mode 100644
index 000000000000..6845bc812e78
--- /dev/null
+++ b/docs/sphinx_intro.rst
@@ -0,0 +1,147 @@
+.. _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, all you should need to do is change to the
+``docs`` directory and invoke make as follows::
+
+ $ cd path/to/project/docs
+ $ make html
+
+Note that on Windows there is a ``make.bat`` command in the docs directory which
+supplies the same interface as the ``Makefile``.
+
+That command will invoke ``sphinx-build`` with the appropriate options for the
+project, and generate the HTML documentation in a ``_build`` subdirectory. You
+can browse it starting from the index page by visiting
+``_build/html/index.html``.
+
+Sphinx supports a wide variety of generation formats (including LaTeX, man
+pages, and plain text). The ``Makefile`` includes a number of convenience
+targets for invoking ``sphinx-build`` appropriately, the common ones are:
+
+ make html
+ Generate the HTML output.
+
+ make latexpdf
+ Generate LaTeX documentation and convert to a PDF.
+
+ make man
+ Generate man pages.
+
+
+.. _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/docs/windows_support.rst b/docs/windows_support.rst
new file mode 100644
index 000000000000..d9906a72ea1e
--- /dev/null
+++ b/docs/windows_support.rst
@@ -0,0 +1,118 @@
+.. 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 has some experimental Windows support. When invoked as ``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 can link itself on Windows x86 using Visual C++
+2012 or 2013 as the compiler.
+
+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.
+ Options for Windows 8 app store are not recognized too
+ (e.g. ``/APPCONTAINER``).
+
+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. LLD uses Microsoft ``lib.exe`` tool to create an import library
+ file.
+
+Windows resource files support
+ :good:`Done`. If an ``.rc`` file is given, LLD converts the file to a COFF
+ file using some external commands and link it. Specifically, ``rc.exe`` is
+ used to compile a resource file (.rc) to a compiled resource (.res)
+ file. ``rescvt.exe`` is then used to convert a compiled resource file to a
+ COFF object file section. Both tools are shipped with MSVC.
+
+Safe Structured Exception Handler (SEH)
+ :good:`Done` for x86. :partial:`Work in progress` for x64.
+
+Module-definition file
+ :partial:`Partially done`. LLD currently recognizes these directives:
+ ``EXPORTS``, ``HEAPSIZE``, ``STACKSIZE``, ``NAME``, and ``VERSION``.
+
+x64 (x86-64)
+ :partial:`Work in progress`. LLD can create PE32+ executable but the generated
+ file does not work unless source object files are very simple because of the
+ lack of SEH handler table.
+
+Debug info
+ :none:`No progress has been made`. Microsoft linker can interpret the CodeGen
+ debug info (old-style debug info) and PDB to emit an .pdb file. LLD doesn't
+ support neither.
+
+
+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``
+
+Known issues
+============
+
+Note that LLD is still in early stage in development, so there are still many
+bugs. Here is a list of notable bugs.
+
+* Symbol name resolution from library files sometimes fails. On Windows, the
+ order of library files in command line does not matter, but LLD sometimes
+ fails to simulate the semantics. A workaround for it is to explicitly add
+ library files to command line with ``/DEFAULTLIB``.
+
+* Subsystem inference is not very reliable. Linker is supposed to set
+ ``subsystem`` field in the PE/COFF header according to entry function name,
+ but LLD sometimes ended up with ``unknown`` subsystem type. You need to give
+ ``/SUBSYSTEM`` option if it fails to infer it.
diff --git a/include/Makefile b/include/Makefile
new file mode 100644
index 000000000000..d8903356d9fb
--- /dev/null
+++ b/include/Makefile
@@ -0,0 +1,4 @@
+LLD_LEVEL := ..
+DIRS := lld
+
+include $(LLD_LEVEL)/Makefile
diff --git a/include/lld/Config/Makefile b/include/lld/Config/Makefile
new file mode 100644
index 000000000000..e2139220e3df
--- /dev/null
+++ b/include/lld/Config/Makefile
@@ -0,0 +1,32 @@
+LLD_LEVEL := ../../..
+
+BUILT_SOURCES = Version.inc
+
+TABLEGEN_INC_FILES_COMMON = 1
+
+include $(LLD_LEVEL)/Makefile
+
+# Compute the lld version from the LLVM version, unless specified explicitly.
+ifndef LLD_VERSION
+LLD_VERSION := $(subst svn,,$(LLVMVersion))
+LLD_VERSION := $(subst rc,,$(LLD_VERSION))
+endif
+
+LLD_VERSION_COMPONENTS := $(subst ., ,$(LLD_VERSION))
+LLD_VERSION_MAJOR := $(word 1,$(LLD_VERSION_COMPONENTS))
+LLD_VERSION_MINOR := $(word 2,$(LLD_VERSION_COMPONENTS))
+
+LLD_REVISION := $(strip \
+ $(shell $(LLVM_SRC_ROOT)/utils/GetSourceVersion $(LLVM_SRC_ROOT)/tools/lld))
+
+LLD_REPOSITORY := $(strip \
+ $(shell $(LLVM_SRC_ROOT)/utils/GetRepositoryPath $(LLVM_SRC_ROOT)/tools/lld))
+
+$(ObjDir)/Version.inc.tmp : Version.inc.in Makefile $(LLVM_OBJ_ROOT)/Makefile.config $(ObjDir)/.dir
+ $(Echo) "Updating LLD version info."
+ $(Verb)sed -e "s#@LLD_VERSION@#$(LLD_VERSION)#g" \
+ -e "s#@LLD_VERSION_MAJOR@#$(LLD_VERSION_MAJOR)#g" \
+ -e "s#@LLD_VERSION_MINOR@#$(LLD_VERSION_MINOR)#g" \
+ -e "s#@LLD_REVISION@#$(LLD_REVISION)#g" \
+ -e "s#@LLD_REPOSITORY@#$(LLD_REPOSITORY)#g" \
+ $< > $@
diff --git a/include/lld/Config/Version.h b/include/lld/Config/Version.h
new file mode 100644
index 000000000000..41433c1175ef
--- /dev/null
+++ b/include/lld/Config/Version.h
@@ -0,0 +1,51 @@
+//===- lld/Config/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.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Defines version macros and version-related utility functions
+/// for lld.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_VERSION_H
+#define LLD_VERSION_H
+
+#include "lld/Config/Version.inc"
+#include "llvm/ADT/StringRef.h"
+#include <string>
+
+/// \brief Helper macro for LLD_VERSION_STRING.
+#define LLD_MAKE_VERSION_STRING2(X) #X
+
+/// \brief Helper macro for LLD_VERSION_STRING.
+#define LLD_MAKE_VERSION_STRING(X, Y) LLD_MAKE_VERSION_STRING2(X.Y)
+
+/// \brief A string that describes the lld version number, e.g., "1.0".
+#define LLD_VERSION_STRING \
+ LLD_MAKE_VERSION_STRING(LLD_VERSION_MAJOR, LLD_VERSION_MINOR)
+
+namespace lld {
+/// \brief Retrieves the repository path (e.g., Subversion path) that
+/// identifies the particular lld branch, tag, or trunk from which this
+/// lld was built.
+llvm::StringRef getLLDRepositoryPath();
+
+/// \brief Retrieves the repository revision number (or identifer) from which
+/// this lld was built.
+llvm::StringRef getLLDRevision();
+
+/// \brief Retrieves the full repository version that is an amalgamation of
+/// the information in getLLDRepositoryPath() and getLLDRevision().
+std::string getLLDRepositoryVersion();
+
+/// \brief Retrieves a string representing the complete lld version.
+llvm::StringRef getLLDVersion();
+}
+
+#endif // LLD_VERSION_H
diff --git a/include/lld/Config/Version.inc.in b/include/lld/Config/Version.inc.in
new file mode 100644
index 000000000000..c893a56686c0
--- /dev/null
+++ b/include/lld/Config/Version.inc.in
@@ -0,0 +1,5 @@
+#define LLD_VERSION @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/include/lld/Core/AbsoluteAtom.h b/include/lld/Core/AbsoluteAtom.h
new file mode 100644
index 000000000000..ed25297cea81
--- /dev/null
+++ b/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/include/lld/Core/Alias.h b/include/lld/Core/Alias.h
new file mode 100644
index 000000000000..610022525ecb
--- /dev/null
+++ b/include/lld/Core/Alias.h
@@ -0,0 +1,102 @@
+//===- lld/Core/Alias.h - Alias atoms -------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Provide alias atoms.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_ALIAS_H
+#define LLD_CORE_ALIAS_H
+
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Simple.h"
+#include "llvm/ADT/Optional.h"
+#include <string>
+
+namespace lld {
+
+// An AliasAtom is a zero-size atom representing an alias for other atom. It has
+// a LayoutAfter reference to the target atom, so that this atom and the target
+// atom will be laid out at the same location in the final result. Initially
+// the target atom is an undefined atom. Resolver will replace it with a defined
+// one.
+//
+// It does not have attributes itself. Most member function calls are forwarded
+// to the target atom.
+class AliasAtom : public SimpleDefinedAtom {
+public:
+ AliasAtom(const File &file, StringRef name)
+ : SimpleDefinedAtom(file), _target(nullptr), _name(name),
+ _merge(DefinedAtom::mergeNo), _deadStrip(DefinedAtom::deadStripNormal) {
+ }
+
+ StringRef name() const override { return _name; }
+ uint64_t size() const override { return 0; }
+ ArrayRef<uint8_t> rawContent() const override { return ArrayRef<uint8_t>(); }
+
+ Scope scope() const override {
+ getTarget();
+ return _target ? _target->scope() : scopeLinkageUnit;
+ }
+
+ Merge merge() const override {
+ if (_merge.hasValue())
+ return _merge.getValue();
+ getTarget();
+ return _target ? _target->merge() : mergeNo;
+ }
+
+ void setMerge(Merge val) { _merge = val; }
+
+ ContentType contentType() const override {
+ getTarget();
+ return _target ? _target->contentType() : typeUnknown;
+ }
+
+ Interposable interposable() const override {
+ getTarget();
+ return _target ? _target->interposable() : interposeNo;
+ }
+
+ SectionChoice sectionChoice() const override {
+ getTarget();
+ return _target ? _target->sectionChoice() : sectionBasedOnContent;
+ }
+
+ StringRef customSectionName() const override {
+ getTarget();
+ return _target ? _target->customSectionName() : StringRef("");
+ }
+
+ DeadStripKind deadStrip() const override { return _deadStrip; }
+ void setDeadStrip(DeadStripKind val) { _deadStrip = val; }
+
+private:
+ void getTarget() const {
+ if (_target)
+ return;
+ for (const Reference *r : *this) {
+ if (r->kindNamespace() == lld::Reference::KindNamespace::all &&
+ r->kindValue() == lld::Reference::kindLayoutAfter) {
+ _target = dyn_cast<DefinedAtom>(r->target());
+ return;
+ }
+ }
+ }
+
+ mutable const DefinedAtom *_target;
+ std::string _name;
+ llvm::Optional<Merge> _merge;
+ DeadStripKind _deadStrip;
+};
+
+} // end namespace lld
+
+#endif
diff --git a/include/lld/Core/ArchiveLibraryFile.h b/include/lld/Core/ArchiveLibraryFile.h
new file mode 100644
index 000000000000..ff379d4f3ecf
--- /dev/null
+++ b/include/lld/Core/ArchiveLibraryFile.h
@@ -0,0 +1,60 @@
+//===- 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 "lld/Core/Parallel.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, bool dataSymbolOnly) = 0;
+
+ virtual std::error_code
+ parseAllMembers(std::vector<std::unique_ptr<File>> &result) = 0;
+
+ // Parses a member file containing a given symbol, so that when you
+ // need the file find() can return that immediately. Calling this function
+ // has no side effect other than pre-instantiating a file. Calling this
+ // function doesn't affect correctness.
+ virtual void preload(TaskGroup &group, StringRef symbolName) {}
+
+ /// Returns a set of all defined symbols in the archive, i.e. all
+ /// resolvable symbol using this file.
+ virtual std::set<StringRef> getDefinedSymbols() {
+ return std::set<StringRef>();
+ }
+
+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/include/lld/Core/Atom.h b/include/lld/Core/Atom.h
new file mode 100644
index 000000000000..27fdde022ba7
--- /dev/null
+++ b/include/lld/Core/Atom.h
@@ -0,0 +1,76 @@
+//===- Core/Atom.h - A node in linking graph ------------------------------===//
+//
+// 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/Core/LLVM.h"
+
+namespace lld {
+
+class File;
+
+///
+/// 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 {
+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() {}
+
+private:
+ Definition _definition;
+};
+
+} // namespace lld
+
+#endif // LLD_CORE_ATOM_H
diff --git a/include/lld/Core/DefinedAtom.h b/include/lld/Core/DefinedAtom.h
new file mode 100644
index 000000000000..86d880c659b4
--- /dev/null
+++ b/include/lld/Core/DefinedAtom.h
@@ -0,0 +1,368 @@
+//===- 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/Core/Atom.h"
+#include "lld/Core/LLVM.h"
+
+namespace lld {
+class File;
+class Reference;
+
+/// \brief 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
+ 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]
+ 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]
+ 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]
+ typeMachHeader, // atom representing mach_header [Darwin]
+ typeThreadZeroFill, // Uninitialized thread local data(TBSS) [ELF]
+ typeThreadData, // Initialized thread local data(TDATA) [ELF]
+ typeRONote, // Identifies readonly note sections [ELF]
+ typeRWNote, // Identifies readwrite note sections [ELF]
+ typeNoAlloc, // Identifies non allocatable sections [ELF]
+ typeGroupComdat, // Identifies a section group [ELF, COFF]
+ typeGnuLinkOnce, // Identifies a gnu.linkonce section [ELF]
+ };
+
+ // 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 {
+ /// \brief The linker may or may not export this atom dynamically depending
+ /// on the output type and other context of the link.
+ dynamicExportNormal,
+ /// \brief 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
+ codeMipsPIC, // PIC function in a PIC / non-PIC mixed file
+ codeMipsMicro, // microMIPS instruction encoding
+ codeMipsMicroPIC, // microMIPS instruction encoding + PIC
+ codeMips16, // MIPS-16 instruction encoding
+ codeARMThumb, // ARM Thumb instruction set
+ };
+
+ struct Alignment {
+ Alignment(int p2, int m = 0)
+ : powerOf2(p2)
+ , modulus(m) {}
+
+ uint16_t powerOf2;
+ uint16_t modulus;
+
+ bool operator==(const Alignment &rhs) const {
+ return (powerOf2 == rhs.powerOf2) && (modulus == rhs.modulus);
+ }
+ };
+
+ /// \brief 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.
+ ///
+ /// Note that this should not be confused with ordinals of exported symbols in
+ /// Windows DLLs. In Windows terminology, ordinals are symbols' export table
+ /// indices (small integers) which can be used instead of symbol names to
+ /// refer items in a DLL.
+ virtual uint64_t ordinal() const = 0;
+
+ /// \brief 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;
+
+ /// \brief 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; }
+
+ /// \brief 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;
+
+ /// \brief Whether the linker should use direct or indirect access to this
+ /// atom.
+ virtual Interposable interposable() const = 0;
+
+ /// \brief how the linker should handle if multiple atoms have the same name.
+ virtual Merge merge() const = 0;
+
+ /// \brief The type of this atom, such as code or data.
+ virtual ContentType contentType() const = 0;
+
+ /// \brief 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;
+
+ /// \brief 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;
+
+ /// \brief If sectionChoice() != sectionBasedOnContent, then this return the
+ /// name of the section the atom should be placed into.
+ virtual StringRef customSectionName() const = 0;
+
+ /// \brief constraints on whether the linker may dead strip away this atom.
+ virtual DeadStripKind deadStrip() const = 0;
+
+ /// \brief Under which conditions should this atom be dynamically exported.
+ virtual DynamicExport dynamicExport() const {
+ return dynamicExportNormal;
+ }
+
+ /// \brief Code model used by the atom.
+ virtual CodeModel codeModel() const { return codeNA; }
+
+ /// \brief 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;
+
+ /// \brief 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;
+ }
+
+ reference_iterator &operator++() {
+ _atom.incrementIterator(_it);
+ return *this;
+ }
+ private:
+ const DefinedAtom &_atom;
+ const void *_it;
+ };
+
+ /// \brief Returns an iterator to the beginning of this Atom's References.
+ virtual reference_iterator begin() const = 0;
+
+ /// \brief Returns an iterator to the end of this Atom's References.
+ virtual reference_iterator end() const = 0;
+
+ 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 ||
+ atomContentType == DefinedAtom::typeThreadZeroFill);
+ }
+
+ /// Utility function to check if the atom belongs to a group section
+ /// that represents section groups or .gnu.linkonce sections.
+ bool isGroupParent() const {
+ ContentType atomContentType = contentType();
+ return (atomContentType == DefinedAtom::typeGroupComdat ||
+ atomContentType == DefinedAtom::typeGnuLinkOnce);
+ }
+
+ // Returns true if lhs should be placed before rhs in the final output.
+ static bool compareByPosition(const DefinedAtom *lhs,
+ const DefinedAtom *rhs);
+
+protected:
+ // DefinedAtom is an abstract base class. Only subclasses can access
+ // constructor.
+ DefinedAtom() : Atom(definitionRegular) { }
+
+ /// \brief Returns a pointer to the Reference object that the abstract
+ /// iterator "points" to.
+ virtual const Reference *derefIterator(const void *iter) const = 0;
+
+ /// \brief 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/include/lld/Core/Error.h b/include/lld/Core/Error.h
new file mode 100644
index 000000000000..7caa25018f40
--- /dev/null
+++ b/include/lld/Core/Error.h
@@ -0,0 +1,82 @@
+//===- 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/Core/LLVM.h"
+#include <system_error>
+
+namespace lld {
+
+const std::error_category &native_reader_category();
+
+enum class NativeReaderError {
+ success = 0,
+ unknown_file_format,
+ file_too_short,
+ file_malformed,
+ unknown_chunk_type,
+ memory_error,
+ conflicting_target_machine,
+};
+
+inline std::error_code make_error_code(NativeReaderError e) {
+ return std::error_code(static_cast<int>(e), native_reader_category());
+}
+
+const std::error_category &YamlReaderCategory();
+
+enum class YamlReaderError {
+ success = 0,
+ unknown_keyword,
+ illegal_value
+};
+
+inline std::error_code make_error_code(YamlReaderError e) {
+ return std::error_code(static_cast<int>(e), YamlReaderCategory());
+}
+
+const std::error_category &LinkerScriptReaderCategory();
+
+enum class LinkerScriptReaderError {
+ success = 0,
+ parse_error,
+ unknown_symbol_in_expr,
+ unrecognized_function_in_expr
+};
+
+inline std::error_code make_error_code(LinkerScriptReaderError e) {
+ return std::error_code(static_cast<int>(e), LinkerScriptReaderCategory());
+}
+
+/// 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);
+std::error_code make_dynamic_error_code(const Twine &msg);
+
+} // end namespace lld
+
+namespace std {
+template <>
+struct is_error_code_enum<lld::NativeReaderError> : std::true_type {};
+template <> struct is_error_code_enum<lld::YamlReaderError> : std::true_type {};
+template <>
+struct is_error_code_enum<lld::LinkerScriptReaderError> : std::true_type {};
+}
+
+#endif
diff --git a/include/lld/Core/File.h b/include/lld/Core/File.h
new file mode 100644
index 000000000000..25b177ec879c
--- /dev/null
+++ b/include/lld/Core/File.h
@@ -0,0 +1,324 @@
+//===- 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 "lld/Core/range.h"
+#include "llvm/ADT/Optional.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();
+
+ /// \brief Kinds of files that are supported.
+ enum Kind {
+ kindObject, ///< object file (.o)
+ kindSharedLibrary, ///< shared library (.so)
+ kindArchiveLibrary ///< archive (.a)
+ };
+
+ /// \brief 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; }
+
+ template <typename T> class atom_iterator; // forward reference
+
+ /// For allocating any objects owned by this File.
+ llvm::BumpPtrAllocator &allocator() const {
+ return _allocator;
+ }
+
+ /// \brief For use interating over DefinedAtoms in this File.
+ typedef atom_iterator<DefinedAtom> defined_iterator;
+
+ /// \brief For use interating over UndefinedAtoms in this File.
+ typedef atom_iterator<UndefinedAtom> undefined_iterator;
+
+ /// \brief For use interating over SharedLibraryAtoms in this File.
+ typedef atom_iterator<SharedLibraryAtom> shared_library_iterator;
+
+ /// \brief For use interating over AbsoluteAtoms in this File.
+ typedef atom_iterator<AbsoluteAtom> absolute_iterator;
+
+ /// \brief Different object file readers may instantiate and manage atoms with
+ /// different data structures. This class is a collection abstraction.
+ /// Each concrete File instance must implement these atom_collection
+ /// methods to enable clients to interate the File's atoms.
+ template <typename T>
+ class atom_collection {
+ public:
+ virtual ~atom_collection() { }
+ virtual atom_iterator<T> begin() const = 0;
+ virtual atom_iterator<T> end() const = 0;
+ virtual const T *deref(const void *it) const = 0;
+ virtual void next(const void *&it) const = 0;
+ virtual uint64_t size() const = 0;
+ bool empty() const { return size() == 0; }
+ };
+
+ /// \brief The class is the iterator type used to iterate through a File's
+ /// Atoms. This iterator delegates the work to the associated atom_collection
+ /// object. There are four kinds of Atoms, so this iterator is templated on
+ /// the four base Atom kinds.
+ template <typename T>
+ class atom_iterator : public std::iterator<std::forward_iterator_tag, T> {
+ public:
+ atom_iterator(const atom_collection<T> &c, const void *it)
+ : _collection(&c), _it(it) { }
+
+ const T *operator*() const {
+ return _collection->deref(_it);
+ }
+ const T *operator->() const {
+ return _collection->deref(_it);
+ }
+
+ friend bool operator==(const atom_iterator<T> &lhs, const atom_iterator<T> &rhs) {
+ return lhs._it == rhs._it;
+ }
+
+ friend bool operator!=(const atom_iterator<T> &lhs, const atom_iterator<T> &rhs) {
+ return !(lhs == rhs);
+ }
+
+ atom_iterator<T> &operator++() {
+ _collection->next(_it);
+ return *this;
+ }
+ private:
+ const atom_collection<T> *_collection;
+ const void *_it;
+ };
+
+ /// \brief Must be implemented to return the atom_collection object for
+ /// all DefinedAtoms in this File.
+ virtual const atom_collection<DefinedAtom> &defined() const = 0;
+
+ /// \brief Must be implemented to return the atom_collection object for
+ /// all UndefinedAtomw in this File.
+ virtual const atom_collection<UndefinedAtom> &undefined() const = 0;
+
+ /// \brief Must be implemented to return the atom_collection object for
+ /// all SharedLibraryAtoms in this File.
+ virtual const atom_collection<SharedLibraryAtom> &sharedLibrary() const = 0;
+
+ /// \brief Must be implemented to return the atom_collection object for
+ /// all AbsoluteAtoms in this File.
+ virtual const atom_collection<AbsoluteAtom> &absolute() const = 0;
+
+ /// \brief 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();
+
+ // This function is called just before the core linker tries to use
+ // a file. Currently the PECOFF reader uses this to trigger the
+ // driver to parse .drectve section (which contains command line options).
+ // If you want to do something having side effects, don't do that in
+ // doParse() because a file could be pre-loaded speculatively.
+ // Use this hook instead.
+ virtual void beforeLink() {}
+
+ // 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:
+ /// \brief only subclasses of File can be instantiated
+ File(StringRef p, Kind kind)
+ : _path(p), _kind(kind), _ordinal(UINT64_MAX) {}
+
+ /// \brief 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(); }
+
+ /// \brief This is a convenience class for File subclasses which manage their
+ /// atoms as a simple std::vector<>.
+ template <typename T>
+ class atom_collection_vector : public atom_collection<T> {
+ public:
+ atom_iterator<T> begin() const override {
+ auto *it = _atoms.empty() ? nullptr
+ : reinterpret_cast<const void *>(_atoms.data());
+ return atom_iterator<T>(*this, it);
+ }
+
+ atom_iterator<T> end() const override {
+ auto *it = _atoms.empty() ? nullptr : reinterpret_cast<const void *>(
+ _atoms.data() + _atoms.size());
+ return atom_iterator<T>(*this, it);
+ }
+
+ const T *deref(const void *it) const override {
+ return *reinterpret_cast<const T *const *>(it);
+ }
+
+ void next(const void *&it) const override {
+ const T *const *p = reinterpret_cast<const T *const *>(it);
+ ++p;
+ it = reinterpret_cast<const void*>(p);
+ }
+
+ uint64_t size() const override { return _atoms.size(); }
+
+ std::vector<const T *> _atoms;
+ };
+
+ /// \brief This is a convenience class for File subclasses which need to
+ /// return an empty collection.
+ template <typename T>
+ class atom_collection_empty : public atom_collection<T> {
+ public:
+ atom_iterator<T> begin() const override {
+ return atom_iterator<T>(*this, nullptr);
+ }
+ atom_iterator<T> end() const override {
+ return atom_iterator<T>(*this, nullptr);
+ }
+ const T *deref(const void *it) const override {
+ llvm_unreachable("empty collection should never be accessed");
+ }
+ void next(const void *&it) const override {}
+ uint64_t size() const override { return 0; }
+ };
+
+ static atom_collection_empty<DefinedAtom> _noDefinedAtoms;
+ static atom_collection_empty<UndefinedAtom> _noUndefinedAtoms;
+ static atom_collection_empty<SharedLibraryAtom> _noSharedLibraryAtoms;
+ static atom_collection_empty<AbsoluteAtom> _noAbsoluteAtoms;
+ mutable llvm::BumpPtrAllocator _allocator;
+
+private:
+ StringRef _path;
+ std::string _archivePath;
+ mutable std::string _archiveMemberPath;
+ Kind _kind;
+ mutable uint64_t _ordinal;
+ std::shared_ptr<MemoryBuffer> _sharedMemoryBuffer;
+ llvm::Optional<std::error_code> _lastError;
+ std::mutex _parseMutex;
+};
+
+/// \brief A mutable File.
+class MutableFile : public File {
+public:
+ /// \brief Add an atom to the file. Invalidates iterators for all returned
+ /// containters.
+ virtual void addAtom(const Atom&) = 0;
+
+ typedef range<std::vector<const DefinedAtom *>::iterator> DefinedAtomRange;
+ virtual DefinedAtomRange definedAtoms() = 0;
+
+ virtual void
+ removeDefinedAtomsIf(std::function<bool(const DefinedAtom *)> pred) = 0;
+
+protected:
+ /// \brief only subclasses of MutableFile can be instantiated
+ MutableFile(StringRef p) : File(p, kindObject) {}
+};
+
+/// 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, kindObject), _ec(ec) {}
+
+ std::error_code doParse() override { return _ec; }
+
+ const atom_collection<DefinedAtom> &defined() const override {
+ llvm_unreachable("internal error");
+ }
+ const atom_collection<UndefinedAtom> &undefined() const override {
+ llvm_unreachable("internal error");
+ }
+ const atom_collection<SharedLibraryAtom> &sharedLibrary() const override {
+ llvm_unreachable("internal error");
+ }
+ const atom_collection<AbsoluteAtom> &absolute() const override {
+ llvm_unreachable("internal error");
+ }
+
+private:
+ std::error_code _ec;
+};
+
+} // end namespace lld
+
+#endif
diff --git a/include/lld/Core/Instrumentation.h b/include/lld/Core/Instrumentation.h
new file mode 100644
index 000000000000..162375905e17
--- /dev/null
+++ b/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
+/// \brief 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
+/// \brief 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; }
+};
+
+/// \brief 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; }
+};
+
+/// \brief 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:
+ /// \brief 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;
+ }
+
+ /// \brief Prematurely end this task.
+ void end() {
+ if (_domain)
+ __itt_task_end(_domain);
+ _domain = nullptr;
+ }
+
+ ~ScopedTask() { end(); }
+};
+
+/// \brief 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/include/lld/Core/LLVM.h b/include/lld/Core/LLVM.h
new file mode 100644
index 000000000000..1bc1173bd48b
--- /dev/null
+++ b/include/lld/Core/LLVM.h
@@ -0,0 +1,75 @@
+//===--- 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_CORE_LLVM_H
+#define LLD_CORE_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 StringRef;
+ class Twine;
+ class MemoryBuffer;
+ template<typename T> class ArrayRef;
+ template<unsigned InternalLen> class SmallString;
+ template<typename T, unsigned N> class SmallVector;
+ template<typename T> class SmallVectorImpl;
+
+ template<typename T>
+ struct SaveAndRestore;
+
+ template<typename T>
+ class ErrorOr;
+
+ class raw_ostream;
+ // TODO: DenseMap, ...
+}
+
+namespace lld {
+ // Casting operators.
+ using llvm::isa;
+ using llvm::cast;
+ using llvm::dyn_cast;
+ using llvm::dyn_cast_or_null;
+ using llvm::cast_or_null;
+
+ // ADT's.
+ using llvm::StringRef;
+ using llvm::Twine;
+ using llvm::MemoryBuffer;
+ using llvm::ArrayRef;
+ using llvm::SmallString;
+ using llvm::SmallVector;
+ using llvm::SmallVectorImpl;
+ using llvm::SaveAndRestore;
+ using llvm::ErrorOr;
+
+ using llvm::raw_ostream;
+} // end namespace lld.
+
+namespace std {
+template <> struct hash<llvm::StringRef> {
+public:
+ size_t operator()(const llvm::StringRef &s) const {
+ return llvm::hash_value(s);
+ }
+};
+}
+
+#endif
diff --git a/include/lld/Core/LinkingContext.h b/include/lld/Core/LinkingContext.h
new file mode 100644
index 000000000000..81a3b4b4eb71
--- /dev/null
+++ b/include/lld/Core/LinkingContext.h
@@ -0,0 +1,364 @@
+//===- lld/Core/LinkingContext.h - Linker Target Info Interface -----------===//
+//
+// 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/Error.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Node.h"
+#include "lld/Core/Parallel.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/range.h"
+#include "lld/Core/Reader.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/raw_ostream.h"
+#include <string>
+#include <vector>
+
+namespace lld {
+class PassManager;
+class File;
+class Writer;
+class Node;
+class SharedLibraryFile;
+
+/// \brief 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. For example, ELFLinkingContext has methods that supplies
+/// options to the ELF Writer and ELF Passes.
+class LinkingContext {
+public:
+ /// \brief The types of output file that the linker creates.
+ enum class OutputFileType : uint8_t {
+ Default, // The default output type for this target
+ YAML, // The output type is set to YAML
+ Native // The output file format is Native (Atoms)
+ };
+
+ 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.
+ const std::vector<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);
+ }
+
+ /// Archive files (aka static libraries) are normally lazily loaded. That is,
+ /// object files within an archive are only loaded and linked in, if the
+ /// object file contains a DefinedAtom which will replace an existing
+ /// UndefinedAtom. If this method returns true, core linking will also look
+ /// for archive members to replace existing tentative definitions in addition
+ /// to replacing undefines. Note: a "tentative definition" (also called a
+ /// "common" symbols) is a C (but not C++) concept. They are modeled in lld
+ /// as a DefinedAtom with merge() of mergeAsTentative.
+ bool searchArchivesToOverrideTentativeDefinitions() const {
+ return _searchArchivesToOverrideTentativeDefinitions;
+ }
+
+ /// Normally core linking will turn a tentative definition into a real
+ /// definition if not replaced by a real DefinedAtom from some object file.
+ /// If this method returns true, core linking will search all supplied
+ /// dynamic shared libraries for symbol names that match remaining tentative
+ /// definitions. If any are found, the corresponding tentative definition
+ /// atom is replaced with SharedLibraryAtom.
+ bool searchSharedLibrariesToOverrideTentativeDefinitions() const {
+ return _searchSharedLibrariesToOverrideTentativeDefinitions;
+ }
+
+ /// 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; }
+
+ /// In the lld model, a SharedLibraryAtom is a proxy atom for something
+ /// that will be found in a dynamic shared library when the program runs.
+ /// A SharedLibraryAtom optionally contains the name of the shared library
+ /// in which to find the symbol name at runtime. Core linking may merge
+ /// two SharedLibraryAtom with the same name. If this method returns true,
+ /// when merging core linking will also verify that they both have the same
+ /// loadName() and if not print a warning.
+ ///
+ /// \todo This should be a method core linking calls so that drivers can
+ /// format the warning as needed.
+ bool warnIfCoalesableAtomsHaveDifferentLoadName() const {
+ return _warnIfCoalesableAtomsHaveDifferentLoadName;
+ }
+
+ /// In C/C++ you can mark a function's prototype with
+ /// __attribute__((weak_import)) or __attribute__((weak)) to say the function
+ /// may not be available at runtime and/or build time and in which case its
+ /// address will evaluate to NULL. In lld this is modeled using the
+ /// UndefinedAtom::canBeNull() method. During core linking, UndefinedAtom
+ /// with the same name are automatically merged. If this method returns
+ /// true, core link also verfies that the canBeNull() value for merged
+ /// UndefinedAtoms are the same and warns if not.
+ ///
+ /// \todo This should be a method core linking calls so that drivers can
+ /// format the warning as needed.
+ bool warnIfCoalesableAtomsHaveDifferentCanBeNull() const {
+ return _warnIfCoalesableAtomsHaveDifferentCanBeNull;
+ }
+
+ /// 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.
+ const std::vector<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 setAllowDuplicates(bool enable) { _allowDuplicates = enable; }
+ void setGlobalsAreDeadStripRoots(bool v) { _globalsAreDeadStripRoots = v; }
+ void setSearchArchivesToOverrideTentativeDefinitions(bool search) {
+ _searchArchivesToOverrideTentativeDefinitions = search;
+ }
+ void setSearchSharedLibrariesToOverrideTentativeDefinitions(bool search) {
+ _searchSharedLibrariesToOverrideTentativeDefinitions = search;
+ }
+ void setWarnIfCoalesableAtomsHaveDifferentCanBeNull(bool warn) {
+ _warnIfCoalesableAtomsHaveDifferentCanBeNull = warn;
+ }
+ void setWarnIfCoalesableAtomsHaveDifferentLoadName(bool warn) {
+ _warnIfCoalesableAtomsHaveDifferentLoadName = warn;
+ }
+ void setPrintRemainingUndefines(bool print) {
+ _printRemainingUndefines = print;
+ }
+ void setAllowRemainingUndefines(bool allow) {
+ _allowRemainingUndefines = allow;
+ }
+ void setAllowShlibUndefines(bool allow) { _allowShlibUndefines = allow; }
+ void setLogInputFiles(bool log) { _logInputFiles = log; }
+
+ // Returns true if multiple definitions should not be treated as a
+ // fatal error.
+ bool getAllowDuplicates() const { return _allowDuplicates; }
+
+ void appendLLVMOption(const char *opt) { _llvmOptions.push_back(opt); }
+
+ void addAlias(StringRef from, StringRef to) { _aliasSymbols[from] = to; }
+ const std::map<std::string, std::string> &getAliases() const {
+ return _aliasSymbols;
+ }
+
+ std::vector<std::unique_ptr<Node>> &getNodes() { return _nodes; }
+ const std::vector<std::unique_ptr<Node>> &getNodes() const { return _nodes; }
+
+ /// Notify the LinkingContext when the symbol table found a name collision.
+ /// The useNew parameter specifies which the symbol table plans to keep,
+ /// but that can be changed by the LinkingContext. This is also an
+ /// opportunity for flavor specific processing.
+ virtual void notifySymbolTableCoalesce(const Atom *existingAtom,
+ const Atom *newAtom, bool &useNew) {}
+
+ /// 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.
+ range<const 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 supplied stream.
+ ///
+ /// \returns true if there is an error with the current settings.
+ bool validate(raw_ostream &diagnostics);
+
+ /// Formats symbol name for use in error messages.
+ virtual std::string demangle(StringRef symbolName) const {
+ return symbolName;
+ }
+
+ /// @}
+ /// \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; }
+
+ /// Set the various output file types that the linker would
+ /// create
+ bool setOutputFileType(StringRef outputFileType) {
+ if (outputFileType.equals_lower("yaml"))
+ _outputFileType = OutputFileType::YAML;
+ else if (outputFileType.equals_lower("native"))
+ _outputFileType = OutputFileType::YAML;
+ else
+ return false;
+ return true;
+ }
+
+ /// Returns the output file type that that the linker needs to create.
+ OutputFileType outputFileType() const { return _outputFileType; }
+
+ /// 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 bool createImplicitFiles(std::vector<std::unique_ptr<File> > &);
+
+ /// 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);
+
+ /// Calls through to the writeFile() method on the specified Writer.
+ ///
+ /// \param linkedFile This is the merged/linked graph of all input file Atoms.
+ virtual std::error_code 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() {}
+
+ TaskGroup &getTaskGroup() { return _taskGroup; }
+
+ /// @}
+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;
+
+ /// Method to create an internal file for alias symbols
+ std::unique_ptr<File> createAliasSymbolFile() const;
+
+ StringRef _outputPath;
+ StringRef _entrySymbolName;
+ bool _deadStrip;
+ bool _allowDuplicates;
+ bool _globalsAreDeadStripRoots;
+ bool _searchArchivesToOverrideTentativeDefinitions;
+ bool _searchSharedLibrariesToOverrideTentativeDefinitions;
+ bool _warnIfCoalesableAtomsHaveDifferentCanBeNull;
+ bool _warnIfCoalesableAtomsHaveDifferentLoadName;
+ bool _printRemainingUndefines;
+ bool _allowRemainingUndefines;
+ bool _logInputFiles;
+ bool _allowShlibUndefines;
+ OutputFileType _outputFileType;
+ std::vector<StringRef> _deadStripRoots;
+ std::map<std::string, std::string> _aliasSymbols;
+ std::vector<const char *> _llvmOptions;
+ StringRefVector _initialUndefinedSymbols;
+ std::vector<std::unique_ptr<Node>> _nodes;
+ mutable llvm::BumpPtrAllocator _allocator;
+ mutable uint64_t _nextOrdinal;
+ Registry _registry;
+
+private:
+ /// Validate the subclass bits. Only called by validate.
+ virtual bool validateImpl(raw_ostream &diagnostics) = 0;
+ TaskGroup _taskGroup;
+};
+
+} // end namespace lld
+
+#endif
diff --git a/include/lld/Core/Node.h b/include/lld/Core/Node.h
new file mode 100644
index 000000000000..cd38fbd4a482
--- /dev/null
+++ b/include/lld/Core/Node.h
@@ -0,0 +1,78 @@
+//===- lld/Core/Node.h - Input file class ---------------------------------===//
+//
+// 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 "llvm/Option/ArgList.h"
+#include <memory>
+#include <vector>
+
+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() {}
+ 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)), _asNeeded(false) {}
+
+ static bool classof(const Node *a) {
+ return a->kind() == Node::Kind::File;
+ }
+
+ File *getFile() { return _file.get(); }
+
+ void setAsNeeded(bool val) { _asNeeded = val; }
+ bool asNeeded() const { return _asNeeded; }
+
+protected:
+ std::unique_ptr<File> _file;
+ bool _asNeeded;
+};
+
+} // namespace lld
+
+#endif // LLD_CORE_NODE_H
diff --git a/include/lld/Core/Parallel.h b/include/lld/Core/Parallel.h
new file mode 100644
index 000000000000..65176ac2b04d
--- /dev/null
+++ b/include/lld/Core/Parallel.h
@@ -0,0 +1,309 @@
+//===- lld/Core/Parallel.h - Parallel utilities ---------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_PARALLEL_H
+#define LLD_CORE_PARALLEL_H
+
+#include "lld/Core/Instrumentation.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/range.h"
+#include "llvm/Support/MathExtras.h"
+
+#ifdef _MSC_VER
+// concrt.h depends on eh.h for __uncaught_exception declaration
+// even if we disable exceptions.
+#include <eh.h>
+#endif
+
+#include <algorithm>
+#include <atomic>
+#include <condition_variable>
+#include <mutex>
+#include <thread>
+#include <stack>
+
+#ifdef _MSC_VER
+#include <concrt.h>
+#include <ppl.h>
+#endif
+
+namespace lld {
+/// \brief Allows one or more threads to wait on a potentially unknown number of
+/// events.
+///
+/// A latch starts at \p count. inc() increments this, and dec() decrements it.
+/// All calls to sync() will block while the count is not 0.
+///
+/// Calling dec() on a Latch with a count of 0 has undefined behaivor.
+class Latch {
+ uint32_t _count;
+ mutable std::mutex _condMut;
+ mutable std::condition_variable _cond;
+
+public:
+ explicit Latch(uint32_t count = 0) : _count(count) {}
+ ~Latch() { sync(); }
+
+ void inc() {
+ std::unique_lock<std::mutex> lock(_condMut);
+ ++_count;
+ }
+
+ void dec() {
+ std::unique_lock<std::mutex> lock(_condMut);
+ if (--_count == 0)
+ _cond.notify_all();
+ }
+
+ void sync() const {
+ std::unique_lock<std::mutex> lock(_condMut);
+ _cond.wait(lock, [&] {
+ return _count == 0;
+ });
+ }
+};
+
+/// \brief An implementation of future. std::future and std::promise in
+/// old libstdc++ have a threading bug; there is a small chance that a
+/// call of future::get throws an exception in the normal use case.
+/// We want to use our own future implementation until we drop support
+/// of old versions of libstdc++.
+/// https://gcc.gnu.org/ml/gcc-patches/2014-05/msg01389.html
+template<typename T> class Future {
+public:
+ Future() : _hasValue(false) {}
+
+ void set(T &&val) {
+ assert(!_hasValue);
+ {
+ std::unique_lock<std::mutex> lock(_mutex);
+ _val = val;
+ _hasValue = true;
+ }
+ _cond.notify_all();
+ }
+
+ T &get() {
+ std::unique_lock<std::mutex> lock(_mutex);
+ if (_hasValue)
+ return _val;
+ _cond.wait(lock, [&] { return _hasValue; });
+ return _val;
+ }
+
+private:
+ T _val;
+ bool _hasValue;
+ std::mutex _mutex;
+ std::condition_variable _cond;
+};
+
+/// \brief An abstract class that takes closures and runs them asynchronously.
+class Executor {
+public:
+ virtual ~Executor() {}
+ virtual void add(std::function<void()> func) = 0;
+};
+
+/// \brief An implementation of an Executor that runs closures on a thread pool
+/// in filo order.
+class ThreadPoolExecutor : public Executor {
+public:
+ explicit ThreadPoolExecutor(unsigned threadCount =
+ std::thread::hardware_concurrency())
+ : _stop(false), _done(threadCount) {
+ // Spawn all but one of the threads in another thread as spawning threads
+ // can take a while.
+ std::thread([&, threadCount] {
+ for (std::size_t i = 1; i < threadCount; ++i) {
+ std::thread([=] {
+ work();
+ }).detach();
+ }
+ work();
+ }).detach();
+ }
+
+ ~ThreadPoolExecutor() {
+ std::unique_lock<std::mutex> lock(_mutex);
+ _stop = true;
+ lock.unlock();
+ _cond.notify_all();
+ // Wait for ~Latch.
+ }
+
+ void add(std::function<void()> f) override {
+ std::unique_lock<std::mutex> lock(_mutex);
+ _workStack.push(f);
+ lock.unlock();
+ _cond.notify_one();
+ }
+
+private:
+ void work() {
+ while (true) {
+ std::unique_lock<std::mutex> lock(_mutex);
+ _cond.wait(lock, [&] {
+ return _stop || !_workStack.empty();
+ });
+ if (_stop)
+ break;
+ auto task = _workStack.top();
+ _workStack.pop();
+ lock.unlock();
+ task();
+ }
+ _done.dec();
+ }
+
+ std::atomic<bool> _stop;
+ std::stack<std::function<void()>> _workStack;
+ std::mutex _mutex;
+ std::condition_variable _cond;
+ Latch _done;
+};
+
+#ifdef _MSC_VER
+/// \brief An Executor that runs tasks via ConcRT.
+class ConcRTExecutor : public Executor {
+ struct Taskish {
+ Taskish(std::function<void()> task) : _task(task) {}
+
+ std::function<void()> _task;
+
+ static void run(void *p) {
+ Taskish *self = static_cast<Taskish *>(p);
+ self->_task();
+ concurrency::Free(self);
+ }
+ };
+
+public:
+ virtual void add(std::function<void()> func) {
+ Concurrency::CurrentScheduler::ScheduleTask(Taskish::run,
+ new (concurrency::Alloc(sizeof(Taskish))) Taskish(func));
+ }
+};
+
+inline Executor *getDefaultExecutor() {
+ static ConcRTExecutor exec;
+ return &exec;
+}
+#else
+inline Executor *getDefaultExecutor() {
+ static ThreadPoolExecutor exec;
+ return &exec;
+}
+#endif
+
+/// \brief Allows launching a number of tasks and waiting for them to finish
+/// either explicitly via sync() or implicitly on destruction.
+class TaskGroup {
+ Latch _latch;
+
+public:
+ void spawn(std::function<void()> f) {
+ _latch.inc();
+ getDefaultExecutor()->add([&, f] {
+ f();
+ _latch.dec();
+ });
+ }
+
+ void sync() const { _latch.sync(); }
+};
+
+#ifdef _MSC_VER
+// Use ppl parallel_sort on Windows.
+template <class RandomAccessIterator, class Comp>
+void parallel_sort(
+ RandomAccessIterator start, RandomAccessIterator end,
+ const Comp &comp = std::less<
+ typename std::iterator_traits<RandomAccessIterator>::value_type>()) {
+ concurrency::parallel_sort(start, end, comp);
+}
+#else
+namespace detail {
+const ptrdiff_t minParallelSize = 1024;
+
+/// \brief Inclusive median.
+template <class RandomAccessIterator, class Comp>
+RandomAccessIterator medianOf3(RandomAccessIterator start,
+ RandomAccessIterator end, const Comp &comp) {
+ RandomAccessIterator mid = start + (std::distance(start, end) / 2);
+ return comp(*start, *(end - 1))
+ ? (comp(*mid, *(end - 1)) ? (comp(*start, *mid) ? mid : start)
+ : end - 1)
+ : (comp(*mid, *start) ? (comp(*(end - 1), *mid) ? mid : end - 1)
+ : start);
+}
+
+template <class RandomAccessIterator, class Comp>
+void parallel_quick_sort(RandomAccessIterator start, RandomAccessIterator end,
+ const Comp &comp, TaskGroup &tg, size_t depth) {
+ // Do a sequential sort for small inputs.
+ if (std::distance(start, end) < detail::minParallelSize || depth == 0) {
+ std::sort(start, end, comp);
+ return;
+ }
+
+ // Partition.
+ auto pivot = medianOf3(start, end, comp);
+ // Move pivot to end.
+ std::swap(*(end - 1), *pivot);
+ pivot = std::partition(start, end - 1, [&comp, end](decltype(*start) v) {
+ return comp(v, *(end - 1));
+ });
+ // Move pivot to middle of partition.
+ std::swap(*pivot, *(end - 1));
+
+ // Recurse.
+ tg.spawn([=, &comp, &tg] {
+ parallel_quick_sort(start, pivot, comp, tg, depth - 1);
+ });
+ parallel_quick_sort(pivot + 1, end, comp, tg, depth - 1);
+}
+}
+
+template <class RandomAccessIterator, class Comp>
+void parallel_sort(
+ RandomAccessIterator start, RandomAccessIterator end,
+ const Comp &comp = std::less<
+ typename std::iterator_traits<RandomAccessIterator>::value_type>()) {
+ TaskGroup tg;
+ detail::parallel_quick_sort(start, end, comp, tg,
+ llvm::Log2_64(std::distance(start, end)) + 1);
+}
+#endif
+
+template <class T> void parallel_sort(T *start, T *end) {
+ parallel_sort(start, end, std::less<T>());
+}
+
+#ifdef _MSC_VER
+// Use ppl parallel_for_each on Windows.
+template <class Iterator, class Func>
+void parallel_for_each(Iterator begin, Iterator end, Func func) {
+ concurrency::parallel_for_each(begin, end, func);
+}
+#else
+template <class Iterator, class Func>
+void parallel_for_each(Iterator begin, Iterator end, Func func) {
+ TaskGroup tg;
+ ptrdiff_t taskSize = 1024;
+ while (taskSize <= std::distance(begin, end)) {
+ tg.spawn([=, &func] { std::for_each(begin, begin + taskSize, func); });
+ begin += taskSize;
+ }
+ std::for_each(begin, end, func);
+}
+#endif
+} // end namespace lld
+
+#endif
diff --git a/include/lld/Core/Pass.h b/include/lld/Core/Pass.h
new file mode 100644
index 000000000000..7a9d2453f482
--- /dev/null
+++ b/include/lld/Core/Pass.h
@@ -0,0 +1,46 @@
+//===------ Core/Pass.h - Base class for 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_H
+#define LLD_CORE_PASS_H
+
+#include "lld/Core/Atom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/range.h"
+#include <vector>
+
+namespace lld {
+class MutableFile;
+
+/// 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() { }
+
+ /// Do the actual work of the Pass.
+ virtual void perform(std::unique_ptr<MutableFile> &mergedFile) = 0;
+
+protected:
+ // Only subclassess can be instantiated.
+ Pass() { }
+};
+
+} // namespace lld
+
+#endif // LLD_CORE_PASS_H
diff --git a/include/lld/Core/PassManager.h b/include/lld/Core/PassManager.h
new file mode 100644
index 000000000000..65fc4d806ceb
--- /dev/null
+++ b/include/lld/Core/PassManager.h
@@ -0,0 +1,46 @@
+//===- 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/Core/LLVM.h"
+#include "lld/Core/Pass.h"
+#include <memory>
+#include <vector>
+
+namespace lld {
+class MutableFile;
+class Pass;
+
+/// \brief 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));
+ }
+
+ std::error_code runOnFile(std::unique_ptr<MutableFile> &file) {
+ for (std::unique_ptr<Pass> &pass : _passes)
+ pass->perform(file);
+ return std::error_code();
+ }
+
+private:
+ /// \brief Passes in the order they should run.
+ std::vector<std::unique_ptr<Pass>> _passes;
+};
+} // end namespace lld
+
+#endif
diff --git a/include/lld/Core/Reader.h b/include/lld/Core/Reader.h
new file mode 100644
index 000000000000..ac90c5a7e85c
--- /dev/null
+++ b/include/lld/Core/Reader.h
@@ -0,0 +1,169 @@
+//===- 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/Core/LLVM.h"
+#include "lld/Core/Reference.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/YAMLTraits.h"
+#include <functional>
+#include <memory>
+#include <vector>
+
+using llvm::sys::fs::file_magic;
+
+namespace llvm {
+namespace yaml {
+class IO;
+}
+}
+
+namespace lld {
+class ELFLinkingContext;
+class File;
+class LinkingContext;
+class PECOFFLinkingContext;
+class TargetHandlerBase;
+class MachOLinkingContext;
+
+/// \brief An abstract class for reading object files, library files, and
+/// executable files.
+///
+/// Each file format (e.g. ELF, mach-o, PECOFF, native, etc) have a concrete
+/// subclass of Reader.
+class Reader {
+public:
+ virtual ~Reader() {}
+
+ /// 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 file extension (e.g. ".obj")
+ /// 3) the whole file content buffer if the above is not enough.
+ virtual bool canParse(file_magic magic, StringRef fileExtension,
+ const MemoryBuffer &mb) const = 0;
+
+ /// \brief 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 std::error_code
+ loadFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &,
+ std::vector<std::unique_ptr<File>> &result) const = 0;
+};
+
+
+/// \brief 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.
+ std::error_code loadFile(std::unique_ptr<MemoryBuffer> mb,
+ std::vector<std::unique_ptr<File>> &result) 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 addSupportNativeObjects();
+ void addSupportCOFFObjects(PECOFFLinkingContext &);
+ void addSupportCOFFImportLibraries(PECOFFLinkingContext &);
+ void addSupportMachOObjects(MachOLinkingContext &);
+ void addSupportELFObjects(ELFLinkingContext &);
+ void addSupportELFDynamicSharedObjects(ELFLinkingContext &);
+
+ /// 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
diff --git a/include/lld/Core/Reference.h b/include/lld/Core/Reference.h
new file mode 100644
index 000000000000..7a804c31e182
--- /dev/null
+++ b/include/lld/Core/Reference.h
@@ -0,0 +1,125 @@
+//===- Core/References.h - A Reference to Another Atom --------------------===//
+//
+// 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 "lld/Core/LLVM.h"
+#include "llvm/ADT/StringSwitch.h"
+
+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
+/// grouping atoms (group comdat), 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. For instance, in ELF the relocation type 10
+/// means R_X86_64_32 for x86_64, and R_386_GOTPC for i386. For PE/COFF
+/// relocation 10 means IMAGE_REL_AMD64_SECTION.
+///
+/// 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,
+ ELF = 2,
+ COFF = 3,
+ mach_o = 4,
+ };
+
+ 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, Hexagon, Mips, 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,
+ // kindGroupChild is treated as a bidirected edge too.
+ kindGroupChild,
+ 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() {}
+
+ KindValue _kindValue;
+ uint8_t _kindNamespace;
+ uint8_t _kindArch;
+};
+
+} // namespace lld
+
+#endif // LLD_CORE_REFERENCES_H
diff --git a/include/lld/Core/Resolver.h b/include/lld/Core/Resolver.h
new file mode 100644
index 000000000000..e16c07b839fa
--- /dev/null
+++ b/include/lld/Core/Resolver.h
@@ -0,0 +1,119 @@
+//===- 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 <set>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+namespace lld {
+
+class Atom;
+class LinkingContext;
+
+/// \brief The Resolver is responsible for merging all input object files
+/// and producing a merged graph.
+class Resolver {
+public:
+ Resolver(LinkingContext &ctx)
+ : _ctx(ctx), _symbolTable(ctx), _result(new MergedFile()),
+ _fileIndex(0) {}
+
+ // InputFiles::Handler methods
+ void doDefinedAtom(const DefinedAtom&);
+ bool doUndefinedAtom(const UndefinedAtom &);
+ void doSharedLibraryAtom(const SharedLibraryAtom &);
+ void doAbsoluteAtom(const AbsoluteAtom &);
+
+ // Handle files, this adds atoms from the current file thats
+ // being processed by the resolver
+ bool handleFile(File &);
+
+ // Handle an archive library file.
+ bool handleArchiveFile(File &);
+
+ // Handle a shared library file.
+ void handleSharedLibrary(File &);
+
+ /// @brief do work of merging and resolving and return list
+ bool resolve();
+
+ std::unique_ptr<MutableFile> resultFile() { return std::move(_result); }
+
+private:
+ typedef std::function<void(StringRef, bool)> UndefCallback;
+
+ bool undefinesAdded(int begin, int end);
+ File *getFile(int &index);
+
+ /// \brief Add section group/.gnu.linkonce if it does not exist previously.
+ void maybeAddSectionGroupOrGnuLinkOnce(const DefinedAtom &atom);
+
+ /// \brief The main function that iterates over the files to resolve
+ void updatePreloadArchiveMap();
+ bool resolveUndefines();
+ void updateReferences();
+ void deadStripOptimize();
+ bool checkUndefines();
+ void removeCoalescedAwayAtoms();
+ void checkDylibSymbolCollisions();
+ void forEachUndefines(File &file, bool searchForOverrides, UndefCallback callback);
+
+ void markLive(const Atom *atom);
+ void addAtoms(const std::vector<const DefinedAtom *>&);
+ void maybePreloadArchiveMember(StringRef sym);
+
+ class MergedFile : public SimpleFile {
+ public:
+ MergedFile() : SimpleFile("<linker-internal>") {}
+ void addAtoms(std::vector<const Atom*>& atoms);
+ };
+
+ LinkingContext &_ctx;
+ SymbolTable _symbolTable;
+ std::vector<const 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;
+ size_t _fileIndex;
+
+ // Preloading
+ llvm::StringMap<ArchiveLibraryFile *> _archiveMap;
+ llvm::DenseSet<ArchiveLibraryFile *> _archiveSeen;
+
+ // 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/include/lld/Core/STDExtras.h b/include/lld/Core/STDExtras.h
new file mode 100644
index 000000000000..4a6183891844
--- /dev/null
+++ b/include/lld/Core/STDExtras.h
@@ -0,0 +1,29 @@
+//===- lld/Core/STDExtra.h - Helpers for the stdlib -----------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_STD_EXTRA_H
+#define LLD_CORE_STD_EXTRA_H
+
+namespace lld {
+/// \brief Deleter for smart pointers that only calls the destructor. Memory is
+/// managed elsewhere. A common use of this is for things allocated with a
+/// BumpPtrAllocator.
+template <class T>
+struct destruct_delete {
+ void operator ()(T *ptr) {
+ ptr->~T();
+ }
+};
+
+template <class T>
+using unique_bump_ptr = std::unique_ptr<T, destruct_delete<T>>;
+
+} // end namespace lld
+
+#endif
diff --git a/include/lld/Core/SharedLibraryAtom.h b/include/lld/Core/SharedLibraryAtom.h
new file mode 100644
index 000000000000..1b0c37c41138
--- /dev/null
+++ b/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 linux that is the DT_NEEDED name.
+ /// On Darwin it is the LC_DYLIB_LOAD dylib name.
+ /// On Windows it is the DLL name that to be referred from .idata section.
+ 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) {}
+};
+
+} // namespace lld
+
+#endif // LLD_CORE_SHARED_LIBRARY_ATOM_H
diff --git a/include/lld/Core/SharedLibraryFile.h b/include/lld/Core/SharedLibraryFile.h
new file mode 100644
index 000000000000..2f84624287d8
--- /dev/null
+++ b/include/lld/Core/SharedLibraryFile.h
@@ -0,0 +1,65 @@
+//===- 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 const SharedLibraryAtom *exports(StringRef name,
+ bool dataSymbolOnly) const = 0;
+
+ // Returns DSO name. It's the soname (ELF), the install name (MachO) or
+ // the import name (Windows).
+ virtual StringRef getDSOName() const = 0;
+
+ const atom_collection<DefinedAtom> &defined() const override {
+ return _definedAtoms;
+ }
+
+ const atom_collection<UndefinedAtom> &undefined() const override {
+ return _undefinedAtoms;
+ }
+
+ const atom_collection<SharedLibraryAtom> &sharedLibrary() const override {
+ return _sharedLibraryAtoms;
+ }
+
+ const atom_collection<AbsoluteAtom> &absolute() const override {
+ return _absoluteAtoms;
+ }
+
+protected:
+ /// only subclasses of SharedLibraryFile can be instantiated
+ explicit SharedLibraryFile(StringRef path) : File(path, kindSharedLibrary) {}
+
+ atom_collection_vector<DefinedAtom> _definedAtoms;
+ atom_collection_vector<UndefinedAtom> _undefinedAtoms;
+ atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
+ atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
+};
+
+} // namespace lld
+
+#endif // LLD_CORE_SHARED_LIBRARY_FILE_H
diff --git a/include/lld/Core/Simple.h b/include/lld/Core/Simple.h
new file mode 100644
index 000000000000..71d0c0702301
--- /dev/null
+++ b/include/lld/Core/Simple.h
@@ -0,0 +1,341 @@
+//===- 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
+/// \brief Provide simple implementations for Atoms and File.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_SIMPLE_H
+#define LLD_CORE_SIMPLE_H
+
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/ArchiveLibraryFile.h"
+#include "lld/Core/LinkingContext.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/UndefinedAtom.h"
+#include "llvm/ADT/ilist.h"
+#include "llvm/ADT/ilist_node.h"
+
+namespace lld {
+
+class SimpleFile : public MutableFile {
+public:
+ SimpleFile(StringRef path) : MutableFile(path) {}
+
+ void addAtom(const Atom &atom) override {
+ if (auto *defAtom = dyn_cast<DefinedAtom>(&atom)) {
+ _definedAtoms._atoms.push_back(defAtom);
+ } else if (auto *undefAtom = dyn_cast<UndefinedAtom>(&atom)) {
+ _undefinedAtoms._atoms.push_back(undefAtom);
+ } else if (auto *shlibAtom = dyn_cast<SharedLibraryAtom>(&atom)) {
+ _sharedLibraryAtoms._atoms.push_back(shlibAtom);
+ } else if (auto *absAtom = dyn_cast<AbsoluteAtom>(&atom)) {
+ _absoluteAtoms._atoms.push_back(absAtom);
+ } else {
+ llvm_unreachable("atom has unknown definition kind");
+ }
+ }
+
+ void
+ removeDefinedAtomsIf(std::function<bool(const DefinedAtom *)> pred) override {
+ auto &atoms = _definedAtoms._atoms;
+ auto newEnd = std::remove_if(atoms.begin(), atoms.end(), pred);
+ atoms.erase(newEnd, atoms.end());
+ }
+
+ const atom_collection<DefinedAtom> &defined() const override {
+ return _definedAtoms;
+ }
+
+ const atom_collection<UndefinedAtom> &undefined() const override {
+ return _undefinedAtoms;
+ }
+
+ const atom_collection<SharedLibraryAtom> &sharedLibrary() const override {
+ return _sharedLibraryAtoms;
+ }
+
+ const atom_collection<AbsoluteAtom> &absolute() const override {
+ return _absoluteAtoms;
+ }
+
+ DefinedAtomRange definedAtoms() override {
+ return make_range(_definedAtoms._atoms);
+ }
+
+private:
+ atom_collection_vector<DefinedAtom> _definedAtoms;
+ atom_collection_vector<UndefinedAtom> _undefinedAtoms;
+ atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
+ atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
+};
+
+/// \brief Archive library file that may be used as a virtual container
+/// for symbols that should be added dynamically in response to
+/// call to find() method.
+class SimpleArchiveLibraryFile : public ArchiveLibraryFile {
+public:
+ SimpleArchiveLibraryFile(StringRef filename)
+ : ArchiveLibraryFile(filename) {}
+
+ const atom_collection<DefinedAtom> &defined() const override {
+ return _definedAtoms;
+ }
+
+ const atom_collection<UndefinedAtom> &undefined() const override {
+ return _undefinedAtoms;
+ }
+
+ const atom_collection<SharedLibraryAtom> &sharedLibrary() const override {
+ return _sharedLibraryAtoms;
+ }
+
+ const atom_collection<AbsoluteAtom> &absolute() const override {
+ return _absoluteAtoms;
+ }
+
+ File *find(StringRef sym, bool dataSymbolOnly) override {
+ // For descendants:
+ // do some checks here and return dynamically generated files with atoms.
+ return nullptr;
+ }
+
+ std::error_code
+ parseAllMembers(std::vector<std::unique_ptr<File>> &result) override {
+ return std::error_code();
+ }
+
+private:
+ atom_collection_vector<DefinedAtom> _definedAtoms;
+ atom_collection_vector<UndefinedAtom> _undefinedAtoms;
+ atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
+ atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
+};
+
+class SimpleReference : public Reference {
+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),
+ _next(nullptr), _prev(nullptr) {
+ }
+ SimpleReference()
+ : Reference(Reference::KindNamespace::all, Reference::KindArch::all, 0),
+ _target(nullptr), _offsetInAtom(0), _addend(0), _next(nullptr),
+ _prev(nullptr) {
+ }
+
+ 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; }
+ SimpleReference *getNext() const { return _next; }
+ SimpleReference *getPrev() const { return _prev; }
+ void setNext(SimpleReference *n) { _next = n; }
+ void setPrev(SimpleReference *p) { _prev = p; }
+
+private:
+ const Atom *_target;
+ uint64_t _offsetInAtom;
+ Addend _addend;
+ SimpleReference *_next;
+ SimpleReference *_prev;
+};
+
+}
+
+// ilist will lazily create a sentinal (so end() can return a node past the
+// end of the list). We need this trait so that the sentinal is allocated
+// via the BumpPtrAllocator.
+namespace llvm {
+template<>
+struct ilist_sentinel_traits<lld::SimpleReference> {
+
+ ilist_sentinel_traits() : _allocator(nullptr) { }
+
+ void setAllocator(llvm::BumpPtrAllocator *alloc) {
+ _allocator = alloc;
+ }
+
+ lld::SimpleReference *createSentinel() const {
+ return new (*_allocator) lld::SimpleReference();
+ }
+
+ static void destroySentinel(lld::SimpleReference*) {}
+
+ static lld::SimpleReference *provideInitialHead() { return nullptr; }
+
+ lld::SimpleReference *ensureHead(lld::SimpleReference *&head) const {
+ if (!head) {
+ head = createSentinel();
+ noteHead(head, head);
+ ilist_traits<lld::SimpleReference>::setNext(head, nullptr);
+ return head;
+ }
+ return ilist_traits<lld::SimpleReference>::getPrev(head);
+ }
+
+ void noteHead(lld::SimpleReference *newHead,
+ lld::SimpleReference *sentinel) const {
+ ilist_traits<lld::SimpleReference>::setPrev(newHead, sentinel);
+ }
+
+private:
+ mutable llvm::BumpPtrAllocator *_allocator;
+};
+}
+
+namespace lld {
+
+class SimpleDefinedAtom : public DefinedAtom {
+public:
+ explicit SimpleDefinedAtom(const File &f) : _file(f) {
+ static uint32_t lastOrdinal = 0;
+ _ordinal = lastOrdinal++;
+ _references.setAllocator(&f.allocator());
+ }
+
+ 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 Alignment(0, 0); }
+
+ 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());
+ return reference_iterator(*this, it);
+ }
+
+ DefinedAtom::reference_iterator end() const override {
+ const void *it = reinterpret_cast<const void *>(&*_references.end());
+ return reference_iterator(*this, it);
+ }
+
+ const Reference *derefIterator(const void *it) const override {
+ return reinterpret_cast<const Reference*>(it);
+ }
+
+ void incrementIterator(const void *&it) const override {
+ const SimpleReference* node = reinterpret_cast<const SimpleReference*>(it);
+ const SimpleReference* next = node->getNext();
+ it = reinterpret_cast<const void*>(next);
+ }
+
+ void addReference(Reference::KindNamespace ns, Reference::KindArch arch,
+ Reference::KindValue kindValue, uint64_t off,
+ const Atom *target, Reference::Addend a) {
+ 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");
+ }
+
+ /// 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;
+};
+
+class SimpleAbsoluteAtom : public AbsoluteAtom {
+public:
+ SimpleAbsoluteAtom(const File &f, StringRef name, Scope s, uint64_t value)
+ : _file(f), _name(name), _scope(s), _value(value) {}
+
+ const 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; }
+
+private:
+ const File &_file;
+ StringRef _name;
+ Scope _scope;
+ uint64_t _value;
+};
+
+} // end namespace lld
+
+#endif
diff --git a/include/lld/Core/SymbolTable.h b/include/lld/Core/SymbolTable.h
new file mode 100644
index 000000000000..683ed65e3635
--- /dev/null
+++ b/include/lld/Core/SymbolTable.h
@@ -0,0 +1,117 @@
+//===- 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/Core/LLVM.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/StringExtras.h"
+#include <cstring>
+#include <map>
+#include <vector>
+
+namespace lld {
+
+class AbsoluteAtom;
+class Atom;
+class DefinedAtom;
+class LinkingContext;
+class ResolverOptions;
+class SharedLibraryAtom;
+class UndefinedAtom;
+
+/// \brief 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:
+ explicit SymbolTable(LinkingContext &);
+
+ /// @brief add atom to symbol table
+ bool add(const DefinedAtom &);
+
+ /// @brief add atom to symbol table
+ bool add(const UndefinedAtom &);
+
+ /// @brief add atom to symbol table
+ bool add(const SharedLibraryAtom &);
+
+ /// @brief add atom to symbol table
+ bool add(const AbsoluteAtom &);
+
+ /// @brief checks if name is in symbol table and if so atom is not
+ /// UndefinedAtom
+ bool isDefined(StringRef sym);
+
+ /// @brief returns atom in symbol table for specified name (or nullptr)
+ const Atom *findByName(StringRef sym);
+
+ /// @brief returns vector of remaining UndefinedAtoms
+ std::vector<const UndefinedAtom *> undefines();
+
+ /// returns vector of tentative definitions
+ std::vector<StringRef> tentativeDefinitions();
+
+ /// @brief add atom to replacement table
+ void addReplacement(const Atom *replaced, const Atom *replacement);
+
+ /// @brief if atom has been coalesced away, return replacement, else return atom
+ const Atom *replacement(const Atom *);
+
+ /// @brief if atom has been coalesced away, return true
+ bool isCoalescedAway(const Atom *);
+
+ /// @brief Find a group atom.
+ const Atom *findGroup(StringRef name);
+
+ /// @brief Add a group atom and returns true/false depending on whether the
+ /// previously existed.
+ bool addGroup(const DefinedAtom &da);
+
+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::HashString(val);
+ }
+ 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 &);
+
+ LinkingContext &_context;
+ AtomToAtom _replacedAtoms;
+ NameToAtom _nameTable;
+ NameToAtom _groupTable;
+ AtomContentSet _contentTable;
+};
+
+} // namespace lld
+
+#endif // LLD_CORE_SYMBOL_TABLE_H
diff --git a/include/lld/Core/TODO.txt b/include/lld/Core/TODO.txt
new file mode 100644
index 000000000000..8888c763ef65
--- /dev/null
+++ b/include/lld/Core/TODO.txt
@@ -0,0 +1,17 @@
+include/lld/Core
+~~~~~~~~~~~~~~~~
+
+* The native/yaml reader/writer interfaces should be changed to return
+ an explanatory string if there is an error. The existing error_code
+ abstraction only works for returning low level OS errors. It does not
+ work for describing formatting issues.
+
+* We need to design a diagnostics interface. It would be nice to share code
+ with Clang_ where possible.
+
+* We need to add more attributes to File. In particular, we need cpu
+ and OS information (like target triples). We should also provide explicit
+ support for `LLVM IR module flags metadata`__.
+
+.. __: http://llvm.org/docs/LangRef.html#module_flags
+.. _Clang: http://clang.llvm.org/docs/InternalsManual.html#Diagnostics
diff --git a/include/lld/Core/UndefinedAtom.h b/include/lld/Core/UndefinedAtom.h
new file mode 100644
index 000000000000..7a835a4ebaa8
--- /dev/null
+++ b/include/lld/Core/UndefinedAtom.h
@@ -0,0 +1,74 @@
+//===- 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; }
+
+ /// Returns an undefined atom if this undefined symbol has a synonym. This is
+ /// mainly used in COFF. In COFF, an unresolved external symbol can have up to
+ /// one optional name (sym2) in addition to its regular name (sym1). If a
+ /// definition of sym1 exists, sym1 is resolved normally. Otherwise, all
+ /// references to sym1 refer to sym2 instead. In that case sym2 must be
+ /// resolved, or link will fail.
+ virtual const UndefinedAtom *fallback() const { return nullptr; }
+
+protected:
+ UndefinedAtom() : Atom(definitionUndefined) {}
+};
+
+} // namespace lld
+
+#endif // LLD_CORE_UNDEFINED_ATOM_H
diff --git a/include/lld/Core/Writer.h b/include/lld/Core/Writer.h
new file mode 100644
index 000000000000..94c75d8d019f
--- /dev/null
+++ b/include/lld/Core/Writer.h
@@ -0,0 +1,52 @@
+//===- 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/Core/LLVM.h"
+#include <memory>
+#include <vector>
+
+namespace lld {
+class File;
+class ELFLinkingContext;
+class MachOLinkingContext;
+class PECOFFLinkingContext;
+class LinkingContext;
+class TargetHandlerBase;
+
+/// \brief The Writer is an abstract class for writing object files, shared
+/// library files, and executable files. Each file format (e.g. ELF, mach-o,
+/// PECOFF, native, etc) have a concrete subclass of Writer.
+class Writer {
+public:
+ virtual ~Writer();
+
+ /// \brief Write a file from the supplied File object
+ virtual std::error_code writeFile(const File &linkedFile, StringRef path) = 0;
+
+ /// \brief 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 bool createImplicitFiles(std::vector<std::unique_ptr<File> > &);
+
+protected:
+ // only concrete subclasses can be instantiated
+ Writer();
+};
+
+std::unique_ptr<Writer> createWriterELF(TargetHandlerBase *handler);
+std::unique_ptr<Writer> createWriterMachO(const MachOLinkingContext &);
+std::unique_ptr<Writer> createWriterPECOFF(const PECOFFLinkingContext &);
+std::unique_ptr<Writer> createWriterNative();
+std::unique_ptr<Writer> createWriterYAML(const LinkingContext &);
+} // end namespace lld
+
+#endif
diff --git a/include/lld/Core/range.h b/include/lld/Core/range.h
new file mode 100644
index 000000000000..614c9672955c
--- /dev/null
+++ b/include/lld/Core/range.h
@@ -0,0 +1,738 @@
+//===-- lld/Core/range.h - Iterator ranges ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Iterator range type based on c++1y range proposal.
+///
+/// See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3350.html
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_RANGE_H
+#define LLD_CORE_RANGE_H
+
+#include "llvm/Support/Compiler.h"
+#include <array>
+#include <cassert>
+#include <iterator>
+#include <string>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+namespace lld {
+// Nothing in this namespace is part of the exported interface.
+namespace detail {
+using std::begin;
+using std::end;
+/// Used as the result type of undefined functions.
+struct undefined {};
+
+template <typename R> class begin_result {
+ template <typename T> static auto check(T &&t) -> decltype(begin(t));
+ static undefined check(...);
+public:
+ typedef decltype(check(std::declval<R>())) type;
+};
+
+template <typename R> class end_result {
+ template <typename T> static auto check(T &&t) -> decltype(end(t));
+ static undefined check(...);
+public:
+ typedef decltype(check(std::declval<R>())) type;
+};
+
+// Things that begin and end work on, in compatible ways, are
+// ranges. [stmt.ranged]
+template <typename R>
+struct is_range : std::is_same<typename detail::begin_result<R>::type,
+ typename detail::end_result<R>::type> {};
+
+// This currently requires specialization and doesn't work for
+// detecting \c range<>s or iterators. We should add
+// \c contiguous_iterator_tag to fix that.
+template <typename R> struct is_contiguous_range : std::false_type {};
+template <typename R>
+struct is_contiguous_range<R &> : is_contiguous_range<R> {};
+template <typename R>
+struct is_contiguous_range <R &&> : is_contiguous_range<R> {};
+template <typename R>
+struct is_contiguous_range<const R> : is_contiguous_range<R> {};
+
+template <typename T, size_t N>
+struct is_contiguous_range<T[N]> : std::true_type {};
+template <typename T, size_t N>
+struct is_contiguous_range<const T[N]> : std::true_type {};
+template <typename T, size_t N>
+struct is_contiguous_range<std::array<T, N> > : std::true_type {};
+template <typename charT, typename traits, typename Allocator>
+struct is_contiguous_range<
+ std::basic_string<charT, traits, Allocator> > : std::true_type {};
+template <typename T, typename Allocator>
+struct is_contiguous_range<std::vector<T, Allocator> > : std::true_type {};
+
+// Removes cv qualifiers from all levels of a multi-level pointer
+// type, not just the type level.
+template <typename T> struct remove_all_cv_ptr {
+ typedef T type;
+};
+template <typename T> struct remove_all_cv_ptr<T *> {
+ typedef typename remove_all_cv_ptr<T>::type *type;
+};
+template <typename T> struct remove_all_cv_ptr<const T> {
+ typedef typename remove_all_cv_ptr<T>::type type;
+};
+template <typename T> struct remove_all_cv_ptr<volatile T> {
+ typedef typename remove_all_cv_ptr<T>::type type;
+};
+template <typename T> struct remove_all_cv_ptr<const volatile T> {
+ typedef typename remove_all_cv_ptr<T>::type type;
+};
+
+template <typename From, typename To>
+struct conversion_preserves_array_indexing : std::false_type {};
+
+template <typename FromVal, typename ToVal>
+struct conversion_preserves_array_indexing<FromVal *,
+ ToVal *> : std::integral_constant<
+ bool, std::is_convertible<FromVal *, ToVal *>::value &&
+ std::is_same<typename remove_all_cv_ptr<FromVal>::type,
+ typename remove_all_cv_ptr<ToVal>::type>::value> {};
+
+template <typename T>
+LLVM_CONSTEXPR auto adl_begin(T &&t) -> decltype(begin(t)) {
+ return begin(std::forward<T>(t));
+}
+
+template <typename T> LLVM_CONSTEXPR auto adl_end(T &&t) -> decltype(end(t)) {
+ return end(std::forward<T>(t));
+}
+} // end namespace detail
+
+/// A \c std::range<Iterator> represents a half-open iterator range
+/// built from two iterators, \c 'begin', and \c 'end'. If \c end is
+/// not reachable from \c begin, the behavior is undefined.
+///
+/// The mutability of elements of the range is controlled by the
+/// Iterator argument. Instantiate
+/// <code>range<<var>Foo</var>::iterator></code> or
+/// <code>range<<var>T</var>*></code>, or call
+/// <code>make_range(<var>non_const_container</var>)</code>, and you
+/// get a mutable range. Instantiate
+/// <code>range<<var>Foo</var>::const_iterator></code> or
+/// <code>range<const <var>T</var>*></code>, or call
+/// <code>make_range(<var>const_container</var>)</code>, and you get a
+/// constant range.
+///
+/// \todo Inherit from std::pair<Iterator, Iterator>?
+///
+/// \todo This interface contains some functions that could be
+/// provided as free algorithms rather than member functions, and all
+/// of the <code>pop_*()</code> functions could be replaced by \c
+/// slice() at the cost of some extra iterator copies. This makes
+/// them more awkward to use, but makes it easier for users to write
+/// their own types that follow the same interface. On the other hand,
+/// a \c range_facade could be provided to help users write new
+/// ranges, and it could provide the members. Such functions are
+/// marked with a note in their documentation. (Of course, all of
+/// these member functions could be provided as free functions using
+/// the iterator access methods, but one goal here is to allow people
+/// to program without touching iterators at all.)
+template <typename Iterator> class range {
+ Iterator begin_, end_;
+public:
+ /// \name types
+ /// @{
+
+ /// The iterator category of \c Iterator.
+ /// \todo Consider defining range categories. If they don't add
+ /// anything over the corresponding iterator categories, then
+ /// they're probably not worth defining.
+ typedef typename std::iterator_traits<
+ Iterator>::iterator_category iterator_category;
+ /// The type of elements of the range. Not cv-qualified.
+ typedef typename std::iterator_traits<Iterator>::value_type value_type;
+ /// The type of the size of the range and offsets within the range.
+ typedef typename std::iterator_traits<
+ Iterator>::difference_type difference_type;
+ /// The return type of element access methods: \c front(), \c back(), etc.
+ typedef typename std::iterator_traits<Iterator>::reference reference;
+ typedef typename std::iterator_traits<Iterator>::pointer pointer;
+ /// @}
+
+ /// \name constructors
+ /// @{
+
+ /// Creates a range of default-constructed (<em>not</em>
+ /// value-initialized) iterators. For most \c Iterator types, this
+ /// will be an invalid range.
+ range() : begin_(), end_() {}
+
+ /// \pre \c end is reachable from \c begin.
+ /// \post <code>this->begin() == begin && this->end() == end</code>
+ LLVM_CONSTEXPR range(Iterator begin, Iterator end)
+ : begin_(begin), end_(end) {}
+
+ /// \par Participates in overload resolution if:
+ /// - \c Iterator is not a pointer type,
+ /// - \c begin(r) and \c end(r) return the same type, and
+ /// - that type is convertible to \c Iterator.
+ ///
+ /// \todo std::begin and std::end are overloaded between T& and
+ /// const T&, which means that if a container has only a non-const
+ /// begin or end method, then it's ill-formed to pass an rvalue to
+ /// the free function. To avoid that problem, we don't use
+ /// std::forward<> here, so begin() and end() are always called with
+ /// an lvalue. Another option would be to insist that rvalue
+ /// arguments to range() must have const begin() and end() methods.
+ template <typename R> LLVM_CONSTEXPR range(
+ R &&r,
+ typename std::enable_if<
+ !std::is_pointer<Iterator>::value &&
+ detail::is_range<R>::value &&
+ std::is_convertible<typename detail::begin_result<R>::type,
+ Iterator>::value>::type* = 0)
+ : begin_(detail::adl_begin(r)), end_(detail::adl_end(r)) {}
+
+ /// This constructor creates a \c range<T*> from any range with
+ /// contiguous iterators. Because dereferencing a past-the-end
+ /// iterator can be undefined behavior, empty ranges get initialized
+ /// with \c nullptr rather than \c &*begin().
+ ///
+ /// \par Participates in overload resolution if:
+ /// - \c Iterator is a pointer type \c T*,
+ /// - \c begin(r) and \c end(r) return the same type,
+ /// - elements \c i of that type satisfy the invariant
+ /// <code>&*(i + N) == (&*i) + N</code>, and
+ /// - The result of <code>&*begin()</code> is convertible to \c T*
+ /// using only qualification conversions [conv.qual] (since
+ /// pointer conversions stop the pointer from pointing to an
+ /// array element).
+ ///
+ /// \todo The <code>&*(i + N) == (&*i) + N</code> invariant is
+ /// currently impossible to check for user-defined types. We need a
+ /// \c contiguous_iterator_tag to let users assert it.
+ template <typename R> LLVM_CONSTEXPR range(
+ R &&r,
+ typename std::enable_if<
+ std::is_pointer<Iterator>::value &&
+ detail::is_contiguous_range<R>::value
+ // MSVC returns false for this in this context, but not if we lift it out of the
+ // constructor.
+#ifndef _MSC_VER
+ && detail::conversion_preserves_array_indexing<
+ decltype(&*detail::adl_begin(r)), Iterator>::value
+#endif
+ >::type* = 0)
+ : begin_((detail::adl_begin(r) == detail::adl_end(r) &&
+ !std::is_pointer<decltype(detail::adl_begin(r))>::value)
+ // For non-pointers, &*begin(r) is only defined behavior
+ // if there's an element there. Otherwise, use nullptr
+ // since the user can't dereference it anyway. This _is_
+ // detectable.
+ ? nullptr : &*detail::adl_begin(r)),
+ end_(begin_ + (detail::adl_end(r) - detail::adl_begin(r))) {}
+
+ /// @}
+
+ /// \name iterator access
+ /// @{
+ LLVM_CONSTEXPR Iterator begin() const { return begin_; }
+ LLVM_CONSTEXPR Iterator end() const { return end_; }
+ /// @}
+
+ /// \name element access
+ /// @{
+
+ /// \par Complexity:
+ /// O(1)
+ /// \pre \c !empty()
+ /// \returns a reference to the element at the front of the range.
+ LLVM_CONSTEXPR reference front() const { return *begin(); }
+
+ /// \par Ill-formed unless:
+ /// \c iterator_category is convertible to \c
+ /// std::bidirectional_iterator_tag.
+ ///
+ /// \par Complexity:
+ /// O(2) (Involves copying and decrementing an iterator, so not
+ /// quite as cheap as \c front())
+ ///
+ /// \pre \c !empty()
+ /// \returns a reference to the element at the front of the range.
+ LLVM_CONSTEXPR reference back() const {
+ static_assert(
+ std::is_convertible<iterator_category,
+ std::bidirectional_iterator_tag>::value,
+ "Can only retrieve the last element of a bidirectional range.");
+ using std::prev;
+ return *prev(end());
+ }
+
+ /// This method is drawn from scripting language indexing. It
+ /// indexes std::forward from the beginning of the range if the argument
+ /// is positive, or backwards from the end of the array if the
+ /// argument is negative.
+ ///
+ /// \par Ill-formed unless:
+ /// \c iterator_category is convertible to \c
+ /// std::random_access_iterator_tag.
+ ///
+ /// \par Complexity:
+ /// O(1)
+ ///
+ /// \pre <code>abs(index) < size() || index == -size()</code>
+ ///
+ /// \returns if <code>index >= 0</code>, a reference to the
+ /// <code>index</code>'th element in the range. Otherwise, a
+ /// reference to the <code>size()+index</code>'th element.
+ LLVM_CONSTEXPR reference operator[](difference_type index) const {
+ static_assert(std::is_convertible<iterator_category,
+ std::random_access_iterator_tag>::value,
+ "Can only index into a random-access range.");
+ // Less readable construction for constexpr support.
+ return index < 0 ? end()[index]
+ : begin()[index];
+ }
+ /// @}
+
+ /// \name size
+ /// @{
+
+ /// \par Complexity:
+ /// O(1)
+ /// \returns \c true if the range contains no elements.
+ LLVM_CONSTEXPR bool empty() const { return begin() == end(); }
+
+ /// \par Ill-formed unless:
+ /// \c iterator_category is convertible to
+ /// \c std::forward_iterator_tag.
+ ///
+ /// \par Complexity:
+ /// O(1) if \c iterator_category is convertible to \c
+ /// std::random_access_iterator_tag. O(<code>size()</code>)
+ /// otherwise.
+ ///
+ /// \returns the number of times \c pop_front() can be called before
+ /// \c empty() becomes true.
+ LLVM_CONSTEXPR difference_type size() const {
+ static_assert(std::is_convertible<iterator_category,
+ std::forward_iterator_tag>::value,
+ "Calling size on an input range would destroy the range.");
+ return dispatch_size(iterator_category());
+ }
+ /// @}
+
+ /// \name traversal from the beginning of the range
+ /// @{
+
+ /// Advances the beginning of the range by one element.
+ /// \pre \c !empty()
+ void pop_front() { ++begin_; }
+
+ /// Advances the beginning of the range by \c n elements.
+ ///
+ /// \par Complexity:
+ /// O(1) if \c iterator_category is convertible to \c
+ /// std::random_access_iterator_tag, O(<code>n</code>) otherwise.
+ ///
+ /// \pre <code>n >= 0</code>, and there must be at least \c n
+ /// elements in the range.
+ void pop_front(difference_type n) { advance(begin_, n); }
+
+ /// Advances the beginning of the range by at most \c n elements,
+ /// stopping if the range becomes empty. A negative argument causes
+ /// no change.
+ ///
+ /// \par Complexity:
+ /// O(1) if \c iterator_category is convertible to \c
+ /// std::random_access_iterator_tag, O(<code>min(n,
+ /// <var>#-elements-in-range</var>)</code>) otherwise.
+ ///
+ /// \note Could be provided as a free function with little-to-no
+ /// loss in efficiency.
+ void pop_front_upto(difference_type n) {
+ advance_upto(begin_, std::max<difference_type>(0, n), end_,
+ iterator_category());
+ }
+
+ /// @}
+
+ /// \name traversal from the end of the range
+ /// @{
+
+ /// Moves the end of the range earlier by one element.
+ ///
+ /// \par Ill-formed unless:
+ /// \c iterator_category is convertible to
+ /// \c std::bidirectional_iterator_tag.
+ ///
+ /// \par Complexity:
+ /// O(1)
+ ///
+ /// \pre \c !empty()
+ void pop_back() {
+ static_assert(std::is_convertible<iterator_category,
+ std::bidirectional_iterator_tag>::value,
+ "Can only access the end of a bidirectional range.");
+ --end_;
+ }
+
+ /// Moves the end of the range earlier by \c n elements.
+ ///
+ /// \par Ill-formed unless:
+ /// \c iterator_category is convertible to
+ /// \c std::bidirectional_iterator_tag.
+ ///
+ /// \par Complexity:
+ /// O(1) if \c iterator_category is convertible to \c
+ /// std::random_access_iterator_tag, O(<code>n</code>) otherwise.
+ ///
+ /// \pre <code>n >= 0</code>, and there must be at least \c n
+ /// elements in the range.
+ void pop_back(difference_type n) {
+ static_assert(std::is_convertible<iterator_category,
+ std::bidirectional_iterator_tag>::value,
+ "Can only access the end of a bidirectional range.");
+ advance(end_, -n);
+ }
+
+ /// Moves the end of the range earlier by <code>min(n,
+ /// size())</code> elements. A negative argument causes no change.
+ ///
+ /// \par Ill-formed unless:
+ /// \c iterator_category is convertible to
+ /// \c std::bidirectional_iterator_tag.
+ ///
+ /// \par Complexity:
+ /// O(1) if \c iterator_category is convertible to \c
+ /// std::random_access_iterator_tag, O(<code>min(n,
+ /// <var>#-elements-in-range</var>)</code>) otherwise.
+ ///
+ /// \note Could be provided as a free function with little-to-no
+ /// loss in efficiency.
+ void pop_back_upto(difference_type n) {
+ static_assert(std::is_convertible<iterator_category,
+ std::bidirectional_iterator_tag>::value,
+ "Can only access the end of a bidirectional range.");
+ advance_upto(end_, -std::max<difference_type>(0, n), begin_,
+ iterator_category());
+ }
+
+ /// @}
+
+ /// \name creating derived ranges
+ /// @{
+
+ /// Divides the range into two pieces at \c index, where a positive
+ /// \c index represents an offset from the beginning of the range
+ /// and a negative \c index represents an offset from the end.
+ /// <code>range[index]</code> is the first element in the second
+ /// piece. If <code>index >= size()</code>, the second piece
+ /// will be empty. If <code>index < -size()</code>, the first
+ /// piece will be empty.
+ ///
+ /// \par Ill-formed unless:
+ /// \c iterator_category is convertible to
+ /// \c std::forward_iterator_tag.
+ ///
+ /// \par Complexity:
+ /// - If \c iterator_category is convertible to \c
+ /// std::random_access_iterator_tag: O(1)
+ /// - Otherwise, if \c iterator_category is convertible to \c
+ /// std::bidirectional_iterator_tag, \c abs(index) iterator increments
+ /// or decrements
+ /// - Otherwise, if <code>index >= 0</code>, \c index iterator
+ /// increments
+ /// - Otherwise, <code>size() + (size() + index)</code>
+ /// iterator increments.
+ ///
+ /// \returns a pair of adjacent ranges.
+ ///
+ /// \post
+ /// - <code>result.first.size() == min(index, this->size())</code>
+ /// - <code>result.first.end() == result.second.begin()</code>
+ /// - <code>result.first.size() + result.second.size()</code> <code>==
+ /// this->size()</code>
+ ///
+ /// \todo split() could take an arbitrary number of indices and
+ /// return an <code>N+1</code>-element \c tuple<>. This is tricky to
+ /// implement with negative indices in the optimal number of
+ /// increments or decrements for a bidirectional iterator, but it
+ /// should be possible. Do we want it?
+ std::pair<range, range> split(difference_type index) const {
+ static_assert(
+ std::is_convertible<iterator_category,
+ std::forward_iterator_tag>::value,
+ "Calling split on a non-std::forward range would return a useless "
+ "first result.");
+ if (index >= 0) {
+ range second = *this;
+ second.pop_front_upto(index);
+ return make_pair(range(begin(), second.begin()), second);
+ } else {
+ return dispatch_split_neg(index, iterator_category());
+ }
+ }
+
+ /// \returns A sub-range from \c start to \c stop (not including \c
+ /// stop, as usual). \c start and \c stop are interpreted as for
+ /// <code>operator[]</code>, with negative values offsetting from
+ /// the end of the range. Omitting the \c stop argument makes the
+ /// sub-range continue to the end of the original range. Positive
+ /// arguments saturate to the end of the range, and negative
+ /// arguments saturate to the beginning. If \c stop is before \c
+ /// start, returns an empty range beginning and ending at \c start.
+ ///
+ /// \par Ill-formed unless:
+ /// \c iterator_category is convertible to
+ /// \c std::forward_iterator_tag.
+ ///
+ /// \par Complexity:
+ /// - If \c iterator_category is convertible to \c
+ /// std::random_access_iterator_tag: O(1)
+ /// - Otherwise, if \c iterator_category is convertible to \c
+ /// std::bidirectional_iterator_tag, at most <code>min(abs(start),
+ /// size()) + min(abs(stop), size())</code> iterator
+ /// increments or decrements
+ /// - Otherwise, if <code>start >= 0 && stop >= 0</code>,
+ /// <code>max(start, stop)</code> iterator increments
+ /// - Otherwise, <code>size() + max(start', stop')</code>
+ /// iterator increments, where \c start' and \c stop' are the
+ /// offsets of the elements \c start and \c stop refer to.
+ ///
+ /// \note \c slice(start) should be implemented with a different
+ /// overload, rather than defaulting \c stop to
+ /// <code>numeric_limits<difference_type>::max()</code>, because
+ /// using a default would force non-random-access ranges to use an
+ /// O(<code>size()</code>) algorithm to compute the end rather
+ /// than the O(1) they're capable of.
+ range slice(difference_type start, difference_type stop) const {
+ static_assert(
+ std::is_convertible<iterator_category,
+ std::forward_iterator_tag>::value,
+ "Calling slice on a non-std::forward range would destroy the original "
+ "range.");
+ return dispatch_slice(start, stop, iterator_category());
+ }
+
+ range slice(difference_type start) const {
+ static_assert(
+ std::is_convertible<iterator_category,
+ std::forward_iterator_tag>::value,
+ "Calling slice on a non-std::forward range would destroy the original "
+ "range.");
+ return split(start).second;
+ }
+
+ /// @}
+
+private:
+ // advance_upto: should be added to <algorithm>, but I'll use it as
+ // a helper function here.
+ //
+ // These return the number of increments that weren't applied
+ // because we ran into 'limit' (or 0 if we didn't run into limit).
+ static difference_type advance_upto(Iterator &it, difference_type n,
+ Iterator limit, std::input_iterator_tag) {
+ if (n < 0)
+ return 0;
+ while (it != limit && n > 0) {
+ ++it;
+ --n;
+ }
+ return n;
+ }
+
+ static difference_type advance_upto(Iterator &it, difference_type n,
+ Iterator limit,
+ std::bidirectional_iterator_tag) {
+ if (n < 0) {
+ while (it != limit && n < 0) {
+ --it;
+ ++n;
+ }
+ } else {
+ while (it != limit && n > 0) {
+ ++it;
+ --n;
+ }
+ }
+ return n;
+ }
+
+ static difference_type advance_upto(Iterator &it, difference_type n,
+ Iterator limit,
+ std::random_access_iterator_tag) {
+ difference_type distance = limit - it;
+ if (distance < 0)
+ assert(n <= 0);
+ else if (distance > 0)
+ assert(n >= 0);
+
+ if (abs(distance) > abs(n)) {
+ it += n;
+ return 0;
+ } else {
+ it = limit;
+ return n - distance;
+ }
+ }
+
+ // Dispatch functions.
+ difference_type dispatch_size(std::forward_iterator_tag) const {
+ return std::distance(begin(), end());
+ }
+
+ LLVM_CONSTEXPR difference_type dispatch_size(
+ std::random_access_iterator_tag) const {
+ return end() - begin();
+ }
+
+ std::pair<range, range> dispatch_split_neg(difference_type index,
+ std::forward_iterator_tag) const {
+ assert(index < 0);
+ difference_type size = this->size();
+ return split(std::max<difference_type>(0, size + index));
+ }
+
+ std::pair<range, range> dispatch_split_neg(
+ difference_type index, std::bidirectional_iterator_tag) const {
+ assert(index < 0);
+ range first = *this;
+ first.pop_back_upto(-index);
+ return make_pair(first, range(first.end(), end()));
+ }
+
+ range dispatch_slice(difference_type start, difference_type stop,
+ std::forward_iterator_tag) const {
+ if (start < 0 || stop < 0) {
+ difference_type size = this->size();
+ if (start < 0)
+ start = std::max<difference_type>(0, size + start);
+ if (stop < 0)
+ stop = size + stop; // Possibly negative; will be fixed in 2 lines.
+ }
+ stop = std::max<difference_type>(start, stop);
+
+ Iterator first = begin();
+ advance_upto(first, start, end(), iterator_category());
+ Iterator last = first;
+ advance_upto(last, stop - start, end(), iterator_category());
+ return range(first, last);
+ }
+
+ range dispatch_slice(const difference_type start, const difference_type stop,
+ std::bidirectional_iterator_tag) const {
+ Iterator first;
+ if (start < 0) {
+ first = end();
+ advance_upto(first, start, begin(), iterator_category());
+ } else {
+ first = begin();
+ advance_upto(first, start, end(), iterator_category());
+ }
+ Iterator last;
+ if (stop < 0) {
+ last = end();
+ advance_upto(last, stop, first, iterator_category());
+ } else {
+ if (start >= 0) {
+ last = first;
+ if (stop > start)
+ advance_upto(last, stop - start, end(), iterator_category());
+ } else {
+ // Complicated: 'start' walked from the end of the sequence,
+ // but 'stop' needs to walk from the beginning.
+ Iterator dummy = begin();
+ // Walk up to 'stop' increments from begin(), stopping when we
+ // get to 'first', and capturing the remaining number of
+ // increments.
+ difference_type increments_past_start =
+ advance_upto(dummy, stop, first, iterator_category());
+ if (increments_past_start == 0) {
+ // If this is 0, then stop was before start.
+ last = first;
+ } else {
+ // Otherwise, count that many spaces beyond first.
+ last = first;
+ advance_upto(last, increments_past_start, end(), iterator_category());
+ }
+ }
+ }
+ return range(first, last);
+ }
+
+ range dispatch_slice(difference_type start, difference_type stop,
+ std::random_access_iterator_tag) const {
+ const difference_type size = this->size();
+ if (start < 0)
+ start = size + start;
+ if (start < 0)
+ start = 0;
+ if (start > size)
+ start = size;
+
+ if (stop < 0)
+ stop = size + stop;
+ if (stop < start)
+ stop = start;
+ if (stop > size)
+ stop = size;
+
+ return range(begin() + start, begin() + stop);
+ }
+};
+
+/// \name deducing constructor wrappers
+/// \relates std::range
+/// \xmlonly <nonmember/> \endxmlonly
+///
+/// These functions do the same thing as the constructor with the same
+/// signature. They just allow users to avoid writing the iterator
+/// type.
+/// @{
+
+/// \todo I'd like to define a \c make_range taking a single iterator
+/// argument representing the beginning of a range that ends with a
+/// default-constructed \c Iterator. This would help with using
+/// iterators like \c istream_iterator. However, using just \c
+/// make_range() could be confusing and lead to people writing
+/// incorrect ranges of more common iterators. Is there a better name?
+template <typename Iterator>
+LLVM_CONSTEXPR range<Iterator> make_range(Iterator begin, Iterator end) {
+ return range<Iterator>(begin, end);
+}
+
+/// \par Participates in overload resolution if:
+/// \c begin(r) and \c end(r) return the same type.
+template <typename Range> LLVM_CONSTEXPR auto make_range(
+ Range &&r,
+ typename std::enable_if<detail::is_range<Range>::value>::type* = 0)
+ -> range<decltype(detail::adl_begin(r))> {
+ return range<decltype(detail::adl_begin(r))>(r);
+}
+
+/// \par Participates in overload resolution if:
+/// - \c begin(r) and \c end(r) return the same type,
+/// - that type satisfies the invariant that <code>&*(i + N) ==
+/// (&*i) + N</code>, and
+/// - \c &*begin(r) has a pointer type.
+template <typename Range> LLVM_CONSTEXPR auto make_ptr_range(
+ Range &&r,
+ typename std::enable_if<
+ detail::is_contiguous_range<Range>::value &&
+ std::is_pointer<decltype(&*detail::adl_begin(r))>::value>::type* = 0)
+ -> range<decltype(&*detail::adl_begin(r))> {
+ return range<decltype(&*detail::adl_begin(r))>(r);
+}
+/// @}
+} // end namespace lld
+
+#endif
diff --git a/include/lld/Driver/Driver.h b/include/lld/Driver/Driver.h
new file mode 100644
index 000000000000..300d2356d050
--- /dev/null
+++ b/include/lld/Driver/Driver.h
@@ -0,0 +1,162 @@
+//===- lld/Driver/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.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+///
+/// Interface for Drivers which convert command line arguments into
+/// LinkingContext objects, then perform the link.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_DRIVER_DRIVER_H
+#define LLD_DRIVER_DRIVER_H
+
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Node.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/raw_ostream.h"
+#include <memory>
+#include <set>
+#include <vector>
+
+namespace lld {
+class LinkingContext;
+class CoreLinkingContext;
+class MachOLinkingContext;
+class PECOFFLinkingContext;
+class ELFLinkingContext;
+
+typedef std::vector<std::unique_ptr<File>> FileVector;
+
+FileVector makeErrorFile(StringRef path, std::error_code ec);
+FileVector parseMemberFiles(FileVector &files);
+FileVector loadFile(LinkingContext &ctx, StringRef path, bool wholeArchive);
+
+/// Base class for all Drivers.
+class Driver {
+protected:
+
+ /// Performs link using specified options
+ static bool link(LinkingContext &context,
+ raw_ostream &diag = llvm::errs());
+
+private:
+ Driver() = delete;
+};
+
+/// Driver for "universal" lld tool which can mimic any linker command line
+/// parsing once it figures out which command line flavor to use.
+class UniversalDriver : public Driver {
+public:
+ /// Determine flavor and pass control to Driver for that flavor.
+ static bool link(int argc, const char *argv[],
+ raw_ostream &diag = llvm::errs());
+
+private:
+ UniversalDriver() = delete;
+};
+
+/// Driver for gnu/binutil 'ld' command line options.
+class GnuLdDriver : public Driver {
+public:
+ /// Parses command line arguments same as gnu/binutils ld and performs link.
+ /// Returns true iff an error occurred.
+ static bool linkELF(int argc, const char *argv[],
+ raw_ostream &diag = llvm::errs());
+
+ /// Uses gnu/binutils style ld command line options to fill in options struct.
+ /// Returns true iff there was an error.
+ static bool parse(int argc, const char *argv[],
+ std::unique_ptr<ELFLinkingContext> &context,
+ raw_ostream &diag = llvm::errs());
+
+ /// Parses a given memory buffer as a linker script and evaluate that.
+ /// Public function for testing.
+ static std::error_code evalLinkerScript(ELFLinkingContext &ctx,
+ std::unique_ptr<MemoryBuffer> mb,
+ raw_ostream &diag, bool nostdlib);
+
+ /// A factory method to create an instance of ELFLinkingContext.
+ static std::unique_ptr<ELFLinkingContext>
+ createELFLinkingContext(llvm::Triple triple);
+
+private:
+ static llvm::Triple getDefaultTarget(const char *progName);
+ static bool applyEmulation(llvm::Triple &triple,
+ llvm::opt::InputArgList &args,
+ raw_ostream &diag);
+ static void addPlatformSearchDirs(ELFLinkingContext &ctx,
+ llvm::Triple &triple,
+ llvm::Triple &baseTriple);
+
+ GnuLdDriver() = delete;
+};
+
+/// Driver for darwin/ld64 'ld' command line options.
+class DarwinLdDriver : public Driver {
+public:
+ /// Parses command line arguments same as darwin's ld and performs link.
+ /// Returns true iff there was an error.
+ static bool linkMachO(int argc, const char *argv[],
+ raw_ostream &diag = llvm::errs());
+
+ /// Uses darwin style ld command line options to update LinkingContext object.
+ /// Returns true iff there was an error.
+ static bool parse(int argc, const char *argv[], MachOLinkingContext &info,
+ raw_ostream &diag = llvm::errs());
+
+private:
+ DarwinLdDriver() = delete;
+};
+
+/// Driver for Windows 'link.exe' command line options
+class WinLinkDriver : public Driver {
+public:
+ /// Parses command line arguments same as Windows link.exe and performs link.
+ /// Returns true iff there was an error.
+ static bool linkPECOFF(int argc, const char *argv[],
+ raw_ostream &diag = llvm::errs());
+
+ /// Uses Windows style link command line options to fill in options struct.
+ /// Returns true iff there was an error.
+ static bool parse(int argc, const char *argv[], PECOFFLinkingContext &info,
+ raw_ostream &diag = llvm::errs(),
+ bool isDirective = false);
+
+ // Same as parse(), but restricted to the context of directives.
+ static bool parseDirectives(int argc, const char *argv[],
+ PECOFFLinkingContext &info,
+ raw_ostream &diag = llvm::errs()) {
+ return parse(argc, argv, info, diag, true);
+ }
+
+private:
+ WinLinkDriver() = delete;
+};
+
+/// Driver for lld unit tests
+class CoreDriver : public Driver {
+public:
+ /// Parses command line arguments same as lld-core and performs link.
+ /// Returns true iff there was an error.
+ static bool link(int argc, const char *argv[],
+ raw_ostream &diag = llvm::errs());
+
+ /// Uses lld-core command line options to fill in options struct.
+ /// Returns true iff there was an error.
+ static bool parse(int argc, const char *argv[], CoreLinkingContext &info,
+ raw_ostream &diag = llvm::errs());
+
+private:
+ CoreDriver() = delete;
+};
+
+} // end namespace lld
+
+#endif
diff --git a/include/lld/Driver/WinLinkModuleDef.h b/include/lld/Driver/WinLinkModuleDef.h
new file mode 100644
index 000000000000..68c9a4bfef70
--- /dev/null
+++ b/include/lld/Driver/WinLinkModuleDef.h
@@ -0,0 +1,200 @@
+//===- lld/Driver/WinLinkModuleDef.h --------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Windows module definition file parser.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_DRIVER_WIN_LINK_MODULE_DEF_H
+#define LLD_DRIVER_WIN_LINK_MODULE_DEF_H
+
+#include "lld/Core/LLVM.h"
+#include "lld/ReaderWriter/PECOFFLinkingContext.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/Support/Allocator.h"
+#include <vector>
+
+namespace lld {
+namespace moduledef {
+
+enum class Kind {
+ unknown,
+ eof,
+ identifier,
+ comma,
+ equal,
+ kw_base,
+ kw_data,
+ kw_exports,
+ kw_heapsize,
+ kw_library,
+ kw_name,
+ kw_noname,
+ kw_private,
+ kw_stacksize,
+ kw_version,
+};
+
+class Token {
+public:
+ Token() : _kind(Kind::unknown) {}
+ Token(Kind kind, StringRef range) : _kind(kind), _range(range) {}
+
+ Kind _kind;
+ StringRef _range;
+};
+
+class Lexer {
+public:
+ explicit Lexer(std::unique_ptr<MemoryBuffer> mb) : _buffer(mb->getBuffer()) {
+ _sourceManager.AddNewSourceBuffer(std::move(mb), llvm::SMLoc());
+ }
+
+ Token lex();
+ const llvm::SourceMgr &getSourceMgr() const { return _sourceManager; }
+
+private:
+ StringRef _buffer;
+ llvm::SourceMgr _sourceManager;
+};
+
+class Directive {
+public:
+ enum class Kind { exports, heapsize, library, name, stacksize, version };
+
+ Kind getKind() const { return _kind; }
+ virtual ~Directive() {}
+
+protected:
+ explicit Directive(Kind k) : _kind(k) {}
+
+private:
+ Kind _kind;
+};
+
+class Exports : public Directive {
+public:
+ explicit Exports(const std::vector<PECOFFLinkingContext::ExportDesc> &exports)
+ : Directive(Kind::exports), _exports(exports) {}
+
+ static bool classof(const Directive *dir) {
+ return dir->getKind() == Kind::exports;
+ }
+
+ const std::vector<PECOFFLinkingContext::ExportDesc> &getExports() const {
+ return _exports;
+ }
+
+private:
+ const std::vector<PECOFFLinkingContext::ExportDesc> _exports;
+};
+
+template <Directive::Kind kind>
+class MemorySize : public Directive {
+public:
+ MemorySize(uint64_t reserve, uint64_t commit)
+ : Directive(kind), _reserve(reserve), _commit(commit) {}
+
+ static bool classof(const Directive *dir) {
+ return dir->getKind() == kind;
+ }
+
+ uint64_t getReserve() const { return _reserve; }
+ uint64_t getCommit() const { return _commit; }
+
+private:
+ const uint64_t _reserve;
+ const uint64_t _commit;
+};
+
+typedef MemorySize<Directive::Kind::heapsize> Heapsize;
+typedef MemorySize<Directive::Kind::stacksize> Stacksize;
+
+class Name : public Directive {
+public:
+ Name(StringRef outputPath, uint64_t baseaddr)
+ : Directive(Kind::name), _outputPath(outputPath), _baseaddr(baseaddr) {}
+
+ static bool classof(const Directive *dir) {
+ return dir->getKind() == Kind::name;
+ }
+
+ StringRef getOutputPath() const { return _outputPath; }
+ uint64_t getBaseAddress() const { return _baseaddr; }
+
+private:
+ const std::string _outputPath;
+ const uint64_t _baseaddr;
+};
+
+class Library : public Directive {
+public:
+ Library(StringRef name, uint64_t baseaddr)
+ : Directive(Kind::library), _name(name), _baseaddr(baseaddr) {}
+
+ static bool classof(const Directive *dir) {
+ return dir->getKind() == Kind::library;
+ }
+
+ StringRef getName() const { return _name; }
+ uint64_t getBaseAddress() const { return _baseaddr; }
+
+private:
+ const std::string _name;
+ const uint64_t _baseaddr;
+};
+
+class Version : public Directive {
+public:
+ Version(int major, int minor)
+ : Directive(Kind::version), _major(major), _minor(minor) {}
+
+ static bool classof(const Directive *dir) {
+ return dir->getKind() == Kind::version;
+ }
+
+ int getMajorVersion() const { return _major; }
+ int getMinorVersion() const { return _minor; }
+
+private:
+ const int _major;
+ const int _minor;
+};
+
+class Parser {
+public:
+ Parser(Lexer &lex, llvm::BumpPtrAllocator &alloc)
+ : _lex(lex), _alloc(alloc) {}
+
+ bool parse(std::vector<Directive *> &ret);
+
+private:
+ void consumeToken();
+ bool consumeTokenAsInt(uint64_t &result);
+ bool expectAndConsume(Kind kind, Twine msg);
+
+ void ungetToken();
+ void error(const Token &tok, Twine msg);
+
+ bool parseOne(Directive *&dir);
+ bool parseExport(PECOFFLinkingContext::ExportDesc &result);
+ bool parseMemorySize(uint64_t &reserve, uint64_t &commit);
+ bool parseName(std::string &outfile, uint64_t &baseaddr);
+ bool parseVersion(int &major, int &minor);
+
+ Lexer &_lex;
+ llvm::BumpPtrAllocator &_alloc;
+ Token _tok;
+ std::vector<Token> _tokBuf;
+};
+}
+}
+
+#endif
diff --git a/include/lld/Makefile b/include/lld/Makefile
new file mode 100644
index 000000000000..5bfb8910313e
--- /dev/null
+++ b/include/lld/Makefile
@@ -0,0 +1,44 @@
+LLD_LEVEL := ../..
+DIRS := Config
+
+include $(LLD_LEVEL)/Makefile
+
+install-local::
+ $(Echo) Installing lld include files
+ $(Verb) $(MKDIR) $(DESTDIR)$(PROJ_includedir)
+ $(Verb) if test -d "$(PROJ_SRC_DIR)" ; then \
+ cd $(PROJ_SRC_DIR)/.. && \
+ for hdr in `find lld -type f \
+ '(' -name LICENSE.TXT \
+ -o -name '*.def' \
+ -o -name '*.h' \
+ -o -name '*.inc' \
+ ')' -print \
+ | grep -v CVS | grep -v .svn | grep -v .dir` ; do \
+ instdir=$(DESTDIR)`dirname "$(PROJ_includedir)/$$hdr"` ; \
+ if test \! -d "$$instdir" ; then \
+ $(EchoCmd) Making install directory $$instdir ; \
+ $(MKDIR) $$instdir ;\
+ fi ; \
+ $(DataInstall) $$hdr $(DESTDIR)$(PROJ_includedir)/$$hdr ; \
+ done ; \
+ fi
+ifneq ($(PROJ_SRC_ROOT),$(PROJ_OBJ_ROOT))
+ $(Verb) if test -d "$(PROJ_OBJ_ROOT)/tools/lld/include/lld" ; then \
+ cd $(PROJ_OBJ_ROOT)/tools/lld/include && \
+ for hdr in `find lld -type f \
+ '(' -name LICENSE.TXT \
+ -o -name '*.def' \
+ -o -name '*.h' \
+ -o -name '*.inc' \
+ ')' -print \
+ | grep -v CVS | grep -v .tmp | grep -v .dir` ; do \
+ instdir=$(DESTDIR)`dirname "$(PROJ_includedir)/$$hdr"` ; \
+ if test \! -d "$$instdir" ; then \
+ $(EchoCmd) Making install directory $$instdir ; \
+ $(MKDIR) $$instdir ;\
+ fi ; \
+ $(DataInstall) $$hdr $(DESTDIR)$(PROJ_includedir)/$$hdr ; \
+ done ; \
+ fi
+endif
diff --git a/include/lld/ReaderWriter/AtomLayout.h b/include/lld/ReaderWriter/AtomLayout.h
new file mode 100644
index 000000000000..ad4cd0607b88
--- /dev/null
+++ b/include/lld/ReaderWriter/AtomLayout.h
@@ -0,0 +1,39 @@
+//===- include/lld/ReaderWriter/AtomLayout.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_ATOM_LAYOUT_H
+#define LLD_READER_WRITER_ATOM_LAYOUT_H
+
+namespace lld {
+class Atom;
+
+/// AtomLayouts are used by a writer to manage physical positions of atoms.
+/// AtomLayout has two positions; one is file offset, and the other is the
+/// address when loaded into memory.
+///
+/// Construction of AtomLayouts is usually a multi-pass process. When an atom
+/// is appended to a section, we don't know the starting address of the
+/// section. Thus, we have no choice but to store the offset from the
+/// beginning of the section as AtomLayout values. After all sections starting
+/// address are fixed, AtomLayout is revisited to get the offsets updated by
+/// adding the starting addresses of the section.
+struct AtomLayout {
+ AtomLayout(const Atom *a, uint64_t fileOff, uint64_t virAddr)
+ : _atom(a), _fileOffset(fileOff), _virtualAddr(virAddr) {}
+
+ AtomLayout() : _atom(nullptr), _fileOffset(0), _virtualAddr(0) {}
+
+ const Atom *_atom;
+ uint64_t _fileOffset;
+ uint64_t _virtualAddr;
+};
+
+}
+
+#endif
diff --git a/include/lld/ReaderWriter/CoreLinkingContext.h b/include/lld/ReaderWriter/CoreLinkingContext.h
new file mode 100644
index 000000000000..d597ca46ddc7
--- /dev/null
+++ b/include/lld/ReaderWriter/CoreLinkingContext.h
@@ -0,0 +1,47 @@
+//===- lld/ReaderWriter/CoreLinkingContext.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_CORE_LINKER_CONTEXT_H
+#define LLD_READER_WRITER_CORE_LINKER_CONTEXT_H
+
+#include "lld/Core/LinkingContext.h"
+#include "lld/Core/Reader.h"
+#include "lld/Core/Writer.h"
+#include "llvm/Support/ErrorHandling.h"
+
+namespace lld {
+
+class CoreLinkingContext : public LinkingContext {
+public:
+ CoreLinkingContext();
+
+ enum {
+ TEST_RELOC_CALL32 = 1,
+ TEST_RELOC_PCREL32 = 2,
+ TEST_RELOC_GOT_LOAD32 = 3,
+ TEST_RELOC_GOT_USE32 = 4,
+ TEST_RELOC_LEA32_WAS_GOT = 5,
+ };
+
+ bool validateImpl(raw_ostream &diagnostics) override;
+ void addPasses(PassManager &pm) override;
+
+ void addPassNamed(StringRef name) { _passNames.push_back(name); }
+
+protected:
+ Writer &writer() const override;
+
+private:
+ std::unique_ptr<Writer> _writer;
+ std::vector<StringRef> _passNames;
+};
+
+} // end namespace lld
+
+#endif
diff --git a/include/lld/ReaderWriter/ELFLinkingContext.h b/include/lld/ReaderWriter/ELFLinkingContext.h
new file mode 100644
index 000000000000..d1cd3d9f3d6b
--- /dev/null
+++ b/include/lld/ReaderWriter/ELFLinkingContext.h
@@ -0,0 +1,362 @@
+//===- lld/ReaderWriter/ELFLinkingContext.h -------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_LINKER_CONTEXT_H
+#define LLD_READER_WRITER_ELF_LINKER_CONTEXT_H
+
+#include "lld/Core/LinkingContext.h"
+#include "lld/Core/Pass.h"
+#include "lld/Core/PassManager.h"
+#include "lld/Core/STDExtras.h"
+#include "lld/Core/range.h"
+#include "lld/Core/Reader.h"
+#include "lld/Core/Writer.h"
+#include "lld/ReaderWriter/LinkerScript.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/ELF.h"
+#include <map>
+#include <memory>
+#include <set>
+
+namespace lld {
+class DefinedAtom;
+class Reference;
+class File;
+
+namespace elf {
+template <typename ELFT> class TargetHandler;
+}
+
+class TargetHandlerBase {
+public:
+ virtual ~TargetHandlerBase() {}
+ virtual void registerRelocationNames(Registry &) = 0;
+
+ virtual std::unique_ptr<Reader> getObjReader() = 0;
+
+ virtual std::unique_ptr<Reader> getDSOReader() = 0;
+
+ virtual std::unique_ptr<Writer> getWriter() = 0;
+};
+
+class ELFLinkingContext : public LinkingContext {
+public:
+ /// \brief The type of ELF executable that the linker
+ /// creates.
+ enum class OutputMagic : uint8_t {
+ DEFAULT, // The default mode, no specific magic set
+ NMAGIC, // Disallow shared libraries and don't align sections
+ // PageAlign Data, Mark Text Segment/Data segment RW
+ OMAGIC // Disallow shared libraries and don't align sections,
+ // Mark Text Segment/Data segment RW
+ };
+
+ llvm::Triple getTriple() const { return _triple; }
+
+ // Page size.
+ virtual uint64_t getPageSize() const {
+ if (_maxPageSize)
+ return *_maxPageSize;
+ return 0x1000;
+ }
+ virtual void setMaxPageSize(uint64_t pagesize) {
+ _maxPageSize = pagesize;
+ }
+ OutputMagic getOutputMagic() const { return _outputMagic; }
+ uint16_t getOutputELFType() const { return _outputELFType; }
+ uint16_t getOutputMachine() const;
+ bool mergeCommonStrings() const { return _mergeCommonStrings; }
+ virtual uint64_t getBaseAddress() const { return _baseAddress; }
+ virtual void setBaseAddress(uint64_t address) { _baseAddress = address; }
+
+ void notifySymbolTableCoalesce(const Atom *existingAtom, const Atom *newAtom,
+ bool &useNew) override;
+
+ /// This controls if undefined atoms need to be created for undefines that are
+ /// present in a SharedLibrary. If this option is set, undefined atoms are
+ /// created for every undefined symbol that are present in the dynamic table
+ /// in the shared library
+ bool useShlibUndefines() const { return _useShlibUndefines; }
+ /// @}
+
+ /// \brief Does this relocation belong in the dynamic relocation table?
+ ///
+ /// This table is evaluated at loadtime by the dynamic loader and is
+ /// referenced by the DT_RELA{,ENT,SZ} entries in the dynamic table.
+ /// Relocations that return true will be added to the dynamic relocation
+ /// table.
+ virtual bool isDynamicRelocation(const Reference &) const { return false; }
+
+ /// \brief Is this a copy relocation?
+ ///
+ /// If this is a copy relocation, its target must be an ObjectAtom. We must
+ /// include in DT_NEEDED the name of the library where this object came from.
+ virtual bool isCopyRelocation(const Reference &) const {
+ return false;
+ }
+
+ bool validateImpl(raw_ostream &diagnostics) override;
+
+ /// \brief Does the linker allow dynamic libraries to be linked with?
+ /// This is true when the output mode of the executable is set to be
+ /// having NMAGIC/OMAGIC
+ virtual bool allowLinkWithDynamicLibraries() const {
+ if (_outputMagic == OutputMagic::NMAGIC ||
+ _outputMagic == OutputMagic::OMAGIC || _noAllowDynamicLibraries)
+ return false;
+ return true;
+ }
+
+ /// \brief Use Elf_Rela format to output relocation tables.
+ virtual bool isRelaOutputFormat() const { return true; }
+
+ /// \brief Does this relocation belong in the dynamic plt relocation table?
+ ///
+ /// This table holds all of the relocations used for delayed symbol binding.
+ /// It will be evaluated at load time if LD_BIND_NOW is set. It is referenced
+ /// by the DT_{JMPREL,PLTRELSZ} entries in the dynamic table.
+ /// Relocations that return true will be added to the dynamic plt relocation
+ /// table.
+ virtual bool isPLTRelocation(const Reference &) const { return false; }
+
+ /// \brief The path to the dynamic interpreter
+ virtual StringRef getDefaultInterpreter() const {
+ return "/lib64/ld-linux-x86-64.so.2";
+ }
+
+ /// \brief The dynamic linker path set by the --dynamic-linker option
+ virtual StringRef getInterpreter() const {
+ if (_dynamicLinkerArg)
+ return _dynamicLinkerPath;
+ return getDefaultInterpreter();
+ }
+
+ /// \brief Does the output have dynamic sections.
+ virtual bool isDynamic() const;
+
+ /// \brief Are we creating a shared library?
+ virtual bool isDynamicLibrary() const {
+ return _outputELFType == llvm::ELF::ET_DYN;
+ }
+
+ /// \brief Is the relocation a relative relocation
+ virtual bool isRelativeReloc(const Reference &r) const;
+
+ template <typename ELFT>
+ lld::elf::TargetHandler<ELFT> &getTargetHandler() const {
+ assert(_targetHandler && "Got null TargetHandler!");
+ return static_cast<lld::elf::TargetHandler<ELFT> &>(*_targetHandler.get());
+ }
+
+ TargetHandlerBase *targetHandler() const { return _targetHandler.get(); }
+ void addPasses(PassManager &pm) override;
+
+ void setTriple(llvm::Triple trip) { _triple = trip; }
+ void setNoInhibitExec(bool v) { _noInhibitExec = v; }
+ void setExportDynamic(bool v) { _exportDynamic = v; }
+ void setIsStaticExecutable(bool v) { _isStaticExecutable = v; }
+ void setMergeCommonStrings(bool v) { _mergeCommonStrings = v; }
+ void setUseShlibUndefines(bool use) { _useShlibUndefines = use; }
+ void setOutputELFType(uint32_t type) { _outputELFType = type; }
+
+ bool shouldExportDynamic() const { return _exportDynamic; }
+
+ void createInternalFiles(std::vector<std::unique_ptr<File>> &) const override;
+
+ void finalizeInputFiles() override;
+
+ /// \brief Set the dynamic linker path
+ void setInterpreter(StringRef dynamicLinker) {
+ _dynamicLinkerArg = true;
+ _dynamicLinkerPath = dynamicLinker;
+ }
+
+ /// \brief Set NMAGIC output kind when the linker specifies --nmagic
+ /// or -n in the command line
+ /// Set OMAGIC output kind when the linker specifies --omagic
+ /// or -N in the command line
+ virtual void setOutputMagic(OutputMagic magic) { _outputMagic = magic; }
+
+ /// \brief Disallow dynamic libraries during linking
+ virtual void setNoAllowDynamicLibraries() { _noAllowDynamicLibraries = true; }
+
+ /// Searches directories for a match on the input File
+ ErrorOr<StringRef> searchLibrary(StringRef libName) const;
+
+ /// \brief Searches directories for a match on the input file.
+ /// If \p fileName is an absolute path and \p isSysRooted is true, check
+ /// the file under sysroot directory. If \p fileName is a relative path
+ /// and is not in the current directory, search the file through library
+ /// search directories.
+ ErrorOr<StringRef> searchFile(StringRef fileName, bool isSysRooted) const;
+
+ /// Get the entry symbol name
+ StringRef entrySymbolName() const override;
+
+ /// \brief Set new initializer function
+ void setInitFunction(StringRef name) { _initFunction = name; }
+
+ /// \brief Return an initializer function name.
+ /// Either default "_init" or configured by the -init command line option.
+ StringRef initFunction() const { return _initFunction; }
+
+ /// \brief Set new finalizer function
+ void setFiniFunction(StringRef name) { _finiFunction = name; }
+
+ /// \brief Return a finalizer function name.
+ /// Either default "_fini" or configured by the -fini command line option.
+ StringRef finiFunction() const { return _finiFunction; }
+
+ /// Add an absolute symbol. Used for --defsym.
+ void addInitialAbsoluteSymbol(StringRef name, uint64_t addr) {
+ _absoluteSymbols[name] = addr;
+ }
+
+ void setSharedObjectName(StringRef soname) {
+ _soname = soname;
+ }
+
+ StringRef sharedObjectName() const { return _soname; }
+
+ StringRef getSysroot() const { return _sysrootPath; }
+
+ /// \brief Set path to the system root
+ void setSysroot(StringRef path) {
+ _sysrootPath = path;
+ }
+
+ void addRpath(StringRef path) {
+ _rpathList.push_back(path);
+ }
+
+ range<const StringRef *> getRpathList() const {
+ return _rpathList;
+ }
+
+ void addRpathLink(StringRef path) {
+ _rpathLinkList.push_back(path);
+ }
+
+ range<const StringRef *> getRpathLinkList() const {
+ return _rpathLinkList;
+ }
+
+ const std::map<std::string, uint64_t> &getAbsoluteSymbols() const {
+ return _absoluteSymbols;
+ }
+
+ /// \brief Helper function to allocate strings.
+ StringRef allocateString(StringRef ref) const {
+ char *x = _allocator.Allocate<char>(ref.size() + 1);
+ memcpy(x, ref.data(), ref.size());
+ x[ref.size()] = '\0';
+ return x;
+ }
+
+ // add search path to list.
+ virtual bool addSearchPath(StringRef ref) {
+ _inputSearchPaths.push_back(ref);
+ return true;
+ }
+
+ // Retrieve search path list.
+ StringRefVector getSearchPaths() { return _inputSearchPaths; };
+
+ // By default, the linker would merge sections that are read only with
+ // segments that have read and execute permissions. When the user specifies a
+ // flag --rosegment, a separate segment needs to be created.
+ bool mergeRODataToTextSegment() const { return _mergeRODataToTextSegment; }
+
+ void setCreateSeparateROSegment() { _mergeRODataToTextSegment = false; }
+
+ bool isDynamicallyExportedSymbol(StringRef name) const {
+ return _dynamicallyExportedSymbols.count(name) != 0;
+ }
+
+ /// \brief Demangle symbols.
+ std::string demangle(StringRef symbolName) const override;
+ bool demangleSymbols() const { return _demangle; }
+ void setDemangleSymbols(bool d) { _demangle = d; }
+
+ /// \brief Align segments.
+ bool alignSegments() const { return _alignSegments; }
+ void setAlignSegments(bool align) { _alignSegments = align; }
+
+ /// \brief Strip symbols.
+ bool stripSymbols() const { return _stripSymbols; }
+ void setStripSymbols(bool strip) { _stripSymbols = strip; }
+
+ /// \brief Collect statistics.
+ bool collectStats() const { return _collectStats; }
+ void setCollectStats(bool s) { _collectStats = s; }
+
+ // --wrap option.
+ void addWrapForSymbol(StringRef sym) { _wrapCalls.insert(sym); }
+
+ const llvm::StringSet<> &wrapCalls() const { return _wrapCalls; }
+
+ void setUndefinesResolver(std::unique_ptr<File> resolver);
+
+ script::Sema &linkerScriptSema() { return _linkerScriptSema; }
+ const script::Sema &linkerScriptSema() const { return _linkerScriptSema; }
+
+private:
+ ELFLinkingContext() = delete;
+
+protected:
+ ELFLinkingContext(llvm::Triple, std::unique_ptr<TargetHandlerBase>);
+
+ Writer &writer() const override;
+
+ /// Method to create a internal file for an undefined symbol
+ std::unique_ptr<File> createUndefinedSymbolFile() const override;
+
+ uint16_t _outputELFType; // e.g ET_EXEC
+ llvm::Triple _triple;
+ std::unique_ptr<TargetHandlerBase> _targetHandler;
+ uint64_t _baseAddress;
+ bool _isStaticExecutable;
+ bool _noInhibitExec;
+ bool _exportDynamic;
+ bool _mergeCommonStrings;
+ bool _useShlibUndefines;
+ bool _dynamicLinkerArg;
+ bool _noAllowDynamicLibraries;
+ bool _mergeRODataToTextSegment;
+ bool _demangle;
+ bool _stripSymbols;
+ bool _alignSegments;
+ bool _nostdlib;
+ bool _collectStats;
+ llvm::Optional<uint64_t> _maxPageSize;
+
+ OutputMagic _outputMagic;
+ StringRefVector _inputSearchPaths;
+ std::unique_ptr<Writer> _writer;
+ StringRef _dynamicLinkerPath;
+ StringRef _initFunction;
+ StringRef _finiFunction;
+ StringRef _sysrootPath;
+ StringRef _soname;
+ StringRefVector _rpathList;
+ StringRefVector _rpathLinkList;
+ llvm::StringSet<> _wrapCalls;
+ std::map<std::string, uint64_t> _absoluteSymbols;
+ llvm::StringSet<> _dynamicallyExportedSymbols;
+ std::unique_ptr<File> _resolver;
+
+ // The linker script semantic object, which owns all script ASTs, is stored
+ // in the current linking context via _linkerScriptSema.
+ script::Sema _linkerScriptSema;
+};
+} // end namespace lld
+
+#endif
diff --git a/include/lld/ReaderWriter/ELFTargets.h b/include/lld/ReaderWriter/ELFTargets.h
new file mode 100644
index 000000000000..3d00339818e2
--- /dev/null
+++ b/include/lld/ReaderWriter/ELFTargets.h
@@ -0,0 +1,38 @@
+//===- lld/ReaderWriter/ELFTargets.h --------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_TARGETS_H
+#define LLD_READER_WRITER_ELF_TARGETS_H
+
+#include "ELFLinkingContext.h"
+
+namespace lld {
+namespace elf {
+
+#define LLVM_TARGET(TargetName) \
+ class TargetName##LinkingContext final : public ELFLinkingContext { \
+ public: \
+ static std::unique_ptr<ELFLinkingContext> create(llvm::Triple); \
+ };
+
+// FIXME: #include "llvm/Config/Targets.def"
+LLVM_TARGET(AArch64)
+LLVM_TARGET(ARM)
+LLVM_TARGET(Hexagon)
+LLVM_TARGET(Mips)
+LLVM_TARGET(X86)
+LLVM_TARGET(Example)
+LLVM_TARGET(X86_64)
+
+#undef LLVM_TARGET
+
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/include/lld/ReaderWriter/LinkerScript.h b/include/lld/ReaderWriter/LinkerScript.h
new file mode 100644
index 000000000000..ae8d18d830c6
--- /dev/null
+++ b/include/lld/ReaderWriter/LinkerScript.h
@@ -0,0 +1,1396 @@
+//===- ReaderWriter/LinkerScript.h ----------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Linker script parser.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_LINKER_SCRIPT_H
+#define LLD_READER_WRITER_LINKER_SCRIPT_H
+
+#include "lld/Core/Error.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/range.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/raw_ostream.h"
+#include <memory>
+#include <system_error>
+#include <unordered_map>
+#include <vector>
+
+namespace lld {
+namespace script {
+class Token {
+public:
+ enum Kind {
+ unknown,
+ eof,
+ exclaim,
+ exclaimequal,
+ amp,
+ ampequal,
+ l_paren,
+ r_paren,
+ star,
+ starequal,
+ plus,
+ plusequal,
+ comma,
+ minus,
+ minusequal,
+ slash,
+ slashequal,
+ number,
+ colon,
+ semicolon,
+ less,
+ lessequal,
+ lessless,
+ lesslessequal,
+ equal,
+ equalequal,
+ greater,
+ greaterequal,
+ greatergreater,
+ greatergreaterequal,
+ question,
+ identifier,
+ libname,
+ kw_align,
+ kw_align_with_input,
+ kw_as_needed,
+ kw_at,
+ kw_discard,
+ kw_entry,
+ kw_exclude_file,
+ kw_extern,
+ kw_group,
+ kw_hidden,
+ kw_input,
+ kw_keep,
+ kw_length,
+ kw_memory,
+ kw_origin,
+ kw_provide,
+ kw_provide_hidden,
+ kw_only_if_ro,
+ kw_only_if_rw,
+ kw_output,
+ kw_output_arch,
+ kw_output_format,
+ kw_overlay,
+ kw_search_dir,
+ kw_sections,
+ kw_sort_by_alignment,
+ kw_sort_by_init_priority,
+ kw_sort_by_name,
+ kw_sort_none,
+ kw_subalign,
+ l_brace,
+ pipe,
+ pipeequal,
+ r_brace,
+ tilde
+ };
+
+ Token() : _kind(unknown) {}
+ Token(StringRef range, Kind kind) : _range(range), _kind(kind) {}
+
+ void dump(raw_ostream &os) const;
+
+ StringRef _range;
+ Kind _kind;
+};
+
+class Lexer {
+public:
+ explicit Lexer(std::unique_ptr<MemoryBuffer> mb) : _buffer(mb->getBuffer()) {
+ _sourceManager.AddNewSourceBuffer(std::move(mb), llvm::SMLoc());
+ }
+
+ void lex(Token &tok);
+
+ const llvm::SourceMgr &getSourceMgr() const { return _sourceManager; }
+
+private:
+ bool canStartNumber(char c) const;
+ bool canContinueNumber(char c) const;
+ bool canStartName(char c) const;
+ bool canContinueName(char c) const;
+ void skipWhitespace();
+
+ Token _current;
+ /// \brief The current buffer state.
+ StringRef _buffer;
+ // Lexer owns the input files.
+ llvm::SourceMgr _sourceManager;
+};
+
+/// All linker scripts commands derive from this class. High-level, sections and
+/// output section commands are all subclasses of this class.
+/// Examples:
+///
+/// OUTPUT_FORMAT("elf64-x86-64") /* A linker script command */
+/// OUTPUT_ARCH(i386:x86-64) /* Another command */
+/// ENTRY(_start) /* Another command */
+///
+/// SECTIONS /* Another command */
+/// {
+/// .interp : { /* A sections-command */
+/// *(.interp) /* An output-section-command */
+/// }
+/// }
+///
+class Command {
+public:
+ enum class Kind {
+ Entry,
+ Extern,
+ Group,
+ Input,
+ InputSectionsCmd,
+ InputSectionName,
+ Memory,
+ Output,
+ OutputArch,
+ OutputFormat,
+ OutputSectionDescription,
+ Overlay,
+ SearchDir,
+ Sections,
+ SortedGroup,
+ SymbolAssignment,
+ };
+
+ Kind getKind() const { return _kind; }
+ inline llvm::BumpPtrAllocator &getAllocator() const;
+
+ virtual void dump(raw_ostream &os) const = 0;
+
+ virtual ~Command() {}
+
+protected:
+ Command(class Parser &ctx, Kind k) : _ctx(ctx), _kind(k) {}
+
+private:
+ Parser &_ctx;
+ Kind _kind;
+};
+
+class Output : public Command {
+public:
+ Output(Parser &ctx, StringRef outputFileName)
+ : Command(ctx, Kind::Output), _outputFileName(outputFileName) {}
+
+ static bool classof(const Command *c) { return c->getKind() == Kind::Output; }
+
+ void dump(raw_ostream &os) const override {
+ os << "OUTPUT(" << _outputFileName << ")\n";
+ }
+
+ StringRef getOutputFileName() const { return _outputFileName; }
+
+private:
+ StringRef _outputFileName;
+};
+
+class OutputFormat : public Command {
+public:
+ OutputFormat(Parser &ctx, const SmallVectorImpl<StringRef> &formats)
+ : Command(ctx, Kind::OutputFormat) {
+ size_t numFormats = formats.size();
+ StringRef *formatsStart = getAllocator().Allocate<StringRef>(numFormats);
+ std::copy(std::begin(formats), std::end(formats), formatsStart);
+ _formats = llvm::makeArrayRef(formatsStart, numFormats);
+ }
+
+ static bool classof(const Command *c) {
+ return c->getKind() == Kind::OutputFormat;
+ }
+
+ void dump(raw_ostream &os) const override {
+ os << "OUTPUT_FORMAT(";
+ bool first = true;
+ for (StringRef format : _formats) {
+ if (!first)
+ os << ",";
+ first = false;
+ os << "\"" << format << "\"";
+ }
+ os << ")\n";
+ }
+
+ llvm::ArrayRef<StringRef> getFormats() { return _formats; }
+
+private:
+ llvm::ArrayRef<StringRef> _formats;
+};
+
+class OutputArch : public Command {
+public:
+ OutputArch(Parser &ctx, StringRef arch)
+ : Command(ctx, Kind::OutputArch), _arch(arch) {}
+
+ static bool classof(const Command *c) {
+ return c->getKind() == Kind::OutputArch;
+ }
+
+ void dump(raw_ostream &os) const override {
+ os << "OUTPUT_ARCH(" << getArch() << ")\n";
+ }
+
+ StringRef getArch() const { return _arch; }
+
+private:
+ StringRef _arch;
+};
+
+struct Path {
+ StringRef _path;
+ bool _asNeeded;
+ bool _isDashlPrefix;
+
+ Path() : _asNeeded(false), _isDashlPrefix(false) {}
+ Path(StringRef path, bool asNeeded = false, bool isLib = false)
+ : _path(path), _asNeeded(asNeeded), _isDashlPrefix(isLib) {}
+};
+
+template<Command::Kind K>
+class PathList : public Command {
+public:
+ PathList(Parser &ctx, StringRef name, const SmallVectorImpl<Path> &paths)
+ : Command(ctx, K), _name(name) {
+ size_t numPaths = paths.size();
+ Path *pathsStart = getAllocator().template Allocate<Path>(numPaths);
+ std::copy(std::begin(paths), std::end(paths), pathsStart);
+ _paths = llvm::makeArrayRef(pathsStart, numPaths);
+ }
+
+ static bool classof(const Command *c) { return c->getKind() == K; }
+
+ void dump(raw_ostream &os) const override {
+ os << _name << "(";
+ bool first = true;
+ for (const Path &path : getPaths()) {
+ if (!first)
+ os << " ";
+ first = false;
+ if (path._asNeeded)
+ os << "AS_NEEDED(";
+ if (path._isDashlPrefix)
+ os << "-l";
+ os << path._path;
+ if (path._asNeeded)
+ os << ")";
+ }
+ os << ")\n";
+ }
+
+ llvm::ArrayRef<Path> getPaths() const { return _paths; }
+
+private:
+ StringRef _name;
+ llvm::ArrayRef<Path> _paths;
+};
+
+class Group : public PathList<Command::Kind::Group> {
+public:
+ template <class RangeT>
+ Group(Parser &ctx, RangeT range)
+ : PathList(ctx, "GROUP", std::move(range)) {}
+};
+
+class Input : public PathList<Command::Kind::Input> {
+public:
+ template <class RangeT>
+ Input(Parser &ctx, RangeT range)
+ : PathList(ctx, "INPUT", std::move(range)) {}
+};
+
+class Entry : public Command {
+public:
+ Entry(Parser &ctx, StringRef entryName)
+ : Command(ctx, Kind::Entry), _entryName(entryName) {}
+
+ static bool classof(const Command *c) { return c->getKind() == Kind::Entry; }
+
+ void dump(raw_ostream &os) const override {
+ os << "ENTRY(" << _entryName << ")\n";
+ }
+
+ StringRef getEntryName() const { return _entryName; }
+
+private:
+ StringRef _entryName;
+};
+
+class SearchDir : public Command {
+public:
+ SearchDir(Parser &ctx, StringRef searchPath)
+ : Command(ctx, Kind::SearchDir), _searchPath(searchPath) {}
+
+ static bool classof(const Command *c) {
+ return c->getKind() == Kind::SearchDir;
+ }
+
+ void dump(raw_ostream &os) const override {
+ os << "SEARCH_DIR(\"" << _searchPath << "\")\n";
+ }
+
+ StringRef getSearchPath() const { return _searchPath; }
+
+private:
+ StringRef _searchPath;
+};
+
+/// Superclass for expression nodes. Linker scripts accept C-like expressions in
+/// many places, such as when defining the value of a symbol or the address of
+/// an output section.
+/// Example:
+///
+/// SECTIONS {
+/// my_symbol = 1 + 1 * 2;
+/// | | ^~~~> Constant : Expression
+/// | | ^~~~> Constant : Expression
+/// | | ^~~~> BinOp : Expression
+/// ^~~~> Constant : Expression
+/// ^~~~> BinOp : Expression (the top-level Expression node)
+/// }
+///
+class Expression {
+public:
+ // The symbol table does not need to own its string keys and the use of StringMap
+ // here is an overkill.
+ typedef llvm::StringMap<int64_t, llvm::BumpPtrAllocator> SymbolTableTy;
+
+ enum class Kind { Constant, Symbol, FunctionCall, Unary, BinOp,
+ TernaryConditional };
+ Kind getKind() const { return _kind; }
+ inline llvm::BumpPtrAllocator &getAllocator() const;
+ virtual void dump(raw_ostream &os) const = 0;
+ virtual ErrorOr<int64_t> evalExpr(SymbolTableTy &symbolTable) const = 0;
+ virtual ~Expression() {}
+
+protected:
+ Expression(class Parser &ctx, Kind k) : _ctx(ctx), _kind(k) {}
+
+private:
+ Parser &_ctx;
+ Kind _kind;
+};
+
+/// A constant value is stored as unsigned because it represents absolute
+/// values. We represent negative numbers by composing the unary '-' operator
+/// with a constant.
+class Constant : public Expression {
+public:
+ Constant(Parser &ctx, uint64_t num)
+ : Expression(ctx, Kind::Constant), _num(num) {}
+ void dump(raw_ostream &os) const override;
+
+ static bool classof(const Expression *c) {
+ return c->getKind() == Kind::Constant;
+ }
+
+ ErrorOr<int64_t> evalExpr(SymbolTableTy &symbolTable) const override;
+
+private:
+ uint64_t _num;
+};
+
+class Symbol : public Expression {
+public:
+ Symbol(Parser &ctx, StringRef name)
+ : Expression(ctx, Kind::Symbol), _name(name) {}
+ void dump(raw_ostream &os) const override;
+
+ static bool classof(const Expression *c) {
+ return c->getKind() == Kind::Symbol;
+ }
+
+ ErrorOr<int64_t> evalExpr(SymbolTableTy &symbolTable) const override;
+
+private:
+ StringRef _name;
+};
+
+class FunctionCall : public Expression {
+public:
+ FunctionCall(Parser &ctx, StringRef name,
+ const SmallVectorImpl<const Expression *> &args)
+ : Expression(ctx, Kind::FunctionCall), _name(name) {
+ size_t numArgs = args.size();
+ const Expression **argsStart =
+ getAllocator().Allocate<const Expression *>(numArgs);
+ std::copy(std::begin(args), std::end(args), argsStart);
+ _args = llvm::makeArrayRef(argsStart, numArgs);
+ }
+
+ void dump(raw_ostream &os) const override;
+
+ static bool classof(const Expression *c) {
+ return c->getKind() == Kind::FunctionCall;
+ }
+
+ ErrorOr<int64_t> evalExpr(SymbolTableTy &symbolTable) const override;
+
+private:
+ StringRef _name;
+ llvm::ArrayRef<const Expression *> _args;
+};
+
+class Unary : public Expression {
+public:
+ enum Operation {
+ Minus,
+ Not
+ };
+
+ Unary(Parser &ctx, Operation op, const Expression *child)
+ : Expression(ctx, Kind::Unary), _op(op), _child(child) {}
+ void dump(raw_ostream &os) const override;
+
+ static bool classof(const Expression *c) {
+ return c->getKind() == Kind::Unary;
+ }
+
+ ErrorOr<int64_t> evalExpr(SymbolTableTy &symbolTable) const override;
+
+private:
+ Operation _op;
+ const Expression *_child;
+};
+
+class BinOp : public Expression {
+public:
+ enum Operation {
+ And,
+ CompareDifferent,
+ CompareEqual,
+ CompareGreater,
+ CompareGreaterEqual,
+ CompareLess,
+ CompareLessEqual,
+ Div,
+ Mul,
+ Or,
+ Shl,
+ Shr,
+ Sub,
+ Sum
+ };
+
+ BinOp(Parser &ctx, const Expression *lhs, Operation op, const Expression *rhs)
+ : Expression(ctx, Kind::BinOp), _op(op), _lhs(lhs), _rhs(rhs) {}
+
+ void dump(raw_ostream &os) const override;
+
+ static bool classof(const Expression *c) {
+ return c->getKind() == Kind::BinOp;
+ }
+
+ ErrorOr<int64_t> evalExpr(SymbolTableTy &symbolTable) const override;
+
+private:
+ Operation _op;
+ const Expression *_lhs;
+ const Expression *_rhs;
+};
+
+/// Operands of the ternary operator can be any expression, similar to the other
+/// operations, including another ternary operator. To disambiguate the parse
+/// tree, note that ternary conditionals have precedence 13 and, different from
+/// other operators, associates right-to-left. For example:
+///
+/// i = i > 3 ? i < 5 ? 1 : 2 : 0;
+///
+/// will have the following parse tree:
+///
+/// i = ((i > 3) ? ((i < 5) ? 1 : 2) : 0);
+///
+/// The '>' binds tigher because it has precedence 6. When faced with two "?"
+/// ternary operators back-to-back, the parser prioritized the rightmost one.
+///
+class TernaryConditional : public Expression {
+public:
+ TernaryConditional(Parser &ctx, const Expression *conditional,
+ const Expression *trueExpr, const Expression *falseExpr)
+ : Expression(ctx, Kind::TernaryConditional), _conditional(conditional),
+ _trueExpr(trueExpr), _falseExpr(falseExpr) {}
+
+ void dump(raw_ostream &os) const override;
+
+ static bool classof(const Expression *c) {
+ return c->getKind() == Kind::TernaryConditional;
+ }
+
+ ErrorOr<int64_t> evalExpr(SymbolTableTy &symbolTable) const override;
+
+private:
+ const Expression *_conditional;
+ const Expression *_trueExpr;
+ const Expression *_falseExpr;
+};
+
+/// Symbol assignments of the form "symbolname = <expression>" may occur either
+/// as sections-commands or as output-section-commands.
+/// Example:
+///
+/// SECTIONS {
+/// mysymbol = . /* SymbolAssignment as a sections-command */
+/// .data : {
+/// othersymbol = . /* SymbolAssignment as an output-section-command */
+/// }
+///}
+///
+class SymbolAssignment : public Command {
+public:
+ enum AssignmentKind { Simple, Sum, Sub, Mul, Div, Shl, Shr, And, Or };
+ enum AssignmentVisibility { Default, Hidden, Provide, ProvideHidden };
+
+ SymbolAssignment(Parser &ctx, StringRef name, const Expression *expr,
+ AssignmentKind kind, AssignmentVisibility visibility)
+ : Command(ctx, Kind::SymbolAssignment), _expression(expr), _symbol(name),
+ _assignmentKind(Simple), _assignmentVisibility(visibility) {}
+
+ static bool classof(const Command *c) {
+ return c->getKind() == Kind::SymbolAssignment;
+ }
+
+ void dump(raw_ostream &os) const override;
+ const Expression *expr() const { return _expression; }
+ StringRef symbol() const { return _symbol; }
+ AssignmentKind assignmentKind() const { return _assignmentKind; }
+ AssignmentVisibility assignmentVisibility() const {
+ return _assignmentVisibility;
+ }
+
+private:
+ const Expression *_expression;
+ StringRef _symbol;
+ AssignmentKind _assignmentKind;
+ AssignmentVisibility _assignmentVisibility;
+};
+
+/// Encodes how to sort file names or section names that are expanded from
+/// wildcard operators. This typically occurs in constructs such as
+/// SECTIONS { .data : SORT_BY_NAME(*)(*) }}, where the order of the expanded
+/// names is important to determine which sections go first.
+enum class WildcardSortMode {
+ NA,
+ ByAlignment,
+ ByAlignmentAndName,
+ ByInitPriority,
+ ByName,
+ ByNameAndAlignment,
+ None
+};
+
+/// Represents either a single input section name or a group of sorted input
+/// section names. They specify which sections to map to a given output section.
+/// Example:
+///
+/// SECTIONS {
+/// .x: { *(.text) }
+/// /* ^~~~^ InputSectionName : InputSection */
+/// .y: { *(SORT(.text*)) }
+/// /* ^~~~~~~~~~~^ InputSectionSortedGroup : InputSection */
+/// }
+class InputSection : public Command {
+public:
+ static bool classof(const Command *c) {
+ return c->getKind() == Kind::InputSectionName ||
+ c->getKind() == Kind::SortedGroup;
+ }
+
+protected:
+ InputSection(Parser &ctx, Kind k) : Command(ctx, k) {}
+};
+
+class InputSectionName : public InputSection {
+public:
+ InputSectionName(Parser &ctx, StringRef name, bool excludeFile)
+ : InputSection(ctx, Kind::InputSectionName), _name(name),
+ _excludeFile(excludeFile) {}
+
+ void dump(raw_ostream &os) const override;
+
+ static bool classof(const Command *c) {
+ return c->getKind() == Kind::InputSectionName;
+ }
+ bool hasExcludeFile() const { return _excludeFile; }
+ StringRef name() const { return _name; }
+
+private:
+ StringRef _name;
+ bool _excludeFile;
+};
+
+class InputSectionSortedGroup : public InputSection {
+public:
+ typedef llvm::ArrayRef<const InputSection *>::const_iterator const_iterator;
+
+ InputSectionSortedGroup(Parser &ctx, WildcardSortMode sort,
+ const SmallVectorImpl<const InputSection *> &sections)
+ : InputSection(ctx, Kind::SortedGroup), _sortMode(sort) {
+ size_t numSections = sections.size();
+ const InputSection **sectionsStart =
+ getAllocator().Allocate<const InputSection *>(numSections);
+ std::copy(std::begin(sections), std::end(sections), sectionsStart);
+ _sections = llvm::makeArrayRef(sectionsStart, numSections);
+ }
+
+ void dump(raw_ostream &os) const override;
+ WildcardSortMode sortMode() const { return _sortMode; }
+
+ static bool classof(const Command *c) {
+ return c->getKind() == Kind::SortedGroup;
+ }
+
+ const_iterator begin() const { return _sections.begin(); }
+ const_iterator end() const { return _sections.end(); }
+
+private:
+ WildcardSortMode _sortMode;
+ llvm::ArrayRef<const InputSection *> _sections;
+};
+
+/// An output-section-command that maps a series of sections inside a given
+/// file-archive pair to an output section.
+/// Example:
+///
+/// SECTIONS {
+/// .x: { *(.text) }
+/// /* ^~~~~~~^ InputSectionsCmd */
+/// .y: { w:z(SORT(.text*)) }
+/// /* ^~~~~~~~~~~~~~~~^ InputSectionsCmd */
+/// }
+class InputSectionsCmd : public Command {
+public:
+ typedef llvm::ArrayRef<const InputSection *>::const_iterator const_iterator;
+ typedef std::vector<const InputSection *> VectorTy;
+
+ InputSectionsCmd(Parser &ctx, StringRef memberName, StringRef archiveName,
+ bool keep, WildcardSortMode fileSortMode,
+ WildcardSortMode archiveSortMode,
+ const SmallVectorImpl<const InputSection *> &sections)
+ : Command(ctx, Kind::InputSectionsCmd), _memberName(memberName),
+ _archiveName(archiveName), _keep(keep), _fileSortMode(fileSortMode),
+ _archiveSortMode(archiveSortMode) {
+ size_t numSections = sections.size();
+ const InputSection **sectionsStart =
+ getAllocator().Allocate<const InputSection *>(numSections);
+ std::copy(std::begin(sections), std::end(sections), sectionsStart);
+ _sections = llvm::makeArrayRef(sectionsStart, numSections);
+ }
+
+ void dump(raw_ostream &os) const override;
+
+ static bool classof(const Command *c) {
+ return c->getKind() == Kind::InputSectionsCmd;
+ }
+
+ StringRef memberName() const { return _memberName; }
+ StringRef archiveName() const { return _archiveName; }
+ const_iterator begin() const { return _sections.begin(); }
+ const_iterator end() const { return _sections.end(); }
+ WildcardSortMode archiveSortMode() const { return _archiveSortMode; }
+ WildcardSortMode fileSortMode() const { return _fileSortMode; }
+
+private:
+ StringRef _memberName;
+ StringRef _archiveName;
+ bool _keep;
+ WildcardSortMode _fileSortMode;
+ WildcardSortMode _archiveSortMode;
+ llvm::ArrayRef<const InputSection *> _sections;
+};
+
+/// A sections-command to specify which input sections and symbols compose a
+/// given output section.
+/// Example:
+///
+/// SECTIONS {
+/// .x: { *(.text) ; symbol = .; }
+/// /*^~~~~~~~~~~~~~~~~~~~~~~~~~~~~^ OutputSectionDescription */
+/// .y: { w:z(SORT(.text*)) }
+/// /*^~~~~~~~~~~~~~~~~~~~~~~~^ OutputSectionDescription */
+/// .a 0x10000 : ONLY_IF_RW { *(.data*) ; *:libc.a(SORT(*)); }
+/// /*^~~~~~~~~~~~~ OutputSectionDescription ~~~~~~~~~~~~~~~~~^ */
+/// }
+class OutputSectionDescription : public Command {
+public:
+ enum Constraint { C_None, C_OnlyIfRO, C_OnlyIfRW };
+
+ typedef llvm::ArrayRef<const Command *>::const_iterator const_iterator;
+
+ OutputSectionDescription(
+ Parser &ctx, StringRef sectionName, const Expression *address,
+ const Expression *align, const Expression *subAlign, const Expression *at,
+ const Expression *fillExpr, StringRef fillStream, bool alignWithInput,
+ bool discard, Constraint constraint,
+ const SmallVectorImpl<const Command *> &outputSectionCommands)
+ : Command(ctx, Kind::OutputSectionDescription), _sectionName(sectionName),
+ _address(address), _align(align), _subAlign(subAlign), _at(at),
+ _fillExpr(fillExpr), _fillStream(fillStream),
+ _alignWithInput(alignWithInput), _discard(discard),
+ _constraint(constraint) {
+ size_t numCommands = outputSectionCommands.size();
+ const Command **commandsStart =
+ getAllocator().Allocate<const Command *>(numCommands);
+ std::copy(std::begin(outputSectionCommands),
+ std::end(outputSectionCommands), commandsStart);
+ _outputSectionCommands = llvm::makeArrayRef(commandsStart, numCommands);
+ }
+
+ static bool classof(const Command *c) {
+ return c->getKind() == Kind::OutputSectionDescription;
+ }
+
+ void dump(raw_ostream &os) const override;
+
+ const_iterator begin() const { return _outputSectionCommands.begin(); }
+ const_iterator end() const { return _outputSectionCommands.end(); }
+ StringRef name() const { return _sectionName; }
+
+private:
+ StringRef _sectionName;
+ const Expression *_address;
+ const Expression *_align;
+ const Expression *_subAlign;
+ const Expression *_at;
+ const Expression *_fillExpr;
+ StringRef _fillStream;
+ bool _alignWithInput;
+ bool _discard;
+ Constraint _constraint;
+ llvm::ArrayRef<const Command *> _outputSectionCommands;
+};
+
+/// Represents an Overlay structure as documented in
+/// https://sourceware.org/binutils/docs/ld/Overlay-Description.html#Overlay-Description
+class Overlay : public Command {
+public:
+ Overlay(Parser &ctx) : Command(ctx, Kind::Overlay) {}
+
+ static bool classof(const Command *c) {
+ return c->getKind() == Kind::Overlay;
+ }
+
+ void dump(raw_ostream &os) const override { os << "Overlay description\n"; }
+};
+
+/// Represents all the contents of the SECTIONS {} construct.
+class Sections : public Command {
+public:
+ typedef llvm::ArrayRef<const Command *>::const_iterator const_iterator;
+
+ Sections(Parser &ctx,
+ const SmallVectorImpl<const Command *> &sectionsCommands)
+ : Command(ctx, Kind::Sections) {
+ size_t numCommands = sectionsCommands.size();
+ const Command **commandsStart =
+ getAllocator().Allocate<const Command *>(numCommands);
+ std::copy(std::begin(sectionsCommands), std::end(sectionsCommands),
+ commandsStart);
+ _sectionsCommands = llvm::makeArrayRef(commandsStart, numCommands);
+ }
+
+ static bool classof(const Command *c) {
+ return c->getKind() == Kind::Sections;
+ }
+
+ void dump(raw_ostream &os) const override;
+ const_iterator begin() const { return _sectionsCommands.begin(); }
+ const_iterator end() const { return _sectionsCommands.end(); }
+
+private:
+ llvm::ArrayRef<const Command *> _sectionsCommands;
+};
+
+/// Represents a single memory block definition in a MEMORY {} command.
+class MemoryBlock {
+public:
+ MemoryBlock(StringRef name, StringRef attr,
+ const Expression *origin, const Expression *length)
+ : _name(name), _attr(attr), _origin(origin), _length(length) {}
+
+ void dump(raw_ostream &os) const;
+
+private:
+ StringRef _name;
+ StringRef _attr;
+ const Expression *_origin;
+ const Expression *_length;
+};
+
+/// Represents all the contents of the MEMORY {} command.
+class Memory : public Command {
+public:
+ Memory(Parser &ctx,
+ const SmallVectorImpl<const MemoryBlock *> &blocks)
+ : Command(ctx, Kind::Memory) {
+ size_t numBlocks = blocks.size();
+ const MemoryBlock **blocksStart =
+ getAllocator().Allocate<const MemoryBlock *>(numBlocks);
+ std::copy(std::begin(blocks), std::end(blocks), blocksStart);
+ _blocks = llvm::makeArrayRef(blocksStart, numBlocks);
+ }
+
+ static bool classof(const Command *c) {
+ return c->getKind() == Kind::Memory;
+ }
+
+ void dump(raw_ostream &os) const override;
+
+private:
+ llvm::ArrayRef<const MemoryBlock *> _blocks;
+};
+
+/// Represents an extern command.
+class Extern : public Command {
+public:
+ typedef llvm::ArrayRef<StringRef>::const_iterator const_iterator;
+
+ Extern(Parser &ctx,
+ const SmallVectorImpl<StringRef> &symbols)
+ : Command(ctx, Kind::Extern) {
+ size_t numSymbols = symbols.size();
+ StringRef *symbolsStart =
+ getAllocator().Allocate<StringRef>(numSymbols);
+ std::copy(std::begin(symbols), std::end(symbols), symbolsStart);
+ _symbols = llvm::makeArrayRef(symbolsStart, numSymbols);
+ }
+
+ static bool classof(const Command *c) {
+ return c->getKind() == Kind::Extern;
+ }
+
+ void dump(raw_ostream &os) const override;
+ const_iterator begin() const { return _symbols.begin(); }
+ const_iterator end() const { return _symbols.end(); }
+
+private:
+ llvm::ArrayRef<StringRef> _symbols;
+};
+
+/// Stores the parse tree of a linker script.
+class LinkerScript {
+public:
+ void dump(raw_ostream &os) const {
+ for (const Command *c : _commands) {
+ c->dump(os);
+ if (isa<SymbolAssignment>(c))
+ os << "\n";
+ }
+ }
+
+ std::vector<const Command *> _commands;
+};
+
+/// Recognizes syntactic constructs of a linker script using a predictive
+/// parser/recursive descent implementation.
+///
+/// Based on the linker script documentation available at
+/// https://sourceware.org/binutils/docs/ld/Scripts.html
+class Parser {
+public:
+ explicit Parser(std::unique_ptr<MemoryBuffer> mb)
+ : _lex(std::move(mb)), _peekAvailable(false) {}
+
+ /// Let's not allow copying of Parser class because it would be expensive
+ /// to update all the AST pointers to a new buffer.
+ Parser(const Parser &instance) = delete;
+
+ /// Lex and parse the current memory buffer to create a linker script AST.
+ std::error_code parse();
+
+ /// Returns a reference to the top level node of the linker script AST.
+ LinkerScript *get() { return &_script; }
+
+ /// Returns a reference to the underlying allocator.
+ llvm::BumpPtrAllocator &getAllocator() { return _alloc; }
+
+private:
+ /// Advances to the next token, either asking the Lexer to lex the next token
+ /// or obtaining it from the look ahead buffer.
+ void consumeToken() {
+ // First check if the look ahead buffer cached the next token
+ if (_peekAvailable) {
+ _tok = _bufferedToken;
+ _peekAvailable = false;
+ return;
+ }
+ _lex.lex(_tok);
+ }
+
+ /// Returns the token that succeeds the current one without consuming the
+ /// current token. This operation will lex an additional token and store it in
+ /// a private buffer.
+ const Token &peek() {
+ if (_peekAvailable)
+ return _bufferedToken;
+
+ _lex.lex(_bufferedToken);
+ _peekAvailable = true;
+ return _bufferedToken;
+ }
+
+ void error(const Token &tok, Twine msg) {
+ _lex.getSourceMgr().PrintMessage(
+ llvm::SMLoc::getFromPointer(tok._range.data()),
+ llvm::SourceMgr::DK_Error, msg);
+ }
+
+ bool expectAndConsume(Token::Kind kind, Twine msg) {
+ if (_tok._kind != kind) {
+ error(_tok, msg);
+ return false;
+ }
+ consumeToken();
+ return true;
+ }
+
+ bool isNextToken(Token::Kind kind) { return (_tok._kind == kind); }
+
+ // Recursive descent parsing member functions
+ // All of these functions consumes tokens and return an AST object,
+ // represented by the Command superclass. However, note that not all AST
+ // objects derive from Command. For nodes of C-like expressions, used in
+ // linker scripts, the superclass is Expression. For nodes that represent
+ // input sections that map to an output section, the superclass is
+ // InputSection.
+ //
+ // Example mapping common constructs to AST nodes:
+ //
+ // SECTIONS { /* Parsed to Sections class */
+ // my_symbol = 1 + 1; /* Parsed to SymbolAssignment class */
+ // /* ^~~> Parsed to Expression class */
+ // .data : { *(.data) } /* Parsed to OutputSectionDescription class */
+ // /* ^~~> Parsed to InputSectionName class */
+ // /* ^~~~~> Parsed to InputSectionsCmd class */
+ // }
+
+ // ==== Expression parsing member functions ====
+
+ /// Parse "identifier(param [, param]...)"
+ ///
+ /// Example:
+ ///
+ /// SECTIONS {
+ /// my_symbol = 0x1000 | ALIGN(other_symbol);
+ /// /* ^~~~> parseFunctionCall()
+ /// }
+ const Expression *parseFunctionCall();
+
+ /// Ensures that the current token is an expression operand. If it is not,
+ /// issues an error to the user and returns false.
+ bool expectExprOperand();
+
+ /// Parse operands of an expression, such as function calls, identifiers,
+ /// literal numbers or unary operators.
+ ///
+ /// Example:
+ ///
+ /// SECTIONS {
+ /// my_symbol = 0x1000 | ALIGN(other_symbol);
+ /// ^~~~> parseExprTerminal()
+ /// }
+ const Expression *parseExprOperand();
+
+ // As a reference to the precedence of C operators, consult
+ // http://en.cppreference.com/w/c/language/operator_precedence
+
+ /// Parse either a single expression operand and returns or parse an entire
+ /// expression if its top-level node has a lower or equal precedence than the
+ /// indicated.
+ const Expression *parseExpression(unsigned precedence = 13);
+
+ /// Parse an operator and its rhs operand, assuming that the lhs was already
+ /// consumed. Keep parsing subsequent operator-operand pairs that do not
+ /// exceed highestPrecedence.
+ /// * lhs points to the left-hand-side operand of this operator
+ /// * maxPrecedence has the maximum operator precedence level that this parse
+ /// function is allowed to consume.
+ const Expression *parseOperatorOperandLoop(const Expression *lhs,
+ unsigned maxPrecedence);
+
+ /// Parse ternary conditionals such as "(condition)? true: false;". This
+ /// operator has precedence level 13 and associates right-to-left.
+ const Expression *parseTernaryCondOp(const Expression *lhs);
+
+ // ==== High-level commands parsing ====
+
+ /// Parse the OUTPUT linker script command.
+ /// Example:
+ /// OUTPUT(/path/to/file)
+ /// ^~~~> parseOutput()
+ ///
+ Output *parseOutput();
+
+ /// Parse the OUTPUT_FORMAT linker script command.
+ /// Example:
+ ///
+ /// OUTPUT_FORMAT(elf64-x86-64,elf64-x86-64,elf64-x86-64)
+ /// ^~~~> parseOutputFormat()
+ ///
+ OutputFormat *parseOutputFormat();
+
+ /// Parse the OUTPUT_ARCH linker script command.
+ /// Example:
+ ///
+ /// OUTPUT_ARCH(i386:x86-64)
+ /// ^~~~> parseOutputArch()
+ ///
+ OutputArch *parseOutputArch();
+
+ /// Parse the INPUT or GROUP linker script command.
+ /// Example:
+ ///
+ /// GROUP ( /lib/x86_64-linux-gnu/libc.so.6
+ /// /usr/lib/x86_64-linux-gnu/libc_nonshared.a
+ /// AS_NEEDED ( /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 )
+ /// -lm -l:libgcc.a )
+ ///
+ template<class T> T *parsePathList();
+ bool parseAsNeeded(SmallVectorImpl<Path> &paths);
+
+ /// Parse the ENTRY linker script command.
+ /// Example:
+ ///
+ /// ENTRY(init)
+ /// ^~~~> parseEntry()
+ ///
+ Entry *parseEntry();
+
+ /// Parse the SEARCH_DIR linker script command.
+ /// Example:
+ ///
+ /// SEARCH_DIR("/usr/x86_64-linux-gnu/lib64");
+ /// ^~~~> parseSearchDir()
+ ///
+ SearchDir *parseSearchDir();
+
+ /// Parse "symbol = expression" commands that live inside the
+ /// SECTIONS directive.
+ /// Example:
+ ///
+ /// SECTIONS {
+ /// my_symbol = 1 + 1;
+ /// ^~~~> parseExpression()
+ /// ^~~~ parseSymbolAssignment()
+ /// }
+ ///
+ const SymbolAssignment *parseSymbolAssignment();
+
+ /// Parse "EXCLUDE_FILE" used inside the listing of input section names.
+ /// Example:
+ ///
+ /// SECTIONS {
+ /// .data : { *(EXCLUDE_FILE (*crtend.o *otherfile.o) .ctors) }
+ /// ^~~~> parseExcludeFile()
+ /// }
+ ///
+ ErrorOr<InputSectionsCmd::VectorTy> parseExcludeFile();
+
+ /// Helper to parse SORT_BY_NAME(, SORT_BY_ALIGNMENT( and SORT_NONE(,
+ /// possibly nested. Returns the number of Token::r_paren tokens that need
+ /// to be consumed, while sortMode is updated with the parsed sort
+ /// criteria.
+ /// Example:
+ ///
+ /// SORT_BY_NAME(SORT_BY_ALIGNMENT(*))
+ /// ^~~~ parseSortDirectives() ~~^
+ /// Returns 2, finishes with sortMode = WildcardSortMode::ByNameAndAlignment
+ ///
+ int parseSortDirectives(WildcardSortMode &sortMode);
+
+ /// Parse a group of input section names that are sorted via SORT* directives.
+ /// Example:
+ /// SORT_BY_NAME(SORT_BY_ALIGNMENT(*data *bss))
+ const InputSection *parseSortedInputSections();
+
+ /// Parse input section description statements.
+ /// Example:
+ ///
+ /// SECTIONS {
+ /// .mysection : crt.o(.data* .bss SORT_BY_NAME(name*))
+ /// ^~~~ parseInputSectionsCmd()
+ /// }
+ const InputSectionsCmd *parseInputSectionsCmd();
+
+ /// Parse output section description statements.
+ /// Example:
+ ///
+ /// SECTIONS {
+ /// .data : { crt.o(.data* .bss SORT_BY_NAME(name*)) }
+ /// ^~~~ parseOutputSectionDescription()
+ /// }
+ const OutputSectionDescription *parseOutputSectionDescription();
+
+ /// Stub for parsing overlay commands. Currently unimplemented.
+ const Overlay *parseOverlay();
+
+ /// Parse the SECTIONS linker script command.
+ /// Example:
+ ///
+ /// SECTIONS {
+ /// ^~~~ parseSections()
+ /// . = 0x100000;
+ /// .data : { *(.data) }
+ /// }
+ ///
+ Sections *parseSections();
+
+ /// Parse the MEMORY linker script command.
+ /// Example:
+ ///
+ /// MEMORY {
+ /// ^~~~ parseMemory()
+ /// ram (rwx) : ORIGIN = 0x20000000, LENGTH = 96K
+ /// rom (rx) : ORIGIN = 0x0, LENGTH = 256K
+ /// }
+ ///
+ Memory *parseMemory();
+
+ /// Parse the EXTERN linker script command.
+ /// Example:
+ ///
+ /// EXTERN(symbol symbol ...)
+ /// ^~~~> parseExtern()
+ ///
+ Extern *parseExtern();
+
+private:
+ // Owns the entire linker script AST nodes
+ llvm::BumpPtrAllocator _alloc;
+
+ // The top-level/entry-point linker script AST node
+ LinkerScript _script;
+
+ Lexer _lex;
+
+ // Current token being analyzed
+ Token _tok;
+
+ // Annotate whether we buffered the next token to allow peeking
+ bool _peekAvailable;
+ Token _bufferedToken;
+};
+
+/// script::Sema traverses all parsed linker script structures and populate
+/// internal data structures to be able to answer the following questions:
+///
+/// * According to the linker script, which input section goes first in the
+/// output file layout, input section A or input section B?
+///
+/// * What is the name of the output section that input section A should be
+/// mapped to?
+///
+/// * Which linker script expressions should be calculated before emitting
+/// a given section?
+///
+/// * How to evaluate a given linker script expression?
+///
+class Sema {
+public:
+ /// From the linker script point of view, this class represents the minimum
+ /// set of information to uniquely identify an input section.
+ struct SectionKey {
+ StringRef archivePath;
+ StringRef memberPath;
+ StringRef sectionName;
+ };
+
+ Sema();
+
+ /// We can parse several linker scripts via command line whose ASTs are stored
+ /// here via addLinkerScript().
+ void addLinkerScript(std::unique_ptr<Parser> script) {
+ _scripts.push_back(std::move(script));
+ }
+
+ const std::vector<std::unique_ptr<Parser>> &getLinkerScripts() {
+ return _scripts;
+ }
+
+ /// Prepare our data structures according to the linker scripts currently in
+ /// our control (control given via addLinkerScript()). Called once all linker
+ /// scripts have been parsed.
+ void perform();
+
+ /// Answer if we have layout commands (section mapping rules). If we don't,
+ /// the output file writer can assume there is no linker script special rule
+ /// to handle.
+ bool hasLayoutCommands() const { return _layoutCommands.size() > 0; }
+
+ /// Return true if this section has a mapping rule in the linker script
+ bool hasMapping(const SectionKey &key) const {
+ return getLayoutOrder(key, true) >= 0;
+ }
+
+ /// Order function - used to sort input sections in the output file according
+ /// to linker script custom mappings. Return true if lhs should appear before
+ /// rhs.
+ bool less(const SectionKey &lhs, const SectionKey &rhs) const;
+
+ /// Retrieve the name of the output section that this input section is mapped
+ /// to, according to custom linker script mappings.
+ StringRef getOutputSection(const SectionKey &key) const;
+
+ /// Retrieve all the linker script expressions that need to be evaluated
+ /// before the given section is emitted. This is *not* const because the
+ /// first section to retrieve a given set of expression is the only one to
+ /// receive it. This set is marked as "delivered" and no other sections can
+ /// retrieve this set again. If we don't do this, multiple sections may map
+ /// to the same set of expressions because of wildcards rules.
+ std::vector<const SymbolAssignment *> getExprs(const SectionKey &key);
+
+ /// Evaluate a single linker script expression according to our current
+ /// context (symbol table). This function is *not* constant because it can
+ /// update our symbol table with new symbols calculated in this expression.
+ std::error_code evalExpr(const SymbolAssignment *assgn, uint64_t &curPos);
+
+ /// Retrieve the set of symbols defined in linker script expressions.
+ const llvm::StringSet<> &getScriptDefinedSymbols() const;
+
+ /// Queries the linker script symbol table for the value of a given symbol.
+ /// This function must be called after linker script expressions evaluation
+ /// has been performed (by calling evalExpr() for all expressions).
+ uint64_t getLinkerScriptExprValue(StringRef name) const;
+
+ void dump() const;
+
+private:
+ /// A custom hash operator to teach the STL how to handle our custom keys.
+ /// This will be used in our hash table mapping Sections to a Layout Order
+ /// number (caching results).
+ struct SectionKeyHash {
+ int64_t operator()(const SectionKey &k) const {
+ return llvm::hash_combine(k.archivePath, k.memberPath, k.sectionName);
+ }
+ };
+
+ /// Teach the STL when two section keys are the same. This will be used in
+ /// our hash table mapping Sections to a Layout Order number (caching results)
+ struct SectionKeyEq {
+ bool operator()(const SectionKey &lhs, const SectionKey &rhs) const {
+ return ((lhs.archivePath == rhs.archivePath) &&
+ (lhs.memberPath == rhs.memberPath) &&
+ (lhs.sectionName == rhs.sectionName));
+ }
+ };
+
+ /// Given an order id, check if it matches the tuple
+ /// <archivePath, memberPath, sectionName> and returns the
+ /// internal id that matched, or -1 if no matches.
+ int matchSectionName(int id, const SectionKey &key) const;
+
+ /// Returns a number that will determine the order of this input section
+ /// in the final layout. If coarse is true, we simply return the layour order
+ /// of the higher-level node InputSectionsCmd, used to order input sections.
+ /// If coarse is false, we return the layout index down to the internal
+ /// InputSectionsCmd arrangement, used to get the set of preceding linker
+ ///expressions.
+ int getLayoutOrder(const SectionKey &key, bool coarse) const;
+
+ /// Compare two sections that have the same mapping rule (i.e., are matched
+ /// by the same InputSectionsCmd).
+ /// Determine if lhs < rhs by analyzing the InputSectionsCmd structure.
+ bool localCompare(int order, const SectionKey &lhs,
+ const SectionKey &rhs) const;
+
+
+ /// Our goal with all linearizeAST overloaded functions is to
+ /// traverse the linker script AST while putting nodes in a vector and
+ /// thus enforcing order among nodes (which comes first).
+ ///
+ /// The order among nodes is determined by their indexes in this vector
+ /// (_layoutCommands). This index allows us to solve the problem of
+ /// establishing the order among two different input sections: we match each
+ /// input sections with their respective layout command and use the indexes
+ /// of these commands to order these sections.
+ ///
+ /// Example:
+ ///
+ /// Given the linker script:
+ /// SECTIONS {
+ /// .text : { *(.text) }
+ /// .data : { *(.data) }
+ /// }
+ ///
+ /// The _layoutCommands vector should contain:
+ /// id 0 : <OutputSectionDescription> (_sectionName = ".text")
+ /// id 1 : <InputSectionsCmd> (_memberName = "*")
+ /// id 2 : <InputSectionName> (_name = ".text)
+ /// id 3 : <OutputSectionDescription> (_sectionName = ".data")
+ /// id 4 : <InputSectionsCmd> (_memberName = "*")
+ /// id 5 : <InputSectionName> (_name = ".data")
+ ///
+ /// If we need to sort the following input sections:
+ ///
+ /// input section A: .text from libc.a (member errno.o)
+ /// input section B: .data from libc.a (member write.o)
+ ///
+ /// Then we match input section A with the InputSectionsCmd of id 1, and
+ /// input section B with the InputSectionsCmd of id 4. Since 1 < 4, we
+ /// put A before B.
+ ///
+ /// The second problem handled by the linearization of the AST is the task
+ /// of finding all preceding expressions that need to be calculated before
+ /// emitting a given section. This task is easier to deal with when all nodes
+ /// are in a vector because otherwise we would need to traverse multiple
+ /// levels of the AST to find the set of expressions that preceed a layout
+ /// command.
+ ///
+ /// The linker script commands that are linearized ("layout commands") are:
+ ///
+ /// * OutputSectionDescription, containing an output section name
+ /// * InputSectionsCmd, containing an input file name
+ /// * InputSectionName, containing a single input section name
+ /// * InputSectionSortedName, a group of input section names
+ /// * SymbolAssignment, containing an expression that may
+ /// change the address where the linker is outputting data
+ ///
+ void linearizeAST(const Sections *sections);
+ void linearizeAST(const InputSectionsCmd *inputSections);
+ void linearizeAST(const InputSection *inputSection);
+
+ void perform(const LinkerScript *ls);
+
+ std::vector<std::unique_ptr<Parser>> _scripts;
+ std::vector<const Command *> _layoutCommands;
+ std::unordered_multimap<std::string, int> _memberToLayoutOrder;
+ std::vector<std::pair<StringRef, int>> _memberNameWildcards;
+ mutable std::unordered_map<SectionKey, int, SectionKeyHash, SectionKeyEq>
+ _cacheSectionOrder, _cacheExpressionOrder;
+ llvm::DenseSet<int> _deliveredExprs;
+ mutable llvm::StringSet<> _definedSymbols;
+
+ Expression::SymbolTableTy _symbolTable;
+};
+
+llvm::BumpPtrAllocator &Command::getAllocator() const {
+ return _ctx.getAllocator();
+}
+llvm::BumpPtrAllocator &Expression::getAllocator() const {
+ return _ctx.getAllocator();
+}
+} // end namespace script
+} // end namespace lld
+
+#endif
diff --git a/include/lld/ReaderWriter/MachOLinkingContext.h b/include/lld/ReaderWriter/MachOLinkingContext.h
new file mode 100644
index 000000000000..8e253a1235f1
--- /dev/null
+++ b/include/lld/ReaderWriter/MachOLinkingContext.h
@@ -0,0 +1,369 @@
+//===- 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/StringMap.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MachO.h"
+#include <set>
+
+using llvm::MachO::HeaderFileType;
+
+namespace lld {
+
+namespace mach_o {
+class ArchHandler;
+class MachODylibFile;
+class MachOFile;
+}
+
+class MachOLinkingContext : public LinkingContext {
+public:
+ MachOLinkingContext();
+ ~MachOLinkingContext();
+
+ 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
+ };
+
+ /// 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);
+
+ void addPasses(PassManager &pm) override;
+ bool validateImpl(raw_ostream &diagnostics) override;
+ std::string demangle(StringRef symbolName) const override;
+
+ bool createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
+
+ 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; }
+ /// 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; }
+
+ uint64_t baseAddress() const { return _baseAddress; }
+ void setBaseAddress(uint64_t baseAddress) { _baseAddress = baseAddress; }
+
+ /// \brief 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;
+
+ /// \brief 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);
+
+ /// \brief 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).
+ ErrorOr<StringRef> searchDirForLibrary(StringRef path,
+ StringRef libName) const;
+
+ /// \brief Iterates through all search path entries looking for libName (as
+ /// specified by -lFoo).
+ ErrorOr<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);
+
+ /// \brief Iterates through all framework directories looking for
+ /// Foo.framework/Foo (when fwName = "Foo").
+ ErrorOr<StringRef> findPathForFramework(StringRef fwName) const;
+
+ /// \brief 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; }
+
+ /// \brief 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; }
+
+ /// \brief 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; }
+
+ /// \brief 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; }
+
+ /// \brief 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 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, uint8_t align2);
+
+ /// Returns true if specified section had alignment constraints.
+ bool sectionAligned(StringRef seg, StringRef sect, uint8_t &align2) 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 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;
+
+ /// 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;
+
+ /// 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(const MemoryBuffer &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);
+
+ void finalizeInputFiles() override;
+
+ bool customAtomOrderer(const DefinedAtom *left, const DefinedAtom *right,
+ bool &leftBeforeRight) const;
+
+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;
+ uint8_t align2;
+ };
+
+ 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; // e.g MH_EXECUTE
+ bool _outputMachOTypeStatic; // Disambiguate static vs dynamic prog
+ bool _doNothing; // for -help and -v which just print info
+ bool _pie;
+ Arch _arch;
+ OS _os;
+ uint32_t _osMinVersion;
+ uint64_t _pageZeroSize;
+ uint64_t _pageSize;
+ uint64_t _baseAddress;
+ uint32_t _compatibilityVersion;
+ uint32_t _currentVersion;
+ StringRef _installName;
+ StringRefVector _rpaths;
+ bool _deadStrippableDylib;
+ bool _printAtoms;
+ bool _testingFileUsage;
+ bool _keepPrivateExterns;
+ bool _demangle;
+ 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::set<mach_o::MachODylibFile*> _allDylibs;
+ mutable std::set<mach_o::MachODylibFile*> _upwardDylibs;
+ mutable std::vector<std::unique_ptr<File>> _indirectDylibs;
+ ExportMode _exportMode;
+ llvm::StringSet<> _exportedSymbols;
+ DebugInfoMode _debugInfoMode;
+ std::unique_ptr<llvm::raw_fd_ostream> _dependencyInfo;
+ llvm::StringMap<std::vector<OrderFileNode>> _orderFiles;
+ unsigned _orderFileEntries;
+};
+
+} // end namespace lld
+
+#endif
diff --git a/include/lld/ReaderWriter/PECOFFLinkingContext.h b/include/lld/ReaderWriter/PECOFFLinkingContext.h
new file mode 100644
index 000000000000..cccb8ac03b6e
--- /dev/null
+++ b/include/lld/ReaderWriter/PECOFFLinkingContext.h
@@ -0,0 +1,463 @@
+//===- lld/ReaderWriter/PECOFFLinkingContext.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_PECOFF_LINKING_CONTEXT_H
+#define LLD_READER_WRITER_PECOFF_LINKING_CONTEXT_H
+
+#include "lld/Core/LinkingContext.h"
+#include "lld/Core/Reader.h"
+#include "lld/Core/Writer.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/COFF.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileUtilities.h"
+#include <map>
+#include <mutex>
+#include <set>
+#include <vector>
+
+using llvm::COFF::MachineTypes;
+using llvm::COFF::WindowsSubsystem;
+
+static const uint8_t DEFAULT_DOS_STUB[128] = {'M', 'Z'};
+
+namespace lld {
+
+class PECOFFLinkingContext : public LinkingContext {
+public:
+ PECOFFLinkingContext()
+ : _mutex(), _allocMutex(), _hasEntry(true),
+ _baseAddress(invalidBaseAddress), _stackReserve(1024 * 1024),
+ _stackCommit(4096), _heapReserve(1024 * 1024), _heapCommit(4096),
+ _noDefaultLibAll(false), _sectionDefaultAlignment(4096),
+ _subsystem(llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN),
+ _machineType(llvm::COFF::IMAGE_FILE_MACHINE_I386), _imageVersion(0, 0),
+ _minOSVersion(6, 0), _nxCompat(true), _largeAddressAware(false),
+ _allowBind(true), _allowIsolation(true), _swapRunFromCD(false),
+ _swapRunFromNet(false), _baseRelocationEnabled(true),
+ _terminalServerAware(true), _dynamicBaseEnabled(true),
+ _createManifest(true), _embedManifest(false), _manifestId(1),
+ _manifestUAC(true), _manifestLevel("'asInvoker'"),
+ _manifestUiAccess("'false'"), _isDll(false), _highEntropyVA(true),
+ _requireSEH(false), _noSEH(false), _implib(""), _debug(false),
+ _pdbFilePath(""), _dosStub(llvm::makeArrayRef(DEFAULT_DOS_STUB)),
+ _parseDirectives(nullptr) {
+ setDeadStripping(true);
+ }
+
+ struct Version {
+ Version(int v1, int v2) : majorVersion(v1), minorVersion(v2) {}
+ int majorVersion;
+ int minorVersion;
+ };
+
+ struct ExportDesc {
+ ExportDesc()
+ : ordinal(-1), noname(false), isData(false), isPrivate(false) {}
+
+ bool operator<(const ExportDesc &other) const {
+ return getExternalName().compare(other.getExternalName()) < 0;
+ }
+
+ StringRef getRealName() const {
+ return mangledName.empty() ? name : mangledName;
+ }
+
+ StringRef getExternalName() const {
+ return externalName.empty() ? name : externalName;
+ }
+
+ std::string name;
+ std::string externalName;
+ std::string mangledName;
+ int ordinal;
+ bool noname;
+ bool isData;
+ bool isPrivate;
+ };
+
+ typedef bool (*ParseDirectives)(int, const char **, PECOFFLinkingContext &,
+ raw_ostream &);
+
+ /// \brief Casting support
+ static bool classof(const LinkingContext *info) { return true; }
+
+ Writer &writer() const override;
+ bool validateImpl(raw_ostream &diagnostics) override;
+
+ void addPasses(PassManager &pm) override;
+
+ bool createImplicitFiles(
+ std::vector<std::unique_ptr<File> > &result) override;
+
+ bool is64Bit() const {
+ return _machineType == llvm::COFF::IMAGE_FILE_MACHINE_AMD64;
+ }
+
+ // Returns a set of all defined symbols in input files.
+ const std::set<std::string> &definedSymbols();
+
+ /// Page size of x86 processor. Some data needs to be aligned at page boundary
+ /// when loaded into memory.
+ uint64_t getPageSize() const {
+ return 0x1000;
+ }
+
+ void appendInputSearchPath(StringRef dirPath) {
+ _inputSearchPaths.push_back(dirPath);
+ }
+
+ const std::vector<StringRef> getInputSearchPaths() {
+ return _inputSearchPaths;
+ }
+
+ void registerTemporaryFile(StringRef path) {
+ std::unique_ptr<llvm::FileRemover> fileRemover(
+ new llvm::FileRemover(Twine(allocate(path))));
+ _tempFiles.push_back(std::move(fileRemover));
+ }
+
+ StringRef searchLibraryFile(StringRef path) const;
+
+ StringRef decorateSymbol(StringRef name) const;
+ StringRef undecorateSymbol(StringRef name) const;
+
+ void setEntrySymbolName(StringRef name) { _entry = name; }
+ StringRef getEntrySymbolName() const { return _entry; }
+
+ void setHasEntry(bool val) { _hasEntry = val; }
+ bool hasEntry() const { return _hasEntry; }
+
+ void setBaseAddress(uint64_t addr) { _baseAddress = addr; }
+ uint64_t getBaseAddress() const;
+
+ void setStackReserve(uint64_t size) { _stackReserve = size; }
+ void setStackCommit(uint64_t size) { _stackCommit = size; }
+ uint64_t getStackReserve() const { return _stackReserve; }
+ uint64_t getStackCommit() const { return _stackCommit; }
+
+ void setHeapReserve(uint64_t size) { _heapReserve = size; }
+ void setHeapCommit(uint64_t size) { _heapCommit = size; }
+ uint64_t getHeapReserve() const { return _heapReserve; }
+ uint64_t getHeapCommit() const { return _heapCommit; }
+
+ void setSectionDefaultAlignment(uint32_t val) {
+ _sectionDefaultAlignment = val;
+ }
+ uint32_t getSectionDefaultAlignment() const {
+ return _sectionDefaultAlignment;
+ }
+
+ void setSubsystem(WindowsSubsystem ss) { _subsystem = ss; }
+ WindowsSubsystem getSubsystem() const { return _subsystem; }
+
+ void setMachineType(MachineTypes type) { _machineType = type; }
+ MachineTypes getMachineType() const { return _machineType; }
+
+ void setImageVersion(const Version &version) { _imageVersion = version; }
+ Version getImageVersion() const { return _imageVersion; }
+
+ void setMinOSVersion(const Version &version) { _minOSVersion = version; }
+ Version getMinOSVersion() const { return _minOSVersion; }
+
+ void setNxCompat(bool nxCompat) { _nxCompat = nxCompat; }
+ bool isNxCompat() const { return _nxCompat; }
+
+ void setLargeAddressAware(bool val) { _largeAddressAware = val; }
+ bool getLargeAddressAware() const { return _largeAddressAware; }
+
+ void setAllowBind(bool val) { _allowBind = val; }
+ bool getAllowBind() const { return _allowBind; }
+
+ void setAllowIsolation(bool val) { _allowIsolation = val; }
+ bool getAllowIsolation() const { return _allowIsolation; }
+
+ void setSwapRunFromCD(bool val) { _swapRunFromCD = val; }
+ bool getSwapRunFromCD() const { return _swapRunFromCD; }
+
+ void setSwapRunFromNet(bool val) { _swapRunFromNet = val; }
+ bool getSwapRunFromNet() const { return _swapRunFromNet; }
+
+ void setBaseRelocationEnabled(bool val) { _baseRelocationEnabled = val; }
+ bool getBaseRelocationEnabled() const { return _baseRelocationEnabled; }
+
+ void setTerminalServerAware(bool val) { _terminalServerAware = val; }
+ bool isTerminalServerAware() const { return _terminalServerAware; }
+
+ void setDynamicBaseEnabled(bool val) { _dynamicBaseEnabled = val; }
+ bool getDynamicBaseEnabled() const { return _dynamicBaseEnabled; }
+
+ void setCreateManifest(bool val) { _createManifest = val; }
+ bool getCreateManifest() const { return _createManifest; }
+
+ void setManifestOutputPath(std::string val) { _manifestOutputPath = val; }
+ const std::string &getManifestOutputPath() const {
+ return _manifestOutputPath;
+ }
+
+ void setEmbedManifest(bool val) { _embedManifest = val; }
+ bool getEmbedManifest() const { return _embedManifest; }
+
+ void setManifestId(int val) { _manifestId = val; }
+ int getManifestId() const { return _manifestId; }
+
+ void setManifestUAC(bool val) { _manifestUAC = val; }
+ bool getManifestUAC() const { return _manifestUAC; }
+
+ void setManifestLevel(std::string val) { _manifestLevel = std::move(val); }
+ const std::string &getManifestLevel() const { return _manifestLevel; }
+
+ void setManifestUiAccess(std::string val) { _manifestUiAccess = val; }
+ const std::string &getManifestUiAccess() const { return _manifestUiAccess; }
+
+ void setManifestDependency(std::string val) { _manifestDependency = val; }
+ const std::string &getManifestDependency() const {
+ return _manifestDependency;
+ }
+
+ void setIsDll(bool val) { _isDll = val; }
+ bool isDll() const { return _isDll; }
+
+ void setSafeSEH(bool val) {
+ if (val)
+ _requireSEH = true;
+ else
+ _noSEH = true;
+ }
+ bool requireSEH() const { return _requireSEH; }
+ bool noSEH() const { return _noSEH; }
+
+ void setHighEntropyVA(bool val) { _highEntropyVA = val; }
+ bool getHighEntropyVA() const { return _highEntropyVA; }
+
+ void setOutputImportLibraryPath(const std::string &val) { _implib = val; }
+ std::string getOutputImportLibraryPath() const;
+
+ void setDebug(bool val) { _debug = val; }
+ bool getDebug() { return _debug; }
+
+ void setPDBFilePath(StringRef str) { _pdbFilePath = str; }
+ std::string getPDBFilePath() const;
+
+ void addDelayLoadDLL(StringRef dll) {
+ _delayLoadDLLs.insert(dll.lower());
+ }
+ bool isDelayLoadDLL(StringRef dll) const {
+ return _delayLoadDLLs.count(dll.lower()) == 1;
+ }
+
+ StringRef getOutputSectionName(StringRef sectionName) const;
+ bool addSectionRenaming(raw_ostream &diagnostics,
+ StringRef from, StringRef to);
+
+ const std::set<std::string> &getAlternateNames(StringRef name) {
+ return _alternateNames[name];
+ }
+
+ void addAlternateName(StringRef weak, StringRef def) {
+ _alternateNames[def].insert(weak);
+ }
+
+ void addNoDefaultLib(StringRef path) {
+ if (path.endswith_lower(".lib"))
+ _noDefaultLibs.insert(path.drop_back(4).lower());
+ else
+ _noDefaultLibs.insert(path.lower());
+ }
+
+ bool hasNoDefaultLib(StringRef path) const {
+ if (path.endswith_lower(".lib"))
+ return _noDefaultLibs.count(path.drop_back(4).lower()) > 0;
+ return _noDefaultLibs.count(path.lower()) > 0;
+ }
+
+ void setNoDefaultLibAll(bool val) { _noDefaultLibAll = val; }
+ bool getNoDefaultLibAll() const { return _noDefaultLibAll; }
+
+ void setSectionSetMask(StringRef sectionName, uint32_t flags);
+ void setSectionClearMask(StringRef sectionName, uint32_t flags);
+ uint32_t getSectionAttributes(StringRef sectionName, uint32_t flags) const;
+
+ void setDosStub(ArrayRef<uint8_t> data) { _dosStub = data; }
+ ArrayRef<uint8_t> getDosStub() const { return _dosStub; }
+
+ void addDllExport(ExportDesc &desc);
+ std::vector<ExportDesc> &getDllExports() { return _dllExports; }
+ const std::vector<ExportDesc> &getDllExports() const { return _dllExports; }
+
+ StringRef getDelayLoadHelperName() const {
+ return is64Bit() ? "__delayLoadHelper2" : "___delayLoadHelper2@8";
+ }
+
+ StringRef allocate(StringRef ref) const {
+ _allocMutex.lock();
+ char *x = _allocator.Allocate<char>(ref.size() + 1);
+ _allocMutex.unlock();
+ memcpy(x, ref.data(), ref.size());
+ x[ref.size()] = '\0';
+ return x;
+ }
+
+ ArrayRef<uint8_t> allocate(ArrayRef<uint8_t> array) const {
+ size_t size = array.size();
+ _allocMutex.lock();
+ uint8_t *p = _allocator.Allocate<uint8_t>(size);
+ _allocMutex.unlock();
+ memcpy(p, array.data(), size);
+ return ArrayRef<uint8_t>(p, p + array.size());
+ }
+
+ template <typename T> T &allocateCopy(const T &x) const {
+ _allocMutex.lock();
+ T *r = new (_allocator) T(x);
+ _allocMutex.unlock();
+ return *r;
+ }
+
+ void addLibraryFile(std::unique_ptr<FileNode> file);
+
+ void setModuleDefinitionFile(const std::string val) {
+ _moduleDefinitionFile = val;
+ }
+ std::string getModuleDefinitionFile() const {
+ return _moduleDefinitionFile;
+ }
+
+ std::recursive_mutex &getMutex() { return _mutex; }
+
+ void setParseDirectives(ParseDirectives parseDirectives) {
+ _parseDirectives = parseDirectives;
+ }
+
+ ParseDirectives getParseDirectives() {
+ return _parseDirectives;
+ }
+
+protected:
+ /// Method to create a internal file for the entry symbol
+ std::unique_ptr<File> createEntrySymbolFile() const override;
+
+ /// Method to create a internal file for an undefined symbol
+ std::unique_ptr<File> createUndefinedSymbolFile() const override;
+
+private:
+ enum : uint64_t {
+ invalidBaseAddress = UINT64_MAX,
+ pe32DefaultBaseAddress = 0x400000U,
+ pe32PlusDefaultBaseAddress = 0x140000000U
+ };
+
+ std::recursive_mutex _mutex;
+ mutable std::mutex _allocMutex;
+
+ std::string _entry;
+
+ // False if /noentry option is given.
+ bool _hasEntry;
+
+ // The start address for the program. The default value for the executable is
+ // 0x400000, but can be altered using /base command line option.
+ uint64_t _baseAddress;
+
+ uint64_t _stackReserve;
+ uint64_t _stackCommit;
+ uint64_t _heapReserve;
+ uint64_t _heapCommit;
+ bool _noDefaultLibAll;
+ uint32_t _sectionDefaultAlignment;
+ WindowsSubsystem _subsystem;
+ MachineTypes _machineType;
+ Version _imageVersion;
+ Version _minOSVersion;
+ bool _nxCompat;
+ bool _largeAddressAware;
+ bool _allowBind;
+ bool _allowIsolation;
+ bool _swapRunFromCD;
+ bool _swapRunFromNet;
+ bool _baseRelocationEnabled;
+ bool _terminalServerAware;
+ bool _dynamicBaseEnabled;
+ bool _createManifest;
+ std::string _manifestOutputPath;
+ bool _embedManifest;
+ int _manifestId;
+ bool _manifestUAC;
+ std::string _manifestLevel;
+ std::string _manifestUiAccess;
+ std::string _manifestDependency;
+ bool _isDll;
+ bool _highEntropyVA;
+
+ // True if /SAFESEH option is specified. Valid only for x86. If true, LLD will
+ // produce an image with SEH table. If any modules were not compatible with
+ // SEH, LLD will exit with an error.
+ bool _requireSEH;
+
+ // True if /SAFESEH:no option is specified. Valid only for x86. If true, LLD
+ // will not produce an image with SEH table even if all input object files are
+ // compatible with SEH.
+ bool _noSEH;
+
+ // /IMPLIB command line option.
+ std::string _implib;
+
+ // True if /DEBUG is given.
+ bool _debug;
+
+ // PDB file output path. NB: this is dummy -- LLD just creates the empty file.
+ std::string _pdbFilePath;
+
+ // /DELAYLOAD option.
+ std::set<std::string> _delayLoadDLLs;
+
+ // The set to store /nodefaultlib arguments.
+ std::set<std::string> _noDefaultLibs;
+
+ std::vector<StringRef> _inputSearchPaths;
+ std::unique_ptr<Writer> _writer;
+
+ // A map for weak aliases.
+ std::map<std::string, std::set<std::string>> _alternateNames;
+
+ // A map for section renaming. For example, if there is an entry in the map
+ // whose value is .rdata -> .text, the section contens of .rdata will be
+ // merged to .text in the resulting executable.
+ std::map<std::string, std::string> _renamedSections;
+
+ // Section attributes specified by /section option.
+ std::map<std::string, uint32_t> _sectionSetMask;
+ std::map<std::string, uint32_t> _sectionClearMask;
+
+ // DLLExport'ed symbols.
+ std::vector<ExportDesc> _dllExports;
+
+ // List of files that will be removed on destruction.
+ std::vector<std::unique_ptr<llvm::FileRemover> > _tempFiles;
+
+ // DOS Stub. DOS stub is data located at the beginning of PE/COFF file.
+ // Windows loader do not really care about DOS stub contents, but it's usually
+ // a small DOS program that prints out a message "This program requires
+ // Microsoft Windows." This feature was somewhat useful before Windows 95.
+ ArrayRef<uint8_t> _dosStub;
+
+ // Name of the temporary file for lib.exe subcommand. For debugging
+ // only.
+ std::string _moduleDefinitionFile;
+
+ std::set<std::string> _definedSyms;
+ std::set<Node *> _seen;
+
+ ParseDirectives _parseDirectives;
+};
+
+} // end namespace lld
+
+#endif
diff --git a/include/lld/ReaderWriter/RelocationHelperFunctions.h b/include/lld/ReaderWriter/RelocationHelperFunctions.h
new file mode 100644
index 000000000000..8738e91ebabc
--- /dev/null
+++ b/include/lld/ReaderWriter/RelocationHelperFunctions.h
@@ -0,0 +1,57 @@
+//===- lld/ReaderWriter/RelocationHelperFunctions.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_RELOCATION_HELPER_FUNCTIONS_H
+#define LLD_READER_WRITER_RELOCATION_HELPER_FUNCTIONS_H
+
+namespace lld {
+
+/// Gather val's bits as specified by the mask. Example:
+///
+/// Val: 0bABCDEFGHIJKLMN
+/// Mask: 0b10111100001011
+/// Output: 0b000000ACDEFKMN
+template <typename T> T gatherBits(T val, T mask) {
+ T result = 0;
+ size_t off = 0;
+
+ for (size_t bit = 0; bit < sizeof(T) * 8; ++bit) {
+ bool maskBit = (mask >> bit) & 1;
+ if (maskBit) {
+ bool valBit = (val >> bit) & 1;
+ result |= static_cast<T>(valBit) << off;
+ ++off;
+ }
+ }
+ return result;
+}
+
+/// Scatter val's bits as specified by the mask. Example:
+///
+/// Val: 0bABCDEFG
+/// Mask: 0b10111100001011
+/// Output: 0b00ABCD0000E0FG
+template <typename T> T scatterBits(T val, T mask) {
+ T result = 0;
+ size_t off = 0;
+
+ for (size_t bit = 0; bit < sizeof(T) * 8; ++bit) {
+ bool maskBit = (mask >> bit) & 1;
+ if (maskBit) {
+ bool valBit = (val >> off) & 1;
+ result |= static_cast<T>(valBit) << bit;
+ ++off;
+ }
+ }
+ return result;
+}
+
+} // namespace lld
+
+#endif // LLD_READER_WRITER_RELOCATION_HELPER_FUNCTIONS_H
diff --git a/include/lld/ReaderWriter/YamlContext.h b/include/lld/ReaderWriter/YamlContext.h
new file mode 100644
index 000000000000..a15a398ec636
--- /dev/null
+++ b/include/lld/ReaderWriter/YamlContext.h
@@ -0,0 +1,46 @@
+//===- 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/Core/LLVM.h"
+#include <functional>
+#include <memory>
+#include <vector>
+
+namespace lld {
+class File;
+class LinkingContext;
+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 {
+ YamlContext()
+ : _linkingContext(nullptr), _registry(nullptr), _file(nullptr),
+ _normalizeMachOFile(nullptr) {}
+
+ const LinkingContext *_linkingContext;
+ const Registry *_registry;
+ File *_file;
+ NormalizedFile *_normalizeMachOFile;
+ StringRef _path;
+};
+
+} // end namespace lld
+
+#endif // LLD_READER_WRITER_YAML_CONTEXT_H
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
new file mode 100644
index 000000000000..699f5e93f8af
--- /dev/null
+++ b/lib/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_subdirectory(Config)
+add_subdirectory(Core)
+add_subdirectory(Driver)
+add_subdirectory(ReaderWriter)
diff --git a/lib/Config/CMakeLists.txt b/lib/Config/CMakeLists.txt
new file mode 100644
index 000000000000..f7ea0423b2c9
--- /dev/null
+++ b/lib/Config/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_llvm_library(lldConfig
+ Version.cpp
+ LINK_LIBS
+ LLVMSupport
+ )
diff --git a/lib/Config/Makefile b/lib/Config/Makefile
new file mode 100644
index 000000000000..b3c57f81418f
--- /dev/null
+++ b/lib/Config/Makefile
@@ -0,0 +1,13 @@
+##===- lib/Config/Makefile ---------------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLD_LEVEL := ../..
+LIBRARYNAME := lldConfig
+
+include $(LLD_LEVEL)/Makefile
diff --git a/lib/Config/Version.cpp b/lib/Config/Version.cpp
new file mode 100644
index 000000000000..b64ccef12c7b
--- /dev/null
+++ b/lib/Config/Version.cpp
@@ -0,0 +1,66 @@
+//===- lib/Config/Version.cpp - LLD Version Number ---------------*- C++-=====//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines several version-related utility functions for LLD.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Config/Version.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstdlib>
+#include <cstring>
+
+using namespace llvm;
+
+namespace lld {
+
+StringRef getLLDRepositoryPath() {
+#ifdef LLD_REPOSITORY_STRING
+ return LLD_REPOSITORY_STRING;
+#else
+ return "";
+#endif
+}
+
+StringRef getLLDRevision() {
+#ifdef LLD_REVISION_STRING
+ return LLD_REVISION_STRING;
+#else
+ return "";
+#endif
+}
+
+std::string getLLDRepositoryVersion() {
+ std::string buf;
+ llvm::raw_string_ostream OS(buf);
+ std::string Path = getLLDRepositoryPath();
+ std::string Revision = getLLDRevision();
+ if (!Path.empty() || !Revision.empty()) {
+ OS << '(';
+ if (!Path.empty())
+ OS << Path;
+ if (!Revision.empty()) {
+ if (!Path.empty())
+ OS << ' ';
+ OS << Revision;
+ }
+ OS << ')';
+ }
+ return OS.str();
+}
+
+StringRef getLLDVersion() {
+#ifdef LLD_VERSION_STRING
+ return LLD_VERSION_STRING;
+#else
+ return "";
+#endif
+}
+
+} // end namespace lld
diff --git a/lib/Core/CMakeLists.txt b/lib/Core/CMakeLists.txt
new file mode 100644
index 000000000000..009b50a38335
--- /dev/null
+++ b/lib/Core/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_llvm_library(lldCore
+ DefinedAtom.cpp
+ Error.cpp
+ File.cpp
+ LinkingContext.cpp
+ Reader.cpp
+ Resolver.cpp
+ SymbolTable.cpp
+ Writer.cpp
+ LINK_LIBS
+ LLVMSupport
+ )
diff --git a/lib/Core/DefinedAtom.cpp b/lib/Core/DefinedAtom.cpp
new file mode 100644
index 000000000000..b3f81ca65a91
--- /dev/null
+++ b/lib/Core/DefinedAtom.cpp
@@ -0,0 +1,96 @@
+//===- DefinedAtom.cpp ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/ErrorHandling.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+
+namespace lld {
+
+DefinedAtom::ContentPermissions DefinedAtom::permissions() const {
+ // By default base permissions on content type.
+ return permissions(this->contentType());
+}
+
+// Utility function for deriving permissions from content type
+DefinedAtom::ContentPermissions DefinedAtom::permissions(ContentType type) {
+ switch (type) {
+ case typeCode:
+ case typeResolver:
+ case typeBranchIsland:
+ case typeBranchShim:
+ case typeStub:
+ case typeStubHelper:
+ case typeMachHeader:
+ return permR_X;
+
+ case typeConstant:
+ case typeCString:
+ case typeUTF16String:
+ case typeCFI:
+ case typeLSDA:
+ case typeLiteral4:
+ case typeLiteral8:
+ case typeLiteral16:
+ case typeDTraceDOF:
+ case typeCompactUnwindInfo:
+ case typeProcessedUnwindInfo:
+ case typeRONote:
+ case typeNoAlloc:
+ return permR__;
+
+ case typeData:
+ case typeDataFast:
+ case typeZeroFill:
+ case typeZeroFillFast:
+ case typeObjC1Class:
+ case typeLazyPointer:
+ case typeLazyDylibPointer:
+ case typeThunkTLV:
+ case typeRWNote:
+ return permRW_;
+
+ case typeGOT:
+ case typeConstData:
+ case typeCFString:
+ case typeInitializerPtr:
+ case typeTerminatorPtr:
+ case typeCStringPtr:
+ case typeObjCClassPtr:
+ case typeObjC2CategoryList:
+ case typeInterposingTuples:
+ case typeTLVInitialData:
+ case typeTLVInitialZeroFill:
+ case typeTLVInitializerPtr:
+ case typeThreadData:
+ case typeThreadZeroFill:
+ return permRW_L;
+
+ case typeGroupComdat:
+ case typeGnuLinkOnce:
+ case typeUnknown:
+ case typeTempLTO:
+ return permUnknown;
+ }
+ llvm_unreachable("unknown content type");
+}
+
+bool DefinedAtom::compareByPosition(const DefinedAtom *lhs,
+ const DefinedAtom *rhs) {
+ if (lhs == rhs)
+ return false;
+ const File *lhsFile = &lhs->file();
+ const File *rhsFile = &rhs->file();
+ if (lhsFile->ordinal() != rhsFile->ordinal())
+ return lhsFile->ordinal() < rhsFile->ordinal();
+ assert(lhs->ordinal() != rhs->ordinal());
+ return lhs->ordinal() < rhs->ordinal();
+}
+
+} // namespace
diff --git a/lib/Core/Error.cpp b/lib/Core/Error.cpp
new file mode 100644
index 000000000000..24809c3869e5
--- /dev/null
+++ b/lib/Core/Error.cpp
@@ -0,0 +1,151 @@
+//===- Error.cpp - system_error extensions for lld --------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/Error.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <mutex>
+#include <string>
+#include <vector>
+
+using namespace lld;
+
+class _NativeReaderErrorCategory : public std::error_category {
+public:
+ const char* name() const LLVM_NOEXCEPT override {
+ return "lld.native.reader";
+ }
+
+ std::string message(int ev) const override {
+ switch (static_cast<NativeReaderError>(ev)) {
+ case NativeReaderError::success:
+ return "Success";
+ case NativeReaderError::unknown_file_format:
+ return "Unknown file format";
+ case NativeReaderError::file_too_short:
+ return "file truncated";
+ case NativeReaderError::file_malformed:
+ return "file malformed";
+ case NativeReaderError::memory_error:
+ return "out of memory";
+ case NativeReaderError::unknown_chunk_type:
+ return "unknown chunk type";
+ case NativeReaderError::conflicting_target_machine:
+ return "conflicting target machine";
+ }
+ llvm_unreachable("An enumerator of NativeReaderError does not have a "
+ "message defined.");
+ }
+};
+
+const std::error_category &lld::native_reader_category() {
+ static _NativeReaderErrorCategory o;
+ return o;
+}
+
+class _YamlReaderErrorCategory : public std::error_category {
+public:
+ const char* name() const LLVM_NOEXCEPT override {
+ return "lld.yaml.reader";
+ }
+
+ std::string message(int ev) const override {
+ switch (static_cast<YamlReaderError>(ev)) {
+ case YamlReaderError::success:
+ return "Success";
+ case YamlReaderError::unknown_keyword:
+ return "Unknown keyword found in yaml file";
+ case YamlReaderError::illegal_value:
+ return "Bad value found in yaml file";
+ }
+ llvm_unreachable("An enumerator of YamlReaderError does not have a "
+ "message defined.");
+ }
+};
+
+const std::error_category &lld::YamlReaderCategory() {
+ static _YamlReaderErrorCategory o;
+ return o;
+}
+
+class _LinkerScriptReaderErrorCategory : public std::error_category {
+public:
+ const char *name() const LLVM_NOEXCEPT override {
+ return "lld.linker-script.reader";
+ }
+
+ std::string message(int ev) const override {
+ switch (static_cast<LinkerScriptReaderError>(ev)) {
+ case LinkerScriptReaderError::success:
+ return "Success";
+ case LinkerScriptReaderError::parse_error:
+ return "Error parsing linker script";
+ case LinkerScriptReaderError::unknown_symbol_in_expr:
+ return "Unknown symbol found when evaluating linker script expression";
+ case LinkerScriptReaderError::unrecognized_function_in_expr:
+ return "Unrecognized function call when evaluating linker script "
+ "expression";
+ }
+ llvm_unreachable("An enumerator of LinkerScriptReaderError does not have a "
+ "message defined.");
+ }
+};
+
+const std::error_category &lld::LinkerScriptReaderCategory() {
+ static _LinkerScriptReaderErrorCategory o;
+ return o;
+}
+
+
+namespace lld {
+
+/// Temporary class to enable make_dynamic_error_code() until
+/// llvm::ErrorOr<> is updated to work with error encapsulations
+/// other than error_code.
+class dynamic_error_category : public std::error_category {
+public:
+ ~dynamic_error_category() LLVM_NOEXCEPT {}
+
+ const char *name() const LLVM_NOEXCEPT override {
+ return "lld.dynamic_error";
+ }
+
+ std::string message(int ev) const override {
+ assert(ev >= 0);
+ assert(ev < (int)_messages.size());
+ // The value is an index into the string vector.
+ return _messages[ev];
+ }
+
+ int add(std::string msg) {
+ std::lock_guard<std::recursive_mutex> lock(_mutex);
+ // Value zero is always the successs value.
+ if (_messages.empty())
+ _messages.push_back("Success");
+ _messages.push_back(msg);
+ // Return the index of the string just appended.
+ return _messages.size() - 1;
+ }
+
+private:
+ std::vector<std::string> _messages;
+ std::recursive_mutex _mutex;
+};
+
+static dynamic_error_category categorySingleton;
+
+std::error_code make_dynamic_error_code(StringRef msg) {
+ return std::error_code(categorySingleton.add(msg), categorySingleton);
+}
+
+std::error_code make_dynamic_error_code(const Twine &msg) {
+ return std::error_code(categorySingleton.add(msg.str()), categorySingleton);
+}
+
+}
diff --git a/lib/Core/File.cpp b/lib/Core/File.cpp
new file mode 100644
index 000000000000..dbac86b368aa
--- /dev/null
+++ b/lib/Core/File.cpp
@@ -0,0 +1,30 @@
+//===- Core/File.cpp - A Container of Atoms -------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/File.h"
+#include "lld/Core/LLVM.h"
+#include <mutex>
+
+namespace lld {
+
+File::~File() {}
+
+File::atom_collection_empty<DefinedAtom> File::_noDefinedAtoms;
+File::atom_collection_empty<UndefinedAtom> File::_noUndefinedAtoms;
+File::atom_collection_empty<SharedLibraryAtom> File::_noSharedLibraryAtoms;
+File::atom_collection_empty<AbsoluteAtom> File::_noAbsoluteAtoms;
+
+std::error_code File::parse() {
+ std::lock_guard<std::mutex> lock(_parseMutex);
+ if (!_lastError.hasValue())
+ _lastError = doParse();
+ return _lastError.getValue();
+}
+
+} // namespace lld
diff --git a/lib/Core/LinkingContext.cpp b/lib/Core/LinkingContext.cpp
new file mode 100644
index 000000000000..c6656b935916
--- /dev/null
+++ b/lib/Core/LinkingContext.cpp
@@ -0,0 +1,104 @@
+//===- lib/Core/LinkingContext.cpp - Linker Context Object Interface ------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/Alias.h"
+#include "lld/Core/LinkingContext.h"
+#include "lld/Core/Resolver.h"
+#include "lld/Core/Simple.h"
+#include "lld/Core/Writer.h"
+#include "llvm/ADT/Triple.h"
+
+namespace lld {
+
+LinkingContext::LinkingContext()
+ : _deadStrip(false), _allowDuplicates(false),
+ _globalsAreDeadStripRoots(false),
+ _searchArchivesToOverrideTentativeDefinitions(false),
+ _searchSharedLibrariesToOverrideTentativeDefinitions(false),
+ _warnIfCoalesableAtomsHaveDifferentCanBeNull(false),
+ _warnIfCoalesableAtomsHaveDifferentLoadName(false),
+ _printRemainingUndefines(true), _allowRemainingUndefines(false),
+ _logInputFiles(false), _allowShlibUndefines(false),
+ _outputFileType(OutputFileType::Default), _nextOrdinal(0) {}
+
+LinkingContext::~LinkingContext() {}
+
+bool LinkingContext::validate(raw_ostream &diagnostics) {
+ return validateImpl(diagnostics);
+}
+
+std::error_code LinkingContext::writeFile(const File &linkedFile) const {
+ return this->writer().writeFile(linkedFile, _outputPath);
+}
+
+bool LinkingContext::createImplicitFiles(
+ std::vector<std::unique_ptr<File> > &result) {
+ return this->writer().createImplicitFiles(result);
+}
+
+std::unique_ptr<File> LinkingContext::createEntrySymbolFile() const {
+ return createEntrySymbolFile("<command line option -e>");
+}
+
+std::unique_ptr<File>
+LinkingContext::createEntrySymbolFile(StringRef filename) const {
+ if (entrySymbolName().empty())
+ return nullptr;
+ std::unique_ptr<SimpleFile> entryFile(new SimpleFile(filename));
+ entryFile->addAtom(
+ *(new (_allocator) SimpleUndefinedAtom(*entryFile, entrySymbolName())));
+ return std::move(entryFile);
+}
+
+std::unique_ptr<File> LinkingContext::createUndefinedSymbolFile() const {
+ return createUndefinedSymbolFile("<command line option -u or --defsym>");
+}
+
+std::unique_ptr<File>
+LinkingContext::createUndefinedSymbolFile(StringRef filename) const {
+ if (_initialUndefinedSymbols.empty())
+ return nullptr;
+ std::unique_ptr<SimpleFile> undefinedSymFile(new SimpleFile(filename));
+ for (StringRef undefSym : _initialUndefinedSymbols)
+ undefinedSymFile->addAtom(*(new (_allocator) SimpleUndefinedAtom(
+ *undefinedSymFile, undefSym)));
+ return std::move(undefinedSymFile);
+}
+
+std::unique_ptr<File> LinkingContext::createAliasSymbolFile() const {
+ if (getAliases().empty())
+ return nullptr;
+ std::unique_ptr<SimpleFile> file(new SimpleFile("<alias>"));
+ for (const auto &i : getAliases()) {
+ StringRef from = i.first;
+ StringRef to = i.second;
+ SimpleDefinedAtom *fromAtom = new (_allocator) AliasAtom(*file, from);
+ UndefinedAtom *toAtom = new (_allocator) SimpleUndefinedAtom(*file, to);
+ fromAtom->addReference(Reference::KindNamespace::all,
+ Reference::KindArch::all, Reference::kindLayoutAfter,
+ 0, toAtom, 0);
+ file->addAtom(*fromAtom);
+ file->addAtom(*toAtom);
+ }
+ return std::move(file);
+}
+
+void LinkingContext::createInternalFiles(
+ std::vector<std::unique_ptr<File> > &result) const {
+ if (std::unique_ptr<File> file = createEntrySymbolFile())
+ result.push_back(std::move(file));
+ if (std::unique_ptr<File> file = createUndefinedSymbolFile())
+ result.push_back(std::move(file));
+ if (std::unique_ptr<File> file = createAliasSymbolFile())
+ result.push_back(std::move(file));
+}
+
+void LinkingContext::addPasses(PassManager &pm) {}
+
+} // end namespace lld
diff --git a/lib/Core/Makefile b/lib/Core/Makefile
new file mode 100644
index 000000000000..042d01a1e1b3
--- /dev/null
+++ b/lib/Core/Makefile
@@ -0,0 +1,13 @@
+##===- lld/lib/Core/Makefile ---------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLD_LEVEL := ../..
+LIBRARYNAME := lldCore
+
+include $(LLD_LEVEL)/Makefile
diff --git a/lib/Core/Reader.cpp b/lib/Core/Reader.cpp
new file mode 100644
index 000000000000..6f8b8cbd1bf8
--- /dev/null
+++ b/lib/Core/Reader.cpp
@@ -0,0 +1,117 @@
+//===- lib/Core/Reader.cpp ------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/File.h"
+#include "lld/Core/Reader.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/FileUtilities.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include <memory>
+#include <system_error>
+
+namespace lld {
+
+YamlIOTaggedDocumentHandler::~YamlIOTaggedDocumentHandler() {}
+
+void Registry::add(std::unique_ptr<Reader> reader) {
+ _readers.push_back(std::move(reader));
+}
+
+void Registry::add(std::unique_ptr<YamlIOTaggedDocumentHandler> handler) {
+ _yamlHandlers.push_back(std::move(handler));
+}
+
+std::error_code
+Registry::loadFile(std::unique_ptr<MemoryBuffer> mb,
+ std::vector<std::unique_ptr<File>> &result) const {
+ // Get file type.
+ StringRef content(mb->getBufferStart(), mb->getBufferSize());
+ llvm::sys::fs::file_magic fileType = llvm::sys::fs::identify_magic(content);
+ // Get file extension.
+ StringRef extension = llvm::sys::path::extension(mb->getBufferIdentifier());
+
+ // Ask each registered reader if it can handle this file type or extension.
+ for (const std::unique_ptr<Reader> &reader : _readers) {
+ if (!reader->canParse(fileType, extension, *mb))
+ continue;
+ if (std::error_code ec = reader->loadFile(std::move(mb), *this, result))
+ return ec;
+ return std::error_code();
+ }
+
+ // No Reader could parse this file.
+ return make_error_code(llvm::errc::executable_format_error);
+}
+
+static const Registry::KindStrings kindStrings[] = {
+ {Reference::kindLayoutAfter, "layout-after"},
+ {Reference::kindGroupChild, "group-child"},
+ {Reference::kindAssociate, "associate"},
+ LLD_KIND_STRING_END};
+
+Registry::Registry() {
+ addKindTable(Reference::KindNamespace::all, Reference::KindArch::all,
+ kindStrings);
+}
+
+bool Registry::handleTaggedDoc(llvm::yaml::IO &io,
+ const lld::File *&file) const {
+ for (const std::unique_ptr<YamlIOTaggedDocumentHandler> &h : _yamlHandlers)
+ if (h->handledDocTag(io, file))
+ return true;
+ return false;
+}
+
+
+void Registry::addKindTable(Reference::KindNamespace ns,
+ Reference::KindArch arch,
+ const KindStrings array[]) {
+ KindEntry entry = { ns, arch, array };
+ _kindEntries.push_back(entry);
+}
+
+bool Registry::referenceKindFromString(StringRef inputStr,
+ Reference::KindNamespace &ns,
+ Reference::KindArch &arch,
+ Reference::KindValue &value) const {
+ for (const KindEntry &entry : _kindEntries) {
+ for (const KindStrings *pair = entry.array; !pair->name.empty(); ++pair) {
+ if (!inputStr.equals(pair->name))
+ continue;
+ ns = entry.ns;
+ arch = entry.arch;
+ value = pair->value;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Registry::referenceKindToString(Reference::KindNamespace ns,
+ Reference::KindArch arch,
+ Reference::KindValue value,
+ StringRef &str) const {
+ for (const KindEntry &entry : _kindEntries) {
+ if (entry.ns != ns)
+ continue;
+ if (entry.arch != arch)
+ continue;
+ for (const KindStrings *pair = entry.array; !pair->name.empty(); ++pair) {
+ if (pair->value != value)
+ continue;
+ str = pair->name;
+ return true;
+ }
+ }
+ return false;
+}
+
+} // end namespace lld
diff --git a/lib/Core/Resolver.cpp b/lib/Core/Resolver.cpp
new file mode 100644
index 000000000000..393a7ef2bfc8
--- /dev/null
+++ b/lib/Core/Resolver.cpp
@@ -0,0 +1,516 @@
+//===- Core/Resolver.cpp - Resolves Atom References -----------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/Atom.h"
+#include "lld/Core/ArchiveLibraryFile.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Instrumentation.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/LinkingContext.h"
+#include "lld/Core/Resolver.h"
+#include "lld/Core/SharedLibraryFile.h"
+#include "lld/Core/SymbolTable.h"
+#include "lld/Core/UndefinedAtom.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <utility>
+#include <vector>
+
+namespace lld {
+
+bool Resolver::handleFile(File &file) {
+ bool undefAdded = false;
+ for (const DefinedAtom *atom : file.defined())
+ doDefinedAtom(*atom);
+ for (const UndefinedAtom *atom : file.undefined()) {
+ if (doUndefinedAtom(*atom)) {
+ undefAdded = true;
+ maybePreloadArchiveMember(atom->name());
+ }
+ }
+ for (const SharedLibraryAtom *atom : file.sharedLibrary())
+ doSharedLibraryAtom(*atom);
+ for (const AbsoluteAtom *atom : file.absolute())
+ doAbsoluteAtom(*atom);
+ return undefAdded;
+}
+
+void Resolver::forEachUndefines(File &file, bool searchForOverrides,
+ UndefCallback callback) {
+ size_t i = _undefineIndex[&file];
+ do {
+ for (; i < _undefines.size(); ++i) {
+ StringRef undefName = _undefines[i];
+ if (undefName.empty())
+ continue;
+ const Atom *atom = _symbolTable.findByName(undefName);
+ if (!isa<UndefinedAtom>(atom) || _symbolTable.isCoalescedAway(atom)) {
+ // The symbol was resolved by some other file. Cache the result.
+ _undefines[i] = "";
+ continue;
+ }
+ callback(undefName, false);
+ }
+ if (!searchForOverrides)
+ continue;
+ for (StringRef tentDefName : _symbolTable.tentativeDefinitions()) {
+ // Load for previous tentative may also have loaded
+ // something that overrode this tentative, so always check.
+ const Atom *curAtom = _symbolTable.findByName(tentDefName);
+ assert(curAtom != nullptr);
+ if (const DefinedAtom *curDefAtom = dyn_cast<DefinedAtom>(curAtom))
+ if (curDefAtom->merge() == DefinedAtom::mergeAsTentative)
+ callback(tentDefName, true);
+ }
+ } while (i < _undefines.size());
+ _undefineIndex[&file] = i;
+}
+
+bool Resolver::handleArchiveFile(File &file) {
+ ArchiveLibraryFile *archiveFile = cast<ArchiveLibraryFile>(&file);
+ bool searchForOverrides =
+ _ctx.searchArchivesToOverrideTentativeDefinitions();
+ bool undefAdded = false;
+ forEachUndefines(file, searchForOverrides,
+ [&](StringRef undefName, bool dataSymbolOnly) {
+ if (File *member = archiveFile->find(undefName, dataSymbolOnly)) {
+ member->setOrdinal(_ctx.getNextOrdinalAndIncrement());
+ member->beforeLink();
+ updatePreloadArchiveMap();
+ undefAdded = handleFile(*member) || undefAdded;
+ }
+ });
+ return undefAdded;
+}
+
+void Resolver::handleSharedLibrary(File &file) {
+ // Add all the atoms from the shared library
+ SharedLibraryFile *sharedLibrary = cast<SharedLibraryFile>(&file);
+ handleFile(*sharedLibrary);
+ bool searchForOverrides =
+ _ctx.searchSharedLibrariesToOverrideTentativeDefinitions();
+ forEachUndefines(file, searchForOverrides,
+ [&](StringRef undefName, bool dataSymbolOnly) {
+ if (const SharedLibraryAtom *atom =
+ sharedLibrary->exports(undefName, dataSymbolOnly))
+ doSharedLibraryAtom(*atom);
+ });
+}
+
+bool Resolver::doUndefinedAtom(const UndefinedAtom &atom) {
+ DEBUG_WITH_TYPE("resolver", llvm::dbgs()
+ << " UndefinedAtom: "
+ << llvm::format("0x%09lX", &atom)
+ << ", name=" << atom.name() << "\n");
+
+ // add to list of known atoms
+ _atoms.push_back(&atom);
+
+ // tell symbol table
+ bool newUndefAdded = _symbolTable.add(atom);
+ if (newUndefAdded)
+ _undefines.push_back(atom.name());
+
+ // If the undefined symbol has an alternative name, try to resolve the
+ // symbol with the name to give it a second chance. This feature is used
+ // for COFF "weak external" symbol.
+ if (newUndefAdded || !_symbolTable.isDefined(atom.name())) {
+ if (const UndefinedAtom *fallbackAtom = atom.fallback()) {
+ doUndefinedAtom(*fallbackAtom);
+ _symbolTable.addReplacement(&atom, fallbackAtom);
+ }
+ }
+ return newUndefAdded;
+}
+
+/// \brief Add the section group and the group-child reference members.
+void Resolver::maybeAddSectionGroupOrGnuLinkOnce(const DefinedAtom &atom) {
+ // First time adding a group?
+ bool isFirstTime = _symbolTable.addGroup(atom);
+
+ if (!isFirstTime) {
+ // If duplicate symbols are allowed, select the first group.
+ if (_ctx.getAllowDuplicates())
+ return;
+ auto *prevGroup = dyn_cast<DefinedAtom>(_symbolTable.findGroup(atom.name()));
+ assert(prevGroup &&
+ "Internal Error: The group atom could only be a defined atom");
+ // The atoms should be of the same content type, reject invalid group
+ // resolution behaviors.
+ if (atom.contentType() == prevGroup->contentType())
+ return;
+ llvm::errs() << "SymbolTable: error while merging " << atom.name()
+ << "\n";
+ llvm::report_fatal_error("duplicate symbol error");
+ return;
+ }
+
+ for (const Reference *r : atom) {
+ if (r->kindNamespace() == lld::Reference::KindNamespace::all &&
+ r->kindValue() == lld::Reference::kindGroupChild) {
+ const DefinedAtom *target = dyn_cast<DefinedAtom>(r->target());
+ assert(target && "Internal Error: kindGroupChild references need to "
+ "be associated with Defined Atoms only");
+ _atoms.push_back(target);
+ _symbolTable.add(*target);
+ }
+ }
+}
+
+// Called on each atom when a file is added. Returns true if a given
+// atom is added to the symbol table.
+void Resolver::doDefinedAtom(const DefinedAtom &atom) {
+ DEBUG_WITH_TYPE("resolver", llvm::dbgs()
+ << " DefinedAtom: "
+ << llvm::format("0x%09lX", &atom)
+ << ", file=#"
+ << atom.file().ordinal()
+ << ", atom=#"
+ << atom.ordinal()
+ << ", name="
+ << atom.name()
+ << "\n");
+
+ // add to list of known atoms
+ _atoms.push_back(&atom);
+
+ if (atom.isGroupParent()) {
+ maybeAddSectionGroupOrGnuLinkOnce(atom);
+ } else {
+ _symbolTable.add(atom);
+ }
+
+ // An atom that should never be dead-stripped is a dead-strip root.
+ if (_ctx.deadStrip() && atom.deadStrip() == DefinedAtom::deadStripNever) {
+ _deadStripRoots.insert(&atom);
+ }
+}
+
+void Resolver::doSharedLibraryAtom(const SharedLibraryAtom &atom) {
+ DEBUG_WITH_TYPE("resolver", llvm::dbgs()
+ << " SharedLibraryAtom: "
+ << llvm::format("0x%09lX", &atom)
+ << ", name="
+ << atom.name()
+ << "\n");
+
+ // add to list of known atoms
+ _atoms.push_back(&atom);
+
+ // tell symbol table
+ _symbolTable.add(atom);
+}
+
+void Resolver::doAbsoluteAtom(const AbsoluteAtom &atom) {
+ DEBUG_WITH_TYPE("resolver", llvm::dbgs()
+ << " AbsoluteAtom: "
+ << llvm::format("0x%09lX", &atom)
+ << ", name="
+ << atom.name()
+ << "\n");
+
+ // add to list of known atoms
+ _atoms.push_back(&atom);
+
+ // tell symbol table
+ if (atom.scope() != Atom::scopeTranslationUnit)
+ _symbolTable.add(atom);
+}
+
+// utility to add a vector of atoms
+void Resolver::addAtoms(const std::vector<const DefinedAtom *> &newAtoms) {
+ for (const DefinedAtom *newAtom : newAtoms)
+ doDefinedAtom(*newAtom);
+}
+
+// Instantiate an archive file member if there's a file containing a
+// defined symbol for a given symbol name. Instantiation is done in a
+// different worker thread and has no visible side effect.
+void Resolver::maybePreloadArchiveMember(StringRef sym) {
+ auto it = _archiveMap.find(sym);
+ if (it == _archiveMap.end())
+ return;
+ ArchiveLibraryFile *archive = it->second;
+ archive->preload(_ctx.getTaskGroup(), sym);
+}
+
+// Returns true if at least one of N previous files has created an
+// undefined symbol.
+bool Resolver::undefinesAdded(int begin, int end) {
+ std::vector<std::unique_ptr<Node>> &inputs = _ctx.getNodes();
+ for (int i = begin; i < end; ++i)
+ if (FileNode *node = dyn_cast<FileNode>(inputs[i].get()))
+ if (_newUndefinesAdded[node->getFile()])
+ return true;
+ return false;
+}
+
+File *Resolver::getFile(int &index) {
+ std::vector<std::unique_ptr<Node>> &inputs = _ctx.getNodes();
+ if ((size_t)index >= inputs.size())
+ return nullptr;
+ if (GroupEnd *group = dyn_cast<GroupEnd>(inputs[index].get())) {
+ // We are at the end of the current group. If one or more new
+ // undefined atom has been added in the last groupSize files, we
+ // reiterate over the files.
+ int size = group->getSize();
+ if (undefinesAdded(index - size, index)) {
+ index -= size;
+ return getFile(index);
+ }
+ ++index;
+ return getFile(index);
+ }
+ return cast<FileNode>(inputs[index++].get())->getFile();
+}
+
+// Update a map of Symbol -> ArchiveFile. The map is used for speculative
+// file loading.
+void Resolver::updatePreloadArchiveMap() {
+ std::vector<std::unique_ptr<Node>> &nodes = _ctx.getNodes();
+ for (int i = nodes.size() - 1; i >= 0; --i) {
+ auto *fnode = dyn_cast<FileNode>(nodes[i].get());
+ if (!fnode)
+ continue;
+ auto *archive = dyn_cast<ArchiveLibraryFile>(fnode->getFile());
+ if (!archive || _archiveSeen.count(archive))
+ continue;
+ _archiveSeen.insert(archive);
+ for (StringRef sym : archive->getDefinedSymbols())
+ _archiveMap[sym] = archive;
+ }
+}
+
+// Keep adding atoms until _ctx.getNextFile() returns an error. This
+// function is where undefined atoms are resolved.
+bool Resolver::resolveUndefines() {
+ ScopedTask task(getDefaultDomain(), "resolveUndefines");
+ int index = 0;
+ std::set<File *> seen;
+ for (;;) {
+ bool undefAdded = false;
+ File *file = getFile(index);
+ if (!file)
+ return true;
+ if (std::error_code ec = file->parse()) {
+ llvm::errs() << "Cannot open " + file->path()
+ << ": " << ec.message() << "\n";
+ return false;
+ }
+ file->beforeLink();
+ updatePreloadArchiveMap();
+ switch (file->kind()) {
+ case File::kindObject:
+ // The same file may be visited more than once if the file is
+ // in --start-group and --end-group. Only library files should
+ // be processed more than once.
+ if (seen.count(file))
+ break;
+ seen.insert(file);
+ assert(!file->hasOrdinal());
+ file->setOrdinal(_ctx.getNextOrdinalAndIncrement());
+ undefAdded = handleFile(*file);
+ break;
+ case File::kindArchiveLibrary:
+ if (!file->hasOrdinal())
+ file->setOrdinal(_ctx.getNextOrdinalAndIncrement());
+ undefAdded = handleArchiveFile(*file);
+ break;
+ case File::kindSharedLibrary:
+ if (!file->hasOrdinal())
+ file->setOrdinal(_ctx.getNextOrdinalAndIncrement());
+ handleSharedLibrary(*file);
+ break;
+ }
+ _newUndefinesAdded[file] = undefAdded;
+ }
+}
+
+// switch all references to undefined or coalesced away atoms
+// to the new defined atom
+void Resolver::updateReferences() {
+ ScopedTask task(getDefaultDomain(), "updateReferences");
+ for (const Atom *atom : _atoms) {
+ if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom)) {
+ for (const Reference *ref : *defAtom) {
+ // A reference of type kindAssociate should't be updated.
+ // Instead, an atom having such reference will be removed
+ // if the target atom is coalesced away, so that they will
+ // go away as a group.
+ if (ref->kindNamespace() == lld::Reference::KindNamespace::all &&
+ ref->kindValue() == lld::Reference::kindAssociate) {
+ if (_symbolTable.isCoalescedAway(atom))
+ _deadAtoms.insert(ref->target());
+ continue;
+ }
+ const Atom *newTarget = _symbolTable.replacement(ref->target());
+ const_cast<Reference *>(ref)->setTarget(newTarget);
+ }
+ }
+ }
+}
+
+// For dead code stripping, recursively mark atoms "live"
+void Resolver::markLive(const Atom *atom) {
+ // Mark the atom is live. If it's already marked live, then stop recursion.
+ auto exists = _liveAtoms.insert(atom);
+ if (!exists.second)
+ return;
+
+ // Mark all atoms it references as live
+ if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom)) {
+ for (const Reference *ref : *defAtom)
+ markLive(ref->target());
+ for (auto &p : llvm::make_range(_reverseRef.equal_range(defAtom))) {
+ const Atom *target = p.second;
+ markLive(target);
+ }
+ }
+}
+
+static bool isBackref(const Reference *ref) {
+ if (ref->kindNamespace() != lld::Reference::KindNamespace::all)
+ return false;
+ return (ref->kindValue() == lld::Reference::kindLayoutAfter ||
+ ref->kindValue() == lld::Reference::kindGroupChild);
+}
+
+// remove all atoms not actually used
+void Resolver::deadStripOptimize() {
+ ScopedTask task(getDefaultDomain(), "deadStripOptimize");
+ // only do this optimization with -dead_strip
+ if (!_ctx.deadStrip())
+ return;
+
+ // Some type of references prevent referring atoms to be dead-striped.
+ // Make a reverse map of such references before traversing the graph.
+ // While traversing the list of atoms, mark AbsoluteAtoms as live
+ // in order to avoid reclaim.
+ for (const Atom *atom : _atoms) {
+ if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom))
+ for (const Reference *ref : *defAtom)
+ if (isBackref(ref))
+ _reverseRef.insert(std::make_pair(ref->target(), atom));
+ if (const AbsoluteAtom *absAtom = dyn_cast<AbsoluteAtom>(atom))
+ markLive(absAtom);
+ }
+
+ // By default, shared libraries are built with all globals as dead strip roots
+ if (_ctx.globalsAreDeadStripRoots())
+ for (const Atom *atom : _atoms)
+ if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom))
+ if (defAtom->scope() == DefinedAtom::scopeGlobal)
+ _deadStripRoots.insert(defAtom);
+
+ // Or, use list of names that are dead strip roots.
+ for (const StringRef &name : _ctx.deadStripRoots()) {
+ const Atom *symAtom = _symbolTable.findByName(name);
+ assert(symAtom);
+ _deadStripRoots.insert(symAtom);
+ }
+
+ // mark all roots as live, and recursively all atoms they reference
+ for (const Atom *dsrAtom : _deadStripRoots)
+ markLive(dsrAtom);
+
+ // now remove all non-live atoms from _atoms
+ _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), [&](const Atom *a) {
+ return _liveAtoms.count(a) == 0;
+ }),
+ _atoms.end());
+}
+
+// error out if some undefines remain
+bool Resolver::checkUndefines() {
+ // build vector of remaining undefined symbols
+ std::vector<const UndefinedAtom *> undefinedAtoms = _symbolTable.undefines();
+ if (_ctx.deadStrip()) {
+ // When dead code stripping, we don't care if dead atoms are undefined.
+ undefinedAtoms.erase(
+ std::remove_if(undefinedAtoms.begin(), undefinedAtoms.end(),
+ [&](const Atom *a) { return _liveAtoms.count(a) == 0; }),
+ undefinedAtoms.end());
+ }
+
+ if (undefinedAtoms.empty())
+ return false;
+
+ // Warn about unresolved symbols.
+ bool foundUndefines = false;
+ for (const UndefinedAtom *undef : undefinedAtoms) {
+ // Skip over a weak symbol.
+ if (undef->canBeNull() != UndefinedAtom::canBeNullNever)
+ continue;
+
+ // If this is a library and undefined symbols are allowed on the
+ // target platform, skip over it.
+ if (isa<SharedLibraryFile>(undef->file()) && _ctx.allowShlibUndefines())
+ continue;
+
+ // If the undefine is coalesced away, skip over it.
+ if (_symbolTable.isCoalescedAway(undef))
+ continue;
+
+ // Seems like this symbol is undefined. Warn that.
+ foundUndefines = true;
+ if (_ctx.printRemainingUndefines()) {
+ llvm::errs() << "Undefined symbol: " << undef->file().path()
+ << ": " << _ctx.demangle(undef->name())
+ << "\n";
+ }
+ }
+ if (!foundUndefines)
+ return false;
+ if (_ctx.printRemainingUndefines())
+ llvm::errs() << "symbol(s) not found\n";
+ return true;
+}
+
+// remove from _atoms all coaleseced away atoms
+void Resolver::removeCoalescedAwayAtoms() {
+ ScopedTask task(getDefaultDomain(), "removeCoalescedAwayAtoms");
+ _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), [&](const Atom *a) {
+ return _symbolTable.isCoalescedAway(a) || _deadAtoms.count(a);
+ }),
+ _atoms.end());
+}
+
+bool Resolver::resolve() {
+ updatePreloadArchiveMap();
+ if (!resolveUndefines())
+ return false;
+ updateReferences();
+ deadStripOptimize();
+ if (checkUndefines())
+ if (!_ctx.allowRemainingUndefines())
+ return false;
+ removeCoalescedAwayAtoms();
+ _result->addAtoms(_atoms);
+ return true;
+}
+
+void Resolver::MergedFile::addAtoms(std::vector<const Atom *> &all) {
+ ScopedTask task(getDefaultDomain(), "addAtoms");
+ DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "Resolver final atom list:\n");
+ for (const Atom *atom : all) {
+ DEBUG_WITH_TYPE("resolver", llvm::dbgs()
+ << llvm::format(" 0x%09lX", atom)
+ << ", name="
+ << atom->name()
+ << "\n");
+ addAtom(*atom);
+ }
+}
+
+} // namespace lld
diff --git a/lib/Core/SymbolTable.cpp b/lib/Core/SymbolTable.cpp
new file mode 100644
index 000000000000..f3f2da9262e0
--- /dev/null
+++ b/lib/Core/SymbolTable.cpp
@@ -0,0 +1,390 @@
+//===- Core/SymbolTable.cpp - Main Symbol Table ---------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/SymbolTable.h"
+#include "lld/Core/AbsoluteAtom.h"
+#include "lld/Core/Atom.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/LinkingContext.h"
+#include "lld/Core/Resolver.h"
+#include "lld/Core/SharedLibraryAtom.h"
+#include "lld/Core/UndefinedAtom.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdlib>
+#include <vector>
+
+namespace lld {
+SymbolTable::SymbolTable(LinkingContext &context) : _context(context) {}
+
+bool SymbolTable::add(const UndefinedAtom &atom) { return addByName(atom); }
+
+bool SymbolTable::add(const SharedLibraryAtom &atom) { return addByName(atom); }
+
+bool SymbolTable::add(const AbsoluteAtom &atom) { return addByName(atom); }
+
+bool SymbolTable::add(const DefinedAtom &atom) {
+ if (!atom.name().empty() &&
+ atom.scope() != DefinedAtom::scopeTranslationUnit) {
+ // Named atoms cannot be merged by content.
+ assert(atom.merge() != DefinedAtom::mergeByContent);
+ // Track named atoms that are not scoped to file (static).
+ return addByName(atom);
+ }
+ if (atom.merge() == DefinedAtom::mergeByContent) {
+ // Named atoms cannot be merged by content.
+ assert(atom.name().empty());
+ // Currently only read-only constants can be merged.
+ if (atom.permissions() == DefinedAtom::permR__)
+ return addByContent(atom);
+ // TODO: support mergeByContent of data atoms by comparing content & fixups.
+ }
+ return false;
+}
+
+const Atom *SymbolTable::findGroup(StringRef sym) {
+ NameToAtom::iterator pos = _groupTable.find(sym);
+ if (pos == _groupTable.end())
+ return nullptr;
+ return pos->second;
+}
+
+bool SymbolTable::addGroup(const DefinedAtom &da) {
+ StringRef name = da.name();
+ assert(!name.empty());
+ const Atom *existing = findGroup(name);
+ if (existing == nullptr) {
+ _groupTable[name] = &da;
+ return true;
+ }
+ _replacedAtoms[&da] = existing;
+ return false;
+}
+
+enum NameCollisionResolution {
+ NCR_First,
+ NCR_Second,
+ NCR_DupDef,
+ NCR_DupUndef,
+ NCR_DupShLib,
+ NCR_Error
+};
+
+static NameCollisionResolution cases[4][4] = {
+ //regular absolute undef sharedLib
+ {
+ // first is regular
+ NCR_DupDef, NCR_Error, NCR_First, NCR_First
+ },
+ {
+ // first is absolute
+ NCR_Error, NCR_Error, NCR_First, NCR_First
+ },
+ {
+ // first is undef
+ NCR_Second, NCR_Second, NCR_DupUndef, NCR_Second
+ },
+ {
+ // first is sharedLib
+ NCR_Second, NCR_Second, NCR_First, NCR_DupShLib
+ }
+};
+
+static NameCollisionResolution collide(Atom::Definition first,
+ Atom::Definition second) {
+ return cases[first][second];
+}
+
+enum MergeResolution {
+ MCR_First,
+ MCR_Second,
+ MCR_Largest,
+ MCR_SameSize,
+ MCR_Error
+};
+
+static MergeResolution mergeCases[][6] = {
+ // no tentative weak weakAddress sameNameAndSize largest
+ {MCR_Error, MCR_First, MCR_First, MCR_First, MCR_SameSize, MCR_Largest}, // no
+ {MCR_Second, MCR_Largest, MCR_Second, MCR_Second, MCR_SameSize, MCR_Largest}, // tentative
+ {MCR_Second, MCR_First, MCR_First, MCR_Second, MCR_SameSize, MCR_Largest}, // weak
+ {MCR_Second, MCR_First, MCR_First, MCR_First, MCR_SameSize, MCR_Largest}, // weakAddress
+ {MCR_SameSize, MCR_SameSize, MCR_SameSize, MCR_SameSize, MCR_SameSize, MCR_SameSize}, // sameSize
+ {MCR_Largest, MCR_Largest, MCR_Largest, MCR_Largest, MCR_SameSize, MCR_Largest}, // largest
+};
+
+static MergeResolution mergeSelect(DefinedAtom::Merge first,
+ DefinedAtom::Merge second) {
+ assert(first != DefinedAtom::mergeByContent);
+ assert(second != DefinedAtom::mergeByContent);
+ return mergeCases[first][second];
+}
+
+bool SymbolTable::addByName(const Atom &newAtom) {
+ StringRef name = newAtom.name();
+ assert(!name.empty());
+ const Atom *existing = findByName(name);
+ if (existing == nullptr) {
+ // Name is not in symbol table yet, add it associate with this atom.
+ _nameTable[name] = &newAtom;
+ return true;
+ }
+
+ // Do nothing if the same object is added more than once.
+ if (existing == &newAtom)
+ return false;
+
+ // Name is already in symbol table and associated with another atom.
+ bool useNew = true;
+ switch (collide(existing->definition(), newAtom.definition())) {
+ case NCR_First:
+ useNew = false;
+ break;
+ case NCR_Second:
+ useNew = true;
+ break;
+ case NCR_DupDef: {
+ const auto *existingDef = cast<DefinedAtom>(existing);
+ const auto *newDef = cast<DefinedAtom>(&newAtom);
+ switch (mergeSelect(existingDef->merge(), newDef->merge())) {
+ case MCR_First:
+ useNew = false;
+ break;
+ case MCR_Second:
+ useNew = true;
+ break;
+ case MCR_Largest: {
+ uint64_t existingSize = existingDef->sectionSize();
+ uint64_t newSize = newDef->sectionSize();
+ useNew = (newSize >= existingSize);
+ break;
+ }
+ case MCR_SameSize: {
+ uint64_t existingSize = existingDef->sectionSize();
+ uint64_t newSize = newDef->sectionSize();
+ if (existingSize == newSize) {
+ useNew = true;
+ break;
+ }
+ llvm::errs() << "Size mismatch: "
+ << existing->name() << " (" << existingSize << ") "
+ << newAtom.name() << " (" << newSize << ")\n";
+ // fallthrough
+ }
+ case MCR_Error:
+ if (!_context.getAllowDuplicates()) {
+ llvm::errs() << "Duplicate symbols: "
+ << existing->name()
+ << ":"
+ << existing->file().path()
+ << " and "
+ << newAtom.name()
+ << ":"
+ << newAtom.file().path()
+ << "\n";
+ llvm::report_fatal_error("duplicate symbol error");
+ }
+ useNew = false;
+ break;
+ }
+ break;
+ }
+ case NCR_DupUndef: {
+ const UndefinedAtom* existingUndef = cast<UndefinedAtom>(existing);
+ const UndefinedAtom* newUndef = cast<UndefinedAtom>(&newAtom);
+
+ bool sameCanBeNull = (existingUndef->canBeNull() == newUndef->canBeNull());
+ if (!sameCanBeNull &&
+ _context.warnIfCoalesableAtomsHaveDifferentCanBeNull()) {
+ llvm::errs() << "lld warning: undefined symbol "
+ << existingUndef->name()
+ << " has different weakness in "
+ << existingUndef->file().path()
+ << " and in " << newUndef->file().path() << "\n";
+ }
+
+ const UndefinedAtom *existingFallback = existingUndef->fallback();
+ const UndefinedAtom *newFallback = newUndef->fallback();
+ bool hasDifferentFallback =
+ (existingFallback && newFallback &&
+ existingFallback->name() != newFallback->name());
+ if (hasDifferentFallback) {
+ llvm::errs() << "lld warning: undefined symbol "
+ << existingUndef->name() << " has different fallback: "
+ << existingFallback->name() << " in "
+ << existingUndef->file().path() << " and "
+ << newFallback->name() << " in "
+ << newUndef->file().path() << "\n";
+ }
+
+ bool hasNewFallback = newUndef->fallback();
+ if (sameCanBeNull)
+ useNew = hasNewFallback;
+ else
+ useNew = (newUndef->canBeNull() < existingUndef->canBeNull());
+ break;
+ }
+ case NCR_DupShLib: {
+ const SharedLibraryAtom *curShLib = cast<SharedLibraryAtom>(existing);
+ const SharedLibraryAtom *newShLib = cast<SharedLibraryAtom>(&newAtom);
+ bool sameNullness =
+ (curShLib->canBeNullAtRuntime() == newShLib->canBeNullAtRuntime());
+ bool sameName = curShLib->loadName().equals(newShLib->loadName());
+ if (sameName && !sameNullness &&
+ _context.warnIfCoalesableAtomsHaveDifferentCanBeNull()) {
+ // FIXME: need diagonstics interface for writing warning messages
+ llvm::errs() << "lld warning: shared library symbol "
+ << curShLib->name() << " has different weakness in "
+ << curShLib->file().path() << " and in "
+ << newShLib->file().path();
+ }
+ if (!sameName && _context.warnIfCoalesableAtomsHaveDifferentLoadName()) {
+ // FIXME: need diagonstics interface for writing warning messages
+ llvm::errs() << "lld warning: shared library symbol "
+ << curShLib->name() << " has different load path in "
+ << curShLib->file().path() << " and in "
+ << newShLib->file().path();
+ }
+ useNew = false;
+ break;
+ }
+ case NCR_Error:
+ llvm::errs() << "SymbolTable: error while merging " << name << "\n";
+ llvm::report_fatal_error("duplicate symbol error");
+ break;
+ }
+
+ // Give context a chance to change which is kept.
+ _context.notifySymbolTableCoalesce(existing, &newAtom, useNew);
+
+ if (useNew) {
+ // Update name table to use new atom.
+ _nameTable[name] = &newAtom;
+ // Add existing atom to replacement table.
+ _replacedAtoms[existing] = &newAtom;
+ } else {
+ // New atom is not being used. Add it to replacement table.
+ _replacedAtoms[&newAtom] = existing;
+ }
+ return false;
+}
+
+unsigned SymbolTable::AtomMappingInfo::getHashValue(const DefinedAtom *atom) {
+ auto content = atom->rawContent();
+ return llvm::hash_combine(atom->size(),
+ atom->contentType(),
+ llvm::hash_combine_range(content.begin(),
+ content.end()));
+}
+
+bool SymbolTable::AtomMappingInfo::isEqual(const DefinedAtom * const l,
+ const DefinedAtom * const r) {
+ if (l == r)
+ return true;
+ if (l == getEmptyKey())
+ return false;
+ if (r == getEmptyKey())
+ return false;
+ if (l == getTombstoneKey())
+ return false;
+ if (r == getTombstoneKey())
+ return false;
+ if (l->contentType() != r->contentType())
+ return false;
+ if (l->size() != r->size())
+ return false;
+ if (l->sectionChoice() != r->sectionChoice())
+ return false;
+ if (l->sectionChoice() == DefinedAtom::sectionCustomRequired) {
+ if (!l->customSectionName().equals(r->customSectionName()))
+ return false;
+ }
+ ArrayRef<uint8_t> lc = l->rawContent();
+ ArrayRef<uint8_t> rc = r->rawContent();
+ return memcmp(lc.data(), rc.data(), lc.size()) == 0;
+}
+
+bool SymbolTable::addByContent(const DefinedAtom &newAtom) {
+ AtomContentSet::iterator pos = _contentTable.find(&newAtom);
+ if (pos == _contentTable.end()) {
+ _contentTable.insert(&newAtom);
+ return true;
+ }
+ const Atom* existing = *pos;
+ // New atom is not being used. Add it to replacement table.
+ _replacedAtoms[&newAtom] = existing;
+ return false;
+}
+
+const Atom *SymbolTable::findByName(StringRef sym) {
+ NameToAtom::iterator pos = _nameTable.find(sym);
+ if (pos == _nameTable.end())
+ return nullptr;
+ return pos->second;
+}
+
+bool SymbolTable::isDefined(StringRef sym) {
+ if (const Atom *atom = findByName(sym))
+ return !isa<UndefinedAtom>(atom);
+ return false;
+}
+
+void SymbolTable::addReplacement(const Atom *replaced,
+ const Atom *replacement) {
+ _replacedAtoms[replaced] = replacement;
+}
+
+const Atom *SymbolTable::replacement(const Atom *atom) {
+ // Find the replacement for a given atom. Atoms in _replacedAtoms
+ // may be chained, so find the last one.
+ for (;;) {
+ AtomToAtom::iterator pos = _replacedAtoms.find(atom);
+ if (pos == _replacedAtoms.end())
+ return atom;
+ atom = pos->second;
+ }
+}
+
+bool SymbolTable::isCoalescedAway(const Atom *atom) {
+ return _replacedAtoms.count(atom) > 0;
+}
+
+std::vector<const UndefinedAtom *> SymbolTable::undefines() {
+ std::vector<const UndefinedAtom *> ret;
+ for (auto it : _nameTable) {
+ const Atom *atom = it.second;
+ assert(atom != nullptr);
+ if (const auto *undef = dyn_cast<const UndefinedAtom>(atom))
+ if (_replacedAtoms.count(undef) == 0)
+ ret.push_back(undef);
+ }
+ return ret;
+}
+
+std::vector<StringRef> SymbolTable::tentativeDefinitions() {
+ std::vector<StringRef> ret;
+ for (auto entry : _nameTable) {
+ const Atom *atom = entry.second;
+ StringRef name = entry.first;
+ assert(atom != nullptr);
+ if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom))
+ if (defAtom->merge() == DefinedAtom::mergeAsTentative)
+ ret.push_back(name);
+ }
+ return ret;
+}
+
+} // namespace lld
diff --git a/lib/Core/TODO.txt b/lib/Core/TODO.txt
new file mode 100644
index 000000000000..196a3e02c2fc
--- /dev/null
+++ b/lib/Core/TODO.txt
@@ -0,0 +1,18 @@
+lib/Core
+~~~~~~~~
+
+* Add endianness support to the native reader and writer.
+
+* The NativeReader has lots of similar code for converting arrays of ivar
+ data in mapped memory into arrays of objects. The commonality can be
+ factored out, maybe templatized.
+
+* The NativeFileFormat.h is old school C structs and constants. We scope
+ things better by defining constants used with a struct inside the struct
+ declaration.
+
+* The native reader and writer currently just blast in memory enumeration
+ values (e.g. DefinedAtom::Scope) into a byte in the disk format. To support
+ future changes to the enumerations, there should be a translation layer
+ to map disk values to in-memory values.
+
diff --git a/lib/Core/Writer.cpp b/lib/Core/Writer.cpp
new file mode 100644
index 000000000000..39bcc9e68523
--- /dev/null
+++ b/lib/Core/Writer.cpp
@@ -0,0 +1,23 @@
+//===- lib/Core/Writer.cpp ------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/File.h"
+#include "lld/Core/Writer.h"
+
+namespace lld {
+Writer::Writer() {
+}
+
+Writer::~Writer() {
+}
+
+bool Writer::createImplicitFiles(std::vector<std::unique_ptr<File> > &) {
+ return true;
+}
+} // end namespace lld
diff --git a/lib/Driver/CMakeLists.txt b/lib/Driver/CMakeLists.txt
new file mode 100644
index 000000000000..5a410e7eed7e
--- /dev/null
+++ b/lib/Driver/CMakeLists.txt
@@ -0,0 +1,43 @@
+set(LLVM_TARGET_DEFINITIONS UniversalDriverOptions.td)
+tablegen(LLVM UniversalDriverOptions.inc -gen-opt-parser-defs)
+set(LLVM_TARGET_DEFINITIONS GnuLdOptions.td)
+tablegen(LLVM GnuLdOptions.inc -gen-opt-parser-defs)
+set(LLVM_TARGET_DEFINITIONS CoreOptions.td)
+tablegen(LLVM CoreOptions.inc -gen-opt-parser-defs)
+set(LLVM_TARGET_DEFINITIONS DarwinLdOptions.td)
+tablegen(LLVM DarwinLdOptions.inc -gen-opt-parser-defs)
+set(LLVM_TARGET_DEFINITIONS WinLinkOptions.td)
+tablegen(LLVM WinLinkOptions.inc -gen-opt-parser-defs)
+add_public_tablegen_target(DriverOptionsTableGen)
+
+add_llvm_library(lldDriver
+ CoreDriver.cpp
+ DarwinLdDriver.cpp
+ Driver.cpp
+ GnuLdDriver.cpp
+ UniversalDriver.cpp
+ WinLinkDriver.cpp
+ WinLinkModuleDef.cpp
+ LINK_LIBS
+ lldConfig
+ lldMachO
+ lldPECOFF
+ lldELF
+ lldAArch64ELFTarget
+ lldARMELFTarget
+ lldHexagonELFTarget
+ lldMipsELFTarget
+ lldX86ELFTarget
+ lldExampleSubTarget
+ lldX86_64ELFTarget
+ lldCore
+ lldNative
+ lldReaderWriter
+ lldYAML
+ LLVMObject
+ LLVMOption
+ LLVMSupport
+ )
+
+add_dependencies(lldDriver DriverOptionsTableGen)
+
diff --git a/lib/Driver/CoreDriver.cpp b/lib/Driver/CoreDriver.cpp
new file mode 100644
index 000000000000..b8adee55746f
--- /dev/null
+++ b/lib/Driver/CoreDriver.cpp
@@ -0,0 +1,172 @@
+//===- lib/Driver/CoreDriver.cpp ------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/Reader.h"
+#include "lld/Driver/Driver.h"
+#include "lld/ReaderWriter/CoreLinkingContext.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace lld;
+
+namespace {
+
+// Create enum with OPT_xxx values for each option in CoreOptions.td
+enum {
+ OPT_INVALID = 0,
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELP, META) \
+ OPT_##ID,
+#include "CoreOptions.inc"
+#undef OPTION
+};
+
+// Create prefix string literals used in CoreOptions.td
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#include "CoreOptions.inc"
+#undef PREFIX
+
+// Create table mapping all options defined in CoreOptions.td
+static const llvm::opt::OptTable::Info infoTable[] = {
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR) \
+ { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \
+ PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS },
+#include "CoreOptions.inc"
+#undef OPTION
+};
+
+// Create OptTable class for parsing actual command line arguments
+class CoreOptTable : public llvm::opt::OptTable {
+public:
+ CoreOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable)){}
+};
+
+} // namespace anonymous
+
+
+namespace lld {
+
+static const Registry::KindStrings coreKindStrings[] = {
+ { CoreLinkingContext::TEST_RELOC_CALL32, "call32" },
+ { CoreLinkingContext::TEST_RELOC_PCREL32, "pcrel32" },
+ { CoreLinkingContext::TEST_RELOC_GOT_LOAD32, "gotLoad32" },
+ { CoreLinkingContext::TEST_RELOC_GOT_USE32, "gotUse32" },
+ { CoreLinkingContext::TEST_RELOC_LEA32_WAS_GOT, "lea32wasGot" },
+ LLD_KIND_STRING_END
+};
+
+bool CoreDriver::link(int argc, const char *argv[], raw_ostream &diagnostics) {
+ CoreLinkingContext ctx;
+
+ // Register possible input file parsers.
+ ctx.registry().addSupportNativeObjects();
+ ctx.registry().addSupportYamlFiles();
+ ctx.registry().addKindTable(Reference::KindNamespace::testing,
+ Reference::KindArch::all, coreKindStrings);
+
+ if (!parse(argc, argv, ctx))
+ return false;
+ return Driver::link(ctx);
+}
+
+bool CoreDriver::parse(int argc, const char *argv[], CoreLinkingContext &ctx,
+ raw_ostream &diagnostics) {
+ // Parse command line options using CoreOptions.td
+ std::unique_ptr<llvm::opt::InputArgList> parsedArgs;
+ CoreOptTable table;
+ unsigned missingIndex;
+ unsigned missingCount;
+ parsedArgs.reset(
+ table.ParseArgs(&argv[1], &argv[argc], missingIndex, missingCount));
+ if (missingCount) {
+ diagnostics << "error: missing arg value for '"
+ << parsedArgs->getArgString(missingIndex) << "' expected "
+ << missingCount << " argument(s).\n";
+ return false;
+ }
+
+ // Set default options
+ ctx.setOutputPath("-");
+ ctx.setDeadStripping(false);
+ ctx.setGlobalsAreDeadStripRoots(false);
+ ctx.setPrintRemainingUndefines(false);
+ ctx.setAllowRemainingUndefines(true);
+ ctx.setSearchArchivesToOverrideTentativeDefinitions(false);
+
+ // Process all the arguments and create input files.
+ for (auto inputArg : *parsedArgs) {
+ switch (inputArg->getOption().getID()) {
+ case OPT_mllvm:
+ ctx.appendLLVMOption(inputArg->getValue());
+ break;
+
+ case OPT_entry:
+ ctx.setEntrySymbolName(inputArg->getValue());
+ break;
+
+ case OPT_output:
+ ctx.setOutputPath(inputArg->getValue());
+ break;
+
+ case OPT_dead_strip:
+ ctx.setDeadStripping(true);
+ break;
+
+ case OPT_keep_globals:
+ ctx.setGlobalsAreDeadStripRoots(true);
+ break;
+
+ case OPT_undefines_are_errors:
+ ctx.setPrintRemainingUndefines(true);
+ ctx.setAllowRemainingUndefines(false);
+ break;
+
+ case OPT_commons_search_archives:
+ ctx.setSearchArchivesToOverrideTentativeDefinitions(true);
+ break;
+
+ case OPT_add_pass:
+ ctx.addPassNamed(inputArg->getValue());
+ break;
+
+ case OPT_INPUT: {
+ std::vector<std::unique_ptr<File>> files
+ = loadFile(ctx, inputArg->getValue(), false);
+ for (std::unique_ptr<File> &file : files)
+ ctx.getNodes().push_back(llvm::make_unique<FileNode>(std::move(file)));
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+
+ if (ctx.getNodes().empty()) {
+ diagnostics << "No input files\n";
+ return false;
+ }
+
+ // Validate the combination of options used.
+ return ctx.validate(diagnostics);
+}
+
+} // namespace lld
diff --git a/lib/Driver/CoreOptions.td b/lib/Driver/CoreOptions.td
new file mode 100644
index 000000000000..df7cb41737d2
--- /dev/null
+++ b/lib/Driver/CoreOptions.td
@@ -0,0 +1,15 @@
+include "llvm/Option/OptParser.td"
+
+def output : Separate<["-"], "o">;
+def entry : Separate<["-"], "e">;
+
+def dead_strip : Flag<["--"], "dead-strip">;
+def undefines_are_errors : Flag<["--"], "undefines-are-errors">;
+def keep_globals : Flag<["--"], "keep-globals">;
+def commons_search_archives : Flag<["--"], "commons-search-archives">;
+
+def add_pass : Separate<["--"], "add-pass">;
+
+def target : Separate<["-"], "target">, HelpText<"Target triple to link for">;
+def mllvm : Separate<["-"], "mllvm">, HelpText<"Options to pass to LLVM">;
+
diff --git a/lib/Driver/DarwinLdDriver.cpp b/lib/Driver/DarwinLdDriver.cpp
new file mode 100644
index 000000000000..2c64aeee38a5
--- /dev/null
+++ b/lib/Driver/DarwinLdDriver.cpp
@@ -0,0 +1,832 @@
+//===- lib/Driver/DarwinLdDriver.cpp --------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+///
+/// Concrete instance of the Driver for darwin's ld.
+///
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/File.h"
+#include "lld/Core/ArchiveLibraryFile.h"
+#include "lld/Core/SharedLibraryFile.h"
+#include "lld/Driver/Driver.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/MachO.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+
+using namespace lld;
+
+namespace {
+
+// Create enum with OPT_xxx values for each option in DarwinLdOptions.td
+enum {
+ OPT_INVALID = 0,
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELP, META) \
+ OPT_##ID,
+#include "DarwinLdOptions.inc"
+#undef OPTION
+};
+
+// Create prefix string literals used in DarwinLdOptions.td
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#include "DarwinLdOptions.inc"
+#undef PREFIX
+
+// Create table mapping all options defined in DarwinLdOptions.td
+static const llvm::opt::OptTable::Info infoTable[] = {
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR) \
+ { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \
+ PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS },
+#include "DarwinLdOptions.inc"
+#undef OPTION
+};
+
+// Create OptTable class for parsing actual command line arguments
+class DarwinLdOptTable : public llvm::opt::OptTable {
+public:
+ DarwinLdOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable)){}
+};
+
+std::vector<std::unique_ptr<File>>
+loadFile(MachOLinkingContext &ctx, StringRef path,
+ raw_ostream &diag, bool wholeArchive, bool upwardDylib) {
+ if (ctx.logInputFiles())
+ diag << path << "\n";
+
+ ErrorOr<std::unique_ptr<MemoryBuffer>> mbOrErr = ctx.getMemoryBuffer(path);
+ if (std::error_code ec = mbOrErr.getError())
+ return makeErrorFile(path, ec);
+ std::vector<std::unique_ptr<File>> files;
+ if (std::error_code ec = ctx.registry().loadFile(std::move(mbOrErr.get()), files))
+ return makeErrorFile(path, ec);
+ for (std::unique_ptr<File> &pf : files) {
+ // If file is a dylib, inform LinkingContext about it.
+ if (SharedLibraryFile *shl = dyn_cast<SharedLibraryFile>(pf.get())) {
+ if (std::error_code ec = shl->parse())
+ return makeErrorFile(path, ec);
+ ctx.registerDylib(reinterpret_cast<mach_o::MachODylibFile*>(shl),
+ upwardDylib);
+ }
+ }
+ if (wholeArchive)
+ return parseMemberFiles(files);
+ return files;
+}
+
+} // anonymous namespace
+
+// Test may be running on Windows. Canonicalize the path
+// separator to '/' to get consistent outputs for tests.
+static std::string canonicalizePath(StringRef path) {
+ char sep = llvm::sys::path::get_separator().front();
+ if (sep != '/') {
+ std::string fixedPath = path;
+ std::replace(fixedPath.begin(), fixedPath.end(), sep, '/');
+ return fixedPath;
+ } else {
+ return path;
+ }
+}
+
+static void addFile(StringRef path, MachOLinkingContext &ctx,
+ bool loadWholeArchive,
+ bool upwardDylib, raw_ostream &diag) {
+ std::vector<std::unique_ptr<File>> files =
+ loadFile(ctx, path, diag, loadWholeArchive, upwardDylib);
+ for (std::unique_ptr<File> &file : files)
+ ctx.getNodes().push_back(llvm::make_unique<FileNode>(std::move(file)));
+}
+
+// Export lists are one symbol per line. Blank lines are ignored.
+// Trailing comments start with #.
+static std::error_code parseExportsList(StringRef exportFilePath,
+ MachOLinkingContext &ctx,
+ raw_ostream &diagnostics) {
+ // Map in export list file.
+ ErrorOr<std::unique_ptr<MemoryBuffer>> mb =
+ MemoryBuffer::getFileOrSTDIN(exportFilePath);
+ if (std::error_code ec = mb.getError())
+ return ec;
+ ctx.addInputFileDependency(exportFilePath);
+ StringRef buffer = mb->get()->getBuffer();
+ while (!buffer.empty()) {
+ // Split off each line in the file.
+ std::pair<StringRef, StringRef> lineAndRest = buffer.split('\n');
+ StringRef line = lineAndRest.first;
+ // Ignore trailing # comments.
+ std::pair<StringRef, StringRef> symAndComment = line.split('#');
+ StringRef sym = symAndComment.first.trim();
+ if (!sym.empty())
+ ctx.addExportSymbol(sym);
+ buffer = lineAndRest.second;
+ }
+ return std::error_code();
+}
+
+
+
+/// Order files are one symbol per line. Blank lines are ignored.
+/// Trailing comments start with #. Symbol names can be prefixed with an
+/// architecture name and/or .o leaf name. Examples:
+/// _foo
+/// bar.o:_bar
+/// libfrob.a(bar.o):_bar
+/// x86_64:_foo64
+static std::error_code parseOrderFile(StringRef orderFilePath,
+ MachOLinkingContext &ctx,
+ raw_ostream &diagnostics) {
+ // Map in order file.
+ ErrorOr<std::unique_ptr<MemoryBuffer>> mb =
+ MemoryBuffer::getFileOrSTDIN(orderFilePath);
+ if (std::error_code ec = mb.getError())
+ return ec;
+ ctx.addInputFileDependency(orderFilePath);
+ StringRef buffer = mb->get()->getBuffer();
+ while (!buffer.empty()) {
+ // Split off each line in the file.
+ std::pair<StringRef, StringRef> lineAndRest = buffer.split('\n');
+ StringRef line = lineAndRest.first;
+ buffer = lineAndRest.second;
+ // Ignore trailing # comments.
+ std::pair<StringRef, StringRef> symAndComment = line.split('#');
+ if (symAndComment.first.empty())
+ continue;
+ StringRef sym = symAndComment.first.trim();
+ if (sym.empty())
+ continue;
+ // Check for prefix.
+ StringRef prefix;
+ std::pair<StringRef, StringRef> prefixAndSym = sym.split(':');
+ if (!prefixAndSym.second.empty()) {
+ sym = prefixAndSym.second;
+ prefix = prefixAndSym.first;
+ if (!prefix.endswith(".o") && !prefix.endswith(".o)")) {
+ // If arch name prefix does not match arch being linked, ignore symbol.
+ if (!ctx.archName().equals(prefix))
+ continue;
+ prefix = "";
+ }
+ } else
+ sym = prefixAndSym.first;
+ if (!sym.empty()) {
+ ctx.appendOrderedSymbol(sym, prefix);
+ //llvm::errs() << sym << ", prefix=" << prefix << "\n";
+ }
+ }
+ return std::error_code();
+}
+
+//
+// There are two variants of the -filelist option:
+//
+// -filelist <path>
+// In this variant, the path is to a text file which contains one file path
+// per line. There are no comments or trimming of whitespace.
+//
+// -fileList <path>,<dir>
+// In this variant, the path is to a text file which contains a partial path
+// per line. The <dir> prefix is prepended to each partial path.
+//
+static std::error_code loadFileList(StringRef fileListPath,
+ MachOLinkingContext &ctx, bool forceLoad,
+ raw_ostream &diagnostics) {
+ // If there is a comma, split off <dir>.
+ std::pair<StringRef, StringRef> opt = fileListPath.split(',');
+ StringRef filePath = opt.first;
+ StringRef dirName = opt.second;
+ ctx.addInputFileDependency(filePath);
+ // Map in file list file.
+ ErrorOr<std::unique_ptr<MemoryBuffer>> mb =
+ MemoryBuffer::getFileOrSTDIN(filePath);
+ if (std::error_code ec = mb.getError())
+ return ec;
+ StringRef buffer = mb->get()->getBuffer();
+ while (!buffer.empty()) {
+ // Split off each line in the file.
+ std::pair<StringRef, StringRef> lineAndRest = buffer.split('\n');
+ StringRef line = lineAndRest.first;
+ StringRef path;
+ if (!dirName.empty()) {
+ // If there is a <dir> then prepend dir to each line.
+ SmallString<256> fullPath;
+ fullPath.assign(dirName);
+ llvm::sys::path::append(fullPath, Twine(line));
+ path = ctx.copy(fullPath.str());
+ } else {
+ // No <dir> use whole line as input file path.
+ path = ctx.copy(line);
+ }
+ if (!ctx.pathExists(path)) {
+ return make_dynamic_error_code(Twine("File not found '")
+ + path
+ + "'");
+ }
+ if (ctx.testingFileUsage()) {
+ diagnostics << "Found filelist entry " << canonicalizePath(path) << '\n';
+ }
+ addFile(path, ctx, forceLoad, false, diagnostics);
+ buffer = lineAndRest.second;
+ }
+ return std::error_code();
+}
+
+/// Parse number assuming it is base 16, but allow 0x prefix.
+static bool parseNumberBase16(StringRef numStr, uint64_t &baseAddress) {
+ if (numStr.startswith_lower("0x"))
+ numStr = numStr.drop_front(2);
+ return numStr.getAsInteger(16, baseAddress);
+}
+
+namespace lld {
+
+bool DarwinLdDriver::linkMachO(int argc, const char *argv[],
+ raw_ostream &diagnostics) {
+ MachOLinkingContext ctx;
+ if (!parse(argc, argv, ctx, diagnostics))
+ return false;
+ if (ctx.doNothing())
+ return true;
+ return link(ctx, diagnostics);
+}
+
+bool DarwinLdDriver::parse(int argc, const char *argv[],
+ MachOLinkingContext &ctx, raw_ostream &diagnostics) {
+ // Parse command line options using DarwinLdOptions.td
+ std::unique_ptr<llvm::opt::InputArgList> parsedArgs;
+ DarwinLdOptTable table;
+ unsigned missingIndex;
+ unsigned missingCount;
+ bool globalWholeArchive = false;
+ parsedArgs.reset(
+ table.ParseArgs(&argv[1], &argv[argc], missingIndex, missingCount));
+ if (missingCount) {
+ diagnostics << "error: missing arg value for '"
+ << parsedArgs->getArgString(missingIndex) << "' expected "
+ << missingCount << " argument(s).\n";
+ return false;
+ }
+
+ for (auto unknownArg : parsedArgs->filtered(OPT_UNKNOWN)) {
+ diagnostics << "warning: ignoring unknown argument: "
+ << unknownArg->getAsString(*parsedArgs) << "\n";
+ }
+
+ // Figure out output kind ( -dylib, -r, -bundle, -preload, or -static )
+ llvm::MachO::HeaderFileType fileType = llvm::MachO::MH_EXECUTE;
+ if ( llvm::opt::Arg *kind = parsedArgs->getLastArg(OPT_dylib, OPT_relocatable,
+ OPT_bundle, OPT_static, OPT_preload)) {
+ switch (kind->getOption().getID()) {
+ case OPT_dylib:
+ fileType = llvm::MachO::MH_DYLIB;
+ break;
+ case OPT_relocatable:
+ fileType = llvm::MachO::MH_OBJECT;
+ break;
+ case OPT_bundle:
+ fileType = llvm::MachO::MH_BUNDLE;
+ break;
+ case OPT_static:
+ fileType = llvm::MachO::MH_EXECUTE;
+ break;
+ case OPT_preload:
+ fileType = llvm::MachO::MH_PRELOAD;
+ break;
+ }
+ }
+
+ // Handle -arch xxx
+ MachOLinkingContext::Arch arch = MachOLinkingContext::arch_unknown;
+ if (llvm::opt::Arg *archStr = parsedArgs->getLastArg(OPT_arch)) {
+ arch = MachOLinkingContext::archFromName(archStr->getValue());
+ if (arch == MachOLinkingContext::arch_unknown) {
+ diagnostics << "error: unknown arch named '" << archStr->getValue()
+ << "'\n";
+ return false;
+ }
+ }
+ // If no -arch specified, scan input files to find first non-fat .o file.
+ if (arch == MachOLinkingContext::arch_unknown) {
+ for (auto &inFile: parsedArgs->filtered(OPT_INPUT)) {
+ // This is expensive because it opens and maps the file. But that is
+ // ok because no -arch is rare.
+ if (MachOLinkingContext::isThinObjectFile(inFile->getValue(), arch))
+ break;
+ }
+ if (arch == MachOLinkingContext::arch_unknown
+ && !parsedArgs->getLastArg(OPT_test_file_usage)) {
+ // If no -arch and no options at all, print usage message.
+ if (parsedArgs->size() == 0)
+ table.PrintHelp(llvm::outs(), argv[0], "LLVM Linker", false);
+ else
+ diagnostics << "error: -arch not specified and could not be inferred\n";
+ return false;
+ }
+ }
+
+ // Handle -macosx_version_min or -ios_version_min
+ MachOLinkingContext::OS os = MachOLinkingContext::OS::macOSX;
+ uint32_t minOSVersion = 0;
+ if (llvm::opt::Arg *minOS =
+ parsedArgs->getLastArg(OPT_macosx_version_min, OPT_ios_version_min,
+ OPT_ios_simulator_version_min)) {
+ switch (minOS->getOption().getID()) {
+ case OPT_macosx_version_min:
+ os = MachOLinkingContext::OS::macOSX;
+ if (MachOLinkingContext::parsePackedVersion(minOS->getValue(),
+ minOSVersion)) {
+ diagnostics << "error: malformed macosx_version_min value\n";
+ return false;
+ }
+ break;
+ case OPT_ios_version_min:
+ os = MachOLinkingContext::OS::iOS;
+ if (MachOLinkingContext::parsePackedVersion(minOS->getValue(),
+ minOSVersion)) {
+ diagnostics << "error: malformed ios_version_min value\n";
+ return false;
+ }
+ break;
+ case OPT_ios_simulator_version_min:
+ os = MachOLinkingContext::OS::iOS_simulator;
+ if (MachOLinkingContext::parsePackedVersion(minOS->getValue(),
+ minOSVersion)) {
+ diagnostics << "error: malformed ios_simulator_version_min value\n";
+ return false;
+ }
+ break;
+ }
+ } else {
+ // No min-os version on command line, check environment variables
+ }
+
+ // Now that there's enough information parsed in, let the linking context
+ // set up default values.
+ ctx.configure(fileType, arch, os, minOSVersion);
+
+ // Handle -e xxx
+ if (llvm::opt::Arg *entry = parsedArgs->getLastArg(OPT_entry))
+ ctx.setEntrySymbolName(entry->getValue());
+
+ // Handle -o xxx
+ if (llvm::opt::Arg *outpath = parsedArgs->getLastArg(OPT_output))
+ ctx.setOutputPath(outpath->getValue());
+ else
+ ctx.setOutputPath("a.out");
+
+ // Handle -image_base XXX and -seg1addr XXXX
+ if (llvm::opt::Arg *imageBase = parsedArgs->getLastArg(OPT_image_base)) {
+ uint64_t baseAddress;
+ if (parseNumberBase16(imageBase->getValue(), baseAddress)) {
+ diagnostics << "error: image_base expects a hex number\n";
+ return false;
+ } else if (baseAddress < ctx.pageZeroSize()) {
+ diagnostics << "error: image_base overlaps with __PAGEZERO\n";
+ return false;
+ } else if (baseAddress % ctx.pageSize()) {
+ diagnostics << "error: image_base must be a multiple of page size ("
+ << llvm::format("0x%" PRIx64, ctx.pageSize()) << ")\n";
+ return false;
+ }
+
+ ctx.setBaseAddress(baseAddress);
+ }
+
+ // Handle -dead_strip
+ if (parsedArgs->getLastArg(OPT_dead_strip))
+ ctx.setDeadStripping(true);
+
+ // Handle -all_load
+ if (parsedArgs->getLastArg(OPT_all_load))
+ globalWholeArchive = true;
+
+ // Handle -install_name
+ if (llvm::opt::Arg *installName = parsedArgs->getLastArg(OPT_install_name))
+ ctx.setInstallName(installName->getValue());
+ else
+ ctx.setInstallName(ctx.outputPath());
+
+ // Handle -mark_dead_strippable_dylib
+ if (parsedArgs->getLastArg(OPT_mark_dead_strippable_dylib))
+ ctx.setDeadStrippableDylib(true);
+
+ // Handle -compatibility_version and -current_version
+ if (llvm::opt::Arg *vers =
+ parsedArgs->getLastArg(OPT_compatibility_version)) {
+ if (ctx.outputMachOType() != llvm::MachO::MH_DYLIB) {
+ diagnostics
+ << "error: -compatibility_version can only be used with -dylib\n";
+ return false;
+ }
+ uint32_t parsedVers;
+ if (MachOLinkingContext::parsePackedVersion(vers->getValue(), parsedVers)) {
+ diagnostics << "error: -compatibility_version value is malformed\n";
+ return false;
+ }
+ ctx.setCompatibilityVersion(parsedVers);
+ }
+
+ if (llvm::opt::Arg *vers = parsedArgs->getLastArg(OPT_current_version)) {
+ if (ctx.outputMachOType() != llvm::MachO::MH_DYLIB) {
+ diagnostics << "-current_version can only be used with -dylib\n";
+ return false;
+ }
+ uint32_t parsedVers;
+ if (MachOLinkingContext::parsePackedVersion(vers->getValue(), parsedVers)) {
+ diagnostics << "error: -current_version value is malformed\n";
+ return false;
+ }
+ ctx.setCurrentVersion(parsedVers);
+ }
+
+ // Handle -bundle_loader
+ if (llvm::opt::Arg *loader = parsedArgs->getLastArg(OPT_bundle_loader))
+ ctx.setBundleLoader(loader->getValue());
+
+ // Handle -sectalign segname sectname align
+ for (auto &alignArg : parsedArgs->filtered(OPT_sectalign)) {
+ const char* segName = alignArg->getValue(0);
+ const char* sectName = alignArg->getValue(1);
+ const char* alignStr = alignArg->getValue(2);
+ if ((alignStr[0] == '0') && (alignStr[1] == 'x'))
+ alignStr += 2;
+ unsigned long long alignValue;
+ if (llvm::getAsUnsignedInteger(alignStr, 16, alignValue)) {
+ diagnostics << "error: -sectalign alignment value '"
+ << alignStr << "' not a valid number\n";
+ return false;
+ }
+ uint8_t align2 = llvm::countTrailingZeros(alignValue);
+ if ( (unsigned long)(1 << align2) != alignValue ) {
+ diagnostics << "warning: alignment for '-sectalign "
+ << segName << " " << sectName
+ << llvm::format(" 0x%llX", alignValue)
+ << "' is not a power of two, using "
+ << llvm::format("0x%08X", (1 << align2)) << "\n";
+ }
+ ctx.addSectionAlignment(segName, sectName, align2);
+ }
+
+ // Handle -mllvm
+ for (auto &llvmArg : parsedArgs->filtered(OPT_mllvm)) {
+ ctx.appendLLVMOption(llvmArg->getValue());
+ }
+
+ // Handle -print_atoms
+ if (parsedArgs->getLastArg(OPT_print_atoms))
+ ctx.setPrintAtoms();
+
+ // Handle -t (trace) option.
+ if (parsedArgs->getLastArg(OPT_t))
+ ctx.setLogInputFiles(true);
+
+ // Handle -demangle option.
+ if (parsedArgs->getLastArg(OPT_demangle))
+ ctx.setDemangleSymbols(true);
+
+ // Handle -keep_private_externs
+ if (parsedArgs->getLastArg(OPT_keep_private_externs)) {
+ ctx.setKeepPrivateExterns(true);
+ if (ctx.outputMachOType() != llvm::MachO::MH_OBJECT)
+ diagnostics << "warning: -keep_private_externs only used in -r mode\n";
+ }
+
+ // Handle -dependency_info <path> used by Xcode.
+ if (llvm::opt::Arg *depInfo = parsedArgs->getLastArg(OPT_dependency_info)) {
+ if (std::error_code ec = ctx.createDependencyFile(depInfo->getValue())) {
+ diagnostics << "warning: " << ec.message()
+ << ", processing '-dependency_info "
+ << depInfo->getValue()
+ << "'\n";
+ }
+ }
+
+ // In -test_file_usage mode, we'll be given an explicit list of paths that
+ // exist. We'll also be expected to print out information about how we located
+ // libraries and so on that the user specified, but not to actually do any
+ // linking.
+ if (parsedArgs->getLastArg(OPT_test_file_usage)) {
+ ctx.setTestingFileUsage();
+
+ // With paths existing by fiat, linking is not going to end well.
+ ctx.setDoNothing(true);
+
+ // Only bother looking for an existence override if we're going to use it.
+ for (auto existingPath : parsedArgs->filtered(OPT_path_exists)) {
+ ctx.addExistingPathForDebug(existingPath->getValue());
+ }
+ }
+
+ // Register possible input file parsers.
+ if (!ctx.doNothing()) {
+ ctx.registry().addSupportMachOObjects(ctx);
+ ctx.registry().addSupportArchives(ctx.logInputFiles());
+ ctx.registry().addSupportNativeObjects();
+ ctx.registry().addSupportYamlFiles();
+ }
+
+ // Now construct the set of library search directories, following ld64's
+ // baroque set of accumulated hacks. Mostly, the algorithm constructs
+ // { syslibroots } x { libpaths }
+ //
+ // Unfortunately, there are numerous exceptions:
+ // 1. Only absolute paths get modified by syslibroot options.
+ // 2. If there is just 1 -syslibroot, system paths not found in it are
+ // skipped.
+ // 3. If the last -syslibroot is "/", all of them are ignored entirely.
+ // 4. If { syslibroots } x path == {}, the original path is kept.
+ std::vector<StringRef> sysLibRoots;
+ for (auto syslibRoot : parsedArgs->filtered(OPT_syslibroot)) {
+ sysLibRoots.push_back(syslibRoot->getValue());
+ }
+ if (!sysLibRoots.empty()) {
+ // Ignore all if last -syslibroot is "/".
+ if (sysLibRoots.back() != "/")
+ ctx.setSysLibRoots(sysLibRoots);
+ }
+
+ // Paths specified with -L come first, and are not considered system paths for
+ // the case where there is precisely 1 -syslibroot.
+ for (auto libPath : parsedArgs->filtered(OPT_L)) {
+ ctx.addModifiedSearchDir(libPath->getValue());
+ }
+
+ // Process -F directories (where to look for frameworks).
+ for (auto fwPath : parsedArgs->filtered(OPT_F)) {
+ ctx.addFrameworkSearchDir(fwPath->getValue());
+ }
+
+ // -Z suppresses the standard search paths.
+ if (!parsedArgs->hasArg(OPT_Z)) {
+ ctx.addModifiedSearchDir("/usr/lib", true);
+ ctx.addModifiedSearchDir("/usr/local/lib", true);
+ ctx.addFrameworkSearchDir("/Library/Frameworks", true);
+ ctx.addFrameworkSearchDir("/System/Library/Frameworks", true);
+ }
+
+ // Now that we've constructed the final set of search paths, print out those
+ // search paths in verbose mode.
+ if (parsedArgs->getLastArg(OPT_v)) {
+ diagnostics << "Library search paths:\n";
+ for (auto path : ctx.searchDirs()) {
+ diagnostics << " " << path << '\n';
+ }
+ diagnostics << "Framework search paths:\n";
+ for (auto path : ctx.frameworkDirs()) {
+ diagnostics << " " << path << '\n';
+ }
+ }
+
+ // Handle -exported_symbols_list <file>
+ for (auto expFile : parsedArgs->filtered(OPT_exported_symbols_list)) {
+ if (ctx.exportMode() == MachOLinkingContext::ExportMode::blackList) {
+ diagnostics << "error: -exported_symbols_list cannot be combined "
+ << "with -unexported_symbol[s_list]\n";
+ return false;
+ }
+ ctx.setExportMode(MachOLinkingContext::ExportMode::whiteList);
+ if (std::error_code ec = parseExportsList(expFile->getValue(), ctx,
+ diagnostics)) {
+ diagnostics << "error: " << ec.message()
+ << ", processing '-exported_symbols_list "
+ << expFile->getValue()
+ << "'\n";
+ return false;
+ }
+ }
+
+ // Handle -exported_symbol <symbol>
+ for (auto symbol : parsedArgs->filtered(OPT_exported_symbol)) {
+ if (ctx.exportMode() == MachOLinkingContext::ExportMode::blackList) {
+ diagnostics << "error: -exported_symbol cannot be combined "
+ << "with -unexported_symbol[s_list]\n";
+ return false;
+ }
+ ctx.setExportMode(MachOLinkingContext::ExportMode::whiteList);
+ ctx.addExportSymbol(symbol->getValue());
+ }
+
+ // Handle -unexported_symbols_list <file>
+ for (auto expFile : parsedArgs->filtered(OPT_unexported_symbols_list)) {
+ if (ctx.exportMode() == MachOLinkingContext::ExportMode::whiteList) {
+ diagnostics << "error: -unexported_symbols_list cannot be combined "
+ << "with -exported_symbol[s_list]\n";
+ return false;
+ }
+ ctx.setExportMode(MachOLinkingContext::ExportMode::blackList);
+ if (std::error_code ec = parseExportsList(expFile->getValue(), ctx,
+ diagnostics)) {
+ diagnostics << "error: " << ec.message()
+ << ", processing '-unexported_symbols_list "
+ << expFile->getValue()
+ << "'\n";
+ return false;
+ }
+ }
+
+ // Handle -unexported_symbol <symbol>
+ for (auto symbol : parsedArgs->filtered(OPT_unexported_symbol)) {
+ if (ctx.exportMode() == MachOLinkingContext::ExportMode::whiteList) {
+ diagnostics << "error: -unexported_symbol cannot be combined "
+ << "with -exported_symbol[s_list]\n";
+ return false;
+ }
+ ctx.setExportMode(MachOLinkingContext::ExportMode::blackList);
+ ctx.addExportSymbol(symbol->getValue());
+ }
+
+ // Handle obosolete -multi_module and -single_module
+ if (llvm::opt::Arg *mod = parsedArgs->getLastArg(OPT_multi_module,
+ OPT_single_module)) {
+ if (mod->getOption().getID() == OPT_multi_module) {
+ diagnostics << "warning: -multi_module is obsolete and being ignored\n";
+ }
+ else {
+ if (ctx.outputMachOType() != llvm::MachO::MH_DYLIB) {
+ diagnostics << "warning: -single_module being ignored. "
+ "It is only for use when producing a dylib\n";
+ }
+ }
+ }
+
+ // Handle -pie or -no_pie
+ if (llvm::opt::Arg *pie = parsedArgs->getLastArg(OPT_pie, OPT_no_pie)) {
+ switch (ctx.outputMachOType()) {
+ case llvm::MachO::MH_EXECUTE:
+ switch (ctx.os()) {
+ case MachOLinkingContext::OS::macOSX:
+ if ((minOSVersion < 0x000A0500) &&
+ (pie->getOption().getID() == OPT_pie)) {
+ diagnostics << "-pie can only be used when targeting "
+ "Mac OS X 10.5 or later\n";
+ return false;
+ }
+ break;
+ case MachOLinkingContext::OS::iOS:
+ if ((minOSVersion < 0x00040200) &&
+ (pie->getOption().getID() == OPT_pie)) {
+ diagnostics << "-pie can only be used when targeting "
+ "iOS 4.2 or later\n";
+ return false;
+ }
+ break;
+ case MachOLinkingContext::OS::iOS_simulator:
+ if (pie->getOption().getID() == OPT_no_pie)
+ diagnostics << "iOS simulator programs must be built PIE\n";
+ return false;
+ break;
+ case MachOLinkingContext::OS::unknown:
+ break;
+ }
+ ctx.setPIE(pie->getOption().getID() == OPT_pie);
+ break;
+ case llvm::MachO::MH_PRELOAD:
+ break;
+ case llvm::MachO::MH_DYLIB:
+ case llvm::MachO::MH_BUNDLE:
+ diagnostics << "warning: " << pie->getSpelling() << " being ignored. "
+ << "It is only used when linking main executables\n";
+ break;
+ default:
+ diagnostics << pie->getSpelling()
+ << " can only used when linking main executables\n";
+ return false;
+ break;
+ }
+ }
+
+ // Handle debug info handling options: -S
+ if (parsedArgs->hasArg(OPT_S))
+ ctx.setDebugInfoMode(MachOLinkingContext::DebugInfoMode::noDebugMap);
+
+ // Handle -order_file <file>
+ for (auto orderFile : parsedArgs->filtered(OPT_order_file)) {
+ if (std::error_code ec = parseOrderFile(orderFile->getValue(), ctx,
+ diagnostics)) {
+ diagnostics << "error: " << ec.message()
+ << ", processing '-order_file "
+ << orderFile->getValue()
+ << "'\n";
+ return false;
+ }
+ }
+
+ // Handle -rpath <path>
+ if (parsedArgs->hasArg(OPT_rpath)) {
+ switch (ctx.outputMachOType()) {
+ case llvm::MachO::MH_EXECUTE:
+ case llvm::MachO::MH_DYLIB:
+ case llvm::MachO::MH_BUNDLE:
+ if (!ctx.minOS("10.5", "2.0")) {
+ if (ctx.os() == MachOLinkingContext::OS::macOSX) {
+ diagnostics << "error: -rpath can only be used when targeting "
+ "OS X 10.5 or later\n";
+ } else {
+ diagnostics << "error: -rpath can only be used when targeting "
+ "iOS 2.0 or later\n";
+ }
+ return false;
+ }
+ break;
+ default:
+ diagnostics << "error: -rpath can only be used when creating "
+ "a dynamic final linked image\n";
+ return false;
+ }
+
+ for (auto rPath : parsedArgs->filtered(OPT_rpath)) {
+ ctx.addRpath(rPath->getValue());
+ }
+ }
+
+ // Handle input files
+ for (auto &arg : *parsedArgs) {
+ bool upward;
+ ErrorOr<StringRef> resolvedPath = StringRef();
+ switch (arg->getOption().getID()) {
+ default:
+ continue;
+ case OPT_INPUT:
+ addFile(arg->getValue(), ctx, globalWholeArchive, false, diagnostics);
+ break;
+ case OPT_upward_library:
+ addFile(arg->getValue(), ctx, false, true, diagnostics);
+ break;
+ case OPT_force_load:
+ addFile(arg->getValue(), ctx, true, false, diagnostics);
+ break;
+ case OPT_l:
+ case OPT_upward_l:
+ upward = (arg->getOption().getID() == OPT_upward_l);
+ resolvedPath = ctx.searchLibrary(arg->getValue());
+ if (!resolvedPath) {
+ diagnostics << "Unable to find library for " << arg->getSpelling()
+ << arg->getValue() << "\n";
+ return false;
+ } else if (ctx.testingFileUsage()) {
+ diagnostics << "Found " << (upward ? "upward " : " ") << "library "
+ << canonicalizePath(resolvedPath.get()) << '\n';
+ }
+ addFile(resolvedPath.get(), ctx, globalWholeArchive, upward, diagnostics);
+ break;
+ case OPT_framework:
+ case OPT_upward_framework:
+ upward = (arg->getOption().getID() == OPT_upward_framework);
+ resolvedPath = ctx.findPathForFramework(arg->getValue());
+ if (!resolvedPath) {
+ diagnostics << "Unable to find framework for "
+ << arg->getSpelling() << " " << arg->getValue() << "\n";
+ return false;
+ } else if (ctx.testingFileUsage()) {
+ diagnostics << "Found " << (upward ? "upward " : " ") << "framework "
+ << canonicalizePath(resolvedPath.get()) << '\n';
+ }
+ addFile(resolvedPath.get(), ctx, globalWholeArchive, upward, diagnostics);
+ break;
+ case OPT_filelist:
+ if (std::error_code ec = loadFileList(arg->getValue(),
+ ctx, globalWholeArchive,
+ diagnostics)) {
+ diagnostics << "error: " << ec.message()
+ << ", processing '-filelist " << arg->getValue()
+ << "'\n";
+ return false;
+ }
+ break;
+ }
+ }
+
+ if (ctx.getNodes().empty()) {
+ diagnostics << "No input files\n";
+ return false;
+ }
+
+ // Validate the combination of options used.
+ return ctx.validate(diagnostics);
+}
+
+
+} // namespace lld
diff --git a/lib/Driver/DarwinLdOptions.td b/lib/Driver/DarwinLdOptions.td
new file mode 100644
index 000000000000..81dcc0a1d925
--- /dev/null
+++ b/lib/Driver/DarwinLdOptions.td
@@ -0,0 +1,187 @@
+include "llvm/Option/OptParser.td"
+
+
+// output kinds
+def grp_kind : OptionGroup<"outs">, HelpText<"OUTPUT KIND">;
+def relocatable : Flag<["-"], "r">,
+ HelpText<"Create relocatable object file">, Group<grp_kind>;
+def static : Flag<["-"], "static">,
+ HelpText<"Create static executable">, Group<grp_kind>;
+def dynamic : Flag<["-"], "dynamic">,
+ HelpText<"Create dynamic executable (default)">,Group<grp_kind>;
+def dylib : Flag<["-"], "dylib">,
+ HelpText<"Create dynamic library">, Group<grp_kind>;
+def bundle : Flag<["-"], "bundle">,
+ HelpText<"Create dynamic bundle">, Group<grp_kind>;
+def execute : Flag<["-"], "execute">,
+ HelpText<"Create main executable (default)">, Group<grp_kind>;
+def preload : Flag<["-"], "preload">,
+ HelpText<"Create binary for use with embedded systems">, Group<grp_kind>;
+
+// optimizations
+def grp_opts : OptionGroup<"opts">, HelpText<"OPTIMIZATIONS">;
+def dead_strip : Flag<["-"], "dead_strip">,
+ HelpText<"Remove unreference code and data">, Group<grp_opts>;
+def macosx_version_min : Separate<["-"], "macosx_version_min">,
+ MetaVarName<"<version>">,
+ HelpText<"Minimum Mac OS X version">, Group<grp_opts>;
+def ios_version_min : Separate<["-"], "ios_version_min">,
+ MetaVarName<"<version>">,
+ HelpText<"Minimum iOS version">, Group<grp_opts>;
+def iphoneos_version_min : Separate<["-"], "iphoneos_version_min">,
+ Alias<ios_version_min>;
+def ios_simulator_version_min : Separate<["-"], "ios_simulator_version_min">,
+ MetaVarName<"<version>">,
+ HelpText<"Minimum iOS simulator version">, Group<grp_opts>;
+def mllvm : Separate<["-"], "mllvm">,
+ MetaVarName<"<option>">,
+ HelpText<"Options to pass to LLVM during LTO">, Group<grp_opts>;
+def exported_symbols_list : Separate<["-"], "exported_symbols_list">,
+ MetaVarName<"<file-path>">,
+ HelpText<"Restricts which symbols will be exported">, Group<grp_opts>;
+def exported_symbol : Separate<["-"], "exported_symbol">,
+ MetaVarName<"<symbol>">,
+ HelpText<"Restricts which symbols will be exported">, Group<grp_opts>;
+def unexported_symbols_list : Separate<["-"], "unexported_symbols_list">,
+ MetaVarName<"<file-path>">,
+ HelpText<"Lists symbols that should not be exported">, Group<grp_opts>;
+def unexported_symbol : Separate<["-"], "unexported_symbol">,
+ MetaVarName<"<symbol>">,
+ HelpText<"A symbol which should not be exported">, Group<grp_opts>;
+def keep_private_externs : Flag<["-"], "keep_private_externs">,
+ HelpText<"Private extern (hidden) symbols should not be transformed "
+ "into local symbols">, Group<grp_opts>;
+def order_file : Separate<["-"], "order_file">,
+ MetaVarName<"<file-path>">,
+ HelpText<"re-order and move specified symbols to start of their section">,
+ Group<grp_opts>;
+
+// main executable options
+def grp_main : OptionGroup<"opts">, HelpText<"MAIN EXECUTABLE OPTIONS">;
+def entry : Separate<["-"], "e">,
+ MetaVarName<"<entry-name>">,
+ HelpText<"entry symbol name">,Group<grp_main>;
+def pie : Flag<["-"], "pie">,
+ HelpText<"Create Position Independent Executable (for ASLR)">,
+ Group<grp_main>;
+def no_pie : Flag<["-"], "no_pie">,
+ HelpText<"Do not create Position Independent Executable">,
+ Group<grp_main>;
+
+// dylib executable options
+def grp_dylib : OptionGroup<"opts">, HelpText<"DYLIB EXECUTABLE OPTIONS">;
+def install_name : Separate<["-"], "install_name">,
+ MetaVarName<"<path>">,
+ HelpText<"The dylib's install name">, Group<grp_dylib>;
+def mark_dead_strippable_dylib : Flag<["-"], "mark_dead_strippable_dylib">,
+ HelpText<"Marks the dylib as having no side effects during initialization">,
+ Group<grp_dylib>;
+def compatibility_version : Separate<["-"], "compatibility_version">,
+ MetaVarName<"<version>">,
+ HelpText<"The dylib's compatibility version">, Group<grp_dylib>;
+def current_version : Separate<["-"], "current_version">,
+ MetaVarName<"<version>">,
+ HelpText<"The dylib's current version">, Group<grp_dylib>;
+
+// dylib executable options - compatibility aliases
+def dylib_install_name : Separate<["-"], "dylib_install_name">,
+ Alias<install_name>;
+def dylib_compatibility_version : Separate<["-"], "dylib_compatibility_version">,
+ MetaVarName<"<version>">, Alias<compatibility_version>;
+def dylib_current_version : Separate<["-"], "dylib_current_version">,
+ MetaVarName<"<version>">, Alias<current_version>;
+
+// bundle executable options
+def grp_bundle : OptionGroup<"opts">, HelpText<"BUNDLE EXECUTABLE OPTIONS">;
+def bundle_loader : Separate<["-"], "bundle_loader">,
+ MetaVarName<"<path>">,
+ HelpText<"The executable that will be loading this Mach-O bundle">,
+ Group<grp_bundle>;
+
+// library options
+def grp_libs : OptionGroup<"libs">, HelpText<"LIBRARY OPTIONS">;
+def L : JoinedOrSeparate<["-"], "L">,
+ MetaVarName<"<dir>">,
+ HelpText<"Add directory to library search path">, Group<grp_libs>;
+def F : JoinedOrSeparate<["-"], "F">,
+ MetaVarName<"<dir>">,
+ HelpText<"Add directory to framework search path">, Group<grp_libs>;
+def Z : Flag<["-"], "Z">,
+ HelpText<"Do not search standard directories for libraries or frameworks">;
+def all_load : Flag<["-"], "all_load">,
+ HelpText<"Forces all members of all static libraries to be loaded">,
+ Group<grp_libs>;
+def force_load : Separate<["-"], "force_load">,
+ MetaVarName<"<library-path>">,
+ HelpText<"Forces all members of specified static libraries to be loaded">,
+ Group<grp_libs>;
+def syslibroot : Separate<["-"], "syslibroot">, MetaVarName<"<dir>">,
+ HelpText<"Add path to SDK to all absolute library search paths">,
+ Group<grp_libs>;
+
+// Input options
+def l : Joined<["-"], "l">,
+ MetaVarName<"<libname>">,
+ HelpText<"Base name of library searched for in -L directories">;
+def upward_l : Joined<["-"], "upward-l">,
+ MetaVarName<"<libname>">,
+ HelpText<"Base name of upward library searched for in -L directories">;
+def framework : Separate<["-"], "framework">,
+ MetaVarName<"<name>">,
+ HelpText<"Base name of framework searched for in -F directories">;
+def upward_framework : Separate<["-"], "upward_framework">,
+ MetaVarName<"<name>">,
+ HelpText<"Base name of upward framework searched for in -F directories">;
+def upward_library : Separate<["-"], "upward_library">,
+ MetaVarName<"<path>">,
+ HelpText<"path to upward dylib to link with">;
+def filelist : Separate<["-"], "filelist">,
+ MetaVarName<"<path>">,
+ HelpText<"file containing paths to input files">;
+
+
+// test case options
+def print_atoms : Flag<["-"], "print_atoms">,
+ HelpText<"Emit output as yaml atoms">;
+def test_file_usage : Flag<["-"], "test_file_usage">,
+ HelpText<"Only files specified by -file_exists are considered to exist. "
+ "Print which files would be used">;
+def path_exists : Separate<["-"], "path_exists">,
+ MetaVarName<"<path>">,
+ HelpText<"Used with -test_file_usage to declare a path">;
+
+
+// general options
+def output : Separate<["-"], "o">,
+ MetaVarName<"<path>">,
+ HelpText<"Output file path">;
+def arch : Separate<["-"], "arch">,
+ MetaVarName<"<arch-name>">,
+ HelpText<"Architecture to link">;
+def sectalign : MultiArg<["-"], "sectalign", 3>,
+ MetaVarName<"<segname> <sectname> <alignment>">,
+ HelpText<"alignment for segment/section">;
+def image_base : Separate<["-"], "image_base">;
+def seg1addr : Separate<["-"], "seg1addr">, Alias<image_base>;
+def demangle : Flag<["-"], "demangle">,
+ HelpText<"Demangles symbol names in errors and warnings">;
+def dependency_info : Separate<["-"], "dependency_info">,
+ MetaVarName<"<file>">,
+ HelpText<"Write binary list of files used during link">;
+def S : Flag<["-"], "S">,
+ HelpText<"Remove debug information (STABS or DWARF) from the output file">;
+def rpath : Separate<["-"], "rpath">,
+ MetaVarName<"<path>">,
+ HelpText<"Add path to the runpath search path list for image being created">;
+
+def t : Flag<["-"], "t">,
+ HelpText<"Print the names of the input files as ld processes them">;
+def v : Flag<["-"], "v">,
+ HelpText<"Print linker information">;
+
+// Obsolete options
+def grp_obsolete : OptionGroup<"obsolete">, HelpText<"OBSOLETE OPTIONS">;
+def single_module : Flag<["-"], "single_module">,
+ HelpText<"Default for dylibs">, Group<grp_obsolete>;
+def multi_module : Flag<["-"], "multi_module">,
+ HelpText<"Unsupported way to build dylibs">, Group<grp_obsolete>;
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
new file mode 100644
index 000000000000..d32bfa6e47be
--- /dev/null
+++ b/lib/Driver/Driver.cpp
@@ -0,0 +1,130 @@
+//===- lib/Driver/Driver.cpp - Linker Driver Emulator ---------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/ArchiveLibraryFile.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Instrumentation.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Parallel.h"
+#include "lld/Core/PassManager.h"
+#include "lld/Core/Reader.h"
+#include "lld/Core/Resolver.h"
+#include "lld/Core/Writer.h"
+#include "lld/Driver/Driver.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/raw_ostream.h"
+#include <mutex>
+
+namespace lld {
+
+FileVector makeErrorFile(StringRef path, std::error_code ec) {
+ std::vector<std::unique_ptr<File>> result;
+ result.push_back(llvm::make_unique<ErrorFile>(path, ec));
+ return result;
+}
+
+FileVector parseMemberFiles(FileVector &files) {
+ std::vector<std::unique_ptr<File>> members;
+ for (std::unique_ptr<File> &file : files) {
+ if (auto *archive = dyn_cast<ArchiveLibraryFile>(file.get())) {
+ if (std::error_code ec = archive->parseAllMembers(members))
+ return makeErrorFile(file->path(), ec);
+ } else {
+ members.push_back(std::move(file));
+ }
+ }
+ return members;
+}
+
+FileVector loadFile(LinkingContext &ctx, StringRef path, bool wholeArchive) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> mb
+ = MemoryBuffer::getFileOrSTDIN(path);
+ if (std::error_code ec = mb.getError())
+ return makeErrorFile(path, ec);
+ std::vector<std::unique_ptr<File>> files;
+ if (std::error_code ec = ctx.registry().loadFile(std::move(mb.get()), files))
+ return makeErrorFile(path, ec);
+ if (wholeArchive)
+ return parseMemberFiles(files);
+ return files;
+}
+
+/// This is where the link is actually performed.
+bool Driver::link(LinkingContext &context, raw_ostream &diagnostics) {
+ // Honor -mllvm
+ if (!context.llvmOptions().empty()) {
+ unsigned numArgs = context.llvmOptions().size();
+ const char **args = new const char *[numArgs + 2];
+ args[0] = "lld (LLVM option parsing)";
+ for (unsigned i = 0; i != numArgs; ++i)
+ args[i + 1] = context.llvmOptions()[i];
+ args[numArgs + 1] = 0;
+ llvm::cl::ParseCommandLineOptions(numArgs + 1, args);
+ }
+ if (context.getNodes().empty())
+ return false;
+
+ for (std::unique_ptr<Node> &ie : context.getNodes())
+ if (FileNode *node = dyn_cast<FileNode>(ie.get()))
+ context.getTaskGroup().spawn([node] { node->getFile()->parse(); });
+
+ std::vector<std::unique_ptr<File>> internalFiles;
+ context.createInternalFiles(internalFiles);
+ for (auto i = internalFiles.rbegin(), e = internalFiles.rend(); i != e; ++i) {
+ auto &members = context.getNodes();
+ members.insert(members.begin(), llvm::make_unique<FileNode>(std::move(*i)));
+ }
+
+ // Give target a chance to add files.
+ std::vector<std::unique_ptr<File>> implicitFiles;
+ context.createImplicitFiles(implicitFiles);
+ for (auto i = implicitFiles.rbegin(), e = implicitFiles.rend(); i != e; ++i) {
+ auto &members = context.getNodes();
+ members.insert(members.begin(), llvm::make_unique<FileNode>(std::move(*i)));
+ }
+
+ // Give target a chance to postprocess input files.
+ // Mach-O uses this chance to move all object files before library files.
+ // ELF adds specific undefined symbols resolver.
+ context.finalizeInputFiles();
+
+ // Do core linking.
+ ScopedTask resolveTask(getDefaultDomain(), "Resolve");
+ Resolver resolver(context);
+ if (!resolver.resolve())
+ return false;
+ std::unique_ptr<MutableFile> merged = resolver.resultFile();
+ resolveTask.end();
+
+ // Run passes on linked atoms.
+ ScopedTask passTask(getDefaultDomain(), "Passes");
+ PassManager pm;
+ context.addPasses(pm);
+ pm.runOnFile(merged);
+ passTask.end();
+
+ // Give linked atoms to Writer to generate output file.
+ ScopedTask writeTask(getDefaultDomain(), "Write");
+ if (std::error_code ec = context.writeFile(*merged)) {
+ diagnostics << "Failed to write file '" << context.outputPath()
+ << "': " << ec.message() << "\n";
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace
diff --git a/lib/Driver/GnuLdDriver.cpp b/lib/Driver/GnuLdDriver.cpp
new file mode 100644
index 000000000000..b9af04d4b615
--- /dev/null
+++ b/lib/Driver/GnuLdDriver.cpp
@@ -0,0 +1,760 @@
+//===- lib/Driver/GnuLdDriver.cpp -----------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+///
+/// Concrete instance of the Driver for GNU's ld.
+///
+//===----------------------------------------------------------------------===//
+
+#include "lld/Driver/Driver.h"
+#include "lld/ReaderWriter/ELFLinkingContext.h"
+#include "lld/ReaderWriter/ELFTargets.h"
+#include "lld/ReaderWriter/LinkerScript.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/Timer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstring>
+#include <tuple>
+
+using namespace lld;
+
+using llvm::BumpPtrAllocator;
+
+namespace {
+
+// Create enum with OPT_xxx values for each option in GnuLdOptions.td
+enum {
+ OPT_INVALID = 0,
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELP, META) \
+ OPT_##ID,
+#include "GnuLdOptions.inc"
+#undef OPTION
+};
+
+// Create prefix string literals used in GnuLdOptions.td
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#include "GnuLdOptions.inc"
+#undef PREFIX
+
+// Create table mapping all options defined in GnuLdOptions.td
+static const llvm::opt::OptTable::Info infoTable[] = {
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR) \
+ { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \
+ PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS },
+#include "GnuLdOptions.inc"
+#undef OPTION
+};
+
+
+// Create OptTable class for parsing actual command line arguments
+class GnuLdOptTable : public llvm::opt::OptTable {
+public:
+ GnuLdOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable)){}
+};
+
+class DriverStringSaver : public llvm::cl::StringSaver {
+public:
+ DriverStringSaver(BumpPtrAllocator &alloc) : _alloc(alloc) {}
+
+ const char *SaveString(const char *s) override {
+ char *p = _alloc.Allocate<char>(strlen(s) + 1);
+ strcpy(p, s);
+ return p;
+ }
+
+private:
+ BumpPtrAllocator &_alloc;
+};
+
+} // anonymous namespace
+
+// If a command line option starts with "@", the driver reads its suffix as a
+// file, parse its contents as a list of command line options, and insert them
+// at the original @file position. If file cannot be read, @file is not expanded
+// and left unmodified. @file can appear in a response file, so it's a recursive
+// process.
+static std::tuple<int, const char **>
+maybeExpandResponseFiles(int argc, const char **argv, BumpPtrAllocator &alloc) {
+ // Expand response files.
+ SmallVector<const char *, 256> smallvec;
+ for (int i = 0; i < argc; ++i)
+ smallvec.push_back(argv[i]);
+ DriverStringSaver saver(alloc);
+ llvm::cl::ExpandResponseFiles(saver, llvm::cl::TokenizeGNUCommandLine, smallvec);
+
+ // Pack the results to a C-array and return it.
+ argc = smallvec.size();
+ const char **copy = alloc.Allocate<const char *>(argc + 1);
+ std::copy(smallvec.begin(), smallvec.end(), copy);
+ copy[argc] = nullptr;
+ return std::make_tuple(argc, copy);
+}
+
+static std::error_code
+getFileMagic(StringRef path, llvm::sys::fs::file_magic &magic) {
+ std::error_code ec = llvm::sys::fs::identify_magic(path, magic);
+ if (ec)
+ return ec;
+ switch (magic) {
+ case llvm::sys::fs::file_magic::archive:
+ case llvm::sys::fs::file_magic::elf_relocatable:
+ case llvm::sys::fs::file_magic::elf_shared_object:
+ case llvm::sys::fs::file_magic::unknown:
+ return std::error_code();
+ default:
+ return make_dynamic_error_code(StringRef("unknown type of object file"));
+ }
+}
+
+// Parses an argument of --defsym=<sym>=<number>
+static bool parseDefsymAsAbsolute(StringRef opt, StringRef &sym,
+ uint64_t &addr) {
+ size_t equalPos = opt.find('=');
+ if (equalPos == 0 || equalPos == StringRef::npos)
+ return false;
+ sym = opt.substr(0, equalPos);
+ if (opt.substr(equalPos + 1).getAsInteger(0, addr))
+ return false;
+ return true;
+}
+
+// Parses an argument of --defsym=<sym>=<sym>
+static bool parseDefsymAsAlias(StringRef opt, StringRef &sym,
+ StringRef &target) {
+ size_t equalPos = opt.find('=');
+ if (equalPos == 0 || equalPos == StringRef::npos)
+ return false;
+ sym = opt.substr(0, equalPos);
+ target = opt.substr(equalPos + 1);
+ return !target.empty();
+}
+
+// Parses -z max-page-size=<value>
+static bool parseMaxPageSize(StringRef opt, uint64_t &val) {
+ size_t equalPos = opt.find('=');
+ if (equalPos == 0 || equalPos == StringRef::npos)
+ return false;
+ StringRef value = opt.substr(equalPos + 1);
+ val = 0;
+ if (value.getAsInteger(0, val) || !val)
+ return false;
+ return true;
+}
+
+bool GnuLdDriver::linkELF(int argc, const char *argv[], raw_ostream &diag) {
+ BumpPtrAllocator alloc;
+ std::tie(argc, argv) = maybeExpandResponseFiles(argc, argv, alloc);
+ std::unique_ptr<ELFLinkingContext> options;
+ if (!parse(argc, argv, options, diag))
+ return false;
+ if (!options)
+ return true;
+ bool linked = link(*options, diag);
+
+ // Handle --stats.
+ if (options->collectStats()) {
+ llvm::TimeRecord t = llvm::TimeRecord::getCurrentTime(true);
+ diag << "total time in link " << t.getProcessTime() << "\n";
+ diag << "data size " << t.getMemUsed() << "\n";
+ }
+ return linked;
+}
+
+static llvm::Optional<llvm::Triple::ArchType>
+getArchType(const llvm::Triple &triple, StringRef value) {
+ switch (triple.getArch()) {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ if (value == "elf_i386")
+ return llvm::Triple::x86;
+ if (value == "elf_x86_64")
+ return llvm::Triple::x86_64;
+ return llvm::None;
+ case llvm::Triple::mipsel:
+ case llvm::Triple::mips64el:
+ if (value == "elf32ltsmip")
+ return llvm::Triple::mipsel;
+ if (value == "elf64ltsmip")
+ return llvm::Triple::mips64el;
+ return llvm::None;
+ case llvm::Triple::aarch64:
+ if (value == "aarch64linux")
+ return llvm::Triple::aarch64;
+ return llvm::None;
+ case llvm::Triple::arm:
+ if (value == "armelf_linux_eabi")
+ return llvm::Triple::arm;
+ return llvm::None;
+ default:
+ return llvm::None;
+ }
+}
+
+static bool isLinkerScript(StringRef path, raw_ostream &diag) {
+ llvm::sys::fs::file_magic magic = llvm::sys::fs::file_magic::unknown;
+ std::error_code ec = getFileMagic(path, magic);
+ if (ec) {
+ diag << "unknown input file format for file " << path << "\n";
+ return false;
+ }
+ return magic == llvm::sys::fs::file_magic::unknown;
+}
+
+static ErrorOr<StringRef>
+findFile(ELFLinkingContext &ctx, StringRef path, bool dashL) {
+ // If the path was referred to by using a -l argument, let's search
+ // for the file in the search path.
+ if (dashL) {
+ ErrorOr<StringRef> pathOrErr = ctx.searchLibrary(path);
+ if (std::error_code ec = pathOrErr.getError())
+ return make_dynamic_error_code(
+ Twine("Unable to find library -l") + path + ": " + ec.message());
+ path = pathOrErr.get();
+ }
+ if (!llvm::sys::fs::exists(path))
+ return make_dynamic_error_code(
+ Twine("lld: cannot find file ") + path);
+ return path;
+}
+
+static bool isPathUnderSysroot(StringRef sysroot, StringRef path) {
+ if (sysroot.empty())
+ return false;
+ while (!path.empty() && !llvm::sys::fs::equivalent(sysroot, path))
+ path = llvm::sys::path::parent_path(path);
+ return !path.empty();
+}
+
+static std::error_code
+addFilesFromLinkerScript(ELFLinkingContext &ctx, StringRef scriptPath,
+ const std::vector<script::Path> &inputPaths,
+ raw_ostream &diag) {
+ bool sysroot = (!ctx.getSysroot().empty()
+ && isPathUnderSysroot(ctx.getSysroot(), scriptPath));
+ for (const script::Path &path : inputPaths) {
+ ErrorOr<StringRef> pathOrErr = path._isDashlPrefix
+ ? ctx.searchLibrary(path._path) : ctx.searchFile(path._path, sysroot);
+ if (std::error_code ec = pathOrErr.getError()) {
+ auto file = llvm::make_unique<ErrorFile>(path._path, ec);
+ ctx.getNodes().push_back(llvm::make_unique<FileNode>(std::move(file)));
+ continue;
+ }
+
+ std::vector<std::unique_ptr<File>> files
+ = loadFile(ctx, pathOrErr.get(), false);
+ for (std::unique_ptr<File> &file : files) {
+ if (ctx.logInputFiles())
+ diag << file->path() << "\n";
+ ctx.getNodes().push_back(llvm::make_unique<FileNode>(std::move(file)));
+ }
+ }
+ return std::error_code();
+}
+
+std::error_code GnuLdDriver::evalLinkerScript(ELFLinkingContext &ctx,
+ std::unique_ptr<MemoryBuffer> mb,
+ raw_ostream &diag,
+ bool nostdlib) {
+ // Read the script file from disk and parse.
+ StringRef path = mb->getBufferIdentifier();
+ auto parser = llvm::make_unique<script::Parser>(std::move(mb));
+ if (std::error_code ec = parser->parse())
+ return ec;
+ script::LinkerScript *script = parser->get();
+ if (!script)
+ return LinkerScriptReaderError::parse_error;
+ // Evaluate script commands.
+ // Currently we only recognize this subset of linker script commands.
+ for (const script::Command *c : script->_commands) {
+ if (auto *input = dyn_cast<script::Input>(c))
+ if (std::error_code ec = addFilesFromLinkerScript(
+ ctx, path, input->getPaths(), diag))
+ return ec;
+ if (auto *group = dyn_cast<script::Group>(c)) {
+ int origSize = ctx.getNodes().size();
+ if (std::error_code ec = addFilesFromLinkerScript(
+ ctx, path, group->getPaths(), diag))
+ return ec;
+ size_t groupSize = ctx.getNodes().size() - origSize;
+ ctx.getNodes().push_back(llvm::make_unique<GroupEnd>(groupSize));
+ }
+ if (auto *searchDir = dyn_cast<script::SearchDir>(c))
+ if (!nostdlib)
+ ctx.addSearchPath(searchDir->getSearchPath());
+ if (auto *entry = dyn_cast<script::Entry>(c))
+ ctx.setEntrySymbolName(entry->getEntryName());
+ if (auto *output = dyn_cast<script::Output>(c))
+ ctx.setOutputPath(output->getOutputFileName());
+ if (auto *externs = dyn_cast<script::Extern>(c)) {
+ for (auto symbol : *externs) {
+ ctx.addInitialUndefinedSymbol(symbol);
+ }
+ }
+ }
+ // Transfer ownership of the script to the linking context
+ ctx.linkerScriptSema().addLinkerScript(std::move(parser));
+ return std::error_code();
+}
+
+bool GnuLdDriver::applyEmulation(llvm::Triple &triple,
+ llvm::opt::InputArgList &args,
+ raw_ostream &diag) {
+ llvm::opt::Arg *arg = args.getLastArg(OPT_m);
+ if (!arg)
+ return true;
+ llvm::Optional<llvm::Triple::ArchType> arch =
+ getArchType(triple, arg->getValue());
+ if (!arch) {
+ diag << "error: unsupported emulation '" << arg->getValue() << "'.\n";
+ return false;
+ }
+ triple.setArch(*arch);
+ return true;
+}
+
+void GnuLdDriver::addPlatformSearchDirs(ELFLinkingContext &ctx,
+ llvm::Triple &triple,
+ llvm::Triple &baseTriple) {
+ if (triple.getOS() == llvm::Triple::NetBSD &&
+ triple.getArch() == llvm::Triple::x86 &&
+ baseTriple.getArch() == llvm::Triple::x86_64) {
+ ctx.addSearchPath("=/usr/lib/i386");
+ return;
+ }
+ ctx.addSearchPath("=/usr/lib");
+}
+
+std::unique_ptr<ELFLinkingContext>
+GnuLdDriver::createELFLinkingContext(llvm::Triple triple) {
+ std::unique_ptr<ELFLinkingContext> p;
+ // FIXME: #include "llvm/Config/Targets.def"
+#define LLVM_TARGET(targetName) \
+ if ((p = elf::targetName##LinkingContext::create(triple))) return p;
+ LLVM_TARGET(AArch64)
+ LLVM_TARGET(ARM)
+ LLVM_TARGET(Hexagon)
+ LLVM_TARGET(Mips)
+ LLVM_TARGET(X86)
+ LLVM_TARGET(Example)
+ LLVM_TARGET(X86_64)
+#undef LLVM_TARGET
+ return nullptr;
+}
+
+static llvm::Optional<bool>
+getBool(const llvm::opt::InputArgList &parsedArgs,
+ unsigned yesFlag, unsigned noFlag) {
+ if (auto *arg = parsedArgs.getLastArg(yesFlag, noFlag))
+ return arg->getOption().getID() == yesFlag;
+ return llvm::None;
+}
+
+bool GnuLdDriver::parse(int argc, const char *argv[],
+ std::unique_ptr<ELFLinkingContext> &context,
+ raw_ostream &diag) {
+ // Parse command line options using GnuLdOptions.td
+ std::unique_ptr<llvm::opt::InputArgList> parsedArgs;
+ GnuLdOptTable table;
+ unsigned missingIndex;
+ unsigned missingCount;
+
+ parsedArgs.reset(
+ table.ParseArgs(&argv[1], &argv[argc], missingIndex, missingCount));
+ if (missingCount) {
+ diag << "error: missing arg value for '"
+ << parsedArgs->getArgString(missingIndex) << "' expected "
+ << missingCount << " argument(s).\n";
+ return false;
+ }
+
+ // Handle --help
+ if (parsedArgs->hasArg(OPT_help)) {
+ table.PrintHelp(llvm::outs(), argv[0], "LLVM Linker", false);
+ return true;
+ }
+
+ // Use -target or use default target triple to instantiate LinkingContext
+ llvm::Triple baseTriple;
+ if (auto *arg = parsedArgs->getLastArg(OPT_target)) {
+ baseTriple = llvm::Triple(arg->getValue());
+ } else {
+ baseTriple = getDefaultTarget(argv[0]);
+ }
+ llvm::Triple triple(baseTriple);
+
+ if (!applyEmulation(triple, *parsedArgs, diag))
+ return false;
+
+ std::unique_ptr<ELFLinkingContext> ctx(createELFLinkingContext(triple));
+
+ if (!ctx) {
+ diag << "unknown target triple\n";
+ return false;
+ }
+
+ // Copy mllvm
+ for (auto *arg : parsedArgs->filtered(OPT_mllvm))
+ ctx->appendLLVMOption(arg->getValue());
+
+ // Ignore unknown arguments.
+ for (auto unknownArg : parsedArgs->filtered(OPT_UNKNOWN))
+ diag << "warning: ignoring unknown argument: "
+ << unknownArg->getValue() << "\n";
+
+ // Set sys root path.
+ if (auto *arg = parsedArgs->getLastArg(OPT_sysroot))
+ ctx->setSysroot(arg->getValue());
+
+ // Handle --demangle option(For compatibility)
+ if (parsedArgs->hasArg(OPT_demangle))
+ ctx->setDemangleSymbols(true);
+
+ // Handle --no-demangle option.
+ if (parsedArgs->hasArg(OPT_no_demangle))
+ ctx->setDemangleSymbols(false);
+
+ // Figure out output kind (-r, -static, -shared)
+ if (parsedArgs->hasArg(OPT_relocatable)) {
+ ctx->setOutputELFType(llvm::ELF::ET_REL);
+ ctx->setPrintRemainingUndefines(false);
+ ctx->setAllowRemainingUndefines(true);
+ }
+
+ if (parsedArgs->hasArg(OPT_static)) {
+ ctx->setOutputELFType(llvm::ELF::ET_EXEC);
+ ctx->setIsStaticExecutable(true);
+ }
+
+ if (parsedArgs->hasArg(OPT_shared)) {
+ ctx->setOutputELFType(llvm::ELF::ET_DYN);
+ ctx->setAllowShlibUndefines(true);
+ ctx->setUseShlibUndefines(false);
+ ctx->setPrintRemainingUndefines(false);
+ ctx->setAllowRemainingUndefines(true);
+ }
+
+ // Handle --stats.
+ if (parsedArgs->hasArg(OPT_stats)) {
+ ctx->setCollectStats(true);
+ }
+
+ // Figure out if the output type is nmagic/omagic
+ if (auto *arg = parsedArgs->getLastArg(
+ OPT_nmagic, OPT_omagic, OPT_no_omagic)) {
+ switch (arg->getOption().getID()) {
+ case OPT_nmagic:
+ ctx->setOutputMagic(ELFLinkingContext::OutputMagic::NMAGIC);
+ ctx->setIsStaticExecutable(true);
+ break;
+ case OPT_omagic:
+ ctx->setOutputMagic(ELFLinkingContext::OutputMagic::OMAGIC);
+ ctx->setIsStaticExecutable(true);
+ break;
+ case OPT_no_omagic:
+ ctx->setOutputMagic(ELFLinkingContext::OutputMagic::DEFAULT);
+ ctx->setNoAllowDynamicLibraries();
+ break;
+ }
+ }
+
+ if (parsedArgs->hasArg(OPT_strip_all))
+ ctx->setStripSymbols(true);
+
+ if (auto *arg = parsedArgs->getLastArg(OPT_soname))
+ ctx->setSharedObjectName(arg->getValue());
+
+ if (parsedArgs->hasArg(OPT_rosegment))
+ ctx->setCreateSeparateROSegment();
+
+ if (parsedArgs->hasArg(OPT_no_align_segments))
+ ctx->setAlignSegments(false);
+
+ if (auto *arg = parsedArgs->getLastArg(OPT_image_base)) {
+ uint64_t baseAddress = 0;
+ StringRef inputValue = arg->getValue();
+ if (inputValue.getAsInteger(0, baseAddress) || !baseAddress) {
+ diag << "invalid value for image base " << inputValue << "\n";
+ return false;
+ }
+ ctx->setBaseAddress(baseAddress);
+ }
+
+ if (parsedArgs->hasArg(OPT_merge_strings))
+ ctx->setMergeCommonStrings(true);
+
+ if (parsedArgs->hasArg(OPT_t))
+ ctx->setLogInputFiles(true);
+
+ if (parsedArgs->hasArg(OPT_use_shlib_undefs))
+ ctx->setUseShlibUndefines(true);
+
+ if (auto val = getBool(*parsedArgs, OPT_allow_shlib_undefs,
+ OPT_no_allow_shlib_undefs))
+ ctx->setAllowShlibUndefines(*val);
+
+ if (auto *arg = parsedArgs->getLastArg(OPT_e))
+ ctx->setEntrySymbolName(arg->getValue());
+
+ if (auto *arg = parsedArgs->getLastArg(OPT_output))
+ ctx->setOutputPath(arg->getValue());
+
+ if (parsedArgs->hasArg(OPT_noinhibit_exec))
+ ctx->setAllowRemainingUndefines(true);
+
+ if (auto val = getBool(*parsedArgs, OPT_export_dynamic,
+ OPT_no_export_dynamic))
+ ctx->setExportDynamic(*val);
+
+ if (parsedArgs->hasArg(OPT_allow_multiple_definition))
+ ctx->setAllowDuplicates(true);
+
+ if (auto *arg = parsedArgs->getLastArg(OPT_dynamic_linker))
+ ctx->setInterpreter(arg->getValue());
+
+ if (auto *arg = parsedArgs->getLastArg(OPT_init))
+ ctx->setInitFunction(arg->getValue());
+
+ if (auto *arg = parsedArgs->getLastArg(OPT_fini))
+ ctx->setFiniFunction(arg->getValue());
+
+ if (auto *arg = parsedArgs->getLastArg(OPT_output_filetype))
+ ctx->setOutputFileType(arg->getValue());
+
+ for (auto *arg : parsedArgs->filtered(OPT_L))
+ ctx->addSearchPath(arg->getValue());
+
+ // Add the default search directory specific to the target.
+ if (!parsedArgs->hasArg(OPT_nostdlib))
+ addPlatformSearchDirs(*ctx, triple, baseTriple);
+
+ for (auto *arg : parsedArgs->filtered(OPT_u))
+ ctx->addInitialUndefinedSymbol(arg->getValue());
+
+ for (auto *arg : parsedArgs->filtered(OPT_defsym)) {
+ StringRef sym, target;
+ uint64_t addr;
+ if (parseDefsymAsAbsolute(arg->getValue(), sym, addr)) {
+ ctx->addInitialAbsoluteSymbol(sym, addr);
+ } else if (parseDefsymAsAlias(arg->getValue(), sym, target)) {
+ ctx->addAlias(sym, target);
+ } else {
+ diag << "invalid --defsym: " << arg->getValue() << "\n";
+ return false;
+ }
+ }
+
+ for (auto *arg : parsedArgs->filtered(OPT_z)) {
+ StringRef opt = arg->getValue();
+ if (opt == "muldefs") {
+ ctx->setAllowDuplicates(true);
+ } else if (opt.startswith("max-page-size")) {
+ // Parse -z max-page-size option.
+ // The default page size is considered the minimum page size the user
+ // can set, check the user input if its atleast the minimum page size
+ // and does not exceed the maximum page size allowed for the target.
+ uint64_t maxPageSize = 0;
+
+ // Error if the page size user set is less than the maximum page size
+ // and greather than the default page size and the user page size is a
+ // modulo of the default page size.
+ if ((!parseMaxPageSize(opt, maxPageSize)) ||
+ (maxPageSize < ctx->getPageSize()) ||
+ (maxPageSize % ctx->getPageSize())) {
+ diag << "invalid option: " << opt << "\n";
+ return false;
+ }
+ ctx->setMaxPageSize(maxPageSize);
+ } else {
+ diag << "warning: ignoring unknown argument for -z: " << opt << "\n";
+ }
+ }
+
+ for (auto *arg : parsedArgs->filtered(OPT_rpath)) {
+ SmallVector<StringRef, 2> rpaths;
+ StringRef(arg->getValue()).split(rpaths, ":");
+ for (auto path : rpaths)
+ ctx->addRpath(path);
+ }
+
+ for (auto *arg : parsedArgs->filtered(OPT_rpath_link)) {
+ SmallVector<StringRef, 2> rpaths;
+ StringRef(arg->getValue()).split(rpaths, ":");
+ for (auto path : rpaths)
+ ctx->addRpathLink(path);
+ }
+
+ // Support --wrap option.
+ for (auto *arg : parsedArgs->filtered(OPT_wrap))
+ ctx->addWrapForSymbol(arg->getValue());
+
+ // Register possible input file parsers.
+ ctx->registry().addSupportELFObjects(*ctx);
+ ctx->registry().addSupportArchives(ctx->logInputFiles());
+ ctx->registry().addSupportYamlFiles();
+ ctx->registry().addSupportNativeObjects();
+ if (ctx->allowLinkWithDynamicLibraries())
+ ctx->registry().addSupportELFDynamicSharedObjects(*ctx);
+
+ std::stack<int> groupStack;
+ int numfiles = 0;
+ bool asNeeded = false;
+ bool wholeArchive = false;
+
+ // Process files
+ for (auto arg : *parsedArgs) {
+ switch (arg->getOption().getID()) {
+ case OPT_no_whole_archive:
+ wholeArchive = false;
+ break;
+
+ case OPT_whole_archive:
+ wholeArchive = true;
+ break;
+
+ case OPT_as_needed:
+ asNeeded = true;
+ break;
+
+ case OPT_no_as_needed:
+ asNeeded = false;
+ break;
+
+ case OPT_start_group:
+ groupStack.push(numfiles);
+ break;
+
+ case OPT_end_group: {
+ if (groupStack.empty()) {
+ diag << "stray --end-group\n";
+ return false;
+ }
+ int startGroupPos = groupStack.top();
+ ctx->getNodes().push_back(
+ llvm::make_unique<GroupEnd>(numfiles - startGroupPos));
+ groupStack.pop();
+ break;
+ }
+
+ case OPT_INPUT:
+ case OPT_l:
+ case OPT_T: {
+ bool dashL = (arg->getOption().getID() == OPT_l);
+ StringRef path = arg->getValue();
+
+ ErrorOr<StringRef> pathOrErr = findFile(*ctx, path, dashL);
+ if (std::error_code ec = pathOrErr.getError()) {
+ auto file = llvm::make_unique<ErrorFile>(path, ec);
+ auto node = llvm::make_unique<FileNode>(std::move(file));
+ node->setAsNeeded(asNeeded);
+ ctx->getNodes().push_back(std::move(node));
+ break;
+ }
+ StringRef realpath = pathOrErr.get();
+
+ bool isScript =
+ (!path.endswith(".objtxt") && isLinkerScript(realpath, diag));
+ if (isScript) {
+ if (ctx->logInputFiles())
+ diag << path << "\n";
+ ErrorOr<std::unique_ptr<MemoryBuffer>> mb =
+ MemoryBuffer::getFileOrSTDIN(realpath);
+ if (std::error_code ec = mb.getError()) {
+ diag << "Cannot open " << path << ": " << ec.message() << "\n";
+ return false;
+ }
+ bool nostdlib = parsedArgs->hasArg(OPT_nostdlib);
+ std::error_code ec =
+ evalLinkerScript(*ctx, std::move(mb.get()), diag, nostdlib);
+ if (ec) {
+ diag << path << ": Error parsing linker script: "
+ << ec.message() << "\n";
+ return false;
+ }
+ break;
+ }
+ std::vector<std::unique_ptr<File>> files
+ = loadFile(*ctx, realpath, wholeArchive);
+ for (std::unique_ptr<File> &file : files) {
+ if (ctx->logInputFiles())
+ diag << file->path() << "\n";
+ auto node = llvm::make_unique<FileNode>(std::move(file));
+ node->setAsNeeded(asNeeded);
+ ctx->getNodes().push_back(std::move(node));
+ }
+ numfiles += files.size();
+ break;
+ }
+ }
+ }
+
+ if (ctx->getNodes().empty()) {
+ diag << "No input files\n";
+ return false;
+ }
+
+ // Set default output file name if the output file was not specified.
+ if (ctx->outputPath().empty()) {
+ switch (ctx->outputFileType()) {
+ case LinkingContext::OutputFileType::YAML:
+ ctx->setOutputPath("-");
+ break;
+ case LinkingContext::OutputFileType::Native:
+ ctx->setOutputPath("a.native");
+ break;
+ default:
+ ctx->setOutputPath("a.out");
+ break;
+ }
+ }
+
+ // Validate the combination of options used.
+ if (!ctx->validate(diag))
+ return false;
+
+ // Perform linker script semantic actions
+ ctx->linkerScriptSema().perform();
+
+ context.swap(ctx);
+ return true;
+}
+
+/// Get the default target triple based on either the program name
+/// (e.g. "x86-ibm-linux-lld") or the primary target llvm was configured for.
+llvm::Triple GnuLdDriver::getDefaultTarget(const char *progName) {
+ SmallVector<StringRef, 4> components;
+ llvm::SplitString(llvm::sys::path::stem(progName), components, "-");
+ // If has enough parts to be start with a triple.
+ if (components.size() >= 4) {
+ llvm::Triple triple(components[0], components[1], components[2],
+ components[3]);
+ // If first component looks like an arch.
+ if (triple.getArch() != llvm::Triple::UnknownArch)
+ return triple;
+ }
+
+ // Fallback to use whatever default triple llvm was configured for.
+ return llvm::Triple(llvm::sys::getDefaultTargetTriple());
+}
diff --git a/lib/Driver/GnuLdOptions.td b/lib/Driver/GnuLdOptions.td
new file mode 100644
index 000000000000..9d06f2935439
--- /dev/null
+++ b/lib/Driver/GnuLdOptions.td
@@ -0,0 +1,323 @@
+include "llvm/Option/OptParser.td"
+
+//===----------------------------------------------------------------------===//
+/// Utility Functions
+//===----------------------------------------------------------------------===//
+// Single and multiple dash options combined
+multiclass smDash<string opt1, string opt2, string help> {
+ // Option
+ def "" : Separate<["-"], opt1>, HelpText<help>;
+ def opt1_eq : Joined<["-"], opt1#"=">,
+ Alias<!cast<Option>(opt1)>;
+ // Compatibility aliases
+ def opt2_dashdash : Separate<["--"], opt2>,
+ Alias<!cast<Option>(opt1)>;
+ def opt2_dashdash_eq : Joined<["--"], opt2#"=">,
+ Alias<!cast<Option>(opt1)>;
+}
+
+// Support -<option>,-<option>=
+multiclass dashEq<string opt1, string opt2, string help> {
+ // Option
+ def "" : Separate<["-"], opt1>, HelpText<help>;
+ // Compatibility aliases
+ def opt2_eq : Joined<["-"], opt2#"=">,
+ Alias<!cast<Option>(opt1)>;
+}
+
+//===----------------------------------------------------------------------===//
+/// LLVM and Target options
+//===----------------------------------------------------------------------===//
+def grp_llvmtarget : OptionGroup<"opts">,
+ HelpText<"LLVM and Target Options">;
+def mllvm : Separate<["-"], "mllvm">,
+ HelpText<"Options to pass to LLVM">, Group<grp_llvmtarget>;
+def target : Separate<["-"], "target">, MetaVarName<"<triple>">,
+ HelpText<"Target triple to link for">,
+ Group<grp_llvmtarget>;
+
+//===----------------------------------------------------------------------===//
+/// Output Kinds
+//===----------------------------------------------------------------------===//
+def grp_kind : OptionGroup<"outs">,
+ HelpText<"OUTPUT KIND">;
+def relocatable : Flag<["-"], "r">,
+ HelpText<"Create relocatable object file">, Group<grp_kind>;
+def static : Flag<["-"], "static">,
+ HelpText<"Create static executable">, Group<grp_kind>;
+def dynamic : Flag<["-"], "dynamic">,
+ HelpText<"Create dynamic executable (default)">,Group<grp_kind>;
+def shared : Flag<["-"], "shared">,
+ HelpText<"Create dynamic library">, Group<grp_kind>;
+
+// output kinds - compatibility aliases
+def Bstatic : Flag<["-"], "Bstatic">, Alias<static>;
+def Bshareable : Flag<["-"], "Bshareable">, Alias<shared>;
+
+//===----------------------------------------------------------------------===//
+/// General Options
+//===----------------------------------------------------------------------===//
+def grp_general : OptionGroup<"opts">,
+ HelpText<"GENERAL OPTIONS">;
+def output : Separate<["-"], "o">, MetaVarName<"<path>">,
+ HelpText<"Path to file to write output">,
+ Group<grp_general>;
+def m : Separate<["-"], "m">, MetaVarName<"<emulation>">,
+ HelpText<"Select target emulation">,
+ Group<grp_general>;
+def build_id : Flag<["--"], "build-id">,
+ HelpText<"Request creation of \".note.gnu.build-id\" ELF note section">,
+ Group<grp_general>;
+def sysroot : Joined<["--"], "sysroot=">,
+ HelpText<"Set the system root">,
+ Group<grp_general>;
+
+
+//===----------------------------------------------------------------------===//
+/// Executable Options
+//===----------------------------------------------------------------------===//
+def grp_main : OptionGroup<"opts">,
+ HelpText<"EXECUTABLE OPTIONS">;
+def L : Joined<["-"], "L">, MetaVarName<"<dir>">,
+ HelpText<"Directory to search for libraries">,
+ Group<grp_main>;
+def l : Joined<["-"], "l">, MetaVarName<"<libName>">,
+ HelpText<"Root name of library to use">,
+ Group<grp_main>;
+def noinhibit_exec : Flag<["--"], "noinhibit-exec">,
+ HelpText<"Retain the executable output file whenever"
+ " it is still usable">,
+ Group<grp_main>;
+defm e : smDash<"e", "entry",
+ "Name of entry point symbol">,
+ Group<grp_main>;
+defm init: dashEq<"init", "init",
+ "Specify an initializer function">,
+ Group<grp_main>;
+defm fini: dashEq<"fini", "fini",
+ "Specify a finalizer function">,
+ Group<grp_main>;
+def whole_archive: Flag<["--"], "whole-archive">,
+ HelpText<"Force load of all members in a static library">,
+ Group<grp_main>;
+def no_whole_archive: Flag<["--"], "no-whole-archive">,
+ HelpText<"Restores the default behavior of loading archive members">,
+ Group<grp_main>;
+def nostdlib : Flag<["-"], "nostdlib">,
+ HelpText<"Disable default search path for libraries">,
+ Group<grp_main>;
+def image_base : Separate<["--"], "image-base">,
+ HelpText<"Set the base address">,
+ Group<grp_main>;
+
+//===----------------------------------------------------------------------===//
+/// Static Executable Options
+//===----------------------------------------------------------------------===//
+def grp_staticexec : OptionGroup<"opts">,
+ HelpText<"STATIC EXECUTABLE OPTIONS">;
+def nmagic : Flag<["--"], "nmagic">,
+ HelpText<"Turn off page alignment of sections,"
+ " and disable linking against shared libraries">,
+ Group<grp_staticexec>;
+def omagic : Flag<["--"], "omagic">,
+ HelpText<"Set the text and data sections to be readable and writable."
+ " Also, do not page-align the data segment, and"
+ " disable linking against shared libraries.">,
+ Group<grp_staticexec>;
+def no_omagic : Flag<["--"], "no-omagic">,
+ HelpText<"This option negates most of the effects of the -N option."
+ "Disable linking with shared libraries">,
+ Group<grp_staticexec>;
+// Compatible Aliases
+def nmagic_alias : Flag<["-"], "n">,
+ Alias<nmagic>;
+def omagic_alias : Flag<["-"], "N">,
+ Alias<omagic>;
+
+//===----------------------------------------------------------------------===//
+/// Dynamic Library/Executable Options
+//===----------------------------------------------------------------------===//
+def grp_dynlibexec : OptionGroup<"opts">,
+ HelpText<"DYNAMIC LIBRARY/EXECUTABLE OPTIONS">;
+def dynamic_linker : Joined<["--"], "dynamic-linker=">,
+ HelpText<"Set the path to the dynamic linker">, Group<grp_dynlibexec>;
+// Executable options - compatibility aliases
+def dynamic_linker_alias : Separate<["-"], "dynamic-linker">,
+ Alias<dynamic_linker>;
+defm rpath : dashEq<"rpath", "rpath",
+ "Add a directory to the runtime library search path">,
+ Group<grp_dynlibexec>;
+def rpath_link : Separate<["-"], "rpath-link">,
+ HelpText<"Specifies the first set of directories to search">,
+ Group<grp_dynlibexec>;
+def export_dynamic : Flag<["-", "--"], "export-dynamic">,
+ HelpText<"Add all symbols to the dynamic symbol table"
+ " when creating executables">,
+ Group<grp_main>;
+def alias_export_dynamic: Flag<["-"], "E">,
+ Alias<export_dynamic>;
+def no_export_dynamic : Flag<["--"], "no-export-dynamic">,
+ Group<grp_main>;
+
+//===----------------------------------------------------------------------===//
+/// Dynamic Library Options
+//===----------------------------------------------------------------------===//
+def grp_dynlib : OptionGroup<"opts">,
+ HelpText<"DYNAMIC LIBRARY OPTIONS">;
+def soname : Joined<["-", "--"], "soname=">,
+ HelpText<"Set the internal DT_SONAME field to the specified name">,
+ Group<grp_dynlib>;
+def soname_separate : Separate<["-", "--"], "soname">, Alias<soname>;
+def soname_h : Separate<["-"], "h">, Alias<soname>;
+
+//===----------------------------------------------------------------------===//
+/// Resolver Options
+//===----------------------------------------------------------------------===//
+def grp_resolveropt : OptionGroup<"opts">,
+ HelpText<"SYMBOL RESOLUTION OPTIONS">;
+defm u : smDash<"u", "undefined",
+ "Force symbol to be entered in the output file"
+ " as an undefined symbol">,
+ Group<grp_resolveropt>;
+def start_group : Flag<["--"], "start-group">,
+ HelpText<"Start a group">,
+ Group<grp_resolveropt>;
+def alias_start_group: Flag<["-"], "(">,
+ Alias<start_group>;
+def end_group : Flag<["--"], "end-group">,
+ HelpText<"End a group">,
+ Group<grp_resolveropt>;
+def alias_end_group: Flag<["-"], ")">,
+ Alias<end_group>;
+def as_needed : Flag<["--"], "as-needed">,
+ HelpText<"This option affects ELF DT_NEEDED tags for "
+ "dynamic libraries mentioned on the command line">,
+ Group<grp_resolveropt>;
+def no_as_needed : Flag<["--"], "no-as-needed">,
+ HelpText<"This option restores the default behavior"
+ " of adding DT_NEEDED entries">,
+ Group<grp_resolveropt>;
+def no_allow_shlib_undefs : Flag<["--"], "no-allow-shlib-undefined">,
+ HelpText<"Do not allow undefined symbols from dynamic"
+ " library when creating executables">,
+ Group<grp_resolveropt>;
+def allow_shlib_undefs : Flag<["-", "--"], "allow-shlib-undefined">,
+ HelpText<"Allow undefined symbols from dynamic"
+ " library when creating executables">,
+ Group<grp_resolveropt>;
+def use_shlib_undefs: Flag<["--"], "use-shlib-undefines">,
+ HelpText<"Resolve undefined symbols from dynamic libraries">,
+ Group<grp_resolveropt>;
+def allow_multiple_definition: Flag<["--"], "allow-multiple-definition">,
+ HelpText<"Allow multiple definitions">,
+ Group<grp_resolveropt>;
+def defsym : Joined<["--"], "defsym=">,
+ HelpText<"Create a defined symbol">,
+ Group<grp_resolveropt>;
+
+//===----------------------------------------------------------------------===//
+/// Custom Options
+//===----------------------------------------------------------------------===//
+def grp_customopts : OptionGroup<"opts">,
+ HelpText<"CUSTOM OPTIONS">;
+def rosegment: Flag<["--"], "rosegment">,
+ HelpText<"Put read-only non-executable sections in their own segment">,
+ Group<grp_customopts>;
+def z : Separate<["-"], "z">,
+ HelpText<"Linker Option extensions">,
+ Group<grp_customopts>;
+def no_align_segments: Flag<["--"], "no-align-segments">,
+ HelpText<"Don't align ELF segments(virtualaddress/fileoffset) to page boundaries">,
+ Group<grp_customopts>;
+
+//===----------------------------------------------------------------------===//
+/// Symbol options
+//===----------------------------------------------------------------------===//
+def grp_symbolopts : OptionGroup<"opts">,
+ HelpText<"SYMBOL OPTIONS">;
+def demangle : Flag<["--"], "demangle">,
+ HelpText<"Demangle C++ symbols">,
+ Group<grp_symbolopts>;
+def no_demangle : Flag<["--"], "no-demangle">,
+ HelpText<"Dont demangle C++ symbols">,
+ Group<grp_symbolopts>;
+def strip_all : Flag<["--"], "strip-all">,
+ HelpText<"Omit all symbol informations from output">,
+ Group<grp_symbolopts>;
+def alias_strip_all : Flag<["-"], "s">,
+ Alias<strip_all>;
+defm wrap : smDash<"wrap", "wrap",
+ "Use a wrapper function for symbol. Any "
+ " undefined reference to symbol will be resolved to "
+ "\"__wrap_symbol\". Any undefined reference to \"__real_symbol\""
+ " will be resolved to symbol.">,
+ MetaVarName<"<symbol>">,
+ Group<grp_symbolopts>;
+
+//===----------------------------------------------------------------------===//
+/// Script Options
+//===----------------------------------------------------------------------===//
+def grp_scriptopts : OptionGroup<"opts">,
+ HelpText<"SCRIPT OPTIONS">;
+defm T : smDash<"T", "script",
+ "Use the given linker script in place of the default script.">,
+ Group<grp_scriptopts>;
+
+//===----------------------------------------------------------------------===//
+/// Optimization Options
+//===----------------------------------------------------------------------===//
+def grp_opts : OptionGroup<"opts">,
+ HelpText<"OPTIMIZATIONS">;
+def hash_style : Joined <["--"], "hash-style=">,
+ HelpText<"Set the type of linker's hash table(s)">,
+ Group<grp_opts>;
+def merge_strings : Flag<["--"], "merge-strings">,
+ HelpText<"Merge common strings across mergeable sections">,
+ Group<grp_opts>;
+def eh_frame_hdr : Flag<["--"], "eh-frame-hdr">,
+ HelpText<"Request creation of .eh_frame_hdr section and ELF "
+ " PT_GNU_EH_FRAME segment header">,
+ Group<grp_opts>;
+
+//===----------------------------------------------------------------------===//
+/// Tracing Options
+//===----------------------------------------------------------------------===//
+def grp_tracingopts : OptionGroup<"opts">,
+ HelpText<"TRACING OPTIONS">;
+def t : Flag<["-"], "t">,
+ HelpText<"Print the names of the input files as ld processes them">,
+ Group<grp_tracingopts>;
+def stats : Flag<["--"], "stats">,
+ HelpText<"Print time and memory usage stats">, Group<grp_tracingopts>;
+
+//===----------------------------------------------------------------------===//
+/// Extensions
+//===----------------------------------------------------------------------===//
+def grp_extns : OptionGroup<"opts">,
+ HelpText<"Extensions">;
+def output_filetype: Separate<["--"], "output-filetype">,
+ HelpText<"Specify what type of output file that lld creates, YAML/Native">,
+ Group<grp_extns>;
+def alias_output_filetype: Joined<["--"], "output-filetype=">,
+ Alias<output_filetype>;
+
+//===----------------------------------------------------------------------===//
+/// Ignored options
+//===----------------------------------------------------------------------===//
+def grp_ignored: OptionGroup<"ignored">,
+ HelpText<"GNU Options ignored for Compatibility ">;
+def dashg : Flag<["-"], "g">,
+ HelpText<"Ignored.">,
+ Group<grp_ignored>;
+def Qy : Flag<["-"], "Qy">,
+ HelpText<"Ignored for SVR4 Compatibility">,
+ Group<grp_ignored>;
+def qmagic : Flag<["-"], "qmagic">,
+ HelpText<"Ignored for Linux Compatibility">,
+ Group<grp_ignored>;
+
+//===----------------------------------------------------------------------===//
+/// Help
+//===----------------------------------------------------------------------===//
+def help : Flag<["--"], "help">,
+ HelpText<"Display this help message">;
diff --git a/lib/Driver/Makefile b/lib/Driver/Makefile
new file mode 100644
index 000000000000..19024cfab0f1
--- /dev/null
+++ b/lib/Driver/Makefile
@@ -0,0 +1,38 @@
+##===- lld/lib/Driver/Makefile ---------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLD_LEVEL := ../..
+LIBRARYNAME := lldDriver
+
+BUILT_SOURCES = CoreOptions.inc UniversalDriverOptions.inc DarwinLdOptions.inc \
+ GnuLdOptions.inc WinLinkOptions.inc
+
+TABLEGEN_INC_FILES_COMMON = 1
+
+include $(LLD_LEVEL)/Makefile
+
+$(ObjDir)/CoreOptions.inc.tmp : CoreOptions.td $(LLVM_TBLGEN) $(ObjDir)/.dir
+ $(Echo) "Building LLD CoreOptions Option tables with tblgen"
+ $(Verb) $(LLVMTableGen) -gen-opt-parser-defs -o $(call SYSPATH, $@) $<
+
+$(ObjDir)/UniversalDriverOptions.inc.tmp : UniversalDriverOptions.td $(LLVM_TBLGEN) $(ObjDir)/.dir
+ $(Echo) "Building LLD Universal Driver Options tables with tblgen"
+ $(Verb) $(LLVMTableGen) -gen-opt-parser-defs -o $(call SYSPATH, $@) $<
+
+$(ObjDir)/DarwinLdOptions.inc.tmp : DarwinLdOptions.td $(LLVM_TBLGEN) $(ObjDir)/.dir
+ $(Echo) "Building LLD Darwin ld Option tables with tblgen"
+ $(Verb) $(LLVMTableGen) -gen-opt-parser-defs -o $(call SYSPATH, $@) $<
+
+$(ObjDir)/GnuLdOptions.inc.tmp : GnuLdOptions.td $(LLVM_TBLGEN) $(ObjDir)/.dir
+ $(Echo) "Building LLD Gnu ld Option tables with tblgen"
+ $(Verb) $(LLVMTableGen) -gen-opt-parser-defs -o $(call SYSPATH, $@) $<
+
+$(ObjDir)/WinLinkOptions.inc.tmp : WinLinkOptions.td $(LLVM_TBLGEN) $(ObjDir)/.dir
+ $(Echo) "Building LLD WinLinkOptions Option tables with tblgen"
+ $(Verb) $(LLVMTableGen) -gen-opt-parser-defs -o $(call SYSPATH, $@) $<
diff --git a/lib/Driver/TODO.rst b/lib/Driver/TODO.rst
new file mode 100644
index 000000000000..e03d829c232d
--- /dev/null
+++ b/lib/Driver/TODO.rst
@@ -0,0 +1,101 @@
+GNU ld Driver
+~~~~~~~~~~~~~
+
+Missing Options
+###############
+
+* --audit
+* -A,--architecture
+* -b,--format
+* -d,-dc,-dp
+* -P,--depaudit
+* --exclude-libs
+* --exclude-modules-for-implib
+* -E,--export-dynamic,--no-export-dynamic
+* -EB (We probably shouldn't support this)
+* -EL (We probably shouldn't support this)
+* -f,--auxiliary
+* -F,--filter
+* -G,--gpsize
+* -h
+* -i
+* --library
+* -M
+* --print-map
+* -output
+* -O
+* -q,--emit-relocs
+* --force-dynamic
+* --relocatable
+* -R,--just-symbols
+* -s,--strip-all
+* -S,--strip-debug
+* --trace
+* -dT,--default-script
+* -Ur
+* --unique
+* -v,--version,-V
+* -x,--discard-all
+* -X,--discard-locals
+* -y,--trace-symbol
+* -z (keywords need to be implemented)
+* --accept-unknown-input-arch,--no-accept-unknown-input-arch
+* -Bdynamic,-dy,-call_shared
+* -Bgroup
+* -dn,-non_shared
+* -Bsymbolic
+* -Bsymbolic-functions
+* --dynamic-list
+* --dynamic-list-data
+* --dynamic-list-cpp-new
+* --dynamic-list-cpp-typeinfo
+* --check-sections,--no-check-sections
+* --copy-dt-needed-entries,--no-copy-dt-needed-entires
+* --cref
+* --no-define-common
+* --defsym (only absolute value supported now)
+* --demangle,--no-demangle
+* -I
+* --fatal-warnings,--no-fatal-warnings
+* --force-exe-suffix
+* --gc-sections,--no-gc-sections
+* --print-gc-sections,--no-print-gc-sections
+* --print-output-format
+* --target-help
+* -Map
+* --no-keep-memory
+* --no-undefined,-z defs
+* --allow-shlib-undefined,--no-alow-shlib-undefined
+* --no-undefined-version
+* --default-symver
+* --default-imported-symver
+* --no-warn-mismatch
+* --no-warn-search-mismatch
+* --oformat
+* -pie,--pic-executable
+* --relax,--no-relax
+* --retain-symbols-file
+* --sort-common
+* --sort-section={name,alignment}
+* --split-by-file
+* --split-by-reloc
+* --stats
+* --section-start
+* -T{bss,data,text,{text,rodata,data}-segment}
+* --unresolved-symbols
+* -dll-verbose,--verbose
+* --version-script
+* --warn-common
+* --warn-constructors
+* --warn-multiple-gp
+* --warn-once
+* --warn-section-align
+* --warn-shared-textrel
+* --warn-alternate-em
+* --warn-unresolved-symbols
+* --error-unresolved-symbols
+* --wrap
+* --no-ld-generated-unwind-info
+* --hash-size
+* --reduce-memory-overheads
+* --build-id
diff --git a/lib/Driver/UniversalDriver.cpp b/lib/Driver/UniversalDriver.cpp
new file mode 100644
index 000000000000..7d42ad7b4bfc
--- /dev/null
+++ b/lib/Driver/UniversalDriver.cpp
@@ -0,0 +1,218 @@
+//===- lib/Driver/UniversalDriver.cpp -------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+///
+/// Driver for "universal" lld tool which can mimic any linker command line
+/// parsing once it figures out which command line flavor to use.
+///
+//===----------------------------------------------------------------------===//
+
+#include "lld/Driver/Driver.h"
+#include "lld/Config/Version.h"
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace lld;
+
+namespace {
+
+// Create enum with OPT_xxx values for each option in GnuLdOptions.td
+enum {
+ OPT_INVALID = 0,
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELP, META) \
+ OPT_##ID,
+#include "UniversalDriverOptions.inc"
+#undef OPTION
+};
+
+// Create prefix string literals used in GnuLdOptions.td
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#include "UniversalDriverOptions.inc"
+#undef PREFIX
+
+// Create table mapping all options defined in GnuLdOptions.td
+static const llvm::opt::OptTable::Info infoTable[] = {
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR) \
+ { \
+ PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \
+ PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS \
+ } \
+ ,
+#include "UniversalDriverOptions.inc"
+#undef OPTION
+};
+
+// Create OptTable class for parsing actual command line arguments
+class UniversalDriverOptTable : public llvm::opt::OptTable {
+public:
+ UniversalDriverOptTable()
+ : OptTable(infoTable, llvm::array_lengthof(infoTable)) {}
+};
+
+enum class Flavor {
+ invalid,
+ gnu_ld, // -flavor gnu
+ win_link, // -flavor link
+ darwin_ld, // -flavor darwin
+ core // -flavor core OR -core
+};
+
+struct ProgramNameParts {
+ StringRef _target;
+ StringRef _flavor;
+};
+
+} // anonymous namespace
+
+static Flavor strToFlavor(StringRef str) {
+ return llvm::StringSwitch<Flavor>(str)
+ .Case("gnu", Flavor::gnu_ld)
+ .Case("link", Flavor::win_link)
+ .Case("lld-link", Flavor::win_link)
+ .Case("darwin", Flavor::darwin_ld)
+ .Case("core", Flavor::core)
+ .Case("ld", Flavor::gnu_ld)
+ .Default(Flavor::invalid);
+}
+
+static ProgramNameParts parseProgramName(StringRef programName) {
+ SmallVector<StringRef, 3> components;
+ llvm::SplitString(programName, components, "-");
+ ProgramNameParts ret;
+
+ using std::begin;
+ using std::end;
+
+ // Erase any lld components.
+ components.erase(std::remove(components.begin(), components.end(), "lld"),
+ components.end());
+
+ // Find the flavor component.
+ auto flIter = std::find_if(components.begin(), components.end(),
+ [](StringRef str) -> bool {
+ return strToFlavor(str) != Flavor::invalid;
+ });
+
+ if (flIter != components.end()) {
+ ret._flavor = *flIter;
+ components.erase(flIter);
+ }
+
+ // Any remaining component must be the target.
+ if (components.size() == 1)
+ ret._target = components[0];
+
+ return ret;
+}
+
+// Removes the argument from argv along with its value, if exists, and updates
+// argc.
+static void removeArg(llvm::opt::Arg *arg, int &argc, const char **&argv) {
+ unsigned int numToRemove = arg->getNumValues() + 1;
+ unsigned int argIndex = arg->getIndex() + 1;
+
+ std::rotate(&argv[argIndex], &argv[argIndex + numToRemove], argv + argc);
+ argc -= numToRemove;
+}
+
+static Flavor getFlavor(int &argc, const char **&argv,
+ std::unique_ptr<llvm::opt::InputArgList> &parsedArgs) {
+ if (llvm::opt::Arg *argCore = parsedArgs->getLastArg(OPT_core)) {
+ removeArg(argCore, argc, argv);
+ return Flavor::core;
+ }
+ if (llvm::opt::Arg *argFlavor = parsedArgs->getLastArg(OPT_flavor)) {
+ removeArg(argFlavor, argc, argv);
+ return strToFlavor(argFlavor->getValue());
+ }
+
+#if LLVM_ON_UNIX
+ if (llvm::sys::path::filename(argv[0]).equals("ld")) {
+#if __APPLE__
+ // On a Darwin systems, if linker binary is named "ld", use Darwin driver.
+ return Flavor::darwin_ld;
+#endif
+ // On a ELF based systems, if linker binary is named "ld", use gnu driver.
+ return Flavor::gnu_ld;
+ }
+#endif
+
+ StringRef name = llvm::sys::path::stem(argv[0]);
+ return strToFlavor(parseProgramName(name)._flavor);
+}
+
+namespace lld {
+
+bool UniversalDriver::link(int argc, const char *argv[],
+ raw_ostream &diagnostics) {
+ // Parse command line options using GnuLdOptions.td
+ std::unique_ptr<llvm::opt::InputArgList> parsedArgs;
+ UniversalDriverOptTable table;
+ unsigned missingIndex;
+ unsigned missingCount;
+
+ // Program name
+ StringRef programName = llvm::sys::path::stem(argv[0]);
+
+ parsedArgs.reset(
+ table.ParseArgs(&argv[1], &argv[argc], missingIndex, missingCount));
+
+ if (missingCount) {
+ diagnostics << "error: missing arg value for '"
+ << parsedArgs->getArgString(missingIndex) << "' expected "
+ << missingCount << " argument(s).\n";
+ return false;
+ }
+
+ // Handle -help
+ if (parsedArgs->getLastArg(OPT_help)) {
+ table.PrintHelp(llvm::outs(), programName.data(), "LLVM Linker", false);
+ return true;
+ }
+
+ // Handle -version
+ if (parsedArgs->getLastArg(OPT_version)) {
+ diagnostics << "LLVM Linker Version: " << getLLDVersion()
+ << getLLDRepositoryVersion() << "\n";
+ return true;
+ }
+
+ Flavor flavor = getFlavor(argc, argv, parsedArgs);
+ std::vector<const char *> args(argv, argv + argc);
+
+ // Switch to appropriate driver.
+ switch (flavor) {
+ case Flavor::gnu_ld:
+ return GnuLdDriver::linkELF(args.size(), args.data(), diagnostics);
+ case Flavor::darwin_ld:
+ return DarwinLdDriver::linkMachO(args.size(), args.data(), diagnostics);
+ case Flavor::win_link:
+ return WinLinkDriver::linkPECOFF(args.size(), args.data(), diagnostics);
+ case Flavor::core:
+ return CoreDriver::link(args.size(), args.data(), diagnostics);
+ case Flavor::invalid:
+ diagnostics << "Select the appropriate flavor\n";
+ table.PrintHelp(llvm::outs(), programName.data(), "LLVM Linker", false);
+ return false;
+ }
+ llvm_unreachable("Unrecognised flavor");
+}
+
+} // end namespace lld
diff --git a/lib/Driver/UniversalDriverOptions.td b/lib/Driver/UniversalDriverOptions.td
new file mode 100644
index 000000000000..14abc9ce9911
--- /dev/null
+++ b/lib/Driver/UniversalDriverOptions.td
@@ -0,0 +1,19 @@
+include "llvm/Option/OptParser.td"
+
+// Select an optional flavor
+def flavor: Separate<["-"], "flavor">,
+ HelpText<"Flavor for linking, options are gnu/darwin/link">;
+
+// Select the core flavor
+def core : Flag<["-"], "core">,
+ HelpText<"CORE linking">;
+
+def target: Separate<["-"], "target">,
+ HelpText<"Select the target">;
+
+def version: Flag<["-"], "version">,
+ HelpText<"Display the version">;
+
+// Help message
+def help : Flag<["-"], "help">,
+ HelpText<"Display this help message">;
diff --git a/lib/Driver/WinLinkDriver.cpp b/lib/Driver/WinLinkDriver.cpp
new file mode 100644
index 000000000000..6ee7a5a004b5
--- /dev/null
+++ b/lib/Driver/WinLinkDriver.cpp
@@ -0,0 +1,1371 @@
+//===- lib/Driver/WinLinkDriver.cpp ---------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+///
+/// Concrete instance of the Driver for Windows link.exe.
+///
+//===----------------------------------------------------------------------===//
+
+#include "lld/Driver/Driver.h"
+#include "lld/Driver/WinLinkModuleDef.h"
+#include "lld/ReaderWriter/PECOFFLinkingContext.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cctype>
+#include <map>
+#include <memory>
+#include <sstream>
+#include <tuple>
+
+namespace lld {
+
+//
+// Option definitions
+//
+
+// Create enum with OPT_xxx values for each option in WinLinkOptions.td
+enum {
+ OPT_INVALID = 0,
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELP, META) \
+ OPT_##ID,
+#include "WinLinkOptions.inc"
+#undef OPTION
+};
+
+// Create prefix string literals used in WinLinkOptions.td
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#include "WinLinkOptions.inc"
+#undef PREFIX
+
+// Create table mapping all options defined in WinLinkOptions.td
+static const llvm::opt::OptTable::Info infoTable[] = {
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR) \
+ { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \
+ PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS },
+#include "WinLinkOptions.inc"
+#undef OPTION
+};
+
+namespace {
+
+// Create OptTable class for parsing actual command line arguments
+class WinLinkOptTable : public llvm::opt::OptTable {
+public:
+ // link.exe's command line options are case insensitive, unlike
+ // other driver's options for Unix.
+ WinLinkOptTable()
+ : OptTable(infoTable, llvm::array_lengthof(infoTable),
+ /* ignoreCase */ true) {}
+};
+
+} // anonymous namespace
+
+//
+// Functions to parse each command line option
+//
+
+// Split the given string with spaces.
+static std::vector<std::string> splitArgList(const std::string &str) {
+ std::stringstream stream(str);
+ std::istream_iterator<std::string> begin(stream);
+ std::istream_iterator<std::string> end;
+ return std::vector<std::string>(begin, end);
+}
+
+// Split the given string with the path separator.
+static std::vector<StringRef> splitPathList(StringRef str) {
+ std::vector<StringRef> ret;
+ while (!str.empty()) {
+ StringRef path;
+ std::tie(path, str) = str.split(';');
+ ret.push_back(path);
+ }
+ return ret;
+}
+
+// Parse an argument for /alternatename. The expected string is
+// "<string>=<string>".
+static bool parseAlternateName(StringRef arg, StringRef &weak, StringRef &def,
+ raw_ostream &diag) {
+ std::tie(weak, def) = arg.split('=');
+ if (weak.empty() || def.empty()) {
+ diag << "Error: malformed /alternatename option: " << arg << "\n";
+ return false;
+ }
+ return true;
+}
+
+// Parse an argument for /base, /stack or /heap. The expected string
+// is "<integer>[,<integer>]".
+static bool parseMemoryOption(StringRef arg, uint64_t &reserve,
+ uint64_t &commit) {
+ StringRef reserveStr, commitStr;
+ std::tie(reserveStr, commitStr) = arg.split(',');
+ if (reserveStr.getAsInteger(0, reserve))
+ return false;
+ if (!commitStr.empty() && commitStr.getAsInteger(0, commit))
+ return false;
+ return true;
+}
+
+// Parse an argument for /version or /subsystem. The expected string is
+// "<integer>[.<integer>]".
+static bool parseVersion(StringRef arg, uint32_t &major, uint32_t &minor) {
+ StringRef majorVersion, minorVersion;
+ std::tie(majorVersion, minorVersion) = arg.split('.');
+ if (minorVersion.empty())
+ minorVersion = "0";
+ if (majorVersion.getAsInteger(0, major))
+ return false;
+ if (minorVersion.getAsInteger(0, minor))
+ return false;
+ return true;
+}
+
+// Returns subsystem type for the given string.
+static llvm::COFF::WindowsSubsystem stringToWinSubsystem(StringRef str) {
+ return llvm::StringSwitch<llvm::COFF::WindowsSubsystem>(str.lower())
+ .Case("windows", llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_GUI)
+ .Case("console", llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_CUI)
+ .Case("boot_application",
+ llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION)
+ .Case("efi_application", llvm::COFF::IMAGE_SUBSYSTEM_EFI_APPLICATION)
+ .Case("efi_boot_service_driver",
+ llvm::COFF::IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER)
+ .Case("efi_rom", llvm::COFF::IMAGE_SUBSYSTEM_EFI_ROM)
+ .Case("efi_runtime_driver",
+ llvm::COFF::IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER)
+ .Case("native", llvm::COFF::IMAGE_SUBSYSTEM_NATIVE)
+ .Case("posix", llvm::COFF::IMAGE_SUBSYSTEM_POSIX_CUI)
+ .Default(llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN);
+}
+
+// Parse /subsystem command line option. The form of /subsystem is
+// "subsystem_name[,majorOSVersion[.minorOSVersion]]".
+static bool parseSubsystem(StringRef arg,
+ llvm::COFF::WindowsSubsystem &subsystem,
+ llvm::Optional<uint32_t> &major,
+ llvm::Optional<uint32_t> &minor, raw_ostream &diag) {
+ StringRef subsystemStr, osVersion;
+ std::tie(subsystemStr, osVersion) = arg.split(',');
+ if (!osVersion.empty()) {
+ uint32_t v1, v2;
+ if (!parseVersion(osVersion, v1, v2))
+ return false;
+ major = v1;
+ minor = v2;
+ }
+ subsystem = stringToWinSubsystem(subsystemStr);
+ if (subsystem == llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN) {
+ diag << "error: unknown subsystem name: " << subsystemStr << "\n";
+ return false;
+ }
+ return true;
+}
+
+static llvm::COFF::MachineTypes stringToMachineType(StringRef str) {
+ // FIXME: we have no way to differentiate between ARM and ARMNT currently.
+ // However, given that LLVM only supports ARM NT, default to that for now.
+ return llvm::StringSwitch<llvm::COFF::MachineTypes>(str.lower())
+ .Case("arm", llvm::COFF::IMAGE_FILE_MACHINE_ARMNT)
+ .Case("x64", llvm::COFF::IMAGE_FILE_MACHINE_AMD64)
+ .Case("x86", llvm::COFF::IMAGE_FILE_MACHINE_I386)
+ .Default(llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN);
+}
+
+// Parse /section:name,[[!]{DEKPRSW}]
+//
+// /section option is to set non-default bits in the Characteristics fields of
+// the section header. D, E, K, P, R, S, and W represent discardable,
+// execute, not_cachable, not_pageable, read, shared, and write bits,
+// respectively. You can specify multiple flags in one /section option.
+//
+// If the flag starts with "!", the flags represent a mask that should be turned
+// off regardless of the default value. You can even create a section which is
+// not readable, writable nor executable with this -- although it's probably
+// useless.
+static bool parseSection(StringRef option, std::string &section,
+ llvm::Optional<uint32_t> &flags,
+ llvm::Optional<uint32_t> &mask) {
+ StringRef flagString;
+ std::tie(section, flagString) = option.split(",");
+
+ bool negative = false;
+ if (flagString.startswith("!")) {
+ negative = true;
+ flagString = flagString.substr(1);
+ }
+ if (flagString.empty())
+ return false;
+
+ uint32_t attribs = 0;
+ for (size_t i = 0, e = flagString.size(); i < e; ++i) {
+ switch (tolower(flagString[i])) {
+#define CASE(c, flag) \
+ case c: \
+ attribs |= flag; \
+ break
+ CASE('d', llvm::COFF::IMAGE_SCN_MEM_DISCARDABLE);
+ CASE('e', llvm::COFF::IMAGE_SCN_MEM_EXECUTE);
+ CASE('k', llvm::COFF::IMAGE_SCN_MEM_NOT_CACHED);
+ CASE('p', llvm::COFF::IMAGE_SCN_MEM_NOT_PAGED);
+ CASE('r', llvm::COFF::IMAGE_SCN_MEM_READ);
+ CASE('s', llvm::COFF::IMAGE_SCN_MEM_SHARED);
+ CASE('w', llvm::COFF::IMAGE_SCN_MEM_WRITE);
+#undef CASE
+ default:
+ return false;
+ }
+ }
+
+ if (negative) {
+ mask = attribs;
+ } else {
+ flags = attribs;
+ }
+ return true;
+}
+
+static bool readFile(PECOFFLinkingContext &ctx, StringRef path,
+ ArrayRef<uint8_t> &result) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> buf = MemoryBuffer::getFile(path);
+ if (!buf)
+ return false;
+ StringRef Data = buf.get()->getBuffer();
+ result = ctx.allocate(ArrayRef<uint8_t>(
+ reinterpret_cast<const uint8_t *>(Data.begin()), Data.size()));
+ return true;
+}
+
+// Parse /manifest:EMBED[,ID=#]|NO.
+static bool parseManifest(StringRef option, bool &enable, bool &embed,
+ int &id) {
+ if (option.equals_lower("no")) {
+ enable = false;
+ return true;
+ }
+ if (!option.startswith_lower("embed"))
+ return false;
+
+ embed = true;
+ option = option.substr(strlen("embed"));
+ if (option.empty())
+ return true;
+ if (!option.startswith_lower(",id="))
+ return false;
+ option = option.substr(strlen(",id="));
+ if (option.getAsInteger(0, id))
+ return false;
+ return true;
+}
+
+static bool isLibraryFile(StringRef path) {
+ return path.endswith_lower(".lib") || path.endswith_lower(".imp");
+}
+
+static StringRef getObjectPath(PECOFFLinkingContext &ctx, StringRef path) {
+ std::string result;
+ if (isLibraryFile(path)) {
+ result = ctx.searchLibraryFile(path);
+ } else if (llvm::sys::path::extension(path).empty()) {
+ result = path.str() + ".obj";
+ } else {
+ result = path;
+ }
+ return ctx.allocate(result);
+}
+
+static StringRef getLibraryPath(PECOFFLinkingContext &ctx, StringRef path) {
+ std::string result = isLibraryFile(path)
+ ? ctx.searchLibraryFile(path)
+ : ctx.searchLibraryFile(path.str() + ".lib");
+ return ctx.allocate(result);
+}
+
+// Returns true if the given file is a Windows resource file.
+static bool isResoruceFile(StringRef path) {
+ llvm::sys::fs::file_magic fileType;
+ if (llvm::sys::fs::identify_magic(path, fileType)) {
+ // If we cannot read the file, assume it's not a resource file.
+ // The further stage will raise an error on this unreadable file.
+ return false;
+ }
+ return fileType == llvm::sys::fs::file_magic::windows_resource;
+}
+
+// Merge Windows resource files and convert them to a single COFF file.
+// The temporary file path is set to result.
+static bool convertResourceFiles(PECOFFLinkingContext &ctx,
+ std::vector<std::string> inFiles,
+ std::string &result) {
+ // Create an output file path.
+ SmallString<128> outFile;
+ if (llvm::sys::fs::createTemporaryFile("resource", "obj", outFile))
+ return false;
+ std::string outFileArg = ("/out:" + outFile).str();
+
+ // Construct CVTRES.EXE command line and execute it.
+ std::string program = "cvtres.exe";
+ ErrorOr<std::string> programPathOrErr = llvm::sys::findProgramByName(program);
+ if (!programPathOrErr) {
+ llvm::errs() << "Unable to find " << program << " in PATH\n";
+ return false;
+ }
+ const std::string &programPath = *programPathOrErr;
+
+ std::vector<const char *> args;
+ args.push_back(programPath.c_str());
+ args.push_back(ctx.is64Bit() ? "/machine:x64" : "/machine:x86");
+ args.push_back("/readonly");
+ args.push_back("/nologo");
+ args.push_back(outFileArg.c_str());
+ for (const std::string &path : inFiles)
+ args.push_back(path.c_str());
+ args.push_back(nullptr);
+
+ if (llvm::sys::ExecuteAndWait(programPath.c_str(), &args[0]) != 0) {
+ llvm::errs() << program << " failed\n";
+ return false;
+ }
+ result = outFile.str();
+ return true;
+}
+
+// Parse /manifestuac:(level=<string>|uiAccess=<string>).
+//
+// The arguments will be embedded to the manifest XML file with no error check,
+// so the values given via the command line must be valid as XML attributes.
+// This may sound a bit odd, but that's how link.exe works, so we will follow.
+static bool parseManifestUAC(StringRef option,
+ llvm::Optional<std::string> &level,
+ llvm::Optional<std::string> &uiAccess) {
+ for (;;) {
+ option = option.ltrim();
+ if (option.empty())
+ return true;
+ if (option.startswith_lower("level=")) {
+ option = option.substr(strlen("level="));
+ StringRef value;
+ std::tie(value, option) = option.split(" ");
+ level = value.str();
+ continue;
+ }
+ if (option.startswith_lower("uiaccess=")) {
+ option = option.substr(strlen("uiaccess="));
+ StringRef value;
+ std::tie(value, option) = option.split(" ");
+ uiAccess = value.str();
+ continue;
+ }
+ return false;
+ }
+}
+
+// Returns the machine type (e.g. x86) of the given input file.
+// If the file is not COFF, returns false.
+static bool getMachineType(StringRef path, llvm::COFF::MachineTypes &result) {
+ llvm::sys::fs::file_magic fileType;
+ if (llvm::sys::fs::identify_magic(path, fileType))
+ return false;
+ if (fileType != llvm::sys::fs::file_magic::coff_object)
+ return false;
+ ErrorOr<std::unique_ptr<MemoryBuffer>> buf = MemoryBuffer::getFile(path);
+ if (!buf)
+ return false;
+ std::error_code ec;
+ llvm::object::COFFObjectFile obj(buf.get()->getMemBufferRef(), ec);
+ if (ec)
+ return false;
+ result = static_cast<llvm::COFF::MachineTypes>(obj.getMachine());
+ return true;
+}
+
+// Parse /export:entryname[=internalname][,@ordinal[,NONAME]][,DATA][,PRIVATE].
+//
+// MSDN doesn't say anything about /export:foo=bar style option or PRIVATE
+// attribtute, but link.exe actually accepts them.
+static bool parseExport(StringRef option,
+ PECOFFLinkingContext::ExportDesc &ret) {
+ StringRef name;
+ StringRef rest;
+ std::tie(name, rest) = option.split(",");
+ if (name.empty())
+ return false;
+ if (name.find('=') == StringRef::npos) {
+ ret.name = name;
+ } else {
+ std::tie(ret.externalName, ret.name) = name.split("=");
+ if (ret.name.empty())
+ return false;
+ }
+
+ for (;;) {
+ if (rest.empty())
+ return true;
+ StringRef arg;
+ std::tie(arg, rest) = rest.split(",");
+ if (arg.equals_lower("noname")) {
+ if (ret.ordinal < 0)
+ return false;
+ ret.noname = true;
+ continue;
+ }
+ if (arg.equals_lower("data")) {
+ ret.isData = true;
+ continue;
+ }
+ if (arg.equals_lower("private")) {
+ ret.isPrivate = true;
+ continue;
+ }
+ if (arg.startswith("@")) {
+ int ordinal;
+ if (arg.substr(1).getAsInteger(0, ordinal))
+ return false;
+ if (ordinal <= 0 || 65535 < ordinal)
+ return false;
+ ret.ordinal = ordinal;
+ continue;
+ }
+ return false;
+ }
+}
+
+// Read module-definition file.
+static bool parseDef(StringRef option, llvm::BumpPtrAllocator &alloc,
+ std::vector<moduledef::Directive *> &result) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> buf = MemoryBuffer::getFile(option);
+ if (!buf)
+ return false;
+ moduledef::Lexer lexer(std::move(buf.get()));
+ moduledef::Parser parser(lexer, alloc);
+ return parser.parse(result);
+}
+
+static StringRef replaceExtension(PECOFFLinkingContext &ctx, StringRef path,
+ StringRef extension) {
+ SmallString<128> val = path;
+ llvm::sys::path::replace_extension(val, extension);
+ return ctx.allocate(val.str());
+}
+
+// Create a manifest file contents.
+static std::string createManifestXml(PECOFFLinkingContext &ctx) {
+ std::string ret;
+ llvm::raw_string_ostream out(ret);
+ // Emit the XML. Note that we do *not* verify that the XML attributes are
+ // syntactically correct. This is intentional for link.exe compatibility.
+ out << "<?xml version=\"1.0\" standalone=\"yes\"?>\n"
+ "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\"\n"
+ " manifestVersion=\"1.0\">\n";
+ if (ctx.getManifestUAC()) {
+ out << " <trustInfo>\n"
+ " <security>\n"
+ " <requestedPrivileges>\n"
+ " <requestedExecutionLevel level=" << ctx.getManifestLevel()
+ << " uiAccess=" << ctx.getManifestUiAccess()
+ << "/>\n"
+ " </requestedPrivileges>\n"
+ " </security>\n"
+ " </trustInfo>\n";
+ const std::string &dependency = ctx.getManifestDependency();
+ if (!dependency.empty()) {
+ out << " <dependency>\n"
+ " <dependentAssembly>\n"
+ " <assemblyIdentity " << dependency
+ << " />\n"
+ " </dependentAssembly>\n"
+ " </dependency>\n";
+ }
+ }
+ out << "</assembly>\n";
+ out.flush();
+ return ret;
+}
+
+// Convert one doublequote to two doublequotes, so that we can embed the string
+// into a resource script file.
+static void quoteAndPrintXml(raw_ostream &out, StringRef str) {
+ for (;;) {
+ if (str.empty())
+ return;
+ StringRef line;
+ std::tie(line, str) = str.split("\n");
+ if (line.empty())
+ continue;
+ out << '\"';
+ const char *p = line.data();
+ for (int i = 0, size = line.size(); i < size; ++i) {
+ switch (p[i]) {
+ case '\"':
+ out << '\"';
+ // fallthrough
+ default:
+ out << p[i];
+ }
+ }
+ out << "\"\n";
+ }
+}
+
+// Create a resource file (.res file) containing the manifest XML. This is done
+// in two steps:
+//
+// 1. Create a resource script file containing the XML as a literal string.
+// 2. Run RC.EXE command to compile the script file to a resource file.
+//
+// The temporary file created in step 1 will be deleted on exit from this
+// function. The file created in step 2 will have the same lifetime as the
+// PECOFFLinkingContext.
+static bool createManifestResourceFile(PECOFFLinkingContext &ctx,
+ raw_ostream &diag,
+ std::string &resFile) {
+ // Create a temporary file for the resource script file.
+ SmallString<128> rcFileSmallString;
+ if (llvm::sys::fs::createTemporaryFile("tmp", "rc", rcFileSmallString)) {
+ diag << "Cannot create a temporary file\n";
+ return false;
+ }
+ StringRef rcFile(rcFileSmallString.str());
+ llvm::FileRemover rcFileRemover((Twine(rcFile)));
+
+ // Open the temporary file for writing.
+ std::error_code ec;
+ llvm::raw_fd_ostream out(rcFileSmallString, ec, llvm::sys::fs::F_Text);
+ if (ec) {
+ diag << "Failed to open " << ctx.getManifestOutputPath() << ": "
+ << ec.message() << "\n";
+ return false;
+ }
+
+ // Write resource script to the RC file.
+ out << "#define LANG_ENGLISH 9\n"
+ << "#define SUBLANG_DEFAULT 1\n"
+ << "#define APP_MANIFEST " << ctx.getManifestId() << "\n"
+ << "#define RT_MANIFEST 24\n"
+ << "LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT\n"
+ << "APP_MANIFEST RT_MANIFEST {\n";
+ quoteAndPrintXml(out, createManifestXml(ctx));
+ out << "}\n";
+ out.close();
+
+ // Create output resource file.
+ SmallString<128> resFileSmallString;
+ if (llvm::sys::fs::createTemporaryFile("tmp", "res", resFileSmallString)) {
+ diag << "Cannot create a temporary file";
+ return false;
+ }
+ resFile = resFileSmallString.str();
+
+ // Register the resource file path so that the file will be deleted when the
+ // context's destructor is called.
+ ctx.registerTemporaryFile(resFile);
+
+ // Run RC.EXE /fo tmp.res tmp.rc
+ std::string program = "rc.exe";
+ ErrorOr<std::string> programPathOrErr = llvm::sys::findProgramByName(program);
+ if (!programPathOrErr) {
+ diag << "Unable to find " << program << " in PATH\n";
+ return false;
+ }
+ const std::string &programPath = *programPathOrErr;
+ std::vector<const char *> args;
+ args.push_back(programPath.c_str());
+ args.push_back("/fo");
+ args.push_back(resFile.c_str());
+ args.push_back("/nologo");
+ args.push_back(rcFileSmallString.c_str());
+ args.push_back(nullptr);
+
+ if (llvm::sys::ExecuteAndWait(programPath.c_str(), &args[0]) != 0) {
+ diag << program << " failed\n";
+ return false;
+ }
+ return true;
+}
+
+
+// Create the a side-by-side manifest file.
+//
+// The manifest file will convey some information to the linker, such as whether
+// the binary needs to run as Administrator or not. Instead of being placed in
+// the PE/COFF header, it's in XML format for some reason -- I guess it's
+// probably because it's invented in the early dot-com era.
+//
+// The side-by-side manifest file is a separate XML file having ".manifest"
+// extension. It will be created in the same directory as the resulting
+// executable.
+static bool createSideBySideManifestFile(PECOFFLinkingContext &ctx,
+ raw_ostream &diag) {
+ std::string path = ctx.getManifestOutputPath();
+ if (path.empty()) {
+ // Default name of the manifest file is "foo.exe.manifest" where "foo.exe" is
+ // the output path.
+ path = ctx.outputPath();
+ path.append(".manifest");
+ }
+
+ std::error_code ec;
+ llvm::raw_fd_ostream out(path, ec, llvm::sys::fs::F_Text);
+ if (ec) {
+ diag << ec.message() << "\n";
+ return false;
+ }
+ out << createManifestXml(ctx);
+ return true;
+}
+
+// Handle /failifmismatch option.
+static bool
+handleFailIfMismatchOption(StringRef option,
+ std::map<StringRef, StringRef> &mustMatch,
+ raw_ostream &diag) {
+ StringRef key, value;
+ std::tie(key, value) = option.split('=');
+ if (key.empty() || value.empty()) {
+ diag << "error: malformed /failifmismatch option: " << option << "\n";
+ return true;
+ }
+ auto it = mustMatch.find(key);
+ if (it != mustMatch.end() && it->second != value) {
+ diag << "error: mismatch detected: '" << it->second << "' and '" << value
+ << "' for key '" << key << "'\n";
+ return true;
+ }
+ mustMatch[key] = value;
+ return false;
+}
+
+//
+// Environment variable
+//
+
+// Process "LINK" environment variable. If defined, the value of the variable
+// should be processed as command line arguments.
+static std::vector<const char *> processLinkEnv(PECOFFLinkingContext &ctx,
+ int argc, const char **argv) {
+ std::vector<const char *> ret;
+ // The first argument is the name of the command. This should stay at the head
+ // of the argument list.
+ assert(argc > 0);
+ ret.push_back(argv[0]);
+
+ // Add arguments specified by the LINK environment variable.
+ llvm::Optional<std::string> env = llvm::sys::Process::GetEnv("LINK");
+ if (env.hasValue())
+ for (std::string &arg : splitArgList(*env))
+ ret.push_back(ctx.allocate(arg).data());
+
+ // Add the rest of arguments passed via the command line.
+ for (int i = 1; i < argc; ++i)
+ ret.push_back(argv[i]);
+ ret.push_back(nullptr);
+ return ret;
+}
+
+// Process "LIB" environment variable. The variable contains a list of search
+// paths separated by semicolons.
+static void processLibEnv(PECOFFLinkingContext &ctx) {
+ llvm::Optional<std::string> env = llvm::sys::Process::GetEnv("LIB");
+ if (env.hasValue())
+ for (StringRef path : splitPathList(*env))
+ ctx.appendInputSearchPath(ctx.allocate(path));
+}
+
+namespace {
+class DriverStringSaver : public llvm::cl::StringSaver {
+public:
+ DriverStringSaver(PECOFFLinkingContext &ctx) : _ctx(ctx) {}
+
+ const char *SaveString(const char *s) override {
+ return _ctx.allocate(StringRef(s)).data();
+ }
+
+private:
+ PECOFFLinkingContext &_ctx;
+};
+}
+
+// Tokenize command line options in a given file and add them to result.
+static bool readResponseFile(StringRef path, PECOFFLinkingContext &ctx,
+ std::vector<const char *> &result) {
+ ArrayRef<uint8_t> contents;
+ if (!readFile(ctx, path, contents))
+ return false;
+ StringRef contentsStr(reinterpret_cast<const char *>(contents.data()),
+ contents.size());
+ DriverStringSaver saver(ctx);
+ SmallVector<const char *, 0> args;
+ llvm::cl::TokenizeWindowsCommandLine(contentsStr, saver, args);
+ for (const char *s : args)
+ result.push_back(s);
+ return true;
+}
+
+// Expand arguments starting with "@". It's an error if a specified file does
+// not exist. Returns true on success.
+static bool expandResponseFiles(int &argc, const char **&argv,
+ PECOFFLinkingContext &ctx, raw_ostream &diag,
+ bool &expanded) {
+ std::vector<const char *> newArgv;
+ for (int i = 0; i < argc; ++i) {
+ if (argv[i][0] != '@') {
+ newArgv.push_back(argv[i]);
+ continue;
+ }
+ StringRef filename = StringRef(argv[i] + 1);
+ if (!readResponseFile(filename, ctx, newArgv)) {
+ diag << "error: cannot read response file: " << filename << "\n";
+ return false;
+ }
+ expanded = true;
+ }
+ if (!expanded)
+ return true;
+ argc = newArgv.size();
+ newArgv.push_back(nullptr);
+ argv = &ctx.allocateCopy(newArgv)[0];
+ return true;
+}
+
+// Parses the given command line options and returns the result. Returns NULL if
+// there's an error in the options.
+static std::unique_ptr<llvm::opt::InputArgList>
+parseArgs(int argc, const char **argv, PECOFFLinkingContext &ctx,
+ raw_ostream &diag, bool isReadingDirectiveSection) {
+ // Expand arguments starting with "@".
+ bool expanded = false;
+ if (!expandResponseFiles(argc, argv, ctx, diag, expanded))
+ return nullptr;
+
+ // Parse command line options using WinLinkOptions.td
+ std::unique_ptr<llvm::opt::InputArgList> parsedArgs;
+ WinLinkOptTable table;
+ unsigned missingIndex;
+ unsigned missingCount;
+ parsedArgs.reset(table.ParseArgs(&argv[1], &argv[argc],
+ missingIndex, missingCount));
+ if (missingCount) {
+ diag << "error: missing arg value for '"
+ << parsedArgs->getArgString(missingIndex) << "' expected "
+ << missingCount << " argument(s).\n";
+ return nullptr;
+ }
+
+ // Show warning for unknown arguments. In .drectve section, unknown options
+ // starting with "-?" are silently ignored. This is a COFF's feature to embed a
+ // new linker option to an object file while keeping backward compatibility.
+ for (auto unknownArg : parsedArgs->filtered(OPT_UNKNOWN)) {
+ StringRef arg = unknownArg->getSpelling();
+ if (isReadingDirectiveSection && arg.startswith("-?"))
+ continue;
+ diag << "warning: ignoring unknown argument: " << arg << "\n";
+ }
+
+ // Copy mllvm
+ for (auto arg : parsedArgs->filtered(OPT_mllvm))
+ ctx.appendLLVMOption(arg->getValue());
+
+ // If we have expaneded response files and /verbose is given, print out the
+ // final command line.
+ if (!isReadingDirectiveSection && expanded &&
+ parsedArgs->getLastArg(OPT_verbose)) {
+ diag << "Command line:";
+ for (int i = 0; i < argc; ++i)
+ diag << " " << argv[i];
+ diag << "\n\n";
+ }
+
+ return parsedArgs;
+}
+
+// Returns true if the given file node has already been added to the input
+// graph.
+static bool hasLibrary(PECOFFLinkingContext &ctx, File *file) {
+ StringRef path = file->path();
+ for (std::unique_ptr<Node> &p : ctx.getNodes())
+ if (auto *f = dyn_cast<FileNode>(p.get()))
+ if (f->getFile()->path() == path)
+ return true;
+ return false;
+}
+
+// If the first command line argument is "/lib", link.exe acts as if it's
+// "lib.exe" command. This is for backward compatibility.
+// http://msdn.microsoft.com/en-us/library/h34w59b3.aspx
+static bool maybeRunLibCommand(int argc, const char **argv, raw_ostream &diag) {
+ if (argc <= 1)
+ return false;
+ if (!StringRef(argv[1]).equals_lower("/lib"))
+ return false;
+ ErrorOr<std::string> pathOrErr = llvm::sys::findProgramByName("lib.exe");
+ if (!pathOrErr) {
+ diag << "Unable to find lib.exe in PATH\n";
+ return true;
+ }
+ const std::string &path = *pathOrErr;
+
+ // Run lib.exe
+ std::vector<const char *> vec;
+ vec.push_back(path.c_str());
+ for (int i = 2; i < argc; ++i)
+ vec.push_back(argv[i]);
+ vec.push_back(nullptr);
+
+ if (llvm::sys::ExecuteAndWait(path.c_str(), &vec[0]) != 0)
+ diag << "lib.exe failed\n";
+ return true;
+}
+
+/// \brief Parse the input file to lld::File.
+void addFiles(PECOFFLinkingContext &ctx, StringRef path, raw_ostream &diag,
+ std::vector<std::unique_ptr<File>> &files) {
+ for (std::unique_ptr<File> &file : loadFile(ctx, path, false)) {
+ if (ctx.logInputFiles())
+ diag << file->path() << "\n";
+ files.push_back(std::move(file));
+ }
+}
+
+//
+// Main driver
+//
+
+bool WinLinkDriver::linkPECOFF(int argc, const char **argv, raw_ostream &diag) {
+ if (maybeRunLibCommand(argc, argv, diag))
+ return true;
+
+ PECOFFLinkingContext ctx;
+ ctx.setParseDirectives(parseDirectives);
+ ctx.registry().addSupportCOFFObjects(ctx);
+ ctx.registry().addSupportCOFFImportLibraries(ctx);
+ ctx.registry().addSupportArchives(ctx.logInputFiles());
+ ctx.registry().addSupportNativeObjects();
+ ctx.registry().addSupportYamlFiles();
+
+ std::vector<const char *> newargv = processLinkEnv(ctx, argc, argv);
+ processLibEnv(ctx);
+ if (!parse(newargv.size() - 1, &newargv[0], ctx, diag))
+ return false;
+
+ // Create the file if needed.
+ if (ctx.getCreateManifest() && !ctx.getEmbedManifest())
+ if (!createSideBySideManifestFile(ctx, diag))
+ return false;
+
+ return link(ctx, diag);
+}
+
+bool WinLinkDriver::parse(int argc, const char *argv[],
+ PECOFFLinkingContext &ctx, raw_ostream &diag,
+ bool isReadingDirectiveSection) {
+ // Parse may be called from multiple threads simultaneously to parse .drectve
+ // sections. This function is not thread-safe because it mutates the context
+ // object. So acquire the lock.
+ std::lock_guard<std::recursive_mutex> lock(ctx.getMutex());
+
+ std::map<StringRef, StringRef> failIfMismatchMap;
+ // Parse the options.
+ std::unique_ptr<llvm::opt::InputArgList> parsedArgs =
+ parseArgs(argc, argv, ctx, diag, isReadingDirectiveSection);
+ if (!parsedArgs)
+ return false;
+
+ // The list of input files.
+ std::vector<std::unique_ptr<File>> files;
+ std::vector<std::unique_ptr<File>> libraries;
+
+ // Handle /help
+ if (parsedArgs->hasArg(OPT_help)) {
+ WinLinkOptTable table;
+ table.PrintHelp(llvm::outs(), argv[0], "LLVM Linker", false);
+ return false;
+ }
+
+ // Handle /machine before parsing all the other options, as the target machine
+ // type affects how to handle other options. For example, x86 needs the
+ // leading underscore to mangle symbols, while x64 doesn't need it.
+ if (llvm::opt::Arg *inputArg = parsedArgs->getLastArg(OPT_machine)) {
+ StringRef arg = inputArg->getValue();
+ llvm::COFF::MachineTypes type = stringToMachineType(arg);
+ if (type == llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN) {
+ diag << "error: unknown machine type: " << arg << "\n";
+ return false;
+ }
+ ctx.setMachineType(type);
+ } else {
+ // If /machine option is missing, we need to take a look at
+ // the magic byte of the first object file to infer machine type.
+ std::vector<StringRef> filePaths;
+ for (auto arg : *parsedArgs)
+ if (arg->getOption().getID() == OPT_INPUT)
+ filePaths.push_back(arg->getValue());
+ if (llvm::opt::Arg *arg = parsedArgs->getLastArg(OPT_DASH_DASH))
+ filePaths.insert(filePaths.end(), arg->getValues().begin(),
+ arg->getValues().end());
+ for (StringRef path : filePaths) {
+ llvm::COFF::MachineTypes type;
+ if (!getMachineType(path, type))
+ continue;
+ if (type == llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN)
+ continue;
+ ctx.setMachineType(type);
+ break;
+ }
+ }
+
+ // Handle /nodefaultlib:<lib>. The same option without argument is handled in
+ // the following for loop.
+ for (auto *arg : parsedArgs->filtered(OPT_nodefaultlib))
+ ctx.addNoDefaultLib(arg->getValue());
+
+ // Handle /defaultlib. Argument of the option is added to the input file list
+ // unless it's blacklisted by /nodefaultlib.
+ std::vector<StringRef> defaultLibs;
+ for (auto *arg : parsedArgs->filtered(OPT_defaultlib))
+ defaultLibs.push_back(arg->getValue());
+
+ // -alternatename:<alias>=<symbol>
+ for (auto *arg : parsedArgs->filtered(OPT_alternatename)) {
+ StringRef weak, def;
+ if (!parseAlternateName(arg->getValue(), weak, def, diag))
+ return false;
+ ctx.addAlternateName(weak, def);
+ }
+
+ // Parse /base command line option. The argument for the parameter is in
+ // the form of "<address>[:<size>]".
+ if (auto *arg = parsedArgs->getLastArg(OPT_base)) {
+ uint64_t addr, size;
+ // Size should be set to SizeOfImage field in the COFF header, and if
+ // it's smaller than the actual size, the linker should warn about that.
+ // Currently we just ignore the value of size parameter.
+ if (!parseMemoryOption(arg->getValue(), addr, size))
+ return false;
+ ctx.setBaseAddress(addr);
+ }
+
+ // Parse /dll command line option
+ if (parsedArgs->hasArg(OPT_dll)) {
+ ctx.setIsDll(true);
+ // Default base address of a DLL is 0x10000000.
+ if (!parsedArgs->hasArg(OPT_base))
+ ctx.setBaseAddress(0x10000000);
+ }
+
+ // Parse /stack command line option
+ if (auto *arg = parsedArgs->getLastArg(OPT_stack)) {
+ uint64_t reserve;
+ uint64_t commit = ctx.getStackCommit();
+ if (!parseMemoryOption(arg->getValue(), reserve, commit))
+ return false;
+ ctx.setStackReserve(reserve);
+ ctx.setStackCommit(commit);
+ }
+
+ // Parse /heap command line option
+ if (auto *arg = parsedArgs->getLastArg(OPT_heap)) {
+ uint64_t reserve;
+ uint64_t commit = ctx.getHeapCommit();
+ if (!parseMemoryOption(arg->getValue(), reserve, commit))
+ return false;
+ ctx.setHeapReserve(reserve);
+ ctx.setHeapCommit(commit);
+ }
+
+ if (auto *arg = parsedArgs->getLastArg(OPT_align)) {
+ uint32_t align;
+ StringRef val = arg->getValue();
+ if (val.getAsInteger(10, align)) {
+ diag << "error: invalid value for /align: " << val << "\n";
+ return false;
+ }
+ ctx.setSectionDefaultAlignment(align);
+ }
+
+ if (auto *arg = parsedArgs->getLastArg(OPT_version)) {
+ uint32_t major, minor;
+ if (!parseVersion(arg->getValue(), major, minor))
+ return false;
+ ctx.setImageVersion(PECOFFLinkingContext::Version(major, minor));
+ }
+
+ // Parse /merge:<from>=<to>.
+ for (auto *arg : parsedArgs->filtered(OPT_merge)) {
+ StringRef from, to;
+ std::tie(from, to) = StringRef(arg->getValue()).split('=');
+ if (from.empty() || to.empty()) {
+ diag << "error: malformed /merge option: " << arg->getValue() << "\n";
+ return false;
+ }
+ if (!ctx.addSectionRenaming(diag, from, to))
+ return false;
+ }
+
+ // Parse /subsystem:<subsystem>[,<majorOSVersion>[.<minorOSVersion>]].
+ if (auto *arg = parsedArgs->getLastArg(OPT_subsystem)) {
+ llvm::COFF::WindowsSubsystem subsystem;
+ llvm::Optional<uint32_t> major, minor;
+ if (!parseSubsystem(arg->getValue(), subsystem, major, minor, diag))
+ return false;
+ ctx.setSubsystem(subsystem);
+ if (major.hasValue())
+ ctx.setMinOSVersion(PECOFFLinkingContext::Version(*major, *minor));
+ }
+
+ // Parse /section:name,[[!]{DEKPRSW}]
+ for (auto *arg : parsedArgs->filtered(OPT_section)) {
+ std::string section;
+ llvm::Optional<uint32_t> flags, mask;
+ if (!parseSection(arg->getValue(), section, flags, mask)) {
+ diag << "Unknown argument for /section: " << arg->getValue() << "\n";
+ return false;
+ }
+ if (flags.hasValue())
+ ctx.setSectionSetMask(section, *flags);
+ if (mask.hasValue())
+ ctx.setSectionClearMask(section, *mask);
+ }
+
+ // Parse /manifest:EMBED[,ID=#]|NO.
+ if (auto *arg = parsedArgs->getLastArg(OPT_manifest_colon)) {
+ bool enable = true;
+ bool embed = false;
+ int id = 1;
+ if (!parseManifest(arg->getValue(), enable, embed, id)) {
+ diag << "Unknown argument for /manifest: " << arg->getValue() << "\n";
+ return false;
+ }
+ ctx.setCreateManifest(enable);
+ ctx.setEmbedManifest(embed);
+ ctx.setManifestId(id);
+ }
+
+ // Parse /manifestuac.
+ if (auto *arg = parsedArgs->getLastArg(OPT_manifestuac)) {
+ if (StringRef(arg->getValue()).equals_lower("no")) {
+ ctx.setManifestUAC(false);
+ } else {
+ llvm::Optional<std::string> privilegeLevel;
+ llvm::Optional<std::string> uiAccess;
+ if (!parseManifestUAC(arg->getValue(), privilegeLevel, uiAccess)) {
+ diag << "Unknown argument for /manifestuac: " << arg->getValue()
+ << "\n";
+ return false;
+ }
+ if (privilegeLevel.hasValue())
+ ctx.setManifestLevel(privilegeLevel.getValue());
+ if (uiAccess.hasValue())
+ ctx.setManifestUiAccess(uiAccess.getValue());
+ }
+ }
+
+ if (auto *arg = parsedArgs->getLastArg(OPT_manifestfile))
+ ctx.setManifestOutputPath(ctx.allocate(arg->getValue()));
+
+ // /manifestdependency:<string> option. Note that the argument will be
+ // embedded to the manifest XML file with no error check, for link.exe
+ // compatibility. We do not gurantete that the resulting XML file is
+ // valid.
+ if (auto *arg = parsedArgs->getLastArg(OPT_manifestdependency))
+ ctx.setManifestDependency(ctx.allocate(arg->getValue()));
+
+ for (auto *arg : parsedArgs->filtered(OPT_failifmismatch))
+ if (handleFailIfMismatchOption(arg->getValue(), failIfMismatchMap, diag))
+ return false;
+
+ if (auto *arg = parsedArgs->getLastArg(OPT_entry))
+ ctx.setEntrySymbolName(ctx.allocate(arg->getValue()));
+
+ for (auto *arg : parsedArgs->filtered(OPT_export)) {
+ PECOFFLinkingContext::ExportDesc desc;
+ if (!parseExport(arg->getValue(), desc)) {
+ diag << "Error: malformed /export option: " << arg->getValue() << "\n";
+ return false;
+ }
+
+ // Mangle the symbol name only if it is reading user-supplied command line
+ // arguments. Because the symbol name in the .drectve section is already
+ // mangled by the compiler, we shouldn't add a leading underscore in that
+ // case. It's odd that the command line option has different semantics in
+ // the .drectve section, but this behavior is needed for compatibility
+ // with MSVC's link.exe.
+ if (!isReadingDirectiveSection)
+ desc.name = ctx.decorateSymbol(desc.name);
+ ctx.addDllExport(desc);
+ }
+
+ for (auto *arg : parsedArgs->filtered(OPT_deffile)) {
+ llvm::BumpPtrAllocator alloc;
+ std::vector<moduledef::Directive *> dirs;
+ if (!parseDef(arg->getValue(), alloc, dirs)) {
+ diag << "Error: invalid module-definition file\n";
+ return false;
+ }
+ for (moduledef::Directive *dir : dirs) {
+ if (auto *exp = dyn_cast<moduledef::Exports>(dir)) {
+ for (PECOFFLinkingContext::ExportDesc desc : exp->getExports()) {
+ desc.name = ctx.decorateSymbol(desc.name);
+ ctx.addDllExport(desc);
+ }
+ } else if (auto *hs = dyn_cast<moduledef::Heapsize>(dir)) {
+ ctx.setHeapReserve(hs->getReserve());
+ ctx.setHeapCommit(hs->getCommit());
+ } else if (auto *lib = dyn_cast<moduledef::Library>(dir)) {
+ ctx.setIsDll(true);
+ ctx.setOutputPath(ctx.allocate(lib->getName()));
+ if (lib->getBaseAddress() && !ctx.getBaseAddress())
+ ctx.setBaseAddress(lib->getBaseAddress());
+ } else if (auto *name = dyn_cast<moduledef::Name>(dir)) {
+ if (!name->getOutputPath().empty() && ctx.outputPath().empty())
+ ctx.setOutputPath(ctx.allocate(name->getOutputPath()));
+ if (name->getBaseAddress() && ctx.getBaseAddress())
+ ctx.setBaseAddress(name->getBaseAddress());
+ } else if (auto *ver = dyn_cast<moduledef::Version>(dir)) {
+ ctx.setImageVersion(PECOFFLinkingContext::Version(
+ ver->getMajorVersion(), ver->getMinorVersion()));
+ } else {
+ llvm::dbgs() << static_cast<int>(dir->getKind()) << "\n";
+ llvm_unreachable("Unknown module-definition directive.\n");
+ }
+ }
+ }
+
+ for (auto *arg : parsedArgs->filtered(OPT_libpath))
+ ctx.appendInputSearchPath(ctx.allocate(arg->getValue()));
+
+ for (auto *arg : parsedArgs->filtered(OPT_opt)) {
+ std::string val = StringRef(arg->getValue()).lower();
+ if (val == "noref") {
+ ctx.setDeadStripping(false);
+ } else if (val != "ref" && val != "icf" && val != "noicf" &&
+ val != "lbr" && val != "nolbr" &&
+ !StringRef(val).startswith("icf=")) {
+ diag << "unknown option for /opt: " << val << "\n";
+ return false;
+ }
+ }
+
+ // LLD is not yet capable of creating a PDB file, so /debug does not have
+ // any effect.
+ // TODO: This should disable dead stripping. Currently we can't do that
+ // because removal of associative sections depends on dead stripping.
+ if (parsedArgs->hasArg(OPT_debug))
+ ctx.setDebug(true);
+
+ if (parsedArgs->hasArg(OPT_verbose))
+ ctx.setLogInputFiles(true);
+
+ // /force and /force:unresolved mean the same thing. We do not currently
+ // support /force:multiple.
+ if (parsedArgs->hasArg(OPT_force) ||
+ parsedArgs->hasArg(OPT_force_unresolved)) {
+ ctx.setAllowRemainingUndefines(true);
+ }
+
+ if (parsedArgs->hasArg(OPT_fixed)) {
+ // /fixed is not compatible with /dynamicbase. Check for it.
+ if (parsedArgs->hasArg(OPT_dynamicbase)) {
+ diag << "/dynamicbase must not be specified with /fixed\n";
+ return false;
+ }
+ ctx.setBaseRelocationEnabled(false);
+ ctx.setDynamicBaseEnabled(false);
+ }
+
+ // /swaprun:{cd,net} options set IMAGE_FILE_{REMOVABLE,NET}_RUN_FROM_SWAP
+ // bits in the COFF header, respectively. If one of the bits is on, the
+ // Windows loader will copy the entire file to swap area then execute it,
+ // so that the user can eject a CD or disconnect from the network.
+ if (parsedArgs->hasArg(OPT_swaprun_cd))
+ ctx.setSwapRunFromCD(true);
+
+ if (parsedArgs->hasArg(OPT_swaprun_net))
+ ctx.setSwapRunFromNet(true);
+
+ if (parsedArgs->hasArg(OPT_profile)) {
+ // /profile implies /opt:ref, /opt:noicf, /incremental:no and /fixed:no.
+ ctx.setDeadStripping(true);
+ ctx.setBaseRelocationEnabled(true);
+ ctx.setDynamicBaseEnabled(true);
+ }
+
+ for (auto *arg : parsedArgs->filtered(OPT_implib))
+ ctx.setOutputImportLibraryPath(arg->getValue());
+
+ for (auto *arg : parsedArgs->filtered(OPT_delayload)) {
+ ctx.addInitialUndefinedSymbol(ctx.getDelayLoadHelperName());
+ ctx.addDelayLoadDLL(arg->getValue());
+ }
+
+ if (auto *arg = parsedArgs->getLastArg(OPT_stub)) {
+ ArrayRef<uint8_t> contents;
+ if (!readFile(ctx, arg->getValue(), contents)) {
+ diag << "Failed to read DOS stub file " << arg->getValue() << "\n";
+ return false;
+ }
+ ctx.setDosStub(contents);
+ }
+
+ for (auto *arg : parsedArgs->filtered(OPT_incl))
+ ctx.addInitialUndefinedSymbol(ctx.allocate(arg->getValue()));
+
+ if (parsedArgs->hasArg(OPT_noentry))
+ ctx.setHasEntry(false);
+
+ if (parsedArgs->hasArg(OPT_nodefaultlib_all))
+ ctx.setNoDefaultLibAll(true);
+
+ if (auto *arg = parsedArgs->getLastArg(OPT_out))
+ ctx.setOutputPath(ctx.allocate(arg->getValue()));
+
+ if (auto *arg = parsedArgs->getLastArg(OPT_pdb))
+ ctx.setPDBFilePath(arg->getValue());
+
+ if (auto *arg = parsedArgs->getLastArg(OPT_lldmoduledeffile))
+ ctx.setModuleDefinitionFile(arg->getValue());
+
+ std::vector<StringRef> inputFiles;
+ for (auto *arg : parsedArgs->filtered(OPT_INPUT))
+ inputFiles.push_back(ctx.allocate(arg->getValue()));
+
+#define BOOLEAN_FLAG(name, setter) \
+ if (auto *arg = parsedArgs->getLastArg(OPT_##name, OPT_##name##_no)) \
+ ctx.setter(arg->getOption().matches(OPT_##name));
+
+ BOOLEAN_FLAG(nxcompat, setNxCompat);
+ BOOLEAN_FLAG(largeaddressaware, setLargeAddressAware);
+ BOOLEAN_FLAG(allowbind, setAllowBind);
+ BOOLEAN_FLAG(allowisolation, setAllowIsolation);
+ BOOLEAN_FLAG(dynamicbase, setDynamicBaseEnabled);
+ BOOLEAN_FLAG(tsaware, setTerminalServerAware);
+ BOOLEAN_FLAG(highentropyva, setHighEntropyVA);
+ BOOLEAN_FLAG(safeseh, setSafeSEH);
+#undef BOOLEAN_FLAG
+
+ // Arguments after "--" are interpreted as filenames even if they
+ // start with a hypen or a slash. This is not compatible with link.exe
+ // but useful for us to test lld on Unix.
+ if (llvm::opt::Arg *dashdash = parsedArgs->getLastArg(OPT_DASH_DASH))
+ for (const StringRef value : dashdash->getValues())
+ inputFiles.push_back(value);
+
+ // Compile Windows resource files to compiled resource file.
+ if (ctx.getCreateManifest() && ctx.getEmbedManifest() &&
+ !isReadingDirectiveSection) {
+ std::string resFile;
+ if (!createManifestResourceFile(ctx, diag, resFile))
+ return false;
+ inputFiles.push_back(ctx.allocate(resFile));
+ }
+
+ // A Windows Resource file is not an object file. It contains data,
+ // such as an icon image, and is not in COFF file format. If resource
+ // files are given, the linker merge them into one COFF file using
+ // CVTRES.EXE and then link the resulting file.
+ {
+ auto it = std::partition(inputFiles.begin(), inputFiles.end(),
+ isResoruceFile);
+ if (it != inputFiles.begin()) {
+ std::vector<std::string> resFiles(inputFiles.begin(), it);
+ std::string resObj;
+ if (!convertResourceFiles(ctx, resFiles, resObj)) {
+ diag << "Failed to convert resource files\n";
+ return false;
+ }
+ inputFiles = std::vector<StringRef>(it, inputFiles.end());
+ inputFiles.push_back(ctx.allocate(resObj));
+ ctx.registerTemporaryFile(resObj);
+ }
+ }
+
+ // Prepare objects to add them to the list of input files.
+ for (StringRef path : inputFiles) {
+ path = ctx.allocate(path);
+ if (isLibraryFile(path)) {
+ addFiles(ctx, getLibraryPath(ctx, path), diag, libraries);
+ } else {
+ addFiles(ctx, getObjectPath(ctx, path), diag, files);
+ }
+ }
+
+ // If dead-stripping is enabled, we need to add the entry symbol and
+ // symbols given by /include to the dead strip root set, so that it
+ // won't be removed from the output.
+ if (ctx.deadStrip())
+ for (const StringRef symbolName : ctx.initialUndefinedSymbols())
+ ctx.addDeadStripRoot(symbolName);
+
+ // Add the libraries specified by /defaultlib unless they are already added
+ // nor blacklisted by /nodefaultlib.
+ if (!ctx.getNoDefaultLibAll())
+ for (const StringRef path : defaultLibs)
+ if (!ctx.hasNoDefaultLib(path))
+ addFiles(ctx, getLibraryPath(ctx, path.lower()), diag, libraries);
+
+ if (files.empty() && !isReadingDirectiveSection) {
+ diag << "No input files\n";
+ return false;
+ }
+
+ // If /out option was not specified, the default output file name is
+ // constructed by replacing an extension of the first input file
+ // with ".exe".
+ if (ctx.outputPath().empty()) {
+ StringRef path = files[0]->path();
+ ctx.setOutputPath(replaceExtension(ctx, path, ".exe"));
+ }
+
+ // Add the input files to the linking context.
+ for (std::unique_ptr<File> &file : files) {
+ if (isReadingDirectiveSection) {
+ File *f = file.get();
+ ctx.getTaskGroup().spawn([f] { f->parse(); });
+ }
+ ctx.getNodes().push_back(llvm::make_unique<FileNode>(std::move(file)));
+ }
+
+ // Add the library group to the linking context.
+ if (!isReadingDirectiveSection) {
+ // Add a group-end marker.
+ ctx.getNodes().push_back(llvm::make_unique<GroupEnd>(0));
+ }
+
+ // Add the library files to the library group.
+ for (std::unique_ptr<File> &file : libraries) {
+ if (!hasLibrary(ctx, file.get())) {
+ if (isReadingDirectiveSection) {
+ File *f = file.get();
+ ctx.getTaskGroup().spawn([f] { f->parse(); });
+ }
+ ctx.addLibraryFile(llvm::make_unique<FileNode>(std::move(file)));
+ }
+ }
+
+ // Validate the combination of options used.
+ return ctx.validate(diag);
+}
+
+} // namespace lld
diff --git a/lib/Driver/WinLinkModuleDef.cpp b/lib/Driver/WinLinkModuleDef.cpp
new file mode 100644
index 000000000000..e55a0bc5fe64
--- /dev/null
+++ b/lib/Driver/WinLinkModuleDef.cpp
@@ -0,0 +1,295 @@
+//===- lib/Driver/WinLinkModuleDef.cpp ------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Windows module definition file parser.
+///
+//===----------------------------------------------------------------------===//
+
+#include "lld/Driver/WinLinkModuleDef.h"
+#include "llvm/ADT/StringSwitch.h"
+
+namespace lld {
+namespace moduledef {
+
+Token Lexer::lex() {
+ for (;;) {
+ _buffer = _buffer.trim();
+ if (_buffer.empty() || _buffer[0] == '\0')
+ return Token(Kind::eof, _buffer);
+
+ switch (_buffer[0]) {
+ case ';': {
+ size_t end = _buffer.find('\n');
+ _buffer = (end == _buffer.npos) ? "" : _buffer.drop_front(end);
+ continue;
+ }
+ case '=':
+ _buffer = _buffer.drop_front();
+ return Token(Kind::equal, "=");
+ case ',':
+ _buffer = _buffer.drop_front();
+ return Token(Kind::comma, ",");
+ case '"': {
+ size_t end = _buffer.find('"', 1);
+ Token ret;
+ if (end == _buffer.npos) {
+ ret = Token(Kind::identifier, _buffer.substr(1, end));
+ _buffer = "";
+ } else {
+ ret = Token(Kind::identifier, _buffer.substr(1, end - 1));
+ _buffer = _buffer.drop_front(end + 1);
+ }
+ return ret;
+ }
+ default: {
+ size_t end = _buffer.find_first_not_of(
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "0123456789_.*~+!@#$%^&*()/");
+ StringRef word = _buffer.substr(0, end);
+ Kind kind = llvm::StringSwitch<Kind>(word)
+ .Case("BASE", Kind::kw_base)
+ .Case("DATA", Kind::kw_data)
+ .Case("EXPORTS", Kind::kw_exports)
+ .Case("HEAPSIZE", Kind::kw_heapsize)
+ .Case("LIBRARY", Kind::kw_library)
+ .Case("NAME", Kind::kw_name)
+ .Case("NONAME", Kind::kw_noname)
+ .Case("PRIVATE", Kind::kw_private)
+ .Case("STACKSIZE", Kind::kw_stacksize)
+ .Case("VERSION", Kind::kw_version)
+ .Default(Kind::identifier);
+ _buffer = (end == _buffer.npos) ? "" : _buffer.drop_front(end);
+ return Token(kind, word);
+ }
+ }
+ }
+}
+
+void Parser::consumeToken() {
+ if (_tokBuf.empty()) {
+ _tok = _lex.lex();
+ return;
+ }
+ _tok = _tokBuf.back();
+ _tokBuf.pop_back();
+}
+
+bool Parser::consumeTokenAsInt(uint64_t &result) {
+ consumeToken();
+ if (_tok._kind != Kind::identifier) {
+ ungetToken();
+ error(_tok, "Integer expected");
+ return false;
+ }
+ if (_tok._range.getAsInteger(10, result)) {
+ error(_tok, "Integer expected");
+ return false;
+ }
+ return true;
+}
+
+bool Parser::expectAndConsume(Kind kind, Twine msg) {
+ consumeToken();
+ if (_tok._kind != kind) {
+ error(_tok, msg);
+ return false;
+ }
+ return true;
+}
+
+void Parser::ungetToken() { _tokBuf.push_back(_tok); }
+
+void Parser::error(const Token &tok, Twine msg) {
+ _lex.getSourceMgr().PrintMessage(
+ llvm::SMLoc::getFromPointer(tok._range.data()), llvm::SourceMgr::DK_Error,
+ msg);
+}
+
+bool Parser::parse(std::vector<Directive *> &ret) {
+ for (;;) {
+ Directive *dir = nullptr;
+ if (!parseOne(dir))
+ return false;
+ if (!dir)
+ return true;
+ ret.push_back(dir);
+ }
+}
+
+bool Parser::parseOne(Directive *&ret) {
+ consumeToken();
+ switch (_tok._kind) {
+ case Kind::eof:
+ return true;
+ case Kind::kw_exports: {
+ // EXPORTS
+ std::vector<PECOFFLinkingContext::ExportDesc> exports;
+ for (;;) {
+ PECOFFLinkingContext::ExportDesc desc;
+ if (!parseExport(desc))
+ break;
+ exports.push_back(desc);
+ }
+ ret = new (_alloc) Exports(exports);
+ return true;
+ }
+ case Kind::kw_heapsize: {
+ // HEAPSIZE
+ uint64_t reserve, commit;
+ if (!parseMemorySize(reserve, commit))
+ return false;
+ ret = new (_alloc) Heapsize(reserve, commit);
+ return true;
+ }
+ case Kind::kw_library: {
+ // LIBRARY
+ std::string name;
+ uint64_t baseaddr;
+ if (!parseName(name, baseaddr))
+ return false;
+ if (!StringRef(name).endswith_lower(".dll"))
+ name.append(".dll");
+ ret = new (_alloc) Library(name, baseaddr);
+ return true;
+ }
+ case Kind::kw_stacksize: {
+ // STACKSIZE
+ uint64_t reserve, commit;
+ if (!parseMemorySize(reserve, commit))
+ return false;
+ ret = new (_alloc) Stacksize(reserve, commit);
+ return true;
+ }
+ case Kind::kw_name: {
+ // NAME
+ std::string outputPath;
+ uint64_t baseaddr;
+ if (!parseName(outputPath, baseaddr))
+ return false;
+ ret = new (_alloc) Name(outputPath, baseaddr);
+ return true;
+ }
+ case Kind::kw_version: {
+ // VERSION
+ int major, minor;
+ if (!parseVersion(major, minor))
+ return false;
+ ret = new (_alloc) Version(major, minor);
+ return true;
+ }
+ default:
+ error(_tok, Twine("Unknown directive: ") + _tok._range);
+ return false;
+ }
+}
+
+bool Parser::parseExport(PECOFFLinkingContext::ExportDesc &result) {
+ consumeToken();
+ if (_tok._kind != Kind::identifier) {
+ ungetToken();
+ return false;
+ }
+ result.name = _tok._range;
+
+ consumeToken();
+ if (_tok._kind == Kind::equal) {
+ consumeToken();
+ if (_tok._kind != Kind::identifier)
+ return false;
+ result.externalName = result.name;
+ result.name = _tok._range;
+ } else {
+ ungetToken();
+ }
+
+ for (;;) {
+ consumeToken();
+ if (_tok._kind == Kind::identifier && _tok._range[0] == '@') {
+ _tok._range.drop_front().getAsInteger(10, result.ordinal);
+ consumeToken();
+ if (_tok._kind == Kind::kw_noname) {
+ result.noname = true;
+ } else {
+ ungetToken();
+ }
+ continue;
+ }
+ if (_tok._kind == Kind::kw_data) {
+ result.isData = true;
+ continue;
+ }
+ if (_tok._kind == Kind::kw_private) {
+ result.isPrivate = true;
+ continue;
+ }
+ ungetToken();
+ return true;
+ }
+}
+
+// HEAPSIZE/STACKSIZE reserve[,commit]
+bool Parser::parseMemorySize(uint64_t &reserve, uint64_t &commit) {
+ if (!consumeTokenAsInt(reserve))
+ return false;
+
+ consumeToken();
+ if (_tok._kind != Kind::comma) {
+ ungetToken();
+ commit = 0;
+ return true;
+ }
+
+ if (!consumeTokenAsInt(commit))
+ return false;
+ return true;
+}
+
+// NAME [outputPath] [BASE=address]
+bool Parser::parseName(std::string &outputPath, uint64_t &baseaddr) {
+ consumeToken();
+ if (_tok._kind == Kind::identifier) {
+ outputPath = _tok._range;
+ } else {
+ outputPath = "";
+ ungetToken();
+ return true;
+ }
+ consumeToken();
+ if (_tok._kind == Kind::kw_base) {
+ if (!expectAndConsume(Kind::equal, "'=' expected"))
+ return false;
+ if (!consumeTokenAsInt(baseaddr))
+ return false;
+ } else {
+ ungetToken();
+ baseaddr = 0;
+ }
+ return true;
+}
+
+// VERSION major[.minor]
+bool Parser::parseVersion(int &major, int &minor) {
+ consumeToken();
+ if (_tok._kind != Kind::identifier)
+ return false;
+ StringRef v1, v2;
+ std::tie(v1, v2) = _tok._range.split('.');
+ if (v1.getAsInteger(10, major))
+ return false;
+ if (v2.empty()) {
+ minor = 0;
+ } else if (v2.getAsInteger(10, minor)) {
+ return false;
+ }
+ return true;
+}
+
+} // moddef
+} // namespace lld
diff --git a/lib/Driver/WinLinkOptions.td b/lib/Driver/WinLinkOptions.td
new file mode 100644
index 000000000000..a545639b5bb2
--- /dev/null
+++ b/lib/Driver/WinLinkOptions.td
@@ -0,0 +1,120 @@
+include "llvm/Option/OptParser.td"
+
+// link.exe accepts options starting with either a dash or a slash.
+
+// Flag that takes no arguments.
+class F<string name> : Flag<["/", "-", "-?"], name>;
+
+// Flag that takes one argument after ":".
+class P<string name, string help> :
+ Joined<["/", "-", "-?"], name#":">, HelpText<help>;
+
+// Boolean flag suffixed by ":no".
+multiclass B<string name, string help> {
+ def "" : F<name>;
+ def _no : F<name#":no">, HelpText<help>;
+}
+
+def alternatename : P<"alternatename", "Define weak alias">;
+def base : P<"base", "Base address of the program">;
+def defaultlib : P<"defaultlib", "Add the library to the list of input files">;
+def nodefaultlib : P<"nodefaultlib", "Remove a default library">;
+def disallowlib : Joined<["/", "-", "-?"], "disallowlib:">, Alias<nodefaultlib>;
+def entry : P<"entry", "Name of entry point symbol">;
+// No help text because /failifmismatch is not intended to be used by the user.
+def export : P<"export", "Export a function">;
+def failifmismatch : P<"failifmismatch", "">;
+def heap : P<"heap", "Size of the heap">;
+def align : P<"align", "Section alignment">;
+def libpath : P<"libpath", "Additional library search path">;
+def mllvm : P<"mllvm", "Options to pass to LLVM">;
+def out : P<"out", "Path to file to write output">;
+def stack : P<"stack", "Size of the stack">;
+def machine : P<"machine", "Specify target platform">;
+def version : P<"version", "Specify a version number in the PE header">;
+def merge : P<"merge", "Combine sections">;
+def section : P<"section", "Specify section attributes">;
+def subsystem : P<"subsystem", "Specify subsystem">;
+def stub : P<"stub", "Specify DOS stub file">;
+def opt : P<"opt", "Control optimizations">;
+def implib : P<"implib", "Import library name">;
+def delayload : P<"delayload", "Delay loaded DLL name">;
+def pdb : P<"pdb", "PDB file path">;
+
+def manifest : F<"manifest">;
+def manifest_colon : P<"manifest", "Create manifest file">;
+def manifestuac : P<"manifestuac", "User access control">;
+def manifestfile : P<"manifestfile", "Manifest file path">;
+def manifestdependency : P<"manifestdependency",
+ "Attributes for <dependency> in manifest file">;
+
+// We cannot use multiclass P because class name "incl" is different
+// from its command line option name. We do this because "include" is
+// a reserved keyword in tablegen.
+def incl : Joined<["/", "-"], "include:">,
+ HelpText<"Force symbol to be added to symbol table as undefined one">;
+
+// "def" is also a keyword.
+def deffile : Joined<["/", "-"], "def:">,
+ HelpText<"Use module-definition file">;
+
+def nodefaultlib_all : F<"nodefaultlib">;
+def noentry : F<"noentry">;
+def dll : F<"dll">;
+def verbose : F<"verbose">;
+def debug : F<"debug">;
+def swaprun_cd : F<"swaprun:cd">;
+def swaprun_net : F<"swaprun:net">;
+def profile : F<"profile">;
+
+def force : F<"force">,
+ HelpText<"Allow undefined symbols when creating executables">;
+def force_unresolved : F<"force:unresolved">;
+
+defm nxcompat : B<"nxcompat", "Disable data execution provention">;
+defm largeaddressaware : B<"largeaddressaware", "Disable large addresses">;
+defm allowbind: B<"allowbind", "Disable DLL binding">;
+defm fixed : B<"fixed", "Enable base relocations">;
+defm tsaware : B<"tsaware", "Create non-Terminal Server aware executable">;
+defm allowisolation : B<"allowisolation", "Set NO_ISOLATION bit">;
+defm dynamicbase : B<"dynamicbase",
+ "Disable address space layout randomization">;
+defm safeseh : B<"safeseh", "Produce an image with Safe Exception Handler">;
+defm highentropyva : B<"highentropyva", "Set HIGH_ENTROPY_VA bit">;
+
+def help : F<"help">;
+def help_q : Flag<["/?", "-?"], "">, Alias<help>;
+
+def DASH_DASH : Option<["--"], "", KIND_REMAINING_ARGS>;
+
+// Flag for debug
+def lldmoduledeffile : Joined<["/", "-"], "lldmoduledeffile:">;
+
+//==============================================================================
+// The flags below do nothing. They are defined only for link.exe compatibility.
+//==============================================================================
+
+class QF<string name> : Joined<["/", "-", "-?"], name#":">;
+
+multiclass QB<string name> {
+ def "" : F<name>;
+ def _no : F<name#":no">;
+}
+
+def functionpadmin : F<"functionpadmin">;
+def ignoreidl : F<"ignoreidl">;
+def incremental : F<"incremental">;
+def no_incremental : F<"incremental:no">;
+def nologo : F<"nologo">;
+
+def delay : QF<"delay">;
+def errorreport : QF<"errorreport">;
+def idlout : QF<"idlout">;
+def ignore : QF<"ignore">;
+def maxilksize : QF<"maxilksize">;
+def pdbaltpath : QF<"pdbaltpath">;
+def tlbid : QF<"tlbid">;
+def tlbout : QF<"tlbout">;
+def verbose_all : QF<"verbose">;
+
+defm wx : QB<"wx">;
diff --git a/lib/Makefile b/lib/Makefile
new file mode 100644
index 000000000000..83112eaf972a
--- /dev/null
+++ b/lib/Makefile
@@ -0,0 +1,16 @@
+##===- lib/Makefile ----------------------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+LLD_LEVEL := ..
+
+# ARCMigrate and Rewrite are always needed because of libclang.
+PARALLEL_DIRS = Config Core Driver ReaderWriter
+
+include $(LLD_LEVEL)/../../Makefile.config
+
+include $(LLD_LEVEL)/Makefile
diff --git a/lib/ReaderWriter/CMakeLists.txt b/lib/ReaderWriter/CMakeLists.txt
new file mode 100644
index 000000000000..1fd19eb73a75
--- /dev/null
+++ b/lib/ReaderWriter/CMakeLists.txt
@@ -0,0 +1,20 @@
+add_subdirectory(ELF)
+add_subdirectory(MachO)
+add_subdirectory(Native)
+add_subdirectory(PECOFF)
+add_subdirectory(YAML)
+
+if (MSVC)
+ add_definitions(-wd4062) # Suppress 'warning C4062: Enumerator has no associated handler in a switch statement.'
+endif()
+
+add_llvm_library(lldReaderWriter
+ CoreLinkingContext.cpp
+ FileArchive.cpp
+ LinkerScript.cpp
+ LINK_LIBS
+ lldCore
+ lldYAML
+ LLVMObject
+ LLVMSupport
+ )
diff --git a/lib/ReaderWriter/CoreLinkingContext.cpp b/lib/ReaderWriter/CoreLinkingContext.cpp
new file mode 100644
index 000000000000..86fad4f6e77d
--- /dev/null
+++ b/lib/ReaderWriter/CoreLinkingContext.cpp
@@ -0,0 +1,171 @@
+//===- lib/ReaderWriter/CoreLinkingContext.cpp ----------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Pass.h"
+#include "lld/Core/PassManager.h"
+#include "lld/Core/Simple.h"
+#include "lld/ReaderWriter/CoreLinkingContext.h"
+#include "llvm/ADT/ArrayRef.h"
+
+using namespace lld;
+
+namespace {
+
+/// \brief Simple atom created by the stubs pass.
+class TestingStubAtom : public DefinedAtom {
+public:
+ TestingStubAtom(const File &F, const Atom &) : _file(F) {
+ static uint32_t lastOrdinal = 0;
+ _ordinal = lastOrdinal++;
+ }
+
+ const File &file() const override { return _file; }
+
+ StringRef name() const override { return StringRef(); }
+
+ uint64_t ordinal() const override { return _ordinal; }
+
+ uint64_t size() const override { return 0; }
+
+ Scope scope() const override { return DefinedAtom::scopeLinkageUnit; }
+
+ Interposable interposable() const override { return DefinedAtom::interposeNo; }
+
+ Merge merge() const override { return DefinedAtom::mergeNo; }
+
+ ContentType contentType() const override { return DefinedAtom::typeStub; }
+
+ Alignment alignment() const override { return Alignment(0, 0); }
+
+ SectionChoice sectionChoice() const override {
+ return DefinedAtom::sectionBasedOnContent;
+ }
+
+ StringRef customSectionName() const override { return StringRef(); }
+
+ DeadStripKind deadStrip() const override {
+ return DefinedAtom::deadStripNormal;
+ }
+
+ ContentPermissions permissions() const override {
+ return DefinedAtom::permR_X;
+ }
+
+ ArrayRef<uint8_t> rawContent() const override { return ArrayRef<uint8_t>(); }
+
+ reference_iterator begin() const override {
+ return reference_iterator(*this, nullptr);
+ }
+
+ reference_iterator end() const override {
+ return reference_iterator(*this, nullptr);
+ }
+
+ const Reference *derefIterator(const void *iter) const override {
+ return nullptr;
+ }
+
+ void incrementIterator(const void *&iter) const override {}
+
+private:
+ const File &_file;
+ uint32_t _ordinal;
+};
+
+/// \brief Simple atom created by the GOT pass.
+class TestingGOTAtom : public DefinedAtom {
+public:
+ TestingGOTAtom(const File &F, const Atom &) : _file(F) {
+ static uint32_t lastOrdinal = 0;
+ _ordinal = lastOrdinal++;
+ }
+
+ const File &file() const override { return _file; }
+
+ StringRef name() const override { return StringRef(); }
+
+ uint64_t ordinal() const override { return _ordinal; }
+
+ uint64_t size() const override { return 0; }
+
+ Scope scope() const override { return DefinedAtom::scopeLinkageUnit; }
+
+ Interposable interposable() const override { return DefinedAtom::interposeNo; }
+
+ Merge merge() const override { return DefinedAtom::mergeNo; }
+
+ ContentType contentType() const override { return DefinedAtom::typeGOT; }
+
+ Alignment alignment() const override { return Alignment(3, 0); }
+
+ SectionChoice sectionChoice() const override {
+ return DefinedAtom::sectionBasedOnContent;
+ }
+
+ StringRef customSectionName() const override { return StringRef(); }
+
+ DeadStripKind deadStrip() const override {
+ return DefinedAtom::deadStripNormal;
+ }
+
+ ContentPermissions permissions() const override {
+ return DefinedAtom::permRW_;
+ }
+
+ ArrayRef<uint8_t> rawContent() const override { return ArrayRef<uint8_t>(); }
+
+ reference_iterator begin() const override {
+ return reference_iterator(*this, nullptr);
+ }
+
+ reference_iterator end() const override {
+ return reference_iterator(*this, nullptr);
+ }
+
+ const Reference *derefIterator(const void *iter) const override {
+ return nullptr;
+ }
+
+ void incrementIterator(const void *&iter) const override {}
+
+private:
+ const File &_file;
+ uint32_t _ordinal;
+};
+
+class OrderPass : public Pass {
+public:
+ /// Sorts atoms by position
+ void perform(std::unique_ptr<MutableFile> &file) override {
+ MutableFile::DefinedAtomRange defined = file->definedAtoms();
+ std::sort(defined.begin(), defined.end(), DefinedAtom::compareByPosition);
+ }
+};
+
+} // anonymous namespace
+
+CoreLinkingContext::CoreLinkingContext() {}
+
+bool CoreLinkingContext::validateImpl(raw_ostream &) {
+ _writer = createWriterYAML(*this);
+ return true;
+}
+
+void CoreLinkingContext::addPasses(PassManager &pm) {
+ for (StringRef name : _passNames) {
+ if (name.equals("order"))
+ pm.add(std::unique_ptr<Pass>(new OrderPass()));
+ else
+ llvm_unreachable("bad pass name");
+ }
+}
+
+Writer &CoreLinkingContext::writer() const { return *_writer; }
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64DynamicLibraryWriter.h b/lib/ReaderWriter/ELF/AArch64/AArch64DynamicLibraryWriter.h
new file mode 100644
index 000000000000..12ba52a38f38
--- /dev/null
+++ b/lib/ReaderWriter/ELF/AArch64/AArch64DynamicLibraryWriter.h
@@ -0,0 +1,69 @@
+//===- lib/ReaderWriter/ELF/AArch64/AArch64DynamicLibraryWriter.h ---------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef AARCH64_DYNAMIC_LIBRARY_WRITER_H
+#define AARCH64_DYNAMIC_LIBRARY_WRITER_H
+
+#include "AArch64LinkingContext.h"
+#include "AArch64TargetHandler.h"
+#include "DynamicLibraryWriter.h"
+
+namespace lld {
+namespace elf {
+
+template <class ELFT>
+class AArch64DynamicLibraryWriter : public DynamicLibraryWriter<ELFT> {
+public:
+ AArch64DynamicLibraryWriter(AArch64LinkingContext &context,
+ AArch64TargetLayout<ELFT> &layout);
+
+protected:
+ // Add any runtime files and their atoms to the output
+ virtual bool createImplicitFiles(std::vector<std::unique_ptr<File>> &);
+
+ virtual void finalizeDefaultAtomValues() {
+ return DynamicLibraryWriter<ELFT>::finalizeDefaultAtomValues();
+ }
+
+ virtual void addDefaultAtoms() {
+ return DynamicLibraryWriter<ELFT>::addDefaultAtoms();
+ }
+
+private:
+ class GOTFile : public SimpleFile {
+ public:
+ GOTFile(const ELFLinkingContext &eti) : SimpleFile("GOTFile") {}
+ llvm::BumpPtrAllocator _alloc;
+ };
+
+ std::unique_ptr<GOTFile> _gotFile;
+ AArch64LinkingContext &_context;
+ AArch64TargetLayout<ELFT> &_AArch64Layout;
+};
+
+template <class ELFT>
+AArch64DynamicLibraryWriter<ELFT>::AArch64DynamicLibraryWriter(
+ AArch64LinkingContext &context, AArch64TargetLayout<ELFT> &layout)
+ : DynamicLibraryWriter<ELFT>(context, layout),
+ _gotFile(new GOTFile(context)), _context(context),
+ _AArch64Layout(layout) {}
+
+template <class ELFT>
+bool AArch64DynamicLibraryWriter<ELFT>::createImplicitFiles(
+ std::vector<std::unique_ptr<File>> &result) {
+ DynamicLibraryWriter<ELFT>::createImplicitFiles(result);
+ _gotFile->addAtom(*new (_gotFile->_alloc) GLOBAL_OFFSET_TABLEAtom(*_gotFile));
+ _gotFile->addAtom(*new (_gotFile->_alloc) DYNAMICAtom(*_gotFile));
+ result.push_back(std::move(_gotFile));
+ return true;
+}
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64ELFFile.h b/lib/ReaderWriter/ELF/AArch64/AArch64ELFFile.h
new file mode 100644
index 000000000000..9d5207c1c4b4
--- /dev/null
+++ b/lib/ReaderWriter/ELF/AArch64/AArch64ELFFile.h
@@ -0,0 +1,41 @@
+//===- lib/ReaderWriter/ELF/AArch64/AArch64ELFFile.h ----------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_AARCH64_AARCH64_ELF_FILE_H
+#define LLD_READER_WRITER_ELF_AARCH64_AARCH64_ELF_FILE_H
+
+#include "ELFReader.h"
+
+namespace lld {
+namespace elf {
+
+class AArch64LinkingContext;
+
+template <class ELFT> class AArch64ELFFile : public ELFFile<ELFT> {
+public:
+ AArch64ELFFile(std::unique_ptr<MemoryBuffer> mb, AArch64LinkingContext &ctx)
+ : ELFFile<ELFT>(std::move(mb), ctx) {}
+
+ static ErrorOr<std::unique_ptr<AArch64ELFFile>>
+ create(std::unique_ptr<MemoryBuffer> mb, AArch64LinkingContext &ctx) {
+ return std::unique_ptr<AArch64ELFFile<ELFT>>(
+ new AArch64ELFFile<ELFT>(std::move(mb), ctx));
+ }
+};
+
+template <class ELFT> class AArch64DynamicFile : public DynamicFile<ELFT> {
+public:
+ AArch64DynamicFile(const AArch64LinkingContext &context, StringRef name)
+ : DynamicFile<ELFT>(context, name) {}
+};
+
+} // elf
+} // lld
+
+#endif // LLD_READER_WRITER_ELF_AARCH64_AARCH64_ELF_FILE_H
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64ELFReader.h b/lib/ReaderWriter/ELF/AArch64/AArch64ELFReader.h
new file mode 100644
index 000000000000..05f312db3e7b
--- /dev/null
+++ b/lib/ReaderWriter/ELF/AArch64/AArch64ELFReader.h
@@ -0,0 +1,62 @@
+//===- lib/ReaderWriter/ELF/AArch64/AArch64ELFReader.h --------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_AARCH64_AARCH64_ELF_READER_H
+#define LLD_READER_WRITER_AARCH64_AARCH64_ELF_READER_H
+
+#include "AArch64ELFFile.h"
+#include "ELFReader.h"
+
+namespace lld {
+namespace elf {
+
+typedef llvm::object::ELFType<llvm::support::little, 2, true> AArch64ELFType;
+
+struct AArch64DynamicFileCreateELFTraits {
+ typedef llvm::ErrorOr<std::unique_ptr<lld::SharedLibraryFile>> result_type;
+
+ template <class ELFT>
+ static result_type create(std::unique_ptr<llvm::MemoryBuffer> mb,
+ AArch64LinkingContext &ctx) {
+ return lld::elf::AArch64DynamicFile<ELFT>::create(std::move(mb), ctx);
+ }
+};
+
+struct AArch64ELFFileCreateELFTraits {
+ typedef llvm::ErrorOr<std::unique_ptr<lld::File>> result_type;
+
+ template <class ELFT>
+ static result_type create(std::unique_ptr<llvm::MemoryBuffer> mb,
+ AArch64LinkingContext &ctx) {
+ return lld::elf::AArch64ELFFile<ELFT>::create(std::move(mb), ctx);
+ }
+};
+
+class AArch64ELFObjectReader
+ : public ELFObjectReader<AArch64ELFType, AArch64ELFFileCreateELFTraits,
+ AArch64LinkingContext> {
+public:
+ AArch64ELFObjectReader(AArch64LinkingContext &ctx)
+ : ELFObjectReader<AArch64ELFType, AArch64ELFFileCreateELFTraits,
+ AArch64LinkingContext>(ctx, llvm::ELF::EM_AARCH64) {}
+};
+
+class AArch64ELFDSOReader
+ : public ELFDSOReader<AArch64ELFType, AArch64DynamicFileCreateELFTraits,
+ AArch64LinkingContext> {
+public:
+ AArch64ELFDSOReader(AArch64LinkingContext &ctx)
+ : ELFDSOReader<AArch64ELFType, AArch64DynamicFileCreateELFTraits,
+ AArch64LinkingContext>(ctx, llvm::ELF::EM_AARCH64) {}
+};
+
+} // namespace elf
+} // namespace lld
+
+#endif // LLD_READER_WRITER_AARCH64_AARCH64_ELF_READER_H
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.h b/lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.h
new file mode 100644
index 000000000000..73963f56ef70
--- /dev/null
+++ b/lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.h
@@ -0,0 +1,68 @@
+//===- lib/ReaderWriter/ELF/AArch64/AArch64ExecutableWriter.h -------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef AARCH64_EXECUTABLE_WRITER_H
+#define AARCH64_EXECUTABLE_WRITER_H
+
+#include "AArch64LinkingContext.h"
+#include "ExecutableWriter.h"
+
+namespace lld {
+namespace elf {
+
+template <class ELFT>
+class AArch64ExecutableWriter : public ExecutableWriter<ELFT> {
+public:
+ AArch64ExecutableWriter(AArch64LinkingContext &context,
+ AArch64TargetLayout<ELFT> &layout);
+
+protected:
+ // Add any runtime files and their atoms to the output
+ bool createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
+
+ void finalizeDefaultAtomValues() override {
+ return ExecutableWriter<ELFT>::finalizeDefaultAtomValues();
+ }
+
+ void addDefaultAtoms() override{
+ return ExecutableWriter<ELFT>::addDefaultAtoms();
+ }
+
+private:
+ class GOTFile : public SimpleFile {
+ public:
+ GOTFile(const ELFLinkingContext &eti) : SimpleFile("GOTFile") {}
+ llvm::BumpPtrAllocator _alloc;
+ };
+
+ std::unique_ptr<GOTFile> _gotFile;
+ AArch64LinkingContext &_context;
+ AArch64TargetLayout<ELFT> &_AArch64Layout;
+};
+
+template <class ELFT>
+AArch64ExecutableWriter<ELFT>::AArch64ExecutableWriter(
+ AArch64LinkingContext &context, AArch64TargetLayout<ELFT> &layout)
+ : ExecutableWriter<ELFT>(context, layout), _gotFile(new GOTFile(context)),
+ _context(context), _AArch64Layout(layout) {}
+
+template <class ELFT>
+bool AArch64ExecutableWriter<ELFT>::createImplicitFiles(
+ std::vector<std::unique_ptr<File>> &result) {
+ ExecutableWriter<ELFT>::createImplicitFiles(result);
+ _gotFile->addAtom(*new (_gotFile->_alloc) GLOBAL_OFFSET_TABLEAtom(*_gotFile));
+ if (_context.isDynamic())
+ _gotFile->addAtom(*new (_gotFile->_alloc) DYNAMICAtom(*_gotFile));
+ result.push_back(std::move(_gotFile));
+ return true;
+}
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.cpp b/lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.cpp
new file mode 100644
index 000000000000..9eb98f447709
--- /dev/null
+++ b/lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.cpp
@@ -0,0 +1,33 @@
+//===- lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.cpp -------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AArch64LinkingContext.h"
+#include "AArch64RelocationPass.h"
+#include "AArch64TargetHandler.h"
+
+using namespace lld;
+
+std::unique_ptr<ELFLinkingContext>
+elf::AArch64LinkingContext::create(llvm::Triple triple) {
+ if (triple.getArch() == llvm::Triple::aarch64)
+ return std::unique_ptr<ELFLinkingContext>(
+ new elf::AArch64LinkingContext(triple));
+ return nullptr;
+}
+
+elf::AArch64LinkingContext::AArch64LinkingContext(llvm::Triple triple)
+ : ELFLinkingContext(triple, std::unique_ptr<TargetHandlerBase>(
+ new AArch64TargetHandler(*this))) {}
+
+void elf::AArch64LinkingContext::addPasses(PassManager &pm) {
+ auto pass = createAArch64RelocationPass(*this);
+ if (pass)
+ pm.add(std::move(pass));
+ ELFLinkingContext::addPasses(pm);
+}
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.h b/lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.h
new file mode 100644
index 000000000000..ebd91fe0a95b
--- /dev/null
+++ b/lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.h
@@ -0,0 +1,95 @@
+//===- lib/ReaderWriter/ELF/AArch64/AArch64LinkingContext.h ---------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_AARCH64_AARCH64_LINKING_CONTEXT_H
+#define LLD_READER_WRITER_ELF_AARCH64_AARCH64_LINKING_CONTEXT_H
+
+#include "lld/ReaderWriter/ELFLinkingContext.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/ELF.h"
+
+namespace lld {
+namespace elf {
+
+enum {
+ /// \brief The offset to add operation for a R_AARCH64_ADR_GOT_PAGE
+ ADD_AARCH64_GOTRELINDEX = 0xE000,
+};
+
+class AArch64LinkingContext final : public ELFLinkingContext {
+public:
+ static std::unique_ptr<ELFLinkingContext> create(llvm::Triple);
+ AArch64LinkingContext(llvm::Triple);
+
+ void addPasses(PassManager &) override;
+
+ uint64_t getBaseAddress() const override {
+ if (_baseAddress == 0)
+ return 0x400000;
+ return _baseAddress;
+ }
+
+ bool isDynamicRelocation(const Reference &r) const override {
+ if (r.kindNamespace() != Reference::KindNamespace::ELF)
+ return false;
+ assert(r.kindArch() == Reference::KindArch::AArch64);
+ switch (r.kindValue()) {
+ case llvm::ELF::R_AARCH64_COPY:
+ case llvm::ELF::R_AARCH64_GLOB_DAT:
+ case llvm::ELF::R_AARCH64_RELATIVE:
+ case llvm::ELF::R_AARCH64_TLS_DTPREL64:
+ case llvm::ELF::R_AARCH64_TLS_DTPMOD64:
+ case llvm::ELF::R_AARCH64_TLS_TPREL64:
+ case llvm::ELF::R_AARCH64_TLSDESC:
+ case llvm::ELF::R_AARCH64_IRELATIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ bool isCopyRelocation(const Reference &r) const override {
+ if (r.kindNamespace() != Reference::KindNamespace::ELF)
+ return false;
+ assert(r.kindArch() == Reference::KindArch::AArch64);
+ if (r.kindValue() == llvm::ELF::R_AARCH64_COPY)
+ return true;
+ return false;
+ }
+
+ bool isPLTRelocation(const Reference &r) const override {
+ if (r.kindNamespace() != Reference::KindNamespace::ELF)
+ return false;
+ assert(r.kindArch() == Reference::KindArch::AArch64);
+ switch (r.kindValue()) {
+ case llvm::ELF::R_AARCH64_JUMP_SLOT:
+ case llvm::ELF::R_AARCH64_IRELATIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ bool isRelativeReloc(const Reference &r) const override {
+ if (r.kindNamespace() != Reference::KindNamespace::ELF)
+ return false;
+ assert(r.kindArch() == Reference::KindArch::AArch64);
+ switch (r.kindValue()) {
+ case llvm::ELF::R_AARCH64_IRELATIVE:
+ case llvm::ELF::R_AARCH64_RELATIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+};
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.cpp b/lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.cpp
new file mode 100644
index 000000000000..d1ecc7fa884b
--- /dev/null
+++ b/lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.cpp
@@ -0,0 +1,440 @@
+//===- lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.cpp ----------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AArch64TargetHandler.h"
+#include "AArch64LinkingContext.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/MathExtras.h"
+
+using namespace lld;
+using namespace lld::elf;
+using namespace llvm::support::endian;
+
+#define PAGE(X) ((X) & ~0x0FFFL)
+
+/// \brief Check X is in the interval (-2^(bits-1), 2^bits]
+static bool withinSignedUnsignedRange(int64_t X, int bits) {
+ return isIntN(bits - 1, X) || isUIntN(bits, X);
+}
+
+/// \brief R_AARCH64_ABS64 - word64: S + A
+static void relocR_AARCH64_ABS64(uint8_t *location, uint64_t P, uint64_t S,
+ int64_t A) {
+ int64_t result = (int64_t)S + A;
+ DEBUG_WITH_TYPE(
+ "AArch64", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
+ llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
+ llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
+ llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
+ llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
+ write64le(location, result | read64le(location));
+}
+
+/// \brief R_AARCH64_PREL32 - word32: S + A - P
+static void relocR_AARCH64_PREL32(uint8_t *location, uint64_t P, uint64_t S,
+ int64_t A) {
+ int32_t result = (int32_t)((S + A) - P);
+ write32le(location, result + (int32_t)read32le(location));
+}
+
+/// \brief R_AARCH64_ABS32 - word32: S + A
+static std::error_code relocR_AARCH64_ABS32(uint8_t *location, uint64_t P,
+ uint64_t S, int64_t A) {
+ int64_t result = S + A;
+ if (!withinSignedUnsignedRange(result, 32))
+ return make_out_of_range_reloc_error();
+ DEBUG_WITH_TYPE(
+ "AArch64", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
+ llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
+ llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
+ llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
+ llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
+ write32le(location, result | read32le(location));
+ return std::error_code();
+}
+
+/// \brief R_AARCH64_ADR_PREL_PG_HI21 - Page(S+A) - Page(P)
+static void relocR_AARCH64_ADR_PREL_PG_HI21(uint8_t *location, uint64_t P,
+ uint64_t S, int64_t A) {
+ uint64_t result = (PAGE(S + A) - PAGE(P));
+ result = result >> 12;
+ uint32_t immlo = result & 0x3;
+ uint32_t immhi = result & 0x1FFFFC;
+ immlo = immlo << 29;
+ immhi = immhi << 3;
+ DEBUG_WITH_TYPE(
+ "AArch64", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
+ llvm::dbgs() << " S: " << Twine::utohexstr(S);
+ llvm::dbgs() << " A: " << Twine::utohexstr(A);
+ llvm::dbgs() << " P: " << Twine::utohexstr(P);
+ llvm::dbgs() << " immhi: " << Twine::utohexstr(immhi);
+ llvm::dbgs() << " immlo: " << Twine::utohexstr(immlo);
+ llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n");
+ write32le(location, immlo | immhi | read32le(location));
+ // TODO: Make sure this is correct!
+}
+
+/// \brief R_AARCH64_ADR_PREL_LO21 - S + A - P
+static void relocR_AARCH64_ADR_PREL_LO21(uint8_t *location, uint64_t P,
+ uint64_t S, int64_t A) {
+ uint64_t result = (S + A) - P;
+ uint32_t immlo = result & 0x3;
+ uint32_t immhi = result & 0x1FFFFC;
+ immlo = immlo << 29;
+ immhi = immhi << 3;
+ DEBUG_WITH_TYPE(
+ "AArch64", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
+ llvm::dbgs() << " S: " << Twine::utohexstr(S);
+ llvm::dbgs() << " A: " << Twine::utohexstr(A);
+ llvm::dbgs() << " P: " << Twine::utohexstr(P);
+ llvm::dbgs() << " immhi: " << Twine::utohexstr(immhi);
+ llvm::dbgs() << " immlo: " << Twine::utohexstr(immlo);
+ llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n");
+ write32le(location, immlo | immhi | read32le(location));
+ // TODO: Make sure this is correct!
+}
+
+/// \brief R_AARCH64_ADD_ABS_LO12_NC
+static void relocR_AARCH64_ADD_ABS_LO12_NC(uint8_t *location, uint64_t P,
+ uint64_t S, int64_t A) {
+ int32_t result = (int32_t)((S + A) & 0xFFF);
+ result <<= 10;
+ DEBUG_WITH_TYPE(
+ "AArch64", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
+ llvm::dbgs() << " S: " << Twine::utohexstr(S);
+ llvm::dbgs() << " A: " << Twine::utohexstr(A);
+ llvm::dbgs() << " P: " << Twine::utohexstr(P);
+ llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n");
+ write32le(location, result | read32le(location));
+}
+
+static void relocJump26(uint8_t *location, uint64_t P, uint64_t S, int64_t A) {
+ int32_t result = (int32_t)((S + A) - P);
+ result &= 0x0FFFFFFC;
+ result >>= 2;
+ DEBUG_WITH_TYPE(
+ "AArch64", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
+ llvm::dbgs() << " S: " << Twine::utohexstr(S);
+ llvm::dbgs() << " A: " << Twine::utohexstr(A);
+ llvm::dbgs() << " P: " << Twine::utohexstr(P);
+ llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n");
+ write32le(location, result | read32le(location));
+}
+
+/// \brief R_AARCH64_CONDBR19
+static void relocR_AARCH64_CONDBR19(uint8_t *location, uint64_t P, uint64_t S,
+ int64_t A) {
+ int32_t result = (int32_t)((S + A) - P);
+ result &= 0x01FFFFC;
+ result <<= 3;
+ DEBUG_WITH_TYPE(
+ "AArch64", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
+ llvm::dbgs() << " S: " << Twine::utohexstr(S);
+ llvm::dbgs() << " A: " << Twine::utohexstr(A);
+ llvm::dbgs() << " P: " << Twine::utohexstr(P);
+ llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n");
+ write32le(location, result | read32le(location));
+}
+
+/// \brief R_AARCH64_LDST8_ABS_LO12_NC - S + A
+static void relocR_AARCH64_LDST8_ABS_LO12_NC(uint8_t *location, uint64_t P,
+ uint64_t S, int64_t A) {
+ int32_t result = (int32_t)((S + A) & 0xFFF);
+ result <<= 10;
+ DEBUG_WITH_TYPE(
+ "AArch64", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
+ llvm::dbgs() << " S: " << Twine::utohexstr(S);
+ llvm::dbgs() << " A: " << Twine::utohexstr(A);
+ llvm::dbgs() << " P: " << Twine::utohexstr(P);
+ llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n");
+ write32le(location, result | read32le(location));
+}
+
+/// \brief R_AARCH64_LDST16_ABS_LO12_NC
+static void relocR_AARCH64_LDST16_ABS_LO12_NC(uint8_t *location, uint64_t P,
+ uint64_t S, int64_t A) {
+ int32_t result = (int32_t)(S + A);
+ result &= 0x0FFC;
+ result <<= 9;
+ DEBUG_WITH_TYPE(
+ "AArch64", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
+ llvm::dbgs() << " S: " << Twine::utohexstr(S);
+ llvm::dbgs() << " A: " << Twine::utohexstr(A);
+ llvm::dbgs() << " P: " << Twine::utohexstr(P);
+ llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n");
+ write32le(location, result | read32le(location));
+}
+
+/// \brief R_AARCH64_LDST32_ABS_LO12_NC
+static void relocR_AARCH64_LDST32_ABS_LO12_NC(uint8_t *location, uint64_t P,
+ uint64_t S, int64_t A) {
+ int32_t result = (int32_t)(S + A);
+ result &= 0x0FFC;
+ result <<= 8;
+ DEBUG_WITH_TYPE(
+ "AArch64", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
+ llvm::dbgs() << " S: " << Twine::utohexstr(S);
+ llvm::dbgs() << " A: " << Twine::utohexstr(A);
+ llvm::dbgs() << " P: " << Twine::utohexstr(P);
+ llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n");
+ write32le(location, result | read32le(location));
+}
+
+/// \brief R_AARCH64_LDST64_ABS_LO12_NC
+static void relocR_AARCH64_LDST64_ABS_LO12_NC(uint8_t *location, uint64_t P,
+ uint64_t S, int64_t A) {
+ int32_t result = (int32_t)(S + A);
+ result &= 0x0FF8;
+ result <<= 7;
+ DEBUG_WITH_TYPE(
+ "AArch64", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
+ llvm::dbgs() << " S: " << Twine::utohexstr(S);
+ llvm::dbgs() << " A: " << Twine::utohexstr(A);
+ llvm::dbgs() << " P: " << Twine::utohexstr(P);
+ llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n");
+ write32le(location, result | read32le(location));
+}
+
+/// \brief R_AARCH64_LDST128_ABS_LO12_NC
+static void relocR_AARCH64_LDST128_ABS_LO12_NC(uint8_t *location, uint64_t P,
+ uint64_t S, int64_t A) {
+ int32_t result = (int32_t)(S + A);
+ result &= 0x0FF8;
+ result <<= 6;
+ DEBUG_WITH_TYPE(
+ "AArch64", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
+ llvm::dbgs() << " S: " << Twine::utohexstr(S);
+ llvm::dbgs() << " A: " << Twine::utohexstr(A);
+ llvm::dbgs() << " P: " << Twine::utohexstr(P);
+ llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n");
+ write32le(location, result | read32le(location));
+}
+
+static void relocR_AARCH64_ADR_GOT_PAGE(uint8_t *location, uint64_t P,
+ uint64_t S, int64_t A) {
+ uint64_t result = PAGE(S + A) - PAGE(P);
+ result >>= 12;
+ uint32_t immlo = result & 0x3;
+ uint32_t immhi = result & 0x1FFFFC;
+ immlo = immlo << 29;
+ immhi = immhi << 3;
+ DEBUG_WITH_TYPE(
+ "AArch64", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
+ llvm::dbgs() << " S: " << Twine::utohexstr(S);
+ llvm::dbgs() << " A: " << Twine::utohexstr(A);
+ llvm::dbgs() << " P: " << Twine::utohexstr(P);
+ llvm::dbgs() << " immhi: " << Twine::utohexstr(immhi);
+ llvm::dbgs() << " immlo: " << Twine::utohexstr(immlo);
+ llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n");
+ write32le(location, result | read32le(location));
+}
+
+// R_AARCH64_LD64_GOT_LO12_NC
+static void relocR_AARCH64_LD64_GOT_LO12_NC(uint8_t *location, uint64_t P,
+ uint64_t S, int64_t A) {
+ int32_t result = S + A;
+ DEBUG_WITH_TYPE(
+ "AArch64", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
+ llvm::dbgs() << " S: " << Twine::utohexstr(S);
+ llvm::dbgs() << " A: " << Twine::utohexstr(A);
+ llvm::dbgs() << " P: " << Twine::utohexstr(P);
+ llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n");
+ result &= 0xFF8;
+ result <<= 7;
+ write32le(location, result | read32le(location));
+}
+
+// ADD_AARCH64_GOTRELINDEX
+static void relocADD_AARCH64_GOTRELINDEX(uint8_t *location, uint64_t P,
+ uint64_t S, int64_t A) {
+ int32_t result = S + A;
+ DEBUG_WITH_TYPE(
+ "AArch64", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
+ llvm::dbgs() << " S: " << Twine::utohexstr(S);
+ llvm::dbgs() << " A: " << Twine::utohexstr(A);
+ llvm::dbgs() << " P: " << Twine::utohexstr(P);
+ llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n");
+ result &= 0xFFF;
+ result <<= 10;
+ write32le(location, result | read32le(location));
+}
+
+// R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21
+static void relocR_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21(uint8_t *location,
+ uint64_t P, uint64_t S,
+ int64_t A) {
+ int64_t result = PAGE(S + A) - PAGE(P);
+ result >>= 12;
+ uint32_t immlo = result & 0x3;
+ uint32_t immhi = result & 0x1FFFFC;
+ immlo = immlo << 29;
+ immhi = immhi << 3;
+ DEBUG_WITH_TYPE(
+ "AArch64", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
+ llvm::dbgs() << " S: " << Twine::utohexstr(S);
+ llvm::dbgs() << " A: " << Twine::utohexstr(A);
+ llvm::dbgs() << " P: " << Twine::utohexstr(P);
+ llvm::dbgs() << " immhi: " << Twine::utohexstr(immhi);
+ llvm::dbgs() << " immlo: " << Twine::utohexstr(immlo);
+ llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n");
+ write32le(location, immlo | immhi | read32le(location));
+}
+
+// R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC
+static void relocR_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC(uint8_t *location,
+ uint64_t P, uint64_t S,
+ int64_t A) {
+ int32_t result = S + A;
+ result &= 0xFF8;
+ result <<= 7;
+ DEBUG_WITH_TYPE(
+ "AArch64", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
+ llvm::dbgs() << " S: " << Twine::utohexstr(S);
+ llvm::dbgs() << " A: " << Twine::utohexstr(A);
+ llvm::dbgs() << " P: " << Twine::utohexstr(P);
+ llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n");
+ write32le(location, result | read32le(location));
+}
+
+/// \brief R_AARCH64_TLSLE_ADD_TPREL_HI12
+static void relocR_AARCH64_TLSLE_ADD_TPREL_HI12(uint8_t *location, uint64_t P,
+ uint64_t S, int64_t A) {
+ int32_t result = S + A;
+ result &= 0x0FFF000;
+ result >>= 2;
+ DEBUG_WITH_TYPE(
+ "AArch64", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
+ llvm::dbgs() << " S: " << Twine::utohexstr(S);
+ llvm::dbgs() << " A: " << Twine::utohexstr(A);
+ llvm::dbgs() << " P: " << Twine::utohexstr(P);
+ llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n");
+ write32le(location, result | read32le(location));
+}
+
+/// \brief R_AARCH64_TLSLE_ADD_TPREL_LO12_NC
+static void relocR_AARCH64_TLSLE_ADD_TPREL_LO12_NC(uint8_t *location,
+ uint64_t P, uint64_t S,
+ int64_t A) {
+ int32_t result = S + A;
+ result &= 0x0FFF;
+ result <<= 10;
+ DEBUG_WITH_TYPE(
+ "AArch64", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
+ llvm::dbgs() << " S: " << Twine::utohexstr(S);
+ llvm::dbgs() << " A: " << Twine::utohexstr(A);
+ llvm::dbgs() << " P: " << Twine::utohexstr(P);
+ llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n");
+ write32le(location, result | read32le(location));
+}
+
+std::error_code AArch64TargetRelocationHandler::applyRelocation(
+ ELFWriter &writer, llvm::FileOutputBuffer &buf, const lld::AtomLayout &atom,
+ const Reference &ref) const {
+ uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset;
+ uint8_t *location = atomContent + ref.offsetInAtom();
+ uint64_t targetVAddress = writer.addressOfAtom(ref.target());
+ uint64_t relocVAddress = atom._virtualAddr + ref.offsetInAtom();
+
+ if (ref.kindNamespace() != Reference::KindNamespace::ELF)
+ return std::error_code();
+ assert(ref.kindArch() == Reference::KindArch::AArch64);
+ switch (ref.kindValue()) {
+ case R_AARCH64_NONE:
+ break;
+ case R_AARCH64_ABS64:
+ relocR_AARCH64_ABS64(location, relocVAddress, targetVAddress, ref.addend());
+ break;
+ case R_AARCH64_PREL32:
+ relocR_AARCH64_PREL32(location, relocVAddress, targetVAddress,
+ ref.addend());
+ break;
+ case R_AARCH64_ABS32:
+ return relocR_AARCH64_ABS32(location, relocVAddress, targetVAddress,
+ ref.addend());
+ // Runtime only relocations. Ignore here.
+ case R_AARCH64_RELATIVE:
+ case R_AARCH64_IRELATIVE:
+ case R_AARCH64_JUMP_SLOT:
+ case R_AARCH64_GLOB_DAT:
+ break;
+ case R_AARCH64_ADR_PREL_PG_HI21:
+ relocR_AARCH64_ADR_PREL_PG_HI21(location, relocVAddress, targetVAddress,
+ ref.addend());
+ break;
+ case R_AARCH64_ADR_PREL_LO21:
+ relocR_AARCH64_ADR_PREL_LO21(location, relocVAddress, targetVAddress,
+ ref.addend());
+ break;
+ case R_AARCH64_ADD_ABS_LO12_NC:
+ relocR_AARCH64_ADD_ABS_LO12_NC(location, relocVAddress, targetVAddress,
+ ref.addend());
+ break;
+ case R_AARCH64_CALL26:
+ case R_AARCH64_JUMP26:
+ relocJump26(location, relocVAddress, targetVAddress, ref.addend());
+ break;
+ case R_AARCH64_CONDBR19:
+ relocR_AARCH64_CONDBR19(location, relocVAddress, targetVAddress,
+ ref.addend());
+ break;
+ case R_AARCH64_ADR_GOT_PAGE:
+ relocR_AARCH64_ADR_GOT_PAGE(location, relocVAddress, targetVAddress,
+ ref.addend());
+ break;
+ case R_AARCH64_LD64_GOT_LO12_NC:
+ relocR_AARCH64_LD64_GOT_LO12_NC(location, relocVAddress, targetVAddress,
+ ref.addend());
+ break;
+ case R_AARCH64_LDST8_ABS_LO12_NC:
+ relocR_AARCH64_LDST8_ABS_LO12_NC(location, relocVAddress, targetVAddress,
+ ref.addend());
+ break;
+ case R_AARCH64_LDST16_ABS_LO12_NC:
+ relocR_AARCH64_LDST16_ABS_LO12_NC(location, relocVAddress, targetVAddress,
+ ref.addend());
+ break;
+ case R_AARCH64_LDST32_ABS_LO12_NC:
+ relocR_AARCH64_LDST32_ABS_LO12_NC(location, relocVAddress, targetVAddress,
+ ref.addend());
+ break;
+ case R_AARCH64_LDST64_ABS_LO12_NC:
+ relocR_AARCH64_LDST64_ABS_LO12_NC(location, relocVAddress, targetVAddress,
+ ref.addend());
+ break;
+ case R_AARCH64_LDST128_ABS_LO12_NC:
+ relocR_AARCH64_LDST128_ABS_LO12_NC(location, relocVAddress, targetVAddress,
+ ref.addend());
+ break;
+ case ADD_AARCH64_GOTRELINDEX:
+ relocADD_AARCH64_GOTRELINDEX(location, relocVAddress, targetVAddress,
+ ref.addend());
+ break;
+ case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
+ relocR_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21(location, relocVAddress,
+ targetVAddress, ref.addend());
+ break;
+ case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
+ relocR_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC(location, relocVAddress,
+ targetVAddress, ref.addend());
+ break;
+ case R_AARCH64_TLSLE_ADD_TPREL_HI12:
+ relocR_AARCH64_TLSLE_ADD_TPREL_HI12(location, relocVAddress, targetVAddress,
+ ref.addend());
+ break;
+ case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
+ relocR_AARCH64_TLSLE_ADD_TPREL_LO12_NC(location, relocVAddress,
+ targetVAddress, ref.addend());
+ break;
+ default:
+ return make_unhandled_reloc_error();
+ }
+
+ return std::error_code();
+}
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.h b/lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.h
new file mode 100644
index 000000000000..b1d3c09dc936
--- /dev/null
+++ b/lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.h
@@ -0,0 +1,33 @@
+//===- lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.h ------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef AARCH64_RELOCATION_HANDLER_H
+#define AARCH64_RELOCATION_HANDLER_H
+
+#include "AArch64TargetHandler.h"
+
+namespace lld {
+namespace elf {
+typedef llvm::object::ELFType<llvm::support::little, 2, true> AArch64ELFType;
+
+template <class ELFT> class AArch64TargetLayout;
+
+class AArch64TargetRelocationHandler final : public TargetRelocationHandler {
+public:
+ std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &,
+ const lld::AtomLayout &,
+ const Reference &) const override;
+
+ static const Registry::KindStrings kindStrings[];
+};
+
+} // end namespace elf
+} // end namespace lld
+
+#endif // AArch64_RELOCATION_HANDLER_H
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.cpp b/lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.cpp
new file mode 100644
index 000000000000..0bd12958b27b
--- /dev/null
+++ b/lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.cpp
@@ -0,0 +1,527 @@
+//===- lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.cpp -------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Defines the relocation processing pass for AArch64. This includes
+/// GOT and PLT entries, TLS, COPY, and ifunc.
+///
+/// This also includes additional behavior that gnu-ld and gold implement but
+/// which is not specified anywhere.
+///
+//===----------------------------------------------------------------------===//
+
+#include "AArch64RelocationPass.h"
+#include "AArch64LinkingContext.h"
+#include "Atoms.h"
+#include "lld/Core/Simple.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Debug.h"
+
+using namespace lld;
+using namespace lld::elf;
+using namespace llvm::ELF;
+
+namespace {
+// .got values
+const uint8_t AArch64GotAtomContent[8] = {0};
+
+// .plt value (entry 0)
+const uint8_t AArch64Plt0AtomContent[32] = {
+ 0xf0, 0x7b, 0xbf,
+ 0xa9, // stp x16, x30, [sp,#-16]!
+ 0x10, 0x00, 0x00,
+ 0x90, // adrp x16, Page(eh_frame)
+ 0x11, 0x02, 0x40,
+ 0xf9, // ldr x17, [x16,#offset]
+ 0x10, 0x02, 0x00,
+ 0x91, // add x16, x16, #offset
+ 0x20, 0x02, 0x1f,
+ 0xd6, // br x17
+ 0x1f, 0x20, 0x03,
+ 0xd5, // nop
+ 0x1f, 0x20, 0x03,
+ 0xd5, // nop
+ 0x1f, 0x20, 0x03,
+ 0xd5 // nop
+};
+
+// .plt values (other entries)
+const uint8_t AArch64PltAtomContent[16] = {
+ 0x10, 0x00, 0x00,
+ 0x90, // adrp x16, PAGE(<GLOBAL_OFFSET_TABLE>)
+ 0x11, 0x02, 0x40,
+ 0xf9, // ldr x17, [x16,#offset]
+ 0x10, 0x02, 0x00,
+ 0x91, // add x16, x16, #offset
+ 0x20, 0x02, 0x1f,
+ 0xd6 // br x17
+};
+
+/// \brief Atoms that are used by AArch64 dynamic linking
+class AArch64GOTAtom : public GOTAtom {
+public:
+ AArch64GOTAtom(const File &f, StringRef secName) : GOTAtom(f, secName) {}
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return ArrayRef<uint8_t>(AArch64GotAtomContent, 8);
+ }
+};
+
+class AArch64PLT0Atom : public PLT0Atom {
+public:
+ AArch64PLT0Atom(const File &f) : PLT0Atom(f) {}
+ ArrayRef<uint8_t> rawContent() const override {
+ return ArrayRef<uint8_t>(AArch64Plt0AtomContent, 32);
+ }
+};
+
+class AArch64PLTAtom : public PLTAtom {
+public:
+ AArch64PLTAtom(const File &f, StringRef secName) : PLTAtom(f, secName) {}
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return ArrayRef<uint8_t>(AArch64PltAtomContent, 16);
+ }
+};
+
+class ELFPassFile : public SimpleFile {
+public:
+ ELFPassFile(const ELFLinkingContext &eti) : SimpleFile("ELFPassFile") {
+ setOrdinal(eti.getNextOrdinalAndIncrement());
+ }
+
+ llvm::BumpPtrAllocator _alloc;
+};
+
+/// \brief CRTP base for handling relocations.
+template <class Derived> class AArch64RelocationPass : public Pass {
+ /// \brief Handle a specific reference.
+ void handleReference(const DefinedAtom &atom, const Reference &ref) {
+ DEBUG_WITH_TYPE(
+ "AArch64", llvm::dbgs()
+ << "\t" << LLVM_FUNCTION_NAME << "()"
+ << ": Name of Defined Atom: " << atom.name().str();
+ llvm::dbgs() << " kindValue: " << ref.kindValue() << "\n");
+ if (ref.kindNamespace() != Reference::KindNamespace::ELF)
+ return;
+ assert(ref.kindArch() == Reference::KindArch::AArch64);
+ switch (ref.kindValue()) {
+ case R_AARCH64_ABS32:
+ case R_AARCH64_ABS16:
+ case R_AARCH64_ABS64:
+ case R_AARCH64_PREL16:
+ case R_AARCH64_PREL32:
+ case R_AARCH64_PREL64:
+ static_cast<Derived *>(this)->handlePlain(ref);
+ break;
+ case R_AARCH64_GOTREL32:
+ case R_AARCH64_GOTREL64:
+ static_cast<Derived *>(this)->handleGOT(ref);
+ break;
+ case R_AARCH64_ADR_PREL_PG_HI21:
+ static_cast<Derived *>(this)->handlePlain(ref);
+ break;
+ case R_AARCH64_LDST8_ABS_LO12_NC:
+ case R_AARCH64_LDST16_ABS_LO12_NC:
+ case R_AARCH64_LDST32_ABS_LO12_NC:
+ case R_AARCH64_LDST64_ABS_LO12_NC:
+ case R_AARCH64_LDST128_ABS_LO12_NC:
+ static_cast<Derived *>(this)->handlePlain(ref);
+ break;
+ case R_AARCH64_ADD_ABS_LO12_NC:
+ static_cast<Derived *>(this)->handlePlain(ref);
+ break;
+ case R_AARCH64_CALL26:
+ case R_AARCH64_JUMP26:
+ case R_AARCH64_CONDBR19:
+ static_cast<Derived *>(this)->handlePlain(ref);
+ break;
+ case R_AARCH64_TLSLE_ADD_TPREL_HI12:
+ case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
+ static_cast<Derived *>(this)->handlePlain(ref);
+ break;
+ case R_AARCH64_ADR_GOT_PAGE:
+ case R_AARCH64_LD64_GOT_LO12_NC:
+ case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
+ case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
+ static_cast<Derived *>(this)->handleGOT(ref);
+ break;
+ }
+ }
+
+protected:
+ /// \brief get the PLT entry for a given IFUNC Atom.
+ ///
+ /// If the entry does not exist. Both the GOT and PLT entry is created.
+ const PLTAtom *getIFUNCPLTEntry(const DefinedAtom *da) {
+ auto plt = _pltMap.find(da);
+ if (plt != _pltMap.end())
+ return plt->second;
+ auto ga = new (_file._alloc) AArch64GOTAtom(_file, ".got.plt");
+ ga->addReferenceELF_AArch64(R_AARCH64_IRELATIVE, 0, da, 0);
+ auto pa = new (_file._alloc) AArch64PLTAtom(_file, ".plt");
+ pa->addReferenceELF_AArch64(R_AARCH64_PREL32, 2, ga, -4);
+#ifndef NDEBUG
+ ga->_name = "__got_ifunc_";
+ ga->_name += da->name();
+ pa->_name = "__plt_ifunc_";
+ pa->_name += da->name();
+#endif
+ _gotMap[da] = ga;
+ _pltMap[da] = pa;
+ _gotVector.push_back(ga);
+ _pltVector.push_back(pa);
+ return pa;
+ }
+
+ /// \brief Redirect the call to the PLT stub for the target IFUNC.
+ ///
+ /// This create a PLT and GOT entry for the IFUNC if one does not exist. The
+ /// GOT entry and a IRELATIVE relocation to the original target resolver.
+ std::error_code handleIFUNC(const Reference &ref) {
+ auto target = dyn_cast_or_null<const DefinedAtom>(ref.target());
+ if (target && target->contentType() == DefinedAtom::typeResolver)
+ const_cast<Reference &>(ref).setTarget(getIFUNCPLTEntry(target));
+ return std::error_code();
+ }
+
+ /// \brief Create a GOT entry for the TP offset of a TLS atom.
+ const GOTAtom *getGOTTPOFF(const Atom *atom) {
+ auto got = _gotMap.find(atom);
+ if (got == _gotMap.end()) {
+ auto g = new (_file._alloc) AArch64GOTAtom(_file, ".got");
+ g->addReferenceELF_AArch64(R_AARCH64_GOTREL64, 0, atom, 0);
+#ifndef NDEBUG
+ g->_name = "__got_tls_";
+ g->_name += atom->name();
+#endif
+ _gotMap[atom] = g;
+ _gotVector.push_back(g);
+ return g;
+ }
+ return got->second;
+ }
+
+ /// \brief Create a TPOFF64 GOT entry and change the relocation to a PC32 to
+ /// the GOT.
+ void handleGOTTPOFF(const Reference &ref) {
+ const_cast<Reference &>(ref).setTarget(getGOTTPOFF(ref.target()));
+ const_cast<Reference &>(ref).setKindValue(R_AARCH64_PREL32);
+ }
+
+ /// \brief Create a GOT entry containing 0.
+ const GOTAtom *getNullGOT() {
+ if (!_null) {
+ _null = new (_file._alloc) AArch64GOTAtom(_file, ".got.plt");
+#ifndef NDEBUG
+ _null->_name = "__got_null";
+#endif
+ }
+ return _null;
+ }
+
+ const GOTAtom *getGOT(const DefinedAtom *da) {
+ auto got = _gotMap.find(da);
+ if (got == _gotMap.end()) {
+ auto g = new (_file._alloc) AArch64GOTAtom(_file, ".got");
+ g->addReferenceELF_AArch64(R_AARCH64_ABS64, 0, da, 0);
+#ifndef NDEBUG
+ g->_name = "__got_";
+ g->_name += da->name();
+#endif
+ _gotMap[da] = g;
+ _gotVector.push_back(g);
+ return g;
+ }
+ return got->second;
+ }
+
+public:
+ AArch64RelocationPass(const ELFLinkingContext &ctx)
+ : _file(ctx), _ctx(ctx), _null(nullptr), _PLT0(nullptr), _got0(nullptr),
+ _got1(nullptr) {}
+
+ /// \brief Do the pass.
+ ///
+ /// The goal here is to first process each reference individually. Each call
+ /// to handleReference may modify the reference itself and/or create new
+ /// atoms which must be stored in one of the maps below.
+ ///
+ /// After all references are handled, the atoms created during that are all
+ /// added to mf.
+ void perform(std::unique_ptr<MutableFile> &mf) override {
+ ScopedTask task(getDefaultDomain(), "AArch64 GOT/PLT Pass");
+ DEBUG_WITH_TYPE(
+ "AArch64", llvm::dbgs() << "Undefined Atoms"
+ << "\n";
+ for (const auto &atom
+ : mf->undefined()) {
+ llvm::dbgs() << " Name of Atom: " << atom->name().str() << "\n";
+ } llvm::dbgs()
+ << "Shared Library Atoms"
+ << "\n";
+ for (const auto &atom
+ : mf->sharedLibrary()) {
+ llvm::dbgs() << " Name of Atom: " << atom->name().str() << "\n";
+ } llvm::dbgs()
+ << "Absolute Atoms"
+ << "\n";
+ for (const auto &atom
+ : mf->absolute()) {
+ llvm::dbgs() << " Name of Atom: " << atom->name().str() << "\n";
+ }
+ // Process all references.
+ llvm::dbgs()
+ << "Defined Atoms"
+ << "\n");
+ for (const auto &atom : mf->defined()) {
+ for (const auto &ref : *atom) {
+ handleReference(*atom, *ref);
+ }
+ }
+
+ // Add all created atoms to the link.
+ uint64_t ordinal = 0;
+ if (_PLT0) {
+ _PLT0->setOrdinal(ordinal++);
+ mf->addAtom(*_PLT0);
+ }
+ for (auto &plt : _pltVector) {
+ plt->setOrdinal(ordinal++);
+ mf->addAtom(*plt);
+ }
+ if (_null) {
+ _null->setOrdinal(ordinal++);
+ mf->addAtom(*_null);
+ }
+ if (_PLT0) {
+ _got0->setOrdinal(ordinal++);
+ _got1->setOrdinal(ordinal++);
+ mf->addAtom(*_got0);
+ mf->addAtom(*_got1);
+ }
+ for (auto &got : _gotVector) {
+ got->setOrdinal(ordinal++);
+ mf->addAtom(*got);
+ }
+ for (auto obj : _objectVector) {
+ obj->setOrdinal(ordinal++);
+ mf->addAtom(*obj);
+ }
+ }
+
+protected:
+ /// \brief Owner of all the Atoms created by this pass.
+ ELFPassFile _file;
+ const ELFLinkingContext &_ctx;
+
+ /// \brief Map Atoms to their GOT entries.
+ llvm::DenseMap<const Atom *, GOTAtom *> _gotMap;
+
+ /// \brief Map Atoms to their PLT entries.
+ llvm::DenseMap<const Atom *, PLTAtom *> _pltMap;
+
+ /// \brief Map Atoms to their Object entries.
+ llvm::DenseMap<const Atom *, ObjectAtom *> _objectMap;
+
+ /// \brief the list of GOT/PLT atoms
+ std::vector<GOTAtom *> _gotVector;
+ std::vector<PLTAtom *> _pltVector;
+ std::vector<ObjectAtom *> _objectVector;
+
+ /// \brief GOT entry that is always 0. Used for undefined weaks.
+ GOTAtom *_null;
+
+ /// \brief The got and plt entries for .PLT0. This is used to call into the
+ /// dynamic linker for symbol resolution.
+ /// @{
+ PLT0Atom *_PLT0;
+ GOTAtom *_got0;
+ GOTAtom *_got1;
+ /// @}
+};
+
+/// This implements the static relocation model. Meaning GOT and PLT entries are
+/// not created for references that can be directly resolved. These are
+/// converted to a direct relocation. For entries that do require a GOT or PLT
+/// entry, that entry is statically bound.
+///
+/// TLS always assumes module 1 and attempts to remove indirection.
+class AArch64StaticRelocationPass final
+ : public AArch64RelocationPass<AArch64StaticRelocationPass> {
+public:
+ AArch64StaticRelocationPass(const elf::AArch64LinkingContext &ctx)
+ : AArch64RelocationPass(ctx) {}
+
+ std::error_code handlePlain(const Reference &ref) { return handleIFUNC(ref); }
+
+ std::error_code handlePLT32(const Reference &ref) {
+ // __tls_get_addr is handled elsewhere.
+ if (ref.target() && ref.target()->name() == "__tls_get_addr") {
+ const_cast<Reference &>(ref).setKindValue(R_AARCH64_NONE);
+ return std::error_code();
+ }
+ // Static code doesn't need PLTs.
+ const_cast<Reference &>(ref).setKindValue(R_AARCH64_PREL32);
+ // Handle IFUNC.
+ if (const DefinedAtom *da =
+ dyn_cast_or_null<const DefinedAtom>(ref.target()))
+ if (da->contentType() == DefinedAtom::typeResolver)
+ return handleIFUNC(ref);
+ return std::error_code();
+ }
+
+ std::error_code handleGOT(const Reference &ref) {
+ if (isa<UndefinedAtom>(ref.target()))
+ const_cast<Reference &>(ref).setTarget(getNullGOT());
+ else if (const DefinedAtom *da = dyn_cast<const DefinedAtom>(ref.target()))
+ const_cast<Reference &>(ref).setTarget(getGOT(da));
+ return std::error_code();
+ }
+};
+
+class AArch64DynamicRelocationPass final
+ : public AArch64RelocationPass<AArch64DynamicRelocationPass> {
+public:
+ AArch64DynamicRelocationPass(const elf::AArch64LinkingContext &ctx)
+ : AArch64RelocationPass(ctx) {}
+
+ const PLT0Atom *getPLT0() {
+ if (_PLT0)
+ return _PLT0;
+ // Fill in the null entry.
+ getNullGOT();
+ _PLT0 = new (_file._alloc) AArch64PLT0Atom(_file);
+ _got0 = new (_file._alloc) AArch64GOTAtom(_file, ".got.plt");
+ _got1 = new (_file._alloc) AArch64GOTAtom(_file, ".got.plt");
+ _PLT0->addReferenceELF_AArch64(R_AARCH64_ADR_GOT_PAGE, 4, _got0, 0);
+ _PLT0->addReferenceELF_AArch64(R_AARCH64_LD64_GOT_LO12_NC, 8, _got1, 0);
+ _PLT0->addReferenceELF_AArch64(ADD_AARCH64_GOTRELINDEX, 12, _got1, 0);
+#ifndef NDEBUG
+ _PLT0->_name = "__PLT0";
+ _got0->_name = "__got0";
+ _got1->_name = "__got1";
+#endif
+ return _PLT0;
+ }
+
+ const PLTAtom *getPLTEntry(const Atom *a) {
+ auto plt = _pltMap.find(a);
+ if (plt != _pltMap.end())
+ return plt->second;
+ auto ga = new (_file._alloc) AArch64GOTAtom(_file, ".got.plt");
+ ga->addReferenceELF_AArch64(R_AARCH64_JUMP_SLOT, 0, a, 0);
+ auto pa = new (_file._alloc) AArch64PLTAtom(_file, ".plt");
+ pa->addReferenceELF_AArch64(R_AARCH64_ADR_GOT_PAGE, 0, ga, 0);
+ pa->addReferenceELF_AArch64(R_AARCH64_LD64_GOT_LO12_NC, 4, ga, 0);
+ pa->addReferenceELF_AArch64(ADD_AARCH64_GOTRELINDEX, 8, ga, 0);
+ pa->addReferenceELF_AArch64(R_AARCH64_NONE, 12, getPLT0(), 0);
+ // Set the starting address of the got entry to the first instruction in
+ // the plt0 entry.
+ ga->addReferenceELF_AArch64(R_AARCH64_ABS32, 0, getPLT0(), 0);
+#ifndef NDEBUG
+ ga->_name = "__got_";
+ ga->_name += a->name();
+ pa->_name = "__plt_";
+ pa->_name += a->name();
+#endif
+ _gotMap[a] = ga;
+ _pltMap[a] = pa;
+ _gotVector.push_back(ga);
+ _pltVector.push_back(pa);
+ return pa;
+ }
+
+ const ObjectAtom *getObjectEntry(const SharedLibraryAtom *a) {
+ auto obj = _objectMap.find(a);
+ if (obj != _objectMap.end())
+ return obj->second;
+
+ auto oa = new (_file._alloc) ObjectAtom(_file);
+ // This needs to point to the atom that we just created.
+ oa->addReferenceELF_AArch64(R_AARCH64_COPY, 0, oa, 0);
+
+ oa->_name = a->name();
+ oa->_size = a->size();
+
+ _objectMap[a] = oa;
+ _objectVector.push_back(oa);
+ return oa;
+ }
+
+ std::error_code handlePlain(const Reference &ref) {
+ if (!ref.target())
+ return std::error_code();
+ if (auto sla = dyn_cast<SharedLibraryAtom>(ref.target())) {
+ if (sla->type() == SharedLibraryAtom::Type::Data)
+ const_cast<Reference &>(ref).setTarget(getObjectEntry(sla));
+ else if (sla->type() == SharedLibraryAtom::Type::Code)
+ const_cast<Reference &>(ref).setTarget(getPLTEntry(sla));
+ } else
+ return handleIFUNC(ref);
+ return std::error_code();
+ }
+
+ std::error_code handlePLT32(const Reference &ref) {
+ // Turn this into a PC32 to the PLT entry.
+ const_cast<Reference &>(ref).setKindValue(R_AARCH64_PREL32);
+ // Handle IFUNC.
+ if (const DefinedAtom *da =
+ dyn_cast_or_null<const DefinedAtom>(ref.target()))
+ if (da->contentType() == DefinedAtom::typeResolver)
+ return handleIFUNC(ref);
+ if (isa<const SharedLibraryAtom>(ref.target()))
+ const_cast<Reference &>(ref).setTarget(getPLTEntry(ref.target()));
+ return std::error_code();
+ }
+
+ const GOTAtom *getSharedGOT(const SharedLibraryAtom *sla) {
+ auto got = _gotMap.find(sla);
+ if (got == _gotMap.end()) {
+ auto g = new (_file._alloc) AArch64GOTAtom(_file, ".got");
+ g->addReferenceELF_AArch64(R_AARCH64_GLOB_DAT, 0, sla, 0);
+#ifndef NDEBUG
+ g->_name = "__got_";
+ g->_name += sla->name();
+#endif
+ _gotMap[sla] = g;
+ _gotVector.push_back(g);
+ return g;
+ }
+ return got->second;
+ }
+
+ std::error_code handleGOT(const Reference &ref) {
+ if (isa<UndefinedAtom>(ref.target()))
+ const_cast<Reference &>(ref).setTarget(getNullGOT());
+ else if (const DefinedAtom *da = dyn_cast<const DefinedAtom>(ref.target()))
+ const_cast<Reference &>(ref).setTarget(getGOT(da));
+ else if (const auto sla = dyn_cast<const SharedLibraryAtom>(ref.target()))
+ const_cast<Reference &>(ref).setTarget(getSharedGOT(sla));
+ return std::error_code();
+ }
+};
+} // end anon namespace
+
+std::unique_ptr<Pass>
+lld::elf::createAArch64RelocationPass(const AArch64LinkingContext &ctx) {
+ switch (ctx.getOutputELFType()) {
+ case llvm::ELF::ET_EXEC:
+ if (ctx.isDynamic())
+ return llvm::make_unique<AArch64DynamicRelocationPass>(ctx);
+ return llvm::make_unique<AArch64StaticRelocationPass>(ctx);
+ case llvm::ELF::ET_DYN:
+ return llvm::make_unique<AArch64DynamicRelocationPass>(ctx);
+ case llvm::ELF::ET_REL:
+ return nullptr;
+ default:
+ llvm_unreachable("Unhandled output file type");
+ }
+}
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.h b/lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.h
new file mode 100644
index 000000000000..73d784e3b52d
--- /dev/null
+++ b/lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.h
@@ -0,0 +1,32 @@
+//===- lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.h ---------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Declares the relocation processing pass for AArch64. This includes
+/// GOT and PLT entries, TLS, COPY, and ifunc.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_AARCH64_AARCH64_RELOCATION_PASS_H
+#define LLD_READER_WRITER_ELF_AARCH64_AARCH64_RELOCATION_PASS_H
+
+#include <memory>
+
+namespace lld {
+class Pass;
+namespace elf {
+class AArch64LinkingContext;
+
+/// \brief Create AArch64 relocation pass for the given linking context.
+std::unique_ptr<Pass>
+createAArch64RelocationPass(const AArch64LinkingContext &);
+}
+}
+
+#endif
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.cpp b/lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.cpp
new file mode 100644
index 000000000000..607f767f8b8a
--- /dev/null
+++ b/lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.cpp
@@ -0,0 +1,52 @@
+//===- lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.cpp --------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Atoms.h"
+#include "AArch64DynamicLibraryWriter.h"
+#include "AArch64ExecutableWriter.h"
+#include "AArch64LinkingContext.h"
+#include "AArch64TargetHandler.h"
+
+using namespace lld;
+using namespace elf;
+
+AArch64TargetHandler::AArch64TargetHandler(AArch64LinkingContext &context)
+ : _context(context),
+ _AArch64TargetLayout(new AArch64TargetLayout<AArch64ELFType>(context)),
+ _AArch64RelocationHandler(new AArch64TargetRelocationHandler()) {}
+
+void AArch64TargetHandler::registerRelocationNames(Registry &registry) {
+ registry.addKindTable(Reference::KindNamespace::ELF,
+ Reference::KindArch::AArch64, kindStrings);
+}
+
+std::unique_ptr<Writer> AArch64TargetHandler::getWriter() {
+ switch (this->_context.getOutputELFType()) {
+ case llvm::ELF::ET_EXEC:
+ return std::unique_ptr<Writer>(new AArch64ExecutableWriter<AArch64ELFType>(
+ _context, *_AArch64TargetLayout.get()));
+ case llvm::ELF::ET_DYN:
+ return std::unique_ptr<Writer>(
+ new AArch64DynamicLibraryWriter<AArch64ELFType>(
+ _context, *_AArch64TargetLayout.get()));
+ case llvm::ELF::ET_REL:
+ llvm_unreachable("TODO: support -r mode");
+ default:
+ llvm_unreachable("unsupported output type");
+ }
+}
+
+#define ELF_RELOC(name, value) LLD_KIND_STRING_ENTRY(name),
+
+const Registry::KindStrings AArch64TargetHandler::kindStrings[] = {
+#include "llvm/Support/ELFRelocs/AArch64.def"
+ LLD_KIND_STRING_END
+};
+
+#undef ELF_RELOC
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.h b/lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.h
new file mode 100644
index 000000000000..4eb6786cdf1f
--- /dev/null
+++ b/lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.h
@@ -0,0 +1,64 @@
+//===- lib/ReaderWriter/ELF/AArch64/AArch64TargetHandler.h ----------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_AARCH64_AARCH64_TARGET_HANDLER_H
+#define LLD_READER_WRITER_ELF_AARCH64_AARCH64_TARGET_HANDLER_H
+
+#include "AArch64ELFFile.h"
+#include "AArch64ELFReader.h"
+#include "AArch64RelocationHandler.h"
+#include "DefaultTargetHandler.h"
+#include "TargetLayout.h"
+#include "lld/Core/Simple.h"
+
+namespace lld {
+namespace elf {
+class AArch64LinkingContext;
+
+template <class ELFT> class AArch64TargetLayout : public TargetLayout<ELFT> {
+public:
+ AArch64TargetLayout(AArch64LinkingContext &context)
+ : TargetLayout<ELFT>(context) {}
+};
+
+class AArch64TargetHandler final : public DefaultTargetHandler<AArch64ELFType> {
+public:
+ AArch64TargetHandler(AArch64LinkingContext &context);
+
+ AArch64TargetLayout<AArch64ELFType> &getTargetLayout() override {
+ return *(_AArch64TargetLayout.get());
+ }
+
+ void registerRelocationNames(Registry &registry) override;
+
+ const AArch64TargetRelocationHandler &getRelocationHandler() const override {
+ return *(_AArch64RelocationHandler.get());
+ }
+
+ std::unique_ptr<Reader> getObjReader() override {
+ return std::unique_ptr<Reader>(new AArch64ELFObjectReader(_context));
+ }
+
+ std::unique_ptr<Reader> getDSOReader() override {
+ return std::unique_ptr<Reader>(new AArch64ELFDSOReader(_context));
+ }
+
+ std::unique_ptr<Writer> getWriter() override;
+
+private:
+ static const Registry::KindStrings kindStrings[];
+ AArch64LinkingContext &_context;
+ std::unique_ptr<AArch64TargetLayout<AArch64ELFType>> _AArch64TargetLayout;
+ std::unique_ptr<AArch64TargetRelocationHandler> _AArch64RelocationHandler;
+};
+
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/AArch64/CMakeLists.txt b/lib/ReaderWriter/ELF/AArch64/CMakeLists.txt
new file mode 100644
index 000000000000..de94a4df5078
--- /dev/null
+++ b/lib/ReaderWriter/ELF/AArch64/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_llvm_library(lldAArch64ELFTarget
+ AArch64LinkingContext.cpp
+ AArch64TargetHandler.cpp
+ AArch64RelocationHandler.cpp
+ AArch64RelocationPass.cpp
+ LINK_LIBS
+ lldELF
+ lldReaderWriter
+ lldCore
+ LLVMObject
+ LLVMSupport
+ )
diff --git a/lib/ReaderWriter/ELF/AArch64/Makefile b/lib/ReaderWriter/ELF/AArch64/Makefile
new file mode 100644
index 000000000000..02cff4747d0d
--- /dev/null
+++ b/lib/ReaderWriter/ELF/AArch64/Makefile
@@ -0,0 +1,15 @@
+##===- lld/lib/ReaderWriter/ELF/AArch64/Makefile ----------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLD_LEVEL := ../../../..
+LIBRARYNAME := lldAArch64ELFTarget
+USEDLIBS = lldCore.a
+CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF/AArch64 -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF
+
+include $(LLD_LEVEL)/Makefile
diff --git a/lib/ReaderWriter/ELF/AArch64/TODO.rst b/lib/ReaderWriter/ELF/AArch64/TODO.rst
new file mode 100644
index 000000000000..aa6f616ff33f
--- /dev/null
+++ b/lib/ReaderWriter/ELF/AArch64/TODO.rst
@@ -0,0 +1,15 @@
+ELF AArch64
+~~~~~~~~~~~
+
+Unimplemented Features
+######################
+
+* Just about everything!
+
+Unimplemented Relocations
+#########################
+
+All of these relocations are defined in:
+http://infocenter.arm.com/help/topic/com.arm.doc.ihi0056b/IHI0056B_aaelf64.pdf
+
+
diff --git a/lib/ReaderWriter/ELF/ARM/ARMELFFile.h b/lib/ReaderWriter/ELF/ARM/ARMELFFile.h
new file mode 100644
index 000000000000..bc5ee35b8213
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ARM/ARMELFFile.h
@@ -0,0 +1,97 @@
+//===--------- lib/ReaderWriter/ELF/ARM/ARMELFFile.h ----------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_ARM_ARM_ELF_FILE_H
+#define LLD_READER_WRITER_ELF_ARM_ARM_ELF_FILE_H
+
+#include "ELFReader.h"
+
+namespace lld {
+namespace elf {
+
+class ARMLinkingContext;
+
+template <class ELFT> class ARMELFDefinedAtom : public ELFDefinedAtom<ELFT> {
+ typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+ typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr;
+
+public:
+ ARMELFDefinedAtom(const ELFFile<ELFT> &file, StringRef symbolName,
+ StringRef sectionName, const Elf_Sym *symbol,
+ const Elf_Shdr *section, ArrayRef<uint8_t> contentData,
+ unsigned int referenceStart, unsigned int referenceEnd,
+ std::vector<ELFReference<ELFT> *> &referenceList)
+ : ELFDefinedAtom<ELFT>(file, symbolName, sectionName, symbol, section,
+ contentData, referenceStart, referenceEnd,
+ referenceList) {}
+
+ bool isThumbFunc(const Elf_Sym *symbol) const {
+ return symbol->getType() == llvm::ELF::STT_FUNC &&
+ (static_cast<uint64_t>(symbol->st_value) & 0x1);
+ }
+
+ /// Correct st_value for symbols addressing Thumb instructions
+ /// by removing its zero bit.
+ uint64_t getSymbolValue(const Elf_Sym *symbol) const override {
+ const auto value = static_cast<uint64_t>(symbol->st_value);
+ return isThumbFunc(symbol) ? value & ~0x1 : value;
+ }
+
+ DefinedAtom::CodeModel codeModel() const override {
+ if (isThumbFunc(this->_symbol))
+ return DefinedAtom::codeARMThumb;
+ return DefinedAtom::codeNA;
+ }
+};
+
+template <class ELFT> class ARMELFFile : public ELFFile<ELFT> {
+public:
+ ARMELFFile(std::unique_ptr<MemoryBuffer> mb, ARMLinkingContext &ctx)
+ : ELFFile<ELFT>(std::move(mb), ctx) {}
+
+ static ErrorOr<std::unique_ptr<ARMELFFile>>
+ create(std::unique_ptr<MemoryBuffer> mb, ARMLinkingContext &ctx) {
+ return std::unique_ptr<ARMELFFile<ELFT>>(
+ new ARMELFFile<ELFT>(std::move(mb), ctx));
+ }
+
+private:
+ typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+ typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr;
+
+ /// Correct st_value for symbols addressing Thumb instructions
+ /// by removing its zero bit.
+ uint64_t getSymbolValue(const Elf_Sym *symbol) const override {
+ const auto value = static_cast<uint64_t>(symbol->st_value);
+ return symbol->getType() == llvm::ELF::STT_FUNC ? value & ~0x1 : value;
+ }
+
+ /// Process the Defined symbol and create an atom for it.
+ ErrorOr<ELFDefinedAtom<ELFT> *> handleDefinedSymbol(StringRef symName,
+ StringRef sectionName,
+ const Elf_Sym *sym, const Elf_Shdr *sectionHdr,
+ ArrayRef<uint8_t> contentData,
+ unsigned int referenceStart, unsigned int referenceEnd,
+ std::vector<ELFReference<ELFT> *> &referenceList) override {
+ return new (this->_readerStorage) ARMELFDefinedAtom<ELFT>(
+ *this, symName, sectionName, sym, sectionHdr, contentData,
+ referenceStart, referenceEnd, referenceList);
+ }
+};
+
+template <class ELFT> class ARMDynamicFile : public DynamicFile<ELFT> {
+public:
+ ARMDynamicFile(const ARMLinkingContext &context, StringRef name)
+ : DynamicFile<ELFT>(context, name) {}
+};
+
+} // elf
+} // lld
+
+#endif // LLD_READER_WRITER_ELF_ARM_ARM_ELF_FILE_H
diff --git a/lib/ReaderWriter/ELF/ARM/ARMELFReader.h b/lib/ReaderWriter/ELF/ARM/ARMELFReader.h
new file mode 100644
index 000000000000..31af531563ea
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ARM/ARMELFReader.h
@@ -0,0 +1,62 @@
+//===--------- lib/ReaderWriter/ELF/ARM/ARMELFReader.h --------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ARM_ARM_ELF_READER_H
+#define LLD_READER_WRITER_ARM_ARM_ELF_READER_H
+
+#include "ARMELFFile.h"
+#include "ELFReader.h"
+
+namespace lld {
+namespace elf {
+
+typedef llvm::object::ELFType<llvm::support::little, 2, false> ARMELFType;
+
+struct ARMDynamicFileCreateELFTraits {
+ typedef llvm::ErrorOr<std::unique_ptr<lld::SharedLibraryFile>> result_type;
+
+ template <class ELFT>
+ static result_type create(std::unique_ptr<llvm::MemoryBuffer> mb,
+ ARMLinkingContext &ctx) {
+ return lld::elf::ARMDynamicFile<ELFT>::create(std::move(mb), ctx);
+ }
+};
+
+struct ARMELFFileCreateELFTraits {
+ typedef llvm::ErrorOr<std::unique_ptr<lld::File>> result_type;
+
+ template <class ELFT>
+ static result_type create(std::unique_ptr<llvm::MemoryBuffer> mb,
+ ARMLinkingContext &ctx) {
+ return lld::elf::ARMELFFile<ELFT>::create(std::move(mb), ctx);
+ }
+};
+
+class ARMELFObjectReader
+ : public ELFObjectReader<ARMELFType, ARMELFFileCreateELFTraits,
+ ARMLinkingContext> {
+public:
+ ARMELFObjectReader(ARMLinkingContext &ctx)
+ : ELFObjectReader<ARMELFType, ARMELFFileCreateELFTraits,
+ ARMLinkingContext>(ctx, llvm::ELF::EM_ARM) {}
+};
+
+class ARMELFDSOReader
+ : public ELFDSOReader<ARMELFType, ARMDynamicFileCreateELFTraits,
+ ARMLinkingContext> {
+public:
+ ARMELFDSOReader(ARMLinkingContext &ctx)
+ : ELFDSOReader<ARMELFType, ARMDynamicFileCreateELFTraits,
+ ARMLinkingContext>(ctx, llvm::ELF::EM_ARM) {}
+};
+
+} // namespace elf
+} // namespace lld
+
+#endif // LLD_READER_WRITER_ARM_ARM_ELF_READER_H
diff --git a/lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h b/lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h
new file mode 100644
index 000000000000..19311d516e4d
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h
@@ -0,0 +1,121 @@
+//===--------- lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h -------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLD_READER_WRITER_ELF_ARM_ARM_EXECUTABLE_WRITER_H
+#define LLD_READER_WRITER_ELF_ARM_ARM_EXECUTABLE_WRITER_H
+
+#include "ExecutableWriter.h"
+#include "ARMLinkingContext.h"
+#include "ARMTargetHandler.h"
+#include "ARMSymbolTable.h"
+
+namespace {
+const char *gotSymbol = "_GLOBAL_OFFSET_TABLE_";
+}
+
+namespace lld {
+namespace elf {
+
+template <class ELFT>
+class ARMExecutableWriter : public ExecutableWriter<ELFT> {
+public:
+ ARMExecutableWriter(ARMLinkingContext &context,
+ ARMTargetLayout<ELFT> &layout);
+
+protected:
+ // Add any runtime files and their atoms to the output
+ bool createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
+
+ void finalizeDefaultAtomValues() override;
+
+ void addDefaultAtoms() override {
+ ExecutableWriter<ELFT>::addDefaultAtoms();
+ }
+
+ /// \brief Create symbol table.
+ unique_bump_ptr<SymbolTable<ELFT>> createSymbolTable() override;
+
+ void processUndefinedSymbol(StringRef symName,
+ RuntimeFile<ELFT> &file) const override;
+
+ // Setup the ELF header.
+ std::error_code setELFHeader() override;
+
+private:
+ ARMLinkingContext &_context;
+ ARMTargetLayout<ELFT> &_armLayout;
+};
+
+template <class ELFT>
+ARMExecutableWriter<ELFT>::ARMExecutableWriter(ARMLinkingContext &context,
+ ARMTargetLayout<ELFT> &layout)
+ : ExecutableWriter<ELFT>(context, layout), _context(context),
+ _armLayout(layout) {}
+
+template <class ELFT>
+bool ARMExecutableWriter<ELFT>::createImplicitFiles(
+ std::vector<std::unique_ptr<File>> &result) {
+ ExecutableWriter<ELFT>::createImplicitFiles(result);
+ return true;
+}
+
+template <class ELFT>
+void ARMExecutableWriter<ELFT>::finalizeDefaultAtomValues() {
+ // Finalize the atom values that are part of the parent.
+ ExecutableWriter<ELFT>::finalizeDefaultAtomValues();
+ auto gotAtomIter = _armLayout.findAbsoluteAtom(gotSymbol);
+ if (gotAtomIter != _armLayout.absoluteAtoms().end()) {
+ auto *gotAtom = *gotAtomIter;
+ if (auto gotpltSection = _armLayout.findOutputSection(".got.plt"))
+ gotAtom->_virtualAddr = gotpltSection->virtualAddr();
+ else if (auto gotSection = _armLayout.findOutputSection(".got"))
+ gotAtom->_virtualAddr = gotSection->virtualAddr();
+ else
+ gotAtom->_virtualAddr = 0;
+ }
+ // TODO: resolve addresses of __exidx_start/_end atoms
+}
+
+template <class ELFT>
+unique_bump_ptr<SymbolTable<ELFT>>
+ ARMExecutableWriter<ELFT>::createSymbolTable() {
+ return unique_bump_ptr<SymbolTable<ELFT>>(
+ new (this->_alloc) ARMSymbolTable<ELFT>(this->_context));
+}
+
+template <class ELFT>
+void ARMExecutableWriter<ELFT>::processUndefinedSymbol(
+ StringRef symName, RuntimeFile<ELFT> &file) const {
+ if (symName == gotSymbol) {
+ file.addAbsoluteAtom(gotSymbol);
+ } else if (symName.startswith("__exidx")) {
+ file.addAbsoluteAtom("__exidx_start");
+ file.addAbsoluteAtom("__exidx_end");
+ }
+}
+
+template <class ELFT>
+std::error_code ARMExecutableWriter<ELFT>::setELFHeader() {
+ if (std::error_code ec = ExecutableWriter<ELFT>::setELFHeader())
+ return ec;
+
+ // Fixup entry point for Thumb code.
+ StringRef entryName = _context.entrySymbolName();
+ if (const AtomLayout *al = _armLayout.findAtomLayoutByName(entryName)) {
+ const auto *ea = dyn_cast<DefinedAtom>(al->_atom);
+ if (ea && ea->codeModel() == DefinedAtom::codeARMThumb)
+ this->_elfHeader->e_entry(al->_virtualAddr | 0x1);
+ }
+
+ return std::error_code();
+}
+
+} // namespace elf
+} // namespace lld
+
+#endif // LLD_READER_WRITER_ELF_ARM_ARM_EXECUTABLE_WRITER_H
diff --git a/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp b/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp
new file mode 100644
index 000000000000..5f2436674268
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp
@@ -0,0 +1,34 @@
+//===--------- lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp -------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ARMLinkingContext.h"
+#include "ARMRelocationPass.h"
+#include "ARMTargetHandler.h"
+
+using namespace lld;
+using namespace lld::elf;
+
+std::unique_ptr<ELFLinkingContext>
+elf::ARMLinkingContext::create(llvm::Triple triple) {
+ if (triple.getArch() == llvm::Triple::arm)
+ return std::unique_ptr<ELFLinkingContext>(
+ new elf::ARMLinkingContext(triple));
+ return nullptr;
+}
+
+elf::ARMLinkingContext::ARMLinkingContext(llvm::Triple triple)
+ : ELFLinkingContext(triple, std::unique_ptr<TargetHandlerBase>(
+ new ARMTargetHandler(*this))) {}
+
+void elf::ARMLinkingContext::addPasses(PassManager &pm) {
+ auto pass = createARMRelocationPass(*this);
+ if (pass)
+ pm.add(std::move(pass));
+ ELFLinkingContext::addPasses(pm);
+}
diff --git a/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h b/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h
new file mode 100644
index 000000000000..249b79c4f07d
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h
@@ -0,0 +1,36 @@
+//===--------- lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h ---------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_ARM_ARM_LINKING_CONTEXT_H
+#define LLD_READER_WRITER_ELF_ARM_ARM_LINKING_CONTEXT_H
+
+#include "lld/ReaderWriter/ELFLinkingContext.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/ELF.h"
+
+namespace lld {
+namespace elf {
+
+class ARMLinkingContext final : public ELFLinkingContext {
+public:
+ static std::unique_ptr<ELFLinkingContext> create(llvm::Triple);
+ ARMLinkingContext(llvm::Triple);
+
+ void addPasses(PassManager &) override;
+
+ uint64_t getBaseAddress() const override {
+ if (_baseAddress == 0)
+ return 0x400000;
+ return _baseAddress;
+ }
+};
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp b/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp
new file mode 100644
index 000000000000..d24fdf0fa410
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp
@@ -0,0 +1,500 @@
+//===--------- lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp ----------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ARMTargetHandler.h"
+#include "ARMLinkingContext.h"
+
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/MathExtras.h"
+
+using namespace lld;
+using namespace lld::elf;
+using namespace llvm::support::endian;
+
+static Reference::Addend readAddend_THM_MOV(const uint8_t *location) {
+ const uint16_t halfHi = read16le(location);
+ const uint16_t halfLo = read16le(location + 2);
+
+ const uint16_t imm8 = halfLo & 0xFF;
+ const uint16_t imm3 = (halfLo >> 12) & 0x7;
+
+ const uint16_t imm4 = halfHi & 0xF;
+ const uint16_t bitI = (halfHi >> 10) & 0x1;
+
+ const auto result = int16_t((imm4 << 12) | (bitI << 11) | (imm3 << 8) | imm8);
+ return result;
+}
+
+static Reference::Addend readAddend_ARM_MOV(const uint8_t *location) {
+ const uint32_t value = read32le(location);
+
+ const uint32_t imm12 = value & 0xFFF;
+ const uint32_t imm4 = (value >> 16) & 0xF;
+
+ const auto result = int32_t((imm4 << 12) | imm12);
+ return result;
+}
+
+static Reference::Addend readAddend_THM_CALL(const uint8_t *location) {
+ const uint16_t halfHi = read16le(location);
+ const uint16_t halfLo = read16le(location + 2);
+
+ const uint16_t imm10 = halfHi & 0x3FF;
+ const uint16_t bitS = (halfHi >> 10) & 0x1;
+
+ const uint16_t imm11 = halfLo & 0x7FF;
+ const uint16_t bitJ2 = (halfLo >> 11) & 0x1;
+ const uint16_t bitI2 = (~(bitJ2 ^ bitS)) & 0x1;
+ const uint16_t bitJ1 = (halfLo >> 13) & 0x1;
+ const uint16_t bitI1 = (~(bitJ1 ^ bitS)) & 0x1;
+
+ const auto result = int32_t((bitS << 24) | (bitI1 << 23) | (bitI2 << 22) |
+ (imm10 << 12) | (imm11 << 1));
+ return llvm::SignExtend64<25>(result);
+}
+
+static Reference::Addend readAddend_ARM_CALL(const uint8_t *location) {
+ const uint32_t value = read32le(location);
+
+ const bool isBLX = (value & 0xF0000000) == 0xF0000000;
+ const uint32_t bitH = isBLX ? ((value & 0x1000000) >> 24) : 0;
+
+ const auto result = int32_t(((value & 0xFFFFFF) << 2) | (bitH << 1));
+ return llvm::SignExtend64<26>(result);
+}
+
+static Reference::Addend readAddend_THM_JUMP11(const uint8_t *location) {
+ const auto value = read16le(location);
+ const uint16_t imm11 = value & 0x7FF;
+
+ return llvm::SignExtend32<12>(imm11 << 1);
+}
+
+static Reference::Addend readAddend(const uint8_t *location,
+ Reference::KindValue kindValue) {
+ switch (kindValue) {
+ case R_ARM_ABS32:
+ case R_ARM_REL32:
+ case R_ARM_TLS_IE32:
+ case R_ARM_TLS_LE32:
+ return (int32_t)read32le(location);
+ case R_ARM_PREL31:
+ return (int32_t)(read32le(location) & 0x7FFFFFFF);
+ case R_ARM_THM_CALL:
+ case R_ARM_THM_JUMP24:
+ return readAddend_THM_CALL(location);
+ case R_ARM_THM_JUMP11:
+ return readAddend_THM_JUMP11(location);
+ case R_ARM_CALL:
+ case R_ARM_JUMP24:
+ return readAddend_ARM_CALL(location);
+ case R_ARM_MOVW_ABS_NC:
+ case R_ARM_MOVT_ABS:
+ return readAddend_ARM_MOV(location);
+ case R_ARM_THM_MOVW_ABS_NC:
+ case R_ARM_THM_MOVT_ABS:
+ return readAddend_THM_MOV(location);
+ default:
+ return 0;
+ }
+}
+
+static inline void applyArmReloc(uint8_t *location, uint32_t result,
+ uint32_t mask = 0xFFFFFFFF) {
+ assert(!(result & ~mask));
+ write32le(location, (read32le(location) & ~mask) | (result & mask));
+}
+
+static inline void applyThmReloc(uint8_t *location, uint16_t resHi,
+ uint16_t resLo, uint16_t maskHi,
+ uint16_t maskLo = 0xFFFF) {
+ assert(!(resHi & ~maskHi) && !(resLo & ~maskLo));
+ write16le(location, (read16le(location) & ~maskHi) | (resHi & maskHi));
+ location += 2;
+ write16le(location, (read16le(location) & ~maskLo) | (resLo & maskLo));
+}
+
+static inline void applyThumb16Reloc(uint8_t *location, uint16_t result,
+ uint16_t mask = 0xFFFF) {
+ assert(!(result & ~mask));
+ write16le(location, (read16le(location) & ~mask) | (result & mask));
+}
+
+/// \brief R_ARM_ABS32 - (S + A) | T
+static void relocR_ARM_ABS32(uint8_t *location, uint64_t P, uint64_t S,
+ int64_t A, bool addressesThumb) {
+ uint64_t T = addressesThumb;
+ uint32_t result = (uint32_t)((S + A) | T);
+
+ DEBUG_WITH_TYPE(
+ "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
+ llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
+ llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
+ llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
+ llvm::dbgs() << " T: 0x" << Twine::utohexstr(T);
+ llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
+ applyArmReloc(location, result);
+}
+
+/// \brief R_ARM_REL32 - ((S + A) | T) - P
+static void relocR_ARM_REL32(uint8_t *location, uint64_t P, uint64_t S,
+ int64_t A, bool addressesThumb) {
+ uint64_t T = addressesThumb;
+ uint32_t result = (uint32_t)(((S + A) | T) - P);
+
+ DEBUG_WITH_TYPE(
+ "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
+ llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
+ llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
+ llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
+ llvm::dbgs() << " T: 0x" << Twine::utohexstr(T);
+ llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
+ applyArmReloc(location, result);
+}
+
+/// \brief R_ARM_PREL31 - ((S + A) | T) - P
+static void relocR_ARM_PREL31(uint8_t *location, uint64_t P, uint64_t S,
+ int64_t A, bool addressesThumb) {
+ uint64_t T = addressesThumb;
+ uint32_t result = (uint32_t)(((S + A) | T) - P);
+ const uint32_t mask = 0x7FFFFFFF;
+ uint32_t rel31 = result & mask;
+
+ DEBUG_WITH_TYPE(
+ "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
+ llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
+ llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
+ llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
+ llvm::dbgs() << " T: 0x" << Twine::utohexstr(T);
+ llvm::dbgs() << " result: 0x" << Twine::utohexstr(result);
+ llvm::dbgs() << " rel31: 0x" << Twine::utohexstr(rel31) << "\n");
+
+ applyArmReloc(location, rel31, mask);
+}
+
+/// \brief Relocate B/BL instructions. useJs defines whether J1 & J2 are used
+static void relocR_ARM_THM_B_L(uint8_t *location, uint32_t result, bool useJs) {
+ result = (result & 0x01FFFFFE) >> 1;
+
+ const uint16_t imm10 = (result >> 11) & 0x3FF;
+ const uint16_t bitS = (result >> 23) & 0x1;
+ const uint16_t resHi = (bitS << 10) | imm10;
+
+ const uint16_t imm11 = result & 0x7FF;
+ const uint16_t bitJ2 = useJs ? ((result >> 21) & 0x1) : bitS;
+ const uint16_t bitI2 = (~(bitJ2 ^ bitS)) & 0x1;
+ const uint16_t bitJ1 = useJs ? ((result >> 22) & 0x1) : bitS;
+ const uint16_t bitI1 = (~(bitJ1 ^ bitS)) & 0x1;
+ const uint16_t resLo = (bitI1 << 13) | (bitI2 << 11) | imm11;
+
+ applyThmReloc(location, resHi, resLo, 0x7FF, 0x2FFF);
+}
+
+/// \brief R_ARM_THM_CALL - ((S + A) | T) - P
+static void relocR_ARM_THM_CALL(uint8_t *location, uint64_t P, uint64_t S,
+ int64_t A, bool useJs, bool addressesThumb) {
+ uint64_t T = addressesThumb;
+ const bool switchMode = !addressesThumb;
+
+ if (switchMode) {
+ P &= ~0x3; // Align(P, 4) by rounding down
+ }
+
+ uint32_t result = (uint32_t)(((S + A) | T) - P);
+
+ DEBUG_WITH_TYPE(
+ "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
+ llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
+ llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
+ llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
+ llvm::dbgs() << " T: 0x" << Twine::utohexstr(T);
+ llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
+ relocR_ARM_THM_B_L(location, result, useJs);
+
+ if (switchMode) {
+ applyThmReloc(location, 0, 0, 0, 0x1001);
+ }
+}
+
+/// \brief R_ARM_THM_JUMP24 - ((S + A) | T) - P
+static void relocR_ARM_THM_JUMP24(uint8_t *location, uint64_t P, uint64_t S,
+ int64_t A, bool addressesThumb) {
+ uint64_t T = addressesThumb;
+ uint32_t result = (uint32_t)(((S + A) | T) - P);
+
+ DEBUG_WITH_TYPE(
+ "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
+ llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
+ llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
+ llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
+ llvm::dbgs() << " T: 0x" << Twine::utohexstr(T);
+ llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
+ relocR_ARM_THM_B_L(location, result, true);
+}
+
+/// \brief R_ARM_THM_JUMP11 - S + A - P
+static void relocR_ARM_THM_JUMP11(uint8_t *location, uint64_t P, uint64_t S,
+ int64_t A) {
+ uint32_t result = (uint32_t)(S + A - P);
+
+ DEBUG_WITH_TYPE(
+ "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
+ llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
+ llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
+ llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
+ llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
+
+ //we cut off first bit because it is always 1 according to p. 4.5.3
+ result = (result & 0x0FFE) >> 1;
+
+ applyThumb16Reloc(location, result, 0x7FF);
+}
+
+/// \brief R_ARM_CALL - ((S + A) | T) - P
+static void relocR_ARM_CALL(uint8_t *location, uint64_t P, uint64_t S,
+ int64_t A, bool addressesThumb) {
+ uint64_t T = addressesThumb;
+ const bool switchMode = addressesThumb;
+
+ uint32_t result = (uint32_t)(((S + A) | T) - P);
+ const uint32_t imm24 = (result & 0x03FFFFFC) >> 2;
+
+ DEBUG_WITH_TYPE(
+ "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
+ llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
+ llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
+ llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
+ llvm::dbgs() << " T: 0x" << Twine::utohexstr(T);
+ llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
+ applyArmReloc(location, imm24, 0xFFFFFF);
+
+ if (switchMode) {
+ const uint32_t bitH = (result & 0x2) >> 1;
+ applyArmReloc(location, (0xFA | bitH) << 24, 0xFF000000);
+ }
+}
+
+/// \brief R_ARM_JUMP24 - ((S + A) | T) - P
+static void relocR_ARM_JUMP24(uint8_t *location, uint64_t P, uint64_t S,
+ int64_t A, bool addressesThumb) {
+ uint64_t T = addressesThumb;
+ uint32_t result = (uint32_t)(((S + A) | T) - P);
+ const uint32_t imm24 = (result & 0x03FFFFFC) >> 2;
+
+ DEBUG_WITH_TYPE(
+ "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
+ llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
+ llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
+ llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
+ llvm::dbgs() << " T: 0x" << Twine::utohexstr(T);
+ llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
+ applyArmReloc(location, imm24, 0xFFFFFF);
+}
+
+/// \brief Relocate ARM MOVW/MOVT instructions
+static void relocR_ARM_MOV(uint8_t *location, uint32_t result) {
+ const uint32_t imm12 = result & 0xFFF;
+ const uint32_t imm4 = (result >> 12) & 0xF;
+
+ applyArmReloc(location, (imm4 << 16) | imm12, 0xF0FFF);
+}
+
+/// \brief R_ARM_MOVW_ABS_NC - (S + A) | T
+static void relocR_ARM_MOVW_ABS_NC(uint8_t *location, uint64_t P, uint64_t S,
+ int64_t A, bool addressesThumb) {
+ uint64_t T = addressesThumb;
+ uint32_t result = (uint32_t)((S + A) | T);
+ const uint32_t arg = result & 0x0000FFFF;
+
+ DEBUG_WITH_TYPE(
+ "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
+ llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
+ llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
+ llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
+ llvm::dbgs() << " T: 0x" << Twine::utohexstr(T);
+ llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
+ return relocR_ARM_MOV(location, arg);
+}
+
+/// \brief R_ARM_MOVT_ABS - S + A
+static void relocR_ARM_MOVT_ABS(uint8_t *location, uint64_t P, uint64_t S,
+ int64_t A) {
+ uint32_t result = (uint32_t)(S + A);
+ const uint32_t arg = (result & 0xFFFF0000) >> 16;
+
+ DEBUG_WITH_TYPE(
+ "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
+ llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
+ llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
+ llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
+ llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
+ return relocR_ARM_MOV(location, arg);
+}
+
+/// \brief Relocate Thumb MOVW/MOVT instructions
+static void relocR_ARM_THM_MOV(uint8_t *location, uint32_t result) {
+ const uint16_t imm8 = result & 0xFF;
+ const uint16_t imm3 = (result >> 8) & 0x7;
+ const uint16_t resLo = (imm3 << 12) | imm8;
+
+ const uint16_t imm4 = (result >> 12) & 0xF;
+ const uint16_t bitI = (result >> 11) & 0x1;
+ const uint16_t resHi = (bitI << 10) | imm4;
+
+ applyThmReloc(location, resHi, resLo, 0x40F, 0x70FF);
+}
+
+/// \brief R_ARM_THM_MOVW_ABS_NC - (S + A) | T
+static void relocR_ARM_THM_MOVW_ABS_NC(uint8_t *location, uint64_t P,
+ uint64_t S, int64_t A,
+ bool addressesThumb) {
+ uint64_t T = addressesThumb;
+ uint32_t result = (uint32_t)((S + A) | T);
+ const uint32_t arg = result & 0x0000FFFF;
+
+ DEBUG_WITH_TYPE(
+ "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
+ llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
+ llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
+ llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
+ llvm::dbgs() << " T: 0x" << Twine::utohexstr(T);
+ llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
+ return relocR_ARM_THM_MOV(location, arg);
+}
+
+/// \brief R_ARM_THM_MOVT_ABS - S + A
+static void relocR_ARM_THM_MOVT_ABS(uint8_t *location, uint64_t P, uint64_t S,
+ int64_t A) {
+ uint32_t result = (uint32_t)(S + A);
+ const uint32_t arg = (result & 0xFFFF0000) >> 16;
+
+ DEBUG_WITH_TYPE(
+ "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
+ llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
+ llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
+ llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
+ llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
+ return relocR_ARM_THM_MOV(location, arg);
+}
+
+/// \brief R_ARM_TLS_IE32 - GOT(S) + A - P => S + A - P
+static void relocR_ARM_TLS_IE32(uint8_t *location, uint64_t P, uint64_t S,
+ int64_t A) {
+ uint32_t result = (uint32_t)(S + A - P);
+
+ DEBUG_WITH_TYPE(
+ "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
+ llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
+ llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
+ llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
+ llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
+ applyArmReloc(location, result);
+}
+
+/// \brief R_ARM_TLS_LE32 - S + A - tp => S + A + tpoff
+static void relocR_ARM_TLS_LE32(uint8_t *location, uint64_t P, uint64_t S,
+ int64_t A, uint64_t tpoff) {
+ uint32_t result = (uint32_t)(S + A + tpoff);
+
+ DEBUG_WITH_TYPE(
+ "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
+ llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
+ llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
+ llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
+ llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
+ applyArmReloc(location, result);
+}
+
+std::error_code ARMTargetRelocationHandler::applyRelocation(
+ ELFWriter &writer, llvm::FileOutputBuffer &buf, const lld::AtomLayout &atom,
+ const Reference &ref) const {
+ uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset;
+ uint8_t *location = atomContent + ref.offsetInAtom();
+ uint64_t targetVAddress = writer.addressOfAtom(ref.target());
+ uint64_t relocVAddress = atom._virtualAddr + ref.offsetInAtom();
+
+ if (ref.kindNamespace() != Reference::KindNamespace::ELF)
+ return std::error_code();
+ assert(ref.kindArch() == Reference::KindArch::ARM);
+
+ // Calculate proper initial addend for the relocation
+ const Reference::Addend addend =
+ readAddend(location, ref.kindValue());
+
+ // Flags that the relocation addresses Thumb instruction
+ bool addressesThumb = false;
+
+ if (const auto *definedAtom = dyn_cast<DefinedAtom>(ref.target())) {
+ addressesThumb = (DefinedAtom::codeARMThumb == definedAtom->codeModel());
+ }
+
+ switch (ref.kindValue()) {
+ case R_ARM_NONE:
+ break;
+ case R_ARM_ABS32:
+ relocR_ARM_ABS32(location, relocVAddress, targetVAddress, addend,
+ addressesThumb);
+ break;
+ case R_ARM_REL32:
+ relocR_ARM_REL32(location, relocVAddress, targetVAddress, addend,
+ addressesThumb);
+ break;
+ case R_ARM_THM_CALL:
+ // TODO: consider adding bool variable to disable J1 & J2 for archs
+ // before ARMv6
+ relocR_ARM_THM_CALL(location, relocVAddress, targetVAddress, addend, true,
+ addressesThumb);
+ break;
+ case R_ARM_CALL:
+ relocR_ARM_CALL(location, relocVAddress, targetVAddress, addend,
+ addressesThumb);
+ break;
+ case R_ARM_JUMP24:
+ relocR_ARM_JUMP24(location, relocVAddress, targetVAddress, addend,
+ addressesThumb);
+ break;
+ case R_ARM_THM_JUMP24:
+ relocR_ARM_THM_JUMP24(location, relocVAddress, targetVAddress, addend,
+ addressesThumb);
+ break;
+ case R_ARM_THM_JUMP11:
+ relocR_ARM_THM_JUMP11(location, relocVAddress, targetVAddress, addend);
+ break;
+ case R_ARM_MOVW_ABS_NC:
+ relocR_ARM_MOVW_ABS_NC(location, relocVAddress, targetVAddress, addend,
+ addressesThumb);
+ break;
+ case R_ARM_MOVT_ABS:
+ relocR_ARM_MOVT_ABS(location, relocVAddress, targetVAddress, addend);
+ break;
+ case R_ARM_THM_MOVW_ABS_NC:
+ relocR_ARM_THM_MOVW_ABS_NC(location, relocVAddress, targetVAddress, addend,
+ addressesThumb);
+ break;
+ case R_ARM_THM_MOVT_ABS:
+ relocR_ARM_THM_MOVT_ABS(location, relocVAddress, targetVAddress, addend);
+ break;
+ case R_ARM_PREL31:
+ relocR_ARM_PREL31(location, relocVAddress, targetVAddress, addend,
+ addressesThumb);
+ break;
+ case R_ARM_TLS_IE32:
+ relocR_ARM_TLS_IE32(location, relocVAddress, targetVAddress, addend);
+ break;
+ case R_ARM_TLS_LE32:
+ relocR_ARM_TLS_LE32(location, relocVAddress, targetVAddress, addend,
+ _armLayout.getTPOffset());
+ break;
+ default:
+ return make_unhandled_reloc_error();
+ }
+
+ return std::error_code();
+}
diff --git a/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h b/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h
new file mode 100644
index 000000000000..227d68617bf9
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h
@@ -0,0 +1,38 @@
+//===--------- lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h ------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_ARM_ARM_RELOCATION_HANDLER_H
+#define LLD_READER_WRITER_ELF_ARM_ARM_RELOCATION_HANDLER_H
+
+#include "ARMTargetHandler.h"
+
+namespace lld {
+namespace elf {
+typedef llvm::object::ELFType<llvm::support::little, 2, false> ARMELFType;
+
+template <class ELFT> class ARMTargetLayout;
+
+class ARMTargetRelocationHandler final
+ : public TargetRelocationHandler {
+public:
+ ARMTargetRelocationHandler(ARMTargetLayout<ARMELFType> &layout)
+ : _armLayout(layout) {}
+
+ std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &,
+ const lld::AtomLayout &,
+ const Reference &) const override;
+
+private:
+ ARMTargetLayout<ARMELFType> &_armLayout;
+};
+
+} // end namespace elf
+} // end namespace lld
+
+#endif // LLD_READER_WRITER_ELF_ARM_ARM_RELOCATION_HANDLER_H
diff --git a/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp b/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp
new file mode 100644
index 000000000000..27ec66ac5557
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp
@@ -0,0 +1,373 @@
+//===--------- lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp -------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Defines the relocation processing pass for ARM. This includes
+/// GOT and PLT entries, TLS, COPY, and ifunc.
+///
+/// This also includes additional behavior that gnu-ld and gold implement but
+/// which is not specified anywhere.
+///
+//===----------------------------------------------------------------------===//
+
+#include "ARMRelocationPass.h"
+#include "ARMLinkingContext.h"
+#include "Atoms.h"
+#include "lld/Core/Simple.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Debug.h"
+
+using namespace lld;
+using namespace lld::elf;
+using namespace llvm::ELF;
+
+// ARM B/BL instructions of static relocation veneer.
+// TODO: consider different instruction set for archs below ARMv5
+// (one as for Thumb may be used though it's less optimal).
+static const uint8_t Veneer_ARM_B_BL_StaticAtomContent[8] = {
+ 0x04, 0xf0, 0x1f, 0xe5, // ldr pc, [pc, #-4]
+ 0x00, 0x00, 0x00, 0x00 // <target_symbol_address>
+};
+
+// Thumb B/BL instructions of static relocation veneer.
+// TODO: consider different instruction set for archs above ARMv5
+// (one as for ARM may be used since it's more optimal).
+static const uint8_t Veneer_THM_B_BL_StaticAtomContent[8] = {
+ 0x78, 0x47, // bx pc
+ 0x00, 0x00, // nop
+ 0xfe, 0xff, 0xff, 0xea // b <target_symbol_address>
+};
+
+// .got values
+static const uint8_t ARMGotAtomContent[4] = {0};
+
+namespace {
+/// \brief Atoms that hold veneer code.
+class VeneerAtom : public SimpleELFDefinedAtom {
+ StringRef _section;
+
+public:
+ VeneerAtom(const File &f, StringRef secName)
+ : SimpleELFDefinedAtom(f), _section(secName) {}
+
+ Scope scope() const override { return DefinedAtom::scopeTranslationUnit; }
+
+ SectionChoice sectionChoice() const override {
+ return DefinedAtom::sectionBasedOnContent;
+ }
+
+ StringRef customSectionName() const override { return _section; }
+
+ ContentType contentType() const override {
+ return DefinedAtom::typeCode;
+ }
+
+ uint64_t size() const override { return rawContent().size(); }
+
+ ContentPermissions permissions() const override { return permR_X; }
+
+ Alignment alignment() const override { return Alignment(2); }
+
+ StringRef name() const override { return _name; }
+ std::string _name;
+};
+
+/// \brief Atoms that hold veneer for statically relocated
+/// ARM B/BL instructions.
+class Veneer_ARM_B_BL_StaticAtom : public VeneerAtom {
+public:
+ Veneer_ARM_B_BL_StaticAtom(const File &f, StringRef secName)
+ : VeneerAtom(f, secName) {}
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return llvm::makeArrayRef(Veneer_ARM_B_BL_StaticAtomContent);
+ }
+};
+
+/// \brief Atoms that hold veneer for statically relocated
+/// Thumb B/BL instructions.
+class Veneer_THM_B_BL_StaticAtom : public VeneerAtom {
+public:
+ Veneer_THM_B_BL_StaticAtom(const File &f, StringRef secName)
+ : VeneerAtom(f, secName) {}
+
+ DefinedAtom::CodeModel codeModel() const override {
+ return DefinedAtom::codeARMThumb;
+ }
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return llvm::makeArrayRef(Veneer_THM_B_BL_StaticAtomContent);
+ }
+};
+
+/// \brief Atoms that are used by ARM dynamic linking
+class ARMGOTAtom : public GOTAtom {
+public:
+ ARMGOTAtom(const File &f, StringRef secName) : GOTAtom(f, secName) {}
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return llvm::makeArrayRef(ARMGotAtomContent);
+ }
+
+ Alignment alignment() const override { return Alignment(2); }
+};
+
+class ELFPassFile : public SimpleFile {
+public:
+ ELFPassFile(const ELFLinkingContext &eti) : SimpleFile("ELFPassFile") {
+ setOrdinal(eti.getNextOrdinalAndIncrement());
+ }
+
+ llvm::BumpPtrAllocator _alloc;
+};
+
+/// \brief CRTP base for handling relocations.
+template <class Derived> class ARMRelocationPass : public Pass {
+ /// \brief Handle a specific reference.
+ void handleReference(const DefinedAtom &atom, const Reference &ref) {
+ DEBUG_WITH_TYPE(
+ "ARM", llvm::dbgs() << "\t" << LLVM_FUNCTION_NAME << "()"
+ << ": Name of Defined Atom: " << atom.name().str();
+ llvm::dbgs() << " kindValue: " << ref.kindValue() << "\n");
+ if (ref.kindNamespace() != Reference::KindNamespace::ELF)
+ return;
+ assert(ref.kindArch() == Reference::KindArch::ARM);
+ switch (ref.kindValue()) {
+ case R_ARM_JUMP24:
+ case R_ARM_THM_JUMP24:
+ static_cast<Derived *>(this)->handleVeneer(atom, ref);
+ break;
+ case R_ARM_TLS_IE32:
+ static_cast<Derived *>(this)->handleTLSIE32(ref);
+ break;
+ }
+ }
+
+protected:
+ std::error_code handleVeneer(const DefinedAtom &atom, const Reference &ref) {
+ // Target symbol and relocated place should have different
+ // instruction sets in order a veneer to be generated in between.
+ const auto *target = dyn_cast<DefinedAtom>(ref.target());
+ if (!target || target->codeModel() == atom.codeModel())
+ return std::error_code();
+
+ // TODO: For unconditional jump instructions (R_ARM_CALL and R_ARM_THM_CALL)
+ // fixup isn't possible without veneer generation for archs below ARMv5.
+
+ // Veneers may only be generated for STT_FUNC target symbols
+ // or for symbols located in sections different to the place of relocation.
+ const auto kindValue = ref.kindValue();
+ StringRef secName = atom.customSectionName();
+ if (DefinedAtom::typeCode != target->contentType() &&
+ !target->customSectionName().equals(secName)) {
+ StringRef kindValStr;
+ if (!this->_ctx.registry().referenceKindToString(
+ ref.kindNamespace(), ref.kindArch(), kindValue, kindValStr)) {
+ kindValStr = "unknown";
+ }
+
+ std::string errStr =
+ (Twine("Reference of type ") + Twine(kindValue) + " (" + kindValStr +
+ ") from " + atom.name() + "+" + Twine(ref.offsetInAtom()) + " to " +
+ ref.target()->name() + "+" + Twine(ref.addend()) +
+ " cannot be effected without a veneer").str();
+
+ llvm_unreachable(errStr.c_str());
+ }
+
+ const Atom *veneer = nullptr;
+ switch (kindValue) {
+ case R_ARM_JUMP24:
+ veneer = static_cast<Derived *>(this)
+ ->getVeneer_ARM_B_BL(target, secName);
+ break;
+ case R_ARM_THM_JUMP24:
+ veneer = static_cast<Derived *>(this)
+ ->getVeneer_THM_B_BL(target, secName);
+ break;
+ default:
+ llvm_unreachable("Unhandled reference type for veneer generation");
+ }
+
+ assert(veneer && "The veneer is not set");
+ const_cast<Reference &>(ref).setTarget(veneer);
+ return std::error_code();
+ }
+
+ std::error_code handleTLSIE32(const Reference &ref) {
+ if (const auto *target = dyn_cast<DefinedAtom>(ref.target())) {
+ const_cast<Reference &>(ref).setTarget(
+ static_cast<Derived *>(this)->getTLSTPOFF32(target));
+ return std::error_code();
+ }
+ llvm_unreachable("R_ARM_TLS_IE32 reloc targets wrong atom type");
+ }
+
+ /// \brief Create a GOT entry for TLS with reloc type and addend specified.
+ template <Reference::KindValue R_ARM_TLS, Reference::Addend A = 0>
+ const GOTAtom *getGOTTLSEntry(const DefinedAtom *da) {
+ auto got = _gotMap.find(da);
+ if (got != _gotMap.end())
+ return got->second;
+ auto g = new (_file._alloc) ARMGOTAtom(_file, ".got");
+ g->addReferenceELF_ARM(R_ARM_TLS, 0, da, A);
+#ifndef NDEBUG
+ g->_name = "__got_tls_";
+ g->_name += da->name();
+#endif
+ _gotMap[da] = g;
+ _gotVector.push_back(g);
+ return g;
+ }
+
+public:
+ ARMRelocationPass(const ELFLinkingContext &ctx) : _file(ctx), _ctx(ctx) {}
+
+ /// \brief Do the pass.
+ ///
+ /// The goal here is to first process each reference individually. Each call
+ /// to handleReference may modify the reference itself and/or create new
+ /// atoms which must be stored in one of the maps below.
+ ///
+ /// After all references are handled, the atoms created during that are all
+ /// added to mf.
+ void perform(std::unique_ptr<MutableFile> &mf) override {
+ ScopedTask task(getDefaultDomain(), "ARM GOT/PLT Pass");
+ DEBUG_WITH_TYPE(
+ "ARM", llvm::dbgs() << "Undefined Atoms" << "\n";
+ for (const auto &atom
+ : mf->undefined()) {
+ llvm::dbgs() << " Name of Atom: " << atom->name().str() << "\n";
+ }
+
+ llvm::dbgs() << "Shared Library Atoms" << "\n";
+ for (const auto &atom
+ : mf->sharedLibrary()) {
+ llvm::dbgs() << " Name of Atom: " << atom->name().str() << "\n";
+ }
+
+ llvm::dbgs() << "Absolute Atoms" << "\n";
+ for (const auto &atom
+ : mf->absolute()) {
+ llvm::dbgs() << " Name of Atom: " << atom->name().str() << "\n";
+ }
+
+ llvm::dbgs() << "Defined Atoms" << "\n";
+ for (const auto &atom
+ : mf->defined()) {
+ llvm::dbgs() << " Name of Atom: " << atom->name().str() << "\n";
+ });
+
+ // Process all references.
+ for (const auto &atom : mf->defined()) {
+ for (const auto &ref : *atom) {
+ handleReference(*atom, *ref);
+ }
+ }
+
+ // Add all created atoms to the link.
+ uint64_t ordinal = 0;
+ for (auto &got : _gotVector) {
+ got->setOrdinal(ordinal++);
+ mf->addAtom(*got);
+ }
+ for (auto &veneer : _veneerVector) {
+ veneer->setOrdinal(ordinal++);
+ mf->addAtom(*veneer);
+ }
+ }
+
+protected:
+ /// \brief Owner of all the Atoms created by this pass.
+ ELFPassFile _file;
+ const ELFLinkingContext &_ctx;
+
+ /// \brief Map Atoms to their GOT entries.
+ llvm::DenseMap<const Atom *, GOTAtom *> _gotMap;
+
+ /// \brief Map Atoms to their veneers.
+ llvm::DenseMap<const Atom *, VeneerAtom *> _veneerMap;
+
+ /// \brief the list of GOT/PLT atoms
+ std::vector<GOTAtom *> _gotVector;
+
+ /// \brief the list of veneer atoms.
+ std::vector<VeneerAtom *> _veneerVector;
+};
+
+/// This implements the static relocation model. Meaning GOT and PLT entries are
+/// not created for references that can be directly resolved. These are
+/// converted to a direct relocation. For entries that do require a GOT or PLT
+/// entry, that entry is statically bound.
+///
+/// TLS always assumes module 1 and attempts to remove indirection.
+class ARMStaticRelocationPass final
+ : public ARMRelocationPass<ARMStaticRelocationPass> {
+public:
+ ARMStaticRelocationPass(const elf::ARMLinkingContext &ctx)
+ : ARMRelocationPass(ctx) {}
+
+ /// \brief Get the veneer for ARM B/BL instructions.
+ const VeneerAtom *getVeneer_ARM_B_BL(const DefinedAtom *da,
+ StringRef secName) {
+ auto veneer = _veneerMap.find(da);
+ if (_veneerMap.end() != veneer)
+ return veneer->second;
+
+ auto v = new (_file._alloc) Veneer_ARM_B_BL_StaticAtom(_file, secName);
+ v->addReferenceELF_ARM(R_ARM_ABS32, 4, da, 0);
+
+ v->_name = "__";
+ v->_name += da->name();
+ v->_name += "_from_arm";
+
+ _veneerMap[da] = v;
+ _veneerVector.push_back(v);
+ return v;
+ }
+
+ /// \brief Get the veneer for Thumb B/BL instructions.
+ const VeneerAtom *getVeneer_THM_B_BL(const DefinedAtom *da,
+ StringRef secName) {
+ auto veneer = _veneerMap.find(da);
+ if (_veneerMap.end() != veneer)
+ return veneer->second;
+
+ auto v = new (_file._alloc) Veneer_THM_B_BL_StaticAtom(_file, secName);
+ v->addReferenceELF_ARM(R_ARM_JUMP24, 4, da, 0);
+
+ v->_name = "__";
+ v->_name += da->name();
+ v->_name += "_from_thumb";
+
+ _veneerMap[da] = v;
+ _veneerVector.push_back(v);
+ return v;
+ }
+
+ /// \brief Create a GOT entry for R_ARM_TLS_TPOFF32 reloc.
+ const GOTAtom *getTLSTPOFF32(const DefinedAtom *da) {
+ return getGOTTLSEntry<R_ARM_TLS_LE32>(da);
+ }
+};
+
+} // end of anon namespace
+
+std::unique_ptr<Pass>
+lld::elf::createARMRelocationPass(const ARMLinkingContext &ctx) {
+ switch (ctx.getOutputELFType()) {
+ case llvm::ELF::ET_EXEC:
+ if (ctx.isDynamic())
+ llvm_unreachable("Unhandled output file type");
+ return llvm::make_unique<ARMStaticRelocationPass>(ctx);
+ default:
+ llvm_unreachable("Unhandled output file type");
+ }
+}
diff --git a/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.h b/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.h
new file mode 100644
index 000000000000..651e798f33b1
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.h
@@ -0,0 +1,31 @@
+//===--------- lib/ReaderWriter/ELF/ARM/ARMRelocationPass.h ---------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Declares the relocation processing pass for ARM. This includes
+/// GOT and PLT entries, TLS, COPY, and ifunc.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_ARM_ARM_RELOCATION_PASS_H
+#define LLD_READER_WRITER_ELF_ARM_ARM_RELOCATION_PASS_H
+
+#include <memory>
+
+namespace lld {
+class Pass;
+namespace elf {
+class ARMLinkingContext;
+
+/// \brief Create ARM relocation pass for the given linking context.
+std::unique_ptr<Pass> createARMRelocationPass(const ARMLinkingContext &);
+}
+}
+
+#endif
diff --git a/lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h b/lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h
new file mode 100644
index 000000000000..540a480421a8
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h
@@ -0,0 +1,46 @@
+//===--------- lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h ------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_ARM_ARM_SYMBOL_TABLE_H
+#define LLD_READER_WRITER_ELF_ARM_ARM_SYMBOL_TABLE_H
+
+namespace lld {
+namespace elf {
+
+/// \brief The SymbolTable class represents the symbol table in a ELF file
+template<class ELFT>
+class ARMSymbolTable : public SymbolTable<ELFT> {
+public:
+ typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+
+ ARMSymbolTable(const ELFLinkingContext &context);
+
+ void addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da,
+ int64_t addr) override;
+};
+
+template <class ELFT>
+ARMSymbolTable<ELFT>::ARMSymbolTable(const ELFLinkingContext &context)
+ : SymbolTable<ELFT>(context, ".symtab",
+ DefaultLayout<ELFT>::ORDER_SYMBOL_TABLE) {}
+
+template <class ELFT>
+void ARMSymbolTable<ELFT>::addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da,
+ int64_t addr) {
+ SymbolTable<ELFT>::addDefinedAtom(sym, da, addr);
+
+ // Set zero bit to distinguish symbols addressing Thumb instructions
+ if (DefinedAtom::codeARMThumb == da->codeModel())
+ sym.st_value = static_cast<int64_t>(sym.st_value) | 0x1;
+}
+
+} // elf
+} // lld
+
+#endif // LLD_READER_WRITER_ELF_ARM_ARM_SYMBOL_TABLE_H
diff --git a/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp b/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp
new file mode 100644
index 000000000000..de90f490f621
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp
@@ -0,0 +1,44 @@
+//===--------- lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp --------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Atoms.h"
+#include "ARMExecutableWriter.h"
+#include "ARMTargetHandler.h"
+#include "ARMLinkingContext.h"
+
+using namespace lld;
+using namespace elf;
+
+ARMTargetHandler::ARMTargetHandler(ARMLinkingContext &context)
+ : _context(context), _armTargetLayout(
+ new ARMTargetLayout<ARMELFType>(context)),
+ _armRelocationHandler(new ARMTargetRelocationHandler(
+ *_armTargetLayout.get())) {}
+
+void ARMTargetHandler::registerRelocationNames(Registry &registry) {
+ registry.addKindTable(Reference::KindNamespace::ELF, Reference::KindArch::ARM,
+ kindStrings);
+}
+
+std::unique_ptr<Writer> ARMTargetHandler::getWriter() {
+ switch (this->_context.getOutputELFType()) {
+ case llvm::ELF::ET_EXEC:
+ return std::unique_ptr<Writer>(
+ new ARMExecutableWriter<ARMELFType>(_context, *_armTargetLayout.get()));
+ default:
+ llvm_unreachable("unsupported output type");
+ }
+}
+
+#define ELF_RELOC(name, value) LLD_KIND_STRING_ENTRY(name),
+
+const Registry::KindStrings ARMTargetHandler::kindStrings[] = {
+#include "llvm/Support/ELFRelocs/ARM.def"
+ LLD_KIND_STRING_END
+};
diff --git a/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h b/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h
new file mode 100644
index 000000000000..10641954da25
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h
@@ -0,0 +1,88 @@
+//===--------- lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h ----------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_ARM_ARM_TARGET_HANDLER_H
+#define LLD_READER_WRITER_ELF_ARM_ARM_TARGET_HANDLER_H
+
+#include "ARMELFFile.h"
+#include "ARMELFReader.h"
+#include "ARMRelocationHandler.h"
+#include "DefaultTargetHandler.h"
+#include "TargetLayout.h"
+
+#include "lld/Core/Simple.h"
+#include "llvm/ADT/Optional.h"
+#include <map>
+
+namespace lld {
+namespace elf {
+typedef llvm::object::ELFType<llvm::support::little, 2, false> ARMELFType;
+class ARMLinkingContext;
+
+template <class ELFT> class ARMTargetLayout : public TargetLayout<ELFT> {
+public:
+ ARMTargetLayout(ARMLinkingContext &context)
+ : TargetLayout<ELFT>(context) {}
+
+ uint64_t getTPOffset() {
+ if (_tpOff.hasValue())
+ return *_tpOff;
+
+ for (const auto &phdr : *this->_programHeader) {
+ if (phdr->p_type == llvm::ELF::PT_TLS) {
+ _tpOff = llvm::RoundUpToAlignment(TCB_SIZE, phdr->p_align);
+ return *_tpOff;
+ }
+ }
+ llvm_unreachable("TLS segment not found");
+ }
+
+private:
+ // TCB block size of the TLS.
+ enum { TCB_SIZE = 0x8 };
+
+ // Cached value of the TLS offset from the $tp pointer.
+ llvm::Optional<uint64_t> _tpOff;
+};
+
+class ARMTargetHandler final : public DefaultTargetHandler<ARMELFType> {
+public:
+ ARMTargetHandler(ARMLinkingContext &context);
+
+ ARMTargetLayout<ARMELFType> &getTargetLayout() override {
+ return *(_armTargetLayout.get());
+ }
+
+ void registerRelocationNames(Registry &registry) override;
+
+ const ARMTargetRelocationHandler &getRelocationHandler() const override {
+ return *(_armRelocationHandler.get());
+ }
+
+ std::unique_ptr<Reader> getObjReader() override {
+ return std::unique_ptr<Reader>(new ARMELFObjectReader(_context));
+ }
+
+ std::unique_ptr<Reader> getDSOReader() override {
+ return std::unique_ptr<Reader>(new ARMELFDSOReader(_context));
+ }
+
+ std::unique_ptr<Writer> getWriter() override;
+
+private:
+ static const Registry::KindStrings kindStrings[];
+ ARMLinkingContext &_context;
+ std::unique_ptr<ARMTargetLayout<ARMELFType>> _armTargetLayout;
+ std::unique_ptr<ARMTargetRelocationHandler> _armRelocationHandler;
+};
+
+} // end namespace elf
+} // end namespace lld
+
+#endif // LLD_READER_WRITER_ELF_ARM_ARM_TARGET_HANDLER_H
diff --git a/lib/ReaderWriter/ELF/ARM/CMakeLists.txt b/lib/ReaderWriter/ELF/ARM/CMakeLists.txt
new file mode 100644
index 000000000000..2ccf9eb6266d
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ARM/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_llvm_library(lldARMELFTarget
+ ARMLinkingContext.cpp
+ ARMTargetHandler.cpp
+ ARMRelocationHandler.cpp
+ ARMRelocationPass.cpp
+ LINK_LIBS
+ lldELF
+ lldReaderWriter
+ lldCore
+ LLVMObject
+ LLVMSupport
+ )
diff --git a/lib/ReaderWriter/ELF/ARM/Makefile b/lib/ReaderWriter/ELF/ARM/Makefile
new file mode 100644
index 000000000000..f67d36a1b612
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ARM/Makefile
@@ -0,0 +1,15 @@
+##===------ lld/lib/ReaderWriter/ELF/ARM/Makefile ----------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLD_LEVEL := ../../../..
+LIBRARYNAME := lldARMELFTarget
+USEDLIBS = lldCore.a
+CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF/ARM -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF
+
+include $(LLD_LEVEL)/Makefile
diff --git a/lib/ReaderWriter/ELF/ARM/TODO.rst b/lib/ReaderWriter/ELF/ARM/TODO.rst
new file mode 100644
index 000000000000..d05419decb78
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ARM/TODO.rst
@@ -0,0 +1,20 @@
+ELF ARM
+~~~~~~~~~~~
+
+Unimplemented Features
+######################
+
+* Static executable linking - in progress
+* Dynamic executable linking
+* DSO linking
+* PLT entries' generation for images larger than 2^28 bytes (see Sec. A.3 of the ELF reference)
+* ARM and Thumb interworking (see http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0203j/Bcghfebi.html)
+* .ARM.exidx section handling
+* -init/-fini options
+* Lots of relocations
+
+Unimplemented Relocations
+#########################
+
+All of these relocations are defined in:
+http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044e/IHI0044E_aaelf.pdf
diff --git a/lib/ReaderWriter/ELF/Atoms.h b/lib/ReaderWriter/ELF/Atoms.h
new file mode 100644
index 000000000000..6a506d21d938
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Atoms.h
@@ -0,0 +1,849 @@
+//===- lib/ReaderWriter/ELF/Atoms.h ---------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_ATOMS_H
+#define LLD_READER_WRITER_ELF_ATOMS_H
+
+#include "TargetHandler.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Simple.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include <memory>
+#include <vector>
+
+namespace lld {
+namespace elf {
+template <class ELFT> class DynamicFile;
+template <typename ELFT> class ELFFile;
+
+/// \brief Relocation References: Defined Atoms may contain references that will
+/// need to be patched before the executable is written.
+///
+/// Construction of ELFReferences is two pass process. ELFReferences are
+/// instantiated while we are iterating over symbol tables to atomize
+/// symbols. At that time we only know the index of relocation target symbol
+/// (not target atom) about a relocation, so we store the index to
+/// ELFREference. In the second pass, ELFReferences are revisited to update
+/// target atoms by target symbol indexes.
+template <class ELFT> class ELFReference : public Reference {
+ typedef llvm::object::Elf_Rel_Impl<ELFT, false> Elf_Rel;
+ typedef llvm::object::Elf_Rel_Impl<ELFT, true> Elf_Rela;
+ typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+
+public:
+ ELFReference(const Elf_Rela *rela, uint64_t off, Reference::KindArch arch,
+ Reference::KindValue relocType, uint32_t idx)
+ : Reference(Reference::KindNamespace::ELF, arch, relocType),
+ _target(nullptr), _targetSymbolIndex(idx), _offsetInAtom(off),
+ _addend(rela->r_addend) {}
+
+ ELFReference(uint64_t off, Reference::KindArch arch,
+ Reference::KindValue relocType, uint32_t idx)
+ : Reference(Reference::KindNamespace::ELF, arch, relocType),
+ _target(nullptr), _targetSymbolIndex(idx), _offsetInAtom(off),
+ _addend(0) {}
+
+ ELFReference(uint32_t edgeKind)
+ : Reference(Reference::KindNamespace::all, Reference::KindArch::all,
+ edgeKind),
+ _target(nullptr), _targetSymbolIndex(0), _offsetInAtom(0), _addend(0) {}
+
+ uint64_t offsetInAtom() const override { return _offsetInAtom; }
+
+ const Atom *target() const override { return _target; }
+
+ /// \brief The symbol table index that contains the target reference.
+ uint64_t targetSymbolIndex() const {
+ return _targetSymbolIndex;
+ }
+
+ Addend addend() const override { return _addend; }
+
+ virtual void setOffset(uint64_t off) { _offsetInAtom = off; }
+
+ void setAddend(Addend A) override { _addend = A; }
+
+ void setTarget(const Atom *newAtom) override { _target = newAtom; }
+
+private:
+ const Atom *_target;
+ uint64_t _targetSymbolIndex;
+ uint64_t _offsetInAtom;
+ Addend _addend;
+};
+
+/// \brief These atoms store symbols that are fixed to a particular address.
+/// This atom has no content its address will be used by the writer to fixup
+/// references that point to it.
+template <class ELFT> class ELFAbsoluteAtom : public AbsoluteAtom {
+ typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+
+public:
+ ELFAbsoluteAtom(const ELFFile<ELFT> &file, StringRef name,
+ const Elf_Sym *symbol, uint64_t value)
+ : _owningFile(file), _name(name), _symbol(symbol), _value(value) {
+ }
+
+ const ELFFile<ELFT> &file() const override { return _owningFile; }
+
+ Scope scope() const override {
+ if (_symbol->getVisibility() == llvm::ELF::STV_HIDDEN)
+ return scopeLinkageUnit;
+ if (_symbol->getBinding() == llvm::ELF::STB_LOCAL)
+ return scopeTranslationUnit;
+ return scopeGlobal;
+ }
+
+ StringRef name() const override { return _name; }
+
+ uint64_t value() const override { return _value; }
+
+private:
+ const ELFFile<ELFT> &_owningFile;
+ StringRef _name;
+ const Elf_Sym *_symbol;
+ uint64_t _value;
+};
+
+/// \brief ELFUndefinedAtom: These atoms store undefined symbols and are place
+/// holders that will be replaced by defined atoms later in the linking process.
+template <class ELFT> class ELFUndefinedAtom : public lld::UndefinedAtom {
+ typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+
+public:
+ ELFUndefinedAtom(const File &file, StringRef name, const Elf_Sym *symbol)
+ : _owningFile(file), _name(name), _symbol(symbol) {}
+
+ const File &file() const override { return _owningFile; }
+
+ StringRef name() const override { return _name; }
+
+ // A symbol in ELF can be undefined at build time if the symbol is a undefined
+ // weak symbol.
+ CanBeNull canBeNull() const override {
+ if (_symbol->getBinding() == llvm::ELF::STB_WEAK)
+ return CanBeNull::canBeNullAtBuildtime;
+ return CanBeNull::canBeNullNever;
+ }
+
+private:
+ const File &_owningFile;
+ StringRef _name;
+ const Elf_Sym *_symbol;
+};
+
+/// \brief This atom stores defined symbols and will contain either data or
+/// code.
+template <class ELFT> class ELFDefinedAtom : public DefinedAtom {
+ typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+ typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr;
+
+public:
+ ELFDefinedAtom(const ELFFile<ELFT> &file, StringRef symbolName,
+ StringRef sectionName, const Elf_Sym *symbol,
+ const Elf_Shdr *section, ArrayRef<uint8_t> contentData,
+ unsigned int referenceStart, unsigned int referenceEnd,
+ std::vector<ELFReference<ELFT> *> &referenceList)
+ : _owningFile(file), _symbolName(symbolName), _sectionName(sectionName),
+ _symbol(symbol), _section(section), _contentData(contentData),
+ _referenceStartIndex(referenceStart), _referenceEndIndex(referenceEnd),
+ _referenceList(referenceList), _contentType(typeUnknown),
+ _permissions(permUnknown) {}
+
+ ~ELFDefinedAtom() {}
+
+ const ELFFile<ELFT> &file() const override { return _owningFile; }
+
+ StringRef name() const override { return _symbolName; }
+
+ uint64_t ordinal() const override { return _ordinal; }
+
+ const Elf_Sym *symbol() const { return _symbol; }
+
+ const Elf_Shdr *section() const { return _section; }
+
+ uint64_t size() const override {
+ // Common symbols are not allocated in object files,
+ // so use st_size to tell how many bytes are required.
+ if (_symbol && (_symbol->getType() == llvm::ELF::STT_COMMON ||
+ _symbol->st_shndx == llvm::ELF::SHN_COMMON))
+ return (uint64_t) _symbol->st_size;
+
+ return _contentData.size();
+ }
+
+ Scope scope() const override {
+ if (!_symbol)
+ return scopeGlobal;
+ if (_symbol->getVisibility() == llvm::ELF::STV_HIDDEN)
+ return scopeLinkageUnit;
+ if (_symbol->getBinding() != llvm::ELF::STB_LOCAL)
+ return scopeGlobal;
+ return scopeTranslationUnit;
+ }
+
+ // FIXME: Need to revisit this in future.
+ Interposable interposable() const override { return interposeNo; }
+
+ Merge merge() const override {
+ if (!_symbol)
+ return mergeNo;
+
+ if (_symbol->getBinding() == llvm::ELF::STB_WEAK)
+ return mergeAsWeak;
+
+ if ((_symbol->getType() == llvm::ELF::STT_COMMON) ||
+ _symbol->st_shndx == llvm::ELF::SHN_COMMON)
+ return mergeAsTentative;
+
+ return mergeNo;
+ }
+
+ ContentType contentType() const override {
+ if (_contentType != typeUnknown)
+ return _contentType;
+
+ ContentType ret = typeUnknown;
+ uint64_t flags = _section->sh_flags;
+
+ if (_section->sh_type == llvm::ELF::SHT_GROUP)
+ return typeGroupComdat;
+
+ if (!_symbol && _sectionName.startswith(".gnu.linkonce"))
+ return typeGnuLinkOnce;
+
+ if (!(flags & llvm::ELF::SHF_ALLOC))
+ return _contentType = typeNoAlloc;
+
+ if (_section->sh_flags ==
+ (llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE | llvm::ELF::SHF_TLS)) {
+ return _contentType = _section->sh_type == llvm::ELF::SHT_NOBITS ? typeThreadZeroFill
+ : typeThreadData;
+ }
+
+ if ((_section->sh_flags == llvm::ELF::SHF_ALLOC) &&
+ (_section->sh_type == llvm::ELF::SHT_PROGBITS))
+ return _contentType = typeConstant;
+
+ if (_symbol->getType() == llvm::ELF::STT_GNU_IFUNC)
+ return _contentType = typeResolver;
+
+ if (_symbol->st_shndx == llvm::ELF::SHN_COMMON)
+ return _contentType = typeZeroFill;
+
+ switch (_section->sh_type) {
+ case llvm::ELF::SHT_PROGBITS:
+ flags &= ~llvm::ELF::SHF_ALLOC;
+ flags &= ~llvm::ELF::SHF_GROUP;
+ switch (flags) {
+ case llvm::ELF::SHF_EXECINSTR:
+ case (llvm::ELF::SHF_WRITE|llvm::ELF::SHF_EXECINSTR):
+ ret = typeCode;
+ break;
+ case llvm::ELF::SHF_WRITE:
+ ret = typeData;
+ break;
+ case (llvm::ELF::SHF_MERGE|llvm::ELF::SHF_STRINGS):
+ case llvm::ELF::SHF_STRINGS:
+ case llvm::ELF::SHF_MERGE:
+ ret = typeConstant;
+ break;
+ default:
+ ret = typeCode;
+ break;
+ }
+ break;
+ case llvm::ELF::SHT_NOTE:
+ flags &= ~llvm::ELF::SHF_ALLOC;
+ switch (flags) {
+ case llvm::ELF::SHF_WRITE:
+ ret = typeRWNote;
+ break;
+ default:
+ ret = typeRONote;
+ break;
+ }
+ break;
+ case llvm::ELF::SHT_NOBITS:
+ ret = typeZeroFill;
+ break;
+ case llvm::ELF::SHT_NULL:
+ if ((_symbol->getType() == llvm::ELF::STT_COMMON)
+ || _symbol->st_shndx == llvm::ELF::SHN_COMMON)
+ ret = typeZeroFill;
+ break;
+ case llvm::ELF::SHT_INIT_ARRAY:
+ case llvm::ELF::SHT_FINI_ARRAY:
+ ret = typeData;
+ break;
+ }
+
+ return _contentType = ret;
+ }
+
+ Alignment alignment() const override {
+ if (!_symbol)
+ return Alignment(0);
+
+ // Obtain proper value of st_value field.
+ const auto symValue = getSymbolValue(_symbol);
+
+ // Unallocated common symbols specify their alignment constraints in
+ // st_value.
+ if ((_symbol->getType() == llvm::ELF::STT_COMMON) ||
+ _symbol->st_shndx == llvm::ELF::SHN_COMMON) {
+ return Alignment(llvm::Log2_64(symValue));
+ }
+ if (_section->sh_addralign == 0) {
+ // sh_addralign of 0 means no alignment
+ return Alignment(0, symValue);
+ }
+ return Alignment(llvm::Log2_64(_section->sh_addralign),
+ symValue % _section->sh_addralign);
+ }
+
+ // Do we have a choice for ELF? All symbols live in explicit sections.
+ SectionChoice sectionChoice() const override {
+ switch (contentType()) {
+ case typeCode:
+ case typeData:
+ case typeZeroFill:
+ case typeThreadZeroFill:
+ case typeThreadData:
+ case typeConstant:
+ if ((_sectionName == ".text") || (_sectionName == ".data") ||
+ (_sectionName == ".bss") || (_sectionName == ".rodata") ||
+ (_sectionName == ".tdata") || (_sectionName == ".tbss"))
+ return sectionBasedOnContent;
+ default:
+ break;
+ }
+ return sectionCustomRequired;
+ }
+
+ StringRef customSectionName() const override {
+ if ((contentType() == typeZeroFill) ||
+ (_symbol && _symbol->st_shndx == llvm::ELF::SHN_COMMON))
+ return ".bss";
+ return _sectionName;
+ }
+
+ // It isn't clear that __attribute__((used)) is transmitted to the ELF object
+ // file.
+ DeadStripKind deadStrip() const override { return deadStripNormal; }
+
+ ContentPermissions permissions() const override {
+ if (_permissions != permUnknown)
+ return _permissions;
+
+ uint64_t flags = _section->sh_flags;
+
+ if (!(flags & llvm::ELF::SHF_ALLOC))
+ return _permissions = perm___;
+
+ switch (_section->sh_type) {
+ // permRW_L is for sections modified by the runtime
+ // loader.
+ case llvm::ELF::SHT_REL:
+ case llvm::ELF::SHT_RELA:
+ return _permissions = permRW_L;
+
+ case llvm::ELF::SHT_DYNAMIC:
+ case llvm::ELF::SHT_PROGBITS:
+ case llvm::ELF::SHT_NOTE:
+ flags &= ~llvm::ELF::SHF_ALLOC;
+ flags &= ~llvm::ELF::SHF_GROUP;
+ switch (flags) {
+ // Code
+ case llvm::ELF::SHF_EXECINSTR:
+ return _permissions = permR_X;
+ case (llvm::ELF::SHF_WRITE|llvm::ELF::SHF_EXECINSTR):
+ return _permissions = permRWX;
+ // Data
+ case llvm::ELF::SHF_WRITE:
+ return _permissions = permRW_;
+ // Strings
+ case llvm::ELF::SHF_MERGE:
+ case llvm::ELF::SHF_STRINGS:
+ return _permissions = permR__;
+
+ default:
+ if (flags & llvm::ELF::SHF_WRITE)
+ return _permissions = permRW_;
+ return _permissions = permR__;
+ }
+
+ case llvm::ELF::SHT_NOBITS:
+ return _permissions = permRW_;
+
+ case llvm::ELF::SHT_INIT_ARRAY:
+ case llvm::ELF::SHT_FINI_ARRAY:
+ return _permissions = permRW_;
+
+ default:
+ return _permissions = perm___;
+ }
+ }
+
+ ArrayRef<uint8_t> rawContent() const override { return _contentData; }
+
+ DefinedAtom::reference_iterator begin() const override {
+ uintptr_t index = _referenceStartIndex;
+ const void *it = reinterpret_cast<const void*>(index);
+ return reference_iterator(*this, it);
+ }
+
+ DefinedAtom::reference_iterator end() const override {
+ uintptr_t index = _referenceEndIndex;
+ const void *it = reinterpret_cast<const void*>(index);
+ return reference_iterator(*this, it);
+ }
+
+ const Reference *derefIterator(const void *It) const override {
+ uintptr_t index = reinterpret_cast<uintptr_t>(It);
+ assert(index >= _referenceStartIndex);
+ assert(index < _referenceEndIndex);
+ return ((_referenceList)[index]);
+ }
+
+ void incrementIterator(const void *&It) const override {
+ uintptr_t index = reinterpret_cast<uintptr_t>(It);
+ ++index;
+ It = reinterpret_cast<const void *>(index);
+ }
+
+ void addReference(ELFReference<ELFT> *reference) {
+ _referenceList.push_back(reference);
+ _referenceEndIndex = _referenceList.size();
+ }
+
+ virtual void setOrdinal(uint64_t ord) { _ordinal = ord; }
+
+protected:
+ /// Returns correct st_value for the symbol depending on the architecture.
+ /// For most architectures it's just a regular st_value with no changes.
+ virtual uint64_t getSymbolValue(const Elf_Sym *symbol) const {
+ return symbol->st_value;
+ }
+
+protected:
+ const ELFFile<ELFT> &_owningFile;
+ StringRef _symbolName;
+ StringRef _sectionName;
+ const Elf_Sym *_symbol;
+ const Elf_Shdr *_section;
+ /// \brief Holds the bits that make up the atom.
+ ArrayRef<uint8_t> _contentData;
+
+ uint64_t _ordinal;
+ unsigned int _referenceStartIndex;
+ unsigned int _referenceEndIndex;
+ std::vector<ELFReference<ELFT> *> &_referenceList;
+ mutable ContentType _contentType;
+ mutable ContentPermissions _permissions;
+};
+
+/// \brief This atom stores mergeable Strings
+template <class ELFT> class ELFMergeAtom : public DefinedAtom {
+ typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr;
+
+public:
+ ELFMergeAtom(const ELFFile<ELFT> &file, StringRef sectionName,
+ const Elf_Shdr *section, ArrayRef<uint8_t> contentData,
+ uint64_t offset)
+ : _owningFile(file), _sectionName(sectionName), _section(section),
+ _contentData(contentData), _offset(offset) {
+ }
+
+ const ELFFile<ELFT> &file() const override { return _owningFile; }
+
+ StringRef name() const override { return ""; }
+
+ virtual uint64_t section() const { return _section->sh_name; }
+
+ virtual uint64_t offset() const { return _offset; }
+
+ virtual void setOrdinal(uint64_t ord) { _ordinal = ord; }
+
+ uint64_t ordinal() const override { return _ordinal; }
+
+ uint64_t size() const override { return _contentData.size(); }
+
+ Scope scope() const override { return scopeTranslationUnit; }
+
+ Interposable interposable() const override { return interposeNo; }
+
+ Merge merge() const override { return mergeByContent; }
+
+ ContentType contentType() const override { return typeConstant; }
+
+ Alignment alignment() const override {
+ return Alignment(llvm::Log2_64(_section->sh_addralign));
+ }
+
+ SectionChoice sectionChoice() const override { return sectionCustomRequired; }
+
+ StringRef customSectionName() const override { return _sectionName; }
+
+ DeadStripKind deadStrip() const override { return deadStripNormal; }
+
+ ContentPermissions permissions() const override { return permR__; }
+
+ ArrayRef<uint8_t> rawContent() const override { return _contentData; }
+
+ DefinedAtom::reference_iterator begin() const override {
+ uintptr_t index = 0;
+ const void *it = reinterpret_cast<const void *>(index);
+ return reference_iterator(*this, it);
+ }
+
+ DefinedAtom::reference_iterator end() const override {
+ uintptr_t index = 0;
+ const void *it = reinterpret_cast<const void *>(index);
+ return reference_iterator(*this, it);
+ }
+
+ const Reference *derefIterator(const void *It) const override {
+ return nullptr;
+ }
+
+ void incrementIterator(const void *&It) const override {}
+
+private:
+
+ const ELFFile<ELFT> &_owningFile;
+ StringRef _sectionName;
+ const Elf_Shdr *_section;
+ /// \brief Holds the bits that make up the atom.
+ ArrayRef<uint8_t> _contentData;
+ uint64_t _ordinal;
+ uint64_t _offset;
+};
+
+template <class ELFT> class ELFCommonAtom : public DefinedAtom {
+ typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+public:
+ ELFCommonAtom(const ELFFile<ELFT> &file,
+ StringRef symbolName,
+ const Elf_Sym *symbol)
+ : _owningFile(file),
+ _symbolName(symbolName),
+ _symbol(symbol) {}
+
+ const ELFFile<ELFT> &file() const override { return _owningFile; }
+
+ StringRef name() const override { return _symbolName; }
+
+ uint64_t ordinal() const override { return _ordinal; }
+
+ virtual void setOrdinal(uint64_t ord) { _ordinal = ord; }
+
+ uint64_t size() const override { return _symbol->st_size; }
+
+ Scope scope() const override {
+ if (_symbol->getVisibility() == llvm::ELF::STV_HIDDEN)
+ return scopeLinkageUnit;
+ if (_symbol->getBinding() != llvm::ELF::STB_LOCAL)
+ return scopeGlobal;
+ return scopeTranslationUnit;
+ }
+
+ Interposable interposable() const override { return interposeNo; }
+
+ Merge merge() const override { return mergeAsTentative; }
+
+ ContentType contentType() const override { return typeZeroFill; }
+
+ Alignment alignment() const override {
+ return Alignment(llvm::Log2_64(_symbol->st_value));
+ }
+
+ SectionChoice sectionChoice() const override { return sectionBasedOnContent; }
+
+ StringRef customSectionName() const override { return ".bss"; }
+
+ DeadStripKind deadStrip() const override { return deadStripNormal; }
+
+ ContentPermissions permissions() const override { return permRW_; }
+
+ ArrayRef<uint8_t> rawContent() const override { return ArrayRef<uint8_t>(); }
+
+ DefinedAtom::reference_iterator begin() const override {
+ uintptr_t index = 0;
+ const void *it = reinterpret_cast<const void *>(index);
+ return reference_iterator(*this, it);
+ }
+
+ DefinedAtom::reference_iterator end() const override {
+ uintptr_t index = 0;
+ const void *it = reinterpret_cast<const void *>(index);
+ return reference_iterator(*this, it);
+ }
+
+protected:
+ const Reference *derefIterator(const void *iter) const override {
+ return nullptr;
+ }
+
+ void incrementIterator(const void *&iter) const override {}
+
+ const ELFFile<ELFT> &_owningFile;
+ StringRef _symbolName;
+ const Elf_Sym *_symbol;
+ uint64_t _ordinal;
+};
+
+/// \brief An atom from a shared library.
+template <class ELFT> class ELFDynamicAtom : public SharedLibraryAtom {
+ typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+
+public:
+ ELFDynamicAtom(const DynamicFile<ELFT> &file, StringRef symbolName,
+ StringRef loadName, const Elf_Sym *symbol)
+ : _owningFile(file), _symbolName(symbolName), _loadName(loadName),
+ _symbol(symbol) {
+ }
+
+ const DynamicFile<ELFT> &file() const override { return _owningFile; }
+
+ StringRef name() const override { return _symbolName; }
+
+ virtual Scope scope() const {
+ if (_symbol->getVisibility() == llvm::ELF::STV_HIDDEN)
+ return scopeLinkageUnit;
+ if (_symbol->getBinding() != llvm::ELF::STB_LOCAL)
+ return scopeGlobal;
+ return scopeTranslationUnit;
+ }
+
+ StringRef loadName() const override { return _loadName; }
+
+ bool canBeNullAtRuntime() const override {
+ return _symbol->getBinding() == llvm::ELF::STB_WEAK;
+ }
+
+ Type type() const override {
+ switch (_symbol->getType()) {
+ case llvm::ELF::STT_FUNC:
+ case llvm::ELF::STT_GNU_IFUNC:
+ return Type::Code;
+ case llvm::ELF::STT_OBJECT:
+ return Type::Data;
+ default:
+ return Type::Unknown;
+ }
+ }
+
+ uint64_t size() const override {
+ return _symbol->st_size;
+ }
+
+private:
+
+ const DynamicFile<ELFT> &_owningFile;
+ StringRef _symbolName;
+ StringRef _loadName;
+ const Elf_Sym *_symbol;
+};
+
+class SimpleELFDefinedAtom : public SimpleDefinedAtom {
+public:
+ SimpleELFDefinedAtom(const File &f) : SimpleDefinedAtom(f) {}
+
+ void addReferenceELF(Reference::KindArch arch, Reference::KindValue kindValue,
+ uint64_t off, const Atom *target,
+ Reference::Addend addend) {
+ this->addReference(Reference::KindNamespace::ELF, arch, kindValue, off,
+ target, addend);
+ }
+
+ void addReferenceELF_Hexagon(Reference::KindValue relocType, uint64_t off,
+ const Atom *t, Reference::Addend a) {
+ this->addReferenceELF(Reference::KindArch::Hexagon, relocType, off, t, a);
+ }
+
+ void addReferenceELF_x86_64(Reference::KindValue relocType, uint64_t off,
+ const Atom *t, Reference::Addend a) {
+ this->addReferenceELF(Reference::KindArch::x86_64, relocType, off, t, a);
+ }
+
+ void addReferenceELF_Mips(Reference::KindValue relocType, uint64_t off,
+ const Atom *t, Reference::Addend a) {
+ this->addReferenceELF(Reference::KindArch::Mips, relocType, off, t, a);
+ }
+
+ void addReferenceELF_AArch64(Reference::KindValue relocType, uint64_t off,
+ const Atom *t, Reference::Addend a) {
+ this->addReferenceELF(Reference::KindArch::AArch64, relocType, off, t, a);
+ }
+
+ void addReferenceELF_ARM(Reference::KindValue relocType, uint64_t off,
+ const Atom *t, Reference::Addend a) {
+ this->addReferenceELF(Reference::KindArch::ARM, relocType, off, t, a);
+ }
+};
+
+/// \brief Atom which represents an object for which a COPY relocation will be
+/// generated.
+class ObjectAtom : public SimpleELFDefinedAtom {
+public:
+ ObjectAtom(const File &f) : SimpleELFDefinedAtom(f) {}
+
+ Scope scope() const override { return scopeGlobal; }
+
+ SectionChoice sectionChoice() const override { return sectionBasedOnContent; }
+
+ ContentType contentType() const override { return typeZeroFill; }
+
+ uint64_t size() const override { return _size; }
+
+ DynamicExport dynamicExport() const override { return dynamicExportAlways; }
+
+ ContentPermissions permissions() const override { return permRW_; }
+
+ ArrayRef<uint8_t> rawContent() const override { return ArrayRef<uint8_t>(); }
+
+ Alignment alignment() const override {
+ // The alignment should be 8 byte aligned
+ return Alignment(3);
+ }
+
+ StringRef name() const override { return _name; }
+
+ std::string _name;
+ uint64_t _size;
+};
+
+class GOTAtom : public SimpleELFDefinedAtom {
+ StringRef _section;
+
+public:
+ GOTAtom(const File &f, StringRef secName)
+ : SimpleELFDefinedAtom(f), _section(secName) {}
+
+ Scope scope() const override { return scopeTranslationUnit; }
+
+ SectionChoice sectionChoice() const override { return sectionCustomRequired; }
+
+ StringRef customSectionName() const override { return _section; }
+
+ ContentType contentType() const override { return typeGOT; }
+
+ uint64_t size() const override { return rawContent().size(); }
+
+ ContentPermissions permissions() const override { return permRW_; }
+
+ Alignment alignment() const override {
+ // The alignment should be 8 byte aligned
+ return Alignment(3);
+ }
+
+#ifndef NDEBUG
+ StringRef name() const override { return _name; }
+ std::string _name;
+#else
+ StringRef name() const override { return ""; }
+#endif
+};
+
+class PLTAtom : public SimpleELFDefinedAtom {
+ StringRef _section;
+
+public:
+ PLTAtom(const File &f, StringRef secName)
+ : SimpleELFDefinedAtom(f), _section(secName) {}
+
+ Scope scope() const override { return scopeTranslationUnit; }
+
+ SectionChoice sectionChoice() const override { return sectionCustomRequired; }
+
+ StringRef customSectionName() const override { return _section; }
+
+ ContentType contentType() const override { return typeStub; }
+
+ uint64_t size() const override { return rawContent().size(); }
+
+ ContentPermissions permissions() const override { return permR_X; }
+
+ Alignment alignment() const override {
+ return Alignment(4); // 16
+ }
+
+#ifndef NDEBUG
+ StringRef name() const override { return _name; }
+ std::string _name;
+#else
+ StringRef name() const override { return ""; }
+#endif
+};
+
+class PLT0Atom : public PLTAtom {
+public:
+ PLT0Atom(const File &f) : PLTAtom(f, ".plt") {
+#ifndef NDEBUG
+ _name = ".PLT0";
+#endif
+ }
+};
+
+class GLOBAL_OFFSET_TABLEAtom : public SimpleELFDefinedAtom {
+public:
+ GLOBAL_OFFSET_TABLEAtom(const File &f) : SimpleELFDefinedAtom(f) {}
+
+ StringRef name() const override { return "_GLOBAL_OFFSET_TABLE_"; }
+
+ Scope scope() const override { return scopeLinkageUnit; }
+
+ SectionChoice sectionChoice() const override { return sectionCustomRequired; }
+
+ StringRef customSectionName() const override { return ".got.plt"; }
+
+ ContentType contentType() const override { return typeGOT; }
+
+ uint64_t size() const override { return 0; }
+
+ ContentPermissions permissions() const override { return permRW_; }
+
+ Alignment alignment() const override {
+ // Needs 8 byte alignment
+ return Alignment(3);
+ }
+
+ ArrayRef<uint8_t> rawContent() const override { return ArrayRef<uint8_t>(); }
+};
+
+class DYNAMICAtom : public SimpleELFDefinedAtom {
+public:
+ DYNAMICAtom(const File &f) : SimpleELFDefinedAtom(f) {}
+
+ StringRef name() const override { return "_DYNAMIC"; }
+
+ Scope scope() const override { return scopeLinkageUnit; }
+
+ Merge merge() const override { return mergeNo; }
+
+ SectionChoice sectionChoice() const override { return sectionCustomRequired; }
+
+ StringRef customSectionName() const override { return ".dynamic"; }
+
+ ContentType contentType() const override { return typeData; }
+
+ uint64_t size() const override { return 0; }
+
+ ContentPermissions permissions() const override { return permRW_; }
+
+ Alignment alignment() const override { return Alignment(0); }
+
+ ArrayRef<uint8_t> rawContent() const override { return ArrayRef<uint8_t>(); }
+};
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/CMakeLists.txt b/lib/ReaderWriter/ELF/CMakeLists.txt
new file mode 100644
index 000000000000..fd4cb669904d
--- /dev/null
+++ b/lib/ReaderWriter/ELF/CMakeLists.txt
@@ -0,0 +1,19 @@
+add_llvm_library(lldELF
+ ELFLinkingContext.cpp
+ Reader.cpp
+ Writer.cpp
+ LINK_LIBS
+ lldReaderWriter
+ lldCore
+ lldYAML
+ LLVMSupport
+ )
+
+include_directories(.)
+
+add_subdirectory(X86)
+add_subdirectory(X86_64)
+add_subdirectory(Mips)
+add_subdirectory(Hexagon)
+add_subdirectory(AArch64)
+add_subdirectory(ARM)
diff --git a/lib/ReaderWriter/ELF/Chunk.h b/lib/ReaderWriter/ELF/Chunk.h
new file mode 100644
index 000000000000..2658d023b3a9
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Chunk.h
@@ -0,0 +1,102 @@
+//===- lib/ReaderWriter/ELF/Chunks.h --------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_CHUNKS_H
+#define LLD_READER_WRITER_ELF_CHUNKS_H
+
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ELF.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include <memory>
+
+namespace lld {
+class ELFLinkingContext;
+
+namespace elf {
+class ELFWriter;
+
+template <class ELFT> class TargetLayout;
+
+/// \brief A chunk is a contiguous region of space
+template<class ELFT>
+class Chunk {
+public:
+
+ /// \brief Describes the type of Chunk
+ enum Kind : uint8_t{ ELFHeader, ///< ELF Header
+ ProgramHeader, ///< Program Header
+ SectionHeader, ///< Section header
+ ELFSegment, ///< Segment
+ ELFSection, ///< Section
+ AtomSection, ///< A section containing atoms.
+ Expression ///< A linker script expression
+ };
+ /// \brief the ContentType of the chunk
+ enum ContentType : uint8_t{ Unknown, Header, Code, Data, Note, TLS };
+
+ Chunk(StringRef name, Kind kind, const ELFLinkingContext &context)
+ : _name(name), _kind(kind), _fsize(0), _msize(0), _alignment(0), _order(0),
+ _ordinal(1), _start(0), _fileoffset(0), _context(context) {}
+ virtual ~Chunk() {}
+ // The name of the chunk
+ StringRef name() const { return _name; }
+ // Kind of chunk
+ Kind kind() const { return _kind; }
+ virtual uint64_t fileSize() const { return _fsize; }
+ virtual void setFileSize(uint64_t sz) { _fsize = sz; }
+ virtual void setAlign(uint64_t align) { _alignment = align; }
+ virtual uint64_t alignment() const { return _alignment; }
+
+ // The ordinal value of the chunk
+ uint64_t ordinal() const { return _ordinal;}
+ void setOrdinal(uint64_t newVal) { _ordinal = newVal;}
+ // The order in which the chunk would appear in the output file
+ uint64_t order() const { return _order; }
+ void setOrder(uint32_t order) { _order = order; }
+ // Output file offset of the chunk
+ uint64_t fileOffset() const { return _fileoffset; }
+ void setFileOffset(uint64_t offset) { _fileoffset = offset; }
+ // Output start address of the chunk
+ virtual void setVirtualAddr(uint64_t start) { _start = start; }
+ virtual uint64_t virtualAddr() const { return _start; }
+ // Memory size of the chunk
+ uint64_t memSize() const { return _msize; }
+ void setMemSize(uint64_t msize) { _msize = msize; }
+ // Whats the contentType of the chunk?
+ virtual int getContentType() const = 0;
+ // Writer the chunk
+ virtual void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
+ llvm::FileOutputBuffer &buffer) = 0;
+ // Finalize the chunk before assigning offsets/virtual addresses
+ virtual void doPreFlight() = 0;
+ // Finalize the chunk before writing
+ virtual void finalize() = 0;
+
+protected:
+ StringRef _name;
+ Kind _kind;
+ uint64_t _fsize;
+ uint64_t _msize;
+ uint64_t _alignment;
+ uint32_t _order;
+ uint64_t _ordinal;
+ uint64_t _start;
+ uint64_t _fileoffset;
+ const ELFLinkingContext &_context;
+};
+
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/CreateELF.h b/lib/ReaderWriter/ELF/CreateELF.h
new file mode 100644
index 000000000000..ad34dddb24d3
--- /dev/null
+++ b/lib/ReaderWriter/ELF/CreateELF.h
@@ -0,0 +1,118 @@
+//===- lib/ReaderWriter/ELF/CreateELF.h -----------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file provides a simple way to create an object templated on
+/// ELFType depending on the runtime type needed.
+///
+//===----------------------------------------------------------------------===//
+#ifndef LLD_READER_WRITER_ELF_CREATE_ELF_H
+#define LLD_READER_WRITER_ELF_CREATE_ELF_H
+
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Compiler.h"
+
+namespace {
+using llvm::object::ELFType;
+
+/// \func createELF
+/// \brief Create an object depending on the runtime attributes and alignment
+/// of an ELF file.
+///
+/// \param Traits
+/// Traits::result_type must be a type convertable from what create returns.
+/// Traits::create must be a template function which takes an ELFType and
+/// returns something convertable to Traits::result_type.
+///
+/// \param ident pair of EI_CLASS and EI_DATA.
+/// \param maxAlignment the maximum alignment of the file.
+/// \param args arguments forwarded to CreateELFTraits<T>::create.
+
+#define LLVM_CREATE_ELF_CreateELFTraits(endian, align, is64, ...) \
+ Traits::template create<ELFType<llvm::support::endian, align, is64>>( \
+ __VA_ARGS__);
+
+#if !LLVM_IS_UNALIGNED_ACCESS_FAST
+# define LLVM_CREATE_ELF_MaxAlignCheck(normal, low, endian, is64, ...) \
+ if (maxAlignment >= normal) \
+ return LLVM_CREATE_ELF_CreateELFTraits(endian, normal, is64, __VA_ARGS__) \
+ else if (maxAlignment >= low) \
+ return LLVM_CREATE_ELF_CreateELFTraits(endian, low, is64, __VA_ARGS__) \
+ else \
+ llvm_unreachable("Invalid alignment for ELF file!");
+#else
+# define LLVM_CREATE_ELF_MaxAlignCheck(normal, low, endian, is64, ...) \
+ if (maxAlignment >= low) \
+ return LLVM_CREATE_ELF_CreateELFTraits(endian, low, is64, __VA_ARGS__) \
+ else \
+ llvm_unreachable("Invalid alignment for ELF file!");
+#endif
+
+#define LLVM_CREATE_ELF_IMPL(...) \
+ if (ident.first == llvm::ELF::ELFCLASS32 && \
+ ident.second == llvm::ELF::ELFDATA2LSB) { \
+ LLVM_CREATE_ELF_MaxAlignCheck(4, 2, little, false, __VA_ARGS__) \
+ } else if (ident.first == llvm::ELF::ELFCLASS32 && \
+ ident.second == llvm::ELF::ELFDATA2MSB) { \
+ LLVM_CREATE_ELF_MaxAlignCheck(4, 2, big, false, __VA_ARGS__) \
+ } else if (ident.first == llvm::ELF::ELFCLASS64 && \
+ ident.second == llvm::ELF::ELFDATA2MSB) { \
+ LLVM_CREATE_ELF_MaxAlignCheck(8, 2, big, true, __VA_ARGS__) \
+ } else if (ident.first == llvm::ELF::ELFCLASS64 && \
+ ident.second == llvm::ELF::ELFDATA2LSB) { \
+ LLVM_CREATE_ELF_MaxAlignCheck(8, 2, little, true, __VA_ARGS__) \
+ } \
+ llvm_unreachable("Invalid ELF type!");
+
+#if LLVM_HAS_VARIADIC_TEMPLATES
+template <class Traits, class ...Args>
+typename Traits::result_type createELF(
+ std::pair<unsigned char, unsigned char> ident, std::size_t maxAlignment,
+ Args &&...args) {
+ LLVM_CREATE_ELF_IMPL(std::forward<Args>(args)...)
+}
+#else
+template <class Traits, class T1>
+typename Traits::result_type createELF(
+ std::pair<unsigned char, unsigned char> ident, std::size_t maxAlignment,
+ T1 &&t1) {
+ LLVM_CREATE_ELF_IMPL(std::forward<T1>(t1))
+}
+
+template <class Traits, class T1, class T2>
+typename Traits::result_type createELF(
+ std::pair<unsigned char, unsigned char> ident, std::size_t maxAlignment,
+ T1 &&t1, T2 &&t2) {
+ LLVM_CREATE_ELF_IMPL(std::forward<T1>(t1), std::forward<T2>(t2))
+}
+
+template <class Traits, class T1, class T2, class T3>
+typename Traits::result_type createELF(
+ std::pair<unsigned char, unsigned char> ident, std::size_t maxAlignment,
+ T1 &&t1, T2 &&t2, T3 &&t3) {
+ LLVM_CREATE_ELF_IMPL(std::forward<T1>(t1), std::forward<T2>(t2),
+ std::forward<T3>(t3))
+}
+
+template <class Traits, class T1, class T2, class T3, class T4>
+typename Traits::result_type createELF(
+ std::pair<unsigned char, unsigned char> ident, std::size_t maxAlignment,
+ T1 &&t1, T2 &&t2, T3 &&t3, T4 &&t4) {
+ LLVM_CREATE_ELF_IMPL(std::forward<T1>(t1), std::forward<T2>(t2),
+ std::forward<T3>(t3), std::forward<T4>(t4))
+}
+
+#endif // LLVM_HAS_VARIADIC_TEMPLATES
+} // end anon namespace
+
+#undef LLVM_CREATE_ELF_CreateELFTraits
+#undef LLVM_CREATE_ELF_MaxAlignCheck
+#undef LLVM_CREATE_ELF_IMPL
+
+#endif
diff --git a/lib/ReaderWriter/ELF/DefaultLayout.h b/lib/ReaderWriter/ELF/DefaultLayout.h
new file mode 100644
index 000000000000..9af3b8eb8dc6
--- /dev/null
+++ b/lib/ReaderWriter/ELF/DefaultLayout.h
@@ -0,0 +1,1050 @@
+//===- lib/ReaderWriter/ELF/DefaultLayout.h -------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_DEFAULT_LAYOUT_H
+#define LLD_READER_WRITER_ELF_DEFAULT_LAYOUT_H
+
+#include "Atoms.h"
+#include "Chunk.h"
+#include "HeaderChunks.h"
+#include "Layout.h"
+#include "SectionChunks.h"
+#include "SegmentChunks.h"
+#include "lld/Core/Instrumentation.h"
+#include "lld/Core/STDExtras.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Format.h"
+#include <map>
+#include <unordered_map>
+
+namespace lld {
+namespace elf {
+/// \brief The DefaultLayout class is used by the Writer to arrange
+/// sections and segments in the order determined by the target ELF
+/// format. The writer creates a single instance of the DefaultLayout
+/// class
+template<class ELFT>
+class DefaultLayout : public Layout {
+public:
+
+ // The order in which the sections appear in the output file
+ // If its determined, that the layout needs to change
+ // just changing the order of enumerations would essentially
+ // change the layout in the output file
+ // Change the enumerations so that Target can override and stick
+ // a section anywhere it wants to
+ enum DefaultSectionOrder {
+ ORDER_NOT_DEFINED = 0,
+ ORDER_INTERP = 10,
+ ORDER_RO_NOTE = 15,
+ ORDER_HASH = 30,
+ ORDER_DYNAMIC_SYMBOLS = 40,
+ ORDER_DYNAMIC_STRINGS = 50,
+ ORDER_DYNAMIC_RELOCS = 52,
+ ORDER_DYNAMIC_PLT_RELOCS = 54,
+ ORDER_INIT = 60,
+ ORDER_PLT = 70,
+ ORDER_TEXT = 80,
+ ORDER_FINI = 90,
+ ORDER_REL = 95,
+ ORDER_RODATA = 100,
+ ORDER_EH_FRAME = 110,
+ ORDER_EH_FRAMEHDR = 120,
+ ORDER_TDATA = 124,
+ ORDER_TBSS = 128,
+ ORDER_CTORS = 130,
+ ORDER_DTORS = 140,
+ ORDER_INIT_ARRAY = 150,
+ ORDER_FINI_ARRAY = 160,
+ ORDER_DYNAMIC = 170,
+ ORDER_GOT = 180,
+ ORDER_GOT_PLT = 190,
+ ORDER_DATA = 200,
+ ORDER_RW_NOTE = 205,
+ ORDER_BSS = 210,
+ ORDER_NOALLOC = 215,
+ ORDER_OTHER = 220,
+ ORDER_SECTION_STRINGS = 230,
+ ORDER_SYMBOL_TABLE = 240,
+ ORDER_STRING_TABLE = 250,
+ ORDER_SECTION_HEADERS = 260
+ };
+
+public:
+
+ // The Key used for creating Sections
+ // The sections are created using
+ // SectionName, contentPermissions
+ struct SectionKey {
+ SectionKey(StringRef name, DefinedAtom::ContentPermissions perm,
+ StringRef path)
+ : _name(name), _perm(perm), _path(path) {}
+
+ // Data members
+ StringRef _name;
+ DefinedAtom::ContentPermissions _perm;
+ StringRef _path;
+ };
+
+ struct SectionKeyHash {
+ int64_t operator()(const SectionKey &k) const {
+ return llvm::hash_combine(k._name, k._perm, k._path);
+ }
+ };
+
+ struct SectionKeyEq {
+ bool operator()(const SectionKey &lhs, const SectionKey &rhs) const {
+ return ((lhs._name == rhs._name) && (lhs._perm == rhs._perm) &&
+ (lhs._path == rhs._path));
+ }
+ };
+
+ typedef typename std::vector<Chunk<ELFT> *>::iterator ChunkIter;
+ typedef typename std::vector<Segment<ELFT> *>::iterator SegmentIter;
+
+ // The additional segments are used to figure out
+ // if there is a segment by that type already created
+ // For example : PT_TLS, we have two sections .tdata/.tbss
+ // that are part of PT_TLS, we need to create this additional
+ // segment only once
+ typedef std::pair<int64_t, int64_t> AdditionalSegmentKey;
+ // The segments are created using
+ // SegmentName, Segment flags
+ typedef std::pair<StringRef, int64_t> SegmentKey;
+
+ // HashKey for the Segment
+ class SegmentHashKey {
+ public:
+ int64_t operator() (const SegmentKey &k) const {
+ // k.first = SegmentName
+ // k.second = SegmentFlags
+ return llvm::hash_combine(k.first, k.second);
+ }
+ };
+
+ class AdditionalSegmentHashKey {
+ public:
+ int64_t operator()(const AdditionalSegmentKey &k) const {
+ // k.first = SegmentName
+ // k.second = SegmentFlags
+ return llvm::hash_combine(k.first, k.second);
+ }
+ };
+
+ // Output Sections contain the map of Sectionnames to a vector of sections,
+ // that have been merged to form a single section
+ typedef llvm::StringMap<OutputSection<ELFT> *> OutputSectionMapT;
+ typedef
+ typename std::vector<OutputSection<ELFT> *>::iterator OutputSectionIter;
+
+ typedef std::unordered_map<SectionKey, AtomSection<ELFT> *, SectionKeyHash,
+ SectionKeyEq> SectionMapT;
+ typedef std::unordered_map<AdditionalSegmentKey, Segment<ELFT> *,
+ AdditionalSegmentHashKey> AdditionalSegmentMapT;
+ typedef std::unordered_map<SegmentKey, Segment<ELFT> *, SegmentHashKey>
+ SegmentMapT;
+
+ /// \brief find a absolute atom pair given a absolute atom name
+ struct FindByName {
+ const std::string _name;
+ FindByName(StringRef name) : _name(name) {}
+ bool operator()(const lld::AtomLayout *j) { return j->_atom->name() == _name; }
+ };
+
+ typedef typename std::vector<lld::AtomLayout *>::iterator AbsoluteAtomIterT;
+
+ typedef llvm::DenseSet<const Atom *> AtomSetT;
+
+ DefaultLayout(ELFLinkingContext &context)
+ : _context(context), _linkerScriptSema(context.linkerScriptSema()) {}
+
+ /// \brief Return the section order for a input section
+ SectionOrder getSectionOrder(StringRef name, int32_t contentType,
+ int32_t contentPermissions) override;
+
+ /// \brief Return the name of the input section by decoding the input
+ /// sectionChoice.
+ virtual StringRef getInputSectionName(const DefinedAtom *da) const;
+
+ /// \brief Return the name of the output section from the input section.
+ virtual StringRef getOutputSectionName(StringRef archivePath,
+ StringRef memberPath,
+ StringRef inputSectionName) const;
+
+ /// \brief Gets or creates a section.
+ AtomSection<ELFT> *
+ getSection(StringRef name, int32_t contentType,
+ DefinedAtom::ContentPermissions contentPermissions,
+ const DefinedAtom *da);
+
+ /// \brief Gets the segment for a output section
+ virtual Layout::SegmentType getSegmentType(Section<ELFT> *section) const;
+
+ /// \brief Returns true/false depending on whether the section has a Output
+ // segment or not
+ static bool hasOutputSegment(Section<ELFT> *section);
+
+ // Adds an atom to the section
+ ErrorOr<const lld::AtomLayout *> addAtom(const Atom *atom) override;
+
+ /// \brief Find an output Section given a section name.
+ OutputSection<ELFT> *findOutputSection(StringRef name) {
+ auto iter = _outputSectionMap.find(name);
+ if (iter == _outputSectionMap.end())
+ return nullptr;
+ return iter->second;
+ }
+
+ /// \brief find a absolute atom given a name
+ AbsoluteAtomIterT findAbsoluteAtom(StringRef name) {
+ return std::find_if(_absoluteAtoms.begin(), _absoluteAtoms.end(),
+ FindByName(name));
+ }
+
+ // Output sections with the same name into a OutputSection
+ void createOutputSections();
+
+ /// \brief Sort the sections by their order as defined by the layout,
+ /// preparing all sections to be assigned to a segment.
+ virtual void sortInputSections();
+
+ /// \brief Add extra chunks to a segment just before including the input
+ /// section given by <archivePath, memberPath, sectionName>. This
+ /// is used to add linker script expressions before each section.
+ virtual void addExtraChunksToSegment(Segment<ELFT> *segment,
+ StringRef archivePath,
+ StringRef memberPath,
+ StringRef sectionName);
+
+ void assignSectionsToSegments() override;
+
+ void assignVirtualAddress() override;
+
+ void assignFileOffsetsForMiscSections();
+
+ range<AbsoluteAtomIterT> absoluteAtoms() { return _absoluteAtoms; }
+
+ void addSection(Chunk<ELFT> *c) { _sections.push_back(c); }
+
+ void finalize() {
+ ScopedTask task(getDefaultDomain(), "Finalize layout");
+ for (auto &si : _sections)
+ si->finalize();
+ }
+
+ void doPreFlight() {
+ for (auto &si : _sections)
+ si->doPreFlight();
+ }
+
+ const AtomLayout *findAtomLayoutByName(StringRef name) const override {
+ for (auto sec : _sections)
+ if (auto section = dyn_cast<Section<ELFT>>(sec))
+ if (auto *al = section->findAtomLayoutByName(name))
+ return al;
+ return nullptr;
+ }
+
+ void setHeader(ELFHeader<ELFT> *elfHeader) { _elfHeader = elfHeader; }
+
+ void setProgramHeader(ProgramHeader<ELFT> *p) {
+ _programHeader = p;
+ }
+
+ range<OutputSectionIter> outputSections() { return _outputSections; }
+
+ range<ChunkIter> sections() { return _sections; }
+
+ range<SegmentIter> segments() { return _segments; }
+
+ ELFHeader<ELFT> *getHeader() { return _elfHeader; }
+
+ bool hasDynamicRelocationTable() const { return !!_dynamicRelocationTable; }
+
+ bool hasPLTRelocationTable() const { return !!_pltRelocationTable; }
+
+ /// \brief Get or create the dynamic relocation table. All relocations in this
+ /// table are processed at startup.
+ RelocationTable<ELFT> *getDynamicRelocationTable() {
+ if (!_dynamicRelocationTable) {
+ _dynamicRelocationTable = std::move(createRelocationTable(
+ _context.isRelaOutputFormat() ? ".rela.dyn" : ".rel.dyn",
+ ORDER_DYNAMIC_RELOCS));
+ addSection(_dynamicRelocationTable.get());
+ }
+ return _dynamicRelocationTable.get();
+ }
+
+ /// \brief Get or create the PLT relocation table. Referenced by DT_JMPREL.
+ RelocationTable<ELFT> *getPLTRelocationTable() {
+ if (!_pltRelocationTable) {
+ _pltRelocationTable = std::move(createRelocationTable(
+ _context.isRelaOutputFormat() ? ".rela.plt" : ".rel.plt",
+ ORDER_DYNAMIC_PLT_RELOCS));
+ addSection(_pltRelocationTable.get());
+ }
+ return _pltRelocationTable.get();
+ }
+
+ uint64_t getTLSSize() const {
+ for (const auto &phdr : *_programHeader)
+ if (phdr->p_type == llvm::ELF::PT_TLS)
+ return phdr->p_memsz;
+ return 0;
+ }
+
+ bool isReferencedByDefinedAtom(const Atom *a) const {
+ return _referencedDynAtoms.count(a);
+ }
+
+ bool isCopied(const SharedLibraryAtom *sla) const {
+ return _copiedDynSymNames.count(sla->name());
+ }
+
+ /// \brief Handle SORT_BY_PRIORITY.
+ void sortOutputSectionByPriority(StringRef outputSectionName,
+ StringRef prefix);
+
+protected:
+ /// \brief TargetLayouts may use these functions to reorder the input sections
+ /// in a order defined by their ABI.
+ virtual void finalizeOutputSectionLayout() {}
+
+ /// \brief Allocate a new section.
+ virtual AtomSection<ELFT> *createSection(
+ StringRef name, int32_t contentType,
+ DefinedAtom::ContentPermissions contentPermissions,
+ SectionOrder sectionOrder);
+
+ /// \brief Create a new relocation table.
+ virtual unique_bump_ptr<RelocationTable<ELFT>>
+ createRelocationTable(StringRef name, int32_t order) {
+ return unique_bump_ptr<RelocationTable<ELFT>>(
+ new (_allocator) RelocationTable<ELFT>(_context, name, order));
+ }
+
+private:
+ /// Helper function that returns the priority value from an input section.
+ uint32_t getPriorityFromSectionName(StringRef sectionName) const;
+
+protected:
+ llvm::BumpPtrAllocator _allocator;
+ SectionMapT _sectionMap;
+ OutputSectionMapT _outputSectionMap;
+ AdditionalSegmentMapT _additionalSegmentMap;
+ SegmentMapT _segmentMap;
+ std::vector<Chunk<ELFT> *> _sections;
+ std::vector<Segment<ELFT> *> _segments;
+ std::vector<OutputSection<ELFT> *> _outputSections;
+ ELFHeader<ELFT> *_elfHeader;
+ ProgramHeader<ELFT> *_programHeader;
+ unique_bump_ptr<RelocationTable<ELFT>> _dynamicRelocationTable;
+ unique_bump_ptr<RelocationTable<ELFT>> _pltRelocationTable;
+ std::vector<lld::AtomLayout *> _absoluteAtoms;
+ AtomSetT _referencedDynAtoms;
+ llvm::StringSet<> _copiedDynSymNames;
+ ELFLinkingContext &_context;
+ script::Sema &_linkerScriptSema;
+};
+
+template <class ELFT>
+Layout::SectionOrder DefaultLayout<ELFT>::getSectionOrder(
+ StringRef name, int32_t contentType, int32_t contentPermissions) {
+ switch (contentType) {
+ case DefinedAtom::typeResolver:
+ case DefinedAtom::typeCode:
+ return llvm::StringSwitch<Layout::SectionOrder>(name)
+ .StartsWith(".eh_frame_hdr", ORDER_EH_FRAMEHDR)
+ .StartsWith(".eh_frame", ORDER_EH_FRAME)
+ .StartsWith(".init", ORDER_INIT)
+ .StartsWith(".fini", ORDER_FINI)
+ .StartsWith(".hash", ORDER_HASH)
+ .Default(ORDER_TEXT);
+
+ case DefinedAtom::typeConstant:
+ return ORDER_RODATA;
+
+ case DefinedAtom::typeData:
+ case DefinedAtom::typeDataFast:
+ return llvm::StringSwitch<Layout::SectionOrder>(name)
+ .StartsWith(".init_array", ORDER_INIT_ARRAY)
+ .StartsWith(".fini_array", ORDER_FINI_ARRAY)
+ .StartsWith(".dynamic", ORDER_DYNAMIC)
+ .StartsWith(".ctors", ORDER_CTORS)
+ .StartsWith(".dtors", ORDER_DTORS)
+ .Default(ORDER_DATA);
+
+ case DefinedAtom::typeZeroFill:
+ case DefinedAtom::typeZeroFillFast:
+ return ORDER_BSS;
+
+ case DefinedAtom::typeGOT:
+ return llvm::StringSwitch<Layout::SectionOrder>(name)
+ .StartsWith(".got.plt", ORDER_GOT_PLT)
+ .Default(ORDER_GOT);
+
+ case DefinedAtom::typeStub:
+ return ORDER_PLT;
+
+ case DefinedAtom::typeRONote:
+ return ORDER_RO_NOTE;
+
+ case DefinedAtom::typeRWNote:
+ return ORDER_RW_NOTE;
+
+ case DefinedAtom::typeNoAlloc:
+ return ORDER_NOALLOC;
+
+ case DefinedAtom::typeThreadData:
+ return ORDER_TDATA;
+ case DefinedAtom::typeThreadZeroFill:
+ return ORDER_TBSS;
+ default:
+ // If we get passed in a section push it to OTHER
+ if (contentPermissions == DefinedAtom::perm___)
+ return ORDER_OTHER;
+
+ return ORDER_NOT_DEFINED;
+ }
+}
+
+/// \brief This maps the input sections to the output section names
+template <class ELFT>
+StringRef
+DefaultLayout<ELFT>::getInputSectionName(const DefinedAtom *da) const {
+ if (da->sectionChoice() == DefinedAtom::sectionBasedOnContent) {
+ switch (da->contentType()) {
+ case DefinedAtom::typeCode:
+ return ".text";
+ case DefinedAtom::typeData:
+ return ".data";
+ case DefinedAtom::typeConstant:
+ return ".rodata";
+ case DefinedAtom::typeZeroFill:
+ return ".bss";
+ case DefinedAtom::typeThreadData:
+ return ".tdata";
+ case DefinedAtom::typeThreadZeroFill:
+ return ".tbss";
+ default:
+ break;
+ }
+ }
+ return da->customSectionName();
+}
+
+/// \brief This maps the input sections to the output section names.
+template <class ELFT>
+StringRef
+DefaultLayout<ELFT>::getOutputSectionName(StringRef archivePath,
+ StringRef memberPath,
+ StringRef inputSectionName) const {
+ StringRef outputSectionName;
+ if (_linkerScriptSema.hasLayoutCommands()) {
+ script::Sema::SectionKey key = {archivePath, memberPath, inputSectionName};
+ outputSectionName = _linkerScriptSema.getOutputSection(key);
+ if (!outputSectionName.empty())
+ return outputSectionName;
+ }
+ return llvm::StringSwitch<StringRef>(inputSectionName)
+ .StartsWith(".text", ".text")
+ .StartsWith(".ctors", ".ctors")
+ .StartsWith(".dtors", ".dtors")
+ .StartsWith(".rodata", ".rodata")
+ .StartsWith(".gcc_except_table", ".gcc_except_table")
+ .StartsWith(".data.rel.ro", ".data.rel.ro")
+ .StartsWith(".data.rel.local", ".data.rel.local")
+ .StartsWith(".data", ".data")
+ .StartsWith(".tdata", ".tdata")
+ .StartsWith(".tbss", ".tbss")
+ .StartsWith(".init_array", ".init_array")
+ .StartsWith(".fini_array", ".fini_array")
+ .Default(inputSectionName);
+}
+
+/// \brief Gets the segment for a output section
+template <class ELFT>
+Layout::SegmentType DefaultLayout<ELFT>::getSegmentType(
+ Section<ELFT> *section) const {
+
+ switch (section->order()) {
+ case ORDER_INTERP:
+ return llvm::ELF::PT_INTERP;
+
+ case ORDER_TEXT:
+ case ORDER_HASH:
+ case ORDER_DYNAMIC_SYMBOLS:
+ case ORDER_DYNAMIC_STRINGS:
+ case ORDER_DYNAMIC_RELOCS:
+ case ORDER_DYNAMIC_PLT_RELOCS:
+ case ORDER_REL:
+ case ORDER_INIT:
+ case ORDER_PLT:
+ case ORDER_FINI:
+ case ORDER_RODATA:
+ case ORDER_EH_FRAME:
+ case ORDER_CTORS:
+ case ORDER_DTORS:
+ return llvm::ELF::PT_LOAD;
+
+ case ORDER_RO_NOTE:
+ case ORDER_RW_NOTE:
+ return llvm::ELF::PT_NOTE;
+
+ case ORDER_DYNAMIC:
+ return llvm::ELF::PT_DYNAMIC;
+
+ case ORDER_EH_FRAMEHDR:
+ return llvm::ELF::PT_GNU_EH_FRAME;
+
+ case ORDER_GOT:
+ case ORDER_GOT_PLT:
+ case ORDER_DATA:
+ case ORDER_BSS:
+ case ORDER_INIT_ARRAY:
+ case ORDER_FINI_ARRAY:
+ return llvm::ELF::PT_LOAD;
+
+ case ORDER_TDATA:
+ case ORDER_TBSS:
+ return llvm::ELF::PT_TLS;
+
+ default:
+ return llvm::ELF::PT_NULL;
+ }
+}
+
+template <class ELFT>
+bool DefaultLayout<ELFT>::hasOutputSegment(Section<ELFT> *section) {
+ switch (section->order()) {
+ case ORDER_INTERP:
+ case ORDER_HASH:
+ case ORDER_DYNAMIC_SYMBOLS:
+ case ORDER_DYNAMIC_STRINGS:
+ case ORDER_DYNAMIC_RELOCS:
+ case ORDER_DYNAMIC_PLT_RELOCS:
+ case ORDER_REL:
+ case ORDER_INIT:
+ case ORDER_PLT:
+ case ORDER_TEXT:
+ case ORDER_FINI:
+ case ORDER_RODATA:
+ case ORDER_EH_FRAME:
+ case ORDER_EH_FRAMEHDR:
+ case ORDER_TDATA:
+ case ORDER_TBSS:
+ case ORDER_RO_NOTE:
+ case ORDER_RW_NOTE:
+ case ORDER_DYNAMIC:
+ case ORDER_CTORS:
+ case ORDER_DTORS:
+ case ORDER_GOT:
+ case ORDER_GOT_PLT:
+ case ORDER_DATA:
+ case ORDER_INIT_ARRAY:
+ case ORDER_FINI_ARRAY:
+ case ORDER_BSS:
+ case ORDER_NOALLOC:
+ return true;
+ default:
+ return section->hasOutputSegment();
+ }
+}
+
+template <class ELFT>
+AtomSection<ELFT> *DefaultLayout<ELFT>::createSection(
+ StringRef sectionName, int32_t contentType,
+ DefinedAtom::ContentPermissions permissions, SectionOrder sectionOrder) {
+ return new (_allocator) AtomSection<ELFT>(_context, sectionName, contentType,
+ permissions, sectionOrder);
+}
+
+template <class ELFT>
+AtomSection<ELFT> *
+DefaultLayout<ELFT>::getSection(StringRef sectionName, int32_t contentType,
+ DefinedAtom::ContentPermissions permissions,
+ const DefinedAtom *da) {
+ const SectionKey sectionKey(sectionName, permissions, da->file().path());
+ SectionOrder sectionOrder = getSectionOrder(sectionName, contentType, permissions);
+ auto sec = _sectionMap.find(sectionKey);
+ if (sec != _sectionMap.end())
+ return sec->second;
+ AtomSection<ELFT> *newSec =
+ createSection(sectionName, contentType, permissions, sectionOrder);
+
+ newSec->setOutputSectionName(getOutputSectionName(
+ da->file().archivePath(), da->file().memberPath(), sectionName));
+ newSec->setOrder(sectionOrder);
+ newSec->setArchiveNameOrPath(da->file().archivePath());
+ newSec->setMemberNameOrPath(da->file().memberPath());
+ _sections.push_back(newSec);
+ _sectionMap.insert(std::make_pair(sectionKey, newSec));
+ return newSec;
+}
+
+template <class ELFT>
+ErrorOr<const lld::AtomLayout *>
+DefaultLayout<ELFT>::addAtom(const Atom *atom) {
+ if (const DefinedAtom *definedAtom = dyn_cast<DefinedAtom>(atom)) {
+ // HACK: Ignore undefined atoms. We need to adjust the interface so that
+ // undefined atoms can still be included in the output symbol table for
+ // -noinhibit-exec.
+ if (definedAtom->contentType() == DefinedAtom::typeUnknown)
+ return make_error_code(llvm::errc::invalid_argument);
+ const DefinedAtom::ContentPermissions permissions =
+ definedAtom->permissions();
+ const DefinedAtom::ContentType contentType = definedAtom->contentType();
+
+ StringRef sectionName = getInputSectionName(definedAtom);
+ AtomSection<ELFT> *section =
+ getSection(sectionName, contentType, permissions, definedAtom);
+
+ // Add runtime relocations to the .rela section.
+ for (const auto &reloc : *definedAtom) {
+ bool isLocalReloc = true;
+ if (_context.isDynamicRelocation(*reloc)) {
+ getDynamicRelocationTable()->addRelocation(*definedAtom, *reloc);
+ isLocalReloc = false;
+ } else if (_context.isPLTRelocation(*reloc)) {
+ getPLTRelocationTable()->addRelocation(*definedAtom, *reloc);
+ isLocalReloc = false;
+ }
+
+ if (!reloc->target())
+ continue;
+
+ //Ignore undefined atoms that are not target of dynamic relocations
+ if (isa<UndefinedAtom>(reloc->target()) && isLocalReloc)
+ continue;
+
+ if (_context.isCopyRelocation(*reloc)) {
+ _copiedDynSymNames.insert(definedAtom->name());
+ continue;
+ }
+
+ _referencedDynAtoms.insert(reloc->target());
+ }
+
+ return section->appendAtom(atom);
+ } else if (const AbsoluteAtom *absoluteAtom = dyn_cast<AbsoluteAtom>(atom)) {
+ // Absolute atoms are not part of any section, they are global for the whole
+ // link
+ _absoluteAtoms.push_back(new (_allocator)
+ lld::AtomLayout(absoluteAtom, 0, absoluteAtom->value()));
+ return _absoluteAtoms.back();
+ } else {
+ llvm_unreachable("Only absolute / defined atoms can be added here");
+ }
+}
+
+/// Output sections with the same name into a OutputSection
+template <class ELFT> void DefaultLayout<ELFT>::createOutputSections() {
+ OutputSection<ELFT> *outputSection;
+
+ for (auto &si : _sections) {
+ Section<ELFT> *section = dyn_cast<Section<ELFT>>(si);
+ if (!section)
+ continue;
+ const std::pair<StringRef, OutputSection<ELFT> *> currentOutputSection(
+ section->outputSectionName(), nullptr);
+ std::pair<typename OutputSectionMapT::iterator, bool> outputSectionInsert(
+ _outputSectionMap.insert(currentOutputSection));
+ if (!outputSectionInsert.second) {
+ outputSection = outputSectionInsert.first->second;
+ } else {
+ outputSection = new (_allocator.Allocate<OutputSection<ELFT>>())
+ OutputSection<ELFT>(section->outputSectionName());
+ _outputSections.push_back(outputSection);
+ outputSectionInsert.first->second = outputSection;
+ }
+ outputSection->appendSection(si);
+ }
+}
+
+template <class ELFT>
+uint32_t
+DefaultLayout<ELFT>::getPriorityFromSectionName(StringRef sectionName) const {
+ StringRef priority = sectionName.drop_front().rsplit('.').second;
+ uint32_t prio;
+ if (priority.getAsInteger(10, prio))
+ return std::numeric_limits<uint32_t>::max();
+ return prio;
+}
+
+template <class ELFT>
+void DefaultLayout<ELFT>::sortOutputSectionByPriority(
+ StringRef outputSectionName, StringRef prefix) {
+ OutputSection<ELFT> *outputSection = findOutputSection(outputSectionName);
+ if (!outputSection)
+ return;
+
+ auto sections = outputSection->sections();
+
+ std::sort(sections.begin(), sections.end(),
+ [&](Chunk<ELFT> *lhs, Chunk<ELFT> *rhs) {
+ Section<ELFT> *lhsSection = dyn_cast<Section<ELFT>>(lhs);
+ Section<ELFT> *rhsSection = dyn_cast<Section<ELFT>>(rhs);
+ if (!lhsSection || !rhsSection)
+ return false;
+ StringRef lhsSectionName = lhsSection->inputSectionName();
+ StringRef rhsSectionName = rhsSection->inputSectionName();
+
+ if (!prefix.empty()) {
+ if (!lhsSectionName.startswith(prefix) ||
+ !rhsSectionName.startswith(prefix))
+ return false;
+ }
+ return getPriorityFromSectionName(lhsSectionName) <
+ getPriorityFromSectionName(rhsSectionName);
+ });
+}
+
+template <class ELFT> void DefaultLayout<ELFT>::assignSectionsToSegments() {
+ ScopedTask task(getDefaultDomain(), "assignSectionsToSegments");
+ ELFLinkingContext::OutputMagic outputMagic = _context.getOutputMagic();
+ // sort the sections by their order as defined by the layout
+ sortInputSections();
+
+ // Create output sections.
+ createOutputSections();
+
+ // Finalize output section layout.
+ finalizeOutputSectionLayout();
+
+ // Set the ordinal after sorting the sections
+ int ordinal = 1;
+ for (auto osi : _outputSections) {
+ osi->setOrdinal(ordinal);
+ for (auto ai : osi->sections()) {
+ ai->setOrdinal(ordinal);
+ }
+ ++ordinal;
+ }
+ for (auto osi : _outputSections) {
+ for (auto ai : osi->sections()) {
+ if (auto section = dyn_cast<Section<ELFT> >(ai)) {
+ if (!hasOutputSegment(section))
+ continue;
+
+ osi->setLoadableSection(section->isLoadableSection());
+
+ // Get the segment type for the section
+ int64_t segmentType = getSegmentType(section);
+
+ osi->setHasSegment();
+ section->setSegmentType(segmentType);
+ StringRef segmentName = section->segmentKindToStr();
+
+ int64_t lookupSectionFlag = osi->flags();
+ if ((!(lookupSectionFlag & llvm::ELF::SHF_WRITE)) &&
+ (_context.mergeRODataToTextSegment()))
+ lookupSectionFlag &= ~llvm::ELF::SHF_EXECINSTR;
+
+ // Merge string sections into Data segment itself
+ lookupSectionFlag &= ~(llvm::ELF::SHF_STRINGS | llvm::ELF::SHF_MERGE);
+
+ // Merge the TLS section into the DATA segment itself
+ lookupSectionFlag &= ~(llvm::ELF::SHF_TLS);
+
+ Segment<ELFT> *segment;
+ // We need a separate segment for sections that don't have
+ // the segment type to be PT_LOAD
+ if (segmentType != llvm::ELF::PT_LOAD) {
+ const AdditionalSegmentKey key(segmentType, lookupSectionFlag);
+ const std::pair<AdditionalSegmentKey, Segment<ELFT> *>
+ additionalSegment(key, nullptr);
+ std::pair<typename AdditionalSegmentMapT::iterator, bool>
+ additionalSegmentInsert(
+ _additionalSegmentMap.insert(additionalSegment));
+ if (!additionalSegmentInsert.second) {
+ segment = additionalSegmentInsert.first->second;
+ } else {
+ segment = new (_allocator)
+ Segment<ELFT>(_context, segmentName, segmentType);
+ additionalSegmentInsert.first->second = segment;
+ _segments.push_back(segment);
+ }
+ segment->append(section);
+ }
+ if (segmentType == llvm::ELF::PT_NULL)
+ continue;
+
+ // If the output magic is set to OutputMagic::NMAGIC or
+ // OutputMagic::OMAGIC, Place the data alongside text in one single
+ // segment
+ if (outputMagic == ELFLinkingContext::OutputMagic::NMAGIC ||
+ outputMagic == ELFLinkingContext::OutputMagic::OMAGIC)
+ lookupSectionFlag = llvm::ELF::SHF_EXECINSTR | llvm::ELF::SHF_ALLOC |
+ llvm::ELF::SHF_WRITE;
+
+ // Use the flags of the merged Section for the segment
+ const SegmentKey key("PT_LOAD", lookupSectionFlag);
+ const std::pair<SegmentKey, Segment<ELFT> *> currentSegment(key,
+ nullptr);
+ std::pair<typename SegmentMapT::iterator, bool> segmentInsert(
+ _segmentMap.insert(currentSegment));
+ if (!segmentInsert.second) {
+ segment = segmentInsert.first->second;
+ } else {
+ segment = new (_allocator)
+ Segment<ELFT>(_context, "PT_LOAD", llvm::ELF::PT_LOAD);
+ segmentInsert.first->second = segment;
+ _segments.push_back(segment);
+ }
+ // Insert chunks with linker script expressions that occur at this
+ // point, just before appending a new input section
+ addExtraChunksToSegment(segment, section->archivePath(),
+ section->memberPath(),
+ section->inputSectionName());
+ segment->append(section);
+ }
+ }
+ }
+ if (_context.isDynamic() && !_context.isDynamicLibrary()) {
+ Segment<ELFT> *segment =
+ new (_allocator) ProgramHeaderSegment<ELFT>(_context);
+ _segments.push_back(segment);
+ segment->append(_elfHeader);
+ segment->append(_programHeader);
+ }
+}
+
+template<class ELFT>
+void
+DefaultLayout<ELFT>::assignVirtualAddress() {
+ if (_segments.empty())
+ return;
+
+ std::sort(_segments.begin(), _segments.end(), Segment<ELFT>::compareSegments);
+
+ uint64_t baseAddress = _context.getBaseAddress();
+
+ // HACK: This is a super dirty hack. The elf header and program header are
+ // not part of a section, but we need them to be loaded at the base address
+ // so that AT_PHDR is set correctly by the loader and so they are accessible
+ // at runtime. To do this we simply prepend them to the first loadable Segment
+ // and let the layout logic take care of it.
+ Segment<ELFT> *firstLoadSegment = nullptr;
+ for (auto si : _segments) {
+ if (si->segmentType() == llvm::ELF::PT_LOAD) {
+ firstLoadSegment = si;
+ si->firstSection()->setAlign(si->alignment());
+ break;
+ }
+ }
+ assert(firstLoadSegment != nullptr && "No loadable segment!");
+ firstLoadSegment->prepend(_programHeader);
+ firstLoadSegment->prepend(_elfHeader);
+ bool newSegmentHeaderAdded = true;
+ bool virtualAddressAssigned = false;
+ bool fileOffsetAssigned = false;
+ while (true) {
+ for (auto si : _segments) {
+ si->finalize();
+ // Don't add PT_NULL segments into the program header
+ if (si->segmentType() != llvm::ELF::PT_NULL)
+ newSegmentHeaderAdded = _programHeader->addSegment(si);
+ }
+ if (!newSegmentHeaderAdded && virtualAddressAssigned)
+ break;
+ uint64_t address = baseAddress;
+ // start assigning virtual addresses
+ for (auto &si : _segments) {
+ if ((si->segmentType() != llvm::ELF::PT_LOAD) &&
+ (si->segmentType() != llvm::ELF::PT_NULL))
+ continue;
+
+ if (si->segmentType() == llvm::ELF::PT_NULL) {
+ si->assignVirtualAddress(0 /*non loadable*/);
+ } else {
+ if (virtualAddressAssigned && (address != baseAddress) &&
+ (address == si->virtualAddr()))
+ break;
+ si->assignVirtualAddress(address);
+ }
+ address = si->virtualAddr() + si->memSize();
+ }
+ uint64_t baseFileOffset = 0;
+ uint64_t fileoffset = baseFileOffset;
+ for (auto &si : _segments) {
+ if ((si->segmentType() != llvm::ELF::PT_LOAD) &&
+ (si->segmentType() != llvm::ELF::PT_NULL))
+ continue;
+ if (fileOffsetAssigned && (fileoffset != baseFileOffset) &&
+ (fileoffset == si->fileOffset()))
+ break;
+ si->assignFileOffsets(fileoffset);
+ fileoffset = si->fileOffset() + si->fileSize();
+ }
+ virtualAddressAssigned = true;
+ fileOffsetAssigned = true;
+ _programHeader->resetProgramHeaders();
+ }
+ Section<ELFT> *section;
+ // Fix the offsets of all the atoms within a section
+ for (auto &si : _sections) {
+ section = dyn_cast<Section<ELFT>>(si);
+ if (section && DefaultLayout<ELFT>::hasOutputSegment(section))
+ section->assignFileOffsets(section->fileOffset());
+ }
+ // Set the size of the merged Sections
+ for (auto osi : _outputSections) {
+ uint64_t sectionfileoffset = 0;
+ uint64_t startFileOffset = 0;
+ uint64_t sectionsize = 0;
+ bool isFirstSection = true;
+ for (auto si : osi->sections()) {
+ if (isFirstSection) {
+ startFileOffset = si->fileOffset();
+ isFirstSection = false;
+ }
+ sectionfileoffset = si->fileOffset();
+ sectionsize = si->fileSize();
+ }
+ sectionsize = (sectionfileoffset - startFileOffset) + sectionsize;
+ osi->setFileOffset(startFileOffset);
+ osi->setSize(sectionsize);
+ }
+ // Set the virtual addr of the merged Sections
+ for (auto osi : _outputSections) {
+ uint64_t sectionstartaddr = 0;
+ uint64_t startaddr = 0;
+ uint64_t sectionsize = 0;
+ bool isFirstSection = true;
+ for (auto si : osi->sections()) {
+ if (isFirstSection) {
+ startaddr = si->virtualAddr();
+ isFirstSection = false;
+ }
+ sectionstartaddr = si->virtualAddr();
+ sectionsize = si->memSize();
+ }
+ sectionsize = (sectionstartaddr - startaddr) + sectionsize;
+ osi->setMemSize(sectionsize);
+ osi->setAddr(startaddr);
+ }
+}
+
+template <class ELFT>
+void DefaultLayout<ELFT>::assignFileOffsetsForMiscSections() {
+ uint64_t fileoffset = 0;
+ uint64_t size = 0;
+ for (auto si : _segments) {
+ // Don't calculate offsets from non loadable segments
+ if ((si->segmentType() != llvm::ELF::PT_LOAD) &&
+ (si->segmentType() != llvm::ELF::PT_NULL))
+ continue;
+ fileoffset = si->fileOffset();
+ size = si->fileSize();
+ }
+ fileoffset = fileoffset + size;
+ Section<ELFT> *section;
+ for (auto si : _sections) {
+ section = dyn_cast<Section<ELFT>>(si);
+ if (section && DefaultLayout<ELFT>::hasOutputSegment(section))
+ continue;
+ fileoffset = llvm::RoundUpToAlignment(fileoffset, si->alignment());
+ si->setFileOffset(fileoffset);
+ si->setVirtualAddr(0);
+ fileoffset += si->fileSize();
+ }
+}
+
+template <class ELFT> void DefaultLayout<ELFT>::sortInputSections() {
+ // First, sort according to default layout's order
+ std::stable_sort(
+ _sections.begin(), _sections.end(),
+ [](Chunk<ELFT> *A, Chunk<ELFT> *B) { return A->order() < B->order(); });
+
+ if (!_linkerScriptSema.hasLayoutCommands())
+ return;
+
+ // Sort the sections by their order as defined by the linker script
+ std::stable_sort(this->_sections.begin(), this->_sections.end(),
+ [this](Chunk<ELFT> *A, Chunk<ELFT> *B) {
+ auto *a = dyn_cast<Section<ELFT>>(A);
+ auto *b = dyn_cast<Section<ELFT>>(B);
+
+ if (a == nullptr)
+ return false;
+ if (b == nullptr)
+ return true;
+
+ return _linkerScriptSema.less(
+ {a->archivePath(), a->memberPath(),
+ a->inputSectionName()},
+ {b->archivePath(), b->memberPath(),
+ b->inputSectionName()});
+ });
+ // Now try to arrange sections with no mapping rules to sections with
+ // similar content
+ auto p = this->_sections.begin();
+ // Find first section that has no assigned rule id
+ while (p != this->_sections.end()) {
+ auto *sect = dyn_cast<AtomSection<ELFT>>(*p);
+ if (!sect)
+ break;
+
+ if (!_linkerScriptSema.hasMapping({sect->archivePath(),
+ sect->memberPath(),
+ sect->inputSectionName()}))
+ break;
+
+ ++p;
+ }
+ // For all sections that have no assigned rule id, try to move them near a
+ // section with similar contents
+ if (p != this->_sections.begin()) {
+ for (; p != this->_sections.end(); ++p) {
+ auto q = p;
+ --q;
+ while (q != this->_sections.begin() &&
+ (*q)->getContentType() != (*p)->getContentType())
+ --q;
+ if ((*q)->getContentType() != (*p)->getContentType())
+ continue;
+ ++q;
+ for (auto i = p; i != q;) {
+ auto next = i--;
+ std::iter_swap(i, next);
+ }
+ }
+ }
+}
+
+template <class ELFT>
+void DefaultLayout<ELFT>::addExtraChunksToSegment(Segment<ELFT> *segment,
+ StringRef archivePath,
+ StringRef memberPath,
+ StringRef sectionName) {
+ if (!_linkerScriptSema.hasLayoutCommands())
+ return;
+
+ std::vector<const script::SymbolAssignment *> exprs =
+ _linkerScriptSema.getExprs({archivePath, memberPath, sectionName});
+ for (auto expr : exprs) {
+ auto expChunk =
+ new (this->_allocator) ExpressionChunk<ELFT>(this->_context, expr);
+ segment->append(expChunk);
+ }
+}
+
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/DefaultTargetHandler.h b/lib/ReaderWriter/ELF/DefaultTargetHandler.h
new file mode 100644
index 000000000000..16668f2df618
--- /dev/null
+++ b/lib/ReaderWriter/ELF/DefaultTargetHandler.h
@@ -0,0 +1,38 @@
+//===- lib/ReaderWriter/ELF/DefaultTargetHandler.h ------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_DEFAULT_TARGET_HANDLER_H
+#define LLD_READER_WRITER_ELF_DEFAULT_TARGET_HANDLER_H
+
+#include "DefaultLayout.h"
+#include "DynamicLibraryWriter.h"
+#include "ELFReader.h"
+#include "ExecutableWriter.h"
+#include "TargetHandler.h"
+#include "lld/ReaderWriter/ELFLinkingContext.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/ELF.h"
+
+namespace lld {
+namespace elf {
+template <class ELFT>
+class DefaultTargetHandler : public TargetHandler<ELFT> {
+public:
+ const TargetRelocationHandler &getRelocationHandler() const = 0;
+
+ virtual std::unique_ptr<Reader> getObjReader() = 0;
+
+ virtual std::unique_ptr<Reader> getDSOReader() = 0;
+
+ virtual std::unique_ptr<Writer> getWriter() = 0;
+};
+
+} // end namespace elf
+} // end namespace lld
+#endif
diff --git a/lib/ReaderWriter/ELF/DynamicFile.h b/lib/ReaderWriter/ELF/DynamicFile.h
new file mode 100644
index 000000000000..c4e3e7165efd
--- /dev/null
+++ b/lib/ReaderWriter/ELF/DynamicFile.h
@@ -0,0 +1,123 @@
+//===- lib/ReaderWriter/ELF/DynamicFile.h ---------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_DYNAMIC_FILE_H
+#define LLD_READER_WRITER_ELF_DYNAMIC_FILE_H
+
+#include "Atoms.h"
+#include "lld/Core/SharedLibraryFile.h"
+#include "lld/ReaderWriter/ELFLinkingContext.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Path.h"
+#include <unordered_map>
+
+namespace lld {
+namespace elf {
+template <class ELFT> class DynamicFile : public SharedLibraryFile {
+public:
+ static ErrorOr<std::unique_ptr<DynamicFile>>
+ create(std::unique_ptr<llvm::MemoryBuffer> mb, ELFLinkingContext &ctx);
+
+ const SharedLibraryAtom *exports(StringRef name,
+ bool dataSymbolOnly) const override {
+ assert(!dataSymbolOnly && "Invalid option for ELF exports!");
+ // See if we have the symbol.
+ auto sym = _nameToSym.find(name);
+ if (sym == _nameToSym.end())
+ return nullptr;
+ // Have we already created a SharedLibraryAtom for it?
+ if (sym->second._atom)
+ return sym->second._atom;
+ // Create a SharedLibraryAtom for this symbol.
+ return sym->second._atom = new (_alloc) ELFDynamicAtom<ELFT>(
+ *this, name, _soname, sym->second._symbol);
+ }
+
+ StringRef getDSOName() const override { return _soname; }
+
+protected:
+ std::error_code doParse() override {
+ std::error_code ec;
+ _objFile.reset(
+ new llvm::object::ELFFile<ELFT>(_mb->getBuffer(), ec));
+ if (ec)
+ return ec;
+
+ llvm::object::ELFFile<ELFT> &obj = *_objFile;
+
+ _soname = obj.getLoadName();
+ if (_soname.empty())
+ _soname = llvm::sys::path::filename(path());
+
+ // Create a map from names to dynamic symbol table entries.
+ // TODO: This should use the object file's build in hash table instead if
+ // it exists.
+ for (auto i = obj.begin_dynamic_symbols(), e = obj.end_dynamic_symbols();
+ i != e; ++i) {
+ auto name = obj.getSymbolName(i);
+ if ((ec = name.getError()))
+ return ec;
+
+ // Dont add local symbols to dynamic entries. The first symbol in the
+ // dynamic symbol table is a local symbol.
+ if (i->getBinding() == llvm::ELF::STB_LOCAL)
+ continue;
+
+ // TODO: Add absolute symbols
+ if (i->st_shndx == llvm::ELF::SHN_ABS)
+ continue;
+
+ if (i->st_shndx == llvm::ELF::SHN_UNDEF) {
+ if (!_useShlibUndefines)
+ continue;
+ // Create an undefined atom.
+ if (!name->empty()) {
+ auto *newAtom = new (_alloc) ELFUndefinedAtom<ELFT>(*this, *name, &*i);
+ _undefinedAtoms._atoms.push_back(newAtom);
+ }
+ continue;
+ }
+ _nameToSym[*name]._symbol = &*i;
+ }
+ return std::error_code();
+ }
+
+private:
+ DynamicFile(std::unique_ptr<MemoryBuffer> mb, ELFLinkingContext &ctx)
+ : SharedLibraryFile(mb->getBufferIdentifier()), _mb(std::move(mb)),
+ _ctx(ctx), _useShlibUndefines(ctx.useShlibUndefines()) {}
+
+ mutable llvm::BumpPtrAllocator _alloc;
+ std::unique_ptr<llvm::object::ELFFile<ELFT>> _objFile;
+ /// \brief DT_SONAME
+ StringRef _soname;
+
+ struct SymAtomPair {
+ SymAtomPair() : _symbol(nullptr), _atom(nullptr) {}
+ const typename llvm::object::ELFFile<ELFT>::Elf_Sym *_symbol;
+ const SharedLibraryAtom *_atom;
+ };
+
+ std::unique_ptr<MemoryBuffer> _mb;
+ ELFLinkingContext &_ctx;
+ bool _useShlibUndefines;
+ mutable std::unordered_map<StringRef, SymAtomPair> _nameToSym;
+};
+
+template <class ELFT>
+ErrorOr<std::unique_ptr<DynamicFile<ELFT>>>
+DynamicFile<ELFT>::create(std::unique_ptr<llvm::MemoryBuffer> mb,
+ ELFLinkingContext &ctx) {
+ return std::unique_ptr<DynamicFile>(new DynamicFile(std::move(mb), ctx));
+}
+
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/DynamicLibraryWriter.h b/lib/ReaderWriter/ELF/DynamicLibraryWriter.h
new file mode 100644
index 000000000000..f97514b525c0
--- /dev/null
+++ b/lib/ReaderWriter/ELF/DynamicLibraryWriter.h
@@ -0,0 +1,96 @@
+//===- lib/ReaderWriter/ELF/DynamicLibraryWriter.h ------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLD_READER_WRITER_ELF_DYNAMIC_LIBRARY_WRITER_H
+#define LLD_READER_WRITER_ELF_DYNAMIC_LIBRARY_WRITER_H
+
+#include "OutputELFWriter.h"
+
+namespace lld {
+namespace elf {
+using namespace llvm;
+using namespace llvm::object;
+
+template<class ELFT>
+class DynamicLibraryWriter;
+
+//===----------------------------------------------------------------------===//
+// DynamicLibraryWriter Class
+//===----------------------------------------------------------------------===//
+template<class ELFT>
+class DynamicLibraryWriter : public OutputELFWriter<ELFT> {
+public:
+ DynamicLibraryWriter(ELFLinkingContext &context, TargetLayout<ELFT> &layout)
+ : OutputELFWriter<ELFT>(context, layout),
+ _runtimeFile(new RuntimeFile<ELFT>(context, "C runtime")) {}
+
+protected:
+ virtual void buildDynamicSymbolTable(const File &file);
+ virtual void addDefaultAtoms();
+ virtual bool createImplicitFiles(std::vector<std::unique_ptr<File> > &);
+ virtual void finalizeDefaultAtomValues();
+
+protected:
+ std::unique_ptr<RuntimeFile<ELFT> > _runtimeFile;
+};
+
+//===----------------------------------------------------------------------===//
+// DynamicLibraryWriter
+//===----------------------------------------------------------------------===//
+template <class ELFT>
+void DynamicLibraryWriter<ELFT>::buildDynamicSymbolTable(const File &file) {
+ // Add all the defined symbols to the dynamic symbol table
+ // we need hooks into the Atom to find out which atoms need
+ // to be exported
+ for (auto sec : this->_layout.sections())
+ if (auto section = dyn_cast<AtomSection<ELFT>>(sec))
+ for (const auto &atom : section->atoms()) {
+ const DefinedAtom *da = dyn_cast<const DefinedAtom>(atom->_atom);
+ if (da && (da->scope() == DefinedAtom::scopeGlobal))
+ this->_dynamicSymbolTable->addSymbol(atom->_atom, section->ordinal(),
+ atom->_virtualAddr, atom);
+ }
+
+ for (const UndefinedAtom *a : file.undefined())
+ this->_dynamicSymbolTable->addSymbol(a, ELF::SHN_UNDEF);
+
+ OutputELFWriter<ELFT>::buildDynamicSymbolTable(file);
+}
+
+template <class ELFT> void DynamicLibraryWriter<ELFT>::addDefaultAtoms() {
+ _runtimeFile->addAbsoluteAtom("_end");
+}
+
+/// \brief Hook in lld to add CRuntime file
+template <class ELFT>
+bool DynamicLibraryWriter<ELFT>::createImplicitFiles(
+ std::vector<std::unique_ptr<File> > &result) {
+ // Add the default atoms as defined by executables
+ DynamicLibraryWriter<ELFT>::addDefaultAtoms();
+ OutputELFWriter<ELFT>::createImplicitFiles(result);
+ result.push_back(std::move(_runtimeFile));
+ return true;
+}
+
+template <class ELFT>
+void DynamicLibraryWriter<ELFT>::finalizeDefaultAtomValues() {
+ auto underScoreEndAtomIter = this->_layout.findAbsoluteAtom("_end");
+
+ if (auto bssSection = this->_layout.findOutputSection(".bss")) {
+ (*underScoreEndAtomIter)->_virtualAddr =
+ bssSection->virtualAddr() + bssSection->memSize();
+ } else if (auto dataSection = this->_layout.findOutputSection(".data")) {
+ (*underScoreEndAtomIter)->_virtualAddr =
+ dataSection->virtualAddr() + dataSection->memSize();
+ }
+}
+
+} // namespace elf
+} // namespace lld
+
+#endif // LLD_READER_WRITER_ELF_DYNAMIC_LIBRARY_WRITER_H
diff --git a/lib/ReaderWriter/ELF/ELFFile.h b/lib/ReaderWriter/ELF/ELFFile.h
new file mode 100644
index 000000000000..11f4ee4fc633
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ELFFile.h
@@ -0,0 +1,1179 @@
+//===- lib/ReaderWriter/ELF/ELFFile.h -------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_FILE_H
+#define LLD_READER_WRITER_ELF_FILE_H
+
+#include "Atoms.h"
+#include <llvm/ADT/MapVector.h>
+#include <map>
+#include <unordered_map>
+
+namespace lld {
+
+namespace elf {
+/// \brief Read a binary, find out based on the symbol table contents what kind
+/// of symbol it is and create corresponding atoms for it
+template <class ELFT> class ELFFile : public File {
+
+ typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+ typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr;
+ typedef llvm::object::Elf_Rel_Impl<ELFT, false> Elf_Rel;
+ typedef llvm::object::Elf_Rel_Impl<ELFT, true> Elf_Rela;
+ typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym_Iter Elf_Sym_Iter;
+ typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela_Iter Elf_Rela_Iter;
+ typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel_Iter Elf_Rel_Iter;
+ typedef typename llvm::object::ELFFile<ELFT>::Elf_Word Elf_Word;
+
+ // A Map is used to hold the atoms that have been divided up
+ // after reading the section that contains Merge String attributes
+ struct MergeSectionKey {
+ MergeSectionKey(const Elf_Shdr *shdr, int64_t offset)
+ : _shdr(shdr), _offset(offset) {}
+ // Data members
+ const Elf_Shdr *_shdr;
+ int64_t _offset;
+ };
+ struct MergeSectionEq {
+ int64_t operator()(const MergeSectionKey &k) const {
+ return llvm::hash_combine((int64_t)(k._shdr->sh_name),
+ (int64_t)k._offset);
+ }
+ bool operator()(const MergeSectionKey &lhs,
+ const MergeSectionKey &rhs) const {
+ return ((lhs._shdr->sh_name == rhs._shdr->sh_name) &&
+ (lhs._offset == rhs._offset));
+ }
+ };
+
+ struct MergeString {
+ MergeString(int64_t offset, StringRef str, const Elf_Shdr *shdr,
+ StringRef sectionName)
+ : _offset(offset), _string(str), _shdr(shdr),
+ _sectionName(sectionName) {}
+ // the offset of this atom
+ int64_t _offset;
+ // The content
+ StringRef _string;
+ // Section header
+ const Elf_Shdr *_shdr;
+ // Section name
+ StringRef _sectionName;
+ };
+
+ // This is used to find the MergeAtom given a relocation
+ // offset
+ typedef std::vector<ELFMergeAtom<ELFT> *> MergeAtomsT;
+
+ /// \brief find a mergeAtom given a start offset
+ struct FindByOffset {
+ const Elf_Shdr *_shdr;
+ int64_t _offset;
+ FindByOffset(const Elf_Shdr *shdr, int64_t offset)
+ : _shdr(shdr), _offset(offset) {}
+ bool operator()(const ELFMergeAtom<ELFT> *a) {
+ int64_t off = a->offset();
+ return (_shdr->sh_name == a->section()) &&
+ ((_offset >= off) && (_offset <= off + (int64_t)a->size()));
+ }
+ };
+
+ /// \brief find a merge atom given a offset
+ ELFMergeAtom<ELFT> *findMergeAtom(const Elf_Shdr *shdr, uint64_t offset) {
+ auto it = std::find_if(_mergeAtoms.begin(), _mergeAtoms.end(),
+ FindByOffset(shdr, offset));
+ assert(it != _mergeAtoms.end());
+ return *it;
+ }
+
+ typedef std::unordered_map<MergeSectionKey, DefinedAtom *, MergeSectionEq,
+ MergeSectionEq> MergedSectionMapT;
+ typedef typename MergedSectionMapT::iterator MergedSectionMapIterT;
+
+public:
+ ELFFile(StringRef name, ELFLinkingContext &ctx)
+ : File(name, kindObject), _ordinal(0),
+ _doStringsMerge(ctx.mergeCommonStrings()), _useWrap(false), _ctx(ctx) {
+ setLastError(std::error_code());
+ }
+
+ ELFFile(std::unique_ptr<MemoryBuffer> mb, ELFLinkingContext &ctx)
+ : File(mb->getBufferIdentifier(), kindObject), _mb(std::move(mb)),
+ _ordinal(0), _doStringsMerge(ctx.mergeCommonStrings()),
+ _useWrap(ctx.wrapCalls().size()), _ctx(ctx) {}
+
+ static ErrorOr<std::unique_ptr<ELFFile>>
+ create(std::unique_ptr<MemoryBuffer> mb, ELFLinkingContext &ctx);
+
+ virtual Reference::KindArch kindArch();
+
+ /// \brief Create symbols from LinkingContext.
+ std::error_code createAtomsFromContext();
+
+ /// \brief Read input sections and populate necessary data structures
+ /// to read them later and create atoms
+ std::error_code createAtomizableSections();
+
+ /// \brief Create mergeable atoms from sections that have the merge attribute
+ /// set
+ std::error_code createMergeableAtoms();
+
+ /// \brief Add the symbols that the sections contain. The symbols will be
+ /// converted to atoms for
+ /// Undefined symbols, absolute symbols
+ std::error_code createSymbolsFromAtomizableSections();
+
+ /// \brief Create individual atoms
+ std::error_code createAtoms();
+
+ const atom_collection<DefinedAtom> &defined() const override {
+ return _definedAtoms;
+ }
+
+ const atom_collection<UndefinedAtom> &undefined() const override {
+ return _undefinedAtoms;
+ }
+
+ const atom_collection<SharedLibraryAtom> &sharedLibrary() const override {
+ return _sharedLibraryAtoms;
+ }
+
+ const atom_collection<AbsoluteAtom> &absolute() const override {
+ return _absoluteAtoms;
+ }
+
+ Atom *findAtom(const Elf_Sym *sourceSymbol, const Elf_Sym *targetSymbol) {
+ // All references to atoms inside a group are through undefined atoms.
+ Atom *targetAtom = _symbolToAtomMapping.lookup(targetSymbol);
+ StringRef targetSymbolName = targetAtom->name();
+ if (targetAtom->definition() != Atom::definitionRegular)
+ return targetAtom;
+ if ((llvm::dyn_cast<DefinedAtom>(targetAtom))->scope() ==
+ DefinedAtom::scopeTranslationUnit)
+ return targetAtom;
+ if (!redirectReferenceUsingUndefAtom(sourceSymbol, targetSymbol))
+ return targetAtom;
+ auto undefForGroupchild = _undefAtomsForGroupChild.find(targetSymbolName);
+ if (undefForGroupchild != _undefAtomsForGroupChild.end())
+ return undefForGroupchild->getValue();
+ auto undefGroupChildAtom =
+ new (_readerStorage) SimpleUndefinedAtom(*this, targetSymbolName);
+ _undefinedAtoms._atoms.push_back(undefGroupChildAtom);
+ return (_undefAtomsForGroupChild[targetSymbolName] = undefGroupChildAtom);
+ }
+
+protected:
+ ELFDefinedAtom<ELFT> *createDefinedAtomAndAssignRelocations(
+ StringRef symbolName, StringRef sectionName, const Elf_Sym *symbol,
+ const Elf_Shdr *section, ArrayRef<uint8_t> symContent,
+ ArrayRef<uint8_t> secContent);
+
+ std::error_code doParse() override;
+
+ /// \brief Iterate over Elf_Rela relocations list and create references.
+ virtual void createRelocationReferences(const Elf_Sym *symbol,
+ ArrayRef<uint8_t> content,
+ range<Elf_Rela_Iter> rels);
+
+ /// \brief Iterate over Elf_Rel relocations list and create references.
+ virtual void createRelocationReferences(const Elf_Sym *symbol,
+ ArrayRef<uint8_t> symContent,
+ ArrayRef<uint8_t> secContent,
+ range<Elf_Rel_Iter> rels);
+
+ /// \brief After all the Atoms and References are created, update each
+ /// Reference's target with the Atom pointer it refers to.
+ void updateReferences();
+
+ /// \brief Update the reference if the access corresponds to a merge string
+ /// section.
+ void updateReferenceForMergeStringAccess(ELFReference<ELFT> *ref,
+ const Elf_Sym *symbol,
+ const Elf_Shdr *shdr);
+
+ /// \brief Do we want to ignore the section. Ignored sections are
+ /// not processed to create atoms
+ bool isIgnoredSection(const Elf_Shdr *section);
+
+ /// \brief Is the current section be treated as a mergeable string section.
+ /// The contents of a mergeable string section are null-terminated strings.
+ /// If the section have mergeable strings, the linker would need to split
+ /// the section into multiple atoms and mark them mergeByContent.
+ bool isMergeableStringSection(const Elf_Shdr *section);
+
+ /// \brief Returns a new anonymous atom whose size is equal to the
+ /// section size. That atom will be used to represent the entire
+ /// section that have no symbols.
+ ELFDefinedAtom<ELFT> *createSectionAtom(const Elf_Shdr *section,
+ StringRef sectionName,
+ ArrayRef<uint8_t> contents);
+
+ /// Returns the symbol's content size. The nextSymbol should be null if the
+ /// symbol is the last one in the section.
+ uint64_t symbolContentSize(const Elf_Shdr *section,
+ const Elf_Sym *symbol,
+ const Elf_Sym *nextSymbol);
+
+ void createEdge(ELFDefinedAtom<ELFT> *from, ELFDefinedAtom<ELFT> *to,
+ uint32_t edgeKind);
+
+ /// Get the section name for a section.
+ ErrorOr<StringRef> getSectionName(const Elf_Shdr *shdr) const {
+ if (!shdr)
+ return StringRef();
+ return _objFile->getSectionName(shdr);
+ }
+
+ /// Determines if the section occupy memory space.
+ bool sectionOccupiesMemorySpace(const Elf_Shdr *shdr) const {
+ return (shdr->sh_type != llvm::ELF::SHT_NOBITS);
+ }
+
+ /// Return the section contents.
+ ErrorOr<ArrayRef<uint8_t>> getSectionContents(const Elf_Shdr *shdr) const {
+ if (!shdr || !sectionOccupiesMemorySpace(shdr))
+ return ArrayRef<uint8_t>();
+ return _objFile->getSectionContents(shdr);
+ }
+
+ /// Returns true if the symbol is a undefined symbol.
+ bool isUndefinedSymbol(const Elf_Sym *sym) const {
+ return (sym->st_shndx == llvm::ELF::SHN_UNDEF);
+ }
+
+ /// Determines if the target wants to create an atom for a section that has no
+ /// symbol references.
+ bool handleSectionWithNoSymbols(const Elf_Shdr *shdr,
+ std::vector<Elf_Sym_Iter> &syms) const {
+ return shdr && (shdr->sh_type == llvm::ELF::SHT_PROGBITS) && syms.empty();
+ }
+
+ /// Handle creation of atoms for .gnu.linkonce sections.
+ std::error_code handleGnuLinkOnceSection(
+ StringRef sectionName,
+ llvm::StringMap<std::vector<ELFDefinedAtom<ELFT> *>> &atomsForSection,
+ const Elf_Shdr *shdr);
+
+ // Handle Section groups/COMDAT scetions.
+ std::error_code handleSectionGroup(
+ StringRef signature, StringRef groupSectionName,
+ llvm::StringMap<std::vector<ELFDefinedAtom<ELFT> *>> &atomsForSection,
+ llvm::DenseMap<const Elf_Shdr *, std::vector<StringRef>> &comdatSections,
+ const Elf_Shdr *shdr);
+
+ /// Process the Undefined symbol and create an atom for it.
+ ErrorOr<ELFUndefinedAtom<ELFT> *>
+ handleUndefinedSymbol(StringRef symName, const Elf_Sym *sym) {
+ return new (_readerStorage) ELFUndefinedAtom<ELFT>(*this, symName, sym);
+ }
+
+ /// Returns true if the symbol is a absolute symbol.
+ bool isAbsoluteSymbol(const Elf_Sym *sym) const {
+ return (sym->st_shndx == llvm::ELF::SHN_ABS);
+ }
+
+ /// Process the Absolute symbol and create an atom for it.
+ ErrorOr<ELFAbsoluteAtom<ELFT> *>
+ handleAbsoluteSymbol(StringRef symName, const Elf_Sym *sym, int64_t value) {
+ return new (_readerStorage)
+ ELFAbsoluteAtom<ELFT>(*this, symName, sym, value);
+ }
+
+ /// Returns true if the symbol is common symbol. A common symbol represents a
+ /// tentive definition in C. It has name, size and alignment constraint, but
+ /// actual storage has not yet been allocated. (The linker will allocate
+ /// storage for them in the later pass after coalescing tentative symbols by
+ /// name.)
+ virtual bool isCommonSymbol(const Elf_Sym *symbol) const {
+ return symbol->getType() == llvm::ELF::STT_COMMON ||
+ symbol->st_shndx == llvm::ELF::SHN_COMMON;
+ }
+
+ /// Returns true if the section is a gnulinkonce section.
+ bool isGnuLinkOnceSection(StringRef sectionName) const {
+ return sectionName.startswith(".gnu.linkonce.");
+ }
+
+ /// Returns true if the section is a COMDAT group section.
+ bool isGroupSection(const Elf_Shdr *shdr) const {
+ return (shdr->sh_type == llvm::ELF::SHT_GROUP);
+ }
+
+ /// Returns true if the section is a member of some group.
+ bool isSectionMemberOfGroup(const Elf_Shdr *shdr) const {
+ return (shdr->sh_flags & llvm::ELF::SHF_GROUP);
+ }
+
+ /// Returns correct st_value for the symbol depending on the architecture.
+ /// For most architectures it's just a regular st_value with no changes.
+ virtual uint64_t getSymbolValue(const Elf_Sym *symbol) const {
+ return symbol->st_value;
+ }
+
+ /// Process the common symbol and create an atom for it.
+ virtual ErrorOr<ELFCommonAtom<ELFT> *>
+ handleCommonSymbol(StringRef symName, const Elf_Sym *sym) {
+ return new (_readerStorage) ELFCommonAtom<ELFT>(*this, symName, sym);
+ }
+
+ /// Returns true if the symbol is a defined symbol.
+ virtual bool isDefinedSymbol(const Elf_Sym *sym) const {
+ return (sym->getType() == llvm::ELF::STT_NOTYPE ||
+ sym->getType() == llvm::ELF::STT_OBJECT ||
+ sym->getType() == llvm::ELF::STT_FUNC ||
+ sym->getType() == llvm::ELF::STT_GNU_IFUNC ||
+ sym->getType() == llvm::ELF::STT_SECTION ||
+ sym->getType() == llvm::ELF::STT_FILE ||
+ sym->getType() == llvm::ELF::STT_TLS);
+ }
+
+ /// Process the Defined symbol and create an atom for it.
+ virtual ErrorOr<ELFDefinedAtom<ELFT> *>
+ handleDefinedSymbol(StringRef symName, StringRef sectionName,
+ const Elf_Sym *sym, const Elf_Shdr *sectionHdr,
+ ArrayRef<uint8_t> contentData,
+ unsigned int referenceStart, unsigned int referenceEnd,
+ std::vector<ELFReference<ELFT> *> &referenceList) {
+ return new (_readerStorage) ELFDefinedAtom<ELFT>(
+ *this, symName, sectionName, sym, sectionHdr, contentData,
+ referenceStart, referenceEnd, referenceList);
+ }
+
+ /// Process the Merge string and create an atom for it.
+ ErrorOr<ELFMergeAtom<ELFT> *>
+ handleMergeString(StringRef sectionName, const Elf_Shdr *sectionHdr,
+ ArrayRef<uint8_t> contentData, unsigned int offset) {
+ ELFMergeAtom<ELFT> *mergeAtom = new (_readerStorage)
+ ELFMergeAtom<ELFT>(*this, sectionName, sectionHdr, contentData, offset);
+ const MergeSectionKey mergedSectionKey(sectionHdr, offset);
+ if (_mergedSectionMap.find(mergedSectionKey) == _mergedSectionMap.end())
+ _mergedSectionMap.insert(std::make_pair(mergedSectionKey, mergeAtom));
+ return mergeAtom;
+ }
+
+ /// References to the sections comprising a group, from sections
+ /// outside the group, must be made via global UNDEF symbols,
+ /// referencing global symbols defined as addresses in the group
+ /// sections. They may not reference local symbols for addresses in
+ /// the group's sections, including section symbols.
+ /// ABI Doc : https://mentorembedded.github.io/cxx-abi/abi/prop-72-comdat.html
+ /// Does the atom need to be redirected using a separate undefined atom?
+ bool redirectReferenceUsingUndefAtom(const Elf_Sym *sourceSymbol,
+ const Elf_Sym *targetSymbol) const;
+
+ void addReferenceToSymbol(const ELFReference<ELFT> *r, const Elf_Sym *sym) {
+ _referenceToSymbol[r] = sym;
+ }
+
+ const Elf_Sym *findSymbolForReference(const ELFReference<ELFT> *r) const {
+ auto elfReferenceToSymbol = _referenceToSymbol.find(r);
+ if (elfReferenceToSymbol != _referenceToSymbol.end())
+ return elfReferenceToSymbol->second;
+ return nullptr;
+ }
+
+ llvm::BumpPtrAllocator _readerStorage;
+ std::unique_ptr<llvm::object::ELFFile<ELFT> > _objFile;
+ atom_collection_vector<DefinedAtom> _definedAtoms;
+ atom_collection_vector<UndefinedAtom> _undefinedAtoms;
+ atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
+ atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
+
+ /// \brief _relocationAddendReferences and _relocationReferences contain the
+ /// list of relocations references. In ELF, if a section named, ".text" has
+ /// relocations will also have a section named ".rel.text" or ".rela.text"
+ /// which will hold the entries.
+ std::unordered_map<StringRef, range<Elf_Rela_Iter>>
+ _relocationAddendReferences;
+ MergedSectionMapT _mergedSectionMap;
+ std::unordered_map<StringRef, range<Elf_Rel_Iter>> _relocationReferences;
+ std::vector<ELFReference<ELFT> *> _references;
+ llvm::DenseMap<const Elf_Sym *, Atom *> _symbolToAtomMapping;
+ llvm::DenseMap<const ELFReference<ELFT> *, const Elf_Sym *>
+ _referenceToSymbol;
+ // Group child atoms have a pair corresponding to the signature and the
+ // section header of the section that was used for generating the signature.
+ llvm::DenseMap<const Elf_Sym *, std::pair<StringRef, const Elf_Shdr *>>
+ _groupChild;
+ llvm::StringMap<Atom *> _undefAtomsForGroupChild;
+
+ /// \brief Atoms that are created for a section that has the merge property
+ /// set
+ MergeAtomsT _mergeAtoms;
+
+ /// \brief the section and the symbols that are contained within it to create
+ /// used to create atoms
+ llvm::MapVector<const Elf_Shdr *, std::vector<Elf_Sym_Iter>> _sectionSymbols;
+
+ /// \brief Sections that have merge string property
+ std::vector<const Elf_Shdr *> _mergeStringSections;
+
+ std::unique_ptr<MemoryBuffer> _mb;
+ int64_t _ordinal;
+
+ /// \brief the cached options relevant while reading the ELF File
+ bool _doStringsMerge;
+
+ /// \brief Is --wrap on?
+ bool _useWrap;
+
+ /// \brief The LinkingContext.
+ ELFLinkingContext &_ctx;
+
+ // Wrap map
+ llvm::StringMap<UndefinedAtom *> _wrapSymbolMap;
+};
+
+/// \brief All atoms are owned by a File. To add linker specific atoms
+/// the atoms need to be inserted to a file called (RuntimeFile) which
+/// are basically additional symbols required by libc and other runtime
+/// libraries part of executing a program. This class provides support
+/// for adding absolute symbols and undefined symbols
+template <class ELFT> class RuntimeFile : public ELFFile<ELFT> {
+public:
+ typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+ RuntimeFile(ELFLinkingContext &context, StringRef name)
+ : ELFFile<ELFT>(name, context) {}
+
+ /// \brief add a global absolute atom
+ virtual Atom *addAbsoluteAtom(StringRef symbolName) {
+ assert(!symbolName.empty() && "AbsoluteAtoms must have a name");
+ Elf_Sym *symbol = new (this->_readerStorage) Elf_Sym;
+ symbol->st_name = 0;
+ symbol->st_value = 0;
+ symbol->st_shndx = llvm::ELF::SHN_ABS;
+ symbol->setBindingAndType(llvm::ELF::STB_GLOBAL, llvm::ELF::STT_OBJECT);
+ symbol->setVisibility(llvm::ELF::STV_DEFAULT);
+ symbol->st_size = 0;
+ auto newAtom = this->handleAbsoluteSymbol(symbolName, symbol, -1);
+ this->_absoluteAtoms._atoms.push_back(*newAtom);
+ return *newAtom;
+ }
+
+ /// \brief add an undefined atom
+ virtual Atom *addUndefinedAtom(StringRef symbolName) {
+ assert(!symbolName.empty() && "UndefinedAtoms must have a name");
+ Elf_Sym *symbol = new (this->_readerStorage) Elf_Sym;
+ symbol->st_name = 0;
+ symbol->st_value = 0;
+ symbol->st_shndx = llvm::ELF::SHN_UNDEF;
+ symbol->setBindingAndType(llvm::ELF::STB_GLOBAL, llvm::ELF::STT_NOTYPE);
+ symbol->setVisibility(llvm::ELF::STV_DEFAULT);
+ symbol->st_size = 0;
+ auto newAtom = this->handleUndefinedSymbol(symbolName, symbol);
+ this->_undefinedAtoms._atoms.push_back(*newAtom);
+ return *newAtom;
+ }
+
+ // cannot add atoms to Runtime file
+ virtual void addAtom(const Atom &) {
+ llvm_unreachable("cannot add atoms to Runtime files");
+ }
+};
+
+template <class ELFT>
+ErrorOr<std::unique_ptr<ELFFile<ELFT>>>
+ELFFile<ELFT>::create(std::unique_ptr<MemoryBuffer> mb,
+ ELFLinkingContext &ctx) {
+ std::unique_ptr<ELFFile<ELFT>> file(new ELFFile<ELFT>(std::move(mb), ctx));
+ return std::move(file);
+}
+
+template <class ELFT>
+std::error_code ELFFile<ELFT>::doParse() {
+ std::error_code ec;
+ _objFile.reset(new llvm::object::ELFFile<ELFT>(_mb->getBuffer(), ec));
+ if (ec)
+ return ec;
+
+ if ((ec = createAtomsFromContext()))
+ return ec;
+
+ // Read input sections from the input file that need to be converted to
+ // atoms
+ if ((ec = createAtomizableSections()))
+ return ec;
+
+ // For mergeable strings, we would need to split the section into various
+ // atoms
+ if ((ec = createMergeableAtoms()))
+ return ec;
+
+ // Create the necessary symbols that are part of the section that we
+ // created in createAtomizableSections function
+ if ((ec = createSymbolsFromAtomizableSections()))
+ return ec;
+
+ // Create the appropriate atoms from the file
+ if ((ec = createAtoms()))
+ return ec;
+ return std::error_code();
+}
+
+template <class ELFT> Reference::KindArch ELFFile<ELFT>::kindArch() {
+ switch (_objFile->getHeader()->e_machine) {
+ case llvm::ELF::EM_X86_64:
+ return Reference::KindArch::x86_64;
+ case llvm::ELF::EM_386:
+ return Reference::KindArch::x86;
+ case llvm::ELF::EM_ARM:
+ return Reference::KindArch::ARM;
+ case llvm::ELF::EM_HEXAGON:
+ return Reference::KindArch::Hexagon;
+ case llvm::ELF::EM_MIPS:
+ return Reference::KindArch::Mips;
+ case llvm::ELF::EM_AARCH64:
+ return Reference::KindArch::AArch64;
+ }
+ llvm_unreachable("unsupported e_machine value");
+}
+
+template <class ELFT>
+std::error_code ELFFile<ELFT>::createAtomizableSections() {
+ // Handle: SHT_REL and SHT_RELA sections:
+ // Increment over the sections, when REL/RELA section types are found add
+ // the contents to the RelocationReferences map.
+ // Record the number of relocs to guess at preallocating the buffer.
+ uint64_t totalRelocs = 0;
+ for (const Elf_Shdr &section : _objFile->sections()) {
+ if (isIgnoredSection(&section))
+ continue;
+
+ if (isMergeableStringSection(&section)) {
+ _mergeStringSections.push_back(&section);
+ continue;
+ }
+
+ if (section.sh_type == llvm::ELF::SHT_RELA) {
+ auto sHdr = _objFile->getSection(section.sh_info);
+
+ auto sectionName = _objFile->getSectionName(sHdr);
+ if (std::error_code ec = sectionName.getError())
+ return ec;
+
+ auto rai(_objFile->begin_rela(&section));
+ auto rae(_objFile->end_rela(&section));
+
+ _relocationAddendReferences[*sectionName] = make_range(rai, rae);
+ totalRelocs += std::distance(rai, rae);
+ } else if (section.sh_type == llvm::ELF::SHT_REL) {
+ auto sHdr = _objFile->getSection(section.sh_info);
+
+ auto sectionName = _objFile->getSectionName(sHdr);
+ if (std::error_code ec = sectionName.getError())
+ return ec;
+
+ auto ri(_objFile->begin_rel(&section));
+ auto re(_objFile->end_rel(&section));
+
+ _relocationReferences[*sectionName] = make_range(ri, re);
+ totalRelocs += std::distance(ri, re);
+ } else {
+ _sectionSymbols[&section];
+ }
+ }
+ _references.reserve(totalRelocs);
+ return std::error_code();
+}
+
+template <class ELFT> std::error_code ELFFile<ELFT>::createMergeableAtoms() {
+ // Divide the section that contains mergeable strings into tokens
+ // TODO
+ // a) add resolver support to recognize multibyte chars
+ // b) Create a separate section chunk to write mergeable atoms
+ std::vector<MergeString *> tokens;
+ for (const Elf_Shdr *msi : _mergeStringSections) {
+ auto sectionName = getSectionName(msi);
+ if (std::error_code ec = sectionName.getError())
+ return ec;
+
+ auto sectionContents = getSectionContents(msi);
+ if (std::error_code ec = sectionContents.getError())
+ return ec;
+
+ StringRef secCont(reinterpret_cast<const char *>(sectionContents->begin()),
+ sectionContents->size());
+
+ unsigned int prev = 0;
+ for (std::size_t i = 0, e = sectionContents->size(); i != e; ++i) {
+ if ((*sectionContents)[i] == '\0') {
+ tokens.push_back(new (_readerStorage) MergeString(
+ prev, secCont.slice(prev, i + 1), msi, *sectionName));
+ prev = i + 1;
+ }
+ }
+ }
+
+ // Create Mergeable atoms
+ for (const MergeString *tai : tokens) {
+ ArrayRef<uint8_t> content((const uint8_t *)tai->_string.data(),
+ tai->_string.size());
+ ErrorOr<ELFMergeAtom<ELFT> *> mergeAtom =
+ handleMergeString(tai->_sectionName, tai->_shdr, content, tai->_offset);
+ (*mergeAtom)->setOrdinal(++_ordinal);
+ _definedAtoms._atoms.push_back(*mergeAtom);
+ _mergeAtoms.push_back(*mergeAtom);
+ }
+ return std::error_code();
+}
+
+template <class ELFT>
+std::error_code ELFFile<ELFT>::createSymbolsFromAtomizableSections() {
+ // Increment over all the symbols collecting atoms and symbol names for
+ // later use.
+ auto SymI = _objFile->begin_symbols(), SymE = _objFile->end_symbols();
+
+ // Skip over dummy sym.
+ if (SymI != SymE)
+ ++SymI;
+
+ for (; SymI != SymE; ++SymI) {
+ const Elf_Shdr *section = _objFile->getSection(&*SymI);
+
+ auto symbolName = _objFile->getSymbolName(SymI);
+ if (std::error_code ec = symbolName.getError())
+ return ec;
+
+ if (isAbsoluteSymbol(&*SymI)) {
+ ErrorOr<ELFAbsoluteAtom<ELFT> *> absAtom =
+ handleAbsoluteSymbol(*symbolName, &*SymI, (int64_t)getSymbolValue(&*SymI));
+ _absoluteAtoms._atoms.push_back(*absAtom);
+ _symbolToAtomMapping.insert(std::make_pair(&*SymI, *absAtom));
+ } else if (isUndefinedSymbol(&*SymI)) {
+ if (_useWrap &&
+ (_wrapSymbolMap.find(*symbolName) != _wrapSymbolMap.end())) {
+ auto wrapAtom = _wrapSymbolMap.find(*symbolName);
+ _symbolToAtomMapping.insert(
+ std::make_pair(&*SymI, wrapAtom->getValue()));
+ continue;
+ }
+ ErrorOr<ELFUndefinedAtom<ELFT> *> undefAtom =
+ handleUndefinedSymbol(*symbolName, &*SymI);
+ _undefinedAtoms._atoms.push_back(*undefAtom);
+ _symbolToAtomMapping.insert(std::make_pair(&*SymI, *undefAtom));
+ } else if (isCommonSymbol(&*SymI)) {
+ ErrorOr<ELFCommonAtom<ELFT> *> commonAtom =
+ handleCommonSymbol(*symbolName, &*SymI);
+ (*commonAtom)->setOrdinal(++_ordinal);
+ _definedAtoms._atoms.push_back(*commonAtom);
+ _symbolToAtomMapping.insert(std::make_pair(&*SymI, *commonAtom));
+ } else if (isDefinedSymbol(&*SymI)) {
+ _sectionSymbols[section].push_back(SymI);
+ } else {
+ llvm::errs() << "Unable to create atom for: " << *symbolName << "\n";
+ return llvm::object::object_error::parse_failed;
+ }
+ }
+
+ return std::error_code();
+}
+
+template <class ELFT> std::error_code ELFFile<ELFT>::createAtoms() {
+ // Holds all the atoms that are part of the section. They are the targets of
+ // the kindGroupChild reference.
+ llvm::StringMap<std::vector<ELFDefinedAtom<ELFT> *>> atomsForSection;
+ // group sections have a mapping of the section header to the
+ // signature/section.
+ llvm::DenseMap<const Elf_Shdr *, std::pair<StringRef, StringRef>>
+ groupSections;
+ // Contains a list of comdat sections for a group.
+ llvm::DenseMap<const Elf_Shdr *, std::vector<StringRef>> comdatSections;
+ for (auto &i : _sectionSymbols) {
+ const Elf_Shdr *section = i.first;
+ std::vector<Elf_Sym_Iter> &symbols = i.second;
+
+ // Sort symbols by position.
+ std::stable_sort(symbols.begin(), symbols.end(),
+ [this](Elf_Sym_Iter a, Elf_Sym_Iter b) {
+ return getSymbolValue(&*a) < getSymbolValue(&*b);
+ });
+
+ ErrorOr<StringRef> sectionName = this->getSectionName(section);
+ if (std::error_code ec = sectionName.getError())
+ return ec;
+
+ auto sectionContents = getSectionContents(section);
+ if (std::error_code ec = sectionContents.getError())
+ return ec;
+
+ bool addAtoms = true;
+
+ // A section of type SHT_GROUP defines a grouping of sections. The name of a
+ // symbol from one of the containing object's symbol tables provides a
+ // signature
+ // for the section group. The section header of the SHT_GROUP section
+ // specifies
+ // the identifying symbol entry, as described : the sh_link member contains
+ // the section header index of the symbol table section that contains the
+ // entry.
+ // The sh_info member contains the symbol table index of the identifying
+ // entry.
+ // The sh_flags member of the section header contains 0. The name of the
+ // section
+ // (sh_name) is not specified.
+ if (isGroupSection(section)) {
+ const Elf_Word *groupMembers =
+ reinterpret_cast<const Elf_Word *>(sectionContents->data());
+ const long count = (section->sh_size) / sizeof(Elf_Word);
+ for (int i = 1; i < count; i++) {
+ const Elf_Shdr *sHdr = _objFile->getSection(groupMembers[i]);
+ ErrorOr<StringRef> sectionName = _objFile->getSectionName(sHdr);
+ if (std::error_code ec = sectionName.getError())
+ return ec;
+ comdatSections[section].push_back(*sectionName);
+ }
+ const Elf_Sym *symbol = _objFile->getSymbol(section->sh_info);
+ const Elf_Shdr *symtab = _objFile->getSection(section->sh_link);
+ ErrorOr<StringRef> symbolName = _objFile->getSymbolName(symtab, symbol);
+ if (std::error_code ec = symbolName.getError())
+ return ec;
+ groupSections.insert(
+ std::make_pair(section, std::make_pair(*symbolName, *sectionName)));
+ continue;
+ }
+
+ if (isGnuLinkOnceSection(*sectionName)) {
+ groupSections.insert(
+ std::make_pair(section, std::make_pair(*sectionName, *sectionName)));
+ addAtoms = false;
+ }
+
+ if (isSectionMemberOfGroup(section))
+ addAtoms = false;
+
+ if (handleSectionWithNoSymbols(section, symbols)) {
+ ELFDefinedAtom<ELFT> *newAtom =
+ createSectionAtom(section, *sectionName, *sectionContents);
+ newAtom->setOrdinal(++_ordinal);
+ if (addAtoms)
+ _definedAtoms._atoms.push_back(newAtom);
+ else
+ atomsForSection[*sectionName].push_back(newAtom);
+ continue;
+ }
+
+ ELFDefinedAtom<ELFT> *previousAtom = nullptr;
+ ELFReference<ELFT> *anonFollowedBy = nullptr;
+
+ for (auto si = symbols.begin(), se = symbols.end(); si != se; ++si) {
+ auto symbol = *si;
+ StringRef symbolName = "";
+ if (symbol->getType() != llvm::ELF::STT_SECTION) {
+ auto symName = _objFile->getSymbolName(symbol);
+ if (std::error_code ec = symName.getError())
+ return ec;
+ symbolName = *symName;
+ }
+
+ uint64_t contentSize = symbolContentSize(
+ section, &*symbol, (si + 1 == se) ? nullptr : &**(si + 1));
+
+ // Check to see if we need to add the FollowOn Reference
+ ELFReference<ELFT> *followOn = nullptr;
+ if (previousAtom) {
+ // Replace the followon atom with the anonymous atom that we created,
+ // so that the next symbol that we create is a followon from the
+ // anonymous atom.
+ if (anonFollowedBy) {
+ followOn = anonFollowedBy;
+ } else {
+ followOn = new (_readerStorage)
+ ELFReference<ELFT>(lld::Reference::kindLayoutAfter);
+ previousAtom->addReference(followOn);
+ }
+ }
+
+ ArrayRef<uint8_t> symbolData((const uint8_t *)sectionContents->data() +
+ getSymbolValue(&*symbol),
+ contentSize);
+
+ // If the linker finds that a section has global atoms that are in a
+ // mergeable section, treat them as defined atoms as they shouldn't be
+ // merged away as well as these symbols have to be part of symbol
+ // resolution
+ if (isMergeableStringSection(section)) {
+ if (symbol->getBinding() == llvm::ELF::STB_GLOBAL) {
+ auto definedMergeAtom = handleDefinedSymbol(
+ symbolName, *sectionName, &**si, section, symbolData,
+ _references.size(), _references.size(), _references);
+ (*definedMergeAtom)->setOrdinal(++_ordinal);
+ if (addAtoms)
+ _definedAtoms._atoms.push_back(*definedMergeAtom);
+ else
+ atomsForSection[*sectionName].push_back(*definedMergeAtom);
+ }
+ continue;
+ }
+
+ // Don't allocate content to a weak symbol, as they may be merged away.
+ // Create an anonymous atom to hold the data.
+ ELFDefinedAtom<ELFT> *anonAtom = nullptr;
+ anonFollowedBy = nullptr;
+ if (symbol->getBinding() == llvm::ELF::STB_WEAK) {
+ // Create anonymous new non-weak ELF symbol that holds the symbol
+ // data.
+ auto sym = new (_readerStorage) Elf_Sym(*symbol);
+ sym->setBinding(llvm::ELF::STB_GLOBAL);
+ anonAtom = createDefinedAtomAndAssignRelocations(
+ "", *sectionName, sym, section, symbolData, *sectionContents);
+ symbolData = ArrayRef<uint8_t>();
+
+ // If this is the last atom, let's not create a followon reference.
+ if (anonAtom && (si + 1) != se) {
+ anonFollowedBy = new (_readerStorage)
+ ELFReference<ELFT>(lld::Reference::kindLayoutAfter);
+ anonAtom->addReference(anonFollowedBy);
+ }
+ }
+
+ ELFDefinedAtom<ELFT> *newAtom = createDefinedAtomAndAssignRelocations(
+ symbolName, *sectionName, &*symbol, section, symbolData,
+ *sectionContents);
+ newAtom->setOrdinal(++_ordinal);
+
+ // If the atom was a weak symbol, let's create a followon reference to
+ // the anonymous atom that we created.
+ if (anonAtom)
+ createEdge(newAtom, anonAtom, Reference::kindLayoutAfter);
+
+ if (previousAtom) {
+ // Set the followon atom to the weak atom that we have created, so
+ // that they would alias when the file gets written.
+ followOn->setTarget(anonAtom ? anonAtom : newAtom);
+ }
+
+ // The previous atom is always the atom created before unless the atom
+ // is a weak atom.
+ previousAtom = anonAtom ? anonAtom : newAtom;
+
+ if (addAtoms)
+ _definedAtoms._atoms.push_back(newAtom);
+ else
+ atomsForSection[*sectionName].push_back(newAtom);
+
+ _symbolToAtomMapping.insert(std::make_pair(&*symbol, newAtom));
+ if (anonAtom) {
+ anonAtom->setOrdinal(++_ordinal);
+ if (addAtoms)
+ _definedAtoms._atoms.push_back(anonAtom);
+ else
+ atomsForSection[*sectionName].push_back(anonAtom);
+ }
+ }
+ }
+
+ // Iterate over all the group sections to create parent atoms pointing to
+ // group-child atoms.
+ for (auto &sect : groupSections) {
+ StringRef signature = sect.second.first;
+ StringRef groupSectionName = sect.second.second;
+ if (isGnuLinkOnceSection(signature))
+ handleGnuLinkOnceSection(signature, atomsForSection, sect.first);
+ else if (isGroupSection(sect.first))
+ handleSectionGroup(signature, groupSectionName, atomsForSection,
+ comdatSections, sect.first);
+ }
+
+ updateReferences();
+ return std::error_code();
+}
+
+template <class ELFT>
+std::error_code ELFFile<ELFT>::handleGnuLinkOnceSection(
+ StringRef signature,
+ llvm::StringMap<std::vector<ELFDefinedAtom<ELFT> *>> &atomsForSection,
+ const Elf_Shdr *shdr) {
+ // TODO: Check for errors.
+ unsigned int referenceStart = _references.size();
+ std::vector<ELFReference<ELFT> *> refs;
+ for (auto ha : atomsForSection[signature]) {
+ _groupChild[ha->symbol()] = std::make_pair(signature, shdr);
+ ELFReference<ELFT> *ref =
+ new (_readerStorage) ELFReference<ELFT>(lld::Reference::kindGroupChild);
+ ref->setTarget(ha);
+ refs.push_back(ref);
+ }
+ atomsForSection[signature].clear();
+ // Create a gnu linkonce atom.
+ auto gnuLinkOnceAtom = handleDefinedSymbol(
+ signature, signature, nullptr, shdr, ArrayRef<uint8_t>(), referenceStart,
+ _references.size(), _references);
+ (*gnuLinkOnceAtom)->setOrdinal(++_ordinal);
+ _definedAtoms._atoms.push_back(*gnuLinkOnceAtom);
+ for (auto reference : refs)
+ (*gnuLinkOnceAtom)->addReference(reference);
+ return std::error_code();
+}
+
+template <class ELFT>
+std::error_code ELFFile<ELFT>::handleSectionGroup(
+ StringRef signature, StringRef groupSectionName,
+ llvm::StringMap<std::vector<ELFDefinedAtom<ELFT> *>> &atomsForSection,
+ llvm::DenseMap<const Elf_Shdr *, std::vector<StringRef>> &comdatSections,
+ const Elf_Shdr *shdr) {
+ // TODO: Check for errors.
+ unsigned int referenceStart = _references.size();
+ std::vector<ELFReference<ELFT> *> refs;
+ auto sectionNamesInGroup = comdatSections[shdr];
+ for (auto sectionName : sectionNamesInGroup) {
+ for (auto ha : atomsForSection[sectionName]) {
+ _groupChild[ha->symbol()] = std::make_pair(signature, shdr);
+ ELFReference<ELFT> *ref = new (_readerStorage)
+ ELFReference<ELFT>(lld::Reference::kindGroupChild);
+ ref->setTarget(ha);
+ refs.push_back(ref);
+ }
+ atomsForSection[sectionName].clear();
+ }
+ // Create a gnu linkonce atom.
+ auto sectionGroupAtom = handleDefinedSymbol(
+ signature, groupSectionName, nullptr, shdr, ArrayRef<uint8_t>(),
+ referenceStart, _references.size(), _references);
+ (*sectionGroupAtom)->setOrdinal(++_ordinal);
+ _definedAtoms._atoms.push_back(*sectionGroupAtom);
+ for (auto reference : refs)
+ (*sectionGroupAtom)->addReference(reference);
+ return std::error_code();
+}
+
+template <class ELFT> std::error_code ELFFile<ELFT>::createAtomsFromContext() {
+ if (!_useWrap)
+ return std::error_code();
+ // Steps :-
+ // a) Create an undefined atom for the symbol specified by the --wrap option,
+ // as that
+ // may be needed to be pulled from an archive.
+ // b) Create an undefined atom for __wrap_<symbolname>.
+ // c) All references to the symbol specified by wrap should point to
+ // __wrap_<symbolname>
+ // d) All references to __real_symbol should point to the <symbol>
+ for (auto &wrapsym : _ctx.wrapCalls()) {
+ StringRef wrapStr = wrapsym.getKey();
+ // Create a undefined symbol fror the wrap symbol.
+ UndefinedAtom *wrapSymAtom =
+ new (_readerStorage) SimpleUndefinedAtom(*this, wrapStr);
+ StringRef wrapCallSym =
+ _ctx.allocateString((llvm::Twine("__wrap_") + wrapStr).str());
+ StringRef realCallSym =
+ _ctx.allocateString((llvm::Twine("__real_") + wrapStr).str());
+ UndefinedAtom *wrapCallAtom =
+ new (_readerStorage) SimpleUndefinedAtom(*this, wrapCallSym);
+ // Create maps, when there is call to sym, it should point to wrapCallSym.
+ _wrapSymbolMap.insert(std::make_pair(wrapStr, wrapCallAtom));
+ // Whenever there is a reference to realCall it should point to the symbol
+ // created for each wrap usage.
+ _wrapSymbolMap.insert(std::make_pair(realCallSym, wrapSymAtom));
+ _undefinedAtoms._atoms.push_back(wrapSymAtom);
+ _undefinedAtoms._atoms.push_back(wrapCallAtom);
+ }
+ return std::error_code();
+}
+
+template <class ELFT>
+ELFDefinedAtom<ELFT> *ELFFile<ELFT>::createDefinedAtomAndAssignRelocations(
+ StringRef symbolName, StringRef sectionName, const Elf_Sym *symbol,
+ const Elf_Shdr *section, ArrayRef<uint8_t> symContent,
+ ArrayRef<uint8_t> secContent) {
+ unsigned int referenceStart = _references.size();
+
+ // Add Rela (those with r_addend) references:
+ auto rari = _relocationAddendReferences.find(sectionName);
+ if (rari != _relocationAddendReferences.end())
+ createRelocationReferences(symbol, symContent, rari->second);
+
+ // Add Rel references.
+ auto rri = _relocationReferences.find(sectionName);
+ if (rri != _relocationReferences.end())
+ createRelocationReferences(symbol, symContent, secContent, rri->second);
+
+ // Create the DefinedAtom and add it to the list of DefinedAtoms.
+ return *handleDefinedSymbol(symbolName, sectionName, symbol, section,
+ symContent, referenceStart, _references.size(),
+ _references);
+}
+
+template <class ELFT>
+void ELFFile<ELFT>::createRelocationReferences(const Elf_Sym *symbol,
+ ArrayRef<uint8_t> content,
+ range<Elf_Rela_Iter> rels) {
+ bool isMips64EL = _objFile->isMips64EL();
+ const auto symValue = getSymbolValue(symbol);
+ for (const auto &rel : rels) {
+ if (rel.r_offset < symValue ||
+ symValue + content.size() <= rel.r_offset)
+ continue;
+ auto elfRelocation = new (_readerStorage)
+ ELFReference<ELFT>(&rel, rel.r_offset - symValue, kindArch(),
+ rel.getType(isMips64EL), rel.getSymbol(isMips64EL));
+ addReferenceToSymbol(elfRelocation, symbol);
+ _references.push_back(elfRelocation);
+ }
+}
+
+template <class ELFT>
+void ELFFile<ELFT>::createRelocationReferences(const Elf_Sym *symbol,
+ ArrayRef<uint8_t> symContent,
+ ArrayRef<uint8_t> secContent,
+ range<Elf_Rel_Iter> rels) {
+ bool isMips64EL = _objFile->isMips64EL();
+ const auto symValue = getSymbolValue(symbol);
+ for (const auto &rel : rels) {
+ if (rel.r_offset < symValue ||
+ symValue + symContent.size() <= rel.r_offset)
+ continue;
+ auto elfRelocation = new (_readerStorage)
+ ELFReference<ELFT>(rel.r_offset - symValue, kindArch(),
+ rel.getType(isMips64EL), rel.getSymbol(isMips64EL));
+ int32_t addend = *(symContent.data() + rel.r_offset - symValue);
+ elfRelocation->setAddend(addend);
+ addReferenceToSymbol(elfRelocation, symbol);
+ _references.push_back(elfRelocation);
+ }
+}
+
+template <class ELFT>
+void ELFFile<ELFT>::updateReferenceForMergeStringAccess(ELFReference<ELFT> *ref,
+ const Elf_Sym *symbol,
+ const Elf_Shdr *shdr) {
+ // If the target atom is mergeable strefng atom, the atom might have been
+ // merged with other atom having the same contents. Try to find the
+ // merged one if that's the case.
+ int64_t addend = ref->addend();
+ if (addend < 0)
+ addend = 0;
+
+ const MergeSectionKey ms(shdr, addend);
+ auto msec = _mergedSectionMap.find(ms);
+ if (msec != _mergedSectionMap.end()) {
+ ref->setTarget(msec->second);
+ return;
+ }
+
+ // The target atom was not merged. Mergeable atoms are not in
+ // _symbolToAtomMapping, so we cannot find it by calling findAtom(). We
+ // instead call findMergeAtom().
+ if (symbol->getType() != llvm::ELF::STT_SECTION)
+ addend = getSymbolValue(symbol) + addend;
+ ELFMergeAtom<ELFT> *mergedAtom = findMergeAtom(shdr, addend);
+ ref->setOffset(addend - mergedAtom->offset());
+ ref->setAddend(0);
+ ref->setTarget(mergedAtom);
+}
+
+template <class ELFT> void ELFFile<ELFT>::updateReferences() {
+ for (auto &ri : _references) {
+ if (ri->kindNamespace() != lld::Reference::KindNamespace::ELF)
+ continue;
+ const Elf_Sym *symbol = _objFile->getSymbol(ri->targetSymbolIndex());
+ const Elf_Shdr *shdr = _objFile->getSection(symbol);
+
+ // If the atom is not in mergeable string section, the target atom is
+ // simply that atom.
+ if (isMergeableStringSection(shdr))
+ updateReferenceForMergeStringAccess(ri, symbol, shdr);
+ else
+ ri->setTarget(findAtom(findSymbolForReference(ri), symbol));
+ }
+}
+
+template <class ELFT>
+bool ELFFile<ELFT>::isIgnoredSection(const Elf_Shdr *section) {
+ switch (section->sh_type) {
+ case llvm::ELF::SHT_NULL:
+ case llvm::ELF::SHT_STRTAB:
+ case llvm::ELF::SHT_SYMTAB:
+ case llvm::ELF::SHT_SYMTAB_SHNDX:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+template <class ELFT>
+bool ELFFile<ELFT>::isMergeableStringSection(const Elf_Shdr *section) {
+ if (_doStringsMerge && section) {
+ int64_t sectionFlags = section->sh_flags;
+ sectionFlags &= ~llvm::ELF::SHF_ALLOC;
+ // Mergeable string sections have both SHF_MERGE and SHF_STRINGS flags
+ // set. sh_entsize is the size of each character which is normally 1.
+ if ((section->sh_entsize < 2) &&
+ (sectionFlags == (llvm::ELF::SHF_MERGE | llvm::ELF::SHF_STRINGS))) {
+ return true;
+ }
+ }
+ return false;
+}
+
+template <class ELFT>
+ELFDefinedAtom<ELFT> *
+ELFFile<ELFT>::createSectionAtom(const Elf_Shdr *section, StringRef sectionName,
+ ArrayRef<uint8_t> content) {
+ Elf_Sym *sym = new (_readerStorage) Elf_Sym;
+ sym->st_name = 0;
+ sym->setBindingAndType(llvm::ELF::STB_LOCAL, llvm::ELF::STT_SECTION);
+ sym->st_other = 0;
+ sym->st_shndx = 0;
+ sym->st_value = 0;
+ sym->st_size = 0;
+ auto *newAtom = createDefinedAtomAndAssignRelocations(
+ "", sectionName, sym, section, content, content);
+ newAtom->setOrdinal(++_ordinal);
+ return newAtom;
+}
+
+template <class ELFT>
+uint64_t ELFFile<ELFT>::symbolContentSize(const Elf_Shdr *section,
+ const Elf_Sym *symbol,
+ const Elf_Sym *nextSymbol) {
+ const auto symValue = getSymbolValue(symbol);
+ // if this is the last symbol, take up the remaining data.
+ return nextSymbol ? getSymbolValue(nextSymbol) - symValue
+ : section->sh_size - symValue;
+}
+
+template <class ELFT>
+void ELFFile<ELFT>::createEdge(ELFDefinedAtom<ELFT> *from,
+ ELFDefinedAtom<ELFT> *to, uint32_t edgeKind) {
+ auto reference = new (_readerStorage) ELFReference<ELFT>(edgeKind);
+ reference->setTarget(to);
+ from->addReference(reference);
+}
+
+/// Does the atom need to be redirected using a separate undefined atom?
+template <class ELFT>
+bool ELFFile<ELFT>::redirectReferenceUsingUndefAtom(
+ const Elf_Sym *sourceSymbol, const Elf_Sym *targetSymbol) const {
+ auto groupChildTarget = _groupChild.find(targetSymbol);
+
+ // If the reference is not to a group child atom, there is no need to redirect
+ // using a undefined atom. Its also not needed if the source and target are
+ // from the same section.
+ if ((groupChildTarget == _groupChild.end()) ||
+ (sourceSymbol->st_shndx == targetSymbol->st_shndx))
+ return false;
+
+ auto groupChildSource = _groupChild.find(sourceSymbol);
+
+ // If the source symbol is not in a group, use a undefined symbol too.
+ if (groupChildSource == _groupChild.end())
+ return true;
+
+ // If the source and child are from the same group, we dont need the
+ // relocation to go through a undefined symbol.
+ if (groupChildSource->second.second == groupChildTarget->second.second)
+ return false;
+
+ return true;
+}
+
+} // end namespace elf
+} // end namespace lld
+
+#endif // LLD_READER_WRITER_ELF_FILE_H
diff --git a/lib/ReaderWriter/ELF/ELFLinkingContext.cpp b/lib/ReaderWriter/ELF/ELFLinkingContext.cpp
new file mode 100644
index 000000000000..c7dffda8a463
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ELFLinkingContext.cpp
@@ -0,0 +1,259 @@
+//===- lib/ReaderWriter/ELF/ELFLinkingContext.cpp -------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/ReaderWriter/ELFLinkingContext.h"
+#include "ELFFile.h"
+#include "OrderPass.h"
+#include "TargetHandler.h"
+#include "lld/Core/Instrumentation.h"
+#include "lld/Core/SharedLibraryFile.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Config/config.h"
+#include "llvm/Support/ELF.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+
+#if defined(HAVE_CXXABI_H)
+#include <cxxabi.h>
+#endif
+
+namespace lld {
+
+class CommandLineUndefinedAtom : public SimpleUndefinedAtom {
+public:
+ CommandLineUndefinedAtom(const File &f, StringRef name)
+ : SimpleUndefinedAtom(f, name) {}
+
+ CanBeNull canBeNull() const override {
+ return CanBeNull::canBeNullAtBuildtime;
+ }
+};
+
+ELFLinkingContext::ELFLinkingContext(
+ llvm::Triple triple, std::unique_ptr<TargetHandlerBase> targetHandler)
+ : _outputELFType(llvm::ELF::ET_EXEC), _triple(triple),
+ _targetHandler(std::move(targetHandler)), _baseAddress(0),
+ _isStaticExecutable(false), _noInhibitExec(false), _exportDynamic(false),
+ _mergeCommonStrings(false), _useShlibUndefines(true),
+ _dynamicLinkerArg(false), _noAllowDynamicLibraries(false),
+ _mergeRODataToTextSegment(true), _demangle(true),
+ _stripSymbols(false), _alignSegments(true), _collectStats(false),
+ _outputMagic(OutputMagic::DEFAULT), _initFunction("_init"),
+ _finiFunction("_fini"), _sysrootPath(""), _linkerScriptSema() {}
+
+void ELFLinkingContext::addPasses(PassManager &pm) {
+ pm.add(llvm::make_unique<elf::OrderPass>());
+}
+
+uint16_t ELFLinkingContext::getOutputMachine() const {
+ switch (getTriple().getArch()) {
+ case llvm::Triple::x86:
+ return llvm::ELF::EM_386;
+ case llvm::Triple::x86_64:
+ return llvm::ELF::EM_X86_64;
+ case llvm::Triple::hexagon:
+ return llvm::ELF::EM_HEXAGON;
+ case llvm::Triple::mipsel:
+ case llvm::Triple::mips64el:
+ return llvm::ELF::EM_MIPS;
+ case llvm::Triple::aarch64:
+ return llvm::ELF::EM_AARCH64;
+ case llvm::Triple::arm:
+ return llvm::ELF::EM_ARM;
+ default:
+ llvm_unreachable("Unhandled arch");
+ }
+}
+
+StringRef ELFLinkingContext::entrySymbolName() const {
+ if (_outputELFType == llvm::ELF::ET_EXEC && _entrySymbolName.empty())
+ return "_start";
+ return _entrySymbolName;
+}
+
+bool ELFLinkingContext::validateImpl(raw_ostream &diagnostics) {
+ switch (outputFileType()) {
+ case LinkingContext::OutputFileType::YAML:
+ _writer = createWriterYAML(*this);
+ break;
+ case LinkingContext::OutputFileType::Native:
+ llvm_unreachable("Unimplemented");
+ break;
+ default:
+ _writer = createWriterELF(this->targetHandler());
+ break;
+ }
+
+ // If -dead_strip, set up initial live symbols.
+ if (deadStrip())
+ addDeadStripRoot(entrySymbolName());
+ return true;
+}
+
+bool ELFLinkingContext::isDynamic() const {
+ switch (_outputELFType) {
+ case llvm::ELF::ET_EXEC:
+ return !_isStaticExecutable;
+ case llvm::ELF::ET_DYN:
+ return true;
+ }
+ return false;
+}
+
+bool ELFLinkingContext::isRelativeReloc(const Reference &) const {
+ return false;
+}
+
+Writer &ELFLinkingContext::writer() const { return *_writer; }
+
+static void buildSearchPath(SmallString<128> &path, StringRef dir,
+ StringRef sysRoot) {
+ if (!dir.startswith("=/"))
+ path.assign(dir);
+ else {
+ path.assign(sysRoot);
+ path.append(dir.substr(1));
+ }
+}
+
+ErrorOr<StringRef> ELFLinkingContext::searchLibrary(StringRef libName) const {
+ bool hasColonPrefix = libName[0] == ':';
+ SmallString<128> path;
+ for (StringRef dir : _inputSearchPaths) {
+ // Search for dynamic library
+ if (!_isStaticExecutable) {
+ buildSearchPath(path, dir, _sysrootPath);
+ llvm::sys::path::append(path, hasColonPrefix
+ ? libName.drop_front()
+ : Twine("lib", libName) + ".so");
+ if (llvm::sys::fs::exists(path.str()))
+ return StringRef(*new (_allocator) std::string(path.str()));
+ }
+ // Search for static libraries too
+ buildSearchPath(path, dir, _sysrootPath);
+ llvm::sys::path::append(path, hasColonPrefix
+ ? libName.drop_front()
+ : Twine("lib", libName) + ".a");
+ if (llvm::sys::fs::exists(path.str()))
+ return StringRef(*new (_allocator) std::string(path.str()));
+ }
+ if (hasColonPrefix && llvm::sys::fs::exists(libName.drop_front()))
+ return libName.drop_front();
+
+ return make_error_code(llvm::errc::no_such_file_or_directory);
+}
+
+ErrorOr<StringRef> ELFLinkingContext::searchFile(StringRef fileName,
+ bool isSysRooted) const {
+ SmallString<128> path;
+ if (llvm::sys::path::is_absolute(fileName) && isSysRooted) {
+ path.assign(_sysrootPath);
+ path.append(fileName);
+ if (llvm::sys::fs::exists(path.str()))
+ return StringRef(*new (_allocator) std::string(path.str()));
+ } else if (llvm::sys::fs::exists(fileName))
+ return fileName;
+
+ if (llvm::sys::path::is_absolute(fileName))
+ return make_error_code(llvm::errc::no_such_file_or_directory);
+
+ for (StringRef dir : _inputSearchPaths) {
+ buildSearchPath(path, dir, _sysrootPath);
+ llvm::sys::path::append(path, fileName);
+ if (llvm::sys::fs::exists(path.str()))
+ return StringRef(*new (_allocator) std::string(path.str()));
+ }
+ return make_error_code(llvm::errc::no_such_file_or_directory);
+}
+
+void ELFLinkingContext::createInternalFiles(
+ std::vector<std::unique_ptr<File>> &files) const {
+ std::unique_ptr<SimpleFile> file(
+ new SimpleFile("<internal file for --defsym>"));
+ for (auto &i : getAbsoluteSymbols()) {
+ StringRef sym = i.first;
+ uint64_t val = i.second;
+ file->addAtom(*(new (_allocator) SimpleAbsoluteAtom(
+ *file, sym, Atom::scopeGlobal, val)));
+ }
+ files.push_back(std::move(file));
+ LinkingContext::createInternalFiles(files);
+}
+
+void ELFLinkingContext::finalizeInputFiles() {
+ // Add virtual archive that resolves undefined symbols.
+ if (_resolver)
+ getNodes().push_back(llvm::make_unique<FileNode>(std::move(_resolver)));
+}
+
+std::unique_ptr<File> ELFLinkingContext::createUndefinedSymbolFile() const {
+ if (_initialUndefinedSymbols.empty())
+ return nullptr;
+ std::unique_ptr<SimpleFile> undefinedSymFile(
+ new SimpleFile("command line option -u"));
+ for (auto undefSymStr : _initialUndefinedSymbols)
+ undefinedSymFile->addAtom(*(new (_allocator) CommandLineUndefinedAtom(
+ *undefinedSymFile, undefSymStr)));
+ return std::move(undefinedSymFile);
+}
+
+void ELFLinkingContext::notifySymbolTableCoalesce(const Atom *existingAtom,
+ const Atom *newAtom,
+ bool &useNew) {
+ // First suppose that the `existingAtom` is defined
+ // and the `newAtom` is undefined.
+ auto *da = dyn_cast<DefinedAtom>(existingAtom);
+ auto *ua = dyn_cast<UndefinedAtom>(newAtom);
+ if (!da && !ua) {
+ // Then try to reverse the assumption.
+ da = dyn_cast<DefinedAtom>(newAtom);
+ ua = dyn_cast<UndefinedAtom>(existingAtom);
+ }
+
+ if (da && ua && da->scope() == Atom::scopeGlobal &&
+ isa<SharedLibraryFile>(ua->file()))
+ // If strong defined atom coalesces away an atom declared
+ // in the shared object the strong atom needs to be dynamically exported.
+ // Save its name.
+ _dynamicallyExportedSymbols.insert(ua->name());
+}
+
+std::string ELFLinkingContext::demangle(StringRef symbolName) const {
+ if (!demangleSymbols())
+ return symbolName;
+
+ // Only try to demangle symbols that look like C++ symbols
+ if (!symbolName.startswith("_Z"))
+ return symbolName;
+
+#if defined(HAVE_CXXABI_H)
+ SmallString<256> symBuff;
+ StringRef nullTermSym = Twine(symbolName).toNullTerminatedStringRef(symBuff);
+ const char *cstr = nullTermSym.data();
+ int status;
+ char *demangled = abi::__cxa_demangle(cstr, nullptr, nullptr, &status);
+ if (demangled != NULL) {
+ std::string result(demangled);
+ // __cxa_demangle() always uses a malloc'ed buffer to return the result.
+ free(demangled);
+ return result;
+ }
+#endif
+
+ return symbolName;
+}
+
+void ELFLinkingContext::setUndefinesResolver(std::unique_ptr<File> resolver) {
+ assert(isa<ArchiveLibraryFile>(resolver.get()) && "Wrong resolver type");
+ _resolver = std::move(resolver);
+}
+
+} // end namespace lld
diff --git a/lib/ReaderWriter/ELF/ELFReader.h b/lib/ReaderWriter/ELF/ELFReader.h
new file mode 100644
index 000000000000..43f218115c66
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ELFReader.h
@@ -0,0 +1,102 @@
+//===- lib/ReaderWriter/ELF/ELFReader.h -----------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_READER_H
+#define LLD_READER_WRITER_ELF_READER_H
+
+#include "CreateELF.h"
+#include "DynamicFile.h"
+#include "ELFFile.h"
+#include "lld/Core/Reader.h"
+
+namespace lld {
+namespace elf {
+
+template <typename ELFT, typename ELFTraitsT, typename ContextT>
+class ELFObjectReader : public Reader {
+public:
+ typedef llvm::object::Elf_Ehdr_Impl<ELFT> Elf_Ehdr;
+
+ ELFObjectReader(ContextT &ctx, uint64_t machine)
+ : _ctx(ctx), _machine(machine) {}
+
+ bool canParse(file_magic magic, StringRef,
+ const MemoryBuffer &buf) const override {
+ return (magic == llvm::sys::fs::file_magic::elf_relocatable &&
+ elfHeader(buf)->e_machine == _machine);
+ }
+
+ std::error_code
+ loadFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &,
+ std::vector<std::unique_ptr<File>> &result) const override {
+ std::size_t maxAlignment =
+ 1ULL << llvm::countTrailingZeros(uintptr_t(mb->getBufferStart()));
+ auto f =
+ createELF<ELFTraitsT>(llvm::object::getElfArchType(mb->getBuffer()),
+ maxAlignment, std::move(mb), _ctx);
+ if (std::error_code ec = f.getError())
+ return ec;
+ result.push_back(std::move(*f));
+ return std::error_code();
+ }
+
+ const Elf_Ehdr *elfHeader(const MemoryBuffer &buf) const {
+ const uint8_t *data =
+ reinterpret_cast<const uint8_t *>(buf.getBuffer().data());
+ return (reinterpret_cast<const Elf_Ehdr *>(data));
+ }
+
+protected:
+ ContextT &_ctx;
+ uint64_t _machine;
+};
+
+template <typename ELFT, typename ELFTraitsT, typename ContextT>
+class ELFDSOReader : public Reader {
+public:
+ typedef llvm::object::Elf_Ehdr_Impl<ELFT> Elf_Ehdr;
+
+ ELFDSOReader(ContextT &ctx, uint64_t machine)
+ : _ctx(ctx), _machine(machine) {}
+
+ bool canParse(file_magic magic, StringRef,
+ const MemoryBuffer &buf) const override {
+ return (magic == llvm::sys::fs::file_magic::elf_shared_object &&
+ elfHeader(buf)->e_machine == _machine);
+ }
+
+ std::error_code
+ loadFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &,
+ std::vector<std::unique_ptr<File>> &result) const override {
+ std::size_t maxAlignment =
+ 1ULL << llvm::countTrailingZeros(uintptr_t(mb->getBufferStart()));
+ auto f =
+ createELF<ELFTraitsT>(llvm::object::getElfArchType(mb->getBuffer()),
+ maxAlignment, std::move(mb), _ctx);
+ if (std::error_code ec = f.getError())
+ return ec;
+ result.push_back(std::move(*f));
+ return std::error_code();
+ }
+
+ const Elf_Ehdr *elfHeader(const MemoryBuffer &buf) const {
+ const uint8_t *data =
+ reinterpret_cast<const uint8_t *>(buf.getBuffer().data());
+ return (reinterpret_cast<const Elf_Ehdr *>(data));
+ }
+
+protected:
+ ContextT &_ctx;
+ uint64_t _machine;
+};
+
+} // namespace elf
+} // namespace lld
+
+#endif // LLD_READER_WRITER_ELF_READER_H
diff --git a/lib/ReaderWriter/ELF/ExecutableWriter.h b/lib/ReaderWriter/ELF/ExecutableWriter.h
new file mode 100644
index 000000000000..477e3920abae
--- /dev/null
+++ b/lib/ReaderWriter/ELF/ExecutableWriter.h
@@ -0,0 +1,182 @@
+//===- lib/ReaderWriter/ELF/ExecutableWriter.h ----------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLD_READER_WRITER_ELF_EXECUTABLE_WRITER_H
+#define LLD_READER_WRITER_ELF_EXECUTABLE_WRITER_H
+
+#include "OutputELFWriter.h"
+
+namespace lld {
+namespace elf {
+using namespace llvm;
+using namespace llvm::object;
+
+template<class ELFT>
+class ExecutableWriter;
+
+//===----------------------------------------------------------------------===//
+// ExecutableWriter Class
+//===----------------------------------------------------------------------===//
+template<class ELFT>
+class ExecutableWriter : public OutputELFWriter<ELFT> {
+public:
+ ExecutableWriter(ELFLinkingContext &context, TargetLayout<ELFT> &layout)
+ : OutputELFWriter<ELFT>(context, layout),
+ _runtimeFile(new RuntimeFile<ELFT>(context, "C runtime")) {}
+
+protected:
+ virtual void buildDynamicSymbolTable(const File &file);
+ virtual void addDefaultAtoms();
+ virtual bool createImplicitFiles(std::vector<std::unique_ptr<File> > &);
+ virtual void finalizeDefaultAtomValues();
+ virtual void createDefaultSections();
+
+ virtual bool isNeededTagRequired(const SharedLibraryAtom *sla) const {
+ return this->_layout.isCopied(sla);
+ }
+
+ unique_bump_ptr<InterpSection<ELFT>> _interpSection;
+ std::unique_ptr<RuntimeFile<ELFT> > _runtimeFile;
+};
+
+//===----------------------------------------------------------------------===//
+// ExecutableWriter
+//===----------------------------------------------------------------------===//
+template<class ELFT>
+void ExecutableWriter<ELFT>::buildDynamicSymbolTable(const File &file) {
+ for (auto sec : this->_layout.sections())
+ if (auto section = dyn_cast<AtomSection<ELFT>>(sec))
+ for (const auto &atom : section->atoms()) {
+ const DefinedAtom *da = dyn_cast<const DefinedAtom>(atom->_atom);
+ if (!da)
+ continue;
+ if (da->dynamicExport() != DefinedAtom::dynamicExportAlways &&
+ !this->_context.isDynamicallyExportedSymbol(da->name()) &&
+ !(this->_context.shouldExportDynamic() &&
+ da->scope() == Atom::Scope::scopeGlobal))
+ continue;
+ this->_dynamicSymbolTable->addSymbol(atom->_atom, section->ordinal(),
+ atom->_virtualAddr, atom);
+ }
+
+ // Put weak symbols in the dynamic symbol table.
+ if (this->_context.isDynamic()) {
+ for (const UndefinedAtom *a : file.undefined()) {
+ if (this->_layout.isReferencedByDefinedAtom(a) &&
+ a->canBeNull() != UndefinedAtom::canBeNullNever)
+ this->_dynamicSymbolTable->addSymbol(a, ELF::SHN_UNDEF);
+ }
+ }
+
+ OutputELFWriter<ELFT>::buildDynamicSymbolTable(file);
+}
+
+/// \brief Add absolute symbols by default. These are linker added
+/// absolute symbols
+template<class ELFT>
+void ExecutableWriter<ELFT>::addDefaultAtoms() {
+ OutputELFWriter<ELFT>::addDefaultAtoms();
+ _runtimeFile->addUndefinedAtom(this->_context.entrySymbolName());
+ _runtimeFile->addAbsoluteAtom("__bss_start");
+ _runtimeFile->addAbsoluteAtom("__bss_end");
+ _runtimeFile->addAbsoluteAtom("_end");
+ _runtimeFile->addAbsoluteAtom("end");
+ _runtimeFile->addAbsoluteAtom("__preinit_array_start");
+ _runtimeFile->addAbsoluteAtom("__preinit_array_end");
+ _runtimeFile->addAbsoluteAtom("__init_array_start");
+ _runtimeFile->addAbsoluteAtom("__init_array_end");
+ if (this->_context.isRelaOutputFormat()) {
+ _runtimeFile->addAbsoluteAtom("__rela_iplt_start");
+ _runtimeFile->addAbsoluteAtom("__rela_iplt_end");
+ } else {
+ _runtimeFile->addAbsoluteAtom("__rel_iplt_start");
+ _runtimeFile->addAbsoluteAtom("__rel_iplt_end");
+ }
+ _runtimeFile->addAbsoluteAtom("__fini_array_start");
+ _runtimeFile->addAbsoluteAtom("__fini_array_end");
+}
+
+/// \brief Hook in lld to add CRuntime file
+template <class ELFT>
+bool ExecutableWriter<ELFT>::createImplicitFiles(
+ std::vector<std::unique_ptr<File> > &result) {
+ // Add the default atoms as defined by executables
+ ExecutableWriter<ELFT>::addDefaultAtoms();
+ OutputELFWriter<ELFT>::createImplicitFiles(result);
+ result.push_back(std::move(_runtimeFile));
+ return true;
+}
+
+template <class ELFT> void ExecutableWriter<ELFT>::createDefaultSections() {
+ OutputELFWriter<ELFT>::createDefaultSections();
+ if (this->_context.isDynamic()) {
+ _interpSection.reset(new (this->_alloc) InterpSection<ELFT>(
+ this->_context, ".interp", DefaultLayout<ELFT>::ORDER_INTERP,
+ this->_context.getInterpreter()));
+ this->_layout.addSection(_interpSection.get());
+ }
+}
+
+/// Finalize the value of all the absolute symbols that we
+/// created
+template <class ELFT> void ExecutableWriter<ELFT>::finalizeDefaultAtomValues() {
+ OutputELFWriter<ELFT>::finalizeDefaultAtomValues();
+ auto bssStartAtomIter = this->_layout.findAbsoluteAtom("__bss_start");
+ auto bssEndAtomIter = this->_layout.findAbsoluteAtom("__bss_end");
+ auto underScoreEndAtomIter = this->_layout.findAbsoluteAtom("_end");
+ auto endAtomIter = this->_layout.findAbsoluteAtom("end");
+
+ auto startEnd = [&](StringRef sym, StringRef sec) -> void {
+ std::string start = ("__" + sym + "_start").str();
+ std::string end = ("__" + sym + "_end").str();
+ auto s = this->_layout.findAbsoluteAtom(start);
+ auto e = this->_layout.findAbsoluteAtom(end);
+ auto section = this->_layout.findOutputSection(sec);
+ if (section) {
+ (*s)->_virtualAddr = section->virtualAddr();
+ (*e)->_virtualAddr = section->virtualAddr() + section->memSize();
+ } else {
+ (*s)->_virtualAddr = 0;
+ (*e)->_virtualAddr = 0;
+ }
+ };
+
+ startEnd("preinit_array", ".preinit_array");
+ startEnd("init_array", ".init_array");
+ if (this->_context.isRelaOutputFormat())
+ startEnd("rela_iplt", ".rela.plt");
+ else
+ startEnd("rel_iplt", ".rel.plt");
+ startEnd("fini_array", ".fini_array");
+
+ assert(!(bssStartAtomIter == this->_layout.absoluteAtoms().end() ||
+ bssEndAtomIter == this->_layout.absoluteAtoms().end() ||
+ underScoreEndAtomIter == this->_layout.absoluteAtoms().end() ||
+ endAtomIter == this->_layout.absoluteAtoms().end()) &&
+ "Unable to find the absolute atoms that have been added by lld");
+
+ auto bssSection = this->_layout.findOutputSection(".bss");
+
+ // If we don't find a bss section, then don't set these values
+ if (bssSection) {
+ (*bssStartAtomIter)->_virtualAddr = bssSection->virtualAddr();
+ (*bssEndAtomIter)->_virtualAddr =
+ bssSection->virtualAddr() + bssSection->memSize();
+ (*underScoreEndAtomIter)->_virtualAddr = (*bssEndAtomIter)->_virtualAddr;
+ (*endAtomIter)->_virtualAddr = (*bssEndAtomIter)->_virtualAddr;
+ } else if (auto dataSection = this->_layout.findOutputSection(".data")) {
+ (*underScoreEndAtomIter)->_virtualAddr =
+ dataSection->virtualAddr() + dataSection->memSize();
+ (*endAtomIter)->_virtualAddr = (*underScoreEndAtomIter)->_virtualAddr;
+ }
+}
+
+} // namespace elf
+} // namespace lld
+
+#endif // LLD_READER_WRITER_ELF_EXECUTABLE_WRITER_H
diff --git a/lib/ReaderWriter/ELF/HeaderChunks.h b/lib/ReaderWriter/ELF/HeaderChunks.h
new file mode 100644
index 000000000000..eab132b9b2f6
--- /dev/null
+++ b/lib/ReaderWriter/ELF/HeaderChunks.h
@@ -0,0 +1,364 @@
+//===- lib/ReaderWriter/ELF/HeaderChunks.h --------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_HEADER_CHUNKS_H
+#define LLD_READER_WRITER_ELF_HEADER_CHUNKS_H
+
+#include "SegmentChunks.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ELF.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/Format.h"
+
+/// \brief An Header represents the Elf[32/64]_Ehdr structure at the
+/// start of an ELF executable file.
+namespace lld {
+namespace elf {
+template <class ELFT> class ELFHeader : public Chunk<ELFT> {
+public:
+ typedef llvm::object::Elf_Ehdr_Impl<ELFT> Elf_Ehdr;
+
+ ELFHeader(const ELFLinkingContext &);
+
+ void e_ident(int I, unsigned char C) { _eh.e_ident[I] = C; }
+ void e_type(uint16_t type) { _eh.e_type = type; }
+ void e_machine(uint16_t machine) { _eh.e_machine = machine; }
+ void e_version(uint32_t version) { _eh.e_version = version; }
+ void e_entry(int64_t entry) { _eh.e_entry = entry; }
+ void e_phoff(int64_t phoff) { _eh.e_phoff = phoff; }
+ void e_shoff(int64_t shoff) { _eh.e_shoff = shoff; }
+ void e_flags(uint32_t flags) { _eh.e_flags = flags; }
+ void e_ehsize(uint16_t ehsize) { _eh.e_ehsize = ehsize; }
+ void e_phentsize(uint16_t phentsize) { _eh.e_phentsize = phentsize; }
+ void e_phnum(uint16_t phnum) { _eh.e_phnum = phnum; }
+ void e_shentsize(uint16_t shentsize) { _eh.e_shentsize = shentsize; }
+ void e_shnum(uint16_t shnum) { _eh.e_shnum = shnum; }
+ void e_shstrndx(uint16_t shstrndx) { _eh.e_shstrndx = shstrndx; }
+ uint64_t fileSize() const { return sizeof(Elf_Ehdr); }
+
+ static bool classof(const Chunk<ELFT> *c) {
+ return c->Kind() == Chunk<ELFT>::Kind::ELFHeader;
+ }
+
+ int getContentType() const { return Chunk<ELFT>::ContentType::Header; }
+
+ void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
+ llvm::FileOutputBuffer &buffer);
+
+ virtual void doPreFlight() {}
+
+ void finalize() {
+ _eh.e_ident[llvm::ELF::EI_CLASS] =
+ (ELFT::Is64Bits) ? llvm::ELF::ELFCLASS64 : llvm::ELF::ELFCLASS32;
+ _eh.e_ident[llvm::ELF::EI_DATA] =
+ (ELFT::TargetEndianness == llvm::support::little)
+ ? llvm::ELF::ELFDATA2LSB
+ : llvm::ELF::ELFDATA2MSB;
+ _eh.e_type = this->_context.getOutputELFType();
+ _eh.e_machine = this->_context.getOutputMachine();
+ }
+
+private:
+ Elf_Ehdr _eh;
+};
+
+template <class ELFT>
+ELFHeader<ELFT>::ELFHeader(const ELFLinkingContext &context)
+ : Chunk<ELFT>("elfhdr", Chunk<ELFT>::Kind::ELFHeader, context) {
+ this->_alignment = ELFT::Is64Bits ? 8 : 4;
+ this->_fsize = sizeof(Elf_Ehdr);
+ this->_msize = sizeof(Elf_Ehdr);
+ memset(_eh.e_ident, 0, llvm::ELF::EI_NIDENT);
+ e_ident(llvm::ELF::EI_MAG0, 0x7f);
+ e_ident(llvm::ELF::EI_MAG1, 'E');
+ e_ident(llvm::ELF::EI_MAG2, 'L');
+ e_ident(llvm::ELF::EI_MAG3, 'F');
+ e_ehsize(sizeof(Elf_Ehdr));
+ e_flags(0);
+}
+
+template <class ELFT>
+void ELFHeader<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout,
+ llvm::FileOutputBuffer &buffer) {
+ uint8_t *chunkBuffer = buffer.getBufferStart();
+ uint8_t *atomContent = chunkBuffer + this->fileOffset();
+ memcpy(atomContent, &_eh, fileSize());
+}
+
+/// \brief An ProgramHeader represents the Elf[32/64]_Phdr structure at the
+/// start of an ELF executable file.
+template<class ELFT>
+class ProgramHeader : public Chunk<ELFT> {
+public:
+ typedef llvm::object::Elf_Phdr_Impl<ELFT> Elf_Phdr;
+ typedef typename std::vector<Elf_Phdr *>::iterator PhIterT;
+ typedef typename std::reverse_iterator<PhIterT> ReversePhIterT;
+
+ /// \brief Find a program header entry, given the type of entry that
+ /// we are looking for
+ class FindPhdr {
+ public:
+ FindPhdr(uint64_t type, uint64_t flags, uint64_t flagsClear)
+ : _type(type)
+ , _flags(flags)
+ , _flagsClear(flagsClear) {
+ }
+
+ bool operator()(const llvm::object::Elf_Phdr_Impl<ELFT> *j) const {
+ return ((j->p_type == _type) &&
+ ((j->p_flags & _flags) == _flags) &&
+ (!(j->p_flags & _flagsClear)));
+ }
+ private:
+ uint64_t _type;
+ uint64_t _flags;
+ uint64_t _flagsClear;
+ };
+
+ ProgramHeader(const ELFLinkingContext &context)
+ : Chunk<ELFT>("elfphdr", Chunk<ELFT>::Kind::ProgramHeader, context) {
+ this->_alignment = ELFT::Is64Bits ? 8 : 4;
+ resetProgramHeaders();
+ }
+
+ bool addSegment(Segment<ELFT> *segment);
+
+ void resetProgramHeaders() { _phi = _ph.begin(); }
+
+ uint64_t fileSize() const { return sizeof(Elf_Phdr) * _ph.size(); }
+
+ static bool classof(const Chunk<ELFT> *c) {
+ return c->Kind() == Chunk<ELFT>::Kind::ProgramHeader;
+ }
+
+ void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
+ llvm::FileOutputBuffer &buffer);
+
+ /// \brief find a program header entry in the list of program headers
+ ReversePhIterT
+ findProgramHeader(uint64_t type, uint64_t flags, uint64_t flagClear) {
+ return std::find_if(_ph.rbegin(), _ph.rend(),
+ FindPhdr(type, flags, flagClear));
+ }
+
+ PhIterT begin() {
+ return _ph.begin();
+ }
+
+ PhIterT end() {
+ return _ph.end();
+ }
+
+ ReversePhIterT rbegin() { return _ph.rbegin(); }
+
+ ReversePhIterT rend() { return _ph.rend(); }
+
+ virtual void doPreFlight() {}
+
+ void finalize() {}
+
+ int64_t entsize() { return sizeof(Elf_Phdr); }
+
+ int64_t numHeaders() {
+ return _ph.size();
+ }
+
+ int getContentType() const { return Chunk<ELFT>::ContentType::Header; }
+
+private:
+ Elf_Phdr *allocateProgramHeader(bool &allocatedNew) {
+ Elf_Phdr *phdr;
+ if (_phi == _ph.end()) {
+ phdr = new (_allocator) Elf_Phdr;
+ _ph.push_back(phdr);
+ _phi = _ph.end();
+ allocatedNew = true;
+ } else {
+ phdr = (*_phi);
+ ++_phi;
+ }
+ return phdr;
+ }
+
+ std::vector<Elf_Phdr *> _ph;
+ PhIterT _phi;
+ llvm::BumpPtrAllocator _allocator;
+};
+
+template <class ELFT>
+bool ProgramHeader<ELFT>::addSegment(Segment<ELFT> *segment) {
+ bool allocatedNew = false;
+ ELFLinkingContext::OutputMagic outputMagic = this->_context.getOutputMagic();
+ // For segments that are not a loadable segment, we
+ // just pick the values directly from the segment as there
+ // wouldnt be any slices within that
+ if (segment->segmentType() != llvm::ELF::PT_LOAD) {
+ Elf_Phdr *phdr = allocateProgramHeader(allocatedNew);
+ phdr->p_type = segment->segmentType();
+ phdr->p_offset = segment->fileOffset();
+ phdr->p_vaddr = segment->virtualAddr();
+ phdr->p_paddr = segment->virtualAddr();
+ phdr->p_filesz = segment->fileSize();
+ phdr->p_memsz = segment->memSize();
+ phdr->p_flags = segment->flags();
+ phdr->p_align = segment->alignment();
+ this->_fsize = fileSize();
+ this->_msize = this->_fsize;
+ return allocatedNew;
+ }
+ // For all other segments, use the slice
+ // to derive program headers
+ for (auto slice : segment->slices()) {
+ Elf_Phdr *phdr = allocateProgramHeader(allocatedNew);
+ phdr->p_type = segment->segmentType();
+ phdr->p_offset = slice->fileOffset();
+ phdr->p_vaddr = slice->virtualAddr();
+ phdr->p_paddr = slice->virtualAddr();
+ phdr->p_filesz = slice->fileSize();
+ phdr->p_memsz = slice->memSize();
+ phdr->p_flags = segment->flags();
+ phdr->p_align = slice->alignment();
+ uint64_t segPageSize = segment->pageSize();
+ uint64_t sliceAlign = slice->alignment();
+ // Alignment of PT_LOAD segments are set to the page size, but if the
+ // alignment of the slice is greater than the page size, set the alignment
+ // of the segment appropriately.
+ if (outputMagic != ELFLinkingContext::OutputMagic::NMAGIC &&
+ outputMagic != ELFLinkingContext::OutputMagic::OMAGIC) {
+ phdr->p_align = (phdr->p_type == llvm::ELF::PT_LOAD)
+ ? (segPageSize < sliceAlign) ? sliceAlign : segPageSize
+ : sliceAlign;
+ } else
+ phdr->p_align = slice->alignment();
+ }
+ this->_fsize = fileSize();
+ this->_msize = this->_fsize;
+
+ return allocatedNew;
+}
+
+template <class ELFT>
+void ProgramHeader<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout,
+ llvm::FileOutputBuffer &buffer) {
+ uint8_t *chunkBuffer = buffer.getBufferStart();
+ uint8_t *dest = chunkBuffer + this->fileOffset();
+ for (auto phi : _ph) {
+ memcpy(dest, phi, sizeof(Elf_Phdr));
+ dest += sizeof(Elf_Phdr);
+ }
+}
+
+/// \brief An SectionHeader represents the Elf[32/64]_Shdr structure
+/// at the end of the file
+template<class ELFT>
+class SectionHeader : public Chunk<ELFT> {
+public:
+ typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr;
+
+ SectionHeader(const ELFLinkingContext &, int32_t order);
+
+ void appendSection(OutputSection<ELFT> *section);
+
+ void updateSection(Section<ELFT> *section);
+
+ static bool classof(const Chunk<ELFT> *c) {
+ return c->getChunkKind() == Chunk<ELFT>::Kind::SectionHeader;
+ }
+
+ void setStringSection(StringTable<ELFT> *s) {
+ _stringSection = s;
+ }
+
+ void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
+ llvm::FileOutputBuffer &buffer);
+
+ virtual void doPreFlight() {}
+
+ void finalize() {}
+
+ uint64_t fileSize() const { return sizeof(Elf_Shdr) * _sectionInfo.size(); }
+
+ uint64_t entsize() { return sizeof(Elf_Shdr); }
+
+ int getContentType() const { return Chunk<ELFT>::ContentType::Header; }
+
+ uint64_t numHeaders() { return _sectionInfo.size(); }
+
+private:
+ StringTable<ELFT> *_stringSection;
+ std::vector<Elf_Shdr*> _sectionInfo;
+ llvm::BumpPtrAllocator _sectionAllocate;
+};
+
+template <class ELFT>
+SectionHeader<ELFT>::SectionHeader(const ELFLinkingContext &context,
+ int32_t order)
+ : Chunk<ELFT>("shdr", Chunk<ELFT>::Kind::SectionHeader, context) {
+ this->_fsize = 0;
+ this->_alignment = 8;
+ this->setOrder(order);
+ // The first element in the list is always NULL
+ Elf_Shdr *nullshdr = new (_sectionAllocate.Allocate<Elf_Shdr>()) Elf_Shdr;
+ ::memset(nullshdr, 0, sizeof (Elf_Shdr));
+ _sectionInfo.push_back(nullshdr);
+ this->_fsize += sizeof (Elf_Shdr);
+}
+
+template <class ELFT>
+void SectionHeader<ELFT>::appendSection(OutputSection<ELFT> *section) {
+ Elf_Shdr *shdr = new (_sectionAllocate.Allocate<Elf_Shdr>()) Elf_Shdr;
+ shdr->sh_name = _stringSection->addString(section->name());
+ shdr->sh_type = section->type();
+ shdr->sh_flags = section->flags();
+ shdr->sh_offset = section->fileOffset();
+ shdr->sh_addr = section->virtualAddr();
+ if (section->isLoadableSection())
+ shdr->sh_size = section->memSize();
+ else
+ shdr->sh_size = section->fileSize();
+ shdr->sh_link = section->link();
+ shdr->sh_info = section->shinfo();
+ shdr->sh_addralign = section->alignment();
+ shdr->sh_entsize = section->entsize();
+ _sectionInfo.push_back(shdr);
+}
+
+template<class ELFT>
+void
+SectionHeader<ELFT>::updateSection(Section<ELFT> *section) {
+ Elf_Shdr *shdr = _sectionInfo[section->ordinal()];
+ shdr->sh_type = section->getType();
+ shdr->sh_flags = section->getFlags();
+ shdr->sh_offset = section->fileOffset();
+ shdr->sh_addr = section->virtualAddr();
+ shdr->sh_size = section->fileSize();
+ shdr->sh_link = section->getLink();
+ shdr->sh_info = section->getInfo();
+ shdr->sh_addralign = section->alignment();
+ shdr->sh_entsize = section->getEntSize();
+}
+
+template <class ELFT>
+void SectionHeader<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout,
+ llvm::FileOutputBuffer &buffer) {
+ uint8_t *chunkBuffer = buffer.getBufferStart();
+ uint8_t *dest = chunkBuffer + this->fileOffset();
+ for (auto shi : _sectionInfo) {
+ memcpy(dest, shi, sizeof(Elf_Shdr));
+ dest += sizeof(Elf_Shdr);
+ }
+ _stringSection->write(writer, layout, buffer);
+}
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/Hexagon/CMakeLists.txt b/lib/ReaderWriter/ELF/Hexagon/CMakeLists.txt
new file mode 100644
index 000000000000..6928f43c5459
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Hexagon/CMakeLists.txt
@@ -0,0 +1,11 @@
+add_llvm_library(lldHexagonELFTarget
+ HexagonLinkingContext.cpp
+ HexagonRelocationHandler.cpp
+ HexagonTargetHandler.cpp
+ LINK_LIBS
+ lldELF
+ lldReaderWriter
+ lldCore
+ LLVMObject
+ LLVMSupport
+ )
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonDynamicLibraryWriter.h b/lib/ReaderWriter/ELF/Hexagon/HexagonDynamicLibraryWriter.h
new file mode 100644
index 000000000000..e2d3193045b7
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Hexagon/HexagonDynamicLibraryWriter.h
@@ -0,0 +1,79 @@
+//===- lib/ReaderWriter/ELF/Hexagon/HexagonDynamicLibraryWriter.h ---------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef HEXAGON_DYNAMIC_LIBRARY_WRITER_H
+#define HEXAGON_DYNAMIC_LIBRARY_WRITER_H
+
+#include "DynamicLibraryWriter.h"
+#include "HexagonExecutableAtoms.h"
+#include "HexagonLinkingContext.h"
+
+namespace lld {
+namespace elf {
+
+template <typename ELFT> class HexagonTargetLayout;
+
+template <class ELFT>
+class HexagonDynamicLibraryWriter : public DynamicLibraryWriter<ELFT>,
+ public HexagonELFWriter<ELFT> {
+public:
+ HexagonDynamicLibraryWriter(HexagonLinkingContext &context,
+ HexagonTargetLayout<ELFT> &layout);
+
+protected:
+ // Add any runtime files and their atoms to the output
+ virtual bool createImplicitFiles(std::vector<std::unique_ptr<File>> &);
+
+ virtual void finalizeDefaultAtomValues();
+
+ virtual std::error_code setELFHeader() {
+ DynamicLibraryWriter<ELFT>::setELFHeader();
+ HexagonELFWriter<ELFT>::setELFHeader(*this->_elfHeader);
+ return std::error_code();
+ }
+
+private:
+ void addDefaultAtoms() {
+ _hexagonRuntimeFile->addAbsoluteAtom("_GLOBAL_OFFSET_TABLE_");
+ _hexagonRuntimeFile->addAbsoluteAtom("_DYNAMIC");
+ }
+
+ HexagonLinkingContext &_hexagonLinkingContext;
+ HexagonTargetLayout<ELFT> &_hexagonTargetLayout;
+ std::unique_ptr<HexagonRuntimeFile<ELFT>> _hexagonRuntimeFile;
+};
+
+template <class ELFT>
+HexagonDynamicLibraryWriter<ELFT>::HexagonDynamicLibraryWriter(
+ HexagonLinkingContext &context, HexagonTargetLayout<ELFT> &layout)
+ : DynamicLibraryWriter<ELFT>(context, layout),
+ HexagonELFWriter<ELFT>(context, layout), _hexagonLinkingContext(context),
+ _hexagonTargetLayout(layout),
+ _hexagonRuntimeFile(new HexagonRuntimeFile<ELFT>(context)) {}
+
+template <class ELFT>
+bool HexagonDynamicLibraryWriter<ELFT>::createImplicitFiles(
+ std::vector<std::unique_ptr<File>> &result) {
+ DynamicLibraryWriter<ELFT>::createImplicitFiles(result);
+ // Add the default atoms as defined for hexagon
+ addDefaultAtoms();
+ result.push_back(std::move(_hexagonRuntimeFile));
+ return true;
+}
+
+template <class ELFT>
+void HexagonDynamicLibraryWriter<ELFT>::finalizeDefaultAtomValues() {
+ // Finalize the atom values that are part of the parent.
+ DynamicLibraryWriter<ELFT>::finalizeDefaultAtomValues();
+ HexagonELFWriter<ELFT>::finalizeHexagonRuntimeAtomValues();
+}
+
+} // namespace elf
+} // namespace lld
+
+#endif // HEXAGON_DYNAMIC_LIBRARY_WRITER_H
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonELFFile.h b/lib/ReaderWriter/ELF/Hexagon/HexagonELFFile.h
new file mode 100644
index 000000000000..ab0b9b432b43
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Hexagon/HexagonELFFile.h
@@ -0,0 +1,170 @@
+//===- lib/ReaderWriter/ELF/HexagonELFFile.h ------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_HEXAGON_ELF_FILE_H
+#define LLD_READER_WRITER_ELF_HEXAGON_ELF_FILE_H
+
+#include "ELFReader.h"
+#include "HexagonLinkingContext.h"
+
+namespace lld {
+namespace elf {
+
+template <class ELFT> class HexagonELFFile;
+
+template <class ELFT>
+class HexagonELFDefinedAtom : public ELFDefinedAtom<ELFT> {
+ typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+ typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr;
+
+public:
+ HexagonELFDefinedAtom(const HexagonELFFile<ELFT> &file, StringRef symbolName,
+ StringRef sectionName, const Elf_Sym *symbol,
+ const Elf_Shdr *section, ArrayRef<uint8_t> contentData,
+ unsigned int referenceStart, unsigned int referenceEnd,
+ std::vector<ELFReference<ELFT> *> &referenceList)
+ : ELFDefinedAtom<ELFT>(file, symbolName, sectionName, symbol, section,
+ contentData, referenceStart, referenceEnd,
+ referenceList) {}
+
+ virtual DefinedAtom::ContentType contentType() const {
+ if (this->_contentType != DefinedAtom::typeUnknown)
+ return this->_contentType;
+ else if (this->_section->sh_flags & llvm::ELF::SHF_HEX_GPREL) {
+ if (this->_section->sh_type == llvm::ELF::SHT_NOBITS)
+ return (this->_contentType = DefinedAtom::typeZeroFillFast);
+ else
+ return (this->_contentType = DefinedAtom::typeDataFast);
+ }
+ return ELFDefinedAtom<ELFT>::contentType();
+ }
+
+ virtual DefinedAtom::ContentPermissions permissions() const {
+ if (this->_section->sh_flags & llvm::ELF::SHF_HEX_GPREL)
+ return DefinedAtom::permRW_;
+ return ELFDefinedAtom<ELFT>::permissions();
+ }
+};
+
+template <class ELFT> class HexagonELFCommonAtom : public ELFCommonAtom<ELFT> {
+ typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+ typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr;
+
+public:
+ HexagonELFCommonAtom(const HexagonELFFile<ELFT> &file, StringRef symbolName,
+ const Elf_Sym *symbol)
+ : ELFCommonAtom<ELFT>(file, symbolName, symbol) {}
+
+ virtual bool isSmallCommonSymbol() const {
+ switch (this->_symbol->st_shndx) {
+ // Common symbols
+ case llvm::ELF::SHN_HEXAGON_SCOMMON:
+ case llvm::ELF::SHN_HEXAGON_SCOMMON_1:
+ case llvm::ELF::SHN_HEXAGON_SCOMMON_2:
+ case llvm::ELF::SHN_HEXAGON_SCOMMON_4:
+ case llvm::ELF::SHN_HEXAGON_SCOMMON_8:
+ return true;
+ default:
+ break;
+ }
+ return false;
+ }
+
+ virtual uint64_t size() const {
+ if (isSmallCommonSymbol())
+ return this->_symbol->st_size;
+ return ELFCommonAtom<ELFT>::size();
+ }
+
+ virtual DefinedAtom::Merge merge() const {
+ if (this->_symbol->getBinding() == llvm::ELF::STB_WEAK)
+ return DefinedAtom::mergeAsWeak;
+ if (isSmallCommonSymbol())
+ return DefinedAtom::mergeAsTentative;
+ return ELFCommonAtom<ELFT>::merge();
+ }
+
+ virtual DefinedAtom::ContentType contentType() const {
+ if (isSmallCommonSymbol())
+ return DefinedAtom::typeZeroFillFast;
+ return ELFCommonAtom<ELFT>::contentType();
+ }
+
+ virtual DefinedAtom::Alignment alignment() const {
+ if (isSmallCommonSymbol())
+ return DefinedAtom::Alignment(llvm::Log2_64(this->_symbol->st_value));
+ return ELFCommonAtom<ELFT>::alignment();
+ }
+
+ virtual DefinedAtom::ContentPermissions permissions() const {
+ if (isSmallCommonSymbol())
+ return DefinedAtom::permRW_;
+ return ELFCommonAtom<ELFT>::permissions();
+ }
+};
+
+template <class ELFT> class HexagonELFFile : public ELFFile<ELFT> {
+ typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+ typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr;
+
+public:
+ HexagonELFFile(std::unique_ptr<MemoryBuffer> mb, HexagonLinkingContext &ctx)
+ : ELFFile<ELFT>(std::move(mb), ctx) {}
+
+ static ErrorOr<std::unique_ptr<HexagonELFFile>>
+ create(std::unique_ptr<MemoryBuffer> mb, HexagonLinkingContext &ctx) {
+ return std::unique_ptr<HexagonELFFile<ELFT>>(
+ new HexagonELFFile<ELFT>(std::move(mb), ctx));
+ }
+
+ bool isCommonSymbol(const Elf_Sym *symbol) const override {
+ switch (symbol->st_shndx) {
+ // Common symbols
+ case llvm::ELF::SHN_HEXAGON_SCOMMON:
+ case llvm::ELF::SHN_HEXAGON_SCOMMON_1:
+ case llvm::ELF::SHN_HEXAGON_SCOMMON_2:
+ case llvm::ELF::SHN_HEXAGON_SCOMMON_4:
+ case llvm::ELF::SHN_HEXAGON_SCOMMON_8:
+ return true;
+ default:
+ break;
+ }
+ return ELFFile<ELFT>::isCommonSymbol(symbol);
+ }
+
+ /// Process the Defined symbol and create an atom for it.
+ ErrorOr<ELFDefinedAtom<ELFT> *>
+ handleDefinedSymbol(StringRef symName, StringRef sectionName,
+ const Elf_Sym *sym, const Elf_Shdr *sectionHdr,
+ ArrayRef<uint8_t> contentData,
+ unsigned int referenceStart, unsigned int referenceEnd,
+ std::vector<ELFReference<ELFT> *> &referenceList) override {
+ return new (this->_readerStorage) HexagonELFDefinedAtom<ELFT>(
+ *this, symName, sectionName, sym, sectionHdr, contentData,
+ referenceStart, referenceEnd, referenceList);
+ }
+
+ /// Process the Common symbol and create an atom for it.
+ ErrorOr<ELFCommonAtom<ELFT> *>
+ handleCommonSymbol(StringRef symName, const Elf_Sym *sym) override {
+ return new (this->_readerStorage)
+ HexagonELFCommonAtom<ELFT>(*this, symName, sym);
+ }
+};
+
+template <class ELFT> class HexagonDynamicFile : public DynamicFile<ELFT> {
+public:
+ HexagonDynamicFile(const HexagonLinkingContext &context, StringRef name)
+ : DynamicFile<ELFT>(context, name) {}
+};
+
+} // elf
+} // lld
+
+#endif // LLD_READER_WRITER_ELF_HEXAGON_ELF_FILE_H
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonELFReader.h b/lib/ReaderWriter/ELF/Hexagon/HexagonELFReader.h
new file mode 100644
index 000000000000..1a4f891df799
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Hexagon/HexagonELFReader.h
@@ -0,0 +1,62 @@
+//===- lib/ReaderWriter/ELF/HexagonELFReader.h ----------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_HEXAGON_ELF_READER_H
+#define LLD_READER_WRITER_HEXAGON_ELF_READER_H
+
+#include "ELFReader.h"
+#include "HexagonELFFile.h"
+
+namespace lld {
+namespace elf {
+
+typedef llvm::object::ELFType<llvm::support::little, 2, false> HexagonELFType;
+
+struct HexagonDynamicFileCreateELFTraits {
+ typedef llvm::ErrorOr<std::unique_ptr<lld::SharedLibraryFile>> result_type;
+
+ template <class ELFT>
+ static result_type create(std::unique_ptr<llvm::MemoryBuffer> mb,
+ HexagonLinkingContext &ctx) {
+ return lld::elf::HexagonDynamicFile<ELFT>::create(std::move(mb), ctx);
+ }
+};
+
+struct HexagonELFFileCreateELFTraits {
+ typedef llvm::ErrorOr<std::unique_ptr<lld::File>> result_type;
+
+ template <class ELFT>
+ static result_type create(std::unique_ptr<llvm::MemoryBuffer> mb,
+ HexagonLinkingContext &ctx) {
+ return lld::elf::HexagonELFFile<ELFT>::create(std::move(mb), ctx);
+ }
+};
+
+class HexagonELFObjectReader
+ : public ELFObjectReader<HexagonELFType, HexagonELFFileCreateELFTraits,
+ HexagonLinkingContext> {
+public:
+ HexagonELFObjectReader(HexagonLinkingContext &ctx)
+ : ELFObjectReader<HexagonELFType, HexagonELFFileCreateELFTraits,
+ HexagonLinkingContext>(ctx, llvm::ELF::EM_HEXAGON) {}
+};
+
+class HexagonELFDSOReader
+ : public ELFDSOReader<HexagonELFType, HexagonDynamicFileCreateELFTraits,
+ HexagonLinkingContext> {
+public:
+ HexagonELFDSOReader(HexagonLinkingContext &ctx)
+ : ELFDSOReader<HexagonELFType, HexagonDynamicFileCreateELFTraits,
+ HexagonLinkingContext>(ctx, llvm::ELF::EM_HEXAGON) {}
+};
+
+} // namespace elf
+} // namespace lld
+
+#endif // LLD_READER_WRITER_ELF_READER_H
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonELFWriters.h b/lib/ReaderWriter/ELF/Hexagon/HexagonELFWriters.h
new file mode 100644
index 000000000000..96c74f72222d
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Hexagon/HexagonELFWriters.h
@@ -0,0 +1,61 @@
+//===- lib/ReaderWriter/ELF/Hexagon/HexagonELFWriters.h -------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef HEXAGON_ELF_WRITERS_H
+#define HEXAGON_ELF_WRITERS_H
+
+#include "HexagonLinkingContext.h"
+#include "OutputELFWriter.h"
+
+namespace lld {
+namespace elf {
+
+template <class ELFT> class HexagonTargetLayout;
+
+template <typename ELFT> class HexagonELFWriter {
+public:
+ HexagonELFWriter(HexagonLinkingContext &context,
+ HexagonTargetLayout<ELFT> &targetLayout)
+ : _hexagonLinkingContext(context), _hexagonTargetLayout(targetLayout) {}
+
+protected:
+ bool setELFHeader(ELFHeader<ELFT> &elfHeader) {
+ elfHeader.e_ident(llvm::ELF::EI_VERSION, 1);
+ elfHeader.e_ident(llvm::ELF::EI_OSABI, 0);
+ elfHeader.e_version(1);
+ elfHeader.e_flags(0x3);
+ return true;
+ }
+
+ void finalizeHexagonRuntimeAtomValues() {
+ if (_hexagonLinkingContext.isDynamic()) {
+ auto gotAtomIter =
+ _hexagonTargetLayout.findAbsoluteAtom("_GLOBAL_OFFSET_TABLE_");
+ auto gotpltSection = _hexagonTargetLayout.findOutputSection(".got.plt");
+ if (gotpltSection)
+ (*gotAtomIter)->_virtualAddr = gotpltSection->virtualAddr();
+ else
+ (*gotAtomIter)->_virtualAddr = 0;
+ auto dynamicAtomIter = _hexagonTargetLayout.findAbsoluteAtom("_DYNAMIC");
+ auto dynamicSection = _hexagonTargetLayout.findOutputSection(".dynamic");
+ if (dynamicSection)
+ (*dynamicAtomIter)->_virtualAddr = dynamicSection->virtualAddr();
+ else
+ (*dynamicAtomIter)->_virtualAddr = 0;
+ }
+ }
+
+private:
+ HexagonLinkingContext &_hexagonLinkingContext;
+ HexagonTargetLayout<ELFT> &_hexagonTargetLayout;
+};
+
+} // elf
+} // lld
+#endif // HEXAGON_ELF_WRITERS_H
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonEncodings.h b/lib/ReaderWriter/ELF/Hexagon/HexagonEncodings.h
new file mode 100644
index 000000000000..3e12786704a2
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Hexagon/HexagonEncodings.h
@@ -0,0 +1,601 @@
+//===- lib/ReaderWriter/ELF/Hexagon/HexagonEncodings.h -------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+Instruction insn_encodings[] = {
+ { 0xffe00004, 0x40000000, 0x20f8, 0x0 },
+ { 0xffe03080, 0x9ca03080, 0xf60, 0x0 },
+ { 0xf9e00000, 0x48c00000, 0x61f20ff, 0x0 },
+ { 0xf7c02300, 0x13802100, 0x3000fe, 0x0 },
+ { 0xffe00000, 0x60c00000, 0x1f18, 0x0 },
+ { 0xffe00000, 0x69c00000, 0x1f18, 0x0 },
+ { 0xffe02000, 0x43000000, 0x7e0, 0x0 },
+ { 0xff602060, 0x3e000060, 0x1f80, 0x0 },
+ { 0xffe03000, 0x9ae01000, 0xf60, 0x0 },
+ { 0xf9e00000, 0x91600000, 0x6003fe0, 0x0 },
+ { 0xffe02084, 0xaf000084, 0x30078, 0x0 },
+ { 0xff602060, 0x3e000020, 0x1f80, 0x0 },
+ { 0xff602060, 0x3e200040, 0x1f80, 0x0 },
+ { 0xf7c02000, 0x10c02000, 0x3000fe, 0x0 },
+ { 0xffe00000, 0x60200000, 0x1f18, 0x0 },
+ { 0xffe00000, 0x69200000, 0x1f18, 0x0 },
+ { 0xffe038c0, 0xada00880, 0x3f, 0x0 },
+ { 0xff602000, 0x73002000, 0x1fe0, 0x0 },
+ { 0xf7c02000, 0x26c02000, 0x3000fe, 0x0 },
+ { 0xffe03880, 0x9f403880, 0x1f0100, 0x0 },
+ { 0xf9e00000, 0x48400000, 0x61f20ff, 0x0 },
+ { 0xffe02000, 0x41600000, 0x7e0, 0x0 },
+ { 0xffe02084, 0xaf000080, 0x30078, 0x0 },
+ { 0xf7c02300, 0x13800100, 0x3000fe, 0x0 },
+ { 0xffe01804, 0x46a00000, 0x20f8, 0x0 },
+ { 0xffe00004, 0x42400000, 0x20f8, 0x0 },
+ { 0xf7c02000, 0x22400000, 0x3000fe, 0x0 },
+ { 0xf7c02000, 0x12402000, 0x3000fe, 0x0 },
+ { 0xfc003d18, 0x28003c18, 0x3f00000, 0x1 },
+ { 0xffe00000, 0x39000000, 0x201f, 0x0 },
+ { 0xff601018, 0xdd400008, 0xfe0, 0x0 },
+ { 0xffc0001c, 0x75400000, 0x203fe0, 0x0 },
+ { 0xfc003fc7, 0x48003f47, 0x3f00000, 0x1 },
+ { 0xffe03080, 0x9ca03000, 0xf60, 0x0 },
+ { 0xf9e00000, 0x90800000, 0x6003fe0, 0x0 },
+ { 0xf8003fc7, 0x40003fc4, 0x7f00000, 0x1 },
+ { 0xfc003e00, 0x68003c00, 0x3f00000, 0x1 },
+ { 0xf8003fc7, 0x40003fc5, 0x7f00000, 0x1 },
+ { 0xf9e00000, 0x91800000, 0x6003fe0, 0x0 },
+ { 0xff602060, 0x3e400060, 0x1f80, 0x0 },
+ { 0xff602060, 0x3e000000, 0x1f80, 0x0 },
+ { 0xf8003d18, 0x20003c18, 0x7f00000, 0x1 },
+ { 0xf8003f00, 0x20003800, 0x7f00000, 0x1 },
+ { 0xf8003d18, 0x20003c10, 0x7f00000, 0x1 },
+ { 0xff602000, 0x73602000, 0x1fe0, 0x0 },
+ { 0xffe03880, 0x9f002080, 0x1f0100, 0x0 },
+ { 0xffe02000, 0x47000000, 0x7e0, 0x0 },
+ { 0xf9e00000, 0x91400000, 0x6003fe0, 0x0 },
+ { 0xffe02080, 0xabc00080, 0x3f, 0x0 },
+ { 0xf7c02000, 0x20802000, 0x3000fe, 0x0 },
+ { 0xf8003fc7, 0x40003f44, 0x7f00000, 0x1 },
+ { 0xffe03884, 0xafa03084, 0x30078, 0x0 },
+ { 0xffe03000, 0x9b001000, 0xf60, 0x0 },
+ { 0xffe01804, 0x42a00800, 0x20f8, 0x0 },
+ { 0xfc003f00, 0x28003100, 0x3f00000, 0x1 },
+ { 0xffe02080, 0xab800080, 0x3f, 0x0 },
+ { 0xf7c02000, 0x24c00000, 0x3000fe, 0x0 },
+ { 0xffe00000, 0x39a00000, 0x201f, 0x0 },
+ { 0xf7c02300, 0x13802300, 0x3000fe, 0x0 },
+ { 0xffe01804, 0x46a00800, 0x20f8, 0x0 },
+ { 0xffe020c0, 0xad602080, 0x3f, 0x0 },
+ { 0xfc003f00, 0x28003500, 0x3f00000, 0x1 },
+ { 0xfc003f00, 0x28003400, 0x3f00000, 0x1 },
+ { 0xffe020c0, 0xad6000c0, 0x3f, 0x0 },
+ { 0xffe00000, 0x60000000, 0x1f18, 0x0 },
+ { 0xf8003000, 0x40000000, 0x7f00000, 0x1 },
+ { 0xffe00000, 0x69000000, 0x1f18, 0x0 },
+ { 0xffe03080, 0x9c601080, 0xf60, 0x0 },
+ { 0xffe03080, 0x9ce01000, 0xf60, 0x0 },
+ { 0xffe03080, 0x9c601000, 0xf60, 0x0 },
+ { 0xf7c02000, 0x13402000, 0x3000fe, 0x0 },
+ { 0xffe03080, 0x9c603000, 0xf60, 0x0 },
+ { 0xf7c02000, 0x21c00000, 0x3000fe, 0x0 },
+ { 0xfc003000, 0x68000000, 0x3f00000, 0x1 },
+ { 0xf8003800, 0x60002000, 0x7f00000, 0x1 },
+ { 0xffe02084, 0xaf802084, 0x30078, 0x0 },
+ { 0xfc003000, 0x48000000, 0x3f00000, 0x1 },
+ { 0xf7c02300, 0x11c02100, 0x3000fe, 0x0 },
+ { 0xf7c02000, 0x12800000, 0x3000fe, 0x0 },
+ { 0xfc003e70, 0x28003a40, 0x3f00000, 0x1 },
+ { 0xfc003f00, 0x28003300, 0x3f00000, 0x1 },
+ { 0xff800000, 0xe0000000, 0x1fe0, 0x0 },
+ { 0xff602060, 0x3f400000, 0x1f80, 0x0 },
+ { 0xffe00004, 0x42000000, 0x20f8, 0x0 },
+ { 0xf8003f00, 0x60003300, 0x7f00000, 0x1 },
+ { 0xffe01804, 0x42a00000, 0x20f8, 0x0 },
+ { 0xf7c02000, 0x12c00000, 0x3000fe, 0x0 },
+ { 0xf0000000, 0x0, 0xfff3fff, 0x0 },
+ { 0xff000016, 0xde000016, 0xe020e8, 0x0 },
+ { 0xffe03000, 0x9b201000, 0xf60, 0x0 },
+ { 0xffe03880, 0xaba00880, 0x3f, 0x0 },
+ { 0xf8003e00, 0x40003c00, 0x7f00000, 0x1 },
+ { 0xff602060, 0x3f200040, 0x1f80, 0x0 },
+ { 0xffe03880, 0x9f203880, 0x1f0100, 0x0 },
+ { 0xf7c02000, 0x20c00000, 0x3000fe, 0x0 },
+ { 0xf9e01800, 0x48a00800, 0x61f20ff, 0x0 },
+ { 0xf9e00000, 0x90a00000, 0x6003fe0, 0x0 },
+ { 0xff802000, 0x74802000, 0x1fe0, 0x0 },
+ { 0xffe03000, 0x9a401000, 0xf60, 0x0 },
+ { 0xf7c02000, 0x10002000, 0x3000fe, 0x0 },
+ { 0xf7c03000, 0x14803000, 0x3000fe, 0x0 },
+ { 0xffe020c0, 0xad0020c0, 0x3f, 0x0 },
+ { 0xffe0001c, 0x75800000, 0x3fe0, 0x0 },
+ { 0xf9e01800, 0x48a01000, 0x61f20ff, 0x0 },
+ { 0xffe03080, 0x9dc03000, 0xf60, 0x0 },
+ { 0xffe03080, 0x9dc03080, 0xf60, 0x0 },
+ { 0xffe03080, 0x9dc01000, 0xf60, 0x0 },
+ { 0xffe03080, 0x9dc01080, 0xf60, 0x0 },
+ { 0xffe03080, 0x9d601000, 0xf60, 0x0 },
+ { 0xffe03080, 0x9d601080, 0xf60, 0x0 },
+ { 0xffe03080, 0x9d603000, 0xf60, 0x0 },
+ { 0xffe03080, 0x9d603080, 0xf60, 0x0 },
+ { 0xfc003e00, 0x48003c00, 0x3f00000, 0x1 },
+ { 0xffe02084, 0xaf402084, 0x30078, 0x0 },
+ { 0xffe00004, 0x46600000, 0x20f8, 0x0 },
+ { 0xffe03880, 0x9f203080, 0x1f0100, 0x0 },
+ { 0xf8003f00, 0x20003100, 0x7f00000, 0x1 },
+ { 0xf7c02000, 0x11402000, 0x3000fe, 0x0 },
+ { 0xf8003d08, 0x20003d00, 0x7f00000, 0x1 },
+ { 0xffe03080, 0x9ca01080, 0xf60, 0x0 },
+ { 0xffe03080, 0x9ca01000, 0xf60, 0x0 },
+ { 0xffe00000, 0x38a00000, 0x201f, 0x0 },
+ { 0xf7c02300, 0x11800000, 0x3000fe, 0x0 },
+ { 0xf7c02300, 0x13c02300, 0x3000fe, 0x0 },
+ { 0xffe03080, 0x9ce03000, 0xf60, 0x0 },
+ { 0xf9e00000, 0x90e00000, 0x6003fe0, 0x0 },
+ { 0xffe02084, 0xaf400080, 0x30078, 0x0 },
+ { 0xffe03080, 0x9ce03080, 0xf60, 0x0 },
+ { 0xff000000, 0x78000000, 0xdf3fe0, 0x0 },
+ { 0xffe03080, 0x9ce01080, 0xf60, 0x0 },
+ { 0xffe03880, 0xaba01080, 0x3f, 0x0 },
+ { 0xffe020c0, 0xad002080, 0x3f, 0x0 },
+ { 0xffe020c0, 0xad0000c0, 0x3f, 0x0 },
+ { 0xffe020c0, 0xad000080, 0x3f, 0x0 },
+ { 0xf7c02000, 0x25000000, 0x3000fe, 0x0 },
+ { 0xff602060, 0x3f200020, 0x1f80, 0x0 },
+ { 0xffe02084, 0xafc00084, 0x30078, 0x0 },
+ { 0xf7c02000, 0x24400000, 0x3000fe, 0x0 },
+ { 0xfc003000, 0x48001000, 0x3f00000, 0x1 },
+ { 0xf9e01800, 0xa1a01000, 0x60020ff, 0x0 },
+ { 0xff602060, 0x3f000040, 0x1f80, 0x0 },
+ { 0xffe02084, 0xaf602084, 0x30078, 0x0 },
+ { 0xf8003f00, 0x20003400, 0x7f00000, 0x1 },
+ { 0xffe02084, 0xaf400084, 0x30078, 0x0 },
+ { 0xffe01804, 0x44a01000, 0x20f8, 0x0 },
+ { 0xff602060, 0x3e200000, 0x1f80, 0x0 },
+ { 0xf8003e70, 0x20003a70, 0x7f00000, 0x1 },
+ { 0xf8003f00, 0x40003e00, 0x7f00000, 0x1 },
+ { 0xf8003f00, 0x20003300, 0x7f00000, 0x1 },
+ { 0xf7c02300, 0x13800300, 0x3000fe, 0x0 },
+ { 0xffe038c0, 0xada00080, 0x3f, 0x0 },
+ { 0xf9e00000, 0x49400000, 0x61f3fe0, 0x0 },
+ { 0xf8003800, 0x40002800, 0x7f00000, 0x1 },
+ { 0xffe038c0, 0xada020c0, 0x3f, 0x0 },
+ { 0xffe03884, 0xafa00880, 0x30078, 0x0 },
+ { 0xf9e00000, 0x49000000, 0x61f3fe0, 0x0 },
+ { 0xff800000, 0xd7000000, 0x6020e0, 0x0 },
+ { 0xffc00000, 0xda000000, 0x203fe0, 0x0 },
+ { 0xf7c02000, 0x12802000, 0x3000fe, 0x0 },
+ { 0xf9e00000, 0x49600000, 0x61f3fe0, 0x0 },
+ { 0xffe02000, 0x47400000, 0x7e0, 0x0 },
+ { 0xf9e00000, 0x49c00000, 0x61f3fe0, 0x0 },
+ { 0xffe03000, 0x9bc01000, 0xf60, 0x0 },
+ { 0xf7c02300, 0x13c00100, 0x3000fe, 0x0 },
+ { 0xffe03880, 0x9f002880, 0x1f0100, 0x0 },
+ { 0xffe03000, 0x9b601000, 0xf60, 0x0 },
+ { 0xffe01804, 0x40a00800, 0x20f8, 0x0 },
+ { 0xffe00004, 0x42800000, 0x20f8, 0x0 },
+ { 0xf7c03000, 0x14800000, 0x3000fe, 0x0 },
+ { 0xfc003000, 0x68001000, 0x3f00000, 0x1 },
+ { 0xfc003fc7, 0x48003f44, 0x3f00000, 0x1 },
+ { 0xfc003fc7, 0x48003f45, 0x3f00000, 0x1 },
+ { 0xf7c02000, 0x10800000, 0x3000fe, 0x0 },
+ { 0xf8003e70, 0x20003a50, 0x7f00000, 0x1 },
+ { 0xf7c02000, 0x21002000, 0x3000fe, 0x0 },
+ { 0xf8003fc4, 0x40003fc0, 0x7f00000, 0x1 },
+ { 0xf9e00000, 0x48000000, 0x61f20ff, 0x0 },
+ { 0xffc0001c, 0x75000010, 0x203fe0, 0x0 },
+ { 0xf8003f00, 0x20003800, 0x7f00000, 0x1 },
+ { 0xf9e00000, 0xa1800000, 0x60020ff, 0x0 },
+ { 0xffc01000, 0x61c00000, 0x202ffe, 0x0 },
+ { 0xffe02084, 0xaf402080, 0x30078, 0x0 },
+ { 0xffe03880, 0x9f602880, 0x1f0100, 0x0 },
+ { 0xfc003f00, 0x68003000, 0x3f00000, 0x1 },
+ { 0xfc003f00, 0x68003100, 0x3f00000, 0x1 },
+ { 0xff602060, 0x3f200000, 0x1f80, 0x0 },
+ { 0xffe03000, 0x9a801000, 0xf60, 0x0 },
+ { 0xf7c02000, 0x24802000, 0x3000fe, 0x0 },
+ { 0xffe00004, 0x42c00000, 0x20f8, 0x0 },
+ { 0xf7c02300, 0x11802000, 0x3000fe, 0x0 },
+ { 0xffc01000, 0x61401000, 0x202ffe, 0x0 },
+ { 0xffe02000, 0x43c00000, 0x7e0, 0x0 },
+ { 0xf7c02000, 0x11400000, 0x3000fe, 0x0 },
+ { 0xf7c02000, 0x21800000, 0x3000fe, 0x0 },
+ { 0xfc003c00, 0x28002c00, 0x3f00000, 0x1 },
+ { 0xfc003f00, 0x28003200, 0x3f00000, 0x1 },
+ { 0xffe03080, 0x9c803080, 0xf60, 0x0 },
+ { 0xf7c03000, 0x14c03000, 0x3000fe, 0x0 },
+ { 0xff800000, 0xdb800000, 0x6020e0, 0x0 },
+ { 0xf7c02000, 0x22402000, 0x3000fe, 0x0 },
+ { 0xffe00004, 0x46800000, 0x20f8, 0x0 },
+ { 0xffe00000, 0x69a00000, 0x1f18, 0x0 },
+ { 0xfc003e00, 0x68002a00, 0x3f00000, 0x1 },
+ { 0xffe00000, 0x60a00000, 0x1f18, 0x0 },
+ { 0xf7c02000, 0x25400000, 0x3000fe, 0x0 },
+ { 0xfc003e70, 0x28003a70, 0x3f00000, 0x1 },
+ { 0xffe03080, 0x9c803000, 0xf60, 0x0 },
+ { 0xffc01000, 0x61400000, 0x202ffe, 0x0 },
+ { 0xffe01804, 0x42a01000, 0x20f8, 0x0 },
+ { 0xffc0001c, 0x75000000, 0x203fe0, 0x0 },
+ { 0xffe02084, 0xafc02080, 0x30078, 0x0 },
+ { 0xffe03884, 0xafa00884, 0x30078, 0x0 },
+ { 0xffe03884, 0xafa02080, 0x30078, 0x0 },
+ { 0xffe00000, 0x38c00000, 0x201f, 0x0 },
+ { 0xffc01000, 0x61001000, 0x202ffe, 0x0 },
+ { 0xf9e00000, 0x48800000, 0x61f20ff, 0x0 },
+ { 0xf8003800, 0x40003000, 0x7f00000, 0x1 },
+ { 0xf7c03000, 0x15403000, 0x3000fe, 0x0 },
+ { 0xf7c03000, 0x15400000, 0x3000fe, 0x0 },
+ { 0xf7c02000, 0x21000000, 0x3000fe, 0x0 },
+ { 0xffe00004, 0x40c00000, 0x20f8, 0x0 },
+ { 0xffe01804, 0x46a01000, 0x20f8, 0x0 },
+ { 0xf8003d08, 0x20003d08, 0x7f00000, 0x1 },
+ { 0xffe038c0, 0xada02080, 0x3f, 0x0 },
+ { 0xffe03080, 0x9c203000, 0xf60, 0x0 },
+ { 0xfc003800, 0x68002000, 0x3f00000, 0x1 },
+ { 0xf9e00000, 0x90600000, 0x6003fe0, 0x0 },
+ { 0xf7c03000, 0x14000000, 0x3000fe, 0x0 },
+ { 0xf8003e70, 0x20003a40, 0x7f00000, 0x1 },
+ { 0xff201800, 0x5c000800, 0xdf20fe, 0x0 },
+ { 0xffe02000, 0x41800000, 0x7e0, 0x0 },
+ { 0xff800000, 0xdb000000, 0x6020e0, 0x0 },
+ { 0xfc003f00, 0x48003e00, 0x3f00000, 0x1 },
+ { 0xf7c03000, 0x14002000, 0x3000fe, 0x0 },
+ { 0xf7c02300, 0x11800100, 0x3000fe, 0x0 },
+ { 0xfc003e00, 0x68002800, 0x3f00000, 0x1 },
+ { 0xffe00004, 0x44c00000, 0x20f8, 0x0 },
+ { 0xffe03880, 0x9f003880, 0x1f0100, 0x0 },
+ { 0xff602000, 0x73402000, 0x1fe0, 0x0 },
+ { 0xffe00000, 0x38200000, 0x201f, 0x0 },
+ { 0xf7c02000, 0x24800000, 0x3000fe, 0x0 },
+ { 0xf7c03000, 0x15001000, 0x3000fe, 0x0 },
+ { 0xff800000, 0x7c800000, 0x1f2000, 0x0 },
+ { 0xf8003fc7, 0x40003fc6, 0x7f00000, 0x1 },
+ { 0xf7c02000, 0x12000000, 0x3000fe, 0x0 },
+ { 0xff602000, 0x73202000, 0x1fe0, 0x0 },
+ { 0xf7c02300, 0x13c00000, 0x3000fe, 0x0 },
+ { 0xff602060, 0x3f400040, 0x1f80, 0x0 },
+ { 0xf7c02000, 0x24002000, 0x3000fe, 0x0 },
+ { 0xffe02084, 0xaf800080, 0x30078, 0x0 },
+ { 0xffe00000, 0x38800000, 0x201f, 0x0 },
+ { 0xfc003f00, 0x28003800, 0x3f00000, 0x1 },
+ { 0xffe03080, 0x9c801080, 0xf60, 0x0 },
+ { 0xffe020c0, 0xad4000c0, 0x3f, 0x0 },
+ { 0xffe00000, 0x39400000, 0x201f, 0x0 },
+ { 0xf7c02300, 0x13c02100, 0x3000fe, 0x0 },
+ { 0xffe020c0, 0xad400080, 0x3f, 0x0 },
+ { 0xffe03880, 0x9f603880, 0x1f0100, 0x0 },
+ { 0xff000016, 0xde000002, 0xe020e8, 0x0 },
+ { 0xfc003d08, 0x28003d00, 0x3f00000, 0x1 },
+ { 0xfc003f00, 0x28003000, 0x3f00000, 0x1 },
+ { 0xffe03080, 0x9c401000, 0xf60, 0x0 },
+ { 0xf7c02000, 0x21402000, 0x3000fe, 0x0 },
+ { 0xff201800, 0x5c200800, 0xdf20fe, 0x0 },
+ { 0xffe01804, 0x40a01000, 0x20f8, 0x0 },
+ { 0xfc003f00, 0x68003300, 0x3f00000, 0x1 },
+ { 0xfc003f00, 0x68003200, 0x3f00000, 0x1 },
+ { 0xf7c03000, 0x15401000, 0x3000fe, 0x0 },
+ { 0xffe01804, 0x44a00800, 0x20f8, 0x0 },
+ { 0xf7c02000, 0x26000000, 0x3000fe, 0x0 },
+ { 0xffc00000, 0xda400000, 0x203fe0, 0x0 },
+ { 0xffe00004, 0x40600000, 0x20f8, 0x0 },
+ { 0xffe02080, 0xab600080, 0x3f, 0x0 },
+ { 0xf8003f00, 0x20003600, 0x7f00000, 0x1 },
+ { 0xf7c02300, 0x11c00300, 0x3000fe, 0x0 },
+ { 0xf8003f00, 0x20003700, 0x7f00000, 0x1 },
+ { 0xf7c02000, 0x25c00000, 0x3000fe, 0x0 },
+ { 0xf7c02300, 0x11800300, 0x3000fe, 0x0 },
+ { 0xffe03880, 0x9f802880, 0x1f0100, 0x0 },
+ { 0xfc003800, 0x48003000, 0x3f00000, 0x1 },
+ { 0xf8003c00, 0x20002c00, 0x7f00000, 0x1 },
+ { 0xf7c02000, 0x10400000, 0x3000fe, 0x0 },
+ { 0xff602060, 0x3f400060, 0x1f80, 0x0 },
+ { 0xffe03080, 0x9c801000, 0xf60, 0x0 },
+ { 0xff602060, 0x3e400040, 0x1f80, 0x0 },
+ { 0xf7c03000, 0x14402000, 0x3000fe, 0x0 },
+ { 0xffe0001c, 0x75800010, 0x3fe0, 0x0 },
+ { 0xff000016, 0xde000014, 0xe020e8, 0x0 },
+ { 0xf7c02300, 0x11c02000, 0x3000fe, 0x0 },
+ { 0xff600018, 0xdd200008, 0x1fe0, 0x0 },
+ { 0xff602060, 0x3e200060, 0x1f80, 0x0 },
+ { 0xff000016, 0xde000006, 0xe020e8, 0x0 },
+ { 0xffe00004, 0x44600000, 0x20f8, 0x0 },
+ { 0xf8003e00, 0x60002800, 0x7f00000, 0x1 },
+ { 0xfe600000, 0x3c000000, 0x207f, 0x0 },
+ { 0xffe03884, 0xafa02884, 0x30078, 0x0 },
+ { 0xf7c02300, 0x11802300, 0x3000fe, 0x0 },
+ { 0xffe00000, 0x38000000, 0x201f, 0x0 },
+ { 0xff200800, 0x5c000000, 0xdf20fe, 0x0 },
+ { 0xf7c02000, 0x13400000, 0x3000fe, 0x0 },
+ { 0xff200800, 0x5c200000, 0xdf20fe, 0x0 },
+ { 0xffe02000, 0x41000000, 0x7e0, 0x0 },
+ { 0xffe03880, 0x9fc02880, 0x1f0100, 0x0 },
+ { 0xffe00004, 0x46000000, 0x20f8, 0x0 },
+ { 0xff602060, 0x3f000020, 0x1f80, 0x0 },
+ { 0xfc003d08, 0x28003d08, 0x3f00000, 0x1 },
+ { 0xff602060, 0x3f200060, 0x1f80, 0x0 },
+ { 0xffe038c0, 0xada028c0, 0x3f, 0x0 },
+ { 0xffe038c0, 0xada008c0, 0x3f, 0x0 },
+ { 0xf8003f00, 0x20003500, 0x7f00000, 0x1 },
+ { 0xfc003fc4, 0x48003f40, 0x3f00000, 0x1 },
+ { 0xf9e01800, 0x48a00000, 0x61f20ff, 0x0 },
+ { 0xf7c03000, 0x14802000, 0x3000fe, 0x0 },
+ { 0xfc003f00, 0x28003900, 0x3f00000, 0x1 },
+ { 0xf8003fc7, 0x40003fc7, 0x7f00000, 0x1 },
+ { 0xffe02000, 0x45400000, 0x7e0, 0x0 },
+ { 0xffe038c0, 0xada02880, 0x3f, 0x0 },
+ { 0xffe02084, 0xaf002080, 0x30078, 0x0 },
+ { 0xffe03880, 0x9f803880, 0x1f0100, 0x0 },
+ { 0xf7c03000, 0x15000000, 0x3000fe, 0x0 },
+ { 0xfc003f00, 0x28003700, 0x3f00000, 0x1 },
+ { 0xfc003f00, 0x28003600, 0x3f00000, 0x1 },
+ { 0xffe02000, 0x47200000, 0x7e0, 0x0 },
+ { 0xffe03880, 0xaba00080, 0x3f, 0x0 },
+ { 0xffe02084, 0xafc00080, 0x30078, 0x0 },
+ { 0xff802000, 0x73800000, 0x1fe0, 0x0 },
+ { 0xffe03880, 0x9f202880, 0x1f0100, 0x0 },
+ { 0xf8003d18, 0x20003c00, 0x7f00000, 0x1 },
+ { 0xf9e00000, 0xa1600000, 0x60020ff, 0x0 },
+ { 0xffe00004, 0x44800000, 0x20f8, 0x0 },
+ { 0xf7c02000, 0x21802000, 0x3000fe, 0x0 },
+ { 0xff000000, 0xd8000000, 0x6020e0, 0x0 },
+ { 0xf9e00000, 0xa1000000, 0x60020ff, 0x0 },
+ { 0xffe03884, 0xafa00084, 0x30078, 0x0 },
+ { 0xff201800, 0x5c201800, 0xdf20fe, 0x0 },
+ { 0xff000016, 0xde000010, 0xe020e8, 0x0 },
+ { 0xffe03880, 0x9f603080, 0x1f0100, 0x0 },
+ { 0xffe02000, 0x41c00000, 0x7e0, 0x0 },
+ { 0xf7c02000, 0x20402000, 0x3000fe, 0x0 },
+ { 0xff800000, 0xe1000000, 0x1fe0, 0x0 },
+ { 0xf9e00000, 0xa1400000, 0x60020ff, 0x0 },
+ { 0xf7c03000, 0x14c00000, 0x3000fe, 0x0 },
+ { 0xf8003fc7, 0x40003f47, 0x7f00000, 0x1 },
+ { 0xffe00004, 0x40800000, 0x20f8, 0x0 },
+ { 0xff800000, 0xe1800000, 0x1fe0, 0x0 },
+ { 0xf7c02300, 0x11802100, 0x3000fe, 0x0 },
+ { 0xf9e00000, 0x49800000, 0x61f3fe0, 0x0 },
+ { 0xf7c02000, 0x26400000, 0x3000fe, 0x0 },
+ { 0xf8003c00, 0x20002800, 0x7f00000, 0x1 },
+ { 0xff902000, 0x7e002000, 0xf1fe0, 0x0 },
+ { 0xff902000, 0x7e802000, 0xf1fe0, 0x0 },
+ { 0xf9e00000, 0x91c00000, 0x6003fe0, 0x0 },
+ { 0xffe03884, 0xafa02880, 0x30078, 0x0 },
+ { 0xf7c02000, 0x22000000, 0x3000fe, 0x0 },
+ { 0xffe03080, 0x9d203000, 0xf60, 0x0 },
+ { 0xf7c02000, 0x26002000, 0x3000fe, 0x0 },
+ { 0xff800000, 0xe2000000, 0x1fe0, 0x0 },
+ { 0xf7c02000, 0x26c00000, 0x3000fe, 0x0 },
+ { 0xff602060, 0x3e400000, 0x1f80, 0x0 },
+ { 0xffe00000, 0x38400000, 0x201f, 0x0 },
+ { 0xfc003800, 0x48002000, 0x3f00000, 0x1 },
+ { 0xff000016, 0xde000000, 0xe020e8, 0x0 },
+ { 0xf8003f00, 0x20003000, 0x7f00000, 0x1 },
+ { 0xf8003e70, 0x20003a60, 0x7f00000, 0x1 },
+ { 0xff902000, 0x7e800000, 0xf1fe0, 0x0 },
+ { 0xffe020c0, 0xad6020c0, 0x3f, 0x0 },
+ { 0xf7c02300, 0x13802000, 0x3000fe, 0x0 },
+ { 0xffe020c0, 0xad600080, 0x3f, 0x0 },
+ { 0xff902000, 0x7e000000, 0xf1fe0, 0x0 },
+ { 0xf7000000, 0x17000000, 0x3000fe, 0x0 },
+ { 0xf7000000, 0x16000000, 0x3000fe, 0x0 },
+ { 0xf7c02000, 0x25002000, 0x3000fe, 0x0 },
+ { 0xfc003fc7, 0x48003fc7, 0x3f00000, 0x1 },
+ { 0xffc01000, 0x61801000, 0x202ffe, 0x0 },
+ { 0xffe03884, 0xafa03080, 0x30078, 0x0 },
+ { 0xf8003fc4, 0x40003f40, 0x7f00000, 0x1 },
+ { 0xfc003e70, 0x28003a60, 0x3f00000, 0x1 },
+ { 0xf7c02300, 0x13800000, 0x3000fe, 0x0 },
+ { 0xffe03880, 0x9f802080, 0x1f0100, 0x0 },
+ { 0xf0000000, 0xb0000000, 0xfe03fe0, 0x0 },
+ { 0xffe03880, 0x9f402080, 0x1f0100, 0x0 },
+ { 0xffe02000, 0x43200000, 0x7e0, 0x0 },
+ { 0xffe00000, 0x39800000, 0x201f, 0x0 },
+ { 0xffe03880, 0x9fc03880, 0x1f0100, 0x0 },
+ { 0xffe02000, 0x45600000, 0x7e0, 0x0 },
+ { 0xf9e00000, 0x91200000, 0x6003fe0, 0x0 },
+ { 0xffe02000, 0x43600000, 0x7e0, 0x0 },
+ { 0xfc003f00, 0x28003800, 0x3f00000, 0x1 },
+ { 0xff802000, 0x74000000, 0x1fe0, 0x0 },
+ { 0xffe02084, 0xaf002084, 0x30078, 0x0 },
+ { 0xff802000, 0x74800000, 0x1fe0, 0x0 },
+ { 0xf7c03000, 0x14c02000, 0x3000fe, 0x0 },
+ { 0xfe000001, 0x5a000000, 0x1ff3ffe, 0x0 },
+ { 0xff602060, 0x3f400020, 0x1f80, 0x0 },
+ { 0xf7c02000, 0x10802000, 0x3000fe, 0x0 },
+ { 0xffe02084, 0xaf802080, 0x30078, 0x0 },
+ { 0xffe00004, 0x46400000, 0x20f8, 0x0 },
+ { 0xffe020c0, 0xad800080, 0x3f, 0x0 },
+ { 0xffe020c0, 0xad8000c0, 0x3f, 0x0 },
+ { 0xf8003fc7, 0x40003f45, 0x7f00000, 0x1 },
+ { 0xf8003e00, 0x60002a00, 0x7f00000, 0x1 },
+ { 0xffe02084, 0xaf600084, 0x30078, 0x0 },
+ { 0xffe03080, 0x9c201000, 0xf60, 0x0 },
+ { 0xffe02000, 0x43400000, 0x7e0, 0x0 },
+ { 0xffe03080, 0x9c203080, 0xf60, 0x0 },
+ { 0xffe02000, 0x41200000, 0x7e0, 0x0 },
+ { 0xffe03080, 0x9c201080, 0xf60, 0x0 },
+ { 0xf7c02300, 0x11c02300, 0x3000fe, 0x0 },
+ { 0xffe03880, 0x9fc03080, 0x1f0100, 0x0 },
+ { 0xffe03880, 0x9f402880, 0x1f0100, 0x0 },
+ { 0xf8003800, 0x40002000, 0x7f00000, 0x1 },
+ { 0xf7c02000, 0x24402000, 0x3000fe, 0x0 },
+ { 0xf7c02000, 0x20c02000, 0x3000fe, 0x0 },
+ { 0xf7c02300, 0x11c00000, 0x3000fe, 0x0 },
+ { 0xffe02000, 0x45200000, 0x7e0, 0x0 },
+ { 0xf8003f00, 0x20003900, 0x7f00000, 0x1 },
+ { 0xf7c02300, 0x11c00100, 0x3000fe, 0x0 },
+ { 0xffe02084, 0xaf800084, 0x30078, 0x0 },
+ { 0xfe600000, 0x3c200000, 0x207f, 0x0 },
+ { 0xf7c02000, 0x26800000, 0x3000fe, 0x0 },
+ { 0xffe03880, 0x9f003080, 0x1f0100, 0x0 },
+ { 0xffe03884, 0xafa01084, 0x30078, 0x0 },
+ { 0xffc00000, 0x76000000, 0x203fe0, 0x0 },
+ { 0xff602060, 0x3e000040, 0x1f80, 0x0 },
+ { 0xffe020c0, 0xadc020c0, 0x3f, 0x0 },
+ { 0xffe00004, 0x44400000, 0x20f8, 0x0 },
+ { 0xffe020c0, 0xadc02080, 0x3f, 0x0 },
+ { 0xfe600000, 0x3c400000, 0x207f, 0x0 },
+ { 0xf7c02000, 0x20400000, 0x3000fe, 0x0 },
+ { 0xff800000, 0x7c000000, 0x1fe0, 0x0 },
+ { 0xffe03884, 0xafa00080, 0x30078, 0x0 },
+ { 0xff201800, 0x5c001800, 0xdf20fe, 0x0 },
+ { 0xffe02000, 0x47800000, 0x7e0, 0x0 },
+ { 0xff601018, 0xdd400000, 0xfe0, 0x0 },
+ { 0xffe020c0, 0xad4020c0, 0x3f, 0x0 },
+ { 0xffe020c0, 0xad402080, 0x3f, 0x0 },
+ { 0xf8003000, 0x40001000, 0x7f00000, 0x1 },
+ { 0xffe02084, 0xafc02084, 0x30078, 0x0 },
+ { 0xffe03080, 0x9c403080, 0xf60, 0x0 },
+ { 0xfc003e40, 0x28003a00, 0x3f00000, 0x1 },
+ { 0xffe038c0, 0xada010c0, 0x3f, 0x0 },
+ { 0xffe038c0, 0xada01080, 0x3f, 0x0 },
+ { 0xffe038c0, 0xada030c0, 0x3f, 0x0 },
+ { 0xffe038c0, 0xada03080, 0x3f, 0x0 },
+ { 0xf7c02000, 0x20800000, 0x3000fe, 0x0 },
+ { 0xfc003fc7, 0x48003f46, 0x3f00000, 0x1 },
+ { 0xffe01804, 0x44a00000, 0x20f8, 0x0 },
+ { 0xf7c02000, 0x20002000, 0x3000fe, 0x0 },
+ { 0xf7c02000, 0x12c02000, 0x3000fe, 0x0 },
+ { 0xffe03000, 0x9a601000, 0xf60, 0x0 },
+ { 0xffc00000, 0xda800000, 0x203fe0, 0x0 },
+ { 0xf9e00000, 0x90400000, 0x6003fe0, 0x0 },
+ { 0xffe02000, 0x47600000, 0x7e0, 0x0 },
+ { 0xffe03080, 0x9d403000, 0xf60, 0x0 },
+ { 0xffe03080, 0x9d403080, 0xf60, 0x0 },
+ { 0xffe03080, 0x9d401000, 0xf60, 0x0 },
+ { 0xffe03080, 0x9d401080, 0xf60, 0x0 },
+ { 0xffe02000, 0x41400000, 0x7e0, 0x0 },
+ { 0xff800000, 0xdf800000, 0x6020e0, 0x0 },
+ { 0xffc01000, 0x61000000, 0x202ffe, 0x0 },
+ { 0xffe03880, 0x9f202080, 0x1f0100, 0x0 },
+ { 0xfc003fc7, 0x48003fc6, 0x3f00000, 0x1 },
+ { 0xfe000000, 0x7a000000, 0x1fe0, 0x0 },
+ { 0xffff0000, 0x6a490000, 0x1f80, 0x0 },
+ { 0xff802000, 0x73000000, 0x1fe0, 0x0 },
+ { 0xff602060, 0x3e200020, 0x1f80, 0x0 },
+ { 0xf7c02000, 0x24000000, 0x3000fe, 0x0 },
+ { 0xf8003e40, 0x20003a00, 0x7f00000, 0x1 },
+ { 0xf7c03000, 0x14401000, 0x3000fe, 0x0 },
+ { 0xf8003f00, 0x20003200, 0x7f00000, 0x1 },
+ { 0xffc00000, 0x76400000, 0x203fe0, 0x0 },
+ { 0xf7c02000, 0x22002000, 0x3000fe, 0x0 },
+ { 0xffc01000, 0x61c01000, 0x202ffe, 0x0 },
+ { 0xf7c03000, 0x14801000, 0x3000fe, 0x0 },
+ { 0xf7c02000, 0x12002000, 0x3000fe, 0x0 },
+ { 0xf7c02000, 0x10402000, 0x3000fe, 0x0 },
+ { 0xff201800, 0x5d200000, 0xdf20fe, 0x0 },
+ { 0xf7c02000, 0x21400000, 0x3000fe, 0x0 },
+ { 0xff201800, 0x5d000000, 0xdf20fe, 0x0 },
+ { 0xffe02000, 0x45c00000, 0x7e0, 0x0 },
+ { 0xf7c02000, 0x25802000, 0x3000fe, 0x0 },
+ { 0xfc003e70, 0x28003a50, 0x3f00000, 0x1 },
+ { 0xf7c02300, 0x13c00300, 0x3000fe, 0x0 },
+ { 0xf9e01800, 0xa1a00800, 0x60020ff, 0x0 },
+ { 0xffe02000, 0x43800000, 0x7e0, 0x0 },
+ { 0xfc003fc4, 0x48003fc0, 0x3f00000, 0x1 },
+ { 0xff800000, 0xe2800000, 0x1fe0, 0x0 },
+ { 0xf7c02300, 0x13c02000, 0x3000fe, 0x0 },
+ { 0xffe03080, 0x9d803080, 0xf60, 0x0 },
+ { 0xffe03080, 0x9d803000, 0xf60, 0x0 },
+ { 0xffe03080, 0x9d801080, 0xf60, 0x0 },
+ { 0xf8003fc4, 0x40003f00, 0x7f00000, 0x1 },
+ { 0xffe00000, 0x39c00000, 0x201f, 0x0 },
+ { 0xffe03080, 0x9d203080, 0xf60, 0x0 },
+ { 0xffe02080, 0xab000080, 0x3f, 0x0 },
+ { 0xf8003e00, 0x60003c00, 0x7f00000, 0x1 },
+ { 0xffe03880, 0x9f602080, 0x1f0100, 0x0 },
+ { 0xffc00000, 0x76800000, 0x203fe0, 0x0 },
+ { 0xffe03884, 0xafa02084, 0x30078, 0x0 },
+ { 0xf7c02000, 0x13002000, 0x3000fe, 0x0 },
+ { 0xf9e00000, 0x91000000, 0x6003fe0, 0x0 },
+ { 0xffe03080, 0x9d201080, 0xf60, 0x0 },
+ { 0xf7c03000, 0x15002000, 0x3000fe, 0x0 },
+ { 0xf8003000, 0x60000000, 0x7f00000, 0x1 },
+ { 0xffc01000, 0x61800000, 0x202ffe, 0x0 },
+ { 0xf7c03000, 0x14400000, 0x3000fe, 0x0 },
+ { 0xffe03000, 0x9b401000, 0xf60, 0x0 },
+ { 0xf7c03000, 0x14003000, 0x3000fe, 0x0 },
+ { 0xffe03880, 0x9fc02080, 0x1f0100, 0x0 },
+ { 0xfc003fc4, 0x48003f00, 0x3f00000, 0x1 },
+ { 0xffe02000, 0x45000000, 0x7e0, 0x0 },
+ { 0xfc003800, 0x48002800, 0x3f00000, 0x1 },
+ { 0xfc003fc7, 0x48003fc5, 0x3f00000, 0x1 },
+ { 0xfc003d18, 0x28003c00, 0x3f00000, 0x1 },
+ { 0xfc003fc7, 0x48003fc4, 0x3f00000, 0x1 },
+ { 0xf8003f00, 0x60003200, 0x7f00000, 0x1 },
+ { 0xffe02084, 0xaf600080, 0x30078, 0x0 },
+ { 0xf9e01800, 0xa1a00000, 0x60020ff, 0x0 },
+ { 0xf7c03000, 0x14001000, 0x3000fe, 0x0 },
+ { 0xf7c03000, 0x14c01000, 0x3000fe, 0x0 },
+ { 0xffe00004, 0x46c00000, 0x20f8, 0x0 },
+ { 0xf7c03000, 0x15003000, 0x3000fe, 0x0 },
+ { 0xf7c02000, 0x10000000, 0x3000fe, 0x0 },
+ { 0xf8003d18, 0x20003c08, 0x7f00000, 0x1 },
+ { 0xffc0001c, 0x75400010, 0x203fe0, 0x0 },
+ { 0xf9e00000, 0x48600000, 0x61f20ff, 0x0 },
+ { 0xffe03080, 0x9c603080, 0xf60, 0x0 },
+ { 0xfe000000, 0x58000000, 0x1ff3ffe, 0x0 },
+ { 0xffe03000, 0x9a201000, 0xf60, 0x0 },
+ { 0xffe00000, 0x69e00000, 0x1f18, 0x0 },
+ { 0xffe020c0, 0xad802080, 0x3f, 0x0 },
+ { 0xffe02000, 0x47c00000, 0x7e0, 0x0 },
+ { 0xffe00000, 0x60e00000, 0x1f18, 0x0 },
+ { 0xf7c03000, 0x15402000, 0x3000fe, 0x0 },
+ { 0xffe020c0, 0xad8020c0, 0x3f, 0x0 },
+ { 0xff000016, 0xde000012, 0xe020e8, 0x0 },
+ { 0xf7c02000, 0x25c02000, 0x3000fe, 0x0 },
+ { 0xf8003f00, 0x60003100, 0x7f00000, 0x1 },
+ { 0xf8003f00, 0x60003000, 0x7f00000, 0x1 },
+ { 0xf7c02000, 0x25800000, 0x3000fe, 0x0 },
+ { 0xf7c03000, 0x14403000, 0x3000fe, 0x0 },
+ { 0xfc003d18, 0x28003c08, 0x3f00000, 0x1 },
+ { 0xffe03880, 0x9f403080, 0x1f0100, 0x0 },
+ { 0xf7c02000, 0x25402000, 0x3000fe, 0x0 },
+ { 0xf7c02000, 0x10c00000, 0x3000fe, 0x0 },
+ { 0xffe02000, 0x45800000, 0x7e0, 0x0 },
+ { 0xffe03880, 0x9f803080, 0x1f0100, 0x0 },
+ { 0xffe03080, 0x9d001000, 0xf60, 0x0 },
+ { 0xffe03080, 0x9d001080, 0xf60, 0x0 },
+ { 0xffe03080, 0x9d003000, 0xf60, 0x0 },
+ { 0xffe03080, 0x9d003080, 0xf60, 0x0 },
+ { 0xffe03080, 0x9d801000, 0xf60, 0x0 },
+ { 0xf9e00000, 0x49200000, 0x61f3fe0, 0x0 },
+ { 0xf9e00000, 0xa1c00000, 0x60020ff, 0x0 },
+ { 0xf9e00000, 0x90200000, 0x6003fe0, 0x0 },
+ { 0xffe03080, 0x9d201000, 0xf60, 0x0 },
+ { 0xffe03884, 0xafa01080, 0x30078, 0x0 },
+ { 0xffe02084, 0xaf602080, 0x30078, 0x0 },
+ { 0xffe038c0, 0xada000c0, 0x3f, 0x0 },
+ { 0xffe02080, 0xab400080, 0x3f, 0x0 },
+ { 0xff000016, 0xde000004, 0xe020e8, 0x0 },
+ { 0xffe00004, 0x44000000, 0x20f8, 0x0 },
+ { 0xf7c02000, 0x20000000, 0x3000fe, 0x0 },
+ { 0xfc003d18, 0x28003c10, 0x3f00000, 0x1 },
+ { 0xff600018, 0xdd000008, 0x1fe0, 0x0 },
+ { 0xffe020c0, 0xadc000c0, 0x3f, 0x0 },
+ { 0xffe020c0, 0xadc00080, 0x3f, 0x0 },
+ { 0xffe03000, 0x9b801000, 0xf60, 0x0 },
+ { 0xf8003fc7, 0x40003f46, 0x7f00000, 0x1 },
+ { 0xf7c02000, 0x21c02000, 0x3000fe, 0x0 },
+ { 0xffe01804, 0x40a00000, 0x20f8, 0x0 },
+ { 0xf7c02000, 0x26402000, 0x3000fe, 0x0 },
+ { 0xffe03080, 0x9c401080, 0xf60, 0x0 },
+ { 0xffe00000, 0x39200000, 0x201f, 0x0 },
+ { 0xffe03080, 0x9c403000, 0xf60, 0x0 },
+ { 0xf7c02000, 0x11002000, 0x3000fe, 0x0 },
+ { 0xfc003c00, 0x28002800, 0x3f00000, 0x1 },
+ { 0xffe00004, 0x40400000, 0x20f8, 0x0 },
+ { 0xf7c02000, 0x26802000, 0x3000fe, 0x0 },
+ { 0xf7c02000, 0x13000000, 0x3000fe, 0x0 },
+ { 0xffe00004, 0x42600000, 0x20f8, 0x0 },
+ { 0xf8003000, 0x60001000, 0x7f00000, 0x1 },
+ { 0xff602060, 0x3e400020, 0x1f80, 0x0 },
+ { 0xff602060, 0x3f000000, 0x1f80, 0x0 },
+ { 0xf7c02000, 0x24c02000, 0x3000fe, 0x0 },
+ { 0xff802000, 0x74002000, 0x1fe0, 0x0 },
+ { 0xf8003800, 0x20002000, 0x7f00000, 0x1 },
+ { 0xffe03000, 0x9aa01000, 0xf60, 0x0 },
+ { 0xf7c02000, 0x12400000, 0x3000fe, 0x0 },
+ { 0xff602060, 0x3f000060, 0x1f80, 0x0 },
+ { 0xf7c02000, 0x11000000, 0x3000fe, 0x0 },
+};
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonExecutableAtoms.h b/lib/ReaderWriter/ELF/Hexagon/HexagonExecutableAtoms.h
new file mode 100644
index 000000000000..a2505aa460c5
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Hexagon/HexagonExecutableAtoms.h
@@ -0,0 +1,29 @@
+//===- lib/ReaderWriter/ELF/Hexagon/HexagonExecutableAtoms.h --------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_EXECUTABLE_ATOM_H
+#define LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_EXECUTABLE_ATOM_H
+
+#include "ELFFile.h"
+
+namespace lld {
+namespace elf {
+typedef llvm::object::ELFType<llvm::support::little, 2, false> HexagonELFType;
+class HexagonLinkingContext;
+
+template <class HexagonELFType> class HexagonRuntimeFile
+ : public RuntimeFile<HexagonELFType> {
+public:
+ HexagonRuntimeFile(HexagonLinkingContext &context)
+ : RuntimeFile<HexagonELFType>(context, "Hexagon runtime file") {}
+};
+} // elf
+} // lld
+
+#endif // LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_EXECUTABLE_ATOM_H
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonExecutableWriter.h b/lib/ReaderWriter/ELF/Hexagon/HexagonExecutableWriter.h
new file mode 100644
index 000000000000..0848e64166fa
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Hexagon/HexagonExecutableWriter.h
@@ -0,0 +1,86 @@
+//===- lib/ReaderWriter/ELF/Hexagon/HexagonExecutableWriter.h -------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef HEXAGON_EXECUTABLE_WRITER_H
+#define HEXAGON_EXECUTABLE_WRITER_H
+
+#include "ExecutableWriter.h"
+#include "HexagonELFWriters.h"
+#include "HexagonExecutableAtoms.h"
+#include "HexagonLinkingContext.h"
+
+namespace lld {
+namespace elf {
+
+template <typename ELFT> class HexagonTargetLayout;
+
+template <class ELFT>
+class HexagonExecutableWriter : public ExecutableWriter<ELFT>,
+ public HexagonELFWriter<ELFT> {
+public:
+ HexagonExecutableWriter(HexagonLinkingContext &context,
+ HexagonTargetLayout<ELFT> &layout);
+
+protected:
+ // Add any runtime files and their atoms to the output
+ virtual bool createImplicitFiles(std::vector<std::unique_ptr<File>> &);
+
+ virtual void finalizeDefaultAtomValues();
+
+ virtual std::error_code setELFHeader() {
+ ExecutableWriter<ELFT>::setELFHeader();
+ HexagonELFWriter<ELFT>::setELFHeader(*this->_elfHeader);
+ return std::error_code();
+ }
+
+private:
+ void addDefaultAtoms() {
+ _hexagonRuntimeFile->addAbsoluteAtom("_SDA_BASE_");
+ if (this->_context.isDynamic()) {
+ _hexagonRuntimeFile->addAbsoluteAtom("_GLOBAL_OFFSET_TABLE_");
+ _hexagonRuntimeFile->addAbsoluteAtom("_DYNAMIC");
+ }
+ }
+
+ HexagonLinkingContext &_hexagonLinkingContext;
+ HexagonTargetLayout<ELFT> &_hexagonTargetLayout;
+ std::unique_ptr<HexagonRuntimeFile<ELFT>> _hexagonRuntimeFile;
+};
+
+template <class ELFT>
+HexagonExecutableWriter<ELFT>::HexagonExecutableWriter(
+ HexagonLinkingContext &context, HexagonTargetLayout<ELFT> &layout)
+ : ExecutableWriter<ELFT>(context, layout),
+ HexagonELFWriter<ELFT>(context, layout), _hexagonLinkingContext(context),
+ _hexagonTargetLayout(layout),
+ _hexagonRuntimeFile(new HexagonRuntimeFile<ELFT>(context)) {}
+
+template <class ELFT>
+bool HexagonExecutableWriter<ELFT>::createImplicitFiles(
+ std::vector<std::unique_ptr<File>> &result) {
+ ExecutableWriter<ELFT>::createImplicitFiles(result);
+ // Add the default atoms as defined for hexagon
+ addDefaultAtoms();
+ result.push_back(std::move(_hexagonRuntimeFile));
+ return true;
+}
+
+template <class ELFT>
+void HexagonExecutableWriter<ELFT>::finalizeDefaultAtomValues() {
+ // Finalize the atom values that are part of the parent.
+ ExecutableWriter<ELFT>::finalizeDefaultAtomValues();
+ auto sdabaseAtomIter = _hexagonTargetLayout.findAbsoluteAtom("_SDA_BASE_");
+ (*sdabaseAtomIter)->_virtualAddr =
+ _hexagonTargetLayout.getSDataSection()->virtualAddr();
+ HexagonELFWriter<ELFT>::finalizeHexagonRuntimeAtomValues();
+}
+
+} // namespace elf
+} // namespace lld
+
+#endif // HEXAGON_EXECUTABLE_WRITER_H
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.cpp b/lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.cpp
new file mode 100644
index 000000000000..7eacb2b44c3b
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.cpp
@@ -0,0 +1,25 @@
+//===- lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.cpp -------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "HexagonLinkingContext.h"
+#include "HexagonTargetHandler.h"
+
+using namespace lld::elf;
+
+std::unique_ptr<lld::ELFLinkingContext>
+HexagonLinkingContext::create(llvm::Triple triple) {
+ if (triple.getArch() == llvm::Triple::hexagon)
+ return std::unique_ptr<lld::ELFLinkingContext>(
+ new HexagonLinkingContext(triple));
+ return nullptr;
+}
+
+HexagonLinkingContext::HexagonLinkingContext(llvm::Triple triple)
+ : ELFLinkingContext(triple, std::unique_ptr<TargetHandlerBase>(
+ new HexagonTargetHandler(*this))) {}
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.h b/lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.h
new file mode 100644
index 000000000000..c920cdf153aa
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.h
@@ -0,0 +1,69 @@
+//===- lib/ReaderWriter/ELF/Hexagon/HexagonLinkingContext.h ---------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_LINKING_CONTEXT_H
+#define LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_LINKING_CONTEXT_H
+
+#include "lld/ReaderWriter/ELFLinkingContext.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/ELF.h"
+
+namespace lld {
+namespace elf {
+
+typedef llvm::object::ELFType<llvm::support::little, 2, false> HexagonELFType;
+
+class HexagonLinkingContext final : public ELFLinkingContext {
+public:
+ static std::unique_ptr<ELFLinkingContext> create(llvm::Triple);
+ HexagonLinkingContext(llvm::Triple triple);
+
+ void addPasses(PassManager &) override;
+
+ bool isDynamicRelocation(const Reference &r) const override {
+ if (r.kindNamespace() != Reference::KindNamespace::ELF)
+ return false;
+ switch (r.kindValue()) {
+ case llvm::ELF::R_HEX_RELATIVE:
+ case llvm::ELF::R_HEX_GLOB_DAT:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ bool isPLTRelocation(const Reference &r) const override {
+ if (r.kindNamespace() != Reference::KindNamespace::ELF)
+ return false;
+ switch (r.kindValue()) {
+ case llvm::ELF::R_HEX_JMP_SLOT:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /// \brief Hexagon has only one relative relocation
+ /// a) for supporting relative relocs - R_HEX_RELATIVE
+ bool isRelativeReloc(const Reference &r) const override {
+ if (r.kindNamespace() != Reference::KindNamespace::ELF)
+ return false;
+ switch (r.kindValue()) {
+ case llvm::ELF::R_HEX_RELATIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+};
+
+} // elf
+} // lld
+
+#endif // LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_LINKING_CONTEXT_H
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationFunctions.h b/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationFunctions.h
new file mode 100644
index 000000000000..2b9e25ce363b
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationFunctions.h
@@ -0,0 +1,49 @@
+//===- HexagonRelocationFunction.h ----------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_RELOCATION_FUNCTIONS_H
+#define LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_RELOCATION_FUNCTIONS_H
+
+namespace lld {
+namespace elf {
+
+/// \brief HexagonInstruction which is used to store various values
+typedef struct {
+ uint32_t insnMask;
+ uint32_t insnCmpMask;
+ uint32_t insnBitMask;
+ bool isDuplex;
+} Instruction;
+
+#include "HexagonEncodings.h"
+
+#define FINDV4BITMASK(INSN) \
+ findBitMask((uint32_t) * ((llvm::support::ulittle32_t *) INSN), \
+ insn_encodings, \
+ sizeof(insn_encodings) / sizeof(Instruction))
+
+/// \brief finds the scatter Bits that need to be used to apply relocations
+inline uint32_t
+findBitMask(uint32_t insn, Instruction *encodings, int32_t numInsns) {
+ for (int32_t i = 0; i < numInsns; i++) {
+ if (((insn & 0xc000) == 0) && !(encodings[i].isDuplex))
+ continue;
+
+ if (((insn & 0xc000) != 0) && (encodings[i].isDuplex))
+ continue;
+
+ if (((encodings[i].insnMask) & insn) == encodings[i].insnCmpMask)
+ return encodings[i].insnBitMask;
+ }
+ llvm_unreachable("found unknown instruction");
+}
+
+} // elf
+} // lld
+
+#endif // LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_RELOCATION_FUNCTIONS_H
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.cpp b/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.cpp
new file mode 100644
index 000000000000..21967d356a31
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.cpp
@@ -0,0 +1,350 @@
+//===- lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.cpp ---------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "HexagonLinkingContext.h"
+#include "HexagonRelocationFunctions.h"
+#include "HexagonTargetHandler.h"
+#include "HexagonRelocationHandler.h"
+#include "llvm/Support/Endian.h"
+
+using namespace lld;
+using namespace lld::elf;
+using namespace llvm::ELF;
+using namespace llvm::support::endian;
+
+#define APPLY_RELOC(result) \
+ write32le(location, result | read32le(location));
+
+static int relocBNPCREL(uint8_t *location, uint64_t P, uint64_t S, uint64_t A,
+ int32_t nBits) {
+ int32_t result = (uint32_t)(((S + A) - P) >> 2);
+ int32_t range = 1 << nBits;
+ if (result < range && result > -range) {
+ result = lld::scatterBits<int32_t>(result, FINDV4BITMASK(location));
+ APPLY_RELOC(result);
+ return 0;
+ }
+ return 1;
+}
+
+/// \brief Word32_LO: 0x00c03fff : (S + A) : Truncate
+static int relocLO16(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) {
+ uint32_t result = (uint32_t)(S + A);
+ result = lld::scatterBits<int32_t>(result, 0x00c03fff);
+ APPLY_RELOC(result);
+ return 0;
+}
+
+/// \brief Word32_LO: 0x00c03fff : (S + A) >> 16 : Truncate
+static int relocHI16(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) {
+ uint32_t result = (uint32_t)((S + A) >> 16);
+ result = lld::scatterBits<int32_t>(result, 0x00c03fff);
+ APPLY_RELOC(result);
+ return 0;
+}
+
+/// \brief Word32: 0xffffffff : (S + A) : Truncate
+static int reloc32(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) {
+ uint32_t result = (uint32_t)(S + A);
+ APPLY_RELOC(result);
+ return 0;
+}
+
+static int reloc32_6_X(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) {
+ int64_t result = ((S + A) >> 6);
+ int64_t range = ((int64_t)1) << 32;
+ if (result > range)
+ return 1;
+ result = lld::scatterBits<int32_t>(result, 0xfff3fff);
+ APPLY_RELOC(result);
+ return 0;
+}
+
+// R_HEX_B32_PCREL_X
+static int relocHexB32PCRELX(uint8_t *location, uint64_t P, uint64_t S,
+ uint64_t A) {
+ int64_t result = ((S + A - P) >> 6);
+ result = lld::scatterBits<int32_t>(result, 0xfff3fff);
+ APPLY_RELOC(result);
+ return 0;
+}
+
+// R_HEX_BN_PCREL_X
+static int relocHexBNPCRELX(uint8_t *location, uint64_t P, uint64_t S,
+ uint64_t A, int nbits) {
+ int32_t result = ((S + A - P) & 0x3f);
+ int32_t range = 1 << nbits;
+ if (result < range && result > -range) {
+ result = lld::scatterBits<int32_t>(result, FINDV4BITMASK(location));
+ APPLY_RELOC(result);
+ return 0;
+ }
+ return 1;
+}
+
+// R_HEX_6_PCREL_X
+static int relocHex6PCRELX(uint8_t *location, uint64_t P, uint64_t S,
+ uint64_t A) {
+ int32_t result = (S + A - P);
+ result = lld::scatterBits<int32_t>(result, FINDV4BITMASK(location));
+ APPLY_RELOC(result);
+ return 0;
+}
+
+// R_HEX_N_X : Word32_U6 : (S + A) : Unsigned Truncate
+static int relocHex_N_X(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) {
+ uint32_t result = (S + A);
+ result = lld::scatterBits<uint32_t>(result, FINDV4BITMASK(location));
+ APPLY_RELOC(result);
+ return 0;
+}
+
+// GP REL relocations
+static int relocHexGPRELN(uint8_t *location, uint64_t P, uint64_t S, uint64_t A,
+ uint64_t GP, int nShiftBits) {
+ int32_t result = (int64_t)((S + A - GP) >> nShiftBits);
+ int32_t range = 1L << 16;
+ if (result <= range) {
+ result = lld::scatterBits<uint32_t>(result, FINDV4BITMASK(location));
+ APPLY_RELOC(result);
+ return 0;
+ }
+ return 1;
+}
+
+/// \brief Word32_LO: 0x00c03fff : (G) : Truncate
+static int relocHexGOTLO16(uint8_t *location, uint64_t A, uint64_t GOT) {
+ int32_t result = (int32_t)(A-GOT);
+ result = lld::scatterBits<int32_t>(result, 0x00c03fff);
+ APPLY_RELOC(result);
+ return 0;
+}
+
+/// \brief Word32_LO: 0x00c03fff : (G) >> 16 : Truncate
+static int relocHexGOTHI16(uint8_t *location, uint64_t A, uint64_t GOT) {
+ int32_t result = (int32_t)((A-GOT) >> 16);
+ result = lld::scatterBits<int32_t>(result, 0x00c03fff);
+ APPLY_RELOC(result);
+ return 0;
+}
+
+/// \brief Word32: 0xffffffff : (G) : Truncate
+static int relocHexGOT32(uint8_t *location, uint64_t A, uint64_t GOT) {
+ int32_t result = (int32_t)(GOT - A);
+ APPLY_RELOC(result);
+ return 0;
+}
+
+/// \brief Word32_U16 : (G) : Truncate
+static int relocHexGOT16(uint8_t *location, uint64_t A, uint64_t GOT) {
+ int32_t result = (int32_t)(GOT-A);
+ int32_t range = 1L << 16;
+ if (result <= range) {
+ result = lld::scatterBits<int32_t>(result, FINDV4BITMASK(location));
+ APPLY_RELOC(result);
+ return 0;
+ }
+ return 1;
+}
+
+static int relocHexGOT32_6_X(uint8_t *location, uint64_t A, uint64_t GOT) {
+ int32_t result = (int32_t)((A-GOT) >> 6);
+ result = lld::scatterBits<int32_t>(result, FINDV4BITMASK(location));
+ APPLY_RELOC(result);
+ return 0;
+}
+
+static int relocHexGOT16_X(uint8_t *location, uint64_t A, uint64_t GOT) {
+ int32_t result = (int32_t)(A-GOT);
+ int32_t range = 1L << 6;
+ if (result <= range) {
+ result = lld::scatterBits<int32_t>(result, FINDV4BITMASK(location));
+ APPLY_RELOC(result);
+ return 0;
+ }
+ return 1;
+}
+
+static int relocHexGOT11_X(uint8_t *location, uint64_t A, uint64_t GOT) {
+ uint32_t result = (uint32_t)(A-GOT);
+ result = lld::scatterBits<uint32_t>(result, FINDV4BITMASK(location));
+ APPLY_RELOC(result);
+ return 0;
+}
+
+static int relocHexGOTRELSigned(uint8_t *location, uint64_t P, uint64_t S,
+ uint64_t A, uint64_t GOT, int shiftBits = 0) {
+ int32_t result = (int32_t)((S + A - GOT) >> shiftBits);
+ result = lld::scatterBits<int32_t>(result, FINDV4BITMASK(location));
+ APPLY_RELOC(result);
+ return 0;
+}
+
+static int relocHexGOTRELUnsigned(uint8_t *location, uint64_t P, uint64_t S,
+ uint64_t A, uint64_t GOT, int shiftBits = 0) {
+ uint32_t result = (uint32_t)((S + A - GOT) >> shiftBits);
+ result = lld::scatterBits<uint32_t>(result, FINDV4BITMASK(location));
+ APPLY_RELOC(result);
+ return 0;
+}
+
+static int relocHexGOTREL_HILO16(uint8_t *location, uint64_t P, uint64_t S,
+ uint64_t A, uint64_t GOT, int shiftBits = 0) {
+ int32_t result = (int32_t)((S + A - GOT) >> shiftBits);
+ result = lld::scatterBits<int32_t>(result, 0x00c03fff);
+ APPLY_RELOC(result);
+ return 0;
+}
+
+static int relocHexGOTREL_32(uint8_t *location, uint64_t P, uint64_t S,
+ uint64_t A, uint64_t GOT) {
+ int32_t result = (int32_t)(S + A - GOT);
+ APPLY_RELOC(result);
+ return 0;
+}
+
+std::error_code HexagonTargetRelocationHandler::applyRelocation(
+ ELFWriter &writer, llvm::FileOutputBuffer &buf, const lld::AtomLayout &atom,
+ const Reference &ref) const {
+ uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset;
+ uint8_t *location = atomContent + ref.offsetInAtom();
+ uint64_t targetVAddress = writer.addressOfAtom(ref.target());
+ uint64_t relocVAddress = atom._virtualAddr + ref.offsetInAtom();
+
+ if (ref.kindNamespace() != Reference::KindNamespace::ELF)
+ return std::error_code();
+ assert(ref.kindArch() == Reference::KindArch::Hexagon);
+ switch (ref.kindValue()) {
+ case R_HEX_B22_PCREL:
+ relocBNPCREL(location, relocVAddress, targetVAddress, ref.addend(), 21);
+ break;
+ case R_HEX_B15_PCREL:
+ relocBNPCREL(location, relocVAddress, targetVAddress, ref.addend(), 14);
+ break;
+ case R_HEX_B9_PCREL:
+ relocBNPCREL(location, relocVAddress, targetVAddress, ref.addend(), 8);
+ break;
+ case R_HEX_LO16:
+ relocLO16(location, relocVAddress, targetVAddress, ref.addend());
+ break;
+ case R_HEX_HI16:
+ relocHI16(location, relocVAddress, targetVAddress, ref.addend());
+ break;
+ case R_HEX_32:
+ reloc32(location, relocVAddress, targetVAddress, ref.addend());
+ break;
+ case R_HEX_32_6_X:
+ reloc32_6_X(location, relocVAddress, targetVAddress, ref.addend());
+ break;
+ case R_HEX_B32_PCREL_X:
+ relocHexB32PCRELX(location, relocVAddress, targetVAddress, ref.addend());
+ break;
+ case R_HEX_B22_PCREL_X:
+ relocHexBNPCRELX(location, relocVAddress, targetVAddress, ref.addend(), 21);
+ break;
+ case R_HEX_B15_PCREL_X:
+ relocHexBNPCRELX(location, relocVAddress, targetVAddress, ref.addend(), 14);
+ break;
+ case R_HEX_B13_PCREL_X:
+ relocHexBNPCRELX(location, relocVAddress, targetVAddress, ref.addend(), 12);
+ break;
+ case R_HEX_B9_PCREL_X:
+ relocHexBNPCRELX(location, relocVAddress, targetVAddress, ref.addend(), 8);
+ break;
+ case R_HEX_B7_PCREL_X:
+ relocHexBNPCRELX(location, relocVAddress, targetVAddress, ref.addend(), 6);
+ break;
+ case R_HEX_GPREL16_0:
+ relocHexGPRELN(location, relocVAddress, targetVAddress, ref.addend(),
+ _hexagonTargetLayout.getSDataSection()->virtualAddr(), 0);
+ break;
+ case R_HEX_GPREL16_1:
+ relocHexGPRELN(location, relocVAddress, targetVAddress, ref.addend(),
+ _hexagonTargetLayout.getSDataSection()->virtualAddr(), 1);
+ break;
+ case R_HEX_GPREL16_2:
+ relocHexGPRELN(location, relocVAddress, targetVAddress, ref.addend(),
+ _hexagonTargetLayout.getSDataSection()->virtualAddr(), 2);
+ break;
+ case R_HEX_GPREL16_3:
+ relocHexGPRELN(location, relocVAddress, targetVAddress, ref.addend(),
+ _hexagonTargetLayout.getSDataSection()->virtualAddr(), 3);
+ break;
+ case R_HEX_16_X:
+ case R_HEX_12_X:
+ case R_HEX_11_X:
+ case R_HEX_10_X:
+ case R_HEX_9_X:
+ case R_HEX_8_X:
+ case R_HEX_7_X:
+ case R_HEX_6_X:
+ relocHex_N_X(location, relocVAddress, targetVAddress, ref.addend());
+ break;
+ case R_HEX_6_PCREL_X:
+ relocHex6PCRELX(location, relocVAddress, targetVAddress, ref.addend());
+ break;
+ case R_HEX_JMP_SLOT:
+ case R_HEX_GLOB_DAT:
+ break;
+ case R_HEX_GOTREL_32:
+ relocHexGOTREL_32(location, relocVAddress, targetVAddress, ref.addend(),
+ _hexagonTargetLayout.getGOTSymAddr());
+ break;
+ case R_HEX_GOTREL_LO16:
+ relocHexGOTREL_HILO16(location, relocVAddress, targetVAddress, ref.addend(),
+ _hexagonTargetLayout.getGOTSymAddr());
+ break;
+ case R_HEX_GOTREL_HI16:
+ relocHexGOTREL_HILO16(location, relocVAddress, targetVAddress, ref.addend(),
+ _hexagonTargetLayout.getGOTSymAddr(), 16);
+ break;
+ case R_HEX_GOT_LO16:
+ relocHexGOTLO16(location, targetVAddress,
+ _hexagonTargetLayout.getGOTSymAddr());
+ break;
+ case R_HEX_GOT_HI16:
+ relocHexGOTHI16(location, targetVAddress,
+ _hexagonTargetLayout.getGOTSymAddr());
+ break;
+ case R_HEX_GOT_32:
+ relocHexGOT32(location, targetVAddress,
+ _hexagonTargetLayout.getGOTSymAddr());
+ break;
+ case R_HEX_GOT_16:
+ relocHexGOT16(location, targetVAddress,
+ _hexagonTargetLayout.getGOTSymAddr());
+ break;
+ case R_HEX_GOT_32_6_X:
+ relocHexGOT32_6_X(location, targetVAddress,
+ _hexagonTargetLayout.getGOTSymAddr());
+ break;
+ case R_HEX_GOT_16_X:
+ relocHexGOT16_X(location, targetVAddress,
+ _hexagonTargetLayout.getGOTSymAddr());
+ break;
+ case R_HEX_GOT_11_X:
+ relocHexGOT11_X(location, targetVAddress,
+ _hexagonTargetLayout.getGOTSymAddr());
+ break;
+ case R_HEX_GOTREL_32_6_X:
+ relocHexGOTRELSigned(location, relocVAddress, targetVAddress, ref.addend(),
+ _hexagonTargetLayout.getGOTSymAddr(), 6);
+ break;
+ case R_HEX_GOTREL_16_X:
+ case R_HEX_GOTREL_11_X:
+ relocHexGOTRELUnsigned(location, relocVAddress, targetVAddress,
+ ref.addend(), _hexagonTargetLayout.getGOTSymAddr());
+ break;
+
+ default:
+ return make_unhandled_reloc_error();
+ }
+
+ return std::error_code();
+}
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.h b/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.h
new file mode 100644
index 000000000000..4795d0264b9c
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.h
@@ -0,0 +1,35 @@
+//===- lld/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.h -----------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_RELOCATION_HANDLER_H
+#define LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_RELOCATION_HANDLER_H
+
+#include "HexagonSectionChunks.h"
+#include "HexagonTargetHandler.h"
+#include "lld/ReaderWriter/RelocationHelperFunctions.h"
+
+namespace lld {
+namespace elf {
+
+class HexagonTargetHandler;
+
+class HexagonTargetRelocationHandler final : public TargetRelocationHandler {
+public:
+ HexagonTargetRelocationHandler(HexagonTargetLayout<HexagonELFType> &layout)
+ : _hexagonTargetLayout(layout) {}
+
+ std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &,
+ const lld::AtomLayout &,
+ const Reference &) const override;
+
+private:
+ HexagonTargetLayout<HexagonELFType> &_hexagonTargetLayout;
+};
+} // elf
+} // lld
+#endif
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonSectionChunks.h b/lib/ReaderWriter/ELF/Hexagon/HexagonSectionChunks.h
new file mode 100644
index 000000000000..5b3fbbbd899b
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Hexagon/HexagonSectionChunks.h
@@ -0,0 +1,86 @@
+//===- lib/ReaderWriter/ELF/Hexagon/HexagonSectionChunks.h-----------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef HEXAGON_SECTION_CHUNKS_H
+#define HEXAGON_SECTION_CHUNKS_H
+
+#include "HexagonTargetHandler.h"
+
+namespace lld {
+namespace elf {
+template <typename ELFT> class HexagonTargetLayout;
+class HexagonLinkingContext;
+
+/// \brief Handle Hexagon SData section
+template <class HexagonELFType>
+class SDataSection : public AtomSection<HexagonELFType> {
+public:
+ SDataSection(const HexagonLinkingContext &context)
+ : AtomSection<HexagonELFType>(
+ context, ".sdata", DefinedAtom::typeDataFast, 0,
+ HexagonTargetLayout<HexagonELFType>::ORDER_SDATA) {
+ this->_type = SHT_PROGBITS;
+ this->_flags = SHF_ALLOC | SHF_WRITE;
+ this->_alignment = 4096;
+ }
+
+ /// \brief Finalize the section contents before writing
+ virtual void doPreFlight();
+
+ /// \brief Does this section have an output segment.
+ virtual bool hasOutputSegment() { return true; }
+
+ const lld::AtomLayout *appendAtom(const Atom *atom) {
+ const DefinedAtom *definedAtom = cast<DefinedAtom>(atom);
+ DefinedAtom::Alignment atomAlign = definedAtom->alignment();
+ uint64_t alignment = 1u << atomAlign.powerOf2;
+ this->_atoms.push_back(new (this->_alloc) lld::AtomLayout(atom, 0, 0));
+ // Set the section alignment to the largest alignment
+ // std::max doesn't support uint64_t
+ if (this->_alignment < alignment)
+ this->_alignment = alignment;
+ return (this->_atoms.back());
+ }
+
+}; // SDataSection
+
+template <class HexagonELFType>
+void SDataSection<HexagonELFType>::doPreFlight() {
+ // sort the atoms on the alignments they have been set
+ std::stable_sort(this->_atoms.begin(), this->_atoms.end(),
+ [](const lld::AtomLayout * A,
+ const lld::AtomLayout * B) {
+ const DefinedAtom *definedAtomA = cast<DefinedAtom>(A->_atom);
+ const DefinedAtom *definedAtomB = cast<DefinedAtom>(B->_atom);
+ int64_t alignmentA = 1 << definedAtomA->alignment().powerOf2;
+ int64_t alignmentB = 1 << definedAtomB->alignment().powerOf2;
+ if (alignmentA == alignmentB) {
+ if (definedAtomA->merge() == DefinedAtom::mergeAsTentative)
+ return false;
+ if (definedAtomB->merge() == DefinedAtom::mergeAsTentative)
+ return true;
+ }
+ return alignmentA < alignmentB;
+ });
+
+ // Set the fileOffset, and the appropriate size of the section
+ for (auto &ai : this->_atoms) {
+ const DefinedAtom *definedAtom = cast<DefinedAtom>(ai->_atom);
+ DefinedAtom::Alignment atomAlign = definedAtom->alignment();
+ uint64_t fOffset = this->alignOffset(this->fileSize(), atomAlign);
+ uint64_t mOffset = this->alignOffset(this->memSize(), atomAlign);
+ ai->_fileOffset = fOffset;
+ this->_fsize = fOffset + definedAtom->size();
+ this->_msize = mOffset + definedAtom->size();
+ }
+} // finalize
+
+} // elf
+} // lld
+
+#endif // LLD_READER_WRITER_ELF_HEXAGON_HEXAGON_SECTION_CHUNKS_H
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.cpp b/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.cpp
new file mode 100644
index 000000000000..9b10c2f160f4
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.cpp
@@ -0,0 +1,334 @@
+//===- lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.cpp --------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "HexagonExecutableWriter.h"
+#include "HexagonDynamicLibraryWriter.h"
+#include "HexagonLinkingContext.h"
+#include "HexagonTargetHandler.h"
+
+using namespace lld;
+using namespace elf;
+using namespace llvm::ELF;
+
+using llvm::makeArrayRef;
+
+HexagonTargetHandler::HexagonTargetHandler(HexagonLinkingContext &context)
+ : _hexagonLinkingContext(context),
+ _hexagonRuntimeFile(new HexagonRuntimeFile<HexagonELFType>(context)),
+ _hexagonTargetLayout(new HexagonTargetLayout<HexagonELFType>(context)),
+ _hexagonRelocationHandler(new HexagonTargetRelocationHandler(
+ *_hexagonTargetLayout.get())) {}
+
+std::unique_ptr<Writer> HexagonTargetHandler::getWriter() {
+ switch (_hexagonLinkingContext.getOutputELFType()) {
+ case llvm::ELF::ET_EXEC:
+ return std::unique_ptr<Writer>(
+ new elf::HexagonExecutableWriter<HexagonELFType>(
+ _hexagonLinkingContext, *_hexagonTargetLayout.get()));
+ case llvm::ELF::ET_DYN:
+ return std::unique_ptr<Writer>(
+ new elf::HexagonDynamicLibraryWriter<HexagonELFType>(
+ _hexagonLinkingContext, *_hexagonTargetLayout.get()));
+ case llvm::ELF::ET_REL:
+ llvm_unreachable("TODO: support -r mode");
+ default:
+ llvm_unreachable("unsupported output type");
+ }
+}
+
+using namespace llvm::ELF;
+
+// .got atom
+const uint8_t hexagonGotAtomContent[4] = { 0 };
+// .got.plt atom (entry 0)
+const uint8_t hexagonGotPlt0AtomContent[16] = { 0 };
+// .got.plt atom (all other entries)
+const uint8_t hexagonGotPltAtomContent[4] = { 0 };
+// .plt (entry 0)
+const uint8_t hexagonPlt0AtomContent[28] = {
+ 0x00, 0x40, 0x00, 0x00, // { immext (#0)
+ 0x1c, 0xc0, 0x49, 0x6a, // r28 = add (pc, ##GOT0@PCREL) } # address of GOT0
+ 0x0e, 0x42, 0x9c, 0xe2, // { r14 -= add (r28, #16) # offset of GOTn from GOTa
+ 0x4f, 0x40, 0x9c, 0x91, // r15 = memw (r28 + #8) # object ID at GOT2
+ 0x3c, 0xc0, 0x9c, 0x91, // r28 = memw (r28 + #4) }# dynamic link at GOT1
+ 0x0e, 0x42, 0x0e, 0x8c, // { r14 = asr (r14, #2) # index of PLTn
+ 0x00, 0xc0, 0x9c, 0x52, // jumpr r28 } # call dynamic linker
+};
+
+// .plt (other entries)
+const uint8_t hexagonPltAtomContent[16] = {
+ 0x00, 0x40, 0x00, 0x00, // { immext (#0)
+ 0x0e, 0xc0, 0x49, 0x6a, // r14 = add (pc, ##GOTn@PCREL) } # address of GOTn
+ 0x1c, 0xc0, 0x8e, 0x91, // r28 = memw (r14) # contents of GOTn
+ 0x00, 0xc0, 0x9c, 0x52, // jumpr r28 # call it
+};
+
+class HexagonGOTAtom : public GOTAtom {
+public:
+ HexagonGOTAtom(const File &f) : GOTAtom(f, ".got") {}
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return makeArrayRef(hexagonGotAtomContent);
+ }
+
+ Alignment alignment() const override { return Alignment(2); }
+};
+
+class HexagonGOTPLTAtom : public GOTAtom {
+public:
+ HexagonGOTPLTAtom(const File &f) : GOTAtom(f, ".got.plt") {}
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return makeArrayRef(hexagonGotPltAtomContent);
+ }
+
+ Alignment alignment() const override { return Alignment(2); }
+};
+
+class HexagonGOTPLT0Atom : public GOTAtom {
+public:
+ HexagonGOTPLT0Atom(const File &f) : GOTAtom(f, ".got.plt") {}
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return makeArrayRef(hexagonGotPlt0AtomContent);
+ }
+
+ Alignment alignment() const override { return Alignment(3); }
+};
+
+class HexagonPLT0Atom : public PLT0Atom {
+public:
+ HexagonPLT0Atom(const File &f) : PLT0Atom(f) {}
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return makeArrayRef(hexagonPlt0AtomContent);
+ }
+};
+
+class HexagonPLTAtom : public PLTAtom {
+
+public:
+ HexagonPLTAtom(const File &f, StringRef secName) : PLTAtom(f, secName) {}
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return makeArrayRef(hexagonPltAtomContent);
+ }
+};
+
+class ELFPassFile : public SimpleFile {
+public:
+ ELFPassFile(const ELFLinkingContext &eti) : SimpleFile("ELFPassFile") {
+ setOrdinal(eti.getNextOrdinalAndIncrement());
+ }
+
+ llvm::BumpPtrAllocator _alloc;
+};
+
+/// \brief Create GOT and PLT entries for relocations. Handles standard GOT/PLT
+template <class Derived> class GOTPLTPass : public Pass {
+ /// \brief Handle a specific reference.
+ void handleReference(const DefinedAtom &atom, const Reference &ref) {
+ if (ref.kindNamespace() != Reference::KindNamespace::ELF)
+ return;
+ assert(ref.kindArch() == Reference::KindArch::Hexagon);
+ switch (ref.kindValue()) {
+ case R_HEX_PLT_B22_PCREL:
+ case R_HEX_B22_PCREL:
+ static_cast<Derived *>(this)->handlePLT32(ref);
+ break;
+ case R_HEX_GOT_LO16:
+ case R_HEX_GOT_HI16:
+ case R_HEX_GOT_32_6_X:
+ case R_HEX_GOT_16_X:
+ case R_HEX_GOT_11_X:
+ static_cast<Derived *>(this)->handleGOTREL(ref);
+ break;
+ }
+ }
+
+protected:
+ /// \brief Create a GOT entry containing 0.
+ const GOTAtom *getNullGOT() {
+ if (!_null) {
+ _null = new (_file._alloc) HexagonGOTPLTAtom(_file);
+#ifndef NDEBUG
+ _null->_name = "__got_null";
+#endif
+ }
+ return _null;
+ }
+
+public:
+ GOTPLTPass(const ELFLinkingContext &ctx)
+ : _file(ctx), _null(nullptr), _PLT0(nullptr), _got0(nullptr) {}
+
+ /// \brief Do the pass.
+ ///
+ /// The goal here is to first process each reference individually. Each call
+ /// to handleReference may modify the reference itself and/or create new
+ /// atoms which must be stored in one of the maps below.
+ ///
+ /// After all references are handled, the atoms created during that are all
+ /// added to mf.
+ void perform(std::unique_ptr<MutableFile> &mf) override {
+ // Process all references.
+ for (const auto &atom : mf->defined())
+ for (const auto &ref : *atom)
+ handleReference(*atom, *ref);
+
+ // Add all created atoms to the link.
+ uint64_t ordinal = 0;
+ if (_PLT0) {
+ _PLT0->setOrdinal(ordinal++);
+ mf->addAtom(*_PLT0);
+ }
+ for (auto &plt : _pltVector) {
+ plt->setOrdinal(ordinal++);
+ mf->addAtom(*plt);
+ }
+ if (_null) {
+ _null->setOrdinal(ordinal++);
+ mf->addAtom(*_null);
+ }
+ if (_got0) {
+ _got0->setOrdinal(ordinal++);
+ mf->addAtom(*_got0);
+ }
+ for (auto &got : _gotVector) {
+ got->setOrdinal(ordinal++);
+ mf->addAtom(*got);
+ }
+ }
+
+protected:
+ /// \brief Owner of all the Atoms created by this pass.
+ ELFPassFile _file;
+
+ /// \brief Map Atoms to their GOT entries.
+ llvm::DenseMap<const Atom *, GOTAtom *> _gotMap;
+
+ /// \brief Map Atoms to their PLT entries.
+ llvm::DenseMap<const Atom *, PLTAtom *> _pltMap;
+
+ /// \brief the list of GOT/PLT atoms
+ std::vector<GOTAtom *> _gotVector;
+ std::vector<PLTAtom *> _pltVector;
+
+ /// \brief GOT entry that is always 0. Used for undefined weaks.
+ GOTAtom *_null;
+
+ /// \brief The got and plt entries for .PLT0. This is used to call into the
+ /// dynamic linker for symbol resolution.
+ /// @{
+ PLT0Atom *_PLT0;
+ GOTAtom *_got0;
+ /// @}
+};
+
+class DynamicGOTPLTPass final : public GOTPLTPass<DynamicGOTPLTPass> {
+public:
+ DynamicGOTPLTPass(const elf::HexagonLinkingContext &ctx) : GOTPLTPass(ctx) {
+ _got0 = new (_file._alloc) HexagonGOTPLT0Atom(_file);
+#ifndef NDEBUG
+ _got0->_name = "__got0";
+#endif
+ }
+
+ const PLT0Atom *getPLT0() {
+ if (_PLT0)
+ return _PLT0;
+ _PLT0 = new (_file._alloc) HexagonPLT0Atom(_file);
+ _PLT0->addReferenceELF_Hexagon(R_HEX_B32_PCREL_X, 0, _got0, 0);
+ _PLT0->addReferenceELF_Hexagon(R_HEX_6_PCREL_X, 4, _got0, 4);
+ DEBUG_WITH_TYPE("PLT", llvm::dbgs() << "[ PLT0/GOT0 ] "
+ << "Adding plt0/got0 \n");
+ return _PLT0;
+ }
+
+ const PLTAtom *getPLTEntry(const Atom *a) {
+ auto plt = _pltMap.find(a);
+ if (plt != _pltMap.end())
+ return plt->second;
+ auto ga = new (_file._alloc) HexagonGOTPLTAtom(_file);
+ ga->addReferenceELF_Hexagon(R_HEX_JMP_SLOT, 0, a, 0);
+ auto pa = new (_file._alloc) HexagonPLTAtom(_file, ".plt");
+ pa->addReferenceELF_Hexagon(R_HEX_B32_PCREL_X, 0, ga, 0);
+ pa->addReferenceELF_Hexagon(R_HEX_6_PCREL_X, 4, ga, 4);
+
+ // Point the got entry to the PLT0 atom initially
+ ga->addReferenceELF_Hexagon(R_HEX_32, 0, getPLT0(), 0);
+#ifndef NDEBUG
+ ga->_name = "__got_";
+ ga->_name += a->name();
+ pa->_name = "__plt_";
+ pa->_name += a->name();
+ DEBUG_WITH_TYPE("PLT", llvm::dbgs() << "[" << a->name() << "] "
+ << "Adding plt/got: " << pa->_name
+ << "/" << ga->_name << "\n");
+#endif
+ _gotMap[a] = ga;
+ _pltMap[a] = pa;
+ _gotVector.push_back(ga);
+ _pltVector.push_back(pa);
+ return pa;
+ }
+
+ const GOTAtom *getGOTEntry(const Atom *a) {
+ auto got = _gotMap.find(a);
+ if (got != _gotMap.end())
+ return got->second;
+ auto ga = new (_file._alloc) HexagonGOTAtom(_file);
+ ga->addReferenceELF_Hexagon(R_HEX_GLOB_DAT, 0, a, 0);
+
+#ifndef NDEBUG
+ ga->_name = "__got_";
+ ga->_name += a->name();
+ DEBUG_WITH_TYPE("GOT", llvm::dbgs() << "[" << a->name() << "] "
+ << "Adding got: " << ga->_name << "\n");
+#endif
+ _gotMap[a] = ga;
+ _gotVector.push_back(ga);
+ return ga;
+ }
+
+ std::error_code handleGOTREL(const Reference &ref) {
+ // Turn this so that the target is set to the GOT entry
+ const_cast<Reference &>(ref).setTarget(getGOTEntry(ref.target()));
+ return std::error_code();
+ }
+
+ std::error_code handlePLT32(const Reference &ref) {
+ // Turn this into a PC32 to the PLT entry.
+ assert(ref.kindNamespace() == Reference::KindNamespace::ELF);
+ assert(ref.kindArch() == Reference::KindArch::Hexagon);
+ const_cast<Reference &>(ref).setKindValue(R_HEX_B22_PCREL);
+ const_cast<Reference &>(ref).setTarget(getPLTEntry(ref.target()));
+ return std::error_code();
+ }
+};
+
+void elf::HexagonLinkingContext::addPasses(PassManager &pm) {
+ if (isDynamic())
+ pm.add(llvm::make_unique<DynamicGOTPLTPass>(*this));
+ ELFLinkingContext::addPasses(pm);
+}
+
+void HexagonTargetHandler::registerRelocationNames(Registry &registry) {
+ registry.addKindTable(Reference::KindNamespace::ELF,
+ Reference::KindArch::Hexagon, kindStrings);
+}
+
+#define ELF_RELOC(name, value) LLD_KIND_STRING_ENTRY(name),
+
+const Registry::KindStrings HexagonTargetHandler::kindStrings[] = {
+#include "llvm/Support/ELFRelocs/Hexagon.def"
+ LLD_KIND_STRING_END
+};
+
+#undef ELF_RELOC
diff --git a/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.h b/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.h
new file mode 100644
index 000000000000..f4315f710ec7
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.h
@@ -0,0 +1,143 @@
+//===- lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.h ----------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef HEXAGON_TARGET_HANDLER_H
+#define HEXAGON_TARGET_HANDLER_H
+
+#include "DefaultTargetHandler.h"
+#include "HexagonELFReader.h"
+#include "HexagonExecutableAtoms.h"
+#include "HexagonRelocationHandler.h"
+#include "HexagonSectionChunks.h"
+#include "TargetLayout.h"
+
+namespace lld {
+namespace elf {
+class HexagonLinkingContext;
+
+/// \brief TargetLayout for Hexagon
+template <class HexagonELFType>
+class HexagonTargetLayout final : public TargetLayout<HexagonELFType> {
+public:
+ enum HexagonSectionOrder {
+ ORDER_SDATA = 205
+ };
+
+ HexagonTargetLayout(HexagonLinkingContext &hti)
+ : TargetLayout<HexagonELFType>(hti), _sdataSection(nullptr),
+ _gotSymAtom(nullptr), _cachedGotSymAtom(false) {
+ _sdataSection = new (_alloc) SDataSection<HexagonELFType>(hti);
+ }
+
+ /// \brief Return the section order for a input section
+ virtual Layout::SectionOrder getSectionOrder(
+ StringRef name, int32_t contentType, int32_t contentPermissions) {
+ if ((contentType == DefinedAtom::typeDataFast) ||
+ (contentType == DefinedAtom::typeZeroFillFast))
+ return ORDER_SDATA;
+
+ return DefaultLayout<HexagonELFType>::getSectionOrder(name, contentType,
+ contentPermissions);
+ }
+
+ /// \brief Return the appropriate input section name.
+ virtual StringRef getInputSectionName(const DefinedAtom *da) const {
+ switch (da->contentType()) {
+ case DefinedAtom::typeDataFast:
+ case DefinedAtom::typeZeroFillFast:
+ return ".sdata";
+ default:
+ break;
+ }
+ return DefaultLayout<HexagonELFType>::getInputSectionName(da);
+ }
+
+ /// \brief Gets or creates a section.
+ virtual AtomSection<HexagonELFType> *
+ createSection(StringRef name, int32_t contentType,
+ DefinedAtom::ContentPermissions contentPermissions,
+ Layout::SectionOrder sectionOrder) {
+ if ((contentType == DefinedAtom::typeDataFast) ||
+ (contentType == DefinedAtom::typeZeroFillFast))
+ return _sdataSection;
+ return DefaultLayout<HexagonELFType>::createSection(
+ name, contentType, contentPermissions, sectionOrder);
+ }
+
+ /// \brief get the segment type for the section thats defined by the target
+ virtual Layout::SegmentType
+ getSegmentType(Section<HexagonELFType> *section) const {
+ if (section->order() == ORDER_SDATA)
+ return PT_LOAD;
+
+ return DefaultLayout<HexagonELFType>::getSegmentType(section);
+ }
+
+ Section<HexagonELFType> *getSDataSection() const {
+ return _sdataSection;
+ }
+
+ uint64_t getGOTSymAddr() {
+ if (!_cachedGotSymAtom) {
+ auto gotAtomIter = this->findAbsoluteAtom("_GLOBAL_OFFSET_TABLE_");
+ _gotSymAtom = (*gotAtomIter);
+ _cachedGotSymAtom = true;
+ }
+ if (_gotSymAtom)
+ return _gotSymAtom->_virtualAddr;
+ return 0;
+ }
+
+private:
+ llvm::BumpPtrAllocator _alloc;
+ SDataSection<HexagonELFType> *_sdataSection;
+ AtomLayout *_gotSymAtom;
+ bool _cachedGotSymAtom;
+};
+
+/// \brief TargetHandler for Hexagon
+class HexagonTargetHandler final :
+ public DefaultTargetHandler<HexagonELFType> {
+public:
+ HexagonTargetHandler(HexagonLinkingContext &targetInfo);
+
+ void registerRelocationNames(Registry &registry) override;
+
+ const HexagonTargetRelocationHandler &getRelocationHandler() const override {
+ return *(_hexagonRelocationHandler.get());
+ }
+
+ HexagonTargetLayout<HexagonELFType> &getTargetLayout() override {
+ return *(_hexagonTargetLayout.get());
+ }
+
+ std::unique_ptr<Reader> getObjReader() override {
+ return std::unique_ptr<Reader>(
+ new HexagonELFObjectReader(_hexagonLinkingContext));
+ }
+
+ std::unique_ptr<Reader> getDSOReader() override {
+ return std::unique_ptr<Reader>(
+ new HexagonELFDSOReader(_hexagonLinkingContext));
+ }
+
+ std::unique_ptr<Writer> getWriter() override;
+
+private:
+ llvm::BumpPtrAllocator _alloc;
+ static const Registry::KindStrings kindStrings[];
+ HexagonLinkingContext &_hexagonLinkingContext;
+ std::unique_ptr<HexagonRuntimeFile<HexagonELFType> > _hexagonRuntimeFile;
+ std::unique_ptr<HexagonTargetLayout<HexagonELFType>> _hexagonTargetLayout;
+ std::unique_ptr<HexagonTargetRelocationHandler> _hexagonRelocationHandler;
+};
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/Hexagon/Makefile b/lib/ReaderWriter/ELF/Hexagon/Makefile
new file mode 100644
index 000000000000..8d6f1a0a3b1e
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Hexagon/Makefile
@@ -0,0 +1,16 @@
+##===- lld/lib/ReaderWriter/ELF/Hexagon/Makefile ----------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLD_LEVEL := ../../../..
+LIBRARYNAME := lldHexagonELFTarget
+USEDLIBS = lldCore.a
+
+CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF/Hexagon -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF
+
+include $(LLD_LEVEL)/Makefile
diff --git a/lib/ReaderWriter/ELF/Layout.h b/lib/ReaderWriter/ELF/Layout.h
new file mode 100644
index 000000000000..826cf5035d59
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Layout.h
@@ -0,0 +1,59 @@
+//===- lib/ReaderWriter/ELF/Layout.h --------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_LAYOUT_H
+#define LLD_READER_WRITER_ELF_LAYOUT_H
+
+#include "lld/Core/DefinedAtom.h"
+#include "lld/ReaderWriter/AtomLayout.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ELF.h"
+#include "llvm/Support/ErrorOr.h"
+
+namespace lld {
+namespace elf {
+
+/// \brief The ELFLayout is an abstract class for managing the final layout for
+/// the kind of binaries(Shared Libraries / Relocatables / Executables 0
+/// Each architecture (Hexagon, MIPS) would have a concrete
+/// subclass derived from Layout for generating each binary thats
+// needed by the lld linker
+class Layout {
+public:
+ typedef uint32_t SectionOrder;
+ typedef uint32_t SegmentType;
+ typedef uint32_t Flags;
+
+public:
+ /// Return the order the section would appear in the output file
+ virtual SectionOrder getSectionOrder(StringRef name, int32_t contentType,
+ int32_t contentPerm) = 0;
+ /// \brief Append the Atom to the layout and create appropriate sections.
+ /// \returns A reference to the atom layout or an error. The atom layout will
+ /// be updated as linking progresses.
+ virtual ErrorOr<const lld::AtomLayout *> addAtom(const Atom *atom) = 0;
+ /// find the Atom in the current layout
+ virtual const AtomLayout *findAtomLayoutByName(StringRef name) const = 0;
+ /// associates a section to a segment
+ virtual void assignSectionsToSegments() = 0;
+ /// associates a virtual address to the segment, section, and the atom
+ virtual void assignVirtualAddress() = 0;
+
+public:
+ Layout() {}
+
+ virtual ~Layout() { }
+};
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/Makefile b/lib/ReaderWriter/ELF/Makefile
new file mode 100644
index 000000000000..5791ecb9733d
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Makefile
@@ -0,0 +1,18 @@
+##===- lld/lib/ReaderWriter/ELF/Makefile --------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLD_LEVEL := ../../..
+LIBRARYNAME := lldELF
+
+CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF
+
+# these link against this lib
+PARALLEL_DIRS := Hexagon X86 X86_64 Mips AArch64 ARM
+
+include $(LLD_LEVEL)/Makefile
diff --git a/lib/ReaderWriter/ELF/Mips/CMakeLists.txt b/lib/ReaderWriter/ELF/Mips/CMakeLists.txt
new file mode 100644
index 000000000000..d982508b7ddc
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/CMakeLists.txt
@@ -0,0 +1,14 @@
+add_llvm_library(lldMipsELFTarget
+ MipsCtorsOrderPass.cpp
+ MipsELFFlagsMerger.cpp
+ MipsLinkingContext.cpp
+ MipsRelocationHandler.cpp
+ MipsRelocationPass.cpp
+ MipsTargetHandler.cpp
+ LINK_LIBS
+ lldELF
+ lldReaderWriter
+ lldCore
+ LLVMObject
+ LLVMSupport
+ )
diff --git a/lib/ReaderWriter/ELF/Mips/Makefile b/lib/ReaderWriter/ELF/Mips/Makefile
new file mode 100644
index 000000000000..0b2f4ff82279
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/Makefile
@@ -0,0 +1,15 @@
+##===- lld/lib/ReaderWriter/ELF/Mips/Makefile ----------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLD_LEVEL := ../../../..
+LIBRARYNAME := lldMipsELFTarget
+USEDLIBS = lldCore.a
+CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF
+
+include $(LLD_LEVEL)/Makefile
diff --git a/lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.cpp b/lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.cpp
new file mode 100644
index 000000000000..8bf80257fc89
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.cpp
@@ -0,0 +1,73 @@
+//===- lib/ReaderWriter/ELF/Mips/Mips/CtorsOrderPass.cpp ------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MipsCtorsOrderPass.h"
+#include <algorithm>
+#include <climits>
+
+using namespace lld;
+using namespace lld::elf;
+
+static bool matchCrtObjName(StringRef objName, StringRef objPath) {
+ if (!objPath.endswith(".o"))
+ return false;
+
+ // check *<objName> case
+ objPath = objPath.drop_back(2);
+ if (objPath.endswith(objName))
+ return true;
+
+ // check *<objName>? case
+ return !objPath.empty() && objPath.drop_back(1).endswith(objName);
+}
+
+static int32_t getSectionPriority(StringRef path, StringRef sectionName) {
+ // Arrange .ctors/.dtors sections in the following order:
+ // .ctors from crtbegin.o or crtbegin?.o
+ // .ctors from regular object files
+ // .ctors.* (sorted) from regular object files
+ // .ctors from crtend.o or crtend?.o
+
+ if (matchCrtObjName("crtbegin", path))
+ return std::numeric_limits<int32_t>::min();
+ if (matchCrtObjName("crtend", path))
+ return std::numeric_limits<int32_t>::max();
+
+ StringRef num = sectionName.drop_front().rsplit('.').second;
+
+ int32_t priority = std::numeric_limits<int32_t>::min() + 1;
+ if (!num.empty())
+ num.getAsInteger(10, priority);
+
+ return priority;
+}
+
+void MipsCtorsOrderPass::perform(std::unique_ptr<MutableFile> &f) {
+ auto definedAtoms = f->definedAtoms();
+
+ auto last = std::stable_partition(definedAtoms.begin(), definedAtoms.end(),
+ [](const DefinedAtom *atom) {
+ if (atom->sectionChoice() != DefinedAtom::sectionCustomRequired)
+ return false;
+
+ StringRef name = atom->customSectionName();
+ return name.startswith(".ctors") || name.startswith(".dtors");
+ });
+
+ std::stable_sort(definedAtoms.begin(), last,
+ [](const DefinedAtom *left, const DefinedAtom *right) {
+ StringRef leftSec = left->customSectionName();
+ StringRef rightSec = right->customSectionName();
+
+ int32_t leftPriority = getSectionPriority(left->file().path(), leftSec);
+ int32_t rightPriority = getSectionPriority(right->file().path(), rightSec);
+
+ return leftPriority < rightPriority;
+ });
+}
diff --git a/lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.h b/lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.h
new file mode 100644
index 000000000000..eeb1a194f9c7
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.h
@@ -0,0 +1,25 @@
+//===- lib/ReaderWriter/ELF/Mips/MipsCtorsOrderPass.h ---------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_CTORS_ORDER_PASS_H
+#define LLD_READER_WRITER_ELF_MIPS_MIPS_CTORS_ORDER_PASS_H
+
+#include "lld/Core/Pass.h"
+
+namespace lld {
+namespace elf {
+/// \brief This pass sorts atoms in .{ctors,dtors}.<priority> sections.
+class MipsCtorsOrderPass : public Pass {
+public:
+ void perform(std::unique_ptr<MutableFile> &mergedFile) override;
+};
+}
+}
+
+#endif
diff --git a/lib/ReaderWriter/ELF/Mips/MipsDynamicLibraryWriter.h b/lib/ReaderWriter/ELF/Mips/MipsDynamicLibraryWriter.h
new file mode 100644
index 000000000000..30b5b0ba6dae
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsDynamicLibraryWriter.h
@@ -0,0 +1,101 @@
+//===- lib/ReaderWriter/ELF/Mips/MipsDynamicLibraryWriter.h ---------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_DYNAMIC_LIBRARY_WRITER_H
+#define LLD_READER_WRITER_ELF_MIPS_MIPS_DYNAMIC_LIBRARY_WRITER_H
+
+#include "DynamicLibraryWriter.h"
+#include "MipsDynamicTable.h"
+#include "MipsELFWriters.h"
+#include "MipsLinkingContext.h"
+
+namespace lld {
+namespace elf {
+
+template <typename ELFT> class MipsSymbolTable;
+template <typename ELFT> class MipsDynamicSymbolTable;
+template <typename ELFT> class MipsTargetLayout;
+
+template <class ELFT>
+class MipsDynamicLibraryWriter : public DynamicLibraryWriter<ELFT> {
+public:
+ MipsDynamicLibraryWriter(MipsLinkingContext &ctx,
+ MipsTargetLayout<ELFT> &layout);
+
+protected:
+ // Add any runtime files and their atoms to the output
+ bool createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
+
+ void finalizeDefaultAtomValues() override;
+
+ std::error_code setELFHeader() override {
+ DynamicLibraryWriter<ELFT>::setELFHeader();
+ _writeHelper.setELFHeader(*this->_elfHeader);
+ return std::error_code();
+ }
+
+ unique_bump_ptr<SymbolTable<ELFT>> createSymbolTable() override;
+ unique_bump_ptr<DynamicTable<ELFT>> createDynamicTable() override;
+
+ unique_bump_ptr<DynamicSymbolTable<ELFT>>
+ createDynamicSymbolTable() override;
+
+private:
+ MipsELFWriter<ELFT> _writeHelper;
+ MipsTargetLayout<ELFT> &_mipsTargetLayout;
+};
+
+template <class ELFT>
+MipsDynamicLibraryWriter<ELFT>::MipsDynamicLibraryWriter(
+ MipsLinkingContext &ctx, MipsTargetLayout<ELFT> &layout)
+ : DynamicLibraryWriter<ELFT>(ctx, layout), _writeHelper(ctx, layout),
+ _mipsTargetLayout(layout) {}
+
+template <class ELFT>
+bool MipsDynamicLibraryWriter<ELFT>::createImplicitFiles(
+ std::vector<std::unique_ptr<File>> &result) {
+ DynamicLibraryWriter<ELFT>::createImplicitFiles(result);
+ result.push_back(std::move(_writeHelper.createRuntimeFile()));
+ return true;
+}
+
+template <class ELFT>
+void MipsDynamicLibraryWriter<ELFT>::finalizeDefaultAtomValues() {
+ // Finalize the atom values that are part of the parent.
+ DynamicLibraryWriter<ELFT>::finalizeDefaultAtomValues();
+ _writeHelper.finalizeMipsRuntimeAtomValues();
+}
+
+template <class ELFT>
+unique_bump_ptr<SymbolTable<ELFT>>
+ MipsDynamicLibraryWriter<ELFT>::createSymbolTable() {
+ return unique_bump_ptr<SymbolTable<ELFT>>(new (
+ this->_alloc) MipsSymbolTable<ELFT>(this->_context));
+}
+
+/// \brief create dynamic table
+template <class ELFT>
+unique_bump_ptr<DynamicTable<ELFT>>
+ MipsDynamicLibraryWriter<ELFT>::createDynamicTable() {
+ return unique_bump_ptr<DynamicTable<ELFT>>(new (
+ this->_alloc) MipsDynamicTable<ELFT>(this->_context, _mipsTargetLayout));
+}
+
+/// \brief create dynamic symbol table
+template <class ELFT>
+unique_bump_ptr<DynamicSymbolTable<ELFT>>
+ MipsDynamicLibraryWriter<ELFT>::createDynamicSymbolTable() {
+ return unique_bump_ptr<DynamicSymbolTable<ELFT>>(
+ new (this->_alloc) MipsDynamicSymbolTable<ELFT>(
+ this->_context, _mipsTargetLayout));
+}
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/Mips/MipsDynamicTable.h b/lib/ReaderWriter/ELF/Mips/MipsDynamicTable.h
new file mode 100644
index 000000000000..2b9562f42b57
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsDynamicTable.h
@@ -0,0 +1,115 @@
+//===- lib/ReaderWriter/ELF/Mips/MipsDynamicTable.h -----------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_DYNAMIC_TABLE_H
+#define LLD_READER_WRITER_ELF_MIPS_MIPS_DYNAMIC_TABLE_H
+
+#include "DefaultLayout.h"
+#include "SectionChunks.h"
+
+namespace lld {
+namespace elf {
+
+template <class ELFType> class MipsTargetLayout;
+
+template <class MipsELFType>
+class MipsDynamicTable : public DynamicTable<MipsELFType> {
+public:
+ MipsDynamicTable(const ELFLinkingContext &ctx,
+ MipsTargetLayout<MipsELFType> &layout)
+ : DynamicTable<MipsELFType>(ctx, layout, ".dynamic",
+ DefaultLayout<MipsELFType>::ORDER_DYNAMIC),
+ _mipsTargetLayout(layout) {}
+
+ void createDefaultEntries() override {
+ DynamicTable<MipsELFType>::createDefaultEntries();
+
+ typename DynamicTable<MipsELFType>::Elf_Dyn dyn;
+
+ // Version id for the Runtime Linker Interface.
+ dyn.d_un.d_val = 1;
+ dyn.d_tag = DT_MIPS_RLD_VERSION;
+ this->addEntry(dyn);
+
+ // MIPS flags.
+ dyn.d_un.d_val = RHF_NOTPOT;
+ dyn.d_tag = DT_MIPS_FLAGS;
+ this->addEntry(dyn);
+
+ // The base address of the segment.
+ dyn.d_un.d_ptr = 0;
+ dyn.d_tag = DT_MIPS_BASE_ADDRESS;
+ _dt_baseaddr = this->addEntry(dyn);
+
+ // Number of local global offset table entries.
+ dyn.d_un.d_val = 0;
+ dyn.d_tag = DT_MIPS_LOCAL_GOTNO;
+ _dt_localgot = this->addEntry(dyn);
+
+ // Number of entries in the .dynsym section.
+ dyn.d_un.d_val = 0;
+ dyn.d_tag = DT_MIPS_SYMTABNO;
+ _dt_symtabno = this->addEntry(dyn);
+
+ // The index of the first dynamic symbol table entry that corresponds
+ // to an entry in the global offset table.
+ dyn.d_un.d_val = 0;
+ dyn.d_tag = DT_MIPS_GOTSYM;
+ _dt_gotsym = this->addEntry(dyn);
+
+ // Address of the .got section.
+ dyn.d_un.d_val = 0;
+ dyn.d_tag = DT_PLTGOT;
+ _dt_pltgot = this->addEntry(dyn);
+ }
+
+ void updateDynamicTable() override {
+ DynamicTable<MipsELFType>::updateDynamicTable();
+
+ // Assign the minimum segment address to the DT_MIPS_BASE_ADDRESS tag.
+ auto baseAddr = std::numeric_limits<uint64_t>::max();
+ for (auto si : _mipsTargetLayout.segments())
+ if (si->segmentType() != llvm::ELF::PT_NULL)
+ baseAddr = std::min(baseAddr, si->virtualAddr());
+ this->_entries[_dt_baseaddr].d_un.d_val = baseAddr;
+
+ auto &got = _mipsTargetLayout.getGOTSection();
+
+ this->_entries[_dt_symtabno].d_un.d_val = this->getSymbolTable()->size();
+ this->_entries[_dt_gotsym].d_un.d_val =
+ this-> getSymbolTable()->size() - got.getGlobalCount();
+ this->_entries[_dt_localgot].d_un.d_val = got.getLocalCount();
+ this->_entries[_dt_pltgot].d_un.d_ptr =
+ _mipsTargetLayout.findOutputSection(".got")->virtualAddr();
+ }
+
+ int64_t getGotPltTag() override { return DT_MIPS_PLTGOT; }
+
+protected:
+ /// \brief Adjust the symbol's value for microMIPS code.
+ uint64_t getAtomVirtualAddress(const AtomLayout *al) const override {
+ if (const auto *da = dyn_cast<DefinedAtom>(al->_atom))
+ if (da->codeModel() == DefinedAtom::codeMipsMicro ||
+ da->codeModel() == DefinedAtom::codeMipsMicroPIC)
+ return al->_virtualAddr | 1;
+ return al->_virtualAddr;
+ }
+
+private:
+ std::size_t _dt_symtabno;
+ std::size_t _dt_localgot;
+ std::size_t _dt_gotsym;
+ std::size_t _dt_pltgot;
+ std::size_t _dt_baseaddr;
+ MipsTargetLayout<MipsELFType> &_mipsTargetLayout;
+};
+
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/Mips/MipsELFFile.h b/lib/ReaderWriter/ELF/Mips/MipsELFFile.h
new file mode 100644
index 000000000000..7381c7e977bf
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsELFFile.h
@@ -0,0 +1,331 @@
+//===- lib/ReaderWriter/ELF/MipsELFFile.h ---------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_ELF_FILE_H
+#define LLD_READER_WRITER_ELF_MIPS_MIPS_ELF_FILE_H
+
+#include "ELFReader.h"
+#include "MipsLinkingContext.h"
+#include "MipsRelocationHandler.h"
+
+namespace llvm {
+namespace object {
+
+template <class ELFT>
+struct Elf_RegInfo;
+
+template <llvm::support::endianness TargetEndianness, std::size_t MaxAlign>
+struct Elf_RegInfo<ELFType<TargetEndianness, MaxAlign, false>> {
+ LLVM_ELF_IMPORT_TYPES(TargetEndianness, MaxAlign, false)
+ Elf_Word ri_gprmask; // bit-mask of used general registers
+ Elf_Word ri_cprmask[4]; // bit-mask of used co-processor registers
+ Elf_Addr ri_gp_value; // gp register value
+};
+
+template <llvm::support::endianness TargetEndianness, std::size_t MaxAlign>
+struct Elf_RegInfo<ELFType<TargetEndianness, MaxAlign, true>> {
+ LLVM_ELF_IMPORT_TYPES(TargetEndianness, MaxAlign, true)
+ Elf_Word ri_gprmask; // bit-mask of used general registers
+ Elf_Word ri_pad; // unused padding field
+ Elf_Word ri_cprmask[4]; // bit-mask of used co-processor registers
+ Elf_Addr ri_gp_value; // gp register value
+};
+
+template <class ELFT> struct Elf_Mips_Options {
+ LLVM_ELF_IMPORT_TYPES(ELFT::TargetEndianness, ELFT::MaxAlignment,
+ ELFT::Is64Bits)
+ uint8_t kind; // Determines interpretation of variable part of descriptor
+ uint8_t size; // Byte size of descriptor, including this header
+ Elf_Half section; // Section header index of section affected,
+ // or 0 for global options
+ Elf_Word info; // Kind-specific information
+};
+
+} // end namespace object.
+} // end namespace llvm.
+
+namespace lld {
+namespace elf {
+
+template <class ELFT> class MipsELFFile;
+
+template <class ELFT>
+class MipsELFDefinedAtom : public ELFDefinedAtom<ELFT> {
+ typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+ typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr;
+
+public:
+ MipsELFDefinedAtom(const MipsELFFile<ELFT> &file, StringRef symbolName,
+ StringRef sectionName, const Elf_Sym *symbol,
+ const Elf_Shdr *section, ArrayRef<uint8_t> contentData,
+ unsigned int referenceStart, unsigned int referenceEnd,
+ std::vector<ELFReference<ELFT> *> &referenceList)
+ : ELFDefinedAtom<ELFT>(file, symbolName, sectionName, symbol, section,
+ contentData, referenceStart, referenceEnd,
+ referenceList) {}
+
+ const MipsELFFile<ELFT>& file() const override {
+ return static_cast<const MipsELFFile<ELFT> &>(this->_owningFile);
+ }
+
+ DefinedAtom::CodeModel codeModel() const override {
+ switch (this->_symbol->st_other & llvm::ELF::STO_MIPS_MIPS16) {
+ case llvm::ELF::STO_MIPS_MIPS16:
+ return DefinedAtom::codeMips16;
+ case llvm::ELF::STO_MIPS_PIC:
+ return DefinedAtom::codeMipsPIC;
+ case llvm::ELF::STO_MIPS_MICROMIPS:
+ return DefinedAtom::codeMipsMicro;
+ case llvm::ELF::STO_MIPS_MICROMIPS | llvm::ELF::STO_MIPS_PIC:
+ return DefinedAtom::codeMipsMicroPIC;
+ default:
+ return DefinedAtom::codeNA;
+ }
+ }
+};
+
+template <class ELFT> class MipsELFReference : public ELFReference<ELFT> {
+ typedef llvm::object::Elf_Rel_Impl<ELFT, false> Elf_Rel;
+ typedef llvm::object::Elf_Rel_Impl<ELFT, true> Elf_Rela;
+
+ static const bool _isMips64EL =
+ ELFT::Is64Bits && ELFT::TargetEndianness == llvm::support::little;
+
+public:
+ MipsELFReference(uint64_t symValue, const Elf_Rela &rel)
+ : ELFReference<ELFT>(
+ &rel, rel.r_offset - symValue, Reference::KindArch::Mips,
+ rel.getType(_isMips64EL) & 0xff, rel.getSymbol(_isMips64EL)),
+ _tag(uint32_t(rel.getType(_isMips64EL)) >> 8) {}
+
+ MipsELFReference(uint64_t symValue, const Elf_Rel &rel)
+ : ELFReference<ELFT>(rel.r_offset - symValue, Reference::KindArch::Mips,
+ rel.getType(_isMips64EL) & 0xff,
+ rel.getSymbol(_isMips64EL)),
+ _tag(uint32_t(rel.getType(_isMips64EL)) >> 8) {}
+
+ uint32_t tag() const override { return _tag; }
+ void setTag(uint32_t tag) { _tag = tag; }
+
+private:
+ uint32_t _tag;
+};
+
+template <class ELFT> class MipsELFFile : public ELFFile<ELFT> {
+public:
+ MipsELFFile(std::unique_ptr<MemoryBuffer> mb, MipsLinkingContext &ctx)
+ : ELFFile<ELFT>(std::move(mb), ctx) {}
+
+ static ErrorOr<std::unique_ptr<MipsELFFile>>
+ create(std::unique_ptr<MemoryBuffer> mb, MipsLinkingContext &ctx) {
+ return std::unique_ptr<MipsELFFile<ELFT>>(
+ new MipsELFFile<ELFT>(std::move(mb), ctx));
+ }
+
+ bool isPIC() const {
+ return this->_objFile->getHeader()->e_flags & llvm::ELF::EF_MIPS_PIC;
+ }
+
+ /// \brief gp register value stored in the .reginfo section.
+ int64_t getGP0() const { return _gp0 ? *_gp0 : 0; }
+
+ /// \brief .tdata section address plus fixed offset.
+ uint64_t getTPOffset() const { return *_tpOff; }
+ uint64_t getDTPOffset() const { return *_dtpOff; }
+
+protected:
+ std::error_code doParse() override {
+ if (std::error_code ec = ELFFile<ELFT>::doParse())
+ return ec;
+ // Retrieve some auxiliary data like GP value, TLS section address etc
+ // from the object file.
+ return readAuxData();
+ }
+
+private:
+ typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+ typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr;
+ typedef llvm::object::Elf_Rel_Impl<ELFT, false> Elf_Rel;
+ typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel_Iter Elf_Rel_Iter;
+ typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela_Iter Elf_Rela_Iter;
+
+ enum { TP_OFFSET = 0x7000, DTP_OFFSET = 0x8000 };
+
+ static const bool _isMips64EL =
+ ELFT::Is64Bits && ELFT::TargetEndianness == llvm::support::little;
+
+ llvm::Optional<int64_t> _gp0;
+ llvm::Optional<uint64_t> _tpOff;
+ llvm::Optional<uint64_t> _dtpOff;
+
+ ErrorOr<ELFDefinedAtom<ELFT> *> handleDefinedSymbol(
+ StringRef symName, StringRef sectionName, const Elf_Sym *sym,
+ const Elf_Shdr *sectionHdr, ArrayRef<uint8_t> contentData,
+ unsigned int referenceStart, unsigned int referenceEnd,
+ std::vector<ELFReference<ELFT> *> &referenceList) override {
+ return new (this->_readerStorage) MipsELFDefinedAtom<ELFT>(
+ *this, symName, sectionName, sym, sectionHdr, contentData,
+ referenceStart, referenceEnd, referenceList);
+ }
+
+ const Elf_Shdr *findSectionByType(uint64_t type) {
+ for (const Elf_Shdr &section : this->_objFile->sections())
+ if (section.sh_type == type)
+ return &section;
+ return nullptr;
+ }
+
+ const Elf_Shdr *findSectionByFlags(uint64_t flags) {
+ for (const Elf_Shdr &section : this->_objFile->sections())
+ if (section.sh_flags & flags)
+ return &section;
+ return nullptr;
+ }
+
+ std::error_code readAuxData() {
+ using namespace llvm::ELF;
+ if (const Elf_Shdr *sec = findSectionByFlags(SHF_TLS)) {
+ _tpOff = sec->sh_addr + TP_OFFSET;
+ _dtpOff = sec->sh_addr + DTP_OFFSET;
+ }
+
+ typedef llvm::object::Elf_RegInfo<ELFT> Elf_RegInfo;
+ typedef llvm::object::Elf_Mips_Options<ELFT> Elf_Mips_Options;
+
+ if (const Elf_Shdr *sec = findSectionByType(SHT_MIPS_OPTIONS)) {
+ auto contents = this->getSectionContents(sec);
+ if (std::error_code ec = contents.getError())
+ return ec;
+
+ ArrayRef<uint8_t> raw = contents.get();
+ while (!raw.empty()) {
+ if (raw.size() < sizeof(Elf_Mips_Options))
+ return make_dynamic_error_code(
+ StringRef("Invalid size of MIPS_OPTIONS section"));
+
+ const auto *opt = reinterpret_cast<const Elf_Mips_Options *>(raw.data());
+ if (opt->kind == ODK_REGINFO) {
+ _gp0 = reinterpret_cast<const Elf_RegInfo *>(opt + 1)->ri_gp_value;
+ break;
+ }
+ raw = raw.slice(opt->size);
+ }
+ } else if (const Elf_Shdr *sec = findSectionByType(SHT_MIPS_REGINFO)) {
+ auto contents = this->getSectionContents(sec);
+ if (std::error_code ec = contents.getError())
+ return ec;
+
+ ArrayRef<uint8_t> raw = contents.get();
+ if (raw.size() != sizeof(Elf_RegInfo))
+ return make_dynamic_error_code(
+ StringRef("Invalid size of MIPS_REGINFO section"));
+
+ _gp0 = reinterpret_cast<const Elf_RegInfo *>(raw.data())->ri_gp_value;
+ }
+ return std::error_code();
+ }
+
+ void createRelocationReferences(const Elf_Sym *symbol,
+ ArrayRef<uint8_t> content,
+ range<Elf_Rela_Iter> rels) override {
+ const auto value = this->getSymbolValue(symbol);
+ for (const auto &rel : rels) {
+ if (rel.r_offset < value || value + content.size() <= rel.r_offset)
+ continue;
+ auto r = new (this->_readerStorage) MipsELFReference<ELFT>(value, rel);
+ this->addReferenceToSymbol(r, symbol);
+ this->_references.push_back(r);
+ }
+ }
+
+ void createRelocationReferences(const Elf_Sym *symbol,
+ ArrayRef<uint8_t> symContent,
+ ArrayRef<uint8_t> secContent,
+ range<Elf_Rel_Iter> rels) override {
+ const auto value = this->getSymbolValue(symbol);
+ for (Elf_Rel_Iter rit = rels.begin(), eit = rels.end(); rit != eit; ++rit) {
+ if (rit->r_offset < value || value + symContent.size() <= rit->r_offset)
+ continue;
+
+ auto r = new (this->_readerStorage) MipsELFReference<ELFT>(value, *rit);
+ this->addReferenceToSymbol(r, symbol);
+ this->_references.push_back(r);
+
+ auto addend = readAddend(*rit, secContent);
+ auto pairRelType = getPairRelocation(*rit);
+ if (pairRelType != llvm::ELF::R_MIPS_NONE) {
+ addend <<= 16;
+ auto mit = findMatchingRelocation(pairRelType, rit, eit);
+ if (mit != eit)
+ addend += int16_t(readAddend(*mit, secContent));
+ else
+ // FIXME (simon): Show detailed warning.
+ llvm::errs() << "lld warning: cannot matching LO16 relocation\n";
+ }
+ this->_references.back()->setAddend(addend);
+ }
+ }
+
+ Reference::Addend readAddend(const Elf_Rel &ri,
+ const ArrayRef<uint8_t> content) const {
+ const auto &rh =
+ this->_ctx.template getTargetHandler<ELFT>().getRelocationHandler();
+ return static_cast<const MipsRelocationHandler &>(rh)
+ .readAddend(getPrimaryType(ri), content.data() + ri.r_offset);
+ }
+
+ uint32_t getPairRelocation(const Elf_Rel &rel) const {
+ switch (getPrimaryType(rel)) {
+ case llvm::ELF::R_MIPS_HI16:
+ return llvm::ELF::R_MIPS_LO16;
+ case llvm::ELF::R_MIPS_PCHI16:
+ return llvm::ELF::R_MIPS_PCLO16;
+ case llvm::ELF::R_MIPS_GOT16:
+ if (isLocalBinding(rel))
+ return llvm::ELF::R_MIPS_LO16;
+ break;
+ case llvm::ELF::R_MICROMIPS_HI16:
+ return llvm::ELF::R_MICROMIPS_LO16;
+ case llvm::ELF::R_MICROMIPS_GOT16:
+ if (isLocalBinding(rel))
+ return llvm::ELF::R_MICROMIPS_LO16;
+ break;
+ default:
+ // Nothing to do.
+ break;
+ }
+ return llvm::ELF::R_MIPS_NONE;
+ }
+
+ Elf_Rel_Iter findMatchingRelocation(uint32_t pairRelType, Elf_Rel_Iter rit,
+ Elf_Rel_Iter eit) const {
+ return std::find_if(rit, eit, [&](const Elf_Rel &rel) {
+ return getPrimaryType(rel) == pairRelType &&
+ rel.getSymbol(_isMips64EL) == rit->getSymbol(_isMips64EL);
+ });
+ }
+
+ static uint8_t getPrimaryType(const Elf_Rel &rel) {
+ return rel.getType(_isMips64EL) & 0xff;
+ }
+ bool isLocalBinding(const Elf_Rel &rel) const {
+ return this->_objFile->getSymbol(rel.getSymbol(_isMips64EL))
+ ->getBinding() == llvm::ELF::STB_LOCAL;
+ }
+};
+
+template <class ELFT> class MipsDynamicFile : public DynamicFile<ELFT> {
+public:
+ MipsDynamicFile(const MipsLinkingContext &context, StringRef name)
+ : DynamicFile<ELFT>(context, name) {}
+};
+
+} // elf
+} // lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/Mips/MipsELFFlagsMerger.cpp b/lib/ReaderWriter/ELF/Mips/MipsELFFlagsMerger.cpp
new file mode 100644
index 000000000000..0ef2c70b8156
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsELFFlagsMerger.cpp
@@ -0,0 +1,149 @@
+//===- lib/ReaderWriter/ELF/MipsELFFlagsMerger.cpp ------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MipsELFFlagsMerger.h"
+#include "lld/Core/Error.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/ELF.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace lld;
+using namespace lld::elf;
+using namespace llvm::ELF;
+
+struct MipsISATreeEdge {
+ unsigned child;
+ unsigned parent;
+};
+
+static MipsISATreeEdge isaTree[] = {
+ // MIPS32R6 and MIPS64R6 are not compatible with other extensions
+
+ // MIPS64 extensions.
+ {EF_MIPS_ARCH_64R2, EF_MIPS_ARCH_64},
+ // MIPS V extensions.
+ {EF_MIPS_ARCH_64, EF_MIPS_ARCH_5},
+ // MIPS IV extensions.
+ {EF_MIPS_ARCH_5, EF_MIPS_ARCH_4},
+ // MIPS III extensions.
+ {EF_MIPS_ARCH_4, EF_MIPS_ARCH_3},
+ // MIPS32 extensions.
+ {EF_MIPS_ARCH_32R2, EF_MIPS_ARCH_32},
+ // MIPS II extensions.
+ {EF_MIPS_ARCH_3, EF_MIPS_ARCH_2},
+ {EF_MIPS_ARCH_32, EF_MIPS_ARCH_2},
+ // MIPS I extensions.
+ {EF_MIPS_ARCH_2, EF_MIPS_ARCH_1},
+};
+
+static bool matchMipsISA(unsigned base, unsigned ext) {
+ if (base == ext)
+ return true;
+ if (base == EF_MIPS_ARCH_32 && matchMipsISA(EF_MIPS_ARCH_64, ext))
+ return true;
+ if (base == EF_MIPS_ARCH_32R2 && matchMipsISA(EF_MIPS_ARCH_64R2, ext))
+ return true;
+ for (const auto &edge : isaTree) {
+ if (ext == edge.child) {
+ ext = edge.parent;
+ if (ext == base)
+ return true;
+ }
+ }
+ return false;
+}
+
+MipsELFFlagsMerger::MipsELFFlagsMerger(bool is64Bits)
+ : _is64Bit(is64Bits), _flags(0) {}
+
+uint32_t MipsELFFlagsMerger::getMergedELFFlags() const { return _flags; }
+
+std::error_code MipsELFFlagsMerger::merge(uint8_t newClass, uint32_t newFlags) {
+ // Check bitness.
+ if (_is64Bit != (newClass == ELFCLASS64))
+ return make_dynamic_error_code(
+ Twine("Bitness is incompatible with that of the selected target"));
+
+ // We support two ABI: O32 and N64. The last one does not have
+ // the corresponding ELF flag.
+ uint32_t inAbi = newFlags & EF_MIPS_ABI;
+ uint32_t supportedAbi = _is64Bit ? 0 : uint32_t(EF_MIPS_ABI_O32);
+ if (inAbi != supportedAbi)
+ return make_dynamic_error_code(Twine("Unsupported ABI"));
+
+ // ... and reduced set of architectures ...
+ uint32_t newArch = newFlags & EF_MIPS_ARCH;
+ switch (newArch) {
+ case EF_MIPS_ARCH_1:
+ case EF_MIPS_ARCH_2:
+ case EF_MIPS_ARCH_3:
+ case EF_MIPS_ARCH_4:
+ case EF_MIPS_ARCH_5:
+ case EF_MIPS_ARCH_32:
+ case EF_MIPS_ARCH_64:
+ case EF_MIPS_ARCH_32R2:
+ case EF_MIPS_ARCH_64R2:
+ case EF_MIPS_ARCH_32R6:
+ case EF_MIPS_ARCH_64R6:
+ break;
+ default:
+ return make_dynamic_error_code(Twine("Unsupported instruction set"));
+ }
+
+ // ... and still do not support MIPS-16 extension.
+ if (newFlags & EF_MIPS_ARCH_ASE_M16)
+ return make_dynamic_error_code(Twine("Unsupported extension: MIPS16"));
+
+ // PIC code is inherently CPIC and may not set CPIC flag explicitly.
+ // Ensure that this flag will exist in the linked file.
+ if (newFlags & EF_MIPS_PIC)
+ newFlags |= EF_MIPS_CPIC;
+
+ std::lock_guard<std::mutex> lock(_mutex);
+
+ // If the old set of flags is empty, use the new one as a result.
+ if (!_flags) {
+ _flags = newFlags;
+ return std::error_code();
+ }
+
+ // Check PIC / CPIC flags compatibility.
+ uint32_t newPic = newFlags & (EF_MIPS_PIC | EF_MIPS_CPIC);
+ uint32_t oldPic = _flags & (EF_MIPS_PIC | EF_MIPS_CPIC);
+
+ if ((newPic != 0) != (oldPic != 0))
+ llvm::errs() << "lld warning: linking abicalls and non-abicalls files\n";
+
+ if (!(newPic & EF_MIPS_PIC))
+ _flags &= ~EF_MIPS_PIC;
+ if (newPic)
+ _flags |= EF_MIPS_CPIC;
+
+ // Check mixing -mnan=2008 / -mnan=legacy modules.
+ if ((newFlags & EF_MIPS_NAN2008) != (_flags & EF_MIPS_NAN2008))
+ return make_dynamic_error_code(
+ Twine("Linking -mnan=2008 and -mnan=legacy modules"));
+
+ // Check ISA compatibility and update the extension flag.
+ uint32_t oldArch = _flags & EF_MIPS_ARCH;
+ if (!matchMipsISA(newArch, oldArch)) {
+ if (!matchMipsISA(oldArch, newArch))
+ return make_dynamic_error_code(
+ Twine("Linking modules with incompatible ISA"));
+ _flags &= ~EF_MIPS_ARCH;
+ _flags |= newArch;
+ }
+
+ _flags |= newFlags & EF_MIPS_NOREORDER;
+ _flags |= newFlags & EF_MIPS_MICROMIPS;
+ _flags |= newFlags & EF_MIPS_NAN2008;
+ _flags |= newFlags & EF_MIPS_32BITMODE;
+
+ return std::error_code();
+}
diff --git a/lib/ReaderWriter/ELF/Mips/MipsELFFlagsMerger.h b/lib/ReaderWriter/ELF/Mips/MipsELFFlagsMerger.h
new file mode 100644
index 000000000000..6ade86f0163c
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsELFFlagsMerger.h
@@ -0,0 +1,36 @@
+//===- lib/ReaderWriter/ELF/MipsELFFlagsMerger.h --------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_ELF_FLAGS_MERGER_H
+#define LLD_READER_WRITER_ELF_MIPS_MIPS_ELF_FLAGS_MERGER_H
+
+#include <mutex>
+#include <system_error>
+
+namespace lld {
+namespace elf {
+
+class MipsELFFlagsMerger {
+public:
+ MipsELFFlagsMerger(bool is64Bits);
+
+ uint32_t getMergedELFFlags() const;
+
+ /// \brief Merge saved ELF header flags and the new set of flags.
+ std::error_code merge(uint8_t newClass, uint32_t newFlags);
+
+private:
+ const bool _is64Bit;
+ std::mutex _mutex;
+ uint32_t _flags;
+};
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/Mips/MipsELFReader.h b/lib/ReaderWriter/ELF/Mips/MipsELFReader.h
new file mode 100644
index 000000000000..8b325b38bb52
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsELFReader.h
@@ -0,0 +1,93 @@
+//===- lib/ReaderWriter/ELF/MipsELFReader.h -------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_ELF_READER_H
+#define LLD_READER_WRITER_ELF_MIPS_MIPS_ELF_READER_H
+
+#include "ELFReader.h"
+#include "MipsELFFile.h"
+#include "MipsELFFlagsMerger.h"
+#include "MipsLinkingContext.h"
+
+namespace lld {
+namespace elf {
+
+struct MipsELFFileCreateTraits {
+ typedef llvm::ErrorOr<std::unique_ptr<lld::File>> result_type;
+
+ template <class ELFT>
+ static result_type create(std::unique_ptr<llvm::MemoryBuffer> mb,
+ MipsLinkingContext &ctx) {
+ return lld::elf::MipsELFFile<ELFT>::create(std::move(mb), ctx);
+ }
+};
+
+struct MipsDynamicFileCreateELFTraits {
+ typedef llvm::ErrorOr<std::unique_ptr<lld::SharedLibraryFile>> result_type;
+
+ template <class ELFT>
+ static result_type create(std::unique_ptr<llvm::MemoryBuffer> mb,
+ MipsLinkingContext &ctx) {
+ return lld::elf::MipsDynamicFile<ELFT>::create(std::move(mb), ctx);
+ }
+};
+
+template <class ELFT>
+class MipsELFObjectReader
+ : public ELFObjectReader<ELFT, MipsELFFileCreateTraits,
+ MipsLinkingContext> {
+ typedef ELFObjectReader<ELFT, MipsELFFileCreateTraits, MipsLinkingContext>
+ BaseReaderType;
+
+public:
+ MipsELFObjectReader(MipsLinkingContext &ctx)
+ : BaseReaderType(ctx, llvm::ELF::EM_MIPS),
+ _flagMerger(ctx.getELFFlagsMerger()) {}
+
+ std::error_code
+ loadFile(std::unique_ptr<MemoryBuffer> mb, const Registry &registry,
+ std::vector<std::unique_ptr<File>> &result) const override {
+ auto &hdr = *this->elfHeader(*mb);
+ if (std::error_code ec = _flagMerger.merge(hdr.getFileClass(), hdr.e_flags))
+ return ec;
+ return BaseReaderType::loadFile(std::move(mb), registry, result);
+ }
+
+private:
+ MipsELFFlagsMerger &_flagMerger;
+};
+
+template <class ELFT>
+class MipsELFDSOReader
+ : public ELFDSOReader<ELFT, MipsDynamicFileCreateELFTraits,
+ MipsLinkingContext> {
+ typedef ELFDSOReader<ELFT, MipsDynamicFileCreateELFTraits, MipsLinkingContext>
+ BaseReaderType;
+
+public:
+ MipsELFDSOReader(MipsLinkingContext &ctx)
+ : BaseReaderType(ctx, llvm::ELF::EM_MIPS),
+ _flagMerger(ctx.getELFFlagsMerger()) {}
+
+ std::error_code
+ loadFile(std::unique_ptr<MemoryBuffer> mb, const Registry &registry,
+ std::vector<std::unique_ptr<File>> &result) const override {
+ auto &hdr = *this->elfHeader(*mb);
+ if (std::error_code ec = _flagMerger.merge(hdr.getFileClass(), hdr.e_flags))
+ return ec;
+ return BaseReaderType::loadFile(std::move(mb), registry, result);
+ }
+
+private:
+ MipsELFFlagsMerger &_flagMerger;
+};
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/Mips/MipsELFWriters.h b/lib/ReaderWriter/ELF/Mips/MipsELFWriters.h
new file mode 100644
index 000000000000..d94dd757a0f3
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsELFWriters.h
@@ -0,0 +1,82 @@
+//===- lib/ReaderWriter/ELF/Mips/MipsELFWriters.h -------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_ELF_WRITERS_H
+#define LLD_READER_WRITER_ELF_MIPS_MIPS_ELF_WRITERS_H
+
+#include "MipsLinkingContext.h"
+#include "OutputELFWriter.h"
+
+namespace lld {
+namespace elf {
+
+template <class ELFT> class MipsRuntimeFile;
+
+template <class ELFT> class MipsTargetLayout;
+
+template <typename ELFT> class MipsELFWriter {
+public:
+ MipsELFWriter(MipsLinkingContext &ctx, MipsTargetLayout<ELFT> &targetLayout)
+ : _ctx(ctx), _targetLayout(targetLayout) {}
+
+ void setELFHeader(ELFHeader<ELFT> &elfHeader) {
+ elfHeader.e_version(1);
+ elfHeader.e_ident(llvm::ELF::EI_VERSION, llvm::ELF::EV_CURRENT);
+ elfHeader.e_ident(llvm::ELF::EI_OSABI, llvm::ELF::ELFOSABI_NONE);
+ if (_targetLayout.findOutputSection(".got.plt"))
+ elfHeader.e_ident(llvm::ELF::EI_ABIVERSION, 1);
+ else
+ elfHeader.e_ident(llvm::ELF::EI_ABIVERSION, 0);
+
+ elfHeader.e_flags(_ctx.getMergedELFFlags());
+ }
+
+ void finalizeMipsRuntimeAtomValues() {
+ if (!_ctx.isDynamic())
+ return;
+
+ auto gotSection = _targetLayout.findOutputSection(".got");
+ auto got = gotSection ? gotSection->virtualAddr() : 0;
+ auto gp = gotSection ? got + _targetLayout.getGPOffset() : 0;
+
+ setAtomValue("_GLOBAL_OFFSET_TABLE_", got);
+ setAtomValue("_gp", gp);
+ setAtomValue("_gp_disp", gp);
+ setAtomValue("__gnu_local_gp", gp);
+ }
+
+ bool hasGlobalGOTEntry(const Atom *a) const {
+ return _targetLayout.getGOTSection().hasGlobalGOTEntry(a);
+ }
+
+ std::unique_ptr<MipsRuntimeFile<ELFT>> createRuntimeFile() {
+ auto file = llvm::make_unique<MipsRuntimeFile<ELFT>>(_ctx);
+ if (_ctx.isDynamic()) {
+ file->addAbsoluteAtom("_GLOBAL_OFFSET_TABLE_");
+ file->addAbsoluteAtom("_gp");
+ file->addAbsoluteAtom("_gp_disp");
+ file->addAbsoluteAtom("__gnu_local_gp");
+ }
+ return file;
+ }
+
+private:
+ MipsLinkingContext &_ctx;
+ MipsTargetLayout<ELFT> &_targetLayout;
+
+ void setAtomValue(StringRef name, uint64_t value) {
+ auto atom = _targetLayout.findAbsoluteAtom(name);
+ assert(atom != _targetLayout.absoluteAtoms().end());
+ (*atom)->_virtualAddr = value;
+ }
+};
+
+} // elf
+} // lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/Mips/MipsExecutableWriter.h b/lib/ReaderWriter/ELF/Mips/MipsExecutableWriter.h
new file mode 100644
index 000000000000..1a85bba3bd0f
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsExecutableWriter.h
@@ -0,0 +1,154 @@
+//===- lib/ReaderWriter/ELF/Mips/MipsExecutableWriter.h -------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_EXECUTABLE_WRITER_H
+#define LLD_READER_WRITER_ELF_MIPS_MIPS_EXECUTABLE_WRITER_H
+
+#include "ExecutableWriter.h"
+#include "MipsDynamicTable.h"
+#include "MipsELFWriters.h"
+#include "MipsLinkingContext.h"
+
+namespace lld {
+namespace elf {
+
+template <typename ELFT> class MipsTargetLayout;
+
+template <class ELFT>
+class MipsExecutableWriter : public ExecutableWriter<ELFT> {
+public:
+ MipsExecutableWriter(MipsLinkingContext &ctx, MipsTargetLayout<ELFT> &layout);
+
+protected:
+ void buildDynamicSymbolTable(const File &file) override;
+
+ // Add any runtime files and their atoms to the output
+ bool createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
+
+ void finalizeDefaultAtomValues() override;
+ std::error_code setELFHeader() override;
+
+ unique_bump_ptr<SymbolTable<ELFT>> createSymbolTable() override;
+ unique_bump_ptr<DynamicTable<ELFT>> createDynamicTable() override;
+
+ unique_bump_ptr<DynamicSymbolTable<ELFT>>
+ createDynamicSymbolTable() override;
+
+private:
+ MipsELFWriter<ELFT> _writeHelper;
+ MipsTargetLayout<ELFT> &_mipsTargetLayout;
+};
+
+template <class ELFT>
+MipsExecutableWriter<ELFT>::MipsExecutableWriter(MipsLinkingContext &ctx,
+ MipsTargetLayout<ELFT> &layout)
+ : ExecutableWriter<ELFT>(ctx, layout), _writeHelper(ctx, layout),
+ _mipsTargetLayout(layout) {}
+
+template <class ELFT>
+std::error_code MipsExecutableWriter<ELFT>::setELFHeader() {
+ std::error_code ec = ExecutableWriter<ELFT>::setELFHeader();
+ if (ec)
+ return ec;
+
+ StringRef entryName = this->_context.entrySymbolName();
+ if (const AtomLayout *al = this->_layout.findAtomLayoutByName(entryName)) {
+ const auto *ea = cast<DefinedAtom>(al->_atom);
+ if (ea->codeModel() == DefinedAtom::codeMipsMicro ||
+ ea->codeModel() == DefinedAtom::codeMipsMicroPIC)
+ // Adjust entry symbol value if this symbol is microMIPS encoded.
+ this->_elfHeader->e_entry(al->_virtualAddr | 1);
+ }
+
+ _writeHelper.setELFHeader(*this->_elfHeader);
+ return std::error_code();
+}
+
+template <class ELFT>
+void MipsExecutableWriter<ELFT>::buildDynamicSymbolTable(const File &file) {
+ // MIPS ABI requires to add to dynsym even undefined symbols
+ // if they have a corresponding entries in a global part of GOT.
+ for (auto sec : this->_layout.sections())
+ if (auto section = dyn_cast<AtomSection<ELFT>>(sec))
+ for (const auto &atom : section->atoms()) {
+ if (_writeHelper.hasGlobalGOTEntry(atom->_atom)) {
+ this->_dynamicSymbolTable->addSymbol(atom->_atom, section->ordinal(),
+ atom->_virtualAddr, atom);
+ continue;
+ }
+
+ const DefinedAtom *da = dyn_cast<const DefinedAtom>(atom->_atom);
+ if (!da)
+ continue;
+
+ if (da->dynamicExport() != DefinedAtom::dynamicExportAlways &&
+ !this->_context.isDynamicallyExportedSymbol(da->name()) &&
+ !(this->_context.shouldExportDynamic() &&
+ da->scope() == Atom::Scope::scopeGlobal))
+ continue;
+
+ this->_dynamicSymbolTable->addSymbol(atom->_atom, section->ordinal(),
+ atom->_virtualAddr, atom);
+ }
+
+ for (const UndefinedAtom *a : file.undefined())
+ // FIXME (simon): Consider to move this check to the
+ // MipsELFUndefinedAtom class method. That allows to
+ // handle more complex coditions in the future.
+ if (_writeHelper.hasGlobalGOTEntry(a))
+ this->_dynamicSymbolTable->addSymbol(a, ELF::SHN_UNDEF);
+
+ // Skip our immediate parent class method
+ // ExecutableWriter<ELFT>::buildDynamicSymbolTable because we replaced it
+ // with our own version. Call OutputELFWriter directly.
+ OutputELFWriter<ELFT>::buildDynamicSymbolTable(file);
+}
+
+template <class ELFT>
+bool MipsExecutableWriter<ELFT>::createImplicitFiles(
+ std::vector<std::unique_ptr<File>> &result) {
+ ExecutableWriter<ELFT>::createImplicitFiles(result);
+ result.push_back(std::move(_writeHelper.createRuntimeFile()));
+ return true;
+}
+
+template <class ELFT>
+void MipsExecutableWriter<ELFT>::finalizeDefaultAtomValues() {
+ // Finalize the atom values that are part of the parent.
+ ExecutableWriter<ELFT>::finalizeDefaultAtomValues();
+ _writeHelper.finalizeMipsRuntimeAtomValues();
+}
+
+template <class ELFT>
+unique_bump_ptr<SymbolTable<ELFT>>
+ MipsExecutableWriter<ELFT>::createSymbolTable() {
+ return unique_bump_ptr<SymbolTable<ELFT>>(new (
+ this->_alloc) MipsSymbolTable<ELFT>(this->_context));
+}
+
+/// \brief create dynamic table
+template <class ELFT>
+unique_bump_ptr<DynamicTable<ELFT>>
+ MipsExecutableWriter<ELFT>::createDynamicTable() {
+ return unique_bump_ptr<DynamicTable<ELFT>>(new (
+ this->_alloc) MipsDynamicTable<ELFT>(this->_context, _mipsTargetLayout));
+}
+
+/// \brief create dynamic symbol table
+template <class ELFT>
+unique_bump_ptr<DynamicSymbolTable<ELFT>>
+ MipsExecutableWriter<ELFT>::createDynamicSymbolTable() {
+ return unique_bump_ptr<DynamicSymbolTable<ELFT>>(
+ new (this->_alloc) MipsDynamicSymbolTable<ELFT>(
+ this->_context, _mipsTargetLayout));
+}
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp b/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp
new file mode 100644
index 000000000000..7bffcbeb5c08
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp
@@ -0,0 +1,115 @@
+//===- lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp -------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Atoms.h"
+#include "MipsCtorsOrderPass.h"
+#include "MipsLinkingContext.h"
+#include "MipsRelocationPass.h"
+#include "MipsTargetHandler.h"
+
+using namespace lld;
+using namespace lld::elf;
+
+std::unique_ptr<ELFLinkingContext>
+MipsLinkingContext::create(llvm::Triple triple) {
+ if (triple.getArch() == llvm::Triple::mipsel ||
+ triple.getArch() == llvm::Triple::mips64el)
+ return std::unique_ptr<ELFLinkingContext>(new MipsLinkingContext(triple));
+ return nullptr;
+}
+
+typedef std::unique_ptr<TargetHandlerBase> TargetHandlerBasePtr;
+
+static TargetHandlerBasePtr createTarget(llvm::Triple triple,
+ MipsLinkingContext &ctx) {
+ switch (triple.getArch()) {
+ case llvm::Triple::mipsel:
+ return TargetHandlerBasePtr(new MipsTargetHandler<Mips32ELType>(ctx));
+ case llvm::Triple::mips64el:
+ return TargetHandlerBasePtr(new MipsTargetHandler<Mips64ELType>(ctx));
+ default:
+ llvm_unreachable("Unhandled arch");
+ }
+}
+
+MipsLinkingContext::MipsLinkingContext(llvm::Triple triple)
+ : ELFLinkingContext(triple, createTarget(triple, *this)),
+ _flagsMerger(triple.isArch64Bit()) {}
+
+uint32_t MipsLinkingContext::getMergedELFFlags() const {
+ return _flagsMerger.getMergedELFFlags();
+}
+
+MipsELFFlagsMerger &MipsLinkingContext::getELFFlagsMerger() {
+ return _flagsMerger;
+}
+
+uint64_t MipsLinkingContext::getBaseAddress() const {
+ if (_baseAddress == 0 && getOutputELFType() == llvm::ELF::ET_EXEC)
+ return getTriple().isArch64Bit() ? 0x120000000 : 0x400000;
+ return _baseAddress;
+}
+
+StringRef MipsLinkingContext::entrySymbolName() const {
+ if (_outputELFType == elf::ET_EXEC && _entrySymbolName.empty())
+ return "__start";
+ return _entrySymbolName;
+}
+
+StringRef MipsLinkingContext::getDefaultInterpreter() const {
+ return getTriple().isArch64Bit() ? "/lib64/ld.so.1" : "/lib/ld.so.1";
+}
+
+void MipsLinkingContext::addPasses(PassManager &pm) {
+ auto pass = createMipsRelocationPass(*this);
+ if (pass)
+ pm.add(std::move(pass));
+ ELFLinkingContext::addPasses(pm);
+ pm.add(llvm::make_unique<elf::MipsCtorsOrderPass>());
+}
+
+bool MipsLinkingContext::isDynamicRelocation(const Reference &r) const {
+ if (r.kindNamespace() != Reference::KindNamespace::ELF)
+ return false;
+ assert(r.kindArch() == Reference::KindArch::Mips);
+ switch (r.kindValue()) {
+ case llvm::ELF::R_MIPS_COPY:
+ case llvm::ELF::R_MIPS_REL32:
+ case llvm::ELF::R_MIPS_TLS_DTPMOD32:
+ case llvm::ELF::R_MIPS_TLS_DTPREL32:
+ case llvm::ELF::R_MIPS_TLS_TPREL32:
+ case llvm::ELF::R_MIPS_TLS_DTPMOD64:
+ case llvm::ELF::R_MIPS_TLS_DTPREL64:
+ case llvm::ELF::R_MIPS_TLS_TPREL64:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool MipsLinkingContext::isCopyRelocation(const Reference &r) const {
+ if (r.kindNamespace() != Reference::KindNamespace::ELF)
+ return false;
+ assert(r.kindArch() == Reference::KindArch::Mips);
+ if (r.kindValue() == llvm::ELF::R_MIPS_COPY)
+ return true;
+ return false;
+}
+
+bool MipsLinkingContext::isPLTRelocation(const Reference &r) const {
+ if (r.kindNamespace() != Reference::KindNamespace::ELF)
+ return false;
+ assert(r.kindArch() == Reference::KindArch::Mips);
+ switch (r.kindValue()) {
+ case llvm::ELF::R_MIPS_JUMP_SLOT:
+ return true;
+ default:
+ return false;
+ }
+}
diff --git a/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h b/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h
new file mode 100644
index 000000000000..824605f5fa7f
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h
@@ -0,0 +1,68 @@
+//===- lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h ---------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_LINKING_CONTEXT_H
+#define LLD_READER_WRITER_ELF_MIPS_MIPS_LINKING_CONTEXT_H
+
+#include "MipsELFFlagsMerger.h"
+#include "lld/ReaderWriter/ELFLinkingContext.h"
+
+namespace lld {
+namespace elf {
+
+/// \brief Mips internal references.
+enum {
+ /// \brief Do nothing but mark GOT entry as a global one.
+ LLD_R_MIPS_GLOBAL_GOT = 1024,
+ /// \brief Apply high 16 bits of symbol + addend.
+ LLD_R_MIPS_32_HI16 = 1025,
+ /// \brief The same as R_MIPS_26 but for global symbols.
+ LLD_R_MIPS_GLOBAL_26 = 1026,
+ /// \brief Setup hi 16 bits using the symbol this reference refers to.
+ LLD_R_MIPS_HI16 = 1027,
+ /// \brief Setup low 16 bits using the symbol this reference refers to.
+ LLD_R_MIPS_LO16 = 1028,
+ /// \brief Represents a reference between PLT and dynamic symbol.
+ LLD_R_MIPS_STO_PLT = 1029,
+ /// \brief The same as R_MICROMIPS_26_S1 but for global symbols.
+ LLD_R_MICROMIPS_GLOBAL_26_S1 = 1030,
+ /// \brief Apply high 32+16 bits of symbol + addend.
+ LLD_R_MIPS_64_HI16 = 1031,
+};
+
+typedef llvm::object::ELFType<llvm::support::little, 2, false> Mips32ELType;
+typedef llvm::object::ELFType<llvm::support::little, 2, true> Mips64ELType;
+typedef llvm::object::ELFType<llvm::support::big, 2, false> Mips32BEType;
+typedef llvm::object::ELFType<llvm::support::big, 2, true> Mips64BEType;
+
+class MipsLinkingContext final : public ELFLinkingContext {
+public:
+ static std::unique_ptr<ELFLinkingContext> create(llvm::Triple);
+ MipsLinkingContext(llvm::Triple triple);
+
+ uint32_t getMergedELFFlags() const;
+ MipsELFFlagsMerger &getELFFlagsMerger();
+
+ // ELFLinkingContext
+ uint64_t getBaseAddress() const override;
+ StringRef entrySymbolName() const override;
+ StringRef getDefaultInterpreter() const override;
+ void addPasses(PassManager &pm) override;
+ bool isRelaOutputFormat() const override { return false; }
+ bool isDynamicRelocation(const Reference &r) const override;
+ bool isCopyRelocation(const Reference &r) const override;
+ bool isPLTRelocation(const Reference &r) const override;
+
+private:
+ MipsELFFlagsMerger _flagsMerger;
+};
+
+} // elf
+} // lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp b/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp
new file mode 100644
index 000000000000..173ce0e6b1a8
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp
@@ -0,0 +1,606 @@
+//===- lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp ----------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MipsTargetHandler.h"
+#include "MipsLinkingContext.h"
+#include "MipsRelocationHandler.h"
+
+using namespace lld;
+using namespace elf;
+using namespace llvm::ELF;
+using namespace llvm::support;
+
+namespace {
+enum class CrossJumpMode {
+ None, // Not a jump or non-isa-cross jump
+ ToRegular, // cross isa jump to regular symbol
+ ToMicro // cross isa jump to microMips symbol
+};
+
+struct MipsRelocationParams {
+ uint8_t _size; // Relocations's size in bytes
+ uint64_t _mask; // Read/write mask of relocation
+ uint8_t _shift; // Relocation's addendum left shift size
+ bool _shuffle; // Relocation's addendum/result needs to be shuffled
+};
+
+template <class ELFT> class RelocationHandler : public MipsRelocationHandler {
+public:
+ RelocationHandler(MipsLinkingContext &ctx) : _ctx(ctx) {}
+
+ std::error_code applyRelocation(ELFWriter &writer,
+ llvm::FileOutputBuffer &buf,
+ const lld::AtomLayout &atom,
+ const Reference &ref) const override;
+
+ Reference::Addend readAddend(Reference::KindValue kind,
+ const uint8_t *content) const override;
+
+private:
+ MipsLinkingContext &_ctx;
+};
+}
+
+static MipsRelocationParams getRelocationParams(uint32_t rType) {
+ switch (rType) {
+ case R_MIPS_NONE:
+ return {4, 0x0, 0, false};
+ case R_MIPS_64:
+ case R_MIPS_SUB:
+ return {8, 0xffffffffffffffffull, 0, false};
+ case R_MIPS_32:
+ case R_MIPS_GPREL32:
+ case R_MIPS_PC32:
+ return {4, 0xffffffff, 0, false};
+ case LLD_R_MIPS_32_HI16:
+ return {4, 0xffff0000, 0, false};
+ case LLD_R_MIPS_64_HI16:
+ return {8, 0xffffffffffff0000ull, 0, false};
+ case R_MIPS_26:
+ case LLD_R_MIPS_GLOBAL_26:
+ return {4, 0x3ffffff, 2, false};
+ case R_MIPS_PC18_S3:
+ return {4, 0x3ffff, 3, false};
+ case R_MIPS_PC19_S2:
+ return {4, 0x7ffff, 2, false};
+ case R_MIPS_PC21_S2:
+ return {4, 0x1fffff, 2, false};
+ case R_MIPS_PC26_S2:
+ return {4, 0x3ffffff, 2, false};
+ case R_MIPS_HI16:
+ case R_MIPS_LO16:
+ case R_MIPS_PCHI16:
+ case R_MIPS_PCLO16:
+ case R_MIPS_GPREL16:
+ case R_MIPS_GOT16:
+ case R_MIPS_GOT_DISP:
+ case R_MIPS_GOT_PAGE:
+ case R_MIPS_GOT_OFST:
+ case R_MIPS_TLS_DTPREL_HI16:
+ case R_MIPS_TLS_DTPREL_LO16:
+ case R_MIPS_TLS_TPREL_HI16:
+ case R_MIPS_TLS_TPREL_LO16:
+ case LLD_R_MIPS_HI16:
+ case LLD_R_MIPS_LO16:
+ return {4, 0xffff, 0, false};
+ case R_MICROMIPS_TLS_DTPREL_HI16:
+ case R_MICROMIPS_TLS_DTPREL_LO16:
+ case R_MICROMIPS_TLS_TPREL_HI16:
+ case R_MICROMIPS_TLS_TPREL_LO16:
+ return {4, 0xffff, 0, true};
+ case R_MICROMIPS_26_S1:
+ case LLD_R_MICROMIPS_GLOBAL_26_S1:
+ return {4, 0x3ffffff, 1, true};
+ case R_MICROMIPS_HI16:
+ case R_MICROMIPS_LO16:
+ case R_MICROMIPS_GOT16:
+ return {4, 0xffff, 0, true};
+ case R_MICROMIPS_PC16_S1:
+ return {4, 0xffff, 1, true};
+ case R_MICROMIPS_PC7_S1:
+ return {4, 0x7f, 1, false};
+ case R_MICROMIPS_PC10_S1:
+ return {4, 0x3ff, 1, false};
+ case R_MICROMIPS_PC23_S2:
+ return {4, 0x7fffff, 2, true};
+ case R_MIPS_CALL16:
+ case R_MIPS_TLS_GD:
+ case R_MIPS_TLS_LDM:
+ case R_MIPS_TLS_GOTTPREL:
+ return {4, 0xffff, 0, false};
+ case R_MICROMIPS_CALL16:
+ case R_MICROMIPS_TLS_GD:
+ case R_MICROMIPS_TLS_LDM:
+ case R_MICROMIPS_TLS_GOTTPREL:
+ return {4, 0xffff, 0, true};
+ case R_MIPS_JALR:
+ return {4, 0x0, 0, false};
+ case R_MICROMIPS_JALR:
+ return {4, 0x0, 0, true};
+ case R_MIPS_REL32:
+ case R_MIPS_JUMP_SLOT:
+ case R_MIPS_COPY:
+ case R_MIPS_TLS_DTPMOD32:
+ case R_MIPS_TLS_DTPREL32:
+ case R_MIPS_TLS_TPREL32:
+ // Ignore runtime relocations.
+ return {4, 0x0, 0, false};
+ case R_MIPS_TLS_DTPMOD64:
+ case R_MIPS_TLS_DTPREL64:
+ case R_MIPS_TLS_TPREL64:
+ return {8, 0x0, 0, false};
+ case LLD_R_MIPS_GLOBAL_GOT:
+ case LLD_R_MIPS_STO_PLT:
+ // Do nothing.
+ return {4, 0x0, 0, false};
+ default:
+ llvm_unreachable("Unknown relocation");
+ }
+}
+
+/// \brief R_MIPS_32
+/// local/external: word32 S + A (truncate)
+static uint32_t reloc32(uint64_t S, int64_t A) { return S + A; }
+
+/// \brief R_MIPS_64
+/// local/external: word64 S + A (truncate)
+static uint64_t reloc64(uint64_t S, int64_t A) { return S + A; }
+
+/// \brief R_MIPS_SUB
+/// local/external: word64 S - A (truncate)
+static uint64_t relocSub(uint64_t S, int64_t A) { return S - A; }
+
+/// \brief R_MIPS_PC32
+/// local/external: word32 S + A i- P (truncate)
+static uint32_t relocpc32(uint64_t P, uint64_t S, int64_t A) {
+ return S + A - P;
+}
+
+/// \brief R_MIPS_26, R_MICROMIPS_26_S1
+/// local : ((A | ((P + 4) & 0x3F000000)) + S) >> 2
+static uint32_t reloc26loc(uint64_t P, uint64_t S, int32_t A, uint32_t shift) {
+ uint32_t result = (A | ((P + 4) & (0xfc000000 << shift))) + S;
+ return result >> shift;
+}
+
+/// \brief LLD_R_MIPS_GLOBAL_26, LLD_R_MICROMIPS_GLOBAL_26_S1
+/// external: (sign-extend(A) + S) >> 2
+static uint32_t reloc26ext(uint64_t S, int32_t A, uint32_t shift) {
+ int32_t result =
+ shift == 1 ? llvm::SignExtend32<27>(A) : llvm::SignExtend32<28>(A);
+ return (result + S) >> shift;
+}
+
+/// \brief R_MIPS_HI16, R_MIPS_TLS_DTPREL_HI16, R_MIPS_TLS_TPREL_HI16,
+/// R_MICROMIPS_HI16, R_MICROMIPS_TLS_DTPREL_HI16, R_MICROMIPS_TLS_TPREL_HI16,
+/// LLD_R_MIPS_HI16
+/// local/external: hi16 (AHL + S) - (short)(AHL + S) (truncate)
+/// _gp_disp : hi16 (AHL + GP - P) - (short)(AHL + GP - P) (verify)
+static uint32_t relocHi16(uint64_t P, uint64_t S, int64_t AHL, bool isGPDisp) {
+ int32_t result = isGPDisp ? AHL + S - P : AHL + S;
+ return (result + 0x8000) >> 16;
+}
+
+/// \brief R_MIPS_PCHI16
+/// local/external: hi16 (S + AHL - P)
+static uint32_t relocPcHi16(uint64_t P, uint64_t S, int64_t AHL) {
+ int32_t result = S + AHL - P;
+ return (result + 0x8000) >> 16;
+}
+
+/// \brief R_MIPS_LO16, R_MIPS_TLS_DTPREL_LO16, R_MIPS_TLS_TPREL_LO16,
+/// R_MICROMIPS_LO16, R_MICROMIPS_TLS_DTPREL_LO16, R_MICROMIPS_TLS_TPREL_LO16,
+/// LLD_R_MIPS_LO16
+/// local/external: lo16 AHL + S (truncate)
+/// _gp_disp : lo16 AHL + GP - P + 4 (verify)
+static uint32_t relocLo16(uint64_t P, uint64_t S, int64_t AHL, bool isGPDisp,
+ bool micro) {
+ int32_t result = isGPDisp ? AHL + S - P + (micro ? 3 : 4) : AHL + S;
+ return result;
+}
+
+/// \brief R_MIPS_PCLO16
+/// local/external: lo16 (S + AHL - P)
+static uint32_t relocPcLo16(uint64_t P, uint64_t S, int64_t AHL) {
+ AHL = llvm::SignExtend32<16>(AHL);
+ int32_t result = S + AHL - P;
+ return result;
+}
+
+/// \brief R_MIPS_GOT16, R_MIPS_CALL16, R_MICROMIPS_GOT16, R_MICROMIPS_CALL16
+/// rel16 G (verify)
+static uint64_t relocGOT(uint64_t S, uint64_t GP) {
+ int64_t G = (int64_t)(S - GP);
+ return G;
+}
+
+/// R_MIPS_GOT_OFST
+/// rel16 offset of (S+A) from the page pointer (verify)
+static uint32_t relocGOTOfst(uint64_t S, int64_t A) {
+ uint64_t page = (S + A + 0x8000) & ~0xffff;
+ return S + A - page;
+}
+
+/// \brief R_MIPS_GPREL16
+/// local: sign-extend(A) + S + GP0 - GP
+/// external: sign-extend(A) + S - GP
+static uint64_t relocGPRel16(uint64_t S, int64_t A, uint64_t GP) {
+ // We added GP0 to addendum for a local symbol during a Relocation pass.
+ return llvm::SignExtend32<16>(A) + S - GP;
+}
+
+/// \brief R_MIPS_GPREL32
+/// local: rel32 A + S + GP0 - GP (truncate)
+static uint64_t relocGPRel32(uint64_t S, int64_t A, uint64_t GP) {
+ // We added GP0 to addendum for a local symbol during a Relocation pass.
+ return A + S - GP;
+}
+
+/// \brief R_MIPS_PC18_S3
+/// local/external: (S + A - P) >> 3 (P with cleared 3 less significant bits)
+static uint32_t relocPc18(uint64_t P, uint64_t S, int64_t A) {
+ A = llvm::SignExtend32<21>(A);
+ // FIXME (simon): Check that S + A has 8-byte alignment
+ int32_t result = S + A - ((P | 7) ^ 7);
+ return result >> 3;
+}
+
+/// \brief R_MIPS_PC19_S2
+/// local/external: (S + A - P) >> 2
+static uint32_t relocPc19(uint64_t P, uint64_t S, int64_t A) {
+ A = llvm::SignExtend32<21>(A);
+ // FIXME (simon): Check that S + A has 4-byte alignment
+ int32_t result = S + A - P;
+ return result >> 2;
+}
+
+/// \brief R_MIPS_PC21_S2
+/// local/external: (S + A - P) >> 2
+static uint32_t relocPc21(uint64_t P, uint64_t S, int64_t A) {
+ A = llvm::SignExtend32<23>(A);
+ // FIXME (simon): Check that S + A has 4-byte alignment
+ int32_t result = S + A - P;
+ return result >> 2;
+}
+
+/// \brief R_MIPS_PC26_S2
+/// local/external: (S + A - P) >> 2
+static uint32_t relocPc26(uint64_t P, uint64_t S, int64_t A) {
+ A = llvm::SignExtend32<28>(A);
+ // FIXME (simon): Check that S + A has 4-byte alignment
+ int32_t result = S + A - P;
+ return result >> 2;
+}
+
+/// \brief R_MICROMIPS_PC7_S1
+static uint32_t relocPc7(uint64_t P, uint64_t S, int64_t A) {
+ A = llvm::SignExtend32<8>(A);
+ int32_t result = S + A - P;
+ return result >> 1;
+}
+
+/// \brief R_MICROMIPS_PC10_S1
+static uint32_t relocPc10(uint64_t P, uint64_t S, int64_t A) {
+ A = llvm::SignExtend32<11>(A);
+ int32_t result = S + A - P;
+ return result >> 1;
+}
+
+/// \brief R_MICROMIPS_PC16_S1
+static uint32_t relocPc16(uint64_t P, uint64_t S, int64_t A) {
+ A = llvm::SignExtend32<17>(A);
+ int32_t result = S + A - P;
+ return result >> 1;
+}
+
+/// \brief R_MICROMIPS_PC23_S2
+static uint32_t relocPc23(uint64_t P, uint64_t S, int64_t A) {
+ A = llvm::SignExtend32<25>(A);
+ int32_t result = S + A - P;
+
+ // Check addiupc 16MB range.
+ if (result + 0x1000000 >= 0x2000000)
+ llvm::errs() << "The addiupc instruction immediate "
+ << llvm::format_hex(result, 10) << " is out of range.\n";
+
+ return result >> 2;
+}
+
+/// \brief LLD_R_MIPS_32_HI16, LLD_R_MIPS_64_HI16
+static uint64_t relocMaskLow16(uint64_t S, int64_t A) {
+ return S + A + 0x8000;
+}
+
+static std::error_code adjustJumpOpCode(uint64_t &ins, uint64_t tgt,
+ CrossJumpMode mode) {
+ if (mode == CrossJumpMode::None)
+ return std::error_code();
+
+ bool toMicro = mode == CrossJumpMode::ToMicro;
+ uint32_t opNative = toMicro ? 0x03 : 0x3d;
+ uint32_t opCross = toMicro ? 0x1d : 0x3c;
+
+ if ((tgt & 1) != toMicro)
+ return make_dynamic_error_code(
+ Twine("Incorrect bit 0 for the jalx target"));
+
+ if (tgt & 2)
+ return make_dynamic_error_code(Twine("The jalx target 0x") +
+ Twine::utohexstr(tgt) +
+ " is not word-aligned");
+ uint8_t op = ins >> 26;
+ if (op != opNative && op != opCross)
+ return make_dynamic_error_code(Twine("Unsupported jump opcode (0x") +
+ Twine::utohexstr(op) +
+ ") for ISA modes cross call");
+
+ ins = (ins & ~(0x3f << 26)) | (opCross << 26);
+ return std::error_code();
+}
+
+static bool isMicroMipsAtom(const Atom *a) {
+ if (const auto *da = dyn_cast<DefinedAtom>(a))
+ return da->codeModel() == DefinedAtom::codeMipsMicro ||
+ da->codeModel() == DefinedAtom::codeMipsMicroPIC;
+ return false;
+}
+
+static CrossJumpMode getCrossJumpMode(const Reference &ref) {
+ if (!isa<DefinedAtom>(ref.target()))
+ return CrossJumpMode::None;
+ bool isTgtMicro = isMicroMipsAtom(ref.target());
+ switch (ref.kindValue()) {
+ case R_MIPS_26:
+ case LLD_R_MIPS_GLOBAL_26:
+ return isTgtMicro ? CrossJumpMode::ToMicro : CrossJumpMode::None;
+ case R_MICROMIPS_26_S1:
+ case LLD_R_MICROMIPS_GLOBAL_26_S1:
+ return isTgtMicro ? CrossJumpMode::None : CrossJumpMode::ToRegular;
+ default:
+ return CrossJumpMode::None;
+ }
+}
+
+static uint32_t microShuffle(uint32_t ins) {
+ return ((ins & 0xffff) << 16) | ((ins & 0xffff0000) >> 16);
+}
+
+static ErrorOr<uint64_t> calculateRelocation(Reference::KindValue kind,
+ Reference::Addend addend,
+ uint64_t tgtAddr, uint64_t relAddr,
+ uint64_t gpAddr, bool isGP,
+ CrossJumpMode jumpMode) {
+ bool isCrossJump = jumpMode != CrossJumpMode::None;
+ switch (kind) {
+ case R_MIPS_NONE:
+ return 0;
+ case R_MIPS_32:
+ return reloc32(tgtAddr, addend);
+ case R_MIPS_64:
+ return reloc64(tgtAddr, addend);
+ case R_MIPS_SUB:
+ return relocSub(tgtAddr, addend);
+ case R_MIPS_26:
+ return reloc26loc(relAddr, tgtAddr, addend, 2);
+ case R_MICROMIPS_26_S1:
+ return reloc26loc(relAddr, tgtAddr, addend, isCrossJump ? 2 : 1);
+ case R_MIPS_HI16:
+ case R_MICROMIPS_HI16:
+ return relocHi16(relAddr, tgtAddr, addend, isGP);
+ case R_MIPS_PCHI16:
+ return relocPcHi16(relAddr, tgtAddr, addend);
+ case R_MIPS_LO16:
+ return relocLo16(relAddr, tgtAddr, addend, isGP, false);
+ case R_MIPS_PCLO16:
+ return relocPcLo16(relAddr, tgtAddr, addend);
+ case R_MICROMIPS_LO16:
+ return relocLo16(relAddr, tgtAddr, addend, isGP, true);
+ case R_MIPS_GOT16:
+ case R_MIPS_CALL16:
+ case R_MIPS_GOT_DISP:
+ case R_MIPS_GOT_PAGE:
+ case R_MICROMIPS_GOT16:
+ case R_MICROMIPS_CALL16:
+ case R_MIPS_TLS_GD:
+ case R_MIPS_TLS_LDM:
+ case R_MIPS_TLS_GOTTPREL:
+ case R_MICROMIPS_TLS_GD:
+ case R_MICROMIPS_TLS_LDM:
+ case R_MICROMIPS_TLS_GOTTPREL:
+ return relocGOT(tgtAddr, gpAddr);
+ case R_MIPS_GOT_OFST:
+ return relocGOTOfst(tgtAddr, addend);
+ case R_MIPS_PC18_S3:
+ return relocPc18(relAddr, tgtAddr, addend);
+ case R_MIPS_PC19_S2:
+ return relocPc19(relAddr, tgtAddr, addend);
+ case R_MIPS_PC21_S2:
+ return relocPc21(relAddr, tgtAddr, addend);
+ case R_MIPS_PC26_S2:
+ return relocPc26(relAddr, tgtAddr, addend);
+ case R_MICROMIPS_PC7_S1:
+ return relocPc7(relAddr, tgtAddr, addend);
+ case R_MICROMIPS_PC10_S1:
+ return relocPc10(relAddr, tgtAddr, addend);
+ case R_MICROMIPS_PC16_S1:
+ return relocPc16(relAddr, tgtAddr, addend);
+ case R_MICROMIPS_PC23_S2:
+ return relocPc23(relAddr, tgtAddr, addend);
+ case R_MIPS_TLS_DTPREL_HI16:
+ case R_MIPS_TLS_TPREL_HI16:
+ case R_MICROMIPS_TLS_DTPREL_HI16:
+ case R_MICROMIPS_TLS_TPREL_HI16:
+ return relocHi16(0, tgtAddr, addend, false);
+ case R_MIPS_TLS_DTPREL_LO16:
+ case R_MIPS_TLS_TPREL_LO16:
+ return relocLo16(0, tgtAddr, addend, false, false);
+ case R_MICROMIPS_TLS_DTPREL_LO16:
+ case R_MICROMIPS_TLS_TPREL_LO16:
+ return relocLo16(0, tgtAddr, addend, false, true);
+ case R_MIPS_GPREL16:
+ return relocGPRel16(tgtAddr, addend, gpAddr);
+ case R_MIPS_GPREL32:
+ return relocGPRel32(tgtAddr, addend, gpAddr);
+ case R_MIPS_JALR:
+ case R_MICROMIPS_JALR:
+ // We do not do JALR optimization now.
+ return 0;
+ case R_MIPS_REL32:
+ case R_MIPS_JUMP_SLOT:
+ case R_MIPS_COPY:
+ case R_MIPS_TLS_DTPMOD32:
+ case R_MIPS_TLS_DTPREL32:
+ case R_MIPS_TLS_TPREL32:
+ case R_MIPS_TLS_DTPMOD64:
+ case R_MIPS_TLS_DTPREL64:
+ case R_MIPS_TLS_TPREL64:
+ // Ignore runtime relocations.
+ return 0;
+ case R_MIPS_PC32:
+ return relocpc32(relAddr, tgtAddr, addend);
+ case LLD_R_MIPS_GLOBAL_GOT:
+ // Do nothing.
+ case LLD_R_MIPS_32_HI16:
+ case LLD_R_MIPS_64_HI16:
+ return relocMaskLow16(tgtAddr, addend);
+ case LLD_R_MIPS_GLOBAL_26:
+ return reloc26ext(tgtAddr, addend, 2);
+ case LLD_R_MICROMIPS_GLOBAL_26_S1:
+ return reloc26ext(tgtAddr, addend, isCrossJump ? 2 : 1);
+ case LLD_R_MIPS_HI16:
+ return relocHi16(0, tgtAddr, 0, false);
+ case LLD_R_MIPS_LO16:
+ return relocLo16(0, tgtAddr, 0, false, false);
+ case LLD_R_MIPS_STO_PLT:
+ // Do nothing.
+ return 0;
+ default:
+ return make_unhandled_reloc_error();
+ }
+}
+
+template <class ELFT>
+static uint64_t relocRead(const MipsRelocationParams &params,
+ const uint8_t *loc) {
+ uint64_t data;
+ switch (params._size) {
+ case 4:
+ data = endian::read<uint32_t, ELFT::TargetEndianness, unaligned>(loc);
+ break;
+ case 8:
+ data = endian::read<uint64_t, ELFT::TargetEndianness, unaligned>(loc);
+ break;
+ default:
+ llvm_unreachable("Unexpected size");
+ }
+ if (params._shuffle)
+ data = microShuffle(data);
+ return data;
+}
+
+template <class ELFT>
+static void relocWrite(uint64_t data, const MipsRelocationParams &params,
+ uint8_t *loc) {
+ if (params._shuffle)
+ data = microShuffle(data);
+ switch (params._size) {
+ case 4:
+ endian::write<uint32_t, ELFT::TargetEndianness, unaligned>(loc, data);
+ break;
+ case 8:
+ endian::write<uint64_t, ELFT::TargetEndianness, unaligned>(loc, data);
+ break;
+ default:
+ llvm_unreachable("Unexpected size");
+ }
+}
+
+template <class ELFT>
+std::error_code RelocationHandler<ELFT>::applyRelocation(
+ ELFWriter &writer, llvm::FileOutputBuffer &buf, const lld::AtomLayout &atom,
+ const Reference &ref) const {
+ if (ref.kindNamespace() != lld::Reference::KindNamespace::ELF)
+ return std::error_code();
+ assert(ref.kindArch() == Reference::KindArch::Mips);
+
+ auto &targetLayout = static_cast<MipsTargetLayout<ELFT> &>(
+ _ctx.getTargetHandler<ELFT>().getTargetLayout());
+
+ AtomLayout *gpAtom = targetLayout.getGP();
+ uint64_t gpAddr = gpAtom ? gpAtom->_virtualAddr : 0;
+
+ AtomLayout *gpDispAtom = targetLayout.getGPDisp();
+ bool isGpDisp = gpDispAtom && ref.target() == gpDispAtom->_atom;
+
+ uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset;
+ uint8_t *location = atomContent + ref.offsetInAtom();
+ uint64_t tgtAddr = writer.addressOfAtom(ref.target());
+ uint64_t relAddr = atom._virtualAddr + ref.offsetInAtom();
+
+ if (isMicroMipsAtom(ref.target()))
+ tgtAddr |= 1;
+
+ CrossJumpMode jumpMode = getCrossJumpMode(ref);
+
+ ErrorOr<uint64_t> res =
+ calculateRelocation(ref.kindValue(), ref.addend(), tgtAddr, relAddr,
+ gpAddr, isGpDisp, jumpMode);
+ if (auto ec = res.getError())
+ return ec;
+
+ Reference::KindValue op = ref.kindValue();
+
+ // FIXME (simon): Handle r_ssym value.
+ for (auto tag = (ref.tag() & 0xffff); tag & 0xff; tag >>= 8) {
+ op = tag & 0xff;
+ res = calculateRelocation(op, *res, 0, relAddr, gpAddr, isGpDisp, jumpMode);
+ if (auto ec = res.getError())
+ return ec;
+ }
+
+ auto params = getRelocationParams(op);
+ uint64_t ins = relocRead<ELFT>(params, location);
+
+ if (auto ec = adjustJumpOpCode(ins, tgtAddr, jumpMode))
+ return ec;
+
+ ins = (ins & ~params._mask) | (*res & params._mask);
+ relocWrite<ELFT>(ins, params, location);
+
+ return std::error_code();
+}
+
+template <class ELFT>
+Reference::Addend
+RelocationHandler<ELFT>::readAddend(Reference::KindValue kind,
+ const uint8_t *content) const {
+ auto params = getRelocationParams(kind);
+ uint64_t ins = relocRead<ELFT>(params, content);
+ return (ins & params._mask) << params._shift;
+}
+
+namespace lld {
+namespace elf {
+
+template <>
+std::unique_ptr<TargetRelocationHandler>
+createMipsRelocationHandler<Mips32ELType>(MipsLinkingContext &ctx) {
+ return std::unique_ptr<TargetRelocationHandler>(
+ new RelocationHandler<Mips32ELType>(ctx));
+}
+
+template <>
+std::unique_ptr<TargetRelocationHandler>
+createMipsRelocationHandler<Mips64ELType>(MipsLinkingContext &ctx) {
+ return std::unique_ptr<TargetRelocationHandler>(
+ new RelocationHandler<Mips64ELType>(ctx));
+}
+
+} // elf
+} // lld
diff --git a/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.h b/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.h
new file mode 100644
index 000000000000..87066b2b5c10
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.h
@@ -0,0 +1,31 @@
+//===- lld/ReaderWriter/ELF/Mips/MipsRelocationHandler.h ------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_RELOCATION_HANDLER_H
+#define LLD_READER_WRITER_ELF_MIPS_MIPS_RELOCATION_HANDLER_H
+
+#include "TargetHandler.h"
+#include "lld/Core/Reference.h"
+
+namespace lld {
+namespace elf {
+
+class MipsRelocationHandler : public TargetRelocationHandler {
+public:
+ virtual Reference::Addend readAddend(Reference::KindValue kind,
+ const uint8_t *content) const = 0;
+};
+
+template <class ELFT>
+std::unique_ptr<TargetRelocationHandler>
+createMipsRelocationHandler(MipsLinkingContext &ctx);
+
+} // elf
+} // lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp b/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp
new file mode 100644
index 000000000000..a1b3530dfcdf
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp
@@ -0,0 +1,1070 @@
+//===- lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp -------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MipsELFFile.h"
+#include "MipsLinkingContext.h"
+#include "MipsRelocationPass.h"
+#include "MipsTargetHandler.h"
+#include "llvm/ADT/DenseSet.h"
+
+using namespace lld;
+using namespace lld::elf;
+using namespace llvm::ELF;
+
+// Lazy resolver
+static const uint8_t mipsGot0AtomContent[] = {
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+// Module pointer
+static const uint8_t mipsGotModulePointerAtomContent[] = {
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x80
+};
+
+// TLS GD Entry
+static const uint8_t mipsGotTlsGdAtomContent[] = {
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+// Regular PLT0 entry
+static const uint8_t mipsPlt0AtomContent[] = {
+ 0x00, 0x00, 0x1c, 0x3c, // lui $28, %hi(&GOTPLT[0])
+ 0x00, 0x00, 0x99, 0x8f, // lw $25, %lo(&GOTPLT[0])($28)
+ 0x00, 0x00, 0x9c, 0x27, // addiu $28, $28, %lo(&GOTPLT[0])
+ 0x23, 0xc0, 0x1c, 0x03, // subu $24, $24, $28
+ 0x21, 0x78, 0xe0, 0x03, // move $15, $31
+ 0x82, 0xc0, 0x18, 0x00, // srl $24, $24, 2
+ 0x09, 0xf8, 0x20, 0x03, // jalr $25
+ 0xfe, 0xff, 0x18, 0x27 // subu $24, $24, 2
+};
+
+// microMIPS PLT0 entry
+static const uint8_t micromipsPlt0AtomContent[] = {
+ 0x80, 0x79, 0x00, 0x00, // addiupc $3, (&GOTPLT[0]) - .
+ 0x23, 0xff, 0x00, 0x00, // lw $25, 0($3)
+ 0x35, 0x05, // subu $2, $2, $3
+ 0x25, 0x25, // srl $2, $2, 2
+ 0x02, 0x33, 0xfe, 0xff, // subu $24, $2, 2
+ 0xff, 0x0d, // move $15, $31
+ 0xf9, 0x45, // jalrs $25
+ 0x83, 0x0f, // move $28, $3
+ 0x00, 0x0c // nop
+};
+
+// Regular PLT entry
+static const uint8_t mipsPltAAtomContent[] = {
+ 0x00, 0x00, 0x0f, 0x3c, // lui $15, %hi(.got.plt entry)
+ 0x00, 0x00, 0xf9, 0x8d, // l[wd] $25, %lo(.got.plt entry)($15)
+ 0x08, 0x00, 0x20, 0x03, // jr $25
+ 0x00, 0x00, 0xf8, 0x25 // addiu $24, $15, %lo(.got.plt entry)
+};
+
+// microMIPS PLT entry
+static const uint8_t micromipsPltAtomContent[] = {
+ 0x00, 0x79, 0x00, 0x00, // addiupc $2, (.got.plt entry) - .
+ 0x22, 0xff, 0x00, 0x00, // lw $25, 0($2)
+ 0x99, 0x45, // jr $25
+ 0x02, 0x0f // move $24, $2
+};
+
+// R6 PLT entry
+static const uint8_t mipsR6PltAAtomContent[] = {
+ 0x00, 0x00, 0x0f, 0x3c, // lui $15, %hi(.got.plt entry)
+ 0x00, 0x00, 0xf9, 0x8d, // l[wd] $25, %lo(.got.plt entry)($15)
+ 0x09, 0x00, 0x20, 0x03, // jr $25
+ 0x00, 0x00, 0xf8, 0x25 // addiu $24, $15, %lo(.got.plt entry)
+};
+
+// LA25 stub entry
+static const uint8_t mipsLA25AtomContent[] = {
+ 0x00, 0x00, 0x19, 0x3c, // lui $25, %hi(func)
+ 0x00, 0x00, 0x00, 0x08, // j func
+ 0x00, 0x00, 0x39, 0x27, // addiu $25, $25, %lo(func)
+ 0x00, 0x00, 0x00, 0x00 // nop
+};
+
+// microMIPS LA25 stub entry
+static const uint8_t micromipsLA25AtomContent[] = {
+ 0xb9, 0x41, 0x00, 0x00, // lui $25, %hi(func)
+ 0x00, 0xd4, 0x00, 0x00, // j func
+ 0x39, 0x33, 0x00, 0x00, // addiu $25, $25, %lo(func)
+ 0x00, 0x00, 0x00, 0x00 // nop
+};
+
+namespace {
+
+/// \brief Abstract base class represent MIPS GOT entries.
+class MipsGOTAtom : public GOTAtom {
+public:
+ MipsGOTAtom(const File &f) : GOTAtom(f, ".got") {}
+
+ Alignment alignment() const override { return Alignment(2); }
+};
+
+/// \brief MIPS GOT entry initialized by zero.
+template <typename ELFT> class GOT0Atom : public MipsGOTAtom {
+public:
+ GOT0Atom(const File &f) : MipsGOTAtom(f) {}
+
+ ArrayRef<uint8_t> rawContent() const override;
+};
+
+template <> ArrayRef<uint8_t> GOT0Atom<Mips32ELType>::rawContent() const {
+ return llvm::makeArrayRef(mipsGot0AtomContent).slice(4);
+}
+template <> ArrayRef<uint8_t> GOT0Atom<Mips64ELType>::rawContent() const {
+ return llvm::makeArrayRef(mipsGot0AtomContent);
+}
+
+/// \brief MIPS GOT entry initialized by zero.
+template <typename ELFT> class GOTModulePointerAtom : public MipsGOTAtom {
+public:
+ GOTModulePointerAtom(const File &f) : MipsGOTAtom(f) {}
+
+ ArrayRef<uint8_t> rawContent() const override;
+};
+
+template <>
+ArrayRef<uint8_t> GOTModulePointerAtom<Mips32ELType>::rawContent() const {
+ return llvm::makeArrayRef(mipsGotModulePointerAtomContent).slice(4);
+}
+template <>
+ArrayRef<uint8_t> GOTModulePointerAtom<Mips64ELType>::rawContent() const {
+ return llvm::makeArrayRef(mipsGotModulePointerAtomContent);
+}
+
+/// \brief MIPS GOT TLS GD entry.
+template <typename ELFT> class GOTTLSGdAtom : public MipsGOTAtom {
+public:
+ GOTTLSGdAtom(const File &f) : MipsGOTAtom(f) {}
+
+ ArrayRef<uint8_t> rawContent() const override;
+};
+
+template <> ArrayRef<uint8_t> GOTTLSGdAtom<Mips32ELType>::rawContent() const {
+ return llvm::makeArrayRef(mipsGotTlsGdAtomContent).slice(8);
+}
+
+template <> ArrayRef<uint8_t> GOTTLSGdAtom<Mips64ELType>::rawContent() const {
+ return llvm::makeArrayRef(mipsGotTlsGdAtomContent);
+}
+
+class GOTPLTAtom : public GOTAtom {
+public:
+ GOTPLTAtom(const File &f) : GOTAtom(f, ".got.plt") {}
+ GOTPLTAtom(const Atom *a, const File &f) : GOTAtom(f, ".got.plt") {
+ // Create dynamic relocation to adjust the .got.plt entry at runtime.
+ addReferenceELF_Mips(R_MIPS_JUMP_SLOT, 0, a, 0);
+ }
+
+ /// Setup reference to assign initial value to the .got.plt entry.
+ void setPLT0(const PLTAtom *plt0) {
+ addReferenceELF_Mips(R_MIPS_32, 0, plt0, 0);
+ }
+
+ Alignment alignment() const override { return Alignment(2); }
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return llvm::makeArrayRef(mipsGot0AtomContent).slice(4);
+ }
+};
+
+class PLT0Atom : public PLTAtom {
+public:
+ PLT0Atom(const Atom *got, const File &f) : PLTAtom(f, ".plt") {
+ // Setup reference to fixup the PLT0 entry.
+ addReferenceELF_Mips(LLD_R_MIPS_HI16, 0, got, 0);
+ addReferenceELF_Mips(LLD_R_MIPS_LO16, 4, got, 0);
+ addReferenceELF_Mips(LLD_R_MIPS_LO16, 8, got, 0);
+ }
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return llvm::makeArrayRef(mipsPlt0AtomContent);
+ }
+};
+
+class PLT0MicroAtom : public PLTAtom {
+public:
+ PLT0MicroAtom(const Atom *got, const File &f) : PLTAtom(f, ".plt") {
+ // Setup reference to fixup the PLT0 entry.
+ addReferenceELF_Mips(R_MICROMIPS_PC23_S2, 0, got, 0);
+ }
+
+ CodeModel codeModel() const override { return codeMipsMicro; }
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return llvm::makeArrayRef(micromipsPlt0AtomContent);
+ }
+};
+
+class PLTAAtom : public PLTAtom {
+public:
+ PLTAAtom(const GOTPLTAtom *got, const File &f) : PLTAtom(f, ".plt") {
+ // Setup reference to fixup the PLT entry.
+ addReferenceELF_Mips(LLD_R_MIPS_HI16, 0, got, 0);
+ addReferenceELF_Mips(LLD_R_MIPS_LO16, 4, got, 0);
+ addReferenceELF_Mips(LLD_R_MIPS_LO16, 12, got, 0);
+ }
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return llvm::makeArrayRef(mipsPltAAtomContent);
+ }
+};
+
+class PLTR6Atom : public PLTAAtom {
+public:
+ PLTR6Atom(const GOTPLTAtom *got, const File &f) : PLTAAtom(got, f) {}
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return llvm::makeArrayRef(mipsR6PltAAtomContent);
+ }
+};
+
+class PLTMicroAtom : public PLTAtom {
+public:
+ PLTMicroAtom(const GOTPLTAtom *got, const File &f) : PLTAtom(f, ".plt") {
+ // Setup reference to fixup the microMIPS PLT entry.
+ addReferenceELF_Mips(R_MICROMIPS_PC23_S2, 0, got, 0);
+ }
+
+ Alignment alignment() const override { return Alignment(1); }
+ CodeModel codeModel() const override { return codeMipsMicro; }
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return llvm::makeArrayRef(micromipsPltAtomContent);
+ }
+};
+
+class LA25Atom : public PLTAtom {
+public:
+ LA25Atom(const File &f) : PLTAtom(f, ".text") {}
+};
+
+class LA25RegAtom : public LA25Atom {
+public:
+ LA25RegAtom(const Atom *a, const File &f) : LA25Atom(f) {
+ // Setup reference to fixup the LA25 stub entry.
+ addReferenceELF_Mips(R_MIPS_HI16, 0, a, 0);
+ addReferenceELF_Mips(R_MIPS_26, 4, a, 0);
+ addReferenceELF_Mips(R_MIPS_LO16, 8, a, 0);
+ }
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return llvm::makeArrayRef(mipsLA25AtomContent);
+ }
+};
+
+class LA25MicroAtom : public LA25Atom {
+public:
+ LA25MicroAtom(const Atom *a, const File &f) : LA25Atom(f) {
+ // Setup reference to fixup the microMIPS LA25 stub entry.
+ addReferenceELF_Mips(R_MICROMIPS_HI16, 0, a, 0);
+ addReferenceELF_Mips(R_MICROMIPS_26_S1, 4, a, 0);
+ addReferenceELF_Mips(R_MICROMIPS_LO16, 8, a, 0);
+ }
+
+ CodeModel codeModel() const override { return codeMipsMicro; }
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return llvm::makeArrayRef(micromipsLA25AtomContent);
+ }
+};
+
+class RelocationPassFile : public SimpleFile {
+public:
+ RelocationPassFile(const ELFLinkingContext &ctx)
+ : SimpleFile("RelocationPassFile") {
+ setOrdinal(ctx.getNextOrdinalAndIncrement());
+ }
+
+ llvm::BumpPtrAllocator _alloc;
+};
+
+template <typename ELFT> class RelocationPass : public Pass {
+public:
+ RelocationPass(MipsLinkingContext &ctx);
+
+ void perform(std::unique_ptr<MutableFile> &mf) override;
+
+private:
+ /// \brief Reference to the linking context.
+ const MipsLinkingContext &_ctx;
+
+ /// \brief Owner of all the Atoms created by this pass.
+ RelocationPassFile _file;
+
+ /// \brief Map Atoms and addend to local GOT entries.
+ typedef std::pair<const Atom *, int64_t> LocalGotMapKeyT;
+ llvm::DenseMap<LocalGotMapKeyT, GOTAtom *> _gotLocalMap;
+ llvm::DenseMap<LocalGotMapKeyT, GOTAtom *> _gotLocalPageMap;
+
+ /// \brief Map Atoms to global GOT entries.
+ llvm::DenseMap<const Atom *, GOTAtom *> _gotGlobalMap;
+
+ /// \brief Map Atoms to TLS GOT entries.
+ llvm::DenseMap<const Atom *, GOTAtom *> _gotTLSMap;
+
+ /// \brief Map Atoms to TLS GD GOT entries.
+ llvm::DenseMap<const Atom *, GOTAtom *> _gotTLSGdMap;
+
+ /// \brief GOT entry for the R_xxxMIPS_TLS_LDM relocations.
+ GOTTLSGdAtom<ELFT> *_gotLDMEntry;
+
+ /// \brief the list of local GOT atoms.
+ std::vector<GOTAtom *> _localGotVector;
+
+ /// \brief the list of global GOT atoms.
+ std::vector<GOTAtom *> _globalGotVector;
+
+ /// \brief the list of TLS GOT atoms.
+ std::vector<GOTAtom *> _tlsGotVector;
+
+ /// \brief Map Atoms to their GOTPLT entries.
+ llvm::DenseMap<const Atom *, GOTPLTAtom *> _gotpltMap;
+
+ /// \brief Map Atoms to their PLT entries.
+ llvm::DenseMap<const Atom *, PLTAAtom *> _pltRegMap;
+ llvm::DenseMap<const Atom *, PLTMicroAtom *> _pltMicroMap;
+
+ /// \brief Map Atoms to their Object entries.
+ llvm::DenseMap<const Atom *, ObjectAtom *> _objectMap;
+
+ /// \brief Map Atoms to their LA25 entries.
+ llvm::DenseMap<const Atom *, LA25RegAtom *> _la25RegMap;
+ llvm::DenseMap<const Atom *, LA25MicroAtom *> _la25MicroMap;
+
+ /// \brief Atoms referenced by static relocations.
+ llvm::DenseSet<const Atom *> _hasStaticRelocations;
+
+ /// \brief Atoms require pointers equality.
+ llvm::DenseSet<const Atom *> _requiresPtrEquality;
+
+ /// \brief References which are candidates for converting
+ /// to the R_MIPS_REL32 relocation.
+ std::vector<Reference *> _rel32Candidates;
+
+ /// \brief the list of PLT atoms.
+ std::vector<PLTAtom *> _pltRegVector;
+ std::vector<PLTAtom *> _pltMicroVector;
+
+ /// \brief the list of GOTPLT atoms.
+ std::vector<GOTPLTAtom *> _gotpltVector;
+
+ /// \brief the list of Object entries.
+ std::vector<ObjectAtom *> _objectVector;
+
+ /// \brief the list of LA25 entries.
+ std::vector<LA25Atom *> _la25Vector;
+
+ /// \brief Handle a specific reference.
+ void handleReference(const MipsELFDefinedAtom<ELFT> &atom, Reference &ref);
+
+ /// \brief Collect information about the reference to use it
+ /// later in the handleReference() routine.
+ void collectReferenceInfo(const MipsELFDefinedAtom<ELFT> &atom,
+ Reference &ref);
+
+ void handlePlain(const MipsELFDefinedAtom<ELFT> &atom, Reference &ref);
+ void handle26(const MipsELFDefinedAtom<ELFT> &atom, Reference &ref);
+ void handleGOT(Reference &ref);
+
+ const GOTAtom *getLocalGOTEntry(const Reference &ref);
+ const GOTAtom *getLocalGOTPageEntry(const Reference &ref);
+ const GOTAtom *getGlobalGOTEntry(const Atom *a);
+ const GOTAtom *getTLSGOTEntry(const Atom *a);
+ const GOTAtom *getTLSGdGOTEntry(const Atom *a);
+ const GOTAtom *getTLSLdmGOTEntry(const Atom *a);
+ const GOTPLTAtom *getGOTPLTEntry(const Atom *a);
+ const PLTAtom *getPLTEntry(const Atom *a);
+ const PLTAtom *getPLTRegEntry(const Atom *a);
+ const PLTAtom *getPLTMicroEntry(const Atom *a);
+ const LA25Atom *getLA25Entry(const Atom *target, bool isMicroMips);
+ const LA25Atom *getLA25RegEntry(const Atom *a);
+ const LA25Atom *getLA25MicroEntry(const Atom *a);
+ const ObjectAtom *getObjectEntry(const SharedLibraryAtom *a);
+
+ PLTAtom *createPLTHeader(bool isMicroMips);
+
+ bool isLocal(const Atom *a) const;
+ bool isLocalCall(const Atom *a) const;
+ bool isDynamic(const Atom *atom) const;
+ bool requireLA25Stub(const Atom *a) const;
+ bool requirePLTEntry(const Atom *a) const;
+ bool requireCopy(const Atom *a) const;
+ bool mightBeDynamic(const MipsELFDefinedAtom<ELFT> &atom,
+ Reference::KindValue refKind) const;
+ bool hasPLTEntry(const Atom *atom) const;
+
+ bool isR6Target() const;
+};
+
+template <typename ELFT>
+RelocationPass<ELFT>::RelocationPass(MipsLinkingContext &ctx)
+ : _ctx(ctx), _file(ctx), _gotLDMEntry(nullptr) {
+ _localGotVector.push_back(new (_file._alloc) GOT0Atom<ELFT>(_file));
+ _localGotVector.push_back(new (_file._alloc)
+ GOTModulePointerAtom<ELFT>(_file));
+}
+
+template <typename ELFT>
+void RelocationPass<ELFT>::perform(std::unique_ptr<MutableFile> &mf) {
+ for (const auto &atom : mf->defined())
+ for (const auto &ref : *atom)
+ collectReferenceInfo(*cast<MipsELFDefinedAtom<ELFT>>(atom),
+ const_cast<Reference &>(*ref));
+
+ // Process all references.
+ for (const auto &atom : mf->defined())
+ for (const auto &ref : *atom)
+ handleReference(*cast<MipsELFDefinedAtom<ELFT>>(atom),
+ const_cast<Reference &>(*ref));
+
+ // Create R_MIPS_REL32 relocations.
+ for (auto *ref : _rel32Candidates) {
+ if (!isDynamic(ref->target()) || hasPLTEntry(ref->target()))
+ continue;
+ ref->setKindValue(R_MIPS_REL32);
+ if (ELFT::Is64Bits)
+ static_cast<MipsELFReference<ELFT> *>(ref)->setTag(R_MIPS_64);
+ if (!isLocalCall(ref->target()))
+ getGlobalGOTEntry(ref->target());
+ }
+
+ uint64_t ordinal = 0;
+
+ for (auto &got : _localGotVector) {
+ got->setOrdinal(ordinal++);
+ mf->addAtom(*got);
+ }
+
+ for (auto &got : _globalGotVector) {
+ got->setOrdinal(ordinal++);
+ mf->addAtom(*got);
+ }
+
+ for (auto &got : _tlsGotVector) {
+ got->setOrdinal(ordinal++);
+ mf->addAtom(*got);
+ }
+
+ // Create and emit PLT0 entry.
+ PLTAtom *plt0Atom = nullptr;
+ if (!_pltRegVector.empty())
+ plt0Atom = createPLTHeader(false);
+ else if (!_pltMicroVector.empty())
+ plt0Atom = createPLTHeader(true);
+
+ if (plt0Atom) {
+ plt0Atom->setOrdinal(ordinal++);
+ mf->addAtom(*plt0Atom);
+ }
+
+ // Emit regular PLT entries firts.
+ for (auto &plt : _pltRegVector) {
+ plt->setOrdinal(ordinal++);
+ mf->addAtom(*plt);
+ }
+
+ // microMIPS PLT entries come after regular ones.
+ for (auto &plt : _pltMicroVector) {
+ plt->setOrdinal(ordinal++);
+ mf->addAtom(*plt);
+ }
+
+ // Assign PLT0 to GOTPLT entries.
+ assert(_gotpltMap.empty() || plt0Atom);
+ for (auto &a: _gotpltMap)
+ a.second->setPLT0(plt0Atom);
+
+ for (auto &gotplt : _gotpltVector) {
+ gotplt->setOrdinal(ordinal++);
+ mf->addAtom(*gotplt);
+ }
+
+ for (auto obj : _objectVector) {
+ obj->setOrdinal(ordinal++);
+ mf->addAtom(*obj);
+ }
+
+ for (auto la25 : _la25Vector) {
+ la25->setOrdinal(ordinal++);
+ mf->addAtom(*la25);
+ }
+}
+
+template <typename ELFT>
+void RelocationPass<ELFT>::handleReference(const MipsELFDefinedAtom<ELFT> &atom,
+ Reference &ref) {
+ if (!ref.target())
+ return;
+ if (ref.kindNamespace() != lld::Reference::KindNamespace::ELF)
+ return;
+ assert(ref.kindArch() == Reference::KindArch::Mips);
+ switch (ref.kindValue()) {
+ case R_MIPS_32:
+ case R_MIPS_PC32:
+ case R_MIPS_HI16:
+ case R_MIPS_LO16:
+ case R_MIPS_PCHI16:
+ case R_MIPS_PCLO16:
+ case R_MICROMIPS_HI16:
+ case R_MICROMIPS_LO16:
+ // FIXME (simon): Handle dynamic/static linking differently.
+ handlePlain(atom, ref);
+ break;
+ case R_MIPS_26:
+ case R_MICROMIPS_26_S1:
+ handle26(atom, ref);
+ break;
+ case R_MIPS_GOT16:
+ case R_MIPS_CALL16:
+ case R_MICROMIPS_GOT16:
+ case R_MICROMIPS_CALL16:
+ case R_MIPS_GOT_DISP:
+ case R_MIPS_GOT_PAGE:
+ handleGOT(ref);
+ break;
+ case R_MIPS_GOT_OFST:
+ // Nothing to do. We create GOT page entry in the R_MIPS_GOT_PAGE handler.
+ break;
+ case R_MIPS_GPREL16:
+ if (isLocal(ref.target()))
+ ref.setAddend(ref.addend() + atom.file().getGP0());
+ break;
+ case R_MIPS_GPREL32:
+ ref.setAddend(ref.addend() + atom.file().getGP0());
+ break;
+ case R_MIPS_TLS_DTPREL_HI16:
+ case R_MIPS_TLS_DTPREL_LO16:
+ case R_MICROMIPS_TLS_DTPREL_HI16:
+ case R_MICROMIPS_TLS_DTPREL_LO16:
+ ref.setAddend(ref.addend() - atom.file().getDTPOffset());
+ break;
+ case R_MIPS_TLS_TPREL_HI16:
+ case R_MIPS_TLS_TPREL_LO16:
+ case R_MICROMIPS_TLS_TPREL_HI16:
+ case R_MICROMIPS_TLS_TPREL_LO16:
+ ref.setAddend(ref.addend() - atom.file().getTPOffset());
+ break;
+ case R_MIPS_TLS_GD:
+ case R_MICROMIPS_TLS_GD:
+ ref.setTarget(getTLSGdGOTEntry(ref.target()));
+ break;
+ case R_MIPS_TLS_LDM:
+ case R_MICROMIPS_TLS_LDM:
+ ref.setTarget(getTLSLdmGOTEntry(ref.target()));
+ break;
+ case R_MIPS_TLS_GOTTPREL:
+ case R_MICROMIPS_TLS_GOTTPREL:
+ ref.setTarget(getTLSGOTEntry(ref.target()));
+ break;
+ }
+}
+
+template <typename ELFT>
+static bool isConstrainSym(const MipsELFDefinedAtom<ELFT> &atom,
+ Reference::KindValue refKind) {
+ if ((atom.section()->sh_flags & SHF_ALLOC) == 0)
+ return false;
+ switch (refKind) {
+ case R_MIPS_NONE:
+ case R_MIPS_JALR:
+ case R_MICROMIPS_JALR:
+ case R_MIPS_GPREL16:
+ case R_MIPS_GPREL32:
+ return false;
+ default:
+ return true;
+ }
+}
+
+template <typename ELFT>
+void RelocationPass<ELFT>::collectReferenceInfo(
+ const MipsELFDefinedAtom<ELFT> &atom, Reference &ref) {
+ if (!ref.target())
+ return;
+ if (ref.kindNamespace() != lld::Reference::KindNamespace::ELF)
+ return;
+
+ auto refKind = ref.kindValue();
+ if (!isConstrainSym(atom, refKind))
+ return;
+
+ if (mightBeDynamic(atom, refKind))
+ _rel32Candidates.push_back(&ref);
+ else
+ _hasStaticRelocations.insert(ref.target());
+
+ if (refKind != R_MIPS_CALL16 && refKind != R_MICROMIPS_CALL16 &&
+ refKind != R_MIPS_26 && refKind != R_MICROMIPS_26_S1)
+ _requiresPtrEquality.insert(ref.target());
+}
+
+template <typename ELFT>
+bool RelocationPass<ELFT>::isLocal(const Atom *a) const {
+ if (auto *da = dyn_cast<DefinedAtom>(a))
+ return da->scope() == Atom::scopeTranslationUnit;
+ return false;
+}
+
+template <typename ELFT>
+static bool isMipsReadonly(const MipsELFDefinedAtom<ELFT> &atom) {
+ auto secFlags = atom.section()->sh_flags;
+ auto secType = atom.section()->sh_type;
+
+ if ((secFlags & SHF_ALLOC) == 0)
+ return false;
+ if (secType == SHT_NOBITS)
+ return false;
+ if ((secFlags & SHF_WRITE) != 0)
+ return false;
+ return true;
+}
+
+template <typename ELFT>
+bool RelocationPass<ELFT>::mightBeDynamic(const MipsELFDefinedAtom<ELFT> &atom,
+ Reference::KindValue refKind) const {
+ if (refKind == R_MIPS_CALL16 || refKind == R_MIPS_GOT16 ||
+ refKind == R_MICROMIPS_CALL16 || refKind == R_MICROMIPS_GOT16)
+ return true;
+
+ if (refKind != R_MIPS_32 && refKind != R_MIPS_64)
+ return false;
+ if ((atom.section()->sh_flags & SHF_ALLOC) == 0)
+ return false;
+
+ if (_ctx.getOutputELFType() == ET_DYN)
+ return true;
+ if (!isMipsReadonly(atom))
+ return true;
+ if (atom.file().isPIC())
+ return true;
+
+ return false;
+}
+
+template <typename ELFT>
+bool RelocationPass<ELFT>::hasPLTEntry(const Atom *atom) const {
+ return _pltRegMap.count(atom) || _pltMicroMap.count(atom);
+}
+
+template <typename ELFT> bool RelocationPass<ELFT>::isR6Target() const {
+ switch (_ctx.getMergedELFFlags() & EF_MIPS_ARCH) {
+ case EF_MIPS_ARCH_32R6:
+ case EF_MIPS_ARCH_64R6:
+ return true;
+ default:
+ return false;
+ }
+}
+
+template <typename ELFT>
+bool RelocationPass<ELFT>::requirePLTEntry(const Atom *a) const {
+ if (!_hasStaticRelocations.count(a))
+ return false;
+ const auto *sa = dyn_cast<ELFDynamicAtom<ELFT>>(a);
+ if (sa && sa->type() != SharedLibraryAtom::Type::Code)
+ return false;
+ const auto *da = dyn_cast<ELFDefinedAtom<ELFT>>(a);
+ if (da && da->contentType() != DefinedAtom::typeCode)
+ return false;
+ if (isLocalCall(a))
+ return false;
+ return true;
+}
+
+template <typename ELFT>
+bool RelocationPass<ELFT>::requireCopy(const Atom *a) const {
+ if (!_hasStaticRelocations.count(a))
+ return false;
+ const auto *sa = dyn_cast<ELFDynamicAtom<ELFT>>(a);
+ return sa && sa->type() == SharedLibraryAtom::Type::Data;
+}
+
+template <typename ELFT>
+bool RelocationPass<ELFT>::isDynamic(const Atom *atom) const {
+ const auto *da = dyn_cast<const DefinedAtom>(atom);
+ if (da && da->dynamicExport() == DefinedAtom::dynamicExportAlways)
+ return true;
+
+ const auto *sa = dyn_cast<SharedLibraryAtom>(atom);
+ if (sa)
+ return true;
+
+ if (_ctx.getOutputELFType() == ET_DYN) {
+ if (da && da->scope() != DefinedAtom::scopeTranslationUnit)
+ return true;
+
+ const auto *ua = dyn_cast<UndefinedAtom>(atom);
+ if (ua)
+ return true;
+ }
+
+ return false;
+}
+
+template <typename ELFT>
+static bool isMicroMips(const MipsELFDefinedAtom<ELFT> &atom) {
+ return atom.codeModel() == DefinedAtom::codeMipsMicro ||
+ atom.codeModel() == DefinedAtom::codeMipsMicroPIC;
+}
+
+template <typename ELFT>
+const LA25Atom *RelocationPass<ELFT>::getLA25Entry(const Atom *target,
+ bool isMicroMips) {
+ return isMicroMips ? getLA25MicroEntry(target) : getLA25RegEntry(target);
+}
+
+template <typename ELFT>
+const PLTAtom *RelocationPass<ELFT>::getPLTEntry(const Atom *a) {
+ bool hasMicroCode = _ctx.getMergedELFFlags() & EF_MIPS_MICROMIPS;
+
+ // If file contains microMIPS code try to reuse compressed PLT entry...
+ if (hasMicroCode) {
+ auto microPLT = _pltMicroMap.find(a);
+ if (microPLT != _pltMicroMap.end())
+ return microPLT->second;
+ }
+
+ // ... then try to reuse a regular PLT entry ...
+ auto regPLT = _pltRegMap.find(a);
+ if (regPLT != _pltRegMap.end())
+ return regPLT->second;
+
+ // ... and finally prefer to create new compressed PLT entry.
+ return hasMicroCode ? getPLTMicroEntry(a) : getPLTRegEntry(a);
+}
+
+template <typename ELFT>
+void RelocationPass<ELFT>::handlePlain(const MipsELFDefinedAtom<ELFT> &atom,
+ Reference &ref) {
+ if (!isDynamic(ref.target()))
+ return;
+
+ if (requirePLTEntry(ref.target()))
+ ref.setTarget(getPLTEntry(ref.target()));
+ else if (requireCopy(ref.target()))
+ ref.setTarget(getObjectEntry(cast<SharedLibraryAtom>(ref.target())));
+}
+
+template <typename ELFT>
+void RelocationPass<ELFT>::handle26(const MipsELFDefinedAtom<ELFT> &atom,
+ Reference &ref) {
+ bool isMicro = ref.kindValue() == R_MICROMIPS_26_S1;
+ assert((isMicro || ref.kindValue() == R_MIPS_26) && "Unexpected relocation");
+
+ const auto *sla = dyn_cast<SharedLibraryAtom>(ref.target());
+ if (sla && sla->type() == SharedLibraryAtom::Type::Code)
+ ref.setTarget(isMicro ? getPLTMicroEntry(sla) : getPLTRegEntry(sla));
+
+ if (requireLA25Stub(ref.target()))
+ ref.setTarget(getLA25Entry(ref.target(), isMicro));
+
+ if (!isLocal(ref.target())) {
+ if (isMicro)
+ ref.setKindValue(LLD_R_MICROMIPS_GLOBAL_26_S1);
+ else
+ ref.setKindValue(LLD_R_MIPS_GLOBAL_26);
+ }
+}
+
+template <typename ELFT> void RelocationPass<ELFT>::handleGOT(Reference &ref) {
+ if (!isLocalCall(ref.target())) {
+ ref.setTarget(getGlobalGOTEntry(ref.target()));
+ return;
+ }
+
+ if (ref.kindValue() == R_MIPS_GOT_PAGE)
+ ref.setTarget(getLocalGOTPageEntry(ref));
+ else if (ref.kindValue() == R_MIPS_GOT_DISP)
+ ref.setTarget(getLocalGOTEntry(ref));
+ else if (isLocal(ref.target()))
+ ref.setTarget(getLocalGOTPageEntry(ref));
+ else
+ ref.setTarget(getLocalGOTEntry(ref));
+}
+
+template <typename ELFT>
+bool RelocationPass<ELFT>::isLocalCall(const Atom *a) const {
+ Atom::Scope scope;
+ if (auto *da = dyn_cast<DefinedAtom>(a))
+ scope = da->scope();
+ else if (auto *aa = dyn_cast<AbsoluteAtom>(a))
+ scope = aa->scope();
+ else
+ return false;
+
+ // Local and hidden symbols must be local.
+ if (scope == Atom::scopeTranslationUnit || scope == Atom::scopeLinkageUnit)
+ return true;
+
+ // Calls to external symbols defined in an executable file resolved locally.
+ if (_ctx.getOutputELFType() == ET_EXEC)
+ return true;
+
+ return false;
+}
+
+template <typename ELFT>
+bool RelocationPass<ELFT>::requireLA25Stub(const Atom *a) const {
+ if (isLocal(a))
+ return false;
+ if (auto *da = dyn_cast<DefinedAtom>(a))
+ return static_cast<const MipsELFDefinedAtom<ELFT> *>(da)->file().isPIC();
+ return false;
+}
+
+template <typename ELFT>
+const GOTAtom *RelocationPass<ELFT>::getLocalGOTEntry(const Reference &ref) {
+ const Atom *a = ref.target();
+ LocalGotMapKeyT key(a, ref.addend());
+
+ auto got = _gotLocalMap.find(key);
+ if (got != _gotLocalMap.end())
+ return got->second;
+
+ auto ga = new (_file._alloc) GOT0Atom<ELFT>(_file);
+ _gotLocalMap[key] = ga;
+
+ _localGotVector.push_back(ga);
+
+ Reference::KindValue relKind = ELFT::Is64Bits ? R_MIPS_64 : R_MIPS_32;
+ ga->addReferenceELF_Mips(relKind, 0, a, 0);
+
+ return ga;
+}
+
+template <typename ELFT>
+const GOTAtom *
+RelocationPass<ELFT>::getLocalGOTPageEntry(const Reference &ref) {
+ const Atom *a = ref.target();
+ LocalGotMapKeyT key(a, ref.addend());
+
+ auto got = _gotLocalPageMap.find(key);
+ if (got != _gotLocalPageMap.end())
+ return got->second;
+
+ auto ga = new (_file._alloc) GOT0Atom<ELFT>(_file);
+ _gotLocalPageMap[key] = ga;
+
+ _localGotVector.push_back(ga);
+
+ Reference::KindValue relKind =
+ ELFT::Is64Bits ? LLD_R_MIPS_64_HI16 : LLD_R_MIPS_32_HI16;
+ ga->addReferenceELF_Mips(relKind, 0, a, ref.addend());
+
+ return ga;
+}
+
+template <typename ELFT>
+const GOTAtom *RelocationPass<ELFT>::getGlobalGOTEntry(const Atom *a) {
+ auto got = _gotGlobalMap.find(a);
+ if (got != _gotGlobalMap.end())
+ return got->second;
+
+ auto ga = new (_file._alloc) GOT0Atom<ELFT>(_file);
+ _gotGlobalMap[a] = ga;
+
+ _globalGotVector.push_back(ga);
+ ga->addReferenceELF_Mips(LLD_R_MIPS_GLOBAL_GOT, 0, a, 0);
+
+ if (const DefinedAtom *da = dyn_cast<DefinedAtom>(a))
+ ga->addReferenceELF_Mips(R_MIPS_32, 0, da, 0);
+
+ return ga;
+}
+
+template <typename ELFT>
+const GOTAtom *RelocationPass<ELFT>::getTLSGOTEntry(const Atom *a) {
+ auto got = _gotTLSMap.find(a);
+ if (got != _gotTLSMap.end())
+ return got->second;
+
+ auto ga = new (_file._alloc) GOT0Atom<ELFT>(_file);
+ _gotTLSMap[a] = ga;
+
+ _tlsGotVector.push_back(ga);
+ Reference::KindValue relKind =
+ ELFT::Is64Bits ? R_MIPS_TLS_TPREL64 : R_MIPS_TLS_TPREL32;
+ ga->addReferenceELF_Mips(relKind, 0, a, 0);
+
+ return ga;
+}
+
+template <typename ELFT>
+const GOTAtom *RelocationPass<ELFT>::getTLSGdGOTEntry(const Atom *a) {
+ auto got = _gotTLSGdMap.find(a);
+ if (got != _gotTLSGdMap.end())
+ return got->second;
+
+ auto ga = new (_file._alloc) GOTTLSGdAtom<ELFT>(_file);
+ _gotTLSGdMap[a] = ga;
+
+ _tlsGotVector.push_back(ga);
+ if (ELFT::Is64Bits) {
+ ga->addReferenceELF_Mips(R_MIPS_TLS_DTPMOD64, 0, a, 0);
+ ga->addReferenceELF_Mips(R_MIPS_TLS_DTPREL64, 8, a, 0);
+ } else {
+ ga->addReferenceELF_Mips(R_MIPS_TLS_DTPMOD32, 0, a, 0);
+ ga->addReferenceELF_Mips(R_MIPS_TLS_DTPREL32, 4, a, 0);
+ }
+
+ return ga;
+}
+
+template <typename ELFT>
+const GOTAtom *RelocationPass<ELFT>::getTLSLdmGOTEntry(const Atom *a) {
+ if (_gotLDMEntry)
+ return _gotLDMEntry;
+
+ _gotLDMEntry = new (_file._alloc) GOTTLSGdAtom<ELFT>(_file);
+ _tlsGotVector.push_back(_gotLDMEntry);
+ if (ELFT::Is64Bits)
+ _gotLDMEntry->addReferenceELF_Mips(R_MIPS_TLS_DTPMOD64, 0, _gotLDMEntry, 0);
+ else
+ _gotLDMEntry->addReferenceELF_Mips(R_MIPS_TLS_DTPMOD32, 0, _gotLDMEntry, 0);
+
+ return _gotLDMEntry;
+}
+
+template <typename ELFT>
+PLTAtom *RelocationPass<ELFT>::createPLTHeader(bool isMicroMips) {
+ auto ga1 = new (_file._alloc) GOTPLTAtom(_file);
+ _gotpltVector.insert(_gotpltVector.begin(), ga1);
+ auto ga0 = new (_file._alloc) GOTPLTAtom(_file);
+ _gotpltVector.insert(_gotpltVector.begin(), ga0);
+
+ if (isMicroMips)
+ return new (_file._alloc) PLT0MicroAtom(ga0, _file);
+ else
+ return new (_file._alloc) PLT0Atom(ga0, _file);
+}
+
+template <typename ELFT>
+const GOTPLTAtom *RelocationPass<ELFT>::getGOTPLTEntry(const Atom *a) {
+ auto it = _gotpltMap.find(a);
+ if (it != _gotpltMap.end())
+ return it->second;
+
+ auto ga = new (_file._alloc) GOTPLTAtom(a, _file);
+ _gotpltMap[a] = ga;
+ _gotpltVector.push_back(ga);
+ return ga;
+}
+
+template <typename ELFT>
+const PLTAtom *RelocationPass<ELFT>::getPLTRegEntry(const Atom *a) {
+ auto plt = _pltRegMap.find(a);
+ if (plt != _pltRegMap.end())
+ return plt->second;
+
+ PLTAAtom *pa = isR6Target()
+ ? new (_file._alloc) PLTR6Atom(getGOTPLTEntry(a), _file)
+ : new (_file._alloc) PLTAAtom(getGOTPLTEntry(a), _file);
+ _pltRegMap[a] = pa;
+ _pltRegVector.push_back(pa);
+
+ // Check that 'a' dynamic symbol table record should point to the PLT.
+ if (_hasStaticRelocations.count(a) && _requiresPtrEquality.count(a))
+ pa->addReferenceELF_Mips(LLD_R_MIPS_STO_PLT, 0, a, 0);
+
+ return pa;
+}
+
+template <typename ELFT>
+const PLTAtom *RelocationPass<ELFT>::getPLTMicroEntry(const Atom *a) {
+ auto plt = _pltMicroMap.find(a);
+ if (plt != _pltMicroMap.end())
+ return plt->second;
+
+ auto pa = new (_file._alloc) PLTMicroAtom(getGOTPLTEntry(a), _file);
+ _pltMicroMap[a] = pa;
+ _pltMicroVector.push_back(pa);
+
+ // Check that 'a' dynamic symbol table record should point to the PLT.
+ if (_hasStaticRelocations.count(a) && _requiresPtrEquality.count(a))
+ pa->addReferenceELF_Mips(LLD_R_MIPS_STO_PLT, 0, a, 0);
+
+ return pa;
+}
+
+template <typename ELFT>
+const LA25Atom *RelocationPass<ELFT>::getLA25RegEntry(const Atom *a) {
+ auto la25 = _la25RegMap.find(a);
+ if (la25 != _la25RegMap.end())
+ return la25->second;
+
+ auto sa = new (_file._alloc) LA25RegAtom(a, _file);
+ _la25RegMap[a] = sa;
+ _la25Vector.push_back(sa);
+
+ return sa;
+}
+
+template <typename ELFT>
+const LA25Atom *RelocationPass<ELFT>::getLA25MicroEntry(const Atom *a) {
+ auto la25 = _la25MicroMap.find(a);
+ if (la25 != _la25MicroMap.end())
+ return la25->second;
+
+ auto sa = new (_file._alloc) LA25MicroAtom(a, _file);
+ _la25MicroMap[a] = sa;
+ _la25Vector.push_back(sa);
+
+ return sa;
+}
+
+template <typename ELFT>
+const ObjectAtom *
+RelocationPass<ELFT>::getObjectEntry(const SharedLibraryAtom *a) {
+ auto obj = _objectMap.find(a);
+ if (obj != _objectMap.end())
+ return obj->second;
+
+ auto oa = new (_file._alloc) ObjectAtom(_file);
+ oa->addReferenceELF_Mips(R_MIPS_COPY, 0, oa, 0);
+ oa->_name = a->name();
+ oa->_size = a->size();
+
+ _objectMap[a] = oa;
+ _objectVector.push_back(oa);
+
+ return oa;
+}
+
+} // end anon namespace
+
+static std::unique_ptr<Pass> createPass(MipsLinkingContext &ctx) {
+ switch (ctx.getTriple().getArch()) {
+ case llvm::Triple::mipsel:
+ return llvm::make_unique<RelocationPass<Mips32ELType>>(ctx);
+ case llvm::Triple::mips64el:
+ return llvm::make_unique<RelocationPass<Mips64ELType>>(ctx);
+ default:
+ llvm_unreachable("Unhandled arch");
+ }
+}
+
+std::unique_ptr<Pass>
+lld::elf::createMipsRelocationPass(MipsLinkingContext &ctx) {
+ switch (ctx.getOutputELFType()) {
+ case ET_EXEC:
+ case ET_DYN:
+ return createPass(ctx);
+ case ET_REL:
+ return nullptr;
+ default:
+ llvm_unreachable("Unhandled output file type");
+ }
+}
diff --git a/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.h b/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.h
new file mode 100644
index 000000000000..af343de5f027
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.h
@@ -0,0 +1,25 @@
+//===- lib/ReaderWriter/ELF/Mips/MipsRelocationPass.h ---------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_RELOCATION_PASS_H
+#define LLD_READER_WRITER_ELF_MIPS_MIPS_RELOCATION_PASS_H
+
+#include <memory>
+
+namespace lld {
+class Pass;
+
+namespace elf {
+class MipsLinkingContext;
+
+std::unique_ptr<Pass> createMipsRelocationPass(MipsLinkingContext &ctx);
+
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h b/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h
new file mode 100644
index 000000000000..de9390f2b307
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h
@@ -0,0 +1,170 @@
+//===- lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h ----------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_SECTION_CHUNKS_H
+#define LLD_READER_WRITER_ELF_MIPS_MIPS_SECTION_CHUNKS_H
+
+namespace lld {
+namespace elf {
+
+template <typename ELFT> class MipsTargetLayout;
+class MipsLinkingContext;
+
+/// \brief Handle Mips GOT section
+template <class ELFType> class MipsGOTSection : public AtomSection<ELFType> {
+public:
+ MipsGOTSection(const MipsLinkingContext &ctx)
+ : AtomSection<ELFType>(ctx, ".got", DefinedAtom::typeGOT,
+ DefinedAtom::permRW_,
+ MipsTargetLayout<ELFType>::ORDER_GOT),
+ _hasNonLocal(false), _localCount(0) {
+ this->_flags |= SHF_MIPS_GPREL;
+ this->_alignment = 4;
+ }
+
+ /// \brief Number of local GOT entries.
+ std::size_t getLocalCount() const { return _localCount; }
+
+ /// \brief Number of global GOT entries.
+ std::size_t getGlobalCount() const { return _posMap.size(); }
+
+ /// \brief Does the atom have a global GOT entry?
+ bool hasGlobalGOTEntry(const Atom *a) const {
+ return _posMap.count(a) || _tlsMap.count(a);
+ }
+
+ /// \brief Compare two atoms accordingly theirs positions in the GOT.
+ bool compare(const Atom *a, const Atom *b) const {
+ auto ia = _posMap.find(a);
+ auto ib = _posMap.find(b);
+
+ if (ia != _posMap.end() && ib != _posMap.end())
+ return ia->second < ib->second;
+
+ return ia == _posMap.end() && ib != _posMap.end();
+ }
+
+ const lld::AtomLayout *appendAtom(const Atom *atom) override {
+ const DefinedAtom *da = dyn_cast<DefinedAtom>(atom);
+
+ for (const auto &r : *da) {
+ if (r->kindNamespace() != lld::Reference::KindNamespace::ELF)
+ continue;
+ assert(r->kindArch() == Reference::KindArch::Mips);
+ switch (r->kindValue()) {
+ case LLD_R_MIPS_GLOBAL_GOT:
+ _hasNonLocal = true;
+ _posMap[r->target()] = _posMap.size();
+ return AtomSection<ELFType>::appendAtom(atom);
+ case R_MIPS_TLS_TPREL32:
+ case R_MIPS_TLS_DTPREL32:
+ case R_MIPS_TLS_TPREL64:
+ case R_MIPS_TLS_DTPREL64:
+ _hasNonLocal = true;
+ _tlsMap[r->target()] = _tlsMap.size();
+ return AtomSection<ELFType>::appendAtom(atom);
+ case R_MIPS_TLS_DTPMOD32:
+ case R_MIPS_TLS_DTPMOD64:
+ _hasNonLocal = true;
+ break;
+ }
+ }
+
+ if (!_hasNonLocal)
+ ++_localCount;
+
+ return AtomSection<ELFType>::appendAtom(atom);
+ }
+
+private:
+ /// \brief True if the GOT contains non-local entries.
+ bool _hasNonLocal;
+
+ /// \brief Number of local GOT entries.
+ std::size_t _localCount;
+
+ /// \brief Map TLS Atoms to their GOT entry index.
+ llvm::DenseMap<const Atom *, std::size_t> _tlsMap;
+
+ /// \brief Map Atoms to their GOT entry index.
+ llvm::DenseMap<const Atom *, std::size_t> _posMap;
+};
+
+/// \brief Handle Mips PLT section
+template <class ELFType> class MipsPLTSection : public AtomSection<ELFType> {
+public:
+ MipsPLTSection(const MipsLinkingContext &ctx)
+ : AtomSection<ELFType>(ctx, ".plt", DefinedAtom::typeGOT,
+ DefinedAtom::permR_X,
+ MipsTargetLayout<ELFType>::ORDER_PLT) {}
+
+ const AtomLayout *findPLTLayout(const Atom *plt) const {
+ auto it = _pltLayoutMap.find(plt);
+ return it != _pltLayoutMap.end() ? it->second : nullptr;
+ }
+
+ const lld::AtomLayout *appendAtom(const Atom *atom) override {
+ const auto *layout = AtomSection<ELFType>::appendAtom(atom);
+
+ const DefinedAtom *da = cast<DefinedAtom>(atom);
+
+ for (const auto &r : *da) {
+ if (r->kindNamespace() != lld::Reference::KindNamespace::ELF)
+ continue;
+ assert(r->kindArch() == Reference::KindArch::Mips);
+ if (r->kindValue() == LLD_R_MIPS_STO_PLT) {
+ _pltLayoutMap[r->target()] = layout;
+ break;
+ }
+ }
+
+ return layout;
+ }
+
+private:
+ /// \brief Map PLT Atoms to their layouts.
+ std::unordered_map<const Atom *, const AtomLayout *> _pltLayoutMap;
+};
+
+template <class ELFT> class MipsRelocationTable : public RelocationTable<ELFT> {
+ typedef llvm::object::Elf_Rel_Impl<ELFT, false> Elf_Rel;
+ typedef llvm::object::Elf_Rel_Impl<ELFT, true> Elf_Rela;
+
+ static const bool _isMips64EL =
+ ELFT::Is64Bits && ELFT::TargetEndianness == llvm::support::little;
+
+public:
+ MipsRelocationTable(const ELFLinkingContext &context, StringRef str,
+ int32_t order)
+ : RelocationTable<ELFT>(context, str, order) {}
+
+protected:
+ void writeRela(ELFWriter *writer, Elf_Rela &r, const DefinedAtom &atom,
+ const Reference &ref) override {
+ uint32_t rType = ref.kindValue() | (ref.tag() << 8);
+ r.setSymbolAndType(this->getSymbolIndex(ref.target()), rType, _isMips64EL);
+ r.r_offset = writer->addressOfAtom(&atom) + ref.offsetInAtom();
+ // The addend is used only by relative relocations
+ if (this->_context.isRelativeReloc(ref))
+ r.r_addend = writer->addressOfAtom(ref.target()) + ref.addend();
+ else
+ r.r_addend = 0;
+ }
+
+ void writeRel(ELFWriter *writer, Elf_Rel &r, const DefinedAtom &atom,
+ const Reference &ref) override {
+ uint32_t rType = ref.kindValue() | (ref.tag() << 8);
+ r.setSymbolAndType(this->getSymbolIndex(ref.target()), rType, _isMips64EL);
+ r.r_offset = writer->addressOfAtom(&atom) + ref.offsetInAtom();
+ }
+};
+
+} // elf
+} // lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp b/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp
new file mode 100644
index 000000000000..f60ab63c6af7
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp
@@ -0,0 +1,35 @@
+//===- lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp --------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MipsTargetHandler.h"
+
+using namespace lld;
+using namespace elf;
+
+void MipsRelocationStringTable::registerTable(Registry &registry) {
+ registry.addKindTable(Reference::KindNamespace::ELF,
+ Reference::KindArch::Mips, kindStrings);
+}
+
+#define ELF_RELOC(name, value) LLD_KIND_STRING_ENTRY(name),
+
+const Registry::KindStrings MipsRelocationStringTable::kindStrings[] = {
+#include "llvm/Support/ELFRelocs/Mips.def"
+ LLD_KIND_STRING_ENTRY(LLD_R_MIPS_GLOBAL_GOT),
+ LLD_KIND_STRING_ENTRY(LLD_R_MIPS_32_HI16),
+ LLD_KIND_STRING_ENTRY(LLD_R_MIPS_64_HI16),
+ LLD_KIND_STRING_ENTRY(LLD_R_MIPS_GLOBAL_26),
+ LLD_KIND_STRING_ENTRY(LLD_R_MIPS_HI16),
+ LLD_KIND_STRING_ENTRY(LLD_R_MIPS_LO16),
+ LLD_KIND_STRING_ENTRY(LLD_R_MIPS_STO_PLT),
+ LLD_KIND_STRING_ENTRY(LLD_R_MICROMIPS_GLOBAL_26_S1),
+ LLD_KIND_STRING_END
+};
+
+#undef ELF_RELOC
diff --git a/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h b/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h
new file mode 100644
index 000000000000..79509addf40b
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h
@@ -0,0 +1,257 @@
+//===- lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h ----------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_TARGET_HANDLER_H
+#define LLD_READER_WRITER_ELF_MIPS_MIPS_TARGET_HANDLER_H
+
+#include "DefaultTargetHandler.h"
+#include "MipsDynamicLibraryWriter.h"
+#include "MipsELFReader.h"
+#include "MipsExecutableWriter.h"
+#include "MipsLinkingContext.h"
+#include "MipsRelocationHandler.h"
+#include "MipsSectionChunks.h"
+#include "TargetLayout.h"
+#include "llvm/ADT/DenseSet.h"
+
+namespace lld {
+namespace elf {
+
+/// \brief TargetLayout for Mips
+template <class ELFT> class MipsTargetLayout final : public TargetLayout<ELFT> {
+public:
+ MipsTargetLayout(MipsLinkingContext &ctx)
+ : TargetLayout<ELFT>(ctx),
+ _gotSection(new (this->_allocator) MipsGOTSection<ELFT>(ctx)),
+ _pltSection(new (this->_allocator) MipsPLTSection<ELFT>(ctx)) {}
+
+ const MipsGOTSection<ELFT> &getGOTSection() const { return *_gotSection; }
+ const MipsPLTSection<ELFT> &getPLTSection() const { return *_pltSection; }
+
+ AtomSection<ELFT> *createSection(StringRef name, int32_t type,
+ DefinedAtom::ContentPermissions permissions,
+ Layout::SectionOrder order) override {
+ if (type == DefinedAtom::typeGOT && name == ".got")
+ return _gotSection;
+ if (type == DefinedAtom::typeStub && name == ".plt")
+ return _pltSection;
+ return DefaultLayout<ELFT>::createSection(name, type, permissions, order);
+ }
+
+ /// \brief GP offset relative to .got section.
+ uint64_t getGPOffset() const { return 0x7FF0; }
+
+ /// \brief Get '_gp' symbol atom layout.
+ AtomLayout *getGP() {
+ if (!_gpAtom.hasValue()) {
+ auto atom = this->findAbsoluteAtom("_gp");
+ _gpAtom = atom != this->absoluteAtoms().end() ? *atom : nullptr;
+ }
+ return *_gpAtom;
+ }
+
+ /// \brief Get '_gp_disp' symbol atom layout.
+ AtomLayout *getGPDisp() {
+ if (!_gpDispAtom.hasValue()) {
+ auto atom = this->findAbsoluteAtom("_gp_disp");
+ _gpDispAtom = atom != this->absoluteAtoms().end() ? *atom : nullptr;
+ }
+ return *_gpDispAtom;
+ }
+
+ /// \brief Return the section order for a input section
+ Layout::SectionOrder getSectionOrder(StringRef name, int32_t contentType,
+ int32_t contentPermissions) override {
+ if ((contentType == DefinedAtom::typeStub) && (name.startswith(".text")))
+ return DefaultLayout<ELFT>::ORDER_TEXT;
+
+ return DefaultLayout<ELFT>::getSectionOrder(name, contentType,
+ contentPermissions);
+ }
+
+protected:
+ unique_bump_ptr<RelocationTable<ELFT>>
+ createRelocationTable(StringRef name, int32_t order) override {
+ return unique_bump_ptr<RelocationTable<ELFT>>(
+ new (this->_allocator)
+ MipsRelocationTable<ELFT>(this->_context, name, order));
+ }
+
+private:
+ MipsGOTSection<ELFT> *_gotSection;
+ MipsPLTSection<ELFT> *_pltSection;
+ llvm::Optional<AtomLayout *> _gpAtom;
+ llvm::Optional<AtomLayout *> _gpDispAtom;
+};
+
+/// \brief Mips Runtime file.
+template <class ELFT> class MipsRuntimeFile final : public RuntimeFile<ELFT> {
+public:
+ MipsRuntimeFile(MipsLinkingContext &ctx)
+ : RuntimeFile<ELFT>(ctx, "Mips runtime file") {}
+};
+
+/// \brief Auxiliary class holds relocation's names table.
+class MipsRelocationStringTable {
+ static const Registry::KindStrings kindStrings[];
+
+public:
+ static void registerTable(Registry &registry);
+};
+
+/// \brief TargetHandler for Mips
+template <class ELFT>
+class MipsTargetHandler final : public DefaultTargetHandler<ELFT> {
+public:
+ MipsTargetHandler(MipsLinkingContext &ctx)
+ : _ctx(ctx), _runtimeFile(new MipsRuntimeFile<ELFT>(ctx)),
+ _targetLayout(new MipsTargetLayout<ELFT>(ctx)),
+ _relocationHandler(createMipsRelocationHandler<ELFT>(ctx)) {}
+
+ MipsTargetLayout<ELFT> &getTargetLayout() override { return *_targetLayout; }
+
+ std::unique_ptr<Reader> getObjReader() override {
+ return std::unique_ptr<Reader>(new MipsELFObjectReader<ELFT>(_ctx));
+ }
+
+ std::unique_ptr<Reader> getDSOReader() override {
+ return std::unique_ptr<Reader>(new MipsELFDSOReader<ELFT>(_ctx));
+ }
+
+ const TargetRelocationHandler &getRelocationHandler() const override {
+ return *_relocationHandler;
+ }
+
+ std::unique_ptr<Writer> getWriter() override {
+ switch (_ctx.getOutputELFType()) {
+ case llvm::ELF::ET_EXEC:
+ return std::unique_ptr<Writer>(
+ new MipsExecutableWriter<ELFT>(_ctx, *_targetLayout));
+ case llvm::ELF::ET_DYN:
+ return std::unique_ptr<Writer>(
+ new MipsDynamicLibraryWriter<ELFT>(_ctx, *_targetLayout));
+ case llvm::ELF::ET_REL:
+ llvm_unreachable("TODO: support -r mode");
+ default:
+ llvm_unreachable("unsupported output type");
+ }
+ }
+
+ void registerRelocationNames(Registry &registry) override {
+ MipsRelocationStringTable::registerTable(registry);
+ }
+
+private:
+ MipsLinkingContext &_ctx;
+ std::unique_ptr<MipsRuntimeFile<ELFT>> _runtimeFile;
+ std::unique_ptr<MipsTargetLayout<ELFT>> _targetLayout;
+ std::unique_ptr<TargetRelocationHandler> _relocationHandler;
+};
+
+template <class ELFT> class MipsSymbolTable : public SymbolTable<ELFT> {
+public:
+ typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+
+ MipsSymbolTable(const ELFLinkingContext &ctx)
+ : SymbolTable<ELFT>(ctx, ".symtab",
+ DefaultLayout<ELFT>::ORDER_SYMBOL_TABLE) {}
+
+ void addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da,
+ int64_t addr) override {
+ SymbolTable<ELFT>::addDefinedAtom(sym, da, addr);
+
+ switch (da->codeModel()) {
+ case DefinedAtom::codeMipsMicro:
+ sym.st_other |= llvm::ELF::STO_MIPS_MICROMIPS;
+ break;
+ case DefinedAtom::codeMipsMicroPIC:
+ sym.st_other |= llvm::ELF::STO_MIPS_MICROMIPS | llvm::ELF::STO_MIPS_PIC;
+ break;
+ default:
+ break;
+ }
+ }
+
+ void finalize(bool sort) override {
+ SymbolTable<ELFT>::finalize(sort);
+
+ for (auto &ste : this->_symbolTable) {
+ if (!ste._atom)
+ continue;
+ if (const auto *da = dyn_cast<DefinedAtom>(ste._atom)) {
+ if (da->codeModel() == DefinedAtom::codeMipsMicro ||
+ da->codeModel() == DefinedAtom::codeMipsMicroPIC) {
+ // Adjust dynamic microMIPS symbol value. That allows a dynamic
+ // linker to recognize and handle this symbol correctly.
+ ste._symbol.st_value = ste._symbol.st_value | 1;
+ }
+ }
+ }
+ }
+};
+
+template <class ELFT>
+class MipsDynamicSymbolTable : public DynamicSymbolTable<ELFT> {
+public:
+ MipsDynamicSymbolTable(const ELFLinkingContext &ctx,
+ MipsTargetLayout<ELFT> &layout)
+ : DynamicSymbolTable<ELFT>(ctx, layout, ".dynsym",
+ DefaultLayout<ELFT>::ORDER_DYNAMIC_SYMBOLS),
+ _targetLayout(layout) {}
+
+ void sortSymbols() override {
+ typedef typename DynamicSymbolTable<ELFT>::SymbolEntry SymbolEntry;
+ std::stable_sort(this->_symbolTable.begin(), this->_symbolTable.end(),
+ [this](const SymbolEntry &A, const SymbolEntry &B) {
+ if (A._symbol.getBinding() != STB_GLOBAL &&
+ B._symbol.getBinding() != STB_GLOBAL)
+ return A._symbol.getBinding() < B._symbol.getBinding();
+
+ return _targetLayout.getGOTSection().compare(A._atom, B._atom);
+ });
+ }
+
+ void finalize() override {
+ DynamicSymbolTable<ELFT>::finalize();
+
+ const auto &pltSection = _targetLayout.getPLTSection();
+
+ for (auto &ste : this->_symbolTable) {
+ const Atom *a = ste._atom;
+ if (!a)
+ continue;
+ if (auto *layout = pltSection.findPLTLayout(a)) {
+ a = layout->_atom;
+ // Under some conditions a dynamic symbol table record should hold
+ // a symbol value of the corresponding PLT entry. For details look
+ // at the PLT entry creation code in the class MipsRelocationPass.
+ // Let's update atomLayout fields for such symbols.
+ assert(!ste._atomLayout);
+ ste._symbol.st_value = layout->_virtualAddr;
+ ste._symbol.st_other |= ELF::STO_MIPS_PLT;
+ }
+
+ if (const auto *da = dyn_cast<DefinedAtom>(a)) {
+ if (da->codeModel() == DefinedAtom::codeMipsMicro ||
+ da->codeModel() == DefinedAtom::codeMipsMicroPIC) {
+ // Adjust dynamic microMIPS symbol value. That allows a dynamic
+ // linker to recognize and handle this symbol correctly.
+ ste._symbol.st_value = ste._symbol.st_value | 1;
+ }
+ }
+ }
+ }
+
+private:
+ MipsTargetLayout<ELFT> &_targetLayout;
+};
+
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/OrderPass.h b/lib/ReaderWriter/ELF/OrderPass.h
new file mode 100644
index 000000000000..d126b830db96
--- /dev/null
+++ b/lib/ReaderWriter/ELF/OrderPass.h
@@ -0,0 +1,30 @@
+//===- lib/ReaderWriter/ELF/OrderPass.h -----------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_ORDER_PASS_H
+#define LLD_READER_WRITER_ELF_ORDER_PASS_H
+
+#include "lld/Core/Parallel.h"
+#include <limits>
+
+namespace lld {
+namespace elf {
+
+/// \brief This pass sorts atoms by file and atom ordinals.
+class OrderPass : public Pass {
+public:
+ void perform(std::unique_ptr<MutableFile> &file) override {
+ parallel_sort(file->definedAtoms().begin(), file->definedAtoms().end(),
+ DefinedAtom::compareByPosition);
+ }
+};
+}
+}
+
+#endif
diff --git a/lib/ReaderWriter/ELF/OutputELFWriter.h b/lib/ReaderWriter/ELF/OutputELFWriter.h
new file mode 100644
index 000000000000..c137905b936b
--- /dev/null
+++ b/lib/ReaderWriter/ELF/OutputELFWriter.h
@@ -0,0 +1,615 @@
+//===- lib/ReaderWriter/ELF/OutputELFWriter.h ----------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLD_READER_WRITER_ELF_OUTPUT_WRITER_H
+#define LLD_READER_WRITER_ELF_OUTPUT_WRITER_H
+
+#include "DefaultLayout.h"
+#include "ELFFile.h"
+#include "TargetLayout.h"
+#include "lld/Core/Instrumentation.h"
+#include "lld/Core/Parallel.h"
+#include "lld/Core/SharedLibraryFile.h"
+#include "lld/ReaderWriter/ELFLinkingContext.h"
+#include "lld/Core/Simple.h"
+#include "lld/Core/Writer.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/Support/Path.h"
+
+namespace lld {
+namespace elf {
+using namespace llvm;
+using namespace llvm::object;
+
+template <class ELFT> class OutputELFWriter;
+template <class ELFT> class TargetLayout;
+
+namespace {
+
+template<class ELFT>
+class SymbolFile : public RuntimeFile<ELFT> {
+public:
+ SymbolFile(ELFLinkingContext &context)
+ : RuntimeFile<ELFT>(context, "Dynamic absolute symbols"),
+ _atomsAdded(false) {}
+
+ Atom *addAbsoluteAtom(StringRef symbolName) override {
+ auto *a = RuntimeFile<ELFT>::addAbsoluteAtom(symbolName);
+ if (a) _atomsAdded = true;
+ return a;
+ }
+
+ Atom *addUndefinedAtom(StringRef) override {
+ llvm_unreachable("Cannot add undefined atoms to resolve undefined symbols");
+ }
+
+ bool hasAtoms() const { return _atomsAdded; }
+
+private:
+ bool _atomsAdded;
+};
+
+template<class ELFT>
+class DynamicSymbolFile : public SimpleArchiveLibraryFile {
+ typedef std::function<void(StringRef, RuntimeFile<ELFT> &)> Resolver;
+public:
+ DynamicSymbolFile(ELFLinkingContext &context, Resolver resolver)
+ : SimpleArchiveLibraryFile("Dynamically added runtime symbols"),
+ _context(context), _resolver(resolver) {}
+
+ File *find(StringRef sym, bool dataSymbolOnly) override {
+ if (!_file)
+ _file.reset(new (_alloc) SymbolFile<ELFT>(_context));
+
+ assert(!_file->hasAtoms() && "The file shouldn't have atoms yet");
+ _resolver(sym, *_file);
+ // If atoms were added - release the file to the caller.
+ return _file->hasAtoms() ? _file.release() : nullptr;
+ }
+
+private:
+ ELFLinkingContext &_context;
+ Resolver _resolver;
+
+ // The allocator should go before bump pointers because of
+ // reversed destruction order.
+ llvm::BumpPtrAllocator _alloc;
+ unique_bump_ptr<SymbolFile<ELFT>> _file;
+};
+
+} // end anon namespace
+
+//===----------------------------------------------------------------------===//
+// OutputELFWriter Class
+//===----------------------------------------------------------------------===//
+/// \brief This acts as the base class for all the ELF writers that are output
+/// for emitting an ELF output file. This class also acts as a common class for
+/// creating static and dynamic executables. All the function in this class
+/// can be overridden and an appropriate writer be created
+template<class ELFT>
+class OutputELFWriter : public ELFWriter {
+public:
+ typedef Elf_Shdr_Impl<ELFT> Elf_Shdr;
+ typedef Elf_Sym_Impl<ELFT> Elf_Sym;
+ typedef Elf_Dyn_Impl<ELFT> Elf_Dyn;
+
+ OutputELFWriter(ELFLinkingContext &context, TargetLayout<ELFT> &layout);
+
+protected:
+ // build the sections that need to be created
+ virtual void createDefaultSections();
+
+ // Build all the output sections
+ void buildChunks(const File &file) override;
+
+ // Build the output file
+ virtual std::error_code buildOutput(const File &file);
+
+ // Setup the ELF header.
+ virtual std::error_code setELFHeader();
+
+ // Write the file to the path specified
+ std::error_code writeFile(const File &File, StringRef path) override;
+
+ // Write to the output file.
+ virtual std::error_code writeOutput(const File &file, StringRef path);
+
+ // Get the size of the output file that the linker would emit.
+ virtual uint64_t outputFileSize() const;
+
+ // Build the atom to address map, this has to be called
+ // before applying relocations
+ virtual void buildAtomToAddressMap(const File &file);
+
+ // Build the symbol table for static linking
+ virtual void buildStaticSymbolTable(const File &file);
+
+ // Build the dynamic symbol table for dynamic linking
+ virtual void buildDynamicSymbolTable(const File &file);
+
+ // Build the section header table
+ virtual void buildSectionHeaderTable();
+
+ // Assign sections that have no segments such as the symbol table,
+ // section header table, string table etc
+ virtual void assignSectionsWithNoSegments();
+
+ // Add default atoms that need to be present in the output file
+ virtual void addDefaultAtoms();
+
+ // Add any runtime files and their atoms to the output
+ bool createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
+
+ // Finalize the default atom values
+ virtual void finalizeDefaultAtomValues();
+
+ // This is called by the write section to apply relocations
+ uint64_t addressOfAtom(const Atom *atom) override {
+ auto addr = _atomToAddressMap.find(atom);
+ return addr == _atomToAddressMap.end() ? 0 : addr->second;
+ }
+
+ // This is a hook for creating default dynamic entries
+ virtual void createDefaultDynamicEntries() {}
+
+ /// \brief Create symbol table.
+ virtual unique_bump_ptr<SymbolTable<ELFT>> createSymbolTable();
+
+ /// \brief create dynamic table.
+ virtual unique_bump_ptr<DynamicTable<ELFT>> createDynamicTable();
+
+ /// \brief create dynamic symbol table.
+ virtual unique_bump_ptr<DynamicSymbolTable<ELFT>>
+ createDynamicSymbolTable();
+
+ /// \brief Create entry in the dynamic symbols table for this atom.
+ virtual bool isDynSymEntryRequired(const SharedLibraryAtom *sla) const {
+ return _layout.isReferencedByDefinedAtom(sla);
+ }
+
+ /// \brief Create DT_NEEDED dynamic tage for the shared library.
+ virtual bool isNeededTagRequired(const SharedLibraryAtom *sla) const {
+ return false;
+ }
+
+ /// \brief Process undefined symbols that left after resolution step.
+ virtual void processUndefinedSymbol(StringRef symName,
+ RuntimeFile<ELFT> &file) const {}
+
+ llvm::BumpPtrAllocator _alloc;
+
+ ELFLinkingContext &_context;
+ TargetHandler<ELFT> &_targetHandler;
+
+ typedef llvm::DenseMap<const Atom *, uint64_t> AtomToAddress;
+ AtomToAddress _atomToAddressMap;
+ TargetLayout<ELFT> &_layout;
+ unique_bump_ptr<ELFHeader<ELFT>> _elfHeader;
+ unique_bump_ptr<ProgramHeader<ELFT>> _programHeader;
+ unique_bump_ptr<SymbolTable<ELFT>> _symtab;
+ unique_bump_ptr<StringTable<ELFT>> _strtab;
+ unique_bump_ptr<StringTable<ELFT>> _shstrtab;
+ unique_bump_ptr<SectionHeader<ELFT>> _shdrtab;
+ unique_bump_ptr<EHFrameHeader<ELFT>> _ehFrameHeader;
+ /// \name Dynamic sections.
+ /// @{
+ unique_bump_ptr<DynamicTable<ELFT>> _dynamicTable;
+ unique_bump_ptr<DynamicSymbolTable<ELFT>> _dynamicSymbolTable;
+ unique_bump_ptr<StringTable<ELFT>> _dynamicStringTable;
+ unique_bump_ptr<HashSection<ELFT>> _hashTable;
+ llvm::StringSet<> _soNeeded;
+ /// @}
+ std::unique_ptr<RuntimeFile<ELFT>> _scriptFile;
+
+private:
+ static StringRef maybeGetSOName(Node *node);
+};
+
+//===----------------------------------------------------------------------===//
+// OutputELFWriter
+//===----------------------------------------------------------------------===//
+template <class ELFT>
+OutputELFWriter<ELFT>::OutputELFWriter(ELFLinkingContext &context,
+ TargetLayout<ELFT> &layout)
+ : _context(context), _targetHandler(context.getTargetHandler<ELFT>()),
+ _layout(layout),
+ _scriptFile(new RuntimeFile<ELFT>(context, "Linker script runtime")) {}
+
+template <class ELFT>
+void OutputELFWriter<ELFT>::buildChunks(const File &file) {
+ ScopedTask task(getDefaultDomain(), "buildChunks");
+ for (const DefinedAtom *definedAtom : file.defined()) {
+ DefinedAtom::ContentType contentType = definedAtom->contentType();
+ // Dont add COMDAT group atoms and GNU linkonce atoms, as they are used for
+ // symbol resolution.
+ // TODO: handle partial linking.
+ if (contentType == DefinedAtom::typeGroupComdat ||
+ contentType == DefinedAtom::typeGnuLinkOnce)
+ continue;
+ _layout.addAtom(definedAtom);
+ }
+ for (const AbsoluteAtom *absoluteAtom : file.absolute())
+ _layout.addAtom(absoluteAtom);
+}
+
+template <class ELFT>
+void OutputELFWriter<ELFT>::buildStaticSymbolTable(const File &file) {
+ ScopedTask task(getDefaultDomain(), "buildStaticSymbolTable");
+ for (auto sec : _layout.sections())
+ if (auto section = dyn_cast<AtomSection<ELFT>>(sec))
+ for (const auto &atom : section->atoms())
+ _symtab->addSymbol(atom->_atom, section->ordinal(), atom->_virtualAddr);
+ for (auto &atom : _layout.absoluteAtoms())
+ _symtab->addSymbol(atom->_atom, ELF::SHN_ABS, atom->_virtualAddr);
+ for (const UndefinedAtom *a : file.undefined())
+ _symtab->addSymbol(a, ELF::SHN_UNDEF);
+}
+
+// Returns the DSO name for a given input file if it's a shared library
+// file and not marked as --as-needed.
+template <class ELFT>
+StringRef OutputELFWriter<ELFT>::maybeGetSOName(Node *node) {
+ if (auto *fnode = dyn_cast<FileNode>(node))
+ if (!fnode->asNeeded())
+ if (auto *file = dyn_cast<SharedLibraryFile>(fnode->getFile()))
+ return file->getDSOName();
+ return "";
+}
+
+template <class ELFT>
+void OutputELFWriter<ELFT>::buildDynamicSymbolTable(const File &file) {
+ ScopedTask task(getDefaultDomain(), "buildDynamicSymbolTable");
+ for (const auto &sla : file.sharedLibrary()) {
+ if (isDynSymEntryRequired(sla)) {
+ _dynamicSymbolTable->addSymbol(sla, ELF::SHN_UNDEF);
+ _soNeeded.insert(sla->loadName());
+ continue;
+ }
+ if (isNeededTagRequired(sla))
+ _soNeeded.insert(sla->loadName());
+ }
+ for (const std::unique_ptr<Node> &node : _context.getNodes()) {
+ StringRef soname = maybeGetSOName(node.get());
+ if (!soname.empty())
+ _soNeeded.insert(soname);
+ }
+ // Never mark the dynamic linker as DT_NEEDED
+ _soNeeded.erase(sys::path::filename(_context.getInterpreter()));
+ for (const auto &loadName : _soNeeded) {
+ Elf_Dyn dyn;
+ dyn.d_tag = DT_NEEDED;
+ dyn.d_un.d_val = _dynamicStringTable->addString(loadName.getKey());
+ _dynamicTable->addEntry(dyn);
+ }
+ const auto &rpathList = _context.getRpathList();
+ if (!rpathList.empty()) {
+ auto rpath = new (_alloc) std::string(join(rpathList.begin(),
+ rpathList.end(), ":"));
+ Elf_Dyn dyn;
+ dyn.d_tag = DT_RPATH;
+ dyn.d_un.d_val = _dynamicStringTable->addString(*rpath);
+ _dynamicTable->addEntry(dyn);
+ }
+ StringRef soname = _context.sharedObjectName();
+ if (!soname.empty() && _context.getOutputELFType() == llvm::ELF::ET_DYN) {
+ Elf_Dyn dyn;
+ dyn.d_tag = DT_SONAME;
+ dyn.d_un.d_val = _dynamicStringTable->addString(soname);
+ _dynamicTable->addEntry(dyn);
+ }
+ // The dynamic symbol table need to be sorted earlier because the hash
+ // table needs to be built using the dynamic symbol table. It would be
+ // late to sort the symbols due to that in finalize. In the dynamic symbol
+ // table finalize, we call the symbol table finalize and we don't want to
+ // sort again
+ _dynamicSymbolTable->sortSymbols();
+
+ // Add the dynamic symbols into the hash table
+ _dynamicSymbolTable->addSymbolsToHashTable();
+}
+
+template <class ELFT>
+void OutputELFWriter<ELFT>::buildAtomToAddressMap(const File &file) {
+ ScopedTask task(getDefaultDomain(), "buildAtomToAddressMap");
+ int64_t totalAbsAtoms = _layout.absoluteAtoms().size();
+ int64_t totalUndefinedAtoms = file.undefined().size();
+ int64_t totalDefinedAtoms = 0;
+ for (auto sec : _layout.sections())
+ if (auto section = dyn_cast<AtomSection<ELFT> >(sec)) {
+ totalDefinedAtoms += section->atoms().size();
+ for (const auto &atom : section->atoms())
+ _atomToAddressMap[atom->_atom] = atom->_virtualAddr;
+ }
+ // build the atomToAddressMap that contains absolute symbols too
+ for (auto &atom : _layout.absoluteAtoms())
+ _atomToAddressMap[atom->_atom] = atom->_virtualAddr;
+
+ // Set the total number of atoms in the symbol table, so that appropriate
+ // resizing of the string table can be done
+ _symtab->setNumEntries(totalDefinedAtoms + totalAbsAtoms +
+ totalUndefinedAtoms);
+}
+
+template<class ELFT>
+void OutputELFWriter<ELFT>::buildSectionHeaderTable() {
+ ScopedTask task(getDefaultDomain(), "buildSectionHeaderTable");
+ for (auto outputSection : _layout.outputSections()) {
+ if (outputSection->kind() != Chunk<ELFT>::Kind::ELFSection &&
+ outputSection->kind() != Chunk<ELFT>::Kind::AtomSection)
+ continue;
+ if (outputSection->hasSegment())
+ _shdrtab->appendSection(outputSection);
+ }
+}
+
+template<class ELFT>
+void OutputELFWriter<ELFT>::assignSectionsWithNoSegments() {
+ ScopedTask task(getDefaultDomain(), "assignSectionsWithNoSegments");
+ for (auto outputSection : _layout.outputSections()) {
+ if (outputSection->kind() != Chunk<ELFT>::Kind::ELFSection &&
+ outputSection->kind() != Chunk<ELFT>::Kind::AtomSection)
+ continue;
+ if (!outputSection->hasSegment())
+ _shdrtab->appendSection(outputSection);
+ }
+ _layout.assignFileOffsetsForMiscSections();
+ for (auto sec : _layout.sections())
+ if (auto section = dyn_cast<Section<ELFT>>(sec))
+ if (!DefaultLayout<ELFT>::hasOutputSegment(section))
+ _shdrtab->updateSection(section);
+}
+
+template <class ELFT> void OutputELFWriter<ELFT>::addDefaultAtoms() {
+ const llvm::StringSet<> &symbols =
+ _context.linkerScriptSema().getScriptDefinedSymbols();
+ for (auto &sym : symbols)
+ _scriptFile->addAbsoluteAtom(sym.getKey());
+}
+
+template <class ELFT>
+bool OutputELFWriter<ELFT>::createImplicitFiles(
+ std::vector<std::unique_ptr<File>> &result) {
+ // Add the virtual archive to resolve undefined symbols.
+ // The file will be added later in the linking context.
+ auto callback = [this](StringRef sym, RuntimeFile<ELFT> &file) {
+ processUndefinedSymbol(sym, file);
+ };
+ auto &ctx = const_cast<ELFLinkingContext &>(_context);
+ ctx.setUndefinesResolver(
+ llvm::make_unique<DynamicSymbolFile<ELFT>>(ctx, std::move(callback)));
+ // Add script defined symbols
+ result.push_back(std::move(_scriptFile));
+ return true;
+}
+
+template <class ELFT>
+void OutputELFWriter<ELFT>::finalizeDefaultAtomValues() {
+ const llvm::StringSet<> &symbols =
+ _context.linkerScriptSema().getScriptDefinedSymbols();
+ for (auto &sym : symbols) {
+ uint64_t res =
+ _context.linkerScriptSema().getLinkerScriptExprValue(sym.getKey());
+ auto a = _layout.findAbsoluteAtom(sym.getKey());
+ (*a)->_virtualAddr = res;
+ }
+}
+
+template <class ELFT> void OutputELFWriter<ELFT>::createDefaultSections() {
+ _elfHeader.reset(new (_alloc) ELFHeader<ELFT>(_context));
+ _programHeader.reset(new (_alloc) ProgramHeader<ELFT>(_context));
+ _layout.setHeader(_elfHeader.get());
+ _layout.setProgramHeader(_programHeader.get());
+
+ _symtab = std::move(this->createSymbolTable());
+ _strtab.reset(new (_alloc) StringTable<ELFT>(
+ _context, ".strtab", DefaultLayout<ELFT>::ORDER_STRING_TABLE));
+ _shstrtab.reset(new (_alloc) StringTable<ELFT>(
+ _context, ".shstrtab", DefaultLayout<ELFT>::ORDER_SECTION_STRINGS));
+ _shdrtab.reset(new (_alloc) SectionHeader<ELFT>(
+ _context, DefaultLayout<ELFT>::ORDER_SECTION_HEADERS));
+ _layout.addSection(_symtab.get());
+ _layout.addSection(_strtab.get());
+ _layout.addSection(_shstrtab.get());
+ _shdrtab->setStringSection(_shstrtab.get());
+ _symtab->setStringSection(_strtab.get());
+ _layout.addSection(_shdrtab.get());
+
+ for (auto sec : _layout.sections()) {
+ // TODO: use findOutputSection
+ auto section = dyn_cast<Section<ELFT>>(sec);
+ if (!section || section->outputSectionName() != ".eh_frame")
+ continue;
+ _ehFrameHeader.reset(new (_alloc) EHFrameHeader<ELFT>(
+ _context, ".eh_frame_hdr", _layout,
+ DefaultLayout<ELFT>::ORDER_EH_FRAMEHDR));
+ _layout.addSection(_ehFrameHeader.get());
+ break;
+ }
+
+ if (_context.isDynamic()) {
+ _dynamicTable = std::move(createDynamicTable());
+ _dynamicStringTable.reset(new (_alloc) StringTable<ELFT>(
+ _context, ".dynstr", DefaultLayout<ELFT>::ORDER_DYNAMIC_STRINGS, true));
+ _dynamicSymbolTable = std::move(createDynamicSymbolTable());
+ _hashTable.reset(new (_alloc) HashSection<ELFT>(
+ _context, ".hash", DefaultLayout<ELFT>::ORDER_HASH));
+ // Set the hash table in the dynamic symbol table so that the entries in the
+ // hash table can be created
+ _dynamicSymbolTable->setHashTable(_hashTable.get());
+ _hashTable->setSymbolTable(_dynamicSymbolTable.get());
+ _layout.addSection(_dynamicTable.get());
+ _layout.addSection(_dynamicStringTable.get());
+ _layout.addSection(_dynamicSymbolTable.get());
+ _layout.addSection(_hashTable.get());
+ _dynamicSymbolTable->setStringSection(_dynamicStringTable.get());
+ _dynamicTable->setSymbolTable(_dynamicSymbolTable.get());
+ _dynamicTable->setHashTable(_hashTable.get());
+ if (_layout.hasDynamicRelocationTable())
+ _layout.getDynamicRelocationTable()->setSymbolTable(
+ _dynamicSymbolTable.get());
+ if (_layout.hasPLTRelocationTable())
+ _layout.getPLTRelocationTable()->setSymbolTable(
+ _dynamicSymbolTable.get());
+ }
+}
+
+template <class ELFT>
+unique_bump_ptr<SymbolTable<ELFT>>
+ OutputELFWriter<ELFT>::createSymbolTable() {
+ return unique_bump_ptr<SymbolTable<ELFT>>(new (_alloc) SymbolTable<ELFT>(
+ this->_context, ".symtab", DefaultLayout<ELFT>::ORDER_SYMBOL_TABLE));
+}
+
+/// \brief create dynamic table
+template <class ELFT>
+unique_bump_ptr<DynamicTable<ELFT>>
+ OutputELFWriter<ELFT>::createDynamicTable() {
+ return unique_bump_ptr<DynamicTable<ELFT>>(
+ new (_alloc) DynamicTable<ELFT>(
+ this->_context, _layout, ".dynamic", DefaultLayout<ELFT>::ORDER_DYNAMIC));
+}
+
+/// \brief create dynamic symbol table
+template <class ELFT>
+unique_bump_ptr<DynamicSymbolTable<ELFT>>
+ OutputELFWriter<ELFT>::createDynamicSymbolTable() {
+ return unique_bump_ptr<DynamicSymbolTable<ELFT>>(
+ new (_alloc) DynamicSymbolTable<ELFT>(
+ this->_context, _layout, ".dynsym",
+ DefaultLayout<ELFT>::ORDER_DYNAMIC_SYMBOLS));
+}
+
+template <class ELFT>
+std::error_code OutputELFWriter<ELFT>::buildOutput(const File &file) {
+ ScopedTask buildTask(getDefaultDomain(), "ELF Writer buildOutput");
+ buildChunks(file);
+
+ // Create the default sections like the symbol table, string table, and the
+ // section string table
+ createDefaultSections();
+
+ // Set the Layout
+ _layout.assignSectionsToSegments();
+
+ // Create the dynamic table entries
+ if (_context.isDynamic()) {
+ _dynamicTable->createDefaultEntries();
+ buildDynamicSymbolTable(file);
+ }
+
+ // Call the preFlight callbacks to modify the sections and the atoms
+ // contained in them, in anyway the targets may want
+ _layout.doPreFlight();
+
+ _layout.assignVirtualAddress();
+
+ // Finalize the default value of symbols that the linker adds
+ finalizeDefaultAtomValues();
+
+ // Build the Atom To Address map for applying relocations
+ buildAtomToAddressMap(file);
+
+ // Create symbol table and section string table
+ // Do it only if -s is not specified.
+ if (!_context.stripSymbols())
+ buildStaticSymbolTable(file);
+
+ // Finalize the layout by calling the finalize() functions
+ _layout.finalize();
+
+ // build Section Header table
+ buildSectionHeaderTable();
+
+ // assign Offsets and virtual addresses
+ // for sections with no segments
+ assignSectionsWithNoSegments();
+
+ if (_context.isDynamic())
+ _dynamicTable->updateDynamicTable();
+
+ return std::error_code();
+}
+
+template <class ELFT> std::error_code OutputELFWriter<ELFT>::setELFHeader() {
+ _elfHeader->e_type(_context.getOutputELFType());
+ _elfHeader->e_machine(_context.getOutputMachine());
+ _elfHeader->e_ident(ELF::EI_VERSION, 1);
+ _elfHeader->e_ident(ELF::EI_OSABI, 0);
+ _elfHeader->e_version(1);
+ _elfHeader->e_phoff(_programHeader->fileOffset());
+ _elfHeader->e_shoff(_shdrtab->fileOffset());
+ _elfHeader->e_phentsize(_programHeader->entsize());
+ _elfHeader->e_phnum(_programHeader->numHeaders());
+ _elfHeader->e_shentsize(_shdrtab->entsize());
+ _elfHeader->e_shnum(_shdrtab->numHeaders());
+ _elfHeader->e_shstrndx(_shstrtab->ordinal());
+ if (const auto *al = _layout.findAtomLayoutByName(_context.entrySymbolName()))
+ _elfHeader->e_entry(al->_virtualAddr);
+ else
+ _elfHeader->e_entry(0);
+
+ return std::error_code();
+}
+
+template <class ELFT> uint64_t OutputELFWriter<ELFT>::outputFileSize() const {
+ return _shdrtab->fileOffset() + _shdrtab->fileSize();
+}
+
+template <class ELFT>
+std::error_code OutputELFWriter<ELFT>::writeOutput(const File &file,
+ StringRef path) {
+ std::unique_ptr<FileOutputBuffer> buffer;
+ ScopedTask createOutputTask(getDefaultDomain(), "ELF Writer Create Output");
+ std::error_code ec = FileOutputBuffer::create(path, outputFileSize(), buffer,
+ FileOutputBuffer::F_executable);
+ createOutputTask.end();
+
+ if (ec)
+ return ec;
+
+ ScopedTask writeTask(getDefaultDomain(), "ELF Writer write to memory");
+
+ // HACK: We have to write out the header and program header here even though
+ // they are a member of a segment because only sections are written in the
+ // following loop.
+
+ // Finalize ELF Header / Program Headers.
+ _elfHeader->finalize();
+ _programHeader->finalize();
+
+ _elfHeader->write(this, _layout, *buffer);
+ _programHeader->write(this, _layout, *buffer);
+
+ auto sections = _layout.sections();
+ parallel_for_each(
+ sections.begin(), sections.end(),
+ [&](Chunk<ELFT> *section) { section->write(this, _layout, *buffer); });
+ writeTask.end();
+
+ ScopedTask commitTask(getDefaultDomain(), "ELF Writer commit to disk");
+ return buffer->commit();
+}
+
+template <class ELFT>
+std::error_code OutputELFWriter<ELFT>::writeFile(const File &file,
+ StringRef path) {
+ std::error_code ec = buildOutput(file);
+ if (ec)
+ return ec;
+
+ ec = setELFHeader();
+ if (ec)
+ return ec;
+
+ return writeOutput(file, path);
+}
+} // namespace elf
+} // namespace lld
+
+#endif // LLD_READER_WRITER_ELF_OUTPUT_WRITER_H
diff --git a/lib/ReaderWriter/ELF/Reader.cpp b/lib/ReaderWriter/ELF/Reader.cpp
new file mode 100644
index 000000000000..fc113d478913
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Reader.cpp
@@ -0,0 +1,43 @@
+//===- lib/ReaderWriter/ELF/Reader.cpp ------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Defines the ELF Reader and all helper sub classes to consume an ELF
+/// file and produces atoms out of it.
+///
+//===----------------------------------------------------------------------===//
+
+#include "ELFReader.h"
+#include <map>
+#include <vector>
+
+using llvm::support::endianness;
+using namespace llvm::object;
+
+namespace lld {
+
+// This dynamic registration of a handler causes support for all ELF
+// architectures to be pulled into the linker. If we want to support making a
+// linker that only supports one ELF architecture, we'd need to change this
+// to have a different registration method for each architecture.
+void Registry::addSupportELFObjects(ELFLinkingContext &ctx) {
+
+ // Tell registry about the ELF object file parser.
+ add(std::move(ctx.targetHandler()->getObjReader()));
+
+ // Tell registry about the relocation name to number mapping for this arch.
+ ctx.targetHandler()->registerRelocationNames(*this);
+}
+
+void Registry::addSupportELFDynamicSharedObjects(ELFLinkingContext &ctx) {
+ // Tell registry about the ELF dynamic shared library file parser.
+ add(ctx.targetHandler()->getDSOReader());
+}
+
+} // end namespace lld
diff --git a/lib/ReaderWriter/ELF/SectionChunks.h b/lib/ReaderWriter/ELF/SectionChunks.h
new file mode 100644
index 000000000000..03bdb59e6568
--- /dev/null
+++ b/lib/ReaderWriter/ELF/SectionChunks.h
@@ -0,0 +1,1498 @@
+//===- lib/ReaderWriter/ELF/SectionChunks.h -------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_SECTION_CHUNKS_H
+#define LLD_READER_WRITER_ELF_SECTION_CHUNKS_H
+
+#include "Chunk.h"
+#include "Layout.h"
+#include "TargetHandler.h"
+#include "Writer.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/Parallel.h"
+#include "lld/Core/range.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Dwarf.h"
+#include "llvm/Support/ELF.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include <memory>
+#include <mutex>
+
+namespace lld {
+namespace elf {
+template <class> class OutputSection;
+using namespace llvm::ELF;
+template <class ELFT> class Segment;
+
+/// \brief An ELF section.
+template <class ELFT> class Section : public Chunk<ELFT> {
+public:
+ Section(const ELFLinkingContext &context, StringRef sectionName,
+ StringRef chunkName,
+ typename Chunk<ELFT>::Kind k = Chunk<ELFT>::Kind::ELFSection)
+ : Chunk<ELFT>(chunkName, k, context), _outputSection(nullptr), _flags(0),
+ _entSize(0), _type(0), _link(0), _info(0),
+ _isFirstSectionInOutputSection(false), _segmentType(SHT_NULL),
+ _inputSectionName(sectionName), _outputSectionName(sectionName) {}
+
+ /// \brief Modify the section contents before assigning virtual addresses
+ // or assigning file offsets
+ void doPreFlight() override {}
+
+ /// \brief Finalize the section contents before writing
+ void finalize() override {}
+
+ /// \brief Does this section have an output segment.
+ virtual bool hasOutputSegment() {
+ return false;
+ }
+
+ /// Return if the section is a loadable section that occupies memory
+ virtual bool isLoadableSection() const { return false; }
+
+ /// \brief Assign file offsets starting at offset.
+ virtual void assignFileOffsets(uint64_t offset) {}
+
+ /// \brief Assign virtual addresses starting at addr.
+ virtual void assignVirtualAddress(uint64_t addr) {}
+
+ uint64_t getFlags() const { return _flags; }
+ uint64_t getEntSize() const { return _entSize; }
+ uint32_t getType() const { return _type; }
+ uint32_t getLink() const { return _link; }
+ uint32_t getInfo() const { return _info; }
+ Layout::SegmentType getSegmentType() const { return _segmentType; }
+
+ /// \brief Return the type of content that the section contains
+ virtual int getContentType() const override {
+ if (_flags & llvm::ELF::SHF_EXECINSTR)
+ return Chunk<ELFT>::ContentType::Code;
+ else if (_flags & llvm::ELF::SHF_WRITE)
+ return Chunk<ELFT>::ContentType::Data;
+ else if (_flags & llvm::ELF::SHF_ALLOC)
+ return Chunk<ELFT>::ContentType::Code;
+ else
+ return Chunk<ELFT>::ContentType::Unknown;
+ }
+
+ /// \brief convert the segment type to a String for diagnostics and printing
+ /// purposes
+ StringRef segmentKindToStr() const;
+
+ /// \brief Records the segmentType, that this section belongs to
+ void setSegmentType(const Layout::SegmentType segmentType) {
+ this->_segmentType = segmentType;
+ }
+
+ virtual const AtomLayout *findAtomLayoutByName(StringRef) const {
+ return nullptr;
+ }
+
+ void setOutputSection(OutputSection<ELFT> *os, bool isFirst = false) {
+ _outputSection = os;
+ _isFirstSectionInOutputSection = isFirst;
+ }
+
+ static bool classof(const Chunk<ELFT> *c) {
+ return c->kind() == Chunk<ELFT>::Kind::ELFSection ||
+ c->kind() == Chunk<ELFT>::Kind::AtomSection;
+ }
+
+ uint64_t alignment() const override {
+ return _isFirstSectionInOutputSection ? _outputSection->alignment()
+ : this->_alignment;
+ }
+
+ virtual StringRef inputSectionName() const { return _inputSectionName; }
+
+ virtual StringRef outputSectionName() const { return _outputSectionName; }
+
+ virtual void setOutputSectionName(StringRef outputSectionName) {
+ _outputSectionName = outputSectionName;
+ }
+
+ void setArchiveNameOrPath(StringRef name) { _archivePath = name; }
+
+ void setMemberNameOrPath(StringRef name) { _memberPath = name; }
+
+ StringRef archivePath() { return _archivePath; }
+
+ StringRef memberPath() { return _memberPath; }
+
+protected:
+ /// \brief OutputSection this Section is a member of, or nullptr.
+ OutputSection<ELFT> *_outputSection;
+ /// \brief ELF SHF_* flags.
+ uint64_t _flags;
+ /// \brief The size of each entity.
+ uint64_t _entSize;
+ /// \brief ELF SHT_* type.
+ uint32_t _type;
+ /// \brief sh_link field.
+ uint32_t _link;
+ /// \brief the sh_info field.
+ uint32_t _info;
+ /// \brief Is this the first section in the output section.
+ bool _isFirstSectionInOutputSection;
+ /// \brief the output ELF segment type of this section.
+ Layout::SegmentType _segmentType;
+ /// \brief Input section name.
+ StringRef _inputSectionName;
+ /// \brief Output section name.
+ StringRef _outputSectionName;
+ StringRef _archivePath;
+ StringRef _memberPath;
+};
+
+/// \brief A section containing atoms.
+template <class ELFT> class AtomSection : public Section<ELFT> {
+public:
+ AtomSection(const ELFLinkingContext &context, StringRef sectionName,
+ int32_t contentType, int32_t permissions, int32_t order)
+ : Section<ELFT>(context, sectionName, "AtomSection",
+ Chunk<ELFT>::Kind::AtomSection),
+ _contentType(contentType), _contentPermissions(permissions),
+ _isLoadedInMemory(true) {
+ this->setOrder(order);
+
+ switch (contentType) {
+ case DefinedAtom::typeCode:
+ case DefinedAtom::typeDataFast:
+ case DefinedAtom::typeData:
+ case DefinedAtom::typeConstant:
+ case DefinedAtom::typeGOT:
+ case DefinedAtom::typeStub:
+ case DefinedAtom::typeResolver:
+ case DefinedAtom::typeThreadData:
+ this->_type = SHT_PROGBITS;
+ break;
+
+ case DefinedAtom::typeThreadZeroFill:
+ case DefinedAtom::typeZeroFillFast:
+ case DefinedAtom::typeZeroFill:
+ this->_type = SHT_NOBITS;
+ break;
+
+ case DefinedAtom::typeRONote:
+ case DefinedAtom::typeRWNote:
+ this->_type = SHT_NOTE;
+ break;
+
+ case DefinedAtom::typeNoAlloc:
+ this->_type = SHT_PROGBITS;
+ this->_isLoadedInMemory = false;
+ break;
+ }
+
+ switch (permissions) {
+ case DefinedAtom::permR__:
+ this->_flags = SHF_ALLOC;
+ break;
+ case DefinedAtom::permR_X:
+ this->_flags = SHF_ALLOC | SHF_EXECINSTR;
+ break;
+ case DefinedAtom::permRW_:
+ case DefinedAtom::permRW_L:
+ this->_flags = SHF_ALLOC | SHF_WRITE;
+ if (_contentType == DefinedAtom::typeThreadData ||
+ _contentType == DefinedAtom::typeThreadZeroFill)
+ this->_flags |= SHF_TLS;
+ break;
+ case DefinedAtom::permRWX:
+ this->_flags = SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR;
+ break;
+ case DefinedAtom::perm___:
+ this->_flags = 0;
+ break;
+ }
+ }
+
+ /// Align the offset to the required modulus defined by the atom alignment
+ uint64_t alignOffset(uint64_t offset, DefinedAtom::Alignment &atomAlign);
+
+ /// Return if the section is a loadable section that occupies memory
+ bool isLoadableSection() const override { return _isLoadedInMemory; }
+
+ // \brief Append an atom to a Section. The atom gets pushed into a vector
+ // contains the atom, the atom file offset, the atom virtual address
+ // the atom file offset is aligned appropriately as set by the Reader
+ virtual const lld::AtomLayout *appendAtom(const Atom *atom);
+
+ /// \brief Set the virtual address of each Atom in the Section. This
+ /// routine gets called after the linker fixes up the virtual address
+ /// of the section
+ virtual void assignVirtualAddress(uint64_t addr) override {
+ parallel_for_each(_atoms.begin(), _atoms.end(), [&](AtomLayout *ai) {
+ ai->_virtualAddr = addr + ai->_fileOffset;
+ });
+ }
+
+ /// \brief Set the file offset of each Atom in the section. This routine
+ /// gets called after the linker fixes up the section offset
+ void assignFileOffsets(uint64_t offset) override {
+ parallel_for_each(_atoms.begin(), _atoms.end(), [&](AtomLayout *ai) {
+ ai->_fileOffset = offset + ai->_fileOffset;
+ });
+ }
+
+ /// \brief Find the Atom address given a name, this is needed to properly
+ /// apply relocation. The section class calls this to find the atom address
+ /// to fix the relocation
+ const AtomLayout *findAtomLayoutByName(StringRef name) const override {
+ for (auto ai : _atoms)
+ if (ai->_atom->name() == name)
+ return ai;
+ return nullptr;
+ }
+
+ /// \brief Return the raw flags, we need this to sort segments
+ int64_t atomflags() const { return _contentPermissions; }
+
+ /// Atom Iterators
+ typedef typename std::vector<lld::AtomLayout *>::iterator atom_iter;
+
+ range<atom_iter> atoms() { return _atoms; }
+
+ void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
+ llvm::FileOutputBuffer &buffer) override;
+
+ static bool classof(const Chunk<ELFT> *c) {
+ return c->kind() == Chunk<ELFT>::Kind::AtomSection;
+ }
+
+protected:
+ llvm::BumpPtrAllocator _alloc;
+ int32_t _contentType;
+ int32_t _contentPermissions;
+ bool _isLoadedInMemory;
+ std::vector<lld::AtomLayout *> _atoms;
+ mutable std::mutex _outputMutex;
+
+ void printError(const std::string &errorStr, const AtomLayout &atom,
+ const Reference &ref) const {
+ StringRef kindValStr;
+ if (!this->_context.registry().referenceKindToString(ref.kindNamespace(),
+ ref.kindArch(),
+ ref.kindValue(),
+ kindValStr)) {
+ kindValStr = "unknown";
+ }
+
+ std::string errStr = (Twine(errorStr) + " in file " +
+ atom._atom->file().path() +
+ ": reference from " + atom._atom->name() +
+ "+" + Twine(ref.offsetInAtom()) +
+ " to " + ref.target()->name() +
+ "+" + Twine(ref.addend()) +
+ " of type " + Twine(ref.kindValue()) +
+ " (" + kindValStr + ")\n").str();
+
+ // Take the lock to prevent output getting interleaved between threads
+ std::lock_guard<std::mutex> lock(_outputMutex);
+ llvm::errs() << errStr;
+ }
+};
+
+/// Align the offset to the required modulus defined by the atom alignment
+template <class ELFT>
+uint64_t AtomSection<ELFT>::alignOffset(uint64_t offset,
+ DefinedAtom::Alignment &atomAlign) {
+ uint64_t requiredModulus = atomAlign.modulus;
+ uint64_t alignment = 1u << atomAlign.powerOf2;
+ uint64_t currentModulus = (offset % alignment);
+ uint64_t retOffset = offset;
+ if (currentModulus != requiredModulus) {
+ if (requiredModulus > currentModulus)
+ retOffset += requiredModulus - currentModulus;
+ else
+ retOffset += alignment + requiredModulus - currentModulus;
+ }
+ return retOffset;
+}
+
+// \brief Append an atom to a Section. The atom gets pushed into a vector
+// contains the atom, the atom file offset, the atom virtual address
+// the atom file offset is aligned appropriately as set by the Reader
+template <class ELFT>
+const lld::AtomLayout *AtomSection<ELFT>::appendAtom(const Atom *atom) {
+ const DefinedAtom *definedAtom = cast<DefinedAtom>(atom);
+
+ DefinedAtom::Alignment atomAlign = definedAtom->alignment();
+ uint64_t alignment = 1u << atomAlign.powerOf2;
+ // Align the atom to the required modulus/ align the file offset and the
+ // memory offset separately this is required so that BSS symbols are handled
+ // properly as the BSS symbols only occupy memory size and not file size
+ uint64_t fOffset = alignOffset(this->fileSize(), atomAlign);
+ uint64_t mOffset = alignOffset(this->memSize(), atomAlign);
+ switch(definedAtom->contentType()) {
+ case DefinedAtom::typeCode:
+ case DefinedAtom::typeConstant:
+ case DefinedAtom::typeData:
+ case DefinedAtom::typeDataFast:
+ case DefinedAtom::typeZeroFillFast:
+ case DefinedAtom::typeGOT:
+ case DefinedAtom::typeStub:
+ case DefinedAtom::typeResolver:
+ case DefinedAtom::typeThreadData:
+ case DefinedAtom::typeRONote:
+ case DefinedAtom::typeRWNote:
+ _atoms.push_back(new (_alloc) lld::AtomLayout(atom, fOffset, 0));
+ this->_fsize = fOffset + definedAtom->size();
+ this->_msize = mOffset + definedAtom->size();
+ DEBUG_WITH_TYPE("Section",
+ llvm::dbgs() << "[" << this->name() << " " << this << "] "
+ << "Adding atom: " << atom->name() << "@"
+ << fOffset << "\n");
+ break;
+ case DefinedAtom::typeNoAlloc:
+ _atoms.push_back(new (_alloc) lld::AtomLayout(atom, fOffset, 0));
+ this->_fsize = fOffset + definedAtom->size();
+ DEBUG_WITH_TYPE("Section", llvm::dbgs() << "[" << this->name() << " "
+ << this << "] "
+ << "Adding atom: " << atom->name()
+ << "@" << fOffset << "\n");
+ break;
+ case DefinedAtom::typeThreadZeroFill:
+ case DefinedAtom::typeZeroFill:
+ _atoms.push_back(new (_alloc) lld::AtomLayout(atom, mOffset, 0));
+ this->_msize = mOffset + definedAtom->size();
+ break;
+ default:
+ llvm::dbgs() << definedAtom->contentType() << "\n";
+ llvm_unreachable("Uexpected content type.");
+ }
+ // Set the section alignment to the largest alignment
+ // std::max doesn't support uint64_t
+ if (this->_alignment < alignment)
+ this->_alignment = alignment;
+
+ if (_atoms.size())
+ return _atoms.back();
+ return nullptr;
+}
+
+/// \brief convert the segment type to a String for diagnostics
+/// and printing purposes
+template <class ELFT> StringRef Section<ELFT>::segmentKindToStr() const {
+ switch(_segmentType) {
+ case llvm::ELF::PT_DYNAMIC:
+ return "DYNAMIC";
+ case llvm::ELF::PT_INTERP:
+ return "INTERP";
+ case llvm::ELF::PT_LOAD:
+ return "LOAD";
+ case llvm::ELF::PT_GNU_EH_FRAME:
+ return "EH_FRAME";
+ case llvm::ELF::PT_GNU_RELRO:
+ return "GNU_RELRO";
+ case llvm::ELF::PT_NOTE:
+ return "NOTE";
+ case llvm::ELF::PT_NULL:
+ return "NULL";
+ case llvm::ELF::PT_TLS:
+ return "TLS";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+/// \brief Write the section and the atom contents to the buffer
+template <class ELFT>
+void AtomSection<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout,
+ llvm::FileOutputBuffer &buffer) {
+ uint8_t *chunkBuffer = buffer.getBufferStart();
+ bool success = true;
+ parallel_for_each(_atoms.begin(), _atoms.end(), [&](lld::AtomLayout * ai) {
+ DEBUG_WITH_TYPE("Section",
+ llvm::dbgs() << "Writing atom: " << ai->_atom->name()
+ << " | " << ai->_fileOffset << "\n");
+ const DefinedAtom *definedAtom = cast<DefinedAtom>(ai->_atom);
+ if (!definedAtom->occupiesDiskSpace())
+ return;
+ // Copy raw content of atom to file buffer.
+ ArrayRef<uint8_t> content = definedAtom->rawContent();
+ uint64_t contentSize = content.size();
+ if (contentSize == 0)
+ return;
+ uint8_t *atomContent = chunkBuffer + ai->_fileOffset;
+ std::memcpy(atomContent, content.data(), contentSize);
+ const TargetRelocationHandler &relHandler =
+ this->_context.template getTargetHandler<ELFT>().getRelocationHandler();
+ for (const auto ref : *definedAtom) {
+ if (std::error_code ec = relHandler.applyRelocation(*writer, buffer,
+ *ai, *ref)) {
+ printError(ec.message(), *ai, *ref);
+ success = false;
+ }
+ }
+ });
+ if (!success)
+ llvm::report_fatal_error("relocating output");
+}
+
+/// \brief A OutputSection represents a set of sections grouped by the same
+/// name. The output file that gets written by the linker has sections grouped
+/// by similar names
+template <class ELFT> class OutputSection {
+public:
+ // Iterators
+ typedef typename std::vector<Chunk<ELFT> *>::iterator ChunkIter;
+
+ OutputSection(StringRef name);
+
+ // Appends a section into the list of sections that are part of this Output
+ // Section
+ void appendSection(Chunk<ELFT> *c);
+
+ // Set the OutputSection is associated with a segment
+ void setHasSegment() { _hasSegment = true; }
+
+ /// Sets the ordinal
+ void setOrdinal(uint64_t ordinal) { _ordinal = ordinal; }
+
+ /// Sets the Memory size
+ void setMemSize(uint64_t memsz) { _memSize = memsz; }
+
+ /// Sets the size fo the output Section.
+ void setSize(uint64_t fsiz) { _size = fsiz; }
+
+ // The offset of the first section contained in the output section is
+ // contained here.
+ void setFileOffset(uint64_t foffset) { _fileOffset = foffset; }
+
+ // Sets the starting address of the section
+ void setAddr(uint64_t addr) { _virtualAddr = addr; }
+
+ // Is the section loadable?
+ bool isLoadableSection() const { return _isLoadableSection; }
+
+ // Set section Loadable
+ void setLoadableSection(bool isLoadable) {
+ _isLoadableSection = isLoadable;
+ }
+
+ void setLink(uint64_t link) { _link = link; }
+
+ void setInfo(uint64_t info) { _shInfo = info; }
+
+ void setFlag(uint64_t flags) { _flags = flags; }
+
+ void setType(int16_t type) { _type = type; }
+
+ range<ChunkIter> sections() { return _sections; }
+
+ // The below functions returns the properties of the OutputSection.
+ bool hasSegment() const { return _hasSegment; }
+
+ StringRef name() const { return _name; }
+
+ int64_t shinfo() const { return _shInfo; }
+
+ uint64_t alignment() const { return _alignment; }
+
+ int64_t link() const { return _link; }
+
+ int64_t type() const { return _type; }
+
+ uint64_t virtualAddr() const { return _virtualAddr; }
+
+ int64_t ordinal() const { return _ordinal; }
+
+ int64_t kind() const { return _kind; }
+
+ uint64_t fileSize() const { return _size; }
+
+ int64_t entsize() const { return _entSize; }
+
+ uint64_t fileOffset() const { return _fileOffset; }
+
+ int64_t flags() const { return _flags; }
+
+ uint64_t memSize() { return _memSize; }
+
+private:
+ StringRef _name;
+ bool _hasSegment;
+ uint64_t _ordinal;
+ uint64_t _flags;
+ uint64_t _size;
+ uint64_t _memSize;
+ uint64_t _fileOffset;
+ uint64_t _virtualAddr;
+ int64_t _shInfo;
+ int64_t _entSize;
+ int64_t _link;
+ uint64_t _alignment;
+ int64_t _kind;
+ int64_t _type;
+ bool _isLoadableSection;
+ std::vector<Chunk<ELFT> *> _sections;
+};
+
+/// OutputSection
+template <class ELFT>
+OutputSection<ELFT>::OutputSection(StringRef name)
+ : _name(name), _hasSegment(false), _ordinal(0), _flags(0), _size(0),
+ _memSize(0), _fileOffset(0), _virtualAddr(0), _shInfo(0), _entSize(0),
+ _link(0), _alignment(0), _kind(0), _type(0), _isLoadableSection(false) {}
+
+template <class ELFT> void OutputSection<ELFT>::appendSection(Chunk<ELFT> *c) {
+ if (c->alignment() > _alignment)
+ _alignment = c->alignment();
+ if (const auto section = dyn_cast<Section<ELFT>>(c)) {
+ assert(!_link && "Section already has a link!");
+ _link = section->getLink();
+ _shInfo = section->getInfo();
+ _entSize = section->getEntSize();
+ _type = section->getType();
+ if (_flags < section->getFlags())
+ _flags = section->getFlags();
+ section->setOutputSection(this, (_sections.size() == 0));
+ }
+ _kind = c->kind();
+ _sections.push_back(c);
+}
+
+/// \brief The class represents the ELF String Table
+template<class ELFT>
+class StringTable : public Section<ELFT> {
+public:
+ StringTable(const ELFLinkingContext &, const char *str, int32_t order,
+ bool dynamic = false);
+
+ uint64_t addString(StringRef symname);
+
+ void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
+ llvm::FileOutputBuffer &buffer) override;
+
+ void setNumEntries(int64_t numEntries) { _stringMap.resize(numEntries); }
+
+private:
+ std::vector<StringRef> _strings;
+
+ struct StringRefMappingInfo {
+ static StringRef getEmptyKey() { return StringRef(); }
+ static StringRef getTombstoneKey() { return StringRef(" ", 1); }
+ static unsigned getHashValue(StringRef const val) {
+ return llvm::HashString(val);
+ }
+ static bool isEqual(StringRef const lhs, StringRef const rhs) {
+ return lhs.equals(rhs);
+ }
+ };
+ typedef typename llvm::DenseMap<StringRef, uint64_t,
+ StringRefMappingInfo> StringMapT;
+ typedef typename StringMapT::iterator StringMapTIter;
+ StringMapT _stringMap;
+};
+
+template <class ELFT>
+StringTable<ELFT>::StringTable(const ELFLinkingContext &context,
+ const char *str, int32_t order, bool dynamic)
+ : Section<ELFT>(context, str, "StringTable") {
+ // the string table has a NULL entry for which
+ // add an empty string
+ _strings.push_back("");
+ this->_fsize = 1;
+ this->_alignment = 1;
+ this->setOrder(order);
+ this->_type = SHT_STRTAB;
+ if (dynamic) {
+ this->_flags = SHF_ALLOC;
+ this->_msize = this->_fsize;
+ }
+}
+
+template <class ELFT> uint64_t StringTable<ELFT>::addString(StringRef symname) {
+ if (symname.empty())
+ return 0;
+ StringMapTIter stringIter = _stringMap.find(symname);
+ if (stringIter == _stringMap.end()) {
+ _strings.push_back(symname);
+ uint64_t offset = this->_fsize;
+ this->_fsize += symname.size() + 1;
+ if (this->_flags & SHF_ALLOC)
+ this->_msize = this->_fsize;
+ _stringMap[symname] = offset;
+ return offset;
+ }
+ return stringIter->second;
+}
+
+template <class ELFT>
+void StringTable<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &,
+ llvm::FileOutputBuffer &buffer) {
+ uint8_t *chunkBuffer = buffer.getBufferStart();
+ uint8_t *dest = chunkBuffer + this->fileOffset();
+ for (auto si : _strings) {
+ memcpy(dest, si.data(), si.size());
+ dest += si.size();
+ memcpy(dest, "", 1);
+ dest += 1;
+ }
+}
+
+/// \brief The SymbolTable class represents the symbol table in a ELF file
+template<class ELFT>
+class SymbolTable : public Section<ELFT> {
+ typedef typename llvm::object::ELFDataTypeTypedefHelper<ELFT>::Elf_Addr
+ Elf_Addr;
+
+public:
+ typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+
+ SymbolTable(const ELFLinkingContext &context, const char *str, int32_t order);
+
+ /// \brief set the number of entries that would exist in the symbol
+ /// table for the current link
+ void setNumEntries(int64_t numEntries) const {
+ if (_stringSection)
+ _stringSection->setNumEntries(numEntries);
+ }
+
+ /// \brief return number of entries
+ std::size_t size() const { return _symbolTable.size(); }
+
+ void addSymbol(const Atom *atom, int32_t sectionIndex, uint64_t addr = 0,
+ const lld::AtomLayout *layout = nullptr);
+
+ /// \brief Get the symbol table index for an Atom. If it's not in the symbol
+ /// table, return STN_UNDEF.
+ uint32_t getSymbolTableIndex(const Atom *a) const {
+ for (size_t i = 0, e = _symbolTable.size(); i < e; ++i)
+ if (_symbolTable[i]._atom == a)
+ return i;
+ return STN_UNDEF;
+ }
+
+ void finalize() override { finalize(true); }
+
+ virtual void sortSymbols() {
+ std::stable_sort(_symbolTable.begin(), _symbolTable.end(),
+ [](const SymbolEntry & A, const SymbolEntry & B) {
+ return A._symbol.getBinding() < B._symbol.getBinding();
+ });
+ }
+
+ virtual void addAbsoluteAtom(Elf_Sym &sym, const AbsoluteAtom *aa,
+ int64_t addr);
+
+ virtual void addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da,
+ int64_t addr);
+
+ virtual void addUndefinedAtom(Elf_Sym &sym, const UndefinedAtom *ua);
+
+ virtual void addSharedLibAtom(Elf_Sym &sym, const SharedLibraryAtom *sla);
+
+ virtual void finalize(bool sort);
+
+ void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
+ llvm::FileOutputBuffer &buffer) override;
+
+ void setStringSection(StringTable<ELFT> *s) { _stringSection = s; }
+
+ StringTable<ELFT> *getStringTable() const { return _stringSection; }
+
+protected:
+ struct SymbolEntry {
+ SymbolEntry(const Atom *a, const Elf_Sym &sym,
+ const lld::AtomLayout *layout)
+ : _atom(a), _atomLayout(layout), _symbol(sym) {}
+
+ const Atom *_atom;
+ const lld::AtomLayout *_atomLayout;
+ Elf_Sym _symbol;
+ };
+
+ llvm::BumpPtrAllocator _symbolAllocate;
+ StringTable<ELFT> *_stringSection;
+ std::vector<SymbolEntry> _symbolTable;
+};
+
+/// ELF Symbol Table
+template <class ELFT>
+SymbolTable<ELFT>::SymbolTable(const ELFLinkingContext &context,
+ const char *str, int32_t order)
+ : Section<ELFT>(context, str, "SymbolTable") {
+ this->setOrder(order);
+ Elf_Sym symbol;
+ std::memset(&symbol, 0, sizeof(Elf_Sym));
+ _symbolTable.push_back(SymbolEntry(nullptr, symbol, nullptr));
+ this->_entSize = sizeof(Elf_Sym);
+ this->_fsize = sizeof(Elf_Sym);
+ this->_alignment = sizeof(Elf_Addr);
+ this->_type = SHT_SYMTAB;
+}
+
+template <class ELFT>
+void SymbolTable<ELFT>::addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da,
+ int64_t addr) {
+ unsigned char binding = 0, type = 0;
+ sym.st_size = da->size();
+ DefinedAtom::ContentType ct;
+ switch (ct = da->contentType()) {
+ case DefinedAtom::typeCode:
+ case DefinedAtom::typeStub:
+ sym.st_value = addr;
+ type = llvm::ELF::STT_FUNC;
+ break;
+ case DefinedAtom::typeResolver:
+ sym.st_value = addr;
+ type = llvm::ELF::STT_GNU_IFUNC;
+ break;
+ case DefinedAtom::typeDataFast:
+ case DefinedAtom::typeData:
+ case DefinedAtom::typeConstant:
+ sym.st_value = addr;
+ type = llvm::ELF::STT_OBJECT;
+ break;
+ case DefinedAtom::typeGOT:
+ sym.st_value = addr;
+ type = llvm::ELF::STT_NOTYPE;
+ break;
+ case DefinedAtom::typeZeroFill:
+ case DefinedAtom::typeZeroFillFast:
+ type = llvm::ELF::STT_OBJECT;
+ sym.st_value = addr;
+ break;
+ case DefinedAtom::typeThreadData:
+ case DefinedAtom::typeThreadZeroFill:
+ type = llvm::ELF::STT_TLS;
+ sym.st_value = addr;
+ break;
+ default:
+ type = llvm::ELF::STT_NOTYPE;
+ }
+ if (da->customSectionName() == da->name())
+ type = llvm::ELF::STT_SECTION;
+
+ if (da->scope() == DefinedAtom::scopeTranslationUnit)
+ binding = llvm::ELF::STB_LOCAL;
+ else
+ binding = llvm::ELF::STB_GLOBAL;
+
+ sym.setBindingAndType(binding, type);
+}
+
+template <class ELFT>
+void SymbolTable<ELFT>::addAbsoluteAtom(Elf_Sym &sym, const AbsoluteAtom *aa,
+ int64_t addr) {
+ unsigned char binding = 0, type = 0;
+ type = llvm::ELF::STT_OBJECT;
+ sym.st_shndx = llvm::ELF::SHN_ABS;
+ switch (aa->scope()) {
+ case AbsoluteAtom::scopeLinkageUnit:
+ sym.setVisibility(llvm::ELF::STV_HIDDEN);
+ binding = llvm::ELF::STB_LOCAL;
+ break;
+ case AbsoluteAtom::scopeTranslationUnit:
+ binding = llvm::ELF::STB_LOCAL;
+ break;
+ case AbsoluteAtom::scopeGlobal:
+ binding = llvm::ELF::STB_GLOBAL;
+ break;
+ }
+ sym.st_value = addr;
+ sym.setBindingAndType(binding, type);
+}
+
+template <class ELFT>
+void SymbolTable<ELFT>::addSharedLibAtom(Elf_Sym &sym,
+ const SharedLibraryAtom *aa) {
+ unsigned char binding = 0, type = 0;
+ if (aa->type() == SharedLibraryAtom::Type::Data) {
+ type = llvm::ELF::STT_OBJECT;
+ sym.st_size = aa->size();
+ } else
+ type = llvm::ELF::STT_FUNC;
+ sym.st_shndx = llvm::ELF::SHN_UNDEF;
+ binding = llvm::ELF::STB_GLOBAL;
+ sym.setBindingAndType(binding, type);
+}
+
+template <class ELFT>
+void SymbolTable<ELFT>::addUndefinedAtom(Elf_Sym &sym,
+ const UndefinedAtom *ua) {
+ unsigned char binding = 0, type = 0;
+ sym.st_value = 0;
+ type = llvm::ELF::STT_NOTYPE;
+ if (ua->canBeNull())
+ binding = llvm::ELF::STB_WEAK;
+ else
+ binding = llvm::ELF::STB_GLOBAL;
+ sym.setBindingAndType(binding, type);
+}
+
+/// Add a symbol to the symbol Table, definedAtoms which get added to the symbol
+/// section don't have their virtual addresses set at the time of adding the
+/// symbol to the symbol table(Example: dynamic symbols), the addresses needs
+/// to be updated in the table before writing the dynamic symbol table
+/// information
+template <class ELFT>
+void SymbolTable<ELFT>::addSymbol(const Atom *atom, int32_t sectionIndex,
+ uint64_t addr,
+ const lld::AtomLayout *atomLayout) {
+ Elf_Sym symbol;
+
+ if (atom->name().empty())
+ return;
+
+ symbol.st_name = _stringSection->addString(atom->name());
+ symbol.st_size = 0;
+ symbol.st_shndx = sectionIndex;
+ symbol.st_value = 0;
+ symbol.st_other = 0;
+ symbol.setVisibility(llvm::ELF::STV_DEFAULT);
+
+ // Add all the atoms
+ if (const DefinedAtom *da = dyn_cast<const DefinedAtom>(atom))
+ addDefinedAtom(symbol, da, addr);
+ else if (const AbsoluteAtom *aa = dyn_cast<const AbsoluteAtom>(atom))
+ addAbsoluteAtom(symbol, aa, addr);
+ else if (isa<const SharedLibraryAtom>(atom))
+ addSharedLibAtom(symbol, dyn_cast<SharedLibraryAtom>(atom));
+ else
+ addUndefinedAtom(symbol, dyn_cast<UndefinedAtom>(atom));
+
+ _symbolTable.push_back(SymbolEntry(atom, symbol, atomLayout));
+ this->_fsize += sizeof(Elf_Sym);
+ if (this->_flags & SHF_ALLOC)
+ this->_msize = this->_fsize;
+}
+
+template <class ELFT> void SymbolTable<ELFT>::finalize(bool sort) {
+ // sh_info should be one greater than last symbol with STB_LOCAL binding
+ // we sort the symbol table to keep all local symbols at the beginning
+ if (sort)
+ sortSymbols();
+
+ uint16_t shInfo = 0;
+ for (const auto &i : _symbolTable) {
+ if (i._symbol.getBinding() != llvm::ELF::STB_LOCAL)
+ break;
+ shInfo++;
+ }
+ this->_info = shInfo;
+ this->_link = _stringSection->ordinal();
+ if (this->_outputSection) {
+ this->_outputSection->setInfo(this->_info);
+ this->_outputSection->setLink(this->_link);
+ }
+}
+
+template <class ELFT>
+void SymbolTable<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &,
+ llvm::FileOutputBuffer &buffer) {
+ uint8_t *chunkBuffer = buffer.getBufferStart();
+ uint8_t *dest = chunkBuffer + this->fileOffset();
+ for (const auto &sti : _symbolTable) {
+ memcpy(dest, &sti._symbol, sizeof(Elf_Sym));
+ dest += sizeof(Elf_Sym);
+ }
+}
+
+template <class ELFT> class HashSection;
+
+template <class ELFT> class DynamicSymbolTable : public SymbolTable<ELFT> {
+public:
+ DynamicSymbolTable(const ELFLinkingContext &context,
+ TargetLayout<ELFT> &layout, const char *str, int32_t order)
+ : SymbolTable<ELFT>(context, str, order), _hashTable(nullptr),
+ _layout(layout) {
+ this->_type = SHT_DYNSYM;
+ this->_flags = SHF_ALLOC;
+ this->_msize = this->_fsize;
+ }
+
+ // Set the dynamic hash table for symbols to be added into
+ void setHashTable(HashSection<ELFT> *hashTable) { _hashTable = hashTable; }
+
+ // Add all the dynamic symbos to the hash table
+ void addSymbolsToHashTable() {
+ int index = 0;
+ for (auto &ste : this->_symbolTable) {
+ if (!ste._atom)
+ _hashTable->addSymbol("", index);
+ else
+ _hashTable->addSymbol(ste._atom->name(), index);
+ ++index;
+ }
+ }
+
+ void finalize() override {
+ // Defined symbols which have been added into the dynamic symbol table
+ // don't have their addresses known until addresses have been assigned
+ // so let's update the symbol values after they have got assigned
+ for (auto &ste: this->_symbolTable) {
+ const lld::AtomLayout *atomLayout = ste._atomLayout;
+ if (!atomLayout)
+ continue;
+ ste._symbol.st_value = atomLayout->_virtualAddr;
+ }
+
+ // Don't sort the symbols
+ SymbolTable<ELFT>::finalize(false);
+ }
+
+protected:
+ HashSection<ELFT> *_hashTable;
+ TargetLayout<ELFT> &_layout;
+};
+
+template <class ELFT> class RelocationTable : public Section<ELFT> {
+public:
+ typedef llvm::object::Elf_Rel_Impl<ELFT, false> Elf_Rel;
+ typedef llvm::object::Elf_Rel_Impl<ELFT, true> Elf_Rela;
+
+ RelocationTable(const ELFLinkingContext &context, StringRef str,
+ int32_t order)
+ : Section<ELFT>(context, str, "RelocationTable"), _symbolTable(nullptr) {
+ this->setOrder(order);
+ this->_flags = SHF_ALLOC;
+ // Set the alignment properly depending on the target architecture
+ this->_alignment = ELFT::Is64Bits ? 8 : 4;
+ if (context.isRelaOutputFormat()) {
+ this->_entSize = sizeof(Elf_Rela);
+ this->_type = SHT_RELA;
+ } else {
+ this->_entSize = sizeof(Elf_Rel);
+ this->_type = SHT_REL;
+ }
+ }
+
+ /// \returns the index of the relocation added.
+ uint32_t addRelocation(const DefinedAtom &da, const Reference &r) {
+ _relocs.emplace_back(&da, &r);
+ this->_fsize = _relocs.size() * this->_entSize;
+ this->_msize = this->_fsize;
+ return _relocs.size() - 1;
+ }
+
+ bool getRelocationIndex(const Reference &r, uint32_t &res) {
+ auto rel = std::find_if(
+ _relocs.begin(), _relocs.end(),
+ [&](const std::pair<const DefinedAtom *, const Reference *> &p) {
+ if (p.second == &r)
+ return true;
+ return false;
+ });
+ if (rel == _relocs.end())
+ return false;
+ res = std::distance(_relocs.begin(), rel);
+ return true;
+ }
+
+ void setSymbolTable(const DynamicSymbolTable<ELFT> *symbolTable) {
+ _symbolTable = symbolTable;
+ }
+
+ /// \brief Check if any relocation modifies a read-only section.
+ bool canModifyReadonlySection() const {
+ for (const auto &rel : _relocs) {
+ const DefinedAtom *atom = rel.first;
+ if ((atom->permissions() & DefinedAtom::permRW_) != DefinedAtom::permRW_)
+ return true;
+ }
+ return false;
+ }
+
+ void finalize() override {
+ this->_link = _symbolTable ? _symbolTable->ordinal() : 0;
+ if (this->_outputSection)
+ this->_outputSection->setLink(this->_link);
+ }
+
+ void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
+ llvm::FileOutputBuffer &buffer) override {
+ uint8_t *chunkBuffer = buffer.getBufferStart();
+ uint8_t *dest = chunkBuffer + this->fileOffset();
+ for (const auto &rel : _relocs) {
+ if (this->_context.isRelaOutputFormat()) {
+ auto &r = *reinterpret_cast<Elf_Rela *>(dest);
+ writeRela(writer, r, *rel.first, *rel.second);
+ DEBUG_WITH_TYPE("ELFRelocationTable",
+ llvm::dbgs()
+ << rel.second->kindValue() << " relocation at "
+ << rel.first->name() << "@" << r.r_offset << " to "
+ << rel.second->target()->name() << "@" << r.r_addend
+ << "\n";);
+ } else {
+ auto &r = *reinterpret_cast<Elf_Rel *>(dest);
+ writeRel(writer, r, *rel.first, *rel.second);
+ DEBUG_WITH_TYPE("ELFRelocationTable",
+ llvm::dbgs() << rel.second->kindValue()
+ << " relocation at " << rel.first->name()
+ << "@" << r.r_offset << " to "
+ << rel.second->target()->name() << "\n";);
+ }
+ dest += this->_entSize;
+ }
+ }
+
+protected:
+ const DynamicSymbolTable<ELFT> *_symbolTable;
+
+ virtual void writeRela(ELFWriter *writer, Elf_Rela &r,
+ const DefinedAtom &atom, const Reference &ref) {
+ r.setSymbolAndType(getSymbolIndex(ref.target()), ref.kindValue(), false);
+ r.r_offset = writer->addressOfAtom(&atom) + ref.offsetInAtom();
+ // The addend is used only by relative relocations
+ if (this->_context.isRelativeReloc(ref))
+ r.r_addend = writer->addressOfAtom(ref.target()) + ref.addend();
+ else
+ r.r_addend = 0;
+ }
+
+ virtual void writeRel(ELFWriter *writer, Elf_Rel &r, const DefinedAtom &atom,
+ const Reference &ref) {
+ r.setSymbolAndType(getSymbolIndex(ref.target()), ref.kindValue(), false);
+ r.r_offset = writer->addressOfAtom(&atom) + ref.offsetInAtom();
+ }
+
+ uint32_t getSymbolIndex(const Atom *a) {
+ return _symbolTable ? _symbolTable->getSymbolTableIndex(a)
+ : (uint32_t)STN_UNDEF;
+ }
+
+private:
+ std::vector<std::pair<const DefinedAtom *, const Reference *> > _relocs;
+};
+
+template <class ELFT> class HashSection;
+
+template <class ELFT> class DynamicTable : public Section<ELFT> {
+public:
+ typedef llvm::object::Elf_Dyn_Impl<ELFT> Elf_Dyn;
+ typedef std::vector<Elf_Dyn> EntriesT;
+
+ DynamicTable(const ELFLinkingContext &context, TargetLayout<ELFT> &layout,
+ StringRef str, int32_t order)
+ : Section<ELFT>(context, str, "DynamicSection"), _layout(layout) {
+ this->setOrder(order);
+ this->_entSize = sizeof(Elf_Dyn);
+ this->_alignment = ELFT::Is64Bits ? 8 : 4;
+ // Reserve space for the DT_NULL entry.
+ this->_fsize = sizeof(Elf_Dyn);
+ this->_msize = sizeof(Elf_Dyn);
+ this->_type = SHT_DYNAMIC;
+ this->_flags = SHF_ALLOC;
+ }
+
+ range<typename EntriesT::iterator> entries() { return _entries; }
+
+ /// \returns the index of the entry.
+ std::size_t addEntry(Elf_Dyn e) {
+ _entries.push_back(e);
+ this->_fsize = (_entries.size() * sizeof(Elf_Dyn)) + sizeof(Elf_Dyn);
+ this->_msize = this->_fsize;
+ return _entries.size() - 1;
+ }
+
+ void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
+ llvm::FileOutputBuffer &buffer) override {
+ uint8_t *chunkBuffer = buffer.getBufferStart();
+ uint8_t *dest = chunkBuffer + this->fileOffset();
+ // Add the null entry.
+ Elf_Dyn d;
+ d.d_tag = 0;
+ d.d_un.d_val = 0;
+ _entries.push_back(d);
+ std::memcpy(dest, _entries.data(), this->_fsize);
+ }
+
+ virtual void createDefaultEntries() {
+ bool isRela = this->_context.isRelaOutputFormat();
+
+ Elf_Dyn dyn;
+ dyn.d_un.d_val = 0;
+
+ dyn.d_tag = DT_HASH;
+ _dt_hash = addEntry(dyn);
+ dyn.d_tag = DT_STRTAB;
+ _dt_strtab = addEntry(dyn);
+ dyn.d_tag = DT_SYMTAB;
+ _dt_symtab = addEntry(dyn);
+ dyn.d_tag = DT_STRSZ;
+ _dt_strsz = addEntry(dyn);
+ dyn.d_tag = DT_SYMENT;
+ _dt_syment = addEntry(dyn);
+ if (_layout.hasDynamicRelocationTable()) {
+ dyn.d_tag = isRela ? DT_RELA : DT_REL;
+ _dt_rela = addEntry(dyn);
+ dyn.d_tag = isRela ? DT_RELASZ : DT_RELSZ;
+ _dt_relasz = addEntry(dyn);
+ dyn.d_tag = isRela ? DT_RELAENT : DT_RELENT;
+ _dt_relaent = addEntry(dyn);
+
+ if (_layout.getDynamicRelocationTable()->canModifyReadonlySection()) {
+ dyn.d_tag = DT_TEXTREL;
+ _dt_textrel = addEntry(dyn);
+ }
+ }
+ if (_layout.hasPLTRelocationTable()) {
+ dyn.d_tag = DT_PLTRELSZ;
+ _dt_pltrelsz = addEntry(dyn);
+ dyn.d_tag = getGotPltTag();
+ _dt_pltgot = addEntry(dyn);
+ dyn.d_tag = DT_PLTREL;
+ dyn.d_un.d_val = isRela ? DT_RELA : DT_REL;
+ _dt_pltrel = addEntry(dyn);
+ dyn.d_un.d_val = 0;
+ dyn.d_tag = DT_JMPREL;
+ _dt_jmprel = addEntry(dyn);
+ }
+ }
+
+ void doPreFlight() override {
+ Elf_Dyn dyn;
+ dyn.d_un.d_val = 0;
+ auto initArray = _layout.findOutputSection(".init_array");
+ auto finiArray = _layout.findOutputSection(".fini_array");
+ if (initArray) {
+ dyn.d_tag = DT_INIT_ARRAY;
+ _dt_init_array = addEntry(dyn);
+ dyn.d_tag = DT_INIT_ARRAYSZ;
+ _dt_init_arraysz = addEntry(dyn);
+ }
+ if (finiArray) {
+ dyn.d_tag = DT_FINI_ARRAY;
+ _dt_fini_array = addEntry(dyn);
+ dyn.d_tag = DT_FINI_ARRAYSZ;
+ _dt_fini_arraysz = addEntry(dyn);
+ }
+ if (getInitAtomLayout()) {
+ dyn.d_tag = DT_INIT;
+ _dt_init = addEntry(dyn);
+ }
+ if (getFiniAtomLayout()) {
+ dyn.d_tag = DT_FINI;
+ _dt_fini = addEntry(dyn);
+ }
+ }
+
+ /// \brief Dynamic table tag for .got.plt section referencing.
+ /// Usually but not always targets use DT_PLTGOT for that.
+ virtual int64_t getGotPltTag() { return DT_PLTGOT; }
+
+ void finalize() override {
+ StringTable<ELFT> *dynamicStringTable =
+ _dynamicSymbolTable->getStringTable();
+ this->_link = dynamicStringTable->ordinal();
+ if (this->_outputSection) {
+ this->_outputSection->setType(this->_type);
+ this->_outputSection->setInfo(this->_info);
+ this->_outputSection->setLink(this->_link);
+ }
+ }
+
+ void setSymbolTable(DynamicSymbolTable<ELFT> *dynsym) {
+ _dynamicSymbolTable = dynsym;
+ }
+
+ const DynamicSymbolTable<ELFT> *getSymbolTable() const {
+ return _dynamicSymbolTable;
+ }
+
+ void setHashTable(HashSection<ELFT> *hsh) { _hashTable = hsh; }
+
+ virtual void updateDynamicTable() {
+ StringTable<ELFT> *dynamicStringTable =
+ _dynamicSymbolTable->getStringTable();
+ _entries[_dt_hash].d_un.d_val = _hashTable->virtualAddr();
+ _entries[_dt_strtab].d_un.d_val = dynamicStringTable->virtualAddr();
+ _entries[_dt_symtab].d_un.d_val = _dynamicSymbolTable->virtualAddr();
+ _entries[_dt_strsz].d_un.d_val = dynamicStringTable->memSize();
+ _entries[_dt_syment].d_un.d_val = _dynamicSymbolTable->getEntSize();
+ auto initArray = _layout.findOutputSection(".init_array");
+ if (initArray) {
+ _entries[_dt_init_array].d_un.d_val = initArray->virtualAddr();
+ _entries[_dt_init_arraysz].d_un.d_val = initArray->memSize();
+ }
+ auto finiArray = _layout.findOutputSection(".fini_array");
+ if (finiArray) {
+ _entries[_dt_fini_array].d_un.d_val = finiArray->virtualAddr();
+ _entries[_dt_fini_arraysz].d_un.d_val = finiArray->memSize();
+ }
+ if (const auto *al = getInitAtomLayout())
+ _entries[_dt_init].d_un.d_val = getAtomVirtualAddress(al);
+ if (const auto *al = getFiniAtomLayout())
+ _entries[_dt_fini].d_un.d_val = getAtomVirtualAddress(al);
+ if (_layout.hasDynamicRelocationTable()) {
+ auto relaTbl = _layout.getDynamicRelocationTable();
+ _entries[_dt_rela].d_un.d_val = relaTbl->virtualAddr();
+ _entries[_dt_relasz].d_un.d_val = relaTbl->memSize();
+ _entries[_dt_relaent].d_un.d_val = relaTbl->getEntSize();
+ }
+ if (_layout.hasPLTRelocationTable()) {
+ auto relaTbl = _layout.getPLTRelocationTable();
+ _entries[_dt_jmprel].d_un.d_val = relaTbl->virtualAddr();
+ _entries[_dt_pltrelsz].d_un.d_val = relaTbl->memSize();
+ auto gotplt = _layout.findOutputSection(".got.plt");
+ _entries[_dt_pltgot].d_un.d_val = gotplt->virtualAddr();
+ }
+ }
+
+protected:
+ EntriesT _entries;
+
+ /// \brief Return a virtual address (maybe adjusted) for the atom layout
+ /// Some targets like microMIPS and ARM Thumb use the last bit
+ /// of a symbol's value to mark 'compressed' code. This function allows
+ /// to adjust a virtal address before using it in the dynamic table tag.
+ virtual uint64_t getAtomVirtualAddress(const AtomLayout *al) const {
+ return al->_virtualAddr;
+ }
+
+private:
+ std::size_t _dt_hash;
+ std::size_t _dt_strtab;
+ std::size_t _dt_symtab;
+ std::size_t _dt_rela;
+ std::size_t _dt_relasz;
+ std::size_t _dt_relaent;
+ std::size_t _dt_strsz;
+ std::size_t _dt_syment;
+ std::size_t _dt_pltrelsz;
+ std::size_t _dt_pltgot;
+ std::size_t _dt_pltrel;
+ std::size_t _dt_jmprel;
+ std::size_t _dt_init_array;
+ std::size_t _dt_init_arraysz;
+ std::size_t _dt_fini_array;
+ std::size_t _dt_fini_arraysz;
+ std::size_t _dt_textrel;
+ std::size_t _dt_init;
+ std::size_t _dt_fini;
+ TargetLayout<ELFT> &_layout;
+ DynamicSymbolTable<ELFT> *_dynamicSymbolTable;
+ HashSection<ELFT> *_hashTable;
+
+ const AtomLayout *getInitAtomLayout() {
+ auto al = _layout.findAtomLayoutByName(this->_context.initFunction());
+ if (al && isa<DefinedAtom>(al->_atom))
+ return al;
+ return nullptr;
+ }
+
+ const AtomLayout *getFiniAtomLayout() {
+ auto al = _layout.findAtomLayoutByName(this->_context.finiFunction());
+ if (al && isa<DefinedAtom>(al->_atom))
+ return al;
+ return nullptr;
+ }
+};
+
+template <class ELFT> class InterpSection : public Section<ELFT> {
+public:
+ InterpSection(const ELFLinkingContext &context, StringRef str, int32_t order,
+ StringRef interp)
+ : Section<ELFT>(context, str, "Dynamic:Interp"), _interp(interp) {
+ this->setOrder(order);
+ this->_alignment = 1;
+ // + 1 for null term.
+ this->_fsize = interp.size() + 1;
+ this->_msize = this->_fsize;
+ this->_type = SHT_PROGBITS;
+ this->_flags = SHF_ALLOC;
+ }
+
+ void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
+ llvm::FileOutputBuffer &buffer) {
+ uint8_t *chunkBuffer = buffer.getBufferStart();
+ uint8_t *dest = chunkBuffer + this->fileOffset();
+ std::memcpy(dest, _interp.data(), _interp.size());
+ }
+
+private:
+ StringRef _interp;
+};
+
+/// The hash table in the dynamic linker is organized into
+///
+/// [ nbuckets ]
+/// [ nchains ]
+/// [ buckets[0] ]
+/// .........................
+/// [ buckets[nbuckets-1] ]
+/// [ chains[0] ]
+/// .........................
+/// [ chains[nchains - 1] ]
+///
+/// nbuckets - total number of hash buckets
+/// nchains is equal to the number of dynamic symbols.
+///
+/// The symbol is searched by the dynamic linker using the below approach.
+/// * Calculate the hash of the symbol that needs to be searched
+/// * Take the value from the buckets[hash % nbuckets] as the index of symbol
+/// * Compare the symbol's name, if true return, if false, look through the
+/// * array since there was a collision
+
+template <class ELFT> class HashSection : public Section<ELFT> {
+ struct SymbolTableEntry {
+ StringRef _name;
+ uint32_t _index;
+ };
+
+public:
+ HashSection(const ELFLinkingContext &context, StringRef name, int32_t order)
+ : Section<ELFT>(context, name, "Dynamic:Hash"), _symbolTable(nullptr) {
+ this->setOrder(order);
+ this->_entSize = 4;
+ this->_type = SHT_HASH;
+ this->_flags = SHF_ALLOC;
+ this->_alignment = ELFT::Is64Bits ? 8 : 4;
+ this->_fsize = 0;
+ this->_msize = 0;
+ }
+
+ /// \brief add the dynamic symbol into the table so that the
+ /// hash could be calculated
+ void addSymbol(StringRef name, uint32_t index) {
+ SymbolTableEntry ste;
+ ste._name = name;
+ ste._index = index;
+ _entries.push_back(ste);
+ }
+
+ /// \brief Set the dynamic symbol table
+ void setSymbolTable(const DynamicSymbolTable<ELFT> *symbolTable) {
+ _symbolTable = symbolTable;
+ }
+
+ // The size of the section has to be determined so that fileoffsets
+ // may be properly assigned. Let's calculate the buckets and the chains
+ // and fill the chains and the buckets hash table used by the dynamic
+ // linker and update the filesize and memory size accordingly
+ void doPreFlight() override {
+ // The number of buckets to use for a certain number of symbols.
+ // If there are less than 3 symbols, 1 bucket will be used. If
+ // there are less than 17 symbols, 3 buckets will be used, and so
+ // forth. The bucket numbers are defined by GNU ld. We use the
+ // same rules here so we generate hash sections with the same
+ // size as those generated by GNU ld.
+ uint32_t hashBuckets[] = { 1, 3, 17, 37, 67, 97, 131, 197, 263, 521, 1031,
+ 2053, 4099, 8209, 16411, 32771, 65537, 131101,
+ 262147 };
+ int hashBucketsCount = sizeof(hashBuckets) / sizeof(uint32_t);
+
+ unsigned int bucketsCount = 0;
+ unsigned int dynSymCount = _entries.size();
+
+ // Get the number of buckes that we want to use
+ for (int i = 0; i < hashBucketsCount; ++i) {
+ if (dynSymCount < hashBuckets[i])
+ break;
+ bucketsCount = hashBuckets[i];
+ }
+ _buckets.resize(bucketsCount);
+ _chains.resize(_entries.size());
+
+ // Create the hash table for the dynamic linker
+ for (auto ai : _entries) {
+ unsigned int dynsymIndex = ai._index;
+ unsigned int bucketpos = llvm::object::elf_hash(ai._name) % bucketsCount;
+ _chains[dynsymIndex] = _buckets[bucketpos];
+ _buckets[bucketpos] = dynsymIndex;
+ }
+
+ this->_fsize = (2 + _chains.size() + _buckets.size()) * sizeof(uint32_t);
+ this->_msize = this->_fsize;
+ }
+
+ void finalize() override {
+ this->_link = _symbolTable ? _symbolTable->ordinal() : 0;
+ if (this->_outputSection)
+ this->_outputSection->setLink(this->_link);
+ }
+
+ void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
+ llvm::FileOutputBuffer &buffer) override {
+ uint8_t *chunkBuffer = buffer.getBufferStart();
+ uint8_t *dest = chunkBuffer + this->fileOffset();
+ uint32_t bucketChainCounts[2];
+ bucketChainCounts[0] = _buckets.size();
+ bucketChainCounts[1] = _chains.size();
+ std::memcpy(dest, (char *)bucketChainCounts, sizeof(bucketChainCounts));
+ dest += sizeof(bucketChainCounts);
+ // write bucket values
+ for (auto bi : _buckets) {
+ uint32_t val = (bi);
+ std::memcpy(dest, &val, sizeof(uint32_t));
+ dest += sizeof(uint32_t);
+ }
+ // write chain values
+ for (auto ci : _chains) {
+ uint32_t val = (ci);
+ std::memcpy(dest, &val, sizeof(uint32_t));
+ dest += sizeof(uint32_t);
+ }
+ }
+
+private:
+ std::vector<SymbolTableEntry> _entries;
+ std::vector<uint32_t> _buckets;
+ std::vector<uint32_t> _chains;
+ const DynamicSymbolTable<ELFT> *_symbolTable;
+};
+
+template <class ELFT> class EHFrameHeader : public Section<ELFT> {
+public:
+ EHFrameHeader(const ELFLinkingContext &context, StringRef name,
+ TargetLayout<ELFT> &layout, int32_t order)
+ : Section<ELFT>(context, name, "EHFrameHeader"), _ehFrameOffset(0),
+ _layout(layout) {
+ this->setOrder(order);
+ this->_entSize = 0;
+ this->_type = SHT_PROGBITS;
+ this->_flags = SHF_ALLOC;
+ this->_alignment = ELFT::Is64Bits ? 8 : 4;
+ // Minimum size for empty .eh_frame_hdr.
+ this->_fsize = 1 + 1 + 1 + 1 + 4;
+ this->_msize = this->_fsize;
+ }
+
+ void doPreFlight() override {
+ // TODO: Generate a proper binary search table.
+ }
+
+ void finalize() override {
+ OutputSection<ELFT> *s = _layout.findOutputSection(".eh_frame");
+ OutputSection<ELFT> *h = _layout.findOutputSection(".eh_frame_hdr");
+ if (s && h)
+ _ehFrameOffset = s->virtualAddr() - (h->virtualAddr() + 4);
+ }
+
+ void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
+ llvm::FileOutputBuffer &buffer) override {
+ uint8_t *chunkBuffer = buffer.getBufferStart();
+ uint8_t *dest = chunkBuffer + this->fileOffset();
+ int pos = 0;
+ dest[pos++] = 1; // version
+ dest[pos++] = llvm::dwarf::DW_EH_PE_pcrel |
+ llvm::dwarf::DW_EH_PE_sdata4; // eh_frame_ptr_enc
+ dest[pos++] = llvm::dwarf::DW_EH_PE_omit; // fde_count_enc
+ dest[pos++] = llvm::dwarf::DW_EH_PE_omit; // table_enc
+ *reinterpret_cast<typename llvm::object::ELFFile<ELFT>::Elf_Sword *>(
+ dest + pos) = _ehFrameOffset;
+ }
+
+private:
+ int32_t _ehFrameOffset;
+ TargetLayout<ELFT> &_layout;
+};
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/SegmentChunks.h b/lib/ReaderWriter/ELF/SegmentChunks.h
new file mode 100644
index 000000000000..f2a975aaeed0
--- /dev/null
+++ b/lib/ReaderWriter/ELF/SegmentChunks.h
@@ -0,0 +1,686 @@
+//===- lib/ReaderWriter/ELF/SegmentChunks.h -------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_SEGMENT_CHUNKS_H
+#define LLD_READER_WRITER_ELF_SEGMENT_CHUNKS_H
+
+#include "Chunk.h"
+#include "Layout.h"
+#include "SectionChunks.h"
+#include "Writer.h"
+#include "lld/Core/range.h"
+#include "lld/Core/Writer.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ELF.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include <memory>
+
+namespace lld {
+namespace elf {
+
+template <typename ELFT> class DefaultLayout;
+
+/// \brief A segment can be divided into segment slices
+/// depending on how the segments can be split
+template<class ELFT>
+class SegmentSlice {
+public:
+ typedef typename std::vector<Chunk<ELFT> *>::iterator SectionIter;
+
+ SegmentSlice() { }
+
+ /// Set the start of the slice.
+ void setStart(int32_t s) { _startSection = s; }
+
+ // Set the segment slice start and end iterators. This is used to walk through
+ // the sections that are part of the Segment slice
+ void setSections(range<SectionIter> sections) { _sections = sections; }
+
+ // Return the fileOffset of the slice
+ uint64_t fileOffset() const { return _offset; }
+
+ void setFileOffset(uint64_t offset) { _offset = offset; }
+
+ // Return the size of the slice
+ uint64_t fileSize() const { return _fsize; }
+
+ void setFileSize(uint64_t filesz) { _fsize = filesz; }
+
+ // Return the start of the slice
+ int32_t startSection() const { return _startSection; }
+
+ // Return the start address of the slice
+ uint64_t virtualAddr() const { return _addr; }
+
+ // Return the memory size of the slice
+ uint64_t memSize() const { return _memSize; }
+
+ // Return the alignment of the slice
+ uint64_t alignment() const { return _alignment; }
+
+ void setMemSize(uint64_t memsz) { _memSize = memsz; }
+
+ void setVirtualAddr(uint64_t addr) { _addr = addr; }
+
+ void setAlign(uint64_t align) { _alignment = align; }
+
+ static bool compare_slices(SegmentSlice<ELFT> *a, SegmentSlice<ELFT> *b) {
+ return a->startSection() < b->startSection();
+ }
+
+ range<SectionIter> sections() { return _sections; }
+
+private:
+ range<SectionIter> _sections;
+ int32_t _startSection;
+ uint64_t _addr;
+ uint64_t _offset;
+ uint64_t _alignment;
+ uint64_t _fsize;
+ uint64_t _memSize;
+};
+
+/// \brief A segment contains a set of sections, that have similar properties
+// the sections are already separated based on different flags and properties
+// the segment is just a way to concatenate sections to segments
+template<class ELFT>
+class Segment : public Chunk<ELFT> {
+public:
+ typedef typename std::vector<SegmentSlice<ELFT> *>::iterator SliceIter;
+ typedef typename std::vector<Chunk<ELFT> *>::iterator SectionIter;
+
+ Segment(const ELFLinkingContext &context, StringRef name,
+ const Layout::SegmentType type);
+
+ /// \brief the Order of segments that appear in the output file
+ enum SegmentOrder {
+ permUnknown,
+ permRWX,
+ permRX,
+ permR,
+ permRWL,
+ permRW,
+ permNonAccess
+ };
+
+ /// append a section to a segment
+ virtual void append(Chunk<ELFT> *chunk);
+
+ /// Sort segments depending on the property
+ /// If we have a Program Header segment, it should appear first
+ /// If we have a INTERP segment, that should appear after the Program Header
+ /// All Loadable segments appear next in this order
+ /// All Read Write Execute segments follow
+ /// All Read Execute segments appear next
+ /// All Read only segments appear first
+ /// All Write execute segments follow
+ static bool compareSegments(Segment<ELFT> *sega, Segment<ELFT> *segb);
+
+ /// \brief Start assigning file offset to the segment chunks The fileoffset
+ /// needs to be page at the start of the segment and in addition the
+ /// fileoffset needs to be aligned to the max section alignment within the
+ /// segment. This is required so that the ELF property p_poffset % p_align =
+ /// p_vaddr mod p_align holds true.
+ /// The algorithm starts off by assigning the startOffset thats passed in as
+ /// parameter to the first section in the segment, if the difference between
+ /// the newly computed offset is greater than a page, then we create a segment
+ /// slice, as it would be a waste of virtual memory just to be filled with
+ /// zeroes
+ void assignFileOffsets(uint64_t startOffset);
+
+ /// \brief Assign virtual addresses to the slices
+ void assignVirtualAddress(uint64_t addr);
+
+ // Write the Segment
+ void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
+ llvm::FileOutputBuffer &buffer);
+
+ int64_t flags() const;
+
+ /// Prepend a generic chunk to the segment.
+ void prepend(Chunk<ELFT> *c) {
+ _sections.insert(_sections.begin(), c);
+ }
+
+ /// Finalize the segment before assigning File Offsets / Virtual addresses
+ void doPreFlight() {}
+
+ /// Finalize the segment, before we want to write the segment header
+ /// information
+ void finalize() {
+ // We want to finalize the segment values for now only for non loadable
+ // segments, since those values are not set in the Layout
+ if (_segmentType == llvm::ELF::PT_LOAD)
+ return;
+ // The size is the difference of the
+ // last section to the first section, especially for TLS because
+ // the TLS segment contains both .tdata/.tbss
+ this->setFileOffset(_sections.front()->fileOffset());
+ this->setVirtualAddr(_sections.front()->virtualAddr());
+ size_t startFileOffset = _sections.front()->fileOffset();
+ size_t startAddr = _sections.front()->virtualAddr();
+ for (auto ai : _sections) {
+ this->_fsize = ai->fileOffset() + ai->fileSize() - startFileOffset;
+ this->_msize = ai->virtualAddr() + ai->memSize() - startAddr;
+ }
+ }
+
+ // For LLVM RTTI
+ static bool classof(const Chunk<ELFT> *c) {
+ return c->kind() == Chunk<ELFT>::Kind::ELFSegment;
+ }
+
+ // Getters
+ int32_t sectionCount() const { return _sections.size(); }
+
+ /// \brief, this function returns the type of segment (PT_*)
+ Layout::SegmentType segmentType() { return _segmentType; }
+
+ /// \brief return the segment type depending on the content,
+ /// If the content corresponds to Code, this will return Segment::Code
+ /// If the content corresponds to Data, this will return Segment::Data
+ /// If the content corresponds to TLS, this will return Segment::TLS
+ virtual int getContentType() const {
+ int64_t fl = flags();
+ switch (_segmentType) {
+ case llvm::ELF::PT_LOAD: {
+ if (fl && llvm::ELF::PF_X)
+ return Chunk<ELFT>::ContentType::Code;
+ if (fl && llvm::ELF::PF_W)
+ return Chunk<ELFT>::ContentType::Data;
+ }
+ case llvm::ELF::PT_TLS:
+ return Chunk<ELFT>::ContentType::TLS;
+ case llvm::ELF::PT_NOTE:
+ return Chunk<ELFT>::ContentType::Note;
+ default:
+ return Chunk<ELFT>::ContentType::Unknown;
+ }
+ }
+
+ int pageSize() const { return this->_context.getPageSize(); }
+
+ int rawflags() const { return _atomflags; }
+
+ int64_t atomflags() const {
+ switch (_atomflags) {
+
+ case DefinedAtom::permUnknown:
+ return permUnknown;
+
+ case DefinedAtom::permRWX:
+ return permRWX;
+
+ case DefinedAtom::permR_X:
+ return permRX;
+
+ case DefinedAtom::permR__:
+ return permR;
+
+ case DefinedAtom::permRW_L:
+ return permRWL;
+
+ case DefinedAtom::permRW_:
+ return permRW;
+
+ case DefinedAtom::perm___:
+ default:
+ return permNonAccess;
+ }
+ }
+
+ int64_t numSlices() const { return _segmentSlices.size(); }
+
+ range<SliceIter> slices() { return _segmentSlices; }
+
+ Chunk<ELFT> *firstSection() { return _sections[0]; }
+
+private:
+
+ /// \brief Check if the chunk needs to be aligned
+ bool needAlign(Chunk<ELFT> *chunk) const {
+ if (chunk->getContentType() == Chunk<ELFT>::ContentType::Data &&
+ _outputMagic == ELFLinkingContext::OutputMagic::NMAGIC)
+ return true;
+ return false;
+ }
+
+ // Cached value of outputMagic
+ ELFLinkingContext::OutputMagic _outputMagic;
+
+protected:
+ /// \brief Section or some other chunk type.
+ std::vector<Chunk<ELFT> *> _sections;
+ std::vector<SegmentSlice<ELFT> *> _segmentSlices;
+ Layout::SegmentType _segmentType;
+ uint64_t _flags;
+ int64_t _atomflags;
+ llvm::BumpPtrAllocator _segmentAllocate;
+};
+
+/// This chunk represents a linker script expression that needs to be calculated
+/// at the time the virtual addresses for the parent segment are being assigned.
+template <class ELFT> class ExpressionChunk : public Chunk<ELFT> {
+public:
+ ExpressionChunk(ELFLinkingContext &ctx, const script::SymbolAssignment *expr)
+ : Chunk<ELFT>(StringRef(), Chunk<ELFT>::Kind::Expression, ctx),
+ _expr(expr), _linkerScriptSema(ctx.linkerScriptSema()) {
+ this->_alignment = 1;
+ }
+
+ static bool classof(const Chunk<ELFT> *c) {
+ return c->kind() == Chunk<ELFT>::Kind::Expression;
+ }
+
+ int getContentType() const override {
+ return Chunk<ELFT>::ContentType::Unknown;
+ }
+ void write(ELFWriter *, TargetLayout<ELFT> &,
+ llvm::FileOutputBuffer &) override {}
+ void doPreFlight() override {}
+ void finalize() override {}
+
+ std::error_code evalExpr(uint64_t &curPos) {
+ return _linkerScriptSema.evalExpr(_expr, curPos);
+ }
+
+private:
+ const script::SymbolAssignment *_expr;
+ script::Sema &_linkerScriptSema;
+};
+
+/// \brief A Program Header segment contains a set of chunks instead of sections
+/// The segment doesn't contain any slice
+template <class ELFT> class ProgramHeaderSegment : public Segment<ELFT> {
+public:
+ ProgramHeaderSegment(const ELFLinkingContext &context)
+ : Segment<ELFT>(context, "PHDR", llvm::ELF::PT_PHDR) {
+ this->_alignment = 8;
+ this->_flags = (llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR);
+ }
+
+ /// Finalize the segment, before we want to write the segment header
+ /// information
+ void finalize() {
+ // If the segment is of type Program Header, then the values fileOffset
+ // and the fileSize need to be picked up from the last section, the first
+ // section points to the ELF header and the second chunk points to the
+ // actual program headers
+ this->setFileOffset(this->_sections.back()->fileOffset());
+ this->setVirtualAddr(this->_sections.back()->virtualAddr());
+ this->_fsize = this->_sections.back()->fileSize();
+ this->_msize = this->_sections.back()->memSize();
+ }
+
+};
+
+template <class ELFT>
+Segment<ELFT>::Segment(const ELFLinkingContext &context, StringRef name,
+ const Layout::SegmentType type)
+ : Chunk<ELFT>(name, Chunk<ELFT>::Kind::ELFSegment, context),
+ _segmentType(type), _flags(0), _atomflags(0) {
+ this->_alignment = 0;
+ this->_fsize = 0;
+ _outputMagic = context.getOutputMagic();
+}
+
+// This function actually is used, but not in all instantiations of Segment.
+LLVM_ATTRIBUTE_UNUSED
+static DefinedAtom::ContentPermissions toAtomPerms(uint64_t flags) {
+ switch (flags & (SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR)) {
+ case SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR:
+ return DefinedAtom::permRWX;
+ case SHF_ALLOC | SHF_EXECINSTR:
+ return DefinedAtom::permR_X;
+ case SHF_ALLOC:
+ return DefinedAtom::permR__;
+ case SHF_ALLOC | SHF_WRITE:
+ return DefinedAtom::permRW_;
+ default:
+ return DefinedAtom::permUnknown;
+ }
+}
+
+template <class ELFT> void Segment<ELFT>::append(Chunk<ELFT> *chunk) {
+ _sections.push_back(chunk);
+ Section<ELFT> *section = dyn_cast<Section<ELFT>>(chunk);
+ if (!section)
+ return;
+ if (_flags < section->getFlags())
+ _flags |= section->getFlags();
+ if (_atomflags < toAtomPerms(_flags))
+ _atomflags = toAtomPerms(_flags);
+ if (this->_alignment < section->alignment())
+ this->_alignment = section->alignment();
+}
+
+template <class ELFT>
+bool Segment<ELFT>::compareSegments(Segment<ELFT> *sega, Segment<ELFT> *segb) {
+ int64_t type1 = sega->segmentType();
+ int64_t type2 = segb->segmentType();
+
+ if (type1 == type2)
+ return sega->atomflags() < segb->atomflags();
+
+ // The single PT_PHDR segment is required to precede any loadable
+ // segment. We simply make it always first.
+ if (type1 == llvm::ELF::PT_PHDR)
+ return true;
+ if (type2 == llvm::ELF::PT_PHDR)
+ return false;
+
+ // The single PT_INTERP segment is required to precede any loadable
+ // segment. We simply make it always second.
+ if (type1 == llvm::ELF::PT_INTERP)
+ return true;
+ if (type2 == llvm::ELF::PT_INTERP)
+ return false;
+
+ // We then put PT_LOAD segments before any other segments.
+ if (type1 == llvm::ELF::PT_LOAD)
+ return true;
+ if (type2 == llvm::ELF::PT_LOAD)
+ return false;
+
+ // We put the PT_GNU_RELRO segment last, because that is where the
+ // dynamic linker expects to find it
+ if (type1 == llvm::ELF::PT_GNU_RELRO)
+ return false;
+ if (type2 == llvm::ELF::PT_GNU_RELRO)
+ return true;
+
+ // We put the PT_TLS segment last except for the PT_GNU_RELRO
+ // segment, because that is where the dynamic linker expects to find
+ if (type1 == llvm::ELF::PT_TLS)
+ return false;
+ if (type2 == llvm::ELF::PT_TLS)
+ return true;
+
+ // Otherwise compare the types to establish an arbitrary ordering.
+ // FIXME: Should figure out if we should just make all other types compare
+ // equal, but if so, we should probably do the same for atom flags and change
+ // users of this to use stable_sort.
+ return type1 < type2;
+}
+
+template <class ELFT>
+void Segment<ELFT>::assignFileOffsets(uint64_t startOffset) {
+ uint64_t fileOffset = startOffset;
+ uint64_t curSliceFileOffset = fileOffset;
+ bool isDataPageAlignedForNMagic = false;
+ bool alignSegments = this->_context.alignSegments();
+ uint64_t p_align = this->_context.getPageSize();
+ uint64_t lastVirtualAddress = 0;
+
+ this->setFileOffset(startOffset);
+ for (auto &slice : slices()) {
+ bool isFirstSection = true;
+ for (auto section : slice->sections()) {
+ // Handle linker script expressions, which may change the offset
+ if (!isFirstSection)
+ if (auto expr = dyn_cast<ExpressionChunk<ELFT>>(section))
+ fileOffset += expr->virtualAddr() - lastVirtualAddress;
+ // Align fileoffset to the alignment of the section.
+ fileOffset = llvm::RoundUpToAlignment(fileOffset, section->alignment());
+ // If the linker outputmagic is set to OutputMagic::NMAGIC, align the Data
+ // to a page boundary
+ if (isFirstSection &&
+ _outputMagic != ELFLinkingContext::OutputMagic::NMAGIC &&
+ _outputMagic != ELFLinkingContext::OutputMagic::OMAGIC) {
+ // Align to a page only if the output is not
+ // OutputMagic::NMAGIC/OutputMagic::OMAGIC
+ if (alignSegments)
+ fileOffset = llvm::RoundUpToAlignment(fileOffset, p_align);
+ else {
+ // Align according to ELF spec.
+ // in p75, http://www.sco.com/developers/devspecs/gabi41.pdf
+ uint64_t virtualAddress = slice->virtualAddr();
+ Section<ELFT> *sect = dyn_cast<Section<ELFT>>(section);
+ if (sect && sect->isLoadableSection() &&
+ ((virtualAddress & (p_align - 1)) !=
+ (fileOffset & (p_align - 1))))
+ fileOffset = llvm::RoundUpToAlignment(fileOffset, p_align) +
+ (virtualAddress % p_align);
+ }
+ } else if (!isDataPageAlignedForNMagic && needAlign(section)) {
+ fileOffset =
+ llvm::RoundUpToAlignment(fileOffset, this->_context.getPageSize());
+ isDataPageAlignedForNMagic = true;
+ }
+ if (isFirstSection) {
+ slice->setFileOffset(fileOffset);
+ isFirstSection = false;
+ curSliceFileOffset = fileOffset;
+ }
+ section->setFileOffset(fileOffset);
+ fileOffset += section->fileSize();
+ lastVirtualAddress = section->virtualAddr() + section->memSize();
+ }
+ slice->setFileSize(fileOffset - curSliceFileOffset);
+ }
+ this->setFileSize(fileOffset - startOffset);
+}
+
+/// \brief Assign virtual addresses to the slices
+template <class ELFT> void Segment<ELFT>::assignVirtualAddress(uint64_t addr) {
+ int startSection = 0;
+ int currSection = 0;
+ SectionIter startSectionIter;
+
+ // slice align is set to the max alignment of the chunks that are
+ // contained in the slice
+ uint64_t sliceAlign = 0;
+ // Current slice size
+ uint64_t curSliceSize = 0;
+ // Current Slice File Offset
+ uint64_t curSliceAddress = 0;
+
+ startSectionIter = _sections.begin();
+ startSection = 0;
+ bool isFirstSection = true;
+ bool isDataPageAlignedForNMagic = false;
+ uint64_t startAddr = addr;
+ SegmentSlice<ELFT> *slice = nullptr;
+ uint64_t tlsStartAddr = 0;
+ bool alignSegments = this->_context.alignSegments();
+ StringRef prevOutputSectionName = StringRef();
+
+ for (auto si = _sections.begin(); si != _sections.end(); ++si) {
+ // If this is first section in the segment, page align the section start
+ // address. The linker needs to align the data section to a page boundary
+ // only if NMAGIC is set.
+ if (isFirstSection) {
+ isFirstSection = false;
+ if (alignSegments &&
+ _outputMagic != ELFLinkingContext::OutputMagic::NMAGIC &&
+ _outputMagic != ELFLinkingContext::OutputMagic::OMAGIC)
+ // Align to a page only if the output is not
+ // OutputMagic::NMAGIC/OutputMagic::OMAGIC
+ startAddr =
+ llvm::RoundUpToAlignment(startAddr, this->_context.getPageSize());
+ else if (!isDataPageAlignedForNMagic && needAlign(*si)) {
+ // If the linker outputmagic is set to OutputMagic::NMAGIC, align the
+ // Data to a page boundary.
+ startAddr =
+ llvm::RoundUpToAlignment(startAddr, this->_context.getPageSize());
+ isDataPageAlignedForNMagic = true;
+ }
+ // align the startOffset to the section alignment
+ uint64_t newAddr = llvm::RoundUpToAlignment(startAddr, (*si)->alignment());
+ // Handle linker script expressions, which *may update newAddr* if the
+ // expression assigns to "."
+ if (auto expr = dyn_cast<ExpressionChunk<ELFT>>(*si))
+ expr->evalExpr(newAddr);
+ curSliceAddress = newAddr;
+ sliceAlign = (*si)->alignment();
+ (*si)->setVirtualAddr(curSliceAddress);
+
+ // Handle TLS.
+ if (auto section = dyn_cast<Section<ELFT>>(*si)) {
+ if (section->getSegmentType() == llvm::ELF::PT_TLS) {
+ tlsStartAddr =
+ llvm::RoundUpToAlignment(tlsStartAddr, (*si)->alignment());
+ section->assignVirtualAddress(tlsStartAddr);
+ tlsStartAddr += (*si)->memSize();
+ } else {
+ section->assignVirtualAddress(newAddr);
+ }
+ }
+ // TBSS section is special in that it doesn't contribute to memory of any
+ // segment. If we see a tbss section, don't add memory size to addr The
+ // fileOffset is automatically taken care of since TBSS section does not
+ // end up using file size
+ if ((*si)->order() != DefaultLayout<ELFT>::ORDER_TBSS)
+ curSliceSize = (*si)->memSize();
+ } else {
+ uint64_t curAddr = curSliceAddress + curSliceSize;
+ if (!isDataPageAlignedForNMagic && needAlign(*si)) {
+ // If the linker outputmagic is set to OutputMagic::NMAGIC, align the
+ // Data
+ // to a page boundary
+ curAddr =
+ llvm::RoundUpToAlignment(curAddr, this->_context.getPageSize());
+ isDataPageAlignedForNMagic = true;
+ }
+ uint64_t newAddr = llvm::RoundUpToAlignment(curAddr, (*si)->alignment());
+ // Handle linker script expressions, which *may update newAddr* if the
+ // expression assigns to "."
+ if (auto expr = dyn_cast<ExpressionChunk<ELFT>>(*si))
+ expr->evalExpr(newAddr);
+ Section<ELFT> *sec = dyn_cast<Section<ELFT>>(*si);
+ StringRef curOutputSectionName;
+ if (sec)
+ curOutputSectionName = sec->outputSectionName();
+ else {
+ // If this is a linker script expression, propagate the name of the
+ // previous section instead
+ if (isa<ExpressionChunk<ELFT>>(*si))
+ curOutputSectionName = prevOutputSectionName;
+ else
+ curOutputSectionName = (*si)->name();
+ }
+ bool autoCreateSlice = true;
+ if (curOutputSectionName == prevOutputSectionName)
+ autoCreateSlice = false;
+ // If the newAddress computed is more than a page away, let's create
+ // a separate segment, so that memory is not used up while running.
+ // Dont create a slice, if the new section falls in the same output
+ // section as the previous section.
+ if (autoCreateSlice &&
+ ((newAddr - curAddr) > this->_context.getPageSize()) &&
+ (_outputMagic != ELFLinkingContext::OutputMagic::NMAGIC &&
+ _outputMagic != ELFLinkingContext::OutputMagic::OMAGIC)) {
+ auto sliceIter =
+ std::find_if(_segmentSlices.begin(), _segmentSlices.end(),
+ [startSection](SegmentSlice<ELFT> *s) -> bool {
+ return s->startSection() == startSection;
+ });
+ if (sliceIter == _segmentSlices.end()) {
+ slice = new (_segmentAllocate.Allocate<SegmentSlice<ELFT>>())
+ SegmentSlice<ELFT>();
+ _segmentSlices.push_back(slice);
+ } else {
+ slice = (*sliceIter);
+ }
+ slice->setStart(startSection);
+ slice->setSections(make_range(startSectionIter, si));
+ slice->setMemSize(curSliceSize);
+ slice->setAlign(sliceAlign);
+ slice->setVirtualAddr(curSliceAddress);
+ // Start new slice
+ curSliceAddress = newAddr;
+ (*si)->setVirtualAddr(curSliceAddress);
+ startSectionIter = si;
+ startSection = currSection;
+ if (auto section = dyn_cast<Section<ELFT>>(*si))
+ section->assignVirtualAddress(newAddr);
+ curSliceSize = newAddr - curSliceAddress + (*si)->memSize();
+ sliceAlign = (*si)->alignment();
+ } else {
+ if (sliceAlign < (*si)->alignment())
+ sliceAlign = (*si)->alignment();
+ (*si)->setVirtualAddr(newAddr);
+ // Handle TLS.
+ if (auto section = dyn_cast<Section<ELFT>>(*si)) {
+ if (section->getSegmentType() == llvm::ELF::PT_TLS) {
+ tlsStartAddr =
+ llvm::RoundUpToAlignment(tlsStartAddr, (*si)->alignment());
+ section->assignVirtualAddress(tlsStartAddr);
+ tlsStartAddr += (*si)->memSize();
+ } else {
+ section->assignVirtualAddress(newAddr);
+ }
+ }
+ // TBSS section is special in that it doesn't contribute to memory of
+ // any segment. If we see a tbss section, don't add memory size to addr
+ // The fileOffset is automatically taken care of since TBSS section does
+ // not end up using file size.
+ if ((*si)->order() != DefaultLayout<ELFT>::ORDER_TBSS)
+ curSliceSize = newAddr - curSliceAddress + (*si)->memSize();
+ else
+ curSliceSize = newAddr - curSliceAddress;
+ }
+ prevOutputSectionName = curOutputSectionName;
+ }
+ currSection++;
+ }
+ auto sliceIter = std::find_if(_segmentSlices.begin(), _segmentSlices.end(),
+ [startSection](SegmentSlice<ELFT> *s) -> bool {
+ return s->startSection() == startSection;
+ });
+ if (sliceIter == _segmentSlices.end()) {
+ slice = new (_segmentAllocate.Allocate<SegmentSlice<ELFT>>())
+ SegmentSlice<ELFT>();
+ _segmentSlices.push_back(slice);
+ } else {
+ slice = (*sliceIter);
+ }
+ slice->setStart(startSection);
+ slice->setVirtualAddr(curSliceAddress);
+ slice->setMemSize(curSliceSize);
+ slice->setSections(make_range(startSectionIter, _sections.end()));
+ slice->setAlign(sliceAlign);
+
+ // Set the segment memory size and the virtual address.
+ this->setMemSize(curSliceAddress - startAddr + curSliceSize);
+ this->setVirtualAddr(curSliceAddress);
+ std::stable_sort(_segmentSlices.begin(), _segmentSlices.end(),
+ SegmentSlice<ELFT>::compare_slices);
+}
+
+// Write the Segment
+template <class ELFT>
+void Segment<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout,
+ llvm::FileOutputBuffer &buffer) {
+ for (auto slice : slices())
+ for (auto section : slice->sections())
+ section->write(writer, layout, buffer);
+}
+
+template<class ELFT>
+int64_t
+Segment<ELFT>::flags() const {
+ int64_t fl = 0;
+ if (_flags & llvm::ELF::SHF_ALLOC)
+ fl |= llvm::ELF::PF_R;
+ if (_flags & llvm::ELF::SHF_WRITE)
+ fl |= llvm::ELF::PF_W;
+ if (_flags & llvm::ELF::SHF_EXECINSTR)
+ fl |= llvm::ELF::PF_X;
+ return fl;
+}
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/TODO.txt b/lib/ReaderWriter/ELF/TODO.txt
new file mode 100644
index 000000000000..90c334b781ba
--- /dev/null
+++ b/lib/ReaderWriter/ELF/TODO.txt
@@ -0,0 +1,18 @@
+lib/ReaderWriter/ELF
+~~~~~~~~~~~~~~~~~~~~
+
+- Implement processing of DT_NEEDED elements including -rpath-link /
+ -rpath processing.
+
+- _GLOBAL_OFFSET_TABLE should be hidden and normally dropped from the output.
+
+- Merge SHT_NOTE sections only if applicable.
+
+- Do not create __got_* / __plt_* symbol table entries by default.
+
+- Weak references to symbols defined in a DSO should remain weak.
+
+- Fix section flags as they appear in input (update content permissions)
+
+- Check for errors in the ELFReader when creating atoms for LinkOnce
+ sections/Group sections. Add tests to account for the change when it happens.
diff --git a/lib/ReaderWriter/ELF/TargetHandler.h b/lib/ReaderWriter/ELF/TargetHandler.h
new file mode 100644
index 000000000000..ca7a442276d1
--- /dev/null
+++ b/lib/ReaderWriter/ELF/TargetHandler.h
@@ -0,0 +1,86 @@
+//===- lib/ReaderWriter/ELF/TargetHandler.h -------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief These interfaces provide target specific hooks to change the linker's
+/// behaivor.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_TARGET_HANDLER_H
+#define LLD_READER_WRITER_ELF_TARGET_HANDLER_H
+
+#include "Layout.h"
+#include "lld/Core/Atom.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/LinkingContext.h"
+#include "lld/Core/STDExtras.h"
+#include "lld/ReaderWriter/ELFLinkingContext.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include <memory>
+#include <vector>
+
+namespace lld {
+namespace elf {
+template <class ELFT> class DynamicTable;
+template <class ELFT> class DynamicSymbolTable;
+template <class ELFT> class ELFDefinedAtom;
+template <class ELFT> class ELFReference;
+class ELFWriter;
+template <class ELFT> class ELFHeader;
+template <class ELFT> class Section;
+template <class ELFT> class TargetLayout;
+
+class TargetRelocationHandler {
+public:
+ /// Constructor
+ TargetRelocationHandler() {}
+ virtual ~TargetRelocationHandler() {}
+
+ virtual std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &,
+ const lld::AtomLayout &,
+ const Reference &) const = 0;
+};
+
+/// \brief TargetHandler contains all the information responsible to handle a
+/// a particular target on ELF. A target might wish to override implementation
+/// of creating atoms and how the atoms are written to the output file.
+template <class ELFT> class TargetHandler : public TargetHandlerBase {
+public:
+ /// The layout determined completely by the Target.
+ virtual TargetLayout<ELFT> &getTargetLayout() = 0;
+
+ /// Determine how relocations need to be applied.
+ virtual const TargetRelocationHandler &getRelocationHandler() const = 0;
+
+ /// How does the target deal with reading input files.
+ virtual std::unique_ptr<Reader> getObjReader() = 0;
+
+ /// How does the target deal with reading dynamic libraries.
+ virtual std::unique_ptr<Reader> getDSOReader() = 0;
+
+ /// How does the target deal with writing ELF output.
+ virtual std::unique_ptr<Writer> getWriter() = 0;
+};
+
+inline std::error_code make_unhandled_reloc_error() {
+ return make_dynamic_error_code(Twine("Unhandled reference type"));
+}
+
+inline std::error_code make_out_of_range_reloc_error() {
+ return make_dynamic_error_code(Twine("Relocation out of range"));
+}
+
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/TargetLayout.h b/lib/ReaderWriter/ELF/TargetLayout.h
new file mode 100644
index 000000000000..ab7a7890a274
--- /dev/null
+++ b/lib/ReaderWriter/ELF/TargetLayout.h
@@ -0,0 +1,28 @@
+//===- lib/ReaderWriter/ELF/TargetLayout.h --------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_TARGET_LAYOUT_H
+#define LLD_READER_WRITER_ELF_TARGET_LAYOUT_H
+
+#include "DefaultLayout.h"
+#include "lld/Core/LLVM.h"
+
+namespace lld {
+namespace elf {
+/// \brief The target can override certain functions in the DefaultLayout
+/// class so that the order, the name of the section and the segment type could
+/// be changed in the final layout
+template <class ELFT> class TargetLayout : public DefaultLayout<ELFT> {
+public:
+ TargetLayout(ELFLinkingContext &context) : DefaultLayout<ELFT>(context) {}
+};
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/Writer.cpp b/lib/ReaderWriter/ELF/Writer.cpp
new file mode 100644
index 000000000000..3071827e07d0
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Writer.cpp
@@ -0,0 +1,23 @@
+//===- lib/ReaderWriter/ELF/WriterELF.cpp ---------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/Writer.h"
+#include "DynamicLibraryWriter.h"
+#include "ExecutableWriter.h"
+
+using namespace llvm;
+using namespace llvm::object;
+
+namespace lld {
+
+std::unique_ptr<Writer> createWriterELF(TargetHandlerBase *handler) {
+ return std::move(handler->getWriter());
+}
+
+} // namespace lld
diff --git a/lib/ReaderWriter/ELF/Writer.h b/lib/ReaderWriter/ELF/Writer.h
new file mode 100644
index 000000000000..1e819467c558
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Writer.h
@@ -0,0 +1,38 @@
+//===- lib/ReaderWriter/ELF/Writer.h --------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_WRITER_H
+#define LLD_READER_WRITER_ELF_WRITER_H
+
+#include "lld/Core/File.h"
+#include "lld/Core/Writer.h"
+
+namespace lld {
+namespace elf {
+/// \brief The Writer class is a base class for the linker to write
+/// various kinds of ELF files.
+class ELFWriter : public Writer {
+public:
+ ELFWriter() { }
+
+public:
+ /// \brief builds the chunks that needs to be written to the output
+ /// ELF file
+ virtual void buildChunks(const File &file) = 0;
+
+ /// \brief Writes the chunks into the output file specified by path
+ virtual std::error_code writeFile(const File &file, StringRef path) = 0;
+
+ /// \brief Get the virtual address of \p atom after layout.
+ virtual uint64_t addressOfAtom(const Atom *atom) = 0;
+};
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/X86/CMakeLists.txt b/lib/ReaderWriter/ELF/X86/CMakeLists.txt
new file mode 100644
index 000000000000..191f7ab3d61d
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86/CMakeLists.txt
@@ -0,0 +1,11 @@
+add_llvm_library(lldX86ELFTarget
+ X86LinkingContext.cpp
+ X86TargetHandler.cpp
+ X86RelocationHandler.cpp
+ LINK_LIBS
+ lldELF
+ lldReaderWriter
+ lldCore
+ LLVMObject
+ LLVMSupport
+ )
diff --git a/lib/ReaderWriter/ELF/X86/Makefile b/lib/ReaderWriter/ELF/X86/Makefile
new file mode 100644
index 000000000000..058d5133eaba
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86/Makefile
@@ -0,0 +1,15 @@
+##===- lld/lib/ReaderWriter/ELF/X86/Makefile ----------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLD_LEVEL := ../../../..
+LIBRARYNAME := lldX86ELFTarget
+USEDLIBS = lldCore.a
+CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF
+
+include $(LLD_LEVEL)/Makefile
diff --git a/lib/ReaderWriter/ELF/X86/X86DynamicLibraryWriter.h b/lib/ReaderWriter/ELF/X86/X86DynamicLibraryWriter.h
new file mode 100644
index 000000000000..86376295bec4
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86/X86DynamicLibraryWriter.h
@@ -0,0 +1,67 @@
+//===- lib/ReaderWriter/ELF/X86/X86DynamicLibraryWriter.h -----------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef X86_X86_DYNAMIC_LIBRARY_WRITER_H
+#define X86_X86_DYNAMIC_LIBRARY_WRITER_H
+
+#include "DynamicLibraryWriter.h"
+#include "X86LinkingContext.h"
+
+namespace lld {
+namespace elf {
+
+template <class ELFT>
+class X86DynamicLibraryWriter : public DynamicLibraryWriter<ELFT> {
+public:
+ X86DynamicLibraryWriter(X86LinkingContext &context,
+ X86TargetLayout<ELFT> &layout);
+
+protected:
+ // Add any runtime files and their atoms to the output
+ virtual bool createImplicitFiles(std::vector<std::unique_ptr<File>> &);
+
+ virtual void finalizeDefaultAtomValues() {
+ return DynamicLibraryWriter<ELFT>::finalizeDefaultAtomValues();
+ }
+
+ virtual void addDefaultAtoms() {
+ return DynamicLibraryWriter<ELFT>::addDefaultAtoms();
+ }
+
+private:
+ class GOTFile : public SimpleFile {
+ public:
+ GOTFile(const ELFLinkingContext &eti) : SimpleFile("GOTFile") {}
+ llvm::BumpPtrAllocator _alloc;
+ };
+
+ std::unique_ptr<GOTFile> _gotFile;
+ X86LinkingContext &_context;
+ X86TargetLayout<ELFT> &_x86Layout;
+};
+
+template <class ELFT>
+X86DynamicLibraryWriter<ELFT>::X86DynamicLibraryWriter(
+ X86LinkingContext &context, X86TargetLayout<ELFT> &layout)
+ : DynamicLibraryWriter<ELFT>(context, layout),
+ _gotFile(new GOTFile(context)), _context(context), _x86Layout(layout) {}
+
+template <class ELFT>
+bool X86DynamicLibraryWriter<ELFT>::createImplicitFiles(
+ std::vector<std::unique_ptr<File>> &result) {
+ DynamicLibraryWriter<ELFT>::createImplicitFiles(result);
+ _gotFile->addAtom(*new (_gotFile->_alloc) GLOBAL_OFFSET_TABLEAtom(*_gotFile));
+ _gotFile->addAtom(*new (_gotFile->_alloc) DYNAMICAtom(*_gotFile));
+ result.push_back(std::move(_gotFile));
+ return true;
+}
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/X86/X86ELFFile.h b/lib/ReaderWriter/ELF/X86/X86ELFFile.h
new file mode 100644
index 000000000000..621c38c43505
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86/X86ELFFile.h
@@ -0,0 +1,41 @@
+//===- lib/ReaderWriter/ELF/X86/X86ELFFile.h ------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_X86_X86_ELF_FILE_H
+#define LLD_READER_WRITER_ELF_X86_X86_ELF_FILE_H
+
+#include "ELFReader.h"
+
+namespace lld {
+namespace elf {
+
+class X86LinkingContext;
+
+template <class ELFT> class X86ELFFile : public ELFFile<ELFT> {
+public:
+ X86ELFFile(std::unique_ptr<MemoryBuffer> mb, X86LinkingContext &ctx)
+ : ELFFile<ELFT>(std::move(mb), ctx) {}
+
+ static ErrorOr<std::unique_ptr<X86ELFFile>>
+ create(std::unique_ptr<MemoryBuffer> mb, X86LinkingContext &ctx) {
+ return std::unique_ptr<X86ELFFile<ELFT>>(
+ new X86ELFFile<ELFT>(std::move(mb), ctx));
+ }
+};
+
+template <class ELFT> class X86DynamicFile : public DynamicFile<ELFT> {
+public:
+ X86DynamicFile(const X86LinkingContext &context, StringRef name)
+ : DynamicFile<ELFT>(context, name) {}
+};
+
+} // elf
+} // lld
+
+#endif // LLD_READER_WRITER_ELF_X86_X86_ELF_FILE_H
diff --git a/lib/ReaderWriter/ELF/X86/X86ELFReader.h b/lib/ReaderWriter/ELF/X86/X86ELFReader.h
new file mode 100644
index 000000000000..96186c5eb024
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86/X86ELFReader.h
@@ -0,0 +1,62 @@
+//===- lib/ReaderWriter/ELF/X86/X86ELFReader.h ----------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_X86_X86_ELF_READER_H
+#define LLD_READER_WRITER_X86_X86_ELF_READER_H
+
+#include "ELFReader.h"
+#include "X86ELFFile.h"
+
+namespace lld {
+namespace elf {
+
+typedef llvm::object::ELFType<llvm::support::little, 2, false> X86ELFType;
+
+struct X86DynamicFileCreateELFTraits {
+ typedef llvm::ErrorOr<std::unique_ptr<lld::SharedLibraryFile>> result_type;
+
+ template <class ELFT>
+ static result_type create(std::unique_ptr<llvm::MemoryBuffer> mb,
+ X86LinkingContext &ctx) {
+ return lld::elf::X86DynamicFile<ELFT>::create(std::move(mb), ctx);
+ }
+};
+
+struct X86ELFFileCreateELFTraits {
+ typedef llvm::ErrorOr<std::unique_ptr<lld::File>> result_type;
+
+ template <class ELFT>
+ static result_type create(std::unique_ptr<llvm::MemoryBuffer> mb,
+ X86LinkingContext &ctx) {
+ return lld::elf::X86ELFFile<ELFT>::create(std::move(mb), ctx);
+ }
+};
+
+class X86ELFObjectReader
+ : public ELFObjectReader<X86ELFType, X86ELFFileCreateELFTraits,
+ X86LinkingContext> {
+public:
+ X86ELFObjectReader(X86LinkingContext &ctx)
+ : ELFObjectReader<X86ELFType, X86ELFFileCreateELFTraits,
+ X86LinkingContext>(ctx, llvm::ELF::EM_386) {}
+};
+
+class X86ELFDSOReader
+ : public ELFDSOReader<X86ELFType, X86DynamicFileCreateELFTraits,
+ X86LinkingContext> {
+public:
+ X86ELFDSOReader(X86LinkingContext &ctx)
+ : ELFDSOReader<X86ELFType, X86DynamicFileCreateELFTraits,
+ X86LinkingContext>(ctx, llvm::ELF::EM_386) {}
+};
+
+} // namespace elf
+} // namespace lld
+
+#endif // LLD_READER_WRITER_X86_X86_ELF_READER_H
diff --git a/lib/ReaderWriter/ELF/X86/X86ExecutableWriter.h b/lib/ReaderWriter/ELF/X86/X86ExecutableWriter.h
new file mode 100644
index 000000000000..68acc06c2261
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86/X86ExecutableWriter.h
@@ -0,0 +1,57 @@
+//===- lib/ReaderWriter/ELF/X86/X86ExecutableWriter.h ---------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef X86_X86_EXECUTABLE_WRITER_H
+#define X86_X86_EXECUTABLE_WRITER_H
+
+#include "ExecutableWriter.h"
+#include "X86LinkingContext.h"
+
+namespace lld {
+namespace elf {
+
+template <class ELFT>
+class X86ExecutableWriter : public ExecutableWriter<ELFT> {
+public:
+ X86ExecutableWriter(X86LinkingContext &context,
+ X86TargetLayout<ELFT> &layout);
+
+protected:
+ // Add any runtime files and their atoms to the output
+ virtual bool createImplicitFiles(std::vector<std::unique_ptr<File>> &);
+
+ virtual void finalizeDefaultAtomValues() {
+ return ExecutableWriter<ELFT>::finalizeDefaultAtomValues();
+ }
+
+ virtual void addDefaultAtoms() {
+ return ExecutableWriter<ELFT>::addDefaultAtoms();
+ }
+
+private:
+ X86LinkingContext &_context;
+ X86TargetLayout<ELFT> &_x86Layout;
+};
+
+template <class ELFT>
+X86ExecutableWriter<ELFT>::X86ExecutableWriter(X86LinkingContext &context,
+ X86TargetLayout<ELFT> &layout)
+ : ExecutableWriter<ELFT>(context, layout), _context(context),
+ _x86Layout(layout) {}
+
+template <class ELFT>
+bool X86ExecutableWriter<ELFT>::createImplicitFiles(
+ std::vector<std::unique_ptr<File>> &result) {
+ ExecutableWriter<ELFT>::createImplicitFiles(result);
+ return true;
+}
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/X86/X86LinkingContext.cpp b/lib/ReaderWriter/ELF/X86/X86LinkingContext.cpp
new file mode 100644
index 000000000000..26d715cf2953
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86/X86LinkingContext.cpp
@@ -0,0 +1,28 @@
+//===- lib/ReaderWriter/ELF/X86/X86LinkingContext.cpp ---------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "X86LinkingContext.h"
+#include "X86TargetHandler.h"
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/ErrorOr.h"
+
+using namespace lld;
+
+std::unique_ptr<ELFLinkingContext>
+elf::X86LinkingContext::create(llvm::Triple triple) {
+ if (triple.getArch() == llvm::Triple::x86)
+ return std::unique_ptr<ELFLinkingContext>(
+ new elf::X86LinkingContext(triple));
+ return nullptr;
+}
+
+elf::X86LinkingContext::X86LinkingContext(llvm::Triple triple)
+ : ELFLinkingContext(triple, std::unique_ptr<TargetHandlerBase>(
+ new X86TargetHandler(*this))) {}
diff --git a/lib/ReaderWriter/ELF/X86/X86LinkingContext.h b/lib/ReaderWriter/ELF/X86/X86LinkingContext.h
new file mode 100644
index 000000000000..ff424f411aae
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86/X86LinkingContext.h
@@ -0,0 +1,42 @@
+//===- lib/ReaderWriter/ELF/X86/X86LinkingContext.h -----------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_X86_TARGETINFO_H
+#define LLD_READER_WRITER_ELF_X86_TARGETINFO_H
+
+#include "lld/ReaderWriter/ELFLinkingContext.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/ELF.h"
+
+namespace lld {
+namespace elf {
+class X86LinkingContext final : public ELFLinkingContext {
+public:
+ static std::unique_ptr<ELFLinkingContext> create(llvm::Triple);
+ X86LinkingContext(llvm::Triple);
+
+ /// \brief X86 has only two relative relocation
+ /// a) for supporting IFUNC relocs - R_386_IRELATIVE
+ /// b) for supporting relative relocs - R_386_RELATIVE
+ bool isRelativeReloc(const Reference &r) const override {
+ if (r.kindNamespace() != Reference::KindNamespace::ELF)
+ return false;
+ assert(r.kindArch() == Reference::KindArch::x86);
+ switch (r.kindValue()) {
+ case llvm::ELF::R_386_IRELATIVE:
+ case llvm::ELF::R_386_RELATIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+};
+} // end namespace elf
+} // end namespace lld
+#endif
diff --git a/lib/ReaderWriter/ELF/X86/X86RelocationHandler.cpp b/lib/ReaderWriter/ELF/X86/X86RelocationHandler.cpp
new file mode 100644
index 000000000000..da5a24c6ec37
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86/X86RelocationHandler.cpp
@@ -0,0 +1,57 @@
+//===- lib/ReaderWriter/ELF/X86/X86RelocationHandler.cpp ------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "X86LinkingContext.h"
+#include "X86TargetHandler.h"
+#include "llvm/Support/Endian.h"
+
+using namespace lld;
+using namespace lld::elf;
+using namespace llvm::support::endian;
+
+namespace {
+/// \brief R_386_32 - word32: S + A
+static int reloc32(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) {
+ int32_t result = (uint32_t)(S + A);
+ write32le(location, result | read32le(location));
+ return 0;
+}
+
+/// \brief R_386_PC32 - word32: S + A - P
+static int relocPC32(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) {
+ uint32_t result = (uint32_t)((S + A) - P);
+ write32le(location, result + read32le(location));
+ return 0;
+}
+}
+
+std::error_code X86TargetRelocationHandler::applyRelocation(
+ ELFWriter &writer, llvm::FileOutputBuffer &buf, const lld::AtomLayout &atom,
+ const Reference &ref) const {
+ uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset;
+ uint8_t *location = atomContent + ref.offsetInAtom();
+ uint64_t targetVAddress = writer.addressOfAtom(ref.target());
+ uint64_t relocVAddress = atom._virtualAddr + ref.offsetInAtom();
+
+ if (ref.kindNamespace() != Reference::KindNamespace::ELF)
+ return std::error_code();
+ assert(ref.kindArch() == Reference::KindArch::x86);
+ switch (ref.kindValue()) {
+ case R_386_32:
+ reloc32(location, relocVAddress, targetVAddress, ref.addend());
+ break;
+ case R_386_PC32:
+ relocPC32(location, relocVAddress, targetVAddress, ref.addend());
+ break;
+ default:
+ return make_unhandled_reloc_error();
+ }
+
+ return std::error_code();
+}
diff --git a/lib/ReaderWriter/ELF/X86/X86RelocationHandler.h b/lib/ReaderWriter/ELF/X86/X86RelocationHandler.h
new file mode 100644
index 000000000000..f161cdd55983
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86/X86RelocationHandler.h
@@ -0,0 +1,29 @@
+//===- lib/ReaderWriter/ELF/X86/X86RelocationHandler.h --------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef X86_X86_RELOCATION_HANDLER_H
+#define X86_X86_RELOCATION_HANDLER_H
+
+#include "X86TargetHandler.h"
+
+namespace lld {
+namespace elf {
+typedef llvm::object::ELFType<llvm::support::little, 2, false> X86ELFType;
+
+class X86TargetRelocationHandler final : public TargetRelocationHandler {
+public:
+ std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &,
+ const lld::AtomLayout &,
+ const Reference &) const override;
+};
+
+} // end namespace elf
+} // end namespace lld
+
+#endif // X86_X86_RELOCATION_HANDLER_H
diff --git a/lib/ReaderWriter/ELF/X86/X86TargetHandler.cpp b/lib/ReaderWriter/ELF/X86/X86TargetHandler.cpp
new file mode 100644
index 000000000000..22d918231424
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86/X86TargetHandler.cpp
@@ -0,0 +1,53 @@
+//===- lib/ReaderWriter/ELF/X86/X86TargetHandler.cpp ----------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "X86TargetHandler.h"
+#include "X86DynamicLibraryWriter.h"
+#include "X86ExecutableWriter.h"
+#include "X86LinkingContext.h"
+#include "X86RelocationHandler.h"
+
+using namespace lld;
+using namespace elf;
+
+using namespace llvm::ELF;
+
+std::unique_ptr<Writer> X86TargetHandler::getWriter() {
+ switch (_x86LinkingContext.getOutputELFType()) {
+ case llvm::ELF::ET_EXEC:
+ return std::unique_ptr<Writer>(new X86ExecutableWriter<X86ELFType>(
+ _x86LinkingContext, *_x86TargetLayout.get()));
+ case llvm::ELF::ET_DYN:
+ return std::unique_ptr<Writer>(new X86DynamicLibraryWriter<X86ELFType>(
+ _x86LinkingContext, *_x86TargetLayout.get()));
+ case llvm::ELF::ET_REL:
+ llvm_unreachable("TODO: support -r mode");
+ default:
+ llvm_unreachable("unsupported output type");
+ }
+}
+
+#define ELF_RELOC(name, value) LLD_KIND_STRING_ENTRY(name),
+
+const Registry::KindStrings X86TargetHandler::kindStrings[] = {
+#include "llvm/Support/ELFRelocs/i386.def"
+ LLD_KIND_STRING_END
+};
+
+#undef ELF_RELOC
+
+void X86TargetHandler::registerRelocationNames(Registry &registry) {
+ registry.addKindTable(Reference::KindNamespace::ELF, Reference::KindArch::x86,
+ kindStrings);
+}
+
+X86TargetHandler::X86TargetHandler(X86LinkingContext &context)
+ : _x86LinkingContext(context),
+ _x86TargetLayout(new X86TargetLayout<X86ELFType>(context)),
+ _x86RelocationHandler(new X86TargetRelocationHandler()) {}
diff --git a/lib/ReaderWriter/ELF/X86/X86TargetHandler.h b/lib/ReaderWriter/ELF/X86/X86TargetHandler.h
new file mode 100644
index 000000000000..6c4026735419
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86/X86TargetHandler.h
@@ -0,0 +1,63 @@
+//===- lib/ReaderWriter/ELF/X86/X86TargetHandler.h ------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_X86_TARGET_HANDLER_H
+#define LLD_READER_WRITER_ELF_X86_TARGET_HANDLER_H
+
+#include "DefaultTargetHandler.h"
+#include "TargetLayout.h"
+#include "X86ELFFile.h"
+#include "X86ELFReader.h"
+#include "X86RelocationHandler.h"
+
+namespace lld {
+namespace elf {
+
+class X86LinkingContext;
+
+template <class ELFT> class X86TargetLayout : public TargetLayout<ELFT> {
+public:
+ X86TargetLayout(X86LinkingContext &context) : TargetLayout<ELFT>(context) {}
+};
+
+class X86TargetHandler final
+ : public DefaultTargetHandler<X86ELFType> {
+public:
+ X86TargetHandler(X86LinkingContext &context);
+
+ X86TargetLayout<X86ELFType> &getTargetLayout() override {
+ return *(_x86TargetLayout.get());
+ }
+
+ void registerRelocationNames(Registry &registry) override;
+
+ const X86TargetRelocationHandler &getRelocationHandler() const override {
+ return *(_x86RelocationHandler.get());
+ }
+
+ std::unique_ptr<Reader> getObjReader() override {
+ return std::unique_ptr<Reader>(new X86ELFObjectReader(_x86LinkingContext));
+ }
+
+ std::unique_ptr<Reader> getDSOReader() override {
+ return std::unique_ptr<Reader>(new X86ELFDSOReader(_x86LinkingContext));
+ }
+
+ std::unique_ptr<Writer> getWriter() override;
+
+protected:
+ static const Registry::KindStrings kindStrings[];
+ X86LinkingContext &_x86LinkingContext;
+ std::unique_ptr<X86TargetLayout<X86ELFType>> _x86TargetLayout;
+ std::unique_ptr<X86TargetRelocationHandler> _x86RelocationHandler;
+};
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/X86_64/CMakeLists.txt b/lib/ReaderWriter/ELF/X86_64/CMakeLists.txt
new file mode 100644
index 000000000000..a85d2b504630
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/CMakeLists.txt
@@ -0,0 +1,16 @@
+add_llvm_library(lldX86_64ELFTarget
+ X86_64LinkingContext.cpp
+ X86_64TargetHandler.cpp
+ X86_64RelocationHandler.cpp
+ X86_64RelocationPass.cpp
+ LINK_LIBS
+ lldELF
+ lldReaderWriter
+ lldCore
+ LLVMObject
+ LLVMSupport
+ )
+
+include_directories(.)
+
+add_subdirectory(ExampleSubTarget)
diff --git a/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/CMakeLists.txt b/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/CMakeLists.txt
new file mode 100644
index 000000000000..d13c98008e55
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/CMakeLists.txt
@@ -0,0 +1,11 @@
+add_llvm_library(lldExampleSubTarget
+ ExampleLinkingContext.cpp
+ ExampleTargetHandler.cpp
+ LINK_LIBS
+ lldX86_64ELFTarget
+ lldELF
+ lldReaderWriter
+ lldCore
+ LLVMObject
+ LLVMSupport
+ )
diff --git a/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleLinkingContext.cpp b/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleLinkingContext.cpp
new file mode 100644
index 000000000000..dbbb3ad3bc90
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleLinkingContext.cpp
@@ -0,0 +1,35 @@
+//===- lib/ReaderWriter/ELF/X86_64/ExampleTarget/ExampleLinkingContext.cpp ----===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExampleLinkingContext.h"
+#include "ExampleTargetHandler.h"
+
+using namespace lld;
+using namespace elf;
+
+std::unique_ptr<ELFLinkingContext>
+ExampleLinkingContext::create(llvm::Triple triple) {
+ if (triple.getVendorName() == "example")
+ return llvm::make_unique<ExampleLinkingContext>(triple);
+ return nullptr;
+}
+
+ExampleLinkingContext::ExampleLinkingContext(llvm::Triple triple)
+ : X86_64LinkingContext(triple, std::unique_ptr<TargetHandlerBase>(
+ new ExampleTargetHandler(*this))) {
+ _outputELFType = llvm::ELF::ET_LOPROC;
+}
+
+StringRef ExampleLinkingContext::entrySymbolName() const {
+ return "_start";
+}
+
+void ExampleLinkingContext::addPasses(PassManager &p) {
+ ELFLinkingContext::addPasses(p);
+}
diff --git a/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleLinkingContext.h b/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleLinkingContext.h
new file mode 100644
index 000000000000..5bb11cd35b41
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleLinkingContext.h
@@ -0,0 +1,31 @@
+//===- lib/ReaderWriter/ELF/X86_64/ExampleTarget/ExampleLinkingContext.h --===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_X86_64_EXAMPLE_TARGET_EXAMPLE_LINKING_CONTEXT
+#define LLD_READER_WRITER_ELF_X86_64_EXAMPLE_TARGET_EXAMPLE_LINKING_CONTEXT
+
+#include "X86_64LinkingContext.h"
+#include "X86_64TargetHandler.h"
+
+namespace lld {
+namespace elf {
+
+class ExampleLinkingContext final : public X86_64LinkingContext {
+public:
+ static std::unique_ptr<ELFLinkingContext> create(llvm::Triple);
+ ExampleLinkingContext(llvm::Triple triple);
+
+ StringRef entrySymbolName() const override;
+ void addPasses(PassManager &) override;
+};
+
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleTargetHandler.cpp b/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleTargetHandler.cpp
new file mode 100644
index 000000000000..b66b0d903f6a
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleTargetHandler.cpp
@@ -0,0 +1,23 @@
+//===- lib/ReaderWriter/ELF/X86_64/ExampleTarget/ExampleTargetHandler.cpp -===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExampleTargetHandler.h"
+#include "X86_64ExecutableWriter.h"
+#include "ExampleLinkingContext.h"
+
+using namespace lld;
+using namespace elf;
+
+ExampleTargetHandler::ExampleTargetHandler(ExampleLinkingContext &c)
+ : X86_64TargetHandler(c), _exampleContext(c) {}
+
+std::unique_ptr<Writer> ExampleTargetHandler::getWriter() {
+ return std::unique_ptr<Writer>(
+ new X86_64ExecutableWriter(_exampleContext, *_x86_64TargetLayout));
+}
diff --git a/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleTargetHandler.h b/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleTargetHandler.h
new file mode 100644
index 000000000000..19a642113359
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/ExampleTargetHandler.h
@@ -0,0 +1,31 @@
+//===- lib/ReaderWriter/ELF/X86_64/ExampleTarget/ExampleTargetHandler.h ---===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_X86_64_EXAMPLE_TARGET_EXAMPLE_TARGET_HANDLER_H
+#define LLD_READER_WRITER_ELF_X86_64_EXAMPLE_TARGET_EXAMPLE_TARGET_HANDLER_H
+
+#include "X86_64TargetHandler.h"
+
+namespace lld {
+namespace elf {
+class ExampleLinkingContext;
+
+class ExampleTargetHandler final : public X86_64TargetHandler {
+public:
+ ExampleTargetHandler(ExampleLinkingContext &c);
+
+ std::unique_ptr<Writer> getWriter() override;
+
+private:
+ ExampleLinkingContext &_exampleContext;
+};
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/Makefile b/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/Makefile
new file mode 100644
index 000000000000..8f0b0fead1f6
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/ExampleSubTarget/Makefile
@@ -0,0 +1,15 @@
+##===- lld/lib/ReaderWriter/ELF/X86_64/Makefile ----------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLD_LEVEL := ../../../../..
+LIBRARYNAME := lldExampleSubTarget
+USEDLIBS = lldX86_64ELFTarget.a
+CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF
+
+include $(LLD_LEVEL)/Makefile
diff --git a/lib/ReaderWriter/ELF/X86_64/Makefile b/lib/ReaderWriter/ELF/X86_64/Makefile
new file mode 100644
index 000000000000..dbeb4d227050
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/Makefile
@@ -0,0 +1,19 @@
+##===- lld/lib/ReaderWriter/ELF/X86_64/Makefile ----------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLD_LEVEL := ../../../..
+LIBRARYNAME := lldX86_64ELFTarget
+USEDLIBS = lldCore.a
+
+CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF
+CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF/X86_64/
+
+PARALLEL_DIRS := ExampleSubTarget
+
+include $(LLD_LEVEL)/Makefile
diff --git a/lib/ReaderWriter/ELF/X86_64/TODO.rst b/lib/ReaderWriter/ELF/X86_64/TODO.rst
new file mode 100644
index 000000000000..a2411a00d1ea
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/TODO.rst
@@ -0,0 +1,46 @@
+ELF x86-64
+~~~~~~~~~~
+
+Unimplemented Features
+######################
+
+* Code models other than the small code model
+* TLS strength reduction
+
+Unimplemented Relocations
+#########################
+
+All of these relocations are defined in:
+http://www.x86-64.org/documentation/abi.pdf
+
+Trivial Relocs
+<<<<<<<<<<<<<<
+
+These are very simple relocation calculations to implement.
+See lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp
+
+* R_X86_64_8
+* R_X86_64_PC8
+* R_X86_64_SIZE32
+* R_X86_64_SIZE64
+* R_X86_64_GOTPC32 (this relocation requires there to be a __GLOBAL_OFFSET_TABLE__)
+
+Global Offset Table Relocs
+<<<<<<<<<<<<<<<<<<<<<<<<<<
+
+* R_X86_64_GOTOFF32
+* R_X86_64_GOTOFF64
+
+Global Dynamic Thread Local Storage Relocs
+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+
+These relocations take more effort to implement, but some of them are done.
+Their implementation lives in lib/ReaderWriter/ELF/X86_64/{X86_64RelocationPass.cpp,X86_64RelocationHandler.cpp}.
+
+Documentation on these relocations can be found in:
+http://www.akkadia.org/drepper/tls.pdf
+http://www.fsfla.org/~lxoliva/writeups/TLS/RFC-TLSDESC-x86.txt
+
+* R_X86_64_GOTPC32_TLSDESC
+* R_X86_64_TLSDESC_CALL
+* R_X86_64_TLSDESC
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64DynamicLibraryWriter.h b/lib/ReaderWriter/ELF/X86_64/X86_64DynamicLibraryWriter.h
new file mode 100644
index 000000000000..b996186115b6
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/X86_64DynamicLibraryWriter.h
@@ -0,0 +1,63 @@
+//===- lib/ReaderWriter/ELF/X86/X86_64DynamicLibraryWriter.h ---------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef X86_64_DYNAMIC_LIBRARY_WRITER_H
+#define X86_64_DYNAMIC_LIBRARY_WRITER_H
+
+#include "DynamicLibraryWriter.h"
+#include "X86_64ElfType.h"
+#include "X86_64LinkingContext.h"
+#include "X86_64TargetHandler.h"
+
+namespace lld {
+namespace elf {
+
+class X86_64DynamicLibraryWriter : public DynamicLibraryWriter<X86_64ELFType> {
+public:
+ X86_64DynamicLibraryWriter(X86_64LinkingContext &context,
+ X86_64TargetLayout &layout);
+
+protected:
+ // Add any runtime files and their atoms to the output
+ virtual bool createImplicitFiles(std::vector<std::unique_ptr<File>> &);
+
+ virtual void finalizeDefaultAtomValues() {
+ return DynamicLibraryWriter::finalizeDefaultAtomValues();
+ }
+
+ virtual void addDefaultAtoms() {
+ return DynamicLibraryWriter::addDefaultAtoms();
+ }
+
+private:
+ class GOTFile : public SimpleFile {
+ public:
+ GOTFile(const ELFLinkingContext &eti) : SimpleFile("GOTFile") {}
+ llvm::BumpPtrAllocator _alloc;
+ };
+
+ std::unique_ptr<GOTFile> _gotFile;
+};
+
+X86_64DynamicLibraryWriter::X86_64DynamicLibraryWriter(
+ X86_64LinkingContext &context, X86_64TargetLayout &layout)
+ : DynamicLibraryWriter(context, layout), _gotFile(new GOTFile(context)) {}
+
+bool X86_64DynamicLibraryWriter::createImplicitFiles(
+ std::vector<std::unique_ptr<File>> &result) {
+ DynamicLibraryWriter::createImplicitFiles(result);
+ _gotFile->addAtom(*new (_gotFile->_alloc) GLOBAL_OFFSET_TABLEAtom(*_gotFile));
+ _gotFile->addAtom(*new (_gotFile->_alloc) DYNAMICAtom(*_gotFile));
+ result.push_back(std::move(_gotFile));
+ return true;
+}
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64ELFFile.h b/lib/ReaderWriter/ELF/X86_64/X86_64ELFFile.h
new file mode 100644
index 000000000000..d43840a63e7e
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/X86_64ELFFile.h
@@ -0,0 +1,41 @@
+//===- lib/ReaderWriter/ELF/X86_64/X86_64ELFFile.h ------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_X86_64_ELF_FILE_H
+#define LLD_READER_WRITER_ELF_X86_64_ELF_FILE_H
+
+#include "ELFReader.h"
+
+namespace lld {
+namespace elf {
+
+class X86_64LinkingContext;
+
+template <class ELFT> class X86_64ELFFile : public ELFFile<ELFT> {
+public:
+ X86_64ELFFile(std::unique_ptr<MemoryBuffer> mb, X86_64LinkingContext &ctx)
+ : ELFFile<ELFT>(std::move(mb), ctx) {}
+
+ static ErrorOr<std::unique_ptr<X86_64ELFFile>>
+ create(std::unique_ptr<MemoryBuffer> mb, X86_64LinkingContext &ctx) {
+ return std::unique_ptr<X86_64ELFFile<ELFT>>(
+ new X86_64ELFFile<ELFT>(std::move(mb), ctx));
+ }
+};
+
+template <class ELFT> class X86_64DynamicFile : public DynamicFile<ELFT> {
+public:
+ X86_64DynamicFile(const X86_64LinkingContext &context, StringRef name)
+ : DynamicFile<ELFT>(context, name) {}
+};
+
+} // elf
+} // lld
+
+#endif // LLD_READER_WRITER_ELF_X86_64_ELF_FILE_H
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64ELFReader.h b/lib/ReaderWriter/ELF/X86_64/X86_64ELFReader.h
new file mode 100644
index 000000000000..9b1284c6dfa8
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/X86_64ELFReader.h
@@ -0,0 +1,62 @@
+//===- lib/ReaderWriter/ELF/X86_64/X86_64ELFReader.h ----------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_X86_64_X86_64_ELF_READER_H
+#define LLD_READER_WRITER_X86_64_X86_64_ELF_READER_H
+
+#include "ELFReader.h"
+#include "X86_64ELFFile.h"
+
+namespace lld {
+namespace elf {
+
+typedef llvm::object::ELFType<llvm::support::little, 2, true> X86_64ELFType;
+
+struct X86_64DynamicFileCreateELFTraits {
+ typedef llvm::ErrorOr<std::unique_ptr<lld::SharedLibraryFile>> result_type;
+
+ template <class ELFT>
+ static result_type create(std::unique_ptr<llvm::MemoryBuffer> mb,
+ X86_64LinkingContext &ctx) {
+ return lld::elf::X86_64DynamicFile<ELFT>::create(std::move(mb), ctx);
+ }
+};
+
+struct X86_64ELFFileCreateELFTraits {
+ typedef llvm::ErrorOr<std::unique_ptr<lld::File>> result_type;
+
+ template <class ELFT>
+ static result_type create(std::unique_ptr<llvm::MemoryBuffer> mb,
+ X86_64LinkingContext &ctx) {
+ return lld::elf::X86_64ELFFile<ELFT>::create(std::move(mb), ctx);
+ }
+};
+
+class X86_64ELFObjectReader
+ : public ELFObjectReader<X86_64ELFType, X86_64ELFFileCreateELFTraits,
+ X86_64LinkingContext> {
+public:
+ X86_64ELFObjectReader(X86_64LinkingContext &ctx)
+ : ELFObjectReader<X86_64ELFType, X86_64ELFFileCreateELFTraits,
+ X86_64LinkingContext>(ctx, llvm::ELF::EM_X86_64) {}
+};
+
+class X86_64ELFDSOReader
+ : public ELFDSOReader<X86_64ELFType, X86_64DynamicFileCreateELFTraits,
+ X86_64LinkingContext> {
+public:
+ X86_64ELFDSOReader(X86_64LinkingContext &ctx)
+ : ELFDSOReader<X86_64ELFType, X86_64DynamicFileCreateELFTraits,
+ X86_64LinkingContext>(ctx, llvm::ELF::EM_X86_64) {}
+};
+
+} // namespace elf
+} // namespace lld
+
+#endif // LLD_READER_WRITER_ELF_X86_64_X86_64_READER_H
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64ElfType.h b/lib/ReaderWriter/ELF/X86_64/X86_64ElfType.h
new file mode 100644
index 000000000000..0b982e7754e2
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/X86_64ElfType.h
@@ -0,0 +1,21 @@
+//===- lib/ReaderWriter/ELF/X86_64/X86_64ElfType.h ------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_X86_64_X86_64_ELF_TYPE_H
+#define LLD_READER_WRITER_ELF_X86_64_X86_64_ELF_TYPE_H
+
+#include "llvm/Object/ELF.h"
+
+namespace lld {
+namespace elf {
+typedef llvm::object::ELFType<llvm::support::little, 2, true> X86_64ELFType;
+}
+}
+
+#endif
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64ExecutableWriter.h b/lib/ReaderWriter/ELF/X86_64/X86_64ExecutableWriter.h
new file mode 100644
index 000000000000..f549ed6dcfcb
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/X86_64ExecutableWriter.h
@@ -0,0 +1,61 @@
+//===- lib/ReaderWriter/ELF/X86/X86_64ExecutableWriter.h ------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef X86_64_EXECUTABLE_WRITER_H
+#define X86_64_EXECUTABLE_WRITER_H
+
+#include "ExecutableWriter.h"
+#include "X86_64ElfType.h"
+#include "X86_64LinkingContext.h"
+
+namespace lld {
+namespace elf {
+
+class X86_64ExecutableWriter : public ExecutableWriter<X86_64ELFType> {
+public:
+ X86_64ExecutableWriter(X86_64LinkingContext &context,
+ X86_64TargetLayout &layout)
+ : ExecutableWriter(context, layout), _gotFile(new GOTFile(context)),
+ _context(context) {}
+
+protected:
+ // Add any runtime files and their atoms to the output
+ virtual bool
+ createImplicitFiles(std::vector<std::unique_ptr<File>> &result) {
+ ExecutableWriter::createImplicitFiles(result);
+ _gotFile->addAtom(*new (_gotFile->_alloc)
+ GLOBAL_OFFSET_TABLEAtom(*_gotFile));
+ if (_context.isDynamic())
+ _gotFile->addAtom(*new (_gotFile->_alloc) DYNAMICAtom(*_gotFile));
+ result.push_back(std::move(_gotFile));
+ return true;
+ }
+
+ virtual void finalizeDefaultAtomValues() {
+ return ExecutableWriter::finalizeDefaultAtomValues();
+ }
+
+ virtual void addDefaultAtoms() {
+ return ExecutableWriter::addDefaultAtoms();
+ }
+
+private:
+ class GOTFile : public SimpleFile {
+ public:
+ GOTFile(const ELFLinkingContext &eti) : SimpleFile("GOTFile") {}
+ llvm::BumpPtrAllocator _alloc;
+ };
+
+ std::unique_ptr<GOTFile> _gotFile;
+ X86_64LinkingContext &_context;
+};
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp b/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp
new file mode 100644
index 000000000000..6a8ce8bd6496
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp
@@ -0,0 +1,38 @@
+//===- lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp ---------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "X86_64LinkingContext.h"
+#include "X86_64RelocationPass.h"
+#include "X86_64TargetHandler.h"
+
+using namespace lld;
+using namespace elf;
+
+X86_64LinkingContext::X86_64LinkingContext(
+ llvm::Triple triple, std::unique_ptr<TargetHandlerBase> handler)
+ : ELFLinkingContext(triple, std::move(handler)) {}
+
+X86_64LinkingContext::X86_64LinkingContext(llvm::Triple triple)
+ : X86_64LinkingContext(triple,
+ llvm::make_unique<X86_64TargetHandler>(*this)) {}
+
+void X86_64LinkingContext::addPasses(PassManager &pm) {
+ auto pass = createX86_64RelocationPass(*this);
+ if (pass)
+ pm.add(std::move(pass));
+ ELFLinkingContext::addPasses(pm);
+}
+
+std::unique_ptr<ELFLinkingContext>
+X86_64LinkingContext::create(llvm::Triple triple) {
+ if (triple.getArch() == llvm::Triple::x86_64)
+ return std::unique_ptr<ELFLinkingContext>(
+ new elf::X86_64LinkingContext(triple));
+ return nullptr;
+}
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h b/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h
new file mode 100644
index 000000000000..2cc799a9c810
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h
@@ -0,0 +1,100 @@
+//===- lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h -----------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_X86_64_X86_64_LINKING_CONTEXT_H
+#define LLD_READER_WRITER_ELF_X86_64_X86_64_LINKING_CONTEXT_H
+
+#include "lld/ReaderWriter/ELFLinkingContext.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/ELF.h"
+
+namespace lld {
+namespace elf {
+
+/// \brief x86-64 internal references.
+enum {
+ /// \brief The 32 bit index of the relocation in the got this reference refers
+ /// to.
+ LLD_R_X86_64_GOTRELINDEX = 1024,
+};
+
+class X86_64LinkingContext : public ELFLinkingContext {
+protected:
+ X86_64LinkingContext(llvm::Triple, std::unique_ptr<TargetHandlerBase>);
+public:
+ static std::unique_ptr<ELFLinkingContext> create(llvm::Triple);
+ X86_64LinkingContext(llvm::Triple);
+
+ void addPasses(PassManager &) override;
+
+ uint64_t getBaseAddress() const override {
+ if (_baseAddress == 0)
+ return 0x400000;
+ return _baseAddress;
+ }
+
+ bool isDynamicRelocation(const Reference &r) const override {
+ if (r.kindNamespace() != Reference::KindNamespace::ELF)
+ return false;
+ assert(r.kindArch() == Reference::KindArch::x86_64);
+ switch (r.kindValue()) {
+ case llvm::ELF::R_X86_64_RELATIVE:
+ case llvm::ELF::R_X86_64_GLOB_DAT:
+ case llvm::ELF::R_X86_64_COPY:
+ case llvm::ELF::R_X86_64_DTPMOD64:
+ case llvm::ELF::R_X86_64_DTPOFF64:
+ case llvm::ELF::R_X86_64_TPOFF64:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ bool isCopyRelocation(const Reference &r) const override {
+ if (r.kindNamespace() != Reference::KindNamespace::ELF)
+ return false;
+ assert(r.kindArch() == Reference::KindArch::x86_64);
+ if (r.kindValue() == llvm::ELF::R_X86_64_COPY)
+ return true;
+ return false;
+ }
+
+ virtual bool isPLTRelocation(const Reference &r) const override {
+ if (r.kindNamespace() != Reference::KindNamespace::ELF)
+ return false;
+ assert(r.kindArch() == Reference::KindArch::x86_64);
+ switch (r.kindValue()) {
+ case llvm::ELF::R_X86_64_JUMP_SLOT:
+ case llvm::ELF::R_X86_64_IRELATIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /// \brief X86_64 has two relative relocations
+ /// a) for supporting IFUNC - R_X86_64_IRELATIVE
+ /// b) for supporting relative relocs - R_X86_64_RELATIVE
+ bool isRelativeReloc(const Reference &r) const override {
+ if (r.kindNamespace() != Reference::KindNamespace::ELF)
+ return false;
+ assert(r.kindArch() == Reference::KindArch::x86_64);
+ switch (r.kindValue()) {
+ case llvm::ELF::R_X86_64_IRELATIVE:
+ case llvm::ELF::R_X86_64_RELATIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+};
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp b/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp
new file mode 100644
index 000000000000..8fd74f43bbd2
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp
@@ -0,0 +1,151 @@
+//===- lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp ------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "X86_64LinkingContext.h"
+#include "X86_64TargetHandler.h"
+#include "llvm/Support/Endian.h"
+
+using namespace lld;
+using namespace lld::elf;
+using namespace llvm::support::endian;
+
+/// \brief R_X86_64_64 - word64: S + A
+static void reloc64(uint8_t *location, uint64_t P, uint64_t S, int64_t A) {
+ uint64_t result = S + A;
+ write64le(location, result | read64le(location));
+}
+
+/// \brief R_X86_64_PC32 - word32: S + A - P
+static void relocPC32(uint8_t *location, uint64_t P, uint64_t S, int64_t A) {
+ uint32_t result = (uint32_t)((S + A) - P);
+ write32le(location, result + read32le(location));
+}
+
+/// \brief R_X86_64_32 - word32: S + A
+static void reloc32(uint8_t *location, uint64_t P, uint64_t S, int64_t A) {
+ int32_t result = (uint32_t)(S + A);
+ write32le(location, result | read32le(location));
+ // TODO: Make sure that the result zero extends to the 64bit value.
+}
+
+/// \brief R_X86_64_32S - word32: S + A
+static void reloc32S(uint8_t *location, uint64_t P, uint64_t S, int64_t A) {
+ int32_t result = (int32_t)(S + A);
+ write32le(location, result | read32le(location));
+ // TODO: Make sure that the result sign extends to the 64bit value.
+}
+
+/// \brief R_X86_64_16 - word16: S + A
+static void reloc16(uint8_t *location, uint64_t P, uint64_t S, int64_t A) {
+ uint16_t result = (uint16_t)(S + A);
+ write16le(location, result | read16le(location));
+ // TODO: Check for overflow.
+}
+
+/// \brief R_X86_64_PC16 - word16: S + A - P
+static void relocPC16(uint8_t *location, uint64_t P, uint64_t S, int64_t A) {
+ uint16_t result = (uint16_t)((S + A) - P);
+ write16le(location, result | read16le(location));
+ // TODO: Check for overflow.
+}
+
+/// \brief R_X86_64_PC64 - word64: S + A - P
+static void relocPC64(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) {
+ int64_t result = (uint64_t)((S + A) - P);
+ write64le(location, result | read64le(location));
+}
+
+std::error_code X86_64TargetRelocationHandler::applyRelocation(
+ ELFWriter &writer, llvm::FileOutputBuffer &buf, const lld::AtomLayout &atom,
+ const Reference &ref) const {
+ uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset;
+ uint8_t *location = atomContent + ref.offsetInAtom();
+ uint64_t targetVAddress = writer.addressOfAtom(ref.target());
+ uint64_t relocVAddress = atom._virtualAddr + ref.offsetInAtom();
+
+ if (ref.kindNamespace() != Reference::KindNamespace::ELF)
+ return std::error_code();
+ assert(ref.kindArch() == Reference::KindArch::x86_64);
+ switch (ref.kindValue()) {
+ case R_X86_64_NONE:
+ break;
+ case R_X86_64_64:
+ reloc64(location, relocVAddress, targetVAddress, ref.addend());
+ break;
+ case R_X86_64_PC32:
+ case R_X86_64_GOTPCREL:
+ relocPC32(location, relocVAddress, targetVAddress, ref.addend());
+ break;
+ case R_X86_64_32:
+ reloc32(location, relocVAddress, targetVAddress, ref.addend());
+ break;
+ case R_X86_64_32S:
+ reloc32S(location, relocVAddress, targetVAddress, ref.addend());
+ break;
+ case R_X86_64_16:
+ reloc16(location, relocVAddress, targetVAddress, ref.addend());
+ break;
+ case R_X86_64_PC16:
+ relocPC16(location, relocVAddress, targetVAddress, ref.addend());
+ break;
+ case R_X86_64_TPOFF64:
+ case R_X86_64_DTPOFF32:
+ case R_X86_64_TPOFF32: {
+ _tlsSize = _x86_64Layout.getTLSSize();
+ if (ref.kindValue() == R_X86_64_TPOFF32 ||
+ ref.kindValue() == R_X86_64_DTPOFF32) {
+ write32le(location, targetVAddress - _tlsSize);
+ } else {
+ write64le(location, targetVAddress - _tlsSize);
+ }
+ break;
+ }
+ case R_X86_64_TLSGD: {
+ relocPC32(location, relocVAddress, targetVAddress, ref.addend());
+ break;
+ }
+ case R_X86_64_TLSLD: {
+ // Rewrite to move %fs:0 into %rax. Technically we should verify that the
+ // next relocation is a PC32 to __tls_get_addr...
+ static uint8_t instr[] = { 0x66, 0x66, 0x66, 0x64, 0x48, 0x8b, 0x04, 0x25,
+ 0x00, 0x00, 0x00, 0x00 };
+ std::memcpy(location - 3, instr, sizeof(instr));
+ break;
+ }
+ case R_X86_64_PC64:
+ relocPC64(location, relocVAddress, targetVAddress, ref.addend());
+ break;
+ case LLD_R_X86_64_GOTRELINDEX: {
+ const DefinedAtom *target = cast<const DefinedAtom>(ref.target());
+ for (const Reference *r : *target) {
+ if (r->kindValue() == R_X86_64_JUMP_SLOT) {
+ uint32_t index;
+ if (!_x86_64Layout.getPLTRelocationTable()->getRelocationIndex(*r,
+ index))
+ llvm_unreachable("Relocation doesn't exist");
+ reloc32(location, 0, index, 0);
+ break;
+ }
+ }
+ break;
+ }
+ // Runtime only relocations. Ignore here.
+ case R_X86_64_RELATIVE:
+ case R_X86_64_IRELATIVE:
+ case R_X86_64_JUMP_SLOT:
+ case R_X86_64_GLOB_DAT:
+ case R_X86_64_DTPMOD64:
+ case R_X86_64_DTPOFF64:
+ break;
+ default:
+ return make_unhandled_reloc_error();
+ }
+
+ return std::error_code();
+}
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.h b/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.h
new file mode 100644
index 000000000000..9e2c2171015d
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.h
@@ -0,0 +1,39 @@
+//===- lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.h --------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef X86_64_RELOCATION_HANDLER_H
+#define X86_64_RELOCATION_HANDLER_H
+
+#include "X86_64TargetHandler.h"
+
+namespace lld {
+namespace elf {
+typedef llvm::object::ELFType<llvm::support::little, 2, true> X86_64ELFType;
+
+class X86_64TargetLayout;
+
+class X86_64TargetRelocationHandler final : public TargetRelocationHandler {
+public:
+ X86_64TargetRelocationHandler(X86_64TargetLayout &layout)
+ : _tlsSize(0), _x86_64Layout(layout) {}
+
+ std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &,
+ const lld::AtomLayout &,
+ const Reference &) const override;
+
+private:
+ // Cached size of the TLS segment.
+ mutable uint64_t _tlsSize;
+ X86_64TargetLayout &_x86_64Layout;
+};
+
+} // end namespace elf
+} // end namespace lld
+
+#endif // X86_64_RELOCATION_HANDLER_H
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp b/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp
new file mode 100644
index 000000000000..0703927fd56c
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp
@@ -0,0 +1,513 @@
+//===- lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp ---------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Defines the relocation processing pass for x86-64. This includes
+/// GOT and PLT entries, TLS, COPY, and ifunc.
+///
+/// This is based on section 4.4.1 of the AMD64 ABI (no stable URL as of Oct,
+/// 2013).
+///
+/// This also includes aditional behaivor that gnu-ld and gold implement but
+/// which is not specified anywhere.
+///
+//===----------------------------------------------------------------------===//
+
+#include "X86_64RelocationPass.h"
+#include "Atoms.h"
+#include "X86_64LinkingContext.h"
+#include "lld/Core/Simple.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
+
+using namespace lld;
+using namespace lld::elf;
+using namespace llvm::ELF;
+
+// .got values
+static const uint8_t x86_64GotAtomContent[8] = {0};
+
+// .plt value (entry 0)
+static const uint8_t x86_64Plt0AtomContent[16] = {
+ 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushq GOT+8(%rip)
+ 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *GOT+16(%rip)
+ 0x90, 0x90, 0x90, 0x90 // nopnopnop
+};
+
+// .plt values (other entries)
+static const uint8_t x86_64PltAtomContent[16] = {
+ 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmpq *gotatom(%rip)
+ 0x68, 0x00, 0x00, 0x00, 0x00, // pushq reloc-index
+ 0xe9, 0x00, 0x00, 0x00, 0x00 // jmpq plt[-1]
+};
+
+// TLS GD Entry
+static const uint8_t x86_64GotTlsGdAtomContent[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+namespace {
+/// \brief Atoms that are used by X86_64 dynamic linking
+class X86_64GOTAtom : public GOTAtom {
+public:
+ X86_64GOTAtom(const File &f, StringRef secName) : GOTAtom(f, secName) {}
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return ArrayRef<uint8_t>(x86_64GotAtomContent, 8);
+ }
+};
+
+/// \brief X86_64 GOT TLS GD entry.
+class GOTTLSGdAtom : public X86_64GOTAtom {
+public:
+ GOTTLSGdAtom(const File &f, StringRef secName) : X86_64GOTAtom(f, secName) {}
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return llvm::makeArrayRef(x86_64GotTlsGdAtomContent);
+ }
+};
+
+class X86_64PLT0Atom : public PLT0Atom {
+public:
+ X86_64PLT0Atom(const File &f) : PLT0Atom(f) {}
+ ArrayRef<uint8_t> rawContent() const override {
+ return ArrayRef<uint8_t>(x86_64Plt0AtomContent, 16);
+ }
+};
+
+class X86_64PLTAtom : public PLTAtom {
+public:
+ X86_64PLTAtom(const File &f, StringRef secName) : PLTAtom(f, secName) {}
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return ArrayRef<uint8_t>(x86_64PltAtomContent, 16);
+ }
+};
+
+class ELFPassFile : public SimpleFile {
+public:
+ ELFPassFile(const ELFLinkingContext &eti) : SimpleFile("ELFPassFile") {
+ setOrdinal(eti.getNextOrdinalAndIncrement());
+ }
+
+ llvm::BumpPtrAllocator _alloc;
+};
+
+/// \brief CRTP base for handling relocations.
+template <class Derived> class RelocationPass : public Pass {
+ /// \brief Handle a specific reference.
+ void handleReference(const DefinedAtom &atom, const Reference &ref) {
+ if (ref.kindNamespace() != Reference::KindNamespace::ELF)
+ return;
+ assert(ref.kindArch() == Reference::KindArch::x86_64);
+ switch (ref.kindValue()) {
+ case R_X86_64_16:
+ case R_X86_64_32:
+ case R_X86_64_32S:
+ case R_X86_64_64:
+ case R_X86_64_PC16:
+ case R_X86_64_PC32:
+ case R_X86_64_PC64:
+ static_cast<Derived *>(this)->handlePlain(ref);
+ break;
+ case R_X86_64_PLT32:
+ static_cast<Derived *>(this)->handlePLT32(ref);
+ break;
+ case R_X86_64_GOT32:
+ case R_X86_64_GOTPC32:
+ case R_X86_64_GOTPCREL:
+ case R_X86_64_GOTOFF64:
+ static_cast<Derived *>(this)->handleGOT(ref);
+ break;
+ case R_X86_64_GOTTPOFF: // GOT Thread Pointer Offset
+ static_cast<Derived *>(this)->handleGOTTPOFF(ref);
+ break;
+ case R_X86_64_TLSGD:
+ static_cast<Derived *>(this)->handleTLSGd(ref);
+ break;
+ }
+ }
+
+protected:
+ /// \brief get the PLT entry for a given IFUNC Atom.
+ ///
+ /// If the entry does not exist. Both the GOT and PLT entry is created.
+ const PLTAtom *getIFUNCPLTEntry(const DefinedAtom *da) {
+ auto plt = _pltMap.find(da);
+ if (plt != _pltMap.end())
+ return plt->second;
+ auto ga = new (_file._alloc) X86_64GOTAtom(_file, ".got.plt");
+ ga->addReferenceELF_x86_64(R_X86_64_IRELATIVE, 0, da, 0);
+ auto pa = new (_file._alloc) X86_64PLTAtom(_file, ".plt");
+ pa->addReferenceELF_x86_64(R_X86_64_PC32, 2, ga, -4);
+#ifndef NDEBUG
+ ga->_name = "__got_ifunc_";
+ ga->_name += da->name();
+ pa->_name = "__plt_ifunc_";
+ pa->_name += da->name();
+#endif
+ _gotMap[da] = ga;
+ _pltMap[da] = pa;
+ _gotVector.push_back(ga);
+ _pltVector.push_back(pa);
+ return pa;
+ }
+
+ /// \brief Redirect the call to the PLT stub for the target IFUNC.
+ ///
+ /// This create a PLT and GOT entry for the IFUNC if one does not exist. The
+ /// GOT entry and a IRELATIVE relocation to the original target resolver.
+ std::error_code handleIFUNC(const Reference &ref) {
+ auto target = dyn_cast_or_null<const DefinedAtom>(ref.target());
+ if (target && target->contentType() == DefinedAtom::typeResolver)
+ const_cast<Reference &>(ref).setTarget(getIFUNCPLTEntry(target));
+ return std::error_code();
+ }
+
+ /// \brief Create a GOT entry for the TP offset of a TLS atom.
+ const GOTAtom *getGOTTPOFF(const Atom *atom) {
+ auto got = _gotMap.find(atom);
+ if (got == _gotMap.end()) {
+ auto g = new (_file._alloc) X86_64GOTAtom(_file, ".got");
+ g->addReferenceELF_x86_64(R_X86_64_TPOFF64, 0, atom, 0);
+#ifndef NDEBUG
+ g->_name = "__got_tls_";
+ g->_name += atom->name();
+#endif
+ _gotMap[atom] = g;
+ _gotVector.push_back(g);
+ return g;
+ }
+ return got->second;
+ }
+
+ /// \brief Create a TPOFF64 GOT entry and change the relocation to a PC32 to
+ /// the GOT.
+ void handleGOTTPOFF(const Reference &ref) {
+ const_cast<Reference &>(ref).setTarget(getGOTTPOFF(ref.target()));
+ const_cast<Reference &>(ref).setKindValue(R_X86_64_PC32);
+ }
+
+ /// \brief Create a TLS GOT entry with DTPMOD64/DTPOFF64 dynamic relocations.
+ void handleTLSGd(const Reference &ref) {
+ const_cast<Reference &>(ref).setTarget(getTLSGdGOTEntry(ref.target()));
+ }
+
+ /// \brief Create a GOT entry containing 0.
+ const GOTAtom *getNullGOT() {
+ if (!_null) {
+ _null = new (_file._alloc) X86_64GOTAtom(_file, ".got.plt");
+#ifndef NDEBUG
+ _null->_name = "__got_null";
+#endif
+ }
+ return _null;
+ }
+
+ const GOTAtom *getGOT(const DefinedAtom *da) {
+ auto got = _gotMap.find(da);
+ if (got == _gotMap.end()) {
+ auto g = new (_file._alloc) X86_64GOTAtom(_file, ".got");
+ g->addReferenceELF_x86_64(R_X86_64_64, 0, da, 0);
+#ifndef NDEBUG
+ g->_name = "__got_";
+ g->_name += da->name();
+#endif
+ _gotMap[da] = g;
+ _gotVector.push_back(g);
+ return g;
+ }
+ return got->second;
+ }
+
+ const GOTAtom *getTLSGdGOTEntry(const Atom *a) {
+ auto got = _gotTLSGdMap.find(a);
+ if (got != _gotTLSGdMap.end())
+ return got->second;
+
+ auto ga = new (_file._alloc) GOTTLSGdAtom(_file, ".got");
+ _gotTLSGdMap[a] = ga;
+
+ _tlsGotVector.push_back(ga);
+ ga->addReferenceELF_x86_64(R_X86_64_DTPMOD64, 0, a, 0);
+ ga->addReferenceELF_x86_64(R_X86_64_DTPOFF64, 8, a, 0);
+
+ return ga;
+ }
+
+public:
+ RelocationPass(const ELFLinkingContext &ctx)
+ : _file(ctx), _ctx(ctx), _null(nullptr), _PLT0(nullptr), _got0(nullptr),
+ _got1(nullptr) {}
+
+ /// \brief Do the pass.
+ ///
+ /// The goal here is to first process each reference individually. Each call
+ /// to handleReference may modify the reference itself and/or create new
+ /// atoms which must be stored in one of the maps below.
+ ///
+ /// After all references are handled, the atoms created during that are all
+ /// added to mf.
+ void perform(std::unique_ptr<MutableFile> &mf) override {
+ ScopedTask task(getDefaultDomain(), "X86-64 GOT/PLT Pass");
+ // Process all references.
+ for (const auto &atom : mf->defined())
+ for (const auto &ref : *atom)
+ handleReference(*atom, *ref);
+
+ // Add all created atoms to the link.
+ uint64_t ordinal = 0;
+ if (_PLT0) {
+ _PLT0->setOrdinal(ordinal++);
+ mf->addAtom(*_PLT0);
+ }
+ for (auto &plt : _pltVector) {
+ plt->setOrdinal(ordinal++);
+ mf->addAtom(*plt);
+ }
+ if (_null) {
+ _null->setOrdinal(ordinal++);
+ mf->addAtom(*_null);
+ }
+ if (_PLT0) {
+ _got0->setOrdinal(ordinal++);
+ _got1->setOrdinal(ordinal++);
+ mf->addAtom(*_got0);
+ mf->addAtom(*_got1);
+ }
+ for (auto &got : _gotVector) {
+ got->setOrdinal(ordinal++);
+ mf->addAtom(*got);
+ }
+ for (auto &got : _tlsGotVector) {
+ got->setOrdinal(ordinal++);
+ mf->addAtom(*got);
+ }
+ for (auto obj : _objectVector) {
+ obj->setOrdinal(ordinal++);
+ mf->addAtom(*obj);
+ }
+ }
+
+protected:
+ /// \brief Owner of all the Atoms created by this pass.
+ ELFPassFile _file;
+ const ELFLinkingContext &_ctx;
+
+ /// \brief Map Atoms to their GOT entries.
+ llvm::DenseMap<const Atom *, GOTAtom *> _gotMap;
+
+ /// \brief Map Atoms to their PLT entries.
+ llvm::DenseMap<const Atom *, PLTAtom *> _pltMap;
+
+ /// \brief Map Atoms to TLS GD GOT entries.
+ llvm::DenseMap<const Atom *, GOTAtom *> _gotTLSGdMap;
+
+ /// \brief Map Atoms to their Object entries.
+ llvm::DenseMap<const Atom *, ObjectAtom *> _objectMap;
+
+ /// \brief the list of GOT/PLT atoms
+ std::vector<GOTAtom *> _gotVector;
+ std::vector<PLTAtom *> _pltVector;
+ std::vector<ObjectAtom *> _objectVector;
+
+ /// \brief the list of TLS GOT atoms.
+ std::vector<GOTAtom *> _tlsGotVector;
+
+ /// \brief GOT entry that is always 0. Used for undefined weaks.
+ GOTAtom *_null;
+
+ /// \brief The got and plt entries for .PLT0. This is used to call into the
+ /// dynamic linker for symbol resolution.
+ /// @{
+ PLT0Atom *_PLT0;
+ GOTAtom *_got0;
+ GOTAtom *_got1;
+ /// @}
+};
+
+/// This implements the static relocation model. Meaning GOT and PLT entries are
+/// not created for references that can be directly resolved. These are
+/// converted to a direct relocation. For entries that do require a GOT or PLT
+/// entry, that entry is statically bound.
+///
+/// TLS always assumes module 1 and attempts to remove indirection.
+class StaticRelocationPass final
+ : public RelocationPass<StaticRelocationPass> {
+public:
+ StaticRelocationPass(const elf::X86_64LinkingContext &ctx)
+ : RelocationPass(ctx) {}
+
+ std::error_code handlePlain(const Reference &ref) { return handleIFUNC(ref); }
+
+ std::error_code handlePLT32(const Reference &ref) {
+ // __tls_get_addr is handled elsewhere.
+ if (ref.target() && ref.target()->name() == "__tls_get_addr") {
+ const_cast<Reference &>(ref).setKindValue(R_X86_64_NONE);
+ return std::error_code();
+ }
+ // Static code doesn't need PLTs.
+ const_cast<Reference &>(ref).setKindValue(R_X86_64_PC32);
+ // Handle IFUNC.
+ if (const DefinedAtom *da =
+ dyn_cast_or_null<const DefinedAtom>(ref.target()))
+ if (da->contentType() == DefinedAtom::typeResolver)
+ return handleIFUNC(ref);
+ return std::error_code();
+ }
+
+ std::error_code handleGOT(const Reference &ref) {
+ if (isa<UndefinedAtom>(ref.target()))
+ const_cast<Reference &>(ref).setTarget(getNullGOT());
+ else if (const DefinedAtom *da = dyn_cast<const DefinedAtom>(ref.target()))
+ const_cast<Reference &>(ref).setTarget(getGOT(da));
+ return std::error_code();
+ }
+};
+
+class DynamicRelocationPass final
+ : public RelocationPass<DynamicRelocationPass> {
+public:
+ DynamicRelocationPass(const elf::X86_64LinkingContext &ctx)
+ : RelocationPass(ctx) {}
+
+ const PLT0Atom *getPLT0() {
+ if (_PLT0)
+ return _PLT0;
+ // Fill in the null entry.
+ getNullGOT();
+ _PLT0 = new (_file._alloc) X86_64PLT0Atom(_file);
+ _got0 = new (_file._alloc) X86_64GOTAtom(_file, ".got.plt");
+ _got1 = new (_file._alloc) X86_64GOTAtom(_file, ".got.plt");
+ _PLT0->addReferenceELF_x86_64(R_X86_64_PC32, 2, _got0, -4);
+ _PLT0->addReferenceELF_x86_64(R_X86_64_PC32, 8, _got1, -4);
+#ifndef NDEBUG
+ _got0->_name = "__got0";
+ _got1->_name = "__got1";
+#endif
+ return _PLT0;
+ }
+
+ const PLTAtom *getPLTEntry(const Atom *a) {
+ auto plt = _pltMap.find(a);
+ if (plt != _pltMap.end())
+ return plt->second;
+ auto ga = new (_file._alloc) X86_64GOTAtom(_file, ".got.plt");
+ ga->addReferenceELF_x86_64(R_X86_64_JUMP_SLOT, 0, a, 0);
+ auto pa = new (_file._alloc) X86_64PLTAtom(_file, ".plt");
+ pa->addReferenceELF_x86_64(R_X86_64_PC32, 2, ga, -4);
+ pa->addReferenceELF_x86_64(LLD_R_X86_64_GOTRELINDEX, 7, ga, 0);
+ pa->addReferenceELF_x86_64(R_X86_64_PC32, 12, getPLT0(), -4);
+ // Set the starting address of the got entry to the second instruction in
+ // the plt entry.
+ ga->addReferenceELF_x86_64(R_X86_64_64, 0, pa, 6);
+#ifndef NDEBUG
+ ga->_name = "__got_";
+ ga->_name += a->name();
+ pa->_name = "__plt_";
+ pa->_name += a->name();
+#endif
+ _gotMap[a] = ga;
+ _pltMap[a] = pa;
+ _gotVector.push_back(ga);
+ _pltVector.push_back(pa);
+ return pa;
+ }
+
+ const ObjectAtom *getObjectEntry(const SharedLibraryAtom *a) {
+ auto obj = _objectMap.find(a);
+ if (obj != _objectMap.end())
+ return obj->second;
+
+ auto oa = new (_file._alloc) ObjectAtom(_file);
+ // This needs to point to the atom that we just created.
+ oa->addReferenceELF_x86_64(R_X86_64_COPY, 0, oa, 0);
+
+ oa->_name = a->name();
+ oa->_size = a->size();
+
+ _objectMap[a] = oa;
+ _objectVector.push_back(oa);
+ return oa;
+ }
+
+ std::error_code handlePlain(const Reference &ref) {
+ if (!ref.target())
+ return std::error_code();
+ if (auto sla = dyn_cast<SharedLibraryAtom>(ref.target())) {
+ if (sla->type() == SharedLibraryAtom::Type::Data)
+ const_cast<Reference &>(ref).setTarget(getObjectEntry(sla));
+ else if (sla->type() == SharedLibraryAtom::Type::Code)
+ const_cast<Reference &>(ref).setTarget(getPLTEntry(sla));
+ } else
+ return handleIFUNC(ref);
+ return std::error_code();
+ }
+
+ std::error_code handlePLT32(const Reference &ref) {
+ // Turn this into a PC32 to the PLT entry.
+ const_cast<Reference &>(ref).setKindValue(R_X86_64_PC32);
+ // Handle IFUNC.
+ if (const DefinedAtom *da =
+ dyn_cast_or_null<const DefinedAtom>(ref.target()))
+ if (da->contentType() == DefinedAtom::typeResolver)
+ return handleIFUNC(ref);
+ // If it is undefined at link time, push the work to the dynamic linker by
+ // creating a PLT entry
+ if (isa<SharedLibraryAtom>(ref.target()) ||
+ isa<UndefinedAtom>(ref.target()))
+ const_cast<Reference &>(ref).setTarget(getPLTEntry(ref.target()));
+ return std::error_code();
+ }
+
+ const GOTAtom *getSharedGOT(const Atom *a) {
+ auto got = _gotMap.find(a);
+ if (got == _gotMap.end()) {
+ auto g = new (_file._alloc) X86_64GOTAtom(_file, ".got");
+ g->addReferenceELF_x86_64(R_X86_64_GLOB_DAT, 0, a, 0);
+#ifndef NDEBUG
+ g->_name = "__got_";
+ g->_name += a->name();
+#endif
+ _gotMap[a] = g;
+ _gotVector.push_back(g);
+ return g;
+ }
+ return got->second;
+ }
+
+ std::error_code handleGOT(const Reference &ref) {
+ if (const DefinedAtom *da = dyn_cast<const DefinedAtom>(ref.target()))
+ const_cast<Reference &>(ref).setTarget(getGOT(da));
+ // Handle undefined atoms in the same way as shared lib atoms: to be
+ // resolved at run time.
+ else if (isa<SharedLibraryAtom>(ref.target()) ||
+ isa<UndefinedAtom>(ref.target()))
+ const_cast<Reference &>(ref).setTarget(getSharedGOT(ref.target()));
+ return std::error_code();
+ }
+};
+} // end anon namespace
+
+std::unique_ptr<Pass>
+lld::elf::createX86_64RelocationPass(const X86_64LinkingContext &ctx) {
+ switch (ctx.getOutputELFType()) {
+ case llvm::ELF::ET_EXEC:
+ if (ctx.isDynamic())
+ return llvm::make_unique<DynamicRelocationPass>(ctx);
+ return llvm::make_unique<StaticRelocationPass>(ctx);
+ case llvm::ELF::ET_DYN:
+ return llvm::make_unique<DynamicRelocationPass>(ctx);
+ case llvm::ELF::ET_REL:
+ return nullptr;
+ default:
+ llvm_unreachable("Unhandled output file type");
+ }
+}
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.h b/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.h
new file mode 100644
index 000000000000..1635b5e5f57b
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.h
@@ -0,0 +1,32 @@
+//===- lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.h -----------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Declares the relocation processing pass for x86-64. This includes
+/// GOT and PLT entries, TLS, COPY, and ifunc.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_X86_64_X86_64_RELOCATION_PASS_H
+#define LLD_READER_WRITER_ELF_X86_64_X86_64_RELOCATION_PASS_H
+
+#include <memory>
+
+namespace lld {
+class Pass;
+namespace elf {
+class X86_64LinkingContext;
+
+/// \brief Create x86-64 relocation pass for the given linking context.
+std::unique_ptr<Pass>
+createX86_64RelocationPass(const X86_64LinkingContext &);
+}
+}
+
+#endif
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.cpp b/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.cpp
new file mode 100644
index 000000000000..f35330eb25c0
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.cpp
@@ -0,0 +1,52 @@
+//===- lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.cpp ----------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Atoms.h"
+#include "X86_64DynamicLibraryWriter.h"
+#include "X86_64ExecutableWriter.h"
+#include "X86_64LinkingContext.h"
+#include "X86_64TargetHandler.h"
+
+using namespace lld;
+using namespace elf;
+
+X86_64TargetHandler::X86_64TargetHandler(X86_64LinkingContext &context)
+ : _context(context), _x86_64TargetLayout(new X86_64TargetLayout(context)),
+ _x86_64RelocationHandler(
+ new X86_64TargetRelocationHandler(*_x86_64TargetLayout.get())) {}
+
+void X86_64TargetHandler::registerRelocationNames(Registry &registry) {
+ registry.addKindTable(Reference::KindNamespace::ELF,
+ Reference::KindArch::x86_64, kindStrings);
+}
+
+std::unique_ptr<Writer> X86_64TargetHandler::getWriter() {
+ switch (this->_context.getOutputELFType()) {
+ case llvm::ELF::ET_EXEC:
+ return std::unique_ptr<Writer>(
+ new X86_64ExecutableWriter(_context, *_x86_64TargetLayout.get()));
+ case llvm::ELF::ET_DYN:
+ return std::unique_ptr<Writer>(
+ new X86_64DynamicLibraryWriter(_context, *_x86_64TargetLayout.get()));
+ case llvm::ELF::ET_REL:
+ llvm_unreachable("TODO: support -r mode");
+ default:
+ llvm_unreachable("unsupported output type");
+ }
+}
+
+#define ELF_RELOC(name, value) LLD_KIND_STRING_ENTRY(name),
+
+const Registry::KindStrings X86_64TargetHandler::kindStrings[] = {
+#include "llvm/Support/ELFRelocs/x86_64.def"
+ LLD_KIND_STRING_ENTRY(LLD_R_X86_64_GOTRELINDEX),
+ LLD_KIND_STRING_END
+};
+
+#undef ELF_RELOC
diff --git a/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h b/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h
new file mode 100644
index 000000000000..57da7bca01e6
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h
@@ -0,0 +1,69 @@
+//===- lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h ------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_X86_64_X86_64_TARGET_HANDLER_H
+#define LLD_READER_WRITER_ELF_X86_64_X86_64_TARGET_HANDLER_H
+
+#include "DefaultTargetHandler.h"
+#include "TargetLayout.h"
+#include "X86_64ELFFile.h"
+#include "X86_64ELFReader.h"
+#include "X86_64LinkingContext.h"
+#include "X86_64RelocationHandler.h"
+#include "lld/Core/Simple.h"
+
+namespace lld {
+namespace elf {
+class X86_64TargetLayout : public TargetLayout<X86_64ELFType> {
+public:
+ X86_64TargetLayout(X86_64LinkingContext &context)
+ : TargetLayout(context) {}
+
+ void finalizeOutputSectionLayout() override {
+ sortOutputSectionByPriority(".init_array", ".init_array");
+ sortOutputSectionByPriority(".fini_array", ".fini_array");
+ }
+};
+
+class X86_64TargetHandler
+ : public DefaultTargetHandler<X86_64ELFType> {
+public:
+ X86_64TargetHandler(X86_64LinkingContext &context);
+
+ X86_64TargetLayout &getTargetLayout() override {
+ return *(_x86_64TargetLayout.get());
+ }
+
+ void registerRelocationNames(Registry &registry) override;
+
+ const X86_64TargetRelocationHandler &getRelocationHandler() const override {
+ return *(_x86_64RelocationHandler.get());
+ }
+
+ std::unique_ptr<Reader> getObjReader() override {
+ return std::unique_ptr<Reader>(new X86_64ELFObjectReader(_context));
+ }
+
+ std::unique_ptr<Reader> getDSOReader() override {
+ return std::unique_ptr<Reader>(new X86_64ELFDSOReader(_context));
+ }
+
+ std::unique_ptr<Writer> getWriter() override;
+
+protected:
+ static const Registry::KindStrings kindStrings[];
+ X86_64LinkingContext &_context;
+ std::unique_ptr<X86_64TargetLayout> _x86_64TargetLayout;
+ std::unique_ptr<X86_64TargetRelocationHandler> _x86_64RelocationHandler;
+};
+
+} // end namespace elf
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/FileArchive.cpp b/lib/ReaderWriter/FileArchive.cpp
new file mode 100644
index 000000000000..3f38814ae18e
--- /dev/null
+++ b/lib/ReaderWriter/FileArchive.cpp
@@ -0,0 +1,293 @@
+//===- 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/Core/ArchiveLibraryFile.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/LinkingContext.h"
+#include "lld/Core/Parallel.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <memory>
+#include <mutex>
+#include <set>
+#include <unordered_map>
+
+using llvm::object::Archive;
+using llvm::object::ObjectFile;
+using llvm::object::SymbolRef;
+using llvm::object::symbol_iterator;
+using llvm::object::object_error;
+
+namespace lld {
+
+namespace {
+
+/// \brief 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) {}
+
+ /// \brief Check if any member of the archive contains an Atom with the
+ /// specified name and return the File object for that member, or nullptr.
+ File *find(StringRef name, bool dataSymbolOnly) override {
+ auto member = _symbolMemberMap.find(name);
+ if (member == _symbolMemberMap.end())
+ return nullptr;
+ Archive::child_iterator ci = member->second;
+
+ // Don't return a member already returned
+ const char *memberStart = ci->getBuffer().data();
+ if (_membersInstantiated.count(memberStart))
+ return nullptr;
+ if (dataSymbolOnly && !isDataSymbol(ci, name))
+ return nullptr;
+
+ _membersInstantiated.insert(memberStart);
+
+ // Check if a file is preloaded.
+ {
+ std::lock_guard<std::mutex> lock(_mutex);
+ auto it = _preloaded.find(memberStart);
+ if (it != _preloaded.end()) {
+ std::unique_ptr<Future<File *>> &p = it->second;
+ Future<File *> *future = p.get();
+ return future->get();
+ }
+ }
+
+ std::unique_ptr<File> result;
+ if (instantiateMember(ci, result))
+ return nullptr;
+
+ // give up the pointer so that this object no longer manages it
+ return result.release();
+ }
+
+ // Instantiate a member file containing a given symbol name.
+ void preload(TaskGroup &group, StringRef name) override {
+ auto member = _symbolMemberMap.find(name);
+ if (member == _symbolMemberMap.end())
+ return;
+ Archive::child_iterator ci = member->second;
+
+ // Do nothing if a member is already instantiated.
+ const char *memberStart = ci->getBuffer().data();
+ if (_membersInstantiated.count(memberStart))
+ return;
+
+ std::lock_guard<std::mutex> lock(_mutex);
+ if (_preloaded.find(memberStart) != _preloaded.end())
+ return;
+
+ // Instantiate the member
+ auto *future = new Future<File *>();
+ _preloaded[memberStart] = std::unique_ptr<Future<File *>>(future);
+
+ group.spawn([=] {
+ std::unique_ptr<File> result;
+ std::error_code ec = instantiateMember(ci, result);
+ future->set(ec ? nullptr : result.release());
+ });
+ }
+
+ /// \brief parse each member
+ std::error_code
+ parseAllMembers(std::vector<std::unique_ptr<File>> &result) override {
+ if (std::error_code ec = parse())
+ return ec;
+ for (auto mf = _archive->child_begin(), me = _archive->child_end();
+ mf != me; ++mf) {
+ std::unique_ptr<File> file;
+ if (std::error_code ec = instantiateMember(mf, file))
+ return ec;
+ result.push_back(std::move(file));
+ }
+ return std::error_code();
+ }
+
+ const atom_collection<DefinedAtom> &defined() const override {
+ return _definedAtoms;
+ }
+
+ const atom_collection<UndefinedAtom> &undefined() const override {
+ return _undefinedAtoms;
+ }
+
+ const atom_collection<SharedLibraryAtom> &sharedLibrary() const override {
+ return _sharedLibraryAtoms;
+ }
+
+ const atom_collection<AbsoluteAtom> &absolute() const override {
+ return _absoluteAtoms;
+ }
+
+ /// Returns a set of all defined symbols in the archive.
+ std::set<StringRef> getDefinedSymbols() override {
+ parse();
+ std::set<StringRef> ret;
+ for (const auto &e : _symbolMemberMap)
+ ret.insert(e.first);
+ return ret;
+ }
+
+protected:
+ std::error_code doParse() override {
+ // Make Archive object which will be owned by FileArchive object.
+ std::error_code ec;
+ _archive.reset(new Archive(_mb->getMemBufferRef(), ec));
+ if (ec)
+ return ec;
+ if ((ec = buildTableOfContents()))
+ return ec;
+ return std::error_code();
+ }
+
+private:
+ std::error_code
+ instantiateMember(Archive::child_iterator member,
+ std::unique_ptr<File> &result) const {
+ ErrorOr<llvm::MemoryBufferRef> mbOrErr = member->getMemoryBufferRef();
+ if (std::error_code ec = mbOrErr.getError())
+ return ec;
+ 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));
+
+ std::vector<std::unique_ptr<File>> files;
+ if (std::error_code ec = _registry.loadFile(std::move(memberMB), files))
+ return ec;
+ assert(files.size() == 1);
+ result = std::move(files[0]);
+ 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();
+ }
+
+ // Parses the given memory buffer as an object file, and returns true
+ // code if the given symbol is a data symbol. If the symbol is not a data
+ // symbol or does not exist, returns false.
+ bool isDataSymbol(Archive::child_iterator member, StringRef symbol) const {
+ ErrorOr<llvm::MemoryBufferRef> buf = member->getMemoryBufferRef();
+ if (buf.getError())
+ return false;
+ std::unique_ptr<MemoryBuffer> mb(MemoryBuffer::getMemBuffer(
+ buf.get().getBuffer(), buf.get().getBufferIdentifier(), false));
+
+ auto objOrErr(ObjectFile::createObjectFile(mb->getMemBufferRef()));
+ if (objOrErr.getError())
+ return false;
+ std::unique_ptr<ObjectFile> obj = std::move(objOrErr.get());
+
+ for (SymbolRef sym : obj->symbols()) {
+ // Skip until we find the symbol.
+ StringRef name;
+ if (sym.getName(name))
+ return false;
+ if (name != symbol)
+ continue;
+ uint32_t flags = sym.getFlags();
+ if (flags <= SymbolRef::SF_Undefined)
+ continue;
+
+ // Returns true if it's a data symbol.
+ SymbolRef::Type type;
+ if (sym.getType(type))
+ return false;
+ if (type == SymbolRef::ST_Data)
+ return true;
+ }
+ return false;
+ }
+
+ std::error_code buildTableOfContents() {
+ DEBUG_WITH_TYPE("FileArchive", llvm::dbgs()
+ << "Table of contents for archive '"
+ << _archive->getFileName() << "':\n");
+ for (const Archive::Symbol &sym : _archive->symbols()) {
+ StringRef name = sym.getName();
+ ErrorOr<Archive::child_iterator> memberOrErr = sym.getMember();
+ if (std::error_code ec = memberOrErr.getError())
+ return ec;
+ Archive::child_iterator member = memberOrErr.get();
+ DEBUG_WITH_TYPE(
+ "FileArchive",
+ llvm::dbgs() << llvm::format("0x%08llX ", member->getBuffer().data())
+ << "'" << name << "'\n");
+ _symbolMemberMap[name] = member;
+ }
+ return std::error_code();
+ }
+
+ typedef std::unordered_map<StringRef, Archive::child_iterator> MemberMap;
+ typedef std::set<const char *> InstantiatedSet;
+
+ std::shared_ptr<MemoryBuffer> _mb;
+ const Registry &_registry;
+ std::unique_ptr<Archive> _archive;
+ MemberMap _symbolMemberMap;
+ InstantiatedSet _membersInstantiated;
+ atom_collection_vector<DefinedAtom> _definedAtoms;
+ atom_collection_vector<UndefinedAtom> _undefinedAtoms;
+ atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
+ atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
+ bool _logLoading;
+ std::vector<std::unique_ptr<MemoryBuffer>> _memberBuffers;
+ std::map<const char *, std::unique_ptr<Future<File *>>> _preloaded;
+ std::mutex _mutex;
+};
+
+class ArchiveReader : public Reader {
+public:
+ ArchiveReader(bool logLoading) : _logLoading(logLoading) {}
+
+ bool canParse(file_magic magic, StringRef,
+ const MemoryBuffer &) const override {
+ return (magic == llvm::sys::fs::file_magic::archive);
+ }
+
+ std::error_code
+ loadFile(std::unique_ptr<MemoryBuffer> mb, const Registry &reg,
+ std::vector<std::unique_ptr<File>> &result) const override {
+ StringRef path = mb->getBufferIdentifier();
+ std::unique_ptr<FileArchive> file(
+ new FileArchive(std::move(mb), reg, path, _logLoading));
+ result.push_back(std::move(file));
+ return std::error_code();
+ }
+
+private:
+ bool _logLoading;
+};
+
+} // anonymous namespace
+
+void Registry::addSupportArchives(bool logLoading) {
+ add(std::unique_ptr<Reader>(new ArchiveReader(logLoading)));
+}
+
+} // end namespace lld
diff --git a/lib/ReaderWriter/LinkerScript.cpp b/lib/ReaderWriter/LinkerScript.cpp
new file mode 100644
index 000000000000..56194cae5e72
--- /dev/null
+++ b/lib/ReaderWriter/LinkerScript.cpp
@@ -0,0 +1,2564 @@
+//===- ReaderWriter/LinkerScript.cpp --------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Linker script parser.
+///
+//===----------------------------------------------------------------------===//
+
+#include "lld/ReaderWriter/LinkerScript.h"
+
+namespace lld {
+namespace script {
+void Token::dump(raw_ostream &os) const {
+ switch (_kind) {
+#define CASE(name) \
+ case Token::name: \
+ os << #name ": "; \
+ break;
+ CASE(unknown)
+ CASE(eof)
+ CASE(exclaim)
+ CASE(exclaimequal)
+ CASE(amp)
+ CASE(ampequal)
+ CASE(l_paren)
+ CASE(r_paren)
+ CASE(star)
+ CASE(starequal)
+ CASE(plus)
+ CASE(plusequal)
+ CASE(comma)
+ CASE(minus)
+ CASE(minusequal)
+ CASE(slash)
+ CASE(slashequal)
+ CASE(number)
+ CASE(colon)
+ CASE(semicolon)
+ CASE(less)
+ CASE(lessequal)
+ CASE(lessless)
+ CASE(lesslessequal)
+ CASE(equal)
+ CASE(equalequal)
+ CASE(greater)
+ CASE(greaterequal)
+ CASE(greatergreater)
+ CASE(greatergreaterequal)
+ CASE(question)
+ CASE(identifier)
+ CASE(libname)
+ CASE(kw_align)
+ CASE(kw_align_with_input)
+ CASE(kw_as_needed)
+ CASE(kw_at)
+ CASE(kw_discard)
+ CASE(kw_entry)
+ CASE(kw_exclude_file)
+ CASE(kw_extern)
+ CASE(kw_group)
+ CASE(kw_hidden)
+ CASE(kw_input)
+ CASE(kw_keep)
+ CASE(kw_length)
+ CASE(kw_memory)
+ CASE(kw_origin)
+ CASE(kw_provide)
+ CASE(kw_provide_hidden)
+ CASE(kw_only_if_ro)
+ CASE(kw_only_if_rw)
+ CASE(kw_output)
+ CASE(kw_output_arch)
+ CASE(kw_output_format)
+ CASE(kw_overlay)
+ CASE(kw_search_dir)
+ CASE(kw_sections)
+ CASE(kw_sort_by_alignment)
+ CASE(kw_sort_by_init_priority)
+ CASE(kw_sort_by_name)
+ CASE(kw_sort_none)
+ CASE(kw_subalign)
+ CASE(l_brace)
+ CASE(pipe)
+ CASE(pipeequal)
+ CASE(r_brace)
+ CASE(tilde)
+#undef CASE
+ }
+ os << _range << "\n";
+}
+
+static llvm::ErrorOr<uint64_t> parseDecimal(StringRef str) {
+ uint64_t res = 0;
+ for (auto &c : str) {
+ res *= 10;
+ if (c < '0' || c > '9')
+ return llvm::ErrorOr<uint64_t>(std::make_error_code(std::errc::io_error));
+ res += c - '0';
+ }
+ return res;
+}
+
+static llvm::ErrorOr<uint64_t> parseOctal(StringRef str) {
+ uint64_t res = 0;
+ for (auto &c : str) {
+ res <<= 3;
+ if (c < '0' || c > '7')
+ return llvm::ErrorOr<uint64_t>(std::make_error_code(std::errc::io_error));
+ res += c - '0';
+ }
+ return res;
+}
+
+static llvm::ErrorOr<uint64_t> parseBinary(StringRef str) {
+ uint64_t res = 0;
+ for (auto &c : str) {
+ res <<= 1;
+ if (c != '0' && c != '1')
+ return llvm::ErrorOr<uint64_t>(std::make_error_code(std::errc::io_error));
+ res += c - '0';
+ }
+ return res;
+}
+
+static llvm::ErrorOr<uint64_t> parseHex(StringRef str) {
+ uint64_t res = 0;
+ for (auto &c : str) {
+ res <<= 4;
+ if (c >= '0' && c <= '9')
+ res += c - '0';
+ else if (c >= 'a' && c <= 'f')
+ res += c - 'a' + 10;
+ else if (c >= 'A' && c <= 'F')
+ res += c - 'A' + 10;
+ else
+ return llvm::ErrorOr<uint64_t>(std::make_error_code(std::errc::io_error));
+ }
+ return res;
+}
+
+static bool parseHexToByteStream(StringRef str, std::string &buf) {
+ unsigned char byte = 0;
+ bool dumpByte = str.size() % 2;
+ for (auto &c : str) {
+ byte <<= 4;
+ if (c >= '0' && c <= '9')
+ byte += c - '0';
+ else if (c >= 'a' && c <= 'f')
+ byte += c - 'a' + 10;
+ else if (c >= 'A' && c <= 'F')
+ byte += c - 'A' + 10;
+ else
+ return false;
+ if (!dumpByte) {
+ dumpByte = true;
+ continue;
+ }
+ buf.push_back(byte);
+ byte = 0;
+ dumpByte = false;
+ }
+ return !dumpByte;
+}
+
+static void dumpByteStream(raw_ostream &os, StringRef stream) {
+ os << "0x";
+ for (auto &c : stream) {
+ unsigned char firstNibble = c >> 4 & 0xF;
+ if (firstNibble > 9)
+ os << (char) ('A' + firstNibble - 10);
+ else
+ os << (char) ('0' + firstNibble);
+ unsigned char secondNibble = c & 0xF;
+ if (secondNibble > 9)
+ os << (char) ('A' + secondNibble - 10);
+ else
+ os << (char) ('0' + secondNibble);
+ }
+}
+
+static llvm::ErrorOr<uint64_t> parseNum(StringRef str) {
+ unsigned multiplier = 1;
+ enum NumKind { decimal, hex, octal, binary };
+ NumKind kind = llvm::StringSwitch<NumKind>(str)
+ .StartsWith("0x", hex)
+ .StartsWith("0X", hex)
+ .StartsWith("0", octal)
+ .Default(decimal);
+
+ // Parse scale
+ if (str.endswith("K")) {
+ multiplier = 1 << 10;
+ str = str.drop_back();
+ } else if (str.endswith("M")) {
+ multiplier = 1 << 20;
+ str = str.drop_back();
+ }
+
+ // Parse type
+ if (str.endswith_lower("o")) {
+ kind = octal;
+ str = str.drop_back();
+ } else if (str.endswith_lower("h")) {
+ kind = hex;
+ str = str.drop_back();
+ } else if (str.endswith_lower("d")) {
+ kind = decimal;
+ str = str.drop_back();
+ } else if (str.endswith_lower("b")) {
+ kind = binary;
+ str = str.drop_back();
+ }
+
+ llvm::ErrorOr<uint64_t> res(0);
+ switch (kind) {
+ case hex:
+ if (str.startswith_lower("0x"))
+ str = str.drop_front(2);
+ res = parseHex(str);
+ break;
+ case octal:
+ res = parseOctal(str);
+ break;
+ case decimal:
+ res = parseDecimal(str);
+ break;
+ case binary:
+ res = parseBinary(str);
+ break;
+ }
+ if (res.getError())
+ return res;
+
+ *res = *res * multiplier;
+ return res;
+}
+
+bool Lexer::canStartNumber(char c) const {
+ return '0' <= c && c <= '9';
+}
+
+bool Lexer::canContinueNumber(char c) const {
+ // [xX] = hex marker, [hHoO] = type suffix, [MK] = scale suffix.
+ return strchr("0123456789ABCDEFabcdefxXhHoOMK", c);
+}
+
+bool Lexer::canStartName(char c) const {
+ return strchr(
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_.$/\\*", c);
+}
+
+bool Lexer::canContinueName(char c) const {
+ return strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+ "0123456789_.$/\\~=+[]*?-:", c);
+}
+
+/// Helper function to split a StringRef in two at the nth character.
+/// The StringRef s is updated, while the function returns the n first
+/// characters.
+static StringRef drop(StringRef &s, int n) {
+ StringRef res = s.substr(0, n);
+ s = s.drop_front(n);
+ return res;
+}
+
+void Lexer::lex(Token &tok) {
+ skipWhitespace();
+ if (_buffer.empty()) {
+ tok = Token(_buffer, Token::eof);
+ return;
+ }
+ switch (_buffer[0]) {
+ case 0:
+ tok = Token(drop(_buffer, 1), Token::eof);
+ return;
+ case '(':
+ tok = Token(drop(_buffer, 1), Token::l_paren);
+ return;
+ case ')':
+ tok = Token(drop(_buffer, 1), Token::r_paren);
+ return;
+ case '{':
+ tok = Token(drop(_buffer, 1), Token::l_brace);
+ return;
+ case '}':
+ tok = Token(drop(_buffer, 1), Token::r_brace);
+ return;
+ case '=':
+ if (_buffer.startswith("==")) {
+ tok = Token(drop(_buffer, 2), Token::equalequal);
+ return;
+ }
+ tok = Token(drop(_buffer, 1), Token::equal);
+ return;
+ case '!':
+ if (_buffer.startswith("!=")) {
+ tok = Token(drop(_buffer, 2), Token::exclaimequal);
+ return;
+ }
+ tok = Token(drop(_buffer, 1), Token::exclaim);
+ return;
+ case ',':
+ tok = Token(drop(_buffer, 1), Token::comma);
+ return;
+ case ';':
+ tok = Token(drop(_buffer, 1), Token::semicolon);
+ return;
+ case ':':
+ tok = Token(drop(_buffer, 1), Token::colon);
+ return;
+ case '&':
+ if (_buffer.startswith("&=")) {
+ tok = Token(drop(_buffer, 2), Token::ampequal);
+ return;
+ }
+ tok = Token(drop(_buffer, 1), Token::amp);
+ return;
+ case '|':
+ if (_buffer.startswith("|=")) {
+ tok = Token(drop(_buffer, 2), Token::pipeequal);
+ return;
+ }
+ tok = Token(drop(_buffer, 1), Token::pipe);
+ return;
+ case '+':
+ if (_buffer.startswith("+=")) {
+ tok = Token(drop(_buffer, 2), Token::plusequal);
+ return;
+ }
+ tok = Token(drop(_buffer, 1), Token::plus);
+ return;
+ case '-': {
+ if (_buffer.startswith("-=")) {
+ tok = Token(drop(_buffer, 2), Token::minusequal);
+ return;
+ }
+ if (!_buffer.startswith("-l")) {
+ tok = Token(drop(_buffer, 1), Token::minus);
+ return;
+ }
+ // -l<lib name>
+ _buffer = _buffer.drop_front(2);
+ StringRef::size_type start = 0;
+ if (_buffer[start] == ':')
+ ++start;
+ if (!canStartName(_buffer[start]))
+ // Create 'unknown' token.
+ break;
+ auto libNameEnd = std::find_if(_buffer.begin() + start + 1, _buffer.end(),
+ [=](char c) { return !canContinueName(c); });
+ StringRef::size_type libNameLen =
+ std::distance(_buffer.begin(), libNameEnd);
+ tok = Token(_buffer.substr(0, libNameLen), Token::libname);
+ _buffer = _buffer.drop_front(libNameLen);
+ return;
+ }
+ case '<':
+ if (_buffer.startswith("<<=")) {
+ tok = Token(drop(_buffer, 3), Token::lesslessequal);
+ return;
+ }
+ if (_buffer.startswith("<<")) {
+ tok = Token(drop(_buffer, 2), Token::lessless);
+ return;
+ }
+ if (_buffer.startswith("<=")) {
+ tok = Token(drop(_buffer, 2), Token::lessequal);
+ return;
+ }
+ tok = Token(drop(_buffer, 1), Token::less);
+ return;
+ case '>':
+ if (_buffer.startswith(">>=")) {
+ tok = Token(drop(_buffer, 3), Token::greatergreaterequal);
+ return;
+ }
+ if (_buffer.startswith(">>")) {
+ tok = Token(drop(_buffer, 2), Token::greatergreater);
+ return;
+ }
+ if (_buffer.startswith(">=")) {
+ tok = Token(drop(_buffer, 2), Token::greaterequal);
+ return;
+ }
+ tok = Token(drop(_buffer, 1), Token::greater);
+ return;
+ case '~':
+ tok = Token(drop(_buffer, 1), Token::tilde);
+ return;
+ case '\"': case '\'': {
+ // Handle quoted strings. They are treated as identifiers for
+ // simplicity.
+ char c = _buffer[0];
+ _buffer = _buffer.drop_front();
+ auto quotedStringEnd = _buffer.find(c);
+ if (quotedStringEnd == StringRef::npos || quotedStringEnd == 0)
+ break;
+ StringRef word = _buffer.substr(0, quotedStringEnd);
+ tok = Token(word, Token::identifier);
+ _buffer = _buffer.drop_front(quotedStringEnd + 1);
+ return;
+ }
+ default:
+ // Handle literal numbers
+ if (canStartNumber(_buffer[0])) {
+ auto endIter = std::find_if(_buffer.begin(), _buffer.end(), [=](char c) {
+ return !canContinueNumber(c);
+ });
+ StringRef::size_type end = endIter == _buffer.end()
+ ? StringRef::npos
+ : std::distance(_buffer.begin(), endIter);
+ if (end == StringRef::npos || end == 0)
+ break;
+ StringRef word = _buffer.substr(0, end);
+ tok = Token(word, Token::number);
+ _buffer = _buffer.drop_front(end);
+ return;
+ }
+ // Handle slashes '/', which can be either an operator inside an expression
+ // or the beginning of an identifier
+ if (_buffer.startswith("/=")) {
+ tok = Token(drop(_buffer, 2), Token::slashequal);
+ return;
+ }
+ if (_buffer[0] == '/' && _buffer.size() > 1 &&
+ !canContinueName(_buffer[1])) {
+ tok = Token(drop(_buffer, 1), Token::slash);
+ return;
+ }
+ // Handle stars '*'
+ if (_buffer.startswith("*=")) {
+ tok = Token(drop(_buffer, 2), Token::starequal);
+ return;
+ }
+ if (_buffer[0] == '*' && _buffer.size() > 1 &&
+ !canContinueName(_buffer[1])) {
+ tok = Token(drop(_buffer, 1), Token::star);
+ return;
+ }
+ // Handle questions '?'
+ if (_buffer[0] == '?' && _buffer.size() > 1 &&
+ !canContinueName(_buffer[1])) {
+ tok = Token(drop(_buffer, 1), Token::question);
+ return;
+ }
+ // keyword or identifier.
+ if (!canStartName(_buffer[0]))
+ break;
+ auto endIter = std::find_if(_buffer.begin() + 1, _buffer.end(),
+ [=](char c) { return !canContinueName(c); });
+ StringRef::size_type end = endIter == _buffer.end()
+ ? StringRef::npos
+ : std::distance(_buffer.begin(), endIter);
+ if (end == StringRef::npos || end == 0)
+ break;
+ StringRef word = _buffer.substr(0, end);
+ Token::Kind kind =
+ llvm::StringSwitch<Token::Kind>(word)
+ .Case("ALIGN", Token::kw_align)
+ .Case("ALIGN_WITH_INPUT", Token::kw_align_with_input)
+ .Case("AS_NEEDED", Token::kw_as_needed)
+ .Case("AT", Token::kw_at)
+ .Case("ENTRY", Token::kw_entry)
+ .Case("EXCLUDE_FILE", Token::kw_exclude_file)
+ .Case("EXTERN", Token::kw_extern)
+ .Case("GROUP", Token::kw_group)
+ .Case("HIDDEN", Token::kw_hidden)
+ .Case("INPUT", Token::kw_input)
+ .Case("KEEP", Token::kw_keep)
+ .Case("LENGTH", Token::kw_length)
+ .Case("l", Token::kw_length)
+ .Case("len", Token::kw_length)
+ .Case("MEMORY", Token::kw_memory)
+ .Case("ONLY_IF_RO", Token::kw_only_if_ro)
+ .Case("ONLY_IF_RW", Token::kw_only_if_rw)
+ .Case("ORIGIN", Token::kw_origin)
+ .Case("o", Token::kw_origin)
+ .Case("org", Token::kw_origin)
+ .Case("OUTPUT", Token::kw_output)
+ .Case("OUTPUT_ARCH", Token::kw_output_arch)
+ .Case("OUTPUT_FORMAT", Token::kw_output_format)
+ .Case("OVERLAY", Token::kw_overlay)
+ .Case("PROVIDE", Token::kw_provide)
+ .Case("PROVIDE_HIDDEN", Token::kw_provide_hidden)
+ .Case("SEARCH_DIR", Token::kw_search_dir)
+ .Case("SECTIONS", Token::kw_sections)
+ .Case("SORT", Token::kw_sort_by_name)
+ .Case("SORT_BY_ALIGNMENT", Token::kw_sort_by_alignment)
+ .Case("SORT_BY_INIT_PRIORITY", Token::kw_sort_by_init_priority)
+ .Case("SORT_BY_NAME", Token::kw_sort_by_name)
+ .Case("SORT_NONE", Token::kw_sort_none)
+ .Case("SUBALIGN", Token::kw_subalign)
+ .Case("/DISCARD/", Token::kw_discard)
+ .Default(Token::identifier);
+ tok = Token(word, kind);
+ _buffer = _buffer.drop_front(end);
+ return;
+ }
+ tok = Token(drop(_buffer, 1), Token::unknown);
+}
+
+void Lexer::skipWhitespace() {
+ while (true) {
+ if (_buffer.empty())
+ return;
+ switch (_buffer[0]) {
+ case ' ':
+ case '\r':
+ case '\n':
+ case '\t':
+ _buffer = _buffer.drop_front();
+ break;
+ // Potential comment.
+ case '/':
+ if (_buffer.size() <= 1 || _buffer[1] != '*')
+ return;
+ // Skip starting /*
+ _buffer = _buffer.drop_front(2);
+ // If the next char is also a /, it's not the end.
+ if (!_buffer.empty() && _buffer[0] == '/')
+ _buffer = _buffer.drop_front();
+
+ // Scan for /'s. We're done if it is preceded by a *.
+ while (true) {
+ if (_buffer.empty())
+ break;
+ _buffer = _buffer.drop_front();
+ if (_buffer.data()[-1] == '/' && _buffer.data()[-2] == '*')
+ break;
+ }
+ break;
+ default:
+ return;
+ }
+ }
+}
+
+// Constant functions
+void Constant::dump(raw_ostream &os) const { os << _num; }
+
+ErrorOr<int64_t> Constant::evalExpr(SymbolTableTy &symbolTable) const {
+ return _num;
+}
+
+// Symbol functions
+void Symbol::dump(raw_ostream &os) const { os << _name; }
+
+ErrorOr<int64_t> Symbol::evalExpr(SymbolTableTy &symbolTable) const {
+ auto it = symbolTable.find(_name);
+ if (it == symbolTable.end())
+ return LinkerScriptReaderError::unknown_symbol_in_expr;
+ return it->second;
+}
+
+// FunctionCall functions
+void FunctionCall::dump(raw_ostream &os) const {
+ os << _name << "(";
+ for (unsigned i = 0, e = _args.size(); i != e; ++i) {
+ if (i)
+ os << ", ";
+ _args[i]->dump(os);
+ }
+ os << ")";
+}
+
+ErrorOr<int64_t> FunctionCall::evalExpr(SymbolTableTy &symbolTable) const {
+ return LinkerScriptReaderError::unrecognized_function_in_expr;
+}
+
+// Unary functions
+void Unary::dump(raw_ostream &os) const {
+ os << "(";
+ if (_op == Unary::Minus)
+ os << "-";
+ else
+ os << "~";
+ _child->dump(os);
+ os << ")";
+}
+
+ErrorOr<int64_t> Unary::evalExpr(SymbolTableTy &symbolTable) const {
+ auto child = _child->evalExpr(symbolTable);
+ if (child.getError())
+ return child.getError();
+
+ int64_t childRes = *child;
+ switch (_op) {
+ case Unary::Minus:
+ return -childRes;
+ case Unary::Not:
+ return ~childRes;
+ }
+
+ llvm_unreachable("");
+}
+
+// BinOp functions
+void BinOp::dump(raw_ostream &os) const {
+ os << "(";
+ _lhs->dump(os);
+ os << " ";
+ switch (_op) {
+ case Sum:
+ os << "+";
+ break;
+ case Sub:
+ os << "-";
+ break;
+ case Mul:
+ os << "*";
+ break;
+ case Div:
+ os << "/";
+ break;
+ case Shl:
+ os << "<<";
+ break;
+ case Shr:
+ os << ">>";
+ break;
+ case And:
+ os << "&";
+ break;
+ case Or:
+ os << "|";
+ break;
+ case CompareEqual:
+ os << "==";
+ break;
+ case CompareDifferent:
+ os << "!=";
+ break;
+ case CompareLess:
+ os << "<";
+ break;
+ case CompareGreater:
+ os << ">";
+ break;
+ case CompareLessEqual:
+ os << "<=";
+ break;
+ case CompareGreaterEqual:
+ os << ">=";
+ break;
+ }
+ os << " ";
+ _rhs->dump(os);
+ os << ")";
+}
+
+ErrorOr<int64_t> BinOp::evalExpr(SymbolTableTy &symbolTable) const {
+ auto lhs = _lhs->evalExpr(symbolTable);
+ if (lhs.getError())
+ return lhs.getError();
+ auto rhs = _rhs->evalExpr(symbolTable);
+ if (rhs.getError())
+ return rhs.getError();
+
+ int64_t lhsRes = *lhs;
+ int64_t rhsRes = *rhs;
+
+ switch(_op) {
+ case And: return lhsRes & rhsRes;
+ case CompareDifferent: return lhsRes != rhsRes;
+ case CompareEqual: return lhsRes == rhsRes;
+ case CompareGreater: return lhsRes > rhsRes;
+ case CompareGreaterEqual: return lhsRes >= rhsRes;
+ case CompareLess: return lhsRes < rhsRes;
+ case CompareLessEqual: return lhsRes <= rhsRes;
+ case Div: return lhsRes / rhsRes;
+ case Mul: return lhsRes * rhsRes;
+ case Or: return lhsRes | rhsRes;
+ case Shl: return lhsRes << rhsRes;
+ case Shr: return lhsRes >> rhsRes;
+ case Sub: return lhsRes - rhsRes;
+ case Sum: return lhsRes + rhsRes;
+ }
+
+ llvm_unreachable("");
+}
+
+// TernaryConditional functions
+void TernaryConditional::dump(raw_ostream &os) const {
+ _conditional->dump(os);
+ os << " ? ";
+ _trueExpr->dump(os);
+ os << " : ";
+ _falseExpr->dump(os);
+}
+
+ErrorOr<int64_t>
+TernaryConditional::evalExpr(SymbolTableTy &symbolTable) const {
+ auto conditional = _conditional->evalExpr(symbolTable);
+ if (conditional.getError())
+ return conditional.getError();
+ if (*conditional)
+ return _trueExpr->evalExpr(symbolTable);
+ return _falseExpr->evalExpr(symbolTable);
+}
+
+// SymbolAssignment functions
+void SymbolAssignment::dump(raw_ostream &os) const {
+ int numParen = 0;
+
+ if (_assignmentVisibility != Default) {
+ switch (_assignmentVisibility) {
+ case Hidden:
+ os << "HIDDEN(";
+ break;
+ case Provide:
+ os << "PROVIDE(";
+ break;
+ case ProvideHidden:
+ os << "PROVIDE_HIDDEN(";
+ break;
+ default:
+ llvm_unreachable("Unknown visibility");
+ }
+ ++numParen;
+ }
+
+ os << _symbol << " ";
+ switch (_assignmentKind) {
+ case Simple:
+ os << "=";
+ break;
+ case Sum:
+ os << "+=";
+ break;
+ case Sub:
+ os << "-=";
+ break;
+ case Mul:
+ os << "*=";
+ break;
+ case Div:
+ os << "/=";
+ break;
+ case Shl:
+ os << "<<=";
+ break;
+ case Shr:
+ os << ">>=";
+ break;
+ case And:
+ os << "&=";
+ break;
+ case Or:
+ os << "|=";
+ break;
+ }
+
+ os << " ";
+ _expression->dump(os);
+ if (numParen)
+ os << ")";
+ os << ";";
+}
+
+static int dumpSortDirectives(raw_ostream &os, WildcardSortMode sortMode) {
+ switch (sortMode) {
+ case WildcardSortMode::NA:
+ return 0;
+ case WildcardSortMode::ByName:
+ os << "SORT_BY_NAME(";
+ return 1;
+ case WildcardSortMode::ByAlignment:
+ os << "SORT_BY_ALIGNMENT(";
+ return 1;
+ case WildcardSortMode::ByInitPriority:
+ os << "SORT_BY_INIT_PRIORITY(";
+ return 1;
+ case WildcardSortMode::ByNameAndAlignment:
+ os << "SORT_BY_NAME(SORT_BY_ALIGNMENT(";
+ return 2;
+ case WildcardSortMode::ByAlignmentAndName:
+ os << "SORT_BY_ALIGNMENT(SORT_BY_NAME(";
+ return 2;
+ case WildcardSortMode::None:
+ os << "SORT_NONE(";
+ return 1;
+ }
+ return 0;
+}
+
+// InputSectionName functions
+void InputSectionName::dump(raw_ostream &os) const {
+ os << _name;
+}
+
+// InputSectionSortedGroup functions
+static void dumpInputSections(raw_ostream &os,
+ llvm::ArrayRef<const InputSection *> secs) {
+ bool excludeFile = false;
+ bool first = true;
+
+ for (auto &secName : secs) {
+ if (!first)
+ os << " ";
+ first = false;
+ // Coalesce multiple input sections marked with EXCLUDE_FILE in the same
+ // EXCLUDE_FILE() group
+ if (auto inputSec = dyn_cast<InputSectionName>(secName)) {
+ if (!excludeFile && inputSec->hasExcludeFile()) {
+ excludeFile = true;
+ os << "EXCLUDE_FILE(";
+ } else if (excludeFile && !inputSec->hasExcludeFile()) {
+ excludeFile = false;
+ os << ") ";
+ }
+ }
+ secName->dump(os);
+ }
+
+ if (excludeFile)
+ os << ")";
+}
+
+void InputSectionSortedGroup::dump(raw_ostream &os) const {
+ int numParen = dumpSortDirectives(os, _sortMode);
+ dumpInputSections(os, _sections);
+ for (int i = 0; i < numParen; ++i)
+ os << ")";
+}
+
+// InputSectionsCmd functions
+void InputSectionsCmd::dump(raw_ostream &os) const {
+ if (_keep)
+ os << "KEEP(";
+
+ int numParen = dumpSortDirectives(os, _fileSortMode);
+ os << _memberName;
+ for (int i = 0; i < numParen; ++i)
+ os << ")";
+
+ if (_archiveName.size() > 0) {
+ os << ":";
+ numParen = dumpSortDirectives(os, _archiveSortMode);
+ os << _archiveName;
+ for (int i = 0; i < numParen; ++i)
+ os << ")";
+ }
+
+ if (_sections.size() > 0) {
+ os << "(";
+ dumpInputSections(os, _sections);
+ os << ")";
+ }
+
+ if (_keep)
+ os << ")";
+}
+
+// OutputSectionDescription functions
+void OutputSectionDescription::dump(raw_ostream &os) const {
+ if (_discard)
+ os << "/DISCARD/";
+ else
+ os << _sectionName;
+
+ if (_address) {
+ os << " ";
+ _address->dump(os);
+ }
+ os << " :\n";
+
+ if (_at) {
+ os << " AT(";
+ _at->dump(os);
+ os << ")\n";
+ }
+
+ if (_align) {
+ os << " ALIGN(";
+ _align->dump(os);
+ os << ")\n";
+ } else if (_alignWithInput) {
+ os << " ALIGN_WITH_INPUT\n";
+ }
+
+ if (_subAlign) {
+ os << " SUBALIGN(";
+ _subAlign->dump(os);
+ os << ")\n";
+ }
+
+ switch (_constraint) {
+ case C_None:
+ break;
+ case C_OnlyIfRO:
+ os << "ONLY_IF_RO";
+ break;
+ case C_OnlyIfRW:
+ os << "ONLY_IF_RW";
+ break;
+ }
+
+ os << " {\n";
+ for (auto &command : _outputSectionCommands) {
+ os << " ";
+ command->dump(os);
+ os << "\n";
+ }
+ os << " }";
+
+ if (_fillStream.size() > 0) {
+ os << " =";
+ dumpByteStream(os, _fillStream);
+ } else if (_fillExpr) {
+ os << " =";
+ _fillExpr->dump(os);
+ }
+}
+
+// Sections functions
+void Sections::dump(raw_ostream &os) const {
+ os << "SECTIONS\n{\n";
+ for (auto &command : _sectionsCommands) {
+ command->dump(os);
+ os << "\n";
+ }
+ os << "}\n";
+}
+
+// Memory functions
+void MemoryBlock::dump(raw_ostream &os) const {
+ os << _name;
+
+ if (!_attr.empty())
+ os << " (" << _attr << ")";
+
+ os << " : ";
+
+ os << "ORIGIN = ";
+ _origin->dump(os);
+ os << ", ";
+
+ os << "LENGTH = ";
+ _length->dump(os);
+}
+
+void Memory::dump(raw_ostream &os) const {
+ os << "MEMORY\n{\n";
+ for (auto &block : _blocks) {
+ block->dump(os);
+ os << "\n";
+ }
+ os << "}\n";
+}
+
+// Extern functions
+void Extern::dump(raw_ostream &os) const {
+ os << "EXTERN(";
+ for (unsigned i = 0, e = _symbols.size(); i != e; ++i) {
+ if (i)
+ os << " ";
+ os << _symbols[i];
+ }
+ os << ")\n";
+}
+
+
+// Parser functions
+std::error_code Parser::parse() {
+ // Get the first token.
+ _lex.lex(_tok);
+ // Parse top level commands.
+ while (true) {
+ switch (_tok._kind) {
+ case Token::eof:
+ return std::error_code();
+ case Token::semicolon:
+ consumeToken();
+ break;
+ case Token::kw_output: {
+ auto output = parseOutput();
+ if (!output)
+ return LinkerScriptReaderError::parse_error;
+ _script._commands.push_back(output);
+ break;
+ }
+ case Token::kw_output_format: {
+ auto outputFormat = parseOutputFormat();
+ if (!outputFormat)
+ return LinkerScriptReaderError::parse_error;
+ _script._commands.push_back(outputFormat);
+ break;
+ }
+ case Token::kw_output_arch: {
+ auto outputArch = parseOutputArch();
+ if (!outputArch)
+ return LinkerScriptReaderError::parse_error;
+ _script._commands.push_back(outputArch);
+ break;
+ }
+ case Token::kw_input: {
+ Input *input = parsePathList<Input>();
+ if (!input)
+ return LinkerScriptReaderError::parse_error;
+ _script._commands.push_back(input);
+ break;
+ }
+ case Token::kw_group: {
+ Group *group = parsePathList<Group>();
+ if (!group)
+ return LinkerScriptReaderError::parse_error;
+ _script._commands.push_back(group);
+ break;
+ }
+ case Token::kw_as_needed:
+ // Not allowed at top level.
+ error(_tok, "AS_NEEDED not allowed at top level.");
+ return LinkerScriptReaderError::parse_error;
+ case Token::kw_entry: {
+ Entry *entry = parseEntry();
+ if (!entry)
+ return LinkerScriptReaderError::parse_error;
+ _script._commands.push_back(entry);
+ break;
+ }
+ case Token::kw_search_dir: {
+ SearchDir *searchDir = parseSearchDir();
+ if (!searchDir)
+ return LinkerScriptReaderError::parse_error;
+ _script._commands.push_back(searchDir);
+ break;
+ }
+ case Token::kw_sections: {
+ Sections *sections = parseSections();
+ if (!sections)
+ return LinkerScriptReaderError::parse_error;
+ _script._commands.push_back(sections);
+ break;
+ }
+ case Token::identifier:
+ case Token::kw_hidden:
+ case Token::kw_provide:
+ case Token::kw_provide_hidden: {
+ const Command *cmd = parseSymbolAssignment();
+ if (!cmd)
+ return LinkerScriptReaderError::parse_error;
+ _script._commands.push_back(cmd);
+ break;
+ }
+ case Token::kw_memory: {
+ const Command *cmd = parseMemory();
+ if (!cmd)
+ return LinkerScriptReaderError::parse_error;
+ _script._commands.push_back(cmd);
+ break;
+ }
+ case Token::kw_extern: {
+ const Command *cmd = parseExtern();
+ if (!cmd)
+ return LinkerScriptReaderError::parse_error;
+ _script._commands.push_back(cmd);
+ break;
+ }
+ default:
+ // Unexpected.
+ error(_tok, "expected linker script command");
+ return LinkerScriptReaderError::parse_error;
+ }
+ }
+ return LinkerScriptReaderError::parse_error;
+}
+
+const Expression *Parser::parseFunctionCall() {
+ assert((_tok._kind == Token::identifier || _tok._kind == Token::kw_align) &&
+ "expected function call first tokens");
+ SmallVector<const Expression *, 8> params;
+ StringRef name = _tok._range;
+
+ consumeToken();
+ if (!expectAndConsume(Token::l_paren, "expected ("))
+ return nullptr;
+
+ if (_tok._kind == Token::r_paren) {
+ consumeToken();
+ return new (_alloc) FunctionCall(*this, _tok._range, params);
+ }
+
+ if (const Expression *firstParam = parseExpression())
+ params.push_back(firstParam);
+ else
+ return nullptr;
+
+ while (_tok._kind == Token::comma) {
+ consumeToken();
+ if (const Expression *param = parseExpression())
+ params.push_back(param);
+ else
+ return nullptr;
+ }
+
+ if (!expectAndConsume(Token::r_paren, "expected )"))
+ return nullptr;
+ return new (_alloc) FunctionCall(*this, name, params);
+}
+
+bool Parser::expectExprOperand() {
+ if (!(_tok._kind == Token::identifier || _tok._kind == Token::number ||
+ _tok._kind == Token::kw_align || _tok._kind == Token::l_paren ||
+ _tok._kind == Token::minus || _tok._kind == Token::tilde)) {
+ error(_tok, "expected symbol, number, minus, tilde or left parenthesis.");
+ return false;
+ }
+ return true;
+}
+
+const Expression *Parser::parseExprOperand() {
+ if (!expectExprOperand())
+ return nullptr;
+
+ switch (_tok._kind) {
+ case Token::identifier: {
+ if (peek()._kind== Token::l_paren)
+ return parseFunctionCall();
+ Symbol *sym = new (_alloc) Symbol(*this, _tok._range);
+ consumeToken();
+ return sym;
+ }
+ case Token::kw_align:
+ return parseFunctionCall();
+ case Token::minus:
+ consumeToken();
+ return new (_alloc) Unary(*this, Unary::Minus, parseExprOperand());
+ case Token::tilde:
+ consumeToken();
+ return new (_alloc) Unary(*this, Unary::Not, parseExprOperand());
+ case Token::number: {
+ auto val = parseNum(_tok._range);
+ if (val.getError()) {
+ error(_tok, "Unrecognized number constant");
+ return nullptr;
+ }
+ Constant *c = new (_alloc) Constant(*this, *val);
+ consumeToken();
+ return c;
+ }
+ case Token::l_paren: {
+ consumeToken();
+ const Expression *expr = parseExpression();
+ if (!expectAndConsume(Token::r_paren, "expected )"))
+ return nullptr;
+ return expr;
+ }
+ default:
+ llvm_unreachable("Unknown token");
+ }
+}
+
+static bool TokenToBinOp(const Token &tok, BinOp::Operation &op,
+ unsigned &precedence) {
+ switch (tok._kind) {
+ case Token::star:
+ op = BinOp::Mul;
+ precedence = 3;
+ return true;
+ case Token::slash:
+ op = BinOp::Div;
+ precedence = 3;
+ return true;
+ case Token::plus:
+ op = BinOp::Sum;
+ precedence = 4;
+ return true;
+ case Token::minus:
+ op = BinOp::Sub;
+ precedence = 4;
+ return true;
+ case Token::lessless:
+ op = BinOp::Shl;
+ precedence = 5;
+ return true;
+ case Token::greatergreater:
+ op = BinOp::Shr;
+ precedence = 5;
+ return true;
+ case Token::less:
+ op = BinOp::CompareLess;
+ precedence = 6;
+ return true;
+ case Token::greater:
+ op = BinOp::CompareGreater;
+ precedence = 6;
+ return true;
+ case Token::lessequal:
+ op = BinOp::CompareLessEqual;
+ precedence = 6;
+ return true;
+ case Token::greaterequal:
+ op = BinOp::CompareGreaterEqual;
+ precedence = 6;
+ return true;
+ case Token::equalequal:
+ op = BinOp::CompareEqual;
+ precedence = 7;
+ return true;
+ case Token::exclaimequal:
+ op = BinOp::CompareDifferent;
+ precedence = 7;
+ return true;
+ case Token::amp:
+ op = BinOp::And;
+ precedence = 8;
+ return true;
+ case Token::pipe:
+ op = BinOp::Or;
+ precedence = 10;
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+static bool isExpressionOperator(Token tok) {
+ switch (tok._kind) {
+ case Token::star:
+ case Token::slash:
+ case Token::plus:
+ case Token::minus:
+ case Token::lessless:
+ case Token::greatergreater:
+ case Token::less:
+ case Token::greater:
+ case Token::lessequal:
+ case Token::greaterequal:
+ case Token::equalequal:
+ case Token::exclaimequal:
+ case Token::amp:
+ case Token::pipe:
+ case Token::question:
+ return true;
+ default:
+ return false;
+ }
+}
+
+const Expression *Parser::parseExpression(unsigned precedence) {
+ assert(precedence <= 13 && "Invalid precedence value");
+ if (!expectExprOperand())
+ return nullptr;
+
+ const Expression *expr = parseExprOperand();
+ if (!expr)
+ return nullptr;
+
+ BinOp::Operation op;
+ unsigned binOpPrecedence = 0;
+ if (TokenToBinOp(_tok, op, binOpPrecedence)) {
+ if (precedence >= binOpPrecedence)
+ return parseOperatorOperandLoop(expr, precedence);
+ return expr;
+ }
+
+ // Non-binary operators
+ if (_tok._kind == Token::question && precedence >= 13)
+ return parseOperatorOperandLoop(expr, precedence);
+ return expr;
+}
+
+const Expression *Parser::parseOperatorOperandLoop(const Expression *lhs,
+ unsigned highestPrecedence) {
+ assert(highestPrecedence <= 13 && "Invalid precedence value");
+ unsigned precedence = 0;
+ const Expression *binOp = nullptr;
+
+ while (1) {
+ BinOp::Operation op;
+ if (!TokenToBinOp(_tok, op, precedence)) {
+ if (_tok._kind == Token::question && highestPrecedence >= 13)
+ return parseTernaryCondOp(lhs);
+ return binOp;
+ }
+
+ if (precedence > highestPrecedence)
+ return binOp;
+
+ consumeToken();
+ const Expression *rhs = parseExpression(precedence - 1);
+ if (!rhs)
+ return nullptr;
+ binOp = new (_alloc) BinOp(*this, lhs, op, rhs);
+ lhs = binOp;
+ }
+}
+
+const Expression *Parser::parseTernaryCondOp(const Expression *lhs) {
+ assert(_tok._kind == Token::question && "Expected question mark");
+
+ consumeToken();
+
+ // The ternary conditional operator has right-to-left associativity.
+ // To implement this, we allow our children to contain ternary conditional
+ // operators themselves (precedence 13).
+ const Expression *trueExpr = parseExpression(13);
+ if (!trueExpr)
+ return nullptr;
+
+ if (!expectAndConsume(Token::colon, "expected :"))
+ return nullptr;
+
+ const Expression *falseExpr = parseExpression(13);
+ if (!falseExpr)
+ return nullptr;
+
+ return new (_alloc) TernaryConditional(*this, lhs, trueExpr, falseExpr);
+}
+
+// Parse OUTPUT(ident)
+Output *Parser::parseOutput() {
+ assert(_tok._kind == Token::kw_output && "Expected OUTPUT");
+ consumeToken();
+ if (!expectAndConsume(Token::l_paren, "expected ("))
+ return nullptr;
+
+ if (_tok._kind != Token::identifier) {
+ error(_tok, "Expected identifier in OUTPUT.");
+ return nullptr;
+ }
+
+ auto ret = new (_alloc) Output(*this, _tok._range);
+ consumeToken();
+
+ if (!expectAndConsume(Token::r_paren, "expected )"))
+ return nullptr;
+
+ return ret;
+}
+
+// Parse OUTPUT_FORMAT(ident)
+OutputFormat *Parser::parseOutputFormat() {
+ assert(_tok._kind == Token::kw_output_format && "Expected OUTPUT_FORMAT!");
+ consumeToken();
+ if (!expectAndConsume(Token::l_paren, "expected ("))
+ return nullptr;
+
+ if (_tok._kind != Token::identifier) {
+ error(_tok, "Expected identifier in OUTPUT_FORMAT.");
+ return nullptr;
+ }
+
+ SmallVector<StringRef, 8> formats;
+ formats.push_back(_tok._range);
+
+ consumeToken();
+
+ do {
+ if (isNextToken(Token::comma))
+ consumeToken();
+ else
+ break;
+ if (_tok._kind != Token::identifier) {
+ error(_tok, "Expected identifier in OUTPUT_FORMAT.");
+ return nullptr;
+ }
+ formats.push_back(_tok._range);
+ consumeToken();
+ } while (isNextToken(Token::comma));
+
+ if (!expectAndConsume(Token::r_paren, "expected )"))
+ return nullptr;
+
+ return new (_alloc) OutputFormat(*this, formats);
+}
+
+// Parse OUTPUT_ARCH(ident)
+OutputArch *Parser::parseOutputArch() {
+ assert(_tok._kind == Token::kw_output_arch && "Expected OUTPUT_ARCH!");
+ consumeToken();
+ if (!expectAndConsume(Token::l_paren, "expected ("))
+ return nullptr;
+
+ if (_tok._kind != Token::identifier) {
+ error(_tok, "Expected identifier in OUTPUT_ARCH.");
+ return nullptr;
+ }
+
+ auto ret = new (_alloc) OutputArch(*this, _tok._range);
+ consumeToken();
+
+ if (!expectAndConsume(Token::r_paren, "expected )"))
+ return nullptr;
+
+ return ret;
+}
+
+// Parse file list for INPUT or GROUP
+template<class T> T *Parser::parsePathList() {
+ consumeToken();
+ if (!expectAndConsume(Token::l_paren, "expected ("))
+ return nullptr;
+
+ SmallVector<Path, 8> paths;
+ while (_tok._kind == Token::identifier || _tok._kind == Token::libname ||
+ _tok._kind == Token::kw_as_needed) {
+ switch (_tok._kind) {
+ case Token::identifier:
+ paths.push_back(Path(_tok._range));
+ consumeToken();
+ break;
+ case Token::libname:
+ paths.push_back(Path(_tok._range, false, true));
+ consumeToken();
+ break;
+ case Token::kw_as_needed:
+ if (!parseAsNeeded(paths))
+ return nullptr;
+ break;
+ default:
+ llvm_unreachable("Invalid token.");
+ }
+ }
+ if (!expectAndConsume(Token::r_paren, "expected )"))
+ return nullptr;
+ return new (_alloc) T(*this, paths);
+}
+
+// Parse AS_NEEDED(file ...)
+bool Parser::parseAsNeeded(SmallVectorImpl<Path> &paths) {
+ assert(_tok._kind == Token::kw_as_needed && "Expected AS_NEEDED!");
+ consumeToken();
+ if (!expectAndConsume(Token::l_paren, "expected ("))
+ return false;
+
+ while (_tok._kind == Token::identifier || _tok._kind == Token::libname) {
+ switch (_tok._kind) {
+ case Token::identifier:
+ paths.push_back(Path(_tok._range, true, false));
+ consumeToken();
+ break;
+ case Token::libname:
+ paths.push_back(Path(_tok._range, true, true));
+ consumeToken();
+ break;
+ default:
+ llvm_unreachable("Invalid token.");
+ }
+ }
+
+ if (!expectAndConsume(Token::r_paren, "expected )"))
+ return false;
+ return true;
+}
+
+// Parse ENTRY(ident)
+Entry *Parser::parseEntry() {
+ assert(_tok._kind == Token::kw_entry && "Expected ENTRY!");
+ consumeToken();
+ if (!expectAndConsume(Token::l_paren, "expected ("))
+ return nullptr;
+ if (_tok._kind != Token::identifier) {
+ error(_tok, "expected identifier in ENTRY");
+ return nullptr;
+ }
+ StringRef entryName(_tok._range);
+ consumeToken();
+ if (!expectAndConsume(Token::r_paren, "expected )"))
+ return nullptr;
+ return new (_alloc) Entry(*this, entryName);
+}
+
+// Parse SEARCH_DIR(ident)
+SearchDir *Parser::parseSearchDir() {
+ assert(_tok._kind == Token::kw_search_dir && "Expected SEARCH_DIR!");
+ consumeToken();
+ if (!expectAndConsume(Token::l_paren, "expected ("))
+ return nullptr;
+ if (_tok._kind != Token::identifier) {
+ error(_tok, "expected identifier in SEARCH_DIR");
+ return nullptr;
+ }
+ StringRef searchPath(_tok._range);
+ consumeToken();
+ if (!expectAndConsume(Token::r_paren, "expected )"))
+ return nullptr;
+ return new (_alloc) SearchDir(*this, searchPath);
+}
+
+const SymbolAssignment *Parser::parseSymbolAssignment() {
+ assert((_tok._kind == Token::identifier || _tok._kind == Token::kw_hidden ||
+ _tok._kind == Token::kw_provide ||
+ _tok._kind == Token::kw_provide_hidden) &&
+ "Expected identifier!");
+ SymbolAssignment::AssignmentVisibility visibility = SymbolAssignment::Default;
+ SymbolAssignment::AssignmentKind kind;
+ int numParen = 0;
+
+ switch (_tok._kind) {
+ case Token::kw_hidden:
+ visibility = SymbolAssignment::Hidden;
+ ++numParen;
+ consumeToken();
+ if (!expectAndConsume(Token::l_paren, "expected ("))
+ return nullptr;
+ break;
+ case Token::kw_provide:
+ visibility = SymbolAssignment::Provide;
+ ++numParen;
+ consumeToken();
+ if (!expectAndConsume(Token::l_paren, "expected ("))
+ return nullptr;
+ break;
+ case Token::kw_provide_hidden:
+ visibility = SymbolAssignment::ProvideHidden;
+ ++numParen;
+ consumeToken();
+ if (!expectAndConsume(Token::l_paren, "expected ("))
+ return nullptr;
+ break;
+ default:
+ break;
+ }
+
+ StringRef name = _tok._range;
+ consumeToken();
+
+ // Parse assignment operator (=, +=, -= etc.)
+ switch (_tok._kind) {
+ case Token::equal:
+ kind = SymbolAssignment::Simple;
+ break;
+ case Token::plusequal:
+ kind = SymbolAssignment::Sum;
+ break;
+ case Token::minusequal:
+ kind = SymbolAssignment::Sub;
+ break;
+ case Token::starequal:
+ kind = SymbolAssignment::Mul;
+ break;
+ case Token::slashequal:
+ kind = SymbolAssignment::Div;
+ break;
+ case Token::ampequal:
+ kind = SymbolAssignment::And;
+ break;
+ case Token::pipeequal:
+ kind = SymbolAssignment::Or;
+ break;
+ case Token::lesslessequal:
+ kind = SymbolAssignment::Shl;
+ break;
+ case Token::greatergreaterequal:
+ kind = SymbolAssignment::Shr;
+ break;
+ default:
+ error(_tok, "unexpected token");
+ return nullptr;
+ }
+
+ consumeToken();
+
+ const Expression *expr = nullptr;
+ switch (_tok._kind) {
+ case Token::number:
+ case Token::kw_align:
+ case Token::identifier:
+ case Token::l_paren:
+ expr = parseExpression();
+ if (!expr)
+ return nullptr;
+ break;
+ default:
+ error(_tok, "unexpected token while parsing assignment value.");
+ return nullptr;
+ }
+
+ for (int i = 0; i < numParen; ++i)
+ if (!expectAndConsume(Token::r_paren, "expected )"))
+ return nullptr;
+
+ return new (_alloc) SymbolAssignment(*this, name, expr, kind, visibility);
+}
+
+llvm::ErrorOr<InputSectionsCmd::VectorTy> Parser::parseExcludeFile() {
+ assert(_tok._kind == Token::kw_exclude_file && "Expected EXCLUDE_FILE!");
+ InputSectionsCmd::VectorTy res;
+ consumeToken();
+
+ if (!expectAndConsume(Token::l_paren, "expected ("))
+ return llvm::ErrorOr<InputSectionsCmd::VectorTy>(
+ std::make_error_code(std::errc::io_error));
+
+ while (_tok._kind == Token::identifier) {
+ res.push_back(new (_alloc) InputSectionName(*this, _tok._range, true));
+ consumeToken();
+ }
+
+ if (!expectAndConsume(Token::r_paren, "expected )"))
+ return llvm::ErrorOr<InputSectionsCmd::VectorTy>(
+ std::make_error_code(std::errc::io_error));
+ return llvm::ErrorOr<InputSectionsCmd::VectorTy>(std::move(res));
+}
+
+int Parser::parseSortDirectives(WildcardSortMode &sortMode) {
+ int numParsedDirectives = 0;
+ sortMode = WildcardSortMode::NA;
+
+ if (_tok._kind == Token::kw_sort_by_name) {
+ consumeToken();
+ if (!expectAndConsume(Token::l_paren, "expected ("))
+ return -1;
+ ++numParsedDirectives;
+ sortMode = WildcardSortMode::ByName;
+ }
+
+ if (_tok._kind == Token::kw_sort_by_init_priority) {
+ consumeToken();
+ if (!expectAndConsume(Token::l_paren, "expected ("))
+ return -1;
+ ++numParsedDirectives;
+ sortMode = WildcardSortMode::ByInitPriority;
+ }
+
+ if (_tok._kind == Token::kw_sort_by_alignment) {
+ consumeToken();
+ if (!expectAndConsume(Token::l_paren, "expected ("))
+ return -1;
+ ++numParsedDirectives;
+ if (sortMode != WildcardSortMode::ByName)
+ sortMode = WildcardSortMode::ByAlignment;
+ else
+ sortMode = WildcardSortMode::ByNameAndAlignment;
+ }
+
+ if (numParsedDirectives < 2 && _tok._kind == Token::kw_sort_by_name) {
+ consumeToken();
+ if (!expectAndConsume(Token::l_paren, "expected ("))
+ return -1;
+ ++numParsedDirectives;
+ if (sortMode == WildcardSortMode::ByAlignment)
+ sortMode = WildcardSortMode::ByAlignmentAndName;
+ }
+
+ if (numParsedDirectives < 2 && _tok._kind == Token::kw_sort_by_alignment) {
+ consumeToken();
+ if (!expectAndConsume(Token::l_paren, "expected ("))
+ return -1;
+ ++numParsedDirectives;
+ }
+
+ if (numParsedDirectives == 0 && _tok._kind == Token::kw_sort_none) {
+ consumeToken();
+ if (!expectAndConsume(Token::l_paren, "expected ("))
+ return -1;
+ ++numParsedDirectives;
+ sortMode = WildcardSortMode::None;
+ }
+
+ return numParsedDirectives;
+}
+
+const InputSection *Parser::parseSortedInputSections() {
+ assert((_tok._kind == Token::kw_sort_by_name ||
+ _tok._kind == Token::kw_sort_by_alignment ||
+ _tok._kind == Token::kw_sort_by_init_priority ||
+ _tok._kind == Token::kw_sort_none) &&
+ "Expected SORT directives!");
+
+ WildcardSortMode sortMode = WildcardSortMode::NA;
+ int numParen = parseSortDirectives(sortMode);
+ if (numParen == -1)
+ return nullptr;
+
+ SmallVector<const InputSection *, 8> inputSections;
+
+ while (_tok._kind == Token::identifier) {
+ inputSections.push_back(new (_alloc)
+ InputSectionName(*this, _tok._range, false));
+ consumeToken();
+ }
+
+ // Eat "numParen" rparens
+ for (int i = 0, e = numParen; i != e; ++i)
+ if (!expectAndConsume(Token::r_paren, "expected )"))
+ return nullptr;
+
+ return new (_alloc) InputSectionSortedGroup(*this, sortMode, inputSections);
+}
+
+const InputSectionsCmd *Parser::parseInputSectionsCmd() {
+ assert((_tok._kind == Token::identifier || _tok._kind == Token::colon ||
+ _tok._kind == Token::star || _tok._kind == Token::kw_keep ||
+ _tok._kind == Token::kw_sort_by_name ||
+ _tok._kind == Token::kw_sort_by_alignment ||
+ _tok._kind == Token::kw_sort_by_init_priority ||
+ _tok._kind == Token::kw_sort_none) &&
+ "Expected input section first tokens!");
+ int numParen = 1;
+ bool keep = false;
+ WildcardSortMode fileSortMode = WildcardSortMode::NA;
+ WildcardSortMode archiveSortMode = WildcardSortMode::NA;
+ StringRef memberName;
+ StringRef archiveName;
+
+ if (_tok._kind == Token::kw_keep) {
+ consumeToken();
+ if (!expectAndConsume(Token::l_paren, "expected ("))
+ return nullptr;
+ ++numParen;
+ keep = true;
+ }
+
+ // Input name
+ if (_tok._kind != Token::colon) {
+ int numParen = parseSortDirectives(fileSortMode);
+ if (numParen == -1)
+ return nullptr;
+ memberName = _tok._range;
+ consumeToken();
+ if (numParen) {
+ while (numParen--)
+ if (!expectAndConsume(Token::r_paren, "expected )"))
+ return nullptr;
+ }
+ }
+ if (_tok._kind == Token::colon) {
+ consumeToken();
+ if (_tok._kind == Token::identifier ||
+ _tok._kind == Token::kw_sort_by_name ||
+ _tok._kind == Token::kw_sort_by_alignment ||
+ _tok._kind == Token::kw_sort_by_init_priority ||
+ _tok._kind == Token::kw_sort_none) {
+ int numParen = parseSortDirectives(archiveSortMode);
+ if (numParen == -1)
+ return nullptr;
+ archiveName = _tok._range;
+ consumeToken();
+ for (int i = 0; i != numParen; ++i)
+ if (!expectAndConsume(Token::r_paren, "expected )"))
+ return nullptr;
+ }
+ }
+
+ SmallVector<const InputSection *, 8> inputSections;
+
+ if (_tok._kind != Token::l_paren)
+ return new (_alloc)
+ InputSectionsCmd(*this, memberName, archiveName, keep, fileSortMode,
+ archiveSortMode, inputSections);
+ consumeToken();
+
+ while (_tok._kind == Token::identifier ||
+ _tok._kind == Token::kw_exclude_file ||
+ _tok._kind == Token::kw_sort_by_name ||
+ _tok._kind == Token::kw_sort_by_alignment ||
+ _tok._kind == Token::kw_sort_by_init_priority ||
+ _tok._kind == Token::kw_sort_none) {
+ switch (_tok._kind) {
+ case Token::kw_exclude_file: {
+ auto vec = parseExcludeFile();
+ if (vec.getError())
+ return nullptr;
+ inputSections.insert(inputSections.end(), vec->begin(), vec->end());
+ break;
+ }
+ case Token::star:
+ case Token::identifier: {
+ inputSections.push_back(new (_alloc)
+ InputSectionName(*this, _tok._range, false));
+ consumeToken();
+ break;
+ }
+ case Token::kw_sort_by_name:
+ case Token::kw_sort_by_alignment:
+ case Token::kw_sort_by_init_priority:
+ case Token::kw_sort_none: {
+ const InputSection *group = parseSortedInputSections();
+ if (!group)
+ return nullptr;
+ inputSections.push_back(group);
+ break;
+ }
+ default:
+ llvm_unreachable("Unknown token");
+ }
+ }
+
+ for (int i = 0; i < numParen; ++i)
+ if (!expectAndConsume(Token::r_paren, "expected )"))
+ return nullptr;
+ return new (_alloc)
+ InputSectionsCmd(*this, memberName, archiveName, keep, fileSortMode,
+ archiveSortMode, inputSections);
+}
+
+const OutputSectionDescription *Parser::parseOutputSectionDescription() {
+ assert((_tok._kind == Token::kw_discard || _tok._kind == Token::identifier) &&
+ "Expected /DISCARD/ or identifier!");
+ StringRef sectionName;
+ const Expression *address = nullptr;
+ const Expression *align = nullptr;
+ const Expression *subAlign = nullptr;
+ const Expression *at = nullptr;
+ const Expression *fillExpr = nullptr;
+ StringRef fillStream;
+ bool alignWithInput = false;
+ bool discard = false;
+ OutputSectionDescription::Constraint constraint =
+ OutputSectionDescription::C_None;
+ SmallVector<const Command *, 8> outputSectionCommands;
+
+ if (_tok._kind == Token::kw_discard)
+ discard = true;
+ else
+ sectionName = _tok._range;
+ consumeToken();
+
+ if (_tok._kind == Token::number || _tok._kind == Token::identifier ||
+ _tok._kind == Token::kw_align || _tok._kind == Token::l_paren) {
+ address = parseExpression();
+ if (!address)
+ return nullptr;
+ }
+
+ if (!expectAndConsume(Token::colon, "expected :"))
+ return nullptr;
+
+ if (_tok._kind == Token::kw_at) {
+ consumeToken();
+ at = parseExpression();
+ if (!at)
+ return nullptr;
+ }
+
+ if (_tok._kind == Token::kw_align) {
+ consumeToken();
+ align = parseExpression();
+ if (!align)
+ return nullptr;
+ }
+
+ if (_tok._kind == Token::kw_align_with_input) {
+ consumeToken();
+ alignWithInput = true;
+ }
+
+ if (_tok._kind == Token::kw_subalign) {
+ consumeToken();
+ subAlign = parseExpression();
+ if (!subAlign)
+ return nullptr;
+ }
+
+ if (_tok._kind == Token::kw_only_if_ro) {
+ consumeToken();
+ constraint = OutputSectionDescription::C_OnlyIfRO;
+ } else if (_tok._kind == Token::kw_only_if_rw) {
+ consumeToken();
+ constraint = OutputSectionDescription::C_OnlyIfRW;
+ }
+
+ if (!expectAndConsume(Token::l_brace, "expected {"))
+ return nullptr;
+
+ // Parse zero or more output-section-commands
+ while (_tok._kind != Token::r_brace) {
+ switch (_tok._kind) {
+ case Token::semicolon:
+ consumeToken();
+ break;
+ case Token::identifier:
+ switch (peek()._kind) {
+ case Token::equal:
+ case Token::plusequal:
+ case Token::minusequal:
+ case Token::starequal:
+ case Token::slashequal:
+ case Token::ampequal:
+ case Token::pipeequal:
+ case Token::lesslessequal:
+ case Token::greatergreaterequal:
+ if (const Command *cmd = parseSymbolAssignment())
+ outputSectionCommands.push_back(cmd);
+ else
+ return nullptr;
+ break;
+ default:
+ if (const Command *cmd = parseInputSectionsCmd())
+ outputSectionCommands.push_back(cmd);
+ else
+ return nullptr;
+ break;
+ }
+ break;
+ case Token::kw_keep:
+ case Token::star:
+ case Token::colon:
+ case Token::kw_sort_by_name:
+ case Token::kw_sort_by_alignment:
+ case Token::kw_sort_by_init_priority:
+ case Token::kw_sort_none:
+ if (const Command *cmd = parseInputSectionsCmd())
+ outputSectionCommands.push_back(cmd);
+ else
+ return nullptr;
+ break;
+ case Token::kw_hidden:
+ case Token::kw_provide:
+ case Token::kw_provide_hidden:
+ if (const Command *cmd = parseSymbolAssignment())
+ outputSectionCommands.push_back(cmd);
+ else
+ return nullptr;
+ break;
+ default:
+ error(_tok, "expected symbol assignment or input file name.");
+ return nullptr;
+ }
+ }
+
+ if (!expectAndConsume(Token::r_brace, "expected }"))
+ return nullptr;
+
+ if (_tok._kind == Token::equal) {
+ consumeToken();
+ if (_tok._kind != Token::number || !_tok._range.startswith_lower("0x")) {
+ fillExpr = parseExpression();
+ if (!fillExpr)
+ return nullptr;
+ } else {
+ std::string strBuf;
+ if (isExpressionOperator(peek()) ||
+ !parseHexToByteStream(_tok._range.drop_front(2), strBuf)) {
+ fillExpr = parseExpression();
+ if(!fillExpr)
+ return nullptr;
+ } else {
+ char *rawBuf = (char *) _alloc.Allocate(strBuf.size(), 1);
+ memcpy(rawBuf, strBuf.c_str(), strBuf.size());
+ fillStream = StringRef(rawBuf, strBuf.size());
+ consumeToken();
+ }
+ }
+ }
+
+ return new (_alloc) OutputSectionDescription(
+ *this, sectionName, address, align, subAlign, at, fillExpr, fillStream,
+ alignWithInput, discard, constraint, outputSectionCommands);
+}
+
+const Overlay *Parser::parseOverlay() {
+ assert(_tok._kind == Token::kw_overlay && "Expected OVERLAY!");
+ error(_tok, "Overlay description is not yet supported.");
+ return nullptr;
+}
+
+Sections *Parser::parseSections() {
+ assert(_tok._kind == Token::kw_sections && "Expected SECTIONS!");
+ consumeToken();
+ if (!expectAndConsume(Token::l_brace, "expected {"))
+ return nullptr;
+ SmallVector<const Command *, 8> sectionsCommands;
+
+ bool unrecognizedToken = false;
+ // Parse zero or more sections-commands
+ while (!unrecognizedToken) {
+ switch (_tok._kind) {
+ case Token::semicolon:
+ consumeToken();
+ break;
+
+ case Token::identifier:
+ switch (peek()._kind) {
+ case Token::equal:
+ case Token::plusequal:
+ case Token::minusequal:
+ case Token::starequal:
+ case Token::slashequal:
+ case Token::ampequal:
+ case Token::pipeequal:
+ case Token::lesslessequal:
+ case Token::greatergreaterequal:
+ if (const Command *cmd = parseSymbolAssignment())
+ sectionsCommands.push_back(cmd);
+ else
+ return nullptr;
+ break;
+ default:
+ if (const Command *cmd = parseOutputSectionDescription())
+ sectionsCommands.push_back(cmd);
+ else
+ return nullptr;
+ break;
+ }
+ break;
+
+ case Token::kw_discard:
+ case Token::star:
+ if (const Command *cmd = parseOutputSectionDescription())
+ sectionsCommands.push_back(cmd);
+ else
+ return nullptr;
+ break;
+
+ case Token::kw_entry:
+ if (const Command *cmd = parseEntry())
+ sectionsCommands.push_back(cmd);
+ else
+ return nullptr;
+ break;
+
+ case Token::kw_hidden:
+ case Token::kw_provide:
+ case Token::kw_provide_hidden:
+ if (const Command *cmd = parseSymbolAssignment())
+ sectionsCommands.push_back(cmd);
+ else
+ return nullptr;
+ break;
+
+ case Token::kw_overlay:
+ if (const Command *cmd = parseOverlay())
+ sectionsCommands.push_back(cmd);
+ else
+ return nullptr;
+ break;
+
+ default:
+ unrecognizedToken = true;
+ break;
+ }
+ }
+
+ if (!expectAndConsume(
+ Token::r_brace,
+ "expected symbol assignment, entry, overlay or output section name."))
+ return nullptr;
+
+ return new (_alloc) Sections(*this, sectionsCommands);
+}
+
+Memory *Parser::parseMemory() {
+ assert(_tok._kind == Token::kw_memory && "Expected MEMORY!");
+ consumeToken();
+ if (!expectAndConsume(Token::l_brace, "expected {"))
+ return nullptr;
+ SmallVector<const MemoryBlock *, 8> blocks;
+
+ bool unrecognizedToken = false;
+ // Parse zero or more memory block descriptors.
+ while (!unrecognizedToken) {
+ if (_tok._kind == Token::identifier) {
+ StringRef name;
+ StringRef attrs;
+ const Expression *origin = nullptr;
+ const Expression *length = nullptr;
+
+ name = _tok._range;
+ consumeToken();
+
+ // Parse optional memory region attributes.
+ if (_tok._kind == Token::l_paren) {
+ consumeToken();
+
+ if (_tok._kind != Token::identifier) {
+ error(_tok, "Expected memory attribute string.");
+ return nullptr;
+ }
+ attrs = _tok._range;
+ consumeToken();
+
+ if (!expectAndConsume(Token::r_paren, "expected )"))
+ return nullptr;
+ }
+
+ if (!expectAndConsume(Token::colon, "expected :"))
+ return nullptr;
+
+ // Parse the ORIGIN (base address of memory block).
+ if (!expectAndConsume(Token::kw_origin, "expected ORIGIN"))
+ return nullptr;
+
+ if (!expectAndConsume(Token::equal, "expected ="))
+ return nullptr;
+
+ origin = parseExpression();
+ if (!origin)
+ return nullptr;
+
+ if (!expectAndConsume(Token::comma, "expected ,"))
+ return nullptr;
+
+ // Parse the LENGTH (length of memory block).
+ if (!expectAndConsume(Token::kw_length, "expected LENGTH"))
+ return nullptr;
+
+ if (!expectAndConsume(Token::equal, "expected ="))
+ return nullptr;
+
+ length = parseExpression();
+ if (!length)
+ return nullptr;
+
+ MemoryBlock *block =
+ new (_alloc) MemoryBlock(name, attrs, origin, length);
+ blocks.push_back(block);
+ } else {
+ unrecognizedToken = true;
+ }
+ }
+ if (!expectAndConsume(
+ Token::r_brace,
+ "expected memory block definition."))
+ return nullptr;
+
+ return new (_alloc) Memory(*this, blocks);
+}
+
+Extern *Parser::parseExtern() {
+ assert(_tok._kind == Token::kw_extern && "Expected EXTERN!");
+ consumeToken();
+ if (!expectAndConsume(Token::l_paren, "expected ("))
+ return nullptr;
+
+ // Parse one or more symbols.
+ SmallVector<StringRef, 8> symbols;
+ if (_tok._kind != Token::identifier) {
+ error(_tok, "expected one or more symbols in EXTERN.");
+ return nullptr;
+ }
+ symbols.push_back(_tok._range);
+ consumeToken();
+ while (_tok._kind == Token::identifier) {
+ symbols.push_back(_tok._range);
+ consumeToken();
+ }
+
+ if (!expectAndConsume(Token::r_paren, "expected symbol in EXTERN."))
+ return nullptr;
+
+ return new (_alloc) Extern(*this, symbols);
+}
+
+// Sema member functions
+Sema::Sema()
+ : _scripts(), _layoutCommands(), _memberToLayoutOrder(),
+ _memberNameWildcards(), _cacheSectionOrder(), _cacheExpressionOrder(),
+ _deliveredExprs(), _symbolTable() {}
+
+void Sema::perform() {
+ for (auto &parser : _scripts)
+ perform(parser->get());
+}
+
+bool Sema::less(const SectionKey &lhs, const SectionKey &rhs) const {
+ int a = getLayoutOrder(lhs, true);
+ int b = getLayoutOrder(rhs, true);
+
+ if (a != b) {
+ if (a < 0)
+ return false;
+ if (b < 0)
+ return true;
+ return a < b;
+ }
+
+ // If both sections are not mapped anywhere, they have the same order
+ if (a < 0)
+ return false;
+
+ // If both sections fall into the same layout order, we need to find their
+ // relative position as written in the (InputSectionsCmd).
+ return localCompare(a, lhs, rhs);
+}
+
+StringRef Sema::getOutputSection(const SectionKey &key) const {
+ int layoutOrder = getLayoutOrder(key, true);
+ if (layoutOrder < 0)
+ return StringRef();
+
+ for (int i = layoutOrder - 1; i >= 0; --i) {
+ if (!isa<OutputSectionDescription>(_layoutCommands[i]))
+ continue;
+
+ const OutputSectionDescription *out =
+ dyn_cast<OutputSectionDescription>(_layoutCommands[i]);
+ return out->name();
+ }
+
+ return StringRef();
+}
+
+std::vector<const SymbolAssignment *>
+Sema::getExprs(const SectionKey &key) {
+ int layoutOrder = getLayoutOrder(key, false);
+ auto ans = std::vector<const SymbolAssignment *>();
+
+ if (layoutOrder < 0 || _deliveredExprs.count(layoutOrder) > 0)
+ return ans;
+
+ for (int i = layoutOrder - 1; i >= 0; --i) {
+ if (isa<InputSection>(_layoutCommands[i]))
+ break;
+ if (auto assgn = dyn_cast<SymbolAssignment>(_layoutCommands[i]))
+ ans.push_back(assgn);
+ }
+
+ // Reverse this order so we evaluate the expressions in the original order
+ // of the linker script
+ std::reverse(ans.begin(), ans.end());
+
+ // Mark this layout number as delivered
+ _deliveredExprs.insert(layoutOrder);
+ return ans;
+}
+
+std::error_code Sema::evalExpr(const SymbolAssignment *assgn,
+ uint64_t &curPos) {
+ _symbolTable[StringRef(".")] = curPos;
+
+ auto ans = assgn->expr()->evalExpr(_symbolTable);
+ if (ans.getError())
+ return ans.getError();
+ uint64_t result = *ans;
+
+ if (assgn->symbol() == ".") {
+ curPos = result;
+ return std::error_code();
+ }
+
+ _symbolTable[assgn->symbol()] = result;
+ return std::error_code();
+}
+
+const llvm::StringSet<> &Sema::getScriptDefinedSymbols() const {
+ // Do we have cached results?
+ if (!_definedSymbols.empty())
+ return _definedSymbols;
+
+ // Populate our defined set and return it
+ for (auto cmd : _layoutCommands)
+ if (auto sa = dyn_cast<SymbolAssignment>(cmd)) {
+ StringRef symbol = sa->symbol();
+ if (!symbol.empty() && symbol != ".")
+ _definedSymbols.insert(symbol);
+ }
+
+ return _definedSymbols;
+}
+
+uint64_t Sema::getLinkerScriptExprValue(StringRef name) const {
+ auto it = _symbolTable.find(name);
+ assert (it != _symbolTable.end() && "Invalid symbol name!");
+ return it->second;
+}
+
+void Sema::dump() const {
+ raw_ostream &os = llvm::outs();
+ os << "Linker script semantics dump\n";
+ int num = 0;
+ for (auto &parser : _scripts) {
+ os << "Dumping script #" << ++num << ":\n";
+ parser->get()->dump(os);
+ os << "\n";
+ }
+ os << "Dumping rule ids:\n";
+ for (unsigned i = 0; i < _layoutCommands.size(); ++i) {
+ os << "LayoutOrder " << i << ":\n";
+ _layoutCommands[i]->dump(os);
+ os << "\n\n";
+ }
+}
+
+/// Given a string "pattern" with wildcard characters, return true if it
+/// matches "name". This function is useful when checking if a given name
+/// pattern written in the linker script, i.e. ".text*", should match
+/// ".text.anytext".
+static bool wildcardMatch(StringRef pattern, StringRef name) {
+ auto i = name.begin();
+
+ // Check if each char in pattern also appears in our input name, handling
+ // special wildcard characters.
+ for (auto j = pattern.begin(), e = pattern.end(); j != e; ++j) {
+ if (i == name.end())
+ return false;
+
+ switch (*j) {
+ case '*':
+ while (!wildcardMatch(pattern.drop_front(j - pattern.begin() + 1),
+ name.drop_front(i - name.begin() + 1))) {
+ if (i == name.end())
+ return false;
+ ++i;
+ }
+ break;
+ case '?':
+ // Matches any character
+ break;
+ case '[': {
+ // Matches a range of characters specified between brackets
+ size_t end = pattern.find(']', j - pattern.begin());
+ if (end == pattern.size())
+ return false;
+
+ StringRef chars = pattern.slice(j - pattern.begin(), end);
+ if (chars.find(i) == StringRef::npos)
+ return false;
+
+ j = pattern.begin() + end;
+ break;
+ }
+ case '\\':
+ ++j;
+ if (*j != *i)
+ return false;
+ break;
+ default:
+ // No wildcard character means we must match exactly the same char
+ if (*j != *i)
+ return false;
+ break;
+ }
+ ++i;
+ }
+
+ // If our pattern has't consumed the entire string, it is not a match
+ return i == name.end();
+}
+
+int Sema::matchSectionName(int id, const SectionKey &key) const {
+ const InputSectionsCmd *cmd = dyn_cast<InputSectionsCmd>(_layoutCommands[id]);
+
+ if (!cmd || !wildcardMatch(cmd->archiveName(), key.archivePath))
+ return -1;
+
+ while ((size_t)++id < _layoutCommands.size() &&
+ (isa<InputSection>(_layoutCommands[id]))) {
+ if (isa<InputSectionSortedGroup>(_layoutCommands[id]))
+ continue;
+
+ const InputSectionName *in =
+ dyn_cast<InputSectionName>(_layoutCommands[id]);
+ if (wildcardMatch(in->name(), key.sectionName))
+ return id;
+ }
+ return -1;
+}
+
+int Sema::getLayoutOrder(const SectionKey &key, bool coarse) const {
+ // First check if we already answered this layout question
+ if (coarse) {
+ auto entry = _cacheSectionOrder.find(key);
+ if (entry != _cacheSectionOrder.end())
+ return entry->second;
+ } else {
+ auto entry = _cacheExpressionOrder.find(key);
+ if (entry != _cacheExpressionOrder.end())
+ return entry->second;
+ }
+
+ // Try to match exact file name
+ auto range = _memberToLayoutOrder.equal_range(key.memberPath);
+ for (auto I = range.first, E = range.second; I != E; ++I) {
+ int order = I->second;
+ int exprOrder = -1;
+
+ if ((exprOrder = matchSectionName(order, key)) >= 0) {
+ if (coarse) {
+ _cacheSectionOrder.insert(std::make_pair(key, order));
+ return order;
+ }
+ _cacheExpressionOrder.insert(std::make_pair(key, exprOrder));
+ return exprOrder;
+ }
+ }
+
+ // If we still couldn't find a rule for this input section, try to match
+ // wildcards
+ for (auto I = _memberNameWildcards.begin(), E = _memberNameWildcards.end();
+ I != E; ++I) {
+ if (!wildcardMatch(I->first, key.memberPath))
+ continue;
+ int order = I->second;
+ int exprOrder = -1;
+
+ if ((exprOrder = matchSectionName(order, key)) >= 0) {
+ if (coarse) {
+ _cacheSectionOrder.insert(std::make_pair(key, order));
+ return order;
+ }
+ _cacheExpressionOrder.insert(std::make_pair(key, exprOrder));
+ return exprOrder;
+ }
+ }
+
+ _cacheSectionOrder.insert(std::make_pair(key, -1));
+ _cacheExpressionOrder.insert(std::make_pair(key, -1));
+ return -1;
+}
+
+static bool compareSortedNames(WildcardSortMode sortMode, StringRef lhs,
+ StringRef rhs) {
+ switch (sortMode) {
+ case WildcardSortMode::None:
+ case WildcardSortMode::NA:
+ return false;
+ case WildcardSortMode::ByAlignment:
+ case WildcardSortMode::ByInitPriority:
+ case WildcardSortMode::ByAlignmentAndName:
+ assert(false && "Unimplemented sort order");
+ break;
+ case WildcardSortMode::ByName:
+ return lhs.compare(rhs) < 0;
+ case WildcardSortMode::ByNameAndAlignment:
+ int compare = lhs.compare(rhs);
+ if (compare != 0)
+ return compare < 0;
+ return compareSortedNames(WildcardSortMode::ByAlignment, lhs, rhs);
+ }
+ return false;
+}
+
+static bool sortedGroupContains(const InputSectionSortedGroup *cmd,
+ const Sema::SectionKey &key) {
+ for (const InputSection *child : *cmd) {
+ if (auto i = dyn_cast<InputSectionName>(child)) {
+ if (wildcardMatch(i->name(), key.sectionName))
+ return true;
+ continue;
+ }
+
+ auto *sortedGroup = dyn_cast<InputSectionSortedGroup>(child);
+ assert(sortedGroup && "Expected InputSectionSortedGroup object");
+
+ if (sortedGroupContains(sortedGroup, key))
+ return true;
+ }
+
+ return false;
+}
+
+bool Sema::localCompare(int order, const SectionKey &lhs,
+ const SectionKey &rhs) const {
+ const InputSectionsCmd *cmd =
+ dyn_cast<InputSectionsCmd>(_layoutCommands[order]);
+
+ assert(cmd && "Invalid InputSectionsCmd index");
+
+ if (lhs.archivePath != rhs.archivePath)
+ return compareSortedNames(cmd->archiveSortMode(), lhs.archivePath,
+ rhs.archivePath);
+
+ if (lhs.memberPath != rhs.memberPath)
+ return compareSortedNames(cmd->fileSortMode(), lhs.memberPath,
+ rhs.memberPath);
+
+ // Both sections come from the same exact same file and rule. Start walking
+ // through input section names as written in the linker script and the
+ // first one to match will have higher priority.
+ for (const InputSection *inputSection : *cmd) {
+ if (auto i = dyn_cast<InputSectionName>(inputSection)) {
+ // If both match, return false (both have equal priority)
+ // If rhs match, return false (rhs has higher priority)
+ if (wildcardMatch(i->name(), rhs.sectionName))
+ return false;
+ // If lhs matches first, it has priority over rhs
+ if (wildcardMatch(i->name(), lhs.sectionName))
+ return true;
+ continue;
+ }
+
+ // Handle sorted subgroups specially
+ auto *sortedGroup = dyn_cast<InputSectionSortedGroup>(inputSection);
+ assert(sortedGroup && "Expected InputSectionSortedGroup object");
+
+ bool a = sortedGroupContains(sortedGroup, lhs);
+ bool b = sortedGroupContains(sortedGroup, rhs);
+ if (a && !b)
+ return false;
+ if (b && !a)
+ return true;
+ if (!a && !a)
+ continue;
+
+ return compareSortedNames(sortedGroup->sortMode(), lhs.sectionName,
+ rhs.sectionName);
+ }
+
+ llvm_unreachable("");
+ return false;
+}
+
+static bool hasWildcard(StringRef name) {
+ for (auto ch : name)
+ if (ch == '*' || ch == '?' || ch == '[' || ch == '\\')
+ return true;
+ return false;
+}
+
+void Sema::linearizeAST(const InputSection *inputSection) {
+ if (isa<InputSectionName>(inputSection)) {
+ _layoutCommands.push_back(inputSection);
+ return;
+ }
+
+ auto *sortedGroup = dyn_cast<InputSectionSortedGroup>(inputSection);
+ assert(sortedGroup && "Expected InputSectionSortedGroup object");
+
+ for (const InputSection *child : *sortedGroup) {
+ linearizeAST(child);
+ }
+}
+
+void Sema::linearizeAST(const InputSectionsCmd *inputSections) {
+ StringRef memberName = inputSections->memberName();
+ // Populate our maps for fast lookup of InputSectionsCmd
+ if (hasWildcard(memberName))
+ _memberNameWildcards.push_back(
+ std::make_pair(memberName, (int)_layoutCommands.size()));
+ else if (!memberName.empty())
+ _memberToLayoutOrder.insert(
+ std::make_pair(memberName.str(), (int)_layoutCommands.size()));
+
+ _layoutCommands.push_back(inputSections);
+ for (const InputSection *inputSection : *inputSections)
+ linearizeAST(inputSection);
+}
+
+void Sema::linearizeAST(const Sections *sections) {
+ for (const Command *sectionCommand : *sections) {
+ if (isa<SymbolAssignment>(sectionCommand)) {
+ _layoutCommands.push_back(sectionCommand);
+ continue;
+ }
+
+ if (!isa<OutputSectionDescription>(sectionCommand))
+ continue;
+
+ _layoutCommands.push_back(sectionCommand);
+ auto *outSection = dyn_cast<OutputSectionDescription>(sectionCommand);
+
+ for (const Command *outSecCommand : *outSection) {
+ if (isa<SymbolAssignment>(outSecCommand)) {
+ _layoutCommands.push_back(outSecCommand);
+ continue;
+ }
+
+ if (!isa<InputSectionsCmd>(outSecCommand))
+ continue;
+
+ linearizeAST(dyn_cast<InputSectionsCmd>(outSecCommand));
+ }
+ }
+}
+
+void Sema::perform(const LinkerScript *ls) {
+ for (const Command *c : ls->_commands) {
+ if (const Sections *sec = dyn_cast<Sections>(c))
+ linearizeAST(sec);
+ }
+}
+
+} // End namespace script
+} // end namespace lld
diff --git a/lib/ReaderWriter/MachO/ArchHandler.cpp b/lib/ReaderWriter/MachO/ArchHandler.cpp
new file mode 100644
index 000000000000..cb20907b3e30
--- /dev/null
+++ b/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/lib/ReaderWriter/MachO/ArchHandler.h b/lib/ReaderWriter/MachO/ArchHandler.h
new file mode 100644
index 000000000000..7f0961ebc807
--- /dev/null
+++ b/lib/ReaderWriter/MachO/ArchHandler.h
@@ -0,0 +1,300 @@
+//===- 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Atoms.h"
+#include "File.h"
+#include "MachONormalizedFile.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/Simple.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/ADT/Triple.h"
+
+#ifndef LLD_READER_WRITER_MACHO_ARCH_HANDLER_H
+#define LLD_READER_WRITER_MACHO_ARCH_HANDLER_H
+
+namespace lld {
+namespace mach_o {
+
+///
+/// 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 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 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;
+
+ 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 &);
+
+ /// 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<std::error_code (uint32_t sectionIndex, uint64_t addr,
+ const lld::Atom **, Reference::Addend *)>
+ FindAtomBySectionAndAddress;
+
+ /// Prototype for a helper function. Given a symbolIndex, finds the atom
+ /// representing that symbol.
+ typedef std::function<std::error_code (uint32_t symbolIndex,
+ const lld::Atom **)> FindAtomBySymbolIndex;
+
+ /// Analyzes a relocation from a .o file and returns the info
+ /// (kind, target, addend) needed to instantiate a Reference.
+ /// Two helper functions are passed as parameters to find the target atom
+ /// given a symbol index or address.
+ virtual std::error_code
+ 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 std::error_code
+ 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,
+ 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;
+
+ uint32_t stubHelperCommonSize;
+ 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/lib/ReaderWriter/MachO/ArchHandler_arm.cpp b/lib/ReaderWriter/MachO/ArchHandler_arm.cpp
new file mode 100644
index 000000000000..43f88a1d30d8
--- /dev/null
+++ b/lib/ReaderWriter/MachO/ArchHandler_arm.cpp
@@ -0,0 +1,1524 @@
+//===- 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();
+ virtual ~ArchHandler_arm();
+
+ 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 unwindRefToCIEKind() override {
+ return invalid;
+ }
+
+ Reference::KindValue unwindRefToFunctionKind() override {
+ return invalid;
+ }
+
+ Reference::KindValue unwindRefToEhFrameKind() override {
+ return invalid;
+ }
+
+ uint32_t dwarfCompactUnwindType() override {
+ // FIXME
+ return -1;
+ }
+
+ std::error_code getReferenceInfo(const normalized::Relocation &reloc,
+ const DefinedAtom *inAtom,
+ uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool swap,
+ FindAtomBySectionAndAddress atomFromAddress,
+ FindAtomBySymbolIndex atomFromSymbolIndex,
+ Reference::KindValue *kind,
+ const lld::Atom **target,
+ Reference::Addend *addend) override;
+ std::error_code
+ 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,
+ 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
+//===----------------------------------------------------------------------===//
+
+ArchHandler_arm::ArchHandler_arm() { }
+
+ArchHandler_arm::~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-Common size and code
+ 36,
+ { // 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;
+}
+
+std::error_code ArchHandler_arm::getReferenceInfo(
+ const Relocation &reloc, const DefinedAtom *inAtom, uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool isBig,
+ FindAtomBySectionAndAddress atomFromAddress,
+ FindAtomBySymbolIndex atomFromSymbolIndex, Reference::KindValue *kind,
+ const lld::Atom **target, Reference::Addend *addend) {
+ typedef std::error_code E;
+ const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+ uint64_t targetAddress;
+ uint32_t instruction = *(const ulittle32_t *)fixupContent;
+ 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 (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ // Instruction contains branch to addend.
+ displacement = getDisplacementFromThumbBranch(instruction, fixupAddress);
+ *addend = fixupAddress + 4 + displacement;
+ return std::error_code();
+ 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 (E ec = atomFromAddress(0, reloc.value, target, addend))
+ return ec;
+ // reloc.value is target atom's address. Instruction contains branch
+ // to atom+addend.
+ *addend += (targetAddress - reloc.value);
+ return std::error_code();
+ 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 (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ // Instruction contains branch to addend.
+ displacement = getDisplacementFromArmBranch(instruction);
+ *addend = fixupAddress + 8 + displacement;
+ return std::error_code();
+ 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 (E ec = atomFromAddress(0, reloc.value, target, addend))
+ return ec;
+ // reloc.value is target atom's address. Instruction contains branch
+ // to atom+addend.
+ *addend += (targetAddress - reloc.value);
+ return std::error_code();
+ case ARM_RELOC_VANILLA | rExtern | rLength4:
+ // ex: .long _foo (and _foo is undefined)
+ *kind = pointer32;
+ if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = instruction;
+ return std::error_code();
+ case ARM_RELOC_VANILLA | rLength4:
+ // ex: .long _foo (and _foo is defined)
+ *kind = pointer32;
+ if (E ec = atomFromAddress(reloc.symbol, instruction, target, addend))
+ return ec;
+ *addend = clearThumbBit((uint32_t) * addend, *target);
+ return std::error_code();
+ case ARM_RELOC_VANILLA | rScattered | rLength4:
+ // ex: .long _foo+a (and _foo is defined)
+ *kind = pointer32;
+ if (E ec = atomFromAddress(0, reloc.value, target, addend))
+ return ec;
+ *addend += (clearThumbBit(instruction, *target) - reloc.value);
+ return std::error_code();
+ default:
+ return make_dynamic_error_code(Twine("unsupported arm relocation type"));
+ }
+ return std::error_code();
+}
+
+std::error_code
+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 make_dynamic_error_code(Twine("unsupported arm relocation pair"));
+ }
+ const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+ std::error_code ec;
+ uint32_t instruction = *(const ulittle32_t *)fixupContent;
+ uint32_t value;
+ uint32_t fromAddress;
+ 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;
+ ec = atomFromAddr(0, toAddress, target, &offsetInTo);
+ if (ec)
+ return ec;
+ ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom);
+ if (ec)
+ return ec;
+ if (scatterable && (fromTarget != inAtom))
+ return make_dynamic_error_code(Twine("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;
+ ec = atomFromAddr(0, toAddress, target, &offsetInTo);
+ if (ec)
+ return ec;
+ ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom);
+ if (ec)
+ return ec;
+ if (fromTarget != inAtom)
+ return make_dynamic_error_code(
+ Twine("ARM_RELOC_HALF_SECTDIFF relocation "
+ "where subtrahend label is not in atom"));
+ other16 = (reloc2.offset & 0xFFFF);
+ if (thumbReloc) {
+ if (top) {
+ if (!isThumbMovt(instruction))
+ return make_dynamic_error_code(Twine("expected movt instruction"));
+ }
+ else {
+ if (!isThumbMovw(instruction))
+ return make_dynamic_error_code(Twine("expected movw instruction"));
+ }
+ instruction16 = getWordFromThumbMov(instruction);
+ }
+ else {
+ if (top) {
+ if (!isArmMovt(instruction))
+ return make_dynamic_error_code(Twine("expected movt instruction"));
+ }
+ else {
+ if (!isArmMovw(instruction))
+ return make_dynamic_error_code(Twine("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 std::error_code();
+ } else {
+ uint32_t sectIndex;
+ if (thumbReloc) {
+ if (top) {
+ if (!isThumbMovt(instruction))
+ return make_dynamic_error_code(Twine("expected movt instruction"));
+ }
+ else {
+ if (!isThumbMovw(instruction))
+ return make_dynamic_error_code(Twine("expected movw instruction"));
+ }
+ instruction16 = getWordFromThumbMov(instruction);
+ }
+ else {
+ if (top) {
+ if (!isArmMovt(instruction))
+ return make_dynamic_error_code(Twine("expected movt instruction"));
+ }
+ else {
+ if (!isArmMovw(instruction))
+ return make_dynamic_error_code(Twine("expected movw instruction"));
+ }
+ instruction16 = getWordFromArmMov(instruction);
+ }
+ other16 = (reloc2.offset & 0xFFFF);
+ if (top)
+ value = (instruction16 << 16) | other16;
+ else
+ value = (other16 << 16) | instruction16;
+ if (reloc1.isExtern) {
+ ec = atomFromSymbolIndex(reloc1.symbol, target);
+ if (ec)
+ return ec;
+ *addend = value;
+ } else {
+ if (reloc1.scattered) {
+ toAddress = reloc1.value;
+ sectIndex = 0;
+ } else {
+ toAddress = value;
+ sectIndex = reloc1.symbol;
+ }
+ ec = atomFromAddr(sectIndex, toAddress, target, &offsetInTo);
+ if (ec)
+ return ec;
+ *addend = value - toAddress;
+ }
+ }
+
+ return std::error_code();
+}
+
+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,
+ uint8_t *atomContentBuffer) {
+ // Copy raw bytes.
+ memcpy(atomContentBuffer, atom.rawContent().data(), atom.size());
+ // 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(0, modeThumbCode, &atom, 0, Reference::KindArch::ARM);
+ }
+}
+
+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());
+ }
+
+ StringRef name() const override {
+ return _name;
+ }
+
+ ContentType contentType() const override {
+ return DefinedAtom::typeCode;
+ }
+
+ Alignment alignment() const override {
+ return Alignment(2);
+ }
+
+ 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());
+ }
+
+ StringRef name() const override {
+ return _name;
+ }
+
+ ContentType contentType() const override {
+ return DefinedAtom::typeCode;
+ }
+
+ Alignment alignment() const override {
+ return Alignment(2);
+ }
+
+ 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/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp b/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp
new file mode 100644
index 000000000000..fd9984b89ce6
--- /dev/null
+++ b/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp
@@ -0,0 +1,822 @@
+//===- 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();
+ virtual ~ArchHandler_arm64();
+
+ 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 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 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 unwindRefToCIEKind() override {
+ return negDelta32;
+ }
+
+ Reference::KindValue unwindRefToFunctionKind() override {
+ return unwindFDEToFunction;
+ }
+
+ Reference::KindValue unwindRefToEhFrameKind() override {
+ return unwindInfoToEhFrame;
+ }
+
+ uint32_t dwarfCompactUnwindType() override {
+ return 0x03000000;
+ }
+
+ std::error_code getReferenceInfo(const normalized::Relocation &reloc,
+ const DefinedAtom *inAtom,
+ uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool isBig,
+ FindAtomBySectionAndAddress atomFromAddress,
+ FindAtomBySymbolIndex atomFromSymbolIndex,
+ Reference::KindValue *kind,
+ const lld::Atom **target,
+ Reference::Addend *addend) override;
+ std::error_code
+ 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,
+ 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).
+ 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);
+};
+
+ArchHandler_arm64::ArchHandler_arm64() {}
+
+ArchHandler_arm64::~ArchHandler_arm64() {}
+
+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(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^2
+ 2,
+
+ // 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-Common size and code
+ 24,
+ { 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;
+}
+
+std::error_code 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 std::error_code();
+ case ARM64_RELOC_PAGE21 | rPcRel | rExtern | rLength4:
+ // ex: adrp x1, _foo@PAGE
+ *kind = page21;
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = 0;
+ return std::error_code();
+ case ARM64_RELOC_PAGEOFF12 | rExtern | rLength4:
+ // ex: ldr x0, [x1, _foo@PAGEOFF]
+ *kind = offset12KindFromInstruction(*(const little32_t *)fixupContent);
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = 0;
+ return std::error_code();
+ case ARM64_RELOC_GOT_LOAD_PAGE21 | rPcRel | rExtern | rLength4:
+ // ex: adrp x1, _foo@GOTPAGE
+ *kind = gotPage21;
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = 0;
+ return std::error_code();
+ case ARM64_RELOC_GOT_LOAD_PAGEOFF12 | rExtern | rLength4:
+ // ex: ldr x0, [x1, _foo@GOTPAGEOFF]
+ *kind = gotOffset12;
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = 0;
+ return std::error_code();
+ case ARM64_RELOC_TLVP_LOAD_PAGE21 | rPcRel | rExtern | rLength4:
+ // ex: adrp x1, _foo@TLVPAGE
+ *kind = tlvPage21;
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = 0;
+ return std::error_code();
+ case ARM64_RELOC_TLVP_LOAD_PAGEOFF12 | rExtern | rLength4:
+ // ex: ldr x0, [x1, _foo@TLVPAGEOFF]
+ *kind = tlvOffset12;
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = 0;
+ return std::error_code();
+ case ARM64_RELOC_UNSIGNED | rExtern | rLength8:
+ // ex: .quad _foo + N
+ *kind = pointer64;
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = *(const little64_t *)fixupContent;
+ return std::error_code();
+ 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 std::error_code();
+ case ARM64_RELOC_POINTER_TO_GOT | rPcRel | rExtern | rLength4:
+ // ex: .long _foo@GOT - .
+ *kind = delta32ToGOT;
+ if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = 0;
+ return std::error_code();
+ default:
+ return make_dynamic_error_code(Twine("unsupported arm64 relocation type"));
+ }
+}
+
+std::error_code ArchHandler_arm64::getPairReferenceInfo(
+ const normalized::Relocation &reloc1, const normalized::Relocation &reloc2,
+ const DefinedAtom *inAtom, uint32_t offsetInAtom, uint64_t fixupAddress,
+ bool swap, bool scatterable, FindAtomBySectionAndAddress atomFromAddress,
+ FindAtomBySymbolIndex atomFromSymbolIndex, Reference::KindValue *kind,
+ const lld::Atom **target, Reference::Addend *addend) {
+ const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+ const uint32_t *cont32 = reinterpret_cast<const uint32_t *>(fixupContent);
+ switch (relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
+ case ((ARM64_RELOC_ADDEND | rLength4) << 16 |
+ ARM64_RELOC_BRANCH26 | rPcRel | rExtern | rLength4):
+ // ex: bl _foo+8
+ *kind = branch26;
+ if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
+ return ec;
+ *addend = reloc1.symbol;
+ return std::error_code();
+ 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 std::error_code();
+ case ((ARM64_RELOC_ADDEND | rLength4) << 16 |
+ ARM64_RELOC_PAGEOFF12 | rExtern | rLength4):
+ // ex: ldr w0, [x1, _foo@PAGEOFF]
+ *kind = offset12KindFromInstruction(*cont32);
+ if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
+ return ec;
+ *addend = reloc1.symbol;
+ return std::error_code();
+ case ((ARM64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 |
+ ARM64_RELOC_UNSIGNED | rExtern | rLength8):
+ // ex: .quad _foo - .
+ *kind = delta64;
+ if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
+ return ec;
+ *addend = (int64_t)*(const little64_t *)fixupContent + offsetInAtom;
+ return std::error_code();
+ 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 std::error_code();
+ default:
+ return make_dynamic_error_code(Twine("unsupported arm64 relocation pair"));
+ }
+}
+
+void ArchHandler_arm64::generateAtomContent(
+ const DefinedAtom &atom, bool relocatable, FindAddressForAtom findAddress,
+ FindAddressForAtom findSectionAddress, uint64_t imageBaseAddress,
+ uint8_t *atomContentBuffer) {
+ // Copy raw bytes.
+ memcpy(atomContentBuffer, atom.rawContent().data(), atom.size());
+ // Apply fix-ups.
+ 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:
+ *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 delta32:
+ *loc32 = ref.addend() + inAtomAddress - fixupAddress;
+ return;
+ case negDelta32:
+ *loc32 = fixupAddress - inAtomAddress + ref.addend();
+ return;
+ case pointer64ToGOT:
+ *loc64 = 0;
+ return;
+ case delta32ToGOT:
+ *loc32 = -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 unwindFDEToFunction:
+ // Do nothing for now
+ 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 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/lib/ReaderWriter/MachO/ArchHandler_x86.cpp b/lib/ReaderWriter/MachO/ArchHandler_x86.cpp
new file mode 100644
index 000000000000..19c8780e707a
--- /dev/null
+++ b/lib/ReaderWriter/MachO/ArchHandler_x86.cpp
@@ -0,0 +1,642 @@
+//===- 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();
+ virtual ~ArchHandler_x86();
+
+ 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 unwindRefToCIEKind() override {
+ return negDelta32;
+ }
+
+ Reference::KindValue unwindRefToFunctionKind() override{
+ return delta32;
+ }
+
+ Reference::KindValue unwindRefToEhFrameKind() override {
+ return invalid;
+ }
+
+
+ uint32_t dwarfCompactUnwindType() override {
+ return 0x04000000U;
+ }
+
+ std::error_code getReferenceInfo(const normalized::Relocation &reloc,
+ const DefinedAtom *inAtom,
+ uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool swap,
+ FindAtomBySectionAndAddress atomFromAddress,
+ FindAtomBySymbolIndex atomFromSymbolIndex,
+ Reference::KindValue *kind,
+ const lld::Atom **target,
+ Reference::Addend *addend) override;
+ std::error_code
+ 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,
+ 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 {
+ switch (refKind) {
+ case modeCode:
+ 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 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
+//===----------------------------------------------------------------------===//
+
+ArchHandler_x86::ArchHandler_x86() {}
+
+ArchHandler_x86::~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-Common size and code
+ 12,
+ { 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);
+}
+
+std::error_code
+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) {
+ typedef std::error_code E;
+ 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 (E 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 (E ec = atomFromAddress(0, reloc.value, target, addend))
+ return ec;
+ *addend = targetAddress - reloc.value;
+ break;
+ case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength2:
+ // ex: callw _foo (and _foo undefined)
+ *kind = branch16;
+ if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ 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 (E 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 (E 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 (E ec = atomFromAddress(0, reloc.value, target, addend))
+ return ec;
+ *addend = *(const ulittle32_t *)fixupContent - reloc.value;
+ break;
+ default:
+ return make_dynamic_error_code(Twine("unsupported i386 relocation type"));
+ }
+ return std::error_code();
+}
+
+std::error_code
+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];
+ std::error_code ec;
+ 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;
+ ec = atomFromAddr(0, toAddress, target, &offsetInTo);
+ if (ec)
+ return ec;
+ ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom);
+ if (ec)
+ return ec;
+ if (fromTarget != inAtom) {
+ if (*target != inAtom)
+ return make_dynamic_error_code(Twine("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 std::error_code();
+ break;
+ default:
+ return make_dynamic_error_code(Twine("unsupported i386 relocation type"));
+ }
+}
+
+void ArchHandler_x86::generateAtomContent(const DefinedAtom &atom,
+ bool relocatable,
+ FindAddressForAtom findAddress,
+ FindAddressForAtom findSectionAddress,
+ uint64_t imageBaseAddress,
+ uint8_t *atomContentBuffer) {
+ // Copy raw bytes.
+ memcpy(atomContentBuffer, atom.rawContent().data(), atom.size());
+ // 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/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp b/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
new file mode 100644
index 000000000000..81fe1af42d7e
--- /dev/null
+++ b/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
@@ -0,0 +1,723 @@
+//===- 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();
+ virtual ~ArchHandler_x86_64();
+
+ 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;
+ }
+ }
+
+ /// 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");
+ 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 unwindRefToCIEKind() override {
+ return negDelta32;
+ }
+
+ Reference::KindValue unwindRefToFunctionKind() override{
+ return unwindFDEToFunction;
+ }
+
+ Reference::KindValue unwindRefToEhFrameKind() override {
+ return unwindInfoToEhFrame;
+ }
+
+ 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;
+
+ std::error_code getReferenceInfo(const normalized::Relocation &reloc,
+ const DefinedAtom *inAtom,
+ uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool swap,
+ FindAtomBySectionAndAddress atomFromAddress,
+ FindAtomBySymbolIndex atomFromSymbolIndex,
+ Reference::KindValue *kind,
+ const lld::Atom **target,
+ Reference::Addend *addend) override;
+ std::error_code
+ 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,
+ 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
+ ripRel32GotLoad, /// ex: movq _foo@GOTPCREL(%rip), %rax
+ ripRel32Got, /// ex: pushq _foo@GOTPCREL(%rip)
+ pointer64, /// ex: .quad _foo
+ pointer64Anon, /// ex: .quad L1
+ delta64, /// ex: .quad _foo - .
+ delta32, /// ex: .long _foo - .
+ delta64Anon, /// ex: .quad L1 - .
+ delta32Anon, /// ex: .long L1 - .
+ 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.
+ };
+
+ Reference::KindValue kindFromReloc(const normalized::Relocation &reloc);
+ Reference::KindValue kindFromRelocPair(const normalized::Relocation &reloc1,
+ const normalized::Relocation &reloc2);
+
+ void applyFixupFinal(const Reference &ref, uint8_t *location,
+ uint64_t fixupAddress, uint64_t targetAddress,
+ 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);
+};
+
+
+ArchHandler_x86_64::ArchHandler_x86_64() { }
+
+ArchHandler_x86_64::~ArchHandler_x86_64() { }
+
+const Registry::KindStrings ArchHandler_x86_64::_sKindStrings[] = {
+ LLD_KIND_STRING_ENTRY(invalid), LLD_KIND_STRING_ENTRY(branch32),
+ LLD_KIND_STRING_ENTRY(ripRel32), LLD_KIND_STRING_ENTRY(ripRel32Minus1),
+ LLD_KIND_STRING_ENTRY(ripRel32Minus2), LLD_KIND_STRING_ENTRY(ripRel32Minus4),
+ LLD_KIND_STRING_ENTRY(ripRel32Anon), LLD_KIND_STRING_ENTRY(ripRel32GotLoad),
+ LLD_KIND_STRING_ENTRY(ripRel32GotLoadNowLea),
+ LLD_KIND_STRING_ENTRY(ripRel32Got), 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(negDelta32),
+ LLD_KIND_STRING_ENTRY(imageOffset), LLD_KIND_STRING_ENTRY(imageOffsetGot),
+ LLD_KIND_STRING_ENTRY(unwindFDEToFunction),
+ LLD_KIND_STRING_ENTRY(unwindInfoToEhFrame),
+ 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-Common size and code
+ 16,
+ { 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_2 | rPcRel | rExtern | rLength4:
+ return ripRel32Minus2;
+ case X86_64_RELOC_SIGNED_4 | rPcRel | rExtern | rLength4:
+ return ripRel32Minus4;
+ 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_UNSIGNED | rExtern | rLength8:
+ return pointer64;
+ case X86_64_RELOC_UNSIGNED | rLength8:
+ return pointer64Anon;
+ default:
+ return invalid;
+ }
+}
+
+std::error_code
+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) {
+ typedef std::error_code E;
+ *kind = kindFromReloc(reloc);
+ if (*kind == invalid)
+ return make_dynamic_error_code(Twine("unknown type"));
+ const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+ uint64_t targetAddress;
+ switch (*kind) {
+ case branch32:
+ case ripRel32:
+ if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = *(const little32_t *)fixupContent;
+ return std::error_code();
+ case ripRel32Minus1:
+ if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = (int32_t)*(const little32_t *)fixupContent + 1;
+ return std::error_code();
+ case ripRel32Minus2:
+ if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = (int32_t)*(const little32_t *)fixupContent + 2;
+ return std::error_code();
+ case ripRel32Minus4:
+ if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = (int32_t)*(const little32_t *)fixupContent + 4;
+ return std::error_code();
+ case ripRel32Anon:
+ targetAddress = fixupAddress + 4 + *(const little32_t *)fixupContent;
+ return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+ case ripRel32GotLoad:
+ case ripRel32Got:
+ if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = *(const little32_t *)fixupContent;
+ return std::error_code();
+ case pointer64:
+ if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = *(const little64_t *)fixupContent;
+ return std::error_code();
+ case pointer64Anon:
+ targetAddress = *(const little64_t *)fixupContent;
+ return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+ default:
+ llvm_unreachable("bad reloc kind");
+ }
+}
+
+Reference::KindValue
+ArchHandler_x86_64::kindFromRelocPair(const normalized::Relocation &reloc1,
+ const normalized::Relocation &reloc2) {
+ switch(relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
+ case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 |
+ X86_64_RELOC_UNSIGNED | rExtern | rLength8):
+ return delta64;
+ case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 |
+ X86_64_RELOC_UNSIGNED | rExtern | rLength4):
+ return delta32;
+ case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 |
+ X86_64_RELOC_UNSIGNED | rLength8):
+ return delta64Anon;
+ case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 |
+ X86_64_RELOC_UNSIGNED | rLength4):
+ return delta32Anon;
+ default:
+ llvm_unreachable("bad reloc pairs");
+ }
+}
+
+std::error_code
+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) {
+ *kind = kindFromRelocPair(reloc1, reloc2);
+ if (*kind == invalid)
+ return make_dynamic_error_code(Twine("unknown pair"));
+ const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+ typedef std::error_code E;
+ uint64_t targetAddress;
+ const lld::Atom *fromTarget;
+ if (E ec = atomFromSymbolIndex(reloc1.symbol, &fromTarget))
+ return ec;
+ if (fromTarget != inAtom)
+ return make_dynamic_error_code(Twine("pointer diff not in base atom"));
+ switch (*kind) {
+ case delta64:
+ if (E ec = atomFromSymbolIndex(reloc2.symbol, target))
+ return ec;
+ *addend = (int64_t)*(const little64_t *)fixupContent + offsetInAtom;
+ return std::error_code();
+ case delta32:
+ if (E ec = atomFromSymbolIndex(reloc2.symbol, target))
+ return ec;
+ *addend = (int32_t)*(const little32_t *)fixupContent + offsetInAtom;
+ return std::error_code();
+ case delta64Anon:
+ targetAddress = offsetInAtom + (int64_t)*(const little64_t *)fixupContent;
+ return atomFromAddress(reloc2.symbol, targetAddress, target, addend);
+ case delta32Anon:
+ targetAddress = offsetInAtom + (int32_t)*(const little32_t *)fixupContent;
+ return atomFromAddress(reloc2.symbol, targetAddress, target, addend);
+ default:
+ llvm_unreachable("bad reloc pair kind");
+ }
+}
+
+void ArchHandler_x86_64::generateAtomContent(
+ const DefinedAtom &atom, bool relocatable, FindAddressForAtom findAddress,
+ FindAddressForAtom findSectionAddress, uint64_t imageBaseAddress,
+ uint8_t *atomContentBuffer) {
+ // Copy raw bytes.
+ memcpy(atomContentBuffer, atom.rawContent().data(), atom.size());
+ // 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:
+ *loc32 = targetAddress - (fixupAddress + 4) + ref.addend();
+ return;
+ case pointer64:
+ case pointer64Anon:
+ *loc64 = targetAddress + ref.addend();
+ return;
+ case ripRel32Minus1:
+ *loc32 = targetAddress - (fixupAddress + 5) + ref.addend();
+ return;
+ case ripRel32Minus2:
+ *loc32 = targetAddress - (fixupAddress + 6) + ref.addend();
+ return;
+ case ripRel32Minus4:
+ *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 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:
+ *loc32 = ref.addend();
+ return;
+ case ripRel32Anon:
+ *loc32 = (targetAddress - (fixupAddress + 4)) + ref.addend();
+ return;
+ case pointer64:
+ *loc64 = ref.addend();
+ return;
+ case pointer64Anon:
+ *loc64 = targetAddress + ref.addend();
+ return;
+ case ripRel32Minus1:
+ *loc32 = ref.addend() - 1;
+ return;
+ case ripRel32Minus2:
+ *loc32 = ref.addend() - 2;
+ return;
+ case ripRel32Minus4:
+ *loc32 = ref.addend() - 4;
+ return;
+ case delta32:
+ *loc32 = ref.addend() + inAtomAddress - fixupAddress;
+ return;
+ case delta32Anon:
+ *loc32 = (targetAddress - fixupAddress) + ref.addend();
+ return;
+ case delta64:
+ *loc64 = ref.addend() + inAtomAddress - fixupAddress;
+ return;
+ case delta64Anon:
+ *loc64 = (targetAddress - fixupAddress) + ref.addend();
+ return;
+ case negDelta32:
+ *loc32 = fixupAddress - targetAddress + ref.addend();
+ 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 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 ripRel32Minus2:
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_SIGNED_2 | rPcRel | rExtern | rLength4 );
+ return;
+ case ripRel32Minus4:
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ X86_64_RELOC_SIGNED_4 | rPcRel | rExtern | 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:
+ case negDelta32:
+ 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/lib/ReaderWriter/MachO/Atoms.h b/lib/ReaderWriter/MachO/Atoms.h
new file mode 100644
index 000000000000..8d60c1a163a6
--- /dev/null
+++ b/lib/ReaderWriter/MachO/Atoms.h
@@ -0,0 +1,181 @@
+//===- lib/ReaderWriter/MachO/Atoms.h -------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_MACHO_ATOMS_H
+#define LLD_READER_WRITER_MACHO_ATOMS_H
+
+#include "lld/Core/Simple.h"
+
+namespace lld {
+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,
+ uint64_t size, bool noDeadStrip, Alignment align)
+ : SimpleDefinedAtom(f), _name(name),
+ _content(ArrayRef<uint8_t>(nullptr, size)), _align(align),
+ _contentType(DefinedAtom::typeZeroFill),
+ _scope(scope), _merge(mergeNo), _thumb(false),
+ _noDeadStrip(noDeadStrip) {}
+
+ 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; }
+
+ void addReference(uint32_t offsetInAtom, uint16_t relocType,
+ const Atom *target, Reference::Addend addend,
+ Reference::KindArch arch = Reference::KindArch::x86_64,
+ Reference::KindNamespace ns
+ = Reference::KindNamespace::mach_o) {
+ SimpleDefinedAtom::addReference(ns, arch, relocType, offsetInAtom, target,
+ addend);
+ }
+
+private:
+ const StringRef _name;
+ const ArrayRef<uint8_t> _content;
+ 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) {}
+
+ 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) {}
+
+ 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 StringRef _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) {}
+ virtual ~MachOSharedLibraryAtom() {}
+
+ virtual StringRef loadName() const override {
+ return _dylibInstallName;
+ }
+
+ virtual bool canBeNullAtRuntime() const override {
+ // FIXME: this may actually be changeable. For now, all symbols are strongly
+ // defined though.
+ return false;
+ }
+
+ virtual const File& file() const override {
+ return _file;
+ }
+
+ virtual StringRef name() const override {
+ return _name;
+ }
+
+ virtual Type type() const override {
+ // Unused in MachO (I think).
+ return Type::Unknown;
+ }
+
+ virtual uint64_t size() const override {
+ // Unused in MachO (I think)
+ return 0;
+ }
+
+private:
+ const File &_file;
+ StringRef _name;
+ StringRef _dylibInstallName;
+};
+
+
+} // mach_o
+} // lld
+
+#endif
diff --git a/lib/ReaderWriter/MachO/CMakeLists.txt b/lib/ReaderWriter/MachO/CMakeLists.txt
new file mode 100644
index 000000000000..e396537c63c8
--- /dev/null
+++ b/lib/ReaderWriter/MachO/CMakeLists.txt
@@ -0,0 +1,26 @@
+add_llvm_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
+ ShimPass.cpp
+ StubsPass.cpp
+ WriterMachO.cpp
+ LINK_LIBS
+ lldCore
+ lldYAML
+ LLVMObject
+ LLVMSupport
+ )
+
+include_directories(.)
diff --git a/lib/ReaderWriter/MachO/CompactUnwindPass.cpp b/lib/ReaderWriter/MachO/CompactUnwindPass.cpp
new file mode 100644
index 000000000000..fc8608383e5d
--- /dev/null
+++ b/lib/ReaderWriter/MachO/CompactUnwindPass.cpp
@@ -0,0 +1,530 @@
+//===- lib/ReaderWriter/MachO/CompactUnwindPass.cpp -----------------------===//
+//
+// 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/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/LLVM.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 {
+ std::vector<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);
+ }
+
+ ContentType contentType() const override {
+ return DefinedAtom::typeProcessedUnwindInfo;
+ }
+
+ Alignment alignment() const override { return Alignment(2); }
+
+ 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
+ CompactUnwindEntry &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)
+ : _context(context), _archHandler(_context.archHandler()),
+ _file("<mach-o Compact Unwind Pass>"),
+ _isBig(MachOLinkingContext::isBigEndian(_context.arch())) {}
+
+private:
+ void perform(std::unique_ptr<MutableFile> &mergedFile) override {
+ 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;
+
+ // 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);
+
+ // Finally, we can start creating pages based on these entries.
+
+ 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;
+ unsigned pageStart = 0;
+ do {
+ pages.push_back(UnwindInfoPage());
+
+ // FIXME: we only create regular pages at the moment. These can hold up to
+ // 1021 entries according to the documentation.
+ unsigned entriesInPage =
+ std::min(1021U, (unsigned)unwindInfos.size() - pageStart);
+
+ std::copy(unwindInfos.begin() + pageStart,
+ unwindInfos.begin() + pageStart + entriesInPage,
+ std::back_inserter(pages.back().entries));
+ pageStart += entriesInPage;
+
+ DEBUG(llvm::dbgs()
+ << " Page from " << pages.back().entries[0].rangeStart->name()
+ << " to " << pages.back().entries.back().rangeStart->name() << " + "
+ << llvm::format("0x%x", pages.back().entries.back().rangeLength)
+ << " has " << entriesInPage << " entries\n");
+ } while (pageStart < unwindInfos.size());
+
+ UnwindInfoAtom *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;
+ });
+ }
+
+ void collectCompactUnwindEntries(
+ std::unique_ptr<MutableFile> &mergedFile,
+ std::map<const Atom *, CompactUnwindEntry> &unwindLocs,
+ std::vector<const Atom *> &personalities, uint32_t &numLSDAs) {
+ DEBUG(llvm::dbgs() << " Collecting __compact_unwind entries\n");
+
+ for (const DefinedAtom *atom : mergedFile->defined()) {
+ if (atom->contentType() != DefinedAtom::typeCompactUnwindInfo)
+ continue;
+
+ auto unwindEntry = extractCompactUnwindEntry(atom);
+ unwindLocs.insert(std::make_pair(unwindEntry.rangeStart, unwindEntry));
+
+ DEBUG(llvm::dbgs() << " Entry for " << unwindEntry.rangeStart->name()
+ << ", encoding="
+ << llvm::format("0x%08x", unwindEntry.encoding));
+ if (unwindEntry.personalityFunction)
+ DEBUG(llvm::dbgs() << ", personality="
+ << unwindEntry.personalityFunction->name()
+ << ", lsdaLoc=" << unwindEntry.lsdaLocation->name());
+ 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(std::unique_ptr<MutableFile> &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 std::unique_ptr<MutableFile> &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;
+
+ 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));
+
+ DEBUG(llvm::dbgs() << " Entry for " << atom->name()
+ << ", final encoding="
+ << llvm::format("0x%08x", unwindInfos.back().encoding)
+ << '\n');
+ }
+
+ return unwindInfos;
+ }
+
+ 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 &_context;
+ 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/lib/ReaderWriter/MachO/ExecutableAtoms.hpp b/lib/ReaderWriter/MachO/ExecutableAtoms.hpp
new file mode 100644
index 000000000000..cd562de216d9
--- /dev/null
+++ b/lib/ReaderWriter/MachO/ExecutableAtoms.hpp
@@ -0,0 +1,136 @@
+//===- lib/ReaderWriter/MachO/ExecutableAtoms.hpp -------------------------===//
+//
+// 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 "llvm/Support/MachO.h"
+
+#include "lld/Core/ArchiveLibraryFile.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"),
+ _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"),
+ _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 ArchiveLibraryFile {
+public:
+ MachHeaderAliasFile(const MachOLinkingContext &context)
+ : ArchiveLibraryFile("mach_header symbols") {
+ switch (context.outputMachOType()) {
+ case llvm::MachO::MH_EXECUTE:
+ _machHeaderSymbolName = "__mh_execute_header";
+ break;
+ case llvm::MachO::MH_DYLIB:
+ _machHeaderSymbolName = "__mh_dylib_header";
+ break;
+ case llvm::MachO::MH_BUNDLE:
+ _machHeaderSymbolName = "__mh_bundle_header";
+ break;
+ case llvm::MachO::MH_DYLINKER:
+ _machHeaderSymbolName = "__mh_dylinker_header";
+ break;
+ case llvm::MachO::MH_PRELOAD:
+ _machHeaderSymbolName = "__mh_preload_header";
+ break;
+ default:
+ llvm_unreachable("no mach_header symbol for file type");
+ }
+ }
+
+ std::error_code
+ parseAllMembers(std::vector<std::unique_ptr<File>> &result) override {
+ return std::error_code();
+ }
+
+ File *find(StringRef sym, bool dataSymbolOnly) override {
+ if (sym.equals("___dso_handle") || sym.equals(_machHeaderSymbolName)) {
+ _definedAtoms._atoms.push_back(new (allocator()) MachODefinedAtom(
+ *this, sym, DefinedAtom::scopeLinkageUnit,
+ DefinedAtom::typeMachHeader, DefinedAtom::mergeNo, false, false,
+ ArrayRef<uint8_t>(), DefinedAtom::Alignment(12,0)));
+ return this;
+ }
+ return nullptr;
+ }
+
+ const atom_collection<DefinedAtom> &defined() const override {
+ return _definedAtoms;
+ }
+ const atom_collection<UndefinedAtom> &undefined() const override {
+ return _undefinedAtoms;
+ }
+
+ const atom_collection<SharedLibraryAtom> &sharedLibrary() const override {
+ return _sharedLibraryAtoms;
+ }
+
+ const atom_collection<AbsoluteAtom> &absolute() const override {
+ return _absoluteAtoms;
+ }
+
+
+private:
+ mutable atom_collection_vector<DefinedAtom> _definedAtoms;
+ atom_collection_vector<UndefinedAtom> _undefinedAtoms;
+ atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
+ atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
+ StringRef _machHeaderSymbolName;
+};
+
+} // namespace mach_o
+} // namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_EXECUTABLE_ATOMS_H
diff --git a/lib/ReaderWriter/MachO/File.h b/lib/ReaderWriter/MachO/File.h
new file mode 100644
index 000000000000..913644ec1fc0
--- /dev/null
+++ b/lib/ReaderWriter/MachO/File.h
@@ -0,0 +1,327 @@
+//===- lib/ReaderWriter/MachO/File.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_FILE_H
+#define LLD_READER_WRITER_MACHO_FILE_H
+
+#include "Atoms.h"
+#include "MachONormalizedFile.h"
+#include "lld/Core/SharedLibraryFile.h"
+#include "lld/Core/Simple.h"
+#include "llvm/ADT/StringMap.h"
+#include <unordered_map>
+
+namespace lld {
+namespace mach_o {
+
+using lld::mach_o::normalized::Section;
+
+class MachOFile : public SimpleFile {
+public:
+ MachOFile(std::unique_ptr<MemoryBuffer> mb, MachOLinkingContext *ctx)
+ : SimpleFile(mb->getBufferIdentifier()), _mb(std::move(mb)), _ctx(ctx) {}
+
+ MachOFile(StringRef path) : SimpleFile(path) {}
+
+ 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 % ((uint64_t)1 << inSection->alignment));
+ MachODefinedAtom *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 % ((uint64_t)1 << inSection->alignment));
+ MachODefinedCustomSectionAtom *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 % ((uint64_t)1 << inSection->alignment));
+ MachODefinedAtom *atom =
+ new (allocator()) MachODefinedAtom(*this, name, scope, 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());
+ }
+ SimpleUndefinedAtom *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());
+ }
+ MachOTentativeDefAtom *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);
+ }
+
+protected:
+ std::error_code doParse() override {
+ // Convert binary file to normalized mach-o.
+ auto normFile = normalized::readBinary(_mb, _ctx->arch());
+ if (std::error_code ec = normFile.getError())
+ return ec;
+ // Convert normalized mach-o to atoms.
+ if (std::error_code ec = normalized::normalizedObjectToAtoms(
+ this, **normFile, false))
+ return 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;
+};
+
+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) {}
+
+ const SharedLibraryAtom *exports(StringRef name, bool isData) 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() { 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 (std::error_code ec = normFile.getError())
+ return ec;
+ // Convert normalized mach-o to atoms.
+ if (std::error_code ec = normalized::normalizedDylibToAtoms(
+ this, **normFile, false))
+ return ec;
+ return std::error_code();
+ }
+
+private:
+ const SharedLibraryAtom *exports(StringRef name,
+ StringRef installName) const {
+ // First, check if requested symbol is directly implemented by this dylib.
+ auto entry = _nameToAtom.find(name);
+ if (entry != _nameToAtom.end()) {
+ if (!entry->second.atom) {
+ // Lazily create SharedLibraryAtom.
+ entry->second.atom =
+ new (allocator()) MachOSharedLibraryAtom(*this, name, installName,
+ entry->second.weakDef);
+ }
+ return entry->second.atom;
+ }
+
+ // 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)
+ 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
diff --git a/lib/ReaderWriter/MachO/GOTPass.cpp b/lib/ReaderWriter/MachO/GOTPass.cpp
new file mode 100644
index 000000000000..1ddec4003cbd
--- /dev/null
+++ b/lib/ReaderWriter/MachO/GOTPass.cpp
@@ -0,0 +1,185 @@
+//===- lib/ReaderWriter/MachO/GOTPass.cpp ---------------------------------===//
+//
+// 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/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/LLVM.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) { }
+
+ ContentType contentType() const override {
+ return DefinedAtom::typeGOT;
+ }
+
+ Alignment alignment() const override {
+ return Alignment(_is64 ? 3 : 2);
+ }
+
+ 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)
+ : _context(context), _archHandler(_context.archHandler()),
+ _file("<mach-o GOT Pass>") { }
+
+private:
+
+ void perform(std::unique_ptr<MutableFile> &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);
+ }
+
+ 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()) {
+ GOTEntryAtom *gotEntry = new (_file.allocator())
+ GOTEntryAtom(_file, _context.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 &_context;
+ mach_o::ArchHandler &_archHandler;
+ MachOFile _file;
+ llvm::DenseMap<const Atom*, const GOTEntryAtom*> _targetToGOT;
+};
+
+
+
+void addGOTPass(PassManager &pm, const MachOLinkingContext &ctx) {
+ assert(ctx.needsGOTPass());
+ pm.add(llvm::make_unique<GOTPass>(ctx));
+}
+
+
+} // end namesapce mach_o
+} // end namesapce lld
diff --git a/lib/ReaderWriter/MachO/LayoutPass.cpp b/lib/ReaderWriter/MachO/LayoutPass.cpp
new file mode 100644
index 000000000000..2d096e4c1a6a
--- /dev/null
+++ b/lib/ReaderWriter/MachO/LayoutPass.cpp
@@ -0,0 +1,482 @@
+//===-- 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/Parallel.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 <algorithm>
+#include <set>
+
+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 MutableFile::DefinedAtomRange &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(MutableFile::DefinedAtomRange &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;
+ const DefinedAtom *right = rc._atom;
+ 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) {
+ 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) {
+ 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) {
+ 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) {
+ 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) {
+ 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);
+ DEBUG({
+ StringRef comp = result ? "<" : ">=";
+ llvm::dbgs() << "Layout: '" << lc._atom->name() << "' " << comp << " '"
+ << rc._atom->name() << "' (" << reason << ")\n";
+ });
+ return result;
+}
+
+LayoutPass::LayoutPass(const Registry &registry, SortOverride sorter)
+ : _registry(registry), _customSorter(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(MutableFile::DefinedAtomRange &range) {
+ ScopedTask task(getDefaultDomain(), "LayoutPass::buildFollowOnTable");
+ // Set the initial size of the followon and the followonNext hash to the
+ // number of atoms that we have.
+ _followOnRoots.resize(range.size());
+ _followOnNexts.resize(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(MutableFile::DefinedAtomRange &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 != NULL;
+ nextAtom = _followOnNexts[nextAtom]) {
+ AtomToOrdinalT::iterator pos = _ordinalOverrideMap.find(nextAtom);
+ if (pos == _ordinalOverrideMap.end())
+ _ordinalOverrideMap[nextAtom] = index++;
+ }
+ }
+}
+
+std::vector<LayoutPass::SortKey>
+LayoutPass::decorate(MutableFile::DefinedAtomRange &atomRange) const {
+ std::vector<SortKey> ret;
+ for (const DefinedAtom *atom : atomRange) {
+ auto ri = _followOnRoots.find(atom);
+ auto oi = _ordinalOverrideMap.find(atom);
+ const DefinedAtom *root = (ri == _followOnRoots.end()) ? atom : ri->second;
+ uint64_t override = (oi == _ordinalOverrideMap.end()) ? 0 : oi->second;
+ ret.push_back(SortKey(atom, root, override));
+ }
+ return ret;
+}
+
+void LayoutPass::undecorate(MutableFile::DefinedAtomRange &atomRange,
+ std::vector<SortKey> &keys) const {
+ size_t i = 0;
+ for (SortKey &k : keys)
+ atomRange[i++] = k._atom;
+}
+
+/// Perform the actual pass
+void LayoutPass::perform(std::unique_ptr<MutableFile> &mergedFile) {
+ // sort the atoms
+ ScopedTask task(getDefaultDomain(), "LayoutPass");
+ MutableFile::DefinedAtomRange atomRange = mergedFile->definedAtoms();
+
+ // Build follow on tables
+ buildFollowOnTable(atomRange);
+
+ // Check the structure of followon graph if running in debug mode.
+ DEBUG(checkFollowonChain(atomRange));
+
+ // Build override maps
+ buildOrdinalOverrideMap(atomRange);
+
+ DEBUG({
+ llvm::dbgs() << "unsorted atoms:\n";
+ printDefinedAtoms(atomRange);
+ });
+
+ std::vector<LayoutPass::SortKey> vec = decorate(atomRange);
+ parallel_sort(vec.begin(), vec.end(),
+ [&](const LayoutPass::SortKey &l, const LayoutPass::SortKey &r) -> bool {
+ return compareAtoms(l, r, _customSorter);
+ });
+ DEBUG(checkTransitivity(vec, _customSorter));
+ undecorate(atomRange, vec);
+
+ DEBUG({
+ llvm::dbgs() << "sorted atoms:\n";
+ printDefinedAtoms(atomRange);
+ });
+}
+
+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/lib/ReaderWriter/MachO/LayoutPass.h b/lib/ReaderWriter/MachO/LayoutPass.h
new file mode 100644
index 000000000000..186f29be0719
--- /dev/null
+++ b/lib/ReaderWriter/MachO/LayoutPass.h
@@ -0,0 +1,97 @@
+//===------ 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 "llvm/ADT/DenseMap.h"
+#include <map>
+#include <string>
+#include <vector>
+
+namespace lld {
+class DefinedAtom;
+class MutableFile;
+
+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(const DefinedAtom *atom, const DefinedAtom *root, uint64_t override)
+ : _atom(atom), _root(root), _override(override) {}
+ const DefinedAtom *_atom;
+ const DefinedAtom *_root;
+ uint64_t _override;
+ };
+
+ 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.
+ void perform(std::unique_ptr<MutableFile> &mergedFile) override;
+
+ virtual ~LayoutPass() {}
+
+private:
+ // Build the followOn atoms chain as specified by the kindLayoutAfter
+ // reference type
+ void buildFollowOnTable(MutableFile::DefinedAtomRange &range);
+
+ // Build a map of Atoms to ordinals for sorting the atoms
+ void buildOrdinalOverrideMap(MutableFile::DefinedAtomRange &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(MutableFile::DefinedAtomRange &atomRange) const;
+ void undecorate(MutableFile::DefinedAtomRange &atomRange,
+ std::vector<SortKey> &keys) const;
+
+ // Check if the follow-on graph is a correct structure. For debugging only.
+ void checkFollowonChain(MutableFile::DefinedAtomRange &range);
+};
+
+} // namespace mach_o
+} // namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_LAYOUT_PASS_H
diff --git a/lib/ReaderWriter/MachO/MachOLinkingContext.cpp b/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
new file mode 100644
index 000000000000..92385cf3e820
--- /dev/null
+++ b/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
@@ -0,0 +1,969 @@
+//===- 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/ReaderWriter/MachOLinkingContext.h"
+#include "ArchHandler.h"
+#include "File.h"
+#include "MachONormalizedFile.h"
+#include "MachOPasses.h"
+#include "lld/Core/ArchiveLibraryFile.h"
+#include "lld/Core/PassManager.h"
+#include "lld/Core/Reader.h"
+#include "lld/Core/Writer.h"
+#include "lld/Driver/Driver.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Config/config.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/MachO.h"
+#include "llvm/Support/Path.h"
+#include <algorithm>
+
+#if defined(HAVE_CXXABI_H)
+#include <cxxabi.h>
+#endif
+
+using lld::mach_o::ArchHandler;
+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;
+}
+
+
+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(const MemoryBuffer &mb,
+ uint32_t &offset,
+ uint32_t &size) {
+ return mach_o::normalized::sliceFromFatFile(mb, _arch, offset, size);
+}
+
+MachOLinkingContext::MachOLinkingContext()
+ : _outputMachOType(MH_EXECUTE), _outputMachOTypeStatic(false),
+ _doNothing(false), _pie(false), _arch(arch_unknown), _os(OS::macOSX),
+ _osMinVersion(0), _pageZeroSize(0), _pageSize(4096), _baseAddress(0),
+ _compatibilityVersion(0), _currentVersion(0), _deadStrippableDylib(false),
+ _printAtoms(false), _testingFileUsage(false), _keepPrivateExterns(false),
+ _demangle(false), _archHandler(nullptr),
+ _exportMode(ExportMode::globals),
+ _debugInfoMode(DebugInfoMode::addDebugMap), _orderFileEntries(0) {}
+
+MachOLinkingContext::~MachOLinkingContext() {}
+
+void MachOLinkingContext::configure(HeaderFileType type, Arch arch, OS os,
+ uint32_t minOSVersion) {
+ _outputMachOType = type;
+ _arch = arch;
+ _os = os;
+ _osMinVersion = minOSVersion;
+
+ // If min OS not specified on command line, use reasonable defaults.
+ if (minOSVersion == 0) {
+ switch (_arch) {
+ case arch_x86_64:
+ case arch_x86:
+ parsePackedVersion("10.8", _osMinVersion);
+ _os = MachOLinkingContext::OS::macOSX;
+ break;
+ case arch_armv6:
+ case arch_armv7:
+ case arch_armv7s:
+ case arch_arm64:
+ parsePackedVersion("7.0", _osMinVersion);
+ _os = MachOLinkingContext::OS::iOS;
+ break;
+ default:
+ break;
+ }
+ }
+
+ 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;
+ }
+
+ // 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;
+ }
+ break;
+ case llvm::MachO::MH_DYLIB:
+ setGlobalsAreDeadStripRoots(true);
+ break;
+ case llvm::MachO::MH_BUNDLE:
+ break;
+ case llvm::MachO::MH_OBJECT:
+ _printRemainingUndefines = false;
+ _allowRemainingUndefines = true;
+ 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::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;
+ }
+}
+
+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:
+ break;
+ }
+ llvm_unreachable("target not configured for iOS or MacOSX");
+}
+
+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);
+}
+
+
+ErrorOr<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 make_error_code(llvm::errc::no_such_file_or_directory);
+ }
+
+ // 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 make_error_code(llvm::errc::no_such_file_or_directory);
+}
+
+
+
+ErrorOr<StringRef> MachOLinkingContext::searchLibrary(StringRef libName) const {
+ SmallString<256> path;
+ for (StringRef dir : searchDirs()) {
+ ErrorOr<StringRef> ec = searchDirForLibrary(dir, libName);
+ if (ec)
+ return ec;
+ }
+
+ return make_error_code(llvm::errc::no_such_file_or_directory);
+}
+
+
+ErrorOr<StringRef> MachOLinkingContext::findPathForFramework(StringRef fwName) const{
+ SmallString<256> fullPath;
+ for (StringRef dir : frameworkDirs()) {
+ fullPath.assign(dir);
+ llvm::sys::path::append(fullPath, Twine(fwName) + ".framework", fwName);
+ if (fileExists(fullPath))
+ return fullPath.str().copy(_allocator);
+ }
+
+ return make_error_code(llvm::errc::no_such_file_or_directory);
+}
+
+bool MachOLinkingContext::validateImpl(raw_ostream &diagnostics) {
+ // TODO: if -arch not specified, look at arch of first .o file.
+
+ if (_currentVersion && _outputMachOType != MH_DYLIB) {
+ diagnostics << "error: -current_version can only be used with dylibs\n";
+ return false;
+ }
+
+ if (_compatibilityVersion && _outputMachOType != MH_DYLIB) {
+ diagnostics
+ << "error: -compatibility_version can only be used with dylibs\n";
+ return false;
+ }
+
+ if (_deadStrippableDylib && _outputMachOType != MH_DYLIB) {
+ diagnostics
+ << "error: -mark_dead_strippable_dylib can only be used with dylibs.\n";
+ return false;
+ }
+
+ if (!_bundleLoader.empty() && outputMachOType() != MH_BUNDLE) {
+ diagnostics
+ << "error: -bundle_loader can only be used with Mach-O bundles\n";
+ 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) {
+ 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 (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, 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;
+
+ std::vector<std::unique_ptr<File>> files;
+ if (registry().loadFile(std::move(mbOrErr.get()), files))
+ return nullptr;
+ assert(files.size() == 1 && "expected one file in dylib");
+ files[0]->parse();
+ MachODylibFile* result = reinterpret_cast<MachODylibFile*>(files[0].get());
+ // Node object now owned by _indirectDylibs vector.
+ _indirectDylibs.push_back(std::move(files[0]));
+ 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.getError()) {
+ return loadIndirectDylib(libPath.get());
+ }
+ }
+
+ // 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 0x1000; // 1.0
+}
+
+uint32_t MachOLinkingContext::dylibCompatVersion(StringRef installName) const {
+ auto pos = _pathToDylibMap.find(installName);
+ if (pos != _pathToDylibMap.end())
+ return pos->second->compatVersion();
+ else
+ return 0x1000; // 1.0
+}
+
+bool 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.
+ return writer().createImplicitFiles(result);
+}
+
+
+void MachOLinkingContext::registerDylib(MachODylibFile *dylib,
+ bool upward) const {
+ _allDylibs.insert(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,
+ uint8_t align2) {
+ SectionAlign entry;
+ entry.segmentName = seg;
+ entry.sectionName = sect;
+ entry.align2 = align2;
+ _sectAligns.push_back(entry);
+}
+
+bool MachOLinkingContext::sectionAligned(StringRef seg, StringRef sect,
+ uint8_t &align2) const {
+ for (const SectionAlign &entry : _sectAligns) {
+ if (seg.equals(entry.segmentName) && sect.equals(entry.sectionName)) {
+ align2 = entry.align2;
+ 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;
+
+#if defined(HAVE_CXXABI_H)
+ 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 = abi::__cxa_demangle(cstr, nullptr, nullptr, &status);
+ if (demangled != NULL) {
+ std::string result(demangled);
+ // __cxa_demangle() always uses a malloc'ed buffer to return the result.
+ free(demangled);
+ return result;
+ }
+#endif
+
+ return symbolName;
+}
+
+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;
+ }
+
+ char linkerVersionOpcode = 0x00;
+ *_dependencyInfo << linkerVersionOpcode;
+ *_dependencyInfo << "lld"; // FIXME
+ *_dependencyInfo << '\0';
+
+ return std::error_code();
+}
+
+void MachOLinkingContext::addInputFileDependency(StringRef path) const {
+ if (!_dependencyInfo)
+ return;
+
+ char inputFileOpcode = 0x10;
+ *_dependencyInfo << inputFileOpcode;
+ *_dependencyInfo << path;
+ *_dependencyInfo << '\0';
+}
+
+void MachOLinkingContext::addInputFileNotFound(StringRef path) const {
+ if (!_dependencyInfo)
+ return;
+
+ char inputFileOpcode = 0x11;
+ *_dependencyInfo << inputFileOpcode;
+ *_dependencyInfo << path;
+ *_dependencyInfo << '\0';
+}
+
+void MachOLinkingContext::addOutputFileDependency(StringRef path) const {
+ if (!_dependencyInfo)
+ return;
+
+ char outputFileOpcode = 0x40;
+ *_dependencyInfo << outputFileOpcode;
+ *_dependencyInfo << path;
+ *_dependencyInfo << '\0';
+}
+
+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));
+}
+
+} // end namespace lld
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFile.h b/lib/ReaderWriter/MachO/MachONormalizedFile.h
new file mode 100644
index 000000000000..70bcde2dea22
--- /dev/null
+++ b/lib/ReaderWriter/MachO/MachONormalizedFile.h
@@ -0,0 +1,323 @@
+//===- 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 |
+/// +-------+
+///
+
+#include "lld/Core/Error.h"
+#include "lld/Core/LLVM.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/MachO.h"
+#include "llvm/Support/YAMLTraits.h"
+
+#ifndef LLD_READER_WRITER_MACHO_NORMALIZE_FILE_H
+#define LLD_READER_WRITER_MACHO_NORMALIZE_FILE_H
+
+using llvm::BumpPtrAllocator;
+using llvm::yaml::Hex64;
+using llvm::yaml::Hex32;
+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)
+
+/// 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(0), address(0) { }
+
+ StringRef segmentName;
+ StringRef sectionName;
+ SectionType type;
+ SectionAttr attributes;
+ uint32_t 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;
+};
+
+/// 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 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 {
+ NormalizedFile() : arch(MachOLinkingContext::arch_unknown),
+ fileType(llvm::MachO::MH_OBJECT),
+ flags(0),
+ hasUUID(false),
+ os(MachOLinkingContext::OS::unknown) { }
+
+ MachOLinkingContext::Arch arch;
+ HeaderFileType fileType;
+ FileFlags flags;
+ 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;
+
+ // Maps to load commands with no LINKEDIT content (final linked images only).
+ std::vector<DependentDylib> dependentDylibs;
+ StringRef installName; // dylibs only
+ PackedVersion compatVersion; // dylibs only
+ PackedVersion currentVersion; // dylibs only
+ bool hasUUID;
+ std::vector<StringRef> rpaths;
+ Hex64 entryAddress;
+ MachOLinkingContext::OS os;
+ Hex64 sourceVersion;
+ PackedVersion minOSverson;
+ PackedVersion sdkVersion;
+
+ // Maps to load commands with LINKEDIT content (final linked images only).
+ Hex32 pageSize;
+ std::vector<RebaseLocation> rebasingInfo;
+ std::vector<BindLocation> bindingInfo;
+ std::vector<BindLocation> weakBindingInfo;
+ std::vector<BindLocation> lazyBindingInfo;
+ std::vector<Export> exportInfo;
+ 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(const MemoryBuffer &mb, MachOLinkingContext::Arch arch,
+ uint32_t &offset, uint32_t &size);
+
+/// Reads a mach-o file and produces an in-memory normalized view.
+ErrorOr<std::unique_ptr<NormalizedFile>>
+readBinary(std::unique_ptr<MemoryBuffer> &mb,
+ const MachOLinkingContext::Arch arch);
+
+/// Takes in-memory normalized view and writes a mach-o object file.
+std::error_code writeBinary(const NormalizedFile &file, StringRef path);
+
+size_t headerAndLoadCommandsSize(const NormalizedFile &file);
+
+
+/// Parses a yaml encoded mach-o file to produce an in-memory normalized view.
+ErrorOr<std::unique_ptr<NormalizedFile>>
+readYaml(std::unique_ptr<MemoryBuffer> &mb);
+
+/// Writes a yaml encoded mach-o files given an in-memory normalized view.
+std::error_code writeYaml(const NormalizedFile &file, raw_ostream &out);
+
+std::error_code
+normalizedObjectToAtoms(MachOFile *file,
+ const NormalizedFile &normalizedFile,
+ bool copyRefs);
+
+std::error_code
+normalizedDylibToAtoms(MachODylibFile *file,
+ const NormalizedFile &normalizedFile,
+ bool copyRefs);
+
+/// Takes in-memory normalized dylib or object and parses it into lld::File
+ErrorOr<std::unique_ptr<lld::File>>
+normalizedToAtoms(const NormalizedFile &normalizedFile, StringRef path,
+ bool copyRefs);
+
+/// Takes atoms and generates a normalized macho-o view.
+ErrorOr<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/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
new file mode 100644
index 000000000000..07a6dbfe569b
--- /dev/null
+++ b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
@@ -0,0 +1,582 @@
+//===- 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 "MachONormalizedFile.h"
+#include "ArchHandler.h"
+#include "MachONormalizedFileBinaryUtils.h"
+#include "lld/Core/Error.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/SharedLibraryFile.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Twine.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/MachO.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::object::MachOObjectFile;
+
+namespace lld {
+namespace mach_o {
+namespace normalized {
+
+// Utility to call a lambda expression on each load command.
+static std::error_code 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 make_error_code(llvm::errc::executable_format_error);
+
+ if (func(slc->cmd, slc->cmdsize, p))
+ return std::error_code();
+
+ p += slc->cmdsize;
+ }
+
+ return std::error_code();
+}
+
+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(const MemoryBuffer &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.
+ErrorOr<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, 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 make_error_code(llvm::errc::executable_format_error);
+
+ // 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 make_error_code(llvm::errc::executable_format_error);
+
+ // Get architecture from mach_header.
+ f->arch = MachOLinkingContext::archFromCpuType(smh->cputype, smh->cpusubtype);
+ if (f->arch != arch) {
+ return make_dynamic_error_code(Twine("file is wrong architecture. Expected "
+ "(" + 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;
+ std::error_code 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 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 = 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 = 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) {
+ const nlist_64 *sin = &symbols[i];
+ nlist_64 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 (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
+ 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;
+ }
+ return false;
+ });
+ if (ec)
+ return 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 +
+ dyldInfo->export_off);
+ ArrayRef<uint8_t> trie(trieStart, dyldInfo->export_size);
+ for (const ExportEntry &trieExport : MachOObjectFile::exports(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);
+ }
+ }
+ }
+
+ return std::move(f);
+}
+
+class MachOObjectReader : public Reader {
+public:
+ MachOObjectReader(MachOLinkingContext &ctx) : _ctx(ctx) {}
+
+ bool canParse(file_magic magic, StringRef ext,
+ const MemoryBuffer &mb) const override {
+ switch (magic) {
+ case llvm::sys::fs::file_magic::macho_object:
+ return (mb.getBufferSize() > 32);
+ default:
+ return false;
+ }
+ }
+
+ std::error_code
+ loadFile(std::unique_ptr<MemoryBuffer> mb, const Registry &registry,
+ std::vector<std::unique_ptr<File>> &result) const override {
+ auto *file = new MachOFile(std::move(mb), &_ctx);
+ result.push_back(std::unique_ptr<MachOFile>(file));
+ return std::error_code();
+ }
+
+private:
+ MachOLinkingContext &_ctx;
+};
+
+class MachODylibReader : public Reader {
+public:
+ MachODylibReader(MachOLinkingContext &ctx) : _ctx(ctx) {}
+
+ bool canParse(file_magic magic, StringRef ext,
+ const MemoryBuffer &mb) const override {
+ switch (magic) {
+ case llvm::sys::fs::file_magic::macho_dynamically_linked_shared_lib:
+ case llvm::sys::fs::file_magic::macho_dynamically_linked_shared_lib_stub:
+ return (mb.getBufferSize() > 32);
+ default:
+ return false;
+ }
+ }
+
+ std::error_code
+ loadFile(std::unique_ptr<MemoryBuffer> mb, const Registry &registry,
+ std::vector<std::unique_ptr<File>> &result) const override {
+ auto *file = new MachODylibFile(std::move(mb), &_ctx);
+ result.push_back(std::unique_ptr<MachODylibFile>(file));
+ return std::error_code();
+ }
+
+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/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h
new file mode 100644
index 000000000000..613c1b2f251a
--- /dev/null
+++ b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h
@@ -0,0 +1,177 @@
+//===- 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.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "MachONormalizedFile.h"
+#include "lld/Core/Error.h"
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/MachO.h"
+#include <system_error>
+
+#ifndef LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H
+#define LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H
+
+namespace lld {
+namespace mach_o {
+namespace normalized {
+
+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 % llvm::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 % llvm::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 % llvm::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]) {
+ StringRef x = s;
+ if ( x.size() > 16 )
+ return x.substr(0, 16);
+ else
+ return x;
+}
+
+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);
+
+} // namespace normalized
+} // namespace mach_o
+} // namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
new file mode 100644
index 000000000000..be7acf9d4d60
--- /dev/null
+++ b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
@@ -0,0 +1,1346 @@
+//===- 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/Core/Error.h"
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.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/LEB128.h"
+#include "llvm/Support/MachO.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 {
+
+/// 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.
+ std::error_code writeBinary(StringRef path);
+
+private:
+ uint32_t loadCommandsSize(uint32_t &count);
+ void buildFileOffsets();
+ void writeMachHeader();
+ std::error_code writeLoadCommands();
+ void writeSectionContent();
+ void writeRelocations();
+ void writeSymbolTable();
+ void writeRebaseInfo();
+ void writeBindingInfo();
+ void writeLazyBindingInfo();
+ void writeExportInfo();
+ void writeDataInCodeInfo();
+ void writeLinkEditContent();
+ void buildLinkEditInfo();
+ void buildRebaseInfo();
+ void buildBindInfo();
+ void buildLazyBindInfo();
+ void buildExportTrie();
+ 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>
+ std::error_code writeSingleSegmentLoadCommand(uint8_t *&lc);
+ template <typename T> std::error_code writeSegmentLoadCommands(uint8_t *&lc);
+
+ uint32_t pointerAlign(uint32_t value);
+ static StringRef dyldPath();
+
+ class ByteBuffer {
+ public:
+ ByteBuffer() : _ostream(_bytes) { }
+
+ void append_byte(uint8_t b) {
+ _ostream << b;
+ }
+ void append_uleb128(uint64_t value) {
+ llvm::encodeULEB128(value, _ostream);
+ }
+ void append_uleb128Fixed(uint64_t value, unsigned byteCount) {
+ unsigned min = llvm::getULEB128Size(value);
+ assert(min <= byteCount);
+ unsigned pad = byteCount - min;
+ llvm::encodeULEB128(value, _ostream, pad);
+ }
+ void append_sleb128(int64_t value) {
+ llvm::encodeSLEB128(value, _ostream);
+ }
+ void append_string(StringRef str) {
+ _ostream << str;
+ append_byte(0);
+ }
+ void align(unsigned alignment) {
+ while ( (_ostream.tell() % alignment) != 0 )
+ append_byte(0);
+ }
+ size_t size() {
+ return _ostream.tell();
+ }
+ const uint8_t *bytes() {
+ return reinterpret_cast<const uint8_t*>(_ostream.str().data());
+ }
+ private:
+ SmallVector<char, 128> _bytes;
+ // Stream ivar must be after SmallVector ivar to construct properly.
+ llvm::raw_svector_ostream _ostream;
+ };
+
+ struct TrieNode; // Forward declaration.
+
+ struct TrieEdge {
+ TrieEdge(StringRef s, TrieNode *node) : _subString(s), _child(node) {}
+ ~TrieEdge() {}
+
+ StringRef _subString;
+ struct TrieNode *_child;
+ };
+
+ struct TrieNode {
+ TrieNode(StringRef s)
+ : _cummulativeString(s), _address(0), _flags(0), _other(0),
+ _trieOffset(0), _hasExportInfo(false) {}
+ ~TrieNode() {}
+
+ void addSymbol(const Export &entry, BumpPtrAllocator &allocator,
+ std::vector<TrieNode *> &allNodes);
+ bool updateOffset(uint32_t &offset);
+ void appendToByteBuffer(ByteBuffer &out);
+
+private:
+ StringRef _cummulativeString;
+ std::list<TrieEdge> _children;
+ uint64_t _address;
+ uint64_t _flags;
+ uint64_t _other;
+ StringRef _importedName;
+ uint32_t _trieOffset;
+ bool _hasExportInfo;
+ };
+
+ struct SegExtraInfo {
+ uint32_t fileOffset;
+ uint32_t fileSize;
+ 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 _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 _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::RoundUpToAlignment(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.dataInCode.empty()) {
+ _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 (sect.type != llvm::MachO::S_ZEROFILL) {
+ offset = llvm::RoundUpToAlignment(offset, 1 << sect.alignment);
+ _sectInfo[&sect].fileOffset = offset;
+ offset += sect.content.size();
+ } else {
+ _sectInfo[&sect].fileOffset = 0;
+ }
+ relocCount += sect.relocations.size();
+ }
+ _endOfSectionsContent = offset;
+
+ computeSymbolTableSizes();
+ computeDataInCodeSize();
+
+ // Align start of relocations.
+ _startOfRelocations = pointerAlign(_endOfSectionsContent);
+ _startOfDataInCode = _startOfRelocations + relocCount * 8;
+ _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();
+ _startOfDataInCode = _endOfExportTrie;
+ _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"
+ << " 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;
+ // Add one LC_SEGMENT for implicit __LINKEDIT segment
+ size += segCommandSize;
+ ++count;
+
+ // If creating a dylib, add LC_ID_DYLIB.
+ if (_file.fileType == llvm::MachO::MH_DYLIB) {
+ 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 and LC_MAIN
+ if (_file.fileType == llvm::MachO::MH_EXECUTE) {
+ size += pointerAlign(sizeof(dylinker_command) + dyldPath().size()+1);
+ ++count;
+ 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 += sizeof(rpath_command) + pointerAlign(path.size()+1);
+ ++count;
+ }
+
+ // Add LC_DATA_IN_CODE if needed
+ if (!_file.dataInCode.empty()) {
+ 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.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.access)
+ segFileSize = _file.pageSize;
+ for (const Section *s : _segInfo[&sg].sections) {
+ uint32_t sectOffset = s->address - sg.address;
+ uint32_t sectFileSize =
+ s->type == llvm::MachO::S_ZEROFILL ? 0 : s->content.size();
+ 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");
+ }
+
+ _segInfo[&sg].fileSize = llvm::RoundUpToAlignment(segFileSize,
+ _file.pageSize);
+ fileOffset = llvm::RoundUpToAlignment(fileOffset + segFileSize,
+ _file.pageSize);
+ _addressOfLinkEdit = sg.address + sg.size;
+ }
+ _startOfLinkEdit = fileOffset;
+}
+
+
+size_t MachOFileLayout::size() const {
+ return _endOfSymbolStrings;
+}
+
+void MachOFileLayout::writeMachHeader() {
+ mach_header *mh = reinterpret_cast<mach_header*>(_buffer);
+ mh->magic = _is64 ? llvm::MachO::MH_MAGIC_64 : llvm::MachO::MH_MAGIC;
+ mh->cputype = MachOLinkingContext::cpuTypeFromArch(_file.arch);
+ mh->cpusubtype = MachOLinkingContext::cpuSubtypeFromArch(_file.arch);
+ mh->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>
+std::error_code 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 = seg->vmsize;
+ 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 = 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 std::error_code();
+}
+
+template <typename T>
+std::error_code MachOFileLayout::writeSegmentLoadCommands(uint8_t *&lc) {
+ uint32_t indirectSymRunningIndex = 0;
+ for (const Segment &seg : _file.segments) {
+ // Write segment command with trailing sections.
+ SegExtraInfo &segInfo = _segInfo[&seg];
+ 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->maxprot = seg.access;
+ cmd->initprot = seg.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 (section->type == llvm::MachO::S_ZEROFILL)
+ sect->offset = 0;
+ else
+ sect->offset = section->address - seg.address + segInfo.fileOffset;
+ sect->align = 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);
+ }
+ // Add implicit __LINKEDIT segment
+ size_t linkeditSize = _endOfLinkEdit - _startOfLinkEdit;
+ typename T::command* cmd = reinterpret_cast<typename T::command*>(lc);
+ cmd->cmd = T::LC;
+ cmd->cmdsize = sizeof(typename T::command);
+ uint8_t *next = lc + cmd->cmdsize;
+ setString16("__LINKEDIT", cmd->segname);
+ cmd->vmaddr = _addressOfLinkEdit;
+ cmd->vmsize = llvm::RoundUpToAlignment(linkeditSize, _file.pageSize);
+ cmd->fileoff = _startOfLinkEdit;
+ cmd->filesize = linkeditSize;
+ cmd->maxprot = VM_PROT_READ;
+ cmd->initprot = VM_PROT_READ;
+ cmd->nsects = 0;
+ cmd->flags = 0;
+ if (_swap)
+ swapStruct(*cmd);
+ lc = next;
+ return std::error_code();
+}
+
+std::error_code MachOFileLayout::writeLoadCommands() {
+ std::error_code ec;
+ uint8_t *lc = &_buffer[_startOfLoadCommands];
+ if (_file.fileType == llvm::MachO::MH_OBJECT) {
+ // Object files have one unnamed segment which holds all sections.
+ if (_is64)
+ ec = writeSingleSegmentLoadCommand<MachO64Trait>(lc);
+ else
+ ec = writeSingleSegmentLoadCommand<MachO32Trait>(lc);
+ // 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.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_DATA_IN_CODE if needed.
+ if (_dataInCodeSize != 0) {
+ 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)
+ ec = writeSegmentLoadCommands<MachO64Trait>(lc);
+ else
+ ec = writeSegmentLoadCommands<MachO32Trait>(lc);
+
+ // 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.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.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 and LC_MAIN.
+ 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;
+ // Build LC_MAIN load command.
+ entry_point_command* ep = reinterpret_cast<entry_point_command*>(lc);
+ ep->cmd = LC_MAIN;
+ ep->cmdsize = sizeof(entry_point_command);
+ ep->entryoff = _file.entryAddress - _seg1addr;
+ ep->stacksize = 0;
+ if (_swap)
+ swapStruct(*ep);
+ 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 = sizeof(rpath_command) + pointerAlign(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_DATA_IN_CODE if needed.
+ if (_dataInCodeSize != 0) {
+ 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 ec;
+}
+
+
+void MachOFileLayout::writeSectionContent() {
+ for (const Section &s : _file.sections) {
+ // Copy all section content to output buffer.
+ if (s.type == llvm::MachO::S_ZEROFILL)
+ 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::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;
+ _buffer[strOffset++] = '\0'; // Reserve n_strx offset of zero to mean no name.
+ 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();
+ 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;
+ for (const BindLocation& entry : _file.bindingInfo) {
+ _bindingInfo.append_byte(BIND_OPCODE_SET_TYPE_IMM | entry.kind);
+ _bindingInfo.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
+ | entry.segIndex);
+ _bindingInfo.append_uleb128(entry.segOffset);
+ _bindingInfo.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | entry.ordinal);
+ _bindingInfo.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM);
+ _bindingInfo.append_string(entry.symbolName);
+ 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_TYPE_IMM | entry.kind);
+ _lazyBindingInfo.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
+ | entry.segIndex);
+ _lazyBindingInfo.append_uleb128Fixed(entry.segOffset, 5);
+ _lazyBindingInfo.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | entry.ordinal);
+ _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.append_byte(BIND_OPCODE_DONE);
+ _lazyBindingInfo.align(_is64 ? 8 : 4);
+}
+
+void MachOFileLayout::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);
+ TrieNode* 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;
+ TrieEdge *bcEdge = new (allocator) TrieEdge(bcEdgeStr, cNode);
+ bNode->_children.push_back(std::move(*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.
+ TrieNode* newNode = new (allocator) TrieNode(entry.name.copy(allocator));
+ TrieEdge *newEdge = new (allocator) TrieEdge(partialStr, newNode);
+ _children.push_back(std::move(*newEdge));
+ DEBUG_WITH_TYPE("trie-builder", llvm::dbgs()
+ << "new TrieNode('" << entry.name << "') with edge '"
+ << 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);
+}
+
+bool MachOFileLayout::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 MachOFileLayout::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.
+ TrieNode* 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);
+ }
+
+ // 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 : allNodes) {
+ if (node->updateOffset(offset))
+ more = true;
+ }
+ } while (more);
+
+ // Serialize trie to ByteBuffer.
+ for (TrieNode* node : allNodes) {
+ 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.localSymbols.size()
+ + _file.globalSymbols.size()
+ + _file.undefinedSymbols.size());
+ _symbolStringPoolSize = 0;
+ 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.localSymbols.size();
+ _symbolTableUndefinesStartIndex = _symbolTableGlobalsStartIndex
+ + _file.globalSymbols.size();
+
+ _indirectSymbolTableCount = 0;
+ for (const Section &sect : _file.sections) {
+ _indirectSymbolTableCount += sect.indirectSymbols.size();
+ }
+}
+
+void MachOFileLayout::computeDataInCodeSize() {
+ _dataInCodeSize = _file.dataInCode.size() * sizeof(data_in_code_entry);
+}
+
+void MachOFileLayout::writeLinkEditContent() {
+ if (_file.fileType == llvm::MachO::MH_OBJECT) {
+ writeRelocations();
+ writeDataInCodeInfo();
+ writeSymbolTable();
+ } else {
+ writeRebaseInfo();
+ writeBindingInfo();
+ writeLazyBindingInfo();
+ // TODO: add weak binding info
+ writeExportInfo();
+ writeDataInCodeInfo();
+ writeSymbolTable();
+ }
+}
+
+std::error_code MachOFileLayout::writeBinary(StringRef path) {
+ // Check for pending error from constructor.
+ if (_ec)
+ return _ec;
+ // Create FileOutputBuffer with calculated size.
+ std::unique_ptr<llvm::FileOutputBuffer> fob;
+ unsigned flags = 0;
+ if (_file.fileType != llvm::MachO::MH_OBJECT)
+ flags = llvm::FileOutputBuffer::F_executable;
+ std::error_code ec;
+ ec = llvm::FileOutputBuffer::create(path, size(), fob, flags);
+ if (ec)
+ return ec;
+
+ // Write content.
+ _buffer = fob->getBufferStart();
+ writeMachHeader();
+ ec = writeLoadCommands();
+ if (ec)
+ return ec;
+ writeSectionContent();
+ writeLinkEditContent();
+ fob->commit();
+
+ return std::error_code();
+}
+
+
+/// Takes in-memory normalized view and writes a mach-o object file.
+std::error_code writeBinary(const NormalizedFile &file, StringRef path) {
+ MachOFileLayout layout(file);
+ return layout.writeBinary(path);
+}
+
+
+} // namespace normalized
+} // namespace mach_o
+} // namespace lld
+
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
new file mode 100644
index 000000000000..4d6183f71df7
--- /dev/null
+++ b/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
@@ -0,0 +1,1238 @@
+//===- 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 "MachONormalizedFile.h"
+#include "ArchHandler.h"
+#include "MachONormalizedFileBinaryUtils.h"
+#include "lld/Core/Error.h"
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/MachO.h"
+#include <map>
+#include <system_error>
+
+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=0);
+
+ StringRef segmentName;
+ StringRef sectionName;
+ SectionType type;
+ uint32_t attributes;
+ uint64_t address;
+ uint64_t size;
+ uint32_t alignment;
+ std::vector<AtomInfo> atomsAndOffsets;
+ uint32_t normalizedSectionIndex;
+ uint32_t finalSectionIndex;
+};
+
+SectionInfo::SectionInfo(StringRef sg, StringRef sct, SectionType t,
+ const MachOLinkingContext &ctxt, uint32_t attrs)
+ : segmentName(sg), sectionName(sct), type(t), attributes(attrs),
+ address(0), size(0), alignment(0),
+ normalizedSectionIndex(0), finalSectionIndex(0) {
+ uint8_t align;
+ if (ctxt.sectionAligned(segmentName, sectionName, align)) {
+ alignment = align;
+ }
+}
+
+struct SegmentInfo {
+ SegmentInfo(StringRef name);
+
+ StringRef name;
+ uint64_t address;
+ uint64_t size;
+ uint32_t access;
+ std::vector<SectionInfo*> sections;
+ uint32_t normalizedSegmentIndex;
+};
+
+SegmentInfo::SegmentInfo(StringRef n)
+ : name(n), address(0), size(0), access(0), normalizedSegmentIndex(0) {
+}
+
+
+class Util {
+public:
+ Util(const MachOLinkingContext &ctxt)
+ : _context(ctxt), _archHandler(ctxt.archHandler()), _entryAtom(nullptr) {}
+ ~Util();
+
+ void assignAtomsToSections(const lld::File &atomFile);
+ void organizeSections();
+ void assignAddressesToSections(const NormalizedFile &file);
+ uint32_t fileFlags();
+ void copySegmentInfo(NormalizedFile &file);
+ void copySectionInfo(NormalizedFile &file);
+ void updateSectionInfo(NormalizedFile &file);
+ void buildAtomToAddressMap();
+ std::error_code 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 buildDataInCodeArray(const lld::File &, NormalizedFile &file);
+ void addDependentDylibs(const lld::File &, NormalizedFile &file);
+ void copyEntryPointAddress(NormalizedFile &file);
+ void copySectionContent(NormalizedFile &file);
+
+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);
+ std::error_code getSymbolTableRegion(const DefinedAtom* atom,
+ bool &inGlobalsRegion,
+ SymbolScope &symbolScope);
+ void appendSection(SectionInfo *si, NormalizedFile &file);
+ uint32_t sectionIndexForAtom(const Atom *atom);
+
+ static uint64_t alignTo(uint64_t value, uint8_t align2);
+ typedef llvm::DenseMap<const Atom*, uint32_t> AtomToIndex;
+ struct AtomAndIndex { const Atom *atom; uint32_t index; SymbolScope scope; };
+ struct AtomSorter {
+ 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 &_context;
+ 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;
+};
+
+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;
+
+ // Use same table used by when parsing .o files.
+ relocatableSectionInfoForContentType(type, segmentName, sectionName,
+ sectionType, sectionAttrs);
+ // 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.
+ SectionInfo *sect = new (_allocator) SectionInfo(segmentName, sectionName,
+ sectionType, _context,
+ sectionAttrs);
+ _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", "__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", "__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::typeCode:
+ case DefinedAtom::typeStub:
+ case DefinedAtom::typeStubHelper:
+ sectionAttrs = S_ATTR_PURE_INSTRUCTIONS;
+ 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.
+ SectionInfo *sect = new (_allocator) SectionInfo(p.segmentName,
+ p.sectionName,
+ p.sectionType,
+ _context,
+ sectionAttrs);
+ _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 = (_context.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);
+ SectionInfo *sect = new (_allocator) SectionInfo(segName, sectName,
+ S_REGULAR, _context);
+ _customSections.push_back(sect);
+ _sectionInfos.push_back(sect);
+ return sect;
+ }
+}
+
+
+void Util::appendAtom(SectionInfo *sect, const DefinedAtom *atom) {
+ // Figure out offset for atom in this section given alignment constraints.
+ uint64_t offset = sect->size;
+ DefinedAtom::Alignment atomAlign = atom->alignment();
+ uint64_t align2 = 1 << atomAlign.powerOf2;
+ uint64_t requiredModulus = atomAlign.modulus;
+ uint64_t currentModulus = (offset % align2);
+ if ( currentModulus != requiredModulus ) {
+ if ( requiredModulus > currentModulus )
+ offset += requiredModulus-currentModulus;
+ else
+ offset += align2+requiredModulus-currentModulus;
+ }
+ // Record max alignment of any atom in this section.
+ if ( atomAlign.powerOf2 > sect->alignment )
+ sect->alignment = atomAlign.powerOf2;
+ // 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::assignAtomsToSections(const lld::File &atomFile) {
+ for (const DefinedAtom *atom : atomFile.defined()) {
+ if (atom->contentType() == DefinedAtom::typeMachHeader)
+ _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;
+ }
+ SegmentInfo *info = new (_allocator) SegmentInfo(segName);
+ if (segName.equals("__TEXT"))
+ info->access = VM_PROT_READ | VM_PROT_EXECUTE;
+ else if (segName.equals("__DATA"))
+ info->access = VM_PROT_READ | VM_PROT_WRITE;
+ else if (segName.equals("__PAGEZERO"))
+ info->access = 0;
+ _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() {
+ if (_context.outputMachOType() == llvm::MachO::MH_OBJECT) {
+ // Leave sections ordered as normalized file specified.
+ uint32_t sectionIndex = 1;
+ for (SectionInfo *si : _sectionInfos) {
+ si->finalSectionIndex = sectionIndex++;
+ }
+ } else {
+ switch (_context.outputMachOType()){
+ case llvm::MachO::MH_EXECUTE:
+ // Main executables, need a zero-page segment
+ segmentForName("__PAGEZERO");
+ // Fall into next case.
+ 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;
+ }
+ // 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++;
+ }
+ }
+ }
+
+}
+
+uint64_t Util::alignTo(uint64_t value, uint8_t align2) {
+ return llvm::RoundUpToAlignment(value, 1 << align2);
+}
+
+
+void Util::layoutSectionsInSegment(SegmentInfo *seg, uint64_t &addr) {
+ seg->address = addr;
+ for (SectionInfo *sect : seg->sections) {
+ sect->address = alignTo(addr, sect->alignment);
+ addr = sect->address + sect->size;
+ }
+ seg->size = llvm::RoundUpToAlignment(addr - seg->address,_context.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 - (1 << sect->alignment));
+ }
+ int64_t padding = taddr - hlcSize;
+ while (padding < 0)
+ padding += _context.pageSize();
+ // Start assigning section address starting at padded offset.
+ addr += (padding + hlcSize);
+ for (SectionInfo *sect : seg->sections) {
+ sect->address = alignTo(addr, sect->alignment);
+ addr = sect->address + sect->size;
+ }
+ seg->size = llvm::RoundUpToAlignment(addr - seg->address,_context.pageSize());
+}
+
+
+void Util::assignAddressesToSections(const NormalizedFile &file) {
+ size_t hlcSize = headerAndLoadCommandsSize(file);
+ uint64_t address = 0;
+ if (_context.outputMachOType() != llvm::MachO::MH_OBJECT) {
+ for (SegmentInfo *seg : _segmentInfos) {
+ if (seg->name.equals("__PAGEZERO")) {
+ seg->size = _context.pageZeroSize();
+ address += seg->size;
+ }
+ else if (seg->name.equals("__TEXT")) {
+ // _context.baseAddress() == 0 implies it was either unspecified or
+ // pageZeroSize is also 0. In either case resetting address is safe.
+ address = _context.baseAddress() ? _context.baseAddress() : address;
+ layoutSectionsInTextSegment(hlcSize, seg, address);
+ } else
+ layoutSectionsInSegment(seg, address);
+
+ address = llvm::RoundUpToAlignment(address, _context.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";
+ }
+ }
+ );
+ } else {
+ for (SectionInfo *sect : _sectionInfos) {
+ sect->address = alignTo(address, sect->alignment);
+ address = sect->address + sect->size;
+ }
+ DEBUG_WITH_TYPE("WriterMachO-norm",
+ llvm::dbgs() << "assignAddressesToSections()\n";
+ for (SectionInfo *si : _sectionInfos) {
+ llvm::dbgs() << " section=" << si->sectionName
+ << " address= " << llvm::format("0x%08X", si->address)
+ << " size= " << llvm::format("0x%08X", si->size)
+ << "\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.access = sgi->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 = (_context.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 (si->type == llvm::MachO::S_ZEROFILL) {
+ const uint8_t *empty = nullptr;
+ normSect->content = llvm::makeArrayRef(empty, si->size);
+ continue;
+ }
+ // Copy content from atoms to content buffer for section.
+ uint8_t *sectionContent = file.ownedAllocations.Allocate<uint8_t>(si->size);
+ normSect->content = llvm::makeArrayRef(sectionContent, si->size);
+ for (AtomInfo &ai : si->atomsAndOffsets) {
+ uint8_t *atomContent = reinterpret_cast<uint8_t*>
+ (&sectionContent[ai.offsetInSection]);
+ _archHandler.generateAtomContent(*ai.atom, r, addrForAtom,
+ sectionAddrForAtom,
+ _context.baseAddress(), atomContent);
+ }
+ }
+}
+
+
+void Util::copySectionInfo(NormalizedFile &file) {
+ file.sections.reserve(_sectionInfos.size());
+ // For final linked images, write sections grouped by segment.
+ if (_context.outputMachOType() != llvm::MachO::MH_OBJECT) {
+ for (SegmentInfo *sgi : _segmentInfos) {
+ for (SectionInfo *si : sgi->sections) {
+ appendSection(si, file);
+ }
+ }
+ } else {
+ // Object files write sections in default order.
+ for (SectionInfo *si : _sectionInfos) {
+ appendSection(si, file);
+ }
+ }
+}
+
+void Util::updateSectionInfo(NormalizedFile &file) {
+ file.sections.reserve(_sectionInfos.size());
+ if (_context.outputMachOType() != llvm::MachO::MH_OBJECT) {
+ // For final linked images, 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;
+ }
+ }
+ } else {
+ // Object files write sections in default order.
+ for (SectionInfo *si : _sectionInfos) {
+ Section *normSect = &file.sections[si->normalizedSectionIndex];
+ normSect->address = si->address;
+ }
+ }
+}
+
+void Util::copyEntryPointAddress(NormalizedFile &nFile) {
+ if (_context.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 = _context.outputTypeHasEntry();
+ for (SectionInfo *sect : _sectionInfos) {
+ for (const AtomInfo &info : sect->atomsAndOffsets) {
+ _atomToAddress[info.atom] = sect->address + info.offsetInSection;
+ if (lookForEntry && (info.atom->contentType() == DefinedAtom::typeCode) &&
+ (info.atom->size() != 0) &&
+ info.atom->name() == _context.entrySymbolName()) {
+ _entryAtom = info.atom;
+ }
+ DEBUG_WITH_TYPE("WriterMachO-address", llvm::dbgs()
+ << " address="
+ << llvm::format("0x%016X", _atomToAddress[info.atom])
+ << " atom=" << info.atom
+ << " name=" << info.atom->name() << "\n");
+ }
+ }
+ for (const Atom *atom : _machHeaderAliasAtoms) {
+ _atomToAddress[atom] = _context.baseAddress();
+ DEBUG_WITH_TYPE("WriterMachO-address", llvm::dbgs()
+ << " address="
+ << llvm::format("0x%016X", _atomToAddress[atom])
+ << " atom=" << atom
+ << " name=" << atom->name() << "\n");
+ }
+}
+
+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 (_archHandler.isThumbFunction(*atom))
+ desc |= N_ARM_THUMB_DEF;
+ if (atom->deadStrip() == DefinedAtom::deadStripNever) {
+ 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);
+}
+
+
+std::error_code Util::getSymbolTableRegion(const DefinedAtom* atom,
+ bool &inGlobalsRegion,
+ SymbolScope &scope) {
+ bool rMode = (_context.outputMachOType() == llvm::MachO::MH_OBJECT);
+ switch (atom->scope()) {
+ case Atom::scopeTranslationUnit:
+ scope = 0;
+ inGlobalsRegion = false;
+ return std::error_code();
+ case Atom::scopeLinkageUnit:
+ if ((_context.exportMode() == MachOLinkingContext::ExportMode::whiteList)
+ && _context.exportSymbolNamed(atom->name())) {
+ return make_dynamic_error_code(Twine("cannot export hidden symbol ")
+ + atom->name());
+ }
+ if (rMode) {
+ if (_context.keepPrivateExterns()) {
+ // -keep_private_externs means keep in globals region as N_PEXT.
+ scope = N_PEXT | N_EXT;
+ inGlobalsRegion = true;
+ return std::error_code();
+ }
+ }
+ // scopeLinkageUnit symbols are no longer global once linked.
+ scope = N_PEXT;
+ inGlobalsRegion = false;
+ return std::error_code();
+ case Atom::scopeGlobal:
+ if (_context.exportRestrictMode()) {
+ if (_context.exportSymbolNamed(atom->name())) {
+ scope = N_EXT;
+ inGlobalsRegion = true;
+ return std::error_code();
+ } else {
+ scope = N_PEXT;
+ inGlobalsRegion = false;
+ return std::error_code();
+ }
+ } else {
+ scope = N_EXT;
+ inGlobalsRegion = true;
+ return std::error_code();
+ }
+ break;
+ }
+ llvm_unreachable("atom->scope() unknown enum value");
+}
+
+std::error_code Util::addSymbols(const lld::File &atomFile,
+ NormalizedFile &file) {
+ bool rMode = (_context.outputMachOType() == llvm::MachO::MH_OBJECT);
+ // Mach-O symbol table has three regions: locals, globals, undefs.
+
+ // 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 = 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 std::error_code();
+}
+
+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 SharedLibraryAtom *slAtom : atomFile.sharedLibrary()) {
+ StringRef loadPath = slAtom->loadName();
+ DylibPathToInfo::iterator pos = _dylibInfo.find(loadPath);
+ if (pos == _dylibInfo.end()) {
+ DylibInfo info;
+ info.ordinal = ordinal++;
+ info.hasWeak = slAtom->canBeNullAtRuntime();
+ info.hasNonWeak = !info.hasWeak;
+ _dylibInfo[loadPath] = info;
+ DependentDylib depInfo;
+ depInfo.path = loadPath;
+ depInfo.kind = llvm::MachO::LC_LOAD_DYLIB;
+ depInfo.currentVersion = _context.dylibCurrentVersion(loadPath);
+ depInfo.compatVersion = _context.dylibCompatVersion(loadPath);
+ nFile.dependentDylibs.push_back(depInfo);
+ } else {
+ if ( slAtom->canBeNullAtRuntime() )
+ pos->second.hasWeak = true;
+ else
+ pos->second.hasNonWeak = true;
+ }
+ }
+ // 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 (_context.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];
+ uint32_t index = 1;
+ for (const SectionInfo *si : _sectionInfos) {
+ if ((si->address <= address) && (address < si->address+si->size))
+ return index;
+ ++index;
+ }
+ llvm_unreachable("atom not in any section");
+}
+
+void Util::addSectionRelocs(const lld::File &, NormalizedFile &file) {
+ if (_context.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) {
+ _archHandler.appendSectionRelocations(*atom, info.offsetInSection, *ref,
+ symIndexForAtom,
+ sectIndexForAtom,
+ addressForAtom,
+ normSect.relocations);
+ }
+ }
+ }
+}
+
+void Util::buildDataInCodeArray(const lld::File &, NormalizedFile &file) {
+ 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 (_context.outputMachOType() == llvm::MachO::MH_OBJECT)
+ return;
+
+ uint8_t segmentIndex;
+ uint64_t segmentStartAddr;
+ 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);
+ }
+ }
+ }
+ }
+}
+
+void Util::addExportInfo(const lld::File &atomFile, NormalizedFile &nFile) {
+ if (_context.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 (_context.exportRestrictMode()) {
+ if (!_context.exportSymbolNamed(atom->name()))
+ continue;
+ }
+ Export exprt;
+ exprt.name = atom->name();
+ exprt.offset = _atomToAddress[atom]; // FIXME: subtract base address
+ 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 (_context.outputMachOType() == MH_OBJECT) {
+ return MH_SUBSECTIONS_VIA_SYMBOLS;
+ } else {
+ if ((_context.outputMachOType() == MH_EXECUTE) && _context.PIE())
+ return MH_DYLDLINK | MH_NOUNDEFS | MH_TWOLEVEL | MH_PIE;
+ else
+ return MH_DYLDLINK | MH_NOUNDEFS | MH_TWOLEVEL;
+ }
+}
+
+} // end anonymous namespace
+
+
+namespace lld {
+namespace mach_o {
+namespace normalized {
+
+/// Convert a set of Atoms into a normalized mach-o file.
+ErrorOr<std::unique_ptr<NormalizedFile>>
+normalizedFromAtoms(const lld::File &atomFile,
+ const MachOLinkingContext &context) {
+ // The util object buffers info until the normalized file can be made.
+ Util util(context);
+ util.assignAtomsToSections(atomFile);
+ util.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.installName = context.installName();
+ normFile.currentVersion = context.currentVersion();
+ normFile.compatVersion = context.compatibilityVersion();
+ normFile.pageSize = context.pageSize();
+ normFile.rpaths = context.rpaths();
+ util.addDependentDylibs(atomFile, normFile);
+ util.copySegmentInfo(normFile);
+ util.copySectionInfo(normFile);
+ util.assignAddressesToSections(normFile);
+ util.buildAtomToAddressMap();
+ util.updateSectionInfo(normFile);
+ util.copySectionContent(normFile);
+ if (auto ec = util.addSymbols(atomFile, normFile)) {
+ return ec;
+ }
+ util.addIndirectSymbols(atomFile, normFile);
+ util.addRebaseAndBindingInfo(atomFile, normFile);
+ util.addExportInfo(atomFile, normFile);
+ util.addSectionRelocs(atomFile, normFile);
+ util.buildDataInCodeArray(atomFile, normFile);
+ util.copyEntryPointAddress(normFile);
+
+ return std::move(f);
+}
+
+
+} // namespace normalized
+} // namespace mach_o
+} // namespace lld
+
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
new file mode 100644
index 000000000000..124e0eaffeeb
--- /dev/null
+++ b/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
@@ -0,0 +1,911 @@
+//===- 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 "MachONormalizedFile.h"
+#include "ArchHandler.h"
+#include "Atoms.h"
+#include "File.h"
+#include "MachONormalizedFileBinaryUtils.h"
+#include "lld/Core/Error.h"
+#include "lld/Core/LLVM.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/MachO.h"
+
+using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
+
+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("", "", 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(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 (section.type == llvm::MachO::S_ZEROFILL) {
+ 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);
+ }
+ }
+}
+
+std::error_code 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 std::error_code();
+
+ 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(0, Reference::kindLayoutAfter, atom, 0,
+ Reference::KindArch::all,
+ Reference::KindNamespace::all);
+ prevAtom = atom;
+ });
+ }
+
+ return std::error_code();
+}
+
+std::error_code 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 make_dynamic_error_code(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 make_dynamic_error_code(Twine(Twine("Section ")
+ + section.segmentName
+ + "/" + section.sectionName
+ + " is malformed. Size of CFI "
+ "starting at offset ("
+ + Twine(offset)
+ + ") is past end of section."));
+ }
+ 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 make_dynamic_error_code(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 std::error_code();
+}
+
+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.
+std::error_code convertRelocs(const Section &section,
+ const NormalizedFile &normalizedFile,
+ bool scatterable,
+ MachOFile &file,
+ ArchHandler &handler) {
+ // Utility function for ArchHandler to find atom by its address.
+ auto atomByAddr = [&] (uint32_t sectIndex, uint64_t addr,
+ const lld::Atom **atom, Reference::Addend *addend)
+ -> std::error_code {
+ if (sectIndex > normalizedFile.sections.size())
+ return make_dynamic_error_code(Twine("out of range section "
+ "index (") + Twine(sectIndex) + ")");
+ const Section *sect = nullptr;
+ if (sectIndex == 0) {
+ sect = findSectionCoveringAddress(normalizedFile, addr);
+ if (!sect)
+ return make_dynamic_error_code(Twine("address (" + Twine(addr)
+ + ") 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 std::error_code();
+ };
+
+ // Utility function for ArchHandler to find atom by its symbol index.
+ auto atomBySymbol = [&] (uint32_t symbolIndex, const lld::Atom **result)
+ -> std::error_code {
+ // Find symbol from index.
+ const Symbol *sym = nullptr;
+ uint32_t numLocal = normalizedFile.localSymbols.size();
+ uint32_t numGlobal = normalizedFile.globalSymbols.size();
+ uint32_t numUndef = normalizedFile.undefinedSymbols.size();
+ if (symbolIndex < numLocal) {
+ sym = &normalizedFile.localSymbols[symbolIndex];
+ } else if (symbolIndex < numLocal+numGlobal) {
+ sym = &normalizedFile.globalSymbols[symbolIndex-numLocal];
+ } else if (symbolIndex < numLocal+numGlobal+numUndef) {
+ sym = &normalizedFile.undefinedSymbols[symbolIndex-numLocal-numGlobal];
+ } else {
+ return make_dynamic_error_code(Twine("symbol index (")
+ + Twine(symbolIndex) + ") out of range");
+ }
+ // Find atom from symbol.
+ if ((sym->type & N_TYPE) == N_SECT) {
+ if (sym->sect > normalizedFile.sections.size())
+ return make_dynamic_error_code(Twine("symbol section index (")
+ + 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 std::error_code();
+ }
+ return make_dynamic_error_code(Twine("no atom found for defined symbol"));
+ } else if ((sym->type & N_TYPE) == N_UNDF) {
+ const lld::Atom *target = file.findUndefAtom(sym->name);
+ if (target) {
+ *result = target;
+ return std::error_code();
+ }
+ return make_dynamic_error_code(Twine("no undefined atom found for sym"));
+ } else {
+ // Search undefs
+ return make_dynamic_error_code(Twine("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 make_dynamic_error_code(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;
+ std::error_code relocErr;
+ if (handler.isPairedReloc(reloc)) {
+ // Handle paired relocations together.
+ relocErr = handler.getPairReferenceInfo(
+ reloc, *++it, inAtom, offsetInAtom, fixupAddress, isBig, scatterable,
+ atomByAddr, atomBySymbol, &kind, &target, &addend);
+ }
+ else {
+ // Use ArchHandler to convert relocation record into information
+ // needed to instantiate an lld::Reference object.
+ relocErr = handler.getReferenceInfo(
+ reloc, inAtom, offsetInAtom, fixupAddress, isBig, atomByAddr,
+ atomBySymbol, &kind, &target, &addend);
+ }
+ if (relocErr) {
+ return make_dynamic_error_code(
+ Twine("bad relocation (") + relocErr.message()
+ + ") in section "
+ + section.segmentName + "/" + section.sectionName
+ + " (r_address=" + Twine::utohexstr(reloc.offset)
+ + ", r_type=" + Twine(reloc.type)
+ + ", r_extern=" + Twine(reloc.isExtern)
+ + ", r_length=" + Twine((int)reloc.length)
+ + ", r_pcrel=" + Twine(reloc.pcRel)
+ + (!reloc.scattered ? (Twine(", r_symbolnum=") + Twine(reloc.symbol))
+ : (Twine(", r_scattered=1, r_value=")
+ + Twine(reloc.value)))
+ + ")" );
+ } else {
+ // Instantiate an lld::Reference object and add to its atom.
+ inAtom->addReference(offsetInAtom, kind, target, addend,
+ handler.kindArch());
+ }
+ }
+
+ return std::error_code();
+}
+
+bool isDebugInfoSection(const Section &section) {
+ if ((section.attributes & S_ATTR_DEBUG) == 0)
+ return false;
+ return section.segmentName.equals("__DWARF");
+}
+
+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;
+}
+
+std::error_code addEHFrameReferences(const NormalizedFile &normalizedFile,
+ MachOFile &file,
+ mach_o::ArchHandler &handler) {
+ const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
+ const bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch);
+
+ const Section *ehFrameSection = nullptr;
+ for (auto &section : normalizedFile.sections)
+ if (section.segmentName == "__TEXT" &&
+ section.sectionName == "__eh_frame") {
+ ehFrameSection = &section;
+ break;
+ }
+
+ // No __eh_frame so nothing to do.
+ if (!ehFrameSection)
+ return std::error_code();
+
+ file.eachAtomInSection(*ehFrameSection,
+ [&](MachODefinedAtom *atom, uint64_t offset) -> void {
+ assert(atom->contentType() == DefinedAtom::typeCFI);
+
+ if (ArchHandler::isDwarfCIE(isBig, atom))
+ return;
+
+ // Compiler wasn't lazy and actually told us what it meant.
+ if (atom->begin() != atom->end())
+ return;
+
+ const uint8_t *frameData = atom->rawContent().data();
+ uint32_t size = read32(frameData, isBig);
+ uint64_t cieFieldInFDE = size == 0xffffffffU
+ ? sizeof(uint32_t) + sizeof(uint64_t)
+ : sizeof(uint32_t);
+
+ // Linker needs to fixup a reference from the FDE to its parent CIE (a
+ // 32-bit byte offset backwards in the __eh_frame section).
+ uint32_t cieDelta = read32(frameData + cieFieldInFDE, isBig);
+ uint64_t cieAddress = ehFrameSection->address + offset + cieFieldInFDE;
+ cieAddress -= cieDelta;
+
+ Reference::Addend addend;
+ const Atom *cie =
+ findAtomCoveringAddress(normalizedFile, file, cieAddress, &addend);
+ atom->addReference(cieFieldInFDE, handler.unwindRefToCIEKind(), cie,
+ addend, handler.kindArch());
+
+ // Linker needs to fixup reference from the FDE to the function it's
+ // describing. FIXME: there are actually different ways to do this, and the
+ // particular method used is specified in the CIE's augmentation fields
+ // (hopefully)
+ uint64_t rangeFieldInFDE = cieFieldInFDE + sizeof(uint32_t);
+
+ int64_t functionFromFDE = readSPtr(is64, isBig, frameData + rangeFieldInFDE);
+ uint64_t rangeStart = ehFrameSection->address + offset + rangeFieldInFDE;
+ rangeStart += functionFromFDE;
+
+ const Atom *func =
+ findAtomCoveringAddress(normalizedFile, file, rangeStart, &addend);
+ atom->addReference(rangeFieldInFDE, handler.unwindRefToFunctionKind(), func,
+ addend, handler.kindArch());
+ });
+ return std::error_code();
+}
+
+
+/// Converts normalized mach-o file into an lld::File and lld::Atoms.
+ErrorOr<std::unique_ptr<lld::File>>
+objectToAtoms(const NormalizedFile &normalizedFile, StringRef path,
+ bool copyRefs) {
+ std::unique_ptr<MachOFile> file(new MachOFile(path));
+ if (std::error_code ec = normalizedObjectToAtoms(
+ file.get(), normalizedFile, copyRefs))
+ return ec;
+ return std::unique_ptr<File>(std::move(file));
+}
+
+ErrorOr<std::unique_ptr<lld::File>>
+dylibToAtoms(const NormalizedFile &normalizedFile, StringRef path,
+ bool copyRefs) {
+ // Instantiate SharedLibraryFile object.
+ std::unique_ptr<MachODylibFile> file(new MachODylibFile(path));
+ normalizedDylibToAtoms(file.get(), normalizedFile, copyRefs);
+ return std::unique_ptr<File>(std::move(file));
+}
+
+} // anonymous namespace
+
+namespace normalized {
+
+std::error_code
+normalizedObjectToAtoms(MachOFile *file,
+ const NormalizedFile &normalizedFile,
+ bool copyRefs) {
+ bool scatterable = ((normalizedFile.flags & MH_SUBSECTIONS_VIA_SYMBOLS) != 0);
+
+ // Create atoms from each section.
+ for (auto &sect : normalizedFile.sections) {
+ if (isDebugInfoSection(sect))
+ continue;
+ bool customSectionName;
+ DefinedAtom::ContentType atomType = atomTypeFromSection(sect,
+ customSectionName);
+ if (std::error_code 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(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 (std::error_code 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 (std::error_code 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 make_dynamic_error_code(Twine("LC_DATA_IN_CODE address ("
+ + Twine(entry.offset)
+ + ") is not in any section"));
+ }
+ uint64_t offsetInSect = entry.offset - s->address;
+ uint32_t offsetInAtom;
+ MachODefinedAtom *atom = file->findAtomCoveringAddress(*s, offsetInSect,
+ &offsetInAtom);
+ if (offsetInAtom + entry.length > atom->size()) {
+ return make_dynamic_error_code(Twine("LC_DATA_IN_CODE entry (offset="
+ + Twine(entry.offset)
+ + ", length="
+ + Twine(entry.length)
+ + ") crosses atom boundary."));
+ }
+ // Add reference that marks start of data-in-code.
+ atom->addReference(offsetInAtom,
+ handler->dataInCodeTransitionStart(*atom), atom,
+ entry.kind, handler->kindArch());
+
+ // 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(offsetInAtom+entry.length,
+ handler->dataInCodeTransitionEnd(*atom), atom, 0,
+ handler->kindArch());
+ }
+
+ // Sort references in each atom to their canonical order.
+ for (const DefinedAtom* defAtom : file->defined()) {
+ reinterpret_cast<const SimpleDefinedAtom*>(defAtom)->sortReferences();
+ }
+ return std::error_code();
+}
+
+std::error_code
+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 std::error_code();
+}
+
+void relocatableSectionInfoForContentType(DefinedAtom::ContentType atomType,
+ StringRef &segmentName,
+ StringRef &sectionName,
+ SectionType &sectionType,
+ SectionAttr &sectionAttrs) {
+
+ 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;
+ if (atomType == DefinedAtom::typeCode)
+ sectionAttrs = S_ATTR_PURE_INSTRUCTIONS;
+ return;
+ }
+ llvm_unreachable("content type not yet supported");
+}
+
+ErrorOr<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/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp
new file mode 100644
index 000000000000..ae14d755e2b9
--- /dev/null
+++ b/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp
@@ -0,0 +1,802 @@
+//===- 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/Core/Error.h"
+#include "lld/Core/LLVM.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/Support/Casting.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/MachO.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(StringRef)
+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);
+ }
+};
+
+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, 0U);
+ io.mapRequired("address", sect.address);
+ if (sect.type == llvm::MachO::S_ZEROFILL) {
+ // 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();
+ 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 bool mustQuote(StringRef) { return false; }
+};
+
+
+template <>
+struct MappingTraits<Segment> {
+ static void mapping(IO &io, Segment& seg) {
+ io.mapRequired("name", seg.name);
+ io.mapRequired("address", seg.address);
+ io.mapRequired("size", seg.size);
+ io.mapRequired("access", seg.access);
+ }
+};
+
+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);
+ }
+};
+
+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 bool mustQuote(StringRef) { return false; }
+};
+
+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("source-version", file.sourceVersion, Hex64(0));
+ io.mapOptional("OS", file.os);
+ io.mapOptional("min-os-version", file.minOSverson, PackedVersion(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.
+ ErrorOr<std::unique_ptr<lld::File>> foe = normalizedToAtoms(nf, info->_path,
+ true);
+ 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;
+
+ if (foe) {
+ // Transfer ownership to "out" File parameter.
+ std::unique_ptr<lld::File> f = std::move(foe.get());
+ file = f.release();
+ return true;
+ } else {
+ io.setError(foe.getError().message());
+ return false;
+ }
+}
+
+
+
+namespace normalized {
+
+/// Parses a yaml encoded mach-o file to produce an in-memory normalized view.
+ErrorOr<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 (yin.error())
+ return make_error_code(lld::YamlReaderError::illegal_value);
+
+ // 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/lib/ReaderWriter/MachO/MachOPasses.h b/lib/ReaderWriter/MachO/MachOPasses.h
new file mode 100644
index 000000000000..86f4bc0f5d54
--- /dev/null
+++ b/lib/ReaderWriter/MachO/MachOPasses.h
@@ -0,0 +1,28 @@
+//===- 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 addCompactUnwindPass(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/lib/ReaderWriter/MachO/Makefile b/lib/ReaderWriter/MachO/Makefile
new file mode 100644
index 000000000000..1acd578ba9d3
--- /dev/null
+++ b/lib/ReaderWriter/MachO/Makefile
@@ -0,0 +1,14 @@
+##===- lld/lib/ReaderWriter/MachO/Makefile --------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLD_LEVEL := ../../..
+LIBRARYNAME := lldMachO
+USEDLIBS = lldCore.a
+
+include $(LLD_LEVEL)/Makefile
diff --git a/lib/ReaderWriter/MachO/ShimPass.cpp b/lib/ReaderWriter/MachO/ShimPass.cpp
new file mode 100644
index 000000000000..a8c69f8ceace
--- /dev/null
+++ b/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/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/Simple.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
+
+namespace lld {
+namespace mach_o {
+
+class ShimPass : public Pass {
+public:
+ ShimPass(const MachOLinkingContext &context)
+ : _context(context)
+ , _archHandler(_context.archHandler())
+ , _stubInfo(_archHandler.stubInfo())
+ , _file("<mach-o shim pass>") {
+ }
+
+
+ void perform(std::unique_ptr<MutableFile> &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;
+
+ // 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);
+ }
+ }
+
+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 &_context;
+ 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/lib/ReaderWriter/MachO/StubsPass.cpp b/lib/ReaderWriter/MachO/StubsPass.cpp
new file mode 100644
index 000000000000..bc4d9c2087f3
--- /dev/null
+++ b/lib/ReaderWriter/MachO/StubsPass.cpp
@@ -0,0 +1,373 @@
+//===- lib/ReaderWriter/MachO/StubsPass.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 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/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/Simple.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/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) { }
+
+ ContentType contentType() const override {
+ return DefinedAtom::typeLazyPointer;
+ }
+
+ Alignment alignment() const override {
+ return Alignment(_is64 ? 3 : 2);
+ }
+
+ 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)
+ : SimpleDefinedAtom(file), _is64(is64) { }
+
+ ContentType contentType() const override {
+ return DefinedAtom::typeGOT;
+ }
+
+ Alignment alignment() const override {
+ return Alignment(_is64 ? 3 : 2);
+ }
+
+ 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;
+};
+
+
+
+//
+// Stub Atom created by the stubs pass.
+//
+class StubAtom : public SimpleDefinedAtom {
+public:
+ StubAtom(const File &file, const ArchHandler::StubInfo &stubInfo)
+ : SimpleDefinedAtom(file), _stubInfo(stubInfo){ }
+
+ ContentType contentType() const override {
+ return DefinedAtom::typeStub;
+ }
+
+ Alignment alignment() const override {
+ return Alignment(_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) { }
+
+ ContentType contentType() const override {
+ return DefinedAtom::typeStubHelper;
+ }
+
+ Alignment alignment() const override {
+ return Alignment(_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) { }
+
+ ContentType contentType() const override {
+ return DefinedAtom::typeStubHelper;
+ }
+
+ Alignment alignment() const override {
+ return Alignment(_stubInfo.codeAlignment);
+ }
+
+ 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)
+ : _context(context), _archHandler(_context.archHandler()),
+ _stubInfo(_archHandler.stubInfo()), _file("<mach-o Stubs pass>") { }
+
+
+ void perform(std::unique_ptr<MutableFile> &mergedFile) override {
+ // Skip this pass if output format uses text relocations instead of stubs.
+ if (!this->noTextRelocs())
+ return;
+
+ // 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;
+
+ // First add help-common and GOT slots used by lazy binding.
+ SimpleDefinedAtom *helperCommonAtom =
+ new (_file.allocator()) StubHelperCommonAtom(_file, _stubInfo);
+ SimpleDefinedAtom *helperCacheNLPAtom =
+ new (_file.allocator()) NonLazyPointerAtom(_file, _context.is64Bit());
+ SimpleDefinedAtom *helperBinderNLPAtom =
+ new (_file.allocator()) NonLazyPointerAtom(_file, _context.is64Bit());
+ 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) {
+ StubAtom *stub = new (_file.allocator()) StubAtom(_file, _stubInfo);
+ LazyPointerAtom *lp =
+ new (_file.allocator()) LazyPointerAtom(_file, _context.is64Bit());
+ StubHelperAtom *helper =
+ new (_file.allocator()) StubHelperAtom(_file, _stubInfo);
+
+ 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;
+ }
+ }
+
+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 &_context;
+ 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/lib/ReaderWriter/MachO/WriterMachO.cpp b/lib/ReaderWriter/MachO/WriterMachO.cpp
new file mode 100644
index 000000000000..de1c0e38063b
--- /dev/null
+++ b/lib/ReaderWriter/MachO/WriterMachO.cpp
@@ -0,0 +1,72 @@
+//===- 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.hpp"
+#include "MachONormalizedFile.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Writer.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/MachO.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) : _context(ctxt) { }
+
+ std::error_code writeFile(const lld::File &file, StringRef path) override {
+ // Construct empty normalized file from atoms.
+ ErrorOr<std::unique_ptr<NormalizedFile>> nFile =
+ normalized::normalizedFromAtoms(file, _context);
+ if (std::error_code ec = nFile.getError())
+ return ec;
+
+ // For testing, write out yaml form of normalized file.
+ if (_context.printAtoms()) {
+ std::unique_ptr<Writer> yamlWriter = createWriterYAML(_context);
+ yamlWriter->writeFile(file, "-");
+ }
+
+ // Write normalized file as mach-o binary.
+ return writeBinary(*nFile->get(), path);
+ }
+
+ bool createImplicitFiles(std::vector<std::unique_ptr<File> > &r) override {
+ // When building main executables, add _main as required entry point.
+ if (_context.outputTypeHasEntry())
+ r.emplace_back(new CEntryFile(_context));
+ // If this can link with dylibs, need helper function (dyld_stub_binder).
+ if (_context.needsStubsPass())
+ r.emplace_back(new StubHelperFile(_context));
+ // Final linked images can access a symbol for their mach_header.
+ if (_context.outputMachOType() != llvm::MachO::MH_OBJECT)
+ r.emplace_back(new MachHeaderAliasFile(_context));
+
+ return true;
+ }
+private:
+ const MachOLinkingContext &_context;
+ };
+
+
+} // 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/lib/ReaderWriter/Makefile b/lib/ReaderWriter/Makefile
new file mode 100644
index 000000000000..23587440805f
--- /dev/null
+++ b/lib/ReaderWriter/Makefile
@@ -0,0 +1,16 @@
+##===- lld/lib/ReaderWriter/Makefile ---------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLD_LEVEL := ../..
+LIBRARYNAME := lldReaderWriter
+
+# these link against this lib
+PARALLEL_DIRS := ELF MachO Native PECOFF YAML
+
+include $(LLD_LEVEL)/Makefile
diff --git a/lib/ReaderWriter/Native/CMakeLists.txt b/lib/ReaderWriter/Native/CMakeLists.txt
new file mode 100644
index 000000000000..e15f3d60e89c
--- /dev/null
+++ b/lib/ReaderWriter/Native/CMakeLists.txt
@@ -0,0 +1,7 @@
+add_llvm_library(lldNative
+ ReaderNative.cpp
+ WriterNative.cpp
+ LINK_LIBS
+ lldCore
+ LLVMSupport
+ )
diff --git a/lib/ReaderWriter/Native/Makefile b/lib/ReaderWriter/Native/Makefile
new file mode 100644
index 000000000000..6aba37868900
--- /dev/null
+++ b/lib/ReaderWriter/Native/Makefile
@@ -0,0 +1,14 @@
+##===- lld/lib/ReaderWriter/Native/Makefile --------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLD_LEVEL := ../../..
+LIBRARYNAME := lldNative
+USEDLIBS = lldCore.a
+
+include $(LLD_LEVEL)/Makefile
diff --git a/lib/ReaderWriter/Native/NativeFileFormat.h b/lib/ReaderWriter/Native/NativeFileFormat.h
new file mode 100644
index 000000000000..535072fe2314
--- /dev/null
+++ b/lib/ReaderWriter/Native/NativeFileFormat.h
@@ -0,0 +1,258 @@
+//===- lib/ReaderWriter/Native/NativeFileFormat.h -------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_NATIVE_NATIVE_FILE_FORMAT_H
+#define LLD_READER_WRITER_NATIVE_NATIVE_FILE_FORMAT_H
+
+#include "llvm/Support/DataTypes.h"
+#include <cstdint>
+
+namespace lld {
+
+//
+// Overview:
+//
+// The number one design goal of this file format is enable the linker to
+// read object files into in-memory Atom objects extremely quickly.
+// The second design goal is to enable future modifications to the
+// Atom attribute model.
+//
+// The llvm native object file format is not like traditional object file
+// formats (e.g. ELF, COFF, mach-o). There is no symbol table and no
+// sections. Instead the file is essentially an array of archived Atoms.
+// It is *not* serialized Atoms which would require deserialization into
+// in memory objects. Instead it is an array of read-only info about each
+// Atom. The NativeReader bulk creates in-memory Atoms which just have
+// an ivar which points to the read-only info for that Atom. No additional
+// processing is done to construct the in-memory Atoms. All Atom attribute
+// getter methods are virtual calls which dig up the info they need from the
+// ivar data.
+//
+// To support the gradual evolution of Atom attributes, the Atom read-only
+// data is versioned. The NativeReader chooses which in-memory Atom class
+// to use based on the version. What this means is that if new attributes
+// are added (or changed) in the Atom model, a new native atom class and
+// read-only atom info struct needs to be defined. Then, all the existing
+// native reader atom classes need to be modified to do their best effort
+// to map their old style read-only data to the new Atom model. At some point
+// some classes to support old versions may be dropped.
+//
+//
+// Details:
+//
+// The native object file format consists of a header that specifies the
+// endianness of the file and the architecture along with a list of "chunks"
+// in the file. A Chunk is simply a tagged range of the file. There is
+// one chunk for the array of atom infos. There is another chunk for the
+// string pool, and another for the content pool.
+//
+// It turns out there most atoms have very similar sets of attributes, only
+// the name and content attribute vary. To exploit this fact to reduce the file
+// size, the atom read-only info contains just the name and content info plus
+// a reference to which attribute set it uses. The attribute sets are stored
+// in another chunk.
+//
+
+
+//
+// An entry in the NativeFileHeader that describes one chunk of the file.
+//
+struct NativeChunk {
+ uint32_t signature;
+ uint32_t fileOffset;
+ uint32_t fileSize;
+ uint32_t elementCount;
+};
+
+
+//
+// The header in a native object file
+//
+struct NativeFileHeader {
+ uint8_t magic[16];
+ uint32_t endian;
+ uint32_t architecture;
+ uint32_t fileSize;
+ uint32_t chunkCount;
+ // NativeChunk chunks[]
+};
+
+//
+// Possible values for NativeChunk.signature field
+//
+enum NativeChunkSignatures {
+ NCS_DefinedAtomsV1 = 1,
+ NCS_AttributesArrayV1 = 2,
+ NCS_AbsoluteAttributesV1 = 12,
+ NCS_UndefinedAtomsV1 = 3,
+ NCS_SharedLibraryAtomsV1 = 4,
+ NCS_AbsoluteAtomsV1 = 5,
+ NCS_Strings = 6,
+ NCS_ReferencesArrayV1 = 7,
+ NCS_ReferencesArrayV2 = 8,
+ NCS_TargetsTable = 9,
+ NCS_AddendsTable = 10,
+ NCS_Content = 11,
+};
+
+//
+// The 16-bytes at the start of a native object file
+//
+#define NATIVE_FILE_HEADER_MAGIC "llvm nat obj v1 "
+
+//
+// Possible values for the NativeFileHeader.endian field
+//
+enum {
+ NFH_BigEndian = 0x42696745,
+ NFH_LittleEndian = 0x4574696c
+};
+
+
+//
+// Possible values for the NativeFileHeader.architecture field
+//
+enum {
+ NFA_x86 = 1,
+ NFA_x86_64 = 2,
+ NFA_armv6 = 3,
+ NFA_armv7 = 4,
+};
+
+
+//
+// The NCS_DefinedAtomsV1 chunk contains an array of these structs
+//
+struct NativeDefinedAtomIvarsV1 {
+ uint32_t nameOffset;
+ uint32_t attributesOffset;
+ uint32_t referencesStartIndex;
+ uint32_t referencesCount;
+ uint32_t contentOffset;
+ uint32_t contentSize;
+ uint64_t sectionSize;
+};
+
+
+//
+// The NCS_AttributesArrayV1 chunk contains an array of these structs
+//
+struct NativeAtomAttributesV1 {
+ uint32_t sectionNameOffset;
+ uint16_t align2;
+ uint16_t alignModulus;
+ uint8_t scope;
+ uint8_t interposable;
+ uint8_t merge;
+ uint8_t contentType;
+ uint8_t sectionChoice;
+ uint8_t deadStrip;
+ uint8_t dynamicExport;
+ uint8_t permissions;
+ uint8_t alias;
+ uint8_t codeModel;
+};
+
+
+
+//
+// The NCS_UndefinedAtomsV1 chunk contains an array of these structs
+//
+struct NativeUndefinedAtomIvarsV1 {
+ uint32_t nameOffset;
+ uint32_t flags;
+ uint32_t fallbackNameOffset;
+};
+
+
+//
+// The NCS_SharedLibraryAtomsV1 chunk contains an array of these structs
+//
+struct NativeSharedLibraryAtomIvarsV1 {
+ uint64_t size;
+ uint32_t nameOffset;
+ uint32_t loadNameOffset;
+ uint32_t type;
+ uint32_t flags;
+};
+
+
+
+//
+// The NCS_AbsoluteAtomsV1 chunk contains an array of these structs
+//
+struct NativeAbsoluteAtomIvarsV1 {
+ uint32_t nameOffset;
+ uint32_t attributesOffset;
+ uint32_t reserved;
+ uint64_t value;
+};
+
+
+
+//
+// The NCS_ReferencesArrayV1 chunk contains an array of these structs
+//
+struct NativeReferenceIvarsV1 {
+ enum {
+ noTarget = UINT16_MAX
+ };
+ uint32_t offsetInAtom;
+ uint16_t kindValue;
+ uint8_t kindNamespace;
+ uint8_t kindArch;
+ uint16_t targetIndex;
+ uint16_t addendIndex;
+};
+
+
+//
+// The NCS_ReferencesArrayV2 chunk contains an array of these structs
+//
+struct NativeReferenceIvarsV2 {
+ enum : unsigned {
+ noTarget = UINT32_MAX
+ };
+ uint64_t offsetInAtom;
+ int64_t addend;
+ uint16_t kindValue;
+ uint8_t kindNamespace;
+ uint8_t kindArch;
+ uint32_t targetIndex;
+ uint32_t tag;
+};
+
+
+//
+// The NCS_TargetsTable chunk contains an array of uint32_t entries.
+// The C++ class Reference has a target() method that returns a
+// pointer to another Atom. We can't have pointers in object files,
+// so instead NativeReferenceIvarsV1 contains an index to the target.
+// The index is into this NCS_TargetsTable of uint32_t entries.
+// The values in this table are the index of the (target) atom in this file.
+// For DefinedAtoms the value is from 0 to NCS_DefinedAtomsV1.elementCount.
+// For UndefinedAtoms the value is from NCS_DefinedAtomsV1.elementCount to
+// NCS_DefinedAtomsV1.elementCount+NCS_UndefinedAtomsV1.elementCount.
+//
+
+
+//
+// The NCS_AddendsTable chunk contains an array of int64_t entries.
+// If we allocated space for addends directly in NativeReferenceIvarsV1
+// it would double the size of that struct. But since addends are rare,
+// we instead just keep a pool of addends and have NativeReferenceIvarsV1
+// (if it needs an addend) just store the index (into the pool) of the
+// addend it needs.
+//
+
+
+
+} // namespace lld
+
+#endif // LLD_READER_WRITER_NATIVE_NATIVE_FILE_FORMAT_H
diff --git a/lib/ReaderWriter/Native/ReaderNative.cpp b/lib/ReaderWriter/Native/ReaderNative.cpp
new file mode 100644
index 000000000000..84cdb4b997e8
--- /dev/null
+++ b/lib/ReaderWriter/Native/ReaderNative.cpp
@@ -0,0 +1,1013 @@
+//===- lib/ReaderWriter/Native/ReaderNative.cpp ---------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeFileFormat.h"
+#include "lld/Core/Atom.h"
+#include "lld/Core/Error.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Reader.h"
+#include "lld/Core/Simple.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <memory>
+#include <vector>
+
+namespace lld {
+namespace native {
+
+// forward reference
+class File;
+
+//
+// An object of this class is instantied for each NativeDefinedAtomIvarsV1
+// struct in the NCS_DefinedAtomsV1 chunk.
+//
+class NativeDefinedAtomV1 : public DefinedAtom {
+public:
+ NativeDefinedAtomV1(const File& f,
+ const NativeDefinedAtomIvarsV1* ivarData)
+ : _file(&f), _ivarData(ivarData) { }
+
+ const lld::File& file() const override;
+
+ uint64_t ordinal() const override;
+
+ StringRef name() const override;
+
+ uint64_t size() const override { return _ivarData->contentSize; }
+
+ uint64_t sectionSize() const override { return _ivarData->sectionSize; }
+
+ DefinedAtom::Scope scope() const override {
+ return (DefinedAtom::Scope)(attributes().scope);
+ }
+
+ DefinedAtom::Interposable interposable() const override {
+ return (DefinedAtom::Interposable)(attributes().interposable);
+ }
+
+ DefinedAtom::Merge merge() const override {
+ return (DefinedAtom::Merge)(attributes().merge);
+ }
+
+ DefinedAtom::ContentType contentType() const override {
+ const NativeAtomAttributesV1& attr = attributes();
+ return (DefinedAtom::ContentType)(attr.contentType);
+ }
+
+ DefinedAtom::Alignment alignment() const override {
+ return DefinedAtom::Alignment(attributes().align2, attributes().alignModulus);
+ }
+
+ DefinedAtom::SectionChoice sectionChoice() const override {
+ return (DefinedAtom::SectionChoice)(attributes().sectionChoice);
+ }
+
+ StringRef customSectionName() const override;
+
+ DefinedAtom::DeadStripKind deadStrip() const override {
+ return (DefinedAtom::DeadStripKind)(attributes().deadStrip);
+ }
+
+ DynamicExport dynamicExport() const override {
+ return (DynamicExport)attributes().dynamicExport;
+ }
+
+ DefinedAtom::CodeModel codeModel() const override {
+ return DefinedAtom::CodeModel(attributes().codeModel);
+ }
+
+ DefinedAtom::ContentPermissions permissions() const override {
+ return (DefinedAtom::ContentPermissions)(attributes().permissions);
+ }
+
+ ArrayRef<uint8_t> rawContent() const override;
+
+ reference_iterator begin() const override;
+
+ reference_iterator end() const override;
+
+ const Reference* derefIterator(const void*) const override;
+
+ void incrementIterator(const void*& it) const override;
+
+private:
+ const NativeAtomAttributesV1& attributes() const;
+
+ const File *_file;
+ const NativeDefinedAtomIvarsV1 *_ivarData;
+};
+
+
+
+//
+// An object of this class is instantied for each NativeUndefinedAtomIvarsV1
+// struct in the NCS_UndefinedAtomsV1 chunk.
+//
+class NativeUndefinedAtomV1 : public UndefinedAtom {
+public:
+ NativeUndefinedAtomV1(const File& f,
+ const NativeUndefinedAtomIvarsV1* ivarData)
+ : _file(&f), _ivarData(ivarData) { }
+
+ const lld::File& file() const override;
+ StringRef name() const override;
+
+ CanBeNull canBeNull() const override {
+ return (CanBeNull)(_ivarData->flags & 0x3);
+ }
+
+ const UndefinedAtom *fallback() const override;
+
+private:
+ const File *_file;
+ const NativeUndefinedAtomIvarsV1 *_ivarData;
+ mutable std::unique_ptr<const SimpleUndefinedAtom> _fallback;
+};
+
+
+//
+// An object of this class is instantied for each NativeUndefinedAtomIvarsV1
+// struct in the NCS_SharedLibraryAtomsV1 chunk.
+//
+class NativeSharedLibraryAtomV1 : public SharedLibraryAtom {
+public:
+ NativeSharedLibraryAtomV1(const File& f,
+ const NativeSharedLibraryAtomIvarsV1* ivarData)
+ : _file(&f), _ivarData(ivarData) { }
+
+ const lld::File& file() const override;
+ StringRef name() const override;
+ StringRef loadName() const override;
+
+ bool canBeNullAtRuntime() const override {
+ return (_ivarData->flags & 0x1);
+ }
+
+ Type type() const override {
+ return (Type)_ivarData->type;
+ }
+
+ uint64_t size() const override {
+ return _ivarData->size;
+ }
+
+private:
+ const File *_file;
+ const NativeSharedLibraryAtomIvarsV1 *_ivarData;
+};
+
+
+//
+// An object of this class is instantied for each NativeAbsoluteAtomIvarsV1
+// struct in the NCS_AbsoluteAtomsV1 chunk.
+//
+class NativeAbsoluteAtomV1 : public AbsoluteAtom {
+public:
+ NativeAbsoluteAtomV1(const File& f,
+ const NativeAbsoluteAtomIvarsV1* ivarData)
+ : _file(&f), _ivarData(ivarData) { }
+
+ const lld::File& file() const override;
+ StringRef name() const override;
+ Scope scope() const override {
+ const NativeAtomAttributesV1& attr = absAttributes();
+ return (Scope)(attr.scope);
+ }
+ uint64_t value() const override {
+ return _ivarData->value;
+ }
+
+private:
+ const NativeAtomAttributesV1& absAttributes() const;
+ const File *_file;
+ const NativeAbsoluteAtomIvarsV1 *_ivarData;
+};
+
+
+//
+// An object of this class is instantied for each NativeReferenceIvarsV1
+// struct in the NCS_ReferencesArrayV1 chunk.
+//
+class NativeReferenceV1 : public Reference {
+public:
+ NativeReferenceV1(const File &f, const NativeReferenceIvarsV1 *ivarData)
+ : Reference((KindNamespace)ivarData->kindNamespace,
+ (KindArch)ivarData->kindArch, ivarData->kindValue),
+ _file(&f), _ivarData(ivarData) {}
+
+ uint64_t offsetInAtom() const override {
+ return _ivarData->offsetInAtom;
+ }
+
+ const Atom* target() const override;
+ Addend addend() const override;
+ void setTarget(const Atom* newAtom) override;
+ void setAddend(Addend a) override;
+
+private:
+ const File *_file;
+ const NativeReferenceIvarsV1 *_ivarData;
+};
+
+
+//
+// An object of this class is instantied for each NativeReferenceIvarsV1
+// struct in the NCS_ReferencesArrayV1 chunk.
+//
+class NativeReferenceV2 : public Reference {
+public:
+ NativeReferenceV2(const File &f, const NativeReferenceIvarsV2 *ivarData)
+ : Reference((KindNamespace)ivarData->kindNamespace,
+ (KindArch)ivarData->kindArch, ivarData->kindValue),
+ _file(&f), _ivarData(ivarData) {}
+
+ uint64_t offsetInAtom() const override {
+ return _ivarData->offsetInAtom;
+ }
+
+ const Atom* target() const override;
+ Addend addend() const override;
+ void setTarget(const Atom* newAtom) override;
+ void setAddend(Addend a) override;
+ uint32_t tag() const override;
+
+private:
+ const File *_file;
+ const NativeReferenceIvarsV2 *_ivarData;
+};
+
+
+//
+// lld::File object for native llvm object file
+//
+class File : public lld::File {
+public:
+ File(std::unique_ptr<MemoryBuffer> mb)
+ : lld::File(mb->getBufferIdentifier(), kindObject),
+ _mb(std::move(mb)), // Reader now takes ownership of buffer
+ _header(nullptr), _targetsTable(nullptr), _targetsTableCount(0),
+ _strings(nullptr), _stringsMaxOffset(0), _addends(nullptr),
+ _addendsMaxIndex(0), _contentStart(nullptr), _contentEnd(nullptr) {
+ _header =
+ reinterpret_cast<const NativeFileHeader *>(_mb->getBufferStart());
+ }
+
+ /// Parses a File object from a native object file.
+ std::error_code doParse() override {
+ const uint8_t *const base =
+ reinterpret_cast<const uint8_t *>(_mb->getBufferStart());
+ StringRef path(_mb->getBufferIdentifier());
+ const NativeFileHeader *const header =
+ reinterpret_cast<const NativeFileHeader *>(base);
+ const NativeChunk *const chunks =
+ reinterpret_cast<const NativeChunk *>(base + sizeof(NativeFileHeader));
+ // make sure magic matches
+ if (memcmp(header->magic, NATIVE_FILE_HEADER_MAGIC,
+ sizeof(header->magic)) != 0)
+ return make_error_code(NativeReaderError::unknown_file_format);
+
+ // make sure mapped file contains all needed data
+ const size_t fileSize = _mb->getBufferSize();
+ if (header->fileSize > fileSize)
+ return make_error_code(NativeReaderError::file_too_short);
+
+ DEBUG_WITH_TYPE("ReaderNative",
+ llvm::dbgs() << " Native File Header:" << " fileSize="
+ << header->fileSize << " chunkCount="
+ << header->chunkCount << "\n");
+
+ // process each chunk
+ for (uint32_t i = 0; i < header->chunkCount; ++i) {
+ std::error_code ec;
+ const NativeChunk* chunk = &chunks[i];
+ // sanity check chunk is within file
+ if ( chunk->fileOffset > fileSize )
+ return make_error_code(NativeReaderError::file_malformed);
+ if ( (chunk->fileOffset + chunk->fileSize) > fileSize)
+ return make_error_code(NativeReaderError::file_malformed);
+ // process chunk, based on signature
+ switch ( chunk->signature ) {
+ case NCS_DefinedAtomsV1:
+ ec = processDefinedAtomsV1(base, chunk);
+ break;
+ case NCS_AttributesArrayV1:
+ ec = processAttributesV1(base, chunk);
+ break;
+ case NCS_UndefinedAtomsV1:
+ ec = processUndefinedAtomsV1(base, chunk);
+ break;
+ case NCS_SharedLibraryAtomsV1:
+ ec = processSharedLibraryAtomsV1(base, chunk);
+ break;
+ case NCS_AbsoluteAtomsV1:
+ ec = processAbsoluteAtomsV1(base, chunk);
+ break;
+ case NCS_AbsoluteAttributesV1:
+ ec = processAbsoluteAttributesV1(base, chunk);
+ break;
+ case NCS_ReferencesArrayV1:
+ ec = processReferencesV1(base, chunk);
+ break;
+ case NCS_ReferencesArrayV2:
+ ec = processReferencesV2(base, chunk);
+ break;
+ case NCS_TargetsTable:
+ ec = processTargetsTable(base, chunk);
+ break;
+ case NCS_AddendsTable:
+ ec = processAddendsTable(base, chunk);
+ break;
+ case NCS_Content:
+ ec = processContent(base, chunk);
+ break;
+ case NCS_Strings:
+ ec = processStrings(base, chunk);
+ break;
+ default:
+ return make_error_code(NativeReaderError::unknown_chunk_type);
+ }
+ if ( ec ) {
+ return ec;
+ }
+ }
+ // TO DO: validate enough chunks were used
+
+ DEBUG_WITH_TYPE("ReaderNative", {
+ llvm::dbgs() << " ReaderNative DefinedAtoms:\n";
+ for (const DefinedAtom *a : defined()) {
+ llvm::dbgs() << llvm::format(" 0x%09lX", a)
+ << ", name=" << a->name()
+ << ", size=" << a->size() << "\n";
+ for (const Reference *r : *a) {
+ llvm::dbgs() << " offset="
+ << llvm::format("0x%03X", r->offsetInAtom())
+ << ", kind=" << r->kindValue()
+ << ", target=" << r->target() << "\n";
+ }
+ }
+ });
+ return make_error_code(NativeReaderError::success);
+ }
+
+ virtual ~File() {
+ // _mb is automatically deleted because of std::unique_ptr<>
+
+ // All other ivar pointers are pointers into the MemoryBuffer, except
+ // the _definedAtoms array which was allocated to contain an array
+ // of Atom objects. The atoms have empty destructors, so it is ok
+ // to just delete the memory.
+ delete _definedAtoms._arrayStart;
+ delete _undefinedAtoms._arrayStart;
+ delete _sharedLibraryAtoms._arrayStart;
+ delete _absoluteAtoms._arrayStart;
+ delete _referencesV1.arrayStart;
+ delete _referencesV2.arrayStart;
+ delete [] _targetsTable;
+ }
+
+ const atom_collection<DefinedAtom>& defined() const override {
+ return _definedAtoms;
+ }
+ const atom_collection<UndefinedAtom>& undefined() const override {
+ return _undefinedAtoms;
+ }
+ const atom_collection<SharedLibraryAtom>& sharedLibrary() const override {
+ return _sharedLibraryAtoms;
+ }
+ const atom_collection<AbsoluteAtom> &absolute() const override {
+ return _absoluteAtoms;
+ }
+
+private:
+ friend NativeDefinedAtomV1;
+ friend NativeUndefinedAtomV1;
+ friend NativeSharedLibraryAtomV1;
+ friend NativeAbsoluteAtomV1;
+ friend NativeReferenceV1;
+ friend NativeReferenceV2;
+
+ // instantiate array of DefinedAtoms from v1 ivar data in file
+ std::error_code processDefinedAtomsV1(const uint8_t *base,
+ const NativeChunk *chunk) {
+ const size_t atomSize = sizeof(NativeDefinedAtomV1);
+ size_t atomsArraySize = chunk->elementCount * atomSize;
+ uint8_t* atomsStart = reinterpret_cast<uint8_t*>
+ (operator new(atomsArraySize, std::nothrow));
+ if (atomsStart == nullptr)
+ return make_error_code(NativeReaderError::memory_error);
+ const size_t ivarElementSize = chunk->fileSize
+ / chunk->elementCount;
+ if ( ivarElementSize != sizeof(NativeDefinedAtomIvarsV1) )
+ return make_error_code(NativeReaderError::file_malformed);
+ uint8_t* atomsEnd = atomsStart + atomsArraySize;
+ const NativeDefinedAtomIvarsV1* ivarData =
+ reinterpret_cast<const NativeDefinedAtomIvarsV1*>
+ (base + chunk->fileOffset);
+ for(uint8_t* s = atomsStart; s != atomsEnd; s += atomSize) {
+ NativeDefinedAtomV1* atomAllocSpace =
+ reinterpret_cast<NativeDefinedAtomV1*>(s);
+ new (atomAllocSpace) NativeDefinedAtomV1(*this, ivarData);
+ ++ivarData;
+ }
+ this->_definedAtoms._arrayStart = atomsStart;
+ this->_definedAtoms._arrayEnd = atomsEnd;
+ this->_definedAtoms._elementSize = atomSize;
+ this->_definedAtoms._elementCount = chunk->elementCount;
+ DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs()
+ << " chunk DefinedAtomsV1: "
+ << " count=" << chunk->elementCount
+ << " chunkSize=" << chunk->fileSize
+ << "\n");
+ return make_error_code(NativeReaderError::success);
+ }
+
+
+
+ // set up pointers to attributes array
+ std::error_code processAttributesV1(const uint8_t *base,
+ const NativeChunk *chunk) {
+ this->_attributes = base + chunk->fileOffset;
+ this->_attributesMaxOffset = chunk->fileSize;
+ DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs()
+ << " chunk AttributesV1: "
+ << " count=" << chunk->elementCount
+ << " chunkSize=" << chunk->fileSize
+ << "\n");
+ return make_error_code(NativeReaderError::success);
+ }
+
+ // set up pointers to attributes array
+ std::error_code processAbsoluteAttributesV1(const uint8_t *base,
+ const NativeChunk *chunk) {
+ this->_absAttributes = base + chunk->fileOffset;
+ this->_absAbsoluteMaxOffset = chunk->fileSize;
+ DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs()
+ << " chunk AbsoluteAttributesV1: "
+ << " count=" << chunk->elementCount
+ << " chunkSize=" << chunk->fileSize
+ << "\n");
+ return make_error_code(NativeReaderError::success);
+ }
+
+ // instantiate array of UndefinedAtoms from v1 ivar data in file
+ std::error_code processUndefinedAtomsV1(const uint8_t *base,
+ const NativeChunk *chunk) {
+ const size_t atomSize = sizeof(NativeUndefinedAtomV1);
+ size_t atomsArraySize = chunk->elementCount * atomSize;
+ uint8_t* atomsStart = reinterpret_cast<uint8_t*>
+ (operator new(atomsArraySize, std::nothrow));
+ if (atomsStart == nullptr)
+ return make_error_code(NativeReaderError::memory_error);
+ const size_t ivarElementSize = chunk->fileSize
+ / chunk->elementCount;
+ if ( ivarElementSize != sizeof(NativeUndefinedAtomIvarsV1) )
+ return make_error_code(NativeReaderError::file_malformed);
+ uint8_t* atomsEnd = atomsStart + atomsArraySize;
+ const NativeUndefinedAtomIvarsV1* ivarData =
+ reinterpret_cast<const NativeUndefinedAtomIvarsV1*>
+ (base + chunk->fileOffset);
+ for(uint8_t* s = atomsStart; s != atomsEnd; s += atomSize) {
+ NativeUndefinedAtomV1* atomAllocSpace =
+ reinterpret_cast<NativeUndefinedAtomV1*>(s);
+ new (atomAllocSpace) NativeUndefinedAtomV1(*this, ivarData);
+ ++ivarData;
+ }
+ this->_undefinedAtoms._arrayStart = atomsStart;
+ this->_undefinedAtoms._arrayEnd = atomsEnd;
+ this->_undefinedAtoms._elementSize = atomSize;
+ this->_undefinedAtoms._elementCount = chunk->elementCount;
+ DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs()
+ << " chunk UndefinedAtomsV1:"
+ << " count=" << chunk->elementCount
+ << " chunkSize=" << chunk->fileSize
+ << "\n");
+ return make_error_code(NativeReaderError::success);
+ }
+
+
+ // instantiate array of ShareLibraryAtoms from v1 ivar data in file
+ std::error_code processSharedLibraryAtomsV1(const uint8_t *base,
+ const NativeChunk *chunk) {
+ const size_t atomSize = sizeof(NativeSharedLibraryAtomV1);
+ size_t atomsArraySize = chunk->elementCount * atomSize;
+ uint8_t* atomsStart = reinterpret_cast<uint8_t*>
+ (operator new(atomsArraySize, std::nothrow));
+ if (atomsStart == nullptr)
+ return make_error_code(NativeReaderError::memory_error);
+ const size_t ivarElementSize = chunk->fileSize
+ / chunk->elementCount;
+ if ( ivarElementSize != sizeof(NativeSharedLibraryAtomIvarsV1) )
+ return make_error_code(NativeReaderError::file_malformed);
+ uint8_t* atomsEnd = atomsStart + atomsArraySize;
+ const NativeSharedLibraryAtomIvarsV1* ivarData =
+ reinterpret_cast<const NativeSharedLibraryAtomIvarsV1*>
+ (base + chunk->fileOffset);
+ for(uint8_t* s = atomsStart; s != atomsEnd; s += atomSize) {
+ NativeSharedLibraryAtomV1* atomAllocSpace =
+ reinterpret_cast<NativeSharedLibraryAtomV1*>(s);
+ new (atomAllocSpace) NativeSharedLibraryAtomV1(*this, ivarData);
+ ++ivarData;
+ }
+ this->_sharedLibraryAtoms._arrayStart = atomsStart;
+ this->_sharedLibraryAtoms._arrayEnd = atomsEnd;
+ this->_sharedLibraryAtoms._elementSize = atomSize;
+ this->_sharedLibraryAtoms._elementCount = chunk->elementCount;
+ DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs()
+ << " chunk SharedLibraryAtomsV1:"
+ << " count=" << chunk->elementCount
+ << " chunkSize=" << chunk->fileSize
+ << "\n");
+ return make_error_code(NativeReaderError::success);
+ }
+
+
+ // instantiate array of AbsoluteAtoms from v1 ivar data in file
+ std::error_code processAbsoluteAtomsV1(const uint8_t *base,
+ const NativeChunk *chunk) {
+ const size_t atomSize = sizeof(NativeAbsoluteAtomV1);
+ size_t atomsArraySize = chunk->elementCount * atomSize;
+ uint8_t* atomsStart = reinterpret_cast<uint8_t*>
+ (operator new(atomsArraySize, std::nothrow));
+ if (atomsStart == nullptr)
+ return make_error_code(NativeReaderError::memory_error);
+ const size_t ivarElementSize = chunk->fileSize
+ / chunk->elementCount;
+ if ( ivarElementSize != sizeof(NativeAbsoluteAtomIvarsV1) )
+ return make_error_code(NativeReaderError::file_malformed);
+ uint8_t* atomsEnd = atomsStart + atomsArraySize;
+ const NativeAbsoluteAtomIvarsV1* ivarData =
+ reinterpret_cast<const NativeAbsoluteAtomIvarsV1*>
+ (base + chunk->fileOffset);
+ for(uint8_t* s = atomsStart; s != atomsEnd; s += atomSize) {
+ NativeAbsoluteAtomV1* atomAllocSpace =
+ reinterpret_cast<NativeAbsoluteAtomV1*>(s);
+ new (atomAllocSpace) NativeAbsoluteAtomV1(*this, ivarData);
+ ++ivarData;
+ }
+ this->_absoluteAtoms._arrayStart = atomsStart;
+ this->_absoluteAtoms._arrayEnd = atomsEnd;
+ this->_absoluteAtoms._elementSize = atomSize;
+ this->_absoluteAtoms._elementCount = chunk->elementCount;
+ DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs()
+ << " chunk AbsoluteAtomsV1: "
+ << " count=" << chunk->elementCount
+ << " chunkSize=" << chunk->fileSize
+ << "\n");
+ return make_error_code(NativeReaderError::success);
+ }
+
+ template <class T, class U>
+ std::error_code
+ processReferences(const uint8_t *base, const NativeChunk *chunk,
+ uint8_t *&refsStart, uint8_t *&refsEnd) const {
+ if (chunk->elementCount == 0)
+ return make_error_code(NativeReaderError::success);
+ size_t refsArraySize = chunk->elementCount * sizeof(T);
+ refsStart = reinterpret_cast<uint8_t *>(
+ operator new(refsArraySize, std::nothrow));
+ if (refsStart == nullptr)
+ return make_error_code(NativeReaderError::memory_error);
+ const size_t ivarElementSize = chunk->fileSize / chunk->elementCount;
+ if (ivarElementSize != sizeof(U))
+ return make_error_code(NativeReaderError::file_malformed);
+ refsEnd = refsStart + refsArraySize;
+ const U* ivarData = reinterpret_cast<const U *>(base + chunk->fileOffset);
+ for (uint8_t *s = refsStart; s != refsEnd; s += sizeof(T), ++ivarData) {
+ T *atomAllocSpace = reinterpret_cast<T *>(s);
+ new (atomAllocSpace) T(*this, ivarData);
+ }
+ return make_error_code(NativeReaderError::success);
+ }
+
+ // instantiate array of References from v1 ivar data in file
+ std::error_code processReferencesV1(const uint8_t *base,
+ const NativeChunk *chunk) {
+ uint8_t *refsStart, *refsEnd;
+ if (std::error_code ec =
+ processReferences<NativeReferenceV1, NativeReferenceIvarsV1>(
+ base, chunk, refsStart, refsEnd))
+ return ec;
+ this->_referencesV1.arrayStart = refsStart;
+ this->_referencesV1.arrayEnd = refsEnd;
+ this->_referencesV1.elementSize = sizeof(NativeReferenceV1);
+ this->_referencesV1.elementCount = chunk->elementCount;
+ DEBUG_WITH_TYPE("ReaderNative", {
+ llvm::dbgs() << " chunk ReferencesV1: "
+ << " count=" << chunk->elementCount
+ << " chunkSize=" << chunk->fileSize << "\n";
+ });
+ return make_error_code(NativeReaderError::success);
+ }
+
+ // instantiate array of References from v2 ivar data in file
+ std::error_code processReferencesV2(const uint8_t *base,
+ const NativeChunk *chunk) {
+ uint8_t *refsStart, *refsEnd;
+ if (std::error_code ec =
+ processReferences<NativeReferenceV2, NativeReferenceIvarsV2>(
+ base, chunk, refsStart, refsEnd))
+ return ec;
+ this->_referencesV2.arrayStart = refsStart;
+ this->_referencesV2.arrayEnd = refsEnd;
+ this->_referencesV2.elementSize = sizeof(NativeReferenceV2);
+ this->_referencesV2.elementCount = chunk->elementCount;
+ DEBUG_WITH_TYPE("ReaderNative", {
+ llvm::dbgs() << " chunk ReferencesV2: "
+ << " count=" << chunk->elementCount
+ << " chunkSize=" << chunk->fileSize << "\n";
+ });
+ return make_error_code(NativeReaderError::success);
+ }
+
+ // set up pointers to target table
+ std::error_code processTargetsTable(const uint8_t *base,
+ const NativeChunk *chunk) {
+ const uint32_t* targetIndexes = reinterpret_cast<const uint32_t*>
+ (base + chunk->fileOffset);
+ this->_targetsTableCount = chunk->elementCount;
+ this->_targetsTable = new const Atom*[chunk->elementCount];
+ for (uint32_t i=0; i < chunk->elementCount; ++i) {
+ const uint32_t index = targetIndexes[i];
+ if ( index < _definedAtoms._elementCount ) {
+ const uint8_t* p = _definedAtoms._arrayStart
+ + index * _definedAtoms._elementSize;
+ this->_targetsTable[i] = reinterpret_cast<const DefinedAtom*>(p);
+ continue;
+ }
+ const uint32_t undefIndex = index - _definedAtoms._elementCount;
+ if ( undefIndex < _undefinedAtoms._elementCount ) {
+ const uint8_t* p = _undefinedAtoms._arrayStart
+ + undefIndex * _undefinedAtoms._elementSize;
+ this->_targetsTable[i] = reinterpret_cast<const UndefinedAtom*>(p);
+ continue;
+ }
+ const uint32_t slIndex = index - _definedAtoms._elementCount
+ - _undefinedAtoms._elementCount;
+ if ( slIndex < _sharedLibraryAtoms._elementCount ) {
+ const uint8_t* p = _sharedLibraryAtoms._arrayStart
+ + slIndex * _sharedLibraryAtoms._elementSize;
+ this->_targetsTable[i] = reinterpret_cast<const SharedLibraryAtom*>(p);
+ continue;
+ }
+ const uint32_t abIndex = index - _definedAtoms._elementCount
+ - _undefinedAtoms._elementCount
+ - _sharedLibraryAtoms._elementCount;
+ if ( abIndex < _absoluteAtoms._elementCount ) {
+ const uint8_t* p = _absoluteAtoms._arrayStart
+ + abIndex * _absoluteAtoms._elementSize;
+ this->_targetsTable[i] = reinterpret_cast<const AbsoluteAtom*>(p);
+ continue;
+ }
+ return make_error_code(NativeReaderError::file_malformed);
+ }
+ DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs()
+ << " chunk Targets Table: "
+ << " count=" << chunk->elementCount
+ << " chunkSize=" << chunk->fileSize
+ << "\n");
+ return make_error_code(NativeReaderError::success);
+ }
+
+
+ // set up pointers to addend pool in file
+ std::error_code processAddendsTable(const uint8_t *base,
+ const NativeChunk *chunk) {
+ this->_addends = reinterpret_cast<const Reference::Addend*>
+ (base + chunk->fileOffset);
+ this->_addendsMaxIndex = chunk->elementCount;
+ DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs()
+ << " chunk Addends: "
+ << " count=" << chunk->elementCount
+ << " chunkSize=" << chunk->fileSize
+ << "\n");
+ return make_error_code(NativeReaderError::success);
+ }
+
+ // set up pointers to string pool in file
+ std::error_code processStrings(const uint8_t *base,
+ const NativeChunk *chunk) {
+ this->_strings = reinterpret_cast<const char*>(base + chunk->fileOffset);
+ this->_stringsMaxOffset = chunk->fileSize;
+ DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs()
+ << " chunk Strings: "
+ << " chunkSize=" << chunk->fileSize
+ << "\n");
+ return make_error_code(NativeReaderError::success);
+ }
+
+ // set up pointers to content area in file
+ std::error_code processContent(const uint8_t *base,
+ const NativeChunk *chunk) {
+ this->_contentStart = base + chunk->fileOffset;
+ this->_contentEnd = base + chunk->fileOffset + chunk->fileSize;
+ DEBUG_WITH_TYPE("ReaderNative", llvm::dbgs()
+ << " chunk content: "
+ << " chunkSize=" << chunk->fileSize
+ << "\n");
+ return make_error_code(NativeReaderError::success);
+ }
+
+ StringRef string(uint32_t offset) const {
+ assert(offset < _stringsMaxOffset);
+ return StringRef(&_strings[offset]);
+ }
+
+ Reference::Addend addend(uint32_t index) const {
+ if ( index == 0 )
+ return 0; // addend index zero is used to mean "no addend"
+ assert(index <= _addendsMaxIndex);
+ return _addends[index-1]; // one-based indexing
+ }
+
+ const NativeAtomAttributesV1& attribute(uint32_t off) const {
+ assert(off < _attributesMaxOffset);
+ return *reinterpret_cast<const NativeAtomAttributesV1*>(_attributes + off);
+ }
+
+ const NativeAtomAttributesV1& absAttribute(uint32_t off) const {
+ assert(off < _absAbsoluteMaxOffset);
+ return *reinterpret_cast<const NativeAtomAttributesV1*>(_absAttributes + off);
+ }
+
+ const uint8_t* content(uint32_t offset, uint32_t size) const {
+ const uint8_t* result = _contentStart + offset;
+ assert((result+size) <= _contentEnd);
+ return result;
+ }
+
+ const Reference* referenceByIndex(uintptr_t index) const {
+ if (index < _referencesV1.elementCount) {
+ return reinterpret_cast<const NativeReferenceV1*>(
+ _referencesV1.arrayStart + index * _referencesV1.elementSize);
+ }
+ assert(index < _referencesV2.elementCount);
+ return reinterpret_cast<const NativeReferenceV2*>(
+ _referencesV2.arrayStart + index * _referencesV2.elementSize);
+ }
+
+ const Atom* targetV1(uint16_t index) const {
+ if ( index == NativeReferenceIvarsV1::noTarget )
+ return nullptr;
+ assert(index < _targetsTableCount);
+ return _targetsTable[index];
+ }
+
+ void setTargetV1(uint16_t index, const Atom* newAtom) const {
+ assert(index != NativeReferenceIvarsV1::noTarget);
+ assert(index > _targetsTableCount);
+ _targetsTable[index] = newAtom;
+ }
+
+ const Atom* targetV2(uint32_t index) const {
+ if (index == NativeReferenceIvarsV2::noTarget)
+ return nullptr;
+ assert(index < _targetsTableCount);
+ return _targetsTable[index];
+ }
+
+ void setTargetV2(uint32_t index, const Atom* newAtom) const {
+ assert(index != NativeReferenceIvarsV2::noTarget);
+ assert(index > _targetsTableCount);
+ _targetsTable[index] = newAtom;
+ }
+
+ template <typename T>
+ class AtomArray : public File::atom_collection<T> {
+ public:
+ AtomArray() : _arrayStart(nullptr), _arrayEnd(nullptr),
+ _elementSize(0), _elementCount(0) { }
+
+ virtual atom_iterator<T> begin() const {
+ return atom_iterator<T>(*this, reinterpret_cast<const void*>(_arrayStart));
+ }
+ virtual atom_iterator<T> end() const{
+ return atom_iterator<T>(*this, reinterpret_cast<const void*>(_arrayEnd));
+ }
+ virtual const T* deref(const void* it) const {
+ return reinterpret_cast<const T*>(it);
+ }
+ virtual void next(const void*& it) const {
+ const uint8_t* p = reinterpret_cast<const uint8_t*>(it);
+ p += _elementSize;
+ it = reinterpret_cast<const void*>(p);
+ }
+ virtual uint64_t size() const { return _elementCount; }
+ const uint8_t *_arrayStart;
+ const uint8_t *_arrayEnd;
+ uint32_t _elementSize;
+ uint32_t _elementCount;
+ };
+
+ struct IvarArray {
+ IvarArray() :
+ arrayStart(nullptr),
+ arrayEnd(nullptr),
+ elementSize(0),
+ elementCount(0) { }
+
+ const uint8_t* arrayStart;
+ const uint8_t* arrayEnd;
+ uint32_t elementSize;
+ uint32_t elementCount;
+ };
+
+ std::unique_ptr<MemoryBuffer> _mb;
+ const NativeFileHeader* _header;
+ AtomArray<DefinedAtom> _definedAtoms;
+ AtomArray<UndefinedAtom> _undefinedAtoms;
+ AtomArray<SharedLibraryAtom> _sharedLibraryAtoms;
+ AtomArray<AbsoluteAtom> _absoluteAtoms;
+ const uint8_t* _absAttributes;
+ uint32_t _absAbsoluteMaxOffset;
+ const uint8_t* _attributes;
+ uint32_t _attributesMaxOffset;
+ IvarArray _referencesV1;
+ IvarArray _referencesV2;
+ const Atom** _targetsTable;
+ uint32_t _targetsTableCount;
+ const char* _strings;
+ uint32_t _stringsMaxOffset;
+ const Reference::Addend* _addends;
+ uint32_t _addendsMaxIndex;
+ const uint8_t *_contentStart;
+ const uint8_t *_contentEnd;
+};
+
+inline const lld::File &NativeDefinedAtomV1::file() const {
+ return *_file;
+}
+
+inline uint64_t NativeDefinedAtomV1:: ordinal() const {
+ const uint8_t* p = reinterpret_cast<const uint8_t*>(_ivarData);
+ return p - _file->_definedAtoms._arrayStart;
+}
+
+inline StringRef NativeDefinedAtomV1::name() const {
+ return _file->string(_ivarData->nameOffset);
+}
+
+inline const NativeAtomAttributesV1& NativeDefinedAtomV1::attributes() const {
+ return _file->attribute(_ivarData->attributesOffset);
+}
+
+inline ArrayRef<uint8_t> NativeDefinedAtomV1::rawContent() const {
+ if (!occupiesDiskSpace())
+ return ArrayRef<uint8_t>();
+ const uint8_t* p = _file->content(_ivarData->contentOffset,
+ _ivarData->contentSize);
+ return ArrayRef<uint8_t>(p, _ivarData->contentSize);
+}
+
+inline StringRef NativeDefinedAtomV1::customSectionName() const {
+ uint32_t offset = attributes().sectionNameOffset;
+ return _file->string(offset);
+}
+
+DefinedAtom::reference_iterator NativeDefinedAtomV1::begin() const {
+ uintptr_t index = _ivarData->referencesStartIndex;
+ const void* it = reinterpret_cast<const void*>(index);
+ return reference_iterator(*this, it);
+}
+
+DefinedAtom::reference_iterator NativeDefinedAtomV1::end() const {
+ uintptr_t index = _ivarData->referencesStartIndex+_ivarData->referencesCount;
+ const void* it = reinterpret_cast<const void*>(index);
+ return reference_iterator(*this, it);
+}
+
+const Reference* NativeDefinedAtomV1::derefIterator(const void* it) const {
+ uintptr_t index = reinterpret_cast<uintptr_t>(it);
+ return _file->referenceByIndex(index);
+}
+
+void NativeDefinedAtomV1::incrementIterator(const void*& it) const {
+ uintptr_t index = reinterpret_cast<uintptr_t>(it);
+ ++index;
+ it = reinterpret_cast<const void*>(index);
+}
+
+inline const lld::File& NativeUndefinedAtomV1::file() const {
+ return *_file;
+}
+
+inline StringRef NativeUndefinedAtomV1::name() const {
+ return _file->string(_ivarData->nameOffset);
+}
+
+inline const UndefinedAtom *NativeUndefinedAtomV1::fallback() const {
+ if (!_ivarData->fallbackNameOffset)
+ return nullptr;
+ if (!_fallback)
+ _fallback.reset(new SimpleUndefinedAtom(
+ *_file, _file->string(_ivarData->fallbackNameOffset)));
+ return _fallback.get();
+}
+
+inline const lld::File& NativeSharedLibraryAtomV1::file() const {
+ return *_file;
+}
+
+inline StringRef NativeSharedLibraryAtomV1::name() const {
+ return _file->string(_ivarData->nameOffset);
+}
+
+inline StringRef NativeSharedLibraryAtomV1::loadName() const {
+ return _file->string(_ivarData->loadNameOffset);
+}
+
+
+
+inline const lld::File& NativeAbsoluteAtomV1::file() const {
+ return *_file;
+}
+
+inline StringRef NativeAbsoluteAtomV1::name() const {
+ return _file->string(_ivarData->nameOffset);
+}
+
+inline const NativeAtomAttributesV1& NativeAbsoluteAtomV1::absAttributes() const {
+ return _file->absAttribute(_ivarData->attributesOffset);
+}
+
+inline const Atom* NativeReferenceV1::target() const {
+ return _file->targetV1(_ivarData->targetIndex);
+}
+
+inline Reference::Addend NativeReferenceV1::addend() const {
+ return _file->addend(_ivarData->addendIndex);
+}
+
+inline void NativeReferenceV1::setTarget(const Atom* newAtom) {
+ return _file->setTargetV1(_ivarData->targetIndex, newAtom);
+}
+
+inline void NativeReferenceV1::setAddend(Addend a) {
+ // Do nothing if addend value is not being changed.
+ if (addend() == a)
+ return;
+ llvm_unreachable("setAddend() not supported");
+}
+
+inline const Atom* NativeReferenceV2::target() const {
+ return _file->targetV2(_ivarData->targetIndex);
+}
+
+inline Reference::Addend NativeReferenceV2::addend() const {
+ return _ivarData->addend;
+}
+
+inline void NativeReferenceV2::setTarget(const Atom* newAtom) {
+ return _file->setTargetV2(_ivarData->targetIndex, newAtom);
+}
+
+inline void NativeReferenceV2::setAddend(Addend a) {
+ // Do nothing if addend value is not being changed.
+ if (addend() == a)
+ return;
+ llvm_unreachable("setAddend() not supported");
+}
+
+uint32_t NativeReferenceV2::tag() const { return _ivarData->tag; }
+
+} // end namespace native
+
+namespace {
+
+class NativeReader : public Reader {
+public:
+ virtual bool canParse(file_magic magic, StringRef,
+ const MemoryBuffer &mb) const override {
+ const NativeFileHeader *const header =
+ reinterpret_cast<const NativeFileHeader *>(mb.getBufferStart());
+ return (memcmp(header->magic, NATIVE_FILE_HEADER_MAGIC,
+ sizeof(header->magic)) == 0);
+ }
+
+ virtual std::error_code
+ loadFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &,
+ std::vector<std::unique_ptr<File>> &result) const override {
+ auto *file = new lld::native::File(std::move(mb));
+ result.push_back(std::unique_ptr<File>(file));
+ return std::error_code();
+ }
+};
+
+}
+
+void Registry::addSupportNativeObjects() {
+ add(std::unique_ptr<Reader>(new NativeReader()));
+}
+
+} // end namespace lld
diff --git a/lib/ReaderWriter/Native/WriterNative.cpp b/lib/ReaderWriter/Native/WriterNative.cpp
new file mode 100644
index 000000000000..5e01a6ce1c7c
--- /dev/null
+++ b/lib/ReaderWriter/Native/WriterNative.cpp
@@ -0,0 +1,566 @@
+//===- lib/ReaderWriter/Native/WriterNative.cpp ---------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeFileFormat.h"
+#include "lld/Core/File.h"
+#include "lld/Core/LinkingContext.h"
+#include "lld/Core/Writer.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstdint>
+#include <set>
+#include <system_error>
+#include <vector>
+
+namespace lld {
+namespace native {
+
+///
+/// Class for writing native object files.
+///
+class Writer : public lld::Writer {
+public:
+ std::error_code writeFile(const lld::File &file, StringRef outPath) override {
+ // reserve first byte for unnamed atoms
+ _stringPool.push_back('\0');
+ // visit all atoms
+ for ( const DefinedAtom *defAtom : file.defined() ) {
+ this->addIVarsForDefinedAtom(*defAtom);
+ // We are trying to process all atoms, but the defined() iterator does not
+ // return group children. So, when a group parent is found, we need to
+ // handle each child atom.
+ if (defAtom->isGroupParent()) {
+ for (const Reference *r : *defAtom) {
+ if (r->kindNamespace() != lld::Reference::KindNamespace::all)
+ continue;
+ if (r->kindValue() == lld::Reference::kindGroupChild) {
+ const DefinedAtom *target = dyn_cast<DefinedAtom>(r->target());
+ assert(target && "Internal Error: kindGroupChild references need "
+ "to be associated with Defined Atoms only");
+ this->addIVarsForDefinedAtom(*target);
+ }
+ }
+ }
+ }
+ for ( const UndefinedAtom *undefAtom : file.undefined() ) {
+ this->addIVarsForUndefinedAtom(*undefAtom);
+ }
+ for ( const SharedLibraryAtom *shlibAtom : file.sharedLibrary() ) {
+ this->addIVarsForSharedLibraryAtom(*shlibAtom);
+ }
+ for ( const AbsoluteAtom *absAtom : file.absolute() ) {
+ this->addIVarsForAbsoluteAtom(*absAtom);
+ }
+
+ maybeConvertReferencesToV1();
+
+ // construct file header based on atom information accumulated
+ this->makeHeader();
+
+ std::error_code ec;
+ llvm::raw_fd_ostream out(outPath, ec, llvm::sys::fs::F_None);
+ if (ec)
+ return ec;
+
+ this->write(out);
+
+ return std::error_code();
+ }
+
+ virtual ~Writer() {
+ }
+
+private:
+
+ // write the lld::File in native format to the specified stream
+ void write(raw_ostream &out) {
+ assert(out.tell() == 0);
+ out.write((char*)_headerBuffer, _headerBufferSize);
+
+ writeChunk(out, _definedAtomIvars, NCS_DefinedAtomsV1);
+ writeChunk(out, _attributes, NCS_AttributesArrayV1);
+ writeChunk(out, _undefinedAtomIvars, NCS_UndefinedAtomsV1);
+ writeChunk(out, _sharedLibraryAtomIvars, NCS_SharedLibraryAtomsV1);
+ writeChunk(out, _absoluteAtomIvars, NCS_AbsoluteAtomsV1);
+ writeChunk(out, _absAttributes, NCS_AbsoluteAttributesV1);
+ writeChunk(out, _stringPool, NCS_Strings);
+ writeChunk(out, _referencesV1, NCS_ReferencesArrayV1);
+ writeChunk(out, _referencesV2, NCS_ReferencesArrayV2);
+
+ if (!_targetsTableIndex.empty()) {
+ assert(out.tell() == findChunk(NCS_TargetsTable).fileOffset);
+ writeTargetTable(out);
+ }
+
+ if (!_addendsTableIndex.empty()) {
+ assert(out.tell() == findChunk(NCS_AddendsTable).fileOffset);
+ writeAddendTable(out);
+ }
+
+ writeChunk(out, _contentPool, NCS_Content);
+ }
+
+ template<class T>
+ void writeChunk(raw_ostream &out, std::vector<T> &vector, uint32_t signature) {
+ if (vector.empty())
+ return;
+ assert(out.tell() == findChunk(signature).fileOffset);
+ out.write((char*)&vector[0], vector.size() * sizeof(T));
+ }
+
+ void addIVarsForDefinedAtom(const DefinedAtom& atom) {
+ _definedAtomIndex[&atom] = _definedAtomIvars.size();
+ NativeDefinedAtomIvarsV1 ivar;
+ unsigned refsCount;
+ ivar.nameOffset = getNameOffset(atom);
+ ivar.attributesOffset = getAttributeOffset(atom);
+ ivar.referencesStartIndex = getReferencesIndex(atom, refsCount);
+ ivar.referencesCount = refsCount;
+ ivar.contentOffset = getContentOffset(atom);
+ ivar.contentSize = atom.size();
+ ivar.sectionSize = atom.sectionSize();
+ _definedAtomIvars.push_back(ivar);
+ }
+
+ void addIVarsForUndefinedAtom(const UndefinedAtom& atom) {
+ _undefinedAtomIndex[&atom] = _undefinedAtomIvars.size();
+ NativeUndefinedAtomIvarsV1 ivar;
+ ivar.nameOffset = getNameOffset(atom);
+ ivar.flags = (atom.canBeNull() & 0x03);
+ ivar.fallbackNameOffset = 0;
+ if (atom.fallback())
+ ivar.fallbackNameOffset = getNameOffset(*atom.fallback());
+ _undefinedAtomIvars.push_back(ivar);
+ }
+
+ void addIVarsForSharedLibraryAtom(const SharedLibraryAtom& atom) {
+ _sharedLibraryAtomIndex[&atom] = _sharedLibraryAtomIvars.size();
+ NativeSharedLibraryAtomIvarsV1 ivar;
+ ivar.size = atom.size();
+ ivar.nameOffset = getNameOffset(atom);
+ ivar.loadNameOffset = getSharedLibraryNameOffset(atom.loadName());
+ ivar.type = (uint32_t)atom.type();
+ ivar.flags = atom.canBeNullAtRuntime();
+ _sharedLibraryAtomIvars.push_back(ivar);
+ }
+
+ void addIVarsForAbsoluteAtom(const AbsoluteAtom& atom) {
+ _absoluteAtomIndex[&atom] = _absoluteAtomIvars.size();
+ NativeAbsoluteAtomIvarsV1 ivar;
+ ivar.nameOffset = getNameOffset(atom);
+ ivar.attributesOffset = getAttributeOffset(atom);
+ ivar.reserved = 0;
+ ivar.value = atom.value();
+ _absoluteAtomIvars.push_back(ivar);
+ }
+
+ void convertReferencesToV1() {
+ for (const NativeReferenceIvarsV2 &v2 : _referencesV2) {
+ NativeReferenceIvarsV1 v1;
+ v1.offsetInAtom = v2.offsetInAtom;
+ v1.kindNamespace = v2.kindNamespace;
+ v1.kindArch = v2.kindArch;
+ v1.kindValue = v2.kindValue;
+ v1.targetIndex = (v2.targetIndex == NativeReferenceIvarsV2::noTarget) ?
+ (uint16_t)NativeReferenceIvarsV1::noTarget : v2.targetIndex;
+ v1.addendIndex = this->getAddendIndex(v2.addend);
+ _referencesV1.push_back(v1);
+ }
+ _referencesV2.clear();
+ }
+
+ bool canConvertReferenceToV1(const NativeReferenceIvarsV2 &ref) {
+ bool validOffset = (ref.offsetInAtom == NativeReferenceIvarsV2::noTarget) ||
+ ref.offsetInAtom < NativeReferenceIvarsV1::noTarget;
+ return validOffset && ref.targetIndex < UINT16_MAX;
+ }
+
+ // Convert vector of NativeReferenceIvarsV2 to NativeReferenceIvarsV1 if
+ // possible.
+ void maybeConvertReferencesToV1() {
+ std::set<int64_t> addends;
+ for (const NativeReferenceIvarsV2 &ref : _referencesV2) {
+ if (!canConvertReferenceToV1(ref))
+ return;
+ addends.insert(ref.addend);
+ if (addends.size() >= UINT16_MAX)
+ return;
+ }
+ convertReferencesToV1();
+ }
+
+ // fill out native file header and chunk directory
+ void makeHeader() {
+ const bool hasDefines = !_definedAtomIvars.empty();
+ const bool hasUndefines = !_undefinedAtomIvars.empty();
+ const bool hasSharedLibraries = !_sharedLibraryAtomIvars.empty();
+ const bool hasAbsolutes = !_absoluteAtomIvars.empty();
+ const bool hasReferencesV1 = !_referencesV1.empty();
+ const bool hasReferencesV2 = !_referencesV2.empty();
+ const bool hasTargetsTable = !_targetsTableIndex.empty();
+ const bool hasAddendTable = !_addendsTableIndex.empty();
+ const bool hasContent = !_contentPool.empty();
+
+ int chunkCount = 1; // always have string pool chunk
+ if ( hasDefines ) chunkCount += 2;
+ if ( hasUndefines ) ++chunkCount;
+ if ( hasSharedLibraries ) ++chunkCount;
+ if ( hasAbsolutes ) chunkCount += 2;
+ if ( hasReferencesV1 ) ++chunkCount;
+ if ( hasReferencesV2 ) ++chunkCount;
+ if ( hasTargetsTable ) ++chunkCount;
+ if ( hasAddendTable ) ++chunkCount;
+ if ( hasContent ) ++chunkCount;
+
+ _headerBufferSize = sizeof(NativeFileHeader)
+ + chunkCount*sizeof(NativeChunk);
+ _headerBuffer = reinterpret_cast<NativeFileHeader*>
+ (operator new(_headerBufferSize, std::nothrow));
+ NativeChunk *chunks =
+ reinterpret_cast<NativeChunk*>(reinterpret_cast<char*>(_headerBuffer)
+ + sizeof(NativeFileHeader));
+ memcpy(_headerBuffer->magic, NATIVE_FILE_HEADER_MAGIC,
+ sizeof(_headerBuffer->magic));
+ _headerBuffer->endian = NFH_LittleEndian;
+ _headerBuffer->architecture = 0;
+ _headerBuffer->fileSize = 0;
+ _headerBuffer->chunkCount = chunkCount;
+
+ // create chunk for defined atom ivar array
+ int nextIndex = 0;
+ uint32_t nextFileOffset = _headerBufferSize;
+ if (hasDefines) {
+ fillChunkHeader(chunks[nextIndex++], nextFileOffset, _definedAtomIvars,
+ NCS_DefinedAtomsV1);
+
+ // create chunk for attributes
+ fillChunkHeader(chunks[nextIndex++], nextFileOffset, _attributes,
+ NCS_AttributesArrayV1);
+ }
+
+ // create chunk for undefined atom array
+ if (hasUndefines)
+ fillChunkHeader(chunks[nextIndex++], nextFileOffset, _undefinedAtomIvars,
+ NCS_UndefinedAtomsV1);
+
+ // create chunk for shared library atom array
+ if (hasSharedLibraries)
+ fillChunkHeader(chunks[nextIndex++], nextFileOffset,
+ _sharedLibraryAtomIvars, NCS_SharedLibraryAtomsV1);
+
+ // create chunk for shared library atom array
+ if (hasAbsolutes) {
+ fillChunkHeader(chunks[nextIndex++], nextFileOffset, _absoluteAtomIvars,
+ NCS_AbsoluteAtomsV1);
+
+ // create chunk for attributes
+ fillChunkHeader(chunks[nextIndex++], nextFileOffset, _absAttributes,
+ NCS_AbsoluteAttributesV1);
+ }
+
+ // create chunk for symbol strings
+ // pad end of string pool to 4-bytes
+ while ((_stringPool.size() % 4) != 0)
+ _stringPool.push_back('\0');
+ fillChunkHeader(chunks[nextIndex++], nextFileOffset, _stringPool,
+ NCS_Strings);
+
+ // create chunk for referencesV2
+ if (hasReferencesV1)
+ fillChunkHeader(chunks[nextIndex++], nextFileOffset, _referencesV1,
+ NCS_ReferencesArrayV1);
+
+ // create chunk for referencesV2
+ if (hasReferencesV2)
+ fillChunkHeader(chunks[nextIndex++], nextFileOffset, _referencesV2,
+ NCS_ReferencesArrayV2);
+
+ // create chunk for target table
+ if (hasTargetsTable) {
+ NativeChunk& cht = chunks[nextIndex++];
+ cht.signature = NCS_TargetsTable;
+ cht.fileOffset = nextFileOffset;
+ cht.fileSize = _targetsTableIndex.size() * sizeof(uint32_t);
+ cht.elementCount = _targetsTableIndex.size();
+ nextFileOffset = cht.fileOffset + cht.fileSize;
+ }
+
+ // create chunk for addend table
+ if (hasAddendTable) {
+ NativeChunk& chad = chunks[nextIndex++];
+ chad.signature = NCS_AddendsTable;
+ chad.fileOffset = nextFileOffset;
+ chad.fileSize = _addendsTableIndex.size() * sizeof(Reference::Addend);
+ chad.elementCount = _addendsTableIndex.size();
+ nextFileOffset = chad.fileOffset + chad.fileSize;
+ }
+
+ // create chunk for content
+ if (hasContent)
+ fillChunkHeader(chunks[nextIndex++], nextFileOffset, _contentPool,
+ NCS_Content);
+
+ _headerBuffer->fileSize = nextFileOffset;
+ }
+
+ template<class T>
+ void fillChunkHeader(NativeChunk &chunk, uint32_t &nextFileOffset,
+ const std::vector<T> &data, uint32_t signature) {
+ chunk.signature = signature;
+ chunk.fileOffset = nextFileOffset;
+ chunk.fileSize = data.size() * sizeof(T);
+ chunk.elementCount = data.size();
+ nextFileOffset = chunk.fileOffset + chunk.fileSize;
+ }
+
+ // scan header to find particular chunk
+ NativeChunk& findChunk(uint32_t signature) {
+ const uint32_t chunkCount = _headerBuffer->chunkCount;
+ NativeChunk* chunks =
+ reinterpret_cast<NativeChunk*>(reinterpret_cast<char*>(_headerBuffer)
+ + sizeof(NativeFileHeader));
+ for (uint32_t i=0; i < chunkCount; ++i) {
+ if ( chunks[i].signature == signature )
+ return chunks[i];
+ }
+ llvm_unreachable("findChunk() signature not found");
+ }
+
+ // append atom name to string pool and return offset
+ uint32_t getNameOffset(const Atom& atom) {
+ return this->getNameOffset(atom.name());
+ }
+
+ // check if name is already in pool or append and return offset
+ uint32_t getSharedLibraryNameOffset(StringRef name) {
+ assert(!name.empty());
+ // look to see if this library name was used by another atom
+ for (auto &it : _sharedLibraryNames)
+ if (name.equals(it.first))
+ return it.second;
+ // first use of this library name
+ uint32_t result = this->getNameOffset(name);
+ _sharedLibraryNames.push_back(std::make_pair(name, result));
+ return result;
+ }
+
+ // append atom name to string pool and return offset
+ uint32_t getNameOffset(StringRef name) {
+ if ( name.empty() )
+ return 0;
+ uint32_t result = _stringPool.size();
+ _stringPool.insert(_stringPool.end(), name.begin(), name.end());
+ _stringPool.push_back(0);
+ return result;
+ }
+
+ // append atom cotent to content pool and return offset
+ uint32_t getContentOffset(const DefinedAtom& atom) {
+ if (!atom.occupiesDiskSpace())
+ return 0;
+ uint32_t result = _contentPool.size();
+ ArrayRef<uint8_t> cont = atom.rawContent();
+ _contentPool.insert(_contentPool.end(), cont.begin(), cont.end());
+ return result;
+ }
+
+ // reuse existing attributes entry or create a new one and return offet
+ uint32_t getAttributeOffset(const DefinedAtom& atom) {
+ NativeAtomAttributesV1 attrs = computeAttributesV1(atom);
+ return getOrPushAttribute(_attributes, attrs);
+ }
+
+ uint32_t getAttributeOffset(const AbsoluteAtom& atom) {
+ NativeAtomAttributesV1 attrs = computeAbsoluteAttributes(atom);
+ return getOrPushAttribute(_absAttributes, attrs);
+ }
+
+ uint32_t getOrPushAttribute(std::vector<NativeAtomAttributesV1> &dest,
+ const NativeAtomAttributesV1 &attrs) {
+ for (size_t i = 0, e = dest.size(); i < e; ++i) {
+ if (!memcmp(&dest[i], &attrs, sizeof(attrs))) {
+ // found that this set of attributes already used, so re-use
+ return i * sizeof(attrs);
+ }
+ }
+ // append new attribute set to end
+ uint32_t result = dest.size() * sizeof(attrs);
+ dest.push_back(attrs);
+ return result;
+ }
+
+ uint32_t sectionNameOffset(const DefinedAtom& atom) {
+ // if section based on content, then no custom section name available
+ if (atom.sectionChoice() == DefinedAtom::sectionBasedOnContent)
+ return 0;
+ StringRef name = atom.customSectionName();
+ assert(!name.empty());
+ // look to see if this section name was used by another atom
+ for (auto &it : _sectionNames)
+ if (name.equals(it.first))
+ return it.second;
+ // first use of this section name
+ uint32_t result = this->getNameOffset(name);
+ _sectionNames.push_back(std::make_pair(name, result));
+ return result;
+ }
+
+ NativeAtomAttributesV1 computeAttributesV1(const DefinedAtom& atom) {
+ NativeAtomAttributesV1 attrs;
+ attrs.sectionNameOffset = sectionNameOffset(atom);
+ attrs.align2 = atom.alignment().powerOf2;
+ attrs.alignModulus = atom.alignment().modulus;
+ attrs.scope = atom.scope();
+ attrs.interposable = atom.interposable();
+ attrs.merge = atom.merge();
+ attrs.contentType = atom.contentType();
+ attrs.sectionChoice = atom.sectionChoice();
+ attrs.deadStrip = atom.deadStrip();
+ attrs.dynamicExport = atom.dynamicExport();
+ attrs.codeModel = atom.codeModel();
+ attrs.permissions = atom.permissions();
+ return attrs;
+ }
+
+ NativeAtomAttributesV1 computeAbsoluteAttributes(const AbsoluteAtom& atom) {
+ NativeAtomAttributesV1 attrs;
+ attrs.scope = atom.scope();
+ return attrs;
+ }
+
+ // add references for this atom in a contiguous block in NCS_ReferencesArrayV2
+ uint32_t getReferencesIndex(const DefinedAtom& atom, unsigned& refsCount) {
+ size_t startRefSize = _referencesV2.size();
+ uint32_t result = startRefSize;
+ for (const Reference *ref : atom) {
+ NativeReferenceIvarsV2 nref;
+ nref.offsetInAtom = ref->offsetInAtom();
+ nref.kindNamespace = (uint8_t)ref->kindNamespace();
+ nref.kindArch = (uint8_t)ref->kindArch();
+ nref.kindValue = ref->kindValue();
+ nref.targetIndex = this->getTargetIndex(ref->target());
+ nref.addend = ref->addend();
+ nref.tag = ref->tag();
+ _referencesV2.push_back(nref);
+ }
+ refsCount = _referencesV2.size() - startRefSize;
+ return (refsCount == 0) ? 0 : result;
+ }
+
+ uint32_t getTargetIndex(const Atom* target) {
+ if ( target == nullptr )
+ return NativeReferenceIvarsV2::noTarget;
+ TargetToIndex::const_iterator pos = _targetsTableIndex.find(target);
+ if ( pos != _targetsTableIndex.end() ) {
+ return pos->second;
+ }
+ uint32_t result = _targetsTableIndex.size();
+ _targetsTableIndex[target] = result;
+ return result;
+ }
+
+ void writeTargetTable(raw_ostream &out) {
+ // Build table of target indexes
+ uint32_t maxTargetIndex = _targetsTableIndex.size();
+ assert(maxTargetIndex > 0);
+ std::vector<uint32_t> targetIndexes(maxTargetIndex);
+ for (auto &it : _targetsTableIndex) {
+ const Atom* atom = it.first;
+ uint32_t targetIndex = it.second;
+ assert(targetIndex < maxTargetIndex);
+
+ TargetToIndex::iterator pos = _definedAtomIndex.find(atom);
+ if (pos != _definedAtomIndex.end()) {
+ targetIndexes[targetIndex] = pos->second;
+ continue;
+ }
+ uint32_t base = _definedAtomIvars.size();
+
+ pos = _undefinedAtomIndex.find(atom);
+ if (pos != _undefinedAtomIndex.end()) {
+ targetIndexes[targetIndex] = pos->second + base;
+ continue;
+ }
+ base += _undefinedAtomIndex.size();
+
+ pos = _sharedLibraryAtomIndex.find(atom);
+ if (pos != _sharedLibraryAtomIndex.end()) {
+ targetIndexes[targetIndex] = pos->second + base;
+ continue;
+ }
+ base += _sharedLibraryAtomIndex.size();
+
+ pos = _absoluteAtomIndex.find(atom);
+ assert(pos != _absoluteAtomIndex.end());
+ targetIndexes[targetIndex] = pos->second + base;
+ }
+ // write table
+ out.write((char*)&targetIndexes[0], maxTargetIndex * sizeof(uint32_t));
+ }
+
+ uint32_t getAddendIndex(Reference::Addend addend) {
+ if ( addend == 0 )
+ return 0; // addend index zero is used to mean "no addend"
+ AddendToIndex::const_iterator pos = _addendsTableIndex.find(addend);
+ if ( pos != _addendsTableIndex.end() ) {
+ return pos->second;
+ }
+ uint32_t result = _addendsTableIndex.size() + 1; // one-based index
+ _addendsTableIndex[addend] = result;
+ return result;
+ }
+
+ void writeAddendTable(raw_ostream &out) {
+ // Build table of addends
+ uint32_t maxAddendIndex = _addendsTableIndex.size();
+ std::vector<Reference::Addend> addends(maxAddendIndex);
+ for (auto &it : _addendsTableIndex) {
+ Reference::Addend addend = it.first;
+ uint32_t index = it.second;
+ assert(index <= maxAddendIndex);
+ addends[index-1] = addend;
+ }
+ // write table
+ out.write((char*)&addends[0], maxAddendIndex*sizeof(Reference::Addend));
+ }
+
+ typedef std::vector<std::pair<StringRef, uint32_t>> NameToOffsetVector;
+
+ typedef llvm::DenseMap<const Atom*, uint32_t> TargetToIndex;
+ typedef llvm::DenseMap<Reference::Addend, uint32_t> AddendToIndex;
+
+ NativeFileHeader* _headerBuffer;
+ size_t _headerBufferSize;
+ std::vector<char> _stringPool;
+ std::vector<uint8_t> _contentPool;
+ std::vector<NativeDefinedAtomIvarsV1> _definedAtomIvars;
+ std::vector<NativeAtomAttributesV1> _attributes;
+ std::vector<NativeAtomAttributesV1> _absAttributes;
+ std::vector<NativeUndefinedAtomIvarsV1> _undefinedAtomIvars;
+ std::vector<NativeSharedLibraryAtomIvarsV1> _sharedLibraryAtomIvars;
+ std::vector<NativeAbsoluteAtomIvarsV1> _absoluteAtomIvars;
+ std::vector<NativeReferenceIvarsV1> _referencesV1;
+ std::vector<NativeReferenceIvarsV2> _referencesV2;
+ TargetToIndex _targetsTableIndex;
+ TargetToIndex _definedAtomIndex;
+ TargetToIndex _undefinedAtomIndex;
+ TargetToIndex _sharedLibraryAtomIndex;
+ TargetToIndex _absoluteAtomIndex;
+ AddendToIndex _addendsTableIndex;
+ NameToOffsetVector _sectionNames;
+ NameToOffsetVector _sharedLibraryNames;
+};
+} // end namespace native
+
+std::unique_ptr<Writer> createWriterNative() {
+ return std::unique_ptr<Writer>(new native::Writer());
+}
+} // end namespace lld
diff --git a/lib/ReaderWriter/PECOFF/Atoms.h b/lib/ReaderWriter/PECOFF/Atoms.h
new file mode 100644
index 000000000000..257edc17884b
--- /dev/null
+++ b/lib/ReaderWriter/PECOFF/Atoms.h
@@ -0,0 +1,312 @@
+//===- lib/ReaderWriter/PECOFF/Atoms.h ------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_PE_COFF_ATOMS_H
+#define LLD_READER_WRITER_PE_COFF_ATOMS_H
+
+#include "lld/Core/File.h"
+#include "lld/Core/Simple.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Object/COFF.h"
+#include <vector>
+
+namespace lld {
+namespace pecoff {
+class COFFDefinedAtom;
+
+class COFFUndefinedAtom : public UndefinedAtom {
+public:
+ COFFUndefinedAtom(const File &file, StringRef name,
+ const UndefinedAtom *fallback = nullptr)
+ : _owningFile(file), _name(name), _fallback(fallback) {}
+
+ const File &file() const override { return _owningFile; }
+ StringRef name() const override { return _name; }
+ CanBeNull canBeNull() const override { return CanBeNull::canBeNullNever; }
+ const UndefinedAtom *fallback() const override { return _fallback; }
+
+private:
+ const File &_owningFile;
+ StringRef _name;
+ const UndefinedAtom *_fallback;
+};
+
+/// The base class of all COFF defined atoms. A derived class of
+/// COFFBaseDefinedAtom may represent atoms read from a file or atoms created
+/// by the linker. An example of the latter case is the jump table for symbols
+/// in a DLL.
+class COFFBaseDefinedAtom : public DefinedAtom {
+public:
+ enum class Kind {
+ File,
+ Internal
+ };
+
+ const File &file() const override { return _file; }
+ StringRef name() const override { return _name; }
+ Interposable interposable() const override { return interposeNo; }
+ Merge merge() const override { return mergeNo; }
+ Alignment alignment() const override { return Alignment(0); }
+ StringRef customSectionName() const override { return ""; }
+ DeadStripKind deadStrip() const override { return deadStripNormal; }
+
+ Kind getKind() const { return _kind; }
+
+ void addReference(std::unique_ptr<SimpleReference> reference) {
+ _references.push_back(std::move(reference));
+ }
+
+ reference_iterator begin() const override {
+ return reference_iterator(*this, reinterpret_cast<const void *>(0));
+ }
+
+ reference_iterator end() const override {
+ return reference_iterator(
+ *this, reinterpret_cast<const void *>(_references.size()));
+ }
+
+protected:
+ COFFBaseDefinedAtom(const File &file, StringRef name, Kind kind)
+ : _file(file), _name(name), _kind(kind) {}
+
+private:
+ const Reference *derefIterator(const void *iter) const override {
+ size_t index = reinterpret_cast<size_t>(iter);
+ return _references[index].get();
+ }
+
+ void incrementIterator(const void *&iter) const override {
+ size_t index = reinterpret_cast<size_t>(iter);
+ iter = reinterpret_cast<const void *>(index + 1);
+ }
+
+ const File &_file;
+ StringRef _name;
+ Kind _kind;
+ std::vector<std::unique_ptr<SimpleReference>> _references;
+};
+
+/// This is the root class of the atom read from a file. This class have two
+/// subclasses; one for the regular atom and another for the BSS atom.
+class COFFDefinedFileAtom : public COFFBaseDefinedAtom {
+public:
+ COFFDefinedFileAtom(const File &file, StringRef name, StringRef sectionName,
+ uint64_t sectionSize, Scope scope,
+ ContentType contentType, ContentPermissions perms,
+ uint64_t ordinal)
+ : COFFBaseDefinedAtom(file, name, Kind::File), _sectionName(sectionName),
+ _sectionSize(sectionSize), _scope(scope), _contentType(contentType),
+ _permissions(perms), _ordinal(ordinal), _alignment(0) {}
+
+ static bool classof(const COFFBaseDefinedAtom *atom) {
+ return atom->getKind() == Kind::File;
+ }
+
+ void setAlignment(Alignment val) { _alignment = val; }
+ SectionChoice sectionChoice() const override { return sectionCustomRequired; }
+ StringRef customSectionName() const override { return _sectionName; }
+ uint64_t sectionSize() const override { return _sectionSize; }
+ Scope scope() const override { return _scope; }
+ ContentType contentType() const override { return _contentType; }
+ ContentPermissions permissions() const override { return _permissions; }
+ uint64_t ordinal() const override { return _ordinal; }
+ Alignment alignment() const override { return _alignment; }
+
+ void addAssociate(const DefinedAtom *other) {
+ auto *ref = new SimpleReference(Reference::KindNamespace::all,
+ Reference::KindArch::all,
+ lld::Reference::kindAssociate, 0, other, 0);
+ addReference(std::unique_ptr<SimpleReference>(ref));
+ }
+
+private:
+ StringRef _sectionName;
+ uint64_t _sectionSize;
+ Scope _scope;
+ ContentType _contentType;
+ ContentPermissions _permissions;
+ uint64_t _ordinal;
+ Alignment _alignment;
+ std::vector<std::unique_ptr<SimpleReference>> _references;
+};
+
+// A COFFDefinedAtom represents an atom read from a file and has contents.
+class COFFDefinedAtom : public COFFDefinedFileAtom {
+public:
+ COFFDefinedAtom(const File &file, StringRef name, StringRef sectionName,
+ uint64_t sectionSize, Scope scope, ContentType type,
+ bool isComdat, ContentPermissions perms, Merge merge,
+ ArrayRef<uint8_t> data, uint64_t ordinal)
+ : COFFDefinedFileAtom(file, name, sectionName, sectionSize,
+ scope, type, perms, ordinal),
+ _isComdat(isComdat), _merge(merge), _dataref(data) {}
+
+ Merge merge() const override { return _merge; }
+ uint64_t size() const override { return _dataref.size(); }
+ ArrayRef<uint8_t> rawContent() const override { return _dataref; }
+
+ DeadStripKind deadStrip() const override {
+ // Only COMDAT symbols would be dead-stripped.
+ return _isComdat ? deadStripNormal : deadStripNever;
+ }
+
+private:
+ bool _isComdat;
+ Merge _merge;
+ ArrayRef<uint8_t> _dataref;
+};
+
+// A COFFDefinedAtom represents an atom for BSS section.
+class COFFBSSAtom : public COFFDefinedFileAtom {
+public:
+ COFFBSSAtom(const File &file, StringRef name, Scope scope,
+ ContentPermissions perms, Merge merge, uint32_t size,
+ uint64_t ordinal)
+ : COFFDefinedFileAtom(file, name, ".bss", 0, scope, typeZeroFill,
+ perms, ordinal),
+ _merge(merge), _size(size) {}
+
+ Merge merge() const override { return _merge; }
+ uint64_t size() const override { return _size; }
+ ArrayRef<uint8_t> rawContent() const override { return _contents; }
+
+private:
+ Merge _merge;
+ uint32_t _size;
+ std::vector<uint8_t> _contents;
+};
+
+/// A COFFLinkerInternalAtom represents a defined atom created by the linker,
+/// not read from file.
+class COFFLinkerInternalAtom : public COFFBaseDefinedAtom {
+public:
+ SectionChoice sectionChoice() const override { return sectionBasedOnContent; }
+ uint64_t ordinal() const override { return _ordinal; }
+ Scope scope() const override { return scopeGlobal; }
+ Alignment alignment() const override { return Alignment(0); }
+ uint64_t size() const override { return _data.size(); }
+ ArrayRef<uint8_t> rawContent() const override { return _data; }
+
+protected:
+ COFFLinkerInternalAtom(const File &file, uint64_t ordinal,
+ std::vector<uint8_t> data, StringRef symbolName = "")
+ : COFFBaseDefinedAtom(file, symbolName, Kind::Internal),
+ _ordinal(ordinal), _data(std::move(data)) {}
+
+private:
+ uint64_t _ordinal;
+ std::vector<uint8_t> _data;
+};
+
+class COFFStringAtom : public COFFLinkerInternalAtom {
+public:
+ COFFStringAtom(const File &file, uint64_t ordinal, StringRef sectionName,
+ StringRef contents)
+ : COFFLinkerInternalAtom(file, ordinal, stringRefToVector(contents)),
+ _sectionName(sectionName) {}
+
+ SectionChoice sectionChoice() const override { return sectionCustomRequired; }
+ StringRef customSectionName() const override { return _sectionName; }
+ ContentType contentType() const override { return typeData; }
+ ContentPermissions permissions() const override { return permR__; }
+
+private:
+ StringRef _sectionName;
+
+ std::vector<uint8_t> stringRefToVector(StringRef name) const {
+ std::vector<uint8_t> ret(name.size() + 1);
+ memcpy(&ret[0], name.data(), name.size());
+ ret[name.size()] = 0;
+ return ret;
+ }
+};
+
+// A COFFSharedLibraryAtom represents a symbol for data in an import library. A
+// reference to a COFFSharedLibraryAtom will be transformed to a real reference
+// to an import address table entry in Idata pass.
+class COFFSharedLibraryAtom : public SharedLibraryAtom {
+public:
+ COFFSharedLibraryAtom(const File &file, uint16_t hint, StringRef symbolName,
+ StringRef importName, StringRef dllName)
+ : _file(file), _hint(hint), _mangledName(addImpPrefix(symbolName)),
+ _importName(importName), _dllName(dllName), _importTableEntry(nullptr) {
+ }
+
+ const File &file() const override { return _file; }
+ uint16_t hint() const { return _hint; }
+
+ /// Returns the symbol name to be used by the core linker.
+ StringRef name() const override { return _mangledName; }
+
+ /// Returns the symbol name to be used in the import description table in the
+ /// COFF header.
+ virtual StringRef importName() const { return _importName; }
+
+ StringRef loadName() const override { return _dllName; }
+ bool canBeNullAtRuntime() const override { return false; }
+ Type type() const override { return Type::Unknown; }
+ uint64_t size() const override { return 0; }
+
+ void setImportTableEntry(const DefinedAtom *atom) {
+ _importTableEntry = atom;
+ }
+
+ const DefinedAtom *getImportTableEntry() const { return _importTableEntry; }
+
+private:
+ /// Mangle the symbol name by adding "__imp_" prefix. See the file comment of
+ /// ReaderImportHeader.cpp for details about the prefix.
+ std::string addImpPrefix(StringRef symbolName) {
+ std::string ret("__imp_");
+ ret.append(symbolName);
+ return ret;
+ }
+
+ const File &_file;
+ uint16_t _hint;
+ std::string _mangledName;
+ std::string _importName;
+ StringRef _dllName;
+ const DefinedAtom *_importTableEntry;
+};
+
+// An instance of this class represents "input file" for atoms created in a
+// pass. Atoms need to be associated to an input file even if it's not read from
+// a file, so we use this class for that.
+class VirtualFile : public SimpleFile {
+public:
+ VirtualFile(const LinkingContext &ctx)
+ : SimpleFile("<virtual-file>"), _nextOrdinal(0) {
+ setOrdinal(ctx.getNextOrdinalAndIncrement());
+ }
+
+ uint64_t getNextOrdinal() { return _nextOrdinal++; }
+
+private:
+ uint64_t _nextOrdinal;
+};
+
+//===----------------------------------------------------------------------===//
+//
+// Utility functions to handle layout edges.
+//
+//===----------------------------------------------------------------------===//
+
+template <typename T, typename U>
+void addLayoutEdge(T *a, U *b, uint32_t which) {
+ auto ref = new SimpleReference(Reference::KindNamespace::all,
+ Reference::KindArch::all,
+ which, 0, b, 0);
+ a->addReference(std::unique_ptr<SimpleReference>(ref));
+}
+
+} // namespace pecoff
+} // namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/PECOFF/CMakeLists.txt b/lib/ReaderWriter/PECOFF/CMakeLists.txt
new file mode 100644
index 000000000000..86b49b79f194
--- /dev/null
+++ b/lib/ReaderWriter/PECOFF/CMakeLists.txt
@@ -0,0 +1,16 @@
+add_llvm_library(lldPECOFF
+ EdataPass.cpp
+ IdataPass.cpp
+ LinkerGeneratedSymbolFile.cpp
+ LoadConfigPass.cpp
+ PECOFFLinkingContext.cpp
+ Pass.cpp
+ ReaderCOFF.cpp
+ ReaderImportHeader.cpp
+ WriterImportLibrary.cpp
+ WriterPECOFF.cpp
+ LINK_LIBS
+ lldCore
+ LLVMObject
+ LLVMSupport
+ )
diff --git a/lib/ReaderWriter/PECOFF/EdataPass.cpp b/lib/ReaderWriter/PECOFF/EdataPass.cpp
new file mode 100644
index 000000000000..ad79f171f3c9
--- /dev/null
+++ b/lib/ReaderWriter/PECOFF/EdataPass.cpp
@@ -0,0 +1,227 @@
+//===- lib/ReaderWriter/PECOFF/EdataPass.cpp ------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Pass.h"
+#include "EdataPass.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Pass.h"
+#include "lld/Core/Simple.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Path.h"
+#include <climits>
+#include <ctime>
+#include <utility>
+
+using lld::pecoff::edata::EdataAtom;
+using lld::pecoff::edata::TableEntry;
+using llvm::object::export_address_table_entry;
+using llvm::object::export_directory_table_entry;
+
+namespace lld {
+namespace pecoff {
+
+typedef PECOFFLinkingContext::ExportDesc ExportDesc;
+
+// dedupExports removes duplicate export entries. If two exports are
+// referring the same symbol, they are considered duplicates.
+// This could happen if the same symbol name is specified as an argument
+// to /export more than once, or an unmangled and mangled name of the
+// same symbol are given to /export. In the latter case, we choose
+// unmangled (shorter) name.
+static void dedupExports(PECOFFLinkingContext &ctx) {
+ std::vector<ExportDesc> &exports = ctx.getDllExports();
+ // Pass 1: find duplicate entries
+ std::set<const ExportDesc *> dup;
+ std::map<StringRef, ExportDesc *> map;
+ for (ExportDesc &exp : exports) {
+ if (!exp.externalName.empty())
+ continue;
+ StringRef symbol = exp.getRealName();
+ auto it = map.find(symbol);
+ if (it == map.end()) {
+ map[symbol] = &exp;
+ } else if (symbol.size() < it->second->getRealName().size()) {
+ map[symbol] = &exp;
+ dup.insert(it->second);
+ } else {
+ dup.insert(&exp);
+ }
+ }
+ // Pass 2: remove duplicate entries
+ auto pred = [&](const ExportDesc &exp) {
+ return dup.count(&exp) == 1;
+ };
+ exports.erase(std::remove_if(exports.begin(), exports.end(), pred),
+ exports.end());
+}
+
+static void assignOrdinals(PECOFFLinkingContext &ctx) {
+ std::vector<ExportDesc> &exports = ctx.getDllExports();
+ int maxOrdinal = -1;
+ for (ExportDesc &desc : exports)
+ maxOrdinal = std::max(maxOrdinal, desc.ordinal);
+
+ std::sort(exports.begin(), exports.end(),
+ [](const ExportDesc &a, const ExportDesc &b) {
+ return a.getExternalName().compare(b.getExternalName()) < 0;
+ });
+
+ int nextOrdinal = (maxOrdinal == -1) ? 1 : (maxOrdinal + 1);
+ for (ExportDesc &desc : exports)
+ if (desc.ordinal == -1)
+ desc.ordinal = nextOrdinal++;
+}
+
+static bool getExportedAtoms(PECOFFLinkingContext &ctx, MutableFile *file,
+ std::vector<TableEntry> &ret) {
+ std::map<StringRef, const DefinedAtom *> definedAtoms;
+ for (const DefinedAtom *atom : file->defined())
+ definedAtoms[atom->name()] = atom;
+
+ for (PECOFFLinkingContext::ExportDesc &desc : ctx.getDllExports()) {
+ auto it = definedAtoms.find(desc.getRealName());
+ if (it == definedAtoms.end()) {
+ llvm::errs() << "Symbol <" << desc.name
+ << "> is exported but not defined.\n";
+ return false;
+ }
+ const DefinedAtom *atom = it->second;
+
+ // One can export a symbol with a different name than the symbol
+ // name used in DLL. If such name is specified, use it in the
+ // .edata section.
+ ret.push_back(TableEntry(ctx.undecorateSymbol(desc.getExternalName()),
+ desc.ordinal, atom, desc.noname));
+ }
+ std::sort(ret.begin(), ret.end(),
+ [](const TableEntry &a, const TableEntry &b) {
+ return a.exportName.compare(b.exportName) < 0;
+ });
+
+ return true;
+}
+
+static std::pair<int, int> getOrdinalBase(std::vector<TableEntry> &entries) {
+ int ordinalBase = INT_MAX;
+ int maxOrdinal = -1;
+ for (TableEntry &e : entries) {
+ ordinalBase = std::min(ordinalBase, e.ordinal);
+ maxOrdinal = std::max(maxOrdinal, e.ordinal);
+ }
+ return std::pair<int, int>(ordinalBase, maxOrdinal);
+}
+
+edata::EdataAtom *
+EdataPass::createAddressTable(const std::vector<TableEntry> &entries,
+ int ordinalBase, int maxOrdinal) {
+ EdataAtom *addressTable =
+ new (_alloc) EdataAtom(_file, sizeof(export_address_table_entry) *
+ (maxOrdinal - ordinalBase + 1));
+
+ for (const TableEntry &e : entries) {
+ int index = e.ordinal - ordinalBase;
+ size_t offset = index * sizeof(export_address_table_entry);
+ addDir32NBReloc(addressTable, e.atom, _ctx.getMachineType(), offset);
+ }
+ return addressTable;
+}
+
+edata::EdataAtom *
+EdataPass::createNamePointerTable(const PECOFFLinkingContext &ctx,
+ const std::vector<TableEntry> &entries,
+ MutableFile *file) {
+ EdataAtom *table =
+ new (_alloc) EdataAtom(_file, sizeof(uint32_t) * entries.size());
+
+ size_t offset = 0;
+ for (const TableEntry &e : entries) {
+ auto *stringAtom = new (_alloc) COFFStringAtom(
+ _file, _stringOrdinal++, ".edata", e.exportName);
+ file->addAtom(*stringAtom);
+ addDir32NBReloc(table, stringAtom, _ctx.getMachineType(), offset);
+ offset += sizeof(uint32_t);
+ }
+ return table;
+}
+
+edata::EdataAtom *EdataPass::createExportDirectoryTable(
+ const std::vector<edata::TableEntry> &namedEntries, int ordinalBase,
+ int maxOrdinal) {
+ EdataAtom *ret =
+ new (_alloc) EdataAtom(_file, sizeof(export_directory_table_entry));
+ auto *data = ret->getContents<export_directory_table_entry>();
+ data->TimeDateStamp = time(nullptr);
+ data->OrdinalBase = ordinalBase;
+ data->AddressTableEntries = maxOrdinal - ordinalBase + 1;
+ data->NumberOfNamePointers = namedEntries.size();
+ return ret;
+}
+
+edata::EdataAtom *
+EdataPass::createOrdinalTable(const std::vector<TableEntry> &entries,
+ int ordinalBase) {
+ EdataAtom *ret =
+ new (_alloc) EdataAtom(_file, sizeof(uint16_t) * entries.size());
+ uint16_t *data = ret->getContents<uint16_t>();
+ int i = 0;
+ for (const TableEntry &e : entries)
+ data[i++] = e.ordinal - ordinalBase;
+ return ret;
+}
+
+void EdataPass::perform(std::unique_ptr<MutableFile> &file) {
+ dedupExports(_ctx);
+ assignOrdinals(_ctx);
+
+ std::vector<TableEntry> entries;
+ if (!getExportedAtoms(_ctx, file.get(), entries))
+ return;
+ if (entries.empty())
+ return;
+
+ int ordinalBase, maxOrdinal;
+ std::tie(ordinalBase, maxOrdinal) = getOrdinalBase(entries);
+
+ std::vector<TableEntry> namedEntries;
+ for (TableEntry &e : entries)
+ if (!e.noname)
+ namedEntries.push_back(e);
+
+ EdataAtom *table =
+ createExportDirectoryTable(namedEntries, ordinalBase, maxOrdinal);
+ file->addAtom(*table);
+
+ COFFStringAtom *dllName =
+ new (_alloc) COFFStringAtom(_file, _stringOrdinal++, ".edata",
+ llvm::sys::path::filename(_ctx.outputPath()));
+ file->addAtom(*dllName);
+ addDir32NBReloc(table, dllName, _ctx.getMachineType(),
+ offsetof(export_directory_table_entry, NameRVA));
+
+ EdataAtom *addressTable =
+ createAddressTable(entries, ordinalBase, maxOrdinal);
+ file->addAtom(*addressTable);
+ addDir32NBReloc(
+ table, addressTable, _ctx.getMachineType(),
+ offsetof(export_directory_table_entry, ExportAddressTableRVA));
+
+ EdataAtom *namePointerTable =
+ createNamePointerTable(_ctx, namedEntries, file.get());
+ file->addAtom(*namePointerTable);
+ addDir32NBReloc(table, namePointerTable, _ctx.getMachineType(),
+ offsetof(export_directory_table_entry, NamePointerRVA));
+
+ EdataAtom *ordinalTable = createOrdinalTable(namedEntries, ordinalBase);
+ file->addAtom(*ordinalTable);
+ addDir32NBReloc(table, ordinalTable, _ctx.getMachineType(),
+ offsetof(export_directory_table_entry, OrdinalTableRVA));
+}
+
+} // namespace pecoff
+} // namespace lld
diff --git a/lib/ReaderWriter/PECOFF/EdataPass.h b/lib/ReaderWriter/PECOFF/EdataPass.h
new file mode 100644
index 000000000000..442be3ca24aa
--- /dev/null
+++ b/lib/ReaderWriter/PECOFF/EdataPass.h
@@ -0,0 +1,99 @@
+//===- lib/ReaderWriter/PECOFF/EdataPass.h --------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file \brief This linker pass creates atoms for the DLL export
+/// information. The defined atoms constructed in this pass will go into .edata
+/// section.
+///
+/// For the details of the .edata section format, see Microsoft PE/COFF
+/// Specification section 5.3, The .edata Section.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_PE_COFF_EDATA_PASS_H
+#define LLD_READER_WRITER_PE_COFF_EDATA_PASS_H
+
+#include "Atoms.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Pass.h"
+#include "lld/Core/Simple.h"
+#include "lld/ReaderWriter/PECOFFLinkingContext.h"
+#include "llvm/Support/COFF.h"
+#include <map>
+
+using llvm::COFF::ImportDirectoryTableEntry;
+
+namespace lld {
+namespace pecoff {
+namespace edata {
+
+struct TableEntry {
+ TableEntry(StringRef exp, int ord, const DefinedAtom *a, bool n)
+ : exportName(exp), ordinal(ord), atom(a), noname(n) {}
+ std::string exportName;
+ int ordinal;
+ const DefinedAtom *atom;
+ bool noname;
+};
+
+/// The root class of all edata atoms.
+class EdataAtom : public COFFLinkerInternalAtom {
+public:
+ EdataAtom(VirtualFile &file, size_t size)
+ : COFFLinkerInternalAtom(file, file.getNextOrdinal(),
+ std::vector<uint8_t>(size)) {}
+
+ SectionChoice sectionChoice() const override { return sectionCustomRequired; }
+ StringRef customSectionName() const override { return ".edata"; }
+ ContentType contentType() const override { return typeData; }
+ ContentPermissions permissions() const override { return permR__; }
+
+ template <typename T> T *getContents() const {
+ return (T *)const_cast<uint8_t *>(rawContent().data());
+ }
+};
+
+} // namespace edata
+
+class EdataPass : public lld::Pass {
+public:
+ EdataPass(PECOFFLinkingContext &ctx)
+ : _ctx(ctx), _file(ctx), _is64(ctx.is64Bit()), _stringOrdinal(1024) {}
+
+ void perform(std::unique_ptr<MutableFile> &file) override;
+
+private:
+ edata::EdataAtom *
+ createExportDirectoryTable(const std::vector<edata::TableEntry> &namedEntries,
+ int ordinalBase, int maxOrdinal);
+
+ edata::EdataAtom *
+ createAddressTable(const std::vector<edata::TableEntry> &entries,
+ int ordinalBase, int maxOrdinal);
+
+ edata::EdataAtom *
+ createNamePointerTable(const PECOFFLinkingContext &ctx,
+ const std::vector<edata::TableEntry> &entries,
+ MutableFile *file);
+
+ edata::EdataAtom *
+ createOrdinalTable(const std::vector<edata::TableEntry> &entries,
+ int ordinalBase);
+
+ PECOFFLinkingContext &_ctx;
+ VirtualFile _file;
+ bool _is64;
+ int _stringOrdinal;
+ mutable llvm::BumpPtrAllocator _alloc;
+};
+
+} // namespace pecoff
+} // namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/PECOFF/IdataPass.cpp b/lib/ReaderWriter/PECOFF/IdataPass.cpp
new file mode 100644
index 000000000000..d41ef581f7fa
--- /dev/null
+++ b/lib/ReaderWriter/PECOFF/IdataPass.cpp
@@ -0,0 +1,345 @@
+//===- lib/ReaderWriter/PECOFF/IdataPass.cpp ------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "IdataPass.h"
+#include "Pass.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Pass.h"
+#include "lld/Core/Simple.h"
+#include "llvm/Support/COFF.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Endian.h"
+#include <algorithm>
+#include <cstddef>
+#include <cstring>
+#include <map>
+#include <vector>
+
+using namespace llvm::support::endian;
+using llvm::object::delay_import_directory_table_entry;
+
+namespace lld {
+namespace pecoff {
+namespace idata {
+
+IdataAtom::IdataAtom(IdataContext &context, std::vector<uint8_t> data)
+ : COFFLinkerInternalAtom(context.dummyFile,
+ context.dummyFile.getNextOrdinal(), data) {
+ context.file.addAtom(*this);
+}
+
+HintNameAtom::HintNameAtom(IdataContext &context, uint16_t hint,
+ StringRef importName)
+ : IdataAtom(context, assembleRawContent(hint, importName)),
+ _importName(importName) {}
+
+std::vector<uint8_t> HintNameAtom::assembleRawContent(uint16_t hint,
+ StringRef importName) {
+ size_t size =
+ llvm::RoundUpToAlignment(sizeof(hint) + importName.size() + 1, 2);
+ std::vector<uint8_t> ret(size);
+ ret[importName.size()] = 0;
+ ret[importName.size() - 1] = 0;
+ write16le(&ret[0], hint);
+ std::memcpy(&ret[2], importName.data(), importName.size());
+ return ret;
+}
+
+std::vector<uint8_t>
+ImportTableEntryAtom::assembleRawContent(uint64_t rva, bool is64) {
+ // The element size of the import table is 32 bit in PE and 64 bit
+ // in PE+. In PE+, bits 62-31 are filled with zero.
+ if (is64) {
+ std::vector<uint8_t> ret(8);
+ write64le(&ret[0], rva);
+ return ret;
+ }
+ std::vector<uint8_t> ret(4);
+ write32le(&ret[0], rva);
+ return ret;
+}
+
+static std::vector<ImportTableEntryAtom *>
+createImportTableAtoms(IdataContext &context,
+ const std::vector<COFFSharedLibraryAtom *> &sharedAtoms,
+ bool shouldAddReference, StringRef sectionName,
+ llvm::BumpPtrAllocator &alloc) {
+ std::vector<ImportTableEntryAtom *> ret;
+ for (COFFSharedLibraryAtom *atom : sharedAtoms) {
+ ImportTableEntryAtom *entry = nullptr;
+ if (atom->importName().empty()) {
+ // Import by ordinal
+ uint64_t hint = atom->hint();
+ hint |= context.ctx.is64Bit() ? (uint64_t(1) << 63) : (uint64_t(1) << 31);
+ entry = new (alloc) ImportTableEntryAtom(context, hint, sectionName);
+ } else {
+ // Import by name
+ entry = new (alloc) ImportTableEntryAtom(context, 0, sectionName);
+ HintNameAtom *hintName =
+ new (alloc) HintNameAtom(context, atom->hint(), atom->importName());
+ addDir32NBReloc(entry, hintName, context.ctx.getMachineType(), 0);
+ }
+ ret.push_back(entry);
+ if (shouldAddReference)
+ atom->setImportTableEntry(entry);
+ }
+ // Add the NULL entry.
+ ret.push_back(new (alloc) ImportTableEntryAtom(context, 0, sectionName));
+ return ret;
+}
+
+// Creates atoms for an import lookup table. The import lookup table is an
+// array of pointers to hint/name atoms. The array needs to be terminated with
+// the NULL entry.
+void ImportDirectoryAtom::addRelocations(
+ IdataContext &context, StringRef loadName,
+ const std::vector<COFFSharedLibraryAtom *> &sharedAtoms) {
+ // Create parallel arrays. The contents of the two are initially the
+ // same. The PE/COFF loader overwrites the import address tables with the
+ // pointers to the referenced items after loading the executable into
+ // memory.
+ std::vector<ImportTableEntryAtom *> importLookupTables =
+ createImportTableAtoms(context, sharedAtoms, false, ".idata.t", _alloc);
+ std::vector<ImportTableEntryAtom *> importAddressTables =
+ createImportTableAtoms(context, sharedAtoms, true, ".idata.a", _alloc);
+
+ addDir32NBReloc(this, importLookupTables[0], context.ctx.getMachineType(),
+ offsetof(ImportDirectoryTableEntry, ImportLookupTableRVA));
+ addDir32NBReloc(this, importAddressTables[0], context.ctx.getMachineType(),
+ offsetof(ImportDirectoryTableEntry, ImportAddressTableRVA));
+ auto *atom = new (_alloc)
+ COFFStringAtom(context.dummyFile, context.dummyFile.getNextOrdinal(),
+ ".idata", loadName);
+ context.file.addAtom(*atom);
+ addDir32NBReloc(this, atom, context.ctx.getMachineType(),
+ offsetof(ImportDirectoryTableEntry, NameRVA));
+}
+
+// Create the contents for the delay-import table.
+std::vector<uint8_t> DelayImportDirectoryAtom::createContent() {
+ std::vector<uint8_t> r(sizeof(delay_import_directory_table_entry), 0);
+ auto entry = reinterpret_cast<delay_import_directory_table_entry *>(&r[0]);
+ // link.exe seems to set 1 to Attributes field, so do we.
+ entry->Attributes = 1;
+ return r;
+}
+
+// Find "___delayLoadHelper2@8" (or "__delayLoadHelper2" on x64).
+// This is not efficient but should be OK for now.
+static const Atom *
+findDelayLoadHelper(MutableFile &file, const PECOFFLinkingContext &ctx) {
+ StringRef sym = ctx.getDelayLoadHelperName();
+ for (const DefinedAtom *atom : file.defined())
+ if (atom->name() == sym)
+ return atom;
+ std::string msg = (sym + " was not found").str();
+ llvm_unreachable(msg.c_str());
+}
+
+// Create the data referred by the delay-import table.
+void DelayImportDirectoryAtom::addRelocations(
+ IdataContext &context, StringRef loadName,
+ const std::vector<COFFSharedLibraryAtom *> &sharedAtoms) {
+ // "ModuleHandle" field. This points to an array of pointer-size data
+ // in ".data" section. Initially the array is initialized with zero.
+ // The delay-load import helper will set DLL base address at runtime.
+ auto *hmodule = new (_alloc) DelayImportAddressAtom(context);
+ addDir32NBReloc(this, hmodule, context.ctx.getMachineType(),
+ offsetof(delay_import_directory_table_entry, ModuleHandle));
+
+ // "NameTable" field. The data structure of this field is the same
+ // as (non-delay) import table's Import Lookup Table. Contains
+ // imported function names. This is a parallel array of AddressTable
+ // field.
+ std::vector<ImportTableEntryAtom *> nameTable =
+ createImportTableAtoms(context, sharedAtoms, false, ".didat", _alloc);
+ addDir32NBReloc(
+ this, nameTable[0], context.ctx.getMachineType(),
+ offsetof(delay_import_directory_table_entry, DelayImportNameTable));
+
+ // "Name" field. This points to the NUL-terminated DLL name string.
+ auto *name = new (_alloc)
+ COFFStringAtom(context.dummyFile, context.dummyFile.getNextOrdinal(),
+ ".didat", loadName);
+ context.file.addAtom(*name);
+ addDir32NBReloc(this, name, context.ctx.getMachineType(),
+ offsetof(delay_import_directory_table_entry, Name));
+
+ // "AddressTable" field. This points to an array of pointers, which
+ // in turn pointing to delay-load functions.
+ std::vector<DelayImportAddressAtom *> addrTable;
+ for (int i = 0, e = sharedAtoms.size() + 1; i < e; ++i)
+ addrTable.push_back(new (_alloc) DelayImportAddressAtom(context));
+ for (int i = 0, e = sharedAtoms.size(); i < e; ++i)
+ sharedAtoms[i]->setImportTableEntry(addrTable[i]);
+ addDir32NBReloc(
+ this, addrTable[0], context.ctx.getMachineType(),
+ offsetof(delay_import_directory_table_entry, DelayImportAddressTable));
+
+ const Atom *delayLoadHelper = findDelayLoadHelper(context.file, context.ctx);
+ for (int i = 0, e = sharedAtoms.size(); i < e; ++i) {
+ const DefinedAtom *loader = new (_alloc) DelayLoaderAtom(
+ context, addrTable[i], this, delayLoadHelper);
+ if (context.ctx.is64Bit())
+ addDir64Reloc(addrTable[i], loader, context.ctx.getMachineType(), 0);
+ else
+ addDir32Reloc(addrTable[i], loader, context.ctx.getMachineType(), 0);
+ }
+}
+
+DelayLoaderAtom::DelayLoaderAtom(IdataContext &context, const Atom *impAtom,
+ const Atom *descAtom, const Atom *delayLoadHelperAtom)
+ : IdataAtom(context, createContent(context.ctx.getMachineType())) {
+ MachineTypes machine = context.ctx.getMachineType();
+ switch (machine) {
+ case llvm::COFF::IMAGE_FILE_MACHINE_I386:
+ addDir32Reloc(this, impAtom, machine, 3);
+ addDir32Reloc(this, descAtom, machine, 8);
+ addRel32Reloc(this, delayLoadHelperAtom, machine, 13);
+ break;
+ case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
+ addRel32Reloc(this, impAtom, machine, 36);
+ addRel32Reloc(this, descAtom, machine, 43);
+ addRel32Reloc(this, delayLoadHelperAtom, machine, 48);
+ break;
+ default:
+ llvm::report_fatal_error("unsupported machine type");
+ }
+}
+
+// DelayLoaderAtom contains a wrapper function for __delayLoadHelper2.
+//
+// __delayLoadHelper2 takes two pointers: a pointer to the delay-load
+// table descripter and a pointer to _imp_ symbol for the function
+// to be resolved.
+//
+// __delayLoadHelper2 looks at the table descriptor to know the DLL
+// name, calls dlopen()-like function to load it, resolves all
+// imported symbols, and then writes the resolved addresses to the
+// import address table. It returns a pointer to the resolved
+// function.
+//
+// __delayLoadHelper2 is defined in delayimp.lib.
+std::vector<uint8_t>
+DelayLoaderAtom::createContent(MachineTypes machine) const {
+ static const uint8_t x86[] = {
+ 0x51, // push ecx
+ 0x52, // push edx
+ 0x68, 0, 0, 0, 0, // push offset ___imp__<FUNCNAME>
+ 0x68, 0, 0, 0, 0, // push offset ___DELAY_IMPORT_DESCRIPTOR_<DLLNAME>_dll
+ 0xE8, 0, 0, 0, 0, // call ___delayLoadHelper2@8
+ 0x5A, // pop edx
+ 0x59, // pop ecx
+ 0xFF, 0xE0, // jmp eax
+ };
+ static const uint8_t x64[] = {
+ 0x51, // push rcx
+ 0x52, // push rdx
+ 0x41, 0x50, // push r8
+ 0x41, 0x51, // push r9
+ 0x48, 0x83, 0xEC, 0x48, // sub rsp, 48h
+ 0x66, 0x0F, 0x7F, 0x04, 0x24, // movdqa xmmword ptr [rsp], xmm0
+ 0x66, 0x0F, 0x7F, 0x4C, 0x24, 0x10, // movdqa xmmword ptr [rsp+10h], xmm1
+ 0x66, 0x0F, 0x7F, 0x54, 0x24, 0x20, // movdqa xmmword ptr [rsp+20h], xmm2
+ 0x66, 0x0F, 0x7F, 0x5C, 0x24, 0x30, // movdqa xmmword ptr [rsp+30h], xmm3
+ 0x48, 0x8D, 0x15, 0, 0, 0, 0, // lea rdx, [__imp_<FUNCNAME>]
+ 0x48, 0x8D, 0x0D, 0, 0, 0, 0, // lea rcx, [___DELAY_IMPORT_...]
+ 0xE8, 0, 0, 0, 0, // call __delayLoadHelper2
+ 0x66, 0x0F, 0x6F, 0x04, 0x24, // movdqa xmm0, xmmword ptr [rsp]
+ 0x66, 0x0F, 0x6F, 0x4C, 0x24, 0x10, // movdqa xmm1, xmmword ptr [rsp+10h]
+ 0x66, 0x0F, 0x6F, 0x54, 0x24, 0x20, // movdqa xmm2, xmmword ptr [rsp+20h]
+ 0x66, 0x0F, 0x6F, 0x5C, 0x24, 0x30, // movdqa xmm3, xmmword ptr [rsp+30h]
+ 0x48, 0x83, 0xC4, 0x48, // add rsp, 48h
+ 0x41, 0x59, // pop r9
+ 0x41, 0x58, // pop r8
+ 0x5A, // pop rdx
+ 0x59, // pop rcx
+ 0xFF, 0xE0, // jmp rax
+ };
+ switch (machine) {
+ case llvm::COFF::IMAGE_FILE_MACHINE_I386:
+ return std::vector<uint8_t>(x86, x86 + sizeof(x86));
+ case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
+ return std::vector<uint8_t>(x64, x64 + sizeof(x64));
+ default:
+ llvm::report_fatal_error("unsupported machine type");
+ }
+}
+
+} // namespace idata
+
+void IdataPass::perform(std::unique_ptr<MutableFile> &file) {
+ if (file->sharedLibrary().empty())
+ return;
+
+ idata::IdataContext context(*file, _dummyFile, _ctx);
+ std::map<StringRef, std::vector<COFFSharedLibraryAtom *>> sharedAtoms =
+ groupByLoadName(*file);
+ bool hasImports = false;
+ bool hasDelayImports = false;
+
+ // Create the import table and terminate it with the null entry.
+ for (auto i : sharedAtoms) {
+ StringRef loadName = i.first;
+ if (_ctx.isDelayLoadDLL(loadName))
+ continue;
+ hasImports = true;
+ std::vector<COFFSharedLibraryAtom *> &atoms = i.second;
+ new (_alloc) idata::ImportDirectoryAtom(context, loadName, atoms);
+ }
+ if (hasImports)
+ new (_alloc) idata::NullImportDirectoryAtom(context);
+
+ // Create the delay import table and terminate it with the null entry.
+ for (auto i : sharedAtoms) {
+ StringRef loadName = i.first;
+ if (!_ctx.isDelayLoadDLL(loadName))
+ continue;
+ hasDelayImports = true;
+ std::vector<COFFSharedLibraryAtom *> &atoms = i.second;
+ new (_alloc) idata::DelayImportDirectoryAtom(context, loadName, atoms);
+ }
+ if (hasDelayImports)
+ new (_alloc) idata::DelayNullImportDirectoryAtom(context);
+
+ replaceSharedLibraryAtoms(*file);
+}
+
+std::map<StringRef, std::vector<COFFSharedLibraryAtom *> >
+IdataPass::groupByLoadName(MutableFile &file) {
+ std::map<StringRef, COFFSharedLibraryAtom *> uniqueAtoms;
+ for (const SharedLibraryAtom *atom : file.sharedLibrary())
+ uniqueAtoms[atom->name()] =
+ (COFFSharedLibraryAtom *)const_cast<SharedLibraryAtom *>(atom);
+
+ std::map<StringRef, std::vector<COFFSharedLibraryAtom *> > ret;
+ for (auto i : uniqueAtoms) {
+ COFFSharedLibraryAtom *atom = i.second;
+ ret[atom->loadName()].push_back(atom);
+ }
+ return ret;
+}
+
+/// Transforms a reference to a COFFSharedLibraryAtom to a real reference.
+void IdataPass::replaceSharedLibraryAtoms(MutableFile &file) {
+ for (const DefinedAtom *atom : file.defined()) {
+ for (const Reference *ref : *atom) {
+ const Atom *target = ref->target();
+ auto *sharedAtom = dyn_cast<SharedLibraryAtom>(target);
+ if (!sharedAtom)
+ continue;
+ const auto *coffSharedAtom = (const COFFSharedLibraryAtom *)sharedAtom;
+ const DefinedAtom *entry = coffSharedAtom->getImportTableEntry();
+ const_cast<Reference *>(ref)->setTarget(entry);
+ }
+ }
+}
+
+} // namespace pecoff
+} // namespace lld
diff --git a/lib/ReaderWriter/PECOFF/IdataPass.h b/lib/ReaderWriter/PECOFF/IdataPass.h
new file mode 100644
index 000000000000..9db82160339a
--- /dev/null
+++ b/lib/ReaderWriter/PECOFF/IdataPass.h
@@ -0,0 +1,218 @@
+//===- lib/ReaderWriter/PECOFF/IdataPass.h---------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file \brief This linker pass creates atoms for the DLL import
+/// information. The defined atoms constructed in this pass will go into .idata
+/// section, unless .idata section is merged with other section such as .data.
+///
+/// For the details of the .idata section format, see Microsoft PE/COFF
+/// Specification section 5.4, The .idata Section.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_PE_COFF_IDATA_PASS_H
+#define LLD_READER_WRITER_PE_COFF_IDATA_PASS_H
+
+#include "Atoms.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Pass.h"
+#include "lld/Core/Simple.h"
+#include "lld/ReaderWriter/PECOFFLinkingContext.h"
+#include "llvm/Support/COFF.h"
+#include <algorithm>
+#include <map>
+
+using llvm::COFF::ImportDirectoryTableEntry;
+
+namespace lld {
+namespace pecoff {
+namespace idata {
+
+class DLLNameAtom;
+class HintNameAtom;
+class ImportTableEntryAtom;
+
+// A state object of this pass.
+struct IdataContext {
+ IdataContext(MutableFile &f, VirtualFile &g, const PECOFFLinkingContext &c)
+ : file(f), dummyFile(g), ctx(c) {}
+ MutableFile &file;
+ VirtualFile &dummyFile;
+ const PECOFFLinkingContext &ctx;
+};
+
+/// The root class of all idata atoms.
+class IdataAtom : public COFFLinkerInternalAtom {
+public:
+ SectionChoice sectionChoice() const override { return sectionCustomRequired; }
+ StringRef customSectionName() const override { return ".idata"; }
+ ContentType contentType() const override { return typeData; }
+ ContentPermissions permissions() const override { return permR__; }
+
+protected:
+ IdataAtom(IdataContext &context, std::vector<uint8_t> data);
+};
+
+/// A HintNameAtom represents a symbol that will be imported from a DLL at
+/// runtime. It consists with an optional hint, which is a small integer, and a
+/// symbol name.
+///
+/// A hint is an index of the export pointer table in a DLL. If the import
+/// library and DLL is in sync (i.e., ".lib" and ".dll" is for the same version
+/// or the symbol ordinal is maintained by hand with ".exp" file), the PE/COFF
+/// loader can find the symbol quickly.
+class HintNameAtom : public IdataAtom {
+public:
+ HintNameAtom(IdataContext &context, uint16_t hint, StringRef importName);
+
+ StringRef getContentString() { return _importName; }
+
+private:
+ std::vector<uint8_t> assembleRawContent(uint16_t hint, StringRef importName);
+ StringRef _importName;
+};
+
+class ImportTableEntryAtom : public IdataAtom {
+public:
+ ImportTableEntryAtom(IdataContext &ctx, uint64_t contents,
+ StringRef sectionName)
+ : IdataAtom(ctx, assembleRawContent(contents, ctx.ctx.is64Bit())),
+ _sectionName(sectionName) {}
+
+ StringRef customSectionName() const override {
+ return _sectionName;
+ };
+
+private:
+ std::vector<uint8_t> assembleRawContent(uint64_t contents, bool is64);
+ StringRef _sectionName;
+};
+
+/// An ImportDirectoryAtom includes information to load a DLL, including a DLL
+/// name, symbols that will be resolved from the DLL, and the import address
+/// table that are overwritten by the loader with the pointers to the referenced
+/// items. The executable has one ImportDirectoryAtom per one imported DLL.
+class ImportDirectoryAtom : public IdataAtom {
+public:
+ ImportDirectoryAtom(IdataContext &context, StringRef loadName,
+ const std::vector<COFFSharedLibraryAtom *> &sharedAtoms)
+ : IdataAtom(context, std::vector<uint8_t>(20, 0)) {
+ addRelocations(context, loadName, sharedAtoms);
+ }
+
+ StringRef customSectionName() const override { return ".idata.d"; }
+
+private:
+ void addRelocations(IdataContext &context, StringRef loadName,
+ const std::vector<COFFSharedLibraryAtom *> &sharedAtoms);
+
+ mutable llvm::BumpPtrAllocator _alloc;
+};
+
+/// The last NULL entry in the import directory.
+class NullImportDirectoryAtom : public IdataAtom {
+public:
+ explicit NullImportDirectoryAtom(IdataContext &context)
+ : IdataAtom(context, std::vector<uint8_t>(20, 0)) {}
+
+ StringRef customSectionName() const override { return ".idata.d"; }
+};
+
+/// The class for the the delay-load import table.
+class DelayImportDirectoryAtom : public IdataAtom {
+public:
+ DelayImportDirectoryAtom(
+ IdataContext &context, StringRef loadName,
+ const std::vector<COFFSharedLibraryAtom *> &sharedAtoms)
+ : IdataAtom(context, createContent()) {
+ addRelocations(context, loadName, sharedAtoms);
+ }
+
+ StringRef customSectionName() const override { return ".didat.d"; }
+
+private:
+ std::vector<uint8_t> createContent();
+ void addRelocations(IdataContext &context, StringRef loadName,
+ const std::vector<COFFSharedLibraryAtom *> &sharedAtoms);
+
+ mutable llvm::BumpPtrAllocator _alloc;
+};
+
+/// Terminator of the delay-load import table. The content of this atom is all
+/// zero.
+class DelayNullImportDirectoryAtom : public IdataAtom {
+public:
+ explicit DelayNullImportDirectoryAtom(IdataContext &context)
+ : IdataAtom(context, createContent()) {}
+ StringRef customSectionName() const override { return ".didat.d"; }
+
+private:
+ std::vector<uint8_t> createContent() const {
+ return std::vector<uint8_t>(
+ sizeof(llvm::object::delay_import_directory_table_entry), 0);
+ }
+};
+
+class DelayImportAddressAtom : public IdataAtom {
+public:
+ explicit DelayImportAddressAtom(IdataContext &context)
+ : IdataAtom(context, createContent(context.ctx)),
+ _align(Alignment(context.ctx.is64Bit() ? 3 : 2)) {}
+ StringRef customSectionName() const override { return ".data"; }
+ ContentPermissions permissions() const override { return permRW_; }
+ Alignment alignment() const override { return _align; }
+
+private:
+ std::vector<uint8_t> createContent(const PECOFFLinkingContext &ctx) const {
+ return std::vector<uint8_t>(ctx.is64Bit() ? 8 : 4, 0);
+ }
+
+ Alignment _align;
+};
+
+// DelayLoaderAtom contains a wrapper function for __delayLoadHelper2.
+class DelayLoaderAtom : public IdataAtom {
+public:
+ DelayLoaderAtom(IdataContext &context, const Atom *impAtom,
+ const Atom *descAtom, const Atom *delayLoadHelperAtom);
+ StringRef customSectionName() const override { return ".text"; }
+ ContentPermissions permissions() const override { return permR_X; }
+ Alignment alignment() const override { return Alignment(0); }
+
+private:
+ std::vector<uint8_t> createContent(MachineTypes machine) const;
+};
+
+} // namespace idata
+
+class IdataPass : public lld::Pass {
+public:
+ IdataPass(const PECOFFLinkingContext &ctx) : _dummyFile(ctx), _ctx(ctx) {}
+
+ void perform(std::unique_ptr<MutableFile> &file) override;
+
+private:
+ std::map<StringRef, std::vector<COFFSharedLibraryAtom *>>
+ groupByLoadName(MutableFile &file);
+
+ void replaceSharedLibraryAtoms(MutableFile &file);
+
+ // A dummy file with which all the atoms created in the pass will be
+ // associated. Atoms need to be associated to an input file even if it's not
+ // read from a file, so we use this object.
+ VirtualFile _dummyFile;
+
+ const PECOFFLinkingContext &_ctx;
+ llvm::BumpPtrAllocator _alloc;
+};
+
+} // namespace pecoff
+} // namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/PECOFF/InferSubsystemPass.h b/lib/ReaderWriter/PECOFF/InferSubsystemPass.h
new file mode 100644
index 000000000000..cbf863ee4784
--- /dev/null
+++ b/lib/ReaderWriter/PECOFF/InferSubsystemPass.h
@@ -0,0 +1,66 @@
+//===- lib/ReaderWriter/PECOFF/InferSubsystemPass.h ----------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_PE_COFF_INFER_SUBSYSTEM_PASS_H
+#define LLD_READER_WRITER_PE_COFF_INFER_SUBSYSTEM_PASS_H
+
+#include "Atoms.h"
+#include "lld/Core/Pass.h"
+#include <vector>
+
+namespace lld {
+namespace pecoff {
+
+// Infers subsystem from entry point function name.
+class InferSubsystemPass : public lld::Pass {
+public:
+ InferSubsystemPass(PECOFFLinkingContext &ctx) : _ctx(ctx) {}
+
+ void perform(std::unique_ptr<MutableFile> &file) override {
+ if (_ctx.getSubsystem() != WindowsSubsystem::IMAGE_SUBSYSTEM_UNKNOWN)
+ return;
+
+ if (_ctx.isDll()) {
+ _ctx.setSubsystem(WindowsSubsystem::IMAGE_SUBSYSTEM_WINDOWS_GUI);
+ return;
+ }
+
+ // Scan the resolved symbols to infer the subsystem.
+ const std::string wWinMain = _ctx.decorateSymbol("wWinMainCRTStartup");
+ const std::string wWinMainAt = _ctx.decorateSymbol("wWinMainCRTStartup@");
+ const std::string winMain = _ctx.decorateSymbol("WinMainCRTStartup");
+ const std::string winMainAt = _ctx.decorateSymbol("WinMainCRTStartup@");
+ const std::string wmain = _ctx.decorateSymbol("wmainCRTStartup");
+ const std::string wmainAt = _ctx.decorateSymbol("wmainCRTStartup@");
+ const std::string main = _ctx.decorateSymbol("mainCRTStartup");
+ const std::string mainAt = _ctx.decorateSymbol("mainCRTStartup@");
+
+ for (const DefinedAtom *atom : file->definedAtoms()) {
+ if (atom->name() == wWinMain || atom->name().startswith(wWinMainAt) ||
+ atom->name() == winMain || atom->name().startswith(winMainAt)) {
+ _ctx.setSubsystem(WindowsSubsystem::IMAGE_SUBSYSTEM_WINDOWS_GUI);
+ return;
+ }
+ if (atom->name() == wmain || atom->name().startswith(wmainAt) ||
+ atom->name() == main || atom->name().startswith(mainAt)) {
+ _ctx.setSubsystem(WindowsSubsystem::IMAGE_SUBSYSTEM_WINDOWS_CUI);
+ return;
+ }
+ }
+ llvm::report_fatal_error("Failed to infer subsystem");
+ }
+
+private:
+ PECOFFLinkingContext &_ctx;
+};
+
+} // namespace pecoff
+} // namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.cpp b/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.cpp
new file mode 100644
index 000000000000..a11410784b8c
--- /dev/null
+++ b/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.cpp
@@ -0,0 +1,48 @@
+//===- lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.cpp --------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LinkerGeneratedSymbolFile.h"
+
+namespace lld {
+namespace pecoff {
+
+// Find decorated symbol, namely /sym@[0-9]+/ or /\?sym@@.+/.
+bool findDecoratedSymbol(PECOFFLinkingContext *ctx,
+ std::string sym, std::string &res) {
+ const std::set<std::string> &defined = ctx->definedSymbols();
+ // Search for /sym@[0-9]+/
+ {
+ std::string s = sym + '@';
+ auto it = defined.lower_bound(s);
+ for (auto e = defined.end(); it != e; ++it) {
+ if (!StringRef(*it).startswith(s))
+ break;
+ if (it->size() == s.size())
+ continue;
+ StringRef suffix = StringRef(*it).substr(s.size());
+ if (suffix.find_first_not_of("0123456789") != StringRef::npos)
+ continue;
+ res = *it;
+ return true;
+ }
+ }
+ // Search for /\?sym@@.+/
+ {
+ std::string s = "?" + ctx->undecorateSymbol(sym).str() + "@@";
+ auto it = defined.lower_bound(s);
+ if (it != defined.end() && StringRef(*it).startswith(s)) {
+ res = *it;
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace pecoff
+} // namespace lld
diff --git a/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h b/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h
new file mode 100644
index 000000000000..b9764d70bb3b
--- /dev/null
+++ b/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h
@@ -0,0 +1,309 @@
+//===- lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h ----------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Atoms.h"
+#include "lld/Core/Simple.h"
+#include "lld/ReaderWriter/PECOFFLinkingContext.h"
+#include "llvm/Support/Allocator.h"
+#include <algorithm>
+#include <mutex>
+
+using llvm::COFF::WindowsSubsystem;
+
+namespace lld {
+namespace pecoff {
+
+bool findDecoratedSymbol(PECOFFLinkingContext *ctx,
+ std::string sym, std::string &res);
+
+namespace impl {
+
+/// The defined atom for dllexported symbols with __imp_ prefix.
+class ImpPointerAtom : public COFFLinkerInternalAtom {
+public:
+ ImpPointerAtom(const File &file, StringRef symbolName, uint64_t ordinal)
+ : COFFLinkerInternalAtom(file, /*oridnal*/ 0, std::vector<uint8_t>(4),
+ symbolName),
+ _ordinal(ordinal) {}
+
+ uint64_t ordinal() const override { return _ordinal; }
+ Scope scope() const override { return scopeGlobal; }
+ ContentType contentType() const override { return typeData; }
+ Alignment alignment() const override { return Alignment(4); }
+ ContentPermissions permissions() const override { return permR__; }
+
+private:
+ uint64_t _ordinal;
+};
+
+class ImpSymbolFile : public SimpleFile {
+public:
+ ImpSymbolFile(StringRef defsym, StringRef undefsym, uint64_t ordinal,
+ bool is64)
+ : SimpleFile(defsym), _undefined(*this, undefsym),
+ _defined(*this, defsym, ordinal) {
+ SimpleReference *ref;
+ if (is64) {
+ ref = new SimpleReference(Reference::KindNamespace::COFF,
+ Reference::KindArch::x86_64,
+ llvm::COFF::IMAGE_REL_AMD64_ADDR32,
+ 0, &_undefined, 0);
+ } else {
+ ref = new SimpleReference(Reference::KindNamespace::COFF,
+ Reference::KindArch::x86,
+ llvm::COFF::IMAGE_REL_I386_DIR32,
+ 0, &_undefined, 0);
+ }
+ _defined.addReference(std::unique_ptr<SimpleReference>(ref));
+ addAtom(_defined);
+ addAtom(_undefined);
+ };
+
+private:
+ SimpleUndefinedAtom _undefined;
+ ImpPointerAtom _defined;
+};
+
+// A file to make Resolver to resolve a symbol TO instead of a symbol FROM,
+// using fallback mechanism for an undefined symbol. One can virtually rename an
+// undefined symbol using this file.
+class SymbolRenameFile : public SimpleFile {
+public:
+ SymbolRenameFile(StringRef from, StringRef to)
+ : SimpleFile("<symbol-rename>"), _fromSym(from), _toSym(to),
+ _from(*this, _fromSym, &_to), _to(*this, _toSym) {
+ addAtom(_from);
+ };
+
+private:
+ std::string _fromSym;
+ std::string _toSym;
+ COFFUndefinedAtom _from;
+ COFFUndefinedAtom _to;
+};
+
+} // namespace impl
+
+// A virtual file containing absolute symbol __ImageBase. __ImageBase (or
+// ___ImageBase on x86) is a linker-generated symbol whose address is the same
+// as the image base address.
+class LinkerGeneratedSymbolFile : public SimpleFile {
+public:
+ LinkerGeneratedSymbolFile(const PECOFFLinkingContext &ctx)
+ : SimpleFile("<linker-internal-file>"),
+ _imageBaseAtom(*this, ctx.decorateSymbol("__ImageBase"),
+ Atom::scopeGlobal, ctx.getBaseAddress()) {
+ addAtom(_imageBaseAtom);
+ };
+
+private:
+ SimpleAbsoluteAtom _imageBaseAtom;
+};
+
+// A LocallyImporteSymbolFile is an archive file containing __imp_
+// symbols for local use.
+//
+// For each defined symbol, linker creates an implicit defined symbol
+// by appending "__imp_" prefix to the original name. The content of
+// the implicit symbol is a pointer to the original symbol
+// content. This feature allows one to compile and link the following
+// code without error, although _imp__hello is not defined in the
+// code. (the leading "_" in this example is automatically appended,
+// assuming it's x86.)
+//
+// void hello() { printf("Hello\n"); }
+// extern void (*_imp__hello)();
+// int main() {
+// _imp__hello();
+// return 0;
+// }
+//
+// This odd feature is for the compatibility with MSVC link.exe.
+class LocallyImportedSymbolFile : public SimpleArchiveLibraryFile {
+public:
+ LocallyImportedSymbolFile(const PECOFFLinkingContext &ctx)
+ : SimpleArchiveLibraryFile("__imp_"), _is64(ctx.is64Bit()),
+ _ordinal(0) {}
+
+ File *find(StringRef sym, bool dataSymbolOnly) override {
+ std::string prefix = "__imp_";
+ if (!sym.startswith(prefix))
+ return nullptr;
+ StringRef undef = sym.substr(prefix.size());
+ return new (_alloc) impl::ImpSymbolFile(sym, undef, _ordinal++, _is64);
+ }
+
+private:
+ bool _is64;
+ uint64_t _ordinal;
+ llvm::BumpPtrAllocator _alloc;
+};
+
+// A ExportedSymbolRenameFile is a virtual archive file for dllexported symbols.
+//
+// One usually has to specify the exact symbol name to resolve it. That's true
+// in most cases for PE/COFF, except the one described below.
+//
+// DLLExported symbols can be specified using a module definition file. In a
+// file, one can write an EXPORT directive followed by symbol names. Such
+// symbols may not be fully decorated.
+//
+// If a symbol FOO is specified to be dllexported by a module definition file,
+// linker has to search not only for /FOO/ but also for /FOO@[0-9]+/ for stdcall
+// and for /\?FOO@@.+/ for C++. This ambiguous matching semantics does not fit
+// well with Resolver.
+//
+// We could probably modify Resolver to resolve ambiguous symbols, but I think
+// we don't want to do that because it'd be rarely used, and only this Windows
+// specific feature would use it. It's probably not a good idea to make the core
+// linker to be able to deal with it.
+//
+// So, instead of tweaking Resolver, we chose to do some hack here. An
+// ExportedSymbolRenameFile maintains a set containing all possibly defined
+// symbol names. That set would be a union of (1) all the defined symbols that
+// are already parsed and read and (2) all the defined symbols in archive files
+// that are not yet be parsed.
+//
+// If Resolver asks this file to return an atom for a dllexported symbol, find()
+// looks up the set, doing ambiguous matching. If there's a symbol with @
+// prefix, it returns an atom to rename the dllexported symbol, hoping that
+// Resolver will find the new symbol with atsign from an archive file at the
+// next visit.
+class ExportedSymbolRenameFile : public SimpleArchiveLibraryFile {
+public:
+ ExportedSymbolRenameFile(const PECOFFLinkingContext &ctx)
+ : SimpleArchiveLibraryFile("<export>"),
+ _ctx(const_cast<PECOFFLinkingContext *>(&ctx)) {
+ for (PECOFFLinkingContext::ExportDesc &desc : _ctx->getDllExports())
+ _exportedSyms.insert(desc.name);
+ }
+
+ File *find(StringRef sym, bool dataSymbolOnly) override {
+ typedef PECOFFLinkingContext::ExportDesc ExportDesc;
+ if (_exportedSyms.count(sym) == 0)
+ return nullptr;
+ std::string replace;
+ if (!findDecoratedSymbol(_ctx, sym.str(), replace))
+ return nullptr;
+
+ for (ExportDesc &exp : _ctx->getDllExports())
+ if (exp.name == sym)
+ exp.mangledName = replace;
+ if (_ctx->deadStrip())
+ _ctx->addDeadStripRoot(_ctx->allocate(replace));
+ return new (_alloc) impl::SymbolRenameFile(sym, replace);
+ }
+
+private:
+ std::set<std::string> _exportedSyms;
+ llvm::BumpPtrAllocator _alloc;
+ PECOFFLinkingContext *_ctx;
+};
+
+// Windows has not only one but many entry point functions. The
+// appropriate one is automatically selected based on the subsystem
+// setting and the user-supplied entry point function.
+//
+// http://msdn.microsoft.com/en-us/library/f9t8842e.aspx
+class EntryPointFile : public SimpleFile {
+public:
+ EntryPointFile(const PECOFFLinkingContext &ctx)
+ : SimpleFile("<entry>"), _ctx(const_cast<PECOFFLinkingContext *>(&ctx)),
+ _firstTime(true) {}
+
+ const atom_collection<UndefinedAtom> &undefined() const override {
+ return const_cast<EntryPointFile *>(this)->getUndefinedAtoms();
+ }
+
+private:
+ const atom_collection<UndefinedAtom> &getUndefinedAtoms() {
+ std::lock_guard<std::mutex> lock(_mutex);
+ if (!_firstTime)
+ return _undefinedAtoms;
+ _firstTime = false;
+
+ if (_ctx->hasEntry()) {
+ StringRef entrySym = _ctx->allocate(getEntry());
+ _undefinedAtoms._atoms.push_back(
+ new (_alloc) SimpleUndefinedAtom(*this, entrySym));
+ _ctx->setHasEntry(true);
+ _ctx->setEntrySymbolName(entrySym);
+ if (_ctx->deadStrip())
+ _ctx->addDeadStripRoot(entrySym);
+ }
+ return _undefinedAtoms;
+ }
+
+ // Returns the entry point function name.
+ std::string getEntry() const {
+ StringRef opt = _ctx->getEntrySymbolName();
+ if (!opt.empty()) {
+ std::string mangled;
+ if (findDecoratedSymbol(_ctx, opt, mangled))
+ return mangled;
+ return _ctx->decorateSymbol(opt);
+ }
+ return _ctx->decorateSymbol(getDefaultEntry());
+ }
+
+ std::string getDefaultEntry() const {
+ const std::string wWinMainCRTStartup = "wWinMainCRTStartup";
+ const std::string WinMainCRTStartup = "WinMainCRTStartup";
+ const std::string wmainCRTStartup = "wmainCRTStartup";
+ const std::string mainCRTStartup = "mainCRTStartup";
+
+ if (_ctx->isDll()) {
+ if (_ctx->getMachineType() == llvm::COFF::IMAGE_FILE_MACHINE_I386)
+ return "_DllMainCRTStartup@12";
+ return "_DllMainCRTStartup";
+ }
+
+ // Returns true if a given name exists in an input object file.
+ auto defined = [&](StringRef name) -> bool {
+ StringRef sym = _ctx->decorateSymbol(name);
+ if (_ctx->definedSymbols().count(sym))
+ return true;
+ std::string ignore;
+ return findDecoratedSymbol(_ctx, sym, ignore);
+ };
+
+ switch (_ctx->getSubsystem()) {
+ case WindowsSubsystem::IMAGE_SUBSYSTEM_UNKNOWN: {
+ if (defined("wWinMain"))
+ return wWinMainCRTStartup;
+ if (defined("WinMain"))
+ return WinMainCRTStartup;
+ if (defined("wmain"))
+ return wmainCRTStartup;
+ if (!defined("main"))
+ llvm::errs() << "Cannot infer subsystem; assuming /subsystem:console\n";
+ return mainCRTStartup;
+ }
+ case WindowsSubsystem::IMAGE_SUBSYSTEM_WINDOWS_GUI:
+ if (defined("WinMain"))
+ return WinMainCRTStartup;
+ return wWinMainCRTStartup;
+ case WindowsSubsystem::IMAGE_SUBSYSTEM_WINDOWS_CUI:
+ if (defined("wmain"))
+ return wmainCRTStartup;
+ return mainCRTStartup;
+ default:
+ return mainCRTStartup;
+ }
+ }
+
+ PECOFFLinkingContext *_ctx;
+ atom_collection_vector<UndefinedAtom> _undefinedAtoms;
+ std::mutex _mutex;
+ llvm::BumpPtrAllocator _alloc;
+ bool _firstTime;
+};
+
+} // end namespace pecoff
+} // end namespace lld
diff --git a/lib/ReaderWriter/PECOFF/LoadConfigPass.cpp b/lib/ReaderWriter/PECOFF/LoadConfigPass.cpp
new file mode 100644
index 000000000000..be2f5627f4ea
--- /dev/null
+++ b/lib/ReaderWriter/PECOFF/LoadConfigPass.cpp
@@ -0,0 +1,75 @@
+//===- lib/ReaderWriter/PECOFF/LoadConfigPass.cpp -------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// A Load Configuration is a data structure for x86 containing an address of the
+// SEH handler table. The Data Directory in the file header points to a load
+// configuration. Technically that indirection is not needed but exists for
+// historical reasons.
+//
+// If the file being handled has .sxdata section containing SEH handler table,
+// this pass will create a Load Configuration atom.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Pass.h"
+#include "LoadConfigPass.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Pass.h"
+#include "lld/Core/Simple.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Path.h"
+#include <climits>
+#include <ctime>
+#include <utility>
+
+using llvm::object::coff_load_configuration32;
+
+namespace lld {
+namespace pecoff {
+namespace loadcfg {
+
+LoadConfigAtom::LoadConfigAtom(VirtualFile &file, const DefinedAtom *sxdata,
+ int count)
+ : COFFLinkerInternalAtom(
+ file, file.getNextOrdinal(),
+ std::vector<uint8_t>(sizeof(coff_load_configuration32))) {
+ addDir32Reloc(
+ this, sxdata, llvm::COFF::IMAGE_FILE_MACHINE_I386,
+ offsetof(llvm::object::coff_load_configuration32, SEHandlerTable));
+ auto *data = getContents<llvm::object::coff_load_configuration32>();
+ data->SEHandlerCount = count;
+}
+
+} // namespace loadcfg
+
+void LoadConfigPass::perform(std::unique_ptr<MutableFile> &file) {
+ if (_ctx.noSEH())
+ return;
+
+ // Find the first atom in .sxdata section.
+ const DefinedAtom *sxdata = nullptr;
+ int sectionSize = 0;
+ for (const DefinedAtom *atom : file->defined()) {
+ if (atom->customSectionName() == ".sxdata") {
+ if (!sxdata)
+ sxdata = atom;
+ sectionSize += sxdata->size();
+ }
+ }
+ if (!sxdata)
+ return;
+
+ auto *loadcfg = new (_alloc)
+ loadcfg::LoadConfigAtom(_file, sxdata, sectionSize / sizeof(uint32_t));
+ file->addAtom(*loadcfg);
+}
+
+} // namespace pecoff
+} // namespace lld
diff --git a/lib/ReaderWriter/PECOFF/LoadConfigPass.h b/lib/ReaderWriter/PECOFF/LoadConfigPass.h
new file mode 100644
index 000000000000..9f4a25f2b10e
--- /dev/null
+++ b/lib/ReaderWriter/PECOFF/LoadConfigPass.h
@@ -0,0 +1,63 @@
+//===- lib/ReaderWriter/PECOFF/LoadConfigPass.h ---------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file \brief This linker pass creates an atom for Load Configuration
+/// structure.
+///
+/// For the details of the Load Configuration structure, see Microsoft PE/COFF
+/// Specification section 5.8. The Load Configuration Structure (Image Only).
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_PE_COFF_LOAD_CONFIG_PASS_H
+#define LLD_READER_WRITER_PE_COFF_LOAD_CONFIG_PASS_H
+
+#include "Atoms.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Pass.h"
+#include "lld/Core/Simple.h"
+#include "lld/ReaderWriter/PECOFFLinkingContext.h"
+#include <map>
+
+namespace lld {
+namespace pecoff {
+namespace loadcfg {
+
+class LoadConfigAtom : public COFFLinkerInternalAtom {
+public:
+ LoadConfigAtom(VirtualFile &file, const DefinedAtom *sxdata, int count);
+
+ SectionChoice sectionChoice() const override { return sectionCustomRequired; }
+ StringRef customSectionName() const override { return ".loadcfg"; }
+ ContentType contentType() const override { return typeData; }
+ ContentPermissions permissions() const override { return permR__; }
+
+ template <typename T> T *getContents() const {
+ return (T *)const_cast<uint8_t *>(rawContent().data());
+ }
+};
+
+} // namespace loadcfg
+
+class LoadConfigPass : public lld::Pass {
+public:
+ LoadConfigPass(PECOFFLinkingContext &ctx) : _ctx(ctx), _file(ctx) {}
+
+ void perform(std::unique_ptr<MutableFile> &file) override;
+
+private:
+ PECOFFLinkingContext &_ctx;
+ VirtualFile _file;
+ mutable llvm::BumpPtrAllocator _alloc;
+};
+
+} // namespace pecoff
+} // namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/PECOFF/Makefile b/lib/ReaderWriter/PECOFF/Makefile
new file mode 100644
index 000000000000..3ad16969bba7
--- /dev/null
+++ b/lib/ReaderWriter/PECOFF/Makefile
@@ -0,0 +1,14 @@
+##===- lld/lib/ReaderWriter/PECOFF/Makefile --------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLD_LEVEL := ../../..
+LIBRARYNAME := lldPECOFF
+USEDLIBS = lldCore.a
+
+include $(LLD_LEVEL)/Makefile
diff --git a/lib/ReaderWriter/PECOFF/OrderPass.h b/lib/ReaderWriter/PECOFF/OrderPass.h
new file mode 100644
index 000000000000..73133ff73638
--- /dev/null
+++ b/lib/ReaderWriter/PECOFF/OrderPass.h
@@ -0,0 +1,67 @@
+//===- lib/ReaderWriter/PECOFF/OrderPass.h -------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file \brief This pass sorts atoms by section name, so that they will appear
+/// in the correct order in the output.
+///
+/// In COFF, sections will be merged into one section by the linker if their
+/// names are the same after discarding the "$" character and all characters
+/// follow it from their names. The characters following the "$" character
+/// determines the merge order. Assume there's an object file containing four
+/// data sections in the following order.
+///
+/// - .data$2
+/// - .data$3
+/// - .data$1
+/// - .data
+///
+/// In this case, the resulting binary should have ".data" section with the
+/// contents of ".data", ".data$1", ".data$2" and ".data$3" in that order.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_PE_COFF_ORDER_PASS_H
+#define LLD_READER_WRITER_PE_COFF_ORDER_PASS_H
+
+#include "Atoms.h"
+#include "lld/Core/Parallel.h"
+#include "lld/Core/Pass.h"
+#include <algorithm>
+
+namespace lld {
+namespace pecoff {
+
+static bool compare(const DefinedAtom *lhs, const DefinedAtom *rhs) {
+ bool lhsCustom = (lhs->sectionChoice() == DefinedAtom::sectionCustomRequired);
+ bool rhsCustom = (rhs->sectionChoice() == DefinedAtom::sectionCustomRequired);
+ if (lhsCustom && rhsCustom) {
+ int cmp = lhs->customSectionName().compare(rhs->customSectionName());
+ if (cmp != 0)
+ return cmp < 0;
+ return DefinedAtom::compareByPosition(lhs, rhs);
+ }
+ if (lhsCustom && !rhsCustom)
+ return true;
+ if (!lhsCustom && rhsCustom)
+ return false;
+ return DefinedAtom::compareByPosition(lhs, rhs);
+}
+
+class OrderPass : public lld::Pass {
+public:
+ void perform(std::unique_ptr<MutableFile> &file) override {
+ MutableFile::DefinedAtomRange defined = file->definedAtoms();
+ parallel_sort(defined.begin(), defined.end(), compare);
+ }
+};
+
+} // namespace pecoff
+} // namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/PECOFF/PDBPass.h b/lib/ReaderWriter/PECOFF/PDBPass.h
new file mode 100644
index 000000000000..0efa054db823
--- /dev/null
+++ b/lib/ReaderWriter/PECOFF/PDBPass.h
@@ -0,0 +1,43 @@
+//===- lib/ReaderWriter/PECOFF/PDBPass.h ----------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_PE_COFF_PDB_PASS_H
+#define LLD_READER_WRITER_PE_COFF_PDB_PASS_H
+
+#include "lld/Core/Pass.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Process.h"
+
+namespace lld {
+namespace pecoff {
+
+class PDBPass : public lld::Pass {
+public:
+ PDBPass(PECOFFLinkingContext &ctx) : _ctx(ctx) {}
+
+ void perform(std::unique_ptr<MutableFile> &file) override {
+ if (_ctx.getDebug())
+ touch(_ctx.getPDBFilePath());
+ }
+
+private:
+ void touch(StringRef path) {
+ int fd;
+ if (llvm::sys::fs::openFileForWrite(path, fd, llvm::sys::fs::F_Append))
+ llvm::report_fatal_error("failed to create a PDB file");
+ llvm::sys::Process::SafelyCloseFileDescriptor(fd);
+ }
+
+ PECOFFLinkingContext &_ctx;
+};
+
+} // namespace pecoff
+} // namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp b/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp
new file mode 100644
index 000000000000..6a657e33541d
--- /dev/null
+++ b/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp
@@ -0,0 +1,352 @@
+//===- lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp -------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Atoms.h"
+#include "EdataPass.h"
+#include "IdataPass.h"
+#include "InferSubsystemPass.h"
+#include "LinkerGeneratedSymbolFile.h"
+#include "LoadConfigPass.h"
+#include "OrderPass.h"
+#include "PDBPass.h"
+#include "lld/Core/PassManager.h"
+#include "lld/Core/Reader.h"
+#include "lld/Core/Simple.h"
+#include "lld/Core/Writer.h"
+#include "lld/ReaderWriter/PECOFFLinkingContext.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Path.h"
+#include <bitset>
+#include <climits>
+#include <set>
+
+namespace lld {
+
+bool PECOFFLinkingContext::validateImpl(raw_ostream &diagnostics) {
+ if (_stackReserve < _stackCommit) {
+ diagnostics << "Invalid stack size: reserve size must be equal to or "
+ << "greater than commit size, but got " << _stackCommit
+ << " and " << _stackReserve << ".\n";
+ return false;
+ }
+
+ if (_heapReserve < _heapCommit) {
+ diagnostics << "Invalid heap size: reserve size must be equal to or "
+ << "greater than commit size, but got " << _heapCommit
+ << " and " << _heapReserve << ".\n";
+ return false;
+ }
+
+ // It's an error if the base address is not multiple of 64K.
+ if (getBaseAddress() & 0xffff) {
+ diagnostics << "Base address have to be multiple of 64K, but got "
+ << getBaseAddress() << "\n";
+ return false;
+ }
+
+ // Specifing /noentry without /dll is an error.
+ if (!hasEntry() && !isDll()) {
+ diagnostics << "/noentry must be specified with /dll\n";
+ return false;
+ }
+
+ // Check for duplicate export ordinals.
+ std::set<int> exports;
+ for (const PECOFFLinkingContext::ExportDesc &desc : getDllExports()) {
+ if (desc.ordinal == -1)
+ continue;
+ if (exports.count(desc.ordinal) == 1) {
+ diagnostics << "Duplicate export ordinals: " << desc.ordinal << "\n";
+ return false;
+ }
+ exports.insert(desc.ordinal);
+ }
+
+ // Check for /align.
+ std::bitset<64> alignment(_sectionDefaultAlignment);
+ if (alignment.count() != 1) {
+ diagnostics << "Section alignment must be a power of 2, but got "
+ << _sectionDefaultAlignment << "\n";
+ return false;
+ }
+
+ _writer = createWriterPECOFF(*this);
+ return true;
+}
+
+const std::set<std::string> &PECOFFLinkingContext::definedSymbols() {
+ std::lock_guard<std::recursive_mutex> lock(_mutex);
+ for (std::unique_ptr<Node> &node : getNodes()) {
+ if (_seen.count(node.get()) > 0)
+ continue;
+ FileNode *fnode = dyn_cast<FileNode>(node.get());
+ if (!fnode)
+ continue;
+ File *file = fnode->getFile();
+ if (file->parse())
+ continue;
+ if (auto *archive = dyn_cast<ArchiveLibraryFile>(file)) {
+ for (const std::string &sym : archive->getDefinedSymbols())
+ _definedSyms.insert(sym);
+ continue;
+ }
+ for (const DefinedAtom *atom : file->defined())
+ if (!atom->name().empty())
+ _definedSyms.insert(atom->name());
+ }
+ return _definedSyms;
+}
+
+std::unique_ptr<File> PECOFFLinkingContext::createEntrySymbolFile() const {
+ return LinkingContext::createEntrySymbolFile("<command line option /entry>");
+}
+
+std::unique_ptr<File> PECOFFLinkingContext::createUndefinedSymbolFile() const {
+ return LinkingContext::createUndefinedSymbolFile(
+ "<command line option /include>");
+}
+
+static int getGroupStartPos(std::vector<std::unique_ptr<Node>> &nodes) {
+ for (int i = 0, e = nodes.size(); i < e; ++i)
+ if (GroupEnd *group = dyn_cast<GroupEnd>(nodes[i].get()))
+ return i - group->getSize();
+ llvm::report_fatal_error("internal error");
+}
+
+void PECOFFLinkingContext::addLibraryFile(std::unique_ptr<FileNode> file) {
+ GroupEnd *currentGroupEnd;
+ int pos = -1;
+ std::vector<std::unique_ptr<Node>> &elements = getNodes();
+ for (int i = 0, e = elements.size(); i < e; ++i) {
+ if ((currentGroupEnd = dyn_cast<GroupEnd>(elements[i].get()))) {
+ pos = i;
+ break;
+ }
+ }
+ assert(pos >= 0);
+ elements.insert(elements.begin() + pos, std::move(file));
+ elements[pos + 1] = llvm::make_unique<GroupEnd>(
+ currentGroupEnd->getSize() + 1);
+}
+
+bool PECOFFLinkingContext::createImplicitFiles(
+ std::vector<std::unique_ptr<File>> &) {
+ std::vector<std::unique_ptr<Node>> &members = getNodes();
+
+ // Create a file for the entry point function.
+ std::unique_ptr<FileNode> entry(new FileNode(
+ llvm::make_unique<pecoff::EntryPointFile>(*this)));
+ members.insert(members.begin() + getGroupStartPos(members), std::move(entry));
+
+ // Create a file for __ImageBase.
+ std::unique_ptr<FileNode> fileNode(new FileNode(
+ llvm::make_unique<pecoff::LinkerGeneratedSymbolFile>(*this)));
+ members.push_back(std::move(fileNode));
+
+ // Create a file for _imp_ symbols.
+ std::unique_ptr<FileNode> impFileNode(new FileNode(
+ llvm::make_unique<pecoff::LocallyImportedSymbolFile>(*this)));
+ members.push_back(std::move(impFileNode));
+
+ // Create a file for dllexported symbols.
+ std::unique_ptr<FileNode> exportNode(new FileNode(
+ llvm::make_unique<pecoff::ExportedSymbolRenameFile>(*this)));
+ addLibraryFile(std::move(exportNode));
+
+ return true;
+}
+
+/// Returns the section name in the resulting executable.
+///
+/// Sections in object files are usually output to the executable with the same
+/// name, but you can rename by command line option. /merge:from=to makes the
+/// linker to combine "from" section contents to "to" section in the
+/// executable. We have a mapping for the renaming. This method looks up the
+/// table and returns a new section name if renamed.
+StringRef
+PECOFFLinkingContext::getOutputSectionName(StringRef sectionName) const {
+ auto it = _renamedSections.find(sectionName);
+ if (it == _renamedSections.end())
+ return sectionName;
+ return getOutputSectionName(it->second);
+}
+
+/// Adds a mapping to the section renaming table. This method will be used for
+/// /merge command line option.
+bool PECOFFLinkingContext::addSectionRenaming(raw_ostream &diagnostics,
+ StringRef from, StringRef to) {
+ auto it = _renamedSections.find(from);
+ if (it != _renamedSections.end()) {
+ if (it->second == to)
+ // There's already the same mapping.
+ return true;
+ diagnostics << "Section \"" << from << "\" is already mapped to \""
+ << it->second << ", so it cannot be mapped to \"" << to << "\".";
+ return true;
+ }
+
+ // Add a mapping, and check if there's no cycle in the renaming mapping. The
+ // cycle detection algorithm we use here is naive, but that's OK because the
+ // number of mapping is usually less than 10.
+ _renamedSections[from] = to;
+ for (auto elem : _renamedSections) {
+ StringRef sectionName = elem.first;
+ std::set<StringRef> visited;
+ visited.insert(sectionName);
+ for (;;) {
+ auto pos = _renamedSections.find(sectionName);
+ if (pos == _renamedSections.end())
+ break;
+ if (visited.count(pos->second)) {
+ diagnostics << "/merge:" << from << "=" << to << " makes a cycle";
+ return false;
+ }
+ sectionName = pos->second;
+ visited.insert(sectionName);
+ }
+ }
+ return true;
+}
+
+/// Try to find the input library file from the search paths and append it to
+/// the input file list. Returns true if the library file is found.
+StringRef PECOFFLinkingContext::searchLibraryFile(StringRef filename) const {
+ // Current directory always takes precedence over the search paths.
+ if (llvm::sys::path::is_absolute(filename) || llvm::sys::fs::exists(filename))
+ return filename;
+ // Iterate over the search paths.
+ for (StringRef dir : _inputSearchPaths) {
+ SmallString<128> path = dir;
+ llvm::sys::path::append(path, filename);
+ if (llvm::sys::fs::exists(path.str()))
+ return allocate(path.str());
+ }
+ return filename;
+}
+
+/// Returns the decorated name of the given symbol name. On 32-bit x86, it
+/// adds "_" at the beginning of the string. On other architectures, the
+/// return value is the same as the argument.
+StringRef PECOFFLinkingContext::decorateSymbol(StringRef name) const {
+ if (_machineType != llvm::COFF::IMAGE_FILE_MACHINE_I386)
+ return name;
+ std::string str = "_";
+ str.append(name);
+ return allocate(str);
+}
+
+StringRef PECOFFLinkingContext::undecorateSymbol(StringRef name) const {
+ if (_machineType != llvm::COFF::IMAGE_FILE_MACHINE_I386)
+ return name;
+ if (!name.startswith("_"))
+ return name;
+ return name.substr(1);
+}
+
+uint64_t PECOFFLinkingContext::getBaseAddress() const {
+ if (_baseAddress == invalidBaseAddress)
+ return is64Bit() ? pe32PlusDefaultBaseAddress : pe32DefaultBaseAddress;
+ return _baseAddress;
+}
+
+Writer &PECOFFLinkingContext::writer() const { return *_writer; }
+
+void PECOFFLinkingContext::setSectionSetMask(StringRef sectionName,
+ uint32_t newFlags) {
+ _sectionSetMask[sectionName] |= newFlags;
+ _sectionClearMask[sectionName] &= ~newFlags;
+ const uint32_t rwx = (llvm::COFF::IMAGE_SCN_MEM_READ |
+ llvm::COFF::IMAGE_SCN_MEM_WRITE |
+ llvm::COFF::IMAGE_SCN_MEM_EXECUTE);
+ if (newFlags & rwx)
+ _sectionClearMask[sectionName] |= ~_sectionSetMask[sectionName] & rwx;
+ assert((_sectionSetMask[sectionName] & _sectionClearMask[sectionName]) == 0);
+}
+
+void PECOFFLinkingContext::setSectionClearMask(StringRef sectionName,
+ uint32_t newFlags) {
+ _sectionClearMask[sectionName] |= newFlags;
+ _sectionSetMask[sectionName] &= ~newFlags;
+ assert((_sectionSetMask[sectionName] & _sectionClearMask[sectionName]) == 0);
+}
+
+uint32_t PECOFFLinkingContext::getSectionAttributes(StringRef sectionName,
+ uint32_t flags) const {
+ auto si = _sectionSetMask.find(sectionName);
+ uint32_t setMask = (si == _sectionSetMask.end()) ? 0 : si->second;
+ auto ci = _sectionClearMask.find(sectionName);
+ uint32_t clearMask = (ci == _sectionClearMask.end()) ? 0 : ci->second;
+ return (flags | setMask) & ~clearMask;
+}
+
+// Returns true if two export descriptors are the same.
+static bool sameExportDesc(const PECOFFLinkingContext::ExportDesc &a,
+ const PECOFFLinkingContext::ExportDesc &b) {
+ return a.ordinal == b.ordinal && a.ordinal == b.ordinal &&
+ a.noname == b.noname && a.isData == b.isData;
+}
+
+void PECOFFLinkingContext::addDllExport(ExportDesc &desc) {
+ addInitialUndefinedSymbol(allocate(desc.name));
+
+ // MSVC link.exe silently drops characters after the first atsign.
+ // For example, /export:foo@4=bar is equivalent to /export:foo=bar.
+ // We do the same thing for compatibility.
+ if (!desc.externalName.empty()) {
+ StringRef s(desc.externalName);
+ size_t pos = s.find('@');
+ if (pos != s.npos)
+ desc.externalName = s.substr(0, pos);
+ }
+
+ // Scan the vector to look for existing entry. It's not very fast,
+ // but because the number of exported symbol is usually not that
+ // much, it should be okay.
+ for (ExportDesc &e : _dllExports) {
+ if (e.name != desc.name)
+ continue;
+ if (!sameExportDesc(e, desc))
+ llvm::errs() << "Export symbol '" << desc.name
+ << "' specified more than once.\n";
+ return;
+ }
+ _dllExports.push_back(desc);
+}
+
+static std::string replaceExtension(StringRef path, StringRef ext) {
+ SmallString<128> ss = path;
+ llvm::sys::path::replace_extension(ss, ext);
+ return ss.str();
+}
+
+std::string PECOFFLinkingContext::getOutputImportLibraryPath() const {
+ if (!_implib.empty())
+ return _implib;
+ return replaceExtension(outputPath(), ".lib");
+}
+
+std::string PECOFFLinkingContext::getPDBFilePath() const {
+ assert(_debug);
+ if (!_pdbFilePath.empty())
+ return _pdbFilePath;
+ return replaceExtension(outputPath(), ".pdb");
+}
+
+void PECOFFLinkingContext::addPasses(PassManager &pm) {
+ pm.add(llvm::make_unique<pecoff::PDBPass>(*this));
+ pm.add(llvm::make_unique<pecoff::EdataPass>(*this));
+ pm.add(llvm::make_unique<pecoff::IdataPass>(*this));
+ pm.add(llvm::make_unique<pecoff::OrderPass>());
+ pm.add(llvm::make_unique<pecoff::LoadConfigPass>(*this));
+ pm.add(llvm::make_unique<pecoff::InferSubsystemPass>(*this));
+}
+
+} // end namespace lld
diff --git a/lib/ReaderWriter/PECOFF/Pass.cpp b/lib/ReaderWriter/PECOFF/Pass.cpp
new file mode 100644
index 000000000000..ed731984e378
--- /dev/null
+++ b/lib/ReaderWriter/PECOFF/Pass.cpp
@@ -0,0 +1,95 @@
+//===- lib/ReaderWriter/PECOFF/Pass.cpp -----------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Atoms.h"
+#include "Pass.h"
+#include "lld/Core/File.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/COFF.h"
+
+namespace lld {
+namespace pecoff {
+
+static void addReloc(COFFBaseDefinedAtom *atom, const Atom *target,
+ size_t offsetInAtom, Reference::KindArch arch,
+ Reference::KindValue relType) {
+ atom->addReference(llvm::make_unique<SimpleReference>(
+ Reference::KindNamespace::COFF, arch, relType, offsetInAtom, target, 0));
+}
+
+void addDir64Reloc(COFFBaseDefinedAtom *atom, const Atom *target,
+ llvm::COFF::MachineTypes machine, size_t offsetInAtom) {
+ switch (machine) {
+ case llvm::COFF::IMAGE_FILE_MACHINE_I386:
+ addReloc(atom, target, offsetInAtom, Reference::KindArch::x86,
+ llvm::COFF::IMAGE_REL_I386_DIR32);
+ return;
+ case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
+ addReloc(atom, target, offsetInAtom, Reference::KindArch::x86_64,
+ llvm::COFF::IMAGE_REL_AMD64_ADDR64);
+ return;
+ default:
+ llvm_unreachable("unsupported machine type");
+ }
+}
+
+void addDir32Reloc(COFFBaseDefinedAtom *atom, const Atom *target,
+ llvm::COFF::MachineTypes machine, size_t offsetInAtom) {
+ switch (machine) {
+ case llvm::COFF::IMAGE_FILE_MACHINE_I386:
+ addReloc(atom, target, offsetInAtom, Reference::KindArch::x86,
+ llvm::COFF::IMAGE_REL_I386_DIR32);
+ return;
+ case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
+ addReloc(atom, target, offsetInAtom, Reference::KindArch::x86_64,
+ llvm::COFF::IMAGE_REL_AMD64_ADDR32);
+ return;
+ default:
+ llvm_unreachable("unsupported machine type");
+ }
+}
+
+void addDir32NBReloc(COFFBaseDefinedAtom *atom, const Atom *target,
+ llvm::COFF::MachineTypes machine, size_t offsetInAtom) {
+ switch (machine) {
+ case llvm::COFF::IMAGE_FILE_MACHINE_I386:
+ addReloc(atom, target, offsetInAtom, Reference::KindArch::x86,
+ llvm::COFF::IMAGE_REL_I386_DIR32NB);
+ return;
+ case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
+ addReloc(atom, target, offsetInAtom, Reference::KindArch::x86_64,
+ llvm::COFF::IMAGE_REL_AMD64_ADDR32NB);
+ return;
+ case llvm::COFF::IMAGE_FILE_MACHINE_ARMNT:
+ addReloc(atom, target, offsetInAtom, Reference::KindArch::ARM,
+ llvm::COFF::IMAGE_REL_ARM_ADDR32NB);
+ return;
+ default:
+ llvm_unreachable("unsupported machine type");
+ }
+}
+
+void addRel32Reloc(COFFBaseDefinedAtom *atom, const Atom *target,
+ llvm::COFF::MachineTypes machine, size_t offsetInAtom) {
+ switch (machine) {
+ case llvm::COFF::IMAGE_FILE_MACHINE_I386:
+ addReloc(atom, target, offsetInAtom, Reference::KindArch::x86,
+ llvm::COFF::IMAGE_REL_I386_REL32);
+ return;
+ case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
+ addReloc(atom, target, offsetInAtom, Reference::KindArch::x86_64,
+ llvm::COFF::IMAGE_REL_AMD64_REL32);
+ return;
+ default:
+ llvm_unreachable("unsupported machine type");
+ }
+}
+
+} // end namespace pecoff
+} // end namespace lld
diff --git a/lib/ReaderWriter/PECOFF/Pass.h b/lib/ReaderWriter/PECOFF/Pass.h
new file mode 100644
index 000000000000..22466f77859e
--- /dev/null
+++ b/lib/ReaderWriter/PECOFF/Pass.h
@@ -0,0 +1,34 @@
+//===- lib/ReaderWriter/PECOFF/Pass.h -------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_PE_COFF_PASS_H
+#define LLD_READER_WRITER_PE_COFF_PASS_H
+
+#include "Atoms.h"
+#include "llvm/Support/COFF.h"
+
+namespace lld {
+namespace pecoff {
+
+void addDir64Reloc(COFFBaseDefinedAtom *atom, const Atom *target,
+ llvm::COFF::MachineTypes machine, size_t offsetInAtom);
+
+void addDir32Reloc(COFFBaseDefinedAtom *atom, const Atom *target,
+ llvm::COFF::MachineTypes machine, size_t offsetInAtom);
+
+void addDir32NBReloc(COFFBaseDefinedAtom *atom, const Atom *target,
+ llvm::COFF::MachineTypes machine, size_t offsetInAtom);
+
+void addRel32Reloc(COFFBaseDefinedAtom *atom, const Atom *target,
+ llvm::COFF::MachineTypes machine, size_t offsetInAtom);
+
+} // namespace pecoff
+} // namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp b/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp
new file mode 100644
index 000000000000..f060bd8dc0bc
--- /dev/null
+++ b/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp
@@ -0,0 +1,1140 @@
+//===- lib/ReaderWriter/PECOFF/ReaderCOFF.cpp -----------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Atoms.h"
+#include "lld/Core/Alias.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Reader.h"
+#include "lld/Driver/Driver.h"
+#include "lld/ReaderWriter/PECOFFLinkingContext.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/FileUtilities.h"
+#include "llvm/Support/Memory.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <map>
+#include <mutex>
+#include <set>
+#include <system_error>
+#include <vector>
+
+#define DEBUG_TYPE "ReaderCOFF"
+
+using lld::pecoff::COFFBSSAtom;
+using lld::pecoff::COFFDefinedAtom;
+using lld::pecoff::COFFDefinedFileAtom;
+using lld::pecoff::COFFUndefinedAtom;
+using llvm::object::coff_aux_section_definition;
+using llvm::object::coff_aux_weak_external;
+using llvm::object::coff_relocation;
+using llvm::object::coff_section;
+using llvm::object::coff_symbol;
+using llvm::support::ulittle32_t;
+
+using namespace lld;
+
+namespace {
+
+class BumpPtrStringSaver : public llvm::cl::StringSaver {
+public:
+ const char *SaveString(const char *str) override {
+ size_t len = strlen(str);
+ std::lock_guard<std::mutex> lock(_allocMutex);
+ char *copy = _alloc.Allocate<char>(len + 1);
+ memcpy(copy, str, len + 1);
+ return copy;
+ }
+
+private:
+ llvm::BumpPtrAllocator _alloc;
+ std::mutex _allocMutex;
+};
+
+class FileCOFF : public File {
+private:
+ typedef std::vector<llvm::object::COFFSymbolRef> SymbolVectorT;
+ typedef std::map<const coff_section *, SymbolVectorT> SectionToSymbolsT;
+
+public:
+ FileCOFF(std::unique_ptr<MemoryBuffer> mb, PECOFFLinkingContext &ctx)
+ : File(mb->getBufferIdentifier(), kindObject), _mb(std::move(mb)),
+ _compatibleWithSEH(false), _ordinal(1),
+ _machineType(llvm::COFF::MT_Invalid), _ctx(ctx) {}
+
+ std::error_code doParse() override;
+ bool isCompatibleWithSEH() const { return _compatibleWithSEH; }
+ llvm::COFF::MachineTypes getMachineType() { return _machineType; }
+
+ const atom_collection<DefinedAtom> &defined() const override {
+ return _definedAtoms;
+ }
+
+ const atom_collection<UndefinedAtom> &undefined() const override {
+ return _undefinedAtoms;
+ }
+
+ const atom_collection<SharedLibraryAtom> &sharedLibrary() const override {
+ return _sharedLibraryAtoms;
+ }
+
+ const atom_collection<AbsoluteAtom> &absolute() const override {
+ return _absoluteAtoms;
+ }
+
+ void beforeLink() override;
+
+ void addUndefinedSymbol(StringRef sym) {
+ _undefinedAtoms._atoms.push_back(new (_alloc) COFFUndefinedAtom(*this, sym));
+ }
+
+ AliasAtom *createAlias(StringRef name, const DefinedAtom *target, int cnt);
+ void createAlternateNameAtoms();
+ std::error_code parseDirectiveSection(StringRef directives);
+
+ mutable llvm::BumpPtrAllocator _alloc;
+
+private:
+ std::error_code readSymbolTable(SymbolVectorT &result);
+
+ void createAbsoluteAtoms(const SymbolVectorT &symbols,
+ std::vector<const AbsoluteAtom *> &result);
+
+ std::error_code
+ createUndefinedAtoms(const SymbolVectorT &symbols,
+ std::vector<const UndefinedAtom *> &result);
+
+ std::error_code
+ createDefinedSymbols(const SymbolVectorT &symbols,
+ std::vector<const DefinedAtom *> &result);
+
+ std::error_code cacheSectionAttributes();
+ std::error_code maybeCreateSXDataAtoms();
+
+ std::error_code
+ AtomizeDefinedSymbolsInSection(const coff_section *section,
+ SymbolVectorT &symbols,
+ std::vector<COFFDefinedFileAtom *> &atoms);
+
+ std::error_code
+ AtomizeDefinedSymbols(SectionToSymbolsT &definedSymbols,
+ std::vector<const DefinedAtom *> &definedAtoms);
+
+ std::error_code findAtomAt(const coff_section *section,
+ uint32_t targetAddress,
+ COFFDefinedFileAtom *&result,
+ uint32_t &offsetInAtom);
+
+ std::error_code getAtomBySymbolIndex(uint32_t index, Atom *&ret);
+
+ std::error_code
+ addRelocationReference(const coff_relocation *rel,
+ const coff_section *section);
+
+ std::error_code getSectionContents(StringRef sectionName,
+ ArrayRef<uint8_t> &result);
+ std::error_code getReferenceArch(Reference::KindArch &result);
+ std::error_code addRelocationReferenceToAtoms();
+ std::error_code findSection(StringRef name, const coff_section *&result);
+ StringRef ArrayRefToString(ArrayRef<uint8_t> array);
+ uint64_t getNextOrdinal();
+
+ std::unique_ptr<const llvm::object::COFFObjectFile> _obj;
+ std::unique_ptr<MemoryBuffer> _mb;
+ atom_collection_vector<DefinedAtom> _definedAtoms;
+ atom_collection_vector<UndefinedAtom> _undefinedAtoms;
+ atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
+ atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
+
+ // The target type of the object.
+ Reference::KindArch _referenceArch;
+
+ // True if the object has "@feat.00" symbol.
+ bool _compatibleWithSEH;
+
+ // A map from symbol to its name. All symbols should be in this map except
+ // unnamed ones.
+ std::map<llvm::object::COFFSymbolRef, StringRef> _symbolName;
+
+ // A map from symbol to its resultant atom.
+ std::map<llvm::object::COFFSymbolRef, Atom *> _symbolAtom;
+
+ // A map from symbol to its aux symbol.
+ std::map<llvm::object::COFFSymbolRef, llvm::object::COFFSymbolRef> _auxSymbol;
+
+ // A map from section to its atoms.
+ std::map<const coff_section *, std::vector<COFFDefinedFileAtom *>>
+ _sectionAtoms;
+
+ // A set of COMDAT sections.
+ std::set<const coff_section *> _comdatSections;
+
+ // A map to get whether the section allows its contents to be merged or not.
+ std::map<const coff_section *, DefinedAtom::Merge> _merge;
+
+ // COMDAT associative sections
+ std::multimap<const coff_section *, const coff_section *> _association;
+
+ // A sorted map to find an atom from a section and an offset within
+ // the section.
+ std::map<const coff_section *, std::multimap<uint32_t, COFFDefinedAtom *>>
+ _definedAtomLocations;
+
+ uint64_t _ordinal;
+ llvm::COFF::MachineTypes _machineType;
+ PECOFFLinkingContext &_ctx;
+ mutable BumpPtrStringSaver _stringSaver;
+};
+
+// Converts the COFF symbol attribute to the LLD's atom attribute.
+Atom::Scope getScope(llvm::object::COFFSymbolRef symbol) {
+ switch (symbol.getStorageClass()) {
+ case llvm::COFF::IMAGE_SYM_CLASS_EXTERNAL:
+ return Atom::scopeGlobal;
+ case llvm::COFF::IMAGE_SYM_CLASS_STATIC:
+ case llvm::COFF::IMAGE_SYM_CLASS_LABEL:
+ return Atom::scopeTranslationUnit;
+ }
+ llvm_unreachable("Unknown scope");
+}
+
+DefinedAtom::ContentType getContentType(const coff_section *section) {
+ if (section->Characteristics & llvm::COFF::IMAGE_SCN_CNT_CODE)
+ return DefinedAtom::typeCode;
+ if (section->Characteristics & llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA)
+ return DefinedAtom::typeData;
+ if (section->Characteristics & llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)
+ return DefinedAtom::typeZeroFill;
+ return DefinedAtom::typeUnknown;
+}
+
+DefinedAtom::ContentPermissions getPermissions(const coff_section *section) {
+ if (section->Characteristics & llvm::COFF::IMAGE_SCN_MEM_READ &&
+ section->Characteristics & llvm::COFF::IMAGE_SCN_MEM_WRITE)
+ return DefinedAtom::permRW_;
+ if (section->Characteristics & llvm::COFF::IMAGE_SCN_MEM_READ &&
+ section->Characteristics & llvm::COFF::IMAGE_SCN_MEM_EXECUTE)
+ return DefinedAtom::permR_X;
+ if (section->Characteristics & llvm::COFF::IMAGE_SCN_MEM_READ)
+ return DefinedAtom::permR__;
+ return DefinedAtom::perm___;
+}
+
+/// Returns the alignment of the section. The contents of the section must be
+/// aligned by this value in the resulting executable/DLL.
+DefinedAtom::Alignment getAlignment(const coff_section *section) {
+ if (section->Characteristics & llvm::COFF::IMAGE_SCN_TYPE_NO_PAD)
+ return DefinedAtom::Alignment(0);
+
+ // Bit [20:24] contains section alignment information. We need to decrease
+ // the value stored by 1 in order to get the real exponent (e.g, ALIGN_1BYTE
+ // is 0x00100000, but the exponent should be 0)
+ uint32_t characteristics = (section->Characteristics >> 20) & 0xf;
+
+ // If all bits are off, we treat it as if ALIGN_1BYTE was on. The PE/COFF spec
+ // does not say anything about this case, but CVTRES.EXE does not set any bit
+ // in characteristics[20:24], and its output is intended to be copied to .rsrc
+ // section with no padding, so I think doing this is the right thing.
+ if (characteristics == 0)
+ return DefinedAtom::Alignment(0);
+
+ uint32_t powerOf2 = characteristics - 1;
+ return DefinedAtom::Alignment(powerOf2);
+}
+
+DefinedAtom::Merge getMerge(const coff_aux_section_definition *auxsym) {
+ switch (auxsym->Selection) {
+ case llvm::COFF::IMAGE_COMDAT_SELECT_NODUPLICATES:
+ return DefinedAtom::mergeNo;
+ case llvm::COFF::IMAGE_COMDAT_SELECT_ANY:
+ return DefinedAtom::mergeAsWeakAndAddressUsed;
+ case llvm::COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH:
+ // TODO: This mapping is wrong. Fix it.
+ return DefinedAtom::mergeByContent;
+ case llvm::COFF::IMAGE_COMDAT_SELECT_SAME_SIZE:
+ return DefinedAtom::mergeSameNameAndSize;
+ case llvm::COFF::IMAGE_COMDAT_SELECT_LARGEST:
+ return DefinedAtom::mergeByLargestSection;
+ case llvm::COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE:
+ case llvm::COFF::IMAGE_COMDAT_SELECT_NEWEST:
+ // FIXME: These attributes has more complicated semantics than the regular
+ // weak symbol. These are mapped to mergeAsWeakAndAddressUsed for now
+ // because the core linker does not support them yet. We eventually have
+ // to implement them for full COFF support.
+ return DefinedAtom::mergeAsWeakAndAddressUsed;
+ default:
+ llvm_unreachable("Unknown merge type");
+ }
+}
+
+StringRef getMachineName(llvm::COFF::MachineTypes Type) {
+ switch (Type) {
+ default: llvm_unreachable("unsupported machine type");
+ case llvm::COFF::IMAGE_FILE_MACHINE_ARMNT:
+ return "ARM";
+ case llvm::COFF::IMAGE_FILE_MACHINE_I386:
+ return "X86";
+ case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
+ return "X64";
+ }
+}
+
+std::error_code FileCOFF::doParse() {
+ auto binaryOrErr = llvm::object::createBinary(_mb->getMemBufferRef());
+ if (std::error_code ec = binaryOrErr.getError())
+ return ec;
+ std::unique_ptr<llvm::object::Binary> bin = std::move(binaryOrErr.get());
+
+ _obj.reset(dyn_cast<const llvm::object::COFFObjectFile>(bin.get()));
+ if (!_obj)
+ return make_error_code(llvm::object::object_error::invalid_file_type);
+ bin.release();
+
+ _machineType = static_cast<llvm::COFF::MachineTypes>(_obj->getMachine());
+
+ if (getMachineType() != llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN &&
+ getMachineType() != _ctx.getMachineType()) {
+ llvm::errs() << "module machine type '"
+ << getMachineName(getMachineType())
+ << "' conflicts with target machine type '"
+ << getMachineName(_ctx.getMachineType()) << "'\n";
+ return NativeReaderError::conflicting_target_machine;
+ }
+
+ if (std::error_code ec = getReferenceArch(_referenceArch))
+ return ec;
+
+ // Read the symbol table and atomize them if possible. Defined atoms
+ // cannot be atomized in one pass, so they will be not be atomized but
+ // added to symbolToAtom.
+ SymbolVectorT symbols;
+ if (std::error_code ec = readSymbolTable(symbols))
+ return ec;
+
+ createAbsoluteAtoms(symbols, _absoluteAtoms._atoms);
+ if (std::error_code ec =
+ createUndefinedAtoms(symbols, _undefinedAtoms._atoms))
+ return ec;
+ if (std::error_code ec = createDefinedSymbols(symbols, _definedAtoms._atoms))
+ return ec;
+ if (std::error_code ec = addRelocationReferenceToAtoms())
+ return ec;
+ if (std::error_code ec = maybeCreateSXDataAtoms())
+ return ec;
+
+ // Check for /SAFESEH.
+ if (_ctx.requireSEH() && !isCompatibleWithSEH()) {
+ llvm::errs() << "/SAFESEH is specified, but "
+ << _mb->getBufferIdentifier()
+ << " is not compatible with SEH.\n";
+ return llvm::object::object_error::parse_failed;
+ }
+ return std::error_code();
+}
+
+void FileCOFF::beforeLink() {
+ // Acquire the mutex to mutate _ctx.
+ std::lock_guard<std::recursive_mutex> lock(_ctx.getMutex());
+ std::set<StringRef> undefSyms;
+
+ // Interpret .drectve section if the section has contents.
+ ArrayRef<uint8_t> directives;
+ if (getSectionContents(".drectve", directives))
+ return;
+ if (!directives.empty()) {
+ std::set<StringRef> orig;
+ for (StringRef sym : _ctx.initialUndefinedSymbols())
+ orig.insert(sym);
+ if (parseDirectiveSection(ArrayRefToString(directives)))
+ return;
+ for (StringRef sym : _ctx.initialUndefinedSymbols())
+ if (orig.count(sym) == 0)
+ undefSyms.insert(sym);
+ }
+
+ // Add /INCLUDE'ed symbols to the file as if they existed in the
+ // file as undefined symbols.
+ for (StringRef sym : undefSyms) {
+ addUndefinedSymbol(sym);
+ _ctx.addDeadStripRoot(sym);
+ }
+
+ // One can define alias symbols using /alternatename:<sym>=<sym> option.
+ // The mapping for /alternatename is in the context object. This helper
+ // function iterate over defined atoms and create alias atoms if needed.
+ createAlternateNameAtoms();
+
+ // In order to emit SEH table, all input files need to be compatible with
+ // SEH. Disable SEH if the file being read is not compatible.
+ if (!isCompatibleWithSEH())
+ _ctx.setSafeSEH(false);
+}
+
+/// Iterate over the symbol table to retrieve all symbols.
+std::error_code
+FileCOFF::readSymbolTable(SymbolVectorT &result) {
+ for (uint32_t i = 0, e = _obj->getNumberOfSymbols(); i != e; ++i) {
+ // Retrieve the symbol.
+ ErrorOr<llvm::object::COFFSymbolRef> sym = _obj->getSymbol(i);
+ StringRef name;
+ if (std::error_code ec = sym.getError())
+ return ec;
+ if (sym->getSectionNumber() == llvm::COFF::IMAGE_SYM_DEBUG)
+ goto next;
+ result.push_back(*sym);
+
+ if (std::error_code ec = _obj->getSymbolName(*sym, name))
+ return ec;
+
+ // Existence of the symbol @feat.00 indicates that object file is compatible
+ // with Safe Exception Handling.
+ if (name == "@feat.00") {
+ _compatibleWithSEH = true;
+ goto next;
+ }
+
+ // Cache the name.
+ _symbolName[*sym] = name;
+
+ // Symbol may be followed by auxiliary symbol table records. The aux
+ // record can be in any format, but the size is always the same as the
+ // regular symbol. The aux record supplies additional information for the
+ // standard symbol. We do not interpret the aux record here, but just
+ // store it to _auxSymbol.
+ if (sym->getNumberOfAuxSymbols() > 0) {
+ ErrorOr<llvm::object::COFFSymbolRef> aux = _obj->getSymbol(i + 1);
+ if (std::error_code ec = aux.getError())
+ return ec;
+ _auxSymbol[*sym] = *aux;
+ }
+ next:
+ i += sym->getNumberOfAuxSymbols();
+ }
+ return std::error_code();
+}
+
+/// Create atoms for the absolute symbols.
+void FileCOFF::createAbsoluteAtoms(const SymbolVectorT &symbols,
+ std::vector<const AbsoluteAtom *> &result) {
+ for (llvm::object::COFFSymbolRef sym : symbols) {
+ if (sym.getSectionNumber() != llvm::COFF::IMAGE_SYM_ABSOLUTE)
+ continue;
+ auto *atom = new (_alloc) SimpleAbsoluteAtom(*this, _symbolName[sym],
+ getScope(sym), sym.getValue());
+ result.push_back(atom);
+ _symbolAtom[sym] = atom;
+ }
+}
+
+/// Create atoms for the undefined symbols. This code is bit complicated
+/// because it supports "weak externals" mechanism of COFF. If an undefined
+/// symbol (sym1) has auxiliary data, the data contains a symbol table index
+/// at which the "second symbol" (sym2) for sym1 exists. If sym1 is resolved,
+/// it's linked normally. If not, sym1 is resolved as if it has sym2's
+/// name. This relationship between sym1 and sym2 is represented using
+/// fallback mechanism of undefined symbol.
+std::error_code
+FileCOFF::createUndefinedAtoms(const SymbolVectorT &symbols,
+ std::vector<const UndefinedAtom *> &result) {
+ std::map<llvm::object::COFFSymbolRef, llvm::object::COFFSymbolRef>
+ weakExternal;
+ std::set<llvm::object::COFFSymbolRef> fallback;
+ for (llvm::object::COFFSymbolRef sym : symbols) {
+ if (sym.getSectionNumber() != llvm::COFF::IMAGE_SYM_UNDEFINED)
+ continue;
+ // Create a mapping from sym1 to sym2, if the undefined symbol has
+ // auxiliary data.
+ auto iter = _auxSymbol.find(sym);
+ if (iter == _auxSymbol.end())
+ continue;
+ const coff_aux_weak_external *aux =
+ reinterpret_cast<const coff_aux_weak_external *>(
+ iter->second.getRawPtr());
+ ErrorOr<llvm::object::COFFSymbolRef> sym2 = _obj->getSymbol(aux->TagIndex);
+ if (std::error_code ec = sym2.getError())
+ return ec;
+ weakExternal[sym] = *sym2;
+ fallback.insert(*sym2);
+ }
+
+ // Create atoms for the undefined symbols.
+ for (llvm::object::COFFSymbolRef sym : symbols) {
+ if (sym.getSectionNumber() != llvm::COFF::IMAGE_SYM_UNDEFINED)
+ continue;
+ if (fallback.count(sym) > 0)
+ continue;
+
+ // If the symbol has sym2, create an undefiend atom for sym2, so that we
+ // can pass it as a fallback atom.
+ UndefinedAtom *fallback = nullptr;
+ auto iter = weakExternal.find(sym);
+ if (iter != weakExternal.end()) {
+ llvm::object::COFFSymbolRef sym2 = iter->second;
+ fallback = new (_alloc) COFFUndefinedAtom(*this, _symbolName[sym2]);
+ _symbolAtom[sym2] = fallback;
+ }
+
+ // Create an atom for the symbol.
+ auto *atom =
+ new (_alloc) COFFUndefinedAtom(*this, _symbolName[sym], fallback);
+ result.push_back(atom);
+ _symbolAtom[sym] = atom;
+ }
+ return std::error_code();
+}
+
+/// Create atoms for the defined symbols. This pass is a bit complicated than
+/// the other two, because in order to create the atom for the defined symbol
+/// we need to know the adjacent symbols.
+std::error_code
+FileCOFF::createDefinedSymbols(const SymbolVectorT &symbols,
+ std::vector<const DefinedAtom *> &result) {
+ // A defined atom can be merged if its section attribute allows its contents
+ // to be merged. In COFF, it's not very easy to get the section attribute
+ // for the symbol, so scan all sections in advance and cache the attributes
+ // for later use.
+ if (std::error_code ec = cacheSectionAttributes())
+ return ec;
+
+ // Filter non-defined atoms, and group defined atoms by its section.
+ SectionToSymbolsT definedSymbols;
+ for (llvm::object::COFFSymbolRef sym : symbols) {
+ // A symbol with section number 0 and non-zero value represents a common
+ // symbol. The MS COFF spec did not give a definition of what the common
+ // symbol is. We should probably follow ELF's definition shown below.
+ //
+ // - If one object file has a common symbol and another has a definition,
+ // the common symbol is treated as an undefined reference.
+ // - If there is no definition for a common symbol, the program linker
+ // acts as though it saw a definition initialized to zero of the
+ // appropriate size.
+ // - Two object files may have common symbols of
+ // different sizes, in which case the program linker will use the
+ // largest size.
+ //
+ // FIXME: We are currently treating the common symbol as a normal
+ // mergeable atom. Implement the above semantcis.
+ if (sym.getSectionNumber() == llvm::COFF::IMAGE_SYM_UNDEFINED &&
+ sym.getValue() > 0) {
+ StringRef name = _symbolName[sym];
+ uint32_t size = sym.getValue();
+ auto *atom = new (_alloc)
+ COFFBSSAtom(*this, name, getScope(sym), DefinedAtom::permRW_,
+ DefinedAtom::mergeAsWeakAndAddressUsed, size, getNextOrdinal());
+
+ // Common symbols should be aligned on natural boundaries with the maximum
+ // of 32 byte. It's not documented anywhere, but it's what MSVC link.exe
+ // seems to be doing.
+ uint64_t alignment = std::min((uint64_t)32, llvm::NextPowerOf2(size));
+ atom->setAlignment(
+ DefinedAtom::Alignment(llvm::countTrailingZeros(alignment)));
+ result.push_back(atom);
+ continue;
+ }
+
+ // Skip if it's not for defined atom.
+ if (sym.getSectionNumber() == llvm::COFF::IMAGE_SYM_DEBUG ||
+ sym.getSectionNumber() == llvm::COFF::IMAGE_SYM_ABSOLUTE ||
+ sym.getSectionNumber() == llvm::COFF::IMAGE_SYM_UNDEFINED)
+ continue;
+
+ const coff_section *sec;
+ if (std::error_code ec = _obj->getSection(sym.getSectionNumber(), sec))
+ return ec;
+ assert(sec && "SectionIndex > 0, Sec must be non-null!");
+
+ uint8_t sc = sym.getStorageClass();
+ if (sc != llvm::COFF::IMAGE_SYM_CLASS_EXTERNAL &&
+ sc != llvm::COFF::IMAGE_SYM_CLASS_STATIC &&
+ sc != llvm::COFF::IMAGE_SYM_CLASS_FUNCTION &&
+ sc != llvm::COFF::IMAGE_SYM_CLASS_LABEL) {
+ llvm::errs() << "Unable to create atom for: " << _symbolName[sym] << " ("
+ << static_cast<int>(sc) << ")\n";
+ return llvm::object::object_error::parse_failed;
+ }
+
+ definedSymbols[sec].push_back(sym);
+ }
+
+ // Atomize the defined symbols.
+ if (std::error_code ec = AtomizeDefinedSymbols(definedSymbols, result))
+ return ec;
+
+ return std::error_code();
+}
+
+// Cache the COMDAT attributes, which indicate whether the symbols in the
+// section can be merged or not.
+std::error_code FileCOFF::cacheSectionAttributes() {
+ // The COMDAT section attribute is not an attribute of coff_section, but is
+ // stored in the auxiliary symbol for the first symbol referring a COMDAT
+ // section. It feels to me that it's unnecessarily complicated, but this is
+ // how COFF works.
+ for (auto i : _auxSymbol) {
+ // Read a section from the file
+ llvm::object::COFFSymbolRef sym = i.first;
+ if (sym.getSectionNumber() == llvm::COFF::IMAGE_SYM_ABSOLUTE ||
+ sym.getSectionNumber() == llvm::COFF::IMAGE_SYM_UNDEFINED)
+ continue;
+
+ const coff_section *sec;
+ if (std::error_code ec = _obj->getSection(sym.getSectionNumber(), sec))
+ return ec;
+ const coff_aux_section_definition *aux =
+ reinterpret_cast<const coff_aux_section_definition *>(
+ i.second.getRawPtr());
+
+ if (sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_COMDAT) {
+ // Read aux symbol data.
+ _comdatSections.insert(sec);
+ _merge[sec] = getMerge(aux);
+ }
+
+ // Handle associative sections.
+ if (aux->Selection == llvm::COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
+ const coff_section *parent;
+ if (std::error_code ec =
+ _obj->getSection(aux->getNumber(sym.isBigObj()), parent))
+ return ec;
+ _association.insert(std::make_pair(parent, sec));
+ }
+ }
+
+ // The sections that does not have auxiliary symbol are regular sections, in
+ // which symbols are not allowed to be merged.
+ for (const auto &section : _obj->sections()) {
+ const coff_section *sec = _obj->getCOFFSection(section);
+ if (!_merge.count(sec))
+ _merge[sec] = DefinedAtom::mergeNo;
+ }
+ return std::error_code();
+}
+
+/// Atomize \p symbols and append the results to \p atoms. The symbols are
+/// assumed to have been defined in the \p section.
+std::error_code FileCOFF::AtomizeDefinedSymbolsInSection(
+ const coff_section *section, SymbolVectorT &symbols,
+ std::vector<COFFDefinedFileAtom *> &atoms) {
+ // Sort symbols by position.
+ std::stable_sort(
+ symbols.begin(), symbols.end(),
+ [](llvm::object::COFFSymbolRef a, llvm::object::COFFSymbolRef b)
+ -> bool { return a.getValue() < b.getValue(); });
+
+ StringRef sectionName;
+ if (std::error_code ec = _obj->getSectionName(section, sectionName))
+ return ec;
+
+ // BSS section does not have contents. If this is the BSS section, create
+ // COFFBSSAtom instead of COFFDefinedAtom.
+ if (section->Characteristics & llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) {
+ for (auto si = symbols.begin(), se = symbols.end(); si != se; ++si) {
+ llvm::object::COFFSymbolRef sym = *si;
+ uint32_t size = (si + 1 == se) ? section->SizeOfRawData - sym.getValue()
+ : si[1].getValue() - sym.getValue();
+ auto *atom = new (_alloc) COFFBSSAtom(
+ *this, _symbolName[sym], getScope(sym), getPermissions(section),
+ DefinedAtom::mergeAsWeakAndAddressUsed, size, getNextOrdinal());
+ atoms.push_back(atom);
+ _symbolAtom[sym] = atom;
+ }
+ return std::error_code();
+ }
+
+ ArrayRef<uint8_t> secData;
+ if (std::error_code ec = _obj->getSectionContents(section, secData))
+ return ec;
+
+ // A section with IMAGE_SCN_LNK_{INFO,REMOVE} attribute will never become
+ // a part of the output image. That's what the COFF spec says.
+ if (section->Characteristics & llvm::COFF::IMAGE_SCN_LNK_INFO ||
+ section->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE)
+ return std::error_code();
+
+ // Supporting debug info needs more work than just linking and combining
+ // .debug sections. We don't support it yet. Let's discard .debug sections at
+ // the very beginning of the process so that we don't spend time on linking
+ // blobs that nobody would understand.
+ if ((section->Characteristics & llvm::COFF::IMAGE_SCN_MEM_DISCARDABLE) &&
+ (sectionName == ".debug" || sectionName.startswith(".debug$"))) {
+ return std::error_code();
+ }
+
+ DefinedAtom::ContentType type = getContentType(section);
+ DefinedAtom::ContentPermissions perms = getPermissions(section);
+ uint64_t sectionSize = section->SizeOfRawData;
+ bool isComdat = (_comdatSections.count(section) == 1);
+
+ // Create an atom for the entire section.
+ if (symbols.empty()) {
+ ArrayRef<uint8_t> data(secData.data(), secData.size());
+ auto *atom = new (_alloc) COFFDefinedAtom(
+ *this, "", sectionName, sectionSize, Atom::scopeTranslationUnit,
+ type, isComdat, perms, _merge[section], data, getNextOrdinal());
+ atoms.push_back(atom);
+ _definedAtomLocations[section].insert(std::make_pair(0, atom));
+ return std::error_code();
+ }
+
+ // Create an unnamed atom if the first atom isn't at the start of the
+ // section.
+ if (symbols[0].getValue() != 0) {
+ uint64_t size = symbols[0].getValue();
+ ArrayRef<uint8_t> data(secData.data(), size);
+ auto *atom = new (_alloc) COFFDefinedAtom(
+ *this, "", sectionName, sectionSize, Atom::scopeTranslationUnit,
+ type, isComdat, perms, _merge[section], data, getNextOrdinal());
+ atoms.push_back(atom);
+ _definedAtomLocations[section].insert(std::make_pair(0, atom));
+ }
+
+ for (auto si = symbols.begin(), se = symbols.end(); si != se; ++si) {
+ const uint8_t *start = secData.data() + si->getValue();
+ // if this is the last symbol, take up the remaining data.
+ const uint8_t *end = (si + 1 == se) ? secData.data() + secData.size()
+ : secData.data() + (si + 1)->getValue();
+ ArrayRef<uint8_t> data(start, end);
+ auto *atom = new (_alloc) COFFDefinedAtom(
+ *this, _symbolName[*si], sectionName, sectionSize, getScope(*si),
+ type, isComdat, perms, _merge[section], data, getNextOrdinal());
+ atoms.push_back(atom);
+ _symbolAtom[*si] = atom;
+ _definedAtomLocations[section].insert(std::make_pair(si->getValue(), atom));
+ }
+ return std::error_code();
+}
+
+std::error_code FileCOFF::AtomizeDefinedSymbols(
+ SectionToSymbolsT &definedSymbols,
+ std::vector<const DefinedAtom *> &definedAtoms) {
+ // For each section, make atoms for all the symbols defined in the
+ // section, and append the atoms to the result objects.
+ for (auto &i : definedSymbols) {
+ const coff_section *section = i.first;
+ SymbolVectorT &symbols = i.second;
+ std::vector<COFFDefinedFileAtom *> atoms;
+ if (std::error_code ec =
+ AtomizeDefinedSymbolsInSection(section, symbols, atoms))
+ return ec;
+
+ // Set alignment to the first atom so that the section contents
+ // will be aligned as specified by the object section header.
+ if (atoms.size() > 0)
+ atoms[0]->setAlignment(getAlignment(section));
+
+ // Connect atoms with layout-after edges. It prevents atoms
+ // from being GC'ed if there is a reference to one of the atoms
+ // in the same layout-after chain. In such case we want to emit
+ // all the atoms appeared in the same chain, because the "live"
+ // atom may reference other atoms in the same chain.
+ if (atoms.size() >= 2)
+ for (auto it = atoms.begin(), e = atoms.end(); it + 1 != e; ++it)
+ addLayoutEdge(*it, *(it + 1), lld::Reference::kindLayoutAfter);
+
+ for (COFFDefinedFileAtom *atom : atoms) {
+ _sectionAtoms[section].push_back(atom);
+ definedAtoms.push_back(atom);
+ }
+ }
+
+ // A COMDAT section with SELECT_ASSOCIATIVE attribute refer to other
+ // section. If the referred section is linked to a binary, the
+ // referring section needs to be linked too. A typical use case of
+ // this attribute is a static initializer; a parent is a comdat BSS
+ // section, and a child is a static initializer code for the data.
+ //
+ // We add referring section contents to the referred section's
+ // associate list, so that Resolver takes care of them.
+ for (auto i : _association) {
+ const coff_section *parent = i.first;
+ const coff_section *child = i.second;
+ if (_sectionAtoms.count(child)) {
+ COFFDefinedFileAtom *p = _sectionAtoms[parent][0];
+ p->addAssociate(_sectionAtoms[child][0]);
+ }
+ }
+
+ return std::error_code();
+}
+
+/// Find the atom that is at \p targetAddress in \p section.
+std::error_code FileCOFF::findAtomAt(const coff_section *section,
+ uint32_t targetAddress,
+ COFFDefinedFileAtom *&result,
+ uint32_t &offsetInAtom) {
+ auto loc = _definedAtomLocations.find(section);
+ if (loc == _definedAtomLocations.end())
+ return llvm::object::object_error::parse_failed;
+ std::multimap<uint32_t, COFFDefinedAtom *> &map = loc->second;
+
+ auto it = map.upper_bound(targetAddress);
+ if (it == map.begin())
+ return llvm::object::object_error::parse_failed;
+ --it;
+ uint32_t atomAddress = it->first;
+ result = it->second;
+ offsetInAtom = targetAddress - atomAddress;
+ return std::error_code();
+}
+
+/// Find the atom for the symbol that was at the \p index in the symbol
+/// table.
+std::error_code FileCOFF::getAtomBySymbolIndex(uint32_t index, Atom *&ret) {
+ ErrorOr<llvm::object::COFFSymbolRef> symbol = _obj->getSymbol(index);
+ if (std::error_code ec = symbol.getError())
+ return ec;
+ ret = _symbolAtom[*symbol];
+ assert(ret);
+ return std::error_code();
+}
+
+/// Add relocation information to an atom based on \p rel. \p rel is an
+/// relocation entry for the \p section, and \p atoms are all the atoms
+/// defined in the \p section.
+std::error_code FileCOFF::addRelocationReference(
+ const coff_relocation *rel, const coff_section *section) {
+ // The address of the item which relocation is applied. Section's
+ // VirtualAddress needs to be added for historical reasons, but the value
+ // is usually just zero, so adding it is usually no-op.
+ uint32_t itemAddress = rel->VirtualAddress + section->VirtualAddress;
+
+ Atom *targetAtom = nullptr;
+ if (std::error_code ec =
+ getAtomBySymbolIndex(rel->SymbolTableIndex, targetAtom))
+ return ec;
+
+ COFFDefinedFileAtom *atom;
+ uint32_t offsetInAtom;
+ if (std::error_code ec = findAtomAt(section, itemAddress, atom, offsetInAtom))
+ return ec;
+ atom->addReference(llvm::make_unique<SimpleReference>(
+ Reference::KindNamespace::COFF, _referenceArch, rel->Type, offsetInAtom,
+ targetAtom, 0));
+ return std::error_code();
+}
+
+// Read section contents.
+std::error_code FileCOFF::getSectionContents(StringRef sectionName,
+ ArrayRef<uint8_t> &result) {
+ const coff_section *section = nullptr;
+ if (std::error_code ec = findSection(sectionName, section))
+ return ec;
+ if (!section)
+ return std::error_code();
+ if (std::error_code ec = _obj->getSectionContents(section, result))
+ return ec;
+ return std::error_code();
+}
+
+AliasAtom *
+FileCOFF::createAlias(StringRef name, const DefinedAtom *target, int cnt) {
+ AliasAtom *alias = new (_alloc) AliasAtom(*this, name);
+ alias->addReference(Reference::KindNamespace::all, Reference::KindArch::all,
+ Reference::kindLayoutAfter, 0, target, 0);
+ alias->setMerge(DefinedAtom::mergeAsWeak);
+ if (target->contentType() == DefinedAtom::typeCode)
+ alias->setDeadStrip(DefinedAtom::deadStripNever);
+ alias->setOrdinal(target->ordinal() - cnt);
+ return alias;
+}
+
+void FileCOFF::createAlternateNameAtoms() {
+ std::vector<AliasAtom *> aliases;
+ for (const DefinedAtom *atom : defined()) {
+ int cnt = 1;
+ for (StringRef alias : _ctx.getAlternateNames(atom->name()))
+ aliases.push_back(createAlias(alias, atom, cnt++));
+ }
+ for (AliasAtom *alias : aliases)
+ _definedAtoms._atoms.push_back(alias);
+}
+
+// Interpret the contents of .drectve section. If exists, the section contains
+// a string containing command line options. The linker is expected to
+// interpret the options as if they were given via the command line.
+//
+// The section mainly contains /defaultlib (-l in Unix), but can contain any
+// options as long as they are valid.
+std::error_code
+FileCOFF::parseDirectiveSection(StringRef directives) {
+ DEBUG(llvm::dbgs() << ".drectve: " << directives << "\n");
+
+ // Split the string into tokens, as the shell would do for argv.
+ SmallVector<const char *, 16> tokens;
+ tokens.push_back("link"); // argv[0] is the command name. Will be ignored.
+ llvm::cl::TokenizeWindowsCommandLine(directives, _stringSaver, tokens);
+ tokens.push_back(nullptr);
+
+ // Calls the command line parser to interpret the token string as if they
+ // were given via the command line.
+ int argc = tokens.size() - 1;
+ const char **argv = &tokens[0];
+ std::string errorMessage;
+ llvm::raw_string_ostream stream(errorMessage);
+ PECOFFLinkingContext::ParseDirectives parseDirectives =
+ _ctx.getParseDirectives();
+ bool parseFailed = !parseDirectives(argc, argv, _ctx, stream);
+ stream.flush();
+ // Print error message if error.
+ if (parseFailed) {
+ return make_dynamic_error_code(
+ Twine("Failed to parse '") + directives + "'\n"
+ + "Reason: " + errorMessage);
+ }
+ if (!errorMessage.empty()) {
+ llvm::errs() << "lld warning: " << errorMessage << "\n";
+ }
+ return std::error_code();
+}
+
+/// Returns the target machine type of the current object file.
+std::error_code FileCOFF::getReferenceArch(Reference::KindArch &result) {
+ switch (_obj->getMachine()) {
+ case llvm::COFF::IMAGE_FILE_MACHINE_I386:
+ result = Reference::KindArch::x86;
+ return std::error_code();
+ case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
+ result = Reference::KindArch::x86_64;
+ return std::error_code();
+ case llvm::COFF::IMAGE_FILE_MACHINE_ARMNT:
+ result = Reference::KindArch::ARM;
+ return std::error_code();
+ case llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN:
+ result = Reference::KindArch::all;
+ return std::error_code();
+ }
+ llvm::errs() << "Unsupported machine type: 0x"
+ << llvm::utohexstr(_obj->getMachine()) << '\n';
+ return llvm::object::object_error::parse_failed;
+}
+
+/// Add relocation information to atoms.
+std::error_code FileCOFF::addRelocationReferenceToAtoms() {
+ // Relocation entries are defined for each section.
+ for (const auto &sec : _obj->sections()) {
+ const coff_section *section = _obj->getCOFFSection(sec);
+
+ // Skip if there's no atom for the section. Currently we do not create any
+ // atoms for some sections, such as "debug$S", and such sections need to
+ // be skipped here too.
+ if (_sectionAtoms.find(section) == _sectionAtoms.end())
+ continue;
+
+ for (const auto &reloc : sec.relocations()) {
+ const coff_relocation *rel = _obj->getCOFFRelocation(reloc);
+ if (auto ec = addRelocationReference(rel, section))
+ return ec;
+ }
+ }
+ return std::error_code();
+}
+
+// Read .sxdata section if exists. .sxdata is a x86-only section that contains a
+// vector of symbol offsets. The symbols pointed by this section are SEH handler
+// functions contained in the same object file. The linker needs to construct a
+// SEH table and emit it to executable.
+//
+// On x86, exception handler addresses are in stack, so they are vulnerable to
+// stack overflow attack. In order to protect against it, Windows runtime uses
+// the SEH table to check if a SEH handler address in stack is a real address of
+// a handler created by compiler.
+//
+// What we want to emit from the linker is a vector of SEH handler VAs, but here
+// we have a vector of offsets to the symbol table. So we convert the latter to
+// the former.
+std::error_code FileCOFF::maybeCreateSXDataAtoms() {
+ ArrayRef<uint8_t> sxdata;
+ if (std::error_code ec = getSectionContents(".sxdata", sxdata))
+ return ec;
+ if (sxdata.empty())
+ return std::error_code();
+
+ auto *atom = new (_alloc) COFFDefinedAtom(
+ *this, "", ".sxdata", 0, Atom::scopeTranslationUnit,
+ DefinedAtom::typeData, false /*isComdat*/, DefinedAtom::permR__,
+ DefinedAtom::mergeNo, sxdata, getNextOrdinal());
+
+ const ulittle32_t *symbolIndex =
+ reinterpret_cast<const ulittle32_t *>(sxdata.data());
+ int numSymbols = sxdata.size() / sizeof(uint32_t);
+
+ for (int i = 0; i < numSymbols; ++i) {
+ Atom *handlerFunc;
+ if (std::error_code ec = getAtomBySymbolIndex(symbolIndex[i], handlerFunc))
+ return ec;
+ int offsetInAtom = i * sizeof(uint32_t);
+
+ uint16_t rtype;
+ switch (_obj->getMachine()) {
+ case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
+ rtype = llvm::COFF::IMAGE_REL_AMD64_ADDR32;
+ break;
+ case llvm::COFF::IMAGE_FILE_MACHINE_I386:
+ rtype = llvm::COFF::IMAGE_REL_I386_DIR32;
+ break;
+ default:
+ llvm_unreachable("unsupported machine type");
+ }
+
+ atom->addReference(llvm::make_unique<SimpleReference>(
+ Reference::KindNamespace::COFF, _referenceArch, rtype, offsetInAtom,
+ handlerFunc, 0));
+ }
+
+ _definedAtoms._atoms.push_back(atom);
+ return std::error_code();
+}
+
+/// Find a section by name.
+std::error_code FileCOFF::findSection(StringRef name,
+ const coff_section *&result) {
+ for (const auto &sec : _obj->sections()) {
+ const coff_section *section = _obj->getCOFFSection(sec);
+ StringRef sectionName;
+ if (auto ec = _obj->getSectionName(section, sectionName))
+ return ec;
+ if (sectionName == name) {
+ result = section;
+ return std::error_code();
+ }
+ }
+ // Section was not found, but it's not an error. This method returns
+ // an error only when there's a read error.
+ return std::error_code();
+}
+
+// Convert ArrayRef<uint8_t> to std::string. The array contains a string which
+// may not be terminated by NUL.
+StringRef FileCOFF::ArrayRefToString(ArrayRef<uint8_t> array) {
+ // .drectve sections are encoded in either ASCII or UTF-8 with BOM.
+ // The PE/COFF spec allows ANSI (Windows-1252 encoding), but seems
+ // it's no longer in use.
+ // Skip a UTF-8 byte marker if exists.
+ if (array.size() >= 3 && array[0] == 0xEF && array[1] == 0xBB &&
+ array[2] == 0xBF) {
+ array = array.slice(3);
+ }
+ if (array.empty())
+ return "";
+ StringRef s(reinterpret_cast<const char *>(array.data()), array.size());
+ s = s.substr(0, s.find_first_of('\0'));
+ std::string *contents = new (_alloc) std::string(s.data(), s.size());
+ return StringRef(*contents).trim();
+}
+
+// getNextOrdinal returns a monotonically increasaing uint64_t number
+// starting from 1. There's a large gap between two numbers returned
+// from this function, so that you can put other atoms between them.
+uint64_t FileCOFF::getNextOrdinal() {
+ return _ordinal++ << 32;
+}
+
+class COFFObjectReader : public Reader {
+public:
+ COFFObjectReader(PECOFFLinkingContext &ctx) : _ctx(ctx) {}
+
+ bool canParse(file_magic magic, StringRef ext,
+ const MemoryBuffer &) const override {
+ return magic == llvm::sys::fs::file_magic::coff_object;
+ }
+
+ std::error_code
+ loadFile(std::unique_ptr<MemoryBuffer> mb, const Registry &,
+ std::vector<std::unique_ptr<File>> &result) const override {
+ // Parse the memory buffer as PECOFF file.
+ auto *file = new FileCOFF(std::move(mb), _ctx);
+ result.push_back(std::unique_ptr<File>(file));
+ return std::error_code();
+ }
+
+private:
+ PECOFFLinkingContext &_ctx;
+};
+
+using namespace llvm::COFF;
+
+const Registry::KindStrings kindStringsI386[] = {
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_ABSOLUTE),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_DIR16),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_REL16),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_DIR32),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_DIR32NB),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_SEG12),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_SECTION),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_SECREL),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_TOKEN),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_SECREL7),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_I386_REL32),
+ LLD_KIND_STRING_END};
+
+const Registry::KindStrings kindStringsAMD64[] = {
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_ABSOLUTE),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_ADDR64),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_ADDR32),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_ADDR32NB),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_REL32),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_REL32_1),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_REL32_2),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_REL32_3),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_REL32_4),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_REL32_5),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_SECTION),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_SECREL),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_SECREL7),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_TOKEN),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_SREL32),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_PAIR),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_AMD64_SSPAN32),
+ LLD_KIND_STRING_END};
+
+const Registry::KindStrings kindStringsARMNT[] = {
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_ABSOLUTE),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_ADDR32),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_ADDR32NB),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_BRANCH24),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_BRANCH11),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_TOKEN),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_BLX24),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_BLX11),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_SECTION),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_SECREL),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_MOV32A),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_MOV32T),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_BRANCH20T),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_BRANCH24T),
+ LLD_KIND_STRING_ENTRY(IMAGE_REL_ARM_BLX23T),
+};
+
+} // end namespace anonymous
+
+namespace lld {
+
+void Registry::addSupportCOFFObjects(PECOFFLinkingContext &ctx) {
+ add(std::unique_ptr<Reader>(new COFFObjectReader(ctx)));
+ addKindTable(Reference::KindNamespace::COFF, Reference::KindArch::x86,
+ kindStringsI386);
+ addKindTable(Reference::KindNamespace::COFF, Reference::KindArch::x86_64,
+ kindStringsAMD64);
+ addKindTable(Reference::KindNamespace::COFF, Reference::KindArch::ARM,
+ kindStringsARMNT);
+}
+
+}
diff --git a/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp b/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp
new file mode 100644
index 000000000000..8c9641376a0d
--- /dev/null
+++ b/lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp
@@ -0,0 +1,389 @@
+//===- lib/ReaderWriter/PECOFF/ReaderImportHeader.cpp ---------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file \brief This file provides a way to read an import library member in a
+/// .lib file.
+///
+/// Archive Files in Windows
+/// ========================
+///
+/// In Windows, archive files with .lib file extension serve two different
+/// purposes.
+///
+/// - For static linking: An archive file in this use case contains multiple
+/// regular .obj files and is used for static linking. This is the same
+/// usage as .a file in Unix.
+///
+/// - For dynamic linking: An archive file in this use case contains pseudo
+/// .obj files to describe exported symbols of a DLL. Each pseudo .obj file
+/// in an archive has a name of an exported symbol and a DLL filename from
+/// which the symbol can be imported. When you link a DLL on Windows, you
+/// pass the name of the .lib file for the DLL instead of the DLL filename
+/// itself. That is the Windows way of linking against a shared library.
+///
+/// This file contains a function to handle the pseudo object file.
+///
+/// Windows Loader and Import Address Table
+/// =======================================
+///
+/// Windows supports a GOT-like mechanism for DLLs. The executable using DLLs
+/// contains a list of DLL names and list of symbols that need to be resolved by
+/// the loader. Windows loader maps the executable and all the DLLs to memory,
+/// resolves the symbols referencing items in DLLs, and updates the import
+/// address table (IAT) in memory. The IAT is an array of pointers to all of the
+/// data or functions in DLL referenced by the executable. You cannot access
+/// items in DLLs directly. They have to be accessed through an extra level of
+/// indirection.
+///
+/// So, if you want to access an item in DLL, you have to go through a
+/// pointer. How do you actually do that? You need a symbol for a pointer in the
+/// IAT. For each symbol defined in a DLL, a symbol with "__imp_" prefix is
+/// exported from the DLL for an IAT entry. For example, if you have a global
+/// variable "foo" in a DLL, a pointer to the variable is available as
+/// "_imp__foo". The IAT is an array of _imp__ symbols.
+///
+/// Is this OK? That's not that complicated. Because items in a DLL are not
+/// directly accessible, you need to access through a pointer, and the pointer
+/// is available as a symbol with _imp__ prefix.
+///
+/// Note 1: Although you can write code with _imp__ prefix, today's compiler and
+/// linker let you write code as if there's no extra level of indirection.
+/// That's why you haven't seen lots of _imp__ in your code. A variable or a
+/// function declared with "dllimport" attribute is treated as an item in a DLL,
+/// and the compiler automatically mangles its name and inserts the extra level
+/// of indirection when accessing the item. Here are some examples:
+///
+/// __declspec(dllimport) int var_in_dll;
+/// var_in_dll = 3; // is equivalent to *_imp__var_in_dll = 3;
+///
+/// __declspec(dllimport) int fn_in_dll(void);
+/// fn_in_dll(); // is equivalent to (*_imp__fn_in_dll)();
+///
+/// It's just the compiler rewrites code for you so that you don't need to
+/// handle the indirection yourself.
+///
+/// Note 2: __declspec(dllimport) is mandatory for data but optional for
+/// function. For a function, the linker creates a jump table with the original
+/// symbol name, so that the function is accessible without _imp__ prefix. The
+/// same function in a DLL can be called through two different symbols if it's
+/// not dllimport'ed.
+///
+/// (*_imp__fn)()
+/// fn()
+///
+/// The above functions do the same thing. fn's content is a JMP instruction to
+/// branch to the address pointed by _imp__fn. The latter may be a little bit
+/// slower than the former because it will execute the extra JMP instruction,
+/// but that's usually negligible.
+///
+/// If a function is dllimport'ed, which is usually done in a header file,
+/// mangled name will be used at compile time so the jump table will not be
+/// used.
+///
+/// Because there's no way to hide the indirection for data access at link time,
+/// data has to be accessed through dllimport'ed symbols or explicit _imp__
+/// prefix.
+///
+/// Idata Sections in the Pseudo Object File
+/// ========================================
+///
+/// The object file created by cl.exe has several sections whose name starts
+/// with ".idata$" followed by a number. The contents of the sections seem the
+/// fragments of a complete ".idata" section. These sections has relocations for
+/// the data referenced from the idata secton. Generally, the linker discards
+/// "$" and all characters that follow from the section name and merges their
+/// contents to one section. So, it looks like if everything would work fine,
+/// the idata section would naturally be constructed without having any special
+/// code for doing that.
+///
+/// However, the LLD linker cannot do that. An idata section constructed in that
+/// way was never be in valid format. We don't know the reason yet. Our
+/// assumption on the idata fragment could simply be wrong, or the LLD linker is
+/// not powerful enough to do the job. Meanwhile, we construct the idata section
+/// ourselves. All the "idata$" sections in the pseudo object file are currently
+/// ignored.
+///
+/// Creating Atoms for the Import Address Table
+/// ===========================================
+///
+/// The function in this file reads a pseudo object file and creates at most two
+/// atoms. One is a shared library atom for _imp__ symbol. The another is a
+/// defined atom for the JMP instruction if the symbol is for a function.
+///
+//===----------------------------------------------------------------------===//
+
+#include "Atoms.h"
+#include "lld/Core/Error.h"
+#include "lld/Core/File.h"
+#include "lld/Core/SharedLibraryAtom.h"
+#include "lld/ReaderWriter/PECOFFLinkingContext.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/COFF.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Memory.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstring>
+#include <map>
+#include <system_error>
+#include <vector>
+
+using namespace lld;
+using namespace lld::pecoff;
+using namespace llvm;
+using namespace llvm::support::endian;
+
+#define DEBUG_TYPE "ReaderImportHeader"
+
+namespace lld {
+
+namespace {
+
+// This code is valid both in x86 and x64.
+const uint8_t FuncAtomContentX86[] = {
+ 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // JMP *0x0
+ 0xcc, 0xcc // INT 3; INT 3
+};
+
+const uint8_t FuncAtomContentARMNT[] = {
+ 0x40, 0xf2, 0x00, 0x0c, // mov.w ip, #0
+ 0xc0, 0xf2, 0x00, 0x0c, // mov.t ip, #0
+ 0xdc, 0xf8, 0x00, 0xf0, // ldr.w pc, [ip]
+};
+
+static void setJumpInstTarget(COFFLinkerInternalAtom *src, const Atom *dst,
+ int off, MachineTypes machine) {
+ SimpleReference *ref;
+
+ switch (machine) {
+ default: llvm::report_fatal_error("unsupported machine type");
+ case llvm::COFF::IMAGE_FILE_MACHINE_I386:
+ ref = new SimpleReference(Reference::KindNamespace::COFF,
+ Reference::KindArch::x86,
+ llvm::COFF::IMAGE_REL_I386_DIR32,
+ off, dst, 0);
+ break;
+ case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
+ ref = new SimpleReference(Reference::KindNamespace::COFF,
+ Reference::KindArch::x86_64,
+ llvm::COFF::IMAGE_REL_AMD64_REL32,
+ off, dst, 0);
+ break;
+ case llvm::COFF::IMAGE_FILE_MACHINE_ARMNT:
+ ref = new SimpleReference(Reference::KindNamespace::COFF,
+ Reference::KindArch::ARM,
+ llvm::COFF::IMAGE_REL_ARM_MOV32T,
+ off, dst, 0);
+ break;
+ }
+ src->addReference(std::unique_ptr<SimpleReference>(ref));
+}
+
+/// The defined atom for jump table.
+class FuncAtom : public COFFLinkerInternalAtom {
+public:
+ FuncAtom(const File &file, StringRef symbolName,
+ const COFFSharedLibraryAtom *impAtom, MachineTypes machine)
+ : COFFLinkerInternalAtom(file, /*oridnal*/ 0, createContent(machine),
+ symbolName) {
+ size_t Offset;
+
+ switch (machine) {
+ default: llvm::report_fatal_error("unsupported machine type");
+ case llvm::COFF::IMAGE_FILE_MACHINE_I386:
+ case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
+ Offset = 2;
+ break;
+ case llvm::COFF::IMAGE_FILE_MACHINE_ARMNT:
+ Offset = 0;
+ break;
+ }
+
+ setJumpInstTarget(this, impAtom, Offset, machine);
+ }
+
+ uint64_t ordinal() const override { return 0; }
+ Scope scope() const override { return scopeGlobal; }
+ ContentType contentType() const override { return typeCode; }
+ Alignment alignment() const override { return Alignment(1); }
+ ContentPermissions permissions() const override { return permR_X; }
+
+private:
+ std::vector<uint8_t> createContent(MachineTypes machine) const {
+ const uint8_t *Data;
+ size_t Size;
+
+ switch (machine) {
+ default: llvm::report_fatal_error("unsupported machine type");
+ case llvm::COFF::IMAGE_FILE_MACHINE_I386:
+ case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
+ Data = FuncAtomContentX86;
+ Size = sizeof(FuncAtomContentX86);
+ break;
+ case llvm::COFF::IMAGE_FILE_MACHINE_ARMNT:
+ Data = FuncAtomContentARMNT;
+ Size = sizeof(FuncAtomContentARMNT);
+ break;
+ }
+
+ return std::vector<uint8_t>(Data, Data + Size);
+ }
+};
+
+class FileImportLibrary : public File {
+public:
+ FileImportLibrary(std::unique_ptr<MemoryBuffer> mb, MachineTypes machine)
+ : File(mb->getBufferIdentifier(), kindSharedLibrary),
+ _mb(std::move(mb)), _machine(machine) {}
+
+ std::error_code doParse() override {
+ const char *buf = _mb->getBufferStart();
+ const char *end = _mb->getBufferEnd();
+
+ // The size of the string that follows the header.
+ uint32_t dataSize
+ = read32le(buf + offsetof(COFF::ImportHeader, SizeOfData));
+
+ // Check if the total size is valid.
+ if (std::size_t(end - buf) != sizeof(COFF::ImportHeader) + dataSize)
+ return make_error_code(NativeReaderError::unknown_file_format);
+
+ uint16_t hint = read16le(buf + offsetof(COFF::ImportHeader, OrdinalHint));
+ StringRef symbolName(buf + sizeof(COFF::ImportHeader));
+ StringRef dllName(buf + sizeof(COFF::ImportHeader) + symbolName.size() + 1);
+
+ // TypeInfo is a bitfield. The least significant 2 bits are import
+ // type, followed by 3 bit import name type.
+ uint16_t typeInfo = read16le(buf + offsetof(COFF::ImportHeader, TypeInfo));
+ int type = typeInfo & 0x3;
+ int nameType = (typeInfo >> 2) & 0x7;
+
+ // Symbol name used by the linker may be different from the symbol name used
+ // by the loader. The latter may lack symbol decorations, or may not even
+ // have name if it's imported by ordinal.
+ StringRef importName = symbolNameToImportName(symbolName, nameType);
+
+ const COFFSharedLibraryAtom *dataAtom =
+ addSharedLibraryAtom(hint, symbolName, importName, dllName);
+ if (type == llvm::COFF::IMPORT_CODE)
+ addFuncAtom(symbolName, dllName, dataAtom);
+
+ return std::error_code();
+ }
+
+ const atom_collection<DefinedAtom> &defined() const override {
+ return _definedAtoms;
+ }
+
+ const atom_collection<UndefinedAtom> &undefined() const override {
+ return _noUndefinedAtoms;
+ }
+
+ const atom_collection<SharedLibraryAtom> &sharedLibrary() const override {
+ return _sharedLibraryAtoms;
+ }
+
+ const atom_collection<AbsoluteAtom> &absolute() const override {
+ return _noAbsoluteAtoms;
+ }
+
+private:
+ const COFFSharedLibraryAtom *addSharedLibraryAtom(uint16_t hint,
+ StringRef symbolName,
+ StringRef importName,
+ StringRef dllName) {
+ auto *atom = new (_alloc)
+ COFFSharedLibraryAtom(*this, hint, symbolName, importName, dllName);
+ _sharedLibraryAtoms._atoms.push_back(atom);
+ return atom;
+ }
+
+ void addFuncAtom(StringRef symbolName, StringRef dllName,
+ const COFFSharedLibraryAtom *impAtom) {
+ auto *atom = new (_alloc) FuncAtom(*this, symbolName, impAtom, _machine);
+ _definedAtoms._atoms.push_back(atom);
+ }
+
+ atom_collection_vector<DefinedAtom> _definedAtoms;
+ atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
+ mutable llvm::BumpPtrAllocator _alloc;
+
+ // Does the same thing as StringRef::ltrim() but removes at most one
+ // character.
+ StringRef ltrim1(StringRef str, const char *chars) const {
+ if (!str.empty() && strchr(chars, str[0]))
+ return str.substr(1);
+ return str;
+ }
+
+ // Convert the given symbol name to the import symbol name exported by the
+ // DLL.
+ StringRef symbolNameToImportName(StringRef symbolName, int nameType) const {
+ StringRef ret;
+ switch (nameType) {
+ case llvm::COFF::IMPORT_ORDINAL:
+ // The import is by ordinal. No symbol name will be used to identify the
+ // item in the DLL. Only its ordinal will be used.
+ return "";
+ case llvm::COFF::IMPORT_NAME:
+ // The import name in this case is identical to the symbol name.
+ return symbolName;
+ case llvm::COFF::IMPORT_NAME_NOPREFIX:
+ // The import name is the symbol name without leading ?, @ or _.
+ ret = ltrim1(symbolName, "?@_");
+ break;
+ case llvm::COFF::IMPORT_NAME_UNDECORATE:
+ // Similar to NOPREFIX, but we also need to truncate at the first @.
+ ret = ltrim1(symbolName, "?@_");
+ ret = ret.substr(0, ret.find('@'));
+ break;
+ }
+ std::string *str = new (_alloc) std::string(ret);
+ return *str;
+ }
+
+ std::unique_ptr<MemoryBuffer> _mb;
+ MachineTypes _machine;
+};
+
+class COFFImportLibraryReader : public Reader {
+public:
+ COFFImportLibraryReader(PECOFFLinkingContext &ctx) : _ctx(ctx) {}
+
+ bool canParse(file_magic magic, StringRef,
+ const MemoryBuffer &mb) const override {
+ if (mb.getBufferSize() < sizeof(COFF::ImportHeader))
+ return false;
+ return (magic == llvm::sys::fs::file_magic::coff_import_library);
+ }
+
+ std::error_code
+ loadFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &,
+ std::vector<std::unique_ptr<File> > &result) const override {
+ auto *file = new FileImportLibrary(std::move(mb), _ctx.getMachineType());
+ result.push_back(std::unique_ptr<File>(file));
+ return std::error_code();
+ }
+
+private:
+ PECOFFLinkingContext &_ctx;
+};
+
+} // end anonymous namespace
+
+void Registry::addSupportCOFFImportLibraries(PECOFFLinkingContext &ctx) {
+ add(llvm::make_unique<COFFImportLibraryReader>(ctx));
+}
+
+} // end namespace lld
diff --git a/lib/ReaderWriter/PECOFF/WriterImportLibrary.cpp b/lib/ReaderWriter/PECOFF/WriterImportLibrary.cpp
new file mode 100644
index 000000000000..fd3360f018b6
--- /dev/null
+++ b/lib/ReaderWriter/PECOFF/WriterImportLibrary.cpp
@@ -0,0 +1,118 @@
+//===- lib/ReaderWriter/PECOFF/WriterImportLibrary.cpp --------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// This file is responsible for creating the Import Library file.
+///
+//===----------------------------------------------------------------------===//
+
+#include "lld/ReaderWriter/PECOFFLinkingContext.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/FileUtilities.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace lld {
+namespace pecoff {
+
+/// Creates a .def file containing the list of exported symbols.
+static std::string
+createModuleDefinitionFile(const PECOFFLinkingContext &ctx) {
+ std::string ret;
+ llvm::raw_string_ostream os(ret);
+ os << "LIBRARY \"" << llvm::sys::path::filename(ctx.outputPath()) << "\"\n"
+ << "EXPORTS\n";
+
+ for (const PECOFFLinkingContext::ExportDesc &desc : ctx.getDllExports()) {
+ // Symbol names in a module-definition file will be mangled by lib.exe,
+ // so we need to demangle them before writing to a .def file.
+ os << " ";
+ if (!desc.externalName.empty()) {
+ os << desc.externalName;
+ } else if (!desc.mangledName.empty()) {
+ os << ctx.undecorateSymbol(desc.mangledName);
+ } else {
+ os << ctx.undecorateSymbol(desc.name);
+ }
+
+ if (!desc.isPrivate)
+ os << " @" << desc.ordinal;
+ if (desc.noname)
+ os << " NONAME";
+ if (desc.isData)
+ os << " DATA";
+ if (desc.isPrivate)
+ os << " PRIVATE";
+ os << "\n";
+ }
+ os.flush();
+ return ret;
+}
+
+static std::string writeToTempFile(StringRef contents) {
+ SmallString<128> path;
+ int fd;
+ if (llvm::sys::fs::createTemporaryFile("tmp", "def", fd, path)) {
+ llvm::errs() << "Failed to create temporary file\n";
+ return "";
+ }
+ llvm::raw_fd_ostream os(fd, /*shouldClose*/ true);
+ os << contents;
+ return path.str();
+}
+
+static void writeTo(StringRef path, StringRef contents) {
+ int fd;
+ if (llvm::sys::fs::openFileForWrite(path, fd, llvm::sys::fs::F_Text)) {
+ llvm::errs() << "Failed to open " << path << "\n";
+ return;
+ }
+ llvm::raw_fd_ostream os(fd, /*shouldClose*/ true);
+ os << contents;
+}
+
+/// Creates a .def file and runs lib.exe on it to create an import library.
+void writeImportLibrary(const PECOFFLinkingContext &ctx) {
+ std::string fileContents = createModuleDefinitionFile(ctx);
+
+ std::string program = "lib.exe";
+ ErrorOr<std::string> programPathOrErr = llvm::sys::findProgramByName(program);
+ if (!programPathOrErr) {
+ llvm::errs() << "Unable to find " << program << " in PATH\n";
+ } else {
+ const std::string &programPath = *programPathOrErr;
+
+ std::string defPath = writeToTempFile(fileContents);
+ llvm::FileRemover tmpFile(defPath);
+
+ std::string defArg = "/def:";
+ defArg.append(defPath);
+ std::string outputArg = "/out:";
+ outputArg.append(ctx.getOutputImportLibraryPath());
+
+ std::vector<const char *> args;
+ args.push_back(programPath.c_str());
+ args.push_back("/nologo");
+ args.push_back(ctx.is64Bit() ? "/machine:x64" : "/machine:x86");
+ args.push_back(defArg.c_str());
+ args.push_back(outputArg.c_str());
+ args.push_back(nullptr);
+
+ if (llvm::sys::ExecuteAndWait(programPath.c_str(), &args[0]) != 0)
+ llvm::errs() << program << " failed\n";
+ }
+
+ // If /lldmoduledeffile:<filename> is given, make a copy of the
+ // temporary module definition file. This feature is for unit tests.
+ if (!ctx.getModuleDefinitionFile().empty())
+ writeTo(ctx.getModuleDefinitionFile(), fileContents);
+}
+
+} // end namespace pecoff
+} // end namespace lld
diff --git a/lib/ReaderWriter/PECOFF/WriterImportLibrary.h b/lib/ReaderWriter/PECOFF/WriterImportLibrary.h
new file mode 100644
index 000000000000..a51b9a3648c5
--- /dev/null
+++ b/lib/ReaderWriter/PECOFF/WriterImportLibrary.h
@@ -0,0 +1,23 @@
+//===- lib/ReaderWriter/PECOFF/WriterImportLibrary.h ----------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_PE_COFF_WRITER_IMPORT_LIBRARY_H
+#define LLD_READER_WRITER_PE_COFF_WRITER_IMPORT_LIBRARY_H
+
+namespace lld {
+class PECOFFLinkingContext;
+
+namespace pecoff {
+
+void writeImportLibrary(const PECOFFLinkingContext &ctx);
+
+} // end namespace pecoff
+} // end namespace lld
+
+#endif
diff --git a/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp b/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp
new file mode 100644
index 000000000000..d34e2d3d63fd
--- /dev/null
+++ b/lib/ReaderWriter/PECOFF/WriterPECOFF.cpp
@@ -0,0 +1,1417 @@
+//===- lib/ReaderWriter/PECOFF/WriterPECOFF.cpp ---------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+///
+/// PE/COFF file consists of DOS Header, PE Header, COFF Header and Section
+/// Tables followed by raw section data.
+///
+/// This writer is responsible for writing Core Linker results to an Windows
+/// executable file.
+///
+/// This writer currently supports 32 bit PE/COFF for x86 processor only.
+///
+//===----------------------------------------------------------------------===//
+
+#include "Atoms.h"
+#include "WriterImportLibrary.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Writer.h"
+#include "lld/ReaderWriter/AtomLayout.h"
+#include "lld/ReaderWriter/PECOFFLinkingContext.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/COFF.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/Format.h"
+#include <algorithm>
+#include <cstdlib>
+#include <map>
+#include <time.h>
+#include <vector>
+
+#define DEBUG_TYPE "WriterPECOFF"
+
+using namespace llvm::support::endian;
+
+using llvm::COFF::DataDirectoryIndex;
+using llvm::object::coff_runtime_function_x64;
+using llvm::support::ulittle16_t;
+using llvm::support::ulittle32_t;
+using llvm::support::ulittle64_t;
+
+namespace lld {
+namespace pecoff {
+
+// Disk sector size. Some data needs to be aligned at disk sector boundary in
+// file.
+static const int SECTOR_SIZE = 512;
+
+namespace {
+class SectionChunk;
+
+/// A Chunk is an abstract contiguous range in an output file.
+class Chunk {
+public:
+ enum Kind {
+ kindHeader,
+ kindSection,
+ kindStringTable,
+ kindAtomChunk
+ };
+
+ explicit Chunk(Kind kind) : _kind(kind), _size(0) {}
+ virtual ~Chunk() {}
+ virtual void write(uint8_t *buffer) = 0;
+ virtual uint64_t size() const { return _size; }
+ virtual uint64_t onDiskSize() const { return size(); }
+ virtual uint64_t align() const { return 1; }
+
+ uint64_t fileOffset() const { return _fileOffset; }
+ void setFileOffset(uint64_t fileOffset) { _fileOffset = fileOffset; }
+ Kind getKind() const { return _kind; }
+
+protected:
+ Kind _kind;
+ uint64_t _size;
+ uint64_t _fileOffset;
+};
+
+/// A HeaderChunk is an abstract class to represent a file header for
+/// PE/COFF. The data in the header chunk is metadata about program and will
+/// be consumed by the windows loader. HeaderChunks are not mapped to memory
+/// when executed.
+class HeaderChunk : public Chunk {
+public:
+ HeaderChunk() : Chunk(kindHeader) {}
+
+ static bool classof(const Chunk *c) { return c->getKind() == kindHeader; }
+};
+
+/// A DOSStubChunk represents the DOS compatible header at the beginning
+/// of PE/COFF files.
+class DOSStubChunk : public HeaderChunk {
+public:
+ explicit DOSStubChunk(const PECOFFLinkingContext &ctx)
+ : HeaderChunk(), _context(ctx) {
+ // Minimum size of DOS stub is 64 bytes. The next block (PE header) needs to
+ // be aligned on 8 byte boundary.
+ size_t size = std::max(_context.getDosStub().size(), (size_t)64);
+ _size = llvm::RoundUpToAlignment(size, 8);
+ }
+
+ void write(uint8_t *buffer) override {
+ ArrayRef<uint8_t> array = _context.getDosStub();
+ std::memcpy(buffer, array.data(), array.size());
+ auto *header = reinterpret_cast<llvm::object::dos_header *>(buffer);
+ header->AddressOfRelocationTable = sizeof(llvm::object::dos_header);
+ header->AddressOfNewExeHeader = _size;
+ }
+
+private:
+ const PECOFFLinkingContext &_context;
+};
+
+/// A PEHeaderChunk represents PE header including COFF header.
+template <class PEHeader>
+class PEHeaderChunk : public HeaderChunk {
+public:
+ explicit PEHeaderChunk(const PECOFFLinkingContext &ctx);
+
+ void write(uint8_t *buffer) override;
+
+ void setSizeOfHeaders(uint64_t size) {
+ // Must be multiple of FileAlignment.
+ _peHeader.SizeOfHeaders = llvm::RoundUpToAlignment(size, SECTOR_SIZE);
+ }
+
+ void setSizeOfCode(uint64_t size) { _peHeader.SizeOfCode = size; }
+ void setBaseOfCode(uint32_t rva) { _peHeader.BaseOfCode = rva; }
+ void setBaseOfData(uint32_t rva);
+ void setSizeOfImage(uint32_t size) { _peHeader.SizeOfImage = size; }
+
+ void setSizeOfInitializedData(uint64_t size) {
+ _peHeader.SizeOfInitializedData = size;
+ }
+
+ void setSizeOfUninitializedData(uint64_t size) {
+ _peHeader.SizeOfUninitializedData = size;
+ }
+
+ void setNumberOfSections(uint32_t num) { _coffHeader.NumberOfSections = num; }
+ void setNumberOfSymbols(uint32_t num) { _coffHeader.NumberOfSymbols = num; }
+
+ void setAddressOfEntryPoint(uint32_t address) {
+ _peHeader.AddressOfEntryPoint = address;
+ }
+
+ void setPointerToSymbolTable(uint32_t rva) {
+ _coffHeader.PointerToSymbolTable = rva;
+ }
+
+private:
+ llvm::object::coff_file_header _coffHeader;
+ PEHeader _peHeader;
+};
+
+/// A SectionHeaderTableChunk represents Section Table Header of PE/COFF
+/// format, which is a list of section headers.
+class SectionHeaderTableChunk : public HeaderChunk {
+public:
+ SectionHeaderTableChunk() : HeaderChunk() {}
+ void addSection(SectionChunk *chunk);
+ uint64_t size() const override;
+ void write(uint8_t *buffer) override;
+
+private:
+ static llvm::object::coff_section createSectionHeader(SectionChunk *chunk);
+
+ std::vector<SectionChunk *> _sections;
+};
+
+class StringTableChunk : public Chunk {
+public:
+ StringTableChunk() : Chunk(kindStringTable) {}
+
+ static bool classof(const Chunk *c) {
+ return c->getKind() == kindStringTable;
+ }
+
+ uint32_t addSectionName(StringRef sectionName) {
+ if (_stringTable.empty()) {
+ // The string table immediately follows the symbol table.
+ // We don't really need a symbol table, but some tools (e.g. dumpbin)
+ // don't like zero-length symbol table.
+ // Make room for the empty symbol slot, which occupies 18 byte.
+ // We also need to reserve 4 bytes for the string table header.
+ int size = sizeof(llvm::object::coff_symbol16) + 4;
+ _stringTable.insert(_stringTable.begin(), size, 0);
+ // Set the name of the dummy symbol to the first string table entry.
+ // It's better than letting dumpbin print out a garabage as a symbol name.
+ char *off = _stringTable.data() + 4;
+ write32le(off, 4);
+ }
+ uint32_t offset = _stringTable.size();
+ _stringTable.insert(_stringTable.end(), sectionName.begin(),
+ sectionName.end());
+ _stringTable.push_back('\0');
+ return offset - sizeof(llvm::object::coff_symbol16);
+ }
+
+ uint64_t size() const override { return _stringTable.size(); }
+
+ void write(uint8_t *buffer) override {
+ if (_stringTable.empty())
+ return;
+ char *off = _stringTable.data() + sizeof(llvm::object::coff_symbol16);
+ write32le(off, _stringTable.size());
+ std::memcpy(buffer, _stringTable.data(), _stringTable.size());
+ }
+
+private:
+ std::vector<char> _stringTable;
+};
+
+class SectionChunk : public Chunk {
+public:
+ uint64_t onDiskSize() const override {
+ if (_characteristics & llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)
+ return 0;
+ return llvm::RoundUpToAlignment(size(), SECTOR_SIZE);
+ }
+
+ uint64_t align() const override { return SECTOR_SIZE; }
+ uint32_t getCharacteristics() const { return _characteristics; }
+ StringRef getSectionName() const { return _sectionName; }
+ virtual uint64_t memAlign() const { return _memAlign; }
+
+ static bool classof(const Chunk *c) {
+ Kind kind = c->getKind();
+ return kind == kindSection || kind == kindAtomChunk;
+ }
+
+ uint64_t getVirtualAddress() { return _virtualAddress; }
+ virtual void setVirtualAddress(uint32_t rva) { _virtualAddress = rva; }
+
+ uint32_t getStringTableOffset() const { return _stringTableOffset; }
+ void setStringTableOffset(uint32_t offset) { _stringTableOffset = offset; }
+
+protected:
+ SectionChunk(Kind kind, StringRef sectionName, uint32_t characteristics,
+ const PECOFFLinkingContext &ctx)
+ : Chunk(kind), _sectionName(sectionName),
+ _characteristics(characteristics), _virtualAddress(0),
+ _stringTableOffset(0), _memAlign(ctx.getPageSize()) {}
+
+private:
+ StringRef _sectionName;
+ const uint32_t _characteristics;
+ uint64_t _virtualAddress;
+ uint32_t _stringTableOffset;
+ uint64_t _memAlign;
+};
+
+struct BaseReloc {
+ BaseReloc(uint64_t a, llvm::COFF::BaseRelocationType t) : addr(a), type(t) {}
+ uint64_t addr;
+ llvm::COFF::BaseRelocationType type;
+};
+
+/// An AtomChunk represents a section containing atoms.
+class AtomChunk : public SectionChunk {
+public:
+ AtomChunk(const PECOFFLinkingContext &ctx, StringRef name,
+ const std::vector<const DefinedAtom *> &atoms);
+
+ void write(uint8_t *buffer) override;
+
+ uint64_t memAlign() const override;
+ void appendAtom(const DefinedAtom *atom);
+ void buildAtomRvaMap(std::map<const Atom *, uint64_t> &atomRva) const;
+
+ void applyRelocationsARM(uint8_t *buffer,
+ std::map<const Atom *, uint64_t> &atomRva,
+ std::vector<uint64_t> &sectionRva,
+ uint64_t imageBaseAddress);
+ void applyRelocationsX86(uint8_t *buffer,
+ std::map<const Atom *, uint64_t> &atomRva,
+ std::vector<uint64_t> &sectionRva,
+ uint64_t imageBaseAddress);
+ void applyRelocationsX64(uint8_t *buffer,
+ std::map<const Atom *, uint64_t> &atomRva,
+ std::vector<uint64_t> &sectionRva,
+ uint64_t imageBaseAddress);
+
+ void printAtomAddresses(uint64_t baseAddr) const;
+ void addBaseRelocations(std::vector<BaseReloc> &relocSites) const;
+
+ void setVirtualAddress(uint32_t rva) override;
+ uint64_t getAtomVirtualAddress(StringRef name) const;
+
+ static bool classof(const Chunk *c) { return c->getKind() == kindAtomChunk; }
+
+protected:
+ std::vector<AtomLayout *> _atomLayouts;
+ uint64_t _virtualAddress;
+
+private:
+ uint32_t
+ computeCharacteristics(const PECOFFLinkingContext &ctx, StringRef name,
+ const std::vector<const DefinedAtom *> &atoms) const {
+ return ctx.getSectionAttributes(name,
+ getDefaultCharacteristics(name, atoms));
+ }
+
+ uint32_t getDefaultCharacteristics(
+ StringRef name, const std::vector<const DefinedAtom *> &atoms) const;
+
+ mutable llvm::BumpPtrAllocator _alloc;
+ llvm::COFF::MachineTypes _machineType;
+ const PECOFFLinkingContext &_ctx;
+};
+
+/// A DataDirectoryChunk represents data directory entries that follows the PE
+/// header in the output file. An entry consists of an 8 byte field that
+/// indicates a relative virtual address (the starting address of the entry data
+/// in memory) and 8 byte entry data size.
+class DataDirectoryChunk : public HeaderChunk {
+public:
+ DataDirectoryChunk()
+ : HeaderChunk(), _data(std::vector<llvm::object::data_directory>(16)) {}
+
+ uint64_t size() const override {
+ return sizeof(llvm::object::data_directory) * _data.size();
+ }
+
+ void setField(DataDirectoryIndex index, uint32_t addr, uint32_t size);
+ void write(uint8_t *buffer) override;
+
+private:
+ std::vector<llvm::object::data_directory> _data;
+};
+
+/// A BaseRelocChunk represents ".reloc" section.
+///
+/// .reloc section contains a list of addresses. If the PE/COFF loader decides
+/// to load the binary at a memory address different from its preferred base
+/// address, which is specified by ImageBase field in the COFF header, the
+/// loader needs to relocate the binary, so that all the addresses in the binary
+/// point to new locations. The loader will do that by fixing up the addresses
+/// specified by .reloc section.
+///
+/// The executable is almost always loaded at the preferred base address because
+/// it's loaded into an empty address space. The DLL is however an subject of
+/// load-time relocation because it may conflict with other DLLs or the
+/// executable.
+class BaseRelocChunk : public SectionChunk {
+ typedef std::vector<std::unique_ptr<Chunk> > ChunkVectorT;
+
+public:
+ BaseRelocChunk(ChunkVectorT &chunks, const PECOFFLinkingContext &ctx)
+ : SectionChunk(kindSection, ".reloc", characteristics, ctx),
+ _ctx(ctx), _contents(createContents(chunks)) {}
+
+ void write(uint8_t *buffer) override {
+ std::memcpy(buffer, &_contents[0], _contents.size());
+ }
+
+ uint64_t size() const override { return _contents.size(); }
+
+private:
+ // When loaded into memory, reloc section should be readable and writable.
+ static const uint32_t characteristics =
+ llvm::COFF::IMAGE_SCN_MEM_READ |
+ llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ llvm::COFF::IMAGE_SCN_MEM_DISCARDABLE;
+
+ std::vector<uint8_t> createContents(ChunkVectorT &chunks) const;
+
+ // Returns a list of RVAs that needs to be relocated if the binary is loaded
+ // at an address different from its preferred one.
+ std::vector<BaseReloc> listRelocSites(ChunkVectorT &chunks) const;
+
+ // Create the content of a relocation block.
+ std::vector<uint8_t>
+ createBaseRelocBlock(uint64_t pageAddr, const BaseReloc *begin,
+ const BaseReloc *end) const;
+
+ const PECOFFLinkingContext &_ctx;
+ std::vector<uint8_t> _contents;
+};
+
+template <class PEHeader>
+PEHeaderChunk<PEHeader>::PEHeaderChunk(const PECOFFLinkingContext &ctx)
+ : HeaderChunk() {
+ // Set the size of the chunk and initialize the header with null bytes.
+ _size = sizeof(llvm::COFF::PEMagic) + sizeof(_coffHeader) + sizeof(_peHeader);
+ std::memset(&_coffHeader, 0, sizeof(_coffHeader));
+ std::memset(&_peHeader, 0, sizeof(_peHeader));
+
+ _coffHeader.Machine = ctx.getMachineType();
+ _coffHeader.TimeDateStamp = time(nullptr);
+
+ // Attributes of the executable.
+ uint16_t characteristics = llvm::COFF::IMAGE_FILE_EXECUTABLE_IMAGE;
+ if (!ctx.is64Bit())
+ characteristics |= llvm::COFF::IMAGE_FILE_32BIT_MACHINE;
+ if (ctx.isDll())
+ characteristics |= llvm::COFF::IMAGE_FILE_DLL;
+ if (ctx.getLargeAddressAware() || ctx.is64Bit())
+ characteristics |= llvm::COFF::IMAGE_FILE_LARGE_ADDRESS_AWARE;
+ if (ctx.getSwapRunFromCD())
+ characteristics |= llvm::COFF::IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP;
+ if (ctx.getSwapRunFromNet())
+ characteristics |= llvm::COFF::IMAGE_FILE_NET_RUN_FROM_SWAP;
+ if (!ctx.getBaseRelocationEnabled())
+ characteristics |= llvm::COFF::IMAGE_FILE_RELOCS_STRIPPED;
+
+ _coffHeader.Characteristics = characteristics;
+
+ _peHeader.Magic = ctx.is64Bit() ? llvm::COFF::PE32Header::PE32_PLUS
+ : llvm::COFF::PE32Header::PE32;
+
+ // The address of the executable when loaded into memory. The default for
+ // DLLs is 0x10000000. The default for executables is 0x400000.
+ _peHeader.ImageBase = ctx.getBaseAddress();
+
+ // Sections should be page-aligned when loaded into memory, which is 4KB on
+ // x86.
+ _peHeader.SectionAlignment = ctx.getSectionDefaultAlignment();
+
+ // Sections in an executable file on disk should be sector-aligned (512 byte).
+ _peHeader.FileAlignment = SECTOR_SIZE;
+
+ // The version number of the resultant executable/DLL. The number is purely
+ // informative, and neither the linker nor the loader won't use it. User can
+ // set the value using /version command line option. Default is 0.0.
+ PECOFFLinkingContext::Version imageVersion = ctx.getImageVersion();
+ _peHeader.MajorImageVersion = imageVersion.majorVersion;
+ _peHeader.MinorImageVersion = imageVersion.minorVersion;
+
+ // The required Windows version number. This is the internal version and
+ // shouldn't be confused with product name. Windows 7 is version 6.1 and
+ // Windows 8 is 6.2, for example.
+ PECOFFLinkingContext::Version minOSVersion = ctx.getMinOSVersion();
+ _peHeader.MajorOperatingSystemVersion = minOSVersion.majorVersion;
+ _peHeader.MinorOperatingSystemVersion = minOSVersion.minorVersion;
+ _peHeader.MajorSubsystemVersion = minOSVersion.majorVersion;
+ _peHeader.MinorSubsystemVersion = minOSVersion.minorVersion;
+
+ _peHeader.Subsystem = ctx.getSubsystem();
+
+ // Despite its name, DLL characteristics field has meaning both for
+ // executables and DLLs. We are not very sure if the following bits must
+ // be set, but regular binaries seem to have these bits, so we follow
+ // them.
+ uint16_t dllCharacteristics = 0;
+ if (ctx.noSEH())
+ dllCharacteristics |= llvm::COFF::IMAGE_DLL_CHARACTERISTICS_NO_SEH;
+ if (ctx.isTerminalServerAware())
+ dllCharacteristics |=
+ llvm::COFF::IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE;
+ if (ctx.isNxCompat())
+ dllCharacteristics |= llvm::COFF::IMAGE_DLL_CHARACTERISTICS_NX_COMPAT;
+ if (ctx.getDynamicBaseEnabled())
+ dllCharacteristics |= llvm::COFF::IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE;
+ if (!ctx.getAllowBind())
+ dllCharacteristics |= llvm::COFF::IMAGE_DLL_CHARACTERISTICS_NO_BIND;
+ if (!ctx.getAllowIsolation())
+ dllCharacteristics |= llvm::COFF::IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION;
+ if (ctx.getHighEntropyVA() && ctx.is64Bit())
+ dllCharacteristics |= llvm::COFF::IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA;
+ _peHeader.DLLCharacteristics = dllCharacteristics;
+
+ _peHeader.SizeOfStackReserve = ctx.getStackReserve();
+ _peHeader.SizeOfStackCommit = ctx.getStackCommit();
+ _peHeader.SizeOfHeapReserve = ctx.getHeapReserve();
+ _peHeader.SizeOfHeapCommit = ctx.getHeapCommit();
+
+ // The number of data directory entries. We always have 16 entries.
+ _peHeader.NumberOfRvaAndSize = 16;
+
+ // The size of PE header including optional data directory.
+ _coffHeader.SizeOfOptionalHeader = sizeof(PEHeader) +
+ _peHeader.NumberOfRvaAndSize * sizeof(llvm::object::data_directory);
+}
+
+template <>
+void PEHeaderChunk<llvm::object::pe32_header>::setBaseOfData(uint32_t rva) {
+ _peHeader.BaseOfData = rva;
+}
+
+template <>
+void PEHeaderChunk<llvm::object::pe32plus_header>::setBaseOfData(uint32_t rva) {
+ // BaseOfData field does not exist in PE32+ header.
+}
+
+template <class PEHeader>
+void PEHeaderChunk<PEHeader>::write(uint8_t *buffer) {
+ std::memcpy(buffer, llvm::COFF::PEMagic, sizeof(llvm::COFF::PEMagic));
+ buffer += sizeof(llvm::COFF::PEMagic);
+ std::memcpy(buffer, &_coffHeader, sizeof(_coffHeader));
+ buffer += sizeof(_coffHeader);
+ std::memcpy(buffer, &_peHeader, sizeof(_peHeader));
+}
+
+AtomChunk::AtomChunk(const PECOFFLinkingContext &ctx, StringRef sectionName,
+ const std::vector<const DefinedAtom *> &atoms)
+ : SectionChunk(kindAtomChunk, sectionName,
+ computeCharacteristics(ctx, sectionName, atoms), ctx),
+ _virtualAddress(0), _machineType(ctx.getMachineType()), _ctx(ctx) {
+ for (auto *a : atoms)
+ appendAtom(a);
+}
+
+void AtomChunk::write(uint8_t *buffer) {
+ if (_atomLayouts.empty())
+ return;
+ if (getCharacteristics() & llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)
+ return;
+ if (getCharacteristics() & llvm::COFF::IMAGE_SCN_CNT_CODE) {
+ // Fill the section with INT 3 (0xCC) rather than NUL, so that the
+ // disassembler will not interpret a garbage between atoms as the beginning
+ // of multi-byte machine code. This does not change the behavior of
+ // resulting binary but help debugging.
+ uint8_t *start = buffer + _atomLayouts.front()->_fileOffset;
+ uint8_t *end = buffer + _atomLayouts.back()->_fileOffset;
+ memset(start, 0xCC, end - start);
+ }
+
+ for (const auto *layout : _atomLayouts) {
+ const DefinedAtom *atom = cast<DefinedAtom>(layout->_atom);
+ ArrayRef<uint8_t> rawContent = atom->rawContent();
+ std::memcpy(buffer + layout->_fileOffset, rawContent.data(),
+ rawContent.size());
+ }
+}
+
+// Add all atoms to the given map. This data will be used to do relocation.
+void
+AtomChunk::buildAtomRvaMap(std::map<const Atom *, uint64_t> &atomRva) const {
+ for (const auto *layout : _atomLayouts)
+ atomRva[layout->_atom] = layout->_virtualAddr;
+}
+
+static int getSectionIndex(uint64_t targetAddr,
+ const std::vector<uint64_t> &sectionRva) {
+ int i = 1;
+ for (uint64_t rva : sectionRva) {
+ if (targetAddr < rva)
+ return i;
+ ++i;
+ }
+ return i;
+}
+
+static uint32_t getSectionStartAddr(uint64_t targetAddr,
+ const std::vector<uint64_t> &sectionRva) {
+ // Scan the list of section start addresses to find the section start address
+ // for the given RVA.
+ for (int i = 0, e = sectionRva.size(); i < e; ++i)
+ if (i == e - 1 || (sectionRva[i] <= targetAddr && targetAddr < sectionRva[i + 1]))
+ return sectionRva[i];
+ llvm_unreachable("Section missing");
+}
+
+static void applyThumbMoveImmediate(ulittle16_t *mov, uint16_t imm) {
+ // MOVW(T3): |11110|i|10|0|1|0|0|imm4|0|imm3|Rd|imm8|
+ // imm32 = zext imm4:i:imm3:imm8
+ // MOVT(T1): |11110|i|10|1|1|0|0|imm4|0|imm3|Rd|imm8|
+ // imm16 = imm4:i:imm3:imm8
+ mov[0] =
+ mov[0] | (((imm & 0x0800) >> 11) << 10) | (((imm & 0xf000) >> 12) << 0);
+ mov[1] =
+ mov[1] | (((imm & 0x0700) >> 8) << 12) | (((imm & 0x00ff) >> 0) << 0);
+}
+
+static void applyThumbBranchImmediate(ulittle16_t *bl, int32_t imm) {
+ // BL(T1): |11110|S|imm10|11|J1|1|J2|imm11|
+ // imm32 = sext S:I1:I2:imm10:imm11:'0'
+ // B.W(T4): |11110|S|imm10|10|J1|1|J2|imm11|
+ // imm32 = sext S:I1:I2:imm10:imm11:'0'
+ //
+ // I1 = ~(J1 ^ S), I2 = ~(J2 ^ S)
+
+ assert((~abs(imm) & (-1 << 24)) && "bl/b.w out of range");
+
+ uint32_t S = (imm < 0 ? 1 : 0);
+ uint32_t J1 = ((~imm & 0x00800000) >> 23) ^ S;
+ uint32_t J2 = ((~imm & 0x00400000) >> 22) ^ S;
+
+ bl[0] = bl[0] | (((imm & 0x003ff000) >> 12) << 0) | (S << 10);
+ bl[1] = bl[1] | (((imm & 0x00000ffe) >> 1) << 0) | (J2 << 11) | (J1 << 13);
+}
+
+void AtomChunk::applyRelocationsARM(uint8_t *Buffer,
+ std::map<const Atom *, uint64_t> &AtomRVA,
+ std::vector<uint64_t> &SectionRVA,
+ uint64_t ImageBase) {
+ Buffer = Buffer + _fileOffset;
+ parallel_for_each(_atomLayouts.begin(), _atomLayouts.end(),
+ [&](const AtomLayout *layout) {
+ const DefinedAtom *Atom = cast<DefinedAtom>(layout->_atom);
+ for (const Reference *R : *Atom) {
+ if (R->kindNamespace() != Reference::KindNamespace::COFF)
+ continue;
+
+ bool AssumeTHUMBCode = false;
+ if (auto Target = dyn_cast<DefinedAtom>(R->target()))
+ AssumeTHUMBCode = Target->permissions() == DefinedAtom::permR_X ||
+ Target->permissions() == DefinedAtom::permRWX;
+
+ const auto AtomOffset = R->offsetInAtom();
+ const auto FileOffset = layout->_fileOffset;
+ const auto TargetAddr = AtomRVA[R->target()] | (AssumeTHUMBCode ? 1 : 0);
+ auto RelocSite16 =
+ reinterpret_cast<ulittle16_t *>(Buffer + FileOffset + AtomOffset);
+ auto RelocSite32 =
+ reinterpret_cast<ulittle32_t *>(Buffer + FileOffset + AtomOffset);
+
+ switch (R->kindValue()) {
+ default: llvm_unreachable("unsupported relocation type");
+ case llvm::COFF::IMAGE_REL_ARM_ADDR32:
+ *RelocSite32 = *RelocSite32 + TargetAddr + ImageBase;
+ break;
+ case llvm::COFF::IMAGE_REL_ARM_ADDR32NB:
+ *RelocSite32 = *RelocSite32 + TargetAddr;
+ break;
+ case llvm::COFF::IMAGE_REL_ARM_MOV32T:
+ applyThumbMoveImmediate(&RelocSite16[0], (TargetAddr + ImageBase) >> 0);
+ applyThumbMoveImmediate(&RelocSite16[2], (TargetAddr + ImageBase) >> 16);
+ break;
+ case llvm::COFF::IMAGE_REL_ARM_BRANCH24T:
+ // NOTE: the thumb bit will implicitly be truncated properly
+ applyThumbBranchImmediate(RelocSite16,
+ TargetAddr - AtomRVA[Atom] - AtomOffset - 4);
+ break;
+ case llvm::COFF::IMAGE_REL_ARM_BLX23T:
+ // NOTE: the thumb bit will implicitly be truncated properly
+ applyThumbBranchImmediate(RelocSite16,
+ TargetAddr - AtomRVA[Atom] - AtomOffset - 4);
+ break;
+ }
+ }
+ });
+}
+
+void AtomChunk::applyRelocationsX86(uint8_t *buffer,
+ std::map<const Atom *, uint64_t> &atomRva,
+ std::vector<uint64_t> &sectionRva,
+ uint64_t imageBaseAddress) {
+ buffer += _fileOffset;
+ parallel_for_each(_atomLayouts.begin(), _atomLayouts.end(),
+ [&](const AtomLayout *layout) {
+ const DefinedAtom *atom = cast<DefinedAtom>(layout->_atom);
+ for (const Reference *ref : *atom) {
+ // Skip if this reference is not for COFF relocation.
+ if (ref->kindNamespace() != Reference::KindNamespace::COFF)
+ continue;
+ auto relocSite32 = reinterpret_cast<ulittle32_t *>(
+ buffer + layout->_fileOffset + ref->offsetInAtom());
+ auto relocSite16 = reinterpret_cast<ulittle16_t *>(relocSite32);
+ const Atom *target = ref->target();
+ uint64_t targetAddr = atomRva[target];
+ // Also account for whatever offset is already stored at the relocation
+ // site.
+ switch (ref->kindValue()) {
+ case llvm::COFF::IMAGE_REL_I386_ABSOLUTE:
+ // This relocation is no-op.
+ break;
+ case llvm::COFF::IMAGE_REL_I386_DIR32:
+ // Set target's 32-bit VA.
+ if (auto *abs = dyn_cast<AbsoluteAtom>(target))
+ *relocSite32 += abs->value();
+ else
+ *relocSite32 += targetAddr + imageBaseAddress;
+ break;
+ case llvm::COFF::IMAGE_REL_I386_DIR32NB:
+ // Set target's 32-bit RVA.
+ *relocSite32 += targetAddr;
+ break;
+ case llvm::COFF::IMAGE_REL_I386_REL32: {
+ // Set 32-bit relative address of the target. This relocation is
+ // usually used for relative branch or call instruction.
+ uint32_t disp = atomRva[atom] + ref->offsetInAtom() + 4;
+ *relocSite32 += targetAddr - disp;
+ break;
+ }
+ case llvm::COFF::IMAGE_REL_I386_SECTION:
+ // The 16-bit section index that contains the target symbol.
+ *relocSite16 += getSectionIndex(targetAddr, sectionRva);
+ break;
+ case llvm::COFF::IMAGE_REL_I386_SECREL:
+ // The 32-bit relative address from the beginning of the section that
+ // contains the target symbol.
+ *relocSite32 +=
+ targetAddr - getSectionStartAddr(targetAddr, sectionRva);
+ break;
+ default:
+ llvm::report_fatal_error("Unsupported relocation kind");
+ }
+ }
+ });
+}
+
+void AtomChunk::applyRelocationsX64(uint8_t *buffer,
+ std::map<const Atom *, uint64_t> &atomRva,
+ std::vector<uint64_t> &sectionRva,
+ uint64_t imageBase) {
+ buffer += _fileOffset;
+ parallel_for_each(_atomLayouts.begin(), _atomLayouts.end(),
+ [&](const AtomLayout *layout) {
+ const DefinedAtom *atom = cast<DefinedAtom>(layout->_atom);
+ for (const Reference *ref : *atom) {
+ if (ref->kindNamespace() != Reference::KindNamespace::COFF)
+ continue;
+
+ uint8_t *loc = buffer + layout->_fileOffset + ref->offsetInAtom();
+ auto relocSite16 = reinterpret_cast<ulittle16_t *>(loc);
+ auto relocSite32 = reinterpret_cast<ulittle32_t *>(loc);
+ auto relocSite64 = reinterpret_cast<ulittle64_t *>(loc);
+ uint64_t targetAddr = atomRva[ref->target()];
+
+ switch (ref->kindValue()) {
+ case llvm::COFF::IMAGE_REL_AMD64_ADDR64:
+ *relocSite64 += targetAddr + imageBase;
+ break;
+ case llvm::COFF::IMAGE_REL_AMD64_ADDR32:
+ *relocSite32 += targetAddr + imageBase;
+ break;
+ case llvm::COFF::IMAGE_REL_AMD64_ADDR32NB:
+ *relocSite32 += targetAddr;
+ break;
+ case llvm::COFF::IMAGE_REL_AMD64_REL32:
+ *relocSite32 += targetAddr - atomRva[atom] - ref->offsetInAtom() - 4;
+ break;
+ case llvm::COFF::IMAGE_REL_AMD64_REL32_1:
+ *relocSite32 += targetAddr - atomRva[atom] - ref->offsetInAtom() - 5;
+ break;
+ case llvm::COFF::IMAGE_REL_AMD64_REL32_2:
+ *relocSite32 += targetAddr - atomRva[atom] - ref->offsetInAtom() - 6;
+ break;
+ case llvm::COFF::IMAGE_REL_AMD64_REL32_3:
+ *relocSite32 += targetAddr - atomRva[atom] - ref->offsetInAtom() - 7;
+ break;
+ case llvm::COFF::IMAGE_REL_AMD64_REL32_4:
+ *relocSite32 += targetAddr - atomRva[atom] - ref->offsetInAtom() - 8;
+ break;
+ case llvm::COFF::IMAGE_REL_AMD64_REL32_5:
+ *relocSite32 += targetAddr - atomRva[atom] - ref->offsetInAtom() - 9;
+ break;
+ case llvm::COFF::IMAGE_REL_AMD64_SECTION:
+ *relocSite16 += getSectionIndex(targetAddr, sectionRva) - 1;
+ break;
+ case llvm::COFF::IMAGE_REL_AMD64_SECREL:
+ *relocSite32 +=
+ targetAddr - getSectionStartAddr(targetAddr, sectionRva);
+ break;
+ default:
+ llvm::errs() << "Kind: " << (int)ref->kindValue() << "\n";
+ llvm::report_fatal_error("Unsupported relocation kind");
+ }
+ }
+ });
+}
+
+/// Print atom VAs. Used only for debugging.
+void AtomChunk::printAtomAddresses(uint64_t baseAddr) const {
+ for (const auto *layout : _atomLayouts) {
+ const DefinedAtom *atom = cast<DefinedAtom>(layout->_atom);
+ uint64_t addr = layout->_virtualAddr;
+ llvm::dbgs() << llvm::format("0x%08llx: ", addr + baseAddr)
+ << (atom->name().empty() ? "(anonymous)" : atom->name())
+ << "\n";
+ }
+}
+
+/// List all virtual addresses (and not relative virtual addresses) that need
+/// to be fixed up if image base is relocated. The only relocation type that
+/// needs to be fixed is DIR32 on i386. REL32 is not (and should not be)
+/// fixed up because it's PC-relative.
+void AtomChunk::addBaseRelocations(std::vector<BaseReloc> &relocSites) const {
+ for (const auto *layout : _atomLayouts) {
+ const DefinedAtom *atom = cast<DefinedAtom>(layout->_atom);
+ for (const Reference *ref : *atom) {
+ if (ref->kindNamespace() != Reference::KindNamespace::COFF)
+ continue;
+
+ // An absolute symbol points to a fixed location in memory. Their
+ // address should not be fixed at load time. One exception is ImageBase
+ // because that's relative to run-time image base address.
+ if (auto *abs = dyn_cast<AbsoluteAtom>(ref->target()))
+ if (!abs->name().equals("__ImageBase") &&
+ !abs->name().equals("___ImageBase"))
+ continue;
+
+ uint64_t address = layout->_virtualAddr + ref->offsetInAtom();
+ switch (_machineType) {
+ default: llvm_unreachable("unsupported machine type");
+ case llvm::COFF::IMAGE_FILE_MACHINE_I386:
+ if (ref->kindValue() == llvm::COFF::IMAGE_REL_I386_DIR32)
+ relocSites.push_back(
+ BaseReloc(address, llvm::COFF::IMAGE_REL_BASED_HIGHLOW));
+ break;
+ case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
+ if (ref->kindValue() == llvm::COFF::IMAGE_REL_AMD64_ADDR64)
+ relocSites.push_back(
+ BaseReloc(address, llvm::COFF::IMAGE_REL_BASED_DIR64));
+ break;
+ case llvm::COFF::IMAGE_FILE_MACHINE_ARMNT:
+ if (ref->kindValue() == llvm::COFF::IMAGE_REL_ARM_ADDR32)
+ relocSites.push_back(
+ BaseReloc(address, llvm::COFF::IMAGE_REL_BASED_HIGHLOW));
+ else if (ref->kindValue() == llvm::COFF::IMAGE_REL_ARM_MOV32T)
+ relocSites.push_back(
+ BaseReloc(address, llvm::COFF::IMAGE_REL_BASED_ARM_MOV32T));
+ break;
+ }
+ }
+ }
+}
+
+void AtomChunk::setVirtualAddress(uint32_t rva) {
+ SectionChunk::setVirtualAddress(rva);
+ for (AtomLayout *layout : _atomLayouts)
+ layout->_virtualAddr += rva;
+}
+
+uint64_t AtomChunk::getAtomVirtualAddress(StringRef name) const {
+ for (auto atomLayout : _atomLayouts)
+ if (atomLayout->_atom->name() == name)
+ return atomLayout->_virtualAddr;
+ return 0;
+}
+
+void DataDirectoryChunk::setField(DataDirectoryIndex index, uint32_t addr,
+ uint32_t size) {
+ llvm::object::data_directory &dir = _data[index];
+ dir.RelativeVirtualAddress = addr;
+ dir.Size = size;
+}
+
+void DataDirectoryChunk::write(uint8_t *buffer) {
+ std::memcpy(buffer, &_data[0], size());
+}
+
+uint64_t AtomChunk::memAlign() const {
+ // ReaderCOFF propagated the section alignment to the first atom in
+ // the section. We restore that here.
+ if (_atomLayouts.empty())
+ return _ctx.getPageSize();
+ int align = _ctx.getPageSize();
+ for (auto atomLayout : _atomLayouts) {
+ auto *atom = cast<const DefinedAtom>(atomLayout->_atom);
+ align = std::max(align, 1 << atom->alignment().powerOf2);
+ }
+ return align;
+}
+
+void AtomChunk::appendAtom(const DefinedAtom *atom) {
+ // Atom may have to be at a proper alignment boundary. If so, move the
+ // pointer to make a room after the last atom before adding new one.
+ _size = llvm::RoundUpToAlignment(_size, 1 << atom->alignment().powerOf2);
+
+ // Create an AtomLayout and move the current pointer.
+ auto *layout = new (_alloc) AtomLayout(atom, _size, _size);
+ _atomLayouts.push_back(layout);
+ _size += atom->size();
+}
+
+uint32_t AtomChunk::getDefaultCharacteristics(
+ StringRef name, const std::vector<const DefinedAtom *> &atoms) const {
+ const uint32_t code = llvm::COFF::IMAGE_SCN_CNT_CODE;
+ const uint32_t execute = llvm::COFF::IMAGE_SCN_MEM_EXECUTE;
+ const uint32_t read = llvm::COFF::IMAGE_SCN_MEM_READ;
+ const uint32_t write = llvm::COFF::IMAGE_SCN_MEM_WRITE;
+ const uint32_t data = llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
+ const uint32_t bss = llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA;
+ if (name == ".text")
+ return code | execute | read;
+ if (name == ".data")
+ return data | read | write;
+ if (name == ".rdata")
+ return data | read;
+ if (name == ".bss")
+ return bss | read | write;
+ assert(atoms.size() > 0);
+ switch (atoms[0]->permissions()) {
+ case DefinedAtom::permR__:
+ return data | read;
+ case DefinedAtom::permRW_:
+ return data | read | write;
+ case DefinedAtom::permR_X:
+ return code | execute | read;
+ case DefinedAtom::permRWX:
+ return code | execute | read | write;
+ default:
+ llvm_unreachable("Unsupported permission");
+ }
+}
+
+void SectionHeaderTableChunk::addSection(SectionChunk *chunk) {
+ _sections.push_back(chunk);
+}
+
+uint64_t SectionHeaderTableChunk::size() const {
+ return _sections.size() * sizeof(llvm::object::coff_section);
+}
+
+void SectionHeaderTableChunk::write(uint8_t *buffer) {
+ uint64_t offset = 0;
+ for (SectionChunk *chunk : _sections) {
+ llvm::object::coff_section header = createSectionHeader(chunk);
+ std::memcpy(buffer + offset, &header, sizeof(header));
+ offset += sizeof(header);
+ }
+}
+
+llvm::object::coff_section
+SectionHeaderTableChunk::createSectionHeader(SectionChunk *chunk) {
+ llvm::object::coff_section header;
+
+ // We have extended the COFF specification by allowing section names to be
+ // greater than eight characters. We achieve this by adding the section names
+ // to the string table. Binutils' linker, ld, performs the same trick.
+ StringRef sectionName = chunk->getSectionName();
+ std::memset(header.Name, 0, llvm::COFF::NameSize);
+ if (uint32_t stringTableOffset = chunk->getStringTableOffset())
+ sprintf(header.Name, "/%u", stringTableOffset);
+ else
+ std::strncpy(header.Name, sectionName.data(), sectionName.size());
+
+ uint32_t characteristics = chunk->getCharacteristics();
+ header.VirtualSize = chunk->size();
+ header.VirtualAddress = chunk->getVirtualAddress();
+ header.SizeOfRawData = chunk->onDiskSize();
+ header.PointerToRelocations = 0;
+ header.PointerToLinenumbers = 0;
+ header.NumberOfRelocations = 0;
+ header.NumberOfLinenumbers = 0;
+ header.Characteristics = characteristics;
+
+ if (characteristics & llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) {
+ header.PointerToRawData = 0;
+ } else {
+ header.PointerToRawData = chunk->fileOffset();
+ }
+ return header;
+}
+
+/// Creates .reloc section content from the other sections. The content of
+/// .reloc is basically a list of relocation sites. The relocation sites are
+/// divided into blocks. Each block represents the base relocation for a 4K
+/// page.
+///
+/// By dividing 32 bit RVAs into blocks, COFF saves disk and memory space for
+/// the base relocation. A block consists of a 32 bit page RVA and 16 bit
+/// relocation entries which represent offsets in the page. That is a more
+/// compact representation than a simple vector of 32 bit RVAs.
+std::vector<uint8_t>
+BaseRelocChunk::createContents(ChunkVectorT &chunks) const {
+ std::vector<uint8_t> contents;
+ std::vector<BaseReloc> relocSites = listRelocSites(chunks);
+
+ uint64_t mask = _ctx.getPageSize() - 1;
+ parallel_sort(relocSites.begin(), relocSites.end(),
+ [=](const BaseReloc &a, const BaseReloc &b) {
+ return (a.addr & ~mask) < (b.addr & ~mask);
+ });
+
+ // Base relocations for the same memory page are grouped together
+ // and passed to createBaseRelocBlock.
+ for (auto it = relocSites.begin(), e = relocSites.end(); it != e;) {
+ auto beginIt = it;
+ uint64_t pageAddr = (beginIt->addr & ~mask);
+ for (++it; it != e; ++it)
+ if ((it->addr & ~mask) != pageAddr)
+ break;
+ const BaseReloc *begin = &*beginIt;
+ const BaseReloc *end = begin + (it - beginIt);
+ std::vector<uint8_t> block = createBaseRelocBlock(pageAddr, begin, end);
+ contents.insert(contents.end(), block.begin(), block.end());
+ }
+ return contents;
+}
+
+// Returns a list of RVAs that needs to be relocated if the binary is loaded
+// at an address different from its preferred one.
+std::vector<BaseReloc>
+BaseRelocChunk::listRelocSites(ChunkVectorT &chunks) const {
+ std::vector<BaseReloc> ret;
+ for (auto &cp : chunks)
+ if (AtomChunk *chunk = dyn_cast<AtomChunk>(&*cp))
+ chunk->addBaseRelocations(ret);
+ return ret;
+}
+
+// Create the content of a relocation block.
+std::vector<uint8_t>
+BaseRelocChunk::createBaseRelocBlock(uint64_t pageAddr,
+ const BaseReloc *begin,
+ const BaseReloc *end) const {
+ // Relocation blocks should be padded with IMAGE_REL_I386_ABSOLUTE to be
+ // aligned to a DWORD size boundary.
+ uint32_t size = llvm::RoundUpToAlignment(
+ sizeof(ulittle32_t) * 2 + sizeof(ulittle16_t) * (end - begin),
+ sizeof(ulittle32_t));
+ std::vector<uint8_t> contents(size);
+ uint8_t *ptr = &contents[0];
+
+ // The first four bytes is the page RVA.
+ write32le(ptr, pageAddr);
+ ptr += sizeof(ulittle32_t);
+
+ // The second four bytes is the size of the block, including the the page
+ // RVA and this size field.
+ write32le(ptr, size);
+ ptr += sizeof(ulittle32_t);
+
+ uint64_t mask = _ctx.getPageSize() - 1;
+ for (const BaseReloc *i = begin; i < end; ++i) {
+ write16le(ptr, (i->type << 12) | (i->addr & mask));
+ ptr += sizeof(ulittle16_t);
+ }
+ return contents;
+}
+
+} // end anonymous namespace
+
+class PECOFFWriter : public Writer {
+public:
+ explicit PECOFFWriter(const PECOFFLinkingContext &context)
+ : _ctx(context), _numSections(0), _imageSizeInMemory(_ctx.getPageSize()),
+ _imageSizeOnDisk(0) {}
+
+ template <class PEHeader> void build(const File &linkedFile);
+ std::error_code writeFile(const File &linkedFile, StringRef path) override;
+
+private:
+ void applyAllRelocations(uint8_t *bufferStart);
+ void printAllAtomAddresses() const;
+ void reorderSEHTableEntries(uint8_t *bufferStart);
+ void reorderSEHTableEntriesX86(uint8_t *bufferStart);
+ void reorderSEHTableEntriesX64(uint8_t *bufferStart);
+
+ void addChunk(Chunk *chunk);
+ void addSectionChunk(std::unique_ptr<SectionChunk> chunk,
+ SectionHeaderTableChunk *table,
+ StringTableChunk *stringTable);
+ void setImageSizeOnDisk();
+ uint64_t
+ calcSectionSize(llvm::COFF::SectionCharacteristics sectionType) const;
+
+ uint64_t calcSizeOfInitializedData() const {
+ return calcSectionSize(llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA);
+ }
+
+ uint64_t calcSizeOfUninitializedData() const {
+ return calcSectionSize(llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA);
+ }
+
+ uint64_t calcSizeOfCode() const {
+ return calcSectionSize(llvm::COFF::IMAGE_SCN_CNT_CODE);
+ }
+
+ std::vector<std::unique_ptr<Chunk> > _chunks;
+ const PECOFFLinkingContext &_ctx;
+ uint32_t _numSections;
+
+ // The size of the image in memory. This is initialized with
+ // _ctx.getPageSize(), as the first page starting at ImageBase is usually left
+ // unmapped. IIUC there's no technical reason to do so, but we'll follow that
+ // convention so that we don't produce odd-looking binary.
+ uint32_t _imageSizeInMemory;
+
+ // The size of the image on disk. This is basically the sum of all chunks in
+ // the output file with paddings between them.
+ uint32_t _imageSizeOnDisk;
+
+ // The map from atom to its relative virtual address.
+ std::map<const Atom *, uint64_t> _atomRva;
+};
+
+StringRef customSectionName(const DefinedAtom *atom) {
+ assert(atom->sectionChoice() == DefinedAtom::sectionCustomRequired);
+ StringRef s = atom->customSectionName();
+ size_t pos = s.find('$');
+ return (pos == StringRef::npos) ? s : s.substr(0, pos);
+}
+
+StringRef chooseSectionByContent(const DefinedAtom *atom) {
+ switch (atom->contentType()) {
+ case DefinedAtom::typeCode:
+ return ".text";
+ case DefinedAtom::typeZeroFill:
+ return ".bss";
+ case DefinedAtom::typeData:
+ if (atom->permissions() == DefinedAtom::permR__)
+ return ".rdata";
+ if (atom->permissions() == DefinedAtom::permRW_)
+ return ".data";
+ break;
+ default:
+ break;
+ }
+ llvm::errs() << "Atom: contentType=" << atom->contentType()
+ << " permission=" << atom->permissions() << "\n";
+ llvm::report_fatal_error("Failed to choose section based on content");
+}
+
+typedef std::map<StringRef, std::vector<const DefinedAtom *> > AtomVectorMap;
+
+void groupAtoms(const PECOFFLinkingContext &ctx, const File &file,
+ AtomVectorMap &result) {
+ for (const DefinedAtom *atom : file.defined()) {
+ if (atom->sectionChoice() == DefinedAtom::sectionCustomRequired) {
+ StringRef section = customSectionName(atom);
+ result[ctx.getOutputSectionName(section)].push_back(atom);
+ continue;
+ }
+ if (atom->sectionChoice() == DefinedAtom::sectionBasedOnContent) {
+ StringRef section = chooseSectionByContent(atom);
+ result[ctx.getOutputSectionName(section)].push_back(atom);
+ continue;
+ }
+ llvm_unreachable("Unknown section choice");
+ }
+}
+
+static const DefinedAtom *findTLSUsedSymbol(const PECOFFLinkingContext &ctx,
+ const File &file) {
+ StringRef sym = ctx.decorateSymbol("_tls_used");
+ for (const DefinedAtom *atom : file.defined())
+ if (atom->name() == sym)
+ return atom;
+ return nullptr;
+}
+
+// Create all chunks that consist of the output file.
+template <class PEHeader>
+void PECOFFWriter::build(const File &linkedFile) {
+ AtomVectorMap atoms;
+ groupAtoms(_ctx, linkedFile, atoms);
+
+ // Create file chunks and add them to the list.
+ auto *dosStub = new DOSStubChunk(_ctx);
+ auto *peHeader = new PEHeaderChunk<PEHeader>(_ctx);
+ auto *dataDirectory = new DataDirectoryChunk();
+ auto *sectionTable = new SectionHeaderTableChunk();
+ auto *stringTable = new StringTableChunk();
+ addChunk(dosStub);
+ addChunk(peHeader);
+ addChunk(dataDirectory);
+ addChunk(sectionTable);
+ addChunk(stringTable);
+
+ // Create sections and add the atoms to them.
+ for (auto i : atoms) {
+ StringRef sectionName = i.first;
+ std::vector<const DefinedAtom *> &contents = i.second;
+ std::unique_ptr<SectionChunk> section(
+ new AtomChunk(_ctx, sectionName, contents));
+ if (section->size() > 0)
+ addSectionChunk(std::move(section), sectionTable, stringTable);
+ }
+
+ // Build atom to its RVA map.
+ for (std::unique_ptr<Chunk> &cp : _chunks)
+ if (AtomChunk *chunk = dyn_cast<AtomChunk>(&*cp))
+ chunk->buildAtomRvaMap(_atomRva);
+
+ // We know the addresses of all defined atoms that needs to be
+ // relocated. So we can create the ".reloc" section which contains
+ // all the relocation sites.
+ if (_ctx.getBaseRelocationEnabled()) {
+ std::unique_ptr<SectionChunk> baseReloc(new BaseRelocChunk(_chunks, _ctx));
+ if (baseReloc->size()) {
+ SectionChunk &ref = *baseReloc;
+ addSectionChunk(std::move(baseReloc), sectionTable, stringTable);
+ dataDirectory->setField(DataDirectoryIndex::BASE_RELOCATION_TABLE,
+ ref.getVirtualAddress(), ref.size());
+ }
+ }
+
+ setImageSizeOnDisk();
+
+ if (stringTable->size()) {
+ peHeader->setPointerToSymbolTable(stringTable->fileOffset());
+ peHeader->setNumberOfSymbols(1);
+ }
+
+ for (std::unique_ptr<Chunk> &chunk : _chunks) {
+ SectionChunk *section = dyn_cast<SectionChunk>(chunk.get());
+ if (!section)
+ continue;
+ if (section->getSectionName() == ".text") {
+ peHeader->setBaseOfCode(section->getVirtualAddress());
+
+ // Find the virtual address of the entry point symbol if any. PECOFF spec
+ // says that entry point for dll images is optional, in which case it must
+ // be set to 0.
+ if (_ctx.hasEntry()) {
+ AtomChunk *atom = cast<AtomChunk>(section);
+ uint64_t entryPointAddress =
+ atom->getAtomVirtualAddress(_ctx.getEntrySymbolName());
+
+ if (entryPointAddress) {
+ // NOTE: ARM NT assumes a pure THUMB execution, so adjust the entry
+ // point accordingly
+ if (_ctx.getMachineType() == llvm::COFF::IMAGE_FILE_MACHINE_ARMNT)
+ entryPointAddress |= 1;
+ peHeader->setAddressOfEntryPoint(entryPointAddress);
+ }
+ } else {
+ peHeader->setAddressOfEntryPoint(0);
+ }
+ }
+ StringRef name = section->getSectionName();
+ if (name == ".data") {
+ peHeader->setBaseOfData(section->getVirtualAddress());
+ continue;
+ }
+ DataDirectoryIndex ignore = DataDirectoryIndex(-1);
+ DataDirectoryIndex idx = llvm::StringSwitch<DataDirectoryIndex>(name)
+ .Case(".pdata", DataDirectoryIndex::EXCEPTION_TABLE)
+ .Case(".rsrc", DataDirectoryIndex::RESOURCE_TABLE)
+ .Case(".idata.a", DataDirectoryIndex::IAT)
+ .Case(".idata.d", DataDirectoryIndex::IMPORT_TABLE)
+ .Case(".edata", DataDirectoryIndex::EXPORT_TABLE)
+ .Case(".loadcfg", DataDirectoryIndex::LOAD_CONFIG_TABLE)
+ .Case(".didat.d", DataDirectoryIndex::DELAY_IMPORT_DESCRIPTOR)
+ .Default(ignore);
+ if (idx == ignore)
+ continue;
+ dataDirectory->setField(idx, section->getVirtualAddress(), section->size());
+ }
+
+ if (const DefinedAtom *atom = findTLSUsedSymbol(_ctx, linkedFile)) {
+ dataDirectory->setField(DataDirectoryIndex::TLS_TABLE, _atomRva[atom],
+ 0x18);
+ }
+
+ // Now that we know the size and file offset of sections. Set the file
+ // header accordingly.
+ peHeader->setSizeOfCode(calcSizeOfCode());
+ peHeader->setSizeOfInitializedData(calcSizeOfInitializedData());
+ peHeader->setSizeOfUninitializedData(calcSizeOfUninitializedData());
+ peHeader->setNumberOfSections(_numSections);
+ peHeader->setSizeOfImage(_imageSizeInMemory);
+ peHeader->setSizeOfHeaders(sectionTable->fileOffset() + sectionTable->size());
+}
+
+std::error_code PECOFFWriter::writeFile(const File &linkedFile,
+ StringRef path) {
+ if (_ctx.is64Bit()) {
+ this->build<llvm::object::pe32plus_header>(linkedFile);
+ } else {
+ this->build<llvm::object::pe32_header>(linkedFile);
+ }
+
+ uint64_t totalSize =
+ _chunks.back()->fileOffset() + _chunks.back()->onDiskSize();
+ std::unique_ptr<llvm::FileOutputBuffer> buffer;
+ std::error_code ec = llvm::FileOutputBuffer::create(
+ path, totalSize, buffer, llvm::FileOutputBuffer::F_executable);
+ if (ec)
+ return ec;
+
+ for (std::unique_ptr<Chunk> &chunk : _chunks)
+ chunk->write(buffer->getBufferStart() + chunk->fileOffset());
+ applyAllRelocations(buffer->getBufferStart());
+ reorderSEHTableEntries(buffer->getBufferStart());
+ DEBUG(printAllAtomAddresses());
+
+ if (_ctx.isDll())
+ writeImportLibrary(_ctx);
+
+ return buffer->commit();
+}
+
+/// Apply relocations to the output file buffer. This two pass. In the first
+/// pass, we visit all atoms to create a map from atom to its virtual
+/// address. In the second pass, we visit all relocation references to fix
+/// up addresses in the buffer.
+void PECOFFWriter::applyAllRelocations(uint8_t *bufferStart) {
+ // Create the list of section start addresses. It's needed for
+ // relocations of SECREL type.
+ std::vector<uint64_t> sectionRva;
+ for (auto &cp : _chunks)
+ if (SectionChunk *section = dyn_cast<SectionChunk>(&*cp))
+ sectionRva.push_back(section->getVirtualAddress());
+
+ uint64_t base = _ctx.getBaseAddress();
+ for (auto &cp : _chunks) {
+ if (AtomChunk *chunk = dyn_cast<AtomChunk>(&*cp)) {
+ switch (_ctx.getMachineType()) {
+ default: llvm_unreachable("unsupported machine type");
+ case llvm::COFF::IMAGE_FILE_MACHINE_ARMNT:
+ chunk->applyRelocationsARM(bufferStart, _atomRva, sectionRva, base);
+ break;
+ case llvm::COFF::IMAGE_FILE_MACHINE_I386:
+ chunk->applyRelocationsX86(bufferStart, _atomRva, sectionRva, base);
+ break;
+ case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
+ chunk->applyRelocationsX64(bufferStart, _atomRva, sectionRva, base);
+ break;
+ }
+ }
+ }
+}
+
+/// Print atom VAs. Used only for debugging.
+void PECOFFWriter::printAllAtomAddresses() const {
+ for (auto &cp : _chunks)
+ if (AtomChunk *chunk = dyn_cast<AtomChunk>(&*cp))
+ chunk->printAtomAddresses(_ctx.getBaseAddress());
+}
+
+void PECOFFWriter::reorderSEHTableEntries(uint8_t *bufferStart) {
+ auto machineType = _ctx.getMachineType();
+ if (machineType == llvm::COFF::IMAGE_FILE_MACHINE_I386)
+ reorderSEHTableEntriesX86(bufferStart);
+ if (machineType == llvm::COFF::IMAGE_FILE_MACHINE_AMD64)
+ reorderSEHTableEntriesX64(bufferStart);
+}
+
+/// It seems that the entries in .sxdata must be sorted. This function is called
+/// after a COFF file image is created in memory and before it is written to
+/// disk. It is safe to reorder entries at this stage because the contents of
+/// the entries are RVAs and there's no reference to a .sxdata entry other than
+/// to the beginning of the section.
+void PECOFFWriter::reorderSEHTableEntriesX86(uint8_t *bufferStart) {
+ for (std::unique_ptr<Chunk> &chunk : _chunks) {
+ if (SectionChunk *section = dyn_cast<SectionChunk>(chunk.get())) {
+ if (section->getSectionName() == ".sxdata") {
+ int numEntries = section->size() / sizeof(ulittle32_t);
+ ulittle32_t *begin = reinterpret_cast<ulittle32_t *>(bufferStart + section->fileOffset());
+ ulittle32_t *end = begin + numEntries;
+ std::sort(begin, end);
+ }
+ }
+ }
+}
+
+/// The entries in .pdata must be sorted according to its BeginAddress field
+/// value. It's safe to do it because of the same reason as .sxdata.
+void PECOFFWriter::reorderSEHTableEntriesX64(uint8_t *bufferStart) {
+ for (std::unique_ptr<Chunk> &chunk : _chunks) {
+ if (SectionChunk *section = dyn_cast<SectionChunk>(chunk.get())) {
+ if (section->getSectionName() != ".pdata")
+ continue;
+ int numEntries = section->size() / sizeof(coff_runtime_function_x64);
+ coff_runtime_function_x64 *begin =
+ (coff_runtime_function_x64 *)(bufferStart + section->fileOffset());
+ coff_runtime_function_x64 *end = begin + numEntries;
+ std::sort(begin, end, [](const coff_runtime_function_x64 &lhs,
+ const coff_runtime_function_x64 &rhs) {
+ return lhs.BeginAddress < rhs.BeginAddress;
+ });
+ }
+ }
+}
+
+void PECOFFWriter::addChunk(Chunk *chunk) {
+ _chunks.push_back(std::unique_ptr<Chunk>(chunk));
+}
+
+void PECOFFWriter::addSectionChunk(std::unique_ptr<SectionChunk> chunk,
+ SectionHeaderTableChunk *table,
+ StringTableChunk *stringTable) {
+ table->addSection(chunk.get());
+ _numSections++;
+
+ StringRef sectionName = chunk->getSectionName();
+ if (sectionName.size() > llvm::COFF::NameSize) {
+ uint32_t stringTableOffset = stringTable->addSectionName(sectionName);
+ chunk->setStringTableOffset(stringTableOffset);
+ }
+
+ // Compute and set the starting address of sections when loaded in
+ // memory. They are different from positions on disk because sections need
+ // to be sector-aligned on disk but page-aligned in memory.
+ _imageSizeInMemory = llvm::RoundUpToAlignment(
+ _imageSizeInMemory, chunk->memAlign());
+ chunk->setVirtualAddress(_imageSizeInMemory);
+ _imageSizeInMemory = llvm::RoundUpToAlignment(
+ _imageSizeInMemory + chunk->size(), _ctx.getPageSize());
+ _chunks.push_back(std::move(chunk));
+}
+
+void PECOFFWriter::setImageSizeOnDisk() {
+ for (auto &chunk : _chunks) {
+ // Compute and set the offset of the chunk in the output file.
+ _imageSizeOnDisk =
+ llvm::RoundUpToAlignment(_imageSizeOnDisk, chunk->align());
+ chunk->setFileOffset(_imageSizeOnDisk);
+ _imageSizeOnDisk += chunk->onDiskSize();
+ }
+}
+
+uint64_t PECOFFWriter::calcSectionSize(
+ llvm::COFF::SectionCharacteristics sectionType) const {
+ uint64_t ret = 0;
+ for (auto &cp : _chunks)
+ if (SectionChunk *chunk = dyn_cast<SectionChunk>(&*cp))
+ if (chunk->getCharacteristics() & sectionType)
+ ret += chunk->onDiskSize();
+ return ret;
+}
+
+} // end namespace pecoff
+
+std::unique_ptr<Writer> createWriterPECOFF(const PECOFFLinkingContext &info) {
+ return std::unique_ptr<Writer>(new pecoff::PECOFFWriter(info));
+}
+
+} // end namespace lld
diff --git a/lib/ReaderWriter/YAML/CMakeLists.txt b/lib/ReaderWriter/YAML/CMakeLists.txt
new file mode 100644
index 000000000000..b955baa94202
--- /dev/null
+++ b/lib/ReaderWriter/YAML/CMakeLists.txt
@@ -0,0 +1,6 @@
+add_llvm_library(lldYAML
+ ReaderWriterYAML.cpp
+ LINK_LIBS
+ lldCore
+ LLVMSupport
+ )
diff --git a/lib/ReaderWriter/YAML/Makefile b/lib/ReaderWriter/YAML/Makefile
new file mode 100644
index 000000000000..739b6eae747a
--- /dev/null
+++ b/lib/ReaderWriter/YAML/Makefile
@@ -0,0 +1,14 @@
+##===- lld/lib/ReaderWriter/YAML/Makefile --------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLD_LEVEL := ../../..
+LIBRARYNAME := lldYAML
+USEDLIBS = lldCore.a
+
+include $(LLD_LEVEL)/Makefile
diff --git a/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp b/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp
new file mode 100644
index 000000000000..868b9497c4cc
--- /dev/null
+++ b/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp
@@ -0,0 +1,1358 @@
+//===- 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/ArchiveLibraryFile.h"
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/Error.h"
+#include "lld/Core/File.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Reader.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/Simple.h"
+#include "lld/Core/Writer.h"
+#include "lld/ReaderWriter/YamlContext.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/YAMLTraits.h"
+#include "llvm/Support/raw_ostream.h"
+#include <memory>
+#include <string>
+#include <system_error>
+
+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;
+ }
+
+ /// \brief Lookup a group parent when there is a reference of type
+ /// kindGroupChild. If there was no group-parent produce an appropriate
+ /// error.
+ const lld::Atom *lookupGroupParent(StringRef name) const {
+ NameToAtom::const_iterator pos = _groupMap.find(name);
+ if (pos != _groupMap.end())
+ return pos->second;
+ _io.setError(Twine("no such group name: ") + name);
+ return nullptr;
+ }
+
+private:
+ typedef llvm::StringMap<const lld::Atom *> NameToAtom;
+
+ void add(StringRef name, const lld::Atom *atom) {
+ if (const lld::DefinedAtom *da = dyn_cast<DefinedAtom>(atom)) {
+ if (da->isGroupParent()) {
+ if (_groupMap.count(name)) {
+ _io.setError(Twine("duplicate group name: ") + name);
+ } else {
+ _groupMap[name] = atom;
+ }
+ return;
+ }
+ }
+ if (_nameMap.count(name)) {
+ _io.setError(Twine("duplicate atom name: ") + name);
+ } else {
+ _nameMap[name] = atom;
+ }
+ }
+
+ IO &_io;
+ NameToAtom _nameMap;
+ NameToAtom _groupMap;
+};
+
+// Used in NormalizedFile to hold the atoms lists.
+template <typename T> class AtomList : public lld::File::atom_collection<T> {
+public:
+ virtual lld::File::atom_iterator<T> begin() const {
+ return lld::File::atom_iterator<T>(
+ *this,
+ _atoms.empty() ? 0 : reinterpret_cast<const void *>(_atoms.data()));
+ }
+ virtual lld::File::atom_iterator<T> end() const {
+ return lld::File::atom_iterator<T>(
+ *this, _atoms.empty() ? 0 : reinterpret_cast<const void *>(
+ _atoms.data() + _atoms.size()));
+ }
+ virtual const T *deref(const void *it) const {
+ return *reinterpret_cast<const T *const *>(it);
+ }
+ virtual void next(const void *&it) const {
+ const T *const *p = reinterpret_cast<const T *const *>(it);
+ ++p;
+ it = reinterpret_cast<const void *>(p);
+ }
+ virtual void push_back(const T *element) { _atoms.push_back(element); }
+ virtual uint64_t size() const { return _atoms.size(); }
+ std::vector<const T *> _atoms;
+};
+
+/// Mapping of kind: field in yaml files.
+enum FileKinds {
+ fileKindObjectAtoms, // atom based object file encoded in yaml
+ fileKindArchive, // static archive library encoded in yaml
+ fileKindObjectELF, // ELF object files encoded in yaml
+ fileKindObjectMachO // mach-o object files encoded in yaml
+};
+
+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;
+};
+
+} // namespace anon
+
+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 bool mustQuote(StringRef) { return false; }
+};
+
+template <> struct ScalarEnumerationTraits<lld::File::Kind> {
+ static void enumeration(IO &io, lld::File::Kind &value) {
+ io.enumCase(value, "object", lld::File::kindObject);
+ io.enumCase(value, "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);
+ }
+};
+
+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-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, "thread-data", DefinedAtom::typeThreadData);
+ io.enumCase(value, "thread-zero-fill",DefinedAtom::typeThreadZeroFill);
+ io.enumCase(value, "ro-note", DefinedAtom::typeRONote);
+ io.enumCase(value, "rw-note", DefinedAtom::typeRWNote);
+ io.enumCase(value, "no-alloc", DefinedAtom::typeNoAlloc);
+ io.enumCase(value, "group-comdat", DefinedAtom::typeGroupComdat);
+ io.enumCase(value, "gnu-linkonce", DefinedAtom::typeGnuLinkOnce);
+ }
+};
+
+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:
+/// 2^3 # 8-byte aligned
+/// 7 mod 2^4 # 16-byte aligned plus 7 bytes
+template <> struct ScalarTraits<lld::DefinedAtom::Alignment> {
+ static void output(const lld::DefinedAtom::Alignment &value, void *ctxt,
+ raw_ostream &out) {
+ if (value.modulus == 0) {
+ out << llvm::format("2^%d", value.powerOf2);
+ } else {
+ out << llvm::format("%d mod 2^%d", value.modulus, value.powerOf2);
+ }
+ }
+
+ 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();
+ }
+ if (!scalar.startswith("2^")) {
+ return "malformed alignment";
+ }
+ StringRef powerStr = scalar.drop_front(2);
+ unsigned int power;
+ if (powerStr.getAsInteger(0, power)) {
+ return "malformed alignment power";
+ }
+ value.powerOf2 = power;
+ if (value.modulus > (1 << value.powerOf2)) {
+ return "malformed alignment, modulus too large for power";
+ }
+ return StringRef(); // returning empty string means success
+ }
+
+ static bool mustQuote(StringRef) { return false; }
+};
+
+template <> struct ScalarEnumerationTraits<FileKinds> {
+ static void enumeration(IO &io, FileKinds &value) {
+ io.enumCase(value, "object", fileKindObjectAtoms);
+ io.enumCase(value, "archive", fileKindArchive);
+ io.enumCase(value, "object-elf", fileKindObjectELF);
+ io.enumCase(value, "object-mach-o", fileKindObjectMachO);
+ }
+};
+
+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 const T *&element(IO &io, AtomList<T> &seq, size_t index) {
+ if (index >= seq._atoms.size())
+ seq._atoms.resize(index + 1);
+ return seq._atoms[index];
+ }
+};
+
+// 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 bool mustQuote(StringRef) { return false; }
+};
+
+// 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(""), _path() {}
+ 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 atom_collection<lld::DefinedAtom> &defined() const override {
+ return _noDefinedAtoms;
+ }
+ const atom_collection<lld::UndefinedAtom> &undefined() const override {
+ return _noUndefinedAtoms;
+ }
+ virtual const atom_collection<lld::SharedLibraryAtom> &
+ sharedLibrary() const override {
+ return _noSharedLibraryAtoms;
+ }
+ const atom_collection<lld::AbsoluteAtom> &absolute() const override {
+ return _noAbsoluteAtoms;
+ }
+ File *find(StringRef name, bool dataSymbolOnly) override {
+ for (const ArchMember &member : _members) {
+ for (const lld::DefinedAtom *atom : member._content->defined()) {
+ if (name == atom->name()) {
+ if (!dataSymbolOnly)
+ return const_cast<File *>(member._content);
+ switch (atom->contentType()) {
+ case lld::DefinedAtom::typeData:
+ case lld::DefinedAtom::typeZeroFill:
+ return const_cast<File *>(member._content);
+ default:
+ break;
+ }
+ }
+ }
+ }
+ return nullptr;
+ }
+
+ virtual 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("", kindObject), _io(io), _rnb(nullptr) {}
+ NormalizedFile(IO &io, const lld::File *file)
+ : File(file->path(), kindObject), _io(io),
+ _rnb(new RefNameBuilder(*file)), _path(file->path()) {
+ for (const lld::DefinedAtom *a : file->defined())
+ _definedAtoms.push_back(a);
+ for (const lld::UndefinedAtom *a : file->undefined())
+ _undefinedAtoms.push_back(a);
+ for (const lld::SharedLibraryAtom *a : file->sharedLibrary())
+ _sharedLibraryAtoms.push_back(a);
+ for (const lld::AbsoluteAtom *a : file->absolute())
+ _absoluteAtoms.push_back(a);
+ }
+ const lld::File *denormalize(IO &io);
+
+ const atom_collection<lld::DefinedAtom> &defined() const override {
+ return _definedAtoms;
+ }
+ const atom_collection<lld::UndefinedAtom> &undefined() const override {
+ return _undefinedAtoms;
+ }
+ virtual const atom_collection<lld::SharedLibraryAtom> &
+ sharedLibrary() const override {
+ return _sharedLibraryAtoms;
+ }
+ const atom_collection<lld::AbsoluteAtom> &absolute() const override {
+ return _absoluteAtoms;
+ }
+
+ // 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;
+ 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) {
+ MappingNormalizationHeap<NormalizedFile, const lld::File *> keys(io, file);
+ YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+ assert(info != nullptr);
+ info->_file = keys.operator->();
+
+ io.mapOptional("path", keys->_path);
+ io.mapOptional("defined-atoms", keys->_definedAtoms);
+ io.mapOptional("undefined-atoms", keys->_undefinedAtoms);
+ io.mapOptional("shared-library-atoms", keys->_sharedLibraryAtoms);
+ io.mapOptional("absolute-atoms", keys->_absoluteAtoms);
+ }
+
+ static void mappingArchive(IO &io, const lld::File *&file) {
+ MappingNormalizationHeap<NormArchiveFile, const lld::File *> keys(io, file);
+
+ 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), _targetName(), _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) {
+ MappingNormalizationHeap<NormalizedReference, const lld::Reference *> keys(
+ io, ref);
+
+ 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)), _name(), _refName(), _contentType(),
+ _alignment(0), _content(), _references(), _isGroupChild(false) {
+ static uint32_t ordinalCounter = 1;
+ _ordinal = ordinalCounter++;
+ }
+ NormalizedAtom(IO &io, const lld::DefinedAtom *atom)
+ : _file(fileFromContext(io)), _name(atom->name()), _refName(),
+ _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);
+ }
+ 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; }
+ void setGroupChild(bool val) { _isGroupChild = val; }
+ bool isGroupChild() const { return _isGroupChild; }
+ 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);
+ }
+
+ 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;
+ bool _isGroupChild;
+ };
+
+ static void mapping(IO &io, const lld::DefinedAtom *&atom) {
+ MappingNormalizationHeap<NormalizedAtom, const lld::DefinedAtom *> keys(
+ io, atom);
+ if (io.outputting()) {
+ // If writing YAML, check if atom needs a ref-name.
+ typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
+ YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
+ assert(info != nullptr);
+ NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
+ assert(f);
+ 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(0));
+ 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);
+ }
+};
+
+// YAML conversion for const lld::UndefinedAtom*
+template <> struct MappingTraits<const lld::UndefinedAtom *> {
+
+ class NormalizedAtom : public lld::UndefinedAtom {
+ public:
+ NormalizedAtom(IO &io)
+ : _file(fileFromContext(io)), _name(), _canBeNull(canBeNullNever),
+ _fallback(nullptr) {}
+
+ NormalizedAtom(IO &io, const lld::UndefinedAtom *atom)
+ : _file(fileFromContext(io)), _name(atom->name()),
+ _canBeNull(atom->canBeNull()), _fallback(atom->fallback()) {}
+
+ 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 UndefinedAtom *fallback() const override { return _fallback; }
+
+ const lld::File &_file;
+ StringRef _name;
+ CanBeNull _canBeNull;
+ const UndefinedAtom *_fallback;
+ };
+
+ static void mapping(IO &io, const lld::UndefinedAtom *&atom) {
+ MappingNormalizationHeap<NormalizedAtom, const lld::UndefinedAtom *> keys(
+ io, atom);
+
+ io.mapRequired("name", keys->_name);
+ io.mapOptional("can-be-null", keys->_canBeNull,
+ lld::UndefinedAtom::canBeNullNever);
+ io.mapOptional("fallback", keys->_fallback,
+ (const lld::UndefinedAtom *)nullptr);
+ }
+};
+
+// YAML conversion for const lld::SharedLibraryAtom*
+template <> struct MappingTraits<const lld::SharedLibraryAtom *> {
+
+ class NormalizedAtom : public lld::SharedLibraryAtom {
+ public:
+ NormalizedAtom(IO &io)
+ : _file(fileFromContext(io)), _name(), _loadName(), _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()) {}
+
+ 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) {
+
+ MappingNormalizationHeap<NormalizedAtom, const lld::SharedLibraryAtom *>
+ keys(io, atom);
+
+ 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));
+ }
+};
+
+// YAML conversion for const lld::AbsoluteAtom*
+template <> struct MappingTraits<const lld::AbsoluteAtom *> {
+
+ class NormalizedAtom : public lld::AbsoluteAtom {
+ public:
+ NormalizedAtom(IO &io)
+ : _file(fileFromContext(io)), _name(), _scope(), _value(0) {}
+ NormalizedAtom(IO &io, const lld::AbsoluteAtom *atom)
+ : _file(fileFromContext(io)), _name(atom->name()),
+ _scope(atom->scope()), _value(atom->value()) {}
+ 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) {
+ MappingNormalizationHeap<NormalizedAtom, const lld::AbsoluteAtom *> keys(
+ io, atom);
+
+ 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);
+ }
+};
+
+} // namespace llvm
+} // 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);
+ }
+
+ _definedAtoms._atoms.erase(
+ std::remove_if(_definedAtoms._atoms.begin(), _definedAtoms._atoms.end(),
+ [](const DefinedAtom *a) {
+ return ((const NormalizedAtom *)a)->isGroupChild();
+ }),
+ _definedAtoms._atoms.end());
+
+ return this;
+}
+
+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) {
+ typedef MappingTraits<const lld::DefinedAtom *>::NormalizedAtom NormalizedAtom;
+
+ _target = resolver.lookup(_targetName);
+
+ if (_mappedKind.ns == lld::Reference::KindNamespace::all &&
+ _mappedKind.value == lld::Reference::kindGroupChild) {
+ ((NormalizedAtom *)const_cast<Atom *>(_target))->setGroupChild(true);
+ }
+}
+
+inline StringRef
+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) : _context(context) {}
+
+ std::error_code writeFile(const lld::File &file, StringRef outPath) override {
+ // Create stream to path.
+ std::error_code ec;
+ llvm::raw_fd_ostream out(outPath, ec, llvm::sys::fs::F_Text);
+ if (ec)
+ return ec;
+
+ // Create yaml Output writer, using yaml options for context.
+ YamlContext yamlContext;
+ yamlContext._linkingContext = &_context;
+ yamlContext._registry = &_context.registry();
+ llvm::yaml::Output yout(out, &yamlContext);
+
+ // Write yaml output.
+ const lld::File *fileRef = &file;
+ yout << fileRef;
+
+ return std::error_code();
+ }
+
+private:
+ const LinkingContext &_context;
+};
+
+} // 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, StringRef ext, const MemoryBuffer &) const override {
+ return (ext.equals(".objtxt") || ext.equals(".yaml"));
+ }
+
+ std::error_code
+ loadFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &,
+ std::vector<std::unique_ptr<File>> &result) 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;
+
+ // Error out now if there were parsing errors.
+ if (yin.error())
+ return make_error_code(lld::YamlReaderError::illegal_value);
+
+ std::shared_ptr<MemoryBuffer> smb(mb.release());
+ for (const File *file : createdFiles) {
+ // Note: loadFile() should return vector of *const* File
+ File *f = const_cast<File *>(file);
+ f->setLastError(std::error_code());
+ f->setSharedMemoryBuffer(smb);
+ result.emplace_back(f);
+ }
+ return make_error_code(lld::YamlReaderError::success);
+ }
+
+private:
+ const Registry &_registry;
+};
+
+} // 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/test/CMakeLists.txt b/test/CMakeLists.txt
new file mode 100644
index 000000000000..e29f5f4c5a90
--- /dev/null
+++ b/test/CMakeLists.txt
@@ -0,0 +1,47 @@
+set(LLVM_SOURCE_DIR "${LLVM_MAIN_SRC_DIR}")
+set(LLVM_BINARY_DIR "${LLVM_BINARY_DIR}")
+set(LLVM_BUILD_MODE "%(build_mode)s")
+set(LLVM_TOOLS_DIR "${LLVM_TOOLS_BINARY_DIR}/%(build_config)s")
+set(LLVM_LIBS_DIR "${LLVM_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX}/%(build_config)s")
+set(CLANG_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/..")
+set(CLANG_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/..")
+if(BUILD_SHARED_LIBS)
+ set(ENABLE_SHARED 1)
+else()
+ set(ENABLE_SHARED 0)
+endif(BUILD_SHARED_LIBS)
+
+configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg)
+configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg
+ )
+
+set(LLD_TEST_DEPS
+ FileCheck not llvm-nm
+ lld llvm-config llvm-objdump llvm-readobj yaml2obj obj2yaml
+ linker-script-test macho-dump llvm-mc llvm-nm
+ )
+if (LLVM_INCLUDE_TESTS)
+ set(LLD_TEST_DEPS ${LLD_TEST_DEPS} LLDUnitTests)
+endif()
+
+set(LLD_TEST_PARAMS
+ lld_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
+ )
+
+add_lit_testsuite(check-lld "Running lld test suite"
+ ${CMAKE_CURRENT_BINARY_DIR}
+ PARAMS lld_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
+ lld_unit_site_config=${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg
+ DEPENDS ${LLD_TEST_DEPS}
+ )
+
+set_target_properties(check-lld PROPERTIES FOLDER "lld tests")
+
+# Add a legacy target spelling: lld-test
+add_custom_target(lld-test)
+add_dependencies(lld-test check-lld)
+set_target_properties(lld-test PROPERTIES FOLDER "lld tests")
diff --git a/test/Driver/Inputs/libtest.a b/test/Driver/Inputs/libtest.a
new file mode 100644
index 000000000000..8b277f0dd5dc
--- /dev/null
+++ b/test/Driver/Inputs/libtest.a
@@ -0,0 +1 @@
+!<arch>
diff --git a/test/Driver/Inputs/usr/lib/i386/libtest.a b/test/Driver/Inputs/usr/lib/i386/libtest.a
new file mode 100644
index 000000000000..8b277f0dd5dc
--- /dev/null
+++ b/test/Driver/Inputs/usr/lib/i386/libtest.a
@@ -0,0 +1 @@
+!<arch>
diff --git a/test/Driver/Inputs/usr/lib/libtest.a b/test/Driver/Inputs/usr/lib/libtest.a
new file mode 100644
index 000000000000..8b277f0dd5dc
--- /dev/null
+++ b/test/Driver/Inputs/usr/lib/libtest.a
@@ -0,0 +1 @@
+!<arch>
diff --git a/test/Driver/def-lib-search.test b/test/Driver/def-lib-search.test
new file mode 100644
index 000000000000..818cbfe6ad61
--- /dev/null
+++ b/test/Driver/def-lib-search.test
@@ -0,0 +1,8 @@
+# Check that search paths explicitly provided by the -L option
+# are used in search before default paths.
+
+RUN: not lld -flavor gnu -target x86_64 -t -ltest \
+RUN: --sysroot=%p/Inputs -L%p/Inputs 2> %t
+RUN: FileCheck %s < %t
+
+CHECK: {{[^ ]+}}{{[\\/]}}Inputs{{[\\/]}}libtest.a
diff --git a/test/Driver/flavor-option.test b/test/Driver/flavor-option.test
new file mode 100644
index 000000000000..2ca3b410cbe2
--- /dev/null
+++ b/test/Driver/flavor-option.test
@@ -0,0 +1,8 @@
+# a) the -flavor option is position independent and does not need to be the 1st
+# argument in the command line (bug 20975);
+# b) UniversalDriver correctly removes -flavor along with its value and the
+# underlying linker does not get a corrupted command line (bug 20977).
+RUN: lld --help -flavor gnu | FileCheck %s
+
+CHECK: --noinhibit-exec
+CHECK: --output-filetype
diff --git a/test/Driver/lib-search.test b/test/Driver/lib-search.test
new file mode 100644
index 000000000000..9d3666f63c36
--- /dev/null
+++ b/test/Driver/lib-search.test
@@ -0,0 +1,24 @@
+RUN: not lld -flavor gnu -t -ltest -L%p/Inputs 2> %t.err
+RUN: FileCheck %s < %t.err
+
+RUN: not lld -flavor gnu -target x86_64--netbsd -t -ltest \
+RUN: --sysroot=%p/Inputs 2> %t2
+RUN: FileCheck -check-prefix=NETBSD-AMD64 %s < %t2
+RUN: not lld -flavor gnu -target x86_64--netbsd -nostdlib -t -ltest \
+RUN: --sysroot=%p/Inputs 2> %t3
+RUN: FileCheck -check-prefix=NETBSD-AMD64-NS %s < %t3
+RUN: not lld -flavor gnu -target i386--netbsd -t -ltest \
+RUN: --sysroot=%p/Inputs 2> %t4
+RUN: FileCheck -check-prefix=NETBSD-I386 %s < %t4
+RUN: not lld -flavor gnu -target x86_64--netbsd -m elf_i386 -t -ltest \
+RUN: --sysroot=%p/Inputs 2> %t5
+RUN: FileCheck -check-prefix=NETBSD-AMD64_32 %s < %t5
+
+# run linker with -t mode to dump full paths to input files
+
+CHECK: {{[^ ]+[\\/]}}Inputs{{[\\/]}}libtest.a
+
+NETBSD-AMD64: {{[^ ]+}}{{[\\/]}}Inputs{{[\\/]}}usr{{[\\/]}}lib{{[\\/]}}libtest.a
+NETBSD-AMD64-NS-NOT: {{[^ ]+}}{{[\\/]}}Inputs{{[\\/]}}usr{{[\\/]}}lib{{[\\/]}}libtest.a
+NETBSD-I386: {{[^ ]+}}{{[\\/]}}Inputs{{[\\/]}}usr{{[\\/]}}lib{{[\\/]}}libtest.a
+NETBSD-AMD64_32: {{[^ ]+}}{{[\\/]}}Inputs{{[\\/]}}usr{{[\\/]}}lib{{[\\/]}}i386{{[\\/]}}libtest.a
diff --git a/test/Driver/so-whole-archive.test b/test/Driver/so-whole-archive.test
new file mode 100644
index 000000000000..0732c35a7a92
--- /dev/null
+++ b/test/Driver/so-whole-archive.test
@@ -0,0 +1,63 @@
+# Check that LLD does not show any error if the --whole-archive
+# is around non-archive.
+
+# RUN: yaml2obj -format=elf -docnum=1 %s > %t-so.o
+# RUN: yaml2obj -format=elf -docnum=2 %s > %t-exe.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t-so.o
+# RUN: lld -flavor gnu -target mipsel -o %t.exe %t-exe.o --whole-archive %t.so
+
+# so.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x10
+ Size: 0x04
+Symbols:
+ Global:
+ - Name: foo
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x04
+
+# exe.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_NOREORDER, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x10
+ Size: 0x04
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x04
+ Info: .text
+ Relocations:
+ - Offset: 0x00
+ Symbol: foo
+ Type: R_MIPS_26
+
+Symbols:
+ Global:
+ - Name: __start
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x04
+ - Name: foo
+...
diff --git a/test/Driver/trivial-driver.test b/test/Driver/trivial-driver.test
new file mode 100644
index 000000000000..196d6cfa9d4d
--- /dev/null
+++ b/test/Driver/trivial-driver.test
@@ -0,0 +1,5 @@
+# This test, tests the Gnu lld option --help
+RUN: lld -flavor gnu --help | FileCheck %s
+
+CHECK: --noinhibit-exec
+CHECK: --output-filetype
diff --git a/test/Driver/undef-basic.objtxt b/test/Driver/undef-basic.objtxt
new file mode 100644
index 000000000000..f942d5c8e904
--- /dev/null
+++ b/test/Driver/undef-basic.objtxt
@@ -0,0 +1,22 @@
+# RUN: lld -flavor gnu -u undefinedsymbol -e entrysymbol %s \
+# RUN: --output-filetype=yaml --noinhibit-exec | FileCheck %s
+
+#
+# Test that we are able to add undefined atoms from the command line
+#
+
+---
+absolute-atoms:
+ - name: putchar
+ value: 0xFFFF0040
+
+ - name: reset
+ value: 0xFFFF0080
+
+...
+
+
+# CHECK: undefined-atoms:
+# CHECK: - name: entrysymbol
+# CHECK: - name: undefinedsymbol
+# CHECK: can-be-null: at-buildtime
diff --git a/test/LinkerScript/expr-precedence.test b/test/LinkerScript/expr-precedence.test
new file mode 100644
index 000000000000..5170e34ba4b3
--- /dev/null
+++ b/test/LinkerScript/expr-precedence.test
@@ -0,0 +1,34 @@
+/*
+ RUN: linker-script-test %s | FileCheck %s
+*/
+SECTIONS {
+ . = foo >= bar + 1 ? bar : 1- - - -1;
+}
+
+/*
+CHECK: kw_sections: SECTIONS
+CHECK: l_brace: {
+CHECK: identifier: .
+CHECK: equal: =
+CHECK: identifier: foo
+CHECK: greaterequal: >=
+CHECK: identifier: bar
+CHECK: plus: +
+CHECK: number: 1
+CHECK: question: ?
+CHECK: identifier: bar
+CHECK: colon: :
+CHECK: number: 1
+CHECK: minus: -
+CHECK: minus: -
+CHECK: minus: -
+CHECK: minus: -
+CHECK: number: 1
+CHECK: semicolon: ;
+CHECK: r_brace: }
+CHECK: eof:
+CHECK: SECTIONS
+CHECK: {
+CHECK: . = (foo >= (bar + 1)) ? bar : (1 - (-(-(-1))))
+CHECK: }
+*/
diff --git a/test/LinkerScript/extern-bad-symbol.test b/test/LinkerScript/extern-bad-symbol.test
new file mode 100644
index 000000000000..279a7cc20567
--- /dev/null
+++ b/test/LinkerScript/extern-bad-symbol.test
@@ -0,0 +1,22 @@
+/*
+ RUN: linker-script-test %s 2> %t | FileCheck %s
+ RUN: FileCheck -input-file %t -check-prefix=CHECK-ERR %s
+*/
+
+
+EXTERN(a b 3)
+/*
+CHECK-ERR: [[@LINE-2]]:12: error: expected symbol in EXTERN.
+CHECK-ERR-NEXT: {{^EXTERN\(a b 3\)}}
+CHECK-ERR-NEXT: {{^ \^}}
+*/
+
+/*
+CHECK: kw_extern: EXTERN
+CHECK: l_paren: (
+CHECK: identifier: a
+CHECK: identifier: b
+CHECK: number: 3
+CHECK: r_paren: )
+CHECK: eof:
+*/
diff --git a/test/LinkerScript/extern-empty.test b/test/LinkerScript/extern-empty.test
new file mode 100644
index 000000000000..a5e1ece084d9
--- /dev/null
+++ b/test/LinkerScript/extern-empty.test
@@ -0,0 +1,19 @@
+/*
+ RUN: linker-script-test %s 2> %t | FileCheck %s
+ RUN: FileCheck -input-file %t -check-prefix=CHECK-ERR %s
+*/
+
+
+EXTERN()
+/*
+CHECK-ERR: [[@LINE-2]]:8: error: expected one or more symbols in EXTERN.
+CHECK-ERR-NEXT: {{^EXTERN()}}
+CHECK-ERR-NEXT: {{^ \^}}
+*/
+
+/*
+CHECK: kw_extern: EXTERN
+CHECK: l_paren: (
+CHECK: r_paren: )
+CHECK: eof:
+*/
diff --git a/test/LinkerScript/extern-valid.test b/test/LinkerScript/extern-valid.test
new file mode 100644
index 000000000000..764b4668a34f
--- /dev/null
+++ b/test/LinkerScript/extern-valid.test
@@ -0,0 +1,29 @@
+/*
+ RUN: linker-script-test %s | FileCheck %s
+*/
+
+EXTERN(a)
+EXTERN(a b)
+EXTERN(_foo _bar _baz)
+
+/*
+CHECK: kw_extern: EXTERN
+CHECK: l_paren: (
+CHECK: identifier: a
+CHECK: r_paren: )
+CHECK: kw_extern: EXTERN
+CHECK: l_paren: (
+CHECK: identifier: a
+CHECK: identifier: b
+CHECK: r_paren: )
+CHECK: kw_extern: EXTERN
+CHECK: l_paren: (
+CHECK: identifier: _foo
+CHECK: identifier: _bar
+CHECK: identifier: _baz
+CHECK: r_paren: )
+CHECK: eof:
+CHECK: EXTERN(a)
+CHECK: EXTERN(a b)
+CHECK: EXTERN(_foo _bar _baz)
+*/
diff --git a/test/LinkerScript/incomplete-ternary.test b/test/LinkerScript/incomplete-ternary.test
new file mode 100644
index 000000000000..fae30537d2de
--- /dev/null
+++ b/test/LinkerScript/incomplete-ternary.test
@@ -0,0 +1,25 @@
+/*
+ RUN: linker-script-test %s 2> %t | FileCheck %s
+ RUN: FileCheck -input-file %t -check-prefix=CHECK-ERR %s
+*/
+SECTIONS {
+ . = foo ? bar;
+/*
+CHECK-ERR: [[@LINE-2]]:18: error: expected :
+CHECK-ERR-NEXT: {{^ \. = foo \? bar;}}
+CHECK-ERR-NEXT: {{^ \^}}
+*/
+}
+
+/*
+CHECK: kw_sections: SECTIONS
+CHECK: l_brace: {
+CHECK: identifier: .
+CHECK: equal: =
+CHECK: identifier: foo
+CHECK: question: ?
+CHECK: identifier: bar
+CHECK: semicolon: ;
+CHECK: r_brace: }
+CHECK: eof:
+*/
diff --git a/test/LinkerScript/libname-err-1.test b/test/LinkerScript/libname-err-1.test
new file mode 100644
index 000000000000..451a469336bd
--- /dev/null
+++ b/test/LinkerScript/libname-err-1.test
@@ -0,0 +1,11 @@
+/* RUN: linker-script-test %s 2>&1 | FileCheck %s
+*/
+
+OUTPUT_ARCH(i386:x86_64)
+OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
+GROUP( -l### )
+ENTRY(init)
+
+/*
+CHECK: libname-err-1.test:6:10: error: expected )
+*/
diff --git a/test/LinkerScript/libname-err-2.test b/test/LinkerScript/libname-err-2.test
new file mode 100644
index 000000000000..f1d96d718151
--- /dev/null
+++ b/test/LinkerScript/libname-err-2.test
@@ -0,0 +1,11 @@
+/* RUN: linker-script-test %s 2>&1 | FileCheck %s
+*/
+
+OUTPUT_ARCH(i386:x86_64)
+OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
+GROUP( -l )
+ENTRY(init)
+
+/*
+CHECK: libname-err-2.test:6:10: error: expected )
+*/
diff --git a/test/LinkerScript/linker-script-outputformat.test b/test/LinkerScript/linker-script-outputformat.test
new file mode 100644
index 000000000000..b47bb38ad8d8
--- /dev/null
+++ b/test/LinkerScript/linker-script-outputformat.test
@@ -0,0 +1,12 @@
+/* RUN: linker-script-test %s | FileCheck %s
+*/
+
+OUTPUT_FORMAT(elf64-x86-64)
+
+/*
+CHECK: kw_output_format: OUTPUT_FORMAT
+CHECK: l_paren: (
+CHECK: identifier: elf64-x86-64
+CHECK: r_paren: )
+CHECK: OUTPUT_FORMAT("elf64-x86-64")
+*/
diff --git a/test/LinkerScript/linker-script.test b/test/LinkerScript/linker-script.test
new file mode 100644
index 000000000000..421493666e84
--- /dev/null
+++ b/test/LinkerScript/linker-script.test
@@ -0,0 +1,46 @@
+/* RUN: linker-script-test %s | FileCheck %s
+*/
+
+OUTPUT_ARCH(i386:x86_64)
+OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
+OUTPUT("/out/foo")
+GROUP ( /lib/x86_64-linux-gnu/libc.so.6 /usr/lib/x86_64-linux-gnu/libc_nonshared.a AS_NEEDED ( /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 ) -lm -l:libgcc.a )
+ENTRY(init)
+
+/*
+CHECK: kw_output_arch: OUTPUT_ARCH
+CHECK: l_paren: (
+CHECK: identifier: i386:x86_64
+CHECK: r_paren: )
+CHECK: kw_output_format: OUTPUT_FORMAT
+CHECK: l_paren: (
+CHECK: identifier: elf64-x86-64
+CHECK: comma: ,
+CHECK: identifier: elf64-x86-64
+CHECK: comma: ,
+CHECK: identifier: elf64-x86-64
+CHECK: r_paren: )
+CHECK: kw_output: OUTPUT
+CHECK: l_paren: (
+CHECK: identifier: /out/foo
+CHECK: r_paren: )
+CHECK: kw_group: GROUP
+CHECK: l_paren: (
+CHECK: identifier: /lib/x86_64-linux-gnu/libc.so.6
+CHECK: identifier: /usr/lib/x86_64-linux-gnu/libc_nonshared.a
+CHECK: kw_as_needed: AS_NEEDED
+CHECK: l_paren: (
+CHECK: identifier: /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
+CHECK: r_paren: )
+CHECK: libname: m
+CHECK: libname: :libgcc.a
+CHECK: r_paren: )
+CHECK: kw_entry: ENTRY
+CHECK: l_paren: (
+CHECK: identifier: init
+CHECK: r_paren: )
+CHECK: eof:
+CHECK: OUTPUT_FORMAT("elf64-x86-64","elf64-x86-64","elf64-x86-64")
+CHECK: GROUP(/lib/x86_64-linux-gnu/libc.so.6 /usr/lib/x86_64-linux-gnu/libc_nonshared.a AS_NEEDED(/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2) -lm -l:libgcc.a)
+CHECK: ENTRY(init)
+*/
diff --git a/test/LinkerScript/memory-empty.test b/test/LinkerScript/memory-empty.test
new file mode 100644
index 000000000000..b71022afdff3
--- /dev/null
+++ b/test/LinkerScript/memory-empty.test
@@ -0,0 +1,17 @@
+/*
+ RUN: linker-script-test %s | FileCheck %s
+*/
+
+MEMORY
+{
+}
+
+/*
+CHECK: kw_memory: MEMORY
+CHECK: l_brace: {
+CHECK: r_brace: }
+CHECK: eof:
+CHECK: MEMORY
+CHECK: {
+CHECK: }
+*/
diff --git a/test/LinkerScript/memory-missing-attrs.test b/test/LinkerScript/memory-missing-attrs.test
new file mode 100644
index 000000000000..fbbf38b76514
--- /dev/null
+++ b/test/LinkerScript/memory-missing-attrs.test
@@ -0,0 +1,32 @@
+/*
+ RUN: linker-script-test %s 2> %t | FileCheck %s
+ RUN: FileCheck -input-file %t -check-prefix=CHECK-ERR %s
+*/
+
+MEMORY
+{
+ ram () : ORIGIN = 0x20000000, LENGTH = 128M
+/*
+CHECK-ERR: [[@LINE-2]]:8: error: Expected memory attribute string.
+CHECK-ERR-NEXT: {{^ ram \(\) : ORIGIN = 0x20000000, LENGTH = 128M}}
+CHECK-ERR-NEXT: {{^ \^}}
+*/
+}
+
+/*
+CHECK: kw_memory: MEMORY
+CHECK: l_brace: {
+CHECK: identifier: ram
+CHECK: l_paren: (
+CHECK: r_paren: )
+CHECK: colon: :
+CHECK: kw_origin: ORIGIN
+CHECK: equal: =
+CHECK: number: 0x20000000
+CHECK: comma: ,
+CHECK: kw_length: LENGTH
+CHECK: equal: =
+CHECK: number: 128M
+CHECK: r_brace: }
+CHECK: eof:
+*/
diff --git a/test/LinkerScript/memory-missing-length.test b/test/LinkerScript/memory-missing-length.test
new file mode 100644
index 000000000000..f317c9a26788
--- /dev/null
+++ b/test/LinkerScript/memory-missing-length.test
@@ -0,0 +1,29 @@
+/*
+ RUN: linker-script-test %s 2> %t | FileCheck %s
+ RUN: FileCheck -input-file %t -check-prefix=CHECK-ERR %s
+*/
+
+MEMORY
+{
+ ram (rwx) : ORIGIN = 0x20000000,
+}
+/*
+CHECK-ERR: [[@LINE-2]]:1: error: expected LENGTH
+CHECK-ERR-NEXT: {{^}}}
+CHECK-ERR-NEXT: {{^\^}}
+*/
+
+/*
+CHECK: kw_memory: MEMORY
+CHECK: l_brace: {
+CHECK: identifier: ram
+CHECK: l_paren: (
+CHECK: identifier: rwx
+CHECK: r_paren: )
+CHECK: colon: :
+CHECK: kw_origin: ORIGIN
+CHECK: equal: =
+CHECK: number: 0x20000000
+CHECK: r_brace: }
+CHECK: eof:
+*/
diff --git a/test/LinkerScript/memory-missing-name.test b/test/LinkerScript/memory-missing-name.test
new file mode 100644
index 000000000000..46597d4351d3
--- /dev/null
+++ b/test/LinkerScript/memory-missing-name.test
@@ -0,0 +1,31 @@
+/*
+ RUN: linker-script-test %s 2> %t | FileCheck %s
+ RUN: FileCheck -input-file %t -check-prefix=CHECK-ERR %s
+*/
+
+MEMORY
+{
+ (rwx) : ORIGIN = 0x20000000, LENGTH = 128M
+/*
+CHECK-ERR: [[@LINE-2]]:3: error: expected memory block definition.
+CHECK-ERR-NEXT: {{^ \(rwx\) : ORIGIN = 0x20000000, LENGTH = 128M}}
+CHECK-ERR-NEXT: {{^ \^}}
+*/
+}
+
+/*
+CHECK: kw_memory: MEMORY
+CHECK: l_brace: {
+CHECK: l_paren: (
+CHECK: r_paren: )
+CHECK: colon: :
+CHECK: kw_origin: ORIGIN
+CHECK: equal: =
+CHECK: number: 0x20000000
+CHECK: comma: ,
+CHECK: kw_length: LENGTH
+CHECK: equal: =
+CHECK: number: 128M
+CHECK: r_brace: }
+CHECK: eof:
+*/
diff --git a/test/LinkerScript/memory-missing-origin.test b/test/LinkerScript/memory-missing-origin.test
new file mode 100644
index 000000000000..50a64d17d6c5
--- /dev/null
+++ b/test/LinkerScript/memory-missing-origin.test
@@ -0,0 +1,30 @@
+/*
+ RUN: linker-script-test %s 2> %t | FileCheck %s
+ RUN: FileCheck -input-file %t -check-prefix=CHECK-ERR %s
+*/
+
+MEMORY
+{
+ ram (rwx) : LENGTH = 128M
+/*
+CHECK-ERR: [[@LINE-2]]:15: error: expected ORIGIN
+CHECK-ERR-NEXT: {{^ ram \(rwx\) : LENGTH = 128M}}
+CHECK-ERR-NEXT: {{^ \^}}
+*/
+
+}
+
+/*
+CHECK: kw_memory: MEMORY
+CHECK: l_brace: {
+CHECK: identifier: ram
+CHECK: l_paren: (
+CHECK: identifier: rwx
+CHECK: r_paren: )
+CHECK: colon: :
+CHECK: kw_length: LENGTH
+CHECK: equal: =
+CHECK: number: 128M
+CHECK: r_brace: }
+CHECK: eof:
+*/
diff --git a/test/LinkerScript/memory-valid.test b/test/LinkerScript/memory-valid.test
new file mode 100644
index 000000000000..7a0e906c5fb5
--- /dev/null
+++ b/test/LinkerScript/memory-valid.test
@@ -0,0 +1,56 @@
+/*
+ RUN: linker-script-test %s | FileCheck %s
+*/
+
+MEMORY
+{
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 96K
+ rom (rx) : org = 0x0, len = 256K
+ boot : o = 0x1000000, l = 0x5f00
+}
+
+/*
+CHECK: kw_memory: MEMORY
+CHECK: l_brace: {
+CHECK: identifier: ram
+CHECK: l_paren: (
+CHECK: identifier: rwx
+CHECK: r_paren: )
+CHECK: colon: :
+CHECK: kw_origin: ORIGIN
+CHECK: equal: =
+CHECK: number: 0x20000000
+CHECK: comma: ,
+CHECK: kw_length: LENGTH
+CHECK: equal: =
+CHECK: number: 96K
+CHECK: identifier: rom
+CHECK: l_paren: (
+CHECK: identifier: rx
+CHECK: r_paren: )
+CHECK: colon: :
+CHECK: kw_origin: org
+CHECK: equal: =
+CHECK: number: 0x0
+CHECK: comma: ,
+CHECK: kw_length: len
+CHECK: equal: =
+CHECK: number: 256K
+CHECK: identifier: boot
+CHECK: colon: :
+CHECK: kw_origin: o
+CHECK: equal: =
+CHECK: number: 0x1000000
+CHECK: comma: ,
+CHECK: kw_length: l
+CHECK: equal: =
+CHECK: number: 0x5f00
+CHECK: r_brace: }
+CHECK: eof:
+CHECK: MEMORY
+CHECK: {
+CHECK: ram (rwx) : ORIGIN = 536870912, LENGTH = 98304
+CHECK: rom (rx) : ORIGIN = 0, LENGTH = 262144
+CHECK: boot : ORIGIN = 16777216, LENGTH = 24320
+CHECK: }
+*/
diff --git a/test/LinkerScript/missing-entry-symbol.test b/test/LinkerScript/missing-entry-symbol.test
new file mode 100644
index 000000000000..54e8f75c90a4
--- /dev/null
+++ b/test/LinkerScript/missing-entry-symbol.test
@@ -0,0 +1,21 @@
+/*
+ RUN: linker-script-test %s 2> %t | FileCheck %s
+ RUN: FileCheck -input-file %t -check-prefix=CHECK-ERR %s
+*/
+SECTIONS {
+ ENTRY()
+/*
+CHECK-ERR: [[@LINE-2]]:11: error: expected identifier in ENTRY
+CHECK-ERR-NEXT: {{^ ENTRY()}}
+CHECK-ERR-NEXT: {{^ \^}}
+*/
+}
+
+/*
+CHECK: l_brace: {
+CHECK: kw_entry: ENTRY
+CHECK: l_paren: (
+CHECK: r_paren: )
+CHECK: r_brace: }
+CHECK: eof:
+*/
diff --git a/test/LinkerScript/missing-input-file-name.test b/test/LinkerScript/missing-input-file-name.test
new file mode 100644
index 000000000000..c4218ccef321
--- /dev/null
+++ b/test/LinkerScript/missing-input-file-name.test
@@ -0,0 +1,25 @@
+/*
+ RUN: linker-script-test %s 2> %t | FileCheck %s
+ RUN: FileCheck -input-file %t -check-prefix=CHECK-ERR %s
+*/
+SECTIONS {
+ .text : { ()}
+/*
+CHECK-ERR: [[@LINE-2]]:15: error: expected symbol assignment or input file name.
+CHECK-ERR-NEXT: {{^ \.text : { \(\)}}}
+CHECK-ERR-NEXT: {{^ \^}}
+*/
+}
+
+/*
+CHECK: kw_sections: SECTIONS
+CHECK: l_brace: {
+CHECK: identifier: .text
+CHECK: colon: :
+CHECK: l_brace: {
+CHECK: l_paren: (
+CHECK: r_paren: )
+CHECK: r_brace: }
+CHECK: r_brace: }
+CHECK: eof:
+*/
diff --git a/test/LinkerScript/missing-input-sections.test b/test/LinkerScript/missing-input-sections.test
new file mode 100644
index 000000000000..5db93444b1a9
--- /dev/null
+++ b/test/LinkerScript/missing-input-sections.test
@@ -0,0 +1,27 @@
+/*
+ RUN: linker-script-test %s 2> %t | FileCheck %s
+ RUN: FileCheck -input-file %t -check-prefix=CHECK-ERR %s
+*/
+SECTIONS {
+ .text : { *(+)}
+/*
+CHECK-ERR: [[@LINE-2]]:16: error: expected )
+CHECK-ERR-NEXT: {{^ \.text : { \*\(\+\)}}}
+CHECK-ERR-NEXT: {{^ \^}}
+*/
+}
+
+/*
+CHECK: kw_sections: SECTIONS
+CHECK: l_brace: {
+CHECK: identifier: .text
+CHECK: colon: :
+CHECK: l_brace: {
+CHECK: star: *
+CHECK: l_paren: (
+CHECK: plus: +
+CHECK: r_paren: )
+CHECK: r_brace: }
+CHECK: r_brace: }
+CHECK: eof:
+*/
diff --git a/test/LinkerScript/missing-operand.test b/test/LinkerScript/missing-operand.test
new file mode 100644
index 000000000000..cfa87bf40768
--- /dev/null
+++ b/test/LinkerScript/missing-operand.test
@@ -0,0 +1,24 @@
+/*
+ RUN: linker-script-test %s 2> %t | FileCheck %s
+ RUN: FileCheck -check-prefix=CHECK-ERR -input-file %t %s
+*/
+SECTIONS {
+ . = foo / ;
+/*
+CHECK-ERR: [[@LINE-2]]:15: error: expected symbol, number, minus, tilde or left parenthesis.
+CHECK-ERR-NEXT: {{^ . = foo / ;}}
+CHECK-ERR-NEXT: {{^ \^}}
+*/
+}
+
+/*
+CHECK: kw_sections: SECTIONS
+CHECK: l_brace: {
+CHECK: identifier: .
+CHECK: equal: =
+CHECK: identifier: foo
+CHECK: slash: /
+CHECK: semicolon: ;
+CHECK: r_brace: }
+CHECK: eof:
+ */
diff --git a/test/LinkerScript/missing-output-section-name.test b/test/LinkerScript/missing-output-section-name.test
new file mode 100644
index 000000000000..79792982b619
--- /dev/null
+++ b/test/LinkerScript/missing-output-section-name.test
@@ -0,0 +1,25 @@
+/*
+ RUN: linker-script-test %s 2> %t | FileCheck %s
+ RUN: FileCheck -input-file %t -check-prefix=CHECK-ERR %s
+*/
+SECTIONS {
+ : { *()}
+/*
+CHECK-ERR: [[@LINE-2]]:5: error: expected symbol assignment, entry, overlay or output section name
+CHECK-ERR-NEXT: {{^ : { \*\(\)}}}
+CHECK-ERR-NEXT: {{^ \^}}
+*/
+}
+
+/*
+CHECK: kw_sections: SECTIONS
+CHECK: l_brace: {
+CHECK: colon: :
+CHECK: l_brace: {
+CHECK: star: *
+CHECK: l_paren: (
+CHECK: r_paren: )
+CHECK: r_brace: }
+CHECK: r_brace: }
+CHECK: eof:
+*/
diff --git a/test/LinkerScript/missing-symbol.test b/test/LinkerScript/missing-symbol.test
new file mode 100644
index 000000000000..4e8777ef40b9
--- /dev/null
+++ b/test/LinkerScript/missing-symbol.test
@@ -0,0 +1,24 @@
+/*
+ RUN: linker-script-test %s 2> %t | FileCheck %s
+ RUN: FileCheck -input-file %t -check-prefix=CHECK-ERR %s
+*/
+SECTIONS {
+ = foo + bar;
+/*
+CHECK-ERR: [[@LINE-2]]:5: error: expected symbol assignment, entry, overlay or output section name.
+CHECK-ERR-NEXT: {{^ = foo \+ bar;}}
+CHECK-ERR-NEXT: {{^ \^}}
+*/
+}
+
+/*
+CHECK: kw_sections: SECTIONS
+CHECK: l_brace: {
+CHECK: equal: =
+CHECK: identifier: foo
+CHECK: plus: +
+CHECK: identifier: bar
+CHECK: semicolon: ;
+CHECK: r_brace: }
+CHECK: eof:
+*/
diff --git a/test/LinkerScript/sections.test b/test/LinkerScript/sections.test
new file mode 100644
index 000000000000..8f7d01418044
--- /dev/null
+++ b/test/LinkerScript/sections.test
@@ -0,0 +1,618 @@
+/*
+ This test exercises parsing typical commands found in GNU ld linker scripts.
+ RUN: linker-script-test %s | FileCheck %s
+*/
+
+SEARCH_DIR("/usr/x86_64-linux-gnu/lib64"); SEARCH_DIR("=/usr/local/lib/x86_64-linux-gnu");
+SECTIONS
+{
+ PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS;
+ .interp : { *(.interp) }
+ .note.gnu.build-id : { *(.note.gnu.build-id) }
+ .hash : { *(.hash) }
+ .rela.dyn :
+ {
+ *(.rela.init)
+ *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
+ *(.rela.fini)
+ *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
+ }
+ .rela.plt :
+ {
+ *(.rela.plt)
+ PROVIDE_HIDDEN (__rela_iplt_start = .);
+ *(.rela.iplt)
+ PROVIDE_HIDDEN (__rela_iplt_end = .);
+ }
+ .init :
+ {
+ KEEP (*(SORT_NONE(.init)))
+ } =0x909090909090909090909090
+ PROVIDE (__etext = .);
+ .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) }
+ .exception_ranges : ONLY_IF_RO { *(.exception_ranges
+ .exception_ranges*) }
+ . = ALIGN (CONSTANT (MAXPAGESIZE)) - ((CONSTANT (MAXPAGESIZE) - .) & (CONSTANT (MAXPAGESIZE) - 1)); . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
+ /* Exception handling */
+ .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) }
+ .ctors :
+ {
+ KEEP (*crtbegin.o(.ctors))
+ KEEP (*crtbegin?.o(.ctors))
+ KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*(.ctors))
+ }
+ .dtors :
+ {
+ KEEP (*crtbegin.o(.dtors))
+ KEEP (*crtbegin?.o(.dtors))
+ KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*(.dtors))
+ }
+ . = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .);
+ .got.plt : { *(.got.plt) *(.igot.plt) }
+ .lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
+ {
+ *(.lrodata .lrodata.* .gnu.linkonce.lr.*)
+ }
+ .ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
+ {
+ *(.ldata .ldata.* .gnu.linkonce.l.*)
+ . = ALIGN(. != 0 ? 64 / 8 : 1);
+ }
+ . = ALIGN(64 / 8);
+ _end = .; PROVIDE (end = .);
+ . = DATA_SEGMENT_END (.);
+ /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
+}
+
+/*
+CHECK: kw_search_dir: SEARCH_DIR
+CHECK: l_paren: (
+CHECK: identifier: /usr/x86_64-linux-gnu/lib64
+CHECK: r_paren: )
+CHECK: semicolon: ;
+CHECK: kw_search_dir: SEARCH_DIR
+CHECK: l_paren: (
+CHECK: identifier: =/usr/local/lib/x86_64-linux-gnu
+CHECK: r_paren: )
+CHECK: semicolon: ;
+CHECK: kw_sections: SECTIONS
+CHECK: l_brace: {
+CHECK: kw_provide: PROVIDE
+CHECK: l_paren: (
+CHECK: identifier: __executable_start
+CHECK: equal: =
+CHECK: identifier: SEGMENT_START
+CHECK: l_paren: (
+CHECK: identifier: text-segment
+CHECK: comma: ,
+CHECK: number: 0x400000
+CHECK: r_paren: )
+CHECK: r_paren: )
+CHECK: semicolon: ;
+CHECK: identifier: .
+CHECK: equal: =
+CHECK: identifier: SEGMENT_START
+CHECK: l_paren: (
+CHECK: identifier: text-segment
+CHECK: comma: ,
+CHECK: number: 0x400000
+CHECK: r_paren: )
+CHECK: plus: +
+CHECK: identifier: SIZEOF_HEADERS
+CHECK: semicolon: ;
+CHECK: identifier: .interp
+CHECK: colon: :
+CHECK: l_brace: {
+CHECK: star: *
+CHECK: l_paren: (
+CHECK: identifier: .interp
+CHECK: r_paren: )
+CHECK: r_brace: }
+CHECK: identifier: .note.gnu.build-id
+CHECK: colon: :
+CHECK: l_brace: {
+CHECK: star: *
+CHECK: l_paren: (
+CHECK: identifier: .note.gnu.build-id
+CHECK: r_paren: )
+CHECK: r_brace: }
+CHECK: identifier: .hash
+CHECK: colon: :
+CHECK: l_brace: {
+CHECK: star: *
+CHECK: l_paren: (
+CHECK: identifier: .hash
+CHECK: r_paren: )
+CHECK: r_brace: }
+CHECK: identifier: .rela.dyn
+CHECK: colon: :
+CHECK: l_brace: {
+CHECK: star: *
+CHECK: l_paren: (
+CHECK: identifier: .rela.init
+CHECK: r_paren: )
+CHECK: star: *
+CHECK: l_paren: (
+CHECK: identifier: .rela.text
+CHECK: identifier: .rela.text.*
+CHECK: identifier: .rela.gnu.linkonce.t.*
+CHECK: r_paren: )
+CHECK: star: *
+CHECK: l_paren: (
+CHECK: identifier: .rela.fini
+CHECK: r_paren: )
+CHECK: star: *
+CHECK: l_paren: (
+CHECK: identifier: .rela.rodata
+CHECK: identifier: .rela.rodata.*
+CHECK: identifier: .rela.gnu.linkonce.r.*
+CHECK: r_paren: )
+CHECK: r_brace: }
+CHECK: identifier: .rela.plt
+CHECK: colon: :
+CHECK: l_brace: {
+CHECK: star: *
+CHECK: l_paren: (
+CHECK: identifier: .rela.plt
+CHECK: r_paren: )
+CHECK: kw_provide_hidden: PROVIDE_HIDDEN
+CHECK: l_paren: (
+CHECK: identifier: __rela_iplt_start
+CHECK: equal: =
+CHECK: identifier: .
+CHECK: r_paren: )
+CHECK: semicolon: ;
+CHECK: star: *
+CHECK: l_paren: (
+CHECK: identifier: .rela.iplt
+CHECK: r_paren: )
+CHECK: kw_provide_hidden: PROVIDE_HIDDEN
+CHECK: l_paren: (
+CHECK: identifier: __rela_iplt_end
+CHECK: equal: =
+CHECK: identifier: .
+CHECK: r_paren: )
+CHECK: semicolon: ;
+CHECK: r_brace: }
+CHECK: identifier: .init
+CHECK: colon: :
+CHECK: l_brace: {
+CHECK: kw_keep: KEEP
+CHECK: l_paren: (
+CHECK: star: *
+CHECK: l_paren: (
+CHECK: kw_sort_none: SORT_NONE
+CHECK: l_paren: (
+CHECK: identifier: .init
+CHECK: r_paren: )
+CHECK: r_paren: )
+CHECK: r_paren: )
+CHECK: r_brace: }
+CHECK: kw_provide: PROVIDE
+CHECK: l_paren: (
+CHECK: identifier: __etext
+CHECK: equal: =
+CHECK: identifier: .
+CHECK: r_paren: )
+CHECK: semicolon: ;
+CHECK: identifier: .eh_frame
+CHECK: colon: :
+CHECK: kw_only_if_ro: ONLY_IF_RO
+CHECK: l_brace: {
+CHECK: kw_keep: KEEP
+CHECK: l_paren: (
+CHECK: star: *
+CHECK: l_paren: (
+CHECK: identifier: .eh_frame
+CHECK: r_paren: )
+CHECK: r_paren: )
+CHECK: r_brace: }
+CHECK: identifier: .exception_ranges
+CHECK: colon: :
+CHECK: kw_only_if_ro: ONLY_IF_RO
+CHECK: l_brace: {
+CHECK: star: *
+CHECK: l_paren: (
+CHECK: identifier: .exception_ranges
+CHECK: identifier: .exception_ranges*
+CHECK: r_paren: )
+CHECK: r_brace: }
+CHECK: identifier: .
+CHECK: equal: =
+CHECK: kw_align: ALIGN
+CHECK: l_paren: (
+CHECK: identifier: CONSTANT
+CHECK: l_paren: (
+CHECK: identifier: MAXPAGESIZE
+CHECK: r_paren: )
+CHECK: r_paren: )
+CHECK: minus: -
+CHECK: l_paren: (
+CHECK: l_paren: (
+CHECK: identifier: CONSTANT
+CHECK: l_paren: (
+CHECK: identifier: MAXPAGESIZE
+CHECK: r_paren: )
+CHECK: minus: -
+CHECK: identifier: .
+CHECK: r_paren: )
+CHECK: amp: &
+CHECK: l_paren: (
+CHECK: identifier: CONSTANT
+CHECK: l_paren: (
+CHECK: identifier: MAXPAGESIZE
+CHECK: r_paren: )
+CHECK: minus: -
+CHECK: number: 1
+CHECK: r_paren: )
+CHECK: r_paren: )
+CHECK: semicolon: ;
+CHECK: identifier: .
+CHECK: equal: =
+CHECK: identifier: DATA_SEGMENT_ALIGN
+CHECK: l_paren: (
+CHECK: identifier: CONSTANT
+CHECK: l_paren: (
+CHECK: identifier: MAXPAGESIZE
+CHECK: r_paren: )
+CHECK: comma: ,
+CHECK: identifier: CONSTANT
+CHECK: l_paren: (
+CHECK: identifier: COMMONPAGESIZE
+CHECK: r_paren: )
+CHECK: r_paren: )
+CHECK: semicolon: ;
+CHECK: identifier: .eh_frame
+CHECK: colon: :
+CHECK: kw_only_if_rw: ONLY_IF_RW
+CHECK: l_brace: {
+CHECK: kw_keep: KEEP
+CHECK: l_paren: (
+CHECK: star: *
+CHECK: l_paren: (
+CHECK: identifier: .eh_frame
+CHECK: r_paren: )
+CHECK: r_paren: )
+CHECK: r_brace: }
+CHECK: identifier: .ctors
+CHECK: colon: :
+CHECK: l_brace: {
+CHECK: kw_keep: KEEP
+CHECK: l_paren: (
+CHECK: identifier: *crtbegin.o
+CHECK: l_paren: (
+CHECK: identifier: .ctors
+CHECK: r_paren: )
+CHECK: r_paren: )
+CHECK: kw_keep: KEEP
+CHECK: l_paren: (
+CHECK: identifier: *crtbegin?.o
+CHECK: l_paren: (
+CHECK: identifier: .ctors
+CHECK: r_paren: )
+CHECK: r_paren: )
+CHECK: kw_keep: KEEP
+CHECK: l_paren: (
+CHECK: star: *
+CHECK: l_paren: (
+CHECK: kw_exclude_file: EXCLUDE_FILE
+CHECK: l_paren: (
+CHECK: identifier: *crtend.o
+CHECK: identifier: *crtend?.o
+CHECK: r_paren: )
+CHECK: identifier: .ctors
+CHECK: r_paren: )
+CHECK: r_paren: )
+CHECK: kw_keep: KEEP
+CHECK: l_paren: (
+CHECK: star: *
+CHECK: l_paren: (
+CHECK: kw_sort_by_name: SORT
+CHECK: l_paren: (
+CHECK: identifier: .ctors.*
+CHECK: r_paren: )
+CHECK: r_paren: )
+CHECK: r_paren: )
+CHECK: kw_keep: KEEP
+CHECK: l_paren: (
+CHECK: star: *
+CHECK: l_paren: (
+CHECK: identifier: .ctors
+CHECK: r_paren: )
+CHECK: r_paren: )
+CHECK: r_brace: }
+CHECK: identifier: .dtors
+CHECK: colon: :
+CHECK: l_brace: {
+CHECK: kw_keep: KEEP
+CHECK: l_paren: (
+CHECK: identifier: *crtbegin.o
+CHECK: l_paren: (
+CHECK: identifier: .dtors
+CHECK: r_paren: )
+CHECK: r_paren: )
+CHECK: kw_keep: KEEP
+CHECK: l_paren: (
+CHECK: identifier: *crtbegin?.o
+CHECK: l_paren: (
+CHECK: identifier: .dtors
+CHECK: r_paren: )
+CHECK: r_paren: )
+CHECK: kw_keep: KEEP
+CHECK: l_paren: (
+CHECK: star: *
+CHECK: l_paren: (
+CHECK: kw_exclude_file: EXCLUDE_FILE
+CHECK: l_paren: (
+CHECK: identifier: *crtend.o
+CHECK: identifier: *crtend?.o
+CHECK: r_paren: )
+CHECK: identifier: .dtors
+CHECK: r_paren: )
+CHECK: r_paren: )
+CHECK: kw_keep: KEEP
+CHECK: l_paren: (
+CHECK: star: *
+CHECK: l_paren: (
+CHECK: kw_sort_by_name: SORT
+CHECK: l_paren: (
+CHECK: identifier: .dtors.*
+CHECK: r_paren: )
+CHECK: r_paren: )
+CHECK: r_paren: )
+CHECK: kw_keep: KEEP
+CHECK: l_paren: (
+CHECK: star: *
+CHECK: l_paren: (
+CHECK: identifier: .dtors
+CHECK: r_paren: )
+CHECK: r_paren: )
+CHECK: r_brace: }
+CHECK: identifier: .
+CHECK: equal: =
+CHECK: identifier: DATA_SEGMENT_RELRO_END
+CHECK: l_paren: (
+CHECK: identifier: SIZEOF
+CHECK: l_paren: (
+CHECK: identifier: .got.plt
+CHECK: r_paren: )
+CHECK: greaterequal: >=
+CHECK: number: 24
+CHECK: question: ?
+CHECK: number: 24
+CHECK: colon: :
+CHECK: number: 0
+CHECK: comma: ,
+CHECK: identifier: .
+CHECK: r_paren: )
+CHECK: semicolon: ;
+CHECK: identifier: .got.plt
+CHECK: colon: :
+CHECK: l_brace: {
+CHECK: star: *
+CHECK: l_paren: (
+CHECK: identifier: .got.plt
+CHECK: r_paren: )
+CHECK: star: *
+CHECK: l_paren: (
+CHECK: identifier: .igot.plt
+CHECK: r_paren: )
+CHECK: r_brace: }
+CHECK: identifier: .lrodata
+CHECK: kw_align: ALIGN
+CHECK: l_paren: (
+CHECK: identifier: CONSTANT
+CHECK: l_paren: (
+CHECK: identifier: MAXPAGESIZE
+CHECK: r_paren: )
+CHECK: r_paren: )
+CHECK: plus: +
+CHECK: l_paren: (
+CHECK: identifier: .
+CHECK: amp: &
+CHECK: l_paren: (
+CHECK: identifier: CONSTANT
+CHECK: l_paren: (
+CHECK: identifier: MAXPAGESIZE
+CHECK: r_paren: )
+CHECK: minus: -
+CHECK: number: 1
+CHECK: r_paren: )
+CHECK: r_paren: )
+CHECK: colon: :
+CHECK: l_brace: {
+CHECK: star: *
+CHECK: l_paren: (
+CHECK: identifier: .lrodata
+CHECK: identifier: .lrodata.*
+CHECK: identifier: .gnu.linkonce.lr.*
+CHECK: r_paren: )
+CHECK: r_brace: }
+CHECK: identifier: .ldata
+CHECK: kw_align: ALIGN
+CHECK: l_paren: (
+CHECK: identifier: CONSTANT
+CHECK: l_paren: (
+CHECK: identifier: MAXPAGESIZE
+CHECK: r_paren: )
+CHECK: r_paren: )
+CHECK: plus: +
+CHECK: l_paren: (
+CHECK: identifier: .
+CHECK: amp: &
+CHECK: l_paren: (
+CHECK: identifier: CONSTANT
+CHECK: l_paren: (
+CHECK: identifier: MAXPAGESIZE
+CHECK: r_paren: )
+CHECK: minus: -
+CHECK: number: 1
+CHECK: r_paren: )
+CHECK: r_paren: )
+CHECK: colon: :
+CHECK: l_brace: {
+CHECK: star: *
+CHECK: l_paren: (
+CHECK: identifier: .ldata
+CHECK: identifier: .ldata.*
+CHECK: identifier: .gnu.linkonce.l.*
+CHECK: r_paren: )
+CHECK: identifier: .
+CHECK: equal: =
+CHECK: kw_align: ALIGN
+CHECK: l_paren: (
+CHECK: identifier: .
+CHECK: exclaimequal: !=
+CHECK: number: 0
+CHECK: question: ?
+CHECK: number: 64
+CHECK: slash: /
+CHECK: number: 8
+CHECK: colon: :
+CHECK: number: 1
+CHECK: r_paren: )
+CHECK: semicolon: ;
+CHECK: r_brace: }
+CHECK: identifier: .
+CHECK: equal: =
+CHECK: kw_align: ALIGN
+CHECK: l_paren: (
+CHECK: number: 64
+CHECK: slash: /
+CHECK: number: 8
+CHECK: r_paren: )
+CHECK: semicolon: ;
+CHECK: identifier: _end
+CHECK: equal: =
+CHECK: identifier: .
+CHECK: semicolon: ;
+CHECK: kw_provide: PROVIDE
+CHECK: l_paren: (
+CHECK: identifier: end
+CHECK: equal: =
+CHECK: identifier: .
+CHECK: r_paren: )
+CHECK: semicolon: ;
+CHECK: identifier: .
+CHECK: equal: =
+CHECK: identifier: DATA_SEGMENT_END
+CHECK: l_paren: (
+CHECK: identifier: .
+CHECK: r_paren: )
+CHECK: semicolon: ;
+CHECK: kw_discard: /DISCARD/
+CHECK: colon: :
+CHECK: l_brace: {
+CHECK: star: *
+CHECK: l_paren: (
+CHECK: identifier: .note.GNU-stack
+CHECK: r_paren: )
+CHECK: star: *
+CHECK: l_paren: (
+CHECK: identifier: .gnu_debuglink
+CHECK: r_paren: )
+CHECK: star: *
+CHECK: l_paren: (
+CHECK: identifier: .gnu.lto_*
+CHECK: r_paren: )
+CHECK: r_brace: }
+CHECK: r_brace: }
+CHECK: eof:
+CHECK: SEARCH_DIR("/usr/x86_64-linux-gnu/lib64")
+CHECK: SEARCH_DIR("=/usr/local/lib/x86_64-linux-gnu")
+CHECK: SECTIONS
+CHECK: {
+CHECK: PROVIDE(__executable_start = SEGMENT_START(text-segment, 4194304))
+CHECK: . = (SEGMENT_START(text-segment, 4194304) + SIZEOF_HEADERS)
+CHECK: .interp :
+CHECK: {
+CHECK: *(.interp)
+CHECK: }
+CHECK: .note.gnu.build-id :
+CHECK: {
+CHECK: *(.note.gnu.build-id)
+CHECK: }
+CHECK: .hash :
+CHECK: {
+CHECK: *(.hash)
+CHECK: }
+CHECK: .rela.dyn :
+CHECK: {
+CHECK: *(.rela.init)
+CHECK: *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
+CHECK: *(.rela.fini)
+CHECK: *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
+CHECK: }
+CHECK: .rela.plt :
+CHECK: {
+CHECK: *(.rela.plt)
+CHECK: PROVIDE_HIDDEN(__rela_iplt_start = .)
+CHECK: *(.rela.iplt)
+CHECK: PROVIDE_HIDDEN(__rela_iplt_end = .)
+CHECK: }
+CHECK: .init :
+CHECK: {
+CHECK: KEEP(*(SORT_NONE(.init)))
+CHECK: } =0x909090909090909090909090
+CHECK: PROVIDE(__etext = .)
+CHECK: .eh_frame :
+CHECK: ONLY_IF_RO {
+CHECK: KEEP(*(.eh_frame))
+CHECK: }
+CHECK: .exception_ranges :
+CHECK: ONLY_IF_RO {
+CHECK: *(.exception_ranges .exception_ranges*)
+CHECK: }
+CHECK: . = (ALIGN(CONSTANT(MAXPAGESIZE)) - ((CONSTANT(MAXPAGESIZE) - .) & (CONSTANT(MAXPAGESIZE) - 1)))
+CHECK: . = DATA_SEGMENT_ALIGN(CONSTANT(MAXPAGESIZE), CONSTANT(COMMONPAGESIZE))
+CHECK: .eh_frame :
+CHECK: ONLY_IF_RW {
+CHECK: KEEP(*(.eh_frame))
+CHECK: }
+CHECK: .ctors :
+CHECK: {
+CHECK: KEEP(*crtbegin.o(.ctors))
+CHECK: KEEP(*crtbegin?.o(.ctors))
+CHECK: KEEP(*(EXCLUDE_FILE(*crtend.o *crtend?.o ) .ctors))
+CHECK: KEEP(*(SORT_BY_NAME(.ctors.*)))
+CHECK: KEEP(*(.ctors))
+CHECK: }
+CHECK: .dtors :
+CHECK: {
+CHECK: KEEP(*crtbegin.o(.dtors))
+CHECK: KEEP(*crtbegin?.o(.dtors))
+CHECK: KEEP(*(EXCLUDE_FILE(*crtend.o *crtend?.o ) .dtors))
+CHECK: KEEP(*(SORT_BY_NAME(.dtors.*)))
+CHECK: KEEP(*(.dtors))
+CHECK: }
+CHECK: . = DATA_SEGMENT_RELRO_END((SIZEOF(.got.plt) >= 24) ? 24 : 0, .)
+CHECK: .got.plt :
+CHECK: {
+CHECK: *(.got.plt)
+CHECK: *(.igot.plt)
+CHECK: }
+CHECK: .lrodata (ALIGN(CONSTANT(MAXPAGESIZE)) + (. & (CONSTANT(MAXPAGESIZE) - 1))) :
+CHECK: {
+CHECK: *(.lrodata .lrodata.* .gnu.linkonce.lr.*)
+CHECK: }
+CHECK: .ldata (ALIGN(CONSTANT(MAXPAGESIZE)) + (. & (CONSTANT(MAXPAGESIZE) - 1))) :
+CHECK: {
+CHECK: *(.ldata .ldata.* .gnu.linkonce.l.*)
+CHECK: . = ALIGN((. != 0) ? (64 / 8) : 1)
+CHECK: }
+CHECK: . = ALIGN((64 / 8))
+CHECK: _end = .
+CHECK: PROVIDE(end = .)
+CHECK: . = DATA_SEGMENT_END(.)
+CHECK: :
+CHECK: {
+CHECK: *(.note.GNU-stack)
+CHECK: *(.gnu_debuglink)
+CHECK: *(.gnu.lto_*)
+CHECK: }
+CHECK: }
+*/
diff --git a/test/Makefile b/test/Makefile
new file mode 100644
index 000000000000..2d45e4fae2a7
--- /dev/null
+++ b/test/Makefile
@@ -0,0 +1,71 @@
+LLD_LEVEL := ..
+include $(LLD_LEVEL)/Makefile
+
+# Test in all immediate subdirectories if unset.
+ifdef TESTSUITE
+TESTDIRS := $(TESTSUITE:%=$(PROJ_SRC_DIR)/%)
+else
+TESTDIRS ?= $(PROJ_SRC_DIR)
+endif
+
+# 'lit' wants objdir paths, so it will pick up the lit.site.cfg.
+TESTDIRS := $(TESTDIRS:$(PROJ_SRC_DIR)%=$(PROJ_OBJ_DIR)%)
+
+# Allow EXTRA_TESTDIRS to provide additional test directories.
+TESTDIRS += $(EXTRA_TESTDIRS)
+
+ifndef TESTARGS
+ifdef VERBOSE
+TESTARGS = -v
+else
+TESTARGS = -s -v
+endif
+endif
+
+# Make sure any extra test suites can find the main site config.
+LIT_ARGS := --param lld_site_config=$(PROJ_OBJ_DIR)/lit.site.cfg
+
+ifdef VG
+ LIT_ARGS += "--vg"
+endif
+
+all:: lit.site.cfg Unit/lit.site.cfg
+ @ echo '--- Running lld tests for $(TARGET_TRIPLE) ---'
+ @ $(PYTHON) $(LLVM_SRC_ROOT)/utils/lit/lit.py \
+ $(LIT_ARGS) $(TESTARGS) $(TESTDIRS)
+
+FORCE:
+
+lit.site.cfg: FORCE
+ @echo "Making lld 'lit.site.cfg' file..."
+ @$(ECHOPATH) s=@LLVM_SOURCE_DIR@=$(LLVM_SRC_ROOT)=g > lit.tmp
+ @$(ECHOPATH) s=@LLVM_BINARY_DIR@=$(LLVM_OBJ_ROOT)=g >> lit.tmp
+ @$(ECHOPATH) s=@LLVM_TOOLS_DIR@=$(ToolDir)=g >> lit.tmp
+ @$(ECHOPATH) s=@LLVM_LIBS_DIR@=$(LibDir)=g >> lit.tmp
+ @$(ECHOPATH) s=@LLD_SOURCE_DIR@=$(PROJ_SRC_DIR)/..=g >> lit.tmp
+ @$(ECHOPATH) s=@LLD_BINARY_DIR@=$(PROJ_OBJ_DIR)/..=g >> lit.tmp
+ @$(ECHOPATH) s=@TARGET_TRIPLE@=$(TARGET_TRIPLE)=g >> lit.tmp
+ @sed -f lit.tmp $(PROJ_SRC_DIR)/lit.site.cfg.in > $@
+ @-rm -f lit.tmp
+
+Unit/lit.site.cfg: FORCE
+ @echo "Making lld 'Unit/lit.site.cfg' file..."
+ @$(MKDIR) $(dir $@)
+ @$(ECHOPATH) s=@LLVM_SOURCE_DIR@=$(LLVM_SRC_ROOT)=g > unit.tmp
+ @$(ECHOPATH) s=@LLVM_BINARY_DIR@=$(LLVM_OBJ_ROOT)=g >> unit.tmp
+ @$(ECHOPATH) s=@LLVM_TOOLS_DIR@=$(ToolDir)=g >> unit.tmp
+ @$(ECHOPATH) s=@LLVM_LIBS_DIR@=$(LibDir)=g >> unit.tmp
+ @$(ECHOPATH) s=@LLD_SOURCE_DIR@=$(PROJ_SRC_DIR)/..=g >> unit.tmp
+ @$(ECHOPATH) s=@LLD_BINARY_DIR@=$(PROJ_OBJ_DIR)/..=g >> unit.tmp
+ @$(ECHOPATH) s=@TARGET_TRIPLE@=$(TARGET_TRIPLE)=g >> unit.tmp
+ @$(ECHOPATH) s=@LLVM_BUILD_MODE@=$(BuildMode)=g >> unit.tmp
+ @$(ECHOPATH) s=@ENABLE_SHARED@=$(ENABLE_SHARED)=g >> unit.tmp
+ @$(ECHOPATH) s=@SHLIBDIR@=$(SharedLibDir)=g >> unit.tmp
+ @$(ECHOPATH) s=@SHLIBPATH_VAR@=$(SHLIBPATH_VAR)=g >> unit.tmp
+ @sed -f unit.tmp $(PROJ_SRC_DIR)/Unit/lit.site.cfg.in > $@
+ @-rm -f unit.tmp
+
+clean::
+ @ find . -name Output | xargs rm -fr
+
+.PHONY: all report clean
diff --git a/test/Unit/lit.cfg b/test/Unit/lit.cfg
new file mode 100644
index 000000000000..4bc973a58edd
--- /dev/null
+++ b/test/Unit/lit.cfg
@@ -0,0 +1,23 @@
+# -*- Python -*-
+
+# Configuration file for the 'lit' test runner.
+
+import os
+
+import lit.formats
+
+# name: The name of this test suite.
+config.name = 'lld-Unit'
+
+# suffixes: A list of file extensions to treat as test files.
+config.suffixes = []
+
+# test_source_root: The root path where unit test binaries are located.
+# test_exec_root: The root path where tests should be run.
+config.test_source_root = os.path.join(config.lld_obj_root, 'unittests')
+config.test_exec_root = config.test_source_root
+
+# testFormat: The test format to use to interpret tests.
+if not hasattr(config, 'llvm_build_mode'):
+ lit_config.fatal("unable to find llvm_build_mode value on config")
+config.test_format = lit.formats.GoogleTest(config.llvm_build_mode, 'Tests')
diff --git a/test/Unit/lit.site.cfg.in b/test/Unit/lit.site.cfg.in
new file mode 100644
index 000000000000..74c5eca91153
--- /dev/null
+++ b/test/Unit/lit.site.cfg.in
@@ -0,0 +1,25 @@
+## Autogenerated by LLVM/lld configuration.
+# Do not edit!
+config.llvm_src_root = "@LLVM_SOURCE_DIR@"
+config.llvm_obj_root = "@LLVM_BINARY_DIR@"
+config.llvm_tools_dir = "@LLVM_TOOLS_DIR@"
+config.llvm_libs_dir = "@LLVM_LIBS_DIR@"
+config.llvm_build_mode = "@LLVM_BUILD_MODE@"
+config.lit_tools_dir = "@LLVM_LIT_TOOLS_DIR@"
+config.lld_obj_root = "@LLD_BINARY_DIR@"
+config.lld_src_root = "@LLD_SOURCE_DIR@"
+config.target_triple = "@TARGET_TRIPLE@"
+config.python_executable = "@PYTHON_EXECUTABLE@"
+
+# Support substitution of the tools and libs dirs with user parameters. This is
+# used when we can't determine the tool dir at configuration time.
+try:
+ config.llvm_tools_dir = config.llvm_tools_dir % lit_config.params
+ config.llvm_libs_dir = config.llvm_libs_dir % lit_config.params
+ config.llvm_build_mode = config.llvm_build_mode % lit_config.params
+except KeyError as e:
+ key, = e.args
+ lit_config.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key,key))
+
+# Let the main config do the real work.
+lit_config.load_config(config, "@LLD_SOURCE_DIR@/test/Unit/lit.cfg")
diff --git a/test/core/absolute-basic.objtxt b/test/core/absolute-basic.objtxt
new file mode 100644
index 000000000000..edfbe8629b0d
--- /dev/null
+++ b/test/core/absolute-basic.objtxt
@@ -0,0 +1,23 @@
+# RUN: lld -core --dead-strip %s | FileCheck %s
+
+#
+# Test that absolute symbols are parsed and preserved
+#
+
+---
+absolute-atoms:
+ - name: putchar
+ value: 0xFFFF0040
+
+ - name: reset
+ value: 0xFFFF0080
+
+...
+
+
+# CHECK: absolute-atoms:
+# CHECK: name: putchar
+# CHECK: value: 0x00000000FFFF0040
+# CHECK: name: reset
+# CHECK: value: 0x00000000FFFF0080
+# CHECK: ...
diff --git a/test/core/absolute-local.objtxt b/test/core/absolute-local.objtxt
new file mode 100644
index 000000000000..1ba4c7f04326
--- /dev/null
+++ b/test/core/absolute-local.objtxt
@@ -0,0 +1,25 @@
+# RUN: lld -core %s | FileCheck %s
+
+#
+# Test that absolute symbols with local scope do not cause name conflict
+#
+---
+absolute-atoms:
+ - name: putchar
+ ref-name: pc1
+ value: 0xFFFF0040
+ scope: static
+
+ - name: putchar
+ ref-name: pc2
+ value: 0xFFFF0040
+ scope: static
+...
+
+# CHECK: ---
+# CHECK: absolute-atoms:
+# CHECK: - name: putchar
+# CHECK: value: 0x00000000FFFF0040
+# CHECK: - name: putchar
+# CHECK: value: 0x00000000FFFF0040
+# CHECK: ...
diff --git a/test/core/archive-basic.objtxt b/test/core/archive-basic.objtxt
new file mode 100644
index 000000000000..ec825c1a7e52
--- /dev/null
+++ b/test/core/archive-basic.objtxt
@@ -0,0 +1,44 @@
+# RUN: lld -core %s | FileCheck %s
+
+#
+# Tests archives in YAML. Tests that an undefined in a regular file will load
+# all atoms in select archive members.
+#
+
+--- !native
+defined-atoms:
+ - name: foo
+ type: code
+
+undefined-atoms:
+ - name: bar
+
+--- !archive
+members:
+ - name: bar.o
+ content: !native
+ defined-atoms:
+ - name: bar
+ scope: global
+ type: code
+
+ - name: bar2
+ type: code
+
+ - name: baz.o
+ content: !native
+ defined-atoms:
+ - name: baz
+ scope: global
+ type: code
+
+ - name: baz2
+ type: code
+...
+
+# CHECK: name: foo
+# CHECK-NOT: undefined-atoms:
+# CHECK: name: bar
+# CHECK: name: bar2
+# CHECK-NOT: name: baz
+# CHECK: ...
diff --git a/test/core/archive-chain.objtxt b/test/core/archive-chain.objtxt
new file mode 100644
index 000000000000..0f80985ec112
--- /dev/null
+++ b/test/core/archive-chain.objtxt
@@ -0,0 +1,70 @@
+# RUN: lld -core %s | FileCheck %s
+
+#
+# Tests that an undefine in one archive can force a load from another archive.
+#
+
+--- !native
+defined-atoms:
+ - name: foo
+ type: code
+
+undefined-atoms:
+ - name: bar1
+
+--- !archive
+members:
+ - name: bar1.o
+ content: !native
+ defined-atoms:
+ - name: bar1
+ scope: global
+ type: code
+
+ - name: bar1b
+ type: code
+
+ undefined-atoms:
+ - name: baz1
+
+ - name: bar2.o
+ content: !native
+ defined-atoms:
+ - name: bar2
+ scope: global
+ type: code
+
+ - name: bar2b
+ type: code
+
+--- !archive
+members:
+ - name: baz1.o
+ content: !native
+ defined-atoms:
+ - name: baz1
+ scope: global
+ type: code
+
+ - name: baz1b
+ type: code
+
+ - name: baz2.o
+ content: !native
+ defined-atoms:
+ - name: baz2
+ scope: global
+ type: code
+
+ - name: baz2b
+ type: code
+...
+
+# CHECK: name: foo
+# CHECK: name: bar1
+# CHECK: name: bar1b
+# CHECK-NOT: name: bar2
+# CHECK: name: baz1
+# CHECK: name: baz1b
+# CHECK-NOT: name: baz2
+# CHECK: ...
diff --git a/test/core/archive-tentdef-search.objtxt b/test/core/archive-tentdef-search.objtxt
new file mode 100644
index 000000000000..3d26778e4986
--- /dev/null
+++ b/test/core/archive-tentdef-search.objtxt
@@ -0,0 +1,42 @@
+# RUN: lld -core %s | FileCheck -check-prefix=CHK1 %s
+# RUN: lld -core --commons-search-archives %s | FileCheck -check-prefix=CHK2 %s
+
+#
+# Tests that -commons-search-archives cause core linker to look for overrides
+# of tentative definition in archives, and that not using that option
+# does not search.
+#
+
+--- !native
+defined-atoms:
+ - name: foo
+ type: code
+
+ - name: bar
+ scope: global
+ type: zero-fill
+ merge: as-tentative
+
+--- !archive
+members:
+ - name: bar.o
+ content: !native
+ defined-atoms:
+ - name: bar
+ scope: global
+ type: data
+
+ - name: bar2
+ type: data
+...
+
+# CHK1: name: foo
+# CHK1: name: bar
+# CHK1: merge: as-tentative
+# CHK1: ...
+
+# CHK2: name: foo
+# CHK2: name: bar
+# CHK2-NOT: merge: as-tentative
+# CHK2: name: bar2
+# CHK2: ...
diff --git a/test/core/associates.objtxt b/test/core/associates.objtxt
new file mode 100644
index 000000000000..bf780693ab70
--- /dev/null
+++ b/test/core/associates.objtxt
@@ -0,0 +1,30 @@
+# RUN: lld -core %s | FileCheck %s
+
+---
+defined-atoms:
+ - name: f1
+ merge: as-weak
+ scope: global
+ references:
+ - kind: associate
+ target: f2
+ - name: f2
+---
+defined-atoms:
+ - name: f1
+ merge: as-weak
+ scope: global
+ references:
+ - kind: associate
+ target: f2
+ - name: f2
+...
+
+# CHECK: defined-atoms:
+# CHECK: - name: f1
+# CHECK: scope: global
+# CHECK: references:
+# CHECK: - kind: associate
+# CHECK: target: f2
+# CHECK: - name: f2
+# CHECK-NOT: - name: f2
diff --git a/test/core/auto-hide-coalesce.objtxt b/test/core/auto-hide-coalesce.objtxt
new file mode 100644
index 000000000000..ad82d5afc573
--- /dev/null
+++ b/test/core/auto-hide-coalesce.objtxt
@@ -0,0 +1,60 @@
+# RUN: lld -core %s | FileCheck %s
+
+#
+# Tests auto-hide bit during coalescing
+#
+
+---
+defined-atoms:
+ - name: _inlineFunc1
+ scope: global
+ type: code
+ merge: as-weak
+
+ - name: _inlineFunc2
+ scope: global
+ type: code
+ merge: as-weak
+
+ - name: _inlineFunc3
+ scope: global
+ type: code
+ merge: as-addressed-weak
+
+ - name: _inlineFunc4
+ scope: global
+ type: code
+ merge: as-addressed-weak
+---
+defined-atoms:
+ - name: _inlineFunc1
+ scope: global
+ type: code
+ merge: as-weak
+
+ - name: _inlineFunc2
+ scope: global
+ type: code
+ merge: as-addressed-weak
+
+ - name: _inlineFunc3
+ scope: global
+ type: code
+ merge: as-weak
+
+ - name: _inlineFunc4
+ scope: global
+ type: code
+ merge: as-addressed-weak
+...
+
+
+# CHECK: name: _inlineFunc1
+# CHECK: merge: as-weak
+# CHECK: name: _inlineFunc3
+# CHECK: merge: as-addressed-weak
+# CHECK: name: _inlineFunc4
+# CHECK: merge: as-addressed-weak
+# CHECK: name: _inlineFunc2
+# CHECK: merge: as-addressed-weak
+# CHECK: ...
diff --git a/test/core/code-model-attributes.objtxt b/test/core/code-model-attributes.objtxt
new file mode 100644
index 000000000000..8c30e868567d
--- /dev/null
+++ b/test/core/code-model-attributes.objtxt
@@ -0,0 +1,50 @@
+# RUN: lld -core %s | FileCheck %s
+
+#
+# Test that code model attributes are preserved
+#
+
+---
+defined-atoms:
+ - name: _def
+---
+defined-atoms:
+ - name: _none
+ code-model: none
+---
+defined-atoms:
+ - name: _mips_pic
+ code-model: mips-pic
+---
+defined-atoms:
+ - name: _mips_micro
+ code-model: mips-micro
+---
+defined-atoms:
+ - name: _mips_micro_pic
+ code-model: mips-micro-pic
+---
+defined-atoms:
+ - name: _mips_16
+ code-model: mips-16
+...
+
+# CHECK: name: _def
+# CHECK-NOT: code-model: mips-pic
+# CHECK-NOT: code-model: mips-micro
+# CHECK-NOT: code-model: mips-micro-pic
+# CHECK-NOT: code-model: mips-16
+# CHECK: name: _none
+# CHECK-NOT: code-model: mips-pic
+# CHECK-NOT: code-model: mips-micro
+# CHECK-NOT: code-model: mips-micro-pic
+# CHECK-NOT: code-model: mips-16
+# CHECK: name: _mips_pic
+# CHECK: code-model: mips-pic
+# CHECK: name: _mips_micro
+# CHECK: code-model: mips-micro
+# CHECK: name: _mips_micro_pic
+# CHECK: code-model: mips-micro-pic
+# CHECK: name: _mips_16
+# CHECK: code-model: mips-16
+# CHECK: ...
diff --git a/test/core/constants-coalesce.objtxt b/test/core/constants-coalesce.objtxt
new file mode 100644
index 000000000000..a82f68009087
--- /dev/null
+++ b/test/core/constants-coalesce.objtxt
@@ -0,0 +1,60 @@
+# RUN: lld -core %s | FileCheck %s
+
+#
+# Test that duplicate merge-by-content anonymous constants are coalesced
+# and non-mergable duplicate constants are not coalesced.
+#
+
+---
+defined-atoms:
+ - ref-name: L4-byte
+ type: constant
+ merge: by-content
+ content: [ 01, 02, 03, 04 ]
+
+ - ref-name: L8-byte
+ type: constant
+ merge: by-content
+ content: [ 01, 23, 45, 67, 89, AB, CD, EF ]
+
+ - ref-name: L1
+ type: constant
+ content: [ 01, 02 ]
+---
+defined-atoms:
+ - ref-name: L1
+ type: constant
+ content: [ 01, 02 ]
+ - ref-name: L2
+ type: constant
+ merge: by-content
+ content: [ 01, 02, 03, 04 ]
+---
+defined-atoms:
+ - ref-name: L2
+ type: constant
+ merge: by-content
+ content: [ 01, 23, 45, 67, 89, AB, CD, EF ]
+ - ref-name: L3
+ type: constant
+ merge: by-content
+ content: [ 01, 02, 03 ]
+...
+
+# CHECK-NOT: name:
+# CHECK: type: constant
+# CHECK: content: [ 01, 02, 03, 04 ]
+# CHECK: merge: by-content
+# CHECK: type: constant
+# CHECK: content: [ 01, 23, 45, 67, 89, AB, CD, EF ]
+# CHECK: merge: by-content
+# CHECK: type: constant
+# CHECK: content: [ 01, 02 ]
+# CHECK: type: constant
+# CHECK: content: [ 01, 02 ]
+# CHECK: type: constant
+# CHECK: content: [ 01, 02, 03 ]
+# CHECK: merge: by-content
+# CHECK: ...
+
+
diff --git a/test/core/cstring-coalesce.objtxt b/test/core/cstring-coalesce.objtxt
new file mode 100644
index 000000000000..78986a08c640
--- /dev/null
+++ b/test/core/cstring-coalesce.objtxt
@@ -0,0 +1,41 @@
+# RUN: lld -core %s | FileCheck %s
+
+#
+# Test that duplicate c-strings are coalesced
+#
+
+---
+defined-atoms:
+ - ref-name: L0
+ type: c-string
+ merge: by-content
+ content: [ 68, 65, 6c, 6c, 6f, 00 ]
+
+ - ref-name: L1
+ type: c-string
+ merge: by-content
+ content: [ 74, 68, 65, 72, 65, 00 ]
+---
+defined-atoms:
+ - ref-name: L2
+ type: c-string
+ merge: by-content
+ content: [ 68, 65, 6c, 6c, 6f, 00 ]
+---
+defined-atoms:
+ - ref-name: L2
+ type: c-string
+ merge: by-content
+ content: [ 74, 68, 65, 72, 65, 00 ]
+...
+
+# CHECK-NOT: name:
+# CHECK: type: c-string
+# CHECK: content: [ 68, 65, 6C, 6C, 6F, 00 ]
+# CHECK: merge: by-content
+# CHECK: type: c-string
+# CHECK: content: [ 74, 68, 65, 72, 65, 00 ]
+# CHECK: merge: by-content
+# CHECK: ...
+
+
diff --git a/test/core/custom-section-coalesce.objtxt b/test/core/custom-section-coalesce.objtxt
new file mode 100644
index 000000000000..e9bada56938d
--- /dev/null
+++ b/test/core/custom-section-coalesce.objtxt
@@ -0,0 +1,78 @@
+# RUN: lld -core %s | FileCheck %s
+
+#
+# Test that custom sections are preserved when duplicate merge-by-content
+# constants are coalesced.
+#
+
+---
+defined-atoms:
+ - ref-name: L1
+ type: constant
+ merge: by-content
+ content: [ 01, 02, 03, 04 ]
+ section-choice: custom-required
+ section-name: .mysection
+
+ - ref-name: L2
+ type: constant
+ merge: by-content
+ content: [ 05, 06, 07, 08 ]
+ section-choice: custom-required
+ section-name: .mysection
+
+ - ref-name: L3
+ type: constant
+ merge: by-content
+ content: [ 01, 02, 03, 04 ]
+
+---
+defined-atoms:
+ - ref-name: L1
+ type: constant
+ merge: by-content
+ content: [ 01, 02, 03, 04 ]
+ section-choice: custom-required
+ section-name: .mysection
+
+ - ref-name: L2
+ type: constant
+ merge: by-content
+ content: [ 01, 02, 03, 04 ]
+ section-choice: custom-required
+ section-name: .mysection2
+---
+defined-atoms:
+ - ref-name: L1
+ type: constant
+ merge: by-content
+ content: [ 05, 06, 07, 08 ]
+ section-choice: custom-required
+ section-name: .mysection
+
+ - ref-name: L2
+ type: constant
+ merge: by-content
+ content: [ 01, 02, 03, 04 ]
+...
+
+
+# CHECK:defined-atoms:
+# CHECK: - type: constant
+# CHECK: content: [ 01, 02, 03, 04 ]
+# CHECK: merge: by-content
+# CHECK: section-choice: custom-required
+# CHECK: section-name: .mysection
+# CHECK: - type: constant
+# CHECK: content: [ 05, 06, 07, 08 ]
+# CHECK: merge: by-content
+# CHECK: section-choice: custom-required
+# CHECK: section-name: .mysection
+# CHECK: - type: constant
+# CHECK: content: [ 01, 02, 03, 04 ]
+# CHECK: merge: by-content
+# CHECK: - type: constant
+# CHECK: content: [ 01, 02, 03, 04 ]
+# CHECK: merge: by-content
+# CHECK: section-choice: custom-required
+# CHECK: section-name: .mysection2
diff --git a/test/core/custom-section.objtxt b/test/core/custom-section.objtxt
new file mode 100644
index 000000000000..ce305e9af38e
--- /dev/null
+++ b/test/core/custom-section.objtxt
@@ -0,0 +1,34 @@
+# RUN: lld -core %s | FileCheck %s
+
+#
+# Test that custom sections are preserved
+#
+
+---
+defined-atoms:
+ - name: _foo1
+ scope: global
+ section-choice: content
+
+ - name: _foo2
+ scope: global
+ section-choice: custom
+ section-name: __foozle
+
+ - name: _foo3
+ scope: global
+ section-choice: custom-required
+ section-name: __boozle
+
+...
+
+
+# CHECK: name: _foo1
+# CHECK-NOT: section-name:
+# CHECK: name: _foo2
+# CHECK: section-choice: custom
+# CHECK: section-name: __foozle
+# CHECK: name: _foo3
+# CHECK: section-choice: custom-required
+# CHECK: section-name: __boozle
+# CHECK: ...
diff --git a/test/core/dead-strip-attributes.objtxt b/test/core/dead-strip-attributes.objtxt
new file mode 100644
index 000000000000..dcb35a21e261
--- /dev/null
+++ b/test/core/dead-strip-attributes.objtxt
@@ -0,0 +1,29 @@
+# RUN: lld -core %s | FileCheck %s
+
+#
+# Test that dead strip attributes are preserved
+#
+
+---
+defined-atoms:
+ - name: _foo1
+ dead-strip: normal
+---
+defined-atoms:
+ - name: _foo2
+ dead-strip: never
+---
+defined-atoms:
+ - name: _foo3
+ dead-strip: always
+...
+
+
+# CHECK: name: _foo1
+# CHECK-NOT: dead-strip: never
+# CHECK-NOT: dead-strip: always
+# CHECK: name: _foo2
+# CHECK: dead-strip: never
+# CHECK: name: _foo3
+# CHECK: dead-strip: always
+# CHECK: ...
diff --git a/test/core/dead-strip-basic.objtxt b/test/core/dead-strip-basic.objtxt
new file mode 100644
index 000000000000..64cd2291c76b
--- /dev/null
+++ b/test/core/dead-strip-basic.objtxt
@@ -0,0 +1,62 @@
+# RUN: lld -core --dead-strip %s | FileCheck -check-prefix=CHK1 %s
+# RUN: lld -core %s | FileCheck -check-prefix=CHK2 %s
+
+#
+# Test that -dead-strip removes unreachable code and data
+# and that not using that option leaves them.
+#
+
+---
+defined-atoms:
+ - name: entry
+ dead-strip: never
+ references:
+ - offset: 1
+ kind: pcrel32
+ target: bar
+ - offset: 6
+ kind: pcrel32
+ target: baz
+
+ - name: mydead1
+ scope: global
+
+undefined-atoms:
+ - name: bar
+
+ - name: baz
+---
+defined-atoms:
+ - name: mydead2
+ scope: global
+ type: data
+
+ - name: bar
+ scope: global
+ type: data
+---
+defined-atoms:
+ - name: baz
+ scope: global
+ type: code
+
+ - name: mydead3
+ type: code
+...
+
+
+# CHK1: name: entry
+# CHK1-NOT: name: mydead1
+# CHK1: name: bar
+# CHK1-NOT: name: mydead2
+# CHK1: name: baz
+# CHK1-NOT: name: mydead3
+# CHK1: ...
+
+# CHK2: name: entry
+# CHK2: name: mydead1
+# CHK2: name: mydead2
+# CHK2: name: bar
+# CHK2: name: baz
+# CHK2: name: mydead3
+# CHK2: ...
diff --git a/test/core/dead-strip-globals.objtxt b/test/core/dead-strip-globals.objtxt
new file mode 100644
index 000000000000..8feb235d07c3
--- /dev/null
+++ b/test/core/dead-strip-globals.objtxt
@@ -0,0 +1,60 @@
+# RUN: lld -core --dead-strip --keep-globals %s | FileCheck -check-prefix=CHK1 %s
+# RUN: lld -core --dead-strip %s | FileCheck -check-prefix=CHK2 %s
+
+#
+# Test that -keep-globals prevents -dead-strip from removing globals.
+#
+
+---
+defined-atoms:
+ - name: entry
+ dead-strip: never
+ references:
+ - offset: 1
+ kind: pcrel32
+ target: bar
+ - offset: 6
+ kind: pcrel32
+ target: baz
+
+ - name: myglobal1
+ scope: global
+
+undefined-atoms:
+ - name: bar
+ - name: baz
+---
+defined-atoms:
+ - name: myglobal2
+ scope: global
+ type: data
+
+ - name: bar
+ scope: hidden
+ type: data
+---
+defined-atoms:
+ - name: baz
+ scope: hidden
+ type: code
+
+ - name: mydead
+ type: code
+...
+
+
+# CHK1: name: entry
+# CHK1: name: myglobal1
+# CHK1: name: myglobal2
+# CHK1: name: bar
+# CHK1: name: baz
+# CHK1-NOT: name: mydead
+# CHK1: ...
+
+# CHK2: name: entry
+# CHK2-NOT: name: myglobal1
+# CHK2-NOT: name: myglobal2
+# CHK2: name: bar
+# CHK2: name: baz
+# CHK2-NOT: name: mydead
+# CHK2: ...
diff --git a/test/core/dead-strip-reverse.objtxt b/test/core/dead-strip-reverse.objtxt
new file mode 100644
index 000000000000..f471bebcdf4e
--- /dev/null
+++ b/test/core/dead-strip-reverse.objtxt
@@ -0,0 +1,25 @@
+# RUN: lld -core --dead-strip %s | FileCheck -check-prefix=CHECK1 %s
+# RUN: lld -core %s | FileCheck -check-prefix=CHECK2 %s
+
+---
+defined-atoms:
+ - name: entry
+ dead-strip: never
+ scope: global
+ references:
+ - kind: layout-after
+ offset: 0
+ target: def
+ - name: def
+ scope: global
+ - name: dead
+ scope: global
+...
+
+# CHECK1: name: entry
+# CHECK1: name: def
+# CHECK1-NOT: name: dead
+
+# CHECK2: name: entry
+# CHECK2: name: def
+# CHECK2: name: dead
diff --git a/test/core/error-atom-attribute.objtxt b/test/core/error-atom-attribute.objtxt
new file mode 100644
index 000000000000..6643aba29eea
--- /dev/null
+++ b/test/core/error-atom-attribute.objtxt
@@ -0,0 +1,19 @@
+# RUN: not lld -core %s 2> %t.err
+# RUN: FileCheck %s < %t.err
+
+#
+# Test that unknown atom attribute produces a readable error.
+#
+
+---
+defined-atoms:
+ - name: entry
+ scope: hidden
+ foobar: true
+ dead-strip: never
+
+...
+
+
+# CHECK: error: unknown key 'foobar'
+# CHECK: foobar
diff --git a/test/core/error-atom-content-byte-value.objtxt b/test/core/error-atom-content-byte-value.objtxt
new file mode 100644
index 000000000000..6e675576461a
--- /dev/null
+++ b/test/core/error-atom-content-byte-value.objtxt
@@ -0,0 +1,18 @@
+# RUN: not lld -core %s 2> %t.err
+# RUN: FileCheck %s < %t.err
+
+#
+# Test that an invalid hex byte produces a readable error.
+#
+
+---
+defined-atoms:
+ - name: entry
+ scope: hidden
+ content: [ A5, 00, 4G, 1F ]
+
+...
+
+
+# CHECK: error: invalid two-digit-hex number
+# CHECK: 4G
diff --git a/test/core/error-atom-content-bytes.objtxt b/test/core/error-atom-content-bytes.objtxt
new file mode 100644
index 000000000000..a8a82b2b45e1
--- /dev/null
+++ b/test/core/error-atom-content-bytes.objtxt
@@ -0,0 +1,19 @@
+# RUN: not lld -core %s 2> %t.err
+# RUN: FileCheck %s < %t.err
+
+#
+# Test that an out of range byte value produces a readable error.
+#
+
+---
+defined-atoms:
+ - name: entry
+ scope: hidden
+ content: [ A5, 1234, 00, 4F ]
+
+...
+
+
+# CHECK: error: out of range two-digit-hex number
+# CHECK: 1234
+
diff --git a/test/core/error-atom-type.objtxt b/test/core/error-atom-type.objtxt
new file mode 100644
index 000000000000..b0943f8e2749
--- /dev/null
+++ b/test/core/error-atom-type.objtxt
@@ -0,0 +1,19 @@
+# RUN: not lld -core %s 2> %t.err
+# RUN: FileCheck %s < %t.err
+
+#
+# Test that an unknown content type produces a readable error.
+#
+
+---
+defined-atoms:
+ - name: entry
+ scope: hidden
+ type: superluminal
+ dead-strip: never
+
+...
+
+
+# CHECK: error: unknown enumerated scalar
+# CHECK: superluminal
diff --git a/test/core/error-atom-undefined-wrong-attribue.objtxt b/test/core/error-atom-undefined-wrong-attribue.objtxt
new file mode 100644
index 000000000000..5cdd8519c804
--- /dev/null
+++ b/test/core/error-atom-undefined-wrong-attribue.objtxt
@@ -0,0 +1,17 @@
+# RUN: not lld -core %s 2> %t.err
+# RUN: FileCheck %s < %t.err
+
+#
+# Test that a defined attribute on an undefined atom produces a readable error.
+#
+
+---
+undefined-atoms:
+ - name: foo
+ type: code
+
+...
+
+
+# CHECK: error: unknown key 'type'
+
diff --git a/test/core/error-duplicate-absolutes.objtxt b/test/core/error-duplicate-absolutes.objtxt
new file mode 100644
index 000000000000..533297e59dcd
--- /dev/null
+++ b/test/core/error-duplicate-absolutes.objtxt
@@ -0,0 +1,24 @@
+# RUN: not lld -core %s 2> %t.err
+# RUN: FileCheck %s < %t.err
+
+#
+# Test that duplicate absolute atoms produces a readable error.
+#
+
+---
+absolute-atoms:
+ - name: absatom
+ value: 0
+ scope: global
+undefined-atoms:
+ - name: undefatom
+---
+absolute-atoms:
+ - name: absatom
+ value: 0
+ scope: global
+...
+
+
+# CHECK: SymbolTable: error while merging absatom
+# CHECK: LLVM ERROR: duplicate symbol error
diff --git a/test/core/error-file-attribute.objtxt b/test/core/error-file-attribute.objtxt
new file mode 100644
index 000000000000..d8393dc5e400
--- /dev/null
+++ b/test/core/error-file-attribute.objtxt
@@ -0,0 +1,17 @@
+# RUN: not lld -core %s 2> %t.err
+# RUN: FileCheck %s < %t.err
+
+#
+# Test that unknown file attribute produces a readable error.
+#
+
+---
+aardvark: true
+defined-atoms:
+ - name: entry
+ scope: hidden
+
+...
+
+
+# CHECK: error: unknown key 'aardvark'
diff --git a/test/core/error-fixup-attribute.objtxt b/test/core/error-fixup-attribute.objtxt
new file mode 100644
index 000000000000..025783a04427
--- /dev/null
+++ b/test/core/error-fixup-attribute.objtxt
@@ -0,0 +1,21 @@
+# RUN: not lld -core %s 2> %t.err
+# RUN: FileCheck %s < %t.err
+
+#
+# Test that unknown fixup attribute produces a readable error.
+#
+
+---
+defined-atoms:
+ - name: entry
+ scope: hidden
+ references:
+ - offset: 3
+ kind: pcrel32
+ weasel: bar
+ addend: 100
+
+...
+
+
+# CHECK: error: unknown key 'weasel'
diff --git a/test/core/error-fixup-target.objtxt b/test/core/error-fixup-target.objtxt
new file mode 100644
index 000000000000..0e20d1636f50
--- /dev/null
+++ b/test/core/error-fixup-target.objtxt
@@ -0,0 +1,26 @@
+# RUN: not lld -core %s 2> %t.err
+# RUN: FileCheck %s < %t.err
+
+#
+# Test that unbindable target name produces a readable error.
+#
+
+---
+defined-atoms:
+ - name: entry
+ scope: hidden
+ references:
+ - offset: 3
+ kind: pcrel32
+ target: bar
+ - offset: 5
+ kind: pcrel32
+ target: baz
+
+undefined-atoms:
+ - name: bar
+
+...
+
+
+# CHECK: error: no such atom name: baz
diff --git a/test/core/fixups-addend.objtxt b/test/core/fixups-addend.objtxt
new file mode 100644
index 000000000000..d976150459c9
--- /dev/null
+++ b/test/core/fixups-addend.objtxt
@@ -0,0 +1,50 @@
+# RUN: lld -core %s | FileCheck %s
+
+#
+# Test addends in references
+#
+
+---
+defined-atoms:
+ - name: foo
+ type: code
+ content: [ 48, 8D, 3D, 00, 00, 00, 00,
+ 48, 8D, 3D, 00, 00, 00, 00 ]
+ references:
+ - offset: 3
+ kind: pcrel32
+ target: bar
+ addend: 100
+ - offset: 10
+ kind: pcrel32
+ target: bar
+ addend: -50
+
+ - name: func
+ type: code
+ content: [ 48, 8D, 3D, 00, 00, 00, 00,
+ 48, 8D, 3D, 00, 00, 00, 00 ]
+ references:
+ - offset: 3
+ kind: pcrel32
+ target: bar
+ addend: 8000000000
+ - offset: 10
+ kind: pcrel32
+ target: bar
+ addend: -50
+
+undefined-atoms:
+ - name: bar
+
+
+...
+
+# CHECK: name: foo
+# CHECK: references:
+# CHECK: addend: 100
+# CHECK: addend: -50
+# CHECK: name: func
+# CHECK: references:
+# CHECK: addend: 8000000000
+# CHECK: addend: -50
diff --git a/test/core/fixups-dup-named.objtxt b/test/core/fixups-dup-named.objtxt
new file mode 100644
index 000000000000..1c57cd73bf09
--- /dev/null
+++ b/test/core/fixups-dup-named.objtxt
@@ -0,0 +1,31 @@
+# RUN: lld -core %s | FileCheck %s
+
+#
+# Test references referencing multiple atoms that have the same name
+#
+
+---
+defined-atoms:
+ - name: foo
+ type: code
+ content: [ E8, 00, 00, 00, 00, E8, 00, 00, 00, 00 ]
+ references:
+ - offset: 1
+ kind: pcrel32
+ target: bar_1
+ - offset: 6
+ kind: pcrel32
+ target: bar_2
+
+ - name: bar
+ ref-name: bar_1
+ scope: static
+
+ - name: bar
+ ref-name: bar_2
+ scope: static
+
+
+...
+
+# CHECK: ...
diff --git a/test/core/fixups-named.objtxt b/test/core/fixups-named.objtxt
new file mode 100644
index 000000000000..1427a9b705d1
--- /dev/null
+++ b/test/core/fixups-named.objtxt
@@ -0,0 +1,36 @@
+# RUN: lld -core %s | FileCheck %s
+
+#
+# Test references to simple named atoms
+#
+
+---
+defined-atoms:
+ - name: foo
+ type: code
+ content: [ E8, 00, 00, 00, 00,
+ E8, 00, 00, 00, 00 ]
+ references:
+ - offset: 1
+ kind: pcrel32
+ target: bar
+ - offset: 6
+ kind: pcrel32
+ target: baz
+
+ - name: baz
+ scope: static
+ type: code
+
+undefined-atoms:
+ - name: bar
+
+
+...
+
+# CHECK: name: foo
+# CHECK: references:
+# CHECK: target: bar
+# CHECK: target: baz
+# CHECK: ...
+
diff --git a/test/core/fixups-unnamed.objtxt b/test/core/fixups-unnamed.objtxt
new file mode 100644
index 000000000000..88afb6a447a2
--- /dev/null
+++ b/test/core/fixups-unnamed.objtxt
@@ -0,0 +1,40 @@
+# RUN: lld -core %s | FileCheck %s
+
+#
+# Test references to unnamed atoms
+#
+
+---
+defined-atoms:
+ - name: foo
+ type: code
+ content: [ 48, 8D, 3D, 00, 00, 00, 00,
+ 48, 8D, 3D, 00, 00, 00, 00 ]
+ references:
+ - offset: 3
+ kind: pcrel32
+ target: LC1
+ - offset: 10
+ kind: pcrel32
+ target: LC2
+
+
+ - ref-name: LC1
+ type: c-string
+ merge: by-content
+ content: [ 68, 65, 6c, 6c, 6f, 00 ]
+
+ - ref-name: LC2
+ type: c-string
+ merge: by-content
+ content: [ 74, 68, 65, 72, 65, 00 ]
+
+
+...
+
+# CHECK: name: foo
+# CHECK: references:
+# CHECK: offset: 3
+# CHECK: offset: 10
+# CHECK: ref-name:
+# CHECK: ref-name:
diff --git a/test/core/gnulinkonce-rearrange-resolve.objtxt b/test/core/gnulinkonce-rearrange-resolve.objtxt
new file mode 100644
index 000000000000..2a6386a6935d
--- /dev/null
+++ b/test/core/gnulinkonce-rearrange-resolve.objtxt
@@ -0,0 +1,79 @@
+# RUN: lld -core %s | FileCheck %s
+
+#
+# Test that gnu linkonce sections are parsed and the first section selected for symbol
+# resolution
+#
+
+---
+defined-atoms:
+ - name: g1
+ scope: global
+ type: gnu-linkonce
+ references:
+ - kind: group-child
+ target: f1
+ - kind: group-child
+ target: f2
+ - kind: group-child
+ target: g1
+ - kind: group-child
+ target: d1
+ - name: f1
+ scope: global
+ type: code
+ - name: f2
+ scope: global
+ type: code
+ - name: g1
+ scope: global
+ type: code
+ - name: d1
+ scope: global
+ type: data
+---
+defined-atoms:
+ - name: g1
+ scope: global
+ type: gnu-linkonce
+ references:
+ - kind: group-child
+ target: f1
+ - kind: group-child
+ target: f2
+ - kind: group-child
+ target: g1
+ - kind: group-child
+ target: d1
+ - name: f1
+ scope: global
+ type: code
+ - name: f2
+ scope: global
+ type: code
+ - name: g1
+ scope: global
+ type: code
+ - name: d1
+ scope: global
+ type: data
+...
+
+# CHECK: defined-atoms:
+# CHECK: - name: g1
+# CHECK: ref-name: [[PARENT:[a-zA-Z\.0-9_]+]]
+# CHECK: type: gnu-linkonce
+# CHECK: references:
+# CHECK: - kind: group-child
+# CHECK: target: f1
+# CHECK: - kind: group-child
+# CHECK: target: f2
+# CHECK: - kind: group-child
+# CHECK: target: [[CHILD:[a-zA-Z\.0-9_]+]]
+# CHECK: - kind: group-child
+# CHECK: target: d1
+# CHECK: - name: f1
+# CHECK: - name: f2
+# CHECK: - name: g1
+# CHECK: ref-name: [[CHILD]]
+# CHECK: - name: d1
diff --git a/test/core/gnulinkonce-remaining-undef.objtxt b/test/core/gnulinkonce-remaining-undef.objtxt
new file mode 100644
index 000000000000..490608209ba9
--- /dev/null
+++ b/test/core/gnulinkonce-remaining-undef.objtxt
@@ -0,0 +1,80 @@
+# RUN: lld -core %s | FileCheck %s
+
+#
+# Test that gnu linkonce sections are parsed and the first section selected for
+# symbol resolution. The second file which has the same gnu linkonce section has
+# a unresolved undefined symbol. lets make sure that the symbol is kept around
+# in the final link and remains undefined.
+#
+
+---
+defined-atoms:
+ - name: f1
+ scope: global
+ type: code
+ - name: f2
+ scope: global
+ type: code
+ - name: g1
+ scope: global
+ type: code
+ - name: d1
+ scope: global
+ type: data
+ - name: g1
+ scope: global
+ type: gnu-linkonce
+ references:
+ - kind: group-child
+ target: f1
+ - kind: group-child
+ target: f2
+ - kind: group-child
+ target: g1
+ - kind: group-child
+ target: d1
+---
+defined-atoms:
+ - name: anotherfunction
+ scope: global
+ type: data
+ - name: f1
+ scope: global
+ type: code
+ - name: f2
+ scope: global
+ type: code
+ - name: f3
+ scope: global
+ type: code
+ - name: g1
+ scope: global
+ type: code
+ - name: d1
+ scope: global
+ type: data
+ - name: g1
+ scope: global
+ type: gnu-linkonce
+ references:
+ - kind: group-child
+ target: f1
+ - kind: group-child
+ target: f2
+ - kind: group-child
+ target: f3
+ - kind: group-child
+ target: g1
+ - kind: group-child
+ target: d1
+---
+undefined-atoms:
+ - name: f3
+ can-be-null: never
+...
+
+#CHECK: - name: anotherfunction
+#CHECK: scope: global
+#CHECK: type: data
+#CHECK: undefined-atoms:
+#CHECK: - name: f3
diff --git a/test/core/gnulinkonce-resolve.objtxt b/test/core/gnulinkonce-resolve.objtxt
new file mode 100644
index 000000000000..817e9cfdd4e0
--- /dev/null
+++ b/test/core/gnulinkonce-resolve.objtxt
@@ -0,0 +1,89 @@
+# RUN: lld -core %s | FileCheck %s
+
+#
+# Test that gnu linkonce sections are parsed and the first section selected for symbol
+# resolution
+#
+
+---
+defined-atoms:
+ - name: f1
+ scope: global
+ type: code
+ - name: f2
+ scope: global
+ type: code
+ - name: g1
+ scope: global
+ type: code
+ - name: d1
+ scope: global
+ type: data
+ - name: g1
+ scope: global
+ type: gnu-linkonce
+ references:
+ - kind: group-child
+ target: f1
+ - kind: group-child
+ target: f2
+ - kind: group-child
+ target: g1
+ - kind: group-child
+ target: d1
+---
+defined-atoms:
+ - name: f1
+ scope: global
+ type: code
+ - name: f2
+ scope: global
+ type: code
+ - name: g1
+ scope: global
+ type: code
+ - name: d1
+ scope: global
+ type: data
+ - name: g1
+ scope: global
+ type: gnu-linkonce
+ references:
+ - kind: group-child
+ target: f1
+ - kind: group-child
+ target: f2
+ - kind: group-child
+ target: g1
+ - kind: group-child
+ target: d1
+...
+
+#CHECK: defined-atoms:
+#CHECK: - name: g1
+#CHECK: ref-name: [[PARENT:[a-zA-Z\.0-9_]+]]
+#CHECK: scope: global
+#CHECK: type: gnu-linkonce
+#CHECK: references:
+#CHECK: - kind: group-child
+#CHECK: offset: 0
+#CHECK: target: f1
+#CHECK: - kind: group-child
+#CHECK: offset: 0
+#CHECK: target: f2
+#CHECK: - kind: group-child
+#CHECK: offset: 0
+#CHECK: target: [[GCHILD:[a-zA-Z\.0-9_]+]]
+#CHECK: - kind: group-child
+#CHECK: offset: 0
+#CHECK: target: d1
+#CHECK: - name: f1
+#CHECK: scope: global
+#CHECK: - name: f2
+#CHECK: scope: global
+#CHECK: - name: g1
+#CHECK: ref-name: [[GCHILD]]
+#CHECK: scope: global
+#CHECK: - name: d1
+#CHECK: scope: global
+#CHECK: type: data
diff --git a/test/core/gnulinkonce-simple.objtxt b/test/core/gnulinkonce-simple.objtxt
new file mode 100644
index 000000000000..da325d48c366
--- /dev/null
+++ b/test/core/gnulinkonce-simple.objtxt
@@ -0,0 +1,80 @@
+# RUN: lld -core %s | FileCheck %s
+
+#
+# Test that gnu linkonce sections are parsed properly when there is a reference to a
+# atom from outside the gnu linkonce section.
+#
+
+---
+defined-atoms:
+ - name: f1
+ scope: global
+ type: code
+ references:
+ - kind: layout-after
+ target: anotherfunction
+ - name: f2
+ scope: global
+ type: code
+ - name: g1
+ scope: global
+ type: code
+ - name: d1
+ scope: global
+ type: data
+ - name: g1
+ scope: global
+ type: gnu-linkonce
+ references:
+ - kind: group-child
+ target: f1
+ - kind: group-child
+ target: f2
+ - kind: group-child
+ target: d1
+ - kind: group-child
+ target: g1
+ - name: anotherfunction
+ scope: global
+ type: data
+---
+undefined-atoms:
+ - name: f1
+ can-be-null: never
+...
+
+#CHECK: defined-atoms:
+#CHECK: - name: g1
+#CHECK: ref-name: [[PARENT:[a-zA-Z\.0-9_]+]]
+#CHECK: scope: global
+#CHECK: type: gnu-linkonce
+#CHECK: references:
+#CHECK: - kind: group-child
+#CHECK: offset: 0
+#CHECK: target: f1
+#CHECK: - kind: group-child
+#CHECK: offset: 0
+#CHECK: target: f2
+#CHECK: - kind: group-child
+#CHECK: offset: 0
+#CHECK: target: d1
+#CHECK: - kind: group-child
+#CHECK: offset: 0
+#CHECK: target: [[GCHILD:[a-zA-Z\.0-9_]+]]
+#CHECK: - name: f1
+#CHECK: scope: global
+#CHECK: references:
+#CHECK: - kind: layout-after
+#CHECK: offset: 0
+#CHECK: target: anotherfunction
+#CHECK: - name: f2
+#CHECK: scope: global
+#CHECK: - name: d1
+#CHECK: scope: global
+#CHECK: type: data
+#CHECK: - name: g1
+#CHECK: ref-name: [[GCHILD]]
+#CHECK: scope: global
+#CHECK: - name: anotherfunction
+#CHECK: scope: global
+#CHECK: type: data
diff --git a/test/core/inline-coalesce.objtxt b/test/core/inline-coalesce.objtxt
new file mode 100644
index 000000000000..6df9d0e7a49a
--- /dev/null
+++ b/test/core/inline-coalesce.objtxt
@@ -0,0 +1,31 @@
+# RUN: lld -core %s | FileCheck %s
+
+#
+# Test that non-inlined inlined functions are silently coalesced
+#
+
+---
+defined-atoms:
+ - name: _inlineFunc
+ scope: global
+ type: code
+ merge: as-weak
+---
+defined-atoms:
+ - name: _inlineFunc
+ scope: global
+ type: code
+ merge: as-weak
+---
+defined-atoms:
+ - name: _inlineFunc
+ scope: global
+ type: code
+ merge: as-weak
+...
+
+
+# CHECK: name: _inlineFunc
+# CHECK: merge: as-weak
+# CHECK-NOT: name: _inlineFunc
+# CHECK: ...
diff --git a/test/core/multiple-def-error.objtxt b/test/core/multiple-def-error.objtxt
new file mode 100644
index 000000000000..7c7732c15fd9
--- /dev/null
+++ b/test/core/multiple-def-error.objtxt
@@ -0,0 +1,19 @@
+# RUN: not lld -core %s 2>&1 | FileCheck %s
+
+#
+# Test that multiple definitions cause an error
+#
+
+# CHECK: duplicate symbol
+
+---
+defined-atoms:
+ - name: _foo
+ scope: global
+ type: data
+---
+defined-atoms:
+ - name: _foo
+ scope: global
+ type: data
+...
diff --git a/test/core/permissions.objtxt b/test/core/permissions.objtxt
new file mode 100644
index 000000000000..af33ea65c455
--- /dev/null
+++ b/test/core/permissions.objtxt
@@ -0,0 +1,57 @@
+# RUN: lld -core %s | FileCheck %s
+
+#
+# Test permissions for known content types are implicit, but can be overridden.
+#
+---
+defined-atoms:
+ - name: one
+ type: code
+
+ - name: two
+ type: data
+ permissions: rw-
+
+ - name: three
+ type: const-data
+
+ - name: four
+ type: unknown
+
+ - name: oddCode
+ type: code
+ permissions: rwx
+
+ - name: oddData
+ type: data
+ permissions: rwx
+
+ - name: oddConstData
+ type: const-data
+ permissions: rw-
+
+ - name: oddUnknown
+ type: unknown
+ permissions: rw-
+
+...
+
+# CHECK: ---
+# CHECK: defined-atoms:
+# CHECK: - name: one
+# CHECK-NOT: permissions:
+# CHECK: - name: two
+# CHECK-NOT: permissions:
+# CHECK: - name: three
+# CHECK-NOT: permissions:
+# CHECK: - name: four
+# CHECK-NOT: permissions:
+# CHECK: - name: oddCode
+# CHECK: permissions: rwx
+# CHECK: - name: oddData
+# CHECK: permissions: rwx
+# CHECK: - name: oddConstData
+# CHECK: permissions: rw-
+# CHECK: - name: oddUnknown
+# CHECK: permissions: rw-
+# CHECK: ...
diff --git a/test/core/sectiongroup-deadstrip.objtxt b/test/core/sectiongroup-deadstrip.objtxt
new file mode 100644
index 000000000000..8606c52d62e1
--- /dev/null
+++ b/test/core/sectiongroup-deadstrip.objtxt
@@ -0,0 +1,88 @@
+# Test for section group members be preserved even if there is a
+# reference to only one functions in the group.
+# RUN: lld -core --dead-strip %s | FileCheck %s
+
+#
+# Test that section groups are parsed properly when there is a reference to a
+# group atom from outside a group.
+#
+
+---
+defined-atoms:
+ - name: entry
+ dead-strip: never
+ references:
+ - offset: 1
+ kind: pcrel32
+ target: d1
+ - name: f1
+ scope: global
+ type: code
+ references:
+ - kind: layout-after
+ target: anotherfunction
+ - name: f2
+ scope: global
+ type: code
+ - name: g1
+ scope: global
+ type: code
+ - name: d1
+ scope: global
+ type: data
+ - name: g1
+ scope: global
+ type: group-comdat
+ references:
+ - kind: group-child
+ target: f1
+ - kind: group-child
+ target: f2
+ - kind: group-child
+ target: d1
+ - kind: group-child
+ target: g1
+ - name: anotherfunction
+ scope: global
+ type: data
+---
+undefined-atoms:
+ - name: f1
+ can-be-null: never
+...
+
+#CHECK: defined-atoms:
+#CHECK: - name: g1
+#CHECK: ref-name: [[PARENT:[a-zA-Z\.0-9_]+]]
+#CHECK: scope: global
+#CHECK: type: group-comdat
+#CHECK: references:
+#CHECK: - kind: group-child
+#CHECK: offset: 0
+#CHECK: target: f1
+#CHECK: - kind: group-child
+#CHECK: offset: 0
+#CHECK: target: f2
+#CHECK: - kind: group-child
+#CHECK: offset: 0
+#CHECK: target: d1
+#CHECK: - kind: group-child
+#CHECK: offset: 0
+#CHECK: target: [[GCHILD:[a-zA-Z\.0-9_]+]]
+#CHECK: - name: f1
+#CHECK: scope: global
+#CHECK: references:
+#CHECK: - kind: layout-after
+#CHECK: offset: 0
+#CHECK: target: anotherfunction
+#CHECK: - name: f2
+#CHECK: scope: global
+#CHECK: - name: d1
+#CHECK: scope: global
+#CHECK: type: data
+#CHECK: - name: g1
+#CHECK: ref-name: [[GCHILD]]
+#CHECK: scope: global
+#CHECK: - name: anotherfunction
+#CHECK: scope: global
+#CHECK: type: data
diff --git a/test/core/sectiongroup-gnulinkonce-error.objtxt b/test/core/sectiongroup-gnulinkonce-error.objtxt
new file mode 100644
index 000000000000..47598957f8df
--- /dev/null
+++ b/test/core/sectiongroup-gnulinkonce-error.objtxt
@@ -0,0 +1,64 @@
+# RUN: not lld -core %s 2>&1 | FileCheck %s
+
+#
+# Test that section groups/gnu linkonce sections are parsed and a merge error
+# is displayed at the time of symbol resolution.
+#
+
+---
+defined-atoms:
+ - name: f1
+ scope: global
+ type: code
+ - name: f2
+ scope: global
+ type: code
+ - name: g1
+ scope: global
+ type: code
+ - name: d1
+ scope: global
+ type: data
+ - name: g1
+ scope: global
+ type: group-comdat
+ references:
+ - kind: group-child
+ target: f1
+ - kind: group-child
+ target: f2
+ - kind: group-child
+ target: g1
+ - kind: group-child
+ target: d1
+---
+defined-atoms:
+ - name: f1
+ scope: global
+ type: code
+ - name: f2
+ scope: global
+ type: code
+ - name: g1
+ scope: global
+ type: code
+ - name: d1
+ scope: global
+ type: data
+ - name: g1
+ scope: global
+ type: gnu-linkonce
+ references:
+ - kind: group-child
+ target: f1
+ - kind: group-child
+ target: f2
+ - kind: group-child
+ target: g1
+ - kind: group-child
+ target: d1
+...
+
+#CHECK: SymbolTable: error while merging g1
+#CHECK: LLVM ERROR: duplicate symbol error
+
diff --git a/test/core/sectiongroup-rearrange-resolve.objtxt b/test/core/sectiongroup-rearrange-resolve.objtxt
new file mode 100644
index 000000000000..7f5d2603775b
--- /dev/null
+++ b/test/core/sectiongroup-rearrange-resolve.objtxt
@@ -0,0 +1,79 @@
+# RUN: lld -core %s | FileCheck %s
+
+#
+# Test that section groups are parsed and the first group selected for symbol
+# resolution
+#
+
+---
+defined-atoms:
+ - name: g1
+ scope: global
+ type: group-comdat
+ references:
+ - kind: group-child
+ target: f1
+ - kind: group-child
+ target: f2
+ - kind: group-child
+ target: g1
+ - kind: group-child
+ target: d1
+ - name: f1
+ scope: global
+ type: code
+ - name: f2
+ scope: global
+ type: code
+ - name: g1
+ scope: global
+ type: code
+ - name: d1
+ scope: global
+ type: data
+---
+defined-atoms:
+ - name: g1
+ scope: global
+ type: group-comdat
+ references:
+ - kind: group-child
+ target: f1
+ - kind: group-child
+ target: f2
+ - kind: group-child
+ target: g1
+ - kind: group-child
+ target: d1
+ - name: f1
+ scope: global
+ type: code
+ - name: f2
+ scope: global
+ type: code
+ - name: g1
+ scope: global
+ type: code
+ - name: d1
+ scope: global
+ type: data
+...
+
+# CHECK: defined-atoms:
+# CHECK: - name: g1
+# CHECK: ref-name: [[PARENT:[a-zA-Z\.0-9_]+]]
+# CHECK: type: group-comdat
+# CHECK: references:
+# CHECK: - kind: group-child
+# CHECK: target: f1
+# CHECK: - kind: group-child
+# CHECK: target: f2
+# CHECK: - kind: group-child
+# CHECK: target: [[CHILD:[a-zA-Z\.0-9_]+]]
+# CHECK: - kind: group-child
+# CHECK: target: d1
+# CHECK: - name: f1
+# CHECK: - name: f2
+# CHECK: - name: g1
+# CHECK: ref-name: [[CHILD]]
+# CHECK: - name: d1
diff --git a/test/core/sectiongroup-remaining-undef.objtxt b/test/core/sectiongroup-remaining-undef.objtxt
new file mode 100644
index 000000000000..7d889b8a4931
--- /dev/null
+++ b/test/core/sectiongroup-remaining-undef.objtxt
@@ -0,0 +1,80 @@
+# RUN: lld -core %s | FileCheck %s
+
+#
+# Test that section groups are parsed and the first group selected for symbol
+# resolution. The second file which has the same group has a unresolved
+# undefined symbol. lets make sure that the symbol is kept around in the final
+# link and remains undefined.
+#
+
+---
+defined-atoms:
+ - name: f1
+ scope: global
+ type: code
+ - name: f2
+ scope: global
+ type: code
+ - name: g1
+ scope: global
+ type: code
+ - name: d1
+ scope: global
+ type: data
+ - name: g1
+ scope: global
+ type: group-comdat
+ references:
+ - kind: group-child
+ target: f1
+ - kind: group-child
+ target: f2
+ - kind: group-child
+ target: g1
+ - kind: group-child
+ target: d1
+---
+defined-atoms:
+ - name: anotherfunction
+ scope: global
+ type: data
+ - name: f1
+ scope: global
+ type: code
+ - name: f2
+ scope: global
+ type: code
+ - name: f3
+ scope: global
+ type: code
+ - name: g1
+ scope: global
+ type: code
+ - name: d1
+ scope: global
+ type: data
+ - name: g1
+ scope: global
+ type: group-comdat
+ references:
+ - kind: group-child
+ target: f1
+ - kind: group-child
+ target: f2
+ - kind: group-child
+ target: f3
+ - kind: group-child
+ target: g1
+ - kind: group-child
+ target: d1
+---
+undefined-atoms:
+ - name: f3
+ can-be-null: never
+...
+
+#CHECK: - name: anotherfunction
+#CHECK: scope: global
+#CHECK: type: data
+#CHECK: undefined-atoms:
+#CHECK: - name: f3
diff --git a/test/core/sectiongroup-resolve.objtxt b/test/core/sectiongroup-resolve.objtxt
new file mode 100644
index 000000000000..2d481b1818b2
--- /dev/null
+++ b/test/core/sectiongroup-resolve.objtxt
@@ -0,0 +1,90 @@
+# RUN: lld -core %s | FileCheck %s
+
+#
+# Test that section groups are parsed and the first group selected for symbol
+# resolution
+#
+
+---
+defined-atoms:
+ - name: f1
+ scope: global
+ type: code
+ - name: f2
+ scope: global
+ type: code
+ - name: g1
+ scope: global
+ type: code
+ - name: d1
+ scope: global
+ type: data
+ - name: g1
+ scope: global
+ type: group-comdat
+ references:
+ - kind: group-child
+ target: f1
+ - kind: group-child
+ target: f2
+ - kind: group-child
+ target: g1
+ - kind: group-child
+ target: d1
+---
+defined-atoms:
+ - name: f1
+ scope: global
+ type: code
+ - name: f2
+ scope: global
+ type: code
+ - name: g1
+ scope: global
+ type: code
+ - name: d1
+ scope: global
+ type: data
+ - name: g1
+ scope: global
+ type: group-comdat
+ references:
+ - kind: group-child
+ target: f1
+ - kind: group-child
+ target: f2
+ - kind: group-child
+ target: g1
+ - kind: group-child
+ target: d1
+...
+
+#CHECK: defined-atoms:
+#CHECK: - name: g1
+#CHECK: ref-name: [[PARENT:[a-zA-Z\.0-9_]+]]
+#CHECK: scope: global
+#CHECK: type: group-comdat
+#CHECK: references:
+#CHECK: - kind: group-child
+#CHECK: offset: 0
+#CHECK: target: f1
+#CHECK: - kind: group-child
+#CHECK: offset: 0
+#CHECK: target: f2
+#CHECK: - kind: group-child
+#CHECK: offset: 0
+#CHECK: target: [[GCHILD:[a-zA-Z\.0-9_]+]]
+#CHECK: - kind: group-child
+#CHECK: offset: 0
+#CHECK: target: d1
+#CHECK: - name: f1
+#CHECK: scope: global
+#CHECK: - name: f2
+#CHECK: scope: global
+#CHECK: - name: g1
+#CHECK: ref-name: [[GCHILD]]
+#CHECK: scope: global
+#CHECK: - name: d1
+#CHECK: scope: global
+#CHECK: type: data
+#CHECK: ...
diff --git a/test/core/sectiongroup-simple.objtxt b/test/core/sectiongroup-simple.objtxt
new file mode 100644
index 000000000000..9f0ff9581c1d
--- /dev/null
+++ b/test/core/sectiongroup-simple.objtxt
@@ -0,0 +1,80 @@
+# RUN: lld -core %s | FileCheck %s
+
+#
+# Test that section groups are parsed properly when there is a reference to a
+# group atom from outside a group.
+#
+
+---
+defined-atoms:
+ - name: f1
+ scope: global
+ type: code
+ references:
+ - kind: layout-after
+ target: anotherfunction
+ - name: f2
+ scope: global
+ type: code
+ - name: g1
+ scope: global
+ type: code
+ - name: d1
+ scope: global
+ type: data
+ - name: g1
+ scope: global
+ type: group-comdat
+ references:
+ - kind: group-child
+ target: f1
+ - kind: group-child
+ target: f2
+ - kind: group-child
+ target: d1
+ - kind: group-child
+ target: g1
+ - name: anotherfunction
+ scope: global
+ type: data
+---
+undefined-atoms:
+ - name: f1
+ can-be-null: never
+...
+
+#CHECK: defined-atoms:
+#CHECK: - name: g1
+#CHECK: ref-name: [[PARENT:[a-zA-Z\.0-9_]+]]
+#CHECK: scope: global
+#CHECK: type: group-comdat
+#CHECK: references:
+#CHECK: - kind: group-child
+#CHECK: offset: 0
+#CHECK: target: f1
+#CHECK: - kind: group-child
+#CHECK: offset: 0
+#CHECK: target: f2
+#CHECK: - kind: group-child
+#CHECK: offset: 0
+#CHECK: target: d1
+#CHECK: - kind: group-child
+#CHECK: offset: 0
+#CHECK: target: [[GCHILD:[a-zA-Z\.0-9_]+]]
+#CHECK: - name: f1
+#CHECK: scope: global
+#CHECK: references:
+#CHECK: - kind: layout-after
+#CHECK: offset: 0
+#CHECK: target: anotherfunction
+#CHECK: - name: f2
+#CHECK: scope: global
+#CHECK: - name: d1
+#CHECK: scope: global
+#CHECK: type: data
+#CHECK: - name: g1
+#CHECK: ref-name: [[GCHILD]]
+#CHECK: scope: global
+#CHECK: - name: anotherfunction
+#CHECK: scope: global
+#CHECK: type: data
diff --git a/test/core/shared-library-basic.objtxt b/test/core/shared-library-basic.objtxt
new file mode 100644
index 000000000000..61445e7431fd
--- /dev/null
+++ b/test/core/shared-library-basic.objtxt
@@ -0,0 +1,40 @@
+# RUN: lld -core %s | FileCheck %s
+
+#
+# Test that shared-library symbols are parsed and preserved
+#
+
+---
+shared-library-atoms:
+ - name: malloc
+ load-name: libc.so
+ type: code
+ size: 0
+
+ - name: free
+ load-name: libc.so
+
+ - name: fast_malloc
+ load-name: libc.so
+ can-be-null: at-runtime
+
+ - name: stdout
+ load-name: libc.so
+ type: data
+ size: 8
+
+...
+
+# CHECK: shared-library-atoms:
+# CHECK: name: malloc
+# CHECK: load-name: libc.so
+# CHECK: name: free
+# CHECK: load-name: libc.so
+# CHECK: name: fast_malloc
+# CHECK: load-name: libc.so
+# CHECK: can-be-null: at-runtime
+# CHECK: name: stdout
+# CHECK: load-name: libc.so
+# CHECK: type: data
+# CHECK: size: 8
+# CHECK: ...
diff --git a/test/core/shared-library-coalesce.objtxt b/test/core/shared-library-coalesce.objtxt
new file mode 100644
index 000000000000..51ff93e87a88
--- /dev/null
+++ b/test/core/shared-library-coalesce.objtxt
@@ -0,0 +1,84 @@
+# RUN: lld -core %s | FileCheck %s
+
+#
+# Test that shared library symbols preserve their attributes and merge properly
+#
+
+---
+shared-library-atoms:
+ - name: foo1
+ load-name: libc.so
+
+ - name: foo2
+ load-name: libc.so
+
+ - name: bar1
+ load-name: libc.so
+ can-be-null: at-runtime
+
+ - name: bar2
+ load-name: libc.so
+ can-be-null: at-runtime
+
+ - name: mismatchNull1
+ load-name: libc.so
+ can-be-null: at-runtime
+
+ - name: mismatchNull2
+ load-name: libc.so
+
+ - name: mismatchload1
+ load-name: liba.so
+
+ - name: mismatchload2
+ load-name: libb.so
+
+---
+shared-library-atoms:
+ - name: foo2
+ load-name: libc.so
+
+ - name: foo3
+ load-name: libc.so
+
+ - name: bar2
+ load-name: libc.so
+ can-be-null: at-runtime
+
+ - name: bar3
+ load-name: libc.so
+ can-be-null: at-runtime
+
+ - name: mismatchNull1
+ load-name: libc.so
+
+ - name: mismatchNull2
+ load-name: libc.so
+ can-be-null: at-runtime
+
+ - name: mismatchload1
+ load-name: libb.so
+
+ - name: mismatchload2
+ load-name: liba.so
+
+...
+
+# CHECK: name: foo1
+# CHECK: name: foo2
+# CHECK: name: bar1
+# CHECK: can-be-null: at-runtime
+# CHECK: name: bar2
+# CHECK: can-be-null: at-runtime
+# CHECK: name: mismatchNull1
+# CHECK: can-be-null: at-runtime
+# CHECK: name: mismatchNull2
+# CHECK-NOT: can-be-null: at-runtime
+# CHECK: name: mismatchload1
+# CHECK: load-name: liba.so
+# CHECK: name: mismatchload2
+# CHECK: load-name: libb.so
+# CHECK: name: foo3
+# CHECK: name: bar3
+# CHECK: can-be-null: at-runtime
+# CHECK: ...
diff --git a/test/core/tent-merge.objtxt b/test/core/tent-merge.objtxt
new file mode 100644
index 000000000000..8ad46d40ae18
--- /dev/null
+++ b/test/core/tent-merge.objtxt
@@ -0,0 +1,25 @@
+# RUN: lld -core %s | FileCheck %s
+
+#
+# Test that a tentative definition and a regular global are merged into
+# one regular global
+#
+
+---
+defined-atoms:
+ - name: _foo
+ merge: as-tentative
+ scope: global
+ type: zero-fill
+ size: 4
+---
+defined-atoms:
+ - name: _foo
+ scope: global
+ type: data
+ content: [ 00, 00, 00, 00 ]
+...
+
+
+# CHECK: name: _foo
+# CHECK-NOT: merge: as-tentative
diff --git a/test/core/undef-coalesce-error.objtxt b/test/core/undef-coalesce-error.objtxt
new file mode 100644
index 000000000000..a0485befd288
--- /dev/null
+++ b/test/core/undef-coalesce-error.objtxt
@@ -0,0 +1,47 @@
+# RUN: not lld -core --undefines-are-errors %s 2> %t.err
+# RUN: FileCheck -check-prefix=CHECKERR %s < %t.err
+# RUN: lld -core %s | FileCheck %s
+
+#
+# Test that -undefines-are-errors triggers and error
+# and that not using that option results in undefined atoms.
+#
+
+---
+defined-atoms:
+ - name: foo
+ type: code
+
+undefined-atoms:
+ - name: malloc
+ - name: free
+---
+defined-atoms:
+ - name: bar
+ type: code
+
+undefined-atoms:
+ - name: malloc
+ - name: myfunc
+---
+defined-atoms:
+ - name: myfunc
+ scope: global
+ type: code
+
+undefined-atoms:
+ - name: free
+...
+
+# CHECKERR: free
+# CHECKERR: malloc
+# CHECKERR: symbol(s) not found
+
+# CHECK: defined-atoms:
+# CHECK: name: foo
+# CHECK: name: bar
+# CHECK: name: myfunc
+# CHECK: undefined-atoms:
+# CHECK: name: malloc
+# CHECK: name: free
+# CHECK: ...
diff --git a/test/core/undef-coalesce.objtxt b/test/core/undef-coalesce.objtxt
new file mode 100644
index 000000000000..822ed5acf191
--- /dev/null
+++ b/test/core/undef-coalesce.objtxt
@@ -0,0 +1,42 @@
+# RUN: lld -core %s | FileCheck %s
+
+#
+# Test that undefined symbols are coalesced with other undefined symbols
+# and definitions override them.
+#
+
+---
+defined-atoms:
+ - name: foo
+ type: code
+
+undefined-atoms:
+ - name: malloc
+ - name: free
+---
+defined-atoms:
+ - name: bar
+ type: code
+
+undefined-atoms:
+ - name: malloc
+ - name: myfunc
+---
+defined-atoms:
+ - name: myfunc
+ scope: global
+ type: code
+
+undefined-atoms:
+ - name: free
+...
+
+# CHECK: defined-atoms:
+# CHECK: name: foo
+# CHECK: name: bar
+# CHECK: name: myfunc
+# CHECK: scope: global
+# CHECK: undefined-atoms:
+# CHECK: name: malloc
+# CHECK: name: free
+# CHECK: ...
diff --git a/test/core/undef-fallback.objtxt b/test/core/undef-fallback.objtxt
new file mode 100644
index 000000000000..8abaa93c8e8d
--- /dev/null
+++ b/test/core/undef-fallback.objtxt
@@ -0,0 +1,37 @@
+# RUN: lld -core %s | FileCheck %s
+
+# Test that fallback atoms can be parsed by YAML reader and processed by the
+# core linker.
+
+---
+defined-atoms:
+ - name: def1
+ scope: global
+
+undefined-atoms:
+ - name: undef1
+ fallback:
+ name: fallback1
+ - name: undef2
+ fallback:
+ name: fallback2
+---
+defined-atoms:
+ - name: fallback1
+
+undefined-atoms:
+ - name: def1
+ fallback:
+ name: fallback3
+...
+
+# CHECK: defined-atoms:
+# CHECK-NEXT: - name: def1
+# CHECK-NEXT: scope: global
+# CHECK-NEXT: - name: fallback1
+# CHECK-NEXT: ref-name: fallback1
+# CHECK-NEXT: undefined-atoms:
+# CHECK-NEXT: - name: fallback1
+# CHECK-NEXT: - name: fallback2
+
+# CHECK-NOT: - name: fallback3
diff --git a/test/core/undef-weak-coalesce.objtxt b/test/core/undef-weak-coalesce.objtxt
new file mode 100644
index 000000000000..97e0fd28500d
--- /dev/null
+++ b/test/core/undef-weak-coalesce.objtxt
@@ -0,0 +1,72 @@
+# RUN: lld -core %s | FileCheck %s
+
+#
+# Test that undefined symbols preserve their attributes and merge properly
+#
+
+---
+undefined-atoms:
+ - name: regular_func
+ can-be-null: never
+ - name: weak_import_func
+ can-be-null: at-runtime
+ - name: weak_func
+ can-be-null: at-buildtime
+ - name: bar1
+ can-be-null: never
+ - name: bar2
+ can-be-null: at-runtime
+ - name: bar3
+ can-be-null: at-buildtime
+ - name: bar4
+ can-be-null: never
+ - name: bar5
+ can-be-null: at-runtime
+ - name: bar6
+ can-be-null: at-buildtime
+ - name: bar7
+ can-be-null: never
+ - name: bar8
+ can-be-null: at-runtime
+ - name: bar9
+ can-be-null: at-buildtime
+---
+undefined-atoms:
+ - name: bar1
+ can-be-null: never
+ - name: bar2
+ can-be-null: at-runtime
+ - name: bar3
+ can-be-null: at-buildtime
+ - name: bar4
+ can-be-null: at-runtime
+ - name: bar5
+ can-be-null: at-buildtime
+ - name: bar6
+ can-be-null: never
+ - name: bar7
+ can-be-null: at-buildtime
+ - name: bar8
+ can-be-null: never
+ - name: bar9
+ can-be-null: at-runtime
+...
+
+# CHECK: - name: regular_func
+# CHECK-NEXT: - name: weak_import_func
+# CHECK-NEXT: can-be-null: at-runtime
+# CHECK-NEXT: - name: weak_func
+# CHECK-NEXT: can-be-null: at-buildtime
+# CHECK-NEXT: - name: bar1
+# CHECK-NEXT: - name: bar2
+# CHECK-NEXT: can-be-null: at-runtime
+# CHECK-NEXT: - name: bar3
+# CHECK-NEXT: can-be-null: at-buildtime
+# CHECK-NEXT: - name: bar4
+# CHECK-NEXT: - name: bar5
+# CHECK-NEXT: can-be-null: at-runtime
+# CHECK-NEXT: - name: bar7
+# CHECK-NEXT: - name: bar6
+# CHECK-NEXT: - name: bar8
+# CHECK-NEXT: - name: bar9
+# CHECK-NEXT: can-be-null: at-runtime
diff --git a/test/core/weak-coalesce.objtxt b/test/core/weak-coalesce.objtxt
new file mode 100644
index 000000000000..550c10cfa468
--- /dev/null
+++ b/test/core/weak-coalesce.objtxt
@@ -0,0 +1,30 @@
+# RUN: lld -core %s | FileCheck %s
+
+#
+# Test that weak definitions are coalesced away in favor of a regular definition
+#
+
+---
+defined-atoms:
+ - name: _foo
+ merge: as-weak
+ scope: global
+ type: data
+---
+defined-atoms:
+ - name: _foo
+ scope: global
+ type: data
+---
+defined-atoms:
+ - name: _foo
+ merge: as-weak
+ scope: global
+ type: data
+...
+
+
+# CHECK: name: _foo
+# CHECK-NOT: merge: as-weak
+# CHECK-NOT: name: _foo
+# CHECK: ...
diff --git a/test/darwin/native-and-mach-o.objtxt b/test/darwin/native-and-mach-o.objtxt
new file mode 100644
index 000000000000..20f2d0b96207
--- /dev/null
+++ b/test/darwin/native-and-mach-o.objtxt
@@ -0,0 +1,65 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t && \
+# RUN: llvm-nm %t | FileCheck %s
+#
+# Test a mix of atoms and mach-o both encoded in yaml
+#
+
+--- !native
+defined-atoms:
+ - name: _main
+ type: code
+ scope: global
+ content: [ 55, 48, 89, E5, 30, C0, E8, 00,
+ 00, 00, 00, 31, C0, 5D, C3 ]
+ references:
+ - offset: 7
+ kind: branch32
+ target: _foo
+
+undefined-atoms:
+ - name: _foo
+
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS ]
+ address: 0
+ content: [ 0xC3 ]
+global-symbols:
+ - name: _foo
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ desc: [ ]
+ value: 0
+
+--- !mach-o
+arch: x86_64
+file-type: MH_DYLIB
+flags: [ ]
+install-name: /usr/lib/libSystem.B.dylib
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0x55 ]
+
+global-symbols:
+ - name: dyld_stub_binder
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+
+
+...
+
+# CHECK: {{[0-9a-f]+}} T _foo
+# CHECK: {{[0-9a-f]+}} T _main
diff --git a/test/elf/AArch64/Inputs/fn.c b/test/elf/AArch64/Inputs/fn.c
new file mode 100644
index 000000000000..54939a2426b2
--- /dev/null
+++ b/test/elf/AArch64/Inputs/fn.c
@@ -0,0 +1,4 @@
+int fn()
+{
+ return 0;
+}
diff --git a/test/elf/AArch64/Inputs/fn.o b/test/elf/AArch64/Inputs/fn.o
new file mode 100644
index 000000000000..53e47ad37742
--- /dev/null
+++ b/test/elf/AArch64/Inputs/fn.o
Binary files differ
diff --git a/test/elf/AArch64/Inputs/initfini-option.c b/test/elf/AArch64/Inputs/initfini-option.c
new file mode 100644
index 000000000000..6021fb57ffa9
--- /dev/null
+++ b/test/elf/AArch64/Inputs/initfini-option.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+
+void init() {
+ printf("%s\n", __FUNCTION__);
+}
+
+void fini() {
+ printf("%s\n", __FUNCTION__);
+}
+
+int main() {
+}
diff --git a/test/elf/AArch64/Inputs/initfini-option.o b/test/elf/AArch64/Inputs/initfini-option.o
new file mode 100644
index 000000000000..c75079b013fa
--- /dev/null
+++ b/test/elf/AArch64/Inputs/initfini-option.o
Binary files differ
diff --git a/test/elf/AArch64/Inputs/initfini.c b/test/elf/AArch64/Inputs/initfini.c
new file mode 100644
index 000000000000..8369d68a8dab
--- /dev/null
+++ b/test/elf/AArch64/Inputs/initfini.c
@@ -0,0 +1,13 @@
+#include <stdio.h>
+
+void __attribute__ ((constructor)) constructor() {
+ printf("%s\n", __FUNCTION__);
+}
+
+void __attribute__ ((destructor)) destructor() {
+ printf("%s\n", __FUNCTION__);
+}
+
+int main() {
+ return 0;
+}
diff --git a/test/elf/AArch64/Inputs/initfini.o b/test/elf/AArch64/Inputs/initfini.o
new file mode 100644
index 000000000000..030fe59878be
--- /dev/null
+++ b/test/elf/AArch64/Inputs/initfini.o
Binary files differ
diff --git a/test/elf/AArch64/Inputs/main.c b/test/elf/AArch64/Inputs/main.c
new file mode 100644
index 000000000000..0280c9127076
--- /dev/null
+++ b/test/elf/AArch64/Inputs/main.c
@@ -0,0 +1,4 @@
+int main() {
+ fn();
+ return 0;
+}
diff --git a/test/elf/AArch64/Inputs/main.o b/test/elf/AArch64/Inputs/main.o
new file mode 100644
index 000000000000..8c0f049da6a8
--- /dev/null
+++ b/test/elf/AArch64/Inputs/main.o
Binary files differ
diff --git a/test/elf/AArch64/Inputs/no-interp-section.c b/test/elf/AArch64/Inputs/no-interp-section.c
new file mode 100644
index 000000000000..3981c038ed33
--- /dev/null
+++ b/test/elf/AArch64/Inputs/no-interp-section.c
@@ -0,0 +1 @@
+int c = 10;
diff --git a/test/elf/AArch64/Inputs/no-interp-section.o b/test/elf/AArch64/Inputs/no-interp-section.o
new file mode 100644
index 000000000000..36b41fdbf782
--- /dev/null
+++ b/test/elf/AArch64/Inputs/no-interp-section.o
Binary files differ
diff --git a/test/elf/AArch64/Inputs/zerosizedsection.o b/test/elf/AArch64/Inputs/zerosizedsection.o
new file mode 100644
index 000000000000..10123fcef90d
--- /dev/null
+++ b/test/elf/AArch64/Inputs/zerosizedsection.o
Binary files differ
diff --git a/test/elf/AArch64/Inputs/zerosizedsection.s b/test/elf/AArch64/Inputs/zerosizedsection.s
new file mode 100644
index 000000000000..651ee3aab503
--- /dev/null
+++ b/test/elf/AArch64/Inputs/zerosizedsection.s
@@ -0,0 +1,3 @@
+.text
+.data
+.word .text
diff --git a/test/elf/AArch64/defsym.test b/test/elf/AArch64/defsym.test
new file mode 100644
index 000000000000..8bf492d4a38a
--- /dev/null
+++ b/test/elf/AArch64/defsym.test
@@ -0,0 +1,22 @@
+RUN: lld -flavor gnu -target aarch64--linux-gnu --defsym=main=fn \
+RUN: --noinhibit-exec %p/Inputs/fn.o -o %t
+RUN: llvm-readobj -symbols %t | FileCheck %s
+
+CHECK: Symbol {
+CHECK: Name: main (1)
+CHECK: Value: 0x4001A4
+CHECK: Size: 0
+CHECK: Binding: Global (0x1)
+CHECK: Type: Function (0x2)
+CHECK: Other: 0
+CHECK: Section: .text (0x5)
+CHECK: }
+CHECK: Symbol {
+CHECK: Name: fn (11)
+CHECK: Value: 0x4001A4
+CHECK: Size: 8
+CHECK: Binding: Global (0x1)
+CHECK: Type: Function (0x2)
+CHECK: Other: 0
+CHECK: Section: .text (0x5)
+CHECK: }
diff --git a/test/elf/AArch64/dontignorezerosize-sections.test b/test/elf/AArch64/dontignorezerosize-sections.test
new file mode 100644
index 000000000000..ac593abcc368
--- /dev/null
+++ b/test/elf/AArch64/dontignorezerosize-sections.test
@@ -0,0 +1,9 @@
+# This tests that lld is not ignoring zero sized sections
+RUN: lld -flavor gnu -target aarch64--linux-gnu %p/Inputs/zerosizedsection.o \
+RUN: --noinhibit-exec --output-filetype=yaml -o %t
+RUN: FileCheck %s < %t
+
+CHECK: references:
+CHECK: - kind: layout-after
+CHECK: offset: 0
+CHECK: target: L000
diff --git a/test/elf/AArch64/dynlib-nointerp-section.test b/test/elf/AArch64/dynlib-nointerp-section.test
new file mode 100644
index 000000000000..9365b4d5b3e9
--- /dev/null
+++ b/test/elf/AArch64/dynlib-nointerp-section.test
@@ -0,0 +1,5 @@
+RUN: lld -flavor gnu -target aarch64--linux-gnu %p/Inputs/no-interp-section.o \
+RUN: -o %t -shared
+RUN: llvm-objdump -section-headers %t | FileCheck %s
+
+CHECK-NOT: .interp
diff --git a/test/elf/AArch64/initfini.test b/test/elf/AArch64/initfini.test
new file mode 100644
index 000000000000..887e44ea105b
--- /dev/null
+++ b/test/elf/AArch64/initfini.test
@@ -0,0 +1,23 @@
+# This tests the functionality that lld is able to read
+# init_array/fini_array sections in the input ELF. This
+# corresponds to the the .init_array/.fini_array sections
+# in the output ELF.
+
+RUN: lld -flavor gnu -target aarch64--linux-gnu %p/Inputs/initfini.o \
+RUN: --noinhibit-exec --output-filetype=yaml -o %t
+RUN: FileCheck %s < %t
+
+CHECK: type: data
+CHECK: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ]
+CHECK: section-name: .init_array
+CHECK: references:
+CHECK: - kind: R_AARCH64_ABS64
+CHECK: offset: 0
+CHECK: target: constructor
+CHECK: type: data
+CHECK: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ]
+CHECK: section-name: .fini_array
+CHECK: references:
+CHECK: - kind: R_AARCH64_ABS64
+CHECK: offset: 0
+CHECK: target: destructor
diff --git a/test/elf/AArch64/rel-abs32-overflow.test b/test/elf/AArch64/rel-abs32-overflow.test
new file mode 100644
index 000000000000..e32fce173c51
--- /dev/null
+++ b/test/elf/AArch64/rel-abs32-overflow.test
@@ -0,0 +1,53 @@
+# Check handling of R_AARCH64_ABS32 relocation overflow.
+# RUN: yaml2obj -format=elf %s > %t-obj
+# RUN: not lld -flavor gnu -target arm64 -o %t-exe %t-obj 2>&1 | FileCheck %s
+
+# CHECK-DAG: Relocation out of range in file {{.*}}: reference from data1+0 to data2+34359738369 of type 258 (R_AARCH64_ABS32)
+# CHECK-DAG: Relocation out of range in file {{.*}}: reference from data2+0 to data1+34359738369 of type 258 (R_AARCH64_ABS32)
+
+!ELF
+FileHeader: !FileHeader
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_AARCH64
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Content: "00000000"
+ AddressAlign: 16
+ Flags: [SHF_ALLOC, SHF_EXECINSTR]
+- Name: .data
+ Type: SHT_PROGBITS
+ Content: "0000000000000000"
+ AddressAlign: 16
+ Flags: [SHF_ALLOC, SHF_WRITE]
+
+- Name: .rela.data
+ Type: SHT_RELA
+ Info: .data
+ AddressAlign: 8
+ Relocations:
+ - Offset: 0x0
+ Symbol: data2
+ Type: R_AARCH64_ABS32
+ Addend: 0x800000001
+ - Offset: 0x4
+ Symbol: data1
+ Type: R_AARCH64_ABS32
+ Addend: 0x800000001
+
+Symbols:
+ Global:
+ - Name: _start
+ Section: .text
+ Value: 0x0
+ Size: 4
+ - Name: data1
+ Section: .data
+ Size: 4
+ - Name: data2
+ Section: .data
+ Value: 0x4
+ Size: 4
diff --git a/test/elf/AArch64/rel-abs32.test b/test/elf/AArch64/rel-abs32.test
new file mode 100644
index 000000000000..edd7b69e428d
--- /dev/null
+++ b/test/elf/AArch64/rel-abs32.test
@@ -0,0 +1,59 @@
+# Check handling of R_AARCH64_ABS32 relocation.
+# RUN: yaml2obj -format=elf %s > %t-obj
+# RUN: lld -flavor gnu -target arm64 -o %t-exe %t-obj
+# RUN: llvm-objdump -s -t %t-exe | FileCheck %s
+
+# CHECK: Contents of section .data:
+# CHECK-NEXT: 401060 65104080 61104080 e.@.a.@.
+# ^^ data2 + 0x80000001 = 0x80401069
+# ^^ data1 + 0x80000001 = 0x80401061
+# CHECK: SYMBOL TABLE:
+# CHECK: 00401060 g .data 00000004 data1
+# CHECK: 00401064 g .data 00000004 data2
+
+!ELF
+FileHeader: !FileHeader
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_AARCH64
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Content: "00000000"
+ AddressAlign: 16
+ Flags: [SHF_ALLOC, SHF_EXECINSTR]
+- Name: .data
+ Type: SHT_PROGBITS
+ Content: "0000000000000000"
+ AddressAlign: 16
+ Flags: [SHF_ALLOC, SHF_WRITE]
+
+- Name: .rela.data
+ Type: SHT_RELA
+ Info: .data
+ AddressAlign: 8
+ Relocations:
+ - Offset: 0x0
+ Symbol: data2
+ Type: R_AARCH64_ABS32
+ Addend: 0x80000001
+ - Offset: 0x4
+ Symbol: data1
+ Type: R_AARCH64_ABS32
+ Addend: 0x80000001
+
+Symbols:
+ Global:
+ - Name: _start
+ Section: .text
+ Value: 0x0
+ Size: 4
+ - Name: data1
+ Section: .data
+ Size: 4
+ - Name: data2
+ Section: .data
+ Value: 0x4
+ Size: 4
diff --git a/test/elf/AArch64/rel-abs64.test b/test/elf/AArch64/rel-abs64.test
new file mode 100644
index 000000000000..c125e3f2450d
--- /dev/null
+++ b/test/elf/AArch64/rel-abs64.test
@@ -0,0 +1,59 @@
+# Check handling of R_AARCH64_ABS64 relocation.
+# RUN: yaml2obj -format=elf %s > %t-obj
+# RUN: lld -flavor gnu -target arm64 -o %t-exe %t-obj
+# RUN: llvm-objdump -s -t %t-exe | FileCheck %s
+
+# CHECK: Contents of section .data:
+# CHECK-NEXT: 401060 69104000 00000080 61104000 00000080 i.@.....a.@.....
+# ^^ data2 + 0x8000000000000001 = 0x8000000000401069
+# ^^ data1 + 0x8000000000000001 = 0x8000000000401061
+# CHECK: SYMBOL TABLE:
+# CHECK: 00401060 g .data 00000008 data1
+# CHECK: 00401068 g .data 00000008 data2
+
+!ELF
+FileHeader: !FileHeader
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_AARCH64
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Content: "00000000"
+ AddressAlign: 16
+ Flags: [SHF_ALLOC, SHF_EXECINSTR]
+- Name: .data
+ Type: SHT_PROGBITS
+ Content: "00000000000000000000000000000000"
+ AddressAlign: 16
+ Flags: [SHF_ALLOC, SHF_WRITE]
+
+- Name: .rela.data
+ Type: SHT_RELA
+ Info: .data
+ AddressAlign: 8
+ Relocations:
+ - Offset: 0x0
+ Symbol: data2
+ Type: R_AARCH64_ABS64
+ Addend: -9223372036854775807
+ - Offset: 0x8
+ Symbol: data1
+ Type: R_AARCH64_ABS64
+ Addend: -9223372036854775807
+
+Symbols:
+ Global:
+ - Name: _start
+ Section: .text
+ Value: 0x0
+ Size: 4
+ - Name: data1
+ Section: .data
+ Size: 8
+ - Name: data2
+ Section: .data
+ Value: 0x8
+ Size: 8
diff --git a/test/elf/AArch64/rel-bad.test b/test/elf/AArch64/rel-bad.test
new file mode 100644
index 000000000000..6b9e831146f3
--- /dev/null
+++ b/test/elf/AArch64/rel-bad.test
@@ -0,0 +1,44 @@
+# Check handling of a bad relocation (in this case dynamic in a static object).
+# RUN: yaml2obj -format=elf %s > %t-obj
+# RUN: not lld -flavor gnu -target arm64 -o %t-exe %t-obj 2>&1 | FileCheck %s
+
+# CHECK: Unhandled reference type in file {{.*}}: reference from data1+4 to data1+0 of type 1024 (R_AARCH64_COPY)
+
+!ELF
+FileHeader: !FileHeader
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_AARCH64
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Content: "00000000"
+ AddressAlign: 16
+ Flags: [SHF_ALLOC, SHF_EXECINSTR]
+- Name: .data
+ Type: SHT_PROGBITS
+ Content: "0000000000000000"
+ AddressAlign: 16
+ Flags: [SHF_ALLOC, SHF_WRITE]
+
+- Name: .rela.data
+ Type: SHT_RELA
+ Info: .data
+ AddressAlign: 8
+ Relocations:
+ - Offset: 0x4
+ Symbol: data1
+ Type: R_AARCH64_COPY
+ Addend: 0
+
+Symbols:
+ Global:
+ - Name: _start
+ Section: .text
+ Value: 0x0
+ Size: 4
+ - Name: data1
+ Section: .data
+ Size: 8
diff --git a/test/elf/ARM/arm-symbols.test b/test/elf/ARM/arm-symbols.test
new file mode 100644
index 000000000000..b99960697679
--- /dev/null
+++ b/test/elf/ARM/arm-symbols.test
@@ -0,0 +1,52 @@
+# Check that symbols formed from ARM instructions are valid:
+# 1. Symbol address.
+# 2. Symbol content size.
+# 3. Symbol content.
+
+# RUN: yaml2obj -format=elf %s > %t-a.o
+# RUN: lld -flavor gnu -target arm-linux-gnu \
+# RUN: -Bstatic --noinhibit-exec %t-a.o -o %t-a
+# RUN: llvm-readobj -symbols %t-a | FileCheck -check-prefix=SYM-ADDR %s
+# RUN: llvm-readobj -symbols %t-a | FileCheck -check-prefix=SYM-SIZE %s
+# RUN: llvm-objdump -s -t %t-a | FileCheck -check-prefix=SYM-CONTENT %s
+
+# SYM-ADDR: Name: main (1)
+# SYM-ADDR-NEXT: Value: 0x400074
+
+# SYM-SIZE: Name: main (1)
+# SYM-SIZE-NEXT: Value: 0x{{[0-9a-f]+}}
+# SYM-SIZE-NEXT: Size: 28
+
+# SYM-CONTENT: Contents of section .text:
+# SYM-CONTENT-NEXT: 400074 04b02de5 00b08de2 0030a0e3 0300a0e1 ..-......0......
+# SYM-CONTENT-NEXT: 400084 00d04be2 04b09de4 1eff2fe1 ..K......./.
+
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_ARM
+ Flags: [ EF_ARM_EABI_VER5 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: 04B02DE500B08DE20030A0E30300A0E100D04BE204B09DE41EFF2FE1
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+Symbols:
+ Global:
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+...
diff --git a/test/elf/ARM/defsym.test b/test/elf/ARM/defsym.test
new file mode 100644
index 000000000000..0cd1736d924e
--- /dev/null
+++ b/test/elf/ARM/defsym.test
@@ -0,0 +1,51 @@
+# Check that defined symbols are present in the generated executable
+
+# RUN: yaml2obj -format=elf %s > %t-o.o
+# RUN: lld -flavor gnu -target arm-linux-gnu --defsym=main=fn \
+# RUN: -Bstatic --noinhibit-exec %t-o.o -o %t
+# RUN: llvm-readobj -symbols %t | FileCheck %s
+
+# CHECK: Name: main (1)
+# CHECK-NEXT: Value: 0x400074
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: Function (0x2)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: .text (0x1)
+# CHECK: Name: fn (6)
+# CHECK-NEXT: Value: 0x400074
+# CHECK-NEXT: Size: {{[0-9]+}}
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: Function (0x2)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: .text (0x1)
+
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_ARM
+ Flags: [ EF_ARM_EABI_VER5 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: 04B02DE500B08DE20030A0E30300A0E100D04BE204B09DE41EFF2FE1
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+Symbols:
+ Global:
+ - Name: fn
+ Type: STT_FUNC
+ Section: .text
+...
diff --git a/test/elf/ARM/entry-point.test b/test/elf/ARM/entry-point.test
new file mode 100644
index 000000000000..d168bb6463c6
--- /dev/null
+++ b/test/elf/ARM/entry-point.test
@@ -0,0 +1,77 @@
+# 1. Check entry point address for ARM code - should be even.
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-arm.o
+# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \
+# RUN: --noinhibit-exec %t-arm.o -o %t-arm
+# RUN: llvm-readobj -file-headers %t-arm | FileCheck -check-prefix=ARM-ENTRY %s
+#
+# ARM-ENTRY: Entry: 0x400074
+
+# 2. Check entry point address for Thumb code - should be odd.
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-thm.o
+# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \
+# RUN: --noinhibit-exec %t-thm.o -o %t-thm
+# RUN: llvm-readobj -file-headers %t-thm | FileCheck -check-prefix=THM-ENTRY %s
+#
+# THM-ENTRY: Entry: 0x400075
+
+# arm.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_ARM
+ Flags: [ EF_ARM_EABI_VER5 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: 04B02DE500B08DE20030A0E30300A0E100D04BE204B09DE41EFF2FE1
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+Symbols:
+ Global:
+ - Name: _start
+ Type: STT_FUNC
+ Section: .text
+
+# thm.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_ARM
+ Flags: [ EF_ARM_EABI_VER5 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: 80B400AF00231846BD465DF8047B7047
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+Symbols:
+ Global:
+ - Name: _start
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000001
+...
diff --git a/test/elf/ARM/missing-symbol.test b/test/elf/ARM/missing-symbol.test
new file mode 100644
index 000000000000..f9b3e26ea1a3
--- /dev/null
+++ b/test/elf/ARM/missing-symbol.test
@@ -0,0 +1,39 @@
+# Check that _MISSING_SYMBOL_ symbol is not resolved
+
+# RUN: yaml2obj -format=elf %s > %t-o.o
+# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \
+# RUN: --noinhibit-exec %t-o.o -o %t 2>&1 | FileCheck %s
+
+# CHECK: Undefined symbol: {{.*}}: _MISSING_SYMBOL_
+
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_ARM
+ Flags: [ EF_ARM_EABI_VER5 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: 80B483B000AF40F20003C0F200037B60002318460C37BD465DF8047B704700BF
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+Symbols:
+ Global:
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000001
+ - Name: _MISSING_SYMBOL_
+...
diff --git a/test/elf/ARM/rel-abs32.test b/test/elf/ARM/rel-abs32.test
new file mode 100644
index 000000000000..57d323100feb
--- /dev/null
+++ b/test/elf/ARM/rel-abs32.test
@@ -0,0 +1,59 @@
+# Check handling of R_ARM_ABS32 relocation.
+# RUN: yaml2obj -format=elf %s > %t-o.o
+# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \
+# RUN: --noinhibit-exec %t-o.o -o %t
+# RUN: llvm-objdump -s -t %t | FileCheck %s
+
+# CHECK: Contents of section .data:
+# CHECK-NEXT: 401000 84004000
+# data = 0x400084 ^^
+# data main addr content
+# 0x400084 = 0x400074 + 0x10
+# CHECK: SYMBOL TABLE:
+# CHECK: 00400074 g F .text {{[0-9a-f]+}} main
+# CHECK: 00401000 g .data 00000004 data
+
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_ARM
+ Flags: [ EF_ARM_EABI_VER5 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: 04B02DE500B08DE20030A0E30300A0E100D04BE204B09DE41EFF2FE1
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: '10000000'
+ - Name: .rel.data
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: .data
+ Relocations:
+ - Offset: 0x0000000000000000
+ Symbol: main
+ Type: R_ARM_ABS32
+ Addend: 0
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+Symbols:
+ Global:
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x000000000000001C
+ - Name: data
+ Type: STT_OBJECT
+ Section: .data
+ Size: 0x0000000000000004
+...
diff --git a/test/elf/ARM/rel-arm-call.test b/test/elf/ARM/rel-arm-call.test
new file mode 100644
index 000000000000..234b34eae92d
--- /dev/null
+++ b/test/elf/ARM/rel-arm-call.test
@@ -0,0 +1,60 @@
+# Check handling of R_ARM_CALL relocation.
+# RUN: yaml2obj -format=elf %s > %t-o.o
+# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \
+# RUN: --noinhibit-exec %t-o.o -o %t
+# RUN: llvm-objdump -s -t %t | FileCheck %s
+
+# CHECK: Contents of section .text:
+# CHECK: 400084 1eff2fe1 00482de9 04b08de2 f7ffffeb
+# offset = -0x24 ^^
+# call site offset PC(arm) _Z1fv addr
+# 0x400090 + (-0x24) + 0x8 = 0x400074
+# CHECK: SYMBOL TABLE:
+# CHECK: 00400074 g F .text {{[0-9a-f]+}} _Z1fv
+# CHECK: 00400088 g F .text {{[0-9a-f]+}} main
+
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_ARM
+ Flags: [ EF_ARM_EABI_VER5 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: 04B02DE500B08DE200D04BE204B09DE41EFF2FE100482DE904B08DE2FEFFFFEB0030A0E30300A0E10088BDE8
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: .text
+ Relocations:
+ - Offset: 0x000000000000001C
+ Symbol: _Z1fv
+ Type: R_ARM_CALL
+ Addend: 0
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+Symbols:
+ Global:
+ - Name: _Z1fv
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x0000000000000014
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000014
+ Size: 0x0000000000000018
+...
diff --git a/test/elf/ARM/rel-arm-jump24-veneer-b.test b/test/elf/ARM/rel-arm-jump24-veneer-b.test
new file mode 100644
index 000000000000..4caeac083b8d
--- /dev/null
+++ b/test/elf/ARM/rel-arm-jump24-veneer-b.test
@@ -0,0 +1,101 @@
+# Check veneer generation for R_ARM_JUMP24 relocation (B instruction call).
+
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-arm.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-thm.o
+# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \
+# RUN: --noinhibit-exec %t-arm.o %t-thm.o -o %t
+
+# RUN: llvm-objdump -s -t %t | FileCheck -check-prefix=B-VENEER %s
+# RUN: llvm-objdump -s -t %t | FileCheck -check-prefix=B-ADDR %s
+
+# B-VENEER: Contents of section .text:
+# B-VENEER: 400074 010000ea
+# Call from main:
+# offset = 0x4 ^^
+# call site offset PC(arm) ___Z1fv_from_arm addr
+# 0x400074 + 0x4 + 0x8 = 0x400080
+#
+# Code of the veneer:
+# B-VENEER: {{[0-9a-f]+}} {{[0-9a-f]+}} 04f01fe5
+# B-VENEER: 400084 79004000
+# call addr = 0x400079 ^^
+# call addr _Z1fv addr Thumb mode
+# 0x400079 = 0x400078 | 0x1
+#
+# B-ADDR: SYMBOL TABLE:
+# B-ADDR: 00400080 l F .text {{[0-9a-f]+}} ___Z1fv_from_arm
+# B-ADDR: 00400074 g F .text {{[0-9a-f]+}} main
+# B-ADDR: 00400078 g F .text {{[0-9a-f]+}} _Z1fv
+
+# arm.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_ARM
+ Flags: [ EF_ARM_EABI_VER5 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: FEFFFFEA
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: .text
+ Relocations:
+ - Offset: 0x0000000000000000
+ Symbol: _Z1fv
+ Type: R_ARM_JUMP24
+ Addend: 0
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+Symbols:
+ Global:
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+ - Name: _Z1fv
+
+# thm.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_ARM
+ Flags: [ EF_ARM_EABI_VER5 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: 4FF0000318467047
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+Symbols:
+ Global:
+ - Name: _Z1fv
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000001
+...
diff --git a/test/elf/ARM/rel-arm-jump24-veneer-bl.test b/test/elf/ARM/rel-arm-jump24-veneer-bl.test
new file mode 100644
index 000000000000..cd386dc5b1a4
--- /dev/null
+++ b/test/elf/ARM/rel-arm-jump24-veneer-bl.test
@@ -0,0 +1,100 @@
+# Check veneer generation for R_ARM_JUMP24 relocation (BL<c> instruction call).
+
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-arm.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-thm.o
+# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \
+# RUN: --noinhibit-exec %t-arm.o %t-thm.o -o %t
+
+# RUN: llvm-objdump -s -t %t | FileCheck -check-prefix=BL-VENEER %s
+# RUN: llvm-objdump -s -t %t | FileCheck -check-prefix=BL-ADDR %s
+
+# BL-VENEER: Contents of section .text:
+# BL-VENEER: 400084 0400000b
+# Call from main:
+# offset = 0x10 ^^
+# call site offset PC(arm) ___Z1fv_from_arm addr
+# 0x400084 + 0x10 + 0x8 = 0x40009c
+#
+# Code of the veneer:
+# BL-VENEER: 400094 {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} 95004000
+# call addr = 0x400095 ^^
+# call addr _Z1fv addr Thumb mode
+# 0x400095 = 0x400094 | 0x1
+#
+# BL-ADDR: SYMBOL TABLE:
+# BL-ADDR: 0040009c l F .text {{[0-9a-f]+}} ___Z1fv_from_arm
+# BL-ADDR: 00400074 g F .text {{[0-9a-f]+}} main
+# BL-ADDR: 00400094 g F .text {{[0-9a-f]+}} _Z1fv
+
+# arm.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_ARM
+ Flags: [ EF_ARM_EABI_VER5 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: 00482DE904B08DE20030A0E3000053E3FEFFFF0B0030A0E30300A0E10088BDE8
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: .text
+ Relocations:
+ - Offset: 0x0000000000000010
+ Symbol: _Z1fv
+ Type: R_ARM_JUMP24
+ Addend: 0
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+Symbols:
+ Global:
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+ - Name: _Z1fv
+
+# thm.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_ARM
+ Flags: [ EF_ARM_EABI_VER5 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: 4FF0000318467047
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+Symbols:
+ Global:
+ - Name: _Z1fv
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000001
+...
diff --git a/test/elf/ARM/rel-arm-jump24.test b/test/elf/ARM/rel-arm-jump24.test
new file mode 100644
index 000000000000..18eb8397d7b5
--- /dev/null
+++ b/test/elf/ARM/rel-arm-jump24.test
@@ -0,0 +1,58 @@
+# Check handling of R_ARM_JUMP24 relocation.
+# RUN: yaml2obj -format=elf %s > %t-o.o
+# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \
+# RUN: --noinhibit-exec %t-o.o -o %t
+# RUN: llvm-objdump -s -t %t | FileCheck %s
+
+# CHECK: Contents of section .text:
+# CHECK: 400094 04b08de2 f5ffffea 0030a0e1 0300a0e1
+# offset = -0x2C ^^
+# call site offset PC(arm) _Z1fv addr
+# 0x400098 + (-0x2C) + 0x8 = 0x400074
+# CHECK: SYMBOL TABLE:
+# CHECK: 00400074 g F .text {{[0-9a-f]+}} _Z1fv
+# CHECK: 00400090 g F .text {{[0-9a-f]+}} main
+
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_ARM
+ Flags: [ EF_ARM_EABI_VER5 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: 04B02DE500B08DE20030A0E30300A0E100D04BE204B09DE41EFF2FE100482DE904B08DE2FEFFFFEA0030A0E10300A0E10088BDE8
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: .text
+ Relocations:
+ - Offset: 0x0000000000000024
+ Symbol: _Z1fv
+ Type: R_ARM_JUMP24
+ Addend: 0
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+Symbols:
+ Global:
+ - Name: _Z1fv
+ Type: STT_FUNC
+ Section: .text
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x000000000000001C
+...
diff --git a/test/elf/ARM/rel-arm-mov.test b/test/elf/ARM/rel-arm-mov.test
new file mode 100644
index 000000000000..e50aea4bb206
--- /dev/null
+++ b/test/elf/ARM/rel-arm-mov.test
@@ -0,0 +1,64 @@
+# Check handling of R_ARM_MOVW_ABS_NC and R_ARM_MOVT_ABS relocation pair.
+# RUN: yaml2obj -format=elf %s > %t-o.o
+# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \
+# RUN: --noinhibit-exec %t-o.o -o %t
+# RUN: llvm-objdump -s -t %t | FileCheck %s
+
+# CHECK: Contents of section .text:
+# CHECK: 400074 04b02de5 00b08de2 003001e3 403040e3
+# addrL = 0x1000 ^^
+# addrH = 0x40 ^^
+# addrH addrL _ZL5data1 addr
+# (0x40 << 16) + 0x1000 = 0x401000
+# CHECK: SYMBOL TABLE:
+# CHECK: 00401000 l .bss 00000004 _ZL5data1
+# CHECK: 00400074 g F .text {{[0-9a-f]+}} main
+
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_ARM
+ Flags: [ EF_ARM_EABI_VER5 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: 04B02DE500B08DE2003000E3003040E30A20A0E3002083E50030A0E30300A0E100D04BE204B09DE41EFF2FE1
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: .text
+ Relocations:
+ - Offset: 0x0000000000000008
+ Symbol: _ZL5data1
+ Type: R_ARM_MOVW_ABS_NC
+ Addend: 0
+ - Offset: 0x000000000000000C
+ Symbol: _ZL5data1
+ Type: R_ARM_MOVT_ABS
+ Addend: 0
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: 411C0000
+Symbols:
+ Local:
+ - Name: _ZL5data1
+ Type: STT_OBJECT
+ Section: .bss
+ Size: 0x0000000000000004
+ Global:
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+...
diff --git a/test/elf/ARM/rel-arm-prel31.test b/test/elf/ARM/rel-arm-prel31.test
new file mode 100644
index 000000000000..1effc4eceb0e
--- /dev/null
+++ b/test/elf/ARM/rel-arm-prel31.test
@@ -0,0 +1,47 @@
+# Check handling of R_ARM_PREL31 relocation.
+# RUN: yaml2obj -format=elf %s > %t-o.o
+# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \
+# RUN: --noinhibit-exec %t-o.o -o %t
+# RUN: llvm-objdump -s -t %t | FileCheck %s
+
+# CHECK: Contents of section .ARM.extab:
+# CHECK: 4000a4 b1fffe7f
+# CHECK: SYMBOL TABLE:
+# CHECK: 00400054 g F .text {{[0-9a-f]+}} __gxx_personality_v0
+
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_ARM
+ Flags: [ EF_ARM_EABI_VER5 ]
+Sections:
+ - Name: .ARM.extab
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC ]
+ AddressAlign: 0x4
+ Content: 0000FF7F84019701B0B0B008FFFF01080E2432003A040000
+ - Name: .rel.ARM.extab
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x4
+ Info: .ARM.extab
+ Relocations:
+ - Offset: 0
+ Symbol: __gxx_personality_v0
+ Type: R_ARM_PREL31
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x4
+ Content: 80B400AF00231846BD465DF8047B704780B582B000AF3B1D1846FFF7FEFFFFF7FEFFFFF7FEFF0420FFF7FEFF0346184601230360002240F20001C0F20001FFF7FEFF3B1D1846FFF7FEFFFFF7FEFF00BF
+Symbols:
+ Local:
+ Global:
+ - Name: __gxx_personality_v0
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x1
+...
+
diff --git a/test/elf/ARM/rel-arm-thm-interwork.test b/test/elf/ARM/rel-arm-thm-interwork.test
new file mode 100644
index 000000000000..8ee9186b48db
--- /dev/null
+++ b/test/elf/ARM/rel-arm-thm-interwork.test
@@ -0,0 +1,123 @@
+# Check ARM <=> Thumb interwork.
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-arm.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-thm.o
+# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \
+# RUN: --noinhibit-exec %t-arm.o %t-thm.o -o %t
+
+# Check R_ARM_CALL veneer to call Thumb code
+# RUN: llvm-objdump -s -t %t | FileCheck -check-prefix=ARM-CALL %s
+
+# ARM-CALL: Contents of section .text:
+# ARM-CALL: 400074 00482de9 04b08de2 000000fa 0088bde8
+# offset = 0x0 ^^
+# call site offset PC(arm) _Z2f2v addr
+# 0x40007C + 0x0 + 0x8 = 0x400084
+# ARM-CALL: SYMBOL TABLE:
+# ARM-CALL: 00400074 g F .text {{[0-9a-f]+}} _Z1fv
+# ARM-CALL: 00400084 g F .text {{[0-9a-f]+}} _Z2f2v
+# ARM-CALL: 00400090 g F .text {{[0-9a-f]+}} main
+
+# Check R_ARM_THM_CALL veneer to call ARM code
+# RUN: llvm-objdump -s -t %t | FileCheck -check-prefix=THM-CALL %s
+
+# THM-CALL: Contents of section .text:
+# THM-CALL: 400094 00bffff7 eeef0023 184680bd
+# offset = -0x24 ^^
+# call site aligned = Align(0x400096, 4) = 0x400094
+# call site aligned offset PC(thm) _Z1fv addr
+# 0x400094 + (-0x24) + 0x4 = 0x400074
+# THM-CALL: SYMBOL TABLE:
+# THM-CALL: 00400074 g F .text {{[0-9a-f]+}} _Z1fv
+# THM-CALL: 00400084 g F .text {{[0-9a-f]+}} _Z2f2v
+# THM-CALL: 00400090 g F .text {{[0-9a-f]+}} main
+
+# arm.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_ARM
+ Flags: [ EF_ARM_EABI_VER5 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: 00482DE904B08DE2FEFFFFEB0088BDE8
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: .text
+ Relocations:
+ - Offset: 0x0000000000000008
+ Symbol: _Z2f2v
+ Type: R_ARM_CALL
+ Addend: 0
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+Symbols:
+ Global:
+ - Name: _Z1fv
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x0000000000000010
+ - Name: _Z2f2v
+
+# thm.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_ARM
+ Flags: [ EF_ARM_EABI_VER5 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: 80B400AFBD465DF8047B704780B500AF00BFFFF7FEFF0023184680BD
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: .text
+ Relocations:
+ - Offset: 0x0000000000000012
+ Symbol: _Z1fv
+ Type: R_ARM_THM_CALL
+ Addend: 0
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+Symbols:
+ Global:
+ - Name: _Z2f2v
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000001
+ Size: 0x000000000000000C
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x000000000000000D
+ Size: 0x0000000000000010
+ - Name: _Z1fv
+...
diff --git a/test/elf/ARM/rel-rel32.test b/test/elf/ARM/rel-rel32.test
new file mode 100644
index 000000000000..47779ac918e3
--- /dev/null
+++ b/test/elf/ARM/rel-rel32.test
@@ -0,0 +1,57 @@
+# Check handling of R_ARM_REL32 relocation.
+# RUN: yaml2obj -format=elf %s > %t-o.o
+# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \
+# RUN: --noinhibit-exec %t-o.o -o %t
+# RUN: llvm-objdump -s -t %t | FileCheck %s
+
+# CHECK: Contents of section .text:
+# CHECK-NEXT: 400074 {{[0-9a-f]+}} 880fff00
+# CHECK: SYMBOL TABLE:
+# CHECK: 00400074 g F .text {{[0-9a-f]+}} main
+# CHECK: 00401000 g .bss {{[0-9a-f]+}} _myref
+
+---
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_ARM
+ Flags: [ EF_ARM_EABI_VER5 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: 80B400AF0000FF0000231846BD465DF8047B7047
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: .text
+ Relocations:
+ - Offset: 0x0000000000000004
+ Symbol: _myref
+ Type: R_ARM_REL32
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+Symbols:
+ Global:
+ - Name: _myref
+ Type: STT_OBJECT
+ Section: .bss
+ Size: 0x0000000000000004
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000001
+ Size: 0x0000000000000014
+...
diff --git a/test/elf/ARM/rel-thm-call.test b/test/elf/ARM/rel-thm-call.test
new file mode 100644
index 000000000000..b9bf8cefc0b8
--- /dev/null
+++ b/test/elf/ARM/rel-thm-call.test
@@ -0,0 +1,61 @@
+# Check handling of R_ARM_THM_CALL relocation.
+# RUN: yaml2obj -format=elf %s > %t-o.o
+# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \
+# RUN: --noinhibit-exec %t-o.o -o %t
+# RUN: llvm-objdump -s -t %t | FileCheck %s
+
+# CHECK: Contents of section .text:
+# CHECK: 400084 fff7f6ff 00231846 80bd00bf
+# ^^ offset = -0x14
+# call site offset PC(thm) _Z1fv addr
+# 0x400084 + (-0x14) + 0x4 = 0x400074
+# CHECK: SYMBOL TABLE:
+# CHECK: 00400074 g F .text {{[0-9a-f]+}} _Z1fv
+# CHECK: 00400080 g F .text {{[0-9a-f]+}} main
+
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_ARM
+ Flags: [ EF_ARM_EABI_VER5 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: 80B400AFBD465DF8047B704780B500AFFFF7FEFF0023184680BD00BF
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: .text
+ Relocations:
+ - Offset: 0x0000000000000010
+ Symbol: _Z1fv
+ Type: R_ARM_THM_CALL
+ Addend: 0
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+Symbols:
+ Global:
+ - Name: _Z1fv
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000001
+ Size: 0x000000000000000C
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x000000000000000D
+ Size: 0x000000000000000E
+...
diff --git a/test/elf/ARM/rel-thm-jump11.test b/test/elf/ARM/rel-thm-jump11.test
new file mode 100644
index 000000000000..4998c2b96c97
--- /dev/null
+++ b/test/elf/ARM/rel-thm-jump11.test
@@ -0,0 +1,141 @@
+# Check handling of R_ARM_THM_JUMP11 relocation.
+# RUN: yaml2obj -format=elf %s > %t-o.o
+# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \
+# RUN: --noinhibit-exec %t-o.o -o %t
+# RUN: llvm-objdump -s -t %t | FileCheck %s
+
+# CHECK: Contents of section .text:
+# CHECK: 4001a4 0021c7e7
+# CHECK: SYMBOL TABLE:
+# CHECK: 00400138 g F .text 00000060 __gnu_h2f_internal
+# CHECK: 004001a4 g F .text 00000004 __gnu_h2f_alternative
+
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_ARM
+ Flags: [ EF_ARM_EABI_VER5 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: 70B4020CC0F3C754FF2CC0F3160302F4004080B241D0002C08BF002B3BD0A4F17F0543F4000315F10E0FA8BF41F6FF7209DA15F1190FA3BFA4F166066FF07F42F2406FF07F4212EA03060CD001325208964208BF03EA42021344B3F1807F24BF5B08A4F17E0501B30F2D26DC15F1180F11DB15F10E0FB5BF4FF6F2710E35CFF6FF71AD02B7BF491BAAB2CB40002202EB5333034398B270BC70470029FBD040EA533370BC43F4FC407047102DDEDD6FEAD0336FEAC33398B2EDE740F4F84398B2E9E700BFC0F3842310B4A3F11F040029B4FA84F400F400424FEA541408BF0024C0F309002146140481B943B14203703302EBC35343EA04005DF8044B704760B1B0FA80F3153B98405B42EFE744EA40305DF8044B40F0FF40704720465DF8044B704700BF01216BE70121FEE7002167E70021FEE7
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: .text
+ Relocations:
+ - Offset: 0x000000000000012A
+ Symbol: __gnu_h2f_internal
+ Type: R_ARM_THM_JUMP11
+ - Offset: 0x0000000000000132
+ Symbol: __gnu_h2f_internal
+ Type: R_ARM_THM_JUMP11
+ - Name: .text.startup
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: 0020FFF7FEBF00BF
+ - Name: .rel.text.startup
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: .text.startup
+ Relocations:
+ - Offset: 0x0000000000000002
+ Symbol: __gnu_h2f_alternative
+ Type: R_ARM_THM_JUMP24
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .comment
+ Type: SHT_PROGBITS
+ Flags: [ SHF_MERGE, SHF_STRINGS ]
+ AddressAlign: 0x0000000000000001
+ Content: 004743433A202863726F7373746F6F6C2D4E47206C696E61726F2D312E31332E312D342E392D323031342E3039202D204C696E61726F2047434320342E392D323031342E30392920342E392E32203230313430393034202870726572656C656173652900
+ - Name: .note.GNU-stack
+ Type: SHT_PROGBITS
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .ARM.attributes
+ Type: SHT_ARM_ATTRIBUTES
+ AddressAlign: 0x0000000000000001
+ Content: 4134000000616561626900012A00000005372D4100060A0741080109020A041204140115011703180119011A021B031C011E022201
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .text.startup
+ Type: STT_SECTION
+ Section: .text.startup
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .comment
+ Type: STT_SECTION
+ Section: .comment
+ - Name: .note.GNU-stack
+ Type: STT_SECTION
+ Section: .note.GNU-stack
+ - Name: .ARM.attributes
+ Type: STT_SECTION
+ Section: .ARM.attributes
+ - Name: '$t'
+ Section: .text
+ - Name: __gnu_f2h_internal
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000001
+ Size: 0x00000000000000C2
+ Global:
+ - Name: __gnu_f2h_alternative
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x000000000000012D
+ Size: 0x0000000000000004
+ Visibility: STV_HIDDEN
+ - Name: __gnu_h2f_alternative
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000131
+ Size: 0x0000000000000004
+ Visibility: STV_HIDDEN
+ - Name: __gnu_h2f_ieee
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000129
+ Size: 0x0000000000000004
+ Visibility: STV_HIDDEN
+ - Name: main
+ Type: STT_FUNC
+ Section: .text.startup
+ Value: 0x0000000000000001
+ Size: 0x0000000000000006
+ - Name: __gnu_f2h_ieee
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000125
+ Size: 0x0000000000000004
+ Visibility: STV_HIDDEN
+ - Name: __gnu_h2f_internal
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x00000000000000C5
+ Size: 0x000000000000005E
+ Visibility: STV_HIDDEN
+...
diff --git a/test/elf/ARM/rel-thm-jump24-veneer.test b/test/elf/ARM/rel-thm-jump24-veneer.test
new file mode 100644
index 000000000000..fffce44ca477
--- /dev/null
+++ b/test/elf/ARM/rel-thm-jump24-veneer.test
@@ -0,0 +1,100 @@
+# Check veneer generation for R_ARM_THM_JUMP24 relocation (B instruction call).
+
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-arm.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-thm.o
+# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \
+# RUN: --noinhibit-exec %t-arm.o %t-thm.o -o %t
+
+# RUN: llvm-objdump -s -t %t | FileCheck -check-prefix=B-VENEER %s
+# RUN: llvm-objdump -s -t %t | FileCheck -check-prefix=B-ADDR %s
+
+# B-VENEER: Contents of section .text:
+# B-VENEER: 400074 {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} 00f000b8
+# Call from main:
+# offset = 0x0 ^^
+# call site offset PC(thm) ___Z1fv_from_thumb addr
+# 0x400080 + 0x0 + 0x4 = 0x400084
+#
+# Code of the veneer:
+# B-VENEER: 400084 78470000 f9ffffea
+# offset = -0x1C ^^
+# call site offset PC(arm) _Z1fv
+# 0x400088 + (-0x1C) + 0x8 = 0x400074
+#
+# B-ADDR: SYMBOL TABLE:
+# B-ADDR: 00400084 l F .text {{[0-9a-f]+}} ___Z1fv_from_thumb
+# B-ADDR: 00400074 g F .text {{[0-9a-f]+}} _Z1fv
+# B-ADDR: 00400080 g F .text {{[0-9a-f]+}} main
+
+# arm.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_ARM
+ Flags: [ EF_ARM_EABI_VER5 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: 0030A0E30300A0E11EFF2FE1
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+Symbols:
+ Global:
+ - Name: _Z1fv
+ Type: STT_FUNC
+ Section: .text
+
+# thm.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_ARM
+ Flags: [ EF_ARM_EABI_VER5 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: FFF7FEBF
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: .text
+ Relocations:
+ - Offset: 0x0000000000000000
+ Symbol: _Z1fv
+ Type: R_ARM_THM_JUMP24
+ Addend: 0
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+Symbols:
+ Global:
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000001
+ - Name: _Z1fv
+...
diff --git a/test/elf/ARM/rel-thm-jump24.test b/test/elf/ARM/rel-thm-jump24.test
new file mode 100644
index 000000000000..6c9b63447c9d
--- /dev/null
+++ b/test/elf/ARM/rel-thm-jump24.test
@@ -0,0 +1,59 @@
+# Check handling of R_ARM_THM_JUMP24 relocation.
+# RUN: yaml2obj -format=elf %s > %t-o.o
+# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \
+# RUN: --noinhibit-exec %t-o.o -o %t
+# RUN: llvm-objdump -s -t %t | FileCheck %s
+
+# CHECK: Contents of section .text:
+# CHECK: 400084 80b500af fff7f4bf 03461846 80bd00bf
+# ^^ offset = -0x18
+# call site offset PC(thm) _Z1fv addr
+# 0x400088 + (-0x18) + 0x4 = 0x400074
+# CHECK: SYMBOL TABLE:
+# CHECK: 00400074 g F .text {{[0-9a-f]+}} _Z1fv
+# CHECK: 00400084 g F .text {{[0-9a-f]+}} main
+
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_ARM
+ Flags: [ EF_ARM_EABI_VER5 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: 80B400AF00231846BD465DF8047B704780B500AFFFF7FEBF0346184680BD00BF
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: .text
+ Relocations:
+ - Offset: 0x0000000000000014
+ Symbol: _Z1fv
+ Type: R_ARM_THM_JUMP24
+ Addend: 0
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+Symbols:
+ Global:
+ - Name: _Z1fv
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000001
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000011
+...
diff --git a/test/elf/ARM/rel-thm-mov.test b/test/elf/ARM/rel-thm-mov.test
new file mode 100644
index 000000000000..25edc4cda4b9
--- /dev/null
+++ b/test/elf/ARM/rel-thm-mov.test
@@ -0,0 +1,70 @@
+# 1. Check handling of R_ARM_THM_MOVW_ABS_NC and R_THM_ARM_MOVT_ABS relocation pair.
+# 2. Check that instructions are not cropped for symbols that address Thumb code.
+# RUN: yaml2obj -format=elf %s > %t-o.o
+# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \
+# RUN: --noinhibit-exec %t-o.o -o %t
+# RUN: llvm-objdump -s -t %t | FileCheck %s
+# RUN: llvm-objdump -s -t %t | FileCheck -check-prefix=INSN-CROP %s
+
+# CHECK: Contents of section .text:
+# CHECK: 400074 {{[0-9a-f]+}} 41f20003 c0f24003 0a221a60
+# addrL = 0x1000 ^^
+# addrH = 0x40 ^^
+# addrH addrL _ZL5data1 addr
+# (0x40 << 16) + 0x1000 = 0x401000
+# CHECK: SYMBOL TABLE:
+# CHECK: 00401000 l .bss 00000004 _ZL5data1
+# CHECK: 00400074 g F .text {{[0-9a-f]+}} main
+#
+# INSN-CROP: Contents of section .text:
+# INSN-CROP: 400074 80b400af
+
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_ARM
+ Flags: [ EF_ARM_EABI_VER5 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: 80B400AF40F20003C0F200030A221A6000231846BD465DF8047B7047
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: .text
+ Relocations:
+ - Offset: 0x0000000000000004
+ Symbol: _ZL5data1
+ Type: R_ARM_THM_MOVW_ABS_NC
+ Addend: 0
+ - Offset: 0x0000000000000008
+ Symbol: _ZL5data1
+ Type: R_ARM_THM_MOVT_ABS
+ Addend: 0
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: 411C0000
+Symbols:
+ Local:
+ - Name: _ZL5data1
+ Type: STT_OBJECT
+ Section: .bss
+ Size: 0x0000000000000004
+ Global:
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000001
+...
diff --git a/test/elf/ARM/rel-tls-ie32.test b/test/elf/ARM/rel-tls-ie32.test
new file mode 100644
index 000000000000..7b65c2f194c7
--- /dev/null
+++ b/test/elf/ARM/rel-tls-ie32.test
@@ -0,0 +1,109 @@
+# Check handling of R_ARM_TLS_IE32 relocation.
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-tls.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-tlsv.o
+# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \
+# RUN: --noinhibit-exec %t-tls.o %t-tlsv.o -o %t
+# RUN: llvm-objdump -s -t %t | FileCheck %s
+
+# CHECK: Contents of section .got:
+# CHECK: 401008 08000000 0c000000
+# tp_off(i) = 0x08 ^^ ^^ tp_off(j) = 0x0c
+# tp_off(i) + sizeof(i) = tp_off(j)
+# 0x08 + 0x04 = 0x0c
+# CHECK: SYMBOL TABLE:
+# CHECK: 00400094 g F .text {{[0-9a-f]+}} main
+# CHECK: 00000000 g .tdata 00000004 i
+# sizeof(i) = 0x04 ^^
+# CHECK: 00000004 g .tdata 00000004 j
+
+# tls.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_ARM
+ Flags: [ EF_ARM_EABI_VER5 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: 80B400AF0C4B7B441B681DEE702FD2580A4B7B441B681DEE701FCB581A44084B7B441B681DEE701FCB585B0013441846BD465DF8047B70472E000000260000001C000000
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: .text
+ Relocations:
+ - Offset: 0x0000000000000038
+ Symbol: i
+ Type: R_ARM_TLS_IE32
+ - Offset: 0x000000000000003C
+ Symbol: i
+ Type: R_ARM_TLS_IE32
+ - Offset: 0x0000000000000040
+ Symbol: j
+ Type: R_ARM_TLS_IE32
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+Symbols:
+ Global:
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000001
+ - Name: i
+ Type: STT_TLS
+ - Name: j
+ Type: STT_TLS
+
+# tlsv.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_ARM
+ Flags: [ EF_ARM_EABI_VER5 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .tdata
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC, SHF_TLS ]
+ AddressAlign: 0x0000000000000004
+ Content: 05000000FBFFFFFF
+Symbols:
+ Global:
+ - Name: i
+ Type: STT_TLS
+ Section: .tdata
+ Size: 0x0000000000000004
+ - Name: j
+ Type: STT_TLS
+ Section: .tdata
+ Value: 0x0000000000000004
+ Size: 0x0000000000000004
+...
diff --git a/test/elf/ARM/rel-tls-le32.test b/test/elf/ARM/rel-tls-le32.test
new file mode 100644
index 000000000000..d0d3d5b6821a
--- /dev/null
+++ b/test/elf/ARM/rel-tls-le32.test
@@ -0,0 +1,61 @@
+# Check handling of R_ARM_TLS_LE32 relocation.
+# RUN: yaml2obj -format=elf %s > %t-o.o
+# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \
+# RUN: --noinhibit-exec %t-o.o -o %t
+# RUN: llvm-objdump -s -t %t | FileCheck %s
+
+# CHECK: Contents of section .text:
+# CHECK: 4000b4 {{[0-9a-f]+}} 08000000
+# tp_off = 0x000008 ^^
+# CHECK: SYMBOL TABLE:
+# CHECK: 00400094 g F .text {{[0-9a-f]+}} main
+# CHECK: 00000000 g .tdata 00000004 i
+
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_ARM
+ Flags: [ EF_ARM_EABI_VER5 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: 04B02DE500B08DE2703F1DEE10209FE5023093E70300A0E100D04BE204B09DE41EFF2FE100000000
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: .text
+ Relocations:
+ - Offset: 0x0000000000000024
+ Symbol: i
+ Type: R_ARM_TLS_LE32
+ Addend: 0
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .tdata
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC, SHF_TLS ]
+ AddressAlign: 0x0000000000000004
+ Content: '05000000'
+Symbols:
+ Global:
+ - Name: i
+ Type: STT_TLS
+ Section: .tdata
+ Size: 0x0000000000000004
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+...
diff --git a/test/elf/ARM/thm-symbols.test b/test/elf/ARM/thm-symbols.test
new file mode 100644
index 000000000000..c91505c98100
--- /dev/null
+++ b/test/elf/ARM/thm-symbols.test
@@ -0,0 +1,52 @@
+# Check that symbols formed from Thumb instructions are valid:
+# 1. Symbol address.
+# 2. Symbol content size.
+# 3. Symbol content.
+
+# RUN: yaml2obj -format=elf %s > %t-t.o
+# RUN: lld -flavor gnu -target arm-linux-gnu \
+# RUN: -Bstatic --noinhibit-exec %t-t.o -o %t-t
+# RUN: llvm-readobj -symbols %t-t | FileCheck -check-prefix=SYM-ADDR %s
+# RUN: llvm-readobj -symbols %t-t | FileCheck -check-prefix=SYM-SIZE %s
+# RUN: llvm-objdump -s -t %t-t | FileCheck -check-prefix=SYM-CONTENT %s
+
+# SYM-ADDR: Name: main (1)
+# SYM-ADDR-NEXT: Value: 0x400075
+
+# SYM-SIZE: Name: main (1)
+# SYM-SIZE-NEXT: Value: 0x{{[0-9a-f]+}}
+# SYM-SIZE-NEXT: Size: 16
+
+# SYM-CONTENT: Contents of section .text:
+# SYM-CONTENT-NEXT: 400074 80b400af 00231846 bd465df8 047b7047 .....#.F.F]..{pG
+
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_ARM
+ Flags: [ EF_ARM_EABI_VER5 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: 80B400AF00231846BD465DF8047B7047
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+Symbols:
+ Global:
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000001
+...
diff --git a/test/elf/ARM/undef-lazy-symbol.test b/test/elf/ARM/undef-lazy-symbol.test
new file mode 100644
index 000000000000..f32549e85be4
--- /dev/null
+++ b/test/elf/ARM/undef-lazy-symbol.test
@@ -0,0 +1,135 @@
+# Check that _GLOBAL_OFFSET_TABLE_ symbol is resolved
+
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-got.o
+# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \
+# RUN: --noinhibit-exec %t-got.o -o %t
+# RUN: llvm-readobj -symbols %t | FileCheck -check-prefix=GOT %s
+
+# GOT: Name: _GLOBAL_OFFSET_TABLE_ (185)
+# GOT-NEXT: Value: {{[0-9]+}}
+# GOT-NEXT: Size: 0
+# GOT-NEXT: Binding: Global (0x1)
+# GOT-NEXT: Type: Object (0x1)
+# GOT-NEXT: Other: 0
+# GOT-NEXT: Section: Absolute (0xFFF1)
+
+# Check that __exidx_start/_end symbols are resolved
+
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-exidx.o
+# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \
+# RUN: --defsym=main=fn --noinhibit-exec %t-exidx.o -o %t
+# RUN: llvm-readobj -symbols %t | FileCheck -check-prefix=EXIDX %s
+
+# EXIDX: Name: __exidx_start (188)
+# EXIDX-NEXT: Value: {{[0-9]+}}
+# EXIDX-NEXT: Size: 0
+# EXIDX-NEXT: Binding: Global (0x1)
+# EXIDX-NEXT: Type: Object (0x1)
+# EXIDX-NEXT: Other: 0
+# EXIDX-NEXT: Section: Absolute (0xFFF1)
+#
+# EXIDX: Name: __exidx_end (202)
+# EXIDX-NEXT: Value: {{[0-9]+}}
+# EXIDX-NEXT: Size: 0
+# EXIDX-NEXT: Binding: Global (0x1)
+# EXIDX-NEXT: Type: Object (0x1)
+# EXIDX-NEXT: Other: 0
+# EXIDX-NEXT: Section: Absolute (0xFFF1)
+
+# Check that all symbols are resolved
+
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-got.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-exidx.o
+# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \
+# RUN: --noinhibit-exec %t-got.o %t-exidx.o -o %t
+# RUN: llvm-readobj -symbols %t | FileCheck -check-prefix=SYMS %s
+
+# SYMS: Name: _GLOBAL_OFFSET_TABLE_ (188)
+# SYMS-NEXT: Value: {{[0-9]+}}
+# SYMS-NEXT: Size: 0
+# SYMS-NEXT: Binding: Global (0x1)
+# SYMS-NEXT: Type: Object (0x1)
+# SYMS-NEXT: Other: 0
+# SYMS-NEXT: Section: Absolute (0xFFF1)
+#
+# SYMS: Name: __exidx_start (210)
+# SYMS-NEXT: Value: {{[0-9]+}}
+# SYMS-NEXT: Size: 0
+# SYMS-NEXT: Binding: Global (0x1)
+# SYMS-NEXT: Type: Object (0x1)
+# SYMS-NEXT: Other: 0
+# SYMS-NEXT: Section: Absolute (0xFFF1)
+#
+# SYMS: Name: __exidx_end (224)
+# SYMS-NEXT: Value: {{[0-9]+}}
+# SYMS-NEXT: Size: 0
+# SYMS-NEXT: Binding: Global (0x1)
+# SYMS-NEXT: Type: Object (0x1)
+# SYMS-NEXT: Other: 0
+# SYMS-NEXT: Section: Absolute (0xFFF1)
+
+# got.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_ARM
+ Flags: [ EF_ARM_EABI_VER5 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: 80B483B000AF40F20003C0F200037B60002318460C37BD465DF8047B704700BF
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+Symbols:
+ Global:
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000001
+ - Name: _GLOBAL_OFFSET_TABLE_
+
+# exidx.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_ARM
+ Flags: [ EF_ARM_EABI_VER5 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: 80B483B000AF40F20003C0F200037B60002318460C37BD465DF8047B704700BF
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+Symbols:
+ Global:
+ - Name: fn
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000001
+ - Name: __exidx_start
+ - Name: __exidx_end
+...
diff --git a/test/elf/Hexagon/Inputs/dynobj-data.c b/test/elf/Hexagon/Inputs/dynobj-data.c
new file mode 100644
index 000000000000..0f4ea9b80526
--- /dev/null
+++ b/test/elf/Hexagon/Inputs/dynobj-data.c
@@ -0,0 +1,3 @@
+int d = 10;
+
+int fn() { return d; }
diff --git a/test/elf/Hexagon/Inputs/dynobj-data.o b/test/elf/Hexagon/Inputs/dynobj-data.o
new file mode 100644
index 000000000000..13d283cd0eff
--- /dev/null
+++ b/test/elf/Hexagon/Inputs/dynobj-data.o
Binary files differ
diff --git a/test/elf/Hexagon/Inputs/dynobj.c b/test/elf/Hexagon/Inputs/dynobj.c
new file mode 100644
index 000000000000..f17fdadd6945
--- /dev/null
+++ b/test/elf/Hexagon/Inputs/dynobj.c
@@ -0,0 +1,26 @@
+extern int shankar;
+static int a;
+static int b;
+int c;
+int fn2() {
+ return 0;
+}
+
+int fn1() {
+ return 0;
+}
+
+int fn() {
+ a = 10;
+ b = 20;
+ c = 10;
+ shankar = 20;
+ return 0;
+}
+
+int fn3() {
+ fn();
+ fn1();
+ fn2();
+ return 0;
+}
diff --git a/test/elf/Hexagon/Inputs/dynobj.o b/test/elf/Hexagon/Inputs/dynobj.o
new file mode 100644
index 000000000000..6c184f2edd60
--- /dev/null
+++ b/test/elf/Hexagon/Inputs/dynobj.o
Binary files differ
diff --git a/test/elf/Hexagon/Inputs/got-plt-order.c b/test/elf/Hexagon/Inputs/got-plt-order.c
new file mode 100644
index 000000000000..621f670ef7c5
--- /dev/null
+++ b/test/elf/Hexagon/Inputs/got-plt-order.c
@@ -0,0 +1,6 @@
+int c = 10;
+int fn() { c = 20; return 0; }
+
+int fn1() {
+ return fn();
+}
diff --git a/test/elf/Hexagon/Inputs/got-plt-order.o b/test/elf/Hexagon/Inputs/got-plt-order.o
new file mode 100644
index 000000000000..e97678b739bd
--- /dev/null
+++ b/test/elf/Hexagon/Inputs/got-plt-order.o
Binary files differ
diff --git a/test/elf/Hexagon/Inputs/libMaxAlignment.a b/test/elf/Hexagon/Inputs/libMaxAlignment.a
new file mode 100644
index 000000000000..cc5461a09ae4
--- /dev/null
+++ b/test/elf/Hexagon/Inputs/libMaxAlignment.a
Binary files differ
diff --git a/test/elf/Hexagon/Inputs/sda-base.o b/test/elf/Hexagon/Inputs/sda-base.o
new file mode 100644
index 000000000000..410a3d47d320
--- /dev/null
+++ b/test/elf/Hexagon/Inputs/sda-base.o
Binary files differ
diff --git a/test/elf/Hexagon/Inputs/sdata1.c b/test/elf/Hexagon/Inputs/sdata1.c
new file mode 100644
index 000000000000..77c2a54c36a1
--- /dev/null
+++ b/test/elf/Hexagon/Inputs/sdata1.c
@@ -0,0 +1,3 @@
+static int a = 0;
+
+int b = 10;
diff --git a/test/elf/Hexagon/Inputs/sdata1.o b/test/elf/Hexagon/Inputs/sdata1.o
new file mode 100644
index 000000000000..bf908fed27e9
--- /dev/null
+++ b/test/elf/Hexagon/Inputs/sdata1.o
Binary files differ
diff --git a/test/elf/Hexagon/Inputs/sdata2.c b/test/elf/Hexagon/Inputs/sdata2.c
new file mode 100644
index 000000000000..96b37271d773
--- /dev/null
+++ b/test/elf/Hexagon/Inputs/sdata2.c
@@ -0,0 +1,6 @@
+int sdata1 = 10;
+int sdata2 = 20;
+int sdata3 = 30;
+
+int sbss1 = 0;
+
diff --git a/test/elf/Hexagon/Inputs/sdata2.o b/test/elf/Hexagon/Inputs/sdata2.o
new file mode 100644
index 000000000000..e4ec810866e5
--- /dev/null
+++ b/test/elf/Hexagon/Inputs/sdata2.o
Binary files differ
diff --git a/test/elf/Hexagon/Inputs/use-shared.hexagon b/test/elf/Hexagon/Inputs/use-shared.hexagon
new file mode 100644
index 000000000000..9e5ffb42d36a
--- /dev/null
+++ b/test/elf/Hexagon/Inputs/use-shared.hexagon
Binary files differ
diff --git a/test/elf/Hexagon/dynlib-data.test b/test/elf/Hexagon/dynlib-data.test
new file mode 100644
index 000000000000..f3260ba4847b
--- /dev/null
+++ b/test/elf/Hexagon/dynlib-data.test
@@ -0,0 +1,9 @@
+RUN: lld -flavor gnu -target hexagon %p/Inputs/dynobj-data.o \
+RUN: -o %t --noinhibit-exec -shared
+RUN: llvm-objdump -s %t > %t1
+RUN: FileCheck -check-prefix=CHECKRELOCS %s < %t1
+
+CHECKRELOCS: Contents of section .text:
+CHECKRELOCS: 00f8 01c09da0 01d89da1 3c400000 18c4496a ........<@....Ij
+CHECKRELOCS: 0108 ff7fff0f 00ff9897 00c08091 38c09d91 ............8...
+CHECKRELOCS: 0118 1ec01e96 ....
diff --git a/test/elf/Hexagon/dynlib-gotoff.test b/test/elf/Hexagon/dynlib-gotoff.test
new file mode 100644
index 000000000000..752d3acd4c08
--- /dev/null
+++ b/test/elf/Hexagon/dynlib-gotoff.test
@@ -0,0 +1,128 @@
+# This tests GOT's and PLT's for dynamic libraries for Hexagon
+RUN: lld -flavor gnu -target hexagon %p/Inputs/dynobj.o \
+RUN: -o %t --output-filetype=yaml -shared --noinhibit-exec
+RUN: FileCheck -check-prefix=CHECKGOTPLT %s < %t
+
+ - name: .PLT0
+CHECKGOTPLT: type: stub
+CHECKGOTPLT: content: [ 00, 40, 00, 00, 1C, C0, 49, 6A, 0E, 42, 9C, E2,
+CHECKGOTPLT: 4F, 40, 9C, 91, 3C, C0, 9C, 91, 0E, 42, 0E, 8C,
+CHECKGOTPLT: 00, C0, 9C, 52 ]
+CHECKGOTPLT: alignment: 2^4
+CHECKGOTPLT: section-name: .plt
+CHECKGOTPLT: references:
+CHECKGOTPLT: - kind: R_HEX_B32_PCREL_X
+CHECKGOTPLT: offset: 0
+ target: __got0
+CHECKGOTPLT: - kind: R_HEX_6_PCREL_X
+CHECKGOTPLT: offset: 4
+ target: __got0
+CHECKGOTPLT: addend: 4
+ - name: __plt_fn
+CHECKGOTPLT: type: stub
+CHECKGOTPLT: content: [ 00, 40, 00, 00, 0E, C0, 49, 6A, 1C, C0, 8E, 91,
+CHECKGOTPLT: 00, C0, 9C, 52 ]
+CHECKGOTPLT: alignment: 2^4
+CHECKGOTPLT: section-name: .plt
+CHECKGOTPLT: references:
+CHECKGOTPLT: - kind: R_HEX_B32_PCREL_X
+CHECKGOTPLT: offset: 0
+ target: __got_fn
+CHECKGOTPLT: - kind: R_HEX_6_PCREL_X
+CHECKGOTPLT: offset: 4
+ target: __got_fn
+CHECKGOTPLT: addend: 4
+ - name: __plt_fn1
+CHECKGOTPLT: type: stub
+CHECKGOTPLT: content: [ 00, 40, 00, 00, 0E, C0, 49, 6A, 1C, C0, 8E, 91,
+CHECKGOTPLT: 00, C0, 9C, 52 ]
+CHECKGOTPLT: alignment: 2^4
+CHECKGOTPLT: section-name: .plt
+CHECKGOTPLT: references:
+CHECKGOTPLT: - kind: R_HEX_B32_PCREL_X
+CHECKGOTPLT: offset: 0
+ target: __got_fn1
+CHECKGOTPLT: - kind: R_HEX_6_PCREL_X
+CHECKGOTPLT: offset: 4
+ target: __got_fn1
+CHECKGOTPLT: addend: 4
+ - name: __plt_fn2
+CHECKGOTPLT: type: stub
+CHECKGOTPLT: content: [ 00, 40, 00, 00, 0E, C0, 49, 6A, 1C, C0, 8E, 91,
+CHECKGOTPLT: 00, C0, 9C, 52 ]
+CHECKGOTPLT: alignment: 2^4
+CHECKGOTPLT: section-name: .plt
+CHECKGOTPLT: references:
+CHECKGOTPLT: - kind: R_HEX_B32_PCREL_X
+CHECKGOTPLT: offset: 0
+ target: __got_fn2
+CHECKGOTPLT: - kind: R_HEX_6_PCREL_X
+CHECKGOTPLT: offset: 4
+ target: __got_fn2
+CHECKGOTPLT: addend: 4
+ - name: __got0
+CHECKGOTPLT: type: got
+CHECKGOTPLT: content: [ 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
+CHECKGOTPLT: 00, 00, 00, 00 ]
+CHECKGOTPLT: alignment: 2^3
+CHECKGOTPLT: section-name: .got.plt
+CHECKGOTPLT: permissions: rw-
+ - name: __got_c
+CHECKGOTPLT: type: got
+CHECKGOTPLT: content: [ 00, 00, 00, 00 ]
+CHECKGOTPLT: alignment: 2^2
+CHECKGOTPLT: section-name: .got
+CHECKGOTPLT: permissions: rw-
+CHECKGOTPLT: references:
+CHECKGOTPLT: - kind: R_HEX_GLOB_DAT
+CHECKGOTPLT: offset: 0
+CHECKGOTPLT: target: c
+ - name: __got_shankar
+CHECKGOTPLT: type: got
+CHECKGOTPLT: content: [ 00, 00, 00, 00 ]
+CHECKGOTPLT: alignment: 2^2
+CHECKGOTPLT: section-name: .got
+CHECKGOTPLT: permissions: rw-
+CHECKGOTPLT: references:
+CHECKGOTPLT: - kind: R_HEX_GLOB_DAT
+CHECKGOTPLT: offset: 0
+CHECKGOTPLT: target: shankar
+ - name: __got_fn
+CHECKGOTPLT: type: got
+CHECKGOTPLT: content: [ 00, 00, 00, 00 ]
+CHECKGOTPLT: alignment: 2^2
+CHECKGOTPLT: section-name: .got.plt
+CHECKGOTPLT: permissions: rw-
+CHECKGOTPLT: references:
+CHECKGOTPLT: - kind: R_HEX_JMP_SLOT
+CHECKGOTPLT: offset: 0
+CHECKGOTPLT: target: fn
+CHECKGOTPLT: - kind: R_HEX_32
+CHECKGOTPLT: offset: 0
+ target: .PLT0
+ - name: __got_fn1
+CHECKGOTPLT: type: got
+CHECKGOTPLT: content: [ 00, 00, 00, 00 ]
+CHECKGOTPLT: alignment: 2^2
+CHECKGOTPLT: section-name: .got.plt
+CHECKGOTPLT: permissions: rw-
+CHECKGOTPLT: references:
+CHECKGOTPLT: - kind: R_HEX_JMP_SLOT
+CHECKGOTPLT: offset: 0
+CHECKGOTPLT: target: fn1
+CHECKGOTPLT: - kind: R_HEX_32
+CHECKGOTPLT: offset: 0
+ target: .PLT0
+ - name: __got_fn2
+CHECKGOTPLT: type: got
+CHECKGOTPLT: content: [ 00, 00, 00, 00 ]
+CHECKGOTPLT: alignment: 2^2
+CHECKGOTPLT: section-name: .got.plt
+CHECKGOTPLT: permissions: rw-
+CHECKGOTPLT: references:
+CHECKGOTPLT: - kind: R_HEX_JMP_SLOT
+CHECKGOTPLT: offset: 0
+CHECKGOTPLT: target: fn2
+CHECKGOTPLT: - kind: R_HEX_32
+CHECKGOTPLT: offset: 0
+ target: .PLT0
diff --git a/test/elf/Hexagon/dynlib-hash.test b/test/elf/Hexagon/dynlib-hash.test
new file mode 100644
index 000000000000..f93176492348
--- /dev/null
+++ b/test/elf/Hexagon/dynlib-hash.test
@@ -0,0 +1,9 @@
+RUN: lld -flavor gnu -target hexagon %p/Inputs/dynobj.o \
+RUN: -o %t --noinhibit-exec -shared
+RUN: llvm-objdump -s %t > %t1
+RUN: FileCheck -check-prefix=CHECKHASH %s < %t1
+
+CHECKHASH: Contents of section .hash:
+CHECKHASH: 0094 03000000 07000000 06000000 01000000
+CHECKHASH: 00a4 04000000 00000000 00000000 00000000
+CHECKHASH: 00b4 00000000 03000000 02000000 05000000
diff --git a/test/elf/Hexagon/dynlib-rela.test b/test/elf/Hexagon/dynlib-rela.test
new file mode 100644
index 000000000000..81617349e2f7
--- /dev/null
+++ b/test/elf/Hexagon/dynlib-rela.test
@@ -0,0 +1,9 @@
+# Tests that the relocation sections have the right alignment.
+RUN: lld -flavor gnu -target hexagon %p/Inputs/use-shared.hexagon -shared -o %t1
+RUN: llvm-readobj -sections %t1 > %t2
+RUN: FileCheck -check-prefix=SECTIONS %s < %t2
+
+SECTIONS: Section {
+SECTIONS: Name: .rela.plt (23)
+SECTIONS: AddressAlignment: 4
+SECTIONS: }
diff --git a/test/elf/Hexagon/dynlib-syms.test b/test/elf/Hexagon/dynlib-syms.test
new file mode 100644
index 000000000000..e649230d9e90
--- /dev/null
+++ b/test/elf/Hexagon/dynlib-syms.test
@@ -0,0 +1,7 @@
+RUN: lld -flavor gnu -target hexagon %p/Inputs/dynobj.o \
+RUN: -o %t --noinhibit-exec -shared
+RUN: llvm-nm -n -M %t > %t1
+RUN: FileCheck -check-prefix=CHECKSYMS %s < %t1
+
+CHECKSYMS: 0000025c A _DYNAMIC
+CHECKSYMS: 00001008 A _GLOBAL_OFFSET_TABLE_
diff --git a/test/elf/Hexagon/dynlib.test b/test/elf/Hexagon/dynlib.test
new file mode 100644
index 000000000000..c5bf23fdf229
--- /dev/null
+++ b/test/elf/Hexagon/dynlib.test
@@ -0,0 +1,36 @@
+RUN: lld -flavor gnu -target hexagon %p/Inputs/use-shared.hexagon -shared -o %t1
+RUN: llvm-readobj -dyn-symbols %t1 > %t2
+RUN: FileCheck -check-prefix=DYNSYMS %s < %t2
+RUN: llvm-readobj -program-headers %t1 | FileCheck %s
+
+DYNSYMS: DynamicSymbols [
+DYNSYMS: Symbol {
+DYNSYMS: Name: fn2
+DYNSYMS-NEXT: Value:
+DYNSYMS-NEXT: Size:
+DYNSYMS-NEXT: Binding: Global
+DYNSYMS-NEXT: Type: Function
+DYNSYMS-NEXT: Other:
+DYNSYMS-NEXT: Section: .text
+DYNSYMS: }
+DYNSYMS: Symbol {
+DYNSYMS: Name: fn1
+DYNSYMS-NEXT: Value:
+DYNSYMS-NEXT: Size:
+DYNSYMS-NEXT: Binding: Global
+DYNSYMS-NEXT: Type: Function
+DYNSYMS-NEXT: Other:
+DYNSYMS-NEXT: Section: .text
+DYNSYMS: }
+DYNSYMS: Symbol {
+DYNSYMS: Name: fn3
+DYNSYMS-NEXT: Value:
+DYNSYMS-NEXT: Size:
+DYNSYMS-NEXT: Binding: Global
+DYNSYMS-NEXT: Type: Function
+DYNSYMS-NEXT: Other:
+DYNSYMS-NEXT: Section: .text
+DYNSYMS-NEXT: }
+DYNSYMS-NEXT: ]
+
+CHECK-NOT: PT_PHDR
diff --git a/test/elf/Hexagon/hexagon-got-plt-order.test b/test/elf/Hexagon/hexagon-got-plt-order.test
new file mode 100644
index 000000000000..7600ebe59fc5
--- /dev/null
+++ b/test/elf/Hexagon/hexagon-got-plt-order.test
@@ -0,0 +1,5 @@
+RUN: lld -flavor gnu -target hexagon %p/Inputs/got-plt-order.o -o %t -shared
+RUN: llvm-objdump -section-headers %t | FileCheck %s
+
+CHECK: .got
+CHECK-NEXT: .got.plt
diff --git a/test/elf/Hexagon/hexagon-plt-setup.test b/test/elf/Hexagon/hexagon-plt-setup.test
new file mode 100644
index 000000000000..15c4e22ed9c5
--- /dev/null
+++ b/test/elf/Hexagon/hexagon-plt-setup.test
@@ -0,0 +1,12 @@
+RUN: lld -flavor gnu -target hexagon %p/Inputs/use-shared.hexagon \
+RUN: --output-filetype=yaml --noinhibit-exec -o %t2
+RUN: FileCheck %s < %t2
+
+CHECK: - name: fn3
+CHECK: references:
+CHECK: - kind: R_HEX_B22_PCREL
+CHECK: offset: 4
+ target:
+CHECK: - kind: R_HEX_B22_PCREL
+CHECK: offset: 8
+ target:
diff --git a/test/elf/Hexagon/maxalignment.test b/test/elf/Hexagon/maxalignment.test
new file mode 100644
index 000000000000..cac1c200734f
--- /dev/null
+++ b/test/elf/Hexagon/maxalignment.test
@@ -0,0 +1,8 @@
+# This tests that we lld is able to get the contentType properly for archives
+# when they intermittently get loaded at an address whose alignment is 2
+
+RUN: lld -flavor gnu -target hexagon --whole-archive %p/Inputs/libMaxAlignment.a \
+RUN: --noinhibit-exec -static -o %t
+RUN: llvm-nm %t | FileCheck %s
+
+CHECK: {{[0-9a-f]+}} D a
diff --git a/test/elf/Hexagon/rela-order.test b/test/elf/Hexagon/rela-order.test
new file mode 100644
index 000000000000..925a82c29290
--- /dev/null
+++ b/test/elf/Hexagon/rela-order.test
@@ -0,0 +1,9 @@
+RUN: lld -flavor gnu -target hexagon %p/Inputs/dynobj.o -shared \
+RUN: --noinhibit-exec -o %t
+RUN: llvm-objdump -section-headers %t | FileCheck %s
+
+CHECK: .dynsym
+CHECK-NEXT: .dynstr
+CHECK-NEXT: .rela.dyn
+CHECK-NEXT: .rela.plt
+CHECK-NEXT: .plt
diff --git a/test/elf/Hexagon/sda-base.test b/test/elf/Hexagon/sda-base.test
new file mode 100644
index 000000000000..0bab92abf685
--- /dev/null
+++ b/test/elf/Hexagon/sda-base.test
@@ -0,0 +1,4 @@
+RUN: lld -flavor gnu -target hexagon %p/Inputs/sda-base.o -o %t1 --noinhibit-exec
+RUN: llvm-nm -n %t1 | FileCheck %s -check-prefix=sdabase
+
+sdabase: 00002000 A _SDA_BASE_
diff --git a/test/elf/Hexagon/zerofillquick-sdata.test b/test/elf/Hexagon/zerofillquick-sdata.test
new file mode 100644
index 000000000000..5488e19f5c44
--- /dev/null
+++ b/test/elf/Hexagon/zerofillquick-sdata.test
@@ -0,0 +1,18 @@
+# This tests that a typeZeroFillFast atom is associated with a section that has
+# the correct memory size.
+
+RUN: lld -flavor gnu -target hexagon %p/Inputs/sdata1.o %p/Inputs/sdata2.o \
+RUN: -o %t --noinhibit-exec -static
+RUN: llvm-readobj -sections %t | FileCheck -check-prefix=CHECKSECTIONSANDSIZE %s
+
+CHECKSECTIONSANDSIZE: Section {
+CHECKSECTIONSANDSIZE: Name: .sdata (13)
+CHECKSECTIONSANDSIZE: Address: 0x1000
+CHECKSECTIONSANDSIZE: Offset: 0x1000
+CHECKSECTIONSANDSIZE: Size: 24
+CHECKSECTIONSANDSIZE: }
+CHECKSECTIONSANDSIZE: Section {
+CHECKSECTIONSANDSIZE: Name: .bss (20)
+CHECKSECTIONSANDSIZE: Address: 0x1018
+CHECKSECTIONSANDSIZE: Offset: 0x1018
+CHECKSECTIONSANDSIZE: }
diff --git a/test/elf/Inputs/abs-test.i386 b/test/elf/Inputs/abs-test.i386
new file mode 100644
index 000000000000..8556c24da551
--- /dev/null
+++ b/test/elf/Inputs/abs-test.i386
Binary files differ
diff --git a/test/elf/Inputs/bar.o.x86-64 b/test/elf/Inputs/bar.o.x86-64
new file mode 100644
index 000000000000..467485f0bb96
--- /dev/null
+++ b/test/elf/Inputs/bar.o.x86-64
Binary files differ
diff --git a/test/elf/Inputs/branch-test.hexagon b/test/elf/Inputs/branch-test.hexagon
new file mode 100644
index 000000000000..1ffb47228e32
--- /dev/null
+++ b/test/elf/Inputs/branch-test.hexagon
Binary files differ
diff --git a/test/elf/Inputs/branch-test.ppc b/test/elf/Inputs/branch-test.ppc
new file mode 100644
index 000000000000..4698941e7503
--- /dev/null
+++ b/test/elf/Inputs/branch-test.ppc
Binary files differ
diff --git a/test/elf/Inputs/consecutive-weak-defs.o.yaml b/test/elf/Inputs/consecutive-weak-defs.o.yaml
new file mode 100644
index 000000000000..144c2426bae1
--- /dev/null
+++ b/test/elf/Inputs/consecutive-weak-defs.o.yaml
@@ -0,0 +1,66 @@
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: 554889E5E8000000005DC3554889E5B8640000005DC3
+ - Name: .rela.text
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .text
+ Relocations:
+ - Offset: 0x0000000000000005
+ Symbol: my_weak_func
+ Type: R_X86_64_PC32
+ Addend: -4
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ Global:
+ - Name: my_func
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x000000000000000B
+ Weak:
+ - Name: my_weak_func
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x000000000000000B
+ Size: 0x000000000000000B
+ - Name: my_weak_func2
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x000000000000000B
+ Size: 0x000000000000000B
+ - Name: my_weak_func3
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x000000000000000B
+ Size: 0x000000000000000B
+...
diff --git a/test/elf/Inputs/constants-merge.x86-64 b/test/elf/Inputs/constants-merge.x86-64
new file mode 100644
index 000000000000..0087eb8f8cb5
--- /dev/null
+++ b/test/elf/Inputs/constants-merge.x86-64
Binary files differ
diff --git a/test/elf/Inputs/constdata.x86-64 b/test/elf/Inputs/constdata.x86-64
new file mode 100644
index 000000000000..d877a5535357
--- /dev/null
+++ b/test/elf/Inputs/constdata.x86-64
Binary files differ
diff --git a/test/elf/Inputs/foo.o.x86-64 b/test/elf/Inputs/foo.o.x86-64
new file mode 100644
index 000000000000..72a89eefa8ed
--- /dev/null
+++ b/test/elf/Inputs/foo.o.x86-64
Binary files differ
diff --git a/test/elf/Inputs/globalconst.c b/test/elf/Inputs/globalconst.c
new file mode 100644
index 000000000000..08395a88e7ca
--- /dev/null
+++ b/test/elf/Inputs/globalconst.c
@@ -0,0 +1,2 @@
+/* compile the code with -fmerge-all-constants */
+const char mystr[] = "foobar";
diff --git a/test/elf/Inputs/globalconst.o.x86-64 b/test/elf/Inputs/globalconst.o.x86-64
new file mode 100644
index 000000000000..d8e266e76334
--- /dev/null
+++ b/test/elf/Inputs/globalconst.o.x86-64
Binary files differ
diff --git a/test/elf/Inputs/gotpcrel.S b/test/elf/Inputs/gotpcrel.S
new file mode 100644
index 000000000000..300675f59612
--- /dev/null
+++ b/test/elf/Inputs/gotpcrel.S
@@ -0,0 +1,11 @@
+ .text
+ .globl main
+ .align 16, 0x90
+ .type main,@function
+main: # @main
+ movq blah@GOTPCREL(%rip), %rax
+ movq main@GOTPCREL(%rip), %rax
+ ret
+
+ .weak blah
+ .type blah,@function
diff --git a/test/elf/Inputs/gotpcrel.x86-64 b/test/elf/Inputs/gotpcrel.x86-64
new file mode 100644
index 000000000000..f9c61d0edf15
--- /dev/null
+++ b/test/elf/Inputs/gotpcrel.x86-64
Binary files differ
diff --git a/test/elf/Inputs/group-cmd-search-1.ls b/test/elf/Inputs/group-cmd-search-1.ls
new file mode 100644
index 000000000000..965369309a20
--- /dev/null
+++ b/test/elf/Inputs/group-cmd-search-1.ls
@@ -0,0 +1 @@
+GROUP ( shared.so-x86-64 )
diff --git a/test/elf/Inputs/group-cmd-search-2.ls b/test/elf/Inputs/group-cmd-search-2.ls
new file mode 100644
index 000000000000..f1eee6a35efa
--- /dev/null
+++ b/test/elf/Inputs/group-cmd-search-2.ls
@@ -0,0 +1 @@
+GROUP ( /shared.so-x86-64 )
diff --git a/test/elf/Inputs/group-cmd-search-3.ls b/test/elf/Inputs/group-cmd-search-3.ls
new file mode 100644
index 000000000000..83ce0ca62fb1
--- /dev/null
+++ b/test/elf/Inputs/group-cmd-search-3.ls
@@ -0,0 +1 @@
+GROUP ( -l:shared.so-x86-64 -lfnarchive )
diff --git a/test/elf/Inputs/ifunc.S b/test/elf/Inputs/ifunc.S
new file mode 100644
index 000000000000..0ac1f5a5b0bb
--- /dev/null
+++ b/test/elf/Inputs/ifunc.S
@@ -0,0 +1,21 @@
+ .text
+ .globl hey;
+ .type hey, @function;
+hey:
+ .type hey, @gnu_indirect_function;
+ leaq __hey_1(%rip), %rax
+ ret
+
+ .text
+ .type __hey_1, @function;
+ .globl __hey_1;
+__hey_1:
+ movq $42, %rax
+ ret
+
+ .text
+ .type plt, @function;
+ .globl plt;
+plt:
+ call hey@PLT
+ ret
diff --git a/test/elf/Inputs/ifunc.cpp b/test/elf/Inputs/ifunc.cpp
new file mode 100644
index 000000000000..2e520277d36c
--- /dev/null
+++ b/test/elf/Inputs/ifunc.cpp
@@ -0,0 +1,3 @@
+extern "C" int hey();
+
+int main() { return hey(); }
diff --git a/test/elf/Inputs/ifunc.cpp.x86-64 b/test/elf/Inputs/ifunc.cpp.x86-64
new file mode 100644
index 000000000000..20c812cabd2c
--- /dev/null
+++ b/test/elf/Inputs/ifunc.cpp.x86-64
Binary files differ
diff --git a/test/elf/Inputs/ifunc.x86-64 b/test/elf/Inputs/ifunc.x86-64
new file mode 100644
index 000000000000..36c8e04ca837
--- /dev/null
+++ b/test/elf/Inputs/ifunc.x86-64
Binary files differ
diff --git a/test/elf/Inputs/init_array.x86-64 b/test/elf/Inputs/init_array.x86-64
new file mode 100644
index 000000000000..2425c227fd42
--- /dev/null
+++ b/test/elf/Inputs/init_array.x86-64
Binary files differ
diff --git a/test/elf/Inputs/libfnarchive.a b/test/elf/Inputs/libfnarchive.a
new file mode 100644
index 000000000000..753acd6e2c65
--- /dev/null
+++ b/test/elf/Inputs/libfnarchive.a
Binary files differ
diff --git a/test/elf/Inputs/libifunc.x86-64.so b/test/elf/Inputs/libifunc.x86-64.so
new file mode 100644
index 000000000000..0f05b308ce78
--- /dev/null
+++ b/test/elf/Inputs/libifunc.x86-64.so
Binary files differ
diff --git a/test/elf/Inputs/libundef.so b/test/elf/Inputs/libundef.so
new file mode 100644
index 000000000000..41f2a668f360
--- /dev/null
+++ b/test/elf/Inputs/libundef.so
Binary files differ
diff --git a/test/elf/Inputs/libweaksym.so b/test/elf/Inputs/libweaksym.so
new file mode 100755
index 000000000000..7ff4ea56ae60
--- /dev/null
+++ b/test/elf/Inputs/libweaksym.so
Binary files differ
diff --git a/test/elf/Inputs/main-with-global-def.o.yaml b/test/elf/Inputs/main-with-global-def.o.yaml
new file mode 100644
index 000000000000..55029614e1e8
--- /dev/null
+++ b/test/elf/Inputs/main-with-global-def.o.yaml
@@ -0,0 +1,56 @@
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: 554889E5B8C80000005DC3554889E54883EC10C745FC00000000B000E8000000004883C4105DC3
+ - Name: .rela.text
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .text
+ Relocations:
+ - Offset: 0x000000000000001D
+ Symbol: my_func
+ Type: R_X86_64_PC32
+ Addend: -4
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ Global:
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x000000000000000B
+ Size: 0x000000000000001C
+ - Name: my_weak_func2
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x000000000000000B
+ - Name: my_func
+...
diff --git a/test/elf/Inputs/mainobj.x86_64 b/test/elf/Inputs/mainobj.x86_64
new file mode 100644
index 000000000000..d0f29418237d
--- /dev/null
+++ b/test/elf/Inputs/mainobj.x86_64
Binary files differ
diff --git a/test/elf/Inputs/object-test.elf-hexagon b/test/elf/Inputs/object-test.elf-hexagon
new file mode 100644
index 000000000000..bfc85a7d0b76
--- /dev/null
+++ b/test/elf/Inputs/object-test.elf-hexagon
Binary files differ
diff --git a/test/elf/Inputs/object-test.elf-i386 b/test/elf/Inputs/object-test.elf-i386
new file mode 100644
index 000000000000..872684c7fcc1
--- /dev/null
+++ b/test/elf/Inputs/object-test.elf-i386
Binary files differ
diff --git a/test/elf/Inputs/phdr.i386 b/test/elf/Inputs/phdr.i386
new file mode 100644
index 000000000000..7c83dd314891
--- /dev/null
+++ b/test/elf/Inputs/phdr.i386
Binary files differ
diff --git a/test/elf/Inputs/quickdata-sort-test.o.elf-hexagon b/test/elf/Inputs/quickdata-sort-test.o.elf-hexagon
new file mode 100644
index 000000000000..03d028707129
--- /dev/null
+++ b/test/elf/Inputs/quickdata-sort-test.o.elf-hexagon
Binary files differ
diff --git a/test/elf/Inputs/quickdata-sortcommon-test.o.elf-hexagon b/test/elf/Inputs/quickdata-sortcommon-test.o.elf-hexagon
new file mode 100644
index 000000000000..410a3d47d320
--- /dev/null
+++ b/test/elf/Inputs/quickdata-sortcommon-test.o.elf-hexagon
Binary files differ
diff --git a/test/elf/Inputs/quickdata-test.elf-hexagon b/test/elf/Inputs/quickdata-test.elf-hexagon
new file mode 100644
index 000000000000..c3ae53a6babe
--- /dev/null
+++ b/test/elf/Inputs/quickdata-test.elf-hexagon
Binary files differ
diff --git a/test/elf/Inputs/reloc-test.elf-i386 b/test/elf/Inputs/reloc-test.elf-i386
new file mode 100644
index 000000000000..1a5558131fff
--- /dev/null
+++ b/test/elf/Inputs/reloc-test.elf-i386
Binary files differ
diff --git a/test/elf/Inputs/reloc-xb.x86 b/test/elf/Inputs/reloc-xb.x86
new file mode 100644
index 000000000000..4d9770aa2356
--- /dev/null
+++ b/test/elf/Inputs/reloc-xb.x86
Binary files differ
diff --git a/test/elf/Inputs/reloc-xt.x86 b/test/elf/Inputs/reloc-xt.x86
new file mode 100644
index 000000000000..dcdfbfb09f71
--- /dev/null
+++ b/test/elf/Inputs/reloc-xt.x86
Binary files differ
diff --git a/test/elf/Inputs/relocs-dynamic.x86-64 b/test/elf/Inputs/relocs-dynamic.x86-64
new file mode 100644
index 000000000000..0c44924d18e6
--- /dev/null
+++ b/test/elf/Inputs/relocs-dynamic.x86-64
Binary files differ
diff --git a/test/elf/Inputs/relocs.x86-64 b/test/elf/Inputs/relocs.x86-64
new file mode 100644
index 000000000000..112dfa733db9
--- /dev/null
+++ b/test/elf/Inputs/relocs.x86-64
Binary files differ
diff --git a/test/elf/Inputs/responsefile b/test/elf/Inputs/responsefile
new file mode 100644
index 000000000000..2fe657a0e3b0
--- /dev/null
+++ b/test/elf/Inputs/responsefile
@@ -0,0 +1 @@
+--inresponsefile
diff --git a/test/elf/Inputs/rodata-test.hexagon b/test/elf/Inputs/rodata-test.hexagon
new file mode 100644
index 000000000000..f448748e2abe
--- /dev/null
+++ b/test/elf/Inputs/rodata-test.hexagon
Binary files differ
diff --git a/test/elf/Inputs/rodata-test.i386 b/test/elf/Inputs/rodata-test.i386
new file mode 100644
index 000000000000..09f71eb59969
--- /dev/null
+++ b/test/elf/Inputs/rodata-test.i386
Binary files differ
diff --git a/test/elf/Inputs/rodata.c b/test/elf/Inputs/rodata.c
new file mode 100644
index 000000000000..b43c9c945898
--- /dev/null
+++ b/test/elf/Inputs/rodata.c
@@ -0,0 +1,4 @@
+const unsigned char *str = "llvm";
+int foo() {
+ return str[0];
+}
diff --git a/test/elf/Inputs/rodata.o b/test/elf/Inputs/rodata.o
new file mode 100644
index 000000000000..f13ddc9bba98
--- /dev/null
+++ b/test/elf/Inputs/rodata.o
Binary files differ
diff --git a/test/elf/Inputs/section-test.i386 b/test/elf/Inputs/section-test.i386
new file mode 100644
index 000000000000..2b447a9f8f5b
--- /dev/null
+++ b/test/elf/Inputs/section-test.i386
Binary files differ
diff --git a/test/elf/Inputs/shared.c b/test/elf/Inputs/shared.c
new file mode 100644
index 000000000000..2be91c4b9e45
--- /dev/null
+++ b/test/elf/Inputs/shared.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+
+extern int i;
+int i = 42;
+
+// Undefined weak function in a dynamic library.
+__attribute__((weak)) void weakfoo();
+
+// Regular function in a dynamic library.
+void foo() {
+ // Try to call weakfoo so that the reference to weekfoo will be included in
+ // the resulting .so file.
+ if (weakfoo)
+ weakfoo();
+ puts("Fooo!!");
+}
diff --git a/test/elf/Inputs/shared.so-x86-64 b/test/elf/Inputs/shared.so-x86-64
new file mode 100644
index 000000000000..0240f0e67431
--- /dev/null
+++ b/test/elf/Inputs/shared.so-x86-64
Binary files differ
diff --git a/test/elf/Inputs/stripped-empty.x86_64 b/test/elf/Inputs/stripped-empty.x86_64
new file mode 100644
index 000000000000..7368ba280d79
--- /dev/null
+++ b/test/elf/Inputs/stripped-empty.x86_64
Binary files differ
diff --git a/test/elf/Inputs/target-test.hexagon b/test/elf/Inputs/target-test.hexagon
new file mode 100644
index 000000000000..7da114561920
--- /dev/null
+++ b/test/elf/Inputs/target-test.hexagon
Binary files differ
diff --git a/test/elf/Inputs/target-test.ppc b/test/elf/Inputs/target-test.ppc
new file mode 100644
index 000000000000..001be338c20d
--- /dev/null
+++ b/test/elf/Inputs/target-test.ppc
Binary files differ
diff --git a/test/elf/Inputs/tls.S b/test/elf/Inputs/tls.S
new file mode 100644
index 000000000000..7d9eab647b53
--- /dev/null
+++ b/test/elf/Inputs/tls.S
@@ -0,0 +1,50 @@
+ .text
+ .globl main
+ .align 16, 0x90
+ .type main,@function
+main: # @main
+ callq GOTTPOFF
+ addl %fs:tls1@TPOFF, %eax
+ addl %fs:tls0@TPOFF, %eax
+ addl %fs:tls2@TPOFF, %eax
+ ret
+
+ .text
+ .globl GOTTPOFF
+ .type GOTTPOFF,@function
+GOTTPOFF:
+ movq tls2@GOTTPOFF(%rip), %rax
+ movl %fs:0(%rax), %eax
+ ret
+
+ .text
+ .globl TLSLD
+ .type TLSLD,@function
+TLSLD:
+ leaq tls0@tlsld(%rip), %rdi
+ call __tls_get_addr@plt
+ leaq tls0@dtpoff(%rax), %rax
+ ret
+
+ .type tls0,@object # @tls0
+ .section .tbss,"awT",@nobits
+ .globl tls0
+ .align 4
+tls0:
+ .long 0 # 0x0
+ .size tls0, 4
+
+ .type tls1,@object # @tls1
+ .globl tls1
+ .align 4
+tls1:
+ .long 0 # 0x0
+ .size tls1, 4
+
+ .type tls2,@object # @tls2
+ .section .tdata,"awT",@progbits
+ .globl tls2
+ .align 4
+tls2:
+ .long 1 # 0x1
+ .size tls2, 4
diff --git a/test/elf/Inputs/tls.c b/test/elf/Inputs/tls.c
new file mode 100644
index 000000000000..672350756562
--- /dev/null
+++ b/test/elf/Inputs/tls.c
@@ -0,0 +1,11 @@
+extern __thread int tls0;
+extern __thread int tls1;
+extern __thread int tls2;
+
+__thread int tls0 = 0;
+__thread int tls1 = 0;
+__thread int tls2 = 1;
+
+int main() {
+ return tls0 + tls1 + tls2;
+}
diff --git a/test/elf/Inputs/tls.x86-64 b/test/elf/Inputs/tls.x86-64
new file mode 100644
index 000000000000..b420ce89b19b
--- /dev/null
+++ b/test/elf/Inputs/tls.x86-64
Binary files differ
diff --git a/test/elf/Inputs/tlsAddr.x86-64 b/test/elf/Inputs/tlsAddr.x86-64
new file mode 100644
index 000000000000..16cc9ab25abf
--- /dev/null
+++ b/test/elf/Inputs/tlsAddr.x86-64
Binary files differ
diff --git a/test/elf/Inputs/tlsaddr.c b/test/elf/Inputs/tlsaddr.c
new file mode 100644
index 000000000000..f62d57b3bfb4
--- /dev/null
+++ b/test/elf/Inputs/tlsaddr.c
@@ -0,0 +1,8 @@
+__thread int tls0 = 0;
+__thread int tls1 = 0;
+__thread int tls2 = 1;
+__thread int tls3 = 2;
+
+int main() {
+ return tls0 + tls1 + tls2;
+}
diff --git a/test/elf/Inputs/undef-from-main-so.c b/test/elf/Inputs/undef-from-main-so.c
new file mode 100644
index 000000000000..f1cb63db7ada
--- /dev/null
+++ b/test/elf/Inputs/undef-from-main-so.c
@@ -0,0 +1 @@
+int x[2] = {1, 2};
diff --git a/test/elf/Inputs/undef-from-main.c b/test/elf/Inputs/undef-from-main.c
new file mode 100644
index 000000000000..366d934dd84f
--- /dev/null
+++ b/test/elf/Inputs/undef-from-main.c
@@ -0,0 +1,5 @@
+extern int x[2];
+
+int main() {
+ x[0] = 2;
+}
diff --git a/test/elf/Inputs/undef-pc32.o b/test/elf/Inputs/undef-pc32.o
new file mode 100644
index 000000000000..954916d59991
--- /dev/null
+++ b/test/elf/Inputs/undef-pc32.o
Binary files differ
diff --git a/test/elf/Inputs/undef.o b/test/elf/Inputs/undef.o
new file mode 100644
index 000000000000..3c9b60c6ca33
--- /dev/null
+++ b/test/elf/Inputs/undef.o
Binary files differ
diff --git a/test/elf/Inputs/undef2-so.o.yaml b/test/elf/Inputs/undef2-so.o.yaml
new file mode 100644
index 000000000000..9ecf374ced11
--- /dev/null
+++ b/test/elf/Inputs/undef2-so.o.yaml
@@ -0,0 +1,50 @@
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000001
+ Content: 554889E5488B05000000008B005DC3
+ - Name: .rela.text
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .text
+ Relocations:
+ - Offset: 0x0000000000000007
+ Symbol: myexportedsymbol
+ Type: R_X86_64_GOTPCREL
+ Addend: -4
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ Global:
+ - Name: func
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x000000000000000F
+ - Name: _GLOBAL_OFFSET_TABLE_
+ - Name: myexportedsymbol
diff --git a/test/elf/Inputs/use-shared-32s.c b/test/elf/Inputs/use-shared-32s.c
new file mode 100644
index 000000000000..63054cb036ea
--- /dev/null
+++ b/test/elf/Inputs/use-shared-32s.c
@@ -0,0 +1,8 @@
+void foo();
+
+void (*func)();
+
+int main() {
+ func = foo;
+ func();
+}
diff --git a/test/elf/Inputs/use-shared-32s.x86-64 b/test/elf/Inputs/use-shared-32s.x86-64
new file mode 100644
index 000000000000..7e223677b93f
--- /dev/null
+++ b/test/elf/Inputs/use-shared-32s.x86-64
Binary files differ
diff --git a/test/elf/Inputs/use-shared.c b/test/elf/Inputs/use-shared.c
new file mode 100644
index 000000000000..b370eaa4fac2
--- /dev/null
+++ b/test/elf/Inputs/use-shared.c
@@ -0,0 +1,7 @@
+extern int i;
+void foo();
+
+int main() {
+ foo();
+ return i;
+}
diff --git a/test/elf/Inputs/use-shared.x86-64 b/test/elf/Inputs/use-shared.x86-64
new file mode 100644
index 000000000000..25e1eb87a2b4
--- /dev/null
+++ b/test/elf/Inputs/use-shared.x86-64
Binary files differ
diff --git a/test/elf/Inputs/weaksym.o b/test/elf/Inputs/weaksym.o
new file mode 100644
index 000000000000..010ce704a313
--- /dev/null
+++ b/test/elf/Inputs/weaksym.o
Binary files differ
diff --git a/test/elf/Inputs/writersyms.o b/test/elf/Inputs/writersyms.o
new file mode 100644
index 000000000000..7cd472d99d77
--- /dev/null
+++ b/test/elf/Inputs/writersyms.o
Binary files differ
diff --git a/test/elf/Inputs/x86-64-relocs.S b/test/elf/Inputs/x86-64-relocs.S
new file mode 100644
index 000000000000..2547c0f19bb0
--- /dev/null
+++ b/test/elf/Inputs/x86-64-relocs.S
@@ -0,0 +1,12 @@
+ .text
+ .globl main
+ .align 16, 0x90
+ .type main,@function
+main: # @main
+ call foo@PLT
+ ret
+
+ .globl foo
+ .type foo,@function
+foo:
+ ret
diff --git a/test/elf/Mips/base-address-64.test b/test/elf/Mips/base-address-64.test
new file mode 100644
index 000000000000..07110e7f918f
--- /dev/null
+++ b/test/elf/Mips/base-address-64.test
@@ -0,0 +1,78 @@
+# Check executable base address configuration. Base address should be
+# equal to 0x400000 and the MIPS_BASE_ADDRESS dynamic tag's value should
+# be the same.
+# RUN: yaml2obj -format=elf %s > %t.o
+# RUN: lld -flavor gnu -target mips64el --noinhibit-exec -o %t.exe %t.o
+# RUN: llvm-readobj -dynamic-table -program-headers %t.exe | FileCheck %s
+
+# CHECK: DynamicSection [ (13 entries)
+# CHECK: Tag Type Name/Value
+# CHECK-NEXT: 0x0000000000000004 HASH 0x{{[0-9A-F]+}}
+# CHECK-NEXT: 0x0000000000000005 STRTAB 0x{{[0-9A-F]+}}
+# CHECK-NEXT: 0x0000000000000006 SYMTAB 0x{{[0-9A-F]+}}
+# CHECK-NEXT: 0x000000000000000A STRSZ 1 (bytes)
+# CHECK-NEXT: 0x000000000000000B SYMENT 24 (bytes)
+# CHECK-NEXT: 0x0000000070000001 MIPS_RLD_VERSION 1
+# CHECK-NEXT: 0x0000000070000005 MIPS_FLAGS NOTPOT
+# CHECK-NEXT: 0x0000000070000006 MIPS_BASE_ADDRESS 0x120000000
+# CHECK-NEXT: 0x000000007000000A MIPS_LOCAL_GOTNO 2
+# CHECK-NEXT: 0x0000000070000011 MIPS_SYMTABNO 1
+# CHECK-NEXT: 0x0000000070000013 MIPS_GOTSYM 0x1
+# CHECK-NEXT: 0x0000000000000003 PLTGOT 0x120001000
+# CHECK-NEXT: 0x0000000000000000 NULL 0x0
+# CHECK-NEXT: ]
+
+# CHECK: ProgramHeaders [
+# CHECK: ProgramHeader {
+# CHECK: Type: PT_PHDR (0x6)
+# CHECK: Offset: 0x40
+# CHECK: VirtualAddress: 0x{{[0-9A-F]+}}
+# CHECK: }
+# CHECK: ProgramHeader {
+# CHECK: Type: PT_INTERP (0x3)
+# CHECK: Offset: 0x190
+# CHECK: VirtualAddress: 0x{{[0-9A-F]+}}
+# CHECK: }
+# CHECK: ProgramHeader {
+# CHECK: Type: PT_LOAD (0x1)
+# CHECK-NEXT: Offset: 0x0
+# CHECK-NEXT: VirtualAddress: 0x120000000
+
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC,
+ EF_MIPS_ARCH_64R2 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x10
+ Size: 0x08
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x10
+ Size: 0x00
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x10
+ Size: 0x00
+
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ Global:
+ - Name: main
+ Section: .text
diff --git a/test/elf/Mips/base-address.test b/test/elf/Mips/base-address.test
new file mode 100644
index 000000000000..f55091f84c33
--- /dev/null
+++ b/test/elf/Mips/base-address.test
@@ -0,0 +1,109 @@
+# Check executable base address configuration. Base address should be
+# equal to 0x400000 and the MIPS_BASE_ADDRESS dynamic tag's value should
+# be the same.
+# RUN: yaml2obj -format=elf %s > %t.o
+# RUN: lld -flavor gnu -target mipsel --noinhibit-exec -o %t.exe %t.o
+# RUN: llvm-readobj -dynamic-table -program-headers %t.exe | FileCheck %s
+
+# CHECK: DynamicSection [ (13 entries)
+# CHECK: Tag Type Name/Value
+# CHECK-NEXT: 0x00000004 HASH 0x{{[0-9A-F]+}}
+# CHECK-NEXT: 0x00000005 STRTAB 0x{{[0-9A-F]+}}
+# CHECK-NEXT: 0x00000006 SYMTAB 0x{{[0-9A-F]+}}
+# CHECK-NEXT: 0x0000000A STRSZ 1 (bytes)
+# CHECK-NEXT: 0x0000000B SYMENT 16 (bytes)
+# CHECK-NEXT: 0x70000001 MIPS_RLD_VERSION 1
+# CHECK-NEXT: 0x70000005 MIPS_FLAGS NOTPOT
+# CHECK-NEXT: 0x70000006 MIPS_BASE_ADDRESS 0x400000
+# CHECK-NEXT: 0x7000000A MIPS_LOCAL_GOTNO 2
+# CHECK-NEXT: 0x70000011 MIPS_SYMTABNO 1
+# CHECK-NEXT: 0x70000013 MIPS_GOTSYM 0x1
+# CHECK-NEXT: 0x00000003 PLTGOT 0x401000
+# CHECK-NEXT: 0x00000000 NULL 0x0
+# CHECK-NEXT: ]
+
+# CHECK: ProgramHeaders [
+# CHECK: ProgramHeader {
+# CHECK: Type: PT_PHDR (0x6)
+# CHECK: Offset: 0x34
+# CHECK: VirtualAddress: 0x{{[0-9A-F]+}}
+# CHECK: }
+# CHECK: ProgramHeader {
+# CHECK: Type: PT_INTERP (0x3)
+# CHECK: Offset: 0xF4
+# CHECK: VirtualAddress: 0x{{[0-9A-F]+}}
+# CHECK: }
+# CHECK: ProgramHeader {
+# CHECK: Type: PT_LOAD (0x1)
+# CHECK: Offset: 0x0
+# CHECK: VirtualAddress: 0x{{[0-9A-F]+}}
+# CHECK: }
+# CHECK: ProgramHeader {
+# CHECK: Type: PT_LOAD (0x1)
+# CHECK: Offset: 0x1000
+# CHECK: VirtualAddress: 0x{{[0-9A-F]+}}
+# CHECK: }
+# CHECK: ProgramHeader {
+# CHECK: Type: PT_LOAD (0x1)
+# CHECK: Offset: 0x2000
+# CHECK: VirtualAddress: 0x{{[0-9A-F]+}}
+# CHECK: }
+# CHECK: ProgramHeader {
+# CHECK: Type: PT_DYNAMIC (0x2)
+# CHECK: Offset: 0x12C
+# CHECK: VirtualAddress: 0x{{[0-9A-F]+}}
+# CHECK: }
+# CHECK: ]
+
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x04
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x04
+ Size: 0x00
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x04
+ Size: 0x00
+ - Name: .reginfo
+ Type: SHT_MIPS_REGINFO
+ Flags: [ SHF_ALLOC ]
+ AddressAlign: 0x01
+ Size: 0x18
+ - Name: .MIPS.abiflags
+ Type: SHT_MIPS_ABIFLAGS
+ Flags: [ SHF_ALLOC ]
+ AddressAlign: 0x08
+ Content: '000020010101000100000000000000000000000000000000'
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .reginfo
+ Type: STT_SECTION
+ Section: .reginfo
+ - Name: .MIPS.abiflags
+ Type: STT_SECTION
+ Section: .MIPS.abiflags
+ Global:
+ - Name: main
+ Section: .text
diff --git a/test/elf/Mips/ctors-order.test b/test/elf/Mips/ctors-order.test
new file mode 100644
index 000000000000..344dcd5fc516
--- /dev/null
+++ b/test/elf/Mips/ctors-order.test
@@ -0,0 +1,163 @@
+# Check ordering of .ctors.* sections.
+
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-crtbeginS.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-crtendS.o
+# RUN: yaml2obj -format=elf -docnum 3 %s > %t-obj.o
+# RUN: lld -flavor gnu -target mipsel -shared --output-filetype=yaml \
+# RUN: %t-crtbeginS.o %t-obj.o %t-crtendS.o | FileCheck %s
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so \
+# RUN: %t-crtbeginS.o %t-obj.o %t-crtendS.o
+# RUN: llvm-objdump -s %t.so | FileCheck -check-prefix=RAW %s
+
+# CHECK: defined-atoms:
+# CHECK-NEXT: - type: data
+# CHECK-NEXT: alignment: 2^2
+# CHECK-NEXT: section-choice: custom-required
+# CHECK-NEXT: section-name: .ctors
+# CHECK-NEXT: references:
+# CHECK-NEXT: - kind: layout-after
+# CHECK-NEXT: offset: 0
+# CHECK-NEXT: target: __CTOR_LIST__
+# CHECK-NEXT: - name: __CTOR_LIST__
+# CHECK-NEXT: type: data
+# CHECK-NEXT: content: [ FF, FF, FF, FF ]
+# CHECK-NEXT: alignment: 2^2
+# CHECK-NEXT: section-choice: custom-required
+# CHECK-NEXT: section-name: .ctors
+# CHECK-NEXT: - type: data
+# CHECK-NEXT: content: [ 11, 11, 11, 11 ]
+# CHECK-NEXT: alignment: 2^2
+# CHECK-NEXT: section-choice: custom-required
+# CHECK-NEXT: section-name: .ctors.1
+# CHECK-NEXT: - type: data
+# CHECK-NEXT: content: [ 22, 22, 22, 22 ]
+# CHECK-NEXT: alignment: 2^2
+# CHECK-NEXT: section-choice: custom-required
+# CHECK-NEXT: section-name: .ctors.2
+# CHECK-NEXT: - ref-name: L003
+# CHECK-NEXT: type: data
+# CHECK-NEXT: alignment: 2^2
+# CHECK-NEXT: section-choice: custom-required
+# CHECK-NEXT: section-name: .ctors
+# CHECK-NEXT: references:
+# CHECK-NEXT: - kind: layout-after
+# CHECK-NEXT: offset: 0
+# CHECK-NEXT: target: __CTOR_END__
+# CHECK-NEXT: - name: __CTOR_END__
+# CHECK-NEXT: type: data
+# CHECK-NEXT: content: [ 00, 00, 00, 00 ]
+# CHECK-NEXT: alignment: 2^2
+# CHECK-NEXT: section-choice: custom-required
+# CHECK-NEXT: section-name: .ctors
+
+# RAW: Contents of section .ctors:
+# RAW-NEXT: 1000 ffffffff 11111111 22222222 00000000
+# crtbeginS.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_NOREORDER, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2 ]
+Sections:
+ - Name: .ctors
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x04
+ Content: 'FFFFFFFF'
+
+Symbols:
+ Local:
+ - Name: .ctors
+ Type: STT_SECTION
+ Section: .ctors
+ - Name: __CTOR_LIST__
+ Type: STT_OBJECT
+ Section: .ctors
+
+# crtendS.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_NOREORDER, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x0F
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ Info: .text
+ AddressAlign: 0x04
+ Relocations:
+ - Offset: 0x00
+ Symbol: .ctors
+ Type: R_MIPS_HI16
+ - Offset: 0x04
+ Symbol: .ctors
+ Type: R_MIPS_LO16
+ - Offset: 0x08
+ Symbol: .ctors
+ Type: R_MIPS_HI16
+ - Offset: 0x0C
+ Symbol: .ctors
+ Type: R_MIPS_LO16
+ - Name: .ctors
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x04
+ Size: 0x04
+
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .ctors
+ Type: STT_SECTION
+ Section: .ctors
+ - Name: __CTOR_END__
+ Type: STT_OBJECT
+ Section: .ctors
+ - Name: __do_global_ctors_aux
+ Type: STT_FUNC
+ Section: .text
+
+# obj.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_NOREORDER, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32 ]
+Sections:
+ - Name: .ctors.2
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x04
+ Content: '22222222'
+ - Name: .ctors.1
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x04
+ Content: '11111111'
+
+Symbols:
+ Local:
+ - Name: .ctors.2
+ Type: STT_SECTION
+ Section: .ctors.2
+ - Name: .ctors.1
+ Type: STT_SECTION
+ Section: .ctors.1
+...
diff --git a/test/elf/Mips/dt-textrel-64.test b/test/elf/Mips/dt-textrel-64.test
new file mode 100644
index 000000000000..32cc99e54b2f
--- /dev/null
+++ b/test/elf/Mips/dt-textrel-64.test
@@ -0,0 +1,74 @@
+# Check that if a dynamic relocation R_MIPS_64 modify a read-only section,
+# .dynamic section contains the DT_TEXTREL tag.
+
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-so.o
+# RUN: lld -flavor gnu -target mips64el -shared -o %t.so %t-so.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-o.o
+# RUN: lld -flavor gnu -target mips64el -e T0 -o %t.exe %t-o.o %t.so
+# RUN: llvm-readobj -dynamic-table %t.exe | FileCheck %s
+
+# CHECK: 0x{{[0-9A-F]+}} TEXTREL
+
+# so.o
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ARCH_64]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x4
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 0x08
+
+# o.o
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ARCH_64]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x4
+ Size: 0x8
+
+ - Name: .rel.text
+ Type: SHT_RELA
+ Link: .symtab
+ Info: .text
+ AddressAlign: 0x04
+ Relocations:
+ - Offset: 0
+ Symbol: T1
+ Type: R_MIPS_64
+
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+
+ Global:
+ - Name: T0
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x8
+ - Name: T1
+...
diff --git a/test/elf/Mips/dt-textrel.test b/test/elf/Mips/dt-textrel.test
new file mode 100644
index 000000000000..ca854dff8e58
--- /dev/null
+++ b/test/elf/Mips/dt-textrel.test
@@ -0,0 +1,74 @@
+# Check that if a dynamic relocation modify a read-only section,
+# .dynamic section contains the DT_TEXTREL tag.
+
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-so.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t-so.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-o.o
+# RUN: lld -flavor gnu -target mipsel -e T0 -o %t.exe %t-o.o %t.so
+# RUN: llvm-readobj -dynamic-table %t.exe | FileCheck %s
+
+# CHECK: 0x{{[0-9A-F]+}} TEXTREL
+
+# so.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x04
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 0x04
+
+# o.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Content: '00000000'
+
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ Info: .text
+ AddressAlign: 0x04
+ Relocations:
+ - Offset: 0
+ Symbol: T1
+ Type: R_MIPS_32
+
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+
+ Global:
+ - Name: T0
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x04
+ - Name: T1
+...
diff --git a/test/elf/Mips/dynlib-dynamic.test b/test/elf/Mips/dynlib-dynamic.test
new file mode 100644
index 000000000000..54afdec263a6
--- /dev/null
+++ b/test/elf/Mips/dynlib-dynamic.test
@@ -0,0 +1,110 @@
+# Check MIPS specific tags in the dynamic table.
+
+# Build shared library
+# RUN: yaml2obj -format=elf %s > %t.o
+# RUN: lld -flavor gnu -target mipsel -shared --noinhibit-exec -o %t.so %t.o
+# RUN: llvm-readobj -dynamic-table %t.so | FileCheck %s
+
+# CHECK: Format: ELF32-mips
+# CHECK: Arch: mipsel
+# CHECK: AddressSize: 32bit
+# CHECK: LoadName:
+# CHECK: DynamicSection [ (13 entries)
+# CHECK: Tag Type Name/Value
+# CHECK-NEXT: 0x00000004 HASH 0x{{[0-9A-F]+}}
+# CHECK-NEXT: 0x00000005 STRTAB 0x{{[0-9A-F]+}}
+# CHECK-NEXT: 0x00000006 SYMTAB 0x{{[0-9A-F]+}}
+# CHECK-NEXT: 0x0000000A STRSZ 17 (bytes)
+# CHECK-NEXT: 0x0000000B SYMENT 16 (bytes)
+# CHECK-NEXT: 0x70000001 MIPS_RLD_VERSION 1
+# CHECK-NEXT: 0x70000005 MIPS_FLAGS NOTPOT
+# CHECK-NEXT: 0x70000006 MIPS_BASE_ADDRESS 0x0
+# CHECK-NEXT: 0x7000000A MIPS_LOCAL_GOTNO 4
+# CHECK-NEXT: 0x70000011 MIPS_SYMTABNO 4
+# CHECK-NEXT: 0x70000013 MIPS_GOTSYM 0x2
+# CHECK-NEXT: 0x00000003 PLTGOT 0x1000
+# CHECK-NEXT: 0x00000000 NULL 0x0
+# CHECK-NEXT: ]
+
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_PIC, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x18
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x04
+ Info: .text
+ Relocations:
+ - Offset: 0x00
+ Symbol: '$.str1'
+ Type: R_MIPS_GOT16
+ - Offset: 0x04
+ Symbol: '$.str1'
+ Type: R_MIPS_LO16
+ - Offset: 0x08
+ Symbol: '$.str2'
+ Type: R_MIPS_GOT16
+ - Offset: 0x0C
+ Symbol: '$.str2'
+ Type: R_MIPS_LO16
+ - Offset: 0x10
+ Symbol: glob2
+ Type: R_MIPS_CALL16
+ - Offset: 0x14
+ Symbol: ext1
+ Type: R_MIPS_CALL16
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x04
+ Size: 0x00
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x04
+ Size: 0x00
+ - Name: .rodata.str1
+ Type: SHT_PROGBITS
+ AddressAlign: 0x01
+ Size: 0x05
+ - Name: .rodata.str2
+ Type: SHT_PROGBITS
+ AddressAlign: 0x01
+ Size: 0x05
+
+Symbols:
+ Local:
+ - Name: '$.str1'
+ Section: .rodata.str1
+ - Name: '$.str2'
+ Section: .rodata.str2
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .rodata.str1
+ Type: STT_SECTION
+ Section: .rodata.str1
+ - Name: .rodata.str2
+ Type: STT_SECTION
+ Section: .rodata.str2
+ Global:
+ - Name: glob
+ Section: .text
+ - Name: ext1
+ - Name: glob2
diff --git a/test/elf/Mips/dynlib-dynsym-micro.test b/test/elf/Mips/dynlib-dynsym-micro.test
new file mode 100644
index 000000000000..4d75945af7b0
--- /dev/null
+++ b/test/elf/Mips/dynlib-dynsym-micro.test
@@ -0,0 +1,208 @@
+# 1. Check sorting of .dynsym content accordingly to .got section
+# in case of using microMIPS relocations.
+# 2. Check that microMIPS records in a dynamic symbol table have:
+# - cleared the STO_MIPS_MICROMIPS flag
+# - adjusted adress
+
+# Build shared library
+# RUN: yaml2obj -format=elf %s > %t.o
+# RUN: lld -flavor gnu -target mipsel -shared --noinhibit-exec -o %t-so %t.o
+# RUN: llvm-readobj -dyn-symbols %t-so | FileCheck -check-prefix=CHECK-DYN %s
+
+# Build shared library (yaml format)
+# RUN: lld -flavor gnu -target mipsel -shared --noinhibit-exec \
+# RUN: --output-filetype=yaml -o %t-yaml %t.o
+# RUN: FileCheck -check-prefix=CHECK-GOT %s < %t-yaml
+
+# CHECK-DYN: Format: ELF32-mips
+# CHECK-DYN: Arch: mipsel
+# CHECK-DYN: AddressSize: 32bit
+# CHECK-DYN: LoadName:
+# CHECK-DYN: DynamicSymbols [
+# CHECK-DYN: Symbol {
+# CHECK-DYN: Name: @ (0)
+# CHECK-DYN: Value: 0x0
+# CHECK-DYN: Size: 0
+# CHECK-DYN: Binding: Local (0x0)
+# CHECK-DYN: Type: None (0x0)
+# CHECK-DYN: Other: 0
+# CHECK-DYN: Section: Undefined (0x0)
+# CHECK-DYN: }
+# CHECK-DYN: Symbol {
+# CHECK-DYN: Name: bar@ (5)
+# CHECK-DYN: Value: 0x139
+# CHECK-DYN: Size: 4
+# CHECK-DYN: Binding: Global (0x1)
+# CHECK-DYN: Type: Function (0x2)
+# CHECK-DYN: Other: 0
+# CHECK-DYN: Section: .text (0x4)
+# CHECK-DYN: }
+# CHECK-DYN: Symbol {
+# CHECK-DYN: Name: foo@ (1)
+# CHECK-DYN: Value: 0x121
+# CHECK-DYN: Size: 24
+# CHECK-DYN: Binding: Global (0x1)
+# CHECK-DYN: Type: Function (0x2)
+# CHECK-DYN: Other: 0
+# CHECK-DYN: Section: .text (0x4)
+# CHECK-DYN: }
+# CHECK-DYN: Symbol {
+# CHECK-DYN: Name: ext1@ (9)
+# CHECK-DYN: Value: 0x0
+# CHECK-DYN: Size: 0
+# CHECK-DYN: Binding: Global (0x1)
+# CHECK-DYN: Type: None (0x0)
+# CHECK-DYN: Other: 0
+# CHECK-DYN: Section: Undefined (0x0)
+# CHECK-DYN: }
+# CHECK-DYN: Symbol {
+# CHECK-DYN: Name: ext2@ (14)
+# CHECK-DYN: Value: 0x0
+# CHECK-DYN: Size: 0
+# CHECK-DYN: Binding: Global (0x1)
+# CHECK-DYN: Type: None (0x0)
+# CHECK-DYN: Other: 0
+# CHECK-DYN: Section: Undefined (0x0)
+# CHECK-DYN: }
+# CHECK-DYN: ]
+
+# CHECK-GOT: - type: got
+# CHECK-GOT: content: [ 00, 00, 00, 00 ]
+# CHECK-GOT: alignment: 2^2
+# CHECK-GOT: section-choice: custom-required
+# CHECK-GOT: section-name: .got
+# CHECK-GOT: permissions: rw-
+# CHECK-GOT: - type: got
+# CHECK-GOT: content: [ 00, 00, 00, 80 ]
+# CHECK-GOT: alignment: 2^2
+# CHECK-GOT: section-choice: custom-required
+# CHECK-GOT: section-name: .got
+# CHECK-GOT: permissions: rw-
+# CHECK-GOT: - ref-name: L000
+# CHECK-GOT: type: got
+# CHECK-GOT: content: [ 00, 00, 00, 00 ]
+# CHECK-GOT: alignment: 2^2
+# CHECK-GOT: section-choice: custom-required
+# CHECK-GOT: section-name: .got
+# CHECK-GOT: permissions: rw-
+# CHECK-GOT: references:
+# CHECK-GOT: - kind: LLD_R_MIPS_32_HI16
+# CHECK-GOT: offset: 0
+# CHECK-GOT: target: L007
+# CHECK-GOT: - ref-name: L002
+# CHECK-GOT: type: got
+# CHECK-GOT: content: [ 00, 00, 00, 00 ]
+# CHECK-GOT: alignment: 2^2
+# CHECK-GOT: section-choice: custom-required
+# CHECK-GOT: section-name: .got
+# CHECK-GOT: permissions: rw-
+# CHECK-GOT: references:
+# CHECK-GOT: - kind: LLD_R_MIPS_32_HI16
+# CHECK-GOT: offset: 0
+# CHECK-GOT: target: L008
+# CHECK-GOT: - ref-name: L004
+# CHECK-GOT: type: got
+# CHECK-GOT: content: [ 00, 00, 00, 00 ]
+# CHECK-GOT: alignment: 2^2
+# CHECK-GOT: section-choice: custom-required
+# CHECK-GOT: section-name: .got
+# CHECK-GOT: permissions: rw-
+# CHECK-GOT: references:
+# CHECK-GOT: - kind: LLD_R_MIPS_GLOBAL_GOT
+# CHECK-GOT: offset: 0
+# CHECK-GOT: target: foo
+# CHECK-GOT: - ref-name: L005
+# CHECK-GOT: type: got
+# CHECK-GOT: content: [ 00, 00, 00, 00 ]
+# CHECK-GOT: alignment: 2^2
+# CHECK-GOT: section-choice: custom-required
+# CHECK-GOT: section-name: .got
+# CHECK-GOT: permissions: rw-
+# CHECK-GOT: references:
+# CHECK-GOT: - kind: LLD_R_MIPS_GLOBAL_GOT
+# CHECK-GOT: offset: 0
+# CHECK-GOT: target: ext1
+# CHECK-GOT: - ref-name: L006
+# CHECK-GOT: type: got
+# CHECK-GOT: content: [ 00, 00, 00, 00 ]
+# CHECK-GOT: alignment: 2^2
+# CHECK-GOT: section-choice: custom-required
+# CHECK-GOT: section-name: .got
+# CHECK-GOT: permissions: rw-
+# CHECK-GOT: references:
+# CHECK-GOT: - kind: LLD_R_MIPS_GLOBAL_GOT
+# CHECK-GOT: offset: 0
+# CHECK-GOT: target: ext2
+
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32,
+ EF_MIPS_ARCH_32R2, EF_MIPS_MICROMIPS ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x1C
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x04
+ Info: .text
+ Relocations:
+ - Offset: 0x00
+ Symbol: .rodata.str1
+ Type: R_MICROMIPS_GOT16
+ - Offset: 0x04
+ Symbol: .rodata.str1
+ Type: R_MICROMIPS_LO16
+ - Offset: 0x08
+ Symbol: .rodata.str2
+ Type: R_MICROMIPS_GOT16
+ - Offset: 0x0C
+ Symbol: .rodata.str2
+ Type: R_MICROMIPS_LO16
+ - Offset: 0x10
+ Symbol: foo
+ Type: R_MICROMIPS_CALL16
+ - Offset: 0x14
+ Symbol: ext1
+ Type: R_MICROMIPS_CALL16
+ - Offset: 0x18
+ Symbol: ext2
+ Type: R_MICROMIPS_CALL16
+ - Name: .rodata.str1
+ Type: SHT_PROGBITS
+ AddressAlign: 0x01
+ Size: 0x05
+ - Name: .rodata.str2
+ Type: SHT_PROGBITS
+ AddressAlign: 0x01
+ Size: 0x05
+
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .rodata.str1
+ Type: STT_SECTION
+ Section: .rodata.str1
+ - Name: .rodata.str2
+ Type: STT_SECTION
+ Section: .rodata.str2
+ Global:
+ - Name: bar
+ Section: .text
+ Value: 0x18
+ Other: [ STO_MIPS_MICROMIPS ]
+ - Name: foo
+ Section: .text
+ Other: [ STO_MIPS_MICROMIPS ]
+ - Name: ext1
+ - Name: ext2
+...
diff --git a/test/elf/Mips/dynlib-dynsym.test b/test/elf/Mips/dynlib-dynsym.test
new file mode 100644
index 000000000000..d480c3cbbe41
--- /dev/null
+++ b/test/elf/Mips/dynlib-dynsym.test
@@ -0,0 +1,202 @@
+# Check sorting of .dynsym content accordingly to .got section.
+
+# Build shared library
+# RUN: yaml2obj -format=elf %s > %t.o
+# RUN: lld -flavor gnu -target mipsel -shared --noinhibit-exec -o %t-so %t.o
+# RUN: llvm-readobj -dyn-symbols %t-so | FileCheck -check-prefix=CHECK-DYN %s
+
+# Build shared library (yaml format)
+# RUN: lld -flavor gnu -target mipsel -shared --noinhibit-exec \
+# RUN: --output-filetype=yaml -o %t-yaml %t.o
+# RUN: FileCheck -check-prefix=CHECK-GOT %s < %t-yaml
+
+# CHECK-DYN: Format: ELF32-mips
+# CHECK-DYN: Arch: mipsel
+# CHECK-DYN: AddressSize: 32bit
+# CHECK-DYN: LoadName:
+# CHECK-DYN: DynamicSymbols [
+# CHECK-DYN: Symbol {
+# CHECK-DYN: Name: @ (0)
+# CHECK-DYN: Value: 0x0
+# CHECK-DYN: Size: 0
+# CHECK-DYN: Binding: Local (0x0)
+# CHECK-DYN: Type: None (0x0)
+# CHECK-DYN: Other: 0
+# CHECK-DYN: Section: Undefined (0x0)
+# CHECK-DYN: }
+# CHECK-DYN: Symbol {
+# CHECK-DYN: Name: bar@ (5)
+# CHECK-DYN: Value: 0x138
+# CHECK-DYN: Size: 4
+# CHECK-DYN: Binding: Global (0x1)
+# CHECK-DYN: Type: Function (0x2)
+# CHECK-DYN: Other: 0
+# CHECK-DYN: Section: .text (0x4)
+# CHECK-DYN: }
+# CHECK-DYN: Symbol {
+# CHECK-DYN: Name: foo@ (1)
+# CHECK-DYN: Value: 0x120
+# CHECK-DYN: Size: 24
+# CHECK-DYN: Binding: Global (0x1)
+# CHECK-DYN: Type: Function (0x2)
+# CHECK-DYN: Other: 0
+# CHECK-DYN: Section: .text (0x4)
+# CHECK-DYN: }
+# CHECK-DYN: Symbol {
+# CHECK-DYN: Name: ext1@ (9)
+# CHECK-DYN: Value: 0x0
+# CHECK-DYN: Size: 0
+# CHECK-DYN: Binding: Global (0x1)
+# CHECK-DYN: Type: None (0x0)
+# CHECK-DYN: Other: 0
+# CHECK-DYN: Section: Undefined (0x0)
+# CHECK-DYN: }
+# CHECK-DYN: Symbol {
+# CHECK-DYN: Name: ext2@ (14)
+# CHECK-DYN: Value: 0x0
+# CHECK-DYN: Size: 0
+# CHECK-DYN: Binding: Global (0x1)
+# CHECK-DYN: Type: None (0x0)
+# CHECK-DYN: Other: 0
+# CHECK-DYN: Section: Undefined (0x0)
+# CHECK-DYN: }
+# CHECK-DYN: ]
+
+# CHECK-GOT: - type: got
+# CHECK-GOT: content: [ 00, 00, 00, 00 ]
+# CHECK-GOT: alignment: 2^2
+# CHECK-GOT: section-choice: custom-required
+# CHECK-GOT: section-name: .got
+# CHECK-GOT: permissions: rw-
+# CHECK-GOT: - type: got
+# CHECK-GOT: content: [ 00, 00, 00, 80 ]
+# CHECK-GOT: alignment: 2^2
+# CHECK-GOT: section-choice: custom-required
+# CHECK-GOT: section-name: .got
+# CHECK-GOT: permissions: rw-
+# CHECK-GOT: - ref-name: L000
+# CHECK-GOT: type: got
+# CHECK-GOT: content: [ 00, 00, 00, 00 ]
+# CHECK-GOT: alignment: 2^2
+# CHECK-GOT: section-choice: custom-required
+# CHECK-GOT: section-name: .got
+# CHECK-GOT: permissions: rw-
+# CHECK-GOT: references:
+# CHECK-GOT: - kind: LLD_R_MIPS_32_HI16
+# CHECK-GOT: offset: 0
+# CHECK-GOT: target: L007
+# CHECK-GOT: - ref-name: L002
+# CHECK-GOT: type: got
+# CHECK-GOT: content: [ 00, 00, 00, 00 ]
+# CHECK-GOT: alignment: 2^2
+# CHECK-GOT: section-choice: custom-required
+# CHECK-GOT: section-name: .got
+# CHECK-GOT: permissions: rw-
+# CHECK-GOT: references:
+# CHECK-GOT: - kind: LLD_R_MIPS_32_HI16
+# CHECK-GOT: offset: 0
+# CHECK-GOT: target: L008
+# CHECK-GOT: - ref-name: L004
+# CHECK-GOT: type: got
+# CHECK-GOT: content: [ 00, 00, 00, 00 ]
+# CHECK-GOT: alignment: 2^2
+# CHECK-GOT: section-choice: custom-required
+# CHECK-GOT: section-name: .got
+# CHECK-GOT: permissions: rw-
+# CHECK-GOT: references:
+# CHECK-GOT: - kind: LLD_R_MIPS_GLOBAL_GOT
+# CHECK-GOT: offset: 0
+# CHECK-GOT: target: foo
+# CHECK-GOT: - ref-name: L005
+# CHECK-GOT: type: got
+# CHECK-GOT: content: [ 00, 00, 00, 00 ]
+# CHECK-GOT: alignment: 2^2
+# CHECK-GOT: section-choice: custom-required
+# CHECK-GOT: section-name: .got
+# CHECK-GOT: permissions: rw-
+# CHECK-GOT: references:
+# CHECK-GOT: - kind: LLD_R_MIPS_GLOBAL_GOT
+# CHECK-GOT: offset: 0
+# CHECK-GOT: target: ext1
+# CHECK-GOT: - ref-name: L006
+# CHECK-GOT: type: got
+# CHECK-GOT: content: [ 00, 00, 00, 00 ]
+# CHECK-GOT: alignment: 2^2
+# CHECK-GOT: section-choice: custom-required
+# CHECK-GOT: section-name: .got
+# CHECK-GOT: permissions: rw-
+# CHECK-GOT: references:
+# CHECK-GOT: - kind: LLD_R_MIPS_GLOBAL_GOT
+# CHECK-GOT: offset: 0
+# CHECK-GOT: target: ext2
+
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32,
+ EF_MIPS_ARCH_32 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x1C
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x04
+ Info: .text
+ Relocations:
+ - Offset: 0x00
+ Symbol: .rodata.str1
+ Type: R_MIPS_GOT16
+ - Offset: 0x04
+ Symbol: .rodata.str1
+ Type: R_MIPS_LO16
+ - Offset: 0x08
+ Symbol: .rodata.str2
+ Type: R_MIPS_GOT16
+ - Offset: 0x0C
+ Symbol: .rodata.str2
+ Type: R_MIPS_LO16
+ - Offset: 0x10
+ Symbol: foo
+ Type: R_MIPS_CALL16
+ - Offset: 0x14
+ Symbol: ext1
+ Type: R_MIPS_CALL16
+ - Offset: 0x18
+ Symbol: ext2
+ Type: R_MIPS_CALL16
+ - Name: .rodata.str1
+ Type: SHT_PROGBITS
+ AddressAlign: 0x01
+ Size: 0x05
+ - Name: .rodata.str2
+ Type: SHT_PROGBITS
+ AddressAlign: 0x01
+ Size: 0x05
+
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .rodata.str1
+ Type: STT_SECTION
+ Section: .rodata.str1
+ - Name: .rodata.str2
+ Type: STT_SECTION
+ Section: .rodata.str2
+ Global:
+ - Name: bar
+ Section: .text
+ Value: 0x18
+ - Name: foo
+ Section: .text
+ - Name: ext1
+ - Name: ext2
+...
diff --git a/test/elf/Mips/dynlib-fileheader-64.test b/test/elf/Mips/dynlib-fileheader-64.test
new file mode 100644
index 000000000000..206f4fa7794d
--- /dev/null
+++ b/test/elf/Mips/dynlib-fileheader-64.test
@@ -0,0 +1,72 @@
+# Check ELF Header for 64-bit shared library.
+
+# Build shared library
+# RUN: yaml2obj -format=elf %s > %t.o
+# RUN: lld -flavor gnu -target mips64el -shared -o %t.so %t.o
+# RUN: llvm-readobj -file-headers %t.so | FileCheck %s
+
+# CHECK: Format: ELF64-mips
+# CHECK: Arch: mips64el
+# CHECK: AddressSize: 64bit
+# CHECK: LoadName:
+# CHECK: ElfHeader {
+# CHECK: Ident {
+# CHECK: Magic: (7F 45 4C 46)
+# CHECK: Class: 64-bit (0x2)
+# CHECK: DataEncoding: LittleEndian (0x1)
+# CHECK: FileVersion: 1
+# CHECK: OS/ABI: SystemV (0x0)
+# CHECK: ABIVersion: 0
+# CHECK: Unused: (00 00 00 00 00 00 00)
+# CHECK: }
+# CHECK: Type: SharedObject (0x3)
+# CHECK: Machine: EM_MIPS (0x8)
+# CHECK: Version: 1
+# CHECK: Entry: 0x170
+# CHECK: ProgramHeaderOffset: 0x40
+# CHECK: SectionHeaderOffset: 0x2140
+# CHECK: Flags [ (0x80000006)
+# CHECK: EF_MIPS_ARCH_64R2 (0x80000000)
+# CHECK: EF_MIPS_CPIC (0x4)
+# CHECK: EF_MIPS_PIC (0x2)
+# CHECK: ]
+# CHECK: HeaderSize: 64
+# CHECK: ProgramHeaderEntrySize: 56
+# CHECK: ProgramHeaderCount: 4
+# CHECK: SectionHeaderEntrySize: 64
+# CHECK: SectionHeaderCount: 11
+# CHECK: StringTableSectionIndex: 8
+# CHECK: }
+
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ARCH_64R2 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x10
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x10
+ Size: 0x08
+
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ Global:
+ - Name: data
+ Type: STT_OBJECT
+ Section: .data
+ Size: 0x04
+...
diff --git a/test/elf/Mips/dynlib-fileheader-micro-64.test b/test/elf/Mips/dynlib-fileheader-micro-64.test
new file mode 100644
index 000000000000..c03a951671ea
--- /dev/null
+++ b/test/elf/Mips/dynlib-fileheader-micro-64.test
@@ -0,0 +1,75 @@
+# Check ELF Header for shared library in case of microMIPS symbols.
+
+# Build shared library
+# RUN: yaml2obj -format=elf %s > %t.o
+# RUN: lld -flavor gnu -target mips64el -shared -o %t.so %t.o
+# RUN: llvm-readobj -file-headers %t.so | FileCheck %s
+
+# CHECK: Format: ELF64-mips
+# CHECK-NEXT: Arch: mips64el
+# CHECK-NEXT: AddressSize: 64bit
+# CHECK-NEXT: LoadName:
+# CHECK-NEXT: ElfHeader {
+# CHECK-NEXT: Ident {
+# CHECK-NEXT: Magic: (7F 45 4C 46)
+# CHECK-NEXT: Class: 64-bit (0x2)
+# CHECK-NEXT: DataEncoding: LittleEndian (0x1)
+# CHECK-NEXT: FileVersion: 1
+# CHECK-NEXT: OS/ABI: SystemV (0x0)
+# CHECK-NEXT: ABIVersion: 0
+# CHECK-NEXT: Unused: (00 00 00 00 00 00 00)
+# CHECK-NEXT: }
+# CHECK-NEXT: Type: SharedObject (0x3)
+# CHECK-NEXT: Machine: EM_MIPS (0x8)
+# CHECK-NEXT: Version: 1
+# CHECK-NEXT: Entry: 0x170
+# CHECK-NEXT: ProgramHeaderOffset: 0x40
+# CHECK-NEXT: SectionHeaderOffset: 0x2140
+# CHECK-NEXT: Flags [ (0x82000007)
+# CHECK-NEXT: EF_MIPS_ARCH_64R2 (0x80000000)
+# CHECK-NEXT: EF_MIPS_CPIC (0x4)
+# CHECK-NEXT: EF_MIPS_MICROMIPS (0x2000000)
+# CHECK-NEXT: EF_MIPS_NOREORDER (0x1)
+# CHECK-NEXT: EF_MIPS_PIC (0x2)
+# CHECK-NEXT: ]
+# CHECK-NEXT: HeaderSize: 64
+# CHECK-NEXT: ProgramHeaderEntrySize: 56
+# CHECK-NEXT: ProgramHeaderCount: 4
+# CHECK-NEXT: SectionHeaderEntrySize: 64
+# CHECK-NEXT: SectionHeaderCount: 11
+# CHECK-NEXT: StringTableSectionIndex: 8
+# CHECK-NEXT:}
+
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC,
+ EF_MIPS_MICROMIPS, EF_MIPS_ARCH_64R2 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x10
+ Size: 0x08
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x10
+ Size: 0x08
+
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ Global:
+ - Name: foo
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x08
+ Other: [ STO_MIPS_MICROMIPS ]
diff --git a/test/elf/Mips/dynlib-fileheader-micro.test b/test/elf/Mips/dynlib-fileheader-micro.test
new file mode 100644
index 000000000000..139b3aa626c9
--- /dev/null
+++ b/test/elf/Mips/dynlib-fileheader-micro.test
@@ -0,0 +1,82 @@
+# Check ELF Header for shared library in case of microMIPS symbols.
+
+# Build shared library
+# RUN: yaml2obj -format=elf %s > %t.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t.o
+# RUN: llvm-readobj -file-headers %t.so | FileCheck %s
+
+# CHECK: Format: ELF32-mips
+# CHECK-NEXT: Arch: mipsel
+# CHECK-NEXT: AddressSize: 32bit
+# CHECK-NEXT: LoadName:
+# CHECK-NEXT: ElfHeader {
+# CHECK-NEXT: Ident {
+# CHECK-NEXT: Magic: (7F 45 4C 46)
+# CHECK-NEXT: Class: 32-bit (0x1)
+# CHECK-NEXT: DataEncoding: LittleEndian (0x1)
+# CHECK-NEXT: FileVersion: 1
+# CHECK-NEXT: OS/ABI: SystemV (0x0)
+# CHECK-NEXT: ABIVersion: 0
+# CHECK-NEXT: Unused: (00 00 00 00 00 00 00)
+# CHECK-NEXT: }
+# CHECK-NEXT: Type: SharedObject (0x3)
+# CHECK-NEXT: Machine: EM_MIPS (0x8)
+# CHECK-NEXT: Version: 1
+# CHECK-NEXT: Entry: 0x100
+# CHECK-NEXT: ProgramHeaderOffset: 0x34
+# CHECK-NEXT: SectionHeaderOffset: 0x2100
+# CHECK-NEXT: Flags [ (0x72001007)
+# CHECK-NEXT: EF_MIPS_ABI_O32 (0x1000)
+# CHECK-NEXT: EF_MIPS_ARCH_32R2 (0x70000000)
+# CHECK-NEXT: EF_MIPS_CPIC (0x4)
+# CHECK-NEXT: EF_MIPS_MICROMIPS (0x2000000)
+# CHECK-NEXT: EF_MIPS_NOREORDER (0x1)
+# CHECK-NEXT: EF_MIPS_PIC (0x2)
+# CHECK-NEXT: ]
+# CHECK-NEXT: HeaderSize: 52
+# CHECK-NEXT: ProgramHeaderEntrySize: 32
+# CHECK-NEXT: ProgramHeaderCount: 4
+# CHECK-NEXT: SectionHeaderEntrySize: 40
+# CHECK-NEXT: SectionHeaderCount: 11
+# CHECK-NEXT: StringTableSectionIndex: 8
+# CHECK-NEXT:}
+
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2, EF_MIPS_MICROMIPS ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x04
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x04
+ Size: 0x00
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x04
+ Size: 0x00
+ - Name: .reginfo
+ Type: SHT_MIPS_REGINFO
+ Flags: [ SHF_ALLOC ]
+ AddressAlign: 0x01
+ Size: 0x18
+ - Name: .MIPS.abiflags
+ Type: SHT_MIPS_ABIFLAGS
+ Flags: [ SHF_ALLOC ]
+ AddressAlign: 0x08
+ Size: 0x18
+
+Symbols:
+ Global:
+ - Name: glob
+ Section: .text
+ Other: [ STO_MIPS_MICROMIPS ]
diff --git a/test/elf/Mips/dynlib-fileheader.test b/test/elf/Mips/dynlib-fileheader.test
new file mode 100644
index 000000000000..5dd9d6a64a71
--- /dev/null
+++ b/test/elf/Mips/dynlib-fileheader.test
@@ -0,0 +1,80 @@
+# Check ELF Header for shared library.
+
+# Build shared library
+# RUN: yaml2obj -format=elf %s > %t.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t.o
+# RUN: llvm-readobj -file-headers %t.so | FileCheck %s
+
+# CHECK: Format: ELF32-mips
+# CHECK: Arch: mipsel
+# CHECK: AddressSize: 32bit
+# CHECK: LoadName:
+# CHECK: ElfHeader {
+# CHECK: Ident {
+# CHECK: Magic: (7F 45 4C 46)
+# CHECK: Class: 32-bit (0x1)
+# CHECK: DataEncoding: LittleEndian (0x1)
+# CHECK: FileVersion: 1
+# CHECK: OS/ABI: SystemV (0x0)
+# CHECK: ABIVersion: 0
+# CHECK: Unused: (00 00 00 00 00 00 00)
+# CHECK: }
+# CHECK: Type: SharedObject (0x3)
+# CHECK: Machine: EM_MIPS (0x8)
+# CHECK: Version: 1
+# CHECK: Entry: 0x100
+# CHECK: ProgramHeaderOffset: 0x34
+# CHECK: SectionHeaderOffset: 0x2100
+# CHECK: Flags [ (0x70001007)
+# CHECK: EF_MIPS_ABI_O32 (0x1000)
+# CHECK: EF_MIPS_ARCH_32R2 (0x70000000)
+# CHECK: EF_MIPS_CPIC (0x4)
+# CHECK: EF_MIPS_NOREORDER (0x1)
+# CHECK: EF_MIPS_PIC (0x2)
+# CHECK: ]
+# CHECK: HeaderSize: 52
+# CHECK: ProgramHeaderEntrySize: 32
+# CHECK: ProgramHeaderCount: 4
+# CHECK: SectionHeaderEntrySize: 40
+# CHECK: SectionHeaderCount: 11
+# CHECK: StringTableSectionIndex: 8
+# CHECK:}
+
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x04
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x04
+ Size: 0x00
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x04
+ Size: 0x00
+ - Name: .reginfo
+ Type: SHT_MIPS_REGINFO
+ Flags: [ SHF_ALLOC ]
+ AddressAlign: 0x01
+ Size: 0x18
+ - Name: .MIPS.abiflags
+ Type: SHT_MIPS_ABIFLAGS
+ Flags: [ SHF_ALLOC ]
+ AddressAlign: 0x08
+ Size: 0x18
+
+Symbols:
+ Global:
+ - Name: glob
+ Section: .text
diff --git a/test/elf/Mips/dynsym-table-1.test b/test/elf/Mips/dynsym-table-1.test
new file mode 100644
index 000000000000..43c48e730405
--- /dev/null
+++ b/test/elf/Mips/dynsym-table-1.test
@@ -0,0 +1,127 @@
+# Check that LLD does not populate an executable file dynamic symbol table
+# by unnecessary symbols.
+# 1. bar.so defines T2
+# 2. foo.so defines T1 and references T2
+# 3. main.o reference T1
+# 4. a.out dynamic table should contain T1 entry only
+
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-bar.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-foo.o
+# RUN: yaml2obj -format=elf -docnum 3 %s > %t-main.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t-bar.so %t-bar.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t-foo.so %t-foo.o %t-bar.so
+# RUN: lld -flavor gnu -target mipsel -e T0 -o %t.exe --as-needed \
+# RUN: %t-main.o %t-foo.so %t-bar.so
+# RUN: llvm-readobj -dt -dynamic-table %t.exe | FileCheck %s
+
+# CHECK: DynamicSymbols [
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: @ (0)
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Local (0x0)
+# CHECK-NEXT: Type: None (0x0)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined (0x0)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: T1@ ({{.*}})
+# CHECK-NEXT: Value: {{.*}}
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: Function (0x2)
+# CHECK-NEXT: Other: 8
+# CHECK-NEXT: Section: Undefined (0x0)
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+
+# CHECK: 0x00000003 PLTGOT 0x401000
+# CHECK-NEXT: 0x00000001 NEEDED SharedLibrary (dynsym-table-1.test.tmp-foo.so)
+# CHECK-NEXT: 0x00000000 NULL 0x0
+
+# bar.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x08
+Symbols:
+ Global:
+ - Name: T2
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x08
+
+# foo.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x08
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x08
+ Info: .text
+ Relocations:
+ - Offset: 0
+ Symbol: T2
+ Type: R_MIPS_CALL16
+Symbols:
+ Global:
+ - Name: T1
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x08
+ - Name: T2
+
+# main.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x08
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x08
+ Info: .text
+ Relocations:
+ - Offset: 0
+ Symbol: T1
+ Type: R_MIPS_32
+Symbols:
+ Global:
+ - Name: T0
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x08
+ - Name: T1
+...
diff --git a/test/elf/Mips/dynsym-table-2.test b/test/elf/Mips/dynsym-table-2.test
new file mode 100644
index 000000000000..538aa758910e
--- /dev/null
+++ b/test/elf/Mips/dynsym-table-2.test
@@ -0,0 +1,105 @@
+# Check that LLD does not populate a shared library dynamic symbol table
+# by unnecessary symbols.
+# 1. bar.so defines T2 and T3
+# 2. foo.so defines T1 and references T2
+# 4. foo.so dynamic table should contain T1 and T2 entries only
+
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-bar.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-foo.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t-bar.so %t-bar.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t-foo.so %t-foo.o %t-bar.so
+# RUN: llvm-readobj -dt -dynamic-table %t-foo.so | FileCheck %s
+
+# CHECK: DynamicSymbols [
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: @ (0)
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Local (0x0)
+# CHECK-NEXT: Type: None (0x0)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined (0x0)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: T1@ ({{.*}})
+# CHECK-NEXT: Value: {{.*}}
+# CHECK-NEXT: Size: 8
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: Function (0x2)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: .text (0x4)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: T2@ ({{.*}})
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: Function (0x2)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined (0x0)
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+
+# CHECK: 0x00000003 PLTGOT 0x1000
+# CHECK-NEXT: 0x00000001 NEEDED SharedLibrary (dynsym-table-2.test.tmp-bar.so)
+# CHECK-NEXT: 0x00000000 NULL 0x0
+
+# bar.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x08
+Symbols:
+ Global:
+ - Name: T2
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x04
+ - Name: T3
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x04
+ Size: 0x04
+
+# foo.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x08
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x08
+ Info: .text
+ Relocations:
+ - Offset: 0
+ Symbol: T2
+ Type: R_MIPS_CALL16
+Symbols:
+ Global:
+ - Name: T1
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x08
+ - Name: T2
+...
diff --git a/test/elf/Mips/e-flags-merge-1-64.test b/test/elf/Mips/e-flags-merge-1-64.test
new file mode 100644
index 000000000000..d5719539baaa
--- /dev/null
+++ b/test/elf/Mips/e-flags-merge-1-64.test
@@ -0,0 +1,30 @@
+# Check that the linker shows an error when object
+# file has unsupported ASE flags.
+
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-mips16.o
+# RUN: not lld -flavor gnu -target mips64el -e T -o %t.exe %t-mips16.o 2>&1 | \
+# RUN: FileCheck -check-prefix=MIPS16 %s
+
+# MIPS16: Unsupported extension: MIPS16
+
+# mips16.o
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ARCH_64, EF_MIPS_ARCH_ASE_M16]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x10
+ Size: 0x08
+
+Symbols:
+ Global:
+ - Name: T
+ Section: .text
+...
diff --git a/test/elf/Mips/e-flags-merge-1.test b/test/elf/Mips/e-flags-merge-1.test
new file mode 100644
index 000000000000..1f1d7aca6c41
--- /dev/null
+++ b/test/elf/Mips/e-flags-merge-1.test
@@ -0,0 +1,56 @@
+# Check that the linker shows an error when object file has missed
+# or unsupported ABI and ARCH flags or unsupported ASE flags.
+
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-no-abi.o
+# RUN: not lld -flavor gnu -target mipsel -e T -o %t.exe %t-no-abi.o 2>&1 | \
+# RUN: FileCheck -check-prefix=INVALID-ABI %s
+
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-mips16.o
+# RUN: not lld -flavor gnu -target mipsel -e T -o %t.exe %t-mips16.o 2>&1 | \
+# RUN: FileCheck -check-prefix=MIPS16 %s
+
+# INVALID-ABI: Unsupported ABI
+# MIPS16: Unsupported extension: MIPS16
+
+# no-abi.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: []
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x04
+
+Symbols:
+ Global:
+ - Name: T
+ Section: .text
+
+# mips16.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ABI_O32, EF_MIPS_ARCH_32, EF_MIPS_ARCH_ASE_M16]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x04
+
+Symbols:
+ Global:
+ - Name: T
+ Section: .text
+...
diff --git a/test/elf/Mips/e-flags-merge-10.test b/test/elf/Mips/e-flags-merge-10.test
new file mode 100644
index 000000000000..a0aa45d5f2c8
--- /dev/null
+++ b/test/elf/Mips/e-flags-merge-10.test
@@ -0,0 +1,43 @@
+# Check that LLD shows an error and does not link files with mips32r2
+# and mips32r6 instructions sets.
+
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-32r2.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-32r6.o
+
+# RUN: not lld -flavor gnu -target mipsel -shared -o %t.so \
+# RUN: %t-32r2.o %t-32r6.o 2>&1 | FileCheck %s
+
+# CHECK: Linking modules with incompatible ISA
+
+# 32r2.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x04
+
+# 32r6.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R6]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x04
+...
diff --git a/test/elf/Mips/e-flags-merge-11.test b/test/elf/Mips/e-flags-merge-11.test
new file mode 100644
index 000000000000..b4c0039bd198
--- /dev/null
+++ b/test/elf/Mips/e-flags-merge-11.test
@@ -0,0 +1,43 @@
+# Check that LLD shows an error and does not link files with mips64r2
+# and mips64r6 instructions sets.
+
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-64r2.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-64r6.o
+
+# RUN: not lld -flavor gnu -target mips64el -shared -o %t.so \
+# RUN: %t-64r2.o %t-64r6.o 2>&1 | FileCheck %s
+
+# CHECK: Linking modules with incompatible ISA
+
+# 64r2.o
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ARCH_64R2]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x04
+
+# 64r6.o
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ARCH_64R6]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x04
+...
diff --git a/test/elf/Mips/e-flags-merge-2-64.test b/test/elf/Mips/e-flags-merge-2-64.test
new file mode 100644
index 000000000000..a169e7ea1645
--- /dev/null
+++ b/test/elf/Mips/e-flags-merge-2-64.test
@@ -0,0 +1,33 @@
+# Check that the linker copies ELF header flags from the single input object
+# file to the generated executable
+
+# RUN: yaml2obj -format=elf %s > %t.o
+# RUN: lld -flavor gnu -target mips64el -e T -o %t.exe %t.o
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
+
+# CHECK: Flags [ (0x62000001)
+# CHECK-NEXT: EF_MIPS_ARCH_64 (0x60000000)
+# CHECK-NEXT: EF_MIPS_MICROMIPS (0x2000000)
+# CHECK-NEXT: EF_MIPS_NOREORDER (0x1)
+# CHECK-NEXT: ]
+
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_ARCH_64, EF_MIPS_NOREORDER, EF_MIPS_MICROMIPS ]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x10
+ Size: 0x08
+
+Symbols:
+ Global:
+ - Name: T
+ Section: .text
+...
diff --git a/test/elf/Mips/e-flags-merge-2.test b/test/elf/Mips/e-flags-merge-2.test
new file mode 100644
index 000000000000..41d4a0b0c45e
--- /dev/null
+++ b/test/elf/Mips/e-flags-merge-2.test
@@ -0,0 +1,35 @@
+# Check that the linker copies ELF header flags from the single input object
+# file to the generated executable
+
+# RUN: yaml2obj -format=elf %s > %t.o
+# RUN: lld -flavor gnu -target mipsel -e T -o %t.exe %t.o
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
+
+# CHECK: Flags [ (0x52001001)
+# CHECK-NEXT: EF_MIPS_ABI_O32 (0x1000)
+# CHECK-NEXT: EF_MIPS_ARCH_32 (0x50000000)
+# CHECK-NEXT: EF_MIPS_MICROMIPS (0x2000000)
+# CHECK-NEXT: EF_MIPS_NOREORDER (0x1)
+# CHECK-NEXT: ]
+
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ABI_O32, EF_MIPS_ARCH_32,
+ EF_MIPS_NOREORDER, EF_MIPS_MICROMIPS]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x04
+
+Symbols:
+ Global:
+ - Name: T
+ Section: .text
+...
diff --git a/test/elf/Mips/e-flags-merge-3-64.test b/test/elf/Mips/e-flags-merge-3-64.test
new file mode 100644
index 000000000000..54065a63fb94
--- /dev/null
+++ b/test/elf/Mips/e-flags-merge-3-64.test
@@ -0,0 +1,130 @@
+# Check PIC/CPIC flags merging in case of multiple input objects.
+
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-none.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-cpic.o
+# RUN: yaml2obj -format=elf -docnum 3 %s > %t-pic.o
+# RUN: yaml2obj -format=elf -docnum 4 %s > %t-both.o
+
+# RUN: lld -flavor gnu -target mips64el -e T1 -o %t-abi1.exe \
+# RUN: %t-none.o %t-pic.o 2>&1 | FileCheck -check-prefix=ABI-CALLS-WARN %s
+# RUN: llvm-readobj -file-headers %t-abi1.exe \
+# RUN: | FileCheck -check-prefix=ABI-CALLS1 %s
+
+# RUN: lld -flavor gnu -target mips64el -e T1 -o %t-abi2.exe \
+# RUN: %t-cpic.o %t-none.o 2>&1 | FileCheck -check-prefix=ABI-CALLS-WARN %s
+# RUN: llvm-readobj -file-headers %t-abi2.exe \
+# RUN: | FileCheck -check-prefix=ABI-CALLS2 %s
+
+# RUN: lld -flavor gnu -target mips64el -e T2 -o %t-cpic.exe %t-cpic.o %t-pic.o
+# RUN: llvm-readobj -file-headers %t-cpic.exe | FileCheck -check-prefix=CPIC %s
+
+# RUN: lld -flavor gnu -target mips64el -e T3 -o %t-both.exe %t-pic.o %t-both.o
+# RUN: llvm-readobj -file-headers %t-both.exe | FileCheck -check-prefix=BOTH %s
+
+# ABI-CALLS-WARN: lld warning: linking abicalls and non-abicalls files
+
+# ABI-CALLS1: Flags [ (0x60000004)
+# ABI-CALLS1-NEXT: EF_MIPS_ARCH_64 (0x60000000)
+# ABI-CALLS1-NEXT: EF_MIPS_CPIC (0x4)
+# ABI-CALLS1-NEXT: ]
+
+# ABI-CALLS2: Flags [ (0x60000004)
+# ABI-CALLS2-NEXT: EF_MIPS_ARCH_64 (0x60000000)
+# ABI-CALLS2-NEXT: EF_MIPS_CPIC (0x4)
+# ABI-CALLS2-NEXT: ]
+
+# CPIC: Flags [ (0x60000004)
+# CPIC-NEXT: EF_MIPS_ARCH_64 (0x60000000)
+# CPIC-NEXT: EF_MIPS_CPIC (0x4)
+# CPIC-NEXT: ]
+
+# BOTH: Flags [ (0x60000006)
+# BOTH-NEXT: EF_MIPS_ARCH_64 (0x60000000)
+# BOTH-NEXT: EF_MIPS_CPIC (0x4)
+# BOTH-NEXT: EF_MIPS_PIC (0x2)
+# BOTH-NEXT: ]
+
+# none.o
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ARCH_64]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x10
+ Size: 0x08
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+
+# cpic.o
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ARCH_64, EF_MIPS_CPIC]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x10
+ Size: 0x08
+
+Symbols:
+ Global:
+ - Name: T2
+ Section: .text
+
+# pic.o
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ARCH_64, EF_MIPS_PIC]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x10
+ Size: 0x08
+
+Symbols:
+ Global:
+ - Name: T3
+ Section: .text
+
+# both.o
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ARCH_64, EF_MIPS_CPIC, EF_MIPS_PIC]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x10
+ Size: 0x08
+
+Symbols:
+ Global:
+ - Name: T4
+ Section: .text
+...
diff --git a/test/elf/Mips/e-flags-merge-3.test b/test/elf/Mips/e-flags-merge-3.test
new file mode 100644
index 000000000000..e2d9f6c2e2fc
--- /dev/null
+++ b/test/elf/Mips/e-flags-merge-3.test
@@ -0,0 +1,134 @@
+# Check PIC/CPIC flags merging in case of multiple input objects.
+
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-none.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-cpic.o
+# RUN: yaml2obj -format=elf -docnum 3 %s > %t-pic.o
+# RUN: yaml2obj -format=elf -docnum 4 %s > %t-both.o
+
+# RUN: lld -flavor gnu -target mipsel -e T1 -o %t-abi1.exe \
+# RUN: %t-none.o %t-pic.o 2>&1 | FileCheck -check-prefix=ABI-CALLS-WARN %s
+# RUN: llvm-readobj -file-headers %t-abi1.exe \
+# RUN: | FileCheck -check-prefix=ABI-CALLS1 %s
+
+# RUN: lld -flavor gnu -target mipsel -e T1 -o %t-abi2.exe \
+# RUN: %t-cpic.o %t-none.o 2>&1 | FileCheck -check-prefix=ABI-CALLS-WARN %s
+# RUN: llvm-readobj -file-headers %t-abi2.exe \
+# RUN: | FileCheck -check-prefix=ABI-CALLS2 %s
+
+# RUN: lld -flavor gnu -target mipsel -e T2 -o %t-cpic.exe %t-cpic.o %t-pic.o
+# RUN: llvm-readobj -file-headers %t-cpic.exe | FileCheck -check-prefix=CPIC %s
+
+# RUN: lld -flavor gnu -target mipsel -e T3 -o %t-both.exe %t-pic.o %t-both.o
+# RUN: llvm-readobj -file-headers %t-both.exe | FileCheck -check-prefix=BOTH %s
+
+# ABI-CALLS-WARN: lld warning: linking abicalls and non-abicalls files
+
+# ABI-CALLS1: Flags [ (0x50001004)
+# ABI-CALLS1-NEXT: EF_MIPS_ABI_O32 (0x1000)
+# ABI-CALLS1-NEXT: EF_MIPS_ARCH_32 (0x50000000)
+# ABI-CALLS1-NEXT: EF_MIPS_CPIC (0x4)
+# ABI-CALLS1-NEXT: ]
+
+# ABI-CALLS2: Flags [ (0x50001004)
+# ABI-CALLS2-NEXT: EF_MIPS_ABI_O32 (0x1000)
+# ABI-CALLS2-NEXT: EF_MIPS_ARCH_32 (0x50000000)
+# ABI-CALLS2-NEXT: EF_MIPS_CPIC (0x4)
+# ABI-CALLS2-NEXT: ]
+
+# CPIC: Flags [ (0x50001004)
+# CPIC-NEXT: EF_MIPS_ABI_O32 (0x1000)
+# CPIC-NEXT: EF_MIPS_ARCH_32 (0x50000000)
+# CPIC-NEXT: EF_MIPS_CPIC (0x4)
+# CPIC-NEXT: ]
+
+# BOTH: Flags [ (0x50001006)
+# BOTH-NEXT: EF_MIPS_ABI_O32 (0x1000)
+# BOTH-NEXT: EF_MIPS_ARCH_32 (0x50000000)
+# BOTH-NEXT: EF_MIPS_CPIC (0x4)
+# BOTH-NEXT: EF_MIPS_PIC (0x2)
+# BOTH-NEXT: ]
+
+# none.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x04
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+
+# cpic.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ABI_O32, EF_MIPS_ARCH_32, EF_MIPS_CPIC]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x04
+
+Symbols:
+ Global:
+ - Name: T2
+ Section: .text
+
+# pic.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ABI_O32, EF_MIPS_ARCH_32, EF_MIPS_PIC]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x04
+
+Symbols:
+ Global:
+ - Name: T3
+ Section: .text
+
+# both.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ABI_O32, EF_MIPS_ARCH_32, EF_MIPS_CPIC, EF_MIPS_PIC]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x04
+
+Symbols:
+ Global:
+ - Name: T4
+ Section: .text
+...
diff --git a/test/elf/Mips/e-flags-merge-4-64.test b/test/elf/Mips/e-flags-merge-4-64.test
new file mode 100644
index 000000000000..9ffa61343711
--- /dev/null
+++ b/test/elf/Mips/e-flags-merge-4-64.test
@@ -0,0 +1,64 @@
+# Check ELF flags merging.
+
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-none.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-noreorder.o
+# RUN: yaml2obj -format=elf -docnum 3 %s > %t-micro.o
+
+# RUN: lld -flavor gnu -target mips64el -shared -o %t.so \
+# RUN: %t-none.o %t-noreorder.o %t-micro.o
+# RUN: llvm-readobj -file-headers %t.so | FileCheck %s
+
+# CHECK: Flags [ (0x82000001)
+# CHECK-NEXT: EF_MIPS_ARCH_64R2 (0x80000000)
+# CHECK-NEXT: EF_MIPS_MICROMIPS (0x2000000)
+# CHECK-NEXT: EF_MIPS_NOREORDER (0x1)
+# CHECK-NEXT: ]
+
+# none.o
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ARCH_5]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x10
+ Size: 0x08
+
+# noreorder.o
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ARCH_64, EF_MIPS_NOREORDER]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x10
+ Size: 0x08
+
+# micro.o
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ARCH_64R2, EF_MIPS_MICROMIPS]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x10
+ Size: 0x08
+...
diff --git a/test/elf/Mips/e-flags-merge-4.test b/test/elf/Mips/e-flags-merge-4.test
new file mode 100644
index 000000000000..096b04d676e9
--- /dev/null
+++ b/test/elf/Mips/e-flags-merge-4.test
@@ -0,0 +1,65 @@
+# Check ELF flags merging.
+
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-none.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-noreorder.o
+# RUN: yaml2obj -format=elf -docnum 3 %s > %t-micro.o
+
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so \
+# RUN: %t-none.o %t-noreorder.o %t-micro.o
+# RUN: llvm-readobj -file-headers %t.so | FileCheck %s
+
+# CHECK: Flags [ (0x52001001)
+# CHECK-NEXT: EF_MIPS_ABI_O32 (0x1000)
+# CHECK-NEXT: EF_MIPS_ARCH_32 (0x50000000)
+# CHECK-NEXT: EF_MIPS_MICROMIPS (0x2000000)
+# CHECK-NEXT: EF_MIPS_NOREORDER (0x1)
+# CHECK-NEXT: ]
+
+# none.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x04
+
+# noreorder.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ABI_O32, EF_MIPS_ARCH_32, EF_MIPS_NOREORDER]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x04
+
+# micro.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ABI_O32, EF_MIPS_ARCH_32, EF_MIPS_MICROMIPS]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x04
+...
diff --git a/test/elf/Mips/e-flags-merge-5-64.test b/test/elf/Mips/e-flags-merge-5-64.test
new file mode 100644
index 000000000000..e629aedbc154
--- /dev/null
+++ b/test/elf/Mips/e-flags-merge-5-64.test
@@ -0,0 +1,42 @@
+# Check that LLD does not allow to mix 32 and 64-bit MIPS object files.
+
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-32.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-64.o
+
+# RUN: not lld -flavor gnu -target mips64el -shared -o %t.so \
+# RUN: %t-32.o %t-64.o 2>&1 | FileCheck %s
+
+# CHECK: Bitness is incompatible with that of the selected target
+
+# 32.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x04
+
+# 64.o
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ARCH_64]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x10
+ Size: 0x08
+...
diff --git a/test/elf/Mips/e-flags-merge-5.test b/test/elf/Mips/e-flags-merge-5.test
new file mode 100644
index 000000000000..3b5b397ab780
--- /dev/null
+++ b/test/elf/Mips/e-flags-merge-5.test
@@ -0,0 +1,42 @@
+# Check that LLD does not allow to mix 32 and 64-bit MIPS object files.
+
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-32.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-64.o
+
+# RUN: not lld -flavor gnu -target mipsel -shared -o %t.so \
+# RUN: %t-32.o %t-64.o 2>&1 | FileCheck %s
+
+# CHECK: Bitness is incompatible with that of the selected target
+
+# 32.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x04
+
+# 64.o
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ARCH_64]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x04
+...
diff --git a/test/elf/Mips/e-flags-merge-6-64.test b/test/elf/Mips/e-flags-merge-6-64.test
new file mode 100644
index 000000000000..fbc32b7135b2
--- /dev/null
+++ b/test/elf/Mips/e-flags-merge-6-64.test
@@ -0,0 +1,79 @@
+# Check selecting ELF header ARCH flag.
+
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-m3.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-m5.o
+# RUN: yaml2obj -format=elf -docnum 3 %s > %t-m64.o
+# RUN: yaml2obj -format=elf -docnum 4 %s > %t-m64r2.o
+
+# RUN: lld -flavor gnu -target mips64el -shared -o %t.so \
+# RUN: %t-m64.o %t-m5.o %t-m64r2.o %t-m3.o
+# RUN: llvm-readobj -file-headers %t.so | FileCheck %s
+
+# CHECK: Flags [ (0x80000000)
+# CHECK-NEXT: EF_MIPS_ARCH_64R2 (0x80000000)
+# CHECK-NEXT: ]
+
+# m3.o
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ARCH_3]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x10
+ Size: 0x08
+
+# m5.o
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ARCH_5]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x10
+ Size: 0x08
+
+# m64.o
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ARCH_64]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x10
+ Size: 0x08
+
+# m64r2.o
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ARCH_64R2]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x10
+ Size: 0x08
+...
diff --git a/test/elf/Mips/e-flags-merge-6.test b/test/elf/Mips/e-flags-merge-6.test
new file mode 100644
index 000000000000..759c8b63c97d
--- /dev/null
+++ b/test/elf/Mips/e-flags-merge-6.test
@@ -0,0 +1,80 @@
+# Check selecting ELF header ARCH flag.
+
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-m1.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-m2.o
+# RUN: yaml2obj -format=elf -docnum 3 %s > %t-m32.o
+# RUN: yaml2obj -format=elf -docnum 4 %s > %t-m32r2.o
+
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so \
+# RUN: %t-m32.o %t-m2.o %t-m32r2.o %t-m1.o
+# RUN: llvm-readobj -file-headers %t.so | FileCheck %s
+
+# CHECK: Flags [ (0x70001000)
+# CHECK-NEXT: EF_MIPS_ABI_O32 (0x1000)
+# CHECK-NEXT: EF_MIPS_ARCH_32R2 (0x70000000)
+# CHECK-NEXT: ]
+
+# m1.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ABI_O32, EF_MIPS_ARCH_1]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x04
+
+# m2.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ABI_O32, EF_MIPS_ARCH_2]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x04
+
+# m32.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x04
+
+# m32r2.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x04
+...
diff --git a/test/elf/Mips/e-flags-merge-7-64.test b/test/elf/Mips/e-flags-merge-7-64.test
new file mode 100644
index 000000000000..07ed6bb54836
--- /dev/null
+++ b/test/elf/Mips/e-flags-merge-7-64.test
@@ -0,0 +1,42 @@
+# Check that LLD does not allow to mix nan2008 and legacy MIPS object files.
+
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-2008.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-legacy.o
+
+# RUN: not lld -flavor gnu -target mips64el -shared -o %t.so \
+# RUN: %t-2008.o %t-legacy.o 2>&1 | FileCheck %s
+
+# CHECK: Linking -mnan=2008 and -mnan=legacy modules
+
+# 2008.o
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ARCH_64, EF_MIPS_NAN2008]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x10
+ Size: 0x08
+
+# legacy.o
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ARCH_64]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x10
+ Size: 0x08
+...
diff --git a/test/elf/Mips/e-flags-merge-7.test b/test/elf/Mips/e-flags-merge-7.test
new file mode 100644
index 000000000000..7e114ff968fe
--- /dev/null
+++ b/test/elf/Mips/e-flags-merge-7.test
@@ -0,0 +1,42 @@
+# Check that LLD does not allow to mix nan2008 and legacy MIPS object files.
+
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-2008.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-legacy.o
+
+# RUN: not lld -flavor gnu -target mipsel -shared -o %t.so \
+# RUN: %t-2008.o %t-legacy.o 2>&1 | FileCheck %s
+
+# CHECK: Linking -mnan=2008 and -mnan=legacy modules
+
+# 2008.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ABI_O32, EF_MIPS_ARCH_32, EF_MIPS_NAN2008]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x04
+
+# legacy.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x04
+...
diff --git a/test/elf/Mips/e-flags-merge-8.test b/test/elf/Mips/e-flags-merge-8.test
new file mode 100644
index 000000000000..57af77d70260
--- /dev/null
+++ b/test/elf/Mips/e-flags-merge-8.test
@@ -0,0 +1,65 @@
+# Check that LLD links files with mips32 and mips64 instructions
+# if all these files satisfy O32 ABI.
+
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-32.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-64.o
+# RUN: yaml2obj -format=elf -docnum 3 %s > %t-64r2.o
+
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t-32.o %t-64.o %t-64r2.o
+# RUN: llvm-readobj -file-headers %t.so | FileCheck %s
+
+# CHECK: Flags [ (0x80001100)
+# CHECK-NEXT: EF_MIPS_32BITMODE (0x100)
+# CHECK-NEXT: EF_MIPS_ABI_O32 (0x1000)
+# CHECK-NEXT: EF_MIPS_ARCH_64R2 (0x80000000)
+# CHECK-NEXT: ]
+
+
+# 32.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x04
+
+# 64.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ABI_O32, EF_MIPS_ARCH_64, EF_MIPS_32BITMODE]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x04
+
+# 64r2.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ABI_O32, EF_MIPS_ARCH_64R2, EF_MIPS_32BITMODE]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x04
+...
diff --git a/test/elf/Mips/e-flags-merge-9.test b/test/elf/Mips/e-flags-merge-9.test
new file mode 100644
index 000000000000..dea32f07cb9e
--- /dev/null
+++ b/test/elf/Mips/e-flags-merge-9.test
@@ -0,0 +1,43 @@
+# Check that LLD shows an error and does not link files with mips32r2
+# and mips64 instructions sets.
+
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-32r2.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-64.o
+
+# RUN: not lld -flavor gnu -target mipsel -shared -o %t.so \
+# RUN: %t-32r2.o %t-64.o 2>&1 | FileCheck %s
+
+# CHECK: Linking modules with incompatible ISA
+
+# 32r2.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x04
+
+# 64.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ABI_O32, EF_MIPS_ARCH_64, EF_MIPS_32BITMODE]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x04
+...
diff --git a/test/elf/Mips/entry-name.test b/test/elf/Mips/entry-name.test
new file mode 100644
index 000000000000..b10adc68bde8
--- /dev/null
+++ b/test/elf/Mips/entry-name.test
@@ -0,0 +1,26 @@
+# Check name of executable entry symbol.
+# RUN: yaml2obj -format=elf %s > %t.o
+# RUN: lld -flavor gnu -target mipsel --noinhibit-exec -o %t.exe %t.o
+# RUN: llvm-nm %t.exe | FileCheck %s
+
+# CHECK: U __start
+# CHECK: 00400108 T main
+
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32 ]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x04
+
+Symbols:
+ Global:
+ - Name: main
+ Section: .text
diff --git a/test/elf/Mips/exe-dynamic.test b/test/elf/Mips/exe-dynamic.test
new file mode 100644
index 000000000000..28d2b13fbce8
--- /dev/null
+++ b/test/elf/Mips/exe-dynamic.test
@@ -0,0 +1,108 @@
+# Check MIPS specific tags in the dynamic table in case executable linking.
+
+# Build shared library
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-so.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t-so.o
+
+# Build executable
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-o.o
+# RUN: lld -flavor gnu -target mipsel -e glob -o %t.exe %t-o.o %t.so
+# RUN: llvm-readobj -dynamic-table %t.exe | FileCheck %s
+
+# CHECK: Format: ELF32-mips
+# CHECK: Arch: mipsel
+# CHECK: AddressSize: 32bit
+# CHECK: LoadName:
+# CHECK: DynamicSection [ (18 entries)
+# CHECK: Tag Type Name/Value
+# CHECK-NEXT: 0x00000004 HASH 0x400104
+# CHECK-NEXT: 0x00000005 STRTAB 0x400138
+# CHECK-NEXT: 0x00000006 SYMTAB 0x400118
+# CHECK-NEXT: 0x0000000A STRSZ 28 (bytes)
+# CHECK-NEXT: 0x0000000B SYMENT 16 (bytes)
+# CHECK-NEXT: 0x00000002 PLTRELSZ 8 (bytes)
+# CHECK-NEXT: 0x70000032 MIPS_PLTGOT 0x402000
+# CHECK-NEXT: 0x00000014 PLTREL REL
+# CHECK-NEXT: 0x00000017 JMPREL 0x400154
+# CHECK-NEXT: 0x70000001 MIPS_RLD_VERSION 1
+# CHECK-NEXT: 0x70000005 MIPS_FLAGS NOTPOT
+# CHECK-NEXT: 0x70000006 MIPS_BASE_ADDRESS 0x400000
+# CHECK-NEXT: 0x7000000A MIPS_LOCAL_GOTNO 2
+# CHECK-NEXT: 0x70000011 MIPS_SYMTABNO 2
+# CHECK-NEXT: 0x70000013 MIPS_GOTSYM 0x2
+# CHECK-NEXT: 0x00000003 PLTGOT 0x401000
+# CHECK-NEXT: 0x00000001 NEEDED SharedLibrary (exe-dynamic.test.tmp.so)
+# CHECK-NEXT: 0x00000000 NULL 0x0
+# CHECK-NEXT: ]
+
+# so.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+
+# o.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_PIC, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Content: 0000000C000000000000000C000000000000000C00000000
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x04
+ Info: .text
+ Relocations:
+ - Offset: 0x00
+ Symbol: T1
+ Type: R_MIPS_26
+ Addend: 0
+ - Offset: 0x08
+ Symbol: .text
+ Type: R_MIPS_26
+ Addend: 0
+ - Offset: 0x10
+ Symbol: glob
+ Type: R_MIPS_26
+ Addend: 0
+
+Symbols:
+ Local:
+ - Name: loc
+ Section: .text
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ Global:
+ - Name: glob
+ Section: .text
+ Value: 0x08
+ - Name: T1
+...
diff --git a/test/elf/Mips/exe-dynsym-micro.test b/test/elf/Mips/exe-dynsym-micro.test
new file mode 100644
index 000000000000..e3b00277ef6a
--- /dev/null
+++ b/test/elf/Mips/exe-dynsym-micro.test
@@ -0,0 +1,94 @@
+# Check that symbol referenced by an entry in the global part of GOT
+# has a corresponded entry in the .dynsym section. This test covers
+# the case when the GOT entry created because of the R_MICROMIPS_GOT16
+# relocation.
+
+# Build executable
+# RUN: yaml2obj -format=elf %s > %t.o
+# RUN: lld -flavor gnu -target mipsel -e glob -o %t.exe %t.o
+# RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck -check-prefix=CHECK-DYN %s
+
+# Build executabl (yaml format)e
+# RUN: lld -flavor gnu -target mipsel -e glob \
+# RUN: --output-filetype=yaml -o %t.yaml %t.o
+# RUN: FileCheck -check-prefix=CHECK-GOT %s < %t.yaml
+
+# CHECK-DYN: Format: ELF32-mips
+# CHECK-DYN: Arch: mipsel
+# CHECK-DYN: AddressSize: 32bit
+# CHECK-DYN: LoadName:
+# CHECK-DYN: DynamicSymbols [
+# CHECK-DYN: Symbol {
+# CHECK-DYN: Name: @ (0)
+# CHECK-DYN: Value: 0x0
+# CHECK-DYN: Size: 0
+# CHECK-DYN: Binding: Local (0x0)
+# CHECK-DYN: Type: None (0x0)
+# CHECK-DYN: Other: 0
+# CHECK-DYN: Section: Undefined (0x0)
+# CHECK-DYN: }
+# CHECK-DYN: Symbol {
+# CHECK-DYN: Name: weakf@ (1)
+# CHECK-DYN: Value: 0x0
+# CHECK-DYN: Size: 0
+# CHECK-DYN: Binding: Weak (0x2)
+# CHECK-DYN: Type: None (0x0)
+# CHECK-DYN: Other: 0
+# CHECK-DYN: Section: Undefined (0x0)
+# CHECK-DYN: }
+# CHECK-DYN: ]
+
+# CHECK-GOT: - type: got
+# CHECK-GOT: content: [ 00, 00, 00, 00 ]
+# CHECK-GOT: alignment: 2^2
+# CHECK-GOT: section-choice: custom-required
+# CHECK-GOT: section-name: .got
+# CHECK-GOT: permissions: rw-
+# CHECK-GOT: - type: got
+# CHECK-GOT: content: [ 00, 00, 00, 80 ]
+# CHECK-GOT: alignment: 2^2
+# CHECK-GOT: section-choice: custom-required
+# CHECK-GOT: section-name: .got
+# CHECK-GOT: permissions: rw-
+# CHECK-GOT: - ref-name: L000
+# CHECK-GOT: type: got
+# CHECK-GOT: content: [ 00, 00, 00, 00 ]
+# CHECK-GOT: alignment: 2^2
+# CHECK-GOT: section-choice: custom-required
+# CHECK-GOT: section-name: .got
+# CHECK-GOT: permissions: rw-
+# CHECK-GOT: references:
+# CHECK-GOT: - kind: LLD_R_MIPS_GLOBAL_GOT
+# CHECK-GOT: offset: 0
+# CHECK-GOT: target: weakf
+
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_PIC, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2, EF_MIPS_MICROMIPS ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x10
+ Size: 0x04
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x04
+ Info: .text
+ Relocations:
+ - Offset: 0x00
+ Symbol: weakf
+ Type: R_MICROMIPS_GOT16
+
+Symbols:
+ Global:
+ - Name: glob
+ Section: .text
+ Other: [ STO_MIPS_MICROMIPS ]
+ Weak:
+ - Name: weakf
diff --git a/test/elf/Mips/exe-dynsym.test b/test/elf/Mips/exe-dynsym.test
new file mode 100644
index 000000000000..a59916c4be4c
--- /dev/null
+++ b/test/elf/Mips/exe-dynsym.test
@@ -0,0 +1,91 @@
+# Check that symbol referenced by an entry in the global part of GOT
+# has a corresponded entry in the .dynsym section.
+
+# Build executable
+# RUN: yaml2obj -format=elf %s > %t.o
+# RUN: lld -flavor gnu -target mipsel -e glob -o %t.exe %t.o
+# RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck -check-prefix=CHECK-DYN %s
+
+# Build executabl (yaml format)e
+# RUN: lld -flavor gnu -target mipsel -e glob \
+# RUN: --output-filetype=yaml -o %t.yaml %t.o
+# RUN: FileCheck -check-prefix=CHECK-GOT %s < %t.yaml
+
+# CHECK-DYN: Format: ELF32-mips
+# CHECK-DYN: Arch: mipsel
+# CHECK-DYN: AddressSize: 32bit
+# CHECK-DYN: LoadName:
+# CHECK-DYN: DynamicSymbols [
+# CHECK-DYN: Symbol {
+# CHECK-DYN: Name: @ (0)
+# CHECK-DYN: Value: 0x0
+# CHECK-DYN: Size: 0
+# CHECK-DYN: Binding: Local (0x0)
+# CHECK-DYN: Type: None (0x0)
+# CHECK-DYN: Other: 0
+# CHECK-DYN: Section: Undefined (0x0)
+# CHECK-DYN: }
+# CHECK-DYN: Symbol {
+# CHECK-DYN: Name: weakf@ (1)
+# CHECK-DYN: Value: 0x0
+# CHECK-DYN: Size: 0
+# CHECK-DYN: Binding: Weak (0x2)
+# CHECK-DYN: Type: None (0x0)
+# CHECK-DYN: Other: 0
+# CHECK-DYN: Section: Undefined (0x0)
+# CHECK-DYN: }
+# CHECK-DYN: ]
+
+# CHECK-GOT: - type: got
+# CHECK-GOT: content: [ 00, 00, 00, 00 ]
+# CHECK-GOT: alignment: 2^2
+# CHECK-GOT: section-choice: custom-required
+# CHECK-GOT: section-name: .got
+# CHECK-GOT: permissions: rw-
+# CHECK-GOT: - type: got
+# CHECK-GOT: content: [ 00, 00, 00, 80 ]
+# CHECK-GOT: alignment: 2^2
+# CHECK-GOT: section-choice: custom-required
+# CHECK-GOT: section-name: .got
+# CHECK-GOT: permissions: rw-
+# CHECK-GOT: - ref-name: L000
+# CHECK-GOT: type: got
+# CHECK-GOT: content: [ 00, 00, 00, 00 ]
+# CHECK-GOT: alignment: 2^2
+# CHECK-GOT: section-choice: custom-required
+# CHECK-GOT: section-name: .got
+# CHECK-GOT: permissions: rw-
+# CHECK-GOT: references:
+# CHECK-GOT: - kind: LLD_R_MIPS_GLOBAL_GOT
+# CHECK-GOT: offset: 0
+# CHECK-GOT: target: weakf
+
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_PIC, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x10
+ Size: 0x04
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x04
+ Info: .text
+ Relocations:
+ - Offset: 0x00
+ Symbol: weakf
+ Type: R_MIPS_GOT16
+
+Symbols:
+ Global:
+ - Name: glob
+ Section: .text
+ Weak:
+ - Name: weakf
diff --git a/test/elf/Mips/exe-fileheader-64.test b/test/elf/Mips/exe-fileheader-64.test
new file mode 100644
index 000000000000..63baff53e678
--- /dev/null
+++ b/test/elf/Mips/exe-fileheader-64.test
@@ -0,0 +1,66 @@
+# Check ELF Header for 64-bit executable file.
+
+# Build executable
+# RUN: yaml2obj -format=elf %s > %t-o.o
+# RUN: lld -flavor gnu -target mips64el -e glob -o %t.exe %t-o.o
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
+
+# CHECK: Format: ELF64-mips
+# CHECK: Arch: mips64el
+# CHECK: AddressSize: 64bit
+# CHECK: LoadName:
+# CHECK: ElfHeader {
+# CHECK: Ident {
+# CHECK: Magic: (7F 45 4C 46)
+# CHECK: Class: 64-bit (0x2)
+# CHECK: DataEncoding: LittleEndian (0x1)
+# CHECK: FileVersion: 1
+# CHECK: OS/ABI: SystemV (0x0)
+# CHECK: ABIVersion: 0
+# CHECK: Unused: (00 00 00 00 00 00 00)
+# CHECK: }
+# CHECK: Type: Executable (0x2)
+# CHECK: Machine: EM_MIPS (0x8)
+# CHECK: Version: 1
+# CHECK: Entry: 0x1200001A0
+# CHECK: ProgramHeaderOffset: 0x40
+# CHECK: SectionHeaderOffset: 0x1300
+# CHECK: Flags [ (0x60000007)
+# CHECK: EF_MIPS_ARCH_64 (0x60000000)
+# CHECK: EF_MIPS_CPIC (0x4)
+# CHECK: EF_MIPS_NOREORDER (0x1)
+# CHECK: EF_MIPS_PIC (0x2)
+# CHECK: ]
+# CHECK: HeaderSize: 64
+# CHECK: ProgramHeaderEntrySize: 56
+# CHECK: ProgramHeaderCount: 5
+# CHECK: SectionHeaderEntrySize: 64
+# CHECK: SectionHeaderCount: 11
+# CHECK: StringTableSectionIndex: 8
+# CHECK: }
+
+# o.o
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC,
+ EF_MIPS_ARCH_64 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x10
+ Size: 0x08
+
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ Global:
+ - Name: glob
+ Section: .text
+...
diff --git a/test/elf/Mips/exe-fileheader-micro-64.test b/test/elf/Mips/exe-fileheader-micro-64.test
new file mode 100644
index 000000000000..044c2f729f38
--- /dev/null
+++ b/test/elf/Mips/exe-fileheader-micro-64.test
@@ -0,0 +1,68 @@
+# Check ELF Header for 64-bit executable file in case of microMIPS entry symbol.
+
+# Build executable
+# RUN: yaml2obj -format=elf %s > %t-o.o
+# RUN: lld -flavor gnu -target mips64el -e glob -o %t.exe %t-o.o
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
+
+# CHECK: Format: ELF64-mips
+# CHECK: Arch: mips64el
+# CHECK: AddressSize: 64bit
+# CHECK: LoadName:
+# CHECK: ElfHeader {
+# CHECK: Ident {
+# CHECK: Magic: (7F 45 4C 46)
+# CHECK: Class: 64-bit (0x2)
+# CHECK: DataEncoding: LittleEndian (0x1)
+# CHECK: FileVersion: 1
+# CHECK: OS/ABI: SystemV (0x0)
+# CHECK: ABIVersion: 0
+# CHECK: Unused: (00 00 00 00 00 00 00)
+# CHECK: }
+# CHECK: Type: Executable (0x2)
+# CHECK: Machine: EM_MIPS (0x8)
+# CHECK: Version: 1
+# CHECK: Entry: 0x1200001A1
+# CHECK: ProgramHeaderOffset: 0x40
+# CHECK: SectionHeaderOffset: 0x1300
+# CHECK: Flags [ (0x82000007)
+# CHECK: EF_MIPS_ARCH_64R2 (0x80000000)
+# CHECK: EF_MIPS_CPIC (0x4)
+# CHECK: EF_MIPS_MICROMIPS (0x2000000)
+# CHECK: EF_MIPS_NOREORDER (0x1)
+# CHECK: EF_MIPS_PIC (0x2)
+# CHECK: ]
+# CHECK: HeaderSize: 64
+# CHECK: ProgramHeaderEntrySize: 56
+# CHECK: ProgramHeaderCount: 5
+# CHECK: SectionHeaderEntrySize: 64
+# CHECK: SectionHeaderCount: 11
+# CHECK: StringTableSectionIndex: 8
+# CHECK: }
+
+# o.o
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC,
+ EF_MIPS_MICROMIPS, EF_MIPS_ARCH_64R2 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x10
+ Size: 0x08
+
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ Global:
+ - Name: glob
+ Section: .text
+ Other: [ STO_MIPS_MICROMIPS ]
+...
diff --git a/test/elf/Mips/exe-fileheader-micro.test b/test/elf/Mips/exe-fileheader-micro.test
new file mode 100644
index 000000000000..351f299b04cd
--- /dev/null
+++ b/test/elf/Mips/exe-fileheader-micro.test
@@ -0,0 +1,69 @@
+# Check ELF Header for non-pic executable file in case
+# of microMIPS entry symbol.
+
+# Build executable
+# RUN: yaml2obj -format=elf %s > %t-o.o
+# RUN: lld -flavor gnu -target mipsel -e glob -o %t.exe %t-o.o
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
+
+# CHECK: Format: ELF32-mips
+# CHECK-NEXT: Arch: mipsel
+# CHECK-NEXT: AddressSize: 32bit
+# CHECK-NEXT: LoadName:
+# CHECK-NEXT: ElfHeader {
+# CHECK-NEXT: Ident {
+# CHECK-NEXT: Magic: (7F 45 4C 46)
+# CHECK-NEXT: Class: 32-bit (0x1)
+# CHECK-NEXT: DataEncoding: LittleEndian (0x1)
+# CHECK-NEXT: FileVersion: 1
+# CHECK-NEXT: OS/ABI: SystemV (0x0)
+# CHECK-NEXT: ABIVersion: 0
+# CHECK-NEXT: Unused: (00 00 00 00 00 00 00)
+# CHECK-NEXT: }
+# CHECK-NEXT: Type: Executable (0x2)
+# CHECK-NEXT: Machine: EM_MIPS (0x8)
+# CHECK-NEXT: Version: 1
+# CHECK-NEXT: Entry: 0x400109
+# CHECK-NEXT: ProgramHeaderOffset: 0x34
+# CHECK-NEXT: SectionHeaderOffset: 0x1268
+# CHECK-NEXT: Flags [ (0x72001005)
+# CHECK-NEXT: EF_MIPS_ABI_O32 (0x1000)
+# CHECK-NEXT: EF_MIPS_ARCH_32R2 (0x70000000)
+# CHECK-NEXT: EF_MIPS_CPIC (0x4)
+# CHECK-NEXT: EF_MIPS_MICROMIPS (0x2000000)
+# CHECK-NEXT: EF_MIPS_NOREORDER (0x1)
+# CHECK-NEXT: ]
+# CHECK-NEXT: HeaderSize: 52
+# CHECK-NEXT: ProgramHeaderEntrySize: 32
+# CHECK-NEXT: ProgramHeaderCount: 5
+# CHECK-NEXT: SectionHeaderEntrySize: 40
+# CHECK-NEXT: SectionHeaderCount: 11
+# CHECK-NEXT: StringTableSectionIndex: 8
+# CHECK-NEXT: }
+
+# o.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_NOREORDER, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2, EF_MIPS_MICROMIPS ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x08
+
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ Global:
+ - Name: glob
+ Section: .text
+ Other: [ STO_MIPS_MICROMIPS ]
+...
diff --git a/test/elf/Mips/exe-fileheader.test b/test/elf/Mips/exe-fileheader.test
new file mode 100644
index 000000000000..ff0d38198c31
--- /dev/null
+++ b/test/elf/Mips/exe-fileheader.test
@@ -0,0 +1,105 @@
+# Check ELF Header for non-pic executable file.
+
+# Build shared library
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-so.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t-so.o
+
+# Build executable
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-o.o
+# RUN: lld -flavor gnu -target mipsel -e glob -o %t.exe %t-o.o %t.so
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
+
+# CHECK: Format: ELF32-mips
+# CHECK: Arch: mipsel
+# CHECK: AddressSize: 32bit
+# CHECK: LoadName:
+# CHECK: ElfHeader {
+# CHECK: Ident {
+# CHECK: Magic: (7F 45 4C 46)
+# CHECK: Class: 32-bit (0x1)
+# CHECK: DataEncoding: LittleEndian (0x1)
+# CHECK: FileVersion: 1
+# CHECK: OS/ABI: SystemV (0x0)
+# CHECK: ABIVersion: 1
+# CHECK: Unused: (00 00 00 00 00 00 00)
+# CHECK: }
+# CHECK: Type: Executable (0x2)
+# CHECK: Machine: EM_MIPS (0x8)
+# CHECK: Version: 1
+# CHECK: Entry: 0x400190
+# CHECK: ProgramHeaderOffset: 0x34
+# CHECK: SectionHeaderOffset: 0x2280
+# CHECK: Flags [ (0x70001005)
+# CHECK: EF_MIPS_ABI_O32 (0x1000)
+# CHECK: EF_MIPS_ARCH_32R2 (0x70000000)
+# CHECK: EF_MIPS_CPIC (0x4)
+# CHECK: EF_MIPS_NOREORDER (0x1)
+# CHECK: ]
+# CHECK: HeaderSize: 52
+# CHECK: ProgramHeaderEntrySize: 32
+# CHECK: ProgramHeaderCount: 6
+# CHECK: SectionHeaderEntrySize: 40
+# CHECK: SectionHeaderCount: 14
+# CHECK: StringTableSectionIndex: 11
+# CHECK: }
+
+# so.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+
+# o.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_NOREORDER, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x08
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x04
+ Info: .text
+ Relocations:
+ - Offset: 0x00
+ Symbol: T1
+ Type: R_MIPS_26
+
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ Global:
+ - Name: glob
+ Section: .text
+ - Name: T1
+...
diff --git a/test/elf/Mips/exe-got-micro.test b/test/elf/Mips/exe-got-micro.test
new file mode 100644
index 000000000000..d2d1588ab964
--- /dev/null
+++ b/test/elf/Mips/exe-got-micro.test
@@ -0,0 +1,115 @@
+# Check that external symbol defined in the executable file
+# and referenced by R_MICROMIPS_CALL16 relocation has a corresponded
+# entry in the local GOT section.
+#
+# Build shared library
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-so.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t-so.o
+
+# Build executable
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-o.o
+# RUN: lld -flavor gnu -target mipsel -e glob \
+# RUN: --output-filetype=yaml -o %t.exe %t-o.o %t.so
+# RUN: FileCheck -check-prefix=GOT %s < %t.exe
+
+# GOT header
+# GOT: - type: got
+# GOT: content: [ 00, 00, 00, 00 ]
+# GOT: alignment: 2^2
+# GOT: section-choice: custom-required
+# GOT: section-name: .got
+# GOT: permissions: rw-
+# GOT: - type: got
+# GOT: content: [ 00, 00, 00, 80 ]
+# GOT: alignment: 2^2
+# GOT: section-choice: custom-required
+# GOT: section-name: .got
+# GOT: permissions: rw-
+# Local GOT entry for 'glob' symbol
+# GOT: - ref-name: L000
+# GOT: type: got
+# GOT: content: [ 00, 00, 00, 00 ]
+# GOT: alignment: 2^2
+# GOT: section-choice: custom-required
+# GOT: section-name: .got
+# GOT: permissions: rw-
+# GOT: references:
+# GOT: - kind: R_MIPS_32
+# GOT: offset: 0
+# GOT: target: glob
+# Global GOT entry for 'T1' symbol
+# GOT: - ref-name: L001
+# GOT: type: got
+# GOT: content: [ 00, 00, 00, 00 ]
+# GOT: alignment: 2^2
+# GOT: section-choice: custom-required
+# GOT: section-name: .got
+# GOT: permissions: rw-
+# GOT: references:
+# GOT: - kind: LLD_R_MIPS_GLOBAL_GOT
+# GOT: offset: 0
+# GOT: target: T1
+
+# so.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+
+# o.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_PIC, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2, EF_MIPS_MICROMIPS ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x08
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x04
+ Info: .text
+ Relocations:
+ - Offset: 0x00
+ Symbol: glob
+ Type: R_MICROMIPS_CALL16
+ - Offset: 0x04
+ Symbol: T1
+ Type: R_MICROMIPS_CALL16
+
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ Global:
+ - Name: glob
+ Section: .text
+ Other: [ STO_MIPS_MICROMIPS ]
+ - Name: T1
+...
diff --git a/test/elf/Mips/exe-got.test b/test/elf/Mips/exe-got.test
new file mode 100644
index 000000000000..7254c87530bc
--- /dev/null
+++ b/test/elf/Mips/exe-got.test
@@ -0,0 +1,116 @@
+# Check that external symbol defined in the executable file
+# and referenced by R_MIPS_CALL16 relocation has a corresponded
+# entry in the local GOT section.
+#
+# Build shared library
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-so.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t-so.o
+
+# Build executable
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-o.o
+# RUN: lld -flavor gnu -target mipsel -e glob \
+# RUN: --output-filetype=yaml -o %t.exe %t-o.o %t.so
+# RUN: FileCheck -check-prefix=GOT %s < %t.exe
+
+# GOT header
+# GOT: - type: got
+# GOT: content: [ 00, 00, 00, 00 ]
+# GOT: alignment: 2^2
+# GOT: section-choice: custom-required
+# GOT: section-name: .got
+# GOT: permissions: rw-
+# GOT: - type: got
+# GOT: content: [ 00, 00, 00, 80 ]
+# GOT: alignment: 2^2
+# GOT: section-choice: custom-required
+# GOT: section-name: .got
+# GOT: permissions: rw-
+# Local GOT entry for 'glob' symbol
+# GOT: - ref-name: L000
+# GOT: type: got
+# GOT: content: [ 00, 00, 00, 00 ]
+# GOT: alignment: 2^2
+# GOT: section-choice: custom-required
+# GOT: section-name: .got
+# GOT: permissions: rw-
+# GOT: references:
+# GOT: - kind: R_MIPS_32
+# GOT: offset: 0
+# GOT: target: glob
+# Global GOT entry for 'T1' symbol
+# GOT: - ref-name: L001
+# GOT: type: got
+# GOT: content: [ 00, 00, 00, 00 ]
+# GOT: alignment: 2^2
+# GOT: section-choice: custom-required
+# GOT: section-name: .got
+# GOT: permissions: rw-
+# GOT: references:
+# GOT: - kind: LLD_R_MIPS_GLOBAL_GOT
+# GOT: offset: 0
+# GOT: target: T1
+
+# so.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+
+# o.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_PIC, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x08
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x04
+ Info: .text
+ Relocations:
+ - Offset: 0x00
+ Symbol: glob
+ Type: R_MIPS_CALL16
+ Addend: 0
+ - Offset: 0x04
+ Symbol: T1
+ Type: R_MIPS_CALL16
+ Addend: 0
+
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ Global:
+ - Name: glob
+ Section: .text
+ - Name: T1
+...
diff --git a/test/elf/Mips/got-page-32.test b/test/elf/Mips/got-page-32.test
new file mode 100644
index 000000000000..00376da78663
--- /dev/null
+++ b/test/elf/Mips/got-page-32.test
@@ -0,0 +1,203 @@
+# Check handling of R_MIPS_GOT_DISP / PAGE / OFST relocations.
+
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-so.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t-so.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-o.o
+# RUN: lld -flavor gnu -target mipsel -e T0 -o %t.exe %t-o.o %t.so
+# RUN: llvm-readobj -symbols -dyn-symbols -mips-plt-got %t.exe \
+# RUN: | FileCheck -check-prefix=GOT %s
+# RUN: llvm-objdump -s %t.exe | FileCheck -check-prefix=RAW %s
+
+# GOT: Symbol {
+# GOT: Name: T0 (1)
+# GOT-NEXT: Value: 0x400154
+# GOT: Symbol {
+# GOT: Name: LT1 (4)
+# GOT-NEXT: Value: 0x40017C
+# GOT: Symbol {
+# GOT: Name: LT2 (8)
+# GOT-NEXT: Value: 0x400180
+# GOT: Symbol {
+# GOT: Name: T1@ (1)
+# GOT-NEXT: Value: 0x0
+# GOT: Symbol {
+# GOT: Name: T2@ (4)
+# GOT-NEXT: Value: 0x0
+
+# GOT: Primary GOT {
+# GOT-NEXT: Canonical gp value: 0x408FF0
+# GOT-NEXT: Reserved entries [
+# GOT-NEXT: Entry {
+# GOT-NEXT: Address: 0x401000
+# GOT-NEXT: Access: -32752
+# GOT-NEXT: Initial: 0x0
+# GOT-NEXT: Purpose: Lazy resolver
+# GOT-NEXT: }
+# GOT-NEXT: Entry {
+# GOT-NEXT: Address: 0x401004
+# GOT-NEXT: Access: -32748
+# GOT-NEXT: Initial: 0x80000000
+# GOT-NEXT: Purpose: Module pointer (GNU extension)
+# GOT-NEXT: }
+# GOT-NEXT: ]
+# GOT-NEXT: Local entries [
+# GOT-NEXT: Entry {
+# GOT-NEXT: Address: 0x401008
+# GOT-NEXT: Access: -32744
+# GOT-NEXT: Initial: 0x40017C
+# GOT-NEXT: }
+# GOT-NEXT: Entry {
+# GOT-NEXT: Address: 0x40100C
+# GOT-NEXT: Access: -32740
+# GOT-NEXT: Initial: 0x400000
+# GOT-NEXT: }
+# GOT-NEXT: Entry {
+# GOT-NEXT: Address: 0x401010
+# GOT-NEXT: Access: -32736
+# GOT-NEXT: Initial: 0x400000
+# GOT-NEXT: }
+# GOT-NEXT: ]
+# GOT-NEXT: Global entries [
+# GOT-NEXT: Entry {
+# GOT-NEXT: Address: 0x401014
+# GOT-NEXT: Access: -32732
+# GOT-NEXT: Initial: 0x0
+# GOT-NEXT: Value: 0x0
+# GOT-NEXT: Type: Function (0x2)
+# GOT-NEXT: Section: Undefined (0x0)
+# GOT-NEXT: Name: T1@ (1)
+# GOT-NEXT: }
+# GOT-NEXT: Entry {
+# GOT-NEXT: Address: 0x401018
+# GOT-NEXT: Access: -32728
+# GOT-NEXT: Initial: 0x0
+# GOT-NEXT: Value: 0x0
+# GOT-NEXT: Type: Function (0x2)
+# GOT-NEXT: Section: Undefined (0x0)
+# GOT-NEXT: Name: T2@ (4)
+# GOT-NEXT: }
+# GOT-NEXT: ]
+# GOT-NEXT: Number of TLS and multi-GOT entries: 0
+# GOT-NEXT: }
+
+# RAW: Contents of section .text:
+# RAW-NEXT: 400154 24800000 18800000 24800000 28800000 $.......$...(...
+# ^ = -32732 (T1)
+# ^ = -32744 (LT1)
+# ^ -32732 (T1)
+# ^ -32728 (T2)
+# RAW-NEXT: 400164 1c800000 20800000 00000000 00000000 .... ...........
+# ^ -32740 (PAGE)
+# ^ -32736 (PAGE)
+# ^ T1 OFST
+# ^ T2 OFST
+# RAW-NEXT: 400174 7c010000 80010000 00000000 00000000 |...............
+# ^ LT1 OFST
+# ^ LT2 OFST
+
+# so.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ARCH_32, EF_MIPS_ABI_O32]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 8
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 0x4
+ - Name: T2
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x4
+ Size: 0x4
+
+# o.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ARCH_32, EF_MIPS_ABI_O32]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x4
+ Size: 0x30
+
+ - Name: .rel.text
+ Type: SHT_RELA
+ Link: .symtab
+ Info: .text
+ AddressAlign: 0x04
+ Relocations:
+ - Offset: 0x0
+ Symbol: T1
+ Type: R_MIPS_GOT_DISP
+ - Offset: 0x4
+ Symbol: LT1
+ Type: R_MIPS_GOT_DISP
+ - Offset: 0x8
+ Symbol: T1
+ Type: R_MIPS_GOT_PAGE
+ - Offset: 0xC
+ Symbol: T2
+ Type: R_MIPS_GOT_PAGE
+ - Offset: 0x10
+ Symbol: LT1
+ Type: R_MIPS_GOT_PAGE
+ - Offset: 0x14
+ Symbol: LT2
+ Type: R_MIPS_GOT_PAGE
+ - Offset: 0x18
+ Symbol: T1
+ Type: R_MIPS_GOT_OFST
+ - Offset: 0x1C
+ Symbol: T2
+ Type: R_MIPS_GOT_OFST
+ - Offset: 0x20
+ Symbol: LT1
+ Type: R_MIPS_GOT_OFST
+ - Offset: 0x24
+ Symbol: LT2
+ Type: R_MIPS_GOT_OFST
+
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+
+ Global:
+ - Name: T0
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x8
+ - Name: LT1
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x28
+ Size: 0x4
+ - Name: LT2
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x2c
+ Size: 0x4
+ - Name: T1
+ - Name: T2
+...
diff --git a/test/elf/Mips/got-page-64.test b/test/elf/Mips/got-page-64.test
new file mode 100644
index 000000000000..21bece5d3242
--- /dev/null
+++ b/test/elf/Mips/got-page-64.test
@@ -0,0 +1,203 @@
+# Check handling of R_MIPS_GOT_DISP / PAGE / OFST relocations.
+
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-so.o
+# RUN: lld -flavor gnu -target mips64el -shared -o %t.so %t-so.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-o.o
+# RUN: lld -flavor gnu -target mips64el -e T0 -o %t.exe %t-o.o %t.so
+# RUN: llvm-readobj -symbols -dyn-symbols -mips-plt-got %t.exe \
+# RUN: | FileCheck -check-prefix=GOT %s
+# RUN: llvm-objdump -s %t.exe | FileCheck -check-prefix=RAW %s
+
+# GOT: Symbol {
+# GOT: Name: T0 (1)
+# GOT-NEXT: Value: 0x1200001F0
+# GOT: Symbol {
+# GOT: Name: LT1 (4)
+# GOT-NEXT: Value: 0x120000218
+# GOT: Symbol {
+# GOT: Name: LT2 (8)
+# GOT-NEXT: Value: 0x12000021C
+# GOT: Symbol {
+# GOT: Name: T1@ (1)
+# GOT-NEXT: Value: 0x0
+# GOT: Symbol {
+# GOT: Name: T2@ (4)
+# GOT-NEXT: Value: 0x0
+
+# GOT: Primary GOT {
+# GOT-NEXT: Canonical gp value: 0x120008FF0
+# GOT-NEXT: Reserved entries [
+# GOT-NEXT: Entry {
+# GOT-NEXT: Address: 0x120001000
+# GOT-NEXT: Access: -32752
+# GOT-NEXT: Initial: 0x0
+# GOT-NEXT: Purpose: Lazy resolver
+# GOT-NEXT: }
+# GOT-NEXT: Entry {
+# GOT-NEXT: Address: 0x120001008
+# GOT-NEXT: Access: -32744
+# GOT-NEXT: Initial: 0x8000000000000000
+# GOT-NEXT: Purpose: Module pointer (GNU extension)
+# GOT-NEXT: }
+# GOT-NEXT: ]
+# GOT-NEXT: Local entries [
+# GOT-NEXT: Entry {
+# GOT-NEXT: Address: 0x120001010
+# GOT-NEXT: Access: -32736
+# GOT-NEXT: Initial: 0x120000218
+# GOT-NEXT: }
+# GOT-NEXT: Entry {
+# GOT-NEXT: Address: 0x120001018
+# GOT-NEXT: Access: -32728
+# GOT-NEXT: Initial: 0x120000000
+# GOT-NEXT: }
+# GOT-NEXT: Entry {
+# GOT-NEXT: Address: 0x120001020
+# GOT-NEXT: Access: -32720
+# GOT-NEXT: Initial: 0x120000000
+# GOT-NEXT: }
+# GOT-NEXT: ]
+# GOT-NEXT: Global entries [
+# GOT-NEXT: Entry {
+# GOT-NEXT: Address: 0x120001028
+# GOT-NEXT: Access: -32712
+# GOT-NEXT: Initial: 0x0
+# GOT-NEXT: Value: 0x0
+# GOT-NEXT: Type: Function (0x2)
+# GOT-NEXT: Section: Undefined (0x0)
+# GOT-NEXT: Name: T1@ (1)
+# GOT-NEXT: }
+# GOT-NEXT: Entry {
+# GOT-NEXT: Address: 0x120001030
+# GOT-NEXT: Access: -32704
+# GOT-NEXT: Initial: 0x0
+# GOT-NEXT: Value: 0x0
+# GOT-NEXT: Type: Function (0x2)
+# GOT-NEXT: Section: Undefined (0x0)
+# GOT-NEXT: Name: T2@ (4)
+# GOT-NEXT: }
+# GOT-NEXT: ]
+# GOT-NEXT: Number of TLS and multi-GOT entries: 0
+# GOT-NEXT: }
+
+# RAW: Contents of section .text:
+# RAW-NEXT: 1200001f0 38800000 20800000 38800000 40800000 8... ...8...@...
+# ^ = -32712 (T1)
+# ^ = -32736 (LT1)
+# ^ -32712 (T1)
+# ^ -32704 (T2)
+# RAW-NEXT: 120000200 28800000 30800000 00000000 00000000 (...0...........
+# ^ -32728 (PAGE)
+# ^ -32720 (PAGE)
+# ^ T1 OFST
+# ^ T2 OFST
+# RAW-NEXT: 120000210 18020000 1c020000 00000000 00000000 ................
+# ^ LT1 OFST
+# ^ LT2 OFST
+
+# so.o
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ARCH_64]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 8
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 0x4
+ - Name: T2
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x4
+ Size: 0x4
+
+# o.o
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ARCH_64]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x4
+ Size: 0x30
+
+ - Name: .rel.text
+ Type: SHT_RELA
+ Link: .symtab
+ Info: .text
+ AddressAlign: 0x04
+ Relocations:
+ - Offset: 0x0
+ Symbol: T1
+ Type: R_MIPS_GOT_DISP
+ - Offset: 0x4
+ Symbol: LT1
+ Type: R_MIPS_GOT_DISP
+ - Offset: 0x8
+ Symbol: T1
+ Type: R_MIPS_GOT_PAGE
+ - Offset: 0xC
+ Symbol: T2
+ Type: R_MIPS_GOT_PAGE
+ - Offset: 0x10
+ Symbol: LT1
+ Type: R_MIPS_GOT_PAGE
+ - Offset: 0x14
+ Symbol: LT2
+ Type: R_MIPS_GOT_PAGE
+ - Offset: 0x18
+ Symbol: T1
+ Type: R_MIPS_GOT_OFST
+ - Offset: 0x1C
+ Symbol: T2
+ Type: R_MIPS_GOT_OFST
+ - Offset: 0x20
+ Symbol: LT1
+ Type: R_MIPS_GOT_OFST
+ - Offset: 0x24
+ Symbol: LT2
+ Type: R_MIPS_GOT_OFST
+
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+
+ Global:
+ - Name: T0
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x8
+ - Name: LT1
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x28
+ Size: 0x4
+ - Name: LT2
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x2c
+ Size: 0x4
+ - Name: T1
+ - Name: T2
+...
diff --git a/test/elf/Mips/got16-2.test b/test/elf/Mips/got16-2.test
new file mode 100644
index 000000000000..6f576536c541
--- /dev/null
+++ b/test/elf/Mips/got16-2.test
@@ -0,0 +1,73 @@
+# Check handling of R_MIPS_GOT16 relocation against local
+# symbols when addresses of local data cross 64 KBytes border.
+
+# RUN: yaml2obj -format=elf %s > %t-obj
+# RUN: lld -flavor gnu -target mipsel -e T0 -o %t-exe %t-obj
+# RUN: llvm-objdump -s %t-exe | FileCheck %s
+
+# CHECK: Contents of section .got:
+# CHECK-NEXT: 40a000 00000000 00000080 00004000 00004100 ..........@...A.
+# lazy module 0x400000 0x410000
+# resolver pointer for L1 for L2
+
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Content: '00000000000000000000000000000000'
+
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ Info: .text
+ AddressAlign: 0x04
+ Address: 0x1000
+ Relocations:
+ - Offset: 0
+ Symbol: L1
+ Type: R_MIPS_GOT16
+ - Offset: 4
+ Symbol: L1
+ Type: R_MIPS_LO16
+ - Offset: 8
+ Symbol: L2
+ Type: R_MIPS_GOT16
+ - Offset: 12
+ Symbol: L2
+ Type: R_MIPS_LO16
+
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC ]
+ AddressAlign: 0x04
+ Size: 0x9000
+
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: L1
+ Type: STT_OBJECT
+ Section: .data
+ Value: 0x00
+ Size: 0x8000
+ - Name: L2
+ Type: STT_OBJECT
+ Section: .data
+ Value: 0x8000
+ Size: 0x04
+
+ Global:
+ - Name: T0
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x04
diff --git a/test/elf/Mips/got16-micro.test b/test/elf/Mips/got16-micro.test
new file mode 100644
index 000000000000..6b77613581ec
--- /dev/null
+++ b/test/elf/Mips/got16-micro.test
@@ -0,0 +1,165 @@
+# REQUIRES: mips
+
+# Check handling of global/local R_MICROMIPS_GOT16 relocations.
+# RUN: llvm-mc -triple=mipsel -mattr=micromips -relocation-model=pic \
+# RUN: -filetype=obj -o=%t.o %s
+# RUN: lld -flavor gnu -target mipsel -shared --noinhibit-exec \
+# RUN: --output-filetype=yaml %t.o \
+# RUN: | FileCheck -check-prefix YAML %s
+# RUN: lld -flavor gnu -target mipsel -shared --noinhibit-exec -o %t2 %t.o
+# RUN: llvm-objdump -t -disassemble -mattr=micromips %t2 \
+# RUN: | FileCheck -check-prefix RAW %s
+
+# Function glob
+# YAML: - name: main
+# YAML: scope: global
+# YAML: content: [ 5C, FC, 00, 00, 42, 30, 00, 00, 5C, FC, 00, 00,
+# YAML: 42, 30, 00, 00, 5C, FC, 00, 00, 5C, FC, 00, 00,
+# YAML: 5C, FC, 00, 00 ]
+# YAML: alignment: 4 mod 2^4
+# YAML: code-model: mips-micro
+# YAML: references:
+# YAML-NEXT: - kind: R_MICROMIPS_GOT16
+# YAML-NEXT: offset: 0
+# YAML-NEXT: target: L000
+# YAML-NEXT: - kind: R_MICROMIPS_LO16
+# YAML-NEXT: offset: 4
+# YAML-NEXT: target: data_1
+# YAML-NEXT: - kind: R_MICROMIPS_GOT16
+# YAML-NEXT: offset: 8
+# YAML-NEXT: target: L001
+# YAML-NEXT: - kind: R_MICROMIPS_LO16
+# YAML-NEXT: offset: 12
+# YAML-NEXT: target: data_2
+# YAML-NEXT: - kind: R_MICROMIPS_GOT16
+# YAML-NEXT: offset: 16
+# YAML-NEXT: target: L002
+# YAML-NEXT: - kind: R_MICROMIPS_CALL16
+# YAML-NEXT: offset: 20
+# YAML-NEXT: target: L003
+# YAML-NEXT: - kind: R_MICROMIPS_CALL16
+# YAML-NEXT: offset: 24
+# YAML-NEXT: target: L004
+
+# Local GOT entries:
+# YAML: - ref-name: L000
+# YAML-NEXT: type: got
+# YAML-NEXT: content: [ 00, 00, 00, 00 ]
+# YAML-NEXT: alignment: 2^2
+# YAML-NEXT: section-choice: custom-required
+# YAML-NEXT: section-name: .got
+# YAML-NEXT: permissions: rw-
+# YAML-NEXT: references:
+# YAML-NEXT: - kind: LLD_R_MIPS_32_HI16
+# YAML-NEXT: offset: 0
+# YAML-NEXT: target: data_1
+# YAML-NEXT: - ref-name: L001
+# YAML-NEXT: type: got
+# YAML-NEXT: content: [ 00, 00, 00, 00 ]
+# YAML-NEXT: alignment: 2^2
+# YAML-NEXT: section-choice: custom-required
+# YAML-NEXT: section-name: .got
+# YAML-NEXT: permissions: rw-
+# YAML-NEXT: references:
+# YAML-NEXT: - kind: LLD_R_MIPS_32_HI16
+# YAML-NEXT: offset: 0
+# YAML-NEXT: target: data_2
+# YAML-NEXT: - ref-name: L002
+# YAML-NEXT: type: got
+# YAML-NEXT: content: [ 00, 00, 00, 00 ]
+# YAML-NEXT: alignment: 2^2
+# YAML-NEXT: section-choice: custom-required
+# YAML-NEXT: section-name: .got
+# YAML-NEXT: permissions: rw-
+# YAML-NEXT: references:
+# YAML-NEXT: - kind: R_MIPS_32
+# YAML-NEXT: offset: 0
+# YAML-NEXT: target: data_h
+
+# Global GOT entries:
+# YAML-NEXT: - ref-name: L003
+# YAML-NEXT: type: got
+# YAML-NEXT: content: [ 00, 00, 00, 00 ]
+# YAML-NEXT: alignment: 2^2
+# YAML-NEXT: section-choice: custom-required
+# YAML-NEXT: section-name: .got
+# YAML-NEXT: permissions: rw-
+# YAML-NEXT: references:
+# YAML-NEXT: - kind: LLD_R_MIPS_GLOBAL_GOT
+# YAML-NEXT: offset: 0
+# YAML-NEXT: target: bar
+# YAML-NEXT: - kind: R_MIPS_32
+# YAML-NEXT: offset: 0
+# YAML-NEXT: target: bar
+# YAML-NEXT: - ref-name: L004
+# YAML-NEXT: type: got
+# YAML-NEXT: content: [ 00, 00, 00, 00 ]
+# YAML-NEXT: alignment: 2^2
+# YAML-NEXT: section-choice: custom-required
+# YAML-NEXT: section-name: .got
+# YAML-NEXT: permissions: rw-
+# YAML-NEXT: references:
+# YAML-NEXT: - kind: LLD_R_MIPS_GLOBAL_GOT
+# YAML-NEXT: offset: 0
+# YAML-NEXT: target: foo
+
+# RAW: Disassembly of section .text:
+# RAW: main:
+# RAW-NEXT: {{[0x0-9a-f]+}}: 5c fc 18 80 lw $2, -32744($gp)
+# RAW-NEXT: {{[0x0-9a-f]+}}: 42 30 40 10 addiu $2, $2, 4160
+# RAW-NEXT: {{[0x0-9a-f]+}}: 5c fc 1c 80 lw $2, -32740($gp)
+# RAW-NEXT: {{[0x0-9a-f]+}}: 42 30 60 20 addiu $2, $2, 8288
+# RAW-NEXT: {{[0x0-9a-f]+}}: 5c fc 20 80 lw $2, -32736($gp)
+# RAW-NEXT: {{[0x0-9a-f]+}}: 5c fc 24 80 lw $2, -32732($gp)
+# RAW-NEXT: {{[0x0-9a-f]+}}: 5c fc 28 80 lw $2, -32728($gp)
+
+# RAW: SYMBOL TABLE:
+# RAW: {{[0x0-9a-f]+}} *UND* 00000000
+# RAW: {{[0x0-9a-f]+}} l .data 00000000 data_1
+# RAW: {{[0x0-9a-f]+}} l .data 00000001 data_2
+# RAW: {{[0x0-9a-f]+}} g F .text 00000004 bar
+# RAW: {{[0x0-9a-f]+}} g F .text 0000001c main
+# RAW: {{[0x0-9a-f]+}} g .data 00000001 data_h
+
+ .data
+ .type data_1, @object
+ .size data_1, 4128
+data_1:
+ .byte 1
+ .space 4127
+ .type data_2, @object
+ .size data_2, 1
+data_2:
+ .byte 2
+ .hidden data_h
+ .globl data_h
+ .type data_h, @object
+ .size data_h, 1
+data_h:
+ .byte 3
+
+ .text
+ .globl bar
+ .set micromips
+ .ent bar
+ .type bar, @function
+bar:
+ nop
+ .end bar
+ .size bar, .-bar
+
+ .globl main
+ .set micromips
+ .ent main
+ .type main, @function
+main:
+ lw $2,%got(data_1)($28)
+ addiu $2,$2,%lo(data_1)
+ lw $2,%got(data_2)($28)
+ addiu $2,$2,%lo(data_2)
+ lw $2,%got(data_h)($28)
+ lw $2,%call16(bar)($28)
+ lw $2,%call16(foo)($28)
+
+ .end main
+ .size main, .-main
diff --git a/test/elf/Mips/got16.test b/test/elf/Mips/got16.test
new file mode 100644
index 000000000000..9090d3003c14
--- /dev/null
+++ b/test/elf/Mips/got16.test
@@ -0,0 +1,196 @@
+# REQUIRES: mips
+
+# Check handling of global/local GOT16 relocations.
+# RUN: yaml2obj -format=elf %s > %t.o
+# RUN: lld -flavor gnu -target mipsel -shared --noinhibit-exec \
+# RUN: --output-filetype=yaml %t.o \
+# RUN: | FileCheck -check-prefix YAML %s
+# RUN: lld -flavor gnu -target mipsel -shared --noinhibit-exec -o %t2 %t.o
+# RUN: llvm-objdump -t -disassemble %t2 | FileCheck -check-prefix RAW %s
+
+# Function glob
+# YAML: - name: glob
+# YAML: scope: global
+# YAML: content: [ 00, 00, 84, 8F, 00, 00, 84, 24, 01, 00, 84, 8F,
+# YAML: 00, 02, 84, 24, 00, 00, 84, 8F, 00, 00, 84, 8F,
+# YAML: 00, 00, 84, 8F ]
+# YAML: alignment: 2^2
+# YAML: references:
+# YAML: - kind: R_MIPS_GOT16
+# YAML: offset: 0
+# YAML: target: L000
+# YAML: - kind: R_MIPS_LO16
+# YAML: offset: 4
+# YAML: target: L009
+# YAML: - kind: R_MIPS_GOT16
+# YAML: offset: 8
+# YAML: target: L002
+# YAML: addend: 66048
+# YAML: - kind: R_MIPS_LO16
+# YAML: offset: 12
+# YAML: target: L009
+# YAML: addend: 512
+# YAML: - kind: R_MIPS_GOT16
+# YAML: offset: 16
+# YAML: target: L004
+# YAML: - kind: R_MIPS_CALL16
+# YAML: offset: 20
+# YAML: target: L005
+# YAML: - kind: R_MIPS_CALL16
+# YAML: offset: 24
+# YAML: target: L006
+
+# Local GOT entries:
+# YAML: - ref-name: L000
+# YAML-NEXT: type: got
+# YAML-NEXT: content: [ 00, 00, 00, 00 ]
+# YAML-NEXT: alignment: 2^2
+# YAML-NEXT: section-choice: custom-required
+# YAML-NEXT: section-name: .got
+# YAML-NEXT: permissions: rw-
+# YAML-NEXT: references:
+# YAML-NEXT: - kind: LLD_R_MIPS_32_HI16
+# YAML-NEXT: offset: 0
+# YAML-NEXT: target: L009
+# YAML-NEXT: - ref-name: L002
+# YAML-NEXT: type: got
+# YAML-NEXT: content: [ 00, 00, 00, 00 ]
+# YAML-NEXT: alignment: 2^2
+# YAML-NEXT: section-choice: custom-required
+# YAML-NEXT: section-name: .got
+# YAML-NEXT: permissions: rw-
+# YAML-NEXT: references:
+# YAML-NEXT: - kind: LLD_R_MIPS_32_HI16
+# YAML-NEXT: offset: 0
+# YAML-NEXT: target: L009
+# YAML-NEXT: addend: 66048
+# YAML-NEXT: - ref-name: L004
+# YAML-NEXT: type: got
+# YAML-NEXT: content: [ 00, 00, 00, 00 ]
+# YAML-NEXT: alignment: 2^2
+# YAML-NEXT: section-choice: custom-required
+# YAML-NEXT: section-name: .got
+# YAML-NEXT: permissions: rw-
+# YAML-NEXT: references:
+# YAML-NEXT: - kind: R_MIPS_32
+# YAML-NEXT: offset: 0
+# YAML-NEXT: target: hidden
+
+# Global GOT entries:
+# YAML-NEXT: - ref-name: L005
+# YAML-NEXT: type: got
+# YAML-NEXT: content: [ 00, 00, 00, 00 ]
+# YAML-NEXT: alignment: 2^2
+# YAML-NEXT: section-choice: custom-required
+# YAML-NEXT: section-name: .got
+# YAML-NEXT: permissions: rw-
+# YAML-NEXT: references:
+# YAML-NEXT: - kind: LLD_R_MIPS_GLOBAL_GOT
+# YAML-NEXT: offset: 0
+# YAML-NEXT: target: glob
+# YAML-NEXT: - kind: R_MIPS_32
+# YAML-NEXT: offset: 0
+# YAML-NEXT: target: glob
+# YAML-NEXT: - ref-name: L006
+# YAML-NEXT: type: got
+# YAML-NEXT: content: [ 00, 00, 00, 00 ]
+# YAML-NEXT: alignment: 2^2
+# YAML-NEXT: section-choice: custom-required
+# YAML-NEXT: section-name: .got
+# YAML-NEXT: permissions: rw-
+# YAML-NEXT: references:
+# YAML-NEXT: - kind: LLD_R_MIPS_GLOBAL_GOT
+# YAML-NEXT: offset: 0
+# YAML-NEXT: target: extern
+
+# RAW: Disassembly of section .text:
+# RAW: glob:
+# RAW-NEXT: {{[0x0-9a-f]+}}: 18 80 84 8f lw $4, -32744($gp)
+# RAW-NEXT: {{[0x0-9a-f]+}}: 00 20 84 24 addiu $4, $4, 8192
+# RAW-NEXT: {{[0x0-9a-f]+}}: 1c 80 84 8f lw $4, -32740($gp)
+# RAW-NEXT: {{[0x0-9a-f]+}}: 00 22 84 24 addiu $4, $4, 8704
+# RAW-NEXT: {{[0x0-9a-f]+}}: 20 80 84 8f lw $4, -32736($gp)
+# RAW-NEXT: {{[0x0-9a-f]+}}: 24 80 84 8f lw $4, -32732($gp)
+# RAW-NEXT: {{[0x0-9a-f]+}}: 28 80 84 8f lw $4, -32728($gp)
+
+# RAW: SYMBOL TABLE:
+# RAW: {{[0x0-9a-f]+}} *UND* 00000000
+# RAW: {{[0x0-9a-f]+}} l .data 00000000 str1
+# RAW: {{[0x0-9a-f]+}} l .data 00000005 str2
+# RAW: {{[0x0-9a-f]+}} g F .text 0000001c glob
+# RAW: {{[0x0-9a-f]+}} g .data 00000004 hidden
+
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32 ]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Content: '0000848F000084240100848F000284240000848F0000848F0000848F'
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x04
+ Info: .text
+ Relocations:
+ - Offset: 0x00
+ Symbol: .data
+ Type: R_MIPS_GOT16
+ - Offset: 0x04
+ Symbol: .data
+ Type: R_MIPS_LO16
+ - Offset: 0x08
+ Symbol: .data
+ Type: R_MIPS_GOT16
+ - Offset: 0x0C
+ Symbol: .data
+ Type: R_MIPS_LO16
+ - Offset: 0x10
+ Symbol: hidden
+ Type: R_MIPS_GOT16
+ - Offset: 0x14
+ Symbol: glob
+ Type: R_MIPS_CALL16
+ - Offset: 0x18
+ Symbol: extern
+ Type: R_MIPS_CALL16
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x04
+ Size: 0x10209
+
+Symbols:
+ Local:
+ - Name: str1
+ Type: STT_OBJECT
+ Section: .data
+ Size: 0x10200
+ - Name: str2
+ Type: STT_OBJECT
+ Section: .data
+ Value: 0x10200
+ Size: 0x05
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ Global:
+ - Name: glob
+ Section: .text
+ - Name: hidden
+ Type: STT_OBJECT
+ Section: .data
+ Value: 0x10205
+ Size: 0x04
+ Visibility: STV_HIDDEN
+ - Name: extern
diff --git a/test/elf/Mips/gotsym.test b/test/elf/Mips/gotsym.test
new file mode 100644
index 000000000000..4581901958aa
--- /dev/null
+++ b/test/elf/Mips/gotsym.test
@@ -0,0 +1,43 @@
+# Check _gp_disp and GOT_OFFSET_TABLE value
+#
+# RUN: yaml2obj -format=elf %s > %t.o
+# RUN: lld -flavor gnu -target mipsel -shared --noinhibit-exec -o %t.so %t.o
+# RUN: llvm-objdump -h -t %t.so | FileCheck -check-prefix=SHARED %s
+
+# SHARED: Sections:
+# SHARED: Idx Name Size Address Type
+# SHARED: 6 .got 00000008 0000000000001000 DATA
+# SHARED: SYMBOL TABLE:
+# SHARED: 00001000 g *ABS* 00000000 _GLOBAL_OFFSET_TABLE_
+# SHARED: 00008ff0 g *ABS* 00000000 _gp
+# SHARED: 00008ff0 g *ABS* 00000000 _gp_disp
+
+# RUN: lld -flavor gnu -target mipsel -e main --noinhibit-exec -o %t.exe %t.o
+# RUN: llvm-objdump -h -t %t.exe | FileCheck -check-prefix=EXE %s
+
+# EXE: Sections:
+# EXE: Idx Name Size Address Type
+# EXE: 7 .got 00000008 0000000000401000 DATA
+# EXE: SYMBOL TABLE:
+# EXE: 00401000 g *ABS* 00000000 _GLOBAL_OFFSET_TABLE_
+# EXE: 00408ff0 g *ABS* 00000000 _gp
+# EXE: 00408ff0 g *ABS* 00000000 _gp_disp
+
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32 ]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x10
+ Size: 0x04
+
+Symbols:
+ Global:
+ - Name: main
+ Section: .text
diff --git a/test/elf/Mips/gp-sym-1-micro.test b/test/elf/Mips/gp-sym-1-micro.test
new file mode 100644
index 000000000000..76274eaaa8ac
--- /dev/null
+++ b/test/elf/Mips/gp-sym-1-micro.test
@@ -0,0 +1,88 @@
+# Check that microMIPS relocations against __gnu_local_gp
+# use "gp" value as target.
+
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-so.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t-so.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-o.o
+# RUN: lld -flavor gnu -target mipsel -e T0 -o %t.exe %t-o.o %t.so
+# RUN: llvm-readobj -symbols %t.exe | FileCheck -check-prefix=SYM %s
+# RUN: llvm-objdump -s %t.exe | FileCheck -check-prefix=SEC %s
+
+# SYM: Name: _gp (203)
+# SYM-NEXT: Value: 0x408FF0
+
+# SEC: Contents of section .text:
+# SEC-NEXT: 400184 00004100 0000f08f 2000bc00 ..A..... ...
+# SEC: Contents of section .got:
+# SEC-NEXT: 401000 00000000 00000080 ........
+
+# so.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+
+# o.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_NOREORDER, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2, EF_MIPS_MICROMIPS ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 12
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ Info: .text
+ AddressAlign: 0x04
+ Relocations:
+ - Offset: 0x00
+ Symbol: __gnu_local_gp
+ Type: R_MICROMIPS_HI16
+ - Offset: 0x04
+ Symbol: __gnu_local_gp
+ Type: R_MICROMIPS_LO16
+ - Offset: 0x08
+ Symbol: T1
+ Type: R_MICROMIPS_26_S1
+
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ Global:
+ - Name: T0
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x08
+ Other: [ STO_MIPS_MICROMIPS ]
+ - Name: __gnu_local_gp
+ - Name: T1
+...
diff --git a/test/elf/Mips/gp-sym-1.test b/test/elf/Mips/gp-sym-1.test
new file mode 100644
index 000000000000..6c2ffb62629d
--- /dev/null
+++ b/test/elf/Mips/gp-sym-1.test
@@ -0,0 +1,86 @@
+# Check that relocations against __gnu_local_gp use "gp" value as target.
+
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-so.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t-so.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-o.o
+# RUN: lld -flavor gnu -target mipsel -e T0 -o %t.exe %t-o.o %t.so
+# RUN: llvm-readobj -symbols %t.exe | FileCheck -check-prefix=SYM %s
+# RUN: llvm-objdump -s %t.exe | FileCheck -check-prefix=SEC %s
+
+# SYM: Name: _gp (203)
+# SYM-NEXT: Value: 0x408FF0
+
+# SEC: Contents of section .text:
+# SEC-NEXT: 400190 41000000 f08f0000 60001000
+# SEC: Contents of section .got:
+# SEC-NEXT: 401000 00000000 00000080
+
+# so.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+
+# o.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_NOREORDER, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 12
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ Info: .text
+ AddressAlign: 0x04
+ Relocations:
+ - Offset: 0x00
+ Symbol: __gnu_local_gp
+ Type: R_MIPS_HI16
+ - Offset: 0x04
+ Symbol: __gnu_local_gp
+ Type: R_MIPS_LO16
+ - Offset: 0x08
+ Symbol: T1
+ Type: R_MIPS_26
+
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ Global:
+ - Name: T0
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x08
+ - Name: __gnu_local_gp
+ - Name: T1
+...
diff --git a/test/elf/Mips/gp-sym-2.test b/test/elf/Mips/gp-sym-2.test
new file mode 100644
index 000000000000..6b9e5a5e52d9
--- /dev/null
+++ b/test/elf/Mips/gp-sym-2.test
@@ -0,0 +1,103 @@
+# Check that R_MIPS32 relocation against __gnu_local_gp causes emitting
+# of R_MIPS_REL32 relocation in case of shared library file linking
+# and does not produce any dynamic relocation in case of linking a non-shared
+# executable file.
+
+# Now the test failed because the __gnu_local_gp symbol becomes defined
+# absolute symbol and we do not generate R_MIPS_REL32 in case of shared
+# library linking.
+# XFAIL: *
+
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-so.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t-1.so %t-so.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-o.o
+# RUN: lld -flavor gnu -target mipsel -e T0 -o %t.exe %t-o.o %t-1.so
+# RUN: llvm-readobj -r %t.exe | FileCheck -check-prefix=EXE %s
+# RUN: lld -flavor gnu -target mipsel -shared -o %t-2.so %t-o.o %t-1.so
+# RUN: llvm-readobj -r %t-2.so | FileCheck -check-prefix=SO %s
+
+# EXE: Relocations [
+# EXE-NEXT: ]
+
+# SO: Relocations [
+# SO-NEXT: Section (5) .rel.dyn {
+# SO-NEXT: 0x0 R_MIPS_NONE - 0x0
+# SO-NEXT: 0x2EC R_MIPS_REL32 __gnu_local_gp 0x0
+# SO-NEXT: }
+# SO-NEXT: ]
+
+# so.so
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_CPIC]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+ - Name: T2
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x4
+ Size: 4
+
+# o.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_NOREORDER, EF_MIPS_CPIC, EF_MIPS_PIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 12
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ Info: .text
+ AddressAlign: 0x04
+ Relocations:
+ - Offset: 0x00
+ Symbol: __gnu_local_gp
+ Type: R_MIPS_32
+ - Offset: 0x04
+ Symbol: T1
+ Type: R_MIPS_LO16
+ - Offset: 0x08
+ Symbol: T2
+ Type: R_MIPS_CALL16
+
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ Global:
+ - Name: T0
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x08
+ - Name: __gnu_local_gp
+ - Name: T1
+ - Name: T2
+...
diff --git a/test/elf/Mips/hilo16-1.test b/test/elf/Mips/hilo16-1.test
new file mode 100644
index 000000000000..c2863408c888
--- /dev/null
+++ b/test/elf/Mips/hilo16-1.test
@@ -0,0 +1,44 @@
+# REQUIRES: mips
+
+# Check handling multiple HI16 relocation followed by a single LO16 relocation.
+#
+# RUN: llvm-mc -triple=mipsel -filetype=obj -o=%t-obj %s
+# RUN: lld -flavor gnu -target mipsel -e glob1 -o %t-exe %t-obj
+# RUN: llvm-objdump -t -disassemble %t-exe | FileCheck %s
+
+# CHECK: Disassembly of section .text:
+# CHECK: glob1:
+# CHECK-NEXT: {{[0-9a-f]+}}: 40 00 08 3c lui $8, 64
+# CHECK-NEXT: {{[0-9a-f]+}}: 40 00 08 3c lui $8, 64
+# CHECK-NEXT: {{[0-9a-f]+}}: 40 00 08 3c lui $8, 64
+# CHECK-NEXT: {{[0-9a-f]+}}: 40 00 08 3c lui $8, 64
+# CHECK-NEXT: {{[0-9a-f]+}}: 42 00 08 3c lui $8, 66
+# CHECK-NEXT: {{[0-9a-f]+}}: 3e 00 08 3c lui $8, 62
+# CHECK-NEXT: {{[0-9a-f]+}}: 40 02 08 3c lui $8, 576
+# CHECK-NEXT: {{[0-9a-f]+}}: 40 fe 08 3c lui $8, 65088
+# CHECK-NEXT: {{[0-9a-f]+}}: 55 01 08 85 lh $8, 341($8)
+
+# CHECK: SYMBOL TABLE:
+# CHECK: {{[0-9a-f]+}} g F .text 00000024 glob1
+# CHECK: {{[0-9a-f]+}} g F .text 00000004 glob2
+
+ .global glob1
+ .ent glob1
+glob1:
+ lui $t0,%hi(glob2+0x1)
+ lui $t0,%hi(glob2+(-0x1))
+ lui $t0,%hi(glob2+0x1ff)
+ lui $t0,%hi(glob2+(-0x1ff))
+ lui $t0,%hi(glob2+0x1ffff)
+ lui $t0,%hi(glob2+(-0x1ffff))
+ lui $t0,%hi(glob2+0x1ffffff)
+ lui $t0,%hi(glob2+(-0x1ffffff))
+
+ lh $t0,%lo(glob2+(-0x1ffffff))($t0)
+ .end glob1
+
+ .global glob2
+ .ent glob2
+glob2:
+ nop
+ .end glob2
diff --git a/test/elf/Mips/hilo16-2.test b/test/elf/Mips/hilo16-2.test
new file mode 100644
index 000000000000..68cb26eec788
--- /dev/null
+++ b/test/elf/Mips/hilo16-2.test
@@ -0,0 +1,68 @@
+# REQUIRES: mips
+
+# Check handling of HI16 and LO16 relocations for regular symbol.
+#
+# R_MIPS_HI16: (AHL + S) - (short)(AHL + S)
+# R_MIPS_LO16: AHL + S
+# where AHL = (AHI << 16) + ALO
+#
+# RUN: llvm-mc -triple=mipsel -filetype=obj -o=%t-obj %s
+# RUN: lld -flavor gnu -target mipsel -e glob1 -o %t-exe %t-obj
+# RUN: llvm-objdump -t -disassemble %t-exe | FileCheck %s
+
+# CHECK: Disassembly of section .text:
+# CHECK: glob1:
+# CHECK-NEXT: {{[0-9a-f]+}}: 40 00 08 3c lui $8, 64
+# CHECK-NEXT: {{[0-9a-f]+}}: 71 01 08 85 lh $8, 369($8)
+# CHECK-NEXT: {{[0-9a-f]+}}: 40 00 08 3c lui $8, 64
+# CHECK-NEXT: {{[0-9a-f]+}}: 6f 01 08 85 lh $8, 367($8)
+# CHECK-NEXT: {{[0-9a-f]+}}: 40 00 08 3c lui $8, 64
+# CHECK-NEXT: {{[0-9a-f]+}}: 6f 03 08 85 lh $8, 879($8)
+# CHECK-NEXT: {{[0-9a-f]+}}: 40 00 08 3c lui $8, 64
+# CHECK-NEXT: {{[0-9a-f]+}}: 71 ff 08 85 lh $8, -143($8)
+# CHECK-NEXT: {{[0-9a-f]+}}: 42 00 08 3c lui $8, 66
+# CHECK-NEXT: {{[0-9a-f]+}}: 6f 01 08 85 lh $8, 367($8)
+# CHECK-NEXT: {{[0-9a-f]+}}: 3e 00 08 3c lui $8, 62
+# CHECK-NEXT: {{[0-9a-f]+}}: 71 01 08 85 lh $8, 369($8)
+# CHECK-NEXT: {{[0-9a-f]+}}: 40 02 08 3c lui $8, 576
+# CHECK-NEXT: {{[0-9a-f]+}}: 6f 01 08 85 lh $8, 367($8)
+# CHECK-NEXT: {{[0-9a-f]+}}: 40 fe 08 3c lui $8, 65088
+# CHECK-NEXT: {{[0-9a-f]+}}: 71 01 08 85 lh $8, 369($8)
+
+# CHECK: SYMBOL TABLE:
+# CHECK: {{[0-9a-f]+}} g F .text 00000040 glob1
+# CHECK: {{[0-9a-f]+}} g F .text 00000004 glob2
+
+ .global glob1
+ .ent glob1
+glob1:
+ lui $t0,%hi(glob2+0x1)
+ lh $t0,%lo(glob2+0x1)($t0)
+
+ lui $t0,%hi(glob2+(-0x1))
+ lh $t0,%lo(glob2+(-0x1))($t0)
+
+ lui $t0,%hi(glob2+0x1ff)
+ lh $t0,%lo(glob2+0x1ff)($t0)
+
+ lui $t0,%hi(glob2+(-0x1ff))
+ lh $t0,%lo(glob2+(-0x1ff))($t0)
+
+ lui $t0,%hi(glob2+0x1ffff)
+ lh $t0,%lo(glob2+0x1ffff)($t0)
+
+ lui $t0,%hi(glob2+(-0x1ffff))
+ lh $t0,%lo(glob2+(-0x1ffff))($t0)
+
+ lui $t0,%hi(glob2+0x1ffffff) # truncate
+ lh $t0,%lo(glob2+0x1ffffff)($t0)
+
+ lui $t0,%hi(glob2+(-0x1ffffff)) # truncate
+ lh $t0,%lo(glob2+(-0x1ffffff))($t0)
+ .end glob1
+
+ .global glob2
+ .ent glob2
+glob2:
+ nop
+ .end glob2
diff --git a/test/elf/Mips/hilo16-3.test b/test/elf/Mips/hilo16-3.test
new file mode 100644
index 000000000000..daf4807d719a
--- /dev/null
+++ b/test/elf/Mips/hilo16-3.test
@@ -0,0 +1,45 @@
+# REQUIRES: mips
+
+# Check handling of HI16 and LO16 relocations for _gp_disp.
+#
+# R_MIPS_HI16: (AHL + GP - P) - (short)(AHL + GP - P)
+# R_MIPS_LO16: AHL + GP - P + 4
+# where AHL = (AHI << 16) + ALO
+#
+# RUN: llvm-mc -triple=mipsel -filetype=obj -o=%t-obj %s
+# RUN: lld -flavor gnu -target mipsel -shared -o %t-so %t-obj
+# RUN: llvm-objdump -t -disassemble %t-so | FileCheck %s
+
+# CHECK: Disassembly of section .text:
+# CHECK: glob1:
+# CHECK-NEXT: {{[0-9a-f]+}}: 01 00 08 3c lui $8, 1
+# CHECK-NEXT: {{[0-9a-f]+}}: 01 8f 08 85 lh $8, -28927($8)
+# CHECK-NEXT: {{[0-9a-f]+}}: 01 00 08 3c lui $8, 1
+# CHECK-NEXT: {{[0-9a-f]+}}: f7 8e 08 85 lh $8, -28937($8)
+# CHECK-NEXT: {{[0-9a-f]+}}: 01 00 08 3c lui $8, 1
+# CHECK-NEXT: {{[0-9a-f]+}}: ef 90 08 85 lh $8, -28433($8)
+# CHECK-NEXT: {{[0-9a-f]+}}: 01 00 08 3c lui $8, 1
+# CHECK-NEXT: {{[0-9a-f]+}}: e9 8c 08 85 lh $8, -29463($8)
+# CHECK-NEXT: {{[0-9a-f]+}}: 03 00 08 3c lui $8, 3
+# CHECK-NEXT: {{[0-9a-f]+}}: df 8e 08 85 lh $8, -28961($8)
+
+# CHECK: SYMBOL TABLE:
+# CHECK: {{[0-9a-f]+}} g F .text 00000028 glob1
+# CHECK: {{[0-9a-f]+}} g *ABS* 00000000 _gp_disp
+
+ .global glob1
+glob1:
+ lui $t0,%hi(_gp_disp+0x1)
+ lh $t0,%lo(_gp_disp+0x1)($t0)
+
+ lui $t0,%hi(_gp_disp+(-0x1))
+ lh $t0,%lo(_gp_disp+(-0x1))($t0)
+
+ lui $t0,%hi(_gp_disp+0x1ff)
+ lh $t0,%lo(_gp_disp+0x1ff)($t0)
+
+ lui $t0,%hi(_gp_disp+(-0x1ff))
+ lh $t0,%lo(_gp_disp+(-0x1ff))($t0)
+
+ lui $t0,%hi(_gp_disp+0x1ffff)
+ lh $t0,%lo(_gp_disp+0x1ffff)($t0)
diff --git a/test/elf/Mips/hilo16-4.test b/test/elf/Mips/hilo16-4.test
new file mode 100644
index 000000000000..8a13f7b131fd
--- /dev/null
+++ b/test/elf/Mips/hilo16-4.test
@@ -0,0 +1,93 @@
+# REQUIRES: mips
+
+# Check pairing of R_MIPS_HI16 and R_MIPS_LO16 relocations.
+# RUN: yaml2obj -format=elf %s > %t-obj
+# RUN: lld -flavor gnu -target mipsel -e glob1 -o %t-exe %t-obj
+# RUN: llvm-objdump -t -disassemble %t-exe | FileCheck %s
+
+# CHECK: Disassembly of section .text:
+# CHECK: glob1:
+# CHECK-NEXT: 400130: 40 00 04 3c lui $4, 64
+# CHECK-NEXT: 400134: ff 9f a6 8c lw $6, -24577($5)
+
+# CHECK: glob2:
+# CHECK-NEXT: 400138: 00 20 c7 80 lb $7, 8192($6)
+# CHECK-NEXT: 40013c: 04 20 c8 80 lb $8, 8196($6)
+
+# CHECK: glob3:
+# CHECK-NEXT: 400140: 40 80 05 3c lui $5, 32832
+
+# CHECK: SYMBOL TABLE:
+# CHECK: 00400130 g F .text 00000008 glob1
+# CHECK: 00400138 g F .text 00000008 glob2
+# CHECK: 00400140 g F .text 00000004 glob3
+# CHECK: 00402000 g .data 0000000c X
+
+!ELF
+FileHeader: !FileHeader
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+# glob1:
+# lui $4,%hi(X) # rel A
+# lw $6,%lo(X+32767)($5) # rel B
+# glob2:
+# lb $7,%lo(X)($6) # rel C
+# lb $8,%lo(X+4)($6) # rel D
+# glob3:
+# lui $5,%hi(X+32767) # rel E
+ Content: "0000043CFF7FA68C0000C7800400C880FF7F053C"
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .data
+ Type: SHT_PROGBITS
+ Content: "000000000000000000000000"
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_ALLOC]
+
+- Name: .rel.text
+ Type: SHT_REL
+ Info: .text
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x10 # rel E
+ Symbol: X
+ Type: R_MIPS_HI16
+ - Offset: 0x04 # rel B
+ Symbol: X
+ Type: R_MIPS_LO16
+ - Offset: 0x00 # rel A
+ Symbol: X
+ Type: R_MIPS_HI16
+ - Offset: 0x0C # rel D
+ Symbol: X
+ Type: R_MIPS_LO16
+ - Offset: 0x08 # rel C
+ Symbol: X
+ Type: R_MIPS_LO16
+
+Symbols:
+ Global:
+ - Name: glob1
+ Section: .text
+ Value: 0x0
+ Size: 8
+ - Name: glob2
+ Section: .text
+ Value: 0x8
+ Size: 8
+ - Name: glob3
+ Section: .text
+ Value: 0x10
+ Size: 4
+ - Name: X
+ Section: .data
+ Value: 0x0
+ Size: 12
diff --git a/test/elf/Mips/hilo16-5.test b/test/elf/Mips/hilo16-5.test
new file mode 100644
index 000000000000..91aca8b1c366
--- /dev/null
+++ b/test/elf/Mips/hilo16-5.test
@@ -0,0 +1,103 @@
+# Check that linker shows a warning when
+# there is orphaned R_MIPS_HI16 relocation.
+
+# RUN: yaml2obj -format=elf -o %t-so.o -docnum 1 %s
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t-so.o
+# RUN: yaml2obj -format=elf -o %t-o.o -docnum 2 %s
+# RUN: lld -flavor gnu -target mipsel -e T0 -o %t.exe %t-o.o %t.so 2>&1 \
+# RUN: | FileCheck -check-prefix=DIAG %s
+# RUN: llvm-objdump -s %t.exe | FileCheck -check-prefix=DATA %s
+
+# DIAG: lld warning: cannot matching LO16 relocation
+# DIAG: lld warning: cannot matching LO16 relocation
+
+# DATA: Contents of section .data:
+# DATA-NEXT: 402000 40000000 10200000 40000000 @.... ..@...
+
+# so.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+ - Name: .data
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: D1
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x0
+ Size: 4
+ - Name: D2
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x4
+ Size: 4
+
+# o.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Content: "00000000"
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .data
+ Type: SHT_PROGBITS
+ Content: "000000000000000000000000"
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_ALLOC]
+
+- Name: .rel.data
+ Type: SHT_REL
+ Info: .data
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x00
+ Symbol: D1
+ Type: R_MIPS_HI16
+ - Offset: 0x08
+ Symbol: D2
+ Type: R_MIPS_HI16
+ - Offset: 0x04
+ Symbol: D1
+ Type: R_MIPS_LO16
+ - Offset: 0x08
+ Symbol: .text
+ Type: R_MIPS_HI16
+
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+
+ Global:
+ - Name: T0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+ - Name: D1
+ - Name: D2
+...
diff --git a/test/elf/Mips/hilo16-8-micro.test b/test/elf/Mips/hilo16-8-micro.test
new file mode 100644
index 000000000000..3248804f8f54
--- /dev/null
+++ b/test/elf/Mips/hilo16-8-micro.test
@@ -0,0 +1,81 @@
+# REQUIRES: mips
+
+# Check calculation of AHL addendums for R_MICROMIPS_HI16 / R_MICROMIPS_LO16
+# relocations for a regular symbol.
+#
+# RUN: llvm-mc -triple=mipsel -mattr=micromips -filetype=obj -o=%t-obj %s
+# RUN: lld -flavor gnu -target mipsel -e glob1 -o %t-exe %t-obj
+# RUN: llvm-objdump -t -d -mattr=micromips %t-exe | FileCheck %s
+
+# CHECK: Disassembly of section .text:
+# CHECK-NEXT: glob1:
+# CHECK-NEXT: 400130: a8 41 40 00 lui $8, 64
+# CHECK-NEXT: 400134: 08 3d 6a 01 lh $8, 362($8)
+# CHECK-NEXT: 400138: a8 41 41 00 lui $8, 65
+# CHECK-NEXT: 40013c: 08 3d 68 81 lh $8, -32408($8)
+# CHECK-NEXT: 400140: a8 41 41 00 lui $8, 65
+# CHECK-NEXT: 400144: 08 3d e9 81 lh $8, -32279($8)
+# CHECK-NEXT: 400148: a8 41 42 00 lui $8, 66
+# CHECK-NEXT: 40014c: 08 3d 69 81 lh $8, -32407($8)
+# CHECK-NEXT: 400150: a8 41 40 40 lui $8, 16448
+# CHECK-NEXT: 400154: 08 3d 69 01 lh $8, 361($8)
+# CHECK-NEXT: 400158: a8 41 40 80 lui $8, 32832
+# CHECK-NEXT: 40015c: 08 3d 69 01 lh $8, 361($8)
+# CHECK-NEXT: 400160: a8 41 c1 80 lui $8, 32961
+# CHECK-NEXT: 400164: 08 3d e9 81 lh $8, -32279($8)
+
+# CHECK: glob2:
+# CHECK-NEXT: 400168: a8 41 40 00 lui $8, 64
+# CHECK-NEXT: 40016c: a8 41 40 00 lui $8, 64
+# CHECK-NEXT: 400170: a8 41 41 00 lui $8, 65
+# CHECK-NEXT: 400174: a8 41 42 00 lui $8, 66
+# CHECK-NEXT: 400178: a8 41 40 40 lui $8, 16448
+# CHECK-NEXT: 40017c: a8 41 40 80 lui $8, 32832
+# CHECK-NEXT: 400180: a8 41 c1 80 lui $8, 32961
+# CHECK-NEXT: 400184: 08 3d b1 81 lh $8, -32335($8)
+
+# CHECK: SYMBOL TABLE:
+# CHECK: 00400130 g F .text 00000038 glob1
+# CHECK: 00400168 g F .text 00000020 glob2
+
+ .globl glob1
+ .type glob1, @function
+ .set micromips
+ .ent glob1
+glob1:
+ lui $t0,%hi(glob2+0x00000001)
+ lh $t0,%lo(glob2+0x00000001)($t0)
+
+ lui $t0,%hi(glob2+0x00007fff)
+ lh $t0,%lo(glob2+0x00007fff)($t0)
+
+ lui $t0,%hi(glob2+0x00008080)
+ lh $t0,%lo(glob2+0x00008080)($t0)
+
+ lui $t0,%hi(glob2+0x00018000)
+ lh $t0,%lo(glob2+0x00018000)($t0)
+
+ lui $t0,%hi(glob2+0x40000000)
+ lh $t0,%lo(glob2+0x40000000)($t0)
+
+ lui $t0,%hi(glob2+0x80000000)
+ lh $t0,%lo(glob2+0x80000000)($t0)
+
+ lui $t0,%hi(glob2+0x80808080)
+ lh $t0,%lo(glob2+0x80808080)($t0)
+ .end glob1
+
+ .globl glob2
+ .type glob2, @function
+ .set micromips
+ .ent glob2
+glob2:
+ lui $t0,%hi(glob1+0x00000001)
+ lui $t0,%hi(glob1+0x00007fff)
+ lui $t0,%hi(glob1+0x00008080)
+ lui $t0,%hi(glob1+0x00018000)
+ lui $t0,%hi(glob1+0x40000000)
+ lui $t0,%hi(glob1+0x80000000)
+ lui $t0,%hi(glob1+0x80808080)
+ lh $t0,%lo(glob1+0x80808080)($t0)
+ .end glob2
diff --git a/test/elf/Mips/hilo16-9-micro.test b/test/elf/Mips/hilo16-9-micro.test
new file mode 100644
index 000000000000..30ad10ce0dd4
--- /dev/null
+++ b/test/elf/Mips/hilo16-9-micro.test
@@ -0,0 +1,68 @@
+# REQUIRES: mips
+
+# Check calculation of AHL addendums for R_MICROMIPS_HI16 / R_MICROMIPS_LO16
+# relocations for the _gp_disp symbol.
+#
+# RUN: llvm-mc -triple=mipsel -mattr=micromips -filetype=obj -o=%t-obj %s
+# RUN: lld -flavor gnu -target mipsel -shared -o %t-so %t-obj
+# RUN: llvm-objdump -t -d -mattr=micromips %t-so | FileCheck %s
+
+# CHECK: Disassembly of section .text:
+# CHECK-NEXT: glob1:
+# CHECK-NEXT: 130: a8 41 01 00 lui $8, 1
+# CHECK-NEXT: 134: 08 3d c0 9e lh $8, -24896($8)
+# CHECK-NEXT: 138: a8 41 01 00 lui $8, 1
+# CHECK-NEXT: 13c: 08 3d b6 1e lh $8, 7862($8)
+# CHECK-NEXT: 140: a8 41 01 00 lui $8, 1
+# CHECK-NEXT: 144: 08 3d 2f 1f lh $8, 7983($8)
+# CHECK-NEXT: 148: a8 41 02 00 lui $8, 2
+# CHECK-NEXT: 14c: 08 3d a7 1e lh $8, 7847($8)
+# CHECK-NEXT: 150: a8 41 01 40 lui $8, 16385
+# CHECK-NEXT: 154: 08 3d 9f 9e lh $8, -24929($8)
+
+# CHECK: glob2:
+# CHECK-NEXT: 158: a8 41 01 00 lui $8, 1
+# CHECK-NEXT: 15c: a8 41 01 00 lui $8, 1
+# CHECK-NEXT: 160: a8 41 02 00 lui $8, 2
+# CHECK-NEXT: 164: a8 41 03 00 lui $8, 3
+# CHECK-NEXT: 168: a8 41 01 40 lui $8, 16385
+# CHECK-NEXT: 16c: 08 3d 87 9e lh $8, -24953($8)
+
+# CHECK: SYMBOL TABLE:
+# CHECK: 00000130 g F .text 00000028 glob1
+# CHECK: 00000158 g F .text 00000018 glob2
+# CHECK: 00009ff0 g *ABS* 00000000 _gp_disp
+
+ .globl glob1
+ .type glob1, @function
+ .set micromips
+ .ent glob1
+glob1:
+ lui $t0,%hi(_gp_disp+0x00000001)
+ lh $t0,%lo(_gp_disp+0x00000001)($t0)
+
+ lui $t0,%hi(_gp_disp+0x00007fff)
+ lh $t0,%lo(_gp_disp+0x00007fff)($t0)
+
+ lui $t0,%hi(_gp_disp+0x00008080)
+ lh $t0,%lo(_gp_disp+0x00008080)($t0)
+
+ lui $t0,%hi(_gp_disp+0x00018000)
+ lh $t0,%lo(_gp_disp+0x00018000)($t0)
+
+ lui $t0,%hi(_gp_disp+0x40000000)
+ lh $t0,%lo(_gp_disp+0x40000000)($t0)
+ .end glob1
+
+ .globl glob2
+ .type glob2, @function
+ .set micromips
+ .ent glob2
+glob2:
+ lui $t0,%hi(_gp_disp+0x00000001)
+ lui $t0,%hi(_gp_disp+0x00007fff)
+ lui $t0,%hi(_gp_disp+0x00008080)
+ lui $t0,%hi(_gp_disp+0x00018000)
+ lui $t0,%hi(_gp_disp+0x40000000)
+ lh $t0,%lo(_gp_disp+0x40000000)($t0)
+ .end glob2
diff --git a/test/elf/Mips/initfini-micro.test b/test/elf/Mips/initfini-micro.test
new file mode 100644
index 000000000000..ba30e89ade21
--- /dev/null
+++ b/test/elf/Mips/initfini-micro.test
@@ -0,0 +1,45 @@
+# Check that if _init/_fini symbols are microMIPS encoded, DT_INIT/DT_FINI tags
+# use adjusted values with set the last bit.
+
+# RUN: yaml2obj -format=elf %s > %t.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t.o
+# RUN: llvm-readobj -symbols -dynamic-table %t.so | FileCheck %s
+
+# CHECK: Name: _init (1)
+# CHECK-NEXT: Value: 0xF5
+# CHECK: Name: _fini (7)
+# CHECK-NEXT: Value: 0xF9
+#
+# CHECK: 0x0000000C INIT 0xF5
+# CHECK: 0x0000000D FINI 0xF9
+
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2, EF_MIPS_MICROMIPS ]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x18
+
+Symbols:
+ Global:
+ - Name: _init
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0
+ Size: 0x4
+ Other: [ STO_MIPS_MICROMIPS ]
+ - Name: _fini
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x4
+ Size: 0x4
+ Other: [ STO_MIPS_MICROMIPS ]
+...
diff --git a/test/elf/Mips/interpreter-64.test b/test/elf/Mips/interpreter-64.test
new file mode 100644
index 000000000000..3ece3e6a467a
--- /dev/null
+++ b/test/elf/Mips/interpreter-64.test
@@ -0,0 +1,26 @@
+# Check program interpreter setup.
+# RUN: yaml2obj -format=elf %s > %t.o
+# RUN: lld -flavor gnu -target mips64el -e main -o %t.exe %t.o
+# RUN: llvm-objdump -s %t.exe | FileCheck %s
+
+# CHECK: Contents of section .interp:
+# CHECK-NEXT: {{[0-9a-f]+}} 2f6c6962 36342f6c 642e736f 2e3100 /lib64/ld.so.1.
+
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ARCH_64 ]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x10
+ Size: 0x08
+
+Symbols:
+ Global:
+ - Name: main
+ Section: .text
diff --git a/test/elf/Mips/interpreter.test b/test/elf/Mips/interpreter.test
new file mode 100644
index 000000000000..5355f7709fbd
--- /dev/null
+++ b/test/elf/Mips/interpreter.test
@@ -0,0 +1,26 @@
+# Check program interpreter setup.
+# RUN: yaml2obj -format=elf %s > %t.o
+# RUN: lld -flavor gnu -target mipsel -e main -o %t.exe %t.o
+# RUN: llvm-objdump -s %t.exe | FileCheck %s
+
+# CHECK: Contents of section .interp:
+# CHECK-NEXT: {{[0-9a-f]+}} 2f6c6962 2f6c642e 736f2e31 00 /lib/ld.so.1.
+
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32 ]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x10
+ Size: 0x04
+
+Symbols:
+ Global:
+ - Name: main
+ Section: .text
diff --git a/test/elf/Mips/invalid-reginfo.test b/test/elf/Mips/invalid-reginfo.test
new file mode 100644
index 000000000000..d56223bf2e04
--- /dev/null
+++ b/test/elf/Mips/invalid-reginfo.test
@@ -0,0 +1,28 @@
+# Check that LLD shows an error if .reginfo section has invalid size
+
+# RUN: yaml2obj -format=elf %s > %t.o
+# RUN: not lld -flavor gnu -target mipsel -o %t.exe %t.o 2>&1 | FileCheck %s
+
+# CHECK: Invalid size of MIPS_REGINFO section
+
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x04
+ - Name: .reginfo
+ Type: SHT_MIPS_REGINFO
+ Flags: [ SHF_ALLOC ]
+ AddressAlign: 0x01
+ Size: 0x25
+Symbols:
+ Global:
+ - Name: main
+ Section: .text
diff --git a/test/elf/Mips/jalx-align-err.test b/test/elf/Mips/jalx-align-err.test
new file mode 100644
index 000000000000..3db18fc98fac
--- /dev/null
+++ b/test/elf/Mips/jalx-align-err.test
@@ -0,0 +1,46 @@
+# Check that LLD shows an error if jalx target value is not word-aligned.
+
+# RUN: yaml2obj -format=elf %s > %t-obj
+# RUN: not lld -flavor gnu -target mipsel -e T0 -o %t-exe %t-obj 2>&1 \
+# RUN: | FileCheck %s
+
+# CHECK: The jalx target 0x400116 is not word-aligned
+
+!ELF
+FileHeader: !FileHeader
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2,
+ EF_MIPS_MICROMIPS ]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 8
+ AddressAlign: 16
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+
+- Name: .rel.text
+ Type: SHT_REL
+ Info: .text
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0
+ Symbol: T1
+ Type: R_MICROMIPS_26_S1
+
+Symbols:
+ Global:
+ - Name: T0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0
+ Size: 4
+ Other: [ STO_MIPS_MICROMIPS ]
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 6
+ Size: 2
diff --git a/test/elf/Mips/jump-fix-err.test b/test/elf/Mips/jump-fix-err.test
new file mode 100644
index 000000000000..981179938397
--- /dev/null
+++ b/test/elf/Mips/jump-fix-err.test
@@ -0,0 +1,45 @@
+# Check that LLD shows an error in case
+# of replacing an unknown unstruction by jalx.
+
+# RUN: yaml2obj -format=elf %s > %t-obj
+# RUN: not lld -flavor gnu -target mipsel -o %t-exe %t-obj 2>&1 | FileCheck %s
+
+# CHECK: Unsupported jump opcode (0x0) for ISA modes cross call
+
+!ELF
+FileHeader: !FileHeader
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2,
+ EF_MIPS_MICROMIPS ]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 8
+ AddressAlign: 16
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+
+- Name: .rel.text
+ Type: SHT_REL
+ Info: .text
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0
+ Symbol: T0
+ Type: R_MICROMIPS_26_S1
+
+Symbols:
+ Global:
+ - Name: __start
+ Section: .text
+ Type: STT_FUNC
+ Size: 4
+ Other: [ STO_MIPS_MICROMIPS ]
+ - Name: T0
+ Section: .text
+ Type: STT_FUNC
+ Value: 4
+ Size: 4
diff --git a/test/elf/Mips/la25-stub-micro.test b/test/elf/Mips/la25-stub-micro.test
new file mode 100644
index 000000000000..d41297a0ddc3
--- /dev/null
+++ b/test/elf/Mips/la25-stub-micro.test
@@ -0,0 +1,140 @@
+# Check microMIPS LA25 stubs creation when PIC code
+# is called from non-PIC routines.
+
+# Build executable from pic and non-pic code.
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-npic.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-pic.o
+# RUN: yaml2obj -format=elf -docnum 3 %s > %t-main.o
+# RUN: lld -flavor gnu -target mipsel -e glob -o %t.exe \
+# RUN: %t-npic.o %t-pic.o %t-main.o
+
+# RUN: llvm-readobj -t %t.exe | FileCheck -check-prefix=SYM %s
+# RUN: llvm-objdump -s %t.exe | FileCheck -check-prefix=ASM %s
+
+# SYM: Name: loc (13)
+# SYM-NEXT: Value: 0x400135
+# SYM: Name: T1N (1)
+# SYM-NEXT: Value: 0x400111
+# SYM: Name: T1 (5)
+# SYM-NEXT: Value: 0x400121
+# SYM: Name: glob (8)
+# SYM-NEXT: Value: 0x400125
+
+# ASM: Contents of section .text:
+# ASM-NEXT: 400110 00000000 00000000 00000000 00000000
+# ASM-NEXT: 400120 00000000 00000000 00000000 10f04900
+# 0x100049 << 2 == 0x400125 (jalx glob) --^
+# ASM-NEXT: 400130 00000000 20f49200 00000000 20f48800
+# ^-- 0x100049 << 2 == 0x400124 (jal glob)
+# 0x100044 << 2 == 0x400110 (jal T1N) --^
+# ASM-NEXT: 400140 00000000 20f4a800 00000000 00000000
+# ^-- 0x100054 << 2 == 0x400150 (jal T1 stub)
+# ASM-NEXT: 400150 b9414000 20d49000 39332101 00000000
+# ^-- j 0x400120 (T1)
+
+# npic.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2,
+ EF_MIPS_CPIC, EF_MIPS_MICROMIPS ]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x04
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1N
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+ Other: [ STO_MIPS_MICROMIPS ]
+
+# pic.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2,
+ EF_MIPS_CPIC, EF_MIPS_PIC, EF_MIPS_MICROMIPS ]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x04
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+ Other: [ STO_MIPS_MICROMIPS ]
+
+# main.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2,
+ EF_MIPS_CPIC, EF_MIPS_MICROMIPS ]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Content: '000000000000000000f400000000000000f400000000000000f400000000000000f4000000000000'
+# jal loc jal glob jal T1N jal T1
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x04
+ Info: .text
+ Relocations:
+ - Offset: 0x08
+ Symbol: .text
+ Type: R_MICROMIPS_26_S1
+ - Offset: 0x10
+ Symbol: glob
+ Type: R_MICROMIPS_26_S1
+ - Offset: 0x18
+ Symbol: T1N
+ Type: R_MICROMIPS_26_S1
+ - Offset: 0x20
+ Symbol: T1
+ Type: R_MICROMIPS_26_S1
+
+Symbols:
+ Local:
+ - Name: loc
+ Section: .text
+ Value: 0x10
+ Size: 0x18
+ Other: [ STO_MIPS_MICROMIPS ]
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ Global:
+ - Name: glob
+ Section: .text
+ Size: 0x10
+ Other: [ STO_MIPS_MICROMIPS ]
+ - Name: T1
+ - Name: T1N
+...
diff --git a/test/elf/Mips/la25-stub.test b/test/elf/Mips/la25-stub.test
new file mode 100644
index 000000000000..2c4b26452cec
--- /dev/null
+++ b/test/elf/Mips/la25-stub.test
@@ -0,0 +1,133 @@
+# Check LA25 stubs creation when PIC code is called from non-PIC routines.
+
+# Build executable from pic and non-pic code.
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-npic.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-pic.o
+# RUN: yaml2obj -format=elf -docnum 3 %s > %t-main.o
+# RUN: lld -flavor gnu -target mipsel -e glob -o %t.exe \
+# RUN: %t-npic.o %t-pic.o %t-main.o
+
+# RUN: llvm-readobj -t %t.exe | FileCheck -check-prefix=SYM %s
+# RUN: llvm-objdump -s %t.exe | FileCheck -check-prefix=ASM %s
+
+# SYM: Name: loc (13)
+# SYM-NEXT: Value: 0x400134
+# SYM: Name: T1N (1)
+# SYM-NEXT: Value: 0x400110
+# SYM: Name: T1 (5)
+# SYM-NEXT: Value: 0x400120
+# SYM: Name: glob (8)
+# SYM-NEXT: Value: 0x400124
+
+# ASM: Contents of section .text:
+# ASM-NEXT: 400110 00000000 00000000 00000000 00000000
+# ASM-NEXT: 400120 00000000 00000000 00000000 49001000
+# 0x100049 << 2 == 0x400124 (glob) --^
+# ASM-NEXT: 400130 00000000 49001000 00000000 44001000
+# ^-- 0x100049 << 2 == 0x400124 (glob)
+# 0x100044 << 2 == 0x400110 (T1N) --^
+# ASM-NEXT: 400140 00000000 54001000 00000000 00000000
+# ^-- 0x100054 << 2 == 0x400150 (T1 stub)
+# ASM-NEXT: 400150 4000193c 48001008 20013927 00000000
+# ^-- j 0x400120 (T1)
+
+# npic.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32, EF_MIPS_CPIC ]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x04
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1N
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+
+# pic.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32, EF_MIPS_CPIC, EF_MIPS_PIC ]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x04
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+
+# main.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32, EF_MIPS_CPIC ]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x28
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x04
+ Info: .text
+ Relocations:
+ - Offset: 0x08
+ Symbol: .text
+ Type: R_MIPS_26
+ Addend: 0
+ - Offset: 0x10
+ Symbol: glob
+ Type: R_MIPS_26
+ Addend: 0
+ - Offset: 0x18
+ Symbol: T1N
+ Type: R_MIPS_26
+ Addend: 0
+ - Offset: 0x20
+ Symbol: T1
+ Type: R_MIPS_26
+ Addend: 0
+
+Symbols:
+ Local:
+ - Name: loc
+ Section: .text
+ Value: 0x10
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ Global:
+ - Name: glob
+ Section: .text
+ - Name: T1
+ - Name: T1N
+...
diff --git a/test/elf/Mips/mips-options-gp0.test b/test/elf/Mips/mips-options-gp0.test
new file mode 100644
index 000000000000..339ab97253b6
--- /dev/null
+++ b/test/elf/Mips/mips-options-gp0.test
@@ -0,0 +1,78 @@
+# Check reading GP0 value from .MIPS.options section
+#
+# RUN: yaml2obj -format=elf %s > %t.o
+# RUN: lld -flavor gnu -target mipsel -e G1 -shared -o %t.so %t.o
+# RUN: llvm-readobj -symbols %t.so | FileCheck -check-prefix=SYM %s
+# RUN: llvm-objdump -s %t.so | FileCheck -check-prefix=SEC %s
+
+# SYM: Name: L1 (1)
+# SYM-NEXT: Value: 0xCC
+# SYM-NEXT: Size: 4
+# SYM-NEXT: Binding: Local (0x0)
+# SYM-NEXT: Type: Function (0x2)
+# SYM-NEXT: Other: 0
+# SYM-NEXT: Section: .text (0x4)
+
+# SYM: Name: _gp (34)
+# SYM-NEXT: Value: 0x8FF0
+# SYM-NEXT: Size: 0
+# SYM-NEXT: Binding: Global (0x1)
+# SYM-NEXT: Type: Object (0x1)
+# SYM-NEXT: Other: 0
+# SYM-NEXT: Section: Absolute (0xFFF1)
+
+# 0xffff80dc == 0x0 (addend) + 0x00cc (L1) + 0x1000 (GP0) - 0x8ff0 (_gp)
+# SEC: Contents of section .rodata:
+# SEC-NEXT: 00d4 dc80ffff 00000000 00000000 00000000 ................
+
+!ELF
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2 ]
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x08
+
+- Name: .rodata
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC ]
+ AddressAlign: 0x04
+ Size: 16
+
+- Name: .rel.rodata
+ Type: SHT_REL
+ Link: .symtab
+ Info: .rodata
+ AddressAlign: 0x04
+ Relocations:
+ - Offset: 0
+ Symbol: L1
+ Type: R_MIPS_GPREL32
+
+- Name: .MIPS.options
+ Type: SHT_MIPS_OPTIONS
+ Flags: [ SHF_ALLOC ]
+ AddressAlign: 0x01
+ Content: "0128000000000000000000000000000000000000000000000000000000100000"
+
+Symbols:
+ Local:
+ - Name: L1
+ Section: .text
+ Value: 0x00
+ Size: 0x04
+ - Name: .rodata
+ Type: STT_SECTION
+ Section: .rodata
+ Global:
+ - Name: G1
+ Section: .text
+ Value: 0x04
+ Size: 0x04
diff --git a/test/elf/Mips/n64-rel-chain.test b/test/elf/Mips/n64-rel-chain.test
new file mode 100644
index 000000000000..0ae7af73ae83
--- /dev/null
+++ b/test/elf/Mips/n64-rel-chain.test
@@ -0,0 +1,134 @@
+# Check handling MIPS N64 ABI relocation "chains".
+
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-so.o
+# RUN: lld -flavor gnu -target mips64el -shared -o %t.so %t-so.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-o.o
+# RUN: lld -flavor gnu -target mips64el -e T0 -o %t.exe %t-o.o %t.so
+# RUN: llvm-objdump -s %t.exe | FileCheck %s
+
+# CHECK: Contents of section .text:
+# CHECK-NEXT: 1200001d0 01000000 00000000 208e0000 00000000 ........ .......
+# CHECK-NEXT: 1200001e0 20800000 f8010000 28800000 00000000 .......(.......
+# CHECK: Contents of section .pdr:
+# CHECK-NEXT: 0000 d0010020 e0010020 ... ...
+
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ARCH_64]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 16
+ Size: 8
+
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+
+ Global:
+ - Name: T1
+ Type: STT_FUNC
+ Section: .text
+ Value: 0
+ Size: 8
+
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ARCH_64]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 16
+ Size: 32
+
+ - Name: .rela.text
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 8
+ Info: .text
+ Relocations:
+ - Offset: 0x00
+ Symbol: LT1
+ Type: R_MIPS_GPREL16
+ Type2: R_MIPS_SUB
+ Type3: R_MIPS_HI16
+ - Offset: 0x08
+ Symbol: LT1
+ Type: R_MIPS_GPREL16
+ Type2: R_MIPS_SUB
+ Type3: R_MIPS_LO16
+ - Offset: 0x10
+ Symbol: .rodata
+ Type: R_MIPS_GOT_PAGE
+ Addend: 8
+ - Offset: 0x14
+ Symbol: .rodata
+ Type: R_MIPS_GOT_OFST
+ Addend: 8
+ - Offset: 0x18
+ Symbol: T1
+ Type: R_MIPS_CALL16
+
+ - Name: .pdr
+ Type: SHT_PROGBITS
+ AddressAlign: 4
+ Size: 8
+
+ - Name: .rela.pdr
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 8
+ Info: .pdr
+ Relocations:
+ - Offset: 0x00
+ Symbol: LT1
+ Type: R_MIPS_32
+ - Offset: 0x04
+ Symbol: T0
+ Type: R_MIPS_32
+
+ - Name: .rodata
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC ]
+ AddressAlign: 16
+ Size: 16
+
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .rodata
+ Type: STT_SECTION
+ Section: .rodata
+ - Name: .pdr
+ Type: STT_SECTION
+ Section: .pdr
+
+ Global:
+ - Name: LT1
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x00
+ Size: 0x10
+ - Name: T0
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x10
+ Size: 0x10
+ - Name: T1
+...
diff --git a/test/elf/Mips/opt-emulation.test b/test/elf/Mips/opt-emulation.test
new file mode 100644
index 000000000000..2d1e7142c386
--- /dev/null
+++ b/test/elf/Mips/opt-emulation.test
@@ -0,0 +1,41 @@
+# Check MIPS specific arguments of the -m command line option.
+
+# RUN: yaml2obj -format=elf %s > %t-obj
+# RUN: lld -flavor gnu -target mipsel -m elf32ltsmip -o %t-exe %t-obj
+# RUN: llvm-readobj -file-headers %t-exe | FileCheck -check-prefix=LE-O32 %s
+
+# LE-O32: Class: 32-bit (0x1)
+# LE-O32: DataEncoding: LittleEndian (0x1)
+# LE-O32: FileVersion: 1
+# LE-O32: OS/ABI: SystemV (0x0)
+# LE-O32: ABIVersion: 0
+# LE-O32: Machine: EM_MIPS (0x8)
+# LE-O32: Version: 1
+# LE-O32: Flags [ (0x70001005)
+# LE-O32-NEXT: EF_MIPS_ABI_O32 (0x1000)
+# LE-O32-NEXT: EF_MIPS_ARCH_32R2 (0x70000000)
+# LE-O32-NEXT: EF_MIPS_CPIC (0x4)
+# LE-O32-NEXT: EF_MIPS_NOREORDER (0x1)
+# LE-O32-NEXT: ]
+
+!ELF
+FileHeader: !FileHeader
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_NOREORDER, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Content: "00000000"
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: __start
+ Section: .text
+ Value: 0x0
+ Size: 4
diff --git a/test/elf/Mips/pc23-range.test b/test/elf/Mips/pc23-range.test
new file mode 100644
index 000000000000..7166176c4628
--- /dev/null
+++ b/test/elf/Mips/pc23-range.test
@@ -0,0 +1,56 @@
+# Check that LLD shows an error if ADDIUPC immediate is out of range.
+
+# RUN: yaml2obj -format=elf %s > %t-obj
+# RUN: lld -flavor gnu -target mipsel -o %t-exe %t-obj 2>&1 | FileCheck %s
+
+# CHECK: The addiupc instruction immediate 0x02000008 is out of range
+
+!ELF
+FileHeader: !FileHeader
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2,
+ EF_MIPS_MICROMIPS ]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Content: "0000000080780100"
+# ^ PC23: 1 << 2 = 4 => T0 + 4 - 4 = T0
+ AddressAlign: 16
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+
+- Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC ]
+ AddressAlign: 0x04
+ Size: 0x4000000
+
+- Name: .rel.text
+ Type: SHT_REL
+ Info: .text
+ AddressAlign: 4
+ Relocations:
+ - Offset: 4
+ Symbol: T0
+ Type: R_MICROMIPS_PC23_S2
+
+Symbols:
+ Global:
+ - Name: __start
+ Section: .text
+ Type: STT_FUNC
+ Size: 8
+ Other: [ STO_MIPS_MICROMIPS ]
+ - Name: TZ
+ Section: .data
+ Type: STT_FUNC
+ Value: 0
+ Size: 0x2000000
+ - Name: T0
+ Section: .data
+ Type: STT_FUNC
+ Value: 0x2000000
+ Size: 4
diff --git a/test/elf/Mips/plt-entry-mixed-1.test b/test/elf/Mips/plt-entry-mixed-1.test
new file mode 100644
index 000000000000..bc45763fa16d
--- /dev/null
+++ b/test/elf/Mips/plt-entry-mixed-1.test
@@ -0,0 +1,114 @@
+# REQUIRES: mips
+
+# Conditions:
+# a) Object file contains both R_MIPS_26 and microMIPS non-jal relocations.
+# b) The R_MIPS_26 relocation handled first.
+# Check:
+# a) PLT contains the only regular entry.
+
+# Build shared library
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t.so.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t.so.o
+
+# Build executable
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t.o.o
+# RUN: lld -flavor gnu -target mipsel -e T0 -o %t.exe %t.o.o %t.so
+# RUN: llvm-objdump -d %t.exe | FileCheck %s
+
+# CHECK: Disassembly of section .plt:
+# CHECK-NEXT: .plt:
+# CHECK-NEXT: 400170: 40 00 1c 3c lui $gp, 64
+# CHECK-NEXT: 400174: 00 20 99 8f lw $25, 8192($gp)
+# CHECK-NEXT: 400178: 00 20 9c 27 addiu $gp, $gp, 8192
+# CHECK-NEXT: 40017c: 23 c0 1c 03 subu $24, $24, $gp
+# CHECK-NEXT: 400180: 21 78 e0 03 move $15, $ra
+# CHECK-NEXT: 400184: 82 c0 18 00 srl $24, $24, 2
+# CHECK-NEXT: 400188: 09 f8 20 03 jalr $25
+# CHECK-NEXT: 40018c: fe ff 18 27 addiu $24, $24, -2
+# CHECK-NEXT: 400190: 40 00 0f 3c lui $15, 64
+# CHECK-NEXT: 400194: 08 20 f9 8d lw $25, 8200($15)
+# CHECK-NEXT: 400198: 08 00 20 03 jr $25
+# CHECK-NEXT: 40019c: 08 20 f8 25 addiu $24, $15, 8200
+
+# so.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+
+# o.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_CPIC, EF_MIPS_ABI_O32,
+ EF_MIPS_ARCH_32R2, EF_MIPS_MICROMIPS]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Content: "0000000C00000000"
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .data
+ Type: SHT_PROGBITS
+ Size: 0x08
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_ALLOC]
+
+- Name: .rel.text
+ Type: SHT_REL
+ Info: .text
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x0
+ Symbol: T1
+ Type: R_MIPS_26
+
+- Name: .rel.data
+ Type: SHT_REL
+ Info: .data
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x00
+ Symbol: T1
+ Type: R_MICROMIPS_HI16
+ - Offset: 0x00
+ Symbol: T1
+ Type: R_MICROMIPS_LO16
+
+Symbols:
+ Global:
+ - Name: T0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 0x8
+ - Name: D0
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x0
+ Size: 8
+ - Name: T1
+...
diff --git a/test/elf/Mips/plt-entry-mixed-2.test b/test/elf/Mips/plt-entry-mixed-2.test
new file mode 100644
index 000000000000..5aec7d7a328a
--- /dev/null
+++ b/test/elf/Mips/plt-entry-mixed-2.test
@@ -0,0 +1,93 @@
+# REQUIRES: mips
+
+# Conditions:
+# a) Object file contains both R_MIPS_26 and R_MICROMIPS_26_S1 relocations.
+# Check:
+# a) PLT contains both regular and compressed PLT entries
+
+# Build shared library
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t.so.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t.so.o
+
+# Build executable
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t.o.o
+# RUN: lld -flavor gnu -target mipsel -e T0 -o %t.exe %t.o.o %t.so
+# RUN: llvm-objdump -s %t.exe | FileCheck %s
+
+# FIXME (simon): Check the disassembler output when llvm-objdump starts
+# to support microMIPS instruction encoding.
+
+# CHECK: Contents of section .plt:
+# CHECK-NEXT: 400170 40001c3c 0020998f 00209c27 23c01c03 @..<. ... .'#...
+# CHECK-NEXT: 400180 2178e003 82c01800 09f82003 feff1827 !x........ ....'
+# CHECK-NEXT: 400190 40000f3c 0820f98d 08002003 0820f825 @..<. .... .. .%
+# CHECK-NEXT: 4001a0 00799a07 22ff0000 9945020f .y.."....E..
+
+# so.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T2
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+
+# o.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_CPIC, EF_MIPS_ABI_O32,
+ EF_MIPS_ARCH_32R2, EF_MIPS_MICROMIPS]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Content: "0000000C000000000000000000000000"
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .rel.text
+ Type: SHT_REL
+ Info: .text
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x0
+ Symbol: T2
+ Type: R_MIPS_26
+ - Offset: 0x8
+ Symbol: T2
+ Type: R_MICROMIPS_26_S1
+
+Symbols:
+ Global:
+ - Name: T0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 0x8
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x8
+ Size: 0x8
+ Other: [STO_MIPS_MICROMIPS]
+ - Name: T2
+...
diff --git a/test/elf/Mips/plt-entry-mixed-3.test b/test/elf/Mips/plt-entry-mixed-3.test
new file mode 100644
index 000000000000..c61991b4b139
--- /dev/null
+++ b/test/elf/Mips/plt-entry-mixed-3.test
@@ -0,0 +1,98 @@
+# REQUIRES: mips
+
+# Conditions:
+# a) Object file contains microMIPS instructions.
+# b) There is a relocation refers arbitrary symbols and requires a PLT entry.
+# Check:
+# a) PLT contains a compressed entry.
+
+# Build shared library
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t.so.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t.so.o
+
+# Build executable
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t.o.o
+# RUN: lld -flavor gnu -target mipsel -e T0 -o %t.exe %t.o.o %t.so
+# RUN: llvm-objdump -s %t.exe | FileCheck %s
+
+# FIXME (simon): Check the disassembler output when llvm-objdump starts
+# to support microMIPS instruction encoding.
+
+# CHECK: Contents of section .plt:
+# CHECK-NEXT: 400170 8079a407 23ff0000 35052525 0233feff .y..#...5.%%.3..
+# CHECK-NEXT: 400180 ff0df945 830f000c 0079a007 22ff0000 ...E.....y.."...
+# CHECK-NEXT: 400190 9945020f .E..
+
+# so.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+
+# o.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_CPIC, EF_MIPS_ABI_O32,
+ EF_MIPS_ARCH_32R2, EF_MIPS_MICROMIPS]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 16
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .data
+ Type: SHT_PROGBITS
+ Size: 0x08
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_ALLOC]
+
+- Name: .rel.data
+ Type: SHT_REL
+ Info: .data
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x00
+ Symbol: T1
+ Type: R_MICROMIPS_HI16
+ - Offset: 0x00
+ Symbol: T1
+ Type: R_MICROMIPS_LO16
+
+Symbols:
+ Global:
+ - Name: T0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 16
+ - Name: D0
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x0
+ Size: 8
+ - Name: T1
+...
diff --git a/test/elf/Mips/plt-entry-mixed-4.test b/test/elf/Mips/plt-entry-mixed-4.test
new file mode 100644
index 000000000000..acf5060621f6
--- /dev/null
+++ b/test/elf/Mips/plt-entry-mixed-4.test
@@ -0,0 +1,85 @@
+# REQUIRES: mips
+
+# Conditions:
+# a) Object file contains R_MIPS_26 relocation refers to the microMIPS symbol.
+# Check:
+# a) PLT contains a regular non-compressed entry.
+
+# Build shared library
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t.so.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t.so.o
+
+# Build executable
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t.o.o
+# RUN: lld -flavor gnu -target mipsel -e T0 -o %t.exe %t.o.o %t.so
+# RUN: llvm-objdump -s %t.exe | FileCheck %s
+
+# FIXME (simon): Check the disassembler output when llvm-objdump starts
+# to support microMIPS instruction encoding.
+
+# CHECK: Contents of section .plt:
+# CHECK-NEXT: 400170 40001c3c 0020998f 00209c27 23c01c03 @..<. ... .'#...
+# CHECK-NEXT: 400180 2178e003 82c01800 09f82003 feff1827 !x........ ....'
+# CHECK-NEXT: 400190 40000f3c 0820f98d 08002003 0820f825 @..<. .... .. .%
+
+# so.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32,
+ EF_MIPS_ARCH_32R2, EF_MIPS_MICROMIPS]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+ Other: [STO_MIPS_MICROMIPS]
+
+# o.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_CPIC, EF_MIPS_ABI_O32,
+ EF_MIPS_ARCH_32R2, EF_MIPS_MICROMIPS]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Content: "0000000C00000000"
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .rel.text
+ Type: SHT_REL
+ Info: .text
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x0
+ Symbol: T1
+ Type: R_MIPS_26
+
+Symbols:
+ Global:
+ - Name: T0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 0x8
+ - Name: T1
+...
diff --git a/test/elf/Mips/plt-entry-r6.test b/test/elf/Mips/plt-entry-r6.test
new file mode 100644
index 000000000000..bb05531487ff
--- /dev/null
+++ b/test/elf/Mips/plt-entry-r6.test
@@ -0,0 +1,109 @@
+# REQUIRES: mips
+
+# Check generation of PLT entries in case of R6 target ABI.
+
+# Build shared library
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-so.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t-so.o
+
+# Build executable
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-o.o
+# RUN: lld -flavor gnu -target mipsel -e T0 -o %t.exe %t-o.o %t.so
+# RUN: llvm-objdump -d %t.exe | FileCheck %s
+
+# CHECK: Disassembly of section .plt:
+# CHECK-NEXT: .plt:
+# CHECK-NEXT: 400160: 40 00 1c 3c lui $gp, 64
+# CHECK-NEXT: 400164: 00 20 99 8f lw $25, 8192($gp)
+# CHECK-NEXT: 400168: 00 20 9c 27 addiu $gp, $gp, 8192
+# CHECK-NEXT: 40016c: 23 c0 1c 03 subu $24, $24, $gp
+# CHECK-NEXT: 400170: 21 78 e0 03 move $15, $ra
+# CHECK-NEXT: 400174: 82 c0 18 00 srl $24, $24, 2
+# CHECK-NEXT: 400178: 09 f8 20 03 jalr $25
+# CHECK-NEXT: 40017c: fe ff 18 27 addiu $24, $24, -2
+# CHECK-NEXT: 400180: 40 00 0f 3c lui $15, 64
+# CHECK-NEXT: 400184: 08 20 f9 8d lw $25, 8200($15)
+# CHECK-NEXT: 400188: 09 00 20 03 jr $25
+# CHECK-NEXT: 40018c: 08 20 f8 25 addiu $24, $15, 8200
+
+# so.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R6]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+
+# o.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R6]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Content: "0000000C00000000"
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .data
+ Type: SHT_PROGBITS
+ Size: 0x08
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_ALLOC]
+
+- Name: .rel.text
+ Type: SHT_REL
+ Info: .text
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x0
+ Symbol: T1
+ Type: R_MIPS_26
+
+- Name: .rel.data
+ Type: SHT_REL
+ Info: .data
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x00
+ Symbol: T1
+ Type: R_MIPS_HI16
+ - Offset: 0x00
+ Symbol: T1
+ Type: R_MIPS_LO16
+
+Symbols:
+ Global:
+ - Name: T0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 0x8
+ - Name: D0
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x0
+ Size: 8
+ - Name: T1
+...
diff --git a/test/elf/Mips/plt-header-micro.test b/test/elf/Mips/plt-header-micro.test
new file mode 100644
index 000000000000..ce042741cd32
--- /dev/null
+++ b/test/elf/Mips/plt-header-micro.test
@@ -0,0 +1,108 @@
+# REQUIRES: mips
+
+# Check initialization of .plt header entries
+# if all PLT entries use microMIPS encoding.
+
+# Build shared library
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-so.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t-so.o
+
+# Build executable
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-o.o
+# RUN: lld -flavor gnu -target mipsel -e glob -o %t.exe %t-o.o %t.so
+# RUN: llvm-objdump -d -mattr=micromips %t.exe | FileCheck -check-prefix=DIS %s
+# RUN: llvm-objdump -section-headers %t.exe | FileCheck -check-prefix=EXE %s
+
+# DIS: Disassembly of section .plt:
+# DIS-NEXT: .plt:
+# DIS-NEXT: 400170: 80 79 a4 07 addiupc $3, 7824
+# DIS-NEXT: 400174: 23 ff 00 00 lw $25, 0($3)
+# DIS-NEXT: 400178: 35 05 subu16 $2, $2, $3
+# DIS-NEXT: 40017a: 25 25 srl16 $2, $2, 2
+# DIS-NEXT: 40017c: 02 33 fe ff addiu $24, $2, -2
+# DIS-NEXT: 400180: ff 0d move $15, $ra
+# DIS-NEXT: 400182: f9 45 jalrs16 $25
+# DIS-NEXT: 400184: 83 0f move $gp, $3
+# DIS-NEXT: 400186: 00 0c nop
+
+# DIS-NEXT: 400188: 00 79 a0 07 addiupc $2, 7808
+# DIS-NEXT: 40018c: 22 ff 00 00 lw $25, 0($2)
+# DIS-NEXT: 400190: 99 45 jr16 $25
+# DIS-NEXT: 400192: 02 0f move $24, $2
+
+# EXE: Sections:
+# EXE: Idx Name Size Address Type
+# EXE: 6 .plt 00000024 0000000000400170 TEXT DATA
+# EXE: 10 .got.plt 0000000c 0000000000402000 DATA
+
+# so.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+
+# o.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_PIC, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2, EF_MIPS_MICROMIPS ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Content: '000000000000000000f4000000000000f400000000000000f400000000000000'
+# jal .text jal glob jal T1
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x04
+ Info: .text
+ Relocations:
+ - Offset: 0x08
+ Symbol: .text
+ Type: R_MICROMIPS_26_S1
+ - Offset: 0x10
+ Symbol: glob
+ Type: R_MICROMIPS_26_S1
+ - Offset: 0x18
+ Symbol: T1
+ Type: R_MICROMIPS_26_S1
+
+Symbols:
+ Local:
+ - Name: loc
+ Section: .text
+ Value: 0x10
+ Other: [ STO_MIPS_MICROMIPS ]
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ Global:
+ - Name: glob
+ Section: .text
+ Other: [ STO_MIPS_MICROMIPS ]
+ - Name: T1
+...
diff --git a/test/elf/Mips/plt-header-mixed.test b/test/elf/Mips/plt-header-mixed.test
new file mode 100644
index 000000000000..0d3af19ee593
--- /dev/null
+++ b/test/elf/Mips/plt-header-mixed.test
@@ -0,0 +1,105 @@
+# REQUIRES: mips
+
+# Check initialization of .plt header entries if there are both regular
+# and microMIPS encoded PLT entries. Check that R_MIPS_26 and R_MICROMIPS_26_S1
+# relocation with the same target cause generation of two distinct PLT entries.
+
+# Build shared library
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-so.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t-so.o
+
+# Build executable
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-o.o
+# RUN: lld -flavor gnu -target mipsel -e globR -o %t.exe %t-o.o %t.so
+# RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=DIS %s
+# RUN: llvm-objdump -section-headers %t.exe | FileCheck -check-prefix=EXE %s
+
+# DIS: Disassembly of section .plt:
+# DIS-NEXT: .plt:
+# DIS-NEXT: 400170: 40 00 1c 3c lui $gp, 64
+# DIS-NEXT: 400174: 00 20 99 8f lw $25, 8192($gp)
+# DIS-NEXT: 400178: 00 20 9c 27 addiu $gp, $gp, 8192
+# DIS-NEXT: 40017c: 23 c0 1c 03 subu $24, $24, $gp
+# DIS-NEXT: 400180: 21 78 e0 03 move $15, $ra
+# DIS-NEXT: 400184: 82 c0 18 00 srl $24, $24, 2
+# DIS-NEXT: 400188: 09 f8 20 03 jalr $25
+# DIS-NEXT: 40018c: fe ff 18 27 addiu $24, $24, -2
+
+# DIS-NEXT: 400190: 40 00 0f 3c lui $15, 64
+# DIS-NEXT: 400194: 08 20 f9 8d lw $25, 8200($15)
+# DIS-NEXT: 400198: 08 00 20 03 jr $25
+# DIS-NEXT: 40019c: 08 20 f8 25 addiu $24, $15, 8200
+
+# FIXME (simon): Check micromips PLT entry
+# DIS-NEXT: 4001a8: 99 45 02 0f jal 201922148
+
+# EXE: Sections:
+# EXE: Idx Name Size Address Type
+# EXE: 6 .plt 0000003c 0000000000400170 TEXT DATA
+# EXE: 10 .got.plt 0000000c 0000000000402000 DATA
+
+# so.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+
+# o.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_PIC, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2, EF_MIPS_MICROMIPS ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x8
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x04
+ Info: .text
+ Relocations:
+ - Offset: 0x0
+ Symbol: T1
+ Type: R_MIPS_26
+ - Offset: 0x4
+ Symbol: T1
+ Type: R_MICROMIPS_26_S1
+
+Symbols:
+ Global:
+ - Name: globR
+ Section: .text
+ Value: 0x0
+ Size: 0x4
+ - Name: globM
+ Section: .text
+ Value: 0x4
+ Size: 0x4
+ Other: [ STO_MIPS_MICROMIPS ]
+ - Name: T1
+...
diff --git a/test/elf/Mips/plt-header.test b/test/elf/Mips/plt-header.test
new file mode 100644
index 000000000000..caf7e83ea5e2
--- /dev/null
+++ b/test/elf/Mips/plt-header.test
@@ -0,0 +1,99 @@
+# REQUIRES: mips
+
+# Check initialization of .plt header entries.
+
+# Build shared library
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-so.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t-so.o
+
+# Build executable
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-o.o
+# RUN: lld -flavor gnu -target mipsel -e glob -o %t.exe %t-o.o %t.so
+# RUN: llvm-objdump -section-headers -disassemble %t.exe | \
+# RUN: FileCheck -check-prefix=EXE %s
+
+# EXE: Disassembly of section .plt:
+# EXE: .plt:
+# PLT0 entry. Points to the .got.plt[0]
+# EXE-NEXT: 400160: 40 00 1c 3c lui $gp, 64
+# EXE-NEXT: 400164: 00 20 99 8f lw $25, 8192($gp)
+# EXE-NEXT: 400168: 00 20 9c 27 addiu $gp, $gp, 8192
+# EXE-NEXT: 40016c: 23 c0 1c 03 subu $24, $24, $gp
+# EXE-NEXT: 400170: 21 78 e0 03 move $15, $ra
+# EXE-NEXT: 400174: 82 c0 18 00 srl $24, $24, 2
+# EXE-NEXT: 400178: 09 f8 20 03 jalr $25
+# EXE-NEXT: 40017c: fe ff 18 27 addiu $24, $24, -2
+
+# EXE: Sections:
+# EXE: Idx Name Size Address Type
+# EXE: 6 .plt 00000030 0000000000400160 TEXT DATA
+# EXE: 10 .got.plt 0000000c 0000000000402000 DATA
+
+# so.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+
+# o.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_PIC, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x20
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x04
+ Info: .text
+ Relocations:
+ - Offset: 0x08
+ Symbol: .text
+ Type: R_MIPS_26
+ - Offset: 0x10
+ Symbol: glob
+ Type: R_MIPS_26
+ - Offset: 0x18
+ Symbol: T1
+ Type: R_MIPS_26
+
+Symbols:
+ Local:
+ - Name: loc
+ Section: .text
+ Value: 0x10
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ Global:
+ - Name: glob
+ Section: .text
+ - Name: T1
+...
diff --git a/test/elf/Mips/r26-1-micro.test b/test/elf/Mips/r26-1-micro.test
new file mode 100644
index 000000000000..629754febc7e
--- /dev/null
+++ b/test/elf/Mips/r26-1-micro.test
@@ -0,0 +1,131 @@
+# REQUIRES: mips
+
+# Check handling of R_MICROMIPS_26_S1 relocation.
+
+# Build shared library
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-so.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t-so.o
+
+# Build executable
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-o.o
+# RUN: llvm-readobj -relocations %t-o.o | \
+# RUN: FileCheck -check-prefix=OBJ-REL %s
+# RUN: lld -flavor gnu -target mipsel -e glob -o %t.exe %t-o.o %t.so
+# RUN: llvm-readobj -relocations %t.exe | FileCheck -check-prefix=EXE-REL %s
+# RUN: llvm-objdump -section-headers %t.exe | FileCheck -check-prefix=EXE %s
+# RUN: llvm-objdump -s -d -mattr=micromips %t.exe | \
+# RUN: FileCheck -check-prefix=DIS %s
+
+# Object file has three R_MICROMIPS_26_S1 relocations
+# OBJ-REL: Relocations [
+# OBJ-REL-NEXT: Section (2) .rel.text {
+# OBJ-REL-NEXT: 0x8 R_MICROMIPS_26_S1 loc 0x0
+# OBJ-REL-NEXT: 0x10 R_MICROMIPS_26_S1 glob 0x0
+# OBJ-REL-NEXT: 0x18 R_MICROMIPS_26_S1 T1 0x0
+# OBJ-REL-NEXT: }
+# OBJ-REL-NEXT: ]
+
+# Executable file has the only relocation for external symbol
+# EXE-REL: Relocations [
+# EXE-REL-NEXT: Section (5) .rel.plt {
+# EXE-REL-NEXT: 0x402008 R_MIPS_JUMP_SLOT T1 0x0
+# EXE-REL-NEXT: }
+# EXE-REL-NEXT: ]
+
+# EXE: Sections:
+# EXE: Idx Name Size Address Type
+# EXE: 6 .plt 00000024 0000000000400160 TEXT DATA
+# EXE: 10 .got.plt 0000000c 0000000000402000 DATA
+
+# DIS: Disassembly of section .plt:
+# DIS-NEXT: .plt:
+# DIS-NEXT: 400160: 80 79 a8 07 addiupc $3, 7840
+# DIS-NEXT: 400164: 23 ff 00 00 lw $25, 0($3)
+# DIS-NEXT: 400168: 35 05 subu16 $2, $2, $3
+# DIS-NEXT: 40016a: 25 25 srl16 $2, $2, 2
+# DIS-NEXT: 40016c: 02 33 fe ff addiu $24, $2, -2
+# DIS-NEXT: 400170: ff 0d move $15, $ra
+# DIS-NEXT: 400172: f9 45 jalrs16 $25
+# DIS-NEXT: 400174: 83 0f move $gp, $3
+# DIS-NEXT: 400176: 00 0c nop
+
+# DIS-NEXT: 400178: 00 79 a4 07 addiupc $2, 7824
+# DIS-NEXT: 40017c: 22 ff 00 00 lw $25, 0($2)
+# DIS-NEXT: 400180: 99 45 jr16 $25
+# DIS-NEXT: 400182: 02 0f move $24, $2
+
+# DIS: Contents of section .text:
+# DIS-NEXT: 400184 09f82003 00000000 2400ca0c 00000000 .. .....$.......
+# DIS-NEXT: 400194 2000c20c 00000000 2000bc0c 00000000 ....... .......
+
+# so.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+
+# o.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_CPIC, EF_MIPS_ABI_O32,
+ EF_MIPS_ARCH_32R2, EF_MIPS_MICROMIPS ]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Content: '09F82003000000000400000C000000000000000C000000000000000C00000000'
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x04
+ Info: .text
+ Relocations:
+ - Offset: 0x08
+ Symbol: loc
+ Type: R_MICROMIPS_26_S1
+ - Offset: 0x10
+ Symbol: glob
+ Type: R_MICROMIPS_26_S1
+ - Offset: 0x18
+ Symbol: T1
+ Type: R_MICROMIPS_26_S1
+
+Symbols:
+ Local:
+ - Name: loc
+ Section: .text
+ Value: 0x10
+ Other: [ STO_MIPS_MICROMIPS ]
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ Global:
+ - Name: glob
+ Section: .text
+ Other: [ STO_MIPS_MICROMIPS ]
+ - Name: T1
+...
diff --git a/test/elf/Mips/r26-1.test b/test/elf/Mips/r26-1.test
new file mode 100644
index 000000000000..abc0a7ce5a81
--- /dev/null
+++ b/test/elf/Mips/r26-1.test
@@ -0,0 +1,132 @@
+# REQUIRES: mips
+
+# Check handling of R_MIPS_26 relocation.
+
+# Build shared library
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-so.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t-so.o
+
+# Build executable
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-o.o
+# RUN: llvm-readobj -relocations %t-o.o | \
+# RUN: FileCheck -check-prefix=OBJ-REL %s
+# RUN: lld -flavor gnu -target mipsel -e glob -o %t.exe %t-o.o %t.so
+# RUN: llvm-objdump -section-headers -disassemble %t.exe | \
+# RUN: FileCheck -check-prefix=EXE %s
+# RUN: llvm-readobj -relocations %t.exe | FileCheck -check-prefix=EXE-REL %s
+
+# Object file has three R_MIPS_26 relocations
+# OBJ-REL: Relocations [
+# OBJ-REL-NEXT: Section (2) .rel.text {
+# OBJ-REL-NEXT: 0x8 R_MIPS_26 .text 0x0
+# OBJ-REL-NEXT: 0x10 R_MIPS_26 glob 0x0
+# OBJ-REL-NEXT: 0x18 R_MIPS_26 T1 0x0
+# OBJ-REL-NEXT: }
+# OBJ-REL-NEXT: ]
+
+# Executable file has the only relocation for external symbol
+# EXE-REL: Relocations [
+# EXE-REL-NEXT: Section (5) .rel.plt {
+# EXE-REL-NEXT: 0x402008 R_MIPS_JUMP_SLOT T1 0x0
+# EXE-REL-NEXT: }
+# EXE-REL-NEXT: ]
+
+# EXE: Disassembly of section .plt:
+# EXE: .plt:
+# PLTA entry. Points to the .got.plt[1]
+# EXE: 400180: 40 00 0f 3c lui $15, 64
+# EXE-NEXT: 400184: 08 20 f9 8d lw $25, 8200($15)
+# EXE-NEXT: 400188: 08 00 20 03 jr $25
+# EXE-NEXT: 40018c: 08 20 f8 25 addiu $24, $15, 8200
+
+# EXE: Disassembly of section .text:
+# EXE: glob:
+# EXE-NEXT: 400190: 09 f8 20 03 jalr $25
+# EXE-NEXT: 400194: 00 00 00 00 nop
+#
+# Jump to 'loc' label address
+# EXE-NEXT: 400198: 68 00 10 0c jal 4194720
+# EXE-NEXT: 40019c: 00 00 00 00 nop
+#
+# EXE: loc:
+# Jump to 'glob' label address
+# EXE-NEXT: 4001a0: 64 00 10 0c jal 4194704
+# EXE-NEXT: 4001a4: 00 00 00 00 nop
+#
+# Jump to the first PLT entry (.plt + 32) for T1 entry
+# EXE-NEXT: 4001a8: 60 00 10 0c jal 4194688
+# EXE-NEXT: 4001ac: 00 00 00 00 nop
+
+# EXE: Sections:
+# EXE: Idx Name Size Address Type
+# EXE: 6 .plt 00000030 0000000000400160 TEXT DATA
+# EXE: 10 .got.plt 0000000c 0000000000402000 DATA
+
+# so.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+
+# o.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32 ]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Content: '09F82003000000000400000C000000000000000C000000000000000C00000000'
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x04
+ Info: .text
+ Relocations:
+ - Offset: 0x08
+ Symbol: .text
+ Type: R_MIPS_26
+ - Offset: 0x10
+ Symbol: glob
+ Type: R_MIPS_26
+ - Offset: 0x18
+ Symbol: T1
+ Type: R_MIPS_26
+
+Symbols:
+ Local:
+ - Name: loc
+ Section: .text
+ Value: 0x10
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ Global:
+ - Name: glob
+ Section: .text
+ - Name: T1
+...
diff --git a/test/elf/Mips/r26-2-micro.test b/test/elf/Mips/r26-2-micro.test
new file mode 100644
index 000000000000..b92b9acf4c84
--- /dev/null
+++ b/test/elf/Mips/r26-2-micro.test
@@ -0,0 +1,88 @@
+# REQUIRES: mips
+
+# Check reading addendum for R_MICROMIPS_26_S1 relocation.
+# RUN: yaml2obj -format=elf %s > %t-obj
+# RUN: lld -flavor gnu -target mipsel -o %t-exe %t-obj
+# RUN: llvm-objdump -d -mattr=micromips %t-exe | FileCheck -check-prefix=DIS %s
+# RUN: llvm-objdump -t %t-exe | FileCheck %s
+
+# DIS: Disassembly of section .text:
+# DIS-NEXT: loc0:
+# DIS-NEXT: 400110: 00 00 00 00 nop
+
+# DIS: __start:
+# DIS-NEXT: 400114: 20 f4 8e e0 jal 4309276
+# DIS-NEXT: 400118: 00 00 00 00 nop
+# DIS-NEXT: 40011c: 20 f4 9a e0 jal 4309300
+# DIS-NEXT: 400120: 00 00 00 00 nop
+
+# DIS: loc1:
+# DIS-NEXT: 400124: 20 f4 89 00 jal 4194578
+# DIS-NEXT: 400128: 00 00 00 00 nop
+# DIS-NEXT: 40012c: 20 f4 91 00 jal 4194594
+# DIS-NEXT: 400130: 00 00 00 00 nop
+
+# CHECK: SYMBOL TABLE:
+# CHECK: 00400124 l F .text 00000010 loc1
+# CHECK: 00400114 g F .text 00000010 __start
+
+!ELF
+FileHeader: !FileHeader
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2, EF_MIPS_MICROMIPS]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+# nop
+# jal __start + 0x1C000
+# nop
+# jal loc + 0x1C000
+# nop
+# jal __start + 7FFFFE2
+# nop
+# jal loc + 7FFFFEA
+# nop
+ Content: "0000000000f404e00000000000f408e000000000FFF7FFFF00000000FFF7FFFF00000000"
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .rel.text
+ Type: SHT_REL
+ Info: .text
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x4
+ Symbol: __start
+ Type: R_MICROMIPS_26_S1
+ - Offset: 0xC
+ Symbol: loc1
+ Type: R_MICROMIPS_26_S1
+ - Offset: 0x14
+ Symbol: __start
+ Type: R_MICROMIPS_26_S1
+ - Offset: 0x1C
+ Symbol: loc1
+ Type: R_MICROMIPS_26_S1
+
+Symbols:
+ Global:
+ - Name: __start
+ Section: .text
+ Value: 0x4
+ Size: 8
+ Other: [ STO_MIPS_MICROMIPS ]
+ Local:
+ - Name: loc0
+ Section: .text
+ Value: 0
+ Size: 4
+ Other: [ STO_MIPS_MICROMIPS ]
+ - Name: loc1
+ Section: .text
+ Value: 0x14
+ Size: 8
+ Other: [ STO_MIPS_MICROMIPS ]
diff --git a/test/elf/Mips/r26-2.test b/test/elf/Mips/r26-2.test
new file mode 100644
index 000000000000..0f0063ae1334
--- /dev/null
+++ b/test/elf/Mips/r26-2.test
@@ -0,0 +1,82 @@
+# REQUIRES: mips
+
+# Check reading addendum for R_MIPS_26 relocation.
+# RUN: yaml2obj -format=elf %s > %t-obj
+# RUN: lld -flavor gnu -target mipsel -o %t-exe %t-obj
+# RUN: llvm-objdump -t -disassemble %t-exe | FileCheck %s
+
+# CHECK: Disassembly of section .text:
+# CHECK-NEXT: __start:
+# CHECK-NEXT: 400110: 00 00 00 00 nop
+# CHECK-NEXT: 400114: 44 70 10 0c jal 4309264
+# 0x107044 << 2 = 0x41C110 = _start + (0x7000 << 2)
+# CHECK-NEXT: 400118: 00 00 00 00 nop
+#
+# CHECK: loc:
+# CHECK-NEXT: 40011c: 47 70 10 0c jal 4309276
+# 0x107047 << 2 = 0x41C11C = loc + (0x7000 << 2)
+# CHECK-NEXT: 400120: 00 00 00 00 nop
+# CHECK-NEXT: 400124: 43 00 10 0c jal 4194572
+# 0x100043 << 2 = 0x40010C = _start - 4
+# CHECK-NEXT: 400128: 00 00 00 00 nop
+# CHECK-NEXT: 40012c: 46 00 10 0c jal 4194584
+# 0x100046 << 2 = 0x400118 = loc - 4
+# CHECK-NEXT: 400130: 00 00 00 00 nop
+
+# CHECK: SYMBOL TABLE:
+# CHECK: 0040011c l F .text 00000018 loc
+# CHECK: 00400110 g F .text 0000000c __start
+
+!ELF
+FileHeader: !FileHeader
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+# nop
+# jal __start + 0x1C000
+# nop
+# jal loc + 0x1C000
+# nop
+# jal __start - 1
+# nop
+# jal loc - 1
+# nop
+ Content: "000000000070000C000000000070000C00000000FFFFFF0F00000000FFFFFF0F00000000"
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .rel.text
+ Type: SHT_REL
+ Info: .text
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x4
+ Symbol: __start
+ Type: R_MIPS_26
+ - Offset: 0xC
+ Symbol: loc
+ Type: R_MIPS_26
+ - Offset: 0x14
+ Symbol: __start
+ Type: R_MIPS_26
+ - Offset: 0x1C
+ Symbol: loc
+ Type: R_MIPS_26
+
+Symbols:
+ Global:
+ - Name: __start
+ Section: .text
+ Value: 0x0
+ Size: 4
+ Local:
+ - Name: loc
+ Section: .text
+ Value: 0xc
+ Size: 4
diff --git a/test/elf/Mips/rel-32.test b/test/elf/Mips/rel-32.test
new file mode 100644
index 000000000000..beefde59b7b1
--- /dev/null
+++ b/test/elf/Mips/rel-32.test
@@ -0,0 +1,59 @@
+# Check handling of R_MIPS_32 relocation.
+# RUN: yaml2obj -format=elf %s > %t-obj
+# RUN: lld -flavor gnu -target mipsel -o %t-exe %t-obj
+# RUN: llvm-objdump -s -t %t-exe | FileCheck %s
+
+# CHECK: Contents of section .data:
+# CHECK-NEXT: 402000 00000000 09204080 05204080 ..... @.. @.
+# ^^ data2 + 0x80000001 = 0x80402009
+# ^^ data1 + 0x80000001 = 0x80402005
+# CHECK: SYMBOL TABLE:
+# CHECK: 00402004 g .data 00000004 data1
+# CHECK: 00402008 g .data 00000004 data2
+
+!ELF
+FileHeader: !FileHeader
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Content: "00000000"
+ AddressAlign: 16
+ Flags: [SHF_ALLOC]
+- Name: .data
+ Type: SHT_PROGBITS
+ Content: "000000000100008001000080"
+ AddressAlign: 16
+ Flags: [SHF_ALLOC, SHF_WRITE]
+
+- Name: .rel.data
+ Type: SHT_REL
+ Info: .data
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x4
+ Symbol: data2
+ Type: R_MIPS_32
+ - Offset: 0x8
+ Symbol: data1
+ Type: R_MIPS_32
+
+Symbols:
+ Global:
+ - Name: __start
+ Section: .text
+ Value: 0x0
+ Size: 4
+ - Name: data1
+ Section: .data
+ Value: 0x4
+ Size: 4
+ - Name: data2
+ Section: .data
+ Value: 0x8
+ Size: 4
diff --git a/test/elf/Mips/rel-64.test b/test/elf/Mips/rel-64.test
new file mode 100644
index 000000000000..e05b75687038
--- /dev/null
+++ b/test/elf/Mips/rel-64.test
@@ -0,0 +1,61 @@
+# Check handling of R_MIPS_64 relocation.
+
+# RUN: yaml2obj -format=elf %s > %t.o
+# RUN: lld -flavor gnu -target mips64el -o %t.exe %t.o
+# RUN: llvm-objdump -s -t %t.exe | FileCheck %s
+
+# CHECK: Contents of section .data:
+# CHECK-NEXT: 120002000 d1010020 01000000 d0010020 01000100 ... ....... ....
+# ^^ __start + 1 = 0x1200001d1
+# ^^ __start + 0x1000000000000
+# = 0x10001200001d0
+# CHECK: SYMBOL TABLE:
+# CHECK: 00000001200001d0 g .rodata 00000008 __start
+
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ARCH_64]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x08
+ AddressAlign: 16
+ Flags: [SHF_ALLOC]
+- Name: .data
+ Type: SHT_PROGBITS
+ Size: 0x10
+ AddressAlign: 16
+ Flags: [SHF_ALLOC, SHF_WRITE]
+
+- Name: .rela.data
+ Type: SHT_RELA
+ Info: .data
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x0
+ Symbol: __start
+ Type: R_MIPS_64
+ Addend: 1
+ - Offset: 0x8
+ Symbol: __start
+ Type: R_MIPS_64
+ Addend: 0x1000000000000
+
+Symbols:
+ Global:
+ - Name: __start
+ Section: .text
+ Value: 0x0
+ Size: 8
+ - Name: data1
+ Section: .data
+ Value: 0x0
+ Size: 8
+ - Name: data2
+ Section: .data
+ Value: 0x8
+ Size: 8
diff --git a/test/elf/Mips/rel-copy-micro.test b/test/elf/Mips/rel-copy-micro.test
new file mode 100644
index 000000000000..afa99198e37f
--- /dev/null
+++ b/test/elf/Mips/rel-copy-micro.test
@@ -0,0 +1,159 @@
+# Check R_MIPS_COPY relocation emitting
+# when linking non-shared executable file.
+#
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-so1.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t1.so %t-so1.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-so2.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t2.so %t-so2.o
+# RUN: yaml2obj -format=elf -docnum 3 %s > %t-o.o
+# RUN: lld -flavor gnu -target mipsel -e T0 -o %t.exe %t-o.o %t1.so %t2.so
+# RUN: llvm-readobj -dt -r -dynamic-table %t.exe | FileCheck %s
+
+# CHECK: Relocations [
+# CHECK-NEXT: Section (5) .rel.dyn {
+# CHECK-NEXT: 0x402010 R_MIPS_COPY D1 0x0
+# CHECK-NEXT: 0x402018 R_MIPS_COPY D2 0x0
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+
+# CHECK: DynamicSymbols [
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: @ (0)
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Local (0x0)
+# CHECK-NEXT: Type: None (0x0)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined (0x0)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: D1@ (1)
+# CHECK-NEXT: Value: 0x402010
+# CHECK-NEXT: Size: 8
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: Object (0x1)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: .bss (0xA)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: D2@ (4)
+# CHECK-NEXT: Value: 0x402018
+# CHECK-NEXT: Size: 4
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: Object (0x1)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: .bss (0xA)
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+
+# CHECK: DynamicSection [ ({{.*}} entries)
+# CHECK: 0x00000001 NEEDED SharedLibrary (rel-copy-micro.test.tmp1.so)
+# CHECK: 0x00000001 NEEDED SharedLibrary (rel-copy-micro.test.tmp2.so)
+# CHECK-NEXT: 0x00000000 NULL 0x0
+# CHECK-NEXT: ]
+
+# so1.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+- Name: .data
+ Type: SHT_PROGBITS
+ Size: 0x08
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: D1
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x0
+ Size: 4
+
+# so2.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+- Name: .data
+ Type: SHT_PROGBITS
+ Size: 0x04
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: D2
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x0
+ Size: 4
+
+# o.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2, EF_MIPS_MICROMIPS]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x08
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .data
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_ALLOC]
+
+- Name: .rel.data
+ Type: SHT_REL
+ Info: .data
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x00
+ Symbol: D1
+ Type: R_MICROMIPS_HI16
+ - Offset: 0x00
+ Symbol: D1
+ Type: R_MICROMIPS_LO16
+ - Offset: 0x08
+ Symbol: D2
+ Type: R_MICROMIPS_HI16
+ - Offset: 0x08
+ Symbol: D2
+ Type: R_MICROMIPS_LO16
+
+Symbols:
+ Global:
+ - Name: T0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 8
+ Other: [ STO_MIPS_MICROMIPS ]
+ - Name: D0
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x0
+ Size: 8
+ - Name: D1
+ Type: STT_OBJECT
+ - Name: D2
+...
diff --git a/test/elf/Mips/rel-copy-pc.test b/test/elf/Mips/rel-copy-pc.test
new file mode 100644
index 000000000000..2dd702334fed
--- /dev/null
+++ b/test/elf/Mips/rel-copy-pc.test
@@ -0,0 +1,113 @@
+# Check R_MIPS_COPY relocation emitting caused by R_MIPS_PCHI16 / R_MIPS_PCLO16
+# relocations when linking non-shared executable file.
+#
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-so.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t-so.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-o.o
+# RUN: lld -flavor gnu -target mipsel -e T0 -o %t.exe %t-o.o %t.so
+# RUN: llvm-readobj -dt -r -dynamic-table %t.exe | FileCheck %s
+
+# CHECK: Relocations [
+# CHECK-NEXT: Section (5) .rel.dyn {
+# CHECK-NEXT: 0x402008 R_MIPS_COPY D1 0x0
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+
+# CHECK: DynamicSymbols [
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: @ (0)
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Local (0x0)
+# CHECK-NEXT: Type: None (0x0)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined (0x0)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: D1@ (1)
+# CHECK-NEXT: Value: 0x402008
+# CHECK-NEXT: Size: 4
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: Object (0x1)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: .bss (0xA)
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+
+# CHECK: DynamicSection [ ({{.*}} entries)
+# CHECK: 0x00000001 NEEDED SharedLibrary (rel-copy-pc.test.tmp.so)
+# CHECK-NEXT: 0x00000000 NULL 0x0
+# CHECK-NEXT: ]
+
+# so.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R6]
+
+Sections:
+- Name: .data
+ Type: SHT_PROGBITS
+ Size: 4
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: D1
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0
+ Size: 4
+
+# o.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R6]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 4
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .data
+ Type: SHT_PROGBITS
+ Size: 4
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_ALLOC]
+
+- Name: .rel.data
+ Type: SHT_REL
+ Info: .data
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0
+ Symbol: D1
+ Type: R_MIPS_PCHI16
+ - Offset: 0
+ Symbol: D1
+ Type: R_MIPS_PCLO16
+
+Symbols:
+ Global:
+ - Name: T0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0
+ Size: 4
+ - Name: D0
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0
+ Size: 4
+ - Name: D1
+...
diff --git a/test/elf/Mips/rel-copy.test b/test/elf/Mips/rel-copy.test
new file mode 100644
index 000000000000..648a25e22ae7
--- /dev/null
+++ b/test/elf/Mips/rel-copy.test
@@ -0,0 +1,177 @@
+# Check R_MIPS_COPY relocation emitting
+# when linking non-shared executable file.
+#
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-so1.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t1.so %t-so1.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-so2.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t2.so %t-so2.o
+# RUN: yaml2obj -format=elf -docnum 3 %s > %t-o.o
+# RUN: lld -flavor gnu -target mipsel -e T0 -o %t.exe %t-o.o %t1.so %t2.so
+# RUN: llvm-readobj -dt -r -dynamic-table %t.exe | FileCheck %s
+
+# CHECK: Relocations [
+# CHECK-NEXT: Section (5) .rel.dyn {
+# CHECK-NEXT: 0x402004 R_MIPS_REL32 D2 0x0
+# CHECK-NEXT: 0x402010 R_MIPS_COPY D1 0x0
+# CHECK-NEXT: 0x402018 R_MIPS_COPY D3 0x0
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+
+# CHECK: DynamicSymbols [
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: @ (0)
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Local (0x0)
+# CHECK-NEXT: Type: None (0x0)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined (0x0)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: D1@ (1)
+# CHECK-NEXT: Value: 0x402010
+# CHECK-NEXT: Size: 4
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: Object (0x1)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: .bss (0xA)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: D3@ (4)
+# CHECK-NEXT: Value: 0x402018
+# CHECK-NEXT: Size: 4
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: Object (0x1)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: .bss (0xA)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: D2@ (7)
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 4
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: Object (0x1)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined (0x0)
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+
+# CHECK: DynamicSection [ ({{.*}} entries)
+# CHECK: 0x00000001 NEEDED SharedLibrary (rel-copy.test.tmp1.so)
+# CHECK: 0x00000001 NEEDED SharedLibrary (rel-copy.test.tmp2.so)
+# CHECK-NEXT: 0x00000000 NULL 0x0
+# CHECK-NEXT: ]
+
+# so1.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+- Name: .data
+ Type: SHT_PROGBITS
+ Size: 0x08
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: D1
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x0
+ Size: 4
+ - Name: D2
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x4
+ Size: 4
+
+# so2.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+- Name: .data
+ Type: SHT_PROGBITS
+ Size: 0x04
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: D3
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x0
+ Size: 4
+
+# o.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x08
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .data
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_ALLOC]
+
+- Name: .rel.data
+ Type: SHT_REL
+ Info: .data
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x00
+ Symbol: D1
+ Type: R_MIPS_HI16
+ - Offset: 0x00
+ Symbol: D1
+ Type: R_MIPS_LO16
+ - Offset: 0x04
+ Symbol: D2
+ Type: R_MIPS_32
+ - Offset: 0x08
+ Symbol: D3
+ Type: R_MIPS_HI16
+ - Offset: 0x08
+ Symbol: D3
+ Type: R_MIPS_LO16
+
+Symbols:
+ Global:
+ - Name: T0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 8
+ - Name: D0
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x0
+ Size: 8
+ - Name: D1
+ Type: STT_OBJECT
+ - Name: D2
+ - Name: D3
+...
diff --git a/test/elf/Mips/rel-dynamic-01-micro.test b/test/elf/Mips/rel-dynamic-01-micro.test
new file mode 100644
index 000000000000..6e0a41bf2606
--- /dev/null
+++ b/test/elf/Mips/rel-dynamic-01-micro.test
@@ -0,0 +1,201 @@
+# REQUIRES: mips
+
+# Conditions:
+# a) Linking a non-shared executable file.
+# b) Relocations' targets are symbols defined in the shared object.
+# Check:
+# a) Emitting R_MIPS_COPY, R_MIPS_JUMP_SLOT relocations.
+# b) PLT entries creation.
+# c) STO_MIPS_PLT flag in the dynamic symbol table for symbols require
+# a pointer equality.
+#
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-so.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t-so.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-o.o
+# RUN: lld -flavor gnu -target mipsel -e T0 -o %t.exe %t-o.o %t.so
+# RUN: llvm-objdump -d -mattr=micromips %t.exe | FileCheck -check-prefix=DIS %s
+# RUN: llvm-readobj -dt -r %t.exe | FileCheck -check-prefix=PLT-SYM %s
+
+# DIS: Disassembly of section .plt:
+# DIS-NEXT: .plt:
+# DIS-NEXT: 4001b0: 80 79 94 07 addiupc $3, 7760
+# DIS-NEXT: 4001b4: 23 ff 00 00 lw $25, 0($3)
+# DIS-NEXT: 4001b8: 35 05 subu16 $2, $2, $3
+# DIS-NEXT: 4001ba: 25 25 srl16 $2, $2, 2
+# DIS-NEXT: 4001bc: 02 33 fe ff addiu $24, $2, -2
+# DIS-NEXT: 4001c0: ff 0d move $15, $ra
+# DIS-NEXT: 4001c2: f9 45 jalrs16 $25
+# DIS-NEXT: 4001c4: 83 0f move $gp, $3
+# DIS-NEXT: 4001c6: 00 0c nop
+
+# DIS-NEXT: 4001c8: 00 79 90 07 addiupc $2, 7744
+# DIS-NEXT: 4001cc: 22 ff 00 00 lw $25, 0($2)
+# DIS-NEXT: 4001d0: 99 45 jr16 $25
+# DIS-NEXT: 4001d2: 02 0f move $24, $2
+
+# DIS-NEXT: 4001d4: 00 79 8e 07 addiupc $2, 7736
+# DIS-NEXT: 4001d8: 22 ff 00 00 lw $25, 0($2)
+# DIS-NEXT: 4001dc: 99 45 jr16 $25
+# DIS-NEXT: 4001de: 02 0f move $24, $2
+
+# PLT-SYM: Relocations [
+# PLT-SYM-NEXT: Section (5) .rel.dyn {
+# PLT-SYM-NEXT: 0x402018 R_MIPS_COPY D1 0x0
+# PLT-SYM-NEXT: }
+# PLT-SYM-NEXT: Section (6) .rel.plt {
+# PLT-SYM-NEXT: 0x402008 R_MIPS_JUMP_SLOT T3 0x0
+# PLT-SYM-NEXT: 0x40200C R_MIPS_JUMP_SLOT T1 0x0
+# PLT-SYM-NEXT: }
+# PLT-SYM-NEXT: ]
+
+# PLT-SYM: DynamicSymbols [
+# PLT-SYM-NEXT: Symbol {
+# PLT-SYM-NEXT: Name: @ (0)
+# PLT-SYM-NEXT: Value: 0x0
+# PLT-SYM-NEXT: Size: 0
+# PLT-SYM-NEXT: Binding: Local (0x0)
+# PLT-SYM-NEXT: Type: None (0x0)
+# PLT-SYM-NEXT: Other: 0
+# PLT-SYM-NEXT: Section: Undefined (0x0)
+# PLT-SYM-NEXT: }
+# PLT-SYM-NEXT: Symbol {
+# PLT-SYM-NEXT: Name: D1@ (1)
+# PLT-SYM-NEXT: Value: 0x402018
+# PLT-SYM-NEXT: Size: 8
+# PLT-SYM-NEXT: Binding: Global (0x1)
+# PLT-SYM-NEXT: Type: Object (0x1)
+# PLT-SYM-NEXT: Other: 0
+# PLT-SYM-NEXT: Section: .bss (0xD)
+# PLT-SYM-NEXT: }
+# PLT-SYM-NEXT: Symbol {
+# PLT-SYM-NEXT: Name: T1@ (4)
+# PLT-SYM-NEXT: Value: 0x4001D5
+# PLT-SYM-NEXT: Size: 0
+# PLT-SYM-NEXT: Binding: Global (0x1)
+# PLT-SYM-NEXT: Type: Function (0x2)
+# PLT-SYM-NEXT: Other: 8
+# PLT-SYM-NEXT: Section: Undefined (0x0)
+# PLT-SYM-NEXT: }
+# PLT-SYM-NEXT: Symbol {
+# PLT-SYM-NEXT: Name: T3@ (7)
+# PLT-SYM-NEXT: Value: 0x0
+# PLT-SYM-NEXT: Size: 0
+# PLT-SYM-NEXT: Binding: Global (0x1)
+# PLT-SYM-NEXT: Type: Function (0x2)
+# PLT-SYM-NEXT: Other: 0
+# PLT-SYM-NEXT: Section: Undefined (0x0)
+# PLT-SYM-NEXT: }
+# PLT-SYM-NEXT: ]
+
+# so.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32,
+ EF_MIPS_ARCH_32R2, EF_MIPS_MICROMIPS]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .data
+ Type: SHT_PROGBITS
+ Size: 0x08
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+ Other: [ STO_MIPS_MICROMIPS ]
+ - Name: T3
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x8
+ Size: 4
+ Other: [ STO_MIPS_MICROMIPS ]
+ - Name: D1
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x0
+ Size: 8
+
+# o.o
+---
+FileHeader: !FileHeader
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2, EF_MIPS_MICROMIPS]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x08
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .data
+ Type: SHT_PROGBITS
+ Size: 0x08
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_ALLOC]
+
+- Name: .rel.text
+ Type: SHT_REL
+ Info: .text
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x04
+ Symbol: T3
+ Type: R_MICROMIPS_26_S1
+
+- Name: .rel.data
+ Type: SHT_REL
+ Info: .data
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x00
+ Symbol: T1
+ Type: R_MICROMIPS_HI16
+ - Offset: 0x00
+ Symbol: T1
+ Type: R_MICROMIPS_LO16
+ - Offset: 0x04
+ Symbol: D1
+ Type: R_MICROMIPS_HI16
+ - Offset: 0x04
+ Symbol: D1
+ Type: R_MICROMIPS_LO16
+
+Symbols:
+ Global:
+ - Name: T0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 8
+ Other: [ STO_MIPS_MICROMIPS ]
+ - Name: T1
+ Type: STT_FUNC
+ - Name: T3
+ Type: STT_FUNC
+ - Name: D0
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x0
+ Size: 8
+ - Name: D1
+ Type: STT_OBJECT
+...
diff --git a/test/elf/Mips/rel-dynamic-01.test b/test/elf/Mips/rel-dynamic-01.test
new file mode 100644
index 000000000000..ca4619668bd2
--- /dev/null
+++ b/test/elf/Mips/rel-dynamic-01.test
@@ -0,0 +1,237 @@
+# REQUIRES: mips
+
+# Conditions:
+# a) Linking a non-shared executable file.
+# b) Relocations' targets are symbols defined in the shared object.
+# Check:
+# a) Emitting R_MIPS_REL32, R_MIPS_COPY, R_MIPS_JUMP_SLOT relocations.
+# b) PLT entries creation.
+# c) STO_MIPS_PLT flag in the dynamic symbol table for symbols require
+# a pointer equality.
+#
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-so.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t-so.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-o.o
+# RUN: lld -flavor gnu -target mipsel -e T0 -o %t.exe %t-o.o %t.so
+# RUN: llvm-objdump -disassemble %t.exe | FileCheck -check-prefix=PLT %s
+# RUN: llvm-readobj -dt -r %t.exe | FileCheck -check-prefix=PLT-SYM %s
+
+# PLT: Disassembly of section .plt:
+# PLT-NEXT: .plt:
+# PLT-NEXT: 4001f0: 40 00 1c 3c lui $gp, 64
+# PLT-NEXT: 4001f4: 00 20 99 8f lw $25, 8192($gp)
+# PLT-NEXT: 4001f8: 00 20 9c 27 addiu $gp, $gp, 8192
+# PLT-NEXT: 4001fc: 23 c0 1c 03 subu $24, $24, $gp
+# PLT-NEXT: 400200: 21 78 e0 03 move $15, $ra
+# PLT-NEXT: 400204: 82 c0 18 00 srl $24, $24, 2
+# PLT-NEXT: 400208: 09 f8 20 03 jalr $25
+# PLT-NEXT: 40020c: fe ff 18 27 addiu $24, $24, -2
+#
+# PLT-NEXT: 400210: 40 00 0f 3c lui $15, 64
+# PLT-NEXT: 400214: 08 20 f9 8d lw $25, 8200($15)
+# PLT-NEXT: 400218: 08 00 20 03 jr $25
+# PLT-NEXT: 40021c: 08 20 f8 25 addiu $24, $15, 8200
+#
+# PLT-NEXT: 400220: 40 00 0f 3c lui $15, 64
+# PLT-NEXT: 400224: 0c 20 f9 8d lw $25, 8204($15)
+# PLT-NEXT: 400228: 08 00 20 03 jr $25
+# PLT-NEXT: 40022c: 0c 20 f8 25 addiu $24, $15, 8204
+
+# PLT-SYM: Relocations [
+# PLT-SYM-NEXT: Section (5) .rel.dyn {
+# PLT-SYM-NEXT: 0x402014 R_MIPS_REL32 T2 0x0
+# PLT-SYM-NEXT: 0x402014 R_MIPS_REL32 D2 0x0
+# PLT-SYM-NEXT: 0x402018 R_MIPS_COPY D1 0x0
+# PLT-SYM-NEXT: }
+# PLT-SYM-NEXT: Section (6) .rel.plt {
+# PLT-SYM-NEXT: 0x402008 R_MIPS_JUMP_SLOT T3 0x0
+# PLT-SYM-NEXT: 0x40200C R_MIPS_JUMP_SLOT T1 0x0
+# PLT-SYM-NEXT: }
+# PLT-SYM-NEXT: ]
+
+# PLT-SYM: DynamicSymbols [
+# PLT-SYM-NEXT: Symbol {
+# PLT-SYM-NEXT: Name: @ (0)
+# PLT-SYM-NEXT: Value: 0x0
+# PLT-SYM-NEXT: Size: 0
+# PLT-SYM-NEXT: Binding: Local (0x0)
+# PLT-SYM-NEXT: Type: None (0x0)
+# PLT-SYM-NEXT: Other: 0
+# PLT-SYM-NEXT: Section: Undefined (0x0)
+# PLT-SYM-NEXT: }
+# PLT-SYM-NEXT: Symbol {
+# PLT-SYM-NEXT: Name: D1@ (1)
+# PLT-SYM-NEXT: Value: 0x402018
+# PLT-SYM-NEXT: Size: 4
+# PLT-SYM-NEXT: Binding: Global (0x1)
+# PLT-SYM-NEXT: Type: Object (0x1)
+# PLT-SYM-NEXT: Other: 0
+# PLT-SYM-NEXT: Section: .bss (0xD)
+# PLT-SYM-NEXT: }
+# PLT-SYM-NEXT: Symbol {
+# PLT-SYM-NEXT: Name: T1@ (4)
+# PLT-SYM-NEXT: Value: 0x400220
+# PLT-SYM-NEXT: Size: 0
+# PLT-SYM-NEXT: Binding: Global (0x1)
+# PLT-SYM-NEXT: Type: Function (0x2)
+# PLT-SYM-NEXT: Other: 8
+# PLT-SYM-NEXT: Section: Undefined (0x0)
+# PLT-SYM-NEXT: }
+# PLT-SYM-NEXT: Symbol {
+# PLT-SYM-NEXT: Name: T3@ (10)
+# PLT-SYM-NEXT: Value: 0x0
+# PLT-SYM-NEXT: Size: 0
+# PLT-SYM-NEXT: Binding: Global (0x1)
+# PLT-SYM-NEXT: Type: Function (0x2)
+# PLT-SYM-NEXT: Other: 0
+# PLT-SYM-NEXT: Section: Undefined (0x0)
+# PLT-SYM-NEXT: }
+# PLT-SYM-NEXT: Symbol {
+# PLT-SYM-NEXT: Name: T2@ (7)
+# PLT-SYM-NEXT: Value: 0x0
+# PLT-SYM-NEXT: Size: 0
+# PLT-SYM-NEXT: Binding: Global (0x1)
+# PLT-SYM-NEXT: Type: Function (0x2)
+# PLT-SYM-NEXT: Other: 0
+# PLT-SYM-NEXT: Section: Undefined (0x0)
+# PLT-SYM-NEXT: }
+# PLT-SYM-NEXT: Symbol {
+# PLT-SYM-NEXT: Name: D2@ (13)
+# PLT-SYM-NEXT: Value: 0x0
+# PLT-SYM-NEXT: Size: 4
+# PLT-SYM-NEXT: Binding: Global (0x1)
+# PLT-SYM-NEXT: Type: Object (0x1)
+# PLT-SYM-NEXT: Other: 0
+# PLT-SYM-NEXT: Section: Undefined (0x0)
+# PLT-SYM-NEXT: }
+# PLT-SYM-NEXT: ]
+
+# so.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .data
+ Type: SHT_PROGBITS
+ Size: 0x08
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+ - Name: T2
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x4
+ Size: 4
+ - Name: T3
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x8
+ Size: 4
+ - Name: D1
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x0
+ Size: 4
+ - Name: D2
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x4
+ Size: 4
+
+# o.o
+---
+FileHeader: !FileHeader
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x08
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .data
+ Type: SHT_PROGBITS
+ Size: 0x08
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_ALLOC]
+
+- Name: .rel.text
+ Type: SHT_REL
+ Info: .text
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x04
+ Symbol: T3
+ Type: R_MIPS_26
+
+- Name: .rel.data
+ Type: SHT_REL
+ Info: .data
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x00
+ Symbol: T1
+ Type: R_MIPS_HI16
+ - Offset: 0x00
+ Symbol: T1
+ Type: R_MIPS_LO16
+ - Offset: 0x04
+ Symbol: T2
+ Type: R_MIPS_32
+
+ - Offset: 0x04
+ Symbol: D1
+ Type: R_MIPS_HI16
+ - Offset: 0x04
+ Symbol: D1
+ Type: R_MIPS_LO16
+ - Offset: 0x04
+ Symbol: D2
+ Type: R_MIPS_32
+
+Symbols:
+ Global:
+ - Name: T0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 8
+ - Name: T1
+ Type: STT_FUNC
+ - Name: T2
+ Type: STT_FUNC
+ - Name: T3
+ Type: STT_FUNC
+ - Name: D0
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x0
+ Size: 8
+ - Name: D1
+ Type: STT_OBJECT
+ - Name: D2
+ Type: STT_OBJECT
+...
diff --git a/test/elf/Mips/rel-dynamic-02.test b/test/elf/Mips/rel-dynamic-02.test
new file mode 100644
index 000000000000..4de86383482c
--- /dev/null
+++ b/test/elf/Mips/rel-dynamic-02.test
@@ -0,0 +1,82 @@
+# Conditions:
+# a) Linking a shared library.
+# b) Relocations' targets are undefined symbols.
+# Check:
+# a) Emitting R_MIPS_REL32 relocations for both undefined symbols.
+# b) There should be no PLT entries.
+#
+# RUN: yaml2obj -format=elf %s > %t-obj
+# RUN: lld -flavor gnu -target mipsel -shared --noinhibit-exec -o %t1-so %t-obj
+# RUN: llvm-readobj -dt -r -s %t1-so | FileCheck -check-prefix=PLT-SYM %s
+
+# PLT-SYM: Sections [
+# PLT-SYM: Section {
+# PLT-SYM-NOT: Name: .plt ({{[0-9]+}})
+#
+# PLT-SYM: Relocations [
+# PLT-SYM-NEXT: Section (4) .rel.dyn {
+# PLT-SYM-NEXT: 0x140 R_MIPS_REL32 T1 0x0
+# PLT-SYM-NEXT: 0x2000 R_MIPS_REL32 T1 0x0
+# PLT-SYM-NEXT: }
+# PLT-SYM-NEXT: ]
+#
+# PLT-SYM: Name: T1@ (7)
+# PLT-SYM-NEXT: Value: 0x0
+# PLT-SYM-NEXT: Size: 0
+# PLT-SYM-NEXT: Binding: Global (0x1)
+# PLT-SYM-NEXT: Type: None (0x0)
+# PLT-SYM-NEXT: Other: 0
+# PLT-SYM-NEXT: Section: Undefined (0x0)
+
+!ELF
+FileHeader: !FileHeader
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Content: "0000000000000000"
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .data
+ Type: SHT_PROGBITS
+ Content: "0000000000000000"
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_ALLOC]
+
+- Name: .rel.text
+ Type: SHT_REL
+ Info: .text
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x00
+ Symbol: T1
+ Type: R_MIPS_32
+
+- Name: .rel.data
+ Type: SHT_REL
+ Info: .data
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x00
+ Symbol: T1
+ Type: R_MIPS_32
+
+Symbols:
+ Global:
+ - Name: T0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+ - Name: T1
+ - Name: D0
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x0
+ Size: 8
diff --git a/test/elf/Mips/rel-dynamic-03-micro.test b/test/elf/Mips/rel-dynamic-03-micro.test
new file mode 100644
index 000000000000..5de2cdcdc131
--- /dev/null
+++ b/test/elf/Mips/rel-dynamic-03-micro.test
@@ -0,0 +1,133 @@
+# REQUIRES: mips
+
+# Conditions:
+# a) Linking a non-shared executable file.
+# b) Relocations' target is a symbol defined in the shared object.
+# c) The target symbol is referenced by both branch (R_MICROMIPS_26_S1)
+# and regular (R_MIPS_32) relocations.
+# Check:
+# a) There should be no R_MIPS_REL32 relocation.
+# b) Linker creates a single PLT entry.
+# c) STO_MIPS_PLT flag in the dynamic symbol table for symbols require
+# a pointer equality.
+#
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-so.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t-so.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-o.o
+# RUN: lld -flavor gnu -target mipsel -e T0 -o %t.exe %t-o.o %t.so
+# RUN: llvm-objdump -d -mattr=micromips %t.exe | FileCheck -check-prefix=DIS %s
+# RUN: llvm-readobj -dt -r %t.exe | FileCheck -check-prefix=PLT-SYM %s
+
+# DIS: Disassembly of section .plt:
+# DIS-NEXT: .plt:
+# DIS-NEXT: 400170: 80 79 a4 07 addiupc $3, 7824
+# DIS-NEXT: 400174: 23 ff 00 00 lw $25, 0($3)
+# DIS-NEXT: 400178: 35 05 subu16 $2, $2, $3
+# DIS-NEXT: 40017a: 25 25 srl16 $2, $2, 2
+# DIS-NEXT: 40017c: 02 33 fe ff addiu $24, $2, -2
+# DIS-NEXT: 400180: ff 0d move $15, $ra
+# DIS-NEXT: 400182: f9 45 jalrs16 $25
+# DIS-NEXT: 400184: 83 0f move $gp, $3
+# DIS-NEXT: 400186: 00 0c nop
+
+# DIS-NEXT: 400188: 00 79 a0 07 addiupc $2, 7808
+# DIS-NEXT: 40018c: 22 ff 00 00 lw $25, 0($2)
+# DIS-NEXT: 400190: 99 45 jr16 $25
+# DIS-NEXT: 400192: 02 0f move $24, $2
+
+# PLT-SYM: Relocations [
+# PLT-SYM-NEXT: Section (5) .rel.plt {
+# PLT-SYM-NEXT: 0x402008 R_MIPS_JUMP_SLOT T1 0x0
+# PLT-SYM-NEXT: }
+# PLT-SYM-NEXT: ]
+
+# PLT-SYM: Name: T1@ (1)
+# PLT-SYM-NEXT: Value: 0x400189
+# PLT-SYM-NEXT: Size: 0
+# PLT-SYM-NEXT: Binding: Global (0x1)
+# PLT-SYM-NEXT: Type: Function (0x2)
+# PLT-SYM-NEXT: Other: 8
+# PLT-SYM-NEXT: Section: Undefined (0x0)
+
+# so.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32,
+ EF_MIPS_ARCH_32R2, EF_MIPS_MICROMIPS]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+ Other: [ STO_MIPS_MICROMIPS ]
+
+# o.o
+---
+FileHeader: !FileHeader
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2, EF_MIPS_MICROMIPS]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x08
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .data
+ Type: SHT_PROGBITS
+ Size: 0x08
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_ALLOC]
+
+- Name: .rel.text
+ Type: SHT_REL
+ Info: .text
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x04
+ Symbol: T1
+ Type: R_MICROMIPS_26_S1
+
+- Name: .rel.data
+ Type: SHT_REL
+ Info: .data
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x04
+ Symbol: T1
+ Type: R_MIPS_32
+
+Symbols:
+ Global:
+ - Name: T0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 8
+ Other: [ STO_MIPS_MICROMIPS ]
+ - Name: T1
+ Type: STT_FUNC
+ - Name: D0
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x0
+ Size: 8
+...
diff --git a/test/elf/Mips/rel-dynamic-03.test b/test/elf/Mips/rel-dynamic-03.test
new file mode 100644
index 000000000000..cc791b051748
--- /dev/null
+++ b/test/elf/Mips/rel-dynamic-03.test
@@ -0,0 +1,129 @@
+# REQUIRES: mips
+
+# Conditions:
+# a) Linking a non-shared executable file.
+# b) Relocations' target is a symbol defined in the shared object.
+# c) The target symbol is referenced by both branch (R_MIPS_26)
+# and regular (R_MIPS_32) relocations.
+# Check:
+# a) There should be no R_MIPS_REL32 relocation.
+# b) Linker creates a single PLT entry.
+# c) STO_MIPS_PLT flag in the dynamic symbol table for symbols require
+# a pointer equality.
+#
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-so.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t-so.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-o.o
+# RUN: lld -flavor gnu -target mipsel -e T0 -o %t.exe %t-o.o %t.so
+# RUN: llvm-objdump -disassemble %t.exe | FileCheck -check-prefix=PLT %s
+# RUN: llvm-readobj -dt -r %t.exe | FileCheck -check-prefix=PLT-SYM %s
+
+# PLT: Disassembly of section .plt:
+# PLT-NEXT: .plt:
+# PLT-NEXT: 400160: 40 00 1c 3c lui $gp, 64
+# PLT-NEXT: 400164: 00 20 99 8f lw $25, 8192($gp)
+# PLT-NEXT: 400168: 00 20 9c 27 addiu $gp, $gp, 8192
+# PLT-NEXT: 40016c: 23 c0 1c 03 subu $24, $24, $gp
+# PLT-NEXT: 400170: 21 78 e0 03 move $15, $ra
+# PLT-NEXT: 400174: 82 c0 18 00 srl $24, $24, 2
+# PLT-NEXT: 400178: 09 f8 20 03 jalr $25
+# PLT-NEXT: 40017c: fe ff 18 27 addiu $24, $24, -2
+#
+# PLT-NEXT: 400180: 40 00 0f 3c lui $15, 64
+# PLT-NEXT: 400184: 08 20 f9 8d lw $25, 8200($15)
+# PLT-NEXT: 400188: 08 00 20 03 jr $25
+# PLT-NEXT: 40018c: 08 20 f8 25 addiu $24, $15, 8200
+#
+# PLT-SYM: Relocations [
+# PLT-SYM-NEXT: Section (5) .rel.plt {
+# PLT-SYM-NEXT: 0x402008 R_MIPS_JUMP_SLOT T1 0x0
+# PLT-SYM-NEXT: }
+# PLT-SYM-NEXT: ]
+
+# PLT-SYM: Name: T1@ (1)
+# PLT-SYM-NEXT: Value: 0x400180
+# PLT-SYM-NEXT: Size: 0
+# PLT-SYM-NEXT: Binding: Global (0x1)
+# PLT-SYM-NEXT: Type: Function (0x2)
+# PLT-SYM-NEXT: Other: 8
+# PLT-SYM-NEXT: Section: Undefined (0x0)
+
+# so.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+
+# o.o
+---
+FileHeader: !FileHeader
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x08
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .data
+ Type: SHT_PROGBITS
+ Size: 0x08
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_ALLOC]
+
+- Name: .rel.text
+ Type: SHT_REL
+ Info: .text
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x04
+ Symbol: T1
+ Type: R_MIPS_26
+
+- Name: .rel.data
+ Type: SHT_REL
+ Info: .data
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x04
+ Symbol: T1
+ Type: R_MIPS_32
+
+Symbols:
+ Global:
+ - Name: T0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 8
+ - Name: T1
+ Type: STT_FUNC
+ - Name: D0
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x0
+ Size: 8
+...
diff --git a/test/elf/Mips/rel-dynamic-04-micro.test b/test/elf/Mips/rel-dynamic-04-micro.test
new file mode 100644
index 000000000000..1c58efdf5f70
--- /dev/null
+++ b/test/elf/Mips/rel-dynamic-04-micro.test
@@ -0,0 +1,211 @@
+# Conditions:
+# a) Linking a non-shared executable file.
+# b) Relocations' targets are symbols defined in the shared object.
+# c) Relocations modify a writable section.
+# d) The first symbol is referenced by R_MIPS32 relocation only
+# e) The second symbol is referenced by R_MIPS_32
+# and R_MICROMIPS_26_S1 relocations.
+# f) The third symbol is referenced by R_MICROMIPS_26_S1
+# and R_MIPS_32 relocations.
+# Check:
+# a) There should be the only R_MIPS_REL32 relocation.
+# b) Linker creates a couple of PLT entry for both symbols referenced
+# by the R_MICROMIPS_26_S1 branch relocation.
+# c) STO_MIPS_PLT flag in the dynamic symbol table for symbols require
+# a pointer equality.
+#
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-so.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t-so.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-o.o
+# RUN: lld -flavor gnu -target mipsel -e T0 -o %t.exe %t-o.o %t.so
+# RUN: llvm-readobj -dt -r -s %t.exe | FileCheck -check-prefix=PLT %s
+
+# PLT: Section {
+# PLT: Index: 5
+# PLT-NEXT: Name: .rel.dyn (31)
+# PLT-NEXT: Type: SHT_REL (0x9)
+# PLT-NEXT: Flags [ (0x2)
+# PLT-NEXT: SHF_ALLOC (0x2)
+# PLT-NEXT: ]
+# PLT-NEXT: Address: 0x4010A0
+# PLT-NEXT: Offset: 0x10A0
+# PLT-NEXT: Size: 8
+# PLT-NEXT: Link: 3
+# PLT-NEXT: Info: 0
+# PLT-NEXT: AddressAlignment: 4
+# PLT-NEXT: EntrySize: 8
+# PLT-NEXT: }
+# PLT-NEXT: Section {
+# PLT-NEXT: Index: 6
+# PLT-NEXT: Name: .rel.plt (40)
+# PLT-NEXT: Type: SHT_REL (0x9)
+# PLT-NEXT: Flags [ (0x2)
+# PLT-NEXT: SHF_ALLOC (0x2)
+# PLT-NEXT: ]
+# PLT-NEXT: Address: 0x4010A8
+# PLT-NEXT: Offset: 0x10A8
+# PLT-NEXT: Size: 16
+# PLT-NEXT: Link: 3
+# PLT-NEXT: Info: 0
+# PLT-NEXT: AddressAlignment: 4
+# PLT-NEXT: EntrySize: 8
+# PLT-NEXT: }
+# PLT-NEXT: Section {
+# PLT-NEXT: Index: 7
+# PLT-NEXT: Name: .plt (49)
+# PLT-NEXT: Type: SHT_PROGBITS (0x1)
+# PLT-NEXT: Flags [ (0x6)
+# PLT-NEXT: SHF_ALLOC (0x2)
+# PLT-NEXT: SHF_EXECINSTR (0x4)
+# PLT-NEXT: ]
+# PLT-NEXT: Address: 0x4010C0
+# PLT-NEXT: Offset: 0x10C0
+# PLT-NEXT: Size: 48
+# PLT-NEXT: Link: 0
+# PLT-NEXT: Info: 0
+# PLT-NEXT: AddressAlignment: 16
+# PLT-NEXT: EntrySize: 0
+# PLT-NEXT: }
+
+# PLT: Relocations [
+# PLT-NEXT: Section (5) .rel.dyn {
+# PLT-NEXT: 0x400120 R_MIPS_REL32 T1 0x0
+# PLT-NEXT: }
+# PLT-NEXT: Section (6) .rel.plt {
+# PLT-NEXT: 0x403008 R_MIPS_JUMP_SLOT T2 0x0
+# PLT-NEXT: 0x40300C R_MIPS_JUMP_SLOT T3 0x0
+# PLT-NEXT: }
+# PLT-NEXT: ]
+
+# PLT: DynamicSymbols [
+# PLT-NEXT: Symbol {
+# PLT-NEXT: Name: @ (0)
+# PLT-NEXT: Value: 0x0
+# PLT-NEXT: Size: 0
+# PLT-NEXT: Binding: Local (0x0)
+# PLT-NEXT: Type: None (0x0)
+# PLT-NEXT: Other: 0
+# PLT-NEXT: Section: Undefined (0x0)
+# PLT-NEXT: }
+# PLT-NEXT: Symbol {
+# PLT-NEXT: Name: T2@ (4)
+# PLT-NEXT: Value: 0x4010D9
+# PLT-NEXT: Size: 0
+# PLT-NEXT: Binding: Global (0x1)
+# PLT-NEXT: Type: Function (0x2)
+# PLT-NEXT: Other: 8
+# PLT-NEXT: Section: Undefined (0x0)
+# PLT-NEXT: }
+# PLT-NEXT: Symbol {
+# PLT-NEXT: Name: T3@ (7)
+# PLT-NEXT: Value: 0x4010E5
+# PLT-NEXT: Size: 0
+# PLT-NEXT: Binding: Global (0x1)
+# PLT-NEXT: Type: Function (0x2)
+# PLT-NEXT: Other: 8
+# PLT-NEXT: Section: Undefined (0x0)
+# PLT-NEXT: }
+# PLT-NEXT: Symbol {
+# PLT-NEXT: Name: T1@ (1)
+# PLT-NEXT: Value: 0x0
+# PLT-NEXT: Size: 0
+# PLT-NEXT: Binding: Global (0x1)
+# PLT-NEXT: Type: Function (0x2)
+# PLT-NEXT: Other: 0
+# PLT-NEXT: Section: Undefined (0x0)
+# PLT-NEXT: }
+# PLT-NEXT: ]
+
+# so.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2 ]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+ - Name: T2
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x4
+ Size: 4
+ - Name: T3
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x8
+ Size: 4
+
+# o.o
+---
+FileHeader: !FileHeader
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_CPIC, EF_MIPS_ABI_O32,
+ EF_MIPS_ARCH_32R2, EF_MIPS_MICROMIPS ]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x14
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .rel.text
+ Type: SHT_REL
+ Info: .text
+ AddressAlign: 4
+ Relocations:
+ # There is no branch relocation for T1.
+ - Offset: 0x00
+ Symbol: T1
+ Type: R_MIPS_32
+ # The R_MIPS_32 relocation for T2 might produce R_MIPS_REL32 ...
+ - Offset: 0x04
+ Symbol: T2
+ Type: R_MIPS_32
+ # ... but R_MICROMIPS_26_S1 creates PLT entry
+ # and makes R_MIPS_REL32 redundant.
+ - Offset: 0x08
+ Symbol: T2
+ Type: R_MICROMIPS_26_S1
+ # Create PLT entry for T3 symbol.
+ - Offset: 0x0c
+ Symbol: T3
+ Type: R_MICROMIPS_26_S1
+ # Take in account existing PLT entry and do not create R_MIPS_REL32.
+ - Offset: 0x10
+ Symbol: T3
+ Type: R_MIPS_32
+
+Symbols:
+ Global:
+ - Name: T0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 0x14
+ Other: [ STO_MIPS_MICROMIPS ]
+ - Name: T1
+ Type: STT_FUNC
+ - Name: T2
+ Type: STT_FUNC
+ - Name: T3
+ Type: STT_FUNC
+...
diff --git a/test/elf/Mips/rel-dynamic-04.test b/test/elf/Mips/rel-dynamic-04.test
new file mode 100644
index 000000000000..5b5bcce01cd8
--- /dev/null
+++ b/test/elf/Mips/rel-dynamic-04.test
@@ -0,0 +1,206 @@
+# Conditions:
+# a) Linking a non-shared executable file.
+# b) Relocations' targets are symbols defined in the shared object.
+# c) Relocations modify a writable section.
+# d) The first symbol is referenced by R_MIPS32 relocation only
+# e) The second symbol is referenced by R_MIPS_32 and R_MIPS26 relocations.
+# f) The third symbol is referenced by R_MIPS26 and R_MIPS_32 relocations.
+# Check:
+# a) There should be the only R_MIPS_REL32 relocation.
+# b) Linker creates a couple of PLT entry for both symbols referenced
+# by the R_MIPS_26 branch relocation.
+# c) STO_MIPS_PLT flag in the dynamic symbol table for symbols require
+# a pointer equality.
+#
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-so.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t-so.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-o.o
+# RUN: lld -flavor gnu -target mipsel -e T0 -o %t.exe %t-o.o %t.so
+# RUN: llvm-readobj -dt -r -s %t.exe | FileCheck -check-prefix=PLT %s
+
+# PLT: Section {
+# PLT: Index: 5
+# PLT-NEXT: Name: .rel.dyn (31)
+# PLT-NEXT: Type: SHT_REL (0x9)
+# PLT-NEXT: Flags [ (0x2)
+# PLT-NEXT: SHF_ALLOC (0x2)
+# PLT-NEXT: ]
+# PLT-NEXT: Address: 0x40109C
+# PLT-NEXT: Offset: 0x109C
+# PLT-NEXT: Size: 8
+# PLT-NEXT: Link: 3
+# PLT-NEXT: Info: 0
+# PLT-NEXT: AddressAlignment: 4
+# PLT-NEXT: EntrySize: 8
+# PLT-NEXT: }
+# PLT-NEXT: Section {
+# PLT-NEXT: Index: 6
+# PLT-NEXT: Name: .rel.plt (40)
+# PLT-NEXT: Type: SHT_REL (0x9)
+# PLT-NEXT: Flags [ (0x2)
+# PLT-NEXT: SHF_ALLOC (0x2)
+# PLT-NEXT: ]
+# PLT-NEXT: Address: 0x4010A4
+# PLT-NEXT: Offset: 0x10A4
+# PLT-NEXT: Size: 16
+# PLT-NEXT: Link: 3
+# PLT-NEXT: Info: 0
+# PLT-NEXT: AddressAlignment: 4
+# PLT-NEXT: EntrySize: 8
+# PLT-NEXT: }
+# PLT-NEXT: Section {
+# PLT-NEXT: Index: 7
+# PLT-NEXT: Name: .plt (49)
+# PLT-NEXT: Type: SHT_PROGBITS (0x1)
+# PLT-NEXT: Flags [ (0x6)
+# PLT-NEXT: SHF_ALLOC (0x2)
+# PLT-NEXT: SHF_EXECINSTR (0x4)
+# PLT-NEXT: ]
+# PLT-NEXT: Address: 0x4010C0
+# PLT-NEXT: Offset: 0x10C0
+# PLT-NEXT: Size: 64
+# PLT-NEXT: Link: 0
+# PLT-NEXT: Info: 0
+# PLT-NEXT: AddressAlignment: 16
+# PLT-NEXT: EntrySize: 0
+# PLT-NEXT: }
+
+# PLT: Relocations [
+# PLT-NEXT: Section (5) .rel.dyn {
+# PLT-NEXT: 0x400120 R_MIPS_REL32 T1 0x0
+# PLT-NEXT: }
+# PLT-NEXT: Section (6) .rel.plt {
+# PLT-NEXT: 0x403008 R_MIPS_JUMP_SLOT T2 0x0
+# PLT-NEXT: 0x40300C R_MIPS_JUMP_SLOT T3 0x0
+# PLT-NEXT: }
+# PLT-NEXT: ]
+
+# PLT: DynamicSymbols [
+# PLT-NEXT: Symbol {
+# PLT-NEXT: Name: @ (0)
+# PLT-NEXT: Value: 0x0
+# PLT-NEXT: Size: 0
+# PLT-NEXT: Binding: Local (0x0)
+# PLT-NEXT: Type: None (0x0)
+# PLT-NEXT: Other: 0
+# PLT-NEXT: Section: Undefined (0x0)
+# PLT-NEXT: }
+# PLT-NEXT: Symbol {
+# PLT-NEXT: Name: T2@ (4)
+# PLT-NEXT: Value: 0x4010E0
+# PLT-NEXT: Size: 0
+# PLT-NEXT: Binding: Global (0x1)
+# PLT-NEXT: Type: Function (0x2)
+# PLT-NEXT: Other: 8
+# PLT-NEXT: Section: Undefined (0x0)
+# PLT-NEXT: }
+# PLT-NEXT: Symbol {
+# PLT-NEXT: Name: T3@ (7)
+# PLT-NEXT: Value: 0x4010F0
+# PLT-NEXT: Size: 0
+# PLT-NEXT: Binding: Global (0x1)
+# PLT-NEXT: Type: Function (0x2)
+# PLT-NEXT: Other: 8
+# PLT-NEXT: Section: Undefined (0x0)
+# PLT-NEXT: }
+# PLT-NEXT: Symbol {
+# PLT-NEXT: Name: T1@ (1)
+# PLT-NEXT: Value: 0x0
+# PLT-NEXT: Size: 0
+# PLT-NEXT: Binding: Global (0x1)
+# PLT-NEXT: Type: Function (0x2)
+# PLT-NEXT: Other: 0
+# PLT-NEXT: Section: Undefined (0x0)
+# PLT-NEXT: }
+# PLT-NEXT: ]
+
+# so.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+ - Name: T2
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x4
+ Size: 4
+ - Name: T3
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x8
+ Size: 4
+
+# o.o
+---
+FileHeader: !FileHeader
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x08
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .rel.text
+ Type: SHT_REL
+ Info: .text
+ AddressAlign: 4
+ Relocations:
+ # There is no branch relocation for T1.
+ - Offset: 0x00
+ Symbol: T1
+ Type: R_MIPS_32
+ # The R_MIPS_32 relocation for T2 might produce R_MIPS_REL32 ...
+ - Offset: 0x00
+ Symbol: T2
+ Type: R_MIPS_32
+ # ... but R_MIPS_26 creates PLT entry and makes R_MIPS_REL32 redundant.
+ - Offset: 0x04
+ Symbol: T2
+ Type: R_MIPS_26
+ # Create PLT entry for T3 symbol.
+ - Offset: 0x00
+ Symbol: T3
+ Type: R_MIPS_26
+ # Take in account existing PLT entry and do not create R_MIPS_REL32.
+ - Offset: 0x04
+ Symbol: T3
+ Type: R_MIPS_32
+
+Symbols:
+ Global:
+ - Name: T0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 8
+ - Name: T1
+ Type: STT_FUNC
+ - Name: T2
+ Type: STT_FUNC
+ - Name: T3
+ Type: STT_FUNC
+...
diff --git a/test/elf/Mips/rel-dynamic-05-micro.test b/test/elf/Mips/rel-dynamic-05-micro.test
new file mode 100644
index 000000000000..d1c87076b596
--- /dev/null
+++ b/test/elf/Mips/rel-dynamic-05-micro.test
@@ -0,0 +1,192 @@
+# Conditions:
+# a) Linking a non-shared executable file.
+# b) Relocations' targets are symbols defined in the shared object.
+# c) Relocations modify a read-only section.
+# d) The first symbol is referenced by R_MIPS32 relocation only
+# e) The second symbol is referenced by R_MIPS_32
+# and R_MICROMIPS_26_S1 relocations.
+# f) The third symbol is referenced by R_MICROMIPS_26_S1
+# and R_MIPS_32 relocations.
+# Check:
+# a) There should be no R_MIPS_REL32 relocations.
+# b) Linker creates PLT entries for all three relocations.
+# c) STO_MIPS_PLT flag in the dynamic symbol table for symbols require
+# a pointer equality.
+#
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-so.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t-so.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-o.o
+# RUN: lld -flavor gnu -target mipsel -e T0 -o %t.exe %t-o.o %t.so
+# RUN: llvm-readobj -dt -r -s %t.exe | FileCheck -check-prefix=PLT %s
+
+# PLT: Section {
+# PLT: Index: 5
+# PLT-NEXT: Name: .rel.plt (31)
+# PLT-NEXT: Type: SHT_REL (0x9)
+# PLT-NEXT: Flags [ (0x2)
+# PLT-NEXT: SHF_ALLOC (0x2)
+# PLT-NEXT: ]
+# PLT-NEXT: Address: 0x400194
+# PLT-NEXT: Offset: 0x194
+# PLT-NEXT: Size: 24
+# PLT-NEXT: Link: 3
+# PLT-NEXT: Info: 0
+# PLT-NEXT: AddressAlignment: 4
+# PLT-NEXT: EntrySize: 8
+# PLT-NEXT: }
+# PLT-NEXT: Section {
+# PLT-NEXT: Index: 6
+# PLT-NEXT: Name: .plt (40)
+# PLT-NEXT: Type: SHT_PROGBITS (0x1)
+# PLT-NEXT: Flags [ (0x6)
+# PLT-NEXT: SHF_ALLOC (0x2)
+# PLT-NEXT: SHF_EXECINSTR (0x4)
+# PLT-NEXT: ]
+# PLT-NEXT: Address: 0x4001B0
+# PLT-NEXT: Offset: 0x1B0
+# PLT-NEXT: Size: 60
+# PLT-NEXT: Link: 0
+# PLT-NEXT: Info: 0
+# PLT-NEXT: AddressAlignment: 16
+# PLT-NEXT: EntrySize: 0
+# PLT-NEXT: }
+
+# PLT: Relocations [
+# PLT-NEXT: Section (5) .rel.plt {
+# PLT-NEXT: 0x402008 R_MIPS_JUMP_SLOT T1 0x0
+# PLT-NEXT: 0x40200C R_MIPS_JUMP_SLOT T2 0x0
+# PLT-NEXT: 0x402010 R_MIPS_JUMP_SLOT T3 0x0
+# PLT-NEXT: }
+# PLT-NEXT: ]
+
+# PLT: DynamicSymbols [
+# PLT-NEXT: Symbol {
+# PLT-NEXT: Name: @ (0)
+# PLT-NEXT: Value: 0x0
+# PLT-NEXT: Size: 0
+# PLT-NEXT: Binding: Local (0x0)
+# PLT-NEXT: Type: None (0x0)
+# PLT-NEXT: Other: 0
+# PLT-NEXT: Section: Undefined (0x0)
+# PLT-NEXT: }
+# PLT-NEXT: Symbol {
+# PLT-NEXT: Name: T1@ (1)
+# PLT-NEXT: Value: 0x4001C9
+# PLT-NEXT: Size: 0
+# PLT-NEXT: Binding: Global (0x1)
+# PLT-NEXT: Type: Function (0x2)
+# PLT-NEXT: Other: 8
+# PLT-NEXT: Section: Undefined (0x0)
+# PLT-NEXT: }
+# PLT-NEXT: Symbol {
+# PLT-NEXT: Name: T2@ (4)
+# PLT-NEXT: Value: 0x4001D5
+# PLT-NEXT: Size: 0
+# PLT-NEXT: Binding: Global (0x1)
+# PLT-NEXT: Type: Function (0x2)
+# PLT-NEXT: Other: 8
+# PLT-NEXT: Section: Undefined (0x0)
+# PLT-NEXT: }
+# PLT-NEXT: Symbol {
+# PLT-NEXT: Name: T3@ (7)
+# PLT-NEXT: Value: 0x4001E1
+# PLT-NEXT: Size: 0
+# PLT-NEXT: Binding: Global (0x1)
+# PLT-NEXT: Type: Function (0x2)
+# PLT-NEXT: Other: 8
+# PLT-NEXT: Section: Undefined (0x0)
+# PLT-NEXT: }
+# PLT-NEXT: ]
+
+# so.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2 ]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+ - Name: T2
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x4
+ Size: 4
+ - Name: T3
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x8
+ Size: 4
+
+# o.o
+---
+FileHeader: !FileHeader
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_CPIC, EF_MIPS_ABI_O32,
+ EF_MIPS_ARCH_32R2, EF_MIPS_MICROMIPS ]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x14
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .rel.text
+ Type: SHT_REL
+ Info: .text
+ AddressAlign: 4
+ Relocations:
+ # There is no branch relocation for T1.
+ - Offset: 0x00
+ Symbol: T1
+ Type: R_MIPS_32
+ # The R_MIPS_32 relocation for T2 might produce R_MIPS_REL32 ...
+ - Offset: 0x04
+ Symbol: T2
+ Type: R_MIPS_32
+ # ... but R_MICROMIPS_26_S1 creates PLT entry and makes R_MIPS_REL32 redundant.
+ - Offset: 0x08
+ Symbol: T2
+ Type: R_MICROMIPS_26_S1
+ # Create PLT entry for T3 symbol.
+ - Offset: 0x0C
+ Symbol: T3
+ Type: R_MICROMIPS_26_S1
+ # Take in account existing PLT entry and do not create R_MIPS_REL32.
+ - Offset: 0x10
+ Symbol: T3
+ Type: R_MIPS_32
+
+Symbols:
+ Global:
+ - Name: T0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 0x14
+ Other: [ STO_MIPS_MICROMIPS ]
+ - Name: T1
+ Type: STT_FUNC
+ - Name: T2
+ Type: STT_FUNC
+ - Name: T3
+ Type: STT_FUNC
+...
diff --git a/test/elf/Mips/rel-dynamic-05.test b/test/elf/Mips/rel-dynamic-05.test
new file mode 100644
index 000000000000..3bfbd3f6efdb
--- /dev/null
+++ b/test/elf/Mips/rel-dynamic-05.test
@@ -0,0 +1,188 @@
+# Conditions:
+# a) Linking a non-shared executable file.
+# b) Relocations' targets are symbols defined in the shared object.
+# c) Relocations modify a read-only section.
+# d) The first symbol is referenced by R_MIPS32 relocation only
+# e) The second symbol is referenced by R_MIPS_32 and R_MIPS26 relocations.
+# f) The third symbol is referenced by R_MIPS26 and R_MIPS_32 relocations.
+# Check:
+# a) There should be no R_MIPS_REL32 relocations.
+# b) Linker creates PLT entries for all three relocations.
+# c) STO_MIPS_PLT flag in the dynamic symbol table for symbols require
+# a pointer equality.
+#
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-so.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t-so.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-o.o
+# RUN: lld -flavor gnu -target mipsel -e T0 -o %t.exe %t-o.o %t.so
+# RUN: llvm-readobj -dt -r -s %t.exe | FileCheck -check-prefix=PLT %s
+
+# PLT: Section {
+# PLT: Index: 5
+# PLT-NEXT: Name: .rel.plt (31)
+# PLT-NEXT: Type: SHT_REL (0x9)
+# PLT-NEXT: Flags [ (0x2)
+# PLT-NEXT: SHF_ALLOC (0x2)
+# PLT-NEXT: ]
+# PLT-NEXT: Address: 0x400190
+# PLT-NEXT: Offset: 0x190
+# PLT-NEXT: Size: 24
+# PLT-NEXT: Link: 3
+# PLT-NEXT: Info: 0
+# PLT-NEXT: AddressAlignment: 4
+# PLT-NEXT: EntrySize: 8
+# PLT-NEXT: }
+# PLT-NEXT: Section {
+# PLT-NEXT: Index: 6
+# PLT-NEXT: Name: .plt (40)
+# PLT-NEXT: Type: SHT_PROGBITS (0x1)
+# PLT-NEXT: Flags [ (0x6)
+# PLT-NEXT: SHF_ALLOC (0x2)
+# PLT-NEXT: SHF_EXECINSTR (0x4)
+# PLT-NEXT: ]
+# PLT-NEXT: Address: 0x4001B0
+# PLT-NEXT: Offset: 0x1B0
+# PLT-NEXT: Size: 80
+# PLT-NEXT: Link: 0
+# PLT-NEXT: Info: 0
+# PLT-NEXT: AddressAlignment: 16
+# PLT-NEXT: EntrySize: 0
+# PLT-NEXT: }
+
+# PLT: Relocations [
+# PLT-NEXT: Section (5) .rel.plt {
+# PLT-NEXT: 0x402008 R_MIPS_JUMP_SLOT T1 0x0
+# PLT-NEXT: 0x40200C R_MIPS_JUMP_SLOT T2 0x0
+# PLT-NEXT: 0x402010 R_MIPS_JUMP_SLOT T3 0x0
+# PLT-NEXT: }
+# PLT-NEXT: ]
+
+# PLT: DynamicSymbols [
+# PLT-NEXT: Symbol {
+# PLT-NEXT: Name: @ (0)
+# PLT-NEXT: Value: 0x0
+# PLT-NEXT: Size: 0
+# PLT-NEXT: Binding: Local (0x0)
+# PLT-NEXT: Type: None (0x0)
+# PLT-NEXT: Other: 0
+# PLT-NEXT: Section: Undefined (0x0)
+# PLT-NEXT: }
+# PLT-NEXT: Symbol {
+# PLT-NEXT: Name: T1@ (1)
+# PLT-NEXT: Value: 0x4001D0
+# PLT-NEXT: Size: 0
+# PLT-NEXT: Binding: Global (0x1)
+# PLT-NEXT: Type: Function (0x2)
+# PLT-NEXT: Other: 8
+# PLT-NEXT: Section: Undefined (0x0)
+# PLT-NEXT: }
+# PLT-NEXT: Symbol {
+# PLT-NEXT: Name: T2@ (4)
+# PLT-NEXT: Value: 0x4001E0
+# PLT-NEXT: Size: 0
+# PLT-NEXT: Binding: Global (0x1)
+# PLT-NEXT: Type: Function (0x2)
+# PLT-NEXT: Other: 8
+# PLT-NEXT: Section: Undefined (0x0)
+# PLT-NEXT: }
+# PLT-NEXT: Symbol {
+# PLT-NEXT: Name: T3@ (7)
+# PLT-NEXT: Value: 0x4001F0
+# PLT-NEXT: Size: 0
+# PLT-NEXT: Binding: Global (0x1)
+# PLT-NEXT: Type: Function (0x2)
+# PLT-NEXT: Other: 8
+# PLT-NEXT: Section: Undefined (0x0)
+# PLT-NEXT: }
+# PLT-NEXT: ]
+
+# so.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+ - Name: T2
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x4
+ Size: 4
+ - Name: T3
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x8
+ Size: 4
+
+# o.o
+---
+FileHeader: !FileHeader
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x08
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .rel.text
+ Type: SHT_REL
+ Info: .text
+ AddressAlign: 4
+ Relocations:
+ # There is no branch relocation for T1.
+ - Offset: 0x00
+ Symbol: T1
+ Type: R_MIPS_32
+ # The R_MIPS_32 relocation for T2 might produce R_MIPS_REL32 ...
+ - Offset: 0x00
+ Symbol: T2
+ Type: R_MIPS_32
+ # ... but R_MIPS_26 creates PLT entry and makes R_MIPS_REL32 redundant.
+ - Offset: 0x04
+ Symbol: T2
+ Type: R_MIPS_26
+ # Create PLT entry for T3 symbol.
+ - Offset: 0x00
+ Symbol: T3
+ Type: R_MIPS_26
+ # Take in account existing PLT entry and do not create R_MIPS_REL32.
+ - Offset: 0x04
+ Symbol: T3
+ Type: R_MIPS_32
+
+Symbols:
+ Global:
+ - Name: T0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 8
+ - Name: T1
+ Type: STT_FUNC
+ - Name: T2
+ Type: STT_FUNC
+ - Name: T3
+ Type: STT_FUNC
+...
diff --git a/test/elf/Mips/rel-dynamic-06-64.test b/test/elf/Mips/rel-dynamic-06-64.test
new file mode 100644
index 000000000000..c153eb22af4c
--- /dev/null
+++ b/test/elf/Mips/rel-dynamic-06-64.test
@@ -0,0 +1,101 @@
+# Conditions:
+# a) Linking a shared library.
+# b) The first relocation modifies a regular .text section.
+# c) The second relocation modifies a .pdr section without SHF_ALLOC flag.
+# Check:
+# a) There should be no PLT entries.
+# b) Linker creates a single R_MIPS_REL32 relocation.
+#
+# RUN: yaml2obj -format=elf %s > %t.o
+# RUN: lld -flavor gnu -target mips64el -shared -o %t.so %t.o
+# RUN: llvm-readobj -dt -r -s %t.so | FileCheck -check-prefix=CHECK %s
+
+# CHECK: Sections [
+# CHECK: Section {
+# CHECK-NOT: Name: .plt ({{[0-9]+}})
+
+# CHECK: Relocations [
+# CHECK-NEXT: Section (4) .rel.dyn {
+# CHECK-NEXT: 0x170 R_MIPS_REL32/R_MIPS_64/R_MIPS_NONE T0 0x0
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+
+# CHECK: DynamicSymbols [
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: @ (0)
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Local (0x0)
+# CHECK-NEXT: Type: None (0x0)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined (0x0)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: T1@ (4)
+# CHECK-NEXT: Value: 0x174
+# CHECK-NEXT: Size: 4
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: Function (0x2)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: .text (0x5)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: T0@ (1)
+# CHECK-NEXT: Value: 0x170
+# CHECK-NEXT: Size: 4
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: Function (0x2)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: .text (0x5)
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ARCH_64]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 8
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .rel.text
+ Type: SHT_RELA
+ Info: .text
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0
+ Symbol: T0
+ Type: R_MIPS_64
+
+- Name: .pdr
+ Type: SHT_PROGBITS
+ Size: 8
+ AddressAlign: 16
+
+- Name: .rel.pdr
+ Type: SHT_RELA
+ Info: .pdr
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0
+ Symbol: T1
+ Type: R_MIPS_64
+
+Symbols:
+ Global:
+ - Name: T0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 4
+ Size: 4
diff --git a/test/elf/Mips/rel-dynamic-06.test b/test/elf/Mips/rel-dynamic-06.test
new file mode 100644
index 000000000000..433eb5fadf59
--- /dev/null
+++ b/test/elf/Mips/rel-dynamic-06.test
@@ -0,0 +1,103 @@
+# Conditions:
+# a) Linking a shared library.
+# b) The first relocation modifies a regular .text section.
+# c) The second relocation modifies a .pdr section without SHF_ALLOC flag.
+# Check:
+# a) There should be no PLT entries.
+# b) Linker creates a single R_MIPS_REL32 relocation.
+#
+# RUN: yaml2obj -format=elf %s > %t-obj
+# RUN: lld -flavor gnu -target mipsel -shared -o %t1-so %t-obj
+# RUN: llvm-readobj -dt -r -s %t1-so | FileCheck -check-prefix=PLT1 %s
+
+# PLT1-SYM: Sections [
+# PLT1-SYM: Section {
+# PLT1-SYM-NOT: Name: .plt ({{[0-9]+}})
+
+# PLT1: Relocations [
+# PLT1-NEXT: Section (4) .rel.dyn {
+# PLT1-NEXT: 0x100 R_MIPS_REL32 T0 0x0
+# PLT1-NEXT: }
+# PLT1-NEXT: ]
+
+# PLT1: DynamicSymbols [
+# PLT1-NEXT: Symbol {
+# PLT1-NEXT: Name: @ (0)
+# PLT1-NEXT: Value: 0x0
+# PLT1-NEXT: Size: 0
+# PLT1-NEXT: Binding: Local (0x0)
+# PLT1-NEXT: Type: None (0x0)
+# PLT1-NEXT: Other: 0
+# PLT1-NEXT: Section: Undefined (0x0)
+# PLT1-NEXT: }
+# PLT1-NEXT: Symbol {
+# PLT1-NEXT: Name: T1@ (4)
+# PLT1-NEXT: Value: 0x104
+# PLT1-NEXT: Size: 4
+# PLT1-NEXT: Binding: Global (0x1)
+# PLT1-NEXT: Type: Function (0x2)
+# PLT1-NEXT: Other: 0
+# PLT1-NEXT: Section: .text (0x5)
+# PLT1-NEXT: }
+# PLT1-NEXT: Symbol {
+# PLT1-NEXT: Name: T0@ (1)
+# PLT1-NEXT: Value: 0x100
+# PLT1-NEXT: Size: 4
+# PLT1-NEXT: Binding: Global (0x1)
+# PLT1-NEXT: Type: Function (0x2)
+# PLT1-NEXT: Other: 0
+# PLT1-NEXT: Section: .text (0x5)
+# PLT1-NEXT: }
+# PLT1-NEXT: ]
+
+!ELF
+FileHeader: !FileHeader
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Content: "0000000000000000"
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .rel.text
+ Type: SHT_REL
+ Info: .text
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x00
+ Symbol: T0
+ Type: R_MIPS_32
+
+- Name: .pdr
+ Type: SHT_PROGBITS
+ Content: "0000000000000000"
+ AddressAlign: 16
+ Flags: []
+
+- Name: .rel.pdr
+ Type: SHT_REL
+ Info: .pdr
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x00
+ Symbol: T1
+ Type: R_MIPS_32
+
+Symbols:
+ Global:
+ - Name: T0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x4
+ Size: 4
diff --git a/test/elf/Mips/rel-dynamic-07-64.test b/test/elf/Mips/rel-dynamic-07-64.test
new file mode 100644
index 000000000000..f7a1c4425823
--- /dev/null
+++ b/test/elf/Mips/rel-dynamic-07-64.test
@@ -0,0 +1,261 @@
+# Conditions:
+# a) Linking a shared library.
+# b) There ars multiple R_MIPS_64 relocations with various targets.
+# Check:
+# a) Emitting of R_MIPS_REL32 relocations.
+#
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-so.o
+# RUN: lld -flavor gnu -target mips64el -shared -o %t1.so %t-so.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-o.o
+# RUN: lld -flavor gnu -target mips64el -shared --noinhibit-exec \
+# RUN: -o %t2.so %t-o.o %t1.so
+# RUN: llvm-readobj -dt -r -sections %t2.so | FileCheck %s
+
+# CHECK: Sections [
+# CHECK: Section {
+# CHECK-NOT: Name: .plt ({{[0-9]+}})
+
+# CHECK: Relocations [
+# CHECK-NEXT: Section (4) .rel.dyn {
+# CHECK-NEXT: 0x2000 R_MIPS_REL32/R_MIPS_64/R_MIPS_NONE T0 0x0
+# CHECK-NEXT: 0x2000 R_MIPS_REL32/R_MIPS_64/R_MIPS_NONE T4 0x0
+# CHECK-NEXT: 0x2000 R_MIPS_REL32/R_MIPS_64/R_MIPS_NONE D2 0x0
+# CHECK-NEXT: 0x2004 R_MIPS_REL32/R_MIPS_64/R_MIPS_NONE T1 0x0
+# CHECK-NEXT: 0x2008 R_MIPS_REL32/R_MIPS_64/R_MIPS_NONE T2 0x0
+# CHECK-NEXT: 0x2004 R_MIPS_REL32/R_MIPS_64/R_MIPS_NONE D0 0x0
+# CHECK-NEXT: 0x2008 R_MIPS_REL32/R_MIPS_64/R_MIPS_NONE D1 0x0
+# CHECK-NEXT: 0x2004 R_MIPS_REL32/R_MIPS_64/R_MIPS_NONE D4 0x0
+# CHECK-NEXT: 0x2008 R_MIPS_REL32/R_MIPS_64/R_MIPS_NONE U1 0x0
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+
+# CHECK: DynamicSymbols [
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: @ (0)
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Local (0x0)
+# CHECK-NEXT: Type: None (0x0)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined (0x0)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: T0@ (1)
+# CHECK-NEXT: Value: 0x324
+# CHECK-NEXT: Size: 8
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: Function (0x2)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: .text (0x5)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: T4@ (7)
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: None (0x0)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined (0x0)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: D2@ (25)
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 4
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: Object (0x1)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined (0x0)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: T1@ (16)
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: Function (0x2)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined (0x0)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: T2@ (19)
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: Function (0x2)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined (0x0)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: D0@ (4)
+# CHECK-NEXT: Value: 0x2004
+# CHECK-NEXT: Size: 8
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: Object (0x1)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: .data (0x8)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: D1@ (22)
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 4
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: Object (0x1)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined (0x0)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: D4@ (10)
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: None (0x0)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined (0x0)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: U1@ (13)
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: None (0x0)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined (0x0)
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+
+# so.o
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ARCH_64]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .data
+ Type: SHT_PROGBITS
+ Size: 0x08
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+ - Name: T2
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x4
+ Size: 4
+ - Name: D1
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x0
+ Size: 4
+ - Name: D2
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x4
+ Size: 4
+
+# o.o
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ARCH_64]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .data
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_ALLOC]
+
+- Name: .rel.data
+ Type: SHT_RELA
+ Info: .data
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x00 # T0 is a defined function
+ Symbol: T0
+ Type: R_MIPS_64
+ - Offset: 0x04 # T1 is a function from shared lib
+ Symbol: T1
+ Type: R_MIPS_64
+ - Offset: 0x08 # T2 has unknown type and defined in shared lib
+ Symbol: T2
+ Type: R_MIPS_64
+ - Offset: 0x00 # T4 is an undefined function
+ Symbol: T4
+ Type: R_MIPS_64
+ - Offset: 0x04 # D0 is a defined data object
+ Symbol: D0
+ Type: R_MIPS_64
+ - Offset: 0x08 # D1 is a data object from shared lib
+ Symbol: D1
+ Type: R_MIPS_64
+ - Offset: 0x00 # D2 has unknown type and defined in shared lib
+ Symbol: D2
+ Type: R_MIPS_64
+ - Offset: 0x04 # D4 is an undefined data object
+ Symbol: D4
+ Type: R_MIPS_64
+ - Offset: 0x08 # U1 is undefined and has unknown type
+ Symbol: U1
+ Type: R_MIPS_64
+
+Symbols:
+ Local:
+ - Name: LT0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0
+ Size: 4
+ - Name: LD0
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0
+ Size: 4
+
+ Global:
+ - Name: T0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x4
+ Size: 8
+ - Name: T1
+ Type: STT_FUNC
+ - Name: T2
+ - Name: T4
+ Type: STT_FUNC
+
+ - Name: D0
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x4
+ Size: 8
+ - Name: D1
+ Type: STT_OBJECT
+ - Name: D2
+ - Name: D4
+ Type: STT_OBJECT
+ - Name: U1
+...
diff --git a/test/elf/Mips/rel-dynamic-07.test b/test/elf/Mips/rel-dynamic-07.test
new file mode 100644
index 000000000000..fc163b9a12f7
--- /dev/null
+++ b/test/elf/Mips/rel-dynamic-07.test
@@ -0,0 +1,276 @@
+# Conditions:
+# a) Linking a shared library.
+# b) There ars multiple R_MIPS_32 relocations with various targets.
+# Check:
+# a) Emitting of R_MIPS_REL32 relocations.
+# b) There should be no R_MIPS_REL32 relocations for the _gp_disp symbol.
+#
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-so.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t1.so %t-so.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-o.o
+# RUN: lld -flavor gnu -target mipsel -shared --noinhibit-exec \
+# RUN: -o %t2.so %t-o.o %t1.so
+# RUN: llvm-readobj -dt -r -sections %t2.so | FileCheck %s
+
+# CHECK: Sections [
+# CHECK: Section {
+# CHECK-NOT: Name: .plt ({{[0-9]+}})
+
+# CHECK: Relocations [
+# CHECK-NEXT: Section (4) .rel.dyn {
+# CHECK-NEXT: 0x2000 R_MIPS_REL32 T0 0x0
+# CHECK-NEXT: 0x2000 R_MIPS_REL32 T4 0x0
+# CHECK-NEXT: 0x2000 R_MIPS_REL32 D2 0x0
+# CHECK-NEXT: 0x2004 R_MIPS_REL32 T1 0x0
+# CHECK-NEXT: 0x2008 R_MIPS_REL32 T2 0x0
+# CHECK-NEXT: 0x2004 R_MIPS_REL32 D0 0x0
+# CHECK-NEXT: 0x2008 R_MIPS_REL32 D1 0x0
+# CHECK-NEXT: 0x2004 R_MIPS_REL32 D4 0x0
+# CHECK-NEXT: 0x2008 R_MIPS_REL32 U1 0x0
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+
+# CHECK: DynamicSymbols [
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: @ (0)
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Local (0x0)
+# CHECK-NEXT: Type: None (0x0)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined (0x0)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: T0@ (1)
+# CHECK-NEXT: Value: 0x214
+# CHECK-NEXT: Size: 8
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: Function (0x2)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: .text (0x5)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: T4@ (7)
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: None (0x0)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined (0x0)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: D2@ (25)
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 4
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: Object (0x1)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined (0x0)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: T1@ (16)
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: Function (0x2)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined (0x0)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: T2@ (19)
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: Function (0x2)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined (0x0)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: D0@ (4)
+# CHECK-NEXT: Value: 0x2004
+# CHECK-NEXT: Size: 8
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: Object (0x1)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: .data (0x8)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: D1@ (22)
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 4
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: Object (0x1)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined (0x0)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: D4@ (10)
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: None (0x0)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined (0x0)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: U1@ (13)
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: None (0x0)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined (0x0)
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+
+# so.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .data
+ Type: SHT_PROGBITS
+ Size: 0x08
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+ - Name: T2
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x4
+ Size: 4
+ - Name: D1
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x0
+ Size: 4
+ - Name: D2
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x4
+ Size: 4
+
+# o.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .data
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_ALLOC]
+
+- Name: .rel.text
+ Type: SHT_REL
+ Info: .text
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x00
+ Symbol: _gp_disp
+ Type: R_MIPS_HI16
+ - Offset: 0x00
+ Symbol: _gp_disp
+ Type: R_MIPS_LO16
+
+- Name: .rel.data
+ Type: SHT_REL
+ Info: .data
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x00 # T0 is a defined function
+ Symbol: T0
+ Type: R_MIPS_32
+ - Offset: 0x04 # T1 is a function from shared lib
+ Symbol: T1
+ Type: R_MIPS_32
+ - Offset: 0x08 # T2 has unknown type and defined in shared lib
+ Symbol: T2
+ Type: R_MIPS_32
+ - Offset: 0x00 # T4 is an undefined function
+ Symbol: T4
+ Type: R_MIPS_32
+ - Offset: 0x04 # D0 is a defined data object
+ Symbol: D0
+ Type: R_MIPS_32
+ - Offset: 0x08 # D1 is a data object from shared lib
+ Symbol: D1
+ Type: R_MIPS_32
+ - Offset: 0x00 # D2 has unknown type and defined in shared lib
+ Symbol: D2
+ Type: R_MIPS_32
+ - Offset: 0x04 # D4 is an undefined data object
+ Symbol: D4
+ Type: R_MIPS_32
+ - Offset: 0x08 # U1 is undefined and has unknown type
+ Symbol: U1
+ Type: R_MIPS_32
+
+Symbols:
+ Local:
+ - Name: LT0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+ - Name: LD0
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x0
+ Size: 4
+
+ Global:
+ - Name: _gp_disp
+ Type: STT_OBJECT
+
+ - Name: T0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x4
+ Size: 8
+ - Name: T1
+ Type: STT_FUNC
+ - Name: T2
+ - Name: T4
+ Type: STT_FUNC
+
+ - Name: D0
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x4
+ Size: 8
+ - Name: D1
+ Type: STT_OBJECT
+ - Name: D2
+ - Name: D4
+ Type: STT_OBJECT
+ - Name: U1
diff --git a/test/elf/Mips/rel-dynamic-08-64.test b/test/elf/Mips/rel-dynamic-08-64.test
new file mode 100644
index 000000000000..d845d7407c1c
--- /dev/null
+++ b/test/elf/Mips/rel-dynamic-08-64.test
@@ -0,0 +1,233 @@
+# Conditions:
+# a) Linking a non-shared executable file.
+# b) There ars multiple R_MIPS_64/R_MIPS_HI16/R_MIPS_LO16 relocations
+# with various targets.
+# Check:
+# a) Emitting of R_MIPS_REL32 relocations.
+#
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-so.o
+# RUN: lld -flavor gnu -target mips64el -shared -o %t.so %t-so.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-o.o
+# RUN: lld -flavor gnu -target mips64el -e T0 --noinhibit-exec \
+# RUN: -o %t.exe %t-o.o %t.so
+# RUN: llvm-readobj -dt -r -sections %t.exe | FileCheck %s
+
+# CHECK: Sections [
+# CHECK: Section {
+# CHECK-NOT: Name: .plt ({{[0-9]+}})
+
+# CHECK: Relocations [
+# CHECK-NEXT: Section (5) .rel.dyn {
+# CHECK-NEXT: 0x120002000 R_MIPS_REL32/R_MIPS_64/R_MIPS_NONE D2 0x0
+# CHECK-NEXT: 0x120002004 R_MIPS_REL32/R_MIPS_64/R_MIPS_NONE T1 0x0
+# CHECK-NEXT: 0x120002008 R_MIPS_REL32/R_MIPS_64/R_MIPS_NONE T2 0x0
+# CHECK-NEXT: 0x120002008 R_MIPS_REL32/R_MIPS_64/R_MIPS_NONE D1 0x0
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+
+# CHECK: DynamicSymbols [
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: @ (0)
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Local (0x0)
+# CHECK-NEXT: Type: None (0x0)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined (0x0)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: D2@ (10)
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 4
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: Object (0x1)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined (0x0)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: T1@ (1)
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: Function (0x2)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined (0x0)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: T2@ (4)
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: Function (0x2)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined (0x0)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: D1@ (7)
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 4
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: Object (0x1)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined (0x0)
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+
+# so.o
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ARCH_64]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .data
+ Type: SHT_PROGBITS
+ Size: 0x08
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+ - Name: T2
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x4
+ Size: 4
+ - Name: D1
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x0
+ Size: 4
+ - Name: D2
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x4
+ Size: 4
+
+# o.o
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ARCH_64]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .data
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_ALLOC]
+
+- Name: .rel.text
+ Type: SHT_RELA
+ Info: .text
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x00
+ Symbol: _gp_disp
+ Type: R_MIPS_HI16
+ - Offset: 0x00
+ Symbol: _gp_disp
+ Type: R_MIPS_LO16
+
+- Name: .rel.data
+ Type: SHT_RELA
+ Info: .data
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x00 # LT0 is a locally defined function
+ Symbol: LT0
+ Type: R_MIPS_64
+ - Offset: 0x00 # LD0 is a locally defined data object
+ Symbol: LD0
+ Type: R_MIPS_64
+ - Offset: 0x00 # T0 is a defined function
+ Symbol: T0
+ Type: R_MIPS_64
+ - Offset: 0x04 # T1 is a function from shared lib
+ Symbol: T1
+ Type: R_MIPS_64
+ - Offset: 0x08 # T2 has unknown type and defined in shared lib
+ Symbol: T2
+ Type: R_MIPS_64
+ - Offset: 0x00 # T4 is an undefined function
+ Symbol: T4
+ Type: R_MIPS_64
+ - Offset: 0x04 # D0 is a defined data object
+ Symbol: D0
+ Type: R_MIPS_64
+ - Offset: 0x08 # D1 is a data object from shared lib
+ Symbol: D1
+ Type: R_MIPS_64
+ - Offset: 0x00 # D2 has unknown type and defined in shared lib
+ Symbol: D2
+ Type: R_MIPS_64
+ - Offset: 0x04 # D4 is an undefined data object
+ Symbol: D4
+ Type: R_MIPS_64
+ - Offset: 0x08 # U1 is undefined and has unknown type
+ Symbol: U1
+ Type: R_MIPS_64
+
+Symbols:
+ Local:
+ - Name: LT0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0
+ Size: 4
+ - Name: LD0
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0
+ Size: 4
+
+ Global:
+ - Name: _gp_disp
+ Type: STT_OBJECT
+
+ - Name: T0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x4
+ Size: 8
+ - Name: T1
+ Type: STT_FUNC
+ - Name: T2
+ - Name: T4
+ Type: STT_FUNC
+
+ - Name: D0
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x4
+ Size: 8
+ - Name: D1
+ Type: STT_OBJECT
+ - Name: D2
+ - Name: D4
+ Type: STT_OBJECT
+ - Name: U1
+...
diff --git a/test/elf/Mips/rel-dynamic-08-micro.test b/test/elf/Mips/rel-dynamic-08-micro.test
new file mode 100644
index 000000000000..de0038956086
--- /dev/null
+++ b/test/elf/Mips/rel-dynamic-08-micro.test
@@ -0,0 +1,236 @@
+# Conditions:
+# a) Linking a non-shared executable file.
+# b) There ars multiple R_MIPS_32/R_MICROMIPS_HI16/R_MICROMIPS_LO16
+# relocations with various targets.
+# Check:
+# a) Emitting of R_MIPS_REL32 relocations.
+#
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-so.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t-so.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-o.o
+# RUN: lld -flavor gnu -target mipsel -e T0 --noinhibit-exec \
+# RUN: -o %t.exe %t-o.o %t.so
+# RUN: llvm-readobj -dt -r -sections %t.exe | FileCheck %s
+
+# CHECK: Sections [
+# CHECK: Section {
+# CHECK-NOT: Name: .plt ({{[0-9]+}})
+
+# CHECK: Relocations [
+# CHECK-NEXT: Section (5) .rel.dyn {
+# CHECK-NEXT: 0x402000 R_MIPS_REL32 D2 0x0
+# CHECK-NEXT: 0x402004 R_MIPS_REL32 T1 0x0
+# CHECK-NEXT: 0x402008 R_MIPS_REL32 T2 0x0
+# CHECK-NEXT: 0x402008 R_MIPS_REL32 D1 0x0
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+
+# CHECK: DynamicSymbols [
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: @ (0)
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Local (0x0)
+# CHECK-NEXT: Type: None (0x0)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined (0x0)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: D2@ (10)
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 4
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: Object (0x1)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined (0x0)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: T1@ (1)
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: Function (0x2)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined (0x0)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: T2@ (4)
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: Function (0x2)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined (0x0)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: D1@ (7)
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 4
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: Object (0x1)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined (0x0)
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+
+# so.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2 ]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .data
+ Type: SHT_PROGBITS
+ Size: 0x08
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+ - Name: T2
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x4
+ Size: 4
+ - Name: D1
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x0
+ Size: 4
+ - Name: D2
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x4
+ Size: 4
+
+# o.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_CPIC, EF_MIPS_ABI_O32,
+ EF_MIPS_ARCH_32R2, EF_MIPS_MICROMIPS ]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .data
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_ALLOC]
+
+- Name: .rel.text
+ Type: SHT_REL
+ Info: .text
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x00
+ Symbol: _gp_disp
+ Type: R_MICROMIPS_HI16
+ - Offset: 0x00
+ Symbol: _gp_disp
+ Type: R_MICROMIPS_LO16
+
+- Name: .rel.data
+ Type: SHT_REL
+ Info: .data
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x00 # LT0 is a locally defined function
+ Symbol: LT0
+ Type: R_MIPS_32
+ - Offset: 0x00 # LD0 is a locally defined data object
+ Symbol: LD0
+ Type: R_MIPS_32
+ - Offset: 0x00 # T0 is a defined function
+ Symbol: T0
+ Type: R_MIPS_32
+ - Offset: 0x04 # T1 is a function from shared lib
+ Symbol: T1
+ Type: R_MIPS_32
+ - Offset: 0x08 # T2 has unknown type and defined in shared lib
+ Symbol: T2
+ Type: R_MIPS_32
+ - Offset: 0x00 # T4 is an undefined function
+ Symbol: T4
+ Type: R_MIPS_32
+ - Offset: 0x04 # D0 is a defined data object
+ Symbol: D0
+ Type: R_MIPS_32
+ - Offset: 0x08 # D1 is a data object from shared lib
+ Symbol: D1
+ Type: R_MIPS_32
+ - Offset: 0x00 # D2 has unknown type and defined in shared lib
+ Symbol: D2
+ Type: R_MIPS_32
+ - Offset: 0x04 # D4 is an undefined data object
+ Symbol: D4
+ Type: R_MIPS_32
+ - Offset: 0x08 # U1 is undefined and has unknown type
+ Symbol: U1
+ Type: R_MIPS_32
+
+Symbols:
+ Local:
+ - Name: LT0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+ Other: [ STO_MIPS_MICROMIPS ]
+ - Name: LD0
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x0
+ Size: 4
+
+ Global:
+ - Name: _gp_disp
+ Type: STT_OBJECT
+
+ - Name: T0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x4
+ Size: 8
+ Other: [ STO_MIPS_MICROMIPS ]
+ - Name: T1
+ Type: STT_FUNC
+ - Name: T2
+ - Name: T4
+ Type: STT_FUNC
+
+ - Name: D0
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x4
+ Size: 8
+ - Name: D1
+ Type: STT_OBJECT
+ - Name: D2
+ - Name: D4
+ Type: STT_OBJECT
+ - Name: U1
+...
diff --git a/test/elf/Mips/rel-dynamic-08.test b/test/elf/Mips/rel-dynamic-08.test
new file mode 100644
index 000000000000..62f4dc278b05
--- /dev/null
+++ b/test/elf/Mips/rel-dynamic-08.test
@@ -0,0 +1,233 @@
+# Conditions:
+# a) Linking a non-shared executable file.
+# b) There ars multiple R_MIPS_32/R_MIPS_HI16/R_MIPS_LO16 relocations
+# with various targets.
+# Check:
+# a) Emitting of R_MIPS_REL32 relocations.
+#
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-so.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t-so.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-o.o
+# RUN: lld -flavor gnu -target mipsel -e T0 --noinhibit-exec \
+# RUN: -o %t.exe %t-o.o %t.so
+# RUN: llvm-readobj -dt -r -sections %t.exe | FileCheck %s
+
+# CHECK: Sections [
+# CHECK: Section {
+# CHECK-NOT: Name: .plt ({{[0-9]+}})
+
+# CHECK: Relocations [
+# CHECK-NEXT: Section (5) .rel.dyn {
+# CHECK-NEXT: 0x402000 R_MIPS_REL32 D2 0x0
+# CHECK-NEXT: 0x402004 R_MIPS_REL32 T1 0x0
+# CHECK-NEXT: 0x402008 R_MIPS_REL32 T2 0x0
+# CHECK-NEXT: 0x402008 R_MIPS_REL32 D1 0x0
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+
+# CHECK: DynamicSymbols [
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: @ (0)
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Local (0x0)
+# CHECK-NEXT: Type: None (0x0)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined (0x0)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: D2@ (10)
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 4
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: Object (0x1)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined (0x0)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: T1@ (1)
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: Function (0x2)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined (0x0)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: T2@ (4)
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: Function (0x2)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined (0x0)
+# CHECK-NEXT: }
+# CHECK-NEXT: Symbol {
+# CHECK-NEXT: Name: D1@ (7)
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 4
+# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Type: Object (0x1)
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined (0x0)
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+
+# so.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .data
+ Type: SHT_PROGBITS
+ Size: 0x08
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+ - Name: T2
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x4
+ Size: 4
+ - Name: D1
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x0
+ Size: 4
+ - Name: D2
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x4
+ Size: 4
+
+# o.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .data
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_ALLOC]
+
+- Name: .rel.text
+ Type: SHT_REL
+ Info: .text
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x00
+ Symbol: _gp_disp
+ Type: R_MIPS_HI16
+ - Offset: 0x00
+ Symbol: _gp_disp
+ Type: R_MIPS_LO16
+
+- Name: .rel.data
+ Type: SHT_REL
+ Info: .data
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x00 # LT0 is a locally defined function
+ Symbol: LT0
+ Type: R_MIPS_32
+ - Offset: 0x00 # LD0 is a locally defined data object
+ Symbol: LD0
+ Type: R_MIPS_32
+ - Offset: 0x00 # T0 is a defined function
+ Symbol: T0
+ Type: R_MIPS_32
+ - Offset: 0x04 # T1 is a function from shared lib
+ Symbol: T1
+ Type: R_MIPS_32
+ - Offset: 0x08 # T2 has unknown type and defined in shared lib
+ Symbol: T2
+ Type: R_MIPS_32
+ - Offset: 0x00 # T4 is an undefined function
+ Symbol: T4
+ Type: R_MIPS_32
+ - Offset: 0x04 # D0 is a defined data object
+ Symbol: D0
+ Type: R_MIPS_32
+ - Offset: 0x08 # D1 is a data object from shared lib
+ Symbol: D1
+ Type: R_MIPS_32
+ - Offset: 0x00 # D2 has unknown type and defined in shared lib
+ Symbol: D2
+ Type: R_MIPS_32
+ - Offset: 0x04 # D4 is an undefined data object
+ Symbol: D4
+ Type: R_MIPS_32
+ - Offset: 0x08 # U1 is undefined and has unknown type
+ Symbol: U1
+ Type: R_MIPS_32
+
+Symbols:
+ Local:
+ - Name: LT0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+ - Name: LD0
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x0
+ Size: 4
+
+ Global:
+ - Name: _gp_disp
+ Type: STT_OBJECT
+
+ - Name: T0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x4
+ Size: 8
+ - Name: T1
+ Type: STT_FUNC
+ - Name: T2
+ - Name: T4
+ Type: STT_FUNC
+
+ - Name: D0
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x4
+ Size: 8
+ - Name: D1
+ Type: STT_OBJECT
+ - Name: D2
+ - Name: D4
+ Type: STT_OBJECT
+ - Name: U1
+...
diff --git a/test/elf/Mips/rel-dynamic-09-micro.test b/test/elf/Mips/rel-dynamic-09-micro.test
new file mode 100644
index 000000000000..07ffce9eb074
--- /dev/null
+++ b/test/elf/Mips/rel-dynamic-09-micro.test
@@ -0,0 +1,109 @@
+# Conditions:
+# a) Linking a non-shared executable file.
+# b) Relocations' targets are undefined symbols.
+# Check:
+# a) There should be no dynamic relocations.
+# b) There should be no PLT entries.
+#
+# RUN: yaml2obj -format=elf %s > %t-obj
+# RUN: lld -flavor gnu -target mipsel --noinhibit-exec -e T0 -o %t2-exe %t-obj
+# RUN: llvm-readobj -dt -r -s %t2-exe | FileCheck -check-prefix=PLT-SYM %s
+
+# PLT-SYM: Sections [
+# PLT-SYM: Section {
+# PLT-SYM-NOT: Name: .plt ({{[0-9]+}})
+
+# PLT-SYM: Relocations [
+# PLT-SYM-NEXT: ]
+
+# PLT-SYM: DynamicSymbols [
+# PLT-SYM-NEXT: Symbol {
+# PLT-SYM-NEXT: Name: @ (0)
+# PLT-SYM-NEXT: Value: 0x0
+# PLT-SYM-NEXT: Size: 0
+# PLT-SYM-NEXT: Binding: Local (0x0)
+# PLT-SYM-NEXT: Type: None (0x0)
+# PLT-SYM-NEXT: Other: 0
+# PLT-SYM-NEXT: Section: Undefined (0x0)
+# PLT-SYM-NEXT: }
+# PLT-SYM-NEXT: ]
+
+!ELF
+FileHeader: !FileHeader
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_CPIC, EF_MIPS_ABI_O32,
+ EF_MIPS_ARCH_32R2, EF_MIPS_MICROMIPS ]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Content: "0000000000000000"
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .data
+ Type: SHT_PROGBITS
+ Content: "0000000000000000"
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_ALLOC]
+
+- Name: .rel.text
+ Type: SHT_REL
+ Info: .text
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x04
+ Symbol: T3
+ Type: R_MICROMIPS_26_S1
+
+- Name: .rel.data
+ Type: SHT_REL
+ Info: .data
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x00
+ Symbol: T1
+ Type: R_MICROMIPS_HI16
+ - Offset: 0x00
+ Symbol: T1
+ Type: R_MICROMIPS_LO16
+ - Offset: 0x04
+ Symbol: T2
+ Type: R_MIPS_32
+
+ - Offset: 0x04
+ Symbol: D1
+ Type: R_MICROMIPS_HI16
+ - Offset: 0x04
+ Symbol: D1
+ Type: R_MICROMIPS_LO16
+ - Offset: 0x04
+ Symbol: D2
+ Type: R_MIPS_32
+
+Symbols:
+ Global:
+ - Name: T0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 8
+ Other: [ STO_MIPS_MICROMIPS ]
+ - Name: T1
+ Type: STT_FUNC
+ - Name: T2
+ Type: STT_FUNC
+ - Name: T3
+ Type: STT_FUNC
+ - Name: D0
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x0
+ Size: 8
+ - Name: D1
+ Type: STT_OBJECT
+ - Name: D2
+ Type: STT_OBJECT
diff --git a/test/elf/Mips/rel-dynamic-09.test b/test/elf/Mips/rel-dynamic-09.test
new file mode 100644
index 000000000000..18eeb9dd33d8
--- /dev/null
+++ b/test/elf/Mips/rel-dynamic-09.test
@@ -0,0 +1,107 @@
+# Conditions:
+# a) Linking a non-shared executable file.
+# b) Relocations' targets are undefined symbols.
+# Check:
+# a) There should be no dynamic relocations.
+# b) There should be no PLT entries.
+#
+# RUN: yaml2obj -format=elf %s > %t-obj
+# RUN: lld -flavor gnu -target mipsel --noinhibit-exec -e T0 -o %t2-exe %t-obj
+# RUN: llvm-readobj -dt -r -s %t2-exe | FileCheck -check-prefix=PLT-SYM %s
+
+# PLT-SYM: Sections [
+# PLT-SYM: Section {
+# PLT-SYM-NOT: Name: .plt ({{[0-9]+}})
+
+# PLT-SYM: Relocations [
+# PLT-SYM-NEXT: ]
+
+# PLT-SYM: DynamicSymbols [
+# PLT-SYM-NEXT: Symbol {
+# PLT-SYM-NEXT: Name: @ (0)
+# PLT-SYM-NEXT: Value: 0x0
+# PLT-SYM-NEXT: Size: 0
+# PLT-SYM-NEXT: Binding: Local (0x0)
+# PLT-SYM-NEXT: Type: None (0x0)
+# PLT-SYM-NEXT: Other: 0
+# PLT-SYM-NEXT: Section: Undefined (0x0)
+# PLT-SYM-NEXT: }
+# PLT-SYM-NEXT: ]
+
+!ELF
+FileHeader: !FileHeader
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32 ]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Content: "0000000000000000"
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .data
+ Type: SHT_PROGBITS
+ Content: "0000000000000000"
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_ALLOC]
+
+- Name: .rel.text
+ Type: SHT_REL
+ Info: .text
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x04
+ Symbol: T3
+ Type: R_MIPS_26
+
+- Name: .rel.data
+ Type: SHT_REL
+ Info: .data
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x00
+ Symbol: T1
+ Type: R_MIPS_HI16
+ - Offset: 0x00
+ Symbol: T1
+ Type: R_MIPS_LO16
+ - Offset: 0x04
+ Symbol: T2
+ Type: R_MIPS_32
+
+ - Offset: 0x04
+ Symbol: D1
+ Type: R_MIPS_HI16
+ - Offset: 0x04
+ Symbol: D1
+ Type: R_MIPS_LO16
+ - Offset: 0x04
+ Symbol: D2
+ Type: R_MIPS_32
+
+Symbols:
+ Global:
+ - Name: T0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 8
+ - Name: T1
+ Type: STT_FUNC
+ - Name: T2
+ Type: STT_FUNC
+ - Name: T3
+ Type: STT_FUNC
+ - Name: D0
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x0
+ Size: 8
+ - Name: D1
+ Type: STT_OBJECT
+ - Name: D2
+ Type: STT_OBJECT
diff --git a/test/elf/Mips/rel-dynamic-10-micro.test b/test/elf/Mips/rel-dynamic-10-micro.test
new file mode 100644
index 000000000000..6b3f2af3db32
--- /dev/null
+++ b/test/elf/Mips/rel-dynamic-10-micro.test
@@ -0,0 +1,166 @@
+# Conditions:
+# a) Linking a non-shared executable file.
+# b) Relocations' targets are symbols defined in the other object.
+# Check:
+# a) There should be no dynamic relocations.
+# b) There should be no PLT entries.
+#
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-o1.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-o2.o
+# RUN: lld -flavor gnu -target mipsel -e T0 -o %t.exe %t-o1.o %t-o2.o
+# RUN: llvm-readobj -dt -r -s %t.exe | FileCheck -check-prefix=PLT-SYM %s
+
+# PLT-SYM: Sections [
+# PLT-SYM: Section {
+# PLT-SYM-NOT: Name: .plt ({{[0-9]+}})
+
+# PLT-SYM: Relocations [
+# PLT-SYM-NEXT: ]
+
+# PLT-SYM: DynamicSymbols [
+# PLT-SYM-NEXT: Symbol {
+# PLT-SYM-NEXT: Name: @ (0)
+# PLT-SYM-NEXT: Value: 0x0
+# PLT-SYM-NEXT: Size: 0
+# PLT-SYM-NEXT: Binding: Local (0x0)
+# PLT-SYM-NEXT: Type: None (0x0)
+# PLT-SYM-NEXT: Other: 0
+# PLT-SYM-NEXT: Section: Undefined (0x0)
+# PLT-SYM-NEXT: }
+# PLT-SYM-NEXT: ]
+
+# o1.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32,
+ EF_MIPS_ARCH_32R2, EF_MIPS_MICROMIPS ]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .data
+ Type: SHT_PROGBITS
+ Size: 0x08
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+ Other: [ STO_MIPS_MICROMIPS ]
+ - Name: T2
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x4
+ Size: 4
+ Other: [ STO_MIPS_MICROMIPS ]
+ - Name: T3
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x8
+ Size: 4
+ Other: [ STO_MIPS_MICROMIPS ]
+ - Name: D1
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x0
+ Size: 4
+ - Name: D2
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x4
+ Size: 4
+
+# o2.o
+---
+FileHeader: !FileHeader
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_CPIC, EF_MIPS_ABI_O32,
+ EF_MIPS_ARCH_32R2, EF_MIPS_MICROMIPS ]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x08
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .data
+ Type: SHT_PROGBITS
+ Size: 0x08
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_ALLOC]
+
+- Name: .rel.text
+ Type: SHT_REL
+ Info: .text
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x04
+ Symbol: T3
+ Type: R_MICROMIPS_26_S1
+
+- Name: .rel.data
+ Type: SHT_REL
+ Info: .data
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x00
+ Symbol: T1
+ Type: R_MICROMIPS_HI16
+ - Offset: 0x00
+ Symbol: T1
+ Type: R_MICROMIPS_LO16
+ - Offset: 0x04
+ Symbol: T2
+ Type: R_MIPS_32
+
+ - Offset: 0x04
+ Symbol: D1
+ Type: R_MICROMIPS_HI16
+ - Offset: 0x04
+ Symbol: D1
+ Type: R_MICROMIPS_LO16
+ - Offset: 0x04
+ Symbol: D2
+ Type: R_MIPS_32
+
+Symbols:
+ Global:
+ - Name: T0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 8
+ Other: [ STO_MIPS_MICROMIPS ]
+ - Name: T1
+ Type: STT_FUNC
+ - Name: T2
+ Type: STT_FUNC
+ - Name: T3
+ Type: STT_FUNC
+ - Name: D0
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x0
+ Size: 8
+ - Name: D1
+ Type: STT_OBJECT
+ - Name: D2
+ Type: STT_OBJECT
+...
diff --git a/test/elf/Mips/rel-dynamic-10.test b/test/elf/Mips/rel-dynamic-10.test
new file mode 100644
index 000000000000..4df558167fc7
--- /dev/null
+++ b/test/elf/Mips/rel-dynamic-10.test
@@ -0,0 +1,160 @@
+# Conditions:
+# a) Linking a non-shared executable file.
+# b) Relocations' targets are symbols defined in the other object.
+# Check:
+# a) There should be no dynamic relocations.
+# b) There should be no PLT entries.
+#
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-o1.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-o2.o
+# RUN: lld -flavor gnu -target mipsel -e T0 -o %t.exe %t-o1.o %t-o2.o
+# RUN: llvm-readobj -dt -r -s %t.exe | FileCheck -check-prefix=PLT-SYM %s
+
+# PLT-SYM: Sections [
+# PLT-SYM: Section {
+# PLT-SYM-NOT: Name: .plt ({{[0-9]+}})
+
+# PLT-SYM: Relocations [
+# PLT-SYM-NEXT: ]
+
+# PLT-SYM: DynamicSymbols [
+# PLT-SYM-NEXT: Symbol {
+# PLT-SYM-NEXT: Name: @ (0)
+# PLT-SYM-NEXT: Value: 0x0
+# PLT-SYM-NEXT: Size: 0
+# PLT-SYM-NEXT: Binding: Local (0x0)
+# PLT-SYM-NEXT: Type: None (0x0)
+# PLT-SYM-NEXT: Other: 0
+# PLT-SYM-NEXT: Section: Undefined (0x0)
+# PLT-SYM-NEXT: }
+# PLT-SYM-NEXT: ]
+
+# o1.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .data
+ Type: SHT_PROGBITS
+ Size: 0x08
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+ - Name: T2
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x4
+ Size: 4
+ - Name: T3
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x8
+ Size: 4
+ - Name: D1
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x0
+ Size: 4
+ - Name: D2
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x4
+ Size: 4
+
+# o2.o
+---
+FileHeader: !FileHeader
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x08
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .data
+ Type: SHT_PROGBITS
+ Size: 0x08
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_ALLOC]
+
+- Name: .rel.text
+ Type: SHT_REL
+ Info: .text
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x04
+ Symbol: T3
+ Type: R_MIPS_26
+
+- Name: .rel.data
+ Type: SHT_REL
+ Info: .data
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x00
+ Symbol: T1
+ Type: R_MIPS_HI16
+ - Offset: 0x00
+ Symbol: T1
+ Type: R_MIPS_LO16
+ - Offset: 0x04
+ Symbol: T2
+ Type: R_MIPS_32
+
+ - Offset: 0x04
+ Symbol: D1
+ Type: R_MIPS_HI16
+ - Offset: 0x04
+ Symbol: D1
+ Type: R_MIPS_LO16
+ - Offset: 0x04
+ Symbol: D2
+ Type: R_MIPS_32
+
+Symbols:
+ Global:
+ - Name: T0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 8
+ - Name: T1
+ Type: STT_FUNC
+ - Name: T2
+ Type: STT_FUNC
+ - Name: T3
+ Type: STT_FUNC
+ - Name: D0
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x0
+ Size: 8
+ - Name: D1
+ Type: STT_OBJECT
+ - Name: D2
+ Type: STT_OBJECT
+...
diff --git a/test/elf/Mips/rel-dynamic-11.test b/test/elf/Mips/rel-dynamic-11.test
new file mode 100644
index 000000000000..20295396cd08
--- /dev/null
+++ b/test/elf/Mips/rel-dynamic-11.test
@@ -0,0 +1,110 @@
+# Conditions:
+# a) Linking a shared library.
+# b) Relocations' targets are symbols defined in the other shared object.
+# Check:
+# a) Emitting R_MIPS_REL32 relocations for both symbols.
+# b) There should be no PLT entries.
+#
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-so.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t1.so %t-so.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-o.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t2.so %t-o.o %t1.so
+# RUN: llvm-readobj -dt -r -s %t2.so | FileCheck -check-prefix=PLT-SYM %s
+
+# PLT-SYM: Sections [
+# PLT-SYM: Section {
+# PLT-SYM-NOT: Name: .plt ({{[0-9]+}})
+#
+# PLT-SYM: Relocations [
+# PLT-SYM-NEXT: Section (4) .rel.dyn {
+# PLT-SYM-NEXT: 0x150 R_MIPS_REL32 T1 0x0
+# PLT-SYM-NEXT: 0x2000 R_MIPS_REL32 T1 0x0
+# PLT-SYM-NEXT: }
+# PLT-SYM-NEXT: ]
+#
+# PLT-SYM: Name: T1@ (7)
+# PLT-SYM-NEXT: Value: 0x0
+# PLT-SYM-NEXT: Size: 0
+# PLT-SYM-NEXT: Binding: Global (0x1)
+# PLT-SYM-NEXT: Type: Function (0x2)
+# PLT-SYM-NEXT: Other: 0
+# PLT-SYM-NEXT: Section: Undefined (0x0)
+
+# so.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+
+# o.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x08
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .data
+ Type: SHT_PROGBITS
+ Size: 0x08
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_ALLOC]
+
+- Name: .rel.text
+ Type: SHT_REL
+ Info: .text
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x00
+ Symbol: T1
+ Type: R_MIPS_32
+
+- Name: .rel.data
+ Type: SHT_REL
+ Info: .data
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x00
+ Symbol: T1
+ Type: R_MIPS_32
+
+Symbols:
+ Global:
+ - Name: T0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+ - Name: T1
+ - Name: D0
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x0
+ Size: 8
+...
diff --git a/test/elf/Mips/rel-dynamic-12.test b/test/elf/Mips/rel-dynamic-12.test
new file mode 100644
index 000000000000..2a4061ab4035
--- /dev/null
+++ b/test/elf/Mips/rel-dynamic-12.test
@@ -0,0 +1,213 @@
+# Conditions:
+# a) Linking a non-shared executable file.
+# b) Relocations' targets are symbols defined in the shared object.
+# c) Relocations are R_MIPS_PCHI16 / R_MIPS_PCLO16.
+# Check:
+# a) Emitting R_MIPS_REL32, R_MIPS_COPY, R_MIPS_JUMP_SLOT relocations.
+# b) STO_MIPS_PLT flag in the dynamic symbol table for symbols require
+# a pointer equality.
+#
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-so.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t-so.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-o.o
+# RUN: lld -flavor gnu -target mipsel -e T0 -o %t.exe %t-o.o %t.so
+# RUN: llvm-readobj -dt -r %t.exe | FileCheck -check-prefix=PLT-SYM %s
+
+# PLT-SYM: Relocations [
+# PLT-SYM-NEXT: Section (5) .rel.dyn {
+# PLT-SYM-NEXT: 0x402014 R_MIPS_REL32 T2 0x0
+# PLT-SYM-NEXT: 0x402014 R_MIPS_REL32 D2 0x0
+# PLT-SYM-NEXT: 0x402018 R_MIPS_COPY D1 0x0
+# PLT-SYM-NEXT: }
+# PLT-SYM-NEXT: Section (6) .rel.plt {
+# PLT-SYM-NEXT: 0x402008 R_MIPS_JUMP_SLOT T3 0x0
+# PLT-SYM-NEXT: 0x40200C R_MIPS_JUMP_SLOT T1 0x0
+# PLT-SYM-NEXT: }
+# PLT-SYM-NEXT: ]
+
+# PLT-SYM: DynamicSymbols [
+# PLT-SYM-NEXT: Symbol {
+# PLT-SYM-NEXT: Name: @ (0)
+# PLT-SYM-NEXT: Value: 0x0
+# PLT-SYM-NEXT: Size: 0
+# PLT-SYM-NEXT: Binding: Local (0x0)
+# PLT-SYM-NEXT: Type: None (0x0)
+# PLT-SYM-NEXT: Other: 0
+# PLT-SYM-NEXT: Section: Undefined (0x0)
+# PLT-SYM-NEXT: }
+# PLT-SYM-NEXT: Symbol {
+# PLT-SYM-NEXT: Name: D1@ (1)
+# PLT-SYM-NEXT: Value: 0x402018
+# PLT-SYM-NEXT: Size: 4
+# PLT-SYM-NEXT: Binding: Global (0x1)
+# PLT-SYM-NEXT: Type: Object (0x1)
+# PLT-SYM-NEXT: Other: 0
+# PLT-SYM-NEXT: Section: .bss (0xD)
+# PLT-SYM-NEXT: }
+# PLT-SYM-NEXT: Symbol {
+# PLT-SYM-NEXT: Name: T1@ (4)
+# PLT-SYM-NEXT: Value: 0x400220
+# PLT-SYM-NEXT: Size: 0
+# PLT-SYM-NEXT: Binding: Global (0x1)
+# PLT-SYM-NEXT: Type: Function (0x2)
+# PLT-SYM-NEXT: Other: 8
+# PLT-SYM-NEXT: Section: Undefined (0x0)
+# PLT-SYM-NEXT: }
+# PLT-SYM-NEXT: Symbol {
+# PLT-SYM-NEXT: Name: T3@ (10)
+# PLT-SYM-NEXT: Value: 0x0
+# PLT-SYM-NEXT: Size: 0
+# PLT-SYM-NEXT: Binding: Global (0x1)
+# PLT-SYM-NEXT: Type: Function (0x2)
+# PLT-SYM-NEXT: Other: 0
+# PLT-SYM-NEXT: Section: Undefined (0x0)
+# PLT-SYM-NEXT: }
+# PLT-SYM-NEXT: Symbol {
+# PLT-SYM-NEXT: Name: T2@ (7)
+# PLT-SYM-NEXT: Value: 0x0
+# PLT-SYM-NEXT: Size: 0
+# PLT-SYM-NEXT: Binding: Global (0x1)
+# PLT-SYM-NEXT: Type: Function (0x2)
+# PLT-SYM-NEXT: Other: 0
+# PLT-SYM-NEXT: Section: Undefined (0x0)
+# PLT-SYM-NEXT: }
+# PLT-SYM-NEXT: Symbol {
+# PLT-SYM-NEXT: Name: D2@ (13)
+# PLT-SYM-NEXT: Value: 0x0
+# PLT-SYM-NEXT: Size: 4
+# PLT-SYM-NEXT: Binding: Global (0x1)
+# PLT-SYM-NEXT: Type: Object (0x1)
+# PLT-SYM-NEXT: Other: 0
+# PLT-SYM-NEXT: Section: Undefined (0x0)
+# PLT-SYM-NEXT: }
+# PLT-SYM-NEXT: ]
+
+# so.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R6]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x0C
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .data
+ Type: SHT_PROGBITS
+ Size: 0x08
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_ALLOC]
+
+Symbols:
+ Global:
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 4
+ - Name: T2
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x4
+ Size: 4
+ - Name: T3
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x8
+ Size: 4
+ - Name: D1
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x0
+ Size: 4
+ - Name: D2
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x4
+ Size: 4
+
+# o.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R6]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x08
+ AddressAlign: 16
+ Flags: [SHF_EXECINSTR, SHF_ALLOC]
+
+- Name: .data
+ Type: SHT_PROGBITS
+ Size: 0x08
+ AddressAlign: 16
+ Flags: [SHF_WRITE, SHF_ALLOC]
+
+- Name: .rel.text
+ Type: SHT_REL
+ Info: .text
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x04
+ Symbol: T3
+ Type: R_MIPS_26
+
+- Name: .rel.data
+ Type: SHT_REL
+ Info: .data
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x00
+ Symbol: T1
+ Type: R_MIPS_PCHI16
+ - Offset: 0x00
+ Symbol: T1
+ Type: R_MIPS_PCLO16
+ - Offset: 0x04
+ Symbol: T2
+ Type: R_MIPS_32
+
+ - Offset: 0x04
+ Symbol: D1
+ Type: R_MIPS_PCHI16
+ - Offset: 0x04
+ Symbol: D1
+ Type: R_MIPS_PCLO16
+ - Offset: 0x04
+ Symbol: D2
+ Type: R_MIPS_32
+
+Symbols:
+ Global:
+ - Name: T0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 8
+ - Name: T1
+ Type: STT_FUNC
+ - Name: T2
+ Type: STT_FUNC
+ - Name: T3
+ Type: STT_FUNC
+ - Name: D0
+ Section: .data
+ Type: STT_OBJECT
+ Value: 0x0
+ Size: 8
+ - Name: D1
+ Type: STT_OBJECT
+ - Name: D2
+ Type: STT_OBJECT
+...
diff --git a/test/elf/Mips/rel-gprel16.test b/test/elf/Mips/rel-gprel16.test
new file mode 100644
index 000000000000..dc188ea6825a
--- /dev/null
+++ b/test/elf/Mips/rel-gprel16.test
@@ -0,0 +1,104 @@
+# Check R_MIPS_GPREL16 relocation handling.
+#
+# RUN: yaml2obj -format=elf %s > %t-obj
+# RUN: lld -flavor gnu -target mipsel -e G1 -shared -o %t.so %t-obj
+# RUN: llvm-readobj -symbols %t.so | FileCheck -check-prefix=SYM %s
+# RUN: llvm-objdump -s %t.so | FileCheck -check-prefix=SEC %s
+
+# SYM: Name: L1 (1)
+# SYM-NEXT: Value: 0xCC
+# SYM-NEXT: Size: 4
+# SYM-NEXT: Binding: Local (0x0)
+# SYM-NEXT: Type: Function (0x2)
+# SYM-NEXT: Other: 0
+# SYM-NEXT: Section: .text (0x4)
+
+# SYM: Name: G1 (4)
+# SYM-NEXT: Value: 0xD0
+# SYM-NEXT: Size: 4
+# SYM-NEXT: Binding: Global (0x1)
+# SYM-NEXT: Type: Function (0x2)
+# SYM-NEXT: Other: 0
+# SYM-NEXT: Section: .text (0x4)
+
+# SYM: Name: _gp (34)
+# SYM-NEXT: Value: 0x8FF0
+# SYM-NEXT: Size: 0
+# SYM-NEXT: Binding: Global (0x1)
+# SYM-NEXT: Type: Object (0x1)
+# SYM-NEXT: Other: 0
+# SYM-NEXT: Section: Absolute (0xFFF1)
+
+# 0x160db == 0xffff (addend) + 0x00cc (L1) + 0x01f000 (GP0) - 0x8ff0 (_gp)
+# SEC: Contents of section .rodata:
+# SEC-NEXT: 00d4 db600008 00000000 00000000 00000000 .`..............
+
+!ELF
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2 ]
+Sections:
+- Type: SHT_PROGBITS
+ Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x08
+
+- Type: SHT_REL
+ Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ Info: .text
+ AddressAlign: 0x04
+ Relocations:
+ - Offset: 0
+ Symbol: .rodata
+ Type: R_MIPS_GOT16
+ - Offset: 4
+ Symbol: .rodata
+ Type: R_MIPS_LO16
+
+- Type: SHT_PROGBITS
+ Name: .rodata
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC ]
+ AddressAlign: 0x04
+ Content: ffff0008000000000000000000000000
+
+- Type: SHT_REL
+ Name: .rel.rodata
+ Type: SHT_REL
+ Link: .symtab
+ Info: .rodata
+ AddressAlign: 0x04
+ Relocations:
+ - Offset: 0
+ Symbol: L1
+ Type: R_MIPS_GPREL16
+
+- Type: SHT_MIPS_REGINFO
+ Name: .reginfo
+ Type: SHT_MIPS_REGINFO
+ Flags: [ SHF_ALLOC ]
+ AddressAlign: 0x01
+ Content: 000000000000000000000000000000000000000000f00100
+
+Symbols:
+ Local:
+ - Name: L1
+ Section: .text
+ Value: 0x00
+ Size: 0x04
+ - Name: .rodata
+ Type: STT_SECTION
+ Section: .rodata
+ Global:
+ - Name: G1
+ Section: .text
+ Value: 0x04
+ Size: 0x04
diff --git a/test/elf/Mips/rel-gprel32-64.test b/test/elf/Mips/rel-gprel32-64.test
new file mode 100644
index 000000000000..723c8e1ee738
--- /dev/null
+++ b/test/elf/Mips/rel-gprel32-64.test
@@ -0,0 +1,70 @@
+# Check R_MIPS_GPREL32/R_MIPS_64 relocations handling.
+
+# RUN: yaml2obj -format=elf %s > %t.o
+# RUN: lld -flavor gnu -target mips64el -e T0 -o %t.exe %t.o
+# RUN: llvm-objdump -s %t.exe | FileCheck %s
+
+# CHECK: Contents of section .text:
+# CHECK-NEXT: 1200001a0 c871ffff ffffffff c871ffff c871ffff .q.......q...q..
+# CHECK-NEXT: 1200001b0 c871ffff ffffffff 00000000 00000000 .q..............
+
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ARCH_64]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 16
+ Size: 32
+
+ - Name: .rela.text
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 8
+ Info: .text
+ Relocations:
+ - Offset: 0x00
+ Symbol: LT1
+ Type: R_MIPS_GPREL16
+ Type2: R_MIPS_64
+ Type3: R_MIPS_NONE
+ - Offset: 0x08
+ Symbol: LT1
+ Type: R_MIPS_GPREL16
+ Type2: R_MIPS_64
+ Type3: R_MIPS_NONE
+ - Offset: 0x0C
+ Symbol: LT1
+ Type: R_MIPS_GPREL32
+ Type2: R_MIPS_64
+ Type3: R_MIPS_NONE
+ - Offset: 0x10
+ Symbol: LT1
+ Type: R_MIPS_GPREL32
+ Type2: R_MIPS_64
+ Type3: R_MIPS_NONE
+
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+
+ Global:
+ - Name: LT1
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x18
+ Size: 0x8
+ - Name: T0
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0
+ Size: 0x18
+...
diff --git a/test/elf/Mips/rel-gprel32.test b/test/elf/Mips/rel-gprel32.test
new file mode 100644
index 000000000000..73ae6f161979
--- /dev/null
+++ b/test/elf/Mips/rel-gprel32.test
@@ -0,0 +1,84 @@
+# Check R_MIPS_GPREL32 relocation handling.
+#
+# RUN: yaml2obj -format=elf %s > %t-obj
+# RUN: lld -flavor gnu -target mipsel -o %t-exe %t-obj
+# RUN: llvm-readobj -symbols %t-exe | FileCheck -check-prefix=SYM %s
+# RUN: llvm-objdump -s %t-exe | FileCheck -check-prefix=SEC %s
+
+# SYM: Name: $L1 (1)
+# SYM-NEXT: Value: 0x400108
+# SYM-NEXT: Size: 4
+# SYM-NEXT: Binding: Local (0x0)
+# SYM-NEXT: Type: Function (0x2)
+# SYM-NEXT: Other: 0
+# SYM-NEXT: Section: .text (0x5)
+#
+# SYM: Name: _gp (212)
+# SYM-NEXT: Value: 0x408FF0
+# SYM-NEXT: Size: 0
+# SYM-NEXT: Binding: Global (0x1)
+# SYM-NEXT: Type: Object (0x1)
+# SYM-NEXT: Other: 0
+# SYM-NEXT: Section: Absolute (0xFFF1)
+
+# 0x08FF711B == 0x8000001 (addend) + 0x400108 ($L1) +
+# 0x1000002 (GP0) - 0x408FF0 (_gp)
+# SEC: Contents of section .rodata:
+# SEC-NEXT: 400118 1b71ff08 00000000 00000000 00000000 .q..............
+
+!ELF
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2 ]
+Sections:
+- Type: SHT_PROGBITS
+ Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Content: 00000000000000000000000000000000
+
+- Type: SHT_PROGBITS
+ Name: .rodata
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC ]
+ AddressAlign: 0x04
+ Content: 01000008000000000000000000000000
+
+- Type: SHT_REL
+ Name: .rel.rodata
+ Type: SHT_REL
+ Link: .symtab
+ Info: .rodata
+ AddressAlign: 0x04
+ Relocations:
+ - Offset: 0
+ Symbol: $L1
+ Type: R_MIPS_GPREL32
+
+- Type: SHT_MIPS_REGINFO
+ Name: .reginfo
+ Type: SHT_MIPS_REGINFO
+ Flags: [ SHF_ALLOC ]
+ AddressAlign: 0x01
+ Content: 000000000000000000000000000000000000000002000001
+
+Symbols:
+ Local:
+ - Name: $L1
+ Section: .text
+ Value: 0x00
+ - Name: .rodata
+ Type: STT_SECTION
+ Section: .rodata
+ Global:
+ - Name: __start
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x04
+ Size: 12
+ - Name: _gp_disp
diff --git a/test/elf/Mips/rel-pc-hilo.test b/test/elf/Mips/rel-pc-hilo.test
new file mode 100644
index 000000000000..89cd2b121797
--- /dev/null
+++ b/test/elf/Mips/rel-pc-hilo.test
@@ -0,0 +1,70 @@
+# Check handling of R_MIPS_PCHI16 / R_MIPS_PCLO16 relocations.
+
+# RUN: yaml2obj -format=elf %s > %t.o
+# RUN: lld -flavor gnu -target mipsel -e T0 -o %t.exe %t.o
+# RUN: llvm-objdump -s -t %t.exe | FileCheck %s
+
+# CHECK: Contents of section .text:
+# CHECK-NEXT: 400110 01000000 02000000 03000000 00000000
+# ^
+# A = 0x10000 - 1 == 0xffff
+# V = (T1 + 0xffff - T0) >> 16 =>
+# V => 0x1000b >> 16 = 1
+# ^
+# A = 0x20000 - 1 == 0x1ffff
+# V = (T1 + 0x1ffff - T0 - 4) >> 16 =>
+# V => 0x20007 >> 16 = 2
+# ^
+# A = 0xffff == -1
+# V = T1 - 1 - T0 - 8 = 3
+
+# CHECK: SYMBOL TABLE:
+# CHECK: 00400110 g F .text 0000000c T0
+# CHECK: 0040011c g F .text 00000004 T1
+
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R6]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Content: "0100000002000000ffff000000000000"
+# ^ T0
+# ^ A := 0x1 == 0x10000
+# ^ A := 0x2 == 0x20000
+# ^ A := 0xffff == -1
+# ^ T1
+ AddressAlign: 16
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+
+- Name: .rel.text
+ Type: SHT_REL
+ Info: .text
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0
+ Symbol: T1
+ Type: R_MIPS_PCHI16
+ - Offset: 4
+ Symbol: T1
+ Type: R_MIPS_PCHI16
+ - Offset: 8
+ Symbol: T1
+ Type: R_MIPS_PCLO16
+
+Symbols:
+ Global:
+ - Name: T0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0
+ Size: 12
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 12
+ Size: 4
diff --git a/test/elf/Mips/rel-pc18-s3.test b/test/elf/Mips/rel-pc18-s3.test
new file mode 100644
index 000000000000..5d5d5c7ce658
--- /dev/null
+++ b/test/elf/Mips/rel-pc18-s3.test
@@ -0,0 +1,54 @@
+# Check handling of R_MIPS_PC18_S3 relocation.
+
+# RUN: yaml2obj -format=elf %s > %t.o
+# RUN: lld -flavor gnu -target mipsel -e T0 -o %t.exe %t.o
+# RUN: llvm-objdump -s -t %t.exe | FileCheck %s
+
+# CHECK: Contents of section .text:
+# CHECK-NEXT: 400110 00000000 01000000 00000000 00000000
+# ^ V
+# A = -1 << 3 = -8 =>
+# V = (T1 - 8 - (T0|7)^7) >> 3 =>
+# V => 8 >> 3 = 1
+
+# CHECK: SYMBOL TABLE:
+# CHECK: 00400110 g F .text 00000010 T0
+# CHECK: 00400120 g F .text 00000004 T1
+
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R6]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Content: "00000000ffff0300000000000000000000000000"
+# ^ T1
+# ^ T0 ^ A := 0x3ffff == -1
+ AddressAlign: 16
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+
+- Name: .rel.text
+ Type: SHT_REL
+ Info: .text
+ AddressAlign: 4
+ Relocations:
+ - Offset: 4
+ Symbol: T1
+ Type: R_MIPS_PC18_S3
+
+Symbols:
+ Global:
+ - Name: T0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0
+ Size: 16
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 16
+ Size: 4
diff --git a/test/elf/Mips/rel-pc19-s2.test b/test/elf/Mips/rel-pc19-s2.test
new file mode 100644
index 000000000000..479965df814f
--- /dev/null
+++ b/test/elf/Mips/rel-pc19-s2.test
@@ -0,0 +1,54 @@
+# Check handling of R_MIPS_PC19_S2 relocation.
+
+# RUN: yaml2obj -format=elf %s > %t.o
+# RUN: lld -flavor gnu -target mipsel -e T0 -o %t.exe %t.o
+# RUN: llvm-objdump -s -t %t.exe | FileCheck %s
+
+# CHECK: Contents of section .text:
+# CHECK-NEXT: 400110 01000000 00000000 00000000
+# ^ V
+# A = -1 << 2 = -4 =>
+# V = (T1 - 4 - T0) >> 2 =>
+# V => 4 >> 2 = 1
+
+# CHECK: SYMBOL TABLE:
+# CHECK: 00400110 g F .text 00000008 T0
+# CHECK: 00400118 g F .text 00000004 T1
+
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R6]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Content: "ffff07000000000000000000"
+# ^ T1
+# ^ T0 A := 0x7ffff == -1
+ AddressAlign: 16
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+
+- Name: .rel.text
+ Type: SHT_REL
+ Info: .text
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0
+ Symbol: T1
+ Type: R_MIPS_PC19_S2
+
+Symbols:
+ Global:
+ - Name: T0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0
+ Size: 8
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 8
+ Size: 4
diff --git a/test/elf/Mips/rel-pc21-s2.test b/test/elf/Mips/rel-pc21-s2.test
new file mode 100644
index 000000000000..44d840e94c32
--- /dev/null
+++ b/test/elf/Mips/rel-pc21-s2.test
@@ -0,0 +1,54 @@
+# Check handling of R_MIPS_PC21_S2 relocation.
+
+# RUN: yaml2obj -format=elf %s > %t.o
+# RUN: lld -flavor gnu -target mipsel -e T0 -o %t.exe %t.o
+# RUN: llvm-objdump -s -t %t.exe | FileCheck %s
+
+# CHECK: Contents of section .text:
+# CHECK-NEXT: 400110 01000000 00000000 00000000
+# ^ V
+# A = -1 << 2 = -4 =>
+# V = (T1 - 4 - T0) >> 2 =>
+# V => 4 >> 2 = 1
+
+# CHECK: SYMBOL TABLE:
+# CHECK: 00400110 g F .text 00000008 T0
+# CHECK: 00400118 g F .text 00000004 T1
+
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R6]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Content: "ffff1f000000000000000000"
+# ^ T1
+# ^ T0 A := 0x1fffff
+ AddressAlign: 16
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+
+- Name: .rel.text
+ Type: SHT_REL
+ Info: .text
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0
+ Symbol: T1
+ Type: R_MIPS_PC21_S2
+
+Symbols:
+ Global:
+ - Name: T0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0
+ Size: 8
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 8
+ Size: 4
diff --git a/test/elf/Mips/rel-pc26-s2.test b/test/elf/Mips/rel-pc26-s2.test
new file mode 100644
index 000000000000..abd05040f0c3
--- /dev/null
+++ b/test/elf/Mips/rel-pc26-s2.test
@@ -0,0 +1,54 @@
+# Check handling of R_MIPS_PC26_S2 relocation.
+
+# RUN: yaml2obj -format=elf %s > %t.o
+# RUN: lld -flavor gnu -target mipsel -e T0 -o %t.exe %t.o
+# RUN: llvm-objdump -s -t %t.exe | FileCheck %s
+
+# CHECK: Contents of section .text:
+# CHECK-NEXT: 400110 01000000 00000000 00000000
+# ^ V
+# A = -1 << 2 = -4 =>
+# V = (T1 - 4 - T0) >> 2 =>
+# V => 4 >> 2 = 1
+
+# CHECK: SYMBOL TABLE:
+# CHECK: 00400110 g F .text 00000008 T0
+# CHECK: 00400118 g F .text 00000004 T1
+
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R6]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Content: "ffffff030000000000000000"
+# ^ T1
+# ^ T0 A := 0x3ffffff == -1
+ AddressAlign: 16
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+
+- Name: .rel.text
+ Type: SHT_REL
+ Info: .text
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0
+ Symbol: T1
+ Type: R_MIPS_PC26_S2
+
+Symbols:
+ Global:
+ - Name: T0
+ Section: .text
+ Type: STT_FUNC
+ Value: 0
+ Size: 8
+ - Name: T1
+ Section: .text
+ Type: STT_FUNC
+ Value: 8
+ Size: 4
diff --git a/test/elf/Mips/rel-pc32.test b/test/elf/Mips/rel-pc32.test
new file mode 100644
index 000000000000..e448e8afc30e
--- /dev/null
+++ b/test/elf/Mips/rel-pc32.test
@@ -0,0 +1,59 @@
+# Check handling of R_MIPS_PC32 relocation.
+# RUN: yaml2obj -format=elf %s > %t-obj
+# RUN: lld -flavor gnu -target mipsel -o %t-exe %t-obj
+# RUN: llvm-objdump -s -t %t-exe | FileCheck %s
+
+# CHECK: Contents of section .data:
+# CHECK-NEXT: 402000 00000000 05000080 fdffff7f ............
+# ^^ data2 + 0x80000001 - data1
+# ^^ data1 + 0x80000001 - data2
+# CHECK: SYMBOL TABLE:
+# CHECK: 00402004 g .data 00000004 data1
+# CHECK: 00402008 g .data 00000004 data2
+
+!ELF
+FileHeader: !FileHeader
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Content: "00000000"
+ AddressAlign: 16
+ Flags: [SHF_ALLOC]
+- Name: .data
+ Type: SHT_PROGBITS
+ Content: "000000000100008001000080"
+ AddressAlign: 16
+ Flags: [SHF_ALLOC, SHF_WRITE]
+
+- Name: .rel.data
+ Type: SHT_REL
+ Info: .data
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x4
+ Symbol: data2
+ Type: R_MIPS_PC32
+ - Offset: 0x8
+ Symbol: data1
+ Type: R_MIPS_PC32
+
+Symbols:
+ Global:
+ - Name: __start
+ Section: .text
+ Value: 0x0
+ Size: 4
+ - Name: data1
+ Section: .data
+ Value: 0x4
+ Size: 4
+ - Name: data2
+ Section: .data
+ Value: 0x8
+ Size: 4
diff --git a/test/elf/Mips/rel-pc7-10-16-23.test b/test/elf/Mips/rel-pc7-10-16-23.test
new file mode 100644
index 000000000000..c38b9eed2a5e
--- /dev/null
+++ b/test/elf/Mips/rel-pc7-10-16-23.test
@@ -0,0 +1,86 @@
+# Check handling of R_MICROMIPS_PC7_S1, R_MICROMIPS_PC10_S1,
+# R_MICROMIPS_PC16_S1, and R_MICROMIPS_PC23_S2 relocations.
+
+# RUN: yaml2obj -format=elf %s > %t-obj
+# RUN: lld -flavor gnu -target mipsel -o %t-exe %t-obj
+# RUN: llvm-objdump -s -t %t-exe | FileCheck %s
+
+# CHECK: Contents of section .text:
+# CHECK-NEXT: 400110 00000000 80780500 a240fcff 000c03cc .....x...@......
+# ^^ addiu s1,$pc,20
+# ^^ bnezc v0,400114 <__start+0x4>
+# ^^ b 400126 <L1>
+# CHECK-NEXT: 400120 000c03ad 00000000 00000000 00000000 ................
+# ^^ bnez v0,40012a <L2>
+# CHECK: SYMBOL TABLE:
+# CHECK: 00400124 l F .text 00000002 L0
+# CHECK: 00400126 l F .text 00000004 L1
+# CHECK: 0040012a l F .text 00000004 L2
+# CHECK: 0040012e l F .text 00000002 L3
+# CHECK: 00400110 g F .text 00000014 __start
+
+!ELF
+FileHeader: !FileHeader
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_CPIC, EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2,
+ EF_MIPS_MICROMIPS ]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+# v nop v nop v L0
+ Content: "0000000080780100a240f5ff000cfdcf000c7dad000000000000000000000000"
+# ^ PC23 ^ PC16 ^ PC10 ^ PC7 ^ L1 ^ L2 ^ L3
+# 7d << 1 = -6 => L3 + 2 - 6 = L2
+# 3fd << 1 = -6 => L2 + 2 - 6 = L1
+# fff5 << 1 = -22 => L1 + 2 - 22 = __start
+# 1 << 2 = 4 => L0 + 4 - 4 = L0
+ AddressAlign: 16
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+
+- Name: .rel.text
+ Type: SHT_REL
+ Info: .text
+ AddressAlign: 4
+ Relocations:
+ - Offset: 4
+ Symbol: L0
+ Type: R_MICROMIPS_PC23_S2
+ - Offset: 8
+ Symbol: L1
+ Type: R_MICROMIPS_PC16_S1
+ - Offset: 14
+ Symbol: L2
+ Type: R_MICROMIPS_PC10_S1
+ - Offset: 18
+ Symbol: L3
+ Type: R_MICROMIPS_PC7_S1
+
+Symbols:
+ Local:
+ - Name: L0
+ Section: .text
+ Value: 20
+ Other: [ STO_MIPS_MICROMIPS ]
+ - Name: L1
+ Section: .text
+ Value: 22
+ Other: [ STO_MIPS_MICROMIPS ]
+ - Name: L2
+ Section: .text
+ Value: 26
+ Other: [ STO_MIPS_MICROMIPS ]
+ - Name: L3
+ Section: .text
+ Value: 30
+ Other: [ STO_MIPS_MICROMIPS ]
+ Global:
+ - Name: __start
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x0
+ Size: 32
+ Other: [ STO_MIPS_MICROMIPS ]
diff --git a/test/elf/Mips/rel-sub.test b/test/elf/Mips/rel-sub.test
new file mode 100644
index 000000000000..93e569a22035
--- /dev/null
+++ b/test/elf/Mips/rel-sub.test
@@ -0,0 +1,61 @@
+# Check handling of R_MIPS_SUB relocation.
+
+# RUN: yaml2obj -format=elf %s > %t.o
+# RUN: lld -flavor gnu -target mips64el -o %t.exe %t.o
+# RUN: llvm-objdump -s -t %t.exe | FileCheck %s
+
+# CHECK: Contents of section .data:
+# CHECK-NEXT: 120002000 cf010020 01000000 d0010020 0100ffff ... ....... ....
+# ^^ __start - 1 = 0x1200001cf
+# ^^ __start - 0x1000000000000
+# = 0Xffff0001200001d0
+# CHECK: SYMBOL TABLE:
+# CHECK: 00000001200001d0 g .rodata 00000008 __start
+
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ARCH_64]
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Size: 0x08
+ AddressAlign: 16
+ Flags: [SHF_ALLOC]
+- Name: .data
+ Type: SHT_PROGBITS
+ Size: 0x10
+ AddressAlign: 16
+ Flags: [SHF_ALLOC, SHF_WRITE]
+
+- Name: .rela.data
+ Type: SHT_RELA
+ Info: .data
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0x0
+ Symbol: __start
+ Type: R_MIPS_SUB
+ Addend: 1
+ - Offset: 0x8
+ Symbol: __start
+ Type: R_MIPS_SUB
+ Addend: 0x1000000000000
+
+Symbols:
+ Global:
+ - Name: __start
+ Section: .text
+ Value: 0x0
+ Size: 8
+ - Name: data1
+ Section: .data
+ Value: 0x0
+ Size: 8
+ - Name: data2
+ Section: .data
+ Value: 0x8
+ Size: 8
diff --git a/test/elf/Mips/st-other.test b/test/elf/Mips/st-other.test
new file mode 100644
index 000000000000..8d15e75676b0
--- /dev/null
+++ b/test/elf/Mips/st-other.test
@@ -0,0 +1,90 @@
+# Check STO_MICROMIPS flag handling. microMIPS symbol records in a dynamic
+# symbol table should not have STO_MICROMIPS flag but their value field
+# must be odd. microMIPS symbol records in a regular symbol table should
+# have the STO_MICROMIPS flag.
+
+# RUN: yaml2obj -format=elf %s > %t-micro.o
+
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t-micro.o
+# RUN: llvm-readobj -dyn-symbols %t.so | FileCheck -check-prefix=SO %s
+
+# RUN: lld -flavor gnu -target mipsel -e S0 -o %t.exe %t-micro.o
+# RUN: llvm-readobj -symbols %t.exe | FileCheck -check-prefix=EXE-SYM %s
+# RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck -check-prefix=EXE-DSYM %s
+
+# SO: Symbol {
+# SO: Name: S0@ (1)
+# SO-NEXT: Value: 0xEC
+# SO-NEXT: Size: 4
+# SO-NEXT: Binding: Global (0x1)
+# SO-NEXT: Type: Function (0x2)
+# SO-NEXT: Other: 0
+# SO-NEXT: Section: .text (0x4)
+# SO-NEXT: }
+
+# SO: Symbol {
+# SO: Name: S1@ (4)
+# SO-NEXT: Value: 0xF1
+# SO-NEXT: Size: 4
+# SO-NEXT: Binding: Global (0x1)
+# SO-NEXT: Type: Function (0x2)
+# SO-NEXT: Other: 0
+# SO-NEXT: Section: .text (0x4)
+# SO-NEXT: }
+
+# EXE-SYM: Symbol {
+# EXE-SYM: Name: S0 (1)
+# EXE-SYM-NEXT: Value: 0x400108
+# EXE-SYM-NEXT: Size: 4
+# EXE-SYM-NEXT: Binding: Global (0x1)
+# EXE-SYM-NEXT: Type: Function (0x2)
+# EXE-SYM-NEXT: Other: 0
+# EXE-SYM-NEXT: Section: .text (0x5)
+# EXE-SYM-NEXT: }
+
+# EXE-SYM: Symbol {
+# EXE-SYM: Name: S1 (4)
+# EXE-SYM-NEXT: Value: 0x40010D
+# EXE-SYM-NEXT: Size: 4
+# EXE-SYM-NEXT: Binding: Global (0x1)
+# EXE-SYM-NEXT: Type: Function (0x2)
+# EXE-SYM-NEXT: Other: 128
+# EXE-SYM-NEXT: Section: .text (0x5)
+# EXE-SYM-NEXT: }
+
+# EXE-DSYM-NOT: Name: S1 (4)
+
+# micro.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2, EF_MIPS_MICROMIPS]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x08
+
+Symbols:
+ Global:
+ - Name: S0
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x04
+ Value: 0x00
+ Visibility: STV_DEFAULT
+ Other: [ ]
+
+ - Name: S1
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x04
+ Value: 0x04
+ Visibility: STV_DEFAULT
+ Other: [ STO_MIPS_MICROMIPS ]
+...
diff --git a/test/elf/Mips/tls-1-micro.test b/test/elf/Mips/tls-1-micro.test
new file mode 100644
index 000000000000..bd962b4e9e80
--- /dev/null
+++ b/test/elf/Mips/tls-1-micro.test
@@ -0,0 +1,65 @@
+# Check handling of R_MICROMIPS_TLS_TPREL_HI16 / R_MICROMIPS_TLS_TPREL_LO16
+# relocations.
+
+# RUN: yaml2obj -format=elf -o %t.o %s
+# RUN: lld -flavor gnu -target mipsel -e L0 -o %t.exe %t.o
+# RUN: llvm-objdump -s %t.exe | FileCheck %s
+
+# CHECK: Contents of section .text:
+# CHECK: 400150 00000000 00000100 00000380 00000480 ................
+
+!ELF
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_NOREORDER, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2, EF_MIPS_MICROMIPS ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x10
+ Content: '00000100000002000000030000000400'
+ - Name: .rel.text
+ Type: SHT_REL
+ Info: .text
+ AddressAlign: 0x04
+ Relocations:
+ - Offset: 0x00
+ Symbol: L1
+ Type: R_MICROMIPS_TLS_TPREL_HI16
+ - Offset: 0x04
+ Symbol: L2
+ Type: R_MICROMIPS_TLS_TPREL_HI16
+ - Offset: 0x08
+ Symbol: L2
+ Type: R_MICROMIPS_TLS_TPREL_LO16
+ - Offset: 0x0C
+ Symbol: L1
+ Type: R_MICROMIPS_TLS_TPREL_LO16
+ - Name: .tdata
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC, SHF_TLS ]
+ AddressAlign: 0x04
+ Address: 0x1000
+ Size: 0x20000
+
+Symbols:
+ Global:
+ - Name: L0
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x58
+ Other: [ STO_MIPS_MICROMIPS ]
+ - Name: L1
+ Type: STT_TLS
+ Section: .tdata
+ Value: 0x00
+ Size: 0x04
+ - Name: L2
+ Type: STT_TLS
+ Section: .tdata
+ Value: 0x10000
+ Size: 0x04
diff --git a/test/elf/Mips/tls-1.test b/test/elf/Mips/tls-1.test
new file mode 100644
index 000000000000..99176e69171d
--- /dev/null
+++ b/test/elf/Mips/tls-1.test
@@ -0,0 +1,63 @@
+# Check handling of R_MIPS_TLS_TPREL_HI16 / R_MIPS_TLS_TPREL_LO16 relocations.
+
+# RUN: yaml2obj -format=elf -o %t.o %s
+# RUN: lld -flavor gnu -target mipsel -e L0 -o %t.exe %t.o
+# RUN: llvm-objdump -s %t.exe | FileCheck %s
+
+# CHECK: Contents of section .text:
+# CHECK: 400150 00000000 01000000 03800000 04800000 ................
+
+!ELF
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_NOREORDER, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x10
+ Content: '01000000020000000300000004000000'
+ - Name: .rel.text
+ Type: SHT_REL
+ Info: .text
+ AddressAlign: 0x04
+ Relocations:
+ - Offset: 0x00
+ Symbol: L1
+ Type: R_MIPS_TLS_TPREL_HI16
+ - Offset: 0x04
+ Symbol: L2
+ Type: R_MIPS_TLS_TPREL_HI16
+ - Offset: 0x08
+ Symbol: L2
+ Type: R_MIPS_TLS_TPREL_LO16
+ - Offset: 0x0C
+ Symbol: L1
+ Type: R_MIPS_TLS_TPREL_LO16
+ - Name: .tdata
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC, SHF_TLS ]
+ AddressAlign: 0x04
+ Address: 0x1000
+ Size: 0x20000
+
+Symbols:
+ Global:
+ - Name: L0
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x58
+ - Name: L1
+ Type: STT_TLS
+ Section: .tdata
+ Value: 0x00
+ Size: 0x04
+ - Name: L2
+ Type: STT_TLS
+ Section: .tdata
+ Value: 0x10000
+ Size: 0x04
diff --git a/test/elf/Mips/tls-2-64.test b/test/elf/Mips/tls-2-64.test
new file mode 100644
index 000000000000..a068934aeafa
--- /dev/null
+++ b/test/elf/Mips/tls-2-64.test
@@ -0,0 +1,69 @@
+# Check handling of R_MIPS_TLS_GOTTPREL and R_MIPS_TLS_GD relocations
+# and generation of corresponding dynamic relocations R_MIPS_TLS_TPREL64,
+# R_MIPS_TLS_DTPMOD64 and R_MIPS_TLS_DTPREL64 in case of shared library.
+
+# Create a shared library with thread symbol D1.
+# RUN: yaml2obj -format=elf -o %t-so.o %s
+# RUN: lld -flavor gnu -target mips64el -shared -o %t.so %t-so.o
+
+# Check dynamic relocations and GOT in the shared library.
+# RUN: llvm-readobj -r %t.so | FileCheck -check-prefix=REL %s
+# RUN: llvm-readobj -dynamic-table %t.so | FileCheck -check-prefix=DYN %s
+# RUN: llvm-readobj -dt %t.so | FileCheck -check-prefix=SYM %s
+# RUN: llvm-objdump -s %t.so | FileCheck -check-prefix=GOT %s
+
+# REL: Section (4) .rel.dyn {
+# REL-NEXT: 0x2010 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE D1 0x0
+# REL-NEXT: 0x2018 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE D1 0x0
+# REL-NEXT: }
+
+# DYN: 0x000000007000000A MIPS_LOCAL_GOTNO 2
+# DYN: 0x0000000070000013 MIPS_GOTSYM 0x3
+
+# SYM: Name: T1@ (1)
+# SYM: Name: D1@ (4)
+
+# GOT: Contents of section .got:
+# GOT-NEXT: 2000 00000000 00000000 00000000 00000080 ................
+# GOT-NEXT: 2010 00000000 00000000 00000000 00000000 ................
+
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ARCH_64]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 4
+ Size: 4
+ - Name: .rel.text
+ Type: SHT_RELA
+ Link: .symtab
+ Info: .text
+ AddressAlign: 4
+ Relocations:
+ - Offset: 0
+ Symbol: D1
+ Type: R_MIPS_TLS_GD
+ - Name: .tdata
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC, SHF_TLS ]
+ AddressAlign: 4
+ Size: 8
+
+Symbols:
+ Global:
+ - Name: T1
+ Type: STT_FUNC
+ Section: .text
+ Size: 4
+ - Name: D1
+ Type: STT_TLS
+ Section: .tdata
+ Size: 8
+...
diff --git a/test/elf/Mips/tls-2-micro.test b/test/elf/Mips/tls-2-micro.test
new file mode 100644
index 000000000000..5a1fe2904ac9
--- /dev/null
+++ b/test/elf/Mips/tls-2-micro.test
@@ -0,0 +1,70 @@
+# Check handling of R_MICROMIPS_TLS_GOTTPREL and R_MICROMIPS_TLS_GD relocations
+# and generation of corresponding dynamic relocations R_MIPS_TLS_TPREL32,
+# R_MIPS_TLS_DTPMOD32 and R_MIPS_TLS_DTPREL32 in case of shared library.
+
+# Create a shared library with thread symbol D1.
+# RUN: yaml2obj -format=elf -o %t-so.o %s
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t-so.o
+
+# Check dynamic relocations and GOT in the shared library.
+# RUN: llvm-readobj -r %t.so | FileCheck -check-prefix=REL %s
+# RUN: llvm-readobj -dynamic-table %t.so | FileCheck -check-prefix=DYN %s
+# RUN: llvm-readobj -dt %t.so | FileCheck -check-prefix=SYM %s
+# RUN: llvm-objdump -s %t.so | FileCheck -check-prefix=GOT %s
+
+# REL: Section (4) .rel.dyn {
+# REL-NEXT: 0x2008 R_MIPS_TLS_DTPMOD32 D1 0x0
+# REL-NEXT: 0x200C R_MIPS_TLS_DTPREL32 D1 0x0
+# REL-NEXT: }
+
+# DYN: 0x7000000A MIPS_LOCAL_GOTNO 2
+# DYN: 0x70000013 MIPS_GOTSYM 0x3
+
+# SYM: Name: T1@ (1)
+# SYM: Name: D1@ (4)
+
+# GOT: Contents of section .got:
+# GOT-NEXT: 2000 00000000 00000080 00000000 00000000 ................
+
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2, EF_MIPS_MICROMIPS ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x04
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ Info: .text
+ AddressAlign: 0x04
+ Relocations:
+ - Offset: 0x00
+ Symbol: D1
+ Type: R_MICROMIPS_TLS_GD
+ - Name: .tdata
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC, SHF_TLS ]
+ AddressAlign: 0x04
+ Size: 0x04
+
+Symbols:
+ Global:
+ - Name: T1
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x04
+ Other: [ STO_MIPS_MICROMIPS ]
+ - Name: D1
+ Type: STT_TLS
+ Section: .tdata
+ Size: 0x04
+...
diff --git a/test/elf/Mips/tls-2.test b/test/elf/Mips/tls-2.test
new file mode 100644
index 000000000000..32b2bc105112
--- /dev/null
+++ b/test/elf/Mips/tls-2.test
@@ -0,0 +1,69 @@
+# Check handling of R_MIPS_TLS_GOTTPREL and R_MIPS_TLS_GD relocations
+# and generation of corresponding dynamic relocations R_MIPS_TLS_TPREL32,
+# R_MIPS_TLS_DTPMOD32 and R_MIPS_TLS_DTPREL32 in case of shared library.
+
+# Create a shared library with thread symbol D1.
+# RUN: yaml2obj -format=elf -o %t-so.o %s
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t-so.o
+
+# Check dynamic relocations and GOT in the shared library.
+# RUN: llvm-readobj -r %t.so | FileCheck -check-prefix=REL %s
+# RUN: llvm-readobj -dynamic-table %t.so | FileCheck -check-prefix=DYN %s
+# RUN: llvm-readobj -dt %t.so | FileCheck -check-prefix=SYM %s
+# RUN: llvm-objdump -s %t.so | FileCheck -check-prefix=GOT %s
+
+# REL: Section (4) .rel.dyn {
+# REL-NEXT: 0x2008 R_MIPS_TLS_DTPMOD32 D1 0x0
+# REL-NEXT: 0x200C R_MIPS_TLS_DTPREL32 D1 0x0
+# REL-NEXT: }
+
+# DYN: 0x7000000A MIPS_LOCAL_GOTNO 2
+# DYN: 0x70000013 MIPS_GOTSYM 0x3
+
+# SYM: Name: T1@ (1)
+# SYM: Name: D1@ (4)
+
+# GOT: Contents of section .got:
+# GOT-NEXT: 2000 00000000 00000080 00000000 00000000 ................
+
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x04
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ Info: .text
+ AddressAlign: 0x04
+ Relocations:
+ - Offset: 0x00
+ Symbol: D1
+ Type: R_MIPS_TLS_GD
+ - Name: .tdata
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC, SHF_TLS ]
+ AddressAlign: 0x04
+ Size: 0x04
+
+Symbols:
+ Global:
+ - Name: T1
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x04
+ - Name: D1
+ Type: STT_TLS
+ Section: .tdata
+ Size: 0x04
+...
diff --git a/test/elf/Mips/tls-3-micro.test b/test/elf/Mips/tls-3-micro.test
new file mode 100644
index 000000000000..0e0f3d556f8f
--- /dev/null
+++ b/test/elf/Mips/tls-3-micro.test
@@ -0,0 +1,183 @@
+# Check handling of R_MICROMIPS_TLS_GOTTPREL and R_MICROMIPS_TLS_GD relocations
+# and generation of corresponding dynamic relocations R_MIPS_TLS_TPREL32,
+# R_MIPS_TLS_DTPMOD32 and R_MIPS_TLS_DTPREL32 in case of executable linking.
+
+# Create a shared library with thread symbol D1.
+# RUN: yaml2obj -format=elf -docnum 1 -o %t-so.o %s
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t-so.o
+
+# Create executable file linked using two object files and the shared library.
+# The object files defines thread symbols D0 and D2.
+# RUN: yaml2obj -format=elf -docnum 2 -o %t-o1.o %s
+# RUN: yaml2obj -format=elf -docnum 3 -o %t-o2.o %s
+# RUN: lld -flavor gnu -target mipsel -e T0 -o %t.exe %t-o1.o %t-o2.o %t.so
+
+# Check dynamic relocations and GOT in the executable file.
+# RUN: llvm-readobj -r %t.exe | FileCheck -check-prefix=REL %s
+# RUN: llvm-readobj -dynamic-table %t.exe | FileCheck -check-prefix=DYN %s
+# RUN: llvm-readobj -dt %t.exe | FileCheck -check-prefix=SYM %s
+# RUN: llvm-objdump -s %t.exe | FileCheck -check-prefix=GOT %s
+
+# REL: Section (5) .rel.dyn {
+# REL-NEXT: 0x402008 R_MIPS_TLS_TPREL32 D1 0x0
+# REL-NEXT: 0x40200C R_MIPS_TLS_TPREL32 D2 0x0
+# REL-NEXT: }
+
+# DYN: 0x7000000A MIPS_LOCAL_GOTNO 2
+# DYN: 0x70000013 MIPS_GOTSYM 0x3
+
+# SYM: Name: D2@ (1)
+# SYM: Name: D1@ (4)
+
+# GOT: Contents of section .got:
+# GOT-NEXT: 402000 00000000 00000080 00000000 00000000 ................
+
+# so.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2, EF_MIPS_MICROMIPS ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x04
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ Info: .text
+ AddressAlign: 0x04
+ Relocations:
+ - Offset: 0x00
+ Symbol: D1
+ Type: R_MICROMIPS_TLS_GD
+ - Name: .tdata
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC, SHF_TLS ]
+ AddressAlign: 0x04
+ Size: 0x04
+
+Symbols:
+ Global:
+ - Name: T1
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x04
+ Other: [ STO_MIPS_MICROMIPS ]
+ - Name: D1
+ Type: STT_TLS
+ Section: .tdata
+ Size: 0x04
+
+# o1.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_NOREORDER, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2, EF_MIPS_MICROMIPS ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x08
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ Info: .text
+ AddressAlign: 0x04
+ Relocations:
+ - Offset: 0x00
+ Symbol: D2
+ Type: R_MICROMIPS_TLS_TPREL_HI16
+ - Offset: 0x04
+ Symbol: D2
+ Type: R_MICROMIPS_TLS_TPREL_LO16
+ - Name: .tdata
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC, SHF_TLS ]
+ AddressAlign: 0x04
+ Size: 0x04
+
+Symbols:
+ Global:
+ - Name: T2
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x08
+ Other: [ STO_MIPS_MICROMIPS ]
+ - Name: D2
+ Type: STT_TLS
+ Section: .tdata
+ Size: 0x04
+
+# o2.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_NOREORDER, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2, EF_MIPS_MICROMIPS ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x10
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ Info: .text
+ AddressAlign: 0x04
+ Relocations:
+ - Offset: 0x00
+ Symbol: D1
+ Type: R_MICROMIPS_TLS_GOTTPREL
+ Addend: 0
+ - Offset: 0x04
+ Symbol: D0
+ Type: R_MICROMIPS_TLS_TPREL_HI16
+ Addend: 0
+ - Offset: 0x08
+ Symbol: D0
+ Type: R_MICROMIPS_TLS_TPREL_LO16
+ Addend: 0
+ - Offset: 0x0C
+ Symbol: D2
+ Type: R_MICROMIPS_TLS_GOTTPREL
+ Addend: 0
+ - Name: .tdata
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC, SHF_TLS ]
+ AddressAlign: 0x04
+ Size: 0x04
+
+Symbols:
+ Global:
+ - Name: D0
+ Type: STT_TLS
+ Section: .tdata
+ Size: 0x04
+ - Name: T0
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x10
+ Other: [ STO_MIPS_MICROMIPS ]
+ - Name: D1
+ Type: STT_TLS
+ - Name: D2
+ Type: STT_TLS
+...
diff --git a/test/elf/Mips/tls-3.test b/test/elf/Mips/tls-3.test
new file mode 100644
index 000000000000..7e54724fade5
--- /dev/null
+++ b/test/elf/Mips/tls-3.test
@@ -0,0 +1,180 @@
+# Check handling of R_MIPS_TLS_GOTTPREL and R_MIPS_TLS_GD relocations
+# and generation of corresponding dynamic relocations R_MIPS_TLS_TPREL32,
+# R_MIPS_TLS_DTPMOD32 and R_MIPS_TLS_DTPREL32 in case of executable linking.
+
+# Create a shared library with thread symbol D1.
+# RUN: yaml2obj -format=elf -docnum 1 -o %t-so.o %s
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t-so.o
+
+# Create executable file linked using two object files and the shared library.
+# The object files defines thread symbols D0 and D2.
+# RUN: yaml2obj -format=elf -docnum 2 -o %t-o1.o %s
+# RUN: yaml2obj -format=elf -docnum 3 -o %t-o2.o %s
+# RUN: lld -flavor gnu -target mipsel -e T0 -o %t.exe %t-o1.o %t-o2.o %t.so
+
+# Check dynamic relocations and GOT in the executable file.
+# RUN: llvm-readobj -r %t.exe | FileCheck -check-prefix=REL %s
+# RUN: llvm-readobj -dynamic-table %t.exe | FileCheck -check-prefix=DYN %s
+# RUN: llvm-readobj -dt %t.exe | FileCheck -check-prefix=SYM %s
+# RUN: llvm-objdump -s %t.exe | FileCheck -check-prefix=GOT %s
+
+# REL: Section (5) .rel.dyn {
+# REL-NEXT: 0x402008 R_MIPS_TLS_TPREL32 D1 0x0
+# REL-NEXT: 0x40200C R_MIPS_TLS_TPREL32 D2 0x0
+# REL-NEXT: }
+
+# DYN: 0x7000000A MIPS_LOCAL_GOTNO 2
+# DYN: 0x70000013 MIPS_GOTSYM 0x3
+
+# SYM: Name: D2@ (1)
+# SYM: Name: D1@ (4)
+
+# GOT: Contents of section .got:
+# GOT-NEXT: 402000 00000000 00000080 00000000 00000000 ................
+
+# so.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x04
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ Info: .text
+ AddressAlign: 0x04
+ Relocations:
+ - Offset: 0x00
+ Symbol: D1
+ Type: R_MIPS_TLS_GD
+ - Name: .tdata
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC, SHF_TLS ]
+ AddressAlign: 0x04
+ Size: 0x04
+
+Symbols:
+ Global:
+ - Name: T1
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x04
+ - Name: D1
+ Type: STT_TLS
+ Section: .tdata
+ Size: 0x04
+
+# o1.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_NOREORDER, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x08
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ Info: .text
+ AddressAlign: 0x04
+ Relocations:
+ - Offset: 0x00
+ Symbol: D2
+ Type: R_MIPS_TLS_TPREL_HI16
+ - Offset: 0x04
+ Symbol: D2
+ Type: R_MIPS_TLS_TPREL_LO16
+ - Name: .tdata
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC, SHF_TLS ]
+ AddressAlign: 0x04
+ Size: 0x04
+
+Symbols:
+ Global:
+ - Name: T2
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x08
+ - Name: D2
+ Type: STT_TLS
+ Section: .tdata
+ Size: 0x04
+
+# o2.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_NOREORDER, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x10
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ Info: .text
+ AddressAlign: 0x04
+ Relocations:
+ - Offset: 0x00
+ Symbol: D1
+ Type: R_MIPS_TLS_GOTTPREL
+ Addend: 0
+ - Offset: 0x04
+ Symbol: D0
+ Type: R_MIPS_TLS_TPREL_HI16
+ Addend: 0
+ - Offset: 0x08
+ Symbol: D0
+ Type: R_MIPS_TLS_TPREL_LO16
+ Addend: 0
+ - Offset: 0x0C
+ Symbol: D2
+ Type: R_MIPS_TLS_GOTTPREL
+ Addend: 0
+ - Name: .tdata
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC, SHF_TLS ]
+ AddressAlign: 0x04
+ Size: 0x04
+
+Symbols:
+ Global:
+ - Name: D0
+ Type: STT_TLS
+ Section: .tdata
+ Size: 0x04
+ - Name: T0
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x10
+ - Name: D1
+ Type: STT_TLS
+ - Name: D2
+ Type: STT_TLS
+...
diff --git a/test/elf/Mips/tls-4-micro.test b/test/elf/Mips/tls-4-micro.test
new file mode 100644
index 000000000000..1b0d03fa8875
--- /dev/null
+++ b/test/elf/Mips/tls-4-micro.test
@@ -0,0 +1,126 @@
+# Check handling of R_MICROMIPS_TLS_LDM relocation and generation
+# of corresponding dynamic relocation R_MICROMIPS_TLS_DTPMOD32.
+
+# RUN: yaml2obj -format=elf -docnum 1 -o %t-so1.o %s
+# RUN: yaml2obj -format=elf -docnum 2 -o %t-so2.o %s
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t-so1.o %t-so2.o
+
+# RUN: llvm-readobj -r %t.so | FileCheck -check-prefix=REL %s
+# RUN: llvm-readobj -dynamic-table %t.so | FileCheck -check-prefix=DYN %s
+# RUN: llvm-readobj -dt %t.so | FileCheck -check-prefix=SYM %s
+# RUN: llvm-objdump -s %t.so | FileCheck -check-prefix=GOT %s
+
+# REL: Section (4) .rel.dyn {
+# REL-NEXT: 0x2008 R_MIPS_TLS_DTPMOD32 - 0x0
+# REL-NEXT: }
+
+# DYN: 0x7000000A MIPS_LOCAL_GOTNO 2
+# DYN: 0x70000013 MIPS_GOTSYM 0x4
+
+# SYM: Name: @ (0)
+# SYM: Name: T1@ (1)
+# SYM: Name: T2@ (4)
+# SYM: Name: T3@ (7)
+
+# GOT: Contents of section .got:
+# GOT-NEXT: 2000 00000000 00000080 00000000 00000000 ................
+# Two LDM entries --^--------^
+
+# so1.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2, EF_MIPS_MICROMIPS ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x08
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x04
+ Info: .text
+ Relocations:
+ - Offset: 0x00
+ Symbol: L01
+ Type: R_MICROMIPS_TLS_LDM
+ - Offset: 0x04
+ Symbol: L01
+ Type: R_MICROMIPS_TLS_LDM
+ - Name: .tdata
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC, SHF_TLS ]
+ AddressAlign: 0x04
+ Size: 0x04
+
+Symbols:
+ Local:
+ - Name: L01
+ Type: STT_TLS
+ Section: .tdata
+ Size: 0x04
+ Global:
+ - Name: T1
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x00
+ Size: 0x04
+ Other: [ STO_MIPS_MICROMIPS ]
+ - Name: T2
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x04
+ Size: 0x04
+ Other: [ STO_MIPS_MICROMIPS ]
+
+# so2.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2, EF_MIPS_MICROMIPS ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x04
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x04
+ Info: .text
+ Relocations:
+ - Offset: 0x00
+ Symbol: L02
+ Type: R_MICROMIPS_TLS_LDM
+ - Name: .tdata
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC, SHF_TLS ]
+ AddressAlign: 0x04
+ Size: 0x04
+
+Symbols:
+ Local:
+ - Name: L02
+ Type: STT_TLS
+ Section: .tdata
+ Size: 0x04
+ Global:
+ - Name: T3
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x04
+ Other: [ STO_MIPS_MICROMIPS ]
+...
diff --git a/test/elf/Mips/tls-4.test b/test/elf/Mips/tls-4.test
new file mode 100644
index 000000000000..fb42f0d93378
--- /dev/null
+++ b/test/elf/Mips/tls-4.test
@@ -0,0 +1,123 @@
+# Check handling of R_MIPS_TLS_LDM relocation and generation of corresponding
+# dynamic relocation R_MIPS_TLS_DTPMOD32.
+
+# RUN: yaml2obj -format=elf -docnum 1 -o %t-so1.o %s
+# RUN: yaml2obj -format=elf -docnum 2 -o %t-so2.o %s
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t-so1.o %t-so2.o
+
+# RUN: llvm-readobj -r %t.so | FileCheck -check-prefix=REL %s
+# RUN: llvm-readobj -dynamic-table %t.so | FileCheck -check-prefix=DYN %s
+# RUN: llvm-readobj -dt %t.so | FileCheck -check-prefix=SYM %s
+# RUN: llvm-objdump -s %t.so | FileCheck -check-prefix=GOT %s
+
+# REL: Section (4) .rel.dyn {
+# REL-NEXT: 0x2008 R_MIPS_TLS_DTPMOD32 - 0x0
+# REL-NEXT: }
+
+# DYN: 0x7000000A MIPS_LOCAL_GOTNO 2
+# DYN: 0x70000013 MIPS_GOTSYM 0x4
+
+# SYM: Name: @ (0)
+# SYM: Name: T1@ (1)
+# SYM: Name: T2@ (4)
+# SYM: Name: T3@ (7)
+
+# GOT: Contents of section .got:
+# GOT-NEXT: 2000 00000000 00000080 00000000 00000000 ................
+# Two LDM entries --^--------^
+
+# so1.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x08
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x04
+ Info: .text
+ Relocations:
+ - Offset: 0x00
+ Symbol: L01
+ Type: R_MIPS_TLS_LDM
+ - Offset: 0x04
+ Symbol: L01
+ Type: R_MIPS_TLS_LDM
+ - Name: .tdata
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC, SHF_TLS ]
+ AddressAlign: 0x04
+ Size: 0x04
+
+Symbols:
+ Local:
+ - Name: L01
+ Type: STT_TLS
+ Section: .tdata
+ Size: 0x04
+ Global:
+ - Name: T1
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x00
+ Size: 0x04
+ - Name: T2
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x04
+ Size: 0x04
+
+# so2.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x04
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x04
+ Info: .text
+ Relocations:
+ - Offset: 0x00
+ Symbol: L02
+ Type: R_MIPS_TLS_LDM
+ - Name: .tdata
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC, SHF_TLS ]
+ AddressAlign: 0x04
+ Size: 0x04
+
+Symbols:
+ Local:
+ - Name: L02
+ Type: STT_TLS
+ Section: .tdata
+ Size: 0x04
+ Global:
+ - Name: T3
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x04
+...
diff --git a/test/elf/Mips/tls-5-64.test b/test/elf/Mips/tls-5-64.test
new file mode 100644
index 000000000000..784d71efc48f
--- /dev/null
+++ b/test/elf/Mips/tls-5-64.test
@@ -0,0 +1,71 @@
+# Check that in case of an executable file linking symbol referred
+# by the R_MIPS_TLS_GD relocation gets an entry in the dynamic symbol table.
+
+# RUN: yaml2obj -format=elf -o %t-o.o %s
+# RUN: lld -flavor gnu -target mips64el -e T0 -o %t.exe %t-o.o
+
+# Check dynamic relocations:
+# RUN: llvm-readobj -r %t.exe | FileCheck -check-prefix=REL %s
+# Check dynamic symbol table:
+# RUN: llvm-readobj -dt %t.exe | FileCheck -check-prefix=SYM %s
+
+# REL: Relocations [
+# REL-NEXT: Section (5) .rel.dyn {
+# REL-NEXT: 0x120002010 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE T1 0x0
+# REL-NEXT: 0x120002018 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE T1 0x0
+# REL-NEXT: }
+# REL-NEXT: ]
+
+# SYM: Symbol {
+# SYM: Name: T1@ (1)
+# SYM-NEXT: Value: 0x0
+# SYM-NEXT: Size: 8
+# SYM-NEXT: Binding: Global (0x1)
+# SYM-NEXT: Type: TLS (0x6)
+# SYM-NEXT: Other: 0
+# SYM-NEXT: Section: .tdata (0x7)
+# SYM-NEXT: }
+
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC, EF_MIPS_ARCH_64]
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x10
+ Size: 8
+
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 4
+ Info: .text
+ Relocations:
+ - Offset: 0
+ Symbol: T1
+ Type: R_MIPS_TLS_GD
+
+ - Name: .tdata
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC, SHF_TLS ]
+ AddressAlign: 4
+ Size: 8
+
+Symbols:
+ Global:
+ - Name: T0
+ Type: STT_FUNC
+ Section: .text
+ Size: 8
+ - Name: T1
+ Type: STT_TLS
+ Section: .tdata
+ Value: 0
+ Size: 8
+...
diff --git a/test/elf/Mips/tls-5-micro.test b/test/elf/Mips/tls-5-micro.test
new file mode 100644
index 000000000000..89d1d98a6877
--- /dev/null
+++ b/test/elf/Mips/tls-5-micro.test
@@ -0,0 +1,70 @@
+# Check that in case of an executable file linking symbol referred by
+# the R_MICROMIPS_TLS_GD relocation gets an entry in the dynamic symbol table.
+
+# RUN: yaml2obj -format=elf -o %t-o.o %s
+# RUN: lld -flavor gnu -target mipsel -e T0 -o %t.exe %t-o.o
+
+# Check dynamic relocations:
+# RUN: llvm-readobj -r %t.exe | FileCheck -check-prefix=REL %s
+# Check dynamic symbol table:
+# RUN: llvm-readobj -dt %t.exe | FileCheck -check-prefix=SYM %s
+
+# REL: Relocations [
+# REL-NEXT: Section (5) .rel.dyn {
+# REL-NEXT: 0x402008 R_MIPS_TLS_DTPMOD32 T1 0x0
+# REL-NEXT: 0x40200C R_MIPS_TLS_DTPREL32 T1 0x0
+# REL-NEXT: }
+# REL-NEXT: ]
+
+# SYM: Symbol {
+# SYM: Name: T1@ (1)
+# SYM-NEXT: Value: 0x0
+# SYM-NEXT: Size: 4
+# SYM-NEXT: Binding: Global (0x1)
+# SYM-NEXT: Type: TLS (0x6)
+# SYM-NEXT: Other: 0
+# SYM-NEXT: Section: .tdata (0x7)
+# SYM-NEXT: }
+
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2, EF_MIPS_MICROMIPS ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x10
+ Size: 0x04
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x04
+ Info: .text
+ Relocations:
+ - Offset: 0x00
+ Symbol: T1
+ Type: R_MICROMIPS_TLS_GD
+ - Name: .tdata
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC, SHF_TLS ]
+ AddressAlign: 0x04
+ Size: 0x04
+
+Symbols:
+ Global:
+ - Name: T0
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x04
+ Other: [ STO_MIPS_MICROMIPS ]
+ - Name: T1
+ Type: STT_TLS
+ Section: .tdata
+ Value: 0x00
+ Size: 0x04
+...
diff --git a/test/elf/Mips/tls-5.test b/test/elf/Mips/tls-5.test
new file mode 100644
index 000000000000..378ce321b8c9
--- /dev/null
+++ b/test/elf/Mips/tls-5.test
@@ -0,0 +1,69 @@
+# Check that in case of an executable file linking symbol referred
+# by the R_MIPS_TLS_GD relocation gets an entry in the dynamic symbol table.
+
+# RUN: yaml2obj -format=elf -o %t-o.o %s
+# RUN: lld -flavor gnu -target mipsel -e T0 -o %t.exe %t-o.o
+
+# Check dynamic relocations:
+# RUN: llvm-readobj -r %t.exe | FileCheck -check-prefix=REL %s
+# Check dynamic symbol table:
+# RUN: llvm-readobj -dt %t.exe | FileCheck -check-prefix=SYM %s
+
+# REL: Relocations [
+# REL-NEXT: Section (5) .rel.dyn {
+# REL-NEXT: 0x402008 R_MIPS_TLS_DTPMOD32 T1 0x0
+# REL-NEXT: 0x40200C R_MIPS_TLS_DTPREL32 T1 0x0
+# REL-NEXT: }
+# REL-NEXT: ]
+
+# SYM: Symbol {
+# SYM: Name: T1@ (1)
+# SYM-NEXT: Value: 0x0
+# SYM-NEXT: Size: 4
+# SYM-NEXT: Binding: Global (0x1)
+# SYM-NEXT: Type: TLS (0x6)
+# SYM-NEXT: Other: 0
+# SYM-NEXT: Section: .tdata (0x7)
+# SYM-NEXT: }
+
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_MIPS
+ Flags: [ EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC,
+ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x10
+ Size: 0x04
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x04
+ Info: .text
+ Relocations:
+ - Offset: 0x00
+ Symbol: T1
+ Type: R_MIPS_TLS_GD
+ - Name: .tdata
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC, SHF_TLS ]
+ AddressAlign: 0x04
+ Size: 0x04
+
+Symbols:
+ Global:
+ - Name: T0
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x04
+ - Name: T1
+ Type: STT_TLS
+ Section: .tdata
+ Value: 0x00
+ Size: 0x04
+...
diff --git a/test/elf/X86_64/ExampleTarget/triple.test b/test/elf/X86_64/ExampleTarget/triple.test
new file mode 100644
index 000000000000..3aecceb4305e
--- /dev/null
+++ b/test/elf/X86_64/ExampleTarget/triple.test
@@ -0,0 +1,32 @@
+# Check that the Example Target is actually used.
+
+# RUN: yaml2obj -format=elf %s -o %t.o
+# RUN: lld -flavor gnu -target x86_64-example-freebsd9 %t.o -o %t.exe
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
+#
+# CHECK: Type: 0xFF00
+
+# object
+
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000010
+ Content: 554889E5B864000000C745FC000000005DC366666666662E0F1F840000000000554889E531C05DC3
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ Global:
+ - Name: _start
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x0000000000000000
diff --git a/test/elf/X86_64/Inputs/constint.c b/test/elf/X86_64/Inputs/constint.c
new file mode 100644
index 000000000000..9fc0ebcf6591
--- /dev/null
+++ b/test/elf/X86_64/Inputs/constint.c
@@ -0,0 +1 @@
+const int b = 20;
diff --git a/test/elf/X86_64/Inputs/constint.o b/test/elf/X86_64/Inputs/constint.o
new file mode 100644
index 000000000000..8324b73014d0
--- /dev/null
+++ b/test/elf/X86_64/Inputs/constint.o
Binary files differ
diff --git a/test/elf/X86_64/Inputs/debug0.c b/test/elf/X86_64/Inputs/debug0.c
new file mode 100644
index 000000000000..1ebe50087383
--- /dev/null
+++ b/test/elf/X86_64/Inputs/debug0.c
@@ -0,0 +1,5 @@
+int adena();
+
+int main() {
+return adena();
+}
diff --git a/test/elf/X86_64/Inputs/debug0.x86-64 b/test/elf/X86_64/Inputs/debug0.x86-64
new file mode 100644
index 000000000000..914f5224b9a2
--- /dev/null
+++ b/test/elf/X86_64/Inputs/debug0.x86-64
Binary files differ
diff --git a/test/elf/X86_64/Inputs/debug1.c b/test/elf/X86_64/Inputs/debug1.c
new file mode 100644
index 000000000000..281b8a361dbb
--- /dev/null
+++ b/test/elf/X86_64/Inputs/debug1.c
@@ -0,0 +1,3 @@
+int adena() {
+return 0;
+}
diff --git a/test/elf/X86_64/Inputs/debug1.x86-64 b/test/elf/X86_64/Inputs/debug1.x86-64
new file mode 100644
index 000000000000..bfc81458a034
--- /dev/null
+++ b/test/elf/X86_64/Inputs/debug1.x86-64
Binary files differ
diff --git a/test/elf/X86_64/Inputs/externtls.c b/test/elf/X86_64/Inputs/externtls.c
new file mode 100644
index 000000000000..499a645a9217
--- /dev/null
+++ b/test/elf/X86_64/Inputs/externtls.c
@@ -0,0 +1,6 @@
+extern __thread int extern_tls;
+
+int main() {
+ extern_tls = 1;
+ return 0;
+}
diff --git a/test/elf/X86_64/Inputs/externtls.x86-64 b/test/elf/X86_64/Inputs/externtls.x86-64
new file mode 100644
index 000000000000..3019aa0ca27c
--- /dev/null
+++ b/test/elf/X86_64/Inputs/externtls.x86-64
Binary files differ
diff --git a/test/elf/X86_64/Inputs/fn.c b/test/elf/X86_64/Inputs/fn.c
new file mode 100644
index 000000000000..54939a2426b2
--- /dev/null
+++ b/test/elf/X86_64/Inputs/fn.c
@@ -0,0 +1,4 @@
+int fn()
+{
+ return 0;
+}
diff --git a/test/elf/X86_64/Inputs/fn.o b/test/elf/X86_64/Inputs/fn.o
new file mode 100644
index 000000000000..4b67d459dfdb
--- /dev/null
+++ b/test/elf/X86_64/Inputs/fn.o
Binary files differ
diff --git a/test/elf/X86_64/Inputs/generaltls-so.o.yaml b/test/elf/X86_64/Inputs/generaltls-so.o.yaml
new file mode 100644
index 000000000000..f0649e7639a6
--- /dev/null
+++ b/test/elf/X86_64/Inputs/generaltls-so.o.yaml
@@ -0,0 +1,68 @@
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000010
+ Content: 554889E566488D3D00000000666648E8000000008B005DC3
+ - Name: .rela.text
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .text
+ Relocations:
+ - Offset: 0x0000000000000008
+ Symbol: mynumber
+ Type: R_X86_64_TLSGD
+ Addend: -4
+ - Offset: 0x0000000000000010
+ Symbol: __tls_get_addr
+ Type: R_X86_64_PLT32
+ Addend: -4
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .tdata
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC, SHF_TLS ]
+ AddressAlign: 0x0000000000000004
+ Content: '21000000'
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .tdata
+ Type: STT_SECTION
+ Section: .tdata
+ Global:
+ - Name: getnumber
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x0000000000000018
+ - Name: mynumber
+ Type: STT_TLS
+ Section: .tdata
+ Size: 0x0000000000000004
+ - Name: _GLOBAL_OFFSET_TABLE_
+ - Name: __tls_get_addr
+...
diff --git a/test/elf/X86_64/Inputs/group/1.c b/test/elf/X86_64/Inputs/group/1.c
new file mode 100644
index 000000000000..f5e618bc4a85
--- /dev/null
+++ b/test/elf/X86_64/Inputs/group/1.c
@@ -0,0 +1,8 @@
+int _start() {
+ return 0;
+}
+
+int main() {
+fn();
+return 0;
+}
diff --git a/test/elf/X86_64/Inputs/group/1.o b/test/elf/X86_64/Inputs/group/1.o
new file mode 100644
index 000000000000..743518eb0fa3
--- /dev/null
+++ b/test/elf/X86_64/Inputs/group/1.o
Binary files differ
diff --git a/test/elf/X86_64/Inputs/group/fn.c b/test/elf/X86_64/Inputs/group/fn.c
new file mode 100644
index 000000000000..e443c73a1ee0
--- /dev/null
+++ b/test/elf/X86_64/Inputs/group/fn.c
@@ -0,0 +1,4 @@
+int fn() {
+fn1();
+return 0;
+}
diff --git a/test/elf/X86_64/Inputs/group/fn.o b/test/elf/X86_64/Inputs/group/fn.o
new file mode 100644
index 000000000000..1134432449cd
--- /dev/null
+++ b/test/elf/X86_64/Inputs/group/fn.o
Binary files differ
diff --git a/test/elf/X86_64/Inputs/group/fn1.c b/test/elf/X86_64/Inputs/group/fn1.c
new file mode 100644
index 000000000000..cca0df7fd277
--- /dev/null
+++ b/test/elf/X86_64/Inputs/group/fn1.c
@@ -0,0 +1,3 @@
+int fn1() {
+fn2();
+}
diff --git a/test/elf/X86_64/Inputs/group/fn1.o b/test/elf/X86_64/Inputs/group/fn1.o
new file mode 100644
index 000000000000..2b02310003db
--- /dev/null
+++ b/test/elf/X86_64/Inputs/group/fn1.o
Binary files differ
diff --git a/test/elf/X86_64/Inputs/group/fn2.c b/test/elf/X86_64/Inputs/group/fn2.c
new file mode 100644
index 000000000000..a60370ed1e6b
--- /dev/null
+++ b/test/elf/X86_64/Inputs/group/fn2.c
@@ -0,0 +1,3 @@
+int fn2() {
+return 0;
+}
diff --git a/test/elf/X86_64/Inputs/group/fn2.o b/test/elf/X86_64/Inputs/group/fn2.o
new file mode 100644
index 000000000000..fabec849a775
--- /dev/null
+++ b/test/elf/X86_64/Inputs/group/fn2.o
Binary files differ
diff --git a/test/elf/X86_64/Inputs/group/group.sh b/test/elf/X86_64/Inputs/group/group.sh
new file mode 100755
index 000000000000..2eba1030160b
--- /dev/null
+++ b/test/elf/X86_64/Inputs/group/group.sh
@@ -0,0 +1,38 @@
+cat > 1.c << \!
+int _start() {
+ return 0;
+}
+
+int main() {
+fn();
+return 0;
+}
+!
+
+cat > fn.c << \!
+int fn() {
+fn1();
+return 0;
+}
+!
+
+cat > fn2.c << \!
+int fn2() {
+return 0;
+}
+!
+
+cat > fn1.c << \!
+int fn1() {
+fn2();
+}
+!
+
+gcc -c 1.c fn.c fn2.c fn1.c
+ar cr libfn.a fn.o fn2.o
+ar cr libfn1.a fn1.o
+lld -flavor gnu -target x86_64 -shared -o libfn2.so fn2.o
+lld -flavor gnu -target x86_64 1.o libfn.a libfn1.a -o x
+lld -flavor gnu -target x86_64 1.o --start-group libfn.a libfn1.a --end-group -o x
+lld -flavor gnu -target x86_64 1.o --start-group fn.o fn2.o fn1.o --end-group -o x
+lld -flavor gnu -target x86_64 1.o --start-group --whole-archive libfn.a --no-whole-archive libfn1.a --end-group -o x
diff --git a/test/elf/X86_64/Inputs/group/libfn.a b/test/elf/X86_64/Inputs/group/libfn.a
new file mode 100644
index 000000000000..c157c3babed9
--- /dev/null
+++ b/test/elf/X86_64/Inputs/group/libfn.a
Binary files differ
diff --git a/test/elf/X86_64/Inputs/group/libfn.so b/test/elf/X86_64/Inputs/group/libfn.so
new file mode 100755
index 000000000000..fcbd11fe5519
--- /dev/null
+++ b/test/elf/X86_64/Inputs/group/libfn.so
Binary files differ
diff --git a/test/elf/X86_64/Inputs/group/libfn1.a b/test/elf/X86_64/Inputs/group/libfn1.a
new file mode 100644
index 000000000000..69b9c75b5d16
--- /dev/null
+++ b/test/elf/X86_64/Inputs/group/libfn1.a
Binary files differ
diff --git a/test/elf/X86_64/Inputs/group/libfn2.so b/test/elf/X86_64/Inputs/group/libfn2.so
new file mode 100755
index 000000000000..7ce867373910
--- /dev/null
+++ b/test/elf/X86_64/Inputs/group/libfn2.so
Binary files differ
diff --git a/test/elf/X86_64/Inputs/initfini-option.c b/test/elf/X86_64/Inputs/initfini-option.c
new file mode 100644
index 000000000000..e9a6c08c12ac
--- /dev/null
+++ b/test/elf/X86_64/Inputs/initfini-option.c
@@ -0,0 +1,13 @@
+#include <stdio.h>
+
+void init() {
+ printf("%s\n", __FUNCTION__);
+}
+
+void fini() {
+ printf("%s\n", __FUNCTION__);
+}
+
+int main() {
+}
+
diff --git a/test/elf/X86_64/Inputs/initfini-option.o b/test/elf/X86_64/Inputs/initfini-option.o
new file mode 100644
index 000000000000..b1ba0557353c
--- /dev/null
+++ b/test/elf/X86_64/Inputs/initfini-option.o
Binary files differ
diff --git a/test/elf/X86_64/Inputs/initfini.c b/test/elf/X86_64/Inputs/initfini.c
new file mode 100644
index 000000000000..9427a86b6c9b
--- /dev/null
+++ b/test/elf/X86_64/Inputs/initfini.c
@@ -0,0 +1,14 @@
+#include <stdio.h>
+
+void __attribute__ ((constructor)) constructor() {
+ printf("%s\n", __FUNCTION__);
+}
+
+void __attribute__ ((destructor)) destructor() {
+ printf("%s\n", __FUNCTION__);
+}
+
+int main() {
+ return 0;
+}
+
diff --git a/test/elf/X86_64/Inputs/initfini.o b/test/elf/X86_64/Inputs/initfini.o
new file mode 100644
index 000000000000..f0e55a90b8b6
--- /dev/null
+++ b/test/elf/X86_64/Inputs/initfini.o
Binary files differ
diff --git a/test/elf/X86_64/Inputs/largebss.c b/test/elf/X86_64/Inputs/largebss.c
new file mode 100644
index 000000000000..157d01755b6a
--- /dev/null
+++ b/test/elf/X86_64/Inputs/largebss.c
@@ -0,0 +1,3 @@
+int largebss[1000] = { 0 };
+int largecommon[1000];
+__thread int largetbss[1000] = { 0 };
diff --git a/test/elf/X86_64/Inputs/largebss.o b/test/elf/X86_64/Inputs/largebss.o
new file mode 100644
index 000000000000..377370ec2db2
--- /dev/null
+++ b/test/elf/X86_64/Inputs/largebss.o
Binary files differ
diff --git a/test/elf/X86_64/Inputs/layoutpass/1.c b/test/elf/X86_64/Inputs/layoutpass/1.c
new file mode 100644
index 000000000000..fec984503214
--- /dev/null
+++ b/test/elf/X86_64/Inputs/layoutpass/1.c
@@ -0,0 +1,8 @@
+int main() {
+ a();
+ return 0;
+}
+
+int b() {
+ return 0;
+}
diff --git a/test/elf/X86_64/Inputs/layoutpass/1.o b/test/elf/X86_64/Inputs/layoutpass/1.o
new file mode 100644
index 000000000000..848a5b3321ac
--- /dev/null
+++ b/test/elf/X86_64/Inputs/layoutpass/1.o
Binary files differ
diff --git a/test/elf/X86_64/Inputs/layoutpass/2.c b/test/elf/X86_64/Inputs/layoutpass/2.c
new file mode 100644
index 000000000000..fb9dbcc28aa6
--- /dev/null
+++ b/test/elf/X86_64/Inputs/layoutpass/2.c
@@ -0,0 +1,7 @@
+int a() {
+ return 0;
+}
+
+int c() {
+ return 0;
+}
diff --git a/test/elf/X86_64/Inputs/layoutpass/2.o b/test/elf/X86_64/Inputs/layoutpass/2.o
new file mode 100644
index 000000000000..4c5ef8679581
--- /dev/null
+++ b/test/elf/X86_64/Inputs/layoutpass/2.o
Binary files differ
diff --git a/test/elf/X86_64/Inputs/layoutpass/3.c b/test/elf/X86_64/Inputs/layoutpass/3.c
new file mode 100644
index 000000000000..054029fe5cfe
--- /dev/null
+++ b/test/elf/X86_64/Inputs/layoutpass/3.c
@@ -0,0 +1,3 @@
+int d() {
+ return 0;
+}
diff --git a/test/elf/X86_64/Inputs/layoutpass/3.o b/test/elf/X86_64/Inputs/layoutpass/3.o
new file mode 100644
index 000000000000..76ef76e97901
--- /dev/null
+++ b/test/elf/X86_64/Inputs/layoutpass/3.o
Binary files differ
diff --git a/test/elf/X86_64/Inputs/layoutpass/lib2.a b/test/elf/X86_64/Inputs/layoutpass/lib2.a
new file mode 100644
index 000000000000..5f076c869817
--- /dev/null
+++ b/test/elf/X86_64/Inputs/layoutpass/lib2.a
Binary files differ
diff --git a/test/elf/X86_64/Inputs/libfn.a b/test/elf/X86_64/Inputs/libfn.a
new file mode 100644
index 000000000000..380844b0838d
--- /dev/null
+++ b/test/elf/X86_64/Inputs/libfn.a
Binary files differ
diff --git a/test/elf/X86_64/Inputs/libfn.so b/test/elf/X86_64/Inputs/libfn.so
new file mode 100755
index 000000000000..dc02480aa690
--- /dev/null
+++ b/test/elf/X86_64/Inputs/libfn.so
Binary files differ
diff --git a/test/elf/X86_64/Inputs/main.c b/test/elf/X86_64/Inputs/main.c
new file mode 100644
index 000000000000..0280c9127076
--- /dev/null
+++ b/test/elf/X86_64/Inputs/main.c
@@ -0,0 +1,4 @@
+int main() {
+ fn();
+ return 0;
+}
diff --git a/test/elf/X86_64/Inputs/main.o b/test/elf/X86_64/Inputs/main.o
new file mode 100644
index 000000000000..ec8929f4b51d
--- /dev/null
+++ b/test/elf/X86_64/Inputs/main.o
Binary files differ
diff --git a/test/elf/X86_64/Inputs/multi-ovrd.c b/test/elf/X86_64/Inputs/multi-ovrd.c
new file mode 100644
index 000000000000..cf6c0b6ac361
--- /dev/null
+++ b/test/elf/X86_64/Inputs/multi-ovrd.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+void f(void)
+{
+ printf("overridden f!\n");
+}
+
+void g(void)
+{
+ printf("overridden g!\n");
+}
diff --git a/test/elf/X86_64/Inputs/multi-ovrd.o b/test/elf/X86_64/Inputs/multi-ovrd.o
new file mode 100644
index 000000000000..e4c4d6037fdd
--- /dev/null
+++ b/test/elf/X86_64/Inputs/multi-ovrd.o
Binary files differ
diff --git a/test/elf/X86_64/Inputs/multi-weak.c b/test/elf/X86_64/Inputs/multi-weak.c
new file mode 100644
index 000000000000..10b9160352d9
--- /dev/null
+++ b/test/elf/X86_64/Inputs/multi-weak.c
@@ -0,0 +1,20 @@
+int fn()
+{
+ return 0;
+}
+
+void __attribute__((weak)) f()
+{
+ printf("original f..\n");
+}
+
+void __attribute__((weak)) g()
+{
+ printf("original f..\n");
+}
+
+int main(void)
+{
+ f();
+ return 0;
+}
diff --git a/test/elf/X86_64/Inputs/multi-weak.o b/test/elf/X86_64/Inputs/multi-weak.o
new file mode 100644
index 000000000000..d5677b699ac4
--- /dev/null
+++ b/test/elf/X86_64/Inputs/multi-weak.o
Binary files differ
diff --git a/test/elf/X86_64/Inputs/multiweaksyms.o b/test/elf/X86_64/Inputs/multiweaksyms.o
new file mode 100644
index 000000000000..5e2e54d66b0d
--- /dev/null
+++ b/test/elf/X86_64/Inputs/multiweaksyms.o
Binary files differ
diff --git a/test/elf/X86_64/Inputs/nmagic.c b/test/elf/X86_64/Inputs/nmagic.c
new file mode 100644
index 000000000000..3ad15f0c4971
--- /dev/null
+++ b/test/elf/X86_64/Inputs/nmagic.c
@@ -0,0 +1,8 @@
+int a = 10;
+__thread int b = 20;
+__thread int c;
+__thread int d;
+
+int main() {
+ return 0;
+}
diff --git a/test/elf/X86_64/Inputs/nmagic.o b/test/elf/X86_64/Inputs/nmagic.o
new file mode 100644
index 000000000000..af28e0ada8b3
--- /dev/null
+++ b/test/elf/X86_64/Inputs/nmagic.o
Binary files differ
diff --git a/test/elf/X86_64/Inputs/no-interp-section.c b/test/elf/X86_64/Inputs/no-interp-section.c
new file mode 100644
index 000000000000..3981c038ed33
--- /dev/null
+++ b/test/elf/X86_64/Inputs/no-interp-section.c
@@ -0,0 +1 @@
+int c = 10;
diff --git a/test/elf/X86_64/Inputs/no-interp-section.o b/test/elf/X86_64/Inputs/no-interp-section.o
new file mode 100644
index 000000000000..063eb3244f22
--- /dev/null
+++ b/test/elf/X86_64/Inputs/no-interp-section.o
Binary files differ
diff --git a/test/elf/X86_64/Inputs/note.o b/test/elf/X86_64/Inputs/note.o
new file mode 100644
index 000000000000..d86b0cf85d19
--- /dev/null
+++ b/test/elf/X86_64/Inputs/note.o
Binary files differ
diff --git a/test/elf/X86_64/Inputs/note.s b/test/elf/X86_64/Inputs/note.s
new file mode 100644
index 000000000000..0a0b03da6bb7
--- /dev/null
+++ b/test/elf/X86_64/Inputs/note.s
@@ -0,0 +1,11 @@
+ .section ".note.ident", "a"
+ .p2align 2
+ .long 1f - 0f # name size (not including padding)
+ .long 3f - 2f # desc size (not including padding)
+ .long 0x01234567 # type
+0: .asciz "NaMe" # name
+1: .p2align 2
+2: .long 0x76543210 # desc
+ .long 0x89abcdef
+3: .p2align 2
+
diff --git a/test/elf/X86_64/Inputs/note_ro_rw.o b/test/elf/X86_64/Inputs/note_ro_rw.o
new file mode 100644
index 000000000000..76f2486d2736
--- /dev/null
+++ b/test/elf/X86_64/Inputs/note_ro_rw.o
Binary files differ
diff --git a/test/elf/X86_64/Inputs/note_ro_rw.s b/test/elf/X86_64/Inputs/note_ro_rw.s
new file mode 100644
index 000000000000..2a0eff5dfb2b
--- /dev/null
+++ b/test/elf/X86_64/Inputs/note_ro_rw.s
@@ -0,0 +1,21 @@
+ .section ".note.ro", "a"
+ .p2align 2
+ .long 1f - 0f # name size (not including padding)
+ .long 3f - 2f # desc size (not including padding)
+ .long 0x01234567 # type
+0: .asciz "NaMe" # name
+1: .p2align 2
+2: .long 0x76543210 # desc
+ .long 0x89abcdef
+3: .p2align 2
+ .section ".note.rw", "aw"
+ .p2align 2
+ .long 1f - 0f # name size (not including padding)
+ .long 3f - 2f # desc size (not including padding)
+ .long 0x01234567 # type
+0: .asciz "NaMe" # name
+1: .p2align 2
+2: .long 0x76543210 # desc
+ .long 0x89abcdef
+3: .p2align 2
+
diff --git a/test/elf/X86_64/Inputs/ovrd.c b/test/elf/X86_64/Inputs/ovrd.c
new file mode 100644
index 000000000000..a3d721dac2aa
--- /dev/null
+++ b/test/elf/X86_64/Inputs/ovrd.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+void f(void)
+{
+ printf("overridden f!\n");
+}
+
diff --git a/test/elf/X86_64/Inputs/ovrd.o b/test/elf/X86_64/Inputs/ovrd.o
new file mode 100644
index 000000000000..ea7353d94ed9
--- /dev/null
+++ b/test/elf/X86_64/Inputs/ovrd.o
Binary files differ
diff --git a/test/elf/X86_64/Inputs/rodata.c b/test/elf/X86_64/Inputs/rodata.c
new file mode 100644
index 000000000000..01489fe550c8
--- /dev/null
+++ b/test/elf/X86_64/Inputs/rodata.c
@@ -0,0 +1,3 @@
+const char _nl_default_default_domain[] __attribute__ ((visibility ("hidden"))) = "messages";
+const char *_nl_current_default_domain __attribute__ ((visibility ("hidden"))) = _nl_default_default_domain;
+const char _nl_default_default_dirname[] = "/usr/local";
diff --git a/test/elf/X86_64/Inputs/rodata.o b/test/elf/X86_64/Inputs/rodata.o
new file mode 100644
index 000000000000..660606cdc9c0
--- /dev/null
+++ b/test/elf/X86_64/Inputs/rodata.o
Binary files differ
diff --git a/test/elf/X86_64/Inputs/rodata.s b/test/elf/X86_64/Inputs/rodata.s
new file mode 100644
index 000000000000..e1a2eb702736
--- /dev/null
+++ b/test/elf/X86_64/Inputs/rodata.s
@@ -0,0 +1,24 @@
+ .file "x.c"
+ .hidden _nl_default_default_domain
+ .globl _nl_default_default_domain
+ .section .rodata._nl_default_default_domain,"ams",@progbits,1
+ .type _nl_default_default_domain, @object
+ .size _nl_default_default_domain, 9
+_nl_default_default_domain:
+ .string "messages"
+ .hidden _nl_current_default_domain
+ .globl _nl_current_default_domain
+ .section .data._nl_current_default_domain,"aw",@progbits
+ .align 8
+ .type _nl_current_default_domain, @object
+ .size _nl_current_default_domain, 8
+_nl_current_default_domain:
+ .quad _nl_default_default_domain
+ .globl _nl_default_default_dirname
+ .section .rodata._nl_default_default_dirname,"ams",@progbits,1
+ .type _nl_default_default_dirname, @object
+ .size _nl_default_default_dirname, 11
+_nl_default_default_dirname:
+ .string "/usr/local"
+ .ident "GCC: (Ubuntu 4.8.1-2ubuntu1~10.04.1) 4.8.1"
+ .section .note.GNU-stack,"",@progbits
diff --git a/test/elf/X86_64/Inputs/rwint.c b/test/elf/X86_64/Inputs/rwint.c
new file mode 100644
index 000000000000..d1cf7d62c801
--- /dev/null
+++ b/test/elf/X86_64/Inputs/rwint.c
@@ -0,0 +1 @@
+int a = 10;
diff --git a/test/elf/X86_64/Inputs/rwint.o b/test/elf/X86_64/Inputs/rwint.o
new file mode 100644
index 000000000000..9fba51f07add
--- /dev/null
+++ b/test/elf/X86_64/Inputs/rwint.o
Binary files differ
diff --git a/test/elf/X86_64/Inputs/sectionmap.c b/test/elf/X86_64/Inputs/sectionmap.c
new file mode 100644
index 000000000000..c4f530148949
--- /dev/null
+++ b/test/elf/X86_64/Inputs/sectionmap.c
@@ -0,0 +1,4 @@
+int foo __attribute__((section(".gcc_except_table.foo"))) = 4;
+const int bar __attribute__((section(".data.rel.local"))) = 2;
+const int baz __attribute__((section(".data.rel.ro"))) = 2;
+const int bak __attribute__((section(".data.xyz"))) = 2;
diff --git a/test/elf/X86_64/Inputs/sectionmap.o b/test/elf/X86_64/Inputs/sectionmap.o
new file mode 100644
index 000000000000..599cf2cca563
--- /dev/null
+++ b/test/elf/X86_64/Inputs/sectionmap.o
Binary files differ
diff --git a/test/elf/X86_64/Inputs/undefcpp.c b/test/elf/X86_64/Inputs/undefcpp.c
new file mode 100644
index 000000000000..ce84c2a592b6
--- /dev/null
+++ b/test/elf/X86_64/Inputs/undefcpp.c
@@ -0,0 +1 @@
+int foo() { return _Z3fooPKc(); }
diff --git a/test/elf/X86_64/Inputs/undefcpp.o b/test/elf/X86_64/Inputs/undefcpp.o
new file mode 100644
index 000000000000..6b8ebf5b6ab0
--- /dev/null
+++ b/test/elf/X86_64/Inputs/undefcpp.o
Binary files differ
diff --git a/test/elf/X86_64/Inputs/weak-zero-sized.o b/test/elf/X86_64/Inputs/weak-zero-sized.o
new file mode 100644
index 000000000000..7c10c6a509ed
--- /dev/null
+++ b/test/elf/X86_64/Inputs/weak-zero-sized.o
Binary files differ
diff --git a/test/elf/X86_64/Inputs/weak.c b/test/elf/X86_64/Inputs/weak.c
new file mode 100644
index 000000000000..ae07ffc745d8
--- /dev/null
+++ b/test/elf/X86_64/Inputs/weak.c
@@ -0,0 +1,14 @@
+int fn()
+{
+ return 0;
+}
+
+void __attribute__((weak)) f()
+{
+ printf("original f..\n");
+}
+int main(void)
+{
+ f();
+ return 0;
+}
diff --git a/test/elf/X86_64/Inputs/weak.o b/test/elf/X86_64/Inputs/weak.o
new file mode 100644
index 000000000000..41cc88a0c482
--- /dev/null
+++ b/test/elf/X86_64/Inputs/weak.o
Binary files differ
diff --git a/test/elf/X86_64/Inputs/weak.s b/test/elf/X86_64/Inputs/weak.s
new file mode 100644
index 000000000000..64ce779553b6
--- /dev/null
+++ b/test/elf/X86_64/Inputs/weak.s
@@ -0,0 +1,21 @@
+ .file "weak.s"
+ .text
+ .p2align 4,,15
+ .globl test
+ .type test, @function
+test:
+ ret
+ .size test, .-test
+ .weak myfn2
+ .data
+ .align 8
+ .type myfn2, @object
+ .size myfn2, 8
+myfn2:
+ .quad test
+ .weak myfn1
+ .align 8
+ .type myfn1, @object
+ .size myfn1, 8
+myfn1:
+ .quad test
diff --git a/test/elf/X86_64/Inputs/zerosizedsection.o b/test/elf/X86_64/Inputs/zerosizedsection.o
new file mode 100644
index 000000000000..a0f2f13a307a
--- /dev/null
+++ b/test/elf/X86_64/Inputs/zerosizedsection.o
Binary files differ
diff --git a/test/elf/X86_64/Inputs/zerosizedsection.s b/test/elf/X86_64/Inputs/zerosizedsection.s
new file mode 100644
index 000000000000..651ee3aab503
--- /dev/null
+++ b/test/elf/X86_64/Inputs/zerosizedsection.s
@@ -0,0 +1,3 @@
+.text
+.data
+.word .text
diff --git a/test/elf/X86_64/alignoffset.test b/test/elf/X86_64/alignoffset.test
new file mode 100644
index 000000000000..b061f8937935
--- /dev/null
+++ b/test/elf/X86_64/alignoffset.test
@@ -0,0 +1,119 @@
+# Checks that segments are aligned as per ELF spec. The segment virtual address
+# modulo page alignment should be equal to offset modulo page alignment.
+
+# Build executable
+# RUN: yaml2obj -format=elf -docnum 1 %s -o %t.o
+# RUN: lld -flavor gnu -target x86_64 %t.o -o %t.exe -static \
+# RUN: --no-align-segments --rosegment --noinhibit-exec
+# RUN: llvm-readobj -program-headers %t.exe | FileCheck %s
+#
+#CHECK: Offset: 0x15C
+#CHECK: VirtualAddress: 0x40015C
+#CHECK: PhysicalAddress: 0x40015C
+#
+#
+#const int a = 0;
+#int main() {
+# foo();
+# return 0;
+#}
+#
+#int foo() { return 0; }
+
+# object
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000010
+ Content: 554889E54883EC10C745FC00000000E81C000000B9000000008945F889C84883C4105DC36666662E0F1F840000000000554889E5B8000000005DC3
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .rodata
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: '00000000'
+ - Name: .comment
+ Type: SHT_PROGBITS
+ Flags: [ SHF_MERGE, SHF_STRINGS ]
+ AddressAlign: 0x0000000000000001
+ Content: 005562756E747520636C616E672076657273696F6E20332E352E302D73766E3231373330342D317E6578703120286272616E636865732F72656C656173655F33352920286261736564206F6E204C4C564D20332E352E302900
+ - Name: .note.GNU-stack
+ Type: SHT_PROGBITS
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .eh_frame
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC ]
+ AddressAlign: 0x0000000000000008
+ Content: 1400000000000000037A5200017810011B0C070890010000180000001C000000000000002400000000410E108602430D060000001800000038000000000000000B00000000410E108602430D06000000
+ - Name: .rela.eh_frame
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .eh_frame
+ Relocations:
+ - Offset: 0x0000000000000020
+ Symbol: .text
+ Type: R_X86_64_PC32
+ Addend: 0
+ - Offset: 0x000000000000003C
+ Symbol: .text
+ Type: R_X86_64_PC32
+ Addend: 48
+Symbols:
+ Local:
+ - Name: 1.c
+ Type: STT_FILE
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .rodata
+ Type: STT_SECTION
+ Section: .rodata
+ - Name: .comment
+ Type: STT_SECTION
+ Section: .comment
+ - Name: .note.GNU-stack
+ Type: STT_SECTION
+ Section: .note.GNU-stack
+ - Name: .eh_frame
+ Type: STT_SECTION
+ Section: .eh_frame
+ Global:
+ - Name: a
+ Type: STT_OBJECT
+ Section: .rodata
+ Size: 0x0000000000000004
+ - Name: foo
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000030
+ Size: 0x000000000000000B
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x0000000000000024
+...
diff --git a/test/elf/X86_64/debug.test b/test/elf/X86_64/debug.test
new file mode 100644
index 000000000000..a13d12fba382
--- /dev/null
+++ b/test/elf/X86_64/debug.test
@@ -0,0 +1,57 @@
+# Test that debug info is assigned typeNoAlloc and that the output sections have
+# a virtual address of 0.
+RUN: lld -flavor gnu -target x86_64 -e main --output-filetype=yaml \
+RUN: %p/Inputs/debug0.x86-64 %p/Inputs/debug1.x86-64 -o %t
+RUN: FileCheck %s -check-prefix YAML < %t
+
+RUN: lld -flavor gnu -target x86_64 -e main %p/Inputs/debug0.x86-64 \
+RUN: %p/Inputs/debug1.x86-64 -o %t1
+RUN: llvm-readobj -sections %t1 | FileCheck %s -check-prefix ELF
+# Verify that non SHF_ALLOC sections are relocated correctly.
+RUN: llvm-objdump -s %t1 | FileCheck %s -check-prefix RELOC
+
+YAML: type: no-alloc
+
+ELF: Section {
+ELF: Name: .debug_info
+ELF: Type: SHT_PROGBITS (0x1)
+ELF: Flags [ (0x0)
+ELF: ]
+ELF: Address: 0x0
+ELF: }
+ELF: Section {
+ELF: Name: .debug_abbrev
+ELF: Type: SHT_PROGBITS (0x1)
+ELF: Flags [ (0x0)
+ELF: ]
+ELF: Address: 0x0
+ELF: }
+ELF: Section {
+ELF: Name: .debug_aranges
+ELF: Type: SHT_PROGBITS (0x1)
+ELF: Flags [ (0x0)
+ELF: ]
+ELF: Address: 0x0
+ELF: }
+ELF: Section {
+ELF: Name: .debug_line
+ELF: Type: SHT_PROGBITS (0x1)
+ELF: Flags [ (0x0)
+ELF: ]
+ELF: Address: 0x0
+ELF: }
+ELF: Section {
+ELF: Name: .debug_str
+ELF: Type: SHT_PROGBITS (0x1)
+ELF: Flags [ (0x0)
+ELF: ]
+ELF: Address: 0x0
+ELF: }
+
+RELOC: Contents of section .debug_info:
+RELOC: 0000 4e000000 04000000 00000801 3a000000 N...........:...
+# ^^ Relocation: ._debug_str + 0x3a
+RELOC: 0010 01780000 00000000 00dc0140 00000000 .x.........@....
+# ^^ Relocation: .debug_str + 0x78
+RELOC: 0020 00100000 00000000 00000000 00028100 ................
+# ^^ Relocation: .debug_str + 0x81
diff --git a/test/elf/X86_64/defsym.test b/test/elf/X86_64/defsym.test
new file mode 100644
index 000000000000..5d2256a09ac8
--- /dev/null
+++ b/test/elf/X86_64/defsym.test
@@ -0,0 +1,22 @@
+RUN: lld -flavor gnu -target x86_64 --defsym=main=fn --noinhibit-exec \
+RUN: %p/Inputs/fn.o -o %t
+RUN: llvm-readobj -symbols %t | FileCheck %s
+
+CHECK: Symbol {
+CHECK: Name: main (1)
+CHECK: Value: 0x4001E0
+CHECK: Size: 0
+CHECK: Binding: Global (0x1)
+CHECK: Type: Function (0x2)
+CHECK: Other: 0
+CHECK: Section: .text (0x5)
+CHECK: }
+CHECK: Symbol {
+CHECK: Name: fn (6)
+CHECK: Value: 0x4001E0
+CHECK: Size: 6
+CHECK: Binding: Global (0x1)
+CHECK: Type: Function (0x2)
+CHECK: Other: 0
+CHECK: Section: .text (0x5)
+CHECK: }
diff --git a/test/elf/X86_64/demangle.test b/test/elf/X86_64/demangle.test
new file mode 100644
index 000000000000..1977fd7f1e3a
--- /dev/null
+++ b/test/elf/X86_64/demangle.test
@@ -0,0 +1,12 @@
+# XFAIL: win32
+#
+# Check that the linker is able to demangle strings properly.
+# Once there is a way to add undefined symbols using yaml2obj, the test will be
+# changed.
+
+RUN: lld -flavor gnu -target x86_64 %p/Inputs/undefcpp.o --noinhibit-exec 2>&1 | FileCheck -check-prefix=DEMANGLE %s
+RUN: lld -flavor gnu -target x86_64 %p/Inputs/undefcpp.o --noinhibit-exec --no-demangle 2>&1 | FileCheck -check-prefix=NODEMANGLE %s
+RUN: lld -flavor gnu -target x86_64 %p/Inputs/undefcpp.o --noinhibit-exec --demangle 2>&1 | FileCheck -check-prefix=DEMANGLE %s
+
+#DEMANGLE: undefcpp.o: foo(char const*)
+#NODEMANGLE: undefcpp.o: _Z3fooPKc
diff --git a/test/elf/X86_64/dontignorezerosize-sections.test b/test/elf/X86_64/dontignorezerosize-sections.test
new file mode 100644
index 000000000000..101e6cb55b24
--- /dev/null
+++ b/test/elf/X86_64/dontignorezerosize-sections.test
@@ -0,0 +1,9 @@
+# This tests that lld is not ignoring zero sized sections
+RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/zerosizedsection.o \
+RUN: --noinhibit-exec --output-filetype=yaml -o %t
+RUN: FileCheck %s < %t
+
+CHECK: references:
+CHECK: - kind: R_X86_64_16
+CHECK: offset: 0
+CHECK: target: L000
diff --git a/test/elf/X86_64/dynamicvars.test b/test/elf/X86_64/dynamicvars.test
new file mode 100644
index 000000000000..f5db73063650
--- /dev/null
+++ b/test/elf/X86_64/dynamicvars.test
@@ -0,0 +1,124 @@
+# Tests that the dynamic variables created by the linker are set to the right
+# values.
+
+#RUN: yaml2obj --format elf -docnum 1 %s -o %t.o
+#RUN: lld -flavor gnu -target x86_64 -e main %t.o -o %t1 --noinhibit-exec
+#RUN: llvm-readobj -sections -symbols %t1 | FileCheck -check-prefix CHECKSYMS %s
+
+
+#CHECKSYMS: Name: .dynamic
+#CHECKSYMS: Type: SHT_DYNAMIC
+#CHECKSYMS: Address: [[TARGETA:[0xa-fA-f0-9]+]]
+#CHECKSYMS: Name: .got.plt
+#CHECKSYMS: Type: SHT_PROGBITS
+#CHECKSYMS: Address: [[TARGETB:[0xa-fA-f0-9]+]]
+#CHECKSYMS: Name: _DYNAMIC
+#CHECKSYMS: Value: [[TARGETA]]
+#CHECKSYMS: Section: .dynamic
+#CHECKSYMS: Name: _GLOBAL_OFFSET_TABLE_
+#CHECKSYMS: Value: [[TARGETB]]
+#CHECKSYMS: Section: .got.plt
+
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000010
+ Content: 554889E54883EC10488B0500000000C745FC00000000C7000A000000E80000000031C98945F889C84883C4105DC36690554889E531C05DC3
+ - Name: .rela.text
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .text
+ Relocations:
+ - Offset: 0x000000000000000B
+ Symbol: a
+ Type: R_X86_64_GOTPCREL
+ Addend: -4
+ - Offset: 0x000000000000001D
+ Symbol: foo
+ Type: R_X86_64_PLT32
+ Addend: -4
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .comment
+ Type: SHT_PROGBITS
+ Flags: [ SHF_MERGE, SHF_STRINGS ]
+ AddressAlign: 0x0000000000000001
+ Content: 00636C616E672076657273696F6E20332E362E302000
+ - Name: .note.GNU-stack
+ Type: SHT_PROGBITS
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .eh_frame
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC ]
+ AddressAlign: 0x0000000000000008
+ Content: 1400000000000000037A5200017810011B0C070890010000180000001C000000000000002E00000000410E108602430D060000001800000038000000000000000800000000410E108602430D06000000
+ - Name: .rela.eh_frame
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .eh_frame
+ Relocations:
+ - Offset: 0x0000000000000020
+ Symbol: .text
+ Type: R_X86_64_PC32
+ Addend: 0
+ - Offset: 0x000000000000003C
+ Symbol: .text
+ Type: R_X86_64_PC32
+ Addend: 48
+Symbols:
+ Local:
+ - Name: 1.c
+ Type: STT_FILE
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .comment
+ Type: STT_SECTION
+ Section: .comment
+ - Name: .note.GNU-stack
+ Type: STT_SECTION
+ Section: .note.GNU-stack
+ - Name: .eh_frame
+ Type: STT_SECTION
+ Section: .eh_frame
+ Global:
+ - Name: a
+ Type: STT_OBJECT
+ Value: 0x0000000000000004
+ Size: 0x0000000000000004
+ - Name: foo
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000030
+ Size: 0x0000000000000008
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x000000000000002E
+ - Name: _GLOBAL_OFFSET_TABLE_
+...
diff --git a/test/elf/X86_64/dynlib-nointerp-section.test b/test/elf/X86_64/dynlib-nointerp-section.test
new file mode 100644
index 000000000000..dca3d925b38b
--- /dev/null
+++ b/test/elf/X86_64/dynlib-nointerp-section.test
@@ -0,0 +1,4 @@
+RUN: lld -flavor gnu -target x86_64 %p/Inputs/no-interp-section.o -o %t -shared
+RUN: llvm-objdump -section-headers %t | FileCheck %s
+
+CHECK-NOT: .interp
diff --git a/test/elf/X86_64/dynlib-search.test b/test/elf/X86_64/dynlib-search.test
new file mode 100644
index 000000000000..017208ac11ad
--- /dev/null
+++ b/test/elf/X86_64/dynlib-search.test
@@ -0,0 +1,6 @@
+# This tests the functionality for finding the shared library libfn.so for ELF
+RUN: lld -flavor gnu -target x86_64 %p/Inputs/main.o -L%p/Inputs/ -lfn -o %t \
+RUN: --noinhibit-exec -t 2> %t1
+RUN: FileCheck %s < %t1
+
+CHECK: {{[\/0-9A-Za-z_]+}}libfn.so
diff --git a/test/elf/X86_64/dynsym-weak.test b/test/elf/X86_64/dynsym-weak.test
new file mode 100644
index 000000000000..4f05656a41f2
--- /dev/null
+++ b/test/elf/X86_64/dynsym-weak.test
@@ -0,0 +1,118 @@
+# Check that a symbol declared as a week in a shared library gets a dynamic
+# symbol table record in an executable file if this executabe file declares the
+# symbol as strong.
+
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t.foo.o
+# RUN: lld -flavor gnu -target x86_64 -shared -o %t.so %t.foo.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t.main.o
+#
+# Link executable file with strong symbol. Weak symbol is in the shared lib.
+# RUN: lld -flavor gnu -target x86_64 -e main -o %t1.exe %t.main.o %t.so
+# RUN: llvm-readobj -dyn-symbols %t1.exe | FileCheck -check-prefix=EXE %s
+#
+# Link executable file. Strong and weak symbol come from different object files.
+# RUN: lld -flavor gnu -target x86_64 -e main -o %t2.exe %t.main.o %t.foo.o
+# RUN: llvm-readobj -dyn-symbols %t2.exe | FileCheck -check-prefix=OBJ %s
+#
+# Link shared library. Weak symbol is in the another shared lib.
+# RUN: lld -flavor gnu -target x86_64 -shared -o %t.res.so %t.main.o %t.so
+# RUN: llvm-readobj -dyn-symbols %t.res.so | FileCheck -check-prefix=SO %s
+
+# EXE: Symbol {
+# EXE: Name: flag@ ({{[0-9]+}})
+# EXE-NEXT: Value: 0x{{[0-9A-F]+}}
+# EXE-NEXT: Size: 4
+# EXE-NEXT: Binding: Global (0x1)
+# EXE-NEXT: Type: Object (0x1)
+# EXE-NEXT: Other: 0
+# EXE-NEXT: Section: .data (0x{{[0-9A-F]+}})
+# EXE-NEXT: }
+
+# OBJ-NOT: Name: flag@ ({{[0-9]+}})
+
+# SO: Symbol {
+# SO: Name: flag@ ({{[0-9]+}})
+# SO-NEXT: Value: 0x{{[0-9A-F]+}}
+# SO-NEXT: Size: 4
+# SO-NEXT: Binding: Global (0x1)
+# SO-NEXT: Type: Object (0x1)
+# SO-NEXT: Other: 0
+# SO-NEXT: Section: .data (0x{{[0-9A-F]+}})
+# SO-NEXT: }
+
+# foo.o
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x08
+ - Name: .rela.text
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x08
+ Info: .text
+ Relocations:
+ - Offset: 0x00
+ Symbol: flag
+ Type: R_X86_64_GOTPCREL
+ Addend: -4
+
+Symbols:
+ Global:
+ - Name: foo
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x08
+ Weak:
+ - Name: flag
+
+# main.o
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x08
+ - Name: .rela.text
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x08
+ Info: .text
+ Relocations:
+ - Offset: 0x00
+ Symbol: foo
+ Type: R_X86_64_PLT32
+ Addend: -4
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x04
+ Size: 0x04
+
+Symbols:
+ Global:
+ - Name: flag
+ Type: STT_OBJECT
+ Section: .data
+ Size: 0x04
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x08
+ - Name: foo
+...
diff --git a/test/elf/X86_64/extern-tls.test b/test/elf/X86_64/extern-tls.test
new file mode 100644
index 000000000000..c8e7580e5f3c
--- /dev/null
+++ b/test/elf/X86_64/extern-tls.test
@@ -0,0 +1,16 @@
+# This tests verifies that TLS variables have correct offsets
+# when variables the TLS variables are not defined in the program
+RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/externtls.x86-64 -static \
+RUN: --output-filetype=yaml --noinhibit-exec | FileCheck %s -check-prefix=CHECKGOT
+
+ - name: __got_tls_extern_tls
+CHECKGOT: type: got
+CHECKGOT: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ]
+CHECKGOT: alignment: 2^3
+CHECKGOT: section-choice: custom-required
+CHECKGOT: section-name: .got
+CHECKGOT: permissions: rw-
+CHECKGOT: references:
+CHECKGOT: - kind: R_X86_64_TPOFF64
+CHECKGOT: offset: 0
+CHECKGOT: target: extern_tls
diff --git a/test/elf/X86_64/general-dynamic-tls.test b/test/elf/X86_64/general-dynamic-tls.test
new file mode 100644
index 000000000000..c1a6f6e5d120
--- /dev/null
+++ b/test/elf/X86_64/general-dynamic-tls.test
@@ -0,0 +1,129 @@
+# This test exercises a simple general dynamic TLS access model in X86_64.
+#
+# It is composed of two parts: a program and a shared library. The shared
+# library uses TLS, but the program does not.
+#
+# The shared library should import __tls_get_addr, since it uses the general
+# dynamic TLS access mode (see www.akkadia.org/drepper/tls.pdf). Notice that
+# once we support TLS strength reduction, this test should be updated, since
+# this can be converted into a local dynamic TLS model.
+
+# Prepare inputs
+#RUN: yaml2obj -format=elf %p/Inputs/generaltls-so.o.yaml -o=%t.o.so
+#RUN: lld -flavor gnu -target x86_64 -shared %t.o.so -o %T/libgeneraltls.so
+#RUN: yaml2obj -format=elf %s -o=%t.o
+
+# Link - (we supply --defsym=__tls_get_addr to avoid the need to link with
+# system libraries)
+#RUN: lld -flavor gnu -target x86_64 -e main %t.o -L%T -lgeneraltls -o %t1 \
+#RUN: --defsym=__tls_get_addr=0
+
+# Check
+#RUN: llvm-readobj -dyn-symbols %t1 | FileCheck -check-prefix CHECKPROG %s
+#RUN: llvm-readobj -relocations -dyn-symbols %T/libgeneraltls.so | FileCheck \
+#RUN: -check-prefix CHECKDSO %s
+
+# Test case generated with the following code:
+#
+# DSO: (file %p/Inputs/generaltls-so.o.yaml)
+#
+# __thread int mynumber=33;
+#
+# int getnumber() {
+# return mynumber;
+# }
+#
+# Program: (this file). Note: The printf() relocation was removed to simplify
+# this test and allow us to test this without libc.
+#
+# #include <stdio.h>
+# int getnumber();
+#
+# int main() {
+# printf("getnumber() = %d\n", getnumber());
+# return 0;
+# }
+#
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000010
+ Content: 554889E54883EC10C745FC00000000B000E80000000048BF000000000000000089C6B000E80000000031F68945F889F04883C4105DC3
+ - Name: .rela.text
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .text
+ Relocations:
+ - Offset: 0x0000000000000012
+ Symbol: getnumber
+ Type: R_X86_64_PC32
+ Addend: -4
+ - Offset: 0x0000000000000018
+ Symbol: .rodata.str1.1
+ Type: R_X86_64_64
+ Addend: 0
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .rodata.str1.1
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_MERGE, SHF_STRINGS ]
+ AddressAlign: 0x0000000000000001
+ Content: 6765746E756D6265722829203D2025640A00
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .rodata.str1.1
+ Type: STT_SECTION
+ Section: .rodata.str1.1
+ Global:
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x0000000000000036
+ - Name: getnumber
+
+# Program should import the function defined in the shared library
+#CHECKPROG: getnumber@
+# Program should not import __tls_get_addr, since it does not directly use TLS
+#CHECKPROG-NOT: __tls_get_addr@
+
+# Check for the presence of X86_64 TLS relocations in the shared library
+#CHECKDSO: R_X86_64_DTPMOD64
+#CHECKDSO: R_X86_64_DTPOFF64
+#CHECKDSO: R_X86_64_JUMP_SLOT
+
+# The shared library should import __tls_get_addr, since it uses the general
+# dynamic TLS access mode.
+#CHECKDSO: Name: __tls_get_addr@
+#CHECKDSO-NEXT: Value: 0x0
+#CHECKDSO-NEXT: Size: 0
+#CHECKDSO-NEXT: Binding: Global
+#CHECKDSO-NEXT: Type: None
+#CHECKDSO-NEXT: Other: 0
+#CHECKDSO-NEXT: Section: Undefined
+
diff --git a/test/elf/X86_64/imagebase.test b/test/elf/X86_64/imagebase.test
new file mode 100644
index 000000000000..67c3b6e1ff49
--- /dev/null
+++ b/test/elf/X86_64/imagebase.test
@@ -0,0 +1,94 @@
+# Checks that segments start at the image address specified.
+
+# Build executable
+# RUN: yaml2obj -format=elf -docnum 1 %s -o %t.o
+# RUN: lld -flavor gnu -target x86_64 %t.o -o %t.exe -static \
+# RUN: --no-align-segments --noinhibit-exec --image-base 0x600000
+# RUN: llvm-readobj -program-headers %t.exe | FileCheck %s
+#
+#CHECK: VirtualAddress: 0x600000
+#CHECK: PhysicalAddress: 0x600000
+#CHECK: VirtualAddress: 0x600178
+#CHECK: PhysicalAddress: 0x600178
+
+# object
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000010
+ Content: 554889E5B864000000C745FC000000005DC366666666662E0F1F840000000000554889E531C05DC3
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: '64000000'
+ - Name: .rodata
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: '64000000'
+ - Name: .eh_frame
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC ]
+ AddressAlign: 0x0000000000000008
+ Content: 1400000000000000037A5200017810011B0C070890010000180000001C000000000000001200000000410E108602430D060000001800000038000000000000000800000000410E108602430D06000000
+ - Name: .rela.eh_frame
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .eh_frame
+ Relocations:
+ - Offset: 0x0000000000000020
+ Symbol: .text
+ Type: R_X86_64_PC32
+ Addend: 0
+ - Offset: 0x000000000000003C
+ Symbol: .text
+ Type: R_X86_64_PC32
+ Addend: 32
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .eh_frame
+ Type: STT_SECTION
+ Section: .eh_frame
+ Global:
+ - Name: foo
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000020
+ Size: 0x0000000000000008
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x0000000000000012
+ - Name: myval
+ Type: STT_OBJECT
+ Section: .bss
+ Size: 0x0000000000000004
+ - Name: val
+ Type: STT_OBJECT
+ Section: .rodata
+ Size: 0x0000000000000004
+...
diff --git a/test/elf/X86_64/initfini-order.test b/test/elf/X86_64/initfini-order.test
new file mode 100644
index 000000000000..d3981eb0914e
--- /dev/null
+++ b/test/elf/X86_64/initfini-order.test
@@ -0,0 +1,10 @@
+# This tests the functionality that lld is able to emit
+# init_array/fini_array sections in the right order.
+
+RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/initfini.o \
+RUN: --noinhibit-exec -o %t
+RUN: llvm-objdump -t -section-headers %t | FileCheck %s
+
+CHECK: {{[0-9]+}} .eh_frame {{[0-9a-z]+}} {{[0-9a-z]+}} DATA
+CHECK: {{[0-9]+}} .init_array {{[0-9a-z]+}} {{[0-9a-z]+}} DATA
+CHECK: {{[0-9]+}} .fini_array {{[0-9a-z]+}} {{[0-9a-z]+}} DATA
diff --git a/test/elf/X86_64/initfini.test b/test/elf/X86_64/initfini.test
new file mode 100644
index 000000000000..d882352a1c38
--- /dev/null
+++ b/test/elf/X86_64/initfini.test
@@ -0,0 +1,23 @@
+# This tests the functionality that lld is able to read
+# init_array/fini_array sections in the input ELF. This
+# corresponds to the the .init_array/.fini_array sections
+# in the output ELF.
+
+RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/initfini.o \
+RUN: --noinhibit-exec --output-filetype=yaml -o %t
+RUN: FileCheck %s < %t
+
+CHECK: - type: data
+CHECK: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ]
+CHECK: section-name: .init_array
+CHECK: references:
+CHECK: - kind: R_X86_64_64
+CHECK: offset: 0
+CHECK: target: constructor
+CHECK: - type: data
+CHECK: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ]
+CHECK: section-name: .fini_array
+CHECK: references:
+CHECK: - kind: R_X86_64_64
+CHECK: offset: 0
+CHECK: target: destructor
diff --git a/test/elf/X86_64/largebss.test b/test/elf/X86_64/largebss.test
new file mode 100644
index 000000000000..d2dde4954139
--- /dev/null
+++ b/test/elf/X86_64/largebss.test
@@ -0,0 +1,20 @@
+# This tests the functionality of handling BSS symbols
+# BSS symbols don't occupy file content and are associated with typeZeroFill
+# Any typeZeroFill content wouldn't have space reserved in the file to store
+# its content
+
+RUN: lld -flavor gnu -target x86_64 %p/Inputs/largebss.o --output-filetype=yaml --noinhibit-exec | FileCheck %s
+
+CHECK: - name: largecommon
+CHECK: scope: global
+CHECK: type: zero-fill
+CHECK: size: 4000
+CHECK: merge: as-tentative
+CHECK: - name: largebss
+CHECK: scope: global
+CHECK: type: zero-fill
+CHECK: size: 4000
+CHECK: - name: largetbss
+CHECK: scope: global
+CHECK: type: thread-zero-fill
+CHECK: size: 4000
diff --git a/test/elf/X86_64/layoutpass-order.test b/test/elf/X86_64/layoutpass-order.test
new file mode 100644
index 000000000000..e4ebef1d52db
--- /dev/null
+++ b/test/elf/X86_64/layoutpass-order.test
@@ -0,0 +1,14 @@
+# This test checks that we follow the command line order of layouting
+# symbols in the output file
+
+RUN: lld -flavor gnu -target x86_64 %p/Inputs/layoutpass/1.o \
+RUN: %p/Inputs/layoutpass/lib2.a %p/Inputs/layoutpass/3.o -o %t \
+RUN: --noinhibit-exec -static
+
+RUN: llvm-nm -n %t | FileCheck -check-prefix=SYMBOLSORDER %s
+
+SYMBOLSORDER: {{[A-Fa-f0-9]+}} T main
+SYMBOLSORDER: {{[A-Fa-f0-9]+}} T b
+SYMBOLSORDER: {{[A-Fa-f0-9]+}} T a
+SYMBOLSORDER: {{[A-Fa-f0-9]+}} T c
+SYMBOLSORDER: {{[A-Fa-f0-9]+}} T d
diff --git a/test/elf/X86_64/maxpagesize.test b/test/elf/X86_64/maxpagesize.test
new file mode 100644
index 000000000000..649d09fcada0
--- /dev/null
+++ b/test/elf/X86_64/maxpagesize.test
@@ -0,0 +1,113 @@
+# Checks that segments are aligned as per ELF spec when the user specifies
+# max-page-size option, and the segment alignment is set to the page size
+# specified by the user.
+
+# Build executable
+# RUN: yaml2obj -format=elf -docnum 1 %s -o %t.o
+# RUN: not lld -flavor gnu -target x86_64 %t.o -o %t.exe -static \
+# RUN: --no-align-segments --noinhibit-exec -z max-page-size=0
+# RUN: not lld -flavor gnu -target x86_64 %t.o -o %t.exe -static \
+# RUN: --no-align-segments --noinhibit-exec -z max-page-size=0xFF
+# RUN: not lld -flavor gnu -target x86_64 %t.o -o %t.exe -static \
+# RUN: --no-align-segments --noinhibit-exec -z max-page-size=0x1010
+# RUN: lld -flavor gnu -target x86_64 %t.o -o %t1.exe -static \
+# RUN: --no-align-segments --noinhibit-exec -z max-page-size=0x100000
+# RUN: lld -flavor gnu -target x86_64 %t.o -o %t.exe -static \
+# RUN: --no-align-segments --noinhibit-exec -z max-page-size=0x10000
+# RUN: llvm-readobj -program-headers %t.exe | FileCheck %s
+# RUN: llvm-readobj -program-headers %t1.exe | FileCheck %s -check-prefix=CHECKLARGE
+#
+#CHECK: VirtualAddress: 0x400000
+#CHECK: PhysicalAddress: 0x400000
+#CHECK: Alignment: 65536
+#CHECK: VirtualAddress: 0x400178
+#CHECK: PhysicalAddress: 0x400178
+#CHECK: Alignment: 65536
+#CHECKLARGE: VirtualAddress: 0x400000
+#CHECKLARGE: PhysicalAddress: 0x400000
+#CHECKLARGE: Alignment: 1048576
+#CHECKLARGE: VirtualAddress: 0x400178
+#CHECKLARGE: PhysicalAddress: 0x400178
+#CHECKLARGE: Alignment: 1048576
+
+# object
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000010
+ Content: 554889E5B864000000C745FC000000005DC366666666662E0F1F840000000000554889E531C05DC3
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: '64000000'
+ - Name: .rodata
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: '64000000'
+ - Name: .eh_frame
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC ]
+ AddressAlign: 0x0000000000000008
+ Content: 1400000000000000037A5200017810011B0C070890010000180000001C000000000000001200000000410E108602430D060000001800000038000000000000000800000000410E108602430D06000000
+ - Name: .rela.eh_frame
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .eh_frame
+ Relocations:
+ - Offset: 0x0000000000000020
+ Symbol: .text
+ Type: R_X86_64_PC32
+ Addend: 0
+ - Offset: 0x000000000000003C
+ Symbol: .text
+ Type: R_X86_64_PC32
+ Addend: 32
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .eh_frame
+ Type: STT_SECTION
+ Section: .eh_frame
+ Global:
+ - Name: foo
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000020
+ Size: 0x0000000000000008
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x0000000000000012
+ - Name: myval
+ Type: STT_OBJECT
+ Section: .bss
+ Size: 0x0000000000000004
+ - Name: val
+ Type: STT_OBJECT
+ Section: .rodata
+ Size: 0x0000000000000004
+...
diff --git a/test/elf/X86_64/mergesimilarstrings.test b/test/elf/X86_64/mergesimilarstrings.test
new file mode 100644
index 000000000000..3836f0b50758
--- /dev/null
+++ b/test/elf/X86_64/mergesimilarstrings.test
@@ -0,0 +1,47 @@
+# Check that relocations to section that contains strings is properly handled
+# when merging strings is enabled.
+#
+# RUN: yaml2obj -format=elf %s > %t.o
+# RUN: lld -flavor gnu -target x86_64 %t.o --noinhibit-exec -o %t1.out
+# RUN: llvm-readobj -sections %t1.out | FileCheck %s
+# RUN: lld -flavor gnu -target x86_64 %t.o --noinhibit-exec -o %t2.out --output-filetype=yaml
+# RUN: FileCheck %s -check-prefix=CHECKRELOCS < %t2.out
+
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Content: 54889e5488d3d00000000e80000000088d3d00000000e800000000b8000000005dc3
+ - Name: .rela.text
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x04
+ Info: .text
+ Relocations:
+ - Offset: 0x07
+ Symbol: .rodata
+ Type: R_X86_64_PC32
+ Addend: -4
+ - Name: .rodata
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_MERGE, SHF_STRINGS ]
+ AddressAlign: 0x01
+ Content: 48656c6c6f20576f726c6400576f726c6400
+Symbols:
+ Global:
+ - Name: .rodata
+ Section: .rodata
+
+#CHECK: Name: .rodata
+#CHECK: Size: 18
+#CHECKRELOCS: references:
+#CHECKRELOCS: - kind: R_X86_64_PC32
+#CHECKRELOCS: offset: 7
+#CHECKRELOCS: target: .rodata
+#CHECKRELOCS: addend: -4
diff --git a/test/elf/X86_64/multi-weak-layout.test b/test/elf/X86_64/multi-weak-layout.test
new file mode 100644
index 000000000000..4bbf1dfc7e90
--- /dev/null
+++ b/test/elf/X86_64/multi-weak-layout.test
@@ -0,0 +1,52 @@
+# Test that we are able to layout multiple weak symbols
+# properly
+
+RUN: lld -flavor gnu -target x86_64 %p/Inputs/multiweaksyms.o \
+RUN: --noinhibit-exec -static --output-filetype=yaml -o %t
+RUN: FileCheck %s -check-prefix=WEAKSYMS < %t
+
+WEAKSYMS: - type: data
+WEAKSYMS: alignment: 2^3
+WEAKSYMS: references:
+WEAKSYMS: - kind: layout-after
+WEAKSYMS: offset: 0
+WEAKSYMS: target: [[L001:[-a-zA-Z0-9_]+]]
+WEAKSYMS: - name: myfn2
+WEAKSYMS: scope: global
+WEAKSYMS: type: data
+WEAKSYMS: merge: as-weak
+WEAKSYMS: alignment: 2^3
+WEAKSYMS: references:
+WEAKSYMS: - kind: layout-after
+WEAKSYMS: offset: 0
+WEAKSYMS: target: [[L001]]
+WEAKSYMS: - ref-name: [[L001]]
+WEAKSYMS: scope: global
+WEAKSYMS: type: data
+WEAKSYMS: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ]
+WEAKSYMS: alignment: 2^3
+WEAKSYMS: references:
+WEAKSYMS: - kind: R_X86_64_64
+WEAKSYMS: offset: 0
+WEAKSYMS: target: test
+WEAKSYMS: - kind: layout-after
+WEAKSYMS: offset: 0
+WEAKSYMS: target: [[L003:[-a-zA-Z0-9_]+]]
+WEAKSYMS: - name: myfn1
+WEAKSYMS: scope: global
+WEAKSYMS: type: data
+WEAKSYMS: merge: as-weak
+WEAKSYMS: alignment: 2^3
+WEAKSYMS: references:
+WEAKSYMS: - kind: layout-after
+WEAKSYMS: offset: 0
+WEAKSYMS: target: [[L003]]
+WEAKSYMS: - ref-name: [[L003]]
+WEAKSYMS: scope: global
+WEAKSYMS: type: data
+WEAKSYMS: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ]
+WEAKSYMS: alignment: 2^3
+WEAKSYMS: references:
+WEAKSYMS: - kind: R_X86_64_64
+WEAKSYMS: offset: 0
+WEAKSYMS: target: test
diff --git a/test/elf/X86_64/multi-weak-override.test b/test/elf/X86_64/multi-weak-override.test
new file mode 100644
index 000000000000..f2d0e0c2f77b
--- /dev/null
+++ b/test/elf/X86_64/multi-weak-override.test
@@ -0,0 +1,16 @@
+# Test for weak symbol getting overridden
+RUN: lld -flavor gnu -target x86_64 %p/Inputs/multi-weak.o \
+RUN: %p/Inputs/multi-ovrd.o -o %t -e main --noinhibit-exec
+RUN: llvm-nm -n %t | FileCheck -check-prefix=WEAKORDER %s
+RUN: lld -flavor gnu -target x86_64 %p/Inputs/multi-weak.o \
+RUN: %p/Inputs/multi-ovrd.o --output-filetype=yaml -o %t2 --noinhibit-exec
+RUN: FileCheck -check-prefix=WEAKATOMSORDER %s < %t2
+
+WEAKORDER: {{[0-9a-f]+}} T f
+WEAKORDER: {{[0-9a-f]+}} T g
+
+WEAKATOMSORDER: - ref-name: {{[A-Z0-9]+}}
+WEAKATOMSORDER: - ref-name: {{[A-Z0-9]+}}
+WEAKATOMSORDER: - name: f
+WEAKATOMSORDER: - name: g
+
diff --git a/test/elf/X86_64/multi-weak-syms-order.test b/test/elf/X86_64/multi-weak-syms-order.test
new file mode 100644
index 000000000000..2b414593fed4
--- /dev/null
+++ b/test/elf/X86_64/multi-weak-syms-order.test
@@ -0,0 +1,13 @@
+# Test for weak symbol getting overridden
+RUN: lld -flavor gnu -target x86_64 %p/Inputs/multi-weak.o -o %t --noinhibit-exec
+RUN: llvm-nm -n %t | FileCheck -check-prefix=WEAKORDER %s
+RUN: lld -flavor gnu -target x86_64 %p/Inputs/multi-weak.o -o %t2 --output-filetype=yaml --noinhibit-exec
+RUN: FileCheck -check-prefix=WEAKATOMSORDER %s < %t2
+
+WEAKORDER: {{[0-9a-f]+}} T fn
+WEAKORDER: {{[0-9a-f]+}} T f
+WEAKORDER: {{[0-9a-f]+}} T g
+WEAKORDER: {{[0-9a-f]+}} T main
+
+WEAKATOMSORDER: - name: f
+WEAKATOMSORDER: - name: g
diff --git a/test/elf/X86_64/nmagic.test b/test/elf/X86_64/nmagic.test
new file mode 100644
index 000000000000..b313c1f051ba
--- /dev/null
+++ b/test/elf/X86_64/nmagic.test
@@ -0,0 +1,91 @@
+# This tests verifies functionality of NMAGIC that we create only two segments,
+# PT_LOAD, PT_TLS
+# The data segment should be aligned to a page boundary
+RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/nmagic.o \
+RUN: --noinhibit-exec -o %t --nmagic -static
+RUN: llvm-readobj -sections %t | FileCheck -check-prefix=NMAGICSECTIONS %s
+RUN: llvm-readobj -program-headers %t | FileCheck -check-prefix=NMAGICPROGRAMHEADERS %s
+
+NMAGICSECTIONS: Section {
+NMAGICSECTIONS: Index: 0
+NMAGICSECTIONS: Name: (0)
+NMAGICSECTIONS: Type: SHT_NULL (0x0)
+NMAGICSECTIONS: }
+NMAGICSECTIONS: Section {
+NMAGICSECTIONS: Name: .text
+NMAGICSECTIONS: Type: SHT_PROGBITS (0x1)
+NMAGICSECTIONS: }
+NMAGICSECTIONS: Section {
+NMAGICSECTIONS: Name: .eh_frame
+NMAGICSECTIONS: Type: SHT_PROGBITS (0x1)
+NMAGICSECTIONS: }
+NMAGICSECTIONS: Section {
+NMAGICSECTIONS: Name: .tdata
+NMAGICSECTIONS: Type: SHT_PROGBITS (0x1)
+NMAGICSECTIONS: }
+NMAGICSECTIONS: Section {
+NMAGICSECTIONS: Name: .tbss
+NMAGICSECTIONS: Type: SHT_NOBITS (0x8)
+NMAGICSECTIONS: }
+NMAGICSECTIONS: Section {
+NMAGICSECTIONS: Name: .got.plt
+NMAGICSECTIONS: Type: SHT_PROGBITS (0x1)
+NMAGICSECTIONS: }
+NMAGICSECTIONS: Section {
+NMAGICSECTIONS: Name: .data
+NMAGICSECTIONS: Type: SHT_PROGBITS (0x1)
+NMAGICSECTIONS: }
+NMAGICSECTIONS: Section {
+NMAGICSECTIONS: Name: .bss
+NMAGICSECTIONS: Type: SHT_NOBITS (0x8)
+NMAGICSECTIONS: }
+NMAGICSECTIONS: Section {
+NMAGICSECTIONS: Name: .comment
+NMAGICSECTIONS: Type: SHT_PROGBITS (0x1)
+NMAGICSECTIONS: }
+NMAGICSECTIONS: Section {
+NMAGICSECTIONS: Name: .note.GNU-stack
+NMAGICSECTIONS: Type: SHT_PROGBITS (0x1)
+NMAGICSECTIONS: }
+NMAGICSECTIONS: Section {
+NMAGICSECTIONS: Name: .shstrtab
+NMAGICSECTIONS: Type: SHT_STRTAB (0x3)
+NMAGICSECTIONS: }
+NMAGICSECTIONS: Section {
+NMAGICSECTIONS: Name: .symtab
+NMAGICSECTIONS: Type: SHT_SYMTAB (0x2)
+NMAGICSECTIONS: }
+NMAGICSECTIONS: Section {
+NMAGICSECTIONS: Name: .strtab
+NMAGICSECTIONS: Type: SHT_STRTAB (0x3)
+NMAGICSECTIONS: }
+
+NMAGICPROGRAMHEADERS: ProgramHeaders [
+NMAGICPROGRAMHEADERS: ProgramHeader {
+NMAGICPROGRAMHEADERS: Type: PT_LOAD (0x1)
+NMAGICPROGRAMHEADERS: Offset: 0x0
+NMAGICPROGRAMHEADERS: VirtualAddress: 0x400000
+NMAGICPROGRAMHEADERS: PhysicalAddress: 0x400000
+NMAGICPROGRAMHEADERS: FileSize: 4108
+NMAGICPROGRAMHEADERS: MemSize: 4108
+NMAGICPROGRAMHEADERS: Flags [ (0x7)
+NMAGICPROGRAMHEADERS: PF_R (0x4)
+NMAGICPROGRAMHEADERS: PF_W (0x2)
+NMAGICPROGRAMHEADERS: PF_X (0x1)
+NMAGICPROGRAMHEADERS: ]
+NMAGICPROGRAMHEADERS: Alignment: 8
+NMAGICPROGRAMHEADERS: }
+NMAGICPROGRAMHEADERS: ProgramHeader {
+NMAGICPROGRAMHEADERS: Type: PT_TLS (0x7)
+NMAGICPROGRAMHEADERS: Offset: 0x1000
+NMAGICPROGRAMHEADERS: VirtualAddress: 0x401000
+NMAGICPROGRAMHEADERS: PhysicalAddress: 0x401000
+NMAGICPROGRAMHEADERS: FileSize: 4
+NMAGICPROGRAMHEADERS: MemSize: 12
+NMAGICPROGRAMHEADERS: Flags [ (0x6)
+NMAGICPROGRAMHEADERS: PF_R (0x4)
+NMAGICPROGRAMHEADERS: PF_W (0x2)
+NMAGICPROGRAMHEADERS: ]
+NMAGICPROGRAMHEADERS: Alignment: 4
+NMAGICPROGRAMHEADERS: }
+NMAGICPROGRAMHEADERS: ]
diff --git a/test/elf/X86_64/noalignsegments.test b/test/elf/X86_64/noalignsegments.test
new file mode 100644
index 000000000000..8432bda51f00
--- /dev/null
+++ b/test/elf/X86_64/noalignsegments.test
@@ -0,0 +1,95 @@
+# Checks that segments are aligned as per ELF spec than aligning each
+# segment fileoffset / virtual address to a page.
+
+# Build executable
+# RUN: yaml2obj -format=elf -docnum 1 %s -o %t.o
+# RUN: lld -flavor gnu -target x86_64 %t.o -o %t.exe -static \
+# RUN: --no-align-segments --noinhibit-exec
+# RUN: llvm-readobj -program-headers %t.exe | FileCheck %s
+#
+#CHECK: VirtualAddress: 0x400000
+#CHECK: PhysicalAddress: 0x400000
+#CHECK: VirtualAddress: 0x400178
+#CHECK: PhysicalAddress: 0x400178
+
+# object
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000010
+ Content: 554889E5B864000000C745FC000000005DC366666666662E0F1F840000000000554889E531C05DC3
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: '64000000'
+ - Name: .rodata
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: '64000000'
+ - Name: .eh_frame
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC ]
+ AddressAlign: 0x0000000000000008
+ Content: 1400000000000000037A5200017810011B0C070890010000180000001C000000000000001200000000410E108602430D060000001800000038000000000000000800000000410E108602430D06000000
+ - Name: .rela.eh_frame
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .eh_frame
+ Relocations:
+ - Offset: 0x0000000000000020
+ Symbol: .text
+ Type: R_X86_64_PC32
+ Addend: 0
+ - Offset: 0x000000000000003C
+ Symbol: .text
+ Type: R_X86_64_PC32
+ Addend: 32
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .eh_frame
+ Type: STT_SECTION
+ Section: .eh_frame
+ Global:
+ - Name: foo
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000020
+ Size: 0x0000000000000008
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x0000000000000012
+ - Name: myval
+ Type: STT_OBJECT
+ Section: .bss
+ Size: 0x0000000000000004
+ - Name: val
+ Type: STT_OBJECT
+ Section: .rodata
+ Size: 0x0000000000000004
+...
diff --git a/test/elf/X86_64/note-sections-ro_plus_rw.test b/test/elf/X86_64/note-sections-ro_plus_rw.test
new file mode 100644
index 000000000000..ddeeaa41a758
--- /dev/null
+++ b/test/elf/X86_64/note-sections-ro_plus_rw.test
@@ -0,0 +1,42 @@
+# This tests the functionality that lld is able to recreate the note sections
+# if they appear in the input, it looks like we need to differentiate RO note
+# sections from RW note sections, and each creating a segment of its own
+
+RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/note_ro_rw.o \
+RUN: --noinhibit-exec -o %t -static
+RUN: llvm-readobj -sections %t | FileCheck -check-prefix=NOTESECTIONS %s
+RUN: llvm-readobj -program-headers %t | FileCheck -check-prefix=NOTESEGMENT %s
+
+NOTESECTIONS: Section {
+NOTESECTIONS: Name: .note.ro (1)
+NOTESECTIONS: Type: SHT_NOTE (0x7)
+NOTESECTIONS: Flags [ (0x2)
+NOTESECTIONS: SHF_ALLOC (0x2)
+NOTESECTIONS: ]
+NOTESECTIONS: AddressAlignment: 4
+NOTESECTIONS: }
+NOTESECTIONS: Section {
+NOTESECTIONS: Name: .note.rw (31)
+NOTESECTIONS: Type: SHT_NOTE (0x7)
+NOTESECTIONS: Flags [ (0x3)
+NOTESECTIONS: SHF_ALLOC (0x2)
+NOTESECTIONS: SHF_WRITE (0x1)
+NOTESECTIONS: ]
+NOTESECTIONS: Size: 28
+NOTESECTIONS: AddressAlignment: 4
+NOTESECTIONS: }
+NOTESEGMENT: ProgramHeader {
+NOTESEGMENT: Type: PT_NOTE (0x4)
+NOTESEGMENT: Flags [ (0x4)
+NOTESEGMENT: PF_R (0x4)
+NOTESEGMENT: ]
+NOTESEGMENT: Alignment: 4
+NOTESEGMENT: }
+NOTESEGMENT: ProgramHeader {
+NOTESEGMENT: Type: PT_NOTE (0x4)
+NOTESEGMENT: Flags [ (0x6)
+NOTESEGMENT: PF_R (0x4)
+NOTESEGMENT: PF_W (0x2)
+NOTESEGMENT: ]
+NOTESEGMENT: Alignment: 4
+NOTESEGMENT: }
diff --git a/test/elf/X86_64/note-sections.test b/test/elf/X86_64/note-sections.test
new file mode 100644
index 000000000000..a49f95cf4a27
--- /dev/null
+++ b/test/elf/X86_64/note-sections.test
@@ -0,0 +1,23 @@
+# This tests the functionality that lld is able to recreate the note sections
+# if they appear in the input
+
+RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/note.o \
+RUN: --noinhibit-exec -o %t -static
+RUN: llvm-readobj -sections %t | FileCheck -check-prefix=NOTESECTIONS %s
+RUN: llvm-readobj -program-headers %t | FileCheck -check-prefix=NOTESEGMENT %s
+
+
+NOTESECTIONS: Section {
+NOTESECTIONS: Index: 1
+NOTESECTIONS: Name: .note.ident (1)
+NOTESECTIONS: Type: SHT_NOTE (0x7)
+NOTESECTIONS: Size: 28
+NOTESECTIONS: AddressAlignment: 4
+NOTESECTIONS: }
+
+NOTESEGMENT: ProgramHeader {
+NOTESEGMENT: Type: PT_NOTE (0x4)
+NOTESEGMENT: FileSize: 28
+NOTESEGMENT: MemSize: 28
+NOTESEGMENT: Alignment: 4
+NOTESEGMENT: }
diff --git a/test/elf/X86_64/omagic.test b/test/elf/X86_64/omagic.test
new file mode 100644
index 000000000000..437d2e2a9f98
--- /dev/null
+++ b/test/elf/X86_64/omagic.test
@@ -0,0 +1,237 @@
+# This tests verifies functionality of omagic that we create only two segments,
+# PT_LOAD, PT_TLS
+# The data segment should not be aligned to a page boundary
+RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/nmagic.o \
+RUN: --noinhibit-exec -o %t --omagic -static
+RUN: llvm-readobj -sections %t | FileCheck -check-prefix=OMAGICSECTIONS %s
+RUN: llvm-readobj -program-headers %t | FileCheck -check-prefix=OMAGICPROGRAMHEADERS %s
+
+OMAGICSECTIONS: Section {
+OMAGICSECTIONS: Name: (0)
+OMAGICSECTIONS: Type: SHT_NULL (0x0)
+OMAGICSECTIONS: Flags [ (0x0)
+OMAGICSECTIONS: ]
+OMAGICSECTIONS: Address: 0x0
+OMAGICSECTIONS: Offset: 0x0
+OMAGICSECTIONS: Size: 0
+OMAGICSECTIONS: Link: 0
+OMAGICSECTIONS: Info: 0
+OMAGICSECTIONS: AddressAlignment: 0
+OMAGICSECTIONS: EntrySize: 0
+OMAGICSECTIONS: }
+OMAGICSECTIONS: Section {
+OMAGICSECTIONS: Name: .text
+OMAGICSECTIONS: Type: SHT_PROGBITS (0x1)
+OMAGICSECTIONS: Flags [ (0x6)
+OMAGICSECTIONS: SHF_ALLOC (0x2)
+OMAGICSECTIONS: SHF_EXECINSTR (0x4)
+OMAGICSECTIONS: ]
+OMAGICSECTIONS: Address: 0x4000E8
+OMAGICSECTIONS: Offset: 0xE8
+OMAGICSECTIONS: Size: 11
+OMAGICSECTIONS: Link: 0
+OMAGICSECTIONS: Info: 0
+OMAGICSECTIONS: AddressAlignment: 4
+OMAGICSECTIONS: EntrySize: 0
+OMAGICSECTIONS: }
+OMAGICSECTIONS: Section {
+OMAGICSECTIONS: Name: .eh_frame
+OMAGICSECTIONS: Type: SHT_PROGBITS (0x1)
+OMAGICSECTIONS: Flags [ (0x2)
+OMAGICSECTIONS: SHF_ALLOC (0x2)
+OMAGICSECTIONS: ]
+OMAGICSECTIONS: Address: 0x4000F8
+OMAGICSECTIONS: Offset: 0xF8
+OMAGICSECTIONS: Size: 56
+OMAGICSECTIONS: Link: 0
+OMAGICSECTIONS: Info: 0
+OMAGICSECTIONS: AddressAlignment: 8
+OMAGICSECTIONS: EntrySize: 0
+OMAGICSECTIONS: }
+OMAGICSECTIONS: Section {
+OMAGICSECTIONS: Name: .eh_frame_hdr
+OMAGICSECTIONS: Type: SHT_PROGBITS (0x1)
+OMAGICSECTIONS: Flags [ (0x2)
+OMAGICSECTIONS: SHF_ALLOC (0x2)
+OMAGICSECTIONS: ]
+OMAGICSECTIONS: Address: 0x400130
+OMAGICSECTIONS: Offset: 0x130
+OMAGICSECTIONS: Size: 8
+OMAGICSECTIONS: Link: 0
+OMAGICSECTIONS: Info: 0
+OMAGICSECTIONS: AddressAlignment: 8
+OMAGICSECTIONS: EntrySize: 0
+OMAGICSECTIONS: }
+OMAGICSECTIONS: Section {
+OMAGICSECTIONS: Name: .tdata
+OMAGICSECTIONS: Type: SHT_PROGBITS (0x1)
+OMAGICSECTIONS: Flags [ (0x403)
+OMAGICSECTIONS: SHF_ALLOC (0x2)
+OMAGICSECTIONS: SHF_TLS (0x400)
+OMAGICSECTIONS: SHF_WRITE (0x1)
+OMAGICSECTIONS: ]
+OMAGICSECTIONS: Address: 0x400138
+OMAGICSECTIONS: Offset: 0x138
+OMAGICSECTIONS: Size: 4
+OMAGICSECTIONS: Link: 0
+OMAGICSECTIONS: Info: 0
+OMAGICSECTIONS: AddressAlignment: 4
+OMAGICSECTIONS: EntrySize: 0
+OMAGICSECTIONS: }
+OMAGICSECTIONS: Section {
+OMAGICSECTIONS: Name: .tbss
+OMAGICSECTIONS: Type: SHT_NOBITS (0x8)
+OMAGICSECTIONS: Flags [ (0x403)
+OMAGICSECTIONS: SHF_ALLOC (0x2)
+OMAGICSECTIONS: SHF_TLS (0x400)
+OMAGICSECTIONS: SHF_WRITE (0x1)
+OMAGICSECTIONS: ]
+OMAGICSECTIONS: Address: 0x40013C
+OMAGICSECTIONS: Offset: 0x13C
+OMAGICSECTIONS: Size: 8
+OMAGICSECTIONS: Link: 0
+OMAGICSECTIONS: Info: 0
+OMAGICSECTIONS: AddressAlignment: 4
+OMAGICSECTIONS: EntrySize: 0
+OMAGICSECTIONS: }
+OMAGICSECTIONS: Section {
+OMAGICSECTIONS: Name: .got.plt
+OMAGICSECTIONS: Type: SHT_PROGBITS (0x1)
+OMAGICSECTIONS: Flags [ (0x3)
+OMAGICSECTIONS: SHF_ALLOC (0x2)
+OMAGICSECTIONS: SHF_WRITE (0x1)
+OMAGICSECTIONS: ]
+OMAGICSECTIONS: Address: 0x400140
+OMAGICSECTIONS: Offset: 0x140
+OMAGICSECTIONS: Size: 0
+OMAGICSECTIONS: Link: 0
+OMAGICSECTIONS: Info: 0
+OMAGICSECTIONS: AddressAlignment: 8
+OMAGICSECTIONS: EntrySize: 0
+OMAGICSECTIONS: }
+OMAGICSECTIONS: Section {
+OMAGICSECTIONS: Name: .data
+OMAGICSECTIONS: Type: SHT_PROGBITS (0x1)
+OMAGICSECTIONS: Flags [ (0x3)
+OMAGICSECTIONS: SHF_ALLOC (0x2)
+OMAGICSECTIONS: SHF_WRITE (0x1)
+OMAGICSECTIONS: ]
+OMAGICSECTIONS: Address: 0x400140
+OMAGICSECTIONS: Offset: 0x140
+OMAGICSECTIONS: Size: 4
+OMAGICSECTIONS: Link: 0
+OMAGICSECTIONS: Info: 0
+OMAGICSECTIONS: AddressAlignment: 4
+OMAGICSECTIONS: EntrySize: 0
+OMAGICSECTIONS: }
+OMAGICSECTIONS: Section {
+OMAGICSECTIONS: Name: .bss
+OMAGICSECTIONS: Type: SHT_NOBITS (0x8)
+OMAGICSECTIONS: Flags [ (0x3)
+OMAGICSECTIONS: SHF_ALLOC (0x2)
+OMAGICSECTIONS: SHF_WRITE (0x1)
+OMAGICSECTIONS: ]
+OMAGICSECTIONS: Address: 0x400144
+OMAGICSECTIONS: Offset: 0x144
+OMAGICSECTIONS: Size: 0
+OMAGICSECTIONS: Link: 0
+OMAGICSECTIONS: Info: 0
+OMAGICSECTIONS: AddressAlignment: 4
+OMAGICSECTIONS: EntrySize: 0
+OMAGICSECTIONS: }
+OMAGICSECTIONS: Section {
+OMAGICSECTIONS: Name: .comment
+OMAGICSECTIONS: Type: SHT_PROGBITS (0x1)
+OMAGICSECTIONS: Flags [ (0x0)
+OMAGICSECTIONS: ]
+OMAGICSECTIONS: Address: 0x0
+OMAGICSECTIONS: Offset: 0x144
+OMAGICSECTIONS: Size: 43
+OMAGICSECTIONS: Link: 0
+OMAGICSECTIONS: Info: 0
+OMAGICSECTIONS: AddressAlignment: 1
+OMAGICSECTIONS: EntrySize: 0
+OMAGICSECTIONS: }
+OMAGICSECTIONS: Section {
+OMAGICSECTIONS: Name: .note.GNU-stack
+OMAGICSECTIONS: Type: SHT_PROGBITS (0x1)
+OMAGICSECTIONS: Flags [ (0x0)
+OMAGICSECTIONS: ]
+OMAGICSECTIONS: Address: 0x0
+OMAGICSECTIONS: Offset: 0x16F
+OMAGICSECTIONS: Size: 0
+OMAGICSECTIONS: Link: 0
+OMAGICSECTIONS: Info: 0
+OMAGICSECTIONS: AddressAlignment: 1
+OMAGICSECTIONS: EntrySize: 0
+OMAGICSECTIONS: }
+OMAGICSECTIONS: Section {
+OMAGICSECTIONS: Name: .shstrtab
+OMAGICSECTIONS: Type: SHT_STRTAB (0x3)
+OMAGICSECTIONS: Flags [ (0x0)
+OMAGICSECTIONS: ]
+OMAGICSECTIONS: Address: 0x0
+OMAGICSECTIONS: Offset: 0x16F
+OMAGICSECTIONS: Size: 115
+OMAGICSECTIONS: Link: 0
+OMAGICSECTIONS: Info: 0
+OMAGICSECTIONS: AddressAlignment: 1
+OMAGICSECTIONS: EntrySize: 0
+OMAGICSECTIONS: }
+OMAGICSECTIONS: Section {
+OMAGICSECTIONS: Name: .symtab
+OMAGICSECTIONS: Type: SHT_SYMTAB (0x2)
+OMAGICSECTIONS: Flags [ (0x0)
+OMAGICSECTIONS: ]
+OMAGICSECTIONS: Address: 0x0
+OMAGICSECTIONS: Offset: 0x1E8
+OMAGICSECTIONS: Size: 504
+OMAGICSECTIONS: Link: 13
+OMAGICSECTIONS: Info: 2
+OMAGICSECTIONS: AddressAlignment: 8
+OMAGICSECTIONS: EntrySize: 24
+OMAGICSECTIONS: }
+OMAGICSECTIONS: Section {
+OMAGICSECTIONS: Name: .strtab
+OMAGICSECTIONS: Type: SHT_STRTAB (0x3)
+OMAGICSECTIONS: Flags [ (0x0)
+OMAGICSECTIONS: ]
+OMAGICSECTIONS: Address: 0x0
+OMAGICSECTIONS: Offset: 0x3E0
+OMAGICSECTIONS: Size: 231
+OMAGICSECTIONS: Link: 0
+OMAGICSECTIONS: Info: 0
+OMAGICSECTIONS: AddressAlignment: 1
+OMAGICSECTIONS: EntrySize: 0
+OMAGICSECTIONS: }
+OMAGICSECTIONS: ]
+
+OMAGICPROGRAMHEADERS: ProgramHeaders [
+OMAGICPROGRAMHEADERS: ProgramHeader {
+OMAGICPROGRAMHEADERS: Type: PT_LOAD (0x1)
+OMAGICPROGRAMHEADERS: Offset: 0x0
+OMAGICPROGRAMHEADERS: VirtualAddress: 0x400000
+OMAGICPROGRAMHEADERS: PhysicalAddress: 0x400000
+OMAGICPROGRAMHEADERS: FileSize: 324
+OMAGICPROGRAMHEADERS: MemSize: 324
+OMAGICPROGRAMHEADERS: Flags [ (0x7)
+OMAGICPROGRAMHEADERS: PF_R (0x4)
+OMAGICPROGRAMHEADERS: PF_W (0x2)
+OMAGICPROGRAMHEADERS: PF_X (0x1)
+OMAGICPROGRAMHEADERS: ]
+OMAGICPROGRAMHEADERS: Alignment: 8
+OMAGICPROGRAMHEADERS: }
+OMAGICPROGRAMHEADERS: ProgramHeader {
+OMAGICPROGRAMHEADERS: Type: PT_TLS (0x7)
+OMAGICPROGRAMHEADERS: Offset: 0x138
+OMAGICPROGRAMHEADERS: VirtualAddress: 0x400138
+OMAGICPROGRAMHEADERS: PhysicalAddress: 0x400138
+OMAGICPROGRAMHEADERS: FileSize: 4
+OMAGICPROGRAMHEADERS: MemSize: 12
+OMAGICPROGRAMHEADERS: Flags [ (0x6)
+OMAGICPROGRAMHEADERS: PF_R (0x4)
+OMAGICPROGRAMHEADERS: PF_W (0x2)
+OMAGICPROGRAMHEADERS: ]
+OMAGICPROGRAMHEADERS: Alignment: 4
+OMAGICPROGRAMHEADERS: }
+OMAGICPROGRAMHEADERS: ]
diff --git a/test/elf/X86_64/outputsegments.test b/test/elf/X86_64/outputsegments.test
new file mode 100644
index 000000000000..ab6ba8deb47d
--- /dev/null
+++ b/test/elf/X86_64/outputsegments.test
@@ -0,0 +1,189 @@
+# Tests that lld does not create separate segment if the input sections are part
+# of the same output section
+
+# Build executable
+# RUN: yaml2obj -format=elf -docnum 1 %s -o %t.o
+# RUN: lld -flavor gnu -target x86_64 %t.o -o %t1.exe -static \
+# RUN: --no-align-segments --noinhibit-exec
+# RUN: lld -flavor gnu -target x86_64 %t.o -o %t2.exe -static \
+# RUN: --noinhibit-exec
+# RUN: llvm-readobj -program-headers %t1.exe | FileCheck %s -check-prefix=SEGMENTS
+# RUN: llvm-readobj -program-headers %t2.exe | FileCheck %s -check-prefix=SEGMENTS
+#
+#SEGMENTS: VirtualAddress: 0x400000
+#SEGMENTS: PhysicalAddress: 0x400000
+#SEGMENTS: FileSize: 288
+#SEGMENTS: MemSize: 288
+#SEGMENTS: VirtualAddress: 0x404000
+#SEGMENTS: PhysicalAddress: 0x404000
+#SEGMENTS: FileSize: 16608
+#SEGMENTS: MemSize: 16608
+#SEGMENTS: Alignment: 16384
+#
+# object
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .text.foo
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000002000
+ Content: 554889E54883EC1048BF0000000000000000B000E800000000B9000000008945FC89C84883C4105DC3
+ - Name: .rela.text.foo
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .text.foo
+ Relocations:
+ - Offset: 0x000000000000000A
+ Symbol: .rodata.str1.1
+ Type: R_X86_64_64
+ Addend: 0
+ - Offset: 0x0000000000000015
+ Symbol: printf
+ Type: R_X86_64_PC32
+ Addend: -4
+ - Name: .text.bar
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000004000
+ Content: 554889E54883EC1048BF0000000000000000B000E800000000B9000000008945FC89C84883C4105DC3
+ - Name: .rela.text.bar
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .text.bar
+ Relocations:
+ - Offset: 0x000000000000000A
+ Symbol: .rodata.str1.1
+ Type: R_X86_64_64
+ Addend: 7
+ - Offset: 0x0000000000000015
+ Symbol: printf
+ Type: R_X86_64_PC32
+ Addend: -4
+ - Name: .text.main
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000010
+ Content: 554889E54883EC10C745FC00000000E8000000008945F8E8000000008B4DF801C189C84883C4105DC3
+ - Name: .rela.text.main
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .text.main
+ Relocations:
+ - Offset: 0x0000000000000010
+ Symbol: foo
+ Type: R_X86_64_PC32
+ Addend: -4
+ - Offset: 0x0000000000000018
+ Symbol: bar
+ Type: R_X86_64_PC32
+ Addend: -4
+ - Name: .rodata.str1.1
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_MERGE, SHF_STRINGS ]
+ AddressAlign: 0x0000000000000001
+ Content: 48656C6C6F0A00576F726C640A00
+ - Name: .comment
+ Type: SHT_PROGBITS
+ Flags: [ SHF_MERGE, SHF_STRINGS ]
+ AddressAlign: 0x0000000000000001
+ Content: 005562756E747520636C616E672076657273696F6E20332E352E302D73766E3231373330342D317E6578703120286272616E636865732F72656C656173655F33352920286261736564206F6E204C4C564D20332E352E302900
+ - Name: .note.GNU-stack
+ Type: SHT_PROGBITS
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .eh_frame
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC ]
+ AddressAlign: 0x0000000000000008
+ Content: 1400000000000000037A5200017810011B0C070890010000180000001C000000000000002900000000410E108602430D060000001800000038000000000000002900000000410E108602430D060000001C00000054000000000000002900000000410E108602430D0600000000000000
+ - Name: .rela.eh_frame
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .eh_frame
+ Relocations:
+ - Offset: 0x0000000000000020
+ Symbol: .text.foo
+ Type: R_X86_64_PC32
+ Addend: 0
+ - Offset: 0x000000000000003C
+ Symbol: .text.bar
+ Type: R_X86_64_PC32
+ Addend: 0
+ - Offset: 0x0000000000000058
+ Symbol: .text.main
+ Type: R_X86_64_PC32
+ Addend: 0
+Symbols:
+ Local:
+ - Name: 1.c
+ Type: STT_FILE
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .text.foo
+ Type: STT_SECTION
+ Section: .text.foo
+ - Name: .text.bar
+ Type: STT_SECTION
+ Section: .text.bar
+ - Name: .text.main
+ Type: STT_SECTION
+ Section: .text.main
+ - Name: .rodata.str1.1
+ Type: STT_SECTION
+ Section: .rodata.str1.1
+ - Name: .comment
+ Type: STT_SECTION
+ Section: .comment
+ - Name: .note.GNU-stack
+ Type: STT_SECTION
+ Section: .note.GNU-stack
+ - Name: .eh_frame
+ Type: STT_SECTION
+ Section: .eh_frame
+ Global:
+ - Name: bar
+ Type: STT_FUNC
+ Section: .text.bar
+ Size: 0x0000000000000029
+ - Name: foo
+ Type: STT_FUNC
+ Section: .text.foo
+ Size: 0x0000000000000029
+ - Name: main
+ Type: STT_FUNC
+ Section: .text.main
+ Size: 0x0000000000000029
+ - Name: printf
+...
diff --git a/test/elf/X86_64/reloc_r_x86_64_16.test b/test/elf/X86_64/reloc_r_x86_64_16.test
new file mode 100644
index 000000000000..7cca839eb623
--- /dev/null
+++ b/test/elf/X86_64/reloc_r_x86_64_16.test
@@ -0,0 +1,60 @@
+# Tests that lld can handle relocations of type R_X86_64_16
+#RUN: yaml2obj -format=elf -docnum 1 %s -o %t1.o
+#RUN: lld -flavor gnu -target x86_64 %t1.o --noinhibit-exec -o %t2.out -static
+#RUN: llvm-objdump -s %t2.out | FileCheck %s
+#CHECK: Contents of section .data:
+#CHECK: 401000 0210
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000008
+ Content: '0000'
+ - Name: .rela.data
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .data
+ Relocations:
+ - Offset: 0x0000000000000000
+ Symbol: foo
+ Type: R_X86_64_16
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ Global:
+ - Name: bar
+ Type: STT_OBJECT
+ Section: .data
+ Size: 0x0000000000000008
+ - Name: foo
+ Type: STT_OBJECT
+ Section: .data
+ Value: 0x0000000000000002
+ Size: 0x0000000000000002
+...
diff --git a/test/elf/X86_64/reloc_r_x86_64_pc16.test b/test/elf/X86_64/reloc_r_x86_64_pc16.test
new file mode 100644
index 000000000000..6e43e5fade61
--- /dev/null
+++ b/test/elf/X86_64/reloc_r_x86_64_pc16.test
@@ -0,0 +1,61 @@
+# Tests that lld can handle relocations of type R_X86_64_PC16
+#RUN: yaml2obj -format=elf -docnum 1 %s -o %t1.o
+#RUN: lld -flavor gnu -target x86_64 %t1.o --noinhibit-exec -o %t2.out -static
+#RUN: llvm-objdump -s %t2.out | FileCheck %s
+#CHECK: Contents of section .data:
+#CHECK: 401000 0700
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000008
+ Content: '0000'
+ - Name: .rela.data
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .data
+ Relocations:
+ - Offset: 0x0000000000000000
+ Symbol: foo
+ Type: R_X86_64_PC16
+ Addend: 5
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ Global:
+ - Name: bar
+ Type: STT_OBJECT
+ Section: .data
+ Size: 0x0000000000000008
+ - Name: foo
+ Type: STT_OBJECT
+ Section: .data
+ Value: 0x0000000000000002
+ Size: 0x0000000000000002
+...
diff --git a/test/elf/X86_64/reloc_r_x86_64_pc64.test b/test/elf/X86_64/reloc_r_x86_64_pc64.test
new file mode 100644
index 000000000000..75744390be91
--- /dev/null
+++ b/test/elf/X86_64/reloc_r_x86_64_pc64.test
@@ -0,0 +1,61 @@
+# Tests that lld can handle relocations of type R_X86_64_PC64
+#RUN: yaml2obj -format=elf -docnum 1 %s -o %t1.o
+#RUN: lld -flavor gnu -target x86_64 %t1.o --noinhibit-exec -o %t2.out -static
+#RUN: llvm-objdump -s %t2.out | FileCheck %s
+#CHECK: Contents of section .data:
+#CHECK: 401000 0a00
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000008
+ Content: '0000'
+ - Name: .rela.data
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .data
+ Relocations:
+ - Offset: 0x0000000000000000
+ Symbol: foo
+ Type: R_X86_64_PC64
+ Addend: 8
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ Global:
+ - Name: bar
+ Type: STT_OBJECT
+ Section: .data
+ Size: 0x0000000000000008
+ - Name: foo
+ Type: STT_OBJECT
+ Section: .data
+ Value: 0x0000000000000002
+ Size: 0x0000000000000002
+...
diff --git a/test/elf/X86_64/rodata.test b/test/elf/X86_64/rodata.test
new file mode 100644
index 000000000000..61af99f65cfc
--- /dev/null
+++ b/test/elf/X86_64/rodata.test
@@ -0,0 +1,9 @@
+# This tests that the ordinals for all merge atoms and defined atoms have been
+# set properly
+
+RUN: lld -flavor gnu -target x86_64 %p/Inputs/rodata.o --noinhibit-exec \
+RUN: --merge-strings -static -o %t1
+RUN: llvm-nm -n %t1 | FileCheck %s
+
+CHECK: {{[0-9a-f]+}} R _nl_default_default_domain
+CHECK: {{[0-9a-f]+}} R _nl_default_default_dirname
diff --git a/test/elf/X86_64/sectionchoice.test b/test/elf/X86_64/sectionchoice.test
new file mode 100644
index 000000000000..4034d8b1111a
--- /dev/null
+++ b/test/elf/X86_64/sectionchoice.test
@@ -0,0 +1,7 @@
+# This tests that we are able to properly set the sectionChoice for DefinedAtoms
+RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/zerosizedsection.o \
+RUN: --noinhibit-exec -o %t --output-filetype=yaml
+RUN: FileCheck %s < %t
+
+CHECK-NOT: section-choice: sectionCustomRequired
+
diff --git a/test/elf/X86_64/sectionmap.test b/test/elf/X86_64/sectionmap.test
new file mode 100644
index 000000000000..a38f23e32b95
--- /dev/null
+++ b/test/elf/X86_64/sectionmap.test
@@ -0,0 +1,22 @@
+# This tests that we are able to merge the section .gcc_except_table,
+# .data.rel.local, .data.rel.ro, any other sections that belong to .data
+# into appropriate output sections
+RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/sectionmap.o \
+RUN: --noinhibit-exec -o %t
+RUN: llvm-readobj -sections %t | FileCheck %s -check-prefix=VERIFYSECTIONHEADERS
+
+VERIFYSECTIONHEADERS: Section {
+VERIFYSECTIONHEADERS: Name: .data
+VERIFYSECTIONHEADERS: }
+VERIFYSECTIONHEADERS: Section {
+VERIFYSECTIONHEADERS: Name: .gcc_except_table
+VERIFYSECTIONHEADERS: }
+VERIFYSECTIONHEADERS: Section {
+VERIFYSECTIONHEADERS: Name: .data.rel.local
+VERIFYSECTIONHEADERS: }
+VERIFYSECTIONHEADERS: Section {
+VERIFYSECTIONHEADERS: Name: .data.rel.ro
+VERIFYSECTIONHEADERS: }
+VERIFYSECTIONHEADERS: Section {
+VERIFYSECTIONHEADERS: Name: .bss
+VERIFYSECTIONHEADERS: }
diff --git a/test/elf/X86_64/startGroupEndGroup.test b/test/elf/X86_64/startGroupEndGroup.test
new file mode 100644
index 000000000000..ce1897683b34
--- /dev/null
+++ b/test/elf/X86_64/startGroupEndGroup.test
@@ -0,0 +1,48 @@
+# This tests functionality of --start-group, --end-group
+
+# This link should fail with unresolve symbol
+RUN: not lld -flavor gnu -target x86_64 %p/Inputs/group/1.o \
+RUN: %p/Inputs/group/libfn.a %p/Inputs/group/libfn1.a -o x 2> %t.err
+
+# Test group
+RUN: lld -flavor gnu -target x86_64 %p/Inputs/group/1.o --start-group \
+RUN: %p/Inputs/group/libfn.a %p/Inputs/group/libfn1.a --end-group -o %t1
+
+# Mix object files in group
+RUN: lld -flavor gnu -target x86_64 %p/Inputs/group/1.o --start-group \
+RUN: %p/Inputs/group/fn.o %p/Inputs/group/fn2.o \
+RUN: %p/Inputs/group/fn1.o --end-group -o %t2
+
+# Mix Whole archive input, the group should not iterate the file libfn.a
+RUN: lld -flavor gnu -target x86_64 %p/Inputs/group/1.o --start-group \
+RUN: --whole-archive %p/Inputs/group/libfn.a --no-whole-archive \
+RUN: %p/Inputs/group/libfn1.a --end-group -o %t3
+
+# Defined symbols in a shared library.
+RUN: lld -flavor gnu -target x86_64 %p/Inputs/group/1.o --start-group \
+RUN: %p/Inputs/group/libfn2.so %p/Inputs/group/fn1.o %p/Inputs/group/fn.o \
+RUN: --end-group -o %t4
+
+# Test alias options too, as they are more widely used
+# Test group
+RUN: lld -flavor gnu -target x86_64 %p/Inputs/group/1.o '-(' \
+RUN: %p/Inputs/group/libfn.a %p/Inputs/group/libfn1.a '-)' -o %t1.alias
+
+# Mix object files in group
+RUN: lld -flavor gnu -target x86_64 %p/Inputs/group/1.o '-(' \
+RUN: %p/Inputs/group/fn.o %p/Inputs/group/fn2.o \
+RUN: %p/Inputs/group/fn1.o '-)' -o %t2.alias
+
+# Mix Whole archive input, the group should not iterate the file libfn.a
+RUN: lld -flavor gnu -target x86_64 %p/Inputs/group/1.o '-(' \
+RUN: --whole-archive %p/Inputs/group/libfn.a --no-whole-archive \
+RUN: %p/Inputs/group/libfn1.a '-)' -o %t3.alias
+
+RUN: llvm-nm %t1 | FileCheck -check-prefix=RESOLVEDEXTERNAL %s
+RUN: llvm-nm %t2 | FileCheck -check-prefix=RESOLVEDEXTERNAL %s
+RUN: llvm-nm %t3 | FileCheck -check-prefix=RESOLVEDEXTERNAL %s
+RUN: llvm-nm %t1.alias | FileCheck -check-prefix=RESOLVEDEXTERNAL %s
+RUN: llvm-nm %t2.alias | FileCheck -check-prefix=RESOLVEDEXTERNAL %s
+RUN: llvm-nm %t3.alias | FileCheck -check-prefix=RESOLVEDEXTERNAL %s
+
+RESOLVEDEXTERNAL: {{[0-9a-z]+}} T fn2
diff --git a/test/elf/X86_64/startGroupEndGroupWithDynlib.test b/test/elf/X86_64/startGroupEndGroupWithDynlib.test
new file mode 100644
index 000000000000..3e40997db384
--- /dev/null
+++ b/test/elf/X86_64/startGroupEndGroupWithDynlib.test
@@ -0,0 +1,10 @@
+# This tests functionality of --start-group, --end-group with a dynamic library
+
+# Mix dynamic libraries/object files in group
+RUN: lld -flavor gnu -target x86_64 %p/Inputs/group/1.o --start-group \
+RUN: %p/Inputs/group/libfn.so %p/Inputs/group/fn2.o \
+RUN: %p/Inputs/group/fn1.o --end-group -o %t1
+
+RUN: llvm-nm %t1 | FileCheck -check-prefix=RESOLVEDEXTERNAL %s
+
+RESOLVEDEXTERNAL: {{[0-9a-z]+}} T fn2
diff --git a/test/elf/X86_64/staticlib-search.test b/test/elf/X86_64/staticlib-search.test
new file mode 100644
index 000000000000..9c512571932d
--- /dev/null
+++ b/test/elf/X86_64/staticlib-search.test
@@ -0,0 +1,6 @@
+# This tests the functionality for finding the static library libfn.a for ELF
+RUN: lld -flavor gnu -target x86_64 %p/Inputs/main.o -L%p/Inputs/ -lfn -o %t \
+RUN: --noinhibit-exec -static -t 2> %t1
+RUN: FileCheck %s < %t1
+
+CHECK: {{[\/0-9A-Za-z_]+}}libfn.a
diff --git a/test/elf/X86_64/undef.test b/test/elf/X86_64/undef.test
new file mode 100644
index 000000000000..8f0039a14693
--- /dev/null
+++ b/test/elf/X86_64/undef.test
@@ -0,0 +1,18 @@
+# This tests the functionality that an undefined symbol thats defined in the
+# commmand line pulls in the required object file from the archive library
+# which is usually the usecase for it
+RUN: lld -flavor gnu -target x86_64 -u fn %p/Inputs/libfn.a -o %t --noinhibit-exec
+RUN: llvm-readobj -symbols %t | FileCheck -check-prefix=SYMFROMARCHIVE %s
+RUN: lld -flavor gnu -target x86_64 %p/Inputs/libfn.a -o %t --noinhibit-exec
+RUN: llvm-readobj -symbols %t | FileCheck %s
+
+SYMFROMARCHIVE: Symbol {
+SYMFROMARCHIVE: Name: fn ({{[0-9]+}}
+SYMFROMARCHIVE: Size: 11
+SYMFROMARCHIVE: Binding: Global (0x1)
+SYMFROMARCHIVE: Type: Function (0x2)
+SYMFROMARCHIVE: Other: 0
+SYMFROMARCHIVE: Section: .text
+SYMFROMARCHIVE: }
+
+CHECK-NOT: Name: fn
diff --git a/test/elf/X86_64/underscore-end.test b/test/elf/X86_64/underscore-end.test
new file mode 100644
index 000000000000..337aa197f812
--- /dev/null
+++ b/test/elf/X86_64/underscore-end.test
@@ -0,0 +1,81 @@
+# This tests verifies that the value of _end symbol is point to the right value
+RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/nmagic.o \
+RUN: --noinhibit-exec -o %t --nmagic
+RUN: llvm-readobj -symbols %t | FileCheck -check-prefix=NMAGICABSSYMBOLS %s
+RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/nmagic.o \
+RUN: --noinhibit-exec -o %t --omagic
+RUN: llvm-readobj -symbols %t | FileCheck -check-prefix=OMAGICABSSYMBOLS %s
+
+NMAGICABSSYMBOLS: Symbol {
+NMAGICABSSYMBOLS: Name: __bss_start ({{[0-9]+}}
+NMAGICABSSYMBOLS: Value: 0x40100C
+NMAGICABSSYMBOLS: Size: 0
+NMAGICABSSYMBOLS: Binding: Global (0x1)
+NMAGICABSSYMBOLS: Type: Object (0x1)
+NMAGICABSSYMBOLS: Other: 0
+NMAGICABSSYMBOLS: Section: Absolute (0xFFF1)
+NMAGICABSSYMBOLS: }
+NMAGICABSSYMBOLS: Symbol {
+NMAGICABSSYMBOLS: Name: __bss_end ({{[0-9]+}}
+NMAGICABSSYMBOLS: Value: 0x40100C
+NMAGICABSSYMBOLS: Size: 0
+NMAGICABSSYMBOLS: Binding: Global (0x1)
+NMAGICABSSYMBOLS: Type: Object (0x1)
+NMAGICABSSYMBOLS: Other: 0
+NMAGICABSSYMBOLS: Section: Absolute (0xFFF1)
+NMAGICABSSYMBOLS: }
+NMAGICABSSYMBOLS: Symbol {
+NMAGICABSSYMBOLS: Name: _end ({{[0-9]+}}
+NMAGICABSSYMBOLS: Value: 0x40100C
+NMAGICABSSYMBOLS: Size: 0
+NMAGICABSSYMBOLS: Binding: Global (0x1)
+NMAGICABSSYMBOLS: Type: Object (0x1)
+NMAGICABSSYMBOLS: Other: 0
+NMAGICABSSYMBOLS: Section: Absolute (0xFFF1)
+NMAGICABSSYMBOLS: }
+NMAGICABSSYMBOLS: Symbol {
+NMAGICABSSYMBOLS: Name: end ({{[0-9]+}}
+NMAGICABSSYMBOLS: Value: 0x40100C
+NMAGICABSSYMBOLS: Size: 0
+NMAGICABSSYMBOLS: Binding: Global (0x1)
+NMAGICABSSYMBOLS: Type: Object (0x1)
+NMAGICABSSYMBOLS: Other: 0
+NMAGICABSSYMBOLS: Section: Absolute (0xFFF1)
+NMAGICABSSYMBOLS: }
+
+OMAGICABSSYMBOLS: Symbol {
+OMAGICABSSYMBOLS: Name: __bss_start ({{[0-9]+}})
+OMAGICABSSYMBOLS: Value: 0x400144
+OMAGICABSSYMBOLS: Size: 0
+OMAGICABSSYMBOLS: Binding: Global (0x1)
+OMAGICABSSYMBOLS: Type: Object (0x1)
+OMAGICABSSYMBOLS: Other: 0
+OMAGICABSSYMBOLS: Section: Absolute (0xFFF1)
+OMAGICABSSYMBOLS: }
+OMAGICABSSYMBOLS: Symbol {
+OMAGICABSSYMBOLS: Name: __bss_end ({{[0-9]+}}
+OMAGICABSSYMBOLS: Value: 0x400144
+OMAGICABSSYMBOLS: Size: 0
+OMAGICABSSYMBOLS: Binding: Global (0x1)
+OMAGICABSSYMBOLS: Type: Object (0x1)
+OMAGICABSSYMBOLS: Other: 0
+OMAGICABSSYMBOLS: Section: Absolute (0xFFF1)
+OMAGICABSSYMBOLS: }
+OMAGICABSSYMBOLS: Symbol {
+OMAGICABSSYMBOLS: Name: _end ({{[0-9]+}}
+OMAGICABSSYMBOLS: Value: 0x400144
+OMAGICABSSYMBOLS: Size: 0
+OMAGICABSSYMBOLS: Binding: Global (0x1)
+OMAGICABSSYMBOLS: Type: Object (0x1)
+OMAGICABSSYMBOLS: Other: 0
+OMAGICABSSYMBOLS: Section: Absolute (0xFFF1)
+OMAGICABSSYMBOLS: }
+OMAGICABSSYMBOLS: Symbol {
+OMAGICABSSYMBOLS: Name: end ({{[0-9]+}}
+OMAGICABSSYMBOLS: Value: 0x400144
+OMAGICABSSYMBOLS: Size: 0
+OMAGICABSSYMBOLS: Binding: Global (0x1)
+OMAGICABSSYMBOLS: Type: Object (0x1)
+OMAGICABSSYMBOLS: Other: 0
+OMAGICABSSYMBOLS: Section: Absolute (0xFFF1)
+OMAGICABSSYMBOLS: }
diff --git a/test/elf/X86_64/weak-override.test b/test/elf/X86_64/weak-override.test
new file mode 100644
index 000000000000..b68b449a6649
--- /dev/null
+++ b/test/elf/X86_64/weak-override.test
@@ -0,0 +1,45 @@
+# Test for weak symbol getting overridden
+RUN: lld -flavor gnu -target x86_64 %p/Inputs/weak.o %p/Inputs/ovrd.o \
+RUN: -o %t --noinhibit-exec
+RUN: llvm-nm %t | FileCheck -check-prefix=WEAKORDER %s
+RUN: lld -flavor gnu -target x86_64 %p/Inputs/weak.o \
+RUN: %p/Inputs/ovrd.o -o %t2 --output-filetype=yaml --noinhibit-exec
+RUN: FileCheck -check-prefix=WEAKATOMSORDER %s < %t2
+
+WEAKORDER: {{[0-9a-c]+}} T f
+
+WEAKATOMSORDER: references:
+WEAKATOMSORDER: - kind: layout-after
+WEAKATOMSORDER: offset: 0
+WEAKATOMSORDER: target: fn
+WEAKATOMSORDER: - name: fn
+WEAKATOMSORDER: references:
+WEAKATOMSORDER: - kind: layout-after
+WEAKATOMSORDER: offset: 0
+WEAKATOMSORDER: target: [[CONSTSTRA:[-a-zA-Z0-9_]+]]
+WEAKATOMSORDER: - ref-name: [[CONSTSTRA]]
+WEAKATOMSORDER: scope: global
+WEAKATOMSORDER: content: [ 55, 48, 89, E5, BF, 00, 00, 00, 00, E8, 00, 00,
+WEAKATOMSORDER: 00, 00, 5D, C3 ]
+WEAKATOMSORDER: references:
+WEAKATOMSORDER: - kind: layout-after
+WEAKATOMSORDER: offset: 0
+WEAKATOMSORDER: target: main
+WEAKATOMSORDER: - name: main
+WEAKATOMSORDER: scope: global
+WEAKATOMSORDER: content: [ 55, 48, 89, E5, B8, 00, 00, 00, 00, E8, 00, 00,
+WEAKATOMSORDER: 00, 00, B8, 00, 00, 00, 00, 5D, C3 ]
+WEAKATOMSORDER: references:
+WEAKATOMSORDER: - kind: R_X86_64_PC32
+WEAKATOMSORDER: offset: 10
+WEAKATOMSORDER: target: f
+WEAKATOMSORDER: addend: -4
+WEAKATOMSORDER: - ref-name: {{[0-9A-Z]+}}
+WEAKATOMSORDER: references:
+WEAKATOMSORDER: - kind: layout-after
+WEAKATOMSORDER: offset: 0
+WEAKATOMSORDER: target: f
+WEAKATOMSORDER: - name: f
+WEAKATOMSORDER: scope: global
+WEAKATOMSORDER: content: [ 55, 48, 89, E5, BF, 00, 00, 00, 00, E8, 00, 00,
+WEAKATOMSORDER: 00, 00, 5D, C3 ]
diff --git a/test/elf/X86_64/weak-zero-sized.test b/test/elf/X86_64/weak-zero-sized.test
new file mode 100644
index 000000000000..76e051064b9d
--- /dev/null
+++ b/test/elf/X86_64/weak-zero-sized.test
@@ -0,0 +1,26 @@
+# Test for zero sized weak atoms, there is only a single weak atom
+RUN: lld -flavor gnu -target x86_64 %p/Inputs/weak-zero-sized.o -o %t \
+RUN: --noinhibit-exec
+RUN: llvm-nm %t | FileCheck -check-prefix=WEAKORDER %s
+RUN: lld -flavor gnu -target x86_64 %p/Inputs/weak-zero-sized.o \
+RUN: --output-filetype=yaml -o %t2 --noinhibit-exec
+RUN: FileCheck -check-prefix=WEAKATOMSORDER %s < %t2
+
+WEAKORDER: 004001a4 T _start
+
+WEAKATOMSORDER: alignment: 2^2
+WEAKATOMSORDER: - kind: layout-after
+WEAKATOMSORDER: offset: 0
+WEAKATOMSORDER: target: [[TARGETC:[-a-zA-Z0-9_]+]]
+WEAKATOMSORDER: - name: [[TARGETA:[-a-zA-Z0-9_]+]]
+WEAKATOMSORDER: scope: global
+WEAKATOMSORDER: merge: as-weak
+WEAKATOMSORDER: alignment: 2^2
+WEAKATOMSORDER: references:
+WEAKATOMSORDER: - kind: layout-after
+WEAKATOMSORDER: offset: 0
+WEAKATOMSORDER: target: [[TARGETC]]
+WEAKATOMSORDER: - ref-name: [[TARGETC]]
+WEAKATOMSORDER: scope: global
+WEAKATOMSORDER: content: [ C3 ]
+WEAKATOMSORDER: alignment: 2^2
diff --git a/test/elf/X86_64/weaksym.test b/test/elf/X86_64/weaksym.test
new file mode 100644
index 000000000000..d44ca8a36968
--- /dev/null
+++ b/test/elf/X86_64/weaksym.test
@@ -0,0 +1,78 @@
+# Tests that an executable with a weak undefine will put this symbol in the
+# dynamic symbol table if the executable has a dynamic relocation against this
+# symbol.
+
+#RUN: yaml2obj --format elf %s -o %t.o
+#RUN: lld -flavor gnu -target x86_64 -e main %t.o -o %t1
+#RUN: llvm-readobj -dt %t1 | FileCheck -check-prefix CHECKSYMS %s
+
+#CHECKSYMS: Name: x@
+#CHECKSYMS-NEXT: Value: 0x0
+#CHECKSYMS-NEXT: Size: 0
+#CHECKSYMS-NEXT: Binding: Weak (0x2)
+#CHECKSYMS-NEXT: Type: None (0x0)
+#CHECKSYMS-NEXT: Other: 0
+#CHECKSYMS-NEXT: Section: Undefined (0x0)
+
+# The object file above corresponds to the following C program compiled with
+# -fPIC:
+# extern int *x __attribute__((weak));
+#
+# int main() {
+# if (x)
+# return 1;
+# return 0;
+# }
+
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000010
+ Content: 554889E5488B0500000000C745FC00000000488138000000000F840C000000C745FC01000000E907000000C745FC000000008B45FC5DC3
+ - Name: .rela.text
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .text
+ Relocations:
+ - Offset: 0x0000000000000007
+ Symbol: x
+ Type: R_X86_64_GOTPCREL
+ Addend: -4
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ Global:
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x0000000000000037
+ - Name: _GLOBAL_OFFSET_TABLE_
+ Weak:
+ - Name: x
diff --git a/test/elf/X86_64/yamlinput.test b/test/elf/X86_64/yamlinput.test
new file mode 100644
index 000000000000..6e529b41b7a6
--- /dev/null
+++ b/test/elf/X86_64/yamlinput.test
@@ -0,0 +1,166 @@
+# This tests the functionality that lld is able to read
+# an input YAML from a previous link
+
+RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/initfini.o \
+RUN: --noinhibit-exec --output-filetype=yaml -o %t.objtxt
+RUN: lld -flavor gnu -target x86_64-linux %t.objtxt \
+RUN: --noinhibit-exec -o %t1
+RUN: llvm-readobj -sections %t1 | FileCheck %s -check-prefix=SECTIONS
+
+SECTIONS: Section {
+SECTIONS: Index: 0
+SECTIONS: Name: (0)
+SECTIONS: Type: SHT_NULL (0x0)
+SECTIONS: Flags [ (0x0)
+SECTIONS: ]
+SECTIONS: }
+SECTIONS: Section {
+SECTIONS: Index: 1
+SECTIONS: Name: .interp
+SECTIONS: Type: SHT_PROGBITS (0x1)
+SECTIONS: Flags [ (0x2)
+SECTIONS: SHF_ALLOC (0x2)
+SECTIONS: ]
+SECTIONS: }
+SECTIONS: Section {
+SECTIONS: Index: 2
+SECTIONS: Name: .hash
+SECTIONS: Type: SHT_HASH (0x5)
+SECTIONS: Flags [ (0x2)
+SECTIONS: SHF_ALLOC (0x2)
+SECTIONS: ]
+SECTIONS: }
+SECTIONS: Section {
+SECTIONS: Index: 3
+SECTIONS: Name: .dynsym
+SECTIONS: Type: SHT_DYNSYM (0xB)
+SECTIONS: Flags [ (0x2)
+SECTIONS: SHF_ALLOC (0x2)
+SECTIONS: ]
+SECTIONS: }
+SECTIONS: Section {
+SECTIONS: Index: 4
+SECTIONS: Name: .dynstr
+SECTIONS: Type: SHT_STRTAB (0x3)
+SECTIONS: Flags [ (0x2)
+SECTIONS: SHF_ALLOC (0x2)
+SECTIONS: ]
+SECTIONS: }
+SECTIONS: Section {
+SECTIONS: Index: 5
+SECTIONS: Name: .text
+SECTIONS: Type: SHT_PROGBITS (0x1)
+SECTIONS: Flags [ (0x6)
+SECTIONS: SHF_ALLOC (0x2)
+SECTIONS: SHF_EXECINSTR (0x4)
+SECTIONS: ]
+SECTIONS: }
+SECTIONS: Section {
+SECTIONS: Index: 6
+SECTIONS: Name: .rodata
+SECTIONS: Type: SHT_PROGBITS (0x1)
+SECTIONS: Flags [ (0x2)
+SECTIONS: SHF_ALLOC (0x2)
+SECTIONS: ]
+SECTIONS: }
+SECTIONS: Section {
+SECTIONS: Index: 7
+SECTIONS: Name: .eh_frame
+SECTIONS: Type: SHT_PROGBITS (0x1)
+SECTIONS: Flags [ (0x2)
+SECTIONS: SHF_ALLOC (0x2)
+SECTIONS: ]
+SECTIONS: }
+SECTIONS: Section {
+SECTIONS: Index: 8
+SECTIONS: Name: .eh_frame_hdr
+SECTIONS: }
+SECTIONS: Section {
+SECTIONS: Index: 9
+SECTIONS: Name: .init_array
+SECTIONS: Type: SHT_PROGBITS (0x1)
+SECTIONS: Flags [ (0x3)
+SECTIONS: SHF_ALLOC (0x2)
+SECTIONS: SHF_WRITE (0x1)
+SECTIONS: ]
+SECTIONS: }
+SECTIONS: Section {
+SECTIONS: Index: 10
+SECTIONS: Name: .fini_array
+SECTIONS: Type: SHT_PROGBITS (0x1)
+SECTIONS: Flags [ (0x3)
+SECTIONS: SHF_ALLOC (0x2)
+SECTIONS: SHF_WRITE (0x1)
+SECTIONS: ]
+SECTIONS: }
+SECTIONS: Section {
+SECTIONS: Index: 11
+SECTIONS: Name: .dynamic
+SECTIONS: Type: SHT_DYNAMIC (0x6)
+SECTIONS: Flags [ (0x3)
+SECTIONS: SHF_ALLOC (0x2)
+SECTIONS: SHF_WRITE (0x1)
+SECTIONS: ]
+SECTIONS: }
+SECTIONS: Section {
+SECTIONS: Index: 12
+SECTIONS: Name: .got.plt
+SECTIONS: Type: SHT_PROGBITS (0x1)
+SECTIONS: Flags [ (0x3)
+SECTIONS: SHF_ALLOC (0x2)
+SECTIONS: SHF_WRITE (0x1)
+SECTIONS: ]
+SECTIONS: }
+SECTIONS: Section {
+SECTIONS: Index: 13
+SECTIONS: Name: .data
+SECTIONS: Type: SHT_PROGBITS (0x1)
+SECTIONS: Flags [ (0x3)
+SECTIONS: SHF_ALLOC (0x2)
+SECTIONS: SHF_WRITE (0x1)
+SECTIONS: ]
+SECTIONS: }
+SECTIONS: Section {
+SECTIONS: Index: 14
+SECTIONS: Name: .bss
+SECTIONS: Type: SHT_NOBITS (0x8)
+SECTIONS: Flags [ (0x3)
+SECTIONS: SHF_ALLOC (0x2)
+SECTIONS: SHF_WRITE (0x1)
+SECTIONS: ]
+SECTIONS: }
+SECTIONS: Section {
+SECTIONS: Index: 15
+SECTIONS: Name: .comment
+SECTIONS: Type: SHT_PROGBITS (0x1)
+SECTIONS: Flags [ (0x0)
+SECTIONS: ]
+SECTIONS: }
+SECTIONS: Section {
+SECTIONS: Index: 16
+SECTIONS: Name: .note.GNU-stack
+SECTIONS: Type: SHT_PROGBITS (0x1)
+SECTIONS: Flags [ (0x0)
+SECTIONS: ]
+SECTIONS: }
+SECTIONS: Section {
+SECTIONS: Index: 17
+SECTIONS: Name: .shstrtab
+SECTIONS: Type: SHT_STRTAB (0x3)
+SECTIONS: Flags [ (0x0)
+SECTIONS: ]
+SECTIONS: }
+SECTIONS: Section {
+SECTIONS: Index: 18
+SECTIONS: Name: .symtab
+SECTIONS: Type: SHT_SYMTAB (0x2)
+SECTIONS: Flags [ (0x0)
+SECTIONS: ]
+SECTIONS: }
+SECTIONS: Section {
+SECTIONS: Index: 19
+SECTIONS: Name: .strtab
+SECTIONS: Type: SHT_STRTAB (0x3)
+SECTIONS: Flags [ (0x0)
+SECTIONS: ]
+SECTIONS: }
diff --git a/test/elf/abs-dup.objtxt b/test/elf/abs-dup.objtxt
new file mode 100644
index 000000000000..7340a29b0f00
--- /dev/null
+++ b/test/elf/abs-dup.objtxt
@@ -0,0 +1,19 @@
+# Tests handling an absolute symbol with no name
+# RUN: lld -flavor gnu -target x86_64 -r %s \
+# RUN: --output-filetype=yaml | FileCheck %s
+
+absolute-atoms:
+ - name: abs
+ scope: static
+ value: 0x10
+ - name: ''
+ scope: static
+ value: 0x15
+
+# CHECK: absolute-atoms:
+# CHECK: - name: abs
+# CHECK: scope: static
+# CHECK: value: 0x0000000000000010
+# CHECK: - name: ''
+# CHECK: scope: static
+# CHECK: value: 0x0000000000000015
diff --git a/test/elf/abs.test b/test/elf/abs.test
new file mode 100644
index 000000000000..bad74f10d194
--- /dev/null
+++ b/test/elf/abs.test
@@ -0,0 +1,19 @@
+#
+# Source File:
+# .local absGlobalSymbol
+# .set absLocalSymbol,0xC0000
+# .type absLocalSymbol, @object
+# .globl absGlobalSymbol
+# .set absGlobalSymbol,0xD0000
+# .type absGlobalSymbol, @object
+
+# built using: "gcc -m32"
+#
+RUN: lld -flavor gnu -target i386 --output-filetype=yaml -r %p/Inputs/abs-test.i386 | FileCheck -check-prefix=YAML %s
+
+YAML: absolute-atoms:
+YAML: - name: absLocalSymbol
+YAML: value: {{0x[0]+C0000}}
+YAML: - name: absGlobalSymbol
+YAML: scope: global
+YAML: value: {{0x[0]+D0000}}
diff --git a/test/elf/allowduplicates.objtxt b/test/elf/allowduplicates.objtxt
new file mode 100644
index 000000000000..dbad3bd312ed
--- /dev/null
+++ b/test/elf/allowduplicates.objtxt
@@ -0,0 +1,51 @@
+# RUN: lld -flavor gnu -target x86_64 --allow-multiple-definition %s \
+# RUN: --output-filetype=yaml --noinhibit-exec | FileCheck %s
+#
+# RUN: not lld -flavor gnu -target x86_64 %s --output-filetype=yaml \
+# RUN: --noinhibit-exec 2>&1 | FileCheck -check-prefix=ERROR %s
+#
+# RUN: lld -flavor gnu -target x86_64 -z muldefs %s \
+# RUN: --noinhibit-exec --output-filetype=yaml | FileCheck %s
+
+---
+defined-atoms:
+ - name: .text
+ alignment: 2^4
+ section-choice: custom-required
+ section-name: .text
+ - name: main
+ scope: global
+ content: [ B8, 00, 00, 00, 00, C7, 44, 24, FC, 00, 00, 00,
+ 00, C3 ]
+ alignment: 2^4
+ section-choice: custom-required
+ section-name: .text
+---
+defined-atoms:
+ - name: .text
+ alignment: 2^4
+ section-choice: custom-required
+ section-name: .text
+ - name: main
+ scope: global
+ content: [ B8, 00, 00, 00, 00, C7, 44, 24, FC, 00, 00, 00,
+ 00, C3 ]
+ alignment: 2^4
+ section-choice: custom-required
+ section-name: .text
+---
+
+# CHECK: defined-atoms:
+# CHECK: - name: .text
+# CHECK: alignment: 2^4
+# CHECK: section-choice: custom-required
+# CHECK: section-name: .text
+# CHECK: - name: main
+# CHECK: scope: global
+# CHECK: content: [ B8, 00, 00, 00, 00, C7, 44, 24, FC, 00, 00, 00,
+# CHECK: 00, C3 ]
+# CHECK: alignment: 2^4
+# CHECK: section-choice: custom-required
+# CHECK: section-name: .text
+
+# ERROR: duplicate symbol error
diff --git a/test/elf/archive-elf-forceload.test b/test/elf/archive-elf-forceload.test
new file mode 100644
index 000000000000..a0d115094815
--- /dev/null
+++ b/test/elf/archive-elf-forceload.test
@@ -0,0 +1,43 @@
+# Tests the functionality of archive libraries reading
+# and resolution
+# Note: The binary files would not be required once we have support to generate
+# binary archives from textual(yaml) input
+#
+# Tests generated using the source files below
+# main file
+# int main()
+# {
+# fn();
+# return 0;
+# }
+#
+# archive file
+# int fn()
+# {
+# return 0;
+# }
+#
+# int fn1()
+# {
+# return 0;
+# }
+# gcc -c main.c fn.c fn1.c
+
+RUN: lld -flavor gnu -target x86_64-linux -e main %p/Inputs/mainobj.x86_64 \
+RUN: --whole-archive %p/Inputs/libfnarchive.a --no-whole-archive --output-filetype=yaml \
+RUN: | FileCheck -check-prefix FORCELOAD %s
+
+FORCELOAD: defined-atoms:
+FORCELOAD: - name: fn1
+FORCELOAD: scope: global
+FORCELOAD: content: [ 55, 48, 89, E5, B8, 00, 00, 00, 00, 5D, C3 ]
+FORCELOAD: - name: fn
+FORCELOAD: scope: global
+FORCELOAD: content: [ 55, 48, 89, E5, B8, 00, 00, 00, 00, 5D, C3 ]
+FORCELOAD: absolute-atoms:
+FORCELOAD: - name: main.c
+FORCELOAD: value: 0x0
+FORCELOAD: - name: fn1.c
+FORCELOAD: value: 0x0
+FORCELOAD: - name: fn.c
+FORCELOAD: value: 0x0
diff --git a/test/elf/archive-elf.test b/test/elf/archive-elf.test
new file mode 100644
index 000000000000..ba6774644cbd
--- /dev/null
+++ b/test/elf/archive-elf.test
@@ -0,0 +1,38 @@
+# Tests the functionality of archive libraries reading
+# and resolution
+# Note: The binary files would not be required once we have support to generate
+# binary archives from textual(yaml) input
+#
+# Tests generated using the source files below
+# main file
+# int main()
+# {
+# fn();
+# return 0;
+# }
+#
+# archive file
+# int fn()
+# {
+# return 0;
+# }
+#
+# int fn1()
+# {
+# return 0;
+# }
+# gcc -c main.c fn.c fn1.c
+
+RUN: lld -flavor gnu -target x86_64-linux --output-filetype=yaml -r \
+RUN: %p/Inputs/mainobj.x86_64 %p/Inputs/libfnarchive.a | \
+RUN: FileCheck -check-prefix NOFORCELOAD %s
+
+NOFORCELOAD: defined-atoms:
+NOFORCELOAD: - name: fn
+NOFORCELOAD: scope: global
+NOFORCELOAD: content: [ 55, 48, 89, E5, B8, 00, 00, 00, 00, 5D, C3 ]
+NOFORCELOAD: absolute-atoms:
+NOFORCELOAD: - name: main.c
+NOFORCELOAD: value: 0x0
+NOFORCELOAD: - name: fn.c
+NOFORCELOAD: value: 0x0
diff --git a/test/elf/as-needed.test b/test/elf/as-needed.test
new file mode 100644
index 000000000000..4477f0fe0ca6
--- /dev/null
+++ b/test/elf/as-needed.test
@@ -0,0 +1,15 @@
+RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/use-shared.x86-64 \
+RUN: --as-needed %p/Inputs/shared.so-x86-64 %p/Inputs/libifunc.x86-64.so \
+RUN: -o %t1 -e main --allow-shlib-undefined
+RUN: llvm-readobj -dynamic-table %t1 | FileCheck %s -check-prefix AS_NEEDED
+
+AS_NEEDED: NEEDED SharedLibrary (shared.so-x86-64)
+AS_NEEDED-NOT: NEEDED SharedLibrary (libifunc.x86-64.so)
+
+RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/use-shared.x86-64 \
+RUN: %p/Inputs/shared.so-x86-64 %p/Inputs/libifunc.x86-64.so \
+RUN: -o %t2 -e main --allow-shlib-undefined
+RUN: llvm-readobj -dynamic-table %t2 | FileCheck %s -check-prefix NO_AS_NEEDED
+
+NO_AS_NEEDED: NEEDED SharedLibrary (shared.so-x86-64)
+NO_AS_NEEDED: NEEDED SharedLibrary (libifunc.x86-64.so)
diff --git a/test/elf/branch.test b/test/elf/branch.test
new file mode 100644
index 000000000000..5e0b4a5aabf1
--- /dev/null
+++ b/test/elf/branch.test
@@ -0,0 +1,34 @@
+RUN: lld -flavor gnu -target hexagon -static --output-filetype=yaml \
+RUN: %p/Inputs/branch-test.hexagon %p/Inputs/target-test.hexagon --noinhibit-exec | FileCheck %s -check-prefix hexagon-yaml
+RUN: lld -flavor gnu -target hexagon -e target -o %t1 \
+RUN: %p/Inputs/branch-test.hexagon %p/Inputs/target-test.hexagon --noinhibit-exec
+RUN: llvm-readobj -h %t1 | FileCheck -check-prefix=hexagon-readobj %s
+
+hexagon-yaml: - name: back
+hexagon-yaml: scope: global
+hexagon-yaml: content: [ 00, C0, 00, 7F, 00, C0, 00, 5A, 00, 00, 00, 00,
+hexagon-yaml: 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00 ]
+hexagon-yaml: references:
+hexagon-yaml: - kind:
+hexagon-yaml: offset: 4
+hexagon-yaml: target: target
+
+hexagon-yaml: - name: target
+hexagon-yaml: scope: global
+hexagon-yaml: content: [ 00, C0, 00, 5A ]
+hexagon-yaml: references:
+hexagon-yaml: - kind:
+hexagon-yaml: offset: 0
+hexagon-yaml: target: back
+
+
+hexagon-readobj: ElfHeader {
+hexagon-readobj: Ident {
+hexagon-readobj: Class: 32-bit (0x1)
+hexagon-readobj: DataEncoding: LittleEndian (0x1)
+hexagon-readobj: FileVersion: 1
+hexagon-readobj: OS/ABI: SystemV (0x0)
+hexagon-readobj: ABIVersion: 0
+hexagon-readobj: }
+hexagon-readobj: Type: Executable (0x2)
+hexagon-readobj: Machine: EM_HEXAGON (0xA4)
diff --git a/test/elf/check.test b/test/elf/check.test
new file mode 100644
index 000000000000..336b7fc1335c
--- /dev/null
+++ b/test/elf/check.test
@@ -0,0 +1,39 @@
+# This tests the basic functionality of ordering data and functions as they
+# appear in the inputs
+RUN: lld -flavor gnu -target i386 -e global_func --noinhibit-exec --output-filetype=yaml \
+RUN: %p/Inputs/object-test.elf-i386 -o %t
+RUN: FileCheck %s -check-prefix ELF-i386 < %t
+RUN: lld -flavor gnu -target hexagon -e global_func --noinhibit-exec --output-filetype=yaml \
+RUN: %p/Inputs/object-test.elf-hexagon -o %t1
+RUN: FileCheck %s -check-prefix ELF-hexagon < %t1
+
+ELF-i386: defined-atoms:
+ELF-i386: - name: global_func
+ELF-i386: - name: static_func
+ELF-i386: - name: weak_func
+ELF-i386: - name: hidden_func
+ELF-i386: - name: no_dead_strip
+ELF-i386: - name: no_special_section_func
+ELF-i386: - name: global_variable
+ELF-i386: - name: uninitialized_static_variable
+ELF-i386: - name: special_section_func
+ELF-i386: undefined-atoms:
+ELF-i386: - name: puts
+ELF-i386: absolute-atoms:
+ELF-i386: - name: sample.c
+
+ELF-hexagon: - name: global_func
+ELF-hexagon: - name: static_func
+ELF-hexagon: - name: weak_func
+ELF-hexagon: - name: hidden_func
+ELF-hexagon: - name: no_dead_strip
+ELF-hexagon: - name: no_special_section_func
+ELF-hexagon: - name: global_variable
+ELF-hexagon: - name: uninitialized_static_variable
+ELF-hexagon: - name: special_section_func
+ELF-hexagon: undefined-atoms:
+ELF-hexagon: - name: puts
+ELF-hexagon: absolute-atoms:
+ELF-hexagon: - name: sample.c
+ELF-hexagon: scope: static
+ELF-hexagon: value: 0x0000000000000000
diff --git a/test/elf/checkrodata.test b/test/elf/checkrodata.test
new file mode 100644
index 000000000000..fc75657b4afb
--- /dev/null
+++ b/test/elf/checkrodata.test
@@ -0,0 +1,9 @@
+
+RUN: lld -flavor gnu -target i386 -o %t1 %p/Inputs/rodata-test.i386 --noinhibit-exec
+RUN: llvm-objdump -section-headers %t1 | FileCheck -check-prefix=i386 %s
+RUN: lld -flavor gnu -target hexagon -o %t2 %p/Inputs/rodata-test.hexagon --noinhibit-exec
+RUN: llvm-objdump -section-headers %t2 | FileCheck -check-prefix=hexagon %s
+
+i386: .rodata 00000004 0000000000000114 DATA
+
+hexagon: .rodata 00000004 0000000000000114 DATA
diff --git a/test/elf/common.test b/test/elf/common.test
new file mode 100644
index 000000000000..46fcfe39d486
--- /dev/null
+++ b/test/elf/common.test
@@ -0,0 +1,10 @@
+RUN: lld -flavor gnu -target x86_64-linux -o %t %p/Inputs/relocs.x86-64 \
+RUN: -e _start -static
+RUN: llvm-readobj -t %t | FileCheck %s
+
+CHECK: Symbol {
+CHECK: Name: i
+CHECK-NEXT: Value:
+CHECK-NEXT: Size:
+CHECK-NEXT: Binding:
+CHECK-NEXT: Type: Object
diff --git a/test/elf/consecutive-weak-sym-defs.test b/test/elf/consecutive-weak-sym-defs.test
new file mode 100644
index 000000000000..095fabb17ab8
--- /dev/null
+++ b/test/elf/consecutive-weak-sym-defs.test
@@ -0,0 +1,81 @@
+#Tests that multiple consecutive weak symbol definitions do not confuse the
+#ELF reader. For example:
+#
+# my_weak_func1:
+# my_weak_func2:
+# my_weak_func3:
+# code
+#
+#If my_weak_func2 is merged to other definition, this should not disturb the
+#definition my_weak_func1 to "code".
+#
+#
+#RUN: yaml2obj -format=elf %p/Inputs/consecutive-weak-defs.o.yaml -o=%t1.o
+#RUN: yaml2obj -format=elf %p/Inputs/main-with-global-def.o.yaml -o=%t2.o
+#RUN: lld -flavor gnu -target x86_64 %t1.o %t2.o -e=main -o %t1
+#RUN: obj2yaml %t1 | FileCheck -check-prefix CHECKLAYOUT %s
+#
+# Check that the layout has not been changed:
+#
+#CHECKLAYOUT: Name: .text
+#CHECKLAYOUT-NEXT: Type:
+#CHECKLAYOUT-NEXT: Flags:
+#CHECKLAYOUT-NEXT: Address:
+#CHECKLAYOUT-NEXT: AddressAlign:
+#CHECKLAYOUT-NEXT: Content: 554889E5E8020000005DC3554889E5B8640000005DC3
+# ^~~> my_func ^~~> my_weak_func
+#
+#
+#
+#Our two input files were produced by the following code:
+#
+#Inputs/consecutive-weak-defs.o.yaml (this one is in assembly to allow us to
+# easily define multiple labels)
+#
+# .text
+# .globl my_func
+# .type my_func,@function
+# my_func:
+# pushq %rbp
+# movq %rsp, %rbp
+# callq my_weak_func
+# popq %rbp
+# retq
+# .Ltmp0:
+# .size my_func, .Ltmp0-my_func
+#
+# .text
+# .weak my_weak_func
+# .type my_weak_func,@function
+# .weak my_weak_func2
+# .type my_weak_func2,@function
+# .weak my_weak_func3
+# .type my_weak_func3,@function
+# my_weak_func:
+# my_weak_func2:
+# my_weak_func3:
+# pushq %rbp
+# movq %rsp, %rbp
+# movl $100, %eax
+# popq %rbp
+# retq
+# .Ltmp1:
+# .size my_weak_func, .Ltmp1-my_weak_func
+# .size my_weak_func2, .Ltmp1-my_weak_func2
+# .size my_weak_func3, .Ltmp1-my_weak_func3
+#
+#Inputs/main-with-global-def.o.yaml:
+#
+# int my_func();
+#
+# int my_weak_func2() {
+# return 200;
+# }
+#
+# int main() {
+# return my_func();
+# }
+#
+#-------------------------------------------------------------------------------
+# The net effect is that this program should return 100.
+
diff --git a/test/elf/defsym.objtxt b/test/elf/defsym.objtxt
new file mode 100644
index 000000000000..e9c3922d5994
--- /dev/null
+++ b/test/elf/defsym.objtxt
@@ -0,0 +1,28 @@
+# RUN: lld -flavor gnu -target x86_64 --defsym=foo=0x1234 -r %s \
+# RUN: --output-filetype=yaml | FileCheck -check-prefix=ABS %s
+
+# RUN: lld -flavor gnu -target x86_64 --defsym=foo=main -r %s \
+# RUN: --output-filetype=yaml | FileCheck -check-prefix=ALIAS %s
+
+defined-atoms:
+ - name: main
+ scope: global
+ content: [ B8, 00, 00, 00, 00, C7, 44, 24, FC, 00, 00, 00, 00, C3 ]
+ alignment: 2^4
+ section-choice: custom-required
+ section-name: .text
+
+# ABS: absolute-atoms:
+# ABS: - name: foo
+# ABS: scope: global
+# ABS: value: 0x0000000000001234
+
+# ALIAS: defined-atoms:
+# ALIAS: - name: foo
+# ALIAS: scope: global
+# ALIAS: section-choice: custom-required
+# ALIAS: section-name: .text
+# ALIAS: references:
+# ALIAS: - kind: layout-after
+# ALIAS: offset: 0
+# ALIAS: target: main
diff --git a/test/elf/dynamic-segorder.test b/test/elf/dynamic-segorder.test
new file mode 100644
index 000000000000..1fdccec9921b
--- /dev/null
+++ b/test/elf/dynamic-segorder.test
@@ -0,0 +1,17 @@
+RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/tls.x86-64 \
+RUN: %p/Inputs/shared.so-x86-64 -o %t -e main --allow-shlib-undefined \
+RUN: --defsym=__tls_get_addr=0
+RUN: llvm-objdump -p %t | FileCheck %s
+
+CHECK: PHDR
+CHECK: flags r-x
+CHECK: INTERP
+CHECK: flags r--
+CHECK: LOAD
+CHECK: flags r-x
+CHECK: LOAD
+CHECK: flags rw-
+CHECK: DYNAMIC
+CHECK: flags rw-
+CHECK: TLS
+CHECK: flags rw-
diff --git a/test/elf/dynamic-undef.test b/test/elf/dynamic-undef.test
new file mode 100644
index 000000000000..7506b21b3ca7
--- /dev/null
+++ b/test/elf/dynamic-undef.test
@@ -0,0 +1,34 @@
+#
+# This test creates a executable and tests the options that are used to
+# to create an executable and a shared library
+#
+# This test will fail because there are unresolved symbols from the shared
+# library and we are not passing --allow-shlib-undefined
+RUN: not lld -flavor gnu -target x86_64-linux %p/Inputs/tls.x86-64 \
+RUN: %p/Inputs/shared.so-x86-64 -o %t -e main 2> %t1
+RUN: FileCheck -check-prefix=EXEC %s < %t1
+# This test will pass because of --allow-shlib-undefined
+RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/tls.x86-64 \
+RUN: %p/Inputs/shared.so-x86-64 -o %t -e main --allow-shlib-undefined \
+RUN: --defsym=__tls_get_addr=0
+# Building shared libraries should not fail when there is a undefined symbol.
+# Test creation of shared library, this should pass because we are using
+# shared option and by default, dynamic library wouldn't create undefined atoms
+# from the input shared library
+RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/tls.x86-64 \
+RUN: %p/Inputs/shared.so-x86-64 -o %t.usenoundefines -e main -shared
+RUN: llvm-readobj -symbols %t.usenoundefines | FileCheck %s -check-prefix=SHLIB-NOUNDEF
+# Test creation of shared library, this should fail because we are using
+# shared option setting the options to use the shared library undefines to
+# create undefined atoms from the input shared library
+RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/tls.x86-64 \
+RUN: %p/Inputs/shared.so-x86-64 -o %t.useundefines -e main -shared \
+RUN: --use-shlib-undefines --no-allow-shlib-undefined 2> %t2
+RUN: llvm-readobj -symbols %t.useundefines | FileCheck -check-prefix=SHLIB-UNDEF-SYMBOLS %s
+
+EXEC: Undefined symbol: {{.+[\\/]}}shared.so-x86-64: puts
+SHLIB: Undefined symbol: {{.+[\\/]}}shared.so-x86-64: puts
+EXEC-NOT: Undefined symbol: {{.+[\\/]}}shared.so-x86-64: weakfoo
+SHLIB-NOT: Undefined symbol: {{.+[\\/]}}shared.so-x86-64: weakfoo
+SHLIB-NOUNDEF-NOT: Name: puts
+SHLIB-UNDEF-SYMBOLS: Name: puts
diff --git a/test/elf/dynamic.test b/test/elf/dynamic.test
new file mode 100644
index 000000000000..59269612cf8e
--- /dev/null
+++ b/test/elf/dynamic.test
@@ -0,0 +1,80 @@
+# Checks functionality of dynamic executables
+RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/use-shared.x86-64 \
+RUN: %p/Inputs/shared.so-x86-64 -o %t -e main --allow-shlib-undefined \
+RUN: -rpath /l1:/l2 -rpath /l3
+RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/use-shared.x86-64 \
+RUN: %p/Inputs/shared.so-x86-64 --output-filetype=yaml -o %t2 --allow-shlib-undefined \
+RUN: --noinhibit-exec
+RUN: llvm-objdump -p %t >> %t2
+RUN: llvm-readobj -s -dyn-symbols -dynamic-table %t >> %t2
+RUN: FileCheck %s < %t2
+
+CHECK: name: main
+CHECK: kind: R_X86_64_PC32
+CHECK: offset: 18
+CHECK: target: [[PLTNAME:[-a-zA-Z0-9_]+]]
+
+CHECK: name: [[PLTNAME]]
+CHECK: type: stub
+
+CHECK: type: got
+CHECK: references:
+CHECK: kind: R_X86_64_JUMP_SLOT
+
+CHECK: shared-library-atoms:
+CHECK: name: foo
+CHECK: load-name: shared.so-x86-64
+
+CHECK: PHDR off 0x{{0+}}40
+CHECK: INTERP
+CHECK: flags r--
+
+CHECK: Section {
+CHECK: Name: .hash
+CHECK-NEXT: Type: SHT_HASH
+CHECK-NEXT: Flags [
+CHECK-NEXT: SHF_ALLOC
+CHECK-NEXT: ]
+CHECK-NEXT: Address:
+CHECK-NEXT: Offset:
+CHECK-NEXT: Size: 32
+CHECK-NEXT: Link:
+CHECK-NEXT: Info:
+CHECK-NEXT: AddressAlignment: 8
+CHECK-NEXT: EntrySize:
+CHECK-NEXT: }
+
+CHECK: DynamicSymbols [
+CHECK: Symbol {
+CHECK: Name: foo
+CHECK-NEXT: Value: 0
+CHECK-NEXT: Size:
+CHECK-NEXT: Binding: Global
+CHECK-NEXT: Type: Function
+CHECK: }
+CHECK: Symbol {
+CHECK: Name: i
+CHECK-NEXT: Value: 0
+CHECK-NEXT: Size:
+CHECK-NEXT: Binding: Global
+CHECK-NEXT: Type: Object
+CHECK: }
+
+CHECK: DynamicSection [ (15 entries)
+CHECK: Tag Type Name/Value
+CHECK: 0x0000000000000004 HASH
+CHECK: 0x0000000000000005 STRTAB
+CHECK: 0x0000000000000006 SYMTAB
+CHECK: 0x000000000000000A STRSZ
+CHECK: 0x000000000000000B SYMENT 24
+CHECK: 0x0000000000000007 RELA
+CHECK: 0x0000000000000008 RELASZ 24
+CHECK: 0x0000000000000009 RELAENT 24
+CHECK: 0x0000000000000002 PLTRELSZ 24
+CHECK: 0x0000000000000003 PLTGOT
+CHECK: 0x0000000000000014 PLTREL RELA
+CHECK: 0x0000000000000017 JMPREL
+CHECK: 0x0000000000000001 NEEDED SharedLibrary (shared.so-x86-64)
+CHECK: 0x000000000000000F RPATH /l1:/l2:/l3
+CHECK: 0x0000000000000000 NULL 0x0
+CHECK: ]
diff --git a/test/elf/eh_frame_hdr.test b/test/elf/eh_frame_hdr.test
new file mode 100644
index 000000000000..31429857ec69
--- /dev/null
+++ b/test/elf/eh_frame_hdr.test
@@ -0,0 +1,30 @@
+#RUN: yaml2obj -format=elf %s > %t
+#RUN: lld -flavor gnu -target x86_64-linux %t --noinhibit-exec \
+#RUN: -o %t1
+#RUN: llvm-objdump -s %t1 | FileCheck %s
+
+!ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+
+Sections:
+- Name: .eh_frame
+ Type: SHT_PROGBITS
+ Content: "00"
+ AddressAlign: 8
+ Flags: [SHF_ALLOC]
+
+Symbols:
+ Local:
+ - Name: .eh_frame
+ Type: STT_SECTION
+ Section: .eh_frame
+
+# CHECK: Contents of section .eh_frame:
+# CHECK-NEXT: 4001e0 00
+# CHECK-NEXT: Contents of section .eh_frame_hdr:
+# CHECK-NEXT: 4001e8 011bffff f4ffffff
+# ^ 0x4001e0 - 0x4001e8 - 4 = 0xfffffff4
diff --git a/test/elf/entry.objtxt b/test/elf/entry.objtxt
new file mode 100644
index 000000000000..7e0c1623565a
--- /dev/null
+++ b/test/elf/entry.objtxt
@@ -0,0 +1,58 @@
+# Tests entry point handling
+#
+# Test generated using the source file below:
+#
+# int main()
+# {
+# return 0;
+# }
+#
+
+# RUN: lld -flavor gnu -target x86_64 %s -e _entrypoint --noinhibit-exec -o %t1
+# RUN: llvm-nm -n %t1 | FileCheck %s
+#
+# CHECK: 004001e0 T main
+# CHECK: 00401000 D _DYNAMIC
+# CHECK: 00401060 A _end
+# CHECK: 00401060 A end
+# CHECK: U _entrypoint
+
+defined-atoms:
+ - name: .text
+ alignment: 2^4
+ section-choice: custom-required
+ section-name: .text
+ - name: main
+ scope: global
+ content: [ B8, 00, 00, 00, 00, C7, 44, 24, FC, 00, 00, 00,
+ 00, C3 ]
+ alignment: 2^4
+ section-choice: custom-required
+ section-name: .text
+ - name: .data
+ type: data
+ alignment: 2^2
+ section-choice: custom-required
+ section-name: .data
+ - name: .bss
+ type: zero-fill
+ alignment: 2^2
+ section-choice: custom-required
+ section-name: .bss
+ - name: .note.GNU-stack
+ section-choice: custom-required
+ section-name: .note.GNU-stack
+ permissions: r--
+ - name: .eh_frame
+ content: [ 14, 00, 00, 00, 00, 00, 00, 00, 01, 7A, 52, 00,
+ 01, 78, 10, 01, 1B, 0C, 07, 08, 90, 01, 00, 00,
+ 14, 00, 00, 00, 1C, 00, 00, 00, 00, 00, 00, 00,
+ 0E, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00 ]
+ alignment: 2^3
+ section-choice: custom-required
+ section-name: .eh_frame
+ permissions: r--
+ references:
+ - kind: R_X86_64_PC32
+ offset: 32
+ target: .text
diff --git a/test/elf/export-dynamic.test b/test/elf/export-dynamic.test
new file mode 100644
index 000000000000..37876a47c840
--- /dev/null
+++ b/test/elf/export-dynamic.test
@@ -0,0 +1,99 @@
+# Tests the --export-dynamic (-E) flag. When creating a dynamic executable and
+# receiving this flag, the linker should export all globally visible symbols in
+# its dynamic symbol table.
+
+#RUN: yaml2obj -format=elf %s -o=%t.o
+#RUN: lld -flavor gnu -target x86_64 -E %t.o -e=main -o %t1
+#RUN: llvm-readobj -dt %t1 | FileCheck -check-prefix CHECKSYMS %s
+
+#CHECKSYMS: myfunc1@
+#CHECKSYMS: main@
+#CHECKSYMS: myvar1@
+
+# The object file below was generated with the following code:
+#
+# (command line clang -c prog.c -o prog.o)
+#
+# int myvar1 = 22;
+#
+# static int mysecretvar = 11;
+#
+# int myfunc1() {
+# return 23;
+# }
+#
+# static int mysecretfunc() {
+# return 42;
+# }
+#
+# int main() {
+# return mysecretfunc() + mysecretvar;
+# }
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000010
+ Content: 554889E5B8170000005DC30F1F440000554889E54883EC10C745FC00000000E81C000000030425000000004883C4105DC36666666666662E0F1F840000000000554889E5B82A0000005DC3
+ - Name: .rela.text
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .text
+ Relocations:
+ - Offset: 0x0000000000000027
+ Symbol: .data
+ Type: R_X86_64_32S
+ Addend: 4
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: 160000000B000000
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+Symbols:
+ Local:
+ - Name: mysecretfunc
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000040
+ Size: 0x000000000000000B
+ - Name: mysecretvar
+ Type: STT_OBJECT
+ Section: .data
+ Value: 0x0000000000000004
+ Size: 0x0000000000000004
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ Global:
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000010
+ Size: 0x0000000000000021
+ - Name: myfunc1
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x000000000000000B
+ - Name: myvar1
+ Type: STT_OBJECT
+ Section: .data
+ Size: 0x0000000000000004
diff --git a/test/elf/filenotfound.test b/test/elf/filenotfound.test
new file mode 100644
index 000000000000..d64568f2ea53
--- /dev/null
+++ b/test/elf/filenotfound.test
@@ -0,0 +1,3 @@
+# Check that a file that cannot be found results in a proper error message
+RUN: not lld -flavor gnu -target x86_64 %p/Inputs/nofile.o 2>&1 | FileCheck %s
+#CHECK: lld: cannot find file {{.+[\\/]}}nofile.o
diff --git a/test/elf/gnulinkonce/gnulinkonce-report-discarded-reference.test b/test/elf/gnulinkonce/gnulinkonce-report-discarded-reference.test
new file mode 100644
index 000000000000..e1d0f8e7b55e
--- /dev/null
+++ b/test/elf/gnulinkonce/gnulinkonce-report-discarded-reference.test
@@ -0,0 +1,147 @@
+# Tests that the linker is able to read .gnu.linkonce sections and link them
+# appropriately. The testcase has been created by using the following source
+# code.
+# TODO: This test should produce a discarded reference error message which it
+# does not currently.
+# linkoncea.s
+# .section .gnu.linkonce.d.dummy,"aw"
+#bar:
+# .long 0
+# linkonceb.s
+# .section .gnu.linkonce.d.dummy,"aw"
+#foo:
+# .long 0
+# .section .blah, "aw"
+# .long foo
+#RUN: yaml2obj -format=elf -docnum 1 %s -o %t.linkonce1a.o
+#RUN: yaml2obj -format=elf -docnum 2 %s -o %t.linkonce1b.o
+#RUN: lld -flavor gnu -target x86_64 %t.linkonce1a.o %t.linkonce1b.o \
+#RUN: --noinhibit-exec --output-filetype=yaml -o %t2.out.yaml
+#RUN: lld -flavor gnu -target x86_64 %t.linkonce1a.o %t.linkonce1b.o \
+#RUN: --noinhibit-exec -o %t2.out
+#RUN: FileCheck %s -check-prefix=CHECKGNULINKONCE < %t2.out.yaml
+#RUN: llvm-readobj -sections %t2.out | FileCheck %s -check-prefix=CHECKGNULINKONCESECTIONS
+#CHECKGNULINKONCE: - name: .gnu.linkonce.d.dummy
+#CHECKGNULINKONCE: scope: global
+#CHECKGNULINKONCE: type: gnu-linkonce
+#CHECKGNULINKONCE: section-choice: custom-required
+#CHECKGNULINKONCE: section-name: .gnu.linkonce.d.dummy
+#CHECKGNULINKONCE: permissions: rw-
+#CHECKGNULINKONCE: references:
+#CHECKGNULINKONCE: - kind: group-child
+#CHECKGNULINKONCE: offset: 0
+#CHECKGNULINKONCE: target: bar
+#CHECKGNULINKONCESECTIONS: Section {
+#CHECKGNULINKONCESECTIONS: Name: .gnu.linkonce.d.dummy
+#CHECKGNULINKONCESECTIONS: Type: SHT_PROGBITS
+#CHECKGNULINKONCESECTIONS: Flags [ (0x3)
+#CHECKGNULINKONCESECTIONS: SHF_ALLOC (0x2)
+#CHECKGNULINKONCESECTIONS: SHF_WRITE (0x1)
+#CHECKGNULINKONCESECTIONS: ]
+#CHECKGNULINKONCESECTIONS: Size: 4
+#CHECKGNULINKONCESECTIONS: }
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .gnu.linkonce.d.dummy
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: '00000000'
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .gnu.linkonce.d.dummy
+ Type: STT_SECTION
+ Section: .gnu.linkonce.d.dummy
+ - Name: bar
+ Section: .gnu.linkonce.d.dummy
+...
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .gnu.linkonce.d.dummy
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: '00000000'
+ - Name: .blah
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: '00000000'
+ - Name: .rela.blah
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .blah
+ Relocations:
+ - Offset: 0x0000000000000000
+ Symbol: foo
+ Type: R_X86_64_32
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .gnu.linkonce.d.dummy
+ Type: STT_SECTION
+ Section: .gnu.linkonce.d.dummy
+ - Name: foo
+ Section: .gnu.linkonce.d.dummy
+ - Name: .blah
+ Type: STT_SECTION
+ Section: .blah
+...
diff --git a/test/elf/gnulinkonce/gnulinkonce-report-undef.test b/test/elf/gnulinkonce/gnulinkonce-report-undef.test
new file mode 100644
index 000000000000..c6d050dcd63a
--- /dev/null
+++ b/test/elf/gnulinkonce/gnulinkonce-report-undef.test
@@ -0,0 +1,129 @@
+# Tests that the linker is able to read .gnu.linkonce sections and link them
+# appropriately. The testcase has been created by using the following source
+# code. This test checks that the linker produces an undefined error.
+# linkoncea.s
+# .section .gnu.linkonce.d.dummy,"aw"
+#bar:
+# .long 0
+# linkonceb.s
+# .section .gnu.linkonce.d.dummy,"aw"
+# .global foo
+#foo:
+# .long 0
+# .section .blah, "aw"
+# .long foo
+#RUN: yaml2obj -format=elf -docnum 1 %s -o %t.linkonce1a.o
+#RUN: yaml2obj -format=elf -docnum 2 %s -o %t.linkonce1b.o
+#RUN: not lld -flavor gnu -target x86_64 %t.linkonce1a.o %t.linkonce1b.o \
+#RUN: --output-filetype=yaml -o %t2.out.yaml 2>&1 | FileCheck \
+#RUN: -check-prefix=UNDEFS %s
+#RUN: not lld -flavor gnu -target x86_64 %t.linkonce1a.o %t.linkonce1b.o \
+#RUN: -o %t2.out 2>&1 | FileCheck -check-prefix=UNDEFS %s
+#UNDEFS: Undefined symbol: {{.*}} foo
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .gnu.linkonce.d.dummy
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: '00000000'
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .gnu.linkonce.d.dummy
+ Type: STT_SECTION
+ Section: .gnu.linkonce.d.dummy
+ - Name: bar
+ Section: .gnu.linkonce.d.dummy
+...
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .gnu.linkonce.d.dummy
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: '00000000'
+ - Name: .blah
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: '00000000'
+ - Name: .rela.blah
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .blah
+ Relocations:
+ - Offset: 0x0000000000000000
+ Symbol: foo
+ Type: R_X86_64_32
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .gnu.linkonce.d.dummy
+ Type: STT_SECTION
+ Section: .gnu.linkonce.d.dummy
+ - Name: .blah
+ Type: STT_SECTION
+ Section: .blah
+ Global:
+ - Name: foo
+ Section: .gnu.linkonce.d.dummy
+...
diff --git a/test/elf/gnulinkonce/gnulinkonce.test b/test/elf/gnulinkonce/gnulinkonce.test
new file mode 100644
index 000000000000..17559f656328
--- /dev/null
+++ b/test/elf/gnulinkonce/gnulinkonce.test
@@ -0,0 +1,151 @@
+# Tests that the linker is able to read .gnu.linkonce sections and link them
+# appropriately. The testcase has been created by using the following source
+# code
+# linkonce1a.s
+# ------------
+# .section .gnu.linkonce.d.dummy,"aw"
+#bar:
+# .long 0
+# linkonce1b.s
+# ------------
+# .globl main
+# .globl start
+# .globl _start
+# .globl __start
+# .text
+#main:
+#start:
+#_start:
+#__start:
+# .long 0
+#
+# .section .gnu.linkonce.d.dummy,"aw"
+#foo:
+# .long 0
+#RUN: yaml2obj -format=elf -docnum 1 %s -o %t.linkonce1a.o
+#RUN: yaml2obj -format=elf -docnum 2 %s -o %t.linkonce1b.o
+#RUN: lld -flavor gnu -target x86_64 %t.linkonce1a.o %t.linkonce1b.o \
+#RUN: --noinhibit-exec --output-filetype=yaml -o %t2.out.yaml
+#RUN: lld -flavor gnu -target x86_64 %t.linkonce1a.o %t.linkonce1b.o \
+#RUN: --noinhibit-exec -o %t2.out
+#RUN: FileCheck %s -check-prefix=CHECKGNULINKONCE < %t2.out.yaml
+#RUN: llvm-readobj -sections %t2.out | FileCheck %s -check-prefix=CHECKGNULINKONCESECTIONS
+#CHECKGNULINKONCE: - name: .gnu.linkonce.d.dummy
+#CHECKGNULINKONCE: scope: global
+#CHECKGNULINKONCE: type: gnu-linkonce
+#CHECKGNULINKONCE: section-choice: custom-required
+#CHECKGNULINKONCE: section-name: .gnu.linkonce.d.dummy
+#CHECKGNULINKONCE: permissions: rw-
+#CHECKGNULINKONCE: references:
+#CHECKGNULINKONCE: - kind: group-child
+#CHECKGNULINKONCE: offset: 0
+#CHECKGNULINKONCE: target: bar
+#CHECKGNULINKONCE: - kind: group-child
+#CHECKGNULINKONCE: offset: 0
+#CHECKGNULINKONCESECTIONS: Section {
+#CHECKGNULINKONCESECTIONS: Name: .gnu.linkonce.d.dummy
+#CHECKGNULINKONCESECTIONS: Type: SHT_PROGBITS
+#CHECKGNULINKONCESECTIONS: Flags [ (0x3)
+#CHECKGNULINKONCESECTIONS: SHF_ALLOC (0x2)
+#CHECKGNULINKONCESECTIONS: SHF_WRITE (0x1)
+#CHECKGNULINKONCESECTIONS: ]
+#CHECKGNULINKONCESECTIONS: Size: 4
+#CHECKGNULINKONCESECTIONS: }
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .gnu.linkonce.d.dummy
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: '00000000'
+Symbols:
+ Local:
+ - Name: bar
+ Section: .gnu.linkonce.d.dummy
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .gnu.linkonce.d.dummy
+ Type: STT_SECTION
+ Section: .gnu.linkonce.d.dummy
+...
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: '00000000'
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .gnu.linkonce.d.dummy
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: '00000000'
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .gnu.linkonce.d.dummy
+ Type: STT_SECTION
+ Section: .gnu.linkonce.d.dummy
+ - Name: foo
+ Section: .gnu.linkonce.d.dummy
+ Global:
+ - Name: main
+ Section: .text
+ - Name: start
+ Section: .text
+ - Name: _start
+ Section: .text
+ - Name: __start
+ Section: .text
+...
diff --git a/test/elf/gotpcrel.test b/test/elf/gotpcrel.test
new file mode 100644
index 000000000000..b6f83c16676d
--- /dev/null
+++ b/test/elf/gotpcrel.test
@@ -0,0 +1,21 @@
+# This test checks that GOTPCREL entries are being handled properly
+RUN: lld -flavor gnu -target x86_64-linux -static -e main --output-filetype=yaml \
+RUN: --noinhibit-exec %p/Inputs/gotpcrel.x86-64 \
+RUN: | FileCheck %s -check-prefix=YAML
+
+YAML: name: main
+YAML: references:
+YAML: kind: R_X86_64_GOTPCREL
+YAML: offset: 3
+YAML: target: [[NULLGOT:[a-zA-Z0-9_]+]]
+YAML: kind: R_X86_64_GOTPCREL
+YAML: offset: 10
+YAML: target: [[MAINGOT:[a-zA-Z0-9_]+]]
+
+YAML: name: [[NULLGOT]]
+YAML: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ]
+YAML-NOT: references:
+
+YAML: name: [[MAINGOT]]
+YAML: kind: R_X86_64_64
+YAML: target: main
diff --git a/test/elf/gottpoff.test b/test/elf/gottpoff.test
new file mode 100644
index 000000000000..9841ee1453d0
--- /dev/null
+++ b/test/elf/gottpoff.test
@@ -0,0 +1,120 @@
+# Test that GOTTPOFF reloc generates an outstanding R_X86_64_TPOFF64
+# to be processed at startup time.
+# Reference: Ulrich Drepper's "ELF Handling for Thread-Local storage"
+
+#RUN: yaml2obj -format=elf %s -o %t.o
+#RUN: lld -flavor gnu -target x86_64 %t.o -o %t -e=main --defsym=__tls_get_addr=0
+#RUN: llvm-readobj -r %t | FileCheck %s
+#
+#CHECK: Section (5) .rela.dyn {
+#CHECK: 0x401098 R_X86_64_TPOFF64 - 0x0
+#CHECK: }
+
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_FREEBSD
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000010
+ Content: E819000000640304250000000064030425000000006403042500000000C3488B0500000000648B00C3488D3D00000000E800000000488D8000000000C3
+ - Name: .rela.text
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .text
+ Relocations:
+ - Offset: 0x0000000000000009
+ Symbol: tls1
+ Type: R_X86_64_TPOFF32
+ - Offset: 0x0000000000000011
+ Symbol: tls0
+ Type: R_X86_64_TPOFF32
+ - Offset: 0x0000000000000019
+ Symbol: tls2
+ Type: R_X86_64_TPOFF32
+ - Offset: 0x0000000000000021
+ Symbol: tls2
+ Type: R_X86_64_GOTTPOFF
+ Addend: -4
+ - Offset: 0x000000000000002C
+ Symbol: tls0
+ Type: R_X86_64_TLSLD
+ Addend: -4
+ - Offset: 0x0000000000000031
+ Symbol: __tls_get_addr
+ Type: R_X86_64_PLT32
+ Addend: -4
+ - Offset: 0x0000000000000038
+ Symbol: tls0
+ Type: R_X86_64_DTPOFF32
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .tbss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC, SHF_TLS ]
+ AddressAlign: 0x0000000000000004
+ Content: '01000000002E7265'
+ - Name: .tdata
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC, SHF_TLS ]
+ AddressAlign: 0x0000000000000004
+ Content: '01000000'
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .tbss
+ Type: STT_SECTION
+ Section: .tbss
+ - Name: .tdata
+ Type: STT_SECTION
+ Section: .tdata
+ Global:
+ - Name: GOTTPOFF
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x000000000000001E
+ - Name: TLSLD
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000029
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+ - Name: tls0
+ Type: STT_TLS
+ Section: .tbss
+ Size: 0x0000000000000004
+ - Name: tls1
+ Type: STT_TLS
+ Section: .tbss
+ Value: 0x0000000000000004
+ Size: 0x0000000000000004
+ - Name: tls2
+ Type: STT_TLS
+ Section: .tdata
+ Size: 0x0000000000000004
+ - Name: _GLOBAL_OFFSET_TABLE_
+ - Name: __tls_get_addr
+...
diff --git a/test/elf/group-cmd-search.test b/test/elf/group-cmd-search.test
new file mode 100644
index 000000000000..5e153c1ac1ad
--- /dev/null
+++ b/test/elf/group-cmd-search.test
@@ -0,0 +1,134 @@
+/*
+ XFAIL: win32
+
+ This test does not pass on Windows because a path starting with
+ "/" is not considered as an absolute path. (It needs a drive
+ letter.)
+*/
+
+/*
+ In general the linker scripts's GROUP command works like a pair
+ of command line options --start-group/--end-group. But there is
+ a difference in the files look up algorithm.
+
+ The --start-group/--end-group commands use a trivial approach:
+ a) If the path has '-l' prefix, add 'lib' prefix and '.a'/'.so'
+ suffix and search the path through library search directories.
+ b) Otherwise, use the path 'as-is'.
+
+ The GROUP command implements more compicated approach:
+ a) If the path has '-l' prefix, add 'lib' prefix and '.a'/'.so'
+ suffix and search the path through library search directories.
+ b) If the path does not have '-l' prefix, and sysroot is configured,
+ and the path starts with the / character, and the script being
+ processed is located inside the sysroot, search the path under
+ the sysroot. Otherwise, try to open the path in the current
+ directory. If it is not found, search through library search
+ directories.
+*/
+
+/*
+ This link should finish successfully. The --start-group/--end-group
+ contains an existing absolute path to the file.
+
+RUN: lld -flavor gnu -target x86_64 -shared \
+RUN: -L%p/Inputs %p/Inputs/use-shared.x86-64 \
+RUN: --start-group %p/Inputs/shared.so-x86-64 --end-group -o %t1
+*/
+
+/*
+ This link should fail with unknown input file format error.
+ There is no shared.so-x86-64 file in the current directory.
+
+RUN: not \
+RUN: lld -flavor gnu -target x86_64 -shared \
+RUN: -L%p/Inputs %p/Inputs/use-shared.x86-64 \
+RUN: --start-group shared.so-x86-64 --end-group -o %t2
+*/
+
+/*
+ This link should fail with unknown input file format error.
+ The absolute path /shared.so-x86-64 does not exist and the linker
+ should not attempt to search it under the sysroot directory.
+
+RUN: not \
+RUN: lld -flavor gnu -target x86_64 -shared --sysroot=%p/Inputs \
+RUN: -L%p/Inputs %p/Inputs/use-shared.x86-64 \
+RUN: --start-group /shared.so-x86-64 --end-group -o %t3
+*/
+
+/*
+ This link should finish successfully. The group-cmd-search-1.ls
+ script contains "GROUP ( shared.so-x86-64 )" command and the linker
+ has to search shared.so-x86-64 through the library search paths.
+
+RUN: lld -flavor gnu -target x86_64 -shared \
+RUN: -L%p/Inputs %p/Inputs/use-shared.x86-64 \
+RUN: %p/Inputs/group-cmd-search-1.ls -o %t4
+*/
+
+/*
+ This link should fail with unknown input file format error.
+ The group-cmd-search-2.ls script contains GROUP command with
+ a non-existing absolute path but there is no --sysroot argument.
+
+RUN: not \
+RUN: lld -flavor gnu -target x86_64 -shared \
+RUN: -L%p/Inputs %p/Inputs/use-shared.x86-64 \
+RUN: %p/Inputs/group-cmd-search-2.ls -o %t5
+*/
+
+/*
+ This link should finish successfully. The group-cmd-search-2.ls
+ script contains GROUP command with an absolute path and the sysroot
+ directory is provided. The linker has to search the absolute path
+ under the sysroot directory.
+
+RUN: lld -flavor gnu -target x86_64 -shared --sysroot=%p/Inputs \
+RUN: -L%p/Inputs %p/Inputs/use-shared.x86-64 \
+RUN: %p/Inputs/group-cmd-search-2.ls -o %t6
+*/
+
+/*
+ This link should finish successfully. The group-cmd-search-2.ls
+ script contains GROUP command with an absolute path and the sysroot
+ directory is provided. The linker has to search the absolute path
+ under the sysroot directory.
+
+RUN: lld -flavor gnu -target x86_64 -shared --sysroot=%p/Inputs/../Inputs \
+RUN: -L%p/Inputs %p/Inputs/use-shared.x86-64 \
+RUN: %p/Inputs/group-cmd-search-2.ls -o %t6
+*/
+
+/*
+ This link should finish successfully. The group-cmd-search-3.ls
+ script contains GROUP command with two elements. The first one
+ has a -l:<path> form and should be found by iterating through
+ lib dirs and searching the 'path' name exactly. The second element
+ has a -l<lib name> form and should be found by constructing a full
+ library name lib<lib name>.a and iterating through lib dirs.
+
+RUN: lld -flavor gnu -target x86_64 -shared \
+RUN: -L%p/Inputs %p/Inputs/use-shared.x86-64 \
+RUN: %p/Inputs/group-cmd-search-3.ls -o %t8
+*/
+
+/*
+ This link should fail with unknown input file format error.
+ The linker script from this file contains GROUP with an absolute
+ path which can be found under provided sysroot directory.
+ But the linker script itself is not under the sysroot.
+
+RUN: not \
+RUN: lld -flavor gnu -target x86_64 -shared --sysroot=%p/Inputs \
+RUN: -L%p/Inputs %p/Inputs/use-shared.x86-64 \
+RUN: %s -o %t7
+*/
+
+/*
+RUN: lld -flavor gnu -target x86_64 -shared \
+RUN: -L%p/Inputs %p/Inputs/use-shared.x86-64 \
+RUN: -l:group-cmd-search-1.ls -o %t9
+*/
+
+GROUP ( /shared.so-x86-64 )
diff --git a/test/elf/hexagon-quickdata-sort.test b/test/elf/hexagon-quickdata-sort.test
new file mode 100644
index 000000000000..efdf9480923d
--- /dev/null
+++ b/test/elf/hexagon-quickdata-sort.test
@@ -0,0 +1,12 @@
+RUN: lld -flavor gnu -target hexagon %p/Inputs/quickdata-sort-test.o.elf-hexagon -o %t1 --noinhibit-exec
+RUN: llvm-nm -n %t1 | FileCheck %s -check-prefix=quickdataSort
+
+quickdataSort: 00002000 D A1
+quickdataSort: 00002001 D AA1
+quickdataSort: 00002002 D B1
+quickdataSort: 00002004 D BB1
+quickdataSort: 00002008 D C1
+quickdataSort: 0000200c D CC1
+quickdataSort: 00002010 D D1
+quickdataSort: 00002018 D DD1
+
diff --git a/test/elf/hexagon-quickdata-sortcommon.test b/test/elf/hexagon-quickdata-sortcommon.test
new file mode 100644
index 000000000000..5b4690b43cb9
--- /dev/null
+++ b/test/elf/hexagon-quickdata-sortcommon.test
@@ -0,0 +1,16 @@
+RUN: lld -flavor gnu -target hexagon -o %t1 --noinhibit-exec \
+RUN: %p/Inputs/quickdata-sortcommon-test.o.elf-hexagon
+RUN: llvm-nm -n %t1 | FileCheck %s -check-prefix=quickdataSortCommon
+
+quickdataSortCommon: 00002000 D A1
+quickdataSortCommon: 00002001 D AA1
+quickdataSortCommon: 00002002 D AAA1
+quickdataSortCommon: 00002004 D B1
+quickdataSortCommon: 00002006 D BB1
+quickdataSortCommon: 00002008 D BBB1
+quickdataSortCommon: 0000200c D C1
+quickdataSortCommon: 00002010 D CC1
+quickdataSortCommon: 00002014 D CCC1
+quickdataSortCommon: 00002018 D D1
+quickdataSortCommon: 00002020 D DD1
+quickdataSortCommon: 00002028 D DDD1
diff --git a/test/elf/ifunc.test b/test/elf/ifunc.test
new file mode 100644
index 000000000000..c567c554cbbb
--- /dev/null
+++ b/test/elf/ifunc.test
@@ -0,0 +1,69 @@
+# REQUIRES: x86
+
+# This test checks that IRELATIVE relocations are created for symbols that
+# need relocation even for static links.
+RUN: lld -flavor gnu -target x86_64-linux --output-filetype=yaml -r \
+RUN: %p/Inputs/ifunc.x86-64 | FileCheck %s
+
+RUN: lld -flavor gnu -target x86_64-linux --output-filetype=yaml --noinhibit-exec \
+RUN: %p/Inputs/ifunc.x86-64 %p/Inputs/ifunc.cpp.x86-64 \
+RUN: | FileCheck %s --check-prefix=PLT
+
+RUN: lld -flavor gnu -target x86_64-linux -o %t %p/Inputs/ifunc.x86-64 \
+RUN: -e main -static %p/Inputs/ifunc.cpp.x86-64
+RUN: llvm-objdump -d -s %t| FileCheck %s --check-prefix=BIN
+RUN: llvm-readobj -r %t | FileCheck %s --check-prefix=RELATIVEADDEND
+
+# Test that STT_GNU_IFUNC symbols have type Code in SharedLibraryAtom.
+RUN: lld -flavor gnu -target x86_64-linux --output-filetype=yaml \
+RUN: --noinhibit-exec %p/Inputs/ifunc.cpp.x86-64 -L%p/Inputs -lifunc.x86-64 \
+RUN: | FileCheck %s --check-prefix=SHARED
+
+PLT: defined-atoms:
+
+PLT: name: plt
+PLT: scope: global
+PLT: references:
+PLT: kind: R_X86_64_PC32
+PLT: target: [[PLTNAME:[-a-zA-Z0-9_]+]]
+
+PLT: name: main
+PLT: scope: global
+PLT: references:
+PLT: kind: R_X86_64_PC32
+PLT: target: [[PLTNAME]]
+
+// Make sure the target of main's relocation is a stub with a PC32 relocation.
+// This relocation is to the got atom, but you can't really write that check in
+// FileCheck.
+PLT: name:
+PLT: type: stub
+PLT: references
+PLT: kind: R_X86_64_PC32
+
+// Make sure there's a got entry with a IRELATIVE relocation.
+PLT: type: got
+PLT: references:
+PLT: kind: R_X86_64_IRELATIVE
+PLT: target: hey
+
+CHECK: name: hey
+CHECK: scope: global
+CHECK: type: resolver
+
+
+// This is a horribly brittle test. We need a way to do arithmetic on captured
+// variables.
+BIN: {{[0-9a-f]+}}: ff 25 {{[0-9a-f]+}} {{[0-9a-f]+}} 00 00 jmpq *{{[0-9]+}}(%rip)
+BIN: .got.plt:
+BIN-NEXT: {{[0-9a-f]+}} 00000000 00000000
+
+RELATIVEADDEND: Relocations [
+RELATIVEADDEND-NEXT: Section (1) .rela.plt {
+RELATIVEADDEND-NEXT: 0x401000 R_X86_64_IRELATIVE - 0x400110
+RELATIVEADDEND-NEXT: }
+RELATIVEADDEND-NEXT: ]
+
+SHARED: shared-library-atoms
+SHARED: name: hey
+SHARED-NOT: data
diff --git a/test/elf/ignore-unknownoption.test b/test/elf/ignore-unknownoption.test
new file mode 100644
index 000000000000..56856ed9f2e4
--- /dev/null
+++ b/test/elf/ignore-unknownoption.test
@@ -0,0 +1,5 @@
+# This test tests that lld is able to print unknown options that are not
+# recognized.
+RUN: not lld -flavor gnu -target x86_64 --gc-sections 2> %t
+RUN: FileCheck %s < %t
+CHECK: warning: ignoring unknown argument: --gc-sections
diff --git a/test/elf/init_array-order.test b/test/elf/init_array-order.test
new file mode 100644
index 000000000000..b57b3807b69c
--- /dev/null
+++ b/test/elf/init_array-order.test
@@ -0,0 +1,67 @@
+#RUN: yaml2obj -format=elf %s > %t
+#RUN: lld -flavor gnu -target x86_64-linux %t --noinhibit-exec \
+#RUN: -o %t1.out
+#RUN: llvm-objdump -s %t1.out | FileCheck %s
+
+!ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Content: "1100000000000000"
+ AddressAlign: 8
+ Flags: [SHF_ALLOC, SHF_EXECINSTR]
+- Name: .init_array.2
+ Type: SHT_INIT_ARRAY
+ Content: "0200000000000000"
+ AddressAlign: 8
+ Flags: [SHF_ALLOC]
+- Name: .init_array.3
+ Type: SHT_INIT_ARRAY
+ Content: "0300000000000000"
+ AddressAlign: 8
+ Flags: [SHF_ALLOC]
+- Name: .init_array
+ Type: SHT_INIT_ARRAY
+ Content: "9900000000000000"
+ AddressAlign: 8
+ Flags: [SHF_ALLOC]
+- Name: .data
+ Type: SHT_PROGBITS
+ Content: "2200000000000000"
+ AddressAlign: 8
+ Flags: [SHF_ALLOC, SHF_WRITE]
+- Name: .init_array.1
+ Type: SHT_INIT_ARRAY
+ Content: "0100000000000000"
+ AddressAlign: 8
+ Flags: [SHF_ALLOC]
+
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .init_array.3
+ Type: STT_SECTION
+ Section: .init_array.3
+ - Name: .init_array.2
+ Type: STT_SECTION
+ Section: .init_array.2
+ - Name: .init_array.1
+ Type: STT_SECTION
+ Section: .init_array.1
+ - Name: .init_array
+ Type: STT_SECTION
+ Section: .init_array
+
+#CHECK: {{[0xa-f0-9]+}} 01000000 00000000 02000000 00000000
+#CHECK: {{[0xa-f0-9]+}} 03000000 00000000 99000000 00000000
diff --git a/test/elf/init_array.test b/test/elf/init_array.test
new file mode 100644
index 000000000000..1acf4a7e7a28
--- /dev/null
+++ b/test/elf/init_array.test
@@ -0,0 +1,6 @@
+RUN: lld -flavor gnu -target x86_64-linux -o %t %p/Inputs/init_array.x86-64 \
+RUN: -e __init_array_start
+RUN: llvm-objdump -t -section-headers %t | FileCheck %s
+
+CHECK: .init_array {{[0-9]+}} [[ADDR:[0-9]+]]
+CHECK: [[ADDR]] g *ABS* {{[0-9]+}} __init_array_start
diff --git a/test/elf/initfini-options.test-1.test b/test/elf/initfini-options.test-1.test
new file mode 100644
index 000000000000..2fc1c3e32bda
--- /dev/null
+++ b/test/elf/initfini-options.test-1.test
@@ -0,0 +1,33 @@
+# Check that if there are no -init/-fini options and _init/_fini symbols
+# are undefined the linker does not emit DT_INIT/DT_FINI tags.
+
+# RUN: yaml2obj -format=elf %s > %t.o
+# RUN: lld -flavor gnu -target x86_64 -shared --noinhibit-exec -o %t.so %t.o
+# RUN: llvm-readobj -dynamic-table %t.so | FileCheck %s
+
+# CHECK-NOT: 0x000000000000000C INIT 0x{{[0-9A-F]+}}
+# CHECK-NOT: 0x000000000000000D FINI 0x{{[0-9A-F]+}}
+
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x08
+
+Symbols:
+ Global:
+ - Name: _start
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x08
+ - Name: _init
+ - Name: _fini
+...
diff --git a/test/elf/initfini-options.test-2.test b/test/elf/initfini-options.test-2.test
new file mode 100644
index 000000000000..4742084c513b
--- /dev/null
+++ b/test/elf/initfini-options.test-2.test
@@ -0,0 +1,47 @@
+# Check that if _init/_fini symbols are defined the linker emits
+# DT_INIT/DT_FINI tags point to these symbols.
+
+# RUN: yaml2obj -format=elf %s > %t.o
+# RUN: lld -flavor gnu -target x86_64 -shared -o %t.so %t.o
+# RUN: llvm-readobj -symbols -dynamic-table %t.so | FileCheck %s
+
+# CHECK: Name: _init (8)
+# CHECK-NEXT: Value: {{[0x0-9a-f]+}}
+# CHECK: Name: _fini (14)
+# CHECK-NEXT: Value: {{[0x0-9a-f]+}}
+#
+# CHECK: 0x000000000000000C INIT {{[0x0-9a-f]+}}
+# CHECK: 0x000000000000000D FINI {{[0x0-9a-f]+}}
+
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x18
+
+Symbols:
+ Global:
+ - Name: _start
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0
+ Size: 0x8
+ - Name: _init
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x8
+ Size: 0x8
+ - Name: _fini
+ Type: STT_FUNC
+ Section: .text
+ Value: 0xF
+ Size: 0x8
+...
diff --git a/test/elf/initfini-options.test-3.test b/test/elf/initfini-options.test-3.test
new file mode 100644
index 000000000000..bf8b216775d9
--- /dev/null
+++ b/test/elf/initfini-options.test-3.test
@@ -0,0 +1,53 @@
+# Check that -init/-fini command line options override default function names
+# and the linker uses these name to search symbols and setup DT_INIT/DT_FINI.
+
+# RUN: yaml2obj -format=elf %s > %t.o
+# RUN: lld -flavor gnu -target x86_64 -shared -o %t.so %t.o \
+# RUN: -init _init -init _start -fini _fini -fini _stop
+# RUN: llvm-readobj -symbols -dynamic-table %t.so | FileCheck %s
+
+# CHECK: Name: _start (1)
+# CHECK-NEXT: Value: {{[0x0-9a-f]+}}
+# CHECK: Name: _stop (8)
+# CHECK-NEXT: Value: {{[0x0-9a-f]+}}
+#
+# CHECK: 0x000000000000000C INIT {{[0x0-9a-f]+}}
+# CHECK: 0x000000000000000D FINI {{[0x0-9a-f]+}}
+
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x20
+
+Symbols:
+ Global:
+ - Name: _start
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0
+ Size: 0x8
+ - Name: _stop
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x8
+ Size: 0x8
+ - Name: _init
+ Type: STT_FUNC
+ Section: .text
+ Value: 0xF
+ Size: 0x8
+ - Name: _fini
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x18
+ Size: 0x8
+...
diff --git a/test/elf/librarynotfound.test b/test/elf/librarynotfound.test
new file mode 100644
index 000000000000..faa1728b478b
--- /dev/null
+++ b/test/elf/librarynotfound.test
@@ -0,0 +1,5 @@
+# Tests the functionality of library not found
+RUN: not lld -flavor gnu -lfn 2> %t1
+RUN: FileCheck %s < %t1
+
+CHECK: Unable to find library -lfn
diff --git a/test/elf/linker-as-ld.test b/test/elf/linker-as-ld.test
new file mode 100644
index 000000000000..8ac75275f996
--- /dev/null
+++ b/test/elf/linker-as-ld.test
@@ -0,0 +1,16 @@
+REQUIRES: system-linker-elf
+
+RUN: mkdir -p %t.dir && cp `which lld` %t.dir/ld
+RUN: %t.dir/ld -target x86_64-linux -o %t %p/Inputs/relocs.x86-64 \
+RUN: -e _start -static
+RUN: llvm-readobj -t %t | FileCheck %s
+
+# Test linker run as "ld" on elf based system works like gnu linker.
+
+
+CHECK: Symbol {
+CHECK: Name: i
+CHECK-NEXT: Value:
+CHECK-NEXT: Size:
+CHECK-NEXT: Binding:
+CHECK-NEXT: Type: Object
diff --git a/test/elf/linkerscript/Inputs/externs.ls b/test/elf/linkerscript/Inputs/externs.ls
new file mode 100644
index 000000000000..20fdc0c3f980
--- /dev/null
+++ b/test/elf/linkerscript/Inputs/externs.ls
@@ -0,0 +1,3 @@
+/* A simple valid linker script used for testing the EXTERN command.
+ */
+EXTERN(_foo bar __baz)
diff --git a/test/elf/linkerscript/Inputs/invalid.ls b/test/elf/linkerscript/Inputs/invalid.ls
new file mode 100644
index 000000000000..894d4bef2732
--- /dev/null
+++ b/test/elf/linkerscript/Inputs/invalid.ls
@@ -0,0 +1 @@
+GROUP(
diff --git a/test/elf/linkerscript/Inputs/prog1.o.yaml b/test/elf/linkerscript/Inputs/prog1.o.yaml
new file mode 100644
index 000000000000..ded590e395d4
--- /dev/null
+++ b/test/elf/linkerscript/Inputs/prog1.o.yaml
@@ -0,0 +1,88 @@
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000010
+ Content: 554889E5B000E800000000BF01000000BA0E0000004889C6E80000000031C05DC3
+ - Name: .rela.text
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .text
+ Relocations:
+ - Offset: 0x0000000000000007
+ Symbol: prog2
+ Type: R_X86_64_PC32
+ Addend: -4
+ - Offset: 0x0000000000000019
+ Symbol: write
+ Type: R_X86_64_PC32
+ Addend: -4
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .comment
+ Type: SHT_PROGBITS
+ Flags: [ SHF_MERGE, SHF_STRINGS ]
+ AddressAlign: 0x0000000000000001
+ Content: 00636C616E672076657273696F6E20332E372E302028687474703A2F2F6C6C766D2E6F72672F6769742F636C616E672E6769742036336134646334616430343938646139623934386330383263623735336430353735323938346638292028687474703A2F2F6C6C766D2E6F72672F6769742F6C6C766D2E67697420623838363135326664656538376564653738613565643965616638663664313839343033616266312900
+ - Name: .note.GNU-stack
+ Type: SHT_PROGBITS
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .eh_frame
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC ]
+ AddressAlign: 0x0000000000000008
+ Content: 1400000000000000037A5200017810011B0C0708900100001C0000001C000000000000002100000000410E108602430D0600000000000000
+ - Name: .rela.eh_frame
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .eh_frame
+ Relocations:
+ - Offset: 0x0000000000000020
+ Symbol: .text
+ Type: R_X86_64_PC32
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .comment
+ Type: STT_SECTION
+ Section: .comment
+ - Name: .note.GNU-stack
+ Type: STT_SECTION
+ Section: .note.GNU-stack
+ - Name: .eh_frame
+ Type: STT_SECTION
+ Section: .eh_frame
+ Global:
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x0000000000000021
+ - Name: prog2
+ - Name: write
+...
diff --git a/test/elf/linkerscript/Inputs/prog2.o.yaml b/test/elf/linkerscript/Inputs/prog2.o.yaml
new file mode 100644
index 000000000000..f88b0ddc96b2
--- /dev/null
+++ b/test/elf/linkerscript/Inputs/prog2.o.yaml
@@ -0,0 +1,89 @@
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000010
+ Content: 554889E548B800000000000000005DC3
+ - Name: .rela.text
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .text
+ Relocations:
+ - Offset: 0x0000000000000006
+ Symbol: .rodata.str1.1
+ Type: R_X86_64_64
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .rodata.str1.1
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_MERGE, SHF_STRINGS ]
+ AddressAlign: 0x0000000000000001
+ Content: 48656C6C6F2C20776F726C64210A00
+ - Name: .comment
+ Type: SHT_PROGBITS
+ Flags: [ SHF_MERGE, SHF_STRINGS ]
+ AddressAlign: 0x0000000000000001
+ Content: 00636C616E672076657273696F6E20332E372E302028687474703A2F2F6C6C766D2E6F72672F6769742F636C616E672E6769742036336134646334616430343938646139623934386330383263623735336430353735323938346638292028687474703A2F2F6C6C766D2E6F72672F6769742F6C6C766D2E67697420623838363135326664656538376564653738613565643965616638663664313839343033616266312900
+ - Name: .note.GNU-stack
+ Type: SHT_PROGBITS
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .eh_frame
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC ]
+ AddressAlign: 0x0000000000000008
+ Content: 1400000000000000037A5200017810011B0C0708900100001C0000001C000000000000001000000000410E108602430D0600000000000000
+ - Name: .rela.eh_frame
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .eh_frame
+ Relocations:
+ - Offset: 0x0000000000000020
+ Symbol: .text
+ Type: R_X86_64_PC32
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .rodata.str1.1
+ Type: STT_SECTION
+ Section: .rodata.str1.1
+ - Name: .comment
+ Type: STT_SECTION
+ Section: .comment
+ - Name: .note.GNU-stack
+ Type: STT_SECTION
+ Section: .note.GNU-stack
+ - Name: .eh_frame
+ Type: STT_SECTION
+ Section: .eh_frame
+ Global:
+ - Name: prog2
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x0000000000000010
+...
diff --git a/test/elf/linkerscript/Inputs/prog3.o.yaml b/test/elf/linkerscript/Inputs/prog3.o.yaml
new file mode 100644
index 000000000000..76aa22267f0b
--- /dev/null
+++ b/test/elf/linkerscript/Inputs/prog3.o.yaml
@@ -0,0 +1,52 @@
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: B8010000000F05C3E800000000B83C0000000F05C3
+ - Name: .rela.text
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .text
+ Relocations:
+ - Offset: 0x0000000000000009
+ Symbol: main
+ Type: R_X86_64_PC32
+ Addend: -4
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ Global:
+ - Name: _start
+ Section: .text
+ Value: 0x0000000000000008
+ - Name: write
+ Section: .text
+ - Name: main
+...
diff --git a/test/elf/linkerscript/Inputs/simple.o.yaml b/test/elf/linkerscript/Inputs/simple.o.yaml
new file mode 100644
index 000000000000..91d4e1b57786
--- /dev/null
+++ b/test/elf/linkerscript/Inputs/simple.o.yaml
@@ -0,0 +1,52 @@
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: B80100000048C7C70100000048C7C60000000048C7C20E0000000F05C3E8DEFFFFFFB83C0000000F05C3
+ - Name: .rela.text
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .text
+ Relocations:
+ - Offset: 0x000000000000000F
+ Symbol: .data
+ Type: R_X86_64_32S
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: 48656C6C6F2C20576F726C64210A00
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+Symbols:
+ Local:
+ - Name: main
+ Section: .text
+ - Name: msg
+ Section: .data
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ Global:
+ - Name: _start
+ Section: .text
+ Value: 0x000000000000001D
+...
diff --git a/test/elf/linkerscript/Inputs/valid.ls b/test/elf/linkerscript/Inputs/valid.ls
new file mode 100644
index 000000000000..43593602d3fb
--- /dev/null
+++ b/test/elf/linkerscript/Inputs/valid.ls
@@ -0,0 +1,6 @@
+/* A simple valid linker script used for testing the -T/--script options.
+ *
+ * An unresolved symbol named '_entry_point' can be scanned for by the tests
+ * to determine that the linker script was processed.
+ */
+ENTRY(_entry_point)
diff --git a/test/elf/linkerscript/externs.objtxt b/test/elf/linkerscript/externs.objtxt
new file mode 100644
index 000000000000..154891eaf710
--- /dev/null
+++ b/test/elf/linkerscript/externs.objtxt
@@ -0,0 +1,21 @@
+# Check symbols defined with the EXTERN command are added as undefined
+# symbols.
+
+# RUN: lld -flavor gnu -target x86_64 -T %p/Inputs/externs.ls -r %s \
+# RUN: --output-filetype=yaml | FileCheck %s
+
+defined-atoms:
+ - name: main
+ scope: global
+ content: [ B8, 00, 00, 00, 00, C7, 44, 24, FC, 00, 00, 00, 00, C3 ]
+ alignment: 2^4
+ section-choice: custom-required
+ section-name: .text
+
+# CHECK: undefined-atoms:
+# CHECK: - name: _foo
+# CHECK: can-be-null: at-buildtime
+# CHECK: - name: bar
+# CHECK: can-be-null: at-buildtime
+# CHECK: - name: __baz
+# CHECK: can-be-null: at-buildtime
diff --git a/test/elf/linkerscript/invalid-script-cli-1.test b/test/elf/linkerscript/invalid-script-cli-1.test
new file mode 100644
index 000000000000..904ba17557c0
--- /dev/null
+++ b/test/elf/linkerscript/invalid-script-cli-1.test
@@ -0,0 +1,10 @@
+# Check that the -T/--script options issue an error when passed
+# filenames for files that do not exist.
+
+RUN: not lld -flavor gnu -target x86_64 -T idonotexist.ls 2> %t.err
+RUN: FileCheck %s < %t.err
+
+RUN: not lld -flavor gnu -target x86_64 --script=idonotexist.ls 2> %t.err
+RUN: FileCheck %s < %t.err
+
+CHECK: {{.*}}lld: cannot find file {{.*}}idonotexist.ls
diff --git a/test/elf/linkerscript/invalid-script-cli-2.test b/test/elf/linkerscript/invalid-script-cli-2.test
new file mode 100644
index 000000000000..6e0e42adc71d
--- /dev/null
+++ b/test/elf/linkerscript/invalid-script-cli-2.test
@@ -0,0 +1,6 @@
+# Check that linker script are *not* picked up with -lscript.ls.
+
+RUN: not lld -flavor gnu -target x86_64 -L%p/Inputs/ -lvalid.ls 2> %t.err
+RUN: FileCheck %s < %t.err
+
+CHECK: {{.*}}: Unable to find library -lvalid.ls
diff --git a/test/elf/linkerscript/invalid.test b/test/elf/linkerscript/invalid.test
new file mode 100644
index 000000000000..42833a6664ff
--- /dev/null
+++ b/test/elf/linkerscript/invalid.test
@@ -0,0 +1,5 @@
+# Check for errors from invalid linker scripts
+RUN: not lld -flavor gnu -target x86_64 %p/Inputs/invalid.ls 2> %t.err
+RUN: FileCheck %s < %t.err
+
+CHECK: {{.*}}invalid.ls: Error parsing linker script
diff --git a/test/elf/linkerscript/sections-order.test b/test/elf/linkerscript/sections-order.test
new file mode 100644
index 000000000000..85a172cb07ad
--- /dev/null
+++ b/test/elf/linkerscript/sections-order.test
@@ -0,0 +1,97 @@
+/*
+Tests a simple linker script that changes the order of output sections and
+also changes the address of output sections by using simple expressions.
+
+This test uses three X86-64 input objects, prog1.o, prog2.o and prog3.o,
+which were created with the following C or assembly code:
+
+*** prog1.o:
+
+(command line clang -c prog1.c -o prog1.o)
+
+const char *prog2();
+void write(int, const char *, int);
+
+int main() {
+ write(1, prog2(), 14);
+}
+
+*** prog2.o:
+
+(command line clang -c prog2.c -o prog2.o)
+
+const char *prog2() {
+ return "Hello, world!\n";
+}
+
+*** prog3.o:
+
+(command line clang -c prog3.S -o prog3.o)
+
+ .globl write
+write:
+ mov $1, %eax
+ syscall
+ ret
+
+ .globl _start
+_start:
+ call main
+ mov $60, %eax
+ syscall
+ ret
+
+We use the following linker script for this test:
+*/
+
+ENTRY(_start)
+
+SECTIONS
+{
+ . = 0x500000;
+ .text : { prog1.o(.text) }
+ .mystring : { prog2.o(.rodata.str1.1) }
+ . = . + 0x6000;
+ .text.2 : {prog3.o(.text) prog2.o(.text) }
+}
+
+/*
+RUN: mkdir -p %T
+RUN: yaml2obj -format=elf %p/Inputs/prog1.o.yaml -o=%T/prog1.o
+RUN: yaml2obj -format=elf %p/Inputs/prog2.o.yaml -o=%T/prog2.o
+RUN: yaml2obj -format=elf %p/Inputs/prog3.o.yaml -o=%T/prog3.o
+RUN: cd %T
+
+RUN: lld -flavor gnu -target x86_64 -T %s prog1.o prog2.o prog3.o \
+RUN: -static -o %t1
+RUN: llvm-readobj -s %t1 | FileCheck -check-prefix CHECKSECTIONS %s
+
+CHECKSECTIONS: Index: 1
+CHECKSECTIONS: Name: .text
+CHECKSECTIONS: Address: 0x500000
+CHECKSECTIONS: Size: 33
+
+CHECKSECTIONS: Index: 2
+CHECKSECTIONS: Name: .mystring
+CHECKSECTIONS: Address: 0x500021
+CHECKSECTIONS: Size: 15
+
+CHECKSECTIONS: Index: 3
+CHECKSECTIONS: Name: .text.2
+CHECKSECTIONS: Address: 0x506030
+CHECKSECTIONS: Size: 48
+
+RUN: llvm-readobj -symbols %t1 | FileCheck -check-prefix CHECKSYMS %s
+
+CHECKSYMS: Name: main
+CHECKSYMS-NEXT: Value: 0x500000
+
+CHECKSYMS: Name: write
+CHECKSYMS-NEXT: Value: 0x506030
+
+CHECKSYMS: Name: _start
+CHECKSYMS-NEXT: Value: 0x506038
+
+CHECKSYMS: Name: prog2
+CHECKSYMS-NEXT: Value: 0x506050
+*/
diff --git a/test/elf/linkerscript/sections-with-wildcards.test b/test/elf/linkerscript/sections-with-wildcards.test
new file mode 100644
index 000000000000..6af80d0883de
--- /dev/null
+++ b/test/elf/linkerscript/sections-with-wildcards.test
@@ -0,0 +1,88 @@
+/*
+Tests a linker script that uses the SECTIONS command with rules containing
+wildcards and simple SORT directives. It also tests that the linker script
+evaluates the expressions in the same order as the one written in the script
+file.
+
+This test uses three X86-64 input objects, prog1.o, prog2.o and prog3.o,
+which were created with the following C or assembly code:
+
+*** prog1.o:
+
+(command line clang -c prog1.c -o prog1.o)
+
+const char *prog2();
+void write(int, const char *, int);
+
+int main() {
+ write(1, prog2(), 14);
+}
+
+*** prog2.o:
+
+(command line clang -c prog2.c -o prog2.o)
+
+const char *prog2() {
+ return "Hello, world!\n";
+}
+
+*** prog3.o:
+
+(command line clang -c prog3.S -o prog3.o)
+
+ .globl write
+write:
+ mov $1, %eax
+ syscall
+ ret
+
+ .globl _start
+_start:
+ call main
+ mov $60, %eax
+ syscall
+ ret
+
+We use the following linker script for this test:
+*/
+
+ENTRY(_start)
+
+SECTIONS
+{
+ my_start_addr = 0x500000;
+ my_symbol = my_start_addr;
+ . = my_symbol;
+ .foo : { SORT(*)(.text .rodata*) }
+}
+
+/*
+RUN: mkdir -p %T
+RUN: yaml2obj -format=elf %p/Inputs/prog1.o.yaml -o=%T/p1.o
+RUN: yaml2obj -format=elf %p/Inputs/prog2.o.yaml -o=%T/p2.o
+RUN: yaml2obj -format=elf %p/Inputs/prog3.o.yaml -o=%T/p3.o
+RUN: cd %T
+
+RUN: lld -flavor gnu -target x86_64 -T %s p1.o p2.o p3.o \
+RUN: -static -o %t1
+RUN: llvm-readobj -s %t1 | FileCheck -check-prefix CHECKSECTIONS %s
+
+CHECKSECTIONS: Index: 1
+CHECKSECTIONS: Name: .foo
+CHECKSECTIONS: Address: 0x500000
+CHECKSECTIONS: Size: 101
+
+RUN: llvm-readobj -symbols %t1 | FileCheck -check-prefix CHECKSYMS %s
+
+CHECKSYMS: Name: main
+CHECKSYMS-NEXT: Value: 0x500000
+
+CHECKSYMS: Name: prog2
+CHECKSYMS-NEXT: Value: 0x500030
+
+CHECKSYMS: Name: write
+CHECKSYMS-NEXT: Value: 0x500050
+
+CHECKSYMS: Name: _start
+CHECKSYMS-NEXT: Value: 0x500058
+*/
diff --git a/test/elf/linkerscript/symbol-definition.test b/test/elf/linkerscript/symbol-definition.test
new file mode 100644
index 000000000000..fc595bbe1f10
--- /dev/null
+++ b/test/elf/linkerscript/symbol-definition.test
@@ -0,0 +1,54 @@
+/*
+We test whether we can define symbols in a linker script and have them exported
+to the output file symbol table.
+
+This test uses a single X86-64 input object, simple.o, created with the
+following X86-64 assembly code:
+
+*** simple.S:
+
+(command line clang -c simple.S -o simple.o)
+
+ .text
+ main:
+ mov $1, %eax
+ movq $1, %rdi
+ movq $msg, %rsi
+ movq $14, %rdx
+ syscall
+ ret
+
+ .globl _start
+ _start:
+ call main
+ mov $60, %eax
+ syscall
+ ret
+
+ .data
+ msg: .asciz "Hello, World!\n"
+
+
+We use the following linker script for this test:
+*/
+
+ENTRY(_start)
+
+SECTIONS
+{
+ . = 0x500000;
+ .text : { *(.text) }
+ MYSTRING = .;
+ .data : { *(.data) }
+}
+
+/*
+RUN: mkdir -p %T
+RUN: yaml2obj -format=elf %p/Inputs/simple.o.yaml -o=%T/simple.o
+
+RUN: lld -flavor gnu -target x86_64 -T %s %T/simple.o -static -o %t1
+RUN: llvm-readobj -symbols %t1 | FileCheck -check-prefix CHECKSYMS %s
+
+CHECKSYMS: Name: MYSTRING
+CHECKSYMS-NEXT: Value: 0x501000
+*/
diff --git a/test/elf/linkerscript/valid-script-cli.objtxt b/test/elf/linkerscript/valid-script-cli.objtxt
new file mode 100644
index 000000000000..b68d430fd98e
--- /dev/null
+++ b/test/elf/linkerscript/valid-script-cli.objtxt
@@ -0,0 +1,23 @@
+# Check that the linker script inputs are accepted properly.
+
+# RUN: lld -flavor gnu -target x86_64 %p/Inputs/valid.ls -r %s \
+# RUN: --output-filetype=yaml | FileCheck %s
+
+# RUN: lld -flavor gnu -target x86_64 -T %p/Inputs/valid.ls -r %s \
+# RUN: --output-filetype=yaml | FileCheck %s
+
+# RUN: lld -flavor gnu -target x86_64 --script=%p/Inputs/valid.ls -r %s \
+# RUN: --output-filetype=yaml | FileCheck %s
+
+# RUN: lld -flavor gnu -target x86_64 -L%p/Inputs/ -l:valid.ls -r %s \
+# RUN: --output-filetype=yaml | FileCheck %s
+
+defined-atoms:
+ - name: main
+ scope: global
+ content: [ B8, 00, 00, 00, 00, C7, 44, 24, FC, 00, 00, 00, 00, C3 ]
+ alignment: 2^4
+ section-choice: custom-required
+ section-name: .text
+
+# CHECK: _entry_point
diff --git a/test/elf/loginputfiles.test b/test/elf/loginputfiles.test
new file mode 100644
index 000000000000..850570d8085e
--- /dev/null
+++ b/test/elf/loginputfiles.test
@@ -0,0 +1,28 @@
+# Tests functionality of -t
+#
+# Tests generated using the source files below
+# main file
+# int main()
+# {
+# fn();
+# return 0;
+# }
+#
+# archive file
+# int fn()
+# {
+# return 0;
+# }
+#
+# int fn1()
+# {
+# return 0;
+# }
+# gcc -c main.c fn.c fn1.c
+
+RUN: lld -flavor gnu -target x86_64-linux \
+RUN: %p/Inputs/mainobj.x86_64 %p/Inputs/libfnarchive.a -t --noinhibit-exec 2>&1 | \
+RUN: FileCheck -check-prefix INPUTFILES %s
+
+#INPUTFILES: mainobj.x86_64
+#INPUTFILES: libfnarchive.a(fn.o)
diff --git a/test/elf/mergeatoms.test b/test/elf/mergeatoms.test
new file mode 100644
index 000000000000..521eb5a12c3c
--- /dev/null
+++ b/test/elf/mergeatoms.test
@@ -0,0 +1,6 @@
+# Tests that atoms are merged by testing it with --merge-strings option
+RUN: lld -flavor gnu -target x86_64-linux --merge-strings -o %t1 \
+RUN: %p/Inputs/foo.o.x86-64 %p/Inputs/bar.o.x86-64 -e bar1
+RUN: llvm-objdump -s %t1 | FileCheck -check-prefix=mergeAtoms %s
+
+mergeAtoms: 62617200 666f6f00 bar.foo.
diff --git a/test/elf/mergeconstants.test b/test/elf/mergeconstants.test
new file mode 100644
index 000000000000..3d06d2c94438
--- /dev/null
+++ b/test/elf/mergeconstants.test
@@ -0,0 +1,20 @@
+# The test checks for mergeable strings that appear in the object file
+RUN: lld -flavor gnu --merge-strings --output-filetype=yaml -target x86_64 \
+RUN: %p/Inputs/constants-merge.x86-64 --noinhibit-exec \
+RUN: | FileCheck -check-prefix=mergeAtoms %s
+
+mergeAtoms: - ref-name: [[CONSTANT:[-a-zA-Z0-9_]+]]
+mergeAtoms: type: constant
+mergeAtoms: content: [ 62, 61, 72, 66, 6F, 6F, 00 ]
+mergeAtoms: merge: by-content
+mergeAtoms: section-choice: custom-required
+mergeAtoms: section-name: .rodata.str1.1
+mergeAtoms: - name: foo
+mergeAtoms: scope: global
+mergeAtoms: type: data
+mergeAtoms: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ]
+mergeAtoms: alignment: 2^3
+mergeAtoms: references:
+mergeAtoms: - kind: R_X86_64_64
+mergeAtoms: offset: 3
+mergeAtoms: target: [[CONSTANT]]
diff --git a/test/elf/mergeglobalatoms.test b/test/elf/mergeglobalatoms.test
new file mode 100644
index 000000000000..e71dca539915
--- /dev/null
+++ b/test/elf/mergeglobalatoms.test
@@ -0,0 +1,11 @@
+# ELF files can have mergeable strings which are global!, treat them as global
+# defined atoms
+RUN: lld -flavor gnu --output-filetype=yaml %p/Inputs/globalconst.o.x86-64 \
+RUN: --noinhibit-exec -target x86_64 | FileCheck -check-prefix=globalatoms %s
+
+globalatoms: - name: mystr
+globalatoms: scope: global
+globalatoms: type: constant
+globalatoms: content: [ 66, 6F, 6F, 62, 61, 72, 00 ]
+globalatoms: section-choice: custom-required
+globalatoms: section-name: .rodata.str1.1
diff --git a/test/elf/note.test b/test/elf/note.test
new file mode 100644
index 000000000000..f0e9c6b2f8d9
--- /dev/null
+++ b/test/elf/note.test
@@ -0,0 +1,49 @@
+# Check that the linker is not ignoring input sections.
+# RUN: yaml2obj -format=elf %s > %t.obj
+# RUN: lld -flavor gnu -target x86_64 %t.obj -o %t.exe --noinhibit-exec
+# RUN: llvm-objdump -h %t.exe | FileCheck %s
+
+# CHECK: {{[0-9]+}} .note
+
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .note
+ Type: SHT_NOTE
+ AddressAlign: 0x0000000000000001
+ Content: '00'
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .note
+ Type: STT_SECTION
+ Section: .note
+...
diff --git a/test/elf/options/dynamic-linker.test b/test/elf/options/dynamic-linker.test
new file mode 100644
index 000000000000..3d8feeb6e307
--- /dev/null
+++ b/test/elf/options/dynamic-linker.test
@@ -0,0 +1,17 @@
+# This tests the functionality of specifying dynamic-linker argument in the
+# command line
+RUN: lld -flavor gnu -target x86_64 --dynamic-linker="/xyz.so" \
+RUN: %p/../Inputs/foo.o.x86-64 --noinhibit-exec -o %t
+RUN: llvm-objdump -s %t | FileCheck -check-prefix=DYNAMICINTERP1 %s
+RUN: lld -flavor gnu -target x86_64 --dynamic-linker="" \
+RUN: %p/../Inputs/foo.o.x86-64 --noinhibit-exec -o %t1
+RUN: llvm-objdump -s %t1 | FileCheck -check-prefix=DYNAMICINTERP2 %s
+RUN: lld -flavor gnu -target x86_64 -dynamic-linker /xyz.so \
+RUN: %p/../Inputs/foo.o.x86-64 --noinhibit-exec -o %t2
+RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=DYNAMICINTERP1 %s
+
+DYNAMICINTERP1:Contents of section .interp:
+DYNAMICINTERP1: 400158 2f78797a 2e736f00 /xyz.so.
+DYNAMICINTERP2:Contents of section .interp:
+DYNAMICINTERP2: 400158 00
+
diff --git a/test/elf/phdr.test b/test/elf/phdr.test
new file mode 100644
index 000000000000..c8ab73d31464
--- /dev/null
+++ b/test/elf/phdr.test
@@ -0,0 +1,99 @@
+# This test checks emission for program header for ELF binaries
+RUN: lld -flavor gnu -target i386-linux -o %t1 -e main %p/Inputs/phdr.i386 \
+RUN: && llvm-readobj -program-headers %t1 | FileCheck -check-prefix=I386 %s
+RUN: lld -flavor gnu -target x86_64-linux -o %t1 -e _start %p/Inputs/relocs.x86-64 -static \
+RUN: && llvm-objdump -p %t1 | FileCheck %s -check-prefix=X86_64
+
+
+I386: ProgramHeaders [
+I386-NEXT: ProgramHeader {
+I386-NEXT: Type: PT_PHDR (0x6)
+I386-NEXT: Offset: 0x34
+I386-NEXT: VirtualAddress: 0x34
+I386-NEXT: PhysicalAddress: 0x34
+I386-NEXT: FileSize: 224
+I386-NEXT: MemSize: 224
+I386-NEXT: Flags [ (0x5)
+I386-NEXT: PF_R (0x4)
+I386-NEXT: PF_X (0x1)
+I386-NEXT: ]
+I386-NEXT: Alignment: 8
+I386-NEXT: }
+I386-NEXT: ProgramHeader {
+I386-NEXT: Type: PT_INTERP (0x3)
+I386-NEXT: Offset: 0x114
+I386-NEXT: VirtualAddress: 0x114
+I386-NEXT: PhysicalAddress: 0x114
+I386-NEXT: FileSize: 28
+I386-NEXT: MemSize: 28
+I386-NEXT: Flags [ (0x4)
+I386-NEXT: PF_R (0x4)
+I386-NEXT: ]
+I386-NEXT: Alignment: 1
+I386-NEXT: }
+I386-NEXT: ProgramHeader {
+I386-NEXT: Type: PT_LOAD (0x1)
+I386-NEXT: Offset: 0x0
+I386-NEXT: VirtualAddress: 0x0
+I386-NEXT: PhysicalAddress: 0x0
+I386-NEXT: FileSize: 556
+I386-NEXT: MemSize: 556
+I386-NEXT: Flags [ (0x5)
+I386-NEXT: PF_R (0x4)
+I386-NEXT: PF_X (0x1)
+I386-NEXT: ]
+I386-NEXT: Alignment: 4096
+I386-NEXT: }
+I386-NEXT: ProgramHeader {
+I386-NEXT: Type: PT_LOAD (0x1)
+I386-NEXT: Offset: 0x1000
+I386-NEXT: VirtualAddress: 0x1000
+I386-NEXT: PhysicalAddress: 0x1000
+I386-NEXT: FileSize: 260
+I386-NEXT: MemSize: 260
+I386-NEXT: Flags [ (0x6)
+I386-NEXT: PF_R (0x4)
+I386-NEXT: PF_W (0x2)
+I386-NEXT: ]
+I386-NEXT: Alignment: 4096
+I386-NEXT: }
+I386-NEXT: ProgramHeader {
+I386-NEXT: Type: PT_LOAD (0x1)
+I386-NEXT: Offset: 0x4000
+I386-NEXT: VirtualAddress: 0x4000
+I386-NEXT: PhysicalAddress: 0x4000
+I386-NEXT: FileSize: 4
+I386-NEXT: MemSize: 8
+I386-NEXT: Flags [ (0x6)
+I386-NEXT: PF_R (0x4)
+I386-NEXT: PF_W (0x2)
+I386-NEXT: ]
+I386-NEXT: Alignment: 16384
+I386-NEXT: }
+I386-NEXT: ProgramHeader {
+I386-NEXT: Type: PT_DYNAMIC (0x2)
+I386-NEXT: Offset: 0x1FC
+I386-NEXT: VirtualAddress: 0x1FC
+I386-NEXT: PhysicalAddress: 0x1FC
+I386-NEXT: FileSize: 48
+I386-NEXT: MemSize: 48
+I386-NEXT: Flags [ (0x4)
+I386-NEXT: PF_R (0x4)
+I386-NEXT: ]
+I386-NEXT: Alignment: 4
+I386-NEXT: }
+I386-NEXT: ProgramHeader {
+I386-NEXT: Type: PT_GNU_EH_FRAME (0x6474E550)
+I386-NEXT: Offset: 0x1F4
+I386-NEXT: VirtualAddress: 0x1F4
+I386-NEXT: PhysicalAddress: 0x1F4
+I386-NEXT: FileSize: 8
+I386-NEXT: MemSize: 8
+I386-NEXT: Flags [ (0x4)
+I386-NEXT: PF_R (0x4)
+I386-NEXT: ]
+I386-NEXT: Alignment: 4
+I386-NEXT: }
+
+X86_64: LOAD off 0x0000000000000000
+X86_64: LOAD off 0x0000000000001000
diff --git a/test/elf/quickdata.test b/test/elf/quickdata.test
new file mode 100644
index 000000000000..a07771517226
--- /dev/null
+++ b/test/elf/quickdata.test
@@ -0,0 +1,15 @@
+RUN: lld -flavor gnu -target hexagon --output-filetype=yaml %p/Inputs/quickdata-test.elf-hexagon \
+RUN: --noinhibit-exec | FileCheck %s -check-prefix hexagon
+
+hexagon: - name: ac1
+hexagon: scope: global
+hexagon: type: zero-fill-quick
+hexagon: size: 1
+hexagon: merge: as-tentative
+hexagon: - name: init
+hexagon: scope: global
+hexagon: type: quick-data
+hexagon: - name: bss1
+hexagon: scope: global
+hexagon: type: zero-fill-quick
+
diff --git a/test/elf/reloc.test b/test/elf/reloc.test
new file mode 100644
index 000000000000..0ecf0b174fe8
--- /dev/null
+++ b/test/elf/reloc.test
@@ -0,0 +1,38 @@
+RUN: lld -flavor gnu -target i386 --merge-strings -r --output-filetype=yaml \
+RUN: %p/Inputs/reloc-test.elf-i386 | FileCheck %s -check-prefix ELF-i386
+
+ELF-i386: defined-atoms:
+ELF-i386: - ref-name: [[STRNAMEA:[-a-zA-Z0-9_]+]]
+ELF-i386: type: constant
+ELF-i386: content: [ 68, 65, 6C, 6C, 6F, 20, 77, 6F, 72, 6C, 64, 00 ]
+ELF-i386: merge: by-content
+ELF-i386: - ref-name: [[STRNAMEB:[-a-zA-Z0-9_]+]]
+ELF-i386: alignment: 2^4
+ELF-i386: section-choice: custom-required
+ELF-i386: section-name: .text.startup
+ELF-i386: references:
+ELF-i386: - kind: layout-after
+ELF-i386: offset: 0
+ELF-i386: target: main
+ELF-i386: - name: main
+ELF-i386: scope: global
+ELF-i386: content: [ 55, 89, E5, 83, E4, F0, 83, EC, 10, C7, 04, 24,
+ELF-i386: 00, 00, 00, 00, E8, FC, FF, FF, FF, 31, C0, C9,
+ELF-i386: C3 ]
+ELF-i386: alignment: 2^4
+ELF-i386: section-choice: custom-required
+ELF-i386: section-name: .text.startup
+ELF-i386: references:
+ELF-i386: - kind: R_386_32
+ELF-i386: offset: 12
+ELF-i386: target: [[STRNAMEA]]
+ELF-i386: - kind: R_386_PC32
+ELF-i386: offset: 17
+ELF-i386: target: puts
+ELF-i386: addend: 252
+ELF-i386: undefined-atoms:
+ELF-i386: - name: puts
+ELF-i386: absolute-atoms:
+ELF-i386: - name: test.c
+ELF-i386: scope: static
+ELF-i386: value: 0x0000000000000000
diff --git a/test/elf/responsefile.test b/test/elf/responsefile.test
new file mode 100644
index 000000000000..5957471bb661
--- /dev/null
+++ b/test/elf/responsefile.test
@@ -0,0 +1,6 @@
+# RUN: not lld -flavor gnu --abc @%p/Inputs/responsefile --baz >& %t.log
+# RUN: FileCheck %s < %t.log
+
+CHECK: warning: ignoring unknown argument: --abc
+CHECK: warning: ignoring unknown argument: --inresponsefile
+CHECK: warning: ignoring unknown argument: --baz
diff --git a/test/elf/rodata.test b/test/elf/rodata.test
new file mode 100644
index 000000000000..dfe6985c0733
--- /dev/null
+++ b/test/elf/rodata.test
@@ -0,0 +1,5 @@
+RUN: lld -flavor gnu -target x86_64-linux -o %t %p/Inputs/constdata.x86-64 \
+RUN: -static -e _start
+RUN: llvm-objdump -s %t | FileCheck %s
+
+CHECK: Hellooooooooo
diff --git a/test/elf/rosegment.test b/test/elf/rosegment.test
new file mode 100644
index 000000000000..32638d8fce6f
--- /dev/null
+++ b/test/elf/rosegment.test
@@ -0,0 +1,26 @@
+# Tests that the option --rosegment produces an output file with a separate
+# segment created for read only data.
+RUN: lld -flavor gnu -target x86_64 %p/Inputs/rodata.o -o %t1.elf \
+RUN: --noinhibit-exec
+RUN: lld -flavor gnu -target x86_64 %p/Inputs/rodata.o --rosegment -o %t2.elf \
+RUN: --noinhibit-exec
+RUN: llvm-readobj -program-headers %t1.elf | FileCheck %s -check-prefix=NORO-SEGMENT
+RUN: llvm-readobj -program-headers %t2.elf | FileCheck %s -check-prefix=RO-SEGMENT
+
+#NORO-SEGMENT: Type: PT_PHDR
+#NORO-SEGMENT: Type: PT_INTERP
+#NORO-SEGMENT: Type: PT_LOAD
+#NORO-SEGMENT: Type: PT_LOAD
+#NORO-SEGMENT: Type: PT_DYNAMIC
+#NORO-SEGMENT: Type: PT_GNU_EH_FRAME
+
+#RO-SEGMENT: Type: PT_PHDR
+#RO-SEGMENT: Type: PT_INTERP
+#RO-SEGMENT: Type: PT_LOAD
+#RO-SEGMENT: Type: PT_LOAD
+#RO-SEGMENT: Flags [
+#RO-SEGMENT: PF_R (0x4)
+#RO-SEGMENT: ]
+#RO-SEGMENT: Type: PT_LOAD
+#RO-SEGMENT: Type: PT_DYNAMIC
+#RO-SEGMENT: Type: PT_GNU_EH_FRAME
diff --git a/test/elf/sectionGroups/sectiongroup-new-members.test b/test/elf/sectionGroups/sectiongroup-new-members.test
new file mode 100644
index 000000000000..d270c5fec94a
--- /dev/null
+++ b/test/elf/sectionGroups/sectiongroup-new-members.test
@@ -0,0 +1,153 @@
+# Checks that the linker picks the first group in the output file when the file
+# have some members dont appear in the first group.
+# 1a.s
+# ------
+#
+# .section .text,"axG",%progbits,foo_group,comdat
+# .weak foo
+#foo:
+# .word 0
+# 1b.s
+# -----
+# .section .text,"axG",%progbits,foo_group,comdat
+# .global foo
+# .global bar
+#foo:
+# .word 0
+#bar:
+#RUN: yaml2obj -format=elf -docnum 1 %s -o %t.group1a.o
+#RUN: yaml2obj -format=elf -docnum 2 %s -o %t.group1b.o
+#RUN: lld -flavor gnu -target x86_64 %t.group1a.o %t.group1b.o \
+#RUN: --noinhibit-exec --output-filetype=yaml -o %t2.out.yaml
+#RUN: lld -flavor gnu -target x86_64 %t.group1a.o %t.group1b.o \
+#RUN: --noinhibit-exec -o %t2.out
+#RUN: FileCheck %s -check-prefix=CHECKGROUP < %t2.out.yaml
+#RUN: llvm-readobj -sections %t2.out | FileCheck %s -check-prefix=CHECKGROUPSECTIONS
+#RUN: llvm-readobj -symbols %t2.out | FileCheck %s -check-prefix=CHECKSYMBOLS
+#CHECKGROUP: - name: foo
+#CHECKGROUP: scope: global
+#CHECKGROUP: merge: as-weak
+#CHECKGROUP: section-name: .text
+#CHECKGROUP: - name: foo_group
+#CHECKGROUP: scope: global
+#CHECKGROUP: type: group-comdat
+#CHECKGROUP: section-choice: custom-required
+#CHECKGROUP: section-name: .group
+#CHECKGROUP: permissions: ---
+#CHECKGROUP: references:
+#CHECKGROUP: - kind: group-child
+#CHECKGROUP: offset: 0
+#CHECKGROUP: target: foo
+#CHECKGROUPSECTIONS: Section {
+#CHECKGROUPSECTIONS: Name: .text
+#CHECKGROUPSECTIONS: Type: SHT_PROGBITS
+#CHECKGROUPSECTIONS: Flags [ (0x6)
+#CHECKGROUPSECTIONS: SHF_ALLOC (0x2)
+#CHECKGROUPSECTIONS: SHF_EXECINSTR (0x4)
+#CHECKGROUPSECTIONS: ]
+#CHECKGROUPSECTIONS: Size: 2
+#CHECKGROUPSECTIONS: AddressAlignment: 1
+#CHECKGROUPSECTIONS: }
+#CHECKSYMBOLS: Name: foo
+#CHECKSYMBOLS: Type: Function
+#CHECKSYMBOLS: Section: .text
+#CHECKSYMBOLS-NOT: Name: bar
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .group
+ Type: SHT_GROUP
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: foo_group
+ Members:
+ - SectionOrType: GRP_COMDAT
+ - SectionOrType: .text
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR, SHF_GROUP ]
+ AddressAlign: 0x0000000000000001
+ Content: '0000'
+Symbols:
+ Local:
+ - Name: foo_group
+ Section: .group
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ Weak:
+ - Name: foo
+ Section: .text
+...
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .group
+ Type: SHT_GROUP
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: foo_group
+ Members:
+ - SectionOrType: GRP_COMDAT
+ - SectionOrType: .text
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR, SHF_GROUP ]
+ AddressAlign: 0x0000000000000001
+ Content: '0000'
+Symbols:
+ Local:
+ - Name: foo_group
+ Section: .group
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ Global:
+ - Name: bar
+ Section: .text
+ Value: 0x0000000000000002
+ - Name: foo
+ Section: .text
+...
diff --git a/test/elf/sectionGroups/sectiongroup-simple.test b/test/elf/sectionGroups/sectiongroup-simple.test
new file mode 100644
index 000000000000..25be6033b0ef
--- /dev/null
+++ b/test/elf/sectionGroups/sectiongroup-simple.test
@@ -0,0 +1,146 @@
+# Checks that the linker picks the first group in the output file when the file
+# have some members dont appear in the first group.
+# 1a.s
+# ------
+# .section .text,"axG",%progbits,foo_group,comdat
+# .weak foo
+#foo:
+# .word 0
+# 1b.s
+# -----
+# .section .text,"axG",%progbits,foo_group,comdat
+# .global bar
+#bar:
+#RUN: yaml2obj -format=elf -docnum 1 %s -o %t.group1a.o
+#RUN: yaml2obj -format=elf -docnum 2 %s -o %t.group1b.o
+#RUN: lld -flavor gnu -target x86_64 %t.group1a.o %t.group1b.o \
+#RUN: --noinhibit-exec --output-filetype=yaml -o %t2.out.yaml
+#RUN: lld -flavor gnu -target x86_64 %t.group1a.o %t.group1b.o \
+#RUN: --noinhibit-exec -o %t2.out
+#RUN: FileCheck %s -check-prefix=CHECKGROUP < %t2.out.yaml
+#RUN: llvm-readobj -sections %t2.out | FileCheck %s -check-prefix=CHECKGROUPSECTIONS
+#RUN: llvm-readobj -symbols %t2.out | FileCheck %s -check-prefix=CHECKSYMBOLS
+#CHECKGROUP: - name: foo
+#CHECKGROUP: scope: global
+#CHECKGROUP: merge: as-weak
+#CHECKGROUP: section-name: .text
+#CHECKGROUP: - name: foo_group
+#CHECKGROUP: scope: global
+#CHECKGROUP: type: group-comdat
+#CHECKGROUP: section-choice: custom-required
+#CHECKGROUP: section-name: .group
+#CHECKGROUP: permissions: ---
+#CHECKGROUP: references:
+#CHECKGROUP: - kind: group-child
+#CHECKGROUP: offset: 0
+#CHECKGROUP: target: foo
+#CHECKGROUPSECTIONS: Section {
+#CHECKGROUPSECTIONS: Name: .text
+#CHECKGROUPSECTIONS: Type: SHT_PROGBITS
+#CHECKGROUPSECTIONS: Flags [ (0x6)
+#CHECKGROUPSECTIONS: SHF_ALLOC (0x2)
+#CHECKGROUPSECTIONS: SHF_EXECINSTR (0x4)
+#CHECKGROUPSECTIONS: ]
+#CHECKGROUPSECTIONS: Size: 2
+#CHECKGROUPSECTIONS: AddressAlignment: 1
+#CHECKGROUPSECTIONS: }
+#CHECKSYMBOLS: Name: foo
+#CHECKSYMBOLS: Type: Function
+#CHECKSYMBOLS: Section: .text
+
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .group
+ Type: SHT_GROUP
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: foo_group
+ Members:
+ - SectionOrType: GRP_COMDAT
+ - SectionOrType: .text
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR, SHF_GROUP ]
+ AddressAlign: 0x0000000000000001
+ Content: '0000'
+Symbols:
+ Local:
+ - Name: foo_group
+ Section: .group
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ Weak:
+ - Name: foo
+ Section: .text
+...
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .group
+ Type: SHT_GROUP
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: foo_group
+ Members:
+ - SectionOrType: GRP_COMDAT
+ - SectionOrType: .text
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR, SHF_GROUP ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+Symbols:
+ Local:
+ - Name: foo_group
+ Section: .group
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ Global:
+ - Name: bar
+ Section: .text
+...
diff --git a/test/elf/sectionGroups/sectiongroup-undef-member-other.test b/test/elf/sectionGroups/sectiongroup-undef-member-other.test
new file mode 100644
index 000000000000..78a5f276a4ca
--- /dev/null
+++ b/test/elf/sectionGroups/sectiongroup-undef-member-other.test
@@ -0,0 +1,158 @@
+# Tests that linker throws an error for an undefined symbol in the section
+# group, which is the same as the signature in the next input file.
+# comdat1.s
+# ------------
+# .section .foo,"axG",@progbits,g1,comdat
+# .word g1
+#comdat2.s
+#-----------
+# .global g1
+# .section .bar,"axG",@progbits,g1,comdat
+#g2:
+# nop
+# .section .car,"axG",@progbits,g1,comdat
+#g3:
+# nop
+#
+#RUN: yaml2obj -format=elf -docnum 1 %s -o %t.group1a.o
+#RUN: yaml2obj -format=elf -docnum 2 %s -o %t.group1b.o
+#RUN: lld -flavor gnu -target x86_64 %t.group1a.o %t.group1b.o \
+#RUN: --noinhibit-exec -o %t2.out 2>&1 | FileCheck %s
+#CHECK: Undefined symbol: {{.*}} g1
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .group
+ Type: SHT_GROUP
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: g1
+ Members:
+ - SectionOrType: GRP_COMDAT
+ - SectionOrType: .foo
+ - SectionOrType: .rela.foo
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .foo
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR, SHF_GROUP ]
+ AddressAlign: 0x0000000000000001
+ Content: '0000'
+ - Name: .rela.foo
+ Type: SHT_RELA
+ Flags: [ SHF_GROUP ]
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .foo
+ Relocations:
+ - Offset: 0x0000000000000000
+ Symbol: g1
+ Type: R_X86_64_16
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .foo
+ Type: STT_SECTION
+ Section: .foo
+ - Name: .group
+ Type: STT_SECTION
+ Section: .group
+ Global:
+ - Name: g1
+...
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .group
+ Type: SHT_GROUP
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: g1
+ Members:
+ - SectionOrType: GRP_COMDAT
+ - SectionOrType: .bar
+ - SectionOrType: .car
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bar
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR, SHF_GROUP ]
+ AddressAlign: 0x0000000000000001
+ Content: '90'
+ - Name: .car
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR, SHF_GROUP ]
+ AddressAlign: 0x0000000000000001
+ Content: '90'
+Symbols:
+ Local:
+ - Name: g2
+ Section: .bar
+ - Name: g3
+ Section: .car
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .bar
+ Type: STT_SECTION
+ Section: .bar
+ - Name: .car
+ Type: STT_SECTION
+ Section: .car
+ - Name: .group
+ Type: STT_SECTION
+ Section: .group
+ Global:
+ - Name: g1
+ Section: .group
+...
diff --git a/test/elf/sectionGroups/sectiongroup-undef-member.test b/test/elf/sectionGroups/sectiongroup-undef-member.test
new file mode 100644
index 000000000000..2f6804d254d8
--- /dev/null
+++ b/test/elf/sectionGroups/sectiongroup-undef-member.test
@@ -0,0 +1,144 @@
+# Tests that linker throws an error for an undefined symbol in the section
+# group.
+#
+#comdata.s
+#------------
+# .section .foo,"axG",@progbits,g1,comdat
+# .word g1
+#
+#comdatb.s
+#------------
+# .global g1
+# .section .foo,"axG",@progbits,g1,comdat
+#g1:
+# nop
+#
+#RUN: yaml2obj -format=elf -docnum 1 %s -o %t.group1a.o
+#RUN: yaml2obj -format=elf -docnum 2 %s -o %t.group1b.o
+#RUN: lld -flavor gnu -target x86_64 %t.group1a.o %t.group1b.o \
+#RUN: --noinhibit-exec -o %t2.out 2>&1 | FileCheck %s
+#CHECK: Undefined symbol: {{.*}} g1
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .group
+ Type: SHT_GROUP
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: g1
+ Members:
+ - SectionOrType: GRP_COMDAT
+ - SectionOrType: .foo
+ - SectionOrType: .rela.foo
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .foo
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR, SHF_GROUP ]
+ AddressAlign: 0x0000000000000001
+ Content: '0000'
+ - Name: .rela.foo
+ Type: SHT_RELA
+ Flags: [ SHF_GROUP ]
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .foo
+ Relocations:
+ - Offset: 0x0000000000000000
+ Symbol: g1
+ Type: R_X86_64_16
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .foo
+ Type: STT_SECTION
+ Section: .foo
+ - Name: .group
+ Type: STT_SECTION
+ Section: .group
+ Global:
+ - Name: g1
+...
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .group
+ Type: SHT_GROUP
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: g1
+ Members:
+ - SectionOrType: GRP_COMDAT
+ - SectionOrType: .foo
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .foo
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR, SHF_GROUP ]
+ AddressAlign: 0x0000000000000001
+ Content: '90'
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .foo
+ Type: STT_SECTION
+ Section: .foo
+ - Name: .group
+ Type: STT_SECTION
+ Section: .group
+ Global:
+ - Name: g1
+ Section: .foo
+...
diff --git a/test/elf/sectionGroups/sectiongroup-with-globalsymbols.test b/test/elf/sectionGroups/sectiongroup-with-globalsymbols.test
new file mode 100644
index 000000000000..0a28e3c98907
--- /dev/null
+++ b/test/elf/sectionGroups/sectiongroup-with-globalsymbols.test
@@ -0,0 +1,253 @@
+# This tests that comdat weak symbol can be overridden by a global symbol.
+# comdat1.s
+#------------------------
+# .weak g1
+# .section .foo,"axG",@progbits,g1,comdat
+#g1:
+# nop
+# .global g2
+#g2:
+# nop
+#!
+#
+#comdat2.s << \!
+#-----------------
+# .global g1
+# .section .foo,"axG",@progbits,g1,comdat
+#g1:
+# nop
+# .global g2
+#g2:
+# nop
+#
+#cat > g1.c << \!
+#int g1() {
+# return 0;
+#}
+#
+#RUN: yaml2obj -format=elf -docnum 1 %s -o %t.comdat1.o
+#RUN: yaml2obj -format=elf -docnum 2 %s -o %t.comdat2.o
+#RUN: yaml2obj -format=elf -docnum 3 %s -o %t.g1.o
+#RUN: lld -flavor gnu -target x86_64 %t.comdat1.o %t.comdat2.o \
+#RUN: %t.g1.o --noinhibit-exec --output-filetype=yaml -o %t2.out.yaml
+#RUN: lld -flavor gnu -target x86_64 %t.comdat1.o %t.comdat2.o \
+#RUN: %t.g1.o --noinhibit-exec -o %t2.out
+#RUN: FileCheck %s -check-prefix=CHECKGROUP < %t2.out.yaml
+#RUN: llvm-readobj -sections %t2.out | FileCheck %s -check-prefix=CHECKGROUPSECTIONS
+#RUN: llvm-readobj -symbols %t2.out | FileCheck %s -check-prefix=CHECKSYMBOLS
+#CHECKGROUP: - name: g2
+#CHECKGROUP: content: [ 90 ]
+#CHECKGROUP: section-choice: custom-required
+#CHECKGROUP: section-name: .foo
+#CHECKGROUP: - name: g1
+#CHECKGROUP: scope: global
+#CHECKGROUP: content: [ 55, 48, 89, E5, 31, C0, 5D, C3 ]
+#CHECKGROUP: alignment: 2^4
+#CHECKGROUP: section-name: .text
+#CHECKGROUPSECTIONS: Name: .text
+#CHECKGROUPSECTIONS: Type: SHT_PROGBITS
+#CHECKGROUPSECTIONS: Flags [
+#CHECKGROUPSECTIONS: SHF_ALLOC
+#CHECKGROUPSECTIONS: SHF_EXECINSTR
+#CHECKGROUPSECTIONS: ]
+#CHECKGROUPSECTIONS: Size: 8
+#CHECKGROUPSECTIONS: Name: .foo
+#CHECKGROUPSECTIONS: Type: SHT_PROGBITS
+#CHECKGROUPSECTIONS: Flags [
+#CHECKGROUPSECTIONS: SHF_ALLOC
+#CHECKGROUPSECTIONS: SHF_EXECINSTR
+#CHECKGROUPSECTIONS: ]
+#CHECKGROUPSECTIONS: Size: 2
+#CHECKSYMBOLS: Name: g2
+#CHECKSYMBOLS: Section: .foo
+#CHECKSYMBOLS: Name: g1
+#CHECKSYMBOLS: Section: .text
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .group
+ Type: SHT_GROUP
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: g1
+ Members:
+ - SectionOrType: GRP_COMDAT
+ - SectionOrType: .foo
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .foo
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR, SHF_GROUP ]
+ AddressAlign: 0x0000000000000001
+ Content: '9090'
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .foo
+ Type: STT_SECTION
+ Section: .foo
+ Global:
+ - Name: g2
+ Section: .foo
+ Value: 0x0000000000000001
+ Weak:
+ - Name: g1
+ Section: .foo
+...
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .group
+ Type: SHT_GROUP
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: g1
+ Members:
+ - SectionOrType: GRP_COMDAT
+ - SectionOrType: .foo
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .foo
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR, SHF_GROUP ]
+ AddressAlign: 0x0000000000000001
+ Content: '9090'
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .foo
+ Type: STT_SECTION
+ Section: .foo
+ Global:
+ - Name: g1
+ Section: .foo
+ - Name: g2
+ Section: .foo
+ Value: 0x0000000000000001
+...
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000010
+ Content: 554889E531C05DC3
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .comment
+ Type: SHT_PROGBITS
+ Flags: [ SHF_MERGE, SHF_STRINGS ]
+ AddressAlign: 0x0000000000000001
+ Content: 00636C616E672076657273696F6E20332E372E3020287472756E6B203232393535372920286C6C766D2F7472756E6B203232393536332900
+ - Name: .note.GNU-stack
+ Type: SHT_PROGBITS
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .eh_frame
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC ]
+ AddressAlign: 0x0000000000000008
+ Content: 1400000000000000037A5200017810011B0C0708900100001C0000001C000000000000000800000000410E108602430D0600000000000000
+ - Name: .rela.eh_frame
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .eh_frame
+ Relocations:
+ - Offset: 0x0000000000000020
+ Symbol: .text
+ Type: R_X86_64_PC32
+Symbols:
+ Local:
+ - Name: g1.c
+ Type: STT_FILE
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .comment
+ Type: STT_SECTION
+ Section: .comment
+ - Name: .note.GNU-stack
+ Type: STT_SECTION
+ Section: .note.GNU-stack
+ - Name: .eh_frame
+ Type: STT_SECTION
+ Section: .eh_frame
+ Global:
+ - Name: g1
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x0000000000000008
+...
diff --git a/test/elf/sectionGroups/sectiongroup-with-undef-external-reference.test b/test/elf/sectionGroups/sectiongroup-with-undef-external-reference.test
new file mode 100644
index 000000000000..a90034ae6d21
--- /dev/null
+++ b/test/elf/sectionGroups/sectiongroup-with-undef-external-reference.test
@@ -0,0 +1,239 @@
+# This tests that comdat undef symbol is overridden by a global symbol.
+# comdat1.s
+#------------------------
+# .global g1
+# .section .foo,"axG",@progbits,g1,comdat
+#g1:
+# .word 5
+#
+#comdat2.s << \!
+#-----------------
+# .global g1
+# .section .foo,"axG",@progbits,g1,comdat
+#g1:
+# nop
+#
+#g1.c
+#-----------
+#extern int g1;
+#int fn() { return g1;}
+#
+#RUN: yaml2obj -format=elf -docnum 1 %s -o %t.comdat1.o
+#RUN: yaml2obj -format=elf -docnum 2 %s -o %t.comdat2.o
+#RUN: yaml2obj -format=elf -docnum 3 %s -o %t.g1.o
+#RUN: lld -flavor gnu -target x86_64 %t.comdat1.o %t.comdat2.o \
+#RUN: %t.g1.o --noinhibit-exec --output-filetype=yaml -o %t2.out.yaml
+#RUN: lld -flavor gnu -target x86_64 %t.comdat1.o %t.comdat2.o \
+#RUN: %t.g1.o --noinhibit-exec -o %t2.out
+#RUN: FileCheck %s -check-prefix=CHECKGROUP < %t2.out.yaml
+#RUN: llvm-readobj -sections %t2.out | FileCheck %s -check-prefix=CHECKGROUPSECTIONS
+#RUN: llvm-readobj -symbols %t2.out | FileCheck %s -check-prefix=CHECKSYMBOLS
+#CHECKGROUP: - name: g1
+#CHECKGROUP: scope: global
+#CHECKGROUP: content: [ 05, 00 ]
+#CHECKGROUP: section-name: .foo
+#CHECKGROUPSECTIONS: Section {
+#CHECKGROUPSECTIONS: Name: .foo
+#CHECKGROUPSECTIONS: Type: SHT_PROGBITS
+#CHECKGROUPSECTIONS: Flags [
+#CHECKGROUPSECTIONS: SHF_ALLOC
+#CHECKGROUPSECTIONS: SHF_EXECINSTR
+#CHECKGROUPSECTIONS: ]
+#CHECKGROUPSECTIONS: Size: 2
+#CHECKGROUPSECTIONS: }
+#CHECKSYMBOLS: Name: g1
+#CHECKSYMBOLS: Section: .foo
+#CHECKSYMBOLS: Name: fn
+#CHECKSYMBOLS: Section: .text
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .group
+ Type: SHT_GROUP
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: g1
+ Members:
+ - SectionOrType: GRP_COMDAT
+ - SectionOrType: .foo
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .foo
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR, SHF_GROUP ]
+ AddressAlign: 0x0000000000000001
+ Content: '0500'
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .foo
+ Type: STT_SECTION
+ Section: .foo
+ Global:
+ - Name: g1
+ Section: .foo
+...
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .group
+ Type: SHT_GROUP
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: g1
+ Members:
+ - SectionOrType: GRP_COMDAT
+ - SectionOrType: .foo
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .foo
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR, SHF_GROUP ]
+ AddressAlign: 0x0000000000000001
+ Content: '90'
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .foo
+ Type: STT_SECTION
+ Section: .foo
+ Global:
+ - Name: g1
+ Section: .foo
+...
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000010
+ Content: 554889E58B0425000000005DC3
+ - Name: .rela.text
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .text
+ Relocations:
+ - Offset: 0x0000000000000007
+ Symbol: g1
+ Type: R_X86_64_32S
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .comment
+ Type: SHT_PROGBITS
+ Flags: [ SHF_MERGE, SHF_STRINGS ]
+ AddressAlign: 0x0000000000000001
+ Content: 00636C616E672076657273696F6E20332E372E3020287472756E6B203232393535372920286C6C766D2F7472756E6B203232393536332900
+ - Name: .note.GNU-stack
+ Type: SHT_PROGBITS
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .eh_frame
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC ]
+ AddressAlign: 0x0000000000000008
+ Content: 1400000000000000037A5200017810011B0C0708900100001C0000001C000000000000000D00000000410E108602430D0600000000000000
+ - Name: .rela.eh_frame
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .eh_frame
+ Relocations:
+ - Offset: 0x0000000000000020
+ Symbol: .text
+ Type: R_X86_64_PC32
+Symbols:
+ Local:
+ - Name: global-g1.c
+ Type: STT_FILE
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .comment
+ Type: STT_SECTION
+ Section: .comment
+ - Name: .note.GNU-stack
+ Type: STT_SECTION
+ Section: .note.GNU-stack
+ - Name: .eh_frame
+ Type: STT_SECTION
+ Section: .eh_frame
+ Global:
+ - Name: fn
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x000000000000000D
+ - Name: g1
+...
diff --git a/test/elf/sectionGroups/sectiongroup-with-undef-signature.test b/test/elf/sectionGroups/sectiongroup-with-undef-signature.test
new file mode 100644
index 000000000000..11cb5de40a63
--- /dev/null
+++ b/test/elf/sectionGroups/sectiongroup-with-undef-signature.test
@@ -0,0 +1,222 @@
+# This tests that comdat undef symbol is overridden by a global symbol.
+# comdat1.s
+#------------------------
+# .section .foo,"axG",@progbits,g1,comdat
+# word g1
+#
+#comdat2.s << \!
+#-----------------
+# .global g1
+# .section .foo,"axG",@progbits,g1,comdat
+#g1:
+# nop
+#
+#global-g1.c
+#-----------
+#int g1=10;
+#
+#RUN: yaml2obj -format=elf -docnum 1 %s -o %t.comdat1.o
+#RUN: yaml2obj -format=elf -docnum 2 %s -o %t.comdat2.o
+#RUN: yaml2obj -format=elf -docnum 3 %s -o %t.g1.o
+#RUN: lld -flavor gnu -target x86_64 %t.comdat1.o %t.comdat2.o \
+#RUN: %t.g1.o --noinhibit-exec --output-filetype=yaml -o %t2.out.yaml
+#RUN: lld -flavor gnu -target x86_64 %t.comdat1.o %t.comdat2.o \
+#RUN: %t.g1.o --noinhibit-exec -o %t2.out
+#RUN: FileCheck %s -check-prefix=CHECKGROUP < %t2.out.yaml
+#RUN: llvm-readobj -sections %t2.out | FileCheck %s -check-prefix=CHECKGROUPSECTIONS
+#RUN: llvm-readobj -symbols %t2.out | FileCheck %s -check-prefix=CHECKSYMBOLS
+#CHECKGROUP: - name: g1
+#CHECKGROUP: scope: global
+#CHECKGROUP: content: [ 0A, 00, 00, 00 ]
+#CHECKGROUP: section-name: .data
+#CHECKGROUPSECTIONS: Name: .foo
+#CHECKGROUPSECTIONS: Type: SHT_PROGBITS
+#CHECKGROUPSECTIONS: Flags [
+#CHECKGROUPSECTIONS: SHF_ALLOC
+#CHECKGROUPSECTIONS: SHF_EXECINSTR
+#CHECKGROUPSECTIONS: ]
+#CHECKGROUPSECTIONS: Size: 2
+#CHECKGROUPSECTIONS: Name: .data
+#CHECKGROUPSECTIONS: Type: SHT_PROGBITS
+#CHECKGROUPSECTIONS: Flags [
+#CHECKGROUPSECTIONS: SHF_ALLOC
+#CHECKGROUPSECTIONS: SHF_WRITE
+#CHECKGROUPSECTIONS: ]
+#CHECKGROUPSECTIONS: Size: 4
+#CHECKSYMBOLS: Name: g1
+#CHECKSYMBOLS: Section: .data
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .group
+ Type: SHT_GROUP
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: g1
+ Members:
+ - SectionOrType: GRP_COMDAT
+ - SectionOrType: .foo
+ - SectionOrType: .rela.foo
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .foo
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR, SHF_GROUP ]
+ AddressAlign: 0x0000000000000001
+ Content: '0000'
+ - Name: .rela.foo
+ Type: SHT_RELA
+ Flags: [ SHF_GROUP ]
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .foo
+ Relocations:
+ - Offset: 0x0000000000000000
+ Symbol: g1
+ Type: R_X86_64_16
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .foo
+ Type: STT_SECTION
+ Section: .foo
+ Global:
+ - Name: g1
+...
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .group
+ Type: SHT_GROUP
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: g1
+ Members:
+ - SectionOrType: GRP_COMDAT
+ - SectionOrType: .foo
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .foo
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR, SHF_GROUP ]
+ AddressAlign: 0x0000000000000001
+ Content: '90'
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .foo
+ Type: STT_SECTION
+ Section: .foo
+ Global:
+ - Name: g1
+ Section: .foo
+...
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: 0A000000
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .comment
+ Type: SHT_PROGBITS
+ Flags: [ SHF_MERGE, SHF_STRINGS ]
+ AddressAlign: 0x0000000000000001
+ Content: 00636C616E672076657273696F6E20332E372E3020287472756E6B203232393535372920286C6C766D2F7472756E6B203232393536332900
+ - Name: .note.GNU-stack
+ Type: SHT_PROGBITS
+ AddressAlign: 0x0000000000000001
+ Content: ''
+Symbols:
+ Local:
+ - Name: global-g1.c
+ Type: STT_FILE
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .comment
+ Type: STT_SECTION
+ Section: .comment
+ - Name: .note.GNU-stack
+ Type: STT_SECTION
+ Section: .note.GNU-stack
+ Global:
+ - Name: g1
+ Type: STT_OBJECT
+ Section: .data
+ Size: 0x0000000000000004
+...
diff --git a/test/elf/sections.test b/test/elf/sections.test
new file mode 100644
index 000000000000..8839aa6d4e8a
--- /dev/null
+++ b/test/elf/sections.test
@@ -0,0 +1,142 @@
+# This test checks if sections are created properly in the output that appear in
+# the input
+RUN: lld -flavor gnu -target i386 -o %t1 %p/Inputs/section-test.i386 \
+RUN: -static -e baz
+RUN: llvm-objdump -section-headers %t1 | FileCheck -check-prefix=OBJDUMP %s
+RUN: llvm-readobj -h -s -t %t1 | FileCheck -check-prefix=READOBJ %s
+
+OBJDUMP: 0 00000000 0000000000000000
+OBJDUMP: 1 .text 0000000a 0000000000000074 TEXT DATA
+OBJDUMP: 2 .data 00000004 0000000000001000 DATA
+OBJDUMP: 3 .special 00000004 0000000000001004 DATA
+OBJDUMP: 4 .anotherspecial 00000004 0000000000001008 DATA
+OBJDUMP: 5 .bss 00000004 000000000000100c BSS
+OBJDUMP: 6 .shstrtab {{[0-9a-f]+}} 0000000000000000
+OBJDUMP: 7 .symtab {{[0-9a-f]+}} 0000000000000000
+OBJDUMP: 8 .strtab {{[0-9a-f]+}} 0000000000000000
+
+READOBJ: Format: ELF32-i386
+READOBJ: Arch: i386
+READOBJ: AddressSize: 32bit
+READOBJ: ElfHeader {
+READOBJ: Ident {
+READOBJ: DataEncoding: LittleEndian (0x1)
+READOBJ: }
+READOBJ: Machine: EM_386
+READOBJ: }
+
+READOBJ: Sections [
+READOBJ: Section {
+READOBJ: Index: 0
+READOBJ: Name: (0)
+READOBJ: Type: SHT_NULL
+READOBJ: Flags [ (0x0)
+READOBJ: ]
+READOBJ: Address: 0x0
+READOBJ: Size: 0
+READOBJ: }
+READOBJ: Section {
+READOBJ: Index: 1
+READOBJ: Name: .text
+READOBJ: Type: SHT_PROGBITS
+READOBJ: Flags [ (0x6)
+READOBJ: SHF_ALLOC
+READOBJ: SHF_EXECINSTR
+READOBJ: ]
+READOBJ: Address: 0x74
+READOBJ: Size: 10
+READOBJ: AddressAlignment: 4
+READOBJ: }
+READOBJ: Section {
+READOBJ: Index: 2
+READOBJ: Name: .data
+READOBJ: Type: SHT_PROGBITS
+READOBJ: Flags [ (0x3)
+READOBJ: SHF_ALLOC
+READOBJ: SHF_WRITE
+READOBJ: ]
+READOBJ: Address: 0x1000
+READOBJ: Size: 4
+READOBJ: AddressAlignment: 4
+READOBJ: }
+READOBJ: Section {
+READOBJ: Index: 3
+READOBJ: Name: .special
+READOBJ: Type: SHT_PROGBITS
+READOBJ: Flags [ (0x3)
+READOBJ: SHF_ALLOC
+READOBJ: SHF_WRITE
+READOBJ: ]
+READOBJ: Address: 0x1004
+READOBJ: Size: 4
+READOBJ: }
+READOBJ: Section {
+READOBJ: Index: 4
+READOBJ: Name: .anotherspecial
+READOBJ: Type: SHT_PROGBITS
+READOBJ: Flags [ (0x3)
+READOBJ: SHF_ALLOC
+READOBJ: SHF_WRITE
+READOBJ: ]
+READOBJ: Address: 0x1008
+READOBJ: Size: 4
+READOBJ: }
+READOBJ: Section {
+READOBJ: Index: 5
+READOBJ: Name: .bss
+READOBJ: Type: SHT_NOBITS
+READOBJ: Flags [ (0x3)
+READOBJ: SHF_ALLOC
+READOBJ: SHF_WRITE
+READOBJ: ]
+READOBJ: Address: 0x100C
+READOBJ: Size: 4
+READOBJ: }
+READOBJ: Section {
+READOBJ: Index: 6
+READOBJ: Name: .shstrtab
+READOBJ: Type: SHT_STRTAB
+READOBJ: Flags [ (0x0)
+READOBJ: ]
+READOBJ: Address: 0x0
+READOBJ: Link: 0
+READOBJ: AddressAlignment: 1
+READOBJ: }
+READOBJ: Section {
+READOBJ: Index: 7
+READOBJ: Name: .symtab
+READOBJ: Type: SHT_SYMTAB
+READOBJ: Flags [ (0x0)
+READOBJ: ]
+READOBJ: Address: 0x0
+READOBJ: Link: 8
+READOBJ: AddressAlignment: 4
+READOBJ: EntrySize: 16
+READOBJ: }
+READOBJ: Section {
+READOBJ: Index: 8
+READOBJ: Name: .strtab
+READOBJ: Type: SHT_STRTAB
+READOBJ: Flags [ (0x0)
+READOBJ: ]
+READOBJ: Address: 0x0
+READOBJ: }
+READOBJ: ]
+
+READOBJ: Symbols [
+READOBJ: Symbol {
+READOBJ: Name: baz
+READOBJ: Value: 0x74
+READOBJ: Size: 10
+READOBJ: Binding: Global
+READOBJ: Type: Function
+READOBJ: Section: .text
+READOBJ: }
+READOBJ: Symbol {
+READOBJ: Name: y
+READOBJ: Value: 0x1004
+READOBJ: Size: 4
+READOBJ: Binding: Global
+READOBJ: Type: Object
+READOBJ: Section: .special
+READOBJ: }
diff --git a/test/elf/sh_addralign.test b/test/elf/sh_addralign.test
new file mode 100644
index 000000000000..9c7a050f565c
--- /dev/null
+++ b/test/elf/sh_addralign.test
@@ -0,0 +1,38 @@
+# Check handling of section alignment.
+# RUN: yaml2obj -format=elf %s > %t-obj
+# RUN: lld -flavor gnu -target arm64 -o %t-exe %t-obj
+# RUN: llvm-objdump -h %t-exe | FileCheck %s
+
+# CHECK: 8 .data 00000000 0000000000402000 DATA
+
+!ELF
+FileHeader: !FileHeader
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_AARCH64
+
+Sections:
+- Name: .text
+ Type: SHT_PROGBITS
+ Content: ''
+ AddressAlign: 0
+ Flags: [SHF_ALLOC, SHF_EXECINSTR]
+- Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 1
+ Content: ''
+ Size: 0x1000
+- Name: .data
+ Type: SHT_PROGBITS
+ Content: ''
+ AddressAlign: 4096
+ Flags: [SHF_ALLOC, SHF_WRITE]
+
+Symbols:
+ Global:
+ - Name: _start
+ Section: .text
+ Value: 0x0
+ Size: 4
diff --git a/test/elf/soname.test b/test/elf/soname.test
new file mode 100644
index 000000000000..79c089ec607c
--- /dev/null
+++ b/test/elf/soname.test
@@ -0,0 +1,6 @@
+RUN: lld -flavor gnu -shared -target i386 -e main %p/Inputs/writersyms.o \
+RUN: -o %t -soname libtest.so
+RUN: llvm-readobj -dynamic-table %t | FileCheck %s
+
+CHECK: LoadName: libtest.so
+CHECK: 0x0000000E SONAME LibrarySoname (libtest.so)
diff --git a/test/elf/strip-all.test b/test/elf/strip-all.test
new file mode 100644
index 000000000000..44a41c2a0d9f
--- /dev/null
+++ b/test/elf/strip-all.test
@@ -0,0 +1,107 @@
+# Tests the --strip-all (-s) flag. We expect the symbol table to not contain
+# any symbol in the output file.
+#
+# The following code was used to generate the object.
+# $ clang -c blah.c -o blah
+#
+# void
+# callMeMaybe(int *v)
+# {
+# *v += 1;
+# }
+#
+# int
+# main(void)
+# {
+#
+# int blah = 42;
+# callMeMaybe(&blah);
+# }
+
+#RUN: yaml2obj -format=elf %s -o=%t.o
+#RUN: lld -flavor gnu -target x86_64 %t.o -e=main --strip-all -o %t1
+#RUN: llvm-readobj -dt %t1 | FileCheck -check-prefix CHECKSYMS %s
+
+#CHECKSYMS: @
+
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_FREEBSD
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000010
+ Content: 554889E548897DF8488B7DF88B07050100000089075DC3660F1F840000000000554889E54883EC10488D7DFCC745FC2A000000E8C8FFFFFFB8000000004883C4105DC3
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .comment
+ Type: SHT_PROGBITS
+ Flags: [ SHF_MERGE, SHF_STRINGS ]
+ AddressAlign: 0x0000000000000001
+ Content: 004672656542534420636C616E672076657273696F6E20332E342E312028746167732F52454C454153455F33342F646F74312D66696E616C203230383033322920323031343035313200
+ - Name: .note.GNU-stack
+ Type: SHT_PROGBITS
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .eh_frame
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC ]
+ AddressAlign: 0x0000000000000008
+ Content: 1400000000000000017A5200017810011B0C070890010000180000001C000000000000001700000000410E108602430D060000001800000038000000000000002300000000410E108602430D06000000
+ - Name: .rela.eh_frame
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .eh_frame
+ Relocations:
+ - Offset: 0x0000000000000020
+ Symbol: .text
+ Type: R_X86_64_PC32
+ - Offset: 0x000000000000003C
+ Symbol: .text
+ Type: R_X86_64_PC32
+ Addend: 32
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .comment
+ Type: STT_SECTION
+ Section: .comment
+ - Name: .note.GNU-stack
+ Type: STT_SECTION
+ Section: .note.GNU-stack
+ - Name: .eh_frame
+ Type: STT_SECTION
+ Section: .eh_frame
+ Global:
+ - Name: callMeMaybe
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x0000000000000017
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000020
+ Size: 0x0000000000000023
+...
diff --git a/test/elf/stripped-empty.test b/test/elf/stripped-empty.test
new file mode 100644
index 000000000000..0403808db2eb
--- /dev/null
+++ b/test/elf/stripped-empty.test
@@ -0,0 +1,4 @@
+RUN: lld -flavor gnu -shared -o test.so \
+RUN: -target x86_64 %p/Inputs/stripped-empty.x86_64
+
+test that we handle files without a symbol table.
diff --git a/test/elf/symbols.test b/test/elf/symbols.test
new file mode 100644
index 000000000000..7f6bbdbc8c1d
--- /dev/null
+++ b/test/elf/symbols.test
@@ -0,0 +1,33 @@
+# Tests the functionality of archive libraries reading
+# and resolution
+# Note: The binary files would not be required once we have support to generate
+# binary archives from textual(yaml) input
+#
+# Tests generated using the source files below
+# main file
+#
+#extern int __bss_start __attribute__ ((weak));
+#int a;
+#int main()
+#{
+# return 0;
+#}
+#
+
+RUN: lld -flavor gnu -target i386 -e main %p/Inputs/writersyms.o -o %t1
+RUN: llvm-nm -n %t1 | FileCheck -check-prefix CHECKSYMS %s
+RUN: lld -flavor gnu -shared -target i386 -e main %p/Inputs/writersyms.o -o %t1
+RUN: llvm-nm -n %t1 | FileCheck -check-prefix CHECKSHAREDSYMS %s
+
+CHECKSYMS: {{[0-9a-f]+}} a 1.c
+CHECKSYMS: {{[0-9a-f]+}} T main
+CHECKSYMS: {{[0-9a-f]+}} A __bss_start
+CHECKSYMS: {{[0-9a-f]+}} B a
+CHECKSYMS: {{[0-9a-f]+}} A __bss_end
+CHECKSYMS: {{[0-9a-f]+}} A _end
+CHECKSYMS: {{[0-9a-f]+}} A end
+
+CHECKSHAREDSYMS: {{[0-9a-f]+}} a 1.c
+CHECKSHAREDSYMS: {{[0-9a-f]+}} T main
+CHECKSHAREDSYMS: {{[0-9a-f]+}} B a
+CHECKSHAREDSYMS: {{[0-9a-f]+}} A _end
diff --git a/test/elf/tls.test b/test/elf/tls.test
new file mode 100644
index 000000000000..038889406b67
--- /dev/null
+++ b/test/elf/tls.test
@@ -0,0 +1,43 @@
+# REQUIRES: x86
+
+# This tests verifies that TLS variables have correct offsets
+RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/tls.x86-64 -static \
+RUN: --output-filetype=yaml --noinhibit-exec | FileCheck %s -check-prefix=YAML
+
+RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/tls.x86-64 -o %t \
+RUN: --noinhibit-exec -e main -static && llvm-objdump -d %t | FileCheck %s
+
+// Verify that the TLS accesses have the correct offsets.
+
+YAML: name: main
+YAML: references:
+YAML: kind: R_X86_64_TPOFF32
+YAML: offset: 9
+YAML: target: tls1
+YAML: kind: R_X86_64_TPOFF32
+YAML: offset: 17
+YAML: target: tls0
+YAML: kind: R_X86_64_TPOFF32
+YAML: offset: 25
+YAML: target: tls2
+
+YAML: name: GOTTPOFF
+YAML: kind: R_X86_64_PC32
+YAML: target: [[GOTNAME:[a-zA-Z0-9_]+]]
+
+YAML: type: got
+YAML: references:
+YAML: kind: R_X86_64_TPOFF64
+YAML: target: tls2
+
+// main
+CHECK: addl %fs:-4
+CHECK: addl %fs:-8
+CHECK: addl %fs:-12
+
+// GOTTPOFF
+CHECK: movq {{[0-9]+}}(%rip)
+
+// TLSLD
+CHECK: movq %fs:0, %rax
+CHECK: leaq -8(%rax), %rax
diff --git a/test/elf/tlsAddr.test b/test/elf/tlsAddr.test
new file mode 100644
index 000000000000..6bc5e3e9bf78
--- /dev/null
+++ b/test/elf/tlsAddr.test
@@ -0,0 +1,7 @@
+# This tests verifies that TLS variables have correct offsets
+# and that TBSS doesn't occupy memory
+RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/tlsAddr.x86-64 -static \
+RUN: -o %t --noinhibit-exec
+RUN: llvm-objdump -section-headers %t | FileCheck -check-prefix=CHECKADDR %s
+
+CHECKADDR: {{[0-9]+}} .data 00000000 0000000000401008 DATA
diff --git a/test/elf/undef-from-dso-to-main.test b/test/elf/undef-from-dso-to-main.test
new file mode 100644
index 000000000000..71d0b51499dd
--- /dev/null
+++ b/test/elf/undef-from-dso-to-main.test
@@ -0,0 +1,52 @@
+# Tests that a reference from a DSO to a regular object
+# forces the final executable to export the symbol.
+
+#RUN: yaml2obj -format=elf %p/Inputs/undef2-so.o.yaml -o=%t.o.so
+#RUN: lld -flavor gnu -target x86_64 -shared %t.o.so -o %T/libundef2.so
+#RUN: yaml2obj -format=elf %s -o=%t.o
+#RUN: lld -flavor gnu -target x86_64 %t.o -L%T -lundef2 -o %t1
+#RUN: llvm-readobj -dyn-symbols %t1 | FileCheck -check-prefix CHECKSYMS %s
+
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000001
+ Content: C3
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: '002E7379'
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ Global:
+ - Name: myexportedsymbol
+ Type: STT_OBJECT
+ Section: .bss
+ Size: 0x0000000000000004
+ - Name: _start
+ Section: .text
+ Size: 0x0000000000000001
+
+#CHECKSYMS: myexportedsymbol
diff --git a/test/elf/undef-from-main-dso.test b/test/elf/undef-from-main-dso.test
new file mode 100644
index 000000000000..43faef0e74c4
--- /dev/null
+++ b/test/elf/undef-from-main-dso.test
@@ -0,0 +1,43 @@
+RUN: lld -flavor gnu -target x86_64 -e main -o %t -L%p/Inputs \
+RUN: %p/Inputs/undef.o -lundef
+RUN: llvm-readobj -relocations -symbols -dyn-symbols %t | FileCheck %s
+
+RUN: lld -flavor gnu -target x86_64 -e main -o %t -L%p/Inputs \
+RUN: %p/Inputs/undef-pc32.o -lundef
+RUN: llvm-readobj -relocations -symbols -dyn-symbols %t | FileCheck %s
+
+# DSO source code:
+# int x[2] = { 1, 2 };
+#
+# Main binary source code:
+#
+# extern int x[2];
+#
+# int main(void)
+# {
+# x[0] = 2;
+# }
+#
+
+CHECK: Relocations [
+CHECK-NEXT: Section ({{[0-9]+}}) .rela.dyn {
+CHECK-NEXT: 0x{{[1-9A-F][0-9A-F]*}} R_X86_64_COPY x 0x0
+CHECK-NEXT: }
+CHECK-NEXT: ]
+
+CHECK: Name: x ({{[0-9]+}}
+CHECK-NEXT: Value: 0x{{[1-9A-F][0-9A-F]*}}
+CHECK-NEXT: Size: 8
+CHECK-NEXT: Binding: Global (0x1)
+CHECK-NEXT: Type: Object (0x1)
+CHECK-NEXT: Other: 0
+CHECK-NEXT: Section: .bss
+
+CHECK: Name: x@ ({{[0-9]+}}
+CHECK-NEXT: Value: 0x{{[1-9A-F][0-9A-F]*}}
+CHECK-NEXT: Size: 8
+CHECK-NEXT: Binding: Global (0x1)
+CHECK-NEXT: Type: Object (0x1)
+CHECK-NEXT: Other: 0
+CHECK-NEXT: Section: .bss
+
diff --git a/test/elf/weaksym.test b/test/elf/weaksym.test
new file mode 100644
index 000000000000..0e265028e5ed
--- /dev/null
+++ b/test/elf/weaksym.test
@@ -0,0 +1,7 @@
+# Tests that a weak reference remains a weak reference,
+# even if a shared library defines the symbol weak as well.
+
+RUN: lld -flavor gnu -target x86_64 -shared %p/Inputs/weaksym.o -L%p/Inputs -lweaksym -o %t1
+RUN: llvm-nm -n %t1 | FileCheck -check-prefix CHECKSYMS %s
+
+CHECKSYMS: w weaksym
diff --git a/test/elf/wrap.test b/test/elf/wrap.test
new file mode 100644
index 000000000000..997439f8f5b4
--- /dev/null
+++ b/test/elf/wrap.test
@@ -0,0 +1,279 @@
+# This tests the functionality of using the --wrap option.
+# The test case is extracted by compiling and linking the following code.
+#
+#cat > main.c << \!
+#int main() {
+# foo();
+# return 0;
+#}
+#!
+#
+#cat > wrapfoo.c << \!
+#int __wrap_foo() {
+# __real_foo();
+# return 0;
+#}
+#!
+#
+#cat > realfoo.c << \!
+#int foo() {
+# return 0;
+#}
+#!
+#
+#clang main.c wrapfoo.c realfoo.c -Xlinker --wrap -Xlinker foo
+#RUN: yaml2obj -format=elf -docnum 1 %s -o %t.main.o
+#RUN: yaml2obj -format=elf -docnum 2 %s -o %t.wrapfoo.o
+#RUN: yaml2obj -format=elf -docnum 3 %s -o %t.realfoo.o
+#RUN: lld -flavor gnu -target x86_64 %t.main.o %t.wrapfoo.o %t.realfoo.o \
+#RUN: --wrap foo --wrap foo --noinhibit-exec --output-filetype=yaml -o %t2.out
+#RUN: lld -flavor gnu -target x86_64 %t.main.o %t.wrapfoo.o \
+#RUN: --wrap foo --wrap foo --noinhibit-exec --output-filetype=yaml -o %t2.out.undef 2>&1 | \
+#RUN: FileCheck %s -check-prefix=CHECKUNDEF
+#CHECKWRAP: - name: main
+#CHECKWRAP: references:
+#CHECKWRAP: - kind: R_X86_64_PC32
+#CHECKWRAP: target: __wrap_foo
+#CHECKWRAP: - name: __wrap_foo
+#CHECKWRAP: references:
+#CHECKWRAP: - kind: R_X86_64_PC32
+#CHECKWRAP: target: foo
+#CHECKUNDEF: Undefined symbol: {{.*}}main.o: foo
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000010
+ Content: 5031C0E80000000031C05AC3
+ - Name: .rela.text
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .text
+ Relocations:
+ - Offset: 0x0000000000000004
+ Symbol: foo
+ Type: R_X86_64_PC32
+ Addend: -4
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .comment
+ Type: SHT_PROGBITS
+ Flags: [ SHF_MERGE, SHF_STRINGS ]
+ AddressAlign: 0x0000000000000001
+ Content: 00636C616E672076657273696F6E20332E372E3020287472756E6B203232383733392920286C6C766D2F7472756E6B203232383734382900
+ - Name: .note.GNU-stack
+ Type: SHT_PROGBITS
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .eh_frame
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC ]
+ AddressAlign: 0x0000000000000008
+ Content: 1400000000000000037A5200017810011B0C070890010000140000001C000000000000000C00000000410E1000000000
+ - Name: .rela.eh_frame
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .eh_frame
+ Relocations:
+ - Offset: 0x0000000000000020
+ Symbol: .text
+ Type: R_X86_64_PC32
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .comment
+ Type: STT_SECTION
+ Section: .comment
+ - Name: .note.GNU-stack
+ Type: STT_SECTION
+ Section: .note.GNU-stack
+ - Name: .eh_frame
+ Type: STT_SECTION
+ Section: .eh_frame
+ Global:
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x000000000000000C
+ - Name: foo
+...
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000010
+ Content: 5031C0E80000000031C05AC3
+ - Name: .rela.text
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .text
+ Relocations:
+ - Offset: 0x0000000000000004
+ Symbol: __real_foo
+ Type: R_X86_64_PC32
+ Addend: -4
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .comment
+ Type: SHT_PROGBITS
+ Flags: [ SHF_MERGE, SHF_STRINGS ]
+ AddressAlign: 0x0000000000000001
+ Content: 00636C616E672076657273696F6E20332E372E3020287472756E6B203232383733392920286C6C766D2F7472756E6B203232383734382900
+ - Name: .note.GNU-stack
+ Type: SHT_PROGBITS
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .eh_frame
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC ]
+ AddressAlign: 0x0000000000000008
+ Content: 1400000000000000037A5200017810011B0C070890010000140000001C000000000000000C00000000410E1000000000
+ - Name: .rela.eh_frame
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .eh_frame
+ Relocations:
+ - Offset: 0x0000000000000020
+ Symbol: .text
+ Type: R_X86_64_PC32
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .comment
+ Type: STT_SECTION
+ Section: .comment
+ - Name: .note.GNU-stack
+ Type: STT_SECTION
+ Section: .note.GNU-stack
+ - Name: .eh_frame
+ Type: STT_SECTION
+ Section: .eh_frame
+ Global:
+ - Name: __wrap_foo
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x000000000000000C
+ - Name: __real_foo
+...
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000010
+ Content: 31C0C3
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+ - Name: .comment
+ Type: SHT_PROGBITS
+ Flags: [ SHF_MERGE, SHF_STRINGS ]
+ AddressAlign: 0x0000000000000001
+ Content: 00636C616E672076657273696F6E20332E372E3020287472756E6B203232383733392920286C6C766D2F7472756E6B203232383734382900
+ - Name: .note.GNU-stack
+ Type: SHT_PROGBITS
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .eh_frame
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC ]
+ AddressAlign: 0x0000000000000008
+ Content: 1400000000000000037A5200017810011B0C070890010000140000001C00000000000000030000000000000000000000
+ - Name: .rela.eh_frame
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .eh_frame
+ Relocations:
+ - Offset: 0x0000000000000020
+ Symbol: .text
+ Type: R_X86_64_PC32
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .comment
+ Type: STT_SECTION
+ Section: .comment
+ - Name: .note.GNU-stack
+ Type: STT_SECTION
+ Section: .note.GNU-stack
+ - Name: .eh_frame
+ Type: STT_SECTION
+ Section: .eh_frame
+ Global:
+ - Name: foo
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x0000000000000003
+...
diff --git a/test/elf/x86-64-dynamic-relocs.test b/test/elf/x86-64-dynamic-relocs.test
new file mode 100644
index 000000000000..325693e3f714
--- /dev/null
+++ b/test/elf/x86-64-dynamic-relocs.test
@@ -0,0 +1,26 @@
+RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/relocs-dynamic.x86-64 \
+RUN: --output-filetype=yaml --noinhibit-exec | FileCheck %s
+
+path: <linker-internal>
+defined-atoms:
+ - name: main
+ scope: global
+ content: [ E8, 00, 00, 00, 00, C3 ]
+ alignment: 2^4
+ section-choice: custom-required
+ section-name: .text
+ references:
+ - kind: R_X86_64_PLT32
+ offset: 1
+ target: foo
+ addend: -4
+ - name: foo
+ scope: global
+ content: [ C3 ]
+ alignment: 6 mod 2^4
+ section-choice: custom-required
+ section-name: .text
+
+# Don't generate a PLT/GOT entry for a PLT32 relocation to a non-shared symbol.
+CHECK-NOT: got
+CHECK-NOT: stub
diff --git a/test/elf/x86-64-dynamic.test b/test/elf/x86-64-dynamic.test
new file mode 100644
index 000000000000..4e24e954a20e
--- /dev/null
+++ b/test/elf/x86-64-dynamic.test
@@ -0,0 +1,79 @@
+# Checks that linking an object file with a shared object creates the necessary
+# PLT/GOT Entries
+RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/use-shared.x86-64 \
+RUN: %p/Inputs/shared.so-x86-64 --output-filetype=yaml -o %t1 --noinhibit-exec
+RUN: FileCheck %s < %t1
+
+RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/use-shared-32s.x86-64 \
+RUN: %p/Inputs/shared.so-x86-64 --output-filetype=yaml --noinhibit-exec \
+RUN: | FileCheck %s --check-prefix=32S
+
+CHECK: - name: main
+CHECK: scope: global
+CHECK: references:
+CHECK: - kind: R_X86_64_PC32
+CHECK: offset: 18
+CHECK: target: [[PLTNAME:[-a-zA-Z0-9_]+]]
+CHECK: addend: -4
+CHECK: - kind: R_X86_64_GOTPCREL
+CHECK: offset: 25
+CHECK: target: [[GOTNAME:[-a-zA-Z0-9_]+]]
+CHECK: addend: -4
+
+ - name: .PLT0
+CHECK: type: stub
+CHECK: content: [ FF, 35, 00, 00, 00, 00, FF, 25, 00, 00, 00, 00,
+CHECK: 90, 90, 90, 90 ]
+CHECK: alignment: 2^4
+CHECK: section-choice: custom-required
+CHECK: section-name: .plt
+CHECK: references:
+CHECK: - kind: R_X86_64_PC32
+CHECK: offset: 2
+ target: __got0
+CHECK: addend: -4
+CHECK: - kind: R_X86_64_PC32
+CHECK: offset: 8
+ target: __got1
+CHECK: addend: -4
+ - name: [[PLTNAME]]
+CHECK: type: stub
+CHECK: content: [ FF, 25, 00, 00, 00, 00, 68, 00, 00, 00, 00, E9,
+CHECK: 00, 00, 00, 00 ]
+CHECK: alignment: 2^4
+CHECK: section-choice: custom-required
+CHECK: section-name: .plt
+CHECK: references:
+CHECK: - kind: R_X86_64_PC32
+CHECK: offset: 2
+ target: __got_foo
+CHECK: addend: -4
+CHECK: - kind: LLD_R_X86_64_GOTRELINDEX
+CHECK: offset: 7
+ target: __got_foo
+CHECK: - kind: R_X86_64_PC32
+CHECK: offset: 12
+ target: .PLT0
+CHECK: addend: -4
+
+// Don't check the GOT and PLT names as they are only present in assert builds.
+CHECK: type: got
+CHECK: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ]
+CHECK: section-choice: custom-required
+CHECK: section-name: .got
+CHECK: permissions: rw-
+CHECK: references:
+CHECK: - kind: R_X86_64_GLOB_DAT
+CHECK: offset: 0
+CHECK: target: i
+
+CHECK:shared-library-atoms:
+CHECK: - name: foo
+CHECK: load-name: shared.so-x86-64
+
+32S: name: main
+32S: kind: R_X86_64_PC32
+32S: target: func
+32S: kind: R_X86_64_32S
+32S: kind: R_X86_64_PC32
+32S: type: stub
diff --git a/test/elf/x86.test b/test/elf/x86.test
new file mode 100644
index 000000000000..6b68837193e6
--- /dev/null
+++ b/test/elf/x86.test
@@ -0,0 +1,38 @@
+# Source for input file: reloc-xb.x86
+# xb.S:
+# .section .text, "ax", @progbits
+# .align 0x4
+# .globl _start
+# _start:
+# .globl back
+# back:
+# call target
+#
+# Source for input file: reloc-xt.x86
+# xt.S:
+# .section .text, "ax", @progbits
+#
+# .globl target
+# target:
+# call back
+#
+# Assembled with: "as --32"
+
+RUN: lld -flavor gnu -target i386 -e back --output-filetype=yaml %p/Inputs/reloc-xb.x86 %p/Inputs/reloc-xt.x86 | FileCheck %s -check-prefix x86-yaml
+
+x86-yaml: - name: back
+x86-yaml: scope: global
+x86-yaml: content: [ E8, FC, FF, FF, FF ]
+x86-yaml: references:
+x86-yaml: - kind: R_386_PC32
+x86-yaml: offset: 1
+x86-yaml: target: target
+
+x86-yaml: - name: target
+x86-yaml: scope: global
+x86-yaml: content: [ E8, FC, FF, FF, FF ]
+x86-yaml: references:
+x86-yaml: - kind: R_386_PC32
+x86-yaml: offset: 1
+x86-yaml: target: back
+
diff --git a/test/elf/x86_64-kinds.test b/test/elf/x86_64-kinds.test
new file mode 100644
index 000000000000..49586059d953
--- /dev/null
+++ b/test/elf/x86_64-kinds.test
@@ -0,0 +1,23 @@
+REQUIRES: x86
+
+RUN: lld -flavor gnu -target x86_64-linux -o %t1 %p/Inputs/relocs.x86-64 \
+RUN: -e _start -static
+RUN: llvm-objdump -d %t1 | FileCheck %s -check-prefix=RELOCS
+
+RUN: lld -flavor gnu -target x86_64-linux --output-filetype=yaml -e _start -static \
+RUN: %p/Inputs/relocs.x86-64 | FileCheck %s -check-prefix=X86_64
+
+RELOCS: ELF64-x86-64
+
+// R_X86_64_32S
+RELOCS: c7 04 25
+RELOCS-NOT: 00 00 00 00
+RELOCS: 05 00 00 00 movl
+
+// R_X86_64_PC32
+RELOCS: e8
+RELOCS-NOT: 00 00 00 00
+RELOCS: callq
+
+X86_64: R_X86_64_32S
+X86_64: R_X86_64_PC32
diff --git a/test/lit.cfg b/test/lit.cfg
new file mode 100644
index 000000000000..5b49765f7894
--- /dev/null
+++ b/test/lit.cfg
@@ -0,0 +1,167 @@
+# -*- Python -*-
+
+import os
+import platform
+import re
+import subprocess
+import locale
+
+import lit.formats
+import lit.util
+
+# Configuration file for the 'lit' test runner.
+
+# name: The name of this test suite.
+config.name = 'lld'
+
+# testFormat: The test format to use to interpret tests.
+#
+# For now we require '&&' between commands, until they get globally killed and
+# the test runner updated.
+execute_external = (platform.system() != 'Windows'
+ or lit_config.getBashPath() not in [None, ""])
+config.test_format = lit.formats.ShTest(execute_external)
+
+# suffixes: A list of file extensions to treat as test files.
+config.suffixes = ['.objtxt', '.test']
+
+# test_source_root: The root path where tests are located.
+config.test_source_root = os.path.dirname(__file__)
+
+# test_exec_root: The root path where tests should be run.
+lld_obj_root = getattr(config, 'lld_obj_root', None)
+if lld_obj_root is not None:
+ config.test_exec_root = os.path.join(lld_obj_root, 'test')
+
+# Set llvm_{src,obj}_root for use by others.
+config.llvm_src_root = getattr(config, 'llvm_src_root', None)
+config.llvm_obj_root = getattr(config, 'llvm_obj_root', None)
+
+# Tweak the PATH to include the tools dir and the scripts dir.
+if lld_obj_root is not None:
+ llvm_tools_dir = getattr(config, 'llvm_tools_dir', None)
+ if not llvm_tools_dir:
+ lit_config.fatal('No LLVM tools dir set!')
+ path = os.path.pathsep.join((llvm_tools_dir, config.environment['PATH']))
+ path = os.path.pathsep.join((os.path.join(getattr(config, 'llvm_src_root', None),'test','Scripts'),path))
+
+ config.environment['PATH'] = path
+
+ llvm_libs_dir = getattr(config, 'llvm_libs_dir', None)
+ if not llvm_libs_dir:
+ lit_config.fatal('No LLVM libs dir set!')
+ path = os.path.pathsep.join((llvm_libs_dir,
+ config.environment.get('LD_LIBRARY_PATH','')))
+ config.environment['LD_LIBRARY_PATH'] = path
+
+ # Propagate LLVM_SRC_ROOT into the environment.
+ config.environment['LLVM_SRC_ROOT'] = getattr(config, 'llvm_src_root', '')
+
+ # Propagate PYTHON_EXECUTABLE into the environment
+ config.environment['PYTHON_EXECUTABLE'] = getattr(config, 'python_executable',
+ '')
+###
+
+# Check that the object root is known.
+if config.test_exec_root is None:
+ # Otherwise, we haven't loaded the site specific configuration (the user is
+ # probably trying to run on a test file directly, and either the site
+ # configuration hasn't been created by the build system, or we are in an
+ # out-of-tree build situation).
+
+ # Check for 'lld_site_config' user parameter, and use that if available.
+ site_cfg = lit_config.params.get('lld_site_config', None)
+ if site_cfg and os.path.exists(site_cfg):
+ lit_config.load_config(config, site_cfg)
+ raise SystemExit
+
+ # Try to detect the situation where we are using an out-of-tree build by
+ # looking for 'llvm-config'.
+ #
+ # FIXME: I debated (i.e., wrote and threw away) adding logic to
+ # automagically generate the lit.site.cfg if we are in some kind of fresh
+ # build situation. This means knowing how to invoke the build system though,
+ # and I decided it was too much magic. We should solve this by just having
+ # the .cfg files generated during the configuration step.
+
+ llvm_config = lit.util.which('llvm-config', config.environment['PATH'])
+ if not llvm_config:
+ lit_config.fatal('No site specific configuration available!')
+
+ # Get the source and object roots.
+ llvm_src_root = lit.util.capture(['llvm-config', '--src-root']).strip()
+ llvm_obj_root = lit.util.capture(['llvm-config', '--obj-root']).strip()
+ lld_src_root = os.path.join(llvm_src_root, "tools", "lld")
+ lld_obj_root = os.path.join(llvm_obj_root, "tools", "lld")
+
+ # Validate that we got a tree which points to here, using the standard
+ # tools/lld layout.
+ this_src_root = os.path.dirname(config.test_source_root)
+ if os.path.realpath(lld_src_root) != os.path.realpath(this_src_root):
+ lit_config.fatal('No site specific configuration available!')
+
+ # Check that the site specific configuration exists.
+ site_cfg = os.path.join(lld_obj_root, 'test', 'lit.site.cfg')
+ if not os.path.exists(site_cfg):
+ lit_config.fatal(
+ 'No site specific configuration available! You may need to '
+ 'run "make test" in your lld build directory.')
+
+ # Okay, that worked. Notify the user of the automagic, and reconfigure.
+ lit_config.note('using out-of-tree build at %r' % lld_obj_root)
+ lit_config.load_config(config, site_cfg)
+ raise SystemExit
+
+# When running under valgrind, we mangle '-vg' onto the end of the triple so we
+# can check it with XFAIL and XTARGET.
+if lit_config.useValgrind:
+ config.target_triple += '-vg'
+
+# Shell execution
+if platform.system() not in ['Windows'] or lit_config.getBashPath() != '':
+ config.available_features.add('shell')
+
+# Running on Darwin OS
+if platform.system() in ['Darwin']:
+ config.available_features.add('system-linker-mach-o')
+
+# Running on ELF based *nix
+if platform.system() in ['FreeBSD', 'Linux']:
+ config.available_features.add('system-linker-elf')
+
+# llvm-config knows whether it is compiled with asserts (and)
+# whether we are operating in release/debug mode.
+import subprocess
+try:
+ llvm_config_cmd = \
+ subprocess.Popen([os.path.join(llvm_tools_dir, 'llvm-config'),
+ '--build-mode', '--assertion-mode', '--targets-built'],
+ stdout = subprocess.PIPE)
+except OSError as why:
+ print("Could not find llvm-config in " + llvm_tools_dir)
+ exit(42)
+
+llvm_config_output = llvm_config_cmd.stdout.read().decode('utf_8')
+llvm_config_output_list = llvm_config_output.split("\n")
+
+if re.search(r'DEBUG', llvm_config_output_list[0]):
+ config.available_features.add('debug')
+if re.search(r'ON', llvm_config_output_list[1]):
+ config.available_features.add('asserts')
+if re.search(r'ARM', llvm_config_output_list[2]):
+ config.available_features.add('arm')
+if re.search(r'Mips', llvm_config_output_list[2]):
+ config.available_features.add('mips')
+if re.search(r'X86', llvm_config_output_list[2]):
+ config.available_features.add('x86')
+llvm_config_cmd.wait()
+
+# Check if Windows resource file compiler exists.
+cvtres = lit.util.which('cvtres', config.environment['PATH'])
+rc = lit.util.which('rc', config.environment['PATH'])
+if cvtres and rc:
+ config.available_features.add('winres')
+
+# Check if "lib.exe" command exists.
+if lit.util.which('lib.exe', config.environment['PATH']):
+ config.available_features.add('winlib')
diff --git a/test/lit.site.cfg.in b/test/lit.site.cfg.in
new file mode 100644
index 000000000000..0eeb889d1b20
--- /dev/null
+++ b/test/lit.site.cfg.in
@@ -0,0 +1,22 @@
+## Autogenerated by LLVM/lld configuration.
+# Do not edit!
+config.llvm_src_root = "@LLVM_SOURCE_DIR@"
+config.llvm_obj_root = "@LLVM_BINARY_DIR@"
+config.llvm_tools_dir = "@LLVM_TOOLS_DIR@"
+config.llvm_libs_dir = "@LLVM_LIBS_DIR@"
+config.lit_tools_dir = "@LLVM_LIT_TOOLS_DIR@"
+config.lld_obj_root = "@LLD_BINARY_DIR@"
+config.target_triple = "@TARGET_TRIPLE@"
+config.python_executable = "@PYTHON_EXECUTABLE@"
+
+# Support substitution of the tools and libs dirs with user parameters. This is
+# used when we can't determine the tool dir at configuration time.
+try:
+ config.llvm_tools_dir = config.llvm_tools_dir % lit_config.params
+ config.llvm_libs_dir = config.llvm_libs_dir % lit_config.params
+except KeyError as e:
+ key, = e.args
+ lit_config.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key,key))
+
+# Let the main config do the real work.
+lit_config.load_config(config, "@LLD_SOURCE_DIR@/test/lit.cfg")
diff --git a/test/mach-o/Inputs/DependencyDump.py b/test/mach-o/Inputs/DependencyDump.py
new file mode 100755
index 000000000000..0f4d49d6fb9a
--- /dev/null
+++ b/test/mach-o/Inputs/DependencyDump.py
@@ -0,0 +1,30 @@
+# -*- Python -*-
+
+
+#
+# Dump out Xcode binary dependency file.
+#
+
+import sys
+
+f = open(sys.argv[1], "rb")
+byte = f.read(1)
+while byte != b'':
+ if byte == b'\000':
+ sys.stdout.write("linker-vers: ")
+ elif byte == b'\020':
+ sys.stdout.write("input-file: ")
+ elif byte == b'\021':
+ sys.stdout.write("not-found: ")
+ elif byte == b'\100':
+ sys.stdout.write("output-file: ")
+ byte = f.read(1)
+ while byte != b'\000':
+ if byte != b'\012':
+ sys.stdout.write(byte.decode("ascii"))
+ byte = f.read(1)
+ sys.stdout.write("\n")
+ byte = f.read(1)
+
+f.close()
+
diff --git a/test/mach-o/Inputs/bar.yaml b/test/mach-o/Inputs/bar.yaml
new file mode 100644
index 000000000000..5605e67e7c35
--- /dev/null
+++ b/test/mach-o/Inputs/bar.yaml
@@ -0,0 +1,18 @@
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0xC3 ]
+global-symbols:
+ - name: _bar
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
diff --git a/test/mach-o/Inputs/exported_symbols_list.exp b/test/mach-o/Inputs/exported_symbols_list.exp
new file mode 100644
index 000000000000..ff6653342472
--- /dev/null
+++ b/test/mach-o/Inputs/exported_symbols_list.exp
@@ -0,0 +1,6 @@
+#
+# For use with exported_symbols_list.yaml
+#
+_foo
+_b
+
diff --git a/test/mach-o/Inputs/full.filelist b/test/mach-o/Inputs/full.filelist
new file mode 100644
index 000000000000..abf98b633377
--- /dev/null
+++ b/test/mach-o/Inputs/full.filelist
@@ -0,0 +1,3 @@
+/foo/bar/a.o
+/foo/bar/b.o
+/foo/x.a
diff --git a/test/mach-o/Inputs/lib-search-paths/usr/lib/libmyshared.dylib b/test/mach-o/Inputs/lib-search-paths/usr/lib/libmyshared.dylib
new file mode 100755
index 000000000000..71185fbdf736
--- /dev/null
+++ b/test/mach-o/Inputs/lib-search-paths/usr/lib/libmyshared.dylib
Binary files differ
diff --git a/test/mach-o/Inputs/lib-search-paths/usr/lib/libmystatic.a b/test/mach-o/Inputs/lib-search-paths/usr/lib/libmystatic.a
new file mode 100644
index 000000000000..b12062941f37
--- /dev/null
+++ b/test/mach-o/Inputs/lib-search-paths/usr/lib/libmystatic.a
Binary files differ
diff --git a/test/mach-o/Inputs/lib-search-paths/usr/local/lib/file.o b/test/mach-o/Inputs/lib-search-paths/usr/local/lib/file.o
new file mode 100644
index 000000000000..f9a923d37db3
--- /dev/null
+++ b/test/mach-o/Inputs/lib-search-paths/usr/local/lib/file.o
Binary files differ
diff --git a/test/mach-o/Inputs/libSystem.yaml b/test/mach-o/Inputs/libSystem.yaml
new file mode 100644
index 000000000000..2a7f46381dcc
--- /dev/null
+++ b/test/mach-o/Inputs/libSystem.yaml
@@ -0,0 +1,13 @@
+#
+# For use by test cases that create dynamic output types which may needs stubs
+# and therefore will need a dylib definition of dyld_stub_binder.
+#
+
+---
+shared-library-atoms:
+ - name: dyld_stub_binder
+ load-name: /usr/lib/libSystem.B.dylib
+ type: code
+ size: 0
+
+...
diff --git a/test/mach-o/Inputs/libbar.a b/test/mach-o/Inputs/libbar.a
new file mode 100644
index 000000000000..64cae6c749ee
--- /dev/null
+++ b/test/mach-o/Inputs/libbar.a
Binary files differ
diff --git a/test/mach-o/Inputs/libfoo.a b/test/mach-o/Inputs/libfoo.a
new file mode 100644
index 000000000000..21194efbabf9
--- /dev/null
+++ b/test/mach-o/Inputs/libfoo.a
Binary files differ
diff --git a/test/mach-o/Inputs/order_file-basic.order b/test/mach-o/Inputs/order_file-basic.order
new file mode 100644
index 000000000000..0ac90cb79da7
--- /dev/null
+++ b/test/mach-o/Inputs/order_file-basic.order
@@ -0,0 +1,11 @@
+
+# input file for order_file-basic.yaml
+
+_func2
+libfoo.a(foo.o):_foo # tests file specific ordering within archive
+i386:_func3 # wrong arch, so ignored
+armv7:_func3 # wrong arch, so ignored
+_func1
+_notfound # unknown symbol silently ignored
+_data3 # data symbols should be orderable
+
diff --git a/test/mach-o/Inputs/partial.filelist b/test/mach-o/Inputs/partial.filelist
new file mode 100644
index 000000000000..281581bf00fc
--- /dev/null
+++ b/test/mach-o/Inputs/partial.filelist
@@ -0,0 +1,3 @@
+bar/a.o
+bar/b.o
+x.a
diff --git a/test/mach-o/Inputs/use-dylib-install-names.yaml b/test/mach-o/Inputs/use-dylib-install-names.yaml
new file mode 100644
index 000000000000..cec2559f2435
--- /dev/null
+++ b/test/mach-o/Inputs/use-dylib-install-names.yaml
@@ -0,0 +1,28 @@
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ ]
+has-UUID: false
+OS: unknown
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0x55, 0x48, 0x89, 0xE5, 0xE8, 0x00, 0x00, 0x00,
+ 0x00, 0xE8, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x00,
+ 0x00, 0x00, 0x00, 0xE8, 0x00, 0x00, 0x00, 0x00,
+ 0xE8, 0x00, 0x00, 0x00, 0x00, 0x5D, 0xE9, 0x00,
+ 0x00, 0x00, 0x00 ]
+global-symbols:
+ - name: _foo
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+undefined-symbols:
+ - name: _myGlobal
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
diff --git a/test/mach-o/PIE.yaml b/test/mach-o/PIE.yaml
new file mode 100644
index 000000000000..2e50951a4544
--- /dev/null
+++ b/test/mach-o/PIE.yaml
@@ -0,0 +1,44 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t && \
+# RUN: llvm-objdump -macho -private-headers %t | FileCheck %s
+#
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -pie -o %t\
+# RUN: && llvm-objdump -macho -private-headers %t | FileCheck %s
+#
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -no_pie -o %t\
+# RUN: && llvm-objdump -macho -private-headers %t \
+# RUN: | FileCheck --check-prefix=CHECK_NO_PIE %s
+#
+# Test various PIE options.
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID: false
+OS: unknown
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0xC3 ]
+global-symbols:
+ - name: _main
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+
+--- !mach-o
+arch: x86_64
+file-type: MH_DYLIB
+install-name: /usr/lib/libSystem.B.dylib
+exports:
+ - name: dyld_stub_binder
+
+...
+
+# CHECK: MH_MAGIC_64 {{[0-9a-zA-Z _]+}} TWOLEVEL PIE
+# CHECK_NO_PIE-NOT: MH_MAGIC_64 {{[0-9a-zA-Z _]+}} TWOLEVEL PIE
diff --git a/test/mach-o/align_text.yaml b/test/mach-o/align_text.yaml
new file mode 100644
index 000000000000..5ddbf911b9e5
--- /dev/null
+++ b/test/mach-o/align_text.yaml
@@ -0,0 +1,45 @@
+# RUN: lld -flavor darwin -arch x86_64 -r %s -o %t -print_atoms | FileCheck %s
+# RUN: lld -flavor darwin -arch x86_64 -r %t -o %t2 -print_atoms | FileCheck %s
+#
+# Test that alignment info round trips through -r
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ alignment: 4
+ address: 0x0000000000000000
+ content: [ 0x90, 0x90, 0x90, 0xC3, 0xC3, 0xC3 ]
+local-symbols:
+ - name: _f1
+ type: N_SECT
+ sect: 1
+ value: 0x0000000000000003
+ - name: _f2
+ type: N_SECT
+ sect: 1
+ value: 0x0000000000000004
+ - name: _f3
+ type: N_SECT
+ sect: 1
+ value: 0x0000000000000005
+...
+
+# CHECK: defined-atoms:
+# CHECK: - content: [ 90, 90, 90 ]
+# CHECK: alignment: 2^4
+# CHECK: - name: _f1
+# CHECK: content: [ C3 ]
+# CHECK: alignment: 3 mod 2^4
+# CHECK: - name: _f2
+# CHECK: content: [ C3 ]
+# CHECK: alignment: 4 mod 2^4
+# CHECK: - name: _f3
+# CHECK: content: [ C3 ]
+# CHECK: alignment: 5 mod 2^4
diff --git a/test/mach-o/arm-interworking-movw.yaml b/test/mach-o/arm-interworking-movw.yaml
new file mode 100644
index 000000000000..59d2f0ddd3d9
--- /dev/null
+++ b/test/mach-o/arm-interworking-movw.yaml
@@ -0,0 +1,393 @@
+# REQUIRES: arm
+# RUN: lld -flavor darwin -arch armv7 -r -print_atoms %s -o %t | FileCheck %s
+# RUN: lld -flavor darwin -arch armv7 -dylib -print_atoms %t -o %t2 \
+# RUN: %p/Inputs/libSystem.yaml -sectalign __TEXT __text 0x1000 | FileCheck %s
+# RUN: llvm-objdump -d -macho %t2 | FileCheck -check-prefix=CODE %s
+#
+# Test thumb and arm branches round trip through -r.
+# Test movw/movt pairs have low bit set properly for thumb vs arm.
+#
+#
+
+--- !mach-o
+arch: armv7
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ alignment: 2
+ address: 0x0000000000000000
+ content: [ 0x40, 0xF2, 0x25, 0x00, 0xC0, 0xF2, 0x00, 0x00,
+ 0x40, 0xF2, 0x01, 0x01, 0xC0, 0xF2, 0x00, 0x01,
+ 0x40, 0xF2, 0x4E, 0x02, 0xC0, 0xF2, 0x00, 0x02,
+ 0x40, 0xF2, 0x2A, 0x03, 0xC0, 0xF2, 0x00, 0x03,
+ 0x78, 0x44, 0x70, 0x47, 0x70, 0x47, 0x25, 0x00,
+ 0x00, 0xE3, 0x00, 0x00, 0x40, 0xE3, 0xD7, 0x1F,
+ 0x0F, 0xE3, 0xFF, 0x1F, 0x4F, 0xE3, 0x4E, 0x20,
+ 0x00, 0xE3, 0x00, 0x20, 0x40, 0xE3, 0x00, 0x30,
+ 0x00, 0xE3, 0x00, 0x30, 0x40, 0xE3, 0x0F, 0x00,
+ 0x80, 0xE0, 0x1E, 0xFF, 0x2F, 0xE1, 0x1E, 0xFF,
+ 0x2F, 0xE1 ]
+ relocations:
+ - offset: 0x00000042
+ scattered: true
+ type: ARM_RELOC_HALF_SECTDIFF
+ length: 1
+ pc-rel: false
+ value: 0x0000004E
+ - offset: 0x00000000
+ scattered: true
+ type: ARM_RELOC_PAIR
+ length: 1
+ pc-rel: false
+ value: 0x00000046
+ - offset: 0x0000003E
+ scattered: true
+ type: ARM_RELOC_HALF_SECTDIFF
+ length: 0
+ pc-rel: false
+ value: 0x0000004E
+ - offset: 0x00000000
+ scattered: true
+ type: ARM_RELOC_PAIR
+ length: 0
+ pc-rel: false
+ value: 0x00000046
+ - offset: 0x0000003A
+ type: ARM_RELOC_HALF
+ length: 1
+ pc-rel: false
+ extern: false
+ symbol: 1
+ - offset: 0x0000004E
+ type: ARM_RELOC_PAIR
+ length: 1
+ pc-rel: false
+ extern: false
+ symbol: 16777215
+ - offset: 0x00000036
+ type: ARM_RELOC_HALF
+ length: 0
+ pc-rel: false
+ extern: false
+ symbol: 1
+ - offset: 0x00000000
+ type: ARM_RELOC_PAIR
+ length: 0
+ pc-rel: false
+ extern: false
+ symbol: 16777215
+ - offset: 0x00000032
+ scattered: true
+ type: ARM_RELOC_HALF_SECTDIFF
+ length: 1
+ pc-rel: false
+ value: 0x00000024
+ - offset: 0x0000FFD6
+ scattered: true
+ type: ARM_RELOC_PAIR
+ length: 1
+ pc-rel: false
+ value: 0x00000046
+ - offset: 0x0000002E
+ scattered: true
+ type: ARM_RELOC_HALF_SECTDIFF
+ length: 0
+ pc-rel: false
+ value: 0x00000024
+ - offset: 0x0000FFFF
+ scattered: true
+ type: ARM_RELOC_PAIR
+ length: 0
+ pc-rel: false
+ value: 0x00000046
+ - offset: 0x0000002A
+ type: ARM_RELOC_HALF
+ length: 1
+ pc-rel: false
+ extern: false
+ symbol: 1
+ - offset: 0x00000025
+ type: ARM_RELOC_PAIR
+ length: 1
+ pc-rel: false
+ extern: false
+ symbol: 16777215
+ - offset: 0x00000026
+ type: ARM_RELOC_HALF
+ length: 0
+ pc-rel: false
+ extern: false
+ symbol: 1
+ - offset: 0x00000000
+ type: ARM_RELOC_PAIR
+ length: 0
+ pc-rel: false
+ extern: false
+ symbol: 16777215
+ - offset: 0x0000001C
+ scattered: true
+ type: ARM_RELOC_HALF_SECTDIFF
+ length: 3
+ pc-rel: false
+ value: 0x0000004E
+ - offset: 0x0000002A
+ scattered: true
+ type: ARM_RELOC_PAIR
+ length: 3
+ pc-rel: false
+ value: 0x00000020
+ - offset: 0x00000018
+ scattered: true
+ type: ARM_RELOC_HALF_SECTDIFF
+ length: 2
+ pc-rel: false
+ value: 0x0000004E
+ - offset: 0x00000000
+ scattered: true
+ type: ARM_RELOC_PAIR
+ length: 2
+ pc-rel: false
+ value: 0x00000020
+ - offset: 0x00000014
+ type: ARM_RELOC_HALF
+ length: 3
+ pc-rel: false
+ extern: false
+ symbol: 1
+ - offset: 0x0000004E
+ type: ARM_RELOC_PAIR
+ length: 3
+ pc-rel: false
+ extern: false
+ symbol: 16777215
+ - offset: 0x00000010
+ type: ARM_RELOC_HALF
+ length: 2
+ pc-rel: false
+ extern: false
+ symbol: 1
+ - offset: 0x00000000
+ type: ARM_RELOC_PAIR
+ length: 2
+ pc-rel: false
+ extern: false
+ symbol: 16777215
+ - offset: 0x0000000C
+ scattered: true
+ type: ARM_RELOC_HALF_SECTDIFF
+ length: 3
+ pc-rel: false
+ value: 0x00000024
+ - offset: 0x00000000
+ scattered: true
+ type: ARM_RELOC_PAIR
+ length: 3
+ pc-rel: false
+ value: 0x00000020
+ - offset: 0x00000008
+ scattered: true
+ type: ARM_RELOC_HALF_SECTDIFF
+ length: 2
+ pc-rel: false
+ value: 0x00000024
+ - offset: 0x00000000
+ scattered: true
+ type: ARM_RELOC_PAIR
+ length: 2
+ pc-rel: false
+ value: 0x00000020
+ - offset: 0x00000004
+ type: ARM_RELOC_HALF
+ length: 3
+ pc-rel: false
+ extern: false
+ symbol: 1
+ - offset: 0x00000025
+ type: ARM_RELOC_PAIR
+ length: 3
+ pc-rel: false
+ extern: false
+ symbol: 16777215
+ - offset: 0x00000000
+ type: ARM_RELOC_HALF
+ length: 2
+ pc-rel: false
+ extern: false
+ symbol: 1
+ - offset: 0x00000000
+ type: ARM_RELOC_PAIR
+ length: 2
+ pc-rel: false
+ extern: false
+ symbol: 16777215
+local-symbols:
+ - name: _t1
+ type: N_SECT
+ sect: 1
+ desc: [ N_ARM_THUMB_DEF ]
+ value: 0x0000000000000000
+ - name: _t2
+ type: N_SECT
+ sect: 1
+ desc: [ N_ARM_THUMB_DEF ]
+ value: 0x0000000000000024
+ - name: _a2
+ type: N_SECT
+ sect: 1
+ value: 0x000000000000004E
+ - name: _a1
+ type: N_SECT
+ sect: 1
+ value: 0x0000000000000026
+...
+
+# CHECK: defined-atoms:
+# CHECK: - name: _t1
+# CHECK: references:
+# CHECK: - kind: modeThumbCode
+# CHECK: offset: 0
+# CHECK: target: _t1
+# CHECK: - kind: thumb_movw
+# CHECK: offset: 0
+# CHECK: target: _t2
+# CHECK-NOT: addend:
+# CHECK: - kind: thumb_movt
+# CHECK: offset: 4
+# CHECK: target: _t2
+# CHECK-NOT: addend:
+# CHECK: - kind: thumb_movw_funcRel
+# CHECK: offset: 8
+# CHECK: target: _t2
+# CHECK: addend: -36
+# CHECK: - kind: thumb_movt_funcRel
+# CHECK: offset: 12
+# CHECK: target: _t2
+# CHECK: addend: -36
+# CHECK: - kind: thumb_movw
+# CHECK: offset: 16
+# CHECK: target: _a2
+# CHECK-NOT: addend:
+# CHECK: - kind: thumb_movt
+# CHECK: offset: 20
+# CHECK: target: _a2
+# CHECK-NOT: addend:
+# CHECK: - kind: thumb_movw_funcRel
+# CHECK: offset: 24
+# CHECK: target: _a2
+# CHECK: addend: -36
+# CHECK: - kind: thumb_movt_funcRel
+# CHECK: offset: 28
+# CHECK: target: _a2
+# CHECK: addend: -36
+# CHECK: - name: _t2
+# CHECK: references:
+# CHECK: - kind: modeThumbCode
+# CHECK: offset: 0
+# CHECK: target: _t2
+# CHECK: - name: _a1
+# CHECK: references:
+# CHECK: - kind: arm_movw
+# CHECK: offset: 0
+# CHECK: target: _t2
+# CHECK-NOT: addend:
+# CHECK: - kind: arm_movt
+# CHECK: offset: 4
+# CHECK: target: _t2
+# CHECK-NOT: addend:
+# CHECK: - kind: arm_movw_funcRel
+# CHECK: offset: 8
+# CHECK: target: _t2
+# CHECK: addend: -40
+# CHECK: - kind: arm_movt_funcRel
+# CHECK: offset: 12
+# CHECK: target: _t2
+# CHECK: addend: -40
+# CHECK: - kind: arm_movw
+# CHECK: offset: 16
+# CHECK: target: _a2
+# CHECK-NOT: addend:
+# CHECK: - kind: arm_movt
+# CHECK: offset: 20
+# CHECK: target: _a2
+# CHECK-NOT: addend:
+# CHECK: - kind: arm_movw_funcRel
+# CHECK: offset: 24
+# CHECK: target: _a2
+# CHECK: addend: -40
+# CHECK: - kind: arm_movt_funcRel
+# CHECK: offset: 28
+# CHECK: target: _a2
+# CHECK: addend: -40
+# CHECK: - name: _a2
+
+
+# CODE: _t1:
+# CODE-NEXT: movw r0, #4133
+# CODE-NEXT: movt r0, #0
+# CODE-NEXT: movw r1, #1
+# CODE-NEXT: movt r1, #0
+# CODE-NEXT: movw r2, _a2
+# CODE-NEXT: movt r2, #0
+# CODE-NEXT: movw r3, #42
+# CODE-NEXT: movt r3, #0
+
+
+# CODE: _a1:
+# CODE-NEXT: movw r0, #4133
+# CODE-NEXT: movt r0, #0
+# CODE-NEXT: movw r1, #65495
+# CODE-NEXT: movt r1, #65535
+# CODE-NEXT: movw r2, _a2
+# CODE-NEXT: movt r2, #0
+# CODE-NEXT: movw r3, #0
+# CODE-NEXT: movt r3, #0
+
+
+
+# .syntax unified
+# .align 2
+#
+# .code 16
+# .thumb_func _t1
+#_t1:
+# movw r0, :lower16:(_t2)
+# movt r0, :upper16:(_t2)
+# movw r1, :lower16:(_t2-(L0+4))
+# movt r1, :upper16:(_t2-(L0+4))
+# movw r2, :lower16:(_a2)
+# movt r2, :upper16:(_a2)
+# movw r3, :lower16:(_a2-(L0+4))
+# movt r3, :upper16:(_a2-(L0+4))
+#L0:
+# add r0, pc
+# bx lr
+#
+#
+# .code 16
+# .thumb_func _t2
+#_t2:
+# bx lr
+#
+#
+#
+# .code 32
+#_a1:
+# movw r0, :lower16:(_t2)
+# movt r0, :upper16:(_t2)
+# movw r1, :lower16:(_t2-(L1+8))
+# movt r1, :upper16:(_t2-(L1+8))
+# movw r2, :lower16:(_a2)
+# movt r2, :upper16:(_a2)
+# movw r3, :lower16:(_a2-(L1+8))
+# movt r3, :upper16:(_a2-(L1+8))
+#L1:
+# add r0, pc
+# bx lr
+#
+#_a2:
+# bx lr
+
diff --git a/test/mach-o/arm-interworking.yaml b/test/mach-o/arm-interworking.yaml
new file mode 100644
index 000000000000..f7e04e65c9f0
--- /dev/null
+++ b/test/mach-o/arm-interworking.yaml
@@ -0,0 +1,362 @@
+# RUN: lld -flavor darwin -arch armv7 -r -print_atoms %s -o %t | FileCheck %s \
+# RUN: && lld -flavor darwin -arch armv7 -dylib -print_atoms \
+# RUN: %p/Inputs/libSystem.yaml %t -o %t2 | FileCheck %s \
+# RUN: && macho-dump --dump-section-data %t2 | FileCheck -check-prefix=CODE %s
+#
+# Test thumb and arm branches round trip through -r.
+# Test bl/blx instructions are fixed up properly.
+#
+#
+
+--- !mach-o
+arch: armv7
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ alignment: 2
+ address: 0x0000000000000000
+ content: [ 0xFF, 0xF7, 0xFE, 0xFF, 0xC0, 0x46, 0xFF, 0xF7,
+ 0xFC, 0xEF, 0xC0, 0x46, 0xFF, 0xF7, 0xF8, 0xEF,
+ 0xFF, 0xF7, 0xF6, 0xFF, 0xC0, 0x46, 0xFF, 0xF7,
+ 0xF3, 0xFF, 0xC0, 0x46, 0x00, 0xF0, 0x06, 0xE8,
+ 0xC0, 0x46, 0x00, 0xF0, 0x03, 0xF8, 0x00, 0xF0,
+ 0x02, 0xF8, 0x70, 0x47, 0x70, 0x47, 0x70, 0x47 ]
+ relocations:
+ - offset: 0x00000026
+ type: ARM_THUMB_RELOC_BR22
+ length: 2
+ pc-rel: true
+ extern: false
+ symbol: 1
+ - offset: 0x00000022
+ type: ARM_THUMB_RELOC_BR22
+ length: 2
+ pc-rel: true
+ extern: false
+ symbol: 1
+ - offset: 0x0000001C
+ type: ARM_THUMB_RELOC_BR22
+ length: 2
+ pc-rel: true
+ extern: false
+ symbol: 1
+ - offset: 0x00000016
+ type: ARM_THUMB_RELOC_BR22
+ length: 2
+ pc-rel: true
+ extern: false
+ symbol: 1
+ - offset: 0x00000010
+ type: ARM_THUMB_RELOC_BR22
+ length: 2
+ pc-rel: true
+ extern: false
+ symbol: 1
+ - offset: 0x0000000C
+ type: ARM_THUMB_RELOC_BR22
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 5
+ - offset: 0x00000006
+ type: ARM_THUMB_RELOC_BR22
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 5
+ - offset: 0x00000000
+ type: ARM_THUMB_RELOC_BR22
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 4
+ - segment: __DATA
+ section: __data
+ type: S_REGULAR
+ attributes: [ ]
+ address: 0x0000000000000030
+ content: [ 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+ relocations:
+ - offset: 0x00000004
+ type: ARM_RELOC_VANILLA
+ length: 2
+ pc-rel: false
+ extern: true
+ symbol: 4
+ - offset: 0x00000000
+ type: ARM_RELOC_VANILLA
+ length: 2
+ pc-rel: false
+ extern: false
+ symbol: 1
+local-symbols:
+ - name: _t3
+ type: N_SECT
+ sect: 1
+ desc: [ N_ARM_THUMB_DEF ]
+ value: 0x000000000000002E
+ - name: _d1
+ type: N_SECT
+ sect: 2
+ value: 0x0000000000000030
+global-symbols:
+ - name: _t1
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ desc: [ N_ARM_THUMB_DEF ]
+ value: 0x0000000000000000
+ - name: _t2
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ desc: [ N_ARM_THUMB_DEF ]
+ value: 0x000000000000002C
+undefined-symbols:
+ - name: _a1
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+ - name: _a2
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+
+--- !mach-o
+arch: armv7
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ alignment: 2
+ address: 0x0000000000000000
+ content: [ 0xFE, 0xFF, 0xFF, 0xEB, 0x02, 0x00, 0x00, 0xFA,
+ 0xFC, 0xFF, 0xFF, 0xEB, 0xFB, 0xFF, 0xFF, 0xFA,
+ 0x1E, 0xFF, 0x2F, 0xE1, 0x1E, 0xFF, 0x2F, 0xE1 ]
+ relocations:
+ - offset: 0x0000000C
+ type: ARM_RELOC_BR24
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 4
+ - offset: 0x00000008
+ type: ARM_RELOC_BR24
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 3
+ - offset: 0x00000004
+ type: ARM_RELOC_BR24
+ length: 2
+ pc-rel: true
+ extern: false
+ symbol: 1
+ - offset: 0x00000000
+ type: ARM_RELOC_BR24
+ length: 2
+ pc-rel: true
+ extern: false
+ symbol: 1
+ - segment: __DATA
+ section: __data
+ type: S_REGULAR
+ attributes: [ ]
+ address: 0x0000000000000018
+ content: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+ relocations:
+ - offset: 0x00000004
+ type: ARM_RELOC_VANILLA
+ length: 2
+ pc-rel: false
+ extern: false
+ symbol: 1
+ - offset: 0x00000000
+ type: ARM_RELOC_VANILLA
+ length: 2
+ pc-rel: false
+ extern: true
+ symbol: 3
+local-symbols:
+ - name: _d2
+ type: N_SECT
+ sect: 2
+ value: 0x0000000000000018
+global-symbols:
+ - name: _a1
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+ - name: _a2
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000014
+undefined-symbols:
+ - name: _t1
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+ - name: _t2
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+...
+
+
+# CHECK: defined-atoms:
+# CHECK: - name: _d1
+# CHECK: type: data
+# CHECK: references:
+# CHECK: - kind: pointer32
+# CHECK: offset: 0
+# CHECK: target: _t2
+# CHECK: - kind: pointer32
+# CHECK: offset: 4
+# CHECK: target: _a1
+# CHECK: - name: _d2
+# CHECK: type: data
+# CHECK: references:
+# CHECK: - kind: pointer32
+# CHECK: offset: 0
+# CHECK: target: _t1
+# CHECK: - kind: pointer32
+# CHECK: offset: 4
+# CHECK: target: _a1
+# CHECK: - name: _t1
+# CHECK: scope: global
+# CHECK: references:
+# CHECK: - kind: modeThumbCode
+# CHECK: offset: 0
+# CHECK: target: _t1
+# CHECK: - kind: thumb_bl22
+# CHECK: offset: 0
+# CHECK: target: _a1
+# CHECK: - kind: thumb_bl22
+# CHECK: offset: 6
+# CHECK: target: _a2
+# CHECK: - kind: thumb_bl22
+# CHECK: offset: 12
+# CHECK: target: _a2
+# CHECK: - kind: thumb_bl22
+# CHECK: offset: 16
+# CHECK: target: _t1
+# CHECK: - kind: thumb_bl22
+# CHECK: offset: 22
+# CHECK: target: _t1
+# CHECK: - kind: thumb_bl22
+# CHECK: offset: 28
+# CHECK: target: _t2
+# CHECK: - kind: thumb_bl22
+# CHECK: offset: 34
+# CHECK: target: _t2
+# CHECK: - kind: thumb_bl22
+# CHECK: offset: 38
+# CHECK: target: _t3
+# CHECK: - name: _t2
+# CHECK: scope: global
+# CHECK: content: [ 70, 47 ]
+# CHECK: references:
+# CHECK: - kind: modeThumbCode
+# CHECK: offset: 0
+# CHECK: target: _t2
+# CHECK: - name: _t3
+# CHECK: content: [ 70, 47 ]
+# CHECK: references:
+# CHECK: - kind: modeThumbCode
+# CHECK: offset: 0
+# CHECK: target: _t3
+# CHECK: - name: _a1
+# CHECK: scope: global
+# CHECK: references:
+# CHECK: - kind: arm_bl24
+# CHECK: offset: 0
+# CHECK: target: _a1
+# CHECK: - kind: arm_bl24
+# CHECK: offset: 4
+# CHECK: target: _a2
+# CHECK: - kind: arm_bl24
+# CHECK: offset: 8
+# CHECK: target: _t1
+# CHECK: - kind: arm_bl24
+# CHECK: offset: 12
+# CHECK: target: _t2
+# CHECK: - name: _a2
+# CHECK: scope: global
+
+
+# CODE: (('section_name', '__text\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
+# CODE: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
+# CODE: ('_section_data', '00f016e8 c04600f0 1ee8c046 00f01ae8 fff7f6ff c046fff7 f3ffc046 00f006f8 c04600f0 03f800f0 02f87047 70477047 feffffeb 020000eb f0fffffa fafffffa 1eff2fe1 1eff2fe1')
+# When we get a good mach-o disassembler the above __text section content check can be change to be symbolic.
+
+# CODE: (('section_name', '__data\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
+# CODE: ('segment_name', '__DATA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
+# CODE: ('_section_data', '{{[0-9a-f]}}{{[13579bdf]}}{{[0-9a-f]+}} {{[0-9a-f]}}{{[02468ade]}}{{[0-9a-f]+}} {{[0-9a-f]}}{{[13579bdf]}}{{[0-9a-f]+}} {{[0-9a-f]}}{{[02468ade]}}{{[0-9a-f]+}}')
+# Verify the low (thumb) bit is set on the first and third pointers but not the second and fourth.
+
+
+
+# Input file one:
+#
+# .align 2
+# .code 16
+# .globl _t1
+# .thumb_func _t1
+#_t1:
+# bl _a1
+# nop
+# blx _a2
+# nop
+# blx _a2
+# bl _t1
+# nop
+# bl _t1
+# nop
+# blx _t2
+# nop
+# blx _t2
+# bx lr
+#
+# .globl _t2
+# .thumb_func _t2
+#_t2:
+# bx lr
+#
+# .data
+#_d1: .long _t2
+# .long _a1
+
+
+
+# Input file two:
+#
+# .align 2
+# .code 32
+# .globl _a1
+#_a1:
+# bl _a1
+# blx _a2
+# bl _t1
+# blx _t2
+# bx lr
+#
+# .globl _a2
+#_a2:
+# bx lr
+#
+# .data
+#_d2: .long _t1
+# .long _a1
+
+
+
+ \ No newline at end of file
diff --git a/test/mach-o/arm-shims.yaml b/test/mach-o/arm-shims.yaml
new file mode 100644
index 000000000000..68a401ca78e8
--- /dev/null
+++ b/test/mach-o/arm-shims.yaml
@@ -0,0 +1,179 @@
+# RUN: lld -flavor darwin -arch armv7 %s -dylib %p/Inputs/libSystem.yaml -o %t
+# RUN: macho-dump --dump-section-data %t | FileCheck %s
+#
+# Test b from arm to thumb or vice versa has shims added.s
+#
+#
+
+--- !mach-o
+arch: armv7
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ alignment: 2
+ address: 0x0000000000000000
+ content: [ 0x00, 0xBF, 0xFF, 0xF7, 0xFE, 0xEF, 0xFF, 0xF7,
+ 0xFB, 0xBF, 0x00, 0x00, 0x00, 0xF0, 0x20, 0xE3,
+ 0xFA, 0xFF, 0xFF, 0xFA, 0xF9, 0xFF, 0xFF, 0xEA ]
+ relocations:
+ - offset: 0x00000014
+ type: ARM_RELOC_BR24
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 3
+ - offset: 0x00000010
+ type: ARM_RELOC_BR24
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 3
+ - offset: 0x00000006
+ type: ARM_THUMB_RELOC_BR22
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 2
+ - offset: 0x00000002
+ type: ARM_THUMB_RELOC_BR22
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 2
+global-symbols:
+ - name: _a1
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x000000000000000C
+ - name: _t1
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ desc: [ N_ARM_THUMB_DEF ]
+ value: 0x0000000000000000
+undefined-symbols:
+ - name: _a2
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+ - name: _t2
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+
+
+--- !mach-o
+arch: armv7
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ alignment: 2
+ address: 0x0000000000000000
+ content: [ 0x00, 0xBF, 0xFF, 0xF7, 0xFE, 0xEF, 0xFF, 0xF7,
+ 0xFB, 0xBF, 0x00, 0x00, 0x00, 0xF0, 0x20, 0xE3,
+ 0xFA, 0xFF, 0xFF, 0xFA, 0xF9, 0xFF, 0xFF, 0xEA ]
+ relocations:
+ - offset: 0x00000014
+ type: ARM_RELOC_BR24
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 3
+ - offset: 0x00000010
+ type: ARM_RELOC_BR24
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 3
+ - offset: 0x00000006
+ type: ARM_THUMB_RELOC_BR22
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 2
+ - offset: 0x00000002
+ type: ARM_THUMB_RELOC_BR22
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 2
+global-symbols:
+ - name: _a2
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x000000000000000C
+ - name: _t2
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ desc: [ N_ARM_THUMB_DEF ]
+ value: 0x0000000000000000
+undefined-symbols:
+ - name: _a1
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+ - name: _t1
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+
+...
+
+
+# CHECK: (('section_name', '__text\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
+# CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
+# CHECK: ('_section_data', '00bf00f0 10e800f0 19b80000 00f020e3 000000fa 0f0000ea 00bffff7 f8ef00f0 07b80000 00f020e3 f4fffffa 050000ea dff804c0 ff446047 d4ffffff dff804c0 ff446047 e0ffffff 04c09fe5 0cc08fe0 1cff2fe1 adffffff 04c09fe5 0cc08fe0 1cff2fe1 b5ffffff')
+
+# When we get a good mach-o disassembler the above __text section content check can be change to be symbolic.
+
+
+# Input file one:
+#
+# .align 2
+# .code 16
+# .globl _t1
+# .thumb_func _t1
+#_t1:
+# nop
+# blx _a2
+# b _a2
+#
+# .code 32
+# .align 2
+# .globl _a1
+#_a1:
+# nop
+# blx _t2
+# b _t2
+
+
+
+# Input file two:
+#
+# .align 2
+# .code 16
+# .globl _t2
+# .thumb_func _t2
+#_t2:
+# nop
+# blx _a1
+# b _a1
+#
+# .code 32
+# .align 2
+# .globl _a2
+#_a2:
+# nop
+# blx _t1
+# b _t1
diff --git a/test/mach-o/arm-subsections-via-symbols.yaml b/test/mach-o/arm-subsections-via-symbols.yaml
new file mode 100644
index 000000000000..b704568f37b1
--- /dev/null
+++ b/test/mach-o/arm-subsections-via-symbols.yaml
@@ -0,0 +1,60 @@
+# RUN: lld -flavor darwin -arch armv7 %s -r -print_atoms -o %t | FileCheck %s
+#
+# Test that assembly written without .subsections_via_symbols is parsed so
+# that atoms are non-dead-strip and there is a layout-after references
+# chaining atoms together.
+#
+
+--- !mach-o
+arch: armv7
+file-type: MH_OBJECT
+flags: [ ]
+has-UUID: false
+OS: unknown
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ alignment: 2
+ address: 0x0000000000000000
+ content: [ 0x04, 0x10, 0x9F, 0xE5, 0x04, 0x20, 0x9F, 0xE5,
+ 0x1E, 0xFF, 0x2F, 0xE1, 0x78, 0x56, 0x34, 0x12,
+ 0x21, 0x43, 0x65, 0x87 ]
+local-symbols:
+ - name: constants1
+ type: N_SECT
+ sect: 1
+ value: 0x000000000000000C
+ - name: constants2
+ type: N_SECT
+ sect: 1
+ value: 0x0000000000000010
+global-symbols:
+ - name: _foo
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+...
+
+
+# CHECK:defined-atoms:
+# CHECK: - name: _foo
+# CHECK: scope: global
+# CHECK: content: [ 04, 10, 9F, E5, 04, 20, 9F, E5, 1E, FF, 2F, E1 ]
+# CHECK: dead-strip: never
+# CHECK: references:
+# CHECK: - kind: layout-after
+# CHECK: offset: 0
+# CHECK: target: constants1
+# CHECK: - name: constants1
+# CHECK: content: [ 78, 56, 34, 12 ]
+# CHECK: dead-strip: never
+# CHECK: references:
+# CHECK: - kind: layout-after
+# CHECK: offset: 0
+# CHECK: target: constants2
+# CHECK: - name: constants2
+# CHECK: content: [ 21, 43, 65, 87 ]
+# CHECK: dead-strip: never
diff --git a/test/mach-o/cstring-sections.yaml b/test/mach-o/cstring-sections.yaml
new file mode 100644
index 000000000000..940f048b5c6c
--- /dev/null
+++ b/test/mach-o/cstring-sections.yaml
@@ -0,0 +1,91 @@
+# RUN: lld -flavor darwin -arch x86_64 -r %s -o %t -print_atoms | FileCheck %s
+#
+# Test -keep_private_externs in -r mode.
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __TEXT
+ section: __objc_methname
+ type: S_CSTRING_LITERALS
+ attributes: [ ]
+ address: 0x0000000000000000
+ content: [ 0x61, 0x62, 0x63, 0x00, 0x64, 0x65, 0x66, 0x00 ]
+ - segment: __TEXT
+ section: __objc_classname
+ type: S_CSTRING_LITERALS
+ attributes: [ ]
+ address: 0x0000000000000006
+ content: [ 0x61, 0x62, 0x63, 0x00, 0x67, 0x68, 0x69, 0x00 ]
+ - segment: __TEXT
+ section: __cstring
+ type: S_CSTRING_LITERALS
+ attributes: [ ]
+ address: 0x000000000000000A
+ content: [ 0x61, 0x62, 0x63, 0x00, 0x6A, 0x6B, 0x6C, 0x00 ]
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID: false
+OS: unknown
+sections:
+ - segment: __TEXT
+ section: __objc_methname
+ type: S_CSTRING_LITERALS
+ attributes: [ ]
+ address: 0x0000000000000000
+ content: [ 0x61, 0x62, 0x63, 0x00 ]
+ - segment: __TEXT
+ section: __objc_classname
+ type: S_CSTRING_LITERALS
+ attributes: [ ]
+ address: 0x0000000000000006
+ content: [ 0x61, 0x62, 0x63, 0x00 ]
+ - segment: __TEXT
+ section: __cstring
+ type: S_CSTRING_LITERALS
+ attributes: [ ]
+ address: 0x000000000000000A
+ content: [ 0x61, 0x62, 0x63, 0x00 ]
+
+
+...
+
+# CHECK: defined-atoms:
+# CHECK: - scope: hidden
+# CHECK: type: c-string
+# CHECK: content: [ 61, 62, 63, 00 ]
+# CHECK: merge: by-content
+# CHECK: section-choice: custom-required
+# CHECK: section-name: __TEXT/__objc_methname
+# CHECK: - scope: hidden
+# CHECK: type: c-string
+# CHECK: content: [ 64, 65, 66, 00 ]
+# CHECK: merge: by-content
+# CHECK: section-choice: custom-required
+# CHECK: section-name: __TEXT/__objc_methname
+# CHECK: - scope: hidden
+# CHECK: type: c-string
+# CHECK: content: [ 61, 62, 63, 00 ]
+# CHECK: merge: by-content
+# CHECK: section-choice: custom-required
+# CHECK: section-name: __TEXT/__objc_classname
+# CHECK: - scope: hidden
+# CHECK: type: c-string
+# CHECK: content: [ 67, 68, 69, 00 ]
+# CHECK: merge: by-content
+# CHECK: section-choice: custom-required
+# CHECK: section-name: __TEXT/__objc_classname
+# CHECK: - scope: hidden
+# CHECK: type: c-string
+# CHECK: content: [ 61, 62, 63, 00 ]
+# CHECK: merge: by-content
+# CHECK: - scope: hidden
+# CHECK: type: c-string
+# CHECK: content: [ 6A, 6B, 6C, 00 ]
+# CHECK: merge: by-content
diff --git a/test/mach-o/data-only-dylib.yaml b/test/mach-o/data-only-dylib.yaml
new file mode 100644
index 000000000000..c285066ad778
--- /dev/null
+++ b/test/mach-o/data-only-dylib.yaml
@@ -0,0 +1,27 @@
+# RUN: lld -flavor darwin -arch x86_64 -dylib %s -o %t %p/Inputs/libSystem.yaml
+# RUN: llvm-nm %t | FileCheck %s
+#
+# Test that a data-only dylib can be built.
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __DATA
+ section: __data
+ type: S_REGULAR
+ attributes: [ ]
+ alignment: 2
+ address: 0x0000000000000000
+ content: [ 0x00, 0x00, 0x00, 0x00 ]
+global-symbols:
+ - name: _myData
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+...
+
+# CHECK: _myData
diff --git a/test/mach-o/demangle.yaml b/test/mach-o/demangle.yaml
new file mode 100644
index 000000000000..640545808477
--- /dev/null
+++ b/test/mach-o/demangle.yaml
@@ -0,0 +1,74 @@
+# REQUIRES: system-linker-mach-o
+#
+# RUN: not lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s \
+# RUN: -dylib -o %t %p/Inputs/libSystem.yaml 2> %t.err
+# RUN: FileCheck %s < %t.err
+#
+# RUN: not lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s \
+# RUN: -dylib -o %t %p/Inputs/libSystem.yaml -demangle 2> %t.err2
+# RUN: FileCheck %s --check-prefix=DCHECK < %t.err2
+#
+# Test -demangle option works on undefined symbol errors.
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0xE8, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x00, 0x00,
+ 0x00, 0x00, 0xE8, 0x00, 0x00, 0x00, 0x00 ]
+ relocations:
+ - offset: 0x0000000B
+ type: X86_64_RELOC_BRANCH
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 2
+ - offset: 0x00000006
+ type: X86_64_RELOC_BRANCH
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 3
+ - offset: 0x00000001
+ type: X86_64_RELOC_BRANCH
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 1
+global-symbols:
+ - name: __Z1xv
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+undefined-symbols:
+ - name: __Znam
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+ - name: __Znotcpp
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+ - name: _foo
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+
+...
+
+# CHECK: __Znotcpp
+# CHECK: __Znam
+# CHECK: _foo
+
+# DCHECK: __Znotcpp
+# DCHECK: operator new[](unsigned long)
+# DCHECK: _foo
+
diff --git a/test/mach-o/dependency_info.yaml b/test/mach-o/dependency_info.yaml
new file mode 100644
index 000000000000..dcce4381dfd3
--- /dev/null
+++ b/test/mach-o/dependency_info.yaml
@@ -0,0 +1,24 @@
+# XFAIL: win32
+# This test fails on Windows because the linker would use '\' instead
+# of '/' as a path separator when concatenating path components.
+# So the output from the linker would be different.
+
+# Test -dependency_info option
+#
+# RUN: lld -flavor darwin -arch x86_64 -test_file_usage \
+# RUN: -dependency_info %t.info \
+# RUN: -path_exists /System/Library/Frameworks \
+# RUN: -path_exists /System/Library/Frameworks/Foo.framework/Foo \
+# RUN: -path_exists /Custom/Frameworks \
+# RUN: -path_exists /Custom/Frameworks/Bar.framework/Bar \
+# RUN: -F/Custom/Frameworks \
+# RUN: -framework Bar \
+# RUN: -framework Foo
+# RUN: python %p/Inputs/DependencyDump.py %t.info | FileCheck %s
+
+
+# CHECK: linker-vers: lld
+# CHECK: input-file: /Custom/Frameworks/Bar.framework/Bar
+# CHECK: not-found: /Custom/Frameworks/Foo.framework/Foo
+# CHECK: input-file: /System/Library/Frameworks/Foo.framework/Foo
+# CHECK: output-file: a.out
diff --git a/test/mach-o/dso_handle.yaml b/test/mach-o/dso_handle.yaml
new file mode 100644
index 000000000000..d39d2c230806
--- /dev/null
+++ b/test/mach-o/dso_handle.yaml
@@ -0,0 +1,62 @@
+# RUN: lld -flavor darwin -arch x86_64 %s %p/Inputs/libSystem.yaml -o %t1
+# RUN: llvm-nm -m -n %t1 | FileCheck %s
+#
+# RUN: lld -flavor darwin -arch x86_64 %s %p/Inputs/libSystem.yaml -dead_strip -o %t2
+# RUN: llvm-nm -m -n %t2 | FileCheck %s
+#
+# RUN: lld -flavor darwin -arch x86_64 %s %p/Inputs/libSystem.yaml -dylib -o %t3
+# RUN: llvm-nm -m -n %t3 | FileCheck %s
+#
+# RUN: lld -flavor darwin -arch x86_64 %s %p/Inputs/libSystem.yaml -bundle -o %t4
+# RUN: llvm-nm -m -n %t4 | FileCheck %s
+#
+# Test that ___dso_handle symbol is available for executables, bundles, and dylibs
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0x55, 0x48, 0x89, 0xE5, 0x31, 0xC0, 0x5D, 0xC3 ]
+ - segment: __DATA
+ section: __data
+ type: S_REGULAR
+ attributes: [ ]
+ alignment: 3
+ address: 0x0000000000000008
+ content: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+ relocations:
+ - offset: 0x00000000
+ type: X86_64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 2
+global-symbols:
+ - name: _d
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 2
+ value: 0x0000000000000008
+ - name: _main
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+undefined-symbols:
+ - name: ___dso_handle
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+
+
+...
+
+# CHECK_NOT: ___dso_handle
+# CHECK: _main
diff --git a/test/mach-o/dylib-exports.yaml b/test/mach-o/dylib-exports.yaml
new file mode 100644
index 000000000000..0a00dfe1e952
--- /dev/null
+++ b/test/mach-o/dylib-exports.yaml
@@ -0,0 +1,41 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 -dylib \
+# RUN: %s %p/Inputs/libSystem.yaml -o %t && \
+# RUN: llvm-objdump -exports-trie %t | FileCheck %s
+#
+#
+# Tests that exports trie builds properly.
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0xC3, 0xC3, 0xC3 ]
+global-symbols:
+ - name: _myHidden
+ type: N_SECT
+ scope: [ N_EXT, N_PEXT ]
+ sect: 1
+ value: 0x0000000000000000
+ - name: _myRegular
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000001
+ - name: _myWeak
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ desc: [ N_WEAK_DEF ]
+ value: 0x0000000000000002
+...
+
+# CHECK-NOT: _myHidden
+# CHECK: _myRegular
+# CHECK: _myWeak [weak_def]
diff --git a/test/mach-o/dylib-install-names.yaml b/test/mach-o/dylib-install-names.yaml
new file mode 100644
index 000000000000..845085be42ab
--- /dev/null
+++ b/test/mach-o/dylib-install-names.yaml
@@ -0,0 +1,74 @@
+# Check we accept -install_name correctly:
+# RUN: lld -flavor darwin -arch x86_64 -install_name libwibble.dylib -dylib \
+# RUN: -compatibility_version 2.0 -current_version 5.3 \
+# RUN: %p/Inputs/libSystem.yaml %s -o %t.dylib
+# RUN: llvm-objdump -private-headers %t.dylib | FileCheck %s --check-prefix=CHECK-BINARY-WRITE
+
+# Check we read LC_ID_DYLIB correctly:
+# RUN: lld -flavor darwin -arch x86_64 %p/Inputs/use-dylib-install-names.yaml \
+# RUN: %p/Inputs/libSystem.yaml %t.dylib -dylib -o %t2.dylib
+# RUN: llvm-objdump -private-headers %t2.dylib | FileCheck %s --check-prefix=CHECK-BINARY-READ
+
+# Check we default the install-name to the output file:
+# RUN: lld -flavor darwin -arch x86_64 -dylib %s -o libwibble.dylib \
+# RUN: -compatibility_version 2.0 -current_version 5.3 \
+# RUN: %p/Inputs/libSystem.yaml
+# RUN: llvm-objdump -private-headers libwibble.dylib | FileCheck %s --check-prefix=CHECK-BINARY-WRITE
+# RUN: rm -f libwibble.dylib
+
+# Check -single_module does nothing
+# RUN: lld -flavor darwin -arch x86_64 -dylib %s -install_name libwibble.dylib \
+# RUN: -compatibility_version 2.0 -current_version 5.3 \
+# RUN: -single_module -o %t2.dylib %p/Inputs/libSystem.yaml
+# RUN: llvm-objdump -private-headers %t2.dylib | FileCheck %s --check-prefix=CHECK-BINARY-WRITE
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID: false
+OS: unknown
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ alignment: 4
+ address: 0x0000000000000000
+ content: [ 0xCC, 0xC3, 0x90, 0xC3, 0x90, 0x90, 0xC3, 0x90,
+ 0x90, 0x90, 0xC3, 0x90, 0x90, 0x90, 0x90, 0xC3,
+ 0x31, 0xC0, 0xC3 ]
+local-symbols:
+ - name: _myStatic
+ type: N_SECT
+ sect: 1
+ value: 0x000000000000000B
+global-symbols:
+ - name: _myGlobal
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000001
+...
+
+
+# CHECK-BINARY-WRITE: cmd LC_ID_DYLIB
+# CHECK-BINARY-WRITE-NEXT: cmdsize 40
+# CHECK-BINARY-WRITE-NEXT: name libwibble.dylib (offset 24)
+# CHECK-BINARY-WRITE-NEXT: time stamp 1
+# CHECK-BINARY-WRITE-NEXT: current version 5.3.0
+# CHECK-BINARY-WRITE-NEXT: compatibility version 2.0.0
+
+# CHECK-BINARY-READ: cmd LC_LOAD_DYLIB
+# CHECK-BINARY-READ-NEXT: cmdsize 56
+# CHECK-BINARY-READ-NEXT: name /usr/lib/libSystem.B.dylib (offset 24)
+# CHECK-BINARY-READ-NEXT: time stamp 2
+# CHECK-BINARY-READ-NEXT: current version 0.16.0
+# CHECK-BINARY-READ-NEXT: compatibility version 0.16.0
+
+# CHECK-BINARY-READ: cmd LC_LOAD_DYLIB
+# CHECK-BINARY-READ-NEXT: cmdsize 40
+# CHECK-BINARY-READ-NEXT: name libwibble.dylib (offset 24)
+# CHECK-BINARY-READ-NEXT: time stamp 2
+# CHECK-BINARY-READ-NEXT: current version 5.3.0
+# CHECK-BINARY-READ-NEXT: compatibility version 2.0.0
diff --git a/test/mach-o/exe-offsets.yaml b/test/mach-o/exe-offsets.yaml
new file mode 100644
index 000000000000..a751507432ee
--- /dev/null
+++ b/test/mach-o/exe-offsets.yaml
@@ -0,0 +1,45 @@
+# RUN: lld -flavor darwin -arch x86_64 %s -o %t -e start %p/Inputs/libSystem.yaml
+# RUN: llvm-readobj -sections %t | FileCheck %s
+
+# Make sure data gets put at offset
+
+--- !native
+defined-atoms:
+ - name: start
+ scope: global
+ content: [ 90 ]
+
+ - name: _s1
+ type: data
+ content: [ 31, 32, 33, 34 ]
+
+ - name: _s2
+ type: zero-fill
+ size: 8192
+
+ - name: _s3
+ type: zero-fill
+ size: 100
+
+ - name: _s4
+ type: data
+ content: [ 01 ]
+
+
+# CHECK-LABEL: Section {
+# CHECK: Name: __text
+# CHECK: Segment: __TEXT
+# CHECK: Size: 0x1
+# CHECK: Offset: 0
+
+# CHECK-LABEL: Section {
+# CHECK: Name: __data
+# CHECK: Segment: __DATA
+# CHECK: Size: 0x5
+# CHECK: Offset: 4096
+
+# CHECK-LABEL: Section {
+# CHECK: Name: __bss
+# CHECK: Segment: __DATA
+# CHECK: Size: 0x2064
+# CHECK: Offset: 0
diff --git a/test/mach-o/exe-segment-overlap.yaml b/test/mach-o/exe-segment-overlap.yaml
new file mode 100644
index 000000000000..a416ee3ca73b
--- /dev/null
+++ b/test/mach-o/exe-segment-overlap.yaml
@@ -0,0 +1,44 @@
+# RUN: lld -flavor darwin -arch x86_64 %s -o %t %p/Inputs/libSystem.yaml
+# RUN: llvm-readobj -sections -section-data %t | FileCheck %s
+
+--- !native
+defined-atoms:
+ - name: _main
+ scope: global
+ content: [ 90 ]
+
+ - name: _s2
+ type: data
+ content: [ 31, 32, 33, 34 ]
+
+ - name: _kustom
+ scope: global
+ type: unknown
+ content: [ 01, 02, 03, 04, 05, 06, 07, 08 ]
+ section-choice: custom-required
+ section-name: __CUST/__custom
+
+
+# CHECK-LABEL: Section {
+# CHECK: Name: __text
+# CHECK: Segment: __TEXT
+# CHECK: Size: 0x1
+# CHECK: Offset: 4095
+
+# CHECK-LABEL: Section {
+# CHECK: Name: __data
+# CHECK: Segment: __DATA
+# CHECK: Size: 0x4
+# CHECK: Offset: 4096
+# CHECK: SectionData (
+# CHECK-NEXT: 0000: 31323334
+# CHECK-NEXT: )
+
+# CHECK-LABEL: Section {
+# CHECK: Name: __custom{{ }}
+# CHECK: Segment: __CUST{{ }}
+# CHECK: Size: 0x8
+# CHECK: Offset: 8192
+# CHECK: SectionData (
+# CHECK-NEXT: 0000: 01020304 05060708
+# CHECK-NEXT: )
diff --git a/test/mach-o/exported_symbols_list-dylib.yaml b/test/mach-o/exported_symbols_list-dylib.yaml
new file mode 100644
index 000000000000..71121d7400f6
--- /dev/null
+++ b/test/mach-o/exported_symbols_list-dylib.yaml
@@ -0,0 +1,77 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 -dylib \
+# RUN: %s %p/Inputs/libSystem.yaml -o %t \
+# RUN: -exported_symbols_list %p/Inputs/exported_symbols_list.exp && \
+# RUN: llvm-nm -m %t | FileCheck %s
+#
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 -dylib \
+# RUN: %s %p/Inputs/libSystem.yaml -o %t2 \
+# RUN: -exported_symbol _foo -exported_symbol _b && \
+# RUN: llvm-nm -m %t2 | FileCheck %s
+#
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 -dylib \
+# RUN: %s %p/Inputs/libSystem.yaml -o %t3 \
+# RUN: -unexported_symbol _bar -unexported_symbol _a && \
+# RUN: llvm-nm -m %t3 | FileCheck %s
+#
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 -dylib \
+# RUN: %s %p/Inputs/libSystem.yaml -dead_strip -o %t \
+# RUN: -exported_symbols_list %p/Inputs/exported_symbols_list.exp && \
+# RUN: llvm-nm -m %t | FileCheck -check-prefix=CHECK_DEAD %s
+#
+# Test -exported_symbols_list and -exported_symbol properly changes visibility.
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0x55, 0x48, 0x89, 0xE5, 0x5D, 0xC3, 0x55, 0x48,
+ 0x89, 0xE5, 0x5D, 0xC3 ]
+ - segment: __DATA
+ section: __data
+ type: S_REGULAR
+ attributes: [ ]
+ alignment: 2
+ address: 0x000000000000000C
+ content: [ 0x0A, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00 ]
+
+global-symbols:
+ - name: _a
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 2
+ value: 0x000000000000000C
+ - name: _b
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 2
+ value: 0x0000000000000010
+ - name: _bar
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000006
+ - name: _foo
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+
+
+...
+
+# CHECK: (__DATA,__data) non-external (was a private external) _a
+# CHECK: (__DATA,__data) external _b
+# CHECK: (__TEXT,__text) non-external (was a private external) _bar
+# CHECK: (__TEXT,__text) external _foo
+
+# CHECK_DEAD-NOT: (__DATA,__data) non-external (was a private external) _a
+# CHECK_DEAD: (__DATA,__data) external _b
+# CHECK_DEAD-NOT: (__TEXT,__text) non-external (was a private external) _bar
+# CHECK_DEAD: (__TEXT,__text) external _foo
diff --git a/test/mach-o/exported_symbols_list-obj.yaml b/test/mach-o/exported_symbols_list-obj.yaml
new file mode 100644
index 000000000000..735162dfedc8
--- /dev/null
+++ b/test/mach-o/exported_symbols_list-obj.yaml
@@ -0,0 +1,67 @@
+# RUN: lld -flavor darwin -arch x86_64 -r %s -o %t -exported_symbol _bar \
+# RUN: && llvm-nm -m %t | FileCheck %s
+#
+# RUN: lld -flavor darwin -arch x86_64 -r %s -o %t2 -keep_private_externs \
+# RUN: -exported_symbol _bar && \
+# RUN: llvm-nm -m %t2 | FileCheck -check-prefix=CHECK_KPE %s
+#
+# RUN: not lld -flavor darwin -arch x86_64 -r %s -o %t3 \
+# RUN: -exported_symbol _foo 2> %t4
+
+# Test -exported_symbols_list properly changes visibility in -r mode.
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0x55, 0x48, 0x89, 0xE5, 0x5D, 0xC3, 0x55, 0x48,
+ 0x89, 0xE5, 0x5D, 0xC3 ]
+ - segment: __DATA
+ section: __data
+ type: S_REGULAR
+ attributes: [ ]
+ alignment: 2
+ address: 0x000000000000000C
+ content: [ 0x0A, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00 ]
+
+global-symbols:
+ - name: _a
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 2
+ value: 0x000000000000000C
+ - name: _b
+ type: N_SECT
+ scope: [ N_EXT, N_PEXT ]
+ sect: 2
+ value: 0x0000000000000010
+ - name: _bar
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000006
+ - name: _foo
+ type: N_SECT
+ scope: [ N_EXT, N_PEXT ]
+ sect: 1
+ value: 0x0000000000000000
+
+
+...
+
+# CHECK: (__DATA,__data) non-external (was a private external) _a
+# CHECK: (__DATA,__data) non-external (was a private external) _b
+# CHECK: (__TEXT,__text) external _bar
+# CHECK: (__TEXT,__text) non-external (was a private external) _foo
+
+# CHECK_KPE: (__DATA,__data) non-external (was a private external) _a
+# CHECK_KPE: (__DATA,__data) private external _b
+# CHECK_KPE: (__TEXT,__text) external _bar
+# CHECK_KPE: (__TEXT,__text) private external _foo
diff --git a/test/mach-o/exported_symbols_list-undef.yaml b/test/mach-o/exported_symbols_list-undef.yaml
new file mode 100644
index 000000000000..c6a8d8f4022f
--- /dev/null
+++ b/test/mach-o/exported_symbols_list-undef.yaml
@@ -0,0 +1,55 @@
+# RUN: not lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 -dylib \
+# RUN: %s %p/Inputs/libSystem.yaml -o %t -exported_symbol _foobar 2> %t2
+#
+# Test -exported_symbol fails if exported symbol not found.
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0x55, 0x48, 0x89, 0xE5, 0x5D, 0xC3, 0x55, 0x48,
+ 0x89, 0xE5, 0x5D, 0xC3 ]
+ - segment: __DATA
+ section: __data
+ type: S_REGULAR
+ attributes: [ ]
+ alignment: 2
+ address: 0x000000000000000C
+ content: [ 0x0A, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00 ]
+
+global-symbols:
+ - name: _a
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 2
+ value: 0x000000000000000C
+ - name: _b
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 2
+ value: 0x0000000000000010
+ - name: _bar
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000006
+ - name: _foo
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+
+
+...
+
+# CHECK: (__DATA,__data) private external _a
+# CHECK: (__DATA,__data) external _b
+# CHECK: (__TEXT,__text) private external _bar
+# CHECK: (__TEXT,__text) external _foo
diff --git a/test/mach-o/fat-archive.yaml b/test/mach-o/fat-archive.yaml
new file mode 100644
index 000000000000..5db7fd96ff0e
--- /dev/null
+++ b/test/mach-o/fat-archive.yaml
@@ -0,0 +1,45 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t \
+# RUN: -L %p/Inputs -lfoo %p/Inputs/libSystem.yaml
+# RUN: llvm-nm -m -n %t | FileCheck %s
+#
+# Test that fat archives are handled.
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ alignment: 4
+ address: 0x0000000000000000
+ content: [ 0x55, 0x48, 0x89, 0xE5, 0x48, 0x83, 0xEC, 0x10,
+ 0xC7, 0x45, 0xFC, 0x00, 0x00, 0x00, 0x00, 0xB0,
+ 0x00, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x31, 0xC0,
+ 0x48, 0x83, 0xC4, 0x10, 0x5D, 0xC3 ]
+ relocations:
+ - offset: 0x00000012
+ type: X86_64_RELOC_BRANCH
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 1
+global-symbols:
+ - name: _main
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+undefined-symbols:
+ - name: _foo
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+
+...
+
+# CHECK: {{[0-9a-f]+}} (__TEXT,__text) external _main
+# CHECK: {{[0-9a-f]+}} (__TEXT,__text) external _foo
diff --git a/test/mach-o/filelist.yaml b/test/mach-o/filelist.yaml
new file mode 100644
index 000000000000..28bfeb74d02b
--- /dev/null
+++ b/test/mach-o/filelist.yaml
@@ -0,0 +1,18 @@
+# RUN: lld -flavor darwin -test_file_usage \
+# RUN: -filelist %p/Inputs/full.filelist \
+# RUN: -path_exists /foo/bar/a.o \
+# RUN: -path_exists /foo/bar/b.o \
+# RUN: -path_exists /foo/x.a \
+# RUN: 2>&1 | FileCheck %s
+#
+# RUN: lld -flavor darwin -test_file_usage -t \
+# RUN: -filelist %p/Inputs/partial.filelist,/foo \
+# RUN: -path_exists /foo/bar/a.o \
+# RUN: -path_exists /foo/bar/b.o \
+# RUN: -path_exists /foo/x.a \
+# RUN: 2>&1 | FileCheck %s
+
+
+# CHECK: Found filelist entry /foo/bar/a.o
+# CHECK: Found filelist entry /foo/bar/b.o
+# CHECK: Found filelist entry /foo/x.a
diff --git a/test/mach-o/force_load-dylib.yaml b/test/mach-o/force_load-dylib.yaml
new file mode 100644
index 000000000000..0b932e159882
--- /dev/null
+++ b/test/mach-o/force_load-dylib.yaml
@@ -0,0 +1,45 @@
+# RUN: lld -flavor darwin -arch x86_64 -dylib %p/Inputs/bar.yaml \
+# RUN: -install_name /usr/lib/libbar.dylib %p/Inputs/libSystem.yaml -o %t1.dylib
+# RUN: lld -flavor darwin -arch x86_64 -dylib %s -all_load %t1.dylib \
+# RUN: -install_name /usr/lib/libfoo.dylib %p/Inputs/libSystem.yaml -o %t
+# RUN: llvm-nm -m %t | FileCheck %s
+#
+#
+# Test -all_load does not break linking with dylibs
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0x55, 0x48, 0x89, 0xE5, 0x31, 0xC0, 0x5D, 0xE9,
+ 0x00, 0x00, 0x00, 0x00 ]
+ relocations:
+ - offset: 0x00000008
+ type: X86_64_RELOC_BRANCH
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 1
+global-symbols:
+ - name: _foo
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+undefined-symbols:
+ - name: _bar
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+
+...
+
+
+# CHECK: (__TEXT,__text) external _foo
diff --git a/test/mach-o/force_load-x86_64.yaml b/test/mach-o/force_load-x86_64.yaml
new file mode 100644
index 000000000000..35905effd2c4
--- /dev/null
+++ b/test/mach-o/force_load-x86_64.yaml
@@ -0,0 +1,38 @@
+# RUN: lld -flavor darwin -arch x86_64 %s %p/Inputs/libSystem.yaml \
+# RUN: %p/Inputs/libfoo.a %p/Inputs/libbar.a -o %t1
+# RUN: llvm-nm -m -n %t1 | FileCheck %s
+#
+# RUN: lld -flavor darwin -arch x86_64 %s %p/Inputs/libSystem.yaml \
+# RUN: -force_load %p/Inputs/libfoo.a %p/Inputs/libbar.a -o %t2
+# RUN: llvm-nm -m -n %t2 | FileCheck --check-prefix=CHECKF %s
+#
+# Test that -force_load causes members of static library to be loaded.
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID: false
+OS: unknown
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0xC3 ]
+global-symbols:
+ - name: _main
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+...
+
+# CHECK: {{[0-9a-f]+}} (__TEXT,__text) external _main
+# CHECK-NOT: {{[0-9a-f]+}} (__TEXT,__text) external _main
+
+# CHECKF: {{[0-9a-f]+}} (__TEXT,__text) external _main
+# CHECKF: {{[0-9a-f]+}} (__TEXT,__text) external _foo
+# CHECKF-NOT: {{[0-9a-f]+}} (__TEXT,__text) external _bar
diff --git a/test/mach-o/framework-user-paths.yaml b/test/mach-o/framework-user-paths.yaml
new file mode 100644
index 000000000000..f6ac64779a71
--- /dev/null
+++ b/test/mach-o/framework-user-paths.yaml
@@ -0,0 +1,41 @@
+#
+# Test framework and SDK search paths.
+# myFrameworks is not an absolute path, so it should not by found in SDK
+# /Custom/Frameworks should be found in SDK
+# /opt/Frameworks should not be found in SDK
+# /System/Library/Frameworks is implicit and should be in SDK
+#
+# RUN: lld -flavor darwin -arch x86_64 -r -test_file_usage -v \
+# RUN: -path_exists myFrameworks \
+# RUN: -path_exists myFrameworks/my.framework/my \
+# RUN: -path_exists /opt/Frameworks \
+# RUN: -path_exists /opt/Frameworks/other.framework/other \
+# RUN: -path_exists /Custom/Frameworks \
+# RUN: -path_exists /Custom/Frameworks/Bar.framework/Bar \
+# RUN: -path_exists /System/Library/Frameworks \
+# RUN: -path_exists /System/Library/Frameworks/Foo.framework/Foo \
+# RUN: -path_exists /SDK/myFrameworks \
+# RUN: -path_exists /SDK/myFrameworks/my.framework/my \
+# RUN: -path_exists /SDK/Custom/Frameworks \
+# RUN: -path_exists /SDK/Custom/Frameworks/Bar.framework/Bar \
+# RUN: -path_exists /SDK/System/Library/Frameworks \
+# RUN: -path_exists /SDK/System/Library/Frameworks/Foo.framework/Foo \
+# RUN: -syslibroot /SDK \
+# RUN: -FmyFrameworks \
+# RUN: -F/Custom/Frameworks \
+# RUN: -F/opt/Frameworks \
+# RUN: -framework my \
+# RUN: -framework Bar \
+# RUN: -framework Foo \
+# RUN: -framework other \
+# RUN: 2>&1 | FileCheck %s
+
+# CHECK: Framework search paths:
+# CHECK-NEXT: myFrameworks
+# CHECK-NEXT: /SDK/Custom/Frameworks
+# CHECK-NEXT: /opt/Frameworks
+# CHECK-NEXT: /SDK/System/Library/Frameworks
+# CHECK: Found framework myFrameworks/my.framework/my
+# CHECK: Found framework /SDK/Custom/Frameworks/Bar.framework/Bar
+# CHECK: Found framework /SDK/System/Library/Frameworks/Foo.framework/Foo
+# CHECK: Found framework /opt/Frameworks/other.framework/other
diff --git a/test/mach-o/got-order.yaml b/test/mach-o/got-order.yaml
new file mode 100644
index 000000000000..fbbc4e0397f2
--- /dev/null
+++ b/test/mach-o/got-order.yaml
@@ -0,0 +1,134 @@
+# RUN: lld -flavor darwin -arch x86_64 %s -o %t %p/Inputs/libSystem.yaml
+# RUN: llvm-objdump -bind %t | FileCheck %s
+#
+# Test that GOT slots are sorted by name
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0x55, 0x48, 0x89, 0xE5, 0x48, 0x8B, 0x0D, 0x00,
+ 0x00, 0x00, 0x00, 0x48, 0x8B, 0x05, 0x00, 0x00,
+ 0x00, 0x00, 0x8B, 0x00, 0x03, 0x01, 0x48, 0x8B,
+ 0x0D, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x5D,
+ 0xC3 ]
+ relocations:
+ - offset: 0x00000019
+ type: X86_64_RELOC_GOT_LOAD
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 2
+ - offset: 0x0000000E
+ type: X86_64_RELOC_GOT_LOAD
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 1
+ - offset: 0x00000007
+ type: X86_64_RELOC_GOT_LOAD
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 3
+global-symbols:
+ - name: _func
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+undefined-symbols:
+ - name: _aaa
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+ - name: _fff
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+ - name: _zzz
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0x55, 0x48, 0x89, 0xE5, 0x48, 0x8B, 0x0D, 0x00,
+ 0x00, 0x00, 0x00, 0x48, 0x8B, 0x05, 0x00, 0x00,
+ 0x00, 0x00, 0x8B, 0x00, 0x03, 0x01, 0x48, 0x8B,
+ 0x0D, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x5D,
+ 0xC3 ]
+ relocations:
+ - offset: 0x00000019
+ type: X86_64_RELOC_GOT_LOAD
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 2
+ - offset: 0x0000000E
+ type: X86_64_RELOC_GOT_LOAD
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 1
+ - offset: 0x00000007
+ type: X86_64_RELOC_GOT_LOAD
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 3
+global-symbols:
+ - name: _main
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+undefined-symbols:
+ - name: _bar
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+ - name: _foo
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+ - name: _zazzle
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+
+--- !mach-o
+arch: x86_64
+file-type: MH_DYLIB
+install-name: /usr/lib/libfoobar.dylib
+exports:
+ - name: _bar
+ - name: _zazzle
+ - name: _foo
+ - name: _aaa
+ - name: _fff
+ - name: _zzz
+...
+
+
+# CHECK: __DATA __got {{[0-9a-zA-Z _]+}} pointer 0 libfoobar _aaa
+# CHECK-NEXT: __DATA __got {{[0-9a-zA-Z _]+}} pointer 0 libfoobar _bar
+# CHECK-NEXT: __DATA __got {{[0-9a-zA-Z _]+}} pointer 0 libfoobar _fff
+# CHECK-NEXT: __DATA __got {{[0-9a-zA-Z _]+}} pointer 0 libfoobar _foo
+# CHECK-NEXT: __DATA __got {{[0-9a-zA-Z _]+}} pointer 0 libfoobar _zazzle
+# CHECK-NEXT: __DATA __got {{[0-9a-zA-Z _]+}} pointer 0 libfoobar _zzz
diff --git a/test/mach-o/hello-world-arm64.yaml b/test/mach-o/hello-world-arm64.yaml
new file mode 100644
index 000000000000..a0555e9cc426
--- /dev/null
+++ b/test/mach-o/hello-world-arm64.yaml
@@ -0,0 +1,104 @@
+# RUN: lld -flavor darwin -arch arm64 %s -o %t
+# RUN: llvm-nm -m -n %t | FileCheck %s
+#
+# Test that arm64 hello-world can be linked into a mach-o executable
+#
+
+--- !mach-o
+arch: arm64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ alignment: 2
+ address: 0x0000000000000000
+ content: [ 0xFD, 0x7B, 0xBF, 0xA9, 0xFD, 0x03, 0x00, 0x91,
+ 0x08, 0x00, 0x00, 0x90, 0x08, 0x01, 0x40, 0xF9,
+ 0x00, 0x01, 0x40, 0xF9, 0x01, 0x00, 0x00, 0x90,
+ 0x21, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x94,
+ 0x00, 0x00, 0x80, 0x52, 0xFD, 0x7B, 0xC1, 0xA8,
+ 0xC0, 0x03, 0x5F, 0xD6 ]
+ relocations:
+ - offset: 0x0000001C
+ type: ARM64_RELOC_BRANCH26
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 5
+ - offset: 0x00000018
+ type: ARM64_RELOC_PAGEOFF12
+ length: 2
+ pc-rel: false
+ extern: true
+ symbol: 1
+ - offset: 0x00000014
+ type: ARM64_RELOC_PAGE21
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 1
+ - offset: 0x0000000C
+ type: ARM64_RELOC_GOT_LOAD_PAGEOFF12
+ length: 2
+ pc-rel: false
+ extern: true
+ symbol: 4
+ - offset: 0x00000008
+ type: ARM64_RELOC_GOT_LOAD_PAGE21
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 4
+ - segment: __TEXT
+ section: __cstring
+ type: S_CSTRING_LITERALS
+ attributes: [ ]
+ address: 0x000000000000002C
+ content: [ 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x00 ]
+local-symbols:
+ - name: ltmp0
+ type: N_SECT
+ sect: 1
+ value: 0x0000000000000000
+ - name: l_.str
+ type: N_SECT
+ sect: 2
+ value: 0x000000000000002C
+ - name: ltmp1
+ type: N_SECT
+ sect: 2
+ value: 0x000000000000002C
+global-symbols:
+ - name: _main
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+undefined-symbols:
+ - name: ___stdoutp
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+ - name: _fprintf
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+...
+
+--- !mach-o
+arch: arm64
+file-type: MH_DYLIB
+install-name: /usr/lib/libSystem.B.dylib
+exports:
+ - name: _fprintf
+ - name: ___stdoutp
+ - name: dyld_stub_binder
+...
+
+# CHECK: {{[0-9a-f]+}} (__TEXT,__text) external _main
+# CHECK: (undefined) external ___stdoutp (from libSystem)
+# CHECK: (undefined) external _fprintf (from libSystem)
+# CHECK: (undefined) external dyld_stub_binder (from libSystem)
diff --git a/test/mach-o/hello-world-armv6.yaml b/test/mach-o/hello-world-armv6.yaml
new file mode 100644
index 000000000000..746ee094da68
--- /dev/null
+++ b/test/mach-o/hello-world-armv6.yaml
@@ -0,0 +1,72 @@
+# RUN: lld -flavor darwin -arch armv6 %s -o %t
+# RUN: llvm-nm -m %t | FileCheck %s
+#
+# Test that armv6 (arm) hello-world can be linked into a mach-o executable
+#
+
+--- !mach-o
+arch: armv6
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID: false
+OS: unknown
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ alignment: 2
+ address: 0x0000000000000000
+ content: [ 0x80, 0x40, 0x2D, 0xE9, 0x10, 0x00, 0x9F, 0xE5,
+ 0x0D, 0x70, 0xA0, 0xE1, 0x00, 0x00, 0x8F, 0xE0,
+ 0xFA, 0xFF, 0xFF, 0xEB, 0x00, 0x00, 0xA0, 0xE3,
+ 0x80, 0x80, 0xBD, 0xE8, 0x0C, 0x00, 0x00, 0x00 ]
+ relocations:
+ - offset: 0x0000001C
+ scattered: true
+ type: ARM_RELOC_SECTDIFF
+ length: 2
+ pc-rel: false
+ value: 0x00000020
+ - offset: 0x00000000
+ scattered: true
+ type: ARM_RELOC_PAIR
+ length: 2
+ pc-rel: false
+ value: 0x0000000C
+ - offset: 0x00000010
+ type: ARM_RELOC_BR24
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 1
+ - segment: __TEXT
+ section: __cstring
+ type: S_CSTRING_LITERALS
+ attributes: [ ]
+ address: 0x0000000000000020
+ content: [ 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x00 ]
+global-symbols:
+ - name: _main
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+undefined-symbols:
+ - name: _printf
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+
+--- !mach-o
+arch: armv6
+file-type: MH_DYLIB
+install-name: /usr/lib/libSystem.B.dylib
+exports:
+ - name: _printf
+ - name: dyld_stub_binder
+...
+
+# CHECK: {{[0-9a-f]+}} (__TEXT,__text) external _main
+# CHECK: (undefined) external _printf (from libSystem)
+# CHECK: (undefined) external dyld_stub_binder (from libSystem)
diff --git a/test/mach-o/hello-world-armv7.yaml b/test/mach-o/hello-world-armv7.yaml
new file mode 100644
index 000000000000..bfc03c382a05
--- /dev/null
+++ b/test/mach-o/hello-world-armv7.yaml
@@ -0,0 +1,85 @@
+# RUN: lld -flavor darwin -arch armv7 %s -o %t
+# RUN: llvm-nm -m -n %t | FileCheck %s
+#
+# Test that armv7 (thumb) hello-world can be linked into a mach-o executable
+#
+
+--- !mach-o
+arch: armv7
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID: false
+OS: unknown
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ alignment: 2
+ address: 0x0000000000000000
+ content: [ 0x80, 0xB5, 0x40, 0xF2, 0x06, 0x00, 0x6F, 0x46,
+ 0xC0, 0xF2, 0x00, 0x00, 0x78, 0x44, 0xFF, 0xF7,
+ 0xF8, 0xEF, 0x00, 0x20, 0x80, 0xBD ]
+ relocations:
+ - offset: 0x0000000E
+ type: ARM_THUMB_RELOC_BR22
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 1
+ - offset: 0x00000008
+ scattered: true
+ type: ARM_RELOC_HALF_SECTDIFF
+ length: 3
+ pc-rel: false
+ value: 0x00000016
+ - offset: 0x00000006
+ scattered: true
+ type: ARM_RELOC_PAIR
+ length: 3
+ pc-rel: false
+ value: 0x0000000C
+ - offset: 0x00000002
+ scattered: true
+ type: ARM_RELOC_HALF_SECTDIFF
+ length: 2
+ pc-rel: false
+ value: 0x00000016
+ - offset: 0x00000000
+ scattered: true
+ type: ARM_RELOC_PAIR
+ length: 2
+ pc-rel: false
+ value: 0x0000000C
+ - segment: __TEXT
+ section: __cstring
+ type: S_CSTRING_LITERALS
+ attributes: [ ]
+ address: 0x0000000000000016
+ content: [ 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x00 ]
+global-symbols:
+ - name: _main
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ desc: [ N_ARM_THUMB_DEF ]
+ value: 0x0000000000000000
+undefined-symbols:
+ - name: _printf
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+...
+
+--- !mach-o
+arch: armv7
+file-type: MH_DYLIB
+install-name: /usr/lib/libSystem.B.dylib
+exports:
+ - name: _printf
+ - name: dyld_stub_binder
+...
+
+# CHECK: {{[0-9a-f]+}} (__TEXT,__text) external [Thumb] _main
+# CHECK: (undefined) external _printf (from libSystem)
+# CHECK: (undefined) external dyld_stub_binder (from libSystem)
diff --git a/test/mach-o/hello-world-x86.yaml b/test/mach-o/hello-world-x86.yaml
new file mode 100644
index 000000000000..de453ed1ac45
--- /dev/null
+++ b/test/mach-o/hello-world-x86.yaml
@@ -0,0 +1,71 @@
+# RUN: lld -flavor darwin -arch i386 %s -o %t
+# RUN: llvm-nm -m %t | FileCheck %s
+#
+# Test that i386 hello-world can be linked into a mach-o executable
+#
+
+--- !mach-o
+arch: x86
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0x55, 0x89, 0xE5, 0x83, 0xEC, 0x08, 0xE8, 0x00,
+ 0x00, 0x00, 0x00, 0x58, 0x8D, 0x80, 0x16, 0x00,
+ 0x00, 0x00, 0x89, 0x04, 0x24, 0xE8, 0xE6, 0xFF,
+ 0xFF, 0xFF, 0x31, 0xC0, 0x83, 0xC4, 0x08, 0x5D,
+ 0xC3 ]
+ relocations:
+ - offset: 0x00000016
+ type: GENERIC_RELOC_VANILLA
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 1
+ - offset: 0x0000000E
+ scattered: true
+ type: GENERIC_RELOC_LOCAL_SECTDIFF
+ length: 2
+ pc-rel: false
+ value: 0x00000021
+ - offset: 0x00000000
+ scattered: true
+ type: GENERIC_RELOC_PAIR
+ length: 2
+ pc-rel: false
+ value: 0x0000000B
+ - segment: __TEXT
+ section: __cstring
+ type: S_CSTRING_LITERALS
+ attributes: [ ]
+ address: 0x0000000000000021
+ content: [ 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x00 ]
+global-symbols:
+ - name: _main
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+undefined-symbols:
+ - name: _printf
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+
+--- !mach-o
+arch: x86
+file-type: MH_DYLIB
+install-name: /usr/lib/libSystem.B.dylib
+exports:
+ - name: _printf
+ - name: dyld_stub_binder
+
+...
+
+# CHECK: {{[0-9a-f]+}} (__TEXT,__text) external _main
+# CHECK: (undefined) external _printf (from libSystem)
+# CHECK: (undefined) external dyld_stub_binder (from libSystem)
diff --git a/test/mach-o/hello-world-x86_64.yaml b/test/mach-o/hello-world-x86_64.yaml
new file mode 100644
index 000000000000..83d4fcb32601
--- /dev/null
+++ b/test/mach-o/hello-world-x86_64.yaml
@@ -0,0 +1,126 @@
+# RUN: lld -flavor darwin -arch x86_64 %s -o %t
+# RUN: llvm-nm -m -n %t | FileCheck %s
+#
+# RUN: lld -flavor darwin -arch x86_64 %s -dead_strip -o %t2
+# RUN: llvm-nm -m -n %t2 | FileCheck %s
+#
+# Test that x86_64 hello-world can be linked into a mach-o executable
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID: false
+OS: unknown
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0x55, 0x48, 0x89, 0xE5, 0x48, 0x8B, 0x05, 0x00,
+ 0x00, 0x00, 0x00, 0x48, 0x8B, 0x38, 0x48, 0x8D,
+ 0x35, 0x00, 0x00, 0x00, 0x00, 0x31, 0xC0, 0xE8,
+ 0x00, 0x00, 0x00, 0x00, 0x31, 0xC0, 0x5D, 0xC3 ]
+ relocations:
+ - offset: 0x00000018
+ type: X86_64_RELOC_BRANCH
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 5
+ - offset: 0x00000011
+ type: X86_64_RELOC_SIGNED
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 0
+ - offset: 0x00000007
+ type: X86_64_RELOC_GOT_LOAD
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 4
+ - segment: __TEXT
+ section: __cstring
+ type: S_CSTRING_LITERALS
+ attributes: [ ]
+ address: 0x0000000000000020
+ content: [ 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x00 ]
+ - segment: __LD
+ section: __compact_unwind
+ type: S_REGULAR
+ attributes: [ ]
+ alignment: 3
+ address: 0x0000000000000028
+ content: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+ relocations:
+ - offset: 0x00000000
+ type: X86_64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: false
+ symbol: 1
+ - segment: __TEXT
+ section: __eh_frame
+ type: S_COALESCED
+ attributes: [ ]
+ alignment: 3
+ address: 0x0000000000000048
+ content: [ 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x7A, 0x52, 0x00, 0x01, 0x78, 0x10, 0x01,
+ 0x10, 0x0C, 0x07, 0x08, 0x90, 0x01, 0x00, 0x00,
+ 0x24, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
+ 0x98, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x41, 0x0E, 0x10, 0x86, 0x02, 0x43, 0x0D,
+ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+local-symbols:
+ - name: L1
+ type: N_SECT
+ sect: 2
+ value: 0x0000000000000020
+ - name: EH_frame0
+ type: N_SECT
+ sect: 4
+ value: 0x0000000000000048
+global-symbols:
+ - name: _main
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+ - name: _main.eh
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 4
+ value: 0x0000000000000060
+undefined-symbols:
+ - name: ___stdoutp
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+ - name: _fprintf
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+
+--- !mach-o
+arch: x86_64
+file-type: MH_DYLIB
+install-name: /usr/lib/libSystem.B.dylib
+exports:
+ - name: _fprintf
+ - name: dyld_stub_binder
+ - name: ___stdoutp
+
+...
+
+# CHECK: {{[0-9a-f]+}} (__TEXT,__text) external _main
+# CHECK: (undefined) external ___stdoutp (from libSystem)
+# CHECK: (undefined) external _fprintf (from libSystem)
+# CHECK: (undefined) external dyld_stub_binder (from libSystem)
diff --git a/test/mach-o/image-base.yaml b/test/mach-o/image-base.yaml
new file mode 100644
index 000000000000..cc272491bc55
--- /dev/null
+++ b/test/mach-o/image-base.yaml
@@ -0,0 +1,27 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.9 %s -o %t -image_base 31415926000 %p/Inputs/libSystem.yaml
+# RUN: macho-dump %t | FileCheck %s
+# RUN: not lld -flavor darwin -arch x86_64 -image_base 0x31415926530 %s >/dev/null 2> %t
+# RUN: FileCheck < %t %s --check-prefix=CHECK-ERROR-MISPAGED
+# RUN: not lld -flavor darwin -arch x86_64 -image_base 1000 %s >/dev/null 2> %t
+# RUN: FileCheck < %t %s --check-prefix=CHECK-ERROR-OVERLAP
+# RUN: not lld -flavor darwin -arch x86_64 -image_base hithere %s >/dev/null 2> %t
+# RUN: FileCheck < %t %s --check-prefix=CHECK-ERROR-NOTHEX
+
+--- !native
+defined-atoms:
+ - name: _main
+ scope: global
+ content: []
+
+ # Unfortunately, llvm-objdump and llvm-readobj are too generic and don't give
+ # us easy access to the MachO segment model, so we have to check the uglier
+ # macho-dump output.
+# CHECK: 'segment_name', '__TEXT
+# CHECK-NEXT: 'vm_addr', 3384796143616
+
+
+# CHECK-ERROR-MISPAGED: error: image_base must be a multiple of page size (0x1000)
+
+# CHECK-ERROR-OVERLAP: error: image_base overlaps with __PAGEZERO
+
+# CHECK-ERROR-NOTHEX: error: image_base expects a hex number
diff --git a/test/mach-o/infer-arch.yaml b/test/mach-o/infer-arch.yaml
new file mode 100644
index 000000000000..94f8543bd72e
--- /dev/null
+++ b/test/mach-o/infer-arch.yaml
@@ -0,0 +1,29 @@
+# RUN: lld -flavor darwin -arch i386 -macosx_version_min 10.8 %s -r -o %t \
+# RUN: && lld -flavor darwin -r %t -o %t2 -print_atoms | FileCheck %s
+#
+# Test linker can detect architecture without -arch option.
+#
+
+--- !mach-o
+arch: x86
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0xC3 ]
+global-symbols:
+ - name: _foo
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+
+...
+
+
+# CHECK: defined-atoms:
+# CHECK: - name: _foo
diff --git a/test/mach-o/interposing-section.yaml b/test/mach-o/interposing-section.yaml
new file mode 100644
index 000000000000..856d4b91f3d2
--- /dev/null
+++ b/test/mach-o/interposing-section.yaml
@@ -0,0 +1,79 @@
+# RUN: lld -flavor darwin -arch x86_64 %s -dylib -o %t %p/Inputs/libSystem.yaml
+# RUN: llvm-objdump -private-headers %t | FileCheck %s
+#
+# RUN: lld -flavor darwin -arch x86_64 %s -r -o %t1
+# RUN: llvm-objdump -private-headers %t1 | FileCheck %s
+#
+# Test that interposing section is preserved by linker.
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0x55, 0x48, 0x89, 0xE5, 0x31, 0xC0, 0x5D, 0xE9,
+ 0x00, 0x00, 0x00, 0x00 ]
+ relocations:
+ - offset: 0x00000008
+ type: X86_64_RELOC_BRANCH
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 2
+ - segment: __DATA
+ section: __interpose
+ type: S_INTERPOSING
+ attributes: [ ]
+ alignment: 3
+ address: 0x0000000000000010
+ content: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+ relocations:
+ - offset: 0x00000008
+ type: X86_64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 2
+ - offset: 0x00000000
+ type: X86_64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 0
+local-symbols:
+ - name: _my_open
+ type: N_SECT
+ sect: 1
+ value: 0x0000000000000000
+ - name: __interpose_open
+ type: N_SECT
+ sect: 2
+ desc: [ N_NO_DEAD_STRIP ]
+ value: 0x0000000000000010
+undefined-symbols:
+ - name: _open
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+
+--- !mach-o
+arch: x86_64
+file-type: MH_DYLIB
+install-name: /usr/lib/libSystem.B.dylib
+exports:
+ - name: _open
+
+...
+
+
+# CHECK: sectname __interposing
+# CHECK: segname __DATA
+# CHECK: type S_INTERPOSING
+
diff --git a/test/mach-o/keep_private_externs.yaml b/test/mach-o/keep_private_externs.yaml
new file mode 100644
index 000000000000..d67941a1c8eb
--- /dev/null
+++ b/test/mach-o/keep_private_externs.yaml
@@ -0,0 +1,63 @@
+# RUN: lld -flavor darwin -arch x86_64 -r %s -o %t \
+# RUN: && llvm-nm -m %t | FileCheck %s
+#
+# RUN: lld -flavor darwin -arch x86_64 -r %s -o %t2 -keep_private_externs \
+# RUN: && llvm-nm -m %t2 | FileCheck -check-prefix=CHECK_KPE %s
+#
+# Test -keep_private_externs in -r mode.
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0x55, 0x48, 0x89, 0xE5, 0x5D, 0xC3, 0x55, 0x48,
+ 0x89, 0xE5, 0x5D, 0xC3 ]
+ - segment: __DATA
+ section: __data
+ type: S_REGULAR
+ attributes: [ ]
+ alignment: 2
+ address: 0x000000000000000C
+ content: [ 0x0A, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00 ]
+
+global-symbols:
+ - name: _a
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 2
+ value: 0x000000000000000C
+ - name: _b
+ type: N_SECT
+ scope: [ N_EXT, N_PEXT ]
+ sect: 2
+ value: 0x0000000000000010
+ - name: _bar
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000006
+ - name: _foo
+ type: N_SECT
+ scope: [ N_EXT, N_PEXT ]
+ sect: 1
+ value: 0x0000000000000000
+
+
+...
+
+# CHECK: (__DATA,__data) external _a
+# CHECK: (__DATA,__data) non-external (was a private external) _b
+# CHECK: (__TEXT,__text) external _bar
+# CHECK: (__TEXT,__text) non-external (was a private external) _foo
+
+# CHECK_KPE: (__DATA,__data) external _a
+# CHECK_KPE: (__DATA,__data) private external _b
+# CHECK_KPE: (__TEXT,__text) external _bar
+# CHECK_KPE: (__TEXT,__text) private external _foo
diff --git a/test/mach-o/lazy-bind-x86_64.yaml b/test/mach-o/lazy-bind-x86_64.yaml
new file mode 100644
index 000000000000..54d787ce91be
--- /dev/null
+++ b/test/mach-o/lazy-bind-x86_64.yaml
@@ -0,0 +1,125 @@
+# REQUIRES: x86
+
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t \
+# RUN: %p/Inputs/libSystem.yaml
+# RUN: llvm-objdump -lazy-bind %t | FileCheck %s
+# RUN: llvm-nm -m %t | FileCheck --check-prefix=CHECK-NM %s
+# RUN: llvm-objdump -disassemble %t | FileCheck --check-prefix=CHECK-HELPERS %s
+# RUN: llvm-objdump -private-headers %t | FileCheck --check-prefix=CHECK-DYLIBS %s
+#
+# Test that correct two-level namespace ordinals are used for lazy bindings.
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0x55, 0x48, 0x89, 0xE5, 0x31, 0xC0, 0xE8, 0x00,
+ 0x00, 0x00, 0x00, 0x31, 0xC0, 0xE8, 0x00, 0x00,
+ 0x00, 0x00, 0x31, 0xC0, 0xE8, 0x00, 0x00, 0x00,
+ 0x00, 0x31, 0xC0, 0x5D, 0xC3 ]
+ relocations:
+ - offset: 0x00000015
+ type: X86_64_RELOC_BRANCH
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 3
+ - offset: 0x0000000E
+ type: X86_64_RELOC_BRANCH
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 2
+ - offset: 0x00000007
+ type: X86_64_RELOC_BRANCH
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 1
+global-symbols:
+ - name: _main
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+undefined-symbols:
+ - name: _bar
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+ - name: _baz
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+ - name: _foo
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+
+--- !mach-o
+arch: x86_64
+file-type: MH_DYLIB
+install-name: /usr/lib/libbar.dylib
+compat-version: 1.0
+current-version: 2.3
+exports:
+ - name: _bar
+
+--- !mach-o
+arch: x86_64
+file-type: MH_DYLIB
+install-name: /usr/lib/libfoo.dylib
+compat-version: 2.0
+current-version: 3.4
+exports:
+ - name: _foo
+
+--- !mach-o
+arch: x86_64
+file-type: MH_DYLIB
+install-name: /usr/lib/libbaz.dylib
+compat-version: 3.0
+current-version: 4.5
+exports:
+ - name: _baz
+
+...
+
+
+# CHECK: libbar _bar
+# CHECK: libbaz _baz
+# CHECK: libfoo _foo
+
+
+# CHECK-NM: (undefined) external _bar (from libbar)
+# CHECK-NM: (undefined) external _baz (from libbaz)
+# CHECK-NM: (undefined) external _foo (from libfoo)
+
+
+# CHECK-HELPERS:Disassembly of section __TEXT,__stub_helper:
+# CHECK-HELPERS: 68 00 00 00 00 pushq $0
+# CHECK-HELPERS: 68 10 00 00 00 pushq $16
+# CHECK-HELPERS: 68 20 00 00 00 pushq $32
+
+
+# CHECK-DYLIBS: cmd LC_LOAD_DYLIB
+# CHECK-DYLIBS: name /usr/lib/libbar.dylib (offset 24)
+# CHECK-DYLIBS: current version 2.3.0
+# CHECK-DYLIBS: compatibility version 1.0.0
+# CHECK-DYLIBS: cmd LC_LOAD_DYLIB
+# CHECK-DYLIBS: name /usr/lib/libfoo.dylib (offset 24)
+# CHECK-DYLIBS: current version 3.4.0
+# CHECK-DYLIBS: compatibility version 2.0.0
+# CHECK-DYLIBS: cmd LC_LOAD_DYLIB
+# CHECK-DYLIBS: name /usr/lib/libbaz.dylib (offset 24)
+# CHECK-DYLIBS: current version 4.5.0
+# CHECK-DYLIBS: compatibility version 3.0.0
+
+
diff --git a/test/mach-o/lib-search-paths.yaml b/test/mach-o/lib-search-paths.yaml
new file mode 100644
index 000000000000..5005f016857f
--- /dev/null
+++ b/test/mach-o/lib-search-paths.yaml
@@ -0,0 +1,16 @@
+# RUN: lld -flavor darwin -arch x86_64 %s -syslibroot %p/Inputs/lib-search-paths -lmyshared -lmystatic -lfile.o -r -print_atoms 2>&1 | FileCheck %s
+
+--- !native
+undefined-atoms:
+ - name: _from_myshared
+ - name: _from_mystatic
+ - name: _from_fileo
+
+# CHECK: defined-atoms:
+# CHECK: - name: _from_fileo
+# CHECK: content: [ 2A, 00, 00, 00 ]
+# CHECK: - name: _from_mystatic
+# CHECK: content: [ 02, 00, 00, 00 ]
+# CHECK: shared-library-atoms:
+# CHECK: - name: _from_myshared
+# CHECK: load-name: libmyshared.dylib
diff --git a/test/mach-o/library-order.yaml b/test/mach-o/library-order.yaml
new file mode 100644
index 000000000000..23e9f6873134
--- /dev/null
+++ b/test/mach-o/library-order.yaml
@@ -0,0 +1,45 @@
+# RUN: lld -flavor darwin -arch x86_64 %p/Inputs/libfoo.a %s -o %t \
+# RUN: %p/Inputs/libSystem.yaml
+# RUN: llvm-nm -m -n %t | FileCheck %s
+#
+# Test that if library is before object file on command line, it still is used.
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ alignment: 4
+ address: 0x0000000000000000
+ content: [ 0x55, 0x48, 0x89, 0xE5, 0x48, 0x83, 0xEC, 0x10,
+ 0xC7, 0x45, 0xFC, 0x00, 0x00, 0x00, 0x00, 0xB0,
+ 0x00, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x31, 0xC0,
+ 0x48, 0x83, 0xC4, 0x10, 0x5D, 0xC3 ]
+ relocations:
+ - offset: 0x00000012
+ type: X86_64_RELOC_BRANCH
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 1
+global-symbols:
+ - name: _main
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+undefined-symbols:
+ - name: _foo
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+
+...
+
+# CHECK: {{[0-9a-f]+}} (__TEXT,__text) external _main
+# CHECK: {{[0-9a-f]+}} (__TEXT,__text) external _foo
diff --git a/test/mach-o/library-rescan.yaml b/test/mach-o/library-rescan.yaml
new file mode 100644
index 000000000000..a58d763fff00
--- /dev/null
+++ b/test/mach-o/library-rescan.yaml
@@ -0,0 +1,46 @@
+# RUN: lld -flavor darwin -arch x86_64 %p/Inputs/libfoo.a %p/Inputs/libbar.a \
+# RUN: %s -o %t %p/Inputs/libSystem.yaml
+# RUN: llvm-nm -m -n %t | FileCheck %s
+#
+# Test that static libraries are automatically rescanned (bar needs foo).
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ alignment: 4
+ address: 0x0000000000000000
+ content: [ 0x55, 0x48, 0x89, 0xE5, 0x48, 0x83, 0xEC, 0x10,
+ 0xC7, 0x45, 0xFC, 0x00, 0x00, 0x00, 0x00, 0xB0,
+ 0x00, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x31, 0xC0,
+ 0x48, 0x83, 0xC4, 0x10, 0x5D, 0xC3 ]
+ relocations:
+ - offset: 0x00000012
+ type: X86_64_RELOC_BRANCH
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 1
+global-symbols:
+ - name: _main
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+undefined-symbols:
+ - name: _bar
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+
+...
+
+# CHECK: {{[0-9a-f]+}} (__TEXT,__text) external _main
+# CHECK: {{[0-9a-f]+}} (__TEXT,__text) external _bar
+# CHECK: {{[0-9a-f]+}} (__TEXT,__text) external _foo
diff --git a/test/mach-o/libresolve-bizarre-root-override.yaml b/test/mach-o/libresolve-bizarre-root-override.yaml
new file mode 100644
index 000000000000..c65ca319432d
--- /dev/null
+++ b/test/mach-o/libresolve-bizarre-root-override.yaml
@@ -0,0 +1,17 @@
+# RUN: not lld -flavor darwin -test_file_usage -v \
+# RUN: -path_exists /usr/lib \
+# RUN: -path_exists /Applications/MySDK/usr/local/lib \
+# RUN: -path_exists /Applications/MySDK/usr/lib \
+# RUN: -path_exists /Applications/MySDK/usr/lib/libSystem.dylib \
+# RUN: -syslibroot /Applications/MySDK \
+# RUN: -syslibroot / \
+# RUN: -lSystem \
+# RUN: 2>&1 | FileCheck %s
+
+# When the last -syslibroot is simply "/", all of them get discarded. So in this
+# case, only /usr/lib should show up.
+
+# CHECK: Library search paths:
+# CHECK: /usr/lib
+# CHECK-NOT: /usr/local/lib
+# CHECK: Unable to find library for -lSystem
diff --git a/test/mach-o/libresolve-multiple-syslibroots.yaml b/test/mach-o/libresolve-multiple-syslibroots.yaml
new file mode 100644
index 000000000000..0b63eb64e7a9
--- /dev/null
+++ b/test/mach-o/libresolve-multiple-syslibroots.yaml
@@ -0,0 +1,17 @@
+# RUN: lld -flavor darwin -test_file_usage -v \
+# RUN: -path_exists /usr/lib \
+# RUN: -path_exists /Applications/MyFirstSDK/usr/local/lib \
+# RUN: -path_exists /Applications/MySecondSDK/usr/local/lib \
+# RUN: -path_exists /Applications/MyFirstSDK/usr/local/lib/libSystem.a \
+# RUN: -path_exists /Applications/MySecondSDK/usr/local/lib/libSystem.a \
+# RUN: -syslibroot /Applications/MyFirstSDK \
+# RUN: -syslibroot /Applications/MySecondSDK \
+# RUN: -lSystem \
+# RUN: 2>&1 | FileCheck %s
+
+
+# CHECK: Library search paths:
+# CHECK: /usr/lib
+# CHECK: /Applications/MyFirstSDK/usr/local/lib
+# CHECK: /Applications/MySecondSDK/usr/local/lib
+# CHECK: Found library /Applications/MyFirstSDK/usr/local/lib/libSystem.a
diff --git a/test/mach-o/libresolve-one-syslibroot.yaml b/test/mach-o/libresolve-one-syslibroot.yaml
new file mode 100644
index 000000000000..f9042fcfada2
--- /dev/null
+++ b/test/mach-o/libresolve-one-syslibroot.yaml
@@ -0,0 +1,25 @@
+# RUN: lld -flavor darwin -test_file_usage -v \
+# RUN: -path_exists /usr/lib \
+# RUN: -path_exists /Applications/MySDK/usr/local/lib \
+# RUN: -path_exists /Applications/MySDK/usr/local/lib/libSystem.a \
+# RUN: -path_exists /hasFoo \
+# RUN: -path_exists /hasFoo/foo.o \
+# RUN: -syslibroot /Applications/MySDK \
+# RUN: -L/hasFoo \
+# RUN: -lSystem -lfoo.o \
+# RUN: 2>&1 | FileCheck %s
+
+# When just one -syslibroot is specified, we apparently want to skip *system*
+# paths that aren't found. User ones should still get added. In this case
+# /usr/lib exists, but not the equivalent in the -syslibroot, so there should be
+# no mention of /usr/lib.
+
+# CHECK: Library search paths:
+# CHECK: /hasFoo
+# CHECK-NOT: /usr/lib
+# CHECK-NOT: /usr/local/lib
+# CHECK: /Applications/MySDK/usr/local/lib
+# CHECK-NOT: /usr/lib
+# CHECK-NOT: /usr/local/lib
+# CHECK: Found library /Applications/MySDK/usr/local/lib/libSystem.a
+# CHECK: Found library /hasFoo/foo.o
diff --git a/test/mach-o/libresolve-simple.yaml b/test/mach-o/libresolve-simple.yaml
new file mode 100644
index 000000000000..ffb045fa3e3c
--- /dev/null
+++ b/test/mach-o/libresolve-simple.yaml
@@ -0,0 +1,21 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -test_file_usage -v \
+# RUN: -path_exists /usr/lib \
+# RUN: -path_exists /usr/local/lib \
+# RUN: -path_exists /usr/lib/libSystem.dylib \
+# RUN: -path_exists hasFoo \
+# RUN: -path_exists hasFoo/libFoo.dylib \
+# RUN: -path_exists /hasBar \
+# RUN: -path_exists /hasBar/libBar.dylib \
+# RUN: -L hasFoo \
+# RUN: -L /hasBar \
+# RUN: -lSystem -lFoo -lBar \
+# RUN: 2>&1 | FileCheck %s
+
+# CHECK: Library search paths:
+# CHECK: hasFoo
+# CHECK: /hasBar
+# CHECK: /usr/lib
+# CHECK: /usr/local/lib
+# CHECK: Found library /usr/lib/libSystem.dylib
+# CHECK: Found library hasFoo/libFoo.dylib
+# CHECK: Found library /hasBar/libBar.dylib
diff --git a/test/mach-o/libresolve-user-paths.yaml b/test/mach-o/libresolve-user-paths.yaml
new file mode 100644
index 000000000000..9fe885671686
--- /dev/null
+++ b/test/mach-o/libresolve-user-paths.yaml
@@ -0,0 +1,20 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -test_file_usage -v \
+# RUN: -path_exists hasFoo \
+# RUN: -path_exists hasFoo/libFoo.dylib \
+# RUN: -path_exists /hasBar \
+# RUN: -path_exists /hasBar/libBar.dylib \
+# RUN: -path_exists /SDK/hasFoo \
+# RUN: -path_exists /SDK/hasFoo/libFoo.dylib \
+# RUN: -path_exists /SDK/hasBar \
+# RUN: -path_exists /SDK/hasBar/libBar.dylib \
+# RUN: -syslibroot /SDK \
+# RUN: -L hasFoo \
+# RUN: -L /hasBar \
+# RUN: -lFoo -lBar \
+# RUN: 2>&1 | FileCheck %s
+
+# CHECK: Library search paths:
+# CHECK: hasFoo
+# CHECK: /SDK/hasBar
+# CHECK: Found library hasFoo/libFoo.dylib
+# CHECK: Found library /SDK/hasBar/libBar.dylib
diff --git a/test/mach-o/libresolve-z.yaml b/test/mach-o/libresolve-z.yaml
new file mode 100644
index 000000000000..1df7eceac1e4
--- /dev/null
+++ b/test/mach-o/libresolve-z.yaml
@@ -0,0 +1,21 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -test_file_usage -v \
+# RUN: -path_exists /usr/lib \
+# RUN: -path_exists /usr/local/lib \
+# RUN: -path_exists /usr/lib/libSystem.dylib \
+# RUN: -path_exists hasFoo \
+# RUN: -path_exists hasFoo/libFoo.dylib \
+# RUN: -path_exists /hasBar \
+# RUN: -path_exists /hasBar/libBar.dylib \
+# RUN: -L hasFoo \
+# RUN: -L /hasBar \
+# RUN: -Z \
+# RUN: -lFoo -lBar \
+# RUN: 2>&1 | FileCheck %s
+
+# CHECK: Library search paths:
+# CHECK: hasFoo
+# CHECK: /hasBar
+# CHECK-NOT: /usr/lib
+# CHECK-NOT: /usr/local/lib
+# CHECK: Found library hasFoo/libFoo.dylib
+# CHECK: Found library /hasBar/libBar.dylib
diff --git a/test/mach-o/linker-as-ld.yaml b/test/mach-o/linker-as-ld.yaml
new file mode 100644
index 000000000000..2dd1f79818e1
--- /dev/null
+++ b/test/mach-o/linker-as-ld.yaml
@@ -0,0 +1,39 @@
+# REQUIRES: system-linker-mach-o
+#
+# RUN: mkdir -p %t.dir && cp `which lld` %t.dir/ld \
+# RUN: && %t.dir/ld -arch x86_64 -macosx_version_min 10.8 %s -o %t \
+# RUN: && llvm-nm %t | FileCheck %s
+#
+# Test linker run as "ld" on darwin works as darwin linker.
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID: false
+OS: unknown
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0xC3 ]
+global-symbols:
+ - name: _main
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+
+--- !mach-o
+arch: x86_64
+file-type: MH_DYLIB
+install-name: /usr/lib/libSystem.B.dylib
+exports:
+ - name: dyld_stub_binder
+
+...
+
+# CHECK: T _main
diff --git a/test/mach-o/lit.local.cfg b/test/mach-o/lit.local.cfg
new file mode 100644
index 000000000000..739a0994fdda
--- /dev/null
+++ b/test/mach-o/lit.local.cfg
@@ -0,0 +1,4 @@
+
+# mach-o test cases encode input files in yaml and use .yaml extension
+config.suffixes = ['.yaml']
+config.excludes = ['Inputs']
diff --git a/test/mach-o/mh_bundle_header.yaml b/test/mach-o/mh_bundle_header.yaml
new file mode 100644
index 000000000000..558df2ca2e95
--- /dev/null
+++ b/test/mach-o/mh_bundle_header.yaml
@@ -0,0 +1,53 @@
+# RUN: lld -flavor darwin -arch x86_64 %s -bundle -o %t %p/Inputs/libSystem.yaml
+# RUN: llvm-nm -m -n %t | FileCheck %s
+#
+# Test that __mh_bundle_header symbol is available for bundles
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0x55, 0x48, 0x89, 0xE5, 0x31, 0xC0, 0x5D, 0xC3 ]
+ - segment: __DATA
+ section: __data
+ type: S_REGULAR
+ attributes: [ ]
+ alignment: 3
+ address: 0x0000000000000008
+ content: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+ relocations:
+ - offset: 0x00000000
+ type: X86_64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 2
+global-symbols:
+ - name: _d
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 2
+ value: 0x0000000000000008
+ - name: _foo
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+undefined-symbols:
+ - name: __mh_bundle_header
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+
+
+...
+
+# CHECK_NOT: __mh_bundle_header
+# CHECK: _foo
diff --git a/test/mach-o/mh_dylib_header.yaml b/test/mach-o/mh_dylib_header.yaml
new file mode 100644
index 000000000000..07429b30c943
--- /dev/null
+++ b/test/mach-o/mh_dylib_header.yaml
@@ -0,0 +1,53 @@
+# RUN: lld -flavor darwin -arch x86_64 %s -dylib -o %t %p/Inputs/libSystem.yaml
+# RUN: llvm-nm -m -n %t | FileCheck %s
+#
+# Test that __mh_dylib_header symbol is available for dylibs
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0x55, 0x48, 0x89, 0xE5, 0x31, 0xC0, 0x5D, 0xC3 ]
+ - segment: __DATA
+ section: __data
+ type: S_REGULAR
+ attributes: [ ]
+ alignment: 3
+ address: 0x0000000000000008
+ content: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+ relocations:
+ - offset: 0x00000000
+ type: X86_64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 2
+global-symbols:
+ - name: _d
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 2
+ value: 0x0000000000000008
+ - name: _foo
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+undefined-symbols:
+ - name: __mh_dylib_header
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+
+
+...
+
+# CHECK_NOT: __mh_dylib_header
+# CHECK: _foo
diff --git a/test/mach-o/objc_export_list.yaml b/test/mach-o/objc_export_list.yaml
new file mode 100644
index 000000000000..5844812295be
--- /dev/null
+++ b/test/mach-o/objc_export_list.yaml
@@ -0,0 +1,63 @@
+# RUN: lld -flavor darwin -arch x86_64 -dylib %s -o %t \
+# RUN: -exported_symbol .objc_class_name_Foo %p/Inputs/libSystem.yaml
+# RUN: llvm-nm -m %t | FileCheck %s
+#
+# Test that exported objc classes can be specificed using old naming
+# (.e.g .objc_class_name_Foo instead of _OBJC_CLASS_$_Foo)
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __DATA
+ section: __objc_data
+ type: S_REGULAR
+ attributes: [ ]
+ alignment: 3
+ address: 0x0000000000000000
+ content: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+ relocations:
+ - offset: 0x00000030
+ type: X86_64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 0
+ - offset: 0x00000028
+ type: X86_64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 1
+ - offset: 0x00000000
+ type: X86_64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 1
+global-symbols:
+ - name: '_OBJC_CLASS_$_Foo'
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+ - name: '_OBJC_METACLASS_$_Foo'
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000028
+...
+
+# CHECK: (__DATA,__objc_data) external _OBJC_CLASS_$_Foo
+# CHECK: (__DATA,__objc_data) external _OBJC_METACLASS_$_Foo
diff --git a/test/mach-o/order_file-basic.yaml b/test/mach-o/order_file-basic.yaml
new file mode 100644
index 000000000000..3fea9be15601
--- /dev/null
+++ b/test/mach-o/order_file-basic.yaml
@@ -0,0 +1,75 @@
+# RUN: lld -flavor darwin -arch x86_64 %s %p/Inputs/libSystem.yaml \
+# RUN: -order_file %p/Inputs/order_file-basic.order \
+# RUN: -force_load %p/Inputs/libfoo.a -o %t
+# RUN: llvm-nm -m -n %t | FileCheck %s
+#
+# Test -order_file
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0xC3, 0xC3, 0xC3, 0xC3 ]
+ - segment: __DATA
+ section: __data
+ type: S_REGULAR
+ attributes: [ ]
+ alignment: 2
+ address: 0x0000000000000014
+ content: [ 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00 ]
+global-symbols:
+ - name: _data1
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 2
+ value: 0x0000000000000014
+ - name: _data2
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 2
+ value: 0x0000000000000018
+ - name: _data3
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 2
+ value: 0x000000000000001C
+ - name: _func1
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+ - name: _func2
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000001
+ - name: _func3
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000002
+ - name: _main
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000003
+...
+
+
+# CHECK: {{[0-9a-f]+}} (__TEXT,__text) external _func2
+# CHECK: {{[0-9a-f]+}} (__TEXT,__text) external _foo
+# CHECK: {{[0-9a-f]+}} (__TEXT,__text) external _func1
+# CHECK: {{[0-9a-f]+}} (__TEXT,__text) external _func3
+# CHECK: {{[0-9a-f]+}} (__TEXT,__text) external _main
+# CHECK: {{[0-9a-f]+}} (__DATA,__data) external _data3
+# CHECK: {{[0-9a-f]+}} (__DATA,__data) external _data1
+# CHECK: {{[0-9a-f]+}} (__DATA,__data) external _data2
+
diff --git a/test/mach-o/parse-aliases.yaml b/test/mach-o/parse-aliases.yaml
new file mode 100644
index 000000000000..457ea58133b9
--- /dev/null
+++ b/test/mach-o/parse-aliases.yaml
@@ -0,0 +1,90 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s
+#
+# Test multiple labels to same address parse into aliases.
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID: false
+OS: unknown
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ alignment: 4
+ address: 0x0000000000000000
+ content: [ 0xCC, 0xC3 ]
+local-symbols:
+ - name: _pad
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+ - name: _myStaticAlias1
+ type: N_SECT
+ sect: 1
+ value: 0x0000000000000001
+ - name: _myStaticAlias3
+ type: N_SECT
+ sect: 1
+ value: 0x0000000000000001
+ - name: _myStaticAlias2
+ type: N_SECT
+ sect: 1
+ value: 0x0000000000000001
+global-symbols:
+ - name: _myGlobalFunc1
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000001
+ - name: _myGlobalFunc2
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000001
+ - name: _myGlobalFunc3
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000001
+ - name: _myHiddenAlias1
+ type: N_SECT
+ scope: [ N_EXT, N_PEXT ]
+ sect: 1
+ value: 0x0000000000000001
+ - name: _myHiddenAlias2
+ type: N_SECT
+ scope: [ N_EXT, N_PEXT ]
+ sect: 1
+ value: 0x0000000000000001
+ - name: _myHiddenAlias3
+ type: N_SECT
+ scope: [ N_EXT, N_PEXT ]
+ sect: 1
+ value: 0x0000000000000001
+...
+
+# CHECK: defined-atoms:
+# CHECK: - name: _pad
+# CHECK: scope: global
+# CHECK: content: [ CC ]
+# CHECK: - name: _myStaticAlias1
+# CHECK: - name: _myStaticAlias2
+# CHECK: - name: _myStaticAlias3
+# CHECK: - name: _myHiddenAlias1
+# CHECK: scope: hidden
+# CHECK: - name: _myHiddenAlias2
+# CHECK: scope: hidden
+# CHECK: - name: _myHiddenAlias3
+# CHECK: scope: hidden
+# CHECK: - name: _myGlobalFunc1
+# CHECK: scope: global
+# CHECK: - name: _myGlobalFunc2
+# CHECK: scope: global
+# CHECK: - name: _myGlobalFunc3
+# CHECK: scope: global
+# CHECK: content: [ C3 ]
diff --git a/test/mach-o/parse-arm-relocs.yaml b/test/mach-o/parse-arm-relocs.yaml
new file mode 100644
index 000000000000..c87c2a99b215
--- /dev/null
+++ b/test/mach-o/parse-arm-relocs.yaml
@@ -0,0 +1,818 @@
+# RUN: lld -flavor darwin -arch armv7 -r -print_atoms %s -o %t | FileCheck %s
+# RUN: lld -flavor darwin -arch armv7 -r -print_atoms %t -o %t2 | FileCheck %s
+#
+# Test parsing of armv7 relocations.
+#
+#
+
+--- !mach-o
+arch: armv7
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ alignment: 2
+ address: 0x0000000000000000
+ content: [ 0x00, 0xF0, 0x4E, 0xF8, 0x00, 0xF0, 0x4E, 0xF8,
+ 0xFF, 0xF7, 0xFA, 0xFF, 0xFF, 0xF7, 0xFA, 0xFF,
+ 0xFF, 0xF7, 0xF6, 0xBF, 0x40, 0xF2, 0x72, 0x01,
+ 0xC0, 0xF2, 0x00, 0x01, 0x40, 0xF2, 0x7A, 0x02,
+ 0xC0, 0xF2, 0x00, 0x02, 0x40, 0xF2, 0x29, 0x01,
+ 0xC0, 0xF2, 0x00, 0x01, 0x79, 0x44, 0x40, 0xF2,
+ 0xA0, 0x03, 0xC0, 0xF2, 0x00, 0x03, 0x40, 0xF2,
+ 0xA8, 0x04, 0xC0, 0xF2, 0x00, 0x04, 0x40, 0xF2,
+ 0x57, 0x03, 0xC0, 0xF2, 0x00, 0x03, 0x40, 0xF2,
+ 0x00, 0x05, 0xC0, 0xF2, 0x00, 0x05, 0x40, 0xF2,
+ 0x08, 0x06, 0xC0, 0xF2, 0x00, 0x06, 0xC0, 0x46,
+ 0x10, 0x00, 0x00, 0xEB, 0x10, 0x00, 0x00, 0xEB,
+ 0xE6, 0xFF, 0xFF, 0xEB, 0xE6, 0xFF, 0xFF, 0xEB,
+ 0xE4, 0xFF, 0xFF, 0xEA, 0x20, 0x10, 0x00, 0xE3,
+ 0x00, 0x10, 0x40, 0xE3, 0x28, 0x20, 0x00, 0xE3,
+ 0x00, 0x20, 0x40, 0xE3, 0x0F, 0x10, 0x81, 0xE0,
+ 0xA0, 0x30, 0x00, 0xE3, 0x00, 0x30, 0x40, 0xE3,
+ 0xA8, 0x40, 0x00, 0xE3, 0x00, 0x40, 0x40, 0xE3,
+ 0x00, 0x50, 0x00, 0xE3, 0x00, 0x50, 0x40, 0xE3,
+ 0x08, 0x60, 0x00, 0xE3, 0x00, 0x60, 0x40, 0xE3 ]
+ relocations:
+ - offset: 0x0000009C
+ type: ARM_RELOC_HALF
+ length: 1
+ pc-rel: false
+ extern: true
+ symbol: 4
+ - offset: 0x00000008
+ type: ARM_RELOC_PAIR
+ length: 1
+ pc-rel: false
+ extern: false
+ symbol: 16777215
+ - offset: 0x00000098
+ type: ARM_RELOC_HALF
+ length: 0
+ pc-rel: false
+ extern: true
+ symbol: 4
+ - offset: 0x00000000
+ type: ARM_RELOC_PAIR
+ length: 0
+ pc-rel: false
+ extern: false
+ symbol: 16777215
+ - offset: 0x00000094
+ type: ARM_RELOC_HALF
+ length: 1
+ pc-rel: false
+ extern: true
+ symbol: 4
+ - offset: 0x00000000
+ type: ARM_RELOC_PAIR
+ length: 1
+ pc-rel: false
+ extern: false
+ symbol: 16777215
+ - offset: 0x00000090
+ type: ARM_RELOC_HALF
+ length: 0
+ pc-rel: false
+ extern: true
+ symbol: 4
+ - offset: 0x00000000
+ type: ARM_RELOC_PAIR
+ length: 0
+ pc-rel: false
+ extern: false
+ symbol: 16777215
+ - offset: 0x0000008C
+ scattered: true
+ type: ARM_RELOC_HALF
+ length: 1
+ pc-rel: false
+ value: 0x000000A0
+ - offset: 0x000000A8
+ type: ARM_RELOC_PAIR
+ length: 1
+ pc-rel: false
+ extern: false
+ symbol: 16777215
+ - offset: 0x00000088
+ scattered: true
+ type: ARM_RELOC_HALF
+ length: 0
+ pc-rel: false
+ value: 0x000000A0
+ - offset: 0x00000000
+ type: ARM_RELOC_PAIR
+ length: 0
+ pc-rel: false
+ extern: false
+ symbol: 16777215
+ - offset: 0x00000084
+ type: ARM_RELOC_HALF
+ length: 1
+ pc-rel: false
+ extern: false
+ symbol: 2
+ - offset: 0x000000A0
+ type: ARM_RELOC_PAIR
+ length: 1
+ pc-rel: false
+ extern: false
+ symbol: 16777215
+ - offset: 0x00000080
+ type: ARM_RELOC_HALF
+ length: 0
+ pc-rel: false
+ extern: false
+ symbol: 2
+ - offset: 0x00000000
+ type: ARM_RELOC_PAIR
+ length: 0
+ pc-rel: false
+ extern: false
+ symbol: 16777215
+ - offset: 0x00000078
+ scattered: true
+ type: ARM_RELOC_HALF_SECTDIFF
+ length: 1
+ pc-rel: false
+ value: 0x000000A0
+ - offset: 0x00000028
+ scattered: true
+ type: ARM_RELOC_PAIR
+ length: 1
+ pc-rel: false
+ value: 0x00000080
+ - offset: 0x00000074
+ scattered: true
+ type: ARM_RELOC_HALF_SECTDIFF
+ length: 0
+ pc-rel: false
+ value: 0x000000A0
+ - offset: 0x00000000
+ scattered: true
+ type: ARM_RELOC_PAIR
+ length: 0
+ pc-rel: false
+ value: 0x00000080
+ - offset: 0x00000070
+ scattered: true
+ type: ARM_RELOC_HALF_SECTDIFF
+ length: 1
+ pc-rel: false
+ value: 0x000000A0
+ - offset: 0x00000020
+ scattered: true
+ type: ARM_RELOC_PAIR
+ length: 1
+ pc-rel: false
+ value: 0x00000080
+ - offset: 0x0000006C
+ scattered: true
+ type: ARM_RELOC_HALF_SECTDIFF
+ length: 0
+ pc-rel: false
+ value: 0x000000A0
+ - offset: 0x00000000
+ scattered: true
+ type: ARM_RELOC_PAIR
+ length: 0
+ pc-rel: false
+ value: 0x00000080
+ - offset: 0x00000068
+ type: ARM_RELOC_BR24
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 4
+ - offset: 0x00000064
+ type: ARM_RELOC_BR24
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 4
+ - offset: 0x00000060
+ type: ARM_RELOC_BR24
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 4
+ - offset: 0x0000005C
+ scattered: true
+ type: ARM_RELOC_BR24
+ length: 2
+ pc-rel: true
+ value: 0x000000A0
+ - offset: 0x00000058
+ type: ARM_RELOC_BR24
+ length: 2
+ pc-rel: true
+ extern: false
+ symbol: 2
+ - offset: 0x00000052
+ type: ARM_RELOC_HALF
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 4
+ - offset: 0x00000008
+ type: ARM_RELOC_PAIR
+ length: 3
+ pc-rel: false
+ extern: false
+ symbol: 16777215
+ - offset: 0x0000004E
+ type: ARM_RELOC_HALF
+ length: 2
+ pc-rel: false
+ extern: true
+ symbol: 4
+ - offset: 0x00000000
+ type: ARM_RELOC_PAIR
+ length: 2
+ pc-rel: false
+ extern: false
+ symbol: 16777215
+ - offset: 0x0000004A
+ type: ARM_RELOC_HALF
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 4
+ - offset: 0x00000000
+ type: ARM_RELOC_PAIR
+ length: 3
+ pc-rel: false
+ extern: false
+ symbol: 16777215
+ - offset: 0x00000046
+ type: ARM_RELOC_HALF
+ length: 2
+ pc-rel: false
+ extern: true
+ symbol: 4
+ - offset: 0x00000000
+ type: ARM_RELOC_PAIR
+ length: 2
+ pc-rel: false
+ extern: false
+ symbol: 16777215
+ - offset: 0x00000042
+ type: ARM_RELOC_HALF
+ length: 3
+ pc-rel: false
+ extern: false
+ symbol: 1
+ - offset: 0x00000057
+ type: ARM_RELOC_PAIR
+ length: 3
+ pc-rel: false
+ extern: false
+ symbol: 16777215
+ - offset: 0x0000003E
+ type: ARM_RELOC_HALF
+ length: 2
+ pc-rel: false
+ extern: false
+ symbol: 1
+ - offset: 0x00000000
+ type: ARM_RELOC_PAIR
+ length: 2
+ pc-rel: false
+ extern: false
+ symbol: 16777215
+ - offset: 0x0000003A
+ scattered: true
+ type: ARM_RELOC_HALF
+ length: 3
+ pc-rel: false
+ value: 0x000000A0
+ - offset: 0x000000A8
+ type: ARM_RELOC_PAIR
+ length: 3
+ pc-rel: false
+ extern: false
+ symbol: 16777215
+ - offset: 0x00000036
+ scattered: true
+ type: ARM_RELOC_HALF
+ length: 2
+ pc-rel: false
+ value: 0x000000A0
+ - offset: 0x00000000
+ type: ARM_RELOC_PAIR
+ length: 2
+ pc-rel: false
+ extern: false
+ symbol: 16777215
+ - offset: 0x00000032
+ type: ARM_RELOC_HALF
+ length: 3
+ pc-rel: false
+ extern: false
+ symbol: 2
+ - offset: 0x000000A0
+ type: ARM_RELOC_PAIR
+ length: 3
+ pc-rel: false
+ extern: false
+ symbol: 16777215
+ - offset: 0x0000002E
+ type: ARM_RELOC_HALF
+ length: 2
+ pc-rel: false
+ extern: false
+ symbol: 2
+ - offset: 0x00000000
+ type: ARM_RELOC_PAIR
+ length: 2
+ pc-rel: false
+ extern: false
+ symbol: 16777215
+ - offset: 0x00000028
+ scattered: true
+ type: ARM_RELOC_HALF_SECTDIFF
+ length: 3
+ pc-rel: false
+ value: 0x00000056
+ - offset: 0x00000028
+ scattered: true
+ type: ARM_RELOC_PAIR
+ length: 3
+ pc-rel: false
+ value: 0x0000002E
+ - offset: 0x00000024
+ scattered: true
+ type: ARM_RELOC_HALF_SECTDIFF
+ length: 2
+ pc-rel: false
+ value: 0x00000056
+ - offset: 0x00000000
+ scattered: true
+ type: ARM_RELOC_PAIR
+ length: 2
+ pc-rel: false
+ value: 0x0000002E
+ - offset: 0x00000020
+ scattered: true
+ type: ARM_RELOC_HALF_SECTDIFF
+ length: 3
+ pc-rel: false
+ value: 0x000000A0
+ - offset: 0x0000007A
+ scattered: true
+ type: ARM_RELOC_PAIR
+ length: 3
+ pc-rel: false
+ value: 0x0000002E
+ - offset: 0x0000001C
+ scattered: true
+ type: ARM_RELOC_HALF_SECTDIFF
+ length: 2
+ pc-rel: false
+ value: 0x000000A0
+ - offset: 0x00000000
+ scattered: true
+ type: ARM_RELOC_PAIR
+ length: 2
+ pc-rel: false
+ value: 0x0000002E
+ - offset: 0x00000018
+ scattered: true
+ type: ARM_RELOC_HALF_SECTDIFF
+ length: 3
+ pc-rel: false
+ value: 0x000000A0
+ - offset: 0x00000072
+ scattered: true
+ type: ARM_RELOC_PAIR
+ length: 3
+ pc-rel: false
+ value: 0x0000002E
+ - offset: 0x00000014
+ scattered: true
+ type: ARM_RELOC_HALF_SECTDIFF
+ length: 2
+ pc-rel: false
+ value: 0x000000A0
+ - offset: 0x00000000
+ scattered: true
+ type: ARM_RELOC_PAIR
+ length: 2
+ pc-rel: false
+ value: 0x0000002E
+ - offset: 0x00000010
+ type: ARM_THUMB_RELOC_BR22
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 4
+ - offset: 0x0000000C
+ type: ARM_THUMB_RELOC_BR22
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 4
+ - offset: 0x00000008
+ type: ARM_THUMB_RELOC_BR22
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 4
+ - offset: 0x00000004
+ scattered: true
+ type: ARM_THUMB_RELOC_BR22
+ length: 2
+ pc-rel: true
+ value: 0x000000A0
+ - offset: 0x00000000
+ type: ARM_THUMB_RELOC_BR22
+ length: 2
+ pc-rel: true
+ extern: false
+ symbol: 2
+ - segment: __DATA
+ section: __data
+ type: S_REGULAR
+ attributes: [ ]
+ address: 0x00000000000000A0
+ content: [ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0xA4, 0xFF, 0xFF, 0xFF,
+ 0xA4, 0xFF, 0xFF, 0xFF, 0x45, 0xFF, 0xFF, 0xFF,
+ 0x45, 0xFF, 0xFF, 0xFF ]
+ relocations:
+ - offset: 0x00000020
+ scattered: true
+ type: ARM_RELOC_SECTDIFF
+ length: 2
+ pc-rel: false
+ value: 0x00000000
+ - offset: 0x00000000
+ scattered: true
+ type: ARM_RELOC_PAIR
+ length: 2
+ pc-rel: false
+ value: 0x000000C0
+ - offset: 0x0000001C
+ scattered: true
+ type: ARM_RELOC_SECTDIFF
+ length: 2
+ pc-rel: false
+ value: 0x00000000
+ - offset: 0x00000000
+ scattered: true
+ type: ARM_RELOC_PAIR
+ length: 2
+ pc-rel: false
+ value: 0x000000BC
+ - offset: 0x00000018
+ scattered: true
+ type: ARM_RELOC_SECTDIFF
+ length: 2
+ pc-rel: false
+ value: 0x00000058
+ - offset: 0x00000000
+ scattered: true
+ type: ARM_RELOC_PAIR
+ length: 2
+ pc-rel: false
+ value: 0x000000B8
+ - offset: 0x00000014
+ scattered: true
+ type: ARM_RELOC_SECTDIFF
+ length: 2
+ pc-rel: false
+ value: 0x00000058
+ - offset: 0x00000000
+ scattered: true
+ type: ARM_RELOC_PAIR
+ length: 2
+ pc-rel: false
+ value: 0x000000B4
+ - offset: 0x00000010
+ type: ARM_RELOC_VANILLA
+ length: 2
+ pc-rel: false
+ extern: true
+ symbol: 4
+ - offset: 0x0000000C
+ type: ARM_RELOC_VANILLA
+ length: 2
+ pc-rel: false
+ extern: true
+ symbol: 4
+ - offset: 0x00000008
+ scattered: true
+ type: ARM_RELOC_VANILLA
+ length: 2
+ pc-rel: false
+ value: 0x00000000
+ - offset: 0x00000004
+ type: ARM_RELOC_VANILLA
+ length: 2
+ pc-rel: false
+ extern: false
+ symbol: 1
+local-symbols:
+ - name: _foo_thumb
+ type: N_SECT
+ sect: 1
+ desc: [ N_ARM_THUMB_DEF ]
+ value: 0x0000000000000000
+ - name: _x
+ type: N_SECT
+ sect: 2
+ value: 0x00000000000000A0
+ - name: _t1
+ type: N_SECT
+ sect: 1
+ desc: [ N_ARM_THUMB_DEF ]
+ value: 0x0000000000000056
+ - name: _foo_arm
+ type: N_SECT
+ sect: 1
+ value: 0x0000000000000058
+undefined-symbols:
+ - name: _undef
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+...
+
+# CHECK: defined-atoms:
+# CHECK: - name: _x
+# CHECK: type: data
+# CHECK: references:
+# CHECK: - kind: pointer32
+# CHECK: offset: 4
+# CHECK: target: _foo_thumb
+# CHECK-NOT: addend:
+# CHECK: - kind: pointer32
+# CHECK: offset: 8
+# CHECK: target: _foo_thumb
+# CHECK: addend: 4
+# CHECK: - kind: pointer32
+# CHECK: offset: 12
+# CHECK: target: _undef
+# CHECK-NOT: addend:
+# CHECK: - kind: pointer32
+# CHECK: offset: 16
+# CHECK: target: _undef
+# CHECK: addend: 4
+# CHECK: - kind: delta32
+# CHECK: offset: 20
+# CHECK: target: _foo_arm
+# CHECK-NOT: addend:
+# CHECK: - kind: delta32
+# CHECK: offset: 24
+# CHECK: target: _foo_arm
+# CHECK: addend: 4
+# CHECK: - kind: delta32
+# CHECK: offset: 28
+# CHECK: target: _foo_thumb
+# CHECK-NOT: addend:
+# CHECK: - kind: delta32
+# CHECK: offset: 32
+# CHECK: target: _foo_thumb
+# CHECK: addend: 4
+# CHECK: - name: _foo_thumb
+# CHECK: references:
+# CHECK: - kind: modeThumbCode
+# CHECK: offset: 0
+# CHECK: - kind: thumb_bl22
+# CHECK: offset: 0
+# CHECK: target: _x
+# CHECK-NOT: addend:
+# CHECK: - kind: thumb_bl22
+# CHECK: offset: 4
+# CHECK: target: _x
+# CHECK: addend: 4
+# CHECK: - kind: thumb_bl22
+# CHECK: offset: 8
+# CHECK: target: _undef
+# CHECK-NOT: addend:
+# CHECK: - kind: thumb_bl22
+# CHECK: offset: 12
+# CHECK: target: _undef
+# CHECK: addend: 4
+# CHECK: - kind: thumb_b22
+# CHECK: offset: 16
+# CHECK: target: _undef
+# CHECK-NOT: addend:
+# CHECK: - kind: thumb_movw_funcRel
+# CHECK: offset: 20
+# CHECK: target: _x
+# CHECK: addend: -46
+# CHECK: - kind: thumb_movt_funcRel
+# CHECK: offset: 24
+# CHECK: target: _x
+# CHECK: addend: -46
+# CHECK: - kind: thumb_movw_funcRel
+# CHECK: offset: 28
+# CHECK: target: _x
+# CHECK: addend: -38
+# CHECK: - kind: thumb_movt_funcRel
+# CHECK: offset: 32
+# CHECK: target: _x
+# CHECK: addend: -38
+# CHECK: - kind: thumb_movw_funcRel
+# CHECK: offset: 36
+# CHECK: target: _t1
+# CHECK: addend: -46
+# CHECK: - kind: thumb_movt_funcRel
+# CHECK: offset: 40
+# CHECK: target: _t1
+# CHECK: addend: -46
+# CHECK: - kind: thumb_movw
+# CHECK: offset: 46
+# CHECK: target: _x
+# CHECK-NOT: addend:
+# CHECK: - kind: thumb_movt
+# CHECK: offset: 50
+# CHECK: target: _x
+# CHECK-NOT: addend:
+# CHECK: - kind: thumb_movw
+# CHECK: offset: 54
+# CHECK: target: _x
+# CHECK: addend: 8
+# CHECK: - kind: thumb_movt
+# CHECK: offset: 58
+# CHECK: target: _x
+# CHECK: addend: 8
+# CHECK: - kind: thumb_movw
+# CHECK: offset: 62
+# CHECK: target: _t1
+# CHECK-NOT: addend:
+# CHECK: - kind: thumb_movt
+# CHECK: offset: 66
+# CHECK: target: _t1
+# CHECK-NOT: addend:
+# CHECK: - kind: thumb_movw
+# CHECK: offset: 70
+# CHECK: target: _undef
+# CHECK-NOT: addend:
+# CHECK: - kind: thumb_movt
+# CHECK: offset: 74
+# CHECK: target: _undef
+# CHECK-NOT: addend:
+# CHECK: - kind: thumb_movw
+# CHECK: offset: 78
+# CHECK: target: _undef
+# CHECK: addend: 8
+# CHECK: - kind: thumb_movt
+# CHECK: offset: 82
+# CHECK: target: _undef
+# CHECK: addend: 8
+# CHECK: - name: _t1
+# CHECK: content: [ C0, 46 ]
+# CHECK: references:
+# CHECK: - kind: modeThumbCode
+# CHECK: offset: 0
+# CHECK: - name: _foo_arm
+# CHECK: references:
+# CHECK-NOT: - kind: modeThumbCode
+# CHECK: - kind: arm_bl24
+# CHECK: offset: 0
+# CHECK: target: _x
+# CHECK-NOT: addend:
+# CHECK: - kind: arm_bl24
+# CHECK: offset: 4
+# CHECK: target: _x
+# CHECK: addend: 4
+# CHECK: - kind: arm_bl24
+# CHECK: offset: 8
+# CHECK: target: _undef
+# CHECK-NOT: addend:
+# CHECK: - kind: arm_bl24
+# CHECK: offset: 12
+# CHECK: target: _undef
+# CHECK: addend: 4
+# CHECK: - kind: arm_b24
+# CHECK: offset: 16
+# CHECK: target: _undef
+# CHECK-NOT: addend:
+# CHECK: - kind: arm_movw_funcRel
+# CHECK: offset: 20
+# CHECK: target: _x
+# CHECK: addend: -40
+# CHECK: - kind: arm_movt_funcRel
+# CHECK: offset: 24
+# CHECK: target: _x
+# CHECK: addend: -40
+# CHECK: - kind: arm_movw_funcRel
+# CHECK: offset: 28
+# CHECK: target: _x
+# CHECK: addend: -32
+# CHECK: - kind: arm_movt_funcRel
+# CHECK: offset: 32
+# CHECK: target: _x
+# CHECK: addend: -32
+# CHECK: - kind: arm_movw
+# CHECK: offset: 40
+# CHECK: target: _x
+# CHECK-NOT: addend:
+# CHECK: - kind: arm_movt
+# CHECK: offset: 44
+# CHECK: target: _x
+# CHECK-NOT: addend:
+# CHECK: - kind: arm_movw
+# CHECK: offset: 48
+# CHECK: target: _x
+# CHECK: addend: 8
+# CHECK: - kind: arm_movt
+# CHECK: offset: 52
+# CHECK: target: _x
+# CHECK: addend: 8
+# CHECK: - kind: arm_movw
+# CHECK: offset: 56
+# CHECK: target: _undef
+# CHECK-NOT: addend:
+# CHECK: - kind: arm_movt
+# CHECK: offset: 60
+# CHECK: target: _undef
+# CHECK-NOT: addend:
+# CHECK: - kind: arm_movw
+# CHECK: offset: 64
+# CHECK: target: _undef
+# CHECK: addend: 8
+# CHECK: - kind: arm_movt
+# CHECK: offset: 68
+# CHECK: target: _undef
+# CHECK: addend: 8
+# CHECK: undefined-atoms:
+# CHECK: - name: _undef
+
+
+
+
+# .align 2
+# .code 16
+# .thumb_func _foo_thumb
+#_foo_thumb:
+# bl _x
+# bl _x+4
+# bl _undef
+# bl _undef+4
+# b _undef
+# movw r1, :lower16:(_x-L1)
+# movt r1, :upper16:(_x-L1)
+# movw r2, :lower16:(_x+8-L1)
+# movt r2, :upper16:(_x+8-L1)
+# movw r1, :lower16:(_t1-L1)
+# movt r1, :upper16:(_t1-L1)
+# add r1, pc
+#L1:
+# movw r3, :lower16:_x
+# movt r3, :upper16:_x
+# movw r4, :lower16:_x+8
+# movt r4, :upper16:_x+8
+# movw r3, :lower16:_t1
+# movt r3, :upper16:_t1
+# movw r5, :lower16:_undef
+# movt r5, :upper16:_undef
+# movw r6, :lower16:_undef+8
+# movt r6, :upper16:_undef+8
+#
+# .thumb_func _t1
+#_t1:
+# nop
+#
+#
+# .code 32
+# .align 2
+#_foo_arm:
+# bl _x
+# bl _x+4
+# bl _undef
+# bl _undef+4
+# b _undef
+# movw r1, :lower16:(_x-L2)
+# movt r1, :upper16:(_x-L2)
+# movw r2, :lower16:(_x+8-L2)
+# movt r2, :upper16:(_x+8-L2)
+# add r1, pc
+#L2:
+# movw r3, :lower16:_x
+# movt r3, :upper16:_x
+# movw r4, :lower16:_x+8
+# movt r4, :upper16:_x+8
+# movw r5, :lower16:_undef
+# movt r5, :upper16:_undef
+# movw r6, :lower16:_undef+8
+# movt r6, :upper16:_undef+8
+#
+#
+# .data
+#_x: .long 0
+# .long _foo_thumb
+# .long _foo_thumb+4
+# .long _undef
+# .long _undef+4
+# .long _foo_arm - .
+# .long _foo_arm+4- .
+# .long _foo_thumb - .
+# .long _foo_thumb+4 - .
+#
diff --git a/test/mach-o/parse-cfstring32.yaml b/test/mach-o/parse-cfstring32.yaml
new file mode 100644
index 000000000000..657e733a779b
--- /dev/null
+++ b/test/mach-o/parse-cfstring32.yaml
@@ -0,0 +1,94 @@
+# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t | FileCheck %s
+#
+# Test parsing of mach-o functions.
+#
+
+--- !mach-o
+arch: x86
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID: false
+OS: unknown
+sections:
+ - segment: __TEXT
+ section: __cstring
+ type: S_CSTRING_LITERALS
+ attributes: [ ]
+ address: 0x0000000000000000
+ content: [ 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x00, 0x74, 0x68,
+ 0x65, 0x72, 0x65, 0x00 ]
+ - segment: __DATA
+ section: __cfstring
+ type: S_REGULAR
+ attributes: [ ]
+ alignment: 3
+ address: 0x0000000000000010
+ content: [ 0x00, 0x00, 0x00, 0x00, 0xC8, 0x07, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xC8, 0x07, 0x00, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00 ]
+ relocations:
+ - offset: 0x00000018
+ type: GENERIC_RELOC_VANILLA
+ length: 2
+ pc-rel: false
+ extern: false
+ symbol: 1
+ - offset: 0x00000010
+ type: GENERIC_RELOC_VANILLA
+ length: 2
+ pc-rel: false
+ extern: true
+ symbol: 0
+ - offset: 0x00000008
+ type: GENERIC_RELOC_VANILLA
+ length: 2
+ pc-rel: false
+ extern: false
+ symbol: 1
+ - offset: 0x00000000
+ type: GENERIC_RELOC_VANILLA
+ length: 2
+ pc-rel: false
+ extern: true
+ symbol: 0
+undefined-symbols:
+ - name: ___CFConstantStringClassReference
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+...
+
+# CHECK: defined-atoms:
+# CHECK: - ref-name: [[STR1:L[L0-9]+]]
+# CHECK: scope: hidden
+# CHECK: type: c-string
+# CHECK: content: [ 68, 65, 6C, 6C, 6F, 00 ]
+# CHECK: merge: by-content
+# CHECK: - ref-name: [[STR2:L[L0-9]+]]
+# CHECK: scope: hidden
+# CHECK: type: c-string
+# CHECK: content: [ 74, 68, 65, 72, 65, 00 ]
+# CHECK: merge: by-content
+# CHECK: - scope: hidden
+# CHECK: type: cfstring
+# CHECK: merge: by-content
+# CHECK: references:
+# CHECK: - kind: pointer32
+# CHECK: offset: 0
+# CHECK: target: ___CFConstantStringClassReference
+# CHECK: - kind: pointer32
+# CHECK: offset: 8
+# CHECK: target: [[STR1]]
+# CHECK: - scope: hidden
+# CHECK: type: cfstring
+# CHECK: merge: by-content
+# CHECK: references:
+# CHECK: - kind: pointer32
+# CHECK: offset: 0
+# CHECK: target: ___CFConstantStringClassReference
+# CHECK: - kind: pointer32
+# CHECK: offset: 8
+# CHECK: target: [[STR2]]
+# CHECK:undefined-atoms:
+# CHECK: - name: ___CFConstantStringClassReference
diff --git a/test/mach-o/parse-cfstring64.yaml b/test/mach-o/parse-cfstring64.yaml
new file mode 100644
index 000000000000..fbd674d90d99
--- /dev/null
+++ b/test/mach-o/parse-cfstring64.yaml
@@ -0,0 +1,108 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s
+#
+# Test parsing of CFString constants.
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID: false
+OS: unknown
+sections:
+ - segment: __TEXT
+ section: __cstring
+ type: S_CSTRING_LITERALS
+ attributes: [ ]
+ address: 0x0000000000000000
+ content: [ 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x00, 0x74, 0x68,
+ 0x65, 0x72, 0x65, 0x00 ]
+ - segment: __DATA
+ section: __cfstring
+ type: S_REGULAR
+ attributes: [ ]
+ alignment: 4
+ address: 0x0000000000000010
+ content: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xC8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xC8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+ relocations:
+ - offset: 0x00000030
+ type: X86_64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 1
+ - offset: 0x00000020
+ type: X86_64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 2
+ - offset: 0x00000010
+ type: X86_64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 0
+ - offset: 0x00000000
+ type: X86_64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 2
+local-symbols:
+ - name: Lstr1
+ type: N_SECT
+ sect: 1
+ value: 0x0000000000000000
+ - name: Lstr2
+ type: N_SECT
+ sect: 1
+ value: 0x0000000000000006
+undefined-symbols:
+ - name: ___CFConstantStringClassReference
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+...
+
+# CHECK:defined-atoms:
+# CHECK: - ref-name: L000
+# CHECK: scope: hidden
+# CHECK: type: c-string
+# CHECK: content: [ 68, 65, 6C, 6C, 6F, 00 ]
+# CHECK: merge: by-content
+# CHECK: - ref-name: L001
+# CHECK: scope: hidden
+# CHECK: type: c-string
+# CHECK: content: [ 74, 68, 65, 72, 65, 00 ]
+# CHECK: merge: by-content
+# CHECK: - scope: hidden
+# CHECK: type: cfstring
+# CHECK: merge: by-content
+# CHECK: references:
+# CHECK: - kind: pointer64
+# CHECK: offset: 0
+# CHECK: target: ___CFConstantStringClassReference
+# CHECK: - kind: pointer64
+# CHECK: offset: 16
+# CHECK: target: L000
+# CHECK: - scope: hidden
+# CHECK: type: cfstring
+# CHECK: merge: by-content
+# CHECK: references:
+# CHECK: - kind: pointer64
+# CHECK: offset: 0
+# CHECK: target: ___CFConstantStringClassReference
+# CHECK: - kind: pointer64
+# CHECK: offset: 16
+# CHECK: target: L001
+# CHECK:undefined-atoms:
+# CHECK: - name: ___CFConstantStringClassReference
+
diff --git a/test/mach-o/parse-compact-unwind32.yaml b/test/mach-o/parse-compact-unwind32.yaml
new file mode 100644
index 000000000000..ff613f0809bb
--- /dev/null
+++ b/test/mach-o/parse-compact-unwind32.yaml
@@ -0,0 +1,72 @@
+# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t | FileCheck %s
+#
+# Test parsing of __LD/__compact_unwind (compact unwind) section.
+#
+
+--- !mach-o
+arch: x86
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID: false
+OS: unknown
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ alignment: 4
+ address: 0x0000000000000000
+ content: [ 0x55, 0x89, 0xE5, 0xB8, 0x0A, 0x00, 0x00, 0x00,
+ 0x5D, 0xC3, 0x55, 0x89, 0xE5, 0xB8, 0x0A, 0x00,
+ 0x00, 0x00, 0x5D, 0xC3 ]
+ - segment: __LD
+ section: __compact_unwind
+ type: S_REGULAR
+ attributes: [ ]
+ alignment: 2
+ address: 0x000000000000001C
+ content: [ 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+ relocations:
+ - offset: 0x00000014
+ type: GENERIC_RELOC_VANILLA
+ length: 2
+ pc-rel: false
+ extern: false
+ symbol: 1
+ - offset: 0x00000000
+ type: GENERIC_RELOC_VANILLA
+ length: 2
+ pc-rel: false
+ extern: false
+ symbol: 1
+global-symbols:
+ - name: __Z3barv
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x000000000000000A
+ - name: __Z3foov
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+...
+
+# CHECK: defined-atoms:
+# CHECK: - type: compact-unwind
+# CHECK: content: [ 00, 00, 00, 00, 0A, 00, 00, 00, 00, 00, 00, 01,
+# CHECK: 00, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK: - type: compact-unwind
+# CHECK: content: [ 10, 00, 00, 00, 0A, 00, 00, 00, 00, 00, 00, 01,
+# CHECK: 00, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK: - name: __Z3foov
+# CHECK: scope: global
+# CHECK: content: [ 55, 89, E5, B8, 0A, 00, 00, 00, 5D, C3 ]
+# CHECK: - name: __Z3barv
+# CHECK: scope: global
+# CHECK: content: [ 55, 89, E5, B8, 0A, 00, 00, 00, 5D, C3 ]
+
diff --git a/test/mach-o/parse-compact-unwind64.yaml b/test/mach-o/parse-compact-unwind64.yaml
new file mode 100644
index 000000000000..b61961a3d0b0
--- /dev/null
+++ b/test/mach-o/parse-compact-unwind64.yaml
@@ -0,0 +1,76 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s
+#
+# Test parsing of __LD/__compact_unwind (compact unwind) section.
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID: false
+OS: unknown
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ alignment: 4
+ address: 0x0000000000000000
+ content: [ 0x55, 0x48, 0x89, 0xE5, 0xB8, 0x0A, 0x00, 0x00,
+ 0x00, 0x5D, 0xC3, 0x55, 0x48, 0x89, 0xE5, 0xB8,
+ 0x0A, 0x00, 0x00, 0x00, 0x5D, 0xC3 ]
+ - segment: __LD
+ section: __compact_unwind
+ type: S_REGULAR
+ attributes: [ ]
+ alignment: 3
+ address: 0x0000000000000020
+ content: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+ relocations:
+ - offset: 0x00000020
+ type: X86_64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: false
+ symbol: 1
+ - offset: 0x00000000
+ type: X86_64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: false
+ symbol: 1
+global-symbols:
+ - name: __Z3barv
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+ - name: __Z3foov
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x000000000000000B
+...
+
+# CHECK: defined-atoms:
+# CHECK: - type: compact-unwind
+# CHECK: content: [ 00, 00, 00, 00, 00, 00, 00, 00, 0B, 00, 00, 00,
+# CHECK: 00, 00, 00, 01, 00, 00, 00, 00, 00, 00, 00, 00,
+# CHECK: 00, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK: - type: compact-unwind
+# CHECK: content: [ 10, 00, 00, 00, 00, 00, 00, 00, 0B, 00, 00, 00,
+# CHECK: 00, 00, 00, 01, 00, 00, 00, 00, 00, 00, 00, 00,
+# CHECK: 00, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK: - name: __Z3barv
+# CHECK: scope: global
+# CHECK: content: [ 55, 48, 89, E5, B8, 0A, 00, 00, 00, 5D, C3 ]
+# CHECK: - name: __Z3foov
+# CHECK: scope: global
+# CHECK: content: [ 55, 48, 89, E5, B8, 0A, 00, 00, 00, 5D, C3 ]
diff --git a/test/mach-o/parse-data-in-code-armv7.yaml b/test/mach-o/parse-data-in-code-armv7.yaml
new file mode 100644
index 000000000000..29b483e7d723
--- /dev/null
+++ b/test/mach-o/parse-data-in-code-armv7.yaml
@@ -0,0 +1,157 @@
+# RUN: lld -flavor darwin -arch armv7 -r -print_atoms %s -o %t | FileCheck %s
+# RUN: lld -flavor darwin -arch armv7 -r -print_atoms %t -o %t2 | FileCheck %s
+# RUN: lld -flavor darwin -arch armv7 -dylib %s -o %t3.dylib %p/Inputs/libSystem.yaml \
+# RUN: && llvm-objdump -macho -private-headers %t3.dylib | FileCheck --check-prefix=CHECK2 %s
+#
+# Test parsing LC_DATA_IN_CODE
+#
+#
+
+--- !mach-o
+arch: armv7
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ alignment: 2
+ address: 0x0000000000000000
+ content: [ 0x00, 0xBF, 0x00, 0xBF, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x00, 0xBF,
+ 0x00, 0xF0, 0x20, 0xE3, 0x0A, 0x00, 0x00, 0x00,
+ 0x0B, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
+ 0x0D, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x20, 0xE3 ]
+local-symbols:
+ - name: _foo_thumb
+ type: N_SECT
+ sect: 1
+ desc: [ N_ARM_THUMB_DEF ]
+ value: 0x0000000000000000
+ - name: _foo_arm
+ type: N_SECT
+ sect: 1
+ value: 0x0000000000000018
+dataInCode:
+ - offset: 0x00000004
+ length: 0x0004
+ kind: DICE_KIND_DATA
+ - offset: 0x00000008
+ length: 0x0004
+ kind: DICE_KIND_JUMP_TABLE32
+ - offset: 0x0000000C
+ length: 0x0004
+ kind: DICE_KIND_JUMP_TABLE16
+ - offset: 0x00000010
+ length: 0x0004
+ kind: DICE_KIND_JUMP_TABLE8
+ - offset: 0x0000001C
+ length: 0x0004
+ kind: DICE_KIND_DATA
+ - offset: 0x00000020
+ length: 0x0004
+ kind: DICE_KIND_JUMP_TABLE32
+ - offset: 0x00000024
+ length: 0x0004
+ kind: DICE_KIND_JUMP_TABLE16
+ - offset: 0x00000028
+ length: 0x0004
+ kind: DICE_KIND_JUMP_TABLE8
+...
+
+
+
+# CHECK: defined-atoms:
+# CHECK: - name: _foo_thumb
+# CHECK: references:
+# CHECK: - kind: modeThumbCode
+# CHECK: offset: 0
+# CHECK: - kind: modeData
+# CHECK: offset: 4
+# CHECK: addend: 1
+# CHECK: - kind: modeData
+# CHECK: offset: 8
+# CHECK: addend: 4
+# CHECK: - kind: modeData
+# CHECK: offset: 12
+# CHECK: addend: 3
+# CHECK: - kind: modeData
+# CHECK: offset: 16
+# CHECK: addend: 2
+# CHECK: - kind: modeThumbCode
+# CHECK: offset: 20
+# CHECK: - name: _foo_arm
+# CHECK: references:
+# CHECK: - kind: modeData
+# CHECK: offset: 4
+# CHECK: addend: 1
+# CHECK: - kind: modeData
+# CHECK: offset: 8
+# CHECK: addend: 4
+# CHECK: - kind: modeData
+# CHECK: offset: 12
+# CHECK: addend: 3
+# CHECK: - kind: modeData
+# CHECK: offset: 16
+# CHECK: addend: 2
+# CHECK: - kind: modeArmCode
+# CHECK: offset: 20
+
+
+# CHECK2: cmd LC_DATA_IN_CODE
+# CHECK2: cmdsize 16
+# CHECK2: datasize 64
+
+
+# .code 16
+# .thumb_func _foo_thumb
+#_foo_thumb:
+# nop
+# nop
+#
+# .data_region
+# .long 0
+# .end_data_region
+#
+# .data_region jt32
+# .long 1
+# .end_data_region
+#
+# .data_region jt16
+# .long 2
+# .end_data_region
+#
+# .data_region jt8
+# .long 3
+# .end_data_region
+#
+# nop
+# nop
+#
+#
+#
+# .code 32
+# .align 2
+#_foo_arm:
+# nop
+#
+# .data_region
+# .long 10
+# .end_data_region
+#
+# .data_region jt32
+# .long 11
+# .end_data_region
+#
+# .data_region jt16
+# .long 12
+# .end_data_region
+#
+# .data_region jt8
+# .long 13
+# .end_data_region
+#
+# nop
+#
diff --git a/test/mach-o/parse-data-in-code-x86.yaml b/test/mach-o/parse-data-in-code-x86.yaml
new file mode 100644
index 000000000000..43934440f2a0
--- /dev/null
+++ b/test/mach-o/parse-data-in-code-x86.yaml
@@ -0,0 +1,77 @@
+# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t | FileCheck %s \
+# RUN: && lld -flavor darwin -arch i386 -r -print_atoms %t -o %t2 | FileCheck %s
+#
+# Test parsing LC_DATA_IN_CODE
+#
+#
+
+--- !mach-o
+arch: x86
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0x90, 0x90, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x90, 0x90, 0x90, 0x90, 0x03, 0x00,
+ 0x00, 0x00 ]
+local-symbols:
+ - name: _func1
+ type: N_SECT
+ sect: 1
+ value: 0x0000000000000000
+ - name: _func2
+ type: N_SECT
+ sect: 1
+ value: 0x000000000000000B
+dataInCode:
+ - offset: 0x00000002
+ length: 0x0008
+ kind: DICE_KIND_JUMP_TABLE32
+ - offset: 0x0000000E
+ length: 0x0004
+ kind: DICE_KIND_JUMP_TABLE32
+...
+
+
+
+# CHECK: defined-atoms:
+# CHECK: - name: _func1
+# CHECK: references:
+# CHECK: - kind: modeData
+# CHECK: offset: 2
+# CHECK: addend: 4
+# CHECK: - kind: modeCode
+# CHECK: offset: 10
+# CHECK: - name: _func2
+# CHECK: references:
+# CHECK: - kind: modeData
+# CHECK: offset: 3
+# CHECK: addend: 4
+# CHECK-NOT: - kind: modeData
+
+
+
+
+#
+#_func1:
+# nop
+# nop
+# .data_region jt32
+# .long 1
+# .long 2
+# .end_data_region
+# nop
+#
+#
+# _func2:
+# nop
+# nop
+# nop
+# .data_region jt32
+# .long 3
+# .end_data_region
+#
diff --git a/test/mach-o/parse-data-relocs-arm64.yaml b/test/mach-o/parse-data-relocs-arm64.yaml
new file mode 100644
index 000000000000..d02422f6a6f9
--- /dev/null
+++ b/test/mach-o/parse-data-relocs-arm64.yaml
@@ -0,0 +1,222 @@
+# RUN: lld -flavor darwin -arch arm64 -r -print_atoms %s -o %t | FileCheck %s
+# RUN: lld -flavor darwin -arch arm64 -r -print_atoms %t -o %t2 | FileCheck %s
+#
+# Test parsing and writing of arm64 data relocations.
+#
+# The first step tests if the supplied mach-o file is parsed into the correct
+# set of references. The second step verifies relocations can be round-tripped
+# by writing to a new .o file, then parsing that file which should result in
+# the same references.
+#
+#_test:
+
+
+--- !mach-o
+arch: arm64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __DATA
+ section: __data
+ type: S_REGULAR
+ attributes: [ ]
+ address: 0x0000000000000000
+ content: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xDC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xC0, 0xFF, 0xFF, 0xFF, 0xBE, 0xFF, 0xFF, 0xFF,
+ 0xB0, 0xFF, 0xFF, 0xFF ]
+ relocations:
+ - offset: 0x00000050
+ type: ARM64_RELOC_POINTER_TO_GOT
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 1
+ - offset: 0x0000004C
+ type: ARM64_RELOC_SUBTRACTOR
+ length: 2
+ pc-rel: false
+ extern: true
+ symbol: 1
+ - offset: 0x0000004C
+ type: ARM64_RELOC_UNSIGNED
+ length: 2
+ pc-rel: false
+ extern: true
+ symbol: 1
+ - offset: 0x00000048
+ type: ARM64_RELOC_SUBTRACTOR
+ length: 2
+ pc-rel: false
+ extern: true
+ symbol: 1
+ - offset: 0x00000048
+ type: ARM64_RELOC_UNSIGNED
+ length: 2
+ pc-rel: false
+ extern: true
+ symbol: 1
+ - offset: 0x00000040
+ type: ARM64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 1
+ - offset: 0x00000038
+ type: ARM64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: false
+ symbol: 1
+ - offset: 0x00000030
+ type: ARM64_RELOC_SUBTRACTOR
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 1
+ - offset: 0x00000030
+ type: ARM64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 1
+ - offset: 0x00000028
+ type: ARM64_RELOC_SUBTRACTOR
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 1
+ - offset: 0x00000028
+ type: ARM64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 1
+ - offset: 0x00000020
+ type: ARM64_RELOC_SUBTRACTOR
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 1
+ - offset: 0x00000020
+ type: ARM64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 1
+ - offset: 0x00000018
+ type: ARM64_RELOC_POINTER_TO_GOT
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 1
+ - offset: 0x00000010
+ type: ARM64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 1
+ - offset: 0x00000008
+ type: ARM64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 1
+local-symbols:
+ - name: _v1
+ type: N_SECT
+ sect: 1
+ value: 0x0000000000000008
+undefined-symbols:
+ - name: _foo
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+...
+
+# CHECK: defined-atoms:
+# CHECK: - ref-name: L000
+# CHECK: type: data
+# CHECK: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK: - name: _v1
+# CHECK: type: data
+# CHECK: content: [ 00, 00, 00, 00, 00, 00, 00, 00, 08, 00, 00, 00,
+# CHECK: 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
+# CHECK: 00, 00, 00, 00, 00, 00, 00, 00, E0, FF, FF, FF,
+# CHECK: FF, FF, FF, FF, DC, FF, FF, FF, FF, FF, FF, FF,
+# CHECK: 00, 00, 00, 00, 00, 00, 00, 00, 04, 00, 00, 00,
+# CHECK: 00, 00, 00, 00, C0, FF, FF, FF, BE, FF, FF, FF,
+# CHECK: B0, FF, FF, FF ]
+# CHECK: references:
+# CHECK: - kind: pointer64
+# CHECK: offset: 0
+# CHECK: target: _foo
+# CHECK-NOT: addend:
+# CHECK: - kind: pointer64
+# CHECK: offset: 8
+# CHECK: target: _foo
+# CHECK: addend: 8
+# CHECK: - kind: pointer64ToGOT
+# CHECK: offset: 16
+# CHECK: target: _foo
+# CHECK-NOT: addend:
+# CHECK: - kind: delta64
+# CHECK: offset: 24
+# CHECK: target: _foo
+# CHECK: addend: 24
+# CHECK: - kind: delta64
+# CHECK: offset: 32
+# CHECK: target: _foo
+# CHECK-NOT: addend:
+# CHECK: - kind: delta64
+# CHECK: offset: 40
+# CHECK: target: _foo
+# CHECK: addend: 4
+# CHECK: - kind: pointer64
+# CHECK: offset: 48
+# CHECK: target: L000
+# CHECK-NOT: addend:
+# CHECK: - kind: pointer64
+# CHECK: offset: 56
+# CHECK: target: _foo
+# CHECK: addend: 4
+# CHECK: - kind: delta32
+# CHECK: offset: 64
+# CHECK: target: _foo
+# CHECK-NOT: addend:
+# CHECK: - kind: delta32
+# CHECK: offset: 68
+# CHECK: target: _foo
+# CHECK: addend: 2
+# CHECK: - kind: delta32ToGOT
+# CHECK: offset: 72
+# CHECK: target: _foo
+# CHECK-NOT: addend:
+# CHECK: undefined-atoms:
+# CHECK: - name: _foo
+
+
+
+# .data
+#Lanon:
+# .quad 0
+#_v1:
+# .quad _foo
+# .quad _foo + 8
+# .quad _foo@GOT
+# .quad _foo + 24 - .
+# .quad _foo - .
+# .quad _foo + 4 - .
+# .quad Lanon
+# .quad Lanon + 4
+# .long _foo - .
+# .long _foo +2 - .
+# .long _foo@GOT - .
+
diff --git a/test/mach-o/parse-data-relocs-x86_64.yaml b/test/mach-o/parse-data-relocs-x86_64.yaml
new file mode 100644
index 000000000000..ae93c1bb75d9
--- /dev/null
+++ b/test/mach-o/parse-data-relocs-x86_64.yaml
@@ -0,0 +1,230 @@
+
+# RUN: lld -flavor darwin -arch x86_64 -r %s -o %t -print_atoms | FileCheck %s \
+# RUN: && lld -flavor darwin -arch x86_64 %t -r -print_atoms -o %t2 | FileCheck %s
+#
+# Test parsing and writing of x86_64 text relocations.
+#
+# The first step tests if the supplied mach-o file is parsed into the correct
+# set of references. The second step verifies relocations can be round-tripped
+# by writing to a new .o file, then parsing that file which should result in
+# the same references.
+#
+#_foo:
+# ret
+#
+#_bar:
+# ret
+#
+# .section __DATA,__custom
+#L1:
+# .quad 0
+#
+# .data
+#_d:
+# .quad _foo
+# .quad _foo+4
+# .quad _foo - .
+# .quad L1
+# .quad L1 + 2
+# .quad _foo - .
+# .quad _foo + 4 - .
+# .quad L1 - .
+# .long _foo - .
+# .long _foo + 4 - .
+# .long L1 - .
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID: false
+OS: unknown
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0xC3, 0xC3 ]
+ - segment: __DATA
+ section: __custom
+ type: S_REGULAR
+ attributes: [ ]
+ address: 0x0000000000000002
+ content: [ 0x00, 0x00, 0x00, 0x00 ]
+ - segment: __DATA
+ section: __data
+ type: S_REGULAR
+ attributes: [ ]
+ alignment: 3
+ address: 0x0000000000000008
+ content: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xDC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xD2, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xC8, 0xFF, 0xFF, 0xFF, 0xC8, 0xFF, 0xFF, 0xFF,
+ 0xC2, 0xFF, 0xFF, 0xFF ]
+ relocations:
+ - offset: 0x00000040
+ type: X86_64_RELOC_SUBTRACTOR
+ length: 2
+ pc-rel: false
+ extern: true
+ symbol: 2
+ - offset: 0x00000040
+ type: X86_64_RELOC_UNSIGNED
+ length: 2
+ pc-rel: false
+ extern: false
+ symbol: 2
+ - offset: 0x0000003C
+ type: X86_64_RELOC_SUBTRACTOR
+ length: 2
+ pc-rel: false
+ extern: true
+ symbol: 2
+ - offset: 0x0000003C
+ type: X86_64_RELOC_UNSIGNED
+ length: 2
+ pc-rel: false
+ extern: true
+ symbol: 0
+ - offset: 0x00000038
+ type: X86_64_RELOC_SUBTRACTOR
+ length: 2
+ pc-rel: false
+ extern: true
+ symbol: 2
+ - offset: 0x00000038
+ type: X86_64_RELOC_UNSIGNED
+ length: 2
+ pc-rel: false
+ extern: true
+ symbol: 0
+ - offset: 0x00000030
+ type: X86_64_RELOC_SUBTRACTOR
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 2
+ - offset: 0x00000030
+ type: X86_64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: false
+ symbol: 2
+ - offset: 0x00000028
+ type: X86_64_RELOC_SUBTRACTOR
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 2
+ - offset: 0x00000028
+ type: X86_64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 0
+ - offset: 0x00000020
+ type: X86_64_RELOC_SUBTRACTOR
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 2
+ - offset: 0x00000020
+ type: X86_64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 0
+ - offset: 0x00000018
+ type: X86_64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: false
+ symbol: 2
+ - offset: 0x00000010
+ type: X86_64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: false
+ symbol: 2
+ - offset: 0x00000008
+ type: X86_64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 0
+ - offset: 0x00000000
+ type: X86_64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 0
+local-symbols:
+ - name: _foo
+ type: N_SECT
+ sect: 1
+ value: 0x0000000000000000
+ - name: _bar
+ type: N_SECT
+ sect: 1
+ value: 0x0000000000000001
+ - name: _d
+ type: N_SECT
+ sect: 3
+ value: 0x0000000000000008
+...
+
+
+# CHECK: defined-atoms:
+# CHECK: - name: _d
+# CHECK: type: data
+# CHECK: references:
+# CHECK: - kind: pointer64
+# CHECK: offset: 0
+# CHECK: target: _foo
+# CHECK: - kind: pointer64
+# CHECK: offset: 8
+# CHECK: target: _foo
+# CHECK: addend: 4
+# CHECK: - kind: pointer64Anon
+# CHECK: offset: 16
+# CHECK: target: L003
+# CHECK: - kind: pointer64Anon
+# CHECK: offset: 24
+# CHECK: target: L003
+# CHECK: addend: 2
+# CHECK: - kind: delta64
+# CHECK: offset: 32
+# CHECK: target: _foo
+# CHECK: - kind: delta64
+# CHECK: offset: 40
+# CHECK: target: _foo
+# CHECK: addend: 4
+# CHECK: - kind: delta64Anon
+# CHECK: offset: 48
+# CHECK: target: L003
+# CHECK: - kind: delta32
+# CHECK: offset: 56
+# CHECK: target: _foo
+# CHECK: - kind: delta32
+# CHECK: offset: 60
+# CHECK: target: _foo
+# CHECK: addend: 4
+# CHECK: - kind: delta32Anon
+# CHECK: offset: 64
+# CHECK: target: L003
+# CHECK: - name: _foo
+# CHECK: content: [ C3 ]
+# CHECK: - name: _bar
+# CHECK: content: [ C3 ]
+# CHECK: - ref-name: L003
+# CHECK: type: unknown
+# CHECK: content: [ 00, 00, 00, 00 ]
+# CHECK: section-choice: custom-required
+# CHECK: section-name: __DATA/__custom
diff --git a/test/mach-o/parse-data.yaml b/test/mach-o/parse-data.yaml
new file mode 100644
index 000000000000..61d77290d108
--- /dev/null
+++ b/test/mach-o/parse-data.yaml
@@ -0,0 +1,119 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s
+#
+# Test parsing of mach-o data symbols.
+#
+# long a = 0x0807060504030201;
+# int b = 0x14131211;
+# int c = 0x24232221;
+# static int s1;
+# static int s2 = 0x34333231;
+#
+#
+
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID: false
+OS: unknown
+sections:
+ - segment: __DATA
+ section: __data
+ type: S_REGULAR
+ attributes: [ ]
+ alignment: 3
+ address: 0x0000000000000000
+ content: [ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x11, 0x12, 0x13, 0x14, 0x21, 0x22, 0x23, 0x24,
+ 0x31, 0x32, 0x33, 0x34, 0x41, 0x42, 0x43, 0x44 ]
+ - segment: __CUST
+ section: __custom
+ type: S_REGULAR
+ attributes: [ ]
+ alignment: 3
+ address: 0x0000000000000018
+ content: [ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 ]
+ - segment: __DATA
+ section: __bss
+ type: S_ZEROFILL
+ attributes: [ ]
+ alignment: 2
+ address: 0x0000000000000020
+ size: 4
+local-symbols:
+ - name: _s1
+ type: N_SECT
+ sect: 3
+ value: 0x0000000000000020
+ - name: _s2
+ type: N_SECT
+ sect: 1
+ value: 0x0000000000000010
+global-symbols:
+ - name: _a
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+ - name: _b
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000008
+ - name: _c
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x000000000000000C
+ - name: _cWeak
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ desc: [ N_WEAK_DEF ]
+ value: 0x0000000000000014
+ - name: _kustom
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 2
+ value: 0x0000000000000018
+...
+
+# CHECK: defined-atoms:
+
+# CHECK: - name: _a
+# CHECK: scope: global
+# CHECK: type: data
+# CHECK: content: [ 01, 02, 03, 04, 05, 06, 07, 08 ]
+
+# CHECK: - name: _b
+# CHECK: scope: global
+# CHECK: type: data
+# CHECK: content: [ 11, 12, 13, 14 ]
+
+# CHECK: - name: _c
+# CHECK: scope: global
+# CHECK: type: data
+# CHECK: content: [ 21, 22, 23, 24 ]
+
+# CHECK: - name: _s2
+# CHECK: type: data
+# CHECK: content: [ 31, 32, 33, 34 ]
+
+# CHECK: - name: _cWeak
+# CHECK: scope: global
+# CHECK: type: data
+# CHECK: content: [ 41, 42, 43, 44 ]
+# CHECK: merge: as-weak
+
+# CHECK: - name: _s1
+# CHECK: type: zero-fill
+# CHECK: size: 4
+
+# CHECK: - name: _kustom
+# CHECK: scope: global
+# CHECK: type: unknown
+# CHECK: content: [ 01, 02, 03, 04, 05, 06, 07, 08 ]
+# CHECK: section-choice: custom-required
+# CHECK: section-name: __CUST/__custom
+
diff --git a/test/mach-o/parse-eh-frame-x86-anon.yaml b/test/mach-o/parse-eh-frame-x86-anon.yaml
new file mode 100644
index 000000000000..9e3adaea1849
--- /dev/null
+++ b/test/mach-o/parse-eh-frame-x86-anon.yaml
@@ -0,0 +1,129 @@
+# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t | FileCheck %s
+#
+# Test parsing of new __eh_frame (dwarf unwind) section that has no .eh labels
+# and no relocations.
+#
+
+--- !mach-o
+arch: x86
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+OS: unknown
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0x55, 0x89, 0xE5, 0x56, 0x83, 0xEC, 0x14, 0xE8,
+ 0x00, 0x00, 0x00, 0x00, 0x5E, 0xC7, 0x04, 0x24,
+ 0x04, 0x00, 0x00, 0x00, 0xE8, 0xE7, 0xFF, 0xFF,
+ 0xFF, 0xC7, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x8B,
+ 0x8E, 0x38, 0x00, 0x00, 0x00, 0x89, 0x4C, 0x24,
+ 0x04, 0x89, 0x04, 0x24, 0xC7, 0x44, 0x24, 0x08,
+ 0x00, 0x00, 0x00, 0x00, 0xE8, 0xC7, 0xFF, 0xFF,
+ 0xFF, 0x55, 0x89, 0xE5, 0x83, 0xEC, 0x08, 0xE8,
+ 0xBC, 0xFF, 0xFF, 0xFF ]
+ relocations:
+ - offset: 0x00000040
+ type: GENERIC_RELOC_VANILLA
+ length: 2
+ pc-rel: true
+ extern: false
+ symbol: 1
+ - offset: 0x00000035
+ type: GENERIC_RELOC_VANILLA
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 4
+ - offset: 0x00000021
+ scattered: true
+ type: GENERIC_RELOC_LOCAL_SECTDIFF
+ length: 2
+ pc-rel: false
+ value: 0x00000044
+ - offset: 0x00000000
+ scattered: true
+ type: GENERIC_RELOC_PAIR
+ length: 2
+ pc-rel: false
+ value: 0x0000000C
+ - offset: 0x00000015
+ type: GENERIC_RELOC_VANILLA
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 3
+ - segment: __IMPORT
+ section: __pointers
+ type: S_NON_LAZY_SYMBOL_POINTERS
+ attributes: [ ]
+ address: 0x0000000000000044
+ content: [ 0x00, 0x00, 0x00, 0x00 ]
+ indirect-syms: [ 5 ]
+ - segment: __TEXT
+ section: __eh_frame
+ type: S_REGULAR
+ attributes: [ ]
+ alignment: 2
+ address: 0x0000000000000048
+ content: [ 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x7A, 0x52, 0x00, 0x01, 0x7C, 0x08, 0x01,
+ 0x10, 0x0C, 0x05, 0x04, 0x88, 0x01, 0x00, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
+ 0x98, 0xFF, 0xFF, 0xFF, 0x39, 0x00, 0x00, 0x00,
+ 0x00, 0x41, 0x0E, 0x08, 0x84, 0x02, 0x42, 0x0D,
+ 0x04, 0x44, 0x86, 0x03, 0x18, 0x00, 0x00, 0x00,
+ 0x38, 0x00, 0x00, 0x00, 0xB5, 0xFF, 0xFF, 0xFF,
+ 0x0B, 0x00, 0x00, 0x00, 0x00, 0x41, 0x0E, 0x08,
+ 0x84, 0x02, 0x42, 0x0D, 0x04, 0x00, 0x00, 0x00 ]
+global-symbols:
+ - name: __Z3barv
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000039
+ - name: __Z3foov
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+undefined-symbols:
+ - name: __ZTIi
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+ - name: ___cxa_allocate_exception
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+ - name: ___cxa_throw
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+...
+
+# CHECK: defined-atoms:
+# CHECK: - ref-name: [[CIE:L[L0-9]+]]
+# CHECK: type: unwind-cfi
+# CHECK: content:
+# CHECK: - type: unwind-cfi
+# CHECK: content:
+# CHECK: references:
+# CHECK: - kind: negDelta32
+# CHECK: offset: 4
+# CHECK: target: [[CIE]]
+# CHECK: - kind: delta32
+# CHECK: offset: 8
+# CHECK: target: __Z3foov
+# CHECK: - type: unwind-cfi
+# CHECK: content:
+# CHECK: references:
+# CHECK: - kind: negDelta32
+# CHECK: offset: 4
+# CHECK: target: [[CIE]]
+# CHECK: - kind: delta32
+# CHECK: offset: 8
+# CHECK: target: __Z3barv
+
diff --git a/test/mach-o/parse-eh-frame-x86-labeled.yaml b/test/mach-o/parse-eh-frame-x86-labeled.yaml
new file mode 100644
index 000000000000..b07a534e6493
--- /dev/null
+++ b/test/mach-o/parse-eh-frame-x86-labeled.yaml
@@ -0,0 +1,193 @@
+# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t | FileCheck %s
+#
+# Test parsing of old __eh_frame (dwarf unwind) section that has .eh labels
+# and relocations.
+#
+
+--- !mach-o
+arch: x86
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+OS: unknown
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0x55, 0x89, 0xE5, 0x56, 0x83, 0xEC, 0x14, 0xE8,
+ 0x00, 0x00, 0x00, 0x00, 0x5E, 0xC7, 0x04, 0x24,
+ 0x04, 0x00, 0x00, 0x00, 0xE8, 0xE7, 0xFF, 0xFF,
+ 0xFF, 0xC7, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x8B,
+ 0x8E, 0x38, 0x00, 0x00, 0x00, 0x89, 0x4C, 0x24,
+ 0x04, 0x89, 0x04, 0x24, 0xC7, 0x44, 0x24, 0x08,
+ 0x00, 0x00, 0x00, 0x00, 0xE8, 0xC7, 0xFF, 0xFF,
+ 0xFF, 0x55, 0x89, 0xE5, 0x83, 0xEC, 0x08, 0xE8,
+ 0xBC, 0xFF, 0xFF, 0xFF ]
+ relocations:
+ - offset: 0x00000040
+ type: GENERIC_RELOC_VANILLA
+ length: 2
+ pc-rel: true
+ extern: false
+ symbol: 1
+ - offset: 0x00000035
+ type: GENERIC_RELOC_VANILLA
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 7
+ - offset: 0x00000021
+ scattered: true
+ type: GENERIC_RELOC_LOCAL_SECTDIFF
+ length: 2
+ pc-rel: false
+ value: 0x00000044
+ - offset: 0x00000000
+ scattered: true
+ type: GENERIC_RELOC_PAIR
+ length: 2
+ pc-rel: false
+ value: 0x0000000C
+ - offset: 0x00000015
+ type: GENERIC_RELOC_VANILLA
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 6
+ - segment: __IMPORT
+ section: __pointers
+ type: S_NON_LAZY_SYMBOL_POINTERS
+ attributes: [ ]
+ address: 0x0000000000000044
+ content: [ 0x00, 0x00, 0x00, 0x00 ]
+ indirect-syms: [ 5 ]
+ - segment: __TEXT
+ section: __eh_frame
+ type: S_REGULAR
+ attributes: [ ]
+ alignment: 2
+ address: 0x0000000000000048
+ content: [ 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x7A, 0x52, 0x00, 0x01, 0x7C, 0x08, 0x01,
+ 0x10, 0x0C, 0x05, 0x04, 0x88, 0x01, 0x00, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
+ 0x98, 0xFF, 0xFF, 0xFF, 0x39, 0x00, 0x00, 0x00,
+ 0x00, 0x41, 0x0E, 0x08, 0x84, 0x02, 0x42, 0x0D,
+ 0x04, 0x44, 0x86, 0x03, 0x18, 0x00, 0x00, 0x00,
+ 0x38, 0x00, 0x00, 0x00, 0xB5, 0xFF, 0xFF, 0xFF,
+ 0x0B, 0x00, 0x00, 0x00, 0x00, 0x41, 0x0E, 0x08,
+ 0x84, 0x02, 0x42, 0x0D, 0x04, 0x00, 0x00, 0x00 ]
+ relocations:
+ - offset: 0x0000001C
+ scattered: true
+ type: GENERIC_RELOC_LOCAL_SECTDIFF
+ length: 2
+ pc-rel: false
+ value: 0x00000064
+ - offset: 0x00000000
+ scattered: true
+ type: GENERIC_RELOC_PAIR
+ length: 2
+ pc-rel: false
+ value: 0x00000048
+ - offset: 0x00000020
+ scattered: true
+ type: GENERIC_RELOC_SECTDIFF
+ length: 2
+ pc-rel: false
+ value: 0x00000000
+ - offset: 0x00000000
+ scattered: true
+ type: GENERIC_RELOC_PAIR
+ length: 2
+ pc-rel: false
+ value: 0x00000068
+ - offset: 0x00000038
+ scattered: true
+ type: GENERIC_RELOC_LOCAL_SECTDIFF
+ length: 2
+ pc-rel: false
+ value: 0x00000080
+ - offset: 0x00000000
+ scattered: true
+ type: GENERIC_RELOC_PAIR
+ length: 2
+ pc-rel: false
+ value: 0x00000048
+ - offset: 0x0000003C
+ scattered: true
+ type: GENERIC_RELOC_SECTDIFF
+ length: 2
+ pc-rel: false
+ value: 0x00000039
+ - offset: 0x00000000
+ scattered: true
+ type: GENERIC_RELOC_PAIR
+ length: 2
+ pc-rel: false
+ value: 0x00000084
+local-symbols:
+ - name: EH_frame0
+ type: N_SECT
+ sect: 3
+ value: 0x0000000000000048
+global-symbols:
+ - name: __Z3barv
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000039
+ - name: __Z3barv.eh
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 3
+ value: 0x000000000000007C
+ - name: __Z3foov
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+ - name: __Z3foov.eh
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 3
+ value: 0x0000000000000060
+undefined-symbols:
+ - name: __ZTIi
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+ - name: ___cxa_allocate_exception
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+ - name: ___cxa_throw
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+...
+
+# CHECK: defined-atoms:
+# CHECK: - ref-name: [[CIE:L[L0-9]+]]
+# CHECK: type: unwind-cfi
+# CHECK: content:
+# CHECK: - type: unwind-cfi
+# CHECK: content:
+# CHECK: references:
+# CHECK: - kind: negDelta32
+# CHECK: offset: 4
+# CHECK: target: [[CIE]]
+# CHECK: - kind: delta32
+# CHECK: offset: 8
+# CHECK: target: __Z3foov
+# CHECK: - type: unwind-cfi
+# CHECK: content:
+# CHECK: references:
+# CHECK: - kind: negDelta32
+# CHECK: offset: 4
+# CHECK: target: [[CIE]]
+# CHECK: - kind: delta32
+# CHECK: offset: 8
+# CHECK: target: __Z3barv
+
diff --git a/test/mach-o/parse-eh-frame.yaml b/test/mach-o/parse-eh-frame.yaml
new file mode 100644
index 000000000000..69324800e991
--- /dev/null
+++ b/test/mach-o/parse-eh-frame.yaml
@@ -0,0 +1,88 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s
+#
+# Test parsing of __eh_frame (dwarf unwind) section.
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID: false
+OS: unknown
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0x55, 0x48, 0x89, 0xE5, 0xB8, 0x09, 0x00, 0x00,
+ 0x00, 0x5D, 0xC3, 0x55, 0x48, 0x89, 0xE5, 0xB8,
+ 0x0A, 0x00, 0x00, 0x00, 0x5D, 0xC3 ]
+ - segment: __TEXT
+ section: __eh_frame
+ type: S_COALESCED
+ attributes: [ ]
+ alignment: 3
+ address: 0x0000000000000058
+ content: [ 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x7A, 0x52, 0x00, 0x01, 0x78, 0x10, 0x01,
+ 0x10, 0x0C, 0x07, 0x08, 0x90, 0x01, 0x00, 0x00,
+ 0x24, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
+ 0x88, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x41, 0x0E, 0x10, 0x86, 0x02, 0x43, 0x0D,
+ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x24, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00,
+ 0x6B, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x41, 0x0E, 0x10, 0x86, 0x02, 0x43, 0x0D,
+ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+global-symbols:
+ - name: __Z3barv
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+ - name: __Z3foov
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x000000000000000B
+...
+
+# CHECK: defined-atoms:
+# CHECK: - ref-name: [[CIE:L[0-9]+]]
+# CHECK: type: unwind-cfi
+# CHECK: content: [ 14, 00, 00, 00, 00, 00, 00, 00, 01, 7A, 52, 00,
+# CHECK: 01, 78, 10, 01, 10, 0C, 07, 08, 90, 01, 00, 00 ]
+# CHECK: - type: unwind-cfi
+# CHECK: content: [ 24, 00, 00, 00, 1C, 00, 00, 00, 88, FF, FF, FF,
+# CHECK: FF, FF, FF, FF, 0B, 00, 00, 00, 00, 00, 00, 00,
+# CHECK: 00, 41, 0E, 10, 86, 02, 43, 0D, 06, 00, 00, 00,
+# CHECK: 00, 00, 00, 00 ]
+# CHECK: references:
+# CHECK: - kind: negDelta32
+# CHECK: offset: 4
+# CHECK: target: [[CIE]]
+# CHECK: - kind: unwindFDEToFunction
+# CHECK: offset: 8
+# CHECK: target: __Z3barv
+# CHECK: - type: unwind-cfi
+# CHECK: content: [ 24, 00, 00, 00, 44, 00, 00, 00, 6B, FF, FF, FF,
+# CHECK: FF, FF, FF, FF, 0B, 00, 00, 00, 00, 00, 00, 00,
+# CHECK: 00, 41, 0E, 10, 86, 02, 43, 0D, 06, 00, 00, 00,
+# CHECK: 00, 00, 00, 00 ]
+# CHECK: references:
+# CHECK: - kind: negDelta32
+# CHECK: offset: 4
+# CHECK: target: [[CIE]]
+# CHECK: - kind: unwindFDEToFunction
+# CHECK: offset: 8
+# CHECK: target: __Z3foov
+# CHECK: - name: __Z3barv
+# CHECK: scope: global
+# CHECK: content: [ 55, 48, 89, E5, B8, 09, 00, 00, 00, 5D, C3 ]
+# CHECK: - name: __Z3foov
+# CHECK: scope: global
+# CHECK: content: [ 55, 48, 89, E5, B8, 0A, 00, 00, 00, 5D, C3 ]
+
diff --git a/test/mach-o/parse-function.yaml b/test/mach-o/parse-function.yaml
new file mode 100644
index 000000000000..1bc9878c7087
--- /dev/null
+++ b/test/mach-o/parse-function.yaml
@@ -0,0 +1,100 @@
+# RUN: lld -flavor darwin -arch x86_64 -r %s -o %t
+# RUN: lld -flavor darwin -arch x86_64 -r %t -print_atoms -o %t2 | FileCheck %s
+#
+# Test parsing of mach-o functions.
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID: false
+OS: unknown
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ alignment: 4
+ address: 0x0000000000000000
+ content: [ 0xCC, 0xC3, 0x90, 0xC3, 0x90, 0x90, 0xC3, 0x90,
+ 0x90, 0x90, 0xC3, 0x90, 0x90, 0x90, 0x90, 0xC3,
+ 0xCC, 0x31, 0xC0, 0xC3 ]
+local-symbols:
+ - name: _myStatic
+ type: N_SECT
+ sect: 1
+ value: 0x000000000000000B
+global-symbols:
+ - name: _myGlobal
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000001
+ - name: _myGlobalWeak
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ desc: [ N_WEAK_DEF ]
+ value: 0x0000000000000002
+ - name: _myHidden
+ type: N_SECT
+ scope: [ N_EXT, N_PEXT ]
+ sect: 1
+ value: 0x0000000000000004
+ - name: _myHiddenWeak
+ type: N_SECT
+ scope: [ N_EXT, N_PEXT ]
+ sect: 1
+ desc: [ N_WEAK_DEF ]
+ value: 0x0000000000000007
+ - name: _myStripNot
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ desc: [ N_NO_DEAD_STRIP ]
+ value: 0x0000000000000010
+ - name: _myResolver
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ desc: [ N_SYMBOL_RESOLVER ]
+ value: 0x0000000000000011
+...
+
+# CHECK-NOT: name:
+# CHECK: content: [ CC ]
+
+# CHECK: name: _myGlobal
+# CHECK: scope: global
+# CHECK: content: [ C3 ]
+
+# CHECK: name: _myGlobalWeak
+# CHECK: scope: global
+# CHECK: content: [ 90, C3 ]
+# CHECK: merge: as-weak
+
+# CHECK: name: _myHidden
+# CHECK: scope: hidden
+# CHECK: content: [ 90, 90, C3 ]
+
+# CHECK: name: _myHiddenWeak
+# CHECK: scope: hidden
+# CHECK: content: [ 90, 90, 90, C3 ]
+# CHECK: merge: as-weak
+
+# CHECK: name: _myStatic
+# CHECK-NOT: scope: global
+# CHECK-NOT: scope: hidden
+# CHECK: content: [ 90, 90, 90, 90, C3 ]
+
+# CHECK: name: _myStripNot
+# CHECK: scope: global
+# CHECK: content: [ CC ]
+# CHECK: dead-strip: never
+
+# CHECK: name: _myResolver
+# CHECK: scope: global
+# CHECK: type: resolver
+# CHECK: content: [ 31, C0, C3 ]
+
diff --git a/test/mach-o/parse-initializers32.yaml b/test/mach-o/parse-initializers32.yaml
new file mode 100644
index 000000000000..ede7b90e2cb9
--- /dev/null
+++ b/test/mach-o/parse-initializers32.yaml
@@ -0,0 +1,84 @@
+# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t | FileCheck %s
+#
+# Test parsing of literal sections.
+#
+
+--- !mach-o
+arch: x86
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID: false
+OS: unknown
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0x55, 0x89, 0xE5, 0x5D, 0xC3, 0x55, 0x89, 0xE5,
+ 0x5D, 0xC3, 0x55, 0x89, 0xE5, 0x5D, 0xC3 ]
+ - segment: __DATA
+ section: __mod_init_func
+ type: S_MOD_INIT_FUNC_POINTERS
+ attributes: [ ]
+ alignment: 2
+ address: 0x0000000000000044
+ content: [ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00 ]
+ relocations:
+ - offset: 0x00000000
+ type: GENERIC_RELOC_VANILLA
+ length: 2
+ pc-rel: false
+ extern: false
+ symbol: 1
+ - offset: 0x00000004
+ type: GENERIC_RELOC_VANILLA
+ length: 2
+ pc-rel: false
+ extern: false
+ symbol: 1
+ - segment: __DATA
+ section: __mod_term_func
+ type: S_MOD_TERM_FUNC_POINTERS
+ attributes: [ ]
+ alignment: 2
+ address: 0x0000000000000104
+ content: [ 0x0A, 0x00, 0x00, 0x00 ]
+global-symbols:
+ - name: _init
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+ - name: _init2
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000005
+ - name: _term
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x000000000000000A
+...
+
+
+# CHECK:defined-atoms:
+# CHECK: - type: initializer-pointer
+# CHECK: content: [ 00, 00, 00, 00 ]
+# CHECK: dead-strip: never
+# CHECK: - type: initializer-pointer
+# CHECK: content: [ 05, 00, 00, 00 ]
+# CHECK: dead-strip: never
+# CHECK: - type: terminator-pointer
+# CHECK: content: [ 0A, 00, 00, 00 ]
+# CHECK: dead-strip: never
+# CHECK: - name: _init
+# CHECK: scope: global
+# CHECK: content: [ 55, 89, E5, 5D, C3 ]
+# CHECK: - name: _init2
+# CHECK: scope: global
+# CHECK: content: [ 55, 89, E5, 5D, C3 ]
+# CHECK: - name: _term
+# CHECK: scope: global
+# CHECK: content: [ 55, 89, E5, 5D, C3 ]
diff --git a/test/mach-o/parse-initializers64.yaml b/test/mach-o/parse-initializers64.yaml
new file mode 100644
index 000000000000..5ebd8dafd7ce
--- /dev/null
+++ b/test/mach-o/parse-initializers64.yaml
@@ -0,0 +1,105 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s
+#
+# Test parsing of literal sections.
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID: false
+OS: unknown
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0x55, 0x48, 0x89, 0xE5, 0x5D, 0xC3, 0x55, 0x48,
+ 0x89, 0xE5, 0x5D, 0xC3, 0x55, 0x48, 0x89, 0xE5,
+ 0x5D, 0xC3 ]
+ - segment: __DATA
+ section: __mod_init_func
+ type: S_MOD_INIT_FUNC_POINTERS
+ attributes: [ ]
+ alignment: 0
+ address: 0x0000000000000100
+ content: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+ relocations:
+ - offset: 0x00000000
+ type: X86_64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 0
+ - offset: 0x00000008
+ type: X86_64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 1
+ - segment: __DATA
+ section: __mod_term_func
+ type: S_MOD_TERM_FUNC_POINTERS
+ attributes: [ ]
+ alignment: 3
+ address: 0x0000000000000108
+ content: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+ relocations:
+ - offset: 0x00000000
+ type: X86_64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 2
+global-symbols:
+ - name: _init
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+ - name: _init2
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000006
+ - name: _term
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x000000000000000C
+...
+
+
+# CHECK:defined-atoms:
+# CHECK: - type: initializer-pointer
+# CHECK: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK: dead-strip: never
+# CHECK: references:
+# CHECK: - kind: pointer64
+# CHECK: offset: 0
+# CHECK: target: _init
+# CHECK: - type: initializer-pointer
+# CHECK: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK: dead-strip: never
+# CHECK: references:
+# CHECK: - kind: pointer64
+# CHECK: offset: 0
+# CHECK: target: _init2
+# CHECK: - type: terminator-pointer
+# CHECK: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK: dead-strip: never
+# CHECK: references:
+# CHECK: - kind: pointer64
+# CHECK: offset: 0
+# CHECK: target: _term
+# CHECK: - name: _init
+# CHECK: scope: global
+# CHECK: content: [ 55, 48, 89, E5, 5D, C3 ]
+# CHECK: - name: _init2
+# CHECK: scope: global
+# CHECK: content: [ 55, 48, 89, E5, 5D, C3 ]
+# CHECK: - name: _term
+# CHECK: scope: global
+# CHECK: content: [ 55, 48, 89, E5, 5D, C3 ]
diff --git a/test/mach-o/parse-literals-error.yaml b/test/mach-o/parse-literals-error.yaml
new file mode 100644
index 000000000000..be21d6efffa3
--- /dev/null
+++ b/test/mach-o/parse-literals-error.yaml
@@ -0,0 +1,25 @@
+# RUN: not lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t 2> %t.err
+# RUN: FileCheck %s < %t.err
+#
+# Test for error if literal section is not correct size mulitple.
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID: false
+OS: unknown
+sections:
+ - segment: __TEXT
+ section: __literal8
+ type: S_8BYTE_LITERALS
+ attributes: [ ]
+ alignment: 0
+ address: 0x0000000000000120
+ content: [ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D ]
+...
+
+# CHECK: error:
+
diff --git a/test/mach-o/parse-literals.yaml b/test/mach-o/parse-literals.yaml
new file mode 100644
index 000000000000..24568ea0fd4f
--- /dev/null
+++ b/test/mach-o/parse-literals.yaml
@@ -0,0 +1,93 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s
+#
+# Test parsing of literal sections.
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID: false
+OS: unknown
+sections:
+ - segment: __TEXT
+ section: __cstring
+ type: S_CSTRING_LITERALS
+ attributes: [ ]
+ alignment: 0
+ address: 0x0000000000000100
+ content: [ 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x00, 0x74, 0x68,
+ 0x65, 0x72, 0x65, 0x00, 0x77, 0x6F, 0x72, 0x6C,
+ 0x00 ]
+ - segment: __TEXT
+ section: __literal4
+ type: S_4BYTE_LITERALS
+ attributes: [ ]
+ alignment: 0
+ address: 0x0000000000000114
+ content: [ 0x01, 0x02, 0x03, 0x04, 0x11, 0x12, 0x13, 0x14,
+ 0x28, 0x29, 0x2A, 0x2B ]
+ - segment: __TEXT
+ section: __literal8
+ type: S_8BYTE_LITERALS
+ attributes: [ ]
+ alignment: 0
+ address: 0x0000000000000120
+ content: [ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F ]
+ - segment: __TEXT
+ section: __literal16
+ type: S_16BYTE_LITERALS
+ attributes: [ ]
+ alignment: 0
+ address: 0x0000000000000130
+ content: [ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00 ]
+ - segment: __TEXT
+ section: __ustring
+ type: S_REGULAR
+ attributes: [ ]
+ alignment: 0
+ address: 0x0000000000000100
+ content: [ 0x68, 0x00, 0x65, 0x00, 0x6C, 0x00, 0x6C, 0x00,
+ 0x6F, 0x00, 0x00, 0x00, 0x74, 0x00, 0x68, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x00, 0x00 ]
+...
+
+
+# CHECK:defined-atoms:
+# CHECK: - scope: hidden
+# CHECK: type: c-string
+# CHECK: content: [ 68, 65, 6C, 6C, 6F, 00 ]
+# CHECK: - scope: hidden
+# CHECK: type: c-string
+# CHECK: content: [ 74, 68, 65, 72, 65, 00 ]
+# CHECK: - scope: hidden
+# CHECK: type: c-string
+# CHECK: content: [ 77, 6F, 72, 6C, 00 ]
+# CHECK: - scope: hidden
+# CHECK: type: utf16-string
+# CHECK: content: [ 68, 00, 65, 00, 6C, 00, 6C, 00, 6F, 00, 00, 00 ]
+# CHECK: - scope: hidden
+# CHECK: type: utf16-string
+# CHECK: content: [ 74, 00, 68, 00, 65, 00, 72, 00, 00, 00 ]
+# CHECK: - scope: hidden
+# CHECK: type: const-4-byte
+# CHECK: content: [ 01, 02, 03, 04 ]
+# CHECK: - scope: hidden
+# CHECK: type: const-4-byte
+# CHECK: content: [ 11, 12, 13, 14 ]
+# CHECK: - scope: hidden
+# CHECK: type: const-4-byte
+# CHECK: content: [ 28, 29, 2A, 2B ]
+# CHECK: - scope: hidden
+# CHECK: type: const-8-byte
+# CHECK: content: [ 01, 02, 03, 04, 05, 06, 07, 08 ]
+# CHECK: - scope: hidden
+# CHECK: type: const-8-byte
+# CHECK: content: [ 28, 29, 2A, 2B, 2C, 2D, 2E, 2F ]
+# CHECK: - scope: hidden
+# CHECK: type: const-16-byte
+# CHECK: content: [ 01, 02, 03, 04, 05, 06, 07, 08, 09, 0A, 0B, 0C,
+# CHECK: 0D, 0E, 0F, 00 ]
+
diff --git a/test/mach-o/parse-non-lazy-pointers.yaml b/test/mach-o/parse-non-lazy-pointers.yaml
new file mode 100644
index 000000000000..0b0ec5cf36ef
--- /dev/null
+++ b/test/mach-o/parse-non-lazy-pointers.yaml
@@ -0,0 +1,98 @@
+# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t | FileCheck %s
+#
+# Test parsing of non-lazy-pointer sections.
+#
+
+--- !mach-o
+arch: x86
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID: false
+OS: unknown
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0x55, 0x89, 0xE5, 0xE8, 0x00, 0x00, 0x00, 0x00,
+ 0x59, 0x8D, 0x81, 0x14, 0x00, 0x00, 0x00, 0x8D,
+ 0x81, 0x18, 0x00, 0x00, 0x00, 0x5D, 0xC3, 0x55,
+ 0x89, 0xE5, 0x5D, 0xC3 ]
+ relocations:
+ - offset: 0x00000011
+ scattered: true
+ type: GENERIC_RELOC_LOCAL_SECTDIFF
+ length: 2
+ pc-rel: false
+ value: 0x00000020
+ - offset: 0x00000000
+ scattered: true
+ type: GENERIC_RELOC_PAIR
+ length: 2
+ pc-rel: false
+ value: 0x00000008
+ - offset: 0x0000000B
+ scattered: true
+ type: GENERIC_RELOC_LOCAL_SECTDIFF
+ length: 2
+ pc-rel: false
+ value: 0x0000001C
+ - offset: 0x00000000
+ scattered: true
+ type: GENERIC_RELOC_PAIR
+ length: 2
+ pc-rel: false
+ value: 0x00000008
+ - segment: __IMPORT
+ section: __pointers
+ type: S_NON_LAZY_SYMBOL_POINTERS
+ attributes: [ ]
+ address: 0x000000000000001C
+ content: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+ indirect-syms: [ 2, 2147483648 ]
+local-symbols:
+ - name: _foo
+ type: N_SECT
+ sect: 1
+ value: 0x0000000000000017
+global-symbols:
+ - name: _get
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+undefined-symbols:
+ - name: _bar
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+...
+
+
+# CHECK:defined-atoms:
+# CHECK: - ref-name: [[GOT1:L[L0-9]+]]
+# CHECK: scope: hidden
+# CHECK: type: got
+# CHECK: content: [ 00, 00, 00, 00 ]
+# CHECK: merge: by-content
+# CHECK: - ref-name: [[GOT2:L[L0-9]+]]
+# CHECK: scope: hidden
+# CHECK: type: got
+# CHECK: content: [ 00, 00, 00, 00 ]
+# CHECK: merge: by-content
+# CHECK: - name: _get
+# CHECK: scope: global
+# CHECK: content: [ 55, 89, E5, E8, 00, 00, 00, 00, 59, 8D, 81, 14,
+# CHECK: 00, 00, 00, 8D, 81, 18, 00, 00, 00, 5D, C3 ]
+# CHECK: references:
+# CHECK: - kind: funcRel32
+# CHECK: offset: 11
+# CHECK: target: [[GOT1]]
+# CHECK: - kind: funcRel32
+# CHECK: offset: 17
+# CHECK: target: [[GOT2]]
+# CHECK: - name: _foo
+# CHECK: content: [ 55, 89, E5, 5D, C3 ]
+
+
diff --git a/test/mach-o/parse-relocs-x86.yaml b/test/mach-o/parse-relocs-x86.yaml
new file mode 100644
index 000000000000..3fc22ae71bfc
--- /dev/null
+++ b/test/mach-o/parse-relocs-x86.yaml
@@ -0,0 +1,296 @@
+# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t | FileCheck %s \
+# RUN: && lld -flavor darwin -arch i386 -r -print_atoms %t -o %t2 | FileCheck %s
+#
+# Test parsing and writing of x86 relocations.
+#
+# The first step tests if the supplied mach-o file is parsed into the correct
+# set of references. The second step verifies relocations can be round-tripped
+# by writing to a new .o file, then parsing that file which should result in
+# the same references.
+#
+# .text
+#_test:
+# call _undef
+# call _undef+2
+# call _foo
+# call _foo+2
+# callw _undef
+# callw _foo
+# callw _foo+2
+#L1:
+# movl _undef, %eax
+# movl _x, %eax
+# movl _x+4, %eax
+# movl _x-L1(%eax), %eax
+# movl _x+4-L1(%eax), %eax
+#
+#_foo:
+# ret
+#
+# .data
+#_x:
+# .long _undef
+# .long _undef+7
+# .long _foo
+# .long _foo+3
+# .long _test - .
+# .long _test+3 - .
+#
+
+--- !mach-o
+arch: x86
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+OS: unknown
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0xE8, 0xFB, 0xFF, 0xFF, 0xFF, 0xE8, 0xF8, 0xFF,
+ 0xFF, 0xFF, 0xE8, 0x2C, 0x00, 0x00, 0x00, 0xE8,
+ 0x29, 0x00, 0x00, 0x00, 0x66, 0xE8, 0xE8, 0xFF,
+ 0x66, 0xE8, 0x1F, 0x00, 0x66, 0xE8, 0x1D, 0x00,
+ 0xA1, 0x00, 0x00, 0x00, 0x00, 0xA1, 0x3C, 0x00,
+ 0x00, 0x00, 0xA1, 0x40, 0x00, 0x00, 0x00, 0x8B,
+ 0x80, 0x1C, 0x00, 0x00, 0x00, 0x8B, 0x80, 0x20,
+ 0x00, 0x00, 0x00, 0xC3 ]
+ relocations:
+ - offset: 0x00000037
+ scattered: true
+ type: GENERIC_RELOC_LOCAL_SECTDIFF
+ length: 2
+ pc-rel: false
+ value: 0x0000003C
+ - offset: 0x00000000
+ scattered: true
+ type: GENERIC_RELOC_PAIR
+ length: 2
+ pc-rel: false
+ value: 0x00000020
+ - offset: 0x00000031
+ scattered: true
+ type: GENERIC_RELOC_LOCAL_SECTDIFF
+ length: 2
+ pc-rel: false
+ value: 0x0000003C
+ - offset: 0x00000000
+ scattered: true
+ type: GENERIC_RELOC_PAIR
+ length: 2
+ pc-rel: false
+ value: 0x00000020
+ - offset: 0x0000002B
+ scattered: true
+ type: GENERIC_RELOC_VANILLA
+ length: 2
+ pc-rel: false
+ value: 0x0000003C
+ - offset: 0x00000026
+ type: GENERIC_RELOC_VANILLA
+ length: 2
+ pc-rel: false
+ extern: false
+ symbol: 2
+ - offset: 0x00000021
+ type: GENERIC_RELOC_VANILLA
+ length: 2
+ pc-rel: false
+ extern: true
+ symbol: 3
+ - offset: 0x0000001E
+ scattered: true
+ type: GENERIC_RELOC_VANILLA
+ length: 1
+ pc-rel: true
+ value: 0x0000003B
+ - offset: 0x0000001A
+ type: GENERIC_RELOC_VANILLA
+ length: 1
+ pc-rel: true
+ extern: false
+ symbol: 1
+ - offset: 0x00000016
+ type: GENERIC_RELOC_VANILLA
+ length: 1
+ pc-rel: true
+ extern: true
+ symbol: 3
+ - offset: 0x00000010
+ scattered: true
+ type: GENERIC_RELOC_VANILLA
+ length: 2
+ pc-rel: true
+ value: 0x0000003B
+ - offset: 0x0000000B
+ type: GENERIC_RELOC_VANILLA
+ length: 2
+ pc-rel: true
+ extern: false
+ symbol: 1
+ - offset: 0x00000006
+ type: GENERIC_RELOC_VANILLA
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 3
+ - offset: 0x00000001
+ type: GENERIC_RELOC_VANILLA
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 3
+ - segment: __DATA
+ section: __data
+ type: S_REGULAR
+ attributes: [ ]
+ address: 0x000000000000003C
+ content: [ 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x3B, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00,
+ 0xB4, 0xFF, 0xFF, 0xFF, 0xB3, 0xFF, 0xFF, 0xFF ]
+ relocations:
+ - offset: 0x00000014
+ scattered: true
+ type: GENERIC_RELOC_LOCAL_SECTDIFF
+ length: 2
+ pc-rel: false
+ value: 0x00000000
+ - offset: 0x00000000
+ scattered: true
+ type: GENERIC_RELOC_PAIR
+ length: 2
+ pc-rel: false
+ value: 0x00000050
+ - offset: 0x00000010
+ scattered: true
+ type: GENERIC_RELOC_LOCAL_SECTDIFF
+ length: 2
+ pc-rel: false
+ value: 0x00000000
+ - offset: 0x00000000
+ scattered: true
+ type: GENERIC_RELOC_PAIR
+ length: 2
+ pc-rel: false
+ value: 0x0000004C
+ - offset: 0x0000000C
+ scattered: true
+ type: GENERIC_RELOC_VANILLA
+ length: 2
+ pc-rel: false
+ value: 0x0000003B
+ - offset: 0x00000008
+ type: GENERIC_RELOC_VANILLA
+ length: 2
+ pc-rel: false
+ extern: false
+ symbol: 1
+ - offset: 0x00000004
+ type: GENERIC_RELOC_VANILLA
+ length: 2
+ pc-rel: false
+ extern: true
+ symbol: 3
+ - offset: 0x00000000
+ type: GENERIC_RELOC_VANILLA
+ length: 2
+ pc-rel: false
+ extern: true
+ symbol: 3
+local-symbols:
+ - name: _test
+ type: N_SECT
+ sect: 1
+ value: 0x0000000000000000
+ - name: _foo
+ type: N_SECT
+ sect: 1
+ value: 0x000000000000003B
+ - name: _x
+ type: N_SECT
+ sect: 2
+ value: 0x000000000000003C
+undefined-symbols:
+ - name: _undef
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+...
+
+# CHECK: defined-atoms:
+# CHECK: - name: _x
+# CHECK: type: data
+# CHECK: references:
+# CHECK: - kind: pointer32
+# CHECK: offset: 0
+# CHECK: target: _undef
+# CHECK-NOT: addend:
+# CHECK: - kind: pointer32
+# CHECK: offset: 4
+# CHECK: target: _undef
+# CHECK: addend: 7
+# CHECK: - kind: pointer32
+# CHECK: offset: 8
+# CHECK: target: _foo
+# CHECK-NOT: addend:
+# CHECK: - kind: pointer32
+# CHECK: offset: 12
+# CHECK: target: _foo
+# CHECK: addend: 3
+# CHECK: - kind: delta32
+# CHECK: offset: 16
+# CHECK: target: _test
+# CHECK: - kind: delta32
+# CHECK: offset: 20
+# CHECK: target: _test
+# CHECK: addend: 3
+# CHECK: - name: _test
+# CHECK: references:
+# CHECK: - kind: branch32
+# CHECK: offset: 1
+# CHECK: target: _undef
+# CHECK-NOT: addend:
+# CHECK: - kind: branch32
+# CHECK: offset: 6
+# CHECK: target: _undef
+# CHECK: addend: 2
+# CHECK: - kind: branch32
+# CHECK: offset: 11
+# CHECK: target: _foo
+# CHECK-NOT: addend:
+# CHECK: - kind: branch32
+# CHECK: offset: 16
+# CHECK: target: _foo
+# CHECK: addend: 2
+# CHECK: - kind: branch16
+# CHECK: offset: 22
+# CHECK: target: _undef
+# CHECK-NOT: addend:
+# CHECK: - kind: branch16
+# CHECK: offset: 26
+# CHECK: target: _foo
+# CHECK-NOT: addend:
+# CHECK: - kind: branch16
+# CHECK: offset: 30
+# CHECK: target: _foo
+# CHECK: addend: 2
+# CHECK: - kind: abs32
+# CHECK: offset: 33
+# CHECK: target: _undef
+# CHECK: - kind: abs32
+# CHECK: offset: 38
+# CHECK: target: _x
+# CHECK: - kind: abs32
+# CHECK: offset: 43
+# CHECK: target: _x
+# CHECK: addend: 4
+# CHECK: - kind: funcRel32
+# CHECK: offset: 49
+# CHECK: target: _x
+# CHECK: addend: -32
+# CHECK: - kind: funcRel32
+# CHECK: offset: 55
+# CHECK: target: _x
+# CHECK: addend: -28
+
diff --git a/test/mach-o/parse-section-no-symbol.yaml b/test/mach-o/parse-section-no-symbol.yaml
new file mode 100644
index 000000000000..46d005a1cd18
--- /dev/null
+++ b/test/mach-o/parse-section-no-symbol.yaml
@@ -0,0 +1,23 @@
+# RUN: lld -flavor darwin -arch x86_64 -r %s -print_atoms -o %t2 | FileCheck %s
+#
+# Test parsing of mach-o functions with no symbols at all.
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID: false
+OS: unknown
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ alignment: 4
+ address: 0x0000000000000000
+ content: [ 0xCC ]
+...
+
+# CHECK-NOT: name:
+# CHECK: content: [ CC ]
diff --git a/test/mach-o/parse-tentative-defs.yaml b/test/mach-o/parse-tentative-defs.yaml
new file mode 100644
index 000000000000..fc75167bd895
--- /dev/null
+++ b/test/mach-o/parse-tentative-defs.yaml
@@ -0,0 +1,88 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s
+#
+# Test parsing of tentative definitions, including size, scope, and alignment.
+#
+#
+# int tent4;
+# long tent8;
+# __attribute__((visibility("hidden"))) int tentHidden;
+# __attribute__((aligned(16))) int tent4_16;
+# __attribute__((aligned(32))) long tent64_32[8];
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID: false
+OS: unknown
+sections:
+ - segment: __TEXT
+ section: __tex
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS ]
+ address: 0x0000000000000000
+undefined-symbols:
+ - name: _tent4
+ type: N_UNDF
+ scope: [ N_EXT ]
+ desc: 0x0200
+ value: 0x0000000000000004
+ - name: _tent4_16
+ type: N_UNDF
+ scope: [ N_EXT ]
+ desc: 0x0400
+ value: 0x0000000000000004
+ - name: _tent64_32
+ type: N_UNDF
+ scope: [ N_EXT ]
+ desc: 0x0500
+ value: 0x0000000000000040
+ - name: _tent8
+ type: N_UNDF
+ scope: [ N_EXT ]
+ desc: 0x0300
+ value: 0x0000000000000008
+ - name: _tentHidden
+ type: N_UNDF
+ scope: [ N_EXT, N_PEXT ]
+ desc: 0x0200
+ value: 0x0000000000000004
+...
+
+
+# CHECK: defined-atoms:
+# CHECK: name: _tent4
+# CHECK: scope: global
+# CHECK: type: zero-fill
+# CHECK: size: 4
+# CHECK: merge: as-tentative
+# CHECK: alignment: 2^2
+
+# CHECK: name: _tent4_16
+# CHECK: scope: global
+# CHECK: type: zero-fill
+# CHECK: size: 4
+# CHECK: merge: as-tentative
+# CHECK: alignment: 2^4
+
+# CHECK: name: _tent64_32
+# CHECK: scope: global
+# CHECK: type: zero-fill
+# CHECK: size: 64
+# CHECK: merge: as-tentative
+# CHECK: alignment: 2^5
+
+# CHECK: name: _tent8
+# CHECK: scope: global
+# CHECK: type: zero-fill
+# CHECK: size: 8
+# CHECK: merge: as-tentative
+# CHECK: alignment: 2^3
+
+# CHECK: name: _tentHidden
+# CHECK: scope: hidden
+# CHECK: type: zero-fill
+# CHECK: size: 4
+# CHECK: merge: as-tentative
+# CHECK: alignment: 2^2
diff --git a/test/mach-o/parse-text-relocs-arm64.yaml b/test/mach-o/parse-text-relocs-arm64.yaml
new file mode 100644
index 000000000000..38a52e7f6f28
--- /dev/null
+++ b/test/mach-o/parse-text-relocs-arm64.yaml
@@ -0,0 +1,237 @@
+# RUN: lld -flavor darwin -arch arm64 -r -print_atoms %s -o %t | FileCheck %s \
+# RUN: && lld -flavor darwin -arch arm64 -r -print_atoms %t -o %t2 | FileCheck %s
+#
+# Test parsing and writing of arm64 text relocations.
+#
+# The first step tests if the supplied mach-o file is parsed into the correct
+# set of references. The second step verifies relocations can be round-tripped
+# by writing to a new .o file, then parsing that file which should result in
+# the same references.
+#
+#_test:
+
+
+--- !mach-o
+arch: arm64
+file-type: MH_OBJECT
+flags: [ ]
+has-UUID: false
+OS: unknown
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x94,
+ 0x01, 0x00, 0x00, 0x90, 0x20, 0x00, 0x40, 0x39,
+ 0x20, 0x00, 0x40, 0x79, 0x20, 0x00, 0x40, 0xB9,
+ 0x20, 0x00, 0x40, 0xF9, 0x20, 0x00, 0xC0, 0x3D,
+ 0x01, 0x00, 0x00, 0x90, 0x20, 0x00, 0x40, 0xB9,
+ 0x01, 0x00, 0x00, 0x90, 0x20, 0x00, 0x40, 0xF9,
+ 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x40, 0xF9 ]
+ relocations:
+ - offset: 0x00000034
+ type: ARM64_RELOC_TLVP_LOAD_PAGEOFF12
+ length: 2
+ pc-rel: false
+ extern: true
+ symbol: 5
+ - offset: 0x00000030
+ type: ARM64_RELOC_TLVP_LOAD_PAGE21
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 5
+ - offset: 0x0000002C
+ type: ARM64_RELOC_GOT_LOAD_PAGEOFF12
+ length: 2
+ pc-rel: false
+ extern: true
+ symbol: 6
+ - offset: 0x00000028
+ type: ARM64_RELOC_GOT_LOAD_PAGE21
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 6
+ - offset: 0x00000024
+ type: ARM64_RELOC_ADDEND
+ length: 2
+ pc-rel: false
+ extern: false
+ symbol: 16
+ - offset: 0x00000024
+ type: ARM64_RELOC_PAGEOFF12
+ length: 2
+ pc-rel: false
+ extern: true
+ symbol: 2
+ - offset: 0x00000020
+ type: ARM64_RELOC_ADDEND
+ length: 2
+ pc-rel: false
+ extern: false
+ symbol: 16
+ - offset: 0x00000020
+ type: ARM64_RELOC_PAGE21
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 2
+ - offset: 0x0000001C
+ type: ARM64_RELOC_PAGEOFF12
+ length: 2
+ pc-rel: false
+ extern: true
+ symbol: 2
+ - offset: 0x00000018
+ type: ARM64_RELOC_PAGEOFF12
+ length: 2
+ pc-rel: false
+ extern: true
+ symbol: 2
+ - offset: 0x00000014
+ type: ARM64_RELOC_PAGEOFF12
+ length: 2
+ pc-rel: false
+ extern: true
+ symbol: 2
+ - offset: 0x00000010
+ type: ARM64_RELOC_PAGEOFF12
+ length: 2
+ pc-rel: false
+ extern: true
+ symbol: 2
+ - offset: 0x0000000C
+ type: ARM64_RELOC_PAGEOFF12
+ length: 2
+ pc-rel: false
+ extern: true
+ symbol: 2
+ - offset: 0x00000008
+ type: ARM64_RELOC_PAGE21
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 2
+ - offset: 0x00000004
+ type: ARM64_RELOC_ADDEND
+ length: 2
+ pc-rel: false
+ extern: false
+ symbol: 8
+ - offset: 0x00000004
+ type: ARM64_RELOC_BRANCH26
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 4
+ - offset: 0x00000000
+ type: ARM64_RELOC_BRANCH26
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 4
+ - segment: __DATA
+ section: __data
+ type: S_REGULAR
+ attributes: [ ]
+ alignment: 2
+ address: 0x0000000000000038
+ content: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+local-symbols:
+ - name: ltmp0
+ type: N_SECT
+ sect: 1
+ value: 0x0000000000000000
+ - name: _func
+ type: N_SECT
+ sect: 1
+ value: 0x0000000000000000
+ - name: _v1
+ type: N_SECT
+ sect: 2
+ value: 0x0000000000000038
+ - name: ltmp1
+ type: N_SECT
+ sect: 2
+ value: 0x0000000000000038
+undefined-symbols:
+ - name: _foo
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+ - name: _tlv
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+ - name: _v2
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+...
+
+# CHECK: defined-atoms:
+# CHECK: - name: _v1
+# CHECK: type: data
+# CHECK: content: [ 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
+# CHECK: 00, 00, 00, 00 ]
+# CHECK: - name: _func
+# CHECK: content: [ 00, 00, 00, 94, 00, 00, 00, 94, 01, 00, 00, 90,
+# CHECK: 20, 00, 40, 39, 20, 00, 40, 79, 20, 00, 40, B9,
+# CHECK: 20, 00, 40, F9, 20, 00, C0, 3D, 01, 00, 00, 90,
+# CHECK: 20, 00, 40, B9, 01, 00, 00, 90, 20, 00, 40, F9,
+# CHECK: 00, 00, 00, 90, 00, 00, 40, F9 ]
+# CHECK: references:
+# CHECK: - kind: branch26
+# CHECK: offset: 0
+# CHECK: target: _foo
+# CHECK: - kind: branch26
+# CHECK: offset: 4
+# CHECK: target: _foo
+# CHECK: addend: 8
+# CHECK: - kind: page21
+# CHECK: offset: 8
+# CHECK: target: _v1
+# CHECK: - kind: offset12
+# CHECK: offset: 12
+# CHECK: target: _v1
+# CHECK: - kind: offset12scale2
+# CHECK: offset: 16
+# CHECK: target: _v1
+# CHECK: - kind: offset12scale4
+# CHECK: offset: 20
+# CHECK: target: _v1
+# CHECK: - kind: offset12scale8
+# CHECK: offset: 24
+# CHECK: target: _v1
+# CHECK: - kind: offset12scale16
+# CHECK: offset: 28
+# CHECK: target: _v1
+# CHECK: - kind: page21
+# CHECK: offset: 32
+# CHECK: target: _v1
+# CHECK: addend: 16
+# CHECK: - kind: offset12scale4
+# CHECK: offset: 36
+# CHECK: target: _v1
+# CHECK: addend: 16
+# CHECK: - kind: gotPage21
+# CHECK: offset: 40
+# CHECK: target: _v2
+# CHECK: - kind: gotOffset12
+# CHECK: offset: 44
+# CHECK: target: _v2
+# CHECK: - kind: tlvPage21
+# CHECK: offset: 48
+# CHECK: target: _tlv
+# CHECK: - kind: tlvOffset12
+# CHECK: offset: 52
+# CHECK: target: _tlv
+# CHECK: undefined-atoms:
+# CHECK: - name: _foo
+# CHECK: - name: _tlv
+# CHECK: - name: _v2
+
diff --git a/test/mach-o/parse-text-relocs-x86_64.yaml b/test/mach-o/parse-text-relocs-x86_64.yaml
new file mode 100644
index 000000000000..9e58e02e3771
--- /dev/null
+++ b/test/mach-o/parse-text-relocs-x86_64.yaml
@@ -0,0 +1,168 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s \
+# RUN: && lld -flavor darwin -arch x86_64 -r -print_atoms %t -o %t2 | FileCheck %s
+#
+# Test parsing and writing of x86_64 text relocations.
+#
+# The first step tests if the supplied mach-o file is parsed into the correct
+# set of references. The second step verifies relocations can be round-tripped
+# by writing to a new .o file, then parsing that file which should result in
+# the same references.
+#
+#_test:
+# call _foo
+# call _foo+4
+# movq _foo@GOTPCREL(%rip), %rax
+# pushq _foo@GOTPCREL(%rip)
+# movl _foo(%rip), %eax
+# movl _foo+4(%rip), %eax
+# movb $0x12, _foo(%rip)
+# movw $0x1234, _foo(%rip)
+# movl $0x12345678, _foo(%rip)
+# movl L2(%rip), %eax
+#
+# .data
+#L2: .long 0
+
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ ]
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0xE8, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x04, 0x00,
+ 0x00, 0x00, 0x48, 0x8B, 0x05, 0x04, 0x00, 0x00,
+ 0x00, 0xFF, 0x35, 0x04, 0x00, 0x00, 0x00, 0x8B,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x05, 0x04,
+ 0x00, 0x00, 0x00, 0xC6, 0x05, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0x12, 0x66, 0xC7, 0x05, 0xFE, 0xFF, 0xFF,
+ 0xFF, 0x34, 0x12, 0xC7, 0x05, 0xFC, 0xFF, 0xFF,
+ 0xFF, 0x78, 0x56, 0x34, 0x12, 0x8B, 0x05, 0x00,
+ 0x00, 0x00, 0x00 ]
+ relocations:
+ - offset: 0x0000003F
+ type: X86_64_RELOC_SIGNED
+ length: 2
+ pc-rel: true
+ extern: false
+ symbol: 2
+ - offset: 0x00000035
+ type: X86_64_RELOC_SIGNED_4
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 1
+ - offset: 0x0000002D
+ type: X86_64_RELOC_SIGNED_2
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 1
+ - offset: 0x00000025
+ type: X86_64_RELOC_SIGNED_1
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 1
+ - offset: 0x0000001F
+ type: X86_64_RELOC_SIGNED
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 1
+ - offset: 0x00000019
+ type: X86_64_RELOC_SIGNED
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 1
+ - offset: 0x00000013
+ type: X86_64_RELOC_GOT
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 1
+ - offset: 0x0000000D
+ type: X86_64_RELOC_GOT_LOAD
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 1
+ - offset: 0x00000006
+ type: X86_64_RELOC_BRANCH
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 1
+ - offset: 0x00000001
+ type: X86_64_RELOC_BRANCH
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 1
+ - segment: __DATA
+ section: __data
+ type: S_REGULAR
+ attributes: [ ]
+ address: 0x0000000000000043
+ content: [ 0x00, 0x00, 0x00, 0x00 ]
+local-symbols:
+ - name: _test
+ type: N_SECT
+ sect: 1
+ value: 0x0000000000000000
+undefined-symbols:
+ - name: _foo
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+...
+
+# CHECK: defined-atoms:
+# CHECK: - ref-name: [[LABEL:L[0-9]+]]
+# CHECK: type: data
+# CHECK: content: [ 00, 00, 00, 00 ]
+# CHECK: - name: _test
+# CHECK: references:
+# CHECK: - kind: branch32
+# CHECK: offset: 1
+# CHECK: target: _foo
+# CHECK: - kind: branch32
+# CHECK: offset: 6
+# CHECK: target: _foo
+# CHECK: addend: 4
+# CHECK: - kind: ripRel32GotLoad
+# CHECK: offset: 13
+# CHECK: target: _foo
+# CHECK: addend: 4
+# CHECK: - kind: ripRel32Got
+# CHECK: offset: 19
+# CHECK: target: _foo
+# CHECK: addend: 4
+# CHECK: - kind: ripRel32
+# CHECK: offset: 25
+# CHECK: target: _foo
+# CHECK: - kind: ripRel32
+# CHECK: offset: 31
+# CHECK: target: _foo
+# CHECK: addend: 4
+# CHECK: - kind: ripRel32Minus1
+# CHECK: offset: 37
+# CHECK: target: _foo
+# CHECK-NOT: addend:
+# CHECK: - kind: ripRel32Minus2
+# CHECK: offset: 45
+# CHECK: target: _foo
+# CHECK-NOT: addend:
+# CHECK: - kind: ripRel32Minus4
+# CHECK: offset: 53
+# CHECK: target: _foo
+# CHECK-NOT: addend:
+# CHECK: - kind: ripRel32Anon
+# CHECK: offset: 63
+# CHECK: target: [[LABEL]]
+# CHECK-NOT: addend:
diff --git a/test/mach-o/re-exported-dylib-ordinal.yaml b/test/mach-o/re-exported-dylib-ordinal.yaml
new file mode 100644
index 000000000000..9d628e9af151
--- /dev/null
+++ b/test/mach-o/re-exported-dylib-ordinal.yaml
@@ -0,0 +1,105 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -dylib -o %t \
+# RUN: && llvm-nm -m %t | FileCheck %s
+#
+# Test that when one dylib A re-exports dylib B that using a symbol from B
+# gets recorded as coming from A.
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID: false
+OS: unknown
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0x55, 0x48, 0x89, 0xE5, 0x31, 0xC0, 0x5D, 0xE9,
+ 0x00, 0x00, 0x00, 0x00 ]
+ relocations:
+ - offset: 0x00000008
+ type: X86_64_RELOC_BRANCH
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 1
+global-symbols:
+ - name: _test
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+undefined-symbols:
+ - name: _bar
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+
+--- !mach-o
+arch: x86_64
+file-type: MH_DYLIB
+flags: [ MH_TWOLEVEL ]
+install-name: /junk/libfoo.dylib
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000F9A
+ content: [ 0x55, 0x48, 0x89, 0xE5, 0x5D, 0xC3 ]
+global-symbols:
+ - name: _foo
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000F9A
+dependents:
+ - path: /junk/libbar.dylib
+ kind: LC_REEXPORT_DYLIB
+
+--- !mach-o
+arch: x86_64
+file-type: MH_DYLIB
+flags: [ MH_TWOLEVEL ]
+install-name: /junk/libbar.dylib
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000F9A
+ content: [ 0x55, 0x48, 0x89, 0xE5, 0x5D, 0xC3 ]
+global-symbols:
+ - name: _bar
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000F9A
+
+--- !mach-o
+arch: x86_64
+file-type: MH_DYLIB
+flags: [ MH_TWOLEVEL ]
+install-name: /usr/lib/libSystem.B.dylib
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0x55 ]
+
+global-symbols:
+ - name: dyld_stub_binder
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+
+...
+
+# CHECK: (undefined) external _bar (from libfoo)
+# CHECK: (undefined) external dyld_stub_binder (from libSystem)
diff --git a/test/mach-o/rpath.yaml b/test/mach-o/rpath.yaml
new file mode 100644
index 000000000000..f0b5f718c15a
--- /dev/null
+++ b/test/mach-o/rpath.yaml
@@ -0,0 +1,38 @@
+# Check we handle -rpath correctly:
+# RUN: lld -flavor darwin -arch x86_64 -rpath @loader_path/../Frameworks \
+# RUN: %p/Inputs/libSystem.yaml %s -o %t
+# RUN: llvm-objdump -private-headers %t | FileCheck %s --check-prefix=CHECK-BINARY-WRITE
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID: false
+OS: unknown
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ alignment: 4
+ address: 0x0000000000000000
+ content: [ 0xCC, 0xC3, 0x90, 0xC3, 0x90, 0x90, 0xC3, 0x90,
+ 0x90, 0x90, 0xC3, 0x90, 0x90, 0x90, 0x90, 0xC3,
+ 0x31, 0xC0, 0xC3 ]
+local-symbols:
+ - name: _myStatic
+ type: N_SECT
+ sect: 1
+ value: 0x000000000000000B
+global-symbols:
+ - name: _main
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000001
+...
+
+
+# CHECK-BINARY-WRITE: cmd LC_RPATH
+# CHECK-BINARY-WRITE-NEXT: cmdsize 44
+# CHECK-BINARY-WRITE-NEXT: path @loader_path/../Frameworks (offset 12)
diff --git a/test/mach-o/sectalign.yaml b/test/mach-o/sectalign.yaml
new file mode 100644
index 000000000000..3556a5ecbcfc
--- /dev/null
+++ b/test/mach-o/sectalign.yaml
@@ -0,0 +1,80 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -dylib \
+# RUN: -sectalign __DATA __custom 0x800 -sectalign __TEXT __text 0x400 \
+# RUN: %p/Inputs/libSystem.yaml -o %t \
+# RUN: && llvm-readobj -sections %t | FileCheck %s
+#
+# Test -sectalign option on __text and a custom section.
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0x55, 0x48, 0x89, 0xE5, 0x8B, 0x05, 0x00, 0x00,
+ 0x00, 0x00, 0x03, 0x05, 0x00, 0x00, 0x00, 0x00,
+ 0x5D, 0xC3 ]
+ relocations:
+ - offset: 0x0000000C
+ type: X86_64_RELOC_SIGNED
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 1
+ - offset: 0x00000006
+ type: X86_64_RELOC_SIGNED
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 2
+ - segment: __DATA
+ section: __data
+ type: S_REGULAR
+ attributes: [ ]
+ alignment: 2
+ address: 0x0000000000000014
+ content: [ 0x0A, 0x00, 0x00, 0x00 ]
+ - segment: __DATA
+ section: __custom
+ type: S_REGULAR
+ attributes: [ ]
+ alignment: 2
+ address: 0x0000000000000018
+ content: [ 0x0A, 0x00, 0x00, 0x00 ]
+global-symbols:
+ - name: _a
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 2
+ value: 0x0000000000000014
+ - name: _b
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 3
+ value: 0x0000000000000018
+ - name: _get
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+
+...
+
+
+# CHECK: Name: __text (5F 5F 74 65 78 74 00 00 00 00 00 00 00 00 00 00)
+# CHECK: Segment: __TEXT (5F 5F 54 45 58 54 00 00 00 00 00 00 00 00 00 00)
+# CHECK: Address: 0xC00
+
+# CHECK: Name: __data (5F 5F 64 61 74 61 00 00 00 00 00 00 00 00 00 00)
+# CHECK: Segment: __DATA (5F 5F 44 41 54 41 00 00 00 00 00 00 00 00 00 00)
+# CHECK: Address: 0x1000
+
+# CHECK: Name: __custom (5F 5F 63 75 73 74 6F 6D 00 00 00 00 00 00 00 00)
+# CHECK: Segment: __DATA (5F 5F 44 41 54 41 00 00 00 00 00 00 00 00 00 00)
+# CHECK: Address: 0x1800
+
diff --git a/test/mach-o/unwind-info-simple-arm64.yaml b/test/mach-o/unwind-info-simple-arm64.yaml
new file mode 100644
index 000000000000..d46b43ff712d
--- /dev/null
+++ b/test/mach-o/unwind-info-simple-arm64.yaml
@@ -0,0 +1,280 @@
+# RUN: lld -flavor darwin -arch arm64 %s -o %t -e _main %p/Inputs/libSystem.yaml
+# RUN: llvm-objdump -unwind-info %t | FileCheck %s
+
+--- !mach-o
+arch: arm64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ alignment: 2
+ address: 0x0000000000000000
+ content: [ 0xFD, 0x7B, 0xBF, 0xA9, 0xFD, 0x03, 0x00, 0x91,
+ 0xE0, 0x03, 0x1E, 0x32, 0x00, 0x00, 0x00, 0x94,
+ 0x48, 0x01, 0x80, 0x52, 0x08, 0x00, 0x00, 0xB9,
+ 0x02, 0x00, 0x80, 0xD2, 0x01, 0x00, 0x00, 0x90,
+ 0x21, 0x00, 0x40, 0xF9, 0x00, 0x00, 0x00, 0x94,
+ 0xFD, 0x7B, 0xBF, 0xA9, 0xFD, 0x03, 0x00, 0x91,
+ 0xE0, 0x03, 0x1E, 0x32, 0x00, 0x00, 0x00, 0x94,
+ 0x48, 0x01, 0x80, 0x52, 0x08, 0x00, 0x00, 0xB9,
+ 0x02, 0x00, 0x80, 0xD2, 0x01, 0x00, 0x00, 0x90,
+ 0x21, 0x00, 0x40, 0xF9, 0x00, 0x00, 0x00, 0x94,
+ 0x3F, 0x04, 0x00, 0x71, 0x81, 0x00, 0x00, 0x54,
+ 0x00, 0x00, 0x00, 0x94, 0xFD, 0x7B, 0xC1, 0xA8,
+ 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x94,
+ 0xFD, 0x7B, 0xBF, 0xA9, 0xFD, 0x03, 0x00, 0x91,
+ 0x00, 0x00, 0x00, 0x94 ]
+ relocations:
+ - offset: 0x00000070
+ type: ARM64_RELOC_BRANCH26
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 5
+ - offset: 0x00000064
+ type: ARM64_RELOC_BRANCH26
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 7
+ - offset: 0x00000060
+ type: ARM64_RELOC_BRANCH26
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 12
+ - offset: 0x00000058
+ type: ARM64_RELOC_BRANCH26
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 11
+ - offset: 0x0000004C
+ type: ARM64_RELOC_BRANCH26
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 13
+ - offset: 0x00000048
+ type: ARM64_RELOC_GOT_LOAD_PAGEOFF12
+ length: 2
+ pc-rel: false
+ extern: true
+ symbol: 8
+ - offset: 0x00000044
+ type: ARM64_RELOC_GOT_LOAD_PAGE21
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 8
+ - offset: 0x00000034
+ type: ARM64_RELOC_BRANCH26
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 10
+ - offset: 0x00000024
+ type: ARM64_RELOC_BRANCH26
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 13
+ - offset: 0x00000020
+ type: ARM64_RELOC_GOT_LOAD_PAGEOFF12
+ length: 2
+ pc-rel: false
+ extern: true
+ symbol: 8
+ - offset: 0x0000001C
+ type: ARM64_RELOC_GOT_LOAD_PAGE21
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 8
+ - offset: 0x0000000C
+ type: ARM64_RELOC_BRANCH26
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 10
+ - segment: __TEXT
+ section: __gcc_except_tab
+ type: S_REGULAR
+ attributes: [ ]
+ alignment: 2
+ address: 0x0000000000000074
+ content: [ 0xFF, 0x9B, 0xAF, 0x80, 0x00, 0x03, 0x27, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
+ 0x01, 0x28, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0xD0, 0xFF, 0xFF, 0xFF ]
+ relocations:
+ - offset: 0x00000030
+ type: ARM64_RELOC_POINTER_TO_GOT
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 9
+ - segment: __LD
+ section: __compact_unwind
+ type: S_REGULAR
+ attributes: [ ]
+ alignment: 3
+ address: 0x00000000000000A8
+ content: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+ relocations:
+ - offset: 0x00000040
+ type: ARM64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: false
+ symbol: 1
+ - offset: 0x00000038
+ type: ARM64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: false
+ symbol: 2
+ - offset: 0x00000030
+ type: ARM64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: true
+ symbol: 14
+ - offset: 0x00000020
+ type: ARM64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: false
+ symbol: 1
+ - offset: 0x00000000
+ type: ARM64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: false
+ symbol: 1
+local-symbols:
+ - name: ltmp0
+ type: N_SECT
+ sect: 1
+ value: 0x0000000000000000
+ - name: ltmp14
+ type: N_SECT
+ sect: 2
+ value: 0x0000000000000074
+ - name: GCC_except_table1
+ type: N_SECT
+ sect: 2
+ value: 0x0000000000000074
+ - name: ltmp21
+ type: N_SECT
+ sect: 3
+ value: 0x00000000000000A8
+global-symbols:
+ - name: __Z3barv
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000028
+ - name: __Z3foov
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+ - name: _main
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000068
+undefined-symbols:
+ - name: __Unwind_Resume
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+ - name: __ZTIi
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+ - name: __ZTIl
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+ - name: ___cxa_allocate_exception
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+ - name: ___cxa_begin_catch
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+ - name: ___cxa_end_catch
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+ - name: ___cxa_throw
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+ - name: ___gxx_personality_v0
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+
+--- !mach-o
+arch: arm64
+file-type: MH_DYLIB
+install-name: /usr/lib/libc++.dylib
+exports:
+ - name: __Unwind_Resume
+ - name: __ZTIl
+ - name: __ZTIi
+ - name: ___cxa_end_catch
+ - name: ___cxa_begin_catch
+ - name: ___cxa_allocate_exception
+ - name: ___cxa_throw
+ - name: ___gxx_personality_v0
+
+...
+
+
+# CHECK: Contents of __unwind_info section:
+# CHECK: Version: 0x1
+# CHECK: Common encodings array section offset: 0x1c
+# CHECK: Number of common encodings in array: 0x0
+# CHECK: Personality function array section offset: 0x1c
+# CHECK: Number of personality functions in array: 0x1
+# CHECK: Index array section offset: 0x20
+# CHECK: Number of indices in array: 0x2
+# CHECK: Common encodings: (count = 0)
+# CHECK: Personality functions: (count = 1)
+# CHECK: personality[1]: 0x00004018
+# CHECK: Top level indices: (count = 2)
+# CHECK: [0]: function offset=0x00003e68, 2nd level page offset=0x00000040, LSDA offset=0x00000038
+# CHECK: [1]: function offset=0x00003edc, 2nd level page offset=0x00000000, LSDA offset=0x00000040
+# CHECK: LSDA descriptors:
+# CHECK: [0]: function offset=0x00003e90, LSDA offset=0x00003f6c
+# CHECK: Second level indices:
+# CHECK: Second level index[0]: offset in section=0x00000040, base function offset=0x00003e68
+# CHECK: [0]: function offset=0x00003e68, encoding=0x04000000
+# CHECK: [1]: function offset=0x00003e90, encoding=0x54000000
+# CHECK: [2]: function offset=0x00003ed0, encoding=0x04000000
+# CHECK-NOT: Contents of __compact_unwind section
+
+
+
diff --git a/test/mach-o/unwind-info-simple-x86_64.yaml b/test/mach-o/unwind-info-simple-x86_64.yaml
new file mode 100644
index 000000000000..8886e5271661
--- /dev/null
+++ b/test/mach-o/unwind-info-simple-x86_64.yaml
@@ -0,0 +1,118 @@
+# RUN: lld -flavor darwin -arch x86_64 %s -o %t -e _main %p/Inputs/libSystem.yaml
+# RUN: llvm-objdump -unwind-info %t | FileCheck %s
+
+# CHECK: Contents of __unwind_info section:
+# CHECK: Version: 0x1
+# CHECK: Common encodings array section offset: 0x1c
+# CHECK: Number of common encodings in array: 0x0
+# CHECK: Personality function array section offset: 0x1c
+# CHECK: Number of personality functions in array: 0x1
+# CHECK: Index array section offset: 0x20
+# CHECK: Number of indices in array: 0x2
+# CHECK: Common encodings: (count = 0)
+# CHECK: Personality functions: (count = 1)
+# CHECK: personality[1]: 0x00001000
+# CHECK: Top level indices: (count = 2)
+# CHECK: [0]: function offset=0x00000efb, 2nd level page offset=0x00000040, LSDA offset=0x00000038
+# CHECK: [1]: function offset=0x00000f00, 2nd level page offset=0x00000000, LSDA offset=0x00000040
+# CHECK: LSDA descriptors:
+# CHECK: [0]: function offset=0x00000efb, LSDA offset=0x00000f00
+# CHECK: Second level indices:
+# CHECK: Second level index[0]: offset in section=0x00000040, base function offset=0x00000efb
+# CHECK: [0]: function offset=0x00000efb, encoding=0x51000000
+# CHECK: [1]: function offset=0x00000efc, encoding=0x01000000
+# CHECK: [2]: function offset=0x00000efd, encoding=0x04000018
+# CHECK: [3]: function offset=0x00000efe, encoding=0x04000040
+# CHECK: [4]: function offset=0x00000eff, encoding=0x00000000
+# CHECK-NOT: Contents of __compact_unwind section
+
+--- !native
+path: '<linker-internal>'
+defined-atoms:
+ - name: GCC_except_table1
+ type: unwind-lsda
+ content: [ FF, 9B, A2, 80, 80, 00, 03, 1A, 08, 00, 00, 00,
+ 05, 00, 00, 00, 1A, 00, 00, 00, 01, 0D, 00, 00,
+ 00, 64, 00, 00, 00, 00, 00, 00, 00, 00, 01, 00,
+ 04, 00, 00, 00 ]
+ - type: compact-unwind
+ content: [ 40, 00, 00, 00, 00, 00, 00, 00, 01, 00, 00, 00,
+ 00, 00, 00, 41, 00, 00, 00, 00, 00, 00, 00, 00,
+ E0, 00, 00, 00, 00, 00, 00, 00 ]
+ references:
+ - kind: pointer64Anon
+ offset: 0
+ target: __Z3barv
+ - kind: pointer64
+ offset: 16
+ target: ___gxx_personality_v0
+ - kind: pointer64Anon
+ offset: 24
+ target: GCC_except_table1
+ - type: compact-unwind
+ content: [ C0, 00, 00, 00, 00, 00, 00, 00, 01, 00, 00, 00,
+ 00, 00, 00, 01, 00, 00, 00, 00, 00, 00, 00, 00,
+ 00, 00, 00, 00, 00, 00, 00, 00 ]
+ references:
+ - kind: pointer64Anon
+ offset: 0
+ target: _main
+ - type: compact-unwind
+ content: [ C1, 00, 00, 00, 00, 00, 00, 00, 01, 00, 00, 00,
+ 00, 00, 00, 04, 00, 00, 00, 00, 00, 00, 00, 00,
+ 00, 00, 00, 00, 00, 00, 00, 00 ]
+ references:
+ - kind: pointer64Anon
+ offset: 0
+ target: _needsDwarfButNoCompactUnwind
+
+# Generic x86_64 CIE:
+ - type: unwind-cfi
+ content: [ 14, 00, 00, 00, 00, 00, 00, 00, 01, 7A, 52, 00,
+ 01, 78, 10, 01, 10, 0C, 07, 08, 90, 01, 00, 00 ]
+
+ - type: unwind-cfi
+ content: [ 24, 00, 00, 00, 1C, 00, 00, 00, C8, FE, FF, FF,
+ FF, FF, FF, FF, 01, 00, 00, 00, 00, 00, 00, 00,
+ 00, 41, 0E, 10, 86, 02, 43, 0D, 06, 00, 00, 00,
+ 00, 00, 00, 00 ]
+ references:
+ - kind: unwindFDEToFunction
+ offset: 8
+ target: _needsDwarfButNoCompactUnwind
+
+ - type: unwind-cfi
+ content: [ 24, 00, 00, 00, 44, 00, 00, 00, C8, FE, FF, FF,
+ FF, FF, FF, FF, 01, 00, 00, 00, 00, 00, 00, 00,
+ 00, 41, 0E, 10, 86, 02, 43, 0D, 06, 00, 00, 00,
+ 00, 00, 00, 00 ]
+ references:
+ - kind: unwindFDEToFunction
+ offset: 8
+ target: _needsDwarfSaysCompactUnwind
+
+
+ - name: __Z3barv
+ scope: global
+ content: [ C3 ]
+ - name: _main
+ scope: global
+ content: [ C3 ]
+ references:
+ - kind: branch32
+ offset: 9
+ target: __Z3barv
+ - name: _needsDwarfButNoCompactUnwind
+ scope: global
+ content: [ C3 ]
+ - name: _needsDwarfSaysCompactUnwind
+ scope: global
+ content: [ C3 ]
+ - name: _noUnwindData
+ scope: global
+ content: [ C3 ]
+
+shared-library-atoms:
+ - name: ___gxx_personality_v0
+ load-name: '/usr/lib/libc++abi.dylib'
+ type: unknown
diff --git a/test/mach-o/upward-dylib-load-command.yaml b/test/mach-o/upward-dylib-load-command.yaml
new file mode 100644
index 000000000000..fee3e41d5bd5
--- /dev/null
+++ b/test/mach-o/upward-dylib-load-command.yaml
@@ -0,0 +1,48 @@
+# RUN: lld -flavor darwin -arch x86_64 -dylib %p/Inputs/bar.yaml \
+# RUN: -install_name /usr/lib/libbar.dylib %p/Inputs/libSystem.yaml -o %t1.dylib
+# RUN: lld -flavor darwin -arch x86_64 -dylib %s -upward_library %t1.dylib \
+# RUN: -install_name /usr/lib/libfoo.dylib %p/Inputs/libSystem.yaml -o %t
+# RUN: llvm-objdump -private-headers %t | FileCheck %s
+#
+#
+# Test upward linking: 1) build libbar.dylib, 2) build libfoo.dylib and upward
+# like with libbar.dylib, 3) dump load commands of libfoo and verify upward link.
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0x55, 0x48, 0x89, 0xE5, 0x31, 0xC0, 0x5D, 0xE9,
+ 0x00, 0x00, 0x00, 0x00 ]
+ relocations:
+ - offset: 0x00000008
+ type: X86_64_RELOC_BRANCH
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 1
+global-symbols:
+ - name: _foo
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+undefined-symbols:
+ - name: _bar
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+
+...
+
+
+# CHECK: cmd LC_LOAD_UPWARD_DYLIB
+# CHECK-NEXT: cmdsize 48
+# CHECK-NEXT: name /usr/lib/libbar.dylib (offset 24)
diff --git a/test/mach-o/upward-dylib-paths.yaml b/test/mach-o/upward-dylib-paths.yaml
new file mode 100644
index 000000000000..53ff9fa2298c
--- /dev/null
+++ b/test/mach-o/upward-dylib-paths.yaml
@@ -0,0 +1,18 @@
+#
+#
+# RUN: lld -flavor darwin -arch x86_64 -r -test_file_usage -v \
+# RUN: -path_exists /Custom/Frameworks \
+# RUN: -path_exists /Custom/Frameworks/Bar.framework/Bar \
+# RUN: -path_exists /usr/lib \
+# RUN: -path_exists /usr/lib/libfoo.dylib \
+# RUN: -path_exists /opt/stuff/libstuff.dylib \
+# RUN: -F/Custom/Frameworks \
+# RUN: -upward_framework Bar \
+# RUN: -upward-lfoo \
+# RUN: -upward_library /opt/stuff/libstuff.dylib \
+# RUN: 2>&1 | FileCheck %s
+
+# CHECK: Found upward framework /Custom/Frameworks/Bar.framework/Bar
+# CHECK: Found upward library /usr/lib/libfoo.dylib
+
+
diff --git a/test/mach-o/usage.yaml b/test/mach-o/usage.yaml
new file mode 100644
index 000000000000..20a506284c96
--- /dev/null
+++ b/test/mach-o/usage.yaml
@@ -0,0 +1,8 @@
+# RUN: not lld -flavor darwin | FileCheck %s
+#
+# Test that running darwin linker with no option prints out usage message.
+#
+
+
+# CHECK: USAGE:
+# CHECK: -arch
diff --git a/test/mach-o/use-simple-dylib.yaml b/test/mach-o/use-simple-dylib.yaml
new file mode 100644
index 000000000000..0da7d1b0bd05
--- /dev/null
+++ b/test/mach-o/use-simple-dylib.yaml
@@ -0,0 +1,131 @@
+# RUN: lld -flavor darwin -arch x86_64 -print_atoms -r %s -o %t | FileCheck %s
+
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ ]
+has-UUID: false
+OS: unknown
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0x55, 0x48, 0x89, 0xE5, 0xE8, 0x00, 0x00, 0x00,
+ 0x00, 0xE8, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x00,
+ 0x00, 0x00, 0x00, 0xE8, 0x00, 0x00, 0x00, 0x00,
+ 0xE8, 0x00, 0x00, 0x00, 0x00, 0x5D, 0xE9, 0x00,
+ 0x00, 0x00, 0x00 ]
+global-symbols:
+ - name: _foo
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+undefined-symbols:
+ - name: _myGlobal
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+ - name: _myGlobalWeak
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+ - name: _myHidden
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+ - name: _myHiddenWeak
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+ - name: _myResolver
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+ - name: _myStatic
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+ - name: _myVariablePreviouslyKnownAsPrivateExtern
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+
+--- !mach-o
+arch: x86_64
+file-type: MH_DYLIB
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID: false
+OS: unknown
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ alignment: 4
+ address: 0x0000000000000000
+ content: [ 0xCC, 0xC3, 0x90, 0xC3, 0x90, 0x90, 0xC3, 0x90,
+ 0x90, 0x90, 0xC3, 0x90, 0x90, 0x90, 0x90, 0xC3,
+ 0x31, 0xC0, 0xC3 ]
+local-symbols:
+ - name: _myStatic
+ type: N_SECT
+ sect: 1
+ value: 0x000000000000000B
+ - name: _myVariablePreviouslyKnownAsPrivateExtern
+ type: N_SECT
+ scope: [ N_PEXT ]
+ sect: 1
+ desc: [ N_SYMBOL_RESOLVER ]
+ value: 0x0000000000000011
+global-symbols:
+ - name: _myGlobal
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000001
+ - name: _myGlobalWeak
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ desc: [ N_WEAK_DEF ]
+ value: 0x0000000000000002
+ - name: _myHidden
+ type: N_SECT
+ scope: [ N_EXT, N_PEXT ]
+ sect: 1
+ value: 0x0000000000000004
+ - name: _myHiddenWeak
+ type: N_SECT
+ scope: [ N_EXT, N_PEXT ]
+ sect: 1
+ desc: [ N_WEAK_DEF ]
+ value: 0x0000000000000007
+ - name: _myResolver
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ desc: [ N_SYMBOL_RESOLVER ]
+ value: 0x0000000000000010
+
+install-name: libspecial.dylib
+...
+
+
+# CHECK: undefined-atoms:
+# CHECK: - name: _myStatic
+# CHECK: - name: _myVariablePreviouslyKnownAsPrivateExtern
+# CHECK: shared-library-atoms:
+# CHECK: - name: _myGlobal
+# CHECK: load-name: libspecial.dylib
+# CHECK: - name: _myGlobalWeak
+# CHECK: load-name: libspecial.dylib
+# CHECK: - name: _myHidden
+# CHECK: load-name: libspecial.dylib
+# CHECK: - name: _myHiddenWeak
+# CHECK: load-name: libspecial.dylib
+# CHECK: - name: _myResolver
+# CHECK: load-name: libspecial.dylib
diff --git a/test/mach-o/write-final-sections.yaml b/test/mach-o/write-final-sections.yaml
new file mode 100644
index 000000000000..7d4afb31900a
--- /dev/null
+++ b/test/mach-o/write-final-sections.yaml
@@ -0,0 +1,167 @@
+# RUN: lld -flavor darwin -arch x86_64 %s -o %t -e _foo
+# RUN: llvm-readobj -sections -section-data %t | FileCheck %s
+
+--- !native
+defined-atoms:
+# For __TEXT, __text (with typeCode)
+ - name: _foo
+ scope: global
+ content: [ 55 ]
+# CHECK: Name: __text
+# CHECK: Segment: __TEXT
+# CHECK: SectionData (
+# CHECK-NEXT: 0000: 55
+# CHECK-NEXT: )
+
+# For __TEXT, __const (with typeConstant),
+ - type: constant
+ content: [ 01, 00, 00, 00 ]
+# From __TEXT, __literal4, (with typeLiteral4)
+ - scope: hidden
+ type: const-4-byte
+ content: [ 02, 00, 00, 00 ]
+# From __TEXT, __literal8, (with typeLiteral8)
+ - scope: hidden
+ type: const-8-byte
+ content: [ 03, 00, 00, 00, 00, 00, 00, 00 ]
+# From __TEXT, __literal16, (with typeLiteral16)
+ - scope: hidden
+ type: const-16-byte
+ content: [ 04, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK: Name: __const
+# CHECK: Segment: __TEXT
+# CHECK: SectionData (
+# CHECK-NEXT: 0000: 01000000 02000000 03000000 00000000
+# CHECK-NEXT: 0010: 04000000 00000000 00000000 00000000
+# CHECK-NEXT: )
+
+# For __TEXT, __cstring (with typeCString)
+ - scope: hidden
+ type: c-string
+ content: [ 57, 69, 62, 62, 6C, 65, 00 ]
+ merge: by-content
+# CHECK: Name: __cstring
+# CHECK: Segment: __TEXT
+# CHECK: SectionData (
+# CHECK-NEXT: 0000: 57696262 6C6500
+# CHECK-NEXT: )
+
+# For __TEXT, __ustring (with typeUTF16String)
+ - scope: hidden
+ type: utf16-string
+ content: [ 05, 00 ]
+ merge: by-content
+# CHECK: Name: __ustring
+# CHECK: Segment: __TEXT
+# CHECK: SectionData (
+# CHECK-NEXT: 0000: 0500
+# CHECK-NEXT: )
+
+# For __TEXT, __gcc_except_tab, (with typeLSDA)
+ - name: GCC_except_table0
+ type: unwind-lsda
+ content: [ 06, 00 ]
+# CHECK: Name: __gcc_except_tab
+# CHECK: Segment: __TEXT
+# CHECK: SectionData (
+# CHECK-NEXT: 0000: 0600
+# CHECK-NEXT: )
+
+# For __TEXT, __eh_frame, (with typeCFI)
+ - type: unwind-cfi
+ content: [ 07 ]
+# CHECK: Name: __eh_frame
+# CHECK: Segment: __TEXT
+# CHECK: SectionData (
+# CHECK-NEXT: 0000: 07
+# CHECK-NEXT: )
+
+# For __DATA, __data, (with typeData)
+ - name: var
+ type: data
+ content: [ 08 ]
+# CHECK: Name: __data
+# CHECK: Segment: __DATA
+# CHECK: SectionData (
+# CHECK-NEXT: 0000: 08
+# CHECK-NEXT: )
+
+# For __DATA, __bss (with typeZeroFill)
+# FIXME: Attributes & tags of __bss are mostly broken. Should be at end of
+# __DATA, should have size, should have S_ZEROFILL flag.
+ - type: zero-fill
+ size: 8
+# CHECK: Name: __bss
+# CHECK: Segment: __DATA
+
+# For __DATA, __const, (with typeConstData)
+ - type: const-data
+ content: [ 09, 00, 00, 00 ]
+# CHECK: Name: __const
+# CHECK: Segment: __DATA
+# CHECK: SectionData (
+# CHECK-NEXT: 0000: 09000000
+# CHECK-NEXT: )
+
+# For __DATA, __cfstring, (with typeCFString)
+ - type: cfstring
+ content: [ 0A, 00 ]
+# CHECK: Name: __cfstring
+# CHECK: Segment: __DATA
+# CHECK: SectionData (
+# CHECK-NEXT: 0000: 0A00
+# CHECK-NEXT: )
+
+# For __DATA, __got (with typeGOT)
+ - type: got
+ content: [ 0B, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK: Name: __got
+# CHECK: Segment: __DATA
+# CHECK: SectionData (
+# CHECK-NEXT: 0000: 0B000000 00000000
+# CHECK-NEXT: )
+
+
+# For __DATA, __mod_init_func (with typeInitializerPtr)
+ - type: initializer-pointer
+ content: [ 0C, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK: Name: __mod_init_func
+# CHECK: Segment: __DATA
+# CHECK: SectionData (
+# CHECK-NEXT: 0000: 0C000000 00000000
+# CHECK-NEXT: )
+
+# For __DATA, __mod_term_func (with typeTerminatorPointer)
+ - type: terminator-pointer
+ content: [ 0D, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK: Name: __mod_term_func
+# CHECK: Segment: __DATA
+# CHECK: SectionData (
+# CHECK-NEXT: 0000: 0D000000 00000000
+# CHECK-NEXT: )
+
+ - type: compact-unwind
+ content: [ 0E, 00, 00, 00, 00, 00, 00, 00 ]
+# CHECK-NOT: Name: __compact_unwind
+
+
+--- !mach-o
+arch: x86_64
+file-type: MH_DYLIB
+flags: [ ]
+install-name: /usr/lib/libSystem.B.dylib
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0x55 ]
+
+global-symbols:
+ - name: dyld_stub_binder
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+
diff --git a/test/mach-o/wrong-arch-error.yaml b/test/mach-o/wrong-arch-error.yaml
new file mode 100644
index 000000000000..6d233798a7b6
--- /dev/null
+++ b/test/mach-o/wrong-arch-error.yaml
@@ -0,0 +1,49 @@
+# RUN: not lld -flavor darwin -arch x86_64 -r %s 2> %t.err
+# RUN: FileCheck %s < %t.err
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ ]
+has-UUID: false
+OS: unknown
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0xCC ]
+
+global-symbols:
+ - name: _foo
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+
+--- !mach-o
+arch: x86
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID: false
+OS: unknown
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ alignment: 4
+ address: 0x0000000000000000
+ content: [ 0xC3 ]
+
+global-symbols:
+ - name: _bar
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+...
+
+
+# CHECK: wrong architecture
diff --git a/test/pecoff/Inputs/abs.obj.yaml b/test/pecoff/Inputs/abs.obj.yaml
new file mode 100644
index 000000000000..65c3901ad8e7
--- /dev/null
+++ b/test/pecoff/Inputs/abs.obj.yaml
@@ -0,0 +1,11 @@
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: []
+sections:
+symbols:
+ - Name: _abs_value
+ Value: 0xDEADBEEF
+ SectionNumber: -1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
diff --git a/test/pecoff/Inputs/alignment.obj.yaml b/test/pecoff/Inputs/alignment.obj.yaml
new file mode 100644
index 000000000000..1b12da0e6bad
--- /dev/null
+++ b/test/pecoff/Inputs/alignment.obj.yaml
@@ -0,0 +1,103 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 256
+ SectionData: CC
+ - Name: .text$1
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4096
+ SectionData: 00
+ - Name: .data$1
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 4
+ SectionData: 00
+ - Name: .data$2
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 4
+ SectionData: 11
+ - Name: .data$3
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 0
+ SectionData: 22
+ - Name: .bss$1
+ Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 16
+ SectionData: 0000
+ - Name: .bss$2
+ Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 16
+ SectionData: 0000
+ - Name: .yyy
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 4096
+ SectionData: 0000
+ - Name: .zzz
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 16384
+ SectionData: 0000
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: .text$1
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: .data$1
+ Value: 0
+ SectionNumber: 3
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: .data$2
+ Value: 0
+ SectionNumber: 4
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: .data$3
+ Value: 0
+ SectionNumber: 5
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: _start
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: .bss$1
+ Value: 0
+ SectionNumber: 6
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: .bss$2
+ Value: 0
+ SectionNumber: 7
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: .foo
+ Value: 0
+ SectionNumber: 8
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: .bar
+ Value: 0
+ SectionNumber: 9
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+...
diff --git a/test/pecoff/Inputs/alternatename1.obj.yaml b/test/pecoff/Inputs/alternatename1.obj.yaml
new file mode 100644
index 000000000000..dac18a8ef595
--- /dev/null
+++ b/test/pecoff/Inputs/alternatename1.obj.yaml
@@ -0,0 +1,23 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ SectionData: 90909090
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: _foo
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/alternatename2.obj.yaml b/test/pecoff/Inputs/alternatename2.obj.yaml
new file mode 100644
index 000000000000..5b70bfced6a1
--- /dev/null
+++ b/test/pecoff/Inputs/alternatename2.obj.yaml
@@ -0,0 +1,23 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: CCCCCCCC
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: _main
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/alternatename3.obj.yaml b/test/pecoff/Inputs/alternatename3.obj.yaml
new file mode 100644
index 000000000000..1865653ea668
--- /dev/null
+++ b/test/pecoff/Inputs/alternatename3.obj.yaml
@@ -0,0 +1,39 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ SectionData: 90909090
+ - Name: .drectve
+ Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+ Alignment: 2147483648
+ SectionData: 2F616C7465726E6174656E616D653A5F6D61696E3D5F666F6F00
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: _foo
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: .drectve
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 13
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+...
diff --git a/test/pecoff/Inputs/armnt-ImageBase.obj.yaml b/test/pecoff/Inputs/armnt-ImageBase.obj.yaml
new file mode 100644
index 000000000000..69cd530253b0
--- /dev/null
+++ b/test/pecoff/Inputs/armnt-ImageBase.obj.yaml
@@ -0,0 +1,39 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_ARMNT
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_PURGEABLE, IMAGE_SCN_MEM_16BIT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 7047FEDE00000000
+ Relocations:
+ - VirtualAddress: 4
+ SymbolName: __ImageBase
+ Type: 1
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 8
+ NumberOfRelocations: 1
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 1
+ - Name: mainCRTStartup
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: __ImageBase
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/armnt-ImageBase.s b/test/pecoff/Inputs/armnt-ImageBase.s
new file mode 100644
index 000000000000..a17458eddb15
--- /dev/null
+++ b/test/pecoff/Inputs/armnt-ImageBase.s
@@ -0,0 +1,16 @@
+
+ .syntax unified
+ .thumb
+ .text
+
+ .def mainCRTStartup
+ .type 32
+ .scl 2
+ .endef
+ .align 2
+ .thumb_func
+mainCRTStartup:
+ bx lr
+ trap
+ .long __ImageBase
+
diff --git a/test/pecoff/Inputs/armnt-addr32-exec.obj.yaml b/test/pecoff/Inputs/armnt-addr32-exec.obj.yaml
new file mode 100644
index 000000000000..b550f58c03e6
--- /dev/null
+++ b/test/pecoff/Inputs/armnt-addr32-exec.obj.yaml
@@ -0,0 +1,55 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_ARMNT
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_PURGEABLE, IMAGE_SCN_MEM_16BIT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: '7047'
+ - Name: .rdata
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: '00000000'
+ Relocations:
+ - VirtualAddress: 0
+ SymbolName: function
+ Type: 1
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 2
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 1
+ - Name: .rdata
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 4
+ NumberOfRelocations: 1
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 2
+ - Name: function
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: fps
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/armnt-addr32-exec.s b/test/pecoff/Inputs/armnt-addr32-exec.s
new file mode 100644
index 000000000000..6a0776de7dd3
--- /dev/null
+++ b/test/pecoff/Inputs/armnt-addr32-exec.s
@@ -0,0 +1,24 @@
+
+# __declspec(dllexport) void function(void) { }
+# const void * const fps[] = { &function, };
+
+ .syntax unified
+ .thumb
+ .text
+
+ .def function
+ .scl 2
+ .type 32
+ .endef
+ .global function
+ .align 2
+ .thumb_func
+function:
+ bx lr
+
+ .section .rdata,"rd"
+ .global fps
+ .align 2
+fps:
+ .long function
+
diff --git a/test/pecoff/Inputs/armnt-addr32.obj.yaml b/test/pecoff/Inputs/armnt-addr32.obj.yaml
new file mode 100644
index 000000000000..62ae2c6ea992
--- /dev/null
+++ b/test/pecoff/Inputs/armnt-addr32.obj.yaml
@@ -0,0 +1,39 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_ARMNT
+ Characteristics: [ ]
+sections:
+ - Name: .rdata
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: '0000000000000000'
+ Relocations:
+ - VirtualAddress: 0
+ SymbolName: i
+ Type: 1
+symbols:
+ - Name: .rdata
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 8
+ NumberOfRelocations: 1
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 1
+ - Name: i
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: is
+ Value: 4
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/armnt-addr32.s b/test/pecoff/Inputs/armnt-addr32.s
new file mode 100644
index 000000000000..c718e9518af9
--- /dev/null
+++ b/test/pecoff/Inputs/armnt-addr32.s
@@ -0,0 +1,18 @@
+
+@ static const int i = 0;
+@ const int * const is[] = { &i, };
+
+ .syntax unified
+ .thumb
+ .text
+
+ .section .rdata,"rd"
+ .align 2 # @i
+i:
+ .long 0 # 0x0
+
+ .global is # @is
+ .align 2
+is:
+ .long i
+
diff --git a/test/pecoff/Inputs/armnt-blx23t.obj.yaml b/test/pecoff/Inputs/armnt-blx23t.obj.yaml
new file mode 100644
index 000000000000..03f82609f4e6
--- /dev/null
+++ b/test/pecoff/Inputs/armnt-blx23t.obj.yaml
@@ -0,0 +1,39 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_ARMNT
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_PURGEABLE, IMAGE_SCN_MEM_16BIT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 704700BF2DE90048EB46202000F000F80130BDE80088
+ Relocations:
+ - VirtualAddress: 12
+ SymbolName: identity
+ Type: 21
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 22
+ NumberOfRelocations: 1
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 1
+ - Name: identity
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: function
+ Value: 4
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/armnt-blx23t.s b/test/pecoff/Inputs/armnt-blx23t.s
new file mode 100644
index 000000000000..89aa4194faae
--- /dev/null
+++ b/test/pecoff/Inputs/armnt-blx23t.s
@@ -0,0 +1,33 @@
+
+# __declspec(noinline) int identity(int i) { return i; }
+# int function() { return identity(32) + 1; }
+
+ .syntax unified
+ .thumb
+ .text
+
+ .def identity
+ .scl 2
+ .type 32
+ .endef
+ .global identity
+ .align 2
+ .thumb_func
+identity:
+ bx lr
+
+ .def function
+ .scl 2
+ .type 32
+ .endef
+ .global function
+ .align 2
+ .thumb_func
+function:
+ push.w {r11, lr}
+ mov r11, sp
+ movs r0, 32
+ bl identity
+ adds r0, 1
+ pop.w {r11, pc}
+
diff --git a/test/pecoff/Inputs/armnt-branch24t.obj.yaml b/test/pecoff/Inputs/armnt-branch24t.obj.yaml
new file mode 100644
index 000000000000..02815a4957dd
--- /dev/null
+++ b/test/pecoff/Inputs/armnt-branch24t.obj.yaml
@@ -0,0 +1,39 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_ARMNT
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_PURGEABLE, IMAGE_SCN_MEM_16BIT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 704700BF202000F000B8
+ Relocations:
+ - VirtualAddress: 6
+ SymbolName: identity
+ Type: 20
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 10
+ NumberOfRelocations: 1
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 1
+ - Name: identity
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: function
+ Value: 4
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/armnt-branch24t.s b/test/pecoff/Inputs/armnt-branch24t.s
new file mode 100644
index 000000000000..8d85cbe0cab2
--- /dev/null
+++ b/test/pecoff/Inputs/armnt-branch24t.s
@@ -0,0 +1,26 @@
+
+# int ___declspec(noinline) identity(int i) { return i; }
+# int function(void) { return identity(32); }
+
+ .syntax unified
+ .thumb
+ .text
+
+ .def identity
+ .scl 2
+ .type 32
+ .endef
+ .global identity
+ .align 2
+ .thumb_func
+identity:
+ bx lr
+
+ .def function
+ .scl 2
+ .type 32
+ .endef
+function:
+ movs r0, 32
+ b identity
+
diff --git a/test/pecoff/Inputs/armnt-exports.def b/test/pecoff/Inputs/armnt-exports.def
new file mode 100644
index 000000000000..afb8258f95bc
--- /dev/null
+++ b/test/pecoff/Inputs/armnt-exports.def
@@ -0,0 +1,4 @@
+LIBRARY "armnt-exports"
+EXPORTS
+ function
+
diff --git a/test/pecoff/Inputs/armnt-exports.obj.yaml b/test/pecoff/Inputs/armnt-exports.obj.yaml
new file mode 100644
index 000000000000..2a971db2fdaa
--- /dev/null
+++ b/test/pecoff/Inputs/armnt-exports.obj.yaml
@@ -0,0 +1,35 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_ARMNT
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_PURGEABLE, IMAGE_SCN_MEM_16BIT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 704700BF7047
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 6
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 1
+ - Name: function
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _DllMainCRTStartup
+ Value: 4
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/armnt-import.obj.yaml b/test/pecoff/Inputs/armnt-import.obj.yaml
new file mode 100644
index 000000000000..08876eeb0d4c
--- /dev/null
+++ b/test/pecoff/Inputs/armnt-import.obj.yaml
@@ -0,0 +1,39 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_ARMNT
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_PURGEABLE, IMAGE_SCN_MEM_16BIT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 40F20000C0F2000000680047
+ Relocations:
+ - VirtualAddress: 0
+ SymbolName: __imp_function
+ Type: 17
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 12
+ NumberOfRelocations: 1
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 1
+ - Name: mainCRTStartup
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: __imp_function
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/armnt-import.s b/test/pecoff/Inputs/armnt-import.s
new file mode 100644
index 000000000000..2790d0edc8d9
--- /dev/null
+++ b/test/pecoff/Inputs/armnt-import.s
@@ -0,0 +1,21 @@
+
+# void __declspec(dllimport) function(void);
+# int mainCRTStartup(void) { return function(); }
+
+ .syntax unified
+ .thumb
+ .text
+
+ .def mainCRTStartup
+ .scl 2
+ .type 32
+ .endef
+ .global mainCRTStartup
+ .align 2
+ .thumb_func
+mainCRTStartup:
+ movw r0, :lower16:__imp_function
+ movt r0, :upper16:__imp_function
+ ldr r0, [r0]
+ bx r0
+
diff --git a/test/pecoff/Inputs/armnt-mov32t-exec.obj.yaml b/test/pecoff/Inputs/armnt-mov32t-exec.obj.yaml
new file mode 100644
index 000000000000..a4630bcb9e0e
--- /dev/null
+++ b/test/pecoff/Inputs/armnt-mov32t-exec.obj.yaml
@@ -0,0 +1,39 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_ARMNT
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_PURGEABLE, IMAGE_SCN_MEM_16BIT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 704700BF40F20000C0F200007047
+ Relocations:
+ - VirtualAddress: 4
+ SymbolName: function
+ Type: 17
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 14
+ NumberOfRelocations: 1
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 1
+ - Name: function
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: get_function
+ Value: 4
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/armnt-mov32t-exec.s b/test/pecoff/Inputs/armnt-mov32t-exec.s
new file mode 100644
index 000000000000..10a20f468c34
--- /dev/null
+++ b/test/pecoff/Inputs/armnt-mov32t-exec.s
@@ -0,0 +1,30 @@
+
+# void function(void) { }
+# void *get_function() { return &function; }
+
+ .syntax unified
+ .thumb
+ .text
+
+ .def function
+ .scl 2
+ .type 32
+ .endef
+ .global function
+ .align 2
+ .thumb_func
+function:
+ bx lr
+
+ .def get_function
+ .scl 2
+ .type 32
+ .endef
+ .global get_function
+ .align 2
+ .thumb_func
+get_function:
+ movw r0, :lower16:function
+ movt r0, :upper16:function
+ bx lr
+
diff --git a/test/pecoff/Inputs/armnt-mov32t.obj.yaml b/test/pecoff/Inputs/armnt-mov32t.obj.yaml
new file mode 100644
index 000000000000..21e890ace28f
--- /dev/null
+++ b/test/pecoff/Inputs/armnt-mov32t.obj.yaml
@@ -0,0 +1,55 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_ARMNT
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_PURGEABLE, IMAGE_SCN_MEM_16BIT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 40F20000C0F200007047
+ Relocations:
+ - VirtualAddress: 0
+ SymbolName: buffer
+ Type: 17
+ - Name: .rdata
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ SectionData: '62756666657200'
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 10
+ NumberOfRelocations: 1
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 1
+ - Name: .rdata
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 7
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 2
+ - Name: get_buffer
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: buffer
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+...
diff --git a/test/pecoff/Inputs/armnt-mov32t.s b/test/pecoff/Inputs/armnt-mov32t.s
new file mode 100644
index 000000000000..289f917597d6
--- /dev/null
+++ b/test/pecoff/Inputs/armnt-mov32t.s
@@ -0,0 +1,24 @@
+
+# static const char buffer[] = "buffer";
+# const char *get_buffer() { return buffer; }
+
+ .syntax unified
+ .thumb
+ .text
+
+ .def get_buffer
+ .scl 2
+ .type 32
+ .endef
+ .global get_buffer
+ .align 2
+ .thumb_func
+get_buffer:
+ movw r0, :lower16:buffer
+ movt r0, :upper16:buffer
+ bx lr
+
+ .section .rdata,"rd"
+buffer:
+ .asciz "buffer"
+
diff --git a/test/pecoff/Inputs/armnt-obj.s b/test/pecoff/Inputs/armnt-obj.s
new file mode 100644
index 000000000000..20eeab0e1dda
--- /dev/null
+++ b/test/pecoff/Inputs/armnt-obj.s
@@ -0,0 +1,12 @@
+
+ .syntax unified
+ .thumb
+ .text
+
+ .def main
+ .scl 2
+ .type 32
+ .endef
+main:
+ bx lr
+
diff --git a/test/pecoff/Inputs/armnt-obj.yaml b/test/pecoff/Inputs/armnt-obj.yaml
new file mode 100644
index 000000000000..7c53c6f00693
--- /dev/null
+++ b/test/pecoff/Inputs/armnt-obj.yaml
@@ -0,0 +1,29 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_ARMNT
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_PURGEABLE, IMAGE_SCN_MEM_16BIT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: '7047'
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 2
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 1
+ - Name: main
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/associative1.obj.yaml b/test/pecoff/Inputs/associative1.obj.yaml
new file mode 100644
index 000000000000..51a7be0b34d7
--- /dev/null
+++ b/test/pecoff/Inputs/associative1.obj.yaml
@@ -0,0 +1,53 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: []
+sections:
+ - Name: .data
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 4
+ SectionData: 00000000
+ - Name: '.CRT$XCU'
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 77777777
+symbols:
+ - Name: .data
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 4
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ Selection: IMAGE_COMDAT_SELECT_ANY
+ - Name: _var
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: '.CRT$XCU'
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 4
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 1
+ Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE
+ - Name: _init
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/associative3.obj.yaml b/test/pecoff/Inputs/associative3.obj.yaml
new file mode 100644
index 000000000000..ffea761a357c
--- /dev/null
+++ b/test/pecoff/Inputs/associative3.obj.yaml
@@ -0,0 +1,33 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: []
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 0000000000000000
+ Relocations:
+ - VirtualAddress: 4
+ SymbolName: _var
+ Type: IMAGE_REL_I386_DIR32
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: _main
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _var
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/basereloc.obj.yaml b/test/pecoff/Inputs/basereloc.obj.yaml
new file mode 100644
index 000000000000..5e5ca16a0ac7
--- /dev/null
+++ b/test/pecoff/Inputs/basereloc.obj.yaml
@@ -0,0 +1,164 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4096
+ SectionData: B800000000506800000000680000000050E80000000050E80000000050E800000000
+ Relocations:
+ - VirtualAddress: 0
+ SymbolName: abs_symbol
+ Type: IMAGE_REL_I386_DIR32
+ - VirtualAddress: 7
+ SymbolName: caption
+ Type: IMAGE_REL_I386_DIR32
+ - VirtualAddress: 12
+ SymbolName: message
+ Type: IMAGE_REL_I386_DIR32
+ - VirtualAddress: 18
+ SymbolName: _MessageBoxA@16
+ Type: IMAGE_REL_I386_REL32
+ - VirtualAddress: 24
+ SymbolName: _ExitProcess@4
+ Type: IMAGE_REL_I386_REL32
+ - VirtualAddress: 30
+ SymbolName: ___ImageBase
+ Type: IMAGE_REL_I386_DIR32
+ - Name: .text2
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4096
+ SectionData: B800000000506800000000680000000050E80000000050E80000000050E800000000
+ Relocations:
+ - VirtualAddress: 0
+ SymbolName: abs_symbol
+ Type: IMAGE_REL_I386_DIR32
+ - VirtualAddress: 7
+ SymbolName: caption
+ Type: IMAGE_REL_I386_DIR32
+ - VirtualAddress: 12
+ SymbolName: message
+ Type: IMAGE_REL_I386_DIR32
+ - VirtualAddress: 18
+ SymbolName: _MessageBoxA@16
+ Type: IMAGE_REL_I386_REL32
+ - VirtualAddress: 24
+ SymbolName: _ExitProcess@4
+ Type: IMAGE_REL_I386_REL32
+ - VirtualAddress: 30
+ SymbolName: ___ImageBase
+ Type: IMAGE_REL_I386_DIR32
+ - Name: .data
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 4
+ SectionData: 48656C6C6F0048656C6C6F20576F726C6400
+ - Name: .drectve
+ Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+ Alignment: 2147483648
+ SectionData: 2F454E5452593A6D61696E20
+symbols:
+ - Name: "@comp.id"
+ Value: 10394907
+ SectionNumber: 65535
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 28
+ NumberOfRelocations: 6
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: .text2
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 28
+ NumberOfRelocations: 6
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: .data
+ Value: 0
+ SectionNumber: 3
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 18
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: _MessageBoxA@16
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _ExitProcess@4
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: message
+ Value: 6
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: _main
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: caption
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: .drectve
+ Value: 0
+ SectionNumber: 3
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 12
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: .file
+ Value: 0
+ SectionNumber: 65534
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ File: "hello.c"
+ - Name: abs_symbol
+ Value: 0xDEADBEEF
+ SectionNumber: -1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: ___ImageBase
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/bss.asm b/test/pecoff/Inputs/bss.asm
new file mode 100644
index 000000000000..802edee8591d
--- /dev/null
+++ b/test/pecoff/Inputs/bss.asm
@@ -0,0 +1,20 @@
+.586
+.model flat, c
+
+extern ExitProcess@4 : PROC
+
+_BSS SEGMENT
+ _x DD 064H DUP (?)
+ _y DD 064H DUP (?)
+_BSS ENDS
+
+.code
+start:
+ mov eax, 42
+ mov _x, eax
+ mov eax, _x
+ push eax
+ call ExitProcess@4
+end start
+
+end
diff --git a/test/pecoff/Inputs/bss.obj b/test/pecoff/Inputs/bss.obj
new file mode 100644
index 000000000000..3c00dfeb830b
--- /dev/null
+++ b/test/pecoff/Inputs/bss.obj
Binary files differ
diff --git a/test/pecoff/Inputs/comdat.obj.yaml b/test/pecoff/Inputs/comdat.obj.yaml
new file mode 100644
index 000000000000..5537499873a3
--- /dev/null
+++ b/test/pecoff/Inputs/comdat.obj.yaml
@@ -0,0 +1,53 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: 558BEC33C05DC3
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: 558BEC33C05DC3
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 7
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 2532800969
+ Number: 0
+ Selection: IMAGE_COMDAT_SELECT_ANY
+ - Name: .text
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 7
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 2532800969
+ Number: 0
+ Selection: IMAGE_COMDAT_SELECT_ANY
+ - Name: "?inlinefn1@@YAHXZ"
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: "?inlinefn2@@YAHXZ"
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/common-symbol.obj.yaml b/test/pecoff/Inputs/common-symbol.obj.yaml
new file mode 100644
index 000000000000..05ddd022f286
--- /dev/null
+++ b/test/pecoff/Inputs/common-symbol.obj.yaml
@@ -0,0 +1,85 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: b800000000b800000000b800000000b800000000b800000000
+ Relocations:
+ - VirtualAddress: 1
+ SymbolName: _bssdata4
+ Type: IMAGE_REL_AMD64_ADDR32
+ - VirtualAddress: 6
+ SymbolName: _bsspad1
+ Type: IMAGE_REL_AMD64_ADDR32
+ - VirtualAddress: 11
+ SymbolName: _bssdata64
+ Type: IMAGE_REL_AMD64_ADDR32
+ - VirtualAddress: 16
+ SymbolName: _bsspad2
+ Type: IMAGE_REL_AMD64_ADDR32
+ - VirtualAddress: 21
+ SymbolName: _bssdata16
+ Type: IMAGE_REL_AMD64_ADDR32
+ - Name: .data
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 4
+ SectionData: 03000000
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 0
+ NumberOfRelocations: 5
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: .data
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 4
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: _bssdata4
+ Value: 4
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _bsspad1
+ Value: 1
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _bssdata64
+ Value: 64
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _bsspad2
+ Value: 1
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _bssdata16
+ Value: 16
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/drectve.obj.yaml b/test/pecoff/Inputs/drectve.obj.yaml
new file mode 100644
index 000000000000..22ec63f96e3e
--- /dev/null
+++ b/test/pecoff/Inputs/drectve.obj.yaml
@@ -0,0 +1,79 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: 558BEC56FF15000000008B0D000000008B3103F0FF150000000003C65E5DC3
+ Relocations:
+ - VirtualAddress: 6
+ SymbolName: __imp__fn
+ Type: IMAGE_REL_I386_DIR32
+ - VirtualAddress: 12
+ SymbolName: __imp__var
+ Type: IMAGE_REL_I386_DIR32
+ - VirtualAddress: 22
+ SymbolName: __imp___name_with_underscore
+ Type: IMAGE_REL_I386_DIR32
+ - Name: .drectve
+ Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+ Alignment: 2147483648
+ SectionData: 2f64656661756c746c69623a766172732e6c6962202f73756273797374656d3a636f6e736f6c652c34322e313935202d3f666f6f00
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 31
+ NumberOfRelocations: 3
+ NumberOfLinenumbers: 0
+ CheckSum: 3595596940
+ Number: 0
+ - Name: __imp__fn
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: __imp___name_with_underscore
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _main
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: __imp__var
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _fn
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: .drectve
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 13
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+...
diff --git a/test/pecoff/Inputs/drectve2.obj.yaml b/test/pecoff/Inputs/drectve2.obj.yaml
new file mode 100644
index 000000000000..836cbc3e743d
--- /dev/null
+++ b/test/pecoff/Inputs/drectve2.obj.yaml
@@ -0,0 +1,45 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: 558BEC56FF15000000008B0D000000008B3103F0FF150000000003C65E5DC3
+ - Name: .drectve
+ Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+ Alignment: 2147483648
+ SectionData: 2f696e636c7564653a666f6f00
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 31
+ NumberOfRelocations: 3
+ NumberOfLinenumbers: 0
+ CheckSum: 3595596940
+ Number: 0
+ - Name: _main
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: .drectve
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 13
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+...
diff --git a/test/pecoff/Inputs/drectve3.lib b/test/pecoff/Inputs/drectve3.lib
new file mode 100644
index 000000000000..c295d1ff6d04
--- /dev/null
+++ b/test/pecoff/Inputs/drectve3.lib
Binary files differ
diff --git a/test/pecoff/Inputs/entry.obj.yaml b/test/pecoff/Inputs/entry.obj.yaml
new file mode 100644
index 000000000000..35eae143c430
--- /dev/null
+++ b/test/pecoff/Inputs/entry.obj.yaml
@@ -0,0 +1,40 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: [ ]
+
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: A100000000030500000000C3
+
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+
+ - Name: _foo
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+
+ - Name: _bar
+ Value: 4
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+
+ - Name: "?baz@@YAXXZ"
+ Value: 4
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/executable.obj.yaml b/test/pecoff/Inputs/executable.obj.yaml
new file mode 100644
index 000000000000..73ba0fe71914
--- /dev/null
+++ b/test/pecoff/Inputs/executable.obj.yaml
@@ -0,0 +1,29 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_ARMNT
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_PURGEABLE, IMAGE_SCN_MEM_16BIT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: '7047'
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 2
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 1
+ - Name: mainCRTStartup
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/executable.s b/test/pecoff/Inputs/executable.s
new file mode 100644
index 000000000000..1c58f7331b26
--- /dev/null
+++ b/test/pecoff/Inputs/executable.s
@@ -0,0 +1,17 @@
+
+# void mainCRTStartup(){}
+
+ .syntax unified
+ .thumb
+ .text
+
+ .def mainCRTStartup
+ .scl 2
+ .type 32
+ .endef
+ .global mainCRTStartup
+ .align 2
+ .thumb_func
+mainCRTStartup:
+ bx lr
+
diff --git a/test/pecoff/Inputs/export.obj.yaml b/test/pecoff/Inputs/export.obj.yaml
new file mode 100644
index 000000000000..fa92cd09bee4
--- /dev/null
+++ b/test/pecoff/Inputs/export.obj.yaml
@@ -0,0 +1,69 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: []
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: B800000000506800000000680000000050E80000000050E800000000
+ - Name: .drectve
+ Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+ Alignment: 2147483648
+ SectionData: 2f6578706f72743a5f6578706f7274666e334032353600 # /export:_exportfn3@256
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 28
+ NumberOfRelocations: 4
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: _init
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _exportfn1
+ Value: 8
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _exportfn2
+ Value: 16
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _exportfn3@256
+ Value: 16
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _exportfn6
+ Value: 16
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _exportfn7@8
+ Value: 16
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: "?exportfn8@@YAXXZ"
+ Value: 16
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/exports.def b/test/pecoff/Inputs/exports.def
new file mode 100644
index 000000000000..7b444f9719d1
--- /dev/null
+++ b/test/pecoff/Inputs/exports.def
@@ -0,0 +1,6 @@
+; This is a comment line
+
+EXPORTS
+ exportfn1 @5 ; foo
+ exportfn2
+ exportfn5=exportfn6 PRIVATE
diff --git a/test/pecoff/Inputs/exports2.def b/test/pecoff/Inputs/exports2.def
new file mode 100644
index 000000000000..1c95f42ceb60
--- /dev/null
+++ b/test/pecoff/Inputs/exports2.def
@@ -0,0 +1,6 @@
+; This is a comment line
+
+EXPORTS
+ exportfn1 @5 ; foo
+ exportfn7
+ exportfn5=exportfn6 PRIVATE
diff --git a/test/pecoff/Inputs/grouped-sections.asm b/test/pecoff/Inputs/grouped-sections.asm
new file mode 100644
index 000000000000..af69363efefb
--- /dev/null
+++ b/test/pecoff/Inputs/grouped-sections.asm
@@ -0,0 +1,18 @@
+.386
+.model flat, c
+
+_data$2 SEGMENT BYTE alias(".data$2")
+ db "orld", 0
+_data$2 ends
+
+_data$1 SEGMENT BYTE alias(".data$1")
+ db "o, w"
+_data$1 ends
+
+.data
+ db "Hell"
+
+.code
+main:
+ nop
+end main
diff --git a/test/pecoff/Inputs/grouped-sections.obj.yaml b/test/pecoff/Inputs/grouped-sections.obj.yaml
new file mode 100644
index 000000000000..2180312acf92
--- /dev/null
+++ b/test/pecoff/Inputs/grouped-sections.obj.yaml
@@ -0,0 +1,83 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 90
+ - Name: .data
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 4
+ SectionData: 48656C6C
+ - Name: ".data$2"
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 1
+ SectionData: 6F726C6400
+ - Name: ".data$1"
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 1
+ SectionData: 6F2C2077
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 1
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: .data
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 4
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: ".data$2"
+ Value: 0
+ SectionNumber: 3
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 5
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: ".data$1"
+ Value: 0
+ SectionNumber: 4
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 4
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: foo
+ Value: 2
+ SectionNumber: 4
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: _main
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/hello.asm b/test/pecoff/Inputs/hello.asm
new file mode 100644
index 000000000000..e360bbf65706
--- /dev/null
+++ b/test/pecoff/Inputs/hello.asm
@@ -0,0 +1,24 @@
+;;; ml hello.asm /link /subsystem:windows /defaultlib:kernel32.lib \
+;;; /defaultlib:user32.lib /out:hello.exe /entry:main
+
+.386
+.model flat, c
+
+extern MessageBoxA@16 : PROC
+extern ExitProcess@4 : PROC
+
+.data
+ caption db "Hello", 0
+ message db "Hello World", 0
+
+.code
+main:
+ mov eax, 0
+ push eax
+ push offset caption
+ push offset message
+ push eax
+ call MessageBoxA@16
+ push eax
+ call ExitProcess@4
+end main
diff --git a/test/pecoff/Inputs/hello.obj.yaml b/test/pecoff/Inputs/hello.obj.yaml
new file mode 100644
index 000000000000..6268a74057bd
--- /dev/null
+++ b/test/pecoff/Inputs/hello.obj.yaml
@@ -0,0 +1,111 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: B800000000506800000000680000000050E80000000050E800000000
+ Relocations:
+ - VirtualAddress: 7
+ SymbolName: caption
+ Type: IMAGE_REL_I386_DIR32
+ - VirtualAddress: 12
+ SymbolName: message
+ Type: IMAGE_REL_I386_DIR32
+ - VirtualAddress: 18
+ SymbolName: _MessageBoxA@16
+ Type: IMAGE_REL_I386_REL32
+ - VirtualAddress: 24
+ SymbolName: _ExitProcess@4
+ Type: IMAGE_REL_I386_REL32
+ - Name: .data
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 4
+ SectionData: 48656C6C6F0048656C6C6F20576F726C6400
+ - Name: .drectve
+ Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+ Alignment: 2147483648
+ SectionData: 2F454E5452593A6D61696E20
+symbols:
+ - Name: "@comp.id"
+ Value: 10394907
+ SectionNumber: 65535
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 28
+ NumberOfRelocations: 4
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: .data
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 18
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: _MessageBoxA@16
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _ExitProcess@4
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: message
+ Value: 6
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: _main
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: caption
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: .drectve
+ Value: 0
+ SectionNumber: 3
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 12
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: .file
+ Value: 0
+ SectionNumber: 65534
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ File: "hello.c"
+...
diff --git a/test/pecoff/Inputs/hello64.asm b/test/pecoff/Inputs/hello64.asm
new file mode 100644
index 000000000000..bc1a41b500d0
--- /dev/null
+++ b/test/pecoff/Inputs/hello64.asm
@@ -0,0 +1,22 @@
+;; ml hello64.asm /link /subsystem:windows /defaultlib:kernel32 \
+;; /defaultlib:user32 /out:hello64.exe /entry:main
+
+extern ExitProcess : PROC
+extern MessageBoxA : PROC
+
+.data
+ caption db 'Hello', 0
+ message db 'Hello World', 0
+
+.code
+main PROC
+ sub rsp,28h
+ mov rcx, 0
+ lea rdx, message
+ lea r8, caption
+ mov r9d, 0
+ call MessageBoxA
+ mov ecx, 0
+ call ExitProcess
+main ENDP
+END
diff --git a/test/pecoff/Inputs/hello64.obj.yaml b/test/pecoff/Inputs/hello64.obj.yaml
new file mode 100644
index 000000000000..36b699623101
--- /dev/null
+++ b/test/pecoff/Inputs/hello64.obj.yaml
@@ -0,0 +1,110 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: [ ]
+sections:
+ - Name: '.text$mn'
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: 4883EC2848C7C100000000488D15000000004C8D050000000041B900000000E800000000B900000000E800000000
+ Relocations:
+ - VirtualAddress: 14
+ SymbolName: message
+ Type: IMAGE_REL_AMD64_REL32
+ - VirtualAddress: 21
+ SymbolName: caption
+ Type: IMAGE_REL_AMD64_REL32
+ - VirtualAddress: 32
+ SymbolName: MessageBoxA
+ Type: IMAGE_REL_AMD64_REL32
+ - VirtualAddress: 42
+ SymbolName: ExitProcess
+ Type: IMAGE_REL_AMD64_REL32
+ - Name: .data
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 16
+ SectionData: 48656C6C6F0048656C6C6F20576F726C6400
+ - Name: '.debug$S'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ SectionData: 04000000F1000000830000004800011100000000433A5C63796777696E5C686F6D655C727569755C6C6C766D5C746F6F6C735C6C6C645C746573745C7065636F66665C496E707574735C68656C6C6F36342E6F626A0037003C1103020000D00000000000000000000C0000000D5201004D6963726F736F667420285229204D6163726F20417373656D626C6572000000
+symbols:
+ - Name: '@comp.id'
+ Value: 14635533
+ SectionNumber: 65535
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: '@feat.00'
+ Value: 16
+ SectionNumber: 65535
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: '.text$mn'
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 46
+ NumberOfRelocations: 4
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: .data
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 18
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: '.debug$S'
+ Value: 0
+ SectionNumber: 3
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 144
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: ExitProcess
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: MessageBoxA
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: message
+ Value: 6
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: caption
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: main
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/hello64lib.asm b/test/pecoff/Inputs/hello64lib.asm
new file mode 100644
index 000000000000..89f95cd49af1
--- /dev/null
+++ b/test/pecoff/Inputs/hello64lib.asm
@@ -0,0 +1,14 @@
+.code
+ExitProcess PROC
+ RET
+ExitProcess ENDP
+
+MessageBoxA PROC
+ RET
+MessageBoxA ENDP
+
+_DllMainCRTStartup PROC
+ RET
+_DllMainCRTStartup ENDP
+
+END
diff --git a/test/pecoff/Inputs/hello64lib.lib b/test/pecoff/Inputs/hello64lib.lib
new file mode 100644
index 000000000000..3109c32593ca
--- /dev/null
+++ b/test/pecoff/Inputs/hello64lib.lib
Binary files differ
diff --git a/test/pecoff/Inputs/imagebase.obj.yaml b/test/pecoff/Inputs/imagebase.obj.yaml
new file mode 100644
index 000000000000..e31e744fa058
--- /dev/null
+++ b/test/pecoff/Inputs/imagebase.obj.yaml
@@ -0,0 +1,55 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: A100000000C3
+ Relocations:
+ - VirtualAddress: 1
+ SymbolName: ___ImageBase
+ Type: IMAGE_REL_I386_DIR32
+ - Name: .data
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 16
+ SectionData: ""
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 6
+ NumberOfRelocations: 1
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: .data
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 0
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: ___ImageBase
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: __start
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/library.lib b/test/pecoff/Inputs/library.lib
new file mode 100755
index 000000000000..2f4207d7983d
--- /dev/null
+++ b/test/pecoff/Inputs/library.lib
Binary files differ
diff --git a/test/pecoff/Inputs/machine-type-unknown.obj.yaml b/test/pecoff/Inputs/machine-type-unknown.obj.yaml
new file mode 100644
index 000000000000..f0da1ea7ac34
--- /dev/null
+++ b/test/pecoff/Inputs/machine-type-unknown.obj.yaml
@@ -0,0 +1,38 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_UNKNOWN
+ Characteristics: []
+sections:
+ - Name: .drectve
+ Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+ Alignment: 2147483648
+ SectionData: ''
+symbols:
+ - Name: '@comp.id'
+ Value: 1
+ SectionNumber: 65535
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: '@feat.00'
+ Value: 1
+ SectionNumber: 65535
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: __imp___close
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: __imp__close
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_WEAK_EXTERNAL
+ WeakExternal:
+ TagIndex: 2
+ Characteristics: IMAGE_WEAK_EXTERN_SEARCH_ALIAS
+...
diff --git a/test/pecoff/Inputs/main.obj.yaml b/test/pecoff/Inputs/main.obj.yaml
new file mode 100644
index 000000000000..73a788049063
--- /dev/null
+++ b/test/pecoff/Inputs/main.obj.yaml
@@ -0,0 +1,70 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: A100000000030500000000C3
+ Relocations:
+ - VirtualAddress: 1
+ SymbolName: _val1
+ Type: IMAGE_REL_I386_DIR32
+ - VirtualAddress: 7
+ SymbolName: _val2
+ Type: IMAGE_REL_I386_DIR32
+ - Name: .data
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 4
+ SectionData: ""
+symbols:
+ - Name: "@comp.id"
+ Value: 10394907
+ SectionNumber: 65535
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 12
+ NumberOfRelocations: 2
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: .data
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 0
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: _val1
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _val2
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _main
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/merge-largest1.obj.yaml b/test/pecoff/Inputs/merge-largest1.obj.yaml
new file mode 100644
index 000000000000..e372f9030603
--- /dev/null
+++ b/test/pecoff/Inputs/merge-largest1.obj.yaml
@@ -0,0 +1,30 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: 00112233
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 7
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 2532800969
+ Number: 0
+ Selection: IMAGE_COMDAT_SELECT_LARGEST
+ - Name: "_foo"
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/merge-largest2.obj.yaml b/test/pecoff/Inputs/merge-largest2.obj.yaml
new file mode 100644
index 000000000000..f232cd3fd870
--- /dev/null
+++ b/test/pecoff/Inputs/merge-largest2.obj.yaml
@@ -0,0 +1,30 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: 0011223344556677
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 7
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 2532800969
+ Number: 0
+ Selection: IMAGE_COMDAT_SELECT_LARGEST
+ - Name: "_foo"
+ Value: 6
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/merge-same-size1.obj.yaml b/test/pecoff/Inputs/merge-same-size1.obj.yaml
new file mode 100644
index 000000000000..02516f37220e
--- /dev/null
+++ b/test/pecoff/Inputs/merge-same-size1.obj.yaml
@@ -0,0 +1,30 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: FFFFFFFFFFFFFF
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 7
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 2532800969
+ Number: 0
+ Selection: IMAGE_COMDAT_SELECT_SAME_SIZE
+ - Name: "_foo"
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/merge-same-size2.obj.yaml b/test/pecoff/Inputs/merge-same-size2.obj.yaml
new file mode 100644
index 000000000000..6b5b593bbab1
--- /dev/null
+++ b/test/pecoff/Inputs/merge-same-size2.obj.yaml
@@ -0,0 +1,30 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: AAAAAAAAAAAAAA
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 7
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 2532800969
+ Number: 0
+ Selection: IMAGE_COMDAT_SELECT_SAME_SIZE
+ - Name: "_foo"
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/merge-same-size3.obj.yaml b/test/pecoff/Inputs/merge-same-size3.obj.yaml
new file mode 100644
index 000000000000..47ad417f2f0c
--- /dev/null
+++ b/test/pecoff/Inputs/merge-same-size3.obj.yaml
@@ -0,0 +1,30 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: FFFF
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 2
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 2532800969
+ Number: 0
+ Selection: IMAGE_COMDAT_SELECT_SAME_SIZE
+ - Name: "_foo"
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/nonstandard-sections.obj.yaml b/test/pecoff/Inputs/nonstandard-sections.obj.yaml
new file mode 100644
index 000000000000..b80d8862ec61
--- /dev/null
+++ b/test/pecoff/Inputs/nonstandard-sections.obj.yaml
@@ -0,0 +1,53 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: []
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 01234678
+ - Name: .data
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 4
+ SectionData: 01234678
+ - Name: .foo
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE, IMAGE_SCN_MEM_EXECUTE ]
+ Alignment: 4
+ SectionData: 01234678
+ - Name: .bar
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 01234678
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: .data
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: .foo
+ Value: 0
+ SectionNumber: 3
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: .bar
+ Value: 0
+ SectionNumber: 4
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: _main
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/nop.asm b/test/pecoff/Inputs/nop.asm
new file mode 100644
index 000000000000..8e53070e7f5c
--- /dev/null
+++ b/test/pecoff/Inputs/nop.asm
@@ -0,0 +1,9 @@
+.386
+.model flat, stdcall
+option casemap :none
+
+.code
+start:
+ mov eax, 42
+ ret
+end start
diff --git a/test/pecoff/Inputs/nop.obj.yaml b/test/pecoff/Inputs/nop.obj.yaml
new file mode 100644
index 000000000000..ccc097e7c926
--- /dev/null
+++ b/test/pecoff/Inputs/nop.obj.yaml
@@ -0,0 +1,51 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: B82A000000C3
+ - Name: .data
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 4
+ SectionData: ""
+symbols:
+ - Name: "@comp.id"
+ Value: 10394907
+ SectionNumber: 65535
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 6
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: .data
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 0
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: _start
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/nop64.obj.yaml b/test/pecoff/Inputs/nop64.obj.yaml
new file mode 100644
index 000000000000..66edc376a90e
--- /dev/null
+++ b/test/pecoff/Inputs/nop64.obj.yaml
@@ -0,0 +1,67 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: C3C3C3C3
+ Relocations:
+ - VirtualAddress: 0
+ SymbolName: __imp__fn
+ Type: IMAGE_REL_AMD64_REL32
+ - Name: .data
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 16
+ SectionData: ''
+symbols:
+ - Name: '@comp.id'
+ Value: 13485607
+ SectionNumber: 65535
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: '@feat.00'
+ Value: 16
+ SectionNumber: 65535
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 1
+ NumberOfRelocations: 1
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: .data
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 0
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: __imp__fn
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: start
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/reloc.obj.yaml b/test/pecoff/Inputs/reloc.obj.yaml
new file mode 100644
index 000000000000..4c83258c623c
--- /dev/null
+++ b/test/pecoff/Inputs/reloc.obj.yaml
@@ -0,0 +1,82 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: 680000000068000000006800000000680000000068000000006800000000
+ Relocations:
+ - VirtualAddress: 1
+ SymbolName: _message
+ Type: IMAGE_REL_I386_SECTION
+ - VirtualAddress: 6
+ SymbolName: _message
+ Type: IMAGE_REL_I386_SECREL
+ - VirtualAddress: 11
+ SymbolName: .data
+ Type: IMAGE_REL_I386_DIR32
+ - VirtualAddress: 16
+ SymbolName: .data
+ Type: IMAGE_REL_I386_DIR32
+ - VirtualAddress: 21
+ SymbolName: __imp__MessageBoxA@16
+ Type: IMAGE_REL_I386_DIR32
+ - VirtualAddress: 26
+ SymbolName: _abs_value
+ Type: IMAGE_REL_I386_DIR32
+ - Name: .data
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 4
+ SectionData: 576F726C64210048656C6C6F2C00
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 60
+ NumberOfRelocations: 3
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 1
+ - Name: .data
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 14
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 2
+ - Name: _main
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _message
+ Value: 5
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: __imp__MessageBoxA@16
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _abs_value
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/reloc64.obj.yaml b/test/pecoff/Inputs/reloc64.obj.yaml
new file mode 100644
index 000000000000..3230ca51c6cc
--- /dev/null
+++ b/test/pecoff/Inputs/reloc64.obj.yaml
@@ -0,0 +1,63 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: []
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: 48B800000000000000ffE8000000ffE8000000ffE8000000ffE8000000ffE8000000ffE8000000ffE8000000ffE8000000ffC3
+ Relocations:
+ - VirtualAddress: 2
+ SymbolName: end
+ Type: IMAGE_REL_AMD64_ADDR64
+ - VirtualAddress: 11
+ SymbolName: end
+ Type: IMAGE_REL_AMD64_REL32
+ - VirtualAddress: 16
+ SymbolName: end
+ Type: IMAGE_REL_AMD64_REL32_1
+ - VirtualAddress: 21
+ SymbolName: end
+ Type: IMAGE_REL_AMD64_REL32_2
+ - VirtualAddress: 26
+ SymbolName: end
+ Type: IMAGE_REL_AMD64_REL32_3
+ - VirtualAddress: 31
+ SymbolName: end
+ Type: IMAGE_REL_AMD64_REL32_4
+ - VirtualAddress: 36
+ SymbolName: end
+ Type: IMAGE_REL_AMD64_REL32_5
+ - VirtualAddress: 41
+ SymbolName: end
+ Type: IMAGE_REL_AMD64_SECTION
+ - VirtualAddress: 46
+ SymbolName: end
+ Type: IMAGE_REL_AMD64_SECREL
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 41
+ NumberOfRelocations: 7
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: entry
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: end
+ Value: 40
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/resource.rc b/test/pecoff/Inputs/resource.rc
new file mode 100644
index 000000000000..df933e83b77a
--- /dev/null
+++ b/test/pecoff/Inputs/resource.rc
@@ -0,0 +1,4 @@
+STRINGTABLE
+{
+ 1, "Hello"
+}
diff --git a/test/pecoff/Inputs/resource.res b/test/pecoff/Inputs/resource.res
new file mode 100755
index 000000000000..f1c799fbbb08
--- /dev/null
+++ b/test/pecoff/Inputs/resource.res
Binary files differ
diff --git a/test/pecoff/Inputs/responsefile.txt b/test/pecoff/Inputs/responsefile.txt
new file mode 100644
index 000000000000..08286119d4ed
--- /dev/null
+++ b/test/pecoff/Inputs/responsefile.txt
@@ -0,0 +1 @@
+-foo -bar\baz
diff --git a/test/pecoff/Inputs/secrel1.obj.yaml b/test/pecoff/Inputs/secrel1.obj.yaml
new file mode 100644
index 000000000000..1c49261bbc43
--- /dev/null
+++ b/test/pecoff/Inputs/secrel1.obj.yaml
@@ -0,0 +1,69 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: C3
+ - Name: .data
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 4
+ SectionData: 00000000000000000000000000000000
+ Relocations:
+ - VirtualAddress: 0
+ SymbolName: .data
+ Type: IMAGE_REL_I386_SECREL
+ - Name: .data2
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 4
+ SectionData: 00000000000000000000000000000000
+ Relocations:
+ - VirtualAddress: 0
+ SymbolName: .data2
+ Type: IMAGE_REL_I386_SECREL
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 60
+ NumberOfRelocations: 1
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 1
+ - Name: .data
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 4
+ NumberOfRelocations: 1
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 2
+ - Name: .data2
+ Value: 0
+ SectionNumber: 3
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 4
+ NumberOfRelocations: 1
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 3
+ - Name: _main
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/secrel2.obj.yaml b/test/pecoff/Inputs/secrel2.obj.yaml
new file mode 100644
index 000000000000..2885fd07bb3a
--- /dev/null
+++ b/test/pecoff/Inputs/secrel2.obj.yaml
@@ -0,0 +1,47 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: [ ]
+sections:
+ - Name: .data
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 4
+ SectionData: 00000000000000000000000000000000
+ Relocations:
+ - VirtualAddress: 0
+ SymbolName: .data
+ Type: IMAGE_REL_I386_SECREL
+ - Name: .data2
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 4
+ SectionData: 00000000000000000000000000000000
+ Relocations:
+ - VirtualAddress: 0
+ SymbolName: .data2
+ Type: IMAGE_REL_I386_SECREL
+symbols:
+ - Name: .data
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 4
+ NumberOfRelocations: 1
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 1
+ - Name: .data2
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 4
+ NumberOfRelocations: 1
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 2
+...
diff --git a/test/pecoff/Inputs/seh.c b/test/pecoff/Inputs/seh.c
new file mode 100644
index 000000000000..b1c139a58f22
--- /dev/null
+++ b/test/pecoff/Inputs/seh.c
@@ -0,0 +1,13 @@
+__declspec(noinline) void triggerSEH() {
+ volatile int *p = 0;
+ *p = 1;
+}
+
+int main() {
+ __try {
+ triggerSEH();
+ } __except(1) {
+ return 42;
+ }
+ return 0;
+}
diff --git a/test/pecoff/Inputs/seh.obj.yaml b/test/pecoff/Inputs/seh.obj.yaml
new file mode 100644
index 000000000000..6767671cdafe
--- /dev/null
+++ b/test/pecoff/Inputs/seh.obj.yaml
@@ -0,0 +1,387 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: [ ]
+sections:
+ - Name: .drectve
+ Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+ Alignment: 1
+ SectionData: 2020202F44454641554C544C49423A22757569642E6C696222202F44454641554C544C49423A22757569642E6C696222202F4641494C49464D49534D415443483A225F4D53435F5645523D3138303022202F4641494C49464D49534D415443483A225F4954455241544F525F44454255475F4C4556454C3D3022202F4641494C49464D49534D415443483A2252756E74696D654C6962726172793D4D445F44796E616D696352656C6561736522202F44454641554C544C49423A226D73766370727422202F44454641554C544C49423A224D535643525422202F44454641554C544C49423A224F4C444E414D45532220
+ - Name: '.debug$S'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ SectionData: 04000000F1000000600000002200011100000000433A5C63796777696E5C686F6D655C727569755C7365682E6F626A003A003C11012200000700120000000D520100120000000D5201004D6963726F736F667420285229204F7074696D697A696E6720436F6D70696C657200
+ - Name: .rdata
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ SectionData: 00
+ - Name: .rdata
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ SectionData: 01
+ - Name: .rdata
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 54726967676572696E672053454820657863657074696F6E0D0A0000457865637574696E6720534548205F5F65786365707420626C6F636B20696E20666F6F0D0A000000457865637574696E6720534548205F5F65786365707420626C6F636B0D0A00
+ - Name: '.text$mn'
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: 558BEC516800000000FF150000000083C404C745FC000000008B45FCC700140000008BE55DC3CCCCCCCCCCCCCCCCCCCC558BEC51E8000000008D4DFFE8000000008BE55DC3CCCCCCCCCCCCCCCCCCCCCC558BEC6AFE6800000000680000000064A1000000005083EC08535657A1000000003145F833C5508D45F064A3000000008965E8C745FC00000000E800000000C745FCFEFFFFFFEB1EB801000000C38B65E86800000000FF150000000083C404C745FCFEFFFFFF8B4DF064890D00000000595F5E5B8BE55DC3CCCCCCCCCCCCCCCC558BEC6AFE6800000000680000000064A1000000005083EC08535657A1000000003145F833C5508D45F064A3000000008965E8C745FC00000000E800000000E800000000C745FCFEFFFFFFEB1EB801000000C38B65E86800000000FF150000000083C404C745FCFEFFFFFF33C08B4DF064890D00000000595F5E5B8BE55DC3
+ Relocations:
+ - VirtualAddress: 5
+ SymbolName: '$SG73531'
+ Type: IMAGE_REL_I386_DIR32
+ - VirtualAddress: 11
+ SymbolName: __imp__printf
+ Type: IMAGE_REL_I386_DIR32
+ - VirtualAddress: 53
+ SymbolName: '?TestCPPEX@@YAXXZ'
+ Type: IMAGE_REL_I386_REL32
+ - VirtualAddress: 61
+ SymbolName: '??1TestClass@@QAE@XZ'
+ Type: IMAGE_REL_I386_REL32
+ - VirtualAddress: 86
+ SymbolName: '__sehtable$?foo@@YAXXZ'
+ Type: IMAGE_REL_I386_DIR32
+ - VirtualAddress: 91
+ SymbolName: __except_handler4
+ Type: IMAGE_REL_I386_DIR32
+ - VirtualAddress: 109
+ SymbolName: ___security_cookie
+ Type: IMAGE_REL_I386_DIR32
+ - VirtualAddress: 139
+ SymbolName: '?TestExceptions@@YAXXZ'
+ Type: IMAGE_REL_I386_REL32
+ - VirtualAddress: 162
+ SymbolName: '$SG73539'
+ Type: IMAGE_REL_I386_DIR32
+ - VirtualAddress: 168
+ SymbolName: __imp__printf
+ Type: IMAGE_REL_I386_DIR32
+ - VirtualAddress: 214
+ SymbolName: '__sehtable$_main'
+ Type: IMAGE_REL_I386_DIR32
+ - VirtualAddress: 219
+ SymbolName: __except_handler4
+ Type: IMAGE_REL_I386_DIR32
+ - VirtualAddress: 237
+ SymbolName: ___security_cookie
+ Type: IMAGE_REL_I386_DIR32
+ - VirtualAddress: 267
+ SymbolName: '?foo@@YAXXZ'
+ Type: IMAGE_REL_I386_REL32
+ - VirtualAddress: 272
+ SymbolName: '?TestExceptions@@YAXXZ'
+ Type: IMAGE_REL_I386_REL32
+ - VirtualAddress: 295
+ SymbolName: '$SG73543'
+ Type: IMAGE_REL_I386_DIR32
+ - VirtualAddress: 301
+ SymbolName: __imp__printf
+ Type: IMAGE_REL_I386_DIR32
+ - Name: '.text$mn'
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: 558BEC51894DFC6800000000FF150000000083C4048BE55DC3
+ Relocations:
+ - VirtualAddress: 8
+ SymbolName: '??_C@_0BI@BBHGNMOG@Destroying?5TestClass?$CB?$AN?6?$AA@'
+ Type: IMAGE_REL_I386_DIR32
+ - VirtualAddress: 14
+ SymbolName: __imp__printf
+ Type: IMAGE_REL_I386_DIR32
+ - Name: '.xdata$x'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ Alignment: 8
+ SectionData: FEFFFFFF00000000D8FFFFFF00000000FEFFFFFF000000000000000000000000FEFFFFFF00000000D8FFFFFF00000000FEFFFFFF0000000000000000
+ Relocations:
+ - VirtualAddress: 20
+ SymbolName: '$LN5'
+ Type: IMAGE_REL_I386_DIR32
+ - VirtualAddress: 24
+ SymbolName: '$LN6'
+ Type: IMAGE_REL_I386_DIR32
+ - VirtualAddress: 52
+ SymbolName: '$LN5'
+ Type: IMAGE_REL_I386_DIR32
+ - VirtualAddress: 56
+ SymbolName: '$LN6'
+ Type: IMAGE_REL_I386_DIR32
+ - Name: .rdata
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 44657374726F79696E672054657374436C617373210D0A00
+ - Name: .sxdata
+ Characteristics: [ IMAGE_SCN_LNK_INFO ]
+ Alignment: 4
+ SectionData: 1B0000001A000000
+symbols:
+ - Name: '@comp.id'
+ Value: 14766605
+ SectionNumber: 65535
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: '@feat.00'
+ Value: 2147484049
+ SectionNumber: 65535
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: .drectve
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 240
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: '.debug$S'
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 108
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: .rdata
+ Value: 0
+ SectionNumber: 3
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 1
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ Selection: IMAGE_COMDAT_SELECT_ANY
+ - Name: '?value@?$integral_constant@_N$0A@@std@@2_NB'
+ Value: 0
+ SectionNumber: 3
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: .rdata
+ Value: 0
+ SectionNumber: 4
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 1
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 1996959894
+ Number: 0
+ Selection: IMAGE_COMDAT_SELECT_ANY
+ - Name: '?value@?$integral_constant@_N$00@std@@2_NB'
+ Value: 0
+ SectionNumber: 4
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: .rdata
+ Value: 0
+ SectionNumber: 5
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 99
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 2801625422
+ Number: 0
+ - Name: '$SG73531'
+ Value: 0
+ SectionNumber: 5
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: '$SG73539'
+ Value: 28
+ SectionNumber: 5
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: '$SG73543'
+ Value: 68
+ SectionNumber: 5
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: '.text$mn'
+ Value: 0
+ SectionNumber: 6
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 335
+ NumberOfRelocations: 17
+ NumberOfLinenumbers: 0
+ CheckSum: 2488225337
+ Number: 0
+ - Name: '.text$mn'
+ Value: 0
+ SectionNumber: 7
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 25
+ NumberOfRelocations: 2
+ NumberOfLinenumbers: 0
+ CheckSum: 210566957
+ Number: 0
+ Selection: IMAGE_COMDAT_SELECT_ANY
+ - Name: __imp__printf
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: '??1TestClass@@QAE@XZ'
+ Value: 0
+ SectionNumber: 7
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: '?TestCPPEX@@YAXXZ'
+ Value: 0
+ SectionNumber: 6
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: '?TestExceptions@@YAXXZ'
+ Value: 48
+ SectionNumber: 6
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: '?foo@@YAXXZ'
+ Value: 80
+ SectionNumber: 6
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _main
+ Value: 208
+ SectionNumber: 6
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: __except_handler4
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: '$LN5'
+ Value: 152
+ SectionNumber: 6
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_LABEL
+ - Name: '$LN7'
+ Value: 157
+ SectionNumber: 6
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_LABEL
+ - Name: '$LN6'
+ Value: 158
+ SectionNumber: 6
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_LABEL
+ - Name: '$LN5'
+ Value: 285
+ SectionNumber: 6
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_LABEL
+ - Name: '$LN7'
+ Value: 290
+ SectionNumber: 6
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_LABEL
+ - Name: '$LN6'
+ Value: 291
+ SectionNumber: 6
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_LABEL
+ - Name: '.xdata$x'
+ Value: 0
+ SectionNumber: 8
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 60
+ NumberOfRelocations: 4
+ NumberOfLinenumbers: 0
+ CheckSum: 2900129504
+ Number: 0
+ - Name: '__sehtable$?foo@@YAXXZ'
+ Value: 32
+ SectionNumber: 8
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: '__sehtable$_main'
+ Value: 0
+ SectionNumber: 8
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: .rdata
+ Value: 0
+ SectionNumber: 9
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 24
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 1296623929
+ Number: 0
+ Selection: IMAGE_COMDAT_SELECT_ANY
+ - Name: '??_C@_0BI@BBHGNMOG@Destroying?5TestClass?$CB?$AN?6?$AA@'
+ Value: 0
+ SectionNumber: 9
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: ___security_cookie
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: .sxdata
+ Value: 0
+ SectionNumber: 10
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 4
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+...
diff --git a/test/pecoff/Inputs/static-data1.obj.yaml b/test/pecoff/Inputs/static-data1.obj.yaml
new file mode 100644
index 000000000000..8dbe3e97eb51
--- /dev/null
+++ b/test/pecoff/Inputs/static-data1.obj.yaml
@@ -0,0 +1,67 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: ""
+ - Name: .data
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 4
+ SectionData: 03000000
+ - Name: ".debug$S"
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ SectionData: 04000000F1000000660000002B00011100000000433A5C63796777696E5C686F6D655C727569755C7374617469635C64617461312E6F626A0037003C1103020000030000000000000000000A0000001B9D01004D6963726F736F667420285229204D6163726F20417373656D626C657200000000
+symbols:
+ - Name: "@comp.id"
+ Value: 10394907
+ SectionNumber: 65535
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 0
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: .data
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 4
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: ".debug$S"
+ Value: 0
+ SectionNumber: 3
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 116
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: _val1
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/static-data2.obj.yaml b/test/pecoff/Inputs/static-data2.obj.yaml
new file mode 100644
index 000000000000..9b368c033887
--- /dev/null
+++ b/test/pecoff/Inputs/static-data2.obj.yaml
@@ -0,0 +1,67 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: ""
+ - Name: .data
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 4
+ SectionData: 04000000
+ - Name: ".debug$S"
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ SectionData: 04000000F1000000660000002B00011100000000433A5C63796777696E5C686F6D655C727569755C7374617469635C64617461322E6F626A0037003C1103020000030000000000000000000A0000001B9D01004D6963726F736F667420285229204D6163726F20417373656D626C657200000000
+symbols:
+ - Name: "@comp.id"
+ Value: 10394907
+ SectionNumber: 65535
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 0
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: .data
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 4
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: ".debug$S"
+ Value: 0
+ SectionNumber: 3
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 116
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: _val2
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/static.lib b/test/pecoff/Inputs/static.lib
new file mode 100644
index 000000000000..5a631010e1d3
--- /dev/null
+++ b/test/pecoff/Inputs/static.lib
Binary files differ
diff --git a/test/pecoff/Inputs/subsystem.main.yaml b/test/pecoff/Inputs/subsystem.main.yaml
new file mode 100644
index 000000000000..25fbe1be0143
--- /dev/null
+++ b/test/pecoff/Inputs/subsystem.main.yaml
@@ -0,0 +1,35 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: B82A000000C3
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 6
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: _main
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _mainCRTStartup
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/subsystem.winmain.yaml b/test/pecoff/Inputs/subsystem.winmain.yaml
new file mode 100644
index 000000000000..7f0381e2dc69
--- /dev/null
+++ b/test/pecoff/Inputs/subsystem.winmain.yaml
@@ -0,0 +1,35 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: B82A000000C3
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 6
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: _WinMain
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _WinMainCRTStartup
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/tlsused.obj.yaml b/test/pecoff/Inputs/tlsused.obj.yaml
new file mode 100644
index 000000000000..6a7880fa7878
--- /dev/null
+++ b/test/pecoff/Inputs/tlsused.obj.yaml
@@ -0,0 +1,29 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: []
+sections:
+ - Name: .data
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 4
+ SectionData: "0000000000000000"
+symbols:
+ - Name: .data
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 8
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: __tls_used
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/unknown-drectve.obj.yaml b/test/pecoff/Inputs/unknown-drectve.obj.yaml
new file mode 100644
index 000000000000..79a12fe7bfa2
--- /dev/null
+++ b/test/pecoff/Inputs/unknown-drectve.obj.yaml
@@ -0,0 +1,42 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: 558BEC56FF15000000008B0D000000008B3103F0FF150000000003C65E5DC3
+ - Name: .drectve
+ Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+ Alignment: 2147483648
+
+ # /nosuchoption:foobar
+ SectionData: 2f6e6f737563686f7074696f6e3a666f6f62617200
+
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 31
+ NumberOfRelocations: 3
+ NumberOfLinenumbers: 0
+ CheckSum: 3595596940
+ Number: 0
+ - Name: .drectve
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 13
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+...
diff --git a/test/pecoff/Inputs/unwind.obj.yaml b/test/pecoff/Inputs/unwind.obj.yaml
new file mode 100644
index 000000000000..2328cd565601
--- /dev/null
+++ b/test/pecoff/Inputs/unwind.obj.yaml
@@ -0,0 +1,129 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 4883EC184889742410440F110424534889E3488D235B4883C418C3C34881ECF0FF00004881ECF0FF80004881C4F0FF80004881C4F0FF0000C3
+ - Name: .xdata
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 0912080312030F300E880000096402000422001A000000000000000021000000000000001B000000000000000100000000000000010E06000E11F0FF80000701FE1F001A
+ Relocations:
+ - VirtualAddress: 20
+ SymbolName: __C_specific_handler
+ Type: IMAGE_REL_AMD64_ADDR32NB
+ - VirtualAddress: 32
+ SymbolName: func
+ Type: IMAGE_REL_AMD64_ADDR32NB
+ - VirtualAddress: 36
+ SymbolName: func
+ Type: IMAGE_REL_AMD64_ADDR32NB
+ - VirtualAddress: 40
+ SymbolName: .xdata
+ Type: IMAGE_REL_AMD64_ADDR32NB
+ - Name: .pdata
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 000000001B0000000000000012000000120000001C00000000000000010000002C000000000000001D00000034000000
+ Relocations:
+ - VirtualAddress: 0
+ SymbolName: func
+ Type: IMAGE_REL_AMD64_ADDR32NB
+ - VirtualAddress: 4
+ SymbolName: func
+ Type: IMAGE_REL_AMD64_ADDR32NB
+ - VirtualAddress: 8
+ SymbolName: .xdata
+ Type: IMAGE_REL_AMD64_ADDR32NB
+ - VirtualAddress: 12
+ SymbolName: func
+ Type: IMAGE_REL_AMD64_ADDR32NB
+ - VirtualAddress: 16
+ SymbolName: func
+ Type: IMAGE_REL_AMD64_ADDR32NB
+ - VirtualAddress: 20
+ SymbolName: .xdata
+ Type: IMAGE_REL_AMD64_ADDR32NB
+ - VirtualAddress: 24
+ SymbolName: smallFunc
+ Type: IMAGE_REL_AMD64_ADDR32NB
+ - VirtualAddress: 28
+ SymbolName: smallFunc
+ Type: IMAGE_REL_AMD64_ADDR32NB
+ - VirtualAddress: 32
+ SymbolName: .xdata
+ Type: IMAGE_REL_AMD64_ADDR32NB
+ - VirtualAddress: 36
+ SymbolName: allocFunc
+ Type: IMAGE_REL_AMD64_ADDR32NB
+ - VirtualAddress: 40
+ SymbolName: allocFunc
+ Type: IMAGE_REL_AMD64_ADDR32NB
+ - VirtualAddress: 44
+ SymbolName: .xdata
+ Type: IMAGE_REL_AMD64_ADDR32NB
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 57
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 1
+ - Name: .xdata
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 68
+ NumberOfRelocations: 4
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 2
+ - Name: .pdata
+ Value: 0
+ SectionNumber: 3
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 48
+ NumberOfRelocations: 12
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 3
+ - Name: func
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: __C_specific_handler
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: smallFunc
+ Value: 27
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: allocFunc
+ Value: 28
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/vars-main-x64.obj.yaml b/test/pecoff/Inputs/vars-main-x64.obj.yaml
new file mode 100644
index 000000000000..c888c28e4a67
--- /dev/null
+++ b/test/pecoff/Inputs/vars-main-x64.obj.yaml
@@ -0,0 +1,63 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: 558BEC56FF15000000008B0D000000008B3103F0FF150000000003C65E5DC3
+ Relocations:
+ - VirtualAddress: 6
+ SymbolName: __imp_fn
+ Type: IMAGE_REL_AMD64_ADDR32
+ - VirtualAddress: 12
+ SymbolName: __imp_var
+ Type: IMAGE_REL_AMD64_ADDR32
+ - VirtualAddress: 22
+ SymbolName: __imp__name_with_underscore
+ Type: IMAGE_REL_AMD64_ADDR32
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 31
+ NumberOfRelocations: 3
+ NumberOfLinenumbers: 0
+ CheckSum: 3595596940
+ Number: 0
+ - Name: __imp_fn
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: __imp__name_with_underscore
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: main
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: "__delayLoadHelper2"
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: __imp_var
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/vars-main-x86.obj.yaml b/test/pecoff/Inputs/vars-main-x86.obj.yaml
new file mode 100644
index 000000000000..fb016828df94
--- /dev/null
+++ b/test/pecoff/Inputs/vars-main-x86.obj.yaml
@@ -0,0 +1,69 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: 558BEC56FF15000000008B0D000000008B3103F0FF150000000003C65E5DC3
+ Relocations:
+ - VirtualAddress: 6
+ SymbolName: __imp__fn
+ Type: IMAGE_REL_I386_DIR32
+ - VirtualAddress: 12
+ SymbolName: __imp__var
+ Type: IMAGE_REL_I386_DIR32
+ - VirtualAddress: 22
+ SymbolName: __imp___name_with_underscore
+ Type: IMAGE_REL_I386_DIR32
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 31
+ NumberOfRelocations: 3
+ NumberOfLinenumbers: 0
+ CheckSum: 3595596940
+ Number: 0
+ - Name: __imp__fn
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: __imp___name_with_underscore
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _main
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: "___delayLoadHelper2@8"
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: __imp__var
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: ___ImageBase
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/Inputs/vars-main.c b/test/pecoff/Inputs/vars-main.c
new file mode 100644
index 000000000000..d588ca54b88e
--- /dev/null
+++ b/test/pecoff/Inputs/vars-main.c
@@ -0,0 +1,7 @@
+__declspec(dllimport) int var;
+__declspec(dllimport) int fn(void);
+__declspec(dllimport) int _name_with_underscore(void);
+
+int main() {
+ return var + fn() + _name_with_underscore();
+}
diff --git a/test/pecoff/Inputs/vars.c b/test/pecoff/Inputs/vars.c
new file mode 100644
index 000000000000..ae2ec46d1f47
--- /dev/null
+++ b/test/pecoff/Inputs/vars.c
@@ -0,0 +1,20 @@
+// cl.exe /c vars.c
+// link /dll /nodefaultlib /entry:dllmain /export:var,@1,NONAME,DATA \
+// /export:fn /export:_name_with_underscore vars.obj
+
+// will be exported by ordinal
+int var = 3;
+
+// will be exported by name
+int fn(void) {
+ return 4;
+}
+
+// will be exported by name
+int _name_with_underscore(void) {
+ return 5;
+}
+
+int dllmain() {
+ return 1;
+}
diff --git a/test/pecoff/Inputs/vars.dll.yaml b/test/pecoff/Inputs/vars.dll.yaml
new file mode 100644
index 000000000000..06f65ced6933
--- /dev/null
+++ b/test/pecoff/Inputs/vars.dll.yaml
@@ -0,0 +1,19 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: [ IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_32BIT_MACHINE, IMAGE_FILE_DLL ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 2147483648
+ SectionData: 558BECB8040000005DC3CCCCCCCCCCCC558BECB8050000005DC3CCCCCCCCCCCC558BECB8010000005DC30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+ - Name: .rdata
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ Alignment: 2147483648
+ SectionData: 0000000050570852000000004020000001000000030000000200000028200000342000003C200000003000001010000000100000492000005F20000001000200766172732E646C6C005F6E616D655F776974685F756E64657273636F726500666E00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+ - Name: .data
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 2147483648
+ SectionData: 0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+symbols:
+...
diff --git a/test/pecoff/Inputs/vars.lib b/test/pecoff/Inputs/vars.lib
new file mode 100644
index 000000000000..2d3aa2af678e
--- /dev/null
+++ b/test/pecoff/Inputs/vars.lib
Binary files differ
diff --git a/test/pecoff/Inputs/vars64.lib b/test/pecoff/Inputs/vars64.lib
new file mode 100644
index 000000000000..fb48c9ab141e
--- /dev/null
+++ b/test/pecoff/Inputs/vars64.lib
Binary files differ
diff --git a/test/pecoff/Inputs/weak-externals.asm b/test/pecoff/Inputs/weak-externals.asm
new file mode 100644
index 000000000000..7a5e918b92e7
--- /dev/null
+++ b/test/pecoff/Inputs/weak-externals.asm
@@ -0,0 +1,25 @@
+.386
+.model flat
+
+;; val1 should be linked normally. no_such_symbol1 should be ignored.
+extern _no_such_symbol1 : PROC
+extern _val1 (_no_such_symbol1): PROC
+
+;; no_such_symbol2 should be linked as val2.
+extern _val2 : PROC
+extern _no_such_symbol2 (_val2) : PROC
+
+;; no_such_symbol3 should fail to link.
+extern _no_such_symbol3 : PROC
+
+public _fn1
+.code
+_fn1:
+ push ebp
+ mov ebp, esp
+ call _val1
+ call _no_such_symbol2
+ call _no_such_symbol3
+ pop ebp
+ ret 0
+end _fn1
diff --git a/test/pecoff/Inputs/weak-externals.obj.yaml b/test/pecoff/Inputs/weak-externals.obj.yaml
new file mode 100644
index 000000000000..ee76936c5326
--- /dev/null
+++ b/test/pecoff/Inputs/weak-externals.obj.yaml
@@ -0,0 +1,91 @@
+---
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 558BECE800000000E800000000E8000000005DC3
+ Relocations:
+ - VirtualAddress: 4
+ SymbolName: _val1
+ Type: IMAGE_REL_I386_REL32
+ - VirtualAddress: 9
+ SymbolName: _no_such_symbol2
+ Type: IMAGE_REL_I386_REL32
+ - VirtualAddress: 14
+ SymbolName: _no_such_symbol3
+ Type: IMAGE_REL_I386_REL32
+ - Name: .data
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 4
+ SectionData: ""
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 20
+ NumberOfRelocations: 3
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: .data
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 0
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: _no_such_symbol1
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _val2
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _no_such_symbol3
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _val1
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_WEAK_EXTERNAL
+ WeakExternal:
+ TagIndex: 4
+ Characteristics: IMAGE_WEAK_EXTERN_SEARCH_LIBRARY
+ - Name: _no_such_symbol2
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_WEAK_EXTERNAL
+ WeakExternal:
+ TagIndex: 5
+ Characteristics: IMAGE_WEAK_EXTERN_SEARCH_LIBRARY
+ - Name: _fn1
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/pecoff/alignment.test b/test/pecoff/alignment.test
new file mode 100644
index 000000000000..bdf8bbaa2a3e
--- /dev/null
+++ b/test/pecoff/alignment.test
@@ -0,0 +1,22 @@
+# RUN: yaml2obj %p/Inputs/alignment.obj.yaml > %t.obj
+#
+# RUN: lld -flavor link /out:%t.exe /subsystem:console /force \
+# RUN: /entry:start /opt:noref -- %t.obj
+# RUN: llvm-readobj -sections %t.exe | FileCheck %s
+
+CHECK: Name: .bss (2E 62 73 73 00 00 00 00)
+CHECK: RawDataSize: 0
+
+CHECK: Name: .data (2E 64 61 74 61 00 00 00)
+CHECK-NEXT: VirtualSize: 0x6
+
+CHECK: Name: .text (2E 74 65 78 74 00 00 00)
+CHECK-NEXT: VirtualSize: 0x1001
+
+CHECK: Name: .yyy
+CHECK-NEXT: VirtualSize: 0x2
+CHECK-NEXT: VirtualAddress: 0x5000
+
+CHECK: Name: .zzz
+CHECK-NEXT: VirtualSize: 0x2
+CHECK-NEXT: VirtualAddress: 0x8000
diff --git a/test/pecoff/alternatename.test b/test/pecoff/alternatename.test
new file mode 100644
index 000000000000..926a8eae2876
--- /dev/null
+++ b/test/pecoff/alternatename.test
@@ -0,0 +1,44 @@
+# REQUIRES: x86
+
+# RUN: yaml2obj %p/Inputs/alternatename1.obj.yaml > %t1.obj
+# RUN: yaml2obj %p/Inputs/alternatename2.obj.yaml > %t2.obj
+# RUN: yaml2obj %p/Inputs/alternatename3.obj.yaml > %t3.obj
+#
+# RUN: lld -flavor link /force /out:%t1.exe /alternatename:_main=_foo \
+# RUN: /subsystem:console -- %t1.obj
+# RUN: llvm-objdump -d %t1.exe | FileCheck -check-prefix=CHECK1 %s
+#
+# RUN: lld -flavor link /force /out:%t2.exe /alternatename:_main=_foo \
+# RUN: /subsystem:console -- %t1.obj %t2.obj
+# RUN: llvm-objdump -d %t2.exe | FileCheck -check-prefix=CHECK2 %s
+#
+# RUN: lld -flavor link /force /out:%t3.exe /subsystem:console -- %t3.obj
+# RUN: llvm-objdump -d %t3.exe | FileCheck -check-prefix=CHECK3 %s
+#
+# RUN: lld -flavor link /force /out:%t4.exe /alternatename:_main=_foo \
+# RUN: /alternatename:_xyz=_foo /subsystem:console -- %t1.obj
+# RUN: llvm-objdump -d %t4.exe | FileCheck -check-prefix=CHECK4 %s
+
+CHECK1: nop
+CHECK1-NEXT: nop
+CHECK1-NEXT: nop
+CHECK1-NEXT: nop
+CHECK1-NOT: int3
+
+CHECK2: int3
+CHECK2-NEXT: int3
+CHECK2-NEXT: int3
+CHECK2-NEXT: int3
+CHECK2-NOT: nop
+
+CHECK3: nop
+CHECK3-NEXT: nop
+CHECK3-NEXT: nop
+CHECK3-NEXT: nop
+CHECK3-NOT: int3
+
+CHECK4: nop
+CHECK4-NEXT: nop
+CHECK4-NEXT: nop
+CHECK4-NEXT: nop
+CHECK4-NOT: int3
diff --git a/test/pecoff/armnt-ImageBase.test b/test/pecoff/armnt-ImageBase.test
new file mode 100644
index 000000000000..b4bf28c5eb81
--- /dev/null
+++ b/test/pecoff/armnt-ImageBase.test
@@ -0,0 +1,14 @@
+# RUN: yaml2obj -format coff -o %t.obj %p/Inputs/armnt-ImageBase.obj.yaml
+# RUN: llvm-readobj -r %t.obj | FileCheck %s -check-prefix BEFORE
+# RUN: lld -flavor link /out:%t.exe %t.obj /subsystem:console
+# RUN: llvm-readobj -r %t.exe | FileCheck %s -check-prefix AFTER
+
+BEFORE: Relocations [
+BEFORE: Section {{.*}} .text {
+BEFORE: 0x4 IMAGE_REL_ARM_ADDR32 __ImageBase
+BEFORE: }
+BEFORE: ]
+
+AFTER: Relocations [
+AFTER-NEXT: ]
+
diff --git a/test/pecoff/armnt-addr32-exec.test b/test/pecoff/armnt-addr32-exec.test
new file mode 100644
index 000000000000..be223a0e7e5d
--- /dev/null
+++ b/test/pecoff/armnt-addr32-exec.test
@@ -0,0 +1,11 @@
+# RUN: yaml2obj -format coff -o %t.obj %p/Inputs/armnt-addr32-exec.obj.yaml
+# RUN: llvm-objdump -s %t.obj | FileCheck %s -check-prefix BEFORE
+# RUN: lld -flavor link /out:%t.exe /entry:function /subsystem:console %t.obj
+# RUN: llvm-objdump -s %t.exe | FileCheck %s -check-prefix AFTER
+
+BEFORE: Contents of section .rdata:
+BEFORE: 0000 00000000
+
+AFTER: Contents of section .rdata:
+AFTER: 1000 01204000
+
diff --git a/test/pecoff/armnt-addr32.test b/test/pecoff/armnt-addr32.test
new file mode 100644
index 000000000000..716217d45758
--- /dev/null
+++ b/test/pecoff/armnt-addr32.test
@@ -0,0 +1,11 @@
+# RUN: yaml2obj -format coff -o %t.obj %p/Inputs/armnt-addr32.obj.yaml
+# RUN: llvm-objdump -s %t.obj | FileCheck %s -check-prefix BEFORE
+# RUN: lld -flavor link /entry:is /subsystem:console /out:%t.exe %t.obj
+# RUN: llvm-objdump -s %t.exe | FileCheck %s -check-prefix AFTER
+
+BEFORE: Contents of section .rdata:
+BEFORE: 0000 00000000 00000000
+
+AFTER: Contents of section .rdata:
+AFTER: 1000 00104000 00000000
+
diff --git a/test/pecoff/armnt-address-of-entry-point.test b/test/pecoff/armnt-address-of-entry-point.test
new file mode 100644
index 000000000000..3013b230bbd1
--- /dev/null
+++ b/test/pecoff/armnt-address-of-entry-point.test
@@ -0,0 +1,6 @@
+# RUN: yaml2obj -format coff -o %t.obj %p/Inputs/executable.obj.yaml
+# RUN: lld -flavor link /out:%t.exe %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
+
+# CHECK: AddressOfEntryPoint: 0x1001
+
diff --git a/test/pecoff/armnt-blx23t.test b/test/pecoff/armnt-blx23t.test
new file mode 100644
index 000000000000..56639fa22be9
--- /dev/null
+++ b/test/pecoff/armnt-blx23t.test
@@ -0,0 +1,27 @@
+# REQUIRES: arm
+
+# RUN: yaml2obj -format coff -o %t.obj %p/Inputs/armnt-blx23t.obj.yaml
+# RUN: llvm-objdump -d %t.obj | FileCheck %s -check-prefix BEFORE
+# RUN: lld -flavor link /entry:function /subsystem:console /out:%t.exe %t.obj
+# RUN: llvm-objdump -d %t.exe | FileCheck %s -check-prefix AFTER
+
+BEFORE: Disassembly of section .text:
+BEFORE: 0: 70 47 bx lr
+BEFORE: 2: 00 bf nop
+BEFORE: 4: 2d e9 00 48 push.w {r11, lr}
+BEFORE: 8: eb 46 mov r11, sp
+BEFORE: a: 20 20 movs r0, #32
+BEFORE: c: 00 f0 00 f8 bl #0
+BEFORE: 10: 01 30 adds r0, #1
+BEFORE: 12: bd e8 00 88 pop.w {r11, pc}
+
+AFTER: Disassembly of section .text:
+AFTER: 1000: 70 47 bx lr
+AFTER: 1002: 00 bf nop
+AFTER: 1004: 2d e9 00 48 push.w {r11, lr}
+AFTER: 1008: eb 46 mov r11, sp
+AFTER: 100a: 20 20 movs r0, #32
+AFTER: 100c: ff f7 f8 ff bl #-16
+AFTER: 1010: 01 30 adds r0, #1
+AFTER: 1012: bd e8 00 88 pop.w {r11, pc}
+
diff --git a/test/pecoff/armnt-branch24t.test b/test/pecoff/armnt-branch24t.test
new file mode 100644
index 000000000000..1a727ed7d725
--- /dev/null
+++ b/test/pecoff/armnt-branch24t.test
@@ -0,0 +1,20 @@
+# REQUIRES: arm
+
+# RUN: yaml2obj -format coff -o %t.obj %p/Inputs/armnt-branch24t.obj.yaml
+# RUN: llvm-objdump -d %t.obj | FileCheck %s -check-prefix BEFORE
+# RUN: lld -flavor link /entry:function /subsystem:console /out:%t.exe %t.obj
+# RUN: llvm-objdump -d %t.exe | FileCheck %s -check-prefix AFTER
+
+BEFORE: Disassembly of section .text:
+BEFORE: 0: 70 47 bx lr
+BEFORE: 2: 00 bf nop
+BEFORE: 4: 20 20 movs r0, #32
+BEFORE: 6: 00 f0 00 b8 b.w #0
+
+AFTER: Disassembly of section .text:
+AFTER: .text:
+AFTER: 1000: 70 47 bx lr
+AFTER: 1002: 00 bf nop
+AFTER: 1004: 20 20 movs r0, #32
+AFTER: 1006: ff f7 fb bf b.w #-10
+
diff --git a/test/pecoff/armnt-exports.s b/test/pecoff/armnt-exports.s
new file mode 100644
index 000000000000..cb500bf02e07
--- /dev/null
+++ b/test/pecoff/armnt-exports.s
@@ -0,0 +1,28 @@
+
+# void __declspec(dllexport) function() {}
+# void _DllMainCRTStartup() {}
+
+ .syntax unified
+ .thumb
+ .text
+
+ .def function
+ .scl 2
+ .type 32
+ .endef
+ .global function
+ .align 2
+ .thumb_func
+function:
+ bx lr
+
+ .def _DllMainCRTStartup
+ .scl 2
+ .type 32
+ .endef
+ .global _DllMainCRTStartup
+ .align 2
+ .thumb_func
+_DllMainCRTStartup
+ bx lr
+
diff --git a/test/pecoff/armnt-exports.test b/test/pecoff/armnt-exports.test
new file mode 100644
index 000000000000..f0aa3eabcacc
--- /dev/null
+++ b/test/pecoff/armnt-exports.test
@@ -0,0 +1,10 @@
+# RUN: yaml2obj -format coff -o %t.obj %p/Inputs/armnt-exports.obj.yaml
+# RUN: lld -flavor link /dll /def:%p/Inputs/armnt-exports.def /out:%t.dll %t.obj
+# RUN: llvm-readobj -coff-exports %t.dll | FileCheck %s
+
+CHECK: Export {
+CHECK: Ordinal: 1
+CHECK: Name: function
+CHECK: RVA: 0x2001
+CHECK: }
+
diff --git a/test/pecoff/armnt-imports.test b/test/pecoff/armnt-imports.test
new file mode 100644
index 000000000000..596270909c52
--- /dev/null
+++ b/test/pecoff/armnt-imports.test
@@ -0,0 +1,11 @@
+# RUN: yaml2obj -format coff -o %t.obj %p/Inputs/armnt-import.obj.yaml
+# RUN: lld -flavor link /out:%t.exe /subsystem:console %t.obj %p/Inputs/library.lib
+# RUN: llvm-readobj -coff-imports %t.exe | FileCheck %s
+
+CHECK: Import {
+CHECK: Name: library.dll
+CHECK: ImportLookupTableRVA: 0x4000
+CHECK: ImportAddressTableRVA: 0x2000
+CHECK: Symbol: function (0)
+CHECK: }
+
diff --git a/test/pecoff/armnt-mov32t-exec.test b/test/pecoff/armnt-mov32t-exec.test
new file mode 100644
index 000000000000..de4feffea0cc
--- /dev/null
+++ b/test/pecoff/armnt-mov32t-exec.test
@@ -0,0 +1,21 @@
+# REQUIRES: arm
+
+# RUN: yaml2obj -format coff -o %t.obj %p/Inputs/armnt-mov32t-exec.obj.yaml
+# RUN: llvm-objdump -d %t.obj | FileCheck %s -check-prefix BEFORE
+# RUN: lld -flavor link /out:%t.exe /subsystem:console /entry:get_function %t.obj
+# RUN: llvm-objdump -d %t.exe | FileCheck %s -check-prefix AFTER
+
+BEFORE: Disassembly of section .text:
+BEFORE: 0: 70 47 bx lr
+BEFORE: 2: 00 bf nop
+BEFORE: 4: 40 f2 00 00 movw r0, #0
+BEFORE: 8: c0 f2 00 00 movt r0, #0
+BEFORE: c: 70 47 bx lr
+
+AFTER: Disassembly of section .text:
+AFTER: 1000: 70 47 bx lr
+AFTER: 1002: 00 bf nop
+AFTER: 1004: 41 f2 01 00 movw r0, #4097
+AFTER: 1008: c0 f2 40 00 movt r0, #64
+AFTER: 100c: 70 47 bx lr
+
diff --git a/test/pecoff/armnt-movt32t.test b/test/pecoff/armnt-movt32t.test
new file mode 100644
index 000000000000..2ae47ef75846
--- /dev/null
+++ b/test/pecoff/armnt-movt32t.test
@@ -0,0 +1,17 @@
+# REQUIRES: arm
+
+# RUN: yaml2obj -format coff -o %t.obj %p/Inputs/armnt-mov32t.obj.yaml
+# RUN: llvm-objdump -d %t.obj | FileCheck %s -check-prefix BEFORE
+# RUN: lld -flavor link /entry:get_buffer /subsystem:console /out:%t.exe %t.obj
+# RUN: llvm-objdump -d %t.exe | FileCheck %s -check-prefix AFTER
+
+BEFORE: Disassembly of section .text:
+BEFORE: 0: 40 f2 00 00 movw r0, #0
+BEFORE: 4: c0 f2 00 00 movt r0, #0
+BEFORE: 8: 70 47 bx lr
+
+AFTER: Disassembly of section .text:
+AFTER: 0: 41 f2 00 00 movw r0, #4096
+AFTER: 4: c0 f2 40 00 movt r0, #64
+AFTER: 8: 70 47 bx lr
+
diff --git a/test/pecoff/armnt.test b/test/pecoff/armnt.test
new file mode 100644
index 000000000000..1cf6cd8114a4
--- /dev/null
+++ b/test/pecoff/armnt.test
@@ -0,0 +1,6 @@
+# RUN: yaml2obj -format coff -o %t.obj %p/Inputs/armnt-obj.yaml
+# RUN: lld -flavor link /out:%t.dll /subsystem:console /entry:main %t.obj
+# RUN: llvm-readobj -sections %t.dll | FileCheck %s
+
+CHECK: Format: COFF-ARM
+
diff --git a/test/pecoff/associative.test b/test/pecoff/associative.test
new file mode 100644
index 000000000000..f998befd007e
--- /dev/null
+++ b/test/pecoff/associative.test
@@ -0,0 +1,10 @@
+# RUN: yaml2obj %p/Inputs/associative1.obj.yaml > %t1.obj
+# RUN: yaml2obj %p/Inputs/associative1.obj.yaml > %t2.obj
+# RUN: yaml2obj %p/Inputs/associative3.obj.yaml > %t3.obj
+#
+# RUN: lld -flavor link /machine:x86 /subsystem:console /entry:main \
+# RUN: /out:%t.exe -- %t1.obj %t2.obj %t3.obj
+# RUN: obj2yaml %t.exe | FileCheck %s
+
+CHECK: - Name: .CRT
+CHECK: SectionData: '77777777'
diff --git a/test/pecoff/base-reloc.test b/test/pecoff/base-reloc.test
new file mode 100644
index 000000000000..5bc83de4d1c2
--- /dev/null
+++ b/test/pecoff/base-reloc.test
@@ -0,0 +1,78 @@
+# RUN: yaml2obj %p/Inputs/basereloc.obj.yaml > %t.obj
+#
+# RUN: lld -flavor link /out:%t.exe /subsystem:console /force /opt:noref \
+# RUN: -- %t.obj
+# RUN: llvm-readobj -coff-basereloc %t.exe | FileCheck %s --check-prefix=BASEREL
+#
+# RUN: lld -flavor link /out:%t2.exe /subsystem:console /force /fixed \
+# RUN: /opt:noref -- %t.obj
+# RUN: llvm-readobj -coff-basereloc %t2.exe | FileCheck %s --check-prefix=NOBASEREL
+
+BASEREL: BaseReloc [
+BASEREL-NEXT: Entry {
+BASEREL-NEXT: Type: HIGHLOW
+BASEREL-NEXT: Address: 0x2007
+BASEREL-NEXT: }
+BASEREL-NEXT: Entry {
+BASEREL-NEXT: Type: HIGHLOW
+BASEREL-NEXT: Address: 0x200C
+BASEREL-NEXT: }
+BASEREL-NEXT: Entry {
+BASEREL-NEXT: Type: HIGHLOW
+BASEREL-NEXT: Address: 0x201E
+BASEREL-NEXT: }
+BASEREL-NEXT: Entry {
+BASEREL-NEXT: Type: ABSOLUTE
+BASEREL-NEXT: Address: 0x2000
+BASEREL-NEXT: }
+BASEREL-NEXT: Entry {
+BASEREL-NEXT: Type: HIGHLOW
+BASEREL-NEXT: Address: 0x3007
+BASEREL-NEXT: }
+BASEREL-NEXT: Entry {
+BASEREL-NEXT: Type: HIGHLOW
+BASEREL-NEXT: Address: 0x300C
+BASEREL-NEXT: }
+BASEREL-NEXT: Entry {
+BASEREL-NEXT: Type: HIGHLOW
+BASEREL-NEXT: Address: 0x301E
+BASEREL-NEXT: }
+BASEREL-NEXT: Entry {
+BASEREL-NEXT: Type: ABSOLUTE
+BASEREL-NEXT: Address: 0x3000
+BASEREL-NEXT: }
+BASEREL-NEXT: ]
+
+NOBASEREL: BaseReloc [
+NOBASEREL-NEXT: ]
+
+# RUN: lld -flavor link /out:%t3.exe /subsystem:console /force /opt:noref \
+# RUN: -- %t.obj
+# RUN: llvm-readobj -file-headers -sections %t3.exe | FileCheck %s \
+# RUN: --check-prefix=BASEREL-HEADER
+#
+# RUN: lld -flavor link /out:%t4.exe /subsystem:console /force /opt:noref \
+# RUN: /fixed -- %t.obj
+# RUN: llvm-readobj -file-headers %t4.exe | FileCheck %s \
+# RUN: --check-prefix=NOBASEREL-HEADER
+
+BASEREL-HEADER-NOT: IMAGE_FILE_RELOCS_STRIPPED
+
+NOBASEREL-HEADER: IMAGE_FILE_RELOCS_STRIPPED
+
+BASEREL-HEADER: BaseRelocationTableRVA: 0x4000
+BASEREL-HEADER: BaseRelocationTableSize: 0x20
+BASEREL-HEADER: Name: .reloc (2E 72 65 6C 6F 63 00 00)
+BASEREL-HEADER-NEXT: VirtualSize: 0x20
+BASEREL-HEADER-NEXT: VirtualAddress: 0x4000
+BASEREL-HEADER-NEXT: RawDataSize: 512
+BASEREL-HEADER-NEXT: PointerToRawData: 0xA00
+BASEREL-HEADER-NEXT: PointerToRelocations: 0x0
+BASEREL-HEADER-NEXT: PointerToLineNumbers: 0x0
+BASEREL-HEADER-NEXT: RelocationCount: 0
+BASEREL-HEADER-NEXT: LineNumberCount: 0
+BASEREL-HEADER-NEXT: Characteristics [ (0x42000040)
+BASEREL-HEADER-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA (0x40)
+BASEREL-HEADER-NEXT: IMAGE_SCN_MEM_DISCARDABLE (0x2000000)
+BASEREL-HEADER-NEXT: IMAGE_SCN_MEM_READ (0x40000000)
+BASEREL-HEADER-NEXT: ]
diff --git a/test/pecoff/baseaddr.test b/test/pecoff/baseaddr.test
new file mode 100644
index 000000000000..dbd091bc2e30
--- /dev/null
+++ b/test/pecoff/baseaddr.test
@@ -0,0 +1,18 @@
+# RUN: yaml2obj %p/Inputs/nop.obj.yaml > %t.obj
+#
+# RUN: lld -flavor link /out:%t1.exe /opt:noref /subsystem:console /force \
+# RUN: -- %t.obj
+# RUN: llvm-readobj -file-headers %t1.exe | FileCheck -check-prefix=DEFAULT %s
+#
+# RUN: lld -flavor link /out:%t2.exe /opt:noref /base:8388608 \
+# RUN: /subsystem:console /force -- %t.obj
+# RUN: llvm-readobj -file-headers %t2.exe | FileCheck -check-prefix=BASE %s
+
+DEFAULT: ImageBase: 0x400000
+
+BASE: ImageBase: 0x800000
+
+# RUN: not lld -flavor link /base:3 /subsystem:console -- %t.obj >& %t.log
+# RUN: FileCheck -check-prefix=ERROR %s < %t.log
+
+ERROR: Base address have to be multiple of 64K, but got 3
diff --git a/test/pecoff/bss-section.test b/test/pecoff/bss-section.test
new file mode 100644
index 000000000000..4181e994fbf5
--- /dev/null
+++ b/test/pecoff/bss-section.test
@@ -0,0 +1,21 @@
+# RUN: lld -flavor link /out:%t.exe /subsystem:console /force \
+# RUN: -- %p/Inputs/bss.obj
+# RUN: llvm-readobj -sections %t.exe | FileCheck %s
+
+CHECK: Section {
+CHECK: Number: 1
+CHECK-NEXT: Name: .bss
+CHECK-NEXT: VirtualSize: 0x320
+CHECK-NEXT: VirtualAddress: 0x1000
+CHECK-NEXT: RawDataSize: 0
+CHECK-NEXT: PointerToRawData: 0x0
+CHECK-NEXT: PointerToRelocations: 0x0
+CHECK-NEXT: PointerToLineNumbers: 0x0
+CHECK-NEXT: RelocationCount: 0
+CHECK-NEXT: LineNumberCount: 0
+CHECK-NEXT: Characteristics [
+CHECK-NEXT: IMAGE_SCN_CNT_UNINITIALIZED_DATA
+CHECK-NEXT: IMAGE_SCN_MEM_READ
+CHECK-NEXT: IMAGE_SCN_MEM_WRITE
+CHECK-NEXT: ]
+CHECK-NEXT: }
diff --git a/test/pecoff/comdat.test b/test/pecoff/comdat.test
new file mode 100644
index 000000000000..d752309d7515
--- /dev/null
+++ b/test/pecoff/comdat.test
@@ -0,0 +1,12 @@
+# RUN: yaml2obj %p/Inputs/comdat.obj.yaml > %t1.obj
+# RUN: yaml2obj %p/Inputs/comdat.obj.yaml > %t2.obj
+#
+# RUN: lld -flavor link /out:%t.exe /subsystem:console /opt:noref /force \
+# RUN: -- %t1.obj %t2.obj 2>&1 > %t.log
+#
+# FileCheck complains if the input files is empty, so add a dummy line.
+# RUN: echo foo >> %t.log
+#
+# RUN: FileCheck %s < %t.log
+
+CHECK-NOT: duplicate symbol error
diff --git a/test/pecoff/common-symbol.test b/test/pecoff/common-symbol.test
new file mode 100644
index 000000000000..49d4d8725da4
--- /dev/null
+++ b/test/pecoff/common-symbol.test
@@ -0,0 +1,14 @@
+# REQUIRES: x86
+
+# RUN: yaml2obj %p/Inputs/common-symbol.obj.yaml > %t.obj
+#
+# RUN: lld -flavor link /machine:x64 /out:%t.exe /subsystem:console /force \
+# RUN: /opt:noref -- %t.obj %t.obj
+# RUN: llvm-objdump -d %t.exe | FileCheck %s
+
+# Operands of B8 (MOV EAX) are common symbols
+CHECK: 3000: b8 00 10 00 40
+CHECK: 3005: b8 04 10 00 40
+CHECK: 300a: b8 20 10 00 40
+CHECK: 300f: b8 60 10 00 40
+CHECK: 3014: b8 80 10 00 40
diff --git a/test/pecoff/conflicting-machine.test b/test/pecoff/conflicting-machine.test
new file mode 100644
index 000000000000..6c71521fe1b7
--- /dev/null
+++ b/test/pecoff/conflicting-machine.test
@@ -0,0 +1,6 @@
+# RUN: yaml2obj %p/Inputs/vars-main-x64.obj.yaml > %t-x64.obj
+
+# RUN: not lld -flavor link /machine:x86 /out:%t.exe /entry:main %t-x64.obj 2>&1 \
+# RUN: | FileCheck %s
+
+CHECK: module machine type 'X64' conflicts with target machine type 'X86'
diff --git a/test/pecoff/delayimport.test b/test/pecoff/delayimport.test
new file mode 100644
index 000000000000..89ceb4ad5b20
--- /dev/null
+++ b/test/pecoff/delayimport.test
@@ -0,0 +1,54 @@
+# RUN: yaml2obj %p/Inputs/vars-main-x86.obj.yaml > %t-x86.obj
+# RUN: yaml2obj %p/Inputs/vars-main-x64.obj.yaml > %t-x64.obj
+#
+# RUN: lld -flavor link /out:%t1.exe /subsystem:console /entry:main \
+# RUN: /delayload:vars.dll -- %t-x86.obj %p/Inputs/vars.lib
+# RUN: llvm-readobj -coff-imports %t1.exe | FileCheck -check-prefix=X86 %s
+#
+# RUN: lld -flavor link /out:%t2.exe /subsystem:console /entry:main \
+# RUN: /machine:x64 /delayload:vars64.dll -- %t-x64.obj %p/Inputs/vars64.lib
+# RUN: llvm-readobj -coff-imports %t2.exe | FileCheck -check-prefix=X64 %s
+
+X86: DelayImport {
+X86-NEXT: Name: vars.dll
+X86-NEXT: Attributes: 0x1
+X86-NEXT: ModuleHandle: 0x1000
+X86-NEXT: ImportAddressTable: 0x1004
+X86-NEXT: ImportNameTable: 0x2000
+X86-NEXT: BoundDelayImportTable: 0x0
+X86-NEXT: UnloadDelayImportTable: 0x0
+X86-NEXT: Import {
+X86-NEXT: Symbol: _name_with_underscore (0)
+X86-NEXT: Address: 0x40501F
+X86-NEXT: }
+X86-NEXT: Import {
+X86-NEXT: Symbol: fn (1)
+X86-NEXT: Address: 0x405034
+X86-NEXT: }
+X86-NEXT: Import {
+X86-NEXT: Symbol: (1)
+X86-NEXT: Address: 0x405049
+X86-NEXT: }
+X86-NEXT: }
+
+X64: DelayImport {
+X64-NEXT: Name: vars64.dll
+X64-NEXT: Attributes: 0x1
+X64-NEXT: ModuleHandle: 0x1000
+X64-NEXT: ImportAddressTable: 0x1008
+X64-NEXT: ImportNameTable: 0x2000
+X64-NEXT: BoundDelayImportTable: 0x0
+X64-NEXT: UnloadDelayImportTable: 0x0
+X64-NEXT: Import {
+X64-NEXT: Symbol: _name_with_underscore (0)
+X64-NEXT: Address: 0x14000501F
+X64-NEXT: }
+X64-NEXT: Import {
+X64-NEXT: Symbol: fn (1)
+X64-NEXT: Address: 0x140005076
+X64-NEXT: }
+X64-NEXT: Import {
+X64-NEXT: Symbol: (1)
+X64-NEXT: Address: 0x1400050CD
+X64-NEXT: }
+X64-NEXT: }
diff --git a/test/pecoff/dll.test b/test/pecoff/dll.test
new file mode 100644
index 000000000000..666e9f1152b0
--- /dev/null
+++ b/test/pecoff/dll.test
@@ -0,0 +1,7 @@
+# RUN: yaml2obj %p/Inputs/nop.obj.yaml > %t.obj
+#
+# RUN: lld -flavor link /out:%t.exe /subsystem:console \
+# RUN: /entry:start /dll -- %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
+
+CHECK: IMAGE_FILE_DLL (0x2000)
diff --git a/test/pecoff/dosstub.test b/test/pecoff/dosstub.test
new file mode 100644
index 000000000000..f0458501704d
--- /dev/null
+++ b/test/pecoff/dosstub.test
@@ -0,0 +1,11 @@
+# RUN: yaml2obj %p/Inputs/nop.obj.yaml > %t.obj
+
+# RUN: echo "MZ Hello world" > %t.stub
+# RUN: lld -flavor link /out:%t.exe /entry:start /subsystem:console \
+# RUN: /stub:%t.stub -- %t.obj
+# RUN: FileCheck -check-prefix=FILE %s < %t.exe
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=READOBJ %s
+
+FILE: MZ Hello world
+
+READOBJ: Format: COFF-i386
diff --git a/test/pecoff/drectve.test b/test/pecoff/drectve.test
new file mode 100644
index 000000000000..258f608e5dff
--- /dev/null
+++ b/test/pecoff/drectve.test
@@ -0,0 +1,39 @@
+# Test if the linker can properly parse the .drectve section contents.
+# "drectve.obj" contains "/defaultlib:vars /subsystem:console,42.195 -?foo"
+# in its .drectve section.
+
+# RUN: yaml2obj %p/Inputs/drectve.obj.yaml > %t.obj
+#
+# RUN: lld -flavor link /out:%t.exe /entry:main /opt:noref /libpath:%p/Inputs \
+# RUN: -- %t.obj >& %t.log
+#
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=HEADER %s
+# RUN: llvm-objdump -p %t.exe | FileCheck -check-prefix=IMPORT %s
+# RUN: echo >> %t.log
+# RUN: FileCheck -check-prefix=ERROR %s < %t.log
+
+HEADER: MajorOperatingSystemVersion: 42
+HEADER: MinorOperatingSystemVersion: 195
+
+IMPORT: DLL Name: vars.dll
+IMPORT-NEXT: Hint/Ord Name
+IMPORT-NEXT: 0 _name_with_underscore
+IMPORT-NEXT: 1 fn
+IMPORT-NEXT: 1
+
+ERROR-NOT: foo
+
+
+# drectve2.obj contains "/include:foo".
+# RUN: yaml2obj %p/Inputs/drectve2.obj.yaml > %t2.obj
+# RUN: not lld -flavor link /out:%t2.exe /entry:main -- %t2.obj >& %t2.log
+# RUN: FileCheck -check-prefix=UNDEF2 %s < %t2.log
+
+UNDEF2: Undefined symbol: {{.*}}: foo
+
+# drectve4.lib contains "/include:bar".
+# RUN: not lld -flavor link /force /out:%t3.exe /entry:main /include:_fn1 -- \
+# RUN: %t2.obj %p/Inputs/drectve3.lib >& %t3.log
+# RUN: FileCheck -check-prefix=UNDEF3 %s < %t3.log
+
+UNDEF3: Undefined symbol: {{.*}}: bar
diff --git a/test/pecoff/dynamic.test b/test/pecoff/dynamic.test
new file mode 100644
index 000000000000..6b9a945b1fc5
--- /dev/null
+++ b/test/pecoff/dynamic.test
@@ -0,0 +1,11 @@
+# RUN: yaml2obj %p/Inputs/vars-main-x86.obj.yaml > %t.obj
+#
+# RUN: lld -flavor link /out:%t.exe /subsystem:console /entry:main /opt:noref \
+# RUN: -- %t.obj %p/Inputs/vars.lib
+# RUN: llvm-objdump -p %t.exe | FileCheck %s
+
+CHECK: DLL Name: vars.dll
+CHECK-NEXT: Hint/Ord Name
+CHECK-NEXT: 0 _name_with_underscore
+CHECK-NEXT: 1 fn
+CHECK-NEXT: 1
diff --git a/test/pecoff/dynamicbase.test b/test/pecoff/dynamicbase.test
new file mode 100644
index 000000000000..9ed795b99db9
--- /dev/null
+++ b/test/pecoff/dynamicbase.test
@@ -0,0 +1,24 @@
+# RUN: yaml2obj %p/Inputs/hello.obj.yaml > %t.obj
+#
+# RUN: lld -flavor link /out:%t1.exe /subsystem:console /force -- %t.obj
+# RUN: llvm-readobj -file-headers %t1.exe | FileCheck %s \
+# RUN: --check-prefix=DYNAMICBASE
+#
+# RUN: lld -flavor link /out:%t2.exe /subsystem:console /force /dynamicbase:no \
+# RUN: -- %t.obj
+# RUN: llvm-readobj -file-headers %t2.exe | FileCheck %s \
+# RUN: --check-prefix=NODYNAMICBASE
+#
+# RUN: lld -flavor link /out:%t3.exe /subsystem:console /force /fixed -- %t.obj
+# RUN: llvm-readobj -file-headers %t3.exe | FileCheck %s \
+# RUN: --check-prefix=NODYNAMICBASE
+#
+# RUN: not lld -flavor link /out:%t4.exe /subsystem:console /force /fixed \
+# RUN: /dynamicbase -- %t.obj 2> %t.err
+# RUN: FileCheck %s --check-prefix=DYNAMIC-AND-FIXED < %t.err
+
+DYNAMICBASE: IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE
+
+NODYNAMICBASE-NOT: IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE
+
+DYNAMIC-AND-FIXED: /dynamicbase must not be specified with /fixed
diff --git a/test/pecoff/entry.test b/test/pecoff/entry.test
new file mode 100644
index 000000000000..b48e5a038293
--- /dev/null
+++ b/test/pecoff/entry.test
@@ -0,0 +1,41 @@
+# REQUIRES: asserts
+
+# RUN: yaml2obj %p/Inputs/entry.obj.yaml > %t.obj
+
+# RUN: not lld -flavor link /out:%t.exe /alternatename:_main=_foo \
+# RUN: -- %t.obj 2> %t.log
+# RUN: FileCheck -check-prefix=MAIN %s < %t.log
+
+MAIN: _mainCRTStartup
+
+# RUN: not lld -flavor link /out:%t.exe /alternatename:_wmain=_foo \
+# RUN: -- %t.obj 2> %t.log
+# RUN: FileCheck -check-prefix=WMAIN %s < %t.log
+
+WMAIN: _wmainCRTStartup
+
+# RUN: not lld -flavor link /out:%t.exe /alternatename:_WinMain=_foo \
+# RUN: -- %t.obj 2> %t.log
+# RUN: FileCheck -check-prefix=WINMAIN %s < %t.log
+# RUN: not lld -flavor link /out:%t.exe /alternatename:_WinMain@16=_foo \
+# RUN: -- %t.obj 2> %t.log
+# RUN: FileCheck -check-prefix=WINMAIN %s < %t.log
+
+WINMAIN: _WinMainCRTStartup
+
+# RUN: not lld -flavor link /out:%t.exe /alternatename:_wWinMain=_foo \
+# RUN: -- %t.obj 2> %t.log
+# RUN: FileCheck -check-prefix=WWINMAIN %s < %t.log
+
+WWINMAIN: _wWinMainCRTStartup
+
+# RUN: lld -flavor link /out:%t.exe /alternatename:_main=_foo \
+# RUN: /alternatename:_mainCRTStartup=_bar -- %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=MAINADDR %s
+
+MAINADDR: AddressOfEntryPoint: 0x1004
+
+# RUN: lld -flavor link /out:%t.exe /subsystem:console /entry:baz -- %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=MANGLE %s
+
+MANGLE: AddressOfEntryPoint: 0x1004
diff --git a/test/pecoff/export-warning.test b/test/pecoff/export-warning.test
new file mode 100644
index 000000000000..5c7647de00bd
--- /dev/null
+++ b/test/pecoff/export-warning.test
@@ -0,0 +1,19 @@
+# RUN: yaml2obj %p/Inputs/export.obj.yaml > %t.obj
+#
+# RUN: lld -flavor link /out:%t1.dll /dll /entry:init \
+# RUN: /export:exportfn1 /export:exportfn1 -- %t.obj 2> %t1.log
+# RUN: echo >> %t1.log
+# RUN: FileCheck -check-prefix=CHECK1 %s < %t1.log
+CHECK1-NOT: Export symbol '_exportfn1' specified more than once.
+
+# RUN: lld -flavor link /out:%t2.dll /dll /entry:init \
+# RUN: /export:exportfn1 /export:exportfn1,@5 -- %t.obj 2> %t2.log
+# RUN: echo >> %t2.log
+# RUN: FileCheck -check-prefix=CHECK2 %s < %t2.log
+CHECK2: Export symbol '_exportfn1' specified more than once.
+
+# RUN: lld -flavor link /out:%t3.dll /dll /entry:init \
+# RUN: /export:exportfn1,@8 /export:exportfn1,@5 -- %t.obj 2> %t3.log
+# RUN: echo >> %t3.log
+# RUN: FileCheck -check-prefix=CHECK3 %s < %t3.log
+CHECK3: Export symbol '_exportfn1' specified more than once.
diff --git a/test/pecoff/export.test b/test/pecoff/export.test
new file mode 100644
index 000000000000..63b8677cd4b7
--- /dev/null
+++ b/test/pecoff/export.test
@@ -0,0 +1,90 @@
+# RUN: yaml2obj %p/Inputs/export.obj.yaml > %t.obj
+#
+# RUN: lld -flavor link /out:%t1.dll /dll /entry:init \
+# RUN: /export:exportfn1 /export:exportfn2 -- %t.obj
+# RUN: llvm-objdump -p %t1.dll | FileCheck -check-prefix=CHECK1 %s
+
+CHECK1: Export Table:
+CHECK1: DLL name: export.test.tmp1.dll
+CHECK1: Ordinal RVA Name
+CHECK1-NEXT: 1 0x2008 exportfn1
+CHECK1-NEXT: 2 0x2010 exportfn2
+
+# RUN: lld -flavor link /out:%t2.dll /dll /subsystem:console /entry:init \
+# RUN: /export:exportfn1,@5 /export:exportfn2 -- %t.obj
+# RUN: llvm-objdump -p %t2.dll | FileCheck -check-prefix=CHECK2 %s
+
+CHECK2: Export Table:
+CHECK2: DLL name: export.test.tmp2.dll
+CHECK2: Ordinal RVA Name
+CHECK2-NEXT: 5 0x2008 exportfn1
+CHECK2-NEXT: 6 0x2010 exportfn2
+
+# RUN: lld -flavor link /out:%t3.dll /dll /subsystem:console /entry:init \
+# RUN: /export:exportfn1,@5,noname /export:exportfn2 -- %t.obj
+# RUN: llvm-objdump -p %t3.dll | FileCheck -check-prefix=CHECK3 %s
+
+CHECK3: Export Table:
+CHECK3: DLL name: export.test.tmp3.dll
+CHECK3: Ordinal RVA Name
+CHECK3-NEXT: 5 0x2008
+CHECK3-NEXT: 6 0x2010 exportfn2
+
+# RUN: lld -flavor link /out:%t4.dll /dll /entry:init \
+# RUN: /def:%p/Inputs/exports.def -- %t.obj
+# RUN: llvm-objdump -p %t4.dll | FileCheck -check-prefix=CHECK4 %s
+
+CHECK4: Export Table:
+CHECK4: DLL name: export.test.tmp4.dll
+CHECK4: Ordinal RVA Name
+CHECK4-NEXT: 5 0x2008 exportfn1
+CHECK4-NEXT: 6 0x2010 exportfn2
+CHECK4-NEXT: 7 0x2010 exportfn3@256
+CHECK4-NEXT: 8 0x2010 exportfn5
+
+# RUN: lld -flavor link /out:%t5.dll /dll /entry:init \
+# RUN: /export:exportfn7 -- %t.obj
+# RUN: llvm-objdump -p %t5.dll | FileCheck -check-prefix=CHECK5 %s
+
+CHECK5: Export Table:
+CHECK5: DLL name: export.test.tmp5.dll
+CHECK5: Ordinal RVA Name
+CHECK5-NEXT: 1 0x2010 exportfn3@256
+CHECK5-NEXT: 2 0x2010 exportfn7
+
+# RUN: lld -flavor link /out:%t6.dll /dll /entry:init \
+# RUN: /export:exportfn8 -- %t.obj
+# RUN: llvm-objdump -p %t6.dll | FileCheck -check-prefix=CHECK6 %s
+
+CHECK6: Export Table:
+CHECK6: DLL name: export.test.tmp6.dll
+CHECK6: Ordinal RVA Name
+CHECK6-NEXT: 1 0x2010 exportfn3@256
+CHECK6-NEXT: 2 0x2010 exportfn8
+
+# RUN: lld -flavor link /out:%t7.dll /dll /entry:init \
+# RUN: /export:exportfn7 /export:exportfn7@8 \
+# RUN: /export:exportfn8 /export:exportfn8 /export:exportfn3 -- %t.obj
+# RUN: llvm-objdump -p %t7.dll | FileCheck -check-prefix=DUP %s
+
+DUP: Export Table:
+DUP: DLL name: export.test.tmp7.dll
+DUP: Ordinal RVA Name
+DUP-NEXT: 1 0x2010 exportfn3
+DUP-NEXT: 2 0x2010 exportfn7
+DUP-NEXT: 3 0x2010 exportfn8
+DUP-NOT: ?exportfn8@@YAXXZ
+DUP-NOT: exportfn3@256
+
+# RUN: yaml2obj %p/Inputs/export.obj.yaml > %t.obj
+#
+# RUN: lld -flavor link /out:%t8.dll /dll /entry:init \
+# RUN: /export:f1=exportfn1 /export:f2@4=exportfn2,private -- %t.obj
+# RUN: llvm-objdump -p %t8.dll | FileCheck -check-prefix=EQUAL %s
+
+EQUAL: Export Table:
+EQUAL: DLL name: export.test.tmp8.dll
+EQUAL: Ordinal RVA Name
+EQUAL-NEXT: 1 0x2010 exportfn3@256
+EQUAL-NEXT: 2 0x2008 f1
+EQUAL-NEXT: 3 0x2010 f2{{$}}
diff --git a/test/pecoff/exportlib.test b/test/pecoff/exportlib.test
new file mode 100644
index 000000000000..b65751cfebd7
--- /dev/null
+++ b/test/pecoff/exportlib.test
@@ -0,0 +1,32 @@
+# REQUIRES: winlib
+
+# RUN: yaml2obj %p/Inputs/export.obj.yaml > %t.obj
+#
+# RUN: lld -flavor link /out:%t.dll /dll /entry:init \
+# RUN: /export:exportfn1 /export:exportfn2 -- %t.obj
+# RUN: llvm-readobj %t.lib | FileCheck %s
+
+CHECK: File: exportlib.test.tmp.dll
+CHECK: Format: COFF-i386
+CHECK: Arch: i386
+CHECK: AddressSize: 32bit
+
+CHECK: File: exportlib.test.tmp.dll
+CHECK: Format: COFF-i386
+CHECK: Arch: i386
+CHECK: AddressSize: 32bit
+
+CHECK: File: exportlib.test.tmp.dll
+CHECK: Format: COFF-i386
+CHECK: Arch: i386
+CHECK: AddressSize: 32bit
+
+CHECK: File: exportlib.test.tmp.dll
+CHECK: Format: COFF-<unknown arch>
+CHECK: Arch: unknown
+CHECK: AddressSize: 32bit
+
+CHECK: File: exportlib.test.tmp.dll
+CHECK: Format: COFF-<unknown arch>
+CHECK: Arch: unknown
+CHECK: AddressSize: 32bit
diff --git a/test/pecoff/exportlib2.test b/test/pecoff/exportlib2.test
new file mode 100644
index 000000000000..e846b0bdd064
--- /dev/null
+++ b/test/pecoff/exportlib2.test
@@ -0,0 +1,21 @@
+# RUN: yaml2obj %p/Inputs/export.obj.yaml > %t.obj
+#
+# RUN: lld -flavor link /out:%t.dll /dll /entry:init \
+# RUN: /export:exportfn1 /export:exportfn2 /lldmoduledeffile:%t1.def -- %t.obj
+# RUN: FileCheck -check-prefix=CHECK1 %s < %t1.def
+
+CHECK1: LIBRARY "exportlib2.test.tmp.dll"
+CHECK1: EXPORTS
+CHECK1: exportfn1 @1
+CHECK1: exportfn2 @2
+CHECK1: exportfn3@256 @3
+
+# RUN: lld -flavor link /out:%t.dll /dll /entry:init \
+# RUN: /def:%p/Inputs/exports2.def /lldmoduledeffile:%t2.def -- %t.obj
+# RUN: FileCheck -check-prefix=CHECK2 %s < %t2.def
+
+CHECK2: LIBRARY "exportlib2.test.tmp.dll"
+CHECK2: EXPORTS
+CHECK2: exportfn1 @5
+CHECK2: exportfn3@256 @6
+CHECK2: exportfn7@8 @7
diff --git a/test/pecoff/grouped-sections.test b/test/pecoff/grouped-sections.test
new file mode 100644
index 000000000000..40ae1478997e
--- /dev/null
+++ b/test/pecoff/grouped-sections.test
@@ -0,0 +1,17 @@
+# RUN: yaml2obj %p/Inputs/grouped-sections.obj.yaml > %t.obj
+#
+# RUN: lld -flavor link /out:%t.exe /subsystem:console /entry:main -- %t.obj
+# RUN: llvm-objdump -s %t.exe | FileCheck %s
+#
+# The file "grouped-sections.obj" has three data sections in the following
+# order:
+#
+# .data$2
+# .data$1
+# .data
+#
+# If all the sections will be merged correctly, the resulting ".data"
+# section will have the string "Hello, world".
+
+CHECK: Contents of section .data:
+CHECK-NEXT: Hello, world
diff --git a/test/pecoff/hello.test b/test/pecoff/hello.test
new file mode 100644
index 000000000000..679b8b3ad984
--- /dev/null
+++ b/test/pecoff/hello.test
@@ -0,0 +1,51 @@
+# RUN: yaml2obj %p/Inputs/hello.obj.yaml > %t.obj
+
+# RUN: lld -flavor link /out:%t1.exe /subsystem:console /force -- %t.obj
+# RUN: llvm-readobj -file-headers %t1.exe | FileCheck -check-prefix=FILE %s
+
+FILE: ImageOptionalHeader {
+FILE: SizeOfInitializedData: 1024
+FILE: SizeOfHeaders: 512
+FILE: }
+
+# RUN: lld -flavor link /out:%t2.exe /subsystem:console /force -- %t.obj
+# RUN: llvm-readobj -sections %t2.exe | FileCheck -check-prefix=SECTIONS %s
+
+SECTIONS: Format: COFF-i386
+SECTIONS-NEXT: Arch: i386
+SECTIONS-NEXT: AddressSize: 32bit
+SECTIONS-NEXT: Sections [
+SECTIONS-NEXT: Section {
+SECTIONS-NEXT: Number: 1
+SECTIONS-NEXT: Name: .data
+SECTIONS-NEXT: VirtualSize: 0x12
+SECTIONS-NEXT: VirtualAddress: 0x1000
+SECTIONS-NEXT: RawDataSize: 512
+SECTIONS-NEXT: PointerToRawData: 0x200
+SECTIONS-NEXT: PointerToRelocations: 0x0
+SECTIONS-NEXT: PointerToLineNumbers: 0x0
+SECTIONS-NEXT: RelocationCount: 0
+SECTIONS-NEXT: LineNumberCount: 0
+SECTIONS-NEXT: Characteristics [
+SECTIONS-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
+SECTIONS-NEXT: IMAGE_SCN_MEM_READ
+SECTIONS-NEXT: IMAGE_SCN_MEM_WRITE
+SECTIONS-NEXT: ]
+SECTIONS-NEXT: }
+SECTIONS-NEXT: Section {
+SECTIONS-NEXT: Number: 2
+SECTIONS-NEXT: Name: .text (2E 74 65 78 74 00 00 00)
+SECTIONS-NEXT: VirtualSize: 0x1C
+SECTIONS-NEXT: VirtualAddress: 0x2000
+SECTIONS-NEXT: RawDataSize: 512
+SECTIONS-NEXT: PointerToRawData: 0x400
+SECTIONS-NEXT: PointerToRelocations: 0x0
+SECTIONS-NEXT: PointerToLineNumbers: 0x0
+SECTIONS-NEXT: RelocationCount: 0
+SECTIONS-NEXT: LineNumberCount: 0
+SECTIONS-NEXT: Characteristics [
+SECTIONS-NEXT: IMAGE_SCN_CNT_CODE
+SECTIONS-NEXT: IMAGE_SCN_MEM_EXECUTE
+SECTIONS-NEXT: IMAGE_SCN_MEM_READ
+SECTIONS-NEXT: ]
+SECTIONS-NEXT: }
diff --git a/test/pecoff/hello64.test b/test/pecoff/hello64.test
new file mode 100644
index 000000000000..7536e5a8fd26
--- /dev/null
+++ b/test/pecoff/hello64.test
@@ -0,0 +1,22 @@
+# REQUIRES: x86
+
+# RUN: yaml2obj %p/Inputs/hello64.obj.yaml > %t.obj
+
+# RUN: lld -flavor link /out:%t.exe /subsystem:windows /machine:x64 \
+# RUN: /entry:main -- %t.obj %p/Inputs/hello64lib.lib
+# RUN: llvm-objdump -disassemble %t.exe | FileCheck %s
+
+CHECK: 6000: 48 83 ec 28 subq $40, %rsp
+CHECK: 6004: 48 c7 c1 00 00 00 00 movq $0, %rcx
+CHECK: 600b: 48 8d 15 f4 af ff ff leaq -20492(%rip), %rdx
+CHECK: 6012: 4c 8d 05 e7 af ff ff leaq -20505(%rip), %r8
+CHECK: 6019: 41 b9 00 00 00 00 movl $0, %r9d
+CHECK: 601f: e8 12 00 00 00 callq 18
+CHECK: 6024: b9 00 00 00 00 movl $0, %ecx
+CHECK: 6029: e8 00 00 00 00 callq 0
+CHECK: 602e: ff 25 cc cf ff ff jmpq *-12340(%rip)
+CHECK: 6034: cc int3
+CHECK: 6035: cc int3
+CHECK: 6036: ff 25 cc cf ff ff jmpq *-12340(%rip)
+CHECK: 603c: cc int3
+CHECK: 603d: cc int3
diff --git a/test/pecoff/help.test b/test/pecoff/help.test
new file mode 100644
index 000000000000..f5e9c358f1a8
--- /dev/null
+++ b/test/pecoff/help.test
@@ -0,0 +1,4 @@
+# RUN: not lld -flavor link /help | FileCheck %s
+# RUN: not lld -flavor link '/?' | FileCheck %s
+
+CHECK: USAGE
diff --git a/test/pecoff/imagebase.test b/test/pecoff/imagebase.test
new file mode 100644
index 000000000000..bb83e6b66124
--- /dev/null
+++ b/test/pecoff/imagebase.test
@@ -0,0 +1,15 @@
+# REQUIRES: x86
+
+# RUN: yaml2obj %p/Inputs/imagebase.obj.yaml > %t.obj
+
+# RUN: lld -flavor link /out:%t1.exe /subsystem:console /entry:_start \
+# RUN: /opt:noref -- %t.obj
+# RUN: llvm-objdump -disassemble %t1.exe | FileCheck -check-prefix=DEFAULT %s
+
+DEFAULT: a1 00 00 40 00 movl 4194304, %eax
+
+# RUN: lld -flavor link /out:%t2.exe /subsystem:console /entry:_start \
+# RUN: /base:65536 /opt:noref -- %t.obj
+# RUN: llvm-objdump -disassemble %t2.exe | FileCheck -check-prefix=BASE %s
+
+BASE: a1 00 00 01 00 movl 65536, %eax
diff --git a/test/pecoff/importlib.test b/test/pecoff/importlib.test
new file mode 100644
index 000000000000..28e74f9dc78d
--- /dev/null
+++ b/test/pecoff/importlib.test
@@ -0,0 +1,55 @@
+# REQUIRES: x86
+
+# Verify that lld can handle .lib files. "main.obj" refers "var" and
+# "fn" defined in "vars.lib".
+#
+# RUN: yaml2obj %p/Inputs/vars-main-x86.obj.yaml > %t.obj
+#
+# RUN: lld -flavor link /out:%t1.exe /subsystem:console /entry:main /opt:noref \
+# RUN: -- %t.obj %p/Inputs/vars.lib
+# RUN: llvm-objdump -d %t1.exe | FileCheck -check-prefix=TEXT %s
+# RUN: llvm-readobj -coff-imports %t1.exe | FileCheck -check-prefix=IMPORT %s
+#
+# RUN: lld -flavor link /out:%t2.exe /subsystem:console /entry:main /opt:noref \
+# RUN: /libpath:%p/Inputs -- %t.obj vars.lib
+# RUN: llvm-objdump -d %t2.exe | FileCheck -check-prefix=TEXT %s
+# RUN: llvm-readobj -coff-imports %t2.exe | FileCheck -check-prefix=IMPORT %s
+#
+# RUN: lld -flavor link /out:%t3.exe /subsystem:console /entry:main /opt:noref \
+# RUN: /libpath:%p/Inputs /defaultlib:vars.lib -- %t.obj
+# RUN: llvm-objdump -d %t3.exe | FileCheck -check-prefix=TEXT %s
+# RUN: llvm-readobj -coff-imports %t3.exe | FileCheck -check-prefix=IMPORT %s
+#
+# RUN: env LIB=%p/Inputs lld -flavor link /out:%t4.exe /subsystem:console \
+# RUN: /opt:noref /entry:main -- %t.obj vars.lib
+# RUN: llvm-objdump -d %t4.exe | FileCheck -check-prefix=TEXT %s
+# RUN: llvm-readobj -coff-imports %t4.exe | FileCheck -check-prefix=IMPORT %s
+#
+# RUN: env LINK="/out:%t5.exe /subsystem:console /entry:main /opt:noref \
+# RUN: -- %t.obj" lld -flavor link %p/Inputs/vars.lib
+# RUN: llvm-objdump -d %t5.exe | FileCheck -check-prefix=TEXT %s
+# RUN: llvm-readobj -coff-imports %t5.exe | FileCheck -check-prefix=IMPORT %s
+
+TEXT: Disassembly of section .text:
+TEXT-NEXT: .text:
+TEXT-NEXT: pushl %ebp
+TEXT-NEXT: movl %esp, %ebp
+TEXT-NEXT: pushl %esi
+TEXT-NEXT: calll *{{[0-9]+}}
+TEXT-NEXT: movl {{[0-9]+}}, %ecx
+TEXT-NEXT: movl (%ecx), %esi
+TEXT-NEXT: addl %eax, %esi
+TEXT-NEXT: calll *{{[0-9]+}}
+TEXT-NEXT: addl %esi, %eax
+TEXT-NEXT: popl %esi
+TEXT-NEXT: popl %ebp
+TEXT-NEXT: ret
+
+IMPORT: Import {
+IMPORT-NEXT: Name: vars.dll
+IMPORT-NEXT: ImportLookupTableRVA: 0x4000
+IMPORT-NEXT: ImportAddressTableRVA: 0x2000
+IMPORT-NEXT: Symbol: _name_with_underscore (0)
+IMPORT-NEXT: Symbol: fn (1)
+IMPORT-NEXT: Symbol: (1)
+IMPORT-NEXT: }
diff --git a/test/pecoff/include.test b/test/pecoff/include.test
new file mode 100644
index 000000000000..bee1f48bf1a7
--- /dev/null
+++ b/test/pecoff/include.test
@@ -0,0 +1,8 @@
+# RUN: yaml2obj %p/Inputs/nop.obj.yaml > %t.obj
+#
+# RUN: not lld -flavor link /out:%t.exe /include:sym1 /include:sym2 \
+# RUN: /subsystem:console -- %t.obj 2> %t.log
+# RUN: FileCheck %s < %t.log
+
+CHECK: Undefined symbol: <command line option /include>: sym1
+CHECK: Undefined symbol: <command line option /include>: sym2
diff --git a/test/pecoff/lib.test b/test/pecoff/lib.test
new file mode 100644
index 000000000000..f435c117bc46
--- /dev/null
+++ b/test/pecoff/lib.test
@@ -0,0 +1,15 @@
+# REQUIRES: x86
+
+# Verify that lld can handle a library file.
+#
+# RUN: yaml2obj %p/Inputs/main.obj.yaml > %t.obj
+#
+# RUN: lld -flavor link /out:%t.exe /subsystem:console /entry:main /opt:noref \
+# RUN: -- %t.obj %p/Inputs/static.lib
+# RUN: llvm-objdump -d %t.exe | FileCheck %s
+
+CHECK: Disassembly of section .text:
+CHECK-NEXT: .text:
+CHECK-NEXT: movl 4198400, %eax
+CHECK-NEXT: addl 4198404, %eax
+CHECK-NEXT: ret
diff --git a/test/pecoff/libarg.test b/test/pecoff/libarg.test
new file mode 100644
index 000000000000..314f030c4fe0
--- /dev/null
+++ b/test/pecoff/libarg.test
@@ -0,0 +1,9 @@
+# REQUIRES: winlib
+#
+# If argv[1] == "/lib", link.exe morphs into lib.exe.
+#
+# RUN: lld -flavor link /lib >& %t.log
+# RUN: FileCheck %s < %t.log
+
+CHECK-NOT: unrecognized option '/lib'
+CHECK: usage: LIB
diff --git a/test/pecoff/localyimported.test b/test/pecoff/localyimported.test
new file mode 100644
index 000000000000..52b32d7b80bd
--- /dev/null
+++ b/test/pecoff/localyimported.test
@@ -0,0 +1,15 @@
+# RUN: yaml2obj %p/Inputs/hello.obj.yaml > %t.obj
+#
+# RUN: not lld -flavor link /out:%t.exe /include:__imp__nosuchsym %t.obj \
+# RUN: >& %t.log
+# RUN: FileCheck -check-prefix=X86 %s < %t.log
+
+X86: Undefined symbol: __imp__nosuchsym: _nosuchsym
+
+# RUN: yaml2obj %p/Inputs/hello64.obj.yaml > %t2.obj
+#
+# RUN: not lld -flavor link /out:%t2.exe /include:__imp__nosuchsym %t2.obj \
+# RUN: /machine:x64 >& %t2.log
+# RUN: FileCheck -check-prefix=X64 %s < %t2.log
+
+X64: Undefined symbol: __imp__nosuchsym: _nosuchsym
diff --git a/test/pecoff/long-section-name.test b/test/pecoff/long-section-name.test
new file mode 100644
index 000000000000..e6721c28302f
--- /dev/null
+++ b/test/pecoff/long-section-name.test
@@ -0,0 +1,7 @@
+# RUN: yaml2obj %p/Inputs/nop.obj.yaml > %t.obj
+#
+# RUN: lld -flavor link /out:%t.exe /subsystem:console /entry:start \
+# RUN: /merge:.text=.longsectionname -- %t.obj
+# RUN: llvm-readobj -sections %t.exe | FileCheck %s
+
+CHECK: Name: .longsectionname (2F 34 00 00 00 00 00 00)
diff --git a/test/pecoff/machinetype.test b/test/pecoff/machinetype.test
new file mode 100644
index 000000000000..5d387f3b0393
--- /dev/null
+++ b/test/pecoff/machinetype.test
@@ -0,0 +1,13 @@
+# RUN: yaml2obj %p/Inputs/machine-type-unknown.obj.yaml > %t1.obj
+# RUN: yaml2obj %p/Inputs/hello.obj.yaml > %t2.obj
+# RUN: yaml2obj %p/Inputs/hello64.obj.yaml > %t3.obj
+
+# RUN: lld -flavor link /out:%t.exe /subsystem:console /force -- %t1.obj %t2.obj
+# RUN: llvm-readobj %t.exe | FileCheck -check-prefix=X86 %s
+
+X86: Arch: i386
+
+# RUN: lld -flavor link /out:%t.exe /subsystem:console /force -- %t1.obj %t3.obj
+# RUN: llvm-readobj %t.exe | FileCheck -check-prefix=X64 %s
+
+X64: Arch: x86_64
diff --git a/test/pecoff/manifest.test b/test/pecoff/manifest.test
new file mode 100644
index 000000000000..33229a45516b
--- /dev/null
+++ b/test/pecoff/manifest.test
@@ -0,0 +1,63 @@
+# RUN: yaml2obj %p/Inputs/nop.obj.yaml > %t.obj
+
+# RUN: lld -flavor link /out:%t1.exe /subsystem:console /force \
+# RUN: -- %t.obj
+# RUN: FileCheck -check-prefix=MANIFEST %s < %t1.exe.manifest
+
+MANIFEST: <?xml version="1.0" standalone="yes"?>
+MANIFEST: <assembly xmlns="urn:schemas-microsoft-com:asm.v1"
+MANIFEST: manifestVersion="1.0">
+MANIFEST: <trustInfo>
+MANIFEST: <security>
+MANIFEST: <requestedPrivileges>
+MANIFEST: <requestedExecutionLevel level='asInvoker' uiAccess='false'/>
+MANIFEST: </requestedPrivileges>
+MANIFEST: </security>
+MANIFEST: </trustInfo>
+MANIFEST: </assembly>
+
+# RUN: lld -flavor link /out:%t2.exe /subsystem:console /force \
+# RUN: /manifestuac:"level='requireAdministrator' uiAccess='true'" -- %t.obj
+# RUN: FileCheck -check-prefix=UAC %s < %t2.exe.manifest
+
+UAC: <?xml version="1.0" standalone="yes"?>
+UAC: <assembly xmlns="urn:schemas-microsoft-com:asm.v1"
+UAC: manifestVersion="1.0">
+UAC: <trustInfo>
+UAC: <security>
+UAC: <requestedPrivileges>
+UAC: <requestedExecutionLevel level='requireAdministrator' uiAccess='true'/>
+UAC: </requestedPrivileges>
+UAC: </security>
+UAC: </trustInfo>
+UAC: </assembly>
+
+# RUN: lld -flavor link /out:%t3.exe /subsystem:console /force \
+# RUN: /manifestdependency:"foo='bar'" -- %t.obj
+# RUN: FileCheck -check-prefix=DEPENDENCY %s < %t3.exe.manifest
+
+DEPENDENCY: <?xml version="1.0" standalone="yes"?>
+DEPENDENCY: <assembly xmlns="urn:schemas-microsoft-com:asm.v1"
+DEPENDENCY: manifestVersion="1.0">
+DEPENDENCY: <trustInfo>
+DEPENDENCY: <security>
+DEPENDENCY: <requestedPrivileges>
+DEPENDENCY: <requestedExecutionLevel level='asInvoker' uiAccess='false'/>
+DEPENDENCY: </requestedPrivileges>
+DEPENDENCY: </security>
+DEPENDENCY: </trustInfo>
+DEPENDENCY: <dependency>
+DEPENDENCY: <dependentAssembly>
+DEPENDENCY: <assemblyIdentity foo='bar' />
+DEPENDENCY: </dependentAssembly>
+DEPENDENCY: </dependency>
+DEPENDENCY: </assembly>
+
+# RUN: lld -flavor link /out:%t4.exe /subsystem:console /force \
+# RUN: /manifestuac:no -- %t.obj
+# RUN: FileCheck -check-prefix=NOUAC %s < %t4.exe.manifest
+
+NOUAC: <?xml version="1.0" standalone="yes"?>
+NOUAC: <assembly xmlns="urn:schemas-microsoft-com:asm.v1"
+NOUAC: manifestVersion="1.0">
+NOUAC: </assembly>
diff --git a/test/pecoff/merge-largest.test b/test/pecoff/merge-largest.test
new file mode 100644
index 000000000000..c3ee96ca9c53
--- /dev/null
+++ b/test/pecoff/merge-largest.test
@@ -0,0 +1,24 @@
+# RUN: yaml2obj %p/Inputs/merge-largest1.obj.yaml > %t1.obj
+# RUN: yaml2obj %p/Inputs/merge-largest2.obj.yaml > %t2.obj
+#
+# RUN: lld -flavor link /out:%t.exe /subsystem:console /opt:noref /force \
+# RUN: -- %t1.obj %t2.obj 2>&1 > %t.log
+#
+# FileCheck complains if the input files is empty, so add a dummy line.
+# RUN: echo foo >> %t.log
+# RUN: FileCheck -check-prefix=STDERR %s < %t.log
+#
+# RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=READOBJ %s
+
+STDERR-NOT: duplicate symbol error
+
+READOBJ: Format: COFF-i386
+READOBJ-NEXT: Arch: i386
+READOBJ-NEXT: AddressSize: 32bit
+READOBJ-NEXT: Sections [
+READOBJ-NEXT: Section {
+READOBJ-NEXT: Number: 1
+READOBJ-NEXT: Name: .text (2E 74 65 78 74 00 00 00)
+READOBJ-NEXT: VirtualSize: 0x8
+READOBJ-NEXT: VirtualAddress: 0x1000
+READOBJ-NEXT: RawDataSize: 512
diff --git a/test/pecoff/merge-same-size.test b/test/pecoff/merge-same-size.test
new file mode 100644
index 000000000000..c2918a2bc1a4
--- /dev/null
+++ b/test/pecoff/merge-same-size.test
@@ -0,0 +1,32 @@
+# RUN: yaml2obj %p/Inputs/merge-same-size1.obj.yaml > %t1.obj
+# RUN: yaml2obj %p/Inputs/merge-same-size2.obj.yaml > %t2.obj
+# RUN: yaml2obj %p/Inputs/merge-same-size3.obj.yaml > %t3.obj
+#
+# RUN: lld -flavor link /out:%t.exe /subsystem:console /opt:noref /force \
+# RUN: -- %t1.obj %t2.obj > %t1.log 2>&1
+#
+# FileCheck complains if the input files is empty, so add a dummy line.
+# RUN: echo foo >> %t1.log
+# RUN: FileCheck -check-prefix=SAMESIZE %s < %t1.log
+#
+# RUN: not lld -flavor link /out:%t.exe /subsystem:console /opt:noref /force \
+# RUN: -- %t1.obj %t3.obj > %t2.log 2>&1
+# RUN: FileCheck -check-prefix=DIFFERENT %s < %t2.log
+#
+# RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=READOBJ %s
+
+SAMESIZE-NOT: duplicate symbol error
+
+DIFFERENT: Size mismatch
+DIFFERENT: duplicate symbol error
+
+READOBJ: Format: COFF-i386
+READOBJ-NEXT: Arch: i386
+READOBJ-NEXT: AddressSize: 32bit
+READOBJ-NEXT: Sections [
+READOBJ-NEXT: Section {
+READOBJ-NEXT: Number: 1
+READOBJ-NEXT: Name: .text (2E 74 65 78 74 00 00 00)
+READOBJ-NEXT: VirtualSize: 0x7
+READOBJ-NEXT: VirtualAddress: 0x1000
+READOBJ-NEXT: RawDataSize: 512
diff --git a/test/pecoff/multi.test b/test/pecoff/multi.test
new file mode 100644
index 000000000000..e0bfdba6dda4
--- /dev/null
+++ b/test/pecoff/multi.test
@@ -0,0 +1,17 @@
+# REQUIRES: x86
+
+# Verify that lld can handle multiple input files.
+#
+# RUN: yaml2obj %p/Inputs/main.obj.yaml > %t1.obj
+# RUN: yaml2obj %p/Inputs/static-data1.obj.yaml > %t2.obj
+# RUN: yaml2obj %p/Inputs/static-data2.obj.yaml > %t3.obj
+#
+# RUN: lld -flavor link /out:%t.exe /subsystem:console /entry:main /opt:noref \
+# RUN: -- %t1.obj %t2.obj %t3.obj
+# RUN: llvm-objdump -d %t.exe | FileCheck %s
+
+CHECK: Disassembly of section .text:
+CHECK: .text:
+CHECK: movl {{[0-9]+}}, %eax
+CHECK: addl {{[0-9]+}}, %eax
+CHECK: ret
diff --git a/test/pecoff/noentry.test b/test/pecoff/noentry.test
new file mode 100644
index 000000000000..55b326dd84cb
--- /dev/null
+++ b/test/pecoff/noentry.test
@@ -0,0 +1,10 @@
+# RUN: yaml2obj %p/Inputs/nop.obj.yaml > %t.obj
+# RUN: lld -flavor link /out:%t.exe /noentry /dll -- %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
+
+CHECK: AddressOfEntryPoint: 0x0
+
+# RUN: not lld -flavor link /out:%t.exe /noentry -- %t.obj >& %t.log
+# RUN: FileCheck --check-prefix=ERROR %s < %t.log
+
+ERROR: /noentry must be specified with /dll
diff --git a/test/pecoff/nonstandard-sections.test b/test/pecoff/nonstandard-sections.test
new file mode 100644
index 000000000000..2ca181629230
--- /dev/null
+++ b/test/pecoff/nonstandard-sections.test
@@ -0,0 +1,75 @@
+# RUN: yaml2obj %p/Inputs/nonstandard-sections.obj.yaml > %t.obj
+# RUN: lld -flavor link /out:%t.exe /subsystem:console /force -- %t.obj
+# RUN: llvm-readobj -sections %t.exe | FileCheck %s
+
+CHECK: Arch: i386
+CHECK-NEXT: AddressSize: 32bit
+CHECK-NEXT: Sections [
+CHECK-NEXT: Section {
+CHECK-NEXT: Number: 1
+CHECK-NEXT: Name: .bar (2E 62 61 72 00 00 00 00)
+CHECK-NEXT: VirtualSize: 0x4
+CHECK-NEXT: VirtualAddress: 0x1000
+CHECK-NEXT: RawDataSize: 512
+CHECK-NEXT: PointerToRawData: 0x400
+CHECK-NEXT: PointerToRelocations: 0x0
+CHECK-NEXT: PointerToLineNumbers: 0x0
+CHECK-NEXT: RelocationCount: 0
+CHECK-NEXT: LineNumberCount: 0
+CHECK-NEXT: Characteristics [ (0x40000040)
+CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA (0x40)
+CHECK-NEXT: IMAGE_SCN_MEM_READ (0x40000000)
+CHECK-NEXT: ]
+CHECK-NEXT: }
+CHECK-NEXT: Section {
+CHECK-NEXT: Number: 2
+CHECK-NEXT: Name: .data (2E 64 61 74 61 00 00 00)
+CHECK-NEXT: VirtualSize: 0x4
+CHECK-NEXT: VirtualAddress: 0x2000
+CHECK-NEXT: RawDataSize: 512
+CHECK-NEXT: PointerToRawData: 0x600
+CHECK-NEXT: PointerToRelocations: 0x0
+CHECK-NEXT: PointerToLineNumbers: 0x0
+CHECK-NEXT: RelocationCount: 0
+CHECK-NEXT: LineNumberCount: 0
+CHECK-NEXT: Characteristics [ (0xC0000040)
+CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA (0x40)
+CHECK-NEXT: IMAGE_SCN_MEM_READ (0x40000000)
+CHECK-NEXT: IMAGE_SCN_MEM_WRITE (0x80000000)
+CHECK-NEXT: ]
+CHECK-NEXT: }
+CHECK-NEXT: Section {
+CHECK-NEXT: Number: 3
+CHECK-NEXT: Name: .foo (2E 66 6F 6F 00 00 00 00)
+CHECK-NEXT: VirtualSize: 0x4
+CHECK-NEXT: VirtualAddress: 0x3000
+CHECK-NEXT: RawDataSize: 512
+CHECK-NEXT: PointerToRawData: 0x800
+CHECK-NEXT: PointerToRelocations: 0x0
+CHECK-NEXT: PointerToLineNumbers: 0x0
+CHECK-NEXT: RelocationCount: 0
+CHECK-NEXT: LineNumberCount: 0
+CHECK-NEXT: Characteristics [ (0xC0000040)
+CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA (0x40)
+CHECK-NEXT: IMAGE_SCN_MEM_READ (0x40000000)
+CHECK-NEXT: IMAGE_SCN_MEM_WRITE (0x80000000)
+CHECK-NEXT: ]
+CHECK-NEXT: }
+CHECK-NEXT: Section {
+CHECK-NEXT: Number: 4
+CHECK-NEXT: Name: .text (2E 74 65 78 74 00 00 00)
+CHECK-NEXT: VirtualSize: 0x4
+CHECK-NEXT: VirtualAddress: 0x4000
+CHECK-NEXT: RawDataSize: 512
+CHECK-NEXT: PointerToRawData: 0xA00
+CHECK-NEXT: PointerToRelocations: 0x0
+CHECK-NEXT: PointerToLineNumbers: 0x0
+CHECK-NEXT: RelocationCount: 0
+CHECK-NEXT: LineNumberCount: 0
+CHECK-NEXT: Characteristics [ (0x60000020)
+CHECK-NEXT: IMAGE_SCN_CNT_CODE (0x20)
+CHECK-NEXT: IMAGE_SCN_MEM_EXECUTE (0x20000000)
+CHECK-NEXT: IMAGE_SCN_MEM_READ (0x40000000)
+CHECK-NEXT: ]
+CHECK-NEXT: }
+CHECK-NEXT: ]
diff --git a/test/pecoff/options.test b/test/pecoff/options.test
new file mode 100644
index 000000000000..3aca2c9fcc91
--- /dev/null
+++ b/test/pecoff/options.test
@@ -0,0 +1,40 @@
+# Tests for miscellaneous command line options.
+
+# RUN: yaml2obj %p/Inputs/nop.obj.yaml > %t-x86.obj
+# RUN: yaml2obj %p/Inputs/nop64.obj.yaml > %t-x64.obj
+
+# RUN: lld -flavor link /align:8192 /out:%t.exe /entry:start \
+# RUN: /subsystem:console -- %t-x86.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=ALIGN %s
+ALIGN: SectionAlignment: 8192
+
+# RUN: lld -flavor link /allowbind:no /out:%t.exe /entry:start \
+# RUN: /subsystem:console -- %t-x86.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NOBIND %s
+NOBIND: IMAGE_DLL_CHARACTERISTICS_NO_BIND
+
+# RUN: lld -flavor link /allowisolation:no /out:%t.exe /entry:start \
+# RUN: /subsystem:console -- %t-x86.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NOISO %s
+NOISO: IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION
+
+# RUN: lld -flavor link /swaprun:cd /out:%t.exe /entry:start \
+# RUN: /subsystem:console -- %t-x86.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=RUNCD %s
+RUNCD: IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP
+
+# RUN: lld -flavor link /swaprun:net /out:%t.exe /entry:start \
+# RUN: /subsystem:console -- %t-x86.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=RUNNET %s
+RUNNET: IMAGE_FILE_NET_RUN_FROM_SWAP
+
+# RUN: lld -flavor link /machine:x64 /force /highentropyva /out:%t.exe \
+# RUN: /entry:start /subsystem:console -- %t-x64.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=ENT %s
+ENT: IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA
+
+# RUN: lld -flavor link /machine:x64 /force /highentropyva:no /out:%t.exe \
+# RUN: /entry:start /subsystem:console -- %t-x64.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NOENT %s
+NOENT-NOT: IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA
+
diff --git a/test/pecoff/pe32plus.test b/test/pecoff/pe32plus.test
new file mode 100644
index 000000000000..1c64e184cbaf
--- /dev/null
+++ b/test/pecoff/pe32plus.test
@@ -0,0 +1,87 @@
+# RUN: yaml2obj %p/Inputs/nop64.obj.yaml > %t.obj
+
+# RUN: lld -flavor link /out:%t.exe /subsystem:console /entry:start \
+# RUN: /machine:x64 -- %t.obj %p/Inputs/vars.lib
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
+
+CHECK: Format: COFF-x86-64
+CHECK-NEXT: Arch: x86_64
+CHECK-NEXT: AddressSize: 64bit
+CHECK-NEXT: ImageFileHeader {
+CHECK-NEXT: Machine: IMAGE_FILE_MACHINE_AMD64 (0x8664)
+CHECK-NEXT: SectionCount: 5
+CHECK-NEXT: TimeDateStamp:
+CHECK-NEXT: PointerToSymbolTable: 0x0
+CHECK-NEXT: SymbolCount: 0
+CHECK-NEXT: OptionalHeaderSize: 240
+CHECK-NEXT: Characteristics [ (0x22)
+CHECK-NEXT: IMAGE_FILE_EXECUTABLE_IMAGE (0x2)
+CHECK-NEXT: IMAGE_FILE_LARGE_ADDRESS_AWARE (0x20)
+CHECK-NEXT: ]
+CHECK-NEXT: }
+CHECK-NEXT: ImageOptionalHeader {
+CHECK-NEXT: MajorLinkerVersion: 0
+CHECK-NEXT: MinorLinkerVersion: 0
+CHECK-NEXT: SizeOfCode: 512
+CHECK-NEXT: SizeOfInitializedData: 2048
+CHECK-NEXT: SizeOfUninitializedData: 0
+CHECK-NEXT: AddressOfEntryPoint: 0x5000
+CHECK-NEXT: BaseOfCode: 0x5000
+CHECK-NEXT: ImageBase: 0x140000000
+CHECK-NEXT: SectionAlignment: 4096
+CHECK-NEXT: FileAlignment: 512
+CHECK-NEXT: MajorOperatingSystemVersion: 6
+CHECK-NEXT: MinorOperatingSystemVersion: 0
+CHECK-NEXT: MajorImageVersion: 0
+CHECK-NEXT: MinorImageVersion: 0
+CHECK-NEXT: MajorSubsystemVersion: 6
+CHECK-NEXT: MinorSubsystemVersion: 0
+CHECK-NEXT: SizeOfImage: 24576
+CHECK-NEXT: SizeOfHeaders: 1024
+CHECK-NEXT: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI (0x3)
+CHECK-NEXT: Characteristics [ (0x8160)
+CHECK-NEXT: IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE (0x40)
+CHECK-NEXT: IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA (0x20)
+CHECK-NEXT: IMAGE_DLL_CHARACTERISTICS_NX_COMPAT (0x100)
+CHECK-NEXT: IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE (0x8000)
+CHECK-NEXT: ]
+CHECK-NEXT: SizeOfStackReserve: 1048576
+CHECK-NEXT: SizeOfStackCommit: 4096
+CHECK-NEXT: SizeOfHeapReserve: 1048576
+CHECK-NEXT: SizeOfHeapCommit: 4096
+CHECK-NEXT: NumberOfRvaAndSize: 16
+CHECK-NEXT: DataDirectory {
+CHECK-NEXT: ExportTableRVA: 0x0
+CHECK-NEXT: ExportTableSize: 0x0
+CHECK-NEXT: ImportTableRVA: 0x3000
+CHECK-NEXT: ImportTableSize: 0x28
+CHECK-NEXT: ResourceTableRVA: 0x0
+CHECK-NEXT: ResourceTableSize: 0x0
+CHECK-NEXT: ExceptionTableRVA: 0x0
+CHECK-NEXT: ExceptionTableSize: 0x0
+CHECK-NEXT: CertificateTableRVA: 0x0
+CHECK-NEXT: CertificateTableSize: 0x0
+CHECK-NEXT: BaseRelocationTableRVA: 0x0
+CHECK-NEXT: BaseRelocationTableSize: 0x0
+CHECK-NEXT: DebugRVA: 0x0
+CHECK-NEXT: DebugSize: 0x0
+CHECK-NEXT: ArchitectureRVA: 0x0
+CHECK-NEXT: ArchitectureSize: 0x0
+CHECK-NEXT: GlobalPtrRVA: 0x0
+CHECK-NEXT: GlobalPtrSize: 0x0
+CHECK-NEXT: TLSTableRVA: 0x0
+CHECK-NEXT: TLSTableSize: 0x0
+CHECK-NEXT: LoadConfigTableRVA: 0x0
+CHECK-NEXT: LoadConfigTableSize: 0x0
+CHECK-NEXT: BoundImportRVA: 0x0
+CHECK-NEXT: BoundImportSize: 0x0
+CHECK-NEXT: IATRVA: 0x2000
+CHECK-NEXT: IATSize: 0x10
+CHECK-NEXT: DelayImportDescriptorRVA: 0x0
+CHECK-NEXT: DelayImportDescriptorSize: 0x0
+CHECK-NEXT: CLRRuntimeHeaderRVA: 0x0
+CHECK-NEXT: CLRRuntimeHeaderSize: 0x0
+CHECK-NEXT: ReservedRVA: 0x0
+CHECK-NEXT: ReservedSize: 0x0
+CHECK-NEXT: }
+CHECK-NEXT: }
diff --git a/test/pecoff/reloc.test b/test/pecoff/reloc.test
new file mode 100644
index 000000000000..5a969e9beaa0
--- /dev/null
+++ b/test/pecoff/reloc.test
@@ -0,0 +1,16 @@
+# REQUIRES: x86
+
+# RUN: yaml2obj %p/Inputs/reloc.obj.yaml > %t1.obj
+# RUN: yaml2obj %p/Inputs/abs.obj.yaml > %t2.obj
+#
+# RUN: lld -flavor link /out:%t.exe /subsystem:console /force /opt:noref \
+# RUN: -- %t1.obj %t2.obj
+# RUN: llvm-objdump -d %t.exe | FileCheck %s
+
+CHECK: .text:
+CHECK: 3000: 68 02 00 00 00
+CHECK: 3005: 68 05 00 00 00
+CHECK: 300a: 68 00 10 40 00
+CHECK: 300f: 68 00 10 40 00
+CHECK: 3014: 68 00 20 40 00
+CHECK: 3019: 68 ef be ad de
diff --git a/test/pecoff/reloc64.test b/test/pecoff/reloc64.test
new file mode 100644
index 000000000000..fc38bff03275
--- /dev/null
+++ b/test/pecoff/reloc64.test
@@ -0,0 +1,20 @@
+# REQUIRES: x86
+
+# RUN: yaml2obj %p/Inputs/reloc64.obj.yaml > %t.obj
+
+# RUN: lld -flavor link /out:%t.exe /subsystem:console /machine:x64 \
+# RUN: /entry:entry -- %t.obj
+# RUN: llvm-objdump -d %t.exe | FileCheck %s
+
+CHECK: Disassembly of section .text:
+CHECK-NEXT: .text:
+CHECK-NEXT: 1000: 48 b8 28 10 00 40 01 00 00 ff
+CHECK-NEXT: 100a: e8 19 00 00 ff
+CHECK-NEXT: 100f: e8 13 00 00 ff
+CHECK-NEXT: 1014: e8 0d 00 00 ff
+CHECK-NEXT: 1019: e8 07 00 00 ff
+CHECK-NEXT: 101e: e8 01 00 00 ff
+CHECK-NEXT: 1023: e8 fb ff ff fe
+CHECK-NEXT: 1028: e8 01 00 00 ff
+CHECK-NEXT: 102d: e8 28 00 00 ff
+CHECK-NEXT: 1032: c3
diff --git a/test/pecoff/resource.test b/test/pecoff/resource.test
new file mode 100644
index 000000000000..8cdc9a5bf83f
--- /dev/null
+++ b/test/pecoff/resource.test
@@ -0,0 +1,16 @@
+# REQUIRES: winres
+
+# RUN: yaml2obj %p/Inputs/nop.obj.yaml > %t.obj
+
+# RUN: lld -flavor link /out:%t.exe /subsystem:console /entry:start /opt:noref \
+# RUN: -- %t.obj %p/Inputs/resource.res
+
+# Check if the binary contains UTF-16LE string "Hello" copied from resource.res.
+# RUN: cat %t.exe | grep 'H.e.l.l.o'
+
+# RUN: lld -flavor link /out:%t.exe /subsystem:console /entry:start /opt:noref \
+# RUN: /manifest:embed -- %t.obj %p/Inputs/resource.res
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
+
+CHECK: ResourceTableRVA: 0x1000
+CHECK: ResourceTableSize: 0x208
diff --git a/test/pecoff/responsefile.test b/test/pecoff/responsefile.test
new file mode 100644
index 000000000000..6a5da298e730
--- /dev/null
+++ b/test/pecoff/responsefile.test
@@ -0,0 +1,7 @@
+# RUN: yaml2obj %p/Inputs/hello.obj.yaml > %t.obj
+# RUN: not lld -flavor link /verbose @%p/Inputs/responsefile.txt >& %t.log
+# RUN: FileCheck %s < %t.log
+
+CHECK: warning: ignoring unknown argument: -foo
+CHECK: warning: ignoring unknown argument: -bar\baz
+Command line: link /verbose -foo -bar\baz
diff --git a/test/pecoff/safeseh.test b/test/pecoff/safeseh.test
new file mode 100644
index 000000000000..78b1b0b53ac1
--- /dev/null
+++ b/test/pecoff/safeseh.test
@@ -0,0 +1,9 @@
+# "hello.obj" does not have the symbol "@feat.00", so it's not
+# compatible with SEH.
+
+# RUN: yaml2obj %p/Inputs/hello.obj.yaml > %t1.obj
+# RUN: not lld -flavor link /safeseh /out:%t1.exe /subsystem:console \
+# RUN: -- %t1.obj 2> %t1.err
+# RUN: FileCheck -check-prefix=INCOMPAT %s < %t1.err
+
+INCOMPAT: /SAFESEH is specified, but {{.*}} is not compatible with SEH.
diff --git a/test/pecoff/secrel.test b/test/pecoff/secrel.test
new file mode 100644
index 000000000000..05014c47af48
--- /dev/null
+++ b/test/pecoff/secrel.test
@@ -0,0 +1,16 @@
+# RUN: yaml2obj %p/Inputs/secrel1.obj.yaml > %t1.obj
+# RUN: yaml2obj %p/Inputs/secrel2.obj.yaml > %t2.obj
+# RUN: yaml2obj %p/Inputs/secrel2.obj.yaml > %t3.obj
+#
+# RUN: lld -flavor link /out:%t.exe /subsystem:console /entry:main \
+# RUN: -- %t1.obj %t2.obj %t3.obj
+# RUN: llvm-objdump -s %t.exe | FileCheck %s
+
+CHECK: Contents of section .data:
+CHECK: 1000 00000000 00000000 00000000 00000000
+CHECK: 1010 10000000 00000000 00000000 00000000
+CHECK: 1020 20000000 00000000 00000000 00000000
+CHECK: Contents of section .data2:
+CHECK: 2000 00000000 00000000 00000000 00000000
+CHECK: 2010 10000000 00000000 00000000 00000000
+CHECK: 2020 20000000 00000000 00000000 00000000
diff --git a/test/pecoff/section-attribute.test b/test/pecoff/section-attribute.test
new file mode 100644
index 000000000000..a5e71625df99
--- /dev/null
+++ b/test/pecoff/section-attribute.test
@@ -0,0 +1,45 @@
+# RUN: yaml2obj %p/Inputs/nonstandard-sections.obj.yaml > %t.obj
+# RUN: lld -flavor link /out:%t.exe /subsystem:console /force \
+# RUN: /section:.foo,d /section:.bar,rw /section:.text,rwe -- %t.obj
+# RUN: llvm-readobj -sections %t.exe | FileCheck %s
+
+CHECK: Sections [
+CHECK: Section {
+CHECK: Number: 1
+CHECK: Name: .bar (2E 62 61 72 00 00 00 00)
+CHECK: Characteristics [ (0xC0000040)
+CHECK: IMAGE_SCN_CNT_INITIALIZED_DATA (0x40)
+CHECK: IMAGE_SCN_MEM_READ (0x40000000)
+CHECK: IMAGE_SCN_MEM_WRITE (0x80000000)
+CHECK: ]
+CHECK: }
+CHECK: Section {
+CHECK: Number: 2
+CHECK: Name: .data (2E 64 61 74 61 00 00 00)
+CHECK: Characteristics [ (0xC0000040)
+CHECK: IMAGE_SCN_CNT_INITIALIZED_DATA (0x40)
+CHECK: IMAGE_SCN_MEM_READ (0x40000000)
+CHECK: IMAGE_SCN_MEM_WRITE (0x80000000)
+CHECK: ]
+CHECK: }
+CHECK: Section {
+CHECK: Number: 3
+CHECK: Name: .foo (2E 66 6F 6F 00 00 00 00)
+CHECK: Characteristics [ (0xC2000040)
+CHECK: IMAGE_SCN_CNT_INITIALIZED_DATA (0x40)
+CHECK: IMAGE_SCN_MEM_DISCARDABLE (0x2000000)
+CHECK: IMAGE_SCN_MEM_READ (0x40000000)
+CHECK: IMAGE_SCN_MEM_WRITE (0x80000000)
+CHECK: ]
+CHECK: }
+CHECK: Section {
+CHECK: Number: 4
+CHECK: Name: .text (2E 74 65 78 74 00 00 00)
+CHECK: Characteristics [ (0xE0000020)
+CHECK: IMAGE_SCN_CNT_CODE (0x20)
+CHECK: IMAGE_SCN_MEM_EXECUTE (0x20000000)
+CHECK: IMAGE_SCN_MEM_READ (0x40000000)
+CHECK: IMAGE_SCN_MEM_WRITE (0x80000000)
+CHECK: ]
+CHECK: }
+CHECK: ]
diff --git a/test/pecoff/section-renaming.test b/test/pecoff/section-renaming.test
new file mode 100644
index 000000000000..d4fc154693af
--- /dev/null
+++ b/test/pecoff/section-renaming.test
@@ -0,0 +1,61 @@
+# RUN: yaml2obj %p/Inputs/nonstandard-sections.obj.yaml > %t.obj
+# RUN: lld -flavor link /out:%t.exe /subsystem:console /force \
+# RUN: /merge:.foo=.hoge /merge:.bar=.text -- %t.obj
+# RUN: llvm-readobj -sections %t.exe | FileCheck %s
+
+CHECK: Format: COFF-i386
+CHECK-NEXT: Arch: i386
+CHECK-NEXT: AddressSize: 32bit
+CHECK-NEXT: Sections [
+CHECK-NEXT: Section {
+CHECK-NEXT: Number: 1
+CHECK-NEXT: Name: .data (2E 64 61 74 61 00 00 00)
+CHECK-NEXT: VirtualSize: 0x4
+CHECK-NEXT: VirtualAddress: 0x1000
+CHECK-NEXT: RawDataSize: 512
+CHECK-NEXT: PointerToRawData: 0x200
+CHECK-NEXT: PointerToRelocations: 0x0
+CHECK-NEXT: PointerToLineNumbers: 0x0
+CHECK-NEXT: RelocationCount: 0
+CHECK-NEXT: LineNumberCount: 0
+CHECK-NEXT: Characteristics [ (0xC0000040)
+CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA (0x40)
+CHECK-NEXT: IMAGE_SCN_MEM_READ (0x40000000)
+CHECK-NEXT: IMAGE_SCN_MEM_WRITE (0x80000000)
+CHECK-NEXT: ]
+CHECK-NEXT: }
+CHECK-NEXT: Section {
+CHECK-NEXT: Number: 2
+CHECK-NEXT: Name: .hoge (2E 68 6F 67 65 00 00 00)
+CHECK-NEXT: VirtualSize: 0x4
+CHECK-NEXT: VirtualAddress: 0x2000
+CHECK-NEXT: RawDataSize: 512
+CHECK-NEXT: PointerToRawData: 0x400
+CHECK-NEXT: PointerToRelocations: 0x0
+CHECK-NEXT: PointerToLineNumbers: 0x0
+CHECK-NEXT: RelocationCount: 0
+CHECK-NEXT: LineNumberCount: 0
+CHECK-NEXT: Characteristics [ (0xC0000040)
+CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA (0x40)
+CHECK-NEXT: IMAGE_SCN_MEM_READ (0x40000000)
+CHECK-NEXT: IMAGE_SCN_MEM_WRITE (0x80000000)
+CHECK-NEXT: ]
+CHECK-NEXT: }
+CHECK-NEXT: Section {
+CHECK-NEXT: Number: 3
+CHECK-NEXT: Name: .text (2E 74 65 78 74 00 00 00)
+CHECK-NEXT: VirtualSize: 0x8
+CHECK-NEXT: VirtualAddress: 0x3000
+CHECK-NEXT: RawDataSize: 512
+CHECK-NEXT: PointerToRawData: 0x600
+CHECK-NEXT: PointerToRelocations: 0x0
+CHECK-NEXT: PointerToLineNumbers: 0x0
+CHECK-NEXT: RelocationCount: 0
+CHECK-NEXT: LineNumberCount: 0
+CHECK-NEXT: Characteristics [ (0x60000020)
+CHECK-NEXT: IMAGE_SCN_CNT_CODE (0x20)
+CHECK-NEXT: IMAGE_SCN_MEM_EXECUTE (0x20000000)
+CHECK-NEXT: IMAGE_SCN_MEM_READ (0x40000000)
+CHECK-NEXT: ]
+CHECK-NEXT: }
+CHECK-NEXT: ]
diff --git a/test/pecoff/seh.test b/test/pecoff/seh.test
new file mode 100644
index 000000000000..c563dc3f31e0
--- /dev/null
+++ b/test/pecoff/seh.test
@@ -0,0 +1,31 @@
+# RUN: yaml2obj %p/Inputs/seh.obj.yaml > %t.obj
+#
+# RUN: lld -flavor link /out:%t.exe /subsystem:console /force /nodefaultlib \
+# RUN: -- %t.obj
+# RUN: llvm-objdump -private-headers %t.exe | FileCheck %s
+
+CHECK: Load configuration:
+CHECK: Timestamp: 0
+CHECK: Major Version: 0
+CHECK: Minor Version: 0
+CHECK: GlobalFlags Clear: 0
+CHECK: GlobalFlags Set: 0
+CHECK: Critical Section Default Timeout: 0
+CHECK: Decommit Free Block Threshold: 0
+CHECK: Decommit Total Free Threshold: 0
+CHECK: Lock Prefix Table: 0
+CHECK: Maximum Allocation Size: 0
+CHECK: Virtual Memory Threshold: 0
+CHECK: Process Affinity Mask: 0
+CHECK: Process Heap Flags: 0
+CHECK: CSD Version: 0
+CHECK: Security Cookie: 0
+CHECK: SEH Table: 4206592
+CHECK: SEH Count: 2
+CHECK: SEH Table: 0x{{[0-9a-f]+}} 0x{{[0-9a-f]+}}
+
+# RUN: lld -flavor link /out:%t.exe /subsystem:console /force /nodefaultlib \
+# RUN: /safeseh:no -- %t.obj
+# RUN: llvm-objdump -private-headers %t.exe | FileCheck -check-prefix=NOSEH %s
+
+NOSEH-NOT: SEH Table:
diff --git a/test/pecoff/seh64.test b/test/pecoff/seh64.test
new file mode 100644
index 000000000000..664ec29e5258
--- /dev/null
+++ b/test/pecoff/seh64.test
@@ -0,0 +1,57 @@
+# RUN: yaml2obj %p/Inputs/unwind.obj.yaml > %t.obj
+#
+# RUN: lld -flavor link /machine:x64 /out:%t.exe /subsystem:console /force \
+# RUN: /nodefaultlib -- %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=HEADER %s
+# RUN: llvm-objdump -unwind-info %t.exe | FileCheck -check-prefix=UNWIND %s
+
+HEADER: ExceptionTableRVA: 0x1000
+
+UNWIND: Function Table:
+UNWIND: Start Address: 0x2000
+UNWIND: End Address: 0x201b
+UNWIND: Unwind Info Address: 0x3000
+UNWIND: Version: 1
+UNWIND: Flags: 1 UNW_ExceptionHandler
+UNWIND: Size of prolog: 18
+UNWIND: Number of Codes: 8
+UNWIND: Frame register: RBX
+UNWIND: Frame offset: 0
+UNWIND: Unwind Codes:
+UNWIND: 0x12: UOP_SetFPReg
+UNWIND: 0x0f: UOP_PushNonVol RBX
+UNWIND: 0x0e: UOP_SaveXMM128 XMM8 [0x0000]
+UNWIND: 0x09: UOP_SaveNonVol RSI [0x0010]
+UNWIND: 0x04: UOP_AllocSmall 24
+UNWIND: 0x00: UOP_PushMachFrame w/o error code
+UNWIND: Function Table:
+UNWIND: Start Address: 0x2012
+UNWIND: End Address: 0x2012
+UNWIND: Unwind Info Address: 0x301c
+UNWIND: Version: 1
+UNWIND: Flags: 4 UNW_ChainInfo
+UNWIND: Size of prolog: 0
+UNWIND: Number of Codes: 0
+UNWIND: No frame pointer used
+UNWIND: Function Table:
+UNWIND: Start Address: 0x201b
+UNWIND: End Address: 0x201c
+UNWIND: Unwind Info Address: 0x302c
+UNWIND: Version: 1
+UNWIND: Flags: 0
+UNWIND: Size of prolog: 0
+UNWIND: Number of Codes: 0
+UNWIND: No frame pointer used
+UNWIND: Function Table:
+UNWIND: Start Address: 0x201c
+UNWIND: End Address: 0x2039
+UNWIND: Unwind Info Address: 0x3034
+UNWIND: Version: 1
+UNWIND: Flags: 0
+UNWIND: Size of prolog: 14
+UNWIND: Number of Codes: 6
+UNWIND: No frame pointer used
+UNWIND: Unwind Codes:
+UNWIND: 0x0e: UOP_AllocLarge 8454128
+UNWIND: 0x07: UOP_AllocLarge 8190
+UNWIND: 0x00: UOP_PushMachFrame w/o error code
diff --git a/test/pecoff/subsystem.test b/test/pecoff/subsystem.test
new file mode 100644
index 000000000000..3ed3572bf231
--- /dev/null
+++ b/test/pecoff/subsystem.test
@@ -0,0 +1,12 @@
+# RUN: yaml2obj %p/Inputs/subsystem.main.yaml > %t.main.obj
+# RUN: yaml2obj %p/Inputs/subsystem.winmain.yaml > %t.winmain.obj
+#
+# RUN: lld -flavor link /out:%t.main.exe -- %t.main.obj
+# RUN: llvm-readobj -file-headers %t.main.exe | FileCheck -check-prefix=MAIN %s
+#
+# RUN: lld -flavor link /out:%t.winmain.exe -- %t.winmain.obj
+# RUN: llvm-readobj -file-headers %t.winmain.exe | \
+# RUN: FileCheck -check-prefix=WINMAIN %s
+
+MAIN: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI
+WINMAIN: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_GUI
diff --git a/test/pecoff/tls.test b/test/pecoff/tls.test
new file mode 100644
index 000000000000..7e400ff60a0b
--- /dev/null
+++ b/test/pecoff/tls.test
@@ -0,0 +1,14 @@
+# RUN: yaml2obj %p/Inputs/hello.obj.yaml > %t1.obj
+# RUN: yaml2obj %p/Inputs/tlsused.obj.yaml > %t2.obj
+
+# RUN: lld -flavor link /out:%t1.exe /subsystem:console /force -- %t1.obj
+# RUN: llvm-readobj -file-headers %t1.exe | FileCheck -check-prefix=NOTLS %s
+
+# RUN: lld -flavor link /out:%t2.exe /subsystem:console /force -- %t1.obj %t2.obj
+# RUN: llvm-readobj -file-headers %t2.exe | FileCheck -check-prefix=TLS %s
+
+NOTLS: TLSTableRVA: 0x0
+NOTLS: TLSTableSize: 0x0
+
+TLS: TLSTableRVA: 0x1014
+TLS: TLSTableSize: 0x18
diff --git a/test/pecoff/trivial.test b/test/pecoff/trivial.test
new file mode 100644
index 000000000000..b1960f632813
--- /dev/null
+++ b/test/pecoff/trivial.test
@@ -0,0 +1,103 @@
+# Checks functionality of PECOFF writer. "nop.obj" is an object that has only
+# text section. Other data, including data sections, relocations, symbol
+# tables are not present in nop.obj.
+#
+# RUN: yaml2obj %p/Inputs/nop.obj.yaml > %t.obj
+#
+# RUN: lld -flavor link /out:%t1.exe /subsystem:console,3.11 /version:1.25 \
+# RUN: /entry:start /opt:noref -- %t.obj
+# RUN: llvm-readobj -file-headers %t1.exe | FileCheck -check-prefix=FILE %s
+#
+# RUN: lld -flavor link /out:%t2.exe /subsystem:console /entry:start \
+# RUN: /opt:noref -- %t.obj
+# RUN: llvm-readobj -sections %t2.exe | FileCheck -check-prefix=SECTIONS %s
+
+FILE: Format: COFF-i386
+FILE-NEXT: Arch: i386
+FILE-NEXT: AddressSize: 32bit
+FILE-NEXT: ImageFileHeader {
+FILE-NEXT: Machine: IMAGE_FILE_MACHINE_I386 (0x14C)
+FILE-NEXT: SectionCount: 1
+FILE-NEXT: TimeDateStamp:
+FILE-NEXT: PointerToSymbolTable: 0x0
+FILE-NEXT: SymbolCount: 0
+FILE-NEXT: OptionalHeaderSize: 224
+FILE-NEXT: Characteristics [ (0x102)
+FILE-NEXT: IMAGE_FILE_32BIT_MACHINE (0x100)
+FILE-NEXT: IMAGE_FILE_EXECUTABLE_IMAGE (0x2)
+FILE-NEXT: ]
+FILE-NEXT: }
+FILE-NEXT: ImageOptionalHeader {
+FILE-NEXT: MajorLinkerVersion: 0
+FILE-NEXT: MinorLinkerVersion: 0
+FILE-NEXT: SizeOfCode: 512
+FILE-NEXT: SizeOfInitializedData: 0
+FILE-NEXT: SizeOfUninitializedData: 0
+FILE-NEXT: AddressOfEntryPoint: 0x1000
+FILE-NEXT: BaseOfCode: 0x1000
+FILE-NEXT: BaseOfData: 0
+FILE-NEXT: ImageBase: 0x400000
+FILE-NEXT: SectionAlignment: 4096
+FILE-NEXT: FileAlignment: 512
+FILE-NEXT: MajorOperatingSystemVersion: 3
+FILE-NEXT: MinorOperatingSystemVersion: 11
+FILE-NEXT: MajorImageVersion: 1
+FILE-NEXT: MinorImageVersion: 25
+FILE-NEXT: MajorSubsystemVersion: 3
+FILE-NEXT: MinorSubsystemVersion: 11
+FILE-NEXT: SizeOfImage: 8192
+FILE-NEXT: SizeOfHeaders: 512
+FILE-NEXT: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI (0x3)
+FILE-NEXT: Characteristics [ (0x8540)
+FILE-NEXT: IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE (0x40)
+FILE-NEXT: IMAGE_DLL_CHARACTERISTICS_NO_SEH (0x400)
+FILE-NEXT: IMAGE_DLL_CHARACTERISTICS_NX_COMPAT (0x100)
+FILE-NEXT: IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE (0x8000)
+FILE-NEXT: ]
+FILE-NEXT: SizeOfStackReserve: 1048576
+FILE-NEXT: SizeOfStackCommit: 4096
+FILE-NEXT: SizeOfHeapReserve: 1048576
+FILE-NEXT: SizeOfHeapCommit: 4096
+FILE-NEXT: NumberOfRvaAndSize: 16
+FILE: DOSHeader {
+FILE-NEXT: Magic: MZ
+FILE-NEXT: UsedBytesInTheLastPage: 0
+FILE-NEXT: FileSizeInPages: 0
+FILE-NEXT: NumberOfRelocationItems: 0
+FILE-NEXT: HeaderSizeInParagraphs: 0
+FILE-NEXT: MinimumExtraParagraphs: 0
+FILE-NEXT: MaximumExtraParagraphs: 0
+FILE-NEXT: InitialRelativeSS: 0
+FILE-NEXT: InitialSP: 0
+FILE-NEXT: Checksum: 0
+FILE-NEXT: InitialIP: 0
+FILE-NEXT: InitialRelativeCS: 0
+FILE-NEXT: AddressOfRelocationTable: 64
+FILE-NEXT: OverlayNumber: 0
+FILE-NEXT: OEMid: 0
+FILE-NEXT: OEMinfo: 0
+FILE-NEXT: AddressOfNewExeHeader: 128
+FILE-NEXT: }
+
+SECTIONS: Format: COFF-i386
+SECTIONS-NEXT: Arch: i386
+SECTIONS-NEXT: AddressSize: 32bit
+SECTIONS-NEXT: Sections [
+SECTIONS-NEXT: Section {
+SECTIONS-NEXT: Number: 1
+SECTIONS-NEXT: Name: .text (2E 74 65 78 74 00 00 00)
+SECTIONS-NEXT: VirtualSize: 0x6
+SECTIONS-NEXT: VirtualAddress: 0x1000
+SECTIONS-NEXT: RawDataSize: 512
+SECTIONS-NEXT: PointerToRawData: 0x200
+SECTIONS-NEXT: PointerToRelocations: 0x0
+SECTIONS-NEXT: PointerToLineNumbers: 0x0
+SECTIONS-NEXT: RelocationCount: 0
+SECTIONS-NEXT: LineNumberCount: 0
+SECTIONS-NEXT: Characteristics [
+SECTIONS-NEXT: IMAGE_SCN_CNT_CODE
+SECTIONS-NEXT: IMAGE_SCN_MEM_EXECUTE
+SECTIONS-NEXT: IMAGE_SCN_MEM_READ
+SECTIONS-NEXT: ]
+SECTIONS-NEXT: }
+SECTIONS-NEXT: ]
diff --git a/test/pecoff/unknown-drectve.test b/test/pecoff/unknown-drectve.test
new file mode 100644
index 000000000000..2c687c5d9163
--- /dev/null
+++ b/test/pecoff/unknown-drectve.test
@@ -0,0 +1,6 @@
+# RUN: yaml2obj %p/Inputs/unknown-drectve.obj.yaml > %t.obj
+#
+# RUN: not lld -flavor link /out:%t.exe -- %t.obj >& %t.log
+# RUN: FileCheck -check-prefix=ERROR %s < %t.log
+
+ERROR: Cannot open /nosuchoption:foobar
diff --git a/test/pecoff/weak-external.test b/test/pecoff/weak-external.test
new file mode 100644
index 000000000000..ff7492dcfd5e
--- /dev/null
+++ b/test/pecoff/weak-external.test
@@ -0,0 +1,9 @@
+# RUN: yaml2obj %p/Inputs/weak-externals.obj.yaml > %t.obj
+
+# RUN: lld -flavor link /force /out:%t.exe /subsystem:console \
+# RUN: /entry:fn -- %t.obj %p/Inputs/static.lib 2> %t2.log
+# RUN: FileCheck %s < %t2.log
+
+CHECK: _no_such_symbol1
+CHECK-NOT: _no_such_symbol2
+CHECK: _no_such_symbol3
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
new file mode 100644
index 000000000000..1151404441b4
--- /dev/null
+++ b/tools/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_subdirectory(linker-script-test)
+add_subdirectory(lld)
diff --git a/tools/Makefile b/tools/Makefile
new file mode 100644
index 000000000000..93d2a58c3068
--- /dev/null
+++ b/tools/Makefile
@@ -0,0 +1,17 @@
+##===- tools/Makefile --------------------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLD_LEVEL := ..
+LEVEL := $(LLD_LEVEL)/../..
+
+include $(LLD_LEVEL)/../../Makefile.config
+
+PARALLEL_DIRS := linker-script-test lld
+
+include $(LLD_LEVEL)/Makefile
diff --git a/tools/linker-script-test/CMakeLists.txt b/tools/linker-script-test/CMakeLists.txt
new file mode 100644
index 000000000000..2492f10aa80c
--- /dev/null
+++ b/tools/linker-script-test/CMakeLists.txt
@@ -0,0 +1,8 @@
+add_llvm_executable(linker-script-test
+ linker-script-test.cpp
+ )
+
+target_link_libraries(linker-script-test
+ LLVMSupport
+ lldReaderWriter
+ )
diff --git a/tools/linker-script-test/Makefile b/tools/linker-script-test/Makefile
new file mode 100644
index 000000000000..fd1b61accc07
--- /dev/null
+++ b/tools/linker-script-test/Makefile
@@ -0,0 +1,24 @@
+##===-------------- linker-script-test/Makefile ----------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===--------------------------------------------------------------------===##
+
+LLD_LEVEL := ../..
+
+TOOLNAME = linker-script-test
+
+# No plugins, optimize startup time.
+TOOL_NO_EXPORTS = 1
+
+#include /Makefile.config
+LEVEL := $(LLD_LEVEL)/../..
+include $(LEVEL)/Makefile.config
+
+LINK_COMPONENTS := $(TARGETS_TO_BUILD)
+USEDLIBS = lldReaderWriter.a lldCore.a LLVMSupport.a
+
+include $(LLD_LEVEL)/Makefile
diff --git a/tools/linker-script-test/linker-script-test.cpp b/tools/linker-script-test/linker-script-test.cpp
new file mode 100644
index 000000000000..027ecb36c382
--- /dev/null
+++ b/tools/linker-script-test/linker-script-test.cpp
@@ -0,0 +1,57 @@
+//===- utils/linker-script-test/linker-script-test.cpp --------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Tool for testing linker script parsing.
+///
+//===----------------------------------------------------------------------===//
+
+#include "lld/ReaderWriter/LinkerScript.h"
+
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Signals.h"
+
+using namespace llvm;
+using namespace lld;
+using namespace script;
+
+int main(int argc, const char **argv) {
+ llvm::sys::PrintStackTraceOnErrorSignal();
+ llvm::PrettyStackTraceProgram X(argc, argv);
+
+ {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> mb =
+ MemoryBuffer::getFileOrSTDIN(argv[1]);
+ if (std::error_code ec = mb.getError()) {
+ llvm::errs() << ec.message() << "\n";
+ return 1;
+ }
+ Lexer l(std::move(mb.get()));
+ Token tok;
+ while (true) {
+ l.lex(tok);
+ tok.dump(llvm::outs());
+ if (tok._kind == Token::eof || tok._kind == Token::unknown)
+ break;
+ }
+ }
+ {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> mb =
+ MemoryBuffer::getFileOrSTDIN(argv[1]);
+ if (std::error_code ec = mb.getError()) {
+ llvm::errs() << ec.message() << "\n";
+ return 1;
+ }
+ Parser p(std::move(mb.get()));
+ if (!p.parse()) {
+ LinkerScript *ls = p.get();
+ ls->dump(llvm::outs());
+ }
+ }
+}
diff --git a/tools/lld/CMakeLists.txt b/tools/lld/CMakeLists.txt
new file mode 100644
index 000000000000..47f26b5300c2
--- /dev/null
+++ b/tools/lld/CMakeLists.txt
@@ -0,0 +1,25 @@
+add_llvm_executable(lld
+ lld.cpp
+ )
+
+target_link_libraries(lld
+ lldDriver
+ LLVMSupport
+ )
+
+install(TARGETS lld
+ RUNTIME DESTINATION bin)
+
+# Create the lld-link[.exe] symlink in the build directory. If symlink is not
+# supported by the operating system, create a copy instead.
+if(UNIX)
+ set(command create_symlink)
+ # Make relative symlink
+ set(src "lld${CMAKE_EXECUTABLE_SUFFIX}")
+else()
+ set(command copy)
+ set(src "${LLVM_RUNTIME_OUTPUT_INTDIR}/lld${CMAKE_EXECUTABLE_SUFFIX}")
+endif()
+set(dst "${LLVM_RUNTIME_OUTPUT_INTDIR}/lld-link${CMAKE_EXECUTABLE_SUFFIX}")
+add_custom_command(TARGET lld POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E ${command} ${src} ${dst})
diff --git a/tools/lld/Makefile b/tools/lld/Makefile
new file mode 100644
index 000000000000..77b0abbef9d0
--- /dev/null
+++ b/tools/lld/Makefile
@@ -0,0 +1,30 @@
+##===------- lld/Makefile --------------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===--------------------------------------------------------------------===##
+
+LLD_LEVEL := ../..
+
+TOOLNAME = lld
+
+# No plugins, optimize startup time.
+TOOL_NO_EXPORTS = 1
+
+#include /Makefile.config
+LEVEL := $(LLD_LEVEL)/../..
+include $(LEVEL)/Makefile.config
+
+LINK_COMPONENTS := $(TARGETS_TO_BUILD)
+USEDLIBS = lldDriver.a lldConfig.a \
+ lldELF.a lldMachO.a lldPECOFF.a lldYAML.a \
+ lldReaderWriter.a lldCore.a lldNative.a \
+ lldHexagonELFTarget.a lldMipsELFTarget.a \
+ lldX86ELFTarget.a lldExampleSubTarget.a lldX86_64ELFTarget.a \
+ lldAArch64ELFTarget.a lldARMELFTarget.a \
+ LLVMOption.a
+
+include $(LLD_LEVEL)/Makefile
diff --git a/tools/lld/TODO.txt b/tools/lld/TODO.txt
new file mode 100644
index 000000000000..20f8db0fcf10
--- /dev/null
+++ b/tools/lld/TODO.txt
@@ -0,0 +1,2 @@
+tools/lld
+~~~~~~~~~
diff --git a/tools/lld/lld.cpp b/tools/lld/lld.cpp
new file mode 100644
index 000000000000..24c3a66a3ac3
--- /dev/null
+++ b/tools/lld/lld.cpp
@@ -0,0 +1,36 @@
+//===- 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.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+///
+/// This is the entry point to the lld driver. This is a thin wrapper which
+/// dispatches to the given platform specific driver.
+///
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/LLVM.h"
+#include "lld/Driver/Driver.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Signals.h"
+
+using namespace lld;
+
+
+/// Universal linker main(). This linker eumulates the gnu, darwin, or
+/// windows linker based on the tool name or if the first argument is
+/// -flavor.
+int main(int argc, const char *argv[]) {
+ // Standard set up, so program fails gracefully.
+ llvm::sys::PrintStackTraceOnErrorSignal();
+ llvm::PrettyStackTraceProgram stackPrinter(argc, argv);
+ llvm::llvm_shutdown_obj shutdown;
+
+ return UniversalDriver::link(argc, argv) ? 0 : 1;
+}
diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt
new file mode 100644
index 000000000000..bb651b5cfe62
--- /dev/null
+++ b/unittests/CMakeLists.txt
@@ -0,0 +1,15 @@
+add_custom_target(LLDUnitTests)
+set_target_properties(LLDUnitTests PROPERTIES FOLDER "lld tests")
+
+# add_lld_unittest(test_dirname file1.cpp file2.cpp)
+#
+# Will compile the list of files together and link against lld
+# Produces a binary named 'basename(test_dirname)'.
+function(add_lld_unittest test_dirname)
+ add_unittest(LLDUnitTests ${test_dirname} ${ARGN})
+ target_link_libraries(${test_dirname} ${LLVM_COMMON_LIBS})
+endfunction()
+
+add_subdirectory(CoreTests)
+add_subdirectory(DriverTests)
+add_subdirectory(MachOTests)
diff --git a/unittests/CoreTests/CMakeLists.txt b/unittests/CoreTests/CMakeLists.txt
new file mode 100644
index 000000000000..aa85617916b4
--- /dev/null
+++ b/unittests/CoreTests/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_lld_unittest(CoreTests
+ ParallelTest.cpp
+ RangeTest.cpp
+ )
diff --git a/unittests/CoreTests/Makefile b/unittests/CoreTests/Makefile
new file mode 100644
index 000000000000..366df01a08cc
--- /dev/null
+++ b/unittests/CoreTests/Makefile
@@ -0,0 +1,14 @@
+##===- unittests/CoreTests/Makefile ----------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLD_LEVEL = ../..
+TESTNAME = CoreTest
+LLVMLIBS = gtest.a LLVMOption.a LLVMSupport.a
+
+include $(LLD_LEVEL)/unittests/Makefile
diff --git a/unittests/CoreTests/ParallelTest.cpp b/unittests/CoreTests/ParallelTest.cpp
new file mode 100644
index 000000000000..c0282437e2e1
--- /dev/null
+++ b/unittests/CoreTests/ParallelTest.cpp
@@ -0,0 +1,31 @@
+//===- lld/unittest/ParallelTest.cpp --------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Parallel.h unit tests.
+///
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+#include "lld/Core/Parallel.h"
+#include <array>
+#include <random>
+
+uint32_t array[1024 * 1024];
+
+TEST(Parallel, sort) {
+ std::mt19937 randEngine;
+ std::uniform_int_distribution<uint32_t> dist;
+
+ for (auto &i : array)
+ i = dist(randEngine);
+
+ lld::parallel_sort(std::begin(array), std::end(array));
+ ASSERT_TRUE(std::is_sorted(std::begin(array), std::end(array)));
+}
diff --git a/unittests/CoreTests/RangeTest.cpp b/unittests/CoreTests/RangeTest.cpp
new file mode 100644
index 000000000000..2b2fcd5f7875
--- /dev/null
+++ b/unittests/CoreTests/RangeTest.cpp
@@ -0,0 +1,240 @@
+//===- lld/unittest/RangeTest.cpp -----------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief range.h unit tests.
+///
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+#include "lld/Core/range.h"
+#include <array>
+#include <assert.h>
+#include <deque>
+#include <forward_list>
+#include <iterator>
+#include <list>
+#include <numeric>
+#include <sstream>
+#include <vector>
+
+template <typename T, typename U> struct AssertTypesSame;
+template <typename T> struct AssertTypesSame<T, T> {};
+#define ASSERT_TYPES_SAME(T, U) AssertTypesSame<T, U>()
+
+struct no_begin {};
+struct member_begin {
+ int *begin();
+};
+struct free_begin {};
+int *begin(free_begin);
+
+template <typename T>
+auto type_of_forward(T &&t) -> decltype(std::forward<T>(t)) {
+ return std::forward<T>(t);
+}
+
+template <typename To> To implicit_cast(To val) { return val; }
+
+void test_traits() {
+ using namespace lld::detail;
+ ASSERT_TYPES_SAME(begin_result<no_begin>::type, undefined);
+ // This causes clang to segfault.
+#if 0
+ ASSERT_TYPES_SAME(
+ begin_result<decltype(type_of_forward(member_begin()))>::type, int *);
+#endif
+ ASSERT_TYPES_SAME(begin_result<free_begin>::type, int *);
+}
+
+TEST(Range, constructors) {
+ std::vector<int> v(5);
+ std::iota(v.begin(), v.end(), 0);
+ lld::range<std::vector<int>::iterator> r = v;
+ EXPECT_EQ(v.begin(), r.begin());
+ EXPECT_EQ(v.end(), r.end());
+
+ int arr[] = { 1, 2, 3, 4, 5 };
+ std::begin(arr);
+ lld::range<int *> r2 = arr;
+ EXPECT_EQ(5, r2.back());
+}
+
+TEST(Range, conversion_to_pointer_range) {
+ std::vector<int> v(5);
+ std::iota(v.begin(), v.end(), 0);
+ lld::range<int *> r = v;
+ EXPECT_EQ(&*v.begin(), r.begin());
+ EXPECT_EQ(2, r[2]);
+}
+
+template <typename Iter> void takes_range(lld::range<Iter> r) {
+ int expected = 0;
+ for (int val : r) {
+ EXPECT_EQ(expected++, val);
+ }
+}
+
+void takes_ptr_range(lld::range<const int *> r) {
+ int expected = 0;
+ for (int val : r) {
+ EXPECT_EQ(expected++, val);
+ }
+}
+
+TEST(Range, passing) {
+ using lld::make_range;
+ using lld::make_ptr_range;
+ std::list<int> l(5);
+ std::iota(l.begin(), l.end(), 0);
+ takes_range(make_range(l));
+ takes_range(make_range(implicit_cast<const std::list<int> &>(l)));
+ std::deque<int> d(5);
+ std::iota(d.begin(), d.end(), 0);
+ takes_range(make_range(d));
+ takes_range(make_range(implicit_cast<const std::deque<int> &>(d)));
+ std::vector<int> v(5);
+ std::iota(v.begin(), v.end(), 0);
+ takes_range(make_range(v));
+ takes_range(make_range(implicit_cast<const std::vector<int> &>(v)));
+ static_assert(
+ std::is_same<decltype(make_ptr_range(v)), lld::range<int *>>::value,
+ "make_ptr_range should return a range of pointers");
+ takes_range(make_ptr_range(v));
+ takes_range(make_ptr_range(implicit_cast<const std::vector<int> &>(v)));
+ int arr[] = { 0, 1, 2, 3, 4 };
+ takes_range(make_range(arr));
+ const int carr[] = { 0, 1, 2, 3, 4 };
+ takes_range(make_range(carr));
+
+ takes_ptr_range(v);
+ takes_ptr_range(implicit_cast<const std::vector<int> &>(v));
+ takes_ptr_range(arr);
+ takes_ptr_range(carr);
+}
+
+TEST(Range, access) {
+ std::array<int, 5> a = { { 1, 2, 3, 4, 5 } };
+ lld::range<decltype(a.begin())> r = a;
+ EXPECT_EQ(4, r[3]);
+ EXPECT_EQ(4, r[-2]);
+}
+
+template <bool b> struct CompileAssert;
+template <> struct CompileAssert<true> {};
+
+#if __has_feature(cxx_constexpr)
+constexpr int arr[] = { 1, 2, 3, 4, 5 };
+TEST(Range, constexpr) {
+ constexpr lld::range<const int *> r(arr, arr + 5);
+ CompileAssert<r.front() == 1>();
+ CompileAssert<r.size() == 5>();
+ CompileAssert<r[4] == 5>();
+}
+#endif
+
+template <typename Container> void test_slice() {
+ Container cont(10);
+ std::iota(cont.begin(), cont.end(), 0);
+ lld::range<decltype(cont.begin())> r = cont;
+
+ // One argument.
+ EXPECT_EQ(10, r.slice(0).size());
+ EXPECT_EQ(8, r.slice(2).size());
+ EXPECT_EQ(2, r.slice(2).front());
+ EXPECT_EQ(1, r.slice(-1).size());
+ EXPECT_EQ(9, r.slice(-1).front());
+
+ // Two positive arguments.
+ EXPECT_TRUE(r.slice(5, 2).empty());
+ EXPECT_EQ(next(cont.begin(), 5), r.slice(5, 2).begin());
+ EXPECT_EQ(1, r.slice(1, 2).size());
+ EXPECT_EQ(1, r.slice(1, 2).front());
+
+ // Two negative arguments.
+ EXPECT_TRUE(r.slice(-2, -5).empty());
+ EXPECT_EQ(next(cont.begin(), 8), r.slice(-2, -5).begin());
+ EXPECT_EQ(1, r.slice(-2, -1).size());
+ EXPECT_EQ(8, r.slice(-2, -1).front());
+
+ // Positive start, negative stop.
+ EXPECT_EQ(1, r.slice(6, -3).size());
+ EXPECT_EQ(6, r.slice(6, -3).front());
+ EXPECT_TRUE(r.slice(6, -5).empty());
+ EXPECT_EQ(next(cont.begin(), 6), r.slice(6, -5).begin());
+
+ // Negative start, positive stop.
+ EXPECT_TRUE(r.slice(-3, 6).empty());
+ EXPECT_EQ(next(cont.begin(), 7), r.slice(-3, 6).begin());
+ EXPECT_EQ(1, r.slice(-5, 6).size());
+ EXPECT_EQ(5, r.slice(-5, 6).front());
+}
+
+TEST(Range, slice) {
+ // -fsanitize=undefined complains about this, but only if optimizations are
+ // enabled.
+#if 0
+ test_slice<std::forward_list<int>>();
+#endif
+ test_slice<std::list<int>>();
+// This doesn't build with libstdc++ 4.7
+#if 0
+ test_slice<std::deque<int>>();
+#endif
+}
+
+// This test is flaky and I've yet to pin down why. Changing between
+// EXPECT_EQ(1, input.front()) and EXPECT_TRUE(input.front() == 1) makes it work
+// with VS 2012 in Debug mode. Clang on Linux seems to fail with -03 and -02 -g
+// -fsanitize=undefined.
+#if 0
+TEST(Range, istream_range) {
+ std::istringstream stream("1 2 3 4 5");
+ // MSVC interprets input as a function declaration if you don't declare start
+ // and instead directly pass std::istream_iterator<int>(stream).
+ auto start = std::istream_iterator<int>(stream);
+ lld::range<std::istream_iterator<int>> input(
+ start, std::istream_iterator<int>());
+ EXPECT_TRUE(input.front() == 1);
+ input.pop_front();
+ EXPECT_TRUE(input.front() == 2);
+ input.pop_front(2);
+ EXPECT_TRUE(input.front() == 4);
+ input.pop_front_upto(7);
+ EXPECT_TRUE(input.empty());
+}
+#endif
+
+//! [algorithm using range]
+template <typename T> void partial_sum(T &container) {
+ using lld::make_range;
+ auto range = make_range(container);
+ typename T::value_type sum = 0;
+ // One would actually use a range-based for loop
+ // in this case, but you get the idea:
+ for (; !range.empty(); range.pop_front()) {
+ sum += range.front();
+ range.front() = sum;
+ }
+}
+
+TEST(Range, user1) {
+ std::vector<int> v(5, 2);
+ partial_sum(v);
+ EXPECT_EQ(8, v[3]);
+}
+//! [algorithm using range]
+
+//! [algorithm using ptr_range]
+void my_write(int fd, lld::range<const char *> buffer) {}
+
+TEST(Range, user2) {
+ std::string s("Hello world");
+ my_write(1, s);
+}
diff --git a/unittests/DriverTests/CMakeLists.txt b/unittests/DriverTests/CMakeLists.txt
new file mode 100644
index 000000000000..59d56d459582
--- /dev/null
+++ b/unittests/DriverTests/CMakeLists.txt
@@ -0,0 +1,14 @@
+add_lld_unittest(DriverTests
+ UniversalDriverTest.cpp
+ GnuLdDriverTest.cpp
+ DarwinLdDriverTest.cpp
+ WinLinkDriverTest.cpp
+ WinLinkModuleDefTest.cpp
+ )
+
+target_link_libraries(DriverTests
+ lldDriver
+ lldCore
+ lldPECOFF
+ lldMachO
+ )
diff --git a/unittests/DriverTests/DarwinLdDriverTest.cpp b/unittests/DriverTests/DarwinLdDriverTest.cpp
new file mode 100644
index 000000000000..1c77a05f5856
--- /dev/null
+++ b/unittests/DriverTests/DarwinLdDriverTest.cpp
@@ -0,0 +1,240 @@
+//===- lld/unittest/DarwinLdDriverTest.cpp --------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Darwin's ld driver tests.
+///
+//===----------------------------------------------------------------------===//
+
+#include "DriverTest.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/Support/MachO.h"
+
+using namespace llvm;
+using namespace lld;
+
+namespace {
+class DarwinLdParserTest
+ : public ParserTest<DarwinLdDriver, MachOLinkingContext> {
+protected:
+ const LinkingContext *linkingContext() override { return &_ctx; }
+};
+}
+
+TEST_F(DarwinLdParserTest, Basic) {
+ EXPECT_TRUE(parse("ld", "foo.o", "bar.o", "-arch", "i386", nullptr));
+ EXPECT_FALSE(_ctx.allowRemainingUndefines());
+ EXPECT_FALSE(_ctx.deadStrip());
+ EXPECT_EQ(2, inputFileCount());
+ EXPECT_EQ("foo.o", inputFile(0));
+ EXPECT_EQ("bar.o", inputFile(1));
+}
+
+TEST_F(DarwinLdParserTest, Output) {
+ EXPECT_TRUE(parse("ld", "-o", "my.out", "foo.o", "-arch", "i386", nullptr));
+ EXPECT_EQ("my.out", _ctx.outputPath());
+}
+
+TEST_F(DarwinLdParserTest, Dylib) {
+ EXPECT_TRUE(parse("ld", "-dylib", "foo.o", "-arch", "i386", nullptr));
+ EXPECT_EQ(llvm::MachO::MH_DYLIB, _ctx.outputMachOType());
+}
+
+TEST_F(DarwinLdParserTest, Relocatable) {
+ EXPECT_TRUE(parse("ld", "-r", "foo.o", "-arch", "i386", nullptr));
+ EXPECT_EQ(llvm::MachO::MH_OBJECT, _ctx.outputMachOType());
+}
+
+TEST_F(DarwinLdParserTest, Bundle) {
+ EXPECT_TRUE(parse("ld", "-bundle", "foo.o", "-arch", "i386", nullptr));
+ EXPECT_EQ(llvm::MachO::MH_BUNDLE, _ctx.outputMachOType());
+}
+
+TEST_F(DarwinLdParserTest, Preload) {
+ EXPECT_TRUE(parse("ld", "-preload", "foo.o", "-arch", "i386", nullptr));
+ EXPECT_EQ(llvm::MachO::MH_PRELOAD, _ctx.outputMachOType());
+}
+
+TEST_F(DarwinLdParserTest, Static) {
+ EXPECT_TRUE(parse("ld", "-static", "foo.o", "-arch", "i386", nullptr));
+ EXPECT_EQ(llvm::MachO::MH_EXECUTE, _ctx.outputMachOType());
+}
+
+TEST_F(DarwinLdParserTest, Entry) {
+ EXPECT_TRUE(parse("ld", "-e", "entryFunc", "foo.o", "-arch", "i386",nullptr));
+ EXPECT_EQ("entryFunc", _ctx.entrySymbolName());
+}
+
+TEST_F(DarwinLdParserTest, DeadStrip) {
+ EXPECT_TRUE(parse("ld", "-arch", "x86_64", "-dead_strip", "foo.o", nullptr));
+ EXPECT_TRUE(_ctx.deadStrip());
+}
+
+TEST_F(DarwinLdParserTest, DeadStripRootsExe) {
+ EXPECT_TRUE(parse("ld", "-arch", "x86_64", "-dead_strip", "foo.o", nullptr));
+ EXPECT_FALSE(_ctx.globalsAreDeadStripRoots());
+}
+
+TEST_F(DarwinLdParserTest, DeadStripRootsDylib) {
+ EXPECT_TRUE(parse("ld", "-arch", "x86_64", "-dylib", "-dead_strip", "foo.o",
+ nullptr));
+ EXPECT_TRUE(_ctx.globalsAreDeadStripRoots());
+}
+
+TEST_F(DarwinLdParserTest, Arch) {
+ EXPECT_TRUE(parse("ld", "-arch", "x86_64", "foo.o", nullptr));
+ EXPECT_EQ(MachOLinkingContext::arch_x86_64, _ctx.arch());
+ EXPECT_EQ((uint32_t)llvm::MachO::CPU_TYPE_X86_64, _ctx.getCPUType());
+ EXPECT_EQ(llvm::MachO::CPU_SUBTYPE_X86_64_ALL, _ctx.getCPUSubType());
+}
+
+TEST_F(DarwinLdParserTest, Arch_x86) {
+ EXPECT_TRUE(parse("ld", "-arch", "i386", "foo.o", nullptr));
+ EXPECT_EQ(MachOLinkingContext::arch_x86, _ctx.arch());
+ EXPECT_EQ((uint32_t)llvm::MachO::CPU_TYPE_I386, _ctx.getCPUType());
+ EXPECT_EQ(llvm::MachO::CPU_SUBTYPE_X86_ALL, _ctx.getCPUSubType());
+}
+
+TEST_F(DarwinLdParserTest, Arch_armv6) {
+ EXPECT_TRUE(parse("ld", "-arch", "armv6", "foo.o", nullptr));
+ EXPECT_EQ(MachOLinkingContext::arch_armv6, _ctx.arch());
+ EXPECT_EQ((uint32_t)llvm::MachO::CPU_TYPE_ARM, _ctx.getCPUType());
+ EXPECT_EQ(llvm::MachO::CPU_SUBTYPE_ARM_V6, _ctx.getCPUSubType());
+}
+
+TEST_F(DarwinLdParserTest, Arch_armv7) {
+ EXPECT_TRUE(parse("ld", "-arch", "armv7", "foo.o", nullptr));
+ EXPECT_EQ(MachOLinkingContext::arch_armv7, _ctx.arch());
+ EXPECT_EQ((uint32_t)llvm::MachO::CPU_TYPE_ARM, _ctx.getCPUType());
+ EXPECT_EQ(llvm::MachO::CPU_SUBTYPE_ARM_V7, _ctx.getCPUSubType());
+}
+
+TEST_F(DarwinLdParserTest, Arch_armv7s) {
+ EXPECT_TRUE(parse("ld", "-arch", "armv7s", "foo.o", nullptr));
+ EXPECT_EQ(MachOLinkingContext::arch_armv7s, _ctx.arch());
+ EXPECT_EQ((uint32_t)llvm::MachO::CPU_TYPE_ARM, _ctx.getCPUType());
+ EXPECT_EQ(llvm::MachO::CPU_SUBTYPE_ARM_V7S, _ctx.getCPUSubType());
+}
+
+TEST_F(DarwinLdParserTest, MinMacOSX10_7) {
+ EXPECT_TRUE(parse("ld", "-macosx_version_min", "10.7", "foo.o",
+ "-arch", "x86_64", nullptr));
+ EXPECT_EQ(MachOLinkingContext::OS::macOSX, _ctx.os());
+ EXPECT_TRUE(_ctx.minOS("10.7", ""));
+ EXPECT_FALSE(_ctx.minOS("10.8", ""));
+}
+
+TEST_F(DarwinLdParserTest, MinMacOSX10_8) {
+ EXPECT_TRUE(parse("ld", "-macosx_version_min", "10.8.3", "foo.o",
+ "-arch", "x86_64", nullptr));
+ EXPECT_EQ(MachOLinkingContext::OS::macOSX, _ctx.os());
+ EXPECT_TRUE(_ctx.minOS("10.7", ""));
+ EXPECT_TRUE(_ctx.minOS("10.8", ""));
+}
+
+TEST_F(DarwinLdParserTest, iOS5) {
+ EXPECT_TRUE(parse("ld", "-ios_version_min", "5.0", "foo.o",
+ "-arch", "armv7", nullptr));
+ EXPECT_EQ(MachOLinkingContext::OS::iOS, _ctx.os());
+ EXPECT_TRUE(_ctx.minOS("", "5.0"));
+ EXPECT_FALSE(_ctx.minOS("", "6.0"));
+}
+
+TEST_F(DarwinLdParserTest, iOS6) {
+ EXPECT_TRUE(parse("ld", "-ios_version_min", "6.0", "foo.o", "-arch", "armv7",
+ nullptr));
+ EXPECT_EQ(MachOLinkingContext::OS::iOS, _ctx.os());
+ EXPECT_TRUE(_ctx.minOS("", "5.0"));
+ EXPECT_TRUE(_ctx.minOS("", "6.0"));
+}
+
+TEST_F(DarwinLdParserTest, iOS_Simulator5) {
+ EXPECT_TRUE(parse("ld", "-ios_simulator_version_min", "5.0", "a.o",
+ "-arch", "i386", nullptr));
+ EXPECT_EQ(MachOLinkingContext::OS::iOS_simulator, _ctx.os());
+ EXPECT_TRUE(_ctx.minOS("", "5.0"));
+ EXPECT_FALSE(_ctx.minOS("", "6.0"));
+}
+
+TEST_F(DarwinLdParserTest, iOS_Simulator6) {
+ EXPECT_TRUE(parse("ld", "-ios_simulator_version_min", "6.0", "a.o",
+ "-arch", "i386", nullptr));
+ EXPECT_EQ(MachOLinkingContext::OS::iOS_simulator, _ctx.os());
+ EXPECT_TRUE(_ctx.minOS("", "5.0"));
+ EXPECT_TRUE(_ctx.minOS("", "6.0"));
+}
+
+TEST_F(DarwinLdParserTest, compatibilityVersion) {
+ EXPECT_TRUE(
+ parse("ld", "-dylib", "-compatibility_version", "1.2.3", "a.o",
+ "-arch", "i386",nullptr));
+ EXPECT_EQ(_ctx.compatibilityVersion(), 0x10203U);
+}
+
+TEST_F(DarwinLdParserTest, compatibilityVersionInvalidType) {
+ EXPECT_FALSE(parse("ld", "-bundle", "-compatibility_version", "1.2.3", "a.o",
+ "-arch", "i386",nullptr));
+}
+
+TEST_F(DarwinLdParserTest, compatibilityVersionInvalidValue) {
+ EXPECT_FALSE(parse("ld", "-bundle", "-compatibility_version", "1,2,3", "a.o",
+ "-arch", "i386", nullptr));
+}
+
+TEST_F(DarwinLdParserTest, currentVersion) {
+ EXPECT_TRUE(
+ parse("ld", "-dylib", "-current_version", "1.2.3", "a.o", "-arch", "i386",
+ nullptr));
+ EXPECT_EQ(_ctx.currentVersion(), 0x10203U);
+}
+
+TEST_F(DarwinLdParserTest, currentVersionInvalidType) {
+ EXPECT_FALSE(
+ parse("ld", "-bundle", "-current_version", "1.2.3", "a.o",
+ "-arch", "i386", nullptr));
+}
+
+TEST_F(DarwinLdParserTest, currentVersionInvalidValue) {
+ EXPECT_FALSE(
+ parse("ld", "-bundle", "-current_version", "1,2,3", "a.o",
+ "-arch", "i386", nullptr));
+}
+
+TEST_F(DarwinLdParserTest, bundleLoader) {
+ EXPECT_TRUE(
+ parse("ld", "-bundle", "-bundle_loader", "/bin/ls", "a.o",
+ "-arch", "i386", nullptr));
+ EXPECT_EQ(_ctx.bundleLoader(), "/bin/ls");
+}
+
+TEST_F(DarwinLdParserTest, bundleLoaderInvalidType) {
+ EXPECT_FALSE(parse("ld", "-bundle_loader", "/bin/ls", "a.o", "-arch", "i386",
+ nullptr));
+}
+
+TEST_F(DarwinLdParserTest, deadStrippableDylib) {
+ EXPECT_TRUE(
+ parse("ld", "-dylib", "-mark_dead_strippable_dylib", "a.o",
+ "-arch", "i386", nullptr));
+ EXPECT_EQ(true, _ctx.deadStrippableDylib());
+}
+
+TEST_F(DarwinLdParserTest, deadStrippableDylibInvalidType) {
+ EXPECT_FALSE(parse("ld", "-mark_dead_strippable_dylib", "a.o",
+ "-arch", "i386", nullptr));
+}
+
+TEST_F(DarwinLdParserTest, llvmOptions) {
+ EXPECT_TRUE(parse("ld", "-mllvm", "-debug-only", "-mllvm", "foo", "a.o",
+ "-arch", "i386", nullptr));
+ const std::vector<const char *> &options = _ctx.llvmOptions();
+ EXPECT_EQ(options.size(), 2UL);
+ EXPECT_EQ(strcmp(options[0],"-debug-only"), 0);
+ EXPECT_EQ(strcmp(options[1],"foo"), 0);
+}
diff --git a/unittests/DriverTests/DriverTest.h b/unittests/DriverTests/DriverTest.h
new file mode 100644
index 000000000000..2349132ee2ce
--- /dev/null
+++ b/unittests/DriverTests/DriverTest.h
@@ -0,0 +1,61 @@
+//===- lld/unittest/DriverTest.h ------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Driver/Driver.h"
+#include "llvm/Support/raw_ostream.h"
+#include "gtest/gtest.h"
+#include <stdarg.h>
+
+namespace {
+
+using namespace llvm;
+using namespace lld;
+
+template<typename D, typename T>
+class ParserTest : public testing::Test {
+protected:
+
+ virtual const LinkingContext *linkingContext() = 0;
+
+ std::string &errorMessage() { return _errorMessage; }
+
+ // Convenience method for getting number of input files.
+ int inputFileCount() {
+ return linkingContext()->getNodes().size();
+ }
+
+ // Convenience method for getting i'th input files name.
+ std::string inputFile(int index) {
+ Node &node = *linkingContext()->getNodes()[index];
+ if (node.kind() == Node::Kind::File)
+ return cast<FileNode>(&node)->getFile()->path();
+ llvm_unreachable("not handling other types of input files");
+ }
+
+ // For unit tests to call driver with various command lines.
+ bool parse(const char *args, ...) {
+ // Construct command line options from varargs.
+ std::vector<const char *> vec;
+ vec.push_back(args);
+ va_list ap;
+ va_start(ap, args);
+ while (const char *arg = va_arg(ap, const char *))
+ vec.push_back(arg);
+ va_end(ap);
+
+ // Call the parser.
+ raw_string_ostream os(_errorMessage);
+ return D::parse(vec.size(), &vec[0], _ctx, os);
+ }
+
+ T _ctx;
+ std::string _errorMessage;
+};
+
+}
diff --git a/unittests/DriverTests/GnuLdDriverTest.cpp b/unittests/DriverTests/GnuLdDriverTest.cpp
new file mode 100644
index 000000000000..92eb920f0180
--- /dev/null
+++ b/unittests/DriverTests/GnuLdDriverTest.cpp
@@ -0,0 +1,284 @@
+//===- lld/unittest/GnuLdDriverTest.cpp -----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief GNU ld driver tests.
+///
+//===----------------------------------------------------------------------===//
+
+#include "DriverTest.h"
+#include "lld/ReaderWriter/ELFLinkingContext.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+using namespace llvm;
+using namespace lld;
+
+namespace {
+
+class GnuLdParserTest
+ : public ParserTest<GnuLdDriver, std::unique_ptr<ELFLinkingContext>> {
+protected:
+ const LinkingContext *linkingContext() override { return _ctx.get(); }
+};
+
+class LinkerScriptTest : public testing::Test {
+protected:
+ void SetUp() override {
+ llvm::Triple triple(llvm::sys::getDefaultTargetTriple());
+ _ctx = std::move(GnuLdDriver::createELFLinkingContext(triple));
+ }
+
+ void parse(StringRef script, bool nostdlib = false) {
+ std::unique_ptr<MemoryBuffer> mb = MemoryBuffer::getMemBuffer(
+ script, "foo.so");
+ std::string s;
+ raw_string_ostream out(s);
+ std::error_code ec =
+ GnuLdDriver::evalLinkerScript(*_ctx, std::move(mb), out, nostdlib);
+ EXPECT_FALSE(ec);
+ };
+
+ std::unique_ptr<ELFLinkingContext> _ctx;
+};
+
+} // anonymous namespace
+
+TEST_F(GnuLdParserTest, Empty) {
+ EXPECT_FALSE(parse("ld", nullptr));
+ EXPECT_EQ(linkingContext(), nullptr);
+ EXPECT_EQ("No input files\n", errorMessage());
+}
+
+// -o
+
+TEST_F(GnuLdParserTest, Output) {
+ EXPECT_TRUE(parse("ld", "a.o", "-o", "foo", nullptr));
+ EXPECT_EQ("foo", _ctx->outputPath());
+}
+
+TEST_F(GnuLdParserTest, OutputDefault) {
+ EXPECT_TRUE(parse("ld", "abc.o", nullptr));
+ EXPECT_EQ("a.out", _ctx->outputPath());
+}
+
+// --noinhibit-exec
+
+TEST_F(GnuLdParserTest, NoinhibitExec) {
+ EXPECT_TRUE(parse("ld", "a.o", "--noinhibit-exec", nullptr));
+ EXPECT_TRUE(_ctx->allowRemainingUndefines());
+}
+
+// --entry
+
+TEST_F(GnuLdParserTest, Entry) {
+ EXPECT_TRUE(parse("ld", "a.o", "--entry", "foo", nullptr));
+ EXPECT_EQ("foo", _ctx->entrySymbolName());
+}
+
+TEST_F(GnuLdParserTest, EntryShort) {
+ EXPECT_TRUE(parse("ld", "a.o", "-e", "foo", nullptr));
+ EXPECT_EQ("foo", _ctx->entrySymbolName());
+}
+
+TEST_F(GnuLdParserTest, EntryJoined) {
+ EXPECT_TRUE(parse("ld", "a.o", "--entry=foo", nullptr));
+ EXPECT_EQ("foo", _ctx->entrySymbolName());
+}
+
+// --export-dynamic
+
+TEST_F(GnuLdParserTest, ExportDynamic) {
+ EXPECT_TRUE(parse("ld", "a.o", "--export-dynamic", nullptr));
+ EXPECT_TRUE(_ctx->shouldExportDynamic());
+}
+
+TEST_F(GnuLdParserTest, NoExportDynamic) {
+ EXPECT_TRUE(parse("ld", "a.o", "--no-export-dynamic", nullptr));
+ EXPECT_FALSE(_ctx->shouldExportDynamic());
+}
+
+// --init
+
+TEST_F(GnuLdParserTest, Init) {
+ EXPECT_TRUE(parse("ld", "a.o", "-init", "foo", "-init", "bar", nullptr));
+ EXPECT_EQ("bar", _ctx->initFunction());
+}
+
+TEST_F(GnuLdParserTest, InitJoined) {
+ EXPECT_TRUE(parse("ld", "a.o", "-init=foo", nullptr));
+ EXPECT_EQ("foo", _ctx->initFunction());
+}
+
+// --soname
+
+TEST_F(GnuLdParserTest, SOName) {
+ EXPECT_TRUE(parse("ld", "a.o", "--soname=foo", nullptr));
+ EXPECT_EQ("foo", _ctx->sharedObjectName());
+}
+
+TEST_F(GnuLdParserTest, SONameSingleDash) {
+ EXPECT_TRUE(parse("ld", "a.o", "-soname=foo", nullptr));
+ EXPECT_EQ("foo", _ctx->sharedObjectName());
+}
+
+TEST_F(GnuLdParserTest, SONameH) {
+ EXPECT_TRUE(parse("ld", "a.o", "-h", "foo", nullptr));
+ EXPECT_EQ("foo", _ctx->sharedObjectName());
+}
+
+// -rpath
+
+TEST_F(GnuLdParserTest, Rpath) {
+ EXPECT_TRUE(parse("ld", "a.o", "-rpath", "foo:bar", nullptr));
+ EXPECT_EQ(2, _ctx->getRpathList().size());
+ EXPECT_EQ("foo", _ctx->getRpathList()[0]);
+ EXPECT_EQ("bar", _ctx->getRpathList()[1]);
+}
+
+TEST_F(GnuLdParserTest, RpathEq) {
+ EXPECT_TRUE(parse("ld", "a.o", "-rpath=foo", nullptr));
+ EXPECT_EQ(1, _ctx->getRpathList().size());
+ EXPECT_EQ("foo", _ctx->getRpathList()[0]);
+}
+
+// --defsym
+
+TEST_F(GnuLdParserTest, DefsymDecimal) {
+ EXPECT_TRUE(parse("ld", "a.o", "--defsym=sym=1000", nullptr));
+ assert(_ctx.get());
+ auto map = _ctx->getAbsoluteSymbols();
+ EXPECT_EQ((size_t)1, map.size());
+ EXPECT_EQ((uint64_t)1000, map["sym"]);
+}
+
+TEST_F(GnuLdParserTest, DefsymHexadecimal) {
+ EXPECT_TRUE(parse("ld", "a.o", "--defsym=sym=0x1000", nullptr));
+ auto map = _ctx->getAbsoluteSymbols();
+ EXPECT_EQ((size_t)1, map.size());
+ EXPECT_EQ((uint64_t)0x1000, map["sym"]);
+}
+
+TEST_F(GnuLdParserTest, DefsymAlias) {
+ EXPECT_TRUE(parse("ld", "a.o", "--defsym=sym=abc", nullptr));
+ auto map = _ctx->getAliases();
+ EXPECT_EQ((size_t)1, map.size());
+ EXPECT_EQ("abc", map["sym"]);
+}
+
+TEST_F(GnuLdParserTest, DefsymOctal) {
+ EXPECT_TRUE(parse("ld", "a.o", "--defsym=sym=0777", nullptr));
+ auto map = _ctx->getAbsoluteSymbols();
+ EXPECT_EQ((size_t)1, map.size());
+ EXPECT_EQ((uint64_t)0777, map["sym"]);
+}
+
+TEST_F(GnuLdParserTest, DefsymMisssingSymbol) {
+ EXPECT_FALSE(parse("ld", "a.o", "--defsym==0", nullptr));
+}
+
+TEST_F(GnuLdParserTest, DefsymMisssingValue) {
+ EXPECT_FALSE(parse("ld", "a.o", "--defsym=sym=", nullptr));
+}
+
+// --as-needed
+
+TEST_F(GnuLdParserTest, AsNeeded) {
+ EXPECT_TRUE(parse("ld", "a.o", "--as-needed", "b.o", "c.o",
+ "--no-as-needed", "d.o", nullptr));
+ std::vector<std::unique_ptr<Node>> &nodes = _ctx->getNodes();
+ EXPECT_EQ((size_t)4, nodes.size());
+ EXPECT_FALSE(cast<FileNode>(nodes[0].get())->asNeeded());
+ EXPECT_TRUE(cast<FileNode>(nodes[1].get())->asNeeded());
+ EXPECT_TRUE(cast<FileNode>(nodes[2].get())->asNeeded());
+ EXPECT_FALSE(cast<FileNode>(nodes[3].get())->asNeeded());
+}
+
+// Linker script
+
+TEST_F(LinkerScriptTest, Input) {
+ parse("INPUT(/x /y)");
+ std::vector<std::unique_ptr<Node>> &nodes = _ctx->getNodes();
+ EXPECT_EQ((size_t)2, nodes.size());
+ EXPECT_EQ("/x", cast<FileNode>(nodes[0].get())->getFile()->path());
+ EXPECT_EQ("/y", cast<FileNode>(nodes[1].get())->getFile()->path());
+}
+
+TEST_F(LinkerScriptTest, Group) {
+ parse("GROUP(/x /y)");
+ std::vector<std::unique_ptr<Node>> &nodes = _ctx->getNodes();
+ EXPECT_EQ((size_t)3, nodes.size());
+ EXPECT_EQ("/x", cast<FileNode>(nodes[0].get())->getFile()->path());
+ EXPECT_EQ("/y", cast<FileNode>(nodes[1].get())->getFile()->path());
+ EXPECT_EQ(2, cast<GroupEnd>(nodes[2].get())->getSize());
+}
+
+TEST_F(LinkerScriptTest, SearchDir) {
+ parse("SEARCH_DIR(\"/foo/bar\")");
+ std::vector<StringRef> paths = _ctx->getSearchPaths();
+ EXPECT_EQ((size_t)1, paths.size());
+ EXPECT_EQ("/foo/bar", paths[0]);
+}
+
+TEST_F(LinkerScriptTest, Entry) {
+ parse("ENTRY(blah)");
+ EXPECT_EQ("blah", _ctx->entrySymbolName());
+}
+
+TEST_F(LinkerScriptTest, Output) {
+ parse("OUTPUT(\"/path/to/output\")");
+ EXPECT_EQ("/path/to/output", _ctx->outputPath());
+}
+
+// Test that search paths are ignored when nostdlib is set.
+TEST_F(LinkerScriptTest, IgnoreSearchDirNoStdLib) {
+ parse("SEARCH_DIR(\"/foo/bar\")", true /*nostdlib*/);
+ std::vector<StringRef> paths = _ctx->getSearchPaths();
+ EXPECT_EQ((size_t)0, paths.size());
+}
+
+TEST_F(LinkerScriptTest, ExprEval) {
+ parse("SECTIONS { symbol = 0x4000 + 0x40; \n"
+ ". = (symbol >= 0x4040)? (0x5001 * 2 & 0xFFF0) << 1 : 0}");
+
+ EXPECT_EQ((size_t)1, _ctx->linkerScriptSema().getLinkerScripts().size());
+
+ script::LinkerScript *ls =
+ _ctx->linkerScriptSema().getLinkerScripts()[0]->get();
+ EXPECT_EQ((size_t)1, ls->_commands.size());
+
+ auto *secs = dyn_cast<const script::Sections>(*ls->_commands.begin());
+ EXPECT_TRUE(secs != nullptr);
+ EXPECT_EQ(2, secs->end() - secs->begin());
+
+ auto command = secs->begin();
+ auto *sa1 = dyn_cast<const script::SymbolAssignment>(*command);
+ EXPECT_TRUE(sa1 != nullptr);
+ EXPECT_EQ(script::SymbolAssignment::Simple, sa1->assignmentKind());
+ EXPECT_EQ(script::SymbolAssignment::Default, sa1->assignmentVisibility());
+
+ ++command;
+ auto *sa2 = dyn_cast<const script::SymbolAssignment>(*command);
+ EXPECT_TRUE(sa2 != nullptr);
+ EXPECT_EQ(script::SymbolAssignment::Simple, sa2->assignmentKind());
+ EXPECT_EQ(script::SymbolAssignment::Default, sa2->assignmentVisibility());
+
+ script::Expression::SymbolTableTy mySymbolTable;
+ auto ans = sa1->expr()->evalExpr(mySymbolTable);
+ EXPECT_FALSE(ans.getError());
+ int64_t result = *ans;
+ EXPECT_EQ(0x4040, result);
+ mySymbolTable[sa1->symbol()] = result;
+
+ auto ans2 = sa2->expr()->evalExpr(mySymbolTable);
+ EXPECT_FALSE(ans2.getError());
+ result = *ans2;
+ EXPECT_EQ(0x14000, result);
+ EXPECT_EQ(0, sa2->symbol().compare(StringRef(".")));
+}
+
diff --git a/unittests/DriverTests/Makefile b/unittests/DriverTests/Makefile
new file mode 100644
index 000000000000..ae97fb01adbf
--- /dev/null
+++ b/unittests/DriverTests/Makefile
@@ -0,0 +1,20 @@
+##===---- unittests/DriverTests/Makefile ----------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===-------------------------------------------------------------------===##
+
+LLD_LEVEL = ../..
+TESTNAME = DriverTests
+USEDLIBS = lldDriver.a lldConfig.a \
+ lldELF.a lldMachO.a lldPECOFF.a \
+ lldCore.a lldNative.a lldReaderWriter.a \
+ lldHexagonELFTarget.a lldMipsELFTarget.a \
+ lldX86ELFTarget.a lldExampleSubTarget.a lldX86_64ELFTarget.a \
+ lldYAML.a lldAArch64ELFTarget.a lldARMELFTarget.a \
+ LLVMObject.a LLVMMCParser.a LLVMMC.a LLVMBitReader.a \
+ LLVMCore.a LLVMOption.a LLVMSupport.a
+include $(LLD_LEVEL)/unittests/Makefile
diff --git a/unittests/DriverTests/UniversalDriverTest.cpp b/unittests/DriverTests/UniversalDriverTest.cpp
new file mode 100644
index 000000000000..8e90ca4d5867
--- /dev/null
+++ b/unittests/DriverTests/UniversalDriverTest.cpp
@@ -0,0 +1,33 @@
+//===- lld/unittest/UniversalDriverTest.cpp -------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Universal driver tests that depend on the value of argv[0].
+///
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+#include "lld/Driver/Driver.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace lld;
+
+TEST(UniversalDriver, flavor) {
+ const char *args[] = { "gnu-ld" };
+
+ std::string diags;
+ raw_string_ostream os(diags);
+ UniversalDriver::link(array_lengthof(args), args, os);
+ EXPECT_EQ(os.str().find("failed to determine driver flavor"),
+ std::string::npos);
+ EXPECT_NE(os.str().find("No input files"),
+ std::string::npos);
+}
diff --git a/unittests/DriverTests/WinLinkDriverTest.cpp b/unittests/DriverTests/WinLinkDriverTest.cpp
new file mode 100644
index 000000000000..c2bc455aa81f
--- /dev/null
+++ b/unittests/DriverTests/WinLinkDriverTest.cpp
@@ -0,0 +1,728 @@
+//===- lld/unittest/WinLinkDriverTest.cpp ---------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Windows link.exe driver tests.
+///
+//===----------------------------------------------------------------------===//
+
+#include "DriverTest.h"
+#include "lld/ReaderWriter/PECOFFLinkingContext.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/Support/COFF.h"
+#include <set>
+#include <vector>
+
+using namespace llvm;
+using namespace lld;
+
+namespace {
+class WinLinkParserTest
+ : public ParserTest<WinLinkDriver, PECOFFLinkingContext> {
+protected:
+ const LinkingContext *linkingContext() override { return &_ctx; }
+};
+}
+
+TEST_F(WinLinkParserTest, Basic) {
+ EXPECT_TRUE(parse("link.exe", "/subsystem:console", "/out:a.exe",
+ "-entry:start", "a.obj", "b.obj", "c.obj", nullptr));
+ EXPECT_EQ(llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_CUI, _ctx.getSubsystem());
+ EXPECT_EQ(llvm::COFF::IMAGE_FILE_MACHINE_I386, _ctx.getMachineType());
+ EXPECT_EQ("a.exe", _ctx.outputPath());
+ EXPECT_EQ("start", _ctx.getEntrySymbolName());
+ EXPECT_EQ(4, inputFileCount());
+ EXPECT_EQ("a.obj", inputFile(0));
+ EXPECT_EQ("b.obj", inputFile(1));
+ EXPECT_EQ("c.obj", inputFile(2));
+ EXPECT_TRUE(_ctx.getInputSearchPaths().empty());
+
+ // Unspecified flags will have default values.
+ EXPECT_FALSE(_ctx.isDll());
+ EXPECT_EQ(6, _ctx.getMinOSVersion().majorVersion);
+ EXPECT_EQ(0, _ctx.getMinOSVersion().minorVersion);
+ EXPECT_EQ(0x400000U, _ctx.getBaseAddress());
+ EXPECT_EQ(1024 * 1024U, _ctx.getStackReserve());
+ EXPECT_EQ(4096U, _ctx.getStackCommit());
+ EXPECT_EQ(4096U, _ctx.getSectionDefaultAlignment());
+ EXPECT_FALSE(_ctx.allowRemainingUndefines());
+ EXPECT_TRUE(_ctx.isNxCompat());
+ EXPECT_FALSE(_ctx.getLargeAddressAware());
+ EXPECT_TRUE(_ctx.getAllowBind());
+ EXPECT_TRUE(_ctx.getAllowIsolation());
+ EXPECT_FALSE(_ctx.getSwapRunFromCD());
+ EXPECT_FALSE(_ctx.getSwapRunFromNet());
+ EXPECT_TRUE(_ctx.getBaseRelocationEnabled());
+ EXPECT_TRUE(_ctx.isTerminalServerAware());
+ EXPECT_TRUE(_ctx.getDynamicBaseEnabled());
+ EXPECT_TRUE(_ctx.getCreateManifest());
+ EXPECT_EQ("", _ctx.getManifestDependency());
+ EXPECT_FALSE(_ctx.getEmbedManifest());
+ EXPECT_EQ(1, _ctx.getManifestId());
+ EXPECT_TRUE(_ctx.getManifestUAC());
+ EXPECT_EQ("'asInvoker'", _ctx.getManifestLevel());
+ EXPECT_EQ("'false'", _ctx.getManifestUiAccess());
+ EXPECT_TRUE(_ctx.deadStrip());
+ EXPECT_FALSE(_ctx.logInputFiles());
+}
+
+TEST_F(WinLinkParserTest, StartsWithHyphen) {
+ EXPECT_TRUE(
+ parse("link.exe", "-subsystem:console", "-out:a.exe", "a.obj", nullptr));
+ EXPECT_EQ(llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_CUI, _ctx.getSubsystem());
+ EXPECT_EQ("a.exe", _ctx.outputPath());
+ EXPECT_EQ(2, inputFileCount());
+ EXPECT_EQ("a.obj", inputFile(0));
+}
+
+TEST_F(WinLinkParserTest, UppercaseOption) {
+ EXPECT_TRUE(
+ parse("link.exe", "/SUBSYSTEM:CONSOLE", "/OUT:a.exe", "a.obj", nullptr));
+ EXPECT_EQ(llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_CUI, _ctx.getSubsystem());
+ EXPECT_EQ("a.exe", _ctx.outputPath());
+ EXPECT_EQ(2, inputFileCount());
+ EXPECT_EQ("a.obj", inputFile(0));
+}
+
+TEST_F(WinLinkParserTest, Mllvm) {
+ EXPECT_TRUE(parse("link.exe", "/mllvm:-debug", "a.obj", nullptr));
+ const std::vector<const char *> &options = _ctx.llvmOptions();
+ EXPECT_EQ(1U, options.size());
+ EXPECT_STREQ("-debug", options[0]);
+}
+
+TEST_F(WinLinkParserTest, NoInputFiles) {
+ EXPECT_FALSE(parse("link.exe", nullptr));
+ EXPECT_EQ("No input files\n", errorMessage());
+}
+
+//
+// Tests for implicit file extension interpolation.
+//
+
+TEST_F(WinLinkParserTest, NoFileExtension) {
+ EXPECT_TRUE(parse("link.exe", "foo", "bar", nullptr));
+ EXPECT_EQ("foo.exe", _ctx.outputPath());
+ EXPECT_EQ(3, inputFileCount());
+ EXPECT_EQ("foo.obj", inputFile(0));
+ EXPECT_EQ("bar.obj", inputFile(1));
+}
+
+TEST_F(WinLinkParserTest, NonStandardFileExtension) {
+ EXPECT_TRUE(parse("link.exe", "foo.o", nullptr));
+ EXPECT_EQ("foo.exe", _ctx.outputPath());
+ EXPECT_EQ(2, inputFileCount());
+ EXPECT_EQ("foo.o", inputFile(0));
+}
+
+TEST_F(WinLinkParserTest, Libpath) {
+ EXPECT_TRUE(
+ parse("link.exe", "/libpath:dir1", "/libpath:dir2", "a.obj", nullptr));
+ const std::vector<StringRef> &paths = _ctx.getInputSearchPaths();
+ EXPECT_EQ(2U, paths.size());
+ EXPECT_EQ("dir1", paths[0]);
+ EXPECT_EQ("dir2", paths[1]);
+}
+
+//
+// Tests for input file order
+//
+
+TEST_F(WinLinkParserTest, InputOrder) {
+ EXPECT_TRUE(parse("link.exe", "a.lib", "b.obj", "c.obj", "a.lib", "d.obj",
+ nullptr));
+ EXPECT_EQ(5, inputFileCount());
+ EXPECT_EQ("b.obj", inputFile(0));
+ EXPECT_EQ("c.obj", inputFile(1));
+ EXPECT_EQ("d.obj", inputFile(2));
+ EXPECT_EQ("a.lib", inputFile(3));
+}
+
+//
+// Tests for command line options that take values.
+//
+
+TEST_F(WinLinkParserTest, AlternateName) {
+ EXPECT_TRUE(parse("link.exe", "/alternatename:sym1=sym",
+ "/alternatename:sym2=sym", "a.out", nullptr));
+ const std::set<std::string> &aliases = _ctx.getAlternateNames("sym");
+ EXPECT_EQ(2U, aliases.size());
+ auto it = aliases.begin();
+ EXPECT_EQ("sym1", *it++);
+ EXPECT_EQ("sym2", *it++);
+}
+
+TEST_F(WinLinkParserTest, Export) {
+ EXPECT_TRUE(parse("link.exe", "/export:foo", "a.out", nullptr));
+ const std::vector<PECOFFLinkingContext::ExportDesc> &exports =
+ _ctx.getDllExports();
+ EXPECT_EQ(1U, exports.size());
+ EXPECT_EQ("_foo", exports[0].name);
+ EXPECT_EQ(-1, exports[0].ordinal);
+ EXPECT_FALSE(exports[0].noname);
+ EXPECT_FALSE(exports[0].isData);
+}
+
+TEST_F(WinLinkParserTest, ExportWithOptions) {
+ EXPECT_TRUE(parse("link.exe", "/export:foo,@8,noname,data",
+ "/export:bar,@10,data", "a.out", nullptr));
+ const std::vector<PECOFFLinkingContext::ExportDesc> &exports =
+ _ctx.getDllExports();
+ EXPECT_EQ(2U, exports.size());
+ EXPECT_EQ("_foo", exports[0].name);
+ EXPECT_EQ(8, exports[0].ordinal);
+ EXPECT_TRUE(exports[0].noname);
+ EXPECT_TRUE(exports[0].isData);
+ EXPECT_EQ("_bar", exports[1].name);
+ EXPECT_EQ(10, exports[1].ordinal);
+ EXPECT_FALSE(exports[1].noname);
+ EXPECT_TRUE(exports[1].isData);
+}
+
+TEST_F(WinLinkParserTest, ExportDuplicateExports) {
+ EXPECT_TRUE(
+ parse("link.exe", "/export:foo", "/export:foo,@2", "a.out", nullptr));
+ const std::vector<PECOFFLinkingContext::ExportDesc> &exports =
+ _ctx.getDllExports();
+ EXPECT_EQ(1U, exports.size());
+ EXPECT_EQ("_foo", exports[0].name);
+ EXPECT_EQ(-1, exports[0].ordinal);
+}
+
+TEST_F(WinLinkParserTest, ExportDuplicateOrdinals) {
+ EXPECT_FALSE(
+ parse("link.exe", "/export:foo,@1", "/export:bar,@1", "a.out", nullptr));
+}
+
+TEST_F(WinLinkParserTest, ExportInvalid1) {
+ EXPECT_FALSE(parse("link.exe", "/export:foo,@0", "a.out", nullptr));
+}
+
+TEST_F(WinLinkParserTest, ExportInvalid2) {
+ EXPECT_FALSE(parse("link.exe", "/export:foo,@65536", "a.out", nullptr));
+}
+
+TEST_F(WinLinkParserTest, MachineX86) {
+ EXPECT_TRUE(parse("link.exe", "/machine:x86", "a.obj", nullptr));
+ EXPECT_EQ(llvm::COFF::IMAGE_FILE_MACHINE_I386, _ctx.getMachineType());
+}
+
+TEST_F(WinLinkParserTest, MachineX64) {
+ EXPECT_TRUE(parse("link.exe", "/machine:x64", "a.obj", nullptr));
+ EXPECT_EQ(llvm::COFF::IMAGE_FILE_MACHINE_AMD64, _ctx.getMachineType());
+}
+
+TEST_F(WinLinkParserTest, MachineArm) {
+ EXPECT_TRUE(parse("link.exe", "/machine:arm", "a.obj", nullptr));
+ EXPECT_EQ(llvm::COFF::IMAGE_FILE_MACHINE_ARMNT, _ctx.getMachineType());
+}
+
+TEST_F(WinLinkParserTest, MachineUnknown) {
+ EXPECT_FALSE(parse("link.exe", "/machine:nosucharch", "a.obj", nullptr));
+ EXPECT_EQ("error: unknown machine type: nosucharch\n", errorMessage());
+}
+
+TEST_F(WinLinkParserTest, MajorImageVersion) {
+ EXPECT_TRUE(parse("link.exe", "/version:7", "foo.o", nullptr));
+ EXPECT_EQ(7, _ctx.getImageVersion().majorVersion);
+ EXPECT_EQ(0, _ctx.getImageVersion().minorVersion);
+}
+
+TEST_F(WinLinkParserTest, MajorMinorImageVersion) {
+ EXPECT_TRUE(parse("link.exe", "/version:72.35", "foo.o", nullptr));
+ EXPECT_EQ(72, _ctx.getImageVersion().majorVersion);
+ EXPECT_EQ(35, _ctx.getImageVersion().minorVersion);
+}
+
+TEST_F(WinLinkParserTest, MinMajorOSVersion) {
+ EXPECT_TRUE(parse("link.exe", "/subsystem:windows,3", "foo.o", nullptr));
+ EXPECT_EQ(llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_GUI, _ctx.getSubsystem());
+ EXPECT_EQ(3, _ctx.getMinOSVersion().majorVersion);
+ EXPECT_EQ(0, _ctx.getMinOSVersion().minorVersion);
+}
+
+TEST_F(WinLinkParserTest, MinMajorMinorOSVersion) {
+ EXPECT_TRUE(parse("link.exe", "/subsystem:windows,3.1", "foo.o", nullptr));
+ EXPECT_EQ(llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_GUI, _ctx.getSubsystem());
+ EXPECT_EQ(3, _ctx.getMinOSVersion().majorVersion);
+ EXPECT_EQ(1, _ctx.getMinOSVersion().minorVersion);
+}
+
+TEST_F(WinLinkParserTest, Base) {
+ EXPECT_TRUE(parse("link.exe", "/base:8388608", "a.obj", nullptr));
+ EXPECT_EQ(0x800000U, _ctx.getBaseAddress());
+}
+
+TEST_F(WinLinkParserTest, InvalidBase) {
+ EXPECT_FALSE(parse("link.exe", "/base:1234", "a.obj", nullptr));
+ EXPECT_TRUE(StringRef(errorMessage())
+ .startswith("Base address have to be multiple of 64K"));
+}
+
+TEST_F(WinLinkParserTest, StackReserve) {
+ EXPECT_TRUE(parse("link.exe", "/stack:8192", "a.obj", nullptr));
+ EXPECT_EQ(8192U, _ctx.getStackReserve());
+ EXPECT_EQ(4096U, _ctx.getStackCommit());
+}
+
+TEST_F(WinLinkParserTest, StackReserveAndCommit) {
+ EXPECT_TRUE(parse("link.exe", "/stack:16384,8192", "a.obj", nullptr));
+ EXPECT_EQ(16384U, _ctx.getStackReserve());
+ EXPECT_EQ(8192U, _ctx.getStackCommit());
+}
+
+TEST_F(WinLinkParserTest, InvalidStackSize) {
+ EXPECT_FALSE(parse("link.exe", "/stack:8192,16384", "a.obj", nullptr));
+ EXPECT_TRUE(StringRef(errorMessage()).startswith("Invalid stack size"));
+}
+
+TEST_F(WinLinkParserTest, HeapReserve) {
+ EXPECT_TRUE(parse("link.exe", "/heap:8192", "a.obj", nullptr));
+ EXPECT_EQ(8192U, _ctx.getHeapReserve());
+ EXPECT_EQ(4096U, _ctx.getHeapCommit());
+}
+
+TEST_F(WinLinkParserTest, HeapReserveAndCommit) {
+ EXPECT_TRUE(parse("link.exe", "/heap:16384,8192", "a.obj", nullptr));
+ EXPECT_EQ(16384U, _ctx.getHeapReserve());
+ EXPECT_EQ(8192U, _ctx.getHeapCommit());
+}
+
+TEST_F(WinLinkParserTest, InvalidHeapSize) {
+ EXPECT_FALSE(parse("link.exe", "/heap:8192,16384", "a.obj", nullptr));
+ EXPECT_TRUE(StringRef(errorMessage()).startswith("Invalid heap size"));
+}
+
+TEST_F(WinLinkParserTest, SectionAlignment) {
+ EXPECT_TRUE(parse("link.exe", "/align:8192", "a.obj", nullptr));
+ EXPECT_EQ(8192U, _ctx.getSectionDefaultAlignment());
+}
+
+TEST_F(WinLinkParserTest, InvalidAlignment) {
+ EXPECT_FALSE(parse("link.exe", "/align:1000", "a.obj", nullptr));
+ EXPECT_EQ("Section alignment must be a power of 2, but got 1000\n",
+ errorMessage());
+}
+
+TEST_F(WinLinkParserTest, Include) {
+ EXPECT_TRUE(parse("link.exe", "/include:foo", "a.out", nullptr));
+ auto symbols = _ctx.initialUndefinedSymbols();
+ EXPECT_FALSE(symbols.empty());
+ EXPECT_EQ("foo", symbols[0]);
+}
+
+TEST_F(WinLinkParserTest, Merge) {
+ EXPECT_TRUE(parse("link.exe", "/merge:.foo=.bar", "/merge:.bar=.baz",
+ "a.out", nullptr));
+ EXPECT_EQ(".baz", _ctx.getOutputSectionName(".foo"));
+ EXPECT_EQ(".baz", _ctx.getOutputSectionName(".bar"));
+ EXPECT_EQ(".abc", _ctx.getOutputSectionName(".abc"));
+}
+
+TEST_F(WinLinkParserTest, Merge_Circular) {
+ EXPECT_FALSE(parse("link.exe", "/merge:.foo=.bar", "/merge:.bar=.foo",
+ "a.out", nullptr));
+}
+
+TEST_F(WinLinkParserTest, Implib) {
+ EXPECT_TRUE(parse("link.exe", "/implib:foo.dll.lib", "a.out", nullptr));
+ EXPECT_EQ("foo.dll.lib", _ctx.getOutputImportLibraryPath());
+}
+
+TEST_F(WinLinkParserTest, ImplibDefault) {
+ EXPECT_TRUE(parse("link.exe", "/out:foobar.dll", "a.out", nullptr));
+ EXPECT_EQ("foobar.lib", _ctx.getOutputImportLibraryPath());
+}
+
+//
+// Tests for /section
+//
+
+namespace {
+const uint32_t discardable = llvm::COFF::IMAGE_SCN_MEM_DISCARDABLE;
+const uint32_t not_cached = llvm::COFF::IMAGE_SCN_MEM_NOT_CACHED;
+const uint32_t not_paged = llvm::COFF::IMAGE_SCN_MEM_NOT_PAGED;
+const uint32_t shared = llvm::COFF::IMAGE_SCN_MEM_SHARED;
+const uint32_t execute = llvm::COFF::IMAGE_SCN_MEM_EXECUTE;
+const uint32_t read = llvm::COFF::IMAGE_SCN_MEM_READ;
+const uint32_t write = llvm::COFF::IMAGE_SCN_MEM_WRITE;
+
+#define TEST_SECTION(testname, arg, expect) \
+ TEST_F(WinLinkParserTest, testname) { \
+ EXPECT_TRUE(parse("link.exe", "/section:.text," arg, "a.obj", nullptr)); \
+ EXPECT_EQ(expect, _ctx.getSectionAttributes(".text", execute | read)); \
+ }
+
+TEST_SECTION(SectionD, "d", execute | read | discardable)
+TEST_SECTION(SectionE, "e", execute)
+TEST_SECTION(SectionK, "k", execute | read | not_cached)
+TEST_SECTION(SectionP, "p", execute | read | not_paged)
+TEST_SECTION(SectionR, "r", read)
+TEST_SECTION(SectionS, "s", execute | read | shared)
+TEST_SECTION(SectionW, "w", write)
+
+#undef TEST_SECTION
+
+TEST_F(WinLinkParserTest, Section) {
+ EXPECT_TRUE(parse("link.exe", "/section:.text,dekprsw",
+ "/section:.text,!dekprsw", "a.obj", nullptr));
+ EXPECT_EQ(0U, _ctx.getSectionAttributes(".text", execute | read));
+}
+
+TEST_F(WinLinkParserTest, SectionNegate) {
+ EXPECT_TRUE(parse("link.exe", "/section:.text,!e", "a.obj", nullptr));
+ EXPECT_EQ(read, _ctx.getSectionAttributes(".text", execute | read));
+}
+
+TEST_F(WinLinkParserTest, SectionMultiple) {
+ EXPECT_TRUE(parse("link.exe", "/section:.foo,e", "/section:.foo,rw",
+ "/section:.foo,!d", "a.obj", nullptr));
+ uint32_t flags = execute | read | not_paged | discardable;
+ uint32_t expected = execute | read | write | not_paged;
+ EXPECT_EQ(expected, _ctx.getSectionAttributes(".foo", flags));
+}
+
+} // end anonymous namespace
+
+//
+// Tests for /defaultlib and /nodefaultlib.
+//
+
+TEST_F(WinLinkParserTest, DefaultLib) {
+ EXPECT_TRUE(parse("link.exe", "/defaultlib:user32.lib",
+ "/defaultlib:kernel32", "a.obj", nullptr));
+ EXPECT_EQ(4, inputFileCount());
+ EXPECT_EQ("a.obj", inputFile(0));
+ EXPECT_EQ("user32.lib", inputFile(1));
+ EXPECT_EQ("kernel32.lib", inputFile(2));
+}
+
+TEST_F(WinLinkParserTest, DefaultLibDuplicates) {
+ EXPECT_TRUE(parse("link.exe", "/defaultlib:user32.lib",
+ "/defaultlib:user32.lib", "a.obj", nullptr));
+ EXPECT_EQ(3, inputFileCount());
+ EXPECT_EQ("a.obj", inputFile(0));
+ EXPECT_EQ("user32.lib", inputFile(1));
+}
+
+TEST_F(WinLinkParserTest, NoDefaultLib) {
+ EXPECT_TRUE(parse("link.exe", "/defaultlib:user32.lib",
+ "/defaultlib:kernel32", "/nodefaultlib:user32.lib", "a.obj",
+ nullptr));
+ EXPECT_EQ(3, inputFileCount());
+ EXPECT_EQ("a.obj", inputFile(0));
+ EXPECT_EQ("kernel32.lib", inputFile(1));
+}
+
+TEST_F(WinLinkParserTest, NoDefaultLibCase) {
+ EXPECT_TRUE(parse("link.exe", "/defaultlib:user32",
+ "/defaultlib:kernel32", "/nodefaultlib:USER32.LIB", "a.obj",
+ nullptr));
+ EXPECT_EQ(3, inputFileCount());
+ EXPECT_EQ("a.obj", inputFile(0));
+ EXPECT_EQ("kernel32.lib", inputFile(1));
+}
+
+TEST_F(WinLinkParserTest, NoDefaultLibAll) {
+ EXPECT_TRUE(parse("link.exe", "/defaultlib:user32.lib",
+ "/defaultlib:kernel32", "/nodefaultlib", "a.obj", nullptr));
+ EXPECT_EQ(2, inputFileCount());
+ EXPECT_EQ("a.obj", inputFile(0));
+}
+
+TEST_F(WinLinkParserTest, DisallowLib) {
+ EXPECT_TRUE(parse("link.exe", "/defaultlib:user32.lib",
+ "/defaultlib:kernel32", "/disallowlib:user32.lib", "a.obj",
+ nullptr));
+ EXPECT_EQ(3, inputFileCount());
+ EXPECT_EQ("a.obj", inputFile(0));
+ EXPECT_EQ("kernel32.lib", inputFile(1));
+}
+
+//
+// Tests for DLL.
+//
+
+TEST_F(WinLinkParserTest, NoEntry) {
+ EXPECT_TRUE(parse("link.exe", "/noentry", "/dll", "a.obj", nullptr));
+ EXPECT_TRUE(_ctx.isDll());
+ EXPECT_EQ(0x10000000U, _ctx.getBaseAddress());
+ EXPECT_EQ("", _ctx.entrySymbolName());
+}
+
+TEST_F(WinLinkParserTest, NoEntryError) {
+ // /noentry without /dll is an error.
+ EXPECT_FALSE(parse("link.exe", "/noentry", "a.obj", nullptr));
+ EXPECT_EQ("/noentry must be specified with /dll\n", errorMessage());
+}
+
+//
+// Tests for DELAYLOAD.
+//
+
+TEST_F(WinLinkParserTest, DelayLoad) {
+ EXPECT_TRUE(parse("link.exe", "/delayload:abc.dll", "/delayload:def.dll",
+ "a.obj", nullptr));
+ EXPECT_TRUE(_ctx.isDelayLoadDLL("abc.dll"));
+ EXPECT_TRUE(_ctx.isDelayLoadDLL("DEF.DLL"));
+ EXPECT_FALSE(_ctx.isDelayLoadDLL("xyz.dll"));
+}
+
+//
+// Tests for SEH.
+//
+
+TEST_F(WinLinkParserTest, SafeSEH) {
+ EXPECT_TRUE(parse("link.exe", "/safeseh", "a.obj", nullptr));
+ EXPECT_TRUE(_ctx.requireSEH());
+ EXPECT_FALSE(_ctx.noSEH());
+}
+
+TEST_F(WinLinkParserTest, NoSafeSEH) {
+ EXPECT_TRUE(parse("link.exe", "/safeseh:no", "a.obj", nullptr));
+ EXPECT_FALSE(_ctx.requireSEH());
+ EXPECT_TRUE(_ctx.noSEH());
+}
+
+//
+// Tests for boolean flags.
+//
+
+TEST_F(WinLinkParserTest, Force) {
+ EXPECT_TRUE(parse("link.exe", "/force", "a.obj", nullptr));
+ EXPECT_TRUE(_ctx.allowRemainingUndefines());
+}
+
+TEST_F(WinLinkParserTest, ForceUnresolved) {
+ EXPECT_TRUE(parse("link.exe", "/force:unresolved", "a.obj", nullptr));
+ EXPECT_TRUE(_ctx.allowRemainingUndefines());
+}
+
+TEST_F(WinLinkParserTest, NoNxCompat) {
+ EXPECT_TRUE(parse("link.exe", "/nxcompat:no", "a.obj", nullptr));
+ EXPECT_FALSE(_ctx.isNxCompat());
+}
+
+TEST_F(WinLinkParserTest, LargeAddressAware) {
+ EXPECT_TRUE(parse("link.exe", "/largeaddressaware", "a.obj", nullptr));
+ EXPECT_TRUE(_ctx.getLargeAddressAware());
+}
+
+TEST_F(WinLinkParserTest, NoLargeAddressAware) {
+ EXPECT_TRUE(parse("link.exe", "/largeaddressaware:no", "a.obj", nullptr));
+ EXPECT_FALSE(_ctx.getLargeAddressAware());
+}
+
+TEST_F(WinLinkParserTest, AllowBind) {
+ EXPECT_TRUE(parse("link.exe", "/allowbind", "a.obj", nullptr));
+ EXPECT_TRUE(_ctx.getAllowBind());
+}
+
+TEST_F(WinLinkParserTest, NoAllowBind) {
+ EXPECT_TRUE(parse("link.exe", "/allowbind:no", "a.obj", nullptr));
+ EXPECT_FALSE(_ctx.getAllowBind());
+}
+
+TEST_F(WinLinkParserTest, AllowIsolation) {
+ EXPECT_TRUE(parse("link.exe", "/allowisolation", "a.obj", nullptr));
+ EXPECT_TRUE(_ctx.getAllowIsolation());
+}
+
+TEST_F(WinLinkParserTest, NoAllowIsolation) {
+ EXPECT_TRUE(parse("link.exe", "/allowisolation:no", "a.obj", nullptr));
+ EXPECT_FALSE(_ctx.getAllowIsolation());
+}
+
+TEST_F(WinLinkParserTest, SwapRunFromCD) {
+ EXPECT_TRUE(parse("link.exe", "/swaprun:cd", "a.obj", nullptr));
+ EXPECT_TRUE(_ctx.getSwapRunFromCD());
+}
+
+TEST_F(WinLinkParserTest, SwapRunFromNet) {
+ EXPECT_TRUE(parse("link.exe", "/swaprun:net", "a.obj", nullptr));
+ EXPECT_TRUE(_ctx.getSwapRunFromNet());
+}
+
+TEST_F(WinLinkParserTest, Debug) {
+ EXPECT_TRUE(parse("link.exe", "/debug", "a.obj", nullptr));
+ EXPECT_TRUE(_ctx.deadStrip());
+ EXPECT_TRUE(_ctx.getDebug());
+ EXPECT_EQ("a.pdb", _ctx.getPDBFilePath());
+}
+
+TEST_F(WinLinkParserTest, PDB) {
+ EXPECT_TRUE(parse("link.exe", "/debug", "/pdb:foo.pdb", "a.obj", nullptr));
+ EXPECT_TRUE(_ctx.getDebug());
+ EXPECT_EQ("foo.pdb", _ctx.getPDBFilePath());
+}
+
+TEST_F(WinLinkParserTest, Fixed) {
+ EXPECT_TRUE(parse("link.exe", "/fixed", "a.out", nullptr));
+ EXPECT_FALSE(_ctx.getBaseRelocationEnabled());
+ EXPECT_FALSE(_ctx.getDynamicBaseEnabled());
+}
+
+TEST_F(WinLinkParserTest, NoFixed) {
+ EXPECT_TRUE(parse("link.exe", "/fixed:no", "a.out", nullptr));
+ EXPECT_TRUE(_ctx.getBaseRelocationEnabled());
+}
+
+TEST_F(WinLinkParserTest, TerminalServerAware) {
+ EXPECT_TRUE(parse("link.exe", "/tsaware", "a.out", nullptr));
+ EXPECT_TRUE(_ctx.isTerminalServerAware());
+}
+
+TEST_F(WinLinkParserTest, NoTerminalServerAware) {
+ EXPECT_TRUE(parse("link.exe", "/tsaware:no", "a.out", nullptr));
+ EXPECT_FALSE(_ctx.isTerminalServerAware());
+}
+
+TEST_F(WinLinkParserTest, DynamicBase) {
+ EXPECT_TRUE(parse("link.exe", "/dynamicbase", "a.out", nullptr));
+ EXPECT_TRUE(_ctx.getDynamicBaseEnabled());
+}
+
+TEST_F(WinLinkParserTest, NoDynamicBase) {
+ EXPECT_TRUE(parse("link.exe", "/dynamicbase:no", "a.out", nullptr));
+ EXPECT_FALSE(_ctx.getDynamicBaseEnabled());
+}
+
+//
+// Test for /failifmismatch
+//
+
+TEST_F(WinLinkParserTest, FailIfMismatch_Match) {
+ EXPECT_TRUE(parse("link.exe", "/failifmismatch:foo=bar",
+ "/failifmismatch:foo=bar", "/failifmismatch:abc=def",
+ "a.out", nullptr));
+}
+
+TEST_F(WinLinkParserTest, FailIfMismatch_Mismatch) {
+ EXPECT_FALSE(parse("link.exe", "/failifmismatch:foo=bar",
+ "/failifmismatch:foo=baz", "a.out", nullptr));
+}
+
+//
+// Tests for /manifest, /manifestuac, /manifestfile, and /manifestdependency.
+//
+TEST_F(WinLinkParserTest, Manifest_Default) {
+ EXPECT_TRUE(parse("link.exe", "/manifest", "a.out", nullptr));
+ EXPECT_TRUE(_ctx.getCreateManifest());
+ EXPECT_FALSE(_ctx.getEmbedManifest());
+ EXPECT_EQ(1, _ctx.getManifestId());
+ EXPECT_EQ("'asInvoker'", _ctx.getManifestLevel());
+ EXPECT_EQ("'false'", _ctx.getManifestUiAccess());
+}
+
+TEST_F(WinLinkParserTest, Manifest_No) {
+ EXPECT_TRUE(parse("link.exe", "/manifest:no", "a.out", nullptr));
+ EXPECT_FALSE(_ctx.getCreateManifest());
+}
+
+TEST_F(WinLinkParserTest, Manifestuac_no) {
+ EXPECT_TRUE(parse("link.exe", "/manifestuac:NO", "a.out", nullptr));
+ EXPECT_FALSE(_ctx.getManifestUAC());
+}
+
+TEST_F(WinLinkParserTest, Manifestuac_Level) {
+ EXPECT_TRUE(parse("link.exe", "/manifestuac:level='requireAdministrator'",
+ "a.out", nullptr));
+ EXPECT_EQ("'requireAdministrator'", _ctx.getManifestLevel());
+ EXPECT_EQ("'false'", _ctx.getManifestUiAccess());
+}
+
+TEST_F(WinLinkParserTest, Manifestuac_UiAccess) {
+ EXPECT_TRUE(parse("link.exe", "/manifestuac:uiAccess='true'", "a.out", nullptr));
+ EXPECT_EQ("'asInvoker'", _ctx.getManifestLevel());
+ EXPECT_EQ("'true'", _ctx.getManifestUiAccess());
+}
+
+TEST_F(WinLinkParserTest, Manifestuac_LevelAndUiAccess) {
+ EXPECT_TRUE(parse("link.exe",
+ "/manifestuac:level='requireAdministrator' uiAccess='true'",
+ "a.out", nullptr));
+ EXPECT_EQ("'requireAdministrator'", _ctx.getManifestLevel());
+ EXPECT_EQ("'true'", _ctx.getManifestUiAccess());
+}
+
+TEST_F(WinLinkParserTest, Manifestfile) {
+ EXPECT_TRUE(parse("link.exe", "/manifestfile:bar.manifest",
+ "a.out", nullptr));
+ EXPECT_EQ("bar.manifest", _ctx.getManifestOutputPath());
+}
+
+TEST_F(WinLinkParserTest, Manifestdependency) {
+ EXPECT_TRUE(parse("link.exe", "/manifestdependency:foo bar", "a.out",
+ nullptr));
+ EXPECT_EQ("foo bar", _ctx.getManifestDependency());
+}
+
+//
+// Test for /OPT
+//
+
+TEST_F(WinLinkParserTest, OptNoRef) {
+ EXPECT_TRUE(parse("link.exe", "/opt:noref", "a.obj", nullptr));
+ EXPECT_FALSE(_ctx.deadStrip());
+}
+
+TEST_F(WinLinkParserTest, OptIgnore) {
+ EXPECT_TRUE(parse("link.exe", "/opt:ref", "/opt:icf", "/opt:noicf",
+ "/opt:icf=foo", "/opt:lbr", "/opt:nolbr", "a.obj",
+ nullptr));
+}
+
+TEST_F(WinLinkParserTest, OptUnknown) {
+ EXPECT_FALSE(parse("link.exe", "/opt:foo", "a.obj", nullptr));
+}
+
+//
+// Test for /PROFILE
+//
+
+TEST_F(WinLinkParserTest, Profile) {
+ EXPECT_TRUE(parse("link.exe", "/profile", "a.obj", nullptr));
+ EXPECT_TRUE(_ctx.deadStrip());
+ EXPECT_TRUE(_ctx.getBaseRelocationEnabled());
+ EXPECT_TRUE(_ctx.getDynamicBaseEnabled());
+}
+
+//
+// Test for command line flags that are ignored.
+//
+
+TEST_F(WinLinkParserTest, Ignore) {
+ // There are some no-op command line options that are recognized for
+ // compatibility with link.exe.
+ EXPECT_TRUE(parse("link.exe", "/nologo", "/errorreport:prompt",
+ "/incremental", "/incremental:no", "/delay:unload",
+ "/disallowlib:foo", "/pdbaltpath:bar",
+ "/wx", "/wx:no", "/tlbid:1", "/tlbout:foo", "/idlout:foo",
+ "/ignore:4000", "/ignoreidl", "/implib:foo", "/safeseh",
+ "/safeseh:no", "/functionpadmin", "/maxilksize:1024",
+ "a.obj", nullptr));
+ EXPECT_EQ("", errorMessage());
+ EXPECT_EQ(2, inputFileCount());
+ EXPECT_EQ("a.obj", inputFile(0));
+}
+
+//
+// Test for "--"
+//
+
+TEST_F(WinLinkParserTest, DashDash) {
+ EXPECT_TRUE(parse("link.exe", "/subsystem:console", "/out:a.exe", "a.obj",
+ "--", "b.obj", "-c.obj", nullptr));
+ EXPECT_EQ(llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_CUI, _ctx.getSubsystem());
+ EXPECT_EQ("a.exe", _ctx.outputPath());
+ EXPECT_EQ(4, inputFileCount());
+ EXPECT_EQ("a.obj", inputFile(0));
+ EXPECT_EQ("b.obj", inputFile(1));
+ EXPECT_EQ("-c.obj", inputFile(2));
+}
diff --git a/unittests/DriverTests/WinLinkModuleDefTest.cpp b/unittests/DriverTests/WinLinkModuleDefTest.cpp
new file mode 100644
index 000000000000..6762fd4b2ea6
--- /dev/null
+++ b/unittests/DriverTests/WinLinkModuleDefTest.cpp
@@ -0,0 +1,155 @@
+//===- lld/unittest/WinLinkModuleDefTest.cpp ------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+#include "lld/Driver/WinLinkModuleDef.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <memory>
+
+using namespace llvm;
+using namespace lld;
+
+class ParserTest : public testing::Test {
+protected:
+ std::vector<moduledef::Directive *> _dirs;
+
+ void parse(const char *contents) {
+ auto membuf =
+ std::unique_ptr<MemoryBuffer>(MemoryBuffer::getMemBuffer(contents));
+ moduledef::Lexer lexer(std::move(membuf));
+ moduledef::Parser parser(lexer, _alloc);
+ EXPECT_TRUE(parser.parse(_dirs));
+ EXPECT_TRUE(!_dirs.empty());
+ }
+
+ void verifyExportDesc(const PECOFFLinkingContext::ExportDesc &exp,
+ StringRef sym, int ordinal, bool noname, bool isData) {
+ EXPECT_EQ(sym, exp.name);
+ EXPECT_EQ(ordinal, exp.ordinal);
+ EXPECT_EQ(noname, exp.noname);
+ EXPECT_EQ(isData, exp.isData);
+ }
+
+private:
+ llvm::BumpPtrAllocator _alloc;
+};
+
+TEST_F(ParserTest, Exports) {
+ parse("EXPORTS\n"
+ " sym1\n"
+ " sym2 @5\n"
+ " sym3 @8 NONAME\n"
+ " sym4 DATA\n"
+ " sym5 @10 NONAME DATA\n");
+ EXPECT_EQ(1U, _dirs.size());
+ const std::vector<PECOFFLinkingContext::ExportDesc> &exports =
+ cast<moduledef::Exports>(_dirs[0])->getExports();
+ EXPECT_EQ(5U, exports.size());
+ verifyExportDesc(exports[0], "sym1", -1, false, false);
+ verifyExportDesc(exports[1], "sym2", 5, false, false);
+ verifyExportDesc(exports[2], "sym3", 8, true, false);
+ verifyExportDesc(exports[3], "sym4", -1, false, true);
+ verifyExportDesc(exports[4], "sym5", 10, true, true);
+}
+
+TEST_F(ParserTest, Heapsize) {
+ parse("HEAPSIZE 65536");
+ EXPECT_EQ(1U, _dirs.size());
+ auto *heapsize = cast<moduledef::Heapsize>(_dirs[0]);
+ EXPECT_EQ(65536U, heapsize->getReserve());
+ EXPECT_EQ(0U, heapsize->getCommit());
+}
+
+TEST_F(ParserTest, HeapsizeWithCommit) {
+ parse("HEAPSIZE 65536, 8192");
+ EXPECT_EQ(1U, _dirs.size());
+ auto *heapsize = cast<moduledef::Heapsize>(_dirs[0]);
+ EXPECT_EQ(65536U, heapsize->getReserve());
+ EXPECT_EQ(8192U, heapsize->getCommit());
+}
+
+TEST_F(ParserTest, StacksizeBasic) {
+ parse("STACKSIZE 65536");
+ EXPECT_EQ(1U, _dirs.size());
+ auto *stacksize = cast<moduledef::Stacksize>(_dirs[0]);
+ EXPECT_EQ(65536U, stacksize->getReserve());
+ EXPECT_EQ(0U, stacksize->getCommit());
+}
+
+TEST_F(ParserTest, StacksizeWithCommit) {
+ parse("STACKSIZE 65536, 8192");
+ EXPECT_EQ(1U, _dirs.size());
+ auto *stacksize = cast<moduledef::Stacksize>(_dirs[0]);
+ EXPECT_EQ(65536U, stacksize->getReserve());
+ EXPECT_EQ(8192U, stacksize->getCommit());
+}
+
+TEST_F(ParserTest, Library) {
+ parse("LIBRARY foo.dll");
+ EXPECT_EQ(1U, _dirs.size());
+ auto *lib = cast<moduledef::Library>(_dirs[0]);
+ EXPECT_EQ("foo.dll", lib->getName());
+}
+
+TEST_F(ParserTest, NameBasic) {
+ parse("NAME foo.exe");
+ EXPECT_EQ(1U, _dirs.size());
+ auto *name = cast<moduledef::Name>(_dirs[0]);
+ EXPECT_EQ("foo.exe", name->getOutputPath());
+ EXPECT_EQ(0U, name->getBaseAddress());
+}
+
+TEST_F(ParserTest, NameWithBase) {
+ parse("NAME foo.exe BASE=4096");
+ EXPECT_EQ(1U, _dirs.size());
+ auto *name = cast<moduledef::Name>(_dirs[0]);
+ EXPECT_EQ("foo.exe", name->getOutputPath());
+ EXPECT_EQ(4096U, name->getBaseAddress());
+}
+
+TEST_F(ParserTest, NameLongFileName) {
+ parse("NAME \"a long file name.exe\"");
+ EXPECT_EQ(1U, _dirs.size());
+ auto *name = cast<moduledef::Name>(_dirs[0]);
+ EXPECT_EQ("a long file name.exe", name->getOutputPath());
+ EXPECT_EQ(0U, name->getBaseAddress());
+}
+
+TEST_F(ParserTest, VersionMajor) {
+ parse("VERSION 12");
+ EXPECT_EQ(1U, _dirs.size());
+ auto *ver = cast<moduledef::Version>(_dirs[0]);
+ EXPECT_EQ(12, ver->getMajorVersion());
+ EXPECT_EQ(0, ver->getMinorVersion());
+}
+
+TEST_F(ParserTest, VersionMajorMinor) {
+ parse("VERSION 12.34");
+ EXPECT_EQ(1U, _dirs.size());
+ auto *ver = cast<moduledef::Version>(_dirs[0]);
+ EXPECT_EQ(12, ver->getMajorVersion());
+ EXPECT_EQ(34, ver->getMinorVersion());
+}
+
+TEST_F(ParserTest, Multiple) {
+ parse("LIBRARY foo\n"
+ "EXPORTS sym\n"
+ "VERSION 12");
+ EXPECT_EQ(3U, _dirs.size());
+ auto *lib = cast<moduledef::Library>(_dirs[0]);
+ EXPECT_EQ("foo.dll", lib->getName());
+
+ const std::vector<PECOFFLinkingContext::ExportDesc> &exports =
+ cast<moduledef::Exports>(_dirs[1])->getExports();
+ EXPECT_EQ(1U, exports.size());
+ verifyExportDesc(exports[0], "sym", -1, false, false);
+
+ auto *ver = cast<moduledef::Version>(_dirs[2]);
+ EXPECT_EQ(12, ver->getMajorVersion());
+}
diff --git a/unittests/MachOTests/CMakeLists.txt b/unittests/MachOTests/CMakeLists.txt
new file mode 100644
index 000000000000..1a683484b5f9
--- /dev/null
+++ b/unittests/MachOTests/CMakeLists.txt
@@ -0,0 +1,13 @@
+
+add_lld_unittest(lldMachOTests
+ MachONormalizedFileBinaryReaderTests.cpp
+ MachONormalizedFileBinaryWriterTests.cpp
+ MachONormalizedFileToAtomsTests.cpp
+ MachONormalizedFileYAMLTests.cpp
+ )
+
+target_link_libraries(lldMachOTests
+ lldDriver
+ lldMachO
+ lldYAML
+ )
diff --git a/unittests/MachOTests/MachONormalizedFileBinaryReaderTests.cpp b/unittests/MachOTests/MachONormalizedFileBinaryReaderTests.cpp
new file mode 100644
index 000000000000..22ed3f15b3e6
--- /dev/null
+++ b/unittests/MachOTests/MachONormalizedFileBinaryReaderTests.cpp
@@ -0,0 +1,748 @@
+//===- lld/unittest/MachOTests/MachONormalizedFileBinaryReaderTests.cpp ---===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+#include "../../lib/ReaderWriter/MachO/MachONormalizedFile.h"
+#include "llvm/Support/MachO.h"
+#include <assert.h>
+#include <vector>
+
+using llvm::StringRef;
+using llvm::MemoryBuffer;
+using llvm::ErrorOr;
+
+using namespace lld::mach_o::normalized;
+using namespace llvm::MachO;
+
+static std::unique_ptr<NormalizedFile>
+fromBinary(const uint8_t bytes[], unsigned length, StringRef archStr) {
+ StringRef sr((const char*)bytes, length);
+ std::unique_ptr<MemoryBuffer> mb(MemoryBuffer::getMemBuffer(sr, "", false));
+ ErrorOr<std::unique_ptr<NormalizedFile>> r =
+ lld::mach_o::normalized::readBinary(
+ mb, lld::MachOLinkingContext::archFromName(archStr));
+ EXPECT_FALSE(!r);
+ return std::move(*r);
+}
+
+// The Mach-O object reader uses functions such as read32 or read64
+// which don't allow unaligned access. Our in-memory object file
+// needs to be aligned to a larger boundary than uint8_t's.
+#if _MSC_VER
+#define FILEBYTES __declspec(align(64)) const uint8_t fileBytes[]
+#else
+#define FILEBYTES const uint8_t fileBytes[] __attribute__((aligned(64)))
+#endif
+
+TEST(BinaryReaderTest, empty_obj_x86_64) {
+ FILEBYTES = {
+ 0xcf, 0xfa, 0xed, 0xfe, 0x07, 0x00, 0x00, 0x01,
+ 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00,
+ 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x19, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5f, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ std::unique_ptr<NormalizedFile> f =
+ fromBinary(fileBytes, sizeof(fileBytes), "x86_64");
+ EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86_64);
+ EXPECT_EQ((int)(f->fileType), MH_OBJECT);
+ EXPECT_EQ((int)(f->flags), MH_SUBSECTIONS_VIA_SYMBOLS);
+ EXPECT_TRUE(f->localSymbols.empty());
+ EXPECT_TRUE(f->globalSymbols.empty());
+ EXPECT_TRUE(f->undefinedSymbols.empty());
+}
+
+
+TEST(BinaryReaderTest, empty_obj_x86) {
+ FILEBYTES = {
+ 0xce, 0xfa, 0xed, 0xfe, 0x07, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x74, 0x65,
+ 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45,
+ 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ std::unique_ptr<NormalizedFile> f =
+ fromBinary(fileBytes, sizeof(fileBytes), "i386");
+ EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86);
+ EXPECT_EQ((int)(f->fileType), MH_OBJECT);
+ EXPECT_EQ((int)(f->flags), MH_SUBSECTIONS_VIA_SYMBOLS);
+ EXPECT_TRUE(f->localSymbols.empty());
+ EXPECT_TRUE(f->globalSymbols.empty());
+ EXPECT_TRUE(f->undefinedSymbols.empty());
+}
+
+
+TEST(BinaryReaderTest, empty_obj_ppc) {
+ FILEBYTES = {
+ 0xfe, 0xed, 0xfa, 0xce, 0x00, 0x00, 0x00, 0x12,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7c,
+ 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
+ 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x74, 0x65,
+ 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45,
+ 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ std::unique_ptr<NormalizedFile> f =
+ fromBinary(fileBytes, sizeof(fileBytes), "ppc");
+ EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_ppc);
+ EXPECT_EQ((int)(f->fileType), MH_OBJECT);
+ EXPECT_EQ((int)(f->flags), MH_SUBSECTIONS_VIA_SYMBOLS);
+ EXPECT_TRUE(f->localSymbols.empty());
+ EXPECT_TRUE(f->globalSymbols.empty());
+ EXPECT_TRUE(f->undefinedSymbols.empty());
+}
+
+
+TEST(BinaryReaderTest, empty_obj_armv7) {
+ FILEBYTES = {
+ 0xce, 0xfa, 0xed, 0xfe, 0x0c, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x74, 0x65,
+ 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45,
+ 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ std::unique_ptr<NormalizedFile> f =
+ fromBinary(fileBytes, sizeof(fileBytes), "armv7");
+ EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_armv7);
+ EXPECT_EQ((int)(f->fileType), MH_OBJECT);
+ EXPECT_EQ((int)(f->flags), MH_SUBSECTIONS_VIA_SYMBOLS);
+ EXPECT_TRUE(f->localSymbols.empty());
+ EXPECT_TRUE(f->globalSymbols.empty());
+ EXPECT_TRUE(f->undefinedSymbols.empty());
+}
+
+TEST(BinaryReaderTest, empty_obj_x86_64_arm7) {
+ FILEBYTES = {
+#include "empty_obj_x86_armv7.txt"
+ };
+ std::unique_ptr<NormalizedFile> f =
+ fromBinary(fileBytes, sizeof(fileBytes), "x86_64");
+ EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86_64);
+ EXPECT_EQ((int)(f->fileType), MH_OBJECT);
+ EXPECT_EQ((int)(f->flags), MH_SUBSECTIONS_VIA_SYMBOLS);
+ EXPECT_TRUE(f->localSymbols.empty());
+ EXPECT_TRUE(f->globalSymbols.empty());
+ EXPECT_TRUE(f->undefinedSymbols.empty());
+
+ std::unique_ptr<NormalizedFile> f2 =
+ fromBinary(fileBytes, sizeof(fileBytes), "armv7");
+ EXPECT_EQ(f2->arch, lld::MachOLinkingContext::arch_armv7);
+ EXPECT_EQ((int)(f2->fileType), MH_OBJECT);
+ EXPECT_EQ((int)(f2->flags), MH_SUBSECTIONS_VIA_SYMBOLS);
+ EXPECT_TRUE(f2->localSymbols.empty());
+ EXPECT_TRUE(f2->globalSymbols.empty());
+ EXPECT_TRUE(f2->undefinedSymbols.empty());
+}
+
+TEST(BinaryReaderTest, hello_obj_x86_64) {
+ FILEBYTES = {
+ 0xCF, 0xFA, 0xED, 0xFE, 0x07, 0x00, 0x00, 0x01,
+ 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x50, 0x01, 0x00, 0x00,
+ 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x19, 0x00, 0x00, 0x00, 0xE8, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x70, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5F, 0x5F, 0x74, 0x65, 0x78, 0x74, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5F, 0x5F, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x70, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0xA4, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x04, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5F, 0x5F, 0x63, 0x73, 0x74, 0x72, 0x69, 0x6E,
+ 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5F, 0x5F, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9D, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0xB4, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0xE4, 0x01, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x0B, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x55, 0x48, 0x89, 0xE5, 0x48, 0x83, 0xEC, 0x10,
+ 0x48, 0x8D, 0x3D, 0x00, 0x00, 0x00, 0x00, 0xC7,
+ 0x45, 0xFC, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x00,
+ 0xE8, 0x00, 0x00, 0x00, 0x00, 0xB9, 0x00, 0x00,
+ 0x00, 0x00, 0x89, 0x45, 0xF8, 0x89, 0xC8, 0x48,
+ 0x83, 0xC4, 0x10, 0x5D, 0xC3, 0x68, 0x65, 0x6C,
+ 0x6C, 0x6F, 0x0A, 0x00, 0x19, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x2D, 0x0B, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1D, 0x0F, 0x00, 0x00, 0x00,
+ 0x0E, 0x02, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x0F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x6D, 0x61,
+ 0x69, 0x6E, 0x00, 0x5F, 0x70, 0x72, 0x69, 0x6E,
+ 0x74, 0x66, 0x00, 0x4C, 0x5F, 0x2E, 0x73, 0x74,
+ 0x72, 0x00, 0x00, 0x00 };
+ std::unique_ptr<NormalizedFile> f =
+ fromBinary(fileBytes, sizeof(fileBytes), "x86_64");
+
+ EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86_64);
+ EXPECT_EQ((int)(f->fileType), MH_OBJECT);
+ EXPECT_EQ((int)(f->flags), MH_SUBSECTIONS_VIA_SYMBOLS);
+ EXPECT_EQ(f->sections.size(), 2UL);
+ const Section& text = f->sections[0];
+ EXPECT_TRUE(text.segmentName.equals("__TEXT"));
+ EXPECT_TRUE(text.sectionName.equals("__text"));
+ EXPECT_EQ(text.type, S_REGULAR);
+ EXPECT_EQ(text.attributes,SectionAttr(S_ATTR_PURE_INSTRUCTIONS
+ | S_ATTR_SOME_INSTRUCTIONS));
+ EXPECT_EQ(text.alignment, 4U);
+ EXPECT_EQ(text.address, Hex64(0x0));
+ EXPECT_EQ(text.content.size(), 45UL);
+ EXPECT_EQ((int)(text.content[0]), 0x55);
+ EXPECT_EQ((int)(text.content[1]), 0x48);
+ EXPECT_TRUE(text.indirectSymbols.empty());
+ EXPECT_EQ(text.relocations.size(), 2UL);
+ const Relocation& call = text.relocations[0];
+ EXPECT_EQ(call.offset, Hex32(0x19));
+ EXPECT_EQ(call.type, X86_64_RELOC_BRANCH);
+ EXPECT_EQ(call.length, 2);
+ EXPECT_EQ(call.isExtern, true);
+ EXPECT_EQ(call.symbol, 2U);
+ const Relocation& str = text.relocations[1];
+ EXPECT_EQ(str.offset, Hex32(0xB));
+ EXPECT_EQ(str.type, X86_64_RELOC_SIGNED);
+ EXPECT_EQ(str.length, 2);
+ EXPECT_EQ(str.isExtern, true);
+ EXPECT_EQ(str.symbol, 0U);
+
+ const Section& cstring = f->sections[1];
+ EXPECT_TRUE(cstring.segmentName.equals("__TEXT"));
+ EXPECT_TRUE(cstring.sectionName.equals("__cstring"));
+ EXPECT_EQ(cstring.type, S_CSTRING_LITERALS);
+ EXPECT_EQ(cstring.attributes, SectionAttr(0));
+ EXPECT_EQ(cstring.alignment, 0U);
+ EXPECT_EQ(cstring.address, Hex64(0x02D));
+ EXPECT_EQ(cstring.content.size(), 7UL);
+ EXPECT_EQ((int)(cstring.content[0]), 0x68);
+ EXPECT_EQ((int)(cstring.content[1]), 0x65);
+ EXPECT_EQ((int)(cstring.content[2]), 0x6c);
+ EXPECT_TRUE(cstring.indirectSymbols.empty());
+ EXPECT_TRUE(cstring.relocations.empty());
+
+ EXPECT_EQ(f->localSymbols.size(), 1UL);
+ const Symbol& strLabel = f->localSymbols[0];
+ EXPECT_EQ(strLabel.type, N_SECT);
+ EXPECT_EQ(strLabel.sect, 2);
+ EXPECT_EQ(strLabel.value, Hex64(0x2D));
+ EXPECT_EQ(f->globalSymbols.size(), 1UL);
+ const Symbol& mainLabel = f->globalSymbols[0];
+ EXPECT_TRUE(mainLabel.name.equals("_main"));
+ EXPECT_EQ(mainLabel.type, N_SECT);
+ EXPECT_EQ(mainLabel.sect, 1);
+ EXPECT_EQ(mainLabel.scope, SymbolScope(N_EXT));
+ EXPECT_EQ(mainLabel.value, Hex64(0x0));
+ EXPECT_EQ(f->undefinedSymbols.size(), 1UL);
+ const Symbol& printfLabel = f->undefinedSymbols[0];
+ EXPECT_TRUE(printfLabel.name.equals("_printf"));
+ EXPECT_EQ(printfLabel.type, N_UNDF);
+ EXPECT_EQ(printfLabel.scope, SymbolScope(N_EXT));
+}
+
+
+TEST(BinaryReaderTest, hello_obj_x86) {
+ FILEBYTES = {
+ 0xCE, 0xFA, 0xED, 0xFE, 0x07, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00,
+ 0x00, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x37, 0x00, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00,
+ 0x37, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5F, 0x5F, 0x74, 0x65,
+ 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5F, 0x5F, 0x54, 0x45,
+ 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x7C, 0x01, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5F, 0x5F, 0x63, 0x73, 0x74, 0x72, 0x69, 0x6E,
+ 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5F, 0x5F, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x74, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x94, 0x01, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0xAC, 0x01, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,
+ 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x55, 0x89, 0xE5, 0x83,
+ 0xEC, 0x18, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x58,
+ 0x8D, 0x80, 0x25, 0x00, 0x00, 0x00, 0xC7, 0x45,
+ 0xFC, 0x00, 0x00, 0x00, 0x00, 0x89, 0x04, 0x24,
+ 0xE8, 0xDF, 0xFF, 0xFF, 0xFF, 0xB9, 0x00, 0x00,
+ 0x00, 0x00, 0x89, 0x45, 0xF8, 0x89, 0xC8, 0x83,
+ 0xC4, 0x18, 0x5D, 0xC3, 0x68, 0x65, 0x6C, 0x6C,
+ 0x6F, 0x0A, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x0D, 0x0E, 0x00, 0x00, 0xA4,
+ 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA1,
+ 0x0B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x0F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x6D, 0x61,
+ 0x69, 0x6E, 0x00, 0x5F, 0x70, 0x72, 0x69, 0x6E,
+ 0x74, 0x66, 0x00, 0x00
+ };
+ std::unique_ptr<NormalizedFile> f =
+ fromBinary(fileBytes, sizeof(fileBytes), "i386");
+
+ EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86);
+ EXPECT_EQ((int)(f->fileType), MH_OBJECT);
+ EXPECT_EQ((int)(f->flags), MH_SUBSECTIONS_VIA_SYMBOLS);
+ EXPECT_EQ(f->sections.size(), 2UL);
+ const Section& text = f->sections[0];
+ EXPECT_TRUE(text.segmentName.equals("__TEXT"));
+ EXPECT_TRUE(text.sectionName.equals("__text"));
+ EXPECT_EQ(text.type, S_REGULAR);
+ EXPECT_EQ(text.attributes,SectionAttr(S_ATTR_PURE_INSTRUCTIONS
+ | S_ATTR_SOME_INSTRUCTIONS));
+ EXPECT_EQ(text.alignment, 4U);
+ EXPECT_EQ(text.address, Hex64(0x0));
+ EXPECT_EQ(text.content.size(), 48UL);
+ EXPECT_EQ((int)(text.content[0]), 0x55);
+ EXPECT_EQ((int)(text.content[1]), 0x89);
+ EXPECT_TRUE(text.indirectSymbols.empty());
+ EXPECT_EQ(text.relocations.size(), 3UL);
+ const Relocation& call = text.relocations[0];
+ EXPECT_EQ(call.offset, Hex32(0x1D));
+ EXPECT_EQ(call.scattered, false);
+ EXPECT_EQ(call.type, GENERIC_RELOC_VANILLA);
+ EXPECT_EQ(call.pcRel, true);
+ EXPECT_EQ(call.length, 2);
+ EXPECT_EQ(call.isExtern, true);
+ EXPECT_EQ(call.symbol, 1U);
+ const Relocation& sectDiff = text.relocations[1];
+ EXPECT_EQ(sectDiff.offset, Hex32(0xE));
+ EXPECT_EQ(sectDiff.scattered, true);
+ EXPECT_EQ(sectDiff.type, GENERIC_RELOC_LOCAL_SECTDIFF);
+ EXPECT_EQ(sectDiff.pcRel, false);
+ EXPECT_EQ(sectDiff.length, 2);
+ EXPECT_EQ(sectDiff.value, 0x30U);
+ const Relocation& pair = text.relocations[2];
+ EXPECT_EQ(pair.offset, Hex32(0x0));
+ EXPECT_EQ(pair.scattered, true);
+ EXPECT_EQ(pair.type, GENERIC_RELOC_PAIR);
+ EXPECT_EQ(pair.pcRel, false);
+ EXPECT_EQ(pair.length, 2);
+ EXPECT_EQ(pair.value, 0x0BU);
+
+ const Section& cstring = f->sections[1];
+ EXPECT_TRUE(cstring.segmentName.equals("__TEXT"));
+ EXPECT_TRUE(cstring.sectionName.equals("__cstring"));
+ EXPECT_EQ(cstring.type, S_CSTRING_LITERALS);
+ EXPECT_EQ(cstring.attributes, SectionAttr(0));
+ EXPECT_EQ(cstring.alignment, 0U);
+ EXPECT_EQ(cstring.address, Hex64(0x030));
+ EXPECT_EQ(cstring.content.size(), 7UL);
+ EXPECT_EQ((int)(cstring.content[0]), 0x68);
+ EXPECT_EQ((int)(cstring.content[1]), 0x65);
+ EXPECT_EQ((int)(cstring.content[2]), 0x6c);
+ EXPECT_TRUE(cstring.indirectSymbols.empty());
+ EXPECT_TRUE(cstring.relocations.empty());
+
+ EXPECT_EQ(f->localSymbols.size(), 0UL);
+ EXPECT_EQ(f->globalSymbols.size(), 1UL);
+ const Symbol& mainLabel = f->globalSymbols[0];
+ EXPECT_TRUE(mainLabel.name.equals("_main"));
+ EXPECT_EQ(mainLabel.type, N_SECT);
+ EXPECT_EQ(mainLabel.sect, 1);
+ EXPECT_EQ(mainLabel.scope, SymbolScope(N_EXT));
+ EXPECT_EQ(mainLabel.value, Hex64(0x0));
+ EXPECT_EQ(f->undefinedSymbols.size(), 1UL);
+ const Symbol& printfLabel = f->undefinedSymbols[0];
+ EXPECT_TRUE(printfLabel.name.equals("_printf"));
+ EXPECT_EQ(printfLabel.type, N_UNDF);
+ EXPECT_EQ(printfLabel.scope, SymbolScope(N_EXT));
+}
+
+
+TEST(BinaryReaderTest, hello_obj_armv7) {
+ FILEBYTES = {
+ 0xCE, 0xFA, 0xED, 0xFE, 0x0C, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00,
+ 0x00, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x31, 0x00, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00,
+ 0x31, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5F, 0x5F, 0x74, 0x65,
+ 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5F, 0x5F, 0x54, 0x45,
+ 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x2A, 0x00, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x78, 0x01, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5F, 0x5F, 0x63, 0x73, 0x74, 0x72, 0x69, 0x6E,
+ 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5F, 0x5F, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x2A, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x6E, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0xA0, 0x01, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0xB8, 0x01, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,
+ 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x80, 0xB5, 0x6F, 0x46,
+ 0x82, 0xB0, 0x40, 0xF2, 0x18, 0x00, 0xC0, 0xF2,
+ 0x00, 0x00, 0x78, 0x44, 0x00, 0x21, 0xC0, 0xF2,
+ 0x00, 0x01, 0x01, 0x91, 0xFF, 0xF7, 0xF2, 0xFF,
+ 0x00, 0x21, 0xC0, 0xF2, 0x00, 0x01, 0x00, 0x90,
+ 0x08, 0x46, 0x02, 0xB0, 0x80, 0xBD, 0x68, 0x65,
+ 0x6C, 0x6C, 0x6F, 0x0A, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x6D,
+ 0x0A, 0x00, 0x00, 0xB9, 0x2A, 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x00, 0xB1, 0x0E, 0x00, 0x00, 0x00,
+ 0x06, 0x00, 0x00, 0xA9, 0x2A, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xA1, 0x0E, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x0F, 0x01, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x5F, 0x6D, 0x61, 0x69, 0x6E, 0x00, 0x5F,
+ 0x70, 0x72, 0x69, 0x6E, 0x74, 0x66, 0x00, 0x00
+ };
+ std::unique_ptr<NormalizedFile> f =
+ fromBinary(fileBytes, sizeof(fileBytes), "armv7");
+
+ EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_armv7);
+ EXPECT_EQ((int)(f->fileType), MH_OBJECT);
+ EXPECT_EQ((int)(f->flags), MH_SUBSECTIONS_VIA_SYMBOLS);
+ EXPECT_EQ(f->sections.size(), 2UL);
+ const Section& text = f->sections[0];
+ EXPECT_TRUE(text.segmentName.equals("__TEXT"));
+ EXPECT_TRUE(text.sectionName.equals("__text"));
+ EXPECT_EQ(text.type, S_REGULAR);
+ EXPECT_EQ(text.attributes,SectionAttr(S_ATTR_PURE_INSTRUCTIONS
+ | S_ATTR_SOME_INSTRUCTIONS));
+ EXPECT_EQ(text.alignment, 2U);
+ EXPECT_EQ(text.address, Hex64(0x0));
+ EXPECT_EQ(text.content.size(), 42UL);
+ EXPECT_EQ((int)(text.content[0]), 0x80);
+ EXPECT_EQ((int)(text.content[1]), 0xB5);
+ EXPECT_TRUE(text.indirectSymbols.empty());
+ EXPECT_EQ(text.relocations.size(), 5UL);
+ const Relocation& call = text.relocations[0];
+ EXPECT_EQ(call.offset, Hex32(0x18));
+ EXPECT_EQ(call.scattered, false);
+ EXPECT_EQ(call.type, ARM_THUMB_RELOC_BR22);
+ EXPECT_EQ(call.length, 2);
+ EXPECT_EQ(call.isExtern, true);
+ EXPECT_EQ(call.symbol, 1U);
+ const Relocation& movt = text.relocations[1];
+ EXPECT_EQ(movt.offset, Hex32(0xA));
+ EXPECT_EQ(movt.scattered, true);
+ EXPECT_EQ(movt.type, ARM_RELOC_HALF_SECTDIFF);
+ EXPECT_EQ(movt.length, 3);
+ EXPECT_EQ(movt.value, Hex32(0x2A));
+ const Relocation& movtPair = text.relocations[2];
+ EXPECT_EQ(movtPair.offset, Hex32(0x18));
+ EXPECT_EQ(movtPair.scattered, true);
+ EXPECT_EQ(movtPair.type, ARM_RELOC_PAIR);
+ EXPECT_EQ(movtPair.length, 3);
+ EXPECT_EQ(movtPair.value, Hex32(0xE));
+ const Relocation& movw = text.relocations[3];
+ EXPECT_EQ(movw.offset, Hex32(0x6));
+ EXPECT_EQ(movw.scattered, true);
+ EXPECT_EQ(movw.type, ARM_RELOC_HALF_SECTDIFF);
+ EXPECT_EQ(movw.length, 2);
+ EXPECT_EQ(movw.value, Hex32(0x2A));
+ const Relocation& movwPair = text.relocations[4];
+ EXPECT_EQ(movwPair.offset, Hex32(0x0));
+ EXPECT_EQ(movwPair.scattered, true);
+ EXPECT_EQ(movwPair.type, ARM_RELOC_PAIR);
+ EXPECT_EQ(movwPair.length, 2);
+ EXPECT_EQ(movwPair.value, Hex32(0xE));
+
+ const Section& cstring = f->sections[1];
+ EXPECT_TRUE(cstring.segmentName.equals("__TEXT"));
+ EXPECT_TRUE(cstring.sectionName.equals("__cstring"));
+ EXPECT_EQ(cstring.type, S_CSTRING_LITERALS);
+ EXPECT_EQ(cstring.attributes, SectionAttr(0));
+ EXPECT_EQ(cstring.alignment, 0U);
+ EXPECT_EQ(cstring.address, Hex64(0x02A));
+ EXPECT_EQ(cstring.content.size(), 7UL);
+ EXPECT_EQ((int)(cstring.content[0]), 0x68);
+ EXPECT_EQ((int)(cstring.content[1]), 0x65);
+ EXPECT_EQ((int)(cstring.content[2]), 0x6c);
+ EXPECT_TRUE(cstring.indirectSymbols.empty());
+ EXPECT_TRUE(cstring.relocations.empty());
+
+ EXPECT_EQ(f->localSymbols.size(), 0UL);
+ EXPECT_EQ(f->globalSymbols.size(), 1UL);
+ const Symbol& mainLabel = f->globalSymbols[0];
+ EXPECT_TRUE(mainLabel.name.equals("_main"));
+ EXPECT_EQ(mainLabel.type, N_SECT);
+ EXPECT_EQ(mainLabel.sect, 1);
+ EXPECT_EQ(mainLabel.scope, SymbolScope(N_EXT));
+ EXPECT_EQ(mainLabel.value, Hex64(0x0));
+ EXPECT_EQ(f->undefinedSymbols.size(), 1UL);
+ const Symbol& printfLabel = f->undefinedSymbols[0];
+ EXPECT_TRUE(printfLabel.name.equals("_printf"));
+ EXPECT_EQ(printfLabel.type, N_UNDF);
+ EXPECT_EQ(printfLabel.scope, SymbolScope(N_EXT));
+}
+
+
+TEST(BinaryReaderTest, hello_obj_ppc) {
+ FILEBYTES = {
+ 0xFE, 0xED, 0xFA, 0xCE, 0x00, 0x00, 0x00, 0x12,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0x28,
+ 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x4B, 0x00, 0x00, 0x01, 0x44,
+ 0x00, 0x00, 0x00, 0x4B, 0x00, 0x00, 0x00, 0x07,
+ 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x00, 0x5F, 0x5F, 0x74, 0x65,
+ 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5F, 0x5F, 0x54, 0x45,
+ 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x01, 0x44,
+ 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x90,
+ 0x00, 0x00, 0x00, 0x05, 0x80, 0x00, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5F, 0x5F, 0x63, 0x73, 0x74, 0x72, 0x69, 0x6E,
+ 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5F, 0x5F, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x07,
+ 0x00, 0x00, 0x01, 0x88, 0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x01, 0xB8,
+ 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0xD0,
+ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0B,
+ 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7C, 0x08, 0x02, 0xA6,
+ 0xBF, 0xC1, 0xFF, 0xF8, 0x90, 0x01, 0x00, 0x08,
+ 0x94, 0x21, 0xFF, 0xB0, 0x7C, 0x3E, 0x0B, 0x78,
+ 0x42, 0x9F, 0x00, 0x05, 0x7F, 0xE8, 0x02, 0xA6,
+ 0x3C, 0x5F, 0x00, 0x00, 0x38, 0x62, 0x00, 0x2C,
+ 0x4B, 0xFF, 0xFF, 0xDD, 0x38, 0x00, 0x00, 0x00,
+ 0x7C, 0x03, 0x03, 0x78, 0x80, 0x21, 0x00, 0x00,
+ 0x80, 0x01, 0x00, 0x08, 0x7C, 0x08, 0x03, 0xA6,
+ 0xBB, 0xC1, 0xFF, 0xF8, 0x4E, 0x80, 0x00, 0x20,
+ 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x01, 0xD3,
+ 0xAB, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x44,
+ 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
+ 0xAC, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x44,
+ 0xA1, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x18,
+ 0x00, 0x00, 0x00, 0x01, 0x0F, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x5F, 0x6D, 0x61, 0x69, 0x6E, 0x00, 0x5F,
+ 0x70, 0x72, 0x69, 0x6E, 0x74, 0x66, 0x00, 0x00
+ };
+ std::unique_ptr<NormalizedFile> f =
+ fromBinary(fileBytes, sizeof(fileBytes), "ppc");
+
+ EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_ppc);
+ EXPECT_EQ((int)(f->fileType), MH_OBJECT);
+ EXPECT_EQ((int)(f->flags), MH_SUBSECTIONS_VIA_SYMBOLS);
+ EXPECT_EQ(f->sections.size(), 2UL);
+ const Section& text = f->sections[0];
+ EXPECT_TRUE(text.segmentName.equals("__TEXT"));
+ EXPECT_TRUE(text.sectionName.equals("__text"));
+ EXPECT_EQ(text.type, S_REGULAR);
+ EXPECT_EQ(text.attributes,SectionAttr(S_ATTR_PURE_INSTRUCTIONS
+ | S_ATTR_SOME_INSTRUCTIONS));
+ EXPECT_EQ(text.alignment, 2U);
+ EXPECT_EQ(text.address, Hex64(0x0));
+ EXPECT_EQ(text.content.size(), 68UL);
+ EXPECT_EQ((int)(text.content[0]), 0x7C);
+ EXPECT_EQ((int)(text.content[1]), 0x08);
+ EXPECT_TRUE(text.indirectSymbols.empty());
+ EXPECT_EQ(text.relocations.size(), 5UL);
+ const Relocation& bl = text.relocations[0];
+ EXPECT_EQ(bl.offset, Hex32(0x24));
+ EXPECT_EQ(bl.type, PPC_RELOC_BR24);
+ EXPECT_EQ(bl.length, 2);
+ EXPECT_EQ(bl.isExtern, true);
+ EXPECT_EQ(bl.symbol, 1U);
+ const Relocation& lo = text.relocations[1];
+ EXPECT_EQ(lo.offset, Hex32(0x20));
+ EXPECT_EQ(lo.scattered, true);
+ EXPECT_EQ(lo.type, PPC_RELOC_LO16_SECTDIFF);
+ EXPECT_EQ(lo.length, 2);
+ EXPECT_EQ(lo.value, Hex32(0x44));
+ const Relocation& loPair = text.relocations[2];
+ EXPECT_EQ(loPair.offset, Hex32(0x0));
+ EXPECT_EQ(loPair.scattered, true);
+ EXPECT_EQ(loPair.type, PPC_RELOC_PAIR);
+ EXPECT_EQ(loPair.length, 2);
+ EXPECT_EQ(loPair.value, Hex32(0x18));
+ const Relocation& ha = text.relocations[3];
+ EXPECT_EQ(ha.offset, Hex32(0x1C));
+ EXPECT_EQ(ha.scattered, true);
+ EXPECT_EQ(ha.type, PPC_RELOC_HA16_SECTDIFF);
+ EXPECT_EQ(ha.length, 2);
+ EXPECT_EQ(ha.value, Hex32(0x44));
+ const Relocation& haPair = text.relocations[4];
+ EXPECT_EQ(haPair.offset, Hex32(0x2c));
+ EXPECT_EQ(haPair.scattered, true);
+ EXPECT_EQ(haPair.type, PPC_RELOC_PAIR);
+ EXPECT_EQ(haPair.length, 2);
+ EXPECT_EQ(haPair.value, Hex32(0x18));
+
+ const Section& cstring = f->sections[1];
+ EXPECT_TRUE(cstring.segmentName.equals("__TEXT"));
+ EXPECT_TRUE(cstring.sectionName.equals("__cstring"));
+ EXPECT_EQ(cstring.type, S_CSTRING_LITERALS);
+ EXPECT_EQ(cstring.attributes, SectionAttr(0));
+ EXPECT_EQ(cstring.alignment, 2U);
+ EXPECT_EQ(cstring.address, Hex64(0x044));
+ EXPECT_EQ(cstring.content.size(), 7UL);
+ EXPECT_EQ((int)(cstring.content[0]), 0x68);
+ EXPECT_EQ((int)(cstring.content[1]), 0x65);
+ EXPECT_EQ((int)(cstring.content[2]), 0x6c);
+ EXPECT_TRUE(cstring.indirectSymbols.empty());
+ EXPECT_TRUE(cstring.relocations.empty());
+
+ EXPECT_EQ(f->localSymbols.size(), 0UL);
+ EXPECT_EQ(f->globalSymbols.size(), 1UL);
+ const Symbol& mainLabel = f->globalSymbols[0];
+ EXPECT_TRUE(mainLabel.name.equals("_main"));
+ EXPECT_EQ(mainLabel.type, N_SECT);
+ EXPECT_EQ(mainLabel.sect, 1);
+ EXPECT_EQ(mainLabel.scope, SymbolScope(N_EXT));
+ EXPECT_EQ(mainLabel.value, Hex64(0x0));
+ EXPECT_EQ(f->undefinedSymbols.size(), 1UL);
+ const Symbol& printfLabel = f->undefinedSymbols[0];
+ EXPECT_TRUE(printfLabel.name.equals("_printf"));
+ EXPECT_EQ(printfLabel.type, N_UNDF);
+ EXPECT_EQ(printfLabel.scope, SymbolScope(N_EXT));
+
+ writeBinary(*f, "/tmp/foo.o");
+
+}
diff --git a/unittests/MachOTests/MachONormalizedFileBinaryWriterTests.cpp b/unittests/MachOTests/MachONormalizedFileBinaryWriterTests.cpp
new file mode 100644
index 000000000000..d79c6d62a847
--- /dev/null
+++ b/unittests/MachOTests/MachONormalizedFileBinaryWriterTests.cpp
@@ -0,0 +1,693 @@
+//===- lld/unittest/MachOTests/MachONormalizedFileBinaryWriterTests.cpp ---===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+#include "../../lib/ReaderWriter/MachO/MachONormalizedFile.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MachO.h"
+#include <cassert>
+#include <memory>
+#include <system_error>
+#include <vector>
+
+using llvm::StringRef;
+using llvm::MemoryBuffer;
+using llvm::SmallString;
+using llvm::Twine;
+using llvm::ErrorOr;
+using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
+
+// Parses binary mach-o file at specified path and returns
+// ownership of buffer to mb parameter and ownership of
+// Normalized file to nf parameter.
+static void fromBinary(StringRef path, std::unique_ptr<MemoryBuffer> &mb,
+ std::unique_ptr<NormalizedFile> &nf, StringRef archStr) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> mbOrErr = MemoryBuffer::getFile(path);
+ std::error_code ec = mbOrErr.getError();
+ EXPECT_FALSE(ec);
+ mb = std::move(mbOrErr.get());
+
+ ErrorOr<std::unique_ptr<NormalizedFile>> r =
+ lld::mach_o::normalized::readBinary(
+ mb, lld::MachOLinkingContext::archFromName(archStr));
+ EXPECT_FALSE(!r);
+ nf.reset(r->release());
+}
+
+static Relocation
+makeReloc(unsigned addr, bool rel, bool ext, RelocationInfoType type,
+ unsigned sym) {
+ Relocation result;
+ result.offset = addr;
+ result.scattered = false;
+ result.type = type;
+ result.length = 2;
+ result.pcRel = rel;
+ result.isExtern = ext;
+ result.value = 0;
+ result.symbol = sym;
+ return result;
+}
+
+static Relocation
+makeScatReloc(unsigned addr, RelocationInfoType type, unsigned value) {
+ Relocation result;
+ result.offset = addr;
+ result.scattered = true;
+ result.type = type;
+ result.length = 2;
+ result.pcRel = false;
+ result.isExtern = true;
+ result.value = value;
+ result.symbol = 0;
+ return result;
+}
+
+static Symbol
+makeUndefSymbol(StringRef name) {
+ Symbol sym;
+ sym.name = name;
+ sym.type = N_UNDF;
+ sym.scope = N_EXT;
+ sym.sect = NO_SECT;
+ sym.desc = 0;
+ sym.value = 0;
+ return sym;
+}
+
+
+static Symbol
+makeSymbol(StringRef name, unsigned addr) {
+ Symbol sym;
+ sym.name = name;
+ sym.type = N_SECT;
+ sym.scope = N_EXT;
+ sym.sect = 1;
+ sym.desc = 0;
+ sym.value = addr;
+ return sym;
+}
+
+static Symbol
+makeThumbSymbol(StringRef name, unsigned addr) {
+ Symbol sym;
+ sym.name = name;
+ sym.type = N_SECT;
+ sym.scope = N_EXT;
+ sym.sect = 1;
+ sym.desc = N_ARM_THUMB_DEF;
+ sym.value = addr;
+ return sym;
+}
+
+TEST(BinaryWriterTest, obj_relocs_x86_64) {
+ SmallString<128> tmpFl;
+ {
+ NormalizedFile f;
+ f.arch = lld::MachOLinkingContext::arch_x86_64;
+ f.fileType = MH_OBJECT;
+ f.flags = MH_SUBSECTIONS_VIA_SYMBOLS;
+ f.os = lld::MachOLinkingContext::OS::macOSX;
+ f.sections.resize(1);
+ Section& text = f.sections.front();
+ text.segmentName = "__TEXT";
+ text.sectionName = "__text";
+ text.type = S_REGULAR;
+ text.attributes = SectionAttr(S_ATTR_PURE_INSTRUCTIONS
+ | S_ATTR_SOME_INSTRUCTIONS);
+ text.alignment = 4;
+ text.address = 0;
+ const uint8_t textBytes[] = {
+ 0xe8, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x05,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x35, 0x00, 0x00,
+ 0x00, 0x00, 0x8b, 0x05, 0x00, 0x00, 0x00, 0x00,
+ 0xc6, 0x05, 0xff, 0xff, 0xff, 0xff, 0x12, 0xc7,
+ 0x05, 0xfc, 0xff, 0xff, 0xff, 0x78, 0x56, 0x34,
+ 0x12, 0x48, 0x8b, 0x3d, 0x00, 0x00, 0x00, 0x00 };
+
+ text.content = llvm::makeArrayRef(textBytes, sizeof(textBytes));
+ text.relocations.push_back(makeReloc(0x01, false, true, X86_64_RELOC_BRANCH, 1));
+ text.relocations.push_back(makeReloc(0x08, false, true, X86_64_RELOC_GOT_LOAD, 1));
+ text.relocations.push_back(makeReloc(0x0E, false, true, X86_64_RELOC_GOT, 1));
+ text.relocations.push_back(makeReloc(0x14, false, true, X86_64_RELOC_SIGNED, 1));
+ text.relocations.push_back(makeReloc(0x1A, false, true, X86_64_RELOC_SIGNED_1, 1));
+ text.relocations.push_back(makeReloc(0x21, false, true, X86_64_RELOC_SIGNED_4, 1));
+ text.relocations.push_back(makeReloc(0x2C, false, true, X86_64_RELOC_TLV, 2));
+
+ f.undefinedSymbols.push_back(makeUndefSymbol("_bar"));
+ f.undefinedSymbols.push_back(makeUndefSymbol("_tbar"));
+
+ std::error_code ec =
+ llvm::sys::fs::createTemporaryFile(Twine("xx"), "o", tmpFl);
+ EXPECT_FALSE(ec);
+ ec = writeBinary(f, tmpFl);
+ EXPECT_FALSE(ec);
+ }
+
+ std::unique_ptr<MemoryBuffer> bufferOwner;
+ std::unique_ptr<NormalizedFile> f2;
+ fromBinary(tmpFl, bufferOwner, f2, "x86_64");
+
+ EXPECT_EQ(lld::MachOLinkingContext::arch_x86_64, f2->arch);
+ EXPECT_EQ(MH_OBJECT, f2->fileType);
+ EXPECT_EQ(FileFlags(MH_SUBSECTIONS_VIA_SYMBOLS), f2->flags);
+
+ EXPECT_TRUE(f2->localSymbols.empty());
+ EXPECT_TRUE(f2->globalSymbols.empty());
+ EXPECT_EQ(2UL, f2->undefinedSymbols.size());
+ const Symbol& barUndef = f2->undefinedSymbols[0];
+ EXPECT_TRUE(barUndef.name.equals("_bar"));
+ EXPECT_EQ(N_UNDF, barUndef.type);
+ EXPECT_EQ(SymbolScope(N_EXT), barUndef.scope);
+ const Symbol& tbarUndef = f2->undefinedSymbols[1];
+ EXPECT_TRUE(tbarUndef.name.equals("_tbar"));
+ EXPECT_EQ(N_UNDF, tbarUndef.type);
+ EXPECT_EQ(SymbolScope(N_EXT), tbarUndef.scope);
+
+ EXPECT_EQ(1UL, f2->sections.size());
+ const Section& text = f2->sections[0];
+ EXPECT_TRUE(text.segmentName.equals("__TEXT"));
+ EXPECT_TRUE(text.sectionName.equals("__text"));
+ EXPECT_EQ(S_REGULAR, text.type);
+ EXPECT_EQ(text.attributes,SectionAttr(S_ATTR_PURE_INSTRUCTIONS
+ | S_ATTR_SOME_INSTRUCTIONS));
+ EXPECT_EQ(text.alignment, 4U);
+ EXPECT_EQ(text.address, Hex64(0x0));
+ EXPECT_EQ(48UL, text.content.size());
+ const Relocation& call = text.relocations[0];
+ EXPECT_EQ(call.offset, Hex32(0x1));
+ EXPECT_EQ(call.type, X86_64_RELOC_BRANCH);
+ EXPECT_EQ(call.length, 2);
+ EXPECT_EQ(call.isExtern, true);
+ EXPECT_EQ(call.symbol, 1U);
+ const Relocation& gotLoad = text.relocations[1];
+ EXPECT_EQ(gotLoad.offset, Hex32(0x8));
+ EXPECT_EQ(gotLoad.type, X86_64_RELOC_GOT_LOAD);
+ EXPECT_EQ(gotLoad.length, 2);
+ EXPECT_EQ(gotLoad.isExtern, true);
+ EXPECT_EQ(gotLoad.symbol, 1U);
+ const Relocation& gotUse = text.relocations[2];
+ EXPECT_EQ(gotUse.offset, Hex32(0xE));
+ EXPECT_EQ(gotUse.type, X86_64_RELOC_GOT);
+ EXPECT_EQ(gotUse.length, 2);
+ EXPECT_EQ(gotUse.isExtern, true);
+ EXPECT_EQ(gotUse.symbol, 1U);
+ const Relocation& signed0 = text.relocations[3];
+ EXPECT_EQ(signed0.offset, Hex32(0x14));
+ EXPECT_EQ(signed0.type, X86_64_RELOC_SIGNED);
+ EXPECT_EQ(signed0.length, 2);
+ EXPECT_EQ(signed0.isExtern, true);
+ EXPECT_EQ(signed0.symbol, 1U);
+ const Relocation& signed1 = text.relocations[4];
+ EXPECT_EQ(signed1.offset, Hex32(0x1A));
+ EXPECT_EQ(signed1.type, X86_64_RELOC_SIGNED_1);
+ EXPECT_EQ(signed1.length, 2);
+ EXPECT_EQ(signed1.isExtern, true);
+ EXPECT_EQ(signed1.symbol, 1U);
+ const Relocation& signed4 = text.relocations[5];
+ EXPECT_EQ(signed4.offset, Hex32(0x21));
+ EXPECT_EQ(signed4.type, X86_64_RELOC_SIGNED_4);
+ EXPECT_EQ(signed4.length, 2);
+ EXPECT_EQ(signed4.isExtern, true);
+ EXPECT_EQ(signed4.symbol, 1U);
+
+ std::error_code ec = llvm::sys::fs::remove(Twine(tmpFl));
+ EXPECT_FALSE(ec);
+}
+
+
+
+TEST(BinaryWriterTest, obj_relocs_x86) {
+ SmallString<128> tmpFl;
+ {
+ NormalizedFile f;
+ f.arch = lld::MachOLinkingContext::arch_x86;
+ f.fileType = MH_OBJECT;
+ f.flags = MH_SUBSECTIONS_VIA_SYMBOLS;
+ f.os = lld::MachOLinkingContext::OS::macOSX;
+ f.sections.resize(1);
+ Section& text = f.sections.front();
+ text.segmentName = "__TEXT";
+ text.sectionName = "__text";
+ text.type = S_REGULAR;
+ text.attributes = SectionAttr(S_ATTR_PURE_INSTRUCTIONS
+ | S_ATTR_SOME_INSTRUCTIONS);
+ text.alignment = 4;
+ text.address = 0;
+ const uint8_t textBytes[] = {
+ 0xe8, 0xfb, 0xff, 0xff, 0xff, 0xa1, 0x00, 0x00,
+ 0x00, 0x00, 0x8b, 0xb0, 0xfb, 0xff, 0xff, 0xff,
+ 0x8b, 0x80, 0x11, 0x00, 0x00, 0x00 };
+
+ text.content = llvm::makeArrayRef(textBytes, sizeof(textBytes));
+ text.relocations.push_back(makeReloc(0x01, true, true, GENERIC_RELOC_VANILLA, 0));
+ text.relocations.push_back(makeReloc(0x06, false, true, GENERIC_RELOC_VANILLA, 0));
+ text.relocations.push_back(makeScatReloc(0x0c, GENERIC_RELOC_LOCAL_SECTDIFF, 0));
+ text.relocations.push_back(makeScatReloc(0x0, GENERIC_RELOC_PAIR, 5));
+ text.relocations.push_back(makeReloc(0x12, true, true, GENERIC_RELOC_TLV, 1));
+
+ f.undefinedSymbols.push_back(makeUndefSymbol("_bar"));
+ f.undefinedSymbols.push_back(makeUndefSymbol("_tbar"));
+
+ std::error_code ec =
+ llvm::sys::fs::createTemporaryFile(Twine("xx"), "o", tmpFl);
+ EXPECT_FALSE(ec);
+ ec = writeBinary(f, tmpFl);
+ EXPECT_FALSE(ec);
+ }
+ std::unique_ptr<MemoryBuffer> bufferOwner;
+ std::unique_ptr<NormalizedFile> f2;
+ fromBinary(tmpFl, bufferOwner, f2, "i386");
+
+ EXPECT_EQ(lld::MachOLinkingContext::arch_x86, f2->arch);
+ EXPECT_EQ(MH_OBJECT, f2->fileType);
+ EXPECT_EQ(FileFlags(MH_SUBSECTIONS_VIA_SYMBOLS), f2->flags);
+
+ EXPECT_TRUE(f2->localSymbols.empty());
+ EXPECT_TRUE(f2->globalSymbols.empty());
+ EXPECT_EQ(2UL, f2->undefinedSymbols.size());
+ const Symbol& barUndef = f2->undefinedSymbols[0];
+ EXPECT_TRUE(barUndef.name.equals("_bar"));
+ EXPECT_EQ(N_UNDF, barUndef.type);
+ EXPECT_EQ(SymbolScope(N_EXT), barUndef.scope);
+ const Symbol& tbarUndef = f2->undefinedSymbols[1];
+ EXPECT_TRUE(tbarUndef.name.equals("_tbar"));
+ EXPECT_EQ(N_UNDF, tbarUndef.type);
+ EXPECT_EQ(SymbolScope(N_EXT), tbarUndef.scope);
+
+ EXPECT_EQ(1UL, f2->sections.size());
+ const Section& text = f2->sections[0];
+ EXPECT_TRUE(text.segmentName.equals("__TEXT"));
+ EXPECT_TRUE(text.sectionName.equals("__text"));
+ EXPECT_EQ(S_REGULAR, text.type);
+ EXPECT_EQ(text.attributes,SectionAttr(S_ATTR_PURE_INSTRUCTIONS
+ | S_ATTR_SOME_INSTRUCTIONS));
+ EXPECT_EQ(text.alignment, 4U);
+ EXPECT_EQ(text.address, Hex64(0x0));
+ EXPECT_EQ(22UL, text.content.size());
+ const Relocation& call = text.relocations[0];
+ EXPECT_EQ(call.offset, Hex32(0x1));
+ EXPECT_EQ(call.scattered, false);
+ EXPECT_EQ(call.type, GENERIC_RELOC_VANILLA);
+ EXPECT_EQ(call.pcRel, true);
+ EXPECT_EQ(call.length, 2);
+ EXPECT_EQ(call.isExtern, true);
+ EXPECT_EQ(call.symbol, 0U);
+ const Relocation& absLoad = text.relocations[1];
+ EXPECT_EQ(absLoad.offset, Hex32(0x6));
+ EXPECT_EQ(absLoad.scattered, false);
+ EXPECT_EQ(absLoad.type, GENERIC_RELOC_VANILLA);
+ EXPECT_EQ(absLoad.pcRel, false);
+ EXPECT_EQ(absLoad.length, 2);
+ EXPECT_EQ(absLoad.isExtern, true);
+ EXPECT_EQ(absLoad.symbol,0U);
+ const Relocation& pic1 = text.relocations[2];
+ EXPECT_EQ(pic1.offset, Hex32(0xc));
+ EXPECT_EQ(pic1.scattered, true);
+ EXPECT_EQ(pic1.type, GENERIC_RELOC_LOCAL_SECTDIFF);
+ EXPECT_EQ(pic1.length, 2);
+ EXPECT_EQ(pic1.value, 0U);
+ const Relocation& pic2 = text.relocations[3];
+ EXPECT_EQ(pic2.offset, Hex32(0x0));
+ EXPECT_EQ(pic1.scattered, true);
+ EXPECT_EQ(pic2.type, GENERIC_RELOC_PAIR);
+ EXPECT_EQ(pic2.length, 2);
+ EXPECT_EQ(pic2.value, 5U);
+ const Relocation& tlv = text.relocations[4];
+ EXPECT_EQ(tlv.offset, Hex32(0x12));
+ EXPECT_EQ(tlv.type, GENERIC_RELOC_TLV);
+ EXPECT_EQ(tlv.length, 2);
+ EXPECT_EQ(tlv.isExtern, true);
+ EXPECT_EQ(tlv.symbol, 1U);
+
+ //llvm::errs() << "temp = " << tmpFl << "\n";
+ std::error_code ec = llvm::sys::fs::remove(Twine(tmpFl));
+ EXPECT_FALSE(ec);
+}
+
+
+
+TEST(BinaryWriterTest, obj_relocs_armv7) {
+ SmallString<128> tmpFl;
+ {
+ NormalizedFile f;
+ f.arch = lld::MachOLinkingContext::arch_armv7;
+ f.fileType = MH_OBJECT;
+ f.flags = MH_SUBSECTIONS_VIA_SYMBOLS;
+ f.os = lld::MachOLinkingContext::OS::macOSX;
+ f.sections.resize(1);
+ Section& text = f.sections.front();
+ text.segmentName = "__TEXT";
+ text.sectionName = "__text";
+ text.type = S_REGULAR;
+ text.attributes = SectionAttr(S_ATTR_PURE_INSTRUCTIONS
+ | S_ATTR_SOME_INSTRUCTIONS);
+ text.alignment = 2;
+ text.address = 0;
+ const uint8_t textBytes[] = {
+ 0xff, 0xf7, 0xfe, 0xef, 0x40, 0xf2, 0x05, 0x01,
+ 0xc0, 0xf2, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xbf };
+
+ text.content = llvm::makeArrayRef(textBytes, sizeof(textBytes));
+ text.relocations.push_back(makeReloc(0x00, true, true,
+ ARM_THUMB_RELOC_BR22, 2));
+ text.relocations.push_back(makeScatReloc(0x04,
+ ARM_RELOC_HALF_SECTDIFF, 0x10));
+ text.relocations.push_back(makeScatReloc(0x00,
+ ARM_RELOC_PAIR, 0xC));
+ text.relocations.push_back(makeScatReloc(0x08,
+ ARM_RELOC_HALF_SECTDIFF, 0x10));
+ text.relocations.push_back(makeScatReloc(0x00,
+ ARM_RELOC_PAIR, 0xC));
+ text.relocations.push_back(makeReloc(0x0C, false, true,
+ ARM_RELOC_VANILLA, 2));
+
+ f.globalSymbols.push_back(makeThumbSymbol("_foo", 0x00));
+ f.globalSymbols.push_back(makeThumbSymbol("_foo2", 0x10));
+ f.undefinedSymbols.push_back(makeUndefSymbol("_bar"));
+
+ std::error_code ec =
+ llvm::sys::fs::createTemporaryFile(Twine("xx"), "o", tmpFl);
+ EXPECT_FALSE(ec);
+ ec = writeBinary(f, tmpFl);
+ EXPECT_FALSE(ec);
+ }
+ std::unique_ptr<MemoryBuffer> bufferOwner;
+ std::unique_ptr<NormalizedFile> f2;
+ fromBinary(tmpFl, bufferOwner, f2, "armv7");
+
+ EXPECT_EQ(lld::MachOLinkingContext::arch_armv7, f2->arch);
+ EXPECT_EQ(MH_OBJECT, f2->fileType);
+ EXPECT_EQ(FileFlags(MH_SUBSECTIONS_VIA_SYMBOLS), f2->flags);
+
+ EXPECT_TRUE(f2->localSymbols.empty());
+ EXPECT_EQ(2UL, f2->globalSymbols.size());
+ const Symbol& fooDef = f2->globalSymbols[0];
+ EXPECT_TRUE(fooDef.name.equals("_foo"));
+ EXPECT_EQ(N_SECT, fooDef.type);
+ EXPECT_EQ(1, fooDef.sect);
+ EXPECT_EQ(SymbolScope(N_EXT), fooDef.scope);
+ const Symbol& foo2Def = f2->globalSymbols[1];
+ EXPECT_TRUE(foo2Def.name.equals("_foo2"));
+ EXPECT_EQ(N_SECT, foo2Def.type);
+ EXPECT_EQ(1, foo2Def.sect);
+ EXPECT_EQ(SymbolScope(N_EXT), foo2Def.scope);
+
+ EXPECT_EQ(1UL, f2->undefinedSymbols.size());
+ const Symbol& barUndef = f2->undefinedSymbols[0];
+ EXPECT_TRUE(barUndef.name.equals("_bar"));
+ EXPECT_EQ(N_UNDF, barUndef.type);
+ EXPECT_EQ(SymbolScope(N_EXT), barUndef.scope);
+
+ EXPECT_EQ(1UL, f2->sections.size());
+ const Section& text = f2->sections[0];
+ EXPECT_TRUE(text.segmentName.equals("__TEXT"));
+ EXPECT_TRUE(text.sectionName.equals("__text"));
+ EXPECT_EQ(S_REGULAR, text.type);
+ EXPECT_EQ(text.attributes,SectionAttr(S_ATTR_PURE_INSTRUCTIONS
+ | S_ATTR_SOME_INSTRUCTIONS));
+ EXPECT_EQ(text.alignment, 2U);
+ EXPECT_EQ(text.address, Hex64(0x0));
+ EXPECT_EQ(18UL, text.content.size());
+ const Relocation& blx = text.relocations[0];
+ EXPECT_EQ(blx.offset, Hex32(0x0));
+ EXPECT_EQ(blx.scattered, false);
+ EXPECT_EQ(blx.type, ARM_THUMB_RELOC_BR22);
+ EXPECT_EQ(blx.pcRel, true);
+ EXPECT_EQ(blx.length, 2);
+ EXPECT_EQ(blx.isExtern, true);
+ EXPECT_EQ(blx.symbol, 2U);
+ const Relocation& movw1 = text.relocations[1];
+ EXPECT_EQ(movw1.offset, Hex32(0x4));
+ EXPECT_EQ(movw1.scattered, true);
+ EXPECT_EQ(movw1.type, ARM_RELOC_HALF_SECTDIFF);
+ EXPECT_EQ(movw1.length, 2);
+ EXPECT_EQ(movw1.value, 0x10U);
+ const Relocation& movw2 = text.relocations[2];
+ EXPECT_EQ(movw2.offset, Hex32(0x0));
+ EXPECT_EQ(movw2.scattered, true);
+ EXPECT_EQ(movw2.type, ARM_RELOC_PAIR);
+ EXPECT_EQ(movw2.length, 2);
+ EXPECT_EQ(movw2.value, Hex32(0xC));
+ const Relocation& movt1 = text.relocations[3];
+ EXPECT_EQ(movt1.offset, Hex32(0x8));
+ EXPECT_EQ(movt1.scattered, true);
+ EXPECT_EQ(movt1.type, ARM_RELOC_HALF_SECTDIFF);
+ EXPECT_EQ(movt1.length, 2);
+ EXPECT_EQ(movt1.value, Hex32(0x10));
+ const Relocation& movt2 = text.relocations[4];
+ EXPECT_EQ(movt2.offset, Hex32(0x0));
+ EXPECT_EQ(movt2.scattered, true);
+ EXPECT_EQ(movt2.type, ARM_RELOC_PAIR);
+ EXPECT_EQ(movt2.length, 2);
+ EXPECT_EQ(movt2.value, Hex32(0xC));
+ const Relocation& absPointer = text.relocations[5];
+ EXPECT_EQ(absPointer.offset, Hex32(0xC));
+ EXPECT_EQ(absPointer.type, ARM_RELOC_VANILLA);
+ EXPECT_EQ(absPointer.length, 2);
+ EXPECT_EQ(absPointer.isExtern, true);
+ EXPECT_EQ(absPointer.symbol, 2U);
+
+ //llvm::errs() << "temp = " << tmpFl << "\n";
+ std::error_code ec = llvm::sys::fs::remove(Twine(tmpFl));
+ EXPECT_FALSE(ec);
+}
+
+
+
+TEST(BinaryWriterTest, obj_relocs_ppc) {
+ SmallString<128> tmpFl;
+ {
+ NormalizedFile f;
+ f.arch = lld::MachOLinkingContext::arch_ppc;
+ f.fileType = MH_OBJECT;
+ f.flags = MH_SUBSECTIONS_VIA_SYMBOLS;
+ f.os = lld::MachOLinkingContext::OS::macOSX;
+ f.sections.resize(1);
+ Section& text = f.sections.front();
+ text.segmentName = "__TEXT";
+ text.sectionName = "__text";
+ text.type = S_REGULAR;
+ text.attributes = SectionAttr(S_ATTR_PURE_INSTRUCTIONS
+ | S_ATTR_SOME_INSTRUCTIONS);
+ text.alignment = 2;
+ text.address = 0;
+ const uint8_t textBytes[] = {
+ 0x48, 0x00, 0x00, 0x01, 0x40, 0x82, 0xff, 0xfc,
+ 0x3c, 0x62, 0x00, 0x00, 0x3c, 0x62, 0x00, 0x00,
+ 0x80, 0x63, 0x00, 0x24, 0x80, 0x63, 0x00, 0x24,
+ 0x3c, 0x40, 0x00, 0x00, 0x3c, 0x60, 0x00, 0x00,
+ 0x80, 0x42, 0x00, 0x28, 0x80, 0x63, 0x00, 0x28,
+ 0x60, 0x00, 0x00, 0x00 };
+
+ text.content = llvm::makeArrayRef(textBytes, sizeof(textBytes));
+ text.relocations.push_back(makeReloc(0x00, true, true,
+ PPC_RELOC_BR24, 2));
+ text.relocations.push_back(makeReloc(0x04, true, true,
+ PPC_RELOC_BR14, 2));
+ text.relocations.push_back(makeScatReloc(0x08,
+ PPC_RELOC_HI16_SECTDIFF, 0x28));
+ text.relocations.push_back(makeScatReloc(0x24,
+ PPC_RELOC_PAIR, 0x4));
+ text.relocations.push_back(makeScatReloc(0x0C,
+ PPC_RELOC_HA16_SECTDIFF, 0x28));
+ text.relocations.push_back(makeScatReloc(0x24,
+ PPC_RELOC_PAIR, 0x4));
+ text.relocations.push_back(makeScatReloc(0x10,
+ PPC_RELOC_LO16_SECTDIFF, 0x28));
+ text.relocations.push_back(makeScatReloc(0x00,
+ PPC_RELOC_PAIR, 0x4));
+ text.relocations.push_back(makeScatReloc(0x14,
+ PPC_RELOC_LO14_SECTDIFF, 0x28));
+ text.relocations.push_back(makeScatReloc(0x00,
+ PPC_RELOC_PAIR, 0x4));
+ text.relocations.push_back(makeReloc(0x18, false, false,
+ PPC_RELOC_HI16, 1));
+ text.relocations.push_back(makeReloc(0x28, false, false,
+ PPC_RELOC_PAIR, 0));
+ text.relocations.push_back(makeReloc(0x1C, false, false,
+ PPC_RELOC_HA16, 1));
+ text.relocations.push_back(makeReloc(0x28, false, false,
+ PPC_RELOC_PAIR, 0));
+ text.relocations.push_back(makeReloc(0x20, false, false,
+ PPC_RELOC_LO16, 1));
+ text.relocations.push_back(makeReloc(0x00, false, false,
+ PPC_RELOC_PAIR, 0));
+ text.relocations.push_back(makeReloc(0x24, false, false,
+ PPC_RELOC_LO14, 1));
+ text.relocations.push_back(makeReloc(0x00, false, false,
+ PPC_RELOC_PAIR, 0));
+
+ f.globalSymbols.push_back(makeSymbol("_foo", 0x00));
+ f.globalSymbols.push_back(makeSymbol("_foo2", 0x28));
+ f.undefinedSymbols.push_back(makeUndefSymbol("_bar"));
+
+ std::error_code ec =
+ llvm::sys::fs::createTemporaryFile(Twine("xx"), "o", tmpFl);
+ EXPECT_FALSE(ec);
+ ec = writeBinary(f, tmpFl);
+ EXPECT_FALSE(ec);
+ }
+ std::unique_ptr<MemoryBuffer> bufferOwner;
+ std::unique_ptr<NormalizedFile> f2;
+ fromBinary(tmpFl, bufferOwner, f2, "ppc");
+
+ EXPECT_EQ(lld::MachOLinkingContext::arch_ppc, f2->arch);
+ EXPECT_EQ(MH_OBJECT, f2->fileType);
+ EXPECT_EQ(FileFlags(MH_SUBSECTIONS_VIA_SYMBOLS), f2->flags);
+
+ EXPECT_TRUE(f2->localSymbols.empty());
+ EXPECT_EQ(2UL, f2->globalSymbols.size());
+ const Symbol& fooDef = f2->globalSymbols[0];
+ EXPECT_TRUE(fooDef.name.equals("_foo"));
+ EXPECT_EQ(N_SECT, fooDef.type);
+ EXPECT_EQ(1, fooDef.sect);
+ EXPECT_EQ(SymbolScope(N_EXT), fooDef.scope);
+ const Symbol& foo2Def = f2->globalSymbols[1];
+ EXPECT_TRUE(foo2Def.name.equals("_foo2"));
+ EXPECT_EQ(N_SECT, foo2Def.type);
+ EXPECT_EQ(1, foo2Def.sect);
+ EXPECT_EQ(SymbolScope(N_EXT), foo2Def.scope);
+
+ EXPECT_EQ(1UL, f2->undefinedSymbols.size());
+ const Symbol& barUndef = f2->undefinedSymbols[0];
+ EXPECT_TRUE(barUndef.name.equals("_bar"));
+ EXPECT_EQ(N_UNDF, barUndef.type);
+ EXPECT_EQ(SymbolScope(N_EXT), barUndef.scope);
+
+ EXPECT_EQ(1UL, f2->sections.size());
+ const Section& text = f2->sections[0];
+ EXPECT_TRUE(text.segmentName.equals("__TEXT"));
+ EXPECT_TRUE(text.sectionName.equals("__text"));
+ EXPECT_EQ(S_REGULAR, text.type);
+ EXPECT_EQ(text.attributes,SectionAttr(S_ATTR_PURE_INSTRUCTIONS
+ | S_ATTR_SOME_INSTRUCTIONS));
+ EXPECT_EQ(text.alignment, 2U);
+ EXPECT_EQ(text.address, Hex64(0x0));
+ EXPECT_EQ(44UL, text.content.size());
+ const Relocation& br24 = text.relocations[0];
+ EXPECT_EQ(br24.offset, Hex32(0x0));
+ EXPECT_EQ(br24.scattered, false);
+ EXPECT_EQ(br24.type, PPC_RELOC_BR24);
+ EXPECT_EQ(br24.pcRel, true);
+ EXPECT_EQ(br24.length, 2);
+ EXPECT_EQ(br24.isExtern, true);
+ EXPECT_EQ(br24.symbol, 2U);
+ const Relocation& br14 = text.relocations[1];
+ EXPECT_EQ(br14.offset, Hex32(0x4));
+ EXPECT_EQ(br14.scattered, false);
+ EXPECT_EQ(br14.type, PPC_RELOC_BR14);
+ EXPECT_EQ(br14.pcRel, true);
+ EXPECT_EQ(br14.length, 2);
+ EXPECT_EQ(br14.isExtern, true);
+ EXPECT_EQ(br14.symbol, 2U);
+ const Relocation& pichi1 = text.relocations[2];
+ EXPECT_EQ(pichi1.offset, Hex32(0x8));
+ EXPECT_EQ(pichi1.scattered, true);
+ EXPECT_EQ(pichi1.type, PPC_RELOC_HI16_SECTDIFF);
+ EXPECT_EQ(pichi1.length, 2);
+ EXPECT_EQ(pichi1.value, 0x28U);
+ const Relocation& pichi2 = text.relocations[3];
+ EXPECT_EQ(pichi2.offset, Hex32(0x24));
+ EXPECT_EQ(pichi2.scattered, true);
+ EXPECT_EQ(pichi2.type, PPC_RELOC_PAIR);
+ EXPECT_EQ(pichi2.length, 2);
+ EXPECT_EQ(pichi2.value, 0x4U);
+ const Relocation& picha1 = text.relocations[4];
+ EXPECT_EQ(picha1.offset, Hex32(0xC));
+ EXPECT_EQ(picha1.scattered, true);
+ EXPECT_EQ(picha1.type, PPC_RELOC_HA16_SECTDIFF);
+ EXPECT_EQ(picha1.length, 2);
+ EXPECT_EQ(picha1.value, 0x28U);
+ const Relocation& picha2 = text.relocations[5];
+ EXPECT_EQ(picha2.offset, Hex32(0x24));
+ EXPECT_EQ(picha2.scattered, true);
+ EXPECT_EQ(picha2.type, PPC_RELOC_PAIR);
+ EXPECT_EQ(picha2.length, 2);
+ EXPECT_EQ(picha2.value, 0x4U);
+ const Relocation& piclo1 = text.relocations[6];
+ EXPECT_EQ(piclo1.offset, Hex32(0x10));
+ EXPECT_EQ(piclo1.scattered, true);
+ EXPECT_EQ(piclo1.type, PPC_RELOC_LO16_SECTDIFF);
+ EXPECT_EQ(piclo1.length, 2);
+ EXPECT_EQ(piclo1.value, 0x28U);
+ const Relocation& piclo2 = text.relocations[7];
+ EXPECT_EQ(piclo2.offset, Hex32(0x0));
+ EXPECT_EQ(piclo2.scattered, true);
+ EXPECT_EQ(piclo2.type, PPC_RELOC_PAIR);
+ EXPECT_EQ(piclo2.length, 2);
+ EXPECT_EQ(piclo2.value, 0x4U);
+ const Relocation& picloa1 = text.relocations[8];
+ EXPECT_EQ(picloa1.offset, Hex32(0x14));
+ EXPECT_EQ(picloa1.scattered, true);
+ EXPECT_EQ(picloa1.type, PPC_RELOC_LO14_SECTDIFF);
+ EXPECT_EQ(picloa1.length, 2);
+ EXPECT_EQ(picloa1.value, 0x28U);
+ const Relocation& picloa2 = text.relocations[9];
+ EXPECT_EQ(picloa2.offset, Hex32(0x0));
+ EXPECT_EQ(picloa2.scattered, true);
+ EXPECT_EQ(picloa2.type, PPC_RELOC_PAIR);
+ EXPECT_EQ(picloa2.length, 2);
+ EXPECT_EQ(picloa2.value, 0x4U);
+ const Relocation& abshi1 = text.relocations[10];
+ EXPECT_EQ(abshi1.offset, Hex32(0x18));
+ EXPECT_EQ(abshi1.scattered, false);
+ EXPECT_EQ(abshi1.type, PPC_RELOC_HI16);
+ EXPECT_EQ(abshi1.length, 2);
+ EXPECT_EQ(abshi1.symbol, 1U);
+ const Relocation& abshi2 = text.relocations[11];
+ EXPECT_EQ(abshi2.offset, Hex32(0x28));
+ EXPECT_EQ(abshi2.scattered, false);
+ EXPECT_EQ(abshi2.type, PPC_RELOC_PAIR);
+ EXPECT_EQ(abshi2.length, 2);
+ EXPECT_EQ(abshi2.symbol, 0U);
+ const Relocation& absha1 = text.relocations[12];
+ EXPECT_EQ(absha1.offset, Hex32(0x1C));
+ EXPECT_EQ(absha1.scattered, false);
+ EXPECT_EQ(absha1.type, PPC_RELOC_HA16);
+ EXPECT_EQ(absha1.length, 2);
+ EXPECT_EQ(absha1.symbol, 1U);
+ const Relocation& absha2 = text.relocations[13];
+ EXPECT_EQ(absha2.offset, Hex32(0x28));
+ EXPECT_EQ(absha2.scattered, false);
+ EXPECT_EQ(absha2.type, PPC_RELOC_PAIR);
+ EXPECT_EQ(absha2.length, 2);
+ EXPECT_EQ(absha2.symbol, 0U);
+ const Relocation& abslo1 = text.relocations[14];
+ EXPECT_EQ(abslo1.offset, Hex32(0x20));
+ EXPECT_EQ(abslo1.scattered, false);
+ EXPECT_EQ(abslo1.type, PPC_RELOC_LO16);
+ EXPECT_EQ(abslo1.length, 2);
+ EXPECT_EQ(abslo1.symbol, 1U);
+ const Relocation& abslo2 = text.relocations[15];
+ EXPECT_EQ(abslo2.offset, Hex32(0x00));
+ EXPECT_EQ(abslo2.scattered, false);
+ EXPECT_EQ(abslo2.type, PPC_RELOC_PAIR);
+ EXPECT_EQ(abslo2.length, 2);
+ EXPECT_EQ(abslo2.symbol, 0U);
+ const Relocation& absloa1 = text.relocations[16];
+ EXPECT_EQ(absloa1.offset, Hex32(0x24));
+ EXPECT_EQ(absloa1.scattered, false);
+ EXPECT_EQ(absloa1.type, PPC_RELOC_LO14);
+ EXPECT_EQ(absloa1.length, 2);
+ EXPECT_EQ(absloa1.symbol, 1U);
+ const Relocation& absloa2 = text.relocations[17];
+ EXPECT_EQ(absloa2.offset, Hex32(0x00));
+ EXPECT_EQ(absloa2.scattered, false);
+ EXPECT_EQ(absloa2.type, PPC_RELOC_PAIR);
+ EXPECT_EQ(absloa2.length, 2);
+ EXPECT_EQ(absloa2.symbol, 0U);
+
+ std::error_code ec = llvm::sys::fs::remove(Twine(tmpFl));
+ EXPECT_FALSE(ec);
+}
+
diff --git a/unittests/MachOTests/MachONormalizedFileToAtomsTests.cpp b/unittests/MachOTests/MachONormalizedFileToAtomsTests.cpp
new file mode 100644
index 000000000000..16ef88aa4a40
--- /dev/null
+++ b/unittests/MachOTests/MachONormalizedFileToAtomsTests.cpp
@@ -0,0 +1,94 @@
+//===- lld/unittest/MachOTests/MachONormalizedFileToAtomsTests.cpp --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+#include "../../lib/ReaderWriter/MachO/MachONormalizedFile.h"
+#include "llvm/Support/MachO.h"
+#include <assert.h>
+#include <vector>
+
+using llvm::ErrorOr;
+
+using namespace lld::mach_o::normalized;
+using namespace llvm::MachO;
+
+TEST(ToAtomsTest, empty_obj_x86_64) {
+ NormalizedFile f;
+ f.arch = lld::MachOLinkingContext::arch_x86_64;
+ ErrorOr<std::unique_ptr<const lld::File>> atom_f =
+ normalizedToAtoms(f, "", false);
+ EXPECT_FALSE(!atom_f);
+ EXPECT_EQ(0U, (*atom_f)->defined().size());
+}
+
+TEST(ToAtomsTest, basic_obj_x86_64) {
+ NormalizedFile f;
+ f.arch = lld::MachOLinkingContext::arch_x86_64;
+ Section textSection;
+ static const uint8_t contentBytes[] = { 0x90, 0xC3, 0xC3, 0xC4 };
+ const unsigned contentSize = sizeof(contentBytes) / sizeof(contentBytes[0]);
+ textSection.content = llvm::makeArrayRef(contentBytes, contentSize);
+ f.sections.push_back(textSection);
+ Symbol fooSymbol;
+ fooSymbol.name = "_foo";
+ fooSymbol.type = N_SECT;
+ fooSymbol.scope = N_EXT;
+ fooSymbol.sect = 1;
+ fooSymbol.value = 0;
+ f.globalSymbols.push_back(fooSymbol);
+ Symbol barSymbol;
+ barSymbol.name = "_bar";
+ barSymbol.type = N_SECT;
+ barSymbol.scope = N_EXT;
+ barSymbol.sect = 1;
+ barSymbol.value = 2;
+ f.globalSymbols.push_back(barSymbol);
+ Symbol undefSym;
+ undefSym.name = "_undef";
+ undefSym.type = N_UNDF;
+ f.undefinedSymbols.push_back(undefSym);
+ Symbol bazSymbol;
+ bazSymbol.name = "_baz";
+ bazSymbol.type = N_SECT;
+ bazSymbol.scope = N_EXT | N_PEXT;
+ bazSymbol.sect = 1;
+ bazSymbol.value = 3;
+ f.localSymbols.push_back(bazSymbol);
+
+ ErrorOr<std::unique_ptr<const lld::File>> atom_f =
+ normalizedToAtoms(f, "", false);
+ EXPECT_FALSE(!atom_f);
+ const lld::File &file = **atom_f;
+ EXPECT_EQ(3U, file.defined().size());
+ lld::File::defined_iterator it = file.defined().begin();
+ const lld::DefinedAtom *atom1 = *it;
+ ++it;
+ const lld::DefinedAtom *atom2 = *it;
+ ++it;
+ const lld::DefinedAtom *atom3 = *it;
+ const lld::UndefinedAtom *atom4 = *file.undefined().begin();
+ EXPECT_TRUE(atom1->name().equals("_foo"));
+ EXPECT_EQ(2U, atom1->rawContent().size());
+ EXPECT_EQ(0x90, atom1->rawContent()[0]);
+ EXPECT_EQ(0xC3, atom1->rawContent()[1]);
+ EXPECT_EQ(lld::Atom::scopeGlobal, atom1->scope());
+
+ EXPECT_TRUE(atom2->name().equals("_bar"));
+ EXPECT_EQ(1U, atom2->rawContent().size());
+ EXPECT_EQ(0xC3, atom2->rawContent()[0]);
+ EXPECT_EQ(lld::Atom::scopeGlobal, atom2->scope());
+
+ EXPECT_TRUE(atom3->name().equals("_baz"));
+ EXPECT_EQ(1U, atom3->rawContent().size());
+ EXPECT_EQ(0xC4, atom3->rawContent()[0]);
+ EXPECT_EQ(lld::Atom::scopeLinkageUnit, atom3->scope());
+
+ EXPECT_TRUE(atom4->name().equals("_undef"));
+ EXPECT_EQ(lld::Atom::definitionUndefined, atom4->definition());
+}
diff --git a/unittests/MachOTests/MachONormalizedFileYAMLTests.cpp b/unittests/MachOTests/MachONormalizedFileYAMLTests.cpp
new file mode 100644
index 000000000000..562dae60049d
--- /dev/null
+++ b/unittests/MachOTests/MachONormalizedFileYAMLTests.cpp
@@ -0,0 +1,766 @@
+//===- lld/unittest/MachOTests/MachONormalizedFileYAMLTests.cpp -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+#include "../../lib/ReaderWriter/MachO/MachONormalizedFile.h"
+#include "llvm/Support/MachO.h"
+#include <assert.h>
+#include <vector>
+
+using llvm::StringRef;
+using llvm::MemoryBuffer;
+using llvm::ErrorOr;
+using lld::mach_o::normalized::NormalizedFile;
+using lld::mach_o::normalized::Symbol;
+using lld::mach_o::normalized::Section;
+using lld::mach_o::normalized::Relocation;
+
+
+static std::unique_ptr<NormalizedFile> fromYAML(StringRef str) {
+ std::unique_ptr<MemoryBuffer> mb(MemoryBuffer::getMemBuffer(str));
+ ErrorOr<std::unique_ptr<NormalizedFile>> r
+ = lld::mach_o::normalized::readYaml(mb);
+ EXPECT_FALSE(!r);
+ return std::move(*r);
+}
+
+static void toYAML(const NormalizedFile &f, std::string &out) {
+ llvm::raw_string_ostream ostr(out);
+ std::error_code ec = lld::mach_o::normalized::writeYaml(f, ostr);
+ EXPECT_TRUE(!ec);
+}
+
+
+// ppc is no longer supported, but it is here to test endianness handling.
+TEST(ObjectFileYAML, empty_ppc) {
+ std::unique_ptr<NormalizedFile> f = fromYAML(
+ "---\n"
+ "arch: ppc\n"
+ "file-type: MH_OBJECT\n"
+ "flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]\n"
+ "...\n");
+ EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_ppc);
+ EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+ EXPECT_EQ((int)(f->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+ EXPECT_TRUE(f->sections.empty());
+ EXPECT_TRUE(f->localSymbols.empty());
+ EXPECT_TRUE(f->globalSymbols.empty());
+ EXPECT_TRUE(f->undefinedSymbols.empty());
+}
+
+TEST(ObjectFileYAML, empty_x86_64) {
+ std::unique_ptr<NormalizedFile> f = fromYAML(
+ "---\n"
+ "arch: x86_64\n"
+ "file-type: MH_OBJECT\n"
+ "flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]\n"
+ "...\n");
+ EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86_64);
+ EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+ EXPECT_EQ((int)(f->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+ EXPECT_TRUE(f->sections.empty());
+ EXPECT_TRUE(f->localSymbols.empty());
+ EXPECT_TRUE(f->globalSymbols.empty());
+ EXPECT_TRUE(f->undefinedSymbols.empty());
+}
+
+TEST(ObjectFileYAML, empty_x86) {
+ std::unique_ptr<NormalizedFile> f = fromYAML(
+ "---\n"
+ "arch: x86\n"
+ "file-type: MH_OBJECT\n"
+ "flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]\n"
+ "...\n");
+ EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86);
+ EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+ EXPECT_EQ((int)(f->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+ EXPECT_TRUE(f->sections.empty());
+ EXPECT_TRUE(f->localSymbols.empty());
+ EXPECT_TRUE(f->globalSymbols.empty());
+ EXPECT_TRUE(f->undefinedSymbols.empty());
+}
+
+TEST(ObjectFileYAML, empty_armv6) {
+ std::unique_ptr<NormalizedFile> f = fromYAML(
+ "---\n"
+ "arch: armv6\n"
+ "file-type: MH_OBJECT\n"
+ "flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]\n"
+ "...\n");
+ EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_armv6);
+ EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+ EXPECT_EQ((int)(f->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+ EXPECT_TRUE(f->sections.empty());
+ EXPECT_TRUE(f->localSymbols.empty());
+ EXPECT_TRUE(f->globalSymbols.empty());
+ EXPECT_TRUE(f->undefinedSymbols.empty());
+}
+
+TEST(ObjectFileYAML, empty_armv7) {
+ std::unique_ptr<NormalizedFile> f = fromYAML(
+ "---\n"
+ "arch: armv7\n"
+ "file-type: MH_OBJECT\n"
+ "flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]\n"
+ "...\n");
+ EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_armv7);
+ EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+ EXPECT_EQ((int)(f->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+ EXPECT_TRUE(f->sections.empty());
+ EXPECT_TRUE(f->localSymbols.empty());
+ EXPECT_TRUE(f->globalSymbols.empty());
+ EXPECT_TRUE(f->undefinedSymbols.empty());
+}
+
+TEST(ObjectFileYAML, empty_armv7s) {
+ std::unique_ptr<NormalizedFile> f = fromYAML(
+ "---\n"
+ "arch: armv7s\n"
+ "file-type: MH_OBJECT\n"
+ "flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]\n"
+ "...\n");
+ EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_armv7s);
+ EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+ EXPECT_EQ((int)(f->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+ EXPECT_TRUE(f->sections.empty());
+ EXPECT_TRUE(f->localSymbols.empty());
+ EXPECT_TRUE(f->globalSymbols.empty());
+ EXPECT_TRUE(f->undefinedSymbols.empty());
+}
+
+
+TEST(ObjectFileYAML, roundTrip) {
+ std::string intermediate;
+ {
+ NormalizedFile f;
+ f.arch = lld::MachOLinkingContext::arch_x86_64;
+ f.fileType = llvm::MachO::MH_OBJECT;
+ f.flags = llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS;
+ f.os = lld::MachOLinkingContext::OS::macOSX;
+ toYAML(f, intermediate);
+ }
+ {
+ std::unique_ptr<NormalizedFile> f2 = fromYAML(intermediate);
+ EXPECT_EQ(f2->arch, lld::MachOLinkingContext::arch_x86_64);
+ EXPECT_EQ((int)(f2->fileType), llvm::MachO::MH_OBJECT);
+ EXPECT_EQ((int)(f2->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+ EXPECT_TRUE(f2->sections.empty());
+ EXPECT_TRUE(f2->localSymbols.empty());
+ EXPECT_TRUE(f2->globalSymbols.empty());
+ EXPECT_TRUE(f2->undefinedSymbols.empty());
+ }
+}
+
+
+TEST(ObjectFileYAML, oneSymbol) {
+ std::unique_ptr<NormalizedFile> f = fromYAML(
+ "---\n"
+ "arch: x86_64\n"
+ "file-type: MH_OBJECT\n"
+ "global-symbols:\n"
+ " - name: _main\n"
+ " type: N_SECT\n"
+ " scope: [ N_EXT ]\n"
+ " sect: 1\n"
+ " desc: [ ]\n"
+ " value: 0x100\n"
+ "...\n");
+ EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86_64);
+ EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+ EXPECT_TRUE(f->sections.empty());
+ EXPECT_TRUE(f->localSymbols.empty());
+ EXPECT_TRUE(f->undefinedSymbols.empty());
+ EXPECT_EQ(f->globalSymbols.size(), 1UL);
+ const Symbol& sym = f->globalSymbols[0];
+ EXPECT_TRUE(sym.name.equals("_main"));
+ EXPECT_EQ((int)(sym.type), llvm::MachO::N_SECT);
+ EXPECT_EQ((int)(sym.scope), llvm::MachO::N_EXT);
+ EXPECT_EQ(sym.sect, 1);
+ EXPECT_EQ((int)(sym.desc), 0);
+ EXPECT_EQ((uint64_t)sym.value, 0x100ULL);
+}
+
+
+TEST(ObjectFileYAML, oneSection) {
+ std::unique_ptr<NormalizedFile> f = fromYAML(
+ "---\n"
+ "arch: x86_64\n"
+ "file-type: MH_OBJECT\n"
+ "sections:\n"
+ " - segment: __TEXT\n"
+ " section: __text\n"
+ " type: S_REGULAR\n"
+ " attributes: [ S_ATTR_PURE_INSTRUCTIONS ]\n"
+ " alignment: 1\n"
+ " address: 0x12345678\n"
+ " content: [ 0x90, 0x90 ]\n"
+ "...\n");
+ EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86_64);
+ EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+ EXPECT_TRUE(f->localSymbols.empty());
+ EXPECT_TRUE(f->globalSymbols.empty());
+ EXPECT_TRUE(f->undefinedSymbols.empty());
+ EXPECT_EQ(f->sections.size(), 1UL);
+ const Section& sect = f->sections[0];
+ EXPECT_TRUE(sect.segmentName.equals("__TEXT"));
+ EXPECT_TRUE(sect.sectionName.equals("__text"));
+ EXPECT_EQ((uint32_t)(sect.type), (uint32_t)(llvm::MachO::S_REGULAR));
+ EXPECT_EQ((uint32_t)(sect.attributes),
+ (uint32_t)(llvm::MachO::S_ATTR_PURE_INSTRUCTIONS));
+ EXPECT_EQ(sect.alignment, 1U);
+ EXPECT_EQ((uint64_t)sect.address, 0x12345678ULL);
+ EXPECT_EQ(sect.content.size(), 2UL);
+ EXPECT_EQ((int)(sect.content[0]), 0x90);
+ EXPECT_EQ((int)(sect.content[1]), 0x90);
+}
+
+
+TEST(ObjectFileYAML, hello_x86_64) {
+ std::unique_ptr<NormalizedFile> f = fromYAML(
+ "---\n"
+ "arch: x86_64\n"
+ "file-type: MH_OBJECT\n"
+ "flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]\n"
+ "sections:\n"
+ " - segment: __TEXT\n"
+ " section: __text\n"
+ " type: S_REGULAR\n"
+ " attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS]\n"
+ " alignment: 0\n"
+ " address: 0x0000\n"
+ " content: [ 0x55, 0x48, 0x89, 0xe5, 0x48, 0x8d, 0x3d, 0x00,\n"
+ " 0x00, 0x00, 0x00, 0x30, 0xc0, 0xe8, 0x00, 0x00,\n"
+ " 0x00, 0x00, 0x31, 0xc0, 0x5d, 0xc3 ]\n"
+ " relocations:\n"
+ " - offset: 0x0e\n"
+ " type: X86_64_RELOC_BRANCH\n"
+ " length: 2\n"
+ " pc-rel: true\n"
+ " extern: true\n"
+ " symbol: 2\n"
+ " - offset: 0x07\n"
+ " type: X86_64_RELOC_SIGNED\n"
+ " length: 2\n"
+ " pc-rel: true\n"
+ " extern: true\n"
+ " symbol: 1\n"
+ " - segment: __TEXT\n"
+ " section: __cstring\n"
+ " type: S_CSTRING_LITERALS\n"
+ " attributes: [ ]\n"
+ " alignment: 0\n"
+ " address: 0x0016\n"
+ " content: [ 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x0a, 0x00 ]\n"
+ "global-symbols:\n"
+ " - name: _main\n"
+ " type: N_SECT\n"
+ " scope: [ N_EXT ]\n"
+ " sect: 1\n"
+ " value: 0x0\n"
+ "local-symbols:\n"
+ " - name: L_.str\n"
+ " type: N_SECT\n"
+ " scope: [ ]\n"
+ " sect: 2\n"
+ " value: 0x16\n"
+ "undefined-symbols:\n"
+ " - name: _printf\n"
+ " type: N_UNDF\n"
+ " value: 0x0\n"
+ "...\n");
+ EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86_64);
+ EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+ EXPECT_EQ((int)(f->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+ EXPECT_EQ(f->sections.size(), 2UL);
+
+ const Section& sect1 = f->sections[0];
+ EXPECT_TRUE(sect1.segmentName.equals("__TEXT"));
+ EXPECT_TRUE(sect1.sectionName.equals("__text"));
+ EXPECT_EQ((uint32_t)(sect1.type), (uint32_t)(llvm::MachO::S_REGULAR));
+ EXPECT_EQ((uint32_t)(sect1.attributes),
+ (uint32_t)(llvm::MachO::S_ATTR_PURE_INSTRUCTIONS
+ | llvm::MachO::S_ATTR_SOME_INSTRUCTIONS));
+ EXPECT_EQ(sect1.alignment, 0U);
+ EXPECT_EQ((uint64_t)sect1.address, 0x0ULL);
+ EXPECT_EQ(sect1.content.size(), 22UL);
+ EXPECT_EQ((int)(sect1.content[0]), 0x55);
+ EXPECT_EQ((int)(sect1.content[1]), 0x48);
+ EXPECT_EQ(sect1.relocations.size(), 2UL);
+ const Relocation& reloc1 = sect1.relocations[0];
+ EXPECT_EQ(reloc1.offset, 0x0eU);
+ EXPECT_FALSE(reloc1.scattered);
+ EXPECT_EQ((int)reloc1.type, (int)llvm::MachO::X86_64_RELOC_BRANCH);
+ EXPECT_EQ(reloc1.length, 2);
+ EXPECT_TRUE(reloc1.pcRel);
+ EXPECT_TRUE(reloc1.isExtern);
+ EXPECT_EQ(reloc1.symbol, 2U);
+ EXPECT_EQ((int)(reloc1.value), 0);
+ const Relocation& reloc2 = sect1.relocations[1];
+ EXPECT_EQ(reloc2.offset, 0x07U);
+ EXPECT_FALSE(reloc2.scattered);
+ EXPECT_EQ((int)reloc2.type, (int)llvm::MachO::X86_64_RELOC_SIGNED);
+ EXPECT_EQ(reloc2.length, 2);
+ EXPECT_TRUE(reloc2.pcRel);
+ EXPECT_TRUE(reloc2.isExtern);
+ EXPECT_EQ(reloc2.symbol, 1U);
+ EXPECT_EQ((int)(reloc2.value), 0);
+
+ const Section& sect2 = f->sections[1];
+ EXPECT_TRUE(sect2.segmentName.equals("__TEXT"));
+ EXPECT_TRUE(sect2.sectionName.equals("__cstring"));
+ EXPECT_EQ((uint32_t)(sect2.type), (uint32_t)(llvm::MachO::S_CSTRING_LITERALS));
+ EXPECT_EQ((uint32_t)(sect2.attributes), 0U);
+ EXPECT_EQ(sect2.alignment, 0U);
+ EXPECT_EQ((uint64_t)sect2.address, 0x016ULL);
+ EXPECT_EQ(sect2.content.size(), 7UL);
+ EXPECT_EQ((int)(sect2.content[0]), 0x68);
+ EXPECT_EQ((int)(sect2.content[1]), 0x65);
+ EXPECT_EQ((int)(sect2.content[2]), 0x6c);
+
+ EXPECT_EQ(f->globalSymbols.size(), 1UL);
+ const Symbol& sym1 = f->globalSymbols[0];
+ EXPECT_TRUE(sym1.name.equals("_main"));
+ EXPECT_EQ((int)(sym1.type), llvm::MachO::N_SECT);
+ EXPECT_EQ((int)(sym1.scope), llvm::MachO::N_EXT);
+ EXPECT_EQ(sym1.sect, 1);
+ EXPECT_EQ((int)(sym1.desc), 0);
+ EXPECT_EQ((uint64_t)sym1.value, 0x0ULL);
+ EXPECT_EQ(f->localSymbols.size(), 1UL);
+ const Symbol& sym2 = f->localSymbols[0];
+ EXPECT_TRUE(sym2.name.equals("L_.str"));
+ EXPECT_EQ((int)(sym2.type), llvm::MachO::N_SECT);
+ EXPECT_EQ((int)(sym2.scope), 0);
+ EXPECT_EQ(sym2.sect, 2);
+ EXPECT_EQ((int)(sym2.desc), 0);
+ EXPECT_EQ((uint64_t)sym2.value, 0x16ULL);
+ EXPECT_EQ(f->undefinedSymbols.size(), 1UL);
+ const Symbol& sym3 = f->undefinedSymbols[0];
+ EXPECT_TRUE(sym3.name.equals("_printf"));
+ EXPECT_EQ((int)(sym3.type), llvm::MachO::N_UNDF);
+ EXPECT_EQ((int)(sym3.scope), 0);
+ EXPECT_EQ(sym3.sect, 0);
+ EXPECT_EQ((int)(sym3.desc), 0);
+ EXPECT_EQ((uint64_t)sym3.value, 0x0ULL);
+}
+
+
+TEST(ObjectFileYAML, hello_x86) {
+ std::unique_ptr<NormalizedFile> f = fromYAML(
+ "---\n"
+ "arch: x86\n"
+ "file-type: MH_OBJECT\n"
+ "flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]\n"
+ "sections:\n"
+ " - segment: __TEXT\n"
+ " section: __text\n"
+ " type: S_REGULAR\n"
+ " attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS]\n"
+ " alignment: 0\n"
+ " address: 0x0000\n"
+ " content: [ 0x55, 0x89, 0xe5, 0x83, 0xec, 0x08, 0xe8, 0x00,\n"
+ " 0x00, 0x00, 0x00, 0x58, 0x8d, 0x80, 0x16, 0x00,\n"
+ " 0x00, 0x00, 0x89, 0x04, 0x24, 0xe8, 0xe6, 0xff,\n"
+ " 0xff, 0xff, 0x31, 0xc0, 0x83, 0xc4, 0x08, 0x5d,\n"
+ " 0xc3 ]\n"
+ " relocations:\n"
+ " - offset: 0x16\n"
+ " type: GENERIC_RELOC_VANILLA\n"
+ " length: 2\n"
+ " pc-rel: true\n"
+ " extern: true\n"
+ " symbol: 1\n"
+ " - offset: 0x0e\n"
+ " scattered: true\n"
+ " type: GENERIC_RELOC_LOCAL_SECTDIFF\n"
+ " length: 2\n"
+ " pc-rel: false\n"
+ " value: 0x21\n"
+ " - offset: 0x0\n"
+ " scattered: true\n"
+ " type: GENERIC_RELOC_PAIR\n"
+ " length: 2\n"
+ " pc-rel: false\n"
+ " value: 0xb\n"
+ " - segment: __TEXT\n"
+ " section: __cstring\n"
+ " type: S_CSTRING_LITERALS\n"
+ " attributes: [ ]\n"
+ " alignment: 0\n"
+ " address: 0x0021\n"
+ " content: [ 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x0a, 0x00 ]\n"
+ "global-symbols:\n"
+ " - name: _main\n"
+ " type: N_SECT\n"
+ " scope: [ N_EXT ]\n"
+ " sect: 1\n"
+ " value: 0x0\n"
+ "undefined-symbols:\n"
+ " - name: _printf\n"
+ " type: N_UNDF\n"
+ " value: 0x0\n"
+ "...\n");
+ EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86);
+ EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+ EXPECT_EQ((int)(f->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+ EXPECT_EQ(f->sections.size(), 2UL);
+
+ const Section& sect1 = f->sections[0];
+ EXPECT_TRUE(sect1.segmentName.equals("__TEXT"));
+ EXPECT_TRUE(sect1.sectionName.equals("__text"));
+ EXPECT_EQ((uint32_t)(sect1.type), (uint32_t)(llvm::MachO::S_REGULAR));
+ EXPECT_EQ((uint32_t)(sect1.attributes),
+ (uint32_t)(llvm::MachO::S_ATTR_PURE_INSTRUCTIONS
+ | llvm::MachO::S_ATTR_SOME_INSTRUCTIONS));
+ EXPECT_EQ(sect1.alignment, 0U);
+ EXPECT_EQ((uint64_t)sect1.address, 0x0ULL);
+ EXPECT_EQ(sect1.content.size(), 33UL);
+ EXPECT_EQ((int)(sect1.content[0]), 0x55);
+ EXPECT_EQ((int)(sect1.content[1]), 0x89);
+ EXPECT_EQ(sect1.relocations.size(), 3UL);
+ const Relocation& reloc1 = sect1.relocations[0];
+ EXPECT_EQ(reloc1.offset, 0x16U);
+ EXPECT_FALSE(reloc1.scattered);
+ EXPECT_EQ((int)reloc1.type, (int)llvm::MachO::GENERIC_RELOC_VANILLA);
+ EXPECT_EQ(reloc1.length, 2);
+ EXPECT_TRUE(reloc1.pcRel);
+ EXPECT_TRUE(reloc1.isExtern);
+ EXPECT_EQ(reloc1.symbol, 1U);
+ EXPECT_EQ((int)(reloc1.value), 0);
+ const Relocation& reloc2 = sect1.relocations[1];
+ EXPECT_EQ(reloc2.offset, 0x0eU);
+ EXPECT_TRUE(reloc2.scattered);
+ EXPECT_EQ((int)reloc2.type, (int)llvm::MachO::GENERIC_RELOC_LOCAL_SECTDIFF);
+ EXPECT_EQ(reloc2.length, 2);
+ EXPECT_FALSE(reloc2.pcRel);
+ EXPECT_EQ(reloc2.symbol, 0U);
+ EXPECT_EQ((int)(reloc2.value), 0x21);
+ const Relocation& reloc3 = sect1.relocations[2];
+ EXPECT_EQ(reloc3.offset, 0U);
+ EXPECT_TRUE(reloc3.scattered);
+ EXPECT_EQ((int)reloc3.type, (int)llvm::MachO::GENERIC_RELOC_PAIR);
+ EXPECT_EQ(reloc3.length, 2);
+ EXPECT_FALSE(reloc3.pcRel);
+ EXPECT_EQ(reloc3.symbol, 0U);
+ EXPECT_EQ((int)(reloc3.value), 0xb);
+
+ const Section& sect2 = f->sections[1];
+ EXPECT_TRUE(sect2.segmentName.equals("__TEXT"));
+ EXPECT_TRUE(sect2.sectionName.equals("__cstring"));
+ EXPECT_EQ((uint32_t)(sect2.type), (uint32_t)(llvm::MachO::S_CSTRING_LITERALS));
+ EXPECT_EQ((uint32_t)(sect2.attributes), 0U);
+ EXPECT_EQ(sect2.alignment, 0U);
+ EXPECT_EQ((uint64_t)sect2.address, 0x021ULL);
+ EXPECT_EQ(sect2.content.size(), 7UL);
+ EXPECT_EQ((int)(sect2.content[0]), 0x68);
+ EXPECT_EQ((int)(sect2.content[1]), 0x65);
+ EXPECT_EQ((int)(sect2.content[2]), 0x6c);
+
+ EXPECT_EQ(f->globalSymbols.size(), 1UL);
+ const Symbol& sym1 = f->globalSymbols[0];
+ EXPECT_TRUE(sym1.name.equals("_main"));
+ EXPECT_EQ((int)(sym1.type), llvm::MachO::N_SECT);
+ EXPECT_EQ((int)(sym1.scope), llvm::MachO::N_EXT);
+ EXPECT_EQ(sym1.sect, 1);
+ EXPECT_EQ((int)(sym1.desc), 0);
+ EXPECT_EQ((uint64_t)sym1.value, 0x0ULL);
+ EXPECT_EQ(f->undefinedSymbols.size(), 1UL);
+ const Symbol& sym2 = f->undefinedSymbols[0];
+ EXPECT_TRUE(sym2.name.equals("_printf"));
+ EXPECT_EQ((int)(sym2.type), llvm::MachO::N_UNDF);
+ EXPECT_EQ((int)(sym2.scope), 0);
+ EXPECT_EQ(sym2.sect, 0);
+ EXPECT_EQ((int)(sym2.desc), 0);
+ EXPECT_EQ((uint64_t)sym2.value, 0x0ULL);
+}
+
+TEST(ObjectFileYAML, hello_armv6) {
+ std::unique_ptr<NormalizedFile> f = fromYAML(
+ "---\n"
+ "arch: armv6\n"
+ "file-type: MH_OBJECT\n"
+ "flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]\n"
+ "sections:\n"
+ " - segment: __TEXT\n"
+ " section: __text\n"
+ " type: S_REGULAR\n"
+ " attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS]\n"
+ " alignment: 2\n"
+ " address: 0x0000\n"
+ " content: [ 0x80, 0x40, 0x2d, 0xe9, 0x10, 0x00, 0x9f, 0xe5,\n"
+ " 0x0d, 0x70, 0xa0, 0xe1, 0x00, 0x00, 0x8f, 0xe0,\n"
+ " 0xfa, 0xff, 0xff, 0xeb, 0x00, 0x00, 0xa0, 0xe3,\n"
+ " 0x80, 0x80, 0xbd, 0xe8, 0x0c, 0x00, 0x00, 0x00 ]\n"
+ " relocations:\n"
+ " - offset: 0x1c\n"
+ " scattered: true\n"
+ " type: ARM_RELOC_SECTDIFF\n"
+ " length: 2\n"
+ " pc-rel: false\n"
+ " value: 0x20\n"
+ " - offset: 0x0\n"
+ " scattered: true\n"
+ " type: ARM_RELOC_PAIR\n"
+ " length: 2\n"
+ " pc-rel: false\n"
+ " value: 0xc\n"
+ " - offset: 0x10\n"
+ " type: ARM_RELOC_BR24\n"
+ " length: 2\n"
+ " pc-rel: true\n"
+ " extern: true\n"
+ " symbol: 1\n"
+ " - segment: __TEXT\n"
+ " section: __cstring\n"
+ " type: S_CSTRING_LITERALS\n"
+ " attributes: [ ]\n"
+ " alignment: 0\n"
+ " address: 0x0020\n"
+ " content: [ 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x0a, 0x00 ]\n"
+ "global-symbols:\n"
+ " - name: _main\n"
+ " type: N_SECT\n"
+ " scope: [ N_EXT ]\n"
+ " sect: 1\n"
+ " value: 0x0\n"
+ "undefined-symbols:\n"
+ " - name: _printf\n"
+ " type: N_UNDF\n"
+ " value: 0x0\n"
+ "...\n");
+ EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_armv6);
+ EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+ EXPECT_EQ((int)(f->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+ EXPECT_EQ(f->sections.size(), 2UL);
+
+ const Section& sect1 = f->sections[0];
+ EXPECT_TRUE(sect1.segmentName.equals("__TEXT"));
+ EXPECT_TRUE(sect1.sectionName.equals("__text"));
+ EXPECT_EQ((uint32_t)(sect1.type), (uint32_t)(llvm::MachO::S_REGULAR));
+ EXPECT_EQ((uint32_t)(sect1.attributes),
+ (uint32_t)(llvm::MachO::S_ATTR_PURE_INSTRUCTIONS
+ | llvm::MachO::S_ATTR_SOME_INSTRUCTIONS));
+ EXPECT_EQ(sect1.alignment, 2U);
+ EXPECT_EQ((uint64_t)sect1.address, 0x0ULL);
+ EXPECT_EQ(sect1.content.size(), 32UL);
+ EXPECT_EQ((int)(sect1.content[0]), 0x80);
+ EXPECT_EQ((int)(sect1.content[1]), 0x40);
+ EXPECT_EQ(sect1.relocations.size(), 3UL);
+ const Relocation& reloc1 = sect1.relocations[0];
+ EXPECT_EQ(reloc1.offset, 0x1cU);
+ EXPECT_TRUE(reloc1.scattered);
+ EXPECT_EQ((int)reloc1.type, (int)llvm::MachO::ARM_RELOC_SECTDIFF);
+ EXPECT_EQ(reloc1.length, 2);
+ EXPECT_FALSE(reloc1.pcRel);
+ EXPECT_EQ(reloc1.symbol, 0U);
+ EXPECT_EQ((int)(reloc1.value), 0x20);
+ const Relocation& reloc2 = sect1.relocations[1];
+ EXPECT_EQ(reloc2.offset, 0x0U);
+ EXPECT_TRUE(reloc2.scattered);
+ EXPECT_EQ((int)reloc2.type, (int)llvm::MachO::ARM_RELOC_PAIR);
+ EXPECT_EQ(reloc2.length, 2);
+ EXPECT_FALSE(reloc2.pcRel);
+ EXPECT_EQ(reloc2.symbol, 0U);
+ EXPECT_EQ((int)(reloc2.value), 0xc);
+ const Relocation& reloc3 = sect1.relocations[2];
+ EXPECT_EQ(reloc3.offset, 0x10U);
+ EXPECT_FALSE(reloc3.scattered);
+ EXPECT_EQ((int)reloc3.type, (int)llvm::MachO::ARM_RELOC_BR24);
+ EXPECT_EQ(reloc3.length, 2);
+ EXPECT_TRUE(reloc3.pcRel);
+ EXPECT_TRUE(reloc3.isExtern);
+ EXPECT_EQ(reloc3.symbol, 1U);
+ EXPECT_EQ((int)(reloc3.value), 0);
+
+ const Section& sect2 = f->sections[1];
+ EXPECT_TRUE(sect2.segmentName.equals("__TEXT"));
+ EXPECT_TRUE(sect2.sectionName.equals("__cstring"));
+ EXPECT_EQ((uint32_t)(sect2.type), (uint32_t)(llvm::MachO::S_CSTRING_LITERALS));
+ EXPECT_EQ((uint32_t)(sect2.attributes), 0U);
+ EXPECT_EQ(sect2.alignment, 0U);
+ EXPECT_EQ((uint64_t)sect2.address, 0x020ULL);
+ EXPECT_EQ(sect2.content.size(), 7UL);
+ EXPECT_EQ((int)(sect2.content[0]), 0x68);
+ EXPECT_EQ((int)(sect2.content[1]), 0x65);
+ EXPECT_EQ((int)(sect2.content[2]), 0x6c);
+
+ EXPECT_EQ(f->globalSymbols.size(), 1UL);
+ const Symbol& sym1 = f->globalSymbols[0];
+ EXPECT_TRUE(sym1.name.equals("_main"));
+ EXPECT_EQ((int)(sym1.type), llvm::MachO::N_SECT);
+ EXPECT_EQ((int)(sym1.scope), llvm::MachO::N_EXT);
+ EXPECT_EQ(sym1.sect, 1);
+ EXPECT_EQ((int)(sym1.desc), 0);
+ EXPECT_EQ((uint64_t)sym1.value, 0x0ULL);
+ EXPECT_EQ(f->undefinedSymbols.size(), 1UL);
+ const Symbol& sym2 = f->undefinedSymbols[0];
+ EXPECT_TRUE(sym2.name.equals("_printf"));
+ EXPECT_EQ((int)(sym2.type), llvm::MachO::N_UNDF);
+ EXPECT_EQ((int)(sym2.scope), 0);
+ EXPECT_EQ(sym2.sect, 0);
+ EXPECT_EQ((int)(sym2.desc), 0);
+ EXPECT_EQ((uint64_t)sym2.value, 0x0ULL);
+}
+
+
+
+TEST(ObjectFileYAML, hello_armv7) {
+ std::unique_ptr<NormalizedFile> f = fromYAML(
+ "---\n"
+ "arch: armv7\n"
+ "file-type: MH_OBJECT\n"
+ "flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]\n"
+ "sections:\n"
+ " - segment: __TEXT\n"
+ " section: __text\n"
+ " type: S_REGULAR\n"
+ " attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS]\n"
+ " alignment: 1\n"
+ " address: 0x0000\n"
+ " content: [ 0x80, 0xb5, 0x40, 0xf2, 0x06, 0x00, 0x6f, 0x46,\n"
+ " 0xc0, 0xf2, 0x00, 0x00, 0x78, 0x44, 0xff, 0xf7,\n"
+ " 0xf8, 0xef, 0x00, 0x20, 0x80, 0xbd ]\n"
+ " relocations:\n"
+ " - offset: 0x0e\n"
+ " type: ARM_THUMB_RELOC_BR22\n"
+ " length: 2\n"
+ " pc-rel: true\n"
+ " extern: true\n"
+ " symbol: 1\n"
+ " - offset: 0x08\n"
+ " scattered: true\n"
+ " type: ARM_RELOC_HALF_SECTDIFF\n"
+ " length: 3\n"
+ " pc-rel: false\n"
+ " value: 0x16\n"
+ " - offset: 0x06\n"
+ " scattered: true\n"
+ " type: ARM_RELOC_PAIR\n"
+ " length: 3\n"
+ " pc-rel: false\n"
+ " value: 0xc\n"
+ " - offset: 0x02\n"
+ " scattered: true\n"
+ " type: ARM_RELOC_HALF_SECTDIFF\n"
+ " length: 2\n"
+ " pc-rel: false\n"
+ " value: 0x16\n"
+ " - offset: 0x0\n"
+ " scattered: true\n"
+ " type: ARM_RELOC_PAIR\n"
+ " length: 2\n"
+ " pc-rel: false\n"
+ " value: 0xc\n"
+ " - segment: __TEXT\n"
+ " section: __cstring\n"
+ " type: S_CSTRING_LITERALS\n"
+ " attributes: [ ]\n"
+ " alignment: 0\n"
+ " address: 0x0016\n"
+ " content: [ 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x0a, 0x00 ]\n"
+ "global-symbols:\n"
+ " - name: _main\n"
+ " type: N_SECT\n"
+ " scope: [ N_EXT ]\n"
+ " sect: 1\n"
+ " desc: [ N_ARM_THUMB_DEF ]\n"
+ " value: 0x0\n"
+ "undefined-symbols:\n"
+ " - name: _printf\n"
+ " type: N_UNDF\n"
+ " value: 0x0\n"
+ "...\n");
+ EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_armv7);
+ EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+ EXPECT_EQ((int)(f->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+ EXPECT_EQ(f->sections.size(), 2UL);
+
+ const Section& sect1 = f->sections[0];
+ EXPECT_TRUE(sect1.segmentName.equals("__TEXT"));
+ EXPECT_TRUE(sect1.sectionName.equals("__text"));
+ EXPECT_EQ((uint32_t)(sect1.type), (uint32_t)(llvm::MachO::S_REGULAR));
+ EXPECT_EQ((uint32_t)(sect1.attributes),
+ (uint32_t)(llvm::MachO::S_ATTR_PURE_INSTRUCTIONS
+ | llvm::MachO::S_ATTR_SOME_INSTRUCTIONS));
+ EXPECT_EQ(sect1.alignment, 1U);
+ EXPECT_EQ((uint64_t)sect1.address, 0x0ULL);
+ EXPECT_EQ(sect1.content.size(), 22UL);
+ EXPECT_EQ((int)(sect1.content[0]), 0x80);
+ EXPECT_EQ((int)(sect1.content[1]), 0xb5);
+ EXPECT_EQ(sect1.relocations.size(), 5UL);
+ const Relocation& reloc1 = sect1.relocations[0];
+ EXPECT_EQ(reloc1.offset, 0x0eU);
+ EXPECT_FALSE(reloc1.scattered);
+ EXPECT_EQ((int)reloc1.type, (int)llvm::MachO::ARM_THUMB_RELOC_BR22);
+ EXPECT_EQ(reloc1.length, 2);
+ EXPECT_TRUE(reloc1.pcRel);
+ EXPECT_TRUE(reloc1.isExtern);
+ EXPECT_EQ(reloc1.symbol, 1U);
+ EXPECT_EQ((int)(reloc1.value), 0);
+ const Relocation& reloc2 = sect1.relocations[1];
+ EXPECT_EQ(reloc2.offset, 0x8U);
+ EXPECT_TRUE(reloc2.scattered);
+ EXPECT_EQ((int)reloc2.type, (int)llvm::MachO::ARM_RELOC_HALF_SECTDIFF);
+ EXPECT_EQ(reloc2.length, 3);
+ EXPECT_FALSE(reloc2.pcRel);
+ EXPECT_EQ(reloc2.symbol, 0U);
+ EXPECT_EQ((int)(reloc2.value), 0x16);
+ const Relocation& reloc3 = sect1.relocations[2];
+ EXPECT_EQ(reloc3.offset, 0x6U);
+ EXPECT_TRUE(reloc3.scattered);
+ EXPECT_EQ((int)reloc3.type, (int)llvm::MachO::ARM_RELOC_PAIR);
+ EXPECT_EQ(reloc3.length, 3);
+ EXPECT_FALSE(reloc3.pcRel);
+ EXPECT_EQ(reloc3.symbol, 0U);
+ EXPECT_EQ((int)(reloc3.value), 0xc);
+ const Relocation& reloc4 = sect1.relocations[3];
+ EXPECT_EQ(reloc4.offset, 0x2U);
+ EXPECT_TRUE(reloc4.scattered);
+ EXPECT_EQ((int)reloc4.type, (int)llvm::MachO::ARM_RELOC_HALF_SECTDIFF);
+ EXPECT_EQ(reloc4.length, 2);
+ EXPECT_FALSE(reloc4.pcRel);
+ EXPECT_EQ(reloc4.symbol, 0U);
+ EXPECT_EQ((int)(reloc4.value), 0x16);
+ const Relocation& reloc5 = sect1.relocations[4];
+ EXPECT_EQ(reloc5.offset, 0x0U);
+ EXPECT_TRUE(reloc5.scattered);
+ EXPECT_EQ((int)reloc5.type, (int)llvm::MachO::ARM_RELOC_PAIR);
+ EXPECT_EQ(reloc5.length, 2);
+ EXPECT_FALSE(reloc5.pcRel);
+ EXPECT_EQ(reloc5.symbol, 0U);
+ EXPECT_EQ((int)(reloc5.value), 0xc);
+
+ const Section& sect2 = f->sections[1];
+ EXPECT_TRUE(sect2.segmentName.equals("__TEXT"));
+ EXPECT_TRUE(sect2.sectionName.equals("__cstring"));
+ EXPECT_EQ((uint32_t)(sect2.type), (uint32_t)(llvm::MachO::S_CSTRING_LITERALS));
+ EXPECT_EQ((uint32_t)(sect2.attributes), 0U);
+ EXPECT_EQ(sect2.alignment, 0U);
+ EXPECT_EQ((uint64_t)sect2.address, 0x016ULL);
+ EXPECT_EQ(sect2.content.size(), 7UL);
+ EXPECT_EQ((int)(sect2.content[0]), 0x68);
+ EXPECT_EQ((int)(sect2.content[1]), 0x65);
+ EXPECT_EQ((int)(sect2.content[2]), 0x6c);
+
+ EXPECT_EQ(f->globalSymbols.size(), 1UL);
+ const Symbol& sym1 = f->globalSymbols[0];
+ EXPECT_TRUE(sym1.name.equals("_main"));
+ EXPECT_EQ((int)(sym1.type), llvm::MachO::N_SECT);
+ EXPECT_EQ((int)(sym1.scope), llvm::MachO::N_EXT);
+ EXPECT_EQ(sym1.sect, 1);
+ EXPECT_EQ((int)(sym1.desc), (int)(llvm::MachO::N_ARM_THUMB_DEF));
+ EXPECT_EQ((uint64_t)sym1.value, 0x0ULL);
+ EXPECT_EQ(f->undefinedSymbols.size(), 1UL);
+ const Symbol& sym2 = f->undefinedSymbols[0];
+ EXPECT_TRUE(sym2.name.equals("_printf"));
+ EXPECT_EQ((int)(sym2.type), llvm::MachO::N_UNDF);
+ EXPECT_EQ((int)(sym2.scope), 0);
+ EXPECT_EQ(sym2.sect, 0);
+ EXPECT_EQ((int)(sym2.desc), 0);
+ EXPECT_EQ((uint64_t)sym2.value, 0x0ULL);
+}
diff --git a/unittests/MachOTests/empty_obj_x86_armv7.txt b/unittests/MachOTests/empty_obj_x86_armv7.txt
new file mode 100644
index 000000000000..9d340cb7132e
--- /dev/null
+++ b/unittests/MachOTests/empty_obj_x86_armv7.txt
@@ -0,0 +1,1272 @@
+0xca, 0xfe, 0xba, 0xbe, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x07, 0x00,
+0x00, 0x00, 0x03, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00,
+0x00, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x40,
+0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0xcf, 0xfa, 0xed, 0xfe, 0x07, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00,
+0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x00,
+0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x98, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00,
+0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x5f, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0xce, 0xfa, 0xed, 0xfe, 0x0c, 0x00, 0x00, 0x00, 0x09,
+0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7c, 0x00,
+0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00,
+0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x74,
+0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
diff --git a/unittests/Makefile b/unittests/Makefile
new file mode 100644
index 000000000000..0fbb17d48289
--- /dev/null
+++ b/unittests/Makefile
@@ -0,0 +1,31 @@
+##===- unittests/Makefile ----------------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+# If LLD_LEVEL is not set, then we are the top-level Makefile. Otherwise, we
+# are being included from a subdirectory makefile.
+
+ifndef LLD_LEVEL
+
+IS_UNITTEST_LEVEL := 1
+LLD_LEVEL := ..
+
+PARALLEL_DIRS = CoreTests DriverTests
+
+include $(LLD_LEVEL)/../../Makefile.config
+
+endif # LLD_LEVEL
+
+include $(LLD_LEVEL)/Makefile
+
+ifndef IS_UNITTEST_LEVEL
+
+MAKEFILE_UNITTEST_NO_INCLUDE_COMMON := 1
+include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest
+
+endif # IS_UNITTEST_LEVEL
diff --git a/utils/astyle-options b/utils/astyle-options
new file mode 100644
index 000000000000..53c496bfebc0
--- /dev/null
+++ b/utils/astyle-options
@@ -0,0 +1,7 @@
+style=java
+indent=spaces=2
+pad-oper
+pad-header
+unpad-paren
+convert-tabs
+align-pointer=name